Initial commit of upstream chromium.

Revision: e5034a51c8214ee6fed4d2ec928ee7e982eea70e
diff --git a/.gn b/.gn
new file mode 100644
index 0000000..853c59a
--- /dev/null
+++ b/.gn
@@ -0,0 +1,189 @@
+# This file is used by the GN meta build system to find the root of the source
+# tree and to set startup options. For documentation on the values set in this
+# file, run "gn help dotfile" at the command line.
+
+# The location of the build configuration file.
+buildconfig = "//build/config/BUILDCONFIG.gn"
+
+# The secondary source root is a parallel directory tree where
+# GN build files are placed when they can not be placed directly
+# in the source tree, e.g. for third party source trees.
+secondary_source = "//build/secondary/"
+
+# These are the targets to check headers for by default. The files in targets
+# matching these patterns (see "gn help label_pattern" for format) will have
+# their includes checked for proper dependencies when you run either
+# "gn check" or "gn gen --check".
+check_targets = [
+  #"//apps/*",  # Medium-hard.
+  #"//ash/*",  # Medium-hard.
+  #"//base/*",  # Needs GN binary changes to work on Android.
+  "//blink/*",
+  "//breakpad/*",
+  "//build/*",
+  "//cc/*",
+
+  #"//chrome/*",  # Epic number of errors.
+  "//chromecast/*",
+
+  # TODO(brettw): Fix http://crbug.com/460828 and uncomment the following
+  # line.
+  #"//chrome_elf/*",
+  "//cloud_print/*",
+
+  #"//components/*",  # Lots of errors.
+  #"//content/*",  # A whole lot of errors.
+  "//courgette/*",
+  "//crypto/*",
+  "//data/*",
+  "//dbus/*",
+  "//device/*",
+
+  #"//extensions/*",  # Lots of errors.
+  #"//gin/*",  # Easy.
+  "//google_apis/*",
+  "//google_update/*",
+
+  #"//gpu/*",  # Lots of errors.
+  #"//ios/*",
+  "//ipc/*",
+
+  #"//jingle/*",
+  #"//media/*",  # Lots of errors.
+  #"//mojo/*",
+  #"//native_client/*",
+  #"//net/*",  # Needs GN binary changes to work on Android.
+
+  #"//pdf/*",  # Medium-hard.
+  #"//ppapi/*",  # Lots of errors.
+  "//printing/*",
+
+  #"//remoting/*",  # Medium-hard.
+  #"//rlz/*",  # Needs checking on Windows.
+  #"//sandbox/*",  # Medium-hard.
+  "//sdch/*",
+  "//skia/*",
+  "//sql/*",
+  "//storage/*",
+  "//sync/*",
+  "//testing/*",
+
+  #"//third_party/*",  # May not ever want this.
+  "//tools/*",
+
+  #"//ui/*",  # Just a few problems.
+  "//url/*",
+  "//v8/*",
+]
+
+# These are the list of GN files that run exec_script. This whitelist exists
+# to force additional review for new uses of exec_script, which is strongly
+# discouraged except for gypi_to_gn calls.
+exec_script_whitelist = [
+  "//ash/BUILD.gn",
+  "//build/config/android/BUILD.gn",
+  "//build/config/android/config.gni",
+  "//build/config/android/internal_rules.gni",
+  "//build/config/android/rules.gni",
+  "//build/config/compiler/BUILD.gn",
+  "//build/config/gcc/gcc_version.gni",
+  "//build/config/ios/ios_sdk.gni",
+  "//build/config/linux/BUILD.gn",
+  "//build/config/linux/pkg_config.gni",
+  "//build/config/mac/mac_sdk.gni",
+  "//build/config/win/visual_studio_version.gni",
+  "//build/gn_helpers.py",
+  "//build/gypi_to_gn.py",
+  "//build/toolchain/gcc_toolchain.gni",
+  "//build/toolchain/mac/BUILD.gn",
+  "//build/toolchain/win/BUILD.gn",
+  "//chrome/android/BUILD.gn",
+  "//chrome/browser/BUILD.gn",
+  "//chrome/browser/chromeos/BUILD.gn",
+  "//chrome/browser/extensions/BUILD.gn",
+  "//chrome/browser/ui/BUILD.gn",
+  "//chrome/chrome_tests.gni",
+  "//chrome/common/BUILD.gn",
+  "//chrome/common/extensions/api/schemas.gni",
+  "//chrome/renderer/BUILD.gn",
+  "//chrome/test/BUILD.gn",
+  "//chrome/utility/BUILD.gn",
+  "//chromeos/BUILD.gn",
+
+  # TODO(dgn): Layer violation but breaks the build otherwise, see
+  # https://crbug.com/474506
+  "//clank/java/BUILD.gn",
+  "//clank/native/framework/BUILD.gn",
+
+  "//components/domain_reliability/BUILD.gn",
+  "//components/scheduler/scheduler.gni",
+  "//components/webui_generator/generator/wug.gni",
+  "//content/browser/browser.gni",
+  "//content/child/child.gni",
+  "//content/common/common.gni",
+  "//content/content.gni",
+  "//content/public/android/BUILD.gn",
+  "//content/renderer/renderer.gni",
+  "//content/test/BUILD.gn",
+  "//extensions/common/api/schemas.gni",
+  "//extensions/extensions.gni",
+  "//extensions/shell/app_shell.gni",
+  "//extensions/shell/common/api/schemas.gni",
+  "//google_apis/BUILD.gn",
+  "//gpu/gles2_conform_support/BUILD.gn",
+  "//jingle/BUILD.gn",
+  "//native_client/build/toolchain/gcc_toolchain.gni",
+  "//native_client/build/toolchain/nacl/BUILD.gn",
+  "//native_client/build/config/android/BUILD.gn",
+  "//native_client/build/config/gcc/gcc_version.gni",
+  "//native_client/build/config/ios/ios_sdk.gni",
+  "//native_client/build/config/linux/BUILD.gn",
+  "//native_client/build/config/linux/pkg_config.gni",
+  "//native_client/build/config/mac/mac_sdk.gni",
+  "//native_client/build/config/win/visual_studio_version.gni",
+  "//native_client/build/toolchain/gcc_toolchain.gni",
+  "//native_client/build/toolchain/mac/BUILD.gn",
+  "//native_client/build/toolchain/nacl/BUILD.gn",
+  "//native_client/build/toolchain/win/BUILD.gn",
+  "//net/BUILD.gn",
+  "//ppapi/ppapi_sources.gni",
+  "//printing/BUILD.gn",
+  "//remoting/host/BUILD.gn",
+  "//remoting/remoting_srcs.gni",
+  "//remoting/remoting_version.gni",
+  "//skia/BUILD.gn",
+  "//third_party/android_platform/BUILD.gn",
+  "//third_party/angle/BUILD.gn",
+  "//third_party/boringssl/BUILD.gn",
+  "//third_party/cld_2/BUILD.gn",
+  "//third_party/cython/rules.gni",
+  "//third_party/google_input_tools/inputview.gni",
+  "//third_party/harfbuzz-ng/BUILD.gn",
+  "//third_party/libaddressinput/BUILD.gn",
+  "//third_party/opus/BUILD.gn",
+  "//third_party/WebKit/Source/bindings/bindings.gni",
+  "//third_party/WebKit/Source/bindings/scripts/scripts.gni",
+  "//third_party/WebKit/Source/config.gni",
+  "//third_party/WebKit/Source/core/core.gni",
+  "//third_party/WebKit/Source/devtools/BUILD.gn",
+  "//third_party/WebKit/Source/modules/modules.gni",
+  "//third_party/WebKit/Source/platform/BUILD.gn",
+  "//third_party/WebKit/Source/platform/platform.gni",
+  "//third_party/WebKit/Source/web/BUILD.gn",
+  "//third_party/WebKit/Source/wtf/BUILD.gn",
+  "//tools/gn/BUILD.gn",
+  "//tools/gn/build_settings.h",
+  "//tools/gn/command_help.cc",
+  "//tools/gn/docs/language.md",
+  "//tools/gn/format_test_data/053.gn",
+  "//tools/gn/format_test_data/053.golden",
+  "//tools/gn/format_test_data/055.gn",
+  "//tools/gn/format_test_data/055.golden",
+  "//tools/gn/function_exec_script.cc",
+  "//tools/gn/gn.gyp",
+  "//tools/gn/input_conversion.cc",
+  "//tools/gn/misc/emacs/gn.el",
+  "//tools/gn/misc/vim/syntax/gn.vim",
+  "//tools/gn/setup.cc",
+  "//ui/views/BUILD.gn",
+]
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fd401bb
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,607 @@
+# 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.
+
+Aaron Jacobs <samusaaron3@gmail.com>
+Aaron Leventhal <aaronlevbugs@gmail.com>
+Aaron Randolph <aaron.randolph@gmail.com>
+Abhijeet Kandalkar <abhijeet.k@samsung.com>
+Abhishek Agarwal <abhishek.a21@samsung.com>
+Adam Roben <adam@github.com>
+Adam Treat <adam.treat@samsung.com>
+Addanki Gandhi Kishor <kishor.ag@samsung.com>
+Adenilson Cavalcanti <a.cavalcanti@samsung.com>
+Aditya Bhargava <heuristicist@gmail.com>
+Ajay Berwal <ajay.berwal@samsung.com>
+Ajay Berwal <a.berwal@samsung.com>
+Ajith Kumar V <ajith.v@samsung.com>
+Aku Kotkavuo <a.kotkavuo@partner.samsung.com>
+Alex Gabriel <minilogo@gmail.com>
+Alex Gartrell <agartrell@cmu.edu>
+Alex Henrie <alexhenrie24@gmail.com>
+Alex Scheele <alexscheele@gmail.com>
+Alexander Sulfrian <alexander@sulfrian.net>
+Alexandre Abreu <wiss1976@gmail.com>
+Alexandru Chiculita <achicu@adobe.com>
+Alexey Korepanov <alexkorep@gmail.com>
+Alexis Menard <alexis.menard@intel.com>
+Alfredo Hernandez <ahernandez.miralles@gmail.com>
+Ali Vathi <ali.akbar@gmail.com>
+Ambarish Rapte <ambarish.r@samsung.com>
+Amit Sarkar <amit.srkr@samsung.com>
+Amogh Bihani <amogh.bihani@samsung.com>
+Amruth Raj <amruthraj@motorola.com>
+Amruth Raj <ckqr36@motorola.com>
+Anand Ratn <anand.ratn@samsung.com>
+Anastasios Cassiotis <tom.cassiotis@gmail.com>
+Ancil George <ancilgeorge@samsung.com>
+Andrei Parvu <andrei.prv@gmail.com>
+Andrei Parvu <parvu@adobe.com>
+Andrew Brampton <me@bramp.net>
+Andrew Tulloch <andrew@tullo.ch>
+Anish Patankar <anish.p@samsung.com>
+Ankit Kumar <ankit2.kumar@samsung.com>
+Anssi Hannula <anssi.hannula@iki.fi>
+Antonio Gomes <a1.gomes@sisa.samsung.com>
+Anuj Kumar Sharma <anujk.sharma@samsung.com>
+Arnaud Renevier <a.renevier@samsung.com>
+Arpita Bahuguna <a.bah@samsung.com>
+Arthur Lussos <developer0420@gmail.com>
+Arun Kulkarni <kulkarni.a@samsung.com>
+Arun Kumar <arun87.kumar@samsung.com>
+Arun Mankuzhi <arun.m@samsung.com>
+Arunoday Sarkar <a.sarkar.arun@gmail.com>
+Arunprasad Rajkumar <ararunprasad@gmail.com>
+Arunprasad Rajkumar <arurajku@cisco.com>
+Attila Dusnoki <dati91@gmail.com>
+Avinaash Doreswamy <avi.nitk@samsung.com>
+Balazs Kelemen <b.kelemen@samsung.com>
+Baul Eun <baul.eun@samsung.com>
+Behara Mani Shyam Patro <behara.ms@samsung.com>
+Bem Jones-Bey <bemajaniman@gmail.com>
+Bem Jones-Bey <bjonesbe@adobe.com>
+Ben Fiola <benfiola@gmail.com>
+Ben Karel <eschew@gmail.com>
+Benjamin Dupont <bedupont@cisco.com>
+Benjamin Jemlich <pcgod99@gmail.com>
+Bernard Cafarelli <voyageur@gentoo.org>
+Bhanukrushana Rout <b.rout@samsung.com>
+Bobby Powers <bobbypowers@gmail.com>
+Branden Archer <bma4@zips.uakron.edu>
+Brendan Long <self@brendanlong.com>
+Brian G. Merrell <bgmerrell@gmail.com>
+Brian Konzman, SJ <b.g.konzman@gmail.com>
+Brian Luft <brian@electroly.com>
+Brian Merrell, Novell Inc. <bgmerrell@gmail.com>
+Bruno Calvignac <bruno@flock.com>
+Bruno de Oliveira Abinader <brunoabinader@gmail.com>
+Bryan Donlan <bdonlan@gmail.com>
+Byoungkwon Ko <gogag2@gmail.com>
+Byungwoo Lee <bw80.lee@samsung.com>
+Caio Marcelo de Oliveira Filho <caio.de.oliveira.filho@intel.com>
+Caitlin Potter <caitpotter88@gmail.com>
+Catalin Badea <badea@adobe.com>
+Cem Kocagil <cem.kocagil@gmail.com>
+Chamal De Silva <chamalsl@yahoo.com>
+Chandra Shekar Vallala <brk376@motorola.com>
+Chang Shu <c.shu@samsung.com>
+ChangSeok Oh <shivamidow@gmail.com>
+Changbin Shao <changbin.shao@intel.com>
+Changjun Yang <changjun.yang@intel.com>
+Changyeon Kim <cyzero.kim@samsung.com>
+Chansik Yun <chansik.yun@gmail.com>
+Chaobin Zhang <zhchbin@gmail.com>
+Chris Greene <cwgreene@amazon.com>
+Chris Harrelson <chrishtr@gmail.com>
+Chris Nardi <hichris123@gmail.com>
+Chris Vasselli <clindsay@gmail.com>
+Christophe Dumez <ch.dumez@samsung.com>
+Christopher Dale <chrelad@gmail.com>
+Clemens Fruhwirth <clemens@endorphin.org>
+Clement Scheelfeldt Skau <clementskau@gmail.com>
+Clinton Staley <clintstaley@chromium.org>
+Clinton Staley <clintstaley@gmail.com>
+Craig Schlenter <craig.schlenter@gmail.com>
+Daegyu Lee <na7jun8gi@gmail.com>
+Dai Chunyang <chunyang.dai@intel.com>
+Daiwei Li <daiweili@suitabletech.com>
+Daniel Bomar <dbdaniel42@gmail.com>
+Daniel Carvalho Liedke <dliedke@gmail.com>
+Daniel Imms <daniimms@amazon.com>
+Daniel Johnson <danielj41@gmail.com>
+Daniel Nishi <dhnishi@gmail.com>
+Daniel Platz <daplatz@googlemail.com>
+Daniel Shaulov <dshaulov@ptc.com>
+Daniel Trebbien <dtrebbien@gmail.com>
+Darshini KN <kn.darshini@samsung.com>
+David Benjamin <davidben@mit.edu>
+David Erceg <erceg.david@gmail.com>
+David Futcher <david.mike.futcher@gmail.com>
+David Leen <davileen@amazon.com>
+David McAllister <mcdavid@amazon.com>
+David Spellman <dspell@amazon.com>
+Debashish Samantaray <d.samantaray@samsung.com>
+Deepak Dilip Borade <deepak.db@samsung.com>
+Deepak Mittal <deepak.m1@samsung.com>
+Deepak Singla <deepak.s@samsung.com>
+Derek Halman <d.halman@gmail.com>
+Devlin Cronin <rdevlin.cronin@gmail.com>
+Diego Ferreiro Val <elfogris@gmail.com>
+Dillon Sellars <dill.sellars@gmail.com>
+Divya Bansal <divya.bansal@samsung.com>
+Dominic Jodoin <dominic.jodoin@gmail.com>
+Dominik Röttsches <dominik.rottsches@intel.com>
+Don Woodward <woodward@adobe.com>
+Dongjun Kim <djmix.kim@samsung.com>
+Dongseong Hwang <dongseong.hwang@intel.com>
+Dongwoo Joshua Im <dw.im@samsung.com>
+Douglas F. Turner <doug.turner@gmail.com>
+Dustin Doloff <doloffd@amazon.com>
+Ebrahim Byagowi <ebraminio@gmail.com>
+Eduardo Lima (Etrunko) <eduardo.lima@intel.com>
+Edward Baker <edward.baker@intel.com>
+Edward Crossman <tedoc2000@gmail.com>
+Eero Häkkinen <e.hakkinen@samsung.com>
+Egor Starkov <egor.starkov@samsung.com>
+Ehsan Akhgari <ehsan.akhgari@gmail.com>
+Elan Ruusamäe <elan.ruusamae@gmail.com>
+Eric Ahn <byungwook.ahn@gmail.com>
+Eric Rescorla <ekr@rtfm.com>
+Erik Hill <erikghill@gmail.com>
+Erik Sjölund <erik.sjolund@gmail.com>
+Eriq Augustine <eriq.augustine@gmail.com>
+Etienne Laurin <etienne@atnnn.com>
+Evan Peterson <evan.peterson.ep@gmail.com>
+Evan Wallace <evan.exe@gmail.com>
+Evangelos Foutras <evangelos@foutrelis.com>
+Evgeniy Dushistov <dushistov@gmail.com>
+Evgeny Agafonchikov <evgeny.agafonchikov@akvelon.com>
+Fabien Tassin <fta@sofaraway.org>
+Felix H. Dahlke <fhd@ubercode.de>
+Fernando Jiménez Moreno <ferjmoreno@gmail.com>
+François Beaufort <beaufort.francois@gmail.com>
+Francois Kritzinger <francoisk777@gmail.com>
+Francois Rauch <leopardb@gmail.com>
+Frédéric Wang <fred.wang@free.fr>
+Gaetano Mendola <mendola@gmail.com>
+Gajendra N <gajendra.n@samsung.com>
+Gajendra Singh <wxjg68@motorola.com>
+Gao Chun <chun.gao@intel.com>
+Gao Chun <gaochun.dev@gmail.com>
+George Liaskos <geo.liaskos@gmail.com>
+Georgy Buranov <gburanov@gmail.com>
+Gitanshu Mehndiratta <g.mehndiratt@samsung.com>
+Giuseppe Iuculano <giuseppe@iuculano.it>
+Glenn Adams <glenn@chromium.org>
+Gnanasekar Somanathan <gnanasekar.s@samsung.com>
+Gordana Cmiljanovic <gordana.cmiljanovic@imgtec.com>
+Goutham Jagannatha <wrm364@motorola.com>
+Graham Yoakum <gyoakum@skobalt.com>
+Gregory Davis <gpdavis.chromium@gmail.com>
+Grzegorz Czajkowski <g.czajkowski@samsung.com>
+Guangzhen Li <guangzhen.li@intel.com>
+Gurpreet Kaur <k.gurpreet@samsung.com>
+Gyuyoung Kim <gyuyoung.kim@samsung.com>
+Gzob Qq <gzobqq@gmail.com>
+Habib Virji <habib.virji@samsung.com>
+Haitao Feng <haitao.feng@intel.com>
+Halton Huo <halton.huo@intel.com>
+Haojian Wu <hokein.wu@gmail.com>
+Harpreet Singh Khurana <harpreet.sk@samsung.com>
+Harshikesh Kumar <harshikeshnobug@gmail.com>
+Hautio Kari <khautio@gmail.com>
+Heejin R. Chung <heejin.r.chung@samsung.com>
+Heeyoun Lee <heeyoun.lee@samsung.com>
+Himanshu Joshi <h.joshi@samsung.com>
+Hong Zheng <hong.zheng@intel.com>
+Hongbo Min <hongbo.min@intel.com>
+Horia Olaru <horia.olaru@gmail.com>
+Horia Olaru <olaru@adobe.com>
+Hosung You <hosung.you@samsung.com>
+Huayong Xu <huayong.xu@samsung.com>
+Hugo Holgersson <hugo.holgersson@sonymobile.com>
+Hwanseung Lee <rucifer1217@gmail.com>
+Hyunjune Kim <hyunjune.kim@samsung.com>
+Hyunki Baik <hyunki.baik@samsung.com>
+Hyungwook Lee <withlhw@gmail.com>
+Ian Scott <ian.scott@arteris.com>
+Ibrar Ahmed <ibrar.ahmad@gmail.com>
+Ion Rosca <rosca@adobe.com>
+Ivan Sham <ivansham@amazon.com>
+J. Ryan Stinnett <jryans@chromium.org>
+Jacob Mandelson <jacob@mandelson.org>
+Jaehun Lim <ljaehun.lim@samsung.com>
+Jaekyeom Kim <btapiz@gmail.com>
+Jaemin Seo <jaemin86.seo@samsung.com>
+Jaime Soriano Pastor <jsorianopastor@gmail.com>
+Jake Helfert <jake@helfert.us>
+Jakob Weigert <jakob.j.w@googlemail.com>
+Jakub Machacek <xtreit@gmail.com>
+James Choi <jchoi42@pha.jhu.edu>
+James Vega <vega.james@gmail.com>
+James Wei <james.wei@intel.com>
+James Willcox <jwillcox@litl.com>
+Janwar Dinata <j.dinata@gmail.com>
+Jared Shumway <jaredshumway94@gmail.com>
+Jared Sohn <jared.sohn@gmail.com>
+Jared Wein <weinjared@gmail.com>
+Jari Karppanen <jkarp@amazon.com>
+Jay Soffian <jaysoffian@gmail.com>
+Jeado Ko <haibane84@gmail.com>
+Jeongeun Kim <je_julie.kim@samsung.com>
+Jeremy Spiegel <jeremysspiegel@gmail.com>
+Jesse Miller <jesse@jmiller.biz>
+Jesus Sanchez-Palencia <jesus.sanchez-palencia.fernandez.fil@intel.com>
+Jiajia Qin <jiajia.qin@intel.com>
+Jie Chen <jie.a.chen@intel.com>
+Jihun Brent Kim <devgrapher@gmail.com>
+Jin Yang <jin.a.yang@intel.com>
+Jincheol Jo <jincheol.jo@navercorp.com>
+Jingwei Liu <kingweiliu@gmail.com>
+Jingyi Wei <wjywbs@gmail.com>
+Jinho Bang <jinho.bang@samsung.com>
+Jinwoo Song <jinwoo7.song@samsung.com>
+Jitendra Kumar Sahoo <jitendra.ks@samsung.com>
+Joachim Bauch <mail@joachim-bauch.de>
+Joe Knoll <joe.knoll@workday.com>
+Joe Thomas <mhx348@motorola.com>
+Joel Stanley <joel@jms.id.au>
+Johannes Rudolph <johannes.rudolph@googlemail.com>
+John Yani <vanuan@gmail.com>
+John Yoo <nearbyh13@gmail.com>
+Johnson Lin <johnson.lin@intel.com>
+Jonathan Frazer <listedegarde@gmail.com>
+Jonathan Garbee <jonathan@garbee.me>
+Jonathan Hacker <jhacker@arcanefour.com>
+Jongsoo Lee <leejongsoo@gmail.com>
+Joone Hur <joone.hur@intel.com>
+Jorge Villatoro <jorge@tomatocannon.com>
+Joseph Gentle <josephg@gmail.com>
+Josh Triplett <josh@joshtriplett.org>
+Josh Triplett <josh.triplett@intel.com>
+Joshua Lock <joshua.lock@intel.com>
+Joshua Roesslein <jroesslein@gmail.com>
+Josué Ratelle <jorat1346@gmail.com>
+Juhui Lee <juhui24.lee@samsung.com>
+Julien Racle <jracle@logitech.com>
+Jun Jiang <jun.a.jiang@intel.com>
+Junchao Han <junchao.han@intel.com>
+JungJik Lee <jungjik.lee@samsung.com>
+Jungkee Song <jungkee.song@samsung.com>
+Junmin Zhu <junmin.zhu@intel.com>
+Kal Conley <kcconley@gmail.com>
+Kalyan Kondapally <kalyan.kondapally@intel.com>
+Kamil Jiwa <kamil.jiwa@gmail.com>
+Kangil Han <kangil.han@samsung.com>
+Kangyuan Shu <kangyuan.shu@intel.com>
+Kartikey Bhatt <kartikey@amazon.com>
+Kaspar Brand <googlecontrib@velox.ch>
+Kaustubh Atrawalkar <kaustubh.ra@gmail.com>
+Kaustubh Atrawalkar <kaustubh.a@samsung.com>
+Keene Pan <keenepan@linpus.com>
+Kenneth Rohde Christiansen <kenneth.r.christiansen@intel.com>
+Keonho Kim <keonho07.kim@samsung.com>
+Kevin Lee Helpingstine <sig11@reprehensible.net>
+Kevin M. McCormick <mckev@amazon.com>
+Kihong Kwon <kihong.kwon@samsung.com>
+Kim Christensen <kimworking@gmail.com>
+Kingshuk Jana <kingshuk.j@samsung.com>
+Kirk Shoop <kirk.shoop@microsoft.com>
+Klemen Forstnerič <klemen.forstneric@gmail.com>
+Krishna Chaitanya <krish.botta@samsung.com>
+Kristof Kosztyo <kkosztyo.u-szeged@partner.samsung.com>
+Krzysztof Czech <k.czech@samsung.com>
+Krzysztof Wolanski <k.wolanski@samsung.com>
+Kunal Thakar <kunalt@gmail.com>
+Kushal Pisavadia <kushi.p@gmail.com>
+Kwangho Shin <k_h.shin@samsung.com>
+Kyle Nahrgang <kpn24@drexel.edu>
+Kyungtae Kim <ktf.kim@samsung.com>
+Kyung Yeol Kim <chitacan@gmail.com>
+Laszlo Gombos <l.gombos@samsung.com>
+Laszlo Radanyi <bekkra@gmail.com>
+Lauren Yeun Kim <lauren.yeun.kim@gmail.com>
+Lauri Oherd <lauri.oherd@gmail.com>
+Legend Lee <guanxian.li@intel.com>
+Leith Bade <leith@leithalweapon.geek.nz>
+Li Yin <li.yin@intel.com>
+Lidwine Genevet <lgenevet@cisco.com>
+Lionel Landwerlin <lionel.g.landwerlin@intel.com>
+Lorenzo Stoakes <lstoakes@gmail.com>
+Lu Guanqun <guanqun.lu@gmail.com>
+Lucie Brozkova <lucinka.brozkova@gmail.com>
+Luke Inman-Semerau <luke.semerau@gmail.com>
+Luke Zarko <lukezarko@gmail.com>
+Maarten Lankhorst <m.b.lankhorst@gmail.com>
+Magnus Danielsson <fuzzac@gmail.com>
+Mahesh Kulkarni <mahesh.kk@samsung.com>
+Malcolm Wang <malcolm.2.wang@gmail.com>
+Manish Chhajer <chhajer.m@samsung.com>
+Manuel Braun <thembrown@gmail.com>
+Mao Yujie <maojie0924@gmail.com>
+Mao Yujie <yujie.mao@intel.com>
+Marco Rodrigues <gothicx@gmail.com>
+Mario Sanchez Prada <mario.prada@samsung.com>
+Mark Hahnenberg <mhahnenb@andrew.cmu.edu>
+Mark Seaborn <mrs@mythic-beasts.com>
+Martin Bednorz <m.s.bednorz@gmail.com>
+Martina Kollarova <martina.kollarova@intel.com>
+Masahiro Yado <yado.masa@gmail.com>
+Matheus Bratfisch <matheusbrat@gmail.com>
+Mathias Bynens <mathias@qiwi.be>
+Mathieu Meisser <mmeisser@logitech.com>
+Matt Arpidone <mma.public@gmail.com>
+Matt Strum <mstrum@amazon.com>
+Matthew Demarest <demarem@amazon.com>
+Matthew Robertson <matthewrobertson03@gmail.com>
+Matthew Turk <matthewturk@gmail.com>
+Matthew Willis <appamatto@gmail.com>
+Matthias Reitinger <reimarvin@gmail.com>
+Max Perepelitsyn <pph34r@gmail.com>
+Max Vujovic <mvujovic@adobe.com>
+Mayur Kankanwadi <mayurk.vk@samsung.com>
+Michael Gilbert <floppymaster@gmail.com>
+Michael Lopez <lopes92290@gmail.com>
+Michael Morrison <codebythepound@gmail.com>
+Michael Schechter <mike.schechter@gmail.com>
+Michael Zugelder <michael@zugelder.org>
+Mihai Maerean <mmaerean@adobe.com>
+Mihai Tica <mihai.o.tica@gmail.com>
+Mihai Tica <mitica@adobe.com>
+Mike Tilburg <mtilburg@adobe.com>
+Mikhail Pozdnyakov <mikhail.pozdnyakov@intel.com>
+Mingmin Xie <melvinxie@gmail.com>
+Mirela Budaes <mbudaes@gmail.com>
+Mirela Budaes <mbudaes@adobe.com>
+Mitchell Rosen <mitchellwrosen@chromium.org>
+Miyoung Shin <myid.shin@samsung.com>
+Mohamed I. Hammad <ibraaaa@gmail.com>
+Mohamed Mansour <m0.interactive@gmail.com>
+Mohammed Wajahat Ali Siddiqui <wajahat.s@samsung.com>
+Mohan Reddy <mohan.reddy@samsung.com>
+Mrunal Kapade <mrunal.kapade@intel.com>
+Myles C. Maxfield <mymax@amazon.com>
+Nagarjuna Atluri <nagarjuna.a@samsung.com>
+Naiem Shaik <naiem.shaik@gmail.com>
+Naoki Takano <takano.naoki@gmail.com>
+Naveen Bobbili <naveenbobbili@motorola.com>
+Naveen Bobbili <qghc36@motorola.com>
+Naveen Kumar S G <naveensg@samsung.com>
+Nayan Kumar K <qtc746@motorola.com>
+Nedeljko Babic <nedeljko.babic@imgtec.com>
+Nikhil Bansal <n.bansal@samsung.com>
+Nikita Ofitserov <himikof@gmail.com>
+Ningxin Hu <ningxin.hu@intel.com>
+Nitish Mehrotra <nitish.m@samsung.com>
+Pan Deng <pan.deng@intel.com>
+Parag Radke <nrqv63@motorola.com>
+Paritosh Kumar <paritosh.in@samsung.com>
+Patrasciuc Sorin Cristian <cristian.patrasciuc@gmail.com>
+Patrick Kettner <patrickkettner@gmail.com>
+Patrick Riordan <patrickriordan177@gmail.com>
+Patrik Ackland <patrikackland@gmail.com>
+Paul Adolph <padolph@netflix.com>
+Paul Kehrer <paul.l.kehrer@gmail.com>
+Paul Lind <paul.lind@imgtec.com>
+Paul Nettleship <pnettleship@gmail.com>
+Paul Robinson <paulrobinson85@googlemail.com>
+Paul Roskell <blurrech@gmail.com>
+Paul Wicks <pwicks86@gmail.com>
+Pavan Kumar Emani <pavan.e@samsung.com>
+Pavel Ivanov <paivanof@gmail.com>
+Paweł Hajdan jr <phajdan.jr@gmail.com>
+Pawel Forysiuk <p.forysiuk@samsung.com>
+Peng Jiang <leiyi.jp@gmail.com>
+Petar Jovanovic <petarj@mips.com>
+Peter Beverloo <peter@chromium.org>
+Peter Bright <drpizza@quiscalusmexicanus.org>
+Peter Brophy <pbrophy@adobe.com>
+Peter Collingbourne <peter@pcc.me.uk>
+Peter Gal <pgal.u-szeged@partner.samsung.com>
+Peter Molnar <pmolnar.u-szeged@partner.samsung.com>
+Philippe Beauchamp <philippe.beauchamp@gmail.com>
+Philippe Beaudoin <philippe.beaudoin@gmail.com>
+Pierre-Antoine LaFayette <pierre.lafayette@gmail.com>
+Po-Chun Chang <pochang0403@gmail.com>
+Pramod Begur Srinath <pramod.bs@samsung.com>
+Pranay Kumar <pranay.kumar@samsung.com>
+Prashant Hiremath <prashhir@cisco.com>
+Prashant Nevase <prashant.n@samsung.com>
+Praveen Akkiraju <praveen.anp@samsung.com>
+Pritam Nikam <pritam.nikam@samsung.com>
+Puttaraju R <puttaraju.r@samsung.com>
+Qiankun Miao <qiankun.miao@intel.com>
+Qing Zhang <qing.zhang@intel.com>
+Qi Yang <qi1988.yang@samsung.com>
+Radu Stavila <stavila@adobe.com>
+Rafael Antognolli <rafael.antognolli@intel.com>
+Raghavendra Ghatage <r.ghatage@samsung.com>
+Rahul Gupta <rahul.g@samsung.com>
+Raman Tenneti <raman.tenneti@gmail.com>
+Ramkumar Gokarnesan <ramkumar.gokarnesan@gmail.com>
+Ramkumar Ramachandra <artagnon@gmail.com>
+Ramya Vadlamudi <ramya.v@samsung.com>
+Randy Posynick <randy.posynick@gmail.com>
+Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>
+Ravi Phaneendra Kasibhatla <r.kasibhatla@samsung.com>
+Ravi Phaneendra Kasibhatla <ravi.kasibhatla@motorola.com>
+Renata Hodovan <rhodovan.u-szeged@partner.samsung.com>
+Rene Bolldorf <rb@radix.io>
+Rene Ladan <r.c.ladan@gmail.com>
+Rijubrata Bhaumik <rijubrata.bhaumik@intel.com>
+Rob Buis <rob.buis@samsung.com>
+Rob Wu <rob@robwu.nl>
+Robert Bear Travis <bear.travis@gmail.com>
+Robert Bear Travis <betravis@adobe.com>
+Robert Bradford <robert.bradford@intel.com>
+Robert Goldberg <goldberg@adobe.com>
+Robert Hogan <robhogan@gmail.com>
+Robert Nagy <robert.nagy@gmail.com>
+Robert Sesek <rsesek@bluestatic.org>
+Roland Takacs <rtakacs.u-szeged@partner.samsung.com>
+Rosen Dash <nqk836@motorola.com>
+Rosen Dash <rosen.dash@gmail.com>
+ruben <chromium@hybridsource.org>
+Ruben Terrazas <rubentopo@gmail.com>
+Ruiyi Luo <luoruiyi2008@gmail.com>
+Ryan Ackley <ryanackley@gmail.com>
+Ryan Norton <rnorton10@gmail.com>
+Ryan Sleevi <ryan-chromium-dev@sleevi.com>
+Ryan Yoakum <ryoakum@skobalt.com>
+Ryuan Choi <ryuan.choi@samsung.com>
+Saikrishna Arcot <saiarcot895@gmail.com>
+Salvatore Iovene <salvatore.iovene@intel.com>
+Sam Larison <qufighter@gmail.com>
+Sam McDonald <sam@sammcd.com>
+Sanghyun Park <sh919.park@samsung.com>
+Sanjoy Pal <ncj674@motorola.com>
+Sanjoy Pal <sanjoy.pal@samsung.com>
+Sanne Wouda <sanne.wouda@gmail.com>
+Santosh Mahto <samahto@cisco.com>
+Sarath Singapati <s.singapati@samsung.com>
+Saravanan KR <sramajay@cisco.com>
+Sathish Kuppuswamy <sathish.kuppuswamy@intel.com>
+Satoshi Matsuzaki <satoshi.matsuzaki@gmail.com>
+Sayan Nayak <sayan.nayak@samsung.com>
+Scott Blomquist <sblom@microsoft.com>
+Sean Bryant <sean@cyberwang.net>
+Seo Sanghyeon <sanxiyn@gmail.com>
+Seokju Kwon <seokju.kwon@gmail.com>
+Sergey Putilin <p.sergey@samsung.com>
+Sergio Carlos Morales Angeles <carloschilazo@gmail.com>
+Sergiy Byelozyorov <rryk.ua@gmail.com>
+Seshadri Mahalingam <seshadri.mahalingam@gmail.com>
+Sevan Janiyan <venture37@geeklan.co.uk>
+ShankarGanesh K <blr.bmlab@gmail.com>
+Sherry Mou <wenjinm@amazon.com>
+Shez Baig <sbaig1@bloomberg.net>
+Shiliu Wang <aofdwsl@gmail.com>
+Shiliu Wang <shiliu.wang@intel.com>
+Shilpa Shri <shilpa.shri@samsung.com>
+Shivakumar JM <shiva.jm@samsung.com>
+Shouqun Liu <shouqun.liu@intel.com>
+Shreeram Kushwaha <shreeram.k@samsung.com>
+Shreyas Gopal <shreyas.g@samsung.com>
+Shreyas VA <v.a.shreyas@gmail.com>
+Siba Samal <siba.samal@samsung.com>
+Simon Arlott <simon.arlott@gmail.com>
+Siva Kumar Gunturi <siva.gunturi@samsung.com>
+Sohan Jyoti Ghosh <sohan.jyoti@samsung.com>
+Song YeWen <ffmpeg@gmail.com>
+Soren Dreijer <dreijerbit@gmail.com>
+Srirama Chandra Sekhar Mogali <srirama.m@samsung.com>
+Stephen Searles <stephen.searles@gmail.com>
+Steven Pennington <spenn@engr.uvic.ca>
+Subrahmanya Praveen Munukutla <sataya.m@samsung.com>
+Suchit Agrawal <a.suchit@samsung.com>
+Sudarsana Babu Nagineni <sudarsana.nagineni@intel.com>
+Sudarshan Parthasarathy <sudarshan.p@samsung.com>
+Sujith S S <sujiths.s@samsung.com>
+Sungguk Lim <limasdf@gmail.com>
+Sungmann Cho <sungmann.cho@gmail.com>
+Sungmann Cho <sungmann.cho@navercorp.com>
+Suyash Sengar <suyash.s@samsung.com>
+Sunil Ratnu <sunil.ratnu@samsung.com>
+Swati Jaiswal <swa.jaiswal@samsung.com>
+Sylvain Zimmer <sylvinus@gmail.com>
+Szymon Piechowicz <szymonpiechowicz@o2.pl>
+Takeshi Kurosawa <taken.spc@gmail.com>
+Tapu Kumar Ghose <ghose.tapu@gmail.com>
+Taylor Price <trprice@gmail.com>
+Ted Kim <neot0000@gmail.com>
+Ted Vessenes <tedvessenes@gmail.com>
+Teodora Novkovic <teodora.petrovic@gmail.com>
+Thiago Farina <thiago.farina@gmail.com>
+Thiago Marcos P. Santos <thiago.santos@intel.com>
+Thomas Butter <tbutter@gmail.com>
+Thomas Conti <tomc@amazon.com>
+Tiago Vignatti <tiago.vignatti@intel.com>
+Tim Ansell <mithro@mithis.com>
+Timo Reimann <ttr314@googlemail.com>
+Torsten Kurbad <google@tk-webart.de>
+Trevor Perrin <unsafe@trevp.net>
+U. Artie Eoff <ullysses.a.eoff@intel.com>
+Umar Hansa <umar.hansa@gmail.com>
+Vamshikrishna Yellenki <vamshi@motorola.com>
+Vani Hegde <vani.hegde@samsung.com>
+Vartul Katiyar <vartul.k@samsung.com>
+Vedran Šajatović <vedran.sajatovic@gmail.com>
+Vernon Tang <vt@foilhead.net>
+Viatcheslav Ostapenko <sl.ostapenko@samsung.com>
+Victor Costan <costan@gmail.com>
+Viet-Trung Luu <viettrungluu@gmail.com>
+Vinay Anantharaman <vinaya@adobe.com>
+Vipul Bhasin <vipul.bhasin@gmail.com>
+Visa Putkinen <v.putkinen@partner.samsung.com>
+Vivek Galatage <vivek.vg@samsung.com>
+Volker Sorge <volker.sorge@gmail.com>
+Wesley Lancel <wesleylancel@gmail.com>
+Will Hirsch <chromium@willhirsch.co.uk>
+William Xie <william.xie@intel.com>
+Xiang Long <xiang.long@intel.com>
+Xinchao He <hexinchao@gmail.com>
+Xing Zhang <xzhang@adobe.com>
+Xu Samuel <samuel.xu@intel.com>
+Xuefei Ren <xrenishere@gmail.com>
+Xun Sun <xun.sun@intel.com>
+Yael Aharon <yael.aharon@intel.com>
+Yair Yogev <progame@chromium.org>
+Yang Gu <yang.gu@intel.com>
+Yarin Kaul <yarin.kaul@gmail.com>
+Ye Liu <cbakgly@gmail.com>
+Yi Shen <yi.shen@samsung.com>
+Yi Sun <ratsunny@gmail.com>
+Yoav Weiss <yoav@yoav.ws>
+Yoav Zilberberg <yoav.zilberberg@gmail.com>
+Yong Shin <sy3620@gmail.com>
+Yongsheng Zhu <yongsheng.zhu@intel.com>
+Yoshinori Sano <yoshinori.sano@gmail.com>
+YoungKi Hong <simon.hong81@gmail.com>
+Youngsun Suh <zard17@gmail.com>
+Yumikiyo Osanai <yumios.art@gmail.com>
+Yunchao He <yunchao.he@intel.com>
+Yuri Gorobets <yuri.gorobets@gmail.com>
+Zeno Albisser <zeno.albisser@digia.com>
+Zhaoze Zhou <zhaoze.zhou@partner.samsung.com>
+Zheng Chuang <zhengchuangscu@gmail.com>
+Zhenyu Liang <zhenyu.liang@intel.com>
+Zhenyu Shan <zhenyu.shan@intel.com>
+Zhuoyu Qian <zhuoyu.qian@samsung.com>
+Ziran Sun <ziran.sun@samsung.com>
+Zoltan Herczeg <zherczeg.u-szeged@partner.samsung.com>
+Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com>
+Yongha Lee <yongha78.lee@samsung.com>
+方觉 (Fang Jue) <fangjue23303@gmail.com>
+Yupei Wang <perryuwang@tencent.com>
+Peng Hu <penghu@tencent.com>
+WenSheng He <wensheng.he@samsung.com>
+Raghu Ram Nagaraj <r.nagaraj@samsung.com>
+Chanho Park <parkch98@gmail.com>
+Payal Pandey <payal.pandey@samsung.com>
+Kenneth Strickland <ken.strickland@gmail.com>
+Olli Syrjälä <olli.syrjala@intel.com>
+Vishal Bhatnagar <vishal.b@samsung.com>
+Yunsik Jang <yunsik.jang@lge.com>
+Siddharth Bagai <b.siddharth@samsung.com>
+
+BlackBerry Limited <*@blackberry.com>
+Code Aurora Forum <*@codeaurora.org>
+Comodo CA Limited
+Google Inc. <*@google.com>
+Igalia S.L. <*@igalia.com>
+NVIDIA Corporation <*@nvidia.com>
+Opera Software ASA <*@opera.com>
+TeamSpeak Systems GmbH <*@teamspeak.com>
+The Chromium Authors <*@chromium.org>
+The MathWorks, Inc. <binod.pant@mathworks.com>
+Torchmobile Inc.
+Venture 3 Systems LLC <*@venture3systems.com>
+Yandex LLC <*@yandex-team.ru>
+ARM Holdings <*@arm.com>
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..972bb2e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/BUILD.gn b/base/BUILD.gn
new file mode 100644
index 0000000..dc3a737
--- /dev/null
+++ b/base/BUILD.gn
@@ -0,0 +1,1510 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+import("//testing/test.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+config("base_implementation") {
+  defines = [ "BASE_IMPLEMENTATION" ]
+}
+
+if (is_win) {
+  # This is in a separate config so the flags can be applied to dependents.
+  # ldflags in GN aren't automatically inherited.
+  config("base_win_linker_flags") {
+    ldflags = [
+      "/DELAYLOAD:cfgmgr32.dll",
+      "/DELAYLOAD:powrprof.dll",
+      "/DELAYLOAD:setupapi.dll",
+    ]
+  }
+}
+
+source_set("base_paths") {
+  sources = [
+    "base_paths.cc",
+    "base_paths.h",
+    "base_paths_android.cc",
+    "base_paths_android.h",
+    "base_paths_mac.h",
+    "base_paths_mac.mm",
+    "base_paths_posix.cc",
+    "base_paths_posix.h",
+    "base_paths_win.cc",
+    "base_paths_win.h",
+  ]
+
+  if (is_android || is_mac) {
+    sources -= [ "base_paths_posix.cc" ]
+  }
+
+  if (is_nacl) {
+    sources -= [
+      "base_paths.cc",
+      "base_paths_posix.cc",
+    ]
+  }
+
+  configs += [ ":base_implementation" ]
+
+  deps = [
+    "//base/memory",
+    "//base/process",
+  ]
+
+  visibility = [ ":base" ]
+}
+
+component("base") {
+  sources = [
+    "allocator/allocator_extension.cc",
+    "allocator/allocator_extension.h",
+    "allocator/type_profiler_control.cc",
+    "allocator/type_profiler_control.h",
+    "android/animation_frame_time_histogram.cc",
+    "android/animation_frame_time_histogram.h",
+    "android/application_status_listener.cc",
+    "android/application_status_listener.h",
+    "android/base_jni_onload.cc",
+    "android/base_jni_onload.h",
+    "android/base_jni_registrar.cc",
+    "android/base_jni_registrar.h",
+    "android/build_info.cc",
+    "android/build_info.h",
+    "android/command_line_android.cc",
+    "android/command_line_android.h",
+    "android/content_uri_utils.cc",
+    "android/content_uri_utils.h",
+    "android/cpu_features.cc",
+    "android/event_log.cc",
+    "android/event_log.h",
+    "android/field_trial_list.cc",
+    "android/field_trial_list.h",
+    "android/fifo_utils.cc",
+    "android/fifo_utils.h",
+    "android/important_file_writer_android.cc",
+    "android/important_file_writer_android.h",
+    "android/java_handler_thread.cc",
+    "android/java_handler_thread.h",
+    "android/java_runtime.cc",
+    "android/java_runtime.h",
+    "android/jni_android.cc",
+    "android/jni_android.h",
+    "android/jni_array.cc",
+    "android/jni_array.h",
+    "android/jni_registrar.cc",
+    "android/jni_registrar.h",
+    "android/jni_string.cc",
+    "android/jni_string.h",
+    "android/jni_utils.cc",
+    "android/jni_utils.h",
+    "android/jni_weak_ref.cc",
+    "android/jni_weak_ref.h",
+    "android/library_loader/library_load_from_apk_status_codes.h",
+    "android/library_loader/library_loader_hooks.cc",
+    "android/library_loader/library_loader_hooks.h",
+    "android/library_loader/library_prefetcher.cc",
+    "android/library_loader/library_prefetcher.h",
+    "android/locale_utils.cc",
+    "android/locale_utils.h",
+    "android/memory_pressure_listener_android.cc",
+    "android/memory_pressure_listener_android.h",
+    "android/path_service_android.cc",
+    "android/path_service_android.h",
+    "android/path_utils.cc",
+    "android/path_utils.h",
+    "android/record_histogram.cc",
+    "android/record_histogram.h",
+    "android/record_user_action.cc",
+    "android/record_user_action.h",
+    "android/scoped_java_ref.cc",
+    "android/scoped_java_ref.h",
+    "android/sys_utils.cc",
+    "android/sys_utils.h",
+    "android/thread_utils.h",
+    "android/trace_event_binding.cc",
+    "android/trace_event_binding.h",
+    "async_socket_io_handler.h",
+    "async_socket_io_handler_posix.cc",
+    "async_socket_io_handler_win.cc",
+    "at_exit.cc",
+    "at_exit.h",
+    "atomic_ref_count.h",
+    "atomic_sequence_num.h",
+    "atomicops.h",
+    "atomicops_internals_gcc.h",
+    "atomicops_internals_mac.h",
+    "atomicops_internals_portable.h",
+    "atomicops_internals_x86_gcc.cc",
+    "atomicops_internals_x86_gcc.h",
+    "atomicops_internals_x86_msvc.h",
+    "auto_reset.h",
+    "barrier_closure.cc",
+    "barrier_closure.h",
+    "base64.cc",
+    "base64.h",
+    "base_export.h",
+    "base_switches.h",
+    "basictypes.h",
+    "big_endian.cc",
+    "big_endian.h",
+    "bind.h",
+    "bind_helpers.cc",
+    "bind_helpers.h",
+    "bind_internal.h",
+    "bind_internal_win.h",
+    "bits.h",
+    "build_time.cc",
+    "build_time.h",
+    "callback.h",
+    "callback_helpers.cc",
+    "callback_helpers.h",
+    "callback_internal.cc",
+    "callback_internal.h",
+    "cancelable_callback.h",
+    "chromeos/memory_pressure_monitor_chromeos.cc",
+    "chromeos/memory_pressure_monitor_chromeos.h",
+    "command_line.cc",
+    "command_line.h",
+    "compiler_specific.h",
+    "containers/adapters.h",
+    "containers/hash_tables.h",
+    "containers/linked_list.h",
+    "containers/mru_cache.h",
+    "containers/scoped_ptr_hash_map.h",
+    "containers/small_map.h",
+    "containers/stack_container.h",
+    "cpu.cc",
+    "cpu.h",
+    "critical_closure.h",
+    "critical_closure_internal_ios.mm",
+    "deferred_sequenced_task_runner.cc",
+    "deferred_sequenced_task_runner.h",
+    "environment.cc",
+    "environment.h",
+    "file_descriptor_posix.h",
+    "file_version_info.h",
+    "file_version_info_mac.h",
+    "file_version_info_mac.mm",
+    "file_version_info_win.cc",
+    "file_version_info_win.h",
+    "files/dir_reader_fallback.h",
+    "files/dir_reader_linux.h",
+    "files/dir_reader_posix.h",
+    "files/file.cc",
+    "files/file_enumerator.cc",
+    "files/file_enumerator.h",
+    "files/file_enumerator_posix.cc",
+    "files/file_enumerator_win.cc",
+    "files/file_path.cc",
+    "files/file_path.h",
+    "files/file_path_constants.cc",
+    "files/file_path_watcher.cc",
+    "files/file_path_watcher.h",
+    "files/file_path_watcher_fsevents.cc",
+    "files/file_path_watcher_fsevents.h",
+    "files/file_path_watcher_kqueue.cc",
+    "files/file_path_watcher_kqueue.h",
+    "files/file_path_watcher_linux.cc",
+    "files/file_path_watcher_mac.cc",
+    "files/file_path_watcher_win.cc",
+    "files/file_posix.cc",
+    "files/file_proxy.cc",
+    "files/file_proxy.h",
+    "files/file_util.cc",
+    "files/file_util.h",
+    "files/file_util_android.cc",
+    "files/file_util_linux.cc",
+    "files/file_util_mac.mm",
+    "files/file_util_posix.cc",
+    "files/file_util_proxy.cc",
+    "files/file_util_proxy.h",
+    "files/file_util_win.cc",
+    "files/file_win.cc",
+    "files/important_file_writer.cc",
+    "files/important_file_writer.h",
+    "files/memory_mapped_file.cc",
+    "files/memory_mapped_file.h",
+    "files/memory_mapped_file_posix.cc",
+    "files/memory_mapped_file_win.cc",
+    "files/scoped_file.cc",
+    "files/scoped_file.h",
+    "files/scoped_temp_dir.cc",
+    "files/scoped_temp_dir.h",
+    "format_macros.h",
+    "gtest_prod_util.h",
+    "guid.cc",
+    "guid.h",
+    "guid_posix.cc",
+    "guid_win.cc",
+    "hash.cc",
+    "hash.h",
+    "id_map.h",
+    "ios/device_util.h",
+    "ios/device_util.mm",
+    "ios/ios_util.h",
+    "ios/ios_util.mm",
+    "ios/scoped_critical_action.h",
+    "ios/scoped_critical_action.mm",
+    "ios/weak_nsobject.h",
+    "ios/weak_nsobject.mm",
+    "lazy_instance.cc",
+    "lazy_instance.h",
+    "linux_util.cc",
+    "linux_util.h",
+    "location.cc",
+    "location.h",
+    "logging.cc",
+    "logging.h",
+    "logging_win.cc",
+    "logging_win.h",
+    "mac/authorization_util.h",
+    "mac/authorization_util.mm",
+    "mac/bind_objc_block.h",
+    "mac/bundle_locations.h",
+    "mac/bundle_locations.mm",
+    "mac/cocoa_protocols.h",
+    "mac/foundation_util.h",
+    "mac/foundation_util.mm",
+    "mac/launch_services_util.cc",
+    "mac/launch_services_util.h",
+    "mac/launchd.cc",
+    "mac/launchd.h",
+    "mac/libdispatch_task_runner.cc",
+    "mac/libdispatch_task_runner.h",
+    "mac/mac_logging.cc",
+    "mac/mac_logging.h",
+    "mac/mac_util.h",
+    "mac/mac_util.mm",
+    "mac/mach_logging.cc",
+    "mac/mach_logging.h",
+    "mac/memory_pressure_monitor_mac.cc",
+    "mac/memory_pressure_monitor_mac.h",
+    "mac/objc_property_releaser.h",
+    "mac/objc_property_releaser.mm",
+    "mac/os_crash_dumps.cc",
+    "mac/os_crash_dumps.h",
+    "mac/scoped_aedesc.h",
+    "mac/scoped_authorizationref.h",
+    "mac/scoped_block.h",
+    "mac/scoped_cftyperef.h",
+    "mac/scoped_ioobject.h",
+    "mac/scoped_ioplugininterface.h",
+    "mac/scoped_launch_data.h",
+    "mac/scoped_mach_port.cc",
+    "mac/scoped_mach_port.h",
+    "mac/scoped_mach_vm.cc",
+    "mac/scoped_mach_vm.h",
+    "mac/scoped_nsautorelease_pool.h",
+    "mac/scoped_nsautorelease_pool.mm",
+    "mac/scoped_nsexception_enabler.h",
+    "mac/scoped_nsexception_enabler.mm",
+    "mac/scoped_nsobject.h",
+    "mac/scoped_objc_class_swizzler.h",
+    "mac/scoped_objc_class_swizzler.mm",
+    "mac/scoped_sending_event.h",
+    "mac/scoped_sending_event.mm",
+    "mac/sdk_forward_declarations.h",
+    "mac/sdk_forward_declarations.mm",
+    "macros.h",
+    "md5.cc",
+    "md5.h",
+    "message_loop/incoming_task_queue.cc",
+    "message_loop/incoming_task_queue.h",
+    "message_loop/message_loop.cc",
+    "message_loop/message_loop.h",
+    "message_loop/message_loop_proxy.cc",
+    "message_loop/message_loop_proxy.h",
+    "message_loop/message_loop_proxy_impl.cc",
+    "message_loop/message_loop_proxy_impl.h",
+    "message_loop/message_pump.cc",
+    "message_loop/message_pump.h",
+    "message_loop/message_pump_android.cc",
+    "message_loop/message_pump_android.h",
+    "message_loop/message_pump_default.cc",
+    "message_loop/message_pump_default.h",
+    "message_loop/message_pump_glib.cc",
+    "message_loop/message_pump_glib.h",
+    "message_loop/message_pump_io_ios.cc",
+    "message_loop/message_pump_io_ios.h",
+    "message_loop/message_pump_libevent.cc",
+    "message_loop/message_pump_libevent.h",
+    "message_loop/message_pump_mac.h",
+    "message_loop/message_pump_mac.mm",
+    "message_loop/message_pump_win.cc",
+    "message_loop/message_pump_win.h",
+    "move.h",
+    "native_library.h",
+    "native_library_ios.mm",
+    "native_library_mac.mm",
+    "native_library_posix.cc",
+    "native_library_win.cc",
+    "nix/mime_util_xdg.cc",
+    "nix/mime_util_xdg.h",
+    "nix/xdg_util.cc",
+    "nix/xdg_util.h",
+    "numerics/safe_conversions.h",
+    "numerics/safe_conversions_impl.h",
+    "numerics/safe_math.h",
+    "numerics/safe_math_impl.h",
+    "observer_list.h",
+    "observer_list_threadsafe.h",
+    "os_compat_android.cc",
+    "os_compat_android.h",
+    "os_compat_nacl.cc",
+    "os_compat_nacl.h",
+    "path_service.cc",
+    "path_service.h",
+    "pending_task.cc",
+    "pending_task.h",
+    "pickle.cc",
+    "pickle.h",
+    "port.h",
+    "posix/eintr_wrapper.h",
+    "posix/file_descriptor_shuffle.cc",
+    "posix/global_descriptors.cc",
+    "posix/global_descriptors.h",
+    "posix/unix_domain_socket_linux.cc",
+    "posix/unix_domain_socket_linux.h",
+    "power_monitor/power_monitor.cc",
+    "power_monitor/power_monitor.h",
+    "power_monitor/power_monitor_device_source.cc",
+    "power_monitor/power_monitor_device_source.h",
+    "power_monitor/power_monitor_device_source_android.cc",
+    "power_monitor/power_monitor_device_source_android.h",
+    "power_monitor/power_monitor_device_source_chromeos.cc",
+    "power_monitor/power_monitor_device_source_ios.mm",
+    "power_monitor/power_monitor_device_source_mac.mm",
+    "power_monitor/power_monitor_device_source_posix.cc",
+    "power_monitor/power_monitor_device_source_win.cc",
+    "power_monitor/power_monitor_source.cc",
+    "power_monitor/power_monitor_source.h",
+    "power_monitor/power_observer.h",
+    "profiler/alternate_timer.cc",
+    "profiler/alternate_timer.h",
+    "profiler/native_stack_sampler.cc",
+    "profiler/native_stack_sampler.h",
+    "profiler/scoped_profile.cc",
+    "profiler/scoped_profile.h",
+    "profiler/scoped_tracker.cc",
+    "profiler/scoped_tracker.h",
+    "profiler/stack_sampling_profiler.cc",
+    "profiler/stack_sampling_profiler.h",
+    "profiler/stack_sampling_profiler_posix.cc",
+    "profiler/stack_sampling_profiler_win.cc",
+    "profiler/tracked_time.cc",
+    "profiler/tracked_time.h",
+    "rand_util.cc",
+    "rand_util.h",
+    "rand_util_nacl.cc",
+    "rand_util_posix.cc",
+    "rand_util_win.cc",
+    "run_loop.cc",
+    "run_loop.h",
+    "safe_strerror_posix.cc",
+    "safe_strerror_posix.h",
+    "scoped_generic.h",
+    "scoped_native_library.cc",
+    "scoped_native_library.h",
+    "scoped_observer.h",
+    "sequence_checker.h",
+    "sequence_checker_impl.cc",
+    "sequence_checker_impl.h",
+    "sequenced_task_runner.cc",
+    "sequenced_task_runner.h",
+    "sequenced_task_runner_helpers.h",
+    "sha1.h",
+    "sha1_portable.cc",
+    "sha1_win.cc",
+    "single_thread_task_runner.h",
+    "stl_util.h",
+    "strings/latin1_string_conversions.cc",
+    "strings/latin1_string_conversions.h",
+    "strings/nullable_string16.cc",
+    "strings/nullable_string16.h",
+    "strings/safe_sprintf.cc",
+    "strings/safe_sprintf.h",
+    "strings/string16.cc",
+    "strings/string16.h",
+    "strings/string_number_conversions.cc",
+    "strings/string_number_conversions.h",
+    "strings/string_piece.cc",
+    "strings/string_piece.h",
+    "strings/string_split.cc",
+    "strings/string_split.h",
+    "strings/string_tokenizer.h",
+    "strings/string_util.cc",
+    "strings/string_util.h",
+    "strings/string_util_constants.cc",
+    "strings/string_util_posix.h",
+    "strings/string_util_win.h",
+    "strings/stringize_macros.h",
+    "strings/stringprintf.cc",
+    "strings/stringprintf.h",
+    "strings/sys_string_conversions.h",
+    "strings/sys_string_conversions_mac.mm",
+    "strings/sys_string_conversions_posix.cc",
+    "strings/sys_string_conversions_win.cc",
+    "strings/utf_offset_string_conversions.cc",
+    "strings/utf_offset_string_conversions.h",
+    "strings/utf_string_conversion_utils.cc",
+    "strings/utf_string_conversion_utils.h",
+    "strings/utf_string_conversions.cc",
+    "strings/utf_string_conversions.h",
+    "supports_user_data.cc",
+    "supports_user_data.h",
+    "sync_socket.h",
+    "sync_socket_posix.cc",
+    "sync_socket_win.cc",
+    "synchronization/cancellation_flag.cc",
+    "synchronization/cancellation_flag.h",
+    "synchronization/condition_variable.h",
+    "synchronization/condition_variable_posix.cc",
+    "synchronization/condition_variable_win.cc",
+    "synchronization/lock.cc",
+    "synchronization/lock.h",
+    "synchronization/lock_impl.h",
+    "synchronization/lock_impl_posix.cc",
+    "synchronization/lock_impl_win.cc",
+    "synchronization/spin_wait.h",
+    "synchronization/waitable_event.h",
+    "synchronization/waitable_event_posix.cc",
+    "synchronization/waitable_event_watcher.h",
+    "synchronization/waitable_event_watcher_posix.cc",
+    "synchronization/waitable_event_watcher_win.cc",
+    "synchronization/waitable_event_win.cc",
+    "sys_byteorder.h",
+    "sys_info.cc",
+    "sys_info.h",
+    "sys_info_android.cc",
+    "sys_info_chromeos.cc",
+    "sys_info_freebsd.cc",
+    "sys_info_ios.mm",
+    "sys_info_linux.cc",
+    "sys_info_mac.cc",
+    "sys_info_openbsd.cc",
+    "sys_info_posix.cc",
+    "sys_info_win.cc",
+    "system_monitor/system_monitor.cc",
+    "system_monitor/system_monitor.h",
+    "task/cancelable_task_tracker.cc",
+    "task/cancelable_task_tracker.h",
+    "task_runner.cc",
+    "task_runner.h",
+    "task_runner_util.h",
+    "template_util.h",
+    "third_party/dmg_fp/dmg_fp.h",
+    "third_party/dmg_fp/dtoa_wrapper.cc",
+    "third_party/dmg_fp/g_fmt.cc",
+    "third_party/icu/icu_utf.cc",
+    "third_party/icu/icu_utf.h",
+    "third_party/nspr/prtime.cc",
+    "third_party/nspr/prtime.h",
+    "third_party/superfasthash/superfasthash.c",
+    "thread_task_runner_handle.cc",
+    "thread_task_runner_handle.h",
+    "threading/non_thread_safe.h",
+    "threading/non_thread_safe_impl.cc",
+    "threading/non_thread_safe_impl.h",
+    "threading/platform_thread.h",
+    "threading/platform_thread_android.cc",
+    "threading/platform_thread_internal_posix.cc",
+    "threading/platform_thread_internal_posix.h",
+    "threading/platform_thread_linux.cc",
+    "threading/platform_thread_mac.mm",
+    "threading/platform_thread_posix.cc",
+    "threading/platform_thread_win.cc",
+    "threading/post_task_and_reply_impl.cc",
+    "threading/post_task_and_reply_impl.h",
+    "threading/sequenced_worker_pool.cc",
+    "threading/sequenced_worker_pool.h",
+    "threading/simple_thread.cc",
+    "threading/simple_thread.h",
+    "threading/thread.cc",
+    "threading/thread.h",
+    "threading/thread_checker.h",
+    "threading/thread_checker_impl.cc",
+    "threading/thread_checker_impl.h",
+    "threading/thread_collision_warner.cc",
+    "threading/thread_collision_warner.h",
+    "threading/thread_id_name_manager.cc",
+    "threading/thread_id_name_manager.h",
+    "threading/thread_local.h",
+    "threading/thread_local_android.cc",
+    "threading/thread_local_posix.cc",
+    "threading/thread_local_storage.cc",
+    "threading/thread_local_storage.h",
+    "threading/thread_local_storage_posix.cc",
+    "threading/thread_local_storage_win.cc",
+    "threading/thread_local_win.cc",
+    "threading/thread_restrictions.cc",
+    "threading/thread_restrictions.h",
+    "threading/watchdog.cc",
+    "threading/watchdog.h",
+    "threading/worker_pool.cc",
+    "threading/worker_pool.h",
+    "threading/worker_pool_posix.cc",
+    "threading/worker_pool_posix.h",
+    "threading/worker_pool_win.cc",
+    "time/clock.cc",
+    "time/clock.h",
+    "time/default_clock.cc",
+    "time/default_clock.h",
+    "time/default_tick_clock.cc",
+    "time/default_tick_clock.h",
+    "time/tick_clock.cc",
+    "time/tick_clock.h",
+    "time/time.cc",
+    "time/time.h",
+    "time/time_mac.cc",
+    "time/time_posix.cc",
+    "time/time_win.cc",
+    "timer/elapsed_timer.cc",
+    "timer/elapsed_timer.h",
+    "timer/hi_res_timer_manager.h",
+    "timer/hi_res_timer_manager_posix.cc",
+    "timer/hi_res_timer_manager_win.cc",
+    "timer/mock_timer.cc",
+    "timer/mock_timer.h",
+    "timer/timer.cc",
+    "timer/timer.h",
+    "tracked_objects.cc",
+    "tracked_objects.h",
+    "tracking_info.cc",
+    "tracking_info.h",
+    "tuple.h",
+    "value_conversions.cc",
+    "value_conversions.h",
+    "values.cc",
+    "values.h",
+    "version.cc",
+    "version.h",
+    "vlog.cc",
+    "vlog.h",
+    "win/enum_variant.cc",
+    "win/enum_variant.h",
+    "win/event_trace_consumer.h",
+    "win/event_trace_controller.cc",
+    "win/event_trace_controller.h",
+    "win/event_trace_provider.cc",
+    "win/event_trace_provider.h",
+    "win/i18n.cc",
+    "win/i18n.h",
+    "win/iat_patch_function.cc",
+    "win/iat_patch_function.h",
+    "win/iunknown_impl.cc",
+    "win/iunknown_impl.h",
+    "win/memory_pressure_monitor.cc",
+    "win/memory_pressure_monitor.h",
+    "win/message_window.cc",
+    "win/message_window.h",
+    "win/metro.cc",
+    "win/metro.h",
+    "win/object_watcher.cc",
+    "win/object_watcher.h",
+    "win/registry.cc",
+    "win/registry.h",
+    "win/resource_util.cc",
+    "win/resource_util.h",
+    "win/scoped_bstr.cc",
+    "win/scoped_bstr.h",
+    "win/scoped_co_mem.h",
+    "win/scoped_com_initializer.h",
+    "win/scoped_comptr.h",
+    "win/scoped_gdi_object.h",
+    "win/scoped_handle.cc",
+    "win/scoped_handle.h",
+    "win/scoped_hdc.h",
+    "win/scoped_hglobal.h",
+    "win/scoped_process_information.cc",
+    "win/scoped_process_information.h",
+    "win/scoped_propvariant.h",
+    "win/scoped_select_object.h",
+    "win/scoped_variant.cc",
+    "win/scoped_variant.h",
+    "win/shortcut.cc",
+    "win/shortcut.h",
+    "win/startup_information.cc",
+    "win/startup_information.h",
+    "win/win_util.cc",
+    "win/win_util.h",
+    "win/windows_version.cc",
+    "win/windows_version.h",
+    "win/wrapped_window_proc.cc",
+    "win/wrapped_window_proc.h",
+  ]
+
+  sources -= [
+    "sys_info_freebsd.cc",
+    "sys_info_openbsd.cc",
+  ]
+
+  configs += [ ":base_implementation" ]
+
+  deps = [
+    ":base_static",
+    "//base/allocator:allocator_extension_thunks",
+    "//base/third_party/dynamic_annotations",
+    "//third_party/modp_b64",
+  ]
+
+  public_deps = [
+    ":base_paths",
+    "//base/debug",
+    "//base/json",
+    "//base/memory",
+    "//base/metrics",
+    "//base/process",
+    "//base/trace_event",
+  ]
+
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos) {
+    defines = [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
+  if (is_android) {
+    sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [
+      "files/file_path_watcher_linux.cc",
+      "posix/unix_domain_socket_linux.cc",
+      "sys_info_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    deps += [
+      ":base_jni_headers",
+      "//third_party/ashmem",
+      "//third_party/android_tools:cpu_features",
+    ]
+
+    # logging.cc uses the Android logging library.
+    libs = [ "log" ]
+  }
+
+  if (is_chromeos) {
+    sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+  }
+
+  if (is_nacl) {
+    # We reset sources_assignment_filter in order to explicitly include
+    # the linux file (which would otherwise be filtered out).
+    set_sources_assignment_filter([])
+    sources += [
+      "files/file_path_watcher_stub.cc",
+      "sync_socket_nacl.cc",
+      "threading/platform_thread_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    sources -= [
+      "allocator/type_profiler_control.cc",
+      "allocator/type_profiler_control.h",
+      "async_socket_io_handler_posix.cc",
+      "cpu.cc",
+      "files/file_enumerator_posix.cc",
+      "files/file_proxy.cc",
+      "files/file_util.cc",
+      "files/file_util_posix.cc",
+      "files/file_util_proxy.cc",
+      "files/important_file_writer.cc",
+      "files/important_file_writer.h",
+      "files/scoped_temp_dir.cc",
+      "message_loop/message_pump_libevent.cc",
+      "native_library_posix.cc",
+      "path_service.cc",
+      "rand_util_posix.cc",
+      "scoped_native_library.cc",
+      "sync_socket_posix.cc",
+      "sys_info.cc",
+      "sys_info_posix.cc",
+    ]
+  } else {
+    # Remove NaCl stuff.
+    sources -= [
+      "os_compat_nacl.cc",
+      "os_compat_nacl.h",
+      "rand_util_nacl.cc",
+    ]
+  }
+
+  # Windows.
+  if (is_win) {
+    sources -= [
+      "message_loop/message_pump_libevent.cc",
+      "strings/string16.cc",
+
+      # Not using sha1_win.cc because it may have caused a
+      # regression to page cycler moz.
+      "sha1_win.cc",
+    ]
+
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+    libs = [
+      "cfgmgr32.lib",
+      "netapi32.lib",
+      "powrprof.lib",
+      "setupapi.lib",
+    ]
+    all_dependent_configs = [ ":base_win_linker_flags" ]
+  } else if (!is_nacl) {
+    # Non-Windows.
+    deps += [ "//third_party/libevent" ]
+  }
+
+  # Mac.
+  if (is_mac) {
+    sources -= [
+      "native_library_posix.cc",
+      "strings/sys_string_conversions_posix.cc",
+      "threading/platform_thread_internal_posix.cc",
+    ]
+  } else {
+    # Non-Mac.
+    sources -= [
+      "files/file_path_watcher_fsevents.cc",
+      "files/file_path_watcher_fsevents.h",
+      "files/file_path_watcher_kqueue.cc",
+      "files/file_path_watcher_kqueue.h",
+    ]
+  }
+
+  # Linux.
+  if (is_linux) {
+    # TODO(brettw) this will need to be parameterized at some point.
+    linux_configs = []
+    if (use_glib) {
+      linux_configs += [ "//build/config/linux:glib" ]
+    }
+
+    configs += linux_configs
+    all_dependent_configs = linux_configs
+
+    # These dependencies are not required on Android, and in the case
+    # of xdg_mime must be excluded due to licensing restrictions.
+    deps += [
+      "//base/third_party/xdg_mime",
+      "//base/third_party/xdg_user_dirs",
+    ]
+  } else {
+    # Non-Linux.
+    sources -= [
+      "nix/mime_util_xdg.cc",
+      "nix/mime_util_xdg.h",
+      "nix/xdg_util.cc",
+      "nix/xdg_util.h",
+    ]
+
+    if (!is_android) {
+      sources -= [
+        "linux_util.cc",
+        "linux_util.h",
+      ]
+    }
+  }
+
+  if (!use_glib) {
+    sources -= [
+      "message_loop/message_pump_glib.cc",
+      "message_loop/message_pump_glib.h",
+    ]
+  }
+
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+
+  allow_circular_includes_from = public_deps
+}
+
+# This is the subset of files from base that should not be used with a dynamic
+# library. Note that this library cannot depend on base because base depends on
+# base_static.
+source_set("base_static") {
+  sources = [
+    "base_switches.cc",
+    "base_switches.h",
+    "win/pe_image.cc",
+    "win/pe_image.h",
+  ]
+
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
+
+component("i18n") {
+  output_name = "base_i18n"
+  sources = [
+    "i18n/base_i18n_export.h",
+    "i18n/bidi_line_iterator.cc",
+    "i18n/bidi_line_iterator.h",
+    "i18n/break_iterator.cc",
+    "i18n/break_iterator.h",
+    "i18n/case_conversion.cc",
+    "i18n/case_conversion.h",
+    "i18n/char_iterator.cc",
+    "i18n/char_iterator.h",
+    "i18n/file_util_icu.cc",
+    "i18n/file_util_icu.h",
+    "i18n/i18n_constants.cc",
+    "i18n/i18n_constants.h",
+    "i18n/icu_encoding_detection.cc",
+    "i18n/icu_encoding_detection.h",
+    "i18n/icu_string_conversions.cc",
+    "i18n/icu_string_conversions.h",
+    "i18n/icu_util.cc",
+    "i18n/icu_util.h",
+    "i18n/number_formatting.cc",
+    "i18n/number_formatting.h",
+    "i18n/rtl.cc",
+    "i18n/rtl.h",
+    "i18n/streaming_utf8_validator.cc",
+    "i18n/streaming_utf8_validator.h",
+    "i18n/string_compare.cc",
+    "i18n/string_compare.h",
+    "i18n/string_search.cc",
+    "i18n/string_search.h",
+    "i18n/time_formatting.cc",
+    "i18n/time_formatting.h",
+    "i18n/timezone.cc",
+    "i18n/timezone.h",
+    "i18n/utf8_validator_tables.cc",
+    "i18n/utf8_validator_tables.h",
+  ]
+  defines = [ "BASE_I18N_IMPLEMENTATION" ]
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  deps = [
+    ":base",
+    "//base/third_party/dynamic_annotations",
+    "//third_party/icu",
+  ]
+
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+}
+
+if (is_win || (is_linux && !is_chromeos)) {
+  # TODO(GYP): Figure out which of these work and are needed on other platforms.
+  test("base_perftests") {
+    sources = [
+      "message_loop/message_pump_perftest.cc",
+
+      # "test/run_all_unittests.cc",
+      "threading/thread_perftest.cc",
+    ]
+    deps = [
+      ":base",
+      "//base/test:test_support",
+      "//base/test:test_support_perf",
+      "//testing/perf",
+      "//testing/gtest",
+    ]
+
+    if (is_android) {
+      deps += [ "//testing/android/native_test:native_test_native_code" ]
+    }
+  }
+
+  test("base_i18n_perftests") {
+    sources = [
+      "i18n/streaming_utf8_validator_perftest.cc",
+    ]
+    deps = [
+      ":base",
+      ":i18n",
+      "//base/test:test_support",
+      "//base/test:test_support_perf",
+      "//testing/gtest",
+    ]
+  }
+
+  if (!is_ios) {
+    executable("build_utf8_validator_tables") {
+      sources = [
+        "i18n/build_utf8_validator_tables.cc",
+      ]
+      deps = [
+        ":base",
+        "//third_party/icu:icuuc",
+      ]
+    }
+
+    executable("check_example") {
+      sources = [
+        "check_example.cc",
+      ]
+      deps = [
+        ":base",
+      ]
+    }
+  }
+}
+
+component("prefs") {
+  sources = [
+    "prefs/base_prefs_export.h",
+    "prefs/default_pref_store.cc",
+    "prefs/default_pref_store.h",
+    "prefs/json_pref_store.cc",
+    "prefs/json_pref_store.h",
+    "prefs/overlay_user_pref_store.cc",
+    "prefs/overlay_user_pref_store.h",
+    "prefs/persistent_pref_store.h",
+    "prefs/pref_change_registrar.cc",
+    "prefs/pref_change_registrar.h",
+    "prefs/pref_filter.h",
+    "prefs/pref_member.cc",
+    "prefs/pref_member.h",
+    "prefs/pref_notifier.h",
+    "prefs/pref_notifier_impl.cc",
+    "prefs/pref_notifier_impl.h",
+    "prefs/pref_observer.h",
+    "prefs/pref_registry.cc",
+    "prefs/pref_registry.h",
+    "prefs/pref_registry_simple.cc",
+    "prefs/pref_registry_simple.h",
+    "prefs/pref_service.cc",
+    "prefs/pref_service.h",
+    "prefs/pref_service_factory.cc",
+    "prefs/pref_service_factory.h",
+    "prefs/pref_store.cc",
+    "prefs/pref_store.h",
+    "prefs/pref_value_map.cc",
+    "prefs/pref_value_map.h",
+    "prefs/pref_value_store.cc",
+    "prefs/pref_value_store.h",
+    "prefs/scoped_user_pref_update.cc",
+    "prefs/scoped_user_pref_update.h",
+    "prefs/value_map_pref_store.cc",
+    "prefs/value_map_pref_store.h",
+    "prefs/writeable_pref_store.h",
+  ]
+
+  defines = [ "BASE_PREFS_IMPLEMENTATION" ]
+
+  deps = [
+    ":base",
+  ]
+
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
+
+source_set("prefs_test_support") {
+  testonly = true
+  sources = [
+    "prefs/mock_pref_change_callback.cc",
+    "prefs/mock_pref_change_callback.h",
+    "prefs/pref_store_observer_mock.cc",
+    "prefs/pref_store_observer_mock.h",
+    "prefs/testing_pref_service.cc",
+    "prefs/testing_pref_service.h",
+    "prefs/testing_pref_store.cc",
+    "prefs/testing_pref_store.h",
+  ]
+
+  public_deps = [
+    ":prefs",
+  ]
+  deps = [
+    ":base",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+source_set("message_loop_tests") {
+  testonly = true
+  sources = [
+    "message_loop/message_loop_test.cc",
+    "message_loop/message_loop_test.h",
+  ]
+
+  deps = [
+    ":base",
+    "//testing/gtest",
+  ]
+}
+
+if (is_win) {
+  # Target to manually rebuild pe_image_test.dll which is checked into
+  # base/test/data/pe_image.
+  shared_library("pe_image_test") {
+    sources = [
+      "win/pe_image_test.cc",
+    ]
+    ldflags = [
+      "/DELAYLOAD:cfgmgr32.dll",
+      "/DELAYLOAD:shell32.dll",
+      "/SUBSYSTEM:WINDOWS",
+    ]
+    libs = [
+      "cfgmgr32.lib",
+      "shell32.lib",
+    ]
+  }
+}
+
+test("base_unittests") {
+  sources = [
+    "android/application_status_listener_unittest.cc",
+    "android/content_uri_utils_unittest.cc",
+    "android/jni_android_unittest.cc",
+    "android/jni_array_unittest.cc",
+    "android/jni_string_unittest.cc",
+    "android/library_loader/library_prefetcher_unittest.cc",
+    "android/path_utils_unittest.cc",
+    "android/scoped_java_ref_unittest.cc",
+    "android/sys_utils_unittest.cc",
+    "async_socket_io_handler_unittest.cc",
+    "at_exit_unittest.cc",
+    "atomicops_unittest.cc",
+    "barrier_closure_unittest.cc",
+    "base64_unittest.cc",
+    "big_endian_unittest.cc",
+    "bind_unittest.cc",
+    "bind_unittest.nc",
+    "bits_unittest.cc",
+    "build_time_unittest.cc",
+    "callback_helpers_unittest.cc",
+    "callback_list_unittest.cc",
+    "callback_list_unittest.nc",
+    "callback_unittest.cc",
+    "callback_unittest.nc",
+    "cancelable_callback_unittest.cc",
+    "chromeos/memory_pressure_monitor_chromeos_unittest.cc",
+    "command_line_unittest.cc",
+    "containers/adapters_unittest.cc",
+    "containers/hash_tables_unittest.cc",
+    "containers/linked_list_unittest.cc",
+    "containers/mru_cache_unittest.cc",
+    "containers/scoped_ptr_hash_map_unittest.cc",
+    "containers/small_map_unittest.cc",
+    "containers/stack_container_unittest.cc",
+    "cpu_unittest.cc",
+    "debug/crash_logging_unittest.cc",
+    "debug/debugger_unittest.cc",
+    "debug/leak_tracker_unittest.cc",
+    "debug/proc_maps_linux_unittest.cc",
+    "debug/stack_trace_unittest.cc",
+    "debug/task_annotator_unittest.cc",
+    "deferred_sequenced_task_runner_unittest.cc",
+    "environment_unittest.cc",
+    "file_version_info_unittest.cc",
+    "files/dir_reader_posix_unittest.cc",
+    "files/file_path_unittest.cc",
+    "files/file_path_watcher_unittest.cc",
+    "files/file_proxy_unittest.cc",
+    "files/file_unittest.cc",
+    "files/file_util_proxy_unittest.cc",
+    "files/file_util_unittest.cc",
+    "files/important_file_writer_unittest.cc",
+    "files/scoped_temp_dir_unittest.cc",
+    "gmock_unittest.cc",
+    "guid_unittest.cc",
+    "hash_unittest.cc",
+    "i18n/break_iterator_unittest.cc",
+    "i18n/case_conversion_unittest.cc",
+    "i18n/char_iterator_unittest.cc",
+    "i18n/file_util_icu_unittest.cc",
+    "i18n/icu_string_conversions_unittest.cc",
+    "i18n/number_formatting_unittest.cc",
+    "i18n/rtl_unittest.cc",
+    "i18n/streaming_utf8_validator_unittest.cc",
+    "i18n/string_search_unittest.cc",
+    "i18n/time_formatting_unittest.cc",
+    "i18n/timezone_unittest.cc",
+    "id_map_unittest.cc",
+    "ios/device_util_unittest.mm",
+    "ios/weak_nsobject_unittest.mm",
+    "json/json_parser_unittest.cc",
+    "json/json_reader_unittest.cc",
+    "json/json_value_converter_unittest.cc",
+    "json/json_value_serializer_unittest.cc",
+    "json/json_writer_unittest.cc",
+    "json/string_escape_unittest.cc",
+    "lazy_instance_unittest.cc",
+    "logging_unittest.cc",
+    "mac/bind_objc_block_unittest.mm",
+    "mac/foundation_util_unittest.mm",
+    "mac/libdispatch_task_runner_unittest.cc",
+    "mac/mac_util_unittest.mm",
+    "mac/objc_property_releaser_unittest.mm",
+    "mac/scoped_nsobject_unittest.mm",
+    "mac/scoped_objc_class_swizzler_unittest.mm",
+    "mac/scoped_sending_event_unittest.mm",
+    "md5_unittest.cc",
+    "memory/aligned_memory_unittest.cc",
+    "memory/discardable_shared_memory_unittest.cc",
+    "memory/linked_ptr_unittest.cc",
+    "memory/ref_counted_memory_unittest.cc",
+    "memory/ref_counted_unittest.cc",
+    "memory/scoped_ptr_unittest.cc",
+    "memory/scoped_ptr_unittest.nc",
+    "memory/scoped_vector_unittest.cc",
+    "memory/shared_memory_unittest.cc",
+    "memory/singleton_unittest.cc",
+    "memory/weak_ptr_unittest.cc",
+    "memory/weak_ptr_unittest.nc",
+    "message_loop/message_loop_proxy_impl_unittest.cc",
+    "message_loop/message_loop_proxy_unittest.cc",
+    "message_loop/message_loop_unittest.cc",
+    "message_loop/message_pump_glib_unittest.cc",
+    "message_loop/message_pump_io_ios_unittest.cc",
+    "metrics/bucket_ranges_unittest.cc",
+    "metrics/field_trial_unittest.cc",
+    "metrics/histogram_base_unittest.cc",
+    "metrics/histogram_delta_serialization_unittest.cc",
+    "metrics/histogram_snapshot_manager_unittest.cc",
+    "metrics/histogram_unittest.cc",
+    "metrics/sample_map_unittest.cc",
+    "metrics/sample_vector_unittest.cc",
+    "metrics/sparse_histogram_unittest.cc",
+    "metrics/statistics_recorder_unittest.cc",
+    "move_unittest.cc",
+    "numerics/safe_numerics_unittest.cc",
+    "observer_list_unittest.cc",
+    "os_compat_android_unittest.cc",
+    "path_service_unittest.cc",
+    "pickle_unittest.cc",
+    "posix/file_descriptor_shuffle_unittest.cc",
+    "posix/unix_domain_socket_linux_unittest.cc",
+    "power_monitor/power_monitor_unittest.cc",
+    "prefs/default_pref_store_unittest.cc",
+    "prefs/json_pref_store_unittest.cc",
+    "prefs/overlay_user_pref_store_unittest.cc",
+    "prefs/pref_change_registrar_unittest.cc",
+    "prefs/pref_member_unittest.cc",
+    "prefs/pref_notifier_impl_unittest.cc",
+    "prefs/pref_service_unittest.cc",
+    "prefs/pref_value_map_unittest.cc",
+    "prefs/pref_value_store_unittest.cc",
+    "prefs/scoped_user_pref_update_unittest.cc",
+    "process/memory_unittest.cc",
+    "process/memory_unittest_mac.h",
+    "process/memory_unittest_mac.mm",
+    "process/process_metrics_unittest.cc",
+    "process/process_metrics_unittest_ios.cc",
+    "process/process_unittest.cc",
+    "process/process_util_unittest.cc",
+    "process/process_util_unittest_ios.cc",
+    "profiler/stack_sampling_profiler_unittest.cc",
+    "profiler/tracked_time_unittest.cc",
+    "rand_util_unittest.cc",
+    "scoped_clear_errno_unittest.cc",
+    "scoped_generic_unittest.cc",
+    "scoped_native_library_unittest.cc",
+    "security_unittest.cc",
+    "sequence_checker_unittest.cc",
+    "sha1_unittest.cc",
+    "stl_util_unittest.cc",
+    "strings/nullable_string16_unittest.cc",
+    "strings/safe_sprintf_unittest.cc",
+    "strings/string16_unittest.cc",
+    "strings/string_number_conversions_unittest.cc",
+    "strings/string_piece_unittest.cc",
+    "strings/string_split_unittest.cc",
+    "strings/string_tokenizer_unittest.cc",
+    "strings/string_util_unittest.cc",
+    "strings/stringize_macros_unittest.cc",
+    "strings/stringprintf_unittest.cc",
+    "strings/sys_string_conversions_mac_unittest.mm",
+    "strings/sys_string_conversions_unittest.cc",
+    "strings/utf_offset_string_conversions_unittest.cc",
+    "strings/utf_string_conversions_unittest.cc",
+    "supports_user_data_unittest.cc",
+    "sync_socket_unittest.cc",
+    "synchronization/cancellation_flag_unittest.cc",
+    "synchronization/condition_variable_unittest.cc",
+    "synchronization/lock_unittest.cc",
+    "synchronization/waitable_event_unittest.cc",
+    "synchronization/waitable_event_watcher_unittest.cc",
+    "sys_info_unittest.cc",
+    "system_monitor/system_monitor_unittest.cc",
+    "task/cancelable_task_tracker_unittest.cc",
+    "task_runner_util_unittest.cc",
+    "template_util_unittest.cc",
+    "test/expectations/expectation_unittest.cc",
+    "test/expectations/parser_unittest.cc",
+    "test/histogram_tester_unittest.cc",
+    "test/test_reg_util_win_unittest.cc",
+    "test/trace_event_analyzer_unittest.cc",
+    "test/user_action_tester_unittest.cc",
+    "threading/non_thread_safe_unittest.cc",
+    "threading/platform_thread_unittest.cc",
+    "threading/sequenced_worker_pool_unittest.cc",
+    "threading/simple_thread_unittest.cc",
+    "threading/thread_checker_unittest.cc",
+    "threading/thread_collision_warner_unittest.cc",
+    "threading/thread_id_name_manager_unittest.cc",
+    "threading/thread_local_storage_unittest.cc",
+    "threading/thread_local_unittest.cc",
+    "threading/thread_unittest.cc",
+    "threading/watchdog_unittest.cc",
+    "threading/worker_pool_posix_unittest.cc",
+    "threading/worker_pool_unittest.cc",
+    "time/pr_time_unittest.cc",
+    "time/time_unittest.cc",
+    "time/time_win_unittest.cc",
+    "timer/hi_res_timer_manager_unittest.cc",
+    "timer/mock_timer_unittest.cc",
+    "timer/timer_unittest.cc",
+    "tools_sanity_unittest.cc",
+    "tracked_objects_unittest.cc",
+    "tuple_unittest.cc",
+    "values_unittest.cc",
+    "version_unittest.cc",
+    "vlog_unittest.cc",
+    "win/dllmain.cc",
+    "win/enum_variant_unittest.cc",
+    "win/event_trace_consumer_unittest.cc",
+    "win/event_trace_controller_unittest.cc",
+    "win/event_trace_provider_unittest.cc",
+    "win/i18n_unittest.cc",
+    "win/iunknown_impl_unittest.cc",
+    "win/memory_pressure_monitor_unittest.cc",
+    "win/message_window_unittest.cc",
+    "win/object_watcher_unittest.cc",
+    "win/pe_image_unittest.cc",
+    "win/registry_unittest.cc",
+    "win/scoped_bstr_unittest.cc",
+    "win/scoped_comptr_unittest.cc",
+    "win/scoped_process_information_unittest.cc",
+    "win/scoped_variant_unittest.cc",
+    "win/shortcut_unittest.cc",
+    "win/startup_information_unittest.cc",
+    "win/win_util_unittest.cc",
+    "win/wrapped_window_proc_unittest.cc",
+  ]
+
+  deps = [
+    ":base",
+    ":i18n",
+    ":message_loop_tests",
+    ":prefs",
+    ":prefs_test_support",
+    "//base/allocator",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//base/third_party/dynamic_annotations",
+    "//base/trace_event:trace_event_unittests",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/icu",
+  ]
+
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos) {
+    defines = [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
+  if (is_android) {
+    apk_deps = [
+      ":base_java",
+      ":base_java_unittest_support",
+    ]
+  }
+
+  if (is_ios) {
+    sources -= [
+      "process/memory_unittest.cc",
+      "process/memory_unittest_mac.h",
+      "process/memory_unittest_mac.mm",
+      "process/process_unittest.cc",
+      "process/process_util_unittest.cc",
+    ]
+
+    # Pull in specific Mac files for iOS (which have been filtered out by file
+    # name rules).
+    set_sources_assignment_filter([])
+    sources += [
+      "mac/bind_objc_block_unittest.mm",
+      "mac/foundation_util_unittest.mm",
+      "mac/objc_property_releaser_unittest.mm",
+      "mac/scoped_nsobject_unittest.mm",
+      "sys_string_conversions_mac_unittest.mm",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    # TODO(GYP): dep on copy_test_data_ios action.
+  }
+
+  if (is_linux) {
+    sources -= [ "file_version_info_unittest.cc" ]
+    sources += [ "nix/xdg_util_unittest.cc" ]
+    deps += [ "//base/test:malloc_wrapper" ]
+
+    if (use_glib) {
+      configs += [ "//build/config/linux:glib" ]
+    }
+  }
+
+  if (!is_linux || use_ozone) {
+    sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
+  }
+
+  if (is_posix || is_ios) {
+    sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
+    deps += [ "//third_party/libevent" ]
+  }
+
+  if (is_android) {
+    deps += [ "//testing/android/native_test:native_test_native_code" ]
+    set_sources_assignment_filter([])
+    sources += [ "debug/proc_maps_linux_unittest.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+}
+
+if (is_android) {
+  # GYP: //base.gyp:base_jni_headers
+  generate_jni("base_jni_headers") {
+    sources = [
+      "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java",
+      "android/java/src/org/chromium/base/ApplicationStatus.java",
+      "android/java/src/org/chromium/base/BuildInfo.java",
+      "android/java/src/org/chromium/base/CommandLine.java",
+      "android/java/src/org/chromium/base/ContentUriUtils.java",
+      "android/java/src/org/chromium/base/CpuFeatures.java",
+      "android/java/src/org/chromium/base/EventLog.java",
+      "android/java/src/org/chromium/base/FieldTrialList.java",
+      "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
+      "android/java/src/org/chromium/base/JNIUtils.java",
+      "android/java/src/org/chromium/base/JavaHandlerThread.java",
+      "android/java/src/org/chromium/base/LocaleUtils.java",
+      "android/java/src/org/chromium/base/MemoryPressureListener.java",
+      "android/java/src/org/chromium/base/PathService.java",
+      "android/java/src/org/chromium/base/PathUtils.java",
+      "android/java/src/org/chromium/base/PowerMonitor.java",
+      "android/java/src/org/chromium/base/SysUtils.java",
+      "android/java/src/org/chromium/base/SystemMessageHandler.java",
+      "android/java/src/org/chromium/base/ThreadUtils.java",
+      "android/java/src/org/chromium/base/TraceEvent.java",
+      "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
+      "android/java/src/org/chromium/base/metrics/RecordHistogram.java",
+      "android/java/src/org/chromium/base/metrics/RecordUserAction.java",
+    ]
+
+    deps = [
+      ":android_runtime_jni_headers",
+    ]
+
+    jni_package = "base"
+  }
+
+  # GYP: //base.gyp:android_runtime_jni_headers
+  generate_jar_jni("android_runtime_jni_headers") {
+    jni_package = "base"
+    classes = [ "java/lang/Runtime.class" ]
+  }
+
+  # GYP: //base.gyp:base_java
+  android_library("base_java") {
+    srcjar_deps = [
+      ":base_android_java_enums_srcjar",
+      ":base_native_libraries_gen",
+    ]
+
+    deps = [
+      "//third_party/jsr-305:jsr_305_javalib",
+    ]
+
+    DEPRECATED_java_in_dir = "android/java/src"
+
+    # A new version of NativeLibraries.java (with the actual correct values)
+    # will be created when creating an apk.
+    jar_excluded_patterns = [
+      "*/NativeLibraries.class",
+      "*/NativeLibraries##*.class",
+    ]
+  }
+
+  # GYP: //base.gyp:base_javatests
+  android_library("base_javatests") {
+    deps = [
+      ":base_java",
+      ":base_java_test_support",
+    ]
+    DEPRECATED_java_in_dir = "android/javatests/src"
+  }
+
+  # GYP: //base.gyp:base_java_test_support
+  android_library("base_java_test_support") {
+    deps = [
+      ":base_java",
+      "//testing/android/reporter:reporter_java",
+    ]
+    DEPRECATED_java_in_dir = "test/android/javatests/src"
+  }
+
+  # GYP: //base.gyp:base_junit_tests
+  junit_binary("base_junit_tests") {
+    java_files = [ "android/junit/src/org/chromium/base/LogTest.java" ]
+    deps = [
+      ":base_java",
+      ":base_java_test_support",
+    ]
+  }
+
+  # GYP: //base.gyp:base_java_application_state
+  # GYP: //base.gyp:base_java_library_load_from_apk_status_codes
+  # GYP: //base.gyp:base_java_library_process_type
+  # GYP: //base.gyp:base_java_memory_pressure_level
+  java_cpp_enum("base_android_java_enums_srcjar") {
+    sources = [
+      "android/application_status_listener.h",
+      "android/library_loader/library_load_from_apk_status_codes.h",
+      "android/library_loader/library_loader_hooks.h",
+      "memory/memory_pressure_listener.h",
+    ]
+    outputs = [
+      "org/chromium/base/ApplicationState.java",
+      "org/chromium/base/library_loader/LibraryLoadFromApkStatusCodes.java",
+      "org/chromium/base/library_loader/LibraryProcessType.java",
+      "org/chromium/base/MemoryPressureLevel.java",
+    ]
+  }
+
+  # GYP: //base/base.gyp:base_native_libraries_gen
+  java_cpp_template("base_native_libraries_gen") {
+    sources = [
+      "android/java/templates/NativeLibraries.template",
+    ]
+    package_name = "org/chromium/base/library_loader"
+  }
+
+  # GYP: //base.gyp:base_java_unittest_support
+  android_library("base_java_unittest_support") {
+    deps = [
+      ":base_java",
+    ]
+    java_files =
+        [ "test/android/java/src/org/chromium/base/ContentUriTestUtils.java" ]
+  }
+}
diff --git a/base/DEPS b/base/DEPS
new file mode 100644
index 0000000..c632e35
--- /dev/null
+++ b/base/DEPS
@@ -0,0 +1,17 @@
+include_rules = [
+  "+jni",
+  "+third_party/ashmem",
+  "+third_party/apple_apsl",
+  "+third_party/libevent",
+  "+third_party/dmg_fp",
+  "+third_party/mach_override",
+  "+third_party/modp_b64",
+  "+third_party/tcmalloc",
+
+  # These are implicitly brought in from the root, and we don't want them.
+  "-ipc",
+  "-url",
+
+  # ICU dependendencies must be separate from the rest of base.
+  "-i18n",
+]
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 0000000..9890491
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,31 @@
+mark@chromium.org
+darin@chromium.org
+thakis@chromium.org
+danakj@chromium.org
+rvargas@chromium.org
+thestig@chromium.org
+
+# On extended leave.
+willchan@chromium.org
+
+# Chromium is a very mature project, most things that are generally useful are
+# already here, and that things not here aren't generally useful.
+#
+# Base is pulled into many projects. For example, various ChromeOS daemons. So
+# the bar for adding stuff is that it must have demonstrated wide
+# applicability. Prefer to add things closer to where they're used (i.e. "not
+# base"), and pull into base only when needed.  In a project our size,
+# sometimes even duplication is OK and inevitable.
+#
+# Adding a new logging macro DPVELOG_NE is not more clear than just
+# writing the stuff you want to log in a regular logging statement, even
+# if it makes your calling code longer. Just add it to your own code.
+
+per-file *.isolate=csharp@chromium.org
+per-file *.isolate=maruel@chromium.org
+per-file security_unittest.cc=jln@chromium.org
+
+# For Android-specific changes:
+per-file *android*=nyquist@chromium.org
+per-file *android*=rmcilroy@chromium.org
+per-file *android*=yfriedman@chromium.org
diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py
new file mode 100644
index 0000000..7fc8107
--- /dev/null
+++ b/base/PRESUBMIT.py
@@ -0,0 +1,49 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Chromium presubmit script for src/base.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into depot_tools.
+"""
+
+def _CheckNoInterfacesInBase(input_api, output_api):
+  """Checks to make sure no files in libbase.a have |@interface|."""
+  pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE)
+  files = []
+  for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
+    if (f.LocalPath().startswith('base/') and
+        not "/ios/" in f.LocalPath() and
+        not "/test/" in f.LocalPath() and
+        not f.LocalPath().endswith('_unittest.mm') and
+        not f.LocalPath().endswith('mac/sdk_forward_declarations.h')):
+      contents = input_api.ReadFile(f)
+      if pattern.search(contents):
+        files.append(f)
+
+  if len(files):
+    return [ output_api.PresubmitError(
+        'Objective-C interfaces or categories are forbidden in libbase. ' +
+        'See http://groups.google.com/a/chromium.org/group/chromium-dev/' +
+        'browse_thread/thread/efb28c10435987fd',
+        files) ]
+  return []
+
+
+def _CommonChecks(input_api, output_api):
+  """Checks common to both upload and commit."""
+  results = []
+  results.extend(_CheckNoInterfacesInBase(input_api, output_api))
+  return results
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
new file mode 100644
index 0000000..a07a356
--- /dev/null
+++ b/base/allocator/BUILD.gn
@@ -0,0 +1,259 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/allocator.gni")
+
+# Only executables and not libraries should depend on the allocator target;
+# only the application (the final executable) knows what allocator makes sense.
+# This "allocator" meta-target will forward to the default allocator according
+# to the build settings.
+group("allocator") {
+  if (use_allocator == "tcmalloc") {
+    deps = [
+      ":tcmalloc",
+    ]
+  }
+}
+
+# This config and libc modification are only used on Windows.
+if (is_win) {
+  import("//build/config/win/visual_studio_version.gni")
+
+  config("nocmt") {
+    ldflags = [
+      "/NODEFAULTLIB:libcmt",
+      "/NODEFAULTLIB:libcmtd",
+    ]
+    libs = [ rebase_path("$target_gen_dir/allocator/libcmt.lib") ]
+  }
+
+  action("prep_libc") {
+    script = "prep_libc.py"
+    outputs = [
+      "$target_gen_dir/allocator/libcmt.lib",
+    ]
+    args = [
+      visual_studio_path + "/vc/lib",
+      rebase_path("$target_gen_dir/allocator"),
+      current_cpu,
+    ]
+  }
+}
+
+if (use_allocator == "tcmalloc") {
+  # tcmalloc currently won't compile on Android.
+  source_set("tcmalloc") {
+    tcmalloc_dir = "//third_party/tcmalloc/chromium"
+
+    # Don't check tcmalloc's includes. These files include various files like
+    # base/foo.h and they actually refer to tcmalloc's forked copy of base
+    # rather than the regular one, which confuses the header checker.
+    check_includes = false
+
+    sources = [
+      # Generated for our configuration from tcmalloc"s build
+      # and checked in.
+      "$tcmalloc_dir/src/config.h",
+      "$tcmalloc_dir/src/config_android.h",
+      "$tcmalloc_dir/src/config_linux.h",
+      "$tcmalloc_dir/src/config_win.h",
+
+      # tcmalloc native and forked files.
+      "$tcmalloc_dir/src/base/abort.cc",
+      "$tcmalloc_dir/src/base/abort.h",
+      "$tcmalloc_dir/src/base/arm_instruction_set_select.h",
+
+      # We don't list dynamic_annotations.c since its copy is already
+      # present in the dynamic_annotations target.
+      "$tcmalloc_dir/src/base/elf_mem_image.cc",
+      "$tcmalloc_dir/src/base/elf_mem_image.h",
+      "$tcmalloc_dir/src/base/linuxthreads.cc",
+      "$tcmalloc_dir/src/base/linuxthreads.h",
+      "$tcmalloc_dir/src/base/logging.cc",
+      "$tcmalloc_dir/src/base/logging.h",
+      "$tcmalloc_dir/src/base/low_level_alloc.cc",
+      "$tcmalloc_dir/src/base/low_level_alloc.h",
+      "$tcmalloc_dir/src/base/spinlock.cc",
+      "$tcmalloc_dir/src/base/spinlock.h",
+      "$tcmalloc_dir/src/base/spinlock_internal.cc",
+      "$tcmalloc_dir/src/base/spinlock_internal.h",
+      "$tcmalloc_dir/src/base/synchronization_profiling.h",
+      "$tcmalloc_dir/src/base/sysinfo.cc",
+      "$tcmalloc_dir/src/base/sysinfo.h",
+      "$tcmalloc_dir/src/base/thread_lister.c",
+      "$tcmalloc_dir/src/base/thread_lister.h",
+      "$tcmalloc_dir/src/base/vdso_support.cc",
+      "$tcmalloc_dir/src/base/vdso_support.h",
+      "$tcmalloc_dir/src/central_freelist.cc",
+      "$tcmalloc_dir/src/central_freelist.h",
+      "$tcmalloc_dir/src/common.cc",
+      "$tcmalloc_dir/src/common.h",
+
+      # #included by debugallocation_shim.cc
+      #"$tcmalloc_dir/src/debugallocation.cc",
+      "$tcmalloc_dir/src/deep-heap-profile.cc",
+      "$tcmalloc_dir/src/deep-heap-profile.h",
+      "$tcmalloc_dir/src/free_list.cc",
+      "$tcmalloc_dir/src/free_list.h",
+      "$tcmalloc_dir/src/heap-profile-table.cc",
+      "$tcmalloc_dir/src/heap-profile-table.h",
+      "$tcmalloc_dir/src/heap-profiler.cc",
+      "$tcmalloc_dir/src/internal_logging.cc",
+      "$tcmalloc_dir/src/internal_logging.h",
+      "$tcmalloc_dir/src/linked_list.h",
+      "$tcmalloc_dir/src/malloc_extension.cc",
+      "$tcmalloc_dir/src/malloc_hook-inl.h",
+      "$tcmalloc_dir/src/malloc_hook.cc",
+      "$tcmalloc_dir/src/maybe_threads.cc",
+      "$tcmalloc_dir/src/maybe_threads.h",
+      "$tcmalloc_dir/src/memory_region_map.cc",
+      "$tcmalloc_dir/src/memory_region_map.h",
+      "$tcmalloc_dir/src/page_heap.cc",
+      "$tcmalloc_dir/src/page_heap.h",
+      "$tcmalloc_dir/src/profile-handler.cc",
+      "$tcmalloc_dir/src/profile-handler.h",
+      "$tcmalloc_dir/src/profiledata.cc",
+      "$tcmalloc_dir/src/profiledata.h",
+      "$tcmalloc_dir/src/profiler.cc",
+      "$tcmalloc_dir/src/raw_printer.cc",
+      "$tcmalloc_dir/src/raw_printer.h",
+      "$tcmalloc_dir/src/sampler.cc",
+      "$tcmalloc_dir/src/sampler.h",
+      "$tcmalloc_dir/src/span.cc",
+      "$tcmalloc_dir/src/span.h",
+      "$tcmalloc_dir/src/stack_trace_table.cc",
+      "$tcmalloc_dir/src/stack_trace_table.h",
+      "$tcmalloc_dir/src/stacktrace.cc",
+      "$tcmalloc_dir/src/static_vars.cc",
+      "$tcmalloc_dir/src/static_vars.h",
+      "$tcmalloc_dir/src/symbolize.cc",
+      "$tcmalloc_dir/src/symbolize.h",
+      "$tcmalloc_dir/src/system-alloc.cc",
+      "$tcmalloc_dir/src/system-alloc.h",
+
+      # #included by debugallocation_shim.cc
+      #"$tcmalloc_dir/src/tcmalloc.cc",
+      "$tcmalloc_dir/src/thread_cache.cc",
+      "$tcmalloc_dir/src/thread_cache.h",
+      "$tcmalloc_dir/src/windows/port.cc",
+      "$tcmalloc_dir/src/windows/port.h",
+      "allocator_shim.cc",
+      "debugallocation_shim.cc",
+
+      # These are both #included by allocator_shim for maximal linking.
+      #"generic_allocators.cc",
+      #"win_allocator.cc",
+    ]
+
+    # Disable the heap checker in tcmalloc.
+    defines = [ "NO_HEAP_CHECK" ]
+
+    include_dirs = [
+      ".",
+      "$tcmalloc_dir/src/base",
+      "$tcmalloc_dir/src",
+    ]
+
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [ "//build/config/compiler:no_chromium_code" ]
+
+    deps = []
+
+    if (is_win) {
+      sources -= [
+        "$tcmalloc_dir/src/base/elf_mem_image.cc",
+        "$tcmalloc_dir/src/base/elf_mem_image.h",
+        "$tcmalloc_dir/src/base/linuxthreads.cc",
+        "$tcmalloc_dir/src/base/linuxthreads.h",
+        "$tcmalloc_dir/src/base/vdso_support.cc",
+        "$tcmalloc_dir/src/base/vdso_support.h",
+        "$tcmalloc_dir/src/maybe_threads.cc",
+        "$tcmalloc_dir/src/maybe_threads.h",
+        "$tcmalloc_dir/src/symbolize.h",
+        "$tcmalloc_dir/src/system-alloc.cc",
+        "$tcmalloc_dir/src/system-alloc.h",
+
+        # included by allocator_shim.cc
+        "debugallocation_shim.cc",
+
+        # cpuprofiler
+        "$tcmalloc_dir/src/base/thread_lister.c",
+        "$tcmalloc_dir/src/base/thread_lister.h",
+        "$tcmalloc_dir/src/profile-handler.cc",
+        "$tcmalloc_dir/src/profile-handler.h",
+        "$tcmalloc_dir/src/profiledata.cc",
+        "$tcmalloc_dir/src/profiledata.h",
+        "$tcmalloc_dir/src/profiler.cc",
+      ]
+      defines += [ "PERFTOOLS_DLL_DECL=" ]
+
+      configs -= [
+        # Tcmalloc defines this itself, and we don't want duplicate definition
+        # warnings.
+        "//build/config/win:nominmax",
+      ]
+
+      public_configs = [ ":nocmt" ]
+
+      deps += [ ":prep_libc" ]
+    }
+
+    if (is_linux || is_android) {
+      sources -= [
+        "$tcmalloc_dir/src/system-alloc.h",
+        "$tcmalloc_dir/src/windows/port.cc",
+        "$tcmalloc_dir/src/windows/port.h",
+
+        # TODO(willchan): Support allocator shim later on.
+        "allocator_shim.cc",
+      ]
+
+      # We enable all warnings by default, but upstream disables a few.
+      # Keep "-Wno-*" flags in sync with upstream by comparing against:
+      # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+      cflags = [
+        "-Wno-sign-compare",
+        "-Wno-unused-result",
+      ]
+
+      configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
+
+      ldflags = [
+        # Don't let linker rip this symbol out, otherwise the heap&cpu
+        # profilers will not initialize properly on startup.
+        "-Wl,-uIsHeapProfilerRunning,-uProfilerStart",
+
+        # Do the same for heap leak checker.
+        "-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi",
+        "-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl",
+        "-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv",
+      ]
+    }
+
+    # Make sure the allocation library is optimized as much as possible when
+    # we"re in release mode.
+    if (!is_debug) {
+      configs -= [ "//build/config/compiler:optimize" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
+
+    deps += [ "//base/third_party/dynamic_annotations" ]
+
+    if (is_win) {
+      ldflags = [ "/ignore:4006:4221" ]
+    }
+  }
+}  # !is_android
+
+source_set("allocator_extension_thunks") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "allocator_extension_thunks.cc",
+    "allocator_extension_thunks.h",
+  ]
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
diff --git a/base/allocator/README b/base/allocator/README
new file mode 100644
index 0000000..ec8a707
--- /dev/null
+++ b/base/allocator/README
@@ -0,0 +1,59 @@
+Notes about the Chrome memory allocator.
+
+Background
+----------
+We use this library as a generic way to fork into any of several allocators.
+Currently we can, at runtime, switch between:
+   the default windows allocator
+   the windows low-fragmentation-heap
+   tcmalloc
+   jemalloc (the heap used most notably within Mozilla Firefox)
+
+The mechanism for hooking LIBCMT in windows is rather tricky.  The core
+problem is that by default, the windows library does not declare malloc and
+free as weak symbols.  Because of this, they cannot be overriden.  To work
+around this, we start with the LIBCMT.LIB, and manually remove all allocator
+related functions from it using the visual studio library tool.  Once removed,
+we can now link against the library and provide custom versions of the 
+allocator related functionality.
+
+
+Source code
+-----------
+This directory contains just the allocator (i.e. shim) layer that switches
+between the different underlying memory allocation implementations.
+
+The tcmalloc and jemalloc libraries originate outside of Chromium
+and exist in ../../third_party/tcmalloc and ../../third_party/jemalloc
+(currently, the actual locations are defined in the allocator.gyp file).
+The third party sources use a vendor-branch SCM pattern to track
+Chromium-specific changes independently from upstream changes.
+
+The general intent is to push local changes upstream so that over
+time we no longer need any forked files.
+
+
+Adding a new allocator
+----------------------
+Adding a new allocator requires definition of the following five functions:
+
+  extern "C" {
+    bool init();
+    void* malloc(size_t s);
+    void* realloc(void* p, size_t s);
+    void free(void* s);
+    size_t msize(void* p);
+  }
+
+All other allocation related functions (new/delete/calloc/etc) have been
+implemented generically to work across all allocators.
+
+
+Usage
+-----
+You can use the different allocators by setting the environment variable
+CHROME_ALLOCATOR to:
+   "tcmalloc"  - TC Malloc (default)
+   "jemalloc"  - JE Malloc
+   "winheap"   - Windows default heap
+   "winlfh"    - Windows Low-Fragmentation heap
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
new file mode 100644
index 0000000..d426c9c
--- /dev/null
+++ b/base/allocator/allocator.gyp
@@ -0,0 +1,572 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'variables': {
+      # This code gets run a lot and debugged rarely, so it should be fast
+      # by default. See http://crbug.com/388949.
+      'debug_optimize': '2',
+      'win_debug_Optimization': '0',
+      # Run time checks are incompatible with any level of optimizations.
+      'win_debug_RuntimeChecks': '0',
+    },
+  },
+  'variables': {
+    'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
+    'use_vtable_verify%': 0,
+  },
+  'targets': [
+    # Only executables and not libraries should depend on the
+    # allocator target; only the application (the final executable)
+    # knows what allocator makes sense.
+    {
+      'target_name': 'allocator',
+      'type': 'static_library',
+      'direct_dependent_settings': {
+        'configurations': {
+          'Common_Base': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+                'AdditionalDependencies': [
+                  '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+                ],
+              },
+            },
+          },
+        },
+        'conditions': [
+          ['OS=="win"', {
+            'defines': [
+              'PERFTOOLS_DLL_DECL=',
+            ],
+          }],
+        ],
+      },
+      'dependencies': [
+        '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      'msvs_settings': {
+        # TODO(sgk):  merge this with build/common.gypi settings
+        'VCLibrarianTool': {
+          'AdditionalOptions': ['/ignore:4006,4221'],
+        },
+        'VCLinkerTool': {
+          'AdditionalOptions': ['/ignore:4006'],
+        },
+      },
+      'configurations': {
+        'Debug_Base': {
+          'msvs_settings': {
+            'VCCLCompilerTool': {
+              'RuntimeLibrary': '0',
+            },
+          },
+          'variables': {
+            # Provide a way to force disable debugallocation in Debug builds,
+            # e.g. for profiling (it's more rare to profile Debug builds,
+            # but people sometimes need to do that).
+            'disable_debugallocation%': 0,
+          },
+          'conditions': [
+            ['disable_debugallocation==0', {
+              'defines': [
+                # Use debugallocation for Debug builds to catch problems early
+                # and cleanly, http://crbug.com/30715 .
+                'TCMALLOC_FOR_DEBUGALLOCATION',
+              ],
+            }],
+          ],
+        },
+      },
+      'conditions': [
+        ['use_allocator=="tcmalloc"', {
+          # Disable the heap checker in tcmalloc.
+          'defines': [
+            'NO_HEAP_CHECK',
+          ],
+          'include_dirs': [
+            '.',
+            '<(tcmalloc_dir)/src/base',
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            # Generated for our configuration from tcmalloc's build
+            # and checked in.
+            '<(tcmalloc_dir)/src/config.h',
+            '<(tcmalloc_dir)/src/config_android.h',
+            '<(tcmalloc_dir)/src/config_linux.h',
+            '<(tcmalloc_dir)/src/config_win.h',
+
+            # all tcmalloc native and forked files
+            '<(tcmalloc_dir)/src/addressmap-inl.h',
+            '<(tcmalloc_dir)/src/base/abort.cc',
+            '<(tcmalloc_dir)/src/base/abort.h',
+            '<(tcmalloc_dir)/src/base/arm_instruction_set_select.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-arm-generic.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-arm-v6plus.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+            '<(tcmalloc_dir)/src/base/atomicops.h',
+            '<(tcmalloc_dir)/src/base/basictypes.h',
+            '<(tcmalloc_dir)/src/base/commandlineflags.h',
+            '<(tcmalloc_dir)/src/base/cycleclock.h',
+            # We don't list dynamic_annotations.c since its copy is already
+            # present in the dynamic_annotations target.
+            '<(tcmalloc_dir)/src/base/dynamic_annotations.h',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+            '<(tcmalloc_dir)/src/base/elfcore.h',
+            '<(tcmalloc_dir)/src/base/googleinit.h',
+            '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+            '<(tcmalloc_dir)/src/base/linuxthreads.cc',
+            '<(tcmalloc_dir)/src/base/linuxthreads.h',
+            '<(tcmalloc_dir)/src/base/logging.cc',
+            '<(tcmalloc_dir)/src/base/logging.h',
+            '<(tcmalloc_dir)/src/base/low_level_alloc.cc',
+            '<(tcmalloc_dir)/src/base/low_level_alloc.h',
+            '<(tcmalloc_dir)/src/base/simple_mutex.h',
+            '<(tcmalloc_dir)/src/base/spinlock.cc',
+            '<(tcmalloc_dir)/src/base/spinlock.h',
+            '<(tcmalloc_dir)/src/base/spinlock_internal.cc',
+            '<(tcmalloc_dir)/src/base/spinlock_internal.h',
+            '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+            '<(tcmalloc_dir)/src/base/stl_allocator.h',
+            '<(tcmalloc_dir)/src/base/synchronization_profiling.h',
+            '<(tcmalloc_dir)/src/base/sysinfo.cc',
+            '<(tcmalloc_dir)/src/base/sysinfo.h',
+            '<(tcmalloc_dir)/src/base/thread_annotations.h',
+            '<(tcmalloc_dir)/src/base/thread_lister.c',
+            '<(tcmalloc_dir)/src/base/thread_lister.h',
+            '<(tcmalloc_dir)/src/base/vdso_support.cc',
+            '<(tcmalloc_dir)/src/base/vdso_support.h',
+            '<(tcmalloc_dir)/src/central_freelist.cc',
+            '<(tcmalloc_dir)/src/central_freelist.h',
+            '<(tcmalloc_dir)/src/common.cc',
+            '<(tcmalloc_dir)/src/common.h',
+            '<(tcmalloc_dir)/src/debugallocation.cc',
+            '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+            '<(tcmalloc_dir)/src/deep-heap-profile.h',
+            '<(tcmalloc_dir)/src/free_list.cc',
+            '<(tcmalloc_dir)/src/free_list.h',
+            '<(tcmalloc_dir)/src/getpc.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+            '<(tcmalloc_dir)/src/gperftools/profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+            '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+            '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+            '<(tcmalloc_dir)/src/heap-checker.cc',
+            '<(tcmalloc_dir)/src/heap-profile-table.cc',
+            '<(tcmalloc_dir)/src/heap-profile-table.h',
+            '<(tcmalloc_dir)/src/heap-profiler.cc',
+            '<(tcmalloc_dir)/src/internal_logging.cc',
+            '<(tcmalloc_dir)/src/internal_logging.h',
+            '<(tcmalloc_dir)/src/libc_override.h',
+            '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+            '<(tcmalloc_dir)/src/libc_override_glibc.h',
+            '<(tcmalloc_dir)/src/libc_override_osx.h',
+            '<(tcmalloc_dir)/src/libc_override_redefine.h',
+            '<(tcmalloc_dir)/src/linked_list.h',
+            '<(tcmalloc_dir)/src/malloc_extension.cc',
+            '<(tcmalloc_dir)/src/malloc_hook-inl.h',
+            '<(tcmalloc_dir)/src/malloc_hook.cc',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+            '<(tcmalloc_dir)/src/maybe_threads.cc',
+            '<(tcmalloc_dir)/src/maybe_threads.h',
+            '<(tcmalloc_dir)/src/memfs_malloc.cc',
+            '<(tcmalloc_dir)/src/memory_region_map.cc',
+            '<(tcmalloc_dir)/src/memory_region_map.h',
+            '<(tcmalloc_dir)/src/packed-cache-inl.h',
+            '<(tcmalloc_dir)/src/page_heap.cc',
+            '<(tcmalloc_dir)/src/page_heap.h',
+            '<(tcmalloc_dir)/src/page_heap_allocator.h',
+            '<(tcmalloc_dir)/src/pagemap.h',
+            '<(tcmalloc_dir)/src/profile-handler.cc',
+            '<(tcmalloc_dir)/src/profile-handler.h',
+            '<(tcmalloc_dir)/src/profiledata.cc',
+            '<(tcmalloc_dir)/src/profiledata.h',
+            '<(tcmalloc_dir)/src/profiler.cc',
+            '<(tcmalloc_dir)/src/raw_printer.cc',
+            '<(tcmalloc_dir)/src/raw_printer.h',
+            '<(tcmalloc_dir)/src/sampler.cc',
+            '<(tcmalloc_dir)/src/sampler.h',
+            '<(tcmalloc_dir)/src/span.cc',
+            '<(tcmalloc_dir)/src/span.h',
+            '<(tcmalloc_dir)/src/stack_trace_table.cc',
+            '<(tcmalloc_dir)/src/stack_trace_table.h',
+            '<(tcmalloc_dir)/src/stacktrace.cc',
+            '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_config.h',
+            '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+            '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+            '<(tcmalloc_dir)/src/static_vars.cc',
+            '<(tcmalloc_dir)/src/static_vars.h',
+            '<(tcmalloc_dir)/src/symbolize.cc',
+            '<(tcmalloc_dir)/src/symbolize.h',
+            '<(tcmalloc_dir)/src/system-alloc.cc',
+            '<(tcmalloc_dir)/src/system-alloc.h',
+            '<(tcmalloc_dir)/src/tcmalloc.cc',
+            '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+            '<(tcmalloc_dir)/src/thread_cache.cc',
+            '<(tcmalloc_dir)/src/thread_cache.h',
+
+            'debugallocation_shim.cc',
+          ],
+          # sources! means that these are not compiled directly.
+          'sources!': [
+            # We simply don't use these, but list them above so that IDE
+            # users can view the full available source for reference, etc.
+            '<(tcmalloc_dir)/src/addressmap-inl.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+            '<(tcmalloc_dir)/src/base/atomicops.h',
+            '<(tcmalloc_dir)/src/base/basictypes.h',
+            '<(tcmalloc_dir)/src/base/commandlineflags.h',
+            '<(tcmalloc_dir)/src/base/cycleclock.h',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+            '<(tcmalloc_dir)/src/base/elfcore.h',
+            '<(tcmalloc_dir)/src/base/googleinit.h',
+            '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+            '<(tcmalloc_dir)/src/base/simple_mutex.h',
+            '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+            '<(tcmalloc_dir)/src/base/stl_allocator.h',
+            '<(tcmalloc_dir)/src/base/thread_annotations.h',
+            '<(tcmalloc_dir)/src/getpc.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+            '<(tcmalloc_dir)/src/gperftools/profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+            '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+            '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+            '<(tcmalloc_dir)/src/heap-checker.cc',
+            '<(tcmalloc_dir)/src/libc_override.h',
+            '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+            '<(tcmalloc_dir)/src/libc_override_glibc.h',
+            '<(tcmalloc_dir)/src/libc_override_osx.h',
+            '<(tcmalloc_dir)/src/libc_override_redefine.h',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+            '<(tcmalloc_dir)/src/memfs_malloc.cc',
+            '<(tcmalloc_dir)/src/packed-cache-inl.h',
+            '<(tcmalloc_dir)/src/page_heap_allocator.h',
+            '<(tcmalloc_dir)/src/pagemap.h',
+            '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_config.h',
+            '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+            '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+            '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+
+            # Included by debugallocation_shim.cc.
+            '<(tcmalloc_dir)/src/debugallocation.cc',
+            '<(tcmalloc_dir)/src/tcmalloc.cc',
+          ]
+        },{
+          'include_dirs': [
+            '.',
+            '../..',
+          ],
+        }],
+        ['OS=="linux" and clang_type_profiler==1', {
+          'dependencies': [
+            'type_profiler_tcmalloc',
+          ],
+          # It is undoing dependencies and cflags_cc for type_profiler which
+          # build/common.gypi injects into all targets.
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            'libcmt',
+          ],
+          'sources': [
+            'allocator_shim_win.cc',
+          ],
+        }],
+        ['profiling!=1', {
+          'sources!': [
+            # cpuprofiler
+            '<(tcmalloc_dir)/src/base/thread_lister.c',
+            '<(tcmalloc_dir)/src/base/thread_lister.h',
+            '<(tcmalloc_dir)/src/profile-handler.cc',
+            '<(tcmalloc_dir)/src/profile-handler.h',
+            '<(tcmalloc_dir)/src/profiledata.cc',
+            '<(tcmalloc_dir)/src/profiledata.h',
+            '<(tcmalloc_dir)/src/profiler.cc',
+          ],
+        }],
+        ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
+          'sources!': [
+            '<(tcmalloc_dir)/src/system-alloc.h',
+          ],
+          # We enable all warnings by default, but upstream disables a few.
+          # Keep "-Wno-*" flags in sync with upstream by comparing against:
+          # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+          'cflags': [
+            '-Wno-sign-compare',
+            '-Wno-unused-result',
+          ],
+          'cflags!': [
+            '-fvisibility=hidden',
+          ],
+          'link_settings': {
+            'ldflags': [
+              # Don't let linker rip this symbol out, otherwise the heap&cpu
+              # profilers will not initialize properly on startup.
+              '-Wl,-uIsHeapProfilerRunning,-uProfilerStart',
+              # Do the same for heap leak checker.
+              '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi',
+              '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl',
+              '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
+          ]},
+        }],
+        [ 'use_vtable_verify==1', {
+          'cflags': [
+            '-fvtable-verify=preinit',
+          ],
+        }],
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset=="target"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      # This library is linked in to src/base.gypi:base and allocator_unittests
+      # It can't depend on either and nothing else should depend on it - all
+      # other code should use the interfaced provided by base.
+      'target_name': 'allocator_extension_thunks',
+      'type': 'static_library',
+      'sources': [
+        'allocator_extension_thunks.cc',
+        'allocator_extension_thunks.h',
+      ],
+      'toolsets': ['host', 'target'],
+      'include_dirs': [
+        '../../'
+      ],
+      'conditions': [
+        ['OS=="linux" and clang_type_profiler==1', {
+          # It is undoing dependencies and cflags_cc for type_profiler which
+          # build/common.gypi injects into all targets.
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+        }],
+      ],
+    },
+   ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'libcmt',
+          'type': 'none',
+          'actions': [
+            {
+              'action_name': 'libcmt',
+              'inputs': [
+                'prep_libc.py',
+              ],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib',
+              ],
+              'action': [
+                'python',
+                'prep_libc.py',
+                '$(VCInstallDir)lib',
+                '<(SHARED_INTERMEDIATE_DIR)/allocator',
+                '<(target_arch)',
+              ],
+            },
+          ],
+        },
+        {
+          'target_name': 'allocator_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'allocator',
+            'allocator_extension_thunks',
+            '../../testing/gtest.gyp:gtest',
+          ],
+          'include_dirs': [
+            '.',
+            '../..',
+          ],
+          'sources': [
+            '../profiler/alternate_timer.cc',
+            '../profiler/alternate_timer.h',
+            'allocator_unittest.cc',
+          ],
+        },
+      ],
+    }],
+    ['OS=="win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'allocator_extension_thunks_win64',
+          'type': 'static_library',
+          'sources': [
+            'allocator_extension_thunks.cc',
+            'allocator_extension_thunks.h',
+          ],
+          'toolsets': ['host', 'target'],
+          'include_dirs': [
+            '../../'
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+    ['OS=="linux" and clang_type_profiler==1', {
+      # Some targets in this section undo dependencies and cflags_cc for
+      # type_profiler which build/common.gypi injects into all targets.
+      'targets': [
+        {
+          'target_name': 'type_profiler',
+          'type': 'static_library',
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'type_profiler.cc',
+            'type_profiler.h',
+            'type_profiler_control.h',
+          ],
+          'toolsets': ['host', 'target'],
+        },
+        {
+          'target_name': 'type_profiler_tcmalloc',
+          'type': 'static_library',
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+            '<(tcmalloc_dir)/src/type_profiler_map.cc',
+            'type_profiler_tcmalloc.cc',
+            'type_profiler_tcmalloc.h',
+          ],
+        },
+        {
+          'target_name': 'type_profiler_unittests',
+          'type': 'executable',
+          'dependencies': [
+            '../../testing/gtest.gyp:gtest',
+            '../base.gyp:base',
+            'allocator',
+            'type_profiler_tcmalloc',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'type_profiler_control.cc',
+            'type_profiler_control.h',
+            'type_profiler_unittest.cc',
+          ],
+        },
+        {
+          'target_name': 'type_profiler_map_unittests',
+          'type': 'executable',
+          'dependencies': [
+            '../../testing/gtest.gyp:gtest',
+            '../base.gyp:base',
+            'allocator',
+          ],
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+            '<(tcmalloc_dir)/src/type_profiler_map.cc',
+            'type_profiler_map_unittest.cc',
+          ],
+        },
+      ],
+    }],
+    ['use_allocator=="tcmalloc"', {
+      'targets': [
+         {
+           'target_name': 'tcmalloc_unittest',
+           'type': 'executable',
+           'sources': [
+             'tcmalloc_unittest.cc',
+           ],
+           'include_dirs': [
+             '<(tcmalloc_dir)/src',
+             '../..',
+           ],
+           'dependencies': [
+             '../../testing/gtest.gyp:gtest',
+             'allocator',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/allocator/allocator_extension.cc b/base/allocator/allocator_extension.cc
new file mode 100644
index 0000000..83e460a
--- /dev/null
+++ b/base/allocator/allocator_extension.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace allocator {
+
+bool GetAllocatorWasteSize(size_t* size) {
+  thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function =
+      thunks::GetGetAllocatorWasteSizeFunction();
+  return get_allocator_waste_size_function != NULL &&
+         get_allocator_waste_size_function(size);
+}
+
+void GetStats(char* buffer, int buffer_length) {
+  DCHECK_GT(buffer_length, 0);
+  thunks::GetStatsFunction get_stats_function = thunks::GetGetStatsFunction();
+  if (get_stats_function)
+    get_stats_function(buffer, buffer_length);
+  else
+    buffer[0] = '\0';
+}
+
+void ReleaseFreeMemory() {
+  thunks::ReleaseFreeMemoryFunction release_free_memory_function =
+      thunks::GetReleaseFreeMemoryFunction();
+  if (release_free_memory_function)
+    release_free_memory_function();
+}
+
+void SetGetAllocatorWasteSizeFunction(
+    thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+  DCHECK_EQ(thunks::GetGetAllocatorWasteSizeFunction(),
+            reinterpret_cast<thunks::GetAllocatorWasteSizeFunction>(NULL));
+  thunks::SetGetAllocatorWasteSizeFunction(get_allocator_waste_size_function);
+}
+
+void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) {
+  DCHECK_EQ(thunks::GetGetStatsFunction(),
+            reinterpret_cast<thunks::GetStatsFunction>(NULL));
+  thunks::SetGetStatsFunction(get_stats_function);
+}
+
+void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function) {
+  DCHECK_EQ(thunks::GetReleaseFreeMemoryFunction(),
+            reinterpret_cast<thunks::ReleaseFreeMemoryFunction>(NULL));
+  thunks::SetReleaseFreeMemoryFunction(release_free_memory_function);
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_extension.h b/base/allocator/allocator_extension.h
new file mode 100644
index 0000000..e65822b
--- /dev/null
+++ b/base/allocator/allocator_extension.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+
+#include <stddef.h> // for size_t
+
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+// Request the allocator to report value of its waste memory size.
+// Waste size corresponds to memory that has been allocated from the OS but
+// not passed up to the application. It e.g. includes memory retained by free
+// lists, internal data, chunks padding, etc.
+//
+// |size| pointer to the returned value, must be not NULL.
+// Returns true if the value has been returned, false otherwise.
+BASE_EXPORT bool GetAllocatorWasteSize(size_t* size);
+
+// Request that the allocator print a human-readable description of the current
+// state of the allocator into a null-terminated string in the memory segment
+// buffer[0,buffer_length-1].
+//
+// |buffer| must point to a valid piece of memory
+// |buffer_length| must be > 0.
+BASE_EXPORT void GetStats(char* buffer, int buffer_length);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+
+// These settings allow specifying a callback used to implement the allocator
+// extension functions.  These are optional, but if set they must only be set
+// once.  These will typically called in an allocator-specific initialization
+// routine.
+//
+// No threading promises are made.  The caller is responsible for making sure
+// these pointers are set before any other threads attempt to call the above
+// functions.
+BASE_EXPORT void SetGetAllocatorWasteSizeFunction(
+    thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+
+BASE_EXPORT void SetGetStatsFunction(
+    thunks::GetStatsFunction get_stats_function);
+
+BASE_EXPORT void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function);
+
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
diff --git a/base/allocator/allocator_extension_thunks.cc b/base/allocator/allocator_extension_thunks.cc
new file mode 100644
index 0000000..e4024fb
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension_thunks.h"
+
+#include <cstddef> // for NULL
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// This slightly odd translation unit exists because of the peculularity of how
+// allocator_unittests work on windows.  That target has to perform
+// tcmalloc-specific initialization on windows, but it cannot depend on base
+// otherwise. This target sits in the middle - base and allocator_unittests
+// can depend on it. This file can't depend on anything else in base, including
+// logging.
+
+static GetAllocatorWasteSizeFunction g_get_allocator_waste_size_function = NULL;
+static GetStatsFunction g_get_stats_function = NULL;
+static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL;
+
+void SetGetAllocatorWasteSizeFunction(
+    GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+  g_get_allocator_waste_size_function = get_allocator_waste_size_function;
+}
+
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction() {
+  return g_get_allocator_waste_size_function;
+}
+
+void SetGetStatsFunction(GetStatsFunction get_stats_function) {
+  g_get_stats_function = get_stats_function;
+}
+
+GetStatsFunction GetGetStatsFunction() {
+  return g_get_stats_function;
+}
+
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function) {
+  g_release_free_memory_function = release_free_memory_function;
+}
+
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() {
+  return g_release_free_memory_function;
+}
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_extension_thunks.h b/base/allocator/allocator_extension_thunks.h
new file mode 100644
index 0000000..4e5027b
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
+
+#include <stddef.h> // for size_t
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// WARNING: You probably don't want to use this file unless you are routing a
+// new allocator extension from a specific allocator implementation to base.
+// See allocator_extension.h to see the interface that base exports.
+
+typedef bool (*GetAllocatorWasteSizeFunction)(size_t* size);
+void SetGetAllocatorWasteSizeFunction(
+    GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction();
+
+typedef void (*GetStatsFunction)(char* buffer, int buffer_length);
+void SetGetStatsFunction(GetStatsFunction get_stats_function);
+GetStatsFunction GetGetStatsFunction();
+
+typedef void (*ReleaseFreeMemoryFunction)();
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function);
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
diff --git a/base/allocator/allocator_shim_win.cc b/base/allocator/allocator_shim_win.cc
new file mode 100644
index 0000000..a1473e5
--- /dev/null
+++ b/base/allocator/allocator_shim_win.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <malloc.h>
+#include <new.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+// This shim make it possible to perform additional checks on allocations
+// before passing them to the Heap functions.
+
+// Heap functions are stripped from libcmt.lib using the prep_libc.py
+// for each object file stripped, we re-implement them here to allow us to
+// perform additional checks:
+// 1. Enforcing the maximum size that can be allocated to 2Gb.
+// 2. Calling new_handler if malloc fails.
+
+extern "C" {
+// We set this to 1 because part of the CRT uses a check of _crtheap != 0
+// to test whether the CRT has been initialized.  Once we've ripped out
+// the allocators from libcmt, we need to provide this definition so that
+// the rest of the CRT is still usable.
+// heapinit.c
+void* _crtheap = reinterpret_cast<void*>(1);
+}
+
+namespace {
+
+const size_t kWindowsPageSize = 4096;
+const size_t kMaxWindowsAllocation = INT_MAX - kWindowsPageSize;
+int new_mode = 0;
+
+// VS2013 crt uses the process heap as its heap, so we do the same here.
+// See heapinit.c in VS CRT sources.
+bool win_heap_init() {
+  // Set the _crtheap global here.  THis allows us to offload most of the
+  // memory management to the CRT, except the functions we need to shim.
+  _crtheap = GetProcessHeap();
+  if (_crtheap == NULL)
+    return false;
+
+  ULONG enable_lfh = 2;
+  // NOTE: Setting LFH may fail.  Vista already has it enabled.
+  //       And under the debugger, it won't use LFH.  So we
+  //       ignore any errors.
+  HeapSetInformation(_crtheap, HeapCompatibilityInformation, &enable_lfh,
+                     sizeof(enable_lfh));
+
+  return true;
+}
+
+void* win_heap_malloc(size_t size) {
+  if (size < kMaxWindowsAllocation)
+    return HeapAlloc(_crtheap, 0, size);
+  return NULL;
+}
+
+void win_heap_free(void* size) {
+  HeapFree(_crtheap, 0, size);
+}
+
+void* win_heap_realloc(void* ptr, size_t size) {
+  if (!ptr)
+    return win_heap_malloc(size);
+  if (!size) {
+    win_heap_free(ptr);
+    return NULL;
+  }
+  if (size < kMaxWindowsAllocation)
+    return HeapReAlloc(_crtheap, 0, ptr, size);
+  return NULL;
+}
+
+void win_heap_term() {
+  _crtheap = NULL;
+}
+
+// Call the new handler, if one has been set.
+// Returns true on successfully calling the handler, false otherwise.
+inline bool call_new_handler(bool nothrow, size_t size) {
+  // Get the current new handler.
+  _PNH nh = _query_new_handler();
+#if defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+  if (!nh)
+    return false;
+  // Since exceptions are disabled, we don't really know if new_handler
+  // failed.  Assume it will abort if it fails.
+  return nh(size);
+#else
+#error "Exceptions in allocator shim are not supported!"
+#endif  // defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+  return false;
+}
+
+// Implement a C++ style allocation, which always calls the new_handler
+// on failure.
+inline void* generic_cpp_alloc(size_t size, bool nothrow) {
+  void* ptr;
+  for (;;) {
+    ptr = malloc(size);
+    if (ptr)
+      return ptr;
+    if (!call_new_handler(nothrow, size))
+      break;
+  }
+  return ptr;
+}
+
+}  // namespace
+
+// new.cpp
+void* operator new(size_t size) {
+  return generic_cpp_alloc(size, false);
+}
+
+// delete.cpp
+void operator delete(void* p) throw() {
+  free(p);
+}
+
+// new2.cpp
+void* operator new[](size_t size) {
+  return generic_cpp_alloc(size, false);
+}
+
+// delete2.cpp
+void operator delete[](void* p) throw() {
+  free(p);
+}
+
+// newopnt.cpp
+void* operator new(size_t size, const std::nothrow_t& nt) {
+  return generic_cpp_alloc(size, true);
+}
+
+// newaopnt.cpp
+void* operator new[](size_t size, const std::nothrow_t& nt) {
+  return generic_cpp_alloc(size, true);
+}
+
+// This function behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Returns the previous mode.
+// new_mode.cpp
+int _set_new_mode(int flag) throw() {
+  int old_mode = new_mode;
+  new_mode = flag;
+  return old_mode;
+}
+
+// new_mode.cpp
+int _query_new_mode() {
+  return new_mode;
+}
+
+extern "C" {
+// malloc.c
+void* malloc(size_t size) {
+  void* ptr;
+  for (;;) {
+    ptr = win_heap_malloc(size);
+    if (ptr)
+      return ptr;
+
+    if (!new_mode || !call_new_handler(true, size))
+      break;
+  }
+  return ptr;
+}
+
+// free.c
+void free(void* p) {
+  win_heap_free(p);
+  return;
+}
+
+// realloc.c
+void* realloc(void* ptr, size_t size) {
+  // Webkit is brittle for allocators that return NULL for malloc(0).  The
+  // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
+  // to call malloc for this case.
+  if (!ptr)
+    return malloc(size);
+
+  void* new_ptr;
+  for (;;) {
+    new_ptr = win_heap_realloc(ptr, size);
+
+    // Subtle warning:  NULL return does not alwas indicate out-of-memory.  If
+    // the requested new size is zero, realloc should free the ptr and return
+    // NULL.
+    if (new_ptr || !size)
+      return new_ptr;
+    if (!new_mode || !call_new_handler(true, size))
+      break;
+  }
+  return new_ptr;
+}
+
+// heapinit.c
+intptr_t _get_heap_handle() {
+  return reinterpret_cast<intptr_t>(_crtheap);
+}
+
+// heapinit.c
+int _heap_init() {
+  return win_heap_init() ? 1 : 0;
+}
+
+// heapinit.c
+void _heap_term() {
+  win_heap_term();
+}
+
+// calloc.c
+void* calloc(size_t n, size_t elem_size) {
+  // Overflow check.
+  const size_t size = n * elem_size;
+  if (elem_size != 0 && size / elem_size != n)
+    return NULL;
+
+  void* result = malloc(size);
+  if (result != NULL) {
+    memset(result, 0, size);
+  }
+  return result;
+}
+
+// recalloc.c
+void* _recalloc(void* p, size_t n, size_t elem_size) {
+  if (!p)
+    return calloc(n, elem_size);
+
+  // This API is a bit odd.
+  // Note: recalloc only guarantees zeroed memory when p is NULL.
+  //   Generally, calls to malloc() have padding.  So a request
+  //   to malloc N bytes actually malloc's N+x bytes.  Later, if
+  //   that buffer is passed to recalloc, we don't know what N
+  //   was anymore.  We only know what N+x is.  As such, there is
+  //   no way to know what to zero out.
+  const size_t size = n * elem_size;
+  if (elem_size != 0 && size / elem_size != n)
+    return NULL;
+  return realloc(p, size);
+}
+
+// calloc_impl.c
+void* _calloc_impl(size_t n, size_t size) {
+  return calloc(n, size);
+}
+
+#ifndef NDEBUG
+#undef malloc
+#undef free
+#undef calloc
+
+static int error_handler(int reportType) {
+  switch (reportType) {
+    case 0:  // _CRT_WARN
+      __debugbreak();
+      return 0;
+
+    case 1:  // _CRT_ERROR
+      __debugbreak();
+      return 0;
+
+    case 2:  // _CRT_ASSERT
+      __debugbreak();
+      return 0;
+  }
+  char* p = NULL;
+  *p = '\0';
+  return 0;
+}
+
+int _CrtDbgReport(int reportType,
+                  const char*,
+                  int,
+                  const char*,
+                  const char*,
+                  ...) {
+  return error_handler(reportType);
+}
+
+int _CrtDbgReportW(int reportType,
+                   const wchar_t*,
+                   int,
+                   const wchar_t*,
+                   const wchar_t*,
+                   ...) {
+  return error_handler(reportType);
+}
+
+int _CrtSetReportMode(int, int) {
+  return 0;
+}
+
+void* _malloc_dbg(size_t size, int, const char*, int) {
+  return malloc(size);
+}
+
+void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
+  return realloc(ptr, size);
+}
+
+void _free_dbg(void* ptr, int) {
+  free(ptr);
+}
+
+void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
+  return calloc(n, size);
+}
+#endif  // NDEBUG
+
+}  // extern C
diff --git a/base/allocator/allocator_unittest.cc b/base/allocator/allocator_unittest.cc
new file mode 100644
index 0000000..a1d1ef0
--- /dev/null
+++ b/base/allocator/allocator_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>   // for min()
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Number of bits in a size_t.
+static const int kSizeBits = 8 * sizeof(size_t);
+// The maximum size of a size_t.
+static const size_t kMaxSize = ~static_cast<size_t>(0);
+// Maximum positive size of a size_t if it were signed.
+static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
+
+namespace {
+
+using std::min;
+
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    buffer[i] = (i & 0xff);
+  }
+}
+
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != (i & 0xff)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Check that a buffer is completely zeroed.
+static bool IsZeroed(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Check alignment
+static void CheckAlignment(void* p, int align) {
+  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
+}
+
+// Return the next interesting size/delta to check.  Returns -1 if no more.
+static int NextSize(int size) {
+  if (size < 100)
+    return size+1;
+
+  if (size < 100000) {
+    // Find next power of two
+    int power = 1;
+    while (power < size)
+      power <<= 1;
+
+    // Yield (power-1, power, power+1)
+    if (size < power-1)
+      return power-1;
+
+    if (size == power-1)
+      return power;
+
+    assert(size == power);
+    return power+1;
+  } else {
+    return -1;
+  }
+}
+
+static void TestCalloc(size_t n, size_t s, bool ok) {
+  char* p = reinterpret_cast<char*>(calloc(n, s));
+  if (!ok) {
+    EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
+  } else {
+    EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
+        "calloc(n, s) should succeed";
+    for (size_t i = 0; i < n*s; i++) {
+      EXPECT_EQ('\0', p[i]);
+    }
+    free(p);
+  }
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+
+TEST(Allocators, Malloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  for (int size = 1; size < 1048576; size *= 2) {
+    unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
+    CheckAlignment(ptr, 2);  // Should be 2 byte aligned
+    Fill(ptr, size);
+    EXPECT_TRUE(Valid(ptr, size));
+    free(ptr);
+  }
+}
+
+TEST(Allocators, Calloc) {
+  TestCalloc(0, 0, true);
+  TestCalloc(0, 1, true);
+  TestCalloc(1, 1, true);
+  TestCalloc(1<<10, 0, true);
+  TestCalloc(1<<20, 0, true);
+  TestCalloc(0, 1<<10, true);
+  TestCalloc(0, 1<<20, true);
+  TestCalloc(1<<20, 2, true);
+  TestCalloc(2, 1<<20, true);
+  TestCalloc(1000, 1000, true);
+
+  TestCalloc(kMaxSize, 2, false);
+  TestCalloc(2, kMaxSize, false);
+  TestCalloc(kMaxSize, kMaxSize, false);
+
+  TestCalloc(kMaxSignedSize, 3, false);
+  TestCalloc(3, kMaxSignedSize, false);
+  TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
+}
+
+// This makes sure that reallocing a small number of bytes in either
+// direction doesn't cause us to allocate new memory.
+TEST(Allocators, Realloc1) {
+  int start_sizes[] = { 100, 1000, 10000, 100000 };
+  int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
+
+  for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
+    void* p = malloc(start_sizes[s]);
+    ASSERT_TRUE(p);
+    // The larger the start-size, the larger the non-reallocing delta.
+    for (int d = 0; d < s*2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] + deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    // Test again, but this time reallocing smaller first.
+    for (int d = 0; d < s*2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] - deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    free(p);
+  }
+}
+
+TEST(Allocators, Realloc2) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(realloc(src, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL) free(dst);
+    }
+  }
+
+  // Now make sure realloc works correctly even when we overflow the
+  // packed cache, so some entries are evicted from the cache.
+  // The cache has 2^12 entries, keyed by page number.
+  const int kNumEntries = 1 << 14;
+  int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
+  int sum = 0;
+  for (int i = 0; i < kNumEntries; i++) {
+    // no page size is likely to be bigger than 8192?
+    p[i] = reinterpret_cast<int*>(malloc(8192));
+    p[i][1000] = i;              // use memory deep in the heart of p
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    sum += p[i][1000];
+    free(p[i]);
+  }
+  EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum);  // assume kNE is even
+  free(p);
+}
+
+// Test recalloc
+TEST(Allocators, Recalloc) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src =
+          reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
+      EXPECT_TRUE(IsZeroed(src, src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL)
+        free(dst);
+    }
+  }
+}
+
+// Test windows specific _aligned_malloc() and _aligned_free() methods.
+TEST(Allocators, AlignedMalloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384};
+  for (int size = 1; size > 0; size = NextSize(size)) {
+    for (int i = 0; i < arraysize(kTestAlignments); ++i) {
+      unsigned char* ptr = static_cast<unsigned char*>(
+          _aligned_malloc(size, kTestAlignments[i]));
+      CheckAlignment(ptr, kTestAlignments[i]);
+      Fill(ptr, size);
+      EXPECT_TRUE(Valid(ptr, size));
+
+      // Make a second allocation of the same size and alignment to prevent
+      // allocators from passing this test by accident.  Per jar, tcmalloc
+      // provides allocations for new (never before seen) sizes out of a thread
+      // local heap of a given "size class."  Each time the test requests a new
+      // size, it will usually get the first element of a span, which is a
+      // 4K aligned allocation.
+      unsigned char* ptr2 = static_cast<unsigned char*>(
+          _aligned_malloc(size, kTestAlignments[i]));
+      CheckAlignment(ptr2, kTestAlignments[i]);
+      Fill(ptr2, size);
+      EXPECT_TRUE(Valid(ptr2, size));
+
+      // Should never happen, but sanity check just in case.
+      ASSERT_NE(ptr, ptr2);
+      _aligned_free(ptr);
+      _aligned_free(ptr2);
+    }
+  }
+}
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/debugallocation_shim.cc b/base/allocator/debugallocation_shim.cc
new file mode 100644
index 0000000..d1cf52a
--- /dev/null
+++ b/base/allocator/debugallocation_shim.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TCMALLOC_FOR_DEBUGALLOCATION)
+#include "third_party/tcmalloc/chromium/src/debugallocation.cc"
+#else
+#include "third_party/tcmalloc/chromium/src/tcmalloc.cc"
+#endif
diff --git a/base/allocator/prep_libc.py b/base/allocator/prep_libc.py
new file mode 100755
index 0000000..079297b
--- /dev/null
+++ b/base/allocator/prep_libc.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This script takes libcmt.lib for VS2013 and removes the allocation related
+# functions from it.
+#
+# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch>
+#
+# VCLibDir is the path where VC is installed, something like:
+#    C:\Program Files\Microsoft Visual Studio 8\VC\lib
+# OutputDir is the directory where the modified libcmt file should be stored.
+# arch is one of: 'ia32', 'x86' or 'x64'. ia32 and x86 are synonyms.
+
+import os
+import shutil
+import subprocess
+import sys
+
+def run(command):
+  """Run |command|.  If any lines that match an error condition then
+      terminate."""
+  error = 'cannot find member object'
+  popen = subprocess.Popen(
+      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+  out, _ = popen.communicate()
+  for line in out.splitlines():
+    print line
+    if error and line.find(error) != -1:
+      print 'prep_libc.py: Error stripping object from C runtime.'
+      sys.exit(1)
+
+def main():
+  bindir = 'SELF_X86'
+  objdir = 'INTEL'
+  vs_install_dir = sys.argv[1]
+  outdir = sys.argv[2]
+  if "x64" in sys.argv[3]:
+    bindir = 'SELF_64_amd64'
+    objdir = 'amd64'
+    vs_install_dir = os.path.join(vs_install_dir, 'amd64')
+  output_lib = os.path.join(outdir, 'libcmt.lib')
+  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
+  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
+                  os.path.join(outdir, 'libcmt.pdb'))
+  cvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
+      '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativec\\\\';
+  cppvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
+      '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\';
+
+  cobjfiles = ['malloc', 'free', 'realloc', 'heapinit', 'calloc', 'recalloc',
+      'calloc_impl']
+  cppobjfiles = ['new', 'new2', 'delete', 'delete2', 'new_mode', 'newopnt',
+      'newaopnt']
+  for obj in cobjfiles:
+    cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
+           (cvspath, obj, output_lib))
+    run(cmd)
+  for obj in cppobjfiles:
+    cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
+           (cppvspath, obj, output_lib))
+    run(cmd)
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc
new file mode 100644
index 0000000..0f7082e
--- /dev/null
+++ b/base/allocator/tcmalloc_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <stddef.h>
+#include <stdio.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TCMalloc header files.
+#include "common.h"  // For TCMalloc constants like page size, etc.
+
+// TCMalloc implementation.
+#include "debugallocation_shim.cc"
+
+namespace {
+
+void* TCMallocDoMallocForTest(size_t size) {
+  return do_malloc(size);
+}
+
+void TCMallocDoFreeForTest(void* ptr) {
+  do_free(ptr);
+}
+
+size_t ExcludeSpaceForMarkForTest(size_t size) {
+  return ExcludeSpaceForMark(size);
+}
+
+}  // namespace
+
+TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+  for (int offset = 1; offset < kPageSize ; offset <<= 1) {
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+                 "Pointer is not pointing to the start of a span");
+  }
+}
+
+TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+
+  for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
+    // Only the first and last page of a span are in heap map. So for others
+    // tcmalloc will give a general error of invalid pointer.
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+                 "Attempt to free invalid pointer");
+  }
+  ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize),
+               "Pointer is not pointing to the start of a span");
+}
+
+TEST(TCMallocFreeCheck, DoubleFreeLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+  ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+               "Object was not in-use");
+}
+
+
+#ifdef NDEBUG
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+  for (size_t size = 1;
+       size <= ExcludeSpaceForMarkForTest(kMaxSize);
+       size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Circular loop in list detected");
+  }
+}
+#else
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+  size_t size = 1;
+
+  // When the object is small, tcmalloc validation can not distinguish normal
+  // memory corruption or double free, because there's not enough space in
+  // freed objects to keep the mark.
+  for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Memory corrupted");
+  }
+
+  for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Attempt to double free");
+  }
+}
+#endif
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/type_profiler.cc b/base/allocator/type_profiler.cc
new file mode 100644
index 0000000..635fbcf
--- /dev/null
+++ b/base/allocator/type_profiler.cc
@@ -0,0 +1,63 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+
+#include <assert.h>
+
+namespace {
+
+void* NopIntercept(void* ptr, size_t size, const std::type_info& type) {
+  return ptr;
+}
+
+base::type_profiler::InterceptFunction* g_new_intercept = NopIntercept;
+base::type_profiler::InterceptFunction* g_delete_intercept = NopIntercept;
+
+}
+
+void* __op_new_intercept__(void* ptr,
+                           size_t size,
+                           const std::type_info& type) {
+  return g_new_intercept(ptr, size, type);
+}
+
+void* __op_delete_intercept__(void* ptr,
+                              size_t size,
+                              const std::type_info& type) {
+  return g_delete_intercept(ptr, size, type);
+}
+
+namespace base {
+namespace type_profiler {
+
+// static
+void InterceptFunctions::SetFunctions(InterceptFunction* new_intercept,
+                                      InterceptFunction* delete_intercept) {
+  // Don't use DCHECK, as this file is injected into targets
+  // that do not and should not depend on base/base.gyp:base
+  assert(g_new_intercept == NopIntercept);
+  assert(g_delete_intercept == NopIntercept);
+
+  g_new_intercept = new_intercept;
+  g_delete_intercept = delete_intercept;
+}
+
+// static
+void InterceptFunctions::ResetFunctions() {
+  g_new_intercept = NopIntercept;
+  g_delete_intercept = NopIntercept;
+}
+
+// static
+bool InterceptFunctions::IsAvailable() {
+  return g_new_intercept != NopIntercept || g_delete_intercept != NopIntercept;
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/base/allocator/type_profiler.h b/base/allocator/type_profiler.h
new file mode 100644
index 0000000..86b5711
--- /dev/null
+++ b/base/allocator/type_profiler.h
@@ -0,0 +1,40 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <stddef.h>  // for size_t
+#include <typeinfo>  // for std::typeinfo
+
+namespace base {
+namespace type_profiler {
+
+typedef void* InterceptFunction(void*, size_t, const std::type_info&);
+
+class InterceptFunctions {
+ public:
+  // It must be called only once in a process while it is in single-thread.
+  // For now, ContentMainRunnerImpl::Initialize is the only supposed caller
+  // of this function except for single-threaded unit tests.
+  static void SetFunctions(InterceptFunction* new_intercept,
+                           InterceptFunction* delete_intercept);
+
+ private:
+  friend class TypeProfilerTest;
+
+  // These functions are not thread safe.
+  // They must be used only from single-threaded unit tests.
+  static void ResetFunctions();
+  static bool IsAvailable();
+};
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_H_
diff --git a/base/allocator/type_profiler_control.cc b/base/allocator/type_profiler_control.cc
new file mode 100644
index 0000000..6be7984
--- /dev/null
+++ b/base/allocator/type_profiler_control.cc
@@ -0,0 +1,38 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/type_profiler_control.h"
+
+namespace base {
+namespace type_profiler {
+
+namespace {
+
+#if defined(TYPE_PROFILING)
+const bool kTypeProfilingEnabled = true;
+#else
+const bool kTypeProfilingEnabled = false;
+#endif
+
+bool g_enable_intercept = kTypeProfilingEnabled;
+
+}  // namespace
+
+// static
+void Controller::Stop() {
+  g_enable_intercept = false;
+}
+
+// static
+bool Controller::IsProfiling() {
+  return kTypeProfilingEnabled && g_enable_intercept;
+}
+
+// static
+void Controller::Restart() {
+  g_enable_intercept = kTypeProfilingEnabled;
+}
+
+}  // namespace type_profiler
+}  // namespace base
diff --git a/base/allocator/type_profiler_control.h b/base/allocator/type_profiler_control.h
new file mode 100644
index 0000000..17cf5b6
--- /dev/null
+++ b/base/allocator/type_profiler_control.h
@@ -0,0 +1,31 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace type_profiler {
+
+class Controller {
+ public:
+  static void Stop();
+  static bool IsProfiling();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest,
+                           TestProfileNewWithoutProfiledDelete);
+
+  // It must be used only from allowed unit tests.  The following is only
+  // allowed for use in unit tests. Profiling should never be restarted in
+  // regular use.
+  static void Restart();
+};
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
diff --git a/base/allocator/type_profiler_map_unittest.cc b/base/allocator/type_profiler_map_unittest.cc
new file mode 100644
index 0000000..514ec16
--- /dev/null
+++ b/base/allocator/type_profiler_map_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a unittest set for type_profiler_map in third_party/tcmalloc.  It is
+// independent from other tests and executed manually like allocator_unittests
+// since type_profiler_map is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+static const void* const g_const_null = static_cast<const void*>(NULL);
+
+TEST(TypeProfilerMapTest, NormalOperation) {
+  // Allocate an object just to get a valid address.
+  // This 'new' is not profiled by type_profiler.
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  EraseType(dummy.get());
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+}
+
+TEST(TypeProfilerMapTest, EraseWithoutInsert) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  for (int i = 0; i < 10; ++i) {
+    EraseType(dummy.get());
+    type = LookupType(dummy.get());
+    EXPECT_EQ(g_const_null, type);
+  }
+}
+
+TEST(TypeProfilerMapTest, InsertThenMultipleErase) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  for (int i = 0; i < 10; ++i) {
+    EraseType(dummy.get());
+    type = LookupType(dummy.get());
+    EXPECT_EQ(g_const_null, type);
+  }
+}
+
+TEST(TypeProfilerMapTest, MultipleInsertWithoutErase) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  InsertType(dummy.get(), 5, typeid(char));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  InsertType(dummy.get(), 129, typeid(long));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(long).name(), type->name());
+
+  EraseType(dummy.get());
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/type_profiler_tcmalloc.cc b/base/allocator/type_profiler_tcmalloc.cc
new file mode 100644
index 0000000..e5e10e0
--- /dev/null
+++ b/base/allocator/type_profiler_tcmalloc.cc
@@ -0,0 +1,37 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler_tcmalloc.h"
+
+#include "base/allocator/type_profiler_control.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+                              size_t size,
+                              const std::type_info& type) {
+  if (Controller::IsProfiling())
+    InsertType(ptr, size, type);
+
+  return ptr;
+}
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+                                 size_t size,
+                                 const std::type_info& type) {
+  if (Controller::IsProfiling())
+    EraseType(ptr);
+
+  return ptr;
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/base/allocator/type_profiler_tcmalloc.h b/base/allocator/type_profiler_tcmalloc.h
new file mode 100644
index 0000000..ac55995
--- /dev/null
+++ b/base/allocator/type_profiler_tcmalloc.h
@@ -0,0 +1,29 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <cstddef>  // for size_t
+#include <typeinfo>  // for std::type_info
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+                              size_t size,
+                              const std::type_info& type);
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+                                 size_t size,
+                                 const std::type_info& type);
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
diff --git a/base/allocator/type_profiler_unittest.cc b/base/allocator/type_profiler_unittest.cc
new file mode 100644
index 0000000..3d7369c
--- /dev/null
+++ b/base/allocator/type_profiler_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a unittest set for type_profiler.  It is independent from other
+// tests and executed manually like allocator_unittests since type_profiler_map
+// used in type_profiler is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others
+//
+// It tests that the profiler doesn't fail in suspicous cases.  For example,
+// 'new' is not profiled, but 'delete' for the created object is profiled.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+#include "base/allocator/type_profiler_control.h"
+#include "base/allocator/type_profiler_tcmalloc.h"
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+class TypeProfilerTest : public testing::Test {
+ public:
+  TypeProfilerTest() {}
+
+  void SetInterceptFunctions() {
+    InterceptFunctions::SetFunctions(NewInterceptForTCMalloc,
+                                     DeleteInterceptForTCMalloc);
+  }
+
+  void ResetInterceptFunctions() {
+    InterceptFunctions::ResetFunctions();
+  }
+
+  void SetUp() {
+    SetInterceptFunctions();
+  }
+
+  void TearDown() {
+    ResetInterceptFunctions();
+  }
+
+ protected:
+  static const size_t kDummyArraySize;
+  static const void* const kConstNull;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest);
+};
+
+const size_t TypeProfilerTest::kDummyArraySize = 10;
+const void* const TypeProfilerTest::kConstNull = static_cast<const void*>(NULL);
+
+TEST_F(TypeProfilerTest, TestNormalProfiling) {
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+  delete dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestNormalArrayProfiling) {
+  int* dummy = new int[kDummyArraySize];
+  const std::type_info* type;
+
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  // For an array, the profiler remembers its base type.
+  EXPECT_STREQ(typeid(int).name(), type->name());
+  delete[] dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) {
+  int *dummy[kDummyArraySize];
+  const std::type_info* type;
+  for (int i = 0; i < kDummyArraySize; ++i)
+    dummy[i] = new int(i);
+
+  for (int i = 0; i < kDummyArraySize; ++i) {
+    type = LookupType(dummy[i]);
+    ASSERT_NE(kConstNull, type);
+    EXPECT_STREQ(typeid(int).name(), type->name());
+  }
+
+  for (int i = 0; i < kDummyArraySize; ++i) {
+    delete dummy[i];
+    type = LookupType(dummy[i]);
+    ASSERT_EQ(kConstNull, type);
+  }
+}
+
+TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) {
+  static const size_t large_size = 256 * 1024;
+
+  char* dummy_char = new char[large_size / sizeof(*dummy_char)];
+  const std::type_info* type;
+
+  type = LookupType(dummy_char);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  // Call "::operator delete" directly to drop __op_delete_intercept__.
+  ::operator delete[](dummy_char);
+
+  type = LookupType(dummy_char);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  // Allocates a little different size.
+  int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1];
+
+  // We expect that tcmalloc returns the same address for these large (over 32k)
+  // allocation calls.  It usually happens, but maybe probablistic.
+  ASSERT_EQ(static_cast<void*>(dummy_char), static_cast<void*>(dummy_int)) <<
+      "two new (malloc) calls didn't return the same address; retry it.";
+
+  type = LookupType(dummy_int);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  delete[] dummy_int;
+
+  type = LookupType(dummy_int);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) {
+  // 'dummy' should be new'ed in this test before intercept functions are set.
+  ResetInterceptFunctions();
+
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  // Set intercept functions again after 'dummy' is new'ed.
+  SetInterceptFunctions();
+
+  delete dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+
+  ResetInterceptFunctions();
+}
+
+TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) {
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  EXPECT_TRUE(Controller::IsProfiling());
+
+  // Stop profiling before deleting 'dummy'.
+  Controller::Stop();
+  EXPECT_FALSE(Controller::IsProfiling());
+
+  delete dummy;
+
+  // NOTE: We accept that a profile entry remains when a profiled object is
+  // deleted after Controller::Stop().
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  Controller::Restart();
+  EXPECT_TRUE(Controller::IsProfiling());
+
+  // Remove manually since 'dummy' is not removed from type_profiler_map.
+  EraseType(dummy);
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/unittest_utils.cc b/base/allocator/unittest_utils.cc
new file mode 100644
index 0000000..130ba15
--- /dev/null
+++ b/base/allocator/unittest_utils.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The unittests need a this in order to link up without pulling in tons
+// of other libraries
+
+#include <config.h>
+
+inline int snprintf(char* buffer, size_t count, const char* format, ...) {
+    int result;
+    va_list args;
+    va_start(args, format);
+    result = _vsnprintf(buffer, count, format, args);
+    va_end(args);
+    return result;
+}
+
diff --git a/base/android/OWNERS b/base/android/OWNERS
new file mode 100644
index 0000000..778fb75
--- /dev/null
+++ b/base/android/OWNERS
@@ -0,0 +1,3 @@
+nyquist@chromium.org
+rmcilroy@chromium.org
+yfriedman@chromium.org
diff --git a/base/android/animation_frame_time_histogram.cc b/base/android/animation_frame_time_histogram.cc
new file mode 100644
index 0000000..0d79619
--- /dev/null
+++ b/base/android/animation_frame_time_histogram.cc
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/animation_frame_time_histogram.h"
+
+#include "base/android/jni_string.h"
+#include "base/metrics/histogram_macros.h"
+#include "jni/AnimationFrameTimeHistogram_jni.h"
+
+// static
+void SaveHistogram(JNIEnv* env,
+                   jobject jcaller,
+                   jstring j_histogram_name,
+                   jlongArray j_frame_times_ms,
+                   jint j_count) {
+  jlong *frame_times_ms = env->GetLongArrayElements(j_frame_times_ms, NULL);
+  std::string histogram_name = base::android::ConvertJavaStringToUTF8(
+      env, j_histogram_name);
+
+  for (int i = 0; i < j_count; ++i) {
+    UMA_HISTOGRAM_TIMES(histogram_name.c_str(),
+                        base::TimeDelta::FromMilliseconds(frame_times_ms[i]));
+  }
+}
+
+namespace base {
+namespace android {
+
+// static
+bool RegisterAnimationFrameTimeHistogram(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/animation_frame_time_histogram.h b/base/android/animation_frame_time_histogram.h
new file mode 100644
index 0000000..63f938b
--- /dev/null
+++ b/base/android/animation_frame_time_histogram.h
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
+#define BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterAnimationFrameTimeHistogram(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
diff --git a/base/android/application_status_listener.cc b/base/android/application_status_listener.cc
new file mode 100644
index 0000000..02178c4
--- /dev/null
+++ b/base/android/application_status_listener.cc
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/application_status_listener.h"
+
+#include <jni.h>
+
+#include "base/lazy_instance.h"
+#include "base/observer_list_threadsafe.h"
+#include "jni/ApplicationStatus_jni.h"
+
+namespace {
+struct LeakyLazyObserverListTraits :
+    base::internal::LeakyLazyInstanceTraits<
+        ObserverListThreadSafe<base::android::ApplicationStatusListener> > {
+  static ObserverListThreadSafe<base::android::ApplicationStatusListener>*
+      New(void* instance) {
+    ObserverListThreadSafe<base::android::ApplicationStatusListener>* ret =
+        base::internal::LeakyLazyInstanceTraits<ObserverListThreadSafe<
+            base::android::ApplicationStatusListener> >::New(instance);
+    // Leaky.
+    ret->AddRef();
+    return ret;
+  }
+};
+
+base::LazyInstance<ObserverListThreadSafe<
+    base::android::ApplicationStatusListener>,
+        LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+namespace base {
+namespace android {
+
+ApplicationStatusListener::ApplicationStatusListener(
+    const ApplicationStatusListener::ApplicationStateChangeCallback& callback)
+    : callback_(callback) {
+  DCHECK(!callback_.is_null());
+  g_observers.Get().AddObserver(this);
+
+  Java_ApplicationStatus_registerThreadSafeNativeApplicationStateListener(
+      base::android::AttachCurrentThread());
+}
+
+ApplicationStatusListener::~ApplicationStatusListener() {
+  g_observers.Get().RemoveObserver(this);
+}
+
+void ApplicationStatusListener::Notify(ApplicationState state) {
+  callback_.Run(state);
+}
+
+// static
+bool ApplicationStatusListener::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+// static
+void ApplicationStatusListener::NotifyApplicationStateChange(
+    ApplicationState state) {
+  g_observers.Get().Notify(FROM_HERE, &ApplicationStatusListener::Notify,
+                           state);
+}
+
+static void OnApplicationStateChange(JNIEnv* env,
+                                     jclass clazz,
+                                     jint new_state) {
+  ApplicationState application_state = static_cast<ApplicationState>(new_state);
+  ApplicationStatusListener::NotifyApplicationStateChange(application_state);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/application_status_listener.h b/base/android/application_status_listener.h
new file mode 100644
index 0000000..30048b2
--- /dev/null
+++ b/base/android/application_status_listener.h
@@ -0,0 +1,87 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_APPLICATION_STATUS_LISTENER_H_
+#define BASE_ANDROID_APPLICATION_STATUS_LISTENER_H_
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list_threadsafe.h"
+
+namespace base {
+namespace android {
+
+// Define application state values like APPLICATION_STATE_VISIBLE in a
+// way that ensures they're always the same than their Java counterpart.
+//
+// Note that these states represent the most visible Activity state.
+// If there are activities with states paused and stopped, only
+// HAS_PAUSED_ACTIVITIES should be returned.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
+enum ApplicationState {
+  APPLICATION_STATE_HAS_RUNNING_ACTIVITIES = 1,
+  APPLICATION_STATE_HAS_PAUSED_ACTIVITIES = 2,
+  APPLICATION_STATE_HAS_STOPPED_ACTIVITIES = 3,
+  APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES = 4
+};
+
+// A native helper class to listen to state changes of the Android
+// Application. This mirrors org.chromium.base.ApplicationStatus.
+// any thread.
+//
+// To start listening, create a new instance, passing a callback to a
+// function that takes an ApplicationState parameter. To stop listening,
+// simply delete the listener object. The implementation guarantees
+// that the callback will always be called on the thread that created
+// the listener.
+//
+// Example:
+//
+//    void OnApplicationStateChange(ApplicationState state) {
+//       ...
+//    }
+//
+//    // Start listening.
+//    ApplicationStatusListener* my_listener =
+//        new ApplicationStatusListener(
+//            base::Bind(&OnApplicationStateChange));
+//
+//    ...
+//
+//    // Stop listening.
+//    delete my_listener
+//
+class BASE_EXPORT ApplicationStatusListener {
+ public:
+  typedef base::Callback<void(ApplicationState)> ApplicationStateChangeCallback;
+
+  explicit ApplicationStatusListener(
+      const ApplicationStateChangeCallback& callback);
+  ~ApplicationStatusListener();
+
+  // Internal use: must be public to be called from base_jni_registrar.cc
+  static bool RegisterBindings(JNIEnv* env);
+
+  // Internal use only: must be public to be called from JNI and unit tests.
+  static void NotifyApplicationStateChange(ApplicationState state);
+
+ private:
+  void Notify(ApplicationState state);
+
+  ApplicationStateChangeCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ApplicationStatusListener);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_APPLICATION_STATUS_LISTENER_H_
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
new file mode 100644
index 0000000..ce78bf9
--- /dev/null
+++ b/base/android/application_status_listener_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/application_status_listener.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+using base::android::ScopedJavaLocalRef;
+
+// An invalid ApplicationState value.
+const ApplicationState kInvalidApplicationState =
+    static_cast<ApplicationState>(100);
+
+// Used to generate a callback that stores the new state at a given location.
+void StoreStateTo(ApplicationState* target, ApplicationState state) {
+  *target = state;
+}
+
+void RunTasksUntilIdle() {
+  RunLoop run_loop;
+  run_loop.RunUntilIdle();
+}
+
+// Shared state for the multi-threaded test.
+// This uses a thread to register for events and listen to them, while state
+// changes are forced on the main thread.
+class MultiThreadedTest {
+ public:
+  MultiThreadedTest()
+      : state_(kInvalidApplicationState),
+        event_(false, false),
+        thread_("ApplicationStatusTest thread"),
+        main_() {
+  }
+
+  void Run() {
+    // Start the thread and tell it to register for events.
+    thread_.Start();
+    thread_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
+                              base::Unretained(this)));
+
+    // Wait for its completion.
+    event_.Wait();
+
+    // Change state, then wait for the thread to modify state.
+    ApplicationStatusListener::NotifyApplicationStateChange(
+        APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+    event_.Wait();
+    EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, state_);
+
+    // Again
+    ApplicationStatusListener::NotifyApplicationStateChange(
+        APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
+    event_.Wait();
+    EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, state_);
+  }
+
+ private:
+  void ExpectOnThread() {
+    EXPECT_EQ(thread_.message_loop(), base::MessageLoop::current());
+  }
+
+  void RegisterThreadForEvents() {
+    ExpectOnThread();
+    listener_.reset(new ApplicationStatusListener(base::Bind(
+        &MultiThreadedTest::StoreStateAndSignal, base::Unretained(this))));
+    EXPECT_TRUE(listener_.get());
+    event_.Signal();
+  }
+
+  void StoreStateAndSignal(ApplicationState state) {
+    ExpectOnThread();
+    state_ = state;
+    event_.Signal();
+  }
+
+  ApplicationState state_;
+  base::WaitableEvent event_;
+  base::Thread thread_;
+  base::MessageLoop main_;
+  scoped_ptr<ApplicationStatusListener> listener_;
+};
+
+}  // namespace
+
+TEST(ApplicationStatusListenerTest, SingleThread) {
+  MessageLoop message_loop;
+
+  ApplicationState result = kInvalidApplicationState;
+
+  // Create a new listener that stores the new state into |result| on every
+  // state change.
+  ApplicationStatusListener listener(
+      base::Bind(&StoreStateTo, base::Unretained(&result)));
+
+  EXPECT_EQ(kInvalidApplicationState, result);
+
+  ApplicationStatusListener::NotifyApplicationStateChange(
+      APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+  RunTasksUntilIdle();
+  EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, result);
+
+  ApplicationStatusListener::NotifyApplicationStateChange(
+      APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
+  RunTasksUntilIdle();
+  EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, result);
+}
+
+TEST(ApplicationStatusListenerTest, TwoThreads) {
+  MultiThreadedTest test;
+  test.Run();
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_onload.cc b/base/android/base_jni_onload.cc
new file mode 100644
index 0000000..7ab4982
--- /dev/null
+++ b/base/android/base_jni_onload.cc
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/base_jni_onload.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_utils.h"
+#include "base/android/library_loader/library_loader_hooks.h"
+#include "base/bind.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+bool RegisterJNI(JNIEnv* env) {
+  return RegisterLibraryLoaderEntryHook(env);
+}
+
+bool Init() {
+  InitAtExitManager();
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::InitReplacementClassLoader(env,
+                                            base::android::GetClassLoader(env));
+  return true;
+}
+
+}  // namespace
+
+
+bool OnJNIOnLoadRegisterJNI(JavaVM* vm,
+                            std::vector<RegisterCallback> callbacks) {
+  base::android::InitVM(vm);
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  callbacks.push_back(base::Bind(&RegisterJNI));
+  for (std::vector<RegisterCallback>::reverse_iterator i =
+           callbacks.rbegin(); i != callbacks.rend(); ++i) {
+    if (!i->Run(env))
+      return false;
+  }
+  return true;
+}
+
+bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks) {
+  callbacks.push_back(base::Bind(&Init));
+  for (std::vector<InitCallback>::reverse_iterator i =
+           callbacks.rbegin(); i != callbacks.rend(); ++i) {
+    if (!i->Run())
+      return false;
+  }
+  return true;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_onload.h b/base/android/base_jni_onload.h
new file mode 100644
index 0000000..dcc7756
--- /dev/null
+++ b/base/android/base_jni_onload.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_BASE_JNI_ONLOAD_H_
+#define BASE_ANDROID_BASE_JNI_ONLOAD_H_
+
+#include <jni.h>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+
+namespace base {
+namespace android {
+
+// Returns whether JNI registration succeeded. Caller shall put the
+// RegisterCallback into |callbacks| in reverse order.
+typedef base::Callback<bool(JNIEnv*)> RegisterCallback;
+BASE_EXPORT bool OnJNIOnLoadRegisterJNI(
+    JavaVM* vm,
+    std::vector<RegisterCallback> callbacks);
+
+// Returns whether initialization succeeded. Caller shall put the
+// InitCallback into |callbacks| in reverse order.
+typedef base::Callback<bool(void)> InitCallback;
+BASE_EXPORT bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BASE_JNI_ONLOAD_H_
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
new file mode 100644
index 0000000..43ba635
--- /dev/null
+++ b/base/android/base_jni_registrar.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/android/base_jni_registrar.h"
+
+#include "base/android/animation_frame_time_histogram.h"
+#include "base/android/application_status_listener.h"
+#include "base/android/build_info.h"
+#include "base/android/command_line_android.h"
+#include "base/android/content_uri_utils.h"
+#include "base/android/cpu_features.h"
+#include "base/android/event_log.h"
+#include "base/android/field_trial_list.h"
+#include "base/android/important_file_writer_android.h"
+#include "base/android/java_handler_thread.h"
+#include "base/android/java_runtime.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/android/jni_utils.h"
+#include "base/android/locale_utils.h"
+#include "base/android/memory_pressure_listener_android.h"
+#include "base/android/path_service_android.h"
+#include "base/android/path_utils.h"
+#include "base/android/record_histogram.h"
+#include "base/android/record_user_action.h"
+#include "base/android/sys_utils.h"
+#include "base/android/thread_utils.h"
+#include "base/android/trace_event_binding.h"
+#include "base/basictypes.h"
+#include "base/message_loop/message_pump_android.h"
+#include "base/power_monitor/power_monitor_device_source_android.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace android {
+
+static RegistrationMethod kBaseRegisteredMethods[] = {
+    {"AnimationFrameTimeHistogram",
+     base::android::RegisterAnimationFrameTimeHistogram},
+    {"ApplicationStatusListener",
+     base::android::ApplicationStatusListener::RegisterBindings},
+    {"BuildInfo", base::android::BuildInfo::RegisterBindings},
+    {"CommandLine", base::android::RegisterCommandLine},
+    {"ContentUriUtils", base::RegisterContentUriUtils},
+    {"CpuFeatures", base::android::RegisterCpuFeatures},
+    {"EventLog", base::android::RegisterEventLog},
+    {"FieldTrialList", base::android::RegisterFieldTrialList},
+    {"ImportantFileWriterAndroid",
+     base::android::RegisterImportantFileWriterAndroid},
+    {"JNIUtils", base::android::RegisterJNIUtils},
+    {"LocaleUtils", base::android::RegisterLocaleUtils},
+    {"MemoryPressureListenerAndroid",
+     base::android::MemoryPressureListenerAndroid::Register},
+    {"JavaHandlerThread", base::android::JavaHandlerThread::RegisterBindings},
+    {"PathService", base::android::RegisterPathService},
+    {"PathUtils", base::android::RegisterPathUtils},
+    {"PowerMonitor", base::RegisterPowerMonitor},
+    {"RecordHistogram", base::android::RegisterRecordHistogram},
+    {"RecordUserAction", base::android::RegisterRecordUserAction},
+    {"Runtime", base::android::JavaRuntime::Register},
+    {"SystemMessageHandler", base::MessagePumpForUI::RegisterBindings},
+    {"SysUtils", base::android::SysUtils::Register},
+    {"ThreadUtils", base::RegisterThreadUtils},
+    {"TraceEvent", base::android::RegisterTraceEvent},
+};
+
+bool RegisterJni(JNIEnv* env) {
+  TRACE_EVENT0("startup", "base_android::RegisterJni");
+  return RegisterNativeMethods(env, kBaseRegisteredMethods,
+                               arraysize(kBaseRegisteredMethods));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_registrar.h b/base/android/base_jni_registrar.h
new file mode 100644
index 0000000..fdaf5f2
--- /dev/null
+++ b/base/android/base_jni_registrar.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+#define BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Register all JNI bindings necessary for base.
+BASE_EXPORT bool RegisterJni(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BASE_JNI_REGISTRAR_H_
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
new file mode 100644
index 0000000..4d3cd55
--- /dev/null
+++ b/base/android/build_info.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/build_info.h"
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "jni/BuildInfo_jni.h"
+
+namespace {
+
+// The caller takes ownership of the returned const char*.
+const char* StrDupJString(const base::android::JavaRef<jstring>& java_string) {
+  std::string str = ConvertJavaStringToUTF8(java_string);
+  return strdup(str.c_str());
+}
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+struct BuildInfoSingletonTraits {
+  static BuildInfo* New() {
+    return new BuildInfo(AttachCurrentThread());
+  }
+
+  static void Delete(BuildInfo* x) {
+    // We're leaking this type, see kRegisterAtExit.
+    NOTREACHED();
+  }
+
+  static const bool kRegisterAtExit = false;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+};
+
+BuildInfo::BuildInfo(JNIEnv* env)
+    : device_(StrDupJString(Java_BuildInfo_getDevice(env))),
+      manufacturer_(StrDupJString(Java_BuildInfo_getDeviceManufacturer(env))),
+      model_(StrDupJString(Java_BuildInfo_getDeviceModel(env))),
+      brand_(StrDupJString(Java_BuildInfo_getBrand(env))),
+      android_build_id_(StrDupJString(Java_BuildInfo_getAndroidBuildId(env))),
+      android_build_fp_(StrDupJString(
+          Java_BuildInfo_getAndroidBuildFingerprint(env))),
+      package_version_code_(StrDupJString(Java_BuildInfo_getPackageVersionCode(
+          env, GetApplicationContext()))),
+      package_version_name_(StrDupJString(Java_BuildInfo_getPackageVersionName(
+          env, GetApplicationContext()))),
+      package_label_(StrDupJString(Java_BuildInfo_getPackageLabel(
+          env, GetApplicationContext()))),
+      package_name_(StrDupJString(Java_BuildInfo_getPackageName(
+          env, GetApplicationContext()))),
+      build_type_(StrDupJString(Java_BuildInfo_getBuildType(env))),
+      sdk_int_(Java_BuildInfo_getSdkInt(env)),
+      java_exception_info_(NULL) {
+}
+
+// static
+BuildInfo* BuildInfo::GetInstance() {
+  return Singleton<BuildInfo, BuildInfoSingletonTraits >::get();
+}
+
+void BuildInfo::SetJavaExceptionInfo(const std::string& info) {
+  DCHECK(!java_exception_info_) << "info should be set only once.";
+  java_exception_info_ = strndup(info.c_str(), 4096);
+}
+
+void BuildInfo::ClearJavaExceptionInfo() {
+  delete java_exception_info_;
+  java_exception_info_ = nullptr;
+}
+
+// static
+bool BuildInfo::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/build_info.h b/base/android/build_info.h
new file mode 100644
index 0000000..d6155b9
--- /dev/null
+++ b/base/android/build_info.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_BUILD_INFO_H_
+#define BASE_ANDROID_BUILD_INFO_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/singleton.h"
+
+namespace base {
+namespace android {
+
+// This enumeration maps to the values returned by BuildInfo::sdk_int(),
+// indicating the Android release associated with a given SDK version.
+enum SdkVersion {
+  SDK_VERSION_JELLY_BEAN = 16,
+  SDK_VERSION_JELLY_BEAN_MR1 = 17,
+  SDK_VERSION_JELLY_BEAN_MR2 = 18,
+  SDK_VERSION_KITKAT = 19,
+  SDK_VERSION_KITKAT_WEAR = 20,
+  SDK_VERSION_LOLLIPOP = 21
+};
+
+// BuildInfo is a singleton class that stores android build and device
+// information. It will be called from Android specific code and gets used
+// primarily in crash reporting.
+
+// It is also used to store the last java exception seen during JNI.
+// TODO(nileshagrawal): Find a better place to store this info.
+class BASE_EXPORT BuildInfo {
+ public:
+
+  ~BuildInfo() {}
+
+  // Static factory method for getting the singleton BuildInfo instance.
+  // Note that ownership is not conferred on the caller and the BuildInfo in
+  // question isn't actually freed until shutdown. This is ok because there
+  // should only be one instance of BuildInfo ever created.
+  static BuildInfo* GetInstance();
+
+  // Const char* is used instead of std::strings because these values must be
+  // available even if the process is in a crash state. Sadly
+  // std::string.c_str() doesn't guarantee that memory won't be allocated when
+  // it is called.
+  const char* device() const {
+    return device_;
+  }
+
+  const char* manufacturer() const {
+    return manufacturer_;
+  }
+
+  const char* model() const {
+    return model_;
+  }
+
+  const char* brand() const {
+    return brand_;
+  }
+
+  const char* android_build_id() const {
+    return android_build_id_;
+  }
+
+  const char* android_build_fp() const {
+    return android_build_fp_;
+  }
+
+  const char* package_version_code() const {
+    return package_version_code_;
+  }
+
+  const char* package_version_name() const {
+    return package_version_name_;
+  }
+
+  const char* package_label() const {
+    return package_label_;
+  }
+
+  const char* package_name() const {
+    return package_name_;
+  }
+
+  const char* build_type() const {
+    return build_type_;
+  }
+
+  int sdk_int() const {
+    return sdk_int_;
+  }
+
+  const char* java_exception_info() const {
+    return java_exception_info_;
+  }
+
+  void SetJavaExceptionInfo(const std::string& info);
+
+  void ClearJavaExceptionInfo();
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  friend struct BuildInfoSingletonTraits;
+
+  explicit BuildInfo(JNIEnv* env);
+
+  // Const char* is used instead of std::strings because these values must be
+  // available even if the process is in a crash state. Sadly
+  // std::string.c_str() doesn't guarantee that memory won't be allocated when
+  // it is called.
+  const char* const device_;
+  const char* const manufacturer_;
+  const char* const model_;
+  const char* const brand_;
+  const char* const android_build_id_;
+  const char* const android_build_fp_;
+  const char* const package_version_code_;
+  const char* const package_version_name_;
+  const char* const package_label_;
+  const char* const package_name_;
+  const char* const build_type_;
+  const int sdk_int_;
+  // This is set via set_java_exception_info, not at constructor time.
+  const char* java_exception_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(BuildInfo);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BUILD_INFO_H_
diff --git a/base/android/command_line_android.cc b/base/android/command_line_android.cc
new file mode 100644
index 0000000..064450d
--- /dev/null
+++ b/base/android/command_line_android.cc
@@ -0,0 +1,86 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/command_line_android.h"
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "jni/CommandLine_jni.h"
+
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertJavaStringToUTF8;
+using base::CommandLine;
+
+namespace {
+
+void AppendJavaStringArrayToCommandLine(JNIEnv* env,
+                                        jobjectArray array,
+                                        bool includes_program) {
+  std::vector<std::string> vec;
+  if (array)
+    base::android::AppendJavaStringArrayToStringVector(env, array, &vec);
+  if (!includes_program)
+    vec.insert(vec.begin(), "");
+  CommandLine extra_command_line(vec);
+  CommandLine::ForCurrentProcess()->AppendArguments(extra_command_line,
+                                                    includes_program);
+}
+
+}  // namespace
+
+static void Reset(JNIEnv* env, jclass clazz) {
+  CommandLine::Reset();
+}
+
+static jboolean HasSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  return CommandLine::ForCurrentProcess()->HasSwitch(switch_string);
+}
+
+static jstring GetSwitchValue(JNIEnv* env, jclass clazz, jstring jswitch) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  std::string value(CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+      switch_string));
+  if (value.empty())
+    return 0;
+  // OK to release, JNI binding.
+  return ConvertUTF8ToJavaString(env, value).Release();
+}
+
+static void AppendSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
+}
+
+static void AppendSwitchWithValue(JNIEnv* env, jclass clazz,
+                                  jstring jswitch, jstring jvalue) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  std::string value_string (ConvertJavaStringToUTF8(env, jvalue));
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switch_string,
+                                                      value_string);
+}
+
+static void AppendSwitchesAndArguments(JNIEnv* env, jclass clazz,
+                                       jobjectArray array) {
+  AppendJavaStringArrayToCommandLine(env, array, false);
+}
+
+namespace base {
+namespace android {
+
+void InitNativeCommandLineFromJavaArray(JNIEnv* env, jobjectArray array) {
+  // TODO(port): Make an overload of Init() that takes StringVector rather than
+  // have to round-trip via AppendArguments.
+  CommandLine::Init(0, NULL);
+  AppendJavaStringArrayToCommandLine(env, array, true);
+}
+
+bool RegisterCommandLine(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/command_line_android.h b/base/android/command_line_android.h
new file mode 100644
index 0000000..cf117e2
--- /dev/null
+++ b/base/android/command_line_android.h
@@ -0,0 +1,26 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_COMMAND_LINE_ANDROID_H_
+#define BASE_ANDROID_COMMAND_LINE_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Appends all strings in the given array as flags to the Chrome command line.
+void BASE_EXPORT InitNativeCommandLineFromJavaArray(
+    JNIEnv* env,
+    jobjectArray init_command_line);
+
+// JNI registration boilerplate.
+bool RegisterCommandLine(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_COMMAND_LINE_ANDROID_H_
diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc
new file mode 100644
index 0000000..0482fee
--- /dev/null
+++ b/base/android/content_uri_utils.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/content_uri_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "jni/ContentUriUtils_jni.h"
+
+using base::android::ConvertUTF8ToJavaString;
+
+namespace base {
+
+bool RegisterContentUriUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+bool ContentUriExists(const FilePath& content_uri) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_uri =
+      ConvertUTF8ToJavaString(env, content_uri.value());
+  return Java_ContentUriUtils_contentUriExists(
+      env, base::android::GetApplicationContext(), j_uri.obj());
+}
+
+File OpenContentUriForRead(const FilePath& content_uri) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_uri =
+      ConvertUTF8ToJavaString(env, content_uri.value());
+  jint fd = Java_ContentUriUtils_openContentUriForRead(
+      env, base::android::GetApplicationContext(), j_uri.obj());
+  if (fd < 0)
+    return File();
+  return File(fd);
+}
+
+std::string GetContentUriMimeType(const FilePath& content_uri) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_uri =
+      ConvertUTF8ToJavaString(env, content_uri.value());
+  ScopedJavaLocalRef<jstring> j_mime =
+      Java_ContentUriUtils_getMimeType(
+          env, base::android::GetApplicationContext(), j_uri.obj());
+  return base::android::ConvertJavaStringToUTF8(env, j_mime.obj());
+}
+
+}  // namespace base
diff --git a/base/android/content_uri_utils.h b/base/android/content_uri_utils.h
new file mode 100644
index 0000000..e66b770
--- /dev/null
+++ b/base/android/content_uri_utils.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_CONTENT_URI_UTILS_H_
+#define BASE_ANDROID_CONTENT_URI_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+
+namespace base {
+
+bool RegisterContentUriUtils(JNIEnv* env);
+
+// Opens a content URI for read and returns the file descriptor to the caller.
+// Returns -1 if the URI is invalid.
+BASE_EXPORT File OpenContentUriForRead(const FilePath& content_uri);
+
+// Check whether a content URI exists.
+BASE_EXPORT bool ContentUriExists(const FilePath& content_uri);
+
+// Gets MIME type from a content URI. Returns an empty string if the URI is
+// invalid.
+BASE_EXPORT std::string GetContentUriMimeType(const FilePath& content_uri);
+
+}  // namespace base
+
+#endif  // BASE_ANDROID_CONTENT_URI_UTILS_H_
diff --git a/base/android/content_uri_utils_unittest.cc b/base/android/content_uri_utils_unittest.cc
new file mode 100644
index 0000000..c762035
--- /dev/null
+++ b/base/android/content_uri_utils_unittest.cc
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/content_uri_utils.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/test_file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(ContentUriUtilsTest, ContentUriMimeTest) {
+  // Get the test image path.
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+  FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
+
+  // Insert the image into MediaStore. MediaStore will do some conversions, and
+  // return the content URI.
+  FilePath path = base::InsertImageIntoMediaStore(image_file);
+  EXPECT_TRUE(path.IsContentUri());
+  EXPECT_TRUE(PathExists(path));
+
+  std::string mime = GetContentUriMimeType(path);
+  EXPECT_EQ(mime, std::string("image/png"));
+
+  FilePath invalid_path("content://foo.bar");
+  mime = GetContentUriMimeType(invalid_path);
+  EXPECT_TRUE(mime.empty());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/cpu_features.cc b/base/android/cpu_features.cc
new file mode 100644
index 0000000..6a18695
--- /dev/null
+++ b/base/android/cpu_features.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cpu-features.h>
+
+#include "base/android/jni_android.h"
+#include "jni/CpuFeatures_jni.h"
+
+namespace base {
+namespace android {
+
+jint GetCoreCount(JNIEnv*, jclass) {
+  return android_getCpuCount();
+}
+
+jlong GetCpuFeatures(JNIEnv*, jclass) {
+  return android_getCpuFeatures();
+}
+
+bool RegisterCpuFeatures(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/cpu_features.h b/base/android/cpu_features.h
new file mode 100644
index 0000000..0a27822
--- /dev/null
+++ b/base/android/cpu_features.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_CPU_FEATURES_H_
+#define BASE_ANDROID_CPU_FEATURES_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterCpuFeatures(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_CPU_FEATURES_H_
diff --git a/base/android/event_log.cc b/base/android/event_log.cc
new file mode 100644
index 0000000..a4b1dd1
--- /dev/null
+++ b/base/android/event_log.cc
@@ -0,0 +1,20 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/event_log.h"
+#include "jni/EventLog_jni.h"
+
+namespace base {
+namespace android {
+
+void EventLogWriteInt(int tag, int value) {
+  Java_EventLog_writeEvent(AttachCurrentThread(), tag, value);
+}
+
+bool RegisterEventLog(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/event_log.h b/base/android/event_log.h
new file mode 100644
index 0000000..dad4e4c
--- /dev/null
+++ b/base/android/event_log.h
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_EVENT_LOG_H_
+#define BASE_ANDROID_EVENT_LOG_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+void BASE_EXPORT EventLogWriteInt(int tag, int value);
+
+bool RegisterEventLog(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_EVENT_LOG_H_
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
new file mode 100644
index 0000000..9cb38d2
--- /dev/null
+++ b/base/android/field_trial_list.cc
@@ -0,0 +1,38 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/field_trial_list.h"
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/metrics/field_trial.h"
+#include "jni/FieldTrialList_jni.h"
+
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+
+static jstring FindFullName(JNIEnv* env,
+                            jclass clazz,
+                            jstring jtrial_name) {
+  std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
+  return ConvertUTF8ToJavaString(
+      env,
+      base::FieldTrialList::FindFullName(trial_name)).Release();
+}
+
+static jboolean TrialExists(JNIEnv* env, jclass clazz, jstring jtrial_name) {
+  std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
+  return base::FieldTrialList::TrialExists(trial_name);
+}
+
+namespace base {
+namespace android {
+
+bool RegisterFieldTrialList(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/field_trial_list.h b/base/android/field_trial_list.h
new file mode 100644
index 0000000..b4eaf91
--- /dev/null
+++ b/base/android/field_trial_list.h
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_FIELD_TRIAL_LIST_H_
+#define BASE_ANDROID_FIELD_TRIAL_LIST_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterFieldTrialList(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_FIELD_TRIAL_LIST_H_
diff --git a/base/android/fifo_utils.cc b/base/android/fifo_utils.cc
new file mode 100644
index 0000000..8f3e95f
--- /dev/null
+++ b/base/android/fifo_utils.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/fifo_utils.h"
+
+#include <sys/stat.h>
+
+#include "base/files/file_path.h"
+
+namespace base {
+namespace android {
+
+bool CreateFIFO(const FilePath& path, int mode) {
+  // Default permissions for mkfifo() is ignored, chmod() is required.
+  return mkfifo(path.value().c_str(), mode) == 0 &&
+         chmod(path.value().c_str(), mode) == 0;
+}
+
+bool RedirectStream(FILE* stream, const FilePath& path, const char* mode) {
+  return freopen(path.value().c_str(), mode, stream) != NULL;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/fifo_utils.h b/base/android/fifo_utils.h
new file mode 100644
index 0000000..1936def
--- /dev/null
+++ b/base/android/fifo_utils.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_FIFO_UTILS_H_
+#define BASE_ANDROID_FIFO_UTILS_H_
+
+#include <stdio.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class FilePath;
+
+namespace android {
+
+// Creates a fifo at the given |path| with POSIX permissions set to |mode|,
+// returning true if it was successfully created and permissions were set.
+BASE_EXPORT bool CreateFIFO(const FilePath& path, int mode);
+
+// Redirects the |stream| to the file provided by |path| with |mode|
+// permissions, returning true if successful.
+BASE_EXPORT bool RedirectStream(FILE* stream,
+                                const FilePath& path,
+                                const char* mode);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_FIFO_UTILS_H_
diff --git a/base/android/important_file_writer_android.cc b/base/android/important_file_writer_android.cc
new file mode 100644
index 0000000..bcbd785
--- /dev/null
+++ b/base/android/important_file_writer_android.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/important_file_writer_android.h"
+
+#include <string>
+
+#include "base/android/jni_string.h"
+#include "base/files/important_file_writer.h"
+#include "base/threading/thread_restrictions.h"
+#include "jni/ImportantFileWriterAndroid_jni.h"
+
+namespace base {
+namespace android {
+
+static jboolean WriteFileAtomically(JNIEnv* env,
+                                    jclass /* clazz */,
+                                    jstring file_name,
+                                    jbyteArray data) {
+  // This is called on the UI thread during shutdown to save tab data, so
+  // needs to enable IO.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  std::string native_file_name;
+  base::android::ConvertJavaStringToUTF8(env, file_name, &native_file_name);
+  base::FilePath path(native_file_name);
+  int data_length = env->GetArrayLength(data);
+  jbyte* native_data = env->GetByteArrayElements(data, NULL);
+  std::string native_data_string(reinterpret_cast<char *>(native_data),
+                                 data_length);
+  bool result = base::ImportantFileWriter::WriteFileAtomically(
+      path, native_data_string);
+  env->ReleaseByteArrayElements(data, native_data, JNI_ABORT);
+  return result;
+}
+
+bool RegisterImportantFileWriterAndroid(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/important_file_writer_android.h b/base/android/important_file_writer_android.h
new file mode 100644
index 0000000..88e4441
--- /dev/null
+++ b/base/android/important_file_writer_android.h
@@ -0,0 +1,18 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
+#define BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterImportantFileWriterAndroid(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
diff --git a/base/android/java/src/org/chromium/base/ActivityState.java b/base/android/java/src/org/chromium/base/ActivityState.java
new file mode 100644
index 0000000..98aff62
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ActivityState.java
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * A set of states that represent the last state change of an Activity.
+ */
+public interface ActivityState {
+    /**
+     * Represents Activity#onCreate().
+     */
+    public final int CREATED = 1;
+
+    /**
+     * Represents Activity#onStart().
+     */
+    public final int STARTED = 2;
+
+    /**
+     * Represents Activity#onResume().
+     */
+    public final int RESUMED = 3;
+
+    /**
+     * Represents Activity#onPause().
+     */
+    public final int PAUSED = 4;
+
+    /**
+     * Represents Activity#onStop().
+     */
+    public final int STOPPED = 5;
+
+    /**
+     * Represents Activity#onDestroy().  This is also used when the state of an Activity is unknown.
+     */
+    public final int DESTROYED = 6;
+}
diff --git a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
new file mode 100644
index 0000000..ad5cdd8
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
@@ -0,0 +1,145 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeAnimator;
+import android.animation.TimeAnimator.TimeListener;
+import android.util.Log;
+
+/**
+ * Record Android animation frame rate and save it to UMA histogram. This is mainly for monitoring
+ * any jankiness of short Chrome Android animations. It is limited to few seconds of recording.
+ */
+public class AnimationFrameTimeHistogram {
+    private static final String TAG = "AnimationFrameTimeHistogram";
+    private static final int MAX_FRAME_TIME_NUM = 600; // 10 sec on 60 fps.
+
+    private final Recorder mRecorder = new Recorder();
+    private final String mHistogramName;
+
+    /**
+     * @param histogramName The histogram name that the recorded frame times will be saved.
+     *                      This must be also defined in histograms.xml
+     * @return An AnimatorListener instance that records frame time histogram on start and end
+     *         automatically.
+     */
+    public static AnimatorListener getAnimatorRecorder(final String histogramName) {
+        return new AnimatorListenerAdapter() {
+            private final AnimationFrameTimeHistogram mAnimationFrameTimeHistogram =
+                    new AnimationFrameTimeHistogram(histogramName);
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mAnimationFrameTimeHistogram.startRecording();
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAnimationFrameTimeHistogram.endRecording();
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mAnimationFrameTimeHistogram.endRecording();
+            }
+        };
+    }
+
+    /**
+     * @param histogramName The histogram name that the recorded frame times will be saved.
+     *                      This must be also defined in histograms.xml
+     */
+    public AnimationFrameTimeHistogram(String histogramName) {
+        mHistogramName = histogramName;
+    }
+
+    /**
+     * Start recording frame times. The recording can fail if it exceeds a few seconds.
+     */
+    public void startRecording() {
+        mRecorder.startRecording();
+    }
+
+    /**
+     * End recording and save it to histogram. It won't save histogram if the recording wasn't
+     * successful.
+     */
+    public void endRecording() {
+        if (mRecorder.endRecording()) {
+            nativeSaveHistogram(mHistogramName,
+                    mRecorder.getFrameTimesMs(), mRecorder.getFrameTimesCount());
+        }
+        mRecorder.cleanUp();
+    }
+
+    /**
+     * Record Android animation frame rate and return the result.
+     */
+    private static class Recorder implements TimeListener {
+        // TODO(kkimlabs): If we can use in the future, migrate to Choreographer for minimal
+        //                 workload.
+        private final TimeAnimator mAnimator = new TimeAnimator();
+        private long[] mFrameTimesMs;
+        private int mFrameTimesCount;
+
+        private Recorder() {
+            mAnimator.setTimeListener(this);
+        }
+
+        private void startRecording() {
+            assert !mAnimator.isRunning();
+            mFrameTimesCount = 0;
+            mFrameTimesMs = new long[MAX_FRAME_TIME_NUM];
+            mAnimator.start();
+        }
+
+        /**
+         * @return Whether the recording was successful. If successful, the result is available via
+         *         getFrameTimesNs and getFrameTimesCount.
+         */
+        private boolean endRecording() {
+            boolean succeeded = mAnimator.isStarted();
+            mAnimator.end();
+            return succeeded;
+        }
+
+        private long[] getFrameTimesMs() {
+            return mFrameTimesMs;
+        }
+
+        private int getFrameTimesCount() {
+            return mFrameTimesCount;
+        }
+
+        /**
+         * Deallocates the temporary buffer to record frame times. Must be called after ending
+         * the recording and getting the result.
+         */
+        private void cleanUp() {
+            mFrameTimesMs = null;
+        }
+
+        @Override
+        public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+            if (mFrameTimesCount == mFrameTimesMs.length) {
+                mAnimator.end();
+                cleanUp();
+                Log.w(TAG, "Animation frame time recording reached the maximum number. It's either"
+                        + "the animation took too long or recording end is not called.");
+                return;
+            }
+
+            // deltaTime is 0 for the first frame.
+            if (deltaTime > 0) {
+                mFrameTimesMs[mFrameTimesCount++] = deltaTime;
+            }
+        }
+    }
+
+    private native void nativeSaveHistogram(String histogramName, long[] frameTimesMs, int count);
+}
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
new file mode 100644
index 0000000..76d7396
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -0,0 +1,407 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+/**
+ * Utility class to use new APIs that were added after ICS (API level 14).
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class ApiCompatibilityUtils {
+    private ApiCompatibilityUtils() {
+    }
+
+    /**
+     * Returns true if view's layout direction is right-to-left.
+     *
+     * @param view the View whose layout is being considered
+     */
+    public static boolean isLayoutRtl(View view) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        } else {
+            // All layouts are LTR before JB MR1.
+            return false;
+        }
+    }
+
+    /**
+     * @see Configuration#getLayoutDirection()
+     */
+    public static int getLayoutDirection(Configuration configuration) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return configuration.getLayoutDirection();
+        } else {
+            // All layouts are LTR before JB MR1.
+            return View.LAYOUT_DIRECTION_LTR;
+        }
+    }
+
+    /**
+     * @return True if the running version of the Android supports printing.
+     */
+    public static boolean isPrintingSupported() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+    }
+
+    /**
+     * @see android.view.View#setLayoutDirection(int)
+     */
+    public static void setLayoutDirection(View view, int layoutDirection) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setLayoutDirection(layoutDirection);
+        } else {
+            // Do nothing. RTL layouts aren't supported before JB MR1.
+        }
+    }
+
+    /**
+     * @see android.view.View#setTextAlignment(int)
+     */
+    public static void setTextAlignment(View view, int textAlignment) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setTextAlignment(textAlignment);
+        } else {
+            // Do nothing. RTL text isn't supported before JB MR1.
+        }
+    }
+
+    /**
+     * @see android.view.View#setTextDirection(int)
+     */
+    public static void setTextDirection(View view, int textDirection) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setTextDirection(textDirection);
+        } else {
+            // Do nothing. RTL text isn't supported before JB MR1.
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)
+     */
+    public static void setMarginEnd(MarginLayoutParams layoutParams, int end) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            layoutParams.setMarginEnd(end);
+        } else {
+            layoutParams.rightMargin = end;
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#getMarginEnd()
+     */
+    public static int getMarginEnd(MarginLayoutParams layoutParams) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return layoutParams.getMarginEnd();
+        } else {
+            return layoutParams.rightMargin;
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#setMarginStart(int)
+     */
+    public static void setMarginStart(MarginLayoutParams layoutParams, int start) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            layoutParams.setMarginStart(start);
+        } else {
+            layoutParams.leftMargin = start;
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#getMarginStart()
+     */
+    public static int getMarginStart(MarginLayoutParams layoutParams) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return layoutParams.getMarginStart();
+        } else {
+            return layoutParams.leftMargin;
+        }
+    }
+
+    /**
+     * @see android.view.View#setPaddingRelative(int, int, int, int)
+     */
+    public static void setPaddingRelative(View view, int start, int top, int end, int bottom) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setPaddingRelative(start, top, end, bottom);
+        } else {
+            // Before JB MR1, all layouts are left-to-right, so start == left, etc.
+            view.setPadding(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * @see android.view.View#getPaddingStart()
+     */
+    public static int getPaddingStart(View view) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return view.getPaddingStart();
+        } else {
+            // Before JB MR1, all layouts are left-to-right, so start == left.
+            return view.getPaddingLeft();
+        }
+    }
+
+    /**
+     * @see android.view.View#getPaddingEnd()
+     */
+    public static int getPaddingEnd(View view) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return view.getPaddingEnd();
+        } else {
+            // Before JB MR1, all layouts are left-to-right, so end == right.
+            return view.getPaddingRight();
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setCompoundDrawablesRelative(Drawable, Drawable, Drawable,
+     *      Drawable)
+     */
+    public static void setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top,
+            Drawable end, Drawable bottom) {
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // On JB MR1, due to a platform bug, setCompoundDrawablesRelative() is a no-op if the
+            // view has ever been measured. As a workaround, use setCompoundDrawables() directly.
+            // See: http://crbug.com/368196 and http://crbug.com/361709
+            boolean isRtl = isLayoutRtl(textView);
+            textView.setCompoundDrawables(isRtl ? end : start, top, isRtl ? start : end, bottom);
+        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            textView.setCompoundDrawablesRelative(start, top, end, bottom);
+        } else {
+            textView.setCompoundDrawables(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable,
+     *      Drawable, Drawable, Drawable)
+     */
+    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
+            Drawable start, Drawable top, Drawable end, Drawable bottom) {
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // Work around the platform bug described in setCompoundDrawablesRelative() above.
+            boolean isRtl = isLayoutRtl(textView);
+            textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
+                    isRtl ? start : end, bottom);
+        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
+        } else {
+            textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int,
+     *      int)
+     */
+    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
+            int start, int top, int end, int bottom) {
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // Work around the platform bug described in setCompoundDrawablesRelative() above.
+            boolean isRtl = isLayoutRtl(textView);
+            textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
+                    isRtl ? start : end, bottom);
+        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
+        } else {
+            textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
+        }
+    }
+
+    // These methods have a new name, and the old name is deprecated.
+
+    /**
+     * @see android.app.PendingIntent#getCreatorPackage()
+     */
+    @SuppressWarnings("deprecation")
+    public static String getCreatorPackage(PendingIntent intent) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return intent.getCreatorPackage();
+        } else {
+            return intent.getTargetPackage();
+        }
+    }
+
+    /**
+     * @see android.provider.Settings.Global#DEVICE_PROVISIONED
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    public static boolean isDeviceProvisioned(Context context) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return true;
+        if (context == null) return true;
+        if (context.getContentResolver() == null) return true;
+        return Settings.Global.getInt(
+                context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    /**
+     * @see android.app.Activity#finishAndRemoveTask()
+     */
+    public static void finishAndRemoveTask(Activity activity) {
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+            activity.finishAndRemoveTask();
+        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+            // crbug.com/395772 : Fallback for Activity.finishAndRemoveTask() failing.
+            new FinishAndRemoveTaskWithRetry(activity).run();
+        } else {
+            activity.finish();
+        }
+    }
+
+    private static class FinishAndRemoveTaskWithRetry implements Runnable {
+        private static final long RETRY_DELAY_MS = 500;
+        private static final long MAX_TRY_COUNT = 3;
+        private final Activity mActivity;
+        private int mTryCount;
+
+        FinishAndRemoveTaskWithRetry(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void run() {
+            mActivity.finishAndRemoveTask();
+            mTryCount++;
+            if (!mActivity.isFinishing()) {
+                if (mTryCount < MAX_TRY_COUNT) {
+                    ThreadUtils.postOnUiThreadDelayed(this, RETRY_DELAY_MS);
+                } else {
+                    mActivity.finish();
+                }
+            }
+        }
+    }
+
+    /**
+     * @return Whether the screen of the device is interactive.
+     */
+    @SuppressWarnings("deprecation")
+    public static boolean isInteractive(Context context) {
+        PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
+            return manager.isInteractive();
+        } else {
+            return manager.isScreenOn();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    public static int getActivityNewDocumentFlag() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+        } else {
+            return Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
+        }
+    }
+
+    /**
+     * @see android.provider.Settings.Secure#SKIP_FIRST_USE_HINTS
+     */
+    public static boolean shouldSkipFirstUseHints(ContentResolver contentResolver) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return Settings.Secure.getInt(
+                    contentResolver, Settings.Secure.SKIP_FIRST_USE_HINTS, 0) != 0;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @param activity Activity that should get the task description update.
+     * @param title Title of the activity.
+     * @param icon Icon of the activity.
+     * @param color Color of the activity.
+     */
+    public static void setTaskDescription(Activity activity, String title, Bitmap icon, int color) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            ActivityManager.TaskDescription description =
+                    new ActivityManager.TaskDescription(title, icon, color);
+            activity.setTaskDescription(description);
+        }
+    }
+
+    /**
+     * @see android.view.Window#setStatusBarColor(int color).
+     * TODO(ianwen): remove this method after downstream rolling.
+     */
+    public static void setStatusBarColor(Activity activity, int statusBarColor) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // If both system bars are black, we can remove these from our layout,
+            // removing or shrinking the SurfaceFlinger overlay required for our views.
+            Window window = activity.getWindow();
+            if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
+                window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            } else {
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            }
+            window.setStatusBarColor(statusBarColor);
+        }
+    }
+
+    /**
+     * @see android.view.Window#setStatusBarColor(int color).
+     */
+    public static void setStatusBarColor(Window window, int statusBarColor) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // If both system bars are black, we can remove these from our layout,
+            // removing or shrinking the SurfaceFlinger overlay required for our views.
+            if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
+                window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            } else {
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            }
+            window.setStatusBarColor(statusBarColor);
+        }
+    }
+
+    /**
+     * @see android.content.res.Resources#getDrawable(int id).
+     */
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawable(Resources res, int id) throws NotFoundException {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return res.getDrawable(id, null);
+        } else {
+            return res.getDrawable(id);
+        }
+    }
+
+    /**
+     * @see android.content.res.Resources#getDrawableForDensity(int id, int density).
+     */
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawableForDensity(Resources res, int id, int density) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return res.getDrawableForDensity(id, density, null);
+        } else {
+            return res.getDrawableForDensity(id, density);
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java
new file mode 100644
index 0000000..8c36b61
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java
@@ -0,0 +1,448 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.Context;
+import android.os.Bundle;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Provides information about the current activity's status, and a way
+ * to register / unregister listeners for state changes.
+ */
+@JNINamespace("base::android")
+public class ApplicationStatus {
+    private static class ActivityInfo {
+        private int mStatus = ActivityState.DESTROYED;
+        private ObserverList<ActivityStateListener> mListeners =
+                new ObserverList<ActivityStateListener>();
+
+        /**
+         * @return The current {@link ActivityState} of the activity.
+         */
+        public int getStatus() {
+            return mStatus;
+        }
+
+        /**
+         * @param status The new {@link ActivityState} of the activity.
+         */
+        public void setStatus(int status) {
+            mStatus = status;
+        }
+
+        /**
+         * @return A list of {@link ActivityStateListener}s listening to this activity.
+         */
+        public ObserverList<ActivityStateListener> getListeners() {
+            return mListeners;
+        }
+    }
+
+    private static Application sApplication;
+
+    private static Object sCachedApplicationStateLock = new Object();
+    private static Integer sCachedApplicationState;
+
+    /** Last activity that was shown (or null if none or it was destroyed). */
+    private static Activity sActivity;
+
+    /** A lazily initialized listener that forwards application state changes to native. */
+    private static ApplicationStateListener sNativeApplicationStateListener;
+
+    /**
+     * A map of which observers listen to state changes from which {@link Activity}.
+     */
+    private static final Map<Activity, ActivityInfo> sActivityInfo =
+            new ConcurrentHashMap<Activity, ActivityInfo>();
+
+    /**
+     * A list of observers to be notified when any {@link Activity} has a state change.
+     */
+    private static final ObserverList<ActivityStateListener> sGeneralActivityStateListeners =
+            new ObserverList<ActivityStateListener>();
+
+    /**
+     * A list of observers to be notified when the visibility state of this {@link Application}
+     * changes.  See {@link #getStateForApplication()}.
+     */
+    private static final ObserverList<ApplicationStateListener> sApplicationStateListeners =
+            new ObserverList<ApplicationStateListener>();
+
+    /**
+     * Interface to be implemented by listeners.
+     */
+    public interface ApplicationStateListener {
+        /**
+         * Called when the application's state changes.
+         * @param newState The application state.
+         */
+        public void onApplicationStateChange(int newState);
+    }
+
+    /**
+     * Interface to be implemented by listeners.
+     */
+    public interface ActivityStateListener {
+        /**
+         * Called when the activity's state changes.
+         * @param activity The activity that had a state change.
+         * @param newState New activity state.
+         */
+        public void onActivityStateChange(Activity activity, int newState);
+    }
+
+    private ApplicationStatus() {}
+
+    /**
+     * Initializes the activity status for a specified application.
+     *
+     * @param application The application whose status you wish to monitor.
+     */
+    public static void initialize(BaseChromiumApplication application) {
+        sApplication = application;
+
+        application.registerWindowFocusChangedListener(
+                new BaseChromiumApplication.WindowFocusChangedListener() {
+                    @Override
+                    public void onWindowFocusChanged(Activity activity, boolean hasFocus) {
+                        if (!hasFocus || activity == sActivity) return;
+
+                        int state = getStateForActivity(activity);
+
+                        if (state != ActivityState.DESTROYED && state != ActivityState.STOPPED) {
+                            sActivity = activity;
+                        }
+
+                        // TODO(dtrainor): Notify of active activity change?
+                    }
+                });
+
+        application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+            @Override
+            public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
+                onStateChange(activity, ActivityState.CREATED);
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                onStateChange(activity, ActivityState.DESTROYED);
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+                onStateChange(activity, ActivityState.PAUSED);
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                onStateChange(activity, ActivityState.RESUMED);
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                onStateChange(activity, ActivityState.STARTED);
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                onStateChange(activity, ActivityState.STOPPED);
+            }
+        });
+    }
+
+    /**
+     * Must be called by the main activity when it changes state.
+     *
+     * @param activity Current activity.
+     * @param newState New state value.
+     */
+    private static void onStateChange(Activity activity, int newState) {
+        if (activity == null) throw new IllegalArgumentException("null activity is not supported");
+
+        if (sActivity == null
+                || newState == ActivityState.CREATED
+                || newState == ActivityState.RESUMED
+                || newState == ActivityState.STARTED) {
+            sActivity = activity;
+        }
+
+        int oldApplicationState = getStateForApplication();
+
+        if (newState == ActivityState.CREATED) {
+            assert !sActivityInfo.containsKey(activity);
+            sActivityInfo.put(activity, new ActivityInfo());
+        }
+
+        // Invalidate the cached application state.
+        synchronized (sCachedApplicationStateLock) {
+            sCachedApplicationState = null;
+        }
+
+        ActivityInfo info = sActivityInfo.get(activity);
+        info.setStatus(newState);
+
+        // Notify all state observers that are specifically listening to this activity.
+        for (ActivityStateListener listener : info.getListeners()) {
+            listener.onActivityStateChange(activity, newState);
+        }
+
+        // Notify all state observers that are listening globally for all activity state
+        // changes.
+        for (ActivityStateListener listener : sGeneralActivityStateListeners) {
+            listener.onActivityStateChange(activity, newState);
+        }
+
+        int applicationState = getStateForApplication();
+        if (applicationState != oldApplicationState) {
+            for (ApplicationStateListener listener : sApplicationStateListeners) {
+                listener.onApplicationStateChange(applicationState);
+            }
+        }
+
+        if (newState == ActivityState.DESTROYED) {
+            sActivityInfo.remove(activity);
+            if (activity == sActivity) sActivity = null;
+        }
+    }
+
+    /**
+     * Testing method to update the state of the specified activity.
+     */
+    @VisibleForTesting
+    public static void onStateChangeForTesting(Activity activity, int newState) {
+        onStateChange(activity, newState);
+    }
+
+    /**
+     * @return The most recent focused {@link Activity} tracked by this class.  Being focused means
+     *         out of all the activities tracked here, it has most recently gained window focus.
+     */
+    public static Activity getLastTrackedFocusedActivity() {
+        return sActivity;
+    }
+
+    /**
+     * @return A {@link List} of all non-destroyed {@link Activity}s.
+     */
+    public static List<WeakReference<Activity>> getRunningActivities() {
+        List<WeakReference<Activity>> activities = new ArrayList<WeakReference<Activity>>();
+        for (Activity activity : sActivityInfo.keySet()) {
+            activities.add(new WeakReference<Activity>(activity));
+        }
+        return activities;
+    }
+
+    /**
+     * @return The {@link Context} for the {@link Application}.
+     */
+    public static Context getApplicationContext() {
+        return sApplication != null ? sApplication.getApplicationContext() : null;
+    }
+
+    /**
+     * Query the state for a given activity.  If the activity is not being tracked, this will
+     * return {@link ActivityState#DESTROYED}.
+     *
+     * <p>
+     * Please note that Chrome can have multiple activities running simultaneously.  Please also
+     * look at {@link #getStateForApplication()} for more details.
+     *
+     * <p>
+     * When relying on this method, be familiar with the expected life cycle state
+     * transitions:
+     * <a href="http://developer.android.com/guide/components/activities.html#Lifecycle">
+     *   Activity Lifecycle
+     * </a>
+     *
+     * <p>
+     * During activity transitions (activity B launching in front of activity A), A will completely
+     * paused before the creation of activity B begins.
+     *
+     * <p>
+     * A basic flow for activity A starting, followed by activity B being opened and then closed:
+     * <ul>
+     *   <li> -- Starting Activity A --
+     *   <li> Activity A - ActivityState.CREATED
+     *   <li> Activity A - ActivityState.STARTED
+     *   <li> Activity A - ActivityState.RESUMED
+     *   <li> -- Starting Activity B --
+     *   <li> Activity A - ActivityState.PAUSED
+     *   <li> Activity B - ActivityState.CREATED
+     *   <li> Activity B - ActivityState.STARTED
+     *   <li> Activity B - ActivityState.RESUMED
+     *   <li> Activity A - ActivityState.STOPPED
+     *   <li> -- Closing Activity B, Activity A regaining focus --
+     *   <li> Activity B - ActivityState.PAUSED
+     *   <li> Activity A - ActivityState.STARTED
+     *   <li> Activity A - ActivityState.RESUMED
+     *   <li> Activity B - ActivityState.STOPPED
+     *   <li> Activity B - ActivityState.DESTROYED
+     * </ul>
+     *
+     * @param activity The activity whose state is to be returned.
+     * @return The state of the specified activity (see {@link ActivityState}).
+     */
+    public static int getStateForActivity(Activity activity) {
+        ActivityInfo info = sActivityInfo.get(activity);
+        return info != null ? info.getStatus() : ActivityState.DESTROYED;
+    }
+
+    /**
+     * @return The state of the application (see {@link ApplicationState}).
+     */
+    public static int getStateForApplication() {
+        synchronized (sCachedApplicationStateLock) {
+            if (sCachedApplicationState == null) {
+                sCachedApplicationState = determineApplicationState();
+            }
+            return sCachedApplicationState.intValue();
+        }
+    }
+
+    /**
+     * Checks whether or not any Activity in this Application is visible to the user.  Note that
+     * this includes the PAUSED state, which can happen when the Activity is temporarily covered
+     * by another Activity's Fragment (e.g.).
+     * @return Whether any Activity under this Application is visible.
+     */
+    public static boolean hasVisibleActivities() {
+        int state = getStateForApplication();
+        return state == ApplicationState.HAS_RUNNING_ACTIVITIES
+                || state == ApplicationState.HAS_PAUSED_ACTIVITIES;
+    }
+
+    /**
+     * Checks to see if there are any active Activity instances being watched by ApplicationStatus.
+     * @return True if all Activities have been destroyed.
+     */
+    public static boolean isEveryActivityDestroyed() {
+        return sActivityInfo.isEmpty();
+    }
+
+    /**
+     * Registers the given listener to receive state changes for all activities.
+     * @param listener Listener to receive state changes.
+     */
+    public static void registerStateListenerForAllActivities(ActivityStateListener listener) {
+        sGeneralActivityStateListeners.addObserver(listener);
+    }
+
+    /**
+     * Registers the given listener to receive state changes for {@code activity}.  After a call to
+     * {@link ActivityStateListener#onActivityStateChange(Activity, int)} with
+     * {@link ActivityState#DESTROYED} all listeners associated with that particular
+     * {@link Activity} are removed.
+     * @param listener Listener to receive state changes.
+     * @param activity Activity to track or {@code null} to track all activities.
+     */
+    public static void registerStateListenerForActivity(ActivityStateListener listener,
+            Activity activity) {
+        assert activity != null;
+
+        ActivityInfo info = sActivityInfo.get(activity);
+        assert info != null && info.getStatus() != ActivityState.DESTROYED;
+        info.getListeners().addObserver(listener);
+    }
+
+    /**
+     * Unregisters the given listener from receiving activity state changes.
+     * @param listener Listener that doesn't want to receive state changes.
+     */
+    public static void unregisterActivityStateListener(ActivityStateListener listener) {
+        sGeneralActivityStateListeners.removeObserver(listener);
+
+        // Loop through all observer lists for all activities and remove the listener.
+        for (ActivityInfo info : sActivityInfo.values()) {
+            info.getListeners().removeObserver(listener);
+        }
+    }
+
+    /**
+     * Registers the given listener to receive state changes for the application.
+     * @param listener Listener to receive state state changes.
+     */
+    public static void registerApplicationStateListener(ApplicationStateListener listener) {
+        sApplicationStateListeners.addObserver(listener);
+    }
+
+    /**
+     * Unregisters the given listener from receiving state changes.
+     * @param listener Listener that doesn't want to receive state changes.
+     */
+    public static void unregisterApplicationStateListener(ApplicationStateListener listener) {
+        sApplicationStateListeners.removeObserver(listener);
+    }
+
+    /**
+     * Registers the single thread-safe native activity status listener.
+     * This handles the case where the caller is not on the main thread.
+     * Note that this is used by a leaky singleton object from the native
+     * side, hence lifecycle management is greatly simplified.
+     */
+    @CalledByNative
+    private static void registerThreadSafeNativeApplicationStateListener() {
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (sNativeApplicationStateListener != null) return;
+
+                sNativeApplicationStateListener = new ApplicationStateListener() {
+                    @Override
+                    public void onApplicationStateChange(int newState) {
+                        nativeOnApplicationStateChange(newState);
+                    }
+                };
+                registerApplicationStateListener(sNativeApplicationStateListener);
+            }
+        });
+    }
+
+    /**
+     * Determines the current application state as defined by {@link ApplicationState}.  This will
+     * loop over all the activities and check their state to determine what the general application
+     * state should be.
+     * @return HAS_RUNNING_ACTIVITIES if any activity is not paused, stopped, or destroyed.
+     *         HAS_PAUSED_ACTIVITIES if none are running and one is paused.
+     *         HAS_STOPPED_ACTIVITIES if none are running/paused and one is stopped.
+     *         HAS_DESTROYED_ACTIVITIES if none are running/paused/stopped.
+     */
+    private static int determineApplicationState() {
+        boolean hasPausedActivity = false;
+        boolean hasStoppedActivity = false;
+
+        for (ActivityInfo info : sActivityInfo.values()) {
+            int state = info.getStatus();
+            if (state != ActivityState.PAUSED
+                    && state != ActivityState.STOPPED
+                    && state != ActivityState.DESTROYED) {
+                return ApplicationState.HAS_RUNNING_ACTIVITIES;
+            } else if (state == ActivityState.PAUSED) {
+                hasPausedActivity = true;
+            } else if (state == ActivityState.STOPPED) {
+                hasStoppedActivity = true;
+            }
+        }
+
+        if (hasPausedActivity) return ApplicationState.HAS_PAUSED_ACTIVITIES;
+        if (hasStoppedActivity) return ApplicationState.HAS_STOPPED_ACTIVITIES;
+        return ApplicationState.HAS_DESTROYED_ACTIVITIES;
+    }
+
+    // Called to notify the native side of state changes.
+    // IMPORTANT: This is always called on the main thread!
+    private static native void nativeOnApplicationStateChange(int newState);
+}
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
new file mode 100644
index 0000000..2946f6f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -0,0 +1,124 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.Window;
+
+/**
+ * Basic application functionality that should be shared among all browser applications.
+ */
+public class BaseChromiumApplication extends Application {
+    /**
+     * Interface to be implemented by listeners for window focus events.
+     */
+    public interface WindowFocusChangedListener {
+        /**
+         * Called when the window focus changes for {@code activity}.
+         * @param activity The {@link Activity} that has a window focus changed event.
+         * @param hasFocus Whether or not {@code activity} gained or lost focus.
+         */
+        public void onWindowFocusChanged(Activity activity, boolean hasFocus);
+    }
+
+    private ObserverList<WindowFocusChangedListener> mWindowFocusListeners =
+            new ObserverList<WindowFocusChangedListener>();
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        ApplicationStatus.initialize(this);
+
+        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+            @Override
+            public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
+                Window.Callback callback = activity.getWindow().getCallback();
+                activity.getWindow().setCallback(new WindowCallbackWrapper(callback) {
+                    @Override
+                    public void onWindowFocusChanged(boolean hasFocus) {
+                        super.onWindowFocusChanged(hasFocus);
+
+                        for (WindowFocusChangedListener listener : mWindowFocusListeners) {
+                            listener.onWindowFocusChanged(activity, hasFocus);
+                        }
+                    }
+
+                    @Override
+                    public boolean dispatchKeyEvent(KeyEvent event) {
+                        // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals
+                        // KEYCODE_MENU. (see b/20529185)
+                        if (event.getKeyCode() == KeyEvent.KEYCODE_MENU
+                                && activity.dispatchKeyEvent(event)) {
+                            return true;
+                        }
+                        return super.dispatchKeyEvent(event);
+                    }
+                });
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper;
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+                assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper;
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper;
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+                assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper;
+            }
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper;
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                assert activity.getWindow().getCallback() instanceof WindowCallbackWrapper;
+            }
+        });
+    }
+
+    /**
+     * Registers a listener to receive window focus updates on activities in this application.
+     * @param listener Listener to receive window focus events.
+     */
+    public void registerWindowFocusChangedListener(WindowFocusChangedListener listener) {
+        mWindowFocusListeners.addObserver(listener);
+    }
+
+    /**
+     * Unregisters a listener from receiving window focus updates on activities in this application.
+     * @param listener Listener that doesn't want to receive window focus events.
+     */
+    public void unregisterWindowFocusChangedListener(WindowFocusChangedListener listener) {
+        mWindowFocusListeners.removeObserver(listener);
+    }
+
+    /** Initializes the {@link CommandLine}. */
+    public void initCommandLine() {}
+
+    /**
+     * This must only be called for contexts whose application is a subclass of
+     * {@link BaseChromiumApplication}.
+     */
+    @VisibleForTesting
+    public static void initCommandLine(Context context) {
+        ((BaseChromiumApplication) context.getApplicationContext()).initCommandLine();
+    };
+}
diff --git a/base/android/java/src/org/chromium/base/BaseSwitches.java b/base/android/java/src/org/chromium/base/BaseSwitches.java
new file mode 100644
index 0000000..ad73e15
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BaseSwitches.java
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * Contains all of the command line switches that are specific to the base/
+ * portion of Chromium on Android.
+ */
+public abstract class BaseSwitches {
+    // Block onCreate() of Chrome until a Java debugger is attached.
+    public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger";
+
+    // Block ChildProcessMain thread of render process service until a Java debugger is attached.
+    public static final String RENDERER_WAIT_FOR_JAVA_DEBUGGER = "renderer-wait-for-java-debugger";
+
+    // Force low-end device mode when set.
+    public static final String ENABLE_LOW_END_DEVICE_MODE = "enable-low-end-device-mode";
+
+    // Force disabling of low-end device mode when set.
+    public static final String DISABLE_LOW_END_DEVICE_MODE = "disable-low-end-device-mode";
+
+    // Adds additional thread idle time information into the trace event output.
+    public static final String ENABLE_IDLE_TRACING = "enable-idle-tracing";
+
+    // Default country code to be used for search engine localization.
+    public static final String DEFAULT_COUNTRY_CODE_AT_INSTALL = "default-country-code";
+
+    // Prevent instantiation.
+    private BaseSwitches() {}
+}
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
new file mode 100644
index 0000000..54f611d
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -0,0 +1,125 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.util.Log;
+
+/**
+ * BuildInfo is a utility class providing easy access to {@link PackageInfo}
+ * information. This is primarly of use for accessesing package information
+ * from native code.
+ */
+public class BuildInfo {
+    private static final String TAG = "BuildInfo";
+    private static final int MAX_FINGERPRINT_LENGTH = 128;
+
+    /**
+     * BuildInfo is a static utility class and therefore shouldn't be
+     * instantiated.
+     */
+    private BuildInfo() {
+    }
+
+    @CalledByNative
+    public static String getDevice() {
+        return Build.DEVICE;
+    }
+
+    @CalledByNative
+    public static String getBrand() {
+        return Build.BRAND;
+    }
+
+    @CalledByNative
+    public static String getAndroidBuildId() {
+        return Build.ID;
+    }
+
+    /**
+     * @return The build fingerprint for the current Android install.  The value is truncated to a
+     *         128 characters as this is used for crash and UMA reporting, which should avoid huge
+     *         strings.
+     */
+    @CalledByNative
+    public static String getAndroidBuildFingerprint() {
+        return Build.FINGERPRINT.substring(
+                0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
+    }
+
+    @CalledByNative
+    public static String getDeviceManufacturer() {
+        return Build.MANUFACTURER;
+    }
+
+    @CalledByNative
+    public static String getDeviceModel() {
+        return Build.MODEL;
+    }
+
+    @CalledByNative
+    public static String getPackageVersionCode(Context context) {
+        String msg = "versionCode not available.";
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+            msg = "";
+            if (pi.versionCode > 0) {
+                msg = Integer.toString(pi.versionCode);
+            }
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, msg);
+        }
+        return msg;
+
+    }
+
+    @CalledByNative
+    public static String getPackageVersionName(Context context) {
+        String msg = "versionName not available";
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+            msg = pi.versionName;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, msg);
+        }
+        return msg;
+    }
+
+    @CalledByNative
+    public static String getPackageLabel(Context context) {
+        try {
+            PackageManager packageManager = context.getPackageManager();
+            ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(),
+                    PackageManager.GET_META_DATA);
+            CharSequence label = packageManager.getApplicationLabel(appInfo);
+            return  label != null ? label.toString() : "";
+        } catch (NameNotFoundException e) {
+            return "";
+        }
+    }
+
+    @CalledByNative
+    public static String getPackageName(Context context) {
+        String packageName = context != null ? context.getPackageName() : null;
+        return packageName != null ? packageName : "";
+    }
+
+    @CalledByNative
+    public static String getBuildType() {
+        return Build.TYPE;
+    }
+
+    @CalledByNative
+    public static int getSdkInt() {
+        return Build.VERSION.SDK_INT;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/CalledByNative.java b/base/android/java/src/org/chromium/base/CalledByNative.java
new file mode 100644
index 0000000..3e6315e
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CalledByNative.java
@@ -0,0 +1,23 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNative is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface CalledByNative {
+    /*
+     *  If present, tells which inner class the method belongs to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/CollectionUtil.java b/base/android/java/src/org/chromium/base/CollectionUtil.java
new file mode 100644
index 0000000..4a4c754
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CollectionUtil.java
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+/**
+ * Functions used for easier initialization of Java collections. Inspired by
+ * functionality in com.google.common.collect in Guava but cherry-picked to
+ * bare-minimum functionality to avoid bloat. (http://crbug.com/272790 provides
+ * further details)
+ */
+public final class CollectionUtil {
+    private CollectionUtil() {}
+
+    @SafeVarargs
+    public static <E> HashSet<E> newHashSet(E... elements) {
+        HashSet<E> set = new HashSet<E>(elements.length);
+        Collections.addAll(set, elements);
+        return set;
+    }
+
+    @SafeVarargs
+    public static <E> ArrayList<E> newArrayList(E... elements) {
+        ArrayList<E> list = new ArrayList<E>(elements.length);
+        Collections.addAll(list, elements);
+        return list;
+    }
+
+    public static <E> ArrayList<E> newArrayList(Iterable<E> iterable) {
+        ArrayList<E> list = new ArrayList<E>();
+        for (E element : iterable) {
+            list.add(element);
+        }
+        return list;
+    }
+}
\ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java
new file mode 100644
index 0000000..9f54079
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -0,0 +1,383 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Java mirror of base/command_line.h.
+ * Android applications don't have command line arguments. Instead, they're "simulated" by reading a
+ * file at a specific location early during startup. Applications each define their own files, e.g.,
+ * ContentShellApplication.COMMAND_LINE_FILE or ChromeShellApplication.COMMAND_LINE_FILE.
+**/
+public abstract class CommandLine {
+    // Public abstract interface, implemented in derived classes.
+    // All these methods reflect their native-side counterparts.
+    /**
+     *  Returns true if this command line contains the given switch.
+     *  (Switch names ARE case-sensitive).
+     */
+    @VisibleForTesting
+    public abstract boolean hasSwitch(String switchString);
+
+    /**
+     * Return the value associated with the given switch, or null.
+     * @param switchString The switch key to lookup. It should NOT start with '--' !
+     * @return switch value, or null if the switch is not set or set to empty.
+     */
+    public abstract String getSwitchValue(String switchString);
+
+    /**
+     * Return the value associated with the given switch, or {@code defaultValue} if the switch
+     * was not specified.
+     * @param switchString The switch key to lookup. It should NOT start with '--' !
+     * @param defaultValue The default value to return if the switch isn't set.
+     * @return Switch value, or {@code defaultValue} if the switch is not set or set to empty.
+     */
+    public String getSwitchValue(String switchString, String defaultValue) {
+        String value = getSwitchValue(switchString);
+        return TextUtils.isEmpty(value) ? defaultValue : value;
+    }
+
+    /**
+     * Append a switch to the command line.  There is no guarantee
+     * this action happens before the switch is needed.
+     * @param switchString the switch to add.  It should NOT start with '--' !
+     */
+    @VisibleForTesting
+    public abstract void appendSwitch(String switchString);
+
+    /**
+     * Append a switch and value to the command line.  There is no
+     * guarantee this action happens before the switch is needed.
+     * @param switchString the switch to add.  It should NOT start with '--' !
+     * @param value the value for this switch.
+     * For example, --foo=bar becomes 'foo', 'bar'.
+     */
+    public abstract void appendSwitchWithValue(String switchString, String value);
+
+    /**
+     * Append switch/value items in "command line" format (excluding argv[0] program name).
+     * E.g. { '--gofast', '--username=fred' }
+     * @param array an array of switch or switch/value items in command line format.
+     *   Unlike the other append routines, these switches SHOULD start with '--' .
+     *   Unlike init(), this does not include the program name in array[0].
+     */
+    public abstract void appendSwitchesAndArguments(String[] array);
+
+    /**
+     * Determine if the command line is bound to the native (JNI) implementation.
+     * @return true if the underlying implementation is delegating to the native command line.
+     */
+    public boolean isNativeImplementation() {
+        return false;
+    }
+
+    private static final AtomicReference<CommandLine> sCommandLine =
+            new AtomicReference<CommandLine>();
+
+    /**
+     * @returns true if the command line has already been initialized.
+     */
+    public static boolean isInitialized() {
+        return sCommandLine.get() != null;
+    }
+
+    // Equivalent to CommandLine::ForCurrentProcess in C++.
+    @VisibleForTesting
+    public static CommandLine getInstance() {
+        CommandLine commandLine = sCommandLine.get();
+        assert commandLine != null;
+        return commandLine;
+    }
+
+    /**
+     * Initialize the singleton instance, must be called exactly once (either directly or
+     * via one of the convenience wrappers below) before using the static singleton instance.
+     * @param args command line flags in 'argv' format: args[0] is the program name.
+     */
+    public static void init(String[] args) {
+        setInstance(new JavaCommandLine(args));
+    }
+
+    /**
+     * Initialize the command line from the command-line file.
+     *
+     * @param file The fully qualified command line file.
+     */
+    public static void initFromFile(String file) {
+        // Arbitrary clamp of 8k on the amount of file we read in.
+        char[] buffer = readUtf8FileFully(file, 8 * 1024);
+        init(buffer == null ? null : tokenizeQuotedAruments(buffer));
+    }
+
+    /**
+     * Resets both the java proxy and the native command lines. This allows the entire
+     * command line initialization to be re-run including the call to onJniLoaded.
+     */
+    @VisibleForTesting
+    public static void reset() {
+        setInstance(null);
+    }
+
+    /**
+     * Public for testing (TODO: why are the tests in a different package?)
+     * Parse command line flags from a flat buffer, supporting double-quote enclosed strings
+     * containing whitespace. argv elements are derived by splitting the buffer on whitepace;
+     * double quote characters may enclose tokens containing whitespace; a double-quote literal
+     * may be escaped with back-slash. (Otherwise backslash is taken as a literal).
+     * @param buffer A command line in command line file format as described above.
+     * @return the tokenized arguments, suitable for passing to init().
+     */
+    public static String[] tokenizeQuotedAruments(char[] buffer) {
+        ArrayList<String> args = new ArrayList<String>();
+        StringBuilder arg = null;
+        final char noQuote = '\0';
+        final char singleQuote = '\'';
+        final char doubleQuote = '"';
+        char currentQuote = noQuote;
+        for (char c : buffer) {
+            // Detect start or end of quote block.
+            if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote))
+                    || c == currentQuote) {
+                if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') {
+                    // Last char was a backslash; pop it, and treat c as a literal.
+                    arg.setCharAt(arg.length() - 1, c);
+                } else {
+                    currentQuote = currentQuote == noQuote ? c : noQuote;
+                }
+            } else if (currentQuote == noQuote && Character.isWhitespace(c)) {
+                if (arg != null) {
+                    args.add(arg.toString());
+                    arg = null;
+                }
+            } else {
+                if (arg == null) arg = new StringBuilder();
+                arg.append(c);
+            }
+        }
+        if (arg != null) {
+            if (currentQuote != noQuote) {
+                Log.w(TAG, "Unterminated quoted string: " + arg);
+            }
+            args.add(arg.toString());
+        }
+        return args.toArray(new String[args.size()]);
+    }
+
+    private static final String TAG = "CommandLine";
+    private static final String SWITCH_PREFIX = "--";
+    private static final String SWITCH_TERMINATOR = SWITCH_PREFIX;
+    private static final String SWITCH_VALUE_SEPARATOR = "=";
+
+    public static void enableNativeProxy() {
+        // Make a best-effort to ensure we make a clean (atomic) switch over from the old to
+        // the new command line implementation. If another thread is modifying the command line
+        // when this happens, all bets are off. (As per the native CommandLine).
+        sCommandLine.set(new NativeCommandLine());
+    }
+
+    public static String[] getJavaSwitchesOrNull() {
+        CommandLine commandLine = sCommandLine.get();
+        if (commandLine != null) {
+            assert !commandLine.isNativeImplementation();
+            return ((JavaCommandLine) commandLine).getCommandLineArguments();
+        }
+        return null;
+    }
+
+    private static void setInstance(CommandLine commandLine) {
+        CommandLine oldCommandLine = sCommandLine.getAndSet(commandLine);
+        if (oldCommandLine != null && oldCommandLine.isNativeImplementation()) {
+            nativeReset();
+        }
+    }
+
+    /**
+     * @param fileName the file to read in.
+     * @param sizeLimit cap on the file size.
+     * @return Array of chars read from the file, or null if the file cannot be read
+     *         or if its length exceeds |sizeLimit|.
+     */
+    private static char[] readUtf8FileFully(String fileName, int sizeLimit) {
+        Reader reader = null;
+        File f = new File(fileName);
+        long fileLength = f.length();
+
+        if (fileLength == 0) {
+            return null;
+        }
+
+        if (fileLength > sizeLimit) {
+            Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds limit "
+                    + sizeLimit);
+            return null;
+        }
+
+        try {
+            char[] buffer = new char[(int) fileLength];
+            reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+            int charsRead = reader.read(buffer);
+            // Debug check that we've exhausted the input stream (will fail e.g. if the
+            // file grew after we inspected its length).
+            assert !reader.ready();
+            return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
+        } catch (FileNotFoundException e) {
+            return null;
+        } catch (IOException e) {
+            return null;
+        } finally {
+            try {
+                if (reader != null) reader.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to close file reader.", e);
+            }
+        }
+    }
+
+    private CommandLine() {}
+
+    private static class JavaCommandLine extends CommandLine {
+        private HashMap<String, String> mSwitches = new HashMap<String, String>();
+        private ArrayList<String> mArgs = new ArrayList<String>();
+
+        // The arguments begin at index 1, since index 0 contains the executable name.
+        private int mArgsBegin = 1;
+
+        JavaCommandLine(String[] args) {
+            if (args == null || args.length == 0 || args[0] == null) {
+                mArgs.add("");
+            } else {
+                mArgs.add(args[0]);
+                appendSwitchesInternal(args, 1);
+            }
+            // Invariant: we always have the argv[0] program name element.
+            assert mArgs.size() > 0;
+        }
+
+        /**
+         * Returns the switches and arguments passed into the program, with switches and their
+         * values coming before all of the arguments.
+         */
+        private String[] getCommandLineArguments() {
+            return mArgs.toArray(new String[mArgs.size()]);
+        }
+
+        @Override
+        public boolean hasSwitch(String switchString) {
+            return mSwitches.containsKey(switchString);
+        }
+
+        @Override
+        public String getSwitchValue(String switchString) {
+            // This is slightly round about, but needed for consistency with the NativeCommandLine
+            // version which does not distinguish empty values from key not present.
+            String value = mSwitches.get(switchString);
+            return value == null || value.isEmpty() ? null : value;
+        }
+
+        @Override
+        public void appendSwitch(String switchString) {
+            appendSwitchWithValue(switchString, null);
+        }
+
+        /**
+         * Appends a switch to the current list.
+         * @param switchString the switch to add.  It should NOT start with '--' !
+         * @param value the value for this switch.
+         */
+        @Override
+        public void appendSwitchWithValue(String switchString, String value) {
+            mSwitches.put(switchString, value == null ? "" : value);
+
+            // Append the switch and update the switches/arguments divider mArgsBegin.
+            String combinedSwitchString = SWITCH_PREFIX + switchString;
+            if (value != null && !value.isEmpty()) {
+                combinedSwitchString += SWITCH_VALUE_SEPARATOR + value;
+            }
+
+            mArgs.add(mArgsBegin++, combinedSwitchString);
+        }
+
+        @Override
+        public void appendSwitchesAndArguments(String[] array) {
+            appendSwitchesInternal(array, 0);
+        }
+
+        // Add the specified arguments, but skipping the first |skipCount| elements.
+        private void appendSwitchesInternal(String[] array, int skipCount) {
+            boolean parseSwitches = true;
+            for (String arg : array) {
+                if (skipCount > 0) {
+                    --skipCount;
+                    continue;
+                }
+
+                if (arg.equals(SWITCH_TERMINATOR)) {
+                    parseSwitches = false;
+                }
+
+                if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) {
+                    String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2);
+                    String value = parts.length > 1 ? parts[1] : null;
+                    appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.length()), value);
+                } else {
+                    mArgs.add(arg);
+                }
+            }
+        }
+    }
+
+    private static class NativeCommandLine extends CommandLine {
+        @Override
+        public boolean hasSwitch(String switchString) {
+            return nativeHasSwitch(switchString);
+        }
+
+        @Override
+        public String getSwitchValue(String switchString) {
+            return nativeGetSwitchValue(switchString);
+        }
+
+        @Override
+        public void appendSwitch(String switchString) {
+            nativeAppendSwitch(switchString);
+        }
+
+        @Override
+        public void appendSwitchWithValue(String switchString, String value) {
+            nativeAppendSwitchWithValue(switchString, value);
+        }
+
+        @Override
+        public void appendSwitchesAndArguments(String[] array) {
+            nativeAppendSwitchesAndArguments(array);
+        }
+
+        @Override
+        public boolean isNativeImplementation() {
+            return true;
+        }
+    }
+
+    private static native void nativeReset();
+    private static native boolean nativeHasSwitch(String switchString);
+    private static native String nativeGetSwitchValue(String switchString);
+    private static native void nativeAppendSwitch(String switchString);
+    private static native void nativeAppendSwitchWithValue(String switchString, String value);
+    private static native void nativeAppendSwitchesAndArguments(String[] array);
+}
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
new file mode 100644
index 0000000..ef527e1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java
@@ -0,0 +1,150 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * This class provides methods to access content URI schemes.
+ */
+public abstract class ContentUriUtils {
+    private static final String TAG = "ContentUriUtils";
+    private static FileProviderUtil sFileProviderUtil;
+
+    /**
+     * Provides functionality to translate a file into a content URI for use
+     * with a content provider.
+     */
+    public interface FileProviderUtil {
+        /**
+         * Generate a content URI from the given file.
+         * @param context Application context.
+         * @param file The file to be translated.
+         */
+        Uri getContentUriFromFile(Context context, File file);
+    }
+
+    // Prevent instantiation.
+    private ContentUriUtils() {}
+
+    public static void setFileProviderUtil(FileProviderUtil util) {
+        sFileProviderUtil = util;
+    }
+
+    public static Uri getContentUriFromFile(Context context, File file) {
+        ThreadUtils.assertOnUiThread();
+        if (sFileProviderUtil != null) {
+            return sFileProviderUtil.getContentUriFromFile(context, file);
+        }
+        return null;
+    }
+
+    /**
+     * Opens the content URI for reading, and returns the file descriptor to
+     * the caller. The caller is responsible for closing the file desciptor.
+     *
+     * @param context {@link Context} in interest
+     * @param uriString the content URI to open
+     * @return file desciptor upon sucess, or -1 otherwise.
+     */
+    @CalledByNative
+    public static int openContentUriForRead(Context context, String uriString) {
+        ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
+        if (pfd != null) {
+            return pfd.detachFd();
+        }
+        return -1;
+    }
+
+    /**
+     * Check whether a content URI exists.
+     *
+     * @param context {@link Context} in interest.
+     * @param uriString the content URI to query.
+     * @return true if the URI exists, or false otherwise.
+     */
+    @CalledByNative
+    public static boolean contentUriExists(Context context, String uriString) {
+        return getParcelFileDescriptor(context, uriString) != null;
+    }
+
+    /**
+     * Retrieve the MIME type for the content URI.
+     *
+     * @param context {@link Context} in interest.
+     * @param uriString the content URI to look up.
+     * @return MIME type or null if the input params are empty or invalid.
+     */
+    @CalledByNative
+    public static String getMimeType(Context context, String uriString) {
+        ContentResolver resolver = context.getContentResolver();
+        if (resolver == null) return null;
+        Uri uri = Uri.parse(uriString);
+        return resolver.getType(uri);
+    }
+
+    /**
+     * Helper method to open a content URI and returns the ParcelFileDescriptor.
+     *
+     * @param context {@link Context} in interest.
+     * @param uriString the content URI to open.
+     * @return ParcelFileDescriptor of the content URI, or NULL if the file does not exist.
+     */
+    private static ParcelFileDescriptor getParcelFileDescriptor(Context context, String uriString) {
+        ContentResolver resolver = context.getContentResolver();
+        Uri uri = Uri.parse(uriString);
+
+        ParcelFileDescriptor pfd = null;
+        try {
+            pfd = resolver.openFileDescriptor(uri, "r");
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "Cannot find content uri: " + uriString, e);
+        } catch (SecurityException e) {
+            Log.w(TAG, "Cannot open content uri: " + uriString, e);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "Unknown content uri: " + uriString, e);
+        }
+        return pfd;
+    }
+
+    /**
+     * Method to resolve the display name of a content URI.
+     *
+     * @param uri the content URI to be resolved.
+     * @param contentResolver the content resolver to query.
+     * @param columnField the column field to query.
+     * @return the display name of the @code uri if present in the database
+     *  or an empty string otherwise.
+     */
+    public static String getDisplayName(
+            Uri uri, ContentResolver contentResolver, String columnField) {
+        if (contentResolver == null || uri == null) return "";
+        Cursor cursor = null;
+        try {
+            cursor = contentResolver.query(uri, null, null, null, null);
+
+            if (cursor != null && cursor.getCount() >= 1) {
+                cursor.moveToFirst();
+                int index = cursor.getColumnIndex(columnField);
+                if (index > -1) return cursor.getString(index);
+            }
+        } catch (NullPointerException e) {
+            // Some android models don't handle the provider call correctly.
+            // see crbug.com/345393
+            return "";
+        } finally {
+            if (cursor != null) cursor.close();
+        }
+        return "";
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/CpuFeatures.java b/base/android/java/src/org/chromium/base/CpuFeatures.java
new file mode 100644
index 0000000..0e8a7ab
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CpuFeatures.java
@@ -0,0 +1,40 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+// The only purpose of this class is to allow sending CPU properties
+// from the browser process to sandboxed renderer processes. This is
+// needed because sandboxed processes cannot, on ARM, query the kernel
+// about the CPU's properties by parsing /proc, so this operation must
+// be performed in the browser process, and the result passed to
+// renderer ones.
+//
+// For more context, see http://crbug.com/164154
+//
+// Technically, this is a wrapper around the native NDK cpufeatures
+// library. The exact CPU features bits are never used in Java so
+// there is no point in duplicating their definitions here.
+//
+@JNINamespace("base::android")
+public abstract class CpuFeatures {
+    /**
+     * Return the number of CPU Cores on the device.
+     */
+    public static int getCount() {
+        return nativeGetCoreCount();
+    }
+
+    /**
+     * Return the CPU feature mask.
+     * This is a 64-bit integer that corresponds to the CPU's features.
+     * The value comes directly from android_getCpuFeatures().
+     */
+    public static long getMask() {
+        return nativeGetCpuFeatures();
+    }
+
+    private static native int nativeGetCoreCount();
+    private static native long nativeGetCpuFeatures();
+}
diff --git a/base/android/java/src/org/chromium/base/EventLog.java b/base/android/java/src/org/chromium/base/EventLog.java
new file mode 100644
index 0000000..894de15
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/EventLog.java
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * A simple interface to Android's EventLog to be used by native code.
+ */
+@JNINamespace("base::android")
+public class EventLog {
+
+    @CalledByNative
+    public static void writeEvent(int tag, int value) {
+        android.util.EventLog.writeEvent(tag, value);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/FieldTrialList.java b/base/android/java/src/org/chromium/base/FieldTrialList.java
new file mode 100644
index 0000000..5fc9a1f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/FieldTrialList.java
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * Helper to get field trial information.
+ */
+public class FieldTrialList {
+
+    private FieldTrialList() {}
+
+    /**
+     * @param trialName The name of the trial to get the group for.
+     * @return The group name chosen for the named trial, or the empty string if the trial does
+     *         not exist.
+     */
+    public static String findFullName(String trialName) {
+        return nativeFindFullName(trialName);
+    }
+
+    /**
+     * @param trialName The name of the trial to get the group for.
+     * @return Whether the trial exists or not.
+     */
+    public static boolean trialExists(String trialName) {
+        return nativeTrialExists(trialName);
+    }
+
+    private static native String nativeFindFullName(String trialName);
+    private static native boolean nativeTrialExists(String trialName);
+}
diff --git a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
new file mode 100644
index 0000000..3921cea
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides an interface to the native class for writing
+ * important data files without risking data loss.
+ */
+@JNINamespace("base::android")
+public class ImportantFileWriterAndroid {
+
+    /**
+     * Write a binary file atomically.
+     *
+     * This either writes all the data or leaves the file unchanged.
+     *
+     * @param fileName The complete path of the file to be written
+     * @param data The data to be written to the file
+     * @return true if the data was written to the file, false if not.
+     */
+    public static boolean writeFileAtomically(String fileName, byte[] data) {
+        return nativeWriteFileAtomically(fileName, data);
+    }
+
+    private static native boolean nativeWriteFileAtomically(
+            String fileName, byte[] data);
+}
diff --git a/base/android/java/src/org/chromium/base/JNIAdditionalImport.java b/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
new file mode 100644
index 0000000..499d158
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JNIAdditionalImport is used by the JNI generator to qualify inner types used on JNI methods. Must
+ * be used when an inner class is used from a class within the same package. Example:
+ *
+ * <pre>
+ * @JNIAdditionImport(Foo.class)
+ * public class Bar {
+ *     @CalledByNative static void doSomethingWithInner(Foo.Inner inner) {
+ *     ...
+ *     }
+ * }
+ * <pre>
+ * <p>
+ * Notes:
+ * 1) Foo must be in the same package as Bar
+ * 2) For classes in different packages, they should be imported as:
+ *    import other.package.Foo;
+ *    and this annotation should not be used.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface JNIAdditionalImport {
+    Class<?>[] value();
+}
diff --git a/base/android/java/src/org/chromium/base/JNINamespace.java b/base/android/java/src/org/chromium/base/JNINamespace.java
new file mode 100644
index 0000000..5ad7a42
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNINamespace.java
@@ -0,0 +1,20 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @JNINamespace is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code using the specified namespace.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JNINamespace {
+    public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/JNIUtils.java b/base/android/java/src/org/chromium/base/JNIUtils.java
new file mode 100644
index 0000000..6f6cd54
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNIUtils.java
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides JNI-related methods to the native library.
+ */
+public class JNIUtils {
+    /**
+     * This returns a ClassLoader that is capable of loading Chromium Java code. Such a ClassLoader
+     * is needed for the few cases where the JNI mechanism is unable to automatically determine the
+     * appropriate ClassLoader instance.
+     */
+    @CalledByNative
+    public static Object getClassLoader() {
+        return JNIUtils.class.getClassLoader();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/JavaHandlerThread.java b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
new file mode 100644
index 0000000..3153a9b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
@@ -0,0 +1,56 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * This class is an internal detail of the native counterpart.
+ * It is instantiated and owned by the native object.
+ */
+@JNINamespace("base::android")
+class JavaHandlerThread {
+    final HandlerThread mThread;
+
+    private JavaHandlerThread(String name) {
+        mThread = new HandlerThread(name);
+    }
+
+    @CalledByNative
+    private static JavaHandlerThread create(String name) {
+        return new JavaHandlerThread(name);
+    }
+
+    @CalledByNative
+    private void start(final long nativeThread, final long nativeEvent) {
+        mThread.start();
+        new Handler(mThread.getLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                nativeInitializeThread(nativeThread, nativeEvent);
+            }
+        });
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+    @CalledByNative
+    private void stop(final long nativeThread, final long nativeEvent) {
+        final boolean quitSafely = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
+        new Handler(mThread.getLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                nativeStopThread(nativeThread, nativeEvent);
+                if (!quitSafely) mThread.quit();
+            }
+        });
+        if (quitSafely) mThread.quitSafely();
+    }
+
+    private native void nativeInitializeThread(long nativeJavaHandlerThread, long nativeEvent);
+    private native void nativeStopThread(long nativeJavaHandlerThread, long nativeEvent);
+}
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
new file mode 100644
index 0000000..82b2c8f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.Locale;
+
+/**
+ * This class provides the locale related methods.
+ */
+public class LocaleUtils {
+    /**
+     * Guards this class from being instantiated.
+     */
+    private LocaleUtils() {
+    }
+
+    /**
+     * @return the default locale, translating Android deprecated
+     * language codes into the modern ones used by Chromium.
+     */
+    @CalledByNative
+    public static String getDefaultLocale() {
+        Locale locale = Locale.getDefault();
+        String language = locale.getLanguage();
+        String country = locale.getCountry();
+
+        // Android uses deprecated lanuages codes for Hebrew and Indonesian but Chromium uses the
+        // updated codes. Also, Android uses "tl" while Chromium uses "fil" for Tagalog/Filipino.
+        // So apply a mapping.
+        // See http://developer.android.com/reference/java/util/Locale.html
+        if ("iw".equals(language)) {
+            language = "he";
+        } else if ("in".equals(language)) {
+            language = "id";
+        } else if ("tl".equals(language)) {
+            language = "fil";
+        }
+        return country.isEmpty() ? language : language + "-" + country;
+    }
+
+    /**
+     * Get the default country code set during install.
+     * @return country code.
+     */
+    @CalledByNative
+    private static String getDefaultCountryCode() {
+        CommandLine commandLine = CommandLine.getInstance();
+        return commandLine.hasSwitch(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL)
+                ? commandLine.getSwitchValue(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL)
+                : Locale.getDefault().getCountry();
+    }
+
+}
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
new file mode 100644
index 0000000..4c79a4d
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -0,0 +1,383 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.text.TextUtils;
+
+import org.chromium.base.annotations.NoSideEffects;
+
+import java.util.Locale;
+
+/**
+ * Utility class for Logging.
+ *
+ * <p>
+ * Defines logging access points for each feature. They format and forward the logs to
+ * {@link android.util.Log}, allowing to standardize the output, to make it easy to identify
+ * the origin of logs, and enable or disable logging in different parts of the code.
+ * </p>
+ * <p>
+ * Please make use of the formatting capability of the logging methods rather than doing
+ * concatenations in the calling code. In the release builds of Chrome, debug and verbose log
+ * calls will be stripped out of the binary. Concatenations and method calls however will still
+ * remain and be executed. If they can't be avoided, try to generate the logs in a method annotated
+ * with {@link NoSideEffects}. Another possibility is to use
+ * {@link android.util.Log#isLoggable(String, int)} to guard those calls.
+ * </p>
+ *
+ * Usage:
+ * <pre>
+ * private static final String TAG = Log.makeTag("Group");
+ *
+ * private void myMethod(String awesome) {
+ *   Log.i(TAG, "My %s message.", awesome);
+ *   Log.d(TAG, "My debug message");
+ * }
+ * </pre>
+ *
+ * Logcat output:
+ * <pre>
+ * I/cr.Group (999): My awesome message
+ * D/cr.Group (999): [MyClass.java:42] My debug message
+ * </pre>
+ *
+ * Set the log level for a given group:
+ * <pre>
+ * $ adb shell setprop log.tag.chromium.Group VERBOSE
+ * </pre>
+ */
+public class Log {
+    private static final String BASE_TAG = "cr";
+
+    /** Convenience property, same as {@link android.util.Log#ASSERT}. */
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    /** Convenience property, same as {@link android.util.Log#DEBUG}. */
+    public static final int DEBUG = android.util.Log.DEBUG;
+
+    /** Convenience property, same as {@link android.util.Log#ERROR}. */
+    public static final int ERROR = android.util.Log.ERROR;
+
+    /** Convenience property, same as {@link android.util.Log#INFO}. */
+    public static final int INFO = android.util.Log.INFO;
+
+    /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+
+    /** Convenience property, same as {@link android.util.Log#WARN}. */
+    public static final int WARN = android.util.Log.WARN;
+
+    private Log() {
+        // Static only access
+    }
+
+    /** Returns a formatted log message, using the supplied format and arguments.*/
+    private static String formatLog(String messageTemplate, Object... params) {
+        if (params != null && params.length != 0) {
+            messageTemplate = String.format(Locale.US, messageTemplate, params);
+        }
+
+        return messageTemplate;
+    }
+
+    /**
+     * Returns a formatted log message, using the supplied format and arguments.
+     * The message will be prepended with the filename and line number of the call.
+     */
+    private static String formatLogWithStack(String messageTemplate, Object... params) {
+        return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, params);
+    }
+
+    /**
+     * Returns a full tag for the provided group tag. Full tags longer than 23 characters
+     * will cause a runtime exception.
+     *
+     * @param groupTag {@code null} and empty string are allowed.
+     *
+     * @see android.util.Log#isLoggable(String, int)
+     * @throws IllegalArgumentException if the tag is too long.
+     */
+    public static String makeTag(String groupTag) {
+        if (TextUtils.isEmpty(groupTag)) return BASE_TAG;
+        String tag = BASE_TAG + "." + groupTag;
+        if (tag.length() > 23) {
+            throw new IllegalArgumentException(
+                    "The full tag (" + tag + ") is longer than 23 characters.");
+        }
+        return tag;
+    }
+
+    /** Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}. */
+    public static boolean isLoggable(String tag, int level) {
+        return android.util.Log.isLoggable(tag, level);
+    }
+
+    /**
+     * Sends a {@link android.util.Log#VERBOSE} log message.
+     *
+     * For optimization purposes, only the fixed parameters versions are visible. If you need more
+     * than 7 parameters, consider building your log message using a function annotated with
+     * {@link NoSideEffects}.
+     *
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
+     *
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    private static void verbose(String tag, String messageTemplate, Object... args) {
+        if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
+            String message = formatLogWithStack(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.v(tag, message, tr);
+            } else {
+                android.util.Log.v(tag, message);
+            }
+        }
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
+    public static void v(String tag, String message) {
+        verbose(tag, message);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
+    public static void v(String tag, String messageTemplate, Object arg1) {
+        verbose(tag, messageTemplate, arg1);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2) {
+        verbose(tag, messageTemplate, arg1, arg2);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */
+    public static void v(
+            String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6, Object arg7) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+
+    /**
+     * Sends a {@link android.util.Log#DEBUG} log message.
+     *
+     * For optimization purposes, only the fixed parameters versions are visible. If you need more
+     * than 7 parameters, consider building your log message using a function annotated with
+     * {@link NoSideEffects}.
+     *
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
+     *
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    private static void debug(String tag, String messageTemplate, Object... args) {
+        if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
+            String message = formatLogWithStack(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.d(tag, message, tr);
+            } else {
+                android.util.Log.d(tag, message);
+            }
+        }
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
+    public static void d(String tag, String message) {
+        debug(tag, message);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
+    public static void d(String tag, String messageTemplate, Object arg1) {
+        debug(tag, messageTemplate, arg1);
+    }
+    /** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2) {
+        debug(tag, messageTemplate, arg1, arg2);
+    }
+    /** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */
+    public static void d(
+            String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+        debug(tag, messageTemplate, arg1, arg2, arg3);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6, Object arg7) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+
+    /**
+     * Sends an {@link android.util.Log#INFO} log message.
+     *
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    public static void i(String tag, String messageTemplate, Object... args) {
+        if (android.util.Log.isLoggable(tag, android.util.Log.INFO)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.i(tag, message, tr);
+            } else {
+                android.util.Log.i(tag, message);
+            }
+        }
+    }
+
+    /**
+     * Sends a {@link android.util.Log#WARN} log message.
+     *
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    public static void w(String tag, String messageTemplate, Object... args) {
+        if (android.util.Log.isLoggable(tag, android.util.Log.WARN)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.w(tag, message, tr);
+            } else {
+                android.util.Log.w(tag, message);
+            }
+        }
+    }
+
+    /**
+     * Sends an {@link android.util.Log#ERROR} log message.
+     *
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    public static void e(String tag, String messageTemplate, Object... args) {
+        if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.e(tag, message, tr);
+            } else {
+                android.util.Log.e(tag, message);
+            }
+        }
+    }
+
+    /**
+     * What a Terrible Failure: Used for conditions that should never happen, and logged at
+     * the {@link android.util.Log#ASSERT} level. Depending on the configuration, it might
+     * terminate the process.
+     *
+     * @see android.util.Log#wtf(String, String, Throwable)
+     *
+     * @param tag Used to identify the source of a log message. Should be created using
+     *            {@link #makeTag(String)}.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    public static void wtf(String tag, String messageTemplate, Object... args) {
+        if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.wtf(tag, message, tr);
+            } else {
+                android.util.Log.wtf(tag, message);
+            }
+        }
+    }
+
+    private static Throwable getThrowableToLog(Object[] args) {
+        if (args == null || args.length == 0) return null;
+
+        Object lastArg = args[args.length - 1];
+
+        if (!(lastArg instanceof Throwable)) return null;
+        return (Throwable) lastArg;
+    }
+
+    /** Returns a string form of the origin of the log call, to be used as secondary tag.*/
+    private static String getCallOrigin() {
+        StackTraceElement[] st = Thread.currentThread().getStackTrace();
+
+        // The call stack should look like:
+        //   n [a variable number of calls depending on the vm used]
+        //  +0 getCallOrigin()
+        //  +1 privateLogFunction: verbose or debug
+        //  +2 formatLogWithStack()
+        //  +3 logFunction: v or d
+        //  +4 caller
+
+        int callerStackIndex;
+        String logClassName = Log.class.getName();
+        for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) {
+            if (st[callerStackIndex].getClassName().equals(logClassName)) {
+                callerStackIndex += 4;
+                break;
+            }
+        }
+
+        return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
new file mode 100644
index 0000000..e7c2030
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
@@ -0,0 +1,114 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.content.ComponentCallbacks2;
+import android.content.Context;
+import android.content.res.Configuration;
+
+
+/**
+ * This is an internal implementation of the C++ counterpart.
+ * It registers a ComponentCallbacks2 with the system, and dispatches into
+ * native for levels that are considered actionable.
+ */
+public class MemoryPressureListener {
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onLowMemory
+     * thus simulating a low memory situations.
+     */
+    private static final String ACTION_LOW_MEMORY = "org.chromium.base.ACTION_LOW_MEMORY";
+
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
+     * thus simulating a low memory situations.
+     */
+    private static final String ACTION_TRIM_MEMORY = "org.chromium.base.ACTION_TRIM_MEMORY";
+
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
+     * with notification level TRIM_MEMORY_RUNNING_CRITICAL thus simulating a low memory situation
+     */
+    private static final String ACTION_TRIM_MEMORY_RUNNING_CRITICAL =
+            "org.chromium.base.ACTION_TRIM_MEMORY_RUNNING_CRITICAL";
+
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
+     * with notification level TRIM_MEMORY_MODERATE thus simulating a low memory situation
+     */
+    private static final String ACTION_TRIM_MEMORY_MODERATE =
+            "org.chromium.base.ACTION_TRIM_MEMORY_MODERATE";
+
+    @CalledByNative
+    private static void registerSystemCallback(Context context) {
+        context.registerComponentCallbacks(
+                new ComponentCallbacks2() {
+                    @Override
+                    public void onTrimMemory(int level) {
+                        maybeNotifyMemoryPresure(level);
+                    }
+
+                    @Override
+                    public void onLowMemory() {
+                        nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL);
+                    }
+
+                    @Override
+                    public void onConfigurationChanged(Configuration configuration) {
+                    }
+                });
+    }
+
+    /**
+     * Used by applications to simulate a memory pressure signal. By throwing certain intent
+     * actions.
+     */
+    public static boolean handleDebugIntent(Activity activity, String action) {
+        if (ACTION_LOW_MEMORY.equals(action)) {
+            simulateLowMemoryPressureSignal(activity);
+        } else if (ACTION_TRIM_MEMORY.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+        } else if (ACTION_TRIM_MEMORY_RUNNING_CRITICAL.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
+        } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity,
+                    ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL);
+        } else {
+            return false;
+        }
+
+        return true;
+    }
+
+    public static void maybeNotifyMemoryPresure(int level) {
+        if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+            nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL);
+        } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
+                || level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
+            // Don't notifiy on TRIM_MEMORY_UI_HIDDEN, since this class only
+            // dispatches actionable memory pressure signals to native.
+            nativeOnMemoryPressure(MemoryPressureLevel.MODERATE);
+        }
+    }
+
+    private static void simulateLowMemoryPressureSignal(Activity activity) {
+        // The Application and the Activity each have a list of callbacks they notify when this
+        // method is called.  Notifying these will simulate the event at the App/Activity level
+        // as well as trigger the listener bound from native in this process.
+        activity.getApplication().onLowMemory();
+        activity.onLowMemory();
+    }
+
+    private static void simulateTrimMemoryPressureSignal(Activity activity, int level) {
+        // The Application and the Activity each have a list of callbacks they notify when this
+        // method is called.  Notifying these will simulate the event at the App/Activity level
+        // as well as trigger the listener bound from native in this process.
+        activity.getApplication().onTrimMemory(level);
+        activity.onTrimMemory(level);
+    }
+
+    private static native void nativeOnMemoryPressure(int memoryPressureType);
+}
diff --git a/base/android/java/src/org/chromium/base/NativeCall.java b/base/android/java/src/org/chromium/base/NativeCall.java
new file mode 100644
index 0000000..352edf7
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/NativeCall.java
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeCall is used by the JNI generator to create the necessary JNI bindings
+ * so a native function can be bound to a Java inner class. The native class for
+ * which the JNI method will be generated is specified by the first parameter.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface NativeCall {
+    /*
+     * Value determines which native class the method should map to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
new file mode 100644
index 0000000..e55b18c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
@@ -0,0 +1,25 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeClassQualifiedName is used by the JNI generator to create the necessary JNI
+ * bindings to call into the specified native class name.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NativeClassQualifiedName {
+    /*
+     * Tells which native class the method is going to be bound to.
+     * The first parameter of the annotated method must be an int nativePtr pointing to
+     * an instance of this class.
+     */
+    public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/OWNERS b/base/android/java/src/org/chromium/base/OWNERS
new file mode 100644
index 0000000..d99aec1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/OWNERS
@@ -0,0 +1,2 @@
+per-file ApiCompatibilityUtils.java=aurimas@chromium.org
+per-file ApiCompatibilityUtils.java=newt@chromium.org
diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/ObserverList.java
new file mode 100644
index 0000000..7a2ab98
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ObserverList.java
@@ -0,0 +1,249 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * A container for a list of observers.
+ * <p/>
+ * This container can be modified during iteration without invalidating the iterator.
+ * So, it safely handles the case of an observer removing itself or other observers from the list
+ * while observers are being notified.
+ * <p/>
+ * The implementation (and the interface) is heavily influenced by the C++ ObserverList.
+ * Notable differences:
+ *   - The iterator implements NOTIFY_EXISTING_ONLY.
+ *   - The FOR_EACH_OBSERVER closure is left to the clients to implement in terms of iterator().
+ * <p/>
+ * This class is not threadsafe. Observers MUST be added, removed and will be notified on the same
+ * thread this is created.
+ *
+ * @param <E> The type of observers that this list should hold.
+ */
+@NotThreadSafe
+public class ObserverList<E> implements Iterable<E> {
+    /**
+     * Extended iterator interface that provides rewind functionality.
+     */
+    public interface RewindableIterator<E> extends Iterator<E> {
+        /**
+         * Rewind the iterator back to the beginning.
+         *
+         * If we need to iterate multiple times, we can avoid iterator object reallocation by using
+         * this method.
+         */
+        public void rewind();
+    }
+
+    public final List<E> mObservers = new ArrayList<E>();
+    private int mIterationDepth = 0;
+    private int mCount = 0;
+    private boolean mNeedsCompact = false;
+
+    public ObserverList() {}
+
+    /**
+     * Add an observer to the list.
+     * <p/>
+     * An observer should not be added to the same list more than once. If an iteration is already
+     * in progress, this observer will be not be visible during that iteration.
+     *
+     * @return true if the observer list changed as a result of the call.
+     */
+    public boolean addObserver(E obs) {
+        // Avoid adding null elements to the list as they may be removed on a compaction.
+        if (obs == null || mObservers.contains(obs)) {
+            return false;
+        }
+
+        // Structurally modifying the underlying list here. This means we
+        // cannot use the underlying list's iterator to iterate over the list.
+        boolean result = mObservers.add(obs);
+        assert result;
+
+        ++mCount;
+        return true;
+    }
+
+    /**
+     * Remove an observer from the list if it is in the list.
+     *
+     * @return true if an element was removed as a result of this call.
+     */
+    public boolean removeObserver(E obs) {
+        if (obs == null) {
+            return false;
+        }
+
+        int index = mObservers.indexOf(obs);
+        if (index == -1) {
+            return false;
+        }
+
+        if (mIterationDepth == 0) {
+            // No one is iterating over the list.
+            mObservers.remove(index);
+        } else {
+            mNeedsCompact = true;
+            mObservers.set(index, null);
+        }
+        --mCount;
+        assert mCount >= 0;
+
+        return true;
+    }
+
+    public boolean hasObserver(E obs) {
+        return mObservers.contains(obs);
+    }
+
+    public void clear() {
+        mCount = 0;
+
+        if (mIterationDepth == 0) {
+            mObservers.clear();
+            return;
+        }
+
+        int size = mObservers.size();
+        mNeedsCompact |= size != 0;
+        for (int i = 0; i < size; i++) {
+            mObservers.set(i, null);
+        }
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return new ObserverListIterator();
+    }
+
+    /**
+     * It's the same as {@link ObserverList#iterator()} but the return type is
+     * {@link RewindableIterator}. Use this iterator type if you need to use
+     * {@link RewindableIterator#rewind()}.
+     */
+    public RewindableIterator<E> rewindableIterator() {
+        return new ObserverListIterator();
+    }
+
+    /**
+     * Returns the number of observers currently registered in the ObserverList.
+     * This is equivalent to the number of non-empty spaces in |mObservers|.
+     */
+    public int size() {
+        return mCount;
+    }
+
+    /**
+     * Returns true if the ObserverList contains no observers.
+     */
+    public boolean isEmpty() {
+        return mCount == 0;
+    }
+
+    /**
+     * Compact the underlying list be removing null elements.
+     * <p/>
+     * Should only be called when mIterationDepth is zero.
+     */
+    private void compact() {
+        assert mIterationDepth == 0;
+        for (int i = mObservers.size() - 1; i >= 0; i--) {
+            if (mObservers.get(i) == null) {
+                mObservers.remove(i);
+            }
+        }
+    }
+
+    private void incrementIterationDepth() {
+        mIterationDepth++;
+    }
+
+    private void decrementIterationDepthAndCompactIfNeeded() {
+        mIterationDepth--;
+        assert mIterationDepth >= 0;
+        if (mIterationDepth > 0) return;
+        if (!mNeedsCompact) return;
+        mNeedsCompact = false;
+        compact();
+    }
+
+    /**
+     * Returns the size of the underlying storage of the ObserverList.
+     * It will take into account the empty spaces inside |mObservers|.
+     */
+    private int capacity() {
+        return mObservers.size();
+    }
+
+    private E getObserverAt(int index) {
+        return mObservers.get(index);
+    }
+
+    private class ObserverListIterator implements RewindableIterator<E> {
+        private int mListEndMarker;
+        private int mIndex = 0;
+        private boolean mIsExhausted = false;
+
+        private ObserverListIterator() {
+            ObserverList.this.incrementIterationDepth();
+            mListEndMarker = ObserverList.this.capacity();
+        }
+
+        @Override
+        public void rewind() {
+            compactListIfNeeded();
+            ObserverList.this.incrementIterationDepth();
+            mListEndMarker = ObserverList.this.capacity();
+            mIsExhausted = false;
+            mIndex = 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            int lookupIndex = mIndex;
+            while (lookupIndex < mListEndMarker
+                    && ObserverList.this.getObserverAt(lookupIndex) == null) {
+                lookupIndex++;
+            }
+            if (lookupIndex < mListEndMarker) return true;
+
+            // We have reached the end of the list, allow for compaction.
+            compactListIfNeeded();
+            return false;
+        }
+
+        @Override
+        public E next() {
+            // Advance if the current element is null.
+            while (mIndex < mListEndMarker && ObserverList.this.getObserverAt(mIndex) == null) {
+                mIndex++;
+            }
+            if (mIndex < mListEndMarker) return ObserverList.this.getObserverAt(mIndex++);
+
+            // We have reached the end of the list, allow for compaction.
+            compactListIfNeeded();
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        private void compactListIfNeeded() {
+            if (!mIsExhausted) {
+                mIsExhausted = true;
+                ObserverList.this.decrementIterationDepthAndCompactIfNeeded();
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PackageUtils.java b/base/android/java/src/org/chromium/base/PackageUtils.java
new file mode 100644
index 0000000..ab554cd
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PackageUtils.java
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+/**
+ * This class provides package checking related methods.
+ */
+public class PackageUtils {
+    /**
+     * Retrieves the version of the given package installed on the device.
+     *
+     * @param context Any context.
+     * @param packageName Name of the package to find.
+     * @return The package's version code if found, -1 otherwise.
+     */
+    public static int getPackageVersion(Context context, String packageName) {
+        int versionCode = -1;
+        PackageManager pm = context.getPackageManager();
+        try {
+            PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+            if (packageInfo != null) versionCode = packageInfo.versionCode;
+        } catch (PackageManager.NameNotFoundException e) {
+            // Do nothing, versionCode stays -1
+        }
+        return versionCode;
+    }
+
+    private PackageUtils() {
+        // Hide constructor
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PathService.java b/base/android/java/src/org/chromium/base/PathService.java
new file mode 100644
index 0000000..b22328c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PathService.java
@@ -0,0 +1,24 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides java side access to the native PathService.
+ */
+@JNINamespace("base::android")
+public abstract class PathService {
+
+    // Must match the value of DIR_MODULE in base/base_paths.h!
+    public static final int DIR_MODULE = 3;
+
+    // Prevent instantiation.
+    private PathService() {}
+
+    public static void override(int what, String path) {
+        nativeOverride(what, path);
+    }
+
+    private static native void nativeOverride(int what, String path);
+}
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
new file mode 100644
index 0000000..0b3ed20
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -0,0 +1,127 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.AsyncTask;
+import android.os.Environment;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * This class provides the path related methods for the native library.
+ */
+public abstract class PathUtils {
+
+    private static final int DATA_DIRECTORY = 0;
+    private static final int DATABASE_DIRECTORY = 1;
+    private static final int CACHE_DIRECTORY = 2;
+    private static final int NUM_DIRECTORIES = 3;
+    private static AsyncTask<String, Void, String[]> sDirPathFetchTask;
+
+    // Prevent instantiation.
+    private PathUtils() {}
+
+    /**
+     * Starts an asynchronous task to fetch the path of the directory where private data is to be
+     * stored by the application.
+     *
+     * @param suffix The private data directory suffix.
+     * @see Context#getDir(String, int)
+     */
+    public static void setPrivateDataDirectorySuffix(String suffix, Context context) {
+        final Context appContext = context.getApplicationContext();
+        sDirPathFetchTask = new AsyncTask<String, Void, String[]>() {
+            @Override
+            protected String[] doInBackground(String... dataDirectorySuffix) {
+                String[] paths = new String[NUM_DIRECTORIES];
+                paths[DATA_DIRECTORY] =
+                        appContext.getDir(dataDirectorySuffix[0], Context.MODE_PRIVATE).getPath();
+                paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
+                // TODO(wnwen): Find a way to avoid calling this function in renderer process.
+                if (appContext.getCacheDir() != null) {
+                    paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
+                }
+                return paths;
+            }
+        }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, suffix);
+    }
+
+    /**
+     * @param index The index of the cached directory path.
+     * @return The directory path requested, or null if not available.
+     */
+    private static String getDirectoryPath(int index) {
+        try {
+            return sDirPathFetchTask.get()[index];
+        } catch (InterruptedException e) {
+        } catch (ExecutionException e) {
+        }
+        return null;
+    }
+
+    /**
+     * @return the private directory that is used to store application data.
+     */
+    @CalledByNative
+    public static String getDataDirectory(Context appContext) {
+        assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
+        return getDirectoryPath(DATA_DIRECTORY);
+    }
+
+    /**
+     * @return the private directory that is used to store application database.
+     */
+    @CalledByNative
+    public static String getDatabaseDirectory(Context appContext) {
+        assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
+        return getDirectoryPath(DATABASE_DIRECTORY);
+    }
+
+    /**
+     * @return the cache directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public static String getCacheDirectory(Context appContext) {
+        assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
+        return getDirectoryPath(CACHE_DIRECTORY);
+    }
+
+    /**
+     * @return the public downloads directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getDownloadsDirectory(Context appContext) {
+        return Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_DOWNLOADS).getPath();
+    }
+
+    /**
+     * @return the path to native libraries.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getNativeLibraryDirectory(Context appContext) {
+        ApplicationInfo ai = appContext.getApplicationInfo();
+        if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
+                || (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            return ai.nativeLibraryDir;
+        }
+
+        return "/system/lib/";
+    }
+
+    /**
+     * @return the external storage directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public static String getExternalStorageDirectory() {
+        return Environment.getExternalStorageDirectory().getAbsolutePath();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PerfTraceEvent.java b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
new file mode 100644
index 0000000..c0e4b21
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
@@ -0,0 +1,379 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Debug;
+import android.os.Debug.MemoryInfo;
+import android.util.Log;
+
+import org.chromium.base.annotations.SuppressFBWarnings;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * PerfTraceEvent can be used like TraceEvent, but is intended for
+ * performance measurement.  By limiting the types of tracing we hope
+ * to minimize impact on measurement.
+ *
+ * All PerfTraceEvent events funnel into TraceEvent. When not doing
+ * performance measurements, they act the same.  However,
+ * PerfTraceEvents can be enabled even when TraceEvent is not.
+ *
+ * Unlike TraceEvent, PerfTraceEvent data is sent to the system log,
+ * not to a trace file.
+ *
+ * Performance events need to have very specific names so we find
+ * the right ones.  For example, we specify the name exactly in
+ * the @TracePerf annotation.  Thus, unlike TraceEvent, we do not
+ * support an implicit trace name based on the callstack.
+ */
+@SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD")
+public class PerfTraceEvent {
+    private static final int MAX_NAME_LENGTH = 40;
+    private static final String MEMORY_TRACE_NAME_SUFFIX = "_BZR_PSS";
+    private static File sOutputFile = null;
+
+    /** The event types understood by the perf trace scripts. */
+    private enum EventType {
+        START("S"),
+        FINISH("F"),
+        INSTANT("I");
+
+        // The string understood by the trace scripts.
+        private final String mTypeStr;
+
+        EventType(String typeStr) {
+            mTypeStr = typeStr;
+        }
+
+        @Override
+        public String toString() {
+            return mTypeStr;
+        }
+    }
+
+    private static boolean sEnabled = false;
+    private static boolean sTrackTiming = true;
+    private static boolean sTrackMemory = false;
+
+    // A list of performance trace event strings.
+    // Events are stored as a JSON dict much like TraceEvent.
+    // E.g. timestamp is in microseconds.
+    private static JSONArray sPerfTraceStrings;
+
+    // A filter for performance tracing.  Only events that match a
+    // string in the list are saved.  Presence of a filter does not
+    // necessarily mean perf tracing is enabled.
+    private static List<String> sFilter;
+
+    // Nanosecond start time of performance tracing.
+    private static long sBeginNanoTime;
+
+    /**
+     * Specifies what event names will be tracked.
+     *
+     * @param strings Event names we will record.
+     */
+    @VisibleForTesting
+    public static synchronized void setFilter(List<String> strings) {
+        sFilter = new LinkedList<String>(strings);
+    }
+
+    /**
+     * Enable or disable perf tracing.
+     * Disabling of perf tracing will dump trace data to the system log.
+     */
+    @VisibleForTesting
+    public static synchronized void setEnabled(boolean enabled) {
+        if (sEnabled == enabled) {
+            return;
+        }
+        if (enabled) {
+            sBeginNanoTime = System.nanoTime();
+            sPerfTraceStrings = new JSONArray();
+        } else {
+            dumpPerf();
+            sPerfTraceStrings = null;
+            sFilter = null;
+        }
+        sEnabled = enabled;
+    }
+
+    /**
+     * Enables memory tracking for all timing perf events tracked.
+     *
+     * <p>
+     * Only works when called in combination with {@link #setEnabled(boolean)}.
+     *
+     * <p>
+     * By enabling this feature, an additional perf event containing the memory usage will be
+     * logged whenever {@link #instant(String)}, {@link #begin(String)}, or {@link #end(String)}
+     * is called.
+     *
+     * @param enabled Whether to enable memory tracking for all perf events.
+     */
+    @VisibleForTesting
+    public static synchronized void setMemoryTrackingEnabled(boolean enabled) {
+        sTrackMemory = enabled;
+    }
+
+    /**
+     * Enables timing tracking for all perf events tracked.
+     *
+     * <p>
+     * Only works when called in combination with {@link #setEnabled(boolean)}.
+     *
+     * <p>
+     * If this feature is enabled, whenever {@link #instant(String)}, {@link #begin(String)},
+     * or {@link #end(String)} is called the time since start of tracking will be logged.
+     *
+     * @param enabled Whether to enable timing tracking for all perf events.
+     */
+    @VisibleForTesting
+    public static synchronized void setTimingTrackingEnabled(boolean enabled) {
+        sTrackTiming = enabled;
+    }
+
+    /**
+     * @return True if tracing is enabled, false otherwise.
+     * It is safe to call trace methods without checking if PerfTraceEvent
+     * is enabled.
+     */
+    @VisibleForTesting
+    public static synchronized boolean enabled() {
+        return sEnabled;
+    }
+
+    /**
+     * Record an "instant" perf trace event.  E.g. "screen update happened".
+     */
+    public static synchronized void instant(String name) {
+        // Instant doesn't really need/take an event id, but this should be okay.
+        final long eventId = name.hashCode();
+        TraceEvent.instant(name);
+        if (sEnabled && matchesFilter(name)) {
+            savePerfString(name, eventId, EventType.INSTANT, false);
+        }
+    }
+
+
+    /**
+     * Record an "begin" perf trace event.
+     * Begin trace events should have a matching end event.
+     */
+    @VisibleForTesting
+    public static synchronized void begin(String name) {
+        final long eventId = name.hashCode();
+        TraceEvent.startAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            // Done before calculating the starting perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            if (sTrackMemory) {
+                savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
+                        true);
+            }
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.START, false);
+            }
+        }
+    }
+
+    /**
+     * Record an "end" perf trace event, to match a begin event.  The
+     * time delta between begin and end is usually interesting to
+     * graph code.
+     */
+    @VisibleForTesting
+    public static synchronized void end(String name) {
+        final long eventId = name.hashCode();
+        TraceEvent.finishAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.FINISH, false);
+            }
+            // Done after calculating the ending perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            if (sTrackMemory) {
+                savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
+                        true);
+            }
+        }
+    }
+
+    /**
+     * Record an "begin" memory trace event.
+     * Begin trace events should have a matching end event.
+     */
+    @VisibleForTesting
+    public static synchronized void begin(String name, MemoryInfo memoryInfo) {
+        final long eventId = name.hashCode();
+        TraceEvent.startAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            // Done before calculating the starting perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
+            savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
+                    timestampUs, memoryInfo);
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.START, false);
+            }
+        }
+    }
+
+    /**
+     * Record an "end" memory trace event, to match a begin event.  The
+     * memory usage delta between begin and end is usually interesting to
+     * graph code.
+     */
+    @VisibleForTesting
+    public static synchronized void end(String name, MemoryInfo memoryInfo) {
+        final long eventId = name.hashCode();
+        TraceEvent.finishAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.FINISH, false);
+            }
+            // Done after calculating the instant perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
+            savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
+                    timestampUs, memoryInfo);
+        }
+    }
+
+    /**
+     * Determine if we are interested in this trace event.
+     * @return True if the name matches the allowed filter; else false.
+     */
+    private static boolean matchesFilter(String name) {
+        return sFilter != null ? sFilter.contains(name) : false;
+    }
+
+    /**
+     * Save a perf trace event as a JSON dict.  The format mirrors a TraceEvent dict.
+     *
+     * @param name The trace data
+     * @param id The id of the event
+     * @param type the type of trace event (I, S, F)
+     * @param includeMemory Whether to include current browser process memory usage in the trace.
+     */
+    private static void savePerfString(String name, long id, EventType type,
+            boolean includeMemory) {
+        long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
+        MemoryInfo memInfo = null;
+        if (includeMemory) {
+            memInfo = new MemoryInfo();
+            Debug.getMemoryInfo(memInfo);
+        }
+        savePerfString(name, id, type, timestampUs, memInfo);
+    }
+
+    /**
+     * Save a perf trace event as a JSON dict.  The format mirrors a TraceEvent dict.
+     *
+     * @param name The trace data
+     * @param id The id of the event
+     * @param type the type of trace event (I, S, F)
+     * @param timestampUs The time stamp at which this event was recorded
+     * @param memoryInfo Memory details to be included in this perf string, null if
+     *                   no memory details are to be included.
+     */
+    private static void savePerfString(String name, long id, EventType type, long timestampUs,
+            MemoryInfo memoryInfo) {
+        try {
+            JSONObject traceObj = new JSONObject();
+            traceObj.put("cat", "Java");
+            traceObj.put("ts", timestampUs);
+            traceObj.put("ph", type);
+            traceObj.put("name", name);
+            traceObj.put("id", id);
+            if (memoryInfo != null) {
+                int pss = memoryInfo.nativePss + memoryInfo.dalvikPss + memoryInfo.otherPss;
+                traceObj.put("mem", pss);
+            }
+            sPerfTraceStrings.put(traceObj);
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generating a trace name for tracking memory based on the timing name passed in.
+     *
+     * @param name The timing name to use as a base for the memory perf name.
+     * @return The memory perf name to use.
+     */
+    public static String makeMemoryTraceNameFromTimingName(String name) {
+        return makeSafeTraceName(name, MEMORY_TRACE_NAME_SUFFIX);
+    }
+
+    /**
+     * Builds a name to be used in the perf trace framework.  The framework has length requirements
+     * for names, so this ensures the generated name does not exceed the maximum (trimming the
+     * base name if necessary).
+     *
+     * @param baseName The base name to use when generating the name.
+     * @param suffix The required suffix to be appended to the name.
+     * @return A name that is safe for the perf trace framework.
+     */
+    public static String makeSafeTraceName(String baseName, String suffix) {
+        int suffixLength = suffix.length();
+
+        if (baseName.length() + suffixLength > MAX_NAME_LENGTH) {
+            baseName = baseName.substring(0, MAX_NAME_LENGTH - suffixLength);
+        }
+        return baseName + suffix;
+    }
+
+    /**
+     * Sets a file to dump the results to.  If {@code file} is {@code null}, it will be dumped
+     * to STDOUT, otherwise the JSON performance data will be appended to {@code file}.  This should
+     * be called before the performance run starts.  When {@link #setEnabled(boolean)} is called
+     * with {@code false}, the perf data will be dumped.
+     *
+     * @param file Which file to append the performance data to.  If {@code null}, the performance
+     *             data will be sent to STDOUT.
+     */
+    @VisibleForTesting
+    public static synchronized void setOutputFile(File file) {
+        sOutputFile = file;
+    }
+
+    /**
+     * Dump all performance data we have saved up to the log.
+     * Output as JSON for parsing convenience.
+     */
+    private static void dumpPerf() {
+        String json = sPerfTraceStrings.toString();
+
+        if (sOutputFile == null) {
+            System.out.println(json);
+        } else {
+            try {
+                PrintStream stream = new PrintStream(new FileOutputStream(sOutputFile, true));
+                try {
+                    stream.print(json);
+                } finally {
+                    try {
+                        stream.close();
+                    } catch (Exception ex) {
+                        Log.e("PerfTraceEvent", "Unable to close perf trace output file.");
+                    }
+                }
+            } catch (FileNotFoundException ex) {
+                Log.e("PerfTraceEvent", "Unable to dump perf trace data to output file.");
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PowerMonitor.java b/base/android/java/src/org/chromium/base/PowerMonitor.java
new file mode 100644
index 0000000..3d0ed48
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PowerMonitor.java
@@ -0,0 +1,98 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
+
+
+/**
+ * Integrates native PowerMonitor with the java side.
+ */
+@JNINamespace("base::android")
+public class PowerMonitor implements ApplicationStatus.ApplicationStateListener {
+    private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000;  // 1 minute.
+    private static class LazyHolder {
+        private static final PowerMonitor INSTANCE = new PowerMonitor();
+    }
+    private static PowerMonitor sInstance;
+
+    private boolean mIsBatteryPower;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main
+    // activity transitioned to the "paused" state. This event is not sent immediately because it
+    // would be too aggressive. An Android activity can be in the "paused" state quite often. This
+    // can happen when a dialog window shows up for instance.
+    private static final Runnable sSuspendTask = new Runnable() {
+        @Override
+        public void run() {
+            nativeOnMainActivitySuspended();
+        }
+    };
+
+    public static void createForTests(Context context) {
+        // Applications will create this once the JNI side has been fully wired up both sides. For
+        // tests, we just need native -> java, that is, we don't need to notify java -> native on
+        // creation.
+        sInstance = LazyHolder.INSTANCE;
+    }
+
+    /**
+     * Create a PowerMonitor instance if none exists.
+     * @param context The context to register broadcast receivers for.  The application context
+     *                will be used from this parameter.
+     */
+    public static void create(Context context) {
+        context = context.getApplicationContext();
+        if (sInstance == null) {
+            sInstance = LazyHolder.INSTANCE;
+            ApplicationStatus.registerApplicationStateListener(sInstance);
+            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+            Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
+            onBatteryChargingChanged(batteryStatusIntent);
+        }
+    }
+
+    private PowerMonitor() {
+    }
+
+    public static void onBatteryChargingChanged(Intent intent) {
+        if (sInstance == null) {
+            // We may be called by the framework intent-filter before being fully initialized. This
+            // is not a problem, since our constructor will check for the state later on.
+            return;
+        }
+        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+        // If we're not plugged, assume we're running on battery power.
+        sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB
+                && chargePlug != BatteryManager.BATTERY_PLUGGED_AC;
+        nativeOnBatteryChargingChanged();
+    }
+
+    @Override
+    public void onApplicationStateChange(int newState) {
+        if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) {
+            // Remove the callback from the message loop in case it hasn't been executed yet.
+            mHandler.removeCallbacks(sSuspendTask);
+            nativeOnMainActivityResumed();
+        } else if (newState == ApplicationState.HAS_PAUSED_ACTIVITIES) {
+            mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS);
+        }
+    }
+
+    @CalledByNative
+    private static boolean isBatteryPower() {
+        return sInstance.mIsBatteryPower;
+    }
+
+    private static native void nativeOnBatteryChargingChanged();
+    private static native void nativeOnMainActivitySuspended();
+    private static native void nativeOnMainActivityResumed();
+}
diff --git a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
new file mode 100644
index 0000000..904a740
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
@@ -0,0 +1,23 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+
+/**
+ * A BroadcastReceiver that listens to changes in power status and notifies
+ * PowerMonitor.
+ * It's instantiated by the framework via the application intent-filter
+ * declared in its manifest.
+ */
+public class PowerStatusReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        PowerMonitor.onBatteryChargingChanged(intent);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
new file mode 100644
index 0000000..2193826
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/README_logging.md
@@ -0,0 +1,159 @@
+## Logging ##
+
+Logging used to be done using Android's [android.util.Log]
+(http://developer.android.com/reference/android/util/Log.html).
+
+A wrapper on that is now available: org.chromium.base.Log. It is designed to write logs as
+belonging to logical groups going beyond single classes, and to make it easy to switch logging on
+or off for individual groups.
+
+Usage:
+
+    private static final String TAG = Log.makeTag("Tag");
+    ...
+    Log.i(TAG, "Some debug info: %s", data);
+
+Output:
+
+    D/cr.Tag: ( 999): [MyClass.java:42] Some debug info: data's toString output"
+
+Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for example. In most
+cases, the class name is not needed anymore. In Debug and Verbose logs, the file name and line
+number will be prepended to the log message. For higher priority logs, those are currently not
+added for performance concerns. It might be useful to make the log messages meaningful enough so
+that with the group tag, it's easy to pinpoint their origin.
+
+All log calls are guarded, which allows to enable or disable logging specific groups using ADB:
+
+    adb shell setprop log.tag.<YOUR_LOG_TAG> <LEVEL>
+
+Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`, and the
+log tag looks like `cr.Tag`. By default, the level for all tags is `INFO`.
+
+**Caveat:** Property keys are limited to 23 characters. If the tag is too long, `Log#isLoggable`
+throws a RuntimeException.
+
+### Logging Best Practices
+
+#### Rule #1: Never log PII (Personal Identification Information):
+
+This is a huge concern, because other applications can access the log and extract a lot of data
+from your own by doing so. Even if JellyBean restricted this, people are going to run your
+application on rooted devices and allow some apps to access it. Also anyone with USB access to the
+device can use ADB to get the full logcat and get the same data right now.
+
+If you really need to print something , print a series of Xs instead (e.g. "XXXXXX"), or print a
+truncated hash of the PII instead. Truncation is required to make it harder for an attacker to
+recover the full data through rainbow tables and similar methods.
+
+Similarly, avoid dumping API keys, cookies, etc...
+
+#### Rule #2: Do not write debug logs in production code:
+
+The kernel log buffer is global and of limited size. Any extra debug log you add to your activity
+or service makes it more difficult to diagnose problems on other parts of the system, because they
+tend to push the interesting bit out of the buffer too soon. This is a recurring problem on
+Android, so avoid participating into it.
+
+All verbose and debug log calls made using `org.chromium.base.Log` will be stripped out of
+production binaries using Proguard. So there will be no way to get those logs in a release build.
+For other levels, they can be disabled using system properties. Because log messages might not be
+written, the cost of creating them should also be avoided. This can be done using three
+complementary ways:
+
+-   Use string formatting instead of concatenations
+
+        // BAD
+        Log.d(TAG, "I " + preference + " writing logs.");
+
+        // BETTER
+        Log.d(TAG, "I %s writing logs.", preference);
+
+    If logging is disabled, the function's arguments will still have to be computed and provided
+    as input. The first call above will always lead to the creation of a `StringBuilder` and a few
+    concatenations, while the second just passes the arguments and won't need that.
+
+-   Guard expensive calls
+
+    Sometimes the values to log aren't readily available and need to be computed specially. This
+    should be avoided when logging is disabled.
+
+    Using `Log#isLoggable` will return whether logging for a specific tag is allowed or not. It is
+    the call used inside the log functions and using allows to know when running the expensive
+    functions is needed.
+
+        if (Log.isLoggable(TAG, Log.DEBUG) {
+          Log.d(TAG, "Something happened: %s", dumpDom(tab));
+        }
+
+    For more info, See the [android framework documentation]
+    (http://developer.android.com/tools/debugging/debugging-log.html).
+
+    Using a debug constant is a less flexible, but more perfomance oriented alternative.
+
+        static private final boolean DEBUG = false;  // set to 'true' to enable debug
+        ...
+        if (DEBUG) {
+          Log.i(TAG, createThatExpensiveLogMessage(activity))
+        }
+
+    Because the variable is a `static final` that can be evaluated at compile time, the Java
+    compiler will optimize out all guarded calls from the generated `.class` file. Changing it
+    however requires editing each of the files for which debug should be enabled and recompiling,
+    while the previous method can enable or disable debugging for a whole feature without changing
+    any source file.
+
+-   Annotate debug functions with the `@NoSideEffects` annotation.
+
+    That annotation tells Proguard to assume that a given function has no side effects, and is
+    called only for its returned value. If this value is unused, the call will be removed. If the
+    function is not called at all, it will also be removed. Since Proguard is already used to
+    strip debug and verbose calls out of release builds, this annotation allows it to have a
+    deeper action by removing also function calls used to generate the log call's arguments.
+  
+        /* If that function is only used in Log.d calls, proguard should completely remove it from
+         * the release builds. */
+        @NoSideEffects
+        private static String getSomeDebugLogString(Thing[] things) {
+          /* Still needs to be guarded to avoid impacting debug builds, or in case it's used for
+           * some other log levels. But at least it is done only once, inside the function. */
+          if (!Log.isLoggable(TAG, Log.DEBUG)) return null;
+
+          StringBuilder sb = new StringBuilder("Reporting " + thing.length + " things:");
+          for (Thing thing : things) {
+            sb.append('\n').append(thing.id).append(' ').append(report.foo);
+          }
+          return sb.toString();
+        }
+
+        public void bar() {
+          ...
+          Log.d(TAG, getSomeDebugLogString(things)); /* In debug builds, the function does nothing
+                                                      * is debug is disabled, and the entire line 
+                                                      * is removed in release builds. */
+        }
+
+    Again, this is useful only if the input to that function are variables already available in
+    the scope. The idea is to move computations, concatenations, etc. to a place where that can be
+    removed when not needed, without invading the main function's logic.
+
+#### Rule #3: Favor small log messages
+
+This is still related to the global fixed-sized kernel buffer used to keep all logs. Try to make
+your log information as terse as possible. This reduces the risk of pushing interesting log data
+out of the buffer when something really nasty happens. It's really better to have a single-line
+log message, than several ones. I.e. don't use:
+
+    Log.GROUP.d(TAG, "field1 = %s", value1);
+    Log.GROUP.d(TAG, "field2 = %s", value2);
+    Log.GROUP.d(TAG, "field3 = %s", value3);
+
+Instead, write this as:
+
+    Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
+
+That doesn't seem to be much different if you count overall character counts, but each independent
+log entry also implies a small, but non-trivial header, in the kernel log buffer.
+And since every byte count, you can also try something even shorter, as in:
+
+    Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
new file mode 100644
index 0000000..d44f2fc
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -0,0 +1,484 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Trace;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+
+/**
+ * Handles extracting the necessary resources bundled in an APK and moving them to a location on
+ * the file system accessible from the native code.
+ */
+public class ResourceExtractor {
+
+    private static final String LOGTAG = "ResourceExtractor";
+    private static final String LAST_LANGUAGE = "Last language";
+    private static final String PAK_FILENAMES_LEGACY_NOREUSE = "Pak filenames";
+    private static final String ICU_DATA_FILENAME = "icudtl.dat";
+    private static final String V8_NATIVES_DATA_FILENAME = "natives_blob.bin";
+    private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
+
+    private static String[] sMandatoryPaks = null;
+
+    // By default, we attempt to extract a pak file for the users
+    // current device locale. Use setExtractImplicitLocale() to
+    // change this behavior.
+    private static boolean sExtractImplicitLocalePak = true;
+
+    private static boolean isAppDataFile(String file) {
+        return ICU_DATA_FILENAME.equals(file)
+                || V8_NATIVES_DATA_FILENAME.equals(file)
+                || V8_SNAPSHOT_DATA_FILENAME.equals(file);
+    }
+
+    private class ExtractTask extends AsyncTask<Void, Void, Void> {
+        private static final int BUFFER_SIZE = 16 * 1024;
+
+        private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
+
+        public ExtractTask() {
+        }
+
+        private void doInBackgroundImpl() {
+            final File outputDir = getOutputDir();
+            final File appDataDir = getAppDataDir();
+            if (!outputDir.exists() && !outputDir.mkdirs()) {
+                Log.e(LOGTAG, "Unable to create pak resources directory!");
+                return;
+            }
+
+            String timestampFile = null;
+            beginTraceSection("checkPakTimeStamp");
+            try {
+                timestampFile = checkPakTimestamp(outputDir);
+            } finally {
+                endTraceSection();
+            }
+            if (timestampFile != null) {
+                deleteFiles();
+            }
+
+            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+            String currentLocale = LocaleUtils.getDefaultLocale();
+            String currentLanguage = currentLocale.split("-", 2)[0];
+            // If everything we need is already there (and the locale hasn't
+            // changed), quick exit.
+            if (prefs.getString(LAST_LANGUAGE, "").equals(currentLanguage)) {
+                boolean filesPresent = true;
+                for (String file : sMandatoryPaks) {
+                    File directory = isAppDataFile(file) ? appDataDir : outputDir;
+                    if (!new File(directory, file).exists()) {
+                        filesPresent = false;
+                        break;
+                    }
+                }
+                if (filesPresent) return;
+            } else {
+                prefs.edit().putString(LAST_LANGUAGE, currentLanguage).apply();
+            }
+
+            StringBuilder p = new StringBuilder();
+            for (String mandatoryPak : sMandatoryPaks) {
+                if (p.length() > 0) p.append('|');
+                p.append("\\Q" + mandatoryPak + "\\E");
+            }
+
+            if (sExtractImplicitLocalePak) {
+                if (p.length() > 0) p.append('|');
+                // As well as the minimum required set of .paks above, we'll
+                // also add all .paks that we have for the user's currently
+                // selected language.
+                p.append(currentLanguage);
+                p.append("(-\\w+)?\\.pak");
+            }
+
+            Pattern paksToInstall = Pattern.compile(p.toString());
+
+            AssetManager manager = mContext.getResources().getAssets();
+            beginTraceSection("WalkAssets");
+            try {
+                // Loop through every asset file that we have in the APK, and look for the
+                // ones that we need to extract by trying to match the Patterns that we
+                // created above.
+                byte[] buffer = null;
+                String[] files = manager.list("");
+                for (String file : files) {
+                    if (!paksToInstall.matcher(file).matches()) {
+                        continue;
+                    }
+                    File output = new File(isAppDataFile(file) ? appDataDir : outputDir, file);
+                    if (output.exists()) {
+                        continue;
+                    }
+
+                    InputStream is = null;
+                    OutputStream os = null;
+                    beginTraceSection("ExtractResource");
+                    try {
+                        is = manager.open(file);
+                        os = new FileOutputStream(output);
+                        Log.i(LOGTAG, "Extracting resource " + file);
+                        if (buffer == null) {
+                            buffer = new byte[BUFFER_SIZE];
+                        }
+
+                        int count = 0;
+                        while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
+                            os.write(buffer, 0, count);
+                        }
+                        os.flush();
+
+                        // Ensure something reasonable was written.
+                        if (output.length() == 0) {
+                            throw new IOException(file + " extracted with 0 length!");
+                        }
+
+                        if (isAppDataFile(file)) {
+                            // icu and V8 data need to be accessed by a renderer
+                            // process.
+                            output.setReadable(true, false);
+                        }
+                    } finally {
+                        try {
+                            if (is != null) {
+                                is.close();
+                            }
+                        } finally {
+                            if (os != null) {
+                                os.close();
+                            }
+                            endTraceSection(); // ExtractResource
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                // TODO(benm): See crbug/152413.
+                // Try to recover here, can we try again after deleting files instead of
+                // returning null? It might be useful to gather UMA here too to track if
+                // this happens with regularity.
+                Log.w(LOGTAG, "Exception unpacking required pak resources: " + e.getMessage());
+                deleteFiles();
+                return;
+            } finally {
+                endTraceSection(); // WalkAssets
+            }
+
+            // Finished, write out a timestamp file if we need to.
+            if (timestampFile != null) {
+                try {
+                    new File(outputDir, timestampFile).createNewFile();
+                } catch (IOException e) {
+                    // Worst case we don't write a timestamp, so we'll re-extract the resource
+                    // paks next start up.
+                    Log.w(LOGTAG, "Failed to write resource pak timestamp!");
+                }
+            }
+        }
+
+        @Override
+        protected Void doInBackground(Void... unused) {
+            // TODO(lizeb): Use chrome tracing here (and above in
+            // doInBackgroundImpl) when it will be possible. This is currently
+            // not doable since the native library is not loaded yet, and the
+            // TraceEvent calls are dropped before this point.
+            beginTraceSection("ResourceExtractor.ExtractTask.doInBackground");
+            try {
+                doInBackgroundImpl();
+            } finally {
+                endTraceSection();
+            }
+            return null;
+        }
+
+        private void onPostExecuteImpl() {
+            for (int i = 0; i < mCompletionCallbacks.size(); i++) {
+                mCompletionCallbacks.get(i).run();
+            }
+            mCompletionCallbacks.clear();
+        }
+
+        @Override
+        protected void onPostExecute(Void result) {
+            beginTraceSection("ResourceExtractor.ExtractTask.onPostExecute");
+            try {
+                onPostExecuteImpl();
+            } finally {
+                endTraceSection();
+            }
+        }
+
+        // Looks for a timestamp file on disk that indicates the version of the APK that
+        // the resource paks were extracted from. Returns null if a timestamp was found
+        // and it indicates that the resources match the current APK. Otherwise returns
+        // a String that represents the filename of a timestamp to create.
+        // Note that we do this to avoid adding a BroadcastReceiver on
+        // android.content.Intent#ACTION_PACKAGE_CHANGED as that causes process churn
+        // on (re)installation of *all* APK files.
+        private String checkPakTimestamp(File outputDir) {
+            final String timestampPrefix = "pak_timestamp-";
+            PackageManager pm = mContext.getPackageManager();
+            PackageInfo pi = null;
+
+            try {
+                pi = pm.getPackageInfo(mContext.getPackageName(), 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                return timestampPrefix;
+            }
+
+            if (pi == null) {
+                return timestampPrefix;
+            }
+
+            String expectedTimestamp = timestampPrefix + pi.versionCode + "-" + pi.lastUpdateTime;
+
+            String[] timestamps = outputDir.list(new FilenameFilter() {
+                @Override
+                public boolean accept(File dir, String name) {
+                    return name.startsWith(timestampPrefix);
+                }
+            });
+
+            if (timestamps.length != 1) {
+                // If there's no timestamp, nuke to be safe as we can't tell the age of the files.
+                // If there's multiple timestamps, something's gone wrong so nuke.
+                return expectedTimestamp;
+            }
+
+            if (!expectedTimestamp.equals(timestamps[0])) {
+                return expectedTimestamp;
+            }
+
+            // timestamp file is already up-to date.
+            return null;
+        }
+
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+        private void beginTraceSection(String section) {
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
+            Trace.beginSection(section);
+        }
+
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+        private void endTraceSection() {
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
+            Trace.endSection();
+        }
+    }
+
+    private final Context mContext;
+    private ExtractTask mExtractTask;
+
+    private static ResourceExtractor sInstance;
+
+    public static ResourceExtractor get(Context context) {
+        if (sInstance == null) {
+            sInstance = new ResourceExtractor(context);
+        }
+        return sInstance;
+    }
+
+    /**
+     * Specifies the .pak files that should be extracted from the APK's asset resources directory
+     * and moved to {@link #getOutputDirFromContext(Context)}.
+     * @param mandatoryPaks The list of pak files to be loaded. If no pak files are
+     *     required, pass a single empty string.
+     */
+    public static void setMandatoryPaksToExtract(String... mandatoryPaks) {
+        assert (sInstance == null || sInstance.mExtractTask == null)
+                : "Must be called before startExtractingResources is called";
+        sMandatoryPaks = mandatoryPaks;
+
+    }
+
+    /**
+     * By default the ResourceExtractor will attempt to extract a pak resource for the users
+     * currently specified locale. This behavior can be changed with this function and is
+     * only needed by tests.
+     * @param extract False if we should not attempt to extract a pak file for
+     *         the users currently selected locale and try to extract only the
+     *         pak files specified in sMandatoryPaks.
+     */
+    @VisibleForTesting
+    public static void setExtractImplicitLocaleForTesting(boolean extract) {
+        assert (sInstance == null || sInstance.mExtractTask == null)
+                : "Must be called before startExtractingResources is called";
+        sExtractImplicitLocalePak = extract;
+    }
+
+    /**
+     * Marks all the 'pak' resources, packaged as assets, for extraction during
+     * running the tests.
+     */
+    @VisibleForTesting
+    public void setExtractAllPaksAndV8SnapshotForTesting() {
+        List<String> pakAndSnapshotFileAssets = new ArrayList<String>();
+        AssetManager manager = mContext.getResources().getAssets();
+        try {
+            String[] files = manager.list("");
+            for (String file : files) {
+                if (file.endsWith(".pak")) pakAndSnapshotFileAssets.add(file);
+            }
+        } catch (IOException e) {
+            Log.w(LOGTAG, "Exception while accessing assets: " + e.getMessage(), e);
+        }
+        pakAndSnapshotFileAssets.add("natives_blob.bin");
+        pakAndSnapshotFileAssets.add("snapshot_blob.bin");
+        setMandatoryPaksToExtract(pakAndSnapshotFileAssets.toArray(
+                new String[pakAndSnapshotFileAssets.size()]));
+    }
+
+    private ResourceExtractor(Context context) {
+        mContext = context.getApplicationContext();
+    }
+
+    /**
+     * Synchronously wait for the resource extraction to be completed.
+     * <p>
+     * This method is bad and you should feel bad for using it.
+     *
+     * @see #addCompletionCallback(Runnable)
+     */
+    public void waitForCompletion() {
+        if (shouldSkipPakExtraction()) {
+            return;
+        }
+
+        assert mExtractTask != null;
+
+        try {
+            mExtractTask.get();
+        } catch (CancellationException e) {
+            // Don't leave the files in an inconsistent state.
+            deleteFiles();
+        } catch (ExecutionException e2) {
+            deleteFiles();
+        } catch (InterruptedException e3) {
+            deleteFiles();
+        }
+    }
+
+    /**
+     * Adds a callback to be notified upon the completion of resource extraction.
+     * <p>
+     * If the resource task has already completed, the callback will be posted to the UI message
+     * queue.  Otherwise, it will be executed after all the resources have been extracted.
+     * <p>
+     * This must be called on the UI thread.  The callback will also always be executed on
+     * the UI thread.
+     *
+     * @param callback The callback to be enqueued.
+     */
+    public void addCompletionCallback(Runnable callback) {
+        ThreadUtils.assertOnUiThread();
+
+        Handler handler = new Handler(Looper.getMainLooper());
+        if (shouldSkipPakExtraction()) {
+            handler.post(callback);
+            return;
+        }
+
+        assert mExtractTask != null;
+        assert !mExtractTask.isCancelled();
+        if (mExtractTask.getStatus() == AsyncTask.Status.FINISHED) {
+            handler.post(callback);
+        } else {
+            mExtractTask.mCompletionCallbacks.add(callback);
+        }
+    }
+
+    /**
+     * This will extract the application pak resources in an
+     * AsyncTask. Call waitForCompletion() at the point resources
+     * are needed to block until the task completes.
+     */
+    public void startExtractingResources() {
+        if (mExtractTask != null) {
+            return;
+        }
+
+        if (shouldSkipPakExtraction()) {
+            return;
+        }
+
+        mExtractTask = new ExtractTask();
+        mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    private File getAppDataDir() {
+        return new File(PathUtils.getDataDirectory(mContext));
+    }
+
+    private File getOutputDir() {
+        return new File(getAppDataDir(), "paks");
+    }
+
+    /**
+     * Pak files (UI strings and other resources) should be updated along with
+     * Chrome. A version mismatch can lead to a rather broken user experience.
+     * Failing to update the V8 snapshot files will lead to a version mismatch
+     * between V8 and the loaded snapshot which will cause V8 to crash, so this
+     * is treated as an error. The ICU data (icudtl.dat) is less
+     * version-sensitive, but still can lead to malfunction/UX misbehavior. So,
+     * we regard failing to update them as an error.
+     */
+    private void deleteFiles() {
+        File icudata = new File(getAppDataDir(), ICU_DATA_FILENAME);
+        if (icudata.exists() && !icudata.delete()) {
+            Log.e(LOGTAG, "Unable to remove the icudata " + icudata.getName());
+        }
+        File v8_natives = new File(getAppDataDir(), V8_NATIVES_DATA_FILENAME);
+        if (v8_natives.exists() && !v8_natives.delete()) {
+            Log.e(LOGTAG,
+                    "Unable to remove the v8 data " + v8_natives.getName());
+        }
+        File v8_snapshot = new File(getAppDataDir(), V8_SNAPSHOT_DATA_FILENAME);
+        if (v8_snapshot.exists() && !v8_snapshot.delete()) {
+            Log.e(LOGTAG,
+                    "Unable to remove the v8 data " + v8_snapshot.getName());
+        }
+        File dir = getOutputDir();
+        if (dir.exists()) {
+            File[] files = dir.listFiles();
+            for (File file : files) {
+                if (!file.delete()) {
+                    Log.e(LOGTAG, "Unable to remove existing resource " + file.getName());
+                }
+            }
+        }
+    }
+
+    /**
+     * Pak extraction not necessarily required by the embedder; we allow them to skip
+     * this process if they call setMandatoryPaksToExtract with a single empty String.
+     */
+    private static boolean shouldSkipPakExtraction() {
+        // Must call setMandatoryPaksToExtract before beginning resource extraction.
+        assert sMandatoryPaks != null;
+        return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
new file mode 100644
index 0000000..457e2ef
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.SecureRandom;
+
+/**
+ * This class contains code to initialize a SecureRandom generator securely on Android platforms
+ * <= 4.3. See
+ * {@link http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html}.
+ */
+public class SecureRandomInitializer {
+    private static final int NUM_RANDOM_BYTES = 16;
+
+    private static byte[] sSeedBytes = new byte[NUM_RANDOM_BYTES];
+
+    /**
+     * Safely initializes the random number generator, by seeding it with data from /dev/urandom.
+     */
+    public static void initialize(SecureRandom generator) throws IOException {
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream("/dev/urandom");
+            if (fis.read(sSeedBytes) != sSeedBytes.length) {
+                throw new IOException("Failed to get enough random data.");
+            }
+            generator.setSeed(sSeedBytes);
+        } finally {
+            try {
+                if (fis != null) {
+                    fis.close();
+                }
+            } catch (IOException e) {
+                // Ignore exception closing the device.
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java
new file mode 100644
index 0000000..9dad516
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SysUtils.java
@@ -0,0 +1,139 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Build;
+import android.os.StrictMode;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Exposes system related information about the current device.
+ */
+public class SysUtils {
+    // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
+    private static final int ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
+
+    // Number of kilobytes in a megabyte.
+    private static final int KBS_IN_MB = 1024;
+
+    private static final String TAG = "SysUtils";
+
+    private static Boolean sLowEndDevice;
+
+    private SysUtils() { }
+
+    /**
+     * Return the amount of physical memory on this device in kilobytes.
+     * @return Amount of physical memory in kilobytes, or 0 if there was
+     *         an error trying to access the information.
+     */
+    private static int amountOfPhysicalMemoryMB() {
+        // Extract total memory RAM size by parsing /proc/meminfo, note that
+        // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
+        // does. However, it can't be called because this method must be
+        // usable before any native code is loaded.
+
+        // An alternative is to use ActivityManager.getMemoryInfo(), but this
+        // requires a valid ActivityManager handle, which can only come from
+        // a valid Context object, which itself cannot be retrieved
+        // during early startup, where this method is called. And making it
+        // an explicit parameter here makes all call paths _much_ more
+        // complicated.
+
+        Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
+        // Synchronously reading files in /proc in the UI thread is safe.
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            FileReader fileReader = new FileReader("/proc/meminfo");
+            try {
+                BufferedReader reader = new BufferedReader(fileReader);
+                try {
+                    String line;
+                    for (;;) {
+                        line = reader.readLine();
+                        if (line == null) {
+                            Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
+                            break;
+                        }
+                        Matcher m = pattern.matcher(line);
+                        if (!m.find()) continue;
+
+                        int totalMemoryKB = Integer.parseInt(m.group(1));
+                        // Sanity check.
+                        if (totalMemoryKB <= KBS_IN_MB) {
+                            Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
+                            break;
+                        }
+
+                        return totalMemoryKB / KBS_IN_MB;
+                    }
+
+                } finally {
+                    reader.close();
+                }
+            } finally {
+                fileReader.close();
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+
+        return 0;
+    }
+
+    /**
+     * @return Whether or not this device should be considered a low end device.
+     */
+    @CalledByNative
+    public static boolean isLowEndDevice() {
+        if (sLowEndDevice == null) {
+            sLowEndDevice = detectLowEndDevice();
+        }
+        return sLowEndDevice.booleanValue();
+    }
+
+    @TargetApi(Build.VERSION_CODES.KITKAT)
+    private static boolean detectLowEndDevice() {
+        assert CommandLine.isInitialized();
+        if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
+            return true;
+        }
+        if (CommandLine.getInstance().hasSwitch(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)) {
+            return false;
+        }
+        // Any pre-KitKat device cannot be considered 'low-end'.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+            return false;
+        }
+
+        Context context = ApplicationStatus.getApplicationContext();
+        if (context != null) {
+            ActivityManager activityManager = (ActivityManager)
+                    context.getSystemService(Context.ACTIVITY_SERVICE);
+            if (activityManager.isLowRamDevice()) {
+                return true;
+            }
+        } else {
+            Log.e(TAG, "ApplicationContext is null in ApplicationStatus");
+        }
+
+        int ramSizeMB = amountOfPhysicalMemoryMB();
+        if (ramSizeMB <= 0) {
+            return false;
+        }
+
+        return ramSizeMB < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
new file mode 100644
index 0000000..fd3dc5a
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -0,0 +1,111 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class SystemMessageHandler extends Handler {
+
+    private static final String TAG = "SystemMessageHandler";
+
+    private static final int SCHEDULED_WORK = 1;
+    private static final int DELAYED_SCHEDULED_WORK = 2;
+
+    // Native class pointer set by the constructor of the SharedClient native class.
+    private long mMessagePumpDelegateNative = 0;
+    private long mDelayedScheduledTimeTicks = 0;
+
+    // Reflected API for marking a message as asynchronous. This is a workaround
+    // to provide fair Chromium task dispatch when served by the Android UI
+    // thread's Looper, avoiding stalls when the Looper has a sync barrier.
+    // Note: Use of this API is experimental and likely to evolve in the future.
+    private Method mMessageMethodSetAsynchronous;
+
+    private SystemMessageHandler(long messagePumpDelegateNative) {
+        mMessagePumpDelegateNative = messagePumpDelegateNative;
+
+        try {
+            Class<?> messageClass = Class.forName("android.os.Message");
+            mMessageMethodSetAsynchronous = messageClass.getMethod(
+                    "setAsynchronous", new Class[]{boolean.class});
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Failed to find android.os.Message class:" + e);
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
+        }
+
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        if (msg.what == DELAYED_SCHEDULED_WORK) {
+            mDelayedScheduledTimeTicks = 0;
+        }
+        nativeDoRunLoopOnce(mMessagePumpDelegateNative, mDelayedScheduledTimeTicks);
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void scheduleWork() {
+        sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void scheduleDelayedWork(long delayedTimeTicks, long millis) {
+        if (mDelayedScheduledTimeTicks != 0) {
+            removeMessages(DELAYED_SCHEDULED_WORK);
+        }
+        mDelayedScheduledTimeTicks = delayedTimeTicks;
+        sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis);
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void removeAllPendingMessages() {
+        removeMessages(SCHEDULED_WORK);
+        removeMessages(DELAYED_SCHEDULED_WORK);
+    }
+
+    private Message obtainAsyncMessage(int what) {
+        Message msg = Message.obtain();
+        msg.what = what;
+        if (mMessageMethodSetAsynchronous != null) {
+            // If invocation fails, assume this is indicative of future
+            // failures, and avoid log spam by nulling the reflected method.
+            try {
+                mMessageMethodSetAsynchronous.invoke(msg, true);
+            } catch (IllegalAccessException e) {
+                Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (InvocationTargetException e) {
+                Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            }
+        }
+        return msg;
+    }
+
+    @CalledByNative
+    private static SystemMessageHandler create(long messagePumpDelegateNative) {
+        return new SystemMessageHandler(messagePumpDelegateNative);
+    }
+
+    private native void nativeDoRunLoopOnce(
+            long messagePumpDelegateNative, long delayedScheduledTimeTicks);
+}
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
new file mode 100644
index 0000000..c0b9172
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -0,0 +1,209 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Helper methods to deal with threading related tasks.
+ */
+public class ThreadUtils {
+
+    private static final Object sLock = new Object();
+
+    private static boolean sWillOverride = false;
+
+    private static Handler sUiThreadHandler = null;
+
+    public static void setWillOverrideUiThread() {
+        synchronized (sLock) {
+            sWillOverride = true;
+        }
+    }
+
+    public static void setUiThread(Looper looper) {
+        synchronized (sLock) {
+            if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
+                throw new RuntimeException("UI thread looper is already set to "
+                        + sUiThreadHandler.getLooper() + " (Main thread looper is "
+                        + Looper.getMainLooper() + "), cannot set to new looper " + looper);
+            } else {
+                sUiThreadHandler = new Handler(looper);
+            }
+        }
+    }
+
+    private static Handler getUiThreadHandler() {
+        synchronized (sLock) {
+            if (sUiThreadHandler == null) {
+                if (sWillOverride) {
+                    throw new RuntimeException("Did not yet override the UI thread");
+                }
+                sUiThreadHandler = new Handler(Looper.getMainLooper());
+            }
+            return sUiThreadHandler;
+        }
+    }
+
+    /**
+     * Run the supplied Runnable on the main thread. The method will block until the Runnable
+     * completes.
+     *
+     * @param r The Runnable to run.
+     */
+    public static void runOnUiThreadBlocking(final Runnable r) {
+        if (runningOnUiThread()) {
+            r.run();
+        } else {
+            FutureTask<Void> task = new FutureTask<Void>(r, null);
+            postOnUiThread(task);
+            try {
+                task.get();
+            } catch (Exception e) {
+                throw new RuntimeException("Exception occured while waiting for runnable", e);
+            }
+        }
+    }
+
+    /**
+     * Run the supplied Callable on the main thread, wrapping any exceptions in a RuntimeException.
+     * The method will block until the Callable completes.
+     *
+     * @param c The Callable to run
+     * @return The result of the callable
+     */
+    public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
+        try {
+            return runOnUiThreadBlocking(c);
+        } catch (ExecutionException e) {
+            throw new RuntimeException("Error occured waiting for callable", e);
+        }
+    }
+
+    /**
+     * Run the supplied Callable on the main thread, The method will block until the Callable
+     * completes.
+     *
+     * @param c The Callable to run
+     * @return The result of the callable
+     * @throws ExecutionException c's exception
+     */
+    public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
+        FutureTask<T> task = new FutureTask<T>(c);
+        runOnUiThread(task);
+        try {
+            return task.get();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted waiting for callable", e);
+        }
+    }
+
+    /**
+     * Run the supplied FutureTask on the main thread. The method will block only if the current
+     * thread is the main thread.
+     *
+     * @param task The FutureTask to run
+     * @return The queried task (to aid inline construction)
+     */
+    public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) {
+        if (runningOnUiThread()) {
+            task.run();
+        } else {
+            postOnUiThread(task);
+        }
+        return task;
+    }
+
+    /**
+     * Run the supplied Callable on the main thread. The method will block only if the current
+     * thread is the main thread.
+     *
+     * @param c The Callable to run
+     * @return A FutureTask wrapping the callable to retrieve results
+     */
+    public static <T> FutureTask<T> runOnUiThread(Callable<T> c) {
+        return runOnUiThread(new FutureTask<T>(c));
+    }
+
+    /**
+     * Run the supplied Runnable on the main thread. The method will block only if the current
+     * thread is the main thread.
+     *
+     * @param r The Runnable to run
+     */
+    public static void runOnUiThread(Runnable r) {
+        if (runningOnUiThread()) {
+            r.run();
+        } else {
+            getUiThreadHandler().post(r);
+        }
+    }
+
+    /**
+     * Post the supplied FutureTask to run on the main thread. The method will not block, even if
+     * called on the UI thread.
+     *
+     * @param task The FutureTask to run
+     * @return The queried task (to aid inline construction)
+     */
+    public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
+        getUiThreadHandler().post(task);
+        return task;
+    }
+
+    /**
+     * Post the supplied Runnable to run on the main thread. The method will not block, even if
+     * called on the UI thread.
+     *
+     * @param task The Runnable to run
+     */
+    public static void postOnUiThread(Runnable task) {
+        getUiThreadHandler().post(task);
+    }
+
+    /**
+     * Post the supplied Runnable to run on the main thread after the given amount of time. The
+     * method will not block, even if called on the UI thread.
+     *
+     * @param task The Runnable to run
+     * @param delayMillis The delay in milliseconds until the Runnable will be run
+     */
+    @VisibleForTesting
+    public static void postOnUiThreadDelayed(Runnable task, long delayMillis) {
+        getUiThreadHandler().postDelayed(task, delayMillis);
+    }
+
+    /**
+     * Asserts that the current thread is running on the main thread.
+     */
+    public static void assertOnUiThread() {
+        assert runningOnUiThread();
+    }
+
+    /**
+     * @return true iff the current thread is the main (UI) thread.
+     */
+    public static boolean runningOnUiThread() {
+        return getUiThreadHandler().getLooper() == Looper.myLooper();
+    }
+
+    public static Looper getUiThreadLooper() {
+        return getUiThreadHandler().getLooper();
+    }
+
+    /**
+     * Set thread priority to audio.
+     */
+    @CalledByNative
+    public static void setThreadPriorityAudio(int tid) {
+        Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
new file mode 100644
index 0000000..3d3b11a
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -0,0 +1,285 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Printer;
+/**
+ * Java mirror of Chrome trace event API. See base/trace_event/trace_event.h. Unlike the native
+ * version, Java does not have stack objects, so a TRACE_EVENT() which does both TRACE_EVENT_BEGIN()
+ * and TRACE_EVENT_END() in ctor/dtor is not possible.
+ * It is OK to use tracing before the native library has loaded, but such traces will
+ * be ignored. (Perhaps we could devise to buffer them up in future?).
+ */
+@JNINamespace("base::android")
+public class TraceEvent {
+
+    private static volatile boolean sEnabled = false;
+
+    private static class BasicLooperMonitor implements Printer {
+        @Override
+        public void println(final String line) {
+            if (line.startsWith(">")) {
+                beginHandling(line);
+            } else {
+                assert line.startsWith("<");
+                endHandling(line);
+            }
+        }
+
+        void beginHandling(final String line) {
+            if (sEnabled) nativeBeginToplevel();
+        }
+
+        void endHandling(final String line) {
+            if (sEnabled) nativeEndToplevel();
+        }
+    }
+
+    /**
+     * A class that records, traces and logs statistics about the UI thead's Looper.
+     * The output of this class can be used in a number of interesting ways:
+     * <p>
+     * <ol><li>
+     * When using chrometrace, there will be a near-continuous line of
+     * measurements showing both event dispatches as well as idles;
+     * </li><li>
+     * Logging messages are output for events that run too long on the
+     * event dispatcher, making it easy to identify problematic areas;
+     * </li><li>
+     * Statistics are output whenever there is an idle after a non-trivial
+     * amount of activity, allowing information to be gathered about task
+     * density and execution cadence on the Looper;
+     * </li></ol>
+     * <p>
+     * The class attaches itself as an idle handler to the main Looper, and
+     * monitors the execution of events and idle notifications. Task counters
+     * accumulate between idle notifications and get reset when a new idle
+     * notification is received.
+     */
+    private static final class IdleTracingLooperMonitor extends BasicLooperMonitor
+            implements MessageQueue.IdleHandler {
+        // Tags for dumping to logcat or TraceEvent
+        private static final String TAG = "TraceEvent.LooperMonitor";
+        private static final String IDLE_EVENT_NAME = "Looper.queueIdle";
+
+        // Calculation constants
+        private static final long FRAME_DURATION_MILLIS = 1000L / 60L; // 60 FPS
+        // A reasonable threshold for defining a Looper event as "long running"
+        private static final long MIN_INTERESTING_DURATION_MILLIS =
+                FRAME_DURATION_MILLIS;
+        // A reasonable threshold for a "burst" of tasks on the Looper
+        private static final long MIN_INTERESTING_BURST_DURATION_MILLIS =
+                MIN_INTERESTING_DURATION_MILLIS * 3;
+
+        // Stats tracking
+        private long mLastIdleStartedAt = 0L;
+        private long mLastWorkStartedAt = 0L;
+        private int mNumTasksSeen = 0;
+        private int mNumIdlesSeen = 0;
+        private int mNumTasksSinceLastIdle = 0;
+
+        // State
+        private boolean mIdleMonitorAttached = false;
+
+        // Called from within the begin/end methods only.
+        // This method can only execute on the looper thread, because that is
+        // the only thread that is permitted to call Looper.myqueue().
+        private final void syncIdleMonitoring() {
+            if (sEnabled && !mIdleMonitorAttached) {
+                // approximate start time for computational purposes
+                mLastIdleStartedAt = SystemClock.elapsedRealtime();
+                Looper.myQueue().addIdleHandler(this);
+                mIdleMonitorAttached = true;
+                Log.v(TAG, "attached idle handler");
+            } else if (mIdleMonitorAttached && !sEnabled) {
+                Looper.myQueue().removeIdleHandler(this);
+                mIdleMonitorAttached = false;
+                Log.v(TAG, "detached idle handler");
+            }
+        }
+
+        @Override
+        final void beginHandling(final String line) {
+            // Close-out any prior 'idle' period before starting new task.
+            if (mNumTasksSinceLastIdle == 0) {
+                TraceEvent.end(IDLE_EVENT_NAME);
+            }
+            mLastWorkStartedAt = SystemClock.elapsedRealtime();
+            syncIdleMonitoring();
+            super.beginHandling(line);
+        }
+
+        @Override
+        final void endHandling(final String line) {
+            final long elapsed = SystemClock.elapsedRealtime()
+                    - mLastWorkStartedAt;
+            if (elapsed > MIN_INTERESTING_DURATION_MILLIS) {
+                traceAndLog(Log.WARN, "observed a task that took "
+                        + elapsed + "ms: " + line);
+            }
+            super.endHandling(line);
+            syncIdleMonitoring();
+            mNumTasksSeen++;
+            mNumTasksSinceLastIdle++;
+        }
+
+        private static void traceAndLog(int level, String message) {
+            TraceEvent.instant("TraceEvent.LooperMonitor:IdleStats", message);
+            Log.println(level, TAG, message);
+        }
+
+        @Override
+        public final boolean queueIdle() {
+            final long now =  SystemClock.elapsedRealtime();
+            if (mLastIdleStartedAt == 0) mLastIdleStartedAt = now;
+            final long elapsed = now - mLastIdleStartedAt;
+            mNumIdlesSeen++;
+            TraceEvent.begin(IDLE_EVENT_NAME, mNumTasksSinceLastIdle + " tasks since last idle.");
+            if (elapsed > MIN_INTERESTING_BURST_DURATION_MILLIS) {
+                // Dump stats
+                String statsString = mNumTasksSeen + " tasks and "
+                        + mNumIdlesSeen + " idles processed so far, "
+                        + mNumTasksSinceLastIdle + " tasks bursted and "
+                        + elapsed + "ms elapsed since last idle";
+                traceAndLog(Log.DEBUG, statsString);
+            }
+            mLastIdleStartedAt = now;
+            mNumTasksSinceLastIdle = 0;
+            return true; // stay installed
+        }
+    }
+
+    // Holder for monitor avoids unnecessary construction on non-debug runs
+    private static final class LooperMonitorHolder {
+        private static final BasicLooperMonitor sInstance =
+                CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_IDLE_TRACING)
+                ? new IdleTracingLooperMonitor() : new BasicLooperMonitor();
+    }
+
+
+    /**
+     * Register an enabled observer, such that java traces are always enabled with native.
+     */
+    public static void registerNativeEnabledObserver() {
+        nativeRegisterEnabledObserver();
+    }
+
+    /**
+     * Notification from native that tracing is enabled/disabled.
+     */
+    @CalledByNative
+    public static void setEnabled(boolean enabled) {
+        sEnabled = enabled;
+        ThreadUtils.getUiThreadLooper().setMessageLogging(
+                enabled ? LooperMonitorHolder.sInstance : null);
+    }
+
+    /**
+     * Enables or disabled Android systrace path of Chrome tracing. If enabled, all Chrome
+     * traces will be also output to Android systrace. Because of the overhead of Android
+     * systrace, this is for WebView only.
+     */
+    public static void setATraceEnabled(boolean enabled) {
+        if (sEnabled == enabled) return;
+        if (enabled) {
+            nativeStartATrace();
+        } else {
+            nativeStopATrace();
+        }
+    }
+
+    /**
+     * @return True if tracing is enabled, false otherwise.
+     * It is safe to call trace methods without checking if TraceEvent
+     * is enabled.
+     */
+    public static boolean enabled() {
+        return sEnabled;
+    }
+
+    /**
+     * Triggers the 'instant' native trace event with no arguments.
+     * @param name The name of the event.
+     */
+    public static void instant(String name) {
+        if (sEnabled) nativeInstant(name, null);
+    }
+
+    /**
+     * Triggers the 'instant' native trace event.
+     * @param name The name of the event.
+     * @param arg  The arguments of the event.
+     */
+    public static void instant(String name, String arg) {
+        if (sEnabled) nativeInstant(name, arg);
+    }
+
+    /**
+     * Triggers the 'start' native trace event with no arguments.
+     * @param name The name of the event.
+     * @param id   The id of the asynchronous event.
+     */
+    public static void startAsync(String name, long id) {
+        if (sEnabled) nativeStartAsync(name, id);
+    }
+
+    /**
+     * Triggers the 'finish' native trace event with no arguments.
+     * @param name The name of the event.
+     * @param id   The id of the asynchronous event.
+     */
+    public static void finishAsync(String name, long id) {
+        if (sEnabled) nativeFinishAsync(name, id);
+    }
+
+    /**
+     * Triggers the 'begin' native trace event with no arguments.
+     * @param name The name of the event.
+     */
+    public static void begin(String name) {
+        if (sEnabled) nativeBegin(name, null);
+    }
+
+    /**
+     * Triggers the 'begin' native trace event.
+     * @param name The name of the event.
+     * @param arg  The arguments of the event.
+     */
+    public static void begin(String name, String arg) {
+        if (sEnabled) nativeBegin(name, arg);
+    }
+
+    /**
+     * Triggers the 'end' native trace event with no arguments.
+     * @param name The name of the event.
+     */
+    public static void end(String name) {
+        if (sEnabled) nativeEnd(name, null);
+    }
+
+    /**
+     * Triggers the 'end' native trace event.
+     * @param name The name of the event.
+     * @param arg  The arguments of the event.
+     */
+    public static void end(String name, String arg) {
+        if (sEnabled) nativeEnd(name, arg);
+    }
+
+    private static native void nativeRegisterEnabledObserver();
+    private static native void nativeStartATrace();
+    private static native void nativeStopATrace();
+    private static native void nativeInstant(String name, String arg);
+    private static native void nativeBegin(String name, String arg);
+    private static native void nativeEnd(String name, String arg);
+    private static native void nativeBeginToplevel();
+    private static native void nativeEndToplevel();
+    private static native void nativeStartAsync(String name, long id);
+    private static native void nativeFinishAsync(String name, long id);
+}
diff --git a/base/android/java/src/org/chromium/base/VisibleForTesting.java b/base/android/java/src/org/chromium/base/VisibleForTesting.java
new file mode 100644
index 0000000..24cbfad
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/VisibleForTesting.java
@@ -0,0 +1,12 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * Annotation used to mark code that has wider visibility or present for testing code.
+ */
+public @interface VisibleForTesting {
+
+}
diff --git a/base/android/java/src/org/chromium/base/WindowCallbackWrapper.java b/base/android/java/src/org/chromium/base/WindowCallbackWrapper.java
new file mode 100644
index 0000000..0718c22
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/WindowCallbackWrapper.java
@@ -0,0 +1,140 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.SuppressLint;
+import android.view.ActionMode;
+import android.view.ActionMode.Callback;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager.LayoutParams;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * A wrapper for a Window.Callback instance, allowing subclasses to listen to or override specific
+ * window messages.
+ */
+class WindowCallbackWrapper implements Window.Callback {
+    private final Window.Callback mCallback;
+
+    public WindowCallbackWrapper(Window.Callback callback) {
+        mCallback = callback;
+    }
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent event) {
+        return mCallback.dispatchGenericMotionEvent(event);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mCallback.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+        return mCallback.dispatchKeyShortcutEvent(event);
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        return mCallback.dispatchPopulateAccessibilityEvent(event);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent event) {
+        return mCallback.dispatchTouchEvent(event);
+    }
+
+    @Override
+    public boolean dispatchTrackballEvent(MotionEvent event) {
+        return mCallback.dispatchTrackballEvent(event);
+    }
+
+    @Override
+    public void onActionModeFinished(ActionMode mode) {
+        mCallback.onActionModeFinished(mode);
+    }
+
+    @Override
+    public void onActionModeStarted(ActionMode mode) {
+        mCallback.onActionModeStarted(mode);
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        mCallback.onAttachedToWindow();
+    }
+
+    @Override
+    public void onContentChanged() {
+        mCallback.onContentChanged();
+    }
+
+    @Override
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+        return mCallback.onCreatePanelMenu(featureId, menu);
+    }
+
+    @Override
+    public View onCreatePanelView(int featureId) {
+        return mCallback.onCreatePanelView(featureId);
+    }
+
+    @Override
+    @SuppressLint("MissingSuperCall")
+    public void onDetachedFromWindow() {
+        mCallback.onDetachedFromWindow();
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        return mCallback.onMenuItemSelected(featureId, item);
+    }
+
+    @Override
+    public boolean onMenuOpened(int featureId, Menu menu) {
+        return mCallback.onMenuOpened(featureId, menu);
+    }
+
+    @Override
+    public void onPanelClosed(int featureId, Menu menu) {
+        mCallback.onPanelClosed(featureId, menu);
+    }
+
+    @Override
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {
+        return mCallback.onPreparePanel(featureId, view, menu);
+    }
+
+    @Override
+    public boolean onSearchRequested() {
+        return mCallback.onSearchRequested();
+    }
+
+    @Override
+    public void onWindowAttributesChanged(LayoutParams attrs) {
+        mCallback.onWindowAttributesChanged(attrs);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        mCallback.onWindowFocusChanged(hasFocus);
+    }
+
+    @Override
+    public ActionMode onWindowStartingActionMode(Callback callback) {
+        return mCallback.onWindowStartingActionMode(callback);
+    }
+
+    public void onWindowDismissed() {
+        // TODO(benm): implement me.
+    }
+
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
new file mode 100644
index 0000000..6df7c11
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
@@ -0,0 +1,20 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *  @AccessedByNative is used to ensure proguard will keep this field, since it's
+ *  only accessed by native.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.CLASS)
+public @interface AccessedByNative {
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
new file mode 100644
index 0000000..c0abcbe
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
@@ -0,0 +1,27 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *  @CalledByNativeUnchecked is used to generate JNI bindings that do not check for exceptions.
+ *  It only makes sense to use this annotation on methods that declare a throws... spec.
+ *  However, note that the exception received native side maybe an 'unchecked' (RuntimeExpception)
+ *  such as NullPointerException, so the native code should differentiate these cases.
+ *  Usage of this should be very rare; where possible handle exceptions in the Java side and use a
+ *  return value to indicate success / failure.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface CalledByNativeUnchecked {
+    /*
+     *  If present, tells which inner class the method belongs to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
new file mode 100644
index 0000000..803c3f9
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to indicate to proguard methods that have no side effects and can be
+ * safely removed if their return value is not used. This is to be used with
+ * {@link org.chromium.base.Log}'s method, that can also be removed by proguard. That way
+ * expensive calls can be left in debug builds but removed in release.
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface NoSideEffects {}
diff --git a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
new file mode 100644
index 0000000..89068ac
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *  @SuppressFBWarnings is used to suppress FindBugs warnings.
+ *
+ *  The long name of FindBugs warnings can be found at
+ *  http://findbugs.sourceforge.net/bugDescriptions.html
+ */
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressFBWarnings {
+    String[] value() default {};
+    String justification() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
new file mode 100644
index 0000000..a2af704
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used for marking methods and fields that are called by reflection.
+ * Useful for keeping components that would otherwise be removed by Proguard.
+ * Use the value parameter to mention a file that calls this method.
+ *
+ * Note that adding this annotation to a method is not enough to guarantee that
+ * it is kept - either its class must be referenced elsewhere in the program, or
+ * the class must be annotated with this as well.
+ */
+@Target({
+        ElementType.METHOD, ElementType.FIELD, ElementType.TYPE,
+        ElementType.CONSTRUCTOR })
+public @interface UsedByReflection {
+    String value();
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
new file mode 100644
index 0000000..9dc6865
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -0,0 +1,532 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.SystemClock;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.CommandLine;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.TraceEvent;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
+
+import java.util.Locale;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class provides functionality to load and register the native libraries.
+ * Callers are allowed to separate loading the libraries from initializing them.
+ * This may be an advantage for Android Webview, where the libraries can be loaded
+ * by the zygote process, but then needs per process initialization after the
+ * application processes are forked from the zygote process.
+ *
+ * The libraries may be loaded and initialized from any thread. Synchronization
+ * primitives are used to ensure that overlapping requests from different
+ * threads are handled sequentially.
+ *
+ * See also base/android/library_loader/library_loader_hooks.cc, which contains
+ * the native counterpart to this class.
+ */
+@JNINamespace("base::android")
+public class LibraryLoader {
+    private static final String TAG = "LibraryLoader";
+
+    // Set to true to enable debug logs.
+    private static final boolean DEBUG = false;
+
+    // Guards all access to the libraries
+    private static final Object sLock = new Object();
+
+    // The singleton instance of LibraryLoader.
+    private static volatile LibraryLoader sInstance;
+
+    // One-way switch becomes true when the libraries are loaded.
+    private boolean mLoaded;
+
+    // One-way switch becomes true when the Java command line is switched to
+    // native.
+    private boolean mCommandLineSwitched;
+
+    // One-way switch becomes true when the libraries are initialized (
+    // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
+    // library_loader_hooks.cc).
+    // Note that this member should remain a one-way switch, since it accessed from multiple
+    // threads without a lock.
+    private volatile boolean mInitialized;
+
+    // One-way switches recording attempts to use Relro sharing in the browser.
+    // The flags are used to report UMA stats later.
+    private boolean mIsUsingBrowserSharedRelros;
+    private boolean mLoadAtFixedAddressFailed;
+
+    // One-way switch becomes true if the device supports memory mapping the
+    // APK file with executable permissions.
+    private boolean mMapApkWithExecPermission;
+
+    // One-way switch to indicate whether we probe for memory mapping the APK
+    // file with executable permissions. We suppress the probe under some
+    // conditions.
+    // For more, see:
+    //   https://code.google.com/p/chromium/issues/detail?id=448084
+    private boolean mProbeMapApkWithExecPermission = true;
+
+    // One-way switch becomes true if the Chromium library was loaded from the
+    // APK file directly.
+    private boolean mLibraryWasLoadedFromApk;
+
+    // One-way switch becomes false if the Chromium library should be loaded
+    // directly from the APK file but it was compressed or not aligned.
+    private boolean mLibraryIsMappableInApk = true;
+
+    // The type of process the shared library is loaded in.
+    // This member can be accessed from multiple threads simultaneously, so it have to be
+    // final (like now) or be protected in some way (volatile of synchronized).
+    private final int mLibraryProcessType;
+
+    /**
+     * @param libraryProcessType the process the shared library is loaded in. refer to
+     *                           LibraryProcessType for possible values.
+     * @return LibraryLoader if existing, otherwise create a new one.
+     */
+    public static LibraryLoader get(int libraryProcessType) throws ProcessInitException {
+        synchronized (sLock) {
+            if (sInstance != null) {
+                if (sInstance.mLibraryProcessType == libraryProcessType) return sInstance;
+                throw new ProcessInitException(
+                        LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED);
+            }
+            sInstance = new LibraryLoader(libraryProcessType);
+            return sInstance;
+        }
+    }
+
+    private LibraryLoader(int libraryProcessType) {
+        mLibraryProcessType = libraryProcessType;
+    }
+
+    /**
+     * The same as ensureInitialized(null, false), should only be called
+     * by non-browser processes.
+     *
+     * @throws ProcessInitException
+     */
+    @VisibleForTesting
+    public void ensureInitialized() throws ProcessInitException {
+        ensureInitialized(null, false);
+    }
+
+    /**
+     *  This method blocks until the library is fully loaded and initialized.
+     *
+     *  @param context The context in which the method is called, the caller
+     *    may pass in a null context if it doesn't know in which context it
+     *    is running.
+     *
+     *  @param shouldDeleteFallbackLibraries The flag tells whether the method
+     *    should delete the fallback libraries or not.
+     */
+    public void ensureInitialized(
+            Context context, boolean shouldDeleteFallbackLibraries)
+            throws ProcessInitException {
+        synchronized (sLock) {
+            if (mInitialized) {
+                // Already initialized, nothing to do.
+                return;
+            }
+            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+            initializeAlreadyLocked();
+        }
+    }
+
+    /**
+     * Checks if library is fully loaded and initialized.
+     */
+    public static boolean isInitialized() {
+        return sInstance != null && sInstance.mInitialized;
+    }
+
+    /**
+     * The same as loadNow(null, false), should only be called by
+     * non-browser process.
+     *
+     * @throws ProcessInitException
+     */
+    public void loadNow() throws ProcessInitException {
+        loadNow(null, false);
+    }
+
+    /**
+     * Loads the library and blocks until the load completes. The caller is responsible
+     * for subsequently calling ensureInitialized().
+     * May be called on any thread, but should only be called once. Note the thread
+     * this is called on will be the thread that runs the native code's static initializers.
+     * See the comment in doInBackground() for more considerations on this.
+     *
+     * @param context The context the code is running, or null if it doesn't have one.
+     * @param shouldDeleteFallbackLibraries The flag tells whether the method
+     *   should delete the old fallback libraries or not.
+     *
+     * @throws ProcessInitException if the native library failed to load.
+     */
+    public void loadNow(Context context, boolean shouldDeleteFallbackLibraries)
+            throws ProcessInitException {
+        synchronized (sLock) {
+            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+        }
+    }
+
+    /**
+     * initializes the library here and now: must be called on the thread that the
+     * native will call its "main" thread. The library must have previously been
+     * loaded with loadNow.
+     */
+    public void initialize() throws ProcessInitException {
+        synchronized (sLock) {
+            initializeAlreadyLocked();
+        }
+    }
+
+    /** Prefetches the native libraries in a background thread.
+     *
+     * Launches an AsyncTask that, through a short-lived forked process, reads a
+     * part of each page of the native library.  This is done to warm up the
+     * page cache, turning hard page faults into soft ones.
+     *
+     * This is done this way, as testing shows that fadvise(FADV_WILLNEED) is
+     * detrimental to the startup time.
+     *
+     * @param context the application context.
+     */
+    public void asyncPrefetchLibrariesToMemory(final Context context) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory");
+                boolean success = nativeForkAndPrefetchNativeLibrary();
+                if (!success) {
+                    Log.w(TAG, "Forking a process to prefetch the native library failed.");
+                }
+                RecordHistogram.recordBooleanHistogram("LibraryLoader.PrefetchStatus", success);
+                TraceEvent.end("LibraryLoader.asyncPrefetchLibrariesToMemory");
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
+    private void loadAlreadyLocked(
+            Context context, boolean shouldDeleteFallbackLibraries)
+            throws ProcessInitException {
+        try {
+            if (!mLoaded) {
+                assert !mInitialized;
+
+                long startTime = SystemClock.uptimeMillis();
+                boolean useChromiumLinker = Linker.isUsed();
+                boolean fallbackWasUsed = false;
+
+                if (useChromiumLinker) {
+                    String apkFilePath = null;
+                    boolean useMapExecSupportFallback = false;
+
+                    // If manufacturer is Samsung then skip the mmap exec check.
+                    //
+                    // For more, see:
+                    //   https://code.google.com/p/chromium/issues/detail?id=448084
+                    final String manufacturer = android.os.Build.MANUFACTURER;
+                    if (manufacturer != null
+                            && manufacturer.toLowerCase(Locale.ENGLISH).contains("samsung")) {
+                        Log.w(TAG, "Suppressed load from APK support check on this device");
+                        mProbeMapApkWithExecPermission = false;
+                    }
+
+                    // Check if the device supports memory mapping the APK file
+                    // with executable permissions.
+                    if (context != null) {
+                        apkFilePath = context.getApplicationInfo().sourceDir;
+                        if (mProbeMapApkWithExecPermission) {
+                            mMapApkWithExecPermission = Linker.checkMapExecSupport(apkFilePath);
+                        }
+                        if (!mMapApkWithExecPermission && Linker.isInZipFile()) {
+                            Log.w(TAG, "the no map executable support fallback will be used because"
+                                    + " memory mapping the APK file with executable permissions is"
+                                    + " not supported");
+                            Linker.enableNoMapExecSupportFallback();
+                            useMapExecSupportFallback = true;
+                        }
+                    } else {
+                        Log.w(TAG, "could not check load from APK support due to null context");
+                    }
+
+                    // Load libraries using the Chromium linker.
+                    Linker.prepareLibraryLoad();
+
+                    for (String library : NativeLibraries.LIBRARIES) {
+                        // Don't self-load the linker. This is because the build system is
+                        // not clever enough to understand that all the libraries packaged
+                        // in the final .apk don't need to be explicitly loaded.
+                        if (Linker.isChromiumLinkerLibrary(library)) {
+                            if (DEBUG) Log.i(TAG, "ignoring self-linker load");
+                            continue;
+                        }
+
+                        // Determine where the library should be loaded from.
+                        String zipFilePath = null;
+                        String libFilePath = System.mapLibraryName(library);
+                        if (apkFilePath != null && Linker.isInZipFile()) {
+                            // The library is in the APK file.
+                            if (!Linker.checkLibraryIsMappableInApk(apkFilePath, libFilePath)) {
+                                mLibraryIsMappableInApk = false;
+                            }
+                            if (mLibraryIsMappableInApk || useMapExecSupportFallback) {
+                                // Load directly from the APK (or use the no map executable
+                                // support fallback, see crazy_linker_elf_loader.cpp).
+                                zipFilePath = apkFilePath;
+                                Log.i(TAG, "Loading " + library + " "
+                                        + (useMapExecSupportFallback
+                                                ? "using no map executable support fallback"
+                                                : "directly")
+                                        + " from within " + apkFilePath);
+                            } else {
+                                // Unpack library fallback.
+                                Log.i(TAG, "Loading " + library
+                                        + " using unpack library fallback from within "
+                                        + apkFilePath);
+                                libFilePath = LibraryLoaderHelper.buildFallbackLibrary(
+                                        context, library);
+                                fallbackWasUsed = true;
+                                Log.i(TAG, "Built fallback library " + libFilePath);
+                            }
+                        } else {
+                            // The library is in its own file.
+                            Log.i(TAG, "Loading " + library);
+                        }
+
+                        // Load the library.
+                        boolean isLoaded = false;
+                        if (Linker.isUsingBrowserSharedRelros()) {
+                            mIsUsingBrowserSharedRelros = true;
+                            try {
+                                loadLibrary(zipFilePath, libFilePath);
+                                isLoaded = true;
+                            } catch (UnsatisfiedLinkError e) {
+                                Log.w(TAG, "Failed to load native library with shared RELRO, "
+                                        + "retrying without");
+                                Linker.disableSharedRelros();
+                                mLoadAtFixedAddressFailed = true;
+                            }
+                        }
+                        if (!isLoaded) {
+                            loadLibrary(zipFilePath, libFilePath);
+                        }
+                    }
+
+                    Linker.finishLibraryLoad();
+                } else {
+                    // Load libraries using the system linker.
+                    for (String library : NativeLibraries.LIBRARIES) {
+                        System.loadLibrary(library);
+                    }
+                }
+
+                if (!fallbackWasUsed && context != null
+                        && shouldDeleteFallbackLibraries) {
+                    LibraryLoaderHelper.deleteLibrariesAsynchronously(
+                            context, LibraryLoaderHelper.LOAD_FROM_APK_FALLBACK_DIR);
+                }
+
+                long stopTime = SystemClock.uptimeMillis();
+                Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
+                        stopTime - startTime,
+                        startTime % 10000,
+                        stopTime % 10000));
+
+                mLoaded = true;
+            }
+        } catch (UnsatisfiedLinkError e) {
+            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED, e);
+        }
+        // Check that the version of the library we have loaded matches the version we expect
+        Log.i(TAG, String.format(
+                "Expected native library version number \"%s\","
+                        + "actual native library version number \"%s\"",
+                NativeLibraries.sVersionNumber,
+                nativeGetVersionNumber()));
+        if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) {
+            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION);
+        }
+    }
+
+    // Load a native shared library with the Chromium linker. If the zip file
+    // path is not null, the library is loaded directly from the zip file.
+    private void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
+        Linker.loadLibrary(zipFilePath, libFilePath);
+        if (zipFilePath != null) {
+            mLibraryWasLoadedFromApk = true;
+        }
+    }
+
+    // The WebView requires the Command Line to be switched over before
+    // initialization is done. This is okay in the WebView's case since the
+    // JNI is already loaded by this point.
+    public void switchCommandLineForWebView() {
+        synchronized (sLock) {
+            ensureCommandLineSwitchedAlreadyLocked();
+        }
+    }
+
+    // Switch the CommandLine over from Java to native if it hasn't already been done.
+    // This must happen after the code is loaded and after JNI is ready (since after the
+    // switch the Java CommandLine will delegate all calls the native CommandLine).
+    private void ensureCommandLineSwitchedAlreadyLocked() {
+        assert mLoaded;
+        if (mCommandLineSwitched) {
+            return;
+        }
+        nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
+        CommandLine.enableNativeProxy();
+        mCommandLineSwitched = true;
+    }
+
+    // Invoke base::android::LibraryLoaded in library_loader_hooks.cc
+    private void initializeAlreadyLocked() throws ProcessInitException {
+        if (mInitialized) {
+            return;
+        }
+
+        // Setup the native command line if necessary.
+        if (!mCommandLineSwitched) {
+            nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
+        }
+
+        if (!nativeLibraryLoaded()) {
+            Log.e(TAG, "error calling nativeLibraryLoaded");
+            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_FAILED_TO_REGISTER_JNI);
+        }
+
+        // The Chrome JNI is registered by now so we can switch the Java
+        // command line over to delegating to native if it's necessary.
+        if (!mCommandLineSwitched) {
+            CommandLine.enableNativeProxy();
+            mCommandLineSwitched = true;
+        }
+
+        // From now on, keep tracing in sync with native.
+        TraceEvent.registerNativeEnabledObserver();
+
+        // From this point on, native code is ready to use and checkIsReady()
+        // shouldn't complain from now on (and in fact, it's used by the
+        // following calls).
+        // Note that this flag can be accessed asynchronously, so any initialization
+        // must be performed before.
+        mInitialized = true;
+    }
+
+    // Called after all native initializations are complete.
+    public void onNativeInitializationComplete(Context context) {
+        recordBrowserProcessHistogram(context);
+    }
+
+    // Record Chromium linker histogram state for the main browser process. Called from
+    // onNativeInitializationComplete().
+    private void recordBrowserProcessHistogram(Context context) {
+        if (Linker.isUsed()) {
+            nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros,
+                                                              mLoadAtFixedAddressFailed,
+                                                              getLibraryLoadFromApkStatus(context));
+        }
+    }
+
+    // Returns the device's status for loading a library directly from the APK file.
+    // This method can only be called when the Chromium linker is used.
+    private int getLibraryLoadFromApkStatus(Context context) {
+        assert Linker.isUsed();
+
+        if (mLibraryWasLoadedFromApk) {
+            return mMapApkWithExecPermission
+                    ? LibraryLoadFromApkStatusCodes.SUCCESSFUL
+                    : LibraryLoadFromApkStatusCodes.USED_NO_MAP_EXEC_SUPPORT_FALLBACK;
+        }
+
+        if (!mLibraryIsMappableInApk) {
+            return LibraryLoadFromApkStatusCodes.USED_UNPACK_LIBRARY_FALLBACK;
+        }
+
+        if (context == null) {
+            Log.w(TAG, "Unknown APK filename due to null context");
+            return LibraryLoadFromApkStatusCodes.UNKNOWN;
+        }
+
+        if (!mProbeMapApkWithExecPermission) {
+            return LibraryLoadFromApkStatusCodes.UNKNOWN;
+        }
+
+        return mMapApkWithExecPermission
+                ? LibraryLoadFromApkStatusCodes.SUPPORTED
+                : LibraryLoadFromApkStatusCodes.NOT_SUPPORTED;
+    }
+
+    // Register pending Chromium linker histogram state for renderer processes. This cannot be
+    // recorded as a histogram immediately because histograms and IPC are not ready at the
+    // time it are captured. This function stores a pending value, so that a later call to
+    // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly.
+    public void registerRendererProcessHistogram(boolean requestedSharedRelro,
+                                                 boolean loadAtFixedAddressFailed) {
+        if (Linker.isUsed()) {
+            nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedSharedRelro,
+                                                                 loadAtFixedAddressFailed);
+        }
+    }
+
+    /**
+     * @return the process the shared library is loaded in, see the LibraryProcessType
+     *         for possible values.
+     */
+    @CalledByNative
+    public static int getLibraryProcessType() {
+        if (sInstance == null) return LibraryProcessType.PROCESS_UNINITIALIZED;
+        return sInstance.mLibraryProcessType;
+    }
+
+    private native void nativeInitCommandLine(String[] initCommandLine);
+
+    // Only methods needed before or during normal JNI registration are during System.OnLoad.
+    // nativeLibraryLoaded is then called to register everything else.  This process is called
+    // "initialization".  This method will be mapped (by generated code) to the LibraryLoaded
+    // definition in base/android/library_loader/library_loader_hooks.cc.
+    //
+    // Return true on success and false on failure.
+    private native boolean nativeLibraryLoaded();
+
+    // Method called to record statistics about the Chromium linker operation for the main
+    // browser process. Indicates whether the linker attempted relro sharing for the browser,
+    // and if it did, whether the library failed to load at a fixed address. Also records
+    // support for loading a library directly from the APK file.
+    private native void nativeRecordChromiumAndroidLinkerBrowserHistogram(
+            boolean isUsingBrowserSharedRelros,
+            boolean loadAtFixedAddressFailed,
+            int libraryLoadFromApkStatus);
+
+    // Method called to register (for later recording) statistics about the Chromium linker
+    // operation for a renderer process. Indicates whether the linker attempted relro sharing,
+    // and if it did, whether the library failed to load at a fixed address.
+    private native void nativeRegisterChromiumAndroidLinkerRendererHistogram(
+            boolean requestedSharedRelro,
+            boolean loadAtFixedAddressFailed);
+
+    // Get the version of the native library. This is needed so that we can check we
+    // have the right version before initializing the (rest of the) JNI.
+    private native String nativeGetVersionNumber();
+
+    // Finds the ranges corresponding to the native library pages, forks a new
+    // process to prefetch these pages and waits for it. The new process then
+    // terminates. This is blocking.
+    private static native boolean nativeForkAndPrefetchNativeLibrary();
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
new file mode 100644
index 0000000..7dd1a29
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
@@ -0,0 +1,338 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+package org.chromium.base.library_loader;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Class representing an exception which occured during the unpacking process.
+ */
+class UnpackingException extends Exception {
+    public UnpackingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public UnpackingException(String message) {
+        super(message);
+    }
+}
+
+/**
+ * The class provides helper functions to extract native libraries from APK,
+ * and load libraries from there.
+ */
+class LibraryLoaderHelper {
+    private static final String TAG = "LibraryLoaderHelper";
+
+    // Fallback directories.
+    static final String LOAD_FROM_APK_FALLBACK_DIR = "fallback";
+
+    private static final int BUFFER_SIZE = 16384;
+
+    /**
+     * Returns the directory for holding extracted native libraries.
+     * It may create the directory if it doesn't exist.
+     *
+     * @param context The context the code is running.
+     * @param dirName The name of the directory containing the libraries.
+     * @return The directory file object.
+     */
+    static File getLibDir(Context context, String dirName) {
+        return context.getDir(dirName, Context.MODE_PRIVATE);
+    }
+
+    /**
+     * Delete libraries and their directory synchronously.
+     */
+    private static void deleteLibrariesSynchronously(Context context, String dirName) {
+        File libDir = getLibDir(context, dirName);
+        deleteObsoleteLibraries(libDir, Collections.<File>emptyList());
+    }
+
+    /**
+     * Delete libraries and their directory asynchronously.
+     * The actual deletion is done in a background thread.
+     */
+    static void deleteLibrariesAsynchronously(
+            final Context context, final String dirName) {
+        // Child process should not reach here.
+        new Thread() {
+            @Override
+            public void run() {
+                deleteLibrariesSynchronously(context, dirName);
+            }
+        }.start();
+    }
+
+    /**
+     * Copy a library from a zip file to the application's private directory.
+     * This is used as a fallback when we are unable to load the library
+     * directly from the APK file (crbug.com/390618).
+     *
+     * @param context The context the code is running in.
+     * @param library Library name.
+     * @return name of the fallback copy of the library.
+     */
+    static String buildFallbackLibrary(Context context, String library) {
+        try {
+            String libName = System.mapLibraryName(library);
+            File fallbackLibDir = getLibDir(context, LOAD_FROM_APK_FALLBACK_DIR);
+            File fallbackLibFile = new File(fallbackLibDir, libName);
+            String pathInZipFile = Linker.getLibraryFilePathInZipFile(libName);
+            Map<String, File> dstFiles = Collections.singletonMap(pathInZipFile, fallbackLibFile);
+
+            deleteObsoleteLibraries(fallbackLibDir, dstFiles.values());
+            unpackLibraries(context, dstFiles);
+
+            return fallbackLibFile.getAbsolutePath();
+        } catch (Exception e) {
+            String errorMessage = "Unable to load fallback for library " + library
+                    + " (" + (e.getMessage() == null ? e.toString() : e.getMessage()) + ")";
+            Log.e(TAG, errorMessage, e);
+            throw new UnsatisfiedLinkError(errorMessage);
+        }
+    }
+
+    // Delete obsolete libraries from a library folder.
+    private static void deleteObsoleteLibraries(File libDir, Collection<File> keptFiles) {
+        try {
+            // Build a list of libraries that should NOT be deleted.
+            Set<String> keptFileNames = new HashSet<String>();
+            for (File k : keptFiles) {
+                keptFileNames.add(k.getName());
+            }
+
+            // Delete the obsolete libraries.
+            Log.i(TAG, "Deleting obsolete libraries in " + libDir.getPath());
+            File[] files = libDir.listFiles();
+            if (files != null) {
+                for (File f : files) {
+                    if (!keptFileNames.contains(f.getName())) {
+                        delete(f);
+                    }
+                }
+            } else {
+                Log.e(TAG, "Failed to list files in " + libDir.getPath());
+            }
+
+            // Delete the folder if no libraries were kept.
+            if (keptFileNames.isEmpty()) {
+                delete(libDir);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to remove obsolete libraries from " + libDir.getPath());
+        }
+    }
+
+    // Unpack libraries from a zip file to the file system.
+    private static void unpackLibraries(Context context,
+            Map<String, File> dstFiles) throws UnpackingException {
+        String zipFilePath = context.getApplicationInfo().sourceDir;
+        Log.i(TAG, "Opening zip file " + zipFilePath);
+        File zipFile = new File(zipFilePath);
+        ZipFile zipArchive = openZipFile(zipFile);
+
+        try {
+            for (Entry<String, File> d : dstFiles.entrySet()) {
+                String pathInZipFile = d.getKey();
+                File dstFile = d.getValue();
+                Log.i(TAG, "Unpacking " + pathInZipFile
+                        + " to " + dstFile.getAbsolutePath());
+                ZipEntry packedLib = zipArchive.getEntry(pathInZipFile);
+
+                if (needToUnpackLibrary(zipFile, packedLib, dstFile)) {
+                    unpackLibraryFromZipFile(zipArchive, packedLib, dstFile);
+                    setLibraryFilePermissions(dstFile);
+                }
+            }
+        } finally {
+            closeZipFile(zipArchive);
+        }
+    }
+
+    // Open a zip file.
+    private static ZipFile openZipFile(File zipFile) throws UnpackingException {
+        try {
+            return new ZipFile(zipFile);
+        } catch (ZipException e) {
+            throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
+        } catch (IOException e) {
+            throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
+        }
+    }
+
+    // Determine whether it is necessary to unpack a library from a zip file.
+    private static boolean needToUnpackLibrary(
+            File zipFile, ZipEntry packedLib, File dstFile) {
+        // Check if the fallback library already exists.
+        if (!dstFile.exists()) {
+            Log.i(TAG, "File " + dstFile.getPath() + " does not exist yet");
+            return true;
+        }
+
+        // Check last modification dates.
+        long zipTime = zipFile.lastModified();
+        long fallbackLibTime = dstFile.lastModified();
+        if (zipTime > fallbackLibTime) {
+            Log.i(TAG, "Not using existing fallback file because "
+                    + "the APK file " + zipFile.getPath()
+                    + " (timestamp=" + zipTime + ") is newer than "
+                    + "the fallback library " + dstFile.getPath()
+                    + "(timestamp=" + fallbackLibTime + ")");
+            return true;
+        }
+
+        // Check file sizes.
+        long packedLibSize = packedLib.getSize();
+        long fallbackLibSize = dstFile.length();
+        if (fallbackLibSize != packedLibSize) {
+            Log.i(TAG, "Not using existing fallback file because "
+                    + "the library in the APK " + zipFile.getPath()
+                    + " (" + packedLibSize + "B) has a different size than "
+                    + "the fallback library " + dstFile.getPath()
+                    + "(" + fallbackLibSize + "B)");
+            return true;
+        }
+
+        Log.i(TAG, "Reusing existing file " + dstFile.getPath());
+        return false;
+    }
+
+    // Unpack a library from a zip file to the filesystem.
+    private static void unpackLibraryFromZipFile(ZipFile zipArchive, ZipEntry packedLib,
+            File dstFile) throws UnpackingException {
+        // Open input stream for the library file inside the zip file.
+        InputStream in;
+        try {
+            in = zipArchive.getInputStream(packedLib);
+        } catch (IOException e) {
+            throw new UnpackingException(
+                    "IO exception when locating library in the zip file", e);
+        }
+
+        // Ensure that the input stream is closed at the end.
+        try {
+            // Delete existing file if it exists.
+            if (dstFile.exists()) {
+                Log.i(TAG, "Deleting existing unpacked library file " + dstFile.getPath());
+                if (!dstFile.delete()) {
+                    throw new UnpackingException(
+                            "Failed to delete existing unpacked library file " + dstFile.getPath());
+                }
+            }
+
+            // Ensure that the library folder exists. Since this is added
+            // for increased robustness, we log errors and carry on.
+            try {
+                dstFile.getParentFile().mkdirs();
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to make library folder", e);
+            }
+
+            // Create the destination file.
+            try {
+                if (!dstFile.createNewFile()) {
+                    throw new UnpackingException("existing unpacked library file was not deleted");
+                }
+            } catch (IOException e) {
+                throw new UnpackingException("failed to create unpacked library file", e);
+            }
+
+            // Open the output stream for the destination file.
+            OutputStream out;
+            try {
+                out = new BufferedOutputStream(new FileOutputStream(dstFile));
+            } catch (FileNotFoundException e) {
+                throw new UnpackingException(
+                        "failed to open output stream for unpacked library file", e);
+            }
+
+            // Ensure that the output stream is closed at the end.
+            try {
+                // Copy the library from the zip file to the destination file.
+                Log.i(TAG, "Copying " + packedLib.getName() + " from " + zipArchive.getName()
+                        + " to " + dstFile.getPath());
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int len;
+                while ((len = in.read(buffer)) != -1) {
+                    out.write(buffer, 0, len);
+                }
+            } catch (IOException e) {
+                throw new UnpackingException(
+                        "failed to copy the library from the zip file", e);
+            } finally {
+                close(out, "output stream");
+            }
+        } finally {
+            close(in, "input stream");
+        }
+    }
+
+    // Set up library file permissions.
+    private static void setLibraryFilePermissions(File libFile) {
+        // Change permission to rwxr-xr-x
+        Log.i(TAG, "Setting file permissions for " + libFile.getPath());
+        if (!libFile.setReadable(/* readable */ true, /* ownerOnly */ false)) {
+            Log.e(TAG, "failed to chmod a+r the temporary file");
+        }
+        if (!libFile.setExecutable(/* executable */ true, /* ownerOnly */ false)) {
+            Log.e(TAG, "failed to chmod a+x the temporary file");
+        }
+        if (!libFile.setWritable(/* writable */ true)) {
+            Log.e(TAG, "failed to chmod +w the temporary file");
+        }
+    }
+
+    // Close a closable and log a warning if it fails.
+    private static void close(Closeable closeable, String name) {
+        try {
+            closeable.close();
+        } catch (IOException e) {
+            // Warn and ignore.
+            Log.w(TAG, "IO exception when closing " + name, e);
+        }
+    }
+
+    // Close a zip file and log a warning if it fails.
+    // This needs to be a separate method because ZipFile is not Closeable in
+    // Java 6 (used on some older devices).
+    private static void closeZipFile(ZipFile file) {
+        try {
+            file.close();
+        } catch (IOException e) {
+            // Warn and ignore.
+            Log.w(TAG, "IO exception when closing zip file", e);
+        }
+    }
+
+    // Delete a file and log it.
+    private static void delete(File file) {
+        if (file.delete()) {
+            Log.i(TAG, "Deleted " + file.getPath());
+        } else {
+            Log.w(TAG, "Failed to delete " + file.getPath());
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
new file mode 100644
index 0000000..7e50998
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -0,0 +1,1143 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.SysUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.AccessedByNative;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/*
+ * Technical note:
+ *
+ * The point of this class is to provide an alternative to System.loadLibrary()
+ * to load native shared libraries. One specific feature that it supports is the
+ * ability to save RAM by sharing the ELF RELRO sections between renderer
+ * processes.
+ *
+ * When two processes load the same native library at the _same_ memory address,
+ * the content of their RELRO section (which includes C++ vtables or any
+ * constants that contain pointers) will be largely identical [1].
+ *
+ * By default, the RELRO section is backed by private RAM in each process,
+ * which is still significant on mobile (e.g. 1.28 MB / process on Chrome 30 for
+ * Android).
+ *
+ * However, it is possible to save RAM by creating a shared memory region,
+ * copy the RELRO content into it, then have each process swap its private,
+ * regular RELRO, with a shared, read-only, mapping of the shared one.
+ *
+ * This trick saves 98% of the RELRO section size per extra process, after the
+ * first one. On the other hand, this requires careful communication between
+ * the process where the shared RELRO is created and the one(s) where it is used.
+ *
+ * Note that swapping the regular RELRO with the shared one is not an atomic
+ * operation. Care must be taken that no other thread tries to run native code
+ * that accesses it during it. In practice, this means the swap must happen
+ * before library native code is executed.
+ *
+ * [1] The exceptions are pointers to external, randomized, symbols, like
+ * those from some system libraries, but these are very few in practice.
+ */
+
+/*
+ * Security considerations:
+ *
+ * - Whether the browser process loads its native libraries at the same
+ *   addresses as the service ones (to save RAM by sharing the RELRO too)
+ *   depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG below.
+ *
+ *   Not using fixed library addresses in the browser process is preferred
+ *   for regular devices since it maintains the efficacy of ASLR as an
+ *   exploit mitigation across the render <-> browser privilege boundary.
+ *
+ * - The shared RELRO memory region is always forced read-only after creation,
+ *   which means it is impossible for a compromised service process to map
+ *   it read-write (e.g. by calling mmap() or mprotect()) and modify its
+ *   content, altering values seen in other service processes.
+ *
+ * - Unfortunately, certain Android systems use an old, buggy kernel, that
+ *   doesn't check Ashmem region permissions correctly. See CVE-2011-1149
+ *   for details. This linker probes the system on startup and will completely
+ *   disable shared RELROs if it detects the problem. For the record, this is
+ *   common for Android emulator system images (which are still based on 2.6.29)
+ *
+ * - Once the RELRO ashmem region is mapped into a service process' address
+ *   space, the corresponding file descriptor is immediately closed. The
+ *   file descriptor is kept opened in the browser process, because a copy needs
+ *   to be sent to each new potential service process.
+ *
+ * - The common library load addresses are randomized for each instance of
+ *   the program on the device. See computeRandomBaseLoadAddress() for more
+ *   details on how this is computed.
+ *
+ * - When loading several libraries in service processes, a simple incremental
+ *   approach from the original random base load address is used. This is
+ *   sufficient to deal correctly with component builds (which can use dozens
+ *   of shared libraries), while regular builds always embed a single shared
+ *   library per APK.
+ */
+
+/**
+ * Here's an explanation of how this class is supposed to be used:
+ *
+ *  - Native shared libraries should be loaded with Linker.loadLibrary(),
+ *    instead of System.loadLibrary(). The two functions take the same parameter
+ *    and should behave the same (at a high level).
+ *
+ *  - Before loading any library, prepareLibraryLoad() should be called.
+ *
+ *  - After loading all libraries, finishLibraryLoad() should be called, before
+ *    running any native code from any of the libraries (except their static
+ *    constructors, which can't be avoided).
+ *
+ *  - A service process shall call either initServiceProcess() or
+ *    disableSharedRelros() early (i.e. before any loadLibrary() call).
+ *    Otherwise, the linker considers that it is running inside the browser
+ *    process. This is because various Chromium projects have vastly
+ *    different initialization paths.
+ *
+ *    disableSharedRelros() completely disables shared RELROs, and loadLibrary()
+ *    will behave exactly like System.loadLibrary().
+ *
+ *    initServiceProcess(baseLoadAddress) indicates that shared RELROs are to be
+ *    used in this process.
+ *
+ *  - The browser is in charge of deciding where in memory each library should
+ *    be loaded. This address must be passed to each service process (see
+ *    ChromiumLinkerParams.java in content for a helper class to do so).
+ *
+ *  - The browser will also generate shared RELROs for each library it loads.
+ *    More specifically, by default when in the browser process, the linker
+ *    will:
+ *
+ *       - Load libraries randomly (just like System.loadLibrary()).
+ *       - Compute the fixed address to be used to load the same library
+ *         in service processes.
+ *       - Create a shared memory region populated with the RELRO region
+ *         content pre-relocated for the specific fixed address above.
+ *
+ *    Note that these shared RELRO regions cannot be used inside the browser
+ *    process. They are also never mapped into it.
+ *
+ *    This behaviour is altered by the BROWSER_SHARED_RELRO_CONFIG configuration
+ *    variable below, which may force the browser to load the libraries at
+ *    fixed addresses too.
+ *
+ *  - Once all libraries are loaded in the browser process, one can call
+ *    getSharedRelros() which returns a Bundle instance containing a map that
+ *    links each loaded library to its shared RELRO region.
+ *
+ *    This Bundle must be passed to each service process, for example through
+ *    a Binder call (note that the Bundle includes file descriptors and cannot
+ *    be added as an Intent extra).
+ *
+ *  - In a service process, finishLibraryLoad() will block until the RELRO
+ *    section Bundle is received. This is typically done by calling
+ *    useSharedRelros() from another thread.
+ *
+ *    This method also ensures the process uses the shared RELROs.
+ */
+public class Linker {
+
+    // Log tag for this class. This must match the name of the linker's native library.
+    private static final String TAG = "chromium_android_linker";
+
+    // Set to true to enable debug logs.
+    private static final boolean DEBUG = false;
+
+    // Constants used to control the behaviour of the browser process with
+    // regards to the shared RELRO section.
+    //   NEVER        -> The browser never uses it itself.
+    //   LOW_RAM_ONLY -> It is only used on devices with low RAM.
+    //   ALWAYS       -> It is always used.
+    // NOTE: These names are known and expected by the Linker test scripts.
+    public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0;
+    public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1;
+    public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2;
+
+    // Configuration variable used to control how the browser process uses the
+    // shared RELRO. Only change this while debugging linker-related issues.
+    // NOTE: This variable's name is known and expected by the Linker test scripts.
+    public static final int BROWSER_SHARED_RELRO_CONFIG =
+            BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY;
+
+    // Constants used to control the value of sMemoryDeviceConfig.
+    //   INIT         -> Value is undetermined (will check at runtime).
+    //   LOW          -> This is a low-memory device.
+    //   NORMAL       -> This is not a low-memory device.
+    public static final int MEMORY_DEVICE_CONFIG_INIT = 0;
+    public static final int MEMORY_DEVICE_CONFIG_LOW = 1;
+    public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2;
+
+    // Indicates if this is a low-memory device or not. The default is to
+    // determine this by probing the system at runtime, but this can be forced
+    // for testing by calling setMemoryDeviceConfig().
+    private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
+
+    // Becomes true after linker initialization.
+    private static boolean sInitialized = false;
+
+    // Set to true to indicate that the system supports safe sharing of RELRO sections.
+    private static boolean sRelroSharingSupported = false;
+
+    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
+    // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in
+    // the browser process) on low-memory devices.
+    private static boolean sInBrowserProcess = true;
+
+    // Becomes true to indicate this process needs to wait for a shared RELRO in
+    // finishLibraryLoad().
+    private static boolean sWaitForSharedRelros = false;
+
+    // Becomes true when initialization determines that the browser process can use the
+    // shared RELRO.
+    private static boolean sBrowserUsesSharedRelro = false;
+
+    // The map of all RELRO sections either created or used in this process.
+    private static Bundle sSharedRelros = null;
+
+    // Current common random base load address.
+    private static long sBaseLoadAddress = 0;
+
+    // Current fixed-location load address for the next library called by loadLibrary().
+    private static long sCurrentLoadAddress = 0;
+
+    // Becomes true once prepareLibraryLoad() has been called.
+    private static boolean sPrepareLibraryLoadCalled = false;
+
+    // Used internally to initialize the linker's static data. Assume lock is held.
+    private static void ensureInitializedLocked() {
+        assert Thread.holdsLock(Linker.class);
+
+        if (!sInitialized) {
+            sRelroSharingSupported = false;
+            if (NativeLibraries.sUseLinker) {
+                if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so");
+                try {
+                    System.loadLibrary(TAG);
+                } catch (UnsatisfiedLinkError  e) {
+                    // In a component build, the ".cr" suffix is added to each library name.
+                    Log.w(TAG, "Couldn't load lib" + TAG + ".so, trying lib" + TAG + ".cr.so");
+                    System.loadLibrary(TAG + ".cr");
+                }
+                sRelroSharingSupported = nativeCanUseSharedRelro();
+                if (!sRelroSharingSupported) {
+                    Log.w(TAG, "This system cannot safely share RELRO sections");
+                } else {
+                    if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
+                }
+
+                if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
+                    sMemoryDeviceConfig = SysUtils.isLowEndDevice()
+                            ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
+                }
+
+                switch (BROWSER_SHARED_RELRO_CONFIG) {
+                    case BROWSER_SHARED_RELRO_CONFIG_NEVER:
+                        sBrowserUsesSharedRelro = false;
+                        break;
+                    case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
+                        sBrowserUsesSharedRelro =
+                                (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW);
+                        if (sBrowserUsesSharedRelro) {
+                            Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
+                        }
+                        break;
+                    case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
+                        Log.w(TAG, "Beware: shared RELROs used in all processes!");
+                        sBrowserUsesSharedRelro = true;
+                        break;
+                    default:
+                        assert false : "Unreached";
+                        break;
+                }
+            } else {
+                if (DEBUG) Log.i(TAG, "Linker disabled");
+            }
+
+            if (!sRelroSharingSupported) {
+                // Sanity.
+                sBrowserUsesSharedRelro = false;
+                sWaitForSharedRelros = false;
+            }
+
+            sInitialized = true;
+        }
+    }
+
+    /**
+     * A public interface used to run runtime linker tests after loading
+     * libraries. Should only be used to implement the linker unit tests,
+     * which is controlled by the value of NativeLibraries.sEnableLinkerTests
+     * configured at build time.
+     */
+    public interface TestRunner {
+        /**
+         * Run runtime checks and return true if they all pass.
+         * @param memoryDeviceConfig The current memory device configuration.
+         * @param inBrowserProcess true iff this is the browser process.
+         */
+        public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProcess);
+    }
+
+    // The name of a class that implements TestRunner.
+    static String sTestRunnerClassName = null;
+
+    /**
+     * Set the TestRunner by its class name. It will be instantiated at
+     * runtime after all libraries are loaded.
+     * @param testRunnerClassName null or a String for the class name of the
+     * TestRunner to use.
+     */
+    public static void setTestRunnerClassName(String testRunnerClassName) {
+        if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
+
+        if (!NativeLibraries.sEnableLinkerTests) {
+            // Ignore this in production code to prevent malvolent runtime injection.
+            return;
+        }
+
+        synchronized (Linker.class) {
+            assert sTestRunnerClassName == null;
+            sTestRunnerClassName = testRunnerClassName;
+        }
+    }
+
+    /**
+     * Call this to retrieve the name of the current TestRunner class name
+     * if any. This can be useful to pass it from the browser process to
+     * child ones.
+     * @return null or a String holding the name of the class implementing
+     * the TestRunner set by calling setTestRunnerClassName() previously.
+     */
+    public static String getTestRunnerClassName() {
+        synchronized (Linker.class) {
+            return sTestRunnerClassName;
+        }
+    }
+
+    /**
+     * Call this method before any other Linker method to force a specific
+     * memory device configuration. Should only be used for testing.
+     * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
+     */
+    public static void setMemoryDeviceConfig(int memoryDeviceConfig) {
+        if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
+        // Sanity check. This method should only be called during tests.
+        assert NativeLibraries.sEnableLinkerTests;
+        synchronized (Linker.class) {
+            assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
+            assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
+                   || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
+            if (DEBUG) {
+                if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
+                    Log.i(TAG, "Simulating a low-memory device");
+                } else {
+                    Log.i(TAG, "Simulating a regular-memory device");
+                }
+            }
+            sMemoryDeviceConfig = memoryDeviceConfig;
+        }
+    }
+
+    /**
+     * Call this method to determine if this chromium project must
+     * use this linker. If not, System.loadLibrary() should be used to load
+     * libraries instead.
+     */
+    public static boolean isUsed() {
+        // Only GYP targets that are APKs and have the 'use_chromium_linker' variable
+        // defined as 1 will use this linker. For all others (the default), the
+        // auto-generated NativeLibraries.sUseLinker variable will be false.
+        if (!NativeLibraries.sUseLinker) return false;
+
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            // At the moment, there is also no point in using this linker if the
+            // system does not support RELRO sharing safely.
+            return sRelroSharingSupported;
+        }
+    }
+
+    /**
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    public static boolean isUsingBrowserSharedRelros() {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            return sBrowserUsesSharedRelro;
+        }
+    }
+
+    /**
+     * Call this method to determine if the chromium project must load
+     * the library directly from the zip file.
+     */
+    public static boolean isInZipFile() {
+        return NativeLibraries.sUseLibraryInZipFile;
+    }
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     */
+    public static void prepareLibraryLoad() {
+        if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
+        synchronized (Linker.class) {
+            sPrepareLibraryLoadCalled = true;
+
+            if (sInBrowserProcess) {
+                // Force generation of random base load address, as well
+                // as creation of shared RELRO sections in this process.
+                setupBaseLoadAddressLocked();
+            }
+        }
+    }
+
+    /**
+     * Call this method just after loading all native shared libraries in this process.
+     * Note that when in a service process, this will block until the RELRO bundle is
+     * received, i.e. when another thread calls useSharedRelros().
+     */
+    public static void finishLibraryLoad() {
+        if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
+        synchronized (Linker.class) {
+            if (DEBUG) Log.i(TAG, String.format(
+                    Locale.US,
+                    "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSharedRelros=%s",
+                    sInBrowserProcess ? "true" : "false",
+                    sBrowserUsesSharedRelro ? "true" : "false",
+                    sWaitForSharedRelros ? "true" : "false"));
+
+            if (sLoadedLibraries == null) {
+                if (DEBUG) Log.i(TAG, "No libraries loaded");
+            } else {
+                if (sInBrowserProcess) {
+                    // Create new Bundle containing RELRO section information
+                    // for all loaded libraries. Make it available to getSharedRelros().
+                    sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries);
+                    if (DEBUG) {
+                        Log.i(TAG, "Shared RELRO created");
+                        dumpBundle(sSharedRelros);
+                    }
+
+                    if (sBrowserUsesSharedRelro) {
+                        useSharedRelrosLocked(sSharedRelros);
+                    }
+                }
+
+                if (sWaitForSharedRelros) {
+                    assert !sInBrowserProcess;
+
+                    // Wait until the shared relro bundle is received from useSharedRelros().
+                    while (sSharedRelros == null) {
+                        try {
+                            Linker.class.wait();
+                        } catch (InterruptedException ie) {
+                            // no-op
+                        }
+                    }
+                    useSharedRelrosLocked(sSharedRelros);
+                    // Clear the Bundle to ensure its file descriptor references can't be reused.
+                    sSharedRelros.clear();
+                    sSharedRelros = null;
+                }
+            }
+
+            if (NativeLibraries.sEnableLinkerTests && sTestRunnerClassName != null) {
+                // The TestRunner implementation must be instantiated _after_
+                // all libraries are loaded to ensure that its native methods
+                // are properly registered.
+                if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName);
+                TestRunner testRunner = null;
+                try {
+                    testRunner = (TestRunner)
+                            Class.forName(sTestRunnerClassName).newInstance();
+                } catch (Exception e) {
+                    Log.e(TAG, "Could not extract test runner class name", e);
+                    testRunner = null;
+                }
+                if (testRunner != null) {
+                    if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserProcess)) {
+                        Log.wtf(TAG, "Linker runtime tests failed in this process!!");
+                        assert false;
+                    } else {
+                        Log.i(TAG, "All linker tests passed!");
+                    }
+                }
+            }
+        }
+        if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
+    }
+
+    /**
+     * Call this to send a Bundle containing the shared RELRO sections to be
+     * used in this process. If initServiceProcess() was previously called,
+     * finishLibraryLoad() will not exit until this method is called in another
+     * thread with a non-null value.
+     * @param bundle The Bundle instance containing a map of shared RELRO sections
+     * to use in this process.
+     */
+    public static void useSharedRelros(Bundle bundle) {
+        // Ensure the bundle uses the application's class loader, not the framework
+        // one which doesn't know anything about LibInfo.
+        // Also, hold a fresh copy of it so the caller can't recycle it.
+        Bundle clonedBundle = null;
+        if (bundle != null) {
+            bundle.setClassLoader(LibInfo.class.getClassLoader());
+            clonedBundle = new Bundle(LibInfo.class.getClassLoader());
+            Parcel parcel = Parcel.obtain();
+            bundle.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            clonedBundle.readFromParcel(parcel);
+            parcel.recycle();
+        }
+        if (DEBUG) {
+            Log.i(TAG, "useSharedRelros() called with " + bundle
+                    + ", cloned " + clonedBundle);
+        }
+        synchronized (Linker.class) {
+            // Note that in certain cases, this can be called before
+            // initServiceProcess() in service processes.
+            sSharedRelros = clonedBundle;
+            // Tell any listener blocked in finishLibraryLoad() about it.
+            Linker.class.notifyAll();
+        }
+    }
+
+    /**
+     * Call this to retrieve the shared RELRO sections created in this process,
+     * after loading all libraries.
+     * @return a new Bundle instance, or null if RELRO sharing is disabled on
+     * this system, or if initServiceProcess() was called previously.
+     */
+    public static Bundle getSharedRelros() {
+        if (DEBUG) Log.i(TAG, "getSharedRelros() called");
+        synchronized (Linker.class) {
+            if (!sInBrowserProcess) {
+                if (DEBUG) Log.i(TAG, "... returning null Bundle");
+                return null;
+            }
+
+            // Return the Bundle created in finishLibraryLoad().
+            if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
+            return sSharedRelros;
+        }
+    }
+
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    public static void disableSharedRelros() {
+        if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
+        synchronized (Linker.class) {
+            sInBrowserProcess = false;
+            sWaitForSharedRelros = false;
+            sBrowserUsesSharedRelro = false;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process is ready to reuse shared RELRO sections from another one.
+     * Typically used when starting service processes.
+     * @param baseLoadAddress the base library load address to use.
+     */
+    public static void initServiceProcess(long baseLoadAddress) {
+        if (DEBUG) {
+            Log.i(TAG, String.format(
+                    Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
+        }
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            sInBrowserProcess = false;
+            sBrowserUsesSharedRelro = false;
+            if (sRelroSharingSupported) {
+                sWaitForSharedRelros = true;
+                sBaseLoadAddress = baseLoadAddress;
+                sCurrentLoadAddress = baseLoadAddress;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the base load address of all shared RELRO sections.
+     * This also enforces the creation of shared RELRO sections in
+     * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
+     * @return a common, random base load address, or 0 if RELRO sharing is
+     * disabled.
+     */
+    public static long getBaseLoadAddress() {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            if (!sInBrowserProcess) {
+                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
+                return 0;
+            }
+
+            setupBaseLoadAddressLocked();
+            if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
+                                                sBaseLoadAddress));
+            return sBaseLoadAddress;
+        }
+    }
+
+    // Used internally to lazily setup the common random base load address.
+    private static void setupBaseLoadAddressLocked() {
+        assert Thread.holdsLock(Linker.class);
+        if (sBaseLoadAddress == 0) {
+            long address = computeRandomBaseLoadAddress();
+            sBaseLoadAddress = address;
+            sCurrentLoadAddress = address;
+            if (address == 0) {
+                // If the computed address is 0, there are issues with finding enough
+                // free address space, so disable RELRO shared / fixed load addresses.
+                Log.w(TAG, "Disabling shared RELROs due address space pressure");
+                sBrowserUsesSharedRelro = false;
+                sWaitForSharedRelros = false;
+            }
+        }
+    }
+
+
+    /**
+     * Compute a random base load address at which to place loaded libraries.
+     * @return new base load address, or 0 if the system does not support
+     * RELRO sharing.
+     */
+    private static long computeRandomBaseLoadAddress() {
+        // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
+        // successfully mapped an area of the given size, on the basis that we will be
+        // able, with high probability, to map our library into it.
+        //
+        // One issue with this is that we do not yet know the size of the library that
+        // we will load is. So here we pass a value that we expect will always be larger
+        // than that needed. If it is smaller the library mapping may still succeed. The
+        // other issue is that although highly unlikely, there is no guarantee that
+        // something else does not map into the area we are going to use between here and
+        // when we try to map into it.
+        //
+        // The above notes mean that all of this is probablistic. It is however okay to do
+        // because if, worst case and unlikely, we get unlucky in our choice of address,
+        // the back-out and retry without the shared RELRO in the ChildProcessService will
+        // keep things running.
+        final long maxExpectedBytes = 192 * 1024 * 1024;
+        final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes);
+        if (DEBUG) {
+            Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address));
+        }
+        return address;
+    }
+
+    // Used for debugging only.
+    private static void dumpBundle(Bundle bundle) {
+        if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
+    }
+
+    /**
+     * Use the shared RELRO section from a Bundle received form another process.
+     * Call this after calling setBaseLoadAddress() then loading all libraries
+     * with loadLibrary().
+     * @param bundle Bundle instance generated with createSharedRelroBundle() in
+     * another process.
+     */
+    private static void useSharedRelrosLocked(Bundle bundle) {
+        assert Thread.holdsLock(Linker.class);
+
+        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
+
+        if (bundle == null) {
+            if (DEBUG) Log.i(TAG, "null bundle!");
+            return;
+        }
+
+        if (!sRelroSharingSupported) {
+            if (DEBUG) Log.i(TAG, "System does not support RELRO sharing");
+            return;
+        }
+
+        if (sLoadedLibraries == null) {
+            if (DEBUG) Log.i(TAG, "No libraries loaded!");
+            return;
+        }
+
+        if (DEBUG) dumpBundle(bundle);
+        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
+
+        // Apply the RELRO section to all libraries that were already loaded.
+        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
+            String libName = entry.getKey();
+            LibInfo libInfo = entry.getValue();
+            if (!nativeUseSharedRelro(libName, libInfo)) {
+                Log.w(TAG, "Could not use shared RELRO section for " + libName);
+            } else {
+                if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libName);
+            }
+        }
+
+        // In service processes, close all file descriptors from the map now.
+        if (!sInBrowserProcess) closeLibInfoMap(relroMap);
+
+        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
+    }
+
+    /**
+     * Load a native shared library with the Chromium linker. If the zip file
+     * is not null, the shared library must be uncompressed and page aligned
+     * inside the zipfile. Note the crazy linker treats libraries and files as
+     * equivalent, so you can only open one library in a given zip file. The
+     * library must not be the Chromium linker library.
+     *
+     * @param zipFilePath The path of the zip file containing the library (or null).
+     * @param libFilePath The path of the library (possibly in the zip file).
+     */
+    public static void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
+        if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
+
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            // Security: Ensure prepareLibraryLoad() was called before.
+            // In theory, this can be done lazily here, but it's more consistent
+            // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
+            // that wrap all calls to loadLibrary() in the library loader.
+            assert sPrepareLibraryLoadCalled;
+
+            if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>();
+
+            if (sLoadedLibraries.containsKey(libFilePath)) {
+                if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice");
+                return;
+            }
+
+            LibInfo libInfo = new LibInfo();
+            long loadAddress = 0;
+            if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) {
+                // Load the library at a fixed address.
+                loadAddress = sCurrentLoadAddress;
+            }
+
+            String sharedRelRoName = libFilePath;
+            if (zipFilePath != null) {
+                if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAddress, libInfo)) {
+                    String errorMessage = "Unable to load library: " + libFilePath
+                                          + ", in: " + zipFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+                sharedRelRoName = zipFilePath;
+            } else {
+                if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
+                    String errorMessage = "Unable to load library: " + libFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+            }
+
+            // Print the load address to the logcat when testing the linker. The format
+            // of the string is expected by the Python test_runner script as one of:
+            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
+            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
+            // Where <library-name> is the library name, and <address> is the hexadecimal load
+            // address.
+            if (NativeLibraries.sEnableLinkerTests) {
+                Log.i(TAG, String.format(
+                        Locale.US,
+                        "%s_LIBRARY_ADDRESS: %s %x",
+                        sInBrowserProcess ? "BROWSER" : "RENDERER",
+                        libFilePath,
+                        libInfo.mLoadAddress));
+            }
+
+            if (sInBrowserProcess) {
+                // Create a new shared RELRO section at the 'current' fixed load address.
+                if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddress, libInfo)) {
+                    Log.w(TAG, String.format(Locale.US,
+                            "Could not create shared RELRO for %s at %x", libFilePath,
+                            sCurrentLoadAddress));
+                } else {
+                    if (DEBUG) Log.i(TAG,
+                        String.format(
+                            Locale.US,
+                            "Created shared RELRO for %s at %x: %s",
+                            sharedRelRoName,
+                            sCurrentLoadAddress,
+                            libInfo.toString()));
+                }
+            }
+
+            if (sCurrentLoadAddress != 0) {
+                // Compute the next current load address. If sBaseLoadAddress
+                // is not 0, this is an explicit library load address. Otherwise,
+                // this is an explicit load address for relocated RELRO sections
+                // only.
+                sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
+            }
+
+            sLoadedLibraries.put(sharedRelRoName, libInfo);
+            if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString());
+        }
+    }
+
+    /**
+     * Enable the fallback due to lack of support for mapping the APK file with
+     * executable permission (see crbug.com/398425).
+     */
+    public static void enableNoMapExecSupportFallback() {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            if (DEBUG) Log.i(TAG, "Enabling no map executable support fallback");
+            nativeEnableNoMapExecSupportFallback();
+        }
+    }
+
+    /**
+     * Determine whether a library is the linker library. Also deal with the
+     * component build that adds a .cr suffix to the name.
+     */
+    public static boolean isChromiumLinkerLibrary(String library) {
+        return library.equals(TAG) || library.equals(TAG + ".cr");
+    }
+
+    /**
+     * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
+     *
+     * @param library The library's base name.
+     * @return the library path.
+     */
+    public static String getLibraryFilePathInZipFile(String library) throws FileNotFoundException {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            String path = nativeGetLibraryFilePathInZipFile(library);
+            if (path.equals("")) {
+                throw new FileNotFoundException(
+                        "Failed to retrieve path in zip file for library " + library);
+            }
+            return path;
+        }
+    }
+
+    /**
+     * Check whether the device supports mapping the APK file with executable permission.
+     *
+     * @param apkFile Filename of the APK.
+     * @return true if supported.
+     */
+    public static boolean checkMapExecSupport(String apkFile) {
+        assert apkFile != null;
+
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            if (DEBUG) Log.i(TAG, "checkMapExecSupport: " + apkFile);
+            boolean supported = nativeCheckMapExecSupport(apkFile);
+            if (DEBUG) Log.i(TAG, "Mapping the APK file with executable permission "
+                    + (supported ? "" : "NOT ") + "supported");
+            return supported;
+        }
+    }
+
+    /**
+     * Check whether a library is page aligned and uncompressed in the APK file.
+     *
+     * @param apkFile Filename of the APK.
+     * @param library The library's base name.
+     * @return true if page aligned and uncompressed.
+     */
+    public static boolean checkLibraryIsMappableInApk(String apkFile, String library) {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            if (DEBUG) Log.i(TAG, "checkLibraryIsMappableInApk: " + apkFile + ", " + library);
+            boolean aligned = nativeCheckLibraryIsMappableInApk(apkFile, library);
+            if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ")
+                    + "page aligned in " + apkFile);
+            return aligned;
+        }
+    }
+
+    /**
+     * Move activity from the native thread to the main UI thread.
+     * Called from native code on its own thread.  Posts a callback from
+     * the UI thread back to native code.
+     *
+     * @param opaque Opaque argument.
+     */
+    @CalledByNative
+    public static void postCallbackOnMainThread(final long opaque) {
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                nativeRunCallbackOnUiThread(opaque);
+            }
+        });
+    }
+
+    /**
+     * Native method to run callbacks on the main UI thread.
+     * Supplied by the crazy linker and called by postCallbackOnMainThread.
+     * @param opaque Opaque crazy linker arguments.
+     */
+    private static native void nativeRunCallbackOnUiThread(long opaque);
+
+    /**
+     * Native method used to load a library.
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibrary(String library,
+                                                    long loadAddress,
+                                                    LibInfo libInfo);
+
+    /**
+     * Native method used to load a library which is inside a zipfile.
+     * @param zipfileName Filename of the zip file containing the library.
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibraryInZipFile(String zipfileName,
+                                                             String libraryName,
+                                                             long loadAddress,
+                                                             LibInfo libInfo);
+
+    /**
+     * Native method used to enable the fallback due to lack of support for
+     * mapping the APK file with executable permission.
+     */
+    private static native void nativeEnableNoMapExecSupportFallback();
+
+    /**
+     * Native method used to create a shared RELRO section.
+     * If the library was already loaded at the same address using
+     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
+     * this loads a new temporary library at the specified address,
+     * creates and extracts the RELRO section from it, then unloads it.
+     * @param library Library name.
+     * @param loadAddress load address, which can be different from the one
+     * used to load the library in the current process!
+     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
+     * and mRelroFd will be set.
+     * @return true on success, false otherwise.
+     */
+    private static native boolean nativeCreateSharedRelro(String library,
+                                                          long loadAddress,
+                                                          LibInfo libInfo);
+
+    /**
+     * Native method used to use a shared RELRO section.
+     * @param library Library name.
+     * @param libInfo A LibInfo instance containing valid RELRO information
+     * @return true on success.
+     */
+    private static native boolean nativeUseSharedRelro(String library,
+                                                       LibInfo libInfo);
+
+    /**
+     * Checks that the system supports shared RELROs. Old Android kernels
+     * have a bug in the way they check Ashmem region protection flags, which
+     * makes using shared RELROs unsafe. This method performs a simple runtime
+     * check for this misfeature, even though nativeEnableSharedRelro() will
+     * always fail if this returns false.
+     */
+    private static native boolean nativeCanUseSharedRelro();
+
+    /**
+     * Return a random address that should be free to be mapped with the given size.
+     * Maps an area of size bytes, and if successful then unmaps it and returns
+     * the address of the area allocated by the system (with ASLR). The idea is
+     * that this area should remain free of other mappings until we map our library
+     * into it.
+     * @param sizeBytes Size of area in bytes to search for.
+     * @return address to pass to future mmap, or 0 on error.
+     */
+    private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
+
+    /**
+      * Native method used to get the full library path in zip file
+      * (lib/<abi>/crazy.<lib_name>).
+      *
+      * @param library The library's base name.
+      * @return the library path (or empty string on failure).
+      */
+    private static native String nativeGetLibraryFilePathInZipFile(String library);
+
+    /**
+     * Native method which checks whether the device supports mapping the APK file
+     * with executable permission.
+     *
+     * @param apkFile Filename of the APK.
+     * @return true if supported.
+     */
+    private static native boolean nativeCheckMapExecSupport(String apkFile);
+
+    /**
+     * Native method which checks whether a library is page aligned and
+     * uncompressed in the APK file.
+     *
+     * @param apkFile Filename of the APK.
+     * @param library The library's base name.
+     * @return true if page aligned and uncompressed.
+     */
+    private static native boolean nativeCheckLibraryIsMappableInApk(String apkFile, String library);
+
+    /**
+     * Record information for a given library.
+     * IMPORTANT: Native code knows about this class's fields, so
+     * don't change them without modifying the corresponding C++ sources.
+     * Also, the LibInfo instance owns the ashmem file descriptor.
+     */
+    public static class LibInfo implements Parcelable {
+
+        public LibInfo() {
+            mLoadAddress = 0;
+            mLoadSize = 0;
+            mRelroStart = 0;
+            mRelroSize = 0;
+            mRelroFd = -1;
+        }
+
+        public void close() {
+            if (mRelroFd >= 0) {
+                try {
+                    ParcelFileDescriptor.adoptFd(mRelroFd).close();
+                } catch (java.io.IOException e) {
+                    if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd);
+                }
+                mRelroFd = -1;
+            }
+        }
+
+        // from Parcelable
+        public LibInfo(Parcel in) {
+            mLoadAddress = in.readLong();
+            mLoadSize = in.readLong();
+            mRelroStart = in.readLong();
+            mRelroSize = in.readLong();
+            ParcelFileDescriptor fd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+            // If CreateSharedRelro fails, the OS file descriptor will be -1 and |fd| will be null.
+            mRelroFd = (fd == null) ? -1 : fd.detachFd();
+        }
+
+        // from Parcelable
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            if (mRelroFd >= 0) {
+                out.writeLong(mLoadAddress);
+                out.writeLong(mLoadSize);
+                out.writeLong(mRelroStart);
+                out.writeLong(mRelroSize);
+                try {
+                    ParcelFileDescriptor fd = ParcelFileDescriptor.fromFd(mRelroFd);
+                    fd.writeToParcel(out, 0);
+                    fd.close();
+                } catch (java.io.IOException e) {
+                    Log.e(TAG, "Cant' write LibInfo file descriptor to parcel", e);
+                }
+            }
+        }
+
+        // from Parcelable
+        @Override
+        public int describeContents() {
+            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+        }
+
+        // from Parcelable
+        public static final Parcelable.Creator<LibInfo> CREATOR =
+                new Parcelable.Creator<LibInfo>() {
+                    @Override
+                    public LibInfo createFromParcel(Parcel in) {
+                        return new LibInfo(in);
+                    }
+
+                    @Override
+                    public LibInfo[] newArray(int size) {
+                        return new LibInfo[size];
+                    }
+                };
+
+        @Override
+        public String toString() {
+            return String.format(Locale.US,
+                                 "[load=0x%x-0x%x relro=0x%x-0x%x fd=%d]",
+                                 mLoadAddress,
+                                 mLoadAddress + mLoadSize,
+                                 mRelroStart,
+                                 mRelroStart + mRelroSize,
+                                 mRelroFd);
+        }
+
+        // IMPORTANT: Don't change these fields without modifying the
+        // native code that accesses them directly!
+        @AccessedByNative
+        public long mLoadAddress; // page-aligned library load address.
+        @AccessedByNative
+        public long mLoadSize;    // page-aligned library load size.
+        @AccessedByNative
+        public long mRelroStart;  // page-aligned address in memory, or 0 if none.
+        @AccessedByNative
+        public long mRelroSize;   // page-aligned size in memory, or 0.
+        @AccessedByNative
+        public int  mRelroFd;     // ashmem file descriptor, or -1
+    }
+
+    // Create a Bundle from a map of LibInfo objects.
+    private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
+        Bundle bundle = new Bundle(map.size());
+        for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
+            bundle.putParcelable(entry.getKey(), entry.getValue());
+        }
+
+        return bundle;
+    }
+
+    // Create a new LibInfo map from a Bundle.
+    private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
+        HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
+        for (String library : bundle.keySet()) {
+            LibInfo libInfo = bundle.getParcelable(library);
+            map.put(library, libInfo);
+        }
+        return map;
+    }
+
+    // Call the close() method on all values of a LibInfo map.
+    private static void closeLibInfoMap(HashMap<String, LibInfo> map) {
+        for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
+            entry.getValue().close();
+        }
+    }
+
+    // The map of libraries that are currently loaded in this process.
+    private static HashMap<String, LibInfo> sLoadedLibraries = null;
+
+    // Used to pass the shared RELRO Bundle through Binder.
+    public static final String EXTRA_LINKER_SHARED_RELROS =
+            "org.chromium.base.android.linker.shared_relros";
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java b/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java
new file mode 100644
index 0000000..2b94370
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+/**
+ * These are the possible failures from the LibraryLoader
+ */
+public class LoaderErrors {
+    public static final int LOADER_ERROR_NORMAL_COMPLETION = 0;
+    public static final int LOADER_ERROR_FAILED_TO_REGISTER_JNI = 1;
+    public static final int LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED = 2;
+    public static final int LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION = 3;
+    public static final int LOADER_ERROR_NATIVE_STARTUP_FAILED = 4;
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java b/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java
new file mode 100644
index 0000000..1066675
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+/**
+ * The exception that is thrown when the intialization of a process was failed.
+ */
+public class ProcessInitException extends Exception {
+    private int mErrorCode = LoaderErrors.LOADER_ERROR_NORMAL_COMPLETION;
+
+    /**
+     * @param errorCode This will be one of the LoaderErrors error codes.
+     */
+    public ProcessInitException(int errorCode) {
+        mErrorCode = errorCode;
+    }
+
+    /**
+     * @param errorCode This will be one of the LoaderErrors error codes.
+     * @param throwable The wrapped throwable obj.
+     */
+    public ProcessInitException(int errorCode, Throwable throwable) {
+        super(null, throwable);
+        mErrorCode = errorCode;
+    }
+
+    /**
+     * Return the error code.
+     */
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
new file mode 100644
index 0000000..2f4356b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
@@ -0,0 +1,177 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.metrics;
+
+import org.chromium.base.JNINamespace;
+import org.chromium.base.VisibleForTesting;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Java API for recording UMA histograms. Internally, the histogram will be cached by
+ * System.identityHashCode(name).
+ *
+ * Note: the JNI calls are relatively costly - avoid calling these methods in performance-critical
+ * code.
+ */
+@JNINamespace("base::android")
+public class RecordHistogram {
+    /**
+     * Records a sample in a boolean UMA histogram of the given name. Boolean histogram has two
+     * buckets, corresponding to success (true) and failure (false). This is the Java equivalent of
+     * the UMA_HISTOGRAM_BOOLEAN C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, either true or false
+     */
+    public static void recordBooleanHistogram(String name, boolean sample) {
+        nativeRecordBooleanHistogram(name, System.identityHashCode(name), sample);
+    }
+
+    /**
+     * Records a sample in an enumerated histogram of the given name and boundary. Note that
+     * |boundary| identifies the histogram - it should be the same at every invocation. This is the
+     * Java equivalent of the UMA_HISTOGRAM_ENUMERATION C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 0 and at most |boundary| - 1
+     * @param boundary upper bound for legal sample values - all sample values have to be strictly
+     *        lower than |boundary|
+     */
+    public static void recordEnumeratedHistogram(String name, int sample, int boundary) {
+        nativeRecordEnumeratedHistogram(name, System.identityHashCode(name), sample, boundary);
+    }
+
+    /**
+     * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_COUNTS C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 1 and at most 999999
+     */
+    public static void recordCountHistogram(String name, int sample) {
+        recordCustomCountHistogram(name, sample, 1, 1000000, 50);
+    }
+
+    /**
+     * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_COUNTS_100 C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 1 and at most 99
+     */
+    public static void recordCount100Histogram(String name, int sample) {
+        recordCustomCountHistogram(name, sample, 1, 100, 50);
+    }
+
+    /**
+     * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_CUSTOM_COUNTS C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least |min| and at most |max| - 1
+     * @param min lower bound for expected sample values
+     * @param max upper bounds for expected sample values
+     * @param numBuckets the number of buckets
+     */
+    public static void recordCustomCountHistogram(
+            String name, int sample, int min, int max, int numBuckets) {
+        nativeRecordCustomCountHistogram(
+                name, System.identityHashCode(name), sample, min, max, numBuckets);
+    }
+
+    /**
+    * Records a sparse histogram. This is the Java equivalent of UMA_HISTOGRAM_SPARSE_SLOWLY.
+    * @param name name of the histogram
+    * @param sample sample to be recorded. All values of |sample| are valid, including negative
+    *        values.
+    */
+    public static void recordSparseSlowlyHistogram(String name, int sample) {
+        nativeRecordSparseHistogram(name, System.identityHashCode(name), sample);
+    }
+
+    /**
+     * Records a sample in a histogram of times. Useful for recording short durations. This is the
+     * Java equivalent of the UMA_HISTOGRAM_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param timeUnit the unit of the duration argument
+     */
+    public static void recordTimesHistogram(String name, long duration, TimeUnit timeUnit) {
+        recordCustomTimesHistogramMilliseconds(
+                name, timeUnit.toMillis(duration), 1, TimeUnit.SECONDS.toMillis(10), 50);
+    }
+
+    /**
+     * Records a sample in a histogram of times. Useful for recording medium durations. This is the
+     * Java equivalent of the UMA_HISTOGRAM_MEDIUM_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param timeUnit the unit of the duration argument
+     */
+    public static void recordMediumTimesHistogram(String name, long duration, TimeUnit timeUnit) {
+        recordCustomTimesHistogramMilliseconds(
+                name, timeUnit.toMillis(duration), 10, TimeUnit.MINUTES.toMillis(3), 50);
+    }
+
+    /**
+     * Records a sample in a histogram of times. Useful for recording long durations. This is the
+     * Java equivalent of the UMA_HISTOGRAM_LONG_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param timeUnit the unit of the duration argument
+     */
+    public static void recordLongTimesHistogram(String name, long duration, TimeUnit timeUnit) {
+        recordCustomTimesHistogramMilliseconds(
+                name, timeUnit.toMillis(duration), 1, TimeUnit.HOURS.toMillis(1), 50);
+    }
+
+    /**
+     * Records a sample in a histogram of times with custom buckets. This is the Java equivalent of
+     * the UMA_HISTOGRAM_CUSTOM_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param min the minimum bucket value
+     * @param max the maximum bucket value
+     * @param timeUnit the unit of the duration, min, and max arguments
+     * @param numBuckets the number of buckets
+     */
+    public static void recordCustomTimesHistogram(
+            String name, long duration, long min, long max, TimeUnit timeUnit, int numBuckets) {
+        recordCustomTimesHistogramMilliseconds(name, timeUnit.toMillis(duration),
+                timeUnit.toMillis(min), timeUnit.toMillis(max), numBuckets);
+    }
+
+    private static void recordCustomTimesHistogramMilliseconds(
+            String name, long duration, long min, long max, int numBuckets) {
+        nativeRecordCustomTimesHistogramMilliseconds(
+                name, System.identityHashCode(name), duration, min, max, numBuckets);
+    }
+
+    /**
+     * Returns the number of samples recorded in the given bucket of the given histogram.
+     * @param name name of the histogram to look up
+     * @param sample the bucket containing this sample value will be looked up
+     */
+    @VisibleForTesting
+    public static int getHistogramValueCountForTesting(String name, int sample) {
+        return nativeGetHistogramValueCountForTesting(name, sample);
+    }
+
+    /**
+     * Initializes the metrics system.
+     */
+    public static void initialize() {
+        nativeInitialize();
+    }
+
+    private static native void nativeRecordCustomTimesHistogramMilliseconds(
+            String name, int key, long duration, long min, long max, int numBuckets);
+
+    private static native void nativeRecordBooleanHistogram(String name, int key, boolean sample);
+    private static native void nativeRecordEnumeratedHistogram(
+            String name, int key, int sample, int boundary);
+    private static native void nativeRecordCustomCountHistogram(
+            String name, int key, int sample, int min, int max, int numBuckets);
+    private static native void nativeRecordSparseHistogram(String name, int key, int sample);
+
+    private static native int nativeGetHistogramValueCountForTesting(String name, int sample);
+    private static native void nativeInitialize();
+}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
new file mode 100644
index 0000000..d7cc32c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.metrics;
+
+import org.chromium.base.JNINamespace;
+import org.chromium.base.ThreadUtils;
+
+/**
+ * Java API for recording UMA actions.
+ *
+ * WARNINGS:
+ * JNI calls are relatively costly - avoid using in performance-critical code.
+ *
+ * We use a script (extract_actions.py) to scan the source code and extract actions. A string
+ * literal (not a variable) must be passed to record().
+ */
+@JNINamespace("base::android")
+public class RecordUserAction {
+    public static void record(final String action) {
+        if (ThreadUtils.runningOnUiThread()) {
+            nativeRecordUserAction(action);
+            return;
+        }
+
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                nativeRecordUserAction(action);
+            }
+        });
+    }
+
+    private static native void nativeRecordUserAction(String action);
+}
diff --git a/base/android/java/templates/NativeLibraries.template b/base/android/java/templates/NativeLibraries.template
new file mode 100644
index 0000000..8b812a6
--- /dev/null
+++ b/base/android/java/templates/NativeLibraries.template
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+import org.chromium.base.annotations.SuppressFBWarnings;
+
+@SuppressFBWarnings
+public class NativeLibraries {
+    /**
+     * IMPORTANT NOTE: The variables defined here must _not_ be 'final'.
+     *
+     * The reason for this is very subtle:
+     *
+     * - This template is used to generate several distinct, but similar
+     *   files used in different contexts:
+     *
+     *   o .../gen/templates/org/chromium/base/library_loader/NativeLibraries.java
+     *
+     *     This file is used to build base.jar, which is the library
+     *     jar used by chromium projects. However, the
+     *     corresponding NativeLibraries.class file will _not_ be part
+     *     of the final base.jar.
+     *
+     *   o .../$PROJECT/native_libraries_java/NativeLibraries.java
+     *
+     *     This file is used to build an APK (e.g. $PROJECT
+     *     could be 'content_shell_apk'). Its content will depend on
+     *     this target's specific build configuration, and differ from
+     *     the source file above.
+     *
+     * - During the final link, all .jar files are linked together into
+     *   a single .dex file, and the second version of NativeLibraries.class
+     *   will be put into the final output file, and used at runtime.
+     *
+     * - If the variables were defined as 'final', their value would be
+     *   optimized out inside of 'base.jar', and could not be specialized
+     *   for every chromium program. This, however, doesn't apply to arrays of
+     *   strings, which can be defined as final.
+     *
+     * This exotic scheme is used to avoid injecting project-specific, or
+     * even build-specific, values into the base layer. E.g. this is
+     * how the component build is supported on Android without modifying
+     * the sources of each and every Chromium-based target.
+     */
+
+#if defined(ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE) && \
+    !defined(ENABLE_CHROMIUM_LINKER)
+#error "Must have ENABLE_CHROMIUM_LINKER to enable library in zip file"
+#endif
+
+    // Set to true to enable the use of the Chromium Linker.
+#if defined(ENABLE_CHROMIUM_LINKER)
+    public static boolean sUseLinker = true;
+#else
+    public static boolean sUseLinker = false;
+#endif
+
+#if defined(ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE)
+    public static boolean sUseLibraryInZipFile = true;
+#else
+    public static boolean sUseLibraryInZipFile = false;
+#endif
+
+#if defined(ENABLE_CHROMIUM_LINKER_TESTS)
+    public static boolean sEnableLinkerTests = true;
+#else
+    public static boolean sEnableLinkerTests = false;
+#endif
+
+    // This is the list of native libraries to be loaded (in the correct order)
+    // by LibraryLoader.java.  The base java library is compiled with no
+    // array defined, and then the build system creates a version of the file
+    // with the real list of libraries required (which changes based upon which
+    // .apk is being built).
+    // TODO(cjhopman): This is public since it is referenced by NativeTestActivity.java
+    // directly. The two ways of library loading should be refactored into one.
+    public static final String[] LIBRARIES =
+#if defined(NATIVE_LIBRARIES_LIST)
+      NATIVE_LIBRARIES_LIST;
+#else
+      {};
+#endif
+
+    // This is the expected version of the 'main' native library, which is the one that
+    // implements the initial set of base JNI functions including
+    // base::android::nativeGetVersionName()
+    static String sVersionNumber =
+#if defined(NATIVE_LIBRARIES_VERSION_NUMBER)
+      NATIVE_LIBRARIES_VERSION_NUMBER;
+#else
+      "";
+#endif
+}
diff --git a/base/android/java_handler_thread.cc b/base/android/java_handler_thread.cc
new file mode 100644
index 0000000..117971e
--- /dev/null
+++ b/base/android/java_handler_thread.cc
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/java_handler_thread.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+#include "jni/JavaHandlerThread_jni.h"
+
+namespace base {
+
+namespace android {
+
+JavaHandlerThread::JavaHandlerThread(const char* name) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  java_thread_.Reset(Java_JavaHandlerThread_create(
+      env, ConvertUTF8ToJavaString(env, name).Release()));
+}
+
+JavaHandlerThread::~JavaHandlerThread() {
+}
+
+void JavaHandlerThread::Start() {
+  // Check the thread has not already been started.
+  DCHECK(!message_loop_);
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::WaitableEvent initialize_event(false, false);
+  Java_JavaHandlerThread_start(env,
+                               java_thread_.obj(),
+                               reinterpret_cast<intptr_t>(this),
+                               reinterpret_cast<intptr_t>(&initialize_event));
+  // Wait for thread to be initialized so it is ready to be used when Start
+  // returns.
+  base::ThreadRestrictions::ScopedAllowWait wait_allowed;
+  initialize_event.Wait();
+}
+
+void JavaHandlerThread::Stop() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::WaitableEvent shutdown_event(false, false);
+  Java_JavaHandlerThread_stop(env,
+                              java_thread_.obj(),
+                              reinterpret_cast<intptr_t>(this),
+                              reinterpret_cast<intptr_t>(&shutdown_event));
+  // Wait for thread to shut down before returning.
+  base::ThreadRestrictions::ScopedAllowWait wait_allowed;
+  shutdown_event.Wait();
+}
+
+void JavaHandlerThread::InitializeThread(JNIEnv* env, jobject obj,
+                                         jlong event) {
+  // TYPE_JAVA to get the Android java style message loop.
+  message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_JAVA));
+  static_cast<MessageLoopForUI*>(message_loop_.get())->Start();
+  reinterpret_cast<base::WaitableEvent*>(event)->Signal();
+}
+
+void JavaHandlerThread::StopThread(JNIEnv* env, jobject obj, jlong event) {
+  static_cast<MessageLoopForUI*>(message_loop_.get())->Quit();
+  reinterpret_cast<base::WaitableEvent*>(event)->Signal();
+}
+
+// static
+bool JavaHandlerThread::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/java_handler_thread.h b/base/android/java_handler_thread.h
new file mode 100644
index 0000000..c9a2c02
--- /dev/null
+++ b/base/android/java_handler_thread.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JAVA_HANDLER_THREAD_H_
+#define BASE_ANDROID_JAVA_HANDLER_THREAD_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class MessageLoop;
+class WaitableEvent;
+
+namespace android {
+
+// A Java Thread with a native message loop. To run tasks, post them
+// to the message loop and they will be scheduled along with Java tasks
+// on the thread.
+// This is useful for callbacks where the receiver expects a thread
+// with a prepared Looper.
+class BASE_EXPORT JavaHandlerThread {
+ public:
+  JavaHandlerThread(const char* name);
+  virtual ~JavaHandlerThread();
+
+  base::MessageLoop* message_loop() const { return message_loop_.get(); }
+  void Start();
+  void Stop();
+
+  // Called from java on the newly created thread.
+  // Start() will not return before this methods has finished.
+  void InitializeThread(JNIEnv* env, jobject obj, jlong event);
+  void StopThread(JNIEnv* env, jobject obj, jlong event);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  scoped_ptr<base::MessageLoop> message_loop_;
+  ScopedJavaGlobalRef<jobject> java_thread_;
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JAVA_HANDLER_THREAD_H_
diff --git a/base/android/java_runtime.cc b/base/android/java_runtime.cc
new file mode 100644
index 0000000..5be9adf
--- /dev/null
+++ b/base/android/java_runtime.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/java_runtime.h"
+
+#include "jni/Runtime_jni.h"
+
+namespace base {
+namespace android {
+
+bool JavaRuntime::Register(JNIEnv* env) {
+  return JNI_Runtime::RegisterNativesImpl(env);
+}
+
+void JavaRuntime::GetMemoryUsage(long* total_memory, long* free_memory) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> runtime =
+      JNI_Runtime::Java_Runtime_getRuntime(env);
+  *total_memory = JNI_Runtime::Java_Runtime_totalMemory(env, runtime.obj());
+  *free_memory = JNI_Runtime::Java_Runtime_freeMemory(env, runtime.obj());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/java_runtime.h b/base/android/java_runtime.h
new file mode 100644
index 0000000..bde4c5c
--- /dev/null
+++ b/base/android/java_runtime.h
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JAVA_RUNTIME_H
+#define BASE_ANDROID_JAVA_RUNTIME_H
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Wrapper class for using the java.lang.Runtime object from jni.
+class BASE_EXPORT JavaRuntime {
+ public:
+  // Registers the jni class (once per process).
+  static bool Register(JNIEnv* env);
+
+  // Fills the total memory used and memory allocated for objects by the java
+  // heap in the current process. Returns true on success.
+  static void GetMemoryUsage(long* total_memory, long* free_memory);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JAVA_RUNTIME_H
diff --git a/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
new file mode 100644
index 0000000..d7c103b
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Application;
+import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.test.InstrumentationTestCase;
+
+import org.chromium.base.test.util.AdvancedMockContext;
+
+/**
+ * Tests for {@link org.chromium.base.test.util.AdvancedMockContext}.
+ */
+public class AdvancedMockContextTest extends InstrumentationTestCase {
+    private static class Callback1 implements ComponentCallbacks {
+        protected Configuration mConfiguration;
+        protected boolean mOnLowMemoryCalled;
+
+        @Override
+        public void onConfigurationChanged(Configuration configuration) {
+            mConfiguration = configuration;
+        }
+
+        @Override
+        public void onLowMemory() {
+            mOnLowMemoryCalled = true;
+        }
+    }
+
+    private static class Callback2 extends Callback1 implements ComponentCallbacks2 {
+        private int mLevel;
+
+        @Override
+        public void onTrimMemory(int level) {
+            mLevel = level;
+        }
+    }
+
+    public void testComponentCallbacksForTargetContext() {
+        Context targetContext = getInstrumentation().getTargetContext();
+        Application targetApplication = (Application) targetContext.getApplicationContext();
+        AdvancedMockContext context = new AdvancedMockContext(targetContext);
+        Callback1 callback1 = new Callback1();
+        Callback2 callback2 = new Callback2();
+        context.registerComponentCallbacks(callback1);
+        context.registerComponentCallbacks(callback2);
+
+        targetApplication.onLowMemory();
+        assertTrue("onLowMemory should have been called.", callback1.mOnLowMemoryCalled);
+        assertTrue("onLowMemory should have been called.", callback2.mOnLowMemoryCalled);
+
+        Configuration configuration = new Configuration();
+        targetApplication.onConfigurationChanged(configuration);
+        assertEquals("onConfigurationChanged should have been called.", configuration,
+                callback1.mConfiguration);
+        assertEquals("onConfigurationChanged should have been called.", configuration,
+                callback2.mConfiguration);
+
+        targetApplication.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
+        assertEquals("onTrimMemory should have been called.", ComponentCallbacks2
+                .TRIM_MEMORY_MODERATE, callback2.mLevel);
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
new file mode 100644
index 0000000..45b3e21
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.os.Build;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test of ApiCompatibilityUtils
+ */
+public class ApiCompatibilityUtilsTest extends InstrumentationTestCase {
+    private static final long WAIT_TIMEOUT_IN_MS = 5000;
+    private static final long SLEEP_INTERVAL_IN_MS = 50;
+
+    static class MockActivity extends Activity {
+        int mFinishAndRemoveTaskCallbackCount;
+        int mFinishCallbackCount;
+        boolean mIsFinishing;
+
+        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+        @Override
+        public void finishAndRemoveTask() {
+            mFinishAndRemoveTaskCallbackCount++;
+            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) mIsFinishing = true;
+        }
+
+        @Override
+        public void finish() {
+            mFinishCallbackCount++;
+            mIsFinishing = true;
+        }
+
+        @Override
+        public boolean isFinishing() {
+            return mIsFinishing;
+        }
+    }
+
+    @SmallTest
+    public void testFinishAndRemoveTask() throws InterruptedException {
+        MockActivity activity = new MockActivity();
+        ApiCompatibilityUtils.finishAndRemoveTask(activity);
+
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+            assertEquals(1, activity.mFinishAndRemoveTaskCallbackCount);
+            assertEquals(0, activity.mFinishCallbackCount);
+        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+            long startTime = SystemClock.uptimeMillis();
+            while (activity.mFinishCallbackCount == 0
+                    && SystemClock.uptimeMillis() - startTime < WAIT_TIMEOUT_IN_MS) {
+                Thread.sleep(SLEEP_INTERVAL_IN_MS);
+            }
+
+            // MockActivity#finishAndRemoveTask() never sets isFinishing() to true for LOLLIPOP to
+            // simulate an exceptional case. In that case, MockActivity#finish() should be called
+            // after 3 tries.
+            assertEquals(3, activity.mFinishAndRemoveTaskCallbackCount);
+            assertEquals(1, activity.mFinishCallbackCount);
+        } else {
+            assertEquals(0, activity.mFinishAndRemoveTaskCallbackCount);
+            assertEquals(1, activity.mFinishCallbackCount);
+        }
+        assertTrue(activity.mIsFinishing);
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineTest.java b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
new file mode 100644
index 0000000..2b1a967
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
@@ -0,0 +1,128 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.util.Feature;
+
+public class CommandLineTest extends InstrumentationTestCase {
+    // A reference command line. Note that switch2 is [brea\d], switch3 is [and "butter"],
+    // and switch4 is [a "quoted" 'food'!]
+    static final String INIT_SWITCHES[] = { "init_command", "--SWITCH", "Arg",
+        "--switch2=brea\\d", "--switch3=and \"butter\"",
+        "--switch4=a \"quoted\" 'food'!",
+        "--", "--actually_an_arg" };
+
+    // The same command line, but in quoted string format.
+    static final char INIT_SWITCHES_BUFFER[] =
+        ("init_command --SWITCH Arg --switch2=brea\\d --switch3=\"and \\\"butt\"er\\\"   "
+        + "--switch4='a \"quoted\" \\'food\\'!' "
+        + "-- --actually_an_arg").toCharArray();
+
+    static final String CL_ADDED_SWITCH = "zappo-dappo-doggy-trainer";
+    static final String CL_ADDED_SWITCH_2 = "username";
+    static final String CL_ADDED_VALUE_2 = "bozo";
+
+    @Override
+    public void setUp() throws Exception {
+        CommandLine.reset();
+    }
+
+    void checkInitSwitches() {
+        CommandLine cl = CommandLine.getInstance();
+        assertFalse(cl.hasSwitch("init_command"));
+        assertFalse(cl.hasSwitch("switch"));
+        assertTrue(cl.hasSwitch("SWITCH"));
+        assertFalse(cl.hasSwitch("--SWITCH"));
+        assertFalse(cl.hasSwitch("Arg"));
+        assertFalse(cl.hasSwitch("actually_an_arg"));
+        assertEquals("brea\\d", cl.getSwitchValue("switch2"));
+        assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
+        assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
+        assertNull(cl.getSwitchValue("SWITCH"));
+        assertNull(cl.getSwitchValue("non-existant"));
+    }
+
+    void checkSettingThenGetting() {
+        CommandLine cl = CommandLine.getInstance();
+
+        // Add a plain switch.
+        assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
+        cl.appendSwitch(CL_ADDED_SWITCH);
+        assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
+
+        // Add a switch paired with a value.
+        assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
+        assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
+        cl.appendSwitchWithValue(CL_ADDED_SWITCH_2, CL_ADDED_VALUE_2);
+        assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
+
+        // Append a few new things.
+        final String switchesAndArgs[] = { "dummy", "--superfast", "--speed=turbo" };
+        assertFalse(cl.hasSwitch("dummy"));
+        assertFalse(cl.hasSwitch("superfast"));
+        assertNull(cl.getSwitchValue("speed"));
+        cl.appendSwitchesAndArguments(switchesAndArgs);
+        assertFalse(cl.hasSwitch("dummy"));
+        assertFalse(cl.hasSwitch("command"));
+        assertTrue(cl.hasSwitch("superfast"));
+        assertTrue("turbo".equals(cl.getSwitchValue("speed")));
+    }
+
+    void checkTokenizer(String[] expected, String toParse) {
+        String[] actual = CommandLine.tokenizeQuotedAruments(toParse.toCharArray());
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; ++i) {
+            assertEquals("comparing element " + i, expected[i], actual[i]);
+        }
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testJavaInitialization() {
+        CommandLine.init(INIT_SWITCHES);
+        checkInitSwitches();
+        checkSettingThenGetting();
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testBufferInitialization() {
+        CommandLine.init(CommandLine.tokenizeQuotedAruments(INIT_SWITCHES_BUFFER));
+        checkInitSwitches();
+        checkSettingThenGetting();
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testArgumentTokenizer() {
+        String toParse = " a\"\\bc de\\\"f g\"\\h ij    k\" \"lm";
+        String[] expected = { "a\\bc de\"f g\\h",
+                              "ij",
+                              "k lm" };
+        checkTokenizer(expected, toParse);
+
+        toParse = "";
+        expected = new String[0];
+        checkTokenizer(expected, toParse);
+
+        toParse = " \t\n";
+        checkTokenizer(expected, toParse);
+
+        toParse = " \"a'b\" 'c\"d' \"e\\\"f\" 'g\\'h' \"i\\'j\" 'k\\\"l'"
+                + " m\"n\\'o\"p q'r\\\"s't";
+        expected = new String[] { "a'b",
+                                  "c\"d",
+                                  "e\"f",
+                                  "g'h",
+                                  "i\\'j",
+                                  "k\\\"l",
+                                  "mn\\'op",
+                                  "qr\\\"st"};
+        checkTokenizer(expected, toParse);
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/ObserverListTest.java b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
new file mode 100644
index 0000000..973682b
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
@@ -0,0 +1,326 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.util.Feature;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests for (@link ObserverList}.
+ */
+public class ObserverListTest extends InstrumentationTestCase {
+    interface Observer {
+        void observe(int x);
+    }
+
+    private static class Foo implements Observer {
+        private final int mScalar;
+        private int mTotal = 0;
+
+        Foo(int scalar) {
+            mScalar = scalar;
+        }
+
+        @Override
+        public void observe(int x) {
+            mTotal += x * mScalar;
+        }
+    }
+
+    /**
+     * An observer which add a given Observer object to the list when observe is called.
+     */
+    private static class FooAdder implements Observer {
+        private final ObserverList<Observer> mList;
+        private final Observer mLucky;
+
+        FooAdder(ObserverList<Observer> list, Observer oblivious) {
+            mList = list;
+            mLucky = oblivious;
+        }
+
+        @Override
+        public void observe(int x) {
+            mList.addObserver(mLucky);
+        }
+    }
+
+    /**
+     * An observer which removes a given Observer object from the list when observe is called.
+     */
+    private static class FooRemover implements Observer {
+        private final ObserverList<Observer> mList;
+        private final Observer mDoomed;
+
+        FooRemover(ObserverList<Observer> list, Observer innocent) {
+            mList = list;
+            mDoomed = innocent;
+        }
+
+        @Override
+        public void observe(int x) {
+            mList.removeObserver(mDoomed);
+        }
+    }
+
+    private static <T> int getSizeOfIterable(Iterable<T> iterable) {
+        int num = 0;
+        for (T el : iterable) num++;
+        return num;
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testRemoveWhileIteration() {
+        ObserverList<Observer> observerList = new ObserverList<Observer>();
+        Foo a = new Foo(1);
+        Foo b = new Foo(-1);
+        Foo c = new Foo(1);
+        Foo d = new Foo(-1);
+        Foo e = new Foo(-1);
+        FooRemover evil = new FooRemover(observerList, c);
+
+        observerList.addObserver(a);
+        observerList.addObserver(b);
+
+        for (Observer obs : observerList) obs.observe(10);
+
+        // Removing an observer not in the list should do nothing.
+        observerList.removeObserver(e);
+
+        observerList.addObserver(evil);
+        observerList.addObserver(c);
+        observerList.addObserver(d);
+
+        for (Observer obs : observerList) obs.observe(10);
+
+        // observe should be called twice on a.
+        assertEquals(20, a.mTotal);
+        // observe should be called twice on b.
+        assertEquals(-20, b.mTotal);
+        // evil removed c from the observerList before it got any callbacks.
+        assertEquals(0, c.mTotal);
+        // observe should be called once on d.
+        assertEquals(-10, d.mTotal);
+        // e was never added to the list, observe should not be called.
+        assertEquals(0, e.mTotal);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testAddWhileIteration() {
+        ObserverList<Observer> observerList = new ObserverList<Observer>();
+        Foo a = new Foo(1);
+        Foo b = new Foo(-1);
+        Foo c = new Foo(1);
+        FooAdder evil = new FooAdder(observerList, c);
+
+        observerList.addObserver(evil);
+        observerList.addObserver(a);
+        observerList.addObserver(b);
+
+        for (Observer obs : observerList) obs.observe(10);
+
+        assertTrue(observerList.hasObserver(c));
+        assertEquals(10, a.mTotal);
+        assertEquals(-10, b.mTotal);
+        assertEquals(0, c.mTotal);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testIterator() {
+        ObserverList<Integer> observerList = new ObserverList<Integer>();
+        observerList.addObserver(5);
+        observerList.addObserver(10);
+        observerList.addObserver(15);
+        assertEquals(3, getSizeOfIterable(observerList));
+
+        observerList.removeObserver(10);
+        assertEquals(2, getSizeOfIterable(observerList));
+
+        Iterator<Integer> it = observerList.iterator();
+        assertTrue(it.hasNext());
+        assertTrue(5 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+        assertFalse(it.hasNext());
+
+        boolean removeExceptionThrown = false;
+        try {
+            it.remove();
+            fail("Expecting UnsupportedOperationException to be thrown here.");
+        } catch (UnsupportedOperationException e) {
+            removeExceptionThrown = true;
+        }
+        assertTrue(removeExceptionThrown);
+        assertEquals(2, getSizeOfIterable(observerList));
+
+        boolean noElementExceptionThrown = false;
+        try {
+            it.next();
+            fail("Expecting NoSuchElementException to be thrown here.");
+        } catch (NoSuchElementException e) {
+            noElementExceptionThrown = true;
+        }
+        assertTrue(noElementExceptionThrown);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testRewindableIterator() {
+        ObserverList<Integer> observerList = new ObserverList<Integer>();
+        observerList.addObserver(5);
+        observerList.addObserver(10);
+        observerList.addObserver(15);
+        assertEquals(3, getSizeOfIterable(observerList));
+
+        ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator();
+        assertTrue(it.hasNext());
+        assertTrue(5 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(10 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+        assertFalse(it.hasNext());
+
+        it.rewind();
+
+        assertTrue(it.hasNext());
+        assertTrue(5 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(10 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+        assertEquals(5, (int) observerList.mObservers.get(0));
+        observerList.removeObserver(5);
+        assertEquals(null, observerList.mObservers.get(0));
+
+        it.rewind();
+
+        assertEquals(10, (int) observerList.mObservers.get(0));
+        assertTrue(it.hasNext());
+        assertTrue(10 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testAddObserverReturnValue() {
+        ObserverList<Object> observerList = new ObserverList<Object>();
+
+        Object a = new Object();
+        assertTrue(observerList.addObserver(a));
+        assertFalse(observerList.addObserver(a));
+
+        Object b = new Object();
+        assertTrue(observerList.addObserver(b));
+        assertFalse(observerList.addObserver(null));
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testRemoveObserverReturnValue() {
+        ObserverList<Object> observerList = new ObserverList<Object>();
+
+        Object a = new Object();
+        Object b = new Object();
+        observerList.addObserver(a);
+        observerList.addObserver(b);
+
+        assertTrue(observerList.removeObserver(a));
+        assertFalse(observerList.removeObserver(a));
+        assertFalse(observerList.removeObserver(new Object()));
+        assertTrue(observerList.removeObserver(b));
+        assertFalse(observerList.removeObserver(null));
+
+        // If we remove an object while iterating, it will be replaced by 'null'.
+        observerList.addObserver(a);
+        assertTrue(observerList.removeObserver(a));
+        assertFalse(observerList.removeObserver(null));
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testSize() {
+        ObserverList<Object> observerList = new ObserverList<Object>();
+
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.addObserver(null);
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        Object a = new Object();
+        observerList.addObserver(a);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.addObserver(a);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.addObserver(null);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        Object b = new Object();
+        observerList.addObserver(b);
+        assertEquals(2, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(null);
+        assertEquals(2, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(new Object());
+        assertEquals(2, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(b);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(b);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(a);
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.removeObserver(a);
+        observerList.removeObserver(b);
+        observerList.removeObserver(null);
+        observerList.removeObserver(new Object());
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.addObserver(new Object());
+        observerList.addObserver(new Object());
+        observerList.addObserver(new Object());
+        observerList.addObserver(a);
+        assertEquals(4, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.clear();
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.removeObserver(a);
+        observerList.removeObserver(b);
+        observerList.removeObserver(null);
+        observerList.removeObserver(new Object());
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
new file mode 100644
index 0000000..24af056
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
@@ -0,0 +1,159 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.metrics;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for the Java API for recording UMA histograms.
+ */
+public class RecordHistogramTest extends InstrumentationTestCase {
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
+        RecordHistogram.initialize();
+    }
+
+    /**
+     * Tests recording of boolean histograms.
+     */
+    @SmallTest
+    public void testRecordBooleanHistogram() {
+        String histogram = "HelloWorld.BooleanMetric";
+        HistogramDelta falseCount = new HistogramDelta(histogram, 0);
+        HistogramDelta trueCount = new HistogramDelta(histogram, 1);
+        assertEquals(0, trueCount.getDelta());
+        assertEquals(0, falseCount.getDelta());
+
+        RecordHistogram.recordBooleanHistogram(histogram, true);
+        assertEquals(1, trueCount.getDelta());
+        assertEquals(0, falseCount.getDelta());
+
+        RecordHistogram.recordBooleanHistogram(histogram, true);
+        assertEquals(2, trueCount.getDelta());
+        assertEquals(0, falseCount.getDelta());
+
+        RecordHistogram.recordBooleanHistogram(histogram, false);
+        assertEquals(2, trueCount.getDelta());
+        assertEquals(1, falseCount.getDelta());
+    }
+
+    /**
+     * Tests recording of enumerated histograms.
+     */
+    @SmallTest
+    public void testRecordEnumeratedHistogram() {
+        String histogram = "HelloWorld.EnumeratedMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 2);
+        final int boundary = 3;
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordEnumeratedHistogram(histogram, 2, boundary);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+    }
+
+    /**
+     * Tests recording of count histograms.
+     */
+    @SmallTest
+    public void testRecordCountHistogram() {
+        String histogram = "HelloWorld.CountMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 2);
+        HistogramDelta eightThousandCount = new HistogramDelta(histogram, 8000);
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 0);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 0);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 2);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 8000);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+        assertEquals(1, eightThousandCount.getDelta());
+    }
+
+    /**
+     * Tests recording of custom times histograms.
+     */
+    @SmallTest
+    public void testRecordCustomTimesHistogram() {
+        String histogram = "HelloWorld.CustomTimesMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 100);
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        TimeUnit milli = TimeUnit.MILLISECONDS;
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 95, 1, 100, milli, 3);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(1, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 200, 1, 100, milli, 3);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(1, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+    }
+}
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
new file mode 100644
index 0000000..5416be3
--- /dev/null
+++ b/base/android/jni_android.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+
+#include <map>
+
+#include "base/android/build_info.h"
+#include "base/android/jni_string.h"
+#include "base/android/jni_utils.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+
+namespace {
+using base::android::GetClass;
+using base::android::MethodID;
+using base::android::ScopedJavaLocalRef;
+
+bool g_disable_manual_jni_registration = false;
+
+JavaVM* g_jvm = NULL;
+// Leak the global app context, as it is used from a non-joinable worker thread
+// that may still be running at shutdown. There is no harm in doing this.
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+    g_application_context = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+    g_class_loader = LAZY_INSTANCE_INITIALIZER;
+jmethodID g_class_loader_load_class_method_id = 0;
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+bool IsManualJniRegistrationDisabled() {
+  return g_disable_manual_jni_registration;
+}
+
+void DisableManualJniRegistration() {
+  DCHECK(!g_disable_manual_jni_registration);
+  g_disable_manual_jni_registration = true;
+}
+
+JNIEnv* AttachCurrentThread() {
+  DCHECK(g_jvm);
+  JNIEnv* env = NULL;
+  jint ret = g_jvm->AttachCurrentThread(&env, NULL);
+  DCHECK_EQ(JNI_OK, ret);
+  return env;
+}
+
+JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name) {
+  DCHECK(g_jvm);
+  JavaVMAttachArgs args;
+  args.version = JNI_VERSION_1_2;
+  args.name = thread_name.c_str();
+  args.group = NULL;
+  JNIEnv* env = NULL;
+  jint ret = g_jvm->AttachCurrentThread(&env, &args);
+  DCHECK_EQ(JNI_OK, ret);
+  return env;
+}
+
+void DetachFromVM() {
+  // Ignore the return value, if the thread is not attached, DetachCurrentThread
+  // will fail. But it is ok as the native thread may never be attached.
+  if (g_jvm)
+    g_jvm->DetachCurrentThread();
+}
+
+void InitVM(JavaVM* vm) {
+  DCHECK(!g_jvm);
+  g_jvm = vm;
+}
+
+bool IsVMInitialized() {
+  return g_jvm != NULL;
+}
+
+void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
+  if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) {
+    // It's safe to set the context more than once if it's the same context.
+    return;
+  }
+  DCHECK(g_application_context.Get().is_null());
+  g_application_context.Get().Reset(context);
+}
+
+void InitReplacementClassLoader(JNIEnv* env,
+                                const JavaRef<jobject>& class_loader) {
+  DCHECK(g_class_loader.Get().is_null());
+  DCHECK(!class_loader.is_null());
+
+  ScopedJavaLocalRef<jclass> class_loader_clazz =
+      GetClass(env, "java/lang/ClassLoader");
+  CHECK(!ClearException(env));
+  g_class_loader_load_class_method_id =
+      env->GetMethodID(class_loader_clazz.obj(),
+                       "loadClass",
+                       "(Ljava/lang/String;)Ljava/lang/Class;");
+  CHECK(!ClearException(env));
+
+  DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj()));
+  g_class_loader.Get().Reset(class_loader);
+}
+
+const jobject GetApplicationContext() {
+  DCHECK(!g_application_context.Get().is_null());
+  return g_application_context.Get().obj();
+}
+
+ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
+  jclass clazz;
+  if (!g_class_loader.Get().is_null()) {
+    // ClassLoader.loadClass expects a classname with components separated by
+    // dots instead of the slashes that JNIEnv::FindClass expects. The JNI
+    // generator generates names with slashes, so we have to replace them here.
+    // TODO(torne): move to an approach where we always use ClassLoader except
+    // for the special case of base::android::GetClassLoader(), and change the
+    // JNI generator to generate dot-separated names. http://crbug.com/461773
+    size_t bufsize = strlen(class_name) + 1;
+    char dotted_name[bufsize];
+    memmove(dotted_name, class_name, bufsize);
+    for (size_t i = 0; i < bufsize; ++i) {
+      if (dotted_name[i] == '/') {
+        dotted_name[i] = '.';
+      }
+    }
+
+    clazz = static_cast<jclass>(
+        env->CallObjectMethod(g_class_loader.Get().obj(),
+                              g_class_loader_load_class_method_id,
+                              ConvertUTF8ToJavaString(env, dotted_name).obj()));
+  } else {
+    clazz = env->FindClass(class_name);
+  }
+  CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
+  return ScopedJavaLocalRef<jclass>(env, clazz);
+}
+
+jclass LazyGetClass(
+    JNIEnv* env,
+    const char* class_name,
+    base::subtle::AtomicWord* atomic_class_id) {
+  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass),
+                 AtomicWord_SmallerThan_jMethodID);
+  subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id);
+  if (value)
+    return reinterpret_cast<jclass>(value);
+  ScopedJavaGlobalRef<jclass> clazz;
+  clazz.Reset(GetClass(env, class_name));
+  subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL);
+  subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap(
+      atomic_class_id,
+      null_aw,
+      reinterpret_cast<subtle::AtomicWord>(clazz.obj()));
+  if (cas_result == null_aw) {
+    // We intentionally leak the global ref since we now storing it as a raw
+    // pointer in |atomic_class_id|.
+    return clazz.Release();
+  } else {
+    return reinterpret_cast<jclass>(cas_result);
+  }
+}
+
+template<MethodID::Type type>
+jmethodID MethodID::Get(JNIEnv* env,
+                        jclass clazz,
+                        const char* method_name,
+                        const char* jni_signature) {
+  jmethodID id = type == TYPE_STATIC ?
+      env->GetStaticMethodID(clazz, method_name, jni_signature) :
+      env->GetMethodID(clazz, method_name, jni_signature);
+  CHECK(base::android::ClearException(env) || id) <<
+      "Failed to find " <<
+      (type == TYPE_STATIC ? "static " : "") <<
+      "method " << method_name << " " << jni_signature;
+  return id;
+}
+
+// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call
+// into ::Get() above. If there's a race, it's ok since the values are the same
+// (and the duplicated effort will happen only once).
+template<MethodID::Type type>
+jmethodID MethodID::LazyGet(JNIEnv* env,
+                            jclass clazz,
+                            const char* method_name,
+                            const char* jni_signature,
+                            base::subtle::AtomicWord* atomic_method_id) {
+  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
+                 AtomicWord_SmallerThan_jMethodID);
+  subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
+  if (value)
+    return reinterpret_cast<jmethodID>(value);
+  jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature);
+  base::subtle::Release_Store(
+      atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
+  return id;
+}
+
+// Various template instantiations.
+template jmethodID MethodID::Get<MethodID::TYPE_STATIC>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature);
+
+template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+bool HasException(JNIEnv* env) {
+  return env->ExceptionCheck() != JNI_FALSE;
+}
+
+bool ClearException(JNIEnv* env) {
+  if (!HasException(env))
+    return false;
+  env->ExceptionDescribe();
+  env->ExceptionClear();
+  return true;
+}
+
+void CheckException(JNIEnv* env) {
+  if (!HasException(env))
+    return;
+
+  // Exception has been found, might as well tell breakpad about it.
+  jthrowable java_throwable = env->ExceptionOccurred();
+  if (java_throwable) {
+    // Clear the pending exception, since a local reference is now held.
+    env->ExceptionDescribe();
+    env->ExceptionClear();
+
+    // Set the exception_string in BuildInfo so that breakpad can read it.
+    // RVO should avoid any extra copies of the exception string.
+    base::android::BuildInfo::GetInstance()->SetJavaExceptionInfo(
+        GetJavaExceptionInfo(env, java_throwable));
+  }
+
+  // Now, feel good about it and die.
+  CHECK(false) << "Please include Java exception stack in crash report";
+}
+
+std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
+  ScopedJavaLocalRef<jclass> throwable_clazz =
+      GetClass(env, "java/lang/Throwable");
+  jmethodID throwable_printstacktrace =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, throwable_clazz.obj(), "printStackTrace",
+          "(Ljava/io/PrintStream;)V");
+
+  // Create an instance of ByteArrayOutputStream.
+  ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
+      GetClass(env, "java/io/ByteArrayOutputStream");
+  jmethodID bytearray_output_stream_constructor =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
+  jmethodID bytearray_output_stream_tostring =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, bytearray_output_stream_clazz.obj(), "toString",
+          "()Ljava/lang/String;");
+  ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
+      env->NewObject(bytearray_output_stream_clazz.obj(),
+                     bytearray_output_stream_constructor));
+
+  // Create an instance of PrintStream.
+  ScopedJavaLocalRef<jclass> printstream_clazz =
+      GetClass(env, "java/io/PrintStream");
+  jmethodID printstream_constructor =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, printstream_clazz.obj(), "<init>",
+          "(Ljava/io/OutputStream;)V");
+  ScopedJavaLocalRef<jobject> printstream(env,
+      env->NewObject(printstream_clazz.obj(), printstream_constructor,
+                     bytearray_output_stream.obj()));
+
+  // Call Throwable.printStackTrace(PrintStream)
+  env->CallVoidMethod(java_throwable, throwable_printstacktrace,
+      printstream.obj());
+
+  // Call ByteArrayOutputStream.toString()
+  ScopedJavaLocalRef<jstring> exception_string(
+      env, static_cast<jstring>(
+          env->CallObjectMethod(bytearray_output_stream.obj(),
+                                bytearray_output_stream_tostring)));
+
+  return ConvertJavaStringToUTF8(exception_string);
+}
+
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
new file mode 100644
index 0000000..9df9041
--- /dev/null
+++ b/base/android/jni_android.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_ANDROID_H_
+#define BASE_ANDROID_JNI_ANDROID_H_
+
+#include <jni.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace android {
+
+// Used to mark symbols to be exported in a shared library's symbol table.
+#define JNI_EXPORT __attribute__ ((visibility("default")))
+
+// Used to disable manual JNI registration in binaries that prefer to use native
+// JNI exports for startup performance. This is not compatible with the crazy
+// linker and so defaults to off. Call DisableManualJniRegistration at the very
+// beginning of JNI_OnLoad to use this.
+BASE_EXPORT bool IsManualJniRegistrationDisabled();
+BASE_EXPORT void DisableManualJniRegistration();
+
+// Contains the registration method information for initializing JNI bindings.
+struct RegistrationMethod {
+  const char* name;
+  bool (*func)(JNIEnv* env);
+};
+
+// Attaches the current thread to the VM (if necessary) and return the JNIEnv*.
+BASE_EXPORT JNIEnv* AttachCurrentThread();
+
+// Same to AttachCurrentThread except that thread name will be set to
+// |thread_name| if it is the first call. Otherwise, thread_name won't be
+// changed. AttachCurrentThread() doesn't regard underlying platform thread
+// name, but just resets it to "Thread-???". This function should be called
+// right after new thread is created if it is important to keep thread name.
+BASE_EXPORT JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name);
+
+// Detaches the current thread from VM if it is attached.
+BASE_EXPORT void DetachFromVM();
+
+// Initializes the global JVM. It is not necessarily called before
+// InitApplicationContext().
+BASE_EXPORT void InitVM(JavaVM* vm);
+
+// Returns true if the global JVM has been initialized.
+BASE_EXPORT bool IsVMInitialized();
+
+// Initializes the global application context object. The |context| can be any
+// valid reference to the application context. Internally holds a global ref to
+// the context. InitVM and InitApplicationContext maybe called in either order.
+BASE_EXPORT void InitApplicationContext(JNIEnv* env,
+                                        const JavaRef<jobject>& context);
+
+// Initializes the global ClassLoader used by the GetClass and LazyGetClass
+// methods. This is needed because JNI will use the base ClassLoader when there
+// is no Java code on the stack. The base ClassLoader doesn't know about any of
+// the application classes and will fail to lookup anything other than system
+// classes.
+BASE_EXPORT void InitReplacementClassLoader(
+    JNIEnv* env,
+    const JavaRef<jobject>& class_loader);
+
+// Gets a global ref to the application context set with
+// InitApplicationContext(). Ownership is retained by the function - the caller
+// must NOT release it.
+const BASE_EXPORT jobject GetApplicationContext();
+
+// Finds the class named |class_name| and returns it.
+// Use this method instead of invoking directly the JNI FindClass method (to
+// prevent leaking local references).
+// This method triggers a fatal assertion if the class could not be found.
+// Use HasClass if you need to check whether the class exists.
+BASE_EXPORT ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env,
+                                                const char* class_name);
+
+// The method will initialize |atomic_class_id| to contain a global ref to the
+// class. And will return that ref on subsequent calls.  It's the caller's
+// responsibility to release the ref when it is no longer needed.
+// The caller is responsible to zero-initialize |atomic_method_id|.
+// It's fine to simultaneously call this on multiple threads referencing the
+// same |atomic_method_id|.
+BASE_EXPORT jclass LazyGetClass(
+    JNIEnv* env,
+    const char* class_name,
+    base::subtle::AtomicWord* atomic_class_id);
+
+// This class is a wrapper for JNIEnv Get(Static)MethodID.
+class BASE_EXPORT MethodID {
+ public:
+  enum Type {
+    TYPE_STATIC,
+    TYPE_INSTANCE,
+  };
+
+  // Returns the method ID for the method with the specified name and signature.
+  // This method triggers a fatal assertion if the method could not be found.
+  template<Type type>
+  static jmethodID Get(JNIEnv* env,
+                       jclass clazz,
+                       const char* method_name,
+                       const char* jni_signature);
+
+  // The caller is responsible to zero-initialize |atomic_method_id|.
+  // It's fine to simultaneously call this on multiple threads referencing the
+  // same |atomic_method_id|.
+  template<Type type>
+  static jmethodID LazyGet(JNIEnv* env,
+                           jclass clazz,
+                           const char* method_name,
+                           const char* jni_signature,
+                           base::subtle::AtomicWord* atomic_method_id);
+};
+
+// Returns true if an exception is pending in the provided JNIEnv*.
+BASE_EXPORT bool HasException(JNIEnv* env);
+
+// If an exception is pending in the provided JNIEnv*, this function clears it
+// and returns true.
+BASE_EXPORT bool ClearException(JNIEnv* env);
+
+// This function will call CHECK() macro if there's any pending exception.
+BASE_EXPORT void CheckException(JNIEnv* env);
+
+// This returns a string representation of the java stack trace.
+BASE_EXPORT std::string GetJavaExceptionInfo(JNIEnv* env,
+                                             jthrowable java_throwable);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ANDROID_H_
diff --git a/base/android/jni_android_unittest.cc b/base/android/jni_android_unittest.cc
new file mode 100644
index 0000000..dabd480
--- /dev/null
+++ b/base/android/jni_android_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+base::subtle::AtomicWord g_atomic_id = 0;
+int LazyMethodIDCall(JNIEnv* env, jclass clazz, int p) {
+  jmethodID id = base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, clazz,
+      "abs",
+      "(I)I",
+      &g_atomic_id);
+
+  return env->CallStaticIntMethod(clazz, id, p);
+}
+
+int MethodIDCall(JNIEnv* env, jclass clazz, jmethodID id, int p) {
+  return env->CallStaticIntMethod(clazz, id, p);
+}
+
+}  // namespace
+
+TEST(JNIAndroidMicrobenchmark, MethodId) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jclass> clazz(GetClass(env, "java/lang/Math"));
+  base::Time start_lazy = base::Time::Now();
+  int o = 0;
+  for (int i = 0; i < 1024; ++i)
+    o += LazyMethodIDCall(env, clazz.obj(), i);
+  base::Time end_lazy = base::Time::Now();
+
+  jmethodID id = reinterpret_cast<jmethodID>(g_atomic_id);
+  base::Time start = base::Time::Now();
+  for (int i = 0; i < 1024; ++i)
+    o += MethodIDCall(env, clazz.obj(), id, i);
+  base::Time end = base::Time::Now();
+
+  // On a Galaxy Nexus, results were in the range of:
+  // JNI LazyMethodIDCall (us) 1984
+  // JNI MethodIDCall (us) 1861
+  LOG(ERROR) << "JNI LazyMethodIDCall (us) " <<
+      base::TimeDelta(end_lazy - start_lazy).InMicroseconds();
+  LOG(ERROR) << "JNI MethodIDCall (us) " <<
+      base::TimeDelta(end - start).InMicroseconds();
+  LOG(ERROR) << "JNI " << o;
+}
+
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
new file mode 100644
index 0000000..1bbc669
--- /dev/null
+++ b/base/android/jni_array.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+namespace {
+
+// As |GetArrayLength| makes no guarantees about the returned value (e.g., it
+// may be -1 if |array| is not a valid Java array), provide a safe wrapper
+// that always returns a valid, non-negative size.
+template <typename JavaArrayType>
+size_t SafeGetArrayLength(JNIEnv* env, JavaArrayType jarray) {
+  DCHECK(jarray);
+  jsize length = env->GetArrayLength(jarray);
+  DCHECK_GE(length, 0) << "Invalid array length: " << length;
+  return static_cast<size_t>(std::max(0, length));
+}
+
+}  // namespace
+
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env, const uint8* bytes, size_t len) {
+  jbyteArray byte_array = env->NewByteArray(len);
+  CheckException(env);
+  DCHECK(byte_array);
+
+  env->SetByteArrayRegion(
+      byte_array, 0, len, reinterpret_cast<const jbyte*>(bytes));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
+}
+
+ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const int* ints, size_t len) {
+  jintArray int_array = env->NewIntArray(len);
+  CheckException(env);
+  DCHECK(int_array);
+
+  env->SetIntArrayRegion(
+      int_array, 0, len, reinterpret_cast<const jint*>(ints));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jintArray>(env, int_array);
+}
+
+ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const std::vector<int>& ints) {
+  return ToJavaIntArray(env, ints.data(), ints.size());
+}
+
+ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const int64* longs, size_t len) {
+  jlongArray long_array = env->NewLongArray(len);
+  CheckException(env);
+  DCHECK(long_array);
+
+  env->SetLongArrayRegion(
+      long_array, 0, len, reinterpret_cast<const jlong*>(longs));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jlongArray>(env, long_array);
+}
+
+// Returns a new Java long array converted from the given int64 array.
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const std::vector<int64>& longs) {
+  return ToJavaLongArray(env, longs.data(), longs.size());
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+    JNIEnv* env, const std::vector<std::string>& v) {
+  ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
+  jobjectArray joa = env->NewObjectArray(v.size(),
+                                         byte_array_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env,
+        reinterpret_cast<const uint8*>(v[i].data()), v[i].length());
+    env->SetObjectArrayElement(joa, i, byte_array.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env, const std::vector<std::string>& v) {
+  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env, const std::vector<string16>& v) {
+  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<string16>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  size_t len = SafeGetArrayLength(env, array);
+  size_t back = out->size();
+  out->resize(back + len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i]));
+  }
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<std::string>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  size_t len = SafeGetArrayLength(env, array);
+  size_t back = out->size();
+  out->resize(back + len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i]));
+  }
+}
+
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+                                     jbyteArray byte_array,
+                                     std::vector<uint8>* out) {
+  DCHECK(out);
+  if (!byte_array)
+    return;
+  size_t len = SafeGetArrayLength(env, byte_array);
+  if (!len)
+    return;
+  size_t back = out->size();
+  out->resize(back + len);
+  env->GetByteArrayRegion(byte_array, 0, len,
+                          reinterpret_cast<int8*>(&(*out)[back]));
+}
+
+void JavaByteArrayToByteVector(JNIEnv* env,
+                               jbyteArray byte_array,
+                               std::vector<uint8>* out) {
+  DCHECK(out);
+  DCHECK(byte_array);
+  out->clear();
+  AppendJavaByteArrayToByteVector(env, byte_array, out);
+}
+
+void JavaIntArrayToIntVector(JNIEnv* env,
+                             jintArray int_array,
+                             std::vector<int>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, int_array);
+  out->resize(len);
+  if (!len)
+    return;
+  // TODO(jdduke): Use |out->data()| for pointer access after switch to libc++,
+  // both here and in the other conversion routines. See crbug.com/427718.
+  env->GetIntArrayRegion(int_array, 0, len, &(*out)[0]);
+}
+
+void JavaLongArrayToLongVector(JNIEnv* env,
+                               jlongArray long_array,
+                               std::vector<jlong>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, long_array);
+  out->resize(len);
+  if (!len)
+    return;
+  env->GetLongArrayRegion(long_array, 0, len, &(*out)[0]);
+}
+
+void JavaFloatArrayToFloatVector(JNIEnv* env,
+                                 jfloatArray float_array,
+                                 std::vector<float>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, float_array);
+  out->resize(len);
+  if (!len)
+    return;
+  env->GetFloatArrayRegion(float_array, 0, len, &(*out)[0]);
+}
+
+void JavaArrayOfByteArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, array);
+  out->resize(len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jbyteArray> bytes_array(
+        env, static_cast<jbyteArray>(
+            env->GetObjectArrayElement(array, i)));
+    jsize bytes_len = env->GetArrayLength(bytes_array.obj());
+    jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), NULL);
+    (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
+    env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
new file mode 100644
index 0000000..0d7ec2e
--- /dev/null
+++ b/base/android/jni_array.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_ARRAY_H_
+#define BASE_ANDROID_JNI_ARRAY_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace android {
+
+// Returns a new Java byte array converted from the given bytes array.
+BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env, const uint8* bytes, size_t len);
+
+// Returns a new Java int array converted from the given int array.
+BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const int* ints, size_t len);
+
+BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const std::vector<int>& ints);
+
+// Returns a new Java long array converted from the given int64 array.
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const int64* longs, size_t len);
+
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const std::vector<int64>& longs);
+
+// Returns a array of Java byte array converted from |v|.
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+    JNIEnv* env, const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env,  const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env,  const std::vector<string16>& v);
+
+// Converts a Java string array to a native array.
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<string16>* out);
+
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out);
+
+// Appends the Java bytes in |bytes_array| onto the end of |out|.
+BASE_EXPORT void AppendJavaByteArrayToByteVector(
+    JNIEnv* env,
+    jbyteArray byte_array,
+    std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java bytes in |bytes_array|.
+BASE_EXPORT void JavaByteArrayToByteVector(
+    JNIEnv* env,
+    jbyteArray byte_array,
+    std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java ints in |int_array|.
+BASE_EXPORT void JavaIntArrayToIntVector(
+    JNIEnv* env,
+    jintArray int_array,
+    std::vector<int>* out);
+
+// Replaces the content of |out| with the Java longs in |long_array|.
+BASE_EXPORT void JavaLongArrayToLongVector(
+    JNIEnv* env,
+    jlongArray long_array,
+    std::vector<jlong>* out);
+
+// Replaces the content of |out| with the Java floats in |float_array|.
+BASE_EXPORT void JavaFloatArrayToFloatVector(
+    JNIEnv* env,
+    jfloatArray float_array,
+    std::vector<float>* out);
+
+// Assuming |array| is an byte[][] (array of byte arrays), replaces the
+// content of |out| with the corresponding vector of strings. No UTF-8
+// conversion is performed.
+BASE_EXPORT void JavaArrayOfByteArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
new file mode 100644
index 0000000..7cb896c
--- /dev/null
+++ b/base/android/jni_array_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniArray, BasicConversions) {
+  const uint8 kBytes[] = { 0, 1, 2, 3 };
+  const size_t kLen = arraysize(kBytes);
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen);
+  ASSERT_TRUE(bytes.obj());
+
+  std::vector<uint8> vec(5);
+  JavaByteArrayToByteVector(env, bytes.obj(), &vec);
+  EXPECT_EQ(4U, vec.size());
+  std::vector<uint8> expected_vec(kBytes, kBytes + kLen);
+  EXPECT_EQ(expected_vec, vec);
+
+  AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec);
+  EXPECT_EQ(8U, vec.size());
+  expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen);
+  EXPECT_EQ(expected_vec, vec);
+}
+
+void CheckIntConversion(
+    JNIEnv* env,
+    const int* int_array,
+    const size_t len,
+    const ScopedJavaLocalRef<jintArray>& ints) {
+  ASSERT_TRUE(ints.obj());
+
+  jsize java_array_len = env->GetArrayLength(ints.obj());
+  ASSERT_EQ(static_cast<jsize>(len), java_array_len);
+
+  jint value;
+  for (size_t i = 0; i < len; ++i) {
+    env->GetIntArrayRegion(ints.obj(), i, 1, &value);
+    ASSERT_EQ(int_array[i], value);
+  }
+}
+
+TEST(JniArray, IntConversions) {
+  const int kInts[] = { 0, 1, -1, kint32min, kint32max};
+  const size_t kLen = arraysize(kInts);
+
+  JNIEnv* env = AttachCurrentThread();
+  CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, kInts, kLen));
+
+  const std::vector<int> vec(kInts, kInts + kLen);
+  CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, vec));
+}
+
+void CheckLongConversion(
+    JNIEnv* env,
+    const int64* long_array,
+    const size_t len,
+    const ScopedJavaLocalRef<jlongArray>& longs) {
+  ASSERT_TRUE(longs.obj());
+
+  jsize java_array_len = env->GetArrayLength(longs.obj());
+  ASSERT_EQ(static_cast<jsize>(len), java_array_len);
+
+  jlong value;
+  for (size_t i = 0; i < len; ++i) {
+    env->GetLongArrayRegion(longs.obj(), i, 1, &value);
+    ASSERT_EQ(long_array[i], value);
+  }
+}
+
+TEST(JniArray, LongConversions) {
+  const int64 kLongs[] = { 0, 1, -1, kint64min, kint64max};
+  const size_t kLen = arraysize(kLongs);
+
+  JNIEnv* env = AttachCurrentThread();
+  CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen));
+
+  const std::vector<int64> vec(kLongs, kLongs + kLen);
+  CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec));
+}
+
+TEST(JniArray, JavaIntArrayToIntVector) {
+  const int kInts[] = {0, 1, -1};
+  const size_t kLen = arraysize(kInts);
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kLen));
+  ASSERT_TRUE(jints.obj());
+
+  for (size_t i = 0; i < kLen; ++i) {
+    jint j = static_cast<jint>(kInts[i]);
+    env->SetIntArrayRegion(jints.obj(), i, 1, &j);
+    ASSERT_FALSE(HasException(env));
+  }
+
+  std::vector<int> ints;
+  JavaIntArrayToIntVector(env, jints.obj(), &ints);
+
+  ASSERT_EQ(static_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj()));
+
+  jint value;
+  for (size_t i = 0; i < kLen; ++i) {
+    env->GetIntArrayRegion(jints.obj(), i, 1, &value);
+    ASSERT_EQ(ints[i], value);
+  }
+}
+
+TEST(JniArray, JavaFloatArrayToFloatVector) {
+  const float kFloats[] = {0.0, 0.5, -0.5};
+  const size_t kLen = arraysize(kFloats);
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jfloatArray> jfloats(env, env->NewFloatArray(kLen));
+  ASSERT_TRUE(jfloats.obj());
+
+  for (size_t i = 0; i < kLen; ++i) {
+    jfloat j = static_cast<jfloat>(kFloats[i]);
+    env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j);
+    ASSERT_FALSE(HasException(env));
+  }
+
+  std::vector<float> floats;
+  JavaFloatArrayToFloatVector(env, jfloats.obj(), &floats);
+
+  ASSERT_EQ(static_cast<jsize>(floats.size()),
+      env->GetArrayLength(jfloats.obj()));
+
+  jfloat value;
+  for (size_t i = 0; i < kLen; ++i) {
+    env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value);
+    ASSERT_EQ(floats[i], value);
+  }
+}
+
+TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
+  const int kMaxItems = 50;
+  JNIEnv* env = AttachCurrentThread();
+
+  // Create a byte[][] object.
+  ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+  ASSERT_TRUE(byte_array_clazz.obj());
+
+  ScopedJavaLocalRef<jobjectArray> array(
+      env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
+  ASSERT_TRUE(array.obj());
+
+  // Create kMaxItems byte buffers.
+  char text[16];
+  for (int i = 0; i < kMaxItems; ++i) {
+    snprintf(text, sizeof text, "%d", i);
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
+        env, reinterpret_cast<uint8*>(text),
+        static_cast<size_t>(strlen(text)));
+    ASSERT_TRUE(byte_array.obj());
+
+    env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
+    ASSERT_FALSE(HasException(env));
+  }
+
+  // Convert to std::vector<std::string>, check the content.
+  std::vector<std::string> vec;
+  JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec);
+
+  EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
+  for (int i = 0; i < kMaxItems; ++i) {
+    snprintf(text, sizeof text, "%d", i);
+    EXPECT_STREQ(text, vec[i].c_str());
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_generator/android_jar.classes b/base/android/jni_generator/android_jar.classes
new file mode 100644
index 0000000..7d412ce
--- /dev/null
+++ b/base/android/jni_generator/android_jar.classes
@@ -0,0 +1,98 @@
+java/lang/AbstractMethodError.class
+java/lang/AbstractStringBuilder.class
+java/lang/Appendable.class
+java/lang/ArithmeticException.class
+java/lang/ArrayIndexOutOfBoundsException.class
+java/lang/ArrayStoreException.class
+java/lang/AssertionError.class
+java/lang/AutoCloseable.class
+java/lang/Boolean.class
+java/lang/Byte.class
+java/lang/Character.class
+java/lang/Character$Subset.class
+java/lang/Character$UnicodeBlock.class
+java/lang/CharSequence.class
+java/lang/ClassCastException.class
+java/lang/ClassCircularityError.class
+java/lang/Class.class
+java/lang/ClassFormatError.class
+java/lang/ClassLoader.class
+java/lang/ClassNotFoundException.class
+java/lang/Cloneable.class
+java/lang/CloneNotSupportedException.class
+java/lang/Comparable.class
+java/lang/Compiler.class
+java/lang/Deprecated.class
+java/lang/Double.class
+java/lang/Enum.class
+java/lang/EnumConstantNotPresentException.class
+java/lang/Error.class
+java/lang/Exception.class
+java/lang/ExceptionInInitializerError.class
+java/lang/Float.class
+java/lang/IllegalAccessError.class
+java/lang/IllegalAccessException.class
+java/lang/IllegalArgumentException.class
+java/lang/IllegalMonitorStateException.class
+java/lang/IllegalStateException.class
+java/lang/IncompatibleClassChangeError.class
+java/lang/IndexOutOfBoundsException.class
+java/lang/InheritableThreadLocal.class
+java/lang/InstantiationError.class
+java/lang/InstantiationException.class
+java/lang/Integer.class
+java/lang/InternalError.class
+java/lang/InterruptedException.class
+java/lang/Iterable.class
+java/lang/LinkageError.class
+java/lang/Long.class
+java/lang/Math.class
+java/lang/NegativeArraySizeException.class
+java/lang/NoClassDefFoundError.class
+java/lang/NoSuchFieldError.class
+java/lang/NoSuchFieldException.class
+java/lang/NoSuchMethodError.class
+java/lang/NoSuchMethodException.class
+java/lang/NullPointerException.class
+java/lang/Number.class
+java/lang/NumberFormatException.class
+java/lang/Object.class
+java/lang/OutOfMemoryError.class
+java/lang/Override.class
+java/lang/Package.class
+java/lang/ProcessBuilder.class
+java/lang/Process.class
+java/lang/Readable.class
+java/lang/ReflectiveOperationException.class
+java/lang/Runnable.class
+java/lang/Runtime.class
+java/lang/RuntimeException.class
+java/lang/RuntimePermission.class
+java/lang/SafeVarargs.class
+java/lang/SecurityException.class
+java/lang/SecurityManager.class
+java/lang/Short.class
+java/lang/StackOverflowError.class
+java/lang/StackTraceElement.class
+java/lang/StrictMath.class
+java/lang/StringBuffer.class
+java/lang/StringBuilder.class
+java/lang/String.class
+java/lang/StringIndexOutOfBoundsException.class
+java/lang/SuppressWarnings.class
+java/lang/System.class
+java/lang/Thread.class
+java/lang/ThreadDeath.class
+java/lang/ThreadGroup.class
+java/lang/ThreadLocal.class
+java/lang/Thread$State.class
+java/lang/Thread$UncaughtExceptionHandler.class
+java/lang/Throwable.class
+java/lang/TypeNotPresentException.class
+java/lang/UnknownError.class
+java/lang/UnsatisfiedLinkError.class
+java/lang/UnsupportedClassVersionError.class
+java/lang/UnsupportedOperationException.class
+java/lang/VerifyError.class
+java/lang/VirtualMachineError.class
+java/lang/Void.class
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
new file mode 100644
index 0000000..ba7494e
--- /dev/null
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -0,0 +1,400 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kInnerStructAClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests$InnerStructA";
+const char kSampleForTestsClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests";
+const char kInnerStructBClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests$InnerStructB";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InnerStructA_clazz = NULL;
+#define InnerStructA_clazz(env) g_InnerStructA_clazz
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_SampleForTests_clazz = NULL;
+#define SampleForTests_clazz(env) g_SampleForTests_clazz
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InnerStructB_clazz = NULL;
+#define InnerStructB_clazz(env) g_InnerStructB_clazz
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+static jlong Init(JNIEnv* env, jobject jcaller,
+    jstring param);
+
+static jdouble GetDoubleFunction(JNIEnv* env, jobject jcaller);
+
+static jfloat GetFloatFunction(JNIEnv* env, jclass jcaller);
+
+static void SetNonPODDatatype(JNIEnv* env, jobject jcaller,
+    jobject rect);
+
+static jobject GetNonPODDatatype(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
+  return native->Destroy(env, jcaller);
+}
+
+static jint Method(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller);
+}
+
+static jdouble MethodOtherP0(JNIEnv* env, jobject jcaller,
+    jlong nativePtr) {
+  CPPClass::InnerClass* native =
+      reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
+  CHECK_NATIVE_PTR(env, jcaller, native, "MethodOtherP0", 0);
+  return native->MethodOtherP0(env, jcaller);
+}
+
+static void AddStructB(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass,
+    jobject b) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "AddStructB");
+  return native->AddStructB(env, jcaller, b);
+}
+
+static void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
+  return native->IterateAndDoSomethingWithStructB(env, jcaller);
+}
+
+static jstring ReturnAString(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "ReturnAString", NULL);
+  return native->ReturnAString(env, jcaller).Release();
+}
+
+static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
+static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj,
+    JniIntWrapper foo,
+    JniIntWrapper bar) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "javaMethod",
+
+"("
+"I"
+"I"
+")"
+"I",
+      &g_SampleForTests_javaMethod);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(foo), as_jint(bar));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
+static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), false);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "staticJavaMethod",
+
+"("
+")"
+"Z",
+      &g_SampleForTests_staticJavaMethod);
+
+  jboolean ret =
+      env->CallStaticBooleanMethod(SampleForTests_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0;
+static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
+    obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "packagePrivateJavaMethod",
+
+"("
+")"
+"V",
+      &g_SampleForTests_packagePrivateJavaMethod);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0;
+static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
+    obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "methodThatThrowsException",
+
+"("
+")"
+"V",
+      &g_SampleForTests_methodThatThrowsException);
+
+     env->CallVoidMethod(obj,
+          method_id);
+
+}
+
+static base::subtle::AtomicWord g_InnerStructA_create = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InnerStructA_create(JNIEnv* env, jlong l,
+    JniIntWrapper i,
+    jstring s) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, InnerStructA_clazz(env),
+      InnerStructA_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, InnerStructA_clazz(env),
+      "create",
+
+"("
+"J"
+"I"
+"Ljava/lang/String;"
+")"
+"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;",
+      &g_InnerStructA_create);
+
+  jobject ret =
+      env->CallStaticObjectMethod(InnerStructA_clazz(env),
+          method_id, l, as_jint(i), s);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_addStructA = 0;
+static void Java_SampleForTests_addStructA(JNIEnv* env, jobject obj, jobject a)
+    {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "addStructA",
+
+"("
+"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;"
+")"
+"V",
+      &g_SampleForTests_addStructA);
+
+     env->CallVoidMethod(obj,
+          method_id, a);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_iterateAndDoSomething = 0;
+static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, jobject obj)
+    {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "iterateAndDoSomething",
+
+"("
+")"
+"V",
+      &g_SampleForTests_iterateAndDoSomething);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InnerStructB_getKey = 0;
+static jlong Java_InnerStructB_getKey(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InnerStructB_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InnerStructB_clazz(env),
+      "getKey",
+
+"("
+")"
+"J",
+      &g_InnerStructB_getKey);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InnerStructB_getValue = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_InnerStructB_getValue(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InnerStructB_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InnerStructB_clazz(env),
+      "getValue",
+
+"("
+")"
+"Ljava/lang/String;",
+      &g_InnerStructB_getValue);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsSampleForTests[] = {
+    { "nativeInit",
+"("
+"Ljava/lang/String;"
+")"
+"J", reinterpret_cast<void*>(Init) },
+    { "nativeDestroy",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+    { "nativeGetDoubleFunction",
+"("
+")"
+"D", reinterpret_cast<void*>(GetDoubleFunction) },
+    { "nativeGetFloatFunction",
+"("
+")"
+"F", reinterpret_cast<void*>(GetFloatFunction) },
+    { "nativeSetNonPODDatatype",
+"("
+"Landroid/graphics/Rect;"
+")"
+"V", reinterpret_cast<void*>(SetNonPODDatatype) },
+    { "nativeGetNonPODDatatype",
+"("
+")"
+"Ljava/lang/Object;", reinterpret_cast<void*>(GetNonPODDatatype) },
+    { "nativeMethod",
+"("
+"J"
+")"
+"I", reinterpret_cast<void*>(Method) },
+    { "nativeMethodOtherP0",
+"("
+"J"
+")"
+"D", reinterpret_cast<void*>(MethodOtherP0) },
+    { "nativeAddStructB",
+"("
+"J"
+"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructB;"
+")"
+"V", reinterpret_cast<void*>(AddStructB) },
+    { "nativeIterateAndDoSomethingWithStructB",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(IterateAndDoSomethingWithStructB) },
+    { "nativeReturnAString",
+"("
+"J"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(ReturnAString) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_InnerStructA_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInnerStructAClassPath).obj()));
+  g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kSampleForTestsClassPath).obj()));
+  g_InnerStructB_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInnerStructBClassPath).obj()));
+
+  const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
+
+  if (env->RegisterNatives(SampleForTests_clazz(env),
+                           kMethodsSampleForTests,
+                           kMethodsSampleForTestsSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, SampleForTests_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace android
+}  // namespace base
+
+#endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
new file mode 100644
index 0000000..89bee99
--- /dev/null
+++ b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
@@ -0,0 +1,305 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.example.jni_generator;
+
+import android.graphics.Rect;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.NativeClassQualifiedName;
+import org.chromium.base.annotations.AccessedByNative;
+import org.chromium.base.annotations.CalledByNativeUnchecked;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+// This class serves as a reference test for the bindings generator, and as example documentation
+// for how to use the jni generator.
+// The C++ counter-part is sample_for_tests.cc.
+// jni_generator.gyp has a jni_generator_tests target that will:
+//   * Generate a header file for the JNI bindings based on this file.
+//   * Compile sample_for_tests.cc using the generated header file.
+//   * link a native executable to prove the generated header + cc file are self-contained.
+// All comments are informational only, and are ignored by the jni generator.
+//
+// Binding C/C++ with Java is not trivial, specially when ownership and object lifetime
+// semantics needs to be managed across boundaries.
+// Following a few guidelines will make the code simpler and less buggy:
+//
+// - Never write any JNI "by hand". Rely on the bindings generator to have a thin
+// layer of type-safety.
+//
+// - Treat the types from the other side as "opaque" as possible. Do not inspect any
+// object directly, but rather, rely on well-defined getters / setters.
+//
+// - Minimize the surface API between the two sides, and rather than calling multiple
+// functions across boundaries, call only one (and then, internally in the other side,
+// call as many little functions as required).
+//
+// - If a Java object "owns" a native object, stash the pointer in a "long mNativeClassName".
+// Note that it needs to have a "destruction path", i.e., it must eventually call a method
+// to delete the native object (for example, the java object has a "close()" method that
+// in turn deletes the native object). Avoid relying on finalizers: those run in a different
+// thread and makes the native lifetime management more difficult.
+//
+// - For native object "owning" java objects:
+//   - If there's a strong 1:1 to relationship between native and java, the best way is to
+//   stash the java object into a base::android::ScopedJavaGlobalRef. This will ensure the
+//   java object can be GC'd once the native object is destroyed but note that this global strong
+//   ref implies a new GC root, so be sure it will not leak and it must never rely on being
+//   triggered (transitively) from a java side GC.
+//   - In all other cases, the native side should keep a JavaObjectWeakGlobalRef, and check whether
+//   that reference is still valid before de-referencing it. Note that you will need another
+//   java-side object to be holding a strong reference to this java object while it is in use, to
+//   avoid unpredictable GC of the object before native side has finished with it.
+//
+// - The best way to pass "compound" datatypes across in either direction is to create an inner
+// class with PODs and a factory function. If possible, make it immutable (i.e., mark all the
+// fields as "final"). See examples with "InnerStructB" below.
+//
+// - It's simpler to create thin wrappers with a well defined JNI interface than to
+// expose a lot of internal details. This is specially significant for system classes where it's
+// simpler to wrap factory methods and a few getters / setters than expose the entire class.
+//
+// - Use static factory functions annotated with @CalledByNative rather than calling the
+// constructors directly.
+//
+// - Iterate over containers where they are originally owned, then create inner structs or
+// directly call methods on the other side. It's much simpler than trying to amalgamate
+// java and stl containers.
+//
+// An important note about qualified class name resolution:
+// The generator doesn't compile the class and have little context about the
+// classes being passed through the JNI layers. It adds a few simple rules:
+//
+// - all classes are either explicitly imported, or they are assumed to be in
+// the same package.
+//
+// - Inner class needs to be done through an import and usage of the
+// outer class, so that the generator knows how to qualify it:
+// import foo.bar.Zoo;
+// void call(Zoo.Inner);
+//
+// - implicitly imported classes aren't supported, so in order to pass
+// things like Runnable, please import java.lang.Runnable;
+//
+// This JNINamespace annotation indicates that all native methods should be
+// generated inside this namespace, including the native class that this
+// object binds to.
+@JNINamespace("base::android")
+class SampleForTests {
+    // Classes can store their C++ pointer counter part as an int that is normally initialized by
+    // calling out a nativeInit() function.
+    long mNativeCPPObject;
+
+    // You can define methods and attributes on the java class just like any other.
+    // Methods without the @CalledByNative annotation won't be exposed to JNI.
+    public SampleForTests() {
+    }
+
+    public void startExample() {
+        // Calls native code and holds a pointer to the C++ class.
+        mNativeCPPObject = nativeInit("myParam");
+    }
+
+    public void doStuff() {
+        // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must
+        // be done to:
+        // * avoid leaks.
+        // * using finalizers are not allowed to destroy the cpp class.
+        nativeMethod(mNativeCPPObject);
+    }
+
+    public void finishExample() {
+        // We're done, so let's destroy nativePtr object.
+        nativeDestroy(mNativeCPPObject);
+    }
+
+    // ---------------------------------------------------------------------------------------------
+    // The following methods demonstrate exporting Java methods for invocation from C++ code.
+    // Java functions are mapping into C global functions by prefixing the method name with
+    // "Java_<Class>_"
+    // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
+
+    // Exported to C++ as:
+    // Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar)
+    // Typically the C++ code would have obtained the jobject via the Init() call described above.
+    @CalledByNative
+    public int javaMethod(int foo, int bar) {
+        return 0;
+    }
+
+    // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env)
+    // Note no jobject argument, as it is static.
+    @CalledByNative
+    public static boolean staticJavaMethod() {
+        return true;
+    }
+
+    // No prefix, so this method is package private. It will still be exported.
+    @CalledByNative
+    void packagePrivateJavaMethod() {
+    }
+
+    // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
+    // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
+    // call ClearException() and act as appropriate.
+    // See more details at the "@CalledByNativeUnchecked" annotation.
+    @CalledByNativeUnchecked
+    void methodThatThrowsException() throws Exception {}
+
+    // The generator is not confused by inline comments:
+    // @CalledByNative void thisShouldNotAppearInTheOutput();
+    // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
+
+    /**
+     * The generator is not confused by block comments:
+     * @CalledByNative void thisShouldNotAppearInTheOutputEither();
+     * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
+     */
+
+    // String constants that look like comments don't confuse the generator:
+    private String mArrgh = "*/*";
+
+    // ---------------------------------------------------------------------------------------------
+    // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
+    // prevent them being eliminated when unreferenced code is stripped.
+    @AccessedByNative
+    private int mJavaField;
+
+    // ---------------------------------------------------------------------------------------------
+    // The following methods demonstrate declaring methods to call into C++ from Java.
+    // The generator detects the "native" and "static" keywords, the type and name of the first
+    // parameter, and the "native" prefix to the function name to determine the C++ function
+    // signatures. Besides these constraints the methods can be freely named.
+
+    // This declares a C++ function which the application code must implement:
+    // static jint Init(JNIEnv* env, jobject obj);
+    // The jobject parameter refers back to this java side object instance.
+    // The implementation must return the pointer to the C++ object cast to jint.
+    // The caller of this method should store it, and supply it as a the nativeCPPClass param to
+    // subsequent native method calls (see the methods below that take an "int native..." as first
+    // param).
+    private native long nativeInit(String param);
+
+    // This defines a function binding to the associated C++ class member function. The name is
+    // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e.
+    // native
+    // prefixes stripped).
+    // The |nativeCPPClass| is automatically cast to type CPPClass* in order to obtain the object on
+    // which to invoke the member function.
+    private native void nativeDestroy(long nativeCPPClass);
+
+    // This declares a C++ function which the application code must implement:
+    // static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+    // The jobject parameter refers back to this java side object instance.
+    private native double nativeGetDoubleFunction();
+
+    // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than
+    // jobject param, as the function is declared static.
+    private static native float nativeGetFloatFunction();
+
+    // This function takes a non-POD datatype. We have a list mapping them to their full classpath
+    // in
+    // jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that
+    // function.
+    private native void nativeSetNonPODDatatype(Rect rect);
+
+    // This declares a C++ function which the application code must implement:
+    // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
+    // The jobject parameter refers back to this java side object instance.
+    // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
+    // deleting the JNI local reference. This is similar with Strings and arrays.
+    private native Object nativeGetNonPODDatatype();
+
+    // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type
+    // and
+    // call its Method member function.
+    private native int nativeMethod(long nativeCPPClass);
+
+    // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
+    // annotation rather than parameter name, which can thus be chosen freely.
+    @NativeClassQualifiedName("CPPClass::InnerClass")
+    private native double nativeMethodOtherP0(long nativePtr);
+
+    // This "struct" will be created by the native side using |createInnerStructA|,
+    // and used by the java-side somehow.
+    // Note that |@CalledByNative| has to contain the inner class name.
+    static class InnerStructA {
+        private final long mLong;
+        private final int mInt;
+        private final String mString;
+
+        private InnerStructA(long l, int i, String s) {
+            mLong = l;
+            mInt = i;
+            mString = s;
+        }
+
+        @CalledByNative("InnerStructA")
+        private static InnerStructA create(long l, int i, String s) {
+            return new InnerStructA(l, i, s);
+        }
+    }
+
+    private List<InnerStructA> mListInnerStructA = new ArrayList<InnerStructA>();
+
+    @CalledByNative
+    private void addStructA(InnerStructA a) {
+        // Called by the native side to append another element.
+        mListInnerStructA.add(a);
+    }
+
+    @CalledByNative
+    private void iterateAndDoSomething() {
+        Iterator<InnerStructA> it = mListInnerStructA.iterator();
+        while (it.hasNext()) {
+            InnerStructA element = it.next();
+            // Now, do something with element.
+        }
+        // Done, clear the list.
+        mListInnerStructA.clear();
+    }
+
+    // This "struct" will be created by the java side passed to native, which
+    // will use its getters.
+    // Note that |@CalledByNative| has to contain the inner class name.
+    static class InnerStructB {
+        private final long mKey;
+        private final String mValue;
+
+        private InnerStructB(long k, String v) {
+            mKey = k;
+            mValue = v;
+        }
+
+        @CalledByNative("InnerStructB")
+        private long getKey() {
+            return mKey;
+        }
+
+        @CalledByNative("InnerStructB")
+        private String getValue() {
+            return mValue;
+        }
+    }
+
+    List<InnerStructB> mListInnerStructB = new ArrayList<InnerStructB>();
+
+    void iterateAndDoSomethingWithMap() {
+        Iterator<InnerStructB> it = mListInnerStructB.iterator();
+        while (it.hasNext()) {
+            InnerStructB element = it.next();
+            // Now, do something with element.
+            nativeAddStructB(mNativeCPPObject, element);
+        }
+        nativeIterateAndDoSomethingWithStructB(mNativeCPPObject);
+    }
+
+    native void nativeAddStructB(long nativeCPPClass, InnerStructB b);
+    native void nativeIterateAndDoSomethingWithStructB(long nativeCPPClass);
+    native String nativeReturnAString(long nativeCPPClass);
+}
diff --git a/base/android/jni_generator/jni_generator.gyp b/base/android/jni_generator/jni_generator.gyp
new file mode 100644
index 0000000..4a17f3e
--- /dev/null
+++ b/base/android/jni_generator/jni_generator.gyp
@@ -0,0 +1,68 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'jni_generator_py_tests',
+      'type': 'none',
+      'variables': {
+        'stamp': '<(INTERMEDIATE_DIR)/jni_generator_py_tests.stamp',
+      },
+      'actions': [
+        {
+          'action_name': 'run_jni_generator_py_tests',
+          'inputs': [
+            'jni_generator.py',
+            'jni_generator_tests.py',
+            'java/src/org/chromium/example/jni_generator/SampleForTests.java',
+            'golden_sample_for_tests_jni.h',
+          ],
+          'outputs': [
+            '<(stamp)',
+          ],
+          'action': [
+            'python', 'jni_generator_tests.py',
+            '--stamp=<(stamp)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'jni_sample_header',
+      'type': 'none',
+      'sources': [
+        'java/src/org/chromium/example/jni_generator/SampleForTests.java',
+      ],
+      'variables': {
+        'jni_gen_package': 'example',
+      },
+      'includes': [ '../../../build/jni_generator.gypi' ],
+    },
+    {
+      'target_name': 'jni_sample_java',
+      'type': 'none',
+      'variables': {
+        'java_in_dir': '../../../base/android/jni_generator/java',
+      },
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base_java',
+      ],
+      'includes': [ '../../../build/java.gypi' ],
+    },
+    {
+      'target_name': 'jni_generator_tests',
+      'type': 'executable',
+      'dependencies': [
+        '../../base.gyp:test_support_base',
+        'jni_generator_py_tests',
+        'jni_sample_header',
+        'jni_sample_java',
+      ],
+      'sources': [
+        'sample_for_tests.cc',
+      ],
+    },
+  ],
+}
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
new file mode 100755
index 0000000..fd03f0e
--- /dev/null
+++ b/base/android/jni_generator/jni_generator.py
@@ -0,0 +1,1557 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Extracts native methods from a Java file and generates the JNI bindings.
+If you change this, please run and update the tests."""
+
+import collections
+import errno
+import optparse
+import os
+import re
+import string
+from string import Template
+import subprocess
+import sys
+import textwrap
+import zipfile
+
+CHROMIUM_SRC = os.path.join(
+    os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)
+BUILD_ANDROID_GYP = os.path.join(
+    CHROMIUM_SRC, 'build', 'android', 'gyp')
+
+sys.path.append(BUILD_ANDROID_GYP)
+
+from util import build_utils
+
+
+class ParseError(Exception):
+  """Exception thrown when we can't parse the input file."""
+
+  def __init__(self, description, *context_lines):
+    Exception.__init__(self)
+    self.description = description
+    self.context_lines = context_lines
+
+  def __str__(self):
+    context = '\n'.join(self.context_lines)
+    return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
+
+
+class Param(object):
+  """Describes a param for a method, either java or native."""
+
+  def __init__(self, **kwargs):
+    self.datatype = kwargs['datatype']
+    self.name = kwargs['name']
+
+
+class NativeMethod(object):
+  """Describes a C/C++ method that is called by Java code"""
+
+  def __init__(self, **kwargs):
+    self.static = kwargs['static']
+    self.java_class_name = kwargs['java_class_name']
+    self.return_type = kwargs['return_type']
+    self.name = kwargs['name']
+    self.params = kwargs['params']
+    if self.params:
+      assert type(self.params) is list
+      assert type(self.params[0]) is Param
+    if (self.params and
+        self.params[0].datatype == kwargs.get('ptr_type', 'int') and
+        self.params[0].name.startswith('native')):
+      self.type = 'method'
+      self.p0_type = self.params[0].name[len('native'):]
+      if kwargs.get('native_class_name'):
+        self.p0_type = kwargs['native_class_name']
+    else:
+      self.type = 'function'
+    self.method_id_var_name = kwargs.get('method_id_var_name', None)
+
+
+class CalledByNative(object):
+  """Describes a java method exported to c/c++"""
+
+  def __init__(self, **kwargs):
+    self.system_class = kwargs['system_class']
+    self.unchecked = kwargs['unchecked']
+    self.static = kwargs['static']
+    self.java_class_name = kwargs['java_class_name']
+    self.return_type = kwargs['return_type']
+    self.name = kwargs['name']
+    self.params = kwargs['params']
+    self.method_id_var_name = kwargs.get('method_id_var_name', None)
+    self.signature = kwargs.get('signature')
+    self.is_constructor = kwargs.get('is_constructor', False)
+    self.env_call = GetEnvCall(self.is_constructor, self.static,
+                               self.return_type)
+    self.static_cast = GetStaticCastForReturnType(self.return_type)
+
+
+class ConstantField(object):
+  def __init__(self, **kwargs):
+    self.name = kwargs['name']
+    self.value = kwargs['value']
+
+
+def JavaDataTypeToC(java_type):
+  """Returns a C datatype for the given java type."""
+  java_pod_type_map = {
+      'int': 'jint',
+      'byte': 'jbyte',
+      'char': 'jchar',
+      'short': 'jshort',
+      'boolean': 'jboolean',
+      'long': 'jlong',
+      'double': 'jdouble',
+      'float': 'jfloat',
+  }
+  java_type_map = {
+      'void': 'void',
+      'String': 'jstring',
+      'java/lang/String': 'jstring',
+      'java/lang/Class': 'jclass',
+  }
+
+  if java_type in java_pod_type_map:
+    return java_pod_type_map[java_type]
+  elif java_type in java_type_map:
+    return java_type_map[java_type]
+  elif java_type.endswith('[]'):
+    if java_type[:-2] in java_pod_type_map:
+      return java_pod_type_map[java_type[:-2]] + 'Array'
+    return 'jobjectArray'
+  elif java_type.startswith('Class'):
+    # Checking just the start of the name, rather than a direct comparison,
+    # in order to handle generics.
+    return 'jclass'
+  else:
+    return 'jobject'
+
+
+def JavaDataTypeToCForCalledByNativeParam(java_type):
+  """Returns a C datatype to be when calling from native."""
+  if java_type == 'int':
+    return 'JniIntWrapper'
+  else:
+    return JavaDataTypeToC(java_type)
+
+
+def JavaReturnValueToC(java_type):
+  """Returns a valid C return value for the given java type."""
+  java_pod_type_map = {
+      'int': '0',
+      'byte': '0',
+      'char': '0',
+      'short': '0',
+      'boolean': 'false',
+      'long': '0',
+      'double': '0',
+      'float': '0',
+      'void': ''
+  }
+  return java_pod_type_map.get(java_type, 'NULL')
+
+
+class JniParams(object):
+  _imports = []
+  _fully_qualified_class = ''
+  _package = ''
+  _inner_classes = []
+  _remappings = []
+  _implicit_imports = []
+
+  @staticmethod
+  def SetFullyQualifiedClass(fully_qualified_class):
+    JniParams._fully_qualified_class = 'L' + fully_qualified_class
+    JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
+
+  @staticmethod
+  def AddAdditionalImport(class_name):
+    assert class_name.endswith('.class')
+    raw_class_name = class_name[:-len('.class')]
+    if '.' in raw_class_name:
+      raise SyntaxError('%s cannot be used in @JNIAdditionalImport. '
+                        'Only import unqualified outer classes.' % class_name)
+    new_import = 'L%s/%s' % (JniParams._package, raw_class_name)
+    if new_import in JniParams._imports:
+      raise SyntaxError('Do not use JNIAdditionalImport on an already '
+                        'imported class: %s' % (new_import.replace('/', '.')))
+    JniParams._imports += [new_import]
+
+  @staticmethod
+  def ExtractImportsAndInnerClasses(contents):
+    if not JniParams._package:
+      raise RuntimeError('SetFullyQualifiedClass must be called before '
+                         'ExtractImportsAndInnerClasses')
+    contents = contents.replace('\n', '')
+    re_import = re.compile(r'import.*?(?P<class>\S*?);')
+    for match in re.finditer(re_import, contents):
+      JniParams._imports += ['L' + match.group('class').replace('.', '/')]
+
+    re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
+    for match in re.finditer(re_inner, contents):
+      inner = match.group('name')
+      if not JniParams._fully_qualified_class.endswith(inner):
+        JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
+                                     inner]
+
+    re_additional_imports = re.compile(
+        r'@JNIAdditionalImport\(\s*{?(?P<class_names>.*?)}?\s*\)')
+    for match in re.finditer(re_additional_imports, contents):
+      for class_name in match.group('class_names').split(','):
+        JniParams.AddAdditionalImport(class_name.strip())
+
+  @staticmethod
+  def ParseJavaPSignature(signature_line):
+    prefix = 'Signature: '
+    index = signature_line.find(prefix)
+    if index == -1:
+      prefix = 'descriptor: '
+      index = signature_line.index(prefix)
+    return '"%s"' % signature_line[index + len(prefix):]
+
+  @staticmethod
+  def JavaToJni(param):
+    """Converts a java param into a JNI signature type."""
+    pod_param_map = {
+        'int': 'I',
+        'boolean': 'Z',
+        'char': 'C',
+        'short': 'S',
+        'long': 'J',
+        'double': 'D',
+        'float': 'F',
+        'byte': 'B',
+        'void': 'V',
+    }
+    object_param_list = [
+        'Ljava/lang/Boolean',
+        'Ljava/lang/Integer',
+        'Ljava/lang/Long',
+        'Ljava/lang/Object',
+        'Ljava/lang/String',
+        'Ljava/lang/Class',
+    ]
+
+    prefix = ''
+    # Array?
+    while param[-2:] == '[]':
+      prefix += '['
+      param = param[:-2]
+    # Generic?
+    if '<' in param:
+      param = param[:param.index('<')]
+    if param in pod_param_map:
+      return prefix + pod_param_map[param]
+    if '/' in param:
+      # Coming from javap, use the fully qualified param directly.
+      return prefix + 'L' + JniParams.RemapClassName(param) + ';'
+
+    for qualified_name in (object_param_list +
+                           [JniParams._fully_qualified_class] +
+                           JniParams._inner_classes):
+      if (qualified_name.endswith('/' + param) or
+          qualified_name.endswith('$' + param.replace('.', '$')) or
+          qualified_name == 'L' + param):
+        return prefix + JniParams.RemapClassName(qualified_name) + ';'
+
+    # Is it from an import? (e.g. referecing Class from import pkg.Class;
+    # note that referencing an inner class Inner from import pkg.Class.Inner
+    # is not supported).
+    for qualified_name in JniParams._imports:
+      if qualified_name.endswith('/' + param):
+        # Ensure it's not an inner class.
+        components = qualified_name.split('/')
+        if len(components) > 2 and components[-2][0].isupper():
+          raise SyntaxError('Inner class (%s) can not be imported '
+                            'and used by JNI (%s). Please import the outer '
+                            'class and use Outer.Inner instead.' %
+                            (qualified_name, param))
+        return prefix + JniParams.RemapClassName(qualified_name) + ';'
+
+    # Is it an inner class from an outer class import? (e.g. referencing
+    # Class.Inner from import pkg.Class).
+    if '.' in param:
+      components = param.split('.')
+      outer = '/'.join(components[:-1])
+      inner = components[-1]
+      for qualified_name in JniParams._imports:
+        if qualified_name.endswith('/' + outer):
+          return (prefix + JniParams.RemapClassName(qualified_name) +
+                  '$' + inner + ';')
+      raise SyntaxError('Inner class (%s) can not be '
+                        'used directly by JNI. Please import the outer '
+                        'class, probably:\n'
+                        'import %s.%s;' %
+                        (param, JniParams._package.replace('/', '.'),
+                         outer.replace('/', '.')))
+
+    JniParams._CheckImplicitImports(param)
+
+    # Type not found, falling back to same package as this class.
+    return (prefix + 'L' +
+            JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
+
+  @staticmethod
+  def _CheckImplicitImports(param):
+    # Ensure implicit imports, such as java.lang.*, are not being treated
+    # as being in the same package.
+    if not JniParams._implicit_imports:
+      # This file was generated from android.jar and lists
+      # all classes that are implicitly imported.
+      with file(os.path.join(os.path.dirname(sys.argv[0]),
+                             'android_jar.classes'), 'r') as f:
+        JniParams._implicit_imports = f.readlines()
+    for implicit_import in JniParams._implicit_imports:
+      implicit_import = implicit_import.strip().replace('.class', '')
+      implicit_import = implicit_import.replace('/', '.')
+      if implicit_import.endswith('.' + param):
+        raise SyntaxError('Ambiguous class (%s) can not be used directly '
+                          'by JNI.\nPlease import it, probably:\n\n'
+                          'import %s;' %
+                          (param, implicit_import))
+
+
+  @staticmethod
+  def Signature(params, returns, wrap):
+    """Returns the JNI signature for the given datatypes."""
+    items = ['(']
+    items += [JniParams.JavaToJni(param.datatype) for param in params]
+    items += [')']
+    items += [JniParams.JavaToJni(returns)]
+    if wrap:
+      return '\n' + '\n'.join(['"' + item + '"' for item in items])
+    else:
+      return '"' + ''.join(items) + '"'
+
+  @staticmethod
+  def Parse(params):
+    """Parses the params into a list of Param objects."""
+    if not params:
+      return []
+    ret = []
+    for p in [p.strip() for p in params.split(',')]:
+      items = p.split(' ')
+      if 'final' in items:
+        items.remove('final')
+      param = Param(
+          datatype=items[0],
+          name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
+      )
+      ret += [param]
+    return ret
+
+  @staticmethod
+  def RemapClassName(class_name):
+    """Remaps class names using the jarjar mapping table."""
+    for old, new in JniParams._remappings:
+      if old.endswith('**') and old[:-2] in class_name:
+        return class_name.replace(old[:-2], new, 1)
+      if '*' not in old and class_name.endswith(old):
+        return class_name.replace(old, new, 1)
+
+    return class_name
+
+  @staticmethod
+  def SetJarJarMappings(mappings):
+    """Parse jarjar mappings from a string."""
+    JniParams._remappings = []
+    for line in mappings.splitlines():
+      rule = line.split()
+      if rule[0] != 'rule':
+        continue
+      _, src, dest = rule
+      src = src.replace('.', '/')
+      dest = dest.replace('.', '/')
+      if src.endswith('**'):
+        src_real_name = src[:-2]
+      else:
+        assert not '*' in src
+        src_real_name = src
+
+      if dest.endswith('@0'):
+        JniParams._remappings.append((src, dest[:-2] + src_real_name))
+      elif dest.endswith('@1'):
+        assert '**' in src
+        JniParams._remappings.append((src, dest[:-2]))
+      else:
+        assert not '@' in dest
+        JniParams._remappings.append((src, dest))
+
+
+def ExtractJNINamespace(contents):
+  re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
+  m = re.findall(re_jni_namespace, contents)
+  if not m:
+    return ''
+  return m[0]
+
+
+def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
+  re_package = re.compile('.*?package (.*?);')
+  matches = re.findall(re_package, contents)
+  if not matches:
+    raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
+  return (matches[0].replace('.', '/') + '/' +
+          os.path.splitext(os.path.basename(java_file_name))[0])
+
+
+def ExtractNatives(contents, ptr_type):
+  """Returns a list of dict containing information about a native method."""
+  contents = contents.replace('\n', '')
+  natives = []
+  re_native = re.compile(r'(@NativeClassQualifiedName'
+                         '\(\"(?P<native_class_name>.*?)\"\)\s+)?'
+                         '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\))\s+)?'
+                         '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*native '
+                         '(?P<return_type>\S*) '
+                         '(?P<name>native\w+)\((?P<params>.*?)\);')
+  for match in re.finditer(re_native, contents):
+    native = NativeMethod(
+        static='static' in match.group('qualifiers'),
+        java_class_name=match.group('java_class_name'),
+        native_class_name=match.group('native_class_name'),
+        return_type=match.group('return_type'),
+        name=match.group('name').replace('native', ''),
+        params=JniParams.Parse(match.group('params')),
+        ptr_type=ptr_type)
+    natives += [native]
+  return natives
+
+
+def GetStaticCastForReturnType(return_type):
+  type_map = { 'String' : 'jstring',
+               'java/lang/String' : 'jstring',
+               'boolean[]': 'jbooleanArray',
+               'byte[]': 'jbyteArray',
+               'char[]': 'jcharArray',
+               'short[]': 'jshortArray',
+               'int[]': 'jintArray',
+               'long[]': 'jlongArray',
+               'float[]': 'jfloatArray',
+               'double[]': 'jdoubleArray' }
+  ret = type_map.get(return_type, None)
+  if ret:
+    return ret
+  if return_type.endswith('[]'):
+    return 'jobjectArray'
+  return None
+
+
+def GetEnvCall(is_constructor, is_static, return_type):
+  """Maps the types availabe via env->Call__Method."""
+  if is_constructor:
+    return 'NewObject'
+  env_call_map = {'boolean': 'Boolean',
+                  'byte': 'Byte',
+                  'char': 'Char',
+                  'short': 'Short',
+                  'int': 'Int',
+                  'long': 'Long',
+                  'float': 'Float',
+                  'void': 'Void',
+                  'double': 'Double',
+                  'Object': 'Object',
+                 }
+  call = env_call_map.get(return_type, 'Object')
+  if is_static:
+    call = 'Static' + call
+  return 'Call' + call + 'Method'
+
+
+def GetMangledParam(datatype):
+  """Returns a mangled identifier for the datatype."""
+  if len(datatype) <= 2:
+    return datatype.replace('[', 'A')
+  ret = ''
+  for i in range(1, len(datatype)):
+    c = datatype[i]
+    if c == '[':
+      ret += 'A'
+    elif c.isupper() or datatype[i - 1] in ['/', 'L']:
+      ret += c.upper()
+  return ret
+
+
+def GetMangledMethodName(name, params, return_type):
+  """Returns a mangled method name for the given signature.
+
+     The returned name can be used as a C identifier and will be unique for all
+     valid overloads of the same method.
+
+  Args:
+     name: string.
+     params: list of Param.
+     return_type: string.
+
+  Returns:
+      A mangled name.
+  """
+  mangled_items = []
+  for datatype in [return_type] + [x.datatype for x in params]:
+    mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
+  mangled_name = name + '_'.join(mangled_items)
+  assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
+  return mangled_name
+
+
+def MangleCalledByNatives(called_by_natives):
+  """Mangles all the overloads from the call_by_natives list."""
+  method_counts = collections.defaultdict(
+      lambda: collections.defaultdict(lambda: 0))
+  for called_by_native in called_by_natives:
+    java_class_name = called_by_native.java_class_name
+    name = called_by_native.name
+    method_counts[java_class_name][name] += 1
+  for called_by_native in called_by_natives:
+    java_class_name = called_by_native.java_class_name
+    method_name = called_by_native.name
+    method_id_var_name = method_name
+    if method_counts[java_class_name][method_name] > 1:
+      method_id_var_name = GetMangledMethodName(method_name,
+                                                called_by_native.params,
+                                                called_by_native.return_type)
+    called_by_native.method_id_var_name = method_id_var_name
+  return called_by_natives
+
+
+# Regex to match the JNI return types that should be included in a
+# ScopedJavaLocalRef.
+RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
+
+# Regex to match a string like "@CalledByNative public void foo(int bar)".
+RE_CALLED_BY_NATIVE = re.compile(
+    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
+    '\s+(?P<prefix>[\w ]*?)'
+    '\s*(?P<return_type>\S+?)'
+    '\s+(?P<name>\w+)'
+    '\s*\((?P<params>[^\)]*)\)')
+
+
+def ExtractCalledByNatives(contents):
+  """Parses all methods annotated with @CalledByNative.
+
+  Args:
+    contents: the contents of the java file.
+
+  Returns:
+    A list of dict with information about the annotated methods.
+    TODO(bulach): return a CalledByNative object.
+
+  Raises:
+    ParseError: if unable to parse.
+  """
+  called_by_natives = []
+  for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
+    called_by_natives += [CalledByNative(
+        system_class=False,
+        unchecked='Unchecked' in match.group('Unchecked'),
+        static='static' in match.group('prefix'),
+        java_class_name=match.group('annotation') or '',
+        return_type=match.group('return_type'),
+        name=match.group('name'),
+        params=JniParams.Parse(match.group('params')))]
+  # Check for any @CalledByNative occurrences that weren't matched.
+  unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
+  for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
+    if '@CalledByNative' in line1:
+      raise ParseError('could not parse @CalledByNative method signature',
+                       line1, line2)
+  return MangleCalledByNatives(called_by_natives)
+
+
+class JNIFromJavaP(object):
+  """Uses 'javap' to parse a .class file and generate the JNI header file."""
+
+  def __init__(self, contents, options):
+    self.contents = contents
+    self.namespace = options.namespace
+    for line in contents:
+      class_name = re.match(
+          '.*?(public).*?(class|interface) (?P<class_name>\S+?)( |\Z)',
+          line)
+      if class_name:
+        self.fully_qualified_class = class_name.group('class_name')
+        break
+    self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
+    # Java 7's javap includes type parameters in output, like HashSet<T>. Strip
+    # away the <...> and use the raw class name that Java 6 would've given us.
+    self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0]
+    JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
+    self.java_class_name = self.fully_qualified_class.split('/')[-1]
+    if not self.namespace:
+      self.namespace = 'JNI_' + self.java_class_name
+    re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
+                           '\((?P<params>.*?)\)')
+    self.called_by_natives = []
+    for lineno, content in enumerate(contents[2:], 2):
+      match = re.match(re_method, content)
+      if not match:
+        continue
+      self.called_by_natives += [CalledByNative(
+          system_class=True,
+          unchecked=False,
+          static='static' in match.group('prefix'),
+          java_class_name='',
+          return_type=match.group('return_type').replace('.', '/'),
+          name=match.group('name'),
+          params=JniParams.Parse(match.group('params').replace('.', '/')),
+          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
+    re_constructor = re.compile('(.*?)public ' +
+                                self.fully_qualified_class.replace('/', '.') +
+                                '\((?P<params>.*?)\)')
+    for lineno, content in enumerate(contents[2:], 2):
+      match = re.match(re_constructor, content)
+      if not match:
+        continue
+      self.called_by_natives += [CalledByNative(
+          system_class=True,
+          unchecked=False,
+          static=False,
+          java_class_name='',
+          return_type=self.fully_qualified_class,
+          name='Constructor',
+          params=JniParams.Parse(match.group('params').replace('.', '/')),
+          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
+          is_constructor=True)]
+    self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
+
+    self.constant_fields = []
+    re_constant_field = re.compile('.*?public static final int (?P<name>.*?);')
+    re_constant_field_value = re.compile(
+        '.*?Constant(Value| value): int (?P<value>(-*[0-9]+)?)')
+    for lineno, content in enumerate(contents[2:], 2):
+      match = re.match(re_constant_field, content)
+      if not match:
+        continue
+      value = re.match(re_constant_field_value, contents[lineno + 2])
+      if not value:
+        value = re.match(re_constant_field_value, contents[lineno + 3])
+      if value:
+        self.constant_fields.append(
+            ConstantField(name=match.group('name'),
+                          value=value.group('value')))
+
+    self.inl_header_file_generator = InlHeaderFileGenerator(
+        self.namespace, self.fully_qualified_class, [],
+        self.called_by_natives, self.constant_fields, options)
+
+  def GetContent(self):
+    return self.inl_header_file_generator.GetContent()
+
+  @staticmethod
+  def CreateFromClass(class_file, options):
+    class_name = os.path.splitext(os.path.basename(class_file))[0]
+    p = subprocess.Popen(args=[options.javap, '-c', '-verbose',
+                               '-s', class_name],
+                         cwd=os.path.dirname(class_file),
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, _ = p.communicate()
+    jni_from_javap = JNIFromJavaP(stdout.split('\n'), options)
+    return jni_from_javap
+
+
+class JNIFromJavaSource(object):
+  """Uses the given java source file to generate the JNI header file."""
+
+  # Match single line comments, multiline comments, character literals, and
+  # double-quoted strings.
+  _comment_remover_regex = re.compile(
+      r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+      re.DOTALL | re.MULTILINE)
+
+  def __init__(self, contents, fully_qualified_class, options):
+    contents = self._RemoveComments(contents)
+    JniParams.SetFullyQualifiedClass(fully_qualified_class)
+    JniParams.ExtractImportsAndInnerClasses(contents)
+    jni_namespace = ExtractJNINamespace(contents) or options.namespace
+    natives = ExtractNatives(contents, options.ptr_type)
+    called_by_natives = ExtractCalledByNatives(contents)
+    if len(natives) == 0 and len(called_by_natives) == 0:
+      raise SyntaxError('Unable to find any JNI methods for %s.' %
+                        fully_qualified_class)
+    inl_header_file_generator = InlHeaderFileGenerator(
+        jni_namespace, fully_qualified_class, natives, called_by_natives,
+        [], options)
+    self.content = inl_header_file_generator.GetContent()
+
+  @classmethod
+  def _RemoveComments(cls, contents):
+    # We need to support both inline and block comments, and we need to handle
+    # strings that contain '//' or '/*'.
+    # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java
+    # parser. Maybe we could ditch JNIFromJavaSource and just always use
+    # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
+    # http://code.google.com/p/chromium/issues/detail?id=138941
+    def replacer(match):
+      # Replace matches that are comments with nothing; return literals/strings
+      # unchanged.
+      s = match.group(0)
+      if s.startswith('/'):
+        return ''
+      else:
+        return s
+    return cls._comment_remover_regex.sub(replacer, contents)
+
+  def GetContent(self):
+    return self.content
+
+  @staticmethod
+  def CreateFromFile(java_file_name, options):
+    contents = file(java_file_name).read()
+    fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
+                                                               contents)
+    return JNIFromJavaSource(contents, fully_qualified_class, options)
+
+
+class InlHeaderFileGenerator(object):
+  """Generates an inline header file for JNI integration."""
+
+  def __init__(self, namespace, fully_qualified_class, natives,
+               called_by_natives, constant_fields, options):
+    self.namespace = namespace
+    self.fully_qualified_class = fully_qualified_class
+    self.class_name = self.fully_qualified_class.split('/')[-1]
+    self.natives = natives
+    self.called_by_natives = called_by_natives
+    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
+    self.constant_fields = constant_fields
+    self.options = options
+    self.init_native = self.ExtractInitNative(options)
+
+  def ExtractInitNative(self, options):
+    for native in self.natives:
+      if options.jni_init_native_name == 'native' + native.name:
+        self.natives.remove(native)
+        return native
+    return None
+
+  def GetContent(self):
+    """Returns the content of the JNI binding file."""
+    template = Template("""\
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+// This file is autogenerated by
+//     ${SCRIPT_NAME}
+// For
+//     ${FULLY_QUALIFIED_CLASS}
+
+#ifndef ${HEADER_GUARD}
+#define ${HEADER_GUARD}
+
+#include <jni.h>
+
+${INCLUDES}
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+$CLASS_PATH_DEFINITIONS
+$METHOD_ID_DEFINITIONS
+}  // namespace
+
+$OPEN_NAMESPACE
+$FORWARD_DECLARATIONS
+
+$CONSTANT_FIELDS
+
+// Step 2: method stubs.
+$METHOD_STUBS
+
+// Step 3: RegisterNatives.
+$JNI_NATIVE_METHODS
+$REGISTER_NATIVES
+$CLOSE_NAMESPACE
+$JNI_REGISTER_NATIVES
+#endif  // ${HEADER_GUARD}
+""")
+    values = {
+        'SCRIPT_NAME': self.options.script_name,
+        'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
+        'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
+        'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(),
+        'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
+        'CONSTANT_FIELDS': self.GetConstantFieldsString(),
+        'METHOD_STUBS': self.GetMethodStubsString(),
+        'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
+        'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(),
+        'REGISTER_NATIVES': self.GetRegisterNativesString(),
+        'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
+        'HEADER_GUARD': self.header_guard,
+        'INCLUDES': self.GetIncludesString(),
+        'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString()
+    }
+    return WrapOutput(template.substitute(values))
+
+  def GetClassPathDefinitionsString(self):
+    ret = []
+    ret += [self.GetClassPathDefinitions()]
+    return '\n'.join(ret)
+
+  def GetMethodIDDefinitionsString(self):
+    """Returns the definition of method ids for the called by native methods."""
+    if not self.options.eager_called_by_natives:
+      return ''
+    template = Template("""\
+jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
+    ret = []
+    for called_by_native in self.called_by_natives:
+      values = {
+          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+      }
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetForwardDeclarationsString(self):
+    ret = []
+    for native in self.natives:
+      if native.type != 'method':
+        ret += [self.GetForwardDeclaration(native)]
+    if self.options.native_exports and ret:
+      return '\nextern "C" {\n' + "\n".join(ret) + '\n};  // extern "C"'
+    return '\n'.join(ret)
+
+  def GetConstantFieldsString(self):
+    if not self.constant_fields:
+      return ''
+    ret = ['enum Java_%s_constant_fields {' % self.class_name]
+    for c in self.constant_fields:
+      ret += ['  %s = %s,' % (c.name, c.value)]
+    ret += ['};']
+    return '\n'.join(ret)
+
+  def GetMethodStubsString(self):
+    """Returns the code corresponding to method stubs."""
+    ret = []
+    for native in self.natives:
+      if native.type == 'method':
+        ret += [self.GetNativeMethodStubString(native)]
+    if self.options.eager_called_by_natives:
+      ret += self.GetEagerCalledByNativeMethodStubs()
+    else:
+      ret += self.GetLazyCalledByNativeMethodStubs()
+
+    if self.options.native_exports and ret:
+      return '\nextern "C" {\n' + "\n".join(ret) + '\n};  // extern "C"'
+    return '\n'.join(ret)
+
+  def GetLazyCalledByNativeMethodStubs(self):
+    return [self.GetLazyCalledByNativeMethodStub(called_by_native)
+            for called_by_native in self.called_by_natives]
+
+  def GetEagerCalledByNativeMethodStubs(self):
+    ret = []
+    if self.called_by_natives:
+      ret += ['namespace {']
+      for called_by_native in self.called_by_natives:
+        ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)]
+      ret += ['}  // namespace']
+    return ret
+
+  def GetIncludesString(self):
+    if not self.options.includes:
+      return ''
+    includes = self.options.includes.split(',')
+    return '\n'.join('#include "%s"' % x for x in includes)
+
+  def GetKMethodsString(self, clazz):
+    ret = []
+    for native in self.natives:
+      if (native.java_class_name == clazz or
+          (not native.java_class_name and clazz == self.class_name)):
+        ret += [self.GetKMethodArrayEntry(native)]
+    return '\n'.join(ret)
+
+  def SubstituteNativeMethods(self, template):
+    """Substitutes JAVA_CLASS and KMETHODS in the provided template."""
+    ret = []
+    all_classes = self.GetUniqueClasses(self.natives)
+    all_classes[self.class_name] = self.fully_qualified_class
+    for clazz in all_classes:
+      kmethods = self.GetKMethodsString(clazz)
+      if kmethods:
+        values = {'JAVA_CLASS': clazz,
+                  'KMETHODS': kmethods}
+        ret += [template.substitute(values)]
+    if not ret: return ''
+    return '\n' + '\n'.join(ret)
+
+  def GetJNINativeMethodsString(self):
+    """Returns the implementation of the array of native methods."""
+    if self.options.native_exports and not self.options.native_exports_optional:
+      return ''
+    template = Template("""\
+static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
+${KMETHODS}
+};
+""")
+    return self.SubstituteNativeMethods(template)
+
+  def GetRegisterCalledByNativesImplString(self):
+    """Returns the code for registering the called by native methods."""
+    if not self.options.eager_called_by_natives:
+      return ''
+    template = Template("""\
+  g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL}
+  if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) {
+    return false;
+  }
+    """)
+    ret = []
+    for called_by_native in self.called_by_natives:
+      values = {
+          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+          'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
+      }
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetRegisterNativesString(self):
+    """Returns the code for RegisterNatives."""
+    template = Template("""\
+${REGISTER_NATIVES_SIGNATURE} {
+${EARLY_EXIT}
+${CLASSES}
+${NATIVES}
+${CALLED_BY_NATIVES}
+  return true;
+}
+""")
+    signature = 'static bool RegisterNativesImpl(JNIEnv* env'
+    if self.init_native:
+      signature += ', jclass clazz)'
+    else:
+      signature += ')'
+
+    early_exit = ''
+    if self.options.native_exports_optional:
+      early_exit = """\
+  if (base::android::IsManualJniRegistrationDisabled()) return true;
+"""
+
+    natives = self.GetRegisterNativesImplString()
+    called_by_natives = self.GetRegisterCalledByNativesImplString()
+    values = {'REGISTER_NATIVES_SIGNATURE': signature,
+              'EARLY_EXIT': early_exit,
+              'CLASSES': self.GetFindClasses(),
+              'NATIVES': natives,
+              'CALLED_BY_NATIVES': called_by_natives,
+             }
+    return template.substitute(values)
+
+  def GetRegisterNativesImplString(self):
+    """Returns the shared implementation for RegisterNatives."""
+    if self.options.native_exports and not self.options.native_exports_optional:
+      return ''
+
+    template = Template("""\
+  const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
+
+  if (env->RegisterNatives(${JAVA_CLASS}_clazz(env),
+                           kMethods${JAVA_CLASS},
+                           kMethods${JAVA_CLASS}Size) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, ${JAVA_CLASS}_clazz(env), __FILE__);
+    return false;
+  }
+""")
+    return self.SubstituteNativeMethods(template)
+
+  def GetJNIRegisterNativesString(self):
+    """Returns the implementation for the JNI registration of native methods."""
+    if not self.init_native:
+      return ''
+
+    template = Template("""\
+extern "C" JNIEXPORT bool JNICALL
+Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
+  return ${NAMESPACE}RegisterNativesImpl(env, clazz);
+}
+""")
+
+    if self.options.native_exports:
+      java_name = JniParams.RemapClassName(self.fully_qualified_class)
+      java_name = java_name.replace('_', '_1').replace('/', '_')
+    else:
+      java_name = self.fully_qualified_class.replace('/', '_')
+
+    namespace = ''
+    if self.namespace:
+      namespace = self.namespace + '::'
+    values = {'FULLY_QUALIFIED_CLASS': java_name,
+              'INIT_NATIVE_NAME': 'native' + self.init_native.name,
+              'NAMESPACE': namespace,
+              'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
+             }
+    return template.substitute(values)
+
+  def GetOpenNamespaceString(self):
+    if self.namespace:
+      all_namespaces = ['namespace %s {' % ns
+                        for ns in self.namespace.split('::')]
+      return '\n'.join(all_namespaces)
+    return ''
+
+  def GetCloseNamespaceString(self):
+    if self.namespace:
+      all_namespaces = ['}  // namespace %s' % ns
+                        for ns in self.namespace.split('::')]
+      all_namespaces.reverse()
+      return '\n'.join(all_namespaces) + '\n'
+    return ''
+
+  def GetJNIFirstParam(self, native):
+    ret = []
+    if native.type == 'method':
+      ret = ['jobject jcaller']
+    elif native.type == 'function':
+      if native.static:
+        ret = ['jclass jcaller']
+      else:
+        ret = ['jobject jcaller']
+    return ret
+
+  def GetParamsInDeclaration(self, native):
+    """Returns the params for the stub declaration.
+
+    Args:
+      native: the native dictionary describing the method.
+
+    Returns:
+      A string containing the params.
+    """
+    return ',\n    '.join(self.GetJNIFirstParam(native) +
+                          [JavaDataTypeToC(param.datatype) + ' ' +
+                           param.name
+                           for param in native.params])
+
+  def GetCalledByNativeParamsInDeclaration(self, called_by_native):
+    return ',\n    '.join([
+        JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' +
+        param.name
+        for param in called_by_native.params])
+
+  def GetStubName(self, native):
+    """Return the name of the stub function for this native method.
+
+    Args:
+      native: the native dictionary describing the method.
+
+    Returns:
+      A string with the stub function name. For native exports mode this is the
+      Java_* symbol name required by the JVM; otherwise it is just the name of
+      the native method itself.
+    """
+    if self.options.native_exports:
+      template = Template("Java_${JAVA_NAME}_native${NAME}")
+
+      java_name = JniParams.RemapClassName(self.fully_qualified_class)
+      java_name = java_name.replace('_', '_1').replace('/', '_')
+      if native.java_class_name:
+        java_name += '_00024' + native.java_class_name
+
+      values = {'NAME': native.name,
+                'JAVA_NAME': java_name}
+      return template.substitute(values)
+    else:
+      return native.name
+
+  def GetForwardDeclaration(self, native):
+    template_str = """
+static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
+"""
+    if self.options.native_exports:
+      template_str += """
+__attribute__((visibility("default")))
+${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS}) {
+  return ${NAME}(${PARAMS_IN_CALL});
+}
+"""
+    template = Template(template_str)
+    params_in_call = []
+    if not self.options.pure_native_methods:
+      params_in_call = ['env', 'jcaller']
+    params_in_call = ', '.join(params_in_call + [p.name for p in native.params])
+
+    values = {'RETURN': JavaDataTypeToC(native.return_type),
+              'NAME': native.name,
+              'PARAMS': self.GetParamsInDeclaration(native),
+              'PARAMS_IN_CALL': params_in_call,
+              'STUB_NAME': self.GetStubName(native)}
+    return template.substitute(values)
+
+  def GetNativeMethodStubString(self, native):
+    """Returns stubs for native methods."""
+    if self.options.native_exports:
+      template_str = """\
+__attribute__((visibility("default")))
+${RETURN} ${STUB_NAME}(JNIEnv* env,
+    ${PARAMS_IN_DECLARATION}) {"""
+    else:
+      template_str = """\
+static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
+    template_str += """
+  ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
+  CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
+  return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
+}
+"""
+
+    template = Template(template_str)
+    params = []
+    if not self.options.pure_native_methods:
+      params = ['env', 'jcaller']
+    params_in_call = ', '.join(params + [p.name for p in native.params[1:]])
+
+    return_type = JavaDataTypeToC(native.return_type)
+    optional_error_return = JavaReturnValueToC(native.return_type)
+    if optional_error_return:
+      optional_error_return = ', ' + optional_error_return
+    post_call = ''
+    if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+      post_call = '.Release()'
+
+    values = {
+        'RETURN': return_type,
+        'OPTIONAL_ERROR_RETURN': optional_error_return,
+        'NAME': native.name,
+        'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
+        'PARAM0_NAME': native.params[0].name,
+        'P0_TYPE': native.p0_type,
+        'PARAMS_IN_CALL': params_in_call,
+        'POST_CALL': post_call,
+        'STUB_NAME': self.GetStubName(native),
+    }
+    return template.substitute(values)
+
+  def GetArgument(self, param):
+    return ('as_jint(' + param.name + ')'
+            if param.datatype == 'int' else param.name)
+
+  def GetArgumentsInCall(self, params):
+    """Return a string of arguments to call from native into Java"""
+    return [self.GetArgument(p) for p in params]
+
+  def GetCalledByNativeValues(self, called_by_native):
+    """Fills in necessary values for the CalledByNative methods."""
+    java_class = called_by_native.java_class_name or self.class_name
+    if called_by_native.static or called_by_native.is_constructor:
+      first_param_in_declaration = ''
+      first_param_in_call = ('%s_clazz(env)' % java_class)
+    else:
+      first_param_in_declaration = ', jobject obj'
+      first_param_in_call = 'obj'
+    params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
+        called_by_native)
+    if params_in_declaration:
+      params_in_declaration = ', ' + params_in_declaration
+    params_in_call = ', '.join(self.GetArgumentsInCall(called_by_native.params))
+    if params_in_call:
+      params_in_call = ', ' + params_in_call
+    pre_call = ''
+    post_call = ''
+    if called_by_native.static_cast:
+      pre_call = 'static_cast<%s>(' % called_by_native.static_cast
+      post_call = ')'
+    check_exception = ''
+    if not called_by_native.unchecked:
+      check_exception = 'jni_generator::CheckException(env);'
+    return_type = JavaDataTypeToC(called_by_native.return_type)
+    optional_error_return = JavaReturnValueToC(called_by_native.return_type)
+    if optional_error_return:
+      optional_error_return = ', ' + optional_error_return
+    return_declaration = ''
+    return_clause = ''
+    if return_type != 'void':
+      pre_call = ' ' + pre_call
+      return_declaration = return_type + ' ret ='
+      if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+        return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
+        return_clause = 'return ' + return_type + '(env, ret);'
+      else:
+        return_clause = 'return ret;'
+    return {
+        'JAVA_CLASS': java_class,
+        'RETURN_TYPE': return_type,
+        'OPTIONAL_ERROR_RETURN': optional_error_return,
+        'RETURN_DECLARATION': return_declaration,
+        'RETURN_CLAUSE': return_clause,
+        'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
+        'PARAMS_IN_DECLARATION': params_in_declaration,
+        'PRE_CALL': pre_call,
+        'POST_CALL': post_call,
+        'ENV_CALL': called_by_native.env_call,
+        'FIRST_PARAM_IN_CALL': first_param_in_call,
+        'PARAMS_IN_CALL': params_in_call,
+        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+        'CHECK_EXCEPTION': check_exception,
+        'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
+    }
+
+  def GetEagerCalledByNativeMethodStub(self, called_by_native):
+    """Returns the implementation of the called by native method."""
+    template = Template("""
+static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\
+JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) {
+  ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
+      g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL};
+  ${RETURN_CLAUSE}
+}""")
+    values = self.GetCalledByNativeValues(called_by_native)
+    return template.substitute(values)
+
+  def GetLazyCalledByNativeMethodStub(self, called_by_native):
+    """Returns a string."""
+    function_signature_template = Template("""\
+static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
+JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
+    function_header_template = Template("""\
+${FUNCTION_SIGNATURE} {""")
+    function_header_with_unused_template = Template("""\
+${FUNCTION_SIGNATURE} __attribute__ ((unused));
+${FUNCTION_SIGNATURE} {""")
+    template = Template("""
+static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
+${FUNCTION_HEADER}
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
+      ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
+  jmethodID method_id =
+    ${GET_METHOD_ID_IMPL}
+  ${RETURN_DECLARATION}
+     ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
+          method_id${PARAMS_IN_CALL})${POST_CALL};
+  ${CHECK_EXCEPTION}
+  ${RETURN_CLAUSE}
+}""")
+    values = self.GetCalledByNativeValues(called_by_native)
+    values['FUNCTION_SIGNATURE'] = (
+        function_signature_template.substitute(values))
+    if called_by_native.system_class:
+      values['FUNCTION_HEADER'] = (
+          function_header_with_unused_template.substitute(values))
+    else:
+      values['FUNCTION_HEADER'] = function_header_template.substitute(values)
+    return template.substitute(values)
+
+  def GetKMethodArrayEntry(self, native):
+    template = Template('    { "native${NAME}", ${JNI_SIGNATURE}, ' +
+                        'reinterpret_cast<void*>(${STUB_NAME}) },')
+    values = {'NAME': native.name,
+              'JNI_SIGNATURE': JniParams.Signature(native.params,
+                                                   native.return_type,
+                                                   True),
+              'STUB_NAME': self.GetStubName(native)}
+    return template.substitute(values)
+
+  def GetUniqueClasses(self, origin):
+    ret = {self.class_name: self.fully_qualified_class}
+    for entry in origin:
+      class_name = self.class_name
+      jni_class_path = self.fully_qualified_class
+      if entry.java_class_name:
+        class_name = entry.java_class_name
+        jni_class_path = self.fully_qualified_class + '$' + class_name
+      ret[class_name] = jni_class_path
+    return ret
+
+  def GetClassPathDefinitions(self):
+    """Returns the ClassPath constants."""
+    ret = []
+    template = Template("""\
+const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
+    native_classes = self.GetUniqueClasses(self.natives)
+    called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
+    if self.options.native_exports:
+      all_classes = called_by_native_classes
+    else:
+      all_classes = native_classes
+      all_classes.update(called_by_native_classes)
+
+    for clazz in all_classes:
+      values = {
+          'JAVA_CLASS': clazz,
+          'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]),
+      }
+      ret += [template.substitute(values)]
+    ret += ''
+
+    class_getter_methods = []
+    if self.options.native_exports:
+      template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0;
+#define ${JAVA_CLASS}_clazz(env) \
+base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \
+&g_${JAVA_CLASS}_clazz)""")
+    else:
+      template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_${JAVA_CLASS}_clazz = NULL;
+#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""")
+
+    for clazz in called_by_native_classes:
+      values = {
+          'JAVA_CLASS': clazz,
+      }
+      ret += [template.substitute(values)]
+
+    return '\n'.join(ret)
+
+  def GetFindClasses(self):
+    """Returns the imlementation of FindClass for all known classes."""
+    if self.init_native:
+      if self.options.native_exports:
+        template = Template("""\
+  base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""")
+      else:
+        template = Template("""\
+  g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
+    else:
+      if self.options.native_exports:
+        return '\n'
+      template = Template("""\
+  g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
+    ret = []
+    for clazz in self.GetUniqueClasses(self.called_by_natives):
+      values = {'JAVA_CLASS': clazz}
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetMethodIDImpl(self, called_by_native):
+    """Returns the implementation of GetMethodID."""
+    if self.options.eager_called_by_natives:
+      template = Template("""\
+env->Get${STATIC_METHOD_PART}MethodID(
+      ${JAVA_CLASS}_clazz(env),
+      "${JNI_NAME}", ${JNI_SIGNATURE});""")
+    else:
+      template = Template("""\
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_${STATIC}>(
+      env, ${JAVA_CLASS}_clazz(env),
+      "${JNI_NAME}",
+      ${JNI_SIGNATURE},
+      &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
+""")
+    jni_name = called_by_native.name
+    jni_return_type = called_by_native.return_type
+    if called_by_native.is_constructor:
+      jni_name = '<init>'
+      jni_return_type = 'void'
+    if called_by_native.signature:
+      signature = called_by_native.signature
+    else:
+      signature = JniParams.Signature(called_by_native.params,
+                                      jni_return_type,
+                                      True)
+    values = {
+        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+        'JNI_NAME': jni_name,
+        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+        'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
+        'STATIC_METHOD_PART': 'Static' if called_by_native.static else '',
+        'JNI_SIGNATURE': signature,
+    }
+    return template.substitute(values)
+
+
+def WrapOutput(output):
+  ret = []
+  for line in output.splitlines():
+    # Do not wrap lines under 80 characters or preprocessor directives.
+    if len(line) < 80 or line.lstrip()[:1] == '#':
+      stripped = line.rstrip()
+      if len(ret) == 0 or len(ret[-1]) or len(stripped):
+        ret.append(stripped)
+    else:
+      first_line_indent = ' ' * (len(line) - len(line.lstrip()))
+      subsequent_indent =  first_line_indent + ' ' * 4
+      if line.startswith('//'):
+        subsequent_indent = '//' + subsequent_indent
+      wrapper = textwrap.TextWrapper(width=80,
+                                     subsequent_indent=subsequent_indent,
+                                     break_long_words=False)
+      ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
+  ret += ['']
+  return '\n'.join(ret)
+
+
+def ExtractJarInputFile(jar_file, input_file, out_dir):
+  """Extracts input file from jar and returns the filename.
+
+  The input file is extracted to the same directory that the generated jni
+  headers will be placed in.  This is passed as an argument to script.
+
+  Args:
+    jar_file: the jar file containing the input files to extract.
+    input_files: the list of files to extract from the jar file.
+    out_dir: the name of the directories to extract to.
+
+  Returns:
+    the name of extracted input file.
+  """
+  jar_file = zipfile.ZipFile(jar_file)
+
+  out_dir = os.path.join(out_dir, os.path.dirname(input_file))
+  try:
+    os.makedirs(out_dir)
+  except OSError as e:
+    if e.errno != errno.EEXIST:
+      raise
+  extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
+  with open(extracted_file_name, 'w') as outfile:
+    outfile.write(jar_file.read(input_file))
+
+  return extracted_file_name
+
+
+def GenerateJNIHeader(input_file, output_file, options):
+  try:
+    if os.path.splitext(input_file)[1] == '.class':
+      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
+      content = jni_from_javap.GetContent()
+    else:
+      jni_from_java_source = JNIFromJavaSource.CreateFromFile(
+          input_file, options)
+      content = jni_from_java_source.GetContent()
+  except ParseError, e:
+    print e
+    sys.exit(1)
+  if output_file:
+    if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
+      os.makedirs(os.path.dirname(os.path.abspath(output_file)))
+    if options.optimize_generation and os.path.exists(output_file):
+      with file(output_file, 'r') as f:
+        existing_content = f.read()
+        if existing_content == content:
+          return
+    with file(output_file, 'w') as f:
+      f.write(content)
+  else:
+    print output
+
+
+def GetScriptName():
+  script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
+  base_index = 0
+  for idx, value in enumerate(script_components):
+    if value == 'base' or value == 'third_party':
+      base_index = idx
+      break
+  return os.sep.join(script_components[base_index:])
+
+
+def main(argv):
+  usage = """usage: %prog [OPTIONS]
+This script will parse the given java source code extracting the native
+declarations and print the header file to stdout (or a file).
+See SampleForTests.java for more details.
+  """
+  option_parser = optparse.OptionParser(usage=usage)
+  build_utils.AddDepfileOption(option_parser)
+
+  option_parser.add_option('-j', '--jar_file', dest='jar_file',
+                           help='Extract the list of input files from'
+                           ' a specified jar file.'
+                           ' Uses javap to extract the methods from a'
+                           ' pre-compiled class. --input should point'
+                           ' to pre-compiled Java .class files.')
+  option_parser.add_option('-n', dest='namespace',
+                           help='Uses as a namespace in the generated header '
+                           'instead of the javap class name, or when there is '
+                           'no JNINamespace annotation in the java source.')
+  option_parser.add_option('--input_file',
+                           help='Single input file name. The output file name '
+                           'will be derived from it. Must be used with '
+                           '--output_dir.')
+  option_parser.add_option('--output_dir',
+                           help='The output directory. Must be used with '
+                           '--input')
+  option_parser.add_option('--optimize_generation', type="int",
+                           default=0, help='Whether we should optimize JNI '
+                           'generation by not regenerating files if they have '
+                           'not changed.')
+  option_parser.add_option('--jarjar',
+                           help='Path to optional jarjar rules file.')
+  option_parser.add_option('--script_name', default=GetScriptName(),
+                           help='The name of this script in the generated '
+                           'header.')
+  option_parser.add_option('--includes',
+                           help='The comma-separated list of header files to '
+                           'include in the generated header.')
+  option_parser.add_option('--pure_native_methods',
+                           action='store_true', dest='pure_native_methods',
+                           help='When true, the native methods will be called '
+                           'without any JNI-specific arguments.')
+  option_parser.add_option('--ptr_type', default='int',
+                           type='choice', choices=['int', 'long'],
+                           help='The type used to represent native pointers in '
+                           'Java code. For 32-bit, use int; '
+                           'for 64-bit, use long.')
+  option_parser.add_option('--jni_init_native_name', default='',
+                           help='The name of the JNI registration method that '
+                           'is used to initialize all native methods. If a '
+                           'method with this name is not present in the Java '
+                           'source file, setting this option is a no-op. When '
+                           'a method with this name is found however, the '
+                           'naming convention Java_<packageName>_<className> '
+                           'will limit the initialization to only the '
+                           'top-level class.')
+  option_parser.add_option('--eager_called_by_natives',
+                           action='store_true', dest='eager_called_by_natives',
+                           help='When true, the called-by-native methods will '
+                           'be initialized in a non-atomic way.')
+  option_parser.add_option('--cpp', default='cpp',
+                           help='The path to cpp command.')
+  option_parser.add_option('--javap', default='javap',
+                           help='The path to javap command.')
+  option_parser.add_option('--native_exports', action='store_true',
+                           help='Native method registration through .so '
+                           'exports.')
+  option_parser.add_option('--native_exports_optional', action='store_true',
+                           help='Support both explicit and native method'
+                           'registration.')
+  options, args = option_parser.parse_args(argv)
+  if options.native_exports_optional:
+    options.native_exports = True
+  if options.jar_file:
+    input_file = ExtractJarInputFile(options.jar_file, options.input_file,
+                                     options.output_dir)
+  elif options.input_file:
+    input_file = options.input_file
+  else:
+    option_parser.print_help()
+    print '\nError: Must specify --jar_file or --input_file.'
+    return 1
+  output_file = None
+  if options.output_dir:
+    root_name = os.path.splitext(os.path.basename(input_file))[0]
+    output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
+  if options.jarjar:
+    with open(options.jarjar) as f:
+      JniParams.SetJarJarMappings(f.read())
+  GenerateJNIHeader(input_file, output_file, options)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
new file mode 100644
index 0000000..b9736e1
--- /dev/null
+++ b/base/android/jni_generator/jni_generator_helper.h
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#ifndef BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
+#define BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// Project-specific macros used by the header files generated by
+// jni_generator.py. Different projects can then specify their own
+// implementation for this file.
+#define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
+    DCHECK(native_ptr) << method_name;
+
+#define CHECK_CLAZZ(env, jcaller, clazz, ...) \
+    DCHECK(clazz);
+
+namespace jni_generator {
+
+  inline void HandleRegistrationError(JNIEnv* env, jclass clazz,
+                                      const char* filename) {
+    LOG(ERROR) << "RegisterNatives failed in " << filename;
+  }
+
+  inline void CheckException(JNIEnv* env) {
+    base::android::CheckException(env);
+  }
+
+}  // namespace jni_generator
+
+using base::android::ScopedJavaLocalRef;
+
+#endif  // BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
new file mode 100755
index 0000000..6014847
--- /dev/null
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -0,0 +1,1175 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for jni_generator.py.
+
+This test suite contains various tests for the JNI generator.
+It exercises the low-level parser all the way up to the
+code generator and ensures the output matches a golden
+file.
+"""
+
+import difflib
+import inspect
+import optparse
+import os
+import sys
+import unittest
+import jni_generator
+from jni_generator import CalledByNative, JniParams, NativeMethod, Param
+
+
+SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py'
+INCLUDES = (
+    'base/android/jni_generator/jni_generator_helper.h'
+)
+
+# Set this environment variable in order to regenerate the golden text
+# files.
+REBASELINE_ENV = 'REBASELINE'
+
+class TestOptions(object):
+  """The mock options object which is passed to the jni_generator.py script."""
+
+  def __init__(self):
+    self.namespace = None
+    self.script_name = SCRIPT_NAME
+    self.includes = INCLUDES
+    self.pure_native_methods = False
+    self.ptr_type = 'long'
+    self.jni_init_native_name = None
+    self.eager_called_by_natives = False
+    self.cpp = 'cpp'
+    self.javap = 'javap'
+    self.native_exports = False
+    self.native_exports_optional = False
+
+class TestGenerator(unittest.TestCase):
+  def assertObjEquals(self, first, second):
+    dict_first = first.__dict__
+    dict_second = second.__dict__
+    self.assertEquals(dict_first.keys(), dict_second.keys())
+    for key, value in dict_first.iteritems():
+      if (type(value) is list and len(value) and
+          isinstance(type(value[0]), object)):
+        self.assertListEquals(value, second.__getattribute__(key))
+      else:
+        actual = second.__getattribute__(key)
+        self.assertEquals(value, actual,
+                          'Key ' + key + ': ' + str(value) + '!=' + str(actual))
+
+  def assertListEquals(self, first, second):
+    self.assertEquals(len(first), len(second))
+    for i in xrange(len(first)):
+      if isinstance(first[i], object):
+        self.assertObjEquals(first[i], second[i])
+      else:
+        self.assertEquals(first[i], second[i])
+
+  def assertTextEquals(self, golden_text, generated_text):
+    if not self.compareText(golden_text, generated_text):
+      self.fail('Golden text mismatch.')
+
+  def compareText(self, golden_text, generated_text):
+    def FilterText(text):
+      return [
+          l.strip() for l in text.split('\n')
+          if not l.startswith('// Copyright')
+      ]
+    stripped_golden = FilterText(golden_text)
+    stripped_generated = FilterText(generated_text)
+    if stripped_golden == stripped_generated:
+      return True
+    print self.id()
+    for line in difflib.context_diff(stripped_golden, stripped_generated):
+      print line
+    print '\n\nGenerated'
+    print '=' * 80
+    print generated_text
+    print '=' * 80
+    print 'Run with:'
+    print 'REBASELINE=1', sys.argv[0]
+    print 'to regenerate the data files.'
+
+  def _ReadGoldenFile(self, golden_file):
+    if not os.path.exists(golden_file):
+      return None
+    with file(golden_file, 'r') as f:
+      return f.read()
+
+  def assertGoldenTextEquals(self, generated_text):
+    script_dir = os.path.dirname(sys.argv[0])
+    # This is the caller test method.
+    caller = inspect.stack()[1][3]
+    self.assertTrue(caller.startswith('test'),
+                    'assertGoldenTextEquals can only be called from a '
+                    'test* method, not %s' % caller)
+    golden_file = os.path.join(script_dir, caller + '.golden')
+    golden_text = self._ReadGoldenFile(golden_file)
+    if os.environ.get(REBASELINE_ENV):
+      if golden_text != generated_text:
+        with file(golden_file, 'w') as f:
+          f.write(generated_text)
+      return
+    self.assertTextEquals(golden_text, generated_text)
+
+  def testInspectCaller(self):
+    def willRaise():
+      # This function can only be called from a test* method.
+      self.assertGoldenTextEquals('')
+    self.assertRaises(AssertionError, willRaise)
+
+  def testNatives(self):
+    test_data = """"
+    interface OnFrameAvailableListener {}
+    private native int nativeInit();
+    private native void nativeDestroy(int nativeChromeBrowserProvider);
+    private native long nativeAddBookmark(
+            int nativeChromeBrowserProvider,
+            String url, String title, boolean isFolder, long parentId);
+    private static native String nativeGetDomainAndRegistry(String url);
+    private static native void nativeCreateHistoricalTabFromState(
+            byte[] state, int tab_index);
+    private native byte[] nativeGetStateAsByteArray(View view);
+    private static native String[] nativeGetAutofillProfileGUIDs();
+    private native void nativeSetRecognitionResults(
+            int sessionId, String[] results);
+    private native long nativeAddBookmarkFromAPI(
+            int nativeChromeBrowserProvider,
+            String url, Long created, Boolean isBookmark,
+            Long date, byte[] favicon, String title, Integer visits);
+    native int nativeFindAll(String find);
+    private static native OnFrameAvailableListener nativeGetInnerClass();
+    private native Bitmap nativeQueryBitmap(
+            int nativeChromeBrowserProvider,
+            String[] projection, String selection,
+            String[] selectionArgs, String sortOrder);
+    private native void nativeGotOrientation(
+            int nativeDataFetcherImplAndroid,
+            double alpha, double beta, double gamma);
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass(
+        'org/chromium/example/jni_generator/SampleForTests')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init',
+                     params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=False, name='Destroy',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='long', static=False, name='AddBookmark',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String',
+                                   name='url'),
+                             Param(datatype='String',
+                                   name='title'),
+                             Param(datatype='boolean',
+                                   name='isFolder'),
+                             Param(datatype='long',
+                                   name='parentId')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='String', static=True,
+                     name='GetDomainAndRegistry',
+                     params=[Param(datatype='String',
+                                   name='url')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=True,
+                     name='CreateHistoricalTabFromState',
+                     params=[Param(datatype='byte[]',
+                                   name='state'),
+                             Param(datatype='int',
+                                   name='tab_index')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='byte[]', static=False,
+                     name='GetStateAsByteArray',
+                     params=[Param(datatype='View', name='view')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='String[]', static=True,
+                     name='GetAutofillProfileGUIDs', params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=False,
+                     name='SetRecognitionResults',
+                     params=[Param(datatype='int', name='sessionId'),
+                             Param(datatype='String[]', name='results')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='long', static=False,
+                     name='AddBookmarkFromAPI',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String',
+                                   name='url'),
+                             Param(datatype='Long',
+                                   name='created'),
+                             Param(datatype='Boolean',
+                                   name='isBookmark'),
+                             Param(datatype='Long',
+                                   name='date'),
+                             Param(datatype='byte[]',
+                                   name='favicon'),
+                             Param(datatype='String',
+                                   name='title'),
+                             Param(datatype='Integer',
+                                   name='visits')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='int', static=False,
+                     name='FindAll',
+                     params=[Param(datatype='String',
+                                   name='find')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='OnFrameAvailableListener', static=True,
+                     name='GetInnerClass',
+                     params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='Bitmap',
+                     static=False,
+                     name='QueryBitmap',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String[]',
+                                   name='projection'),
+                             Param(datatype='String',
+                                   name='selection'),
+                             Param(datatype='String[]',
+                                   name='selectionArgs'),
+                             Param(datatype='String',
+                                   name='sortOrder'),
+                            ],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='void', static=False,
+                     name='GotOrientation',
+                     params=[Param(datatype='int',
+                                   name='nativeDataFetcherImplAndroid'),
+                             Param(datatype='double',
+                                   name='alpha'),
+                             Param(datatype='double',
+                                   name='beta'),
+                             Param(datatype='double',
+                                   name='gamma'),
+                            ],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='content::DataFetcherImplAndroid'),
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testInnerClassNatives(self):
+    test_data = """
+    class MyInnerClass {
+      @NativeCall("MyInnerClass")
+      private native int nativeInit();
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testInnerClassNativesMultiple(self):
+    test_data = """
+    class MyInnerClass {
+      @NativeCall("MyInnerClass")
+      private native int nativeInit();
+    }
+    class MyOtherInnerClass {
+      @NativeCall("MyOtherInnerClass")
+      private native int nativeInit();
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyInnerClass',
+                     type='function'),
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyOtherInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testInnerClassNativesBothInnerAndOuter(self):
+    test_data = """
+    class MyOuterClass {
+      private native int nativeInit();
+      class MyOtherInnerClass {
+        @NativeCall("MyOtherInnerClass")
+        private native int nativeInit();
+      }
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyOtherInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testCalledByNatives(self):
+    test_data = """"
+    import android.graphics.Bitmap;
+    import android.view.View;
+    import java.io.InputStream;
+    import java.util.List;
+
+    class InnerClass {}
+
+    @CalledByNative
+    InnerClass showConfirmInfoBar(int nativeInfoBar,
+            String buttonOk, String buttonCancel, String title, Bitmap icon) {
+        InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext,
+                                             buttonOk, buttonCancel,
+                                             title, icon);
+        return infobar;
+    }
+    @CalledByNative
+    InnerClass showAutoLoginInfoBar(int nativeInfoBar,
+            String realm, String account, String args) {
+        AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext,
+                realm, account, args);
+        if (infobar.displayedAccountCount() == 0)
+            infobar = null;
+        return infobar;
+    }
+    @CalledByNative("InfoBar")
+    void dismiss();
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static boolean shouldShowAutoLogin(View view,
+            String realm, String account, String args) {
+        AccountManagerContainer accountManagerContainer =
+            new AccountManagerContainer((Activity)contentView.getContext(),
+            realm, account, args);
+        String[] logins = accountManagerContainer.getAccountLogins(null);
+        return logins.length != 0;
+    }
+    @CalledByNative
+    static InputStream openUrl(String url) {
+        return null;
+    }
+    @CalledByNative
+    private void activateHardwareAcceleration(final boolean activated,
+            final int iPid, final int iType,
+            final int iPrimaryID, final int iSecondaryID) {
+      if (!activated) {
+          return
+      }
+    }
+    @CalledByNativeUnchecked
+    private void uncheckedCall(int iParam);
+
+    @CalledByNative
+    public byte[] returnByteArray();
+
+    @CalledByNative
+    public boolean[] returnBooleanArray();
+
+    @CalledByNative
+    public char[] returnCharArray();
+
+    @CalledByNative
+    public short[] returnShortArray();
+
+    @CalledByNative
+    public int[] returnIntArray();
+
+    @CalledByNative
+    public long[] returnLongArray();
+
+    @CalledByNative
+    public double[] returnDoubleArray();
+
+    @CalledByNative
+    public Object[] returnObjectArray();
+
+    @CalledByNative
+    public byte[][] returnArrayOfByteArray();
+
+    @CalledByNative
+    public Bitmap.CompressFormat getCompressFormat();
+
+    @CalledByNative
+    public List<Bitmap.CompressFormat> getCompressFormatList();
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    called_by_natives = jni_generator.ExtractCalledByNatives(test_data)
+    golden_called_by_natives = [
+        CalledByNative(
+            return_type='InnerClass',
+            system_class=False,
+            static=False,
+            name='showConfirmInfoBar',
+            method_id_var_name='showConfirmInfoBar',
+            java_class_name='',
+            params=[Param(datatype='int', name='nativeInfoBar'),
+                    Param(datatype='String', name='buttonOk'),
+                    Param(datatype='String', name='buttonCancel'),
+                    Param(datatype='String', name='title'),
+                    Param(datatype='Bitmap', name='icon')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='InnerClass',
+            system_class=False,
+            static=False,
+            name='showAutoLoginInfoBar',
+            method_id_var_name='showAutoLoginInfoBar',
+            java_class_name='',
+            params=[Param(datatype='int', name='nativeInfoBar'),
+                    Param(datatype='String', name='realm'),
+                    Param(datatype='String', name='account'),
+                    Param(datatype='String', name='args')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='dismiss',
+            method_id_var_name='dismiss',
+            java_class_name='InfoBar',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='boolean',
+            system_class=False,
+            static=True,
+            name='shouldShowAutoLogin',
+            method_id_var_name='shouldShowAutoLogin',
+            java_class_name='',
+            params=[Param(datatype='View', name='view'),
+                    Param(datatype='String', name='realm'),
+                    Param(datatype='String', name='account'),
+                    Param(datatype='String', name='args')],
+            env_call=('Boolean', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='InputStream',
+            system_class=False,
+            static=True,
+            name='openUrl',
+            method_id_var_name='openUrl',
+            java_class_name='',
+            params=[Param(datatype='String', name='url')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='activateHardwareAcceleration',
+            method_id_var_name='activateHardwareAcceleration',
+            java_class_name='',
+            params=[Param(datatype='boolean', name='activated'),
+                    Param(datatype='int', name='iPid'),
+                    Param(datatype='int', name='iType'),
+                    Param(datatype='int', name='iPrimaryID'),
+                    Param(datatype='int', name='iSecondaryID'),
+                   ],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='uncheckedCall',
+            method_id_var_name='uncheckedCall',
+            java_class_name='',
+            params=[Param(datatype='int', name='iParam')],
+            env_call=('Void', ''),
+            unchecked=True,
+        ),
+        CalledByNative(
+            return_type='byte[]',
+            system_class=False,
+            static=False,
+            name='returnByteArray',
+            method_id_var_name='returnByteArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='boolean[]',
+            system_class=False,
+            static=False,
+            name='returnBooleanArray',
+            method_id_var_name='returnBooleanArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='char[]',
+            system_class=False,
+            static=False,
+            name='returnCharArray',
+            method_id_var_name='returnCharArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='short[]',
+            system_class=False,
+            static=False,
+            name='returnShortArray',
+            method_id_var_name='returnShortArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='int[]',
+            system_class=False,
+            static=False,
+            name='returnIntArray',
+            method_id_var_name='returnIntArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='long[]',
+            system_class=False,
+            static=False,
+            name='returnLongArray',
+            method_id_var_name='returnLongArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='double[]',
+            system_class=False,
+            static=False,
+            name='returnDoubleArray',
+            method_id_var_name='returnDoubleArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='Object[]',
+            system_class=False,
+            static=False,
+            name='returnObjectArray',
+            method_id_var_name='returnObjectArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='byte[][]',
+            system_class=False,
+            static=False,
+            name='returnArrayOfByteArray',
+            method_id_var_name='returnArrayOfByteArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='Bitmap.CompressFormat',
+            system_class=False,
+            static=False,
+            name='getCompressFormat',
+            method_id_var_name='getCompressFormat',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='List<Bitmap.CompressFormat>',
+            system_class=False,
+            static=False,
+            name='getCompressFormatList',
+            method_id_var_name='getCompressFormatList',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+    ]
+    self.assertListEquals(golden_called_by_natives, called_by_natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             [], called_by_natives, [],
+                                             TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testCalledByNativeParseError(self):
+    try:
+      jni_generator.ExtractCalledByNatives("""
+@CalledByNative
+public static int foo(); // This one is fine
+
+@CalledByNative
+scooby doo
+""")
+      self.fail('Expected a ParseError')
+    except jni_generator.ParseError, e:
+      self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines)
+
+  def testFullyQualifiedClassName(self):
+    contents = """
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import org.chromium.base.BuildInfo;
+"""
+    self.assertEquals('org/chromium/content/browser/Foo',
+                      jni_generator.ExtractFullyQualifiedJavaClassName(
+                          'org/chromium/content/browser/Foo.java', contents))
+    self.assertEquals('org/chromium/content/browser/Foo',
+                      jni_generator.ExtractFullyQualifiedJavaClassName(
+                          'frameworks/Foo.java', contents))
+    self.assertRaises(SyntaxError,
+                      jni_generator.ExtractFullyQualifiedJavaClassName,
+                      'com/foo/Bar', 'no PACKAGE line')
+
+  def testMethodNameMangling(self):
+    self.assertEquals('closeV',
+        jni_generator.GetMangledMethodName('close', [], 'void'))
+    self.assertEquals('readI_AB_I_I',
+        jni_generator.GetMangledMethodName('read',
+            [Param(name='p1',
+                   datatype='byte[]'),
+             Param(name='p2',
+                   datatype='int'),
+             Param(name='p3',
+                   datatype='int'),],
+             'int'))
+    self.assertEquals('openJIIS_JLS',
+        jni_generator.GetMangledMethodName('open',
+            [Param(name='p1',
+                   datatype='java/lang/String'),],
+             'java/io/InputStream'))
+
+  def testFromJavaPGenerics(self):
+    contents = """
+public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E>
+      implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
+    public void dummy();
+  Signature: ()V
+}
+"""
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                TestOptions())
+    self.assertEquals(1, len(jni_from_javap.called_by_natives))
+    self.assertGoldenTextEquals(jni_from_javap.GetContent())
+
+  def testSnippnetJavap6_7_8(self):
+    content_javap6 = """
+public class java.util.HashSet {
+public boolean add(java.lang.Object);
+ Signature: (Ljava/lang/Object;)Z
+}
+"""
+
+    content_javap7 = """
+public class java.util.HashSet {
+public boolean add(E);
+  Signature: (Ljava/lang/Object;)Z
+}
+"""
+
+    content_javap8 = """
+public class java.util.HashSet {
+  public boolean add(E);
+    descriptor: (Ljava/lang/Object;)Z
+}
+"""
+
+    jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'),
+                                                 TestOptions())
+    jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'),
+                                                 TestOptions())
+    jni_from_javap8 = jni_generator.JNIFromJavaP(content_javap8.split('\n'),
+                                                 TestOptions())
+    self.assertTrue(jni_from_javap6.GetContent())
+    self.assertTrue(jni_from_javap7.GetContent())
+    self.assertTrue(jni_from_javap8.GetContent())
+    # Ensure the javap7 is correctly parsed and uses the Signature field rather
+    # than the "E" parameter.
+    self.assertTextEquals(jni_from_javap6.GetContent(),
+                          jni_from_javap7.GetContent())
+    # Ensure the javap8 is correctly parsed and uses the descriptor field.
+    self.assertTextEquals(jni_from_javap7.GetContent(),
+                          jni_from_javap8.GetContent())
+
+  def testFromJavaP(self):
+    contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]),
+        'testInputStream.javap'))
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                TestOptions())
+    self.assertEquals(10, len(jni_from_javap.called_by_natives))
+    self.assertGoldenTextEquals(jni_from_javap.GetContent())
+
+  def testConstantsFromJavaP(self):
+    for f in ['testMotionEvent.javap', 'testMotionEvent.javap7']:
+      contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]),
+          f))
+      jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                  TestOptions())
+      self.assertEquals(86, len(jni_from_javap.called_by_natives))
+      self.assertGoldenTextEquals(jni_from_javap.GetContent())
+
+  def testREForNatives(self):
+    # We should not match "native SyncSetupFlow" inside the comment.
+    test_data = """
+    /**
+     * Invoked when the setup process is complete so we can disconnect from the
+     * native-side SyncSetupFlowHandler.
+     */
+    public void destroy() {
+        Log.v(TAG, "Destroying native SyncSetupFlow");
+        if (mNativeSyncSetupFlow != 0) {
+            nativeSyncSetupEnded(mNativeSyncSetupFlow);
+            mNativeSyncSetupFlow = 0;
+        }
+    }
+    private native void nativeSyncSetupEnded(
+        int nativeAndroidSyncSetupFlowHandler);
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'foo/bar', TestOptions())
+
+  def testRaisesOnNonJNIMethod(self):
+    test_data = """
+    class MyInnerClass {
+      private int Foo(int p0) {
+      }
+    }
+    """
+    self.assertRaises(SyntaxError,
+                      jni_generator.JNIFromJavaSource,
+                      test_data, 'foo/bar', TestOptions())
+
+  def testJniSelfDocumentingExample(self):
+    script_dir = os.path.dirname(sys.argv[0])
+    content = file(os.path.join(script_dir,
+        'java/src/org/chromium/example/jni_generator/SampleForTests.java')
+        ).read()
+    golden_file = os.path.join(script_dir, 'golden_sample_for_tests_jni.h')
+    golden_content = file(golden_file).read()
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        content, 'org/chromium/example/jni_generator/SampleForTests',
+        TestOptions())
+    generated_text = jni_from_java.GetContent()
+    if not self.compareText(golden_content, generated_text):
+      if os.environ.get(REBASELINE_ENV):
+        with file(golden_file, 'w') as f:
+          f.write(generated_text)
+        return
+      self.fail('testJniSelfDocumentingExample')
+
+  def testNoWrappingPreprocessorLines(self):
+    test_data = """
+    package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday;
+
+    class ReallyLongClassNamesAreAllTheRage {
+        private static native int nativeTest();
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, ('com/google/lookhowextremelylongiam/snarf/'
+                    'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'),
+        TestOptions())
+    jni_lines = jni_from_java.GetContent().split('\n')
+    line = filter(lambda line: line.lstrip().startswith('#ifndef'),
+                  jni_lines)[0]
+    self.assertTrue(len(line) > 80,
+                    ('Expected #ifndef line to be > 80 chars: ', line))
+
+  def testJarJarRemapping(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    import org.chromium.example2.Test;
+
+    import org.chromium.example3.PrefixFoo;
+    import org.chromium.example3.Prefix;
+    import org.chromium.example3.Bar$Inner;
+
+    class Example {
+      private static native void nativeTest(Test t);
+      private static native void nativeTest2(PrefixFoo t);
+      private static native void nativeTest3(Prefix t);
+      private static native void nativeTest4(Bar$Inner t);
+    }
+    """
+    jni_generator.JniParams.SetJarJarMappings(
+        """rule org.chromium.example.** com.test.@1
+        rule org.chromium.example2.** org.test2.@1
+        rule org.chromium.example3.Prefix org.test3.Test
+        rule org.chromium.example3.Bar$** org.test3.TestBar$@1""")
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Example', TestOptions())
+    jni_generator.JniParams.SetJarJarMappings('')
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testImports(self):
+    import_header = """
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.app;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.ArrayList;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.content.app.ContentMain;
+import org.chromium.content.browser.SandboxedProcessConnection;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+import org.chromium.content.common.WillNotRaise.AnException;
+import org.chromium.content.common.WillRaise.AnException;
+
+import static org.chromium.Bar.Zoo;
+
+class Foo {
+  public static class BookmarkNode implements Parcelable {
+  }
+  public interface PasswordListObserver {
+  }
+}
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass(
+        'org/chromium/content/app/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header)
+    self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/Bar/Zoo' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner;',
+                      jni_generator.JniParams.JavaToJni('ContentMain.Inner'))
+    self.assertRaises(SyntaxError,
+                      jni_generator.JniParams.JavaToJni,
+                      'AnException')
+
+  def testJniParamsJavaToJni(self):
+    self.assertTextEquals('I', JniParams.JavaToJni('int'))
+    self.assertTextEquals('[B', JniParams.JavaToJni('byte[]'))
+    self.assertTextEquals(
+        '[Ljava/nio/ByteBuffer;', JniParams.JavaToJni('java/nio/ByteBuffer[]'))
+
+  def testNativesLong(self):
+    test_options = TestOptions()
+    test_options.ptr_type = 'long'
+    test_data = """"
+    private native void nativeDestroy(long nativeChromeBrowserProvider);
+    """
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type)
+    golden_natives = [
+        NativeMethod(return_type='void', static=False, name='Destroy',
+                     params=[Param(datatype='long',
+                                   name='nativeChromeBrowserProvider')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider',
+                     ptr_type=test_options.ptr_type),
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], test_options)
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testPureNativeMethodsOption(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native long nativeMethod(long nativeTest, int arg1);
+    }
+    """
+    options = TestOptions()
+    options.pure_native_methods = True
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Test', options)
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testJNIInitNativeNameOption(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native boolean nativeInitNativeClass();
+        private static native int nativeMethod(long nativeTest, int arg1);
+    }
+    """
+    options = TestOptions()
+    options.jni_init_native_name = 'nativeInitNativeClass'
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Test', options)
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testEagerCalledByNativesOption(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native boolean nativeInitNativeClass();
+        private static native int nativeMethod(long nativeTest, int arg1);
+        @CalledByNative
+        private void testMethodWithParam(int iParam);
+        @CalledByNative
+        private static int testStaticMethodWithParam(int iParam);
+        @CalledByNative
+        private static double testMethodWithNoParam();
+        @CalledByNative
+        private static String testStaticMethodWithNoParam();
+    }
+    """
+    options = TestOptions()
+    options.jni_init_native_name = 'nativeInitNativeClass'
+    options.eager_called_by_natives = True
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Test', options)
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def runNativeExportsOption(self, optional):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native boolean nativeInitNativeClass();
+        private static native int nativeStaticMethod(long nativeTest, int arg1);
+        private native int nativeMethod(long nativeTest, int arg1);
+        @CalledByNative
+        private void testMethodWithParam(int iParam);
+        @CalledByNative
+        private String testMethodWithParamAndReturn(int iParam);
+        @CalledByNative
+        private static int testStaticMethodWithParam(int iParam);
+        @CalledByNative
+        private static double testMethodWithNoParam();
+        @CalledByNative
+        private static String testStaticMethodWithNoParam();
+
+        class MyInnerClass {
+          @NativeCall("MyInnerClass")
+          private native int nativeInit();
+        }
+        class MyOtherInnerClass {
+          @NativeCall("MyOtherInnerClass")
+          private native int nativeInit();
+        }
+    }
+    """
+    options = TestOptions()
+    options.jni_init_native_name = 'nativeInitNativeClass'
+    options.native_exports = True
+    options.native_exports_optional = optional
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/SampleForTests', options)
+    return jni_from_java.GetContent()
+
+  def testNativeExportsOption(self):
+    content = self.runNativeExportsOption(False)
+    self.assertGoldenTextEquals(content)
+
+  def testNativeExportsOptionalOption(self):
+    content = self.runNativeExportsOption(True)
+    self.assertGoldenTextEquals(content)
+
+  def testOuterInnerRaises(self):
+    test_data = """
+    package org.chromium.media;
+
+    @CalledByNative
+    static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) {
+        return format.getWidth();
+    }
+    """
+    def willRaise():
+      jni_generator.JNIFromJavaSource(
+          test_data,
+          'org/chromium/media/VideoCaptureFactory',
+          TestOptions())
+    self.assertRaises(SyntaxError, willRaise)
+
+  def testImplicitImport(self):
+    test_data = """
+    package org.chromium.android_webview;
+
+    %(IMPORT)s
+
+    @CalledByNative
+    private static void clientCertificatesCleared(Runnable callback) {
+        if (callbaback == null) return;
+        callback.run();
+    }
+    """
+    def generate(import_clause):
+      jni_generator.JNIFromJavaSource(
+          test_data % {'IMPORT': import_clause},
+          'org/chromium/android_webview/AwContentStatics',
+          TestOptions())
+    # Ensure it raises without the import.
+    self.assertRaises(SyntaxError, lambda: generate(''))
+
+    # Ensure it's fine with the import.
+    generate('import java.lang.Runnable;')
+
+  def testSingleJNIAdditionalImport(self):
+    test_data = """
+    package org.chromium.foo;
+
+    @JNIAdditionalImport(Bar.class)
+    class Foo {
+
+    @CalledByNative
+    private static void calledByNative(Bar.Callback callback) {
+    }
+
+    private static native void nativeDoSomething(Bar.Callback callback);
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(test_data,
+                                                    'org/chromium/foo/Foo',
+                                                    TestOptions())
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testMultipleJNIAdditionalImport(self):
+    test_data = """
+    package org.chromium.foo;
+
+    @JNIAdditionalImport({Bar1.class, Bar2.class})
+    class Foo {
+
+    @CalledByNative
+    private static void calledByNative(Bar1.Callback callback1,
+                                       Bar2.Callback callback2) {
+    }
+
+    private static native void nativeDoSomething(Bar1.Callback callback1,
+                                                 Bar2.Callback callback2);
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(test_data,
+                                                    'org/chromium/foo/Foo',
+                                                    TestOptions())
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+
+def TouchStamp(stamp_path):
+  dir_name = os.path.dirname(stamp_path)
+  if not os.path.isdir(dir_name):
+    os.makedirs()
+
+  with open(stamp_path, 'a'):
+    os.utime(stamp_path, None)
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('--stamp', help='Path to touch on success.')
+  options, _ = parser.parse_args(argv[1:])
+
+  test_result = unittest.main(argv=argv[0:1], exit=False)
+
+  if test_result.result.wasSuccessful() and options.stamp:
+    TouchStamp(options.stamp)
+
+  return not test_result.result.wasSuccessful()
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc
new file mode 100644
index 0000000..6707742
--- /dev/null
+++ b/base/android/jni_generator/sample_for_tests.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_generator/sample_for_tests.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "jni/SampleForTests_jni.h"
+
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+
+namespace base {
+namespace android {
+
+jdouble CPPClass::InnerClass::MethodOtherP0(JNIEnv* env, jobject obj) {
+  return 0.0;
+}
+
+CPPClass::CPPClass() {
+}
+
+CPPClass::~CPPClass() {
+}
+
+void CPPClass::Destroy(JNIEnv* env, jobject obj) {
+  delete this;
+}
+
+jint CPPClass::Method(JNIEnv* env, jobject obj) {
+  return 0;
+}
+
+void CPPClass::AddStructB(JNIEnv* env, jobject obj, jobject structb) {
+  long key = Java_InnerStructB_getKey(env, structb);
+  std::string value = ConvertJavaStringToUTF8(
+      env, Java_InnerStructB_getValue(env, structb).obj());
+  map_[key] = value;
+}
+
+void CPPClass::IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj) {
+  // Iterate over the elements and do something with them.
+  for (std::map<long, std::string>::const_iterator it = map_.begin();
+       it != map_.end(); ++it) {
+    long key = it->first;
+    std::string value = it->second;
+  }
+  map_.clear();
+}
+
+base::android::ScopedJavaLocalRef<jstring> CPPClass::ReturnAString(
+    JNIEnv* env, jobject obj) {
+  base::android::ScopedJavaLocalRef<jstring> ret = ConvertUTF8ToJavaString(
+      env, "test");
+  return ret;
+}
+
+// Static free functions declared and called directly from java.
+static jlong Init(JNIEnv* env, jobject obj, jstring param) {
+  return 0;
+}
+
+static jdouble GetDoubleFunction(JNIEnv*, jobject) {
+  return 0;
+}
+
+static jfloat GetFloatFunction(JNIEnv*, jclass) {
+  return 0;
+}
+
+static void SetNonPODDatatype(JNIEnv*, jobject, jobject) {
+}
+
+static jobject GetNonPODDatatype(JNIEnv*, jobject) {
+  return NULL;
+}
+
+static jint InnerFunction(JNIEnv*, jclass) {
+  return 0;
+}
+
+} // namespace android
+} // namespace base
+
+int main() {
+  // On a regular application, you'd call AttachCurrentThread(). This sample is
+  // not yet linking with all the libraries.
+  JNIEnv* env = /* AttachCurrentThread() */ NULL;
+
+  // This is how you call a java static method from C++.
+  bool foo = base::android::Java_SampleForTests_staticJavaMethod(env);
+
+  // This is how you call a java method from C++. Note that you must have
+  // obtained the jobject somehow.
+  jobject my_java_object = NULL;
+  int bar = base::android::Java_SampleForTests_javaMethod(
+      env, my_java_object, 1, 2);
+
+  for (int i = 0; i < 10; ++i) {
+    // Creates a "struct" that will then be used by the java side.
+    ScopedJavaLocalRef<jobject> struct_a =
+        base::android::Java_InnerStructA_create(
+            env, 0, 1,
+            base::android::ConvertUTF8ToJavaString(env, "test").obj());
+    base::android::Java_SampleForTests_addStructA(
+        env, my_java_object, struct_a.obj());
+  }
+  base::android::Java_SampleForTests_iterateAndDoSomething(env, my_java_object);
+  return 0;
+}
diff --git a/base/android/jni_generator/sample_for_tests.h b/base/android/jni_generator/sample_for_tests.h
new file mode 100644
index 0000000..c98cf97
--- /dev/null
+++ b/base/android/jni_generator/sample_for_tests.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
+#define BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
+
+#include <jni.h>
+#include <map>
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+// This file is used to:
+// - document the best practices and guidelines on JNI usage.
+// - ensure sample_for_tests_jni.h compiles and the functions declared in it
+// as expected.
+//
+// All methods are called directly from Java. See more documentation in
+// SampleForTests.java.
+class CPPClass {
+ public:
+  CPPClass();
+  ~CPPClass();
+
+  class InnerClass {
+   public:
+    jdouble MethodOtherP0(JNIEnv* env, jobject obj);
+  };
+
+  void Destroy(JNIEnv* env, jobject obj);
+
+  jint Method(JNIEnv* env, jobject obj);
+
+  void AddStructB(JNIEnv* env, jobject obj, jobject structb);
+
+  void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj);
+
+  base::android::ScopedJavaLocalRef<jstring> ReturnAString(
+      JNIEnv* env, jobject obj);
+
+ private:
+  std::map<long, std::string> map_;
+
+  DISALLOW_COPY_AND_ASSIGN(CPPClass);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
new file mode 100644
index 0000000..e33356a
--- /dev/null
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -0,0 +1,510 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InfoBar_clazz = NULL;
+#define InfoBar_clazz(env) g_InfoBar_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_showConfirmInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
+    nativeInfoBar,
+    jstring buttonOk,
+    jstring buttonCancel,
+    jstring title,
+    jobject icon) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "showConfirmInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Landroid/graphics/Bitmap;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+      &g_TestJni_showConfirmInfoBar);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id, as_jint(nativeInfoBar), buttonOk, buttonCancel, title,
+              icon);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_showAutoLoginInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
+    nativeInfoBar,
+    jstring realm,
+    jstring account,
+    jstring args) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "showAutoLoginInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+      &g_TestJni_showAutoLoginInfoBar);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id, as_jint(nativeInfoBar), realm, account, args);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
+static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InfoBar_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InfoBar_clazz(env),
+      "dismiss",
+
+"("
+")"
+"V",
+      &g_InfoBar_dismiss);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_shouldShowAutoLogin = 0;
+static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
+    jstring realm,
+    jstring account,
+    jstring args) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, TestJni_clazz(env),
+      TestJni_clazz(env), false);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, TestJni_clazz(env),
+      "shouldShowAutoLogin",
+
+"("
+"Landroid/view/View;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Z",
+      &g_TestJni_shouldShowAutoLogin);
+
+  jboolean ret =
+      env->CallStaticBooleanMethod(TestJni_clazz(env),
+          method_id, view, realm, account, args);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_TestJni_openUrl = 0;
+static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
+    env, jstring url) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, TestJni_clazz(env),
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, TestJni_clazz(env),
+      "openUrl",
+
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/io/InputStream;",
+      &g_TestJni_openUrl);
+
+  jobject ret =
+      env->CallStaticObjectMethod(TestJni_clazz(env),
+          method_id, url);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
+static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
+    jboolean activated,
+    JniIntWrapper iPid,
+    JniIntWrapper iType,
+    JniIntWrapper iPrimaryID,
+    JniIntWrapper iSecondaryID) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "activateHardwareAcceleration",
+
+"("
+"Z"
+"I"
+"I"
+"I"
+"I"
+")"
+"V",
+      &g_TestJni_activateHardwareAcceleration);
+
+     env->CallVoidMethod(obj,
+          method_id, activated, as_jint(iPid), as_jint(iType),
+              as_jint(iPrimaryID), as_jint(iSecondaryID));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0;
+static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, JniIntWrapper
+    iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "uncheckedCall",
+
+"("
+"I"
+")"
+"V",
+      &g_TestJni_uncheckedCall);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(iParam));
+
+}
+
+static base::subtle::AtomicWord g_TestJni_returnByteArray = 0;
+static base::android::ScopedJavaLocalRef<jbyteArray>
+    Java_TestJni_returnByteArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnByteArray",
+
+"("
+")"
+"[B",
+      &g_TestJni_returnByteArray);
+
+  jbyteArray ret =
+      static_cast<jbyteArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0;
+static base::android::ScopedJavaLocalRef<jbooleanArray>
+    Java_TestJni_returnBooleanArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnBooleanArray",
+
+"("
+")"
+"[Z",
+      &g_TestJni_returnBooleanArray);
+
+  jbooleanArray ret =
+      static_cast<jbooleanArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnCharArray = 0;
+static base::android::ScopedJavaLocalRef<jcharArray>
+    Java_TestJni_returnCharArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnCharArray",
+
+"("
+")"
+"[C",
+      &g_TestJni_returnCharArray);
+
+  jcharArray ret =
+      static_cast<jcharArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnShortArray = 0;
+static base::android::ScopedJavaLocalRef<jshortArray>
+    Java_TestJni_returnShortArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnShortArray",
+
+"("
+")"
+"[S",
+      &g_TestJni_returnShortArray);
+
+  jshortArray ret =
+      static_cast<jshortArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnIntArray = 0;
+static base::android::ScopedJavaLocalRef<jintArray>
+    Java_TestJni_returnIntArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnIntArray",
+
+"("
+")"
+"[I",
+      &g_TestJni_returnIntArray);
+
+  jintArray ret =
+      static_cast<jintArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnLongArray = 0;
+static base::android::ScopedJavaLocalRef<jlongArray>
+    Java_TestJni_returnLongArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnLongArray",
+
+"("
+")"
+"[J",
+      &g_TestJni_returnLongArray);
+
+  jlongArray ret =
+      static_cast<jlongArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0;
+static base::android::ScopedJavaLocalRef<jdoubleArray>
+    Java_TestJni_returnDoubleArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnDoubleArray",
+
+"("
+")"
+"[D",
+      &g_TestJni_returnDoubleArray);
+
+  jdoubleArray ret =
+      static_cast<jdoubleArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0;
+static base::android::ScopedJavaLocalRef<jobjectArray>
+    Java_TestJni_returnObjectArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnObjectArray",
+
+"("
+")"
+"[Ljava/lang/Object;",
+      &g_TestJni_returnObjectArray);
+
+  jobjectArray ret =
+      static_cast<jobjectArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0;
+static base::android::ScopedJavaLocalRef<jobjectArray>
+    Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnArrayOfByteArray",
+
+"("
+")"
+"[[B",
+      &g_TestJni_returnArrayOfByteArray);
+
+  jobjectArray ret =
+      static_cast<jobjectArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_getCompressFormat(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "getCompressFormat",
+
+"("
+")"
+"Landroid/graphics/Bitmap$CompressFormat;",
+      &g_TestJni_getCompressFormat);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_getCompressFormatList(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "getCompressFormatList",
+
+"("
+")"
+"Ljava/util/List;",
+      &g_TestJni_getCompressFormatList);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+  g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInfoBarClassPath).obj()));
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
new file mode 100644
index 0000000..1c816bc
--- /dev/null
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -0,0 +1,2233 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     android/view/MotionEvent
+
+#ifndef android_view_MotionEvent_JNI
+#define android_view_MotionEvent_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kMotionEventClassPath[] = "android/view/MotionEvent";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_MotionEvent_clazz = NULL;
+#define MotionEvent_clazz(env) g_MotionEvent_clazz
+
+}  // namespace
+
+namespace JNI_MotionEvent {
+
+enum Java_MotionEvent_constant_fields {
+  INVALID_POINTER_ID = -1,
+  ACTION_MASK = 255,
+  ACTION_DOWN = 0,
+  ACTION_UP = 1,
+  ACTION_MOVE = 2,
+  ACTION_CANCEL = 3,
+  ACTION_OUTSIDE = 4,
+  ACTION_POINTER_DOWN = 5,
+  ACTION_POINTER_UP = 6,
+  ACTION_HOVER_MOVE = 7,
+  ACTION_SCROLL = 8,
+  ACTION_HOVER_ENTER = 9,
+  ACTION_HOVER_EXIT = 10,
+  ACTION_POINTER_INDEX_MASK = 65280,
+  ACTION_POINTER_INDEX_SHIFT = 8,
+  ACTION_POINTER_1_DOWN = 5,
+  ACTION_POINTER_2_DOWN = 261,
+  ACTION_POINTER_3_DOWN = 517,
+  ACTION_POINTER_1_UP = 6,
+  ACTION_POINTER_2_UP = 262,
+  ACTION_POINTER_3_UP = 518,
+  ACTION_POINTER_ID_MASK = 65280,
+  ACTION_POINTER_ID_SHIFT = 8,
+  FLAG_WINDOW_IS_OBSCURED = 1,
+  EDGE_TOP = 1,
+  EDGE_BOTTOM = 2,
+  EDGE_LEFT = 4,
+  EDGE_RIGHT = 8,
+  AXIS_X = 0,
+  AXIS_Y = 1,
+  AXIS_PRESSURE = 2,
+  AXIS_SIZE = 3,
+  AXIS_TOUCH_MAJOR = 4,
+  AXIS_TOUCH_MINOR = 5,
+  AXIS_TOOL_MAJOR = 6,
+  AXIS_TOOL_MINOR = 7,
+  AXIS_ORIENTATION = 8,
+  AXIS_VSCROLL = 9,
+  AXIS_HSCROLL = 10,
+  AXIS_Z = 11,
+  AXIS_RX = 12,
+  AXIS_RY = 13,
+  AXIS_RZ = 14,
+  AXIS_HAT_X = 15,
+  AXIS_HAT_Y = 16,
+  AXIS_LTRIGGER = 17,
+  AXIS_RTRIGGER = 18,
+  AXIS_THROTTLE = 19,
+  AXIS_RUDDER = 20,
+  AXIS_WHEEL = 21,
+  AXIS_GAS = 22,
+  AXIS_BRAKE = 23,
+  AXIS_DISTANCE = 24,
+  AXIS_TILT = 25,
+  AXIS_GENERIC_1 = 32,
+  AXIS_GENERIC_2 = 33,
+  AXIS_GENERIC_3 = 34,
+  AXIS_GENERIC_4 = 35,
+  AXIS_GENERIC_5 = 36,
+  AXIS_GENERIC_6 = 37,
+  AXIS_GENERIC_7 = 38,
+  AXIS_GENERIC_8 = 39,
+  AXIS_GENERIC_9 = 40,
+  AXIS_GENERIC_10 = 41,
+  AXIS_GENERIC_11 = 42,
+  AXIS_GENERIC_12 = 43,
+  AXIS_GENERIC_13 = 44,
+  AXIS_GENERIC_14 = 45,
+  AXIS_GENERIC_15 = 46,
+  AXIS_GENERIC_16 = 47,
+  BUTTON_PRIMARY = 1,
+  BUTTON_SECONDARY = 2,
+  BUTTON_TERTIARY = 4,
+  BUTTON_BACK = 8,
+  BUTTON_FORWARD = 16,
+  TOOL_TYPE_UNKNOWN = 0,
+  TOOL_TYPE_FINGER = 1,
+  TOOL_TYPE_STYLUS = 2,
+  TOOL_TYPE_MOUSE = 3,
+  TOOL_TYPE_ERASER = 4,
+};
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_MotionEvent_finalize = 0;
+static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "finalize",
+      "()V",
+      &g_MotionEvent_finalize);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord
+    g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
+    env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jobjectArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12,
+    JniIntWrapper p13) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
+    env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jobjectArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12,
+    JniIntWrapper p13) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+"(JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6),
+              as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
+              as_jint(p13));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord
+    g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
+    jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jintArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    jfloat p7,
+    jfloat p8,
+    JniIntWrapper p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
+    jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jintArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    jfloat p7,
+    jfloat p8,
+    JniIntWrapper p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+"(JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6), p7,
+              p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I
+    = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(JJIFFFFIFFII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
+              as_jint(p10), as_jint(p11));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord
+    g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    jfloat p7,
+    JniIntWrapper p8,
+    jfloat p9,
+    jfloat p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    jfloat p7,
+    JniIntWrapper p8,
+    jfloat p9,
+    jfloat p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(JJIIFFFFIFFII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
+              as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(JJIFFI)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_F_F_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainAVME_AVME = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_AVME);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainNoHistory = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtainNoHistory",
+      "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainNoHistory);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_recycle = 0;
+static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "recycle",
+      "()V",
+      &g_MotionEvent_recycle);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getDeviceId = 0;
+static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getDeviceId",
+      "()I",
+      &g_MotionEvent_getDeviceId);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getSource = 0;
+static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getSource",
+      "()I",
+      &g_MotionEvent_getSource);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setSource = 0;
+static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setSource",
+      "(I)V",
+      &g_MotionEvent_setSource);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getAction = 0;
+static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getAction",
+      "()I",
+      &g_MotionEvent_getAction);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getActionMasked = 0;
+static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getActionMasked",
+      "()I",
+      &g_MotionEvent_getActionMasked);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getActionIndex = 0;
+static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getActionIndex",
+      "()I",
+      &g_MotionEvent_getActionIndex);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getFlags = 0;
+static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getFlags",
+      "()I",
+      &g_MotionEvent_getFlags);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getDownTime = 0;
+static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getDownTime",
+      "()J",
+      &g_MotionEvent_getDownTime);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getEventTime = 0;
+static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getEventTime",
+      "()J",
+      &g_MotionEvent_getEventTime);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getXF = 0;
+static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getX",
+      "()F",
+      &g_MotionEvent_getXF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getYF = 0;
+static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getY",
+      "()F",
+      &g_MotionEvent_getYF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPressureF = 0;
+static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPressure",
+      "()F",
+      &g_MotionEvent_getPressureF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getSizeF = 0;
+static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getSize",
+      "()F",
+      &g_MotionEvent_getSizeF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF = 0;
+static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMajor",
+      "()F",
+      &g_MotionEvent_getTouchMajorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF = 0;
+static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMinor",
+      "()F",
+      &g_MotionEvent_getTouchMinorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMajorF = 0;
+static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMajor",
+      "()F",
+      &g_MotionEvent_getToolMajorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMinorF = 0;
+static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMinor",
+      "()F",
+      &g_MotionEvent_getToolMinorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getOrientationF = 0;
+static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getOrientation",
+      "()F",
+      &g_MotionEvent_getOrientationF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I = 0;
+static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getAxisValue",
+      "(I)F",
+      &g_MotionEvent_getAxisValueF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerCount = 0;
+static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerCount",
+      "()I",
+      &g_MotionEvent_getPointerCount);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerId = 0;
+static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerId",
+      "(I)I",
+      &g_MotionEvent_getPointerId);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolType = 0;
+static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolType",
+      "(I)I",
+      &g_MotionEvent_getToolType);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_findPointerIndex = 0;
+static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "findPointerIndex",
+      "(I)I",
+      &g_MotionEvent_findPointerIndex);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getXF_I = 0;
+static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getX",
+      "(I)F",
+      &g_MotionEvent_getXF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getYF_I = 0;
+static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getY",
+      "(I)F",
+      &g_MotionEvent_getYF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPressureF_I = 0;
+static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPressure",
+      "(I)F",
+      &g_MotionEvent_getPressureF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getSizeF_I = 0;
+static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getSize",
+      "(I)F",
+      &g_MotionEvent_getSizeF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF_I = 0;
+static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMajor",
+      "(I)F",
+      &g_MotionEvent_getTouchMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF_I = 0;
+static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMinor",
+      "(I)F",
+      &g_MotionEvent_getTouchMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMajorF_I = 0;
+static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMajor",
+      "(I)F",
+      &g_MotionEvent_getToolMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMinorF_I = 0;
+static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMinor",
+      "(I)F",
+      &g_MotionEvent_getToolMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getOrientationF_I = 0;
+static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getOrientation",
+      "(I)F",
+      &g_MotionEvent_getOrientationF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I_I = 0;
+static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getAxisValue",
+      "(II)F",
+      &g_MotionEvent_getAxisValueF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerCoords = 0;
+static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) __attribute__ ((unused));
+static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerCoords",
+      "(ILandroid/view/MotionEvent$PointerCoords;)V",
+      &g_MotionEvent_getPointerCoords);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0), p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerProperties = 0;
+static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) __attribute__ ((unused));
+static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerProperties",
+      "(ILandroid/view/MotionEvent$PointerProperties;)V",
+      &g_MotionEvent_getPointerProperties);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0), p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getMetaState = 0;
+static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getMetaState",
+      "()I",
+      &g_MotionEvent_getMetaState);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getButtonState = 0;
+static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getButtonState",
+      "()I",
+      &g_MotionEvent_getButtonState);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getRawX = 0;
+static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getRawX",
+      "()F",
+      &g_MotionEvent_getRawX);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getRawY = 0;
+static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getRawY",
+      "()F",
+      &g_MotionEvent_getRawY);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getXPrecision = 0;
+static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getXPrecision",
+      "()F",
+      &g_MotionEvent_getXPrecision);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getYPrecision = 0;
+static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getYPrecision",
+      "()F",
+      &g_MotionEvent_getYPrecision);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistorySize = 0;
+static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistorySize",
+      "()I",
+      &g_MotionEvent_getHistorySize);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalEventTime = 0;
+static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalEventTime",
+      "(I)J",
+      &g_MotionEvent_getHistoricalEventTime);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalX",
+      "(I)F",
+      &g_MotionEvent_getHistoricalXF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalY",
+      "(I)F",
+      &g_MotionEvent_getHistoricalYF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalPressure",
+      "(I)F",
+      &g_MotionEvent_getHistoricalPressureF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalSize",
+      "(I)F",
+      &g_MotionEvent_getHistoricalSizeF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMajor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalTouchMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMinor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalTouchMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMajor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalToolMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMinor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalToolMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalOrientation",
+      "(I)F",
+      &g_MotionEvent_getHistoricalOrientationF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalAxisValue",
+      "(II)F",
+      &g_MotionEvent_getHistoricalAxisValueF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalX",
+      "(II)F",
+      &g_MotionEvent_getHistoricalXF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalY",
+      "(II)F",
+      &g_MotionEvent_getHistoricalYF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalPressure",
+      "(II)F",
+      &g_MotionEvent_getHistoricalPressureF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalSize",
+      "(II)F",
+      &g_MotionEvent_getHistoricalSizeF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMajor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalTouchMajorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMinor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalTouchMinorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMajor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalToolMajorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMinor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalToolMinorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalOrientation",
+      "(II)F",
+      &g_MotionEvent_getHistoricalOrientationF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalAxisValue",
+      "(III)F",
+      &g_MotionEvent_getHistoricalAxisValueF_I_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1), as_jint(p2));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalPointerCoords = 0;
+static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    jobject p2) __attribute__ ((unused));
+static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    jobject p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalPointerCoords",
+      "(IILandroid/view/MotionEvent$PointerCoords;)V",
+      &g_MotionEvent_getHistoricalPointerCoords);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0), as_jint(p1), p2);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getEdgeFlags = 0;
+static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getEdgeFlags",
+      "()I",
+      &g_MotionEvent_getEdgeFlags);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setEdgeFlags = 0;
+static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setEdgeFlags",
+      "(I)V",
+      &g_MotionEvent_setEdgeFlags);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setAction = 0;
+static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setAction",
+      "(I)V",
+      &g_MotionEvent_setAction);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_offsetLocation = 0;
+static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) __attribute__ ((unused));
+static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "offsetLocation",
+      "(FF)V",
+      &g_MotionEvent_offsetLocation);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setLocation = 0;
+static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) __attribute__ ((unused));
+static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setLocation",
+      "(FF)V",
+      &g_MotionEvent_setLocation);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_transform = 0;
+static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0)
+    __attribute__ ((unused));
+static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "transform",
+      "(Landroid/graphics/Matrix;)V",
+      &g_MotionEvent_transform);
+
+     env->CallVoidMethod(obj,
+          method_id, p0);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_F_F_F_F_I = 0;
+static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jfloat p1,
+    jfloat p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) __attribute__ ((unused));
+static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jfloat p1,
+    jfloat p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "addBatch",
+      "(JFFFFI)V",
+      &g_MotionEvent_addBatchV_J_F_F_F_F_I);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1, p2, p3, p4, as_jint(p5));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_LAVMEPC_I = 0;
+static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jobjectArray p1,
+    JniIntWrapper p2) __attribute__ ((unused));
+static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jobjectArray p1,
+    JniIntWrapper p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "addBatch",
+      "(J[Landroid/view/MotionEvent$PointerCoords;I)V",
+      &g_MotionEvent_addBatchV_J_LAVMEPC_I);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1, as_jint(p2));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_toString = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_toString(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_toString(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "toString",
+      "()Ljava/lang/String;",
+      &g_MotionEvent_toString);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_actionToString = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "actionToString",
+      "(I)Ljava/lang/String;",
+      &g_MotionEvent_actionToString);
+
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, as_jint(p0)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_axisToString = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "axisToString",
+      "(I)Ljava/lang/String;",
+      &g_MotionEvent_axisToString);
+
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, as_jint(p0)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_axisFromString = 0;
+static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "axisFromString",
+      "(Ljava/lang/String;)I",
+      &g_MotionEvent_axisFromString);
+
+  jint ret =
+      env->CallStaticIntMethod(MotionEvent_clazz(env),
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_writeToParcel = 0;
+static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "writeToParcel",
+      "(Landroid/os/Parcel;I)V",
+      &g_MotionEvent_writeToParcel);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, as_jint(p1));
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_MotionEvent_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kMotionEventClassPath).obj()));
+
+  return true;
+}
+
+}  // namespace JNI_MotionEvent
+
+#endif  // android_view_MotionEvent_JNI
diff --git a/base/android/jni_generator/testEagerCalledByNativesOption.golden b/base/android/jni_generator/testEagerCalledByNativesOption.golden
new file mode 100644
index 0000000..19108bf
--- /dev/null
+++ b/base/android/jni_generator/testEagerCalledByNativesOption.golden
@@ -0,0 +1,146 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/Test
+
+#ifndef org_chromium_example_jni_generator_Test_JNI
+#define org_chromium_example_jni_generator_Test_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
+jmethodID g_Test_testMethodWithParam = NULL;
+jmethodID g_Test_testStaticMethodWithParam = NULL;
+jmethodID g_Test_testMethodWithNoParam = NULL;
+jmethodID g_Test_testStaticMethodWithNoParam = NULL;
+}  // namespace
+
+// Step 2: method stubs.
+static jint Method(JNIEnv* env, jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller, arg1);
+}
+
+namespace {
+
+static void testMethodWithParam(JNIEnv* env, jobject obj, JniIntWrapper iParam)
+    {
+  env->CallVoidMethod(obj,
+      g_Test_testMethodWithParam, as_jint(iParam));
+
+}
+
+static jint testStaticMethodWithParam(JNIEnv* env, JniIntWrapper iParam) {
+  jint ret = env->CallStaticIntMethod(Test_clazz(env),
+      g_Test_testStaticMethodWithParam, as_jint(iParam));
+  return ret;
+}
+
+static jdouble testMethodWithNoParam(JNIEnv* env) {
+  jdouble ret = env->CallStaticDoubleMethod(Test_clazz(env),
+      g_Test_testMethodWithNoParam);
+  return ret;
+}
+
+static base::android::ScopedJavaLocalRef<jstring>
+    testStaticMethodWithNoParam(JNIEnv* env) {
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(Test_clazz(env),
+      g_Test_testStaticMethodWithNoParam));
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+}  // namespace
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTest[] = {
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I", reinterpret_cast<void*>(Method) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
+  g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
+
+  const int kMethodsTestSize = arraysize(kMethodsTest);
+
+  if (env->RegisterNatives(Test_clazz(env),
+                           kMethodsTest,
+                           kMethodsTestSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Test_clazz(env), __FILE__);
+    return false;
+  }
+
+  g_Test_testMethodWithParam = env->GetMethodID(
+      Test_clazz(env),
+      "testMethodWithParam",
+"("
+"I"
+")"
+"V");
+  if (g_Test_testMethodWithParam == NULL) {
+    return false;
+  }
+
+  g_Test_testStaticMethodWithParam = env->GetStaticMethodID(
+      Test_clazz(env),
+      "testStaticMethodWithParam",
+"("
+"I"
+")"
+"I");
+  if (g_Test_testStaticMethodWithParam == NULL) {
+    return false;
+  }
+
+  g_Test_testMethodWithNoParam = env->GetStaticMethodID(
+      Test_clazz(env),
+      "testMethodWithNoParam",
+"("
+")"
+"D");
+  if (g_Test_testMethodWithNoParam == NULL) {
+    return false;
+  }
+
+  g_Test_testStaticMethodWithNoParam = env->GetStaticMethodID(
+      Test_clazz(env),
+      "testStaticMethodWithNoParam",
+"("
+")"
+"Ljava/lang/String;");
+  if (g_Test_testStaticMethodWithNoParam == NULL) {
+    return false;
+  }
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_generator_Test_nativeInitNativeClass(JNIEnv* env,
+    jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
new file mode 100644
index 0000000..b7276bc
--- /dev/null
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -0,0 +1,267 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     java/io/InputStream
+
+#ifndef java_io_InputStream_JNI
+#define java_io_InputStream_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kInputStreamClassPath[] = "java/io/InputStream";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InputStream_clazz = NULL;
+#define InputStream_clazz(env) g_InputStream_clazz
+
+}  // namespace
+
+namespace JNI_InputStream {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_InputStream_available = 0;
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "available",
+      "()I",
+      &g_InputStream_available);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_close = 0;
+static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_InputStream_close(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "close",
+      "()V",
+      &g_InputStream_close);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_mark = 0;
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0)
+    __attribute__ ((unused));
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "mark",
+      "(I)V",
+      &g_InputStream_mark);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_markSupported = 0;
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), false);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "markSupported",
+      "()Z",
+      &g_InputStream_markSupported);
+
+  jboolean ret =
+      env->CallBooleanMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI = 0;
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "read",
+      "()I",
+      &g_InputStream_readI);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB = 0;
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0)
+    __attribute__ ((unused));
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "read",
+      "([B)I",
+      &g_InputStream_readI_AB);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB_I_I = 0;
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+    p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) __attribute__ ((unused));
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+    p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "read",
+      "([BII)I",
+      &g_InputStream_readI_AB_I_I);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, p0, as_jint(p1), as_jint(p2));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_reset = 0;
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "reset",
+      "()V",
+      &g_InputStream_reset);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_skip = 0;
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0)
+    __attribute__ ((unused));
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "skip",
+      "(J)J",
+      &g_InputStream_skip);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_Constructor = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InputStream_Constructor(JNIEnv* env) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InputStream_Constructor(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, InputStream_clazz(env),
+      InputStream_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "<init>",
+      "()V",
+      &g_InputStream_Constructor);
+
+  jobject ret =
+      env->NewObject(InputStream_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInputStreamClassPath).obj()));
+
+  return true;
+}
+
+}  // namespace JNI_InputStream
+
+#endif  // java_io_InputStream_JNI
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
new file mode 100644
index 0000000..489872c
--- /dev/null
+++ b/base/android/jni_generator/testFromJavaPGenerics.golden
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     java/util/HashSet
+
+#ifndef java_util_HashSet_JNI
+#define java_util_HashSet_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kHashSetClassPath[] = "java/util/HashSet";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_HashSet_clazz = NULL;
+#define HashSet_clazz(env) g_HashSet_clazz
+
+}  // namespace
+
+namespace JNI_HashSet {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_HashSet_dummy = 0;
+static void Java_HashSet_dummy(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      HashSet_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, HashSet_clazz(env),
+      "dummy",
+      "()V",
+      &g_HashSet_dummy);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_HashSet_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kHashSetClassPath).obj()));
+
+  return true;
+}
+
+}  // namespace JNI_HashSet
+
+#endif  // java_util_HashSet_JNI
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
new file mode 100644
index 0000000..5a525ef
--- /dev/null
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
new file mode 100644
index 0000000..c8d4b3c
--- /dev/null
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kMyOtherInnerClassClassPath[] =
+    "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsMyOtherInnerClassSize =
+      arraysize(kMethodsMyOtherInnerClass);
+
+  if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
+                           kMethodsMyOtherInnerClass,
+                           kMethodsMyOtherInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyOtherInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(TestJni_clazz(env),
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, TestJni_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
new file mode 100644
index 0000000..42643ae
--- /dev/null
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kMyOtherInnerClassClassPath[] =
+    "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsMyOtherInnerClassSize =
+      arraysize(kMethodsMyOtherInnerClass);
+
+  if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
+                           kMethodsMyOtherInnerClass,
+                           kMethodsMyOtherInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyOtherInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInputStream.javap b/base/android/jni_generator/testInputStream.javap
new file mode 100644
index 0000000..50ab617
--- /dev/null
+++ b/base/android/jni_generator/testInputStream.javap
@@ -0,0 +1,228 @@
+Compiled from "InputStream.java"
+public abstract class java.io.InputStream extends java.lang.Object implements java.io.Closeable
+  SourceFile: "InputStream.java"
+  minor version: 0
+  major version: 49
+  Constant pool:
+const #1 = Method #6.#39; //  java/lang/Object."<init>":()V
+const #2 = class  #40;  //  java/lang/RuntimeException
+const #3 = String #41;  //  Stub!
+const #4 = Method #2.#42; //  java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+const #5 = class  #43;  //  java/io/InputStream
+const #6 = class  #44;  //  java/lang/Object
+const #7 = class  #45;  //  java/io/Closeable
+const #8 = Asciz  <init>;
+const #9 = Asciz  ()V;
+const #10 = Asciz Code;
+const #11 = Asciz LineNumberTable;
+const #12 = Asciz LocalVariableTable;
+const #13 = Asciz this;
+const #14 = Asciz Ljava/io/InputStream;;
+const #15 = Asciz available;
+const #16 = Asciz ()I;
+const #17 = Asciz Exceptions;
+const #18 = class #46;  //  java/io/IOException
+const #19 = Asciz close;
+const #20 = Asciz mark;
+const #21 = Asciz (I)V;
+const #22 = Asciz readlimit;
+const #23 = Asciz I;
+const #24 = Asciz markSupported;
+const #25 = Asciz ()Z;
+const #26 = Asciz read;
+const #27 = Asciz ([B)I;
+const #28 = Asciz buffer;
+const #29 = Asciz [B;
+const #30 = Asciz ([BII)I;
+const #31 = Asciz byteOffset;
+const #32 = Asciz byteCount;
+const #33 = Asciz reset;
+const #34 = Asciz skip;
+const #35 = Asciz (J)J;
+const #36 = Asciz J;
+const #37 = Asciz SourceFile;
+const #38 = Asciz InputStream.java;
+const #39 = NameAndType #8:#9;//  "<init>":()V
+const #40 = Asciz java/lang/RuntimeException;
+const #41 = Asciz Stub!;
+const #42 = NameAndType #8:#47;//  "<init>":(Ljava/lang/String;)V
+const #43 = Asciz java/io/InputStream;
+const #44 = Asciz java/lang/Object;
+const #45 = Asciz java/io/Closeable;
+const #46 = Asciz java/io/IOException;
+const #47 = Asciz (Ljava/lang/String;)V;
+
+{
+public java.io.InputStream();
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: aload_0
+   1: invokespecial #1; //Method java/lang/Object."<init>":()V
+   4: new #2; //class java/lang/RuntimeException
+   7: dup
+   8: ldc #3; //String Stub!
+   10:  invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   13:  athrow
+  LineNumberTable:
+   line 5: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      14      0    this       Ljava/io/InputStream;
+
+
+public int available()   throws java.io.IOException;
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 6: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+  Exceptions:
+   throws java.io.IOException
+public void close()   throws java.io.IOException;
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 7: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+  Exceptions:
+   throws java.io.IOException
+public void mark(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 8: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    readlimit       I
+
+
+public boolean markSupported();
+  Signature: ()Z
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 9: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+
+public abstract int read()   throws java.io.IOException;
+  Signature: ()I
+  Exceptions:
+   throws java.io.IOException
+public int read(byte[])   throws java.io.IOException;
+  Signature: ([B)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 11: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    buffer       [B
+
+  Exceptions:
+   throws java.io.IOException
+public int read(byte[], int, int)   throws java.io.IOException;
+  Signature: ([BII)I
+  Code:
+   Stack=3, Locals=4, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 12: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    buffer       [B
+   0      10      2    byteOffset       I
+   0      10      3    byteCount       I
+
+  Exceptions:
+   throws java.io.IOException
+public synchronized void reset()   throws java.io.IOException;
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 13: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+  Exceptions:
+   throws java.io.IOException
+public long skip(long)   throws java.io.IOException;
+  Signature: (J)J
+  Code:
+   Stack=3, Locals=3, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 14: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    byteCount       J
+
+  Exceptions:
+   throws java.io.IOException
+}
+
diff --git a/base/android/jni_generator/testJNIInitNativeNameOption.golden b/base/android/jni_generator/testJNIInitNativeNameOption.golden
new file mode 100644
index 0000000..a0998da
--- /dev/null
+++ b/base/android/jni_generator/testJNIInitNativeNameOption.golden
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/Test
+
+#ifndef org_chromium_example_jni_generator_Test_JNI
+#define org_chromium_example_jni_generator_Test_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+static jint Method(JNIEnv* env, jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller, arg1);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTest[] = {
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I", reinterpret_cast<void*>(Method) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
+  g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
+
+  const int kMethodsTestSize = arraysize(kMethodsTest);
+
+  if (env->RegisterNatives(Test_clazz(env),
+                           kMethodsTest,
+                           kMethodsTestSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Test_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_generator_Test_nativeInitNativeClass(JNIEnv* env,
+    jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testJarJarRemapping.golden b/base/android/jni_generator/testJarJarRemapping.golden
new file mode 100644
index 0000000..2f85122
--- /dev/null
+++ b/base/android/jni_generator/testJarJarRemapping.golden
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/Example
+
+#ifndef org_chromium_example_jni_generator_Example_JNI
+#define org_chromium_example_jni_generator_Example_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kExampleClassPath[] = "com/test/jni_generator/Example";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Example_clazz = NULL;
+#define Example_clazz(env) g_Example_clazz
+
+}  // namespace
+
+static void Test(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+static void Test2(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+static void Test3(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+static void Test4(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsExample[] = {
+    { "nativeTest",
+"("
+"Lorg/test2/Test;"
+")"
+"V", reinterpret_cast<void*>(Test) },
+    { "nativeTest2",
+"("
+"Lorg/chromium/example3/PrefixFoo;"
+")"
+"V", reinterpret_cast<void*>(Test2) },
+    { "nativeTest3",
+"("
+"Lorg/test3/Test;"
+")"
+"V", reinterpret_cast<void*>(Test3) },
+    { "nativeTest4",
+"("
+"Lorg/test3/TestBar$Inner;"
+")"
+"V", reinterpret_cast<void*>(Test4) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Example_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kExampleClassPath).obj()));
+
+  const int kMethodsExampleSize = arraysize(kMethodsExample);
+
+  if (env->RegisterNatives(Example_clazz(env),
+                           kMethodsExample,
+                           kMethodsExampleSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Example_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_example_jni_generator_Example_JNI
diff --git a/base/android/jni_generator/testMotionEvent.javap b/base/android/jni_generator/testMotionEvent.javap
new file mode 100644
index 0000000..0746943
--- /dev/null
+++ b/base/android/jni_generator/testMotionEvent.javap
@@ -0,0 +1,2295 @@
+Compiled from "MotionEvent.java"
+public final class android.view.MotionEvent extends android.view.InputEvent implements android.os.Parcelable
+  SourceFile: "MotionEvent.java"
+  InnerClass:
+   public final #10= #9 of #6; //PointerProperties=class android/view/MotionEvent$PointerProperties of class android/view/MotionEvent
+   public final #13= #12 of #6; //PointerCoords=class android/view/MotionEvent$PointerCoords of class android/view/MotionEvent
+   public abstract #150= #149 of #8; //Creator=class android/os/Parcelable$Creator of class android/os/Parcelable
+  minor version: 0
+  major version: 49
+  Constant pool:
+const #1 = Method #7.#293;  //  android/view/InputEvent."<init>":()V
+const #2 = class  #294; //  java/lang/RuntimeException
+const #3 = String #295; //  Stub!
+const #4 = Method #2.#296;  //  java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+const #5 = Field  #6.#297;  //  android/view/MotionEvent.CREATOR:Landroid/os/Parcelable$Creator;
+const #6 = class  #298; //  android/view/MotionEvent
+const #7 = class  #299; //  android/view/InputEvent
+const #8 = class  #300; //  android/os/Parcelable
+const #9 = class  #301; //  android/view/MotionEvent$PointerProperties
+const #10 = Asciz PointerProperties;
+const #11 = Asciz InnerClasses;
+const #12 = class #302; //  android/view/MotionEvent$PointerCoords
+const #13 = Asciz PointerCoords;
+const #14 = Asciz INVALID_POINTER_ID;
+const #15 = Asciz I;
+const #16 = Asciz ConstantValue;
+const #17 = int -1;
+const #18 = Asciz ACTION_MASK;
+const #19 = int 255;
+const #20 = Asciz ACTION_DOWN;
+const #21 = int 0;
+const #22 = Asciz ACTION_UP;
+const #23 = int 1;
+const #24 = Asciz ACTION_MOVE;
+const #25 = int 2;
+const #26 = Asciz ACTION_CANCEL;
+const #27 = int 3;
+const #28 = Asciz ACTION_OUTSIDE;
+const #29 = int 4;
+const #30 = Asciz ACTION_POINTER_DOWN;
+const #31 = int 5;
+const #32 = Asciz ACTION_POINTER_UP;
+const #33 = int 6;
+const #34 = Asciz ACTION_HOVER_MOVE;
+const #35 = int 7;
+const #36 = Asciz ACTION_SCROLL;
+const #37 = int 8;
+const #38 = Asciz ACTION_HOVER_ENTER;
+const #39 = int 9;
+const #40 = Asciz ACTION_HOVER_EXIT;
+const #41 = int 10;
+const #42 = Asciz ACTION_POINTER_INDEX_MASK;
+const #43 = int 65280;
+const #44 = Asciz ACTION_POINTER_INDEX_SHIFT;
+const #45 = Asciz ACTION_POINTER_1_DOWN;
+const #46 = Asciz Deprecated;
+const #47 = Asciz RuntimeVisibleAnnotations;
+const #48 = Asciz Ljava/lang/Deprecated;;
+const #49 = Asciz ACTION_POINTER_2_DOWN;
+const #50 = int 261;
+const #51 = Asciz ACTION_POINTER_3_DOWN;
+const #52 = int 517;
+const #53 = Asciz ACTION_POINTER_1_UP;
+const #54 = Asciz ACTION_POINTER_2_UP;
+const #55 = int 262;
+const #56 = Asciz ACTION_POINTER_3_UP;
+const #57 = int 518;
+const #58 = Asciz ACTION_POINTER_ID_MASK;
+const #59 = Asciz ACTION_POINTER_ID_SHIFT;
+const #60 = Asciz FLAG_WINDOW_IS_OBSCURED;
+const #61 = Asciz EDGE_TOP;
+const #62 = Asciz EDGE_BOTTOM;
+const #63 = Asciz EDGE_LEFT;
+const #64 = Asciz EDGE_RIGHT;
+const #65 = Asciz AXIS_X;
+const #66 = Asciz AXIS_Y;
+const #67 = Asciz AXIS_PRESSURE;
+const #68 = Asciz AXIS_SIZE;
+const #69 = Asciz AXIS_TOUCH_MAJOR;
+const #70 = Asciz AXIS_TOUCH_MINOR;
+const #71 = Asciz AXIS_TOOL_MAJOR;
+const #72 = Asciz AXIS_TOOL_MINOR;
+const #73 = Asciz AXIS_ORIENTATION;
+const #74 = Asciz AXIS_VSCROLL;
+const #75 = Asciz AXIS_HSCROLL;
+const #76 = Asciz AXIS_Z;
+const #77 = int 11;
+const #78 = Asciz AXIS_RX;
+const #79 = int 12;
+const #80 = Asciz AXIS_RY;
+const #81 = int 13;
+const #82 = Asciz AXIS_RZ;
+const #83 = int 14;
+const #84 = Asciz AXIS_HAT_X;
+const #85 = int 15;
+const #86 = Asciz AXIS_HAT_Y;
+const #87 = int 16;
+const #88 = Asciz AXIS_LTRIGGER;
+const #89 = int 17;
+const #90 = Asciz AXIS_RTRIGGER;
+const #91 = int 18;
+const #92 = Asciz AXIS_THROTTLE;
+const #93 = int 19;
+const #94 = Asciz AXIS_RUDDER;
+const #95 = int 20;
+const #96 = Asciz AXIS_WHEEL;
+const #97 = int 21;
+const #98 = Asciz AXIS_GAS;
+const #99 = int 22;
+const #100 = Asciz  AXIS_BRAKE;
+const #101 = int  23;
+const #102 = Asciz  AXIS_DISTANCE;
+const #103 = int  24;
+const #104 = Asciz  AXIS_TILT;
+const #105 = int  25;
+const #106 = Asciz  AXIS_GENERIC_1;
+const #107 = int  32;
+const #108 = Asciz  AXIS_GENERIC_2;
+const #109 = int  33;
+const #110 = Asciz  AXIS_GENERIC_3;
+const #111 = int  34;
+const #112 = Asciz  AXIS_GENERIC_4;
+const #113 = int  35;
+const #114 = Asciz  AXIS_GENERIC_5;
+const #115 = int  36;
+const #116 = Asciz  AXIS_GENERIC_6;
+const #117 = int  37;
+const #118 = Asciz  AXIS_GENERIC_7;
+const #119 = int  38;
+const #120 = Asciz  AXIS_GENERIC_8;
+const #121 = int  39;
+const #122 = Asciz  AXIS_GENERIC_9;
+const #123 = int  40;
+const #124 = Asciz  AXIS_GENERIC_10;
+const #125 = int  41;
+const #126 = Asciz  AXIS_GENERIC_11;
+const #127 = int  42;
+const #128 = Asciz  AXIS_GENERIC_12;
+const #129 = int  43;
+const #130 = Asciz  AXIS_GENERIC_13;
+const #131 = int  44;
+const #132 = Asciz  AXIS_GENERIC_14;
+const #133 = int  45;
+const #134 = Asciz  AXIS_GENERIC_15;
+const #135 = int  46;
+const #136 = Asciz  AXIS_GENERIC_16;
+const #137 = int  47;
+const #138 = Asciz  BUTTON_PRIMARY;
+const #139 = Asciz  BUTTON_SECONDARY;
+const #140 = Asciz  BUTTON_TERTIARY;
+const #141 = Asciz  BUTTON_BACK;
+const #142 = Asciz  BUTTON_FORWARD;
+const #143 = Asciz  TOOL_TYPE_UNKNOWN;
+const #144 = Asciz  TOOL_TYPE_FINGER;
+const #145 = Asciz  TOOL_TYPE_STYLUS;
+const #146 = Asciz  TOOL_TYPE_MOUSE;
+const #147 = Asciz  TOOL_TYPE_ERASER;
+const #148 = Asciz  CREATOR;
+const #149 = class  #303; //  android/os/Parcelable$Creator
+const #150 = Asciz  Creator;
+const #151 = Asciz  Landroid/os/Parcelable$Creator;;
+const #152 = Asciz  Signature;
+const #153 = Asciz  Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;;
+const #154 = Asciz  <init>;
+const #155 = Asciz  ()V;
+const #156 = Asciz  Code;
+const #157 = Asciz  LineNumberTable;
+const #158 = Asciz  LocalVariableTable;
+const #159 = Asciz  this;
+const #160 = Asciz  Landroid/view/MotionEvent;;
+const #161 = Asciz  finalize;
+const #162 = Asciz  Exceptions;
+const #163 = class  #304; //  java/lang/Throwable
+const #164 = Asciz  obtain;
+const #165 = Asciz  (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;;
+const #166 = Asciz  downTime;
+const #167 = Asciz  J;
+const #168 = Asciz  eventTime;
+const #169 = Asciz  action;
+const #170 = Asciz  pointerCount;
+const #171 = Asciz  pointerProperties;
+const #172 = Asciz  [Landroid/view/MotionEvent$PointerProperties;;
+const #173 = Asciz  pointerCoords;
+const #174 = Asciz  [Landroid/view/MotionEvent$PointerCoords;;
+const #175 = Asciz  metaState;
+const #176 = Asciz  buttonState;
+const #177 = Asciz  xPrecision;
+const #178 = Asciz  F;
+const #179 = Asciz  yPrecision;
+const #180 = Asciz  deviceId;
+const #181 = Asciz  edgeFlags;
+const #182 = Asciz  source;
+const #183 = Asciz  flags;
+const #184 = Asciz  (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;;
+const #185 = Asciz  pointerIds;
+const #186 = Asciz  [I;
+const #187 = Asciz  (JJIFFFFIFFII)Landroid/view/MotionEvent;;
+const #188 = Asciz  x;
+const #189 = Asciz  y;
+const #190 = Asciz  pressure;
+const #191 = Asciz  size;
+const #192 = Asciz  (JJIIFFFFIFFII)Landroid/view/MotionEvent;;
+const #193 = Asciz  (JJIFFI)Landroid/view/MotionEvent;;
+const #194 = Asciz  (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;;
+const #195 = Asciz  other;
+const #196 = Asciz  obtainNoHistory;
+const #197 = Asciz  recycle;
+const #198 = Asciz  getDeviceId;
+const #199 = Asciz  ()I;
+const #200 = Asciz  getSource;
+const #201 = Asciz  setSource;
+const #202 = Asciz  (I)V;
+const #203 = Asciz  getAction;
+const #204 = Asciz  getActionMasked;
+const #205 = Asciz  getActionIndex;
+const #206 = Asciz  getFlags;
+const #207 = Asciz  getDownTime;
+const #208 = Asciz  ()J;
+const #209 = Asciz  getEventTime;
+const #210 = Asciz  getX;
+const #211 = Asciz  ()F;
+const #212 = Asciz  getY;
+const #213 = Asciz  getPressure;
+const #214 = Asciz  getSize;
+const #215 = Asciz  getTouchMajor;
+const #216 = Asciz  getTouchMinor;
+const #217 = Asciz  getToolMajor;
+const #218 = Asciz  getToolMinor;
+const #219 = Asciz  getOrientation;
+const #220 = Asciz  getAxisValue;
+const #221 = Asciz  (I)F;
+const #222 = Asciz  axis;
+const #223 = Asciz  getPointerCount;
+const #224 = Asciz  getPointerId;
+const #225 = Asciz  (I)I;
+const #226 = Asciz  pointerIndex;
+const #227 = Asciz  getToolType;
+const #228 = Asciz  findPointerIndex;
+const #229 = Asciz  pointerId;
+const #230 = Asciz  (II)F;
+const #231 = Asciz  getPointerCoords;
+const #232 = Asciz  (ILandroid/view/MotionEvent$PointerCoords;)V;
+const #233 = Asciz  outPointerCoords;
+const #234 = Asciz  Landroid/view/MotionEvent$PointerCoords;;
+const #235 = Asciz  getPointerProperties;
+const #236 = Asciz  (ILandroid/view/MotionEvent$PointerProperties;)V;
+const #237 = Asciz  outPointerProperties;
+const #238 = Asciz  Landroid/view/MotionEvent$PointerProperties;;
+const #239 = Asciz  getMetaState;
+const #240 = Asciz  getButtonState;
+const #241 = Asciz  getRawX;
+const #242 = Asciz  getRawY;
+const #243 = Asciz  getXPrecision;
+const #244 = Asciz  getYPrecision;
+const #245 = Asciz  getHistorySize;
+const #246 = Asciz  getHistoricalEventTime;
+const #247 = Asciz  (I)J;
+const #248 = Asciz  pos;
+const #249 = Asciz  getHistoricalX;
+const #250 = Asciz  getHistoricalY;
+const #251 = Asciz  getHistoricalPressure;
+const #252 = Asciz  getHistoricalSize;
+const #253 = Asciz  getHistoricalTouchMajor;
+const #254 = Asciz  getHistoricalTouchMinor;
+const #255 = Asciz  getHistoricalToolMajor;
+const #256 = Asciz  getHistoricalToolMinor;
+const #257 = Asciz  getHistoricalOrientation;
+const #258 = Asciz  getHistoricalAxisValue;
+const #259 = Asciz  (III)F;
+const #260 = Asciz  getHistoricalPointerCoords;
+const #261 = Asciz  (IILandroid/view/MotionEvent$PointerCoords;)V;
+const #262 = Asciz  getEdgeFlags;
+const #263 = Asciz  setEdgeFlags;
+const #264 = Asciz  setAction;
+const #265 = Asciz  offsetLocation;
+const #266 = Asciz  (FF)V;
+const #267 = Asciz  deltaX;
+const #268 = Asciz  deltaY;
+const #269 = Asciz  setLocation;
+const #270 = Asciz  transform;
+const #271 = Asciz  (Landroid/graphics/Matrix;)V;
+const #272 = Asciz  matrix;
+const #273 = Asciz  Landroid/graphics/Matrix;;
+const #274 = Asciz  addBatch;
+const #275 = Asciz  (JFFFFI)V;
+const #276 = Asciz  (J[Landroid/view/MotionEvent$PointerCoords;I)V;
+const #277 = Asciz  toString;
+const #278 = Asciz  ()Ljava/lang/String;;
+const #279 = Asciz  actionToString;
+const #280 = Asciz  (I)Ljava/lang/String;;
+const #281 = Asciz  axisToString;
+const #282 = Asciz  axisFromString;
+const #283 = Asciz  (Ljava/lang/String;)I;
+const #284 = Asciz  symbolicName;
+const #285 = Asciz  Ljava/lang/String;;
+const #286 = Asciz  writeToParcel;
+const #287 = Asciz  (Landroid/os/Parcel;I)V;
+const #288 = Asciz  out;
+const #289 = Asciz  Landroid/os/Parcel;;
+const #290 = Asciz  <clinit>;
+const #291 = Asciz  SourceFile;
+const #292 = Asciz  MotionEvent.java;
+const #293 = NameAndType  #154:#155;//  "<init>":()V
+const #294 = Asciz  java/lang/RuntimeException;
+const #295 = Asciz  Stub!;
+const #296 = NameAndType  #154:#305;//  "<init>":(Ljava/lang/String;)V
+const #297 = NameAndType  #148:#151;//  CREATOR:Landroid/os/Parcelable$Creator;
+const #298 = Asciz  android/view/MotionEvent;
+const #299 = Asciz  android/view/InputEvent;
+const #300 = Asciz  android/os/Parcelable;
+const #301 = Asciz  android/view/MotionEvent$PointerProperties;
+const #302 = Asciz  android/view/MotionEvent$PointerCoords;
+const #303 = Asciz  android/os/Parcelable$Creator;
+const #304 = Asciz  java/lang/Throwable;
+const #305 = Asciz  (Ljava/lang/String;)V;
+
+{
+public static final int INVALID_POINTER_ID;
+  Signature: I
+  Constant value: int -1
+
+public static final int ACTION_MASK;
+  Signature: I
+  Constant value: int 255
+
+public static final int ACTION_DOWN;
+  Signature: I
+  Constant value: int 0
+
+public static final int ACTION_UP;
+  Signature: I
+  Constant value: int 1
+
+public static final int ACTION_MOVE;
+  Signature: I
+  Constant value: int 2
+
+public static final int ACTION_CANCEL;
+  Signature: I
+  Constant value: int 3
+
+public static final int ACTION_OUTSIDE;
+  Signature: I
+  Constant value: int 4
+
+public static final int ACTION_POINTER_DOWN;
+  Signature: I
+  Constant value: int 5
+
+public static final int ACTION_POINTER_UP;
+  Signature: I
+  Constant value: int 6
+
+public static final int ACTION_HOVER_MOVE;
+  Signature: I
+  Constant value: int 7
+
+public static final int ACTION_SCROLL;
+  Signature: I
+  Constant value: int 8
+
+public static final int ACTION_HOVER_ENTER;
+  Signature: I
+  Constant value: int 9
+
+public static final int ACTION_HOVER_EXIT;
+  Signature: I
+  Constant value: int 10
+
+public static final int ACTION_POINTER_INDEX_MASK;
+  Signature: I
+  Constant value: int 65280
+
+public static final int ACTION_POINTER_INDEX_SHIFT;
+  Signature: I
+  Constant value: int 8
+
+public static final int ACTION_POINTER_1_DOWN;
+  Signature: I
+  Constant value: int 5Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_2_DOWN;
+  Signature: I
+  Constant value: int 261Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_3_DOWN;
+  Signature: I
+  Constant value: int 517Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_1_UP;
+  Signature: I
+  Constant value: int 6Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_2_UP;
+  Signature: I
+  Constant value: int 262Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_3_UP;
+  Signature: I
+  Constant value: int 518Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_ID_MASK;
+  Signature: I
+  Constant value: int 65280Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_ID_SHIFT;
+  Signature: I
+  Constant value: int 8Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int FLAG_WINDOW_IS_OBSCURED;
+  Signature: I
+  Constant value: int 1
+
+public static final int EDGE_TOP;
+  Signature: I
+  Constant value: int 1
+
+public static final int EDGE_BOTTOM;
+  Signature: I
+  Constant value: int 2
+
+public static final int EDGE_LEFT;
+  Signature: I
+  Constant value: int 4
+
+public static final int EDGE_RIGHT;
+  Signature: I
+  Constant value: int 8
+
+public static final int AXIS_X;
+  Signature: I
+  Constant value: int 0
+
+public static final int AXIS_Y;
+  Signature: I
+  Constant value: int 1
+
+public static final int AXIS_PRESSURE;
+  Signature: I
+  Constant value: int 2
+
+public static final int AXIS_SIZE;
+  Signature: I
+  Constant value: int 3
+
+public static final int AXIS_TOUCH_MAJOR;
+  Signature: I
+  Constant value: int 4
+
+public static final int AXIS_TOUCH_MINOR;
+  Signature: I
+  Constant value: int 5
+
+public static final int AXIS_TOOL_MAJOR;
+  Signature: I
+  Constant value: int 6
+
+public static final int AXIS_TOOL_MINOR;
+  Signature: I
+  Constant value: int 7
+
+public static final int AXIS_ORIENTATION;
+  Signature: I
+  Constant value: int 8
+
+public static final int AXIS_VSCROLL;
+  Signature: I
+  Constant value: int 9
+
+public static final int AXIS_HSCROLL;
+  Signature: I
+  Constant value: int 10
+
+public static final int AXIS_Z;
+  Signature: I
+  Constant value: int 11
+
+public static final int AXIS_RX;
+  Signature: I
+  Constant value: int 12
+
+public static final int AXIS_RY;
+  Signature: I
+  Constant value: int 13
+
+public static final int AXIS_RZ;
+  Signature: I
+  Constant value: int 14
+
+public static final int AXIS_HAT_X;
+  Signature: I
+  Constant value: int 15
+
+public static final int AXIS_HAT_Y;
+  Signature: I
+  Constant value: int 16
+
+public static final int AXIS_LTRIGGER;
+  Signature: I
+  Constant value: int 17
+
+public static final int AXIS_RTRIGGER;
+  Signature: I
+  Constant value: int 18
+
+public static final int AXIS_THROTTLE;
+  Signature: I
+  Constant value: int 19
+
+public static final int AXIS_RUDDER;
+  Signature: I
+  Constant value: int 20
+
+public static final int AXIS_WHEEL;
+  Signature: I
+  Constant value: int 21
+
+public static final int AXIS_GAS;
+  Signature: I
+  Constant value: int 22
+
+public static final int AXIS_BRAKE;
+  Signature: I
+  Constant value: int 23
+
+public static final int AXIS_DISTANCE;
+  Signature: I
+  Constant value: int 24
+
+public static final int AXIS_TILT;
+  Signature: I
+  Constant value: int 25
+
+public static final int AXIS_GENERIC_1;
+  Signature: I
+  Constant value: int 32
+
+public static final int AXIS_GENERIC_2;
+  Signature: I
+  Constant value: int 33
+
+public static final int AXIS_GENERIC_3;
+  Signature: I
+  Constant value: int 34
+
+public static final int AXIS_GENERIC_4;
+  Signature: I
+  Constant value: int 35
+
+public static final int AXIS_GENERIC_5;
+  Signature: I
+  Constant value: int 36
+
+public static final int AXIS_GENERIC_6;
+  Signature: I
+  Constant value: int 37
+
+public static final int AXIS_GENERIC_7;
+  Signature: I
+  Constant value: int 38
+
+public static final int AXIS_GENERIC_8;
+  Signature: I
+  Constant value: int 39
+
+public static final int AXIS_GENERIC_9;
+  Signature: I
+  Constant value: int 40
+
+public static final int AXIS_GENERIC_10;
+  Signature: I
+  Constant value: int 41
+
+public static final int AXIS_GENERIC_11;
+  Signature: I
+  Constant value: int 42
+
+public static final int AXIS_GENERIC_12;
+  Signature: I
+  Constant value: int 43
+
+public static final int AXIS_GENERIC_13;
+  Signature: I
+  Constant value: int 44
+
+public static final int AXIS_GENERIC_14;
+  Signature: I
+  Constant value: int 45
+
+public static final int AXIS_GENERIC_15;
+  Signature: I
+  Constant value: int 46
+
+public static final int AXIS_GENERIC_16;
+  Signature: I
+  Constant value: int 47
+
+public static final int BUTTON_PRIMARY;
+  Signature: I
+  Constant value: int 1
+
+public static final int BUTTON_SECONDARY;
+  Signature: I
+  Constant value: int 2
+
+public static final int BUTTON_TERTIARY;
+  Signature: I
+  Constant value: int 4
+
+public static final int BUTTON_BACK;
+  Signature: I
+  Constant value: int 8
+
+public static final int BUTTON_FORWARD;
+  Signature: I
+  Constant value: int 16
+
+public static final int TOOL_TYPE_UNKNOWN;
+  Signature: I
+  Constant value: int 0
+
+public static final int TOOL_TYPE_FINGER;
+  Signature: I
+  Constant value: int 1
+
+public static final int TOOL_TYPE_STYLUS;
+  Signature: I
+  Constant value: int 2
+
+public static final int TOOL_TYPE_MOUSE;
+  Signature: I
+  Constant value: int 3
+
+public static final int TOOL_TYPE_ERASER;
+  Signature: I
+  Constant value: int 4
+
+public static final android.os.Parcelable$Creator CREATOR;
+  Signature: Landroid/os/Parcelable$Creator;
+  Signature: length = 0x2
+   00 FFFFFF99
+
+
+android.view.MotionEvent();
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: aload_0
+   1: invokespecial #1; //Method android/view/InputEvent."<init>":()V
+   4: new #2; //class java/lang/RuntimeException
+   7: dup
+   8: ldc #3; //String Stub!
+   10:  invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   13:  athrow
+  LineNumberTable:
+   line 35: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      14      0    this       Landroid/view/MotionEvent;
+
+
+protected void finalize()   throws java.lang.Throwable;
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 36: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+  Exceptions:
+   throws java.lang.Throwable
+public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent$PointerProperties[], android.view.MotionEvent$PointerCoords[], int, int, float, float, int, int, int, int);
+  Signature: (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=16, Args_size=14
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 37: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    pointerCount       I
+   0      10      6    pointerProperties       [Landroid/view/MotionEvent$PointerProperties;
+   0      10      7    pointerCoords       [Landroid/view/MotionEvent$PointerCoords;
+   0      10      8    metaState       I
+   0      10      9    buttonState       I
+   0      10      10    xPrecision       F
+   0      10      11    yPrecision       F
+   0      10      12    deviceId       I
+   0      10      13    edgeFlags       I
+   0      10      14    source       I
+   0      10      15    flags       I
+
+
+public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent$PointerCoords[], int, float, float, int, int, int, int);
+  Signature: (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=15, Args_size=13
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 39: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    pointerCount       I
+   0      10      6    pointerIds       [I
+   0      10      7    pointerCoords       [Landroid/view/MotionEvent$PointerCoords;
+   0      10      8    metaState       I
+   0      10      9    xPrecision       F
+   0      10      10    yPrecision       F
+   0      10      11    deviceId       I
+   0      10      12    edgeFlags       I
+   0      10      13    source       I
+   0      10      14    flags       I
+
+  Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
+  Signature: (JJIFFFFIFFII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=14, Args_size=12
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 40: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    x       F
+   0      10      6    y       F
+   0      10      7    pressure       F
+   0      10      8    size       F
+   0      10      9    metaState       I
+   0      10      10    xPrecision       F
+   0      10      11    yPrecision       F
+   0      10      12    deviceId       I
+   0      10      13    edgeFlags       I
+
+
+public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
+  Signature: (JJIIFFFFIFFII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=15, Args_size=13
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 42: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    pointerCount       I
+   0      10      6    x       F
+   0      10      7    y       F
+   0      10      8    pressure       F
+   0      10      9    size       F
+   0      10      10    metaState       I
+   0      10      11    xPrecision       F
+   0      10      12    yPrecision       F
+   0      10      13    deviceId       I
+   0      10      14    edgeFlags       I
+
+  Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+public static android.view.MotionEvent obtain(long, long, int, float, float, int);
+  Signature: (JJIFFI)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=8, Args_size=6
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 43: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    x       F
+   0      10      6    y       F
+   0      10      7    metaState       I
+
+
+public static android.view.MotionEvent obtain(android.view.MotionEvent);
+  Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 44: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    other       Landroid/view/MotionEvent;
+
+
+public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
+  Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 45: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    other       Landroid/view/MotionEvent;
+
+
+public final void recycle();
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 46: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getDeviceId();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 47: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getSource();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 48: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final void setSource(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 49: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    source       I
+
+
+public final int getAction();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 50: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getActionMasked();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 51: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getActionIndex();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 52: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getFlags();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 53: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final long getDownTime();
+  Signature: ()J
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 54: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final long getEventTime();
+  Signature: ()J
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 55: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getX();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 56: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getY();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 57: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getPressure();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 58: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getSize();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 59: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getTouchMajor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 60: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getTouchMinor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 61: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getToolMajor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 62: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getToolMinor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 63: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getOrientation();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 64: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getAxisValue(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 65: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+
+
+public final int getPointerCount();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 66: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getPointerId(int);
+  Signature: (I)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 67: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final int getToolType(int);
+  Signature: (I)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 68: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final int findPointerIndex(int);
+  Signature: (I)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 69: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerId       I
+
+
+public final float getX(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 70: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getY(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 71: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getPressure(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 72: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getSize(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 73: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getTouchMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 74: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getTouchMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 75: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getToolMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 76: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getToolMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 77: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getOrientation(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 78: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getAxisValue(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 79: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+   0      10      2    pointerIndex       I
+
+
+public final void getPointerCoords(int, android.view.MotionEvent$PointerCoords);
+  Signature: (ILandroid/view/MotionEvent$PointerCoords;)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 80: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    outPointerCoords       Landroid/view/MotionEvent$PointerCoords;
+
+
+public final void getPointerProperties(int, android.view.MotionEvent$PointerProperties);
+  Signature: (ILandroid/view/MotionEvent$PointerProperties;)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 81: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    outPointerProperties       Landroid/view/MotionEvent$PointerProperties;
+
+
+public final int getMetaState();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 82: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getButtonState();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 83: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getRawX();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 84: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getRawY();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 85: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getXPrecision();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 86: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getYPrecision();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 87: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getHistorySize();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 88: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final long getHistoricalEventTime(int);
+  Signature: (I)J
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 89: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalX(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 90: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalY(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 91: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalPressure(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 92: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalSize(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 93: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalTouchMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 94: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalTouchMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 95: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalToolMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 96: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalToolMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 97: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalOrientation(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 98: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalAxisValue(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 99: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalX(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 100: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalY(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 101: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalPressure(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 102: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalSize(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 103: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalTouchMajor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 104: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalTouchMinor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 105: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalToolMajor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 106: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalToolMinor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 107: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalOrientation(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 108: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalAxisValue(int, int, int);
+  Signature: (III)F
+  Code:
+   Stack=3, Locals=4, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 109: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+   0      10      2    pointerIndex       I
+   0      10      3    pos       I
+
+
+public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent$PointerCoords);
+  Signature: (IILandroid/view/MotionEvent$PointerCoords;)V
+  Code:
+   Stack=3, Locals=4, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 110: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+   0      10      3    outPointerCoords       Landroid/view/MotionEvent$PointerCoords;
+
+
+public final int getEdgeFlags();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 111: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final void setEdgeFlags(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 112: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    flags       I
+
+
+public final void setAction(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 113: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    action       I
+
+
+public final void offsetLocation(float, float);
+  Signature: (FF)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 114: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    deltaX       F
+   0      10      2    deltaY       F
+
+
+public final void setLocation(float, float);
+  Signature: (FF)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 115: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    x       F
+   0      10      2    y       F
+
+
+public final void transform(android.graphics.Matrix);
+  Signature: (Landroid/graphics/Matrix;)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 116: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    matrix       Landroid/graphics/Matrix;
+
+
+public final void addBatch(long, float, float, float, float, int);
+  Signature: (JFFFFI)V
+  Code:
+   Stack=3, Locals=8, Args_size=7
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 117: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    eventTime       J
+   0      10      3    x       F
+   0      10      4    y       F
+   0      10      5    pressure       F
+   0      10      6    size       F
+   0      10      7    metaState       I
+
+
+public final void addBatch(long, android.view.MotionEvent$PointerCoords[], int);
+  Signature: (J[Landroid/view/MotionEvent$PointerCoords;I)V
+  Code:
+   Stack=3, Locals=5, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 118: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    eventTime       J
+   0      10      3    pointerCoords       [Landroid/view/MotionEvent$PointerCoords;
+   0      10      4    metaState       I
+
+
+public java.lang.String toString();
+  Signature: ()Ljava/lang/String;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 119: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public static java.lang.String actionToString(int);
+  Signature: (I)Ljava/lang/String;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 120: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    action       I
+
+
+public static java.lang.String axisToString(int);
+  Signature: (I)Ljava/lang/String;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 121: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    axis       I
+
+
+public static int axisFromString(java.lang.String);
+  Signature: (Ljava/lang/String;)I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 122: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    symbolicName       Ljava/lang/String;
+
+
+public void writeToParcel(android.os.Parcel, int);
+  Signature: (Landroid/os/Parcel;I)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 123: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    out       Landroid/os/Parcel;
+   0      10      2    flags       I
+
+
+static {};
+  Signature: ()V
+  Code:
+   Stack=1, Locals=0, Args_size=0
+   0: aconst_null
+   1: putstatic #5; //Field CREATOR:Landroid/os/Parcelable$Creator;
+   4: return
+  LineNumberTable:
+   line 213: 0
+
+
+}
+
diff --git a/base/android/jni_generator/testMotionEvent.javap7 b/base/android/jni_generator/testMotionEvent.javap7
new file mode 100644
index 0000000..f4f5444
--- /dev/null
+++ b/base/android/jni_generator/testMotionEvent.javap7
@@ -0,0 +1,2370 @@
+Classfile out_android/Debug/gen/content/jni/android/view/MotionEvent.class
+  Last modified Feb 27, 2014; size 13369 bytes
+  MD5 checksum 3718d77a994cb8aceb7b35c5df3c4dd1
+  Compiled from "MotionEvent.java"
+public final class android.view.MotionEvent extends android.view.InputEvent implements android.os.Parcelable
+  SourceFile: "MotionEvent.java"
+  InnerClasses:
+       public static final #10= #9 of #6; //PointerProperties=class android/view/MotionEvent$PointerProperties of class android/view/MotionEvent
+       public static final #13= #12 of #6; //PointerCoords=class android/view/MotionEvent$PointerCoords of class android/view/MotionEvent
+       public static #150= #149 of #8; //Creator=class android/os/Parcelable$Creator of class android/os/Parcelable
+  minor version: 0
+  major version: 49
+  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
+Constant pool:
+    #1 = Methodref          #7.#293       //  android/view/InputEvent."<init>":()V
+    #2 = Class              #294          //  java/lang/RuntimeException
+    #3 = String             #295          //  Stub!
+    #4 = Methodref          #2.#296       //  java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+    #5 = Fieldref           #6.#297       //  android/view/MotionEvent.CREATOR:Landroid/os/Parcelable$Creator;
+    #6 = Class              #298          //  android/view/MotionEvent
+    #7 = Class              #299          //  android/view/InputEvent
+    #8 = Class              #300          //  android/os/Parcelable
+    #9 = Class              #301          //  android/view/MotionEvent$PointerProperties
+   #10 = Utf8               PointerProperties
+   #11 = Utf8               InnerClasses
+   #12 = Class              #302          //  android/view/MotionEvent$PointerCoords
+   #13 = Utf8               PointerCoords
+   #14 = Utf8               INVALID_POINTER_ID
+   #15 = Utf8               I
+   #16 = Utf8               ConstantValue
+   #17 = Integer            -1
+   #18 = Utf8               ACTION_MASK
+   #19 = Integer            255
+   #20 = Utf8               ACTION_DOWN
+   #21 = Integer            0
+   #22 = Utf8               ACTION_UP
+   #23 = Integer            1
+   #24 = Utf8               ACTION_MOVE
+   #25 = Integer            2
+   #26 = Utf8               ACTION_CANCEL
+   #27 = Integer            3
+   #28 = Utf8               ACTION_OUTSIDE
+   #29 = Integer            4
+   #30 = Utf8               ACTION_POINTER_DOWN
+   #31 = Integer            5
+   #32 = Utf8               ACTION_POINTER_UP
+   #33 = Integer            6
+   #34 = Utf8               ACTION_HOVER_MOVE
+   #35 = Integer            7
+   #36 = Utf8               ACTION_SCROLL
+   #37 = Integer            8
+   #38 = Utf8               ACTION_HOVER_ENTER
+   #39 = Integer            9
+   #40 = Utf8               ACTION_HOVER_EXIT
+   #41 = Integer            10
+   #42 = Utf8               ACTION_POINTER_INDEX_MASK
+   #43 = Integer            65280
+   #44 = Utf8               ACTION_POINTER_INDEX_SHIFT
+   #45 = Utf8               ACTION_POINTER_1_DOWN
+   #46 = Utf8               Deprecated
+   #47 = Utf8               RuntimeVisibleAnnotations
+   #48 = Utf8               Ljava/lang/Deprecated;
+   #49 = Utf8               ACTION_POINTER_2_DOWN
+   #50 = Integer            261
+   #51 = Utf8               ACTION_POINTER_3_DOWN
+   #52 = Integer            517
+   #53 = Utf8               ACTION_POINTER_1_UP
+   #54 = Utf8               ACTION_POINTER_2_UP
+   #55 = Integer            262
+   #56 = Utf8               ACTION_POINTER_3_UP
+   #57 = Integer            518
+   #58 = Utf8               ACTION_POINTER_ID_MASK
+   #59 = Utf8               ACTION_POINTER_ID_SHIFT
+   #60 = Utf8               FLAG_WINDOW_IS_OBSCURED
+   #61 = Utf8               EDGE_TOP
+   #62 = Utf8               EDGE_BOTTOM
+   #63 = Utf8               EDGE_LEFT
+   #64 = Utf8               EDGE_RIGHT
+   #65 = Utf8               AXIS_X
+   #66 = Utf8               AXIS_Y
+   #67 = Utf8               AXIS_PRESSURE
+   #68 = Utf8               AXIS_SIZE
+   #69 = Utf8               AXIS_TOUCH_MAJOR
+   #70 = Utf8               AXIS_TOUCH_MINOR
+   #71 = Utf8               AXIS_TOOL_MAJOR
+   #72 = Utf8               AXIS_TOOL_MINOR
+   #73 = Utf8               AXIS_ORIENTATION
+   #74 = Utf8               AXIS_VSCROLL
+   #75 = Utf8               AXIS_HSCROLL
+   #76 = Utf8               AXIS_Z
+   #77 = Integer            11
+   #78 = Utf8               AXIS_RX
+   #79 = Integer            12
+   #80 = Utf8               AXIS_RY
+   #81 = Integer            13
+   #82 = Utf8               AXIS_RZ
+   #83 = Integer            14
+   #84 = Utf8               AXIS_HAT_X
+   #85 = Integer            15
+   #86 = Utf8               AXIS_HAT_Y
+   #87 = Integer            16
+   #88 = Utf8               AXIS_LTRIGGER
+   #89 = Integer            17
+   #90 = Utf8               AXIS_RTRIGGER
+   #91 = Integer            18
+   #92 = Utf8               AXIS_THROTTLE
+   #93 = Integer            19
+   #94 = Utf8               AXIS_RUDDER
+   #95 = Integer            20
+   #96 = Utf8               AXIS_WHEEL
+   #97 = Integer            21
+   #98 = Utf8               AXIS_GAS
+   #99 = Integer            22
+  #100 = Utf8               AXIS_BRAKE
+  #101 = Integer            23
+  #102 = Utf8               AXIS_DISTANCE
+  #103 = Integer            24
+  #104 = Utf8               AXIS_TILT
+  #105 = Integer            25
+  #106 = Utf8               AXIS_GENERIC_1
+  #107 = Integer            32
+  #108 = Utf8               AXIS_GENERIC_2
+  #109 = Integer            33
+  #110 = Utf8               AXIS_GENERIC_3
+  #111 = Integer            34
+  #112 = Utf8               AXIS_GENERIC_4
+  #113 = Integer            35
+  #114 = Utf8               AXIS_GENERIC_5
+  #115 = Integer            36
+  #116 = Utf8               AXIS_GENERIC_6
+  #117 = Integer            37
+  #118 = Utf8               AXIS_GENERIC_7
+  #119 = Integer            38
+  #120 = Utf8               AXIS_GENERIC_8
+  #121 = Integer            39
+  #122 = Utf8               AXIS_GENERIC_9
+  #123 = Integer            40
+  #124 = Utf8               AXIS_GENERIC_10
+  #125 = Integer            41
+  #126 = Utf8               AXIS_GENERIC_11
+  #127 = Integer            42
+  #128 = Utf8               AXIS_GENERIC_12
+  #129 = Integer            43
+  #130 = Utf8               AXIS_GENERIC_13
+  #131 = Integer            44
+  #132 = Utf8               AXIS_GENERIC_14
+  #133 = Integer            45
+  #134 = Utf8               AXIS_GENERIC_15
+  #135 = Integer            46
+  #136 = Utf8               AXIS_GENERIC_16
+  #137 = Integer            47
+  #138 = Utf8               BUTTON_PRIMARY
+  #139 = Utf8               BUTTON_SECONDARY
+  #140 = Utf8               BUTTON_TERTIARY
+  #141 = Utf8               BUTTON_BACK
+  #142 = Utf8               BUTTON_FORWARD
+  #143 = Utf8               TOOL_TYPE_UNKNOWN
+  #144 = Utf8               TOOL_TYPE_FINGER
+  #145 = Utf8               TOOL_TYPE_STYLUS
+  #146 = Utf8               TOOL_TYPE_MOUSE
+  #147 = Utf8               TOOL_TYPE_ERASER
+  #148 = Utf8               CREATOR
+  #149 = Class              #303          //  android/os/Parcelable$Creator
+  #150 = Utf8               Creator
+  #151 = Utf8               Landroid/os/Parcelable$Creator;
+  #152 = Utf8               Signature
+  #153 = Utf8               Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;
+  #154 = Utf8               <init>
+  #155 = Utf8               ()V
+  #156 = Utf8               Code
+  #157 = Utf8               LineNumberTable
+  #158 = Utf8               LocalVariableTable
+  #159 = Utf8               this
+  #160 = Utf8               Landroid/view/MotionEvent;
+  #161 = Utf8               finalize
+  #162 = Utf8               Exceptions
+  #163 = Class              #304          //  java/lang/Throwable
+  #164 = Utf8               obtain
+  #165 = Utf8               (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
+  #166 = Utf8               downTime
+  #167 = Utf8               J
+  #168 = Utf8               eventTime
+  #169 = Utf8               action
+  #170 = Utf8               pointerCount
+  #171 = Utf8               pointerProperties
+  #172 = Utf8               [Landroid/view/MotionEvent$PointerProperties;
+  #173 = Utf8               pointerCoords
+  #174 = Utf8               [Landroid/view/MotionEvent$PointerCoords;
+  #175 = Utf8               metaState
+  #176 = Utf8               buttonState
+  #177 = Utf8               xPrecision
+  #178 = Utf8               F
+  #179 = Utf8               yPrecision
+  #180 = Utf8               deviceId
+  #181 = Utf8               edgeFlags
+  #182 = Utf8               source
+  #183 = Utf8               flags
+  #184 = Utf8               (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
+  #185 = Utf8               pointerIds
+  #186 = Utf8               [I
+  #187 = Utf8               (JJIFFFFIFFII)Landroid/view/MotionEvent;
+  #188 = Utf8               x
+  #189 = Utf8               y
+  #190 = Utf8               pressure
+  #191 = Utf8               size
+  #192 = Utf8               (JJIIFFFFIFFII)Landroid/view/MotionEvent;
+  #193 = Utf8               (JJIFFI)Landroid/view/MotionEvent;
+  #194 = Utf8               (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+  #195 = Utf8               other
+  #196 = Utf8               obtainNoHistory
+  #197 = Utf8               recycle
+  #198 = Utf8               getDeviceId
+  #199 = Utf8               ()I
+  #200 = Utf8               getSource
+  #201 = Utf8               setSource
+  #202 = Utf8               (I)V
+  #203 = Utf8               getAction
+  #204 = Utf8               getActionMasked
+  #205 = Utf8               getActionIndex
+  #206 = Utf8               getFlags
+  #207 = Utf8               getDownTime
+  #208 = Utf8               ()J
+  #209 = Utf8               getEventTime
+  #210 = Utf8               getX
+  #211 = Utf8               ()F
+  #212 = Utf8               getY
+  #213 = Utf8               getPressure
+  #214 = Utf8               getSize
+  #215 = Utf8               getTouchMajor
+  #216 = Utf8               getTouchMinor
+  #217 = Utf8               getToolMajor
+  #218 = Utf8               getToolMinor
+  #219 = Utf8               getOrientation
+  #220 = Utf8               getAxisValue
+  #221 = Utf8               (I)F
+  #222 = Utf8               axis
+  #223 = Utf8               getPointerCount
+  #224 = Utf8               getPointerId
+  #225 = Utf8               (I)I
+  #226 = Utf8               pointerIndex
+  #227 = Utf8               getToolType
+  #228 = Utf8               findPointerIndex
+  #229 = Utf8               pointerId
+  #230 = Utf8               (II)F
+  #231 = Utf8               getPointerCoords
+  #232 = Utf8               (ILandroid/view/MotionEvent$PointerCoords;)V
+  #233 = Utf8               outPointerCoords
+  #234 = Utf8               Landroid/view/MotionEvent$PointerCoords;
+  #235 = Utf8               getPointerProperties
+  #236 = Utf8               (ILandroid/view/MotionEvent$PointerProperties;)V
+  #237 = Utf8               outPointerProperties
+  #238 = Utf8               Landroid/view/MotionEvent$PointerProperties;
+  #239 = Utf8               getMetaState
+  #240 = Utf8               getButtonState
+  #241 = Utf8               getRawX
+  #242 = Utf8               getRawY
+  #243 = Utf8               getXPrecision
+  #244 = Utf8               getYPrecision
+  #245 = Utf8               getHistorySize
+  #246 = Utf8               getHistoricalEventTime
+  #247 = Utf8               (I)J
+  #248 = Utf8               pos
+  #249 = Utf8               getHistoricalX
+  #250 = Utf8               getHistoricalY
+  #251 = Utf8               getHistoricalPressure
+  #252 = Utf8               getHistoricalSize
+  #253 = Utf8               getHistoricalTouchMajor
+  #254 = Utf8               getHistoricalTouchMinor
+  #255 = Utf8               getHistoricalToolMajor
+  #256 = Utf8               getHistoricalToolMinor
+  #257 = Utf8               getHistoricalOrientation
+  #258 = Utf8               getHistoricalAxisValue
+  #259 = Utf8               (III)F
+  #260 = Utf8               getHistoricalPointerCoords
+  #261 = Utf8               (IILandroid/view/MotionEvent$PointerCoords;)V
+  #262 = Utf8               getEdgeFlags
+  #263 = Utf8               setEdgeFlags
+  #264 = Utf8               setAction
+  #265 = Utf8               offsetLocation
+  #266 = Utf8               (FF)V
+  #267 = Utf8               deltaX
+  #268 = Utf8               deltaY
+  #269 = Utf8               setLocation
+  #270 = Utf8               transform
+  #271 = Utf8               (Landroid/graphics/Matrix;)V
+  #272 = Utf8               matrix
+  #273 = Utf8               Landroid/graphics/Matrix;
+  #274 = Utf8               addBatch
+  #275 = Utf8               (JFFFFI)V
+  #276 = Utf8               (J[Landroid/view/MotionEvent$PointerCoords;I)V
+  #277 = Utf8               toString
+  #278 = Utf8               ()Ljava/lang/String;
+  #279 = Utf8               actionToString
+  #280 = Utf8               (I)Ljava/lang/String;
+  #281 = Utf8               axisToString
+  #282 = Utf8               axisFromString
+  #283 = Utf8               (Ljava/lang/String;)I
+  #284 = Utf8               symbolicName
+  #285 = Utf8               Ljava/lang/String;
+  #286 = Utf8               writeToParcel
+  #287 = Utf8               (Landroid/os/Parcel;I)V
+  #288 = Utf8               out
+  #289 = Utf8               Landroid/os/Parcel;
+  #290 = Utf8               <clinit>
+  #291 = Utf8               SourceFile
+  #292 = Utf8               MotionEvent.java
+  #293 = NameAndType        #154:#155     //  "<init>":()V
+  #294 = Utf8               java/lang/RuntimeException
+  #295 = Utf8               Stub!
+  #296 = NameAndType        #154:#305     //  "<init>":(Ljava/lang/String;)V
+  #297 = NameAndType        #148:#151     //  CREATOR:Landroid/os/Parcelable$Creator;
+  #298 = Utf8               android/view/MotionEvent
+  #299 = Utf8               android/view/InputEvent
+  #300 = Utf8               android/os/Parcelable
+  #301 = Utf8               android/view/MotionEvent$PointerProperties
+  #302 = Utf8               android/view/MotionEvent$PointerCoords
+  #303 = Utf8               android/os/Parcelable$Creator
+  #304 = Utf8               java/lang/Throwable
+  #305 = Utf8               (Ljava/lang/String;)V
+{
+  public static final int INVALID_POINTER_ID;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int -1
+
+
+  public static final int ACTION_MASK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 255
+
+
+  public static final int ACTION_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 0
+
+
+  public static final int ACTION_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int ACTION_MOVE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int ACTION_CANCEL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 3
+
+
+  public static final int ACTION_OUTSIDE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int ACTION_POINTER_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 5
+
+
+  public static final int ACTION_POINTER_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 6
+
+
+  public static final int ACTION_HOVER_MOVE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 7
+
+
+  public static final int ACTION_SCROLL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int ACTION_HOVER_ENTER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 9
+
+
+  public static final int ACTION_HOVER_EXIT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 10
+
+
+  public static final int ACTION_POINTER_INDEX_MASK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 65280
+
+
+  public static final int ACTION_POINTER_INDEX_SHIFT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int ACTION_POINTER_1_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 5
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_2_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 261
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_3_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 517
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_1_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 6
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_2_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 262
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_3_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 518
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_ID_MASK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 65280
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_ID_SHIFT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int FLAG_WINDOW_IS_OBSCURED;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int EDGE_TOP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int EDGE_BOTTOM;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int EDGE_LEFT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int EDGE_RIGHT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int AXIS_X;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 0
+
+
+  public static final int AXIS_Y;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int AXIS_PRESSURE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int AXIS_SIZE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 3
+
+
+  public static final int AXIS_TOUCH_MAJOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int AXIS_TOUCH_MINOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 5
+
+
+  public static final int AXIS_TOOL_MAJOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 6
+
+
+  public static final int AXIS_TOOL_MINOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 7
+
+
+  public static final int AXIS_ORIENTATION;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int AXIS_VSCROLL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 9
+
+
+  public static final int AXIS_HSCROLL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 10
+
+
+  public static final int AXIS_Z;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 11
+
+
+  public static final int AXIS_RX;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 12
+
+
+  public static final int AXIS_RY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 13
+
+
+  public static final int AXIS_RZ;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 14
+
+
+  public static final int AXIS_HAT_X;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 15
+
+
+  public static final int AXIS_HAT_Y;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 16
+
+
+  public static final int AXIS_LTRIGGER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 17
+
+
+  public static final int AXIS_RTRIGGER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 18
+
+
+  public static final int AXIS_THROTTLE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 19
+
+
+  public static final int AXIS_RUDDER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 20
+
+
+  public static final int AXIS_WHEEL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 21
+
+
+  public static final int AXIS_GAS;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 22
+
+
+  public static final int AXIS_BRAKE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 23
+
+
+  public static final int AXIS_DISTANCE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 24
+
+
+  public static final int AXIS_TILT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 25
+
+
+  public static final int AXIS_GENERIC_1;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 32
+
+
+  public static final int AXIS_GENERIC_2;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 33
+
+
+  public static final int AXIS_GENERIC_3;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 34
+
+
+  public static final int AXIS_GENERIC_4;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 35
+
+
+  public static final int AXIS_GENERIC_5;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 36
+
+
+  public static final int AXIS_GENERIC_6;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 37
+
+
+  public static final int AXIS_GENERIC_7;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 38
+
+
+  public static final int AXIS_GENERIC_8;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 39
+
+
+  public static final int AXIS_GENERIC_9;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 40
+
+
+  public static final int AXIS_GENERIC_10;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 41
+
+
+  public static final int AXIS_GENERIC_11;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 42
+
+
+  public static final int AXIS_GENERIC_12;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 43
+
+
+  public static final int AXIS_GENERIC_13;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 44
+
+
+  public static final int AXIS_GENERIC_14;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 45
+
+
+  public static final int AXIS_GENERIC_15;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 46
+
+
+  public static final int AXIS_GENERIC_16;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 47
+
+
+  public static final int BUTTON_PRIMARY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int BUTTON_SECONDARY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int BUTTON_TERTIARY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int BUTTON_BACK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int BUTTON_FORWARD;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 16
+
+
+  public static final int TOOL_TYPE_UNKNOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 0
+
+
+  public static final int TOOL_TYPE_FINGER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int TOOL_TYPE_STYLUS;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int TOOL_TYPE_MOUSE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 3
+
+
+  public static final int TOOL_TYPE_ERASER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final android.os.Parcelable$Creator<android.view.MotionEvent> CREATOR;
+    Signature: Landroid/os/Parcelable$Creator;
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #153                         // Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;
+
+
+  android.view.MotionEvent();
+    Signature: ()V
+    flags:
+    Code:
+      stack=3, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #1                  // Method android/view/InputEvent."<init>":()V
+         4: new           #2                  // class java/lang/RuntimeException
+         7: dup
+         8: ldc           #3                  // String Stub!
+        10: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        13: athrow
+      LineNumberTable:
+        line 35: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      14     0  this   Landroid/view/MotionEvent;
+
+  protected void finalize() throws java.lang.Throwable;
+    Signature: ()V
+    flags: ACC_PROTECTED
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 36: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+    Exceptions:
+      throws java.lang.Throwable
+
+  public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent$PointerProperties[], android.view.MotionEvent$PointerCoords[], int, int, float, float, int, int, int, int);
+    Signature: (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=16, args_size=14
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 37: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5 pointerCount   I
+               0      10     6 pointerProperties   [Landroid/view/MotionEvent$PointerProperties;
+               0      10     7 pointerCoords   [Landroid/view/MotionEvent$PointerCoords;
+               0      10     8 metaState   I
+               0      10     9 buttonState   I
+               0      10    10 xPrecision   F
+               0      10    11 yPrecision   F
+               0      10    12 deviceId   I
+               0      10    13 edgeFlags   I
+               0      10    14 source   I
+               0      10    15 flags   I
+
+  public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent$PointerCoords[], int, float, float, int, int, int, int);
+    Signature: (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=15, args_size=13
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 39: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5 pointerCount   I
+               0      10     6 pointerIds   [I
+               0      10     7 pointerCoords   [Landroid/view/MotionEvent$PointerCoords;
+               0      10     8 metaState   I
+               0      10     9 xPrecision   F
+               0      10    10 yPrecision   F
+               0      10    11 deviceId   I
+               0      10    12 edgeFlags   I
+               0      10    13 source   I
+               0      10    14 flags   I
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+  public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
+    Signature: (JJIFFFFIFFII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=14, args_size=12
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 40: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5     x   F
+               0      10     6     y   F
+               0      10     7 pressure   F
+               0      10     8  size   F
+               0      10     9 metaState   I
+               0      10    10 xPrecision   F
+               0      10    11 yPrecision   F
+               0      10    12 deviceId   I
+               0      10    13 edgeFlags   I
+
+  public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
+    Signature: (JJIIFFFFIFFII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=15, args_size=13
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 42: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5 pointerCount   I
+               0      10     6     x   F
+               0      10     7     y   F
+               0      10     8 pressure   F
+               0      10     9  size   F
+               0      10    10 metaState   I
+               0      10    11 xPrecision   F
+               0      10    12 yPrecision   F
+               0      10    13 deviceId   I
+               0      10    14 edgeFlags   I
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+  public static android.view.MotionEvent obtain(long, long, int, float, float, int);
+    Signature: (JJIFFI)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=8, args_size=6
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 43: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5     x   F
+               0      10     6     y   F
+               0      10     7 metaState   I
+
+  public static android.view.MotionEvent obtain(android.view.MotionEvent);
+    Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 44: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 other   Landroid/view/MotionEvent;
+
+  public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
+    Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 45: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 other   Landroid/view/MotionEvent;
+
+  public final void recycle();
+    Signature: ()V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 46: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getDeviceId();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 47: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getSource();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 48: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final void setSource(int);
+    Signature: (I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 49: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 source   I
+
+  public final int getAction();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 50: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getActionMasked();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 51: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getActionIndex();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 52: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getFlags();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 53: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final long getDownTime();
+    Signature: ()J
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 54: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final long getEventTime();
+    Signature: ()J
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 55: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getX();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 56: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getY();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 57: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getPressure();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 58: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getSize();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 59: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getTouchMajor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 60: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getTouchMinor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 61: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getToolMajor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 62: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getToolMinor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 63: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getOrientation();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 64: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getAxisValue(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 65: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+
+  public final int getPointerCount();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 66: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getPointerId(int);
+    Signature: (I)I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 67: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final int getToolType(int);
+    Signature: (I)I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 68: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final int findPointerIndex(int);
+    Signature: (I)I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 69: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerId   I
+
+  public final float getX(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 70: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getY(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 71: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getPressure(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 72: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getSize(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 73: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getTouchMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 74: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getTouchMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 75: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getToolMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 76: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getToolMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 77: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getOrientation(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 78: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getAxisValue(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 79: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+               0      10     2 pointerIndex   I
+
+  public final void getPointerCoords(int, android.view.MotionEvent$PointerCoords);
+    Signature: (ILandroid/view/MotionEvent$PointerCoords;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 80: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2 outPointerCoords   Landroid/view/MotionEvent$PointerCoords;
+
+  public final void getPointerProperties(int, android.view.MotionEvent$PointerProperties);
+    Signature: (ILandroid/view/MotionEvent$PointerProperties;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 81: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2 outPointerProperties   Landroid/view/MotionEvent$PointerProperties;
+
+  public final int getMetaState();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 82: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getButtonState();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 83: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getRawX();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 84: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getRawY();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 85: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getXPrecision();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 86: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getYPrecision();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 87: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getHistorySize();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 88: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final long getHistoricalEventTime(int);
+    Signature: (I)J
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 89: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalX(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 90: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalY(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 91: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalPressure(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 92: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalSize(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 93: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalTouchMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 94: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalTouchMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 95: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalToolMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 96: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalToolMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 97: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalOrientation(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 98: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalAxisValue(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 99: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+               0      10     2   pos   I
+
+  public final float getHistoricalX(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 100: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalY(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 101: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalPressure(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 102: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalSize(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 103: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalTouchMajor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 104: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalTouchMinor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 105: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalToolMajor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 106: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalToolMinor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 107: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalOrientation(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 108: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalAxisValue(int, int, int);
+    Signature: (III)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=4, args_size=4
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 109: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+               0      10     2 pointerIndex   I
+               0      10     3   pos   I
+
+  public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent$PointerCoords);
+    Signature: (IILandroid/view/MotionEvent$PointerCoords;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=4, args_size=4
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 110: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+               0      10     3 outPointerCoords   Landroid/view/MotionEvent$PointerCoords;
+
+  public final int getEdgeFlags();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 111: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final void setEdgeFlags(int);
+    Signature: (I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 112: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 flags   I
+
+  public final void setAction(int);
+    Signature: (I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 113: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 action   I
+
+  public final void offsetLocation(float, float);
+    Signature: (FF)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 114: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 deltaX   F
+               0      10     2 deltaY   F
+
+  public final void setLocation(float, float);
+    Signature: (FF)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 115: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1     x   F
+               0      10     2     y   F
+
+  public final void transform(android.graphics.Matrix);
+    Signature: (Landroid/graphics/Matrix;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 116: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 matrix   Landroid/graphics/Matrix;
+
+  public final void addBatch(long, float, float, float, float, int);
+    Signature: (JFFFFI)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=8, args_size=7
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 117: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 eventTime   J
+               0      10     3     x   F
+               0      10     4     y   F
+               0      10     5 pressure   F
+               0      10     6  size   F
+               0      10     7 metaState   I
+
+  public final void addBatch(long, android.view.MotionEvent$PointerCoords[], int);
+    Signature: (J[Landroid/view/MotionEvent$PointerCoords;I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=5, args_size=4
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 118: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 eventTime   J
+               0      10     3 pointerCoords   [Landroid/view/MotionEvent$PointerCoords;
+               0      10     4 metaState   I
+
+  public java.lang.String toString();
+    Signature: ()Ljava/lang/String;
+    flags: ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 119: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public static java.lang.String actionToString(int);
+    Signature: (I)Ljava/lang/String;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 120: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 action   I
+
+  public static java.lang.String axisToString(int);
+    Signature: (I)Ljava/lang/String;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 121: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  axis   I
+
+  public static int axisFromString(java.lang.String);
+    Signature: (Ljava/lang/String;)I
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 122: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 symbolicName   Ljava/lang/String;
+
+  public void writeToParcel(android.os.Parcel, int);
+    Signature: (Landroid/os/Parcel;I)V
+    flags: ACC_PUBLIC
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 123: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   out   Landroid/os/Parcel;
+               0      10     2 flags   I
+
+  static {};
+    Signature: ()V
+    flags: ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: aconst_null
+         1: putstatic     #5                  // Field CREATOR:Landroid/os/Parcelable$Creator;
+         4: return
+      LineNumberTable:
+        line 213: 0
+}
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
new file mode 100644
index 0000000..b0db9dd
--- /dev/null
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/foo/Foo
+
+#ifndef org_chromium_foo_Foo_JNI
+#define org_chromium_foo_Foo_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kFooClassPath[] = "org/chromium/foo/Foo";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Foo_clazz = NULL;
+#define Foo_clazz(env) g_Foo_clazz
+
+}  // namespace
+
+static void DoSomething(JNIEnv* env, jclass jcaller,
+    jobject callback1,
+    jobject callback2);
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_Foo_calledByNative = 0;
+static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
+    jobject callback2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, Foo_clazz(env),
+      Foo_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, Foo_clazz(env),
+      "calledByNative",
+
+"("
+"Lorg/chromium/foo/Bar1$Callback;"
+"Lorg/chromium/foo/Bar2$Callback;"
+")"
+"V",
+      &g_Foo_calledByNative);
+
+     env->CallStaticVoidMethod(Foo_clazz(env),
+          method_id, callback1, callback2);
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsFoo[] = {
+    { "nativeDoSomething",
+"("
+"Lorg/chromium/foo/Bar1$Callback;"
+"Lorg/chromium/foo/Bar2$Callback;"
+")"
+"V", reinterpret_cast<void*>(DoSomething) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kFooClassPath).obj()));
+
+  const int kMethodsFooSize = arraysize(kMethodsFoo);
+
+  if (env->RegisterNatives(Foo_clazz(env),
+                           kMethodsFoo,
+                           kMethodsFooSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Foo_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden
new file mode 100644
index 0000000..395fc39
--- /dev/null
+++ b/base/android/jni_generator/testNativeExportsOption.golden
@@ -0,0 +1,219 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kSampleForTestsClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
+#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
+
+}  // namespace
+
+extern "C" {
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
+
+};  // extern "C"
+
+// Step 2: method stubs.
+
+extern "C" {
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
+    env,
+    jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
+  return native->StaticMethod(env, jcaller, arg1);
+}
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
+    env,
+    jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller, arg1);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
+static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithParam",
+
+"("
+"I"
+")"
+"V",
+      &g_SampleForTests_testMethodWithParam);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(iParam));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
+    0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithParamAndReturn",
+
+"("
+"I"
+")"
+"Ljava/lang/String;",
+      &g_SampleForTests_testMethodWithParamAndReturn);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id, as_jint(iParam)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
+static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testStaticMethodWithParam",
+
+"("
+"I"
+")"
+"I",
+      &g_SampleForTests_testStaticMethodWithParam);
+
+  jint ret =
+      env->CallStaticIntMethod(SampleForTests_clazz(env),
+          method_id, as_jint(iParam));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
+static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithNoParam",
+
+"("
+")"
+"D",
+      &g_SampleForTests_testMethodWithNoParam);
+
+  jdouble ret =
+      env->CallStaticDoubleMethod(SampleForTests_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
+    0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testStaticMethodWithNoParam",
+
+"("
+")"
+"Ljava/lang/String;",
+      &g_SampleForTests_testStaticMethodWithNoParam);
+
+  jstring ret =
+static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+};  // extern "C"
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
+  base::subtle::Release_Store(&g_SampleForTests_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
+    env, jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
new file mode 100644
index 0000000..f47cb98
--- /dev/null
+++ b/base/android/jni_generator/testNativeExportsOptionalOption.golden
@@ -0,0 +1,288 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kSampleForTestsClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
+#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
+
+}  // namespace
+
+extern "C" {
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
+
+};  // extern "C"
+
+// Step 2: method stubs.
+
+extern "C" {
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
+    env,
+    jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
+  return native->StaticMethod(env, jcaller, arg1);
+}
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
+    env,
+    jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller, arg1);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
+static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithParam",
+
+"("
+"I"
+")"
+"V",
+      &g_SampleForTests_testMethodWithParam);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(iParam));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
+    0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithParamAndReturn",
+
+"("
+"I"
+")"
+"Ljava/lang/String;",
+      &g_SampleForTests_testMethodWithParamAndReturn);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id, as_jint(iParam)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
+static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
+    JniIntWrapper iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testStaticMethodWithParam",
+
+"("
+"I"
+")"
+"I",
+      &g_SampleForTests_testStaticMethodWithParam);
+
+  jint ret =
+      env->CallStaticIntMethod(SampleForTests_clazz(env),
+          method_id, as_jint(iParam));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
+static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testMethodWithNoParam",
+
+"("
+")"
+"D",
+      &g_SampleForTests_testMethodWithNoParam);
+
+  jdouble ret =
+      env->CallStaticDoubleMethod(SampleForTests_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
+    0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "testStaticMethodWithNoParam",
+
+"("
+")"
+"Ljava/lang/String;",
+      &g_SampleForTests_testStaticMethodWithNoParam);
+
+  jstring ret =
+static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+};  // extern "C"
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit)
+    },
+};
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit)
+    },
+};
+
+static const JNINativeMethod kMethodsSampleForTests[] = {
+    { "nativeStaticMethod",
+"("
+"J"
+"I"
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod)
+    },
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I",
+    reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
+    },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+  if (base::android::IsManualJniRegistrationDisabled()) return true;
+
+  base::subtle::Release_Store(&g_SampleForTests_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
+
+  const int kMethodsMyOtherInnerClassSize =
+      arraysize(kMethodsMyOtherInnerClass);
+
+  if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
+                           kMethodsMyOtherInnerClass,
+                           kMethodsMyOtherInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyOtherInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
+
+  if (env->RegisterNatives(SampleForTests_clazz(env),
+                           kMethodsSampleForTests,
+                           kMethodsSampleForTestsSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, SampleForTests_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
+    env, jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
new file mode 100644
index 0000000..e5a4fab
--- /dev/null
+++ b/base/android/jni_generator/testNatives.golden
@@ -0,0 +1,218 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+static jstring GetDomainAndRegistry(JNIEnv* env, jclass jcaller,
+    jstring url);
+
+static void CreateHistoricalTabFromState(JNIEnv* env, jclass jcaller,
+    jbyteArray state,
+    jint tab_index);
+
+static jbyteArray GetStateAsByteArray(JNIEnv* env, jobject jcaller,
+    jobject view);
+
+static jobjectArray GetAutofillProfileGUIDs(JNIEnv* env, jclass jcaller);
+
+static void SetRecognitionResults(JNIEnv* env, jobject jcaller,
+    jint sessionId,
+    jobjectArray results);
+
+static jint FindAll(JNIEnv* env, jobject jcaller,
+    jstring find);
+
+static jobject GetInnerClass(JNIEnv* env, jclass jcaller);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
+  return native->Destroy(env, jcaller);
+}
+
+static jlong AddBookmark(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider,
+    jstring url,
+    jstring title,
+    jboolean isFolder,
+    jlong parentId) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmark", 0);
+  return native->AddBookmark(env, jcaller, url, title, isFolder, parentId);
+}
+
+static jlong AddBookmarkFromAPI(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider,
+    jstring url,
+    jobject created,
+    jobject isBookmark,
+    jobject date,
+    jbyteArray favicon,
+    jstring title,
+    jobject visits) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmarkFromAPI", 0);
+  return native->AddBookmarkFromAPI(env, jcaller, url, created, isBookmark,
+      date, favicon, title, visits);
+}
+
+static jobject QueryBitmap(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider,
+    jobjectArray projection,
+    jstring selection,
+    jobjectArray selectionArgs,
+    jstring sortOrder) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "QueryBitmap", NULL);
+  return native->QueryBitmap(env, jcaller, projection, selection, selectionArgs,
+      sortOrder).Release();
+}
+
+static void GotOrientation(JNIEnv* env, jobject jcaller,
+    jint nativeDataFetcherImplAndroid,
+    jdouble alpha,
+    jdouble beta,
+    jdouble gamma) {
+  DataFetcherImplAndroid* native =
+      reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
+  CHECK_NATIVE_PTR(env, jcaller, native, "GotOrientation");
+  return native->GotOrientation(env, jcaller, alpha, beta, gamma);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+    { "nativeDestroy",
+"("
+"I"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+    { "nativeAddBookmark",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Z"
+"J"
+")"
+"J", reinterpret_cast<void*>(AddBookmark) },
+    { "nativeGetDomainAndRegistry",
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(GetDomainAndRegistry) },
+    { "nativeCreateHistoricalTabFromState",
+"("
+"[B"
+"I"
+")"
+"V", reinterpret_cast<void*>(CreateHistoricalTabFromState) },
+    { "nativeGetStateAsByteArray",
+"("
+"Landroid/view/View;"
+")"
+"[B", reinterpret_cast<void*>(GetStateAsByteArray) },
+    { "nativeGetAutofillProfileGUIDs",
+"("
+")"
+"[Ljava/lang/String;", reinterpret_cast<void*>(GetAutofillProfileGUIDs) },
+    { "nativeSetRecognitionResults",
+"("
+"I"
+"[Ljava/lang/String;"
+")"
+"V", reinterpret_cast<void*>(SetRecognitionResults) },
+    { "nativeAddBookmarkFromAPI",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/Long;"
+"Ljava/lang/Boolean;"
+"Ljava/lang/Long;"
+"[B"
+"Ljava/lang/String;"
+"Ljava/lang/Integer;"
+")"
+"J", reinterpret_cast<void*>(AddBookmarkFromAPI) },
+    { "nativeFindAll",
+"("
+"Ljava/lang/String;"
+")"
+"I", reinterpret_cast<void*>(FindAll) },
+    { "nativeGetInnerClass",
+"("
+")"
+"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
+    reinterpret_cast<void*>(GetInnerClass) },
+    { "nativeQueryBitmap",
+"("
+"I"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Landroid/graphics/Bitmap;", reinterpret_cast<void*>(QueryBitmap) },
+    { "nativeGotOrientation",
+"("
+"I"
+"D"
+"D"
+"D"
+")"
+"V", reinterpret_cast<void*>(GotOrientation) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(TestJni_clazz(env),
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, TestJni_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
new file mode 100644
index 0000000..5fa901c
--- /dev/null
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject jcaller,
+    jlong nativeChromeBrowserProvider) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
+  return native->Destroy(env, jcaller);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeDestroy",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(TestJni_clazz(env),
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, TestJni_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testPureNativeMethodsOption.golden b/base/android/jni_generator/testPureNativeMethodsOption.golden
new file mode 100644
index 0000000..ad63cca
--- /dev/null
+++ b/base/android/jni_generator/testPureNativeMethodsOption.golden
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/example/jni_generator/Test
+
+#ifndef org_chromium_example_jni_generator_Test_JNI
+#define org_chromium_example_jni_generator_Test_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+static jlong Method(JNIEnv* env, jobject jcaller,
+    jlong nativeTest,
+    jint arg1) {
+  Test* native = reinterpret_cast<Test*>(nativeTest);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(arg1);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTest[] = {
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"J", reinterpret_cast<void*>(Method) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Test_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestClassPath).obj()));
+
+  const int kMethodsTestSize = arraysize(kMethodsTest);
+
+  if (env->RegisterNatives(Test_clazz(env),
+                           kMethodsTest,
+                           kMethodsTestSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Test_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
new file mode 100644
index 0000000..1cf6554
--- /dev/null
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -0,0 +1,84 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/foo/Foo
+
+#ifndef org_chromium_foo_Foo_JNI
+#define org_chromium_foo_Foo_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kFooClassPath[] = "org/chromium/foo/Foo";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Foo_clazz = NULL;
+#define Foo_clazz(env) g_Foo_clazz
+
+}  // namespace
+
+static void DoSomething(JNIEnv* env, jclass jcaller,
+    jobject callback);
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_Foo_calledByNative = 0;
+static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, Foo_clazz(env),
+      Foo_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, Foo_clazz(env),
+      "calledByNative",
+
+"("
+"Lorg/chromium/foo/Bar$Callback;"
+")"
+"V",
+      &g_Foo_calledByNative);
+
+     env->CallStaticVoidMethod(Foo_clazz(env),
+          method_id, callback);
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsFoo[] = {
+    { "nativeDoSomething",
+"("
+"Lorg/chromium/foo/Bar$Callback;"
+")"
+"V", reinterpret_cast<void*>(DoSomething) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kFooClassPath).obj()));
+
+  const int kMethodsFooSize = arraysize(kMethodsFoo);
+
+  if (env->RegisterNatives(Foo_clazz(env),
+                           kMethodsFoo,
+                           kMethodsFooSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Foo_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_int_wrapper.h b/base/android/jni_int_wrapper.h
new file mode 100644
index 0000000..fa0f3d5
--- /dev/null
+++ b/base/android/jni_int_wrapper.h
@@ -0,0 +1,56 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_INT_WRAPPER_H_
+#define BASE_ANDROID_JNI_INT_WRAPPER_H_
+
+// Wrapper used to receive int when calling Java from native.
+// The wrapper disallows automatic conversion of long to int.
+// This is to avoid a common anti-pattern where a Java int is used
+// to receive a native pointer. Please use a Java long to receive
+// native pointers, so that the code works on both 32-bit and 64-bit
+// platforms. Note the wrapper allows other lossy conversions into
+// jint that could be consider anti-patterns, such as from size_t.
+
+// Checking is only done in debugging builds.
+
+#ifdef NDEBUG
+
+typedef jint JniIntWrapper;
+
+// This inline is sufficiently trivial that it does not change the
+// final code generated by g++.
+inline jint as_jint(JniIntWrapper wrapper) {
+  return wrapper;
+}
+
+#else
+
+class JniIntWrapper {
+ public:
+  JniIntWrapper() : i_(0) {}
+  JniIntWrapper(int i) : i_(i) {}
+  JniIntWrapper(const JniIntWrapper& ji) : i_(ji.i_) {}
+  template <class T> JniIntWrapper(const T& t) : i_(t) {}
+  jint as_jint() const { return i_; }
+ private:
+  // If you get an "is private" error at the line below it is because you used
+  // an implicit conversion to convert a long to an int when calling Java.
+  // We disallow this, as a common anti-pattern allows converting a native
+  // pointer (intptr_t) to a Java int. Please use a Java long to represent
+  // a native pointer. If you want a lossy conversion, please use an
+  // explicit conversion in your C++ code. Note an error is only seen when
+  // compiling on a 64-bit platform, as intptr_t is indistinguishable from
+  // int on 32-bit platforms.
+  JniIntWrapper(long);
+  jint i_;
+};
+
+inline jint as_jint(const JniIntWrapper& wrapper) {
+  return wrapper.as_jint();
+}
+
+#endif  // NDEBUG
+
+#endif  // BASE_ANDROID_JNI_INT_WRAPPER_H_
diff --git a/base/android/jni_registrar.cc b/base/android/jni_registrar.cc
new file mode 100644
index 0000000..8e13e60
--- /dev/null
+++ b/base/android/jni_registrar.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_registrar.h"
+
+#include "base/logging.h"
+#include "base/android/jni_android.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace android {
+
+bool RegisterNativeMethods(JNIEnv* env,
+                           const RegistrationMethod* method,
+                           size_t count) {
+  TRACE_EVENT0("startup", "base_android::RegisterNativeMethods")
+  const RegistrationMethod* end = method + count;
+  while (method != end) {
+    if (!method->func(env)) {
+      DLOG(ERROR) << method->name << " failed registration!";
+      return false;
+    }
+    method++;
+  }
+  return true;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_registrar.h b/base/android/jni_registrar.h
new file mode 100644
index 0000000..849d07f
--- /dev/null
+++ b/base/android/jni_registrar.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_REGISTRAR_H_
+#define BASE_ANDROID_JNI_REGISTRAR_H_
+
+#include <jni.h>
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+struct RegistrationMethod;
+
+// Registers the JNI bindings for the specified |method| definition containing
+// |count| elements.  Returns whether the registration of the given methods
+// succeeded.
+BASE_EXPORT bool RegisterNativeMethods(JNIEnv* env,
+                                       const RegistrationMethod* method,
+                                       size_t count);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_REGISTRAR_H_
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
new file mode 100644
index 0000000..57c2805
--- /dev/null
+++ b/base/android/jni_string.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+// Internal version that does not use a scoped local pointer.
+jstring ConvertUTF16ToJavaStringImpl(JNIEnv* env,
+                                     const base::StringPiece16& str) {
+  jstring result = env->NewString(str.data(), str.length());
+  base::android::CheckException(env);
+  return result;
+}
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+void ConvertJavaStringToUTF8(JNIEnv* env, jstring str, std::string* result) {
+  if (!str) {
+    LOG(WARNING) << "ConvertJavaStringToUTF8 called with null string.";
+    result->clear();
+    return;
+  }
+  // JNI's GetStringUTFChars() returns strings in Java "modified" UTF8, so
+  // instead get the String in UTF16 and convert using chromium's conversion
+  // function that yields plain (non Java-modified) UTF8.
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  UTF16ToUTF8(chars, env->GetStringLength(str), result);
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+}
+
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
+  std::string result;
+  ConvertJavaStringToUTF8(env, str, &result);
+  return result;
+}
+
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str) {
+  // JNI's NewStringUTF expects "modified" UTF8 so instead create the string
+  // via our own UTF16 conversion utility.
+  // Further, Dalvik requires the string passed into NewStringUTF() to come from
+  // a trusted source. We can't guarantee that all UTF8 will be sanitized before
+  // it gets here, so constructing via UTF16 side-steps this issue.
+  // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
+  // a significant performance hit by doing it this way).
+  return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
+      env, UTF8ToUTF16(str)));
+}
+
+void ConvertJavaStringToUTF16(JNIEnv* env, jstring str, string16* result) {
+  if (!str) {
+    LOG(WARNING) << "ConvertJavaStringToUTF16 called with null string.";
+    result->clear();
+    return;
+  }
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  // GetStringChars isn't required to NULL-terminate the strings
+  // it returns, so the length must be explicitly checked.
+  result->assign(chars, env->GetStringLength(str));
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+}
+
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
+  string16 result;
+  ConvertJavaStringToUTF16(env, str, &result);
+  return result;
+}
+
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str) {
+  return ScopedJavaLocalRef<jstring>(env,
+                                     ConvertUTF16ToJavaStringImpl(env, str));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_string.h b/base/android/jni_string.h
new file mode 100644
index 0000000..89af5b0
--- /dev/null
+++ b/base/android/jni_string.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_STRING_H_
+#define BASE_ANDROID_JNI_STRING_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+namespace android {
+
+// Convert a Java string to UTF8. Returns a std string.
+BASE_EXPORT void ConvertJavaStringToUTF8(JNIEnv* env,
+                                         jstring str,
+                                         std::string* result);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
+
+// Convert a std string to Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str);
+
+// Convert a Java string to UTF16. Returns a string16.
+BASE_EXPORT void ConvertJavaStringToUTF16(JNIEnv* env,
+                                          jstring str,
+                                          string16* result);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
+
+// Convert a string16 to a Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_STRING_H_
diff --git a/base/android/jni_string_unittest.cc b/base/android/jni_string_unittest.cc
new file mode 100644
index 0000000..abd0683
--- /dev/null
+++ b/base/android/jni_string_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniString, BasicConversionsUTF8) {
+  const std::string kSimpleString = "SimpleTest8";
+  JNIEnv* env = AttachCurrentThread();
+  std::string result =
+      ConvertJavaStringToUTF8(ConvertUTF8ToJavaString(env, kSimpleString));
+  EXPECT_EQ(kSimpleString, result);
+}
+
+TEST(JniString, BasicConversionsUTF16) {
+  const string16 kSimpleString = UTF8ToUTF16("SimpleTest16");
+  JNIEnv* env = AttachCurrentThread();
+  string16 result =
+      ConvertJavaStringToUTF16(ConvertUTF16ToJavaString(env, kSimpleString));
+  EXPECT_EQ(kSimpleString, result);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_utils.cc b/base/android/jni_utils.cc
new file mode 100644
index 0000000..b4d682b
--- /dev/null
+++ b/base/android/jni_utils.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+#include "jni/JNIUtils_jni.h"
+
+namespace base {
+namespace android {
+
+ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env) {
+  return Java_JNIUtils_getClassLoader(env);
+}
+
+bool RegisterJNIUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
+
diff --git a/base/android/jni_utils.h b/base/android/jni_utils.h
new file mode 100644
index 0000000..b793aed
--- /dev/null
+++ b/base/android/jni_utils.h
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_UTILS_H_
+#define BASE_ANDROID_JNI_UTILS_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+
+namespace base {
+
+namespace android {
+
+// Gets a ClassLoader instance capable of loading Chromium java classes.
+// This should be called either from JNI_OnLoad or from within a method called
+// via JNI from Java.
+BASE_EXPORT ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env);
+
+bool RegisterJNIUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_UTILS_H_
+
diff --git a/base/android/jni_weak_ref.cc b/base/android/jni_weak_ref.cc
new file mode 100644
index 0000000..35a76da
--- /dev/null
+++ b/base/android/jni_weak_ref.cc
@@ -0,0 +1,67 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_weak_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+using base::android::AttachCurrentThread;
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef()
+  : obj_(NULL) {
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
+    const JavaObjectWeakGlobalRef& orig)
+    : obj_(NULL) {
+  Assign(orig);
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj)
+    : obj_(env->NewWeakGlobalRef(obj)) {
+  DCHECK(obj_);
+}
+
+JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() {
+  reset();
+}
+
+void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) {
+  Assign(rhs);
+}
+
+void JavaObjectWeakGlobalRef::reset() {
+  if (obj_) {
+    AttachCurrentThread()->DeleteWeakGlobalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+    JavaObjectWeakGlobalRef::get(JNIEnv* env) const {
+  return GetRealObject(env, obj_);
+}
+
+base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+    JNIEnv* env, jweak obj) {
+  jobject real = NULL;
+  if (obj) {
+    real = env->NewLocalRef(obj);
+    if (!real)
+      DLOG(ERROR) << "The real object has been deleted!";
+  }
+  return base::android::ScopedJavaLocalRef<jobject>(env, real);
+}
+
+void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) {
+  if (&other == this)
+    return;
+
+  JNIEnv* env = AttachCurrentThread();
+  if (obj_)
+    env->DeleteWeakGlobalRef(obj_);
+
+  obj_ = other.obj_ ? env->NewWeakGlobalRef(other.obj_) : NULL;
+}
diff --git a/base/android/jni_weak_ref.h b/base/android/jni_weak_ref.h
new file mode 100644
index 0000000..c851046
--- /dev/null
+++ b/base/android/jni_weak_ref.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_WEAK_REF_H_
+#define BASE_ANDROID_JNI_WEAK_REF_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+// Manages WeakGlobalRef lifecycle.
+// This class is not thread-safe w.r.t. get() and reset(). Multiple threads may
+// safely use get() concurrently, but if the user calls reset() (or of course,
+// calls the destructor) they'll need to provide their own synchronization.
+class BASE_EXPORT JavaObjectWeakGlobalRef {
+ public:
+  JavaObjectWeakGlobalRef();
+  JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig);
+  JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj);
+  virtual ~JavaObjectWeakGlobalRef();
+
+  void operator=(const JavaObjectWeakGlobalRef& rhs);
+
+  base::android::ScopedJavaLocalRef<jobject> get(JNIEnv* env) const;
+
+  bool is_empty() const { return obj_ == NULL; }
+
+  void reset();
+
+ private:
+  void Assign(const JavaObjectWeakGlobalRef& rhs);
+
+  jweak obj_;
+};
+
+// Get the real object stored in the weak reference returned as a
+// ScopedJavaLocalRef.
+BASE_EXPORT base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+    JNIEnv* env, jweak obj);
+
+#endif  // BASE_ANDROID_JNI_WEAK_REF_H_
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
new file mode 100644
index 0000000..46bdc67
--- /dev/null
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -0,0 +1,99 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowLog;
+
+import java.util.List;
+
+/** Unit tests for {@link Log}. */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {LogTest.PermissiveShadowLog.class})
+public class LogTest {
+    /** Test method for {@link Log#makeTag(String)} */
+    @Test
+    public void testMakeTag() {
+        assertEquals("cr.Foo", Log.makeTag("Foo"));
+        assertEquals("cr", Log.makeTag(null));
+        assertEquals("cr", Log.makeTag(""));
+    }
+
+    /** Test method for {@link Log#makeTag(String)} */
+    @Test(expected = IllegalArgumentException.class)
+    public void testMakeTagFailure() {
+        Log.makeTag("ThisIs21Char.....Long");
+    }
+
+    /** Tests that the computed call origin is the correct one. */
+    @Test
+    public void callOriginTest() {
+        Log.d("Foo", "Bar");
+
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+        assertEquals("Only one log should be written", 1, logs.size());
+
+        assertTrue("The origin of the log message (" + logs.get(0).msg + ") looks wrong.",
+                logs.get(0).msg.matches("\\[LogTest.java:\\d+\\].*"));
+    }
+
+    /** Tests that exceptions provided to the log functions are properly recognized and printed. */
+    @Test
+    public void exceptionLoggingTest() {
+        Throwable t = new Throwable() {
+            @Override
+            public String toString() {
+                return "MyThrowable";
+            }
+        };
+
+        Throwable t2 = new Throwable() {
+            @Override
+            public String toString() {
+                return "MyOtherThrowable";
+            }
+        };
+
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        // The throwable gets printed out
+        Log.i("Foo", "Bar", t);
+        assertEquals(t, logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar", logs.get(logs.size() - 1).msg);
+
+        // The throwable can be both added to the message itself and printed out
+        Log.i("Foo", "Bar %s", t);
+        assertEquals(t, logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar MyThrowable", logs.get(logs.size() - 1).msg);
+
+        // Non throwable are properly identified
+        Log.i("Foo", "Bar %s", t, "Baz");
+        assertNull(logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar MyThrowable", logs.get(logs.size() - 1).msg);
+
+        // The last throwable is the one used that is going to be printed out
+        Log.i("Foo", "Bar %s %s", t, t2);
+        assertEquals(t2, logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar MyThrowable MyOtherThrowable", logs.get(logs.size() - 1).msg);
+    }
+
+    /** Needed to allow debug/verbose logging that is disabled by default. */
+    @Implements(android.util.Log.class)
+    public static class PermissiveShadowLog extends ShadowLog {
+        @Implementation
+        public static boolean isLoggable(String tag, int level) {
+            return true;
+        }
+    }
+}
diff --git a/base/android/library_loader/library_load_from_apk_status_codes.h b/base/android/library_loader/library_load_from_apk_status_codes.h
new file mode 100644
index 0000000..9591d3f
--- /dev/null
+++ b/base/android/library_loader/library_load_from_apk_status_codes.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+
+namespace base {
+namespace android {
+
+namespace {
+
+// This enum must be kept in sync with the LibraryLoadFromApkStatus enum in
+// tools/metrics/histograms/histograms.xml.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.library_loader
+enum LibraryLoadFromApkStatusCodes {
+  // The loader was unable to determine whether the functionality is supported.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_UNKNOWN = 0,
+
+  // The device does not support loading a library directly from the APK file.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_NOT_SUPPORTED = 1,
+
+  // The device supports loading a library directly from the APK file.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUPPORTED = 2,
+
+  // The Chromium library was successfully loaded directly from the APK file.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUCCESSFUL = 3,
+
+  // The Chromium library was successfully loaded using the unpack library
+  // fallback because it was compressed or not page aligned in the APK file.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_UNPACK_LIBRARY_FALLBACK = 4,
+
+  // The Chromium library was successfully loaded using the no map executable
+  // support fallback.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_NO_MAP_EXEC_SUPPORT_FALLBACK = 5,
+
+  // End sentinel.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX = 6,
+};
+
+}  // namespace
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
new file mode 100644
index 0000000..0b59a30
--- /dev/null
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -0,0 +1,152 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/library_loader/library_loader_hooks.h"
+
+#include "base/android/command_line_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/library_loader/library_load_from_apk_status_codes.h"
+#include "base/android/library_loader/library_prefetcher.h"
+#include "base/at_exit.h"
+#include "base/metrics/histogram.h"
+#include "jni/LibraryLoader_jni.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+base::AtExitManager* g_at_exit_manager = NULL;
+const char* g_library_version_number = "";
+LibraryLoadedHook* g_registration_callback = NULL;
+
+enum RendererHistogramCode {
+  // Renderer load at fixed address success, fail, or not attempted.
+  // Renderers do not attempt to load at at fixed address if on a
+  // low-memory device on which browser load at fixed address has already
+  // failed.
+  LFA_SUCCESS = 0,
+  LFA_BACKOFF_USED = 1,
+  LFA_NOT_ATTEMPTED = 2,
+
+  // End sentinel, also used as nothing-pending indicator.
+  MAX_RENDERER_HISTOGRAM_CODE = 3,
+  NO_PENDING_HISTOGRAM_CODE = MAX_RENDERER_HISTOGRAM_CODE
+};
+
+enum BrowserHistogramCode {
+  // Non-low-memory random address browser loads.
+  NORMAL_LRA_SUCCESS = 0,
+
+  // Low-memory browser loads at fixed address, success or fail.
+  LOW_MEMORY_LFA_SUCCESS = 1,
+  LOW_MEMORY_LFA_BACKOFF_USED = 2,
+
+  MAX_BROWSER_HISTOGRAM_CODE = 3,
+};
+
+RendererHistogramCode g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
+
+} // namespace
+
+static void RegisterChromiumAndroidLinkerRendererHistogram(
+    JNIEnv* env,
+    jobject jcaller,
+    jboolean requested_shared_relro,
+    jboolean load_at_fixed_address_failed) {
+  // Note a pending histogram value for later recording.
+  if (requested_shared_relro) {
+    g_renderer_histogram_code = load_at_fixed_address_failed
+                                ? LFA_BACKOFF_USED : LFA_SUCCESS;
+  } else {
+    g_renderer_histogram_code = LFA_NOT_ATTEMPTED;
+  }
+}
+
+void RecordChromiumAndroidLinkerRendererHistogram() {
+  if (g_renderer_histogram_code == NO_PENDING_HISTOGRAM_CODE)
+    return;
+  // Record and release the pending histogram value.
+  UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.RendererStates",
+                            g_renderer_histogram_code,
+                            MAX_RENDERER_HISTOGRAM_CODE);
+  g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
+}
+
+static void RecordChromiumAndroidLinkerBrowserHistogram(
+    JNIEnv* env,
+    jobject jcaller,
+    jboolean is_using_browser_shared_relros,
+    jboolean load_at_fixed_address_failed,
+    jint library_load_from_apk_status) {
+  // For low-memory devices, record whether or not we successfully loaded the
+  // browser at a fixed address. Otherwise just record a normal invocation.
+  BrowserHistogramCode histogram_code;
+  if (is_using_browser_shared_relros) {
+    histogram_code = load_at_fixed_address_failed
+                     ? LOW_MEMORY_LFA_BACKOFF_USED : LOW_MEMORY_LFA_SUCCESS;
+  } else {
+    histogram_code = NORMAL_LRA_SUCCESS;
+  }
+  UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.BrowserStates",
+                            histogram_code,
+                            MAX_BROWSER_HISTOGRAM_CODE);
+
+  // Record the device support for loading a library directly from the APK file.
+  UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.LibraryLoadFromApkStatus",
+                            library_load_from_apk_status,
+                            LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX);
+}
+
+void SetLibraryLoadedHook(LibraryLoadedHook* func) {
+  g_registration_callback = func;
+}
+
+static void InitCommandLine(JNIEnv* env,
+                            jobject jcaller,
+                            jobjectArray init_command_line) {
+  InitNativeCommandLineFromJavaArray(env, init_command_line);
+}
+
+static jboolean LibraryLoaded(JNIEnv* env, jobject jcaller) {
+  if (g_registration_callback == NULL) {
+    return true;
+  }
+  return g_registration_callback(env, NULL);
+}
+
+void LibraryLoaderExitHook() {
+  if (g_at_exit_manager) {
+    delete g_at_exit_manager;
+    g_at_exit_manager = NULL;
+  }
+}
+
+static jboolean ForkAndPrefetchNativeLibrary(JNIEnv* env, jclass clazz) {
+  return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+}
+
+bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void SetVersionNumber(const char* version_number) {
+  g_library_version_number = strdup(version_number);
+}
+
+jstring GetVersionNumber(JNIEnv* env, jobject jcaller) {
+  return ConvertUTF8ToJavaString(env, g_library_version_number).Release();
+}
+
+LibraryProcessType GetLibraryProcessType(JNIEnv* env) {
+  return static_cast<LibraryProcessType>(
+      Java_LibraryLoader_getLibraryProcessType(env));
+}
+
+void InitAtExitManager() {
+  g_at_exit_manager = new base::AtExitManager();
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/library_loader/library_loader_hooks.h b/base/android/library_loader/library_loader_hooks.h
new file mode 100644
index 0000000..ca3c5a2
--- /dev/null
+++ b/base/android/library_loader/library_loader_hooks.h
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// The process the shared library is loaded in.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.library_loader
+enum LibraryProcessType {
+  // The LibraryLoad has not been initialized.
+  PROCESS_UNINITIALIZED = 0,
+  // Shared library is running in browser process.
+  PROCESS_BROWSER = 1,
+  // Shared library is running in child process.
+  PROCESS_CHILD = 2,
+  // Shared library is running in webview process.
+  PROCESS_WEBVIEW = 3,
+};
+
+// Record any pending renderer histogram value as a histogram.  Pending values
+// are set by RegisterChromiumAndroidLinkerRendererHistogram.
+BASE_EXPORT void RecordChromiumAndroidLinkerRendererHistogram();
+
+// Registers the callbacks that allows the entry point of the library to be
+// exposed to the calling java code.  This handles only registering the
+// the callbacks needed by the loader. Any application specific JNI bindings
+// should happen once the native library has fully loaded, either in the library
+// loaded hook function or later.
+BASE_EXPORT bool RegisterLibraryLoaderEntryHook(JNIEnv* env);
+
+// Typedef for hook function to be called (indirectly from Java) once the
+// libraries are loaded. The hook function should register the JNI bindings
+// required to start the application. It should return true for success and
+// false for failure.
+// Note: this can't use base::Callback because there is no way of initializing
+// the default callback without using static objects, which we forbid.
+typedef bool LibraryLoadedHook(JNIEnv* env,
+                               jclass clazz);
+
+// Set the hook function to be called (from Java) once the libraries are loaded.
+// SetLibraryLoadedHook may only be called from JNI_OnLoad. The hook function
+// should register the JNI bindings required to start the application.
+
+BASE_EXPORT void SetLibraryLoadedHook(LibraryLoadedHook* func);
+
+// Pass the version name to the loader. This used to check that the library
+// version matches the version expected by Java before completing JNI
+// registration.
+// Note: argument must remain valid at least until library loading is complete.
+BASE_EXPORT void SetVersionNumber(const char* version_number);
+
+// Call on exit to delete the AtExitManager which OnLibraryLoadedOnUIThread
+// created.
+BASE_EXPORT void LibraryLoaderExitHook();
+
+// Return the process type the shared library is loaded in.
+BASE_EXPORT LibraryProcessType GetLibraryProcessType(JNIEnv* env);
+
+// Initialize AtExitManager, this must be done at the begining of loading
+// shared library.
+void InitAtExitManager();
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
new file mode 100644
index 0000000..798a283
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/library_loader/library_prefetcher.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+// Android defines the background priority to this value since at least 2009
+// (see Process.java).
+const int kBackgroundPriority = 10;
+// Valid for all the Android architectures.
+const size_t kPageSize = 4096;
+const char* kLibchromeSuffix = "libchrome.so";
+// "base.apk" is a suffix because the library may be loaded directly from the
+// APK.
+const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
+
+bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
+  return region.permissions & base::debug::MappedMemoryRegion::READ &&
+         region.permissions & base::debug::MappedMemoryRegion::PRIVATE;
+}
+
+bool PathMatchesSuffix(const std::string& path) {
+  for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
+    if (EndsWith(path, kSuffixesToMatch[i], true)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// For each range, reads a byte per page to force it into the page cache.
+// Heap allocations, syscalls and library functions are not allowed in this
+// function.
+// Returns true for success.
+bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
+  for (const auto& range : ranges) {
+    const uintptr_t page_mask = kPageSize - 1;
+    // If start or end is not page-aligned, parsing went wrong. It is better to
+    // exit with an error.
+    if ((range.first & page_mask) || (range.second & page_mask)) {
+      return false;  // CHECK() is not allowed here.
+    }
+    unsigned char* start_ptr = reinterpret_cast<unsigned char*>(range.first);
+    unsigned char* end_ptr = reinterpret_cast<unsigned char*>(range.second);
+    unsigned char dummy = 0;
+    for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
+      // Volatile is required to prevent the compiler from eliminating this
+      // loop.
+      dummy ^= *static_cast<volatile unsigned char*>(ptr);
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+// static
+bool NativeLibraryPrefetcher::IsGoodToPrefetch(
+    const base::debug::MappedMemoryRegion& region) {
+  return PathMatchesSuffix(region.path) &&
+         IsReadableAndPrivate(region);  // .text and .data mappings are private.
+}
+
+// static
+void NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(
+    const std::vector<base::debug::MappedMemoryRegion>& regions,
+    std::vector<AddressRange>* ranges) {
+  bool has_libchrome_region = false;
+  for (const base::debug::MappedMemoryRegion& region : regions) {
+    if (EndsWith(region.path, kLibchromeSuffix, true)) {
+      has_libchrome_region = true;
+      break;
+    }
+  }
+  for (const base::debug::MappedMemoryRegion& region : regions) {
+    if (has_libchrome_region &&
+        !EndsWith(region.path, kLibchromeSuffix, true)) {
+      continue;
+    }
+    ranges->push_back(std::make_pair(region.start, region.end));
+  }
+}
+
+// static
+bool NativeLibraryPrefetcher::FindRanges(std::vector<AddressRange>* ranges) {
+  std::string proc_maps;
+  if (!base::debug::ReadProcMaps(&proc_maps))
+    return false;
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  if (!base::debug::ParseProcMaps(proc_maps, &regions))
+    return false;
+
+  std::vector<base::debug::MappedMemoryRegion> regions_to_prefetch;
+  for (const auto& region : regions) {
+    if (IsGoodToPrefetch(region)) {
+      regions_to_prefetch.push_back(region);
+    }
+  }
+
+  FilterLibchromeRangesOnlyIfPossible(regions_to_prefetch, ranges);
+  return true;
+}
+
+// static
+bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+  // Looking for ranges is done before the fork, to avoid syscalls and/or memory
+  // allocations in the forked process. The child process inherits the lock
+  // state of its parent thread. It cannot rely on being able to acquire any
+  // lock (unless special care is taken in a pre-fork handler), including being
+  // able to call malloc().
+  std::vector<AddressRange> ranges;
+  if (!FindRanges(&ranges))
+    return false;
+  pid_t pid = fork();
+  if (pid == 0) {
+    setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
+    // _exit() doesn't call the atexit() handlers.
+    _exit(Prefetch(ranges) ? 0 : 1);
+  } else {
+    if (pid < 0) {
+      return false;
+    }
+    int status;
+    const pid_t result = HANDLE_EINTR(waitpid(pid, &status, 0));
+    if (result == pid) {
+      if (WIFEXITED(status)) {
+        return WEXITSTATUS(status) == 0;
+      }
+    }
+    return false;
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
new file mode 100644
index 0000000..64e5e1e
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.h
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+
+#include <jni.h>
+
+#include <stdint.h>
+#include <string>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace android {
+
+// Forks and waits for a process prefetching the native library. This is done in
+// a forked process for the following reasons:
+// - Isolating the main process from mistakes in the parsing. If the parsing
+//   returns an incorrect address, only the forked process will crash.
+// - Not inflating the memory used by the main process uselessly, which could
+//   increase its likelihood to be killed.
+// The forked process has background priority and, since it is not declared to
+// the Android runtime, can be killed at any time, which is not an issue here.
+class BASE_EXPORT NativeLibraryPrefetcher {
+ public:
+  // Finds the ranges matching the native library, forks a low priority
+  // process pre-fetching these ranges and wait()s for it.
+  // Returns true for success.
+  static bool ForkAndPrefetchNativeLibrary();
+
+ private:
+  using AddressRange = std::pair<uintptr_t, uintptr_t>;
+  // Returns true if the region matches native code or data.
+  static bool IsGoodToPrefetch(const base::debug::MappedMemoryRegion& region);
+  // Filters the regions to keep only libchrome ranges if possible.
+  static void FilterLibchromeRangesOnlyIfPossible(
+      const std::vector<base::debug::MappedMemoryRegion>& regions,
+      std::vector<AddressRange>* ranges);
+  // Finds the ranges matching the native library in /proc/self/maps.
+  // Returns true for success.
+  static bool FindRanges(std::vector<AddressRange>* ranges);
+
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchNoRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchUnreadableRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchSkipSharedRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchLibchromeRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchBaseApkRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
diff --git a/base/android/library_loader/library_prefetcher_unittest.cc b/base/android/library_loader/library_prefetcher_unittest.cc
new file mode 100644
index 0000000..7b7296f
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/library_loader/library_prefetcher.h"
+
+#include <string>
+#include <vector>
+#include "base/debug/proc_maps_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+const uint8 kRead = base::debug::MappedMemoryRegion::READ;
+const uint8 kReadPrivate = base::debug::MappedMemoryRegion::READ |
+                           base::debug::MappedMemoryRegion::PRIVATE;
+const uint8 kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
+                              base::debug::MappedMemoryRegion::PRIVATE;
+}  // namespace
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
+  const base::debug::MappedMemoryRegion regions[4] = {
+      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, ""},
+      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, "foo"},
+      base::debug::MappedMemoryRegion{
+          0x4000, 0x5000, 10, kReadPrivate, "foobar.apk"},
+      base::debug::MappedMemoryRegion{
+          0x4000, 0x5000, 10, kReadPrivate, "libchromium.so"}};
+  for (int i = 0; i < 4; ++i) {
+    ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(regions[i]));
+  }
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchUnreadableRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kExecutePrivate, "base.apk"};
+  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchSkipSharedRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kRead, "base.apk"};
+  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchLibchromeRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kReadPrivate, "libchrome.so"};
+  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchBaseApkRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kReadPrivate, "base.apk"};
+  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest,
+     TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome) {
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+                                                               &ranges);
+  EXPECT_EQ(ranges.size(), 2U);
+  EXPECT_EQ(ranges[0].first, 0x1U);
+  EXPECT_EQ(ranges[0].second, 0x2U);
+  EXPECT_EQ(ranges[1].first, 0x3U);
+  EXPECT_EQ(ranges[1].second, 0x4U);
+}
+
+TEST(NativeLibraryPrefetcherTest,
+     TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome) {
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+  regions.push_back(base::debug::MappedMemoryRegion{
+      0x6, 0x7, 0, kReadPrivate, "libchrome.so"});
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+                                                               &ranges);
+  EXPECT_EQ(ranges.size(), 1U);
+  EXPECT_EQ(ranges[0].first, 0x6U);
+  EXPECT_EQ(ranges[0].second, 0x7U);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/linker/BUILD.gn b/base/android/linker/BUILD.gn
new file mode 100644
index 0000000..190ea47
--- /dev/null
+++ b/base/android/linker/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+
+assert(is_android)
+
+# GYP: //base/base.gyp:chromium_android_linker
+shared_library("chromium_android_linker") {
+  sources = [
+    "linker_jni.cc",
+  ]
+
+  # The NDK contains the crazy_linker here:
+  #   '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
+  # However, we use our own fork.  See bug 384700.
+  deps = [
+    "//third_party/android_crazy_linker",
+  ]
+
+  # TODO(GYP):
+  # The crazy linker is never instrumented.
+  #'cflags!': [
+  #'-finstrument-functions',
+  #],
+}
diff --git a/base/android/linker/DEPS b/base/android/linker/DEPS
new file mode 100644
index 0000000..15c3afb
--- /dev/null
+++ b/base/android/linker/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  # This code cannot depend on anything from base/
+  "-base",
+]
diff --git a/base/android/linker/config.gni b/base/android/linker/config.gni
new file mode 100644
index 0000000..99cbcf0
--- /dev/null
+++ b/base/android/linker/config.gni
@@ -0,0 +1,8 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(GYP) add "|| profiling_full_stack_frames
+# Only enable the chromium linker on regular builds, since the
+# component build crashes on Android 4.4. See b/11379966
+chromium_linker_supported = !is_component_build
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
new file mode 100644
index 0000000..b79eaf4
--- /dev/null
+++ b/base/android/linker/linker_jni.cc
@@ -0,0 +1,861 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is the Android-specific Chromium linker, a tiny shared library
+// implementing a custom dynamic linker that can be used to load the
+// real Chromium libraries (e.g. libcontentshell.so).
+
+// The main point of this linker is to be able to share the RELRO
+// section of libcontentshell.so (or equivalent) between the browser and
+// renderer process.
+
+// This source code *cannot* depend on anything from base/ or the C++
+// STL, to keep the final library small, and avoid ugly dependency issues.
+
+#include <android/log.h>
+#include <crazy_linker.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+// Set this to 1 to enable debug traces to the Android log.
+// Note that LOG() from "base/logging.h" cannot be used, since it is
+// in base/ which hasn't been loaded yet.
+#define DEBUG 0
+
+#define TAG "chromium_android_linker"
+
+#if DEBUG
+#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
+#else
+#define LOG_INFO(...) ((void)0)
+#endif
+#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+
+#define UNUSED __attribute__((unused))
+
+namespace {
+
+// A simply scoped UTF String class that can be initialized from
+// a Java jstring handle. Modeled like std::string, which cannot
+// be used here.
+class String {
+ public:
+  String(JNIEnv* env, jstring str);
+
+  ~String() {
+    if (ptr_)
+      ::free(ptr_);
+  }
+
+  const char* c_str() const { return ptr_ ? ptr_ : ""; }
+  size_t size() const { return size_; }
+
+ private:
+  char* ptr_;
+  size_t size_;
+};
+
+String::String(JNIEnv* env, jstring str) {
+  size_ = env->GetStringUTFLength(str);
+  ptr_ = static_cast<char*>(::malloc(size_ + 1));
+
+  // Note: the result contains Java "modified UTF-8" bytes.
+  // Good enough for the linker though.
+  const char* bytes = env->GetStringUTFChars(str, NULL);
+  ::memcpy(ptr_, bytes, size_);
+  ptr_[size_] = '\0';
+
+  env->ReleaseStringUTFChars(str, bytes);
+}
+
+// Return true iff |address| is a valid address for the target CPU.
+bool IsValidAddress(jlong address) {
+  return static_cast<jlong>(static_cast<size_t>(address)) == address;
+}
+
+// Find the jclass JNI reference corresponding to a given |class_name|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*clazz|.
+bool InitClassReference(JNIEnv* env, const char* class_name, jclass* clazz) {
+  *clazz = env->FindClass(class_name);
+  if (!*clazz) {
+    LOG_ERROR("Could not find class for %s", class_name);
+    return false;
+  }
+  return true;
+}
+
+// Initialize a jfieldID corresponding to the field of a given |clazz|,
+// with name |field_name| and signature |field_sig|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*field_id|.
+bool InitFieldId(JNIEnv* env,
+                 jclass clazz,
+                 const char* field_name,
+                 const char* field_sig,
+                 jfieldID* field_id) {
+  *field_id = env->GetFieldID(clazz, field_name, field_sig);
+  if (!*field_id) {
+    LOG_ERROR("Could not find ID for field '%s'", field_name);
+    return false;
+  }
+  LOG_INFO(
+      "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name);
+  return true;
+}
+
+// Initialize a jmethodID corresponding to the static method of a given
+// |clazz|, with name |method_name| and signature |method_sig|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*method_id|.
+bool InitStaticMethodId(JNIEnv* env,
+                        jclass clazz,
+                        const char* method_name,
+                        const char* method_sig,
+                        jmethodID* method_id) {
+  *method_id = env->GetStaticMethodID(clazz, method_name, method_sig);
+  if (!*method_id) {
+    LOG_ERROR("Could not find ID for static method '%s'", method_name);
+    return false;
+  }
+  LOG_INFO("%s: Found ID %p for static method '%s'",
+           __FUNCTION__, *method_id, method_name);
+  return true;
+}
+
+// Initialize a jfieldID corresponding to the static field of a given |clazz|,
+// with name |field_name| and signature |field_sig|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*field_id|.
+bool InitStaticFieldId(JNIEnv* env,
+                       jclass clazz,
+                       const char* field_name,
+                       const char* field_sig,
+                       jfieldID* field_id) {
+  *field_id = env->GetStaticFieldID(clazz, field_name, field_sig);
+  if (!*field_id) {
+    LOG_ERROR("Could not find ID for static field '%s'", field_name);
+    return false;
+  }
+  LOG_INFO(
+      "%s: Found ID %p for static field '%s'",
+      __FUNCTION__, *field_id, field_name);
+  return true;
+}
+
+// Initialize a jint corresponding to the static integer field of a class
+// with class name |class_name| and field name |field_name|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*value|.
+bool InitStaticInt(JNIEnv* env,
+                   const char* class_name,
+                   const char* field_name,
+                   jint* value) {
+  jclass clazz;
+  if (!InitClassReference(env, class_name, &clazz))
+    return false;
+
+  jfieldID field_id;
+  if (!InitStaticFieldId(env, clazz, field_name, "I", &field_id))
+    return false;
+
+  *value = env->GetStaticIntField(clazz, field_id);
+  LOG_INFO(
+      "%s: Found value %d for class '%s', static field '%s'",
+      __FUNCTION__, *value, class_name, field_name);
+
+  return true;
+}
+
+// A class used to model the field IDs of the org.chromium.base.Linker
+// LibInfo inner class, used to communicate data with the Java side
+// of the linker.
+struct LibInfo_class {
+  jfieldID load_address_id;
+  jfieldID load_size_id;
+  jfieldID relro_start_id;
+  jfieldID relro_size_id;
+  jfieldID relro_fd_id;
+
+  // Initialize an instance.
+  bool Init(JNIEnv* env) {
+    jclass clazz;
+    if (!InitClassReference(
+             env, "org/chromium/base/library_loader/Linker$LibInfo", &clazz)) {
+      return false;
+    }
+
+    return InitFieldId(env, clazz, "mLoadAddress", "J", &load_address_id) &&
+           InitFieldId(env, clazz, "mLoadSize", "J", &load_size_id) &&
+           InitFieldId(env, clazz, "mRelroStart", "J", &relro_start_id) &&
+           InitFieldId(env, clazz, "mRelroSize", "J", &relro_size_id) &&
+           InitFieldId(env, clazz, "mRelroFd", "I", &relro_fd_id);
+  }
+
+  void SetLoadInfo(JNIEnv* env,
+                   jobject library_info_obj,
+                   size_t load_address,
+                   size_t load_size) {
+    env->SetLongField(library_info_obj, load_address_id, load_address);
+    env->SetLongField(library_info_obj, load_size_id, load_size);
+  }
+
+  // Use this instance to convert a RelroInfo reference into
+  // a crazy_library_info_t.
+  void GetRelroInfo(JNIEnv* env,
+                    jobject library_info_obj,
+                    size_t* relro_start,
+                    size_t* relro_size,
+                    int* relro_fd) {
+    *relro_start = static_cast<size_t>(
+        env->GetLongField(library_info_obj, relro_start_id));
+
+    *relro_size =
+        static_cast<size_t>(env->GetLongField(library_info_obj, relro_size_id));
+
+    *relro_fd = env->GetIntField(library_info_obj, relro_fd_id);
+  }
+
+  void SetRelroInfo(JNIEnv* env,
+                    jobject library_info_obj,
+                    size_t relro_start,
+                    size_t relro_size,
+                    int relro_fd) {
+    env->SetLongField(library_info_obj, relro_start_id, relro_start);
+    env->SetLongField(library_info_obj, relro_size_id, relro_size);
+    env->SetIntField(library_info_obj, relro_fd_id, relro_fd);
+  }
+};
+
+static LibInfo_class s_lib_info_fields;
+
+// Retrieve the SDK build version and pass it into the crazy linker. This
+// needs to be done early in initialization, before any other crazy linker
+// code is run.
+// |env| is the current JNI environment handle.
+// On success, return true.
+bool InitSDKVersionInfo(JNIEnv* env) {
+  jint value = 0;
+  if (!InitStaticInt(env, "android/os/Build$VERSION", "SDK_INT", &value))
+    return false;
+
+  crazy_set_sdk_build_version(static_cast<int>(value));
+  LOG_INFO("%s: Set SDK build version to %d",
+           __FUNCTION__, static_cast<int>(value));
+
+  return true;
+}
+
+// The linker uses a single crazy_context_t object created on demand.
+// There is no need to protect this against concurrent access, locking
+// is already handled on the Java side.
+static crazy_context_t* s_crazy_context;
+
+crazy_context_t* GetCrazyContext() {
+  if (!s_crazy_context) {
+    // Create new context.
+    s_crazy_context = crazy_context_create();
+
+    // Ensure libraries located in the same directory as the linker
+    // can be loaded before system ones.
+    crazy_context_add_search_path_for_address(
+        s_crazy_context, reinterpret_cast<void*>(&s_crazy_context));
+  }
+
+  return s_crazy_context;
+}
+
+// A scoped crazy_library_t that automatically closes the handle
+// on scope exit, unless Release() has been called.
+class ScopedLibrary {
+ public:
+  ScopedLibrary() : lib_(NULL) {}
+
+  ~ScopedLibrary() {
+    if (lib_)
+      crazy_library_close_with_context(lib_, GetCrazyContext());
+  }
+
+  crazy_library_t* Get() { return lib_; }
+
+  crazy_library_t** GetPtr() { return &lib_; }
+
+  crazy_library_t* Release() {
+    crazy_library_t* ret = lib_;
+    lib_ = NULL;
+    return ret;
+  }
+
+ private:
+  crazy_library_t* lib_;
+};
+
+namespace {
+
+template <class LibraryOpener>
+bool GenericLoadLibrary(
+    JNIEnv* env,
+    const char* library_name, jlong load_address, jobject lib_info_obj,
+    const LibraryOpener& opener) {
+  crazy_context_t* context = GetCrazyContext();
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__, load_address);
+    return false;
+  }
+
+  // Set the desired load address (0 means randomize it).
+  crazy_context_set_load_address(context, static_cast<size_t>(load_address));
+
+  ScopedLibrary library;
+  if (!opener.Open(library.GetPtr(), library_name, context)) {
+    return false;
+  }
+
+  crazy_library_info_t info;
+  if (!crazy_library_get_info(library.Get(), context, &info)) {
+    LOG_ERROR("%s: Could not get library information for %s: %s",
+              __FUNCTION__,
+              library_name,
+              crazy_context_get_error(context));
+    return false;
+  }
+
+  // Release library object to keep it alive after the function returns.
+  library.Release();
+
+  s_lib_info_fields.SetLoadInfo(
+      env, lib_info_obj, info.load_address, info.load_size);
+  LOG_INFO("%s: Success loading library %s", __FUNCTION__, library_name);
+  return true;
+}
+
+// Used for opening the library in a regular file.
+class FileLibraryOpener {
+ public:
+  bool Open(
+      crazy_library_t** library,
+      const char* library_name,
+      crazy_context_t* context) const;
+};
+
+bool FileLibraryOpener::Open(
+    crazy_library_t** library,
+    const char* library_name,
+    crazy_context_t* context) const {
+  if (!crazy_library_open(library, library_name, context)) {
+    LOG_ERROR("%s: Could not open %s: %s",
+              __FUNCTION__,
+              library_name,
+              crazy_context_get_error(context));
+    return false;
+  }
+  return true;
+}
+
+// Used for opening the library in a zip file.
+class ZipLibraryOpener {
+ public:
+  explicit ZipLibraryOpener(const char* zip_file) : zip_file_(zip_file) {}
+  bool Open(
+      crazy_library_t** library,
+      const char* library_name,
+      crazy_context_t* context) const;
+ private:
+  const char* zip_file_;
+};
+
+bool ZipLibraryOpener::Open(
+    crazy_library_t** library,
+    const char* library_name,
+    crazy_context_t* context) const {
+  if (!crazy_library_open_in_zip_file(
+          library, zip_file_, library_name, context)) {
+     LOG_ERROR("%s: Could not open %s in zip file %s: %s",
+               __FUNCTION__, library_name, zip_file_,
+               crazy_context_get_error(context));
+     return false;
+  }
+  return true;
+}
+
+}  // unnamed namespace
+
+// Load a library with the chromium linker. This will also call its
+// JNI_OnLoad() method, which shall register its methods. Note that
+// lazy native method resolution will _not_ work after this, because
+// Dalvik uses the system's dlsym() which won't see the new library,
+// so explicit registration is mandatory.
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |library_name| is the library name (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |library_info| is a LibInfo handle used to communicate information
+// with the Java side.
+// Return true on success.
+jboolean LoadLibrary(JNIEnv* env,
+                     jclass clazz,
+                     jstring library_name,
+                     jlong load_address,
+                     jobject lib_info_obj) {
+  String lib_name(env, library_name);
+  FileLibraryOpener opener;
+  return GenericLoadLibrary(
+      env, lib_name.c_str(),
+      static_cast<size_t>(load_address), lib_info_obj, opener);
+}
+
+// Load a library from a zipfile with the chromium linker. The
+// library in the zipfile must be uncompressed and page aligned.
+// The basename of the library is given. The library is expected
+// to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the
+// same as the abi for this linker. The "crazy." prefix is included
+// so that the Android Package Manager doesn't extract the library into
+// /data/app-lib.
+//
+// Loading the library will also call its JNI_OnLoad() method, which
+// shall register its methods. Note that lazy native method resolution
+// will _not_ work after this, because Dalvik uses the system's dlsym()
+// which won't see the new library, so explicit registration is mandatory.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |zipfile_name| is the filename of the zipfile containing the library.
+// |library_name| is the library base name (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |library_info| is a LibInfo handle used to communicate information
+// with the Java side.
+// Returns true on success.
+jboolean LoadLibraryInZipFile(JNIEnv* env,
+                              jclass clazz,
+                              jstring zipfile_name,
+                              jstring library_name,
+                              jlong load_address,
+                              jobject lib_info_obj) {
+  String zipfile_name_str(env, zipfile_name);
+  String lib_name(env, library_name);
+  ZipLibraryOpener opener(zipfile_name_str.c_str());
+  return GenericLoadLibrary(
+      env, lib_name.c_str(),
+      static_cast<size_t>(load_address), lib_info_obj, opener);
+}
+
+// Enable the fallback due to lack of support for mapping the APK file with
+// executable permission in the crazy linker.
+//
+// |env| is the current JNI environment handle and is ignored here.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+void EnableNoMapExecSupportFallback(JNIEnv* env, jclass clazz) {
+  crazy_context_t* context = GetCrazyContext();
+  crazy_context_set_no_map_exec_support_fallback_enabled(context, true);
+}
+
+// Class holding the Java class and method ID for the Java side Linker
+// postCallbackOnMainThread method.
+struct JavaCallbackBindings_class {
+  jclass clazz;
+  jmethodID method_id;
+
+  // Initialize an instance.
+  bool Init(JNIEnv* env, jclass linker_class) {
+    clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class));
+    return InitStaticMethodId(env,
+                              linker_class,
+                              "postCallbackOnMainThread",
+                              "(J)V",
+                              &method_id);
+  }
+};
+
+static JavaCallbackBindings_class s_java_callback_bindings;
+
+// Designated receiver function for callbacks from Java. Its name is known
+// to the Java side.
+// |env| is the current JNI environment handle and is ignored here.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |arg| is a pointer to an allocated crazy_callback_t, deleted after use.
+void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) {
+  crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg);
+
+  LOG_INFO("%s: Called back from java with handler %p, opaque %p",
+           __FUNCTION__, callback->handler, callback->opaque);
+
+  crazy_callback_run(callback);
+  delete callback;
+}
+
+// Request a callback from Java. The supplied crazy_callback_t is valid only
+// for the duration of this call, so we copy it to a newly allocated
+// crazy_callback_t and then call the Java side's postCallbackOnMainThread.
+// This will call back to to our RunCallbackOnUiThread some time
+// later on the UI thread.
+// |callback_request| is a crazy_callback_t.
+// |poster_opaque| is unused.
+// Returns true if the callback request succeeds.
+static bool PostForLaterExecution(crazy_callback_t* callback_request,
+                                  void* poster_opaque UNUSED) {
+  crazy_context_t* context = GetCrazyContext();
+
+  JavaVM* vm;
+  int minimum_jni_version;
+  crazy_context_get_java_vm(context,
+                            reinterpret_cast<void**>(&vm),
+                            &minimum_jni_version);
+
+  // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own.
+  JNIEnv* env;
+  if (JNI_OK != vm->GetEnv(
+      reinterpret_cast<void**>(&env), minimum_jni_version)) {
+    LOG_ERROR("Could not create JNIEnv");
+    return false;
+  }
+
+  // Copy the callback; the one passed as an argument may be temporary.
+  crazy_callback_t* callback = new crazy_callback_t();
+  *callback = *callback_request;
+
+  LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
+           __FUNCTION__, callback->handler, callback->opaque);
+
+  jlong arg = static_cast<jlong>(reinterpret_cast<uintptr_t>(callback));
+
+  env->CallStaticVoidMethod(
+      s_java_callback_bindings.clazz, s_java_callback_bindings.method_id, arg);
+
+  // Back out and return false if we encounter a JNI exception.
+  if (env->ExceptionCheck() == JNI_TRUE) {
+    env->ExceptionDescribe();
+    env->ExceptionClear();
+    delete callback;
+    return false;
+  }
+
+  return true;
+}
+
+jboolean CreateSharedRelro(JNIEnv* env,
+                           jclass clazz,
+                           jstring library_name,
+                           jlong load_address,
+                           jobject lib_info_obj) {
+  String lib_name(env, library_name);
+
+  LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str());
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__, load_address);
+    return false;
+  }
+
+  ScopedLibrary library;
+  if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
+    LOG_ERROR("%s: Could not find %s", __FUNCTION__, lib_name.c_str());
+    return false;
+  }
+
+  crazy_context_t* context = GetCrazyContext();
+  size_t relro_start = 0;
+  size_t relro_size = 0;
+  int relro_fd = -1;
+
+  if (!crazy_library_create_shared_relro(library.Get(),
+                                         context,
+                                         static_cast<size_t>(load_address),
+                                         &relro_start,
+                                         &relro_size,
+                                         &relro_fd)) {
+    LOG_ERROR("%s: Could not create shared RELRO sharing for %s: %s\n",
+              __FUNCTION__,
+              lib_name.c_str(),
+              crazy_context_get_error(context));
+    return false;
+  }
+
+  s_lib_info_fields.SetRelroInfo(
+      env, lib_info_obj, relro_start, relro_size, relro_fd);
+  return true;
+}
+
+jboolean UseSharedRelro(JNIEnv* env,
+                        jclass clazz,
+                        jstring library_name,
+                        jobject lib_info_obj) {
+  String lib_name(env, library_name);
+
+  LOG_INFO("%s: called for %s, lib_info_ref=%p",
+           __FUNCTION__,
+           lib_name.c_str(),
+           lib_info_obj);
+
+  ScopedLibrary library;
+  if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
+    LOG_ERROR("%s: Could not find %s", __FUNCTION__, lib_name.c_str());
+    return false;
+  }
+
+  crazy_context_t* context = GetCrazyContext();
+  size_t relro_start = 0;
+  size_t relro_size = 0;
+  int relro_fd = -1;
+  s_lib_info_fields.GetRelroInfo(
+      env, lib_info_obj, &relro_start, &relro_size, &relro_fd);
+
+  LOG_INFO("%s: library=%s relro start=%p size=%p fd=%d",
+           __FUNCTION__,
+           lib_name.c_str(),
+           (void*)relro_start,
+           (void*)relro_size,
+           relro_fd);
+
+  if (!crazy_library_use_shared_relro(
+           library.Get(), context, relro_start, relro_size, relro_fd)) {
+    LOG_ERROR("%s: Could not use shared RELRO for %s: %s",
+              __FUNCTION__,
+              lib_name.c_str(),
+              crazy_context_get_error(context));
+    return false;
+  }
+
+  LOG_INFO("%s: Library %s using shared RELRO section!",
+           __FUNCTION__,
+           lib_name.c_str());
+
+  return true;
+}
+
+jboolean CanUseSharedRelro(JNIEnv* env, jclass clazz) {
+  return crazy_system_can_share_relro();
+}
+
+jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) {
+  void* address =
+      mmap(NULL, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (address == MAP_FAILED) {
+    LOG_INFO("%s: Random base load address not determinable\n", __FUNCTION__);
+    return 0;
+  }
+  munmap(address, bytes);
+  LOG_INFO("%s: Random base load address is %p\n", __FUNCTION__, address);
+  return static_cast<jlong>(reinterpret_cast<uintptr_t>(address));
+}
+
+// Get the full path of a library in the zip file
+// (lib/<abi>/crazy.<lib_name>).
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle which is not used here.
+// |lib_name| is the library base name.
+// Returns the full path (or empty string on failure).
+jstring GetLibraryFilePathInZipFile(JNIEnv* env,
+                                    jclass clazz,
+                                    jstring lib_name) {
+  String lib_name_str(env, lib_name);
+  const char* lib_name_c_str = lib_name_str.c_str();
+  char buffer[kMaxFilePathLengthInZip + 1];
+  if (crazy_library_file_path_in_zip_file(
+          lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) {
+    LOG_ERROR("%s: Failed to get full filename for library '%s'",
+              __FUNCTION__, lib_name_c_str);
+    buffer[0] = '\0';
+  }
+  return env->NewStringUTF(buffer);
+}
+
+// Check whether the device supports mapping the APK file with executable
+// permission.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle which is not used here.
+// |apkfile_name| is the filename of the APK.
+// Returns true if supported.
+jboolean CheckMapExecSupport(JNIEnv* env, jclass clazz, jstring apkfile_name) {
+  String apkfile_name_str(env, apkfile_name);
+  const char* apkfile_name_c_str = apkfile_name_str.c_str();
+
+  int fd = open(apkfile_name_c_str, O_RDONLY);
+  if (fd == -1) {
+    LOG_ERROR("%s: Failed to open %s\n", __FUNCTION__, apkfile_name_c_str);
+    return false;
+  }
+
+  LOG_INFO(
+      "%s: Memory mapping the first page of %s with executable permissions\n",
+      __FUNCTION__, apkfile_name_c_str);
+  void* address = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_PRIVATE, fd, 0);
+
+  jboolean status;
+  if (address == MAP_FAILED) {
+    status = false;
+  } else {
+    status = true;
+    munmap(address, PAGE_SIZE);
+  }
+
+  close(fd);
+
+  LOG_INFO("%s: %s\n", __FUNCTION__, status ? "Supported" : "NOT supported");
+  return status;
+}
+
+// Check whether a library is page aligned and uncompressed in the APK file.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle which is not used here.
+// |apkfile_name| is the filename of the APK.
+// |library_name| is the library base name.
+// Returns true if page aligned and uncompressed.
+jboolean CheckLibraryIsMappableInApk(JNIEnv* env, jclass clazz,
+                                     jstring apkfile_name,
+                                     jstring library_name) {
+  String apkfile_name_str(env, apkfile_name);
+  const char* apkfile_name_c_str = apkfile_name_str.c_str();
+  String library_name_str(env, library_name);
+  const char* library_name_c_str = library_name_str.c_str();
+
+  LOG_INFO("%s: Checking if %s is page-aligned and uncompressed in %s\n",
+           __FUNCTION__, library_name_c_str, apkfile_name_c_str);
+  jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file(
+      apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS;
+  LOG_INFO("%s: %s\n", __FUNCTION__, mappable ? "Mappable" : "NOT mappable");
+
+  return mappable;
+}
+
+const JNINativeMethod kNativeMethods[] = {
+    {"nativeLoadLibrary",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibrary)},
+    {"nativeLoadLibraryInZipFile",
+     "("
+     "Ljava/lang/String;"
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibraryInZipFile)},
+    {"nativeEnableNoMapExecSupportFallback",
+     "("
+     ")"
+     "V",
+     reinterpret_cast<void*>(&EnableNoMapExecSupportFallback)},
+    {"nativeRunCallbackOnUiThread",
+     "("
+     "J"
+     ")"
+     "V",
+     reinterpret_cast<void*>(&RunCallbackOnUiThread)},
+    {"nativeCreateSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CreateSharedRelro)},
+    {"nativeUseSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&UseSharedRelro)},
+    {"nativeCanUseSharedRelro",
+     "("
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CanUseSharedRelro)},
+    {"nativeGetRandomBaseLoadAddress",
+     "("
+     "J"
+     ")"
+     "J",
+     reinterpret_cast<void*>(&GetRandomBaseLoadAddress)},
+    {"nativeGetLibraryFilePathInZipFile",
+     "("
+     "Ljava/lang/String;"
+     ")"
+     "Ljava/lang/String;",
+     reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)},
+    {"nativeCheckMapExecSupport",
+     "("
+     "Ljava/lang/String;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CheckMapExecSupport)},
+    {"nativeCheckLibraryIsMappableInApk",
+     "("
+     "Ljava/lang/String;"
+     "Ljava/lang/String;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CheckLibraryIsMappableInApk)}, };
+
+}  // namespace
+
+// JNI_OnLoad() hook called when the linker library is loaded through
+// the regular System.LoadLibrary) API. This shall save the Java VM
+// handle and initialize LibInfo fields.
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+  LOG_INFO("%s: Entering", __FUNCTION__);
+  // Get new JNIEnv
+  JNIEnv* env;
+  if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) {
+    LOG_ERROR("Could not create JNIEnv");
+    return -1;
+  }
+
+  // Initialize SDK version info.
+  LOG_INFO("%s: Retrieving SDK version info", __FUNCTION__);
+  if (!InitSDKVersionInfo(env))
+    return -1;
+
+  // Register native methods.
+  jclass linker_class;
+  if (!InitClassReference(env,
+                          "org/chromium/base/library_loader/Linker",
+                          &linker_class))
+    return -1;
+
+  LOG_INFO("%s: Registering native methods", __FUNCTION__);
+  env->RegisterNatives(linker_class,
+                       kNativeMethods,
+                       sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
+
+  // Find LibInfo field ids.
+  LOG_INFO("%s: Caching field IDs", __FUNCTION__);
+  if (!s_lib_info_fields.Init(env)) {
+    return -1;
+  }
+
+  // Resolve and save the Java side Linker callback class and method.
+  LOG_INFO("%s: Resolving callback bindings", __FUNCTION__);
+  if (!s_java_callback_bindings.Init(env, linker_class)) {
+    return -1;
+  }
+
+  // Save JavaVM* handle into context.
+  crazy_context_t* context = GetCrazyContext();
+  crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4);
+
+  // Register the function that the crazy linker can call to post code
+  // for later execution.
+  crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL);
+
+  LOG_INFO("%s: Done", __FUNCTION__);
+  return JNI_VERSION_1_4;
+}
diff --git a/base/android/locale_utils.cc b/base/android/locale_utils.cc
new file mode 100644
index 0000000..af46f89
--- /dev/null
+++ b/base/android/locale_utils.cc
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/locale_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "jni/LocaleUtils_jni.h"
+
+namespace base {
+namespace android {
+
+std::string GetDefaultCountryCode() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return ConvertJavaStringToUTF8(Java_LocaleUtils_getDefaultCountryCode(env));
+}
+
+std::string GetDefaultLocale() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> locale = Java_LocaleUtils_getDefaultLocale(
+      env);
+  return ConvertJavaStringToUTF8(locale);
+}
+
+bool RegisterLocaleUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/locale_utils.h b/base/android/locale_utils.h
new file mode 100644
index 0000000..9e03b83
--- /dev/null
+++ b/base/android/locale_utils.h
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_LOCALE_UTILS_H_
+#define BASE_ANDROID_LOCALE_UTILS_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+BASE_EXPORT std::string GetDefaultCountryCode();
+
+// Return the current default locale of the device.
+BASE_EXPORT std::string GetDefaultLocale();
+
+BASE_EXPORT bool RegisterLocaleUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LOCALE_UTILS_H_
diff --git a/base/android/memory_pressure_listener_android.cc b/base/android/memory_pressure_listener_android.cc
new file mode 100644
index 0000000..80c07bc
--- /dev/null
+++ b/base/android/memory_pressure_listener_android.cc
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/memory_pressure_listener_android.h"
+
+#include "base/memory/memory_pressure_listener.h"
+#include "jni/MemoryPressureListener_jni.h"
+
+// Defined and called by JNI.
+static void OnMemoryPressure(
+    JNIEnv* env, jclass clazz, jint memory_pressure_level) {
+  base::MemoryPressureListener::NotifyMemoryPressure(
+      static_cast<base::MemoryPressureListener::MemoryPressureLevel>(
+          memory_pressure_level));
+}
+
+namespace base {
+namespace android {
+
+bool MemoryPressureListenerAndroid::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void MemoryPressureListenerAndroid::RegisterSystemCallback(JNIEnv* env) {
+  Java_MemoryPressureListener_registerSystemCallback(
+      env, GetApplicationContext());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/memory_pressure_listener_android.h b/base/android/memory_pressure_listener_android.h
new file mode 100644
index 0000000..eed8dbb
--- /dev/null
+++ b/base/android/memory_pressure_listener_android.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
+#define BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
+
+#include "base/android/jni_android.h"
+
+namespace base {
+namespace android {
+
+// Implements the C++ counter part of MemoryPressureListener.java
+class BASE_EXPORT MemoryPressureListenerAndroid {
+ public:
+  static bool Register(JNIEnv* env);
+
+  static void RegisterSystemCallback(JNIEnv* env);
+
+  // Called by JNI.
+  static void OnMemoryPressure(int memory_pressure_type);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureListenerAndroid);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
diff --git a/base/android/path_service_android.cc b/base/android/path_service_android.cc
new file mode 100644
index 0000000..18ca70c
--- /dev/null
+++ b/base/android/path_service_android.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_service_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "jni/PathService_jni.h"
+
+namespace base {
+namespace android {
+
+void Override(JNIEnv* env, jclass clazz, jint what, jstring path) {
+  FilePath file_path(ConvertJavaStringToUTF8(env, path));
+  PathService::Override(what, file_path);
+}
+
+bool RegisterPathService(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/path_service_android.h b/base/android/path_service_android.h
new file mode 100644
index 0000000..26040f9
--- /dev/null
+++ b/base/android/path_service_android.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+#define BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterPathService(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_SERVICE_ANDROID_H_
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
new file mode 100644
index 0000000..c98007c
--- /dev/null
+++ b/base/android/path_utils.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/files/file_path.h"
+
+#include "jni/PathUtils_jni.h"
+
+namespace base {
+namespace android {
+
+bool GetDataDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDataDirectory(env, GetApplicationContext());
+  FilePath data_path(ConvertJavaStringToUTF8(path));
+  *result = data_path;
+  return true;
+}
+
+bool GetDatabaseDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDatabaseDirectory(env, GetApplicationContext());
+  FilePath data_path(ConvertJavaStringToUTF8(path));
+  *result = data_path;
+  return true;
+}
+
+bool GetCacheDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getCacheDirectory(env, GetApplicationContext());
+  FilePath cache_path(ConvertJavaStringToUTF8(path));
+  *result = cache_path;
+  return true;
+}
+
+bool GetDownloadsDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDownloadsDirectory(env, GetApplicationContext());
+  FilePath downloads_path(ConvertJavaStringToUTF8(path));
+  *result = downloads_path;
+  return true;
+}
+
+bool GetNativeLibraryDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getNativeLibraryDirectory(env, GetApplicationContext());
+  FilePath library_path(ConvertJavaStringToUTF8(path));
+  *result = library_path;
+  return true;
+}
+
+bool GetExternalStorageDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getExternalStorageDirectory(env);
+  FilePath storage_path(ConvertJavaStringToUTF8(path));
+  *result = storage_path;
+  return true;
+}
+
+bool RegisterPathUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
new file mode 100644
index 0000000..d3421b3
--- /dev/null
+++ b/base/android/path_utils.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_PATH_UTILS_H_
+#define BASE_ANDROID_PATH_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+
+class FilePath;
+
+namespace android {
+
+// Retrieves the absolute path to the data directory of the current
+// application. The result is placed in the FilePath pointed to by 'result'.
+// This method is dedicated for base_paths_android.c, Using
+// PathService::Get(base::DIR_ANDROID_APP_DATA, ...) gets the data dir.
+BASE_EXPORT bool GetDataDirectory(FilePath* result);
+
+// Retrieves the absolute path to the database directory that Android
+// framework's SQLiteDatabase class uses when creating database files.
+BASE_EXPORT bool GetDatabaseDirectory(FilePath* result);
+
+// Retrieves the absolute path to the cache directory. The result is placed in
+// the FilePath pointed to by 'result'. This method is dedicated for
+// base_paths_android.c, Using PathService::Get(base::DIR_CACHE, ...) gets the
+// cache dir.
+BASE_EXPORT bool GetCacheDirectory(FilePath* result);
+
+// Retrieves the path to the public downloads directory. The result is placed
+// in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetDownloadsDirectory(FilePath* result);
+
+// Retrieves the path to the native JNI libraries via
+// ApplicationInfo.nativeLibraryDir on the Java side. The result is placed in
+// the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetNativeLibraryDirectory(FilePath* result);
+
+// Retrieves the absolute path to the external storage directory. The result
+// is placed in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result);
+
+bool RegisterPathUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_UTILS_H_
diff --git a/base/android/path_utils_unittest.cc b/base/android/path_utils_unittest.cc
new file mode 100644
index 0000000..c678ce2
--- /dev/null
+++ b/base/android/path_utils_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_utils.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+typedef testing::Test PathUtilsTest;
+
+TEST_F(PathUtilsTest, TestGetDataDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetDataDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/app_chrome",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetCacheDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetCacheDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/cache",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that the directory contains
+  // the base tests shared object.
+  FilePath path;
+  GetNativeLibraryDirectory(&path);
+  EXPECT_TRUE(base::PathExists(path.Append(("libbase_unittests.so"))) ||
+              base::PathExists(path.Append(("libbase_unittests.cr.so"))));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc
new file mode 100644
index 0000000..9a68dec
--- /dev/null
+++ b/base/android/record_histogram.cc
@@ -0,0 +1,245 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/record_histogram.h"
+
+#include <map>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/lazy_instance.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "jni/RecordHistogram_jni.h"
+
+namespace base {
+namespace android {
+namespace {
+
+// Simple thread-safe wrapper for caching histograms. This avoids
+// relatively expensive JNI string translation for each recording.
+class HistogramCache {
+ public:
+  HistogramCache() {}
+
+  HistogramBase* BooleanHistogram(JNIEnv* env,
+                                  jstring j_histogram_name,
+                                  jint j_histogram_key) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    if (histogram)
+      return histogram;
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram = BooleanHistogram::FactoryGet(
+        histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* EnumeratedHistogram(JNIEnv* env,
+                                     jstring j_histogram_name,
+                                     jint j_histogram_key,
+                                     jint j_boundary) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    int boundary = static_cast<int>(j_boundary);
+    if (histogram) {
+      DCHECK(histogram->HasConstructionArguments(1, boundary, boundary + 1));
+      return histogram;
+    }
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram =
+        LinearHistogram::FactoryGet(histogram_name, 1, boundary, boundary + 1,
+                                    HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* CustomCountHistogram(JNIEnv* env,
+                                      jstring j_histogram_name,
+                                      jint j_histogram_key,
+                                      jint j_min,
+                                      jint j_max,
+                                      jint j_num_buckets) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    int64 min = static_cast<int64>(j_min);
+    int64 max = static_cast<int64>(j_max);
+    int num_buckets = static_cast<int>(j_num_buckets);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    if (histogram) {
+      DCHECK(histogram->HasConstructionArguments(min, max, num_buckets));
+      return histogram;
+    }
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram =
+        Histogram::FactoryGet(histogram_name, min, max, num_buckets,
+                              HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* SparseHistogram(JNIEnv* env,
+                                 jstring j_histogram_name,
+                                 jint j_histogram_key) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    if (histogram)
+      return histogram;
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram = SparseHistogram::FactoryGet(
+        histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* CustomTimesHistogram(JNIEnv* env,
+                                      jstring j_histogram_name,
+                                      jint j_histogram_key,
+                                      jlong j_min,
+                                      jlong j_max,
+                                      jint j_bucket_count) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    int64 min = static_cast<int64>(j_min);
+    int64 max = static_cast<int64>(j_max);
+    int bucket_count = static_cast<int>(j_bucket_count);
+    if (histogram) {
+      DCHECK(histogram->HasConstructionArguments(min, max, bucket_count));
+      return histogram;
+    }
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
+    // is just a convenience for constructing the underlying Histogram with
+    // TimeDelta arguments.
+    histogram = Histogram::FactoryGet(histogram_name, min, max, bucket_count,
+                                      HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+ private:
+  HistogramBase* FindLocked(jint j_histogram_key) {
+    base::AutoLock locked(lock_);
+    auto histogram_it = histograms_.find(j_histogram_key);
+    return histogram_it != histograms_.end() ? histogram_it->second : nullptr;
+  }
+
+  HistogramBase* InsertLocked(jint j_histogram_key, HistogramBase* histogram) {
+    base::AutoLock locked(lock_);
+    histograms_.insert(std::make_pair(j_histogram_key, histogram));
+    return histogram;
+  }
+
+  base::Lock lock_;
+  std::map<jint, HistogramBase*> histograms_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramCache);
+};
+
+base::LazyInstance<HistogramCache>::Leaky g_histograms;
+
+}  // namespace
+
+void RecordBooleanHistogram(JNIEnv* env,
+                            jclass clazz,
+                            jstring j_histogram_name,
+                            jint j_histogram_key,
+                            jboolean j_sample) {
+  bool sample = static_cast<bool>(j_sample);
+  g_histograms.Get()
+      .BooleanHistogram(env, j_histogram_name, j_histogram_key)
+      ->AddBoolean(sample);
+}
+
+void RecordEnumeratedHistogram(JNIEnv* env,
+                               jclass clazz,
+                               jstring j_histogram_name,
+                               jint j_histogram_key,
+                               jint j_sample,
+                               jint j_boundary) {
+  int sample = static_cast<int>(j_sample);
+
+  g_histograms.Get()
+      .EnumeratedHistogram(env, j_histogram_name, j_histogram_key, j_boundary)
+      ->Add(sample);
+}
+
+void RecordCustomCountHistogram(JNIEnv* env,
+                                jclass clazz,
+                                jstring j_histogram_name,
+                                jint j_histogram_key,
+                                jint j_sample,
+                                jint j_min,
+                                jint j_max,
+                                jint j_num_buckets) {
+  int sample = static_cast<int>(j_sample);
+
+  g_histograms.Get()
+      .CustomCountHistogram(env, j_histogram_name, j_histogram_key, j_min,
+                            j_max, j_num_buckets)
+      ->Add(sample);
+}
+
+void RecordSparseHistogram(JNIEnv* env,
+                                 jclass clazz,
+                                 jstring j_histogram_name,
+                                 jint j_histogram_key,
+                                 jint j_sample) {
+    int sample = static_cast<int>(j_sample);
+    g_histograms.Get()
+        .SparseHistogram(env, j_histogram_name, j_histogram_key)
+        ->Add(sample);
+}
+
+void RecordCustomTimesHistogramMilliseconds(JNIEnv* env,
+                                            jclass clazz,
+                                            jstring j_histogram_name,
+                                            jint j_histogram_key,
+                                            jlong j_duration,
+                                            jlong j_min,
+                                            jlong j_max,
+                                            jint j_num_buckets) {
+  g_histograms.Get()
+      .CustomTimesHistogram(env, j_histogram_name, j_histogram_key, j_min,
+                            j_max, j_num_buckets)
+      ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64>(j_duration)));
+}
+
+void Initialize(JNIEnv* env, jclass) {
+  StatisticsRecorder::Initialize();
+}
+
+// This backs a Java test util for testing histograms -
+// MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
+// currently can't have test-specific native code packaged in test-specific Java
+// targets - see http://crbug.com/415945.
+jint GetHistogramValueCountForTesting(JNIEnv* env,
+                                      jclass clazz,
+                                      jstring histogram_name,
+                                      jint sample) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(
+      android::ConvertJavaStringToUTF8(env, histogram_name));
+  if (histogram == nullptr) {
+    // No samples have been recorded for this histogram (yet?).
+    return 0;
+  }
+
+  scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  return samples->GetCount(static_cast<int>(sample));
+}
+
+bool RegisterRecordHistogram(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/record_histogram.h b/base/android/record_histogram.h
new file mode 100644
index 0000000..caa10f0
--- /dev/null
+++ b/base/android/record_histogram.h
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_RECORD_HISTOGRAM_H_
+#define BASE_ANDROID_RECORD_HISTOGRAM_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterRecordHistogram(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_RECORD_HISTOGRAM_H_
diff --git a/base/android/record_user_action.cc b/base/android/record_user_action.cc
new file mode 100644
index 0000000..6172f2e
--- /dev/null
+++ b/base/android/record_user_action.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/record_user_action.h"
+
+#include "base/android/jni_string.h"
+#include "base/metrics/user_metrics.h"
+#include "jni/RecordUserAction_jni.h"
+
+namespace base {
+namespace android {
+
+static void RecordUserAction(JNIEnv* env, jclass clazz, jstring j_action) {
+  RecordComputedAction(ConvertJavaStringToUTF8(env, j_action));
+}
+
+// Register native methods
+bool RegisterRecordUserAction(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/record_user_action.h b/base/android/record_user_action.h
new file mode 100644
index 0000000..2c2b854
--- /dev/null
+++ b/base/android/record_user_action.h
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_RECORD_USER_ACTION_H_
+#define BASE_ANDROID_RECORD_USER_ACTION_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+// Registers the native methods through jni
+bool RegisterRecordUserAction(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_RECORD_USER_ACTION_H_
diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc
new file mode 100644
index 0000000..bb6f503
--- /dev/null
+++ b/base/android/scoped_java_ref.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+namespace {
+
+const int kDefaultLocalFrameCapacity = 16;
+
+}  // namespace
+
+ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env) : env_(env) {
+  int failed = env_->PushLocalFrame(kDefaultLocalFrameCapacity);
+  DCHECK(!failed);
+}
+
+ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env, int capacity)
+    : env_(env) {
+  int failed = env_->PushLocalFrame(capacity);
+  DCHECK(!failed);
+}
+
+ScopedJavaLocalFrame::~ScopedJavaLocalFrame() { env_->PopLocalFrame(NULL); }
+
+JavaRef<jobject>::JavaRef() : obj_(NULL) {}
+
+JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {
+  if (obj) {
+    DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType);
+  }
+}
+
+JavaRef<jobject>::~JavaRef() {
+}
+
+JNIEnv* JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) {
+  if (!env) {
+    env = AttachCurrentThread();
+  } else {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+  }
+  if (obj)
+    obj = env->NewLocalRef(obj);
+  if (obj_)
+    env->DeleteLocalRef(obj_);
+  obj_ = obj;
+  return env;
+}
+
+void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) {
+  if (!env) {
+    env = AttachCurrentThread();
+  } else {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+  }
+  if (obj)
+    obj = env->NewGlobalRef(obj);
+  if (obj_)
+    env->DeleteGlobalRef(obj_);
+  obj_ = obj;
+}
+
+void JavaRef<jobject>::ResetLocalRef(JNIEnv* env) {
+  if (obj_) {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+    env->DeleteLocalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+void JavaRef<jobject>::ResetGlobalRef() {
+  if (obj_) {
+    AttachCurrentThread()->DeleteGlobalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+jobject JavaRef<jobject>::ReleaseInternal() {
+  jobject obj = obj_;
+  obj_ = NULL;
+  return obj;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
new file mode 100644
index 0000000..7863c0b
--- /dev/null
+++ b/base/android/scoped_java_ref.h
@@ -0,0 +1,215 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_
+#define BASE_ANDROID_SCOPED_JAVA_REF_H_
+
+#include <jni.h>
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+// Creates a new local reference frame, in which at least a given number of
+// local references can be created. Note that local references already created
+// in previous local frames are still valid in the current local frame.
+class BASE_EXPORT ScopedJavaLocalFrame {
+ public:
+  explicit ScopedJavaLocalFrame(JNIEnv* env);
+  ScopedJavaLocalFrame(JNIEnv* env, int capacity);
+  ~ScopedJavaLocalFrame();
+
+ private:
+  // This class is only good for use on the thread it was created on so
+  // it's safe to cache the non-threadsafe JNIEnv* inside this object.
+  JNIEnv* env_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedJavaLocalFrame);
+};
+
+// Forward declare the generic java reference template class.
+template<typename T> class JavaRef;
+
+// Template specialization of JavaRef, which acts as the base class for all
+// other JavaRef<> template types. This allows you to e.g. pass
+// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
+template<>
+class BASE_EXPORT JavaRef<jobject> {
+ public:
+  jobject obj() const { return obj_; }
+
+  bool is_null() const { return obj_ == NULL; }
+
+ protected:
+  // Initializes a NULL reference.
+  JavaRef();
+
+  // Takes ownership of the |obj| reference passed; requires it to be a local
+  // reference type.
+  JavaRef(JNIEnv* env, jobject obj);
+
+  ~JavaRef();
+
+  // The following are implementation detail convenience methods, for
+  // use by the sub-classes.
+  JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
+  void SetNewGlobalRef(JNIEnv* env, jobject obj);
+  void ResetLocalRef(JNIEnv* env);
+  void ResetGlobalRef();
+  jobject ReleaseInternal();
+
+ private:
+  jobject obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
+// for allowing functions to accept a reference without having to mandate
+// whether it is a local or global type.
+template<typename T>
+class JavaRef : public JavaRef<jobject> {
+ public:
+  T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
+
+ protected:
+  JavaRef() {}
+  ~JavaRef() {}
+
+  JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Holds a local reference to a Java object. The local reference is scoped
+// to the lifetime of this object.
+// Instances of this class may hold onto any JNIEnv passed into it until
+// destroyed. Therefore, since a JNIEnv is only suitable for use on a single
+// thread, objects of this class must be created, used, and destroyed, on a
+// single thread.
+// Therefore, this class should only be used as a stack-based object and from a
+// single thread. If you wish to have the reference outlive the current
+// callstack (e.g. as a class member) or you wish to pass it across threads,
+// use a ScopedJavaGlobalRef instead.
+template<typename T>
+class ScopedJavaLocalRef : public JavaRef<T> {
+ public:
+  ScopedJavaLocalRef() : env_(NULL) {}
+
+  // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
+  // by value as this is the normal usage pattern.
+  ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other)
+      : env_(other.env_) {
+    this->SetNewLocalRef(env_, other.obj());
+  }
+
+  template<typename U>
+  explicit ScopedJavaLocalRef(const U& other)
+      : env_(NULL) {
+    this->Reset(other);
+  }
+
+  // Assumes that |obj| is a local reference to a Java object and takes
+  // ownership  of this local reference.
+  ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
+
+  ~ScopedJavaLocalRef() {
+    this->Reset();
+  }
+
+  // Overloaded assignment operator defined for consistency with the implicit
+  // copy constructor.
+  void operator=(const ScopedJavaLocalRef<T>& other) {
+    this->Reset(other);
+  }
+
+  void Reset() {
+    this->ResetLocalRef(env_);
+  }
+
+  template<typename U>
+  void Reset(const ScopedJavaLocalRef<U>& other) {
+    // We can copy over env_ here as |other| instance must be from the same
+    // thread as |this| local ref. (See class comment for multi-threading
+    // limitations, and alternatives).
+    this->Reset(other.env_, other.obj());
+  }
+
+  template<typename U>
+  void Reset(const U& other) {
+    // If |env_| was not yet set (is still NULL) it will be attached to the
+    // current thread in SetNewLocalRef().
+    this->Reset(env_, other.obj());
+  }
+
+  template<typename U>
+  void Reset(JNIEnv* env, U obj) {
+    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    env_ = this->SetNewLocalRef(env, obj);
+  }
+
+  // Releases the local reference to the caller. The caller *must* delete the
+  // local reference when it is done with it.
+  T Release() {
+    return static_cast<T>(this->ReleaseInternal());
+  }
+
+ private:
+  // This class is only good for use on the thread it was created on so
+  // it's safe to cache the non-threadsafe JNIEnv* inside this object.
+  JNIEnv* env_;
+};
+
+// Holds a global reference to a Java object. The global reference is scoped
+// to the lifetime of this object. This class does not hold onto any JNIEnv*
+// passed to it, hence it is safe to use across threads (within the constraints
+// imposed by the underlying Java object that it references).
+template<typename T>
+class ScopedJavaGlobalRef : public JavaRef<T> {
+ public:
+  ScopedJavaGlobalRef() {}
+
+  explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
+    this->Reset(other);
+  }
+
+  template<typename U>
+  explicit ScopedJavaGlobalRef(const U& other) {
+    this->Reset(other);
+  }
+
+  ~ScopedJavaGlobalRef() {
+    this->Reset();
+  }
+
+  void Reset() {
+    this->ResetGlobalRef();
+  }
+
+  template<typename U>
+  void Reset(const U& other) {
+    this->Reset(NULL, other.obj());
+  }
+
+  template<typename U>
+  void Reset(JNIEnv* env, U obj) {
+    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    this->SetNewGlobalRef(env, obj);
+  }
+
+  // Releases the global reference to the caller. The caller *must* delete the
+  // global reference when it is done with it.
+  T Release() {
+    return static_cast<T>(this->ReleaseInternal());
+  }
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_SCOPED_JAVA_REF_H_
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc
new file mode 100644
index 0000000..3f4419a
--- /dev/null
+++ b/base/android/scoped_java_ref_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+int g_local_refs = 0;
+int g_global_refs = 0;
+
+const JNINativeInterface* g_previous_functions;
+
+jobject NewGlobalRef(JNIEnv* env, jobject obj) {
+  ++g_global_refs;
+  return g_previous_functions->NewGlobalRef(env, obj);
+}
+
+void DeleteGlobalRef(JNIEnv* env, jobject obj) {
+  --g_global_refs;
+  return g_previous_functions->DeleteGlobalRef(env, obj);
+}
+
+jobject NewLocalRef(JNIEnv* env, jobject obj) {
+  ++g_local_refs;
+  return g_previous_functions->NewLocalRef(env, obj);
+}
+
+void DeleteLocalRef(JNIEnv* env, jobject obj) {
+  --g_local_refs;
+  return g_previous_functions->DeleteLocalRef(env, obj);
+}
+}  // namespace
+
+class ScopedJavaRefTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    g_local_refs = 0;
+    g_global_refs = 0;
+    JNIEnv* env = AttachCurrentThread();
+    g_previous_functions = env->functions;
+    hooked_functions = *g_previous_functions;
+    env->functions = &hooked_functions;
+    // We inject our own functions in JNINativeInterface so we can keep track
+    // of the reference counting ourselves.
+    hooked_functions.NewGlobalRef = &NewGlobalRef;
+    hooked_functions.DeleteGlobalRef = &DeleteGlobalRef;
+    hooked_functions.NewLocalRef = &NewLocalRef;
+    hooked_functions.DeleteLocalRef = &DeleteLocalRef;
+  }
+
+  void TearDown() override {
+    JNIEnv* env = AttachCurrentThread();
+    env->functions = g_previous_functions;
+  }
+  // From JellyBean release, the instance of this struct provided in JNIEnv is
+  // read-only, so we deep copy it to allow individual functions to be hooked.
+  JNINativeInterface hooked_functions;
+};
+
+// The main purpose of this is testing the various conversions compile.
+TEST_F(ScopedJavaRefTest, Conversions) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
+  ScopedJavaGlobalRef<jstring> global(str);
+  {
+    ScopedJavaGlobalRef<jobject> global_obj(str);
+    ScopedJavaLocalRef<jobject> local_obj(global);
+    const JavaRef<jobject>& obj_ref1(str);
+    const JavaRef<jobject>& obj_ref2(global);
+    EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj()));
+    EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj()));
+  }
+  global.Reset(str);
+  const JavaRef<jstring>& str_ref = str;
+  EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
+  str.Reset();
+}
+
+TEST_F(ScopedJavaRefTest, RefCounts) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> str;
+  // The ConvertJavaStringToUTF8 below creates a new string that would normally
+  // return a local ref. We simulate that by starting the g_local_refs count at
+  // 1.
+  g_local_refs = 1;
+  str.Reset(ConvertUTF8ToJavaString(env, "string"));
+  EXPECT_EQ(1, g_local_refs);
+  EXPECT_EQ(0, g_global_refs);
+  {
+    ScopedJavaGlobalRef<jstring> global_str(str);
+    ScopedJavaGlobalRef<jobject> global_obj(global_str);
+    EXPECT_EQ(1, g_local_refs);
+    EXPECT_EQ(2, g_global_refs);
+
+    ScopedJavaLocalRef<jstring> str2(env, str.Release());
+    EXPECT_EQ(1, g_local_refs);
+    {
+      ScopedJavaLocalRef<jstring> str3(str2);
+      EXPECT_EQ(2, g_local_refs);
+    }
+    EXPECT_EQ(1, g_local_refs);
+    str2.Reset();
+    EXPECT_EQ(0, g_local_refs);
+    global_str.Reset();
+    EXPECT_EQ(1, g_global_refs);
+    ScopedJavaGlobalRef<jobject> global_obj2(global_obj);
+    EXPECT_EQ(2, g_global_refs);
+  }
+
+  EXPECT_EQ(0, g_local_refs);
+  EXPECT_EQ(0, g_global_refs);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc
new file mode 100644
index 0000000..e89c1b3
--- /dev/null
+++ b/base/android/sys_utils.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/sys_utils.h"
+
+#include "base/android/build_info.h"
+#include "base/sys_info.h"
+#include "jni/SysUtils_jni.h"
+
+namespace base {
+namespace android {
+
+bool SysUtils::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+bool SysUtils::IsLowEndDeviceFromJni() {
+  JNIEnv* env = AttachCurrentThread();
+  return Java_SysUtils_isLowEndDevice(env);
+}
+
+}  // namespace android
+
+}  // namespace base
\ No newline at end of file
diff --git a/base/android/sys_utils.h b/base/android/sys_utils.h
new file mode 100644
index 0000000..85dc035
--- /dev/null
+++ b/base/android/sys_utils.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_SYS_UTILS_H_
+#define BASE_ANDROID_SYS_UTILS_H_
+
+#include "base/android/jni_android.h"
+
+namespace base {
+namespace android {
+
+class BASE_EXPORT SysUtils {
+ public:
+  static bool Register(JNIEnv* env);
+
+  // Returns true iff this is a low-end device.
+  static bool IsLowEndDeviceFromJni();
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_SYS_UTILS_H_
diff --git a/base/android/sys_utils_unittest.cc b/base/android/sys_utils_unittest.cc
new file mode 100644
index 0000000..d1421ec
--- /dev/null
+++ b/base/android/sys_utils_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <unistd.h>
+
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(SysUtils, AmountOfPhysicalMemory) {
+  // Check that the RAM size reported by sysconf() matches the one
+  // computed by base::SysInfo::AmountOfPhysicalMemory().
+  size_t sys_ram_size =
+      static_cast<size_t>(sysconf(_SC_PHYS_PAGES) * PAGE_SIZE);
+  EXPECT_EQ(sys_ram_size,
+            static_cast<size_t>(SysInfo::AmountOfPhysicalMemory()));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/thread_utils.h b/base/android/thread_utils.h
new file mode 100644
index 0000000..cbe65f0
--- /dev/null
+++ b/base/android/thread_utils.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_THREAD_UTILS_H_
+#define BASE_ANDROID_THREAD_UTILS_H_
+
+#include "base/android/jni_android.h"
+
+namespace base {
+
+bool RegisterThreadUtils(JNIEnv* env);
+
+}  // namespace base
+
+#endif  // BASE_ANDROID_THREAD_UTILS_H_
diff --git a/base/android/trace_event_binding.cc b/base/android/trace_event_binding.cc
new file mode 100644
index 0000000..791b67f
--- /dev/null
+++ b/base/android/trace_event_binding.cc
@@ -0,0 +1,148 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/trace_event_binding.h"
+
+#include <jni.h>
+
+#include <set>
+
+#include "base/lazy_instance.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "jni/TraceEvent_jni.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+const char kJavaCategory[] = "Java";
+const char kToplevelCategory[] = "toplevel";
+const char kLooperDispatchMessage[] = "Looper.dispatchMessage";
+
+// Boilerplate for safely converting Java data to TRACE_EVENT data.
+class TraceEventDataConverter {
+ public:
+  TraceEventDataConverter(JNIEnv* env,
+                          jstring jname,
+                          jstring jarg)
+      : env_(env),
+        jname_(jname),
+        jarg_(jarg),
+        name_(env->GetStringUTFChars(jname, NULL)),
+        arg_(jarg ? env->GetStringUTFChars(jarg, NULL) : NULL) {
+  }
+  ~TraceEventDataConverter() {
+    env_->ReleaseStringUTFChars(jname_, name_);
+    if (jarg_)
+      env_->ReleaseStringUTFChars(jarg_, arg_);
+  }
+
+  // Return saves values to pass to TRACE_EVENT macros.
+  const char* name() { return name_; }
+  const char* arg_name() { return arg_ ? "arg" : NULL; }
+  const char* arg() { return arg_; }
+
+ private:
+  JNIEnv* env_;
+  jstring jname_;
+  jstring jarg_;
+  const char* name_;
+  const char* arg_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
+};
+
+class TraceEnabledObserver
+    : public trace_event::TraceLog::EnabledStateObserver {
+  public:
+   void OnTraceLogEnabled() override {
+      JNIEnv* env = base::android::AttachCurrentThread();
+      base::android::Java_TraceEvent_setEnabled(env, true);
+    }
+    void OnTraceLogDisabled() override {
+      JNIEnv* env = base::android::AttachCurrentThread();
+      base::android::Java_TraceEvent_setEnabled(env, false);
+    }
+};
+
+base::LazyInstance<TraceEnabledObserver>::Leaky g_trace_enabled_state_observer_;
+
+}  // namespace
+
+static void RegisterEnabledObserver(JNIEnv* env, jclass clazz) {
+  bool enabled = trace_event::TraceLog::GetInstance()->IsEnabled();
+  base::android::Java_TraceEvent_setEnabled(env, enabled);
+  trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(
+      g_trace_enabled_state_observer_.Pointer());
+}
+
+static void StartATrace(JNIEnv* env, jclass clazz) {
+  base::trace_event::TraceLog::GetInstance()->StartATrace();
+}
+
+static void StopATrace(JNIEnv* env, jclass clazz) {
+  base::trace_event::TraceLog::GetInstance()->StopATrace();
+}
+
+static void Instant(JNIEnv* env, jclass clazz,
+                    jstring jname, jstring jarg) {
+  TraceEventDataConverter converter(env, jname, jarg);
+  if (converter.arg()) {
+    TRACE_EVENT_COPY_INSTANT1(kJavaCategory, converter.name(),
+                              TRACE_EVENT_SCOPE_THREAD,
+                              converter.arg_name(), converter.arg());
+  } else {
+    TRACE_EVENT_COPY_INSTANT0(kJavaCategory, converter.name(),
+                              TRACE_EVENT_SCOPE_THREAD);
+  }
+}
+
+static void Begin(JNIEnv* env, jclass clazz,
+                  jstring jname, jstring jarg) {
+  TraceEventDataConverter converter(env, jname, jarg);
+  if (converter.arg()) {
+    TRACE_EVENT_COPY_BEGIN1(kJavaCategory, converter.name(),
+                       converter.arg_name(), converter.arg());
+  } else {
+    TRACE_EVENT_COPY_BEGIN0(kJavaCategory, converter.name());
+  }
+}
+
+static void End(JNIEnv* env, jclass clazz,
+                jstring jname, jstring jarg) {
+  TraceEventDataConverter converter(env, jname, jarg);
+  if (converter.arg()) {
+    TRACE_EVENT_COPY_END1(kJavaCategory, converter.name(),
+                     converter.arg_name(), converter.arg());
+  } else {
+    TRACE_EVENT_COPY_END0(kJavaCategory, converter.name());
+  }
+}
+
+static void BeginToplevel(JNIEnv* env, jclass clazz) {
+  TRACE_EVENT_BEGIN0(kToplevelCategory, kLooperDispatchMessage);
+}
+
+static void EndToplevel(JNIEnv* env, jclass clazz) {
+  TRACE_EVENT_END0(kToplevelCategory, kLooperDispatchMessage);
+}
+
+static void StartAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+  TraceEventDataConverter converter(env, jname, nullptr);
+  TRACE_EVENT_COPY_ASYNC_BEGIN0(kJavaCategory, converter.name(), jid);
+}
+
+static void FinishAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+  TraceEventDataConverter converter(env, jname, nullptr);
+  TRACE_EVENT_COPY_ASYNC_END0(kJavaCategory, converter.name(), jid);
+}
+
+bool RegisterTraceEvent(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/trace_event_binding.h b/base/android/trace_event_binding.h
new file mode 100644
index 0000000..1c1a60b
--- /dev/null
+++ b/base/android/trace_event_binding.h
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_TRACE_EVENT_BINDING_H_
+#define BASE_ANDROID_TRACE_EVENT_BINDING_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+extern bool RegisterTraceEvent(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_TRACE_EVENT_BINDING_H_
diff --git a/base/async_socket_io_handler.h b/base/async_socket_io_handler.h
new file mode 100644
index 0000000..a22c29d
--- /dev/null
+++ b/base/async_socket_io_handler.h
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ASYNC_SOCKET_IO_HANDLER_H_
+#define BASE_ASYNC_SOCKET_IO_HANDLER_H_
+
+#include "base/message_loop/message_loop.h"
+#include "base/sync_socket.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace base {
+
+// Extends the CancelableSyncSocket class to allow reading from a socket
+// asynchronously on a TYPE_IO message loop thread.  This makes it easy to share
+// a thread that uses a message loop (e.g. for IPC and other things) and not
+// require a separate thread to read from the socket.
+//
+// Example usage (also see the unit tests):
+//
+// class SocketReader {
+//  public:
+//   SocketReader(base::CancelableSyncSocket* socket)
+//       : socket_(socket), buffer_() {
+//     io_handler.Initialize(socket_->handle(),
+//                           base::Bind(&SocketReader::OnDataAvailable,
+//                                      base::Unretained(this));
+//   }
+//
+//   void AsyncRead() {
+//     CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
+//   }
+//
+//  private:
+//   void OnDataAvailable(int bytes_read) {
+//     if (ProcessData(&buffer_[0], bytes_read)) {
+//       // Issue another read.
+//       CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
+//     }
+//   }
+//
+//   base::AsyncSocketIoHandler io_handler;
+//   base::CancelableSyncSocket* socket_;
+//   char buffer_[kBufferSize];
+// };
+//
+class BASE_EXPORT AsyncSocketIoHandler
+    : public NON_EXPORTED_BASE(base::NonThreadSafe),
+// The message loop callback interface is different based on platforms.
+#if defined(OS_WIN)
+      public NON_EXPORTED_BASE(base::MessageLoopForIO::IOHandler) {
+#else
+      public NON_EXPORTED_BASE(base::MessageLoopForIO::Watcher) {
+#endif
+ public:
+  AsyncSocketIoHandler();
+  ~AsyncSocketIoHandler() override;
+
+  // Type definition for the callback. The parameter tells how many
+  // bytes were read and is 0 if an error occurred.
+  typedef base::Callback<void(int)> ReadCompleteCallback;
+
+  // Initializes the AsyncSocketIoHandler by hooking it up to the current
+  // thread's message loop (must be TYPE_IO), to do async reads from the socket
+  // on the current thread.  The |callback| will be invoked whenever a Read()
+  // has completed.
+  bool Initialize(base::SyncSocket::Handle socket,
+                  const ReadCompleteCallback& callback);
+
+  // Attempts to read from the socket.  The return value will be |false|
+  // if an error occurred and |true| if data was read or a pending read
+  // was issued.  Regardless of async or sync operation, the
+  // ReadCompleteCallback (see above) will be called when data is available.
+  bool Read(char* buffer, int buffer_len);
+
+ private:
+#if defined(OS_WIN)
+  // Implementation of IOHandler on Windows.
+  void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
+                     DWORD bytes_transfered,
+                     DWORD error) override;
+#elif defined(OS_POSIX)
+  // Implementation of base::MessageLoopForIO::Watcher.
+  void OnFileCanWriteWithoutBlocking(int socket) override {}
+  void OnFileCanReadWithoutBlocking(int socket) override;
+
+  void EnsureWatchingSocket();
+#endif
+
+  base::SyncSocket::Handle socket_;
+#if defined(OS_WIN)
+  base::MessageLoopForIO::IOContext* context_;
+  bool is_pending_;
+#elif defined(OS_POSIX)
+  base::MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
+  // |pending_buffer_| and |pending_buffer_len_| are valid only between
+  // Read() and OnFileCanReadWithoutBlocking().
+  char* pending_buffer_;
+  int pending_buffer_len_;
+  // |true| iff the message loop is watching the socket for IO events.
+  bool is_watching_;
+#endif
+  ReadCompleteCallback read_complete_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncSocketIoHandler);
+};
+
+}  // namespace base.
+
+#endif  // BASE_ASYNC_SOCKET_IO_HANDLER_H_
diff --git a/base/async_socket_io_handler_posix.cc b/base/async_socket_io_handler_posix.cc
new file mode 100644
index 0000000..2fffb84
--- /dev/null
+++ b/base/async_socket_io_handler_posix.cc
@@ -0,0 +1,98 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/async_socket_io_handler.h"
+
+#include <fcntl.h>
+
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+AsyncSocketIoHandler::AsyncSocketIoHandler()
+    : socket_(base::SyncSocket::kInvalidHandle),
+      pending_buffer_(NULL),
+      pending_buffer_len_(0),
+      is_watching_(false) {
+}
+
+AsyncSocketIoHandler::~AsyncSocketIoHandler() {
+  DCHECK(CalledOnValidThread());
+}
+
+void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(socket, socket_);
+  DCHECK(!read_complete_.is_null());
+
+  if (pending_buffer_) {
+    int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
+                                       pending_buffer_len_));
+    DCHECK_GE(bytes_read, 0);
+    pending_buffer_ = NULL;
+    pending_buffer_len_ = 0;
+    read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
+  } else {
+    // We're getting notifications that we can read from the socket while
+    // we're not waiting for data.  In order to not starve the message loop,
+    // let's stop watching the fd and restart the watch when Read() is called.
+    is_watching_ = false;
+    socket_watcher_.StopWatchingFileDescriptor();
+  }
+}
+
+bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!read_complete_.is_null());
+  DCHECK(!pending_buffer_);
+
+  EnsureWatchingSocket();
+
+  int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
+  if (bytes_read < 0) {
+    if (errno == EAGAIN) {
+      pending_buffer_ = buffer;
+      pending_buffer_len_ = buffer_len;
+    } else {
+      NOTREACHED() << "read(): " << errno;
+      return false;
+    }
+  } else {
+    read_complete_.Run(bytes_read);
+  }
+  return true;
+}
+
+bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
+                                      const ReadCompleteCallback& callback) {
+  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
+
+  DetachFromThread();
+
+  socket_ = socket;
+  read_complete_ = callback;
+
+  // SyncSocket is blocking by default, so let's convert it to non-blocking.
+  int value = fcntl(socket, F_GETFL);
+  if (!(value & O_NONBLOCK)) {
+    // Set the socket to be non-blocking so we can do async reads.
+    if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void AsyncSocketIoHandler::EnsureWatchingSocket() {
+  DCHECK(CalledOnValidThread());
+  if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
+    is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
+        socket_, true, base::MessageLoopForIO::WATCH_READ,
+        &socket_watcher_, this);
+  }
+}
+
+}  // namespace base.
diff --git a/base/async_socket_io_handler_unittest.cc b/base/async_socket_io_handler_unittest.cc
new file mode 100644
index 0000000..721de9c
--- /dev/null
+++ b/base/async_socket_io_handler_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/async_socket_io_handler.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kAsyncSocketIoTestString[] = "Hello, AsyncSocketIoHandler";
+const size_t kAsyncSocketIoTestStringLength =
+    arraysize(kAsyncSocketIoTestString);
+
+class TestSocketReader {
+ public:
+  // Set |number_of_reads_before_quit| to >0 when you expect a specific number
+  // of Read operations to complete.  Once that number is reached, the current
+  // message loop will be Quit().  Set |number_of_reads_before_quit| to -1 if
+  // callbacks should not be counted.
+  TestSocketReader(base::CancelableSyncSocket* socket,
+                   int number_of_reads_before_quit,
+                   bool issue_reads_from_callback,
+                   bool expect_eof)
+      : socket_(socket), buffer_(),
+        number_of_reads_before_quit_(number_of_reads_before_quit),
+        callbacks_received_(0),
+        issue_reads_from_callback_(issue_reads_from_callback),
+        expect_eof_(expect_eof) {
+    io_handler.Initialize(socket_->handle(),
+                          base::Bind(&TestSocketReader::OnRead,
+                                     base::Unretained(this)));
+  }
+  ~TestSocketReader() {}
+
+  bool IssueRead() {
+    return io_handler.Read(&buffer_[0], sizeof(buffer_));
+  }
+
+  const char* buffer() const { return &buffer_[0]; }
+
+  int callbacks_received() const { return callbacks_received_; }
+
+ private:
+  void OnRead(int bytes_read) {
+    if (!expect_eof_) {
+      EXPECT_GT(bytes_read, 0);
+    } else {
+      EXPECT_GE(bytes_read, 0);
+    }
+    ++callbacks_received_;
+    if (number_of_reads_before_quit_ == callbacks_received_) {
+      base::MessageLoop::current()->Quit();
+    } else if (issue_reads_from_callback_) {
+      IssueRead();
+    }
+  }
+
+  base::AsyncSocketIoHandler io_handler;
+  base::CancelableSyncSocket* socket_;  // Ownership lies outside the class.
+  char buffer_[kAsyncSocketIoTestStringLength];
+  int number_of_reads_before_quit_;
+  int callbacks_received_;
+  bool issue_reads_from_callback_;
+  bool expect_eof_;
+};
+
+// Workaround to be able to use a base::Closure for sending data.
+// Send() returns int but a closure must return void.
+void SendData(base::CancelableSyncSocket* socket,
+              const void* buffer,
+              size_t length) {
+  socket->Send(buffer, length);
+}
+
+}  // end namespace.
+
+// Tests doing a pending read from a socket and use an IO handler to get
+// notified of data.
+TEST(AsyncSocketIoHandlerTest, AsynchronousReadWithMessageLoop) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  TestSocketReader reader(&pair[0], 1, false, false);
+  EXPECT_TRUE(reader.IssueRead());
+
+  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
+  EXPECT_EQ(1, reader.callbacks_received());
+}
+
+// Tests doing a read from a socket when we know that there is data in the
+// socket.  Here we want to make sure that any async 'can read' notifications
+// won't trip us off and that the synchronous case works as well.
+TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  TestSocketReader reader(&pair[0], -1, false, false);
+
+  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100));
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(reader.IssueRead());
+  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
+  // We've now verified that the read happened synchronously, but it's not
+  // guaranteed that the callback has been issued since the callback will be
+  // called asynchronously even though the read may have been done.
+  // So we call RunUntilIdle() to allow any event notifications or APC's on
+  // Windows, to execute before checking the count of how many callbacks we've
+  // received.
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(1, reader.callbacks_received());
+}
+
+// Calls Read() from within a callback to test that simple read "loops" work.
+TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  const int kReadOperationCount = 10;
+  TestSocketReader reader(&pair[0], kReadOperationCount, true, false);
+  EXPECT_TRUE(reader.IssueRead());
+
+  // Issue sends on an interval to satisfy the Read() requirements.
+  int64 milliseconds = 0;
+  for (int i = 0; i < kReadOperationCount; ++i) {
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
+                              kAsyncSocketIoTestStringLength),
+        base::TimeDelta::FromMilliseconds(milliseconds));
+    milliseconds += 10;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100 + milliseconds));
+
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
+}
+
+// Calls Read() then close other end, check that a correct callback is received.
+TEST(AsyncSocketIoHandlerTest, ReadThenClose) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  const int kReadOperationCount = 1;
+  TestSocketReader reader(&pair[0], kReadOperationCount, false, true);
+  EXPECT_TRUE(reader.IssueRead());
+
+  pair[1].Close();
+
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
+}
diff --git a/base/async_socket_io_handler_win.cc b/base/async_socket_io_handler_win.cc
new file mode 100644
index 0000000..e1d215c
--- /dev/null
+++ b/base/async_socket_io_handler_win.cc
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/async_socket_io_handler.h"
+
+namespace base {
+
+AsyncSocketIoHandler::AsyncSocketIoHandler()
+    : socket_(base::SyncSocket::kInvalidHandle),
+      context_(NULL),
+      is_pending_(false) {}
+
+AsyncSocketIoHandler::~AsyncSocketIoHandler() {
+  // We need to be deleted on the correct thread to avoid racing with the
+  // message loop thread.
+  DCHECK(CalledOnValidThread());
+
+  if (context_) {
+    if (is_pending_) {
+      // Make the context be deleted by the message pump when done.
+      context_->handler = NULL;
+    } else {
+      delete context_;
+    }
+  }
+}
+
+// Implementation of IOHandler on Windows.
+void AsyncSocketIoHandler::OnIOCompleted(
+    base::MessageLoopForIO::IOContext* context,
+    DWORD bytes_transfered,
+    DWORD error) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(context_, context);
+  DCHECK(!read_complete_.is_null());
+  is_pending_ = false;
+  read_complete_.Run(error == ERROR_SUCCESS ? bytes_transfered : 0);
+}
+
+bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!read_complete_.is_null());
+  DCHECK(!is_pending_);
+  DCHECK_NE(socket_, base::SyncSocket::kInvalidHandle);
+
+  DWORD bytes_read = 0;
+  BOOL ok = ::ReadFile(socket_, buffer, buffer_len, &bytes_read,
+                       &context_->overlapped);
+  // The completion port will be signaled regardless of completing the read
+  // straight away or asynchronously (ERROR_IO_PENDING). OnIOCompleted() will
+  // be called regardless and we don't need to explicitly run the callback
+  // in the case where ok is FALSE and GLE==ERROR_IO_PENDING.
+  is_pending_ = !ok && (GetLastError() == ERROR_IO_PENDING);
+  return ok || is_pending_;
+}
+
+bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
+                                      const ReadCompleteCallback& callback) {
+  DCHECK(!context_);
+  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
+
+  DetachFromThread();
+
+  socket_ = socket;
+  read_complete_ = callback;
+
+  base::MessageLoopForIO::current()->RegisterIOHandler(socket, this);
+
+  context_ = new base::MessageLoopForIO::IOContext();
+  context_->handler = this;
+  memset(&context_->overlapped, 0, sizeof(context_->overlapped));
+
+  return true;
+}
+
+}  // namespace base.
diff --git a/base/at_exit.cc b/base/at_exit.cc
new file mode 100644
index 0000000..0fba355
--- /dev/null
+++ b/base/at_exit.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+
+#include <stddef.h>
+#include <ostream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Keep a stack of registered AtExitManagers.  We always operate on the most
+// recent, and we should never have more than one outside of testing (for a
+// statically linked version of this library).  Testing may use the shadow
+// version of the constructor, and if we are building a dynamic library we may
+// end up with multiple AtExitManagers on the same process.  We don't protect
+// this for thread-safe access, since it will only be modified in testing.
+static AtExitManager* g_top_manager = NULL;
+
+AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
+// If multiple modules instantiate AtExitManagers they'll end up living in this
+// module... they have to coexist.
+#if !defined(COMPONENT_BUILD)
+  DCHECK(!g_top_manager);
+#endif
+  g_top_manager = this;
+}
+
+AtExitManager::~AtExitManager() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
+    return;
+  }
+  DCHECK_EQ(this, g_top_manager);
+
+  ProcessCallbacksNow();
+  g_top_manager = next_manager_;
+}
+
+// static
+void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
+  DCHECK(func);
+  RegisterTask(base::Bind(func, param));
+}
+
+// static
+void AtExitManager::RegisterTask(base::Closure task) {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
+    return;
+  }
+
+  AutoLock lock(g_top_manager->lock_);
+  g_top_manager->stack_.push(task);
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+    return;
+  }
+
+  AutoLock lock(g_top_manager->lock_);
+
+  while (!g_top_manager->stack_.empty()) {
+    base::Closure task = g_top_manager->stack_.top();
+    task.Run();
+    g_top_manager->stack_.pop();
+  }
+}
+
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
+  DCHECK(shadow || !g_top_manager);
+  g_top_manager = this;
+}
+
+}  // namespace base
diff --git a/base/at_exit.h b/base/at_exit.h
new file mode 100644
index 0000000..6fe7361
--- /dev/null
+++ b/base/at_exit.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include <stack>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+//    base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class BASE_EXPORT AtExitManager {
+ public:
+  typedef void (*AtExitCallbackType)(void*);
+
+  AtExitManager();
+
+  // The dtor calls all the registered callbacks. Do not try to register more
+  // callbacks after this point.
+  ~AtExitManager();
+
+  // Registers the specified function to be called at exit. The prototype of
+  // the callback function is void func(void*).
+  static void RegisterCallback(AtExitCallbackType func, void* param);
+
+  // Registers the specified task to be called at exit.
+  static void RegisterTask(base::Closure task);
+
+  // Calls the functions registered with RegisterCallback in LIFO order. It
+  // is possible to register new callbacks after calling this function.
+  static void ProcessCallbacksNow();
+
+ protected:
+  // This constructor will allow this instance of AtExitManager to be created
+  // even if one already exists.  This should only be used for testing!
+  // AtExitManagers are kept on a global stack, and it will be removed during
+  // destruction.  This allows you to shadow another AtExitManager.
+  explicit AtExitManager(bool shadow);
+
+ private:
+  base::Lock lock_;
+  std::stack<base::Closure> stack_;
+  AtExitManager* next_manager_;  // Stack of managers to allow shadowing.
+
+  DISALLOW_COPY_AND_ASSIGN(AtExitManager);
+};
+
+#if defined(UNIT_TEST)
+class ShadowingAtExitManager : public AtExitManager {
+ public:
+  ShadowingAtExitManager() : AtExitManager(true) {}
+};
+#endif  // defined(UNIT_TEST)
+
+}  // namespace base
+
+#endif  // BASE_AT_EXIT_H_
diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc
new file mode 100644
index 0000000..cda7340
--- /dev/null
+++ b/base/at_exit_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int g_test_counter_1 = 0;
+int g_test_counter_2 = 0;
+
+void IncrementTestCounter1(void* unused) {
+  ++g_test_counter_1;
+}
+
+void IncrementTestCounter2(void* unused) {
+  ++g_test_counter_2;
+}
+
+void ZeroTestCounters() {
+  g_test_counter_1 = 0;
+  g_test_counter_2 = 0;
+}
+
+void ExpectCounter1IsZero(void* unused) {
+  EXPECT_EQ(0, g_test_counter_1);
+}
+
+void ExpectParamIsNull(void* param) {
+  EXPECT_EQ(static_cast<void*>(NULL), param);
+}
+
+void ExpectParamIsCounter(void* param) {
+  EXPECT_EQ(&g_test_counter_1, param);
+}
+
+}  // namespace
+
+class AtExitTest : public testing::Test {
+ private:
+  // Don't test the global AtExitManager, because asking it to process its
+  // AtExit callbacks can ruin the global state that other tests may depend on.
+  base::ShadowingAtExitManager exit_manager_;
+};
+
+TEST_F(AtExitTest, Basic) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+
+  EXPECT_EQ(0, g_test_counter_1);
+  EXPECT_EQ(0, g_test_counter_2);
+  base::AtExitManager::ProcessCallbacksNow();
+  EXPECT_EQ(2, g_test_counter_1);
+  EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, LIFOOrder) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+  base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+
+  EXPECT_EQ(0, g_test_counter_1);
+  EXPECT_EQ(0, g_test_counter_2);
+  base::AtExitManager::ProcessCallbacksNow();
+  EXPECT_EQ(1, g_test_counter_1);
+  EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, Param) {
+  base::AtExitManager::RegisterCallback(&ExpectParamIsNull, NULL);
+  base::AtExitManager::RegisterCallback(&ExpectParamIsCounter,
+                                        &g_test_counter_1);
+  base::AtExitManager::ProcessCallbacksNow();
+}
+
+TEST_F(AtExitTest, Task) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter,
+                                               &g_test_counter_1));
+  base::AtExitManager::ProcessCallbacksNow();
+}
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
new file mode 100644
index 0000000..2ab7242
--- /dev/null
+++ b/base/atomic_ref_count.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a low level implementation of atomic semantics for reference
+// counting.  Please use base/memory/ref_counted.h directly instead.
+
+#ifndef BASE_ATOMIC_REF_COUNT_H_
+#define BASE_ATOMIC_REF_COUNT_H_
+
+#include "base/atomicops.h"
+
+namespace base {
+
+typedef subtle::Atomic32 AtomicRefCount;
+
+// Increment a reference count by "increment", which must exceed 0.
+inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
+                               AtomicRefCount increment) {
+  subtle::NoBarrier_AtomicIncrement(ptr, increment);
+}
+
+// Decrement a reference count by "decrement", which must exceed 0,
+// and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
+                               AtomicRefCount decrement) {
+  bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
+  return res;
+}
+
+// Increment a reference count by 1.
+inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
+  base::AtomicRefCountIncN(ptr, 1);
+}
+
+// Decrement a reference count by 1 and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
+  return base::AtomicRefCountDecN(ptr, 1);
+}
+
+// Return whether the reference count is one.  If the reference count is used
+// in the conventional way, a refrerence count of 1 implies that the current
+// thread owns the reference and no other thread shares it.  This call performs
+// the test for a reference count of one, and performs the memory barrier
+// needed for the owning thread to act on the object, knowing that it has
+// exclusive access to the object.
+inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
+  bool res = (subtle::Acquire_Load(ptr) == 1);
+  return res;
+}
+
+// Return whether the reference count is zero.  With conventional object
+// referencing counting, the object will be destroyed, so the reference count
+// should never be zero.  Hence this is generally used for a debug check.
+inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
+  bool res = (subtle::Acquire_Load(ptr) == 0);
+  return res;
+}
+
+}  // namespace base
+
+#endif  // BASE_ATOMIC_REF_COUNT_H_
diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h
new file mode 100644
index 0000000..7bf2778
--- /dev/null
+++ b/base/atomic_sequence_num.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
+#define BASE_ATOMIC_SEQUENCE_NUM_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class AtomicSequenceNumber;
+
+// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or
+// non-function scope) ONLY. This implementation does not generate any static
+// initializer.  Note that it does not implement any constructor which means
+// that its fields are not initialized except when it is stored in the global
+// data section (.data in ELF). If you want to allocate an atomic sequence
+// number on the stack (or heap), please use the AtomicSequenceNumber class
+// declared below.
+class StaticAtomicSequenceNumber {
+ public:
+  inline int GetNext() {
+    return static_cast<int>(
+        base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
+  }
+
+ private:
+  friend class AtomicSequenceNumber;
+
+  inline void Reset() {
+    base::subtle::Release_Store(&seq_, 0);
+  }
+
+  base::subtle::Atomic32 seq_;
+};
+
+// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are
+// always initialized as opposed to StaticAtomicSequenceNumber declared above).
+// Please use StaticAtomicSequenceNumber if you want to declare an atomic
+// sequence number in the global scope.
+class AtomicSequenceNumber {
+ public:
+  AtomicSequenceNumber() {
+    seq_.Reset();
+  }
+
+  inline int GetNext() {
+    return seq_.GetNext();
+  }
+
+ private:
+  StaticAtomicSequenceNumber seq_;
+  DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
+};
+
+}  // namespace base
+
+#endif  // BASE_ATOMIC_SEQUENCE_NUM_H_
diff --git a/base/atomicops.h b/base/atomicops.h
new file mode 100644
index 0000000..6a5371c
--- /dev/null
+++ b/base/atomicops.h
@@ -0,0 +1,213 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For atomic operations on reference counts, see atomic_refcount.h.
+// For atomic operations on sequence numbers, see atomic_sequence_num.h.
+
+// The routines exported by this module are subtle.  If you use them, even if
+// you get the code right, it will depend on careful reasoning about atomicity
+// and memory ordering; it will be less readable, and harder to maintain.  If
+// you plan to use these routines, you should have a good reason, such as solid
+// evidence that performance would otherwise suffer, or there being no
+// alternative.  You should assume only properties explicitly guaranteed by the
+// specifications in this file.  You are almost certainly _not_ writing code
+// just for the x86; if you assume x86 semantics, x86 hardware bugs and
+// implementations on other archtectures will cause your code to break.  If you
+// do not know what you are doing, avoid these routines, and use a Mutex.
+//
+// It is incorrect to make direct assignments to/from an atomic variable.
+// You should use one of the Load or Store routines.  The NoBarrier
+// versions are provided when no barriers are needed:
+//   NoBarrier_Store()
+//   NoBarrier_Load()
+// Although there are currently no compiler enforcement, you are encouraged
+// to use these.
+//
+
+#ifndef BASE_ATOMICOPS_H_
+#define BASE_ATOMICOPS_H_
+
+#include <stdint.h>
+
+// Small C++ header which defines implementation specific macros used to
+// identify the STL implementation.
+// - libc++: captures __config for _LIBCPP_VERSION
+// - libstdc++: captures bits/c++config.h for __GLIBCXX__
+#include <cstddef>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+namespace base {
+namespace subtle {
+
+typedef int32_t Atomic32;
+#ifdef ARCH_CPU_64_BITS
+// We need to be able to go between Atomic64 and AtomicWord implicitly.  This
+// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(__ILP32__) || defined(OS_NACL)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+typedef int64_t Atomic64;
+#else
+typedef intptr_t Atomic64;
+#endif
+#endif
+
+// Use AtomicWord for a machine-sized pointer.  It will use the Atomic32 or
+// Atomic64 routines below, depending on your architecture.
+typedef intptr_t AtomicWord;
+
+// Atomically execute:
+//      result = *ptr;
+//      if (*ptr == old_value)
+//        *ptr = new_value;
+//      return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                  Atomic32 old_value,
+                                  Atomic32 new_value);
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                 Atomic32 increment);
+
+// These following lower-level operations are typically useful only to people
+// implementing higher-level synchronization operations like spinlocks,
+// mutexes, and condition-variables.  They combine CompareAndSwap(), a load, or
+// a store with appropriate memory-ordering instructions.  "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                Atomic32 old_value,
+                                Atomic32 new_value);
+Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                Atomic32 old_value,
+                                Atomic32 new_value);
+
+void MemoryBarrier();
+void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
+void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
+void Release_Store(volatile Atomic32* ptr, Atomic32 value);
+
+Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
+Atomic32 Acquire_Load(volatile const Atomic32* ptr);
+Atomic32 Release_Load(volatile const Atomic32* ptr);
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#ifdef ARCH_CPU_64_BITS
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                  Atomic64 old_value,
+                                  Atomic64 new_value);
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
+Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+
+Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                Atomic64 old_value,
+                                Atomic64 new_value);
+Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                Atomic64 old_value,
+                                Atomic64 new_value);
+void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
+void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
+void Release_Store(volatile Atomic64* ptr, Atomic64 value);
+Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
+Atomic64 Acquire_Load(volatile const Atomic64* ptr);
+Atomic64 Release_Load(volatile const Atomic64* ptr);
+#endif  // ARCH_CPU_64_BITS
+
+}  // namespace subtle
+}  // namespace base
+
+// The following x86 CPU features are used in atomicops_internals_x86_gcc.h, but
+// this file is duplicated inside of Chrome: protobuf and tcmalloc rely on the
+// struct being present at link time. Some parts of Chrome can currently use the
+// portable interface whereas others still use GCC one. The include guards are
+// the same as in atomicops_internals_x86_gcc.cc.
+#if defined(__i386__) || defined(__x86_64__)
+// This struct is not part of the public API of this module; clients may not
+// use it.  (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86.  Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+  bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+                            // after acquire compare-and-swap.
+  // The following fields are unused by Chrome's base implementation but are
+  // still used by copies of the same code in other parts of the code base. This
+  // causes an ODR violation, and the other code is likely reading invalid
+  // memory.
+  // TODO(jfb) Delete these fields once the rest of the Chrome code base doesn't
+  //           depend on them.
+  bool has_sse2;            // Processor has SSE2.
+  bool has_cmpxchg16b;      // Processor supports cmpxchg16b instruction.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+    AtomicOps_Internalx86CPUFeatures;
+#endif
+
+// Try to use a portable implementation based on C++11 atomics.
+//
+// Some toolchains support C++11 language features without supporting library
+// features (recent compiler, older STL). Whitelist libstdc++ and libc++ that we
+// know will have <atomic> when compiling C++11.
+#if ((__cplusplus >= 201103L) &&                            \
+     ((defined(__GLIBCXX__) && (__GLIBCXX__ > 20110216)) || \
+      (defined(_LIBCPP_VERSION) && (_LIBCPP_STD_VER >= 11))))
+#  include "base/atomicops_internals_portable.h"
+#else  // Otherwise use a platform specific implementation.
+#  if defined(THREAD_SANITIZER)
+#    error "Thread sanitizer must use the portable atomic operations"
+#  elif (defined(OS_WIN) && defined(COMPILER_MSVC) && \
+         defined(ARCH_CPU_X86_FAMILY))
+#    include "base/atomicops_internals_x86_msvc.h"
+#  elif defined(OS_MACOSX)
+#    include "base/atomicops_internals_mac.h"
+#  elif defined(OS_NACL)
+#    include "base/atomicops_internals_gcc.h"
+#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
+#    include "base/atomicops_internals_arm_gcc.h"
+#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
+#    include "base/atomicops_internals_arm64_gcc.h"
+#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
+#    include "base/atomicops_internals_x86_gcc.h"
+#  elif (defined(COMPILER_GCC) && \
+         (defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)))
+#    include "base/atomicops_internals_mips_gcc.h"
+#  else
+#    error "Atomic operations are not supported on your platform"
+#  endif
+#endif   // Portable / non-portable includes.
+
+// On some platforms we need additional declarations to make
+// AtomicWord compatible with our other Atomic* types.
+#if defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include "base/atomicops_internals_atomicword_compat.h"
+#endif
+
+#endif  // BASE_ATOMICOPS_H_
diff --git a/base/atomicops_internals_arm64_gcc.h b/base/atomicops_internals_arm64_gcc.h
new file mode 100644
index 0000000..ddcfec9
--- /dev/null
+++ b/base/atomicops_internals_arm64_gcc.h
@@ -0,0 +1,307 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+// TODO(rmcilroy): Investigate whether we can use __sync__ intrinsics instead of
+//                 the hand coded assembly without introducing perf regressions.
+// TODO(rmcilroy): Investigate whether we can use acquire / release versions of
+//                 exclusive load / store assembly instructions and do away with
+//                 the barriers.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
+
+#if defined(OS_QNX)
+#include <sys/cpuinline.h>
+#endif
+
+namespace base {
+namespace subtle {
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__ ("dmb ish" ::: "memory");  // NOLINT
+}
+
+// NoBarrier versions of the operation include "memory" in the clobber list.
+// This is not required for direct usage of the NoBarrier versions of the
+// operations. However this is required for correctness when they are used as
+// part of the Acquire or Release versions, to ensure that nothing from outside
+// the call is reordered between the operation and the memory barrier. This does
+// not change the code generated, so has no or minimal impact on the
+// NoBarrier operations.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %w[prev], %[ptr]                 \n\t"  // Load the previous value.
+    "cmp %w[prev], %w[old_value]           \n\t"
+    "bne 1f                                \n\t"
+    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
+    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
+    "1:                                    \n\t"
+    : [prev]"=&r" (prev),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [old_value]"IJr" (old_value),
+      [new_value]"r" (new_value)
+    : "cc", "memory"
+  );  // NOLINT
+
+  return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %w[result], %[ptr]               \n\t"  // Load the previous value.
+    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
+    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [new_value]"r" (new_value)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                       \n\t"
+    "ldxr %w[result], %[ptr]                  \n\t"  // Load the previous value.
+    "add %w[result], %w[result], %w[increment]\n\t"
+    "stxr %w[temp], %w[result], %[ptr]        \n\t"  // Try to store the result.
+    "cbnz %w[temp], 0b                        \n\t"  // Retry on failure.
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [increment]"IJr" (increment)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  MemoryBarrier();
+  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+
+  return result;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+
+  return prev;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+
+  return prev;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  __asm__ __volatile__ (  // NOLINT
+    "stlr %w[value], %[ptr]  \n\t"
+    : [ptr]"=Q" (*ptr)
+    : [value]"r" (value)
+    : "memory"
+  );  // NOLINT
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value;
+
+  __asm__ __volatile__ (  // NOLINT
+    "ldar %w[value], %[ptr]  \n\t"
+    : [value]"=r" (value)
+    : [ptr]"Q" (*ptr)
+    : "memory"
+  );  // NOLINT
+
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+// 64-bit versions of the operations.
+// See the 32-bit versions for comments.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %[prev], %[ptr]                  \n\t"
+    "cmp %[prev], %[old_value]             \n\t"
+    "bne 1f                                \n\t"
+    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
+    "cbnz %w[temp], 0b                     \n\t"
+    "1:                                    \n\t"
+    : [prev]"=&r" (prev),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [old_value]"IJr" (old_value),
+      [new_value]"r" (new_value)
+    : "cc", "memory"
+  );  // NOLINT
+
+  return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %[result], %[ptr]                \n\t"
+    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
+    "cbnz %w[temp], 0b                     \n\t"
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [new_value]"r" (new_value)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                     \n\t"
+    "ldxr %[result], %[ptr]                 \n\t"
+    "add %[result], %[result], %[increment] \n\t"
+    "stxr %w[temp], %[result], %[ptr]       \n\t"
+    "cbnz %w[temp], 0b                      \n\t"
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [increment]"IJr" (increment)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  MemoryBarrier();
+  Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+
+  return result;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+
+  return prev;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  MemoryBarrier();
+  Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+
+  return prev;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  __asm__ __volatile__ (  // NOLINT
+    "stlr %x[value], %[ptr]  \n\t"
+    : [ptr]"=Q" (*ptr)
+    : [value]"r" (value)
+    : "memory"
+  );  // NOLINT
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value;
+
+  __asm__ __volatile__ (  // NOLINT
+    "ldar %x[value], %[ptr]  \n\t"
+    : [value]"=r" (value)
+    : [ptr]"Q" (*ptr)
+    : "memory"
+  );  // NOLINT
+
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h
new file mode 100644
index 0000000..44c91c8
--- /dev/null
+++ b/base/atomicops_internals_arm_gcc.h
@@ -0,0 +1,294 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+
+#if defined(OS_QNX)
+#include <sys/cpuinline.h>
+#endif
+
+namespace base {
+namespace subtle {
+
+// Memory barriers on ARM are funky, but the kernel is here to help:
+//
+// * ARMv5 didn't support SMP, there is no memory barrier instruction at
+//   all on this architecture, or when targeting its machine code.
+//
+// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by
+//   writing a random value to a very specific coprocessor register.
+//
+// * On ARMv7, the "dmb" instruction is used to perform a full memory
+//   barrier (though writing to the co-processor will still work).
+//   However, on single core devices (e.g. Nexus One, or Nexus S),
+//   this instruction will take up to 200 ns, which is huge, even though
+//   it's completely un-needed on these devices.
+//
+// * There is no easy way to determine at runtime if the device is
+//   single or multi-core. However, the kernel provides a useful helper
+//   function at a fixed memory address (0xffff0fa0), which will always
+//   perform a memory barrier in the most efficient way. I.e. on single
+//   core devices, this is an empty function that exits immediately.
+//   On multi-core devices, it implements a full memory barrier.
+//
+// * This source could be compiled to ARMv5 machine code that runs on a
+//   multi-core ARMv6 or ARMv7 device. In this case, memory barriers
+//   are needed for correct execution. Always call the kernel helper, even
+//   when targeting ARMv5TE.
+//
+
+inline void MemoryBarrier() {
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  // Note: This is a function call, which is also an implicit compiler barrier.
+  typedef void (*KernelMemoryBarrierFunc)();
+  ((KernelMemoryBarrierFunc)0xffff0fa0)();
+#elif defined(OS_QNX)
+  __cpu_membarrier();
+#else
+#error MemoryBarrier() is not implemented on this platform.
+#endif
+}
+
+// An ARM toolchain would only define one of these depending on which
+// variant of the target architecture is being used. This tests against
+// any known ARMv6 or ARMv7 variant, where it is possible to directly
+// use ldrex/strex instructions to implement fast atomic operations.
+#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
+    defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \
+    defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+    defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+    defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  int reloop;
+  do {
+    // The following is equivalent to:
+    //
+    //   prev_value = LDREX(ptr)
+    //   reloop = 0
+    //   if (prev_value != old_value)
+    //      reloop = STREX(ptr, new_value)
+    __asm__ __volatile__("    ldrex %0, [%3]\n"
+                         "    mov %1, #0\n"
+                         "    cmp %0, %4\n"
+#ifdef __thumb2__
+                         "    it eq\n"
+#endif
+                         "    strexeq %1, %5, [%3]\n"
+                         : "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr)
+                         : "r"(ptr), "r"(old_value), "r"(new_value)
+                         : "cc", "memory");
+  } while (reloop != 0);
+  return prev_value;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return result;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 value;
+  int reloop;
+  do {
+    // Equivalent to:
+    //
+    //  value = LDREX(ptr)
+    //  value += increment
+    //  reloop = STREX(ptr, value)
+    //
+    __asm__ __volatile__("    ldrex %0, [%3]\n"
+                         "    add %0, %0, %4\n"
+                         "    strex %1, %0, [%3]\n"
+                         : "=&r"(value), "=&r"(reloop), "+m"(*ptr)
+                         : "r"(ptr), "r"(increment)
+                         : "cc", "memory");
+  } while (reloop);
+  return value;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  // TODO(digit): Investigate if it's possible to implement this with
+  // a single MemoryBarrier() operation between the LDREX and STREX.
+  // See http://crbug.com/246514
+  MemoryBarrier();
+  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return result;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  int reloop;
+  do {
+    // old_value = LDREX(ptr)
+    // reloop = STREX(ptr, new_value)
+    __asm__ __volatile__("   ldrex %0, [%3]\n"
+                         "   strex %1, %4, [%3]\n"
+                         : "=&r"(old_value), "=&r"(reloop), "+m"(*ptr)
+                         : "r"(ptr), "r"(new_value)
+                         : "cc", "memory");
+  } while (reloop != 0);
+  return old_value;
+}
+
+// This tests against any known ARMv5 variant.
+#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
+      defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
+
+// The kernel also provides a helper function to perform an atomic
+// compare-and-swap operation at the hard-wired address 0xffff0fc0.
+// On ARMv5, this is implemented by a special code path that the kernel
+// detects and treats specially when thread pre-emption happens.
+// On ARMv6 and higher, it uses LDREX/STREX instructions instead.
+//
+// Note that this always perform a full memory barrier, there is no
+// need to add calls MemoryBarrier() before or after it. It also
+// returns 0 on success, and 1 on exit.
+//
+// Available and reliable since Linux 2.6.24. Both Android and ChromeOS
+// use newer kernel revisions, so this should not be a concern.
+namespace {
+
+inline int LinuxKernelCmpxchg(Atomic32 old_value,
+                              Atomic32 new_value,
+                              volatile Atomic32* ptr) {
+  typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*);
+  return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr);
+}
+
+}  // namespace
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  for (;;) {
+    prev_value = *ptr;
+    if (prev_value != old_value)
+      return prev_value;
+    if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
+      return old_value;
+  }
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (LinuxKernelCmpxchg(old_value, new_value, ptr));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  for (;;) {
+    // Atomic exchange the old value with an incremented one.
+    Atomic32 old_value = *ptr;
+    Atomic32 new_value = old_value + increment;
+    if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) {
+      // The exchange took place as expected.
+      return new_value;
+    }
+    // Otherwise, *ptr changed mid-loop and we need to retry.
+  }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev_value;
+  for (;;) {
+    prev_value = *ptr;
+    if (prev_value != old_value) {
+      // Always ensure acquire semantics.
+      MemoryBarrier();
+      return prev_value;
+    }
+    if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
+      return old_value;
+  }
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  // This could be implemented as:
+  //    MemoryBarrier();
+  //    return NoBarrier_CompareAndSwap();
+  //
+  // But would use 3 barriers per succesful CAS. To save performance,
+  // use Acquire_CompareAndSwap(). Its implementation guarantees that:
+  // - A succesful swap uses only 2 barriers (in the kernel helper).
+  // - An early return due to (prev_value != old_value) performs
+  //   a memory barrier with no store, which is equivalent to the
+  //   generic implementation above.
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#else
+#  error "Your CPU's ARM architecture is not supported yet"
+#endif
+
+// NOTE: Atomicity of the following load and store operations is only
+// guaranteed in case of 32-bit alignement of |ptr| values.
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 0000000..342a6e4
--- /dev/null
+++ b/base/atomicops_internals_atomicword_compat.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+// which in turn means int. On some LP32 platforms, intptr_t is an int, but
+// on others, it's a long. When AtomicWord and Atomic32 are based on different
+// fundamental types, their pointers are incompatible.
+//
+// This file defines function overloads to allow both AtomicWord and Atomic32
+// data to be used with this interface.
+//
+// On LP64 platforms, AtomicWord and Atomic64 are both always long,
+// so this problem doesn't occur.
+
+#if !defined(ARCH_CPU_64_BITS)
+
+namespace base {
+namespace subtle {
+
+inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
+                                           AtomicWord old_value,
+                                           AtomicWord new_value) {
+  return NoBarrier_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
+                                           AtomicWord new_value) {
+  return NoBarrier_AtomicExchange(
+      reinterpret_cast<volatile Atomic32*>(ptr), new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
+                                            AtomicWord increment) {
+  return NoBarrier_AtomicIncrement(
+      reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
+                                          AtomicWord increment) {
+  return Barrier_AtomicIncrement(
+      reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
+                                         AtomicWord old_value,
+                                         AtomicWord new_value) {
+  return base::subtle::Acquire_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
+                                         AtomicWord old_value,
+                                         AtomicWord new_value) {
+  return base::subtle::Release_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
+  NoBarrier_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
+  return base::subtle::Acquire_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
+  return base::subtle::Release_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
+  return NoBarrier_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
+  return base::subtle::Acquire_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
+  return base::subtle::Release_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // !defined(ARCH_CPU_64_BITS)
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/base/atomicops_internals_gcc.h b/base/atomicops_internals_gcc.h
new file mode 100644
index 0000000..35c95fe
--- /dev/null
+++ b/base/atomicops_internals_gcc.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, include base/atomicops.h
+// instead. This file is for platforms that use GCC intrinsics rather than
+// platform-specific assembly code for atomic operations.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_GCC_H_
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (__sync_bool_compare_and_swap(ptr, old_value, new_value))
+      return old_value;
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (!__sync_bool_compare_and_swap(ptr, old_value, new_value));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  for (;;) {
+    // Atomic exchange the old value with an incremented one.
+    Atomic32 old_value = *ptr;
+    Atomic32 new_value = old_value + increment;
+    if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
+      // The exchange took place as expected.
+      return new_value;
+    }
+    // Otherwise, *ptr changed mid-loop and we need to retry.
+  }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  // Since NoBarrier_CompareAndSwap uses __sync_bool_compare_and_swap, which
+  // is a full memory barrier, none is needed here or below in Release.
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_GCC_H_
+
diff --git a/base/atomicops_internals_mac.h b/base/atomicops_internals_mac.h
new file mode 100644
index 0000000..98864a7
--- /dev/null
+++ b/base/atomicops_internals_mac.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MAC_H_
+#define BASE_ATOMICOPS_INTERNALS_MAC_H_
+
+#include <libkern/OSAtomic.h>
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap32(old_value, new_value,
+                                 const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (!OSAtomicCompareAndSwap32(old_value, new_value,
+                                     const_cast<Atomic32*>(ptr)));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline void MemoryBarrier() {
+  OSMemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
+                                        const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#ifdef __LP64__
+
+// 64-bit implementation on 64-bit platform
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap64(old_value, new_value,
+                                 reinterpret_cast<volatile int64_t*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 old_value;
+  do {
+    old_value = *ptr;
+  } while (!OSAtomicCompareAndSwap64(old_value, new_value,
+                                     reinterpret_cast<volatile int64_t*>(ptr)));
+  return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return OSAtomicAdd64Barrier(increment,
+                              reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap64Barrier(
+        old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  // The lib kern interface does not distinguish between
+  // Acquire and Release memory barriers; they are equivalent.
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#endif  // defined(__LP64__)
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/base/atomicops_internals_mips_gcc.h b/base/atomicops_internals_mips_gcc.h
new file mode 100644
index 0000000..b4551b8
--- /dev/null
+++ b/base/atomicops_internals_mips_gcc.h
@@ -0,0 +1,280 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+
+namespace base {
+namespace subtle {
+
+// Atomically execute:
+//      result = *ptr;
+//      if (*ptr == old_value)
+//        *ptr = new_value;
+//      return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev, tmp;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %0, %5\n"  // prev = *ptr
+                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
+                       "move %2, %4\n"  // tmp = new_value
+                       "sc %2, %1\n"  // *ptr = tmp (with atomic check)
+                       "beqz %2, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       "2:\n"
+                       ".set pop\n"
+                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+                       : "r" (old_value), "r" (new_value), "m" (*ptr)
+                       : "memory");
+  return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 temp, old;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %1, %4\n"  // old = *ptr
+                       "move %0, %3\n"  // temp = new_value
+                       "sc %0, %2\n"  // *ptr = temp (with atomic check)
+                       "beqz %0, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+                       : "r" (new_value), "m" (*ptr)
+                       : "memory");
+
+  return old;
+}
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp, temp2;
+
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %0, %4\n"  // temp = *ptr
+                       "addu %1, %0, %3\n"  // temp2 = temp + increment
+                       "sc %1, %2\n"  // *ptr = temp2 (with atomic check)
+                       "beqz %1, 1b\n"  // start again on atomic error
+                       "addu %1, %0, %3\n"  // temp2 = temp + increment
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+                       : "Ir" (increment), "m" (*ptr)
+                       : "memory");
+  // temp2 now holds the final value.
+  return temp2;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  MemoryBarrier();
+  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__("sync" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(__LP64__)
+// 64-bit versions of the atomic ops.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev, tmp;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "lld %0, %5\n"  // prev = *ptr
+                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
+                       "move %2, %4\n"  // tmp = new_value
+                       "scd %2, %1\n"  // *ptr = tmp (with atomic check)
+                       "beqz %2, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       "2:\n"
+                       ".set pop\n"
+                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+                       : "r" (old_value), "r" (new_value), "m" (*ptr)
+                       : "memory");
+  return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 temp, old;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "lld %1, %4\n"  // old = *ptr
+                       "move %0, %3\n"  // temp = new_value
+                       "scd %0, %2\n"  // *ptr = temp (with atomic check)
+                       "beqz %0, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+                       : "r" (new_value), "m" (*ptr)
+                       : "memory");
+
+  return old;
+}
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 temp, temp2;
+
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "lld %0, %4\n"  // temp = *ptr
+                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
+                       "scd %1, %2\n"  // *ptr = temp2 (with atomic check)
+                       "beqz %1, 1b\n"  // start again on atomic error
+                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+                       : "Ir" (increment), "m" (*ptr)
+                       : "memory");
+  // temp2 now holds the final value.
+  return temp2;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  MemoryBarrier();
+  Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+#endif
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/base/atomicops_internals_portable.h b/base/atomicops_internals_portable.h
new file mode 100644
index 0000000..d285610
--- /dev/null
+++ b/base/atomicops_internals_portable.h
@@ -0,0 +1,227 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+//
+// This implementation uses C++11 atomics' member functions. The code base is
+// currently written assuming atomicity revolves around accesses instead of
+// C++11's memory locations. The burden is on the programmer to ensure that all
+// memory locations accessed atomically are never accessed non-atomically (tsan
+// should help with this).
+//
+// TODO(jfb) Modify the atomicops.h API and user code to declare atomic
+//           locations as truly atomic. See the static_assert below.
+//
+// Of note in this implementation:
+//  * All NoBarrier variants are implemented as relaxed.
+//  * All Barrier variants are implemented as sequentially-consistent.
+//  * Compare exchange's failure ordering is always the same as the success one
+//    (except for release, which fails as relaxed): using a weaker ordering is
+//    only valid under certain uses of compare exchange.
+//  * Acquire store doesn't exist in the C11 memory model, it is instead
+//    implemented as a relaxed store followed by a sequentially consistent
+//    fence.
+//  * Release load doesn't exist in the C11 memory model, it is instead
+//    implemented as sequentially consistent fence followed by a relaxed load.
+//  * Atomic increment is expected to return the post-incremented value, whereas
+//    C11 fetch add returns the previous value. The implementation therefore
+//    needs to increment twice (which the compiler should be able to detect and
+//    optimize).
+
+#ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+#define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+
+#include <atomic>
+
+namespace base {
+namespace subtle {
+
+// This implementation is transitional and maintains the original API for
+// atomicops.h. This requires casting memory locations to the atomic types, and
+// assumes that the API and the C++11 implementation are layout-compatible,
+// which isn't true for all implementations or hardware platforms. The static
+// assertion should detect this issue, were it to fire then this header
+// shouldn't be used.
+//
+// TODO(jfb) If this header manages to stay committed then the API should be
+//           modified, and all call sites updated.
+typedef volatile std::atomic<Atomic32>* AtomicLocation32;
+static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
+              "incompatible 32-bit atomic layout");
+
+inline void MemoryBarrier() {
+#if defined(__GLIBCXX__)
+  // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
+  // not defined, leading to the linker complaining about undefined references.
+  __atomic_thread_fence(std::memory_order_seq_cst);
+#else
+  std::atomic_thread_fence(std::memory_order_seq_cst);
+#endif
+}
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_relaxed,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  return ((AtomicLocation32)ptr)
+      ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return increment +
+         ((AtomicLocation32)ptr)
+             ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_acquire,
+                                std::memory_order_acquire);
+  return old_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_release,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+#if defined(ARCH_CPU_64_BITS)
+
+typedef volatile std::atomic<Atomic64>* AtomicLocation64;
+static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
+              "incompatible 64-bit atomic layout");
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_relaxed,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  return ((AtomicLocation64)ptr)
+      ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return increment +
+         ((AtomicLocation64)ptr)
+             ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_acquire,
+                                std::memory_order_acquire);
+  return old_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_release,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+#endif  // defined(ARCH_CPU_64_BITS)
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
new file mode 100644
index 0000000..c21e96d
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module gets enough CPU information to optimize the
+// atomicops module on x86.
+
+#include <stdint.h>
+#include <string.h>
+
+#include "base/atomicops.h"
+
+// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
+// of the global offset table.  To avoid breaking such executables, this code
+// must preserve that register's value across cpuid instructions.
+//
+// The include guards are the same as in atomicops.h.
+#if defined(__i386__)
+#define cpuid(a, b, c, d, inp) \
+  asm("mov %%ebx, %%edi\n"     \
+      "cpuid\n"                \
+      "xchg %%edi, %%ebx\n"    \
+      : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#elif defined(__x86_64__)
+#define cpuid(a, b, c, d, inp) \
+  asm("mov %%rbx, %%rdi\n"     \
+      "cpuid\n"                \
+      "xchg %%rdi, %%rbx\n"    \
+      : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#endif
+
+#if defined(cpuid)        // initialize the struct only on x86
+
+// Set the flags so that code will run correctly and conservatively, so even
+// if we haven't been initialized yet, we're probably single threaded, and our
+// default values should hopefully be pretty safe.
+struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
+  false, // bug can't exist before process spawns multiple threads
+  false, // Chrome requires SSE2, but for transition assume not and initialize
+         // this properly.
+  false, // cmpxchg16b isn't present on early AMD64 CPUs.
+};
+
+namespace {
+
+// Initialize the AtomicOps_Internalx86CPUFeatures struct.
+void AtomicOps_Internalx86CPUFeaturesInit() {
+  uint32_t eax;
+  uint32_t ebx;
+  uint32_t ecx;
+  uint32_t edx;
+
+  // Get vendor string (issue CPUID with eax = 0)
+  cpuid(eax, ebx, ecx, edx, 0);
+  char vendor[13];
+  memcpy(vendor, &ebx, 4);
+  memcpy(vendor + 4, &edx, 4);
+  memcpy(vendor + 8, &ecx, 4);
+  vendor[12] = 0;
+
+  // get feature flags in ecx/edx, and family/model in eax
+  cpuid(eax, ebx, ecx, edx, 1);
+
+  int family = (eax >> 8) & 0xf;        // family and model fields
+  int model = (eax >> 4) & 0xf;
+  if (family == 0xf) {                  // use extended family and model fields
+    family += (eax >> 20) & 0xff;
+    model += ((eax >> 16) & 0xf) << 4;
+  }
+
+  // Opteron Rev E has a bug in which on very rare occasions a locked
+  // instruction doesn't act as a read-acquire barrier if followed by a
+  // non-locked read-modify-write instruction.  Rev F has this bug in
+  // pre-release versions, but not in versions released to customers,
+  // so we test only for Rev E, which is family 15, model 32..63 inclusive.
+  if (strcmp(vendor, "AuthenticAMD") == 0 &&       // AMD
+      family == 15 &&
+      32 <= model && model <= 63) {
+    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
+  } else {
+    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
+  }
+
+  // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
+  AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
+
+  // ecx bit 13 indicates whether the cmpxchg16b instruction is supported
+  AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1);
+}
+
+class AtomicOpsx86Initializer {
+ public:
+  AtomicOpsx86Initializer() {
+    AtomicOps_Internalx86CPUFeaturesInit();
+  }
+};
+
+// A global to get use initialized on startup via static initialization :/
+AtomicOpsx86Initializer g_initer;
+
+}  // namespace
+
+#endif  // if x86
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
new file mode 100644
index 0000000..f0d2242
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.h
@@ -0,0 +1,228 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// 32-bit low-level operations on any platform.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev;
+  __asm__ __volatile__("lock; cmpxchgl %1,%2"
+                       : "=a" (prev)
+                       : "q" (new_value), "m" (*ptr), "0" (old_value)
+                       : "memory");
+  return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
+                       : "=r" (new_value)
+                       : "m" (*ptr), "0" (new_value)
+                       : "memory");
+  return new_value;  // Now it's the previous value.
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp = increment;
+  __asm__ __volatile__("lock; xaddl %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now holds the old value of *ptr
+  return temp + increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  Atomic32 temp = increment;
+  __asm__ __volatile__("lock; xaddl %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now holds the old value of *ptr
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return temp + increment;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__("mfence" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ATOMICOPS_COMPILER_BARRIER();
+  *ptr = value; // An x86 store acts as a release barrier.
+  // See comments in Atomic64 version of Release_Store(), below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
+  // See comments in Atomic64 version of Release_Store(), below.
+  ATOMICOPS_COMPILER_BARRIER();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev;
+  __asm__ __volatile__("lock; cmpxchgq %1,%2"
+                       : "=a" (prev)
+                       : "q" (new_value), "m" (*ptr), "0" (old_value)
+                       : "memory");
+  return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
+                       : "=r" (new_value)
+                       : "m" (*ptr), "0" (new_value)
+                       : "memory");
+  return new_value;  // Now it's the previous value.
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 temp = increment;
+  __asm__ __volatile__("lock; xaddq %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now contains the previous value of *ptr
+  return temp + increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  Atomic64 temp = increment;
+  __asm__ __volatile__("lock; xaddq %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now contains the previous value of *ptr
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return temp + increment;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ATOMICOPS_COMPILER_BARRIER();
+
+  *ptr = value; // An x86 store acts as a release barrier
+                // for current AMD/Intel chips as of Jan 2008.
+                // See also Acquire_Load(), below.
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+  //
+  // x86 stores/loads fail to act as barriers for a few instructions (clflush
+  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
+  // not generated by the compiler, and are rare.  Users of these instructions
+  // need to know about cache behaviour in any case since all of these involve
+  // either flushing cache lines or non-temporal cache hints.
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
+                         // for current AMD/Intel chips as of Jan 2008.
+                         // See also Release_Store(), above.
+  ATOMICOPS_COMPILER_BARRIER();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return x;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif  // defined(__x86_64__)
+
+}  // namespace subtle
+}  // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000..71ddca2
--- /dev/null
+++ b/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+
+#include <windows.h>
+
+#include <intrin.h>
+
+#include "base/macros.h"
+
+#if defined(ARCH_CPU_64_BITS)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  LONG result = _InterlockedCompareExchange(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(new_value),
+      static_cast<LONG>(old_value));
+  return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  LONG result = _InterlockedExchange(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(new_value));
+  return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return _InterlockedExchangeAdd(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(increment)) + increment;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void MemoryBarrier() {
+#if defined(ARCH_CPU_64_BITS)
+  // See #undef and note at the top of this file.
+  __faststorefence();
+#else
+  // We use MemoryBarrier from WinNT.h
+  ::MemoryBarrier();
+#endif
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+  // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedCompareExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return InterlockedExchangeAdd64(
+      reinterpret_cast<volatile LONGLONG*>(ptr),
+      static_cast<LONGLONG>(increment)) + increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif  // defined(_WIN64)
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc
new file mode 100644
index 0000000..3fd5597
--- /dev/null
+++ b/base/atomicops_unittest.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/atomicops.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <class AtomicType>
+static void TestAtomicIncrement() {
+  // For now, we just test single threaded execution
+
+  // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
+  // outside the expected address bounds.  This is in particular to
+  // test that some future change to the asm code doesn't cause the
+  // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit
+  // machines.
+  struct {
+    AtomicType prev_word;
+    AtomicType count;
+    AtomicType next_word;
+  } s;
+
+  AtomicType prev_word_value, next_word_value;
+  memset(&prev_word_value, 0xFF, sizeof(AtomicType));
+  memset(&next_word_value, 0xEE, sizeof(AtomicType));
+
+  s.prev_word = prev_word_value;
+  s.count = 0;
+  s.next_word = next_word_value;
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
+  EXPECT_EQ(s.count, 6);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
+  EXPECT_EQ(s.count, -1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
+  EXPECT_EQ(s.count, -5);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+}
+
+
+#define NUM_BITS(T) (sizeof(T) * 8)
+
+
+template <class AtomicType>
+static void TestCompareAndSwap() {
+  AtomicType value = 0;
+  AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(0, prev);
+
+  // Use test value that has non-zero bits in both halves, more for testing
+  // 64-bit implementation on 32-bit platforms.
+  const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
+                                 (NUM_BITS(AtomicType) - 2)) + 11;
+  value = k_test_val;
+  prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
+  EXPECT_EQ(k_test_val, value);
+  EXPECT_EQ(k_test_val, prev);
+
+  value = k_test_val;
+  prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
+  EXPECT_EQ(5, value);
+  EXPECT_EQ(k_test_val, prev);
+}
+
+
+template <class AtomicType>
+static void TestAtomicExchange() {
+  AtomicType value = 0;
+  AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(0, new_value);
+
+  // Use test value that has non-zero bits in both halves, more for testing
+  // 64-bit implementation on 32-bit platforms.
+  const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
+                                 (NUM_BITS(AtomicType) - 2)) + 11;
+  value = k_test_val;
+  new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
+  EXPECT_EQ(k_test_val, value);
+  EXPECT_EQ(k_test_val, new_value);
+
+  value = k_test_val;
+  new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
+  EXPECT_EQ(5, value);
+  EXPECT_EQ(k_test_val, new_value);
+}
+
+
+template <class AtomicType>
+static void TestAtomicIncrementBounds() {
+  // Test at rollover boundary between int_max and int_min
+  AtomicType test_val = (static_cast<uint64_t>(1) <<
+                         (NUM_BITS(AtomicType) - 1));
+  AtomicType value = -1 ^ test_val;
+  AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+  EXPECT_EQ(test_val, value);
+  EXPECT_EQ(value, new_value);
+
+  base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+  EXPECT_EQ(-1 ^ test_val, value);
+
+  // Test at 32-bit boundary for 64-bit atomic type.
+  test_val = static_cast<uint64_t>(1) << (NUM_BITS(AtomicType) / 2);
+  value = test_val - 1;
+  new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+  EXPECT_EQ(test_val, value);
+  EXPECT_EQ(value, new_value);
+
+  base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+  EXPECT_EQ(test_val - 1, value);
+}
+
+// Return an AtomicType with the value 0xa5a5a5..
+template <class AtomicType>
+static AtomicType TestFillValue() {
+  AtomicType val = 0;
+  memset(&val, 0xa5, sizeof(AtomicType));
+  return val;
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestStore() {
+  const AtomicType kVal1 = TestFillValue<AtomicType>();
+  const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+  AtomicType value;
+
+  base::subtle::NoBarrier_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::NoBarrier_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+
+  base::subtle::Acquire_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::Acquire_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+
+  base::subtle::Release_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::Release_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestLoad() {
+  const AtomicType kVal1 = TestFillValue<AtomicType>();
+  const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+  AtomicType value;
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
+}
+
+TEST(AtomicOpsTest, Inc) {
+  TestAtomicIncrement<base::subtle::Atomic32>();
+  TestAtomicIncrement<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, CompareAndSwap) {
+  TestCompareAndSwap<base::subtle::Atomic32>();
+  TestCompareAndSwap<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Exchange) {
+  TestAtomicExchange<base::subtle::Atomic32>();
+  TestAtomicExchange<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, IncrementBounds) {
+  TestAtomicIncrementBounds<base::subtle::Atomic32>();
+  TestAtomicIncrementBounds<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Store) {
+  TestStore<base::subtle::Atomic32>();
+  TestStore<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Load) {
+  TestLoad<base::subtle::Atomic32>();
+  TestLoad<base::subtle::AtomicWord>();
+}
diff --git a/base/auto_reset.h b/base/auto_reset.h
new file mode 100644
index 0000000..a5bcfaa
--- /dev/null
+++ b/base/auto_reset.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AUTO_RESET_H_
+#define BASE_AUTO_RESET_H_
+
+#include "base/basictypes.h"
+
+// base::AutoReset<> is useful for setting a variable to a new value only within
+// a particular scope. An base::AutoReset<> object resets a variable to its
+// original value upon destruction, making it an alternative to writing
+// "var = false;" or "var = old_val;" at all of a block's exit points.
+//
+// This should be obvious, but note that an base::AutoReset<> instance should
+// have a shorter lifetime than its scoped_variable, to prevent invalid memory
+// writes when the base::AutoReset<> object is destroyed.
+
+namespace base {
+
+template<typename T>
+class AutoReset {
+ public:
+  AutoReset(T* scoped_variable, T new_value)
+      : scoped_variable_(scoped_variable),
+        original_value_(*scoped_variable) {
+    *scoped_variable_ = new_value;
+  }
+
+  ~AutoReset() { *scoped_variable_ = original_value_; }
+
+ private:
+  T* scoped_variable_;
+  T original_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutoReset);
+};
+
+}  // namespace base
+
+#endif  // BASE_AUTO_RESET_H_
diff --git a/base/barrier_closure.cc b/base/barrier_closure.cc
new file mode 100644
index 0000000..1dcc502
--- /dev/null
+++ b/base/barrier_closure.cc
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/barrier_closure.h"
+
+#include "base/atomic_ref_count.h"
+#include "base/bind.h"
+
+namespace {
+
+// Maintains state for a BarrierClosure.
+class BarrierInfo {
+ public:
+  BarrierInfo(int num_callbacks_left, const base::Closure& done_closure);
+  void Run();
+
+ private:
+  base::AtomicRefCount num_callbacks_left_;
+  base::Closure done_closure_;
+};
+
+BarrierInfo::BarrierInfo(int num_callbacks, const base::Closure& done_closure)
+    : num_callbacks_left_(num_callbacks),
+      done_closure_(done_closure) {
+}
+
+void BarrierInfo::Run() {
+  DCHECK(!base::AtomicRefCountIsZero(&num_callbacks_left_));
+  if (!base::AtomicRefCountDec(&num_callbacks_left_)) {
+    base::Closure done_closure = done_closure_;
+    done_closure_.Reset();
+    done_closure.Run();
+  }
+}
+
+}  // namespace
+
+namespace base {
+
+base::Closure BarrierClosure(int num_callbacks_left,
+                             const base::Closure& done_closure) {
+  DCHECK_GE(num_callbacks_left, 0);
+
+  if (num_callbacks_left == 0)
+    done_closure.Run();
+
+  return base::Bind(&BarrierInfo::Run,
+                    base::Owned(
+                        new BarrierInfo(num_callbacks_left, done_closure)));
+}
+
+}  // namespace base
diff --git a/base/barrier_closure.h b/base/barrier_closure.h
new file mode 100644
index 0000000..b1204d8
--- /dev/null
+++ b/base/barrier_closure.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BARRIER_CLOSURE_H_
+#define BASE_BARRIER_CLOSURE_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+
+namespace base {
+
+// BarrierClosure executes |done_closure| after it has been invoked
+// |num_closures| times.
+//
+// If |num_closures| is 0, |done_closure| is executed immediately.
+//
+// BarrierClosure is thread-safe - the count of remaining closures is
+// maintained as a base::AtomicRefCount. |done_closure| will be run on
+// the thread that calls the final Run() on the returned closures.
+//
+// |done_closure| is also Reset() on the final calling thread but due to the
+// refcounted nature of callbacks, it is hard to know what thread resources
+// will be released on.
+BASE_EXPORT base::Closure BarrierClosure(int num_closures,
+                                         const base::Closure& done_closure);
+
+}  // namespace base
+
+#endif  // BASE_BARRIER_CLOSURE_H_
diff --git a/base/barrier_closure_unittest.cc b/base/barrier_closure_unittest.cc
new file mode 100644
index 0000000..dcea09f
--- /dev/null
+++ b/base/barrier_closure_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/barrier_closure.h"
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void Increment(int* count) { (*count)++; }
+
+TEST(BarrierClosureTest, RunImmediatelyForZeroClosures) {
+  int count = 0;
+  base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure barrier_closure = base::BarrierClosure(0, done_closure);
+  EXPECT_EQ(1, count);
+}
+
+TEST(BarrierClosureTest, RunAfterNumClosures) {
+  int count = 0;
+  base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure barrier_closure = base::BarrierClosure(2, done_closure);
+  EXPECT_EQ(0, count);
+
+  barrier_closure.Run();
+  EXPECT_EQ(0, count);
+
+  barrier_closure.Run();
+  EXPECT_EQ(1, count);
+}
+
+class DestructionIndicator {
+ public:
+  // Sets |*destructed| to true in destructor.
+  DestructionIndicator(bool* destructed) : destructed_(destructed) {
+    *destructed_ = false;
+  }
+
+  ~DestructionIndicator() { *destructed_ = true; }
+
+  void DoNothing() {}
+
+ private:
+  bool* destructed_;
+};
+
+TEST(BarrierClosureTest, ReleasesDoneClosureWhenDone) {
+  bool done_destructed = false;
+  base::Closure barrier_closure = base::BarrierClosure(
+      1, base::Bind(&DestructionIndicator::DoNothing,
+                    base::Owned(new DestructionIndicator(&done_destructed))));
+  EXPECT_FALSE(done_destructed);
+  barrier_closure.Run();
+  EXPECT_TRUE(done_destructed);
+}
+
+void ResetBarrierClosure(base::Closure* closure) {
+  *closure = base::Closure();
+}
+
+// Tests a case when |done_closure| resets a |barrier_closure|.
+// |barrier_closure| is a Closure holding the |done_closure|. |done_closure|
+// holds a pointer back to the |barrier_closure|. When |barrier_closure| is
+// Run() it calls ResetBarrierClosure() which erases the |barrier_closure| while
+// still inside of its Run(). The Run() implementation (in base::BarrierClosure)
+// must not try use itself after executing ResetBarrierClosure() or this test
+// would crash inside Run().
+TEST(BarrierClosureTest, KeepingClosureAliveUntilDone) {
+  base::Closure barrier_closure;
+  base::Closure done_closure =
+      base::Bind(ResetBarrierClosure, &barrier_closure);
+  barrier_closure = base::BarrierClosure(1, done_closure);
+  barrier_closure.Run();
+}
+
+}  // namespace
diff --git a/base/base.gyp b/base/base.gyp
new file mode 100644
index 0000000..1078434
--- /dev/null
+++ b/base/base.gyp
@@ -0,0 +1,1628 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../build/win_precompile.gypi',
+    'base.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'base',
+      'type': '<(component)',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'base_target': 1,
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base_static',
+        'allocator/allocator.gyp:allocator_extension_thunks',
+        '../testing/gtest.gyp:gtest_prod',
+        '../third_party/modp_b64/modp_b64.gyp:modp_b64',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      # TODO(gregoryd): direct_dependent_settings should be shared with the
+      #  64-bit target, but it doesn't work due to a bug in gyp
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '..',
+        ],
+      },
+      'conditions': [
+        ['desktop_linux == 1 or chromeos == 1', {
+          'conditions': [
+            ['chromeos==1', {
+              'sources/': [ ['include', '_chromeos\\.cc$'] ]
+            }],
+          ],
+          'dependencies': [
+            'symbolize',
+            'xdg_mime',
+          ],
+          'defines': [
+            'USE_SYMBOLIZE',
+          ],
+        }, {  # desktop_linux == 0 and chromeos == 0
+            'sources/': [
+              ['exclude', '/xdg_user_dirs/'],
+              ['exclude', '_nss\\.cc$'],
+            ],
+        }],
+        ['use_glib==1', {
+          'dependencies': [
+            '../build/linux/system.gyp:glib',
+          ],
+          'export_dependent_settings': [
+            '../build/linux/system.gyp:glib',
+          ],
+        }],
+        ['OS == "android" and _toolset == "host"', {
+          # Always build base as a static_library for host toolset, even if
+          # we're doing a component build. Specifically, we only care about the
+          # target toolset using components since that's what developers are
+          # focusing on. In theory we should do this more generally for all
+          # targets when building for host, but getting the gyp magic
+          # per-toolset for the "component" variable is hard, and we really only
+          # need base on host.
+          'type': 'static_library',
+          # Base for host support is the minimum required to run the
+          # ssl false start blacklist tool. It requires further changes
+          # to generically support host builds (and tests).
+          # Note: when building for host, gyp has OS == "android",
+          # hence the *_android.cc files are included but the actual code
+          # doesn't have OS_ANDROID / ANDROID defined.
+          'conditions': [
+            ['host_os == "mac"', {
+              'sources/': [
+                ['exclude', '^native_library_linux\\.cc$'],
+                ['exclude', '^process_util_linux\\.cc$'],
+                ['exclude', '^sys_info_linux\\.cc$'],
+                ['exclude', '^sys_string_conversions_linux\\.cc$'],
+                ['exclude', '^worker_pool_linux\\.cc$'],
+              ],
+            }],
+          ],
+        }],
+        ['OS == "android" and _toolset == "target"', {
+          'conditions': [
+            ['target_arch == "ia32" or target_arch == "x64"', {
+              'sources/': [
+                ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ],
+            }],
+            ['target_arch == "mipsel"', {
+              'sources/': [
+                ['include', '^atomicops_internals_mips_gcc\\.cc$'],
+              ],
+            }],
+          ],
+          'dependencies': [
+            'base_java',
+            'base_jni_headers',
+            '../build/android/ndk.gyp:cpu_features',
+            '../third_party/ashmem/ashmem.gyp:ashmem',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-llog',
+            ],
+          },
+          'sources!': [
+            'debug/stack_trace_posix.cc',
+          ],
+        }],
+        ['os_bsd==1', {
+          'include_dirs': [
+            '/usr/local/include',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-L/usr/local/lib -lexecinfo',
+            ],
+          },
+        }],
+        ['OS == "linux"', {
+          'link_settings': {
+            'libraries': [
+              # We need rt for clock_gettime().
+              '-lrt',
+              # For 'native_library_linux.cc'
+              '-ldl',
+            ],
+          },
+          'conditions': [
+            ['use_allocator!="tcmalloc"', {
+              'defines': [
+                'NO_TCMALLOC',
+              ],
+              'direct_dependent_settings': {
+                'defines': [
+                  'NO_TCMALLOC',
+                ],
+              },
+            }],
+          ],
+        }],
+        ['OS == "win"', {
+          # Specify delayload for base.dll.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'powrprof.dll',
+                'setupapi.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'powrprof.lib',
+                'setupapi.lib',
+              ],
+            },
+          },
+          # Specify delayload for components that link with base.lib.
+          'all_dependent_settings': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'DelayLoadDLLs': [
+                  'cfgmgr32.dll',
+                  'powrprof.dll',
+                  'setupapi.dll',
+                ],
+                'AdditionalDependencies': [
+                  'cfgmgr32.lib',
+                  'powrprof.lib',
+                  'setupapi.lib',
+                ],
+              },
+            },
+          },
+          'copies': [
+            {
+              'destination': '<(PRODUCT_DIR)/',
+              'files': [
+                '../build/win/dbghelp_xp/dbghelp.dll',
+              ],
+            },
+          ],
+          'dependencies': [
+           'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
+          ],
+        }],
+        ['OS == "mac" or (OS == "ios" and _toolset == "host")', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Security.framework',
+            ],
+          },
+        }],
+        ['OS == "ios" and _toolset != "host"', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreText.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+            ],
+          },
+        }],
+        ['OS != "win" and (OS != "ios" or _toolset == "host")', {
+            'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+        },],
+        ['component=="shared_library"', {
+          'conditions': [
+            ['OS=="win"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+        }],
+      ],
+      'sources': [
+        'async_socket_io_handler.h',
+        'async_socket_io_handler_posix.cc',
+        'async_socket_io_handler_win.cc',
+        'auto_reset.h',
+        'linux_util.cc',
+        'linux_util.h',
+        'message_loop/message_pump_android.cc',
+        'message_loop/message_pump_android.h',
+        'message_loop/message_pump_glib.cc',
+        'message_loop/message_pump_glib.h',
+        'message_loop/message_pump_io_ios.cc',
+        'message_loop/message_pump_io_ios.h',
+        'message_loop/message_pump_libevent.cc',
+        'message_loop/message_pump_libevent.h',
+        'message_loop/message_pump_mac.h',
+        'message_loop/message_pump_mac.mm',
+        'metrics/field_trial.cc',
+        'metrics/field_trial.h',
+        'posix/file_descriptor_shuffle.cc',
+        'posix/file_descriptor_shuffle.h',
+        'sync_socket.h',
+        'sync_socket_posix.cc',
+        'sync_socket_win.cc',
+        'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+        'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    {
+      'target_name': 'base_i18n',
+      'type': '<(component)',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+        'base_i18n_target': 1,
+      },
+      'dependencies': [
+        'base',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+      ],
+      'conditions': [
+        ['OS == "win"', {
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [
+            4267,
+          ],
+        }],
+        ['icu_use_data_file_flag==1', {
+          'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE'],
+        }, { # else icu_use_data_file_flag !=1
+          'conditions': [
+            ['OS=="win"', {
+              'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_SHARED'],
+            }, {
+              'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC'],
+            }],
+          ],
+        }],
+        ['OS == "ios"', {
+          'toolsets': ['host', 'target'],
+        }],
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    {
+      'target_name': 'base_message_loop_tests',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'message_loop/message_loop_test.cc',
+        'message_loop/message_loop_test.h',
+      ],
+    },
+    {
+      'target_name': 'base_prefs',
+      'type': '<(component)',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base',
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'defines': [
+        'BASE_PREFS_IMPLEMENTATION',
+      ],
+      'sources': [
+        'prefs/base_prefs_export.h',
+        'prefs/default_pref_store.cc',
+        'prefs/default_pref_store.h',
+        'prefs/json_pref_store.cc',
+        'prefs/json_pref_store.h',
+        'prefs/overlay_user_pref_store.cc',
+        'prefs/overlay_user_pref_store.h',
+        'prefs/persistent_pref_store.h',
+        'prefs/pref_change_registrar.cc',
+        'prefs/pref_change_registrar.h',
+        'prefs/pref_filter.h',
+        'prefs/pref_member.cc',
+        'prefs/pref_member.h',
+        'prefs/pref_notifier.h',
+        'prefs/pref_notifier_impl.cc',
+        'prefs/pref_notifier_impl.h',
+        'prefs/pref_observer.h',
+        'prefs/pref_registry.cc',
+        'prefs/pref_registry.h',
+        'prefs/pref_registry_simple.cc',
+        'prefs/pref_registry_simple.h',
+        'prefs/pref_service.cc',
+        'prefs/pref_service.h',
+        'prefs/pref_service_factory.cc',
+        'prefs/pref_service_factory.h',
+        'prefs/pref_store.cc',
+        'prefs/pref_store.h',
+        'prefs/pref_value_map.cc',
+        'prefs/pref_value_map.h',
+        'prefs/pref_value_store.cc',
+        'prefs/pref_value_store.h',
+        'prefs/scoped_user_pref_update.cc',
+        'prefs/scoped_user_pref_update.h',
+        'prefs/value_map_pref_store.cc',
+        'prefs/value_map_pref_store.h',
+        'prefs/writeable_pref_store.h',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    {
+      'target_name': 'base_prefs_test_support',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'base_prefs',
+        '../testing/gmock.gyp:gmock',
+      ],
+      'sources': [
+        'prefs/mock_pref_change_callback.cc',
+        'prefs/pref_store_observer_mock.cc',
+        'prefs/pref_store_observer_mock.h',
+        'prefs/testing_pref_service.cc',
+        'prefs/testing_pref_service.h',
+        'prefs/testing_pref_store.cc',
+        'prefs/testing_pref_store.h',
+      ],
+    },
+    {
+      # This is the subset of files from base that should not be used with a
+      # dynamic library. Note that this library cannot depend on base because
+      # base depends on base_static.
+      'target_name': 'base_static',
+      'type': 'static_library',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'toolsets': ['host', 'target'],
+      'sources': [
+        'base_switches.cc',
+        'base_switches.h',
+        'win/pe_image.cc',
+        'win/pe_image.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    # Include this target for a main() function that simply instantiates
+    # and runs a base::TestSuite.
+    {
+      'target_name': 'run_all_unittests',
+      'type': 'static_library',
+      'dependencies': [
+        'test_support_base',
+      ],
+      'sources': [
+        'test/run_all_unittests.cc',
+      ],
+    },
+    {
+      'target_name': 'base_unittests',
+      'type': '<(gtest_target_type)',
+      'sources': [
+        'android/application_status_listener_unittest.cc',
+        'android/content_uri_utils_unittest.cc',
+        'android/jni_android_unittest.cc',
+        'android/jni_array_unittest.cc',
+        'android/jni_string_unittest.cc',
+        'android/library_loader/library_prefetcher_unittest.cc',
+        'android/path_utils_unittest.cc',
+        'android/scoped_java_ref_unittest.cc',
+        'android/sys_utils_unittest.cc',
+        'async_socket_io_handler_unittest.cc',
+        'at_exit_unittest.cc',
+        'atomicops_unittest.cc',
+        'barrier_closure_unittest.cc',
+        'base64_unittest.cc',
+        'big_endian_unittest.cc',
+        'bind_unittest.cc',
+        'bind_unittest.nc',
+        'bits_unittest.cc',
+        'build_time_unittest.cc',
+        'callback_helpers_unittest.cc',
+        'callback_list_unittest.cc',
+        'callback_list_unittest.nc',
+        'callback_unittest.cc',
+        'callback_unittest.nc',
+        'cancelable_callback_unittest.cc',
+        'chromeos/memory_pressure_monitor_chromeos_unittest.cc',
+        'command_line_unittest.cc',
+        'containers/adapters_unittest.cc',
+        'containers/hash_tables_unittest.cc',
+        'containers/linked_list_unittest.cc',
+        'containers/mru_cache_unittest.cc',
+        'containers/scoped_ptr_hash_map_unittest.cc',
+        'containers/small_map_unittest.cc',
+        'containers/stack_container_unittest.cc',
+        'cpu_unittest.cc',
+        'debug/crash_logging_unittest.cc',
+        'debug/debugger_unittest.cc',
+        'debug/leak_tracker_unittest.cc',
+        'debug/proc_maps_linux_unittest.cc',
+        'debug/stack_trace_unittest.cc',
+        'debug/task_annotator_unittest.cc',
+        'deferred_sequenced_task_runner_unittest.cc',
+        'environment_unittest.cc',
+        'file_version_info_unittest.cc',
+        'files/dir_reader_posix_unittest.cc',
+        'files/file_path_unittest.cc',
+        'files/file_path_watcher_unittest.cc',
+        'files/file_proxy_unittest.cc',
+        'files/file_unittest.cc',
+        'files/file_util_proxy_unittest.cc',
+        'files/file_util_unittest.cc',
+        'files/important_file_writer_unittest.cc',
+        'files/memory_mapped_file_unittest.cc',
+        'files/scoped_temp_dir_unittest.cc',
+        'gmock_unittest.cc',
+        'guid_unittest.cc',
+        'hash_unittest.cc',
+        'i18n/break_iterator_unittest.cc',
+        'i18n/case_conversion_unittest.cc',
+        'i18n/char_iterator_unittest.cc',
+        'i18n/file_util_icu_unittest.cc',
+        'i18n/icu_string_conversions_unittest.cc',
+        'i18n/number_formatting_unittest.cc',
+        'i18n/rtl_unittest.cc',
+        'i18n/streaming_utf8_validator_unittest.cc',
+        'i18n/string_search_unittest.cc',
+        'i18n/time_formatting_unittest.cc',
+        'i18n/timezone_unittest.cc',
+        'id_map_unittest.cc',
+        'ios/crb_protocol_observers_unittest.mm',
+        'ios/device_util_unittest.mm',
+        'ios/weak_nsobject_unittest.mm',
+        'json/json_parser_unittest.cc',
+        'json/json_reader_unittest.cc',
+        'json/json_value_converter_unittest.cc',
+        'json/json_value_serializer_unittest.cc',
+        'json/json_writer_unittest.cc',
+        'json/string_escape_unittest.cc',
+        'lazy_instance_unittest.cc',
+        'logging_unittest.cc',
+        'mac/bind_objc_block_unittest.mm',
+        'mac/foundation_util_unittest.mm',
+        'mac/libdispatch_task_runner_unittest.cc',
+        'mac/mac_util_unittest.mm',
+        'mac/memory_pressure_monitor_mac_unittest.cc',
+        'mac/objc_property_releaser_unittest.mm',
+        'mac/scoped_nsobject_unittest.mm',
+        'mac/scoped_objc_class_swizzler_unittest.mm',
+        'mac/scoped_sending_event_unittest.mm',
+        'md5_unittest.cc',
+        'memory/aligned_memory_unittest.cc',
+        'memory/discardable_shared_memory_unittest.cc',
+        'memory/linked_ptr_unittest.cc',
+        'memory/ref_counted_memory_unittest.cc',
+        'memory/ref_counted_unittest.cc',
+        'memory/scoped_ptr_unittest.cc',
+        'memory/scoped_ptr_unittest.nc',
+        'memory/scoped_vector_unittest.cc',
+        'memory/shared_memory_unittest.cc',
+        'memory/singleton_unittest.cc',
+        'memory/weak_ptr_unittest.cc',
+        'memory/weak_ptr_unittest.nc',
+        'message_loop/message_loop_proxy_impl_unittest.cc',
+        'message_loop/message_loop_proxy_unittest.cc',
+        'message_loop/message_loop_unittest.cc',
+        'message_loop/message_pump_glib_unittest.cc',
+        'message_loop/message_pump_io_ios_unittest.cc',
+        'message_loop/message_pump_libevent_unittest.cc',
+        'metrics/bucket_ranges_unittest.cc',
+        'metrics/field_trial_unittest.cc',
+        'metrics/histogram_base_unittest.cc',
+        'metrics/histogram_delta_serialization_unittest.cc',
+        'metrics/histogram_macros_unittest.cc',
+        'metrics/histogram_snapshot_manager_unittest.cc',
+        'metrics/histogram_unittest.cc',
+        'metrics/sample_map_unittest.cc',
+        'metrics/sample_vector_unittest.cc',
+        'metrics/sparse_histogram_unittest.cc',
+        'metrics/statistics_recorder_unittest.cc',
+        'move_unittest.cc',
+        'numerics/safe_numerics_unittest.cc',
+        'observer_list_unittest.cc',
+        'os_compat_android_unittest.cc',
+        'path_service_unittest.cc',
+        'pickle_unittest.cc',
+        'posix/file_descriptor_shuffle_unittest.cc',
+        'posix/unix_domain_socket_linux_unittest.cc',
+        'power_monitor/power_monitor_unittest.cc',
+        'prefs/default_pref_store_unittest.cc',
+        'prefs/json_pref_store_unittest.cc',
+        'prefs/mock_pref_change_callback.h',
+        'prefs/overlay_user_pref_store_unittest.cc',
+        'prefs/pref_change_registrar_unittest.cc',
+        'prefs/pref_member_unittest.cc',
+        'prefs/pref_notifier_impl_unittest.cc',
+        'prefs/pref_service_unittest.cc',
+        'prefs/pref_value_map_unittest.cc',
+        'prefs/pref_value_store_unittest.cc',
+        'prefs/scoped_user_pref_update_unittest.cc',
+        'process/memory_unittest.cc',
+        'process/memory_unittest_mac.h',
+        'process/memory_unittest_mac.mm',
+        'process/process_metrics_unittest.cc',
+        'process/process_metrics_unittest_ios.cc',
+        'process/process_unittest.cc',
+        'process/process_util_unittest.cc',
+        'profiler/stack_sampling_profiler_unittest.cc',
+        'profiler/tracked_time_unittest.cc',
+        'rand_util_unittest.cc',
+        'scoped_clear_errno_unittest.cc',
+        'scoped_generic_unittest.cc',
+        'scoped_native_library_unittest.cc',
+        'security_unittest.cc',
+        'sequence_checker_unittest.cc',
+        'sha1_unittest.cc',
+        'stl_util_unittest.cc',
+        'strings/nullable_string16_unittest.cc',
+        'strings/safe_sprintf_unittest.cc',
+        'strings/string16_unittest.cc',
+        'strings/string_number_conversions_unittest.cc',
+        'strings/string_piece_unittest.cc',
+        'strings/string_split_unittest.cc',
+        'strings/string_tokenizer_unittest.cc',
+        'strings/string_util_unittest.cc',
+        'strings/stringize_macros_unittest.cc',
+        'strings/stringprintf_unittest.cc',
+        'strings/sys_string_conversions_mac_unittest.mm',
+        'strings/sys_string_conversions_unittest.cc',
+        'strings/utf_offset_string_conversions_unittest.cc',
+        'strings/utf_string_conversions_unittest.cc',
+        'supports_user_data_unittest.cc',
+        'sync_socket_unittest.cc',
+        'synchronization/cancellation_flag_unittest.cc',
+        'synchronization/condition_variable_unittest.cc',
+        'synchronization/lock_unittest.cc',
+        'synchronization/waitable_event_unittest.cc',
+        'synchronization/waitable_event_watcher_unittest.cc',
+        'sys_info_unittest.cc',
+        'system_monitor/system_monitor_unittest.cc',
+        'task/cancelable_task_tracker_unittest.cc',
+        'task_runner_util_unittest.cc',
+        'template_util_unittest.cc',
+        'test/expectations/expectation_unittest.cc',
+        'test/expectations/parser_unittest.cc',
+        'test/histogram_tester_unittest.cc',
+        'test/test_pending_task_unittest.cc',
+        'test/test_reg_util_win_unittest.cc',
+        'test/trace_event_analyzer_unittest.cc',
+        'test/user_action_tester_unittest.cc',
+        'threading/non_thread_safe_unittest.cc',
+        'threading/platform_thread_unittest.cc',
+        'threading/sequenced_worker_pool_unittest.cc',
+        'threading/simple_thread_unittest.cc',
+        'threading/thread_checker_unittest.cc',
+        'threading/thread_collision_warner_unittest.cc',
+        'threading/thread_id_name_manager_unittest.cc',
+        'threading/thread_local_storage_unittest.cc',
+        'threading/thread_local_unittest.cc',
+        'threading/thread_unittest.cc',
+        'threading/watchdog_unittest.cc',
+        'threading/worker_pool_posix_unittest.cc',
+        'threading/worker_pool_unittest.cc',
+        'time/pr_time_unittest.cc',
+        'time/time_unittest.cc',
+        'time/time_win_unittest.cc',
+        'timer/hi_res_timer_manager_unittest.cc',
+        'timer/mock_timer_unittest.cc',
+        'timer/timer_unittest.cc',
+        'tools_sanity_unittest.cc',
+        'tracked_objects_unittest.cc',
+        'tuple_unittest.cc',
+        'values_unittest.cc',
+        'version_unittest.cc',
+        'vlog_unittest.cc',
+        'win/dllmain.cc',
+        'win/enum_variant_unittest.cc',
+        'win/event_trace_consumer_unittest.cc',
+        'win/event_trace_controller_unittest.cc',
+        'win/event_trace_provider_unittest.cc',
+        'win/i18n_unittest.cc',
+        'win/iunknown_impl_unittest.cc',
+        'win/memory_pressure_monitor_unittest.cc',
+        'win/message_window_unittest.cc',
+        'win/object_watcher_unittest.cc',
+        'win/pe_image_unittest.cc',
+        'win/registry_unittest.cc',
+        'win/scoped_bstr_unittest.cc',
+        'win/scoped_comptr_unittest.cc',
+        'win/scoped_process_information_unittest.cc',
+        'win/scoped_variant_unittest.cc',
+        'win/shortcut_unittest.cc',
+        'win/startup_information_unittest.cc',
+        'win/win_util_unittest.cc',
+        'win/wrapped_window_proc_unittest.cc',
+        '<@(trace_event_test_sources)',
+      ],
+      'dependencies': [
+        'base',
+        'base_i18n',
+        'base_message_loop_tests',
+        'base_prefs',
+        'base_prefs_test_support',
+        'base_static',
+        'run_all_unittests',
+        'test_support_base',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+      ],
+      'includes': ['../build/nocompile.gypi'],
+      'variables': {
+         # TODO(ajwong): Is there a way to autodetect this?
+        'module_dir': 'base'
+      },
+      'conditions': [
+        ['OS == "android"', {
+          'dependencies': [
+            'android/jni_generator/jni_generator.gyp:jni_generator_tests',
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+        ['OS == "ios" and _toolset != "host"', {
+          'sources/': [
+            # Only test the iOS-meaningful portion of process_utils.
+            ['exclude', '^process/memory_unittest'],
+            ['exclude', '^process/process_unittest\\.cc$'],
+            ['exclude', '^process/process_util_unittest\\.cc$'],
+            ['include', '^process/process_util_unittest_ios\\.cc$'],
+            # iOS does not use message_pump_libevent.
+            ['exclude', '^message_loop/message_pump_libevent_unittest\\.cc$'],
+          ],
+          'actions': [
+            {
+              'action_name': 'copy_test_data',
+              'variables': {
+                'test_data_files': [
+                  'test/data',
+                ],
+                'test_data_prefix': 'base',
+              },
+              'includes': [ '../build/copy_test_data_ios.gypi' ],
+            },
+          ],
+        }],
+        ['desktop_linux == 1 or chromeos == 1', {
+          'defines': [
+            'USE_SYMBOLIZE',
+          ],
+          'sources!': [
+            'file_version_info_unittest.cc',
+          ],
+          'conditions': [
+            [ 'desktop_linux==1', {
+              'sources': [
+                'nix/xdg_util_unittest.cc',
+              ],
+            }],
+          ],
+        }],
+        ['use_glib == 1', {
+          'dependencies': [
+            '../build/linux/system.gyp:glib',
+          ],
+        }, {  # use_glib == 0
+          'sources!': [
+            'message_loop/message_pump_glib_unittest.cc',
+          ]
+        }],
+        ['use_ozone == 1', {
+          'sources!': [
+            'message_loop/message_pump_glib_unittest.cc',
+          ]
+        }],
+        ['OS == "linux"', {
+          'dependencies': [
+            'malloc_wrapper',
+          ],
+          'conditions': [
+            ['use_allocator!="none"', {
+              'dependencies': [
+                'allocator/allocator.gyp:allocator',
+              ],
+            }],
+          ]},
+        ],
+        ['OS == "win"', {
+          'sources!': [
+            'file_descriptor_shuffle_unittest.cc',
+            'files/dir_reader_posix_unittest.cc',
+            'message_loop/message_pump_libevent_unittest.cc',
+            'threading/worker_pool_posix_unittest.cc',
+          ],
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [
+            4267,
+          ],
+          'conditions': [
+            # This is needed so base_unittests uses the allocator shim, as
+            # SecurityTest.MemoryAllocationRestriction* tests are dependent
+            # on tcmalloc.
+            # TODO(wfh): crbug.com/246278 Move tcmalloc specific tests into
+            # their own test suite.
+            ['win_use_allocator_shim==1', {
+              'dependencies': [
+                'allocator/allocator.gyp:allocator',
+              ],
+            }],
+            ['icu_use_data_file_flag==0', {
+              # This is needed to trigger the dll copy step on windows.
+              # TODO(mark): This should not be necessary.
+              'dependencies': [
+                '../third_party/icu/icu.gyp:icudata',
+              ],
+            }],
+          ],
+        }, {  # OS != "win"
+          'dependencies': [
+            '../third_party/libevent/libevent.gyp:libevent'
+          ],
+        }],
+      ],  # conditions
+      'target_conditions': [
+        ['OS == "ios" and _toolset != "host"', {
+          'sources/': [
+            # Pull in specific Mac files for iOS (which have been filtered out
+            # by file name rules).
+            ['include', '^mac/bind_objc_block_unittest\\.mm$'],
+            ['include', '^mac/foundation_util_unittest\\.mm$',],
+            ['include', '^mac/objc_property_releaser_unittest\\.mm$'],
+            ['include', '^mac/scoped_nsobject_unittest\\.mm$'],
+            ['include', '^sys_string_conversions_mac_unittest\\.mm$'],
+          ],
+        }],
+        ['OS == "android"', {
+          'sources/': [
+            ['include', '^debug/proc_maps_linux_unittest\\.cc$'],
+          ],
+        }],
+        # Enable more direct string conversions on platforms with native utf8
+        # strings
+        ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+          'defines': ['SYSTEM_NATIVE_UTF8'],
+        }],
+      ],  # target_conditions
+    },
+    {
+      # GN: //base:base_perftests
+      'target_name': 'base_perftests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'base',
+        'test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'message_loop/message_pump_perftest.cc',
+        'test/run_all_unittests.cc',
+        'threading/thread_perftest.cc',
+        '../testing/perf/perf_test.cc'
+      ],
+      'conditions': [
+        ['OS == "android"', {
+          'dependencies': [
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+      ],
+    },
+    {
+      # GN: //base:base_i18n_perftests
+      'target_name': 'base_i18n_perftests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'test_support_base',
+        'test_support_perf',
+        '../testing/gtest.gyp:gtest',
+        'base_i18n',
+        'base',
+      ],
+      'sources': [
+        'i18n/streaming_utf8_validator_perftest.cc',
+      ],
+    },
+    {
+      # GN: //base/test:test_support
+      'target_name': 'test_support_base',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'base_static',
+        'base_i18n',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icuuc',
+        '../third_party/libxml/libxml.gyp:libxml',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'conditions': [
+        ['os_posix==0', {
+          'sources!': [
+            'test/scoped_locale.cc',
+            'test/scoped_locale.h',
+          ],
+        }],
+        ['os_bsd==1', {
+          'sources!': [
+            'test/test_file_util_linux.cc',
+          ],
+        }],
+        ['OS == "android"', {
+          'dependencies': [
+            'base_unittests_jni_headers',
+            'base_java_unittest_support',
+          ],
+        }],
+        ['OS == "ios"', {
+          'toolsets': ['host', 'target'],
+        }],
+      ],
+      'sources': [
+        'test/expectations/expectation.cc',
+        'test/expectations/expectation.h',
+        'test/expectations/parser.cc',
+        'test/expectations/parser.h',
+        'test/gtest_util.cc',
+        'test/gtest_util.h',
+        'test/gtest_xml_util.cc',
+        'test/gtest_xml_util.h',
+        'test/histogram_tester.cc',
+        'test/histogram_tester.h',
+        'test/ios/wait_util.h',
+        'test/ios/wait_util.mm',
+        'test/launcher/test_launcher.cc',
+        'test/launcher/test_launcher.h',
+        'test/launcher/test_result.cc',
+        'test/launcher/test_result.h',
+        'test/launcher/test_results_tracker.cc',
+        'test/launcher/test_results_tracker.h',
+        'test/launcher/unit_test_launcher.cc',
+        'test/launcher/unit_test_launcher.h',
+        'test/launcher/unit_test_launcher_ios.cc',
+        'test/mock_chrome_application_mac.h',
+        'test/mock_chrome_application_mac.mm',
+        'test/mock_devices_changed_observer.cc',
+        'test/mock_devices_changed_observer.h',
+        'test/mock_entropy_provider.cc',
+        'test/mock_entropy_provider.h',
+        'test/mock_log.cc',
+        'test/mock_log.h',
+        'test/multiprocess_test.cc',
+        'test/multiprocess_test.h',
+        'test/multiprocess_test_android.cc',
+        'test/null_task_runner.cc',
+        'test/null_task_runner.h',
+        'test/opaque_ref_counted.cc',
+        'test/opaque_ref_counted.h',
+        'test/perf_log.cc',
+        'test/perf_log.h',
+        'test/perf_test_suite.cc',
+        'test/perf_test_suite.h',
+        'test/perf_time_logger.cc',
+        'test/perf_time_logger.h',
+        'test/power_monitor_test_base.cc',
+        'test/power_monitor_test_base.h',
+        'test/scoped_locale.cc',
+        'test/scoped_locale.h',
+        'test/scoped_path_override.cc',
+        'test/scoped_path_override.h',
+        'test/sequenced_task_runner_test_template.cc',
+        'test/sequenced_task_runner_test_template.h',
+        'test/sequenced_worker_pool_owner.cc',
+        'test/sequenced_worker_pool_owner.h',
+        'test/simple_test_clock.cc',
+        'test/simple_test_clock.h',
+        'test/simple_test_tick_clock.cc',
+        'test/simple_test_tick_clock.h',
+        'test/task_runner_test_template.cc',
+        'test/task_runner_test_template.h',
+        'test/test_discardable_memory_allocator.cc',
+        'test/test_discardable_memory_allocator.h',
+        'test/test_file_util.cc',
+        'test/test_file_util.h',
+        'test/test_file_util_android.cc',
+        'test/test_file_util_linux.cc',
+        'test/test_file_util_mac.cc',
+        'test/test_file_util_posix.cc',
+        'test/test_file_util_win.cc',
+        'test/test_io_thread.cc',
+        'test/test_io_thread.h',
+        'test/test_listener_ios.h',
+        'test/test_listener_ios.mm',
+        'test/test_mock_time_task_runner.cc',
+        'test/test_mock_time_task_runner.h',
+        'test/test_pending_task.cc',
+        'test/test_pending_task.h',
+        'test/test_reg_util_win.cc',
+        'test/test_reg_util_win.h',
+        'test/test_shortcut_win.cc',
+        'test/test_shortcut_win.h',
+        'test/test_simple_task_runner.cc',
+        'test/test_simple_task_runner.h',
+        'test/test_suite.cc',
+        'test/test_suite.h',
+        'test/test_support_android.cc',
+        'test/test_support_android.h',
+        'test/test_support_ios.h',
+        'test/test_support_ios.mm',
+        'test/test_switches.cc',
+        'test/test_switches.h',
+        'test/test_timeouts.cc',
+        'test/test_timeouts.h',
+        'test/thread_test_helper.cc',
+        'test/thread_test_helper.h',
+        'test/trace_event_analyzer.cc',
+        'test/trace_event_analyzer.h',
+        'test/trace_to_file.cc',
+        'test/trace_to_file.h',
+        'test/user_action_tester.cc',
+        'test/user_action_tester.h',
+        'test/values_test_util.cc',
+        'test/values_test_util.h',
+      ],
+      'target_conditions': [
+        ['OS == "ios"', {
+          'sources/': [
+            # Pull in specific Mac files for iOS (which have been filtered out
+            # by file name rules).
+            ['include', '^test/test_file_util_mac\\.cc$'],
+          ],
+        }],
+        ['OS == "ios" and _toolset == "target"', {
+          'sources!': [
+            # iOS uses its own unit test launcher.
+            'test/launcher/unit_test_launcher.cc',
+          ],
+        }],
+        ['OS == "ios" and _toolset == "host"', {
+          'sources!': [
+            'test/launcher/unit_test_launcher_ios.cc',
+            'test/test_support_ios.h',
+            'test/test_support_ios.mm',
+          ],
+        }],
+      ],  # target_conditions
+    },
+    {
+      'target_name': 'test_support_perf',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'test/run_all_perftests.cc',
+      ],
+      'direct_dependent_settings': {
+        'defines': [
+          'PERF_TEST',
+        ],
+      },
+    },
+  ],
+  'conditions': [
+    ['OS=="ios" and "<(GENERATOR)"=="ninja"', {
+      'targets': [
+        {
+          'target_name': 'test_launcher',
+          'toolsets': ['host'],
+          'type': 'executable',
+          'dependencies': [
+            'test_support_base',
+          ],
+          'sources': [
+            'test/launcher/test_launcher_ios.cc',
+          ],
+        },
+      ],
+    }],
+    ['OS!="ios"', {
+      'targets': [
+        {
+          # GN: //base:check_example
+          'target_name': 'check_example',
+          'type': 'executable',
+          'sources': [
+            'check_example.cc',
+          ],
+          'dependencies': [
+            'base',
+          ],
+        },
+        {
+          'target_name': 'build_utf8_validator_tables',
+          'type': 'executable',
+          'toolsets': ['host'],
+          'dependencies': [
+            'base',
+            '../third_party/icu/icu.gyp:icuuc',
+          ],
+          'sources': [
+            'i18n/build_utf8_validator_tables.cc'
+          ],
+        },
+      ],
+    }],
+    ['OS == "win" and target_arch=="ia32"', {
+      'targets': [
+        # The base_win64 target here allows us to use base for Win64 targets
+        # (the normal build is 32 bits).
+        {
+          'target_name': 'base_win64',
+          'type': '<(component)',
+          'variables': {
+            'base_target': 1,
+          },
+          'dependencies': [
+            'base_static_win64',
+            'allocator/allocator.gyp:allocator_extension_thunks_win64',
+            '../third_party/modp_b64/modp_b64.gyp:modp_b64_win64',
+            'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+            'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
+          ],
+          # TODO(gregoryd): direct_dependent_settings should be shared with the
+          # 32-bit target, but it doesn't work due to a bug in gyp
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '..',
+            ],
+          },
+          'defines': [
+            'BASE_WIN64',
+            '<@(nacl_win64_defines)',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'conditions': [
+            ['component == "shared_library"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+          # Specify delayload for base_win64.dll.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'powrprof.dll',
+                'setupapi.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'powrprof.lib',
+                'setupapi.lib',
+              ],
+            },
+          },
+          # Specify delayload for components that link with base_win64.lib.
+          'all_dependent_settings': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'DelayLoadDLLs': [
+                  'cfgmgr32.dll',
+                  'powrprof.dll',
+                  'setupapi.dll',
+                ],
+                'AdditionalDependencies': [
+                  'cfgmgr32.lib',
+                  'powrprof.lib',
+                  'setupapi.lib',
+                ],
+              },
+            },
+          },
+          # TODO(rvargas): Bug 78117. Remove this.
+          'msvs_disabled_warnings': [
+            4244,
+            4996,
+            4267,
+          ],
+          'sources': [
+            'async_socket_io_handler.h',
+            'async_socket_io_handler_posix.cc',
+            'async_socket_io_handler_win.cc',
+            'auto_reset.h',
+            'linux_util.cc',
+            'linux_util.h',
+            'md5.cc',
+            'md5.h',
+            'message_loop/message_pump_libevent.cc',
+            'message_loop/message_pump_libevent.h',
+            'metrics/field_trial.cc',
+            'metrics/field_trial.h',
+            'posix/file_descriptor_shuffle.cc',
+            'posix/file_descriptor_shuffle.h',
+            'sync_socket.h',
+            'sync_socket_posix.cc',
+            'sync_socket_win.cc',
+            'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+            'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+          ],
+        },
+        {
+          'target_name': 'base_i18n_nacl_win64',
+          'type': '<(component)',
+          # TODO(gregoryd): direct_dependent_settings should be shared with the
+          # 32-bit target, but it doesn't work due to a bug in gyp
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '..',
+            ],
+          },
+          'defines': [
+            '<@(nacl_win64_defines)',
+            'BASE_I18N_IMPLEMENTATION',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'sources': [
+            'i18n/icu_util_nacl_win64.cc',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+        {
+          # TODO(rvargas): Remove this when gyp finally supports a clean model.
+          # See bug 36232.
+          'target_name': 'base_static_win64',
+          'type': 'static_library',
+          'sources': [
+            'base_switches.cc',
+            'base_switches.h',
+            'win/pe_image.cc',
+            'win/pe_image.h',
+          ],
+          'sources!': [
+            # base64.cc depends on modp_b64.
+            'base64.cc',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'defines': [
+            '<@(nacl_win64_defines)',
+          ],
+          # TODO(rvargas): Bug 78117. Remove this.
+          'msvs_disabled_warnings': [
+            4244,
+          ],
+        },
+      ],
+    }],
+    ['os_posix==1 and OS!="mac" and OS!="ios"', {
+      'targets': [
+        {
+          'target_name': 'symbolize',
+          'type': 'static_library',
+          'toolsets': ['host', 'target'],
+          'variables': {
+            'chromium_code': 0,
+          },
+          'conditions': [
+            ['OS == "solaris"', {
+              'include_dirs': [
+                '/usr/gnu/include',
+                '/usr/gnu/include/libelf',
+              ],
+            },],
+          ],
+          'cflags': [
+            '-Wno-sign-compare',
+          ],
+          'cflags!': [
+            '-Wextra',
+          ],
+          'defines': [
+            'GLOG_BUILD_CONFIG_INCLUDE="build/build_config.h"',
+          ],
+          'sources': [
+            'third_party/symbolize/config.h',
+            'third_party/symbolize/demangle.cc',
+            'third_party/symbolize/demangle.h',
+            'third_party/symbolize/glog/logging.h',
+            'third_party/symbolize/glog/raw_logging.h',
+            'third_party/symbolize/symbolize.cc',
+            'third_party/symbolize/symbolize.h',
+            'third_party/symbolize/utilities.h',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'includes': [
+            '../build/android/increase_size_for_speed.gypi',
+          ],
+        },
+        {
+          'target_name': 'xdg_mime',
+          'type': 'static_library',
+          'toolsets': ['host', 'target'],
+          'variables': {
+            'chromium_code': 0,
+          },
+          'cflags!': [
+            '-Wextra',
+          ],
+          'sources': [
+            'third_party/xdg_mime/xdgmime.c',
+            'third_party/xdg_mime/xdgmime.h',
+            'third_party/xdg_mime/xdgmimealias.c',
+            'third_party/xdg_mime/xdgmimealias.h',
+            'third_party/xdg_mime/xdgmimecache.c',
+            'third_party/xdg_mime/xdgmimecache.h',
+            'third_party/xdg_mime/xdgmimeglob.c',
+            'third_party/xdg_mime/xdgmimeglob.h',
+            'third_party/xdg_mime/xdgmimeicon.c',
+            'third_party/xdg_mime/xdgmimeicon.h',
+            'third_party/xdg_mime/xdgmimeint.c',
+            'third_party/xdg_mime/xdgmimeint.h',
+            'third_party/xdg_mime/xdgmimemagic.c',
+            'third_party/xdg_mime/xdgmimemagic.h',
+            'third_party/xdg_mime/xdgmimeparent.c',
+            'third_party/xdg_mime/xdgmimeparent.h',
+          ],
+          'includes': [
+            '../build/android/increase_size_for_speed.gypi',
+          ],
+        },
+      ],
+    }],
+    ['OS == "linux"', {
+      'targets': [
+        {
+          'target_name': 'malloc_wrapper',
+          'type': 'shared_library',
+          'dependencies': [
+            'base',
+          ],
+          'sources': [
+            'test/malloc_wrapper.cc',
+          ],
+        }
+      ],
+    }],
+    ['OS == "android"', {
+      'targets': [
+        {
+          # GN: //base:base_jni_headers
+          'target_name': 'base_jni_headers',
+          'type': 'none',
+          'sources': [
+            'android/java/src/org/chromium/base/ApplicationStatus.java',
+            'android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java',
+            'android/java/src/org/chromium/base/BuildInfo.java',
+            'android/java/src/org/chromium/base/CommandLine.java',
+            'android/java/src/org/chromium/base/ContentUriUtils.java',
+            'android/java/src/org/chromium/base/CpuFeatures.java',
+            'android/java/src/org/chromium/base/EventLog.java',
+            'android/java/src/org/chromium/base/FieldTrialList.java',
+            'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java',
+            'android/java/src/org/chromium/base/JNIUtils.java',
+            'android/java/src/org/chromium/base/JavaHandlerThread.java',
+            'android/java/src/org/chromium/base/LocaleUtils.java',
+            'android/java/src/org/chromium/base/MemoryPressureListener.java',
+            'android/java/src/org/chromium/base/PathService.java',
+            'android/java/src/org/chromium/base/PathUtils.java',
+            'android/java/src/org/chromium/base/PowerMonitor.java',
+            'android/java/src/org/chromium/base/SysUtils.java',
+            'android/java/src/org/chromium/base/SystemMessageHandler.java',
+            'android/java/src/org/chromium/base/ThreadUtils.java',
+            'android/java/src/org/chromium/base/TraceEvent.java',
+            'android/java/src/org/chromium/base/library_loader/LibraryLoader.java',
+            'android/java/src/org/chromium/base/metrics/RecordHistogram.java',
+            'android/java/src/org/chromium/base/metrics/RecordUserAction.java',
+          ],
+          'variables': {
+            'jni_gen_package': 'base',
+          },
+          'dependencies': [
+            'android_runtime_jni_headers',
+          ],
+          'includes': [ '../build/jni_generator.gypi' ],
+        },
+        {
+          # GN: //base:android_runtime_jni_headers
+          'target_name': 'android_runtime_jni_headers',
+          'type': 'none',
+          'variables': {
+            'jni_gen_package': 'base',
+            'input_java_class': 'java/lang/Runtime.class',
+          },
+          'includes': [ '../build/jar_file_jni_generator.gypi' ],
+        },
+        {
+          # TODO(GN)
+          'target_name': 'base_unittests_jni_headers',
+          'type': 'none',
+          'sources': [
+            'test/android/java/src/org/chromium/base/ContentUriTestUtils.java',
+          ],
+          'variables': {
+            'jni_gen_package': 'base',
+          },
+          'includes': [ '../build/jni_generator.gypi' ],
+        },
+        {
+          # GN: //base:base_native_libraries_gen
+          'target_name': 'base_native_libraries_gen',
+          'type': 'none',
+          'sources': [
+            'android/java/templates/NativeLibraries.template',
+          ],
+          'variables': {
+            'package_name': 'org/chromium/base/library_loader',
+            'template_deps': [],
+          },
+          'includes': [ '../build/android/java_cpp_template.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_library_process_type',
+          'type': 'none',
+          'variables': {
+            'source_file': 'android/library_loader/library_loader_hooks.h',
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_java
+          'target_name': 'base_java',
+          'type': 'none',
+          'variables': {
+            'java_in_dir': '../base/android/java',
+            'jar_excluded_classes': [ '*/NativeLibraries.class' ],
+          },
+          'dependencies': [
+            'base_java_application_state',
+            'base_java_library_load_from_apk_status_codes',
+            'base_java_library_process_type',
+            'base_java_memory_pressure_level',
+            'base_native_libraries_gen',
+            '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
+          ],
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base:base_java_unittest_support
+          'target_name': 'base_java_unittest_support',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+          ],
+          'variables': {
+            'java_in_dir': '../base/test/android/java',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_application_state',
+          'type': 'none',
+          'variables': {
+            'source_file': 'android/application_status_listener.h',
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_library_load_from_apk_status_codes',
+          'type': 'none',
+          'variables': {
+            'source_file': 'android/library_loader/library_load_from_apk_status_codes.h'
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_memory_pressure_level',
+          'type': 'none',
+          'variables': {
+            'source_file': 'memory/memory_pressure_listener.h',
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_java_test_support
+          'target_name': 'base_java_test_support',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            '../testing/android/on_device_instrumentation.gyp:reporter_java',
+          ],
+          'variables': {
+            'java_in_dir': '../base/test/android/javatests',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base:base_junit_tests
+          'target_name': 'base_junit_tests',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_java_test_support',
+            '../testing/android/junit/junit_test.gyp:junit_test_support',
+          ],
+          'variables': {
+             'main_class': 'org.chromium.testing.local.JunitTestMain',
+             'src_paths': [
+               '../base/android/junit/',
+             ],
+           },
+          'includes': [ '../build/host_jar.gypi' ],
+        },
+        {
+          # GN: //base:base_javatests
+          'target_name': 'base_javatests',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_java_test_support',
+          ],
+          'variables': {
+            'java_in_dir': '../base/android/javatests',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base/android/linker:chromium_android_linker
+          'target_name': 'chromium_android_linker',
+          'type': 'shared_library',
+          'sources': [
+            'android/linker/linker_jni.cc',
+          ],
+          # The crazy linker is never instrumented.
+          'cflags!': [
+            '-finstrument-functions',
+          ],
+          'dependencies': [
+            # The NDK contains the crazy_linker here:
+            #   '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
+            # However, we use our own fork.  See bug 384700.
+            '../third_party/android_crazy_linker/crazy_linker.gyp:crazy_linker',
+          ],
+        },
+        {
+          # TODO(GN)
+          'target_name': 'base_perftests_apk',
+          'type': 'none',
+          'dependencies': [
+            'base_perftests',
+          ],
+          'variables': {
+            'test_suite_name': 'base_perftests',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+        {
+          # GN: //base:base_unittests_apk
+          'target_name': 'base_unittests_apk',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_unittests',
+          ],
+          'variables': {
+            'test_suite_name': 'base_unittests',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+      ],
+    }],
+    ['OS == "win"', {
+      'targets': [
+        {
+          'target_name': 'debug_message',
+          'type': 'executable',
+          'sources': [
+            'debug_message.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+            },
+          },
+        },
+        {
+          # Target to manually rebuild pe_image_test.dll which is checked into
+          # base/test/data/pe_image.
+          'target_name': 'pe_image_test',
+          'type': 'shared_library',
+          'sources': [
+            'win/pe_image_test.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'shell32.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'shell32.lib',
+              ],
+            },
+          },
+        },
+      ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'base_unittests',
+          ],
+          'includes': [
+            '../build/isolate.gypi',
+          ],
+          'sources': [
+            'base_unittests.isolate',
+          ],
+          'conditions': [
+            ['use_x11 == 1', {
+              'dependencies': [
+                '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
+              ],
+            }],
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/base.gypi b/base/base.gypi
new file mode 100644
index 0000000..cefc863
--- /dev/null
+++ b/base/base.gypi
@@ -0,0 +1,1031 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    'trace_event/trace_event.gypi',
+  ],
+  'target_defaults': {
+    'variables': {
+      'base_target': 0,
+      'base_i18n_target': 0,
+    },
+    'target_conditions': [
+      # This part is shared between the targets defined below.
+      ['base_target==1', {
+        'sources': [
+          '../build/build_config.h',
+          'allocator/allocator_extension.cc',
+          'allocator/allocator_extension.h',
+          'allocator/type_profiler_control.cc',
+          'allocator/type_profiler_control.h',
+          'android/animation_frame_time_histogram.cc',
+          'android/animation_frame_time_histogram.h',
+          'android/application_status_listener.cc',
+          'android/application_status_listener.h',
+          'android/base_jni_onload.cc',
+          'android/base_jni_onload.h',
+          'android/base_jni_registrar.cc',
+          'android/base_jni_registrar.h',
+          'android/build_info.cc',
+          'android/build_info.h',
+          'android/command_line_android.cc',
+          'android/command_line_android.h',
+          'android/content_uri_utils.cc',
+          'android/content_uri_utils.h',
+          'android/cpu_features.cc',
+          'android/event_log.cc',
+          'android/event_log.h',
+          'android/field_trial_list.cc',
+          'android/field_trial_list.h',
+          'android/fifo_utils.cc',
+          'android/fifo_utils.h',
+          'android/important_file_writer_android.cc',
+          'android/important_file_writer_android.h',
+          'android/java_handler_thread.cc',
+          'android/java_handler_thread.h',
+          'android/java_runtime.cc',
+          'android/java_runtime.h',
+          'android/jni_android.cc',
+          'android/jni_android.h',
+          'android/jni_array.cc',
+          'android/jni_array.h',
+          'android/jni_registrar.cc',
+          'android/jni_registrar.h',
+          'android/jni_string.cc',
+          'android/jni_string.h',
+          'android/jni_utils.cc',
+          'android/jni_utils.h',
+          'android/jni_weak_ref.cc',
+          'android/jni_weak_ref.h',
+          'android/library_loader/library_load_from_apk_status_codes.h',
+          'android/library_loader/library_loader_hooks.cc',
+          'android/library_loader/library_loader_hooks.h',
+          'android/library_loader/library_prefetcher.cc',
+          'android/library_loader/library_prefetcher.h',
+          'android/locale_utils.cc',
+          'android/locale_utils.h',
+          'android/memory_pressure_listener_android.cc',
+          'android/memory_pressure_listener_android.h',
+          'android/path_service_android.cc',
+          'android/path_service_android.h',
+          'android/path_utils.cc',
+          'android/path_utils.h',
+          'android/record_histogram.cc',
+          'android/record_histogram.h',
+          'android/record_user_action.cc',
+          'android/record_user_action.h',
+          'android/scoped_java_ref.cc',
+          'android/scoped_java_ref.h',
+          'android/sys_utils.cc',
+          'android/sys_utils.h',
+          'android/thread_utils.h',
+          'android/trace_event_binding.cc',
+          'android/trace_event_binding.h',
+          'at_exit.cc',
+          'at_exit.h',
+          'atomic_ref_count.h',
+          'atomic_sequence_num.h',
+          'atomicops.h',
+          'atomicops_internals_gcc.h',
+          'atomicops_internals_mac.h',
+          'atomicops_internals_portable.h',
+          'atomicops_internals_x86_gcc.cc',
+          'atomicops_internals_x86_gcc.h',
+          'atomicops_internals_x86_msvc.h',
+          'barrier_closure.cc',
+          'barrier_closure.h',
+          'base64.cc',
+          'base64.h',
+          'base_export.h',
+          'base_paths.cc',
+          'base_paths.h',
+          'base_paths_android.cc',
+          'base_paths_android.h',
+          'base_paths_mac.h',
+          'base_paths_mac.mm',
+          'base_paths_posix.cc',
+          'base_paths_posix.h',
+          'base_paths_win.cc',
+          'base_paths_win.h',
+          'base_switches.h',
+          'basictypes.h',
+          'big_endian.cc',
+          'big_endian.h',
+          'bind.h',
+          'bind_helpers.cc',
+          'bind_helpers.h',
+          'bind_internal.h',
+          'bind_internal_win.h',
+          'bits.h',
+          'build_time.cc',
+          'build_time.h',
+          'callback.h',
+          'callback_helpers.cc',
+          'callback_helpers.h',
+          'callback_internal.cc',
+          'callback_internal.h',
+          'callback_list.h',
+          'cancelable_callback.h',
+          'chromeos/memory_pressure_monitor_chromeos.cc',
+          'chromeos/memory_pressure_monitor_chromeos.h',
+          'command_line.cc',
+          'command_line.h',
+          'compiler_specific.h',
+          'containers/adapters.h',
+          'containers/hash_tables.h',
+          'containers/linked_list.h',
+          'containers/mru_cache.h',
+          'containers/scoped_ptr_hash_map.h',
+          'containers/small_map.h',
+          'containers/stack_container.h',
+          'cpu.cc',
+          'cpu.h',
+          'critical_closure.h',
+          'critical_closure_internal_ios.mm',
+          'debug/alias.cc',
+          'debug/alias.h',
+          'debug/asan_invalid_access.cc',
+          'debug/asan_invalid_access.h',
+          'debug/crash_logging.cc',
+          'debug/crash_logging.h',
+          'debug/debugger.cc',
+          'debug/debugger.h',
+          'debug/debugger_posix.cc',
+          'debug/debugger_win.cc',
+          'debug/dump_without_crashing.cc',
+          'debug/dump_without_crashing.h',
+          'debug/gdi_debug_util_win.cc',
+          'debug/gdi_debug_util_win.h',
+          # This file depends on files from the 'allocator' target,
+          # but this target does not depend on 'allocator' (see
+          # allocator.gyp for details).
+          'debug/leak_annotations.h',
+          'debug/leak_tracker.h',
+          'debug/proc_maps_linux.cc',
+          'debug/proc_maps_linux.h',
+          'debug/profiler.cc',
+          'debug/profiler.h',
+          'debug/stack_trace.cc',
+          'debug/stack_trace.h',
+          'debug/stack_trace_android.cc',
+          'debug/stack_trace_posix.cc',
+          'debug/stack_trace_win.cc',
+          'debug/task_annotator.cc',
+          'debug/task_annotator.h',
+          'deferred_sequenced_task_runner.cc',
+          'deferred_sequenced_task_runner.h',
+          'environment.cc',
+          'environment.h',
+          'file_descriptor_posix.h',
+          'file_version_info.h',
+          'file_version_info_mac.h',
+          'file_version_info_mac.mm',
+          'file_version_info_win.cc',
+          'file_version_info_win.h',
+          'files/dir_reader_fallback.h',
+          'files/dir_reader_linux.h',
+          'files/dir_reader_posix.h',
+          'files/file.cc',
+          'files/file.h',
+          'files/file_enumerator.cc',
+          'files/file_enumerator.h',
+          'files/file_enumerator_posix.cc',
+          'files/file_enumerator_win.cc',
+          'files/file_path.cc',
+          'files/file_path.h',
+          'files/file_path_constants.cc',
+          'files/file_path_watcher.cc',
+          'files/file_path_watcher.h',
+          'files/file_path_watcher_fsevents.cc',
+          'files/file_path_watcher_fsevents.h',
+          'files/file_path_watcher_kqueue.cc',
+          'files/file_path_watcher_kqueue.h',
+          'files/file_path_watcher_linux.cc',
+          'files/file_path_watcher_mac.cc',
+          'files/file_path_watcher_stub.cc',
+          'files/file_path_watcher_win.cc',
+          'files/file_posix.cc',
+          'files/file_proxy.cc',
+          'files/file_proxy.h',
+          'files/file_util.cc',
+          'files/file_util.h',
+          'files/file_util_android.cc',
+          'files/file_util_linux.cc',
+          'files/file_util_mac.mm',
+          'files/file_util_posix.cc',
+          'files/file_util_proxy.cc',
+          'files/file_util_proxy.h',
+          'files/file_util_win.cc',
+          'files/file_win.cc',
+          'files/important_file_writer.cc',
+          'files/important_file_writer.h',
+          'files/memory_mapped_file.cc',
+          'files/memory_mapped_file.h',
+          'files/memory_mapped_file_posix.cc',
+          'files/memory_mapped_file_win.cc',
+          'files/scoped_file.cc',
+          'files/scoped_file.h',
+          'files/scoped_temp_dir.cc',
+          'files/scoped_temp_dir.h',
+          'format_macros.h',
+          'gtest_prod_util.h',
+          'guid.cc',
+          'guid.h',
+          'guid_posix.cc',
+          'guid_win.cc',
+          'hash.cc',
+          'hash.h',
+          'id_map.h',
+          'ios/block_types.h',
+          'ios/crb_protocol_observers.h',
+          'ios/crb_protocol_observers.mm',
+          'ios/device_util.h',
+          'ios/device_util.mm',
+          'ios/ios_util.h',
+          'ios/ios_util.mm',
+          'ios/scoped_critical_action.h',
+          'ios/scoped_critical_action.mm',
+          'ios/weak_nsobject.h',
+          'ios/weak_nsobject.mm',
+          'json/json_file_value_serializer.cc',
+          'json/json_file_value_serializer.h',
+          'json/json_parser.cc',
+          'json/json_parser.h',
+          'json/json_reader.cc',
+          'json/json_reader.h',
+          'json/json_string_value_serializer.cc',
+          'json/json_string_value_serializer.h',
+          'json/json_value_converter.cc',
+          'json/json_value_converter.h',
+          'json/json_writer.cc',
+          'json/json_writer.h',
+          'json/string_escape.cc',
+          'json/string_escape.h',
+          'lazy_instance.cc',
+          'lazy_instance.h',
+          'location.cc',
+          'location.h',
+          'logging.cc',
+          'logging.h',
+          'logging_win.cc',
+          'logging_win.h',
+          'mac/authorization_util.h',
+          'mac/authorization_util.mm',
+          'mac/bind_objc_block.h',
+          'mac/bundle_locations.h',
+          'mac/bundle_locations.mm',
+          'mac/close_nocancel.cc',
+          'mac/cocoa_protocols.h',
+          'mac/foundation_util.h',
+          'mac/foundation_util.mm',
+          'mac/launch_services_util.cc',
+          'mac/launch_services_util.h',
+          'mac/launchd.cc',
+          'mac/launchd.h',
+          'mac/libdispatch_task_runner.cc',
+          'mac/libdispatch_task_runner.h',
+          'mac/mac_logging.cc',
+          'mac/mac_logging.h',
+          'mac/mac_util.h',
+          'mac/mac_util.mm',
+          'mac/mach_logging.cc',
+          'mac/mach_logging.h',
+          'mac/memory_pressure_monitor_mac.cc',
+          'mac/memory_pressure_monitor_mac.h',
+          'mac/objc_property_releaser.h',
+          'mac/objc_property_releaser.mm',
+          'mac/os_crash_dumps.cc',
+          'mac/os_crash_dumps.h',
+          'mac/scoped_aedesc.h',
+          'mac/scoped_authorizationref.h',
+          'mac/scoped_block.h',
+          'mac/scoped_cftyperef.h',
+          'mac/scoped_ioobject.h',
+          'mac/scoped_ioplugininterface.h',
+          'mac/scoped_launch_data.h',
+          'mac/scoped_mach_port.cc',
+          'mac/scoped_mach_port.h',
+          'mac/scoped_mach_vm.cc',
+          'mac/scoped_mach_vm.h',
+          'mac/scoped_nsautorelease_pool.h',
+          'mac/scoped_nsautorelease_pool.mm',
+          'mac/scoped_nsexception_enabler.h',
+          'mac/scoped_nsexception_enabler.mm',
+          'mac/scoped_nsobject.h',
+          'mac/scoped_objc_class_swizzler.h',
+          'mac/scoped_objc_class_swizzler.mm',
+          'mac/scoped_sending_event.h',
+          'mac/scoped_sending_event.mm',
+          'mac/scoped_typeref.h',
+          'mac/sdk_forward_declarations.h',
+          'mac/sdk_forward_declarations.mm',
+          'macros.h',
+          'md5.cc',
+          'md5.h',
+          'memory/aligned_memory.cc',
+          'memory/aligned_memory.h',
+          'memory/discardable_memory.cc',
+          'memory/discardable_memory.h',
+          'memory/discardable_memory_allocator.cc',
+          'memory/discardable_memory_allocator.h',
+          'memory/discardable_shared_memory.cc',
+          'memory/discardable_shared_memory.h',
+          'memory/linked_ptr.h',
+          'memory/manual_constructor.h',
+          'memory/memory_pressure_listener.cc',
+          'memory/memory_pressure_listener.h',
+          'memory/memory_pressure_monitor.cc',
+          'memory/memory_pressure_monitor.h',
+          'memory/raw_scoped_refptr_mismatch_checker.h',
+          'memory/ref_counted.cc',
+          'memory/ref_counted.h',
+          'memory/ref_counted_delete_on_message_loop.h',
+          'memory/ref_counted_memory.cc',
+          'memory/ref_counted_memory.h',
+          'memory/scoped_policy.h',
+          'memory/scoped_ptr.h',
+          'memory/scoped_vector.h',
+          'memory/shared_memory.h',
+          'memory/shared_memory_android.cc',
+          'memory/shared_memory_nacl.cc',
+          'memory/shared_memory_posix.cc',
+          'memory/shared_memory_win.cc',
+          'memory/singleton.cc',
+          'memory/singleton.h',
+          'memory/weak_ptr.cc',
+          'memory/weak_ptr.h',
+          'message_loop/incoming_task_queue.cc',
+          'message_loop/incoming_task_queue.h',
+          'message_loop/message_loop.cc',
+          'message_loop/message_loop.h',
+          'message_loop/message_loop_proxy.cc',
+          'message_loop/message_loop_proxy.h',
+          'message_loop/message_loop_proxy_impl.cc',
+          'message_loop/message_loop_proxy_impl.h',
+          'message_loop/message_pump.cc',
+          'message_loop/message_pump.h',
+          'message_loop/message_pump_android.cc',
+          'message_loop/message_pump_android.h',
+          'message_loop/message_pump_default.cc',
+          'message_loop/message_pump_default.h',
+          'message_loop/message_pump_win.cc',
+          'message_loop/message_pump_win.h',
+          'message_loop/timer_slack.h',
+          'metrics/bucket_ranges.cc',
+          'metrics/bucket_ranges.h',
+          'metrics/histogram.cc',
+          'metrics/histogram.h',
+          'metrics/histogram_base.cc',
+          'metrics/histogram_base.h',
+          'metrics/histogram_delta_serialization.cc',
+          'metrics/histogram_delta_serialization.h',
+          'metrics/histogram_flattener.h',
+          'metrics/histogram_macros.h',
+          'metrics/histogram_samples.cc',
+          'metrics/histogram_samples.h',
+          'metrics/histogram_snapshot_manager.cc',
+          'metrics/histogram_snapshot_manager.h',
+          'metrics/sample_map.cc',
+          'metrics/sample_map.h',
+          'metrics/sample_vector.cc',
+          'metrics/sample_vector.h',
+          'metrics/sparse_histogram.cc',
+          'metrics/sparse_histogram.h',
+          'metrics/statistics_recorder.cc',
+          'metrics/statistics_recorder.h',
+          'metrics/user_metrics.cc',
+          'metrics/user_metrics.h',
+          'metrics/user_metrics_action.h',
+          'move.h',
+          'native_library.h',
+          'native_library_ios.mm',
+          'native_library_mac.mm',
+          'native_library_posix.cc',
+          'native_library_win.cc',
+          'nix/mime_util_xdg.cc',
+          'nix/mime_util_xdg.h',
+          'nix/xdg_util.cc',
+          'nix/xdg_util.h',
+          'numerics/safe_conversions.h',
+          'numerics/safe_conversions_impl.h',
+          'numerics/safe_math.h',
+          'numerics/safe_math_impl.h',
+          'observer_list.h',
+          'observer_list_threadsafe.h',
+          'os_compat_android.cc',
+          'os_compat_android.h',
+          'os_compat_nacl.cc',
+          'os_compat_nacl.h',
+          'path_service.cc',
+          'path_service.h',
+          'pending_task.cc',
+          'pending_task.h',
+          'pickle.cc',
+          'pickle.h',
+          'port.h',
+          'posix/eintr_wrapper.h',
+          'posix/global_descriptors.cc',
+          'posix/global_descriptors.h',
+          'posix/unix_domain_socket_linux.cc',
+          'posix/unix_domain_socket_linux.h',
+          'power_monitor/power_monitor.cc',
+          'power_monitor/power_monitor.h',
+          'power_monitor/power_monitor_device_source.cc',
+          'power_monitor/power_monitor_device_source.h',
+          'power_monitor/power_monitor_device_source_android.cc',
+          'power_monitor/power_monitor_device_source_android.h',
+          'power_monitor/power_monitor_device_source_chromeos.cc',
+          'power_monitor/power_monitor_device_source_ios.mm',
+          'power_monitor/power_monitor_device_source_mac.mm',
+          'power_monitor/power_monitor_device_source_posix.cc',
+          'power_monitor/power_monitor_device_source_win.cc',
+          'power_monitor/power_monitor_source.cc',
+          'power_monitor/power_monitor_source.h',
+          'power_monitor/power_observer.h',
+          'process/internal_linux.cc',
+          'process/internal_linux.h',
+          'process/kill.cc',
+          'process/kill.h',
+          'process/kill_mac.cc',
+          'process/kill_posix.cc',
+          'process/kill_win.cc',
+          'process/launch.cc',
+          'process/launch.h',
+          'process/launch_ios.cc',
+          'process/launch_mac.cc',
+          'process/launch_posix.cc',
+          'process/launch_win.cc',
+          'process/memory.cc',
+          'process/memory.h',
+          'process/memory_linux.cc',
+          'process/memory_mac.mm',
+          'process/memory_win.cc',
+          'process/process.h',
+          'process/process_handle_freebsd.cc',
+          'process/process_handle_linux.cc',
+          'process/process_handle_mac.cc',
+          'process/process_handle_openbsd.cc',
+          'process/process_handle_posix.cc',
+          'process/process_handle_win.cc',
+          'process/process_info.h',
+          'process/process_info_linux.cc',
+          'process/process_info_mac.cc',
+          'process/process_info_win.cc',
+          'process/process_iterator.cc',
+          'process/process_iterator.h',
+          'process/process_iterator_freebsd.cc',
+          'process/process_iterator_linux.cc',
+          'process/process_iterator_mac.cc',
+          'process/process_iterator_openbsd.cc',
+          'process/process_iterator_win.cc',
+          'process/process_linux.cc',
+          'process/process_metrics.cc',
+          'process/process_metrics.h',
+          'process/process_metrics_freebsd.cc',
+          'process/process_metrics_ios.cc',
+          'process/process_metrics_linux.cc',
+          'process/process_metrics_mac.cc',
+          'process/process_metrics_openbsd.cc',
+          'process/process_metrics_posix.cc',
+          'process/process_metrics_win.cc',
+          'process/process_posix.cc',
+          'process/process_win.cc',
+          'profiler/alternate_timer.cc',
+          'profiler/alternate_timer.h',
+          'profiler/native_stack_sampler.cc',
+          'profiler/native_stack_sampler.h',
+          'profiler/scoped_profile.cc',
+          'profiler/scoped_profile.h',
+          'profiler/scoped_tracker.cc',
+          'profiler/scoped_tracker.h',
+          'profiler/stack_sampling_profiler.cc',
+          'profiler/stack_sampling_profiler.h',
+          'profiler/stack_sampling_profiler_posix.cc',
+          'profiler/stack_sampling_profiler_win.cc',
+          'profiler/tracked_time.cc',
+          'profiler/tracked_time.h',
+          'rand_util.cc',
+          'rand_util.h',
+          'rand_util_nacl.cc',
+          'rand_util_posix.cc',
+          'rand_util_win.cc',
+          'run_loop.cc',
+          'run_loop.h',
+          'safe_strerror_posix.cc',
+          'safe_strerror_posix.h',
+          'scoped_generic.h',
+          'scoped_native_library.cc',
+          'scoped_native_library.h',
+          'scoped_observer.h',
+          'sequence_checker.h',
+          'sequence_checker_impl.cc',
+          'sequence_checker_impl.h',
+          'sequenced_task_runner.cc',
+          'sequenced_task_runner.h',
+          'sequenced_task_runner_helpers.h',
+          'sha1.h',
+          'sha1_portable.cc',
+          'sha1_win.cc',
+          'single_thread_task_runner.h',
+          'stl_util.h',
+          'strings/latin1_string_conversions.cc',
+          'strings/latin1_string_conversions.h',
+          'strings/nullable_string16.cc',
+          'strings/nullable_string16.h',
+          'strings/safe_sprintf.cc',
+          'strings/safe_sprintf.h',
+          'strings/string16.cc',
+          'strings/string16.h',
+          'strings/string_number_conversions.cc',
+          'strings/string_number_conversions.h',
+          'strings/string_piece.cc',
+          'strings/string_piece.h',
+          'strings/string_split.cc',
+          'strings/string_split.h',
+          'strings/string_tokenizer.h',
+          'strings/string_util.cc',
+          'strings/string_util.h',
+          'strings/string_util_constants.cc',
+          'strings/string_util_posix.h',
+          'strings/string_util_win.h',
+          'strings/stringize_macros.h',
+          'strings/stringprintf.cc',
+          'strings/stringprintf.h',
+          'strings/sys_string_conversions.h',
+          'strings/sys_string_conversions_mac.mm',
+          'strings/sys_string_conversions_posix.cc',
+          'strings/sys_string_conversions_win.cc',
+          'strings/utf_offset_string_conversions.cc',
+          'strings/utf_offset_string_conversions.h',
+          'strings/utf_string_conversion_utils.cc',
+          'strings/utf_string_conversion_utils.h',
+          'strings/utf_string_conversions.cc',
+          'strings/utf_string_conversions.h',
+          'supports_user_data.cc',
+          'supports_user_data.h',
+          'synchronization/cancellation_flag.cc',
+          'synchronization/cancellation_flag.h',
+          'synchronization/condition_variable.h',
+          'synchronization/condition_variable_posix.cc',
+          'synchronization/condition_variable_win.cc',
+          'synchronization/lock.cc',
+          'synchronization/lock.h',
+          'synchronization/lock_impl.h',
+          'synchronization/lock_impl_posix.cc',
+          'synchronization/lock_impl_win.cc',
+          'synchronization/spin_wait.h',
+          'synchronization/waitable_event.h',
+          'synchronization/waitable_event_posix.cc',
+          'synchronization/waitable_event_watcher.h',
+          'synchronization/waitable_event_watcher_posix.cc',
+          'synchronization/waitable_event_watcher_win.cc',
+          'synchronization/waitable_event_win.cc',
+          'sys_byteorder.h',
+          'sys_info.cc',
+          'sys_info.h',
+          'sys_info_android.cc',
+          'sys_info_chromeos.cc',
+          'sys_info_freebsd.cc',
+          'sys_info_internal.h',
+          'sys_info_ios.mm',
+          'sys_info_linux.cc',
+          'sys_info_mac.cc',
+          'sys_info_openbsd.cc',
+          'sys_info_posix.cc',
+          'sys_info_win.cc',
+          'system_monitor/system_monitor.cc',
+          'system_monitor/system_monitor.h',
+          'task/cancelable_task_tracker.cc',
+          'task/cancelable_task_tracker.h',
+          'task_runner.cc',
+          'task_runner.h',
+          'task_runner_util.h',
+          'template_util.h',
+          'third_party/dmg_fp/dmg_fp.h',
+          'third_party/dmg_fp/dtoa_wrapper.cc',
+          'third_party/dmg_fp/g_fmt.cc',
+          'third_party/icu/icu_utf.cc',
+          'third_party/icu/icu_utf.h',
+          'third_party/nspr/prtime.cc',
+          'third_party/nspr/prtime.h',
+          'third_party/superfasthash/superfasthash.c',
+          'third_party/xdg_mime/xdgmime.h',
+          'thread_task_runner_handle.cc',
+          'thread_task_runner_handle.h',
+          'threading/non_thread_safe.h',
+          'threading/non_thread_safe_impl.cc',
+          'threading/non_thread_safe_impl.h',
+          'threading/platform_thread.h',
+          'threading/platform_thread_android.cc',
+          'threading/platform_thread_internal_posix.cc',
+          'threading/platform_thread_internal_posix.h',
+          'threading/platform_thread_linux.cc',
+          'threading/platform_thread_mac.mm',
+          'threading/platform_thread_posix.cc',
+          'threading/platform_thread_win.cc',
+          'threading/post_task_and_reply_impl.cc',
+          'threading/post_task_and_reply_impl.h',
+          'threading/sequenced_worker_pool.cc',
+          'threading/sequenced_worker_pool.h',
+          'threading/simple_thread.cc',
+          'threading/simple_thread.h',
+          'threading/thread.cc',
+          'threading/thread.h',
+          'threading/thread_checker.h',
+          'threading/thread_checker_impl.cc',
+          'threading/thread_checker_impl.h',
+          'threading/thread_collision_warner.cc',
+          'threading/thread_collision_warner.h',
+          'threading/thread_id_name_manager.cc',
+          'threading/thread_id_name_manager.h',
+          'threading/thread_local.h',
+          'threading/thread_local_android.cc',
+          'threading/thread_local_posix.cc',
+          'threading/thread_local_storage.cc',
+          'threading/thread_local_storage.h',
+          'threading/thread_local_storage_posix.cc',
+          'threading/thread_local_storage_win.cc',
+          'threading/thread_local_win.cc',
+          'threading/thread_restrictions.cc',
+          'threading/thread_restrictions.h',
+          'threading/watchdog.cc',
+          'threading/watchdog.h',
+          'threading/worker_pool.cc',
+          'threading/worker_pool.h',
+          'threading/worker_pool_posix.cc',
+          'threading/worker_pool_posix.h',
+          'threading/worker_pool_win.cc',
+          'time/clock.cc',
+          'time/clock.h',
+          'time/default_clock.cc',
+          'time/default_clock.h',
+          'time/default_tick_clock.cc',
+          'time/default_tick_clock.h',
+          'time/tick_clock.cc',
+          'time/tick_clock.h',
+          'time/time.cc',
+          'time/time.h',
+          'time/time_mac.cc',
+          'time/time_posix.cc',
+          'time/time_win.cc',
+          'timer/elapsed_timer.cc',
+          'timer/elapsed_timer.h',
+          'timer/hi_res_timer_manager.h',
+          'timer/hi_res_timer_manager_posix.cc',
+          'timer/hi_res_timer_manager_win.cc',
+          'timer/mock_timer.cc',
+          'timer/mock_timer.h',
+          'timer/timer.cc',
+          'timer/timer.h',
+          'tracked_objects.cc',
+          'tracked_objects.h',
+          'tracking_info.cc',
+          'tracking_info.h',
+          'tuple.h',
+          'value_conversions.cc',
+          'value_conversions.h',
+          'values.cc',
+          'values.h',
+          'version.cc',
+          'version.h',
+          'vlog.cc',
+          'vlog.h',
+          'win/enum_variant.cc',
+          'win/enum_variant.h',
+          'win/event_trace_consumer.h',
+          'win/event_trace_controller.cc',
+          'win/event_trace_controller.h',
+          'win/event_trace_provider.cc',
+          'win/event_trace_provider.h',
+          'win/i18n.cc',
+          'win/i18n.h',
+          'win/iat_patch_function.cc',
+          'win/iat_patch_function.h',
+          'win/iunknown_impl.cc',
+          'win/iunknown_impl.h',
+          'win/memory_pressure_monitor.cc',
+          'win/memory_pressure_monitor.h',
+          'win/message_window.cc',
+          'win/message_window.h',
+          'win/metro.cc',
+          'win/metro.h',
+          'win/object_watcher.cc',
+          'win/object_watcher.h',
+          'win/registry.cc',
+          'win/registry.h',
+          'win/resource_util.cc',
+          'win/resource_util.h',
+          'win/scoped_bstr.cc',
+          'win/scoped_bstr.h',
+          'win/scoped_co_mem.h',
+          'win/scoped_com_initializer.h',
+          'win/scoped_comptr.h',
+          'win/scoped_gdi_object.h',
+          'win/scoped_handle.cc',
+          'win/scoped_handle.h',
+          'win/scoped_hdc.h',
+          'win/scoped_hglobal.h',
+          'win/scoped_process_information.cc',
+          'win/scoped_process_information.h',
+          'win/scoped_propvariant.h',
+          'win/scoped_select_object.h',
+          'win/scoped_variant.cc',
+          'win/scoped_variant.h',
+          'win/shortcut.cc',
+          'win/shortcut.h',
+          'win/startup_information.cc',
+          'win/startup_information.h',
+          'win/win_util.cc',
+          'win/win_util.h',
+          'win/windows_version.cc',
+          'win/windows_version.h',
+          'win/wrapped_window_proc.cc',
+          'win/wrapped_window_proc.h',
+          '<@(trace_event_sources)',
+        ],
+        'defines': [
+          'BASE_IMPLEMENTATION',
+        ],
+        'include_dirs': [
+          '..',
+        ],
+        'msvs_disabled_warnings': [
+          4018,
+        ],
+        'target_conditions': [
+          ['(<(desktop_linux) == 0 and <(chromeos) == 0) or >(nacl_untrusted_build)==1', {
+              'sources/': [
+                ['exclude', '^nix/'],
+              ],
+              'sources!': [
+                'atomicops_internals_x86_gcc.cc',
+              ],
+          }],
+          ['<(use_glib)==0 or >(nacl_untrusted_build)==1', {
+              'sources!': [
+                'message_loop/message_pump_glib.cc',
+              ],
+          }],
+          ['(OS != "linux" and <(os_bsd) != 1 and OS != "android") or >(nacl_untrusted_build)==1', {
+              'sources!': [
+                # Not automatically excluded by the *linux.cc rules.
+                'linux_util.cc',
+              ],
+            },
+          ],
+          ['>(nacl_untrusted_build)==1', {
+            'sources!': [
+               'allocator/type_profiler_control.cc',
+               'allocator/type_profiler_control.h',
+               'base_paths.cc',
+               'cpu.cc',
+               'debug/stack_trace.cc',
+               'debug/stack_trace_posix.cc',
+               'files/file_enumerator_posix.cc',
+               'files/file_path_watcher_fsevents.cc',
+               'files/file_path_watcher_fsevents.h',
+               'files/file_path_watcher_kqueue.cc',
+               'files/file_path_watcher_kqueue.h',
+               'files/file_proxy.cc',
+               'files/file_util.cc',
+               'files/file_util_posix.cc',
+               'files/file_util_proxy.cc',
+               'files/important_file_writer.cc',
+               'files/scoped_temp_dir.cc',
+               'memory/shared_memory_posix.cc',
+               'native_library_posix.cc',
+               'path_service.cc',
+               'posix/unix_domain_socket_linux.cc',
+               'process/kill.cc',
+               'process/kill_posix.cc',
+               'process/launch.cc',
+               'process/launch_posix.cc',
+               'process/process_metrics.cc',
+               'process/process_metrics_posix.cc',
+               'process/process_posix.cc',
+               'rand_util_posix.cc',
+               'scoped_native_library.cc',
+               'sys_info.cc',
+               'sys_info_posix.cc',
+               'third_party/dynamic_annotations/dynamic_annotations.c',
+            ],
+            'sources/': [
+              ['include', '^threading/platform_thread_linux\\.cc$'],
+            ],
+          }],
+          ['OS == "android" and >(nacl_untrusted_build)==0', {
+            'sources!': [
+              'base_paths_posix.cc',
+              'files/file_path_watcher_fsevents.cc',
+              'files/file_path_watcher_fsevents.h',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_kqueue.h',
+              'files/file_path_watcher_stub.cc',
+              'power_monitor/power_monitor_device_source_posix.cc',
+            ],
+            'sources/': [
+              ['include', '^debug/proc_maps_linux\\.cc$'],
+              ['include', '^files/file_path_watcher_linux\\.cc$'],
+              ['include', '^process/memory_linux\\.cc$'],
+              ['include', '^process/internal_linux\\.cc$'],
+              ['include', '^process/process_handle_linux\\.cc$'],
+              ['include', '^process/process_iterator\\.cc$'],
+              ['include', '^process/process_iterator_linux\\.cc$'],
+              ['include', '^process/process_metrics_linux\\.cc$'],
+              ['include', '^posix/unix_domain_socket_linux\\.cc$'],
+              ['include', '^strings/sys_string_conversions_posix\\.cc$'],
+              ['include', '^sys_info_linux\\.cc$'],
+              ['include', '^worker_pool_linux\\.cc$'],
+            ],
+          }],
+          ['OS == "android" and _toolset == "host" and host_os == "linux"', {
+            'defines': [
+              'OS_ANDROID_HOST=Linux',
+            ],
+            'sources/': [
+              # Pull in specific files for host builds.
+              ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ['include', '^threading/platform_thread_linux\\.cc$'],
+            ],
+          }],
+          ['<(chromeos) == 1', {
+            'sources!': [
+              'power_monitor/power_monitor_device_source_posix.cc',
+            ],
+          }],
+          ['OS == "ios" and _toolset != "host"', {
+            'sources/': [
+              # Pull in specific Mac files for iOS (which have been filtered out
+              # by file name rules).
+              ['include', '^atomicops_internals_mac\\.'],
+              ['include', '^base_paths_mac\\.'],
+              ['include', '^files/file_util_mac\\.'],
+              ['include', '^file_version_info_mac\\.'],
+              ['include', '^mac/bundle_locations\\.'],
+              ['include', '^mac/foundation_util\\.'],
+              ['include', '^mac/mac_logging\\.'],
+              ['include', '^mac/mach_logging\\.'],
+              ['include', '^mac/objc_property_releaser\\.'],
+              ['include', '^mac/scoped_mach_port\\.'],
+              ['include', '^mac/scoped_mach_vm\\.'],
+              ['include', '^mac/scoped_nsautorelease_pool\\.'],
+              ['include', '^mac/scoped_nsobject\\.'],
+              ['include', '^mac/scoped_objc_class_swizzler\\.'],
+              ['include', '^message_loop/message_pump_mac\\.'],
+              ['include', '^strings/sys_string_conversions_mac\\.'],
+              ['include', '^threading/platform_thread_mac\\.'],
+              ['include', '^time/time_mac\\.'],
+              ['include', '^worker_pool_mac\\.'],
+              # Exclude all process/ except the minimal implementation
+              # needed on iOS (mostly for unit tests).
+              ['exclude', '^process/.*'],
+              ['include', '^process/.*_ios\.(cc|mm)$'],
+              ['include', '^process/memory_stubs\.cc$'],
+              ['include', '^process/process_handle_posix\.cc$'],
+              ['include', '^process/process_metrics\\.cc$'],
+              ['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
+              ['exclude', 'files/file_path_watcher_fsevents.cc'],
+              ['exclude', 'files/file_path_watcher_fsevents.h'],
+              ['include', 'files/file_path_watcher_mac.cc'],
+            ],
+            'sources': [
+              'process/memory_stubs.cc',
+            ],
+            'sources!': [
+              'message_loop/message_pump_libevent.cc'
+            ],
+          }],
+          ['OS == "ios" and _toolset == "host"', {
+            'sources/': [
+              # Copied filename_rules to switch from iOS to Mac inclusions.
+              ['include', '_(cocoa|mac)(_unittest)?\\.(h|cc|mm?)$'],
+              ['include', '(^|/)(cocoa|mac)/'],
+              ['exclude', '_ios(_unittest)?\\.(h|cc|mm?)$'],
+              ['exclude', '(^|/)ios/'],
+              ['exclude', 'files/file_path_watcher_fsevents.cc'],
+              ['exclude', 'files/file_path_watcher_fsevents.h'],
+              ['include', 'files/file_path_watcher_mac.cc'],
+            ]
+          }],
+          # For now, just test the *BSD platforms enough to exclude them.
+          # Subsequent changes will include them further.
+          ['OS != "freebsd" or >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '_freebsd\\.cc$'] ],
+            },
+          ],
+          ['OS != "openbsd" or >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '_openbsd\\.cc$'] ],
+            },
+          ],
+          ['OS == "win" and >(nacl_untrusted_build)==0', {
+            'include_dirs': [
+              '<(DEPTH)/third_party/wtl/include',
+            ],
+            'sources!': [
+              'files/file_path_watcher_fsevents.cc',
+              'files/file_path_watcher_fsevents.h',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_kqueue.h',
+              'files/file_path_watcher_stub.cc',
+              'message_loop/message_pump_libevent.cc',
+              'posix/file_descriptor_shuffle.cc',
+              # Not using sha1_win.cc because it may have caused a
+              # regression to page cycler moz.
+              'sha1_win.cc',
+              'strings/string16.cc',
+            ],
+          },],
+          ['<(use_ozone) == 1', {
+            'sources!': [
+              'message_loop/message_pump_glib.cc',
+            ]
+          }],
+          ['OS == "linux" and >(nacl_untrusted_build)==0', {
+            'sources!': [
+              'files/file_path_watcher_fsevents.cc',
+              'files/file_path_watcher_fsevents.h',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_kqueue.h',
+              'files/file_path_watcher_stub.cc',
+            ],
+          }],
+          ['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', {
+            'sources/': [
+              ['exclude', '^base_paths_posix\\.cc$'],
+              ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+              ['exclude', '^native_library_posix\\.cc$'],
+              ['exclude', '^strings/sys_string_conversions_posix\\.cc$'],
+              ['exclude', '^threading/platform_thread_internal_posix\\.cc$'],
+            ],
+          }],
+          ['<(os_bsd)==1 and >(nacl_untrusted_build)==0', {
+            'sources': [
+              'process/memory_stubs.cc',
+            ],
+            'sources/': [
+              ['exclude', '^files/file_path_watcher_linux\\.cc$'],
+              ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+              ['exclude', '^files/file_util_linux\\.cc$'],
+              ['exclude', '^process/process_linux\\.cc$'],
+              ['exclude', '^sys_info_linux\\.cc$'],
+            ],
+          }],
+          # Remove all unnecessary files for build_nexe.py to avoid exceeding
+          # command-line-string limitation when building NaCl on Windows.
+          ['OS == "win" and >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '\\.h$'] ],
+          }],
+          # Enable more direct string conversions on platforms with native utf8
+          # strings
+          ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+            'defines': ['SYSTEM_NATIVE_UTF8'],
+          }],
+        ],
+      }],
+      ['base_i18n_target==1', {
+        'defines': [
+          'BASE_I18N_IMPLEMENTATION',
+        ],
+        'sources': [
+          'i18n/base_i18n_export.h',
+          'i18n/bidi_line_iterator.cc',
+          'i18n/bidi_line_iterator.h',
+          'i18n/break_iterator.cc',
+          'i18n/break_iterator.h',
+          'i18n/case_conversion.cc',
+          'i18n/case_conversion.h',
+          'i18n/char_iterator.cc',
+          'i18n/char_iterator.h',
+          'i18n/file_util_icu.cc',
+          'i18n/file_util_icu.h',
+          'i18n/i18n_constants.cc',
+          'i18n/i18n_constants.h',
+          'i18n/icu_encoding_detection.cc',
+          'i18n/icu_encoding_detection.h',
+          'i18n/icu_string_conversions.cc',
+          'i18n/icu_string_conversions.h',
+          'i18n/icu_util.cc',
+          'i18n/icu_util.h',
+          'i18n/number_formatting.cc',
+          'i18n/number_formatting.h',
+          'i18n/rtl.cc',
+          'i18n/rtl.h',
+          'i18n/streaming_utf8_validator.cc',
+          'i18n/streaming_utf8_validator.h',
+          'i18n/string_compare.cc',
+          'i18n/string_compare.h',
+          'i18n/string_search.cc',
+          'i18n/string_search.h',
+          'i18n/time_formatting.cc',
+          'i18n/time_formatting.h',
+          'i18n/timezone.cc',
+          'i18n/timezone.h',
+          'i18n/utf8_validator_tables.cc',
+          'i18n/utf8_validator_tables.h',
+        ],
+      }]
+    ],
+  },
+}
diff --git a/base/base.isolate b/base/base.isolate
new file mode 100644
index 0000000..c7ba651
--- /dev/null
+++ b/base/base.isolate
@@ -0,0 +1,98 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'includes': [
+    # While the target 'base' doesn't depend on ../third_party/icu/icu.gyp
+    # itself, virtually all targets using it has to include icu. The only
+    # exception is the Windows sandbox (?).
+    '../third_party/icu/icu.isolate',
+    # Sanitizer-instrumented third-party libraries (if enabled).
+    '../third_party/instrumented_libraries/instrumented_libraries.isolate',
+  ],
+  'conditions': [
+    ['use_custom_libcxx==1', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/lib/libc++.so',
+        ],
+      },
+    }],
+    ['OS=="mac" and asan==1', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/libclang_rt.asan_osx_dynamic.dylib',
+        ],
+      },
+    }],
+    ['OS=="win"', {
+      # Required for base/stack_trace_win.cc to symbolize correctly.
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/dbghelp.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and asan==1 and component=="shared_library"', {
+      'variables': {
+        'files': [
+          '../third_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll',
+        ],
+      },
+    }],
+    ['OS=="linux" and (asan==1 or lsan==1 or msan==1 or tsan==1)', {
+      'variables': {
+        'files': [
+          # For llvm-symbolizer.
+          '../third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6',
+        ],
+      },
+    }],
+    ['asan==1 or lsan==1 or msan==1 or tsan==1', {
+      'variables': {
+        'files': [
+          '../tools/valgrind/asan/',
+          '../third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer<(EXECUTABLE_SUFFIX)',
+        ],
+      },
+    }],
+    # Copy the VS runtime DLLs into the isolate so that they
+    # don't have to be preinstalled on the target machine.
+    ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp120d.dll',
+          '<(PRODUCT_DIR)/x64/msvcr120d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Release"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp120.dll',
+          '<(PRODUCT_DIR)/x64/msvcr120.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Debug" or CONFIGURATION_NAME=="Debug_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp120d.dll',
+          '<(PRODUCT_DIR)/msvcr120d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp120.dll',
+          '<(PRODUCT_DIR)/msvcr120.dll',
+        ],
+      },
+    }],
+    # Workaround for https://code.google.com/p/swarming/issues/detail?id=211
+    ['asan==0 or lsan==0 or msan==0 or tsan==0', {
+      'variables': {},
+    }],
+  ],
+}
diff --git a/base/base64.cc b/base/base64.cc
new file mode 100644
index 0000000..8ed1249
--- /dev/null
+++ b/base/base64.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64.h"
+
+#include "third_party/modp_b64/modp_b64.h"
+
+namespace base {
+
+void Base64Encode(const StringPiece& input, std::string* output) {
+  std::string temp;
+  temp.resize(modp_b64_encode_len(input.size()));  // makes room for null byte
+
+  // modp_b64_encode_len() returns at least 1, so temp[0] is safe to use.
+  size_t output_size = modp_b64_encode(&(temp[0]), input.data(), input.size());
+
+  temp.resize(output_size);  // strips off null byte
+  output->swap(temp);
+}
+
+bool Base64Decode(const StringPiece& input, std::string* output) {
+  std::string temp;
+  temp.resize(modp_b64_decode_len(input.size()));
+
+  // does not null terminate result since result is binary data!
+  size_t input_size = input.size();
+  size_t output_size = modp_b64_decode(&(temp[0]), input.data(), input_size);
+  if (output_size == MODP_B64_ERROR)
+    return false;
+
+  temp.resize(output_size);
+  output->swap(temp);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base64.h b/base/base64.h
new file mode 100644
index 0000000..def9b67
--- /dev/null
+++ b/base/base64.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE64_H__
+#define BASE_BASE64_H__
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Encodes the input string in base64. The encoding can be done in-place.
+BASE_EXPORT void Base64Encode(const StringPiece& input, std::string* output);
+
+// Decodes the base64 input string.  Returns true if successful and false
+// otherwise. The output string is only modified if successful. The decoding can
+// be done in-place.
+BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
+
+}  // namespace base
+
+#endif  // BASE_BASE64_H__
diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc
new file mode 100644
index 0000000..91651f4
--- /dev/null
+++ b/base/base64_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(Base64Test, Basic) {
+  const std::string kText = "hello world";
+  const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+
+  std::string encoded;
+  std::string decoded;
+  bool ok;
+
+  Base64Encode(kText, &encoded);
+  EXPECT_EQ(kBase64Text, encoded);
+
+  ok = Base64Decode(encoded, &decoded);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(kText, decoded);
+}
+
+TEST(Base64Test, InPlace) {
+  const std::string kText = "hello world";
+  const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+  std::string text(kText);
+
+  Base64Encode(text, &text);
+  EXPECT_EQ(kBase64Text, text);
+
+  bool ok = Base64Decode(text, &text);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(text, kText);
+}
+
+}  // namespace base
diff --git a/base/base_export.h b/base/base_export.h
new file mode 100644
index 0000000..723b38a
--- /dev/null
+++ b/base/base_export.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#define BASE_EXPORT_PRIVATE __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#define BASE_EXPORT_PRIVATE __declspec(dllimport)
+#endif  // defined(BASE_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
+#else
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif  // defined(BASE_IMPLEMENTATION)
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif
+
+#endif  // BASE_BASE_EXPORT_H_
diff --git a/base/base_nacl.gyp b/base/base_nacl.gyp
new file mode 100644
index 0000000..40005d2
--- /dev/null
+++ b/base/base_nacl.gyp
@@ -0,0 +1,118 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    # base.gypi must be included before common_untrusted.gypi.
+    #
+    # TODO(sergeyu): Replace the target_defaults magic in base.gypi with a
+    # sources variables lists. That way order of includes will not matter.
+    'base.gypi',
+    '../build/common_untrusted.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'base_nacl',
+          'type': 'none',
+          'variables': {
+            'base_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_nacl.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 1,
+            'build_pnacl_newlib': 1,
+            'sources': [
+              'base_switches.cc',
+              'base_switches.h',
+              'strings/string16.cc',
+              'sync_socket_nacl.cc',
+              'time/time_posix.cc',
+            ],
+            'gcc_compile_flags': [
+              '-fno-strict-aliasing',
+            ],
+          },
+        },
+        {
+          'target_name': 'base_i18n_nacl',
+          'type': 'none',
+          'variables': {
+            'base_i18n_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_i18n_nacl.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 1,
+            'sources': [
+              'base_switches.cc',
+              'base_switches.h',
+              'strings/string16.cc',
+              'sync_socket_nacl.cc',
+              'time/time_posix.cc',
+            ],
+          },
+          'dependencies': [
+            '../third_party/icu/icu_nacl.gyp:icudata_nacl',
+            '../third_party/icu/icu_nacl.gyp:icui18n_nacl',
+            '../third_party/icu/icu_nacl.gyp:icuuc_nacl',
+          ],
+        },
+        {
+          'target_name': 'base_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'base_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'base_switches.cc',
+              'base_switches.h',
+
+              # For PathExists and ReadFromFD.
+              'files/file_util_posix.cc',
+
+              # For MessageLoopForIO based on libevent.
+              'message_loop/message_pump_libevent.cc',
+              'message_loop/message_pump_libevent.h',
+
+              # For UnixDomainSocket::SendMsg and RecvMsg.
+              'posix/unix_domain_socket_linux.cc',
+
+              # For GetKnownDeadTerminationStatus and GetTerminationStatus.
+              'process/kill_posix.cc',
+
+              # Unlike libbase_nacl, for Non-SFI build, we need to use
+              # rand_util_posix for random implementation, instead of
+              # rand_util_nacl.cc, which is based on IRT. rand_util_nacl.cc is
+              # excluded below.
+              'rand_util_posix.cc',
+
+              # For CancelableSyncSocket.
+              'sync_socket_nacl.cc',
+            ],
+          },
+          'sources!': [
+            'rand_util_nacl.cc',
+          ],
+          'dependencies': [
+            '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/base_paths.cc b/base/base_paths.cc
new file mode 100644
index 0000000..7076ec3
--- /dev/null
+++ b/base/base_paths.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_paths.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+
+namespace base {
+
+bool PathProvider(int key, FilePath* result) {
+  // NOTE: DIR_CURRENT is a special case in PathService::Get
+
+  switch (key) {
+    case DIR_EXE:
+      PathService::Get(FILE_EXE, result);
+      *result = result->DirName();
+      return true;
+    case DIR_MODULE:
+      PathService::Get(FILE_MODULE, result);
+      *result = result->DirName();
+      return true;
+    case DIR_TEMP:
+      if (!GetTempDir(result))
+        return false;
+      return true;
+    case base::DIR_HOME:
+      *result = GetHomeDir();
+      return true;
+    case DIR_TEST_DATA:
+      if (!PathService::Get(DIR_SOURCE_ROOT, result))
+        return false;
+      *result = result->Append(FILE_PATH_LITERAL("base"));
+      *result = result->Append(FILE_PATH_LITERAL("test"));
+      *result = result->Append(FILE_PATH_LITERAL("data"));
+      if (!PathExists(*result))  // We don't want to create this.
+        return false;
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths.h b/base/base_paths.h
new file mode 100644
index 0000000..26b2fd4
--- /dev/null
+++ b/base/base_paths.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_H_
+#define BASE_BASE_PATHS_H_
+
+// This file declares path keys for the base module.  These can be used with
+// the PathService to access various special directories and files.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#elif defined(OS_ANDROID)
+#include "base/base_paths_android.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "base/base_paths_posix.h"
+#endif
+
+namespace base {
+
+enum BasePathKey {
+  PATH_START = 0,
+
+  DIR_CURRENT,       // Current directory.
+  DIR_EXE,           // Directory containing FILE_EXE.
+  DIR_MODULE,        // Directory containing FILE_MODULE.
+  DIR_TEMP,          // Temporary directory.
+  DIR_HOME,          // User's root home directory. On Windows this will look
+                     // like "C:\Users\you" (or on XP
+                     // "C:\Document and Settings\you") which isn't necessarily
+                     // a great place to put files.
+  FILE_EXE,          // Path and filename of the current executable.
+  FILE_MODULE,       // Path and filename of the module containing the code for
+                     // the PathService (which could differ from FILE_EXE if the
+                     // PathService were compiled into a shared object, for
+                     // example).
+  DIR_SOURCE_ROOT,   // Returns the root of the source tree. This key is useful
+                     // for tests that need to locate various resources. It
+                     // should not be used outside of test code.
+  DIR_USER_DESKTOP,  // The current user's Desktop.
+
+  DIR_TEST_DATA,     // Used only for testing.
+
+  PATH_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_H_
diff --git a/base/base_paths_android.cc b/base/base_paths_android.cc
new file mode 100644
index 0000000..56c6cc7
--- /dev/null
+++ b/base/base_paths_android.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines base::PathProviderAndroid which replaces base::PathProviderPosix for
+// Android in base/path_service.cc.
+
+#include <unistd.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/path_utils.h"
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+namespace base {
+
+bool PathProviderAndroid(int key, FilePath* result) {
+  switch (key) {
+    case base::FILE_EXE: {
+      char bin_dir[PATH_MAX + 1];
+      int bin_dir_size = readlink(kProcSelfExe, bin_dir, PATH_MAX);
+      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
+        NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
+        return false;
+      }
+      bin_dir[bin_dir_size] = 0;
+      *result = FilePath(bin_dir);
+      return true;
+    }
+    case base::FILE_MODULE:
+      // dladdr didn't work in Android as only the file name was returned.
+      NOTIMPLEMENTED();
+      return false;
+    case base::DIR_MODULE:
+      return base::android::GetNativeLibraryDirectory(result);
+    case base::DIR_SOURCE_ROOT:
+      // This const is only used for tests.
+      return base::android::GetExternalStorageDirectory(result);
+    case base::DIR_USER_DESKTOP:
+      // Android doesn't support GetUserDesktop.
+      NOTIMPLEMENTED();
+      return false;
+    case base::DIR_CACHE:
+      return base::android::GetCacheDirectory(result);
+    case base::DIR_ANDROID_APP_DATA:
+      return base::android::GetDataDirectory(result);
+    case base::DIR_ANDROID_EXTERNAL_STORAGE:
+      return base::android::GetExternalStorageDirectory(result);
+    default:
+      // Note: the path system expects this function to override the default
+      // behavior. So no need to log an error if we don't support a given
+      // path. The system will just use the default.
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths_android.h b/base/base_paths_android.h
new file mode 100644
index 0000000..7a9ac4a
--- /dev/null
+++ b/base/base_paths_android.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_ANDROID_H_
+#define BASE_BASE_PATHS_ANDROID_H_
+
+// This file declares Android-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_ANDROID_START = 300,
+
+  DIR_ANDROID_APP_DATA,  // Directory where to put Android app's data.
+  DIR_ANDROID_EXTERNAL_STORAGE,  // Android external storage directory.
+
+  PATH_ANDROID_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_ANDROID_H_
diff --git a/base/base_paths_mac.h b/base/base_paths_mac.h
new file mode 100644
index 0000000..ac75402
--- /dev/null
+++ b/base/base_paths_mac.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_MAC_H_
+#define BASE_BASE_PATHS_MAC_H_
+
+// This file declares Mac-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_MAC_START = 200,
+
+  DIR_APP_DATA,  // ~/Library/Application Support
+
+  PATH_MAC_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_MAC_H_
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
new file mode 100644
index 0000000..9864eb3
--- /dev/null
+++ b/base/base_paths_mac.mm
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
+// in base/path_service.cc.
+
+#include <dlfcn.h>
+#import <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+
+#include "base/base_paths.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+
+namespace {
+
+void GetNSExecutablePath(base::FilePath* path) {
+  DCHECK(path);
+  // Executable path can have relative references ("..") depending on
+  // how the app was launched.
+  uint32_t executable_length = 0;
+  _NSGetExecutablePath(NULL, &executable_length);
+  DCHECK_GT(executable_length, 1u);
+  std::string executable_path;
+  int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
+                                &executable_length);
+  DCHECK_EQ(rv, 0);
+
+  // _NSGetExecutablePath may return paths containing ./ or ../ which makes
+  // FilePath::DirName() work incorrectly, convert it to absolute path so that
+  // paths such as DIR_SOURCE_ROOT can work, since we expect absolute paths to
+  // be returned here.
+  *path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
+}
+
+// Returns true if the module for |address| is found. |path| will contain
+// the path to the module. Note that |path| may not be absolute.
+bool GetModulePathForAddress(base::FilePath* path,
+                             const void* address) WARN_UNUSED_RESULT;
+
+bool GetModulePathForAddress(base::FilePath* path, const void* address) {
+  Dl_info info;
+  if (dladdr(address, &info) == 0)
+    return false;
+  *path = base::FilePath(info.dli_fname);
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+bool PathProviderMac(int key, base::FilePath* result) {
+  switch (key) {
+    case base::FILE_EXE:
+      GetNSExecutablePath(result);
+      return true;
+    case base::FILE_MODULE:
+      return GetModulePathForAddress(result,
+          reinterpret_cast<const void*>(&base::PathProviderMac));
+    case base::DIR_APP_DATA: {
+      bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
+                                                 result);
+#if defined(OS_IOS)
+      // On IOS, this directory does not exist unless it is created explicitly.
+      if (success && !base::PathExists(*result))
+        success = base::CreateDirectory(*result);
+#endif  // defined(OS_IOS)
+      return success;
+    }
+    case base::DIR_SOURCE_ROOT:
+      // Go through PathService to catch overrides.
+      if (!PathService::Get(base::FILE_EXE, result))
+        return false;
+
+      // Start with the executable's directory.
+      *result = result->DirName();
+
+#if !defined(OS_IOS)
+      if (base::mac::AmIBundled()) {
+        // The bundled app executables (Chromium, TestShell, etc) live five
+        // levels down, eg:
+        // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
+        *result = result->DirName().DirName().DirName().DirName().DirName();
+      } else {
+        // Unit tests execute two levels deep from the source root, eg:
+        // src/xcodebuild/{Debug|Release}/base_unittests
+        *result = result->DirName().DirName();
+      }
+#endif
+      return true;
+    case base::DIR_USER_DESKTOP:
+#if defined(OS_IOS)
+      // iOS does not have desktop directories.
+      NOTIMPLEMENTED();
+      return false;
+#else
+      return base::mac::GetUserDirectory(NSDesktopDirectory, result);
+#endif
+    case base::DIR_CACHE:
+      return base::mac::GetUserDirectory(NSCachesDirectory, result);
+    default:
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc
new file mode 100644
index 0000000..048434f
--- /dev/null
+++ b/base/base_paths_posix.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines base::PathProviderPosix, default path provider on POSIX OSes that
+// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and
+// Android).
+
+#include <ostream>
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/nix/xdg_util.h"
+#include "base/path_service.h"
+#include "base/process/process_metrics.h"
+#include "build/build_config.h"
+
+#if defined(OS_FREEBSD)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#elif defined(OS_SOLARIS)
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+bool PathProviderPosix(int key, FilePath* result) {
+  FilePath path;
+  switch (key) {
+    case base::FILE_EXE:
+    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
+#if defined(OS_LINUX)
+      FilePath bin_dir;
+      if (!ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) {
+        NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
+        return false;
+      }
+      *result = bin_dir;
+      return true;
+#elif defined(OS_FREEBSD)
+      int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+      char bin_dir[PATH_MAX + 1];
+      size_t length = sizeof(bin_dir);
+      // Upon return, |length| is the number of bytes written to |bin_dir|
+      // including the string terminator.
+      int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
+      if (error < 0 || length <= 1) {
+        NOTREACHED() << "Unable to resolve path.";
+        return false;
+      }
+      *result = FilePath(FilePath::StringType(bin_dir, length - 1));
+      return true;
+#elif defined(OS_SOLARIS)
+      char bin_dir[PATH_MAX + 1];
+      if (realpath(getexecname(), bin_dir) == NULL) {
+        NOTREACHED() << "Unable to resolve " << getexecname() << ".";
+        return false;
+      }
+      *result = FilePath(bin_dir);
+      return true;
+#elif defined(OS_OPENBSD)
+      // There is currently no way to get the executable path on OpenBSD
+      char* cpath;
+      if ((cpath = getenv("CHROME_EXE_PATH")) != NULL)
+        *result = FilePath(cpath);
+      else
+        *result = FilePath("/usr/local/chrome/chrome");
+      return true;
+#endif
+    }
+    case base::DIR_SOURCE_ROOT: {
+      // Allow passing this in the environment, for more flexibility in build
+      // tree configurations (sub-project builds, gyp --output_dir, etc.)
+      scoped_ptr<base::Environment> env(base::Environment::Create());
+      std::string cr_source_root;
+      if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) {
+        path = FilePath(cr_source_root);
+        if (base::PathExists(path)) {
+          *result = path;
+          return true;
+        } else {
+          DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
+                        << "point to a directory.";
+        }
+      }
+      // On POSIX, unit tests execute two levels deep from the source root.
+      // For example:  out/{Debug|Release}/net_unittest
+      if (PathService::Get(base::DIR_EXE, &path)) {
+        *result = path.DirName().DirName();
+        return true;
+      }
+
+      DLOG(ERROR) << "Couldn't find your source root.  "
+                  << "Try running from your chromium/src directory.";
+      return false;
+    }
+    case base::DIR_USER_DESKTOP:
+      *result = base::nix::GetXDGUserDirectory("DESKTOP", "Desktop");
+      return true;
+    case base::DIR_CACHE: {
+      scoped_ptr<base::Environment> env(base::Environment::Create());
+      FilePath cache_dir(base::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
+                                                    ".cache"));
+      *result = cache_dir;
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/base_paths_posix.h b/base/base_paths_posix.h
new file mode 100644
index 0000000..ef002ae
--- /dev/null
+++ b/base/base_paths_posix.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_POSIX_H_
+#define BASE_BASE_PATHS_POSIX_H_
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_POSIX_START = 400,
+
+  DIR_CACHE,    // Directory where to put cache data.  Note this is
+                // *not* where the browser cache lives, but the
+                // browser cache can be a subdirectory.
+                // This is $XDG_CACHE_HOME on Linux and
+                // ~/Library/Caches on Mac.
+  PATH_POSIX_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_POSIX_H_
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
new file mode 100644
index 0000000..4ecb59d
--- /dev/null
+++ b/base/base_paths_win.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <shlobj.h>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/windows_version.h"
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+using base::FilePath;
+
+namespace base {
+
+bool PathProviderWin(int key, FilePath* result) {
+  // We need to go compute the value. It would be nice to support paths with
+  // names longer than MAX_PATH, but the system functions don't seem to be
+  // designed for it either, with the exception of GetTempPath (but other
+  // things will surely break if the temp path is too long, so we don't bother
+  // handling it.
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+
+  FilePath cur;
+  switch (key) {
+    case base::FILE_EXE:
+      GetModuleFileName(NULL, system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::FILE_MODULE: {
+      // the resource containing module is assumed to be the one that
+      // this code lives in, whether that's a dll or exe
+      HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+      GetModuleFileName(this_module, system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    }
+    case base::DIR_WINDOWS:
+      GetWindowsDirectory(system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_SYSTEM:
+      GetSystemDirectory(system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_PROGRAM_FILESX86:
+      if (base::win::OSInfo::GetInstance()->architecture() !=
+          base::win::OSInfo::X86_ARCHITECTURE) {
+        if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
+                                   SHGFP_TYPE_CURRENT, system_buffer)))
+          return false;
+        cur = FilePath(system_buffer);
+        break;
+      }
+      // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
+    case base::DIR_PROGRAM_FILES:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_PROGRAM_FILES6432:
+#if !defined(_WIN64)
+      if (base::win::OSInfo::GetInstance()->wow64_status() ==
+          base::win::OSInfo::WOW64_ENABLED) {
+        scoped_ptr<base::Environment> env(base::Environment::Create());
+        std::string programfiles_w6432;
+        // 32-bit process running in WOW64 sets ProgramW6432 environment
+        // variable. See
+        // https://msdn.microsoft.com/library/windows/desktop/aa384274.aspx.
+        if (!env->GetVar("ProgramW6432", &programfiles_w6432))
+          return false;
+        // GetVar returns UTF8 - convert back to Wide.
+        cur = FilePath(UTF8ToWide(programfiles_w6432));
+        break;
+      }
+#endif
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_IE_INTERNET_CACHE:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_START_MENU:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_START_MENU:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
+                                 system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_LOCAL_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_SOURCE_ROOT: {
+      FilePath executableDir;
+      // On Windows, unit tests execute two levels deep from the source root.
+      // For example:  chrome/{Debug|Release}/ui_tests.exe
+      PathService::Get(base::DIR_EXE, &executableDir);
+      cur = executableDir.DirName().DirName();
+      break;
+    }
+    case base::DIR_APP_SHORTCUTS: {
+      if (win::GetVersion() < win::VERSION_WIN8)
+        return false;
+
+      base::win::ScopedCoMem<wchar_t> path_buf;
+      if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
+                                      &path_buf)))
+        return false;
+
+      cur = FilePath(string16(path_buf));
+      break;
+    }
+    case base::DIR_USER_DESKTOP:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_DESKTOP:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_USER_QUICK_LAUNCH:
+      if (!PathService::Get(base::DIR_APP_DATA, &cur))
+        return false;
+      // According to various sources, appending
+      // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
+      // reliable way to get the quick launch folder across all versions of
+      // Windows.
+      // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
+      // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
+      cur = cur.AppendASCII("Microsoft")
+                .AppendASCII("Internet Explorer")
+                .AppendASCII("Quick Launch");
+      break;
+    case base::DIR_TASKBAR_PINS:
+      if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
+        return false;
+      cur = cur.AppendASCII("User Pinned");
+      cur = cur.AppendASCII("TaskBar");
+      break;
+    case base::DIR_WINDOWS_FONTS:
+      if (FAILED(SHGetFolderPath(
+              NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    default:
+      return false;
+  }
+
+  *result = cur;
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
new file mode 100644
index 0000000..4ab6af1
--- /dev/null
+++ b/base/base_paths_win.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_WIN_H__
+#define BASE_BASE_PATHS_WIN_H__
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_WIN_START = 100,
+
+  DIR_WINDOWS,  // Windows directory, usually "c:\windows"
+  DIR_SYSTEM,   // Usually c:\windows\system32"
+  //                         32-bit     32-bit on 64-bit   64-bit on 64-bit
+  // DIR_PROGRAM_FILES         1               2                  1
+  // DIR_PROGRAM_FILESX86      1               2                  2
+  // DIR_PROGRAM_FILES6432     1               1                  1
+  // 1 - C:\Program Files   2 - C:\Program Files (x86)
+  DIR_PROGRAM_FILES,      // See table above.
+  DIR_PROGRAM_FILESX86,   // See table above.
+  DIR_PROGRAM_FILES6432,  // See table above.
+
+  DIR_IE_INTERNET_CACHE,  // Temporary Internet Files directory.
+  DIR_COMMON_START_MENU,  // Usually "C:\Documents and Settings\All Users\
+                          // Start Menu\Programs"
+  DIR_START_MENU,         // Usually "C:\Documents and Settings\<user>\
+                          // Start Menu\Programs"
+  DIR_APP_DATA,           // Application Data directory under the user profile.
+  DIR_LOCAL_APP_DATA,     // "Local Settings\Application Data" directory under
+                          // the user profile.
+  DIR_COMMON_APP_DATA,    // W2K, XP, W2K3: "C:\Documents and Settings\
+                          // All Users\Application Data".
+                          // Vista, W2K8 and above: "C:\ProgramData".
+  DIR_APP_SHORTCUTS,      // Where tiles on the start screen are stored, only
+                          // for Windows 8. Maps to "Local\AppData\Microsoft\
+                          // Windows\Application Shortcuts\".
+  DIR_COMMON_DESKTOP,     // Directory for the common desktop (visible
+                          // on all user's Desktop).
+  DIR_USER_QUICK_LAUNCH,  // Directory for the quick launch shortcuts.
+  DIR_TASKBAR_PINS,       // Directory for the shortcuts pinned to taskbar via
+                          // base::win::TaskbarPinShortcutLink().
+  DIR_WINDOWS_FONTS,      // Usually C:\Windows\Fonts.
+
+  PATH_WIN_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_WIN_H__
diff --git a/base/base_switches.cc b/base/base_switches.cc
new file mode 100644
index 0000000..3076540
--- /dev/null
+++ b/base/base_switches.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_switches.h"
+
+namespace switches {
+
+// Disables the crash reporting.
+const char kDisableBreakpad[]               = "disable-breakpad";
+
+// Indicates that crash reporting should be enabled. On platforms where helper
+// processes cannot access to files needed to make this decision, this flag is
+// generated internally.
+const char kEnableCrashReporter[]           = "enable-crash-reporter";
+
+// Generates full memory crash dump.
+const char kFullMemoryCrashReport[]         = "full-memory-crash-report";
+
+// Force low-end device mode when set.
+const char kEnableLowEndDeviceMode[]        = "enable-low-end-device-mode";
+
+// Force disabling of low-end device mode when set.
+const char kDisableLowEndDeviceMode[]       = "disable-low-end-device-mode";
+
+// Suppresses all error dialogs when present.
+const char kNoErrorDialogs[]                = "noerrdialogs";
+
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process is a child process.
+const char kTestChildProcess[]              = "test-child-process";
+
+// Gives the default maximal active V-logging level; 0 is the default.
+// Normally positive values are used for V-logging levels.
+const char kV[]                             = "v";
+
+// Gives the per-module maximal V-logging levels to override the value
+// given by --v.  E.g. "my_module=2,foo*=3" would change the logging
+// level for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+//
+// Any pattern containing a forward or backward slash will be tested
+// against the whole pathname and not just the module.  E.g.,
+// "*/foo/bar/*=2" would change the logging level for all code in
+// source files under a "foo/bar" directory.
+const char kVModule[]                       = "vmodule";
+
+// Will wait for 60 seconds for a debugger to come to attach to the process.
+const char kWaitForDebugger[]               = "wait-for-debugger";
+
+// Sends a pretty-printed version of tracing info to the console.
+const char kTraceToConsole[]                = "trace-to-console";
+
+// Sends trace events from these categories to a file.
+// --trace-to-file on its own sends to default categories.
+const char kTraceToFile[]                   = "trace-to-file";
+
+// Specifies the file name for --trace-to-file. If unspecified, it will
+// go to a default file name.
+const char kTraceToFileName[]               = "trace-to-file-name";
+
+// Configure whether chrome://profiler will contain timing information. This
+// option is enabled by default. A value of "0" will disable profiler timing,
+// while all other values will enable it.
+const char kProfilerTiming[]                = "profiler-timing";
+// Value of the --profiler-timing flag that will disable timing information for
+// chrome://profiler.
+const char kProfilerTimingDisabledValue[]   = "0";
+
+#if defined(OS_POSIX)
+// Used for turning on Breakpad crash reporting in a debug environment where
+// crash reporting is typically compiled but disabled.
+const char kEnableCrashReporterForTesting[] =
+    "enable-crash-reporter-for-testing";
+#endif
+
+}  // namespace switches
diff --git a/base/base_switches.h b/base/base_switches.h
new file mode 100644
index 0000000..c579f6a
--- /dev/null
+++ b/base/base_switches.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines all the "base" command-line switches.
+
+#ifndef BASE_BASE_SWITCHES_H_
+#define BASE_BASE_SWITCHES_H_
+
+#include "build/build_config.h"
+
+namespace switches {
+
+extern const char kDisableBreakpad[];
+extern const char kEnableCrashReporter[];
+extern const char kFullMemoryCrashReport[];
+extern const char kEnableLowEndDeviceMode[];
+extern const char kDisableLowEndDeviceMode[];
+extern const char kNoErrorDialogs[];
+extern const char kProfilerTiming[];
+extern const char kProfilerTimingDisabledValue[];
+extern const char kTestChildProcess[];
+extern const char kTraceToConsole[];
+extern const char kTraceToFile[];
+extern const char kTraceToFileName[];
+extern const char kV[];
+extern const char kVModule[];
+extern const char kWaitForDebugger[];
+
+#if defined(OS_POSIX)
+extern const char kEnableCrashReporterForTesting[];
+#endif
+
+}  // namespace switches
+
+#endif  // BASE_BASE_SWITCHES_H_
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
new file mode 100644
index 0000000..b1c270c
--- /dev/null
+++ b/base/base_unittests.isolate
@@ -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.
+{
+  'conditions': [
+    ['use_x11==0', {
+      'variables': {
+        'command': [
+          '../testing/test_env.py',
+          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
+          '--test-launcher-bot-mode',
+          '--asan=<(asan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
+        ],
+      },
+    }],
+    ['use_x11==1', {
+      'variables': {
+        'command': [
+          '../testing/xvfb.py',
+          '<(PRODUCT_DIR)',
+          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+          '--brave-new-test-launcher',
+          '--test-launcher-bot-mode',
+          '--asan=<(asan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
+        ],
+        'files': [
+          '../testing/xvfb.py',
+          '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+        ],
+      },
+    }],
+    ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'files': [
+          'test/data/',
+        ],
+      },
+    }],
+    ['OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'files': [
+          '../testing/test_env.py',
+          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+        'read_only': 1,
+      },
+    }],
+    ['OS=="linux"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/lib/libmalloc_wrapper.so',
+        ],
+      },
+    }],
+    ['OS=="mac" and asan==1 and fastbuild==0', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/base_unittests.dSYM/',
+        ],
+      },
+    }],
+    ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/base_unittests.exe.pdb',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    'base.isolate',
+  ],
+}
diff --git a/base/basictypes.h b/base/basictypes.h
new file mode 100644
index 0000000..bf75e67
--- /dev/null
+++ b/base/basictypes.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains definitions of our old basic integral types
+// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99
+// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed.
+// Note that the macros and macro-like constructs that were formerly defined in
+// this file are now available separately in base/macros.h.
+
+#ifndef BASE_BASICTYPES_H_
+#define BASE_BASICTYPES_H_
+
+#include <limits.h>  // So we can set the bounds of our types.
+#include <stddef.h>  // For size_t.
+#include <stdint.h>  // For intptr_t.
+
+#include "base/macros.h"
+#include "base/port.h"  // Types that only need exist on certain systems.
+
+// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
+typedef int8_t int8;
+typedef uint8_t uint8;
+typedef int16_t int16;
+typedef uint16_t uint16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+
+// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
+const uint8  kuint8max  =  0xFF;
+const uint16 kuint16max =  0xFFFF;
+const uint32 kuint32max =  0xFFFFFFFF;
+const uint64 kuint64max =  0xFFFFFFFFFFFFFFFFULL;
+const  int8  kint8min   = -0x7F - 1;
+const  int8  kint8max   =  0x7F;
+const  int16 kint16min  = -0x7FFF - 1;
+const  int16 kint16max  =  0x7FFF;
+const  int32 kint32min  = -0x7FFFFFFF - 1;
+const  int32 kint32max  =  0x7FFFFFFF;
+const  int64 kint64min  = -0x7FFFFFFFFFFFFFFFLL - 1;
+const  int64 kint64max  =  0x7FFFFFFFFFFFFFFFLL;
+
+#endif  // BASE_BASICTYPES_H_
diff --git a/base/big_endian.cc b/base/big_endian.cc
new file mode 100644
index 0000000..9b69147
--- /dev/null
+++ b/base/big_endian.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/big_endian.h"
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+BigEndianReader::BigEndianReader(const char* buf, size_t len)
+    : ptr_(buf), end_(ptr_ + len) {}
+
+bool BigEndianReader::Skip(size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  ptr_ += len;
+  return true;
+}
+
+bool BigEndianReader::ReadBytes(void* out, size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  memcpy(out, ptr_, len);
+  ptr_ += len;
+  return true;
+}
+
+bool BigEndianReader::ReadPiece(base::StringPiece* out, size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  *out = base::StringPiece(ptr_, len);
+  ptr_ += len;
+  return true;
+}
+
+template<typename T>
+bool BigEndianReader::Read(T* value) {
+  if (ptr_ + sizeof(T) > end_)
+    return false;
+  ReadBigEndian<T>(ptr_, value);
+  ptr_ += sizeof(T);
+  return true;
+}
+
+bool BigEndianReader::ReadU8(uint8* value) {
+  return Read(value);
+}
+
+bool BigEndianReader::ReadU16(uint16* value) {
+  return Read(value);
+}
+
+bool BigEndianReader::ReadU32(uint32* value) {
+  return Read(value);
+}
+
+bool BigEndianReader::ReadU64(uint64* value) {
+  return Read(value);
+}
+
+BigEndianWriter::BigEndianWriter(char* buf, size_t len)
+    : ptr_(buf), end_(ptr_ + len) {}
+
+bool BigEndianWriter::Skip(size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  ptr_ += len;
+  return true;
+}
+
+bool BigEndianWriter::WriteBytes(const void* buf, size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  memcpy(ptr_, buf, len);
+  ptr_ += len;
+  return true;
+}
+
+template<typename T>
+bool BigEndianWriter::Write(T value) {
+  if (ptr_ + sizeof(T) > end_)
+    return false;
+  WriteBigEndian<T>(ptr_, value);
+  ptr_ += sizeof(T);
+  return true;
+}
+
+bool BigEndianWriter::WriteU8(uint8 value) {
+  return Write(value);
+}
+
+bool BigEndianWriter::WriteU16(uint16 value) {
+  return Write(value);
+}
+
+bool BigEndianWriter::WriteU32(uint32 value) {
+  return Write(value);
+}
+
+bool BigEndianWriter::WriteU64(uint64 value) {
+  return Write(value);
+}
+
+}  // namespace base
diff --git a/base/big_endian.h b/base/big_endian.h
new file mode 100644
index 0000000..914767f
--- /dev/null
+++ b/base/big_endian.h
@@ -0,0 +1,104 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIG_ENDIAN_H_
+#define BASE_BIG_ENDIAN_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Read an integer (signed or unsigned) from |buf| in Big Endian order.
+// Note: this loop is unrolled with -O1 and above.
+// NOTE(szym): glibc dns-canon.c and SpdyFrameBuilder use
+// ntohs(*(uint16_t*)ptr) which is potentially unaligned.
+// This would cause SIGBUS on ARMv5 or earlier and ARMv6-M.
+template<typename T>
+inline void ReadBigEndian(const char buf[], T* out) {
+  *out = buf[0];
+  for (size_t i = 1; i < sizeof(T); ++i) {
+    *out <<= 8;
+    // Must cast to uint8 to avoid clobbering by sign extension.
+    *out |= static_cast<uint8>(buf[i]);
+  }
+}
+
+// Write an integer (signed or unsigned) |val| to |buf| in Big Endian order.
+// Note: this loop is unrolled with -O1 and above.
+template<typename T>
+inline void WriteBigEndian(char buf[], T val) {
+  for (size_t i = 0; i < sizeof(T); ++i) {
+    buf[sizeof(T)-i-1] = static_cast<char>(val & 0xFF);
+    val >>= 8;
+  }
+}
+
+// Specializations to make clang happy about the (dead code) shifts above.
+template<>
+inline void ReadBigEndian<uint8>(const char buf[], uint8* out) {
+  *out = buf[0];
+}
+
+template<>
+inline void WriteBigEndian<uint8>(char buf[], uint8 val) {
+  buf[0] = static_cast<char>(val);
+}
+
+// Allows reading integers in network order (big endian) while iterating over
+// an underlying buffer. All the reading functions advance the internal pointer.
+class BASE_EXPORT BigEndianReader {
+ public:
+  BigEndianReader(const char* buf, size_t len);
+
+  const char* ptr() const { return ptr_; }
+  int remaining() const { return end_ - ptr_; }
+
+  bool Skip(size_t len);
+  bool ReadBytes(void* out, size_t len);
+  // Creates a StringPiece in |out| that points to the underlying buffer.
+  bool ReadPiece(base::StringPiece* out, size_t len);
+  bool ReadU8(uint8* value);
+  bool ReadU16(uint16* value);
+  bool ReadU32(uint32* value);
+  bool ReadU64(uint64* value);
+
+ private:
+  // Hidden to promote type safety.
+  template<typename T>
+  bool Read(T* v);
+
+  const char* ptr_;
+  const char* end_;
+};
+
+// Allows writing integers in network order (big endian) while iterating over
+// an underlying buffer. All the writing functions advance the internal pointer.
+class BASE_EXPORT BigEndianWriter {
+ public:
+  BigEndianWriter(char* buf, size_t len);
+
+  char* ptr() const { return ptr_; }
+  int remaining() const { return end_ - ptr_; }
+
+  bool Skip(size_t len);
+  bool WriteBytes(const void* buf, size_t len);
+  bool WriteU8(uint8 value);
+  bool WriteU16(uint16 value);
+  bool WriteU32(uint32 value);
+  bool WriteU64(uint64 value);
+
+ private:
+  // Hidden to promote type safety.
+  template<typename T>
+  bool Write(T v);
+
+  char* ptr_;
+  char* end_;
+};
+
+}  // namespace base
+
+#endif  // BASE_BIG_ENDIAN_H_
diff --git a/base/big_endian_unittest.cc b/base/big_endian_unittest.cc
new file mode 100644
index 0000000..0e4b3f1
--- /dev/null
+++ b/base/big_endian_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/big_endian.h"
+
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(BigEndianReaderTest, ReadsValues) {
+  char data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
+                  0x1A, 0x2B, 0x3C, 0x4D, 0x5E };
+  char buf[2];
+  uint8 u8;
+  uint16 u16;
+  uint32 u32;
+  uint64 u64;
+  base::StringPiece piece;
+  BigEndianReader reader(data, sizeof(data));
+
+  EXPECT_TRUE(reader.Skip(2));
+  EXPECT_EQ(data + 2, reader.ptr());
+  EXPECT_EQ(reader.remaining(), static_cast<int>(sizeof(data)) - 2);
+  EXPECT_TRUE(reader.ReadBytes(buf, sizeof(buf)));
+  EXPECT_EQ(0x2, buf[0]);
+  EXPECT_EQ(0x3, buf[1]);
+  EXPECT_TRUE(reader.ReadU8(&u8));
+  EXPECT_EQ(0x4, u8);
+  EXPECT_TRUE(reader.ReadU16(&u16));
+  EXPECT_EQ(0x0506, u16);
+  EXPECT_TRUE(reader.ReadU32(&u32));
+  EXPECT_EQ(0x0708090Au, u32);
+  EXPECT_TRUE(reader.ReadU64(&u64));
+  EXPECT_EQ(0x0B0C0D0E0F1A2B3Cllu, u64);
+  base::StringPiece expected(reader.ptr(), 2);
+  EXPECT_TRUE(reader.ReadPiece(&piece, 2));
+  EXPECT_EQ(2u, piece.size());
+  EXPECT_EQ(expected.data(), piece.data());
+}
+
+TEST(BigEndianReaderTest, RespectsLength) {
+  char data[8];
+  char buf[2];
+  uint8 u8;
+  uint16 u16;
+  uint32 u32;
+  uint64 u64;
+  base::StringPiece piece;
+  BigEndianReader reader(data, sizeof(data));
+  // 8 left
+  EXPECT_FALSE(reader.Skip(9));
+  EXPECT_TRUE(reader.Skip(1));
+  // 7 left
+  EXPECT_FALSE(reader.ReadU64(&u64));
+  EXPECT_TRUE(reader.Skip(4));
+  // 3 left
+  EXPECT_FALSE(reader.ReadU32(&u32));
+  EXPECT_FALSE(reader.ReadPiece(&piece, 4));
+  EXPECT_TRUE(reader.Skip(2));
+  // 1 left
+  EXPECT_FALSE(reader.ReadU16(&u16));
+  EXPECT_FALSE(reader.ReadBytes(buf, 2));
+  EXPECT_TRUE(reader.Skip(1));
+  // 0 left
+  EXPECT_FALSE(reader.ReadU8(&u8));
+  EXPECT_EQ(0, reader.remaining());
+}
+
+TEST(BigEndianWriterTest, WritesValues) {
+  char expected[] = { 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE,
+                      0xF, 0x1A, 0x2B, 0x3C };
+  char data[sizeof(expected)];
+  char buf[] = { 0x2, 0x3 };
+  memset(data, 0, sizeof(data));
+  BigEndianWriter writer(data, sizeof(data));
+
+  EXPECT_TRUE(writer.Skip(2));
+  EXPECT_TRUE(writer.WriteBytes(buf, sizeof(buf)));
+  EXPECT_TRUE(writer.WriteU8(0x4));
+  EXPECT_TRUE(writer.WriteU16(0x0506));
+  EXPECT_TRUE(writer.WriteU32(0x0708090A));
+  EXPECT_TRUE(writer.WriteU64(0x0B0C0D0E0F1A2B3Cllu));
+  EXPECT_EQ(0, memcmp(expected, data, sizeof(expected)));
+}
+
+TEST(BigEndianWriterTest, RespectsLength) {
+  char data[8];
+  char buf[2];
+  uint8 u8 = 0;
+  uint16 u16 = 0;
+  uint32 u32 = 0;
+  uint64 u64 = 0;
+  BigEndianWriter writer(data, sizeof(data));
+  // 8 left
+  EXPECT_FALSE(writer.Skip(9));
+  EXPECT_TRUE(writer.Skip(1));
+  // 7 left
+  EXPECT_FALSE(writer.WriteU64(u64));
+  EXPECT_TRUE(writer.Skip(4));
+  // 3 left
+  EXPECT_FALSE(writer.WriteU32(u32));
+  EXPECT_TRUE(writer.Skip(2));
+  // 1 left
+  EXPECT_FALSE(writer.WriteU16(u16));
+  EXPECT_FALSE(writer.WriteBytes(buf, 2));
+  EXPECT_TRUE(writer.Skip(1));
+  // 0 left
+  EXPECT_FALSE(writer.WriteU8(u8));
+  EXPECT_EQ(0, writer.remaining());
+}
+
+}  // namespace base
diff --git a/base/bind.h b/base/bind.h
new file mode 100644
index 0000000..51be10d
--- /dev/null
+++ b/base/bind.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_H_
+#define BASE_BIND_H_
+
+#include "base/bind_internal.h"
+#include "base/callback_internal.h"
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// See base/callback.h for documentation.
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// If you're reading the implementation, before proceeding further, you should
+// read the top comment of base/bind_internal.h for a definition of common
+// terms and concepts.
+//
+// RETURN TYPES
+//
+// Though Bind()'s result is meant to be stored in a Callback<> type, it
+// cannot actually return the exact type without requiring a large amount
+// of extra template specializations. The problem is that in order to
+// discern the correct specialization of Callback<>, Bind would need to
+// unwrap the function signature to determine the signature's arity, and
+// whether or not it is a method.
+//
+// Each unique combination of (arity, function_type, num_prebound) where
+// function_type is one of {function, method, const_method} would require
+// one specialization.  We eventually have to do a similar number of
+// specializations anyways in the implementation (see the Invoker<>,
+// classes).  However, it is avoidable in Bind if we return the result
+// via an indirection like we do below.
+//
+// TODO(ajwong): We might be able to avoid this now, but need to test.
+//
+// It is possible to move most of the static_assert into BindState<>, but it
+// feels a little nicer to have the asserts here so people do not need to crack
+// open bind_internal.h.  On the other hand, it makes Bind() harder to read.
+
+namespace base {
+
+template <typename Functor>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        internal::TypeList<>>::UnboundRunType>
+Bind(Functor functor) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  typedef internal::BindState<RunnableType, RunType,
+                              internal::TypeList<>> BindState;
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor)));
+}
+
+template <typename Functor, typename... Args>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        internal::TypeList<
+            typename internal::CallbackParamTraits<Args>::StorageType...>>
+            ::UnboundRunType>
+Bind(Functor functor, const Args&... args) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef typename RunnableType::RunType BoundRunType;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  static_assert(!internal::HasNonConstReferenceParam<BoundRunType>::value,
+                "do_not_bind_functions_with_nonconst_ref");
+
+  const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
+                "first_bound_argument_to_method_cannot_be_array");
+  static_assert(
+      !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
+      "a_parameter_is_refcounted_type_and_needs_scoped_refptr");
+
+  typedef internal::BindState<
+      RunnableType, RunType,
+      internal::TypeList<
+          typename internal::CallbackParamTraits<Args>::StorageType...>>
+      BindState;
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), args...));
+}
+
+}  // namespace base
+
+#endif  // BASE_BIND_H_
diff --git a/base/bind_helpers.cc b/base/bind_helpers.cc
new file mode 100644
index 0000000..f1fe46d
--- /dev/null
+++ b/base/bind_helpers.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind_helpers.h"
+
+#include "base/callback.h"
+
+namespace base {
+
+void DoNothing() {
+}
+
+}  // namespace base
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
new file mode 100644
index 0000000..24063ad
--- /dev/null
+++ b/base/bind_helpers.h
@@ -0,0 +1,602 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This defines a set of argument wrappers and related factory methods that
+// can be used specify the refcounting and reference semantics of arguments
+// that are bound by the Bind() function in base/bind.h.
+//
+// It also defines a set of simple functions and utilities that people want
+// when using Callback<> and Bind().
+//
+//
+// ARGUMENT BINDING WRAPPERS
+//
+// The wrapper functions are base::Unretained(), base::Owned(), base::Passed(),
+// base::ConstRef(), and base::IgnoreResult().
+//
+// Unretained() allows Bind() to bind a non-refcounted class, and to disable
+// refcounting on arguments that are refcounted objects.
+//
+// Owned() transfers ownership of an object to the Callback resulting from
+// bind; the object will be deleted when the Callback is deleted.
+//
+// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr)
+// through a Callback. Logically, this signifies a destructive transfer of
+// the state of the argument into the target function.  Invoking
+// Callback::Run() twice on a Callback that was created with a Passed()
+// argument will CHECK() because the first invocation would have already
+// transferred ownership to the target function.
+//
+// ConstRef() allows binding a constant reference to an argument rather
+// than a copy.
+//
+// IgnoreResult() is used to adapt a function or Callback with a return type to
+// one with a void return. This is most useful if you have a function with,
+// say, a pesky ignorable bool return that you want to use with PostTask or
+// something else that expect a Callback with a void return.
+//
+// EXAMPLE OF Unretained():
+//
+//   class Foo {
+//    public:
+//     void func() { cout << "Foo:f" << endl; }
+//   };
+//
+//   // In some function somewhere.
+//   Foo foo;
+//   Closure foo_callback =
+//       Bind(&Foo::func, Unretained(&foo));
+//   foo_callback.Run();  // Prints "Foo:f".
+//
+// Without the Unretained() wrapper on |&foo|, the above call would fail
+// to compile because Foo does not support the AddRef() and Release() methods.
+//
+//
+// EXAMPLE OF Owned():
+//
+//   void foo(int* arg) { cout << *arg << endl }
+//
+//   int* pn = new int(1);
+//   Closure foo_callback = Bind(&foo, Owned(pn));
+//
+//   foo_callback.Run();  // Prints "1"
+//   foo_callback.Run();  // Prints "1"
+//   *n = 2;
+//   foo_callback.Run();  // Prints "2"
+//
+//   foo_callback.Reset();  // |pn| is deleted.  Also will happen when
+//                          // |foo_callback| goes out of scope.
+//
+// Without Owned(), someone would have to know to delete |pn| when the last
+// reference to the Callback is deleted.
+//
+//
+// EXAMPLE OF ConstRef():
+//
+//   void foo(int arg) { cout << arg << endl }
+//
+//   int n = 1;
+//   Closure no_ref = Bind(&foo, n);
+//   Closure has_ref = Bind(&foo, ConstRef(n));
+//
+//   no_ref.Run();  // Prints "1"
+//   has_ref.Run();  // Prints "1"
+//
+//   n = 2;
+//   no_ref.Run();  // Prints "1"
+//   has_ref.Run();  // Prints "2"
+//
+// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
+// its bound callbacks.
+//
+//
+// EXAMPLE OF IgnoreResult():
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//
+//   // Assign to a Callback with a void return type.
+//   Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething));
+//   cb->Run(1);  // Prints "1".
+//
+//   // Prints "1" on |ml|.
+//   ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1);
+//
+//
+// EXAMPLE OF Passed():
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) { }
+//   scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
+//
+//   scoped_ptr<Foo> f(new Foo());
+//
+//   // |cb| is given ownership of Foo(). |f| is now NULL.
+//   // You can use f.Pass() in place of &f, but it's more verbose.
+//   Closure cb = Bind(&TakesOwnership, Passed(&f));
+//
+//   // Run was never called so |cb| still owns Foo() and deletes
+//   // it on Reset().
+//   cb.Reset();
+//
+//   // |cb| is given a new Foo created by CreateFoo().
+//   cb = Bind(&TakesOwnership, Passed(CreateFoo()));
+//
+//   // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
+//   // no longer owns Foo() and, if reset, would not delete Foo().
+//   cb.Run();  // Foo() is now transferred to |arg| and deleted.
+//   cb.Run();  // This CHECK()s since Foo() already been used once.
+//
+// Passed() is particularly useful with PostTask() when you are transferring
+// ownership of an argument into a task, but don't necessarily know if the
+// task will always be executed. This can happen if the task is cancellable
+// or if it is posted to a TaskRunner.
+//
+//
+// SIMPLE FUNCTIONS AND UTILITIES.
+//
+//   DoNothing() - Useful for creating a Closure that does nothing when called.
+//   DeletePointer<T>() - Useful for creating a Closure that will delete a
+//                        pointer when invoked. Only use this when necessary.
+//                        In most cases MessageLoop::DeleteSoon() is a better
+//                        fit.
+
+#ifndef BASE_BIND_HELPERS_H_
+#define BASE_BIND_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
+// for the existence of AddRef() and Release() functions of the correct
+// signature.
+//
+// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
+// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
+// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
+//
+// The last link in particular show the method used below.
+//
+// For SFINAE to work with inherited methods, we need to pull some extra tricks
+// with multiple inheritance.  In the more standard formulation, the overloads
+// of Check would be:
+//
+//   template <typename C>
+//   Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
+//
+//   template <typename C>
+//   No NotTheCheckWeWant(...);
+//
+//   static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
+//
+// The problem here is that template resolution will not match
+// C::TargetFunc if TargetFunc does not exist directly in C.  That is, if
+// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
+// |value| will be false.  This formulation only checks for whether or
+// not TargetFunc exist directly in the class being introspected.
+//
+// To get around this, we play a dirty trick with multiple inheritance.
+// First, We create a class BaseMixin that declares each function that we
+// want to probe for.  Then we create a class Base that inherits from both T
+// (the class we wish to probe) and BaseMixin.  Note that the function
+// signature in BaseMixin does not need to match the signature of the function
+// we are probing for; thus it's easiest to just use void(void).
+//
+// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
+// ambiguous resolution between BaseMixin and T.  This lets us write the
+// following:
+//
+//   template <typename C>
+//   No GoodCheck(Helper<&C::TargetFunc>*);
+//
+//   template <typename C>
+//   Yes GoodCheck(...);
+//
+//   static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
+//
+// Notice here that the variadic version of GoodCheck() returns Yes here
+// instead of No like the previous one. Also notice that we calculate |value|
+// by specializing GoodCheck() on Base instead of T.
+//
+// We've reversed the roles of the variadic, and Helper overloads.
+// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
+// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
+// to the variadic version if T has TargetFunc.  If T::TargetFunc does not
+// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
+// will prefer GoodCheck(Helper<&C::TargetFunc>*).
+//
+// This method of SFINAE will correctly probe for inherited names, but it cannot
+// typecheck those names.  It's still a good enough sanity check though.
+//
+// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
+//
+// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
+// this works well.
+//
+// TODO(ajwong): Make this check for Release() as well.
+// See http://crbug.com/82038.
+template <typename T>
+class SupportsAddRefAndRelease {
+  typedef char Yes[1];
+  typedef char No[2];
+
+  struct BaseMixin {
+    void AddRef();
+  };
+
+// MSVC warns when you try to use Base if T has a private destructor, the
+// common pattern for refcounted types. It does this even though no attempt to
+// instantiate Base is made.  We disable the warning for this definition.
+#if defined(OS_WIN)
+#pragma warning(push)
+#pragma warning(disable:4624)
+#endif
+  struct Base : public T, public BaseMixin {
+  };
+#if defined(OS_WIN)
+#pragma warning(pop)
+#endif
+
+  template <void(BaseMixin::*)(void)> struct Helper {};
+
+  template <typename C>
+  static No& Check(Helper<&C::AddRef>*);
+
+  template <typename >
+  static Yes& Check(...);
+
+ public:
+  enum { value = sizeof(Check<Base>(0)) == sizeof(Yes) };
+};
+
+// Helpers to assert that arguments of a recounted type are bound with a
+// scoped_refptr.
+template <bool IsClasstype, typename T>
+struct UnsafeBindtoRefCountedArgHelper : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArgHelper<true, T>
+    : integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg<T*>
+    : UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
+};
+
+template <typename T>
+class HasIsMethodTag {
+  typedef char Yes[1];
+  typedef char No[2];
+
+  template <typename U>
+  static Yes& Check(typename U::IsMethod*);
+
+  template <typename U>
+  static No& Check(...);
+
+ public:
+  enum { value = sizeof(Check<T>(0)) == sizeof(Yes) };
+};
+
+template <typename T>
+class UnretainedWrapper {
+ public:
+  explicit UnretainedWrapper(T* o) : ptr_(o) {}
+  T* get() const { return ptr_; }
+ private:
+  T* ptr_;
+};
+
+template <typename T>
+class ConstRefWrapper {
+ public:
+  explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
+  const T& get() const { return *ptr_; }
+ private:
+  const T* ptr_;
+};
+
+template <typename T>
+struct IgnoreResultHelper {
+  explicit IgnoreResultHelper(T functor) : functor_(functor) {}
+
+  T functor_;
+};
+
+template <typename T>
+struct IgnoreResultHelper<Callback<T> > {
+  explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {}
+
+  const Callback<T>& functor_;
+};
+
+// An alternate implementation is to avoid the destructive copy, and instead
+// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to
+// a class that is essentially a scoped_ptr<>.
+//
+// The current implementation has the benefit though of leaving ParamTraits<>
+// fully in callback_internal.h as well as avoiding type conversions during
+// storage.
+template <typename T>
+class OwnedWrapper {
+ public:
+  explicit OwnedWrapper(T* o) : ptr_(o) {}
+  ~OwnedWrapper() { delete ptr_; }
+  T* get() const { return ptr_; }
+  OwnedWrapper(const OwnedWrapper& other) {
+    ptr_ = other.ptr_;
+    other.ptr_ = NULL;
+  }
+
+ private:
+  mutable T* ptr_;
+};
+
+// PassedWrapper is a copyable adapter for a scoper that ignores const.
+//
+// It is needed to get around the fact that Bind() takes a const reference to
+// all its arguments.  Because Bind() takes a const reference to avoid
+// unnecessary copies, it is incompatible with movable-but-not-copyable
+// types; doing a destructive "move" of the type into Bind() would violate
+// the const correctness.
+//
+// This conundrum cannot be solved without either C++11 rvalue references or
+// a O(2^n) blowup of Bind() templates to handle each combination of regular
+// types and movable-but-not-copyable types.  Thus we introduce a wrapper type
+// that is copyable to transmit the correct type information down into
+// BindState<>. Ignoring const in this type makes sense because it is only
+// created when we are explicitly trying to do a destructive move.
+//
+// Two notes:
+//  1) PassedWrapper supports any type that has a "Pass()" function.
+//     This is intentional. The whitelisting of which specific types we
+//     support is maintained by CallbackParamTraits<>.
+//  2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
+//     scoper to a Callback and allow the Callback to execute once.
+template <typename T>
+class PassedWrapper {
+ public:
+  explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
+  PassedWrapper(const PassedWrapper& other)
+      : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
+  }
+  T Pass() const {
+    CHECK(is_valid_);
+    is_valid_ = false;
+    return scoper_.Pass();
+  }
+
+ private:
+  mutable bool is_valid_;
+  mutable T scoper_;
+};
+
+// Unwrap the stored parameters for the wrappers above.
+template <typename T>
+struct UnwrapTraits {
+  typedef const T& ForwardType;
+  static ForwardType Unwrap(const T& o) { return o; }
+};
+
+template <typename T>
+struct UnwrapTraits<UnretainedWrapper<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
+    return unretained.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<ConstRefWrapper<T> > {
+  typedef const T& ForwardType;
+  static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
+    return const_ref.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<scoped_refptr<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
+};
+
+template <typename T>
+struct UnwrapTraits<WeakPtr<T> > {
+  typedef const WeakPtr<T>& ForwardType;
+  static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
+};
+
+template <typename T>
+struct UnwrapTraits<OwnedWrapper<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(const OwnedWrapper<T>& o) {
+    return o.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<PassedWrapper<T> > {
+  typedef T ForwardType;
+  static T Unwrap(PassedWrapper<T>& o) {
+    return o.Pass();
+  }
+};
+
+// Utility for handling different refcounting semantics in the Bind()
+// function.
+template <bool is_method, typename... T>
+struct MaybeScopedRefPtr;
+
+template <bool is_method>
+struct MaybeScopedRefPtr<is_method> {
+  MaybeScopedRefPtr() {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<false, T, Rest...> {
+  MaybeScopedRefPtr(const T&, const Rest&...) {}
+};
+
+template <typename T, size_t n, typename... Rest>
+struct MaybeScopedRefPtr<false, T[n], Rest...> {
+  MaybeScopedRefPtr(const T*, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, T, Rest...> {
+  MaybeScopedRefPtr(const T& o, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, T*, Rest...> {
+  MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
+  scoped_refptr<T> ref_;
+};
+
+// No need to additionally AddRef() and Release() since we are storing a
+// scoped_refptr<> inside the storage object already.
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
+  MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, const T*, Rest...> {
+  MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
+  scoped_refptr<const T> ref_;
+};
+
+// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
+// method.  It is used internally by Bind() to select the correct
+// InvokeHelper that will no-op itself in the event the WeakPtr<> for
+// the target object is invalidated.
+//
+// The first argument should be the type of the object that will be received by
+// the method.
+template <bool IsMethod, typename... Args>
+struct IsWeakMethod : public false_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, WeakPtr<T>, Args...> : public true_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...>
+    : public true_type {};
+
+
+// Packs a list of types to hold them in a single type.
+template <typename... Types>
+struct TypeList {};
+
+// Used for DropTypeListItem implementation.
+template <size_t n, typename List>
+struct DropTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List>
+struct DropTypeListItemImpl<n, TypeList<T, List...>>
+    : DropTypeListItemImpl<n - 1, TypeList<List...>> {};
+
+template <typename T, typename... List>
+struct DropTypeListItemImpl<0, TypeList<T, List...>> {
+  typedef TypeList<T, List...> Type;
+};
+
+template <>
+struct DropTypeListItemImpl<0, TypeList<>> {
+  typedef TypeList<> Type;
+};
+
+// A type-level function that drops |n| list item from given TypeList.
+template <size_t n, typename List>
+using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
+
+// Used for ConcatTypeLists implementation.
+template <typename List1, typename List2>
+struct ConcatTypeListsImpl;
+
+template <typename... Types1, typename... Types2>
+struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
+  typedef TypeList<Types1..., Types2...> Type;
+};
+
+// A type-level function that concats two TypeLists.
+template <typename List1, typename List2>
+using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
+
+// Used for MakeFunctionType implementation.
+template <typename R, typename ArgList>
+struct MakeFunctionTypeImpl;
+
+template <typename R, typename... Args>
+struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
+  typedef R(Type)(Args...);
+};
+
+// A type-level function that constructs a function type that has |R| as its
+// return type and has TypeLists items as its arguments.
+template <typename R, typename ArgList>
+using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
+
+}  // namespace internal
+
+template <typename T>
+static inline internal::UnretainedWrapper<T> Unretained(T* o) {
+  return internal::UnretainedWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
+  return internal::ConstRefWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::OwnedWrapper<T> Owned(T* o) {
+  return internal::OwnedWrapper<T>(o);
+}
+
+// We offer 2 syntaxes for calling Passed().  The first takes a temporary and
+// is best suited for use with the return value of a function. The second
+// takes a pointer to the scoper and is just syntactic sugar to avoid having
+// to write Passed(scoper.Pass()).
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T scoper) {
+  return internal::PassedWrapper<T>(scoper.Pass());
+}
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T* scoper) {
+  return internal::PassedWrapper<T>(scoper->Pass());
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
+  return internal::IgnoreResultHelper<T>(data);
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<Callback<T> >
+IgnoreResult(const Callback<T>& data) {
+  return internal::IgnoreResultHelper<Callback<T> >(data);
+}
+
+BASE_EXPORT void DoNothing();
+
+template<typename T>
+void DeletePointer(T* obj) {
+  delete obj;
+}
+
+}  // namespace base
+
+#endif  // BASE_BIND_HELPERS_H_
diff --git a/base/bind_internal.h b/base/bind_internal.h
new file mode 100644
index 0000000..5fc1459
--- /dev/null
+++ b/base/bind_internal.h
@@ -0,0 +1,414 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/bind_internal_win.h"
+#endif
+
+namespace base {
+namespace internal {
+
+// See base/callback.h for user documentation.
+//
+//
+// CONCEPTS:
+//  Runnable -- A type (really a type class) that has a single Run() method
+//              and a RunType typedef that corresponds to the type of Run().
+//              A Runnable can declare that it should treated like a method
+//              call by including a typedef named IsMethod.  The value of
+//              this typedef is NOT inspected, only the existence.  When a
+//              Runnable declares itself a method, Bind() will enforce special
+//              refcounting + WeakPtr handling semantics for the first
+//              parameter which is expected to be an object.
+//  Functor -- A copyable type representing something that should be called.
+//             All function pointers, Callback<>, and Runnables are functors
+//             even if the invocation syntax differs.
+//  RunType -- A function type (as opposed to function _pointer_ type) for
+//             a Run() function.  Usually just a convenience typedef.
+//  (Bound)ArgsType -- A function type that is being (ab)used to store the
+//                     types of set of arguments.  The "return" type is always
+//                     void here.  We use this hack so that we do not need
+//                     a new type name for each arity of type. (eg.,
+//                     BindState1, BindState2).  This makes forward
+//                     declarations and friending much much easier.
+//
+// Types:
+//  RunnableAdapter<> -- Wraps the various "function" pointer types into an
+//                       object that adheres to the Runnable interface.
+//  ForceVoidReturn<> -- Helper class for translating function signatures to
+//                       equivalent forms with a "void" return type.
+//  FunctorTraits<> -- Type traits used determine the correct RunType and
+//                     RunnableType for a Functor.  This is where function
+//                     signature adapters are applied.
+//  MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
+//                    type class that represents the underlying Functor.
+//                    There are |O(1)| MakeRunnable types.
+//  InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
+//                    Handle the differing syntaxes needed for WeakPtr<>
+//                    support, and for ignoring return values.  This is separate
+//                    from Invoker to avoid creating multiple version of
+//                    Invoker<>.
+//  Invoker<> -- Unwraps the curried parameters and executes the Runnable.
+//  BindState<> -- Stores the curried parameters, and is the main entry point
+//                 into the Bind() system, doing most of the type resolution.
+//                 There are ARITY BindState types.
+
+// HasNonConstReferenceParam selects true_type when any of the parameters in
+// |Sig| is a non-const reference.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename Sig>
+struct HasNonConstReferenceParam : false_type {};
+
+// Implementation note: Select true_type if the first parameter is a non-const
+// reference.  Otherwise, skip the first parameter and check rest of parameters
+// recursively.
+template <typename R, typename T, typename... Args>
+struct HasNonConstReferenceParam<R(T, Args...)>
+    : SelectType<is_non_const_reference<T>::value,
+                 true_type,
+                 HasNonConstReferenceParam<R(Args...)>>::Type {};
+
+// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
+// pointer to a RefCounted type.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename... Args>
+struct HasRefCountedTypeAsRawPtr : false_type {};
+
+// Implementation note: Select true_type if the first parameter is a raw pointer
+// to a RefCounted type. Otherwise, skip the first parameter and check rest of
+// parameters recursively.
+template <typename T, typename... Args>
+struct HasRefCountedTypeAsRawPtr<T, Args...>
+    : SelectType<NeedsScopedRefptrButGetsRawPtr<T>::value,
+                 true_type,
+                 HasRefCountedTypeAsRawPtr<Args...>>::Type {};
+
+// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
+// item of |Args| is an array type.
+// Implementation note: This non-specialized case handles !is_method case and
+// zero-arity case only.  Other cases should be handled by the specialization
+// below.
+template <bool is_method, typename... Args>
+struct BindsArrayToFirstArg : false_type {};
+
+template <typename T, typename... Args>
+struct BindsArrayToFirstArg<true, T, Args...> : is_array<T> {};
+
+// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
+// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
+// Implementation note: This non-specialized case handles !is_method case and
+// zero-arity case only.  Other cases should be handled by the specialization
+// below.
+template <bool is_method, typename... Args>
+struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
+
+template <typename T, typename... Args>
+struct HasRefCountedParamAsRawPtr<true, T, Args...>
+    : HasRefCountedTypeAsRawPtr<Args...> {};
+
+// RunnableAdapter<>
+//
+// The RunnableAdapter<> templates provide a uniform interface for invoking
+// a function pointer, method pointer, or const method pointer. The adapter
+// exposes a Run() method with an appropriate signature. Using this wrapper
+// allows for writing code that supports all three pointer types without
+// undue repetition.  Without it, a lot of code would need to be repeated 3
+// times.
+//
+// For method pointers and const method pointers the first argument to Run()
+// is considered to be the received of the method.  This is similar to STL's
+// mem_fun().
+//
+// This class also exposes a RunType typedef that is the function type of the
+// Run() function.
+//
+// If and only if the wrapper contains a method or const method pointer, an
+// IsMethod typedef is exposed.  The existence of this typedef (NOT the value)
+// marks that the wrapper should be considered a method wrapper.
+
+template <typename Functor>
+class RunnableAdapter;
+
+// Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(*)(Args...)> {
+ public:
+  typedef R (RunType)(Args...);
+
+  explicit RunnableAdapter(R(*function)(Args...))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+    return function_(CallbackForward(args)...);
+  }
+
+ private:
+  R (*function_)(Args...);
+};
+
+// Method.
+template <typename R, typename T, typename... Args>
+class RunnableAdapter<R(T::*)(Args...)> {
+ public:
+  typedef R (RunType)(T*, Args...);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(Args...))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) {
+    return (object->*method_)(CallbackForward(args)...);
+  }
+
+ private:
+  R (T::*method_)(Args...);
+};
+
+// Const Method.
+template <typename R, typename T, typename... Args>
+class RunnableAdapter<R(T::*)(Args...) const> {
+ public:
+  typedef R (RunType)(const T*, Args...);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(Args...) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object,
+        typename CallbackParamTraits<Args>::ForwardType... args) {
+    return (object->*method_)(CallbackForward(args)...);
+  }
+
+ private:
+  R (T::*method_)(Args...) const;
+};
+
+
+// ForceVoidReturn<>
+//
+// Set of templates that support forcing the function return type to void.
+template <typename Sig>
+struct ForceVoidReturn;
+
+template <typename R, typename... Args>
+struct ForceVoidReturn<R(Args...)> {
+  typedef void(RunType)(Args...);
+};
+
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename T>
+struct FunctorTraits {
+  typedef RunnableAdapter<T> RunnableType;
+  typedef typename RunnableType::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T>> {
+  typedef typename FunctorTraits<T>::RunnableType RunnableType;
+  typedef typename ForceVoidReturn<
+      typename RunnableType::RunType>::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<Callback<T>> {
+  typedef Callback<T> RunnableType;
+  typedef typename Callback<T>::RunType RunType;
+};
+
+
+// MakeRunnable<>
+//
+// Converts a passed in functor to a RunnableType using type inference.
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
+  return RunnableAdapter<T>(t);
+}
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType
+MakeRunnable(const IgnoreResultHelper<T>& t) {
+  return MakeRunnable(t.functor_);
+}
+
+template <typename T>
+const typename FunctorTraits<Callback<T>>::RunnableType&
+MakeRunnable(const Callback<T>& t) {
+  DCHECK(!t.is_null());
+  return t;
+}
+
+
+// InvokeHelper<>
+//
+// There are 3 logical InvokeHelper<> specializations: normal, void-return,
+// WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// We need a InvokeHelper to handle void return types in order to support
+// IgnoreResult().  Normally, if the Runnable's RunType had a void return,
+// the template system would just accept "return functor.Run()" ignoring
+// the fact that a void function is being used with return. This piece of
+// sugar breaks though when the Runnable's RunType is not void.  Thus, we
+// need a partial specialization to change the syntax to drop the "return"
+// from the invocation call.
+//
+// WeakCalls similarly need special syntax that is applied to the first
+// argument to check if they should no-op themselves.
+template <bool IsWeakCall, typename ReturnType, typename Runnable,
+          typename ArgsType>
+struct InvokeHelper;
+
+template <typename ReturnType, typename Runnable, typename... Args>
+struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> {
+  static ReturnType MakeItSo(Runnable runnable, Args... args) {
+    return runnable.Run(CallbackForward(args)...);
+  }
+};
+
+template <typename Runnable, typename... Args>
+struct InvokeHelper<false, void, Runnable, TypeList<Args...>> {
+  static void MakeItSo(Runnable runnable, Args... args) {
+    runnable.Run(CallbackForward(args)...);
+  }
+};
+
+template <typename Runnable, typename BoundWeakPtr, typename... Args>
+struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> {
+  static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) {
+    if (!weak_ptr.get()) {
+      return;
+    }
+    runnable.Run(weak_ptr.get(), CallbackForward(args)...);
+  }
+};
+
+#if !defined(_MSC_VER)
+
+template <typename ReturnType, typename Runnable, typename ArgsType>
+struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
+  // WeakCalls are only supported for functions with a void return type.
+  // Otherwise, the function result would be undefined if the the WeakPtr<>
+  // is invalidated.
+  COMPILE_ASSERT(is_void<ReturnType>::value,
+                 weak_ptrs_can_only_bind_to_methods_without_return_values);
+};
+
+#endif
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <typename BoundIndices,
+          typename StorageType, typename Unwrappers,
+          typename InvokeHelperType, typename UnboundForwardRunType>
+struct Invoker;
+
+template <size_t... bound_indices,
+          typename StorageType,
+          typename... Unwrappers,
+          typename InvokeHelperType,
+          typename R,
+          typename... UnboundForwardArgs>
+struct Invoker<IndexSequence<bound_indices...>,
+               StorageType, TypeList<Unwrappers...>,
+               InvokeHelperType, R(UnboundForwardArgs...)> {
+  static R Run(BindStateBase* base,
+               UnboundForwardArgs... unbound_args) {
+    StorageType* storage = static_cast<StorageType*>(base);
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    return InvokeHelperType::MakeItSo(
+        storage->runnable_,
+        Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
+        CallbackForward(unbound_args)...);
+  }
+};
+
+
+// BindState<>
+//
+// This stores all the state passed into Bind() and is also where most
+// of the template resolution magic occurs.
+//
+// Runnable is the functor we are binding arguments to.
+// RunType is type of the Run() function that the Invoker<> should use.
+// Normally, this is the same as the RunType of the Runnable, but it can
+// be different if an adapter like IgnoreResult() has been used.
+//
+// BoundArgsType contains the storage type for all the bound arguments by
+// (ab)using a function type.
+template <typename Runnable, typename RunType, typename BoundArgList>
+struct BindState;
+
+template <typename Runnable,
+          typename R, typename... Args,
+          typename... BoundArgs>
+struct BindState<Runnable, R(Args...), TypeList<BoundArgs...>>
+    : public BindStateBase {
+ private:
+  using StorageType = BindState<Runnable, R(Args...), TypeList<BoundArgs...>>;
+  using RunnableType = Runnable;
+
+  // true_type if Runnable is a method invocation and the first bound argument
+  // is a WeakPtr.
+  using IsWeakCall =
+      IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
+
+  using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
+  using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
+  using UnboundForwardArgs = DropTypeListItem<
+      sizeof...(BoundArgs),
+      TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
+  using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
+
+  using InvokeHelperArgs = ConcatTypeLists<
+      TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>,
+      UnboundForwardArgs>;
+  using InvokeHelperType =
+      InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>;
+
+  using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
+
+ public:
+  using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
+                              InvokeHelperType, UnboundForwardRunType>;
+  using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
+
+  BindState(const Runnable& runnable, const BoundArgs&... bound_args)
+      : runnable_(runnable), ref_(bound_args...), bound_args_(bound_args...) {}
+
+  RunnableType runnable_;
+  MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
+  Tuple<BoundArgs...> bound_args_;
+
+ private:
+  ~BindState() override {}
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_H_
diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h
new file mode 100644
index 0000000..c3f7477
--- /dev/null
+++ b/base/bind_internal_win.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Specializations of RunnableAdapter<> for Windows specific calling
+// conventions.  Please see base/bind_internal.h for more info.
+
+#ifndef BASE_BIND_INTERNAL_WIN_H_
+#define BASE_BIND_INTERNAL_WIN_H_
+
+// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
+// the same as __cdecl which would turn the following specializations into
+// multiple definitions.
+#if !defined(ARCH_CPU_X86_64)
+
+namespace base {
+namespace internal {
+
+template <typename Functor>
+class RunnableAdapter;
+
+// __stdcall Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(__stdcall *)(Args...)> {
+ public:
+  typedef R (RunType)(Args...);
+
+  explicit RunnableAdapter(R(__stdcall *function)(Args...))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+    return function_(args...);
+  }
+
+ private:
+  R (__stdcall *function_)(Args...);
+};
+
+// __fastcall Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(__fastcall *)(Args...)> {
+ public:
+  typedef R (RunType)(Args...);
+
+  explicit RunnableAdapter(R(__fastcall *function)(Args...))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+    return function_(args...);
+  }
+
+ private:
+  R (__fastcall *function_)(Args...);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !defined(ARCH_CPU_X86_64)
+
+#endif  // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
new file mode 100644
index 0000000..f885403
--- /dev/null
+++ b/base/bind_unittest.cc
@@ -0,0 +1,829 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+namespace base {
+namespace {
+
+class IncompleteType;
+
+class NoRef {
+ public:
+  NoRef() {}
+
+  MOCK_METHOD0(VoidMethod0, void(void));
+  MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
+
+  MOCK_METHOD0(IntMethod0, int(void));
+  MOCK_CONST_METHOD0(IntConstMethod0, int(void));
+
+ private:
+  // Particularly important in this test to ensure no copies are made.
+  DISALLOW_COPY_AND_ASSIGN(NoRef);
+};
+
+class HasRef : public NoRef {
+ public:
+  HasRef() {}
+
+  MOCK_CONST_METHOD0(AddRef, void(void));
+  MOCK_CONST_METHOD0(Release, bool(void));
+
+ private:
+  // Particularly important in this test to ensure no copies are made.
+  DISALLOW_COPY_AND_ASSIGN(HasRef);
+};
+
+class HasRefPrivateDtor : public HasRef {
+ private:
+  ~HasRefPrivateDtor() {}
+};
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class Parent {
+ public:
+  void AddRef(void) const {}
+  void Release(void) const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  void VirtualSet() override { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+  void VirtualSet() override { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+// Used for probing the number of copies that occur if a type must be coerced
+// during argument forwarding in the Run() methods.
+struct DerivedCopyCounter {
+  DerivedCopyCounter(int* copies, int* assigns)
+      : copies_(copies), assigns_(assigns) {
+  }
+  int* copies_;
+  int* assigns_;
+};
+
+// Used for probing the number of copies in an argument.
+class CopyCounter {
+ public:
+  CopyCounter(int* copies, int* assigns)
+      : copies_(copies), assigns_(assigns) {
+  }
+
+  CopyCounter(const CopyCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_) {
+    (*copies_)++;
+  }
+
+  // Probing for copies from coercion.
+  explicit CopyCounter(const DerivedCopyCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_) {
+    (*copies_)++;
+  }
+
+  const CopyCounter& operator=(const CopyCounter& rhs) {
+    copies_ = rhs.copies_;
+    assigns_ = rhs.assigns_;
+
+    if (assigns_) {
+      (*assigns_)++;
+    }
+
+    return *this;
+  }
+
+  int copies() const {
+    return *copies_;
+  }
+
+ private:
+  int* copies_;
+  int* assigns_;
+};
+
+class DeleteCounter {
+ public:
+  explicit DeleteCounter(int* deletes)
+      : deletes_(deletes) {
+  }
+
+  ~DeleteCounter() {
+    (*deletes_)++;
+  }
+
+  void VoidMethod0() {}
+
+ private:
+  int* deletes_;
+};
+
+template <typename T>
+T PassThru(T scoper) {
+  return scoper.Pass();
+}
+
+// Some test functions that we can Bind to.
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+int Identity(int n) {
+  return n;
+}
+
+int ArrayGet(const int array[], int n) {
+  return array[n];
+}
+
+int Sum(int a, int b, int c, int d, int e, int f) {
+  return a + b + c + d + e + f;
+}
+
+const char* CStringIdentity(const char* s) {
+  return s;
+}
+
+int GetCopies(const CopyCounter& counter) {
+  return counter.copies();
+}
+
+int UnwrapNoRefParent(NoRefParent p) {
+  return p.value;
+}
+
+int UnwrapNoRefParentPtr(NoRefParent* p) {
+  return p->value;
+}
+
+int UnwrapNoRefParentConstRef(const NoRefParent& p) {
+  return p.value;
+}
+
+void RefArgSet(int &n) {
+  n = 2;
+}
+
+void PtrArgSet(int *n) {
+  *n = 2;
+}
+
+int FunctionWithWeakFirstParam(WeakPtr<NoRef> o, int n) {
+  return n;
+}
+
+int FunctionWithScopedRefptrFirstParam(const scoped_refptr<HasRef>& o, int n) {
+  return n;
+}
+
+void TakesACallback(const Closure& callback) {
+  callback.Run();
+}
+
+class BindTest : public ::testing::Test {
+ public:
+  BindTest() {
+    const_has_ref_ptr_ = &has_ref_;
+    const_no_ref_ptr_ = &no_ref_;
+    static_func_mock_ptr = &static_func_mock_;
+  }
+
+  virtual ~BindTest() {
+  }
+
+  static void VoidFunc0(void) {
+    static_func_mock_ptr->VoidMethod0();
+  }
+
+  static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); }
+
+ protected:
+  StrictMock<NoRef> no_ref_;
+  StrictMock<HasRef> has_ref_;
+  const HasRef* const_has_ref_ptr_;
+  const NoRef* const_no_ref_ptr_;
+  StrictMock<NoRef> static_func_mock_;
+
+  // Used by the static functions to perform expectations.
+  static StrictMock<NoRef>* static_func_mock_ptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BindTest);
+};
+
+StrictMock<NoRef>* BindTest::static_func_mock_ptr;
+
+// Sanity check that we can instantiate a callback for each arity.
+TEST_F(BindTest, ArityTest) {
+  Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
+  EXPECT_EQ(63, c0.Run());
+
+  Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2);
+  EXPECT_EQ(75, c1.Run(13));
+
+  Callback<int(int,int)> c2 = Bind(&Sum, 32, 16, 8, 4);
+  EXPECT_EQ(85, c2.Run(13, 12));
+
+  Callback<int(int,int,int)> c3 = Bind(&Sum, 32, 16, 8);
+  EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+  Callback<int(int,int,int,int)> c4 = Bind(&Sum, 32, 16);
+  EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+  Callback<int(int,int,int,int,int)> c5 = Bind(&Sum, 32);
+  EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+  Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+  EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+}
+
+// Test the Currying ability of the Callback system.
+TEST_F(BindTest, CurryingTest) {
+  Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+  EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+
+  Callback<int(int,int,int,int,int)> c5 = Bind(c6, 32);
+  EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+  Callback<int(int,int,int,int)> c4 = Bind(c5, 16);
+  EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+  Callback<int(int,int,int)> c3 = Bind(c4, 8);
+  EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+  Callback<int(int,int)> c2 = Bind(c3, 4);
+  EXPECT_EQ(85, c2.Run(13, 12));
+
+  Callback<int(int)> c1 = Bind(c2, 2);
+  EXPECT_EQ(75, c1.Run(13));
+
+  Callback<int(void)> c0 = Bind(c1, 1);
+  EXPECT_EQ(63, c0.Run());
+}
+
+// Test that currying the rvalue result of another Bind() works correctly.
+//   - rvalue should be usable as argument to Bind().
+//   - multiple runs of resulting Callback remain valid.
+TEST_F(BindTest, CurryingRvalueResultOfBind) {
+  int n = 0;
+  Closure cb = base::Bind(&TakesACallback, base::Bind(&PtrArgSet, &n));
+
+  // If we implement Bind() such that the return value has auto_ptr-like
+  // semantics, the second call here will fail because ownership of
+  // the internal BindState<> would have been transfered to a *temporary*
+  // constructon of a Callback object on the first call.
+  cb.Run();
+  EXPECT_EQ(2, n);
+
+  n = 0;
+  cb.Run();
+  EXPECT_EQ(2, n);
+}
+
+// Function type support.
+//   - Normal function.
+//   - Normal function bound with non-refcounted first argument.
+//   - Method bound to non-const object.
+//   - Method bound to scoped_refptr.
+//   - Const method bound to non-const object.
+//   - Const method bound to const object.
+//   - Derived classes can be used with pointers to non-virtual base functions.
+//   - Derived classes can be used with pointers to virtual base functions (and
+//     preserve virtual dispatch).
+TEST_F(BindTest, FunctionTypeSupport) {
+  EXPECT_CALL(static_func_mock_, VoidMethod0());
+  EXPECT_CALL(has_ref_, AddRef()).Times(5);
+  EXPECT_CALL(has_ref_, Release()).Times(5);
+  EXPECT_CALL(has_ref_, VoidMethod0()).Times(2);
+  EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
+
+  Closure normal_cb = Bind(&VoidFunc0);
+  Callback<NoRef*(void)> normal_non_refcounted_cb =
+      Bind(&PolymorphicIdentity<NoRef*>, &no_ref_);
+  normal_cb.Run();
+  EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run());
+
+  Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_);
+  Closure method_refptr_cb = Bind(&HasRef::VoidMethod0,
+                                  make_scoped_refptr(&has_ref_));
+  Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0,
+                                              &has_ref_);
+  Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0,
+                                           const_has_ref_ptr_);
+  method_cb.Run();
+  method_refptr_cb.Run();
+  const_method_nonconst_obj_cb.Run();
+  const_method_const_obj_cb.Run();
+
+  Child child;
+  child.value = 0;
+  Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child);
+  virtual_set_cb.Run();
+  EXPECT_EQ(kChildValue, child.value);
+
+  child.value = 0;
+  Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child);
+  non_virtual_set_cb.Run();
+  EXPECT_EQ(kParentValue, child.value);
+}
+
+// Return value support.
+//   - Function with return value.
+//   - Method with return value.
+//   - Const method with return value.
+TEST_F(BindTest, ReturnValues) {
+  EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+  EXPECT_CALL(has_ref_, AddRef()).Times(3);
+  EXPECT_CALL(has_ref_, Release()).Times(3);
+  EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337));
+  EXPECT_CALL(has_ref_, IntConstMethod0())
+      .WillOnce(Return(41337))
+      .WillOnce(Return(51337));
+
+  Callback<int(void)> normal_cb = Bind(&IntFunc0);
+  Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+  Callback<int(void)> const_method_nonconst_obj_cb =
+      Bind(&HasRef::IntConstMethod0, &has_ref_);
+  Callback<int(void)> const_method_const_obj_cb =
+      Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
+  EXPECT_EQ(1337, normal_cb.Run());
+  EXPECT_EQ(31337, method_cb.Run());
+  EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run());
+  EXPECT_EQ(51337, const_method_const_obj_cb.Run());
+}
+
+// IgnoreResult adapter test.
+//   - Function with return value.
+//   - Method with return value.
+//   - Const Method with return.
+//   - Method with return value bound to WeakPtr<>.
+//   - Const Method with return bound to WeakPtr<>.
+TEST_F(BindTest, IgnoreResult) {
+  EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+  EXPECT_CALL(has_ref_, AddRef()).Times(2);
+  EXPECT_CALL(has_ref_, Release()).Times(2);
+  EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10));
+  EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11));
+  EXPECT_CALL(no_ref_, IntMethod0()).WillOnce(Return(12));
+  EXPECT_CALL(no_ref_, IntConstMethod0()).WillOnce(Return(13));
+
+  Closure normal_func_cb = Bind(IgnoreResult(&IntFunc0));
+  normal_func_cb.Run();
+
+  Closure non_void_method_cb =
+      Bind(IgnoreResult(&HasRef::IntMethod0), &has_ref_);
+  non_void_method_cb.Run();
+
+  Closure non_void_const_method_cb =
+      Bind(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_);
+  non_void_const_method_cb.Run();
+
+  WeakPtrFactory<NoRef> weak_factory(&no_ref_);
+  WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_);
+
+  Closure non_void_weak_method_cb  =
+      Bind(IgnoreResult(&NoRef::IntMethod0), weak_factory.GetWeakPtr());
+  non_void_weak_method_cb.Run();
+
+  Closure non_void_weak_const_method_cb =
+      Bind(IgnoreResult(&NoRef::IntConstMethod0), weak_factory.GetWeakPtr());
+  non_void_weak_const_method_cb.Run();
+
+  weak_factory.InvalidateWeakPtrs();
+  non_void_weak_const_method_cb.Run();
+  non_void_weak_method_cb.Run();
+}
+
+// Argument binding tests.
+//   - Argument binding to primitive.
+//   - Argument binding to primitive pointer.
+//   - Argument binding to a literal integer.
+//   - Argument binding to a literal string.
+//   - Argument binding with template function.
+//   - Argument binding to an object.
+//   - Argument binding to pointer to incomplete type.
+//   - Argument gets type converted.
+//   - Pointer argument gets converted.
+//   - Const Reference forces conversion.
+TEST_F(BindTest, ArgumentBinding) {
+  int n = 2;
+
+  Callback<int(void)> bind_primitive_cb = Bind(&Identity, n);
+  EXPECT_EQ(n, bind_primitive_cb.Run());
+
+  Callback<int*(void)> bind_primitive_pointer_cb =
+      Bind(&PolymorphicIdentity<int*>, &n);
+  EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
+
+  Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3);
+  EXPECT_EQ(3, bind_int_literal_cb.Run());
+
+  Callback<const char*(void)> bind_string_literal_cb =
+      Bind(&CStringIdentity, "hi");
+  EXPECT_STREQ("hi", bind_string_literal_cb.Run());
+
+  Callback<int(void)> bind_template_function_cb =
+      Bind(&PolymorphicIdentity<int>, 4);
+  EXPECT_EQ(4, bind_template_function_cb.Run());
+
+  NoRefParent p;
+  p.value = 5;
+  Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+  EXPECT_EQ(5, bind_object_cb.Run());
+
+  IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123);
+  Callback<IncompleteType*(void)> bind_incomplete_ptr_cb =
+      Bind(&PolymorphicIdentity<IncompleteType*>, incomplete_ptr);
+  EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run());
+
+  NoRefChild c;
+  c.value = 6;
+  Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+  EXPECT_EQ(6, bind_promotes_cb.Run());
+
+  c.value = 7;
+  Callback<int(void)> bind_pointer_promotes_cb =
+      Bind(&UnwrapNoRefParentPtr, &c);
+  EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
+
+  c.value = 8;
+  Callback<int(void)> bind_const_reference_promotes_cb =
+      Bind(&UnwrapNoRefParentConstRef, c);
+  EXPECT_EQ(8, bind_const_reference_promotes_cb.Run());
+}
+
+// Unbound argument type support tests.
+//   - Unbound value.
+//   - Unbound pointer.
+//   - Unbound reference.
+//   - Unbound const reference.
+//   - Unbound unsized array.
+//   - Unbound sized array.
+//   - Unbound array-of-arrays.
+TEST_F(BindTest, UnboundArgumentTypeSupport) {
+  Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic1<int>);
+  Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic1<int*>);
+  Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic1<int&>);
+  Callback<void(const int&)> unbound_const_ref_cb =
+      Bind(&VoidPolymorphic1<const int&>);
+  Callback<void(int[])> unbound_unsized_array_cb =
+      Bind(&VoidPolymorphic1<int[]>);
+  Callback<void(int[2])> unbound_sized_array_cb =
+      Bind(&VoidPolymorphic1<int[2]>);
+  Callback<void(int[][2])> unbound_array_of_arrays_cb =
+      Bind(&VoidPolymorphic1<int[][2]>);
+}
+
+// Function with unbound reference parameter.
+//   - Original parameter is modified by callback.
+TEST_F(BindTest, UnboundReferenceSupport) {
+  int n = 0;
+  Callback<void(int&)> unbound_ref_cb = Bind(&RefArgSet);
+  unbound_ref_cb.Run(n);
+  EXPECT_EQ(2, n);
+}
+
+// Functions that take reference parameters.
+//  - Forced reference parameter type still stores a copy.
+//  - Forced const reference parameter type still stores a copy.
+TEST_F(BindTest, ReferenceArgumentBinding) {
+  int n = 1;
+  int& ref_n = n;
+  const int& const_ref_n = n;
+
+  Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n);
+  EXPECT_EQ(n, ref_copies_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, ref_copies_cb.Run());
+
+  Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n);
+  EXPECT_EQ(n, const_ref_copies_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, const_ref_copies_cb.Run());
+}
+
+// Check that we can pass in arrays and have them be stored as a pointer.
+//  - Array of values stores a pointer.
+//  - Array of const values stores a pointer.
+TEST_F(BindTest, ArrayArgumentBinding) {
+  int array[4] = {1, 1, 1, 1};
+  const int (*const_array_ptr)[4] = &array;
+
+  Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1);
+  EXPECT_EQ(1, array_cb.Run());
+
+  Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
+  EXPECT_EQ(1, const_array_cb.Run());
+
+  array[1] = 3;
+  EXPECT_EQ(3, array_cb.Run());
+  EXPECT_EQ(3, const_array_cb.Run());
+}
+
+// Verify SupportsAddRefAndRelease correctly introspects the class type for
+// AddRef() and Release().
+//  - Class with AddRef() and Release()
+//  - Class without AddRef() and Release()
+//  - Derived Class with AddRef() and Release()
+//  - Derived Class without AddRef() and Release()
+//  - Derived Class with AddRef() and Release() and a private destructor.
+TEST_F(BindTest, SupportsAddRefAndRelease) {
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value);
+  EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value);
+
+  // StrictMock<T> is a derived class of T.  So, we use StrictMock<HasRef> and
+  // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over
+  // inheritance.
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value);
+  EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value);
+
+  // This matters because the implementation creates a dummy class that
+  // inherits from the template type.
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRefPrivateDtor>::value);
+}
+
+// Unretained() wrapper support.
+//   - Method bound to Unretained() non-const object.
+//   - Const method bound to Unretained() non-const object.
+//   - Const method bound to Unretained() const object.
+TEST_F(BindTest, Unretained) {
+  EXPECT_CALL(no_ref_, VoidMethod0());
+  EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+  Callback<void(void)> method_cb =
+      Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
+  method_cb.Run();
+
+  Callback<void(void)> const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
+  const_method_cb.Run();
+
+  Callback<void(void)> const_method_const_ptr_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
+  const_method_const_ptr_cb.Run();
+}
+
+// WeakPtr() support.
+//   - Method bound to WeakPtr<> to non-const object.
+//   - Const method bound to WeakPtr<> to non-const object.
+//   - Const method bound to WeakPtr<> to const object.
+//   - Normal Function with WeakPtr<> as P1 can have return type and is
+//     not canceled.
+TEST_F(BindTest, WeakPtr) {
+  EXPECT_CALL(no_ref_, VoidMethod0());
+  EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+  WeakPtrFactory<NoRef> weak_factory(&no_ref_);
+  WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_);
+
+  Closure method_cb =
+      Bind(&NoRef::VoidMethod0, weak_factory.GetWeakPtr());
+  method_cb.Run();
+
+  Closure const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr());
+  const_method_cb.Run();
+
+  Closure const_method_const_ptr_cb =
+      Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr());
+  const_method_const_ptr_cb.Run();
+
+  Callback<int(int)> normal_func_cb =
+      Bind(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr());
+  EXPECT_EQ(1, normal_func_cb.Run(1));
+
+  weak_factory.InvalidateWeakPtrs();
+  const_weak_factory.InvalidateWeakPtrs();
+
+  method_cb.Run();
+  const_method_cb.Run();
+  const_method_const_ptr_cb.Run();
+
+  // Still runs even after the pointers are invalidated.
+  EXPECT_EQ(2, normal_func_cb.Run(2));
+}
+
+// ConstRef() wrapper support.
+//   - Binding w/o ConstRef takes a copy.
+//   - Binding a ConstRef takes a reference.
+//   - Binding ConstRef to a function ConstRef does not copy on invoke.
+TEST_F(BindTest, ConstRef) {
+  int n = 1;
+
+  Callback<int(void)> copy_cb = Bind(&Identity, n);
+  Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n));
+  EXPECT_EQ(n, copy_cb.Run());
+  EXPECT_EQ(n, const_ref_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, copy_cb.Run());
+  EXPECT_EQ(n, const_ref_cb.Run());
+
+  int copies = 0;
+  int assigns = 0;
+  CopyCounter counter(&copies, &assigns);
+  Callback<int(void)> all_const_ref_cb =
+      Bind(&GetCopies, ConstRef(counter));
+  EXPECT_EQ(0, all_const_ref_cb.Run());
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+TEST_F(BindTest, ScopedRefptr) {
+  // BUG: The scoped_refptr should cause the only AddRef()/Release() pair. But
+  // due to a bug in base::Bind(), there's an extra call when invoking the
+  // callback.
+  // https://code.google.com/p/chromium/issues/detail?id=251937
+  EXPECT_CALL(has_ref_, AddRef()).Times(2);
+  EXPECT_CALL(has_ref_, Release()).Times(2);
+
+  const scoped_refptr<StrictMock<HasRef> > refptr(&has_ref_);
+
+  Callback<int(void)> scoped_refptr_const_ref_cb =
+      Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1);
+  EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run());
+}
+
+// Test Owned() support.
+TEST_F(BindTest, Owned) {
+  int deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+
+  // If we don't capture, delete happens on Callback destruction/reset.
+  // return the same value.
+  Callback<DeleteCounter*(void)> no_capture_cb =
+      Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter));
+  ASSERT_EQ(counter, no_capture_cb.Run());
+  ASSERT_EQ(counter, no_capture_cb.Run());
+  EXPECT_EQ(0, deletes);
+  no_capture_cb.Reset();  // This should trigger a delete.
+  EXPECT_EQ(1, deletes);
+
+  deletes = 0;
+  counter = new DeleteCounter(&deletes);
+  base::Closure own_object_cb =
+      Bind(&DeleteCounter::VoidMethod0, Owned(counter));
+  own_object_cb.Run();
+  EXPECT_EQ(0, deletes);
+  own_object_cb.Reset();
+  EXPECT_EQ(1, deletes);
+}
+
+// Passed() wrapper support.
+//   - Passed() can be constructed from a pointer to scoper.
+//   - Passed() can be constructed from a scoper rvalue.
+//   - Using Passed() gives Callback Ownership.
+//   - Ownership is transferred from Callback to callee on the first Run().
+//   - Callback supports unbound arguments.
+TEST_F(BindTest, ScopedPtr) {
+  int deletes = 0;
+
+  // Tests the Passed() function's support for pointers.
+  scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
+  Callback<scoped_ptr<DeleteCounter>(void)> unused_callback =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // If we never invoke the Callback, it retains ownership and deletes.
+  unused_callback.Reset();
+  EXPECT_EQ(1, deletes);
+
+  // Tests the Passed() function's support for rvalues.
+  deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+  Callback<scoped_ptr<DeleteCounter>(void)> callback =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >,
+           Passed(scoped_ptr<DeleteCounter>(counter)));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // Check that ownership can be transferred back out.
+  scoped_ptr<DeleteCounter> result = callback.Run();
+  ASSERT_EQ(counter, result.get());
+  EXPECT_EQ(0, deletes);
+
+  // Resetting does not delete since ownership was transferred.
+  callback.Reset();
+  EXPECT_EQ(0, deletes);
+
+  // Ensure that we actually did get ownership.
+  result.reset();
+  EXPECT_EQ(1, deletes);
+
+  // Test unbound argument forwarding.
+  Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >);
+  ptr.reset(new DeleteCounter(&deletes));
+  cb_unbound.Run(ptr.Pass());
+}
+
+// Argument Copy-constructor usage for non-reference parameters.
+//   - Bound arguments are only copied once.
+//   - Forwarded arguments are only copied once.
+//   - Forwarded arguments with coercions are only copied twice (once for the
+//     coercion, and one for the final dispatch).
+TEST_F(BindTest, ArgumentCopies) {
+  int copies = 0;
+  int assigns = 0;
+
+  CopyCounter counter(&copies, &assigns);
+
+  Callback<void(void)> copy_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>, counter);
+  EXPECT_GE(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Callback<void(CopyCounter)> forward_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>);
+  forward_cb.Run(counter);
+  EXPECT_GE(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  DerivedCopyCounter derived(&copies, &assigns);
+  Callback<void(CopyCounter)> coerce_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>);
+  coerce_cb.Run(CopyCounter(derived));
+  EXPECT_GE(2, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+// Callback construction and assignment tests.
+//   - Construction from an InvokerStorageHolder should not cause ref/deref.
+//   - Assignment from other callback should only cause one ref
+//
+// TODO(ajwong): Is there actually a way to test this?
+
+#if defined(OS_WIN)
+int __fastcall FastCallFunc(int n) {
+  return n;
+}
+
+int __stdcall StdCallFunc(int n) {
+  return n;
+}
+
+// Windows specific calling convention support.
+//   - Can bind a __fastcall function.
+//   - Can bind a __stdcall function.
+TEST_F(BindTest, WindowsCallingConventions) {
+  Callback<int(void)> fastcall_cb = Bind(&FastCallFunc, 1);
+  EXPECT_EQ(1, fastcall_cb.Run());
+
+  Callback<int(void)> stdcall_cb = Bind(&StdCallFunc, 2);
+  EXPECT_EQ(2, stdcall_cb.Run());
+}
+#endif
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+// Test null callbacks cause a DCHECK.
+TEST(BindDeathTest, NullCallback) {
+  base::Callback<void(int)> null_cb;
+  ASSERT_TRUE(null_cb.is_null());
+  EXPECT_DEATH(base::Bind(null_cb, 42), "");
+}
+
+#endif  // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) &&
+        //     GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
new file mode 100644
index 0000000..2596386
--- /dev/null
+++ b/base/bind_unittest.nc
@@ -0,0 +1,202 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// Do not put everything inside an anonymous namespace.  If you do, many of the
+// helper function declarations will generate unused definition warnings.
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class NoRef {
+ public:
+  void VoidMethod0() {}
+  void VoidConstMethod0() const {}
+  int IntMethod0() { return 1; }
+};
+
+class HasRef : public NoRef, public base::RefCounted<HasRef> {
+};
+
+class Parent {
+ public:
+  void AddRef(void) const {}
+  void Release(void) const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  virtual void VirtualSet() { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+  virtual void VirtualSet() { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+int UnwrapParentRef(Parent& p) {
+  return p.value;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+#if defined(NCTEST_METHOD_ON_CONST_OBJECT)  // [r"fatal error: cannot initialize a parameter of type 'base::NoRef \*' with an lvalue of type 'typename enable_if<!IsMoveOnlyType<const HasRef \*const>::value, const HasRef \*const>::type' \(aka 'const base::HasRef \*const'\)"]
+
+// Method bound to const-object.
+//
+// Only const methods should be allowed to work with const objects.
+void WontCompile() {
+  HasRef has_ref;
+  const HasRef* const_has_ref_ptr_ = &has_ref;
+  Callback<void(void)> method_to_const_cb =
+      Bind(&HasRef::VoidMethod0, const_has_ref_ptr_);
+  method_to_const_cb.Run();
+}
+
+#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
+
+// Method bound to non-refcounted object.
+//
+// We require refcounts unless you have Unretained().
+void WontCompile() {
+  NoRef no_ref;
+  Callback<void(void)> no_ref_cb =
+      Bind(&NoRef::VoidMethod0, &no_ref);
+  no_ref_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
+
+// Const Method bound to non-refcounted object.
+//
+// We require refcounts unless you have Unretained().
+void WontCompile() {
+  NoRef no_ref;
+  Callback<void(void)> no_ref_const_cb =
+      Bind(&NoRef::VoidConstMethod0, &no_ref);
+  no_ref_const_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_POINTER)  // [r"fatal error: reference to type 'base::NoRef \*const' could not bind to an lvalue of type 'typename enable_if<!IsMoveOnlyType<const NoRef \*const>::value, const NoRef \*const>::type' \(aka 'const base::NoRef \*const'\)"]
+
+// Const argument used with non-const pointer parameter of same type.
+//
+// This is just a const-correctness check.
+void WontCompile() {
+  const NoRef* const_no_ref_ptr;
+  Callback<NoRef*(void)> pointer_same_cb =
+      Bind(&PolymorphicIdentity<NoRef*>, const_no_ref_ptr);
+  pointer_same_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_POINTER_SUBTYPE)  // [r"fatal error: reference to type 'base::NoRefParent \*const' could not bind to an lvalue of type 'typename enable_if<!IsMoveOnlyType<const NoRefChild \*const>::value, const NoRefChild \*const>::type' \(aka 'const base::NoRefChild \*const'\)"]
+
+// Const argument used with non-const pointer parameter of super type.
+//
+// This is just a const-correctness check.
+void WontCompile() {
+  const NoRefChild* const_child_ptr;
+  Callback<NoRefParent*(void)> pointer_super_cb =
+    Bind(&PolymorphicIdentity<NoRefParent*>, const_child_ptr);
+  pointer_super_cb.Run();
+}
+
+#elif defined(DISABLED_NCTEST_DISALLOW_NON_CONST_REF_PARAM)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
+// TODO(dcheng): I think there's a type safety promotion issue here where we can
+// pass a const ref to a non const-ref function, or vice versa accidentally. Or
+// we make a copy accidentally. Check.
+
+// Functions with reference parameters, unsupported.
+//
+// First, non-const reference parameters are disallowed by the Google
+// style guide. Second, since we are doing argument forwarding it becomes
+// very tricky to avoid copies, maintain const correctness, and not
+// accidentally have the function be modifying a temporary, or a copy.
+void WontCompile() {
+  Parent p;
+  Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapParentRef);
+  ref_arg_cb.Run(p);
+}
+
+#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM)  // [r"fatal error: static_assert failed \"do_not_bind_functions_with_nonconst_ref\""]
+
+// Binding functions with reference parameters, unsupported.
+//
+// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM
+void WontCompile() {
+  Parent p;
+  Callback<int(void)> ref_cb = Bind(&UnwrapParentRef, p);
+  ref_cb.Run();
+}
+
+#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION)  // [r"fatal error: static_assert failed \"first_bound_argument_to_method_cannot_be_array\""]
+
+// A method should not be bindable with an array of objects.
+//
+// This is likely not wanted behavior. We specifically check for it though
+// because it is possible, depending on how you implement prebinding, to
+// implicitly convert an array type to a pointer type.
+void WontCompile() {
+  HasRef p[10];
+  Callback<void(void)> method_bound_to_array_cb =
+      Bind(&HasRef::VoidMethod0, p);
+  method_bound_to_array_cb.Run();
+}
+
+#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"fatal error: static_assert failed \"a_parameter_is_refcounted_type_and_needs_scoped_refptr\""]
+
+// Refcounted types should not be bound as a raw pointer.
+void WontCompile() {
+  HasRef for_raw_ptr;
+  int a;
+  Callback<void(void)> ref_count_as_raw_ptr_a =
+      Bind(&VoidPolymorphic1<int*>, &a);
+  Callback<void(void)> ref_count_as_raw_ptr =
+      Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr);
+}
+
+#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID)  // [r"fatal error: static_assert failed \"weak_ptrs_can_only_bind_to_methods_without_return_values\""]
+
+// WeakPtrs cannot be bound to methods with return types.
+void WontCompile() {
+  NoRef no_ref;
+  WeakPtrFactory<NoRef> weak_factory(&no_ref);
+  Callback<int(void)> weak_ptr_with_non_void_return_type =
+      Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr());
+  weak_ptr_with_non_void_return_type.Run();
+}
+
+#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES)  // [r"fatal error: no viable conversion from 'Callback<typename internal::BindState<typename internal::FunctorTraits<void \(\*\)\(int\)>::RunnableType, typename internal::FunctorTraits<void \(\*\)\(int\)>::RunType, internal::TypeList<> >::UnboundRunType>' to 'Callback<void \(\)>'"]
+
+// Bind result cannot be assigned to Callbacks with a mismatching type.
+void WontCompile() {
+  Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1<int>);
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/bits.h b/base/bits.h
new file mode 100644
index 0000000..b2209e8
--- /dev/null
+++ b/base/bits.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines some bit utilities.
+
+#ifndef BASE_BITS_H_
+#define BASE_BITS_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace bits {
+
+// Returns the integer i such as 2^i <= n < 2^(i+1)
+inline int Log2Floor(uint32 n) {
+  if (n == 0)
+    return -1;
+  int log = 0;
+  uint32 value = n;
+  for (int i = 4; i >= 0; --i) {
+    int shift = (1 << i);
+    uint32 x = value >> shift;
+    if (x != 0) {
+      value = x;
+      log += shift;
+    }
+  }
+  DCHECK_EQ(value, 1u);
+  return log;
+}
+
+// Returns the integer i such as 2^(i-1) < n <= 2^i
+inline int Log2Ceiling(uint32 n) {
+  if (n == 0) {
+    return -1;
+  } else {
+    // Log2Floor returns -1 for 0, so the following works correctly for n=1.
+    return 1 + Log2Floor(n - 1);
+  }
+}
+
+}  // namespace bits
+}  // namespace base
+
+#endif  // BASE_BITS_H_
diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc
new file mode 100644
index 0000000..e913d6a
--- /dev/null
+++ b/base/bits_unittest.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the unit tests for the bit utilities.
+
+#include "base/bits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace bits {
+
+TEST(BitsTest, Log2Floor) {
+  EXPECT_EQ(-1, Log2Floor(0));
+  EXPECT_EQ(0, Log2Floor(1));
+  EXPECT_EQ(1, Log2Floor(2));
+  EXPECT_EQ(1, Log2Floor(3));
+  EXPECT_EQ(2, Log2Floor(4));
+  for (int i = 3; i < 31; ++i) {
+    unsigned int value = 1U << i;
+    EXPECT_EQ(i, Log2Floor(value));
+    EXPECT_EQ(i, Log2Floor(value + 1));
+    EXPECT_EQ(i, Log2Floor(value + 2));
+    EXPECT_EQ(i - 1, Log2Floor(value - 1));
+    EXPECT_EQ(i - 1, Log2Floor(value - 2));
+  }
+  EXPECT_EQ(31, Log2Floor(0xffffffffU));
+}
+
+TEST(BitsTest, Log2Ceiling) {
+  EXPECT_EQ(-1, Log2Ceiling(0));
+  EXPECT_EQ(0, Log2Ceiling(1));
+  EXPECT_EQ(1, Log2Ceiling(2));
+  EXPECT_EQ(2, Log2Ceiling(3));
+  EXPECT_EQ(2, Log2Ceiling(4));
+  for (int i = 3; i < 31; ++i) {
+    unsigned int value = 1U << i;
+    EXPECT_EQ(i, Log2Ceiling(value));
+    EXPECT_EQ(i + 1, Log2Ceiling(value + 1));
+    EXPECT_EQ(i + 1, Log2Ceiling(value + 2));
+    EXPECT_EQ(i, Log2Ceiling(value - 1));
+    EXPECT_EQ(i, Log2Ceiling(value - 2));
+  }
+  EXPECT_EQ(32, Log2Ceiling(0xffffffffU));
+}
+
+}  // namespace bits
+}  // namespace base
diff --git a/base/build_time.cc b/base/build_time.cc
new file mode 100644
index 0000000..b8b4296
--- /dev/null
+++ b/base/build_time.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/build_time.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace base {
+
+Time GetBuildTime() {
+  Time integral_build_time;
+  // The format of __DATE__ and __TIME__ is specified by the ANSI C Standard,
+  // section 6.8.8.
+  //
+  // __DATE__ is exactly "Mmm DD YYYY".
+  // __TIME__ is exactly "hh:mm:ss".
+#if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
+  const char kDateTime[] = "Sep 02 2008 08:00:00 PST";
+#else
+  const char kDateTime[] = __DATE__ " " __TIME__ " PST";
+#endif
+  bool result = Time::FromString(kDateTime, &integral_build_time);
+  DCHECK(result);
+  return integral_build_time;
+}
+
+}  // namespace base
diff --git a/base/build_time.h b/base/build_time.h
new file mode 100644
index 0000000..4f0abc3
--- /dev/null
+++ b/base/build_time.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BUILD_TIME_H_
+#define BASE_BUILD_TIME_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// GetBuildTime returns the time at which the current binary was built.
+//
+// This uses the __DATE__ and __TIME__ macros, which don't trigger a rebuild
+// when they change. However, official builds will always be rebuilt from
+// scratch.
+//
+// Also, since __TIME__ doesn't include a timezone, this value should only be
+// considered accurate to a day.
+//
+// NOTE: This function is disabled except for the official builds, by default
+// the date returned is "Sep 02 2008 08:00:00 PST".
+Time BASE_EXPORT GetBuildTime();
+
+}  // namespace base
+
+#endif  // BASE_BUILD_TIME_H_
diff --git a/base/build_time_unittest.cc b/base/build_time_unittest.cc
new file mode 100644
index 0000000..aac64a7
--- /dev/null
+++ b/base/build_time_unittest.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/build_time.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(BuildTime, DateLooksValid) {
+#if !defined(DONT_EMBED_BUILD_METADATA)
+  char build_date[] = __DATE__;
+#else
+  char build_date[] = "Sep 02 2008";
+#endif
+
+  EXPECT_EQ(11u, strlen(build_date));
+  EXPECT_EQ(' ', build_date[3]);
+  EXPECT_EQ(' ', build_date[6]);
+}
+
+TEST(BuildTime, TimeLooksValid) {
+#if defined(DONT_EMBED_BUILD_METADATA)
+  char build_time[] = "08:00:00";
+#else
+  char build_time[] = __TIME__;
+#endif
+
+  EXPECT_EQ(8u, strlen(build_time));
+  EXPECT_EQ(':', build_time[2]);
+  EXPECT_EQ(':', build_time[5]);
+}
+
+TEST(BuildTime, DoesntCrash) {
+  // Since __DATE__ isn't updated unless one does a clobber build, we can't
+  // really test the value returned by it, except to check that it doesn't
+  // crash.
+  base::GetBuildTime();
+}
diff --git a/base/callback.h b/base/callback.h
new file mode 100644
index 0000000..00669dd
--- /dev/null
+++ b/base/callback.h
@@ -0,0 +1,411 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_H_
+#define BASE_CALLBACK_H_
+
+#include "base/callback_forward.h"
+#include "base/callback_internal.h"
+#include "base/template_util.h"
+
+// NOTE: Header files that do not require the full definition of Callback or
+// Closure should #include "base/callback_forward.h" instead of this file.
+
+// -----------------------------------------------------------------------------
+// Introduction
+// -----------------------------------------------------------------------------
+//
+// The templated Callback class is a generalized function object. Together
+// with the Bind() function in bind.h, they provide a type-safe method for
+// performing partial application of functions.
+//
+// Partial application (or "currying") is the process of binding a subset of
+// a function's arguments to produce another function that takes fewer
+// arguments. This can be used to pass around a unit of delayed execution,
+// much like lexical closures are used in other languages. For example, it
+// is used in Chromium code to schedule tasks on different MessageLoops.
+//
+// A callback with no unbound input parameters (base::Callback<void(void)>)
+// is called a base::Closure. Note that this is NOT the same as what other
+// languages refer to as a closure -- it does not retain a reference to its
+// enclosing environment.
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for basic stuff
+// -----------------------------------------------------------------------------
+//
+// BINDING A BARE FUNCTION
+//
+//   int Return5() { return 5; }
+//   base::Callback<int(void)> func_cb = base::Bind(&Return5);
+//   LOG(INFO) << func_cb.Run();  // Prints 5.
+//
+// BINDING A CLASS METHOD
+//
+//   The first argument to bind is the member function to call, the second is
+//   the object on which to call it.
+//
+//   class Ref : public base::RefCountedThreadSafe<Ref> {
+//    public:
+//     int Foo() { return 3; }
+//     void PrintBye() { LOG(INFO) << "bye."; }
+//   };
+//   scoped_refptr<Ref> ref = new Ref();
+//   base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+//   LOG(INFO) << ref_cb.Run();  // Prints out 3.
+//
+//   By default the object must support RefCounted or you will get a compiler
+//   error. If you're passing between threads, be sure it's
+//   RefCountedThreadSafe! See "Advanced binding of member functions" below if
+//   you don't want to use reference counting.
+//
+// RUNNING A CALLBACK
+//
+//   Callbacks can be run with their "Run" method, which has the same
+//   signature as the template argument to the callback.
+//
+//   void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+//     callback.Run(5, "hello");
+//   }
+//
+//   Callbacks can be run more than once (they don't get deleted or marked when
+//   run). However, this precludes using base::Passed (see below).
+//
+//   void DoSomething(const base::Callback<double(double)>& callback) {
+//     double myresult = callback.Run(3.14159);
+//     myresult += callback.Run(2.71828);
+//   }
+//
+// PASSING UNBOUND INPUT PARAMETERS
+//
+//   Unbound parameters are specified at the time a callback is Run(). They are
+//   specified in the Callback template type:
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
+//   cb.Run(23, "hello, world");
+//
+// PASSING BOUND INPUT PARAMETERS
+//
+//   Bound parameters are specified when you create thee callback as arguments
+//   to Bind(). They will be passed to the function and the Run()ner of the
+//   callback doesn't see those values or even know that the function it's
+//   calling.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+//   cb.Run();
+//
+//   A callback with no unbound input parameters (base::Callback<void(void)>)
+//   is called a base::Closure. So we could have also written:
+//
+//   base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
+//
+//   When calling member functions, bound parameters just go after the object
+//   pointer.
+//
+//   base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
+//
+// PARTIAL BINDING OF PARAMETERS
+//
+//   You can specify some parameters when you create the callback, and specify
+//   the rest when you execute the callback.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+//   cb.Run("hello world");
+//
+//   When calling a function bound parameters are first, followed by unbound
+//   parameters.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for advanced binding
+// -----------------------------------------------------------------------------
+//
+// BINDING A CLASS METHOD WITH WEAK POINTERS
+//
+//   base::Bind(&MyClass::Foo, GetWeakPtr());
+//
+//   The callback will not be run if the object has already been destroyed.
+//   DANGER: weak pointers are not threadsafe, so don't use this
+//   when passing between threads!
+//
+// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
+//
+//   base::Bind(&MyClass::Foo, base::Unretained(this));
+//
+//   This disables all lifetime management on the object. You're responsible
+//   for making sure the object is alive at the time of the call. You break it,
+//   you own it!
+//
+// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
+//
+//   MyClass* myclass = new MyClass;
+//   base::Bind(&MyClass::Foo, base::Owned(myclass));
+//
+//   The object will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown). Potentially useful for
+//   "fire and forget" cases.
+//
+// IGNORING RETURN VALUES
+//
+//   Sometimes you want to call a function that returns a value in a callback
+//   that doesn't expect a return value.
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//   base::Callback<void<int>) cb =
+//       base::Bind(base::IgnoreResult(&DoSomething));
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for binding parameters to Bind()
+// -----------------------------------------------------------------------------
+//
+// Bound parameters are specified as arguments to Bind() and are passed to the
+// function. A callback with no parameters or no unbound parameters is called a
+// Closure (base::Callback<void(void)> and base::Closure are the same thing).
+//
+// PASSING PARAMETERS OWNED BY THE CALLBACK
+//
+//   void Foo(int* arg) { cout << *arg << endl; }
+//   int* pn = new int(1);
+//   base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
+//
+//   The parameter will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown).
+//
+// PASSING PARAMETERS AS A scoped_ptr
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {}
+//   scoped_ptr<Foo> f(new Foo);
+//   // f becomes null during the following call.
+//   base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
+//
+//   Ownership of the parameter will be with the callback until the it is run,
+//   when ownership is passed to the callback function. This means the callback
+//   can only be run once. If the callback is never run, it will delete the
+//   object when it's destroyed.
+//
+// PASSING PARAMETERS AS A scoped_refptr
+//
+//   void TakesOneRef(scoped_refptr<Foo> arg) {}
+//   scoped_refptr<Foo> f(new Foo)
+//   base::Closure cb = base::Bind(&TakesOneRef, f);
+//
+//   This should "just work." The closure will take a reference as long as it
+//   is alive, and another reference will be taken for the called function.
+//
+// PASSING PARAMETERS BY REFERENCE
+//
+//   Const references are *copied* unless ConstRef is used. Example:
+//
+//   void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
+//   int n = 1;
+//   base::Closure has_copy = base::Bind(&foo, n);
+//   base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
+//   n = 2;
+//   foo(n);                        // Prints "2 0xaaaaaaaaaaaa"
+//   has_copy.Run();                // Prints "1 0xbbbbbbbbbbbb"
+//   has_ref.Run();                 // Prints "2 0xaaaaaaaaaaaa"
+//
+//   Normally parameters are copied in the closure. DANGER: ConstRef stores a
+//   const reference instead, referencing the original parameter. This means
+//   that you must ensure the object outlives the callback!
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// WHERE IS THIS DESIGN FROM:
+//
+// The design Callback and Bind is heavily influenced by C++'s
+// tr1::function/tr1::bind, and by the "Google Callback" system used inside
+// Google.
+//
+//
+// HOW THE IMPLEMENTATION WORKS:
+//
+// There are three main components to the system:
+//   1) The Callback classes.
+//   2) The Bind() functions.
+//   3) The arguments wrappers (e.g., Unretained() and ConstRef()).
+//
+// The Callback classes represent a generic function pointer. Internally,
+// it stores a refcounted piece of state that represents the target function
+// and all its bound parameters.  Each Callback specialization has a templated
+// constructor that takes an BindState<>*.  In the context of the constructor,
+// the static type of this BindState<> pointer uniquely identifies the
+// function it is representing, all its bound parameters, and a Run() method
+// that is capable of invoking the target.
+//
+// Callback's constructor takes the BindState<>* that has the full static type
+// and erases the target function type as well as the types of the bound
+// parameters.  It does this by storing a pointer to the specific Run()
+// function, and upcasting the state of BindState<>* to a
+// BindStateBase*. This is safe as long as this BindStateBase pointer
+// is only used with the stored Run() pointer.
+//
+// To BindState<> objects are created inside the Bind() functions.
+// These functions, along with a set of internal templates, are responsible for
+//
+//  - Unwrapping the function signature into return type, and parameters
+//  - Determining the number of parameters that are bound
+//  - Creating the BindState storing the bound parameters
+//  - Performing compile-time asserts to avoid error-prone behavior
+//  - Returning an Callback<> with an arity matching the number of unbound
+//    parameters and that knows the correct refcounting semantics for the
+//    target object if we are binding a method.
+//
+// The Bind functions do the above using type-inference, and template
+// specializations.
+//
+// By default Bind() will store copies of all bound parameters, and attempt
+// to refcount a target object if the function being bound is a class method.
+// These copies are created even if the function takes parameters as const
+// references. (Binding to non-const references is forbidden, see bind.h.)
+//
+// To change this behavior, we introduce a set of argument wrappers
+// (e.g., Unretained(), and ConstRef()).  These are simple container templates
+// that are passed by value, and wrap a pointer to argument.  See the
+// file-level comment in base/bind_helpers.h for more info.
+//
+// These types are passed to the Unwrap() functions, and the MaybeRefcount()
+// functions respectively to modify the behavior of Bind().  The Unwrap()
+// and MaybeRefcount() functions change behavior by doing partial
+// specialization based on whether or not a parameter is a wrapper type.
+//
+// ConstRef() is similar to tr1::cref.  Unretained() is specific to Chromium.
+//
+//
+// WHY NOT TR1 FUNCTION/BIND?
+//
+// Direct use of tr1::function and tr1::bind was considered, but ultimately
+// rejected because of the number of copy constructors invocations involved
+// in the binding of arguments during construction, and the forwarding of
+// arguments during invocation.  These copies will no longer be an issue in
+// C++0x because C++0x will support rvalue reference allowing for the compiler
+// to avoid these copies.  However, waiting for C++0x is not an option.
+//
+// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
+// tr1::bind call itself will invoke a non-trivial copy constructor three times
+// for each bound parameter.  Also, each when passing a tr1::function, each
+// bound argument will be copied again.
+//
+// In addition to the copies taken at binding and invocation, copying a
+// tr1::function causes a copy to be made of all the bound parameters and
+// state.
+//
+// Furthermore, in Chromium, it is desirable for the Callback to take a
+// reference on a target object when representing a class method call.  This
+// is not supported by tr1.
+//
+// Lastly, tr1::function and tr1::bind has a more general and flexible API.
+// This includes things like argument reordering by use of
+// tr1::bind::placeholder, support for non-const reference parameters, and some
+// limited amount of subtyping of the tr1::function object (e.g.,
+// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
+//
+// These are not features that are required in Chromium. Some of them, such as
+// allowing for reference parameters, and subtyping of functions, may actually
+// become a source of errors. Removing support for these features actually
+// allows for a simpler implementation, and a terser Currying API.
+//
+//
+// WHY NOT GOOGLE CALLBACKS?
+//
+// The Google callback system also does not support refcounting.  Furthermore,
+// its implementation has a number of strange edge cases with respect to type
+// conversion of its arguments.  In particular, the argument's constness must
+// at times match exactly the function signature, or the type-inference might
+// break.  Given the above, writing a custom solution was easier.
+//
+//
+// MISSING FUNCTIONALITY
+//  - Invoking the return of Bind.  Bind(&foo).Run() does not work;
+//  - Binding arrays to functions that take a non-const pointer.
+//    Example:
+//      void Foo(const char* ptr);
+//      void Bar(char* ptr);
+//      Bind(&Foo, "test");
+//      Bind(&Bar, "test");  // This fails because ptr is not const.
+
+namespace base {
+
+// First, we forward declare the Callback class template. This informs the
+// compiler that the template only has 1 type parameter which is the function
+// signature that the Callback is representing.
+//
+// After this, create template specializations for 0-7 parameters. Note that
+// even though the template typelist grows, the specialization still
+// only has one type: the function signature.
+//
+// If you are thinking of forward declaring Callback in your own header file,
+// please include "base/callback_forward.h" instead.
+template <typename Sig>
+class Callback;
+
+namespace internal {
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+}  // namespace internal
+
+template <typename R, typename... Args>
+class Callback<R(Args...)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(Args...);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
+      const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(args)...);
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+      typename internal::CallbackParamTraits<Args>::ForwardType...);
+};
+
+// Syntactic sugar to make Callback<void(void)> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_H_
diff --git a/base/callback_forward.h b/base/callback_forward.h
new file mode 100644
index 0000000..262c306
--- /dev/null
+++ b/base/callback_forward.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_FORWARD_H_
+#define BASE_CALLBACK_FORWARD_H_
+
+namespace base {
+
+template <typename Sig>
+class Callback;
+
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_FORWARD_H_
diff --git a/base/callback_helpers.cc b/base/callback_helpers.cc
new file mode 100644
index 0000000..ef02b2b
--- /dev/null
+++ b/base/callback_helpers.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_helpers.h"
+
+#include "base/callback.h"
+
+namespace base {
+
+ScopedClosureRunner::ScopedClosureRunner() {
+}
+
+ScopedClosureRunner::ScopedClosureRunner(const Closure& closure)
+    : closure_(closure) {
+}
+
+ScopedClosureRunner::~ScopedClosureRunner() {
+  if (!closure_.is_null())
+    closure_.Run();
+}
+
+void ScopedClosureRunner::Reset() {
+  Closure old_closure = Release();
+  if (!old_closure.is_null())
+    old_closure.Run();
+}
+
+void ScopedClosureRunner::Reset(const Closure& closure) {
+  Closure old_closure = Release();
+  closure_ = closure;
+  if (!old_closure.is_null())
+    old_closure.Run();
+}
+
+Closure ScopedClosureRunner::Release() {
+  Closure result = closure_;
+  closure_.Reset();
+  return result;
+}
+
+}  // namespace base
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
new file mode 100644
index 0000000..8481e3e
--- /dev/null
+++ b/base/callback_helpers.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This defines helpful methods for dealing with Callbacks.  Because Callbacks
+// are implemented using templates, with a class per callback signature, adding
+// methods to Callback<> itself is unattractive (lots of extra code gets
+// generated).  Instead, consider adding methods here.
+//
+// ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a
+// copy) after the original callback is Reset().  This can be handy if Run()
+// reads/writes the variable holding the Callback.
+
+#ifndef BASE_CALLBACK_HELPERS_H_
+#define BASE_CALLBACK_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+template <typename Sig>
+base::Callback<Sig> ResetAndReturn(base::Callback<Sig>* cb) {
+  base::Callback<Sig> ret(*cb);
+  cb->Reset();
+  return ret;
+}
+
+// ScopedClosureRunner is akin to scoped_ptr for Closures. It ensures that the
+// Closure is executed and deleted no matter how the current scope exits.
+class BASE_EXPORT ScopedClosureRunner {
+ public:
+  ScopedClosureRunner();
+  explicit ScopedClosureRunner(const Closure& closure);
+  ~ScopedClosureRunner();
+
+  void Reset();
+  void Reset(const Closure& closure);
+  Closure Release() WARN_UNUSED_RESULT;
+
+ private:
+  Closure closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_HELPERS_H_
diff --git a/base/callback_helpers_unittest.cc b/base/callback_helpers_unittest.cc
new file mode 100644
index 0000000..3b17a6b
--- /dev/null
+++ b/base/callback_helpers_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_helpers.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void Increment(int* value) {
+  (*value)++;
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerRelease) {
+  int run_count = 0;
+  base::Closure c;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    c = runner.Release();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(0, run_count);
+  c.Run();
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerReset) {
+  int run_count_1 = 0;
+  int run_count_2 = 0;
+  {
+    base::ScopedClosureRunner runner;
+    runner.Reset(base::Bind(&Increment, &run_count_1));
+    runner.Reset(base::Bind(&Increment, &run_count_2));
+    EXPECT_EQ(1, run_count_1);
+    EXPECT_EQ(0, run_count_2);
+  }
+  EXPECT_EQ(1, run_count_2);
+
+  int run_count_3 = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_3));
+    EXPECT_EQ(0, run_count_3);
+    runner.Reset();
+    EXPECT_EQ(1, run_count_3);
+  }
+  EXPECT_EQ(1, run_count_3);
+}
+
+}  // namespace
diff --git a/base/callback_internal.cc b/base/callback_internal.cc
new file mode 100644
index 0000000..f360388
--- /dev/null
+++ b/base/callback_internal.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/callback_internal.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+CallbackBase::CallbackBase(const CallbackBase& c) = default;
+CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
+
+void CallbackBase::Reset() {
+  polymorphic_invoke_ = NULL;
+  // NULL the bind_state_ last, since it may be holding the last ref to whatever
+  // object owns us, and we may be deleted after that.
+  bind_state_ = NULL;
+}
+
+bool CallbackBase::Equals(const CallbackBase& other) const {
+  return bind_state_.get() == other.bind_state_.get() &&
+         polymorphic_invoke_ == other.polymorphic_invoke_;
+}
+
+CallbackBase::CallbackBase(BindStateBase* bind_state)
+    : bind_state_(bind_state),
+      polymorphic_invoke_(NULL) {
+  DCHECK(!bind_state_.get() || bind_state_->HasOneRef());
+}
+
+CallbackBase::~CallbackBase() {
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/callback_internal.h b/base/callback_internal.h
new file mode 100644
index 0000000..8a5c437
--- /dev/null
+++ b/base/callback_internal.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// 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:
+  CallbackBase(const CallbackBase& c);
+  CallbackBase& operator=(const CallbackBase& c);
+
+  // Returns true if Callback is null (doesn't refer to anything).
+  bool is_null() const { return bind_state_.get() == NULL; }
+
+  // Returns the Callback into an uninitialized state.
+  void Reset();
+
+ protected:
+  // In C++, it is safe to cast function pointers to function pointers of
+  // another type. It is not okay to use void*. We create a InvokeFuncStorage
+  // that that can store our function pointer, and then cast it back to
+  // the original type on usage.
+  typedef void(*InvokeFuncStorage)(void);
+
+  // Returns true if this callback equals |other|. |other| may be null.
+  bool Equals(const CallbackBase& other) const;
+
+  // Allow initializing of |bind_state_| via the constructor to avoid default
+  // initialization of the scoped_refptr.  We do not also initialize
+  // |polymorphic_invoke_| here because doing a normal assignment in the
+  // derived Callback templates makes for much nicer compiler errors.
+  explicit CallbackBase(BindStateBase* bind_state);
+
+  // Force the destructor to be instantiated inside this translation unit so
+  // that our subclasses will not get inlined versions.  Avoids more template
+  // bloat.
+  ~CallbackBase();
+
+  scoped_refptr<BindStateBase> bind_state_;
+  InvokeFuncStorage polymorphic_invoke_;
+};
+
+// A helper template to determine if given type is non-const move-only-type,
+// i.e. if a value of the given type should be passed via .Pass() in a
+// destructive way.
+template <typename T> struct IsMoveOnlyType {
+  template <typename U>
+  static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
+
+  template <typename U>
+  static NoType Test(...);
+
+  static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) &&
+                            !is_const<T>::value;
+};
+
+// Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns
+// |Else|.
+template <bool condition, typename Then, typename Else>
+struct SelectType {
+  typedef Then Type;
+};
+
+template <typename Then, typename Else>
+struct SelectType<false, Then, Else> {
+  typedef Else Type;
+};
+
+template <typename>
+struct CallbackParamTraitsForMoveOnlyType;
+
+template <typename>
+struct CallbackParamTraitsForNonMoveOnlyType;
+
+// TODO(tzik): Use a default parameter once MSVS supports variadic templates
+// with default values.
+// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
+//
+// This is a typetraits object that's used to take an argument type, and
+// extract a suitable type for storing and forwarding arguments.
+//
+// In particular, it strips off references, and converts arrays to
+// pointers for storage; and it avoids accidentally trying to create a
+// "reference of a reference" if the argument is a reference type.
+//
+// This array type becomes an issue for storage because we are passing bound
+// parameters by const reference. In this case, we end up passing an actual
+// array type in the initializer list which C++ does not allow.  This will
+// break passing of C-string literals.
+template <typename T>
+struct CallbackParamTraits
+    : SelectType<IsMoveOnlyType<T>::value,
+         CallbackParamTraitsForMoveOnlyType<T>,
+         CallbackParamTraitsForNonMoveOnlyType<T> >::Type {
+};
+
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType {
+  typedef const T& ForwardType;
+  typedef T StorageType;
+};
+
+// The Storage should almost be impossible to trigger unless someone manually
+// specifies type of the bind parameters.  However, in case they do,
+// this will guard against us accidentally storing a reference parameter.
+//
+// The ForwardType should only be used for unbound arguments.
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType<T&> {
+  typedef T& ForwardType;
+  typedef T StorageType;
+};
+
+// Note that for array types, we implicitly add a const in the conversion. This
+// means that it is not possible to bind array arguments to functions that take
+// a non-const pointer. Trying to specialize the template based on a "const
+// T[n]" does not seem to match correctly, so we are stuck with this
+// restriction.
+template <typename T, size_t n>
+struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
+  typedef const T* ForwardType;
+  typedef const T* StorageType;
+};
+
+// See comment for CallbackParamTraits<T[n]>.
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
+  typedef const T* ForwardType;
+  typedef const T* StorageType;
+};
+
+// Parameter traits for movable-but-not-copyable scopers.
+//
+// Callback<>/Bind() understands movable-but-not-copyable semantics where
+// the type cannot be copied but can still have its state destructively
+// transferred (aka. moved) to another instance of the same type by calling a
+// helper function.  When used with Bind(), this signifies transferal of the
+// object's state to the target function.
+//
+// For these types, the ForwardType must not be a const reference, or a
+// reference.  A const reference is inappropriate, and would break const
+// correctness, because we are implementing a destructive move.  A non-const
+// reference cannot be used with temporaries which means the result of a
+// function or a cast would not be usable with Callback<> or Bind().
+template <typename T>
+struct CallbackParamTraitsForMoveOnlyType {
+  typedef T ForwardType;
+  typedef T StorageType;
+};
+
+// CallbackForward() is a very limited simulation of C++11's std::forward()
+// used by the Callback/Bind system for a set of movable-but-not-copyable
+// types.  It is needed because forwarding a movable-but-not-copyable
+// argument to another function requires us to invoke the proper move
+// operator to create a rvalue version of the type.  The supported types are
+// whitelisted below as overloads of the CallbackForward() function. The
+// default template compiles out to be a no-op.
+//
+// In C++11, std::forward would replace all uses of this function.  However, it
+// is impossible to implement a general std::forward with C++11 due to a lack
+// of rvalue references.
+//
+// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
+// simulate std::forward() and forward the result of one Callback as a
+// parameter to another callback. This is to support Callbacks that return
+// the movable-but-not-copyable types whitelisted above.
+template <typename T>
+typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
+  return t;
+}
+
+template <typename T>
+typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
+  return t.Pass();
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_CALLBACK_INTERNAL_H_
diff --git a/base/callback_list.h b/base/callback_list.h
new file mode 100644
index 0000000..aeed5f1
--- /dev/null
+++ b/base/callback_list.h
@@ -0,0 +1,230 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_LIST_H_
+#define BASE_CALLBACK_LIST_H_
+
+#include <list>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/callback_internal.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+// OVERVIEW:
+//
+// A container for a list of callbacks.  Unlike a normal STL vector or list,
+// this container can be modified during iteration without invalidating the
+// iterator. It safely handles the case of a callback removing itself
+// or another callback from the list while callbacks are being run.
+//
+// TYPICAL USAGE:
+//
+// class MyWidget {
+//  public:
+//   ...
+//
+//   typedef base::Callback<void(const Foo&)> OnFooCallback;
+//
+//   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
+//   RegisterCallback(const OnFooCallback& cb) {
+//     return callback_list_.Add(cb);
+//   }
+//
+//  private:
+//   void NotifyFoo(const Foo& foo) {
+//      callback_list_.Notify(foo);
+//   }
+//
+//   base::CallbackList<void(const Foo&)> callback_list_;
+//
+//   DISALLOW_COPY_AND_ASSIGN(MyWidget);
+// };
+//
+//
+// class MyWidgetListener {
+//  public:
+//   MyWidgetListener::MyWidgetListener() {
+//     foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
+//             base::Bind(&MyWidgetListener::OnFoo, this)));
+//   }
+//
+//   MyWidgetListener::~MyWidgetListener() {
+//      // Subscription gets deleted automatically and will deregister
+//      // the callback in the process.
+//   }
+//
+//  private:
+//   void OnFoo(const Foo& foo) {
+//     // Do something.
+//   }
+//
+//   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
+//       foo_subscription_;
+//
+//   DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
+// };
+
+namespace base {
+
+namespace internal {
+
+template <typename CallbackType>
+class CallbackListBase {
+ public:
+  class Subscription {
+   public:
+    Subscription(CallbackListBase<CallbackType>* list,
+                 typename std::list<CallbackType>::iterator iter)
+        : list_(list),
+          iter_(iter) {
+    }
+
+    ~Subscription() {
+      if (list_->active_iterator_count_) {
+        iter_->Reset();
+      } else {
+        list_->callbacks_.erase(iter_);
+        if (!list_->removal_callback_.is_null())
+          list_->removal_callback_.Run();
+      }
+    }
+
+   private:
+    CallbackListBase<CallbackType>* list_;
+    typename std::list<CallbackType>::iterator iter_;
+
+    DISALLOW_COPY_AND_ASSIGN(Subscription);
+  };
+
+  // Add a callback to the list. The callback will remain registered until the
+  // returned Subscription is destroyed, which must occur before the
+  // CallbackList is destroyed.
+  scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
+    DCHECK(!cb.is_null());
+    return scoped_ptr<Subscription>(
+        new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
+  }
+
+  // Sets a callback which will be run when a subscription list is changed.
+  void set_removal_callback(const Closure& callback) {
+    removal_callback_ = callback;
+  }
+
+  // Returns true if there are no subscriptions. This is only valid to call when
+  // not looping through the list.
+  bool empty() {
+    DCHECK_EQ(0, active_iterator_count_);
+    return callbacks_.empty();
+  }
+
+ protected:
+  // An iterator class that can be used to access the list of callbacks.
+  class Iterator {
+   public:
+    explicit Iterator(CallbackListBase<CallbackType>* list)
+        : list_(list),
+          list_iter_(list_->callbacks_.begin()) {
+      ++list_->active_iterator_count_;
+    }
+
+    Iterator(const Iterator& iter)
+        : list_(iter.list_),
+          list_iter_(iter.list_iter_) {
+      ++list_->active_iterator_count_;
+    }
+
+    ~Iterator() {
+      if (list_ && --list_->active_iterator_count_ == 0) {
+        list_->Compact();
+      }
+    }
+
+    CallbackType* GetNext() {
+      while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
+        ++list_iter_;
+
+      CallbackType* cb = NULL;
+      if (list_iter_ != list_->callbacks_.end()) {
+        cb = &(*list_iter_);
+        ++list_iter_;
+      }
+      return cb;
+    }
+
+   private:
+    CallbackListBase<CallbackType>* list_;
+    typename std::list<CallbackType>::iterator list_iter_;
+  };
+
+  CallbackListBase() : active_iterator_count_(0) {}
+
+  ~CallbackListBase() {
+    DCHECK_EQ(0, active_iterator_count_);
+    DCHECK_EQ(0U, callbacks_.size());
+  }
+
+  // Returns an instance of a CallbackListBase::Iterator which can be used
+  // to run callbacks.
+  Iterator GetIterator() {
+    return Iterator(this);
+  }
+
+  // Compact the list: remove any entries which were NULLed out during
+  // iteration.
+  void Compact() {
+    typename std::list<CallbackType>::iterator it = callbacks_.begin();
+    bool updated = false;
+    while (it != callbacks_.end()) {
+      if ((*it).is_null()) {
+        updated = true;
+        it = callbacks_.erase(it);
+      } else {
+        ++it;
+      }
+
+      if (updated && !removal_callback_.is_null())
+        removal_callback_.Run();
+    }
+  }
+
+ private:
+  std::list<CallbackType> callbacks_;
+  int active_iterator_count_;
+  Closure removal_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
+};
+
+}  // namespace internal
+
+template <typename Sig> class CallbackList;
+
+template <typename... Args>
+class CallbackList<void(Args...)>
+    : public internal::CallbackListBase<Callback<void(Args...)> > {
+ public:
+  typedef Callback<void(Args...)> CallbackType;
+
+  CallbackList() {}
+
+  void Notify(
+      typename internal::CallbackParamTraits<Args>::ForwardType... args) {
+    typename internal::CallbackListBase<CallbackType>::Iterator it =
+        this->GetIterator();
+    CallbackType* cb;
+    while ((cb = it.GetNext()) != NULL) {
+      cb->Run(args...);
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CallbackList);
+};
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_LIST_H_
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc
new file mode 100644
index 0000000..9adbabb
--- /dev/null
+++ b/base/callback_list_unittest.cc
@@ -0,0 +1,291 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_list.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Listener {
+ public:
+  Listener() : total_(0), scaler_(1) {}
+  explicit Listener(int scaler) : total_(0), scaler_(scaler) {}
+  void IncrementTotal() { total_++; }
+  void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; }
+
+  int total() const { return total_; }
+
+ private:
+  int total_;
+  int scaler_;
+  DISALLOW_COPY_AND_ASSIGN(Listener);
+};
+
+class Remover {
+ public:
+  Remover() : total_(0) {}
+  void IncrementTotalAndRemove() {
+    total_++;
+    removal_subscription_.reset();
+  }
+  void SetSubscriptionToRemove(
+      scoped_ptr<CallbackList<void(void)>::Subscription> sub) {
+    removal_subscription_ = sub.Pass();
+  }
+
+  int total() const { return total_; }
+
+ private:
+  int total_;
+  scoped_ptr<CallbackList<void(void)>::Subscription> removal_subscription_;
+  DISALLOW_COPY_AND_ASSIGN(Remover);
+};
+
+class Adder {
+ public:
+  explicit Adder(CallbackList<void(void)>* cb_reg)
+      : added_(false),
+        total_(0),
+        cb_reg_(cb_reg) {
+  }
+  void AddCallback() {
+    if (!added_) {
+      added_ = true;
+      subscription_ =
+          cb_reg_->Add(Bind(&Adder::IncrementTotal, Unretained(this)));
+    }
+  }
+  void IncrementTotal() { total_++; }
+
+  bool added() const { return added_; }
+
+  int total() const { return total_; }
+
+ private:
+  bool added_;
+  int total_;
+  CallbackList<void(void)>* cb_reg_;
+  scoped_ptr<CallbackList<void(void)>::Subscription> subscription_;
+  DISALLOW_COPY_AND_ASSIGN(Adder);
+};
+
+class Summer {
+ public:
+  Summer() : value_(0) {}
+
+  void AddOneParam(int a) { value_ = a; }
+  void AddTwoParam(int a, int b) { value_ = a + b; }
+  void AddThreeParam(int a, int b, int c) { value_ = a + b + c; }
+  void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; }
+  void AddFiveParam(int a, int b, int c, int d, int e) {
+    value_ = a + b + c + d + e;
+  }
+  void AddSixParam(int a, int b, int c, int d, int e , int f) {
+    value_ = a + b + c + d + e + f;
+  }
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  DISALLOW_COPY_AND_ASSIGN(Summer);
+};
+
+// Sanity check that we can instantiate a CallbackList for each arity.
+TEST(CallbackListTest, ArityTest) {
+  Summer s;
+
+  CallbackList<void(int)> c1;
+  scoped_ptr<CallbackList<void(int)>::Subscription> subscription1 =
+      c1.Add(Bind(&Summer::AddOneParam, Unretained(&s)));
+
+  c1.Notify(1);
+  EXPECT_EQ(1, s.value());
+
+  CallbackList<void(int, int)> c2;
+  scoped_ptr<CallbackList<void(int, int)>::Subscription> subscription2 =
+      c2.Add(Bind(&Summer::AddTwoParam, Unretained(&s)));
+
+  c2.Notify(1, 2);
+  EXPECT_EQ(3, s.value());
+
+  CallbackList<void(int, int, int)> c3;
+  scoped_ptr<CallbackList<void(int, int, int)>::Subscription>
+      subscription3 = c3.Add(Bind(&Summer::AddThreeParam, Unretained(&s)));
+
+  c3.Notify(1, 2, 3);
+  EXPECT_EQ(6, s.value());
+
+  CallbackList<void(int, int, int, int)> c4;
+  scoped_ptr<CallbackList<void(int, int, int, int)>::Subscription>
+      subscription4 = c4.Add(Bind(&Summer::AddFourParam, Unretained(&s)));
+
+  c4.Notify(1, 2, 3, 4);
+  EXPECT_EQ(10, s.value());
+
+  CallbackList<void(int, int, int, int, int)> c5;
+  scoped_ptr<CallbackList<void(int, int, int, int, int)>::Subscription>
+      subscription5 = c5.Add(Bind(&Summer::AddFiveParam, Unretained(&s)));
+
+  c5.Notify(1, 2, 3, 4, 5);
+  EXPECT_EQ(15, s.value());
+
+  CallbackList<void(int, int, int, int, int, int)> c6;
+  scoped_ptr<CallbackList<void(int, int, int, int, int, int)>::Subscription>
+      subscription6 = c6.Add(Bind(&Summer::AddSixParam, Unretained(&s)));
+
+  c6.Notify(1, 2, 3, 4, 5, 6);
+  EXPECT_EQ(21, s.value());
+}
+
+// Sanity check that closures added to the list will be run, and those removed
+// from the list will not be run.
+TEST(CallbackListTest, BasicTest) {
+  CallbackList<void(void)> cb_reg;
+  Listener a, b, c;
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  EXPECT_TRUE(a_subscription.get());
+  EXPECT_TRUE(b_subscription.get());
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(1, a.total());
+  EXPECT_EQ(1, b.total());
+
+  b_subscription.reset();
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> c_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&c)));
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(2, a.total());
+  EXPECT_EQ(1, b.total());
+  EXPECT_EQ(1, c.total());
+
+  a_subscription.reset();
+  b_subscription.reset();
+  c_subscription.reset();
+}
+
+// Sanity check that callbacks with details added to the list will be run, with
+// the correct details, and those removed from the list will not be run.
+TEST(CallbackListTest, BasicTestWithParams) {
+  CallbackList<void(int)> cb_reg;
+  Listener a(1), b(-1), c(1);
+
+  scoped_ptr<CallbackList<void(int)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
+  scoped_ptr<CallbackList<void(int)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
+
+  EXPECT_TRUE(a_subscription.get());
+  EXPECT_TRUE(b_subscription.get());
+
+  cb_reg.Notify(10);
+
+  EXPECT_EQ(10, a.total());
+  EXPECT_EQ(-10, b.total());
+
+  b_subscription.reset();
+
+  scoped_ptr<CallbackList<void(int)>::Subscription> c_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
+
+  cb_reg.Notify(10);
+
+  EXPECT_EQ(20, a.total());
+  EXPECT_EQ(-10, b.total());
+  EXPECT_EQ(10, c.total());
+
+  a_subscription.reset();
+  b_subscription.reset();
+  c_subscription.reset();
+}
+
+// Test the a callback can remove itself or a different callback from the list
+// during iteration without invalidating the iterator.
+TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
+  CallbackList<void(void)> cb_reg;
+  Listener a, b;
+  Remover remover_1, remover_2;
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
+      cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+          Unretained(&remover_1)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
+      cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+          Unretained(&remover_2)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  // |remover_1| will remove itself.
+  remover_1.SetSubscriptionToRemove(remover_1_sub.Pass());
+  // |remover_2| will remove a.
+  remover_2.SetSubscriptionToRemove(a_subscription.Pass());
+
+  cb_reg.Notify();
+
+  // |remover_1| runs once (and removes itself), |remover_2| runs once (and
+  // removes a), |a| never runs, and |b| runs once.
+  EXPECT_EQ(1, remover_1.total());
+  EXPECT_EQ(1, remover_2.total());
+  EXPECT_EQ(0, a.total());
+  EXPECT_EQ(1, b.total());
+
+  cb_reg.Notify();
+
+  // Only |remover_2| and |b| run this time.
+  EXPECT_EQ(1, remover_1.total());
+  EXPECT_EQ(2, remover_2.total());
+  EXPECT_EQ(0, a.total());
+  EXPECT_EQ(2, b.total());
+}
+
+// Test that a callback can add another callback to the list durning iteration
+// without invalidating the iterator. The newly added callback should be run on
+// the current iteration as will all other callbacks in the list.
+TEST(CallbackListTest, AddCallbacksDuringIteration) {
+  CallbackList<void(void)> cb_reg;
+  Adder a(&cb_reg);
+  Listener b;
+  scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Adder::AddCallback, Unretained(&a)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(1, a.total());
+  EXPECT_EQ(1, b.total());
+  EXPECT_TRUE(a.added());
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(2, a.total());
+  EXPECT_EQ(2, b.total());
+}
+
+// Sanity check: notifying an empty list is a no-op.
+TEST(CallbackListTest, EmptyList) {
+  CallbackList<void(void)> cb_reg;
+
+  cb_reg.Notify();
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/callback_list_unittest.nc b/base/callback_list_unittest.nc
new file mode 100644
index 0000000..2d464cf
--- /dev/null
+++ b/base/callback_list_unittest.nc
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_list.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class Foo {
+ public:
+  Foo() {}
+  ~Foo() {}
+};
+
+class FooListener {
+ public:
+  FooListener() {}
+
+  void GotAScopedFoo(scoped_ptr<Foo> f) { foo_ = f.Pass(); }
+
+  scoped_ptr<Foo> foo_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FooListener);
+};
+
+
+#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER)  // [r"calling a private constructor of class"]
+
+// Callbacks run with a move-only typed parameter.
+//
+// CallbackList does not support move-only typed parameters. Notify() is
+// designed to take zero or more parameters, and run each registered callback
+// with them. With move-only types, the parameter will be set to NULL after the
+// first callback has been run.
+void WontCompile() {
+  FooListener f;
+  CallbackList<void(scoped_ptr<Foo>)> c1;
+  scoped_ptr<CallbackList<void(scoped_ptr<Foo>)>::Subscription> sub =
+      c1.Add(Bind(&FooListener::GotAScopedFoo, Unretained(&f)));
+  c1.Notify(scoped_ptr<Foo>(new Foo()));
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc
new file mode 100644
index 0000000..5644b85
--- /dev/null
+++ b/base/callback_unittest.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/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;
+ private:
+  ~BindState() override {}
+};
+
+template <>
+struct BindState<void(void), void(void),
+                           void(FakeInvoker, FakeInvoker)>
+    : public BindStateBase {
+ public:
+  typedef FakeInvoker InvokerType;
+ private:
+  ~BindState() override {}
+};
+}  // namespace internal
+
+namespace {
+
+typedef internal::BindState<void(void), void(void), void(FakeInvoker)>
+    FakeBindState1;
+typedef internal::BindState<void(void), void(void),
+                            void(FakeInvoker, FakeInvoker)>
+   FakeBindState2;
+
+class CallbackTest : public ::testing::Test {
+ public:
+  CallbackTest()
+      : callback_a_(new FakeBindState1()),
+        callback_b_(new FakeBindState2()) {
+  }
+
+  ~CallbackTest() override {}
+
+ protected:
+  Callback<void(void)> callback_a_;
+  const Callback<void(void)> callback_b_;  // Ensure APIs work with const.
+  Callback<void(void)> null_callback_;
+};
+
+// Ensure we can create unbound callbacks. We need this to be able to store
+// them in class members that can be initialized later.
+TEST_F(CallbackTest, DefaultConstruction) {
+  Callback<void(void)> c0;
+  Callback<void(int)> c1;
+  Callback<void(int,int)> c2;
+  Callback<void(int,int,int)> c3;
+  Callback<void(int,int,int,int)> c4;
+  Callback<void(int,int,int,int,int)> c5;
+  Callback<void(int,int,int,int,int,int)> c6;
+
+  EXPECT_TRUE(c0.is_null());
+  EXPECT_TRUE(c1.is_null());
+  EXPECT_TRUE(c2.is_null());
+  EXPECT_TRUE(c3.is_null());
+  EXPECT_TRUE(c4.is_null());
+  EXPECT_TRUE(c5.is_null());
+  EXPECT_TRUE(c6.is_null());
+}
+
+TEST_F(CallbackTest, IsNull) {
+  EXPECT_TRUE(null_callback_.is_null());
+  EXPECT_FALSE(callback_a_.is_null());
+  EXPECT_FALSE(callback_b_.is_null());
+}
+
+TEST_F(CallbackTest, Equals) {
+  EXPECT_TRUE(callback_a_.Equals(callback_a_));
+  EXPECT_FALSE(callback_a_.Equals(callback_b_));
+  EXPECT_FALSE(callback_b_.Equals(callback_a_));
+
+  // We should compare based on instance, not type.
+  Callback<void(void)> callback_c(new FakeBindState1());
+  Callback<void(void)> callback_a2 = callback_a_;
+  EXPECT_TRUE(callback_a_.Equals(callback_a2));
+  EXPECT_FALSE(callback_a_.Equals(callback_c));
+
+  // Empty, however, is always equal to empty.
+  Callback<void(void)> empty2;
+  EXPECT_TRUE(null_callback_.Equals(empty2));
+}
+
+TEST_F(CallbackTest, Reset) {
+  // Resetting should bring us back to empty.
+  ASSERT_FALSE(callback_a_.is_null());
+  ASSERT_FALSE(callback_a_.Equals(null_callback_));
+
+  callback_a_.Reset();
+
+  EXPECT_TRUE(callback_a_.is_null());
+  EXPECT_TRUE(callback_a_.Equals(null_callback_));
+}
+
+struct TestForReentrancy {
+  TestForReentrancy()
+      : cb_already_run(false),
+        cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) {
+  }
+  void AssertCBIsNull() {
+    ASSERT_TRUE(cb.is_null());
+    cb_already_run = true;
+  }
+  bool cb_already_run;
+  Closure cb;
+};
+
+TEST_F(CallbackTest, ResetAndReturn) {
+  TestForReentrancy tfr;
+  ASSERT_FALSE(tfr.cb.is_null());
+  ASSERT_FALSE(tfr.cb_already_run);
+  ResetAndReturn(&tfr.cb).Run();
+  ASSERT_TRUE(tfr.cb.is_null());
+  ASSERT_TRUE(tfr.cb_already_run);
+}
+
+class CallbackOwner : public base::RefCounted<CallbackOwner> {
+ public:
+  explicit CallbackOwner(bool* deleted) {
+    callback_ = Bind(&CallbackOwner::Unused, this);
+    deleted_ = deleted;
+  }
+  void Reset() {
+    callback_.Reset();
+    // We are deleted here if no-one else had a ref to us.
+  }
+
+ private:
+  friend class base::RefCounted<CallbackOwner>;
+  virtual ~CallbackOwner() {
+    *deleted_ = true;
+  }
+  void Unused() {
+    FAIL() << "Should never be called";
+  }
+
+  Closure callback_;
+  bool* deleted_;
+};
+
+TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) {
+  bool deleted = false;
+  CallbackOwner* owner = new CallbackOwner(&deleted);
+  owner->Reset();
+  ASSERT_TRUE(deleted);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc
new file mode 100644
index 0000000..e7607d9
--- /dev/null
+++ b/base/callback_unittest.nc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+
+namespace base {
+
+class Parent {
+};
+
+class Child : Parent {
+};
+
+#if defined(NCTEST_EQUALS_REQUIRES_SAMETYPE)  // [r"fatal error: no viable conversion from 'Callback<int \(\)>' to 'const Callback<void \(\)>'"]
+
+// Attempting to call comparison function on two callbacks of different type.
+//
+// This should be a compile time failure because each callback type should be
+// considered distinct.
+void WontCompile() {
+  Closure c1;
+  Callback<int(void)> c2;
+  c1.Equals(c2);
+}
+
+#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE)  // [r"fatal error: no viable conversion from 'Callback<base::Parent \(\)>' to 'Callback<base::Child \(\)>'"]
+
+// Construction of Callback<A> from Callback<B> if A is supertype of B.
+//
+// While this is technically safe, most people aren't used to it when coding
+// C++ so if this is happening, it is almost certainly an error.
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b = cb_a;
+}
+
+#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE)  // [r"fatal error: no viable overloaded '='"]
+
+// Assignment of Callback<A> from Callback<B> if A is supertype of B.
+// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b;
+  cb_a = cb_b;
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
new file mode 100644
index 0000000..2b9d260
--- /dev/null
+++ b/base/cancelable_callback.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// CancelableCallback is a wrapper around base::Callback that allows
+// cancellation of a callback. CancelableCallback takes a reference on the
+// wrapped callback until this object is destroyed or Reset()/Cancel() are
+// called.
+//
+// NOTE:
+//
+// Calling CancelableCallback::Cancel() brings the object back to its natural,
+// default-constructed state, i.e., CancelableCallback::callback() will return
+// a null callback.
+//
+// THREAD-SAFETY:
+//
+// CancelableCallback objects must be created on, posted to, cancelled on, and
+// destroyed on the same thread.
+//
+//
+// EXAMPLE USAGE:
+//
+// In the following example, the test is verifying that RunIntensiveTest()
+// Quit()s the message loop within 4 seconds. The cancelable callback is posted
+// to the message loop, the intensive test runs, the message loop is run,
+// then the callback is cancelled.
+//
+// void TimeoutCallback(const std::string& timeout_message) {
+//   FAIL() << timeout_message;
+//   MessageLoop::current()->QuitWhenIdle();
+// }
+//
+// CancelableClosure timeout(base::Bind(&TimeoutCallback, "Test timed out."));
+// MessageLoop::current()->PostDelayedTask(FROM_HERE, timeout.callback(),
+//                                         4000)  // 4 seconds to run.
+// RunIntensiveTest();
+// MessageLoop::current()->Run();
+// timeout.Cancel();  // Hopefully this is hit before the timeout callback runs.
+//
+
+#ifndef BASE_CANCELABLE_CALLBACK_H_
+#define BASE_CANCELABLE_CALLBACK_H_
+
+#include "base/base_export.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_internal.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+
+template <typename Sig>
+class CancelableCallback;
+
+template <typename... A>
+class CancelableCallback<void(A...)> {
+ public:
+  CancelableCallback() : weak_factory_(this) {}
+
+  // |callback| must not be null.
+  explicit CancelableCallback(const base::Callback<void(A...)>& callback)
+      : callback_(callback), weak_factory_(this) {
+    DCHECK(!callback.is_null());
+    InitializeForwarder();
+  }
+
+  ~CancelableCallback() {}
+
+  // Cancels and drops the reference to the wrapped callback.
+  void Cancel() {
+    weak_factory_.InvalidateWeakPtrs();
+    forwarder_.Reset();
+    callback_.Reset();
+  }
+
+  // Returns true if the wrapped callback has been cancelled.
+  bool IsCancelled() const {
+    return callback_.is_null();
+  }
+
+  // Sets |callback| as the closure that may be cancelled. |callback| may not
+  // be null. Outstanding and any previously wrapped callbacks are cancelled.
+  void Reset(const base::Callback<void(A...)>& callback) {
+    DCHECK(!callback.is_null());
+
+    // Outstanding tasks (e.g., posted to a message loop) must not be called.
+    Cancel();
+
+    // |forwarder_| is no longer valid after Cancel(), so re-bind.
+    InitializeForwarder();
+
+    callback_ = callback;
+  }
+
+  // Returns a callback that can be disabled by calling Cancel().
+  const base::Callback<void(A...)>& callback() const {
+    return forwarder_;
+  }
+
+ private:
+  void Forward(A... args) const {
+    callback_.Run(args...);
+  }
+
+  // Helper method to bind |forwarder_| using a weak pointer from
+  // |weak_factory_|.
+  void InitializeForwarder() {
+    forwarder_ = base::Bind(&CancelableCallback<void(A...)>::Forward,
+                            weak_factory_.GetWeakPtr());
+  }
+
+  // The wrapper closure.
+  base::Callback<void(A...)> forwarder_;
+
+  // The stored closure that may be cancelled.
+  base::Callback<void(A...)> callback_;
+
+  // Used to ensure Forward() is not run when this object is destroyed.
+  base::WeakPtrFactory<CancelableCallback<void(A...)>> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
+};
+
+typedef CancelableCallback<void(void)> CancelableClosure;
+
+}  // namespace base
+
+#endif  // BASE_CANCELABLE_CALLBACK_H_
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
new file mode 100644
index 0000000..6d0a114
--- /dev/null
+++ b/base/cancelable_callback_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cancelable_callback.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
+ private:
+  friend class RefCountedThreadSafe<TestRefCounted>;
+  ~TestRefCounted() {};
+};
+
+void Increment(int* count) { (*count)++; }
+void IncrementBy(int* count, int n) { (*count) += n; }
+void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
+
+// Cancel().
+//  - Callback can be run multiple times.
+//  - After Cancel(), Run() completes but has no effect.
+TEST(CancelableCallbackTest, Cancel) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback = cancelable.callback();
+  callback.Run();
+  EXPECT_EQ(1, count);
+
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  cancelable.Cancel();
+  callback.Run();
+  EXPECT_EQ(2, count);
+}
+
+// Cancel() called multiple times.
+//  - Cancel() cancels all copies of the wrapped callback.
+//  - Calling Cancel() more than once has no effect.
+//  - After Cancel(), callback() returns a null callback.
+TEST(CancelableCallbackTest, MultipleCancel) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback1 = cancelable.callback();
+  base::Closure callback2 = cancelable.callback();
+  cancelable.Cancel();
+
+  callback1.Run();
+  EXPECT_EQ(0, count);
+
+  callback2.Run();
+  EXPECT_EQ(0, count);
+
+  // Calling Cancel() again has no effect.
+  cancelable.Cancel();
+
+  // callback() of a cancelled callback is null.
+  base::Closure callback3 = cancelable.callback();
+  EXPECT_TRUE(callback3.is_null());
+}
+
+// CancelableCallback destroyed before callback is run.
+//  - Destruction of CancelableCallback cancels outstanding callbacks.
+TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
+  int count = 0;
+  base::Closure callback;
+
+  {
+    CancelableClosure cancelable(
+        base::Bind(&Increment, base::Unretained(&count)));
+
+    callback = cancelable.callback();
+    callback.Run();
+    EXPECT_EQ(1, count);
+  }
+
+  callback.Run();
+  EXPECT_EQ(1, count);
+}
+
+// Cancel() called on bound closure with a RefCounted parameter.
+//  - Cancel drops wrapped callback (and, implicitly, its bound arguments).
+TEST(CancelableCallbackTest, CancelDropsCallback) {
+  scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
+  EXPECT_TRUE(ref_counted->HasOneRef());
+
+  CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted));
+  EXPECT_FALSE(cancelable.IsCancelled());
+  EXPECT_TRUE(ref_counted.get());
+  EXPECT_FALSE(ref_counted->HasOneRef());
+
+  // There is only one reference to |ref_counted| after the Cancel().
+  cancelable.Cancel();
+  EXPECT_TRUE(cancelable.IsCancelled());
+  EXPECT_TRUE(ref_counted.get());
+  EXPECT_TRUE(ref_counted->HasOneRef());
+}
+
+// Reset().
+//  - Reset() replaces the existing wrapped callback with a new callback.
+//  - Reset() deactivates outstanding callbacks.
+TEST(CancelableCallbackTest, Reset) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback = cancelable.callback();
+  callback.Run();
+  EXPECT_EQ(1, count);
+
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  cancelable.Reset(
+      base::Bind(&IncrementBy, base::Unretained(&count), 3));
+  EXPECT_FALSE(cancelable.IsCancelled());
+
+  // The stale copy of the cancelable callback is non-null.
+  ASSERT_FALSE(callback.is_null());
+
+  // The stale copy of the cancelable callback is no longer active.
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  base::Closure callback2 = cancelable.callback();
+  ASSERT_FALSE(callback2.is_null());
+
+  callback2.Run();
+  EXPECT_EQ(5, count);
+}
+
+// IsCanceled().
+//  - Cancel() transforms the CancelableCallback into a cancelled state.
+TEST(CancelableCallbackTest, IsNull) {
+  CancelableClosure cancelable;
+  EXPECT_TRUE(cancelable.IsCancelled());
+
+  int count = 0;
+  cancelable.Reset(base::Bind(&Increment,
+                              base::Unretained(&count)));
+  EXPECT_FALSE(cancelable.IsCancelled());
+
+  cancelable.Cancel();
+  EXPECT_TRUE(cancelable.IsCancelled());
+}
+
+// CancelableCallback posted to a MessageLoop with PostTask.
+//  - Callbacks posted to a MessageLoop can be cancelled.
+TEST(CancelableCallbackTest, PostTask) {
+  MessageLoop loop;
+
+  int count = 0;
+  CancelableClosure cancelable(base::Bind(&Increment,
+                                           base::Unretained(&count)));
+
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, count);
+
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
+
+  // Cancel before running the message loop.
+  cancelable.Cancel();
+  RunLoop().RunUntilIdle();
+
+  // Callback never ran due to cancellation; count is the same.
+  EXPECT_EQ(1, count);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/check_example.cc b/base/check_example.cc
new file mode 100644
index 0000000..4b3f428
--- /dev/null
+++ b/base/check_example.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is meant for analyzing the code generated by the CHECK
+// macros in a small executable file that's easy to disassemble.
+
+#include "base/logging.h"
+
+// An official build shouldn't generate code to print out messages for
+// the CHECK* macros, nor should it have the strings in the
+// executable.
+
+void DoCheck(bool b) {
+  CHECK(b) << "DoCheck " << b;
+}
+
+void DoCheckEq(int x, int y) {
+  CHECK_EQ(x, y);
+}
+
+int main(int argc, const char* argv[]) {
+  DoCheck(argc > 1);
+  DoCheckEq(argc, 1);
+}
diff --git a/base/chromeos/OWNERS b/base/chromeos/OWNERS
new file mode 100644
index 0000000..8fda46a
--- /dev/null
+++ b/base/chromeos/OWNERS
@@ -0,0 +1,3 @@
+skuhne@chromium.org
+oshima@chromium.org
+
diff --git a/base/chromeos/memory_pressure_monitor_chromeos.cc b/base/chromeos/memory_pressure_monitor_chromeos.cc
new file mode 100644
index 0000000..82bc6a1
--- /dev/null
+++ b/base/chromeos/memory_pressure_monitor_chromeos.cc
@@ -0,0 +1,264 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/chromeos/memory_pressure_monitor_chromeos.h"
+
+#include <fcntl.h>
+#include <sys/select.h>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+
+namespace {
+
+// The time between memory pressure checks. While under critical pressure, this
+// is also the timer to repeat cleanup attempts.
+const int kMemoryPressureIntervalMs = 1000;
+
+// The time which should pass between two moderate memory pressure calls.
+const int kModerateMemoryPressureCooldownMs = 10000;
+
+// Number of event polls before the next moderate pressure event can be sent.
+const int kModerateMemoryPressureCooldown =
+    kModerateMemoryPressureCooldownMs / kMemoryPressureIntervalMs;
+
+// Threshold constants to emit pressure events.
+const int kNormalMemoryPressureModerateThresholdPercent = 60;
+const int kNormalMemoryPressureCriticalThresholdPercent = 95;
+const int kAggressiveMemoryPressureModerateThresholdPercent = 35;
+const int kAggressiveMemoryPressureCriticalThresholdPercent = 70;
+
+// The possible state for memory pressure level. The values should be in line
+// with values in MemoryPressureListener::MemoryPressureLevel and should be
+// updated if more memory pressure levels are introduced.
+enum MemoryPressureLevelUMA {
+  MEMORY_PRESSURE_LEVEL_NONE = 0,
+  MEMORY_PRESSURE_LEVEL_MODERATE,
+  MEMORY_PRESSURE_LEVEL_CRITICAL,
+  NUM_MEMORY_PRESSURE_LEVELS
+};
+
+// This is the file that will exist if low memory notification is available
+// on the device.  Whenever it becomes readable, it signals a low memory
+// condition.
+const char kLowMemFile[] = "/dev/chromeos-low-mem";
+
+// Converts a |MemoryPressureThreshold| value into a used memory percentage for
+// the moderate pressure event.
+int GetModerateMemoryThresholdInPercent(
+    MemoryPressureMonitorChromeOS::MemoryPressureThresholds thresholds) {
+  return thresholds == MemoryPressureMonitorChromeOS::
+                           THRESHOLD_AGGRESSIVE_CACHE_DISCARD ||
+         thresholds == MemoryPressureMonitorChromeOS::THRESHOLD_AGGRESSIVE
+             ? kAggressiveMemoryPressureModerateThresholdPercent
+             : kNormalMemoryPressureModerateThresholdPercent;
+}
+
+// Converts a |MemoryPressureThreshold| value into a used memory percentage for
+// the critical pressure event.
+int GetCriticalMemoryThresholdInPercent(
+    MemoryPressureMonitorChromeOS::MemoryPressureThresholds thresholds) {
+  return thresholds == MemoryPressureMonitorChromeOS::
+                           THRESHOLD_AGGRESSIVE_TAB_DISCARD ||
+         thresholds == MemoryPressureMonitorChromeOS::THRESHOLD_AGGRESSIVE
+             ? kAggressiveMemoryPressureCriticalThresholdPercent
+             : kNormalMemoryPressureCriticalThresholdPercent;
+}
+
+// Converts free percent of memory into a memory pressure value.
+MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel(
+    int actual_fill_level,
+    int moderate_threshold,
+    int critical_threshold) {
+  if (actual_fill_level < moderate_threshold)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+  return actual_fill_level < critical_threshold
+             ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
+             : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+}
+
+// This function will be called less then once a second. It will check if
+// the kernel has detected a low memory situation.
+bool IsLowMemoryCondition(int file_descriptor) {
+  fd_set fds;
+  struct timeval tv;
+
+  FD_ZERO(&fds);
+  FD_SET(file_descriptor, &fds);
+
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  return HANDLE_EINTR(select(file_descriptor + 1, &fds, NULL, NULL, &tv)) > 0;
+}
+
+}  // namespace
+
+MemoryPressureMonitorChromeOS::MemoryPressureMonitorChromeOS(
+    MemoryPressureThresholds thresholds)
+    : current_memory_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      moderate_pressure_repeat_count_(0),
+      moderate_pressure_threshold_percent_(
+          GetModerateMemoryThresholdInPercent(thresholds)),
+      critical_pressure_threshold_percent_(
+          GetCriticalMemoryThresholdInPercent(thresholds)),
+      low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))),
+      weak_ptr_factory_(this) {
+  StartObserving();
+  LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener";
+}
+
+MemoryPressureMonitorChromeOS::~MemoryPressureMonitorChromeOS() {
+  StopObserving();
+}
+
+void MemoryPressureMonitorChromeOS::ScheduleEarlyCheck() {
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&MemoryPressureMonitorChromeOS::CheckMemoryPressure,
+                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorChromeOS::GetCurrentPressureLevel() const {
+  return current_memory_pressure_level_;
+}
+
+void MemoryPressureMonitorChromeOS::StartObserving() {
+  timer_.Start(FROM_HERE,
+               TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs),
+               Bind(&MemoryPressureMonitorChromeOS::
+                        CheckMemoryPressureAndRecordStatistics,
+                    weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MemoryPressureMonitorChromeOS::StopObserving() {
+  // If StartObserving failed, StopObserving will still get called.
+  timer_.Stop();
+}
+
+void MemoryPressureMonitorChromeOS::CheckMemoryPressureAndRecordStatistics() {
+  CheckMemoryPressure();
+
+  // Record UMA histogram statistics for the current memory pressure level.
+  MemoryPressureLevelUMA memory_pressure_level_uma(MEMORY_PRESSURE_LEVEL_NONE);
+  switch (current_memory_pressure_level_) {
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_NONE;
+      break;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_MODERATE;
+      break;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_CRITICAL;
+      break;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel",
+                            memory_pressure_level_uma,
+                            NUM_MEMORY_PRESSURE_LEVELS);
+}
+
+void MemoryPressureMonitorChromeOS::CheckMemoryPressure() {
+  MemoryPressureListener::MemoryPressureLevel old_pressure =
+      current_memory_pressure_level_;
+
+  // If we have the kernel low memory observer, we use it's flag instead of our
+  // own computation (for now). Note that in "simulation mode" it can be null.
+  // TODO(skuhne): We need to add code which makes sure that the kernel and this
+  // computation come to similar results and then remove this override again.
+  // TODO(skuhne): Add some testing framework here to see how close the kernel
+  // and the internal functions are.
+  if (low_mem_file_.is_valid() && IsLowMemoryCondition(low_mem_file_.get())) {
+    current_memory_pressure_level_ =
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+  } else {
+    current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel(
+        GetUsedMemoryInPercent(),
+        moderate_pressure_threshold_percent_,
+        critical_pressure_threshold_percent_);
+
+    // When listening to the kernel, we ignore the reported memory pressure
+    // level from our own computation and reduce critical to moderate.
+    if (low_mem_file_.is_valid() &&
+        current_memory_pressure_level_ ==
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+      current_memory_pressure_level_ =
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+    }
+  }
+
+  // In case there is no memory pressure we do not notify.
+  if (current_memory_pressure_level_ ==
+      MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
+    return;
+  }
+  if (old_pressure == current_memory_pressure_level_) {
+    // If the memory pressure is still at the same level, we notify again for a
+    // critical level. In case of a moderate level repeat however, we only send
+    // a notification after a certain time has passed.
+    if (current_memory_pressure_level_ ==
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
+          ++moderate_pressure_repeat_count_ <
+              kModerateMemoryPressureCooldown) {
+      return;
+    }
+  } else if (current_memory_pressure_level_ ==
+               MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
+             old_pressure ==
+               MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+    // When we reducing the pressure level from critical to moderate, we
+    // restart the timeout and do not send another notification.
+    moderate_pressure_repeat_count_ = 0;
+    return;
+  }
+  moderate_pressure_repeat_count_ = 0;
+  MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+}
+
+// Gets the used ChromeOS memory in percent.
+int MemoryPressureMonitorChromeOS::GetUsedMemoryInPercent() {
+  base::SystemMemoryInfoKB info;
+  if (!base::GetSystemMemoryInfo(&info)) {
+    VLOG(1) << "Cannot determine the free memory of the system.";
+    return 0;
+  }
+  // TODO(skuhne): Instead of adding the kernel memory pressure calculation
+  // logic here, we should have a kernel mechanism similar to the low memory
+  // notifier in ChromeOS which offers multiple pressure states.
+  // To track this, we have crbug.com/381196.
+
+  // The available memory consists of "real" and virtual (z)ram memory.
+  // Since swappable memory uses a non pre-deterministic compression and
+  // the compression creates its own "dynamic" in the system, it gets
+  // de-emphasized by the |kSwapWeight| factor.
+  const int kSwapWeight = 4;
+
+  // The total memory we have is the "real memory" plus the virtual (z)ram.
+  int total_memory = info.total + info.swap_total / kSwapWeight;
+
+  // The kernel internally uses 50MB.
+  const int kMinFileMemory = 50 * 1024;
+
+  // Most file memory can be easily reclaimed.
+  int file_memory = info.active_file + info.inactive_file;
+  // unless it is dirty or it's a minimal portion which is required.
+  file_memory -= info.dirty + kMinFileMemory;
+
+  // Available memory is the sum of free, swap and easy reclaimable memory.
+  int available_memory =
+      info.free + info.swap_free / kSwapWeight + file_memory;
+
+  DCHECK(available_memory < total_memory);
+  int percentage = ((total_memory - available_memory) * 100) / total_memory;
+  return percentage;
+}
+
+}  // namespace base
diff --git a/base/chromeos/memory_pressure_monitor_chromeos.h b/base/chromeos/memory_pressure_monitor_chromeos.h
new file mode 100644
index 0000000..45855eb
--- /dev/null
+++ b/base/chromeos/memory_pressure_monitor_chromeos.h
@@ -0,0 +1,113 @@
+// Copyright 2014 The Chromium Authors. All 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_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
+#define BASE_CHROMEOS_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+
+namespace base {
+
+class TestMemoryPressureMonitor;
+
+////////////////////////////////////////////////////////////////////////////////
+// MemoryPressureMonitorChromeOS
+//
+// A class to handle the observation of our free memory. It notifies the
+// MemoryPressureListener of memory fill level changes, so that it can take
+// action to reduce memory resources accordingly.
+//
+class BASE_EXPORT MemoryPressureMonitorChromeOS : public MemoryPressureMonitor {
+ public:
+  using GetUsedMemoryInPercentCallback = int (*)();
+
+  // There are two memory pressure events:
+  // MODERATE - which will mainly release caches.
+  // CRITICAL - which will discard tabs.
+  // The |MemoryPressureThresholds| enum selects the strategy of firing these
+  // events: A conservative strategy will keep as much content in memory as
+  // possible (causing the system to swap to zram) and an aggressive strategy
+  // will release memory earlier to avoid swapping.
+  enum MemoryPressureThresholds {
+    // Use the system default.
+    THRESHOLD_DEFAULT = 0,
+    // Try to keep as much content in memory as possible.
+    THRESHOLD_CONSERVATIVE = 1,
+    // Discard caches earlier, allowing to keep more tabs in memory.
+    THRESHOLD_AGGRESSIVE_CACHE_DISCARD = 2,
+    // Discard tabs earlier, allowing the system to get faster.
+    THRESHOLD_AGGRESSIVE_TAB_DISCARD = 3,
+    // Discard caches and tabs earlier to allow the system to be faster.
+    THRESHOLD_AGGRESSIVE = 4
+  };
+
+  explicit MemoryPressureMonitorChromeOS(MemoryPressureThresholds thresholds);
+  ~MemoryPressureMonitorChromeOS() override;
+
+  // Redo the memory pressure calculation soon and call again if a critical
+  // memory pressure prevails. Note that this call will trigger an asynchronous
+  // action which gives the system time to release memory back into the pool.
+  void ScheduleEarlyCheck();
+
+  // Get the current memory pressure level.
+  MemoryPressureListener::MemoryPressureLevel GetCurrentPressureLevel() const
+      override;
+
+ private:
+  friend TestMemoryPressureMonitor;
+  // Starts observing the memory fill level.
+  // Calls to StartObserving should always be matched with calls to
+  // StopObserving.
+  void StartObserving();
+
+  // Stop observing the memory fill level.
+  // May be safely called if StartObserving has not been called.
+  void StopObserving();
+
+  // The function which gets periodically called to check any changes in the
+  // memory pressure. It will report pressure changes as well as continuous
+  // critical pressure levels.
+  void CheckMemoryPressure();
+
+  // The function periodically checks the memory pressure changes and records
+  // the UMA histogram statistics for the current memory pressure level.
+  void CheckMemoryPressureAndRecordStatistics();
+
+  // Get the memory pressure in percent (virtual for testing).
+  virtual int GetUsedMemoryInPercent();
+
+  // The current memory pressure.
+  base::MemoryPressureListener::MemoryPressureLevel
+      current_memory_pressure_level_;
+
+  // A periodic timer to check for resource pressure changes. This will get
+  // replaced by a kernel triggered event system (see crbug.com/381196).
+  base::RepeatingTimer<MemoryPressureMonitorChromeOS> timer_;
+
+  // To slow down the amount of moderate pressure event calls, this counter
+  // gets used to count the number of events since the last event occured.
+  int moderate_pressure_repeat_count_;
+
+  // The thresholds for moderate and critical pressure.
+  const int moderate_pressure_threshold_percent_;
+  const int critical_pressure_threshold_percent_;
+
+  // File descriptor used to detect low memory condition.
+  ScopedFD low_mem_file_;
+
+  base::WeakPtrFactory<MemoryPressureMonitorChromeOS> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitorChromeOS);
+};
+
+}  // namespace base
+
+#endif  // BASE_CHROMEOS_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
diff --git a/base/chromeos/memory_pressure_monitor_chromeos_unittest.cc b/base/chromeos/memory_pressure_monitor_chromeos_unittest.cc
new file mode 100644
index 0000000..72e00d3
--- /dev/null
+++ b/base/chromeos/memory_pressure_monitor_chromeos_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright 2014 The Chromium Authors. All 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/chromeos/memory_pressure_monitor_chromeos.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// True if the memory notifier got called.
+// Do not read/modify value directly.
+bool on_memory_pressure_called = false;
+
+// If the memory notifier got called, this is the memory pressure reported.
+MemoryPressureListener::MemoryPressureLevel on_memory_pressure_level =
+    MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+// Processes OnMemoryPressure calls.
+void OnMemoryPressure(MemoryPressureListener::MemoryPressureLevel level) {
+  on_memory_pressure_called = true;
+  on_memory_pressure_level = level;
+}
+
+// Resets the indicator for memory pressure.
+void ResetOnMemoryPressureCalled() {
+  on_memory_pressure_called = false;
+}
+
+// Returns true when OnMemoryPressure was called (and resets it).
+bool WasOnMemoryPressureCalled() {
+  bool b = on_memory_pressure_called;
+  ResetOnMemoryPressureCalled();
+  return b;
+}
+
+}  // namespace
+
+class TestMemoryPressureMonitor : public MemoryPressureMonitorChromeOS {
+ public:
+  TestMemoryPressureMonitor() :
+    MemoryPressureMonitorChromeOS(
+        MemoryPressureMonitorChromeOS::THRESHOLD_DEFAULT),
+    memory_in_percent_override_(0) {
+    // Disable any timers which are going on and set a special memory reporting
+    // function.
+    StopObserving();
+  }
+  ~TestMemoryPressureMonitor() override {}
+
+  void SetMemoryInPercentOverride(int percent) {
+    memory_in_percent_override_ = percent;
+  }
+
+  void CheckMemoryPressureForTest() {
+    CheckMemoryPressure();
+  }
+
+ private:
+  int GetUsedMemoryInPercent() override {
+    return memory_in_percent_override_;
+  }
+
+  int memory_in_percent_override_;
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST(MemoryPressureMonitorChromeOSTest, CheckMemoryPressure) {
+  base::MessageLoopForUI message_loop;
+  scoped_ptr<TestMemoryPressureMonitor> monitor(
+      new TestMemoryPressureMonitor);
+  scoped_ptr<MemoryPressureListener> listener(
+      new MemoryPressureListener(base::Bind(&OnMemoryPressure)));
+  // Checking the memory pressure while 0% are used should not produce any
+  // events.
+  monitor->SetMemoryInPercentOverride(0);
+  ResetOnMemoryPressureCalled();
+
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            monitor->GetCurrentPressureLevel());
+
+  // Setting the memory level to 80% should produce a moderate pressure level.
+  monitor->SetMemoryInPercentOverride(80);
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor->GetCurrentPressureLevel());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            on_memory_pressure_level);
+
+  // We need to check that the event gets reposted after a while.
+  int i = 0;
+  for (; i < 100; i++) {
+    monitor->CheckMemoryPressureForTest();
+    message_loop.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->GetCurrentPressureLevel());
+    if (WasOnMemoryPressureCalled()) {
+      EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+                on_memory_pressure_level);
+      break;
+    }
+  }
+  // Should be more then 5 and less then 100.
+  EXPECT_LE(5, i);
+  EXPECT_GE(99, i);
+
+  // Setting the memory usage to 99% should produce critical levels.
+  monitor->SetMemoryInPercentOverride(99);
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            on_memory_pressure_level);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor->GetCurrentPressureLevel());
+
+  // Calling it again should immediately produce a second call.
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            on_memory_pressure_level);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor->GetCurrentPressureLevel());
+
+  // When lowering the pressure again we should not get an event, but the
+  // pressure should go back to moderate.
+  monitor->SetMemoryInPercentOverride(80);
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor->GetCurrentPressureLevel());
+
+  // We should need exactly the same amount of calls as before, before the next
+  // call comes in.
+  int j = 0;
+  for (; j < 100; j++) {
+    monitor->CheckMemoryPressureForTest();
+    message_loop.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->GetCurrentPressureLevel());
+    if (WasOnMemoryPressureCalled()) {
+      EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+                on_memory_pressure_level);
+      break;
+    }
+  }
+  // We should have needed exactly the same amount of checks as before.
+  EXPECT_EQ(j, i);
+}
+
+}  // namespace base
diff --git a/base/command_line.cc b/base/command_line.cc
new file mode 100644
index 0000000..61ff5c1
--- /dev/null
+++ b/base/command_line.cc
@@ -0,0 +1,456 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#endif
+
+namespace base {
+
+CommandLine* CommandLine::current_process_commandline_ = NULL;
+
+namespace {
+
+const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
+const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
+
+// Since we use a lazy match, make sure that longer versions (like "--") are
+// listed before shorter versions (like "-") of similar prefixes.
+#if defined(OS_WIN)
+// By putting slash last, we can control whether it is treaded as a switch
+// value by changing the value of switch_prefix_count to be one less than
+// the array size.
+const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
+#elif defined(OS_POSIX)
+// Unixes don't use slash as a switch.
+const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"};
+#endif
+size_t switch_prefix_count = arraysize(kSwitchPrefixes);
+
+size_t GetSwitchPrefixLength(const CommandLine::StringType& string) {
+  for (size_t i = 0; i < switch_prefix_count; ++i) {
+    CommandLine::StringType prefix(kSwitchPrefixes[i]);
+    if (string.compare(0, prefix.length(), prefix) == 0)
+      return prefix.length();
+  }
+  return 0;
+}
+
+// Fills in |switch_string| and |switch_value| if |string| is a switch.
+// This will preserve the input switch prefix in the output |switch_string|.
+bool IsSwitch(const CommandLine::StringType& string,
+              CommandLine::StringType* switch_string,
+              CommandLine::StringType* switch_value) {
+  switch_string->clear();
+  switch_value->clear();
+  size_t prefix_length = GetSwitchPrefixLength(string);
+  if (prefix_length == 0 || prefix_length == string.length())
+    return false;
+
+  const size_t equals_position = string.find(kSwitchValueSeparator);
+  *switch_string = string.substr(0, equals_position);
+  if (equals_position != CommandLine::StringType::npos)
+    *switch_value = string.substr(equals_position + 1);
+  return true;
+}
+
+// Append switches and arguments, keeping switches before arguments.
+void AppendSwitchesAndArguments(CommandLine* command_line,
+                                const CommandLine::StringVector& argv) {
+  bool parse_switches = true;
+  for (size_t i = 1; i < argv.size(); ++i) {
+    CommandLine::StringType arg = argv[i];
+    TrimWhitespace(arg, TRIM_ALL, &arg);
+
+    CommandLine::StringType switch_string;
+    CommandLine::StringType switch_value;
+    parse_switches &= (arg != kSwitchTerminator);
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+#if defined(OS_WIN)
+      command_line->AppendSwitchNative(UTF16ToASCII(switch_string),
+                                       switch_value);
+#elif defined(OS_POSIX)
+      command_line->AppendSwitchNative(switch_string, switch_value);
+#endif
+    } else {
+      command_line->AppendArgNative(arg);
+    }
+  }
+}
+
+// Lowercase switches for backwards compatiblity *on Windows*.
+#if defined(OS_WIN)
+std::string LowerASCIIOnWindows(const std::string& string) {
+  return StringToLowerASCII(string);
+}
+#elif defined(OS_POSIX)
+const std::string& LowerASCIIOnWindows(const std::string& string) {
+  return string;
+}
+#endif
+
+
+#if defined(OS_WIN)
+// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
+string16 QuoteForCommandLineToArgvW(const string16& arg,
+                                    bool quote_placeholders) {
+  // We follow the quoting rules of CommandLineToArgvW.
+  // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  string16 quotable_chars(L" \\\"");
+  // We may also be required to quote '%', which is commonly used in a command
+  // line as a placeholder. (It may be substituted for a string with spaces.)
+  if (quote_placeholders)
+    quotable_chars.push_back(L'%');
+  if (arg.find_first_of(quotable_chars) == string16::npos) {
+    // No quoting necessary.
+    return arg;
+  }
+
+  string16 out;
+  out.push_back(L'"');
+  for (size_t i = 0; i < arg.size(); ++i) {
+    if (arg[i] == '\\') {
+      // Find the extent of this run of backslashes.
+      size_t start = i, end = start + 1;
+      for (; end < arg.size() && arg[end] == '\\'; ++end) {}
+      size_t backslash_count = end - start;
+
+      // Backslashes are escapes only if the run is followed by a double quote.
+      // Since we also will end the string with a double quote, we escape for
+      // either a double quote or the end of the string.
+      if (end == arg.size() || arg[end] == '"') {
+        // To quote, we need to output 2x as many backslashes.
+        backslash_count *= 2;
+      }
+      for (size_t j = 0; j < backslash_count; ++j)
+        out.push_back('\\');
+
+      // Advance i to one before the end to balance i++ in loop.
+      i = end - 1;
+    } else if (arg[i] == '"') {
+      out.push_back('\\');
+      out.push_back('"');
+    } else {
+      out.push_back(arg[i]);
+    }
+  }
+  out.push_back('"');
+
+  return out;
+}
+#endif
+
+}  // namespace
+
+CommandLine::CommandLine(NoProgram no_program)
+    : argv_(1),
+      begin_args_(1) {
+}
+
+CommandLine::CommandLine(const FilePath& program)
+    : argv_(1),
+      begin_args_(1) {
+  SetProgram(program);
+}
+
+CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
+    : argv_(1),
+      begin_args_(1) {
+  InitFromArgv(argc, argv);
+}
+
+CommandLine::CommandLine(const StringVector& argv)
+    : argv_(1),
+      begin_args_(1) {
+  InitFromArgv(argv);
+}
+
+CommandLine::~CommandLine() {
+}
+
+#if defined(OS_WIN)
+// static
+void CommandLine::set_slash_is_not_a_switch() {
+  // The last switch prefix should be slash, so adjust the size to skip it.
+  DCHECK_EQ(wcscmp(kSwitchPrefixes[arraysize(kSwitchPrefixes) - 1], L"/"), 0);
+  switch_prefix_count = arraysize(kSwitchPrefixes) - 1;
+}
+#endif
+
+// static
+bool CommandLine::Init(int argc, const char* const* argv) {
+  if (current_process_commandline_) {
+    // If this is intentional, Reset() must be called first. If we are using
+    // the shared build mode, we have to share a single object across multiple
+    // shared libraries.
+    return false;
+  }
+
+  current_process_commandline_ = new CommandLine(NO_PROGRAM);
+#if defined(OS_WIN)
+  current_process_commandline_->ParseFromString(::GetCommandLineW());
+#elif defined(OS_POSIX)
+  current_process_commandline_->InitFromArgv(argc, argv);
+#endif
+
+  return true;
+}
+
+// static
+void CommandLine::Reset() {
+  DCHECK(current_process_commandline_);
+  delete current_process_commandline_;
+  current_process_commandline_ = NULL;
+}
+
+// static
+CommandLine* CommandLine::ForCurrentProcess() {
+  DCHECK(current_process_commandline_);
+  return current_process_commandline_;
+}
+
+// static
+bool CommandLine::InitializedForCurrentProcess() {
+  return !!current_process_commandline_;
+}
+
+#if defined(OS_WIN)
+// static
+CommandLine CommandLine::FromString(const string16& command_line) {
+  CommandLine cmd(NO_PROGRAM);
+  cmd.ParseFromString(command_line);
+  return cmd;
+}
+#endif
+
+void CommandLine::InitFromArgv(int argc,
+                               const CommandLine::CharType* const* argv) {
+  StringVector new_argv;
+  for (int i = 0; i < argc; ++i)
+    new_argv.push_back(argv[i]);
+  InitFromArgv(new_argv);
+}
+
+void CommandLine::InitFromArgv(const StringVector& argv) {
+  argv_ = StringVector(1);
+  switches_.clear();
+  begin_args_ = 1;
+  SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
+  AppendSwitchesAndArguments(this, argv);
+}
+
+FilePath CommandLine::GetProgram() const {
+  return FilePath(argv_[0]);
+}
+
+void CommandLine::SetProgram(const FilePath& program) {
+  TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
+}
+
+bool CommandLine::HasSwitch(const std::string& switch_string) const {
+  DCHECK_EQ(StringToLowerASCII(switch_string), switch_string);
+  return switches_.find(switch_string) != switches_.end();
+}
+
+bool CommandLine::HasSwitch(const char string_constant[]) const {
+  return HasSwitch(std::string(string_constant));
+}
+
+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 UTF16ToASCII(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_.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(ASCIIToUTF16(switch_key));
+#elif defined(OS_POSIX)
+  StringType combined_switch_string(switch_string);
+#endif
+  size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
+  switches_[switch_key.substr(prefix_length)] = value;
+  // Preserve existing switch prefixes in |argv_|; only append one if necessary.
+  if (prefix_length == 0)
+    combined_switch_string = kSwitchPrefixes[0] + combined_switch_string;
+  if (!value.empty())
+    combined_switch_string += kSwitchValueSeparator + value;
+  // Append the switch and update the switches/arguments divider |begin_args_|.
+  argv_.insert(argv_.begin() + begin_args_++, combined_switch_string);
+}
+
+void CommandLine::AppendSwitchASCII(const std::string& switch_string,
+                                    const std::string& value_string) {
+#if defined(OS_WIN)
+  AppendSwitchNative(switch_string, ASCIIToUTF16(value_string));
+#elif defined(OS_POSIX)
+  AppendSwitchNative(switch_string, value_string);
+#endif
+}
+
+void CommandLine::CopySwitchesFrom(const CommandLine& source,
+                                   const char* const switches[],
+                                   size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    if (source.HasSwitch(switches[i]))
+      AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i]));
+  }
+}
+
+CommandLine::StringVector CommandLine::GetArgs() const {
+  // Gather all arguments after the last switch (may include kSwitchTerminator).
+  StringVector args(argv_.begin() + begin_args_, argv_.end());
+  // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
+  StringVector::iterator switch_terminator =
+      std::find(args.begin(), args.end(), kSwitchTerminator);
+  if (switch_terminator != args.end())
+    args.erase(switch_terminator);
+  return args;
+}
+
+void CommandLine::AppendArg(const std::string& value) {
+#if defined(OS_WIN)
+  DCHECK(IsStringUTF8(value));
+  AppendArgNative(UTF8ToWide(value));
+#elif defined(OS_POSIX)
+  AppendArgNative(value);
+#endif
+}
+
+void CommandLine::AppendArgPath(const FilePath& path) {
+  AppendArgNative(path.value());
+}
+
+void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
+  argv_.push_back(value);
+}
+
+void CommandLine::AppendArguments(const CommandLine& other,
+                                  bool include_program) {
+  if (include_program)
+    SetProgram(other.GetProgram());
+  AppendSwitchesAndArguments(this, other.argv());
+}
+
+void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
+  if (wrapper.empty())
+    return;
+  // The wrapper may have embedded arguments (like "gdb --args"). In this case,
+  // we don't pretend to do anything fancy, we just split on spaces.
+  StringVector wrapper_argv;
+  SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
+  // Prepend the wrapper and update the switches/arguments |begin_args_|.
+  argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
+  begin_args_ += wrapper_argv.size();
+}
+
+#if defined(OS_WIN)
+void CommandLine::ParseFromString(const string16& command_line) {
+  string16 command_line_string;
+  TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
+  if (command_line_string.empty())
+    return;
+
+  int num_args = 0;
+  wchar_t** args = NULL;
+  args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
+
+  DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
+                         << UTF16ToUTF8(command_line);
+  InitFromArgv(num_args, args);
+  LocalFree(args);
+}
+#endif
+
+CommandLine::StringType CommandLine::GetCommandLineStringInternal(
+    bool quote_placeholders) const {
+  StringType string(argv_[0]);
+#if defined(OS_WIN)
+  string = QuoteForCommandLineToArgvW(string, quote_placeholders);
+#endif
+  StringType params(GetArgumentsStringInternal(quote_placeholders));
+  if (!params.empty()) {
+    string.append(StringType(FILE_PATH_LITERAL(" ")));
+    string.append(params);
+  }
+  return string;
+}
+
+CommandLine::StringType CommandLine::GetArgumentsStringInternal(
+    bool quote_placeholders) const {
+  StringType params;
+  // Append switches and arguments.
+  bool parse_switches = true;
+  for (size_t i = 1; i < argv_.size(); ++i) {
+    StringType arg = argv_[i];
+    StringType switch_string;
+    StringType switch_value;
+    parse_switches &= arg != kSwitchTerminator;
+    if (i > 1)
+      params.append(StringType(FILE_PATH_LITERAL(" ")));
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+      params.append(switch_string);
+      if (!switch_value.empty()) {
+#if defined(OS_WIN)
+        switch_value =
+            QuoteForCommandLineToArgvW(switch_value, quote_placeholders);
+#endif
+        params.append(kSwitchValueSeparator + switch_value);
+      }
+    } else {
+#if defined(OS_WIN)
+      arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
+#endif
+      params.append(arg);
+    }
+  }
+  return params;
+}
+
+}  // namespace base
diff --git a/base/command_line.h b/base/command_line.h
new file mode 100644
index 0000000..439921e
--- /dev/null
+++ b/base/command_line.h
@@ -0,0 +1,232 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This class works with command lines: building and parsing.
+// Arguments with prefixes ('--', '-', and on Windows, '/') are switches.
+// Switches will precede all other arguments without switch prefixes.
+// Switches can optionally have values, delimited by '=', e.g., "-switch=value".
+// An argument of "--" will terminate switch parsing during initialization,
+// interpreting subsequent tokens as non-switch arguments, regardless of prefix.
+
+// There is a singleton read-only CommandLine that represents the command line
+// that the current process was started with.  It must be initialized in main().
+
+#ifndef BASE_COMMAND_LINE_H_
+#define BASE_COMMAND_LINE_H_
+
+#include <stddef.h>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+class BASE_EXPORT CommandLine {
+ public:
+#if defined(OS_WIN)
+  // The native command line string type.
+  typedef base::string16 StringType;
+#elif defined(OS_POSIX)
+  typedef std::string StringType;
+#endif
+
+  typedef StringType::value_type CharType;
+  typedef std::vector<StringType> StringVector;
+  typedef std::map<std::string, StringType> SwitchMap;
+
+  // 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();
+
+#if defined(OS_WIN)
+  // By default this class will treat command-line arguments beginning with
+  // slashes as switches on Windows, but not other platforms.
+  //
+  // If this behavior is inappropriate for your application, you can call this
+  // function BEFORE initializing the current process' global command line
+  // object and the behavior will be the same as Posix systems (only hyphens
+  // begin switches, everything else will be an arg).
+  static void set_slash_is_not_a_switch();
+#endif
+
+  // Initialize the current process CommandLine singleton. On Windows, ignores
+  // its arguments (we instead parse GetCommandLineW() directly) because we
+  // don't trust the CRT's parsing of the command line, but it still must be
+  // called to set up the command line. Returns false if initialization has
+  // already occurred, and true otherwise. Only the caller receiving a 'true'
+  // return value should take responsibility for calling Reset.
+  static bool Init(int argc, const char* const* argv);
+
+  // Destroys the current process CommandLine singleton. This is necessary if
+  // you want to reset the base library to its initial state (for example, in an
+  // outer library that needs to be able to terminate, and be re-initialized).
+  // If Init is called only once, as in main(), Reset() is not necessary.
+  static void Reset();
+
+  // Get the singleton CommandLine representing the current process's
+  // command line. Note: returned value is mutable, but not thread safe;
+  // only mutate if you know what you're doing!
+  static CommandLine* ForCurrentProcess();
+
+  // Returns true if the CommandLine has been initialized for the given process.
+  static bool InitializedForCurrentProcess();
+
+#if defined(OS_WIN)
+  static CommandLine FromString(const base::string16& command_line);
+#endif
+
+  // Initialize from an argv vector.
+  void InitFromArgv(int argc, const CharType* const* argv);
+  void InitFromArgv(const StringVector& argv);
+
+  // Constructs and returns the represented command line string.
+  // CAUTION! This should be avoided on POSIX because quoting behavior is
+  // unclear.
+  StringType GetCommandLineString() const {
+    return GetCommandLineStringInternal(false);
+  }
+
+#if defined(OS_WIN)
+  // Constructs and returns the represented command line string. Assumes the
+  // command line contains placeholders (eg, %1) and quotes any program or
+  // argument with a '%' in it. This should be avoided unless the placeholder is
+  // required by an external interface (eg, the Windows registry), because it is
+  // not generally safe to replace it with an arbitrary string. If possible,
+  // placeholders should be replaced *before* converting the command line to a
+  // string.
+  StringType GetCommandLineStringWithPlaceholders() const {
+    return GetCommandLineStringInternal(true);
+  }
+#endif
+
+  // Constructs and returns the represented arguments string.
+  // CAUTION! This should be avoided on POSIX because quoting behavior is
+  // unclear.
+  StringType GetArgumentsString() const {
+    return GetArgumentsStringInternal(false);
+  }
+
+#if defined(OS_WIN)
+  // Constructs and returns the represented arguments string. Assumes the
+  // command line contains placeholders (eg, %1) and quotes any argument with a
+  // '%' in it. This should be avoided unless the placeholder is required by an
+  // external interface (eg, the Windows registry), because it is not generally
+  // safe to replace it with an arbitrary string. If possible, placeholders
+  // should be replaced *before* converting the arguments to a string.
+  StringType GetArgumentsStringWithPlaceholders() const {
+    return GetArgumentsStringInternal(true);
+  }
+#endif
+
+  // Returns the original command line string as a vector of strings.
+  const StringVector& argv() const { return argv_; }
+
+  // Get and Set the program part of the command line string (the first item).
+  FilePath GetProgram() const;
+  void SetProgram(const FilePath& program);
+
+  // Returns true if this command line contains the given switch.
+  // Switch names should only be lowercase.
+  // The second override provides an optimized version to avoid inlining the
+  // codegen for the string allocation.
+  bool HasSwitch(const std::string& switch_string) const;
+  bool HasSwitch(const char switch_constant[]) const;
+
+  // Returns the value associated with the given switch. If the switch has no
+  // value or isn't present, this method returns the empty string.
+  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 base::string16& command_line);
+#endif
+
+ private:
+  // Disallow default constructor; a program name must be explicitly specified.
+  CommandLine();
+  // Allow the copy constructor. A common pattern is to copy of the current
+  // process's command line and then add some flags to it. For example:
+  //   CommandLine cl(*CommandLine::ForCurrentProcess());
+  //   cl.AppendSwitch(...);
+
+  // Internal version of GetCommandLineString. If |quote_placeholders| is true,
+  // also quotes parts with '%' in them.
+  StringType GetCommandLineStringInternal(bool quote_placeholders) const;
+
+  // Internal version of GetArgumentsString. If |quote_placeholders| is true,
+  // also quotes parts with '%' in them.
+  StringType GetArgumentsStringInternal(bool quote_placeholders) const;
+
+  // 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_;
+};
+
+}  // namespace base
+
+#endif  // BASE_COMMAND_LINE_H_
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
new file mode 100644
index 0000000..db1a0b2
--- /dev/null
+++ b/base/command_line_unittest.cc
@@ -0,0 +1,382 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// To test Windows quoting behavior, we use a string that has some backslashes
+// and quotes.
+// Consider the command-line argument: q\"bs1\bs2\\bs3q\\\"
+// Here it is with C-style escapes.
+static const CommandLine::StringType kTrickyQuoted =
+    FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\"");
+// It should be parsed by Windows as: q"bs1\bs2\\bs3q\"
+// Here that is with C-style escapes.
+static const CommandLine::StringType kTricky =
+    FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\"");
+
+TEST(CommandLineTest, CommandLineConstructor) {
+  const CommandLine::CharType* argv[] = {
+      FILE_PATH_LITERAL("program"),
+      FILE_PATH_LITERAL("--foo="),
+      FILE_PATH_LITERAL("-bAr"),
+      FILE_PATH_LITERAL("-spaetzel=pierogi"),
+      FILE_PATH_LITERAL("-baz"),
+      FILE_PATH_LITERAL("flim"),
+      FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"),
+      FILE_PATH_LITERAL("-spaetzle=Crepe"),
+      FILE_PATH_LITERAL("-=loosevalue"),
+      FILE_PATH_LITERAL("-"),
+      FILE_PATH_LITERAL("FLAN"),
+      FILE_PATH_LITERAL("a"),
+      FILE_PATH_LITERAL("--input-translation=45--output-rotation"),
+      FILE_PATH_LITERAL("--"),
+      FILE_PATH_LITERAL("--"),
+      FILE_PATH_LITERAL("--not-a-switch"),
+      FILE_PATH_LITERAL("\"in the time of submarines...\""),
+      FILE_PATH_LITERAL("unquoted arg-with-space")};
+  CommandLine cl(arraysize(argv), argv);
+
+  EXPECT_FALSE(cl.GetCommandLineString().empty());
+  EXPECT_FALSE(cl.HasSwitch("cruller"));
+  EXPECT_FALSE(cl.HasSwitch("flim"));
+  EXPECT_FALSE(cl.HasSwitch("program"));
+  EXPECT_FALSE(cl.HasSwitch("dog"));
+  EXPECT_FALSE(cl.HasSwitch("cat"));
+  EXPECT_FALSE(cl.HasSwitch("output-rotation"));
+  EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
+  EXPECT_FALSE(cl.HasSwitch("--"));
+
+  EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
+            cl.GetProgram().value());
+
+  EXPECT_TRUE(cl.HasSwitch("foo"));
+#if defined(OS_WIN)
+  EXPECT_TRUE(cl.HasSwitch("bar"));
+#else
+  EXPECT_FALSE(cl.HasSwitch("bar"));
+#endif
+  EXPECT_TRUE(cl.HasSwitch("baz"));
+  EXPECT_TRUE(cl.HasSwitch("spaetzle"));
+  EXPECT_TRUE(cl.HasSwitch("other-switches"));
+  EXPECT_TRUE(cl.HasSwitch("input-translation"));
+
+  EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
+  EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
+      "other-switches"));
+  EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
+
+  const CommandLine::StringVector& args = cl.GetArgs();
+  ASSERT_EQ(8U, args.size());
+
+  std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
+  EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("-"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("a"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter);
+  ++iter;
+  EXPECT_TRUE(iter == args.end());
+}
+
+TEST(CommandLineTest, CommandLineFromString) {
+#if defined(OS_WIN)
+  CommandLine cl = CommandLine::FromString(
+      L"program --foo= -bAr  /Spaetzel=pierogi /Baz flim "
+      L"--other-switches=\"--dog=canine --cat=feline\" "
+      L"-spaetzle=Crepe   -=loosevalue  FLAN "
+      L"--input-translation=\"45\"--output-rotation "
+      L"--quotes=" + kTrickyQuoted + L" "
+      L"-- -- --not-a-switch "
+      L"\"in the time of submarines...\"");
+
+  EXPECT_FALSE(cl.GetCommandLineString().empty());
+  EXPECT_FALSE(cl.HasSwitch("cruller"));
+  EXPECT_FALSE(cl.HasSwitch("flim"));
+  EXPECT_FALSE(cl.HasSwitch("program"));
+  EXPECT_FALSE(cl.HasSwitch("dog"));
+  EXPECT_FALSE(cl.HasSwitch("cat"));
+  EXPECT_FALSE(cl.HasSwitch("output-rotation"));
+  EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
+  EXPECT_FALSE(cl.HasSwitch("--"));
+
+  EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
+            cl.GetProgram().value());
+
+  EXPECT_TRUE(cl.HasSwitch("foo"));
+  EXPECT_TRUE(cl.HasSwitch("bar"));
+  EXPECT_TRUE(cl.HasSwitch("baz"));
+  EXPECT_TRUE(cl.HasSwitch("spaetzle"));
+  EXPECT_TRUE(cl.HasSwitch("other-switches"));
+  EXPECT_TRUE(cl.HasSwitch("input-translation"));
+  EXPECT_TRUE(cl.HasSwitch("quotes"));
+
+  EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
+  EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
+      "other-switches"));
+  EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
+  EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes"));
+
+  const CommandLine::StringVector& args = cl.GetArgs();
+  ASSERT_EQ(5U, args.size());
+
+  std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
+  EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter);
+  ++iter;
+  EXPECT_TRUE(iter == args.end());
+
+  // Check that a generated string produces an equivalent command line.
+  CommandLine cl_duplicate = CommandLine::FromString(cl.GetCommandLineString());
+  EXPECT_EQ(cl.GetCommandLineString(), cl_duplicate.GetCommandLineString());
+#endif
+}
+
+// Tests behavior with an empty input string.
+TEST(CommandLineTest, EmptyString) {
+#if defined(OS_WIN)
+  CommandLine cl_from_string = CommandLine::FromString(L"");
+  EXPECT_TRUE(cl_from_string.GetCommandLineString().empty());
+  EXPECT_TRUE(cl_from_string.GetProgram().empty());
+  EXPECT_EQ(1U, cl_from_string.argv().size());
+  EXPECT_TRUE(cl_from_string.GetArgs().empty());
+#endif
+  CommandLine cl_from_argv(0, NULL);
+  EXPECT_TRUE(cl_from_argv.GetCommandLineString().empty());
+  EXPECT_TRUE(cl_from_argv.GetProgram().empty());
+  EXPECT_EQ(1U, cl_from_argv.argv().size());
+  EXPECT_TRUE(cl_from_argv.GetArgs().empty());
+}
+
+TEST(CommandLineTest, GetArgumentsString) {
+  static const FilePath::CharType kPath1[] =
+      FILE_PATH_LITERAL("C:\\Some File\\With Spaces.ggg");
+  static const FilePath::CharType kPath2[] =
+      FILE_PATH_LITERAL("C:\\no\\spaces.ggg");
+
+  static const char kFirstArgName[] = "first-arg";
+  static const char kSecondArgName[] = "arg2";
+  static const char kThirdArgName[] = "arg with space";
+  static const char kFourthArgName[] = "nospace";
+  static const char kFifthArgName[] = "%1";
+
+  CommandLine cl(CommandLine::NO_PROGRAM);
+  cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1));
+  cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2));
+  cl.AppendArg(kThirdArgName);
+  cl.AppendArg(kFourthArgName);
+  cl.AppendArg(kFifthArgName);
+
+#if defined(OS_WIN)
+  CommandLine::StringType expected_first_arg(UTF8ToUTF16(kFirstArgName));
+  CommandLine::StringType expected_second_arg(UTF8ToUTF16(kSecondArgName));
+  CommandLine::StringType expected_third_arg(UTF8ToUTF16(kThirdArgName));
+  CommandLine::StringType expected_fourth_arg(UTF8ToUTF16(kFourthArgName));
+  CommandLine::StringType expected_fifth_arg(UTF8ToUTF16(kFifthArgName));
+#elif defined(OS_POSIX)
+  CommandLine::StringType expected_first_arg(kFirstArgName);
+  CommandLine::StringType expected_second_arg(kSecondArgName);
+  CommandLine::StringType expected_third_arg(kThirdArgName);
+  CommandLine::StringType expected_fourth_arg(kFourthArgName);
+  CommandLine::StringType expected_fifth_arg(kFifthArgName);
+#endif
+
+#if defined(OS_WIN)
+#define QUOTE_ON_WIN FILE_PATH_LITERAL("\"")
+#else
+#define QUOTE_ON_WIN FILE_PATH_LITERAL("")
+#endif  // OS_WIN
+
+  CommandLine::StringType expected_str;
+  expected_str.append(FILE_PATH_LITERAL("--"))
+              .append(expected_first_arg)
+              .append(FILE_PATH_LITERAL("="))
+              .append(QUOTE_ON_WIN)
+              .append(kPath1)
+              .append(QUOTE_ON_WIN)
+              .append(FILE_PATH_LITERAL(" "))
+              .append(FILE_PATH_LITERAL("--"))
+              .append(expected_second_arg)
+              .append(FILE_PATH_LITERAL("="))
+              .append(QUOTE_ON_WIN)
+              .append(kPath2)
+              .append(QUOTE_ON_WIN)
+              .append(FILE_PATH_LITERAL(" "))
+              .append(QUOTE_ON_WIN)
+              .append(expected_third_arg)
+              .append(QUOTE_ON_WIN)
+              .append(FILE_PATH_LITERAL(" "))
+              .append(expected_fourth_arg)
+              .append(FILE_PATH_LITERAL(" "));
+
+  CommandLine::StringType expected_str_no_quote_placeholders(expected_str);
+  expected_str_no_quote_placeholders.append(expected_fifth_arg);
+  EXPECT_EQ(expected_str_no_quote_placeholders, cl.GetArgumentsString());
+
+#if defined(OS_WIN)
+  CommandLine::StringType expected_str_quote_placeholders(expected_str);
+  expected_str_quote_placeholders.append(QUOTE_ON_WIN)
+                                 .append(expected_fifth_arg)
+                                 .append(QUOTE_ON_WIN);
+  EXPECT_EQ(expected_str_quote_placeholders,
+            cl.GetArgumentsStringWithPlaceholders());
+#endif
+}
+
+// Test methods for appending switches to a command line.
+TEST(CommandLineTest, AppendSwitches) {
+  std::string switch1 = "switch1";
+  std::string switch2 = "switch2";
+  std::string value2 = "value";
+  std::string switch3 = "switch3";
+  std::string value3 = "a value with spaces";
+  std::string switch4 = "switch4";
+  std::string value4 = "\"a value with quotes\"";
+  std::string switch5 = "quotes";
+  CommandLine::StringType value5 = kTricky;
+
+  CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
+
+  cl.AppendSwitch(switch1);
+  cl.AppendSwitchASCII(switch2, value2);
+  cl.AppendSwitchASCII(switch3, value3);
+  cl.AppendSwitchASCII(switch4, value4);
+  cl.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());
+  EXPECT_EQ(L"\"Program Path\"", cmd_string);
+
+  // Check the optional quoting of placeholders in programs.
+  CommandLine cl_quote_placeholder(FilePath(L"%1"));
+  EXPECT_EQ(L"%1", cl_quote_placeholder.GetCommandLineString());
+  EXPECT_EQ(L"\"%1\"",
+            cl_quote_placeholder.GetCommandLineStringWithPlaceholders());
+}
+#endif
+
+// Calling Init multiple times should not modify the previous CommandLine.
+TEST(CommandLineTest, Init) {
+  CommandLine* initial = CommandLine::ForCurrentProcess();
+  EXPECT_FALSE(CommandLine::Init(0, NULL));
+  CommandLine* current = CommandLine::ForCurrentProcess();
+  EXPECT_EQ(initial, current);
+}
+
+} // namespace base
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
new file mode 100644
index 0000000..63297dc
--- /dev/null
+++ b/base/compiler_specific.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+
+// Macros for suppressing and disabling warnings on MSVC.
+//
+// Warning numbers are enumerated at:
+// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
+//
+// The warning pragma:
+// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
+//
+// Using __pragma instead of #pragma inside macros:
+// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
+
+// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and
+// for the next line of the source file.
+#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n))
+
+// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
+// The warning remains disabled until popped by MSVC_POP_WARNING.
+#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
+                                     __pragma(warning(disable:n))
+
+// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level.  The level
+// remains in effect until popped by MSVC_POP_WARNING().  Use 0 to disable all
+// warnings.
+#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
+
+// Pop effects of innermost MSVC_PUSH_* macro.
+#define MSVC_POP_WARNING() __pragma(warning(pop))
+
+#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off))
+#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on))
+
+// Allows exporting a class that inherits from a non-exported base class.
+// This uses suppress instead of push/pop because the delimiter after the
+// declaration (either "," or "{") has to be placed before the pop macro.
+//
+// Example usage:
+// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) {
+//
+// MSVC Compiler warning C4275:
+// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
+// Note that this is intended to be used only when no access to the base class'
+// static data is done through derived classes or inline methods. For more info,
+// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \
+                                code
+
+#else  // Not MSVC
+
+#define MSVC_SUPPRESS_WARNING(n)
+#define MSVC_PUSH_DISABLE_WARNING(n)
+#define MSVC_PUSH_WARNING_LEVEL(n)
+#define MSVC_POP_WARNING()
+#define MSVC_DISABLE_OPTIMIZE()
+#define MSVC_ENABLE_OPTIMIZE()
+#define NON_EXPORTED_BASE(code) code
+
+#endif  // COMPILER_MSVC
+
+
+// The C++ standard requires that static const members have an out-of-class
+// definition (in a single compilation unit), but MSVC chokes on this (when
+// language extensions, which are required, are enabled). (You're only likely to
+// notice the need for a definition if you take the address of the member or,
+// more commonly, pass it to a function that takes it as a reference argument --
+// probably an STL function.) This macro makes MSVC do the right thing. See
+// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
+// information. Use like:
+//
+// In .h file:
+//   struct Foo {
+//     static const int kBar = 5;
+//   };
+//
+// In .cc file:
+//   STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
+#if defined(COMPILER_MSVC)
+#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
+#else
+#define STATIC_CONST_MEMBER_DEFINITION
+#endif
+
+// Annotate a variable indicating it's ok if the variable is not used.
+// (Typically used to silence a compiler warning when the assignment
+// is important for some other reason.)
+// Use like:
+//   int x = ...;
+//   ALLOW_UNUSED_LOCAL(x);
+#define ALLOW_UNUSED_LOCAL(x) false ? (void)x : (void)0
+
+// Annotate a typedef or function indicating it's ok if it's not used.
+// Use like:
+//   typedef Foo Bar ALLOW_UNUSED_TYPE;
+#if defined(COMPILER_GCC)
+#define ALLOW_UNUSED_TYPE __attribute__((unused))
+#else
+#define ALLOW_UNUSED_TYPE
+#endif
+
+// Annotate a function indicating it should not be inlined.
+// Use like:
+//   NOINLINE void DoStuff() { ... }
+#if defined(COMPILER_GCC)
+#define NOINLINE __attribute__((noinline))
+#elif defined(COMPILER_MSVC)
+#define NOINLINE __declspec(noinline)
+#else
+#define NOINLINE
+#endif
+
+// Specify memory alignment for structs, classes, etc.
+// Use like:
+//   class ALIGNAS(16) MyClass { ... }
+//   ALIGNAS(16) int array[4];
+#if defined(COMPILER_MSVC)
+#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#elif defined(COMPILER_GCC)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#endif
+
+// Return the byte alignment of the given type (available at compile time).
+// Use like:
+//   ALIGNOF(int32)  // this would be 4
+#if defined(COMPILER_MSVC)
+#define ALIGNOF(type) __alignof(type)
+#elif defined(COMPILER_GCC)
+#define ALIGNOF(type) __alignof__(type)
+#endif
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+#if defined(COMPILER_GCC)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+
+// Tell the compiler a function is using a printf-style format string.
+// |format_param| is the one-based index of the format string parameter;
+// |dots_param| is the one-based index of the "..." parameter.
+// For v*printf functions (which take a va_list), pass 0 for dots_param.
+// (This is undocumented but matches what the system C headers do.)
+#if defined(COMPILER_GCC)
+#define PRINTF_FORMAT(format_param, dots_param) \
+    __attribute__((format(printf, format_param, dots_param)))
+#else
+#define PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// WPRINTF_FORMAT is the same, but for wide format strings.
+// This doesn't appear to yet be implemented in any compiler.
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
+#define WPRINTF_FORMAT(format_param, dots_param)
+// If available, it would look like:
+//   __attribute__((format(wprintf, format_param, dots_param)))
+
+// MemorySanitizer annotations.
+#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
+#include <sanitizer/msan_interface.h>
+
+// Mark a memory region fully initialized.
+// Use this to annotate code that deliberately reads uninitialized data, for
+// example a GC scavenging root set pointers from the stack.
+#define MSAN_UNPOISON(p, size)  __msan_unpoison(p, size)
+
+// Check a memory region for initializedness, as if it was being used here.
+// If any bits are uninitialized, crash with an MSan report.
+// Use this to sanitize data which MSan won't be able to track, e.g. before
+// passing data to another process via shared memory.
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
+    __msan_check_mem_is_initialized(p, size)
+#else  // MEMORY_SANITIZER
+#define MSAN_UNPOISON(p, size)
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
+#endif  // MEMORY_SANITIZER
+
+// Macro useful for writing cross-platform function pointers.
+#if !defined(CDECL)
+#if defined(OS_WIN)
+#define CDECL __cdecl
+#else  // defined(OS_WIN)
+#define CDECL
+#endif  // defined(OS_WIN)
+#endif  // !defined(CDECL)
+
+// Macro for hinting that an expression is likely to be false.
+#if !defined(UNLIKELY)
+#if defined(COMPILER_GCC)
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define UNLIKELY(x) (x)
+#endif  // defined(COMPILER_GCC)
+#endif  // !defined(UNLIKELY)
+
+#endif  // BASE_COMPILER_SPECIFIC_H_
diff --git a/base/containers/adapters.h b/base/containers/adapters.h
new file mode 100644
index 0000000..cc151fc
--- /dev/null
+++ b/base/containers/adapters.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_ADAPTERS_H_
+#define BASE_CONTAINERS_ADAPTERS_H_
+
+#include "base/macros.h"
+
+namespace base {
+
+namespace internal {
+
+// Internal adapter class for implementing base::Reversed.
+template <typename T>
+class ReversedAdapter {
+ public:
+  typedef decltype(static_cast<T*>(nullptr)->rbegin()) Iterator;
+
+  explicit ReversedAdapter(T& t) : t_(t) {}
+  ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+  Iterator begin() const { return t_.rbegin(); }
+  Iterator end() const { return t_.rend(); }
+
+ private:
+  T& t_;
+
+  DISALLOW_ASSIGN(ReversedAdapter);
+};
+
+}  // namespace internal
+
+// Reversed returns a container adapter usable in a range-based "for" statement
+// for iterating a reversible container in reverse order.
+//
+// Example:
+//
+//   std::vector<int> v = ...;
+//   for (int i : base::Reversed(v)) {
+//     // iterates through v from back to front
+//   }
+template <typename T>
+internal::ReversedAdapter<T> Reversed(T& t) {
+  return internal::ReversedAdapter<T>(t);
+}
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_ADAPTERS_H_
diff --git a/base/containers/adapters_unittest.cc b/base/containers/adapters_unittest.cc
new file mode 100644
index 0000000..4c87472
--- /dev/null
+++ b/base/containers/adapters_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/adapters.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(AdaptersTest, Reversed) {
+  std::vector<int> v;
+  v.push_back(3);
+  v.push_back(2);
+  v.push_back(1);
+  int j = 0;
+  for (int& i : base::Reversed(v)) {
+    EXPECT_EQ(++j, i);
+    i += 100;
+  }
+  EXPECT_EQ(103, v[0]);
+  EXPECT_EQ(102, v[1]);
+  EXPECT_EQ(101, v[2]);
+}
+
+TEST(AdaptersTest, ConstReversed) {
+  std::vector<int> v;
+  v.push_back(3);
+  v.push_back(2);
+  v.push_back(1);
+  const std::vector<int>& cv = v;
+  int j = 0;
+  for (int i : base::Reversed(cv)) {
+    EXPECT_EQ(++j, i);
+  }
+}
+
+}  // namespace
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
new file mode 100644
index 0000000..5ce9161
--- /dev/null
+++ b/base/containers/hash_tables.h
@@ -0,0 +1,320 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Deal with the differences between Microsoft and GNU implemenations
+// of hash_map. Allows all platforms to use |base::hash_map| and
+// |base::hash_set|.
+//  eg:
+//   base::hash_map<int> my_map;
+//   base::hash_set<int> my_set;
+//
+// NOTE: It is an explicit non-goal of this class to provide a generic hash
+// function for pointers.  If you want to hash a pointers to a particular class,
+// please define the template specialization elsewhere (for example, in its
+// header file) and keep it specific to just pointers to that class.  This is
+// because identity hashes are not desirable for all types that might show up
+// in containers as pointers.
+
+#ifndef BASE_CONTAINERS_HASH_TABLES_H_
+#define BASE_CONTAINERS_HASH_TABLES_H_
+
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <unordered_map>
+#include <unordered_set>
+
+#define BASE_HASH_NAMESPACE std
+
+#elif defined(COMPILER_GCC)
+
+#define BASE_HASH_NAMESPACE base_hash
+
+// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
+// being deprecated.  We can get rid of this when we upgrade to VS2008 and we
+// can use <tr1/unordered_map> and <tr1/unordered_set>.
+#ifdef __DEPRECATED
+#define CHROME_OLD__DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#endif
+
+#include <ext/hash_map>
+#include <ext/hash_set>
+#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
+
+#include <string>
+
+#ifdef CHROME_OLD__DEPRECATED
+#define __DEPRECATED CHROME_OLD__DEPRECATED
+#undef CHROME_OLD__DEPRECATED
+#endif
+
+namespace BASE_HASH_NAMESPACE {
+
+// The pre-standard hash behaves like C++11's std::hash, except around pointers.
+// const char* is specialized to hash the C string and hash functions for
+// general T* are missing. Define a BASE_HASH_NAMESPACE::hash which aligns with
+// the C++11 behavior.
+
+template<typename T>
+struct hash {
+  std::size_t operator()(const T& value) const {
+    return BASE_HASH_IMPL_NAMESPACE::hash<T>()(value);
+  }
+};
+
+template<typename T>
+struct hash<T*> {
+  std::size_t operator()(T* value) const {
+    return BASE_HASH_IMPL_NAMESPACE::hash<uintptr_t>()(
+        reinterpret_cast<uintptr_t>(value));
+  }
+};
+
+// The GNU C++ library provides identity hash functions for many integral types,
+// but not for |long long|.  This hash function will truncate if |size_t| is
+// narrower than |long long|.  This is probably good enough for what we will
+// use it for.
+
+#define DEFINE_TRIVIAL_HASH(integral_type) \
+    template<> \
+    struct hash<integral_type> { \
+      std::size_t operator()(integral_type value) const { \
+        return static_cast<std::size_t>(value); \
+      } \
+    }
+
+DEFINE_TRIVIAL_HASH(long long);
+DEFINE_TRIVIAL_HASH(unsigned long long);
+
+#undef DEFINE_TRIVIAL_HASH
+
+// Implement string hash functions so that strings of various flavors can
+// be used as keys in STL maps and sets.  The hash algorithm comes from the
+// GNU C++ library, in <tr1/functional>.  It is duplicated here because GCC
+// versions prior to 4.3.2 are unable to compile <tr1/functional> when RTTI
+// is disabled, as it is in our build.
+
+#define DEFINE_STRING_HASH(string_type) \
+    template<> \
+    struct hash<string_type> { \
+      std::size_t operator()(const string_type& s) const { \
+        std::size_t result = 0; \
+        for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \
+          result = (result * 131) + *i; \
+        return result; \
+      } \
+    }
+
+DEFINE_STRING_HASH(std::string);
+DEFINE_STRING_HASH(base::string16);
+
+#undef DEFINE_STRING_HASH
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#else  // COMPILER
+#error define BASE_HASH_NAMESPACE for your compiler
+#endif  // COMPILER
+
+namespace base {
+
+// On MSVC, use the C++11 containers.
+#if defined(COMPILER_MSVC)
+
+template<class Key, class T,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_map = std::unordered_map<Key, T, Hash, Pred, Alloc>;
+
+template<class Key, class T,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_multimap = std::unordered_multimap<Key, T, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_multiset = std::unordered_multiset<Key, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_set = std::unordered_set<Key, Hash, Pred, Alloc>;
+
+#else  // !COMPILER_MSVC
+
+// Otherwise, use the pre-standard ones, but override the default hash to match
+// C++11.
+template<class Key, class T,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_map = BASE_HASH_IMPL_NAMESPACE::hash_map<Key, T, Hash, Pred, Alloc>;
+
+template<class Key, class T,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_multimap =
+    BASE_HASH_IMPL_NAMESPACE::hash_multimap<Key, T, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_multiset =
+    BASE_HASH_IMPL_NAMESPACE::hash_multiset<Key, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
+
+#undef BASE_HASH_IMPL_NAMESPACE
+
+#endif  // COMPILER_MSVC
+
+// Implement hashing for pairs of at-most 32 bit integer values.
+// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
+// multiply-add hashing. This algorithm, as described in
+// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in
+// eingeschränkten Branchingprogrammmodellen" by Woelfel, is:
+//
+//   h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
+//
+// Contact danakj@chromium.org for any questions.
+inline std::size_t HashInts32(uint32 value1, uint32 value2) {
+  uint64 value1_64 = value1;
+  uint64 hash64 = (value1_64 << 32) | value2;
+
+  if (sizeof(std::size_t) >= sizeof(uint64))
+    return static_cast<std::size_t>(hash64);
+
+  uint64 odd_random = 481046412LL << 32 | 1025306955LL;
+  uint32 shift_random = 10121U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  std::size_t high_bits = static_cast<std::size_t>(
+      hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+  return high_bits;
+}
+
+// Implement hashing for pairs of up-to 64-bit integer values.
+// We use the compound integer hash method to produce a 64-bit hash code, by
+// breaking the two 64-bit inputs into 4 32-bit values:
+// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
+// Then we reduce our result to 32 bits if required, similar to above.
+inline std::size_t HashInts64(uint64 value1, uint64 value2) {
+  uint32 short_random1 = 842304669U;
+  uint32 short_random2 = 619063811U;
+  uint32 short_random3 = 937041849U;
+  uint32 short_random4 = 3309708029U;
+
+  uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
+  uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
+  uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
+  uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
+
+  uint64 product1 = static_cast<uint64>(value1a) * short_random1;
+  uint64 product2 = static_cast<uint64>(value1b) * short_random2;
+  uint64 product3 = static_cast<uint64>(value2a) * short_random3;
+  uint64 product4 = static_cast<uint64>(value2b) * short_random4;
+
+  uint64 hash64 = product1 + product2 + product3 + product4;
+
+  if (sizeof(std::size_t) >= sizeof(uint64))
+    return static_cast<std::size_t>(hash64);
+
+  uint64 odd_random = 1578233944LL << 32 | 194370989LL;
+  uint32 shift_random = 20591U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  std::size_t high_bits = static_cast<std::size_t>(
+      hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+  return high_bits;
+}
+
+#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
+inline std::size_t HashPair(Type1 value1, Type2 value2) { \
+  return HashInts32(value1, value2); \
+}
+
+DEFINE_32BIT_PAIR_HASH(int16, int16);
+DEFINE_32BIT_PAIR_HASH(int16, uint16);
+DEFINE_32BIT_PAIR_HASH(int16, int32);
+DEFINE_32BIT_PAIR_HASH(int16, uint32);
+DEFINE_32BIT_PAIR_HASH(uint16, int16);
+DEFINE_32BIT_PAIR_HASH(uint16, uint16);
+DEFINE_32BIT_PAIR_HASH(uint16, int32);
+DEFINE_32BIT_PAIR_HASH(uint16, uint32);
+DEFINE_32BIT_PAIR_HASH(int32, int16);
+DEFINE_32BIT_PAIR_HASH(int32, uint16);
+DEFINE_32BIT_PAIR_HASH(int32, int32);
+DEFINE_32BIT_PAIR_HASH(int32, uint32);
+DEFINE_32BIT_PAIR_HASH(uint32, int16);
+DEFINE_32BIT_PAIR_HASH(uint32, uint16);
+DEFINE_32BIT_PAIR_HASH(uint32, int32);
+DEFINE_32BIT_PAIR_HASH(uint32, uint32);
+
+#undef DEFINE_32BIT_PAIR_HASH
+
+#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
+inline std::size_t HashPair(Type1 value1, Type2 value2) { \
+  return HashInts64(value1, value2); \
+}
+
+DEFINE_64BIT_PAIR_HASH(int16, int64);
+DEFINE_64BIT_PAIR_HASH(int16, uint64);
+DEFINE_64BIT_PAIR_HASH(uint16, int64);
+DEFINE_64BIT_PAIR_HASH(uint16, uint64);
+DEFINE_64BIT_PAIR_HASH(int32, int64);
+DEFINE_64BIT_PAIR_HASH(int32, uint64);
+DEFINE_64BIT_PAIR_HASH(uint32, int64);
+DEFINE_64BIT_PAIR_HASH(uint32, uint64);
+DEFINE_64BIT_PAIR_HASH(int64, int16);
+DEFINE_64BIT_PAIR_HASH(int64, uint16);
+DEFINE_64BIT_PAIR_HASH(int64, int32);
+DEFINE_64BIT_PAIR_HASH(int64, uint32);
+DEFINE_64BIT_PAIR_HASH(int64, int64);
+DEFINE_64BIT_PAIR_HASH(int64, uint64);
+DEFINE_64BIT_PAIR_HASH(uint64, int16);
+DEFINE_64BIT_PAIR_HASH(uint64, uint16);
+DEFINE_64BIT_PAIR_HASH(uint64, int32);
+DEFINE_64BIT_PAIR_HASH(uint64, uint32);
+DEFINE_64BIT_PAIR_HASH(uint64, int64);
+DEFINE_64BIT_PAIR_HASH(uint64, uint64);
+
+#undef DEFINE_64BIT_PAIR_HASH
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+// Implement methods for hashing a pair of integers, so they can be used as
+// keys in STL containers.
+
+template<typename Type1, typename Type2>
+struct hash<std::pair<Type1, Type2> > {
+  std::size_t operator()(std::pair<Type1, Type2> value) const {
+    return base::HashPair(value.first, value.second);
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#undef DEFINE_PAIR_HASH_FUNCTION_START
+#undef DEFINE_PAIR_HASH_FUNCTION_END
+
+#endif  // BASE_CONTAINERS_HASH_TABLES_H_
diff --git a/base/containers/hash_tables_unittest.cc b/base/containers/hash_tables_unittest.cc
new file mode 100644
index 0000000..60fbeaa
--- /dev/null
+++ b/base/containers/hash_tables_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/hash_tables.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class HashPairTest : public testing::Test {
+};
+
+#define INSERT_PAIR_TEST(Type, value1, value2) \
+  { \
+    Type pair(value1, value2); \
+    base::hash_map<Type, int> map; \
+    map[pair] = 1; \
+  }
+
+// Verify that a hash_map can be constructed for pairs of integers of various
+// sizes.
+TEST_F(HashPairTest, IntegerPairs) {
+  typedef std::pair<int16, int16> Int16Int16Pair;
+  typedef std::pair<int16, int32> Int16Int32Pair;
+  typedef std::pair<int16, int64> Int16Int64Pair;
+
+  INSERT_PAIR_TEST(Int16Int16Pair, 4, 6);
+  INSERT_PAIR_TEST(Int16Int32Pair, 9, (1 << 29) + 378128932);
+  INSERT_PAIR_TEST(Int16Int64Pair, 10,
+                   (GG_INT64_C(1) << 60) + GG_INT64_C(78931732321));
+
+  typedef std::pair<int32, int16> Int32Int16Pair;
+  typedef std::pair<int32, int32> Int32Int32Pair;
+  typedef std::pair<int32, int64> Int32Int64Pair;
+
+  INSERT_PAIR_TEST(Int32Int16Pair, 4, 6);
+  INSERT_PAIR_TEST(Int32Int32Pair, 9, (1 << 29) + 378128932);
+  INSERT_PAIR_TEST(Int32Int64Pair, 10,
+                   (GG_INT64_C(1) << 60) + GG_INT64_C(78931732321));
+
+  typedef std::pair<int64, int16> Int64Int16Pair;
+  typedef std::pair<int64, int32> Int64Int32Pair;
+  typedef std::pair<int64, int64> Int64Int64Pair;
+
+  INSERT_PAIR_TEST(Int64Int16Pair, 4, 6);
+  INSERT_PAIR_TEST(Int64Int32Pair, 9, (1 << 29) + 378128932);
+  INSERT_PAIR_TEST(Int64Int64Pair, 10,
+                   (GG_INT64_C(1) << 60) + GG_INT64_C(78931732321));
+}
+
+// Verify that base::hash_set<const char*> compares by pointer value, not as C
+// strings.
+TEST(HashTableTest, CharPointers) {
+  std::string str1("hello");
+  std::string str2("hello");
+  base::hash_set<const char*> set;
+
+  set.insert(str1.c_str());
+  EXPECT_EQ(1u, set.count(str1.c_str()));
+  EXPECT_EQ(0u, set.count(str2.c_str()));
+}
+
+}  // namespace
diff --git a/base/containers/linked_list.h b/base/containers/linked_list.h
new file mode 100644
index 0000000..41461ff
--- /dev/null
+++ b/base/containers/linked_list.h
@@ -0,0 +1,176 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_LINKED_LIST_H_
+#define BASE_CONTAINERS_LINKED_LIST_H_
+
+#include "base/macros.h"
+
+// Simple LinkedList type. (See the Q&A section to understand how this
+// differs from std::list).
+//
+// To use, start by declaring the class which will be contained in the linked
+// list, as extending LinkNode (this gives it next/previous pointers).
+//
+//   class MyNodeType : public LinkNode<MyNodeType> {
+//     ...
+//   };
+//
+// Next, to keep track of the list's head/tail, use a LinkedList instance:
+//
+//   LinkedList<MyNodeType> list;
+//
+// To add elements to the list, use any of LinkedList::Append,
+// LinkNode::InsertBefore, or LinkNode::InsertAfter:
+//
+//   LinkNode<MyNodeType>* n1 = ...;
+//   LinkNode<MyNodeType>* n2 = ...;
+//   LinkNode<MyNodeType>* n3 = ...;
+//
+//   list.Append(n1);
+//   list.Append(n3);
+//   n3->InsertBefore(n3);
+//
+// Lastly, to iterate through the linked list forwards:
+//
+//   for (LinkNode<MyNodeType>* node = list.head();
+//        node != list.end();
+//        node = node->next()) {
+//     MyNodeType* value = node->value();
+//     ...
+//   }
+//
+// Or to iterate the linked list backwards:
+//
+//   for (LinkNode<MyNodeType>* node = list.tail();
+//        node != list.end();
+//        node = node->previous()) {
+//     MyNodeType* value = node->value();
+//     ...
+//   }
+//
+// Questions and Answers:
+//
+// Q. Should I use std::list or base::LinkedList?
+//
+// A. The main reason to use base::LinkedList over std::list is
+//    performance. If you don't care about the performance differences
+//    then use an STL container, as it makes for better code readability.
+//
+//    Comparing the performance of base::LinkedList<T> to std::list<T*>:
+//
+//    * Erasing an element of type T* from base::LinkedList<T> is
+//      an O(1) operation. Whereas for std::list<T*> it is O(n).
+//      That is because with std::list<T*> you must obtain an
+//      iterator to the T* element before you can call erase(iterator).
+//
+//    * Insertion operations with base::LinkedList<T> never require
+//      heap allocations.
+//
+// Q. How does base::LinkedList implementation differ from std::list?
+//
+// A. Doubly-linked lists are made up of nodes that contain "next" and
+//    "previous" pointers that reference other nodes in the list.
+//
+//    With base::LinkedList<T>, the type being inserted already reserves
+//    space for the "next" and "previous" pointers (base::LinkNode<T>*).
+//    Whereas with std::list<T> the type can be anything, so the implementation
+//    needs to glue on the "next" and "previous" pointers using
+//    some internal node type.
+
+namespace base {
+
+template <typename T>
+class LinkNode {
+ public:
+  LinkNode() : previous_(NULL), next_(NULL) {}
+  LinkNode(LinkNode<T>* previous, LinkNode<T>* next)
+      : previous_(previous), next_(next) {}
+
+  // Insert |this| into the linked list, before |e|.
+  void InsertBefore(LinkNode<T>* e) {
+    this->next_ = e;
+    this->previous_ = e->previous_;
+    e->previous_->next_ = this;
+    e->previous_ = this;
+  }
+
+  // Insert |this| into the linked list, after |e|.
+  void InsertAfter(LinkNode<T>* e) {
+    this->next_ = e->next_;
+    this->previous_ = e;
+    e->next_->previous_ = this;
+    e->next_ = this;
+  }
+
+  // Remove |this| from the linked list.
+  void RemoveFromList() {
+    this->previous_->next_ = this->next_;
+    this->next_->previous_ = this->previous_;
+    // next() and previous() return non-NULL if and only this node is not in any
+    // list.
+    this->next_ = NULL;
+    this->previous_ = NULL;
+  }
+
+  LinkNode<T>* previous() const {
+    return previous_;
+  }
+
+  LinkNode<T>* next() const {
+    return next_;
+  }
+
+  // Cast from the node-type to the value type.
+  const T* value() const {
+    return static_cast<const T*>(this);
+  }
+
+  T* value() {
+    return static_cast<T*>(this);
+  }
+
+ private:
+  LinkNode<T>* previous_;
+  LinkNode<T>* next_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinkNode);
+};
+
+template <typename T>
+class LinkedList {
+ public:
+  // The "root" node is self-referential, and forms the basis of a circular
+  // list (root_.next() will point back to the start of the list,
+  // and root_->previous() wraps around to the end of the list).
+  LinkedList() : root_(&root_, &root_) {}
+
+  // Appends |e| to the end of the linked list.
+  void Append(LinkNode<T>* e) {
+    e->InsertBefore(&root_);
+  }
+
+  LinkNode<T>* head() const {
+    return root_.next();
+  }
+
+  LinkNode<T>* tail() const {
+    return root_.previous();
+  }
+
+  const LinkNode<T>* end() const {
+    return &root_;
+  }
+
+  bool empty() const { return head() == end(); }
+
+ private:
+  LinkNode<T> root_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinkedList);
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_LINKED_LIST_H_
diff --git a/base/containers/linked_list_unittest.cc b/base/containers/linked_list_unittest.cc
new file mode 100644
index 0000000..93a9f38
--- /dev/null
+++ b/base/containers/linked_list_unittest.cc
@@ -0,0 +1,308 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/containers/linked_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Node : public LinkNode<Node> {
+ public:
+  explicit Node(int id) : id_(id) {}
+
+  int id() const { return id_; }
+
+ private:
+  int id_;
+};
+
+class MultipleInheritanceNodeBase {
+ public:
+  MultipleInheritanceNodeBase() : field_taking_up_space_(0) {}
+  int field_taking_up_space_;
+};
+
+class MultipleInheritanceNode : public MultipleInheritanceNodeBase,
+                                public LinkNode<MultipleInheritanceNode> {
+ public:
+  MultipleInheritanceNode() {}
+};
+
+// Checks that when iterating |list| (either from head to tail, or from
+// tail to head, as determined by |forward|), we get back |node_ids|,
+// which is an array of size |num_nodes|.
+void ExpectListContentsForDirection(const LinkedList<Node>& list,
+  int num_nodes, const int* node_ids, bool forward) {
+  int i = 0;
+  for (const LinkNode<Node>* node = (forward ? list.head() : list.tail());
+       node != list.end();
+       node = (forward ? node->next() : node->previous())) {
+    ASSERT_LT(i, num_nodes);
+    int index_of_id = forward ? i : num_nodes - i - 1;
+    EXPECT_EQ(node_ids[index_of_id], node->value()->id());
+    ++i;
+  }
+  EXPECT_EQ(num_nodes, i);
+}
+
+void ExpectListContents(const LinkedList<Node>& list,
+                        int num_nodes,
+                        const int* node_ids) {
+  {
+    SCOPED_TRACE("Iterating forward (from head to tail)");
+    ExpectListContentsForDirection(list, num_nodes, node_ids, true);
+  }
+  {
+    SCOPED_TRACE("Iterating backward (from tail to head)");
+    ExpectListContentsForDirection(list, num_nodes, node_ids, false);
+  }
+}
+
+TEST(LinkedList, Empty) {
+  LinkedList<Node> list;
+  EXPECT_EQ(list.end(), list.head());
+  EXPECT_EQ(list.end(), list.tail());
+  ExpectListContents(list, 0, NULL);
+}
+
+TEST(LinkedList, Append) {
+  LinkedList<Node> list;
+  ExpectListContents(list, 0, NULL);
+
+  Node n1(1);
+  list.Append(&n1);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n1, list.tail());
+  {
+    const int expected[] = {1};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  Node n2(2);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  Node n3(3);
+  list.Append(&n3);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, RemoveFromList) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+  Node n5(5);
+
+  list.Append(&n1);
+  list.Append(&n2);
+  list.Append(&n3);
+  list.Append(&n4);
+  list.Append(&n5);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 3, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the middle.
+  n3.RemoveFromList();
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the tail.
+  n5.RemoveFromList();
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n4, list.tail());
+  {
+    const int expected[] = {1, 2, 4};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the head.
+  n1.RemoveFromList();
+
+  EXPECT_EQ(&n2, list.head());
+  EXPECT_EQ(&n4, list.tail());
+  {
+    const int expected[] = {2, 4};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Empty the list.
+  n2.RemoveFromList();
+  n4.RemoveFromList();
+
+  ExpectListContents(list, 0, NULL);
+  EXPECT_EQ(list.end(), list.head());
+  EXPECT_EQ(list.end(), list.tail());
+
+  // Fill the list once again.
+  list.Append(&n1);
+  list.Append(&n2);
+  list.Append(&n3);
+  list.Append(&n4);
+  list.Append(&n5);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 3, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, InsertBefore) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+
+  list.Append(&n1);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n3.InsertBefore(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 3, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n4.InsertBefore(&n1);
+
+  EXPECT_EQ(&n4, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {4, 1, 3, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, InsertAfter) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+
+  list.Append(&n1);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n3.InsertAfter(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n4.InsertAfter(&n1);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 4, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, MultipleInheritanceNode) {
+  MultipleInheritanceNode node;
+  EXPECT_EQ(&node, node.value());
+}
+
+TEST(LinkedList, EmptyListIsEmpty) {
+  LinkedList<Node> list;
+  EXPECT_TRUE(list.empty());
+}
+
+TEST(LinkedList, NonEmptyListIsNotEmpty) {
+  LinkedList<Node> list;
+
+  Node n(1);
+  list.Append(&n);
+
+  EXPECT_FALSE(list.empty());
+}
+
+TEST(LinkedList, EmptiedListIsEmptyAgain) {
+  LinkedList<Node> list;
+
+  Node n(1);
+  list.Append(&n);
+  n.RemoveFromList();
+
+  EXPECT_TRUE(list.empty());
+}
+
+TEST(LinkedList, NodesCanBeReused) {
+  LinkedList<Node> list1;
+  LinkedList<Node> list2;
+
+  Node n(1);
+  list1.Append(&n);
+  n.RemoveFromList();
+  list2.Append(&n);
+
+  EXPECT_EQ(list2.head()->value(), &n);
+}
+
+TEST(LinkedList, RemovedNodeHasNullNextPrevious) {
+  LinkedList<Node> list;
+
+  Node n(1);
+  list.Append(&n);
+  n.RemoveFromList();
+
+  EXPECT_EQ(NULL, n.next());
+  EXPECT_EQ(NULL, n.previous());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/containers/mru_cache.h b/base/containers/mru_cache.h
new file mode 100644
index 0000000..ed1ad25
--- /dev/null
+++ b/base/containers/mru_cache.h
@@ -0,0 +1,307 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains a template for a Most Recently Used cache that allows
+// constant-time access to items using a key, but easy identification of the
+// least-recently-used items for removal.  Each key can only be associated with
+// one payload item at a time.
+//
+// The key object will be stored twice, so it should support efficient copying.
+//
+// NOTE: While all operations are O(1), this code is written for
+// legibility rather than optimality. If future profiling identifies this as
+// a bottleneck, there is room for smaller values of 1 in the O(1). :]
+
+#ifndef BASE_CONTAINERS_MRU_CACHE_H_
+#define BASE_CONTAINERS_MRU_CACHE_H_
+
+#include <list>
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+
+namespace base {
+
+// MRUCacheBase ----------------------------------------------------------------
+
+// This template is used to standardize map type containers that can be used
+// by MRUCacheBase. This level of indirection is necessary because of the way
+// that template template params and default template params interact.
+template <class KeyType, class ValueType>
+struct MRUCacheStandardMap {
+  typedef std::map<KeyType, ValueType> Type;
+};
+
+// Base class for the MRU cache specializations defined below.
+// The deletor will get called on all payloads that are being removed or
+// replaced.
+template <class KeyType, class PayloadType, class DeletorType,
+          template <typename, typename> class MapType = MRUCacheStandardMap>
+class MRUCacheBase {
+ public:
+  // The payload of the list. This maintains a copy of the key so we can
+  // efficiently delete things given an element of the list.
+  typedef std::pair<KeyType, PayloadType> value_type;
+
+ private:
+  typedef std::list<value_type> PayloadList;
+  typedef typename MapType<KeyType,
+                           typename PayloadList::iterator>::Type KeyIndex;
+
+ public:
+  typedef typename PayloadList::size_type size_type;
+
+  typedef typename PayloadList::iterator iterator;
+  typedef typename PayloadList::const_iterator const_iterator;
+  typedef typename PayloadList::reverse_iterator reverse_iterator;
+  typedef typename PayloadList::const_reverse_iterator const_reverse_iterator;
+
+  enum { NO_AUTO_EVICT = 0 };
+
+  // The max_size is the size at which the cache will prune its members to when
+  // a new item is inserted. If the caller wants to manager this itself (for
+  // example, maybe it has special work to do when something is evicted), it
+  // can pass NO_AUTO_EVICT to not restrict the cache size.
+  explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {
+  }
+
+  MRUCacheBase(size_type max_size, const DeletorType& deletor)
+      : max_size_(max_size), deletor_(deletor) {
+  }
+
+  virtual ~MRUCacheBase() {
+    iterator i = begin();
+    while (i != end())
+      i = Erase(i);
+  }
+
+  size_type max_size() const { return max_size_; }
+
+  // Inserts a payload item with the given key. If an existing item has
+  // the same key, it is removed prior to insertion. An iterator indicating the
+  // inserted item will be returned (this will always be the front of the list).
+  //
+  // The payload will be copied. In the case of an OwningMRUCache, this function
+  // will take ownership of the pointer.
+  iterator Put(const KeyType& key, const PayloadType& payload) {
+    // Remove any existing payload with that key.
+    typename KeyIndex::iterator index_iter = index_.find(key);
+    if (index_iter != index_.end()) {
+      // Erase the reference to it. This will call the deletor on the removed
+      // element. The index reference will be replaced in the code below.
+      Erase(index_iter->second);
+    } else if (max_size_ != NO_AUTO_EVICT) {
+      // New item is being inserted which might make it larger than the maximum
+      // size: kick the oldest thing out if necessary.
+      ShrinkToSize(max_size_ - 1);
+    }
+
+    ordering_.push_front(value_type(key, payload));
+    index_.insert(std::make_pair(key, ordering_.begin()));
+    return ordering_.begin();
+  }
+
+  // Retrieves the contents of the given key, or end() if not found. This method
+  // has the side effect of moving the requested item to the front of the
+  // recency list.
+  //
+  // TODO(brettw) We may want a const version of this function in the future.
+  iterator Get(const KeyType& key) {
+    typename KeyIndex::iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    typename PayloadList::iterator iter = index_iter->second;
+
+    // Move the touched item to the front of the recency ordering.
+    ordering_.splice(ordering_.begin(), ordering_, iter);
+    return ordering_.begin();
+  }
+
+  // Retrieves the payload associated with a given key and returns it via
+  // result without affecting the ordering (unlike Get).
+  iterator Peek(const KeyType& key) {
+    typename KeyIndex::const_iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    return index_iter->second;
+  }
+
+  const_iterator Peek(const KeyType& key) const {
+    typename KeyIndex::const_iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    return index_iter->second;
+  }
+
+  // Erases the item referenced by the given iterator. An iterator to the item
+  // following it will be returned. The iterator must be valid.
+  iterator Erase(iterator pos) {
+    deletor_(pos->second);
+    index_.erase(pos->first);
+    return ordering_.erase(pos);
+  }
+
+  // MRUCache entries are often processed in reverse order, so we add this
+  // convenience function (not typically defined by STL containers).
+  reverse_iterator Erase(reverse_iterator pos) {
+    // We have to actually give it the incremented iterator to delete, since
+    // the forward iterator that base() returns is actually one past the item
+    // being iterated over.
+    return reverse_iterator(Erase((++pos).base()));
+  }
+
+  // Shrinks the cache so it only holds |new_size| items. If |new_size| is
+  // bigger or equal to the current number of items, this will do nothing.
+  void ShrinkToSize(size_type new_size) {
+    for (size_type i = size(); i > new_size; i--)
+      Erase(rbegin());
+  }
+
+  // Deletes everything from the cache.
+  void Clear() {
+    for (typename PayloadList::iterator i(ordering_.begin());
+         i != ordering_.end(); ++i)
+      deletor_(i->second);
+    index_.clear();
+    ordering_.clear();
+  }
+
+  // Returns the number of elements in the cache.
+  size_type size() const {
+    // We don't use ordering_.size() for the return value because
+    // (as a linked list) it can be O(n).
+    DCHECK(index_.size() == ordering_.size());
+    return index_.size();
+  }
+
+  // Allows iteration over the list. Forward iteration starts with the most
+  // recent item and works backwards.
+  //
+  // Note that since these iterators are actually iterators over a list, you
+  // can keep them as you insert or delete things (as long as you don't delete
+  // the one you are pointing to) and they will still be valid.
+  iterator begin() { return ordering_.begin(); }
+  const_iterator begin() const { return ordering_.begin(); }
+  iterator end() { return ordering_.end(); }
+  const_iterator end() const { return ordering_.end(); }
+
+  reverse_iterator rbegin() { return ordering_.rbegin(); }
+  const_reverse_iterator rbegin() const { return ordering_.rbegin(); }
+  reverse_iterator rend() { return ordering_.rend(); }
+  const_reverse_iterator rend() const { return ordering_.rend(); }
+
+  bool empty() const { return ordering_.empty(); }
+
+ private:
+  PayloadList ordering_;
+  KeyIndex index_;
+
+  size_type max_size_;
+
+  DeletorType deletor_;
+
+  DISALLOW_COPY_AND_ASSIGN(MRUCacheBase);
+};
+
+// MRUCache --------------------------------------------------------------------
+
+// A functor that does nothing. Used by the MRUCache.
+template<class PayloadType>
+class MRUCacheNullDeletor {
+ public:
+  void operator()(const PayloadType& payload) {}
+};
+
+// A container that does not do anything to free its data. Use this when storing
+// value types (as opposed to pointers) in the list.
+template <class KeyType, class PayloadType>
+class MRUCache : public MRUCacheBase<KeyType,
+                                     PayloadType,
+                                     MRUCacheNullDeletor<PayloadType> > {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+      MRUCacheNullDeletor<PayloadType> > ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit MRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~MRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MRUCache);
+};
+
+// OwningMRUCache --------------------------------------------------------------
+
+template<class PayloadType>
+class MRUCachePointerDeletor {
+ public:
+  void operator()(const PayloadType& payload) { delete payload; }
+};
+
+// A cache that owns the payload type, which must be a non-const pointer type.
+// The pointers will be deleted when they are removed, replaced, or when the
+// cache is destroyed.
+template <class KeyType, class PayloadType>
+class OwningMRUCache
+    : public MRUCacheBase<KeyType,
+                          PayloadType,
+                          MRUCachePointerDeletor<PayloadType> > {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+      MRUCachePointerDeletor<PayloadType> > ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit OwningMRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~OwningMRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OwningMRUCache);
+};
+
+// HashingMRUCache ------------------------------------------------------------
+
+template <class KeyType, class ValueType>
+struct MRUCacheHashMap {
+  typedef base::hash_map<KeyType, ValueType> Type;
+};
+
+// This class is similar to MRUCache, except that it uses base::hash_map as
+// the map type instead of std::map. Note that your KeyType must be hashable
+// to use this cache.
+template <class KeyType, class PayloadType>
+class HashingMRUCache : public MRUCacheBase<KeyType,
+                                            PayloadType,
+                                            MRUCacheNullDeletor<PayloadType>,
+                                            MRUCacheHashMap> {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+                       MRUCacheNullDeletor<PayloadType>,
+                       MRUCacheHashMap> ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit HashingMRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~HashingMRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HashingMRUCache);
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_MRU_CACHE_H_
diff --git a/base/containers/mru_cache_unittest.cc b/base/containers/mru_cache_unittest.cc
new file mode 100644
index 0000000..a8e8932
--- /dev/null
+++ b/base/containers/mru_cache_unittest.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/containers/mru_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int cached_item_live_count = 0;
+
+struct CachedItem {
+  CachedItem() : value(0) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(int new_value) : value(new_value) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(const CachedItem& other) : value(other.value) {
+    cached_item_live_count++;
+  }
+
+  ~CachedItem() {
+    cached_item_live_count--;
+  }
+
+  int value;
+};
+
+}  // namespace
+
+TEST(MRUCacheTest, Basic) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  // Check failure conditions
+  {
+    CachedItem test_item;
+    EXPECT_TRUE(cache.Get(0) == cache.end());
+    EXPECT_TRUE(cache.Peek(0) == cache.end());
+  }
+
+  static const int kItem1Key = 5;
+  CachedItem item1(10);
+  Cache::iterator inserted_item = cache.Put(kItem1Key, item1);
+  EXPECT_EQ(1U, cache.size());
+
+  // Check that item1 was properly inserted.
+  {
+    Cache::iterator found = cache.Get(kItem1Key);
+    EXPECT_TRUE(inserted_item == cache.begin());
+    EXPECT_TRUE(found != cache.end());
+
+    found = cache.Peek(kItem1Key);
+    EXPECT_TRUE(found != cache.end());
+
+    EXPECT_EQ(kItem1Key, found->first);
+    EXPECT_EQ(item1.value, found->second.value);
+  }
+
+  static const int kItem2Key = 7;
+  CachedItem item2(12);
+  cache.Put(kItem2Key, item2);
+  EXPECT_EQ(2U, cache.size());
+
+  // Check that item1 is the oldest since item2 was added afterwards.
+  {
+    Cache::reverse_iterator oldest = cache.rbegin();
+    ASSERT_TRUE(oldest != cache.rend());
+    EXPECT_EQ(kItem1Key, oldest->first);
+    EXPECT_EQ(item1.value, oldest->second.value);
+  }
+
+  // Check that item1 is still accessible by key.
+  {
+    Cache::iterator test_item = cache.Get(kItem1Key);
+    ASSERT_TRUE(test_item != cache.end());
+    EXPECT_EQ(kItem1Key, test_item->first);
+    EXPECT_EQ(item1.value, test_item->second.value);
+  }
+
+  // Check that retrieving item1 pushed item2 to oldest.
+  {
+    Cache::reverse_iterator oldest = cache.rbegin();
+    ASSERT_TRUE(oldest != cache.rend());
+    EXPECT_EQ(kItem2Key, oldest->first);
+    EXPECT_EQ(item2.value, oldest->second.value);
+  }
+
+  // Remove the oldest item and check that item1 is now the only member.
+  {
+    Cache::reverse_iterator next = cache.Erase(cache.rbegin());
+
+    EXPECT_EQ(1U, cache.size());
+
+    EXPECT_TRUE(next == cache.rbegin());
+    EXPECT_EQ(kItem1Key, next->first);
+    EXPECT_EQ(item1.value, next->second.value);
+
+    cache.Erase(cache.begin());
+    EXPECT_EQ(0U, cache.size());
+  }
+
+  // Check that Clear() works properly.
+  cache.Put(kItem1Key, item1);
+  cache.Put(kItem2Key, item2);
+  EXPECT_EQ(2U, cache.size());
+  cache.Clear();
+  EXPECT_EQ(0U, cache.size());
+}
+
+TEST(MRUCacheTest, GetVsPeek) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  static const int kItem1Key = 1;
+  CachedItem item1(10);
+  cache.Put(kItem1Key, item1);
+
+  static const int kItem2Key = 2;
+  CachedItem item2(20);
+  cache.Put(kItem2Key, item2);
+
+  // This should do nothing since the size is bigger than the number of items.
+  cache.ShrinkToSize(100);
+
+  // Check that item1 starts out as oldest
+  {
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+    EXPECT_EQ(kItem1Key, iter->first);
+    EXPECT_EQ(item1.value, iter->second.value);
+  }
+
+  // Check that Peek doesn't change ordering
+  {
+    Cache::iterator peekiter = cache.Peek(kItem1Key);
+    ASSERT_TRUE(peekiter != cache.end());
+
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+    EXPECT_EQ(kItem1Key, iter->first);
+    EXPECT_EQ(item1.value, iter->second.value);
+  }
+}
+
+TEST(MRUCacheTest, KeyReplacement) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  static const int kItem1Key = 1;
+  CachedItem item1(10);
+  cache.Put(kItem1Key, item1);
+
+  static const int kItem2Key = 2;
+  CachedItem item2(20);
+  cache.Put(kItem2Key, item2);
+
+  static const int kItem3Key = 3;
+  CachedItem item3(30);
+  cache.Put(kItem3Key, item3);
+
+  static const int kItem4Key = 4;
+  CachedItem item4(40);
+  cache.Put(kItem4Key, item4);
+
+  CachedItem item5(50);
+  cache.Put(kItem3Key, item5);
+
+  EXPECT_EQ(4U, cache.size());
+  for (int i = 0; i < 3; ++i) {
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+  }
+
+  // Make it so only the most important element is there.
+  cache.ShrinkToSize(1);
+
+  Cache::iterator iter = cache.begin();
+  EXPECT_EQ(kItem3Key, iter->first);
+  EXPECT_EQ(item5.value, iter->second.value);
+}
+
+// Make sure that the owning version release its pointers properly.
+TEST(MRUCacheTest, Owning) {
+  typedef base::OwningMRUCache<int, CachedItem*> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  int initial_count = cached_item_live_count;
+
+  // First insert and item and then overwrite it.
+  static const int kItem1Key = 1;
+  cache.Put(kItem1Key, new CachedItem(20));
+  cache.Put(kItem1Key, new CachedItem(22));
+
+  // There should still be one item, and one extra live item.
+  Cache::iterator iter = cache.Get(kItem1Key);
+  EXPECT_EQ(1U, cache.size());
+  EXPECT_TRUE(iter != cache.end());
+  EXPECT_EQ(initial_count + 1, cached_item_live_count);
+
+  // Now remove it.
+  cache.Erase(cache.begin());
+  EXPECT_EQ(initial_count, cached_item_live_count);
+
+  // Now try another cache that goes out of scope to make sure its pointers
+  // go away.
+  {
+    Cache cache2(Cache::NO_AUTO_EVICT);
+    cache2.Put(1, new CachedItem(20));
+    cache2.Put(2, new CachedItem(20));
+  }
+
+  // There should be no objects leaked.
+  EXPECT_EQ(initial_count, cached_item_live_count);
+
+  // Check that Clear() also frees things correctly.
+  {
+    Cache cache2(Cache::NO_AUTO_EVICT);
+    cache2.Put(1, new CachedItem(20));
+    cache2.Put(2, new CachedItem(20));
+    EXPECT_EQ(initial_count + 2, cached_item_live_count);
+    cache2.Clear();
+    EXPECT_EQ(initial_count, cached_item_live_count);
+  }
+}
+
+TEST(MRUCacheTest, AutoEvict) {
+  typedef base::OwningMRUCache<int, CachedItem*> Cache;
+  static const Cache::size_type kMaxSize = 3;
+
+  int initial_count = cached_item_live_count;
+
+  {
+    Cache cache(kMaxSize);
+
+    static const int kItem1Key = 1, kItem2Key = 2, kItem3Key = 3, kItem4Key = 4;
+    cache.Put(kItem1Key, new CachedItem(20));
+    cache.Put(kItem2Key, new CachedItem(21));
+    cache.Put(kItem3Key, new CachedItem(22));
+    cache.Put(kItem4Key, new CachedItem(23));
+
+    // The cache should only have kMaxSize items in it even though we inserted
+    // more.
+    EXPECT_EQ(kMaxSize, cache.size());
+  }
+
+  // There should be no objects leaked.
+  EXPECT_EQ(initial_count, cached_item_live_count);
+}
+
+TEST(MRUCacheTest, HashingMRUCache) {
+  // Very simple test to make sure that the hashing cache works correctly.
+  typedef base::HashingMRUCache<std::string, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  CachedItem one(1);
+  cache.Put("First", one);
+
+  CachedItem two(2);
+  cache.Put("Second", two);
+
+  EXPECT_EQ(one.value, cache.Get("First")->second.value);
+  EXPECT_EQ(two.value, cache.Get("Second")->second.value);
+  cache.ShrinkToSize(1);
+  EXPECT_EQ(two.value, cache.Get("Second")->second.value);
+  EXPECT_TRUE(cache.Get("First") == cache.end());
+}
diff --git a/base/containers/scoped_ptr_hash_map.h b/base/containers/scoped_ptr_hash_map.h
new file mode 100644
index 0000000..8fe550e
--- /dev/null
+++ b/base/containers/scoped_ptr_hash_map.h
@@ -0,0 +1,172 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+#define BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+
+#include <algorithm>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+// This type acts like a hash_map<K, scoped_ptr<V, D> >, based on top of
+// base::hash_map. The ScopedPtrHashMap has ownership of all values in the data
+// structure.
+template <typename Key, typename ScopedPtr>
+class ScopedPtrHashMap {
+  typedef base::hash_map<Key, typename ScopedPtr::element_type*> Container;
+
+ public:
+  typedef typename Container::key_type key_type;
+  typedef typename Container::mapped_type mapped_type;
+  typedef typename Container::value_type value_type;
+  typedef typename Container::iterator iterator;
+  typedef typename Container::const_iterator const_iterator;
+
+  ScopedPtrHashMap() {}
+
+  ~ScopedPtrHashMap() { clear(); }
+
+  void swap(ScopedPtrHashMap<Key, ScopedPtr>& other) {
+    data_.swap(other.data_);
+  }
+
+  // Replaces value but not key if key is already present.
+  iterator set(const Key& key, ScopedPtr data) {
+    iterator it = find(key);
+    if (it != end()) {
+      // Let ScopedPtr decide how to delete. For example, it may use custom
+      // deleter.
+      ScopedPtr(it->second).reset();
+      it->second = data.release();
+      return it;
+    }
+
+    return data_.insert(std::make_pair(key, data.release())).first;
+  }
+
+  // Does nothing if key is already present
+  std::pair<iterator, bool> add(const Key& key, ScopedPtr data) {
+    std::pair<iterator, bool> result =
+        data_.insert(std::make_pair(key, data.get()));
+    if (result.second)
+      ignore_result(data.release());
+    return result;
+  }
+
+  void erase(iterator it) {
+    // Let ScopedPtr decide how to delete.
+    ScopedPtr(it->second).reset();
+    data_.erase(it);
+  }
+
+  size_t erase(const Key& k) {
+    iterator it = data_.find(k);
+    if (it == data_.end())
+      return 0;
+    erase(it);
+    return 1;
+  }
+
+  ScopedPtr take(iterator it) {
+    DCHECK(it != data_.end());
+    if (it == data_.end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    it->second = NULL;
+    return ret.Pass();
+  }
+
+  ScopedPtr take(const Key& k) {
+    iterator it = find(k);
+    if (it == data_.end())
+      return ScopedPtr();
+
+    return take(it);
+  }
+
+  ScopedPtr take_and_erase(iterator it) {
+    DCHECK(it != data_.end());
+    if (it == data_.end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    data_.erase(it);
+    return ret.Pass();
+  }
+
+  ScopedPtr take_and_erase(const Key& k) {
+    iterator it = find(k);
+    if (it == data_.end())
+      return ScopedPtr();
+
+    return take_and_erase(it);
+  }
+
+  // Returns the element in the hash_map that matches the given key.
+  // If no such element exists it returns NULL.
+  typename ScopedPtr::element_type* get(const Key& k) const {
+    const_iterator it = find(k);
+    if (it == end())
+      return NULL;
+    return it->second;
+  }
+
+  inline bool contains(const Key& k) const { return data_.count(k) > 0; }
+
+  inline void clear() {
+    auto it = data_.begin();
+    while (it != data_.end()) {
+      // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+      // Deleting the value does not always invalidate the iterator, but it may
+      // do so if the key is a pointer into the value object.
+      auto temp = it;
+      ++it;
+      // Let ScopedPtr decide how to delete.
+      ScopedPtr(temp->second).reset();
+    }
+    data_.clear();
+  }
+
+  inline const_iterator find(const Key& k) const { return data_.find(k); }
+  inline iterator find(const Key& k) { return data_.find(k); }
+
+  inline size_t count(const Key& k) const { return data_.count(k); }
+  inline std::pair<const_iterator, const_iterator> equal_range(
+      const Key& k) const {
+    return data_.equal_range(k);
+  }
+  inline std::pair<iterator, iterator> equal_range(const Key& k) {
+    return data_.equal_range(k);
+  }
+
+  inline size_t size() const { return data_.size(); }
+  inline size_t max_size() const { return data_.max_size(); }
+
+  inline bool empty() const { return data_.empty(); }
+
+  inline size_t bucket_count() const { return data_.bucket_count(); }
+  inline void resize(size_t size) { return data_.resize(size); }
+
+  inline iterator begin() { return data_.begin(); }
+  inline const_iterator begin() const { return data_.begin(); }
+  inline iterator end() { return data_.end(); }
+  inline const_iterator end() const { return data_.end(); }
+
+ private:
+  Container data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPtrHashMap);
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
diff --git a/base/containers/scoped_ptr_hash_map_unittest.cc b/base/containers/scoped_ptr_hash_map_unittest.cc
new file mode 100644
index 0000000..88fe41f
--- /dev/null
+++ b/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/scoped_ptr_hash_map.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct DeleteCounter {
+ public:
+  DeleteCounter() {}
+  ~DeleteCounter() { g_delete_count++; }
+
+  static void ResetCounter() { g_delete_count = 0; }
+  static int delete_count() { return g_delete_count; }
+
+ private:
+  static int g_delete_count;
+};
+
+int DeleteCounter::g_delete_count = 0;
+
+struct CountingDeleter {
+ public:
+  inline void operator()(DeleteCounter* ptr) const {
+    g_deleter_call_count++;
+    delete ptr;
+  }
+
+  static int count() { return g_deleter_call_count; }
+  static void ResetCounter() { g_deleter_call_count = 0; }
+
+ private:
+  static int g_deleter_call_count;
+};
+
+int CountingDeleter::g_deleter_call_count = 0;
+
+TEST(ScopedPtrHashMapTest, CustomDeleter) {
+  int key = 123;
+
+  // Test dtor.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+  }
+  EXPECT_EQ(1, DeleteCounter::delete_count());
+  EXPECT_EQ(1, CountingDeleter::count());
+
+  // Test set and erase.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.erase(map.set(
+        key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter)));
+    EXPECT_EQ(1, DeleteCounter::delete_count());
+    EXPECT_EQ(1, CountingDeleter::count());
+  }
+  EXPECT_EQ(1, DeleteCounter::delete_count());
+  EXPECT_EQ(1, CountingDeleter::count());
+
+  // Test set more than once.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    EXPECT_EQ(2, DeleteCounter::delete_count());
+    EXPECT_EQ(2, CountingDeleter::count());
+  }
+  EXPECT_EQ(3, DeleteCounter::delete_count());
+  EXPECT_EQ(3, CountingDeleter::count());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/containers/small_map.h b/base/containers/small_map.h
new file mode 100644
index 0000000..df3d22a
--- /dev/null
+++ b/base/containers/small_map.h
@@ -0,0 +1,652 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_SMALL_MAP_H_
+#define BASE_CONTAINERS_SMALL_MAP_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/manual_constructor.h"
+
+namespace base {
+
+// An STL-like associative container which starts out backed by a simple
+// array but switches to some other container type if it grows beyond a
+// fixed size.
+//
+// WHAT TYPE OF MAP SHOULD YOU USE?
+// --------------------------------
+//
+//  - std::map should be the default if you're not sure, since it's the most
+//    difficult to mess up. Generally this is backed by a red-black tree. It
+//    will generate a lot of code (if you use a common key type like int or
+//    string the linker will probably emiminate the duplicates). It will
+//    do heap allocations for each element.
+//
+//  - If you only ever keep a couple of items and have very simple usage,
+//    consider whether a using a vector and brute-force searching it will be
+//    the most efficient. It's not a lot of generated code (less then a
+//    red-black tree if your key is "weird" and not eliminated as duplicate of
+//    something else) and will probably be faster and do fewer heap allocations
+//    than std::map if you have just a couple of items.
+//
+//  - base::hash_map should be used if you need O(1) lookups. It may waste
+//    space in the hash table, and it can be easy to write correct-looking
+//    code with the default hash function being wrong or poorly-behaving.
+//
+//  - SmallMap combines the performance benefits of the brute-force-searched
+//    vector for small cases (no extra heap allocations), but can efficiently
+//    fall back if you end up adding many items. It will generate more code
+//    than std::map (at least 160 bytes for operator[]) which is bad if you
+//    have a "weird" key where map functions can't be
+//    duplicate-code-eliminated. If you have a one-off key and aren't in
+//    performance-critical code, this bloat may negate some of the benefits and
+//    you should consider on of the other options.
+//
+// SmallMap will pick up the comparator from the underlying map type. In
+// std::map (and in MSVC additionally hash_map) only a "less" operator is
+// defined, which requires us to do two comparisons per element when doing the
+// brute-force search in the simple array.
+//
+// We define default overrides for the common map types to avoid this
+// double-compare, but you should be aware of this if you use your own
+// operator< for your map and supply yor own version of == to the SmallMap.
+// You can use regular operator== by just doing:
+//
+//   base::SmallMap<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey> >
+//
+//
+// USAGE
+// -----
+//
+// NormalMap:  The map type to fall back to.  This also defines the key
+//             and value types for the SmallMap.
+// kArraySize:  The size of the initial array of results. This will be
+//              allocated with the SmallMap object rather than separately on
+//              the heap. Once the map grows beyond this size, the map type
+//              will be used instead.
+// EqualKey:  A functor which tests two keys for equality.  If the wrapped
+//            map type has a "key_equal" member (hash_map does), then that will
+//            be used by default. If the wrapped map type has a strict weak
+//            ordering "key_compare" (std::map does), that will be used to
+//            implement equality by default.
+// MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to
+//          initialize the map. This functor will be called at most once per
+//          SmallMap, when the map exceeds the threshold of kArraySize and we
+//          are about to copy values from the array to the map. The functor
+//          *must* call one of the Init() methods provided by
+//          ManualConstructor, since after it runs we assume that the NormalMap
+//          has been initialized.
+//
+// example:
+//   base::SmallMap< std::map<string, int> > days;
+//   days["sunday"   ] = 0;
+//   days["monday"   ] = 1;
+//   days["tuesday"  ] = 2;
+//   days["wednesday"] = 3;
+//   days["thursday" ] = 4;
+//   days["friday"   ] = 5;
+//   days["saturday" ] = 6;
+//
+// You should assume that SmallMap might invalidate all the iterators
+// on any call to erase(), insert() and operator[].
+
+namespace internal {
+
+template <typename NormalMap>
+class SmallMapDefaultInit {
+ public:
+  void operator()(ManualConstructor<NormalMap>* map) const {
+    map->Init();
+  }
+};
+
+// has_key_equal<M>::value is true iff there exists a type M::key_equal. This is
+// used to dispatch to one of the select_equal_key<> metafunctions below.
+template <typename M>
+struct has_key_equal {
+  typedef char sml;  // "small" is sometimes #defined so we use an abbreviation.
+  typedef struct { char dummy[2]; } big;
+  // Two functions, one accepts types that have a key_equal member, and one that
+  // accepts anything. They each return a value of a different size, so we can
+  // determine at compile-time which function would have been called.
+  template <typename U> static big test(typename U::key_equal*);
+  template <typename> static sml test(...);
+  // Determines if M::key_equal exists by looking at the size of the return
+  // type of the compiler-chosen test() function.
+  static const bool value = (sizeof(test<M>(0)) == sizeof(big));
+};
+template <typename M> const bool has_key_equal<M>::value;
+
+// Base template used for map types that do NOT have an M::key_equal member,
+// e.g., std::map<>. These maps have a strict weak ordering comparator rather
+// than an equality functor, so equality will be implemented in terms of that
+// comparator.
+//
+// There's a partial specialization of this template below for map types that do
+// have an M::key_equal member.
+template <typename M, bool has_key_equal_value>
+struct select_equal_key {
+  struct equal_key {
+    bool operator()(const typename M::key_type& left,
+                    const typename M::key_type& right) {
+      // Implements equality in terms of a strict weak ordering comparator.
+      typename M::key_compare comp;
+      return !comp(left, right) && !comp(right, left);
+    }
+  };
+};
+
+// Provide overrides to use operator== for key compare for the "normal" map and
+// hash map types. If you override the default comparator or allocator for a
+// map or hash_map, or use another type of map, this won't get used.
+//
+// If we switch to using std::unordered_map for base::hash_map, then the
+// hash_map specialization can be removed.
+template <typename KeyType, typename ValueType>
+struct select_equal_key< std::map<KeyType, ValueType>, false> {
+  struct equal_key {
+    bool operator()(const KeyType& left, const KeyType& right) {
+      return left == right;
+    }
+  };
+};
+template <typename KeyType, typename ValueType>
+struct select_equal_key< base::hash_map<KeyType, ValueType>, false> {
+  struct equal_key {
+    bool operator()(const KeyType& left, const KeyType& right) {
+      return left == right;
+    }
+  };
+};
+
+// Partial template specialization handles case where M::key_equal exists, e.g.,
+// hash_map<>.
+template <typename M>
+struct select_equal_key<M, true> {
+  typedef typename M::key_equal equal_key;
+};
+
+}  // namespace internal
+
+template <typename NormalMap,
+          int kArraySize = 4,
+          typename EqualKey =
+              typename internal::select_equal_key<
+                  NormalMap,
+                  internal::has_key_equal<NormalMap>::value>::equal_key,
+          typename MapInit = internal::SmallMapDefaultInit<NormalMap> >
+class SmallMap {
+  // We cannot rely on the compiler to reject array of size 0.  In
+  // particular, gcc 2.95.3 does it but later versions allow 0-length
+  // arrays.  Therefore, we explicitly reject non-positive kArraySize
+  // here.
+  COMPILE_ASSERT(kArraySize > 0, default_initial_size_should_be_positive);
+
+ public:
+  typedef typename NormalMap::key_type key_type;
+  typedef typename NormalMap::mapped_type data_type;
+  typedef typename NormalMap::mapped_type mapped_type;
+  typedef typename NormalMap::value_type value_type;
+  typedef EqualKey key_equal;
+
+  SmallMap() : size_(0), functor_(MapInit()) {}
+
+  explicit SmallMap(const MapInit& functor) : size_(0), functor_(functor) {}
+
+  // Allow copy-constructor and assignment, since STL allows them too.
+  SmallMap(const SmallMap& src) {
+    // size_ and functor_ are initted in InitFrom()
+    InitFrom(src);
+  }
+  void operator=(const SmallMap& src) {
+    if (&src == this) return;
+
+    // This is not optimal. If src and dest are both using the small
+    // array, we could skip the teardown and reconstruct. One problem
+    // to be resolved is that the value_type itself is pair<const K,
+    // V>, and const K is not assignable.
+    Destroy();
+    InitFrom(src);
+  }
+  ~SmallMap() {
+    Destroy();
+  }
+
+  class const_iterator;
+
+  class iterator {
+   public:
+    typedef typename NormalMap::iterator::iterator_category iterator_category;
+    typedef typename NormalMap::iterator::value_type value_type;
+    typedef typename NormalMap::iterator::difference_type difference_type;
+    typedef typename NormalMap::iterator::pointer pointer;
+    typedef typename NormalMap::iterator::reference reference;
+
+    inline iterator(): array_iter_(NULL) {}
+
+    inline iterator& operator++() {
+      if (array_iter_ != NULL) {
+        ++array_iter_;
+      } else {
+        ++hash_iter_;
+      }
+      return *this;
+    }
+    inline iterator operator++(int /*unused*/) {
+      iterator result(*this);
+      ++(*this);
+      return result;
+    }
+    inline iterator& operator--() {
+      if (array_iter_ != NULL) {
+        --array_iter_;
+      } else {
+        --hash_iter_;
+      }
+      return *this;
+    }
+    inline iterator operator--(int /*unused*/) {
+      iterator result(*this);
+      --(*this);
+      return result;
+    }
+    inline value_type* operator->() const {
+      if (array_iter_ != NULL) {
+        return array_iter_->get();
+      } else {
+        return hash_iter_.operator->();
+      }
+    }
+
+    inline value_type& operator*() const {
+      if (array_iter_ != NULL) {
+        return *array_iter_->get();
+      } else {
+        return *hash_iter_;
+      }
+    }
+
+    inline bool operator==(const iterator& other) const {
+      if (array_iter_ != NULL) {
+        return array_iter_ == other.array_iter_;
+      } else {
+        return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_;
+      }
+    }
+
+    inline bool operator!=(const iterator& other) const {
+      return !(*this == other);
+    }
+
+    bool operator==(const const_iterator& other) const;
+    bool operator!=(const const_iterator& other) const;
+
+   private:
+    friend class SmallMap;
+    friend class const_iterator;
+    inline explicit iterator(ManualConstructor<value_type>* init)
+      : array_iter_(init) {}
+    inline explicit iterator(const typename NormalMap::iterator& init)
+      : array_iter_(NULL), hash_iter_(init) {}
+
+    ManualConstructor<value_type>* array_iter_;
+    typename NormalMap::iterator hash_iter_;
+  };
+
+  class const_iterator {
+   public:
+    typedef typename NormalMap::const_iterator::iterator_category
+        iterator_category;
+    typedef typename NormalMap::const_iterator::value_type value_type;
+    typedef typename NormalMap::const_iterator::difference_type difference_type;
+    typedef typename NormalMap::const_iterator::pointer pointer;
+    typedef typename NormalMap::const_iterator::reference reference;
+
+    inline const_iterator(): array_iter_(NULL) {}
+    // Non-explicit ctor lets us convert regular iterators to const iterators
+    inline const_iterator(const iterator& other)
+      : array_iter_(other.array_iter_), hash_iter_(other.hash_iter_) {}
+
+    inline const_iterator& operator++() {
+      if (array_iter_ != NULL) {
+        ++array_iter_;
+      } else {
+        ++hash_iter_;
+      }
+      return *this;
+    }
+    inline const_iterator operator++(int /*unused*/) {
+      const_iterator result(*this);
+      ++(*this);
+      return result;
+    }
+
+    inline const_iterator& operator--() {
+      if (array_iter_ != NULL) {
+        --array_iter_;
+      } else {
+        --hash_iter_;
+      }
+      return *this;
+    }
+    inline const_iterator operator--(int /*unused*/) {
+      const_iterator result(*this);
+      --(*this);
+      return result;
+    }
+
+    inline const value_type* operator->() const {
+      if (array_iter_ != NULL) {
+        return array_iter_->get();
+      } else {
+        return hash_iter_.operator->();
+      }
+    }
+
+    inline const value_type& operator*() const {
+      if (array_iter_ != NULL) {
+        return *array_iter_->get();
+      } else {
+        return *hash_iter_;
+      }
+    }
+
+    inline bool operator==(const const_iterator& other) const {
+      if (array_iter_ != NULL) {
+        return array_iter_ == other.array_iter_;
+      } else {
+        return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_;
+      }
+    }
+
+    inline bool operator!=(const const_iterator& other) const {
+      return !(*this == other);
+    }
+
+   private:
+    friend class SmallMap;
+    inline explicit const_iterator(
+        const ManualConstructor<value_type>* init)
+      : array_iter_(init) {}
+    inline explicit const_iterator(
+        const typename NormalMap::const_iterator& init)
+      : array_iter_(NULL), hash_iter_(init) {}
+
+    const ManualConstructor<value_type>* array_iter_;
+    typename NormalMap::const_iterator hash_iter_;
+  };
+
+  iterator find(const key_type& key) {
+    key_equal compare;
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, key)) {
+          return iterator(array_ + i);
+        }
+      }
+      return iterator(array_ + size_);
+    } else {
+      return iterator(map()->find(key));
+    }
+  }
+
+  const_iterator find(const key_type& key) const {
+    key_equal compare;
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, key)) {
+          return const_iterator(array_ + i);
+        }
+      }
+      return const_iterator(array_ + size_);
+    } else {
+      return const_iterator(map()->find(key));
+    }
+  }
+
+  // Invalidates iterators.
+  data_type& operator[](const key_type& key) {
+    key_equal compare;
+
+    if (size_ >= 0) {
+      // operator[] searches backwards, favoring recently-added
+      // elements.
+      for (int i = size_-1; i >= 0; --i) {
+        if (compare(array_[i]->first, key)) {
+          return array_[i]->second;
+        }
+      }
+      if (size_ == kArraySize) {
+        ConvertToRealMap();
+        return (*map_)[key];
+      } else {
+        array_[size_].Init(key, data_type());
+        return array_[size_++]->second;
+      }
+    } else {
+      return (*map_)[key];
+    }
+  }
+
+  // Invalidates iterators.
+  std::pair<iterator, bool> insert(const value_type& x) {
+    key_equal compare;
+
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, x.first)) {
+          return std::make_pair(iterator(array_ + i), false);
+        }
+      }
+      if (size_ == kArraySize) {
+        ConvertToRealMap();  // Invalidates all iterators!
+        std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x);
+        return std::make_pair(iterator(ret.first), ret.second);
+      } else {
+        array_[size_].Init(x);
+        return std::make_pair(iterator(array_ + size_++), true);
+      }
+    } else {
+      std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x);
+      return std::make_pair(iterator(ret.first), ret.second);
+    }
+  }
+
+  // Invalidates iterators.
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l) {
+    while (f != l) {
+      insert(*f);
+      ++f;
+    }
+  }
+
+  iterator begin() {
+    if (size_ >= 0) {
+      return iterator(array_);
+    } else {
+      return iterator(map_->begin());
+    }
+  }
+  const_iterator begin() const {
+    if (size_ >= 0) {
+      return const_iterator(array_);
+    } else {
+      return const_iterator(map_->begin());
+    }
+  }
+
+  iterator end() {
+    if (size_ >= 0) {
+      return iterator(array_ + size_);
+    } else {
+      return iterator(map_->end());
+    }
+  }
+  const_iterator end() const {
+    if (size_ >= 0) {
+      return const_iterator(array_ + size_);
+    } else {
+      return const_iterator(map_->end());
+    }
+  }
+
+  void clear() {
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Destroy();
+      }
+    } else {
+      map_.Destroy();
+    }
+    size_ = 0;
+  }
+
+  // Invalidates iterators.
+  void erase(const iterator& position) {
+    if (size_ >= 0) {
+      int i = position.array_iter_ - array_;
+      array_[i].Destroy();
+      --size_;
+      if (i != size_) {
+        array_[i].Init(*array_[size_]);
+        array_[size_].Destroy();
+      }
+    } else {
+      map_->erase(position.hash_iter_);
+    }
+  }
+
+  size_t erase(const key_type& key) {
+    iterator iter = find(key);
+    if (iter == end()) return 0u;
+    erase(iter);
+    return 1u;
+  }
+
+  size_t count(const key_type& key) const {
+    return (find(key) == end()) ? 0 : 1;
+  }
+
+  size_t size() const {
+    if (size_ >= 0) {
+      return static_cast<size_t>(size_);
+    } else {
+      return map_->size();
+    }
+  }
+
+  bool empty() const {
+    if (size_ >= 0) {
+      return (size_ == 0);
+    } else {
+      return map_->empty();
+    }
+  }
+
+  // Returns true if we have fallen back to using the underlying map
+  // representation.
+  bool UsingFullMap() const {
+    return size_ < 0;
+  }
+
+  inline NormalMap* map() {
+    CHECK(UsingFullMap());
+    return map_.get();
+  }
+  inline const NormalMap* map() const {
+    CHECK(UsingFullMap());
+    return map_.get();
+  }
+
+ private:
+  int size_;  // negative = using hash_map
+
+  MapInit functor_;
+
+  // We want to call constructors and destructors manually, but we don't
+  // want to allocate and deallocate the memory used for them separately.
+  // So, we use this crazy ManualConstructor class.
+  //
+  // Since array_ and map_ are mutually exclusive, we'll put them in a
+  // union, too.  We add in a dummy_ value which quiets MSVC from otherwise
+  // giving an erroneous "union member has copy constructor" error message
+  // (C2621). This dummy member has to come before array_ to quiet the
+  // compiler.
+  //
+  // TODO(brettw) remove this and use C++11 unions when we require C++11.
+  union {
+    ManualConstructor<value_type> dummy_;
+    ManualConstructor<value_type> array_[kArraySize];
+    ManualConstructor<NormalMap> map_;
+  };
+
+  void ConvertToRealMap() {
+    // Move the current elements into a temporary array.
+    ManualConstructor<value_type> temp_array[kArraySize];
+
+    for (int i = 0; i < kArraySize; i++) {
+      temp_array[i].Init(*array_[i]);
+      array_[i].Destroy();
+    }
+
+    // Initialize the map.
+    size_ = -1;
+    functor_(&map_);
+
+    // Insert elements into it.
+    for (int i = 0; i < kArraySize; i++) {
+      map_->insert(*temp_array[i]);
+      temp_array[i].Destroy();
+    }
+  }
+
+  // Helpers for constructors and destructors.
+  void InitFrom(const SmallMap& src) {
+    functor_ = src.functor_;
+    size_ = src.size_;
+    if (src.size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Init(*src.array_[i]);
+      }
+    } else {
+      functor_(&map_);
+      (*map_.get()) = (*src.map_.get());
+    }
+  }
+  void Destroy() {
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Destroy();
+      }
+    } else {
+      map_.Destroy();
+    }
+  }
+};
+
+template <typename NormalMap, int kArraySize, typename EqualKey,
+          typename Functor>
+inline bool SmallMap<NormalMap, kArraySize, EqualKey,
+                     Functor>::iterator::operator==(
+    const const_iterator& other) const {
+  return other == *this;
+}
+template <typename NormalMap, int kArraySize, typename EqualKey,
+          typename Functor>
+inline bool SmallMap<NormalMap, kArraySize, EqualKey,
+                     Functor>::iterator::operator!=(
+    const const_iterator& other) const {
+  return other != *this;
+}
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_SMALL_MAP_H_
diff --git a/base/containers/small_map_unittest.cc b/base/containers/small_map_unittest.cc
new file mode 100644
index 0000000..f87a8f0
--- /dev/null
+++ b/base/containers/small_map_unittest.cc
@@ -0,0 +1,482 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/small_map.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <functional>
+#include <map>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(SmallMap, General) {
+  SmallMap<hash_map<int, int> > m;
+
+  EXPECT_TRUE(m.empty());
+
+  m[0] = 5;
+
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.size(), 1u);
+
+  m[9] = 2;
+
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.size(), 2u);
+
+  EXPECT_EQ(m[9], 2);
+  EXPECT_EQ(m[0], 5);
+  EXPECT_FALSE(m.UsingFullMap());
+
+  SmallMap<hash_map<int, int> >::iterator iter(m.begin());
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ((*iter).first, 9);
+  EXPECT_EQ((*iter).second, 2);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  m[8] = 23;
+  m[1234] = 90;
+  m[-5] = 6;
+
+  EXPECT_EQ(m[   9],  2);
+  EXPECT_EQ(m[   0],  5);
+  EXPECT_EQ(m[1234], 90);
+  EXPECT_EQ(m[   8], 23);
+  EXPECT_EQ(m[  -5],  6);
+  EXPECT_EQ(m.size(), 5u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_TRUE(m.UsingFullMap());
+
+  iter = m.begin();
+  for (int i = 0; i < 5; i++) {
+    EXPECT_TRUE(iter != m.end());
+    ++iter;
+  }
+  EXPECT_TRUE(iter == m.end());
+
+  const SmallMap<hash_map<int, int> >& ref = m;
+  EXPECT_TRUE(ref.find(1234) != m.end());
+  EXPECT_TRUE(ref.find(5678) == m.end());
+}
+
+TEST(SmallMap, PostFixIteratorIncrement) {
+  SmallMap<hash_map<int, int> > m;
+  m[0] = 5;
+  m[2] = 3;
+
+  {
+    SmallMap<hash_map<int, int> >::iterator iter(m.begin());
+    SmallMap<hash_map<int, int> >::iterator last(iter++);
+    ++last;
+    EXPECT_TRUE(last == iter);
+  }
+
+  {
+    SmallMap<hash_map<int, int> >::const_iterator iter(m.begin());
+    SmallMap<hash_map<int, int> >::const_iterator last(iter++);
+    ++last;
+    EXPECT_TRUE(last == iter);
+  }
+}
+
+// Based on the General testcase.
+TEST(SmallMap, CopyConstructor) {
+  SmallMap<hash_map<int, int> > src;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_TRUE(m.empty());
+  }
+
+  src[0] = 5;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_FALSE(m.empty());
+    EXPECT_EQ(m.size(), 1u);
+  }
+
+  src[9] = 2;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_FALSE(m.empty());
+    EXPECT_EQ(m.size(), 2u);
+
+    EXPECT_EQ(m[9], 2);
+    EXPECT_EQ(m[0], 5);
+    EXPECT_FALSE(m.UsingFullMap());
+  }
+
+  src[8] = 23;
+  src[1234] = 90;
+  src[-5] = 6;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_EQ(m[   9],  2);
+    EXPECT_EQ(m[   0],  5);
+    EXPECT_EQ(m[1234], 90);
+    EXPECT_EQ(m[   8], 23);
+    EXPECT_EQ(m[  -5],  6);
+    EXPECT_EQ(m.size(), 5u);
+    EXPECT_FALSE(m.empty());
+    EXPECT_TRUE(m.UsingFullMap());
+  }
+}
+
+template<class inner>
+static bool SmallMapIsSubset(SmallMap<inner> const& a,
+                             SmallMap<inner> const& b) {
+  typename SmallMap<inner>::const_iterator it;
+  for (it = a.begin(); it != a.end(); ++it) {
+    typename SmallMap<inner>::const_iterator it_in_b = b.find(it->first);
+    if (it_in_b == b.end() || it_in_b->second != it->second)
+      return false;
+  }
+  return true;
+}
+
+template<class inner>
+static bool SmallMapEqual(SmallMap<inner> const& a,
+                          SmallMap<inner> const& b) {
+  return SmallMapIsSubset(a, b) && SmallMapIsSubset(b, a);
+}
+
+TEST(SmallMap, AssignmentOperator) {
+  SmallMap<hash_map<int, int> > src_small;
+  SmallMap<hash_map<int, int> > src_large;
+
+  src_small[1] = 20;
+  src_small[2] = 21;
+  src_small[3] = 22;
+  EXPECT_FALSE(src_small.UsingFullMap());
+
+  src_large[1] = 20;
+  src_large[2] = 21;
+  src_large[3] = 22;
+  src_large[5] = 23;
+  src_large[6] = 24;
+  src_large[7] = 25;
+  EXPECT_TRUE(src_large.UsingFullMap());
+
+  // Assignments to empty.
+  SmallMap<hash_map<int, int> > dest_small;
+  dest_small = src_small;
+  EXPECT_TRUE(SmallMapEqual(dest_small, src_small));
+  EXPECT_EQ(dest_small.UsingFullMap(),
+            src_small.UsingFullMap());
+
+  SmallMap<hash_map<int, int> > dest_large;
+  dest_large = src_large;
+  EXPECT_TRUE(SmallMapEqual(dest_large, src_large));
+  EXPECT_EQ(dest_large.UsingFullMap(),
+            src_large.UsingFullMap());
+
+  // Assignments which assign from full to small, and vice versa.
+  dest_small = src_large;
+  EXPECT_TRUE(SmallMapEqual(dest_small, src_large));
+  EXPECT_EQ(dest_small.UsingFullMap(),
+            src_large.UsingFullMap());
+
+  dest_large = src_small;
+  EXPECT_TRUE(SmallMapEqual(dest_large, src_small));
+  EXPECT_EQ(dest_large.UsingFullMap(),
+            src_small.UsingFullMap());
+
+  // Double check that SmallMapEqual works:
+  dest_large[42] = 666;
+  EXPECT_FALSE(SmallMapEqual(dest_large, src_small));
+}
+
+TEST(SmallMap, Insert) {
+  SmallMap<hash_map<int, int> > sm;
+
+  // loop through the transition from small map to map.
+  for (int i = 1; i <= 10; ++i) {
+    VLOG(1) << "Iteration " << i;
+    // insert an element
+    std::pair<SmallMap<hash_map<int, int> >::iterator,
+        bool> ret;
+    ret = sm.insert(std::make_pair(i, 100*i));
+    EXPECT_TRUE(ret.second);
+    EXPECT_TRUE(ret.first == sm.find(i));
+    EXPECT_EQ(ret.first->first, i);
+    EXPECT_EQ(ret.first->second, 100*i);
+
+    // try to insert it again with different value, fails, but we still get an
+    // iterator back with the original value.
+    ret = sm.insert(std::make_pair(i, -i));
+    EXPECT_FALSE(ret.second);
+    EXPECT_TRUE(ret.first == sm.find(i));
+    EXPECT_EQ(ret.first->first, i);
+    EXPECT_EQ(ret.first->second, 100*i);
+
+    // check the state of the map.
+    for (int j = 1; j <= i; ++j) {
+      SmallMap<hash_map<int, int> >::iterator it = sm.find(j);
+      EXPECT_TRUE(it != sm.end());
+      EXPECT_EQ(it->first, j);
+      EXPECT_EQ(it->second, j * 100);
+    }
+    EXPECT_EQ(sm.size(), static_cast<size_t>(i));
+    EXPECT_FALSE(sm.empty());
+  }
+}
+
+TEST(SmallMap, InsertRange) {
+  // loop through the transition from small map to map.
+  for (int elements = 0; elements <= 10; ++elements) {
+    VLOG(1) << "Elements " << elements;
+    hash_map<int, int> normal_map;
+    for (int i = 1; i <= elements; ++i) {
+      normal_map.insert(std::make_pair(i, 100*i));
+    }
+
+    SmallMap<hash_map<int, int> > sm;
+    sm.insert(normal_map.begin(), normal_map.end());
+    EXPECT_EQ(normal_map.size(), sm.size());
+    for (int i = 1; i <= elements; ++i) {
+      VLOG(1) << "Iteration " << i;
+      EXPECT_TRUE(sm.find(i) != sm.end());
+      EXPECT_EQ(sm.find(i)->first, i);
+      EXPECT_EQ(sm.find(i)->second, 100*i);
+    }
+  }
+}
+
+TEST(SmallMap, Erase) {
+  SmallMap<hash_map<std::string, int> > m;
+  SmallMap<hash_map<std::string, int> >::iterator iter;
+
+  m["monday"] = 1;
+  m["tuesday"] = 2;
+  m["wednesday"] = 3;
+
+  EXPECT_EQ(m["monday"   ], 1);
+  EXPECT_EQ(m["tuesday"  ], 2);
+  EXPECT_EQ(m["wednesday"], 3);
+  EXPECT_EQ(m.count("tuesday"), 1u);
+  EXPECT_FALSE(m.UsingFullMap());
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "monday");
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "tuesday");
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "wednesday");
+  EXPECT_EQ(iter->second, 3);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  EXPECT_EQ(m.erase("tuesday"), 1u);
+
+  EXPECT_EQ(m["monday"   ], 1);
+  EXPECT_EQ(m["wednesday"], 3);
+  EXPECT_EQ(m.count("tuesday"), 0u);
+  EXPECT_EQ(m.erase("tuesday"), 0u);
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "monday");
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "wednesday");
+  EXPECT_EQ(iter->second, 3);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  m["thursday"] = 4;
+  m["friday"] = 5;
+  EXPECT_EQ(m.size(), 4u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_FALSE(m.UsingFullMap());
+
+  m["saturday"] = 6;
+  EXPECT_TRUE(m.UsingFullMap());
+
+  EXPECT_EQ(m.count("friday"), 1u);
+  EXPECT_EQ(m.erase("friday"), 1u);
+  EXPECT_TRUE(m.UsingFullMap());
+  EXPECT_EQ(m.count("friday"), 0u);
+  EXPECT_EQ(m.erase("friday"), 0u);
+
+  EXPECT_EQ(m.size(), 4u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.erase("monday"), 1u);
+  EXPECT_EQ(m.size(), 3u);
+  EXPECT_FALSE(m.empty());
+
+  m.clear();
+  EXPECT_FALSE(m.UsingFullMap());
+  EXPECT_EQ(m.size(), 0u);
+  EXPECT_TRUE(m.empty());
+}
+
+TEST(SmallMap, NonHashMap) {
+  SmallMap<std::map<int, int>, 4, std::equal_to<int> > m;
+  EXPECT_TRUE(m.empty());
+
+  m[9] = 2;
+  m[0] = 5;
+
+  EXPECT_EQ(m[9], 2);
+  EXPECT_EQ(m[0], 5);
+  EXPECT_EQ(m.size(), 2u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_FALSE(m.UsingFullMap());
+
+  SmallMap<std::map<int, int>, 4, std::equal_to<int> >::iterator iter(
+      m.begin());
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 9);
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+  --iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+
+  m[8] = 23;
+  m[1234] = 90;
+  m[-5] = 6;
+
+  EXPECT_EQ(m[   9],  2);
+  EXPECT_EQ(m[   0],  5);
+  EXPECT_EQ(m[1234], 90);
+  EXPECT_EQ(m[   8], 23);
+  EXPECT_EQ(m[  -5],  6);
+  EXPECT_EQ(m.size(), 5u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_TRUE(m.UsingFullMap());
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, -5);
+  EXPECT_EQ(iter->second, 6);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 8);
+  EXPECT_EQ(iter->second, 23);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 9);
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 1234);
+  EXPECT_EQ(iter->second, 90);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+  --iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 1234);
+  EXPECT_EQ(iter->second, 90);
+}
+
+TEST(SmallMap, DefaultEqualKeyWorks) {
+  // If these tests compile, they pass. The EXPECT calls are only there to avoid
+  // unused variable warnings.
+  SmallMap<hash_map<int, int> > hm;
+  EXPECT_EQ(0u, hm.size());
+  SmallMap<std::map<int, int> > m;
+  EXPECT_EQ(0u, m.size());
+}
+
+namespace {
+
+class hash_map_add_item : public hash_map<int, int> {
+ public:
+  hash_map_add_item() {}
+  explicit hash_map_add_item(const std::pair<int, int>& item) {
+    insert(item);
+  }
+};
+
+void InitMap(ManualConstructor<hash_map_add_item>* map_ctor) {
+  map_ctor->Init(std::make_pair(0, 0));
+}
+
+class hash_map_add_item_initializer {
+ public:
+  explicit hash_map_add_item_initializer(int item_to_add)
+      : item_(item_to_add) {}
+  hash_map_add_item_initializer()
+      : item_(0) {}
+  void operator()(ManualConstructor<hash_map_add_item>* map_ctor) const {
+    map_ctor->Init(std::make_pair(item_, item_));
+  }
+
+  int item_;
+};
+
+}  // anonymous namespace
+
+TEST(SmallMap, SubclassInitializationWithFunctionPointer) {
+  SmallMap<hash_map_add_item, 4, std::equal_to<int>,
+      void (&)(ManualConstructor<hash_map_add_item>*)> m(InitMap);
+
+  EXPECT_TRUE(m.empty());
+
+  m[1] = 1;
+  m[2] = 2;
+  m[3] = 3;
+  m[4] = 4;
+
+  EXPECT_EQ(4u, m.size());
+  EXPECT_EQ(0u, m.count(0));
+
+  m[5] = 5;
+  EXPECT_EQ(6u, m.size());
+  // Our function adds an extra item when we convert to a map.
+  EXPECT_EQ(1u, m.count(0));
+}
+
+TEST(SmallMap, SubclassInitializationWithFunctionObject) {
+  SmallMap<hash_map_add_item, 4, std::equal_to<int>,
+      hash_map_add_item_initializer> m(hash_map_add_item_initializer(-1));
+
+  EXPECT_TRUE(m.empty());
+
+  m[1] = 1;
+  m[2] = 2;
+  m[3] = 3;
+  m[4] = 4;
+
+  EXPECT_EQ(4u, m.size());
+  EXPECT_EQ(0u, m.count(-1));
+
+  m[5] = 5;
+  EXPECT_EQ(6u, m.size());
+  // Our functor adds an extra item when we convert to a map.
+  EXPECT_EQ(1u, m.count(-1));
+}
+
+}  // namespace base
diff --git a/base/containers/stack_container.h b/base/containers/stack_container.h
new file mode 100644
index 0000000..54090d3
--- /dev/null
+++ b/base/containers/stack_container.h
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_STACK_CONTAINER_H_
+#define BASE_CONTAINERS_STACK_CONTAINER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/aligned_memory.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// This allocator can be used with STL containers to provide a stack buffer
+// from which to allocate memory and overflows onto the heap. This stack buffer
+// would be allocated on the stack and allows us to avoid heap operations in
+// some situations.
+//
+// STL likes to make copies of allocators, so the allocator itself can't hold
+// the data. Instead, we make the creator responsible for creating a
+// StackAllocator::Source which contains the data. Copying the allocator
+// merely copies the pointer to this shared source, so all allocators created
+// based on our allocator will share the same stack buffer.
+//
+// This stack buffer implementation is very simple. The first allocation that
+// fits in the stack buffer will use the stack buffer. Any subsequent
+// allocations will not use the stack buffer, even if there is unused room.
+// This makes it appropriate for array-like containers, but the caller should
+// be sure to reserve() in the container up to the stack buffer size. Otherwise
+// the container will allocate a small array which will "use up" the stack
+// buffer.
+template<typename T, size_t stack_capacity>
+class StackAllocator : public std::allocator<T> {
+ public:
+  typedef typename std::allocator<T>::pointer pointer;
+  typedef typename std::allocator<T>::size_type size_type;
+
+  // Backing store for the allocator. The container owner is responsible for
+  // maintaining this for as long as any containers using this allocator are
+  // live.
+  struct Source {
+    Source() : used_stack_buffer_(false) {
+    }
+
+    // Casts the buffer in its right type.
+    T* stack_buffer() { return stack_buffer_.template data_as<T>(); }
+    const T* stack_buffer() const {
+      return stack_buffer_.template data_as<T>();
+    }
+
+    // The buffer itself. It is not of type T because we don't want the
+    // constructors and destructors to be automatically called. Define a POD
+    // buffer of the right size instead.
+    base::AlignedMemory<sizeof(T[stack_capacity]), ALIGNOF(T)> stack_buffer_;
+#if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY)
+    COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612);
+#endif
+
+    // Set when the stack buffer is used for an allocation. We do not track
+    // how much of the buffer is used, only that somebody is using it.
+    bool used_stack_buffer_;
+  };
+
+  // Used by containers when they want to refer to an allocator of type U.
+  template<typename U>
+  struct rebind {
+    typedef StackAllocator<U, stack_capacity> other;
+  };
+
+  // For the straight up copy c-tor, we can share storage.
+  StackAllocator(const StackAllocator<T, stack_capacity>& rhs)
+      : std::allocator<T>(), source_(rhs.source_) {
+  }
+
+  // ISO C++ requires the following constructor to be defined,
+  // and std::vector in VC++2008SP1 Release fails with an error
+  // in the class _Container_base_aux_alloc_real (from <xutility>)
+  // if the constructor does not exist.
+  // For this constructor, we cannot share storage; there's
+  // no guarantee that the Source buffer of Ts is large enough
+  // for Us.
+  // TODO: If we were fancy pants, perhaps we could share storage
+  // iff sizeof(T) == sizeof(U).
+  template<typename U, size_t other_capacity>
+  StackAllocator(const StackAllocator<U, other_capacity>& other)
+      : source_(NULL) {
+  }
+
+  // This constructor must exist. It creates a default allocator that doesn't
+  // actually have a stack buffer. glibc's std::string() will compare the
+  // current allocator against the default-constructed allocator, so this
+  // should be fast.
+  StackAllocator() : source_(NULL) {
+  }
+
+  explicit StackAllocator(Source* source) : source_(source) {
+  }
+
+  // Actually do the allocation. Use the stack buffer if nobody has used it yet
+  // and the size requested fits. Otherwise, fall through to the standard
+  // allocator.
+  pointer allocate(size_type n, void* hint = 0) {
+    if (source_ != NULL && !source_->used_stack_buffer_
+        && n <= stack_capacity) {
+      source_->used_stack_buffer_ = true;
+      return source_->stack_buffer();
+    } else {
+      return std::allocator<T>::allocate(n, hint);
+    }
+  }
+
+  // Free: when trying to free the stack buffer, just mark it as free. For
+  // non-stack-buffer pointers, just fall though to the standard allocator.
+  void deallocate(pointer p, size_type n) {
+    if (source_ != NULL && p == source_->stack_buffer())
+      source_->used_stack_buffer_ = false;
+    else
+      std::allocator<T>::deallocate(p, n);
+  }
+
+ private:
+  Source* source_;
+};
+
+// A wrapper around STL containers that maintains a stack-sized buffer that the
+// initial capacity of the vector is based on. Growing the container beyond the
+// stack capacity will transparently overflow onto the heap. The container must
+// support reserve().
+//
+// WATCH OUT: the ContainerType MUST use the proper StackAllocator for this
+// type. This object is really intended to be used only internally. You'll want
+// to use the wrappers below for different types.
+template<typename TContainerType, int stack_capacity>
+class StackContainer {
+ public:
+  typedef TContainerType ContainerType;
+  typedef typename ContainerType::value_type ContainedType;
+  typedef StackAllocator<ContainedType, stack_capacity> Allocator;
+
+  // Allocator must be constructed before the container!
+  StackContainer() : allocator_(&stack_data_), container_(allocator_) {
+    // Make the container use the stack allocation by reserving our buffer size
+    // before doing anything else.
+    container_.reserve(stack_capacity);
+  }
+
+  // Getters for the actual container.
+  //
+  // Danger: any copies of this made using the copy constructor must have
+  // shorter lifetimes than the source. The copy will share the same allocator
+  // and therefore the same stack buffer as the original. Use std::copy to
+  // copy into a "real" container for longer-lived objects.
+  ContainerType& container() { return container_; }
+  const ContainerType& container() const { return container_; }
+
+  // Support operator-> to get to the container. This allows nicer syntax like:
+  //   StackContainer<...> foo;
+  //   std::sort(foo->begin(), foo->end());
+  ContainerType* operator->() { return &container_; }
+  const ContainerType* operator->() const { return &container_; }
+
+#ifdef UNIT_TEST
+  // Retrieves the stack source so that that unit tests can verify that the
+  // buffer is being used properly.
+  const typename Allocator::Source& stack_data() const {
+    return stack_data_;
+  }
+#endif
+
+ protected:
+  typename Allocator::Source stack_data_;
+  Allocator allocator_;
+  ContainerType container_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackContainer);
+};
+
+// StackString -----------------------------------------------------------------
+
+template<size_t stack_capacity>
+class StackString : public StackContainer<
+    std::basic_string<char,
+                      std::char_traits<char>,
+                      StackAllocator<char, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackString() : StackContainer<
+      std::basic_string<char,
+                        std::char_traits<char>,
+                        StackAllocator<char, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackString);
+};
+
+// StackStrin16 ----------------------------------------------------------------
+
+template<size_t stack_capacity>
+class StackString16 : public StackContainer<
+    std::basic_string<char16,
+                      base::string16_char_traits,
+                      StackAllocator<char16, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackString16() : StackContainer<
+      std::basic_string<char16,
+                        base::string16_char_traits,
+                        StackAllocator<char16, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackString16);
+};
+
+// StackVector -----------------------------------------------------------------
+
+// Example:
+//   StackVector<int, 16> foo;
+//   foo->push_back(22);  // we have overloaded operator->
+//   foo[0] = 10;         // as well as operator[]
+template<typename T, size_t stack_capacity>
+class StackVector : public StackContainer<
+    std::vector<T, StackAllocator<T, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackVector() : StackContainer<
+      std::vector<T, StackAllocator<T, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+  // We need to put this in STL containers sometimes, which requires a copy
+  // constructor. We can't call the regular copy constructor because that will
+  // take the stack buffer from the original. Here, we create an empty object
+  // and make a stack buffer of its own.
+  StackVector(const StackVector<T, stack_capacity>& other)
+      : StackContainer<
+            std::vector<T, StackAllocator<T, stack_capacity> >,
+            stack_capacity>() {
+    this->container().assign(other->begin(), other->end());
+  }
+
+  StackVector<T, stack_capacity>& operator=(
+      const StackVector<T, stack_capacity>& other) {
+    this->container().assign(other->begin(), other->end());
+    return *this;
+  }
+
+  // Vectors are commonly indexed, which isn't very convenient even with
+  // operator-> (using "->at()" does exception stuff we don't want).
+  T& operator[](size_t i) { return this->container().operator[](i); }
+  const T& operator[](size_t i) const {
+    return this->container().operator[](i);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_STACK_CONTAINER_H_
diff --git a/base/containers/stack_container_unittest.cc b/base/containers/stack_container_unittest.cc
new file mode 100644
index 0000000..e6c1914
--- /dev/null
+++ b/base/containers/stack_container_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/stack_container.h"
+
+#include <algorithm>
+
+#include "base/memory/aligned_memory.h"
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class Dummy : public base::RefCounted<Dummy> {
+ public:
+  explicit Dummy(int* alive) : alive_(alive) {
+    ++*alive_;
+  }
+
+ private:
+  friend class base::RefCounted<Dummy>;
+
+  ~Dummy() {
+    --*alive_;
+  }
+
+  int* const alive_;
+};
+
+}  // namespace
+
+TEST(StackContainer, Vector) {
+  const int stack_size = 3;
+  StackVector<int, stack_size> vect;
+  const int* stack_buffer = &vect.stack_data().stack_buffer()[0];
+
+  // The initial |stack_size| elements should appear in the stack buffer.
+  EXPECT_EQ(static_cast<size_t>(stack_size), vect.container().capacity());
+  for (int i = 0; i < stack_size; i++) {
+    vect.container().push_back(i);
+    EXPECT_EQ(stack_buffer, &vect.container()[0]);
+    EXPECT_TRUE(vect.stack_data().used_stack_buffer_);
+  }
+
+  // Adding more elements should push the array onto the heap.
+  for (int i = 0; i < stack_size; i++) {
+    vect.container().push_back(i + stack_size);
+    EXPECT_NE(stack_buffer, &vect.container()[0]);
+    EXPECT_FALSE(vect.stack_data().used_stack_buffer_);
+  }
+
+  // The array should still be in order.
+  for (int i = 0; i < stack_size * 2; i++)
+    EXPECT_EQ(i, vect.container()[i]);
+
+  // Resize to smaller. Our STL implementation won't reallocate in this case,
+  // otherwise it might use our stack buffer. We reserve right after the resize
+  // to guarantee it isn't using the stack buffer, even though it doesn't have
+  // much data.
+  vect.container().resize(stack_size);
+  vect.container().reserve(stack_size * 2);
+  EXPECT_FALSE(vect.stack_data().used_stack_buffer_);
+
+  // Copying the small vector to another should use the same allocator and use
+  // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since
+  // they have to get the template types just right and it can cause errors.
+  std::vector<int, StackAllocator<int, stack_size> > other(vect.container());
+  EXPECT_EQ(stack_buffer, &other.front());
+  EXPECT_TRUE(vect.stack_data().used_stack_buffer_);
+  for (int i = 0; i < stack_size; i++)
+    EXPECT_EQ(i, other[i]);
+}
+
+TEST(StackContainer, VectorDoubleDelete) {
+  // Regression testing for double-delete.
+  typedef StackVector<scoped_refptr<Dummy>, 2> Vector;
+  typedef Vector::ContainerType Container;
+  Vector vect;
+
+  int alive = 0;
+  scoped_refptr<Dummy> dummy(new Dummy(&alive));
+  EXPECT_EQ(alive, 1);
+
+  vect->push_back(dummy);
+  EXPECT_EQ(alive, 1);
+
+  Dummy* dummy_unref = dummy.get();
+  dummy = NULL;
+  EXPECT_EQ(alive, 1);
+
+  Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref);
+  EXPECT_EQ(itr->get(), dummy_unref);
+  vect->erase(itr);
+  EXPECT_EQ(alive, 0);
+
+  // Shouldn't crash at exit.
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() { memset(data_.void_data(), 0, alignment); }
+  ~AlignedData() {}
+  base::AlignedMemory<alignment, alignment> data_;
+};
+
+}  // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(StackContainer, BufferAlignment) {
+  StackVector<wchar_t, 16> text;
+  text->push_back(L'A');
+  EXPECT_ALIGNED(&text[0], ALIGNOF(wchar_t));
+
+  StackVector<double, 1> doubles;
+  doubles->push_back(0.0);
+  EXPECT_ALIGNED(&doubles[0], ALIGNOF(double));
+
+  StackVector<AlignedData<16>, 1> aligned16;
+  aligned16->push_back(AlignedData<16>());
+  EXPECT_ALIGNED(&aligned16[0], 16);
+
+#if !defined(__GNUC__) || defined(ARCH_CPU_X86_FAMILY)
+  // It seems that non-X86 gcc doesn't respect greater than 16 byte alignment.
+  // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33721 for details.
+  // TODO(sbc):re-enable this if GCC starts respecting higher alignments.
+  StackVector<AlignedData<256>, 1> aligned256;
+  aligned256->push_back(AlignedData<256>());
+  EXPECT_ALIGNED(&aligned256[0], 256);
+#endif
+}
+
+template class StackVector<int, 2>;
+template class StackVector<scoped_refptr<Dummy>, 2>;
+
+}  // namespace base
diff --git a/base/cpu.cc b/base/cpu.cc
new file mode 100644
index 0000000..ef3309d
--- /dev/null
+++ b/base/cpu.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cpu.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#endif
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#if defined(_MSC_VER)
+#include <intrin.h>
+#include <immintrin.h>  // For _xgetbv()
+#endif
+#endif
+
+namespace base {
+
+CPU::CPU()
+  : signature_(0),
+    type_(0),
+    family_(0),
+    model_(0),
+    stepping_(0),
+    ext_model_(0),
+    ext_family_(0),
+    has_mmx_(false),
+    has_sse_(false),
+    has_sse2_(false),
+    has_sse3_(false),
+    has_ssse3_(false),
+    has_sse41_(false),
+    has_sse42_(false),
+    has_avx_(false),
+    has_avx_hardware_(false),
+    has_aesni_(false),
+    has_non_stop_time_stamp_counter_(false),
+    has_broken_neon_(false),
+    cpu_vendor_("unknown") {
+  Initialize();
+}
+
+namespace {
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#ifndef _MSC_VER
+
+#if defined(__pic__) && defined(__i386__)
+
+void __cpuid(int cpu_info[4], int info_type) {
+  __asm__ volatile (
+    "mov %%ebx, %%edi\n"
+    "cpuid\n"
+    "xchg %%edi, %%ebx\n"
+    : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+    : "a"(info_type)
+  );
+}
+
+#else
+
+void __cpuid(int cpu_info[4], int info_type) {
+  __asm__ volatile (
+    "cpuid \n\t"
+    : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+    : "a"(info_type)
+  );
+}
+
+#endif
+
+// _xgetbv returns the value of an Intel Extended Control Register (XCR).
+// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
+uint64 _xgetbv(uint32 xcr) {
+  uint32 eax, edx;
+
+  __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
+  return (static_cast<uint64>(edx) << 32) | eax;
+}
+
+#endif  // !_MSC_VER
+#endif  // ARCH_CPU_X86_FAMILY
+
+#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+class LazyCpuInfoValue {
+ public:
+  LazyCpuInfoValue() : has_broken_neon_(false) {
+    // This function finds the value from /proc/cpuinfo under the key "model
+    // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
+    // and later for arm64) and is shown once per CPU. "Processor" is used in
+    // earler versions and is shown only once at the top of /proc/cpuinfo
+    // regardless of the number CPUs.
+    const char kModelNamePrefix[] = "model name\t: ";
+    const char kProcessorPrefix[] = "Processor\t: ";
+
+    // This function also calculates whether we believe that this CPU has a
+    // broken NEON unit based on these fields from cpuinfo:
+    unsigned implementer = 0, architecture = 0, variant = 0, part = 0,
+             revision = 0;
+    const struct {
+      const char key[17];
+      unsigned *result;
+    } kUnsignedValues[] = {
+      {"CPU implementer", &implementer},
+      {"CPU architecture", &architecture},
+      {"CPU variant", &variant},
+      {"CPU part", &part},
+      {"CPU revision", &revision},
+    };
+
+    std::string contents;
+    ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
+    DCHECK(!contents.empty());
+    if (contents.empty()) {
+      return;
+    }
+
+    std::istringstream iss(contents);
+    std::string line;
+    while (std::getline(iss, line)) {
+      if (brand_.empty() &&
+          (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 ||
+           line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) {
+        brand_.assign(line.substr(strlen(kModelNamePrefix)));
+      }
+
+      for (size_t i = 0; i < arraysize(kUnsignedValues); i++) {
+        const char *key = kUnsignedValues[i].key;
+        const size_t len = strlen(key);
+
+        if (line.compare(0, len, key) == 0 &&
+            line.size() >= len + 1 &&
+            (line[len] == '\t' || line[len] == ' ' || line[len] == ':')) {
+          size_t colon_pos = line.find(':', len);
+          if (colon_pos == std::string::npos) {
+            continue;
+          }
+
+          const StringPiece line_sp(line);
+          StringPiece value_sp = line_sp.substr(colon_pos + 1);
+          while (!value_sp.empty() &&
+                 (value_sp[0] == ' ' || value_sp[0] == '\t')) {
+            value_sp = value_sp.substr(1);
+          }
+
+          // The string may have leading "0x" or not, so we use strtoul to
+          // handle that.
+          char *endptr;
+          std::string value(value_sp.as_string());
+          unsigned long int result = strtoul(value.c_str(), &endptr, 0);
+          if (*endptr == 0 && result <= UINT_MAX) {
+            *kUnsignedValues[i].result = result;
+          }
+        }
+      }
+    }
+
+    has_broken_neon_ =
+      implementer == 0x51 &&
+      architecture == 7 &&
+      variant == 1 &&
+      part == 0x4d &&
+      revision == 0;
+  }
+
+  const std::string& brand() const { return brand_; }
+  bool has_broken_neon() const { return has_broken_neon_; }
+
+ private:
+  std::string brand_;
+  bool has_broken_neon_;
+  DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
+};
+
+base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo =
+    LAZY_INSTANCE_INITIALIZER;
+
+#endif  // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
+        // defined(OS_LINUX))
+
+}  // anonymous namespace
+
+void CPU::Initialize() {
+#if defined(ARCH_CPU_X86_FAMILY)
+  int cpu_info[4] = {-1};
+  char cpu_string[48];
+
+  // __cpuid with an InfoType argument of 0 returns the number of
+  // valid Ids in CPUInfo[0] and the CPU identification string in
+  // the other three array elements. The CPU identification string is
+  // not in linear order. The code below arranges the information
+  // in a human readable form. The human readable order is CPUInfo[1] |
+  // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
+  // before using memcpy to copy these three array elements to cpu_string.
+  __cpuid(cpu_info, 0);
+  int num_ids = cpu_info[0];
+  std::swap(cpu_info[2], cpu_info[3]);
+  memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1]));
+  cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1]));
+
+  // Interpret CPU feature information.
+  if (num_ids > 0) {
+    __cpuid(cpu_info, 1);
+    signature_ = cpu_info[0];
+    stepping_ = cpu_info[0] & 0xf;
+    model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
+    family_ = (cpu_info[0] >> 8) & 0xf;
+    type_ = (cpu_info[0] >> 12) & 0x3;
+    ext_model_ = (cpu_info[0] >> 16) & 0xf;
+    ext_family_ = (cpu_info[0] >> 20) & 0xff;
+    has_mmx_ =   (cpu_info[3] & 0x00800000) != 0;
+    has_sse_ =   (cpu_info[3] & 0x02000000) != 0;
+    has_sse2_ =  (cpu_info[3] & 0x04000000) != 0;
+    has_sse3_ =  (cpu_info[2] & 0x00000001) != 0;
+    has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
+    has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
+    has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
+    has_avx_hardware_ =
+                 (cpu_info[2] & 0x10000000) != 0;
+    // AVX instructions will generate an illegal instruction exception unless
+    //   a) they are supported by the CPU,
+    //   b) XSAVE is supported by the CPU and
+    //   c) XSAVE is enabled by the kernel.
+    // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
+    //
+    // In addition, we have observed some crashes with the xgetbv instruction
+    // even after following Intel's example code. (See crbug.com/375968.)
+    // Because of that, we also test the XSAVE bit because its description in
+    // the CPUID documentation suggests that it signals xgetbv support.
+    has_avx_ =
+        has_avx_hardware_ &&
+        (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
+        (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
+        (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
+    has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
+  }
+
+  // Get the brand string of the cpu.
+  __cpuid(cpu_info, 0x80000000);
+  const int parameter_end = 0x80000004;
+  int max_parameter = cpu_info[0];
+
+  if (cpu_info[0] >= parameter_end) {
+    char* cpu_string_ptr = cpu_string;
+
+    for (int parameter = 0x80000002; parameter <= parameter_end &&
+         cpu_string_ptr < &cpu_string[sizeof(cpu_string)]; parameter++) {
+      __cpuid(cpu_info, parameter);
+      memcpy(cpu_string_ptr, cpu_info, sizeof(cpu_info));
+      cpu_string_ptr += sizeof(cpu_info);
+    }
+    cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string);
+  }
+
+  const int parameter_containing_non_stop_time_stamp_counter = 0x80000007;
+  if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) {
+    __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
+    has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
+  }
+#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+  cpu_brand_.assign(g_lazy_cpuinfo.Get().brand());
+  has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon();
+#endif
+}
+
+CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
+  if (has_avx()) return AVX;
+  if (has_sse42()) return SSE42;
+  if (has_sse41()) return SSE41;
+  if (has_ssse3()) return SSSE3;
+  if (has_sse3()) return SSE3;
+  if (has_sse2()) return SSE2;
+  if (has_sse()) return SSE;
+  return PENTIUM;
+}
+
+}  // namespace base
diff --git a/base/cpu.h b/base/cpu.h
new file mode 100644
index 0000000..0c809f0
--- /dev/null
+++ b/base/cpu.h
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CPU_H_
+#define BASE_CPU_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Query information about the processor.
+class BASE_EXPORT CPU {
+ public:
+  // Constructor
+  CPU();
+
+  enum IntelMicroArchitecture {
+    PENTIUM,
+    SSE,
+    SSE2,
+    SSE3,
+    SSSE3,
+    SSE41,
+    SSE42,
+    AVX,
+    MAX_INTEL_MICRO_ARCHITECTURE
+  };
+
+  // Accessors for CPU information.
+  const std::string& vendor_name() const { return cpu_vendor_; }
+  int signature() const { return signature_; }
+  int stepping() const { return stepping_; }
+  int model() const { return model_; }
+  int family() const { return family_; }
+  int type() const { return type_; }
+  int extended_model() const { return ext_model_; }
+  int extended_family() const { return ext_family_; }
+  bool has_mmx() const { return has_mmx_; }
+  bool has_sse() const { return has_sse_; }
+  bool has_sse2() const { return has_sse2_; }
+  bool has_sse3() const { return has_sse3_; }
+  bool has_ssse3() const { return has_ssse3_; }
+  bool has_sse41() const { return has_sse41_; }
+  bool has_sse42() const { return has_sse42_; }
+  bool has_avx() const { return has_avx_; }
+  // has_avx_hardware returns true when AVX is present in the CPU. This might
+  // differ from the value of |has_avx()| because |has_avx()| also tests for
+  // operating system support needed to actually call AVX instuctions.
+  // Note: you should never need to call this function. It was added in order
+  // to workaround a bug in NSS but |has_avx()| is what you want.
+  bool has_avx_hardware() const { return has_avx_hardware_; }
+  bool has_aesni() const { return has_aesni_; }
+  bool has_non_stop_time_stamp_counter() const {
+    return has_non_stop_time_stamp_counter_;
+  }
+  // has_broken_neon is only valid on ARM chips. If true, it indicates that we
+  // believe that the NEON unit on the current CPU is flawed and cannot execute
+  // some code. See https://code.google.com/p/chromium/issues/detail?id=341598
+  bool has_broken_neon() const { return has_broken_neon_; }
+
+  IntelMicroArchitecture GetIntelMicroArchitecture() const;
+  const std::string& cpu_brand() const { return cpu_brand_; }
+
+ private:
+  // Query the processor for CPUID information.
+  void Initialize();
+
+  int signature_;  // raw form of type, family, model, and stepping
+  int type_;  // process type
+  int family_;  // family of the processor
+  int model_;  // model of processor
+  int stepping_;  // processor revision number
+  int ext_model_;
+  int ext_family_;
+  bool has_mmx_;
+  bool has_sse_;
+  bool has_sse2_;
+  bool has_sse3_;
+  bool has_ssse3_;
+  bool has_sse41_;
+  bool has_sse42_;
+  bool has_avx_;
+  bool has_avx_hardware_;
+  bool has_aesni_;
+  bool has_non_stop_time_stamp_counter_;
+  bool has_broken_neon_;
+  std::string cpu_vendor_;
+  std::string cpu_brand_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CPU_H_
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc
new file mode 100644
index 0000000..18bf959
--- /dev/null
+++ b/base/cpu_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cpu.h"
+#include "build/build_config.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests whether we can run extended instructions represented by the CPU
+// information. This test actually executes some extended instructions (such as
+// MMX, SSE, etc.) supported by the CPU and sees we can run them without
+// "undefined instruction" exceptions. That is, this test succeeds when this
+// test finishes without a crash.
+TEST(CPU, RunExtendedInstructions) {
+#if defined(ARCH_CPU_X86_FAMILY)
+  // Retrieve the CPU information.
+  base::CPU cpu;
+
+// TODO(jschuh): crbug.com/168866 Find a way to enable this on Win64.
+#if defined(OS_WIN) && !defined(_M_X64)
+  ASSERT_TRUE(cpu.has_mmx());
+
+  // Execute an MMX instruction.
+  __asm emms;
+
+  if (cpu.has_sse()) {
+    // Execute an SSE instruction.
+    __asm xorps xmm0, xmm0;
+  }
+
+  if (cpu.has_sse2()) {
+    // Execute an SSE 2 instruction.
+    __asm psrldq xmm0, 0;
+  }
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm addsubpd xmm0, xmm0;
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm psignb xmm0, xmm0;
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm pmuldq xmm0, xmm0;
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm crc32 eax, eax;
+  }
+#elif defined(OS_POSIX) && defined(__x86_64__)
+  ASSERT_TRUE(cpu.has_mmx());
+
+  // Execute an MMX instruction.
+  __asm__ __volatile__("emms\n" : : : "mm0");
+
+  if (cpu.has_sse()) {
+    // Execute an SSE instruction.
+    __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse2()) {
+    // Execute an SSE 2 instruction.
+    __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
+  }
+#endif
+#endif
+}
diff --git a/base/critical_closure.h b/base/critical_closure.h
new file mode 100644
index 0000000..75e3704
--- /dev/null
+++ b/base/critical_closure.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CRITICAL_CLOSURE_H_
+#define BASE_CRITICAL_CLOSURE_H_
+
+#include "base/callback.h"
+
+#if defined(OS_IOS)
+#include "base/bind.h"
+#include "base/ios/scoped_critical_action.h"
+#endif
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_IOS)
+// Returns true if multi-tasking is supported on this iOS device.
+bool IsMultiTaskingSupported();
+
+// This class wraps a closure so it can continue to run for a period of time
+// when the application goes to the background by using
+// |ios::ScopedCriticalAction|.
+template <typename R>
+class CriticalClosure {
+ public:
+  explicit CriticalClosure(const Callback<R(void)>& closure)
+      : closure_(closure) {}
+
+  ~CriticalClosure() {}
+
+  R Run() {
+    return closure_.Run();
+  }
+
+ private:
+  ios::ScopedCriticalAction critical_action_;
+  Callback<R(void)> closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(CriticalClosure);
+};
+#endif  // defined(OS_IOS)
+
+}  // namespace internal
+
+// Returns a closure (which may return a result, but must not require any extra
+// arguments) that will continue to run for a period of time when the
+// application goes to the background if possible on platforms where
+// applications don't execute while backgrounded, otherwise the original task is
+// returned.
+//
+// Example:
+//   file_task_runner_->PostTask(
+//       FROM_HERE,
+//       MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
+//
+// Note new closures might be posted in this closure. If the new closures need
+// background running time, |MakeCriticalClosure| should be applied on them
+// before posting.
+#if defined(OS_IOS)
+template <typename R>
+Callback<R(void)> MakeCriticalClosure(const Callback<R(void)>& closure) {
+  DCHECK(internal::IsMultiTaskingSupported());
+  return base::Bind(&internal::CriticalClosure<R>::Run,
+                    Owned(new internal::CriticalClosure<R>(closure)));
+}
+#else  // defined(OS_IOS)
+template <typename R>
+inline Callback<R(void)> MakeCriticalClosure(const Callback<R(void)>& closure) {
+  // No-op for platforms where the application does not need to acquire
+  // background time for closures to finish when it goes into the background.
+  return closure;
+}
+#endif  // defined(OS_IOS)
+
+}  // namespace base
+
+#endif  // BASE_CRITICAL_CLOSURE_H_
diff --git a/base/critical_closure_internal_ios.mm b/base/critical_closure_internal_ios.mm
new file mode 100644
index 0000000..b8fec14
--- /dev/null
+++ b/base/critical_closure_internal_ios.mm
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/critical_closure.h"
+
+#import <UIKit/UIKit.h>
+
+namespace base {
+namespace internal {
+
+bool IsMultiTaskingSupported() {
+  return [[UIDevice currentDevice] isMultitaskingSupported];
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/debug/BUILD.gn b/base/debug/BUILD.gn
new file mode 100644
index 0000000..8ed623b
--- /dev/null
+++ b/base/debug/BUILD.gn
@@ -0,0 +1,76 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("debug") {
+  sources = [
+    "alias.cc",
+    "alias.h",
+    "asan_invalid_access.cc",
+    "asan_invalid_access.h",
+    "crash_logging.cc",
+    "crash_logging.h",
+    "debugger.cc",
+    "debugger.h",
+    "debugger_posix.cc",
+    "debugger_win.cc",
+    "dump_without_crashing.cc",
+    "dump_without_crashing.h",
+    "gdi_debug_util_win.cc",
+    "gdi_debug_util_win.h",
+
+    # This file depends on files from the "allocator" target,
+    # but this target does not depend on "allocator" (see
+    # allocator.gyp for details).
+    "leak_annotations.h",
+    "leak_tracker.h",
+    "proc_maps_linux.cc",
+    "proc_maps_linux.h",
+    "profiler.cc",
+    "profiler.h",
+    "stack_trace.cc",
+    "stack_trace.h",
+    "stack_trace_android.cc",
+    "stack_trace_posix.cc",
+    "stack_trace_win.cc",
+    "task_annotator.cc",
+    "task_annotator.h",
+  ]
+
+  if (is_android) {
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [ "proc_maps_linux.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    sources -= [ "stack_trace_posix.cc" ]
+  }
+
+  if (is_nacl) {
+    sources -= [
+      "crash_logging.cc",
+      "crash_logging.h",
+      "stack_trace.cc",
+      "stack_trace_posix.cc",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/memory",
+    "//base/process",
+  ]
+
+  if (is_linux) {
+    defines = [ "USE_SYMBOLIZE" ]
+    deps += [ "//base/third_party/symbolize" ]
+  }
+
+  allow_circular_includes_from = [
+    "//base/memory",
+    "//base/process",
+  ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/debug/OWNERS b/base/debug/OWNERS
new file mode 100644
index 0000000..4976ab1
--- /dev/null
+++ b/base/debug/OWNERS
@@ -0,0 +1,3 @@
+per-file trace_event*=nduca@chromium.org
+per-file trace_event*=dsinclair@chromium.org
+per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/debug/alias.cc b/base/debug/alias.cc
new file mode 100644
index 0000000..6b0caaa
--- /dev/null
+++ b/base/debug/alias.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/alias.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace debug {
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", off)
+#endif
+
+void Alias(const void* var) {
+}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/alias.h b/base/debug/alias.h
new file mode 100644
index 0000000..3b2ab64
--- /dev/null
+++ b/base/debug/alias.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_ALIAS_H_
+#define BASE_DEBUG_ALIAS_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Make the optimizer think that var is aliased. This is to prevent it from
+// optimizing out variables that that would not otherwise be live at the point
+// of a potential crash.
+void BASE_EXPORT Alias(const void* var);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_ALIAS_H_
diff --git a/base/debug/asan_invalid_access.cc b/base/debug/asan_invalid_access.cc
new file mode 100644
index 0000000..cee2106
--- /dev/null
+++ b/base/debug/asan_invalid_access.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/debug/alias.h"
+#include "base/debug/asan_invalid_access.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+#if defined(SYZYASAN) && defined(COMPILER_MSVC)
+// Disable warning C4530: "C++ exception handler used, but unwind semantics are
+// not enabled". We don't want to change the compilation flags just for this
+// test, and no exception should be triggered here, so this warning has no value
+// here.
+#pragma warning(push)
+#pragma warning(disable: 4530)
+// Corrupt a memory block and make sure that the corruption gets detected either
+// when we free it or when another crash happens (if |induce_crash| is set to
+// true).
+NOINLINE void CorruptMemoryBlock(bool induce_crash) {
+  // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to
+  //     trigger an Address Sanitizer (ASAN) error report.
+  static const int kArraySize = 5;
+  int* array = new int[kArraySize];
+  // Encapsulate the invalid memory access into a try-catch statement to prevent
+  // this function from being instrumented. This way the underflow won't be
+  // detected but the corruption will (as the allocator will still be hooked).
+  try {
+    // Declares the dummy value as volatile to make sure it doesn't get
+    // optimized away.
+    int volatile dummy = array[-1]--;
+    base::debug::Alias(const_cast<int*>(&dummy));
+  } catch (...) {
+  }
+  if (induce_crash)
+    CHECK(false);
+  delete[] array;
+}
+#pragma warning(pop)
+#endif  // SYZYASAN && COMPILER_MSVC
+
+}  // namespace
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+// NOTE(sebmarchand): We intentionally perform some invalid heap access here in
+//     order to trigger an AddressSanitizer (ASan) error report.
+
+static const size_t kArraySize = 5;
+
+void AsanHeapOverflow() {
+  scoped_ptr<int[]> array(new int[kArraySize]);
+  // Declares the dummy value as volatile to make sure it doesn't get optimized
+  // away.
+  int volatile dummy = 0;
+  dummy = array[kArraySize];
+  base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+void AsanHeapUnderflow() {
+  scoped_ptr<int[]> array(new int[kArraySize]);
+  // Declares the dummy value as volatile to make sure it doesn't get optimized
+  // away.
+  int volatile dummy = 0;
+  // We need to store the underflow address in a temporary variable as trying to
+  // access array[-1] will trigger a warning C4245: "conversion from 'int' to
+  // 'size_t', signed/unsigned mismatch".
+  int* underflow_address = &array[0] - 1;
+  dummy = *underflow_address;
+  base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+void AsanHeapUseAfterFree() {
+  scoped_ptr<int[]> array(new int[kArraySize]);
+  // Declares the dummy value as volatile to make sure it doesn't get optimized
+  // away.
+  int volatile dummy = 0;
+  int* dangling = array.get();
+  array.reset();
+  dummy = dangling[kArraySize / 2];
+  base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+
+#if defined(SYZYASAN) && defined(COMPILER_MSVC)
+void AsanCorruptHeapBlock() {
+  CorruptMemoryBlock(false);
+}
+
+void AsanCorruptHeap() {
+  CorruptMemoryBlock(true);
+}
+#endif  // SYZYASAN && COMPILER_MSVC
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/asan_invalid_access.h b/base/debug/asan_invalid_access.h
new file mode 100644
index 0000000..bc9390e
--- /dev/null
+++ b/base/debug/asan_invalid_access.h
@@ -0,0 +1,47 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Defines some functions that intentionally do an invalid memory access in
+// order to trigger an AddressSanitizer (ASan) error report.
+
+#ifndef BASE_DEBUG_ASAN_INVALID_ACCESS_H_
+#define BASE_DEBUG_ASAN_INVALID_ACCESS_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace debug {
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+// Generates an heap buffer overflow.
+BASE_EXPORT NOINLINE void AsanHeapOverflow();
+
+// Generates an heap buffer underflow.
+BASE_EXPORT NOINLINE void AsanHeapUnderflow();
+
+// Generates an use after free.
+BASE_EXPORT NOINLINE void AsanHeapUseAfterFree();
+
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+
+// The "corrupt-block" and "corrupt-heap" classes of bugs is specific to
+// SyzyASan.
+#if defined(SYZYASAN) && defined(COMPILER_MSVC)
+
+// Corrupts a memory block and makes sure that the corruption gets detected when
+// we try to free this block.
+BASE_EXPORT NOINLINE void AsanCorruptHeapBlock();
+
+// Corrupts the heap and makes sure that the corruption gets detected when a
+// crash occur.
+BASE_EXPORT NOINLINE void AsanCorruptHeap();
+
+#endif  // SYZYASAN && COMPILER_MSVC
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_ASAN_INVALID_ACCESS_H_
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
new file mode 100644
index 0000000..f9b4449
--- /dev/null
+++ b/base/debug/crash_logging.cc
@@ -0,0 +1,203 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/crash_logging.h"
+
+#include <cmath>
+#include <map>
+
+#include "base/debug/stack_trace.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Global map of crash key names to registration entries.
+typedef std::map<base::StringPiece, CrashKey> CrashKeyMap;
+CrashKeyMap* g_crash_keys_ = NULL;
+
+// The maximum length of a single chunk.
+size_t g_chunk_max_length_ = 0;
+
+// String used to format chunked key names.
+const char kChunkFormatString[] = "%s-%" PRIuS;
+
+// The functions that are called to actually set the key-value pairs in the
+// crash reportng system.
+SetCrashKeyValueFuncT g_set_key_func_ = NULL;
+ClearCrashKeyValueFuncT g_clear_key_func_ = NULL;
+
+// For a given |length|, computes the number of chunks a value of that size
+// will occupy.
+size_t NumChunksForLength(size_t length) {
+  // Compute (length / g_chunk_max_length_), rounded up.
+  return (length + g_chunk_max_length_ - 1) / g_chunk_max_length_;
+}
+
+// The longest max_length allowed by the system.
+const size_t kLargestValueAllowed = 1024;
+
+}  // namespace
+
+void SetCrashKeyValue(const base::StringPiece& key,
+                      const base::StringPiece& value) {
+  if (!g_set_key_func_ || !g_crash_keys_)
+    return;
+
+  const CrashKey* crash_key = LookupCrashKey(key);
+
+  DCHECK(crash_key) << "All crash keys must be registered before use "
+                    << "(key = " << key << ")";
+
+  // Handle the un-chunked case.
+  if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
+    g_set_key_func_(key, value);
+    return;
+  }
+
+  // Unset the unused chunks.
+  std::vector<std::string> chunks =
+      ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_);
+  for (size_t i = chunks.size();
+       i < NumChunksForLength(crash_key->max_length);
+       ++i) {
+    g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
+  }
+
+  // Set the chunked keys.
+  for (size_t i = 0; i < chunks.size(); ++i) {
+    g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1),
+                    chunks[i]);
+  }
+}
+
+void ClearCrashKey(const base::StringPiece& key) {
+  if (!g_clear_key_func_ || !g_crash_keys_)
+    return;
+
+  const CrashKey* crash_key = LookupCrashKey(key);
+
+  // Handle the un-chunked case.
+  if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
+    g_clear_key_func_(key);
+    return;
+  }
+
+  for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) {
+    g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
+  }
+}
+
+void SetCrashKeyToStackTrace(const base::StringPiece& key,
+                             const StackTrace& trace) {
+  size_t count = 0;
+  const void* const* addresses = trace.Addresses(&count);
+  SetCrashKeyFromAddresses(key, addresses, count);
+}
+
+void SetCrashKeyFromAddresses(const base::StringPiece& key,
+                              const void* const* addresses,
+                              size_t count) {
+  std::string value = "<null>";
+  if (addresses && count) {
+    const size_t kBreakpadValueMax = 255;
+
+    std::vector<std::string> hex_backtrace;
+    size_t length = 0;
+
+    for (size_t i = 0; i < count; ++i) {
+      std::string s = base::StringPrintf("%p", addresses[i]);
+      length += s.length() + 1;
+      if (length > kBreakpadValueMax)
+        break;
+      hex_backtrace.push_back(s);
+    }
+
+    value = JoinString(hex_backtrace, ' ');
+
+    // Warn if this exceeds the breakpad limits.
+    DCHECK_LE(value.length(), kBreakpadValueMax);
+  }
+
+  SetCrashKeyValue(key, value);
+}
+
+ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key,
+                               const base::StringPiece& value)
+    : key_(key.as_string()) {
+  SetCrashKeyValue(key, value);
+}
+
+ScopedCrashKey::~ScopedCrashKey() {
+  ClearCrashKey(key_);
+}
+
+size_t InitCrashKeys(const CrashKey* const keys, size_t count,
+                     size_t chunk_max_length) {
+  DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once";
+  if (!keys) {
+    delete g_crash_keys_;
+    g_crash_keys_ = NULL;
+    return 0;
+  }
+
+  g_crash_keys_ = new CrashKeyMap;
+  g_chunk_max_length_ = chunk_max_length;
+
+  size_t total_keys = 0;
+  for (size_t i = 0; i < count; ++i) {
+    g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i]));
+    total_keys += NumChunksForLength(keys[i].max_length);
+    DCHECK_LT(keys[i].max_length, kLargestValueAllowed);
+  }
+  DCHECK_EQ(count, g_crash_keys_->size())
+      << "Duplicate crash keys were registered";
+
+  return total_keys;
+}
+
+const CrashKey* LookupCrashKey(const base::StringPiece& key) {
+  if (!g_crash_keys_)
+    return NULL;
+  CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string());
+  if (it == g_crash_keys_->end())
+    return NULL;
+  return &(it->second);
+}
+
+void SetCrashKeyReportingFunctions(
+    SetCrashKeyValueFuncT set_key_func,
+    ClearCrashKeyValueFuncT clear_key_func) {
+  g_set_key_func_ = set_key_func;
+  g_clear_key_func_ = clear_key_func;
+}
+
+std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key,
+                                            const base::StringPiece& value,
+                                            size_t chunk_max_length) {
+  std::string value_string = value.substr(0, crash_key.max_length).as_string();
+  std::vector<std::string> chunks;
+  for (size_t offset = 0; offset < value_string.length(); ) {
+    std::string chunk = value_string.substr(offset, chunk_max_length);
+    chunks.push_back(chunk);
+    offset += chunk.length();
+  }
+  return chunks;
+}
+
+void ResetCrashLoggingForTesting() {
+  delete g_crash_keys_;
+  g_crash_keys_ = NULL;
+  g_chunk_max_length_ = 0;
+  g_set_key_func_ = NULL;
+  g_clear_key_func_ = NULL;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
new file mode 100644
index 0000000..90e6687
--- /dev/null
+++ b/base/debug/crash_logging.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_CRASH_LOGGING_H_
+#define BASE_DEBUG_CRASH_LOGGING_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+// These functions add metadata to the upload payload when sending crash reports
+// to the crash server.
+//
+// IMPORTANT: On OS X and Linux, the key/value pairs are only sent as part of
+// the upload and are not included in the minidump!
+
+namespace base {
+namespace debug {
+
+class StackTrace;
+
+// Set or clear a specific key-value pair from the crash metadata. Keys and
+// values are terminated at the null byte.
+BASE_EXPORT void SetCrashKeyValue(const base::StringPiece& key,
+                                  const base::StringPiece& value);
+BASE_EXPORT void ClearCrashKey(const base::StringPiece& key);
+
+// Records the given StackTrace into a crash key.
+BASE_EXPORT void SetCrashKeyToStackTrace(const base::StringPiece& key,
+                                         const StackTrace& trace);
+
+// Formats |count| instruction pointers from |addresses| using %p and
+// sets the resulting string as a value for crash key |key|. A maximum of 23
+// items will be encoded, since breakpad limits values to 255 bytes.
+BASE_EXPORT void SetCrashKeyFromAddresses(const base::StringPiece& key,
+                                          const void* const* addresses,
+                                          size_t count);
+
+// A scoper that sets the specified key to value for the lifetime of the
+// object, and clears it on destruction.
+class BASE_EXPORT ScopedCrashKey {
+ public:
+  ScopedCrashKey(const base::StringPiece& key, const base::StringPiece& value);
+  ~ScopedCrashKey();
+
+ private:
+  std::string key_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCrashKey);
+};
+
+// Before setting values for a key, all the keys must be registered.
+struct BASE_EXPORT CrashKey {
+  // The name of the crash key, used in the above functions.
+  const char* key_name;
+
+  // The maximum length for a value. If the value is longer than this, it will
+  // be truncated. If the value is larger than the |chunk_max_length| passed to
+  // InitCrashKeys() but less than this value, it will be split into multiple
+  // numbered chunks.
+  size_t max_length;
+};
+
+// Before the crash key logging mechanism can be used, all crash keys must be
+// registered with this function. The function returns the amount of space
+// the crash reporting implementation should allocate space for the registered
+// crash keys. |chunk_max_length| is the maximum size that a value in a single
+// chunk can be.
+BASE_EXPORT size_t InitCrashKeys(const CrashKey* const keys, size_t count,
+                                 size_t chunk_max_length);
+
+// Returns the correspnding crash key object or NULL for a given key.
+BASE_EXPORT const CrashKey* LookupCrashKey(const base::StringPiece& key);
+
+// In the platform crash reporting implementation, these functions set and
+// clear the NUL-termianted key-value pairs.
+typedef void (*SetCrashKeyValueFuncT)(const base::StringPiece&,
+                                      const base::StringPiece&);
+typedef void (*ClearCrashKeyValueFuncT)(const base::StringPiece&);
+
+// Sets the function pointers that are used to integrate with the platform-
+// specific crash reporting libraries.
+BASE_EXPORT void SetCrashKeyReportingFunctions(
+    SetCrashKeyValueFuncT set_key_func,
+    ClearCrashKeyValueFuncT clear_key_func);
+
+// Helper function that breaks up a value according to the parameters
+// specified by the crash key object.
+BASE_EXPORT std::vector<std::string> ChunkCrashKeyValue(
+    const CrashKey& crash_key,
+    const base::StringPiece& value,
+    size_t chunk_max_length);
+
+// Resets the crash key system so it can be reinitialized. For testing only.
+BASE_EXPORT void ResetCrashLoggingForTesting();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_CRASH_LOGGING_H_
diff --git a/base/debug/crash_logging_unittest.cc b/base/debug/crash_logging_unittest.cc
new file mode 100644
index 0000000..4cd9f3e
--- /dev/null
+++ b/base/debug/crash_logging_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/crash_logging.h"
+
+#include <map>
+#include <string>
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+std::map<std::string, std::string>* key_values_ = NULL;
+
+}  // namespace
+
+class CrashLoggingTest : public testing::Test {
+ public:
+  void SetUp() override {
+    key_values_ = new std::map<std::string, std::string>;
+    base::debug::SetCrashKeyReportingFunctions(
+        &CrashLoggingTest::SetKeyValue,
+        &CrashLoggingTest::ClearKeyValue);
+  }
+
+  void TearDown() override {
+    base::debug::ResetCrashLoggingForTesting();
+
+    delete key_values_;
+    key_values_ = NULL;
+  }
+
+ private:
+  static void SetKeyValue(const base::StringPiece& key,
+                          const base::StringPiece& value) {
+    (*key_values_)[key.as_string()] = value.as_string();
+  }
+
+  static void ClearKeyValue(const base::StringPiece& key) {
+    key_values_->erase(key.as_string());
+  }
+};
+
+TEST_F(CrashLoggingTest, SetClearSingle) {
+  const char kTestKey[] = "test-key";
+  base::debug::CrashKey keys[] = { { kTestKey, 255 } };
+  base::debug::InitCrashKeys(keys, arraysize(keys), 255);
+
+  base::debug::SetCrashKeyValue(kTestKey, "value");
+  EXPECT_EQ("value", (*key_values_)[kTestKey]);
+
+  base::debug::ClearCrashKey(kTestKey);
+  EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey));
+}
+
+TEST_F(CrashLoggingTest, SetChunked) {
+  const char kTestKey[] = "chunky";
+  const char kChunk1[] = "chunky-1";
+  const char kChunk2[] = "chunky-2";
+  const char kChunk3[] = "chunky-3";
+  base::debug::CrashKey keys[] = { { kTestKey, 15 } };
+  base::debug::InitCrashKeys(keys, arraysize(keys), 5);
+
+  std::map<std::string, std::string>& values = *key_values_;
+
+  // Fill only the first chunk.
+  base::debug::SetCrashKeyValue(kTestKey, "foo");
+  EXPECT_EQ(1u, values.size());
+  EXPECT_EQ("foo", values[kChunk1]);
+  EXPECT_TRUE(values.end() == values.find(kChunk2));
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+
+  // Fill three chunks with truncation (max length is 15, this string is 20).
+  base::debug::SetCrashKeyValue(kTestKey, "five four three two");
+  EXPECT_EQ(3u, values.size());
+  EXPECT_EQ("five ", values[kChunk1]);
+  EXPECT_EQ("four ", values[kChunk2]);
+  EXPECT_EQ("three", values[kChunk3]);
+
+  // Clear everything.
+  base::debug::ClearCrashKey(kTestKey);
+  EXPECT_EQ(0u, values.size());
+  EXPECT_TRUE(values.end() == values.find(kChunk1));
+  EXPECT_TRUE(values.end() == values.find(kChunk2));
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+
+  // Refill all three chunks with truncation, then test that setting a smaller
+  // value clears the third chunk.
+  base::debug::SetCrashKeyValue(kTestKey, "five four three two");
+  base::debug::SetCrashKeyValue(kTestKey, "allays");
+  EXPECT_EQ(2u, values.size());
+  EXPECT_EQ("allay", values[kChunk1]);
+  EXPECT_EQ("s", values[kChunk2]);
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+
+  // Clear everything.
+  base::debug::ClearCrashKey(kTestKey);
+  EXPECT_EQ(0u, values.size());
+  EXPECT_TRUE(values.end() == values.find(kChunk1));
+  EXPECT_TRUE(values.end() == values.find(kChunk2));
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+}
+
+TEST_F(CrashLoggingTest, ScopedCrashKey) {
+  const char kTestKey[] = "test-key";
+  base::debug::CrashKey keys[] = { { kTestKey, 255 } };
+  base::debug::InitCrashKeys(keys, arraysize(keys), 255);
+
+  EXPECT_EQ(0u, key_values_->size());
+  EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey));
+  {
+    base::debug::ScopedCrashKey scoped_crash_key(kTestKey, "value");
+    EXPECT_EQ("value", (*key_values_)[kTestKey]);
+    EXPECT_EQ(1u, key_values_->size());
+  }
+  EXPECT_EQ(0u, key_values_->size());
+  EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey));
+}
+
+TEST_F(CrashLoggingTest, InitSize) {
+  base::debug::CrashKey keys[] = {
+    { "chunked-3", 15 },
+    { "single", 5 },
+    { "chunked-6", 30 },
+  };
+
+  size_t num_keys = base::debug::InitCrashKeys(keys, arraysize(keys), 5);
+
+  EXPECT_EQ(10u, num_keys);
+
+  EXPECT_TRUE(base::debug::LookupCrashKey("chunked-3"));
+  EXPECT_TRUE(base::debug::LookupCrashKey("single"));
+  EXPECT_TRUE(base::debug::LookupCrashKey("chunked-6"));
+  EXPECT_FALSE(base::debug::LookupCrashKey("chunked-6-4"));
+}
+
+TEST_F(CrashLoggingTest, ChunkValue) {
+  using base::debug::ChunkCrashKeyValue;
+
+  // Test truncation.
+  base::debug::CrashKey key = { "chunky", 10 };
+  std::vector<std::string> results =
+      ChunkCrashKeyValue(key, "hello world", 64);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_EQ("hello worl", results[0]);
+
+  // Test short string.
+  results = ChunkCrashKeyValue(key, "hi", 10);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_EQ("hi", results[0]);
+
+  // Test chunk pair.
+  key.max_length = 6;
+  results = ChunkCrashKeyValue(key, "foobar", 3);
+  ASSERT_EQ(2u, results.size());
+  EXPECT_EQ("foo", results[0]);
+  EXPECT_EQ("bar", results[1]);
+
+  // Test chunk pair truncation.
+  results = ChunkCrashKeyValue(key, "foobared", 3);
+  ASSERT_EQ(2u, results.size());
+  EXPECT_EQ("foo", results[0]);
+  EXPECT_EQ("bar", results[1]);
+
+  // Test extra chunks.
+  key.max_length = 100;
+  results = ChunkCrashKeyValue(key, "hello world", 3);
+  ASSERT_EQ(4u, results.size());
+  EXPECT_EQ("hel", results[0]);
+  EXPECT_EQ("lo ", results[1]);
+  EXPECT_EQ("wor", results[2]);
+  EXPECT_EQ("ld",  results[3]);
+}
+
+TEST_F(CrashLoggingTest, ChunkRounding) {
+  // If max_length=12 and max_chunk_length=5, there should be 3 chunks,
+  // not 2.
+  base::debug::CrashKey key = { "round", 12 };
+  EXPECT_EQ(3u, base::debug::InitCrashKeys(&key, 1, 5));
+}
diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc
new file mode 100644
index 0000000..79233c5
--- /dev/null
+++ b/base/debug/debugger.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace debug {
+
+static bool is_debug_ui_suppressed = false;
+
+bool WaitForDebugger(int wait_seconds, bool silent) {
+#if defined(OS_ANDROID)
+  // The pid from which we know which process to attach to are not output by
+  // android ddms, so we have to print it out explicitly.
+  DLOG(INFO) << "DebugUtil::WaitForDebugger(pid=" << static_cast<int>(getpid())
+             << ")";
+#endif
+  for (int i = 0; i < wait_seconds * 10; ++i) {
+    if (BeingDebugged()) {
+      if (!silent)
+        BreakDebugger();
+      return true;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+  return false;
+}
+
+void SetSuppressDebugUI(bool suppress) {
+  is_debug_ui_suppressed = suppress;
+}
+
+bool IsDebugUISuppressed() {
+  return is_debug_ui_suppressed;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debugger.h b/base/debug/debugger.h
new file mode 100644
index 0000000..8680e28
--- /dev/null
+++ b/base/debug/debugger.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a cross platform interface for helper functions related to
+// debuggers.  You should use this to test if you're running under a debugger,
+// and if you would like to yield (breakpoint) into the debugger.
+
+#ifndef BASE_DEBUG_DEBUGGER_H_
+#define BASE_DEBUG_DEBUGGER_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Waits wait_seconds seconds for a debugger to attach to the current process.
+// When silent is false, an exception is thrown when a debugger is detected.
+BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);
+
+// Returns true if the given process is being run under a debugger.
+//
+// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
+// To get around this, this function caches its value.
+//
+// WARNING: Because of this, on OS X, a call MUST be made to this function
+// BEFORE the sandbox is enabled.
+BASE_EXPORT bool BeingDebugged();
+
+// Break into the debugger, assumes a debugger is present.
+BASE_EXPORT void BreakDebugger();
+
+// Used in test code, this controls whether showing dialogs and breaking into
+// the debugger is suppressed for debug errors, even in debug mode (normally
+// release mode doesn't do this stuff --  this is controlled separately).
+// Normally UI is not suppressed.  This is normally used when running automated
+// tests where we want a crash rather than a dialog or a debugger.
+BASE_EXPORT void SetSuppressDebugUI(bool suppress);
+BASE_EXPORT bool IsDebugUISuppressed();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_DEBUGGER_H_
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
new file mode 100644
index 0000000..48393f4
--- /dev/null
+++ b/base/debug/debugger_posix.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+#include "build/build_config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_BSD)
+#include <sys/sysctl.h>
+#endif
+
+#if defined(OS_FREEBSD)
+#include <sys/user.h>
+#endif
+
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/safe_strerror_posix.h"
+#include "base/strings/string_piece.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/threading/platform_thread.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(OS_MACOSX) || defined(OS_BSD)
+
+// Based on Apple's recommended method as described in
+// http://developer.apple.com/qa/qa2004/qa1361.html
+bool BeingDebugged() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+  //
+  // While some code used below may be async-signal unsafe, note how
+  // the result is cached (see |is_set| and |being_debugged| static variables
+  // right below). If this code is properly warmed-up early
+  // in the start-up process, it should be safe to use later.
+
+  // If the process is sandboxed then we can't use the sysctl, so cache the
+  // value.
+  static bool is_set = false;
+  static bool being_debugged = false;
+
+  if (is_set)
+    return being_debugged;
+
+  // Initialize mib, which tells sysctl what info we want.  In this case,
+  // we're looking for information about a specific process ID.
+  int mib[] = {
+    CTL_KERN,
+    KERN_PROC,
+    KERN_PROC_PID,
+    getpid()
+#if defined(OS_OPENBSD)
+    , sizeof(struct kinfo_proc),
+    0
+#endif
+  };
+
+  // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
+  // binary interfaces may change.
+  struct kinfo_proc info;
+  size_t info_size = sizeof(info);
+
+#if defined(OS_OPENBSD)
+  if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (info_size / sizeof(struct kinfo_proc));
+#endif
+
+  int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
+  DCHECK_EQ(sysctl_result, 0);
+  if (sysctl_result != 0) {
+    is_set = true;
+    being_debugged = false;
+    return being_debugged;
+  }
+
+  // This process is being debugged if the P_TRACED flag is set.
+  is_set = true;
+#if defined(OS_FREEBSD)
+  being_debugged = (info.ki_flag & P_TRACED) != 0;
+#elif defined(OS_BSD)
+  being_debugged = (info.p_flag & P_TRACED) != 0;
+#else
+  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
+#endif
+  return being_debugged;
+}
+
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+
+// We can look in /proc/self/status for TracerPid.  We are likely used in crash
+// handling, so we are careful not to use the heap or have side effects.
+// Another option that is common is to try to ptrace yourself, but then we
+// can't detach without forking(), and that's not so great.
+// static
+bool BeingDebugged() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  int status_fd = open("/proc/self/status", O_RDONLY);
+  if (status_fd == -1)
+    return false;
+
+  // We assume our line will be in the first 1024 characters and that we can
+  // read this much all at once.  In practice this will generally be true.
+  // This simplifies and speeds up things considerably.
+  char buf[1024];
+
+  ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
+  if (IGNORE_EINTR(close(status_fd)) < 0)
+    return false;
+
+  if (num_read <= 0)
+    return false;
+
+  StringPiece status(buf, num_read);
+  StringPiece tracer("TracerPid:\t");
+
+  StringPiece::size_type pid_index = status.find(tracer);
+  if (pid_index == StringPiece::npos)
+    return false;
+
+  // Our pid is 0 without a debugger, assume this for any pid starting with 0.
+  pid_index += tracer.size();
+  return pid_index < status.size() && status[pid_index] != '0';
+}
+
+#else
+
+bool BeingDebugged() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+#endif
+
+// We want to break into the debugger in Debug mode, and cause a crash dump in
+// Release mode. Breakpad behaves as follows:
+//
+// +-------+-----------------+-----------------+
+// | OS    | Dump on SIGTRAP | Dump on SIGABRT |
+// +-------+-----------------+-----------------+
+// | Linux |       N         |        Y        |
+// | Mac   |       Y         |        N        |
+// +-------+-----------------+-----------------+
+//
+// Thus we do the following:
+// Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send
+//        SIGABRT
+// Mac: Always send SIGTRAP.
+
+#if defined(ARCH_CPU_ARMEL)
+#define DEBUG_BREAK_ASM() asm("bkpt 0")
+#elif defined(ARCH_CPU_ARM64)
+#define DEBUG_BREAK_ASM() asm("brk 0")
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+#define DEBUG_BREAK_ASM() asm("break 2")
+#elif defined(ARCH_CPU_X86_FAMILY)
+#define DEBUG_BREAK_ASM() asm("int3")
+#endif
+
+#if defined(NDEBUG) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+#define DEBUG_BREAK() abort()
+#elif defined(OS_NACL)
+// The NaCl verifier doesn't let use use int3.  For now, we call abort().  We
+// should ask for advice from some NaCl experts about the optimum thing here.
+// http://code.google.com/p/nativeclient/issues/detail?id=645
+#define DEBUG_BREAK() abort()
+#elif !defined(OS_MACOSX)
+// Though Android has a "helpful" process called debuggerd to catch native
+// signals on the general assumption that they are fatal errors. If no debugger
+// is attached, we call abort since Breakpad needs SIGABRT to create a dump.
+// When debugger is attached, for ARM platform the bkpt instruction appears
+// to cause SIGBUS which is trapped by debuggerd, and we've had great
+// difficulty continuing in a debugger once we stop from SIG triggered by native
+// code, use GDB to set |go| to 1 to resume execution; for X86 platform, use
+// "int3" to setup breakpiont and raise SIGTRAP.
+//
+// On other POSIX architectures, except Mac OS X, we use the same logic to
+// ensure that breakpad creates a dump on crashes while it is still possible to
+// use a debugger.
+namespace {
+void DebugBreak() {
+  if (!BeingDebugged()) {
+    abort();
+  } else {
+#if defined(DEBUG_BREAK_ASM)
+    DEBUG_BREAK_ASM();
+#else
+    volatile int go = 0;
+    while (!go) {
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+    }
+#endif
+  }
+}
+}  // namespace
+#define DEBUG_BREAK() DebugBreak()
+#elif defined(DEBUG_BREAK_ASM)
+#define DEBUG_BREAK() DEBUG_BREAK_ASM()
+#else
+#error "Don't know how to debug break on this architecture/OS"
+#endif
+
+void BreakDebugger() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  DEBUG_BREAK();
+#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
+  // For Android development we always build release (debug builds are
+  // unmanageably large), so the unofficial build is used for debugging. It is
+  // helpful to be able to insert BreakDebugger() statements in the source,
+  // attach the debugger, inspect the state of the program and then resume it by
+  // setting the 'go' variable above.
+#elif defined(NDEBUG)
+  // Terminate the program after signaling the debug break.
+  _exit(1);
+#endif
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debugger_unittest.cc b/base/debug/debugger_unittest.cc
new file mode 100644
index 0000000..0a5a039
--- /dev/null
+++ b/base/debug/debugger_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+void CrashWithBreakDebugger() {
+  base::debug::SetSuppressDebugUI(false);
+  base::debug::BreakDebugger();
+
+#if defined(OS_WIN)
+  // This should not be executed.
+  _exit(125);
+#endif
+}
+#endif  // defined(GTEST_HAS_DEATH_TEST)
+
+}  // namespace
+
+// Death tests misbehave on Android.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+TEST(Debugger, CrashAtBreakpoint) {
+  EXPECT_DEATH(CrashWithBreakDebugger(), "");
+}
+
+#if defined(OS_WIN)
+TEST(Debugger, DoesntExecuteBeyondBreakpoint) {
+  EXPECT_EXIT(CrashWithBreakDebugger(),
+              ::testing::ExitedWithCode(0x80000003), "");
+}
+#endif  // defined(OS_WIN)
+
+#else  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+TEST(Debugger, NoTest) {
+}
+#endif  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
new file mode 100644
index 0000000..a1d86e4
--- /dev/null
+++ b/base/debug/debugger_win.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/debugger.h"
+
+#include <stdlib.h>
+#include <windows.h>
+
+namespace base {
+namespace debug {
+
+bool BeingDebugged() {
+  return ::IsDebuggerPresent() != 0;
+}
+
+void BreakDebugger() {
+  if (IsDebugUISuppressed())
+    _exit(1);
+
+  __debugbreak();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/dump_without_crashing.cc b/base/debug/dump_without_crashing.cc
new file mode 100644
index 0000000..47fd873
--- /dev/null
+++ b/base/debug/dump_without_crashing.cc
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/dump_without_crashing.h"
+
+#include "base/logging.h"
+
+namespace {
+
+// Pointer to the function that's called by DumpWithoutCrashing() to dump the
+// process's memory.
+void (CDECL *dump_without_crashing_function_)() = NULL;
+
+}  // namespace
+
+namespace base {
+
+namespace debug {
+
+void DumpWithoutCrashing() {
+  if (dump_without_crashing_function_)
+    (*dump_without_crashing_function_)();
+}
+
+void SetDumpWithoutCrashingFunction(void (CDECL *function)()) {
+  dump_without_crashing_function_ = function;
+}
+
+}  // namespace debug
+
+}  // namespace base
diff --git a/base/debug/dump_without_crashing.h b/base/debug/dump_without_crashing.h
new file mode 100644
index 0000000..b8ed174
--- /dev/null
+++ b/base/debug/dump_without_crashing.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
+#define BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace debug {
+
+// Handler to silently dump the current process without crashing.
+// Before calling this function, call SetDumpWithoutCrashingFunction to pass a
+// function pointer, typically chrome!DumpProcessWithoutCrash.  See example code
+// in chrome_main.cc that does this for chrome.dll.
+BASE_EXPORT void DumpWithoutCrashing();
+
+// Sets a function that'll be invoked to dump the current process when
+// DumpWithoutCrashing() is called.
+BASE_EXPORT void SetDumpWithoutCrashingFunction(void (CDECL *function)());
+
+}  // namespace debug
+
+}  // namespace base
+
+#endif  // BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
diff --git a/base/debug/gdi_debug_util_win.cc b/base/debug/gdi_debug_util_win.cc
new file mode 100644
index 0000000..3cd71f1
--- /dev/null
+++ b/base/debug/gdi_debug_util_win.cc
@@ -0,0 +1,124 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "base/debug/gdi_debug_util_win.h"
+
+#include <cmath>
+
+#include <psapi.h>
+#include <TlHelp32.h>
+
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace {
+
+void CollectChildGDIUsageAndDie(DWORD parent_pid) {
+  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+  CHECK_NE(INVALID_HANDLE_VALUE, snapshot);
+
+  int child_count = 0;
+  base::debug::Alias(&child_count);
+  int peak_gdi_count = 0;
+  base::debug::Alias(&peak_gdi_count);
+  int sum_gdi_count = 0;
+  base::debug::Alias(&sum_gdi_count);
+  int sum_user_count = 0;
+  base::debug::Alias(&sum_user_count);
+
+  PROCESSENTRY32 proc_entry = {0};
+  proc_entry.dwSize = sizeof(PROCESSENTRY32);
+  CHECK(Process32First(snapshot, &proc_entry));
+
+  do {
+    if (parent_pid != proc_entry.th32ParentProcessID)
+      continue;
+    // Got a child process. Compute GDI usage.
+    base::win::ScopedHandle process(
+        OpenProcess(PROCESS_QUERY_INFORMATION,
+                    FALSE,
+                    proc_entry.th32ParentProcessID));
+    if (!process.IsValid())
+      continue;
+
+    int num_gdi_handles = GetGuiResources(process.Get(), GR_GDIOBJECTS);
+    int num_user_handles = GetGuiResources(process.Get(), GR_USEROBJECTS);
+
+    // Compute sum and peak counts.
+    ++child_count;
+    sum_user_count += num_user_handles;
+    sum_gdi_count += num_gdi_handles;
+    if (peak_gdi_count < num_gdi_handles)
+      peak_gdi_count = num_gdi_handles;
+
+  } while (Process32Next(snapshot, &proc_entry));
+
+  CloseHandle(snapshot);
+  CHECK(false);
+}
+
+}  // namespace
+
+namespace base {
+namespace debug {
+
+void GDIBitmapAllocFailure(BITMAPINFOHEADER* header, HANDLE shared_section) {
+  // Make sure parameters are saved in the minidump.
+  DWORD last_error = GetLastError();
+
+  LONG width = header->biWidth;
+  LONG heigth = header->biHeight;
+
+  base::debug::Alias(&last_error);
+  base::debug::Alias(&width);
+  base::debug::Alias(&heigth);
+  base::debug::Alias(&shared_section);
+
+  int num_user_handles = GetGuiResources(GetCurrentProcess(),
+                                         GR_USEROBJECTS);
+
+  int num_gdi_handles = GetGuiResources(GetCurrentProcess(),
+                                        GR_GDIOBJECTS);
+  if (num_gdi_handles == 0) {
+    DWORD get_gui_resources_error = GetLastError();
+    base::debug::Alias(&get_gui_resources_error);
+    CHECK(false);
+  }
+
+  base::debug::Alias(&num_gdi_handles);
+  base::debug::Alias(&num_user_handles);
+
+  const DWORD kLotsOfHandles = 9990;
+  CHECK_LE(num_gdi_handles, kLotsOfHandles);
+
+  PROCESS_MEMORY_COUNTERS_EX pmc;
+  pmc.cb = sizeof(pmc);
+  CHECK(GetProcessMemoryInfo(GetCurrentProcess(),
+                             reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc),
+                             sizeof(pmc)));
+  const size_t kLotsOfMemory = 1500 * 1024 * 1024; // 1.5GB
+  CHECK_LE(pmc.PagefileUsage, kLotsOfMemory);
+  CHECK_LE(pmc.PrivateUsage, kLotsOfMemory);
+
+  void* small_data = NULL;
+  base::debug::Alias(&small_data);
+
+  if (std::abs(heigth) * width > 100) {
+    // Huh, that's weird.  We don't have crazy handle count, we don't have
+    // ridiculous memory usage. Try to allocate a small bitmap and see if that
+    // fails too.
+    header->biWidth = 5;
+    header->biHeight = -5;
+    HBITMAP small_bitmap = CreateDIBSection(
+        NULL, reinterpret_cast<BITMAPINFO*>(&header),
+        0, &small_data, shared_section, 0);
+    CHECK(small_bitmap != NULL);
+    DeleteObject(small_bitmap);
+  }
+  // Maybe the child processes are the ones leaking GDI or USER resouces.
+  CollectChildGDIUsageAndDie(GetCurrentProcessId());
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/gdi_debug_util_win.h b/base/debug/gdi_debug_util_win.h
new file mode 100644
index 0000000..5887ecb
--- /dev/null
+++ b/base/debug/gdi_debug_util_win.h
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
+#define BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Crashes the process leaving valuable information on the dump via
+// debug::alias so we can find what is causing the allocation failures.
+void BASE_EXPORT GDIBitmapAllocFailure(BITMAPINFOHEADER* header,
+                                       HANDLE shared_section);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h
new file mode 100644
index 0000000..ef37959
--- /dev/null
+++ b/base/debug/leak_annotations.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
+#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+// This file defines macros which can be used to annotate intentional memory
+// leaks. Support for annotations is implemented in LeakSanitizer. Annotated
+// objects will be treated as a source of live pointers, i.e. any heap objects
+// reachable by following pointers from an annotated object will not be
+// reported as leaks.
+//
+// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope
+// will be annotated as leaks.
+// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
+// be annotated as a leak.
+
+#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
+
+#include <sanitizer/lsan_interface.h>
+
+class ScopedLeakSanitizerDisabler {
+ public:
+  ScopedLeakSanitizerDisabler() { __lsan_disable(); }
+  ~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
+};
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK \
+    ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0)
+
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X);
+
+#else
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
+
+#endif
+
+#endif  // BASE_DEBUG_LEAK_ANNOTATIONS_H_
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
new file mode 100644
index 0000000..8c5aaf3
--- /dev/null
+++ b/base/debug/leak_tracker.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_LEAK_TRACKER_H_
+#define BASE_DEBUG_LEAK_TRACKER_H_
+
+#include "build/build_config.h"
+
+// Only enable leak tracking in non-uClibc debug builds.
+#if !defined(NDEBUG) && !defined(__UCLIBC__)
+#define ENABLE_LEAK_TRACKER
+#endif
+
+#ifdef ENABLE_LEAK_TRACKER
+#include "base/containers/linked_list.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#endif  // ENABLE_LEAK_TRACKER
+
+// LeakTracker is a helper to verify that all instances of a class
+// have been destroyed.
+//
+// It is particularly useful for classes that are bound to a single thread --
+// before destroying that thread, one can check that there are no remaining
+// instances of that class.
+//
+// For example, to enable leak tracking for class net::URLRequest, start by
+// adding a member variable of type LeakTracker<net::URLRequest>.
+//
+//   class URLRequest {
+//     ...
+//    private:
+//     base::LeakTracker<URLRequest> leak_tracker_;
+//   };
+//
+//
+// Next, when we believe all instances of net::URLRequest have been deleted:
+//
+//   LeakTracker<net::URLRequest>::CheckForLeaks();
+//
+// Should the check fail (because there are live instances of net::URLRequest),
+// then the allocation callstack for each leaked instances is dumped to
+// the error log.
+//
+// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
+
+namespace base {
+namespace debug {
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, do nothing.
+template<typename T>
+class LeakTracker {
+ public:
+  ~LeakTracker() {}
+  static void CheckForLeaks() {}
+  static int NumLiveInstances() { return -1; }
+};
+
+#else
+
+// If leak tracking is enabled we track where the object was allocated from.
+
+template<typename T>
+class LeakTracker : public LinkNode<LeakTracker<T> > {
+ public:
+  LeakTracker() {
+    instances()->Append(this);
+  }
+
+  ~LeakTracker() {
+    this->RemoveFromList();
+  }
+
+  static void CheckForLeaks() {
+    // Walk the allocation list and print each entry it contains.
+    size_t count = 0;
+
+    // Copy the first 3 leak allocation callstacks onto the stack.
+    // This way if we hit the CHECK() in a release build, the leak
+    // information will be available in mini-dump.
+    const size_t kMaxStackTracesToCopyOntoStack = 3;
+    StackTrace stacktraces[kMaxStackTracesToCopyOntoStack];
+
+    for (LinkNode<LeakTracker<T> >* node = instances()->head();
+         node != instances()->end();
+         node = node->next()) {
+      StackTrace& allocation_stack = node->value()->allocation_stack_;
+
+      if (count < kMaxStackTracesToCopyOntoStack)
+        stacktraces[count] = allocation_stack;
+
+      ++count;
+      if (LOG_IS_ON(ERROR)) {
+        LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:";
+        allocation_stack.OutputToStream(&LOG_STREAM(ERROR));
+      }
+    }
+
+    CHECK_EQ(0u, count);
+
+    // Hack to keep |stacktraces| and |count| alive (so compiler
+    // doesn't optimize it out, and it will appear in mini-dumps).
+    if (count == 0x1234) {
+      for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i)
+        stacktraces[i].Print();
+    }
+  }
+
+  static int NumLiveInstances() {
+    // Walk the allocation list and count how many entries it has.
+    int count = 0;
+    for (LinkNode<LeakTracker<T> >* node = instances()->head();
+         node != instances()->end();
+         node = node->next()) {
+      ++count;
+    }
+    return count;
+  }
+
+ private:
+  // Each specialization of LeakTracker gets its own static storage.
+  static LinkedList<LeakTracker<T> >* instances() {
+    static LinkedList<LeakTracker<T> > list;
+    return &list;
+  }
+
+  StackTrace allocation_stack_;
+};
+
+#endif  // ENABLE_LEAK_TRACKER
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_LEAK_TRACKER_H_
diff --git a/base/debug/leak_tracker_unittest.cc b/base/debug/leak_tracker_unittest.cc
new file mode 100644
index 0000000..99df4c1
--- /dev/null
+++ b/base/debug/leak_tracker_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/leak_tracker.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+class ClassA {
+ private:
+  LeakTracker<ClassA> leak_tracker_;
+};
+
+class ClassB {
+ private:
+  LeakTracker<ClassB> leak_tracker_;
+};
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, we should do nothing.
+TEST(LeakTrackerTest, NotEnabled) {
+  EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+
+  // Use scoped_ptr so compiler doesn't complain about unused variables.
+  scoped_ptr<ClassA> a1(new ClassA);
+  scoped_ptr<ClassB> b1(new ClassB);
+  scoped_ptr<ClassB> b2(new ClassB);
+
+  EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+#else
+
+TEST(LeakTrackerTest, Basic) {
+  {
+    ClassA a1;
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+    ClassB b1;
+    ClassB b2;
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+    scoped_ptr<ClassA> a2(new ClassA);
+
+    EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+    a2.reset();
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+  }
+
+  EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+// Try some orderings of create/remove to hit different cases in the linked-list
+// assembly.
+TEST(LeakTrackerTest, LinkedList) {
+  EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+  scoped_ptr<ClassA> a1(new ClassA);
+  scoped_ptr<ClassA> a2(new ClassA);
+  scoped_ptr<ClassA> a3(new ClassA);
+  scoped_ptr<ClassA> a4(new ClassA);
+
+  EXPECT_EQ(4, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Remove the head of the list (a1).
+  a1.reset();
+  EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Remove the tail of the list (a4).
+  a4.reset();
+  EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Append to the new tail of the list (a3).
+  scoped_ptr<ClassA> a5(new ClassA);
+  EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+  a2.reset();
+  a3.reset();
+
+  EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+
+  a5.reset();
+  EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+}
+
+TEST(LeakTrackerTest, NoOpCheckForLeaks) {
+  // There are no live instances of ClassA, so this should do nothing.
+  LeakTracker<ClassA>::CheckForLeaks();
+}
+
+#endif  // ENABLE_LEAK_TRACKER
+
+}  // namespace
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/proc_maps_linux.cc b/base/debug/proc_maps_linux.cc
new file mode 100644
index 0000000..4c1aedf
--- /dev/null
+++ b/base/debug/proc_maps_linux.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/proc_maps_linux.h"
+
+#include <fcntl.h>
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <inttypes.h>
+#endif
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/strings/string_split.h"
+
+#if defined(OS_ANDROID) && !defined(__LP64__)
+// In 32-bit mode, Bionic's inttypes.h defines PRI/SCNxPTR as an
+// unsigned long int, which is incompatible with Bionic's stdint.h
+// defining uintptr_t as an unsigned int:
+// https://code.google.com/p/android/issues/detail?id=57218
+#undef SCNxPTR
+#define SCNxPTR "x"
+#endif
+
+namespace base {
+namespace debug {
+
+// Scans |proc_maps| starting from |pos| returning true if the gate VMA was
+// found, otherwise returns false.
+static bool ContainsGateVMA(std::string* proc_maps, size_t pos) {
+#if defined(ARCH_CPU_ARM_FAMILY)
+  // The gate VMA on ARM kernels is the interrupt vectors page.
+  return proc_maps->find(" [vectors]\n", pos) != std::string::npos;
+#elif defined(ARCH_CPU_X86_64)
+  // The gate VMA on x86 64-bit kernels is the virtual system call page.
+  return proc_maps->find(" [vsyscall]\n", pos) != std::string::npos;
+#else
+  // Otherwise assume there is no gate VMA in which case we shouldn't
+  // get duplicate entires.
+  return false;
+#endif
+}
+
+bool ReadProcMaps(std::string* proc_maps) {
+  // seq_file only writes out a page-sized amount on each call. Refer to header
+  // file for details.
+  const long kReadSize = sysconf(_SC_PAGESIZE);
+
+  base::ScopedFD fd(HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)));
+  if (!fd.is_valid()) {
+    DPLOG(ERROR) << "Couldn't open /proc/self/maps";
+    return false;
+  }
+  proc_maps->clear();
+
+  while (true) {
+    // To avoid a copy, resize |proc_maps| so read() can write directly into it.
+    // Compute |buffer| afterwards since resize() may reallocate.
+    size_t pos = proc_maps->size();
+    proc_maps->resize(pos + kReadSize);
+    void* buffer = &(*proc_maps)[pos];
+
+    ssize_t bytes_read = HANDLE_EINTR(read(fd.get(), buffer, kReadSize));
+    if (bytes_read < 0) {
+      DPLOG(ERROR) << "Couldn't read /proc/self/maps";
+      proc_maps->clear();
+      return false;
+    }
+
+    // ... and don't forget to trim off excess bytes.
+    proc_maps->resize(pos + bytes_read);
+
+    if (bytes_read == 0)
+      break;
+
+    // The gate VMA is handled as a special case after seq_file has finished
+    // iterating through all entries in the virtual memory table.
+    //
+    // Unfortunately, if additional entries are added at this point in time
+    // seq_file gets confused and the next call to read() will return duplicate
+    // entries including the gate VMA again.
+    //
+    // Avoid this by searching for the gate VMA and breaking early.
+    if (ContainsGateVMA(proc_maps, pos))
+      break;
+  }
+
+  return true;
+}
+
+bool ParseProcMaps(const std::string& input,
+                   std::vector<MappedMemoryRegion>* regions_out) {
+  CHECK(regions_out);
+  std::vector<MappedMemoryRegion> regions;
+
+  // This isn't async safe nor terribly efficient, but it doesn't need to be at
+  // this point in time.
+  std::vector<std::string> lines;
+  SplitString(input, '\n', &lines);
+
+  for (size_t i = 0; i < lines.size(); ++i) {
+    // Due to splitting on '\n' the last line should be empty.
+    if (i == lines.size() - 1) {
+      if (!lines[i].empty()) {
+        DLOG(WARNING) << "Last line not empty";
+        return false;
+      }
+      break;
+    }
+
+    MappedMemoryRegion region;
+    const char* line = lines[i].c_str();
+    char permissions[5] = {'\0'};  // Ensure NUL-terminated string.
+    uint8 dev_major = 0;
+    uint8 dev_minor = 0;
+    long inode = 0;
+    int path_index = 0;
+
+    // Sample format from man 5 proc:
+    //
+    // address           perms offset  dev   inode   pathname
+    // 08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
+    //
+    // The final %n term captures the offset in the input string, which is used
+    // to determine the path name. It *does not* increment the return value.
+    // Refer to man 3 sscanf for details.
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4c %llx %hhx:%hhx %ld %n",
+               &region.start, &region.end, permissions, &region.offset,
+               &dev_major, &dev_minor, &inode, &path_index) < 7) {
+      DPLOG(WARNING) << "sscanf failed for line: " << line;
+      return false;
+    }
+
+    region.permissions = 0;
+
+    if (permissions[0] == 'r')
+      region.permissions |= MappedMemoryRegion::READ;
+    else if (permissions[0] != '-')
+      return false;
+
+    if (permissions[1] == 'w')
+      region.permissions |= MappedMemoryRegion::WRITE;
+    else if (permissions[1] != '-')
+      return false;
+
+    if (permissions[2] == 'x')
+      region.permissions |= MappedMemoryRegion::EXECUTE;
+    else if (permissions[2] != '-')
+      return false;
+
+    if (permissions[3] == 'p')
+      region.permissions |= MappedMemoryRegion::PRIVATE;
+    else if (permissions[3] != 's' && permissions[3] != 'S')  // Shared memory.
+      return false;
+
+    // Pushing then assigning saves us a string copy.
+    regions.push_back(region);
+    regions.back().path.assign(line + path_index);
+  }
+
+  regions_out->swap(regions);
+  return true;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/proc_maps_linux.h b/base/debug/proc_maps_linux.h
new file mode 100644
index 0000000..9fbd478
--- /dev/null
+++ b/base/debug/proc_maps_linux.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
+#define BASE_DEBUG_PROC_MAPS_LINUX_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace debug {
+
+// Describes a region of mapped memory and the path of the file mapped.
+struct MappedMemoryRegion {
+  enum Permission {
+    READ = 1 << 0,
+    WRITE = 1 << 1,
+    EXECUTE = 1 << 2,
+    PRIVATE = 1 << 3,  // If set, region is private, otherwise it is shared.
+  };
+
+  // The address range [start,end) of mapped memory.
+  uintptr_t start;
+  uintptr_t end;
+
+  // Byte offset into |path| of the range mapped into memory.
+  unsigned long long offset;
+
+  // Bitmask of read/write/execute/private/shared permissions.
+  uint8 permissions;
+
+  // Name of the file mapped into memory.
+  //
+  // NOTE: path names aren't guaranteed to point at valid files. For example,
+  // "[heap]" and "[stack]" are used to represent the location of the process'
+  // heap and stack, respectively.
+  std::string path;
+};
+
+// Reads the data from /proc/self/maps and stores the result in |proc_maps|.
+// Returns true if successful, false otherwise.
+//
+// There is *NO* guarantee that the resulting contents will be free of
+// duplicates or even contain valid entries by time the method returns.
+//
+//
+// THE GORY DETAILS
+//
+// Did you know it's next-to-impossible to atomically read the whole contents
+// of /proc/<pid>/maps? You would think that if we passed in a large-enough
+// buffer to read() that It Should Just Work(tm), but sadly that's not the case.
+//
+// Linux's procfs uses seq_file [1] for handling iteration, text formatting,
+// and dealing with resulting data that is larger than the size of a page. That
+// last bit is especially important because it means that seq_file will never
+// return more than the size of a page in a single call to read().
+//
+// Unfortunately for a program like Chrome the size of /proc/self/maps is
+// larger than the size of page so we're forced to call read() multiple times.
+// If the virtual memory table changed in any way between calls to read() (e.g.,
+// a different thread calling mprotect()), it can make seq_file generate
+// duplicate entries or skip entries.
+//
+// Even if seq_file was changed to keep flushing the contents of its page-sized
+// buffer to the usermode buffer inside a single call to read(), it has to
+// release its lock on the virtual memory table to handle page faults while
+// copying data to usermode. This puts us in the same situation where the table
+// can change while we're copying data.
+//
+// Alternatives such as fork()-and-suspend-the-parent-while-child-reads were
+// attempted, but they present more subtle problems than it's worth. Depending
+// on your use case your best bet may be to read /proc/<pid>/maps prior to
+// starting other threads.
+//
+// [1] http://kernelnewbies.org/Documents/SeqFileHowTo
+BASE_EXPORT bool ReadProcMaps(std::string* proc_maps);
+
+// Parses /proc/<pid>/maps input data and stores in |regions|. Returns true
+// and updates |regions| if and only if all of |input| was successfully parsed.
+BASE_EXPORT bool ParseProcMaps(const std::string& input,
+                               std::vector<MappedMemoryRegion>* regions);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_PROC_MAPS_LINUX_H_
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc
new file mode 100644
index 0000000..cbc0dd0
--- /dev/null
+++ b/base/debug/proc_maps_linux_unittest.cc
@@ -0,0 +1,338 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+TEST(ProcMapsTest, Empty) {
+  std::vector<MappedMemoryRegion> regions;
+  EXPECT_TRUE(ParseProcMaps("", &regions));
+  EXPECT_EQ(0u, regions.size());
+}
+
+TEST(ProcMapsTest, NoSpaces) {
+  static const char kNoSpaces[] =
+      "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kNoSpaces, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00002200u, regions[0].offset);
+  EXPECT_EQ("/bin/cat", regions[0].path);
+}
+
+TEST(ProcMapsTest, Spaces) {
+  static const char kSpaces[] =
+      "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kSpaces, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00002200u, regions[0].offset);
+  EXPECT_EQ("/bin/space cat", regions[0].path);
+}
+
+TEST(ProcMapsTest, NoNewline) {
+  static const char kNoSpaces[] =
+      "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_FALSE(ParseProcMaps(kNoSpaces, &regions));
+}
+
+TEST(ProcMapsTest, NoPath) {
+  static const char kNoPath[] =
+      "00400000-0040b000 rw-p 00000000 00:00 0 \n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kNoPath, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("", regions[0].path);
+}
+
+TEST(ProcMapsTest, Heap) {
+  static const char kHeap[] =
+      "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kHeap, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x022ac000u, regions[0].start);
+  EXPECT_EQ(0x022cd000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("[heap]", regions[0].path);
+}
+
+#if defined(ARCH_CPU_32_BITS)
+TEST(ProcMapsTest, Stack32) {
+  static const char kStack[] =
+      "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kStack, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0xbeb04000u, regions[0].start);
+  EXPECT_EQ(0xbeb25000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("[stack]", regions[0].path);
+}
+#elif defined(ARCH_CPU_64_BITS)
+TEST(ProcMapsTest, Stack64) {
+  static const char kStack[] =
+      "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kStack, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x7fff69c5b000u, regions[0].start);
+  EXPECT_EQ(0x7fff69c7d000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("[stack]", regions[0].path);
+}
+#endif
+
+TEST(ProcMapsTest, Multiple) {
+  static const char kMultiple[] =
+      "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n"
+      "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n"
+      "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kMultiple, &regions));
+  ASSERT_EQ(3u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("/bin/cat", regions[0].path);
+
+  EXPECT_EQ(0x0060a000u, regions[1].start);
+  EXPECT_EQ(0x0060b000u, regions[1].end);
+  EXPECT_EQ(0x0000a000u, regions[1].offset);
+  EXPECT_EQ("/bin/cat", regions[1].path);
+
+  EXPECT_EQ(0x0060b000u, regions[2].start);
+  EXPECT_EQ(0x0060c000u, regions[2].end);
+  EXPECT_EQ(0x0000b000u, regions[2].offset);
+  EXPECT_EQ("/bin/cat", regions[2].path);
+}
+
+TEST(ProcMapsTest, Permissions) {
+  static struct {
+    const char* input;
+    uint8 permissions;
+  } kTestCases[] = {
+    {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0},
+    {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0},
+    {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ},
+    {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::WRITE},
+    {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::EXECUTE},
+    {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
+         MappedMemoryRegion::EXECUTE},
+    {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
+         MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(
+        base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input));
+
+    std::vector<MappedMemoryRegion> regions;
+    EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, &regions));
+    EXPECT_EQ(1u, regions.size());
+    if (regions.empty())
+      continue;
+    EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions);
+  }
+}
+
+#if defined(ADDRESS_SANITIZER)
+// AddressSanitizer may move local variables to a dedicated "fake stack" which
+// is outside the stack region listed in /proc/self/maps. We disable ASan
+// instrumentation for this function to force the variable to be local.
+__attribute__((no_sanitize_address))
+#endif
+void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> &regions) {
+  // We should be able to find both the current executable as well as the stack
+  // mapped into memory. Use the address of |exe_path| as a way of finding the
+  // stack.
+  FilePath exe_path;
+  EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path));
+  uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path);
+  bool found_exe = false;
+  bool found_stack = false;
+  bool found_address = false;
+
+  for (size_t i = 0; i < regions.size(); ++i) {
+    if (regions[i].path == exe_path.value()) {
+      // It's OK to find the executable mapped multiple times as there'll be
+      // multiple sections (e.g., text, data).
+      found_exe = true;
+    }
+
+    // Valgrind uses its own allocated stacks instead of the kernel-provided
+    // stack without letting the kernel know via prctl(PR_SET_MM_START_STACK).
+    // Depending on which kernel you're running it'll impact the output of
+    // /proc/self/maps.
+    //
+    // Prior to version 3.4, the kernel completely ignores other stacks and
+    // always prints out the vma lying within mm->start_stack as [stack] even
+    // if the program was currently executing on a different stack.
+    //
+    // Starting in 3.4, the kernel will print out the vma containing the current
+    // stack pointer as [stack:TID] as long as that vma does not lie within
+    // mm->start_stack.
+    //
+    // Because this has gotten too complicated and brittle of a test, completely
+    // ignore checking for the stack and address when running under Valgrind.
+    // See http://crbug.com/431702 for more details.
+    if (!RunningOnValgrind() && regions[i].path == "[stack]") {
+      EXPECT_GE(address, regions[i].start);
+      EXPECT_LT(address, regions[i].end);
+      EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ);
+      EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE);
+      EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE);
+      EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE);
+      EXPECT_FALSE(found_stack) << "Found duplicate stacks";
+      found_stack = true;
+    }
+
+    if (address >= regions[i].start && address < regions[i].end) {
+      EXPECT_FALSE(found_address) << "Found same address in multiple regions";
+      found_address = true;
+    }
+  }
+
+  EXPECT_TRUE(found_exe);
+  if (!RunningOnValgrind()) {
+    EXPECT_TRUE(found_stack);
+    EXPECT_TRUE(found_address);
+  }
+}
+
+TEST(ProcMapsTest, ReadProcMaps) {
+  std::string proc_maps;
+  ASSERT_TRUE(ReadProcMaps(&proc_maps));
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
+  ASSERT_FALSE(regions.empty());
+
+  CheckProcMapsRegions(regions);
+}
+
+TEST(ProcMapsTest, ReadProcMapsNonEmptyString) {
+  std::string old_string("I forgot to clear the string");
+  std::string proc_maps(old_string);
+  ASSERT_TRUE(ReadProcMaps(&proc_maps));
+  EXPECT_EQ(std::string::npos, proc_maps.find(old_string));
+}
+
+TEST(ProcMapsTest, MissingFields) {
+  static const char* const kTestCases[] = {
+    "00400000\n",                               // Missing end + beyond.
+    "00400000-0040b000\n",                      // Missing perms + beyond.
+    "00400000-0040b000 r-xp\n",                 // Missing offset + beyond.
+    "00400000-0040b000 r-xp 00000000\n",        // Missing device + beyond.
+    "00400000-0040b000 r-xp 00000000 fc:00\n",  // Missing inode + beyond.
+    "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n",  // Missing perms.
+    "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n",      // Missing offset.
+    "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n",    // Missing inode.
+    "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n",      // Missing end.
+    "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n",     // Missing start.
+    "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n",   // Missing device.
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
+    std::vector<MappedMemoryRegion> regions;
+    EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
+  }
+}
+
+TEST(ProcMapsTest, InvalidInput) {
+  static const char* const kTestCases[] = {
+    "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
+    "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n",
+    "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n",
+    "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n",
+    "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n",
+    "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n",
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
+    std::vector<MappedMemoryRegion> regions;
+    EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
+  }
+}
+
+TEST(ProcMapsTest, ParseProcMapsEmptyString) {
+  std::vector<MappedMemoryRegion> regions;
+  EXPECT_TRUE(ParseProcMaps("", &regions));
+  EXPECT_EQ(0ULL, regions.size());
+}
+
+// Testing a couple of remotely possible weird things in the input:
+// - Line ending with \r\n or \n\r.
+// - File name contains quotes.
+// - File name has whitespaces.
+TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) {
+  std::vector<MappedMemoryRegion> regions;
+  const std::string kContents =
+    "00400000-0040b000 r-xp 00000000 fc:00 2106562 "
+      "               /bin/cat\r\n"
+    "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 "
+      "       /lib/x86_64-linux-gnu/libc-2.15.so\n\r"
+    "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 "
+      "        /lib/x86_64-linux-gnu/ld-2.15.so\n"
+    "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 "
+      "               \"vd so\"\n"
+    "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
+      "               [vsys call]\n";
+  EXPECT_TRUE(ParseProcMaps(kContents, &regions));
+  EXPECT_EQ(5ULL, regions.size());
+  EXPECT_EQ("/bin/cat", regions[0].path);
+  EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path);
+  EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path);
+  EXPECT_EQ("\"vd so\"", regions[3].path);
+  EXPECT_EQ("[vsys call]", regions[4].path);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
new file mode 100644
index 0000000..ed553cd
--- /dev/null
+++ b/base/debug/profiler.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/profiler.h"
+
+#include <string>
+
+#include "base/process/process_handle.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+#if defined(OS_WIN)
+#include "base/win/pe_image.h"
+#endif  // defined(OS_WIN)
+
+// TODO(peria): Enable profiling on Windows.
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
+#endif
+
+namespace base {
+namespace debug {
+
+// TODO(peria): Enable profiling on Windows.
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+
+static int profile_count = 0;
+
+void StartProfiling(const std::string& name) {
+  ++profile_count;
+  std::string full_name(name);
+  std::string pid = StringPrintf("%d", GetCurrentProcId());
+  std::string count = StringPrintf("%d", profile_count);
+  ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
+  ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
+  ProfilerStart(full_name.c_str());
+}
+
+void StopProfiling() {
+  ProfilerFlush();
+  ProfilerStop();
+}
+
+void FlushProfiling() {
+  ProfilerFlush();
+}
+
+bool BeingProfiled() {
+  return ProfilingIsEnabledForAllThreads();
+}
+
+void RestartProfilingAfterFork() {
+  ProfilerRegisterThread();
+}
+
+#else
+
+void StartProfiling(const std::string& name) {
+}
+
+void StopProfiling() {
+}
+
+void FlushProfiling() {
+}
+
+bool BeingProfiled() {
+  return false;
+}
+
+void RestartProfilingAfterFork() {
+}
+
+#endif
+
+#if !defined(OS_WIN)
+
+bool IsBinaryInstrumented() {
+  return false;
+}
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+  return NULL;
+}
+
+DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
+  return NULL;
+}
+
+AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
+  return NULL;
+}
+
+MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
+  return NULL;
+}
+
+#else  // defined(OS_WIN)
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+bool IsBinaryInstrumented() {
+  enum InstrumentationCheckState {
+    UNINITIALIZED,
+    INSTRUMENTED_IMAGE,
+    NON_INSTRUMENTED_IMAGE,
+  };
+
+  static InstrumentationCheckState state = UNINITIALIZED;
+
+  if (state == UNINITIALIZED) {
+    HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+    base::win::PEImage image(this_module);
+
+    // Check to be sure our image is structured as we'd expect.
+    DCHECK(image.VerifyMagic());
+
+    // Syzygy-instrumented binaries contain a PE image section named ".thunks",
+    // and all Syzygy-modified binaries contain the ".syzygy" image section.
+    // This is a very fast check, as it only looks at the image header.
+    if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
+        (image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
+      state = INSTRUMENTED_IMAGE;
+    } else {
+      state = NON_INSTRUMENTED_IMAGE;
+    }
+  }
+  DCHECK(state != UNINITIALIZED);
+
+  return state == INSTRUMENTED_IMAGE;
+}
+
+namespace {
+
+struct FunctionSearchContext {
+  const char* name;
+  FARPROC function;
+};
+
+// Callback function to PEImage::EnumImportChunks.
+bool FindResolutionFunctionInImports(
+    const base::win::PEImage &image, const char* module_name,
+    PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
+    PVOID cookie) {
+  FunctionSearchContext* context =
+      reinterpret_cast<FunctionSearchContext*>(cookie);
+
+  DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context);
+  DCHECK_EQ(static_cast<FARPROC>(NULL), context->function);
+
+  // Our import address table contains pointers to the functions we import
+  // at this point. Let's retrieve the first such function and use it to
+  // find the module this import was resolved to by the loader.
+  const wchar_t* function_in_module =
+      reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
+
+  // Retrieve the module by a function in the module.
+  const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
+  HMODULE module = NULL;
+  if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
+    // This can happen if someone IAT patches us to a thunk.
+    return true;
+  }
+
+  // See whether this module exports the function we're looking for.
+  FARPROC exported_func = ::GetProcAddress(module, context->name);
+  if (exported_func != NULL) {
+    // We found it, return the function and terminate the enumeration.
+    context->function = exported_func;
+    return false;
+  }
+
+  // Keep going.
+  return true;
+}
+
+template <typename FunctionType>
+FunctionType FindFunctionInImports(const char* function_name) {
+  if (!IsBinaryInstrumented())
+    return NULL;
+
+  HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+  base::win::PEImage image(this_module);
+
+  FunctionSearchContext ctx = { function_name, NULL };
+  image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
+
+  return reinterpret_cast<FunctionType>(ctx.function);
+}
+
+}  // namespace
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+  return FindFunctionInImports<ReturnAddressLocationResolver>(
+      "ResolveReturnAddressLocation");
+}
+
+DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
+  return FindFunctionInImports<DynamicFunctionEntryHook>(
+      "OnDynamicFunctionEntry");
+}
+
+AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
+  return FindFunctionInImports<AddDynamicSymbol>(
+      "AddDynamicSymbol");
+}
+
+MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
+  return FindFunctionInImports<MoveDynamicSymbol>(
+      "MoveDynamicSymbol");
+}
+
+#endif  // defined(OS_WIN)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/profiler.h b/base/debug/profiler.h
new file mode 100644
index 0000000..c50555e
--- /dev/null
+++ b/base/debug/profiler.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_PROFILER_H_
+#define BASE_DEBUG_PROFILER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// The Profiler functions allow usage of the underlying sampling based
+// profiler. If the application has not been built with the necessary
+// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
+// are noops.
+namespace base {
+namespace debug {
+
+// Start profiling with the supplied name.
+// {pid} will be replaced by the process' pid and {count} will be replaced
+// by the count of the profile run (starts at 1 with each process).
+BASE_EXPORT void StartProfiling(const std::string& name);
+
+// Stop profiling and write out data.
+BASE_EXPORT void StopProfiling();
+
+// Force data to be written to file.
+BASE_EXPORT void FlushProfiling();
+
+// Returns true if process is being profiled.
+BASE_EXPORT bool BeingProfiled();
+
+// Reset profiling after a fork, which disables timers.
+BASE_EXPORT void RestartProfilingAfterFork();
+
+// Returns true iff this executable is instrumented with the Syzygy profiler.
+BASE_EXPORT bool IsBinaryInstrumented();
+
+// There's a class of profilers that use "return address swizzling" to get a
+// hook on function exits. This class of profilers uses some form of entry hook,
+// like e.g. binary instrumentation, or a compiler flag, that calls a hook each
+// time a function is invoked. The hook then switches the return address on the
+// stack for the address of an exit hook function, and pushes the original
+// return address to a shadow stack of some type. When in due course the CPU
+// executes a return to the exit hook, the exit hook will do whatever work it
+// does on function exit, then arrange to return to the original return address.
+// This class of profiler does not play well with programs that look at the
+// return address, as does e.g. V8. V8 uses the return address to certain
+// runtime functions to find the JIT code that called it, and from there finds
+// the V8 data structures associated to the JS function involved.
+// A return address resolution function is used to fix this. It allows such
+// programs to resolve a location on stack where a return address originally
+// resided, to the shadow stack location where the profiler stashed it.
+typedef uintptr_t (*ReturnAddressLocationResolver)(
+    uintptr_t return_addr_location);
+
+// This type declaration must match V8's FunctionEntryHook.
+typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
+                                         uintptr_t return_addr_location);
+
+// The functions below here are to support profiling V8-generated code.
+// V8 has provisions for generating a call to an entry hook for newly generated
+// JIT code, and it can push symbol information on code generation and advise
+// when the garbage collector moves code. The functions declarations below here
+// make glue between V8's facilities and a profiler.
+
+// This type declaration must match V8's FunctionEntryHook.
+typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
+                                         uintptr_t return_addr_location);
+
+typedef void (*AddDynamicSymbol)(const void* address,
+                                 size_t length,
+                                 const char* name,
+                                 size_t name_len);
+typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address);
+
+
+// If this binary is instrumented and the instrumentation supplies a function
+// for each of those purposes, find and return the function in question.
+// Otherwise returns NULL.
+BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc();
+BASE_EXPORT DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc();
+BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc();
+BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_PROFILER_H__
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
new file mode 100644
index 0000000..ce9e9ad
--- /dev/null
+++ b/base/debug/stack_trace.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/stack_trace.h"
+
+#include "base/basictypes.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <sstream>
+
+namespace base {
+namespace debug {
+
+StackTrace::StackTrace(const void* const* trace, size_t count) {
+  count = std::min(count, arraysize(trace_));
+  if (count)
+    memcpy(trace_, trace, count * sizeof(trace_[0]));
+  count_ = count;
+}
+
+StackTrace::~StackTrace() {
+}
+
+const void *const *StackTrace::Addresses(size_t* count) const {
+  *count = count_;
+  if (count_)
+    return trace_;
+  return NULL;
+}
+
+std::string StackTrace::ToString() const {
+  std::stringstream stream;
+#if !defined(__UCLIBC__)
+  OutputToStream(&stream);
+#endif
+  return stream.str();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
new file mode 100644
index 0000000..fb271b6
--- /dev/null
+++ b/base/debug/stack_trace.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_STACK_TRACE_H_
+#define BASE_DEBUG_STACK_TRACE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN)
+struct _EXCEPTION_POINTERS;
+struct _CONTEXT;
+#endif
+
+namespace base {
+namespace debug {
+
+// Enables stack dump to console output on exception and signals.
+// When enabled, the process will quit immediately. This is meant to be used in
+// unit_tests only! This is not thread-safe: only call from main thread.
+BASE_EXPORT bool EnableInProcessStackDumping();
+
+// A different version of EnableInProcessStackDumping that also works for
+// sandboxed processes.  For more details take a look at the description
+// of EnableInProcessStackDumping.
+// Calling this function on Linux opens /proc/self/maps and caches its
+// contents. In DEBUG builds, this function also opens the object files that
+// are loaded in memory and caches their file descriptors (this cannot be
+// done in official builds because it has security implications).
+BASE_EXPORT bool EnableInProcessStackDumpingForSandbox();
+
+// A stacktrace can be helpful in debugging. For example, you can include a
+// stacktrace member in a object (probably around #ifndef NDEBUG) so that you
+// can later see where the given object was created from.
+class BASE_EXPORT StackTrace {
+ public:
+  // Creates a stacktrace from the current location.
+  StackTrace();
+
+  // Creates a stacktrace from an existing array of instruction
+  // pointers (such as returned by Addresses()).  |count| will be
+  // trimmed to |kMaxTraces|.
+  StackTrace(const void* const* trace, size_t count);
+
+#if defined(OS_WIN)
+  // Creates a stacktrace for an exception.
+  // Note: this function will throw an import not found (StackWalk64) exception
+  // on system without dbghelp 5.1.
+  StackTrace(const _EXCEPTION_POINTERS* exception_pointers);
+  StackTrace(const _CONTEXT* context);
+#endif
+
+  // Copying and assignment are allowed with the default functions.
+
+  ~StackTrace();
+
+  // Gets an array of instruction pointer values. |*count| will be set to the
+  // number of elements in the returned array.
+  const void* const* Addresses(size_t* count) const;
+
+  // Prints the stack trace to stderr.
+  void Print() const;
+
+#if !defined(__UCLIBC__)
+  // Resolves backtrace to symbols and write to stream.
+  void OutputToStream(std::ostream* os) const;
+#endif
+
+  // Resolves backtrace to symbols and returns as string.
+  std::string ToString() const;
+
+ private:
+#if defined(OS_WIN)
+  void InitTrace(_CONTEXT* context_record);
+#endif
+
+  // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
+  // the sum of FramesToSkip and FramesToCapture must be less than 63,
+  // so set it to 62. Even if on POSIX it could be a larger value, it usually
+  // doesn't give much more information.
+  static const int kMaxTraces = 62;
+
+  void* trace_[kMaxTraces];
+
+  // The number of valid frames in |trace_|.
+  size_t count_;
+};
+
+namespace internal {
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+BASE_EXPORT char *itoa_r(intptr_t i,
+                         char *buf,
+                         size_t sz,
+                         int base,
+                         size_t padding);
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+}  // namespace internal
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_STACK_TRACE_H_
diff --git a/base/debug/stack_trace_android.cc b/base/debug/stack_trace_android.cc
new file mode 100644
index 0000000..5168b18
--- /dev/null
+++ b/base/debug/stack_trace_android.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/stack_trace.h"
+
+#include <android/log.h>
+#include <unwind.h>
+#include <ostream>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+
+#ifdef __LP64__
+#define FMT_ADDR  "0x%016lx"
+#else
+#define FMT_ADDR  "0x%08x"
+#endif
+
+namespace {
+
+struct StackCrawlState {
+  StackCrawlState(uintptr_t* frames, size_t max_depth)
+      : frames(frames),
+        frame_count(0),
+        max_depth(max_depth),
+        have_skipped_self(false) {}
+
+  uintptr_t* frames;
+  size_t frame_count;
+  size_t max_depth;
+  bool have_skipped_self;
+};
+
+_Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) {
+  StackCrawlState* state = static_cast<StackCrawlState*>(arg);
+  uintptr_t ip = _Unwind_GetIP(context);
+
+  // The first stack frame is this function itself.  Skip it.
+  if (ip != 0 && !state->have_skipped_self) {
+    state->have_skipped_self = true;
+    return _URC_NO_REASON;
+  }
+
+  state->frames[state->frame_count++] = ip;
+  if (state->frame_count >= state->max_depth)
+    return _URC_END_OF_STACK;
+  return _URC_NO_REASON;
+}
+
+}  // namespace
+
+namespace base {
+namespace debug {
+
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  // TODO(phajdan.jr): De-duplicate this SIGPIPE code.
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  action.sa_handler = SIG_IGN;
+  sigemptyset(&action.sa_mask);
+  return (sigaction(SIGPIPE, &action, NULL) == 0);
+}
+
+StackTrace::StackTrace() {
+  StackCrawlState state(reinterpret_cast<uintptr_t*>(trace_), kMaxTraces);
+  _Unwind_Backtrace(&TraceStackFrame, &state);
+  count_ = state.frame_count;
+}
+
+void StackTrace::Print() const {
+  std::string backtrace = ToString();
+  __android_log_write(ANDROID_LOG_ERROR, "chromium", backtrace.c_str());
+}
+
+// NOTE: Native libraries in APKs are stripped before installing. Print out the
+// relocatable address and library names so host computers can use tools to
+// symbolize and demangle (e.g., addr2line, c++filt).
+void StackTrace::OutputToStream(std::ostream* os) const {
+  std::string proc_maps;
+  std::vector<MappedMemoryRegion> regions;
+  // Allow IO to read /proc/self/maps. Reading this file doesn't hit the disk
+  // since it lives in procfs, and this is currently used to print a stack trace
+  // on fatal log messages in debug builds only. If the restriction is enabled
+  // then it will recursively trigger fatal failures when this enters on the
+  // UI thread.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  if (!ReadProcMaps(&proc_maps)) {
+    __android_log_write(
+        ANDROID_LOG_ERROR, "chromium", "Failed to read /proc/self/maps");
+  } else if (!ParseProcMaps(proc_maps, &regions)) {
+    __android_log_write(
+        ANDROID_LOG_ERROR, "chromium", "Failed to parse /proc/self/maps");
+  }
+
+  for (size_t i = 0; i < count_; ++i) {
+    // Subtract one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    uintptr_t address = reinterpret_cast<uintptr_t>(trace_[i]) - 1;
+
+    std::vector<MappedMemoryRegion>::iterator iter = regions.begin();
+    while (iter != regions.end()) {
+      if (address >= iter->start && address < iter->end &&
+          !iter->path.empty()) {
+        break;
+      }
+      ++iter;
+    }
+
+    *os << base::StringPrintf("#%02zd " FMT_ADDR " ", i, address);
+
+    if (iter != regions.end()) {
+      uintptr_t rel_pc = address - iter->start + iter->offset;
+      const char* path = iter->path.c_str();
+      *os << base::StringPrintf("%s+" FMT_ADDR, path, rel_pc);
+    } else {
+      *os << "<unknown>";
+    }
+
+    *os << "\n";
+  }
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
new file mode 100644
index 0000000..2eac14e
--- /dev/null
+++ b/base/debug/stack_trace_posix.cc
@@ -0,0 +1,833 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/stack_trace.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <map>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+#if !defined(__UCLIBC__)
+#include <execinfo.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "base/debug/proc_maps_linux.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+namespace base {
+namespace debug {
+
+namespace {
+
+volatile sig_atomic_t in_signal_handler = 0;
+
+#if !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
+// The prefix used for mangled symbols, per the Itanium C++ ABI:
+// http://www.codesourcery.com/cxx-abi/abi.html#mangling
+const char kMangledSymbolPrefix[] = "_Z";
+
+// Characters that can be used for symbols, generated by Ruby:
+// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
+const char kSymbolCharacters[] =
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+#endif  // !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
+
+#if !defined(USE_SYMBOLIZE)
+// Demangles C++ symbols in the given text. Example:
+//
+// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
+// =>
+// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
+void DemangleSymbols(std::string* text) {
+  // Note: code in this function is NOT async-signal safe (std::string uses
+  // malloc internally).
+
+#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
+
+  std::string::size_type search_from = 0;
+  while (search_from < text->size()) {
+    // Look for the start of a mangled symbol, from search_from.
+    std::string::size_type mangled_start =
+        text->find(kMangledSymbolPrefix, search_from);
+    if (mangled_start == std::string::npos) {
+      break;  // Mangled symbol not found.
+    }
+
+    // Look for the end of the mangled symbol.
+    std::string::size_type mangled_end =
+        text->find_first_not_of(kSymbolCharacters, mangled_start);
+    if (mangled_end == std::string::npos) {
+      mangled_end = text->size();
+    }
+    std::string mangled_symbol =
+        text->substr(mangled_start, mangled_end - mangled_start);
+
+    // Try to demangle the mangled symbol candidate.
+    int status = 0;
+    scoped_ptr<char, base::FreeDeleter> demangled_symbol(
+        abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status));
+    if (status == 0) {  // Demangling is successful.
+      // Remove the mangled symbol.
+      text->erase(mangled_start, mangled_end - mangled_start);
+      // Insert the demangled symbol.
+      text->insert(mangled_start, demangled_symbol.get());
+      // Next time, we'll start right after the demangled symbol we inserted.
+      search_from = mangled_start + strlen(demangled_symbol.get());
+    } else {
+      // Failed to demangle.  Retry after the "_Z" we just found.
+      search_from = mangled_start + 2;
+    }
+  }
+
+#endif  // defined(__GLIBCXX__) && !defined(__UCLIBC__)
+}
+#endif  // !defined(USE_SYMBOLIZE)
+
+class BacktraceOutputHandler {
+ public:
+  virtual void HandleOutput(const char* output) = 0;
+
+ protected:
+  virtual ~BacktraceOutputHandler() {}
+};
+
+void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
+  // This should be more than enough to store a 64-bit number in hex:
+  // 16 hex digits + 1 for null-terminator.
+  char buf[17] = { '\0' };
+  handler->HandleOutput("0x");
+  internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
+                   buf, sizeof(buf), 16, 12);
+  handler->HandleOutput(buf);
+}
+
+#if defined(USE_SYMBOLIZE)
+void OutputFrameId(intptr_t frame_id, BacktraceOutputHandler* handler) {
+  // Max unsigned 64-bit number in decimal has 20 digits (18446744073709551615).
+  // Hence, 30 digits should be more than enough to represent it in decimal
+  // (including the null-terminator).
+  char buf[30] = { '\0' };
+  handler->HandleOutput("#");
+  internal::itoa_r(frame_id, buf, sizeof(buf), 10, 1);
+  handler->HandleOutput(buf);
+}
+#endif  // defined(USE_SYMBOLIZE)
+
+void ProcessBacktrace(void *const *trace,
+                      size_t size,
+                      BacktraceOutputHandler* handler) {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if defined(USE_SYMBOLIZE)
+  for (size_t i = 0; i < size; ++i) {
+    OutputFrameId(i, handler);
+    handler->HandleOutput(" ");
+    OutputPointer(trace[i], handler);
+    handler->HandleOutput(" ");
+
+    char buf[1024] = { '\0' };
+
+    // Subtract by one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    void* address = static_cast<char*>(trace[i]) - 1;
+    if (google::Symbolize(address, buf, sizeof(buf)))
+      handler->HandleOutput(buf);
+    else
+      handler->HandleOutput("<unknown>");
+
+    handler->HandleOutput("\n");
+  }
+#elif !defined(__UCLIBC__)
+  bool printed = false;
+
+  // Below part is async-signal unsafe (uses malloc), so execute it only
+  // when we are not executing the signal handler.
+  if (in_signal_handler == 0) {
+    scoped_ptr<char*, FreeDeleter>
+        trace_symbols(backtrace_symbols(trace, size));
+    if (trace_symbols.get()) {
+      for (size_t i = 0; i < size; ++i) {
+        std::string trace_symbol = trace_symbols.get()[i];
+        DemangleSymbols(&trace_symbol);
+        handler->HandleOutput(trace_symbol.c_str());
+        handler->HandleOutput("\n");
+      }
+
+      printed = true;
+    }
+  }
+
+  if (!printed) {
+    for (size_t i = 0; i < size; ++i) {
+      handler->HandleOutput(" [");
+      OutputPointer(trace[i], handler);
+      handler->HandleOutput("]\n");
+    }
+  }
+#endif  // defined(USE_SYMBOLIZE)
+}
+
+void PrintToStderr(const char* output) {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+  ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output))));
+}
+
+void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
+  // NOTE: This code MUST be async-signal safe.
+  // NO malloc or stdio is allowed here.
+
+  // Record the fact that we are in the signal handler now, so that the rest
+  // of StackTrace can behave in an async-signal-safe manner.
+  in_signal_handler = 1;
+
+  if (BeingDebugged())
+    BreakDebugger();
+
+  PrintToStderr("Received signal ");
+  char buf[1024] = { 0 };
+  internal::itoa_r(signal, buf, sizeof(buf), 10, 0);
+  PrintToStderr(buf);
+  if (signal == SIGBUS) {
+    if (info->si_code == BUS_ADRALN)
+      PrintToStderr(" BUS_ADRALN ");
+    else if (info->si_code == BUS_ADRERR)
+      PrintToStderr(" BUS_ADRERR ");
+    else if (info->si_code == BUS_OBJERR)
+      PrintToStderr(" BUS_OBJERR ");
+    else
+      PrintToStderr(" <unknown> ");
+  } else if (signal == SIGFPE) {
+    if (info->si_code == FPE_FLTDIV)
+      PrintToStderr(" FPE_FLTDIV ");
+    else if (info->si_code == FPE_FLTINV)
+      PrintToStderr(" FPE_FLTINV ");
+    else if (info->si_code == FPE_FLTOVF)
+      PrintToStderr(" FPE_FLTOVF ");
+    else if (info->si_code == FPE_FLTRES)
+      PrintToStderr(" FPE_FLTRES ");
+    else if (info->si_code == FPE_FLTSUB)
+      PrintToStderr(" FPE_FLTSUB ");
+    else if (info->si_code == FPE_FLTUND)
+      PrintToStderr(" FPE_FLTUND ");
+    else if (info->si_code == FPE_INTDIV)
+      PrintToStderr(" FPE_INTDIV ");
+    else if (info->si_code == FPE_INTOVF)
+      PrintToStderr(" FPE_INTOVF ");
+    else
+      PrintToStderr(" <unknown> ");
+  } else if (signal == SIGILL) {
+    if (info->si_code == ILL_BADSTK)
+      PrintToStderr(" ILL_BADSTK ");
+    else if (info->si_code == ILL_COPROC)
+      PrintToStderr(" ILL_COPROC ");
+    else if (info->si_code == ILL_ILLOPN)
+      PrintToStderr(" ILL_ILLOPN ");
+    else if (info->si_code == ILL_ILLADR)
+      PrintToStderr(" ILL_ILLADR ");
+    else if (info->si_code == ILL_ILLTRP)
+      PrintToStderr(" ILL_ILLTRP ");
+    else if (info->si_code == ILL_PRVOPC)
+      PrintToStderr(" ILL_PRVOPC ");
+    else if (info->si_code == ILL_PRVREG)
+      PrintToStderr(" ILL_PRVREG ");
+    else
+      PrintToStderr(" <unknown> ");
+  } else if (signal == SIGSEGV) {
+    if (info->si_code == SEGV_MAPERR)
+      PrintToStderr(" SEGV_MAPERR ");
+    else if (info->si_code == SEGV_ACCERR)
+      PrintToStderr(" SEGV_ACCERR ");
+    else
+      PrintToStderr(" <unknown> ");
+  }
+  if (signal == SIGBUS || signal == SIGFPE ||
+      signal == SIGILL || signal == SIGSEGV) {
+    internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr),
+                     buf, sizeof(buf), 16, 12);
+    PrintToStderr(buf);
+  }
+  PrintToStderr("\n");
+
+  debug::StackTrace().Print();
+
+#if defined(OS_LINUX)
+#if ARCH_CPU_X86_FAMILY
+  ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
+  const struct {
+    const char* label;
+    greg_t value;
+  } registers[] = {
+#if ARCH_CPU_32_BITS
+    { "  gs: ", context->uc_mcontext.gregs[REG_GS] },
+    { "  fs: ", context->uc_mcontext.gregs[REG_FS] },
+    { "  es: ", context->uc_mcontext.gregs[REG_ES] },
+    { "  ds: ", context->uc_mcontext.gregs[REG_DS] },
+    { " edi: ", context->uc_mcontext.gregs[REG_EDI] },
+    { " esi: ", context->uc_mcontext.gregs[REG_ESI] },
+    { " ebp: ", context->uc_mcontext.gregs[REG_EBP] },
+    { " esp: ", context->uc_mcontext.gregs[REG_ESP] },
+    { " ebx: ", context->uc_mcontext.gregs[REG_EBX] },
+    { " edx: ", context->uc_mcontext.gregs[REG_EDX] },
+    { " ecx: ", context->uc_mcontext.gregs[REG_ECX] },
+    { " eax: ", context->uc_mcontext.gregs[REG_EAX] },
+    { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
+    { " err: ", context->uc_mcontext.gregs[REG_ERR] },
+    { "  ip: ", context->uc_mcontext.gregs[REG_EIP] },
+    { "  cs: ", context->uc_mcontext.gregs[REG_CS] },
+    { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
+    { " usp: ", context->uc_mcontext.gregs[REG_UESP] },
+    { "  ss: ", context->uc_mcontext.gregs[REG_SS] },
+#elif ARCH_CPU_64_BITS
+    { "  r8: ", context->uc_mcontext.gregs[REG_R8] },
+    { "  r9: ", context->uc_mcontext.gregs[REG_R9] },
+    { " r10: ", context->uc_mcontext.gregs[REG_R10] },
+    { " r11: ", context->uc_mcontext.gregs[REG_R11] },
+    { " r12: ", context->uc_mcontext.gregs[REG_R12] },
+    { " r13: ", context->uc_mcontext.gregs[REG_R13] },
+    { " r14: ", context->uc_mcontext.gregs[REG_R14] },
+    { " r15: ", context->uc_mcontext.gregs[REG_R15] },
+    { "  di: ", context->uc_mcontext.gregs[REG_RDI] },
+    { "  si: ", context->uc_mcontext.gregs[REG_RSI] },
+    { "  bp: ", context->uc_mcontext.gregs[REG_RBP] },
+    { "  bx: ", context->uc_mcontext.gregs[REG_RBX] },
+    { "  dx: ", context->uc_mcontext.gregs[REG_RDX] },
+    { "  ax: ", context->uc_mcontext.gregs[REG_RAX] },
+    { "  cx: ", context->uc_mcontext.gregs[REG_RCX] },
+    { "  sp: ", context->uc_mcontext.gregs[REG_RSP] },
+    { "  ip: ", context->uc_mcontext.gregs[REG_RIP] },
+    { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
+    { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
+    { " erf: ", context->uc_mcontext.gregs[REG_ERR] },
+    { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
+    { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
+    { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
+#endif
+  };
+
+#if ARCH_CPU_32_BITS
+  const int kRegisterPadding = 8;
+#elif ARCH_CPU_64_BITS
+  const int kRegisterPadding = 16;
+#endif
+
+  for (size_t i = 0; i < arraysize(registers); i++) {
+    PrintToStderr(registers[i].label);
+    internal::itoa_r(registers[i].value, buf, sizeof(buf),
+                     16, kRegisterPadding);
+    PrintToStderr(buf);
+
+    if ((i + 1) % 4 == 0)
+      PrintToStderr("\n");
+  }
+  PrintToStderr("\n");
+#endif
+#elif defined(OS_MACOSX)
+  // TODO(shess): Port to 64-bit, and ARM architecture (32 and 64-bit).
+#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
+  ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
+  size_t len;
+
+  // NOTE: Even |snprintf()| is not on the approved list for signal
+  // handlers, but buffered I/O is definitely not on the list due to
+  // potential for |malloc()|.
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "ax: %x, bx: %x, cx: %x, dx: %x\n",
+               context->uc_mcontext->__ss.__eax,
+               context->uc_mcontext->__ss.__ebx,
+               context->uc_mcontext->__ss.__ecx,
+               context->uc_mcontext->__ss.__edx));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
+               context->uc_mcontext->__ss.__edi,
+               context->uc_mcontext->__ss.__esi,
+               context->uc_mcontext->__ss.__ebp,
+               context->uc_mcontext->__ss.__esp,
+               context->uc_mcontext->__ss.__ss,
+               context->uc_mcontext->__ss.__eflags));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
+               context->uc_mcontext->__ss.__eip,
+               context->uc_mcontext->__ss.__cs,
+               context->uc_mcontext->__ss.__ds,
+               context->uc_mcontext->__ss.__es,
+               context->uc_mcontext->__ss.__fs,
+               context->uc_mcontext->__ss.__gs));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+#endif  // ARCH_CPU_32_BITS
+#endif  // defined(OS_MACOSX)
+  _exit(1);
+}
+
+class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  PrintBacktraceOutputHandler() {}
+
+  void HandleOutput(const char* output) override {
+    // NOTE: This code MUST be async-signal safe (it's used by in-process
+    // stack dumping signal handler). NO malloc or stdio is allowed here.
+    PrintToStderr(output);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
+};
+
+class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
+  }
+
+  void HandleOutput(const char* output) override { (*os_) << output; }
+
+ private:
+  std::ostream* os_;
+
+  DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
+};
+
+void WarmUpBacktrace() {
+  // Warm up stack trace infrastructure. It turns out that on the first
+  // call glibc initializes some internal data structures using pthread_once,
+  // and even backtrace() can call malloc(), leading to hangs.
+  //
+  // Example stack trace snippet (with tcmalloc):
+  //
+  // #8  0x0000000000a173b5 in tc_malloc
+  //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
+  // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
+  // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
+  // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
+  // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
+  //             at dl-open.c:639
+  // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
+  // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
+  // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
+  // #16 __GI___libc_dlopen_mode at dl-libc.c:165
+  // #17 0x00007ffff61ef8f5 in init
+  //             at ../sysdeps/x86_64/../ia64/backtrace.c:53
+  // #18 0x00007ffff6aad400 in pthread_once
+  //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
+  // #19 0x00007ffff61efa14 in __GI___backtrace
+  //             at ../sysdeps/x86_64/../ia64/backtrace.c:104
+  // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
+  //             at base/debug/stack_trace_posix.cc:175
+  // #21 0x00000000007a4ae5 in
+  //             base::(anonymous namespace)::StackDumpSignalHandler
+  //             at base/process_util_posix.cc:172
+  // #22 <signal handler called>
+  StackTrace stack_trace;
+}
+
+}  // namespace
+
+#if defined(USE_SYMBOLIZE)
+
+// class SandboxSymbolizeHelper.
+//
+// The purpose of this class is to prepare and install a "file open" callback
+// needed by the stack trace symbolization code
+// (base/third_party/symbolize/symbolize.h) so that it can function properly
+// in a sandboxed process.  The caveat is that this class must be instantiated
+// before the sandboxing is enabled so that it can get the chance to open all
+// the object files that are loaded in the virtual address space of the current
+// process.
+class SandboxSymbolizeHelper {
+ public:
+  // Returns the singleton instance.
+  static SandboxSymbolizeHelper* GetInstance() {
+    return Singleton<SandboxSymbolizeHelper>::get();
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<SandboxSymbolizeHelper>;
+
+  SandboxSymbolizeHelper()
+      : is_initialized_(false) {
+    Init();
+  }
+
+  ~SandboxSymbolizeHelper() {
+    UnregisterCallback();
+    CloseObjectFiles();
+  }
+
+  // Returns a O_RDONLY file descriptor for |file_path| if it was opened
+  // sucessfully during the initialization.  The file is repositioned at
+  // offset 0.
+  // IMPORTANT: This function must be async-signal-safe because it can be
+  // called from a signal handler (symbolizing stack frames for a crash).
+  int GetFileDescriptor(const char* file_path) {
+    int fd = -1;
+
+#if !defined(NDEBUG)
+    if (file_path) {
+      // The assumption here is that iterating over std::map<std::string, int>
+      // using a const_iterator does not allocate dynamic memory, hense it is
+      // async-signal-safe.
+      std::map<std::string, int>::const_iterator it;
+      for (it = modules_.begin(); it != modules_.end(); ++it) {
+        if (strcmp((it->first).c_str(), file_path) == 0) {
+          // POSIX.1-2004 requires an implementation to guarantee that dup()
+          // is async-signal-safe.
+          fd = dup(it->second);
+          break;
+        }
+      }
+      // POSIX.1-2004 requires an implementation to guarantee that lseek()
+      // is async-signal-safe.
+      if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) {
+        // Failed to seek.
+        fd = -1;
+      }
+    }
+#endif  // !defined(NDEBUG)
+
+    return fd;
+  }
+
+  // Searches for the object file (from /proc/self/maps) that contains
+  // the specified pc.  If found, sets |start_address| to the start address
+  // of where this object file is mapped in memory, sets the module base
+  // address into |base_address|, copies the object file name into
+  // |out_file_name|, and attempts to open the object file.  If the object
+  // file is opened successfully, returns the file descriptor.  Otherwise,
+  // returns -1.  |out_file_name_size| is the size of the file name buffer
+  // (including the null terminator).
+  // IMPORTANT: This function must be async-signal-safe because it can be
+  // called from a signal handler (symbolizing stack frames for a crash).
+  static int OpenObjectFileContainingPc(uint64_t pc, uint64_t& start_address,
+                                        uint64_t& base_address, char* file_path,
+                                        int file_path_size) {
+    // This method can only be called after the singleton is instantiated.
+    // This is ensured by the following facts:
+    // * This is the only static method in this class, it is private, and
+    //   the class has no friends (except for the DefaultSingletonTraits).
+    //   The compiler guarantees that it can only be called after the
+    //   singleton is instantiated.
+    // * This method is used as a callback for the stack tracing code and
+    //   the callback registration is done in the constructor, so logically
+    //   it cannot be called before the singleton is created.
+    SandboxSymbolizeHelper* instance = GetInstance();
+
+    // The assumption here is that iterating over
+    // std::vector<MappedMemoryRegion> using a const_iterator does not allocate
+    // dynamic memory, hence it is async-signal-safe.
+    std::vector<MappedMemoryRegion>::const_iterator it;
+    bool is_first = true;
+    for (it = instance->regions_.begin(); it != instance->regions_.end();
+         ++it, is_first = false) {
+      const MappedMemoryRegion& region = *it;
+      if (region.start <= pc && pc < region.end) {
+        start_address = region.start;
+        // Don't subtract 'start_address' from the first entry:
+        // * If a binary is compiled w/o -pie, then the first entry in
+        //   process maps is likely the binary itself (all dynamic libs
+        //   are mapped higher in address space). For such a binary,
+        //   instruction offset in binary coincides with the actual
+        //   instruction address in virtual memory (as code section
+        //   is mapped to a fixed memory range).
+        // * If a binary is compiled with -pie, all the modules are
+        //   mapped high at address space (in particular, higher than
+        //   shadow memory of the tool), so the module can't be the
+        //   first entry.
+        base_address = (is_first ? 0U : start_address) - region.offset;
+        if (file_path && file_path_size > 0) {
+          strncpy(file_path, region.path.c_str(), file_path_size);
+          // Ensure null termination.
+          file_path[file_path_size - 1] = '\0';
+        }
+        return instance->GetFileDescriptor(region.path.c_str());
+      }
+    }
+    return -1;
+  }
+
+  // Parses /proc/self/maps in order to compile a list of all object file names
+  // for the modules that are loaded in the current process.
+  // Returns true on success.
+  bool CacheMemoryRegions() {
+    // Reads /proc/self/maps.
+    std::string contents;
+    if (!ReadProcMaps(&contents)) {
+      LOG(ERROR) << "Failed to read /proc/self/maps";
+      return false;
+    }
+
+    // Parses /proc/self/maps.
+    if (!ParseProcMaps(contents, &regions_)) {
+      LOG(ERROR) << "Failed to parse the contents of /proc/self/maps";
+      return false;
+    }
+
+    is_initialized_ = true;
+    return true;
+  }
+
+  // Opens all object files and caches their file descriptors.
+  void OpenSymbolFiles() {
+    // Pre-opening and caching the file descriptors of all loaded modules is
+    // not considered safe for retail builds.  Hence it is only done in debug
+    // builds.  For more details, take a look at: http://crbug.com/341966
+    // Enabling this to release mode would require approval from the security
+    // team.
+#if !defined(NDEBUG)
+    // Open the object files for all read-only executable regions and cache
+    // their file descriptors.
+    std::vector<MappedMemoryRegion>::const_iterator it;
+    for (it = regions_.begin(); it != regions_.end(); ++it) {
+      const MappedMemoryRegion& region = *it;
+      // Only interesed in read-only executable regions.
+      if ((region.permissions & MappedMemoryRegion::READ) ==
+              MappedMemoryRegion::READ &&
+          (region.permissions & MappedMemoryRegion::WRITE) == 0 &&
+          (region.permissions & MappedMemoryRegion::EXECUTE) ==
+              MappedMemoryRegion::EXECUTE) {
+        if (region.path.empty()) {
+          // Skip regions with empty file names.
+          continue;
+        }
+        if (region.path[0] == '[') {
+          // Skip pseudo-paths, like [stack], [vdso], [heap], etc ...
+          continue;
+        }
+        // Avoid duplicates.
+        if (modules_.find(region.path) == modules_.end()) {
+          int fd = open(region.path.c_str(), O_RDONLY | O_CLOEXEC);
+          if (fd >= 0) {
+            modules_.insert(std::make_pair(region.path, fd));
+          } else {
+            LOG(WARNING) << "Failed to open file: " << region.path
+                         << "\n  Error: " << strerror(errno);
+          }
+        }
+      }
+    }
+#endif  // !defined(NDEBUG)
+  }
+
+  // Initializes and installs the symbolization callback.
+  void Init() {
+    if (CacheMemoryRegions()) {
+      OpenSymbolFiles();
+      google::InstallSymbolizeOpenObjectFileCallback(
+          &OpenObjectFileContainingPc);
+    }
+  }
+
+  // Unregister symbolization callback.
+  void UnregisterCallback() {
+    if (is_initialized_) {
+      google::InstallSymbolizeOpenObjectFileCallback(NULL);
+      is_initialized_ = false;
+    }
+  }
+
+  // Closes all file descriptors owned by this instance.
+  void CloseObjectFiles() {
+#if !defined(NDEBUG)
+    std::map<std::string, int>::iterator it;
+    for (it = modules_.begin(); it != modules_.end(); ++it) {
+      int ret = IGNORE_EINTR(close(it->second));
+      DCHECK(!ret);
+      it->second = -1;
+    }
+    modules_.clear();
+#endif  // !defined(NDEBUG)
+  }
+
+  // Set to true upon successful initialization.
+  bool is_initialized_;
+
+#if !defined(NDEBUG)
+  // Mapping from file name to file descriptor.  Includes file descriptors
+  // for all successfully opened object files and the file descriptor for
+  // /proc/self/maps.  This code is not safe for release builds so
+  // this is only done for DEBUG builds.
+  std::map<std::string, int> modules_;
+#endif  // !defined(NDEBUG)
+
+  // Cache for the process memory regions.  Produced by parsing the contents
+  // of /proc/self/maps cache.
+  std::vector<MappedMemoryRegion> regions_;
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxSymbolizeHelper);
+};
+#endif  // USE_SYMBOLIZE
+
+bool EnableInProcessStackDumpingForSandbox() {
+#if defined(USE_SYMBOLIZE)
+  SandboxSymbolizeHelper::GetInstance();
+#endif  // USE_SYMBOLIZE
+
+  return EnableInProcessStackDumping();
+}
+
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  struct sigaction sigpipe_action;
+  memset(&sigpipe_action, 0, sizeof(sigpipe_action));
+  sigpipe_action.sa_handler = SIG_IGN;
+  sigemptyset(&sigpipe_action.sa_mask);
+  bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0);
+
+  // Avoid hangs during backtrace initialization, see above.
+  WarmUpBacktrace();
+
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  action.sa_flags = SA_RESETHAND | SA_SIGINFO;
+  action.sa_sigaction = &StackDumpSignalHandler;
+  sigemptyset(&action.sa_mask);
+
+  success &= (sigaction(SIGILL, &action, NULL) == 0);
+  success &= (sigaction(SIGABRT, &action, NULL) == 0);
+  success &= (sigaction(SIGFPE, &action, NULL) == 0);
+  success &= (sigaction(SIGBUS, &action, NULL) == 0);
+  success &= (sigaction(SIGSEGV, &action, NULL) == 0);
+// On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing.
+#if !defined(OS_LINUX)
+  success &= (sigaction(SIGSYS, &action, NULL) == 0);
+#endif  // !defined(OS_LINUX)
+
+  return success;
+}
+
+StackTrace::StackTrace() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if !defined(__UCLIBC__)
+  // Though the backtrace API man page does not list any possible negative
+  // return values, we take no chance.
+  count_ = base::saturated_cast<size_t>(backtrace(trace_, arraysize(trace_)));
+#else
+  count_ = 0;
+#endif
+}
+
+void StackTrace::Print() const {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if !defined(__UCLIBC__)
+  PrintBacktraceOutputHandler handler;
+  ProcessBacktrace(trace_, count_, &handler);
+#endif
+}
+
+#if !defined(__UCLIBC__)
+void StackTrace::OutputToStream(std::ostream* os) const {
+  StreamBacktraceOutputHandler handler(os);
+  ProcessBacktrace(trace_, count_, &handler);
+}
+#endif
+
+namespace internal {
+
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+  // Make sure we can write at least one NUL byte.
+  size_t n = 1;
+  if (n > sz)
+    return NULL;
+
+  if (base < 2 || base > 16) {
+    buf[0] = '\000';
+    return NULL;
+  }
+
+  char *start = buf;
+
+  uintptr_t j = i;
+
+  // Handle negative numbers (only for base 10).
+  if (i < 0 && base == 10) {
+    j = -i;
+
+    // Make sure we can write the '-' character.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+    *start++ = '-';
+  }
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  char *ptr = start;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+
+    // Output the next digit.
+    *ptr++ = "0123456789abcdef"[j % base];
+    j /= base;
+
+    if (padding > 0)
+      padding--;
+  } while (j > 0 || padding > 0);
+
+  // Terminate the output with a NUL character.
+  *ptr = '\000';
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible "-" sign).
+  while (--ptr > start) {
+    char ch = *ptr;
+    *ptr = *start;
+    *start++ = ch;
+  }
+  return buf;
+}
+
+}  // namespace internal
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
new file mode 100644
index 0000000..15c9093
--- /dev/null
+++ b/base/debug/stack_trace_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+#include <sstream>
+#include <string>
+
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/process/kill.h"
+#include "base/process/process_handle.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "base/test/multiprocess_test.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
+typedef MultiProcessTest StackTraceTest;
+#else
+typedef testing::Test StackTraceTest;
+#endif
+
+// Note: On Linux, this test currently only fully works on Debug builds.
+// See comments in the #ifdef soup if you intend to change this.
+#if defined(OS_WIN)
+// Always fails on Windows: crbug.com/32070
+#define MAYBE_OutputToStream DISABLED_OutputToStream
+#else
+#define MAYBE_OutputToStream OutputToStream
+#endif
+#if !defined(__UCLIBC__)
+TEST_F(StackTraceTest, MAYBE_OutputToStream) {
+  StackTrace trace;
+
+  // Dump the trace into a string.
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  std::string backtrace_message = os.str();
+
+  // ToString() should produce the same output.
+  EXPECT_EQ(backtrace_message, trace.ToString());
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+  // Stack traces require an extra data table that bloats our binaries,
+  // so they're turned off for release builds.  We stop the test here,
+  // at least letting us verify that the calls don't crash.
+  return;
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+
+  size_t frames_found = 0;
+  trace.Addresses(&frames_found);
+  ASSERT_GE(frames_found, 5u) <<
+      "No stack frames found.  Skipping rest of test.";
+
+  // Check if the output has symbol initialization warning.  If it does, fail.
+  ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"),
+            std::string::npos) <<
+      "Unable to resolve symbols.  Skipping rest of test.";
+
+#if defined(OS_MACOSX)
+#if 0
+  // Disabled due to -fvisibility=hidden in build config.
+
+  // Symbol resolution via the backtrace_symbol function does not work well
+  // in OS X.
+  // See this thread:
+  //
+  //    http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html
+  //
+  // Just check instead that we find our way back to the "start" symbol
+  // which should be the first symbol in the trace.
+  //
+  // TODO(port): Find a more reliable way to resolve symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("start") != std::string::npos)
+      << "Expected to find start in backtrace:\n"
+      << backtrace_message;
+
+#endif
+#elif defined(USE_SYMBOLIZE)
+  // This branch is for gcc-compiled code, but not Mac due to the
+  // above #if.
+  // Expect a demangled symbol.
+  EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") !=
+              std::string::npos)
+      << "Expected a demangled symbol in backtrace:\n"
+      << backtrace_message;
+
+#elif 0
+  // This is the fall-through case; it used to cover Windows.
+  // But it's disabled because of varying buildbot configs;
+  // some lack symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("main") != std::string::npos)
+      << "Expected to find main in backtrace:\n"
+      << backtrace_message;
+
+#if defined(OS_WIN)
+// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with
+// MSVC's __FUNCTION__ macro.
+#define __func__ __FUNCTION__
+#endif
+
+  // Expect to find this function as well.
+  // Note: This will fail if not linked with -rdynamic (aka -export_dynamic)
+  EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos)
+      << "Expected to find " << __func__ << " in backtrace:\n"
+      << backtrace_message;
+
+#endif  // define(OS_MACOSX)
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST_F(StackTraceTest, DebugOutputToStream) {
+  StackTrace trace;
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  VLOG(1) << os.str();
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST_F(StackTraceTest, DebugPrintBacktrace) {
+  StackTrace().Print();
+}
+#endif  // !defined(__UCLIBC__)
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#if !defined(OS_IOS)
+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) {
+  Process child = SpawnChild("MismatchedMallocChildProcess");
+  ASSERT_TRUE(child.IsValid());
+  int exit_code;
+  ASSERT_TRUE(child.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
+                                           &exit_code));
+}
+#endif  // !defined(OS_IOS)
+
+namespace {
+
+std::string itoa_r_wrapper(intptr_t i, size_t sz, int base, size_t padding) {
+  char buffer[1024];
+  CHECK_LE(sz, sizeof(buffer));
+
+  char* result = internal::itoa_r(i, buffer, sz, base, padding);
+  EXPECT_TRUE(result);
+  return std::string(buffer);
+}
+
+}  // namespace
+
+TEST_F(StackTraceTest, itoa_r) {
+  EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0));
+  EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0));
+
+  // Test edge cases.
+  if (sizeof(intptr_t) == 4) {
+    EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16, 0));
+    EXPECT_EQ("-2147483648",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
+    EXPECT_EQ("2147483647",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
+
+    EXPECT_EQ("80000000",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
+    EXPECT_EQ("7fffffff",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
+  } else if (sizeof(intptr_t) == 8) {
+    EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0));
+    EXPECT_EQ("-9223372036854775808",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
+    EXPECT_EQ("9223372036854775807",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
+
+    EXPECT_EQ("8000000000000000",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
+    EXPECT_EQ("7fffffffffffffff",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
+  } else {
+    ADD_FAILURE() << "Missing test case for your size of intptr_t ("
+                  << sizeof(intptr_t) << ")";
+  }
+
+  // Test hex output.
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
+  EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0));
+
+  // Check that itoa_r respects passed buffer size limit.
+  char buffer[1024];
+  EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0));
+  EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0));
+  EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0));
+  EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16, 0));
+  EXPECT_TRUE(internal::itoa_r(0xbeef, buffer, 5, 16, 4));
+  EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 5));
+  EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 6));
+
+  // Test padding.
+  EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 0));
+  EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 1));
+  EXPECT_EQ("01", itoa_r_wrapper(1, 128, 10, 2));
+  EXPECT_EQ("001", itoa_r_wrapper(1, 128, 10, 3));
+  EXPECT_EQ("0001", itoa_r_wrapper(1, 128, 10, 4));
+  EXPECT_EQ("00001", itoa_r_wrapper(1, 128, 10, 5));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 1));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 2));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 3));
+  EXPECT_EQ("0688", itoa_r_wrapper(0x688, 128, 16, 4));
+  EXPECT_EQ("00688", itoa_r_wrapper(0x688, 128, 16, 5));
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
new file mode 100644
index 0000000..55d5562
--- /dev/null
+++ b/base/debug/stack_trace_win.cc
@@ -0,0 +1,283 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/stack_trace.h"
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#include <iostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/lock.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Previous unhandled filter. Will be called if not NULL when we intercept an
+// exception. Only used in unit tests.
+LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
+
+// Prints the exception call stack.
+// This is the unit tests exception filter.
+long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
+  debug::StackTrace(info).Print();
+  if (g_previous_filter)
+    return g_previous_filter(info);
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+FilePath GetExePath() {
+  wchar_t system_buffer[MAX_PATH];
+  GetModuleFileName(NULL, system_buffer, MAX_PATH);
+  system_buffer[MAX_PATH - 1] = L'\0';
+  return FilePath(system_buffer);
+}
+
+// SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family
+// of functions.  The Sym* family of functions may only be invoked by one
+// thread at a time.  SymbolContext code may access a symbol server over the
+// network while holding the lock for this singleton.  In the case of high
+// latency, this code will adversely affect performance.
+//
+// There is also a known issue where this backtrace code can interact
+// badly with breakpad if breakpad is invoked in a separate thread while
+// we are using the Sym* functions.  This is because breakpad does now
+// share a lock with this function.  See this related bug:
+//
+//   http://code.google.com/p/google-breakpad/issues/detail?id=311
+//
+// This is a very unlikely edge case, and the current solution is to
+// just ignore it.
+class SymbolContext {
+ public:
+  static SymbolContext* GetInstance() {
+    // We use a leaky singleton because code may call this during process
+    // termination.
+    return
+      Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get();
+  }
+
+  // Returns the error code of a failed initialization.
+  DWORD init_error() const {
+    return init_error_;
+  }
+
+  // For the given trace, attempts to resolve the symbols, and output a trace
+  // to the ostream os.  The format for each line of the backtrace is:
+  //
+  //    <tab>SymbolName[0xAddress+Offset] (FileName:LineNo)
+  //
+  // This function should only be called if Init() has been called.  We do not
+  // LOG(FATAL) here because this code is called might be triggered by a
+  // LOG(FATAL) itself. Also, it should not be calling complex code that is
+  // extensible like PathService since that can in turn fire CHECKs.
+  void OutputTraceToStream(const void* const* trace,
+                           size_t count,
+                           std::ostream* os) {
+    base::AutoLock lock(lock_);
+
+    for (size_t i = 0; (i < count) && os->good(); ++i) {
+      const int kMaxNameLength = 256;
+      DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]);
+
+      // Code adapted from MSDN example:
+      // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+      ULONG64 buffer[
+        (sizeof(SYMBOL_INFO) +
+          kMaxNameLength * sizeof(wchar_t) +
+          sizeof(ULONG64) - 1) /
+        sizeof(ULONG64)];
+      memset(buffer, 0, sizeof(buffer));
+
+      // Initialize symbol information retrieval structures.
+      DWORD64 sym_displacement = 0;
+      PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
+      symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+      symbol->MaxNameLen = kMaxNameLength - 1;
+      BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame,
+                                    &sym_displacement, symbol);
+
+      // Attempt to retrieve line number information.
+      DWORD line_displacement = 0;
+      IMAGEHLP_LINE64 line = {};
+      line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+      BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
+                                           &line_displacement, &line);
+
+      // Output the backtrace line.
+      (*os) << "\t";
+      if (has_symbol) {
+        (*os) << symbol->Name << " [0x" << trace[i] << "+"
+              << sym_displacement << "]";
+      } else {
+        // If there is no symbol information, add a spacer.
+        (*os) << "(No symbol) [0x" << trace[i] << "]";
+      }
+      if (has_line) {
+        (*os) << " (" << line.FileName << ":" << line.LineNumber << ")";
+      }
+      (*os) << "\n";
+    }
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<SymbolContext>;
+
+  SymbolContext() : init_error_(ERROR_SUCCESS) {
+    // Initializes the symbols for the process.
+    // Defer symbol load until they're needed, use undecorated names, and
+    // get line numbers.
+    SymSetOptions(SYMOPT_DEFERRED_LOADS |
+                  SYMOPT_UNDNAME |
+                  SYMOPT_LOAD_LINES);
+    if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+      init_error_ = GetLastError();
+      // TODO(awong): Handle error: SymInitialize can fail with
+      // ERROR_INVALID_PARAMETER.
+      // When it fails, we should not call debugbreak since it kills the current
+      // process (prevents future tests from running or kills the browser
+      // process).
+      DLOG(ERROR) << "SymInitialize failed: " << init_error_;
+      return;
+    }
+
+    init_error_ = ERROR_SUCCESS;
+
+    // When transferring the binaries e.g. between bots, path put
+    // into the executable will get off. To still retrieve symbols correctly,
+    // add the directory of the executable to symbol search path.
+    // All following errors are non-fatal.
+    const size_t kSymbolsArraySize = 1024;
+    scoped_ptr<wchar_t[]> symbols_path(new wchar_t[kSymbolsArraySize]);
+
+    // Note: The below function takes buffer size as number of characters,
+    // not number of bytes!
+    if (!SymGetSearchPathW(GetCurrentProcess(),
+                           symbols_path.get(),
+                           kSymbolsArraySize)) {
+      DLOG(WARNING) << "SymGetSearchPath failed: ";
+      return;
+    }
+
+    std::wstring new_path(std::wstring(symbols_path.get()) +
+                          L";" + GetExePath().DirName().value());
+    if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) {
+      DLOG(WARNING) << "SymSetSearchPath failed.";
+      return;
+    }
+  }
+
+  DWORD init_error_;
+  base::Lock lock_;
+  DISALLOW_COPY_AND_ASSIGN(SymbolContext);
+};
+
+}  // namespace
+
+bool EnableInProcessStackDumping() {
+  // Add stack dumping support on exception on windows. Similar to OS_POSIX
+  // signal() handling in process_util_posix.cc.
+  g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
+  RouteStdioToConsole();
+  return true;
+}
+
+// Disable optimizations for the StackTrace::StackTrace function. It is
+// important to disable at least frame pointer optimization ("y"), since
+// that breaks CaptureStackBackTrace() and prevents StackTrace from working
+// in Release builds (it may still be janky if other frames are using FPO,
+// but at least it will make it further).
+#if defined(COMPILER_MSVC)
+#pragma optimize("", off)
+#endif
+
+StackTrace::StackTrace() {
+  // When walking our own stack, use CaptureStackBackTrace().
+  count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_, NULL);
+}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+StackTrace::StackTrace(const EXCEPTION_POINTERS* exception_pointers) {
+  // StackWalk64() may modify context record passed to it, so we will
+  // use a copy.
+  CONTEXT context_record = *exception_pointers->ContextRecord;
+  InitTrace(&context_record);
+}
+
+StackTrace::StackTrace(const CONTEXT* context) {
+  // StackWalk64() may modify context record passed to it, so we will
+  // use a copy.
+  CONTEXT context_record = *context;
+  InitTrace(&context_record);
+}
+
+void StackTrace::InitTrace(CONTEXT* context_record) {
+  // When walking an exception stack, we need to use StackWalk64().
+  count_ = 0;
+  // Initialize stack walking.
+  STACKFRAME64 stack_frame;
+  memset(&stack_frame, 0, sizeof(stack_frame));
+#if defined(_WIN64)
+  int machine_type = IMAGE_FILE_MACHINE_AMD64;
+  stack_frame.AddrPC.Offset = context_record->Rip;
+  stack_frame.AddrFrame.Offset = context_record->Rbp;
+  stack_frame.AddrStack.Offset = context_record->Rsp;
+#else
+  int machine_type = IMAGE_FILE_MACHINE_I386;
+  stack_frame.AddrPC.Offset = context_record->Eip;
+  stack_frame.AddrFrame.Offset = context_record->Ebp;
+  stack_frame.AddrStack.Offset = context_record->Esp;
+#endif
+  stack_frame.AddrPC.Mode = AddrModeFlat;
+  stack_frame.AddrFrame.Mode = AddrModeFlat;
+  stack_frame.AddrStack.Mode = AddrModeFlat;
+  while (StackWalk64(machine_type,
+                     GetCurrentProcess(),
+                     GetCurrentThread(),
+                     &stack_frame,
+                     context_record,
+                     NULL,
+                     &SymFunctionTableAccess64,
+                     &SymGetModuleBase64,
+                     NULL) &&
+         count_ < arraysize(trace_)) {
+    trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
+  }
+
+  for (size_t i = count_; i < arraysize(trace_); ++i)
+    trace_[i] = NULL;
+}
+
+void StackTrace::Print() const {
+  OutputToStream(&std::cerr);
+}
+
+void StackTrace::OutputToStream(std::ostream* os) const {
+  SymbolContext* context = SymbolContext::GetInstance();
+  DWORD error = context->init_error();
+  if (error != ERROR_SUCCESS) {
+    (*os) << "Error initializing symbols (" << error
+          << ").  Dumping unresolved backtrace:\n";
+    for (size_t i = 0; (i < count_) && os->good(); ++i) {
+      (*os) << "\t" << trace_[i] << "\n";
+    }
+  } else {
+    (*os) << "Backtrace:\n";
+    context->OutputTraceToStream(trace_, count_, os);
+  }
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
new file mode 100644
index 0000000..19df8cb
--- /dev/null
+++ b/base/debug/task_annotator.cc
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/task_annotator.h"
+
+#include "base/debug/alias.h"
+#include "base/pending_task.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+namespace debug {
+
+TaskAnnotator::TaskAnnotator() {
+}
+
+TaskAnnotator::~TaskAnnotator() {
+}
+
+void TaskAnnotator::DidQueueTask(const char* queue_function,
+                                 const PendingTask& pending_task) {
+  TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                          queue_function,
+                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)));
+}
+
+void TaskAnnotator::RunTask(const char* queue_function,
+                            const char* run_function,
+                            const PendingTask& pending_task) {
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  tracked_objects::Duration queue_duration =
+      stopwatch.StartTime() - pending_task.EffectiveTimePosted();
+
+  TRACE_EVENT_FLOW_END1(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                        queue_function,
+                        TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+                        "queue_duration",
+                        queue_duration.InMilliseconds());
+
+  // When tracing memory for posted tasks it's more valuable to attribute the
+  // memory allocations to the source function than generically to the task
+  // runner.
+  TRACE_EVENT_WITH_MEMORY_TAG2(
+      "toplevel",
+      run_function,
+      pending_task.posted_from.function_name(),  // Name for memory tracking.
+      "src_file",
+      pending_task.posted_from.file_name(),
+      "src_func",
+      pending_task.posted_from.function_name());
+
+  // Before running the task, store the program counter where it was posted
+  // and deliberately alias it to ensure it is on the stack if the task
+  // crashes. Be careful not to assume that the variable itself will have the
+  // expected value when displayed by the optimizer in an optimized build.
+  // Look at a memory dump of the stack.
+  const void* program_counter = pending_task.posted_from.program_counter();
+  debug::Alias(&program_counter);
+
+  pending_task.task.Run();
+
+  stopwatch.Stop();
+  tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(
+      pending_task, stopwatch);
+}
+
+uint64 TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
+  return (static_cast<uint64>(task.sequence_num) << 32) |
+         ((static_cast<uint64>(reinterpret_cast<intptr_t>(this)) << 32) >> 32);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
new file mode 100644
index 0000000..aa5f17b
--- /dev/null
+++ b/base/debug/task_annotator.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_TASK_ANNOTATOR_H_
+#define BASE_DEBUG_TASK_ANNOTATOR_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+struct PendingTask;
+namespace debug {
+
+// Implements common debug annotations for posted tasks. This includes data
+// such as task origins, queueing durations and memory usage.
+class BASE_EXPORT TaskAnnotator {
+ public:
+  TaskAnnotator();
+  ~TaskAnnotator();
+
+  // Called to indicate that a task has been queued to run in the future.
+  // |queue_function| is used as the trace flow event name.
+  void DidQueueTask(const char* queue_function,
+                    const PendingTask& pending_task);
+
+  // Run a previously queued task. |queue_function| should match what was
+  // passed into |DidQueueTask| for this task. |run_function| is used as the
+  // name for the trace event that surrounds the task's execution.
+  void RunTask(const char* queue_function,
+               const char* run_function,
+               const PendingTask& pending_task);
+
+ private:
+  // Creates a process-wide unique ID to represent this task in trace events.
+  // This will be mangled with a Process ID hash to reduce the likelyhood of
+  // colliding with TaskAnnotator pointers on other processes.
+  uint64 GetTaskTraceID(const PendingTask& task) const;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
+};
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_TASK_ANNOTATOR_H_
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc
new file mode 100644
index 0000000..ddffc21
--- /dev/null
+++ b/base/debug/task_annotator_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/task_annotator.h"
+#include "base/bind.h"
+#include "base/pending_task.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+namespace {
+
+void TestTask(int* result) {
+  *result = 123;
+}
+
+}  // namespace
+
+TEST(TaskAnnotatorTest, QueueAndRunTask) {
+  int result = 0;
+  PendingTask pending_task(FROM_HERE, Bind(&TestTask, &result));
+
+  TaskAnnotator annotator;
+  annotator.DidQueueTask("TaskAnnotatorTest::Queue", pending_task);
+  EXPECT_EQ(0, result);
+  annotator.RunTask(
+      "TaskAnnotatorTest::Queue", "TaskAnnotatorTest::Run", pending_task);
+  EXPECT_EQ(123, result);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug_message.cc b/base/debug_message.cc
new file mode 100644
index 0000000..10f441d
--- /dev/null
+++ b/base/debug_message.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+// Display the command line. This program is designed to be called from
+// another process to display assertions. Since the other process has
+// complete control of our command line, we assume that it did *not*
+// add the program name as the first parameter. This allows us to just
+// show the command line directly as the message.
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                     LPSTR lpCmdLine, int nCmdShow) {
+  LPWSTR cmdline = GetCommandLineW();
+  MessageBox(NULL, cmdline, L"Kr\x00d8m", MB_TOPMOST);
+  return 0;
+}
diff --git a/base/deferred_sequenced_task_runner.cc b/base/deferred_sequenced_task_runner.cc
new file mode 100644
index 0000000..dc118f3
--- /dev/null
+++ b/base/deferred_sequenced_task_runner.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/deferred_sequenced_task_runner.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace base {
+
+DeferredSequencedTaskRunner::DeferredTask::DeferredTask()
+    : is_non_nestable(false) {
+}
+
+DeferredSequencedTaskRunner::DeferredTask::~DeferredTask() {
+}
+
+DeferredSequencedTaskRunner::DeferredSequencedTaskRunner(
+    const scoped_refptr<SequencedTaskRunner>& target_task_runner)
+    : started_(false),
+      target_task_runner_(target_task_runner) {
+}
+
+DeferredSequencedTaskRunner::~DeferredSequencedTaskRunner() {
+}
+
+bool DeferredSequencedTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock lock(lock_);
+  if (started_) {
+    DCHECK(deferred_tasks_queue_.empty());
+    return target_task_runner_->PostDelayedTask(from_here, task, delay);
+  }
+
+  QueueDeferredTask(from_here, task, delay, false /* is_non_nestable */);
+  return true;
+}
+
+bool DeferredSequencedTaskRunner::RunsTasksOnCurrentThread() const {
+  return target_task_runner_->RunsTasksOnCurrentThread();
+}
+
+bool DeferredSequencedTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock lock(lock_);
+  if (started_) {
+    DCHECK(deferred_tasks_queue_.empty());
+    return target_task_runner_->PostNonNestableDelayedTask(from_here,
+                                                           task,
+                                                           delay);
+  }
+  QueueDeferredTask(from_here, task, delay, true /* is_non_nestable */);
+  return true;
+}
+
+void DeferredSequencedTaskRunner::QueueDeferredTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay,
+    bool is_non_nestable) {
+  DeferredTask deferred_task;
+  deferred_task.posted_from = from_here;
+  deferred_task.task = task;
+  deferred_task.delay = delay;
+  deferred_task.is_non_nestable = is_non_nestable;
+  deferred_tasks_queue_.push_back(deferred_task);
+}
+
+
+void DeferredSequencedTaskRunner::Start() {
+  AutoLock lock(lock_);
+  DCHECK(!started_);
+  started_ = true;
+  for (std::vector<DeferredTask>::iterator i = deferred_tasks_queue_.begin();
+      i != deferred_tasks_queue_.end();
+      ++i) {
+    const DeferredTask& task = *i;
+    if (task.is_non_nestable) {
+      target_task_runner_->PostNonNestableDelayedTask(task.posted_from,
+                                                      task.task,
+                                                      task.delay);
+    } else {
+      target_task_runner_->PostDelayedTask(task.posted_from,
+                                           task.task,
+                                           task.delay);
+    }
+    // Replace the i-th element in the |deferred_tasks_queue_| with an empty
+    // |DelayedTask| to ensure that |task| is destroyed before the next task
+    // is posted.
+    *i = DeferredTask();
+  }
+  deferred_tasks_queue_.clear();
+}
+
+}  // namespace base
diff --git a/base/deferred_sequenced_task_runner.h b/base/deferred_sequenced_task_runner.h
new file mode 100644
index 0000000..110d988
--- /dev/null
+++ b/base/deferred_sequenced_task_runner.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
+#define BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+// A DeferredSequencedTaskRunner is a subclass of SequencedTaskRunner that
+// queues up all requests until the first call to Start() is issued.
+class BASE_EXPORT DeferredSequencedTaskRunner : public SequencedTaskRunner {
+ public:
+  explicit DeferredSequencedTaskRunner(
+      const scoped_refptr<SequencedTaskRunner>& target_runner);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // SequencedTaskRunner implementation
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+  // Start the execution - posts all queued tasks to the target executor. The
+  // deferred tasks are posted with their initial delay, meaning that the task
+  // execution delay is actually measured from Start.
+  // Fails when called a second time.
+  void Start();
+
+ private:
+  struct DeferredTask  {
+    DeferredTask();
+    ~DeferredTask();
+
+    tracked_objects::Location posted_from;
+    Closure task;
+    // The delay this task was initially posted with.
+    TimeDelta delay;
+    bool is_non_nestable;
+  };
+
+  ~DeferredSequencedTaskRunner() override;
+
+  // Creates a |Task| object and adds it to |deferred_tasks_queue_|.
+  void QueueDeferredTask(const tracked_objects::Location& from_here,
+                         const Closure& task,
+                         TimeDelta delay,
+                         bool is_non_nestable);
+
+  // // Protects |started_| and |deferred_tasks_queue_|.
+  mutable Lock lock_;
+
+  bool started_;
+  const scoped_refptr<SequencedTaskRunner> target_task_runner_;
+  std::vector<DeferredTask> deferred_tasks_queue_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeferredSequencedTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc
new file mode 100644
index 0000000..6e17ad9
--- /dev/null
+++ b/base/deferred_sequenced_task_runner_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/deferred_sequenced_task_runner.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class DeferredSequencedTaskRunnerTest : public testing::Test,
+                                        public base::NonThreadSafe {
+ public:
+  class ExecuteTaskOnDestructor :
+      public base::RefCounted<ExecuteTaskOnDestructor> {
+   public:
+    ExecuteTaskOnDestructor(
+        DeferredSequencedTaskRunnerTest* executor,
+        int task_id)
+        : executor_(executor),
+          task_id_(task_id) {
+    }
+  private:
+    friend class base::RefCounted<ExecuteTaskOnDestructor>;
+    virtual ~ExecuteTaskOnDestructor() {
+      executor_->ExecuteTask(task_id_);
+    }
+    DeferredSequencedTaskRunnerTest* executor_;
+    int task_id_;
+  };
+
+  void ExecuteTask(int task_id) {
+    base::AutoLock lock(lock_);
+    executed_task_ids_.push_back(task_id);
+  }
+
+  void PostExecuteTask(int task_id) {
+    runner_->PostTask(FROM_HERE,
+                      base::Bind(&DeferredSequencedTaskRunnerTest::ExecuteTask,
+                                 base::Unretained(this),
+                                 task_id));
+  }
+
+  void StartRunner() {
+    runner_->Start();
+  }
+
+  void DoNothing(ExecuteTaskOnDestructor* object) {
+  }
+
+ protected:
+  DeferredSequencedTaskRunnerTest()
+      : loop_(),
+        runner_(new base::DeferredSequencedTaskRunner(loop_.task_runner())) {}
+
+  base::MessageLoop loop_;
+  scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
+  mutable base::Lock lock_;
+  std::vector<int> executed_task_ids_;
+};
+
+TEST_F(DeferredSequencedTaskRunnerTest, Stopped) {
+  PostExecuteTask(1);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, Start) {
+  StartRunner();
+  PostExecuteTask(1);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) {
+  StartRunner();
+  for (int i = 1; i < 5; ++i)
+    PostExecuteTask(i);
+
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) {
+  PostExecuteTask(1);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
+
+  StartRunner();
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
+
+  PostExecuteTask(2);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) {
+  for (int i = 1; i < 5; ++i)
+    PostExecuteTask(i);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
+
+  StartRunner();
+  for (int i = 5; i < 9; ++i)
+    PostExecuteTask(i);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) {
+  {
+    base::Thread thread1("DeferredSequencedTaskRunnerTestThread1");
+    base::Thread thread2("DeferredSequencedTaskRunnerTestThread2");
+    thread1.Start();
+    thread2.Start();
+    for (int i = 0; i < 5; ++i) {
+      thread1.task_runner()->PostTask(
+          FROM_HERE,
+          base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
+                     base::Unretained(this), 2 * i));
+      thread2.task_runner()->PostTask(
+          FROM_HERE,
+          base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
+                     base::Unretained(this), 2 * i + 1));
+      if (i == 2) {
+        thread1.task_runner()->PostTask(
+            FROM_HERE, base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
+                                  base::Unretained(this)));
+      }
+    }
+  }
+
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_,
+      testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) {
+  {
+    base::Thread thread("DeferredSequencedTaskRunnerTestThread");
+    thread.Start();
+    runner_ = new base::DeferredSequencedTaskRunner(thread.task_runner());
+    for (int i = 0; i < 5; ++i) {
+      {
+        // Use a block to ensure that no reference to |short_lived_object|
+        // is kept on the main thread after it is posted to |runner_|.
+        scoped_refptr<ExecuteTaskOnDestructor> short_lived_object =
+            new ExecuteTaskOnDestructor(this, 2 * i);
+        runner_->PostTask(
+            FROM_HERE,
+            base::Bind(&DeferredSequencedTaskRunnerTest::DoNothing,
+                       base::Unretained(this),
+                       short_lived_object));
+      }
+      // |short_lived_object| with id |2 * i| should be destroyed before the
+      // task |2 * i + 1| is executed.
+      PostExecuteTask(2 * i + 1);
+    }
+    StartRunner();
+  }
+
+  // All |short_lived_object| with id |2 * i| are destroyed before the task
+  // |2 * i + 1| is executed.
+  EXPECT_THAT(executed_task_ids_,
+              testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+}
+
+}  // namespace
diff --git a/base/environment.cc b/base/environment.cc
new file mode 100644
index 0000000..6cf7a18
--- /dev/null
+++ b/base/environment.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/environment.h"
+
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(OS_POSIX)
+#include <stdlib.h>
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+namespace {
+
+class EnvironmentImpl : public base::Environment {
+ public:
+  bool GetVar(const char* variable_name, std::string* result) override {
+    if (GetVarImpl(variable_name, result))
+      return true;
+
+    // Some commonly used variable names are uppercase while others
+    // are lowercase, which is inconsistent. Let's try to be helpful
+    // and look for a variable name with the reverse case.
+    // I.e. HTTP_PROXY may be http_proxy for some users/systems.
+    char first_char = variable_name[0];
+    std::string alternate_case_var;
+    if (first_char >= 'a' && first_char <= 'z')
+      alternate_case_var = StringToUpperASCII(std::string(variable_name));
+    else if (first_char >= 'A' && first_char <= 'Z')
+      alternate_case_var = base::StringToLowerASCII(std::string(variable_name));
+    else
+      return false;
+    return GetVarImpl(alternate_case_var.c_str(), result);
+  }
+
+  bool SetVar(const char* variable_name,
+              const std::string& new_value) override {
+    return SetVarImpl(variable_name, new_value);
+  }
+
+  bool UnSetVar(const char* variable_name) override {
+    return UnSetVarImpl(variable_name);
+  }
+
+ private:
+  bool GetVarImpl(const char* variable_name, std::string* result) {
+#if defined(OS_POSIX)
+    const char* env_value = getenv(variable_name);
+    if (!env_value)
+      return false;
+    // Note that the variable may be defined but empty.
+    if (result)
+      *result = env_value;
+    return true;
+#elif defined(OS_WIN)
+    DWORD value_length = ::GetEnvironmentVariable(
+        UTF8ToWide(variable_name).c_str(), NULL, 0);
+    if (value_length == 0)
+      return false;
+    if (result) {
+      scoped_ptr<wchar_t[]> value(new wchar_t[value_length]);
+      ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(),
+                               value_length);
+      *result = WideToUTF8(value.get());
+    }
+    return true;
+#else
+#error need to port
+#endif
+  }
+
+  bool SetVarImpl(const char* variable_name, const std::string& new_value) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !setenv(variable_name, new_value.c_str(), 1);
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(),
+                                    UTF8ToWide(new_value).c_str());
+#endif
+  }
+
+  bool UnSetVarImpl(const char* variable_name) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !unsetenv(variable_name);
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL);
+#endif
+  }
+};
+
+// Parses a null-terminated input string of an environment block. The key is
+// placed into the given string, and the total length of the line, including
+// the terminating null, is returned.
+size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
+                    NativeEnvironmentString* key) {
+  // Skip to the equals or end of the string, this is the key.
+  size_t cur = 0;
+  while (input[cur] && input[cur] != '=')
+    cur++;
+  *key = NativeEnvironmentString(&input[0], cur);
+
+  // Now just skip to the end of the string.
+  while (input[cur])
+    cur++;
+  return cur + 1;
+}
+
+}  // namespace
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+// On Posix systems, this variable contains the location of the user's home
+// directory. (e.g, /home/username/).
+const char kHome[] = "HOME";
+#endif
+
+}  // namespace env_vars
+
+Environment::~Environment() {}
+
+// static
+Environment* Environment::Create() {
+  return new EnvironmentImpl();
+}
+
+bool Environment::HasVar(const char* variable_name) {
+  return GetVar(variable_name, NULL);
+}
+
+#if defined(OS_WIN)
+
+string16 AlterEnvironment(const wchar_t* env,
+                          const EnvironmentMap& changes) {
+  string16 result;
+
+  // First copy all unmodified values to the output.
+  size_t cur_env = 0;
+  string16 key;
+  while (env[cur_env]) {
+    const wchar_t* line = &env[cur_env];
+    size_t line_length = ParseEnvLine(line, &key);
+
+    // Keep only values not specified in the change vector.
+    EnvironmentMap::const_iterator found_change = changes.find(key);
+    if (found_change == changes.end())
+      result.append(line, line_length);
+
+    cur_env += line_length;
+  }
+
+  // Now append all modified and new values.
+  for (EnvironmentMap::const_iterator i = changes.begin();
+       i != changes.end(); ++i) {
+    if (!i->second.empty()) {
+      result.append(i->first);
+      result.push_back('=');
+      result.append(i->second);
+      result.push_back(0);
+    }
+  }
+
+  // An additional null marks the end of the list. We always need a double-null
+  // in case nothing was added above.
+  if (result.empty())
+    result.push_back(0);
+  result.push_back(0);
+  return result;
+}
+
+#elif defined(OS_POSIX)
+
+scoped_ptr<char*[]> AlterEnvironment(const char* const* const env,
+                                     const EnvironmentMap& changes) {
+  std::string value_storage;  // Holds concatenated null-terminated strings.
+  std::vector<size_t> result_indices;  // Line indices into value_storage.
+
+  // First build up all of the unchanged environment strings. These are
+  // null-terminated of the form "key=value".
+  std::string key;
+  for (size_t i = 0; env[i]; i++) {
+    size_t line_length = ParseEnvLine(env[i], &key);
+
+    // Keep only values not specified in the change vector.
+    EnvironmentMap::const_iterator found_change = changes.find(key);
+    if (found_change == changes.end()) {
+      result_indices.push_back(value_storage.size());
+      value_storage.append(env[i], line_length);
+    }
+  }
+
+  // Now append all modified and new values.
+  for (EnvironmentMap::const_iterator i = changes.begin();
+       i != changes.end(); ++i) {
+    if (!i->second.empty()) {
+      result_indices.push_back(value_storage.size());
+      value_storage.append(i->first);
+      value_storage.push_back('=');
+      value_storage.append(i->second);
+      value_storage.push_back(0);
+    }
+  }
+
+  size_t pointer_count_required =
+      result_indices.size() + 1 +  // Null-terminated array of pointers.
+      (value_storage.size() + sizeof(char*) - 1) / sizeof(char*);  // Buffer.
+  scoped_ptr<char*[]> result(new char*[pointer_count_required]);
+
+  // The string storage goes after the array of pointers.
+  char* storage_data = reinterpret_cast<char*>(
+      &result.get()[result_indices.size() + 1]);
+  if (!value_storage.empty())
+    memcpy(storage_data, value_storage.data(), value_storage.size());
+
+  // Fill array of pointers at the beginning of the result.
+  for (size_t i = 0; i < result_indices.size(); i++)
+    result[i] = &storage_data[result_indices[i]];
+  result[result_indices.size()] = 0;  // Null terminator.
+
+  return result.Pass();
+}
+
+#endif  // OS_POSIX
+
+}  // namespace base
diff --git a/base/environment.h b/base/environment.h
new file mode 100644
index 0000000..c8811e2
--- /dev/null
+++ b/base/environment.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ENVIRONMENT_H_
+#define BASE_ENVIRONMENT_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+BASE_EXPORT extern const char kHome[];
+#endif
+
+}  // namespace env_vars
+
+class BASE_EXPORT Environment {
+ public:
+  virtual ~Environment();
+
+  // Static factory method that returns the implementation that provide the
+  // appropriate platform-specific instance.
+  static Environment* Create();
+
+  // Gets an environment variable's value and stores it in |result|.
+  // Returns false if the key is unset.
+  virtual bool GetVar(const char* variable_name, std::string* result) = 0;
+
+  // Syntactic sugar for GetVar(variable_name, NULL);
+  virtual bool HasVar(const char* variable_name);
+
+  // Returns true on success, otherwise returns false.
+  virtual bool SetVar(const char* variable_name,
+                      const std::string& new_value) = 0;
+
+  // Returns true on success, otherwise returns false.
+  virtual bool UnSetVar(const char* variable_name) = 0;
+};
+
+
+#if defined(OS_WIN)
+
+typedef string16 NativeEnvironmentString;
+typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
+    EnvironmentMap;
+
+// Returns a modified environment vector constructed from the given environment
+// and the list of changes given in |changes|. Each key in the environment is
+// matched against the first element of the pairs. In the event of a match, the
+// value is replaced by the second of the pair, unless the second is empty, in
+// which case the key-value is removed.
+//
+// This Windows version takes and returns a Windows-style environment block
+// which is a concatenated list of null-terminated 16-bit strings. The end is
+// marked by a double-null terminator. The size of the returned string will
+// include the terminators.
+BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
+                                      const EnvironmentMap& changes);
+
+#elif defined(OS_POSIX)
+
+typedef std::string NativeEnvironmentString;
+typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
+    EnvironmentMap;
+
+// See general comments for the Windows version above.
+//
+// This Posix version takes and returns a Posix-style environment block, which
+// is a null-terminated list of pointers to null-terminated strings. The
+// returned array will have appended to it the storage for the array itself so
+// there is only one pointer to manage, but this means that you can't copy the
+// array without keeping the original around.
+BASE_EXPORT scoped_ptr<char*[]> AlterEnvironment(
+    const char* const* env,
+    const EnvironmentMap& changes);
+
+#endif
+
+}  // namespace base
+
+#endif  // BASE_ENVIRONMENT_H_
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc
new file mode 100644
index 0000000..f0577a8
--- /dev/null
+++ b/base/environment_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/environment.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest EnvironmentTest;
+
+namespace base {
+
+TEST_F(EnvironmentTest, GetVar) {
+  // Every setup should have non-empty PATH...
+  scoped_ptr<Environment> env(Environment::Create());
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar("PATH", &env_value));
+  EXPECT_NE(env_value, "");
+}
+
+TEST_F(EnvironmentTest, GetVarReverse) {
+  scoped_ptr<Environment> env(Environment::Create());
+  const char kFooUpper[] = "FOO";
+  const char kFooLower[] = "foo";
+
+  // Set a variable in UPPER case.
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // And then try to get this variable passing the lower case.
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar(kFooLower, &env_value));
+
+  EXPECT_STREQ(env_value.c_str(), kFooLower);
+
+  EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+  const char kBar[] = "bar";
+  // Now do the opposite, set the variable in the lower case.
+  EXPECT_TRUE(env->SetVar(kFooLower, kBar));
+
+  // And then try to get this variable passing the UPPER case.
+  EXPECT_TRUE(env->GetVar(kFooUpper, &env_value));
+
+  EXPECT_STREQ(env_value.c_str(), kBar);
+
+  EXPECT_TRUE(env->UnSetVar(kFooLower));
+}
+
+TEST_F(EnvironmentTest, HasVar) {
+  // Every setup should have PATH...
+  scoped_ptr<Environment> env(Environment::Create());
+  EXPECT_TRUE(env->HasVar("PATH"));
+}
+
+TEST_F(EnvironmentTest, SetVar) {
+  scoped_ptr<Environment> env(Environment::Create());
+
+  const char kFooUpper[] = "FOO";
+  const char kFooLower[] = "foo";
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // Now verify that the environment has the new variable.
+  EXPECT_TRUE(env->HasVar(kFooUpper));
+
+  std::string var_value;
+  EXPECT_TRUE(env->GetVar(kFooUpper, &var_value));
+  EXPECT_EQ(var_value, kFooLower);
+}
+
+TEST_F(EnvironmentTest, UnSetVar) {
+  scoped_ptr<Environment> env(Environment::Create());
+
+  const char kFooUpper[] = "FOO";
+  const char kFooLower[] = "foo";
+  // First set some environment variable.
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // Now verify that the environment has the new variable.
+  EXPECT_TRUE(env->HasVar(kFooUpper));
+
+  // Finally verify that the environment variable was erased.
+  EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+  // And check that the variable has been unset.
+  EXPECT_FALSE(env->HasVar(kFooUpper));
+}
+
+#if defined(OS_WIN)
+
+TEST_F(EnvironmentTest, AlterEnvironment) {
+  const wchar_t empty[] = L"\0";
+  const wchar_t a2[] = L"A=2\0";
+  EnvironmentMap changes;
+  string16 e;
+
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(0, e[0]);
+
+  changes[L"A"] = L"1";
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(string16(L"A=1\0\0", 5), e);
+
+  changes.clear();
+  changes[L"A"] = string16();
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(string16(L"\0\0", 2), e);
+
+  changes.clear();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(string16(L"A=2\0\0", 5), e);
+
+  changes.clear();
+  changes[L"A"] = L"1";
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(string16(L"A=1\0\0", 5), e);
+
+  changes.clear();
+  changes[L"A"] = string16();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(string16(L"\0\0", 2), e);
+}
+
+#else
+
+TEST_F(EnvironmentTest, AlterEnvironment) {
+  const char* const empty[] = { NULL };
+  const char* const a2[] = { "A=2", NULL };
+  EnvironmentMap changes;
+  scoped_ptr<char*[]> e;
+
+  e = AlterEnvironment(empty, changes).Pass();
+  EXPECT_TRUE(e[0] == NULL);
+
+  changes["A"] = "1";
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(std::string("A=1"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+
+  changes.clear();
+  changes["A"] = std::string();
+  e = AlterEnvironment(empty, changes);
+  EXPECT_TRUE(e[0] == NULL);
+
+  changes.clear();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(std::string("A=2"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+
+  changes.clear();
+  changes["A"] = "1";
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(std::string("A=1"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+
+  changes.clear();
+  changes["A"] = std::string();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_TRUE(e[0] == NULL);
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/event_types.h b/base/event_types.h
new file mode 100644
index 0000000..9905800
--- /dev/null
+++ b/base/event_types.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_EVENT_TYPES_H_
+#define BASE_EVENT_TYPES_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(USE_X11)
+typedef union _XEvent XEvent;
+#elif defined(OS_MACOSX)
+#if defined(__OBJC__)
+@class NSEvent;
+#else  // __OBJC__
+class NSEvent;
+#endif // __OBJC__
+#endif
+
+namespace base {
+
+// Cross platform typedefs for native event types.
+#if defined(OS_WIN)
+typedef MSG NativeEvent;
+#elif defined(USE_X11)
+typedef XEvent* NativeEvent;
+#elif defined(OS_MACOSX)
+typedef NSEvent* NativeEvent;
+#else
+typedef void* NativeEvent;
+#endif
+
+} // namespace base
+
+#endif  // BASE_EVENT_TYPES_H_
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
new file mode 100644
index 0000000..376ad39
--- /dev/null
+++ b/base/file_descriptor_posix.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_
+#define BASE_FILE_DESCRIPTOR_POSIX_H_
+
+#include "base/files/file.h"
+#include "base/files/scoped_file.h"
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// We introduct a special structure for file descriptors in order that we are
+// able to use template specialisation to special-case their handling.
+//
+// WARNING: (Chromium only) There are subtleties to consider if serialising
+// these objects over IPC. See comments in ipc/ipc_message_utils.h
+// above the template specialisation for this structure.
+// -----------------------------------------------------------------------------
+struct FileDescriptor {
+  FileDescriptor() : fd(-1), auto_close(false) {}
+
+  FileDescriptor(int ifd, bool iauto_close) : fd(ifd), auto_close(iauto_close) {
+  }
+
+  FileDescriptor(File file) : fd(file.TakePlatformFile()), auto_close(true) {}
+  explicit FileDescriptor(ScopedFD fd) : fd(fd.release()), auto_close(true) {}
+
+  bool operator==(const FileDescriptor& other) const {
+    return (fd == other.fd && auto_close == other.auto_close);
+  }
+
+  bool operator!=(const FileDescriptor& other) const {
+    return !operator==(other);
+  }
+
+  // A comparison operator so that we can use these as keys in a std::map.
+  bool operator<(const FileDescriptor& other) const {
+    return other.fd < fd;
+  }
+
+  int fd;
+  // If true, this file descriptor should be closed after it has been used. For
+  // example an IPC system might interpret this flag as indicating that the
+  // file descriptor it has been given should be closed after use.
+  bool auto_close;
+};
+
+}  // namespace base
+
+#endif  // BASE_FILE_DESCRIPTOR_POSIX_H_
diff --git a/base/file_version_info.h b/base/file_version_info.h
new file mode 100644
index 0000000..5bc577c
--- /dev/null
+++ b/base/file_version_info.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_VERSION_INFO_H__
+#define BASE_FILE_VERSION_INFO_H__
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+#endif  // OS_WIN
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+class FilePath;
+}
+
+// Provides an interface for accessing the version information for a file. This
+// is the information you access when you select a file in the Windows Explorer,
+// right-click select Properties, then click the Version tab, and on the Mac
+// when you select a file in the Finder and do a Get Info.
+//
+// This list of properties is straight out of Win32's VerQueryValue
+// <http://msdn.microsoft.com/en-us/library/ms647464.aspx> and the Mac
+// version returns values from the Info.plist as appropriate. TODO(avi): make
+// this a less-obvious Windows-ism.
+
+class BASE_EXPORT FileVersionInfo {
+ public:
+  virtual ~FileVersionInfo() {}
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  // Creates a FileVersionInfo for the specified path. Returns NULL if something
+  // goes wrong (typically the file does not exit or cannot be opened). The
+  // returned object should be deleted when you are done with it.
+  static FileVersionInfo* CreateFileVersionInfo(
+      const base::FilePath& file_path);
+#endif  // OS_WIN || OS_MACOSX
+
+#if defined(OS_WIN)
+  // Creates a FileVersionInfo for the specified module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  static FileVersionInfo* CreateFileVersionInfoForModule(HMODULE module);
+
+  // Creates a FileVersionInfo for the current module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  // This function should be inlined so that the "current module" is evaluated
+  // correctly, instead of being the module that contains base.
+  __forceinline static FileVersionInfo*
+  CreateFileVersionInfoForCurrentModule() {
+    HMODULE module = reinterpret_cast<HMODULE>(&__ImageBase);
+    return CreateFileVersionInfoForModule(module);
+  }
+#else
+  // Creates a FileVersionInfo for the current module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
+#endif  // OS_WIN
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  virtual base::string16 company_name() = 0;
+  virtual base::string16 company_short_name() = 0;
+  virtual base::string16 product_name() = 0;
+  virtual base::string16 product_short_name() = 0;
+  virtual base::string16 internal_name() = 0;
+  virtual base::string16 product_version() = 0;
+  virtual base::string16 private_build() = 0;
+  virtual base::string16 special_build() = 0;
+  virtual base::string16 comments() = 0;
+  virtual base::string16 original_filename() = 0;
+  virtual base::string16 file_description() = 0;
+  virtual base::string16 file_version() = 0;
+  virtual base::string16 legal_copyright() = 0;
+  virtual base::string16 legal_trademarks() = 0;
+  virtual base::string16 last_change() = 0;
+  virtual bool is_official_build() = 0;
+};
+
+#endif  // BASE_FILE_VERSION_INFO_H__
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
new file mode 100644
index 0000000..e677838
--- /dev/null
+++ b/base/file_version_info_mac.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_VERSION_INFO_MAC_H_
+#define BASE_FILE_VERSION_INFO_MAC_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <string>
+
+#include "base/file_version_info.h"
+#include "base/mac/scoped_nsobject.h"
+
+@class NSBundle;
+
+class FileVersionInfoMac : public FileVersionInfo {
+ public:
+  explicit FileVersionInfoMac(NSBundle *bundle);
+  ~FileVersionInfoMac() override;
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  base::string16 company_name() override;
+  base::string16 company_short_name() override;
+  base::string16 product_name() override;
+  base::string16 product_short_name() override;
+  base::string16 internal_name() override;
+  base::string16 product_version() override;
+  base::string16 private_build() override;
+  base::string16 special_build() override;
+  base::string16 comments() override;
+  base::string16 original_filename() override;
+  base::string16 file_description() override;
+  base::string16 file_version() override;
+  base::string16 legal_copyright() override;
+  base::string16 legal_trademarks() override;
+  base::string16 last_change() override;
+  bool is_official_build() override;
+
+ private:
+  // Returns a base::string16 value for a property name.
+  // Returns the empty string if the property does not exist.
+  base::string16 GetString16Value(CFStringRef name);
+
+  base::scoped_nsobject<NSBundle> bundle_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileVersionInfoMac);
+};
+
+#endif  // BASE_FILE_VERSION_INFO_MAC_H_
diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm
new file mode 100644
index 0000000..8542b19
--- /dev/null
+++ b/base/file_version_info_mac.mm
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_version_info_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+
+FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle)
+    : bundle_([bundle retain]) {
+}
+
+FileVersionInfoMac::~FileVersionInfoMac() {}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() {
+  return CreateFileVersionInfo(base::mac::FrameworkBundlePath());
+}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
+    const base::FilePath& file_path) {
+  NSString* path = base::SysUTF8ToNSString(file_path.value());
+  NSBundle* bundle = [NSBundle bundleWithPath:path];
+  return new FileVersionInfoMac(bundle);
+}
+
+base::string16 FileVersionInfoMac::company_name() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::company_short_name() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::internal_name() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::product_name() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+base::string16 FileVersionInfoMac::product_short_name() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+base::string16 FileVersionInfoMac::comments() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::legal_copyright() {
+  return GetString16Value(CFSTR("CFBundleGetInfoString"));
+}
+
+base::string16 FileVersionInfoMac::product_version() {
+  // On OS X, CFBundleVersion is used by LaunchServices, and must follow
+  // specific formatting rules, so the four-part Chrome version is in
+  // CFBundleShortVersionString. On iOS, both have a policy-enfoced limit
+  // of three version components, so the full version is stored in a custom
+  // key (CrBundleVersion) falling back to CFBundleVersion if not present.
+#if defined(OS_IOS)
+  base::string16 version(GetString16Value(CFSTR("CrBundleVersion")));
+  if (version.length() > 0)
+    return version;
+  return GetString16Value(CFSTR("CFBundleVersion"));
+#else
+  return GetString16Value(CFSTR("CFBundleShortVersionString"));
+#endif  // defined(OS_IOS)
+}
+
+base::string16 FileVersionInfoMac::file_description() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::legal_trademarks() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::private_build() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::file_version() {
+  return product_version();
+}
+
+base::string16 FileVersionInfoMac::original_filename() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+base::string16 FileVersionInfoMac::special_build() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::last_change() {
+  return GetString16Value(CFSTR("SCMRevision"));
+}
+
+bool FileVersionInfoMac::is_official_build() {
+#if defined (GOOGLE_CHROME_BUILD)
+  return true;
+#else
+  return false;
+#endif
+}
+
+base::string16 FileVersionInfoMac::GetString16Value(CFStringRef name) {
+  if (bundle_) {
+    NSString *ns_name = base::mac::CFToNSCast(name);
+    NSString* value = [bundle_ objectForInfoDictionaryKey:ns_name];
+    if (value) {
+      return base::SysNSStringToUTF16(value);
+    }
+  }
+  return base::string16();
+}
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
new file mode 100644
index 0000000..9b10d04
--- /dev/null
+++ b/base/file_version_info_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_version_info.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/file_version_info_win.h"
+#endif
+
+using base::FilePath;
+
+namespace {
+
+#if defined(OS_WIN)
+FilePath GetTestDataPath() {
+  FilePath path;
+  PathService::Get(base::DIR_SOURCE_ROOT, &path);
+  path = path.AppendASCII("base");
+  path = path.AppendASCII("test");
+  path = path.AppendASCII("data");
+  path = path.AppendASCII("file_version_info_unittest");
+  return path;
+}
+#endif
+
+}  // namespace
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, HardCodedProperties) {
+  const wchar_t* kDLLNames[] = {
+    L"FileVersionInfoTest1.dll"
+  };
+
+  const wchar_t* kExpectedValues[1][15] = {
+      // FileVersionInfoTest.dll
+      L"Goooooogle",                      // company_name
+      L"Google",                          // company_short_name
+      L"This is the product name",        // product_name
+      L"This is the product short name",  // product_short_name
+      L"The Internal Name",               // internal_name
+      L"4.3.2.1",                         // product_version
+      L"Private build property",          // private_build
+      L"Special build property",          // special_build
+      L"This is a particularly interesting comment",  // comments
+      L"This is the original filename",   // original_filename
+      L"This is my file description",     // file_description
+      L"1.2.3.4",                         // file_version
+      L"This is the legal copyright",     // legal_copyright
+      L"This is the legal trademarks",    // legal_trademarks
+      L"This is the last change",         // last_change
+  };
+
+  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+    int j = 0;
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_short_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_short_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->internal_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_version());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->private_build());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->special_build());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->comments());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->original_filename());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_description());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_version());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_copyright());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_trademarks());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->last_change());
+  }
+}
+#endif
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, IsOfficialBuild) {
+  const wchar_t* kDLLNames[] = {
+    L"FileVersionInfoTest1.dll",
+    L"FileVersionInfoTest2.dll"
+  };
+
+  const bool kExpected[] = {
+    true,
+    false,
+  };
+
+  // Test consistency check.
+  ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected));
+
+  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+    EXPECT_EQ(kExpected[i], version_info->is_official_build());
+  }
+}
+#endif
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, CustomProperties) {
+  FilePath dll_path = GetTestDataPath();
+  dll_path = dll_path.AppendASCII("FileVersionInfoTest1.dll");
+
+  scoped_ptr<FileVersionInfo> version_info(
+      FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+  // Test few existing properties.
+  std::wstring str;
+  FileVersionInfoWin* version_info_win =
+      static_cast<FileVersionInfoWin*>(version_info.get());
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 1",  &str));
+  EXPECT_EQ(L"Un", str);
+  EXPECT_EQ(L"Un", version_info_win->GetStringValue(L"Custom prop 1"));
+
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 2",  &str));
+  EXPECT_EQ(L"Deux", str);
+  EXPECT_EQ(L"Deux", version_info_win->GetStringValue(L"Custom prop 2"));
+
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 3",  &str));
+  EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", str);
+  EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043",
+            version_info_win->GetStringValue(L"Custom prop 3"));
+
+  // Test an non-existing property.
+  EXPECT_FALSE(version_info_win->GetValue(L"Unknown property",  &str));
+  EXPECT_EQ(L"", version_info_win->GetStringValue(L"Unknown property"));
+}
+#endif
diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc
new file mode 100644
index 0000000..ca3e4b1
--- /dev/null
+++ b/base/file_version_info_win.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/file_version_info_win.h"
+
+#include <windows.h>
+
+#include "base/file_version_info.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+using base::FilePath;
+
+FileVersionInfoWin::FileVersionInfoWin(void* data,
+                                       WORD language,
+                                       WORD code_page)
+    : language_(language), code_page_(code_page) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  data_.reset((char*) data);
+  fixed_file_info_ = NULL;
+  UINT size;
+  ::VerQueryValue(data_.get(), L"\\", (LPVOID*)&fixed_file_info_, &size);
+}
+
+FileVersionInfoWin::~FileVersionInfoWin() {
+  DCHECK(data_.get());
+}
+
+typedef struct {
+  WORD language;
+  WORD code_page;
+} LanguageAndCodePage;
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForModule(
+    HMODULE module) {
+  // Note that the use of MAX_PATH is basically in line with what we do for
+  // all registered paths (PathProviderWin).
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+  if (!GetModuleFileName(module, system_buffer, MAX_PATH))
+    return NULL;
+
+  FilePath app_path(system_buffer);
+  return CreateFileVersionInfo(app_path);
+}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
+    const FilePath& file_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  DWORD dummy;
+  const wchar_t* path = file_path.value().c_str();
+  DWORD length = ::GetFileVersionInfoSize(path, &dummy);
+  if (length == 0)
+    return NULL;
+
+  void* data = calloc(length, 1);
+  if (!data)
+    return NULL;
+
+  if (!::GetFileVersionInfo(path, dummy, length, data)) {
+    free(data);
+    return NULL;
+  }
+
+  LanguageAndCodePage* translate = NULL;
+  uint32 page_count;
+  BOOL query_result = VerQueryValue(data, L"\\VarFileInfo\\Translation",
+                                   (void**) &translate, &page_count);
+
+  if (query_result && translate) {
+    return new FileVersionInfoWin(data, translate->language,
+                                  translate->code_page);
+
+  } else {
+    free(data);
+    return NULL;
+  }
+}
+
+base::string16 FileVersionInfoWin::company_name() {
+  return GetStringValue(L"CompanyName");
+}
+
+base::string16 FileVersionInfoWin::company_short_name() {
+  return GetStringValue(L"CompanyShortName");
+}
+
+base::string16 FileVersionInfoWin::internal_name() {
+  return GetStringValue(L"InternalName");
+}
+
+base::string16 FileVersionInfoWin::product_name() {
+  return GetStringValue(L"ProductName");
+}
+
+base::string16 FileVersionInfoWin::product_short_name() {
+  return GetStringValue(L"ProductShortName");
+}
+
+base::string16 FileVersionInfoWin::comments() {
+  return GetStringValue(L"Comments");
+}
+
+base::string16 FileVersionInfoWin::legal_copyright() {
+  return GetStringValue(L"LegalCopyright");
+}
+
+base::string16 FileVersionInfoWin::product_version() {
+  return GetStringValue(L"ProductVersion");
+}
+
+base::string16 FileVersionInfoWin::file_description() {
+  return GetStringValue(L"FileDescription");
+}
+
+base::string16 FileVersionInfoWin::legal_trademarks() {
+  return GetStringValue(L"LegalTrademarks");
+}
+
+base::string16 FileVersionInfoWin::private_build() {
+  return GetStringValue(L"PrivateBuild");
+}
+
+base::string16 FileVersionInfoWin::file_version() {
+  return GetStringValue(L"FileVersion");
+}
+
+base::string16 FileVersionInfoWin::original_filename() {
+  return GetStringValue(L"OriginalFilename");
+}
+
+base::string16 FileVersionInfoWin::special_build() {
+  return GetStringValue(L"SpecialBuild");
+}
+
+base::string16 FileVersionInfoWin::last_change() {
+  return GetStringValue(L"LastChange");
+}
+
+bool FileVersionInfoWin::is_official_build() {
+  return (GetStringValue(L"Official Build").compare(L"1") == 0);
+}
+
+bool FileVersionInfoWin::GetValue(const wchar_t* name,
+                                  std::wstring* value_str) {
+  WORD lang_codepage[8];
+  int i = 0;
+  // Use the language and codepage from the DLL.
+  lang_codepage[i++] = language_;
+  lang_codepage[i++] = code_page_;
+  // Use the default language and codepage from the DLL.
+  lang_codepage[i++] = ::GetUserDefaultLangID();
+  lang_codepage[i++] = code_page_;
+  // Use the language from the DLL and Latin codepage (most common).
+  lang_codepage[i++] = language_;
+  lang_codepage[i++] = 1252;
+  // Use the default language and Latin codepage (most common).
+  lang_codepage[i++] = ::GetUserDefaultLangID();
+  lang_codepage[i++] = 1252;
+
+  i = 0;
+  while (i < arraysize(lang_codepage)) {
+    wchar_t sub_block[MAX_PATH];
+    WORD language = lang_codepage[i++];
+    WORD code_page = lang_codepage[i++];
+    _snwprintf_s(sub_block, MAX_PATH, MAX_PATH,
+                 L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name);
+    LPVOID value = NULL;
+    uint32 size;
+    BOOL r = ::VerQueryValue(data_.get(), sub_block, &value, &size);
+    if (r && value) {
+      value_str->assign(static_cast<wchar_t*>(value));
+      return true;
+    }
+  }
+  return false;
+}
+
+std::wstring FileVersionInfoWin::GetStringValue(const wchar_t* name) {
+  std::wstring str;
+  if (GetValue(name, &str))
+    return str;
+  else
+    return L"";
+}
diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h
new file mode 100644
index 0000000..09d8d37
--- /dev/null
+++ b/base/file_version_info_win.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_VERSION_INFO_WIN_H_
+#define BASE_FILE_VERSION_INFO_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_version_info.h"
+#include "base/memory/scoped_ptr.h"
+
+struct tagVS_FIXEDFILEINFO;
+typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
+
+class BASE_EXPORT FileVersionInfoWin : public FileVersionInfo {
+ public:
+  FileVersionInfoWin(void* data, WORD language, WORD code_page);
+  ~FileVersionInfoWin() override;
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  base::string16 company_name() override;
+  base::string16 company_short_name() override;
+  base::string16 product_name() override;
+  base::string16 product_short_name() override;
+  base::string16 internal_name() override;
+  base::string16 product_version() override;
+  base::string16 private_build() override;
+  base::string16 special_build() override;
+  base::string16 comments() override;
+  base::string16 original_filename() override;
+  base::string16 file_description() override;
+  base::string16 file_version() override;
+  base::string16 legal_copyright() override;
+  base::string16 legal_trademarks() override;
+  base::string16 last_change() override;
+  bool is_official_build() override;
+
+  // Lets you access other properties not covered above.
+  bool GetValue(const wchar_t* name, std::wstring* value);
+
+  // Similar to GetValue but returns a wstring (empty string if the property
+  // does not exist).
+  std::wstring GetStringValue(const wchar_t* name);
+
+  // Get the fixed file info if it exists. Otherwise NULL
+  VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; }
+
+ private:
+  scoped_ptr<char, base::FreeDeleter> data_;
+  WORD language_;
+  WORD code_page_;
+  // This is a pointer into the data_ if it exists. Otherwise NULL.
+  VS_FIXEDFILEINFO* fixed_file_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileVersionInfoWin);
+};
+
+#endif  // BASE_FILE_VERSION_INFO_WIN_H_
diff --git a/base/files/OWNERS b/base/files/OWNERS
new file mode 100644
index 0000000..b99e8a2
--- /dev/null
+++ b/base/files/OWNERS
@@ -0,0 +1,3 @@
+rvargas@chromium.org
+
+per-file file_path_watcher*=mnissler@chromium.org
diff --git a/base/files/dir_reader_fallback.h b/base/files/dir_reader_fallback.h
new file mode 100644
index 0000000..a435f25
--- /dev/null
+++ b/base/files/dir_reader_fallback.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_DIR_READER_FALLBACK_H_
+#define BASE_FILES_DIR_READER_FALLBACK_H_
+
+namespace base {
+
+class DirReaderFallback {
+ public:
+  // Open a directory. If |IsValid| is true, then |Next| can be called to start
+  // the iteration at the beginning of the directory.
+  explicit DirReaderFallback(const char* directory_path) {}
+
+  // After construction, IsValid returns true iff the directory was
+  // successfully opened.
+  bool IsValid() const { return false; }
+
+  // Move to the next entry returning false if the iteration is complete.
+  bool Next() { return false; }
+
+  // Return the name of the current directory entry.
+  const char* name() { return 0;}
+
+  // Return the file descriptor which is being used.
+  int fd() const { return -1; }
+
+  // Returns true if this is a no-op fallback class (for testing).
+  static bool IsFallback() { return true; }
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_DIR_READER_FALLBACK_H_
diff --git a/base/files/dir_reader_linux.h b/base/files/dir_reader_linux.h
new file mode 100644
index 0000000..cb0cbd3
--- /dev/null
+++ b/base/files/dir_reader_linux.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_DIR_READER_LINUX_H_
+#define BASE_FILES_DIR_READER_LINUX_H_
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+// See the comments in dir_reader_posix.h about this.
+
+namespace base {
+
+struct linux_dirent {
+  uint64_t        d_ino;
+  int64_t         d_off;
+  unsigned short  d_reclen;
+  unsigned char   d_type;
+  char            d_name[0];
+};
+
+class DirReaderLinux {
+ public:
+  explicit DirReaderLinux(const char* directory_path)
+      : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
+        offset_(0),
+        size_(0) {
+    memset(buf_, 0, sizeof(buf_));
+  }
+
+  ~DirReaderLinux() {
+    if (fd_ >= 0) {
+      if (IGNORE_EINTR(close(fd_)))
+        RAW_LOG(ERROR, "Failed to close directory handle");
+    }
+  }
+
+  bool IsValid() const {
+    return fd_ >= 0;
+  }
+
+  // Move to the next entry returning false if the iteration is complete.
+  bool Next() {
+    if (size_) {
+      linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
+      offset_ += dirent->d_reclen;
+    }
+
+    if (offset_ != size_)
+      return true;
+
+    const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
+    if (r == 0)
+      return false;
+    if (r == -1) {
+      DPLOG(FATAL) << "getdents64 returned an error: " << errno;
+      return false;
+    }
+    size_ = r;
+    offset_ = 0;
+    return true;
+  }
+
+  const char* name() const {
+    if (!size_)
+      return NULL;
+
+    const linux_dirent* dirent =
+        reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
+    return dirent->d_name;
+  }
+
+  int fd() const {
+    return fd_;
+  }
+
+  static bool IsFallback() {
+    return false;
+  }
+
+ private:
+  const int fd_;
+  unsigned char buf_[512];
+  size_t offset_, size_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
+};
+
+}  // namespace base
+
+#endif // BASE_FILES_DIR_READER_LINUX_H_
diff --git a/base/files/dir_reader_posix.h b/base/files/dir_reader_posix.h
new file mode 100644
index 0000000..6a20ced
--- /dev/null
+++ b/base/files/dir_reader_posix.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_DIR_READER_POSIX_H_
+#define BASE_FILES_DIR_READER_POSIX_H_
+
+#include "build/build_config.h"
+
+// This header provides a class, DirReaderPosix, which allows one to open and
+// read from directories without allocating memory. For the interface, see
+// the generic fallback in dir_reader_fallback.h.
+
+// Mac note: OS X has getdirentries, but it only works if we restrict Chrome to
+// 32-bit inodes. There is a getdirentries64 syscall in 10.6, but it's not
+// wrapped and the direct syscall interface is unstable. Using an unstable API
+// seems worse than falling back to enumerating all file descriptors so we will
+// probably never implement this on the Mac.
+
+#if defined(OS_LINUX)
+#include "base/files/dir_reader_linux.h"
+#else
+#include "base/files/dir_reader_fallback.h"
+#endif
+
+namespace base {
+
+#if defined(OS_LINUX)
+typedef DirReaderLinux DirReaderPosix;
+#else
+typedef DirReaderFallback DirReaderPosix;
+#endif
+
+}  // namespace base
+
+#endif // BASE_FILES_DIR_READER_POSIX_H_
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
new file mode 100644
index 0000000..0685031
--- /dev/null
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/dir_reader_posix.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+TEST(DirReaderPosixUnittest, Read) {
+  static const unsigned kNumFiles = 100;
+
+  if (DirReaderPosix::IsFallback())
+    return;
+
+  char kDirTemplate[] = "/tmp/org.chromium.dir-reader-posix-XXXXXX";
+  const char* dir = mkdtemp(kDirTemplate);
+  ASSERT_TRUE(dir);
+
+  const int prev_wd = open(".", O_RDONLY | O_DIRECTORY);
+  DCHECK_GE(prev_wd, 0);
+
+  PCHECK(chdir(dir) == 0);
+
+  for (unsigned i = 0; i < kNumFiles; i++) {
+    char buf[16];
+    snprintf(buf, sizeof(buf), "%d", i);
+    const int fd = open(buf, O_CREAT | O_RDONLY | O_EXCL, 0600);
+    PCHECK(fd >= 0);
+    PCHECK(close(fd) == 0);
+  }
+
+  std::set<unsigned> seen;
+
+  DirReaderPosix reader(dir);
+  EXPECT_TRUE(reader.IsValid());
+
+  if (!reader.IsValid())
+    return;
+
+  bool seen_dot = false, seen_dotdot = false;
+
+  for (; reader.Next(); ) {
+    if (strcmp(reader.name(), ".") == 0) {
+      seen_dot = true;
+      continue;
+    }
+    if (strcmp(reader.name(), "..") == 0) {
+      seen_dotdot = true;
+      continue;
+    }
+
+    SCOPED_TRACE(testing::Message() << "reader.name(): " << reader.name());
+
+    char *endptr;
+    const unsigned long value = strtoul(reader.name(), &endptr, 10);
+
+    EXPECT_FALSE(*endptr);
+    EXPECT_LT(value, kNumFiles);
+    EXPECT_EQ(0u, seen.count(value));
+    seen.insert(value);
+  }
+
+  for (unsigned i = 0; i < kNumFiles; i++) {
+    char buf[16];
+    snprintf(buf, sizeof(buf), "%d", i);
+    PCHECK(unlink(buf) == 0);
+  }
+
+  PCHECK(rmdir(dir) == 0);
+
+  PCHECK(fchdir(prev_wd) == 0);
+  PCHECK(close(prev_wd) == 0);
+
+  EXPECT_TRUE(seen_dot);
+  EXPECT_TRUE(seen_dotdot);
+  EXPECT_EQ(kNumFiles, seen.size());
+}
+
+}  // namespace base
diff --git a/base/files/file.cc b/base/files/file.cc
new file mode 100644
index 0000000..8030bf1
--- /dev/null
+++ b/base/files/file.cc
@@ -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.
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/metrics/histogram.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+File::Info::Info()
+    : size(0),
+      is_directory(false),
+      is_symbolic_link(false) {
+}
+
+File::Info::~Info() {
+}
+
+File::File()
+    : error_details_(FILE_ERROR_FAILED),
+      created_(false),
+      async_(false) {
+}
+
+#if !defined(OS_NACL)
+File::File(const FilePath& name, uint32 flags)
+    : error_details_(FILE_OK),
+      created_(false),
+      async_(false) {
+  Initialize(name, flags);
+}
+#endif
+
+File::File(PlatformFile platform_file)
+    : file_(platform_file),
+      error_details_(FILE_OK),
+      created_(false),
+      async_(false) {
+#if defined(OS_POSIX)
+  DCHECK_GE(platform_file, -1);
+#endif
+}
+
+File::File(Error error_details)
+    : error_details_(error_details),
+      created_(false),
+      async_(false) {
+}
+
+File::File(RValue other)
+    : file_(other.object->TakePlatformFile()),
+      error_details_(other.object->error_details()),
+      created_(other.object->created()),
+      async_(other.object->async_) {
+}
+
+File::~File() {
+  // Go through the AssertIOAllowed logic.
+  Close();
+}
+
+File& File::operator=(RValue other) {
+  if (this != other.object) {
+    Close();
+    SetPlatformFile(other.object->TakePlatformFile());
+    error_details_ = other.object->error_details();
+    created_ = other.object->created();
+    async_ = other.object->async_;
+  }
+  return *this;
+}
+
+#if !defined(OS_NACL)
+void File::Initialize(const FilePath& name, uint32 flags) {
+  if (name.ReferencesParent()) {
+    error_details_ = FILE_ERROR_ACCESS_DENIED;
+    return;
+  }
+  DoInitialize(name, flags);
+}
+#endif
+
+std::string File::ErrorToString(Error error) {
+  switch (error) {
+    case FILE_OK:
+      return "FILE_OK";
+    case FILE_ERROR_FAILED:
+      return "FILE_ERROR_FAILED";
+    case FILE_ERROR_IN_USE:
+      return "FILE_ERROR_IN_USE";
+    case FILE_ERROR_EXISTS:
+      return "FILE_ERROR_EXISTS";
+    case FILE_ERROR_NOT_FOUND:
+      return "FILE_ERROR_NOT_FOUND";
+    case FILE_ERROR_ACCESS_DENIED:
+      return "FILE_ERROR_ACCESS_DENIED";
+    case FILE_ERROR_TOO_MANY_OPENED:
+      return "FILE_ERROR_TOO_MANY_OPENED";
+    case FILE_ERROR_NO_MEMORY:
+      return "FILE_ERROR_NO_MEMORY";
+    case FILE_ERROR_NO_SPACE:
+      return "FILE_ERROR_NO_SPACE";
+    case FILE_ERROR_NOT_A_DIRECTORY:
+      return "FILE_ERROR_NOT_A_DIRECTORY";
+    case FILE_ERROR_INVALID_OPERATION:
+      return "FILE_ERROR_INVALID_OPERATION";
+    case FILE_ERROR_SECURITY:
+      return "FILE_ERROR_SECURITY";
+    case FILE_ERROR_ABORT:
+      return "FILE_ERROR_ABORT";
+    case FILE_ERROR_NOT_A_FILE:
+      return "FILE_ERROR_NOT_A_FILE";
+    case FILE_ERROR_NOT_EMPTY:
+      return "FILE_ERROR_NOT_EMPTY";
+    case FILE_ERROR_INVALID_URL:
+      return "FILE_ERROR_INVALID_URL";
+    case FILE_ERROR_IO:
+      return "FILE_ERROR_IO";
+    case FILE_ERROR_MAX:
+      break;
+  }
+
+  NOTREACHED();
+  return "";
+}
+
+bool File::Flush() {
+  ElapsedTimer timer;
+  bool return_value = DoFlush();
+  UMA_HISTOGRAM_TIMES("PlatformFile.FlushTime", timer.Elapsed());
+  return return_value;
+}
+
+}  // namespace base
diff --git a/base/files/file.h b/base/files/file.h
new file mode 100644
index 0000000..89077b4
--- /dev/null
+++ b/base/files/file.h
@@ -0,0 +1,376 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_H_
+#define BASE_FILES_FILE_H_
+
+#include "build/build_config.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
+#include "base/move.h"
+#include "base/time/time.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
+
+namespace base {
+
+class FilePath;
+
+#if defined(OS_WIN)
+typedef HANDLE PlatformFile;
+#elif defined(OS_POSIX)
+typedef int PlatformFile;
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+typedef struct stat stat_wrapper_t;
+#else
+typedef struct stat64 stat_wrapper_t;
+#endif
+#endif  // defined(OS_POSIX)
+
+// Thin wrapper around an OS-level file.
+// Note that this class does not provide any support for asynchronous IO, other
+// than the ability to create asynchronous handles on Windows.
+//
+// Note about const: this class does not attempt to determine if the underlying
+// file system object is affected by a particular method in order to consider
+// that method const or not. Only methods that deal with member variables in an
+// obvious non-modifying way are marked as const. Any method that forward calls
+// to the OS is not considered const, even if there is no apparent change to
+// member variables.
+class BASE_EXPORT File {
+  MOVE_ONLY_TYPE_FOR_CPP_03(File, RValue)
+
+ public:
+  // FLAG_(OPEN|CREATE).* are mutually exclusive. You should specify exactly one
+  // of the five (possibly combining with other flags) when opening or creating
+  // a file.
+  // FLAG_(WRITE|APPEND) are mutually exclusive. This is so that APPEND behavior
+  // will be consistent with O_APPEND on POSIX.
+  // FLAG_EXCLUSIVE_(READ|WRITE) only grant exclusive access to the file on
+  // creation on POSIX; for existing files, consider using Lock().
+  enum Flags {
+    FLAG_OPEN = 1 << 0,             // Opens a file, only if it exists.
+    FLAG_CREATE = 1 << 1,           // Creates a new file, only if it does not
+                                    // already exist.
+    FLAG_OPEN_ALWAYS = 1 << 2,      // May create a new file.
+    FLAG_CREATE_ALWAYS = 1 << 3,    // May overwrite an old file.
+    FLAG_OPEN_TRUNCATED = 1 << 4,   // Opens a file and truncates it, only if it
+                                    // exists.
+    FLAG_READ = 1 << 5,
+    FLAG_WRITE = 1 << 6,
+    FLAG_APPEND = 1 << 7,
+    FLAG_EXCLUSIVE_READ = 1 << 8,   // EXCLUSIVE is opposite of Windows SHARE.
+    FLAG_EXCLUSIVE_WRITE = 1 << 9,
+    FLAG_ASYNC = 1 << 10,
+    FLAG_TEMPORARY = 1 << 11,       // Used on Windows only.
+    FLAG_HIDDEN = 1 << 12,          // Used on Windows only.
+    FLAG_DELETE_ON_CLOSE = 1 << 13,
+    FLAG_WRITE_ATTRIBUTES = 1 << 14,  // Used on Windows only.
+    FLAG_SHARE_DELETE = 1 << 15,      // Used on Windows only.
+    FLAG_TERMINAL_DEVICE = 1 << 16,   // Serial port flags.
+    FLAG_BACKUP_SEMANTICS = 1 << 17,  // Used on Windows only.
+    FLAG_EXECUTE = 1 << 18,           // Used on Windows only.
+  };
+
+  // This enum has been recorded in multiple histograms. If the order of the
+  // fields needs to change, please ensure that those histograms are obsolete or
+  // have been moved to a different enum.
+  //
+  // FILE_ERROR_ACCESS_DENIED is returned when a call fails because of a
+  // filesystem restriction. FILE_ERROR_SECURITY is returned when a browser
+  // policy doesn't allow the operation to be executed.
+  enum Error {
+    FILE_OK = 0,
+    FILE_ERROR_FAILED = -1,
+    FILE_ERROR_IN_USE = -2,
+    FILE_ERROR_EXISTS = -3,
+    FILE_ERROR_NOT_FOUND = -4,
+    FILE_ERROR_ACCESS_DENIED = -5,
+    FILE_ERROR_TOO_MANY_OPENED = -6,
+    FILE_ERROR_NO_MEMORY = -7,
+    FILE_ERROR_NO_SPACE = -8,
+    FILE_ERROR_NOT_A_DIRECTORY = -9,
+    FILE_ERROR_INVALID_OPERATION = -10,
+    FILE_ERROR_SECURITY = -11,
+    FILE_ERROR_ABORT = -12,
+    FILE_ERROR_NOT_A_FILE = -13,
+    FILE_ERROR_NOT_EMPTY = -14,
+    FILE_ERROR_INVALID_URL = -15,
+    FILE_ERROR_IO = -16,
+    // Put new entries here and increment FILE_ERROR_MAX.
+    FILE_ERROR_MAX = -17
+  };
+
+  // This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
+  enum Whence {
+    FROM_BEGIN   = 0,
+    FROM_CURRENT = 1,
+    FROM_END     = 2
+  };
+
+  // Used to hold information about a given file.
+  // If you add more fields to this structure (platform-specific fields are OK),
+  // make sure to update all functions that use it in file_util_{win|posix}.cc,
+  // too, and the ParamTraits<base::File::Info> implementation in
+  // ipc/ipc_message_utils.cc.
+  struct BASE_EXPORT Info {
+    Info();
+    ~Info();
+#if defined(OS_POSIX)
+    // Fills this struct with values from |stat_info|.
+    void FromStat(const stat_wrapper_t& stat_info);
+#endif
+
+    // The size of the file in bytes.  Undefined when is_directory is true.
+    int64 size;
+
+    // True if the file corresponds to a directory.
+    bool is_directory;
+
+    // True if the file corresponds to a symbolic link.  For Windows currently
+    // not supported and thus always false.
+    bool is_symbolic_link;
+
+    // The last modified time of a file.
+    Time last_modified;
+
+    // The last accessed time of a file.
+    Time last_accessed;
+
+    // The creation time of a file.
+    Time creation_time;
+  };
+
+  File();
+
+  // Creates or opens the given file. This will fail with 'access denied' if the
+  // |name| contains path traversal ('..') components.
+  File(const FilePath& name, uint32 flags);
+
+  // Takes ownership of |platform_file|.
+  explicit File(PlatformFile platform_file);
+
+  // Creates an object with a specific error_details code.
+  explicit File(Error error_details);
+
+  // Move constructor for C++03 move emulation of this type.
+  File(RValue other);
+
+  ~File();
+
+  // Move operator= for C++03 move emulation of this type.
+  File& operator=(RValue other);
+
+  // Creates or opens the given file.
+  void Initialize(const FilePath& name, uint32 flags);
+
+  bool IsValid() const;
+
+  // Returns true if a new file was created (or an old one truncated to zero
+  // length to simulate a new file, which can happen with
+  // FLAG_CREATE_ALWAYS), and false otherwise.
+  bool created() const { return created_; }
+
+  // Returns the OS result of opening this file. Note that the way to verify
+  // the success of the operation is to use IsValid(), not this method:
+  //   File file(name, flags);
+  //   if (!file.IsValid())
+  //     return;
+  Error error_details() const { return error_details_; }
+
+  PlatformFile GetPlatformFile() const;
+  PlatformFile TakePlatformFile();
+
+  // Destroying this object closes the file automatically.
+  void Close();
+
+  // Changes current position in the file to an |offset| relative to an origin
+  // defined by |whence|. Returns the resultant current position in the file
+  // (relative to the start) or -1 in case of error.
+  int64 Seek(Whence whence, int64 offset);
+
+  // Reads the given number of bytes (or until EOF is reached) starting with the
+  // given offset. Returns the number of bytes read, or -1 on error. Note that
+  // this function makes a best effort to read all data on all platforms, so it
+  // is not intended for stream oriented files but instead for cases when the
+  // normal expectation is that actually |size| bytes are read unless there is
+  // an error.
+  int Read(int64 offset, char* data, int size);
+
+  // Same as above but without seek.
+  int ReadAtCurrentPos(char* data, int size);
+
+  // Reads the given number of bytes (or until EOF is reached) starting with the
+  // given offset, but does not make any effort to read all data on all
+  // platforms. Returns the number of bytes read, or -1 on error.
+  int ReadNoBestEffort(int64 offset, char* data, int size);
+
+  // Same as above but without seek.
+  int ReadAtCurrentPosNoBestEffort(char* data, int size);
+
+  // Writes the given buffer into the file at the given offset, overwritting any
+  // data that was previously there. Returns the number of bytes written, or -1
+  // on error. Note that this function makes a best effort to write all data on
+  // all platforms.
+  // Ignores the offset and writes to the end of the file if the file was opened
+  // with FLAG_APPEND.
+  int Write(int64 offset, const char* data, int size);
+
+  // Save as above but without seek.
+  int WriteAtCurrentPos(const char* data, int size);
+
+  // Save as above but does not make any effort to write all data on all
+  // platforms. Returns the number of bytes written, or -1 on error.
+  int WriteAtCurrentPosNoBestEffort(const char* data, int size);
+
+  // Returns the current size of this file, or a negative number on failure.
+  int64 GetLength();
+
+  // Truncates the file to the given length. If |length| is greater than the
+  // current size of the file, the file is extended with zeros. If the file
+  // doesn't exist, |false| is returned.
+  bool SetLength(int64 length);
+
+  // Instructs the filesystem to flush the file to disk. (POSIX: fsync, Windows:
+  // FlushFileBuffers).
+  bool Flush();
+
+  // Updates the file times.
+  bool SetTimes(Time last_access_time, Time last_modified_time);
+
+  // Returns some basic information for the given file.
+  bool GetInfo(Info* info);
+
+  // Attempts to take an exclusive write lock on the file. Returns immediately
+  // (i.e. does not wait for another process to unlock the file). If the lock
+  // was obtained, the result will be FILE_OK. A lock only guarantees
+  // that other processes may not also take a lock on the same file with the
+  // same API - it may still be opened, renamed, unlinked, etc.
+  //
+  // Common semantics:
+  //  * Locks are held by processes, but not inherited by child processes.
+  //  * Locks are released by the OS on file close or process termination.
+  //  * Locks are reliable only on local filesystems.
+  //  * Duplicated file handles may also write to locked files.
+  // Windows-specific semantics:
+  //  * Locks are mandatory for read/write APIs, advisory for mapping APIs.
+  //  * Within a process, locking the same file (by the same or new handle)
+  //    will fail.
+  // POSIX-specific semantics:
+  //  * Locks are advisory only.
+  //  * Within a process, locking the same file (by the same or new handle)
+  //    will succeed.
+  //  * Closing any descriptor on a given file releases the lock.
+  Error Lock();
+
+  // Unlock a file previously locked.
+  Error Unlock();
+
+  // Returns a new object referencing this file for use within the current
+  // process. Handling of FLAG_DELETE_ON_CLOSE varies by OS. On POSIX, the File
+  // object that was created or initialized with this flag will have unlinked
+  // the underlying file when it was created or opened. On Windows, the
+  // underlying file is deleted when the last handle to it is closed.
+  File Duplicate();
+
+  bool async() const { return async_; }
+
+#if defined(OS_WIN)
+  static Error OSErrorToFileError(DWORD last_error);
+#elif defined(OS_POSIX)
+  static Error OSErrorToFileError(int saved_errno);
+#endif
+
+  // Converts an error value to a human-readable form. Used for logging.
+  static std::string ErrorToString(Error error);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+#if defined(OS_POSIX)
+  // Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
+  // alongside it. This checksum is validated at every access, allowing early
+  // detection of memory corruption.
+
+  // TODO(gavinp): This is in place temporarily to help us debug
+  // https://crbug.com/424562 , which can't be reproduced in valgrind. Remove
+  // this code after we have fixed this issue.
+  class MemoryCheckingScopedFD {
+   public:
+    MemoryCheckingScopedFD();
+    MemoryCheckingScopedFD(int fd);
+    ~MemoryCheckingScopedFD();
+
+    bool is_valid() const { Check(); return file_.is_valid(); }
+    int get() const { Check(); return file_.get(); }
+
+    void reset() { Check(); file_.reset(); UpdateChecksum(); }
+    void reset(int fd) { Check(); file_.reset(fd); UpdateChecksum(); }
+    int release() {
+      Check();
+      int fd = file_.release();
+      UpdateChecksum();
+      return fd;
+    }
+
+   private:
+    FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+    // Computes the checksum for the current value of |file_|. Returns via an
+    // out parameter to guard against implicit conversions of unsigned integral
+    // types.
+    void ComputeMemoryChecksum(unsigned int* out_checksum) const;
+
+    // Confirms that the current |file_| and |file_memory_checksum_| agree,
+    // failing a CHECK if they do not.
+    void Check() const;
+
+    void UpdateChecksum();
+
+    ScopedFD file_;
+    unsigned int file_memory_checksum_;
+  };
+#endif
+
+  // Creates or opens the given file. Only called if |name| has no traversal
+  // ('..') components.
+  void DoInitialize(const FilePath& name, uint32 flags);
+
+  // TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
+  // cf. issue 473337.
+  bool DoFlush();
+
+  void SetPlatformFile(PlatformFile file);
+
+#if defined(OS_WIN)
+  win::ScopedHandle file_;
+#elif defined(OS_POSIX)
+  MemoryCheckingScopedFD file_;
+#endif
+
+  Error error_details_;
+  bool created_;
+  bool async_;
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_H_
diff --git a/base/files/file_enumerator.cc b/base/files/file_enumerator.cc
new file mode 100644
index 0000000..9749980
--- /dev/null
+++ b/base/files/file_enumerator.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_enumerator.h"
+
+#include "base/files/file_util.h"
+
+namespace base {
+
+FileEnumerator::FileInfo::~FileInfo() {
+}
+
+bool FileEnumerator::ShouldSkip(const FilePath& path) {
+  FilePath::StringType basename = path.BaseName().value();
+  return basename == FILE_PATH_LITERAL(".") ||
+         (basename == FILE_PATH_LITERAL("..") &&
+          !(INCLUDE_DOT_DOT & file_type_));
+}
+
+}  // namespace base
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h
new file mode 100644
index 0000000..38bb833
--- /dev/null
+++ b/base/files/file_enumerator.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_ENUMERATOR_H_
+#define BASE_FILES_FILE_ENUMERATOR_H_
+
+#include <stack>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+// A class for enumerating the files in a provided path. The order of the
+// results is not guaranteed.
+//
+// This is blocking. Do not use on critical threads.
+//
+// Example:
+//
+//   base::FileEnumerator enum(my_dir, false, base::FileEnumerator::FILES,
+//                             FILE_PATH_LITERAL("*.txt"));
+//   for (base::FilePath name = enum.Next(); !name.empty(); name = enum.Next())
+//     ...
+class BASE_EXPORT FileEnumerator {
+ public:
+  // Note: copy & assign supported.
+  class BASE_EXPORT FileInfo {
+   public:
+    FileInfo();
+    ~FileInfo();
+
+    bool IsDirectory() const;
+
+    // The name of the file. This will not include any path information. This
+    // is in constrast to the value returned by FileEnumerator.Next() which
+    // includes the |root_path| passed into the FileEnumerator constructor.
+    FilePath GetName() const;
+
+    int64 GetSize() const;
+    Time GetLastModifiedTime() const;
+
+#if defined(OS_WIN)
+    // Note that the cAlternateFileName (used to hold the "short" 8.3 name)
+    // of the WIN32_FIND_DATA will be empty. Since we don't use short file
+    // names, we tell Windows to omit it which speeds up the query slightly.
+    const WIN32_FIND_DATA& find_data() const { return find_data_; }
+#elif defined(OS_POSIX)
+    const struct stat& stat() const { return stat_; }
+#endif
+
+   private:
+    friend class FileEnumerator;
+
+#if defined(OS_WIN)
+    WIN32_FIND_DATA find_data_;
+#elif defined(OS_POSIX)
+    struct stat stat_;
+    FilePath filename_;
+#endif
+  };
+
+  enum FileType {
+    FILES                 = 1 << 0,
+    DIRECTORIES           = 1 << 1,
+    INCLUDE_DOT_DOT       = 1 << 2,
+#if defined(OS_POSIX)
+    SHOW_SYM_LINKS        = 1 << 4,
+#endif
+  };
+
+  // |root_path| is the starting directory to search for. It may or may not end
+  // in a slash.
+  //
+  // If |recursive| is true, this will enumerate all matches in any
+  // subdirectories matched as well. It does a breadth-first search, so all
+  // files in one directory will be returned before any files in a
+  // subdirectory.
+  //
+  // |file_type|, a bit mask of FileType, specifies whether the enumerator
+  // should match files, directories, or both.
+  //
+  // |pattern| is an optional pattern for which files to match. This
+  // works like shell globbing. For example, "*.txt" or "Foo???.doc".
+  // However, be careful in specifying patterns that aren't cross platform
+  // since the underlying code uses OS-specific matching routines.  In general,
+  // Windows matching is less featureful than others, so test there first.
+  // If unspecified, this will match all files.
+  // NOTE: the pattern only matches the contents of root_path, not files in
+  // recursive subdirectories.
+  // TODO(erikkay): Fix the pattern matching to work at all levels.
+  FileEnumerator(const FilePath& root_path,
+                 bool recursive,
+                 int file_type);
+  FileEnumerator(const FilePath& root_path,
+                 bool recursive,
+                 int file_type,
+                 const FilePath::StringType& pattern);
+  ~FileEnumerator();
+
+  // Returns the next file or an empty string if there are no more results.
+  //
+  // The returned path will incorporate the |root_path| passed in the
+  // constructor: "<root_path>/file_name.txt". If the |root_path| is absolute,
+  // then so will be the result of Next().
+  FilePath Next();
+
+  // Write the file info into |info|.
+  FileInfo GetInfo() const;
+
+ private:
+  // Returns true if the given path should be skipped in enumeration.
+  bool ShouldSkip(const FilePath& path);
+
+#if defined(OS_WIN)
+  // True when find_data_ is valid.
+  bool has_find_data_;
+  WIN32_FIND_DATA find_data_;
+  HANDLE find_handle_;
+#elif defined(OS_POSIX)
+
+  // Read the filenames in source into the vector of DirectoryEntryInfo's
+  static bool ReadDirectory(std::vector<FileInfo>* entries,
+                            const FilePath& source, bool show_links);
+
+  // The files in the current directory
+  std::vector<FileInfo> directory_entries_;
+
+  // The next entry to use from the directory_entries_ vector
+  size_t current_directory_entry_;
+#endif
+
+  FilePath root_path_;
+  bool recursive_;
+  int file_type_;
+  FilePath::StringType pattern_;  // Empty when we want to find everything.
+
+  // A stack that keeps track of which subdirectories we still need to
+  // enumerate in the breadth-first search.
+  std::stack<FilePath> pending_paths_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileEnumerator);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_ENUMERATOR_H_
diff --git a/base/files/file_enumerator_posix.cc b/base/files/file_enumerator_posix.cc
new file mode 100644
index 0000000..7533a24
--- /dev/null
+++ b/base/files/file_enumerator_posix.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_enumerator.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+// FileEnumerator::FileInfo ----------------------------------------------------
+
+FileEnumerator::FileInfo::FileInfo() {
+  memset(&stat_, 0, sizeof(stat_));
+}
+
+bool FileEnumerator::FileInfo::IsDirectory() const {
+  return S_ISDIR(stat_.st_mode);
+}
+
+FilePath FileEnumerator::FileInfo::GetName() const {
+  return filename_;
+}
+
+int64 FileEnumerator::FileInfo::GetSize() const {
+  return stat_.st_size;
+}
+
+base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
+  return base::Time::FromTimeT(stat_.st_mtime);
+}
+
+// FileEnumerator --------------------------------------------------------------
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type)
+    : current_directory_entry_(0),
+      root_path_(root_path),
+      recursive_(recursive),
+      file_type_(file_type) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type,
+                               const FilePath::StringType& pattern)
+    : current_directory_entry_(0),
+      root_path_(root_path),
+      recursive_(recursive),
+      file_type_(file_type),
+      pattern_(root_path.Append(pattern).value()) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  // The Windows version of this code appends the pattern to the root_path,
+  // potentially only matching against items in the top-most directory.
+  // Do the same here.
+  if (pattern.empty())
+    pattern_ = FilePath::StringType();
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::~FileEnumerator() {
+}
+
+FilePath FileEnumerator::Next() {
+  ++current_directory_entry_;
+
+  // While we've exhausted the entries in the current directory, do the next
+  while (current_directory_entry_ >= directory_entries_.size()) {
+    if (pending_paths_.empty())
+      return FilePath();
+
+    root_path_ = pending_paths_.top();
+    root_path_ = root_path_.StripTrailingSeparators();
+    pending_paths_.pop();
+
+    std::vector<FileInfo> entries;
+    if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
+      continue;
+
+    directory_entries_.clear();
+    current_directory_entry_ = 0;
+    for (std::vector<FileInfo>::const_iterator i = entries.begin();
+         i != entries.end(); ++i) {
+      FilePath full_path = root_path_.Append(i->filename_);
+      if (ShouldSkip(full_path))
+        continue;
+
+      if (pattern_.size() &&
+          fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE))
+        continue;
+
+      if (recursive_ && S_ISDIR(i->stat_.st_mode))
+        pending_paths_.push(full_path);
+
+      if ((S_ISDIR(i->stat_.st_mode) && (file_type_ & DIRECTORIES)) ||
+          (!S_ISDIR(i->stat_.st_mode) && (file_type_ & FILES)))
+        directory_entries_.push_back(*i);
+    }
+  }
+
+  return root_path_.Append(
+      directory_entries_[current_directory_entry_].filename_);
+}
+
+FileEnumerator::FileInfo FileEnumerator::GetInfo() const {
+  return directory_entries_[current_directory_entry_];
+}
+
+bool FileEnumerator::ReadDirectory(std::vector<FileInfo>* entries,
+                                   const FilePath& source, bool show_links) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DIR* dir = opendir(source.value().c_str());
+  if (!dir)
+    return false;
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \
+    !defined(OS_SOLARIS) && !defined(OS_ANDROID)
+  #error Port warning: depending on the definition of struct dirent, \
+         additional space for pathname may be needed
+#endif
+
+  struct dirent dent_buf;
+  struct dirent* dent;
+  while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
+    FileInfo info;
+    info.filename_ = FilePath(dent->d_name);
+
+    FilePath full_name = source.Append(dent->d_name);
+    int ret;
+    if (show_links)
+      ret = lstat(full_name.value().c_str(), &info.stat_);
+    else
+      ret = stat(full_name.value().c_str(), &info.stat_);
+    if (ret < 0) {
+      // Print the stat() error message unless it was ENOENT and we're
+      // following symlinks.
+      if (!(errno == ENOENT && !show_links)) {
+        DPLOG(ERROR) << "Couldn't stat "
+                     << source.Append(dent->d_name).value();
+      }
+      memset(&info.stat_, 0, sizeof(info.stat_));
+    }
+    entries->push_back(info);
+  }
+
+  closedir(dir);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
new file mode 100644
index 0000000..931d154
--- /dev/null
+++ b/base/files/file_enumerator_win.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_enumerator.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+// FileEnumerator::FileInfo ----------------------------------------------------
+
+FileEnumerator::FileInfo::FileInfo() {
+  memset(&find_data_, 0, sizeof(find_data_));
+}
+
+bool FileEnumerator::FileInfo::IsDirectory() const {
+  return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+FilePath FileEnumerator::FileInfo::GetName() const {
+  return FilePath(find_data_.cFileName);
+}
+
+int64 FileEnumerator::FileInfo::GetSize() const {
+  ULARGE_INTEGER size;
+  size.HighPart = find_data_.nFileSizeHigh;
+  size.LowPart = find_data_.nFileSizeLow;
+  DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max());
+  return static_cast<int64>(size.QuadPart);
+}
+
+base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
+  return base::Time::FromFileTime(find_data_.ftLastWriteTime);
+}
+
+// FileEnumerator --------------------------------------------------------------
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type)
+    : recursive_(recursive),
+      file_type_(file_type),
+      has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  memset(&find_data_, 0, sizeof(find_data_));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type,
+                               const FilePath::StringType& pattern)
+    : recursive_(recursive),
+      file_type_(file_type),
+      has_find_data_(false),
+      pattern_(pattern),
+      find_handle_(INVALID_HANDLE_VALUE) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  memset(&find_data_, 0, sizeof(find_data_));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::~FileEnumerator() {
+  if (find_handle_ != INVALID_HANDLE_VALUE)
+    FindClose(find_handle_);
+}
+
+FileEnumerator::FileInfo FileEnumerator::GetInfo() const {
+  if (!has_find_data_) {
+    NOTREACHED();
+    return FileInfo();
+  }
+  FileInfo ret;
+  memcpy(&ret.find_data_, &find_data_, sizeof(find_data_));
+  return ret;
+}
+
+FilePath FileEnumerator::Next() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  while (has_find_data_ || !pending_paths_.empty()) {
+    if (!has_find_data_) {
+      // The last find FindFirstFile operation is done, prepare a new one.
+      root_path_ = pending_paths_.top();
+      pending_paths_.pop();
+
+      // Start a new find operation.
+      FilePath src = root_path_;
+
+      if (pattern_.empty())
+        src = src.Append(L"*");  // No pattern = match everything.
+      else
+        src = src.Append(pattern_);
+
+      if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+        // Use a "large fetch" on newer Windows which should speed up large
+        // enumerations (we seldom abort in the middle).
+        find_handle_ = FindFirstFileEx(src.value().c_str(),
+                                       FindExInfoBasic,  // Omit short name.
+                                       &find_data_,
+                                       FindExSearchNameMatch,
+                                       NULL,
+                                       FIND_FIRST_EX_LARGE_FETCH);
+      } else {
+        find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
+      }
+      has_find_data_ = true;
+    } else {
+      // Search for the next file/directory.
+      if (!FindNextFile(find_handle_, &find_data_)) {
+        FindClose(find_handle_);
+        find_handle_ = INVALID_HANDLE_VALUE;
+      }
+    }
+
+    if (INVALID_HANDLE_VALUE == find_handle_) {
+      has_find_data_ = false;
+
+      // This is reached when we have finished a directory and are advancing to
+      // the next one in the queue. We applied the pattern (if any) to the files
+      // in the root search directory, but for those directories which were
+      // matched, we want to enumerate all files inside them. This will happen
+      // when the handle is empty.
+      pattern_ = FilePath::StringType();
+
+      continue;
+    }
+
+    FilePath cur_file(find_data_.cFileName);
+    if (ShouldSkip(cur_file))
+      continue;
+
+    // Construct the absolute filename.
+    cur_file = root_path_.Append(find_data_.cFileName);
+
+    if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      if (recursive_) {
+        // If |cur_file| is a directory, and we are doing recursive searching,
+        // add it to pending_paths_ so we scan it after we finish scanning this
+        // directory. However, don't do recursion through reparse points or we
+        // may end up with an infinite cycle.
+        DWORD attributes = GetFileAttributes(cur_file.value().c_str());
+        if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
+          pending_paths_.push(cur_file);
+      }
+      if (file_type_ & FileEnumerator::DIRECTORIES)
+        return cur_file;
+    } else if (file_type_ & FileEnumerator::FILES) {
+      return cur_file;
+    }
+  }
+
+  return FilePath();
+}
+
+}  // namespace base
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
new file mode 100644
index 0000000..33d5ca1
--- /dev/null
+++ b/base/files/file_path.cc
@@ -0,0 +1,1324 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+
+#include <string.h>
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+
+// These includes are just for the *Hack functions, and should be removed
+// when those functions are removed.
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_cftyperef.h"
+#include "base/third_party/icu/icu_utf.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace base {
+
+typedef FilePath::StringType StringType;
+
+namespace {
+
+const char* const kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2", "bz" };
+const char* const kCommonDoubleExtensions[] = { "user.js" };
+
+const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0');
+
+// If this FilePath contains a drive letter specification, returns the
+// position of the last character of the drive letter specification,
+// otherwise returns npos.  This can only be true on Windows, when a pathname
+// begins with a letter followed by a colon.  On other platforms, this always
+// returns npos.
+StringType::size_type FindDriveLetter(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // This is dependent on an ASCII-based character set, but that's a
+  // reasonable assumption.  iswalpha can be too inclusive here.
+  if (path.length() >= 2 && path[1] == L':' &&
+      ((path[0] >= L'A' && path[0] <= L'Z') ||
+       (path[0] >= L'a' && path[0] <= L'z'))) {
+    return 1;
+  }
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+  return StringType::npos;
+}
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+bool EqualDriveLetterCaseInsensitive(const StringType& a,
+                                     const StringType& b) {
+  size_t a_letter_pos = FindDriveLetter(a);
+  size_t b_letter_pos = FindDriveLetter(b);
+
+  if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
+    return a == b;
+
+  StringType a_letter(a.substr(0, a_letter_pos + 1));
+  StringType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, false))
+    return false;
+
+  StringType a_rest(a.substr(a_letter_pos + 1));
+  StringType b_rest(b.substr(b_letter_pos + 1));
+  return a_rest == b_rest;
+}
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+bool IsPathAbsolute(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  StringType::size_type letter = FindDriveLetter(path);
+  if (letter != StringType::npos) {
+    // Look for a separator right after the drive specification.
+    return path.length() > letter + 1 &&
+        FilePath::IsSeparator(path[letter + 1]);
+  }
+  // Look for a pair of leading separators.
+  return path.length() > 1 &&
+      FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+  // Look for a separator in the first position.
+  return path.length() > 0 && FilePath::IsSeparator(path[0]);
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+}
+
+bool AreAllSeparators(const StringType& input) {
+  for (StringType::const_iterator it = input.begin();
+      it != input.end(); ++it) {
+    if (!FilePath::IsSeparator(*it))
+      return false;
+  }
+
+  return true;
+}
+
+// Find the position of the '.' that separates the extension from the rest
+// of the file name. The position is relative to BaseName(), not value().
+// Returns npos if it can't find an extension.
+StringType::size_type FinalExtensionSeparatorPosition(const StringType& path) {
+  // Special case "." and ".."
+  if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory)
+    return StringType::npos;
+
+  return path.rfind(FilePath::kExtensionSeparator);
+}
+
+// Same as above, but allow a second extension component of up to 4
+// characters when the rightmost extension component is a common double
+// extension (gz, bz2, Z).  For example, foo.tar.gz or foo.tar.Z would have
+// extension components of '.tar.gz' and '.tar.Z' respectively.
+StringType::size_type ExtensionSeparatorPosition(const StringType& path) {
+  const StringType::size_type last_dot = FinalExtensionSeparatorPosition(path);
+
+  // No extension, or the extension is the whole filename.
+  if (last_dot == StringType::npos || last_dot == 0U)
+    return last_dot;
+
+  const StringType::size_type penultimate_dot =
+      path.rfind(FilePath::kExtensionSeparator, last_dot - 1);
+  const StringType::size_type last_separator =
+      path.find_last_of(FilePath::kSeparators, last_dot - 1,
+                        FilePath::kSeparatorsLength - 1);
+
+  if (penultimate_dot == StringType::npos ||
+      (last_separator != StringType::npos &&
+       penultimate_dot < last_separator)) {
+    return last_dot;
+  }
+
+  for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) {
+    StringType extension(path, penultimate_dot + 1);
+    if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i]))
+      return penultimate_dot;
+  }
+
+  StringType extension(path, last_dot + 1);
+  for (size_t i = 0; i < arraysize(kCommonDoubleExtensionSuffixes); ++i) {
+    if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensionSuffixes[i])) {
+      if ((last_dot - penultimate_dot) <= 5U &&
+          (last_dot - penultimate_dot) > 1U) {
+        return penultimate_dot;
+      }
+    }
+  }
+
+  return last_dot;
+}
+
+// Returns true if path is "", ".", or "..".
+bool IsEmptyOrSpecialCase(const StringType& path) {
+  // Special cases "", ".", and ".."
+  if (path.empty() || path == FilePath::kCurrentDirectory ||
+      path == FilePath::kParentDirectory) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+FilePath::FilePath() {
+}
+
+FilePath::FilePath(const FilePath& that) : path_(that.path_) {
+}
+
+FilePath::FilePath(const StringType& path) : path_(path) {
+  StringType::size_type nul_pos = path_.find(kStringTerminator);
+  if (nul_pos != StringType::npos)
+    path_.erase(nul_pos, StringType::npos);
+}
+
+FilePath::~FilePath() {
+}
+
+FilePath& FilePath::operator=(const FilePath& that) {
+  path_ = that.path_;
+  return *this;
+}
+
+bool FilePath::operator==(const FilePath& that) const {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return EqualDriveLetterCaseInsensitive(this->path_, that.path_);
+#else  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return path_ == that.path_;
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+}
+
+bool FilePath::operator!=(const FilePath& that) const {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return !EqualDriveLetterCaseInsensitive(this->path_, that.path_);
+#else  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return path_ != that.path_;
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+}
+
+// static
+bool FilePath::IsSeparator(CharType character) {
+  for (size_t i = 0; i < kSeparatorsLength - 1; ++i) {
+    if (character == kSeparators[i]) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void FilePath::GetComponents(std::vector<StringType>* components) const {
+  DCHECK(components);
+  if (!components)
+    return;
+  components->clear();
+  if (value().empty())
+    return;
+
+  std::vector<StringType> ret_val;
+  FilePath current = *this;
+  FilePath base;
+
+  // Capture path components.
+  while (current != current.DirName()) {
+    base = current.BaseName();
+    if (!AreAllSeparators(base.value()))
+      ret_val.push_back(base.value());
+    current = current.DirName();
+  }
+
+  // Capture root, if any.
+  base = current.BaseName();
+  if (!base.value().empty() && base.value() != kCurrentDirectory)
+    ret_val.push_back(current.BaseName().value());
+
+  // Capture drive letter, if any.
+  FilePath dir = current.DirName();
+  StringType::size_type letter = FindDriveLetter(dir.value());
+  if (letter != StringType::npos) {
+    ret_val.push_back(StringType(dir.value(), 0, letter + 1));
+  }
+
+  *components = std::vector<StringType>(ret_val.rbegin(), ret_val.rend());
+}
+
+bool FilePath::IsParent(const FilePath& child) const {
+  return AppendRelativePath(child, NULL);
+}
+
+bool FilePath::AppendRelativePath(const FilePath& child,
+                                  FilePath* path) const {
+  std::vector<StringType> parent_components;
+  std::vector<StringType> child_components;
+  GetComponents(&parent_components);
+  child.GetComponents(&child_components);
+
+  if (parent_components.empty() ||
+      parent_components.size() >= child_components.size())
+    return false;
+
+  std::vector<StringType>::const_iterator parent_comp =
+      parent_components.begin();
+  std::vector<StringType>::const_iterator child_comp =
+      child_components.begin();
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // Windows can access case sensitive filesystems, so component
+  // comparisions must be case sensitive, but drive letters are
+  // never case sensitive.
+  if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
+      (FindDriveLetter(*child_comp) != StringType::npos)) {
+    if (!StartsWith(*parent_comp, *child_comp, false))
+      return false;
+    ++parent_comp;
+    ++child_comp;
+  }
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+  while (parent_comp != parent_components.end()) {
+    if (*parent_comp != *child_comp)
+      return false;
+    ++parent_comp;
+    ++child_comp;
+  }
+
+  if (path != NULL) {
+    for (; child_comp != child_components.end(); ++child_comp) {
+      *path = path->Append(*child_comp);
+    }
+  }
+  return true;
+}
+
+// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
+// guaranteed to not modify their input strings, and in fact are implemented
+// differently in this regard on different platforms.  Don't use them, but
+// adhere to their behavior.
+FilePath FilePath::DirName() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // The drive letter, if any, always needs to remain in the output.  If there
+  // is no drive letter, as will always be the case on platforms which do not
+  // support drive letters, letter will be npos, or -1, so the comparisons and
+  // resizes below using letter will still be valid.
+  StringType::size_type letter = FindDriveLetter(new_path.path_);
+
+  StringType::size_type last_separator =
+      new_path.path_.find_last_of(kSeparators, StringType::npos,
+                                  kSeparatorsLength - 1);
+  if (last_separator == StringType::npos) {
+    // path_ is in the current directory.
+    new_path.path_.resize(letter + 1);
+  } else if (last_separator == letter + 1) {
+    // path_ is in the root directory.
+    new_path.path_.resize(letter + 2);
+  } else if (last_separator == letter + 2 &&
+             IsSeparator(new_path.path_[letter + 1])) {
+    // path_ is in "//" (possibly with a drive letter); leave the double
+    // separator intact indicating alternate root.
+    new_path.path_.resize(letter + 3);
+  } else if (last_separator != 0) {
+    // path_ is somewhere else, trim the basename.
+    new_path.path_.resize(last_separator);
+  }
+
+  new_path.StripTrailingSeparatorsInternal();
+  if (!new_path.path_.length())
+    new_path.path_ = kCurrentDirectory;
+
+  return new_path;
+}
+
+FilePath FilePath::BaseName() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // The drive letter, if any, is always stripped.
+  StringType::size_type letter = FindDriveLetter(new_path.path_);
+  if (letter != StringType::npos) {
+    new_path.path_.erase(0, letter + 1);
+  }
+
+  // Keep everything after the final separator, but if the pathname is only
+  // one character and it's a separator, leave it alone.
+  StringType::size_type last_separator =
+      new_path.path_.find_last_of(kSeparators, StringType::npos,
+                                  kSeparatorsLength - 1);
+  if (last_separator != StringType::npos &&
+      last_separator < new_path.path_.length() - 1) {
+    new_path.path_.erase(0, last_separator + 1);
+  }
+
+  return new_path;
+}
+
+StringType FilePath::Extension() const {
+  FilePath base(BaseName());
+  const StringType::size_type dot = ExtensionSeparatorPosition(base.path_);
+  if (dot == StringType::npos)
+    return StringType();
+
+  return base.path_.substr(dot, StringType::npos);
+}
+
+StringType FilePath::FinalExtension() const {
+  FilePath base(BaseName());
+  const StringType::size_type dot = FinalExtensionSeparatorPosition(base.path_);
+  if (dot == StringType::npos)
+    return StringType();
+
+  return base.path_.substr(dot, StringType::npos);
+}
+
+FilePath FilePath::RemoveExtension() const {
+  if (Extension().empty())
+    return *this;
+
+  const StringType::size_type dot = ExtensionSeparatorPosition(path_);
+  if (dot == StringType::npos)
+    return *this;
+
+  return FilePath(path_.substr(0, dot));
+}
+
+FilePath FilePath::RemoveFinalExtension() const {
+  if (FinalExtension().empty())
+    return *this;
+
+  const StringType::size_type dot = FinalExtensionSeparatorPosition(path_);
+  if (dot == StringType::npos)
+    return *this;
+
+  return FilePath(path_.substr(0, dot));
+}
+
+FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
+  if (suffix.empty())
+    return FilePath(path_);
+
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  StringType ext = Extension();
+  StringType ret = RemoveExtension().value();
+  ret.append(suffix);
+  ret.append(ext);
+  return FilePath(ret);
+}
+
+FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix)
+    const {
+  DCHECK(IsStringASCII(suffix));
+#if defined(OS_WIN)
+  return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
+#elif defined(OS_POSIX)
+  return InsertBeforeExtension(suffix.as_string());
+#endif
+}
+
+FilePath FilePath::AddExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  // If the new extension is "" or ".", then just return the current FilePath.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return *this;
+
+  StringType str = path_;
+  if (extension[0] != kExtensionSeparator &&
+      *(str.end() - 1) != kExtensionSeparator) {
+    str.append(1, kExtensionSeparator);
+  }
+  str.append(extension);
+  return FilePath(str);
+}
+
+FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  FilePath no_ext = RemoveExtension();
+  // If the new extension is "" or ".", then just remove the current extension.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return no_ext;
+
+  StringType str = no_ext.value();
+  if (extension[0] != kExtensionSeparator)
+    str.append(1, kExtensionSeparator);
+  str.append(extension);
+  return FilePath(str);
+}
+
+bool FilePath::MatchesExtension(const StringType& extension) const {
+  DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
+
+  StringType current_extension = Extension();
+
+  if (current_extension.length() != extension.length())
+    return false;
+
+  return FilePath::CompareEqualIgnoreCase(extension, current_extension);
+}
+
+FilePath FilePath::Append(const StringType& component) const {
+  const StringType* appended = &component;
+  StringType without_nuls;
+
+  StringType::size_type nul_pos = component.find(kStringTerminator);
+  if (nul_pos != StringType::npos) {
+    without_nuls = component.substr(0, nul_pos);
+    appended = &without_nuls;
+  }
+
+  DCHECK(!IsPathAbsolute(*appended));
+
+  if (path_.compare(kCurrentDirectory) == 0) {
+    // Append normally doesn't do any normalization, but as a special case,
+    // when appending to kCurrentDirectory, just return a new path for the
+    // component argument.  Appending component to kCurrentDirectory would
+    // serve no purpose other than needlessly lengthening the path, and
+    // it's likely in practice to wind up with FilePath objects containing
+    // only kCurrentDirectory when calling DirName on a single relative path
+    // component.
+    return FilePath(*appended);
+  }
+
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // Don't append a separator if the path is empty (indicating the current
+  // directory) or if the path component is empty (indicating nothing to
+  // append).
+  if (appended->length() > 0 && new_path.path_.length() > 0) {
+    // Don't append a separator if the path still ends with a trailing
+    // separator after stripping (indicating the root directory).
+    if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
+      // Don't append a separator if the path is just a drive letter.
+      if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
+        new_path.path_.append(1, kSeparators[0]);
+      }
+    }
+  }
+
+  new_path.path_.append(*appended);
+  return new_path;
+}
+
+FilePath FilePath::Append(const FilePath& component) const {
+  return Append(component.value());
+}
+
+FilePath FilePath::AppendASCII(const StringPiece& component) const {
+  DCHECK(base::IsStringASCII(component));
+#if defined(OS_WIN)
+  return Append(ASCIIToUTF16(component.as_string()));
+#elif defined(OS_POSIX)
+  return Append(component.as_string());
+#endif
+}
+
+bool FilePath::IsAbsolute() const {
+  return IsPathAbsolute(path_);
+}
+
+bool FilePath::EndsWithSeparator() const {
+  if (empty())
+    return false;
+  return IsSeparator(path_[path_.size() - 1]);
+}
+
+FilePath FilePath::AsEndingWithSeparator() const {
+  if (EndsWithSeparator() || path_.empty())
+    return *this;
+
+  StringType path_str;
+  path_str.reserve(path_.length() + 1);  // Only allocate string once.
+
+  path_str = path_;
+  path_str.append(&kSeparators[0], 1);
+  return FilePath(path_str);
+}
+
+FilePath FilePath::StripTrailingSeparators() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  return new_path;
+}
+
+bool FilePath::ReferencesParent() const {
+  std::vector<StringType> components;
+  GetComponents(&components);
+
+  std::vector<StringType>::const_iterator it = components.begin();
+  for (; it != components.end(); ++it) {
+    const StringType& component = *it;
+    // Windows has odd, undocumented behavior with path components containing
+    // only whitespace and . characters. So, if all we see is . and
+    // whitespace, then we treat any .. sequence as referencing parent.
+    // For simplicity we enforce this on all platforms.
+    if (component.find_first_not_of(FILE_PATH_LITERAL(". \n\r\t")) ==
+            std::string::npos &&
+        component.find(kParentDirectory) != std::string::npos) {
+      return true;
+    }
+  }
+  return false;
+}
+
+#if defined(OS_POSIX)
+// See file_path.h for a discussion of the encoding of paths on POSIX
+// platforms.  These encoding conversion functions are not quite correct.
+
+string16 FilePath::LossyDisplayName() const {
+  return WideToUTF16(SysNativeMBToWide(path_));
+}
+
+std::string FilePath::MaybeAsASCII() const {
+  if (base::IsStringASCII(path_))
+    return path_;
+  return std::string();
+}
+
+std::string FilePath::AsUTF8Unsafe() const {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return value();
+#else
+  return WideToUTF8(SysNativeMBToWide(value()));
+#endif
+}
+
+string16 FilePath::AsUTF16Unsafe() const {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return UTF8ToUTF16(value());
+#else
+  return WideToUTF16(SysNativeMBToWide(value()));
+#endif
+}
+
+// static
+FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return FilePath(utf8);
+#else
+  return FilePath(SysWideToNativeMB(UTF8ToWide(utf8)));
+#endif
+}
+
+// static
+FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return FilePath(UTF16ToUTF8(utf16));
+#else
+  return FilePath(SysWideToNativeMB(UTF16ToWide(utf16)));
+#endif
+}
+
+#elif defined(OS_WIN)
+string16 FilePath::LossyDisplayName() const {
+  return path_;
+}
+
+std::string FilePath::MaybeAsASCII() const {
+  if (base::IsStringASCII(path_))
+    return UTF16ToASCII(path_);
+  return std::string();
+}
+
+std::string FilePath::AsUTF8Unsafe() const {
+  return WideToUTF8(value());
+}
+
+string16 FilePath::AsUTF16Unsafe() const {
+  return value();
+}
+
+// static
+FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
+  return FilePath(UTF8ToWide(utf8));
+}
+
+// static
+FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
+  return FilePath(utf16);
+}
+#endif
+
+void FilePath::WriteToPickle(Pickle* pickle) const {
+#if defined(OS_WIN)
+  pickle->WriteString16(path_);
+#else
+  pickle->WriteString(path_);
+#endif
+}
+
+bool FilePath::ReadFromPickle(PickleIterator* iter) {
+#if defined(OS_WIN)
+  if (!iter->ReadString16(&path_))
+    return false;
+#else
+  if (!iter->ReadString(&path_))
+    return false;
+#endif
+
+  if (path_.find(kStringTerminator) != StringType::npos)
+    return false;
+
+  return true;
+}
+
+#if defined(OS_WIN)
+// Windows specific implementation of file string comparisons
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Perform character-wise upper case comparison rather than using the
+  // fully Unicode-aware CompareString(). For details see:
+  // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx
+  StringType::const_iterator i1 = string1.begin();
+  StringType::const_iterator i2 = string2.begin();
+  StringType::const_iterator string1end = string1.end();
+  StringType::const_iterator string2end = string2.end();
+  for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
+    wchar_t c1 =
+        (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
+    wchar_t c2 =
+        (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i2, 0)));
+    if (c1 < c2)
+      return -1;
+    if (c1 > c2)
+      return 1;
+  }
+  if (i1 != string1end)
+    return 1;
+  if (i2 != string2end)
+    return -1;
+  return 0;
+}
+
+#elif defined(OS_MACOSX)
+// Mac OS X specific implementation of file string comparisons
+
+// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+//
+// "When using CreateTextEncoding to create a text encoding, you should set
+// the TextEncodingBase to kTextEncodingUnicodeV2_0, set the
+// TextEncodingVariant to kUnicodeCanonicalDecompVariant, and set the
+// TextEncodingFormat to kUnicode16BitFormat. Using these values ensures that
+// the Unicode will be in the same form as on an HFS Plus volume, even as the
+// Unicode standard evolves."
+//
+// Another technical article for X 10.4 updates this: one should use
+// the new (unambiguous) kUnicodeHFSPlusDecompVariant.
+// cf. http://developer.apple.com/mac/library/releasenotes/TextFonts/RN-TEC/index.html
+//
+// This implementation uses CFStringGetFileSystemRepresentation() to get the
+// decomposed form, and an adapted version of the FastUnicodeCompare as
+// described in the tech note to compare the strings.
+
+// Character conversion table for FastUnicodeCompare()
+//
+// The lower case table consists of a 256-entry high-byte table followed by
+// some number of 256-entry subtables. The high-byte table contains either an
+// offset to the subtable for characters with that high byte or zero, which
+// means that there are no case mappings or ignored characters in that block.
+// Ignored characters are mapped to zero.
+//
+// cf. downloadable file linked in
+// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+
+namespace {
+
+const UInt16 lower_case_table[] = {
+  // High-byte indices ( == 0 iff no case mapping and no ignorables )
+
+  /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00,
+
+  // Table 1 (for high byte 0x00)
+
+  /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+          0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+  /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+          0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+  /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+          0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+  /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+          0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+  /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+          0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+  /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+          0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+  /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+          0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+  /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+          0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+  /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+          0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+  /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+          0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+  /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+          0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+  /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+          0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+  /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7,
+          0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+  /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+          0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+  /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+          0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+  /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+          0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+
+  // Table 2 (for high byte 0x01)
+
+  /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
+          0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+  /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117,
+          0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+  /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127,
+          0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+  /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137,
+          0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+  /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
+          0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+  /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157,
+          0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+  /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167,
+          0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+  /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177,
+          0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+  /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+          0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+  /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+          0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+  /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8,
+          0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+  /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
+          0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+  /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
+          0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+  /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7,
+          0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+  /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7,
+          0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+  /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7,
+          0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+  // Table 3 (for high byte 0x03)
+
+  /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+          0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+  /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+          0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+  /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+          0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+  /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+          0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+  /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347,
+          0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+  /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+          0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+  /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+          0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+  /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+          0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+  /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,
+          0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+  /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+          0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+  /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+          0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+  /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+          0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+  /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+          0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+  /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
+          0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+  /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
+          0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+  /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,
+          0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+  // Table 4 (for high byte 0x04)
+
+  /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407,
+          0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+  /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+          0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+  /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+          0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+  /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+          0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+  /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+          0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+  /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+          0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+  /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+          0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+  /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477,
+          0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+  /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+          0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+  /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+          0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+  /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7,
+          0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+  /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7,
+          0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+  /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8,
+          0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+  /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7,
+          0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+  /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7,
+          0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+  /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7,
+          0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+  // Table 5 (for high byte 0x05)
+
+  /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507,
+          0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+  /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+          0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+  /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+          0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+  /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+          0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+  /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+          0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+  /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+          0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+  /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+          0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+  /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+          0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+  /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
+          0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+  /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+          0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+  /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7,
+          0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+  /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+          0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+  /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7,
+          0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+  /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+          0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+  /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+          0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+  /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7,
+          0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+  // Table 6 (for high byte 0x10)
+
+  /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
+          0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+  /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
+          0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+  /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
+          0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+  /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037,
+          0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+  /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047,
+          0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+  /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057,
+          0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+  /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
+          0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+  /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077,
+          0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+  /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087,
+          0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+  /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097,
+          0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+  /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+          0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+  /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+          0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+  /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7,
+          0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+  /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+          0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+  /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+          0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+  /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7,
+          0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+  // Table 7 (for high byte 0x20)
+
+  /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
+          0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017,
+          0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+  /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027,
+          0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+  /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037,
+          0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+  /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047,
+          0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+  /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057,
+          0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+  /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067,
+          0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077,
+          0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+  /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+          0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+  /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097,
+          0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+  /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7,
+          0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+  /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7,
+          0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+  /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7,
+          0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+  /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7,
+          0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+  /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7,
+          0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+  /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7,
+          0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+  // Table 8 (for high byte 0x21)
+
+  /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+          0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+  /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+          0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+  /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127,
+          0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+  /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+          0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+  /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+          0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+  /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+          0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+  /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+          0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+  /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+          0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+  /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
+          0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+  /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+          0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+  /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7,
+          0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+  /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7,
+          0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+  /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7,
+          0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+  /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7,
+          0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+  /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7,
+          0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+  /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7,
+          0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+  // Table 9 (for high byte 0xFE)
+
+  /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07,
+          0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+  /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17,
+          0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+  /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27,
+          0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+  /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37,
+          0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+  /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47,
+          0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+  /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57,
+          0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+  /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67,
+          0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+  /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77,
+          0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+  /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87,
+          0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+  /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97,
+          0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+  /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7,
+          0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+  /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7,
+          0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+  /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7,
+          0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+  /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7,
+          0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+  /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7,
+          0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+  /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7,
+          0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+  // Table 10 (for high byte 0xFF)
+
+  /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07,
+          0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+  /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
+          0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+  /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+          0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+  /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+          0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+  /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+          0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+  /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+          0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+  /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
+          0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+  /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
+          0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+  /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
+          0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+  /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
+          0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+  /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7,
+          0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+  /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7,
+          0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+  /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7,
+          0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+  /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7,
+          0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+  /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7,
+          0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+  /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
+          0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+
+// Returns the next non-ignorable codepoint within string starting from the
+// position indicated by index, or zero if there are no more.
+// The passed-in index is automatically advanced as the characters in the input
+// HFS-decomposed UTF-8 strings are read.
+inline int HFSReadNextNonIgnorableCodepoint(const char* string,
+                                            int length,
+                                            int* index) {
+  int codepoint = 0;
+  while (*index < length && codepoint == 0) {
+    // CBU8_NEXT returns a value < 0 in error cases. For purposes of string
+    // comparison, we just use that value and flag it with DCHECK.
+    CBU8_NEXT(string, *index, length, codepoint);
+    DCHECK_GT(codepoint, 0);
+    if (codepoint > 0) {
+      // Check if there is a subtable for this upper byte.
+      int lookup_offset = lower_case_table[codepoint >> 8];
+      if (lookup_offset != 0)
+        codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)];
+      // Note: codepoint1 may be again 0 at this point if the character was
+      // an ignorable.
+    }
+  }
+  return codepoint;
+}
+
+}  // anonymous namespace
+
+// Special UTF-8 version of FastUnicodeCompare. Cf:
+// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+// The input strings must be in the special HFS decomposed form.
+int FilePath::HFSFastUnicodeCompare(const StringType& string1,
+                                    const StringType& string2) {
+  int length1 = string1.length();
+  int length2 = string2.length();
+  int index1 = 0;
+  int index2 = 0;
+
+  for (;;) {
+    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(),
+                                                      length1,
+                                                      &index1);
+    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(),
+                                                      length2,
+                                                      &index2);
+    if (codepoint1 != codepoint2)
+      return (codepoint1 < codepoint2) ? -1 : 1;
+    if (codepoint1 == 0) {
+      DCHECK_EQ(index1, length1);
+      DCHECK_EQ(index2, length2);
+      return 0;
+    }
+  }
+}
+
+StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
+  ScopedCFTypeRef<CFStringRef> cfstring(
+      CFStringCreateWithBytesNoCopy(
+          NULL,
+          reinterpret_cast<const UInt8*>(string.c_str()),
+          string.length(),
+          kCFStringEncodingUTF8,
+          false,
+          kCFAllocatorNull));
+  // Query the maximum length needed to store the result. In most cases this
+  // will overestimate the required space. The return value also already
+  // includes the space needed for a terminating 0.
+  CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstring);
+  DCHECK_GT(length, 0);  // should be at least 1 for the 0-terminator.
+  // Reserve enough space for CFStringGetFileSystemRepresentation to write into.
+  // Also set the length to the maximum so that we can shrink it later.
+  // (Increasing rather than decreasing it would clobber the string contents!)
+  StringType result;
+  result.reserve(length);
+  result.resize(length - 1);
+  Boolean success = CFStringGetFileSystemRepresentation(cfstring,
+                                                        &result[0],
+                                                        length);
+  if (success) {
+    // Reduce result.length() to actual string length.
+    result.resize(strlen(result.c_str()));
+  } else {
+    // An error occurred -> clear result.
+    result.clear();
+  }
+  return result;
+}
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Quick checks for empty strings - these speed things up a bit and make the
+  // following code cleaner.
+  if (string1.empty())
+    return string2.empty() ? 0 : -1;
+  if (string2.empty())
+    return 1;
+
+  StringType hfs1 = GetHFSDecomposedForm(string1);
+  StringType hfs2 = GetHFSDecomposedForm(string2);
+
+  // GetHFSDecomposedForm() returns an empty string in an error case.
+  if (hfs1.empty() || hfs2.empty()) {
+    NOTREACHED();
+    ScopedCFTypeRef<CFStringRef> cfstring1(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string1.c_str()),
+            string1.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    ScopedCFTypeRef<CFStringRef> cfstring2(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string2.c_str()),
+            string2.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    return CFStringCompare(cfstring1,
+                           cfstring2,
+                           kCFCompareCaseInsensitive);
+  }
+
+  return HFSFastUnicodeCompare(hfs1, hfs2);
+}
+
+#else  // << WIN. MACOSX | other (POSIX) >>
+
+// Generic (POSIX) implementation of file string comparison.
+// TODO(rolandsteiner) check if this is sufficient/correct.
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  int comparison = strcasecmp(string1.c_str(), string2.c_str());
+  if (comparison < 0)
+    return -1;
+  if (comparison > 0)
+    return 1;
+  return 0;
+}
+
+#endif  // OS versions of CompareIgnoreCase()
+
+
+void FilePath::StripTrailingSeparatorsInternal() {
+  // If there is no drive letter, start will be 1, which will prevent stripping
+  // the leading separator if there is only one separator.  If there is a drive
+  // letter, start will be set appropriately to prevent stripping the first
+  // separator following the drive letter, if a separator immediately follows
+  // the drive letter.
+  StringType::size_type start = FindDriveLetter(path_) + 2;
+
+  StringType::size_type last_stripped = StringType::npos;
+  for (StringType::size_type pos = path_.length();
+       pos > start && IsSeparator(path_[pos - 1]);
+       --pos) {
+    // If the string only has two separators and they're at the beginning,
+    // don't strip them, unless the string began with more than two separators.
+    if (pos != start + 1 || last_stripped == start + 2 ||
+        !IsSeparator(path_[start - 1])) {
+      path_.resize(pos - 1);
+      last_stripped = pos;
+    }
+  }
+}
+
+FilePath FilePath::NormalizePathSeparators() const {
+  return NormalizePathSeparatorsTo(kSeparators[0]);
+}
+
+FilePath FilePath::NormalizePathSeparatorsTo(CharType separator) const {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+  DCHECK_NE(kSeparators + kSeparatorsLength,
+            std::find(kSeparators, kSeparators + kSeparatorsLength, separator));
+  StringType copy = path_;
+  for (size_t i = 0; i < kSeparatorsLength; ++i) {
+    std::replace(copy.begin(), copy.end(), kSeparators[i], separator);
+  }
+  return FilePath(copy);
+#else
+  return *this;
+#endif
+}
+
+#if defined(OS_ANDROID)
+bool FilePath::IsContentUri() const {
+  return StartsWithASCII(path_, "content://", false /*case_sensitive*/);
+}
+#endif
+
+}  // namespace base
+
+void PrintTo(const base::FilePath& path, std::ostream* out) {
+  *out << path.value();
+}
diff --git a/base/files/file_path.h b/base/files/file_path.h
new file mode 100644
index 0000000..5225b12
--- /dev/null
+++ b/base/files/file_path.h
@@ -0,0 +1,464 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// FilePath is a container for pathnames stored in a platform's native string
+// type, providing containers for manipulation in according with the
+// platform's conventions for pathnames.  It supports the following path
+// types:
+//
+//                   POSIX            Windows
+//                   ---------------  ----------------------------------
+// Fundamental type  char[]           wchar_t[]
+// Encoding          unspecified*     UTF-16
+// Separator         /                \, tolerant of /
+// Drive letters     no               case-insensitive A-Z followed by :
+// Alternate root    // (surprise!)   \\, for UNC paths
+//
+// * The encoding need not be specified on POSIX systems, although some
+//   POSIX-compliant systems do specify an encoding.  Mac OS X uses UTF-8.
+//   Chrome OS also uses UTF-8.
+//   Linux does not specify an encoding, but in practice, the locale's
+//   character set may be used.
+//
+// For more arcane bits of path trivia, see below.
+//
+// FilePath objects are intended to be used anywhere paths are.  An
+// application may pass FilePath objects around internally, masking the
+// underlying differences between systems, only differing in implementation
+// where interfacing directly with the system.  For example, a single
+// OpenFile(const FilePath &) function may be made available, allowing all
+// callers to operate without regard to the underlying implementation.  On
+// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might
+// wrap _wfopen_s, perhaps both by calling file_path.value().c_str().  This
+// allows each platform to pass pathnames around without requiring conversions
+// between encodings, which has an impact on performance, but more imporantly,
+// has an impact on correctness on platforms that do not have well-defined
+// encodings for pathnames.
+//
+// Several methods are available to perform common operations on a FilePath
+// object, such as determining the parent directory (DirName), isolating the
+// final path component (BaseName), and appending a relative pathname string
+// to an existing FilePath object (Append).  These methods are highly
+// recommended over attempting to split and concatenate strings directly.
+// These methods are based purely on string manipulation and knowledge of
+// platform-specific pathname conventions, and do not consult the filesystem
+// at all, making them safe to use without fear of blocking on I/O operations.
+// These methods do not function as mutators but instead return distinct
+// instances of FilePath objects, and are therefore safe to use on const
+// objects.  The objects themselves are safe to share between threads.
+//
+// To aid in initialization of FilePath objects from string literals, a
+// FILE_PATH_LITERAL macro is provided, which accounts for the difference
+// between char[]-based pathnames on POSIX systems and wchar_t[]-based
+// pathnames on Windows.
+//
+// As a precaution against premature truncation, paths can't contain NULs.
+//
+// Because a FilePath object should not be instantiated at the global scope,
+// instead, use a FilePath::CharType[] and initialize it with
+// FILE_PATH_LITERAL.  At runtime, a FilePath object can be created from the
+// character array.  Example:
+//
+// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt");
+// |
+// | void Function() {
+// |   FilePath log_file_path(kLogFileName);
+// |   [...]
+// | }
+//
+// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even
+// when the UI language is RTL. This means you always need to pass filepaths
+// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the
+// RTL UI.
+//
+// This is a very common source of bugs, please try to keep this in mind.
+//
+// ARCANE BITS OF PATH TRIVIA
+//
+//  - A double leading slash is actually part of the POSIX standard.  Systems
+//    are allowed to treat // as an alternate root, as Windows does for UNC
+//    (network share) paths.  Most POSIX systems don't do anything special
+//    with two leading slashes, but FilePath handles this case properly
+//    in case it ever comes across such a system.  FilePath needs this support
+//    for Windows UNC paths, anyway.
+//    References:
+//    The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname")
+//    and 4.12 ("Pathname Resolution"), available at:
+//    http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267
+//    http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12
+//
+//  - Windows treats c:\\ the same way it treats \\.  This was intended to
+//    allow older applications that require drive letters to support UNC paths
+//    like \\server\share\path, by permitting c:\\server\share\path as an
+//    equivalent.  Since the OS treats these paths specially, FilePath needs
+//    to do the same.  Since Windows can use either / or \ as the separator,
+//    FilePath treats c://, c:\\, //, and \\ all equivalently.
+//    Reference:
+//    The Old New Thing, "Why is a drive letter permitted in front of UNC
+//    paths (sometimes)?", available at:
+//    http://blogs.msdn.com/oldnewthing/archive/2005/11/22/495740.aspx
+
+#ifndef BASE_FILES_FILE_PATH_H_
+#define BASE_FILES_FILE_PATH_H_
+
+#include <stddef.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"  // For implicit conversions.
+#include "build/build_config.h"
+
+// Windows-style drive letter support and pathname separator characters can be
+// enabled and disabled independently, to aid testing.  These #defines are
+// here so that the same setting can be used in both the implementation and
+// in the unit test.
+#if defined(OS_WIN)
+#define FILE_PATH_USES_DRIVE_LETTERS
+#define FILE_PATH_USES_WIN_SEPARATORS
+#endif  // OS_WIN
+
+class Pickle;
+class PickleIterator;
+
+namespace base {
+
+// An abstraction to isolate users from the differences between native
+// pathnames on different platforms.
+class BASE_EXPORT FilePath {
+ public:
+#if defined(OS_POSIX)
+  // On most platforms, native pathnames are char arrays, and the encoding
+  // may or may not be specified.  On Mac OS X, native pathnames are encoded
+  // in UTF-8.
+  typedef std::string StringType;
+#elif defined(OS_WIN)
+  // On Windows, for Unicode-aware applications, native pathnames are wchar_t
+  // arrays encoded in UTF-16.
+  typedef std::wstring StringType;
+#endif  // OS_WIN
+
+  typedef StringType::value_type CharType;
+
+  // Null-terminated array of separators used to separate components in
+  // hierarchical paths.  Each character in this array is a valid separator,
+  // but kSeparators[0] is treated as the canonical separator and will be used
+  // when composing pathnames.
+  static const CharType kSeparators[];
+
+  // arraysize(kSeparators).
+  static const size_t kSeparatorsLength;
+
+  // A special path component meaning "this directory."
+  static const CharType kCurrentDirectory[];
+
+  // A special path component meaning "the parent directory."
+  static const CharType kParentDirectory[];
+
+  // The character used to identify a file extension.
+  static const CharType kExtensionSeparator;
+
+  FilePath();
+  FilePath(const FilePath& that);
+  explicit FilePath(const StringType& path);
+  ~FilePath();
+  FilePath& operator=(const FilePath& that);
+
+  bool operator==(const FilePath& that) const;
+
+  bool operator!=(const FilePath& that) const;
+
+  // Required for some STL containers and operations
+  bool operator<(const FilePath& that) const {
+    return path_ < that.path_;
+  }
+
+  const StringType& value() const { return path_; }
+
+  bool empty() const { return path_.empty(); }
+
+  void clear() { path_.clear(); }
+
+  // Returns true if |character| is in kSeparators.
+  static bool IsSeparator(CharType character);
+
+  // Returns a vector of all of the components of the provided path. It is
+  // equivalent to calling DirName().value() on the path's root component,
+  // and BaseName().value() on each child component.
+  //
+  // To make sure this is lossless so we can differentiate absolute and
+  // relative paths, the root slash will be included even though no other
+  // slashes will be. The precise behavior is:
+  //
+  // Posix:  "/foo/bar"  ->  [ "/", "foo", "bar" ]
+  // Windows:  "C:\foo\bar"  ->  [ "C:", "\\", "foo", "bar" ]
+  void GetComponents(std::vector<FilePath::StringType>* components) const;
+
+  // Returns true if this FilePath is a strict parent of the |child|. Absolute
+  // and relative paths are accepted i.e. is /foo parent to /foo/bar and
+  // is foo parent to foo/bar. Does not convert paths to absolute, follow
+  // symlinks or directory navigation (e.g. ".."). A path is *NOT* its own
+  // parent.
+  bool IsParent(const FilePath& child) const;
+
+  // If IsParent(child) holds, appends to path (if non-NULL) the
+  // relative path to child and returns true.  For example, if parent
+  // holds "/Users/johndoe/Library/Application Support", child holds
+  // "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and
+  // *path holds "/Users/johndoe/Library/Caches", then after
+  // parent.AppendRelativePath(child, path) is called *path will hold
+  // "/Users/johndoe/Library/Caches/Google/Chrome/Default".  Otherwise,
+  // returns false.
+  bool AppendRelativePath(const FilePath& child, FilePath* path) const;
+
+  // Returns a FilePath corresponding to the directory containing the path
+  // named by this object, stripping away the file component.  If this object
+  // only contains one component, returns a FilePath identifying
+  // kCurrentDirectory.  If this object already refers to the root directory,
+  // returns a FilePath identifying the root directory.
+  FilePath DirName() const WARN_UNUSED_RESULT;
+
+  // Returns a FilePath corresponding to the last path component of this
+  // object, either a file or a directory.  If this object already refers to
+  // the root directory, returns a FilePath identifying the root directory;
+  // this is the only situation in which BaseName will return an absolute path.
+  FilePath BaseName() const WARN_UNUSED_RESULT;
+
+  // Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if
+  // the file has no extension.  If non-empty, Extension() will always start
+  // with precisely one ".".  The following code should always work regardless
+  // of the value of path.  For common double-extensions like .tar.gz and
+  // .user.js, this method returns the combined extension.  For a single
+  // component, use FinalExtension().
+  // new_path = path.RemoveExtension().value().append(path.Extension());
+  // ASSERT(new_path == path.value());
+  // NOTE: this is different from the original file_util implementation which
+  // returned the extension without a leading "." ("jpg" instead of ".jpg")
+  StringType Extension() const WARN_UNUSED_RESULT;
+
+  // Returns the path's file extension, as in Extension(), but will
+  // never return a double extension.
+  //
+  // TODO(davidben): Check all our extension-sensitive code to see if
+  // we can rename this to Extension() and the other to something like
+  // LongExtension(), defaulting to short extensions and leaving the
+  // long "extensions" to logic like base::GetUniquePathNumber().
+  StringType FinalExtension() const WARN_UNUSED_RESULT;
+
+  // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
+  // NOTE: this is slightly different from the similar file_util implementation
+  // which returned simply 'jojo'.
+  FilePath RemoveExtension() const WARN_UNUSED_RESULT;
+
+  // Removes the path's file extension, as in RemoveExtension(), but
+  // ignores double extensions.
+  FilePath RemoveFinalExtension() const WARN_UNUSED_RESULT;
+
+  // Inserts |suffix| after the file name portion of |path| but before the
+  // extension.  Returns "" if BaseName() == "." or "..".
+  // Examples:
+  // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg"
+  // path == "jojo.jpg"         suffix == " (1)", returns "jojo (1).jpg"
+  // path == "C:\pics\jojo"     suffix == " (1)", returns "C:\pics\jojo (1)"
+  // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
+  FilePath InsertBeforeExtension(
+      const StringType& suffix) const WARN_UNUSED_RESULT;
+  FilePath InsertBeforeExtensionASCII(
+      const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
+
+  // Adds |extension| to |file_name|. Returns the current FilePath if
+  // |extension| is empty. Returns "" if BaseName() == "." or "..".
+  FilePath AddExtension(
+      const StringType& extension) const WARN_UNUSED_RESULT;
+
+  // Replaces the extension of |file_name| with |extension|.  If |file_name|
+  // does not have an extension, then |extension| is added.  If |extension| is
+  // empty, then the extension is removed from |file_name|.
+  // Returns "" if BaseName() == "." or "..".
+  FilePath ReplaceExtension(
+      const StringType& extension) const WARN_UNUSED_RESULT;
+
+  // Returns true if the file path matches the specified extension. The test is
+  // case insensitive. Don't forget the leading period if appropriate.
+  bool MatchesExtension(const StringType& extension) const;
+
+  // Returns a FilePath by appending a separator and the supplied path
+  // component to this object's path.  Append takes care to avoid adding
+  // excessive separators if this object's path already ends with a separator.
+  // If this object's path is kCurrentDirectory, a new FilePath corresponding
+  // only to |component| is returned.  |component| must be a relative path;
+  // it is an error to pass an absolute path.
+  FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
+  FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
+
+  // Although Windows StringType is std::wstring, since the encoding it uses for
+  // paths is well defined, it can handle ASCII path components as well.
+  // Mac uses UTF8, and since ASCII is a subset of that, it works there as well.
+  // On Linux, although it can use any 8-bit encoding for paths, we assume that
+  // ASCII is a valid subset, regardless of the encoding, since many operating
+  // system paths will always be ASCII.
+  FilePath AppendASCII(const base::StringPiece& component)
+      const WARN_UNUSED_RESULT;
+
+  // Returns true if this FilePath contains an absolute path.  On Windows, an
+  // absolute path begins with either a drive letter specification followed by
+  // a separator character, or with two separator characters.  On POSIX
+  // platforms, an absolute path begins with a separator character.
+  bool IsAbsolute() const;
+
+  // Returns true if the patch ends with a path separator character.
+  bool EndsWithSeparator() const WARN_UNUSED_RESULT;
+
+  // Returns a copy of this FilePath that ends with a trailing separator. If
+  // the input path is empty, an empty FilePath will be returned.
+  FilePath AsEndingWithSeparator() const WARN_UNUSED_RESULT;
+
+  // Returns a copy of this FilePath that does not end with a trailing
+  // separator.
+  FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT;
+
+  // Returns true if this FilePath contains an attempt to reference a parent
+  // directory (e.g. has a path component that is "..").
+  bool ReferencesParent() const;
+
+  // Return a Unicode human-readable version of this path.
+  // Warning: you can *not*, in general, go from a display name back to a real
+  // path.  Only use this when displaying paths to users, not just when you
+  // want to stuff a string16 into some other API.
+  string16 LossyDisplayName() const;
+
+  // Return the path as ASCII, or the empty string if the path is not ASCII.
+  // This should only be used for cases where the FilePath is representing a
+  // known-ASCII filename.
+  std::string MaybeAsASCII() const;
+
+  // Return the path as UTF-8.
+  //
+  // This function is *unsafe* as there is no way to tell what encoding is
+  // used in file names on POSIX systems other than Mac and Chrome OS,
+  // although UTF-8 is practically used everywhere these days. To mitigate
+  // the encoding issue, this function internally calls
+  // SysNativeMBToWide() on POSIX systems other than Mac and Chrome OS,
+  // per assumption that the current locale's encoding is used in file
+  // names, but this isn't a perfect solution.
+  //
+  // Once it becomes safe to to stop caring about non-UTF-8 file names,
+  // the SysNativeMBToWide() hack will be removed from the code, along
+  // with "Unsafe" in the function name.
+  std::string AsUTF8Unsafe() const;
+
+  // Similar to AsUTF8Unsafe, but returns UTF-16 instead.
+  string16 AsUTF16Unsafe() const;
+
+  // Returns a FilePath object from a path name in UTF-8. This function
+  // should only be used for cases where you are sure that the input
+  // string is UTF-8.
+  //
+  // Like AsUTF8Unsafe(), this function is unsafe. This function
+  // internally calls SysWideToNativeMB() on POSIX systems other than Mac
+  // and Chrome OS, to mitigate the encoding issue. See the comment at
+  // AsUTF8Unsafe() for details.
+  static FilePath FromUTF8Unsafe(const std::string& utf8);
+
+  // Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
+  static FilePath FromUTF16Unsafe(const string16& utf16);
+
+  void WriteToPickle(Pickle* pickle) const;
+  bool ReadFromPickle(PickleIterator* iter);
+
+  // Normalize all path separators to backslash on Windows
+  // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+  FilePath NormalizePathSeparators() const;
+
+  // Normalize all path separattors to given type on Windows
+  // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+  FilePath NormalizePathSeparatorsTo(CharType separator) const;
+
+  // Compare two strings in the same way the file system does.
+  // Note that these always ignore case, even on file systems that are case-
+  // sensitive. If case-sensitive comparison is ever needed, add corresponding
+  // methods here.
+  // The methods are written as a static method so that they can also be used
+  // on parts of a file path, e.g., just the extension.
+  // CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
+  // greater-than respectively.
+  static int CompareIgnoreCase(const StringType& string1,
+                               const StringType& string2);
+  static bool CompareEqualIgnoreCase(const StringType& string1,
+                                     const StringType& string2) {
+    return CompareIgnoreCase(string1, string2) == 0;
+  }
+  static bool CompareLessIgnoreCase(const StringType& string1,
+                                    const StringType& string2) {
+    return CompareIgnoreCase(string1, string2) < 0;
+  }
+
+#if defined(OS_MACOSX)
+  // Returns the string in the special canonical decomposed form as defined for
+  // HFS, which is close to, but not quite, decomposition form D. See
+  // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+  // for further comments.
+  // Returns the epmty string if the conversion failed.
+  static StringType GetHFSDecomposedForm(const FilePath::StringType& string);
+
+  // Special UTF-8 version of FastUnicodeCompare. Cf:
+  // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+  // IMPORTANT: The input strings must be in the special HFS decomposed form!
+  // (cf. above GetHFSDecomposedForm method)
+  static int HFSFastUnicodeCompare(const StringType& string1,
+                                   const StringType& string2);
+#endif
+
+#if defined(OS_ANDROID)
+  // On android, file selection dialog can return a file with content uri
+  // scheme(starting with content://). Content uri needs to be opened with
+  // ContentResolver to guarantee that the app has appropriate permissions
+  // to access it.
+  // Returns true if the path is a content uri, or false otherwise.
+  bool IsContentUri() const;
+#endif
+
+ private:
+  // Remove trailing separators from this object.  If the path is absolute, it
+  // will never be stripped any more than to refer to the absolute root
+  // directory, so "////" will become "/", not "".  A leading pair of
+  // separators is never stripped, to support alternate roots.  This is used to
+  // support UNC paths on Windows.
+  void StripTrailingSeparatorsInternal();
+
+  StringType path_;
+};
+
+}  // namespace base
+
+// This is required by googletest to print a readable output on test failures.
+BASE_EXPORT extern void PrintTo(const base::FilePath& path, std::ostream* out);
+
+// Macros for string literal initialization of FilePath::CharType[], and for
+// using a FilePath::CharType[] in a printf-style format string.
+#if defined(OS_POSIX)
+#define FILE_PATH_LITERAL(x) x
+#define PRFilePath "s"
+#elif defined(OS_WIN)
+#define FILE_PATH_LITERAL(x) L ## x
+#define PRFilePath "ls"
+#endif  // OS_WIN
+
+// Provide a hash function so that hash_sets and maps can contain FilePath
+// objects.
+namespace BASE_HASH_NAMESPACE {
+
+template<>
+struct hash<base::FilePath> {
+  size_t operator()(const base::FilePath& f) const {
+    return hash<base::FilePath::StringType>()(f.value());
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_FILES_FILE_PATH_H_
diff --git a/base/files/file_path_constants.cc b/base/files/file_path_constants.cc
new file mode 100644
index 0000000..34b17a6
--- /dev/null
+++ b/base/files/file_path_constants.cc
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+
+namespace base {
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
+#else  // FILE_PATH_USES_WIN_SEPARATORS
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+
+const size_t FilePath::kSeparatorsLength = arraysize(kSeparators);
+
+const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
+const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
+
+const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
+
+}  // namespace base
diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc
new file mode 100644
index 0000000..c162938
--- /dev/null
+++ b/base/files/file_path_unittest.cc
@@ -0,0 +1,1276 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/files/file_path.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// This macro helps avoid wrapped lines in the test structs.
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+// This macro constructs strings which can contain NULs.
+#define FPS(x) FilePath::StringType(FPL(x), arraysize(FPL(x)) - 1)
+
+namespace base {
+
+struct UnaryTestData {
+  const FilePath::CharType* input;
+  const FilePath::CharType* expected;
+};
+
+struct UnaryBooleanTestData {
+  const FilePath::CharType* input;
+  bool expected;
+};
+
+struct BinaryTestData {
+  const FilePath::CharType* inputs[2];
+  const FilePath::CharType* expected;
+};
+
+struct BinaryBooleanTestData {
+  const FilePath::CharType* inputs[2];
+  bool expected;
+};
+
+struct BinaryIntTestData {
+  const FilePath::CharType* inputs[2];
+  int expected;
+};
+
+struct UTF8TestData {
+  const FilePath::CharType* native;
+  const char* utf8;
+};
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+typedef PlatformTest FilePathTest;
+
+TEST_F(FilePathTest, DirName) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),              FPL(".") },
+    { FPL("aa"),            FPL(".") },
+    { FPL("/aa/bb"),        FPL("/aa") },
+    { FPL("/aa/bb/"),       FPL("/aa") },
+    { FPL("/aa/bb//"),      FPL("/aa") },
+    { FPL("/aa/bb/ccc"),    FPL("/aa/bb") },
+    { FPL("/aa"),           FPL("/") },
+    { FPL("/aa/"),          FPL("/") },
+    { FPL("/"),             FPL("/") },
+    { FPL("//"),            FPL("//") },
+    { FPL("///"),           FPL("/") },
+    { FPL("aa/"),           FPL(".") },
+    { FPL("aa/bb"),         FPL("aa") },
+    { FPL("aa/bb/"),        FPL("aa") },
+    { FPL("aa/bb//"),       FPL("aa") },
+    { FPL("aa//bb//"),      FPL("aa") },
+    { FPL("aa//bb/"),       FPL("aa") },
+    { FPL("aa//bb"),        FPL("aa") },
+    { FPL("//aa/bb"),       FPL("//aa") },
+    { FPL("//aa/"),         FPL("//") },
+    { FPL("//aa"),          FPL("//") },
+    { FPL("0:"),            FPL(".") },
+    { FPL("@:"),            FPL(".") },
+    { FPL("[:"),            FPL(".") },
+    { FPL("`:"),            FPL(".") },
+    { FPL("{:"),            FPL(".") },
+    { FPL("\xB3:"),         FPL(".") },
+    { FPL("\xC5:"),         FPL(".") },
+#if defined(OS_WIN)
+    { FPL("\x0143:"),       FPL(".") },
+#endif  // OS_WIN
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:"),            FPL("c:") },
+    { FPL("C:"),            FPL("C:") },
+    { FPL("A:"),            FPL("A:") },
+    { FPL("Z:"),            FPL("Z:") },
+    { FPL("a:"),            FPL("a:") },
+    { FPL("z:"),            FPL("z:") },
+    { FPL("c:aa"),          FPL("c:") },
+    { FPL("c:/"),           FPL("c:/") },
+    { FPL("c://"),          FPL("c://") },
+    { FPL("c:///"),         FPL("c:/") },
+    { FPL("c:/aa"),         FPL("c:/") },
+    { FPL("c:/aa/"),        FPL("c:/") },
+    { FPL("c:/aa/bb"),      FPL("c:/aa") },
+    { FPL("c:aa/bb"),       FPL("c:aa") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("\\aa\\bb"),      FPL("\\aa") },
+    { FPL("\\aa\\bb\\"),    FPL("\\aa") },
+    { FPL("\\aa\\bb\\\\"),  FPL("\\aa") },
+    { FPL("\\aa\\bb\\ccc"), FPL("\\aa\\bb") },
+    { FPL("\\aa"),          FPL("\\") },
+    { FPL("\\aa\\"),        FPL("\\") },
+    { FPL("\\"),            FPL("\\") },
+    { FPL("\\\\"),          FPL("\\\\") },
+    { FPL("\\\\\\"),        FPL("\\") },
+    { FPL("aa\\"),          FPL(".") },
+    { FPL("aa\\bb"),        FPL("aa") },
+    { FPL("aa\\bb\\"),      FPL("aa") },
+    { FPL("aa\\bb\\\\"),    FPL("aa") },
+    { FPL("aa\\\\bb\\\\"),  FPL("aa") },
+    { FPL("aa\\\\bb\\"),    FPL("aa") },
+    { FPL("aa\\\\bb"),      FPL("aa") },
+    { FPL("\\\\aa\\bb"),    FPL("\\\\aa") },
+    { FPL("\\\\aa\\"),      FPL("\\\\") },
+    { FPL("\\\\aa"),        FPL("\\\\") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:\\"),          FPL("c:\\") },
+    { FPL("c:\\\\"),        FPL("c:\\\\") },
+    { FPL("c:\\\\\\"),      FPL("c:\\") },
+    { FPL("c:\\aa"),        FPL("c:\\") },
+    { FPL("c:\\aa\\"),      FPL("c:\\") },
+    { FPL("c:\\aa\\bb"),    FPL("c:\\aa") },
+    { FPL("c:aa\\bb"),      FPL("c:aa") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.DirName();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, BaseName) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),              FPL("") },
+    { FPL("aa"),            FPL("aa") },
+    { FPL("/aa/bb"),        FPL("bb") },
+    { FPL("/aa/bb/"),       FPL("bb") },
+    { FPL("/aa/bb//"),      FPL("bb") },
+    { FPL("/aa/bb/ccc"),    FPL("ccc") },
+    { FPL("/aa"),           FPL("aa") },
+    { FPL("/"),             FPL("/") },
+    { FPL("//"),            FPL("//") },
+    { FPL("///"),           FPL("/") },
+    { FPL("aa/"),           FPL("aa") },
+    { FPL("aa/bb"),         FPL("bb") },
+    { FPL("aa/bb/"),        FPL("bb") },
+    { FPL("aa/bb//"),       FPL("bb") },
+    { FPL("aa//bb//"),      FPL("bb") },
+    { FPL("aa//bb/"),       FPL("bb") },
+    { FPL("aa//bb"),        FPL("bb") },
+    { FPL("//aa/bb"),       FPL("bb") },
+    { FPL("//aa/"),         FPL("aa") },
+    { FPL("//aa"),          FPL("aa") },
+    { FPL("0:"),            FPL("0:") },
+    { FPL("@:"),            FPL("@:") },
+    { FPL("[:"),            FPL("[:") },
+    { FPL("`:"),            FPL("`:") },
+    { FPL("{:"),            FPL("{:") },
+    { FPL("\xB3:"),         FPL("\xB3:") },
+    { FPL("\xC5:"),         FPL("\xC5:") },
+#if defined(OS_WIN)
+    { FPL("\x0143:"),       FPL("\x0143:") },
+#endif  // OS_WIN
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:"),            FPL("") },
+    { FPL("C:"),            FPL("") },
+    { FPL("A:"),            FPL("") },
+    { FPL("Z:"),            FPL("") },
+    { FPL("a:"),            FPL("") },
+    { FPL("z:"),            FPL("") },
+    { FPL("c:aa"),          FPL("aa") },
+    { FPL("c:/"),           FPL("/") },
+    { FPL("c://"),          FPL("//") },
+    { FPL("c:///"),         FPL("/") },
+    { FPL("c:/aa"),         FPL("aa") },
+    { FPL("c:/aa/"),        FPL("aa") },
+    { FPL("c:/aa/bb"),      FPL("bb") },
+    { FPL("c:aa/bb"),       FPL("bb") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("\\aa\\bb"),      FPL("bb") },
+    { FPL("\\aa\\bb\\"),    FPL("bb") },
+    { FPL("\\aa\\bb\\\\"),  FPL("bb") },
+    { FPL("\\aa\\bb\\ccc"), FPL("ccc") },
+    { FPL("\\aa"),          FPL("aa") },
+    { FPL("\\"),            FPL("\\") },
+    { FPL("\\\\"),          FPL("\\\\") },
+    { FPL("\\\\\\"),        FPL("\\") },
+    { FPL("aa\\"),          FPL("aa") },
+    { FPL("aa\\bb"),        FPL("bb") },
+    { FPL("aa\\bb\\"),      FPL("bb") },
+    { FPL("aa\\bb\\\\"),    FPL("bb") },
+    { FPL("aa\\\\bb\\\\"),  FPL("bb") },
+    { FPL("aa\\\\bb\\"),    FPL("bb") },
+    { FPL("aa\\\\bb"),      FPL("bb") },
+    { FPL("\\\\aa\\bb"),    FPL("bb") },
+    { FPL("\\\\aa\\"),      FPL("aa") },
+    { FPL("\\\\aa"),        FPL("aa") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:\\"),          FPL("\\") },
+    { FPL("c:\\\\"),        FPL("\\\\") },
+    { FPL("c:\\\\\\"),      FPL("\\") },
+    { FPL("c:\\aa"),        FPL("aa") },
+    { FPL("c:\\aa\\"),      FPL("aa") },
+    { FPL("c:\\aa\\bb"),    FPL("bb") },
+    { FPL("c:aa\\bb"),      FPL("bb") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.BaseName();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, Append) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),           FPL("cc") }, FPL("cc") },
+    { { FPL("."),          FPL("ff") }, FPL("ff") },
+    { { FPL("/"),          FPL("cc") }, FPL("/cc") },
+    { { FPL("/aa"),        FPL("") },   FPL("/aa") },
+    { { FPL("/aa/"),       FPL("") },   FPL("/aa") },
+    { { FPL("//aa"),       FPL("") },   FPL("//aa") },
+    { { FPL("//aa/"),      FPL("") },   FPL("//aa") },
+    { { FPL("//"),         FPL("aa") }, FPL("//aa") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:"),         FPL("a") },  FPL("c:a") },
+    { { FPL("c:"),         FPL("") },   FPL("c:") },
+    { { FPL("c:/"),        FPL("a") },  FPL("c:/a") },
+    { { FPL("c://"),       FPL("a") },  FPL("c://a") },
+    { { FPL("c:///"),      FPL("a") },  FPL("c:/a") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    // Append introduces the default separator character, so these test cases
+    // need to be defined with different expected results on platforms that use
+    // different default separator characters.
+    { { FPL("\\"),         FPL("cc") }, FPL("\\cc") },
+    { { FPL("\\aa"),       FPL("") },   FPL("\\aa") },
+    { { FPL("\\aa\\"),     FPL("") },   FPL("\\aa") },
+    { { FPL("\\\\aa"),     FPL("") },   FPL("\\\\aa") },
+    { { FPL("\\\\aa\\"),   FPL("") },   FPL("\\\\aa") },
+    { { FPL("\\\\"),       FPL("aa") }, FPL("\\\\aa") },
+    { { FPL("/aa/bb"),     FPL("cc") }, FPL("/aa/bb\\cc") },
+    { { FPL("/aa/bb/"),    FPL("cc") }, FPL("/aa/bb\\cc") },
+    { { FPL("aa/bb/"),     FPL("cc") }, FPL("aa/bb\\cc") },
+    { { FPL("aa/bb"),      FPL("cc") }, FPL("aa/bb\\cc") },
+    { { FPL("a/b"),        FPL("c") },  FPL("a/b\\c") },
+    { { FPL("a/b/"),       FPL("c") },  FPL("a/b\\c") },
+    { { FPL("//aa"),       FPL("bb") }, FPL("//aa\\bb") },
+    { { FPL("//aa/"),      FPL("bb") }, FPL("//aa\\bb") },
+    { { FPL("\\aa\\bb"),   FPL("cc") }, FPL("\\aa\\bb\\cc") },
+    { { FPL("\\aa\\bb\\"), FPL("cc") }, FPL("\\aa\\bb\\cc") },
+    { { FPL("aa\\bb\\"),   FPL("cc") }, FPL("aa\\bb\\cc") },
+    { { FPL("aa\\bb"),     FPL("cc") }, FPL("aa\\bb\\cc") },
+    { { FPL("a\\b"),       FPL("c") },  FPL("a\\b\\c") },
+    { { FPL("a\\b\\"),     FPL("c") },  FPL("a\\b\\c") },
+    { { FPL("\\\\aa"),     FPL("bb") }, FPL("\\\\aa\\bb") },
+    { { FPL("\\\\aa\\"),   FPL("bb") }, FPL("\\\\aa\\bb") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:\\"),       FPL("a") },  FPL("c:\\a") },
+    { { FPL("c:\\\\"),     FPL("a") },  FPL("c:\\\\a") },
+    { { FPL("c:\\\\\\"),   FPL("a") },  FPL("c:\\a") },
+    { { FPL("c:\\"),       FPL("") },   FPL("c:\\") },
+    { { FPL("c:\\a"),      FPL("b") },  FPL("c:\\a\\b") },
+    { { FPL("c:\\a\\"),    FPL("b") },  FPL("c:\\a\\b") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#else  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("/aa/bb"),     FPL("cc") }, FPL("/aa/bb/cc") },
+    { { FPL("/aa/bb/"),    FPL("cc") }, FPL("/aa/bb/cc") },
+    { { FPL("aa/bb/"),     FPL("cc") }, FPL("aa/bb/cc") },
+    { { FPL("aa/bb"),      FPL("cc") }, FPL("aa/bb/cc") },
+    { { FPL("a/b"),        FPL("c") },  FPL("a/b/c") },
+    { { FPL("a/b/"),       FPL("c") },  FPL("a/b/c") },
+    { { FPL("//aa"),       FPL("bb") }, FPL("//aa/bb") },
+    { { FPL("//aa/"),      FPL("bb") }, FPL("//aa/bb") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/"),        FPL("a") },  FPL("c:/a") },
+    { { FPL("c:/"),        FPL("") },   FPL("c:/") },
+    { { FPL("c:/a"),       FPL("b") },  FPL("c:/a/b") },
+    { { FPL("c:/a/"),      FPL("b") },  FPL("c:/a/b") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath root(cases[i].inputs[0]);
+    FilePath::StringType leaf(cases[i].inputs[1]);
+    FilePath observed_str = root.Append(leaf);
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) <<
+              "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
+    FilePath observed_path = root.Append(FilePath(leaf));
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_path.value()) <<
+              "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
+
+    // TODO(erikkay): It would be nice to have a unicode test append value to
+    // handle the case when AppendASCII is passed UTF8
+#if defined(OS_WIN)
+    std::string ascii = WideToUTF8(leaf);
+#elif defined(OS_POSIX)
+    std::string ascii = leaf;
+#endif
+    observed_str = root.AppendASCII(ascii);
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) <<
+              "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
+  }
+}
+
+TEST_F(FilePathTest, StripTrailingSeparators) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),              FPL("") },
+    { FPL("/"),             FPL("/") },
+    { FPL("//"),            FPL("//") },
+    { FPL("///"),           FPL("/") },
+    { FPL("////"),          FPL("/") },
+    { FPL("a/"),            FPL("a") },
+    { FPL("a//"),           FPL("a") },
+    { FPL("a///"),          FPL("a") },
+    { FPL("a////"),         FPL("a") },
+    { FPL("/a"),            FPL("/a") },
+    { FPL("/a/"),           FPL("/a") },
+    { FPL("/a//"),          FPL("/a") },
+    { FPL("/a///"),         FPL("/a") },
+    { FPL("/a////"),        FPL("/a") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:"),            FPL("c:") },
+    { FPL("c:/"),           FPL("c:/") },
+    { FPL("c://"),          FPL("c://") },
+    { FPL("c:///"),         FPL("c:/") },
+    { FPL("c:////"),        FPL("c:/") },
+    { FPL("c:/a"),          FPL("c:/a") },
+    { FPL("c:/a/"),         FPL("c:/a") },
+    { FPL("c:/a//"),        FPL("c:/a") },
+    { FPL("c:/a///"),       FPL("c:/a") },
+    { FPL("c:/a////"),      FPL("c:/a") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("\\"),            FPL("\\") },
+    { FPL("\\\\"),          FPL("\\\\") },
+    { FPL("\\\\\\"),        FPL("\\") },
+    { FPL("\\\\\\\\"),      FPL("\\") },
+    { FPL("a\\"),           FPL("a") },
+    { FPL("a\\\\"),         FPL("a") },
+    { FPL("a\\\\\\"),       FPL("a") },
+    { FPL("a\\\\\\\\"),     FPL("a") },
+    { FPL("\\a"),           FPL("\\a") },
+    { FPL("\\a\\"),         FPL("\\a") },
+    { FPL("\\a\\\\"),       FPL("\\a") },
+    { FPL("\\a\\\\\\"),     FPL("\\a") },
+    { FPL("\\a\\\\\\\\"),   FPL("\\a") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:\\"),          FPL("c:\\") },
+    { FPL("c:\\\\"),        FPL("c:\\\\") },
+    { FPL("c:\\\\\\"),      FPL("c:\\") },
+    { FPL("c:\\\\\\\\"),    FPL("c:\\") },
+    { FPL("c:\\a"),         FPL("c:\\a") },
+    { FPL("c:\\a\\"),       FPL("c:\\a") },
+    { FPL("c:\\a\\\\"),     FPL("c:\\a") },
+    { FPL("c:\\a\\\\\\"),   FPL("c:\\a") },
+    { FPL("c:\\a\\\\\\\\"), FPL("c:\\a") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.StripTrailingSeparators();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, IsAbsolute) {
+  const struct UnaryBooleanTestData cases[] = {
+    { FPL(""),       false },
+    { FPL("a"),      false },
+    { FPL("c:"),     false },
+    { FPL("c:a"),    false },
+    { FPL("a/b"),    false },
+    { FPL("//"),     true },
+    { FPL("//a"),    true },
+    { FPL("c:a/b"),  false },
+    { FPL("?:/a"),   false },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("/"),      false },
+    { FPL("/a"),     false },
+    { FPL("/."),     false },
+    { FPL("/.."),    false },
+    { FPL("c:/"),    true },
+    { FPL("c:/a"),   true },
+    { FPL("c:/."),   true },
+    { FPL("c:/.."),  true },
+    { FPL("C:/a"),   true },
+    { FPL("d:/a"),   true },
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+    { FPL("/"),      true },
+    { FPL("/a"),     true },
+    { FPL("/."),     true },
+    { FPL("/.."),    true },
+    { FPL("c:/"),    false },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("a\\b"),   false },
+    { FPL("\\\\"),   true },
+    { FPL("\\\\a"),  true },
+    { FPL("a\\b"),   false },
+    { FPL("\\\\"),   true },
+    { FPL("//a"),    true },
+    { FPL("c:a\\b"), false },
+    { FPL("?:\\a"),  false },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("\\"),     false },
+    { FPL("\\a"),    false },
+    { FPL("\\."),    false },
+    { FPL("\\.."),   false },
+    { FPL("c:\\"),   true },
+    { FPL("c:\\"),   true },
+    { FPL("c:\\a"),  true },
+    { FPL("c:\\."),  true },
+    { FPL("c:\\.."), true },
+    { FPL("C:\\a"),  true },
+    { FPL("d:\\a"),  true },
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+    { FPL("\\"),     true },
+    { FPL("\\a"),    true },
+    { FPL("\\."),    true },
+    { FPL("\\.."),   true },
+    { FPL("c:\\"),   false },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.IsAbsolute();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, PathComponentsTest) {
+  const struct UnaryTestData cases[] = {
+    { FPL("//foo/bar/baz/"),          FPL("|//|foo|bar|baz")},
+    { FPL("///"),                     FPL("|/")},
+    { FPL("/foo//bar//baz/"),         FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz/"),           FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz//"),          FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz///"),         FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz"),            FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar.bot/baz.txt"),    FPL("|/|foo|bar.bot|baz.txt")},
+    { FPL("//foo//bar/baz"),          FPL("|//|foo|bar|baz")},
+    { FPL("/"),                       FPL("|/")},
+    { FPL("foo"),                     FPL("|foo")},
+    { FPL(""),                        FPL("")},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("e:/foo"),                  FPL("|e:|/|foo")},
+    { FPL("e:/"),                     FPL("|e:|/")},
+    { FPL("e:"),                      FPL("|e:")},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("../foo"),                  FPL("|..|foo")},
+    { FPL("./foo"),                   FPL("|foo")},
+    { FPL("../foo/bar/"),             FPL("|..|foo|bar") },
+    { FPL("\\\\foo\\bar\\baz\\"),     FPL("|\\\\|foo|bar|baz")},
+    { FPL("\\\\\\"),                  FPL("|\\")},
+    { FPL("\\foo\\\\bar\\\\baz\\"),   FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz\\"),       FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz\\\\"),     FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz\\\\\\"),   FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz"),         FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar/baz\\\\\\"),    FPL("|\\|foo|bar|baz")},
+    { FPL("/foo\\bar\\baz"),          FPL("|/|foo|bar|baz")},
+    { FPL("\\foo\\bar.bot\\baz.txt"), FPL("|\\|foo|bar.bot|baz.txt")},
+    { FPL("\\\\foo\\\\bar\\baz"),     FPL("|\\\\|foo|bar|baz")},
+    { FPL("\\"),                      FPL("|\\")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    std::vector<FilePath::StringType> comps;
+    input.GetComponents(&comps);
+
+    FilePath::StringType observed;
+    for (size_t j = 0; j < comps.size(); ++j) {
+      observed.append(FILE_PATH_LITERAL("|"), 1);
+      observed.append(comps[j]);
+    }
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, IsParentTest) {
+  const struct BinaryBooleanTestData cases[] = {
+    { { FPL("/"),             FPL("/foo/bar/baz") },      true},
+    { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      true},
+    { { FPL("/foo/bar/"),     FPL("/foo/bar/baz") },      true},
+    { { FPL("//foo/bar/"),    FPL("//foo/bar/baz") },     true},
+    { { FPL("/foo/bar"),      FPL("/foo2/bar/baz") },     false},
+    { { FPL("/foo/bar.txt"),  FPL("/foo/bar/baz") },      false},
+    { { FPL("/foo/bar"),      FPL("/foo/bar2/baz") },     false},
+    { { FPL("/foo/bar"),      FPL("/foo/bar") },          false},
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          false},
+    { { FPL("foo/bar"),       FPL("foo/bar/baz") },       true},
+    { { FPL("foo/bar"),       FPL("foo2/bar/baz") },      false},
+    { { FPL("foo/bar"),       FPL("foo/bar2/baz") },      false},
+    { { FPL(""),              FPL("foo") },               false},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar/baz") },    true},
+    { { FPL("E:/foo/bar"),    FPL("e:/foo/bar/baz") },    true},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/bar/baz") },    true},
+    { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar/baz") },    false},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar/baz") },    false},
+    { { FPL("c:/"),           FPL("c:/foo/bar/baz") },    true},
+    { { FPL("c:"),            FPL("c:/foo/bar/baz") },    true},
+    { { FPL("c:/foo/bar"),    FPL("d:/foo/bar/baz") },    false},
+    { { FPL("c:/foo/bar"),    FPL("D:/foo/bar/baz") },    false},
+    { { FPL("C:/foo/bar"),    FPL("d:/foo/bar/baz") },    false},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar/baz") },   false},
+    { { FPL("e:/foo/bar"),    FPL("E:/foo2/bar/baz") },   false},
+    { { FPL("F:/foo/bar"),    FPL("f:/foo2/bar/baz") },   false},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar2/baz") },   false},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar\\baz") },   true},
+    { { FPL("\\foo/bar"),     FPL("\\foo\\bar\\baz") },   true},
+    { { FPL("\\foo/bar"),     FPL("\\foo/bar/baz") },     true},
+    { { FPL("\\"),            FPL("\\foo\\bar\\baz") },   true},
+    { { FPL(""),              FPL("\\foo\\bar\\baz") },   false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar\\baz") },  false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2\\baz") },  false},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath parent(cases[i].inputs[0]);
+    FilePath child(cases[i].inputs[1]);
+
+    EXPECT_EQ(parent.IsParent(child), cases[i].expected) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+  }
+}
+
+TEST_F(FilePathTest, AppendRelativePathTest) {
+  const struct BinaryTestData cases[] = {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("/"),             FPL("/foo/bar/baz") },      FPL("foo\\bar\\baz")},
+#else  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("/"),             FPL("/foo/bar/baz") },      FPL("foo/bar/baz")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      FPL("baz")},
+    { { FPL("/foo/bar/"),     FPL("/foo/bar/baz") },      FPL("baz")},
+    { { FPL("//foo/bar/"),    FPL("//foo/bar/baz") },     FPL("baz")},
+    { { FPL("/foo/bar"),      FPL("/foo2/bar/baz") },     FPL("")},
+    { { FPL("/foo/bar.txt"),  FPL("/foo/bar/baz") },      FPL("")},
+    { { FPL("/foo/bar"),      FPL("/foo/bar2/baz") },     FPL("")},
+    { { FPL("/foo/bar"),      FPL("/foo/bar") },          FPL("")},
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          FPL("")},
+    { { FPL("foo/bar"),       FPL("foo/bar/baz") },       FPL("baz")},
+    { { FPL("foo/bar"),       FPL("foo2/bar/baz") },      FPL("")},
+    { { FPL("foo/bar"),       FPL("foo/bar2/baz") },      FPL("")},
+    { { FPL(""),              FPL("foo") },               FPL("")},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar/baz") },    FPL("baz")},
+    { { FPL("E:/foo/bar"),    FPL("e:/foo/bar/baz") },    FPL("baz")},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/bar/baz") },    FPL("baz")},
+    { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar/baz") },    FPL("")},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar/baz") },    FPL("")},
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("c:/"),           FPL("c:/foo/bar/baz") },    FPL("foo\\bar\\baz")},
+    // TODO(akalin): Figure out how to handle the corner case in the
+    // commented-out test case below.  Appending to an empty path gives
+    // /foo\bar\baz but appending to a nonempty path "blah" gives
+    // blah\foo\bar\baz.
+    // { { FPL("c:"),            FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("c:/foo/bar"),    FPL("d:/foo/bar/baz") },    FPL("")},
+    { { FPL("c:/foo/bar"),    FPL("D:/foo/bar/baz") },    FPL("")},
+    { { FPL("C:/foo/bar"),    FPL("d:/foo/bar/baz") },    FPL("")},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar/baz") },   FPL("")},
+    { { FPL("e:/foo/bar"),    FPL("E:/foo2/bar/baz") },   FPL("")},
+    { { FPL("F:/foo/bar"),    FPL("f:/foo2/bar/baz") },   FPL("")},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar2/baz") },   FPL("")},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar\\baz") },   FPL("baz")},
+    { { FPL("\\foo/bar"),     FPL("\\foo\\bar\\baz") },   FPL("baz")},
+    { { FPL("\\foo/bar"),     FPL("\\foo/bar/baz") },     FPL("baz")},
+    { { FPL("\\"),            FPL("\\foo\\bar\\baz") },   FPL("foo\\bar\\baz")},
+    { { FPL(""),              FPL("\\foo\\bar\\baz") },   FPL("")},
+    { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar\\baz") },  FPL("")},
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2\\baz") },  FPL("")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  const FilePath base(FPL("blah"));
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath parent(cases[i].inputs[0]);
+    FilePath child(cases[i].inputs[1]);
+    {
+      FilePath result;
+      bool success = parent.AppendRelativePath(child, &result);
+      EXPECT_EQ(cases[i].expected[0] != '\0', success) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+      EXPECT_STREQ(cases[i].expected, result.value().c_str()) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+    }
+    {
+      FilePath result(base);
+      bool success = parent.AppendRelativePath(child, &result);
+      EXPECT_EQ(cases[i].expected[0] != '\0', success) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+      EXPECT_EQ(base.Append(cases[i].expected).value(), result.value()) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+    }
+  }
+}
+
+TEST_F(FilePathTest, EqualityTest) {
+  const struct BinaryBooleanTestData cases[] = {
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar/baz") },      true},
+    { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      false},
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          false},
+    { { FPL("//foo/bar/"),    FPL("//foo/bar/") },        true},
+    { { FPL("/foo/bar"),      FPL("/foo2/bar") },         false},
+    { { FPL("/foo/bar.txt"),  FPL("/foo/bar") },          false},
+    { { FPL("foo/bar"),       FPL("foo/bar") },           true},
+    { { FPL("foo/bar"),       FPL("foo/bar/baz") },       false},
+    { { FPL(""),              FPL("foo") },               false},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar") },        true},
+    { { FPL("E:/foo/bar"),    FPL("e:/foo/bar") },        true},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/bar") },        true},
+    { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar") },        false},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar") },        false},
+    { { FPL("c:/"),           FPL("c:/") },               true},
+    { { FPL("c:"),            FPL("c:") },                true},
+    { { FPL("c:/foo/bar"),    FPL("d:/foo/bar") },        false},
+    { { FPL("c:/foo/bar"),    FPL("D:/foo/bar") },        false},
+    { { FPL("C:/foo/bar"),    FPL("d:/foo/bar") },        false},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar") },       false},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar") },        true},
+    { { FPL("\\foo/bar"),     FPL("\\foo/bar") },         true},
+    { { FPL("\\foo/bar"),     FPL("\\foo\\bar") },        false},
+    { { FPL("\\"),            FPL("\\") },                true},
+    { { FPL("\\"),            FPL("/") },                 false},
+    { { FPL(""),              FPL("\\") },                false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar") },       false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2") },       false},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:\\foo\\bar"),    FPL("c:\\foo\\bar") },    true},
+    { { FPL("E:\\foo\\bar"),    FPL("e:\\foo\\bar") },    true},
+    { { FPL("f:\\foo\\bar"),    FPL("F:\\foo/bar") },     false},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath a(cases[i].inputs[0]);
+    FilePath b(cases[i].inputs[1]);
+
+    EXPECT_EQ(a == b, cases[i].expected) <<
+      "equality i: " << i << ", a: " << a.value() << ", b: " <<
+      b.value();
+  }
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath a(cases[i].inputs[0]);
+    FilePath b(cases[i].inputs[1]);
+
+    EXPECT_EQ(a != b, !cases[i].expected) <<
+      "inequality i: " << i << ", a: " << a.value() << ", b: " <<
+      b.value();
+  }
+}
+
+TEST_F(FilePathTest, Extension) {
+  FilePath base_dir(FILE_PATH_LITERAL("base_dir"));
+
+  FilePath jpg = base_dir.Append(FILE_PATH_LITERAL("foo.jpg"));
+  EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.Extension());
+  EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.FinalExtension());
+
+  FilePath base = jpg.BaseName().RemoveExtension();
+  EXPECT_EQ(FILE_PATH_LITERAL("foo"), base.value());
+
+  FilePath path_no_ext = base_dir.Append(base);
+  EXPECT_EQ(path_no_ext.value(), jpg.RemoveExtension().value());
+
+  EXPECT_EQ(path_no_ext.value(), path_no_ext.RemoveExtension().value());
+  EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.Extension());
+  EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.FinalExtension());
+}
+
+TEST_F(FilePathTest, Extension2) {
+  const struct UnaryTestData cases[] = {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("C:\\a\\b\\c.ext"),        FPL(".ext") },
+    { FPL("C:\\a\\b\\c."),           FPL(".") },
+    { FPL("C:\\a\\b\\c"),            FPL("") },
+    { FPL("C:\\a\\b\\"),             FPL("") },
+    { FPL("C:\\a\\b.\\"),            FPL(".") },
+    { FPL("C:\\a\\b\\c.ext1.ext2"),  FPL(".ext2") },
+    { FPL("C:\\foo.bar\\\\\\"),      FPL(".bar") },
+    { FPL("C:\\foo.bar\\.."),        FPL("") },
+    { FPL("C:\\foo.bar\\..\\\\"),    FPL("") },
+#endif
+    { FPL("/foo/bar/baz.ext"),       FPL(".ext") },
+    { FPL("/foo/bar/baz."),          FPL(".") },
+    { FPL("/foo/bar/baz.."),         FPL(".") },
+    { FPL("/foo/bar/baz"),           FPL("") },
+    { FPL("/foo/bar/"),              FPL("") },
+    { FPL("/foo/bar./"),             FPL(".") },
+    { FPL("/foo/bar/baz.ext1.ext2"), FPL(".ext2") },
+    { FPL("/subversion-1.6.12.zip"), FPL(".zip") },
+    { FPL("/foo.12345.gz"),          FPL(".gz") },
+    { FPL("/foo..gz"),               FPL(".gz") },
+    { FPL("."),                      FPL("") },
+    { FPL(".."),                     FPL("") },
+    { FPL("./foo"),                  FPL("") },
+    { FPL("./foo.ext"),              FPL(".ext") },
+    { FPL("/foo.ext1/bar.ext2"),     FPL(".ext2") },
+    { FPL("/foo.bar////"),           FPL(".bar") },
+    { FPL("/foo.bar/.."),            FPL("") },
+    { FPL("/foo.bar/..////"),        FPL("") },
+    { FPL("/foo.1234.luser.js"),     FPL(".js") },
+    { FPL("/user.js"),               FPL(".js") },
+  };
+  const struct UnaryTestData double_extension_cases[] = {
+    { FPL("/foo.tar.gz"),            FPL(".tar.gz") },
+    { FPL("/foo.tar.Z"),             FPL(".tar.Z") },
+    { FPL("/foo.tar.bz2"),           FPL(".tar.bz2") },
+    { FPL("/foo.1234.gz"),           FPL(".1234.gz") },
+    { FPL("/foo.1234.tar.gz"),       FPL(".tar.gz") },
+    { FPL("/foo.tar.tar.gz"),        FPL(".tar.gz") },
+    { FPL("/foo.tar.gz.gz"),         FPL(".gz.gz") },
+    { FPL("/foo.1234.user.js"),      FPL(".user.js") },
+    { FPL("foo.user.js"),            FPL(".user.js") },
+    { FPL("/foo.tar.bz"),            FPL(".tar.bz") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].input);
+    FilePath::StringType extension = path.Extension();
+    FilePath::StringType final_extension = path.FinalExtension();
+    EXPECT_STREQ(cases[i].expected, extension.c_str())
+        << "i: " << i << ", path: " << path.value();
+    EXPECT_STREQ(cases[i].expected, final_extension.c_str())
+        << "i: " << i << ", path: " << path.value();
+  }
+  for (unsigned int i = 0; i < arraysize(double_extension_cases); ++i) {
+    FilePath path(double_extension_cases[i].input);
+    FilePath::StringType extension = path.Extension();
+    EXPECT_STREQ(double_extension_cases[i].expected, extension.c_str())
+        << "i: " << i << ", path: " << path.value();
+  }
+}
+
+TEST_F(FilePathTest, InsertBeforeExtension) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),                FPL("") },        FPL("") },
+    { { FPL(""),                FPL("txt") },     FPL("") },
+    { { FPL("."),               FPL("txt") },     FPL("") },
+    { { FPL(".."),              FPL("txt") },     FPL("") },
+    { { FPL("foo.dll"),         FPL("txt") },     FPL("footxt.dll") },
+    { { FPL("."),               FPL("") },        FPL(".") },
+    { { FPL("foo.dll"),         FPL(".txt") },    FPL("foo.txt.dll") },
+    { { FPL("foo"),             FPL("txt") },     FPL("footxt") },
+    { { FPL("foo"),             FPL(".txt") },    FPL("foo.txt") },
+    { { FPL("foo.baz.dll"),     FPL("txt") },     FPL("foo.baztxt.dll") },
+    { { FPL("foo.baz.dll"),     FPL(".txt") },    FPL("foo.baz.txt.dll") },
+    { { FPL("foo.dll"),         FPL("") },        FPL("foo.dll") },
+    { { FPL("foo.dll"),         FPL(".") },       FPL("foo..dll") },
+    { { FPL("foo"),             FPL("") },        FPL("foo") },
+    { { FPL("foo"),             FPL(".") },       FPL("foo.") },
+    { { FPL("foo.baz.dll"),     FPL("") },        FPL("foo.baz.dll") },
+    { { FPL("foo.baz.dll"),     FPL(".") },       FPL("foo.baz..dll") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\"),              FPL("") },        FPL("\\") },
+    { { FPL("\\"),              FPL("txt") },     FPL("\\txt") },
+    { { FPL("\\."),             FPL("txt") },     FPL("") },
+    { { FPL("\\.."),            FPL("txt") },     FPL("") },
+    { { FPL("\\."),             FPL("") },        FPL("\\.") },
+    { { FPL("C:\\bar\\foo.dll"), FPL("txt") },
+        FPL("C:\\bar\\footxt.dll") },
+    { { FPL("C:\\bar.baz\\foodll"), FPL("txt") },
+        FPL("C:\\bar.baz\\foodlltxt") },
+    { { FPL("C:\\bar.baz\\foo.dll"), FPL("txt") },
+        FPL("C:\\bar.baz\\footxt.dll") },
+    { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("txt") },
+        FPL("C:\\bar.baz\\foo.dlltxt.exe") },
+    { { FPL("C:\\bar.baz\\foo"), FPL("") },
+        FPL("C:\\bar.baz\\foo") },
+    { { FPL("C:\\bar.baz\\foo.exe"), FPL("") },
+        FPL("C:\\bar.baz\\foo.exe") },
+    { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("") },
+        FPL("C:\\bar.baz\\foo.dll.exe") },
+    { { FPL("C:\\bar\\baz\\foo.exe"), FPL(" (1)") },
+        FPL("C:\\bar\\baz\\foo (1).exe") },
+    { { FPL("C:\\foo.baz\\\\"), FPL(" (1)") },    FPL("C:\\foo (1).baz") },
+    { { FPL("C:\\foo.baz\\..\\"), FPL(" (1)") },  FPL("") },
+#endif
+    { { FPL("/"),               FPL("") },        FPL("/") },
+    { { FPL("/"),               FPL("txt") },     FPL("/txt") },
+    { { FPL("/."),              FPL("txt") },     FPL("") },
+    { { FPL("/.."),             FPL("txt") },     FPL("") },
+    { { FPL("/."),              FPL("") },        FPL("/.") },
+    { { FPL("/bar/foo.dll"),    FPL("txt") },     FPL("/bar/footxt.dll") },
+    { { FPL("/bar.baz/foodll"), FPL("txt") },     FPL("/bar.baz/foodlltxt") },
+    { { FPL("/bar.baz/foo.dll"), FPL("txt") },    FPL("/bar.baz/footxt.dll") },
+    { { FPL("/bar.baz/foo.dll.exe"), FPL("txt") },
+        FPL("/bar.baz/foo.dlltxt.exe") },
+    { { FPL("/bar.baz/foo"),    FPL("") },        FPL("/bar.baz/foo") },
+    { { FPL("/bar.baz/foo.exe"), FPL("") },       FPL("/bar.baz/foo.exe") },
+    { { FPL("/bar.baz/foo.dll.exe"), FPL("") },   FPL("/bar.baz/foo.dll.exe") },
+    { { FPL("/bar/baz/foo.exe"), FPL(" (1)") },   FPL("/bar/baz/foo (1).exe") },
+    { { FPL("/bar/baz/..////"), FPL(" (1)") },    FPL("") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath result = path.InsertBeforeExtension(cases[i].inputs[1]);
+    EXPECT_EQ(cases[i].expected, result.value()) << "i: " << i <<
+        ", path: " << path.value() << ", insert: " << cases[i].inputs[1];
+  }
+}
+
+TEST_F(FilePathTest, RemoveExtension) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),                    FPL("") },
+    { FPL("."),                   FPL(".") },
+    { FPL(".."),                  FPL("..") },
+    { FPL("foo.dll"),             FPL("foo") },
+    { FPL("./foo.dll"),           FPL("./foo") },
+    { FPL("foo..dll"),            FPL("foo.") },
+    { FPL("foo"),                 FPL("foo") },
+    { FPL("foo."),                FPL("foo") },
+    { FPL("foo.."),               FPL("foo.") },
+    { FPL("foo.baz.dll"),         FPL("foo.baz") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("C:\\foo.bar\\foo"),    FPL("C:\\foo.bar\\foo") },
+    { FPL("C:\\foo.bar\\..\\\\"), FPL("C:\\foo.bar\\..\\\\") },
+#endif
+    { FPL("/foo.bar/foo"),        FPL("/foo.bar/foo") },
+    { FPL("/foo.bar/..////"),     FPL("/foo.bar/..////") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].input);
+    FilePath removed = path.RemoveExtension();
+    FilePath removed_final = path.RemoveFinalExtension();
+    EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i <<
+        ", path: " << path.value();
+    EXPECT_EQ(cases[i].expected, removed_final.value()) << "i: " << i <<
+        ", path: " << path.value();
+  }
+  {
+    FilePath path(FPL("foo.tar.gz"));
+    FilePath removed = path.RemoveExtension();
+    FilePath removed_final = path.RemoveFinalExtension();
+    EXPECT_EQ(FPL("foo"), removed.value()) << ", path: " << path.value();
+    EXPECT_EQ(FPL("foo.tar"), removed_final.value()) << ", path: "
+                                                     << path.value();
+  }
+}
+
+TEST_F(FilePathTest, ReplaceExtension) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),              FPL("") },      FPL("") },
+    { { FPL(""),              FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("txt") },   FPL("") },
+    { { FPL(".."),            FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("") },      FPL("") },
+    { { FPL("foo.dll"),       FPL("txt") },   FPL("foo.txt") },
+    { { FPL("./foo.dll"),     FPL("txt") },   FPL("./foo.txt") },
+    { { FPL("foo..dll"),      FPL("txt") },   FPL("foo..txt") },
+    { { FPL("foo.dll"),       FPL(".txt") },  FPL("foo.txt") },
+    { { FPL("foo"),           FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo."),          FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo.."),         FPL("txt") },   FPL("foo..txt") },
+    { { FPL("foo"),           FPL(".txt") },  FPL("foo.txt") },
+    { { FPL("foo.baz.dll"),   FPL("txt") },   FPL("foo.baz.txt") },
+    { { FPL("foo.baz.dll"),   FPL(".txt") },  FPL("foo.baz.txt") },
+    { { FPL("foo.dll"),       FPL("") },      FPL("foo") },
+    { { FPL("foo.dll"),       FPL(".") },     FPL("foo") },
+    { { FPL("foo"),           FPL("") },      FPL("foo") },
+    { { FPL("foo"),           FPL(".") },     FPL("foo") },
+    { { FPL("foo.baz.dll"),   FPL("") },      FPL("foo.baz") },
+    { { FPL("foo.baz.dll"),   FPL(".") },     FPL("foo.baz") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("C:\\foo.bar\\foo"),    FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") },
+    { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") },
+#endif
+    { { FPL("/foo.bar/foo"),        FPL("baz") }, FPL("/foo.bar/foo.baz") },
+    { { FPL("/foo.bar/..////"),     FPL("baz") }, FPL("") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath replaced = path.ReplaceExtension(cases[i].inputs[1]);
+    EXPECT_EQ(cases[i].expected, replaced.value()) << "i: " << i <<
+        ", path: " << path.value() << ", replace: " << cases[i].inputs[1];
+  }
+}
+
+TEST_F(FilePathTest, AddExtension) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),              FPL("") },      FPL("") },
+    { { FPL(""),              FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("txt") },   FPL("") },
+    { { FPL(".."),            FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("") },      FPL("") },
+    { { FPL("foo.dll"),       FPL("txt") },   FPL("foo.dll.txt") },
+    { { FPL("./foo.dll"),     FPL("txt") },   FPL("./foo.dll.txt") },
+    { { FPL("foo..dll"),      FPL("txt") },   FPL("foo..dll.txt") },
+    { { FPL("foo.dll"),       FPL(".txt") },  FPL("foo.dll.txt") },
+    { { FPL("foo"),           FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo."),          FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo.."),         FPL("txt") },   FPL("foo..txt") },
+    { { FPL("foo"),           FPL(".txt") },  FPL("foo.txt") },
+    { { FPL("foo.baz.dll"),   FPL("txt") },   FPL("foo.baz.dll.txt") },
+    { { FPL("foo.baz.dll"),   FPL(".txt") },  FPL("foo.baz.dll.txt") },
+    { { FPL("foo.dll"),       FPL("") },      FPL("foo.dll") },
+    { { FPL("foo.dll"),       FPL(".") },     FPL("foo.dll") },
+    { { FPL("foo"),           FPL("") },      FPL("foo") },
+    { { FPL("foo"),           FPL(".") },     FPL("foo") },
+    { { FPL("foo.baz.dll"),   FPL("") },      FPL("foo.baz.dll") },
+    { { FPL("foo.baz.dll"),   FPL(".") },     FPL("foo.baz.dll") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("C:\\foo.bar\\foo"),    FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") },
+    { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") },
+#endif
+    { { FPL("/foo.bar/foo"),        FPL("baz") }, FPL("/foo.bar/foo.baz") },
+    { { FPL("/foo.bar/..////"),     FPL("baz") }, FPL("") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath added = path.AddExtension(cases[i].inputs[1]);
+    EXPECT_EQ(cases[i].expected, added.value()) << "i: " << i <<
+        ", path: " << path.value() << ", add: " << cases[i].inputs[1];
+  }
+}
+
+TEST_F(FilePathTest, MatchesExtension) {
+  const struct BinaryBooleanTestData cases[] = {
+    { { FPL("foo"),                     FPL("") },                    true},
+    { { FPL("foo"),                     FPL(".") },                   false},
+    { { FPL("foo."),                    FPL("") },                    false},
+    { { FPL("foo."),                    FPL(".") },                   true},
+    { { FPL("foo.txt"),                 FPL(".dll") },                false},
+    { { FPL("foo.txt"),                 FPL(".txt") },                true},
+    { { FPL("foo.txt.dll"),             FPL(".txt") },                false},
+    { { FPL("foo.txt.dll"),             FPL(".dll") },                true},
+    { { FPL("foo.TXT"),                 FPL(".txt") },                true},
+    { { FPL("foo.txt"),                 FPL(".TXT") },                true},
+    { { FPL("foo.tXt"),                 FPL(".txt") },                true},
+    { { FPL("foo.txt"),                 FPL(".tXt") },                true},
+    { { FPL("foo.tXt"),                 FPL(".TXT") },                true},
+    { { FPL("foo.tXt"),                 FPL(".tXt") },                true},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo.txt.dll"),          FPL(".txt") },                false},
+    { { FPL("c:/foo.txt"),              FPL(".txt") },                true},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("c:\\bar\\foo.txt.dll"),    FPL(".txt") },                false},
+    { { FPL("c:\\bar\\foo.txt"),        FPL(".txt") },                true},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+    { { FPL("/bar/foo.txt.dll"),        FPL(".txt") },                false},
+    { { FPL("/bar/foo.txt"),            FPL(".txt") },                true},
+#if defined(OS_WIN) || defined(OS_MACOSX)
+    // Umlauts A, O, U: direct comparison, and upper case vs. lower case
+    { { FPL("foo.\u00E4\u00F6\u00FC"),  FPL(".\u00E4\u00F6\u00FC") }, true},
+    { { FPL("foo.\u00C4\u00D6\u00DC"),  FPL(".\u00E4\u00F6\u00FC") }, true},
+    // C with circumflex: direct comparison, and upper case vs. lower case
+    { { FPL("foo.\u0109"),              FPL(".\u0109") },             true},
+    { { FPL("foo.\u0108"),              FPL(".\u0109") },             true},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath::StringType ext(cases[i].inputs[1]);
+
+    EXPECT_EQ(cases[i].expected, path.MatchesExtension(ext)) <<
+        "i: " << i << ", path: " << path.value() << ", ext: " << ext;
+  }
+}
+
+TEST_F(FilePathTest, CompareIgnoreCase) {
+  const struct BinaryIntTestData cases[] = {
+    { { FPL("foo"),                          FPL("foo") },                  0},
+    { { FPL("FOO"),                          FPL("foo") },                  0},
+    { { FPL("foo.ext"),                      FPL("foo.ext") },              0},
+    { { FPL("FOO.EXT"),                      FPL("foo.ext") },              0},
+    { { FPL("Foo.Ext"),                      FPL("foo.ext") },              0},
+    { { FPL("foO"),                          FPL("foo") },                  0},
+    { { FPL("foo"),                          FPL("foO") },                  0},
+    { { FPL("fOo"),                          FPL("foo") },                  0},
+    { { FPL("foo"),                          FPL("fOo") },                  0},
+    { { FPL("bar"),                          FPL("foo") },                 -1},
+    { { FPL("foo"),                          FPL("bar") },                  1},
+    { { FPL("BAR"),                          FPL("foo") },                 -1},
+    { { FPL("FOO"),                          FPL("bar") },                  1},
+    { { FPL("bar"),                          FPL("FOO") },                 -1},
+    { { FPL("foo"),                          FPL("BAR") },                  1},
+    { { FPL("BAR"),                          FPL("FOO") },                 -1},
+    { { FPL("FOO"),                          FPL("BAR") },                  1},
+    // German "Eszett" (lower case and the new-fangled upper case)
+    // Note that uc(<lowercase eszett>) => "SS", NOT <uppercase eszett>!
+    // However, neither Windows nor Mac OSX converts these.
+    // (or even have glyphs for <uppercase eszett>)
+    { { FPL("\u00DF"),                       FPL("\u00DF") },               0},
+    { { FPL("\u1E9E"),                       FPL("\u1E9E") },               0},
+    { { FPL("\u00DF"),                       FPL("\u1E9E") },              -1},
+    { { FPL("SS"),                           FPL("\u00DF") },              -1},
+    { { FPL("SS"),                           FPL("\u1E9E") },              -1},
+#if defined(OS_WIN) || defined(OS_MACOSX)
+    // Umlauts A, O, U: direct comparison, and upper case vs. lower case
+    { { FPL("\u00E4\u00F6\u00FC"),           FPL("\u00E4\u00F6\u00FC") },   0},
+    { { FPL("\u00C4\u00D6\u00DC"),           FPL("\u00E4\u00F6\u00FC") },   0},
+    // C with circumflex: direct comparison, and upper case vs. lower case
+    { { FPL("\u0109"),                       FPL("\u0109") },               0},
+    { { FPL("\u0108"),                       FPL("\u0109") },               0},
+    // Cyrillic letter SHA: direct comparison, and upper case vs. lower case
+    { { FPL("\u0428"),                       FPL("\u0428") },               0},
+    { { FPL("\u0428"),                       FPL("\u0448") },               0},
+    // Greek letter DELTA: direct comparison, and upper case vs. lower case
+    { { FPL("\u0394"),                       FPL("\u0394") },               0},
+    { { FPL("\u0394"),                       FPL("\u03B4") },               0},
+    // Japanese full-width A: direct comparison, and upper case vs. lower case
+    // Note that full-width and standard characters are considered different.
+    { { FPL("\uFF21"),                       FPL("\uFF21") },               0},
+    { { FPL("\uFF21"),                       FPL("\uFF41") },               0},
+    { { FPL("A"),                            FPL("\uFF21") },              -1},
+    { { FPL("A"),                            FPL("\uFF41") },              -1},
+    { { FPL("a"),                            FPL("\uFF21") },              -1},
+    { { FPL("a"),                            FPL("\uFF41") },              -1},
+#endif
+#if defined(OS_MACOSX)
+    // Codepoints > 0x1000
+    // Georgian letter DON: direct comparison, and upper case vs. lower case
+    { { FPL("\u10A3"),                       FPL("\u10A3") },               0},
+    { { FPL("\u10A3"),                       FPL("\u10D3") },               0},
+    // Combining characters vs. pre-composed characters, upper and lower case
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E31\u1E77\u1E53n") },  0},
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("kuon") },                 1},
+    { { FPL("kuon"), FPL("k\u0301u\u032Do\u0304\u0301n") },                -1},
+    { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("KUON") },                 1},
+    { { FPL("KUON"), FPL("K\u0301U\u032DO\u0304\u0301N") },                -1},
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("KUON") },                 1},
+    { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n") },  0},
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n") },  0},
+    { { FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n") },  1},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath::StringType s1(cases[i].inputs[0]);
+    FilePath::StringType s2(cases[i].inputs[1]);
+    int result = FilePath::CompareIgnoreCase(s1, s2);
+    EXPECT_EQ(cases[i].expected, result) <<
+        "i: " << i << ", s1: " << s1 << ", s2: " << s2;
+  }
+}
+
+TEST_F(FilePathTest, ReferencesParent) {
+  const struct UnaryBooleanTestData cases[] = {
+    { FPL("."),        false },
+    { FPL(".."),       true },
+    { FPL(".. "),      true },
+    { FPL(" .."),      true },
+    { FPL("..."),      true },
+    { FPL("a.."),      false },
+    { FPL("..a"),      false },
+    { FPL("../"),      true },
+    { FPL("/.."),      true },
+    { FPL("/../"),     true },
+    { FPL("/a../"),    false },
+    { FPL("/..a/"),    false },
+    { FPL("//.."),     true },
+    { FPL("..//"),     true },
+    { FPL("//..//"),   true },
+    { FPL("a//..//c"), true },
+    { FPL("../b/c"),   true },
+    { FPL("/../b/c"),  true },
+    { FPL("a/b/.."),   true },
+    { FPL("a/b/../"),  true },
+    { FPL("a/../c"),   true },
+    { FPL("a/b/c"),    false },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.ReferencesParent();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {
+  const struct UTF8TestData cases[] = {
+    { FPL("foo.txt"), "foo.txt" },
+    // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them.
+    { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" },
+    // Full-width "ABC".
+    { FPL("\uFF21\uFF22\uFF23.txt"),
+      "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    // Test FromUTF8Unsafe() works.
+    FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8);
+    EXPECT_EQ(cases[i].native, from_utf8.value())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test AsUTF8Unsafe() works.
+    FilePath from_native = FilePath(cases[i].native);
+    EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test the two file paths are identical.
+    EXPECT_EQ(from_utf8.value(), from_native.value());
+  }
+}
+
+TEST_F(FilePathTest, ConstructWithNUL) {
+  // Assert FPS() works.
+  ASSERT_EQ(3U, FPS("a\0b").length());
+
+  // Test constructor strips '\0'
+  FilePath path(FPS("a\0b"));
+  EXPECT_EQ(1U, path.value().length());
+  EXPECT_EQ(FPL("a"), path.value());
+}
+
+TEST_F(FilePathTest, AppendWithNUL) {
+  // Assert FPS() works.
+  ASSERT_EQ(3U, FPS("b\0b").length());
+
+  // Test Append() strips '\0'
+  FilePath path(FPL("a"));
+  path = path.Append(FPS("b\0b"));
+  EXPECT_EQ(3U, path.value().length());
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+  EXPECT_EQ(FPL("a\\b"), path.value());
+#else
+  EXPECT_EQ(FPL("a/b"), path.value());
+#endif
+}
+
+TEST_F(FilePathTest, ReferencesParentWithNUL) {
+  // Assert FPS() works.
+  ASSERT_EQ(3U, FPS("..\0").length());
+
+  // Test ReferencesParent() doesn't break with "..\0"
+  FilePath path(FPS("..\0"));
+  EXPECT_TRUE(path.ReferencesParent());
+}
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+TEST_F(FilePathTest, NormalizePathSeparators) {
+  const struct UnaryTestData cases[] = {
+    { FPL("foo/bar"), FPL("foo\\bar") },
+    { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") },
+    { FPL("foo\\bar"), FPL("foo\\bar") },
+    { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") },
+    { FPL("foo"), FPL("foo") },
+    // Trailing slashes don't automatically get stripped.  That's what
+    // StripTrailingSeparators() is for.
+    { FPL("foo\\"), FPL("foo\\") },
+    { FPL("foo/"), FPL("foo\\") },
+    { FPL("foo/bar\\"), FPL("foo\\bar\\") },
+    { FPL("foo\\bar/"), FPL("foo\\bar\\") },
+    { FPL("foo/bar/"), FPL("foo\\bar\\") },
+    { FPL("foo\\bar\\"), FPL("foo\\bar\\") },
+    { FPL("\\foo/bar"), FPL("\\foo\\bar") },
+    { FPL("/foo\\bar"), FPL("\\foo\\bar") },
+    { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") },
+    { FPL("/foo/bar/"), FPL("\\foo\\bar\\") },
+    { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") },
+    { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") },
+    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    // This method does not normalize the number of path separators.
+    { FPL("foo\\\\bar"), FPL("foo\\\\bar") },
+    { FPL("foo//bar"), FPL("foo\\\\bar") },
+    { FPL("foo/\\bar"), FPL("foo\\\\bar") },
+    { FPL("foo\\/bar"), FPL("foo\\\\bar") },
+    { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") },
+    { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") },
+    { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") },
+    { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") },
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.NormalizePathSeparators();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+#endif
+
+TEST_F(FilePathTest, EndsWithSeparator) {
+  const UnaryBooleanTestData cases[] = {
+    { FPL(""), false },
+    { FPL("/"), true },
+    { FPL("foo/"), true },
+    { FPL("bar"), false },
+    { FPL("/foo/bar"), false },
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input = FilePath(cases[i].input).NormalizePathSeparators();
+    EXPECT_EQ(cases[i].expected, input.EndsWithSeparator());
+  }
+}
+
+TEST_F(FilePathTest, AsEndingWithSeparator) {
+  const UnaryTestData cases[] = {
+    { FPL(""), FPL("") },
+    { FPL("/"), FPL("/") },
+    { FPL("foo"), FPL("foo/") },
+    { FPL("foo/"), FPL("foo/") }
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input = FilePath(cases[i].input).NormalizePathSeparators();
+    FilePath expected = FilePath(cases[i].expected).NormalizePathSeparators();
+    EXPECT_EQ(expected.value(), input.AsEndingWithSeparator().value());
+  }
+}
+
+#if defined(OS_ANDROID)
+TEST_F(FilePathTest, ContentUriTest) {
+  const struct UnaryBooleanTestData cases[] = {
+    { FPL("content://foo.bar"),    true },
+    { FPL("content://foo.bar/"),   true },
+    { FPL("content://foo/bar"),    true },
+    { FPL("CoNTenT://foo.bar"),    true },
+    { FPL("content://"),           true },
+    { FPL("content:///foo.bar"),   true },
+    { FPL("content://3foo/bar"),   true },
+    { FPL("content://_foo/bar"),   true },
+    { FPL(".. "),                  false },
+    { FPL("foo.bar"),              false },
+    { FPL("content:foo.bar"),      false },
+    { FPL("content:/foo.ba"),      false },
+    { FPL("content:/dir/foo.bar"), false },
+    { FPL("content: //foo.bar"),   false },
+    { FPL("content%2a%2f%2f"),     false },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.IsContentUri();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+#endif
+
+}  // namespace base
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc
new file mode 100644
index 0000000..59ae705
--- /dev/null
+++ b/base/files/file_path_watcher.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Cross platform methods for FilePathWatcher. See the various platform
+// specific implementation files, too.
+
+#include "base/files/file_path_watcher.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/mac/mac_util.h"
+#endif
+
+namespace base {
+
+FilePathWatcher::~FilePathWatcher() {
+  impl_->Cancel();
+}
+
+// static
+void FilePathWatcher::CancelWatch(
+    const scoped_refptr<PlatformDelegate>& delegate) {
+  delegate->CancelOnMessageLoopThread();
+}
+
+// static
+bool FilePathWatcher::RecursiveWatchAvailable() {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // FSEvents isn't available on iOS and is broken on OSX 10.6 and earlier.
+  // See http://crbug.com/54822#c31
+  return mac::IsOSLionOrLater();
+#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
+  return true;
+#else
+  return false;
+#endif
+}
+
+FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) {
+}
+
+FilePathWatcher::PlatformDelegate::~PlatformDelegate() {
+  DCHECK(is_cancelled());
+}
+
+bool FilePathWatcher::Watch(const FilePath& path,
+                            bool recursive,
+                            const Callback& callback) {
+  DCHECK(path.IsAbsolute());
+  return impl_->Watch(path, recursive, callback);
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
new file mode 100644
index 0000000..4f132af
--- /dev/null
+++ b/base/files/file_path_watcher.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module provides a way to monitor a file or directory for changes.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_H_
+#define BASE_FILES_FILE_PATH_WATCHER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// This class lets you register interest in changes on a FilePath.
+// The callback will get called whenever the file or directory referenced by the
+// FilePath is changed, including created or deleted. Due to limitations in the
+// underlying OS APIs, FilePathWatcher has slightly different semantics on OS X
+// than on Windows or Linux. FilePathWatcher on Linux and Windows will detect
+// modifications to files in a watched directory. FilePathWatcher on Mac will
+// detect the creation and deletion of files in a watched directory, but will
+// not detect modifications to those files. See file_path_watcher_kqueue.cc for
+// details.
+class BASE_EXPORT FilePathWatcher {
+ public:
+  // Callback type for Watch(). |path| points to the file that was updated,
+  // and |error| is true if the platform specific code detected an error. In
+  // that case, the callback won't be invoked again.
+  typedef base::Callback<void(const FilePath& path, bool error)> Callback;
+
+  // Used internally to encapsulate different members on different platforms.
+  class PlatformDelegate : public base::RefCountedThreadSafe<PlatformDelegate> {
+   public:
+    PlatformDelegate();
+
+    // Start watching for the given |path| and notify |delegate| about changes.
+    virtual bool Watch(const FilePath& path,
+                       bool recursive,
+                       const Callback& callback) WARN_UNUSED_RESULT = 0;
+
+    // Stop watching. This is called from FilePathWatcher's dtor in order to
+    // allow to shut down properly while the object is still alive.
+    // It can be called from any thread.
+    virtual void Cancel() = 0;
+
+   protected:
+    friend class base::RefCountedThreadSafe<PlatformDelegate>;
+    friend class FilePathWatcher;
+
+    virtual ~PlatformDelegate();
+
+    // Stop watching. This is only called on the thread of the appropriate
+    // message loop. Since it can also be called more than once, it should
+    // check |is_cancelled()| to avoid duplicate work.
+    virtual void CancelOnMessageLoopThread() = 0;
+
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+      return task_runner_;
+    }
+
+    void set_task_runner(
+        scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+      task_runner_ = task_runner.Pass();
+    }
+
+    // Must be called before the PlatformDelegate is deleted.
+    void set_cancelled() {
+      cancelled_ = true;
+    }
+
+    bool is_cancelled() const {
+      return cancelled_;
+    }
+
+   private:
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+    bool cancelled_;
+  };
+
+  FilePathWatcher();
+  virtual ~FilePathWatcher();
+
+  // A callback that always cleans up the PlatformDelegate, either when executed
+  // or when deleted without having been executed at all, as can happen during
+  // shutdown.
+  static void CancelWatch(const scoped_refptr<PlatformDelegate>& delegate);
+
+  // Returns true if the platform and OS version support recursive watches.
+  static bool RecursiveWatchAvailable();
+
+  // Invokes |callback| whenever updates to |path| are detected. This should be
+  // called at most once, and from a MessageLoop of TYPE_IO. Set |recursive| to
+  // true, to watch |path| and its children. The callback will be invoked on
+  // the same loop. Returns true on success.
+  //
+  // Recursive watch is not supported on all platforms and file systems.
+  // Watch() will return false in the case of failure.
+  bool Watch(const FilePath& path, bool recursive, const Callback& callback);
+
+ private:
+  scoped_refptr<PlatformDelegate> impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_H_
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc
new file mode 100644
index 0000000..da01c43
--- /dev/null
+++ b/base/files/file_path_watcher_fsevents.cc
@@ -0,0 +1,284 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher_fsevents.h"
+
+#include <list>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/libdispatch_task_runner.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
+
+namespace base {
+
+namespace {
+
+// The latency parameter passed to FSEventsStreamCreate().
+const CFAbsoluteTime kEventLatencySeconds = 0.3;
+
+class FSEventsTaskRunner : public mac::LibDispatchTaskRunner {
+ public:
+   FSEventsTaskRunner()
+       : mac::LibDispatchTaskRunner("org.chromium.FilePathWatcherFSEvents") {
+   }
+
+ protected:
+  ~FSEventsTaskRunner() override {}
+};
+
+static LazyInstance<FSEventsTaskRunner>::Leaky g_task_runner =
+    LAZY_INSTANCE_INITIALIZER;
+
+// Resolve any symlinks in the path.
+FilePath ResolvePath(const FilePath& path) {
+  const unsigned kMaxLinksToResolve = 255;
+
+  std::vector<FilePath::StringType> component_vector;
+  path.GetComponents(&component_vector);
+  std::list<FilePath::StringType>
+      components(component_vector.begin(), component_vector.end());
+
+  FilePath result;
+  unsigned resolve_count = 0;
+  while (resolve_count < kMaxLinksToResolve && !components.empty()) {
+    FilePath component(*components.begin());
+    components.pop_front();
+
+    FilePath current;
+    if (component.IsAbsolute()) {
+      current = component;
+    } else {
+      current = result.Append(component);
+    }
+
+    FilePath target;
+    if (ReadSymbolicLink(current, &target)) {
+      if (target.IsAbsolute())
+        result.clear();
+      std::vector<FilePath::StringType> target_components;
+      target.GetComponents(&target_components);
+      components.insert(components.begin(), target_components.begin(),
+                        target_components.end());
+      resolve_count++;
+    } else {
+      result = current;
+    }
+  }
+
+  if (resolve_count >= kMaxLinksToResolve)
+    result.clear();
+  return result;
+}
+
+}  // namespace
+
+FilePathWatcherFSEvents::FilePathWatcherFSEvents() : fsevent_stream_(NULL) {
+}
+
+bool FilePathWatcherFSEvents::Watch(const FilePath& path,
+                                    bool recursive,
+                                    const FilePathWatcher::Callback& callback) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(!callback.is_null());
+  DCHECK(callback_.is_null());
+
+  // This class could support non-recursive watches, but that is currently
+  // left to FilePathWatcherKQueue.
+  if (!recursive)
+    return false;
+
+  set_task_runner(ThreadTaskRunnerHandle::Get());
+  callback_ = callback;
+
+  FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
+  g_task_runner.Get().PostTask(
+      FROM_HERE, Bind(&FilePathWatcherFSEvents::StartEventStream, this,
+                      start_event, path));
+  return true;
+}
+
+void FilePathWatcherFSEvents::Cancel() {
+  set_cancelled();
+  callback_.Reset();
+
+  // Switch to the dispatch queue thread to tear down the event stream.
+  g_task_runner.Get().PostTask(
+      FROM_HERE,
+      Bind(&FilePathWatcherFSEvents::CancelOnMessageLoopThread, this));
+}
+
+// static
+void FilePathWatcherFSEvents::FSEventsCallback(
+    ConstFSEventStreamRef stream,
+    void* event_watcher,
+    size_t num_events,
+    void* event_paths,
+    const FSEventStreamEventFlags flags[],
+    const FSEventStreamEventId event_ids[]) {
+  FilePathWatcherFSEvents* watcher =
+      reinterpret_cast<FilePathWatcherFSEvents*>(event_watcher);
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+
+  bool root_changed = watcher->ResolveTargetPath();
+  std::vector<FilePath> paths;
+  FSEventStreamEventId root_change_at = FSEventStreamGetLatestEventId(stream);
+  for (size_t i = 0; i < num_events; i++) {
+    if (flags[i] & kFSEventStreamEventFlagRootChanged)
+      root_changed = true;
+    if (event_ids[i])
+      root_change_at = std::min(root_change_at, event_ids[i]);
+    paths.push_back(FilePath(
+        reinterpret_cast<char**>(event_paths)[i]).StripTrailingSeparators());
+  }
+
+  // Reinitialize the event stream if we find changes to the root. This is
+  // necessary since FSEvents doesn't report any events for the subtree after
+  // the directory to be watched gets created.
+  if (root_changed) {
+    // Resetting the event stream from within the callback fails (FSEvents spews
+    // bad file descriptor errors), so post a task to do the reset.
+    g_task_runner.Get().PostTask(
+        FROM_HERE,
+        Bind(&FilePathWatcherFSEvents::UpdateEventStream, watcher,
+             root_change_at));
+  }
+
+  watcher->OnFilePathsChanged(paths);
+}
+
+FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {
+  // This method may be called on either the libdispatch or task_runner()
+  // thread. Checking callback_ on the libdispatch thread here is safe because
+  // it is executing in a task posted by Cancel() which first reset callback_.
+  // PostTask forms a sufficient memory barrier to ensure that the value is
+  // consistent on the target thread.
+  DCHECK(callback_.is_null())
+      << "Cancel() must be called before FilePathWatcher is destroyed.";
+}
+
+void FilePathWatcherFSEvents::OnFilePathsChanged(
+    const std::vector<FilePath>& paths) {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+  DCHECK(!resolved_target_.empty());
+  task_runner()->PostTask(
+      FROM_HERE, Bind(&FilePathWatcherFSEvents::DispatchEvents, this, paths,
+                      target_, resolved_target_));
+}
+
+void FilePathWatcherFSEvents::DispatchEvents(const std::vector<FilePath>& paths,
+                                             const FilePath& target,
+                                             const FilePath& resolved_target) {
+  DCHECK(task_runner()->RunsTasksOnCurrentThread());
+
+  // Don't issue callbacks after Cancel() has been called.
+  if (is_cancelled() || callback_.is_null()) {
+    return;
+  }
+
+  for (const FilePath& path : paths) {
+    if (resolved_target.IsParent(path) || resolved_target == path) {
+      callback_.Run(target, false);
+      return;
+    }
+  }
+}
+
+void FilePathWatcherFSEvents::CancelOnMessageLoopThread() {
+  // For all other implementations, the "message loop thread" is the IO thread,
+  // as returned by task_runner(). This implementation, however, needs to
+  // cancel pending work on the Dispatch Queue thread.
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+
+  if (fsevent_stream_) {
+    DestroyEventStream();
+    target_.clear();
+    resolved_target_.clear();
+  }
+}
+
+void FilePathWatcherFSEvents::UpdateEventStream(
+    FSEventStreamEventId start_event) {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+
+  // It can happen that the watcher gets canceled while tasks that call this
+  // function are still in flight, so abort if this situation is detected.
+  if (resolved_target_.empty())
+    return;
+
+  if (fsevent_stream_)
+    DestroyEventStream();
+
+  ScopedCFTypeRef<CFStringRef> cf_path(CFStringCreateWithCString(
+      NULL, resolved_target_.value().c_str(), kCFStringEncodingMacHFS));
+  ScopedCFTypeRef<CFStringRef> cf_dir_path(CFStringCreateWithCString(
+      NULL, resolved_target_.DirName().value().c_str(),
+      kCFStringEncodingMacHFS));
+  CFStringRef paths_array[] = { cf_path.get(), cf_dir_path.get() };
+  ScopedCFTypeRef<CFArrayRef> watched_paths(CFArrayCreate(
+      NULL, reinterpret_cast<const void**>(paths_array), arraysize(paths_array),
+      &kCFTypeArrayCallBacks));
+
+  FSEventStreamContext context;
+  context.version = 0;
+  context.info = this;
+  context.retain = NULL;
+  context.release = NULL;
+  context.copyDescription = NULL;
+
+  fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context,
+                                        watched_paths,
+                                        start_event,
+                                        kEventLatencySeconds,
+                                        kFSEventStreamCreateFlagWatchRoot);
+  FSEventStreamSetDispatchQueue(fsevent_stream_,
+                                g_task_runner.Get().GetDispatchQueue());
+
+  if (!FSEventStreamStart(fsevent_stream_)) {
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+  }
+}
+
+bool FilePathWatcherFSEvents::ResolveTargetPath() {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+  FilePath resolved = ResolvePath(target_).StripTrailingSeparators();
+  bool changed = resolved != resolved_target_;
+  resolved_target_ = resolved;
+  if (resolved_target_.empty()) {
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+  }
+  return changed;
+}
+
+void FilePathWatcherFSEvents::ReportError(const FilePath& target) {
+  DCHECK(task_runner()->RunsTasksOnCurrentThread());
+  if (!callback_.is_null()) {
+    callback_.Run(target, true);
+  }
+}
+
+void FilePathWatcherFSEvents::DestroyEventStream() {
+  FSEventStreamStop(fsevent_stream_);
+  FSEventStreamInvalidate(fsevent_stream_);
+  FSEventStreamRelease(fsevent_stream_);
+  fsevent_stream_ = NULL;
+}
+
+void FilePathWatcherFSEvents::StartEventStream(FSEventStreamEventId start_event,
+                                               const FilePath& path) {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+  DCHECK(resolved_target_.empty());
+
+  target_ = path;
+  ResolveTargetPath();
+  UpdateEventStream(start_event);
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
new file mode 100644
index 0000000..300aa76
--- /dev/null
+++ b/base/files/file_path_watcher_fsevents.h
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
+#define BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
+
+#include <CoreServices/CoreServices.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+
+namespace base {
+
+// Mac-specific file watcher implementation based on FSEvents.
+// There are trade-offs between the FSEvents implementation and a kqueue
+// implementation. The biggest issues are that FSEvents on 10.6 sometimes drops
+// events and kqueue does not trigger for modifications to a file in a watched
+// directory. See file_path_watcher_mac.cc for the code that decides when to
+// use which one.
+class FilePathWatcherFSEvents : public FilePathWatcher::PlatformDelegate {
+ public:
+  FilePathWatcherFSEvents();
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+  void Cancel() override;
+
+ private:
+  static void FSEventsCallback(ConstFSEventStreamRef stream,
+                               void* event_watcher,
+                               size_t num_events,
+                               void* event_paths,
+                               const FSEventStreamEventFlags flags[],
+                               const FSEventStreamEventId event_ids[]);
+
+  ~FilePathWatcherFSEvents() override;
+
+  // Called from FSEventsCallback whenever there is a change to the paths.
+  void OnFilePathsChanged(const std::vector<FilePath>& paths);
+
+  // Called on the message_loop() thread to dispatch path events. Can't access
+  // target_ and resolved_target_ directly as those are modified on the
+  // libdispatch thread.
+  void DispatchEvents(const std::vector<FilePath>& paths,
+                      const FilePath& target,
+                      const FilePath& resolved_target);
+
+  // Cleans up and stops the event stream.
+  void CancelOnMessageLoopThread() override;
+
+  // (Re-)Initialize the event stream to start reporting events from
+  // |start_event|.
+  void UpdateEventStream(FSEventStreamEventId start_event);
+
+  // Returns true if resolving the target path got a different result than
+  // last time it was done.
+  bool ResolveTargetPath();
+
+  // Report an error watching the given target.
+  void ReportError(const FilePath& target);
+
+  // Destroy the event stream.
+  void DestroyEventStream();
+
+  // Start watching the FSEventStream.
+  void StartEventStream(FSEventStreamEventId start_event, const FilePath& path);
+
+  // Callback to notify upon changes.
+  // (Only accessed from the message_loop() thread.)
+  FilePathWatcher::Callback callback_;
+
+  // Target path to watch (passed to callback).
+  // (Only accessed from the libdispatch thread.)
+  FilePath target_;
+
+  // Target path with all symbolic links resolved.
+  // (Only accessed from the libdispatch thread.)
+  FilePath resolved_target_;
+
+  // Backend stream we receive event callbacks from (strong reference).
+  // (Only accessed from the libdispatch thread.)
+  FSEventStreamRef fsevent_stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
new file mode 100644
index 0000000..e15cba7
--- /dev/null
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -0,0 +1,390 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher_kqueue.h"
+
+#include <fcntl.h>
+#include <sys/param.h>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
+
+// On some platforms these are not defined.
+#if !defined(EV_RECEIPT)
+#define EV_RECEIPT 0
+#endif
+#if !defined(O_EVTONLY)
+#define O_EVTONLY O_RDONLY
+#endif
+
+namespace base {
+
+FilePathWatcherKQueue::FilePathWatcherKQueue() : kqueue_(-1) {}
+
+FilePathWatcherKQueue::~FilePathWatcherKQueue() {}
+
+void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) {
+  CloseFileDescriptor(&event.ident);
+  EventData* entry = EventDataForKevent(event);
+  delete entry;
+  event.udata = NULL;
+}
+
+int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) {
+  DCHECK(MessageLoopForIO::current());
+  // Make sure that we are working with a clean slate.
+  DCHECK(events->empty());
+
+  std::vector<FilePath::StringType> components;
+  path.GetComponents(&components);
+
+  if (components.size() < 1) {
+    return -1;
+  }
+
+  int last_existing_entry = 0;
+  FilePath built_path;
+  bool path_still_exists = true;
+  for (std::vector<FilePath::StringType>::iterator i = components.begin();
+      i != components.end(); ++i) {
+    if (i == components.begin()) {
+      built_path = FilePath(*i);
+    } else {
+      built_path = built_path.Append(*i);
+    }
+    uintptr_t fd = kNoFileDescriptor;
+    if (path_still_exists) {
+      fd = FileDescriptorForPath(built_path);
+      if (fd == kNoFileDescriptor) {
+        path_still_exists = false;
+      } else {
+        ++last_existing_entry;
+      }
+    }
+    FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : "";
+    EventData* data = new EventData(built_path, subdir);
+    struct kevent event;
+    EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT),
+           (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB |
+            NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data);
+    events->push_back(event);
+  }
+  return last_existing_entry;
+}
+
+uintptr_t FilePathWatcherKQueue::FileDescriptorForPath(const FilePath& path) {
+  int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY));
+  if (fd == -1)
+    return kNoFileDescriptor;
+  return fd;
+}
+
+void FilePathWatcherKQueue::CloseFileDescriptor(uintptr_t* fd) {
+  if (*fd == kNoFileDescriptor) {
+    return;
+  }
+
+  if (IGNORE_EINTR(close(*fd)) != 0) {
+    DPLOG(ERROR) << "close";
+  }
+  *fd = kNoFileDescriptor;
+}
+
+bool FilePathWatcherKQueue::AreKeventValuesValid(struct kevent* kevents,
+                                               int count) {
+  if (count < 0) {
+    DPLOG(ERROR) << "kevent";
+    return false;
+  }
+  bool valid = true;
+  for (int i = 0; i < count; ++i) {
+    if (kevents[i].flags & EV_ERROR && kevents[i].data) {
+      // Find the kevent in |events_| that matches the kevent with the error.
+      EventVector::iterator event = events_.begin();
+      for (; event != events_.end(); ++event) {
+        if (event->ident == kevents[i].ident) {
+          break;
+        }
+      }
+      std::string path_name;
+      if (event != events_.end()) {
+        EventData* event_data = EventDataForKevent(*event);
+        if (event_data != NULL) {
+          path_name = event_data->path_.value();
+        }
+      }
+      if (path_name.empty()) {
+        path_name = base::StringPrintf(
+            "fd %ld", reinterpret_cast<long>(&kevents[i].ident));
+      }
+      DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name;
+      valid = false;
+    }
+  }
+  return valid;
+}
+
+void FilePathWatcherKQueue::HandleAttributesChange(
+    const EventVector::iterator& event,
+    bool* target_file_affected,
+    bool* update_watches) {
+  EventVector::iterator next_event = event + 1;
+  EventData* next_event_data = EventDataForKevent(*next_event);
+  // Check to see if the next item in path is still accessible.
+  uintptr_t have_access = FileDescriptorForPath(next_event_data->path_);
+  if (have_access == kNoFileDescriptor) {
+    *target_file_affected = true;
+    *update_watches = true;
+    EventVector::iterator local_event(event);
+    for (; local_event != events_.end(); ++local_event) {
+      // Close all nodes from the event down. This has the side effect of
+      // potentially rendering other events in |updates| invalid.
+      // There is no need to remove the events from |kqueue_| because this
+      // happens as a side effect of closing the file descriptor.
+      CloseFileDescriptor(&local_event->ident);
+    }
+  } else {
+    CloseFileDescriptor(&have_access);
+  }
+}
+
+void FilePathWatcherKQueue::HandleDeleteOrMoveChange(
+    const EventVector::iterator& event,
+    bool* target_file_affected,
+    bool* update_watches) {
+  *target_file_affected = true;
+  *update_watches = true;
+  EventVector::iterator local_event(event);
+  for (; local_event != events_.end(); ++local_event) {
+    // Close all nodes from the event down. This has the side effect of
+    // potentially rendering other events in |updates| invalid.
+    // There is no need to remove the events from |kqueue_| because this
+    // happens as a side effect of closing the file descriptor.
+    CloseFileDescriptor(&local_event->ident);
+  }
+}
+
+void FilePathWatcherKQueue::HandleCreateItemChange(
+    const EventVector::iterator& event,
+    bool* target_file_affected,
+    bool* update_watches) {
+  // Get the next item in the path.
+  EventVector::iterator next_event = event + 1;
+  // Check to see if it already has a valid file descriptor.
+  if (!IsKeventFileDescriptorOpen(*next_event)) {
+    EventData* next_event_data = EventDataForKevent(*next_event);
+    // If not, attempt to open a file descriptor for it.
+    next_event->ident = FileDescriptorForPath(next_event_data->path_);
+    if (IsKeventFileDescriptorOpen(*next_event)) {
+      *update_watches = true;
+      if (next_event_data->subdir_.empty()) {
+        *target_file_affected = true;
+      }
+    }
+  }
+}
+
+bool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) {
+  // Iterate over events adding kevents for items that exist to the kqueue.
+  // Then check to see if new components in the path have been created.
+  // Repeat until no new components in the path are detected.
+  // This is to get around races in directory creation in a watched path.
+  bool update_watches = true;
+  while (update_watches) {
+    size_t valid;
+    for (valid = 0; valid < events_.size(); ++valid) {
+      if (!IsKeventFileDescriptorOpen(events_[valid])) {
+        break;
+      }
+    }
+    if (valid == 0) {
+      // The root of the file path is inaccessible?
+      return false;
+    }
+
+    EventVector updates(valid);
+    int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0],
+                                    valid, NULL));
+    if (!AreKeventValuesValid(&updates[0], count)) {
+      return false;
+    }
+    update_watches = false;
+    for (; valid < events_.size(); ++valid) {
+      EventData* event_data = EventDataForKevent(events_[valid]);
+      events_[valid].ident = FileDescriptorForPath(event_data->path_);
+      if (IsKeventFileDescriptorOpen(events_[valid])) {
+        update_watches = true;
+        if (event_data->subdir_.empty()) {
+          *target_file_affected = true;
+        }
+      } else {
+        break;
+      }
+    }
+  }
+  return true;
+}
+
+void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK_EQ(fd, kqueue_);
+  DCHECK(events_.size());
+
+  // Request the file system update notifications that have occurred and return
+  // them in |updates|. |count| will contain the number of updates that have
+  // occurred.
+  EventVector updates(events_.size());
+  struct timespec timeout = {0, 0};
+  int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(),
+                                  &timeout));
+
+  // Error values are stored within updates, so check to make sure that no
+  // errors occurred.
+  if (!AreKeventValuesValid(&updates[0], count)) {
+    callback_.Run(target_, true /* error */);
+    Cancel();
+    return;
+  }
+
+  bool update_watches = false;
+  bool send_notification = false;
+
+  // Iterate through each of the updates and react to them.
+  for (int i = 0; i < count; ++i) {
+    // Find our kevent record that matches the update notification.
+    EventVector::iterator event = events_.begin();
+    for (; event != events_.end(); ++event) {
+      if (!IsKeventFileDescriptorOpen(*event) ||
+          event->ident == updates[i].ident) {
+        break;
+      }
+    }
+    if (event == events_.end() || !IsKeventFileDescriptorOpen(*event)) {
+      // The event may no longer exist in |events_| because another event
+      // modified |events_| in such a way to make it invalid. For example if
+      // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for
+      // foo, bar and bam will be sent. If foo is processed first, then
+      // the file descriptors for bar and bam will already be closed and set
+      // to -1 before they get a chance to be processed.
+      continue;
+    }
+
+    EventData* event_data = EventDataForKevent(*event);
+
+    // If the subdir is empty, this is the last item on the path and is the
+    // target file.
+    bool target_file_affected = event_data->subdir_.empty();
+    if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) {
+      HandleAttributesChange(event, &target_file_affected, &update_watches);
+    }
+    if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) {
+      HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches);
+    }
+    if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) {
+      HandleCreateItemChange(event, &target_file_affected, &update_watches);
+    }
+    send_notification |= target_file_affected;
+  }
+
+  if (update_watches) {
+    if (!UpdateWatches(&send_notification)) {
+      callback_.Run(target_, true /* error */);
+      Cancel();
+    }
+  }
+
+  if (send_notification) {
+    callback_.Run(target_, false);
+  }
+}
+
+void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) {
+  NOTREACHED();
+}
+
+void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+bool FilePathWatcherKQueue::Watch(const FilePath& path,
+                                  bool recursive,
+                                  const FilePathWatcher::Callback& callback) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(target_.value().empty());  // Can only watch one path.
+  DCHECK(!callback.is_null());
+  DCHECK_EQ(kqueue_, -1);
+
+  if (recursive) {
+    // Recursive watch is not supported using kqueue.
+    NOTIMPLEMENTED();
+    return false;
+  }
+
+  callback_ = callback;
+  target_ = path;
+
+  MessageLoop::current()->AddDestructionObserver(this);
+  io_task_runner_ = ThreadTaskRunnerHandle::Get();
+
+  kqueue_ = kqueue();
+  if (kqueue_ == -1) {
+    DPLOG(ERROR) << "kqueue";
+    return false;
+  }
+
+  int last_entry = EventsForPath(target_, &events_);
+  DCHECK_NE(last_entry, 0);
+
+  EventVector responses(last_entry);
+
+  int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
+                                  &responses[0], last_entry, NULL));
+  if (!AreKeventValuesValid(&responses[0], count)) {
+    // Calling Cancel() here to close any file descriptors that were opened.
+    // This would happen in the destructor anyways, but FilePathWatchers tend to
+    // be long lived, and if an error has occurred, there is no reason to waste
+    // the file descriptors.
+    Cancel();
+    return false;
+  }
+
+  return MessageLoopForIO::current()->WatchFileDescriptor(
+      kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
+}
+
+void FilePathWatcherKQueue::Cancel() {
+  SingleThreadTaskRunner* task_runner = io_task_runner_.get();
+  if (!task_runner) {
+    set_cancelled();
+    return;
+  }
+  if (!task_runner->BelongsToCurrentThread()) {
+    task_runner->PostTask(FROM_HERE,
+                          base::Bind(&FilePathWatcherKQueue::Cancel, this));
+    return;
+  }
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherKQueue::CancelOnMessageLoopThread() {
+  DCHECK(MessageLoopForIO::current());
+  if (!is_cancelled()) {
+    set_cancelled();
+    kqueue_watcher_.StopWatchingFileDescriptor();
+    if (IGNORE_EINTR(close(kqueue_)) != 0) {
+      DPLOG(ERROR) << "close kqueue";
+    }
+    kqueue_ = -1;
+    std::for_each(events_.begin(), events_.end(), ReleaseEvent);
+    events_.clear();
+    io_task_runner_ = NULL;
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    callback_.Reset();
+  }
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
new file mode 100644
index 0000000..69555a3
--- /dev/null
+++ b/base/files/file_path_watcher_kqueue.h
@@ -0,0 +1,132 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_
+#define BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_
+
+#include <sys/event.h>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// Mac-specific file watcher implementation based on kqueue.
+// The Linux and Windows versions are able to detect:
+// - file creation/deletion/modification in a watched directory
+// - file creation/deletion/modification for a watched file
+// - modifications to the paths to a watched object that would affect the
+//   object such as renaming/attibute changes etc.
+// The kqueue implementation will handle all of the items in the list above
+// except for detecting modifications to files in a watched directory. It will
+// detect the creation and deletion of files, just not the modification of
+// files. It does however detect the attribute changes that the FSEvents impl
+// would miss.
+class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate,
+                              public MessageLoopForIO::Watcher,
+                              public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherKQueue();
+
+  // MessageLoopForIO::Watcher overrides.
+  void OnFileCanReadWithoutBlocking(int fd) override;
+  void OnFileCanWriteWithoutBlocking(int fd) override;
+
+  // MessageLoop::DestructionObserver overrides.
+  void WillDestroyCurrentMessageLoop() override;
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+  void Cancel() override;
+
+ protected:
+  ~FilePathWatcherKQueue() override;
+
+ private:
+  class EventData {
+   public:
+    EventData(const FilePath& path, const FilePath::StringType& subdir)
+        : path_(path), subdir_(subdir) { }
+    FilePath path_;  // Full path to this item.
+    FilePath::StringType subdir_;  // Path to any sub item.
+  };
+
+  typedef std::vector<struct kevent> EventVector;
+
+  // Can only be called on |io_task_runner_|'s thread.
+  void CancelOnMessageLoopThread() override;
+
+  // Returns true if the kevent values are error free.
+  bool AreKeventValuesValid(struct kevent* kevents, int count);
+
+  // Respond to a change of attributes of the path component represented by
+  // |event|. Sets |target_file_affected| to true if |target_| is affected.
+  // Sets |update_watches| to true if |events_| need to be updated.
+  void HandleAttributesChange(const EventVector::iterator& event,
+                              bool* target_file_affected,
+                              bool* update_watches);
+
+  // Respond to a move or deletion of the path component represented by
+  // |event|. Sets |target_file_affected| to true if |target_| is affected.
+  // Sets |update_watches| to true if |events_| need to be updated.
+  void HandleDeleteOrMoveChange(const EventVector::iterator& event,
+                                bool* target_file_affected,
+                                bool* update_watches);
+
+  // Respond to a creation of an item in the path component represented by
+  // |event|. Sets |target_file_affected| to true if |target_| is affected.
+  // Sets |update_watches| to true if |events_| need to be updated.
+  void HandleCreateItemChange(const EventVector::iterator& event,
+                              bool* target_file_affected,
+                              bool* update_watches);
+
+  // Update |events_| with the current status of the system.
+  // Sets |target_file_affected| to true if |target_| is affected.
+  // Returns false if an error occurs.
+  bool UpdateWatches(bool* target_file_affected);
+
+  // Fills |events| with one kevent per component in |path|.
+  // Returns the number of valid events created where a valid event is
+  // defined as one that has a ident (file descriptor) field != -1.
+  static int EventsForPath(FilePath path, EventVector *events);
+
+  // Release a kevent generated by EventsForPath.
+  static void ReleaseEvent(struct kevent& event);
+
+  // Returns a file descriptor that will not block the system from deleting
+  // the file it references.
+  static uintptr_t FileDescriptorForPath(const FilePath& path);
+
+  static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1);
+
+  // Closes |*fd| and sets |*fd| to -1.
+  static void CloseFileDescriptor(uintptr_t* fd);
+
+  // Returns true if kevent has open file descriptor.
+  static bool IsKeventFileDescriptorOpen(const struct kevent& event) {
+    return event.ident != kNoFileDescriptor;
+  }
+
+  static EventData* EventDataForKevent(const struct kevent& event) {
+    return reinterpret_cast<EventData*>(event.udata);
+  }
+
+  EventVector events_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+  MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
+  FilePathWatcher::Callback callback_;
+  FilePath target_;
+  int kqueue_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherKQueue);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
new file mode 100644
index 0000000..ba2f1d9
--- /dev/null
+++ b/base/files/file_path_watcher_linux.cc
@@ -0,0 +1,690 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/containers/hash_tables.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl;
+
+// Singleton to manage all inotify watches.
+// TODO(tony): It would be nice if this wasn't a singleton.
+// http://crbug.com/38174
+class InotifyReader {
+ public:
+  typedef int Watch;  // Watch descriptor used by AddWatch and RemoveWatch.
+  static const Watch kInvalidWatch = -1;
+
+  // Watch directory |path| for changes. |watcher| will be notified on each
+  // change. Returns kInvalidWatch on failure.
+  Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher);
+
+  // Remove |watch| if it's valid.
+  void RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
+
+  // Callback for InotifyReaderTask.
+  void OnInotifyEvent(const inotify_event* event);
+
+ private:
+  friend struct DefaultLazyInstanceTraits<InotifyReader>;
+
+  typedef std::set<FilePathWatcherImpl*> WatcherSet;
+
+  InotifyReader();
+  ~InotifyReader();
+
+  // We keep track of which delegates want to be notified on which watches.
+  hash_map<Watch, WatcherSet> watchers_;
+
+  // Lock to protect watchers_.
+  Lock lock_;
+
+  // Separate thread on which we run blocking read for inotify events.
+  Thread thread_;
+
+  // File descriptor returned by inotify_init.
+  const int inotify_fd_;
+
+  // Use self-pipe trick to unblock select during shutdown.
+  int shutdown_pipe_[2];
+
+  // Flag set to true when startup was successful.
+  bool valid_;
+
+  DISALLOW_COPY_AND_ASSIGN(InotifyReader);
+};
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+                            public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherImpl();
+
+  // Called for each event coming from the watch. |fired_watch| identifies the
+  // watch that fired, |child| indicates what has changed, and is relative to
+  // the currently watched path for |fired_watch|.
+  //
+  // |created| is true if the object appears.
+  // |deleted| is true if the object disappears.
+  // |is_dir| is true if the object is a directory.
+  void OnFilePathChanged(InotifyReader::Watch fired_watch,
+                         const FilePath::StringType& child,
+                         bool created,
+                         bool deleted,
+                         bool is_dir);
+
+ protected:
+  ~FilePathWatcherImpl() override {}
+
+ private:
+  // Start watching |path| for changes and notify |delegate| on each change.
+  // Returns true if watch for |path| has been added successfully.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+
+  // Cancel the watch. This unregisters the instance with InotifyReader.
+  void Cancel() override;
+
+  // Cleans up and stops observing the message_loop() thread.
+  void CancelOnMessageLoopThread() override;
+
+  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
+  // object in the right thread. This also observes destruction of the required
+  // cleanup thread, in case it quits before Cancel() is called.
+  void WillDestroyCurrentMessageLoop() override;
+
+  // Inotify watches are installed for all directory components of |target_|.
+  // A WatchEntry instance holds:
+  // - |watch|: the watch descriptor for a component.
+  // - |subdir|: the subdirectory that identifies the next component.
+  //   - For the last component, there is no next component, so it is empty.
+  // - |linkname|: the target of the symlink.
+  //   - Only if the target being watched is a symbolic link.
+  struct WatchEntry {
+    explicit WatchEntry(const FilePath::StringType& dirname)
+        : watch(InotifyReader::kInvalidWatch),
+          subdir(dirname) {}
+
+    InotifyReader::Watch watch;
+    FilePath::StringType subdir;
+    FilePath::StringType linkname;
+  };
+  typedef std::vector<WatchEntry> WatchVector;
+
+  // Reconfigure to watch for the most specific parent directory of |target_|
+  // that exists. Also calls UpdateRecursiveWatches() below.
+  void UpdateWatches();
+
+  // Reconfigure to recursively watch |target_| and all its sub-directories.
+  // - This is a no-op if the watch is not recursive.
+  // - If |target_| does not exist, then clear all the recursive watches.
+  // - Assuming |target_| exists, passing kInvalidWatch as |fired_watch| forces
+  //   addition of recursive watches for |target_|.
+  // - Otherwise, only the directory associated with |fired_watch| and its
+  //   sub-directories will be reconfigured.
+  void UpdateRecursiveWatches(InotifyReader::Watch fired_watch, bool is_dir);
+
+  // Enumerate recursively through |path| and add / update watches.
+  void UpdateRecursiveWatchesForPath(const FilePath& path);
+
+  // Do internal bookkeeping to update mappings between |watch| and its
+  // associated full path |path|.
+  void TrackWatchForRecursion(InotifyReader::Watch watch, const FilePath& path);
+
+  // Remove all the recursive watches.
+  void RemoveRecursiveWatches();
+
+  // |path| is a symlink to a non-existent target. Attempt to add a watch to
+  // the link target's parent directory. Returns true and update |watch_entry|
+  // on success.
+  bool AddWatchForBrokenSymlink(const FilePath& path, WatchEntry* watch_entry);
+
+  bool HasValidWatchVector() const;
+
+  // Callback to notify upon changes.
+  FilePathWatcher::Callback callback_;
+
+  // The file or directory we're supposed to watch.
+  FilePath target_;
+
+  bool recursive_;
+
+  // The vector of watches and next component names for all path components,
+  // starting at the root directory. The last entry corresponds to the watch for
+  // |target_| and always stores an empty next component name in |subdir|.
+  WatchVector watches_;
+
+  hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_;
+  std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+void InotifyReaderCallback(InotifyReader* reader, int inotify_fd,
+                           int shutdown_fd) {
+  // Make sure the file descriptors are good for use with select().
+  CHECK_LE(0, inotify_fd);
+  CHECK_GT(FD_SETSIZE, inotify_fd);
+  CHECK_LE(0, shutdown_fd);
+  CHECK_GT(FD_SETSIZE, shutdown_fd);
+
+  trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
+
+  while (true) {
+    fd_set rfds;
+    FD_ZERO(&rfds);
+    FD_SET(inotify_fd, &rfds);
+    FD_SET(shutdown_fd, &rfds);
+
+    // Wait until some inotify events are available.
+    int select_result =
+      HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1,
+                          &rfds, NULL, NULL, NULL));
+    if (select_result < 0) {
+      DPLOG(WARNING) << "select failed";
+      return;
+    }
+
+    if (FD_ISSET(shutdown_fd, &rfds))
+      return;
+
+    // Adjust buffer size to current event queue size.
+    int buffer_size;
+    int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd, FIONREAD,
+                                          &buffer_size));
+
+    if (ioctl_result != 0) {
+      DPLOG(WARNING) << "ioctl failed";
+      return;
+    }
+
+    std::vector<char> buffer(buffer_size);
+
+    ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd, &buffer[0],
+                                           buffer_size));
+
+    if (bytes_read < 0) {
+      DPLOG(WARNING) << "read from inotify fd failed";
+      return;
+    }
+
+    ssize_t i = 0;
+    while (i < bytes_read) {
+      inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
+      size_t event_size = sizeof(inotify_event) + event->len;
+      DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
+      reader->OnInotifyEvent(event);
+      i += event_size;
+    }
+  }
+}
+
+static LazyInstance<InotifyReader>::Leaky g_inotify_reader =
+    LAZY_INSTANCE_INITIALIZER;
+
+InotifyReader::InotifyReader()
+    : thread_("inotify_reader"),
+      inotify_fd_(inotify_init()),
+      valid_(false) {
+  if (inotify_fd_ < 0)
+    PLOG(ERROR) << "inotify_init() failed";
+
+  shutdown_pipe_[0] = -1;
+  shutdown_pipe_[1] = -1;
+  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
+    thread_.task_runner()->PostTask(
+        FROM_HERE,
+        Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0]));
+    valid_ = true;
+  }
+}
+
+InotifyReader::~InotifyReader() {
+  if (valid_) {
+    // Write to the self-pipe so that the select call in InotifyReaderTask
+    // returns.
+    ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
+    DPCHECK(ret > 0);
+    DCHECK_EQ(ret, 1);
+    thread_.Stop();
+  }
+  if (inotify_fd_ >= 0)
+    close(inotify_fd_);
+  if (shutdown_pipe_[0] >= 0)
+    close(shutdown_pipe_[0]);
+  if (shutdown_pipe_[1] >= 0)
+    close(shutdown_pipe_[1]);
+}
+
+InotifyReader::Watch InotifyReader::AddWatch(
+    const FilePath& path, FilePathWatcherImpl* watcher) {
+  if (!valid_)
+    return kInvalidWatch;
+
+  AutoLock auto_lock(lock_);
+
+  Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
+                                  IN_ATTRIB | IN_CREATE | IN_DELETE |
+                                  IN_CLOSE_WRITE | IN_MOVE |
+                                  IN_ONLYDIR);
+
+  if (watch == kInvalidWatch)
+    return kInvalidWatch;
+
+  watchers_[watch].insert(watcher);
+
+  return watch;
+}
+
+void InotifyReader::RemoveWatch(Watch watch, FilePathWatcherImpl* watcher) {
+  if (!valid_ || (watch == kInvalidWatch))
+    return;
+
+  AutoLock auto_lock(lock_);
+
+  watchers_[watch].erase(watcher);
+
+  if (watchers_[watch].empty()) {
+    watchers_.erase(watch);
+    inotify_rm_watch(inotify_fd_, watch);
+  }
+}
+
+void InotifyReader::OnInotifyEvent(const inotify_event* event) {
+  if (event->mask & IN_IGNORED)
+    return;
+
+  FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
+  AutoLock auto_lock(lock_);
+
+  for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
+       watcher != watchers_[event->wd].end();
+       ++watcher) {
+    (*watcher)->OnFilePathChanged(event->wd,
+                                  child,
+                                  event->mask & (IN_CREATE | IN_MOVED_TO),
+                                  event->mask & (IN_DELETE | IN_MOVED_FROM),
+                                  event->mask & IN_ISDIR);
+  }
+}
+
+FilePathWatcherImpl::FilePathWatcherImpl()
+    : recursive_(false) {
+}
+
+void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
+                                            const FilePath::StringType& child,
+                                            bool created,
+                                            bool deleted,
+                                            bool is_dir) {
+  if (!task_runner()->BelongsToCurrentThread()) {
+    // Switch to task_runner() to access |watches_| safely.
+    task_runner()->PostTask(FROM_HERE,
+                            Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
+                                 fired_watch, child, created, deleted, is_dir));
+    return;
+  }
+
+  // Check to see if CancelOnMessageLoopThread() has already been called.
+  // May happen when code flow reaches here from the PostTask() above.
+  if (watches_.empty()) {
+    DCHECK(target_.empty());
+    return;
+  }
+
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(HasValidWatchVector());
+
+  // Used below to avoid multiple recursive updates.
+  bool did_update = false;
+
+  // Find the entry in |watches_| that corresponds to |fired_watch|.
+  for (size_t i = 0; i < watches_.size(); ++i) {
+    const WatchEntry& watch_entry = watches_[i];
+    if (fired_watch != watch_entry.watch)
+      continue;
+
+    // Check whether a path component of |target_| changed.
+    bool change_on_target_path =
+        child.empty() ||
+        (child == watch_entry.linkname) ||
+        (child == watch_entry.subdir);
+
+    // Check if the change references |target_| or a direct child of |target_|.
+    bool target_changed;
+    if (watch_entry.subdir.empty()) {
+      // The fired watch is for a WatchEntry without a subdir. Thus for a given
+      // |target_| = "/path/to/foo", this is for "foo". Here, check either:
+      // - the target has no symlink: it is the target and it changed.
+      // - the target has a symlink, and it matches |child|.
+      target_changed = (watch_entry.linkname.empty() ||
+                        child == watch_entry.linkname);
+    } else {
+      // The fired watch is for a WatchEntry with a subdir. Thus for a given
+      // |target_| = "/path/to/foo", this is for {"/", "/path", "/path/to"}.
+      // So we can safely access the next WatchEntry since we have not reached
+      // the end yet. Check |watch_entry| is for "/path/to", i.e. the next
+      // element is "foo".
+      bool next_watch_may_be_for_target = watches_[i + 1].subdir.empty();
+      if (next_watch_may_be_for_target) {
+        // The current |watch_entry| is for "/path/to", so check if the |child|
+        // that changed is "foo".
+        target_changed = watch_entry.subdir == child;
+      } else {
+        // The current |watch_entry| is not for "/path/to", so the next entry
+        // cannot be "foo". Thus |target_| has not changed.
+        target_changed = false;
+      }
+    }
+
+    // Update watches if a directory component of the |target_| path
+    // (dis)appears. Note that we don't add the additional restriction of
+    // checking the event mask to see if it is for a directory here as changes
+    // to symlinks on the target path will not have IN_ISDIR set in the event
+    // masks. As a result we may sometimes call UpdateWatches() unnecessarily.
+    if (change_on_target_path && (created || deleted) && !did_update) {
+      UpdateWatches();
+      did_update = true;
+    }
+
+    // Report the following events:
+    //  - The target or a direct child of the target got changed (in case the
+    //    watched path refers to a directory).
+    //  - One of the parent directories got moved or deleted, since the target
+    //    disappears in this case.
+    //  - One of the parent directories appears. The event corresponding to
+    //    the target appearing might have been missed in this case, so recheck.
+    if (target_changed ||
+        (change_on_target_path && deleted) ||
+        (change_on_target_path && created && PathExists(target_))) {
+      if (!did_update) {
+        UpdateRecursiveWatches(fired_watch, is_dir);
+        did_update = true;
+      }
+      callback_.Run(target_, false /* error */);
+      return;
+    }
+  }
+
+  if (ContainsKey(recursive_paths_by_watch_, fired_watch)) {
+    if (!did_update)
+      UpdateRecursiveWatches(fired_watch, is_dir);
+    callback_.Run(target_, false /* error */);
+  }
+}
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                bool recursive,
+                                const FilePathWatcher::Callback& callback) {
+  DCHECK(target_.empty());
+  DCHECK(MessageLoopForIO::current());
+
+  set_task_runner(ThreadTaskRunnerHandle::Get());
+  callback_ = callback;
+  target_ = path;
+  recursive_ = recursive;
+  MessageLoop::current()->AddDestructionObserver(this);
+
+  std::vector<FilePath::StringType> comps;
+  target_.GetComponents(&comps);
+  DCHECK(!comps.empty());
+  for (size_t i = 1; i < comps.size(); ++i)
+    watches_.push_back(WatchEntry(comps[i]));
+  watches_.push_back(WatchEntry(FilePath::StringType()));
+  UpdateWatches();
+  return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+  if (callback_.is_null()) {
+    // Watch was never called, or the message_loop() thread is already gone.
+    set_cancelled();
+    return;
+  }
+
+  // Switch to the message_loop() if necessary so we can access |watches_|.
+  if (!task_runner()->BelongsToCurrentThread()) {
+    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+                                            make_scoped_refptr(this)));
+  } else {
+    CancelOnMessageLoopThread();
+  }
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  set_cancelled();
+
+  if (!callback_.is_null()) {
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    callback_.Reset();
+  }
+
+  for (size_t i = 0; i < watches_.size(); ++i)
+    g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this);
+  watches_.clear();
+  target_.clear();
+
+  if (recursive_)
+    RemoveRecursiveWatches();
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherImpl::UpdateWatches() {
+  // Ensure this runs on the message_loop() exclusively in order to avoid
+  // concurrency issues.
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  DCHECK(HasValidWatchVector());
+
+  // Walk the list of watches and update them as we go.
+  FilePath path(FILE_PATH_LITERAL("/"));
+  bool path_valid = true;
+  for (size_t i = 0; i < watches_.size(); ++i) {
+    WatchEntry& watch_entry = watches_[i];
+    InotifyReader::Watch old_watch = watch_entry.watch;
+    watch_entry.watch = InotifyReader::kInvalidWatch;
+    watch_entry.linkname.clear();
+    if (path_valid) {
+      watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
+      if (watch_entry.watch == InotifyReader::kInvalidWatch) {
+        if (IsLink(path)) {
+          path_valid = AddWatchForBrokenSymlink(path, &watch_entry);
+        } else {
+          path_valid = false;
+        }
+      }
+    }
+    if (old_watch != watch_entry.watch)
+      g_inotify_reader.Get().RemoveWatch(old_watch, this);
+    path = path.Append(watch_entry.subdir);
+  }
+
+  UpdateRecursiveWatches(InotifyReader::kInvalidWatch,
+                         false /* is directory? */);
+}
+
+void FilePathWatcherImpl::UpdateRecursiveWatches(
+    InotifyReader::Watch fired_watch,
+    bool is_dir) {
+  if (!recursive_)
+    return;
+
+  if (!DirectoryExists(target_)) {
+    RemoveRecursiveWatches();
+    return;
+  }
+
+  // Check to see if this is a forced update or if some component of |target_|
+  // has changed. For these cases, redo the watches for |target_| and below.
+  if (!ContainsKey(recursive_paths_by_watch_, fired_watch)) {
+    UpdateRecursiveWatchesForPath(target_);
+    return;
+  }
+
+  // Underneath |target_|, only directory changes trigger watch updates.
+  if (!is_dir)
+    return;
+
+  const FilePath& changed_dir = recursive_paths_by_watch_[fired_watch];
+
+  std::map<FilePath, InotifyReader::Watch>::iterator start_it =
+      recursive_watches_by_path_.lower_bound(changed_dir);
+  std::map<FilePath, InotifyReader::Watch>::iterator end_it = start_it;
+  for (; end_it != recursive_watches_by_path_.end(); ++end_it) {
+    const FilePath& cur_path = end_it->first;
+    if (!changed_dir.IsParent(cur_path))
+      break;
+    if (!DirectoryExists(cur_path))
+      g_inotify_reader.Get().RemoveWatch(end_it->second, this);
+  }
+  recursive_watches_by_path_.erase(start_it, end_it);
+  UpdateRecursiveWatchesForPath(changed_dir);
+}
+
+void FilePathWatcherImpl::UpdateRecursiveWatchesForPath(const FilePath& path) {
+  DCHECK(recursive_);
+  DCHECK(!path.empty());
+  DCHECK(DirectoryExists(path));
+
+  // Note: SHOW_SYM_LINKS exposes symlinks as symlinks, so they are ignored
+  // rather than followed. Following symlinks can easily lead to the undesirable
+  // situation where the entire file system is being watched.
+  FileEnumerator enumerator(
+      path,
+      true /* recursive enumeration */,
+      FileEnumerator::DIRECTORIES | FileEnumerator::SHOW_SYM_LINKS);
+  for (FilePath current = enumerator.Next();
+       !current.empty();
+       current = enumerator.Next()) {
+    DCHECK(enumerator.GetInfo().IsDirectory());
+
+    if (!ContainsKey(recursive_watches_by_path_, current)) {
+      // Add new watches.
+      InotifyReader::Watch watch =
+          g_inotify_reader.Get().AddWatch(current, this);
+      TrackWatchForRecursion(watch, current);
+    } else {
+      // Update existing watches.
+      InotifyReader::Watch old_watch = recursive_watches_by_path_[current];
+      DCHECK_NE(InotifyReader::kInvalidWatch, old_watch);
+      InotifyReader::Watch watch =
+          g_inotify_reader.Get().AddWatch(current, this);
+      if (watch != old_watch) {
+        g_inotify_reader.Get().RemoveWatch(old_watch, this);
+        recursive_paths_by_watch_.erase(old_watch);
+        recursive_watches_by_path_.erase(current);
+        TrackWatchForRecursion(watch, current);
+      }
+    }
+  }
+}
+
+void FilePathWatcherImpl::TrackWatchForRecursion(InotifyReader::Watch watch,
+                                                 const FilePath& path) {
+  DCHECK(recursive_);
+  DCHECK(!path.empty());
+  DCHECK(target_.IsParent(path));
+
+  if (watch == InotifyReader::kInvalidWatch)
+    return;
+
+  DCHECK(!ContainsKey(recursive_paths_by_watch_, watch));
+  DCHECK(!ContainsKey(recursive_watches_by_path_, path));
+  recursive_paths_by_watch_[watch] = path;
+  recursive_watches_by_path_[path] = watch;
+}
+
+void FilePathWatcherImpl::RemoveRecursiveWatches() {
+  if (!recursive_)
+    return;
+
+  for (hash_map<InotifyReader::Watch, FilePath>::const_iterator it =
+           recursive_paths_by_watch_.begin();
+       it != recursive_paths_by_watch_.end();
+       ++it) {
+    g_inotify_reader.Get().RemoveWatch(it->first, this);
+  }
+  recursive_paths_by_watch_.clear();
+  recursive_watches_by_path_.clear();
+}
+
+bool FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
+                                                   WatchEntry* watch_entry) {
+  DCHECK_EQ(InotifyReader::kInvalidWatch, watch_entry->watch);
+  FilePath link;
+  if (!ReadSymbolicLink(path, &link))
+    return false;
+
+  if (!link.IsAbsolute())
+    link = path.DirName().Append(link);
+
+  // Try watching symlink target directory. If the link target is "/", then we
+  // shouldn't get here in normal situations and if we do, we'd watch "/" for
+  // changes to a component "/" which is harmless so no special treatment of
+  // this case is required.
+  InotifyReader::Watch watch =
+      g_inotify_reader.Get().AddWatch(link.DirName(), this);
+  if (watch == InotifyReader::kInvalidWatch) {
+    // TODO(craig) Symlinks only work if the parent directory for the target
+    // exist. Ideally we should make sure we've watched all the components of
+    // the symlink path for changes. See crbug.com/91561 for details.
+    DPLOG(WARNING) << "Watch failed for "  << link.DirName().value();
+    return false;
+  }
+  watch_entry->watch = watch;
+  watch_entry->linkname = link.BaseName().value();
+  return true;
+}
+
+bool FilePathWatcherImpl::HasValidWatchVector() const {
+  if (watches_.empty())
+    return false;
+  for (size_t i = 0; i < watches_.size() - 1; ++i) {
+    if (watches_[i].subdir.empty())
+      return false;
+  }
+  return watches_[watches_.size() - 1].subdir.empty();
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_mac.cc b/base/files/file_path_watcher_mac.cc
new file mode 100644
index 0000000..6f55ba4
--- /dev/null
+++ b/base/files/file_path_watcher_mac.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher.h"
+#include "base/files/file_path_watcher_kqueue.h"
+
+#if !defined(OS_IOS)
+#include "base/files/file_path_watcher_fsevents.h"
+#endif
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override {
+    // Use kqueue for non-recursive watches and FSEvents for recursive ones.
+    DCHECK(!impl_.get());
+    if (recursive) {
+      if (!FilePathWatcher::RecursiveWatchAvailable())
+        return false;
+#if !defined(OS_IOS)
+      impl_ = new FilePathWatcherFSEvents();
+#endif  // OS_IOS
+    } else {
+      impl_ = new FilePathWatcherKQueue();
+    }
+    DCHECK(impl_.get());
+    return impl_->Watch(path, recursive, callback);
+  }
+
+  void Cancel() override {
+    if (impl_.get())
+      impl_->Cancel();
+    set_cancelled();
+  }
+
+  void CancelOnMessageLoopThread() override {
+    if (impl_.get())
+      impl_->Cancel();
+    set_cancelled();
+  }
+
+ protected:
+  ~FilePathWatcherImpl() override {}
+
+  scoped_refptr<PlatformDelegate> impl_;
+};
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc
new file mode 100644
index 0000000..8138692
--- /dev/null
+++ b/base/files/file_path_watcher_stub.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file exists for Unix systems which don't have the inotify headers, and
+// thus cannot build file_watcher_inotify.cc
+
+#include "base/files/file_path_watcher.h"
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override {
+    return false;
+  }
+
+  void Cancel() override {}
+
+  void CancelOnMessageLoopThread() override {}
+
+ protected:
+  ~FilePathWatcherImpl() override {}
+};
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
new file mode 100644
index 0000000..21e9dd1
--- /dev/null
+++ b/base/files/file_path_watcher_unittest.cc
@@ -0,0 +1,908 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <aclapi.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/path_utils.h"
+#endif  // defined(OS_ANDROID)
+
+namespace base {
+
+namespace {
+
+class TestDelegate;
+
+// Aggregates notifications from the test delegates and breaks the message loop
+// the test thread is waiting on once they all came in.
+class NotificationCollector
+    : public base::RefCountedThreadSafe<NotificationCollector> {
+ public:
+  NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
+  // Called from the file thread by the delegates.
+  void OnChange(TestDelegate* delegate) {
+    task_runner_->PostTask(
+        FROM_HERE, base::Bind(&NotificationCollector::RecordChange, this,
+                              base::Unretained(delegate)));
+  }
+
+  void Register(TestDelegate* delegate) {
+    delegates_.insert(delegate);
+  }
+
+  void Reset() {
+    signaled_.clear();
+  }
+
+  bool Success() {
+    return signaled_ == delegates_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<NotificationCollector>;
+  ~NotificationCollector() {}
+
+  void RecordChange(TestDelegate* delegate) {
+    // Warning: |delegate| is Unretained. Do not dereference.
+    ASSERT_TRUE(task_runner_->BelongsToCurrentThread());
+    ASSERT_TRUE(delegates_.count(delegate));
+    signaled_.insert(delegate);
+
+    // Check whether all delegates have been signaled.
+    if (signaled_ == delegates_)
+      task_runner_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+  }
+
+  // Set of registered delegates.
+  std::set<TestDelegate*> delegates_;
+
+  // Set of signaled delegates.
+  std::set<TestDelegate*> signaled_;
+
+  // The loop we should break after all delegates signaled.
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+};
+
+class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
+ public:
+  TestDelegateBase() {}
+  virtual ~TestDelegateBase() {}
+
+  virtual void OnFileChanged(const FilePath& path, bool error) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
+};
+
+// A mock class for testing. Gmock is not appropriate because it is not
+// thread-safe for setting expectations. Thus the test code cannot safely
+// reset expectations while the file watcher is running.
+// Instead, TestDelegate gets the notifications from FilePathWatcher and uses
+// NotificationCollector to aggregate the results.
+class TestDelegate : public TestDelegateBase {
+ public:
+  explicit TestDelegate(NotificationCollector* collector)
+      : collector_(collector) {
+    collector_->Register(this);
+  }
+  ~TestDelegate() override {}
+
+  void OnFileChanged(const FilePath& path, bool error) override {
+    if (error)
+      ADD_FAILURE() << "Error " << path.value();
+    else
+      collector_->OnChange(this);
+  }
+
+ private:
+  scoped_refptr<NotificationCollector> collector_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+void SetupWatchCallback(const FilePath& target,
+                        FilePathWatcher* watcher,
+                        TestDelegateBase* delegate,
+                        bool recursive_watch,
+                        bool* result,
+                        base::WaitableEvent* completion) {
+  *result = watcher->Watch(target, recursive_watch,
+                           base::Bind(&TestDelegateBase::OnFileChanged,
+                                      delegate->AsWeakPtr()));
+  completion->Signal();
+}
+
+class FilePathWatcherTest : public testing::Test {
+ public:
+  FilePathWatcherTest()
+      : file_thread_("FilePathWatcherTest") {}
+
+  ~FilePathWatcherTest() override {}
+
+ protected:
+  void SetUp() override {
+    // Create a separate file thread in order to test proper thread usage.
+    base::Thread::Options options(MessageLoop::TYPE_IO, 0);
+    ASSERT_TRUE(file_thread_.StartWithOptions(options));
+#if defined(OS_ANDROID)
+    // Watching files is only permitted when all parent directories are
+    // accessible, which is not the case for the default temp directory
+    // on Android which is under /data/data.  Use /sdcard instead.
+    // TODO(pauljensen): Remove this when crbug.com/475568 is fixed.
+    FilePath parent_dir;
+    ASSERT_TRUE(android::GetExternalStorageDirectory(&parent_dir));
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(parent_dir));
+#else   // defined(OS_ANDROID)
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+#endif  // defined(OS_ANDROID)
+    collector_ = new NotificationCollector();
+  }
+
+  void TearDown() override { RunLoop().RunUntilIdle(); }
+
+  void DeleteDelegateOnFileThread(TestDelegate* delegate) {
+    file_thread_.task_runner()->DeleteSoon(FROM_HERE, delegate);
+  }
+
+  FilePath test_file() {
+    return temp_dir_.path().AppendASCII("FilePathWatcherTest");
+  }
+
+  FilePath test_link() {
+    return temp_dir_.path().AppendASCII("FilePathWatcherTest.lnk");
+  }
+
+  // Write |content| to |file|. Returns true on success.
+  bool WriteFile(const FilePath& file, const std::string& content) {
+    int write_size = ::base::WriteFile(file, content.c_str(), content.length());
+    return write_size == static_cast<int>(content.length());
+  }
+
+  bool SetupWatch(const FilePath& target,
+                  FilePathWatcher* watcher,
+                  TestDelegateBase* delegate,
+                  bool recursive_watch) WARN_UNUSED_RESULT;
+
+  bool WaitForEvents() WARN_UNUSED_RESULT {
+    collector_->Reset();
+    loop_.Run();
+    return collector_->Success();
+  }
+
+  NotificationCollector* collector() { return collector_.get(); }
+
+  MessageLoop loop_;
+  base::Thread file_thread_;
+  ScopedTempDir temp_dir_;
+  scoped_refptr<NotificationCollector> collector_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest);
+};
+
+bool FilePathWatcherTest::SetupWatch(const FilePath& target,
+                                     FilePathWatcher* watcher,
+                                     TestDelegateBase* delegate,
+                                     bool recursive_watch) {
+  base::WaitableEvent completion(false, false);
+  bool result;
+  file_thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(SetupWatchCallback, target, watcher, delegate,
+                            recursive_watch, &result, &completion));
+  completion.Wait();
+  return result;
+}
+
+// Basic test: Create the file and verify that we notice.
+TEST_F(FilePathWatcherTest, NewFile) {
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that modifying the file is caught.
+TEST_F(FilePathWatcherTest, ModifiedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that moving the file into place is caught.
+TEST_F(FilePathWatcherTest, MovedFile) {
+  FilePath source_file(temp_dir_.path().AppendASCII("source"));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(base::Move(source_file, test_file()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, DeletedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is deleted.
+  base::DeleteFile(test_file(), false);
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Used by the DeleteDuringNotify test below.
+// Deletes the FilePathWatcher when it's notified.
+class Deleter : public TestDelegateBase {
+ public:
+  Deleter(FilePathWatcher* watcher, MessageLoop* loop)
+      : watcher_(watcher),
+        loop_(loop) {
+  }
+  ~Deleter() override {}
+
+  void OnFileChanged(const FilePath&, bool) override {
+    watcher_.reset();
+    loop_->task_runner()->PostTask(FROM_HERE,
+                                   MessageLoop::QuitWhenIdleClosure());
+  }
+
+  FilePathWatcher* watcher() const { return watcher_.get(); }
+
+ private:
+  scoped_ptr<FilePathWatcher> watcher_;
+  MessageLoop* loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(Deleter);
+};
+
+// Verify that deleting a watcher during the callback doesn't crash.
+TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
+  FilePathWatcher* watcher = new FilePathWatcher;
+  // Takes ownership of watcher.
+  scoped_ptr<Deleter> deleter(new Deleter(watcher, &loop_));
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // We win if we haven't crashed yet.
+  // Might as well double-check it got deleted, too.
+  ASSERT_TRUE(deleter->watcher() == NULL);
+}
+
+// Verify that deleting the watcher works even if there is a pending
+// notification.
+// Flaky on MacOS (and ARM linux): http://crbug.com/85930
+TEST_F(FilePathWatcherTest, DISABLED_DestroyWithPendingNotification) {
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  FilePathWatcher* watcher = new FilePathWatcher;
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  file_thread_.task_runner()->DeleteSoon(FROM_HERE, watcher);
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
+  FilePathWatcher watcher1, watcher2;
+  scoped_ptr<TestDelegate> delegate1(new TestDelegate(collector()));
+  scoped_ptr<TestDelegate> delegate2(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get(), false));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate1.release());
+  DeleteDelegateOnFileThread(delegate2.release());
+}
+
+// Verify that watching a file whose parent directory doesn't exist yet works if
+// the directory and file are created eventually.
+TEST_F(FilePathWatcherTest, NonExistentDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::CreateDirectory(dir));
+
+  ASSERT_TRUE(WriteFile(file, "content"));
+
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Exercises watch reconfiguration for the case that directories on the path
+// are rapidly created.
+TEST_F(FilePathWatcherTest, DirectoryChain) {
+  FilePath path(temp_dir_.path());
+  std::vector<std::string> dir_names;
+  for (int i = 0; i < 20; i++) {
+    std::string dir(base::StringPrintf("d%d", i));
+    dir_names.push_back(dir);
+    path = path.AppendASCII(dir);
+  }
+
+  FilePathWatcher watcher;
+  FilePath file(path.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  FilePath sub_path(temp_dir_.path());
+  for (std::vector<std::string>::const_iterator d(dir_names.begin());
+       d != dir_names.end(); ++d) {
+    sub_path = sub_path.AppendASCII(*d);
+    ASSERT_TRUE(base::CreateDirectory(sub_path));
+  }
+  VLOG(1) << "Create File";
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file modification";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_MACOSX)
+// http://crbug.com/85930
+#define DisappearingDirectory DISABLED_DisappearingDirectory
+#endif
+TEST_F(FilePathWatcherTest, DisappearingDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::DeleteFile(dir, true));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Tests that a file that is deleted and reappears is tracked correctly.
+TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::DeleteFile(test_file(), false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, WatchDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file1(dir.AppendASCII("file1"));
+  FilePath file2(dir.AppendASCII("file2"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  VLOG(1) << "Waiting for directory creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file1, "content"));
+  VLOG(1) << "Waiting for file1 creation";
+  ASSERT_TRUE(WaitForEvents());
+
+#if !defined(OS_MACOSX)
+  // Mac implementation does not detect files modified in a directory.
+  ASSERT_TRUE(WriteFile(file1, "content v2"));
+  VLOG(1) << "Waiting for file1 modification";
+  ASSERT_TRUE(WaitForEvents());
+#endif  // !OS_MACOSX
+
+  ASSERT_TRUE(base::DeleteFile(file1, false));
+  VLOG(1) << "Waiting for file1 deletion";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file2, "content"));
+  VLOG(1) << "Waiting for file2 creation";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, MoveParent) {
+  FilePathWatcher file_watcher;
+  FilePathWatcher subdir_watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath dest(temp_dir_.path().AppendASCII("dest"));
+  FilePath subdir(dir.AppendASCII("subdir"));
+  FilePath file(subdir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false));
+  scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get(),
+                         false));
+
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(base::CreateDirectory(subdir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  // Move the parent directory.
+  base::Move(dir, dest);
+  VLOG(1) << "Waiting for directory move";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(file_delegate.release());
+  DeleteDelegateOnFileThread(subdir_delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, RecursiveWatch) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  bool setup_result = SetupWatch(dir, &watcher, delegate.get(), true);
+  if (!FilePathWatcher::RecursiveWatchAvailable()) {
+    ASSERT_FALSE(setup_result);
+    DeleteDelegateOnFileThread(delegate.release());
+    return;
+  }
+  ASSERT_TRUE(setup_result);
+
+  // Main directory("dir") creation.
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/file1".
+  FilePath file1(dir.AppendASCII("file1"));
+  ASSERT_TRUE(WriteFile(file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir".
+  FilePath subdir(dir.AppendASCII("subdir"));
+  ASSERT_TRUE(base::CreateDirectory(subdir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_file1".
+  FilePath subdir_file1(subdir.AppendASCII("subdir_file1"));
+  ASSERT_TRUE(WriteFile(subdir_file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_child_dir".
+  FilePath subdir_child_dir(subdir.AppendASCII("subdir_child_dir"));
+  ASSERT_TRUE(base::CreateDirectory(subdir_child_dir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_child_dir/child_dir_file1".
+  FilePath child_dir_file1(subdir_child_dir.AppendASCII("child_dir_file1"));
+  ASSERT_TRUE(WriteFile(child_dir_file1, "content v2"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Write into "$dir/subdir/subdir_child_dir/child_dir_file1".
+  ASSERT_TRUE(WriteFile(child_dir_file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4".  Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#if !defined(OS_ANDROID)
+  // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes.
+  ASSERT_TRUE(base::MakeFileUnreadable(child_dir_file1));
+  ASSERT_TRUE(WaitForEvents());
+#endif
+
+  // Delete "$dir/subdir/subdir_file1".
+  ASSERT_TRUE(base::DeleteFile(subdir_file1, false));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Delete "$dir/subdir/subdir_child_dir/child_dir_file1".
+  ASSERT_TRUE(base::DeleteFile(child_dir_file1, false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_POSIX)
+#if defined(OS_ANDROID)
+// Apps cannot create symlinks on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4".  Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#define RecursiveWithSymLink DISABLED_RecursiveWithSymLink
+#endif  // defined(OS_ANDROID)
+TEST_F(FilePathWatcherTest, RecursiveWithSymLink) {
+  if (!FilePathWatcher::RecursiveWatchAvailable())
+    return;
+
+  FilePathWatcher watcher;
+  FilePath test_dir(temp_dir_.path().AppendASCII("test_dir"));
+  ASSERT_TRUE(base::CreateDirectory(test_dir));
+  FilePath symlink(test_dir.AppendASCII("symlink"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(symlink, &watcher, delegate.get(), true));
+
+  // Link creation.
+  FilePath target1(temp_dir_.path().AppendASCII("target1"));
+  ASSERT_TRUE(base::CreateSymbolicLink(target1, symlink));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Target1 creation.
+  ASSERT_TRUE(base::CreateDirectory(target1));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create a file in target1.
+  FilePath target1_file(target1.AppendASCII("file"));
+  ASSERT_TRUE(WriteFile(target1_file, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Link change.
+  FilePath target2(temp_dir_.path().AppendASCII("target2"));
+  ASSERT_TRUE(base::CreateDirectory(target2));
+  ASSERT_TRUE(base::DeleteFile(symlink, false));
+  ASSERT_TRUE(base::CreateSymbolicLink(target2, symlink));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create a file in target2.
+  FilePath target2_file(target2.AppendASCII("file"));
+  ASSERT_TRUE(WriteFile(target2_file, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  DeleteDelegateOnFileThread(delegate.release());
+}
+#endif  // OS_POSIX
+
+TEST_F(FilePathWatcherTest, MoveChild) {
+  FilePathWatcher file_watcher;
+  FilePathWatcher subdir_watcher;
+  FilePath source_dir(temp_dir_.path().AppendASCII("source"));
+  FilePath source_subdir(source_dir.AppendASCII("subdir"));
+  FilePath source_file(source_subdir.AppendASCII("file"));
+  FilePath dest_dir(temp_dir_.path().AppendASCII("dest"));
+  FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
+  FilePath dest_file(dest_subdir.AppendASCII("file"));
+
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(base::CreateDirectory(source_subdir));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false));
+  scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get(),
+                         false));
+
+  // Move the directory into place, s.t. the watched file appears.
+  ASSERT_TRUE(base::Move(source_dir, dest_dir));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(file_delegate.release());
+  DeleteDelegateOnFileThread(subdir_delegate.release());
+}
+
+// Verify that changing attributes on a file is caught
+#if defined(OS_ANDROID)
+// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4".  Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#define FileAttributesChanged DISABLED_FileAttributesChanged
+#endif  // defined(OS_ANDROID
+TEST_F(FilePathWatcherTest, FileAttributesChanged) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(base::MakeFileUnreadable(test_file()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_LINUX)
+
+// Verify that creating a symlink is caught.
+TEST_F(FilePathWatcherTest, CreateLink) {
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the link is created.
+  // Note that test_file() doesn't have to exist.
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that deleting a symlink is caught.
+TEST_F(FilePathWatcherTest, DeleteLink) {
+  // Unfortunately this test case only works if the link target exists.
+  // TODO(craig) fix this as part of crbug.com/91561.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the link is deleted.
+  ASSERT_TRUE(base::DeleteFile(test_link(), false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that modifying a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, ModifiedLinkedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that creating a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, CreateTargetLinkedFile) {
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the target file is created.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that deleting a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, DeleteTargetLinkedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the target file is deleted.
+  ASSERT_TRUE(base::DeleteFile(test_file(), false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file whose parent directory is a link that
+// doesn't exist yet works if the symlink is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // dir/file should exist.
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  // Note that we are watching dir.lnk/file which doesn't exist yet.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(CreateSymbolicLink(dir, link_dir));
+  VLOG(1) << "Waiting for link creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file whose parent directory is a
+// dangling symlink works if the directory is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Now create the link from dir.lnk pointing to dir but
+  // neither dir nor dir/file exist yet.
+  ASSERT_TRUE(CreateSymbolicLink(dir, link_dir));
+  // Note that we are watching dir.lnk/file.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for dir/file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file with a symlink on the path
+// to the file works.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(CreateSymbolicLink(dir, link_dir));
+  // Note that we are watching dir.lnk/file but the file doesn't exist yet.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#endif  // OS_LINUX
+
+enum Permission {
+  Read,
+  Write,
+  Execute
+};
+
+#if defined(OS_MACOSX)
+bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) {
+  struct stat stat_buf;
+
+  if (stat(path.value().c_str(), &stat_buf) != 0)
+    return false;
+
+  mode_t mode = 0;
+  switch (perm) {
+    case Read:
+      mode = S_IRUSR | S_IRGRP | S_IROTH;
+      break;
+    case Write:
+      mode = S_IWUSR | S_IWGRP | S_IWOTH;
+      break;
+    case Execute:
+      mode = S_IXUSR | S_IXGRP | S_IXOTH;
+      break;
+    default:
+      ADD_FAILURE() << "unknown perm " << perm;
+      return false;
+  }
+  if (allow) {
+    stat_buf.st_mode |= mode;
+  } else {
+    stat_buf.st_mode &= ~mode;
+  }
+  return chmod(path.value().c_str(), stat_buf.st_mode) == 0;
+}
+#endif  // defined(OS_MACOSX)
+
+#if defined(OS_MACOSX)
+// Linux implementation of FilePathWatcher doesn't catch attribute changes.
+// http://crbug.com/78043
+// Windows implementation of FilePathWatcher catches attribute changes that
+// don't affect the path being watched.
+// http://crbug.com/78045
+
+// Verify that changing attributes on a directory works.
+TEST_F(FilePathWatcherTest, DirAttributesChanged) {
+  FilePath test_dir1(temp_dir_.path().AppendASCII("DirAttributesChangedDir1"));
+  FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2"));
+  FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile"));
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(base::CreateDirectory(test_dir1));
+  ASSERT_TRUE(base::CreateDirectory(test_dir2));
+  ASSERT_TRUE(WriteFile(test_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get(), false));
+
+  // We should not get notified in this case as it hasn't affected our ability
+  // to access the file.
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
+  loop_.PostDelayedTask(FROM_HERE,
+                        MessageLoop::QuitWhenIdleClosure(),
+                        TestTimeouts::tiny_timeout());
+  ASSERT_FALSE(WaitForEvents());
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true));
+
+  // We should get notified in this case because filepathwatcher can no
+  // longer access the file
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false));
+  ASSERT_TRUE(WaitForEvents());
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true));
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#endif  // OS_MACOSX
+}  // namespace
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
new file mode 100644
index 0000000..081698f
--- /dev/null
+++ b/base/files/file_path_watcher_win.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path_watcher.h"
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+                            public base::win::ObjectWatcher::Delegate,
+                            public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherImpl()
+      : handle_(INVALID_HANDLE_VALUE),
+        recursive_watch_(false) {}
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+  void Cancel() override;
+
+  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
+  // object in the right thread. This also observes destruction of the required
+  // cleanup thread, in case it quits before Cancel() is called.
+  void WillDestroyCurrentMessageLoop() override;
+
+  // Callback from MessageLoopForIO.
+  void OnObjectSignaled(HANDLE object) override;
+
+ private:
+  ~FilePathWatcherImpl() override {}
+
+  // Setup a watch handle for directory |dir|. Set |recursive| to true to watch
+  // the directory sub trees. Returns true if no fatal error occurs. |handle|
+  // will receive the handle value if |dir| is watchable, otherwise
+  // INVALID_HANDLE_VALUE.
+  static bool SetupWatchHandle(const FilePath& dir,
+                               bool recursive,
+                               HANDLE* handle) WARN_UNUSED_RESULT;
+
+  // (Re-)Initialize the watch handle.
+  bool UpdateWatch() WARN_UNUSED_RESULT;
+
+  // Destroy the watch handle.
+  void DestroyWatch();
+
+  // Cleans up and stops observing the |task_runner_| thread.
+  void CancelOnMessageLoopThread() override;
+
+  // Callback to notify upon changes.
+  FilePathWatcher::Callback callback_;
+
+  // Path we're supposed to watch (passed to callback).
+  FilePath target_;
+
+  // Handle for FindFirstChangeNotification.
+  HANDLE handle_;
+
+  // ObjectWatcher to watch handle_ for events.
+  base::win::ObjectWatcher watcher_;
+
+  // Set to true to watch the sub trees of the specified directory file path.
+  bool recursive_watch_;
+
+  // Keep track of the last modified time of the file.  We use nulltime
+  // to represent the file not existing.
+  Time last_modified_;
+
+  // The time at which we processed the first notification with the
+  // |last_modified_| time stamp.
+  Time first_notification_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                bool recursive,
+                                const FilePathWatcher::Callback& callback) {
+  DCHECK(target_.value().empty());  // Can only watch one path.
+
+  set_task_runner(ThreadTaskRunnerHandle::Get());
+  callback_ = callback;
+  target_ = path;
+  recursive_watch_ = recursive;
+  MessageLoop::current()->AddDestructionObserver(this);
+
+  File::Info file_info;
+  if (GetFileInfo(target_, &file_info)) {
+    last_modified_ = file_info.last_modified;
+    first_notification_ = Time::Now();
+  }
+
+  if (!UpdateWatch())
+    return false;
+
+  watcher_.StartWatching(handle_, this);
+
+  return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+  if (callback_.is_null()) {
+    // Watch was never called, or the |task_runner_| has already quit.
+    set_cancelled();
+    return;
+  }
+
+  // Switch to the file thread if necessary so we can stop |watcher_|.
+  if (!task_runner()->BelongsToCurrentThread()) {
+    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+                                            make_scoped_refptr(this)));
+  } else {
+    CancelOnMessageLoopThread();
+  }
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  set_cancelled();
+
+  if (handle_ != INVALID_HANDLE_VALUE)
+    DestroyWatch();
+
+  if (!callback_.is_null()) {
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    callback_.Reset();
+  }
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
+  DCHECK(object == handle_);
+  // Make sure we stay alive through the body of this function.
+  scoped_refptr<FilePathWatcherImpl> keep_alive(this);
+
+  if (!UpdateWatch()) {
+    callback_.Run(target_, true /* error */);
+    return;
+  }
+
+  // Check whether the event applies to |target_| and notify the callback.
+  File::Info file_info;
+  bool file_exists = GetFileInfo(target_, &file_info);
+  if (recursive_watch_) {
+    // Only the mtime of |target_| is tracked but in a recursive watch,
+    // some other file or directory may have changed so all notifications
+    // are passed through. It is possible to figure out which file changed
+    // using ReadDirectoryChangesW() instead of FindFirstChangeNotification(),
+    // but that function is quite complicated:
+    // http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
+    callback_.Run(target_, false);
+  } else if (file_exists && (last_modified_.is_null() ||
+             last_modified_ != file_info.last_modified)) {
+    last_modified_ = file_info.last_modified;
+    first_notification_ = Time::Now();
+    callback_.Run(target_, false);
+  } else if (file_exists && last_modified_ == file_info.last_modified &&
+             !first_notification_.is_null()) {
+    // The target's last modification time is equal to what's on record. This
+    // means that either an unrelated event occurred, or the target changed
+    // again (file modification times only have a resolution of 1s). Comparing
+    // file modification times against the wall clock is not reliable to find
+    // out whether the change is recent, since this code might just run too
+    // late. Moreover, there's no guarantee that file modification time and wall
+    // clock times come from the same source.
+    //
+    // Instead, the time at which the first notification carrying the current
+    // |last_notified_| time stamp is recorded. Later notifications that find
+    // the same file modification time only need to be forwarded until wall
+    // clock has advanced one second from the initial notification. After that
+    // interval, client code is guaranteed to having seen the current revision
+    // of the file.
+    if (Time::Now() - first_notification_ > TimeDelta::FromSeconds(1)) {
+      // Stop further notifications for this |last_modification_| time stamp.
+      first_notification_ = Time();
+    }
+    callback_.Run(target_, false);
+  } else if (!file_exists && !last_modified_.is_null()) {
+    last_modified_ = Time();
+    callback_.Run(target_, false);
+  }
+
+  // The watch may have been cancelled by the callback.
+  if (handle_ != INVALID_HANDLE_VALUE)
+    watcher_.StartWatching(handle_, this);
+}
+
+// static
+bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
+                                           bool recursive,
+                                           HANDLE* handle) {
+  *handle = FindFirstChangeNotification(
+      dir.value().c_str(),
+      recursive,
+      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
+      FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
+      FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
+  if (*handle != INVALID_HANDLE_VALUE) {
+    // Make sure the handle we got points to an existing directory. It seems
+    // that windows sometimes hands out watches to directories that are
+    // about to go away, but doesn't sent notifications if that happens.
+    if (!DirectoryExists(dir)) {
+      FindCloseChangeNotification(*handle);
+      *handle = INVALID_HANDLE_VALUE;
+    }
+    return true;
+  }
+
+  // If FindFirstChangeNotification failed because the target directory
+  // doesn't exist, access is denied (happens if the file is already gone but
+  // there are still handles open), or the target is not a directory, try the
+  // immediate parent directory instead.
+  DWORD error_code = GetLastError();
+  if (error_code != ERROR_FILE_NOT_FOUND &&
+      error_code != ERROR_PATH_NOT_FOUND &&
+      error_code != ERROR_ACCESS_DENIED &&
+      error_code != ERROR_SHARING_VIOLATION &&
+      error_code != ERROR_DIRECTORY) {
+    DPLOG(ERROR) << "FindFirstChangeNotification failed for "
+                 << dir.value();
+    return false;
+  }
+
+  return true;
+}
+
+bool FilePathWatcherImpl::UpdateWatch() {
+  if (handle_ != INVALID_HANDLE_VALUE)
+    DestroyWatch();
+
+  // Start at the target and walk up the directory chain until we succesfully
+  // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
+  // directories stripped from target, in reverse order.
+  std::vector<FilePath> child_dirs;
+  FilePath watched_path(target_);
+  while (true) {
+    if (!SetupWatchHandle(watched_path, recursive_watch_, &handle_))
+      return false;
+
+    // Break if a valid handle is returned. Try the parent directory otherwise.
+    if (handle_ != INVALID_HANDLE_VALUE)
+      break;
+
+    // Abort if we hit the root directory.
+    child_dirs.push_back(watched_path.BaseName());
+    FilePath parent(watched_path.DirName());
+    if (parent == watched_path) {
+      DLOG(ERROR) << "Reached the root directory";
+      return false;
+    }
+    watched_path = parent;
+  }
+
+  // At this point, handle_ is valid. However, the bottom-up search that the
+  // above code performs races against directory creation. So try to walk back
+  // down and see whether any children appeared in the mean time.
+  while (!child_dirs.empty()) {
+    watched_path = watched_path.Append(child_dirs.back());
+    child_dirs.pop_back();
+    HANDLE temp_handle = INVALID_HANDLE_VALUE;
+    if (!SetupWatchHandle(watched_path, recursive_watch_, &temp_handle))
+      return false;
+    if (temp_handle == INVALID_HANDLE_VALUE)
+      break;
+    FindCloseChangeNotification(handle_);
+    handle_ = temp_handle;
+  }
+
+  return true;
+}
+
+void FilePathWatcherImpl::DestroyWatch() {
+  watcher_.StopWatching();
+  FindCloseChangeNotification(handle_);
+  handle_ = INVALID_HANDLE_VALUE;
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
new file mode 100644
index 0000000..4c79057
--- /dev/null
+++ b/base/files/file_posix.cc
@@ -0,0 +1,549 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+// Make sure our Whence mappings match the system headers.
+COMPILE_ASSERT(File::FROM_BEGIN   == SEEK_SET &&
+               File::FROM_CURRENT == SEEK_CUR &&
+               File::FROM_END     == SEEK_END, whence_matches_system);
+
+namespace {
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return fstat(fd, sb);
+}
+#else
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return fstat64(fd, sb);
+}
+#endif
+
+// NaCl doesn't provide the following system calls, so either simulate them or
+// wrap them in order to minimize the number of #ifdef's in this file.
+#if !defined(OS_NACL)
+static bool IsOpenAppend(PlatformFile file) {
+  return (fcntl(file, F_GETFL) & O_APPEND) != 0;
+}
+
+static int CallFtruncate(PlatformFile file, int64 length) {
+  return HANDLE_EINTR(ftruncate(file, length));
+}
+
+static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+#ifdef __USE_XOPEN2K8
+  // futimens should be available, but futimes might not be
+  // http://pubs.opengroup.org/onlinepubs/9699919799/
+
+  timespec ts_times[2];
+  ts_times[0].tv_sec  = times[0].tv_sec;
+  ts_times[0].tv_nsec = times[0].tv_usec * 1000;
+  ts_times[1].tv_sec  = times[1].tv_sec;
+  ts_times[1].tv_nsec = times[1].tv_usec * 1000;
+
+  return futimens(file, ts_times);
+#else
+  return futimes(file, times);
+#endif
+}
+
+static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+  struct flock lock;
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;  // Lock entire file.
+  if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
+    return File::OSErrorToFileError(errno);
+  return File::FILE_OK;
+}
+#else  // defined(OS_NACL)
+
+static bool IsOpenAppend(PlatformFile file) {
+  // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
+  // standard and always appends if the file is opened with O_APPEND, just
+  // return false here.
+  return false;
+}
+
+static int CallFtruncate(PlatformFile file, int64 length) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement ftruncate.
+  return 0;
+}
+
+static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement futimes.
+  return 0;
+}
+
+static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement flock struct.
+  return File::FILE_ERROR_INVALID_OPERATION;
+}
+#endif  // defined(OS_NACL)
+
+}  // namespace
+
+void File::Info::FromStat(const stat_wrapper_t& stat_info) {
+  is_directory = S_ISDIR(stat_info.st_mode);
+  is_symbolic_link = S_ISLNK(stat_info.st_mode);
+  size = stat_info.st_size;
+
+#if defined(OS_LINUX)
+  time_t last_modified_sec = stat_info.st_mtim.tv_sec;
+  int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
+  time_t last_accessed_sec = stat_info.st_atim.tv_sec;
+  int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
+  time_t creation_time_sec = stat_info.st_ctim.tv_sec;
+  int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
+#elif defined(OS_ANDROID)
+  time_t last_modified_sec = stat_info.st_mtime;
+  int64 last_modified_nsec = stat_info.st_mtime_nsec;
+  time_t last_accessed_sec = stat_info.st_atime;
+  int64 last_accessed_nsec = stat_info.st_atime_nsec;
+  time_t creation_time_sec = stat_info.st_ctime;
+  int64 creation_time_nsec = stat_info.st_ctime_nsec;
+#elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
+  time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
+  int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
+  time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
+  int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
+  time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
+  int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
+#else
+  time_t last_modified_sec = stat_info.st_mtime;
+  int64 last_modified_nsec = 0;
+  time_t last_accessed_sec = stat_info.st_atime;
+  int64 last_accessed_nsec = 0;
+  time_t creation_time_sec = stat_info.st_ctime;
+  int64 creation_time_nsec = 0;
+#endif
+
+  last_modified =
+      Time::FromTimeT(last_modified_sec) +
+      TimeDelta::FromMicroseconds(last_modified_nsec /
+                                  Time::kNanosecondsPerMicrosecond);
+
+  last_accessed =
+      Time::FromTimeT(last_accessed_sec) +
+      TimeDelta::FromMicroseconds(last_accessed_nsec /
+                                  Time::kNanosecondsPerMicrosecond);
+
+  creation_time =
+      Time::FromTimeT(creation_time_sec) +
+      TimeDelta::FromMicroseconds(creation_time_nsec /
+                                  Time::kNanosecondsPerMicrosecond);
+}
+
+bool File::IsValid() const {
+  return file_.is_valid();
+}
+
+PlatformFile File::GetPlatformFile() const {
+  return file_.get();
+}
+
+PlatformFile File::TakePlatformFile() {
+  return file_.release();
+}
+
+void File::Close() {
+  if (!IsValid())
+    return;
+
+  ThreadRestrictions::AssertIOAllowed();
+  file_.reset();
+}
+
+int64 File::Seek(Whence whence, int64 offset) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+#if defined(OS_ANDROID)
+  COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
+  return lseek64(file_.get(), static_cast<off64_t>(offset),
+                 static_cast<int>(whence));
+#else
+  COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
+  return lseek(file_.get(), static_cast<off_t>(offset),
+               static_cast<int>(whence));
+#endif
+}
+
+int File::Read(int64 offset, char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  int bytes_read = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
+                            size - bytes_read, offset + bytes_read));
+    if (rv <= 0)
+      break;
+
+    bytes_read += rv;
+  } while (bytes_read < size);
+
+  return bytes_read ? bytes_read : rv;
+}
+
+int File::ReadAtCurrentPos(char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  int bytes_read = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read));
+    if (rv <= 0)
+      break;
+
+    bytes_read += rv;
+  } while (bytes_read < size);
+
+  return bytes_read ? bytes_read : rv;
+}
+
+int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  return HANDLE_EINTR(pread(file_.get(), data, size, offset));
+}
+
+int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  return HANDLE_EINTR(read(file_.get(), data, size));
+}
+
+int File::Write(int64 offset, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (IsOpenAppend(file_.get()))
+    return WriteAtCurrentPos(data, size);
+
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  int bytes_written = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
+                             size - bytes_written, offset + bytes_written));
+    if (rv <= 0)
+      break;
+
+    bytes_written += rv;
+  } while (bytes_written < size);
+
+  return bytes_written ? bytes_written : rv;
+}
+
+int File::WriteAtCurrentPos(const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  int bytes_written = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
+                            size - bytes_written));
+    if (rv <= 0)
+      break;
+
+    bytes_written += rv;
+  } while (bytes_written < size);
+
+  return bytes_written ? bytes_written : rv;
+}
+
+int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  return HANDLE_EINTR(write(file_.get(), data, size));
+}
+
+int64 File::GetLength() {
+  DCHECK(IsValid());
+
+  stat_wrapper_t file_info;
+  if (CallFstat(file_.get(), &file_info))
+    return false;
+
+  return file_info.st_size;
+}
+
+bool File::SetLength(int64 length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  return !CallFtruncate(file_.get(), length);
+}
+
+bool File::SetTimes(Time last_access_time, Time last_modified_time) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  timeval times[2];
+  times[0] = last_access_time.ToTimeVal();
+  times[1] = last_modified_time.ToTimeVal();
+
+  return !CallFutimes(file_.get(), times);
+}
+
+bool File::GetInfo(Info* info) {
+  DCHECK(IsValid());
+
+  stat_wrapper_t file_info;
+  if (CallFstat(file_.get(), &file_info))
+    return false;
+
+  info->FromStat(file_info);
+  return true;
+}
+
+File::Error File::Lock() {
+  return CallFctnlFlock(file_.get(), true);
+}
+
+File::Error File::Unlock() {
+  return CallFctnlFlock(file_.get(), false);
+}
+
+File File::Duplicate() {
+  if (!IsValid())
+    return File();
+
+  PlatformFile other_fd = dup(GetPlatformFile());
+  if (other_fd == -1)
+    return File(OSErrorToFileError(errno));
+
+  File other(other_fd);
+  if (async())
+    other.async_ = true;
+  return other.Pass();
+}
+
+// Static.
+File::Error File::OSErrorToFileError(int saved_errno) {
+  switch (saved_errno) {
+    case EACCES:
+    case EISDIR:
+    case EROFS:
+    case EPERM:
+      return FILE_ERROR_ACCESS_DENIED;
+    case EBUSY:
+#if !defined(OS_NACL)  // ETXTBSY not defined by NaCl.
+    case ETXTBSY:
+#endif
+      return FILE_ERROR_IN_USE;
+    case EEXIST:
+      return FILE_ERROR_EXISTS;
+    case EIO:
+      return FILE_ERROR_IO;
+    case ENOENT:
+      return FILE_ERROR_NOT_FOUND;
+    case EMFILE:
+      return FILE_ERROR_TOO_MANY_OPENED;
+    case ENOMEM:
+      return FILE_ERROR_NO_MEMORY;
+    case ENOSPC:
+      return FILE_ERROR_NO_SPACE;
+    case ENOTDIR:
+      return FILE_ERROR_NOT_A_DIRECTORY;
+    default:
+#if !defined(OS_NACL)  // NaCl build has no metrics code.
+      UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
+                                  saved_errno);
+#endif
+      return FILE_ERROR_FAILED;
+  }
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
+  UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
+  UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
+
+// static
+void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
+    unsigned int* out_checksum) const {
+  // Use a single iteration of a linear congruentional generator (lcg) to
+  // provide a cheap checksum unlikely to be accidentally matched by a random
+  // memory corruption.
+
+  // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
+  // length, we insure that each distinct fd value maps to a distinct checksum,
+  // which maximises the utility of our checksum.
+
+  // This code uses "unsigned int" throughout for its defined modular semantics,
+  // which implicitly gives us a divisor that is a power of two.
+
+  const unsigned int kMultiplier = 13035 * 4 + 1;
+  COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
+  const unsigned int kIncrement = 1595649551;
+  COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
+
+  *out_checksum =
+      static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
+}
+
+void File::MemoryCheckingScopedFD::Check() const {
+  unsigned int computed_checksum;
+  ComputeMemoryChecksum(&computed_checksum);
+  CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
+}
+
+void File::MemoryCheckingScopedFD::UpdateChecksum() {
+  ComputeMemoryChecksum(&file_memory_checksum_);
+}
+
+// NaCl doesn't implement system calls to open files directly.
+#if !defined(OS_NACL)
+// TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
+void File::DoInitialize(const FilePath& name, uint32 flags) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsValid());
+
+  int open_flags = 0;
+  if (flags & FLAG_CREATE)
+    open_flags = O_CREAT | O_EXCL;
+
+  created_ = false;
+
+  if (flags & FLAG_CREATE_ALWAYS) {
+    DCHECK(!open_flags);
+    DCHECK(flags & FLAG_WRITE);
+    open_flags = O_CREAT | O_TRUNC;
+  }
+
+  if (flags & FLAG_OPEN_TRUNCATED) {
+    DCHECK(!open_flags);
+    DCHECK(flags & FLAG_WRITE);
+    open_flags = O_TRUNC;
+  }
+
+  if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
+    NOTREACHED();
+    errno = EOPNOTSUPP;
+    error_details_ = FILE_ERROR_FAILED;
+    return;
+  }
+
+  if (flags & FLAG_WRITE && flags & FLAG_READ) {
+    open_flags |= O_RDWR;
+  } else if (flags & FLAG_WRITE) {
+    open_flags |= O_WRONLY;
+  } else if (!(flags & FLAG_READ) &&
+             !(flags & FLAG_WRITE_ATTRIBUTES) &&
+             !(flags & FLAG_APPEND) &&
+             !(flags & FLAG_OPEN_ALWAYS)) {
+    NOTREACHED();
+  }
+
+  if (flags & FLAG_TERMINAL_DEVICE)
+    open_flags |= O_NOCTTY | O_NDELAY;
+
+  if (flags & FLAG_APPEND && flags & FLAG_READ)
+    open_flags |= O_APPEND | O_RDWR;
+  else if (flags & FLAG_APPEND)
+    open_flags |= O_APPEND | O_WRONLY;
+
+  COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+
+  int mode = S_IRUSR | S_IWUSR;
+#if defined(OS_CHROMEOS)
+  mode |= S_IRGRP | S_IROTH;
+#endif
+
+  int descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
+
+  if (flags & FLAG_OPEN_ALWAYS) {
+    if (descriptor < 0) {
+      open_flags |= O_CREAT;
+      if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
+        open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
+
+      descriptor = HANDLE_EINTR(open(name.value().c_str(), open_flags, mode));
+      if (descriptor >= 0)
+        created_ = true;
+    }
+  }
+
+  if (descriptor < 0) {
+    error_details_ = File::OSErrorToFileError(errno);
+    return;
+  }
+
+  if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
+    created_ = true;
+
+  if (flags & FLAG_DELETE_ON_CLOSE)
+    unlink(name.value().c_str());
+
+  async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
+  error_details_ = FILE_OK;
+  file_.reset(descriptor);
+}
+#endif  // !defined(OS_NACL)
+
+bool File::DoFlush() {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();  // NaCl doesn't implement fsync.
+  return true;
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+  return !HANDLE_EINTR(fdatasync(file_.get()));
+#else
+  return !HANDLE_EINTR(fsync(file_.get()));
+#endif
+}
+
+void File::SetPlatformFile(PlatformFile file) {
+  DCHECK(!file_.is_valid());
+  file_.reset(file);
+}
+
+}  // namespace base
diff --git a/base/files/file_proxy.cc b/base/files/file_proxy.cc
new file mode 100644
index 0000000..f995735
--- /dev/null
+++ b/base/files/file_proxy.cc
@@ -0,0 +1,358 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+
+namespace {
+
+void FileDeleter(base::File file) {
+}
+
+}  // namespace
+
+namespace base {
+
+class FileHelper {
+ public:
+   FileHelper(FileProxy* proxy, File file)
+      : file_(file.Pass()),
+        error_(File::FILE_ERROR_FAILED),
+        task_runner_(proxy->task_runner()),
+        proxy_(AsWeakPtr(proxy)) {
+   }
+
+   void PassFile() {
+     if (proxy_)
+       proxy_->SetFile(file_.Pass());
+     else if (file_.IsValid())
+       task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
+   }
+
+ protected:
+  File file_;
+  File::Error error_;
+
+ private:
+  scoped_refptr<TaskRunner> task_runner_;
+  WeakPtr<FileProxy> proxy_;
+  DISALLOW_COPY_AND_ASSIGN(FileHelper);
+};
+
+namespace {
+
+class GenericFileHelper : public FileHelper {
+ public:
+  GenericFileHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void Close() {
+    file_.Close();
+    error_ = File::FILE_OK;
+  }
+
+  void SetTimes(Time last_access_time, Time last_modified_time) {
+    bool rv = file_.SetTimes(last_access_time, last_modified_time);
+    error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED;
+  }
+
+  void SetLength(int64 length) {
+    if (file_.SetLength(length))
+      error_ = File::FILE_OK;
+  }
+
+  void Flush() {
+    if (file_.Flush())
+      error_ = File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::StatusCallback& callback) {
+    PassFile();
+    if (!callback.is_null())
+      callback.Run(error_);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GenericFileHelper);
+};
+
+class CreateOrOpenHelper : public FileHelper {
+ public:
+  CreateOrOpenHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void RunWork(const FilePath& file_path, int file_flags) {
+    file_.Initialize(file_path, file_flags);
+    error_ = file_.IsValid() ? File::FILE_OK : file_.error_details();
+  }
+
+  void Reply(const FileProxy::StatusCallback& callback) {
+    DCHECK(!callback.is_null());
+    PassFile();
+    callback.Run(error_);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
+};
+
+class CreateTemporaryHelper : public FileHelper {
+ public:
+  CreateTemporaryHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void RunWork(uint32 additional_file_flags) {
+    // TODO(darin): file_util should have a variant of CreateTemporaryFile
+    // that returns a FilePath and a File.
+    if (!CreateTemporaryFile(&file_path_)) {
+      // TODO(davidben): base::CreateTemporaryFile should preserve the error
+      // code.
+      error_ = File::FILE_ERROR_FAILED;
+      return;
+    }
+
+    uint32 file_flags = File::FLAG_WRITE |
+                        File::FLAG_TEMPORARY |
+                        File::FLAG_CREATE_ALWAYS |
+                        additional_file_flags;
+
+    file_.Initialize(file_path_, file_flags);
+    if (file_.IsValid()) {
+      error_ = File::FILE_OK;
+    } else {
+      error_ = file_.error_details();
+      DeleteFile(file_path_, false);
+      file_path_.clear();
+    }
+  }
+
+  void Reply(const FileProxy::CreateTemporaryCallback& callback) {
+    DCHECK(!callback.is_null());
+    PassFile();
+    callback.Run(error_, file_path_);
+  }
+
+ private:
+  FilePath file_path_;
+  DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
+};
+
+class GetInfoHelper : public FileHelper {
+ public:
+  GetInfoHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void RunWork() {
+    if (file_.GetInfo(&file_info_))
+      error_  = File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::GetFileInfoCallback& callback) {
+    PassFile();
+    DCHECK(!callback.is_null());
+    callback.Run(error_, file_info_);
+  }
+
+ private:
+  File::Info file_info_;
+  DISALLOW_COPY_AND_ASSIGN(GetInfoHelper);
+};
+
+class ReadHelper : public FileHelper {
+ public:
+  ReadHelper(FileProxy* proxy, File file, int bytes_to_read)
+      : FileHelper(proxy, file.Pass()),
+        buffer_(new char[bytes_to_read]),
+        bytes_to_read_(bytes_to_read),
+        bytes_read_(0) {
+  }
+
+  void RunWork(int64 offset) {
+    bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_);
+    error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::ReadCallback& callback) {
+    PassFile();
+    DCHECK(!callback.is_null());
+    callback.Run(error_, buffer_.get(), bytes_read_);
+  }
+
+ private:
+  scoped_ptr<char[]> buffer_;
+  int bytes_to_read_;
+  int bytes_read_;
+  DISALLOW_COPY_AND_ASSIGN(ReadHelper);
+};
+
+class WriteHelper : public FileHelper {
+ public:
+  WriteHelper(FileProxy* proxy,
+              File file,
+              const char* buffer, int bytes_to_write)
+      : FileHelper(proxy, file.Pass()),
+        buffer_(new char[bytes_to_write]),
+        bytes_to_write_(bytes_to_write),
+        bytes_written_(0) {
+    memcpy(buffer_.get(), buffer, bytes_to_write);
+  }
+
+  void RunWork(int64 offset) {
+    bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_);
+    error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::WriteCallback& callback) {
+    PassFile();
+    if (!callback.is_null())
+      callback.Run(error_, bytes_written_);
+  }
+
+ private:
+  scoped_ptr<char[]> buffer_;
+  int bytes_to_write_;
+  int bytes_written_;
+  DISALLOW_COPY_AND_ASSIGN(WriteHelper);
+};
+
+}  // namespace
+
+FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) {
+}
+
+FileProxy::~FileProxy() {
+  if (file_.IsValid())
+    task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
+}
+
+bool FileProxy::CreateOrOpen(const FilePath& file_path,
+                             uint32 file_flags,
+                             const StatusCallback& callback) {
+  DCHECK(!file_.IsValid());
+  CreateOrOpenHelper* helper = new CreateOrOpenHelper(this, File());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path,
+           file_flags),
+      Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::CreateTemporary(uint32 additional_file_flags,
+                                const CreateTemporaryCallback& callback) {
+  DCHECK(!file_.IsValid());
+  CreateTemporaryHelper* helper = new CreateTemporaryHelper(this, File());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
+           additional_file_flags),
+      Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::IsValid() const {
+  return file_.IsValid();
+}
+
+void FileProxy::SetFile(File file) {
+  DCHECK(!file_.IsValid());
+  file_ = file.Pass();
+}
+
+File FileProxy::TakeFile() {
+  return file_.Pass();
+}
+
+PlatformFile FileProxy::GetPlatformFile() const {
+  return file_.GetPlatformFile();
+}
+
+bool FileProxy::Close(const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::Close, Unretained(helper)),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::GetInfo(const GetFileInfoCallback& callback) {
+  DCHECK(file_.IsValid());
+  GetInfoHelper* helper = new GetInfoHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GetInfoHelper::RunWork, Unretained(helper)),
+      Bind(&GetInfoHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::Read(int64 offset,
+                     int bytes_to_read,
+                     const ReadCallback& callback) {
+  DCHECK(file_.IsValid());
+  if (bytes_to_read < 0)
+    return false;
+
+  ReadHelper* helper = new ReadHelper(this, file_.Pass(), bytes_to_read);
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&ReadHelper::RunWork, Unretained(helper), offset),
+      Bind(&ReadHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::Write(int64 offset,
+                      const char* buffer,
+                      int bytes_to_write,
+                      const WriteCallback& callback) {
+  DCHECK(file_.IsValid());
+  if (bytes_to_write <= 0 || buffer == NULL)
+    return false;
+
+  WriteHelper* helper =
+      new WriteHelper(this, file_.Pass(), buffer, bytes_to_write);
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&WriteHelper::RunWork, Unretained(helper), offset),
+      Bind(&WriteHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::SetTimes(Time last_access_time,
+                         Time last_modified_time,
+                         const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::SetTimes, Unretained(helper), last_access_time,
+           last_modified_time),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::SetLength(int64 length, const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::SetLength, Unretained(helper), length),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::Flush(const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::Flush, Unretained(helper)),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+}  // namespace base
diff --git a/base/files/file_proxy.h b/base/files/file_proxy.h
new file mode 100644
index 0000000..f990d04
--- /dev/null
+++ b/base/files/file_proxy.h
@@ -0,0 +1,142 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_PROXY_H_
+#define BASE_FILES_FILE_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+namespace tracked_objects {
+class Location;
+};
+
+namespace base {
+
+class TaskRunner;
+class Time;
+
+// This class provides asynchronous access to a File. All methods follow the
+// same rules of the equivalent File method, as they are implemented by bouncing
+// the operation to File using a TaskRunner.
+//
+// This class performs automatic proxying to close the underlying file at
+// destruction.
+//
+// The TaskRunner is in charge of any sequencing of the operations, but a single
+// operation can be proxied at a time, regardless of the use of a callback.
+// In other words, having a sequence like
+//
+//   proxy.Write(...);
+//   proxy.Write(...);
+//
+// means the second Write will always fail.
+class BASE_EXPORT FileProxy : public SupportsWeakPtr<FileProxy> {
+ public:
+  // This callback is used by methods that report only an error code. It is
+  // valid to pass a null callback to some functions that takes a
+  // StatusCallback, in which case the operation will complete silently.
+  typedef Callback<void(File::Error)> StatusCallback;
+
+  typedef Callback<void(File::Error,
+                        const FilePath&)> CreateTemporaryCallback;
+  typedef Callback<void(File::Error,
+                        const File::Info&)> GetFileInfoCallback;
+  typedef Callback<void(File::Error,
+                        const char* data,
+                        int bytes_read)> ReadCallback;
+  typedef Callback<void(File::Error,
+                        int bytes_written)> WriteCallback;
+
+  FileProxy();
+  explicit FileProxy(TaskRunner* task_runner);
+  ~FileProxy();
+
+  // Creates or opens a file with the given flags. It is invalid to pass a null
+  // callback. If File::FLAG_CREATE is set in |file_flags| it always tries to
+  // create a new file at the given |file_path| and fails if the file already
+  // exists.
+  //
+  // This returns false if task posting to |task_runner| has failed.
+  bool CreateOrOpen(const FilePath& file_path,
+                    uint32 file_flags,
+                    const StatusCallback& callback);
+
+  // Creates a temporary file for writing. The path and an open file are
+  // returned. It is invalid to pass a null callback. The additional file flags
+  // will be added on top of the default file flags which are:
+  //   File::FLAG_CREATE_ALWAYS
+  //   File::FLAG_WRITE
+  //   File::FLAG_TEMPORARY.
+  //
+  // This returns false if task posting to |task_runner| has failed.
+  bool CreateTemporary(uint32 additional_file_flags,
+                       const CreateTemporaryCallback& callback);
+
+  // Returns true if the underlying |file_| is valid.
+  bool IsValid() const;
+
+  // Returns true if a new file was created (or an old one truncated to zero
+  // length to simulate a new file), and false otherwise.
+  bool created() const { return file_.created(); }
+
+  // Claims ownership of |file|. It is an error to call this method when
+  // IsValid() returns true.
+  void SetFile(File file);
+
+  File TakeFile();
+
+  PlatformFile GetPlatformFile() const;
+
+  // Proxies File::Close. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool Close(const StatusCallback& callback);
+
+  // Proxies File::GetInfo. The callback can't be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool GetInfo(const GetFileInfoCallback& callback);
+
+  // Proxies File::Read. The callback can't be null.
+  // This returns false if |bytes_to_read| is less than zero, or
+  // if task posting to |task_runner| has failed.
+  bool Read(int64 offset, int bytes_to_read, const ReadCallback& callback);
+
+  // Proxies File::Write. The callback can be null.
+  // This returns false if |bytes_to_write| is less than or equal to zero,
+  // if |buffer| is NULL, or if task posting to |task_runner| has failed.
+  bool Write(int64 offset,
+             const char* buffer,
+             int bytes_to_write,
+             const WriteCallback& callback);
+
+  // Proxies File::SetTimes. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool SetTimes(Time last_access_time,
+                Time last_modified_time,
+                const StatusCallback& callback);
+
+  // Proxies File::SetLength. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool SetLength(int64 length, const StatusCallback& callback);
+
+  // Proxies File::Flush. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool Flush(const StatusCallback& callback);
+
+ private:
+  friend class FileHelper;
+  TaskRunner* task_runner() { return task_runner_.get(); }
+
+  scoped_refptr<TaskRunner> task_runner_;
+  File file_;
+  DISALLOW_COPY_AND_ASSIGN(FileProxy);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PROXY_H_
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc
new file mode 100644
index 0000000..df0bbc8
--- /dev/null
+++ b/base/files/file_proxy_unittest.cc
@@ -0,0 +1,369 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_proxy.h"
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FileProxyTest : public testing::Test {
+ public:
+  FileProxyTest()
+      : file_thread_("FileProxyTestFileThread"),
+        error_(File::FILE_OK),
+        bytes_written_(-1),
+        weak_factory_(this) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(file_thread_.Start());
+  }
+
+  void DidFinish(File::Error error) {
+    error_ = error;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidCreateOrOpen(File::Error error) {
+    error_ = error;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidCreateTemporary(File::Error error,
+                          const FilePath& path) {
+    error_ = error;
+    path_ = path;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidGetFileInfo(File::Error error,
+                      const File::Info& file_info) {
+    error_ = error;
+    file_info_ = file_info;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidRead(File::Error error,
+               const char* data,
+               int bytes_read) {
+    error_ = error;
+    buffer_.resize(bytes_read);
+    memcpy(&buffer_[0], data, bytes_read);
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidWrite(File::Error error,
+                int bytes_written) {
+    error_ = error;
+    bytes_written_ = bytes_written;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+ protected:
+  void CreateProxy(uint32 flags, FileProxy* proxy) {
+    proxy->CreateOrOpen(
+        test_path(), flags,
+        Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+    MessageLoop::current()->Run();
+    EXPECT_TRUE(proxy->IsValid());
+  }
+
+  TaskRunner* file_task_runner() const {
+    return file_thread_.task_runner().get();
+  }
+  const FilePath& test_dir_path() const { return dir_.path(); }
+  const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
+
+  MessageLoopForIO message_loop_;
+  Thread file_thread_;
+
+  ScopedTempDir dir_;
+  File::Error error_;
+  FilePath path_;
+  File::Info file_info_;
+  std::vector<char> buffer_;
+  int bytes_written_;
+  WeakPtrFactory<FileProxyTest> weak_factory_;
+};
+
+TEST_F(FileProxyTest, CreateOrOpen_Create) {
+  FileProxy proxy(file_task_runner());
+  proxy.CreateOrOpen(
+      test_path(),
+      File::FLAG_CREATE | File::FLAG_READ,
+      Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_TRUE(proxy.IsValid());
+  EXPECT_TRUE(proxy.created());
+  EXPECT_TRUE(PathExists(test_path()));
+}
+
+TEST_F(FileProxyTest, CreateOrOpen_Open) {
+  // Creates a file.
+  base::WriteFile(test_path(), NULL, 0);
+  ASSERT_TRUE(PathExists(test_path()));
+
+  // Opens the created file.
+  FileProxy proxy(file_task_runner());
+  proxy.CreateOrOpen(
+      test_path(),
+      File::FLAG_OPEN | File::FLAG_READ,
+      Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_TRUE(proxy.IsValid());
+  EXPECT_FALSE(proxy.created());
+}
+
+TEST_F(FileProxyTest, CreateOrOpen_OpenNonExistent) {
+  FileProxy proxy(file_task_runner());
+  proxy.CreateOrOpen(
+      test_path(),
+      File::FLAG_OPEN | File::FLAG_READ,
+      Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, error_);
+  EXPECT_FALSE(proxy.IsValid());
+  EXPECT_FALSE(proxy.created());
+  EXPECT_FALSE(PathExists(test_path()));
+}
+
+TEST_F(FileProxyTest, CreateOrOpen_AbandonedCreate) {
+  bool prev = ThreadRestrictions::SetIOAllowed(false);
+  {
+    FileProxy proxy(file_task_runner());
+    proxy.CreateOrOpen(
+        test_path(),
+        File::FLAG_CREATE | File::FLAG_READ,
+        Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  }
+  MessageLoop::current()->Run();
+  ThreadRestrictions::SetIOAllowed(prev);
+
+  EXPECT_TRUE(PathExists(test_path()));
+}
+
+TEST_F(FileProxyTest, Close) {
+  // Creates a file.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
+
+#if defined(OS_WIN)
+  // This fails on Windows if the file is not closed.
+  EXPECT_FALSE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
+#endif
+
+  proxy.Close(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_FALSE(proxy.IsValid());
+
+  // Now it should pass on all platforms.
+  EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
+}
+
+TEST_F(FileProxyTest, CreateTemporary) {
+  {
+    FileProxy proxy(file_task_runner());
+    proxy.CreateTemporary(
+        0 /* additional_file_flags */,
+        Bind(&FileProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr()));
+    MessageLoop::current()->Run();
+
+    EXPECT_TRUE(proxy.IsValid());
+    EXPECT_EQ(File::FILE_OK, error_);
+    EXPECT_TRUE(PathExists(path_));
+
+    // The file should be writable.
+    proxy.Write(0, "test", 4,
+                Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
+    MessageLoop::current()->Run();
+    EXPECT_EQ(File::FILE_OK, error_);
+    EXPECT_EQ(4, bytes_written_);
+  }
+
+  // Make sure the written data can be read from the returned path.
+  std::string data;
+  EXPECT_TRUE(ReadFileToString(path_, &data));
+  EXPECT_EQ("test", data);
+
+  // Make sure we can & do delete the created file to prevent leaks on the bots.
+  EXPECT_TRUE(base::DeleteFile(path_, false));
+}
+
+TEST_F(FileProxyTest, SetAndTake) {
+  File file(test_path(), File::FLAG_CREATE | File::FLAG_READ);
+  ASSERT_TRUE(file.IsValid());
+  FileProxy proxy(file_task_runner());
+  EXPECT_FALSE(proxy.IsValid());
+  proxy.SetFile(file.Pass());
+  EXPECT_TRUE(proxy.IsValid());
+  EXPECT_FALSE(file.IsValid());
+
+  file = proxy.TakeFile();
+  EXPECT_FALSE(proxy.IsValid());
+  EXPECT_TRUE(file.IsValid());
+}
+
+TEST_F(FileProxyTest, GetInfo) {
+  // Setup.
+  ASSERT_EQ(4, base::WriteFile(test_path(), "test", 4));
+  File::Info expected_info;
+  GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
+  proxy.GetInfo(
+      Bind(&FileProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileProxyTest, Read) {
+  // Setup.
+  const char expected_data[] = "bleh";
+  int expected_bytes = arraysize(expected_data);
+  ASSERT_EQ(expected_bytes,
+            base::WriteFile(test_path(), expected_data, expected_bytes));
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
+
+  proxy.Read(0, 128, Bind(&FileProxyTest::DidRead, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size()));
+  for (size_t i = 0; i < buffer_.size(); ++i) {
+    EXPECT_EQ(expected_data[i], buffer_[i]);
+  }
+}
+
+TEST_F(FileProxyTest, WriteAndFlush) {
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
+
+  const char data[] = "foo!";
+  int data_bytes = arraysize(data);
+  proxy.Write(0, data, data_bytes,
+              Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(data_bytes, bytes_written_);
+
+  // Flush the written data.  (So that the following read should always
+  // succeed.  On some platforms it may work with or without this flush.)
+  proxy.Flush(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+
+  // Verify the written data.
+  char buffer[10];
+  EXPECT_EQ(data_bytes, base::ReadFile(test_path(), buffer, data_bytes));
+  for (int i = 0; i < data_bytes; ++i) {
+    EXPECT_EQ(data[i], buffer[i]);
+  }
+}
+
+TEST_F(FileProxyTest, SetTimes) {
+  FileProxy proxy(file_task_runner());
+  CreateProxy(
+      File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES,
+      &proxy);
+
+  Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
+  Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
+
+  proxy.SetTimes(last_accessed_time, last_modified_time,
+                 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+
+  // The returned values may only have the seconds precision, so we cast
+  // the double values to int here.
+  EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
+            static_cast<int>(info.last_modified.ToDoubleT()));
+  EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
+            static_cast<int>(info.last_accessed.ToDoubleT()));
+}
+
+TEST_F(FileProxyTest, SetLength_Shrink) {
+  // Setup.
+  const char kTestData[] = "0123456789";
+  ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10));
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(10, info.size);
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
+  proxy.SetLength(7,
+                  Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(7, info.size);
+
+  char buffer[7];
+  EXPECT_EQ(7, base::ReadFile(test_path(), buffer, 7));
+  int i = 0;
+  for (; i < 7; ++i)
+    EXPECT_EQ(kTestData[i], buffer[i]);
+}
+
+TEST_F(FileProxyTest, SetLength_Expand) {
+  // Setup.
+  const char kTestData[] = "9876543210";
+  ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10));
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(10, info.size);
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
+  proxy.SetLength(53,
+                  Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(53, info.size);
+
+  char buffer[53];
+  EXPECT_EQ(53, base::ReadFile(test_path(), buffer, 53));
+  int i = 0;
+  for (; i < 10; ++i)
+    EXPECT_EQ(kTestData[i], buffer[i]);
+  for (; i < 53; ++i)
+    EXPECT_EQ(0, buffer[i]);
+}
+
+}  // namespace base
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
new file mode 100644
index 0000000..5c59424
--- /dev/null
+++ b/base/files/file_unittest.cc
@@ -0,0 +1,580 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::File;
+using base::FilePath;
+
+TEST(FileTest, Create) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+  {
+    // Don't create a File at all.
+    File file;
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_EQ(base::File::FILE_ERROR_FAILED, file.error_details());
+
+    File file2(base::File::FILE_ERROR_TOO_MANY_OPENED);
+    EXPECT_FALSE(file2.IsValid());
+    EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, file2.error_details());
+  }
+
+  {
+    // Open a file that doesn't exist.
+    File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
+  }
+
+  {
+    // Open or create a file.
+    File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  }
+
+  {
+    // Open an existing file.
+    File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+
+    // This time verify closing the file.
+    file.Close();
+    EXPECT_FALSE(file.IsValid());
+  }
+
+  {
+    // Open an existing file through Initialize
+    File file;
+    file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+
+    // This time verify closing the file.
+    file.Close();
+    EXPECT_FALSE(file.IsValid());
+  }
+
+  {
+    // Create a file that exists.
+    File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ);
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details());
+  }
+
+  {
+    // Create or overwrite a file.
+    File file(file_path,
+              base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  }
+
+  {
+    // Create a delete-on-close file.
+    file_path = temp_dir.path().AppendASCII("create_file_2");
+    File file(file_path,
+              base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
+                  base::File::FLAG_DELETE_ON_CLOSE);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  }
+
+  EXPECT_FALSE(base::PathExists(file_path));
+}
+
+TEST(FileTest, Async) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file");
+
+  {
+    File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_ASYNC);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.async());
+  }
+
+  {
+    File file(file_path, base::File::FLAG_OPEN_ALWAYS);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.async());
+  }
+}
+
+TEST(FileTest, DeleteOpenFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+  // Create a file.
+  File file(file_path,
+            base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
+                base::File::FLAG_SHARE_DELETE);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_TRUE(file.created());
+  EXPECT_EQ(base::File::FILE_OK, file.error_details());
+
+  // Open an existing file and mark it as delete on close.
+  File same_file(file_path,
+                 base::File::FLAG_OPEN | base::File::FLAG_DELETE_ON_CLOSE |
+                     base::File::FLAG_READ);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_FALSE(same_file.created());
+  EXPECT_EQ(base::File::FILE_OK, same_file.error_details());
+
+  // Close both handles and check that the file is gone.
+  file.Close();
+  same_file.Close();
+  EXPECT_FALSE(base::PathExists(file_path));
+}
+
+TEST(FileTest, ReadWrite) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("read_write_file");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+
+  char data_to_write[] = "test";
+  const int kTestDataSize = 4;
+
+  // Write 0 bytes to the file.
+  int bytes_written = file.Write(0, data_to_write, 0);
+  EXPECT_EQ(0, bytes_written);
+
+  // Write "test" to the file.
+  bytes_written = file.Write(0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Read from EOF.
+  char data_read_1[32];
+  int bytes_read = file.Read(kTestDataSize, data_read_1, kTestDataSize);
+  EXPECT_EQ(0, bytes_read);
+
+  // Read from somewhere in the middle of the file.
+  const int kPartialReadOffset = 1;
+  bytes_read = file.Read(kPartialReadOffset, data_read_1, kTestDataSize);
+  EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read);
+  for (int i = 0; i < bytes_read; i++)
+    EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
+
+  // Read 0 bytes.
+  bytes_read = file.Read(0, data_read_1, 0);
+  EXPECT_EQ(0, bytes_read);
+
+  // Read the entire file.
+  bytes_read = file.Read(0, data_read_1, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_read);
+  for (int i = 0; i < bytes_read; i++)
+    EXPECT_EQ(data_to_write[i], data_read_1[i]);
+
+  // Read again, but using the trivial native wrapper.
+  bytes_read = file.ReadNoBestEffort(0, data_read_1, kTestDataSize);
+  EXPECT_LE(bytes_read, kTestDataSize);
+  for (int i = 0; i < bytes_read; i++)
+    EXPECT_EQ(data_to_write[i], data_read_1[i]);
+
+  // Write past the end of the file.
+  const int kOffsetBeyondEndOfFile = 10;
+  const int kPartialWriteLength = 2;
+  bytes_written = file.Write(kOffsetBeyondEndOfFile,
+                             data_to_write, kPartialWriteLength);
+  EXPECT_EQ(kPartialWriteLength, bytes_written);
+
+  // Make sure the file was extended.
+  int64 file_size = 0;
+  EXPECT_TRUE(GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
+
+  // Make sure the file was zero-padded.
+  char data_read_2[32];
+  bytes_read = file.Read(0, data_read_2, static_cast<int>(file_size));
+  EXPECT_EQ(file_size, bytes_read);
+  for (int i = 0; i < kTestDataSize; i++)
+    EXPECT_EQ(data_to_write[i], data_read_2[i]);
+  for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++)
+    EXPECT_EQ(0, data_read_2[i]);
+  for (int i = kOffsetBeyondEndOfFile; i < file_size; i++)
+    EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]);
+}
+
+TEST(FileTest, Append) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("append_file");
+  File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_APPEND);
+  ASSERT_TRUE(file.IsValid());
+
+  char data_to_write[] = "test";
+  const int kTestDataSize = 4;
+
+  // Write 0 bytes to the file.
+  int bytes_written = file.Write(0, data_to_write, 0);
+  EXPECT_EQ(0, bytes_written);
+
+  // Write "test" to the file.
+  bytes_written = file.Write(0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  file.Close();
+  File file2(file_path,
+             base::File::FLAG_OPEN | base::File::FLAG_READ |
+                 base::File::FLAG_APPEND);
+  ASSERT_TRUE(file2.IsValid());
+
+  // Test passing the file around.
+  file = file2.Pass();
+  EXPECT_FALSE(file2.IsValid());
+  ASSERT_TRUE(file.IsValid());
+
+  char append_data_to_write[] = "78";
+  const int kAppendDataSize = 2;
+
+  // Append "78" to the file.
+  bytes_written = file.Write(0, append_data_to_write, kAppendDataSize);
+  EXPECT_EQ(kAppendDataSize, bytes_written);
+
+  // Read the entire file.
+  char data_read_1[32];
+  int bytes_read = file.Read(0, data_read_1,
+                             kTestDataSize + kAppendDataSize);
+  EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read);
+  for (int i = 0; i < kTestDataSize; i++)
+    EXPECT_EQ(data_to_write[i], data_read_1[i]);
+  for (int i = 0; i < kAppendDataSize; i++)
+    EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]);
+}
+
+
+TEST(FileTest, Length) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("truncate_file");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+  EXPECT_EQ(0, file.GetLength());
+
+  // Write "test" to the file.
+  char data_to_write[] = "test";
+  int kTestDataSize = 4;
+  int bytes_written = file.Write(0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Extend the file.
+  const int kExtendedFileLength = 10;
+  int64 file_size = 0;
+  EXPECT_TRUE(file.SetLength(kExtendedFileLength));
+  EXPECT_EQ(kExtendedFileLength, file.GetLength());
+  EXPECT_TRUE(GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kExtendedFileLength, file_size);
+
+  // Make sure the file was zero-padded.
+  char data_read[32];
+  int bytes_read = file.Read(0, data_read, static_cast<int>(file_size));
+  EXPECT_EQ(file_size, bytes_read);
+  for (int i = 0; i < kTestDataSize; i++)
+    EXPECT_EQ(data_to_write[i], data_read[i]);
+  for (int i = kTestDataSize; i < file_size; i++)
+    EXPECT_EQ(0, data_read[i]);
+
+  // Truncate the file.
+  const int kTruncatedFileLength = 2;
+  EXPECT_TRUE(file.SetLength(kTruncatedFileLength));
+  EXPECT_EQ(kTruncatedFileLength, file.GetLength());
+  EXPECT_TRUE(GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kTruncatedFileLength, file_size);
+
+  // Make sure the file was truncated.
+  bytes_read = file.Read(0, data_read, kTestDataSize);
+  EXPECT_EQ(file_size, bytes_read);
+  for (int i = 0; i < file_size; i++)
+    EXPECT_EQ(data_to_write[i], data_read[i]);
+}
+
+// Flakily fails: http://crbug.com/86494
+#if defined(OS_ANDROID)
+TEST(FileTest, TouchGetInfo) {
+#else
+TEST(FileTest, DISABLED_TouchGetInfo) {
+#endif
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  File file(temp_dir.path().AppendASCII("touch_get_info_file"),
+            base::File::FLAG_CREATE | base::File::FLAG_WRITE |
+                base::File::FLAG_WRITE_ATTRIBUTES);
+  ASSERT_TRUE(file.IsValid());
+
+  // Get info for a newly created file.
+  base::File::Info info;
+  EXPECT_TRUE(file.GetInfo(&info));
+
+  // Add 2 seconds to account for possible rounding errors on
+  // filesystems that use a 1s or 2s timestamp granularity.
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2);
+  EXPECT_EQ(0, info.size);
+  EXPECT_FALSE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+  EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
+  EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
+  EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
+  base::Time creation_time = info.creation_time;
+
+  // Write "test" to the file.
+  char data[] = "test";
+  const int kTestDataSize = 4;
+  int bytes_written = file.Write(0, data, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Change the last_accessed and last_modified dates.
+  // It's best to add values that are multiples of 2 (in seconds)
+  // to the current last_accessed and last_modified times, because
+  // FATxx uses a 2s timestamp granularity.
+  base::Time new_last_accessed =
+      info.last_accessed + base::TimeDelta::FromSeconds(234);
+  base::Time new_last_modified =
+      info.last_modified + base::TimeDelta::FromMinutes(567);
+
+  EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified));
+
+  // Make sure the file info was updated accordingly.
+  EXPECT_TRUE(file.GetInfo(&info));
+  EXPECT_EQ(info.size, kTestDataSize);
+  EXPECT_FALSE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+
+  // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
+#if defined(OS_POSIX)
+  EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
+            new_last_accessed.ToTimeVal().tv_sec);
+  EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
+            new_last_modified.ToTimeVal().tv_sec);
+#else
+  EXPECT_EQ(info.last_accessed.ToInternalValue(),
+            new_last_accessed.ToInternalValue());
+  EXPECT_EQ(info.last_modified.ToInternalValue(),
+            new_last_modified.ToInternalValue());
+#endif
+
+  EXPECT_EQ(info.creation_time.ToInternalValue(),
+            creation_time.ToInternalValue());
+}
+
+TEST(FileTest, ReadAtCurrentPosition) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("read_at_current_position");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+
+  const char kData[] = "test";
+  const int kDataSize = sizeof(kData) - 1;
+  EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize));
+
+  EXPECT_EQ(0, file.Seek(base::File::FROM_BEGIN, 0));
+
+  char buffer[kDataSize];
+  int first_chunk_size = kDataSize / 2;
+  EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size));
+  EXPECT_EQ(kDataSize - first_chunk_size,
+            file.ReadAtCurrentPos(buffer + first_chunk_size,
+                                  kDataSize - first_chunk_size));
+  EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
+}
+
+TEST(FileTest, WriteAtCurrentPosition) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("write_at_current_position");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+
+  const char kData[] = "test";
+  const int kDataSize = sizeof(kData) - 1;
+
+  int first_chunk_size = kDataSize / 2;
+  EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size));
+  EXPECT_EQ(kDataSize - first_chunk_size,
+            file.WriteAtCurrentPos(kData + first_chunk_size,
+                                   kDataSize - first_chunk_size));
+
+  char buffer[kDataSize];
+  EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize));
+  EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
+}
+
+TEST(FileTest, Seek) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("seek_file");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+
+  const int64 kOffset = 10;
+  EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset));
+  EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset));
+  EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset));
+  EXPECT_TRUE(file.SetLength(kOffset * 2));
+  EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset));
+}
+
+TEST(FileTest, Duplicate) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("file");
+  File file(file_path,(base::File::FLAG_CREATE |
+                       base::File::FLAG_READ |
+                       base::File::FLAG_WRITE));
+  ASSERT_TRUE(file.IsValid());
+
+  File file2(file.Duplicate());
+  ASSERT_TRUE(file2.IsValid());
+
+  // Write through one handle, close it, read through the other.
+  static const char kData[] = "now is a good time.";
+  static const int kDataLen = sizeof(kData) - 1;
+
+  ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0));
+  ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0));
+  ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
+  ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0));
+  ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0));
+  file.Close();
+  char buf[kDataLen];
+  ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
+  ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
+}
+
+TEST(FileTest, DuplicateDeleteOnClose) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("file");
+  File file(file_path,(base::File::FLAG_CREATE |
+                       base::File::FLAG_READ |
+                       base::File::FLAG_WRITE |
+                       base::File::FLAG_DELETE_ON_CLOSE));
+  ASSERT_TRUE(file.IsValid());
+  File file2(file.Duplicate());
+  ASSERT_TRUE(file2.IsValid());
+  file.Close();
+  file2.Close();
+  ASSERT_FALSE(base::PathExists(file_path));
+}
+
+#if defined(OS_WIN)
+TEST(FileTest, GetInfoForDirectory) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath empty_dir = temp_dir.path().Append(FILE_PATH_LITERAL("gpfi_test"));
+  ASSERT_TRUE(CreateDirectory(empty_dir));
+
+  base::File dir(
+      ::CreateFile(empty_dir.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+  ASSERT_TRUE(dir.IsValid());
+
+  base::File::Info info;
+  EXPECT_TRUE(dir.GetInfo(&info));
+  EXPECT_TRUE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+  EXPECT_EQ(0, info.size);
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && defined(GTEST_HAS_DEATH_TEST)
+TEST(FileTest, MemoryCorruption) {
+  {
+    // Test that changing the checksum value is detected.
+    base::File file;
+    EXPECT_NE(file.file_.file_memory_checksum_,
+              implicit_cast<unsigned int>(file.GetPlatformFile()));
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(file.IsValid(), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that changing the file descriptor value is detected.
+    base::File file;
+    file.file_.file_.reset(17);
+    EXPECT_DEATH(file.IsValid(), "");
+
+    // Do not crash on File::~File().
+    ignore_result(file.file_.file_.release());
+    file.file_.UpdateChecksum();
+  }
+
+  {
+    // Test that GetPlatformFile() checks for corruption.
+    base::File file;
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(file.GetPlatformFile(), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that the base::File destructor checks for corruption.
+    scoped_ptr<base::File> file(new File());
+    file->file_.file_memory_checksum_ = file->GetPlatformFile();
+    EXPECT_DEATH(file.reset(), "");
+
+    // Do not crash on this thread's destructor call.
+    file->file_.UpdateChecksum();
+  }
+
+  {
+    // Test that the base::File constructor checks for corruption.
+    base::File file;
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(File f(file.Pass()), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that doing IO checks for corruption.
+    base::File file;
+    file.file_.file_.reset(17);  // A fake open FD value.
+
+    EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), "");
+    EXPECT_DEATH(file.Read(0, NULL, 0), "");
+    EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), "");
+    EXPECT_DEATH(file.Write(0, NULL, 0), "");
+
+    ignore_result(file.file_.file_.release());
+    file.file_.UpdateChecksum();
+  }
+}
+#endif  // defined(OS_POSIX)
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
new file mode 100644
index 0000000..32dab6b
--- /dev/null
+++ b/base/files/file_util.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#endif
+#include <stdio.h>
+
+#include <fstream>
+#include <limits>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// The maximum number of 'uniquified' files we will try to create.
+// This is used when the filename we're trying to download is already in use,
+// so we create a new unique filename by appending " (nnn)" before the
+// extension, where 1 <= nnn <= kMaxUniqueFiles.
+// Also used by code that cleans up said files.
+static const int kMaxUniqueFiles = 100;
+
+}  // namespace
+
+int64 ComputeDirectorySize(const FilePath& root_path) {
+  int64 running_size = 0;
+  FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
+  while (!file_iter.Next().empty())
+    running_size += file_iter.GetInfo().GetSize();
+  return running_size;
+}
+
+bool Move(const FilePath& from_path, const FilePath& to_path) {
+  if (from_path.ReferencesParent() || to_path.ReferencesParent())
+    return false;
+  return internal::MoveUnsafe(from_path, to_path);
+}
+
+bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
+  // We open the file in binary format even if they are text files because
+  // we are just comparing that bytes are exactly same in both files and not
+  // doing anything smart with text formatting.
+  std::ifstream file1(filename1.value().c_str(),
+                      std::ios::in | std::ios::binary);
+  std::ifstream file2(filename2.value().c_str(),
+                      std::ios::in | std::ios::binary);
+
+  // Even if both files aren't openable (and thus, in some sense, "equal"),
+  // any unusable file yields a result of "false".
+  if (!file1.is_open() || !file2.is_open())
+    return false;
+
+  const int BUFFER_SIZE = 2056;
+  char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
+  do {
+    file1.read(buffer1, BUFFER_SIZE);
+    file2.read(buffer2, BUFFER_SIZE);
+
+    if ((file1.eof() != file2.eof()) ||
+        (file1.gcount() != file2.gcount()) ||
+        (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
+      file1.close();
+      file2.close();
+      return false;
+    }
+  } while (!file1.eof() || !file2.eof());
+
+  file1.close();
+  file2.close();
+  return true;
+}
+
+bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
+  std::ifstream file1(filename1.value().c_str(), std::ios::in);
+  std::ifstream file2(filename2.value().c_str(), std::ios::in);
+
+  // Even if both files aren't openable (and thus, in some sense, "equal"),
+  // any unusable file yields a result of "false".
+  if (!file1.is_open() || !file2.is_open())
+    return false;
+
+  do {
+    std::string line1, line2;
+    getline(file1, line1);
+    getline(file2, line2);
+
+    // Check for mismatched EOF states, or any error state.
+    if ((file1.eof() != file2.eof()) ||
+        file1.bad() || file2.bad()) {
+      return false;
+    }
+
+    // Trim all '\r' and '\n' characters from the end of the line.
+    std::string::size_type end1 = line1.find_last_not_of("\r\n");
+    if (end1 == std::string::npos)
+      line1.clear();
+    else if (end1 + 1 < line1.length())
+      line1.erase(end1 + 1);
+
+    std::string::size_type end2 = line2.find_last_not_of("\r\n");
+    if (end2 == std::string::npos)
+      line2.clear();
+    else if (end2 + 1 < line2.length())
+      line2.erase(end2 + 1);
+
+    if (line1 != line2)
+      return false;
+  } while (!file1.eof() || !file2.eof());
+
+  return true;
+}
+
+bool ReadFileToString(const FilePath& path,
+                      std::string* contents,
+                      size_t max_size) {
+  if (contents)
+    contents->clear();
+  if (path.ReferencesParent())
+    return false;
+  FILE* file = OpenFile(path, "rb");
+  if (!file) {
+    return false;
+  }
+
+  const size_t kBufferSize = 1 << 16;
+  scoped_ptr<char[]> buf(new char[kBufferSize]);
+  size_t len;
+  size_t size = 0;
+  bool read_status = true;
+
+  // Many files supplied in |path| have incorrect size (proc files etc).
+  // Hence, the file is read sequentially as opposed to a one-shot read.
+  while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
+    if (contents)
+      contents->append(buf.get(), std::min(len, max_size - size));
+
+    if ((max_size - size) < len) {
+      read_status = false;
+      break;
+    }
+
+    size += len;
+  }
+  read_status = read_status && !ferror(file);
+  CloseFile(file);
+
+  return read_status;
+}
+
+bool ReadFileToString(const FilePath& path, std::string* contents) {
+  return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
+}
+
+bool IsDirectoryEmpty(const FilePath& dir_path) {
+  FileEnumerator files(dir_path, false,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
+  if (files.Next().empty())
+    return true;
+  return false;
+}
+
+FILE* CreateAndOpenTemporaryFile(FilePath* path) {
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return NULL;
+
+  return CreateAndOpenTemporaryFileInDir(directory, path);
+}
+
+bool CreateDirectory(const FilePath& full_path) {
+  return CreateDirectoryAndGetError(full_path, NULL);
+}
+
+bool GetFileSize(const FilePath& file_path, int64* file_size) {
+  File::Info info;
+  if (!GetFileInfo(file_path, &info))
+    return false;
+  *file_size = info.size;
+  return true;
+}
+
+bool TouchFile(const FilePath& path,
+               const Time& last_accessed,
+               const Time& last_modified) {
+  int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
+
+#if defined(OS_WIN)
+  // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
+  if (DirectoryExists(path))
+    flags |= File::FLAG_BACKUP_SEMANTICS;
+#endif  // OS_WIN
+
+  File file(path, flags);
+  if (!file.IsValid())
+    return false;
+
+  return file.SetTimes(last_accessed, last_modified);
+}
+
+bool CloseFile(FILE* file) {
+  if (file == NULL)
+    return true;
+  return fclose(file) == 0;
+}
+
+bool TruncateFile(FILE* file) {
+  if (file == NULL)
+    return false;
+  long current_offset = ftell(file);
+  if (current_offset == -1)
+    return false;
+#if defined(OS_WIN)
+  int fd = _fileno(file);
+  if (_chsize(fd, current_offset) != 0)
+    return false;
+#else
+  int fd = fileno(file);
+  if (ftruncate(fd, current_offset) != 0)
+    return false;
+#endif
+  return true;
+}
+
+int GetUniquePathNumber(const FilePath& path,
+                        const FilePath::StringType& suffix) {
+  bool have_suffix = !suffix.empty();
+  if (!PathExists(path) &&
+      (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
+    return 0;
+  }
+
+  FilePath new_path;
+  for (int count = 1; count <= kMaxUniqueFiles; ++count) {
+    new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
+    if (!PathExists(new_path) &&
+        (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
+      return count;
+    }
+  }
+
+  return -1;
+}
+
+}  // namespace base
diff --git a/base/files/file_util.h b/base/files/file_util.h
new file mode 100644
index 0000000..7f169f1
--- /dev/null
+++ b/base/files/file_util.h
@@ -0,0 +1,436 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains utility functions for dealing with the local
+// filesystem.
+
+#ifndef BASE_FILES_FILE_UTIL_H_
+#define BASE_FILES_FILE_UTIL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#endif
+
+namespace base {
+
+class Time;
+
+//-----------------------------------------------------------------------------
+// Functions that involve filesystem access or modification:
+
+// Returns an absolute version of a relative path. Returns an empty path on
+// error. On POSIX, this function fails if the path does not exist. This
+// function can result in I/O so it can be slow.
+BASE_EXPORT FilePath MakeAbsoluteFilePath(const FilePath& input);
+
+// Returns the total number of bytes used by all the files under |root_path|.
+// If the path does not exist the function returns 0.
+//
+// This function is implemented using the FileEnumerator class so it is not
+// particularly speedy in any platform.
+BASE_EXPORT int64 ComputeDirectorySize(const FilePath& root_path);
+
+// Deletes the given path, whether it's a file or a directory.
+// If it's a directory, it's perfectly happy to delete all of the
+// directory's contents.  Passing true to recursive deletes
+// subdirectories and their contents as well.
+// Returns true if successful, false otherwise. It is considered successful
+// to attempt to delete a file that does not exist.
+//
+// In posix environment and if |path| is a symbolic link, this deletes only
+// the symlink. (even if the symlink points to a non-existent file)
+//
+// WARNING: USING THIS WITH recursive==true IS EQUIVALENT
+//          TO "rm -rf", SO USE WITH CAUTION.
+BASE_EXPORT bool DeleteFile(const FilePath& path, bool recursive);
+
+#if defined(OS_WIN)
+// Schedules to delete the given path, whether it's a file or a directory, until
+// the operating system is restarted.
+// Note:
+// 1) The file/directory to be deleted should exist in a temp folder.
+// 2) The directory to be deleted must be empty.
+BASE_EXPORT bool DeleteFileAfterReboot(const FilePath& path);
+#endif
+
+// Moves the given path, whether it's a file or a directory.
+// If a simple rename is not possible, such as in the case where the paths are
+// on different volumes, this will attempt to copy and delete. Returns
+// true for success.
+// This function fails if either path contains traversal components ('..').
+BASE_EXPORT bool Move(const FilePath& from_path, const FilePath& to_path);
+
+// Renames file |from_path| to |to_path|. Both paths must be on the same
+// volume, or the function will fail. Destination file will be created
+// if it doesn't exist. Prefer this function over Move when dealing with
+// temporary files. On Windows it preserves attributes of the target file.
+// Returns true on success, leaving *error unchanged.
+// Returns false on failure and sets *error appropriately, if it is non-NULL.
+BASE_EXPORT bool ReplaceFile(const FilePath& from_path,
+                             const FilePath& to_path,
+                             File::Error* error);
+
+// Copies a single file. Use CopyDirectory to copy directories.
+// This function fails if either path contains traversal components ('..').
+//
+// This function keeps the metadata on Windows. The read only bit on Windows is
+// not kept.
+BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path);
+
+// Copies the given path, and optionally all subdirectories and their contents
+// as well.
+//
+// If there are files existing under to_path, always overwrite. Returns true
+// if successful, false otherwise. Wildcards on the names are not supported.
+//
+// This function calls into CopyFile() so the same behavior w.r.t. metadata
+// applies.
+//
+// If you only need to copy a file use CopyFile, it's faster.
+BASE_EXPORT bool CopyDirectory(const FilePath& from_path,
+                               const FilePath& to_path,
+                               bool recursive);
+
+// Returns true if the given path exists on the local filesystem,
+// false otherwise.
+BASE_EXPORT bool PathExists(const FilePath& path);
+
+// Returns true if the given path is writable by the user, false otherwise.
+BASE_EXPORT bool PathIsWritable(const FilePath& path);
+
+// Returns true if the given path exists and is a directory, false otherwise.
+BASE_EXPORT bool DirectoryExists(const FilePath& path);
+
+// Returns true if the contents of the two files given are equal, false
+// otherwise.  If either file can't be read, returns false.
+BASE_EXPORT bool ContentsEqual(const FilePath& filename1,
+                               const FilePath& filename2);
+
+// Returns true if the contents of the two text files given are equal, false
+// otherwise.  This routine treats "\r\n" and "\n" as equivalent.
+BASE_EXPORT bool TextContentsEqual(const FilePath& filename1,
+                                   const FilePath& filename2);
+
+// Reads the file at |path| into |contents| and returns true on success and
+// false on error.  For security reasons, a |path| containing path traversal
+// components ('..') is treated as a read error and |contents| is set to empty.
+// In case of I/O error, |contents| holds the data that could be read from the
+// file before the error occurred.
+// |contents| may be NULL, in which case this function is useful for its side
+// effect of priming the disk cache (could be used for unit tests).
+BASE_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents);
+
+// Reads the file at |path| into |contents| and returns true on success and
+// false on error.  For security reasons, a |path| containing path traversal
+// components ('..') is treated as a read error and |contents| is set to empty.
+// In case of I/O error, |contents| holds the data that could be read from the
+// file before the error occurred.  When the file size exceeds |max_size|, the
+// function returns false with |contents| holding the file truncated to
+// |max_size|.
+// |contents| may be NULL, in which case this function is useful for its side
+// effect of priming the disk cache (could be used for unit tests).
+BASE_EXPORT bool ReadFileToString(const FilePath& path,
+                                  std::string* contents,
+                                  size_t max_size);
+
+#if defined(OS_POSIX)
+
+// Read exactly |bytes| bytes from file descriptor |fd|, storing the result
+// in |buffer|. This function is protected against EINTR and partial reads.
+// Returns true iff |bytes| bytes have been successfully read from |fd|.
+BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
+
+// Creates a symbolic link at |symlink| pointing to |target|.  Returns
+// false on failure.
+BASE_EXPORT bool CreateSymbolicLink(const FilePath& target,
+                                    const FilePath& symlink);
+
+// Reads the given |symlink| and returns where it points to in |target|.
+// Returns false upon failure.
+BASE_EXPORT bool ReadSymbolicLink(const FilePath& symlink, FilePath* target);
+
+// Bits and masks of the file permission.
+enum FilePermissionBits {
+  FILE_PERMISSION_MASK              = S_IRWXU | S_IRWXG | S_IRWXO,
+  FILE_PERMISSION_USER_MASK         = S_IRWXU,
+  FILE_PERMISSION_GROUP_MASK        = S_IRWXG,
+  FILE_PERMISSION_OTHERS_MASK       = S_IRWXO,
+
+  FILE_PERMISSION_READ_BY_USER      = S_IRUSR,
+  FILE_PERMISSION_WRITE_BY_USER     = S_IWUSR,
+  FILE_PERMISSION_EXECUTE_BY_USER   = S_IXUSR,
+  FILE_PERMISSION_READ_BY_GROUP     = S_IRGRP,
+  FILE_PERMISSION_WRITE_BY_GROUP    = S_IWGRP,
+  FILE_PERMISSION_EXECUTE_BY_GROUP  = S_IXGRP,
+  FILE_PERMISSION_READ_BY_OTHERS    = S_IROTH,
+  FILE_PERMISSION_WRITE_BY_OTHERS   = S_IWOTH,
+  FILE_PERMISSION_EXECUTE_BY_OTHERS = S_IXOTH,
+};
+
+// Reads the permission of the given |path|, storing the file permission
+// bits in |mode|. If |path| is symbolic link, |mode| is the permission of
+// a file which the symlink points to.
+BASE_EXPORT bool GetPosixFilePermissions(const FilePath& path, int* mode);
+// Sets the permission of the given |path|. If |path| is symbolic link, sets
+// the permission of a file which the symlink points to.
+BASE_EXPORT bool SetPosixFilePermissions(const FilePath& path, int mode);
+
+#endif  // OS_POSIX
+
+// Returns true if the given directory is empty
+BASE_EXPORT bool IsDirectoryEmpty(const FilePath& dir_path);
+
+// Get the temporary directory provided by the system.
+//
+// WARNING: In general, you should use CreateTemporaryFile variants below
+// instead of this function. Those variants will ensure that the proper
+// permissions are set so that other users on the system can't edit them while
+// they're open (which can lead to security issues).
+BASE_EXPORT bool GetTempDir(FilePath* path);
+
+// Get the home directory. This is more complicated than just getenv("HOME")
+// as it knows to fall back on getpwent() etc.
+//
+// You should not generally call this directly. Instead use DIR_HOME with the
+// path service which will use this function but cache the value.
+// Path service may also override DIR_HOME.
+BASE_EXPORT FilePath GetHomeDir();
+
+// Creates a temporary file. The full path is placed in |path|, and the
+// function returns true if was successful in creating the file. The file will
+// be empty and all handles closed after this function returns.
+BASE_EXPORT bool CreateTemporaryFile(FilePath* path);
+
+// Same as CreateTemporaryFile but the file is created in |dir|.
+BASE_EXPORT bool CreateTemporaryFileInDir(const FilePath& dir,
+                                          FilePath* temp_file);
+
+// Create and open a temporary file.  File is opened for read/write.
+// The full path is placed in |path|.
+// Returns a handle to the opened file or NULL if an error occurred.
+BASE_EXPORT FILE* CreateAndOpenTemporaryFile(FilePath* path);
+
+// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|.
+BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir,
+                                                  FilePath* path);
+
+// Create a new directory. If prefix is provided, the new directory name is in
+// the format of prefixyyyy.
+// NOTE: prefix is ignored in the POSIX implementation.
+// If success, return true and output the full path of the directory created.
+BASE_EXPORT bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                                        FilePath* new_temp_path);
+
+// Create a directory within another directory.
+// Extra characters will be appended to |prefix| to ensure that the
+// new directory does not have the same name as an existing directory.
+BASE_EXPORT bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                                         const FilePath::StringType& prefix,
+                                         FilePath* new_dir);
+
+// Creates a directory, as well as creating any parent directories, if they
+// don't exist. Returns 'true' on successful creation, or if the directory
+// already exists.  The directory is only readable by the current user.
+// Returns true on success, leaving *error unchanged.
+// Returns false on failure and sets *error appropriately, if it is non-NULL.
+BASE_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path,
+                                            File::Error* error);
+
+// Backward-compatible convenience method for the above.
+BASE_EXPORT bool CreateDirectory(const FilePath& full_path);
+
+// Returns the file size. Returns true on success.
+BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64* file_size);
+
+// Sets |real_path| to |path| with symbolic links and junctions expanded.
+// On windows, make sure the path starts with a lettered drive.
+// |path| must reference a file.  Function will fail if |path| points to
+// a directory or to a nonexistent path.  On windows, this function will
+// fail if |path| is a junction or symlink that points to an empty file,
+// or if |real_path| would be longer than MAX_PATH characters.
+BASE_EXPORT bool NormalizeFilePath(const FilePath& path, FilePath* real_path);
+
+#if defined(OS_WIN)
+
+// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."),
+// return in |drive_letter_path| the equivalent path that starts with
+// a drive letter ("C:\...").  Return false if no such path exists.
+BASE_EXPORT bool DevicePathToDriveLetterPath(const FilePath& device_path,
+                                             FilePath* drive_letter_path);
+
+// Given an existing file in |path|, set |real_path| to the path
+// in native NT format, of the form "\Device\HarddiskVolumeXX\..".
+// Returns false if the path can not be found. Empty files cannot
+// be resolved with this function.
+BASE_EXPORT bool NormalizeToNativeFilePath(const FilePath& path,
+                                           FilePath* nt_path);
+#endif
+
+// This function will return if the given file is a symlink or not.
+BASE_EXPORT bool IsLink(const FilePath& file_path);
+
+// Returns information about the given file path.
+BASE_EXPORT bool GetFileInfo(const FilePath& file_path, File::Info* info);
+
+// Sets the time of the last access and the time of the last modification.
+BASE_EXPORT bool TouchFile(const FilePath& path,
+                           const Time& last_accessed,
+                           const Time& last_modified);
+
+// Wrapper for fopen-like calls. Returns non-NULL FILE* on success.
+BASE_EXPORT FILE* OpenFile(const FilePath& filename, const char* mode);
+
+// Closes file opened by OpenFile. Returns true on success.
+BASE_EXPORT bool CloseFile(FILE* file);
+
+// Associates a standard FILE stream with an existing File. Note that this
+// functions take ownership of the existing File.
+BASE_EXPORT FILE* FileToFILE(File file, const char* mode);
+
+// Truncates an open file to end at the location of the current file pointer.
+// This is a cross-platform analog to Windows' SetEndOfFile() function.
+BASE_EXPORT bool TruncateFile(FILE* file);
+
+// Reads at most the given number of bytes from the file into the buffer.
+// Returns the number of read bytes, or -1 on error.
+BASE_EXPORT int ReadFile(const FilePath& filename, char* data, int max_size);
+
+// Writes the given buffer into the file, overwriting any data that was
+// previously there.  Returns the number of bytes written, or -1 on error.
+BASE_EXPORT int WriteFile(const FilePath& filename, const char* data,
+                          int size);
+
+#if defined(OS_POSIX)
+// Appends |data| to |fd|. Does not close |fd| when done.  Returns true iff
+// |size| bytes of |data| were written to |fd|.
+BASE_EXPORT bool WriteFileDescriptor(const int fd, const char* data, int size);
+#endif
+
+// Appends |data| to |filename|.  Returns true iff |size| bytes of |data| were
+// written to |filename|.
+BASE_EXPORT bool AppendToFile(const FilePath& filename,
+                              const char* data,
+                              int size);
+
+// Gets the current working directory for the process.
+BASE_EXPORT bool GetCurrentDirectory(FilePath* path);
+
+// Sets the current working directory for the process.
+BASE_EXPORT bool SetCurrentDirectory(const FilePath& path);
+
+// Attempts to find a number that can be appended to the |path| to make it
+// unique. If |path| does not exist, 0 is returned.  If it fails to find such
+// a number, -1 is returned. If |suffix| is not empty, also checks the
+// existence of it with the given suffix.
+BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
+                                    const FilePath::StringType& suffix);
+
+#if defined(OS_POSIX)
+// Test that |path| can only be changed by a given user and members of
+// a given set of groups.
+// Specifically, test that all parts of |path| under (and including) |base|:
+// * Exist.
+// * Are owned by a specific user.
+// * Are not writable by all users.
+// * Are owned by a member of a given set of groups, or are not writable by
+//   their group.
+// * Are not symbolic links.
+// This is useful for checking that a config file is administrator-controlled.
+// |base| must contain |path|.
+BASE_EXPORT bool VerifyPathControlledByUser(const base::FilePath& base,
+                                            const base::FilePath& path,
+                                            uid_t owner_uid,
+                                            const std::set<gid_t>& group_gids);
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// Is |path| writable only by a user with administrator privileges?
+// This function uses Mac OS conventions.  The super user is assumed to have
+// uid 0, and the administrator group is assumed to be named "admin".
+// Testing that |path|, and every parent directory including the root of
+// the filesystem, are owned by the superuser, controlled by the group
+// "admin", are not writable by all users, and contain no symbolic links.
+// Will return false if |path| does not exist.
+BASE_EXPORT bool VerifyPathControlledByAdmin(const base::FilePath& path);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+// Returns the maximum length of path component on the volume containing
+// the directory |path|, in the number of FilePath::CharType, or -1 on failure.
+BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path);
+
+#if defined(OS_LINUX)
+// Broad categories of file systems as returned by statfs() on Linux.
+enum FileSystemType {
+  FILE_SYSTEM_UNKNOWN,  // statfs failed.
+  FILE_SYSTEM_0,        // statfs.f_type == 0 means unknown, may indicate AFS.
+  FILE_SYSTEM_ORDINARY,       // on-disk filesystem like ext2
+  FILE_SYSTEM_NFS,
+  FILE_SYSTEM_SMB,
+  FILE_SYSTEM_CODA,
+  FILE_SYSTEM_MEMORY,         // in-memory file system
+  FILE_SYSTEM_CGROUP,         // cgroup control.
+  FILE_SYSTEM_OTHER,          // any other value.
+  FILE_SYSTEM_TYPE_COUNT
+};
+
+// Attempts determine the FileSystemType for |path|.
+// Returns false if |path| doesn't exist.
+BASE_EXPORT bool GetFileSystemType(const FilePath& path, FileSystemType* type);
+#endif
+
+#if defined(OS_POSIX)
+// Get a temporary directory for shared memory files. The directory may depend
+// on whether the destination is intended for executable files, which in turn
+// depends on how /dev/shmem was mounted. As a result, you must supply whether
+// you intend to create executable shmem segments so this function can find
+// an appropriate location.
+BASE_EXPORT bool GetShmemTempDir(bool executable, FilePath* path);
+#endif
+
+// Internal --------------------------------------------------------------------
+
+namespace internal {
+
+// Same as Move but allows paths with traversal components.
+// Use only with extreme care.
+BASE_EXPORT bool MoveUnsafe(const FilePath& from_path,
+                            const FilePath& to_path);
+
+#if defined(OS_WIN)
+// Copy from_path to to_path recursively and then delete from_path recursively.
+// Returns true if all operations succeed.
+// This function simulates Move(), but unlike Move() it works across volumes.
+// This function is not transactional.
+BASE_EXPORT bool CopyAndDeleteDirectory(const FilePath& from_path,
+                                        const FilePath& to_path);
+#endif  // defined(OS_WIN)
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_UTIL_H_
diff --git a/base/files/file_util_android.cc b/base/files/file_util_android.cc
new file mode 100644
index 0000000..b8b3b37
--- /dev/null
+++ b/base/files/file_util_android.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+
+namespace base {
+
+bool GetShmemTempDir(bool executable, base::FilePath* path) {
+  return PathService::Get(base::DIR_CACHE, path);
+}
+
+}  // namespace base
diff --git a/base/files/file_util_linux.cc b/base/files/file_util_linux.cc
new file mode 100644
index 0000000..b230fd9
--- /dev/null
+++ b/base/files/file_util_linux.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+
+#include <errno.h>
+#include <linux/magic.h>
+#include <sys/vfs.h>
+
+#include "base/files/file_path.h"
+
+namespace base {
+
+bool GetFileSystemType(const FilePath& path, FileSystemType* type) {
+  struct statfs statfs_buf;
+  if (statfs(path.value().c_str(), &statfs_buf) < 0) {
+    if (errno == ENOENT)
+      return false;
+    *type = FILE_SYSTEM_UNKNOWN;
+    return true;
+  }
+
+  // Not all possible |statfs_buf.f_type| values are in linux/magic.h.
+  // Missing values are copied from the statfs man page.
+  switch (statfs_buf.f_type) {
+    case 0:
+      *type = FILE_SYSTEM_0;
+      break;
+    case EXT2_SUPER_MAGIC:  // Also ext3 and ext4
+    case MSDOS_SUPER_MAGIC:
+    case REISERFS_SUPER_MAGIC:
+    case BTRFS_SUPER_MAGIC:
+    case 0x5346544E:  // NTFS
+    case 0x58465342:  // XFS
+    case 0x3153464A:  // JFS
+      *type = FILE_SYSTEM_ORDINARY;
+      break;
+    case NFS_SUPER_MAGIC:
+      *type = FILE_SYSTEM_NFS;
+      break;
+    case SMB_SUPER_MAGIC:
+    case 0xFF534D42:  // CIFS
+      *type = FILE_SYSTEM_SMB;
+      break;
+    case CODA_SUPER_MAGIC:
+      *type = FILE_SYSTEM_CODA;
+      break;
+    case HUGETLBFS_MAGIC:
+    case RAMFS_MAGIC:
+    case TMPFS_MAGIC:
+      *type = FILE_SYSTEM_MEMORY;
+      break;
+    case CGROUP_SUPER_MAGIC:
+      *type = FILE_SYSTEM_CGROUP;
+      break;
+    default:
+      *type = FILE_SYSTEM_OTHER;
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/files/file_util_mac.mm b/base/files/file_util_mac.mm
new file mode 100644
index 0000000..acac8d7
--- /dev/null
+++ b/base/files/file_util_mac.mm
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+
+#import <Foundation/Foundation.h>
+#include <copyfile.h>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (from_path.ReferencesParent() || to_path.ReferencesParent())
+    return false;
+  return (copyfile(from_path.value().c_str(),
+                   to_path.value().c_str(), NULL, COPYFILE_DATA) == 0);
+}
+
+bool GetTempDir(base::FilePath* path) {
+  NSString* tmp = NSTemporaryDirectory();
+  if (tmp == nil)
+    return false;
+  *path = base::mac::NSStringToFilePath(tmp);
+  return true;
+}
+
+FilePath GetHomeDir() {
+  NSString* tmp = NSHomeDirectory();
+  if (tmp != nil) {
+    FilePath mac_home_dir = base::mac::NSStringToFilePath(tmp);
+    if (!mac_home_dir.empty())
+      return mac_home_dir;
+  }
+
+  // Fall back on temp dir if no home directory is defined.
+  FilePath rv;
+  if (GetTempDir(&rv))
+    return rv;
+
+  // Last resort.
+  return FilePath("/tmp");
+}
+
+}  // namespace base
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
new file mode 100644
index 0000000..b4a64ba
--- /dev/null
+++ b/base/files/file_util_posix.cc
@@ -0,0 +1,932 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#include "base/mac/foundation_util.h"
+#elif !defined(OS_CHROMEOS) && defined(USE_GLIB)
+#include <glib.h>  // for g_get_home_dir()
+#endif
+
+#include "base/basictypes.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/content_uri_utils.h"
+#include "base/os_compat_android.h"
+#endif
+
+#if !defined(OS_IOS)
+#include <grp.h>
+#endif
+
+namespace base {
+
+namespace {
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+static int CallStat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return stat(path, sb);
+}
+static int CallLstat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return lstat(path, sb);
+}
+#else  //  defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+static int CallStat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return stat64(path, sb);
+}
+static int CallLstat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return lstat64(path, sb);
+}
+#endif  // !(defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL))
+
+#if !defined(OS_NACL_NONSFI)
+// Helper for NormalizeFilePath(), defined below.
+bool RealPath(const FilePath& path, FilePath* real_path) {
+  ThreadRestrictions::AssertIOAllowed();  // For realpath().
+  FilePath::CharType buf[PATH_MAX];
+  if (!realpath(path.value().c_str(), buf))
+    return false;
+
+  *real_path = FilePath(buf);
+  return true;
+}
+
+// Helper for VerifyPathControlledByUser.
+bool VerifySpecificPathControlledByUser(const FilePath& path,
+                                        uid_t owner_uid,
+                                        const std::set<gid_t>& group_gids) {
+  stat_wrapper_t stat_info;
+  if (CallLstat(path.value().c_str(), &stat_info) != 0) {
+    DPLOG(ERROR) << "Failed to get information on path "
+                 << path.value();
+    return false;
+  }
+
+  if (S_ISLNK(stat_info.st_mode)) {
+    DLOG(ERROR) << "Path " << path.value()
+               << " is a symbolic link.";
+    return false;
+  }
+
+  if (stat_info.st_uid != owner_uid) {
+    DLOG(ERROR) << "Path " << path.value()
+                << " is owned by the wrong user.";
+    return false;
+  }
+
+  if ((stat_info.st_mode & S_IWGRP) &&
+      !ContainsKey(group_gids, stat_info.st_gid)) {
+    DLOG(ERROR) << "Path " << path.value()
+                << " is writable by an unprivileged group.";
+    return false;
+  }
+
+  if (stat_info.st_mode & S_IWOTH) {
+    DLOG(ERROR) << "Path " << path.value()
+                << " is writable by any user.";
+    return false;
+  }
+
+  return true;
+}
+
+std::string TempFileName() {
+#if defined(OS_MACOSX)
+  return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID());
+#endif
+
+#if defined(GOOGLE_CHROME_BUILD)
+  return std::string(".com.google.Chrome.XXXXXX");
+#else
+  return std::string(".org.chromium.Chromium.XXXXXX");
+#endif
+}
+
+// Creates and opens a temporary file in |directory|, returning the
+// file descriptor. |path| is set to the temporary file path.
+// This function does NOT unlink() the file.
+int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to mkstemp().
+  *path = directory.Append(base::TempFileName());
+  const std::string& tmpdir_string = path->value();
+  // this should be OK since mkstemp just replaces characters in place
+  char* buffer = const_cast<char*>(tmpdir_string.c_str());
+
+  return HANDLE_EINTR(mkstemp(buffer));
+}
+
+#if defined(OS_LINUX)
+// Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC.
+// This depends on the mount options used for /dev/shm, which vary among
+// different Linux distributions and possibly local configuration.  It also
+// depends on details of kernel--ChromeOS uses the noexec option for /dev/shm
+// but its kernel allows mprotect with PROT_EXEC anyway.
+bool DetermineDevShmExecutable() {
+  bool result = false;
+  FilePath path;
+
+  ScopedFD fd(CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path));
+  if (fd.is_valid()) {
+    DeleteFile(path, false);
+    long sysconf_result = sysconf(_SC_PAGESIZE);
+    CHECK_GE(sysconf_result, 0);
+    size_t pagesize = static_cast<size_t>(sysconf_result);
+    CHECK_GE(sizeof(pagesize), sizeof(sysconf_result));
+    void* mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd.get(), 0);
+    if (mapping != MAP_FAILED) {
+      if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0)
+        result = true;
+      munmap(mapping, pagesize);
+    }
+  }
+  return result;
+}
+#endif  // defined(OS_LINUX)
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace
+
+#if !defined(OS_NACL_NONSFI)
+FilePath MakeAbsoluteFilePath(const FilePath& input) {
+  ThreadRestrictions::AssertIOAllowed();
+  char full_path[PATH_MAX];
+  if (realpath(input.value().c_str(), full_path) == NULL)
+    return FilePath();
+  return FilePath(full_path);
+}
+
+// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
+// which works both with and without the recursive flag.  I'm not sure we need
+// that functionality. If not, remove from file_util_win.cc, otherwise add it
+// here.
+bool DeleteFile(const FilePath& path, bool recursive) {
+  ThreadRestrictions::AssertIOAllowed();
+  const char* path_str = path.value().c_str();
+  stat_wrapper_t file_info;
+  int test = CallLstat(path_str, &file_info);
+  if (test != 0) {
+    // The Windows version defines this condition as success.
+    bool ret = (errno == ENOENT || errno == ENOTDIR);
+    return ret;
+  }
+  if (!S_ISDIR(file_info.st_mode))
+    return (unlink(path_str) == 0);
+  if (!recursive)
+    return (rmdir(path_str) == 0);
+
+  bool success = true;
+  std::stack<std::string> directories;
+  directories.push(path.value());
+  FileEnumerator traversal(path, true,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
+      FileEnumerator::SHOW_SYM_LINKS);
+  for (FilePath current = traversal.Next(); success && !current.empty();
+       current = traversal.Next()) {
+    if (traversal.GetInfo().IsDirectory())
+      directories.push(current.value());
+    else
+      success = (unlink(current.value().c_str()) == 0);
+  }
+
+  while (success && !directories.empty()) {
+    FilePath dir = FilePath(directories.top());
+    directories.pop();
+    success = (rmdir(dir.value().c_str()) == 0);
+  }
+  return success;
+}
+
+bool ReplaceFile(const FilePath& from_path,
+                 const FilePath& to_path,
+                 File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
+    return true;
+  if (error)
+    *error = File::OSErrorToFileError(errno);
+  return false;
+}
+
+bool CopyDirectory(const FilePath& from_path,
+                   const FilePath& to_path,
+                   bool recursive) {
+  ThreadRestrictions::AssertIOAllowed();
+  // Some old callers of CopyDirectory want it to support wildcards.
+  // After some discussion, we decided to fix those callers.
+  // Break loudly here if anyone tries to do this.
+  DCHECK(to_path.value().find('*') == std::string::npos);
+  DCHECK(from_path.value().find('*') == std::string::npos);
+
+  if (from_path.value().size() >= PATH_MAX) {
+    return false;
+  }
+
+  // This function does not properly handle destinations within the source
+  FilePath real_to_path = to_path;
+  if (PathExists(real_to_path)) {
+    real_to_path = MakeAbsoluteFilePath(real_to_path);
+    if (real_to_path.empty())
+      return false;
+  } else {
+    real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
+    if (real_to_path.empty())
+      return false;
+  }
+  FilePath real_from_path = MakeAbsoluteFilePath(from_path);
+  if (real_from_path.empty())
+    return false;
+  if (real_to_path.value().size() >= real_from_path.value().size() &&
+      real_to_path.value().compare(0, real_from_path.value().size(),
+                                   real_from_path.value()) == 0) {
+    return false;
+  }
+
+  int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS;
+  if (recursive)
+    traverse_type |= FileEnumerator::DIRECTORIES;
+  FileEnumerator traversal(from_path, recursive, traverse_type);
+
+  // We have to mimic windows behavior here. |to_path| may not exist yet,
+  // start the loop with |to_path|.
+  struct stat from_stat;
+  FilePath current = from_path;
+  if (stat(from_path.value().c_str(), &from_stat) < 0) {
+    DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
+                << from_path.value() << " errno = " << errno;
+    return false;
+  }
+  struct stat to_path_stat;
+  FilePath from_path_base = from_path;
+  if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 &&
+      S_ISDIR(to_path_stat.st_mode)) {
+    // If the destination already exists and is a directory, then the
+    // top level of source needs to be copied.
+    from_path_base = from_path.DirName();
+  }
+
+  // The Windows version of this function assumes that non-recursive calls
+  // will always have a directory for from_path.
+  // TODO(maruel): This is not necessary anymore.
+  DCHECK(recursive || S_ISDIR(from_stat.st_mode));
+
+  bool success = true;
+  while (success && !current.empty()) {
+    // current is the source path, including from_path, so append
+    // the suffix after from_path to to_path to create the target_path.
+    FilePath target_path(to_path);
+    if (from_path_base != current) {
+      if (!from_path_base.AppendRelativePath(current, &target_path)) {
+        success = false;
+        break;
+      }
+    }
+
+    if (S_ISDIR(from_stat.st_mode)) {
+      if (mkdir(target_path.value().c_str(),
+                (from_stat.st_mode & 01777) | S_IRUSR | S_IXUSR | S_IWUSR) !=
+              0 &&
+          errno != EEXIST) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
+                    << target_path.value() << " errno = " << errno;
+        success = false;
+      }
+    } else if (S_ISREG(from_stat.st_mode)) {
+      if (!CopyFile(current, target_path)) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create file: "
+                    << target_path.value();
+        success = false;
+      }
+    } else {
+      DLOG(WARNING) << "CopyDirectory() skipping non-regular file: "
+                    << current.value();
+    }
+
+    current = traversal.Next();
+    if (!current.empty())
+      from_stat = traversal.GetInfo().stat();
+  }
+
+  return success;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool PathExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+#if defined(OS_ANDROID)
+  if (path.IsContentUri()) {
+    return ContentUriExists(path);
+  }
+#endif
+  return access(path.value().c_str(), F_OK) == 0;
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool PathIsWritable(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  return access(path.value().c_str(), W_OK) == 0;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool DirectoryExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  stat_wrapper_t file_info;
+  if (CallStat(path.value().c_str(), &file_info) == 0)
+    return S_ISDIR(file_info.st_mode);
+  return false;
+}
+
+bool ReadFromFD(int fd, char* buffer, size_t bytes) {
+  size_t total_read = 0;
+  while (total_read < bytes) {
+    ssize_t bytes_read =
+        HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
+    if (bytes_read <= 0)
+      break;
+    total_read += bytes_read;
+  }
+  return total_read == bytes;
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool CreateSymbolicLink(const FilePath& target_path,
+                        const FilePath& symlink_path) {
+  DCHECK(!symlink_path.empty());
+  DCHECK(!target_path.empty());
+  return ::symlink(target_path.value().c_str(),
+                   symlink_path.value().c_str()) != -1;
+}
+
+bool ReadSymbolicLink(const FilePath& symlink_path, FilePath* target_path) {
+  DCHECK(!symlink_path.empty());
+  DCHECK(target_path);
+  char buf[PATH_MAX];
+  ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
+
+  if (count <= 0) {
+    target_path->clear();
+    return false;
+  }
+
+  *target_path = FilePath(FilePath::StringType(buf, count));
+  return true;
+}
+
+bool GetPosixFilePermissions(const FilePath& path, int* mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(mode);
+
+  stat_wrapper_t file_info;
+  // Uses stat(), because on symbolic link, lstat() does not return valid
+  // permission bits in st_mode
+  if (CallStat(path.value().c_str(), &file_info) != 0)
+    return false;
+
+  *mode = file_info.st_mode & FILE_PERMISSION_MASK;
+  return true;
+}
+
+bool SetPosixFilePermissions(const FilePath& path,
+                             int mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0);
+
+  // Calls stat() so that we can preserve the higher bits like S_ISGID.
+  stat_wrapper_t stat_buf;
+  if (CallStat(path.value().c_str(), &stat_buf) != 0)
+    return false;
+
+  // Clears the existing permission bits, and adds the new ones.
+  mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK;
+  updated_mode_bits |= mode & FILE_PERMISSION_MASK;
+
+  if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0)
+    return false;
+
+  return true;
+}
+
+#if !defined(OS_MACOSX)
+// This is implemented in file_util_mac.mm for Mac.
+bool GetTempDir(FilePath* path) {
+  const char* tmp = getenv("TMPDIR");
+  if (tmp) {
+    *path = FilePath(tmp);
+  } else {
+#if defined(OS_ANDROID)
+    return PathService::Get(base::DIR_CACHE, path);
+#else
+    *path = FilePath("/tmp");
+#endif
+  }
+  return true;
+}
+#endif  // !defined(OS_MACOSX)
+
+#if !defined(OS_MACOSX)  // Mac implementation is in file_util_mac.mm.
+FilePath GetHomeDir() {
+#if defined(OS_CHROMEOS)
+  if (SysInfo::IsRunningOnChromeOS()) {
+    // On Chrome OS chrome::DIR_USER_DATA is overridden with a primary user
+    // homedir once it becomes available. Return / as the safe option.
+    return FilePath("/");
+  }
+#endif
+
+  const char* home_dir = getenv("HOME");
+  if (home_dir && home_dir[0])
+    return FilePath(home_dir);
+
+#if defined(OS_ANDROID)
+  DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented.";
+#elif defined(USE_GLIB) && !defined(OS_CHROMEOS)
+  // g_get_home_dir calls getpwent, which can fall through to LDAP calls so
+  // this may do I/O. However, it should be rare that $HOME is not defined and
+  // this is typically called from the path service which has no threading
+  // restrictions. The path service will cache the result which limits the
+  // badness of blocking on I/O. As a result, we don't have a thread
+  // restriction here.
+  home_dir = g_get_home_dir();
+  if (home_dir && home_dir[0])
+    return FilePath(home_dir);
+#endif
+
+  FilePath rv;
+  if (GetTempDir(&rv))
+    return rv;
+
+  // Last resort.
+  return FilePath("/tmp");
+}
+#endif  // !defined(OS_MACOSX)
+
+bool CreateTemporaryFile(FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to close().
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return false;
+  int fd = CreateAndOpenFdForTemporaryFile(directory, path);
+  if (fd < 0)
+    return false;
+  close(fd);
+  return true;
+}
+
+FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+  int fd = CreateAndOpenFdForTemporaryFile(dir, path);
+  if (fd < 0)
+    return NULL;
+
+  FILE* file = fdopen(fd, "a+");
+  if (!file)
+    close(fd);
+  return file;
+}
+
+bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to close().
+  int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
+  return ((fd >= 0) && !IGNORE_EINTR(close(fd)));
+}
+
+static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
+                                        const FilePath::StringType& name_tmpl,
+                                        FilePath* new_dir) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to mkdtemp().
+  DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
+      << "Directory name template must contain \"XXXXXX\".";
+
+  FilePath sub_dir = base_dir.Append(name_tmpl);
+  std::string sub_dir_string = sub_dir.value();
+
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer = const_cast<char*>(sub_dir_string.c_str());
+  char* dtemp = mkdtemp(buffer);
+  if (!dtemp) {
+    DPLOG(ERROR) << "mkdtemp";
+    return false;
+  }
+  *new_dir = FilePath(dtemp);
+  return true;
+}
+
+bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                             const FilePath::StringType& prefix,
+                             FilePath* new_dir) {
+  FilePath::StringType mkdtemp_template = prefix;
+  mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
+  return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
+}
+
+bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                            FilePath* new_temp_path) {
+  FilePath tmpdir;
+  if (!GetTempDir(&tmpdir))
+    return false;
+
+  return CreateTemporaryDirInDirImpl(tmpdir, TempFileName(), new_temp_path);
+}
+
+bool CreateDirectoryAndGetError(const FilePath& full_path,
+                                File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to mkdir().
+  std::vector<FilePath> subpaths;
+
+  // Collect a list of all parent directories.
+  FilePath last_path = full_path;
+  subpaths.push_back(full_path);
+  for (FilePath path = full_path.DirName();
+       path.value() != last_path.value(); path = path.DirName()) {
+    subpaths.push_back(path);
+    last_path = path;
+  }
+
+  // Iterate through the parents and create the missing ones.
+  for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
+       i != subpaths.rend(); ++i) {
+    if (DirectoryExists(*i))
+      continue;
+    if (mkdir(i->value().c_str(), 0700) == 0)
+      continue;
+    // Mkdir failed, but it might have failed with EEXIST, or some other error
+    // due to the the directory appearing out of thin air. This can occur if
+    // two processes are trying to create the same file system tree at the same
+    // time. Check to see if it exists and make sure it is a directory.
+    int saved_errno = errno;
+    if (!DirectoryExists(*i)) {
+      if (error)
+        *error = File::OSErrorToFileError(saved_errno);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) {
+  FilePath real_path_result;
+  if (!RealPath(path, &real_path_result))
+    return false;
+
+  // To be consistant with windows, fail if |real_path_result| is a
+  // directory.
+  stat_wrapper_t file_info;
+  if (CallStat(real_path_result.value().c_str(), &file_info) != 0 ||
+      S_ISDIR(file_info.st_mode))
+    return false;
+
+  *normalized_path = real_path_result;
+  return true;
+}
+
+// TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks
+// correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948
+bool IsLink(const FilePath& file_path) {
+  stat_wrapper_t st;
+  // If we can't lstat the file, it's safe to assume that the file won't at
+  // least be a 'followable' link.
+  if (CallLstat(file_path.value().c_str(), &st) != 0)
+    return false;
+
+  if (S_ISLNK(st.st_mode))
+    return true;
+  else
+    return false;
+}
+
+bool GetFileInfo(const FilePath& file_path, File::Info* results) {
+  stat_wrapper_t file_info;
+#if defined(OS_ANDROID)
+  if (file_path.IsContentUri()) {
+    File file = OpenContentUriForRead(file_path);
+    if (!file.IsValid())
+      return false;
+    return file.GetInfo(results);
+  } else {
+#endif  // defined(OS_ANDROID)
+    if (CallStat(file_path.value().c_str(), &file_info) != 0)
+      return false;
+#if defined(OS_ANDROID)
+  }
+#endif  // defined(OS_ANDROID)
+
+  results->FromStat(file_info);
+  return true;
+}
+
+FILE* OpenFile(const FilePath& filename, const char* mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  FILE* result = NULL;
+  do {
+    result = fopen(filename.value().c_str(), mode);
+  } while (!result && errno == EINTR);
+  return result;
+}
+
+// NaCl doesn't implement system calls to open files directly.
+#if !defined(OS_NACL)
+FILE* FileToFILE(File file, const char* mode) {
+  FILE* stream = fdopen(file.GetPlatformFile(), mode);
+  if (stream)
+    file.TakePlatformFile();
+  return stream;
+}
+#endif  // !defined(OS_NACL)
+
+int ReadFile(const FilePath& filename, char* data, int max_size) {
+  ThreadRestrictions::AssertIOAllowed();
+  int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY));
+  if (fd < 0)
+    return -1;
+
+  ssize_t bytes_read = HANDLE_EINTR(read(fd, data, max_size));
+  if (IGNORE_EINTR(close(fd)) < 0)
+    return -1;
+  return bytes_read;
+}
+
+int WriteFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0640));
+  if (fd < 0)
+    return -1;
+
+  int bytes_written = WriteFileDescriptor(fd, data, size) ? size : -1;
+  if (IGNORE_EINTR(close(fd)) < 0)
+    return -1;
+  return bytes_written;
+}
+
+bool WriteFileDescriptor(const int fd, const char* data, int size) {
+  // Allow for partial writes.
+  ssize_t bytes_written_total = 0;
+  for (ssize_t bytes_written_partial = 0; bytes_written_total < size;
+       bytes_written_total += bytes_written_partial) {
+    bytes_written_partial =
+        HANDLE_EINTR(write(fd, data + bytes_written_total,
+                           size - bytes_written_total));
+    if (bytes_written_partial < 0)
+      return false;
+  }
+
+  return true;
+}
+
+bool AppendToFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  bool ret = true;
+  int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND));
+  if (fd < 0) {
+    VPLOG(1) << "Unable to create file " << filename.value();
+    return false;
+  }
+
+  // This call will either write all of the data or return false.
+  if (!WriteFileDescriptor(fd, data, size)) {
+    VPLOG(1) << "Error while writing to file " << filename.value();
+    ret = false;
+  }
+
+  if (IGNORE_EINTR(close(fd)) < 0) {
+    VPLOG(1) << "Error while closing file " << filename.value();
+    return false;
+  }
+
+  return ret;
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(FilePath* dir) {
+  // getcwd can return ENOENT, which implies it checks against the disk.
+  ThreadRestrictions::AssertIOAllowed();
+
+  char system_buffer[PATH_MAX] = "";
+  if (!getcwd(system_buffer, sizeof(system_buffer))) {
+    NOTREACHED();
+    return false;
+  }
+  *dir = FilePath(system_buffer);
+  return true;
+}
+
+// Sets the current working directory for the process.
+bool SetCurrentDirectory(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  int ret = chdir(path.value().c_str());
+  return !ret;
+}
+
+bool VerifyPathControlledByUser(const FilePath& base,
+                                const FilePath& path,
+                                uid_t owner_uid,
+                                const std::set<gid_t>& group_gids) {
+  if (base != path && !base.IsParent(path)) {
+     DLOG(ERROR) << "|base| must be a subdirectory of |path|.  base = \""
+                 << base.value() << "\", path = \"" << path.value() << "\"";
+     return false;
+  }
+
+  std::vector<FilePath::StringType> base_components;
+  std::vector<FilePath::StringType> path_components;
+
+  base.GetComponents(&base_components);
+  path.GetComponents(&path_components);
+
+  std::vector<FilePath::StringType>::const_iterator ib, ip;
+  for (ib = base_components.begin(), ip = path_components.begin();
+       ib != base_components.end(); ++ib, ++ip) {
+    // |base| must be a subpath of |path|, so all components should match.
+    // If these CHECKs fail, look at the test that base is a parent of
+    // path at the top of this function.
+    DCHECK(ip != path_components.end());
+    DCHECK(*ip == *ib);
+  }
+
+  FilePath current_path = base;
+  if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids))
+    return false;
+
+  for (; ip != path_components.end(); ++ip) {
+    current_path = current_path.Append(*ip);
+    if (!VerifySpecificPathControlledByUser(
+            current_path, owner_uid, group_gids))
+      return false;
+  }
+  return true;
+}
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+bool VerifyPathControlledByAdmin(const FilePath& path) {
+  const unsigned kRootUid = 0;
+  const FilePath kFileSystemRoot("/");
+
+  // The name of the administrator group on mac os.
+  const char* const kAdminGroupNames[] = {
+    "admin",
+    "wheel"
+  };
+
+  // Reading the groups database may touch the file system.
+  ThreadRestrictions::AssertIOAllowed();
+
+  std::set<gid_t> allowed_group_ids;
+  for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) {
+    struct group *group_record = getgrnam(kAdminGroupNames[i]);
+    if (!group_record) {
+      DPLOG(ERROR) << "Could not get the group ID of group \""
+                   << kAdminGroupNames[i] << "\".";
+      continue;
+    }
+
+    allowed_group_ids.insert(group_record->gr_gid);
+  }
+
+  return VerifyPathControlledByUser(
+      kFileSystemRoot, path, kRootUid, allowed_group_ids);
+}
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+int GetMaximumPathComponentLength(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  return pathconf(path.value().c_str(), _PC_NAME_MAX);
+}
+
+#if !defined(OS_ANDROID)
+// This is implemented in file_util_android.cc for that platform.
+bool GetShmemTempDir(bool executable, FilePath* path) {
+#if defined(OS_LINUX)
+  bool use_dev_shm = true;
+  if (executable) {
+    static const bool s_dev_shm_executable = DetermineDevShmExecutable();
+    use_dev_shm = s_dev_shm_executable;
+  }
+  if (use_dev_shm) {
+    *path = FilePath("/dev/shm");
+    return true;
+  }
+#endif
+  return GetTempDir(path);
+}
+#endif  // !defined(OS_ANDROID)
+
+#if !defined(OS_MACOSX)
+// Mac has its own implementation, this is for all other Posix systems.
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  File infile;
+#if defined(OS_ANDROID)
+  if (from_path.IsContentUri()) {
+    infile = OpenContentUriForRead(from_path);
+  } else {
+    infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+  }
+#else
+  infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+#endif
+  if (!infile.IsValid())
+    return false;
+
+  File outfile(to_path, File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
+  if (!outfile.IsValid())
+    return false;
+
+  const size_t kBufferSize = 32768;
+  std::vector<char> buffer(kBufferSize);
+  bool result = true;
+
+  while (result) {
+    ssize_t bytes_read = infile.ReadAtCurrentPos(&buffer[0], buffer.size());
+    if (bytes_read < 0) {
+      result = false;
+      break;
+    }
+    if (bytes_read == 0)
+      break;
+    // Allow for partial writes
+    ssize_t bytes_written_per_read = 0;
+    do {
+      ssize_t bytes_written_partial = outfile.WriteAtCurrentPos(
+          &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read);
+      if (bytes_written_partial < 0) {
+        result = false;
+        break;
+      }
+      bytes_written_per_read += bytes_written_partial;
+    } while (bytes_written_per_read < bytes_read);
+  }
+
+  return result;
+}
+#endif  // !defined(OS_MACOSX)
+
+// -----------------------------------------------------------------------------
+
+namespace internal {
+
+bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  // Windows compatibility: if to_path exists, from_path and to_path
+  // must be the same type, either both files, or both directories.
+  stat_wrapper_t to_file_info;
+  if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
+    stat_wrapper_t from_file_info;
+    if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
+      if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
+        return false;
+    } else {
+      return false;
+    }
+  }
+
+  if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
+    return true;
+
+  if (!CopyDirectory(from_path, to_path, true))
+    return false;
+
+  DeleteFile(from_path, true);
+  return true;
+}
+
+}  // namespace internal
+
+#endif  // !defined(OS_NACL_NONSFI)
+}  // namespace base
diff --git a/base/files/file_util_proxy.cc b/base/files/file_util_proxy.cc
new file mode 100644
index 0000000..0942e7a
--- /dev/null
+++ b/base/files/file_util_proxy.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+
+namespace base {
+
+namespace {
+
+void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback,
+                                 bool value) {
+  DCHECK(!callback.is_null());
+  callback.Run(value ? File::FILE_OK : File::FILE_ERROR_FAILED);
+}
+
+class GetFileInfoHelper {
+ public:
+  GetFileInfoHelper()
+      : error_(File::FILE_OK) {}
+
+  void RunWorkForFilePath(const FilePath& file_path) {
+    if (!PathExists(file_path)) {
+      error_ = File::FILE_ERROR_NOT_FOUND;
+      return;
+    }
+    if (!GetFileInfo(file_path, &file_info_))
+      error_ = File::FILE_ERROR_FAILED;
+  }
+
+  void Reply(const FileUtilProxy::GetFileInfoCallback& callback) {
+    if (!callback.is_null()) {
+      callback.Run(error_, file_info_);
+    }
+  }
+
+ private:
+  File::Error error_;
+  File::Info file_info_;
+  DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
+};
+
+File::Error DeleteAdapter(const FilePath& file_path, bool recursive) {
+  if (!PathExists(file_path)) {
+    return File::FILE_ERROR_NOT_FOUND;
+  }
+  if (!base::DeleteFile(file_path, recursive)) {
+    if (!recursive && !base::IsDirectoryEmpty(file_path)) {
+      return File::FILE_ERROR_NOT_EMPTY;
+    }
+    return File::FILE_ERROR_FAILED;
+  }
+  return File::FILE_OK;
+}
+
+}  // namespace
+
+// Retrieves the information about a file. It is invalid to pass NULL for the
+// callback.
+bool FileUtilProxy::GetFileInfo(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const GetFileInfoCallback& callback) {
+  GetFileInfoHelper* helper = new GetFileInfoHelper;
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GetFileInfoHelper::RunWorkForFilePath,
+           Unretained(helper), file_path),
+      Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::DeleteFile(TaskRunner* task_runner,
+                               const FilePath& file_path,
+                               bool recursive,
+                               const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner, FROM_HERE,
+      Bind(&DeleteAdapter, file_path, recursive),
+      callback);
+}
+
+// static
+bool FileUtilProxy::Touch(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const Time& last_access_time,
+    const Time& last_modified_time,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner,
+      FROM_HERE,
+      Bind(&TouchFile, file_path, last_access_time, last_modified_time),
+      Bind(&CallWithTranslatedParameter, callback));
+}
+
+}  // namespace base
diff --git a/base/files/file_util_proxy.h b/base/files/file_util_proxy.h
new file mode 100644
index 0000000..80688cf
--- /dev/null
+++ b/base/files/file_util_proxy.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_UTIL_PROXY_H_
+#define BASE_FILES_FILE_UTIL_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+
+namespace base {
+
+class TaskRunner;
+class Time;
+
+// This class provides asynchronous access to common file routines.
+class BASE_EXPORT FileUtilProxy {
+ public:
+  // This callback is used by methods that report only an error code.  It is
+  // valid to pass a null callback to any function that takes a StatusCallback,
+  // in which case the operation will complete silently.
+  typedef Callback<void(File::Error)> StatusCallback;
+
+  typedef Callback<void(File::Error,
+                        const File::Info&)> GetFileInfoCallback;
+
+  // Retrieves the information about a file. It is invalid to pass a null
+  // callback.
+  // This returns false if task posting to |task_runner| has failed.
+  static bool GetFileInfo(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const GetFileInfoCallback& callback);
+
+  // Deletes a file or a directory.
+  // It is an error to delete a non-empty directory with recursive=false.
+  // This returns false if task posting to |task_runner| has failed.
+  static bool DeleteFile(TaskRunner* task_runner,
+                         const FilePath& file_path,
+                         bool recursive,
+                         const StatusCallback& callback);
+
+  // Touches a file. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  static bool Touch(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const Time& last_access_time,
+      const Time& last_modified_time,
+      const StatusCallback& callback);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilProxy);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_UTIL_PROXY_H_
diff --git a/base/files/file_util_proxy_unittest.cc b/base/files/file_util_proxy_unittest.cc
new file mode 100644
index 0000000..7408369
--- /dev/null
+++ b/base/files/file_util_proxy_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util_proxy.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FileUtilProxyTest : public testing::Test {
+ public:
+  FileUtilProxyTest()
+      : file_thread_("FileUtilProxyTestFileThread"),
+        error_(File::FILE_OK),
+        weak_factory_(this) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(file_thread_.Start());
+  }
+
+  void DidFinish(File::Error error) {
+    error_ = error;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidGetFileInfo(File::Error error,
+                      const File::Info& file_info) {
+    error_ = error;
+    file_info_ = file_info;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+ protected:
+  TaskRunner* file_task_runner() const {
+    return file_thread_.task_runner().get();
+  }
+  const FilePath& test_dir_path() const { return dir_.path(); }
+  const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
+
+  MessageLoopForIO message_loop_;
+  Thread file_thread_;
+
+  ScopedTempDir dir_;
+  File::Error error_;
+  FilePath path_;
+  File::Info file_info_;
+  std::vector<char> buffer_;
+  WeakPtrFactory<FileUtilProxyTest> weak_factory_;
+};
+
+
+TEST_F(FileUtilProxyTest, GetFileInfo_File) {
+  // Setup.
+  ASSERT_EQ(4, WriteFile(test_path(), "test", 4));
+  File::Info expected_info;
+  GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileUtilProxy::GetFileInfo(
+      file_task_runner(),
+      test_path(),
+      Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileUtilProxyTest, GetFileInfo_Directory) {
+  // Setup.
+  ASSERT_TRUE(base::CreateDirectory(test_path()));
+  File::Info expected_info;
+  GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileUtilProxy::GetFileInfo(
+      file_task_runner(),
+      test_path(),
+      Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileUtilProxyTest, Touch) {
+  ASSERT_EQ(4, WriteFile(test_path(), "test", 4));
+  Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
+  Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
+
+  FileUtilProxy::Touch(
+      file_task_runner(),
+      test_path(),
+      last_accessed_time,
+      last_modified_time,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+
+  // The returned values may only have the seconds precision, so we cast
+  // the double values to int here.
+  EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
+            static_cast<int>(info.last_modified.ToDoubleT()));
+  EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
+            static_cast<int>(info.last_accessed.ToDoubleT()));
+}
+
+}  // namespace base
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
new file mode 100644
index 0000000..b107b0f
--- /dev/null
+++ b/base/files/file_util_unittest.cc
@@ -0,0 +1,2620 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+#include <winioctl.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#include <algorithm>
+#include <fstream>
+#include <set>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_file_util.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/android/content_uri_utils.h"
+#endif
+
+// This macro helps avoid wrapped lines in the test structs.
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+namespace base {
+
+namespace {
+
+// To test that NormalizeFilePath() deals with NTFS reparse points correctly,
+// we need functions to create and delete reparse points.
+#if defined(OS_WIN)
+typedef struct _REPARSE_DATA_BUFFER {
+  ULONG  ReparseTag;
+  USHORT  ReparseDataLength;
+  USHORT  Reserved;
+  union {
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      ULONG Flags;
+      WCHAR PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      WCHAR PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct {
+      UCHAR DataBuffer[1];
+    } GenericReparseBuffer;
+  };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+// Sets a reparse point. |source| will now point to |target|. Returns true if
+// the call succeeds, false otherwise.
+bool SetReparsePoint(HANDLE source, const FilePath& target_path) {
+  std::wstring kPathPrefix = L"\\??\\";
+  std::wstring target_str;
+  // The juction will not work if the target path does not start with \??\ .
+  if (kPathPrefix != target_path.value().substr(0, kPathPrefix.size()))
+    target_str += kPathPrefix;
+  target_str += target_path.value();
+  const wchar_t* target = target_str.c_str();
+  USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]);
+  char buffer[2000] = {0};
+  DWORD returned;
+
+  REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
+
+  data->ReparseTag = 0xa0000003;
+  memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2);
+
+  data->MountPointReparseBuffer.SubstituteNameLength = size_target;
+  data->MountPointReparseBuffer.PrintNameOffset = size_target + 2;
+  data->ReparseDataLength = size_target + 4 + 8;
+
+  int data_size = data->ReparseDataLength + 8;
+
+  if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size,
+                       NULL, 0, &returned, NULL)) {
+    return false;
+  }
+  return true;
+}
+
+// Delete the reparse point referenced by |source|. Returns true if the call
+// succeeds, false otherwise.
+bool DeleteReparsePoint(HANDLE source) {
+  DWORD returned;
+  REPARSE_DATA_BUFFER data = {0};
+  data.ReparseTag = 0xa0000003;
+  if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0,
+                       &returned, NULL)) {
+    return false;
+  }
+  return true;
+}
+
+// Manages a reparse point for a test.
+class ReparsePoint {
+ public:
+  // Creates a reparse point from |source| (an empty directory) to |target|.
+  ReparsePoint(const FilePath& source, const FilePath& target) {
+    dir_.Set(
+      ::CreateFile(source.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+    created_ = dir_.IsValid() && SetReparsePoint(dir_.Get(), target);
+  }
+
+  ~ReparsePoint() {
+    if (created_)
+      DeleteReparsePoint(dir_.Get());
+  }
+
+  bool IsValid() { return created_; }
+
+ private:
+  win::ScopedHandle dir_;
+  bool created_;
+  DISALLOW_COPY_AND_ASSIGN(ReparsePoint);
+};
+
+#endif
+
+#if defined(OS_POSIX)
+// Provide a simple way to change the permissions bits on |path| in tests.
+// ASSERT failures will return, but not stop the test.  Caller should wrap
+// calls to this function in ASSERT_NO_FATAL_FAILURE().
+void ChangePosixFilePermissions(const FilePath& path,
+                                int mode_bits_to_set,
+                                int mode_bits_to_clear) {
+  ASSERT_FALSE(mode_bits_to_set & mode_bits_to_clear)
+      << "Can't set and clear the same bits.";
+
+  int mode = 0;
+  ASSERT_TRUE(GetPosixFilePermissions(path, &mode));
+  mode |= mode_bits_to_set;
+  mode &= ~mode_bits_to_clear;
+  ASSERT_TRUE(SetPosixFilePermissions(path, mode));
+}
+#endif  // defined(OS_POSIX)
+
+const wchar_t bogus_content[] = L"I'm cannon fodder.";
+
+const int FILES_AND_DIRECTORIES =
+    FileEnumerator::FILES | FileEnumerator::DIRECTORIES;
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+class FileUtilTest : public PlatformTest {
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+  ScopedTempDir temp_dir_;
+};
+
+// Collects all the results from the given file enumerator, and provides an
+// interface to query whether a given file is present.
+class FindResultCollector {
+ public:
+  explicit FindResultCollector(FileEnumerator* enumerator) {
+    FilePath cur_file;
+    while (!(cur_file = enumerator->Next()).value().empty()) {
+      FilePath::StringType path = cur_file.value();
+      // The file should not be returned twice.
+      EXPECT_TRUE(files_.end() == files_.find(path))
+          << "Same file returned twice";
+
+      // Save for later.
+      files_.insert(path);
+    }
+  }
+
+  // Returns true if the enumerator found the file.
+  bool HasFile(const FilePath& file) const {
+    return files_.find(file.value()) != files_.end();
+  }
+
+  int size() {
+    return static_cast<int>(files_.size());
+  }
+
+ private:
+  std::set<FilePath::StringType> files_;
+};
+
+// Simple function to dump some text into a new file.
+void CreateTextFile(const FilePath& filename,
+                    const std::wstring& contents) {
+  std::wofstream file;
+  file.open(filename.value().c_str());
+  ASSERT_TRUE(file.is_open());
+  file << contents;
+  file.close();
+}
+
+// Simple function to take out some text from a file.
+std::wstring ReadTextFile(const FilePath& filename) {
+  wchar_t contents[64];
+  std::wifstream file;
+  file.open(filename.value().c_str());
+  EXPECT_TRUE(file.is_open());
+  file.getline(contents, arraysize(contents));
+  file.close();
+  return std::wstring(contents);
+}
+
+#if defined(OS_WIN)
+uint64 FileTimeAsUint64(const FILETIME& ft) {
+  ULARGE_INTEGER u;
+  u.LowPart = ft.dwLowDateTime;
+  u.HighPart = ft.dwHighDateTime;
+  return u.QuadPart;
+}
+#endif
+
+TEST_F(FileUtilTest, FileAndDirectorySize) {
+  // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize
+  // should return 53 bytes.
+  FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt"));
+  CreateTextFile(file_01, L"12345678901234567890");
+  int64 size_f1 = 0;
+  ASSERT_TRUE(GetFileSize(file_01, &size_f1));
+  EXPECT_EQ(20ll, size_f1);
+
+  FilePath subdir_path = temp_dir_.path().Append(FPL("Level2"));
+  CreateDirectory(subdir_path);
+
+  FilePath file_02 = subdir_path.Append(FPL("The file 02.txt"));
+  CreateTextFile(file_02, L"123456789012345678901234567890");
+  int64 size_f2 = 0;
+  ASSERT_TRUE(GetFileSize(file_02, &size_f2));
+  EXPECT_EQ(30ll, size_f2);
+
+  FilePath subsubdir_path = subdir_path.Append(FPL("Level3"));
+  CreateDirectory(subsubdir_path);
+
+  FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt"));
+  CreateTextFile(file_03, L"123");
+
+  int64 computed_size = ComputeDirectorySize(temp_dir_.path());
+  EXPECT_EQ(size_f1 + size_f2 + 3, computed_size);
+}
+
+TEST_F(FileUtilTest, NormalizeFilePathBasic) {
+  // Create a directory under the test dir.  Because we create it,
+  // we know it is not a link.
+  FilePath file_a_path = temp_dir_.path().Append(FPL("file_a"));
+  FilePath dir_path = temp_dir_.path().Append(FPL("dir"));
+  FilePath file_b_path = dir_path.Append(FPL("file_b"));
+  CreateDirectory(dir_path);
+
+  FilePath normalized_file_a_path, normalized_file_b_path;
+  ASSERT_FALSE(PathExists(file_a_path));
+  ASSERT_FALSE(NormalizeFilePath(file_a_path, &normalized_file_a_path))
+    << "NormalizeFilePath() should fail on nonexistent paths.";
+
+  CreateTextFile(file_a_path, bogus_content);
+  ASSERT_TRUE(PathExists(file_a_path));
+  ASSERT_TRUE(NormalizeFilePath(file_a_path, &normalized_file_a_path));
+
+  CreateTextFile(file_b_path, bogus_content);
+  ASSERT_TRUE(PathExists(file_b_path));
+  ASSERT_TRUE(NormalizeFilePath(file_b_path, &normalized_file_b_path));
+
+  // Beacuse this test created |dir_path|, we know it is not a link
+  // or junction.  So, the real path of the directory holding file a
+  // must be the parent of the path holding file b.
+  ASSERT_TRUE(normalized_file_a_path.DirName()
+      .IsParent(normalized_file_b_path.DirName()));
+}
+
+#if defined(OS_WIN)
+
+TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
+  // Build the following directory structure:
+  //
+  // temp_dir
+  // |-> base_a
+  // |   |-> sub_a
+  // |       |-> file.txt
+  // |       |-> long_name___... (Very long name.)
+  // |           |-> sub_long
+  // |              |-> deep.txt
+  // |-> base_b
+  //     |-> to_sub_a (reparse point to temp_dir\base_a\sub_a)
+  //     |-> to_base_b (reparse point to temp_dir\base_b)
+  //     |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long)
+
+  FilePath base_a = temp_dir_.path().Append(FPL("base_a"));
+#if defined(OS_WIN)
+  // TEMP can have a lower case drive letter.
+  string16 temp_base_a = base_a.value();
+  ASSERT_FALSE(temp_base_a.empty());
+  *temp_base_a.begin() = base::ToUpperASCII(*temp_base_a.begin());
+  base_a = FilePath(temp_base_a);
+#endif
+  ASSERT_TRUE(CreateDirectory(base_a));
+
+  FilePath sub_a = base_a.Append(FPL("sub_a"));
+  ASSERT_TRUE(CreateDirectory(sub_a));
+
+  FilePath file_txt = sub_a.Append(FPL("file.txt"));
+  CreateTextFile(file_txt, bogus_content);
+
+  // Want a directory whose name is long enough to make the path to the file
+  // inside just under MAX_PATH chars.  This will be used to test that when
+  // a junction expands to a path over MAX_PATH chars in length,
+  // NormalizeFilePath() fails without crashing.
+  FilePath sub_long_rel(FPL("sub_long"));
+  FilePath deep_txt(FPL("deep.txt"));
+
+  int target_length = MAX_PATH;
+  target_length -= (sub_a.value().length() + 1);  // +1 for the sepperator '\'.
+  target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1);
+  // Without making the path a bit shorter, CreateDirectory() fails.
+  // the resulting path is still long enough to hit the failing case in
+  // NormalizePath().
+  const int kCreateDirLimit = 4;
+  target_length -= kCreateDirLimit;
+  FilePath::StringType long_name_str = FPL("long_name_");
+  long_name_str.resize(target_length, '_');
+
+  FilePath long_name = sub_a.Append(FilePath(long_name_str));
+  FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt);
+  ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length());
+
+  FilePath sub_long = deep_file.DirName();
+  ASSERT_TRUE(CreateDirectory(sub_long));
+  CreateTextFile(deep_file, bogus_content);
+
+  FilePath base_b = temp_dir_.path().Append(FPL("base_b"));
+  ASSERT_TRUE(CreateDirectory(base_b));
+
+  FilePath to_sub_a = base_b.Append(FPL("to_sub_a"));
+  ASSERT_TRUE(CreateDirectory(to_sub_a));
+  FilePath normalized_path;
+  {
+    ReparsePoint reparse_to_sub_a(to_sub_a, sub_a);
+    ASSERT_TRUE(reparse_to_sub_a.IsValid());
+
+    FilePath to_base_b = base_b.Append(FPL("to_base_b"));
+    ASSERT_TRUE(CreateDirectory(to_base_b));
+    ReparsePoint reparse_to_base_b(to_base_b, base_b);
+    ASSERT_TRUE(reparse_to_base_b.IsValid());
+
+    FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
+    ASSERT_TRUE(CreateDirectory(to_sub_long));
+    ReparsePoint reparse_to_sub_long(to_sub_long, sub_long);
+    ASSERT_TRUE(reparse_to_sub_long.IsValid());
+
+    // Normalize a junction free path: base_a\sub_a\file.txt .
+    ASSERT_TRUE(NormalizeFilePath(file_txt, &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude
+    // the junction to_sub_a.
+    ASSERT_TRUE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                             &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be
+    // normalized to exclude junctions to_base_b and to_sub_a .
+    ASSERT_TRUE(NormalizeFilePath(base_b.Append(FPL("to_base_b"))
+                                                   .Append(FPL("to_base_b"))
+                                                   .Append(FPL("to_sub_a"))
+                                                   .Append(FPL("file.txt")),
+                                             &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // A long enough path will cause NormalizeFilePath() to fail.  Make a long
+    // path using to_base_b many times, and check that paths long enough to fail
+    // do not cause a crash.
+    FilePath long_path = base_b;
+    const int kLengthLimit = MAX_PATH + 200;
+    while (long_path.value().length() <= kLengthLimit) {
+      long_path = long_path.Append(FPL("to_base_b"));
+    }
+    long_path = long_path.Append(FPL("to_sub_a"))
+                         .Append(FPL("file.txt"));
+
+    ASSERT_FALSE(NormalizeFilePath(long_path, &normalized_path));
+
+    // Normalizing the junction to deep.txt should fail, because the expanded
+    // path to deep.txt is longer than MAX_PATH.
+    ASSERT_FALSE(NormalizeFilePath(to_sub_long.Append(deep_txt),
+                                              &normalized_path));
+
+    // Delete the reparse points, and see that NormalizeFilePath() fails
+    // to traverse them.
+  }
+
+  ASSERT_FALSE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                            &normalized_path));
+}
+
+TEST_F(FileUtilTest, DevicePathToDriveLetter) {
+  // Get a drive letter.
+  std::wstring real_drive_letter = temp_dir_.path().value().substr(0, 2);
+  StringToUpperASCII(&real_drive_letter);
+  if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
+    LOG(ERROR) << "Can't get a drive letter to test with.";
+    return;
+  }
+
+  // Get the NT style path to that drive.
+  wchar_t device_path[MAX_PATH] = {'\0'};
+  ASSERT_TRUE(
+      ::QueryDosDevice(real_drive_letter.c_str(), device_path, MAX_PATH));
+  FilePath actual_device_path(device_path);
+  FilePath win32_path;
+
+  // Run DevicePathToDriveLetterPath() on the NT style path we got from
+  // QueryDosDevice().  Expect the drive letter we started with.
+  ASSERT_TRUE(DevicePathToDriveLetterPath(actual_device_path, &win32_path));
+  ASSERT_EQ(real_drive_letter, win32_path.value());
+
+  // Add some directories to the path.  Expect those extra path componenets
+  // to be preserved.
+  FilePath kRelativePath(FPL("dir1\\dir2\\file.txt"));
+  ASSERT_TRUE(DevicePathToDriveLetterPath(
+      actual_device_path.Append(kRelativePath),
+      &win32_path));
+  EXPECT_EQ(FilePath(real_drive_letter + L"\\").Append(kRelativePath).value(),
+            win32_path.value());
+
+  // Deform the real path so that it is invalid by removing the last four
+  // characters.  The way windows names devices that are hard disks
+  // (\Device\HardDiskVolume${NUMBER}) guarantees that the string is longer
+  // than three characters.  The only way the truncated string could be a
+  // real drive is if more than 10^3 disks are mounted:
+  // \Device\HardDiskVolume10000 would be truncated to \Device\HardDiskVolume1
+  // Check that DevicePathToDriveLetterPath fails.
+  int path_length = actual_device_path.value().length();
+  int new_length = path_length - 4;
+  ASSERT_LT(0, new_length);
+  FilePath prefix_of_real_device_path(
+      actual_device_path.value().substr(0, new_length));
+  ASSERT_FALSE(DevicePathToDriveLetterPath(prefix_of_real_device_path,
+                                           &win32_path));
+
+  ASSERT_FALSE(DevicePathToDriveLetterPath(
+      prefix_of_real_device_path.Append(kRelativePath),
+      &win32_path));
+
+  // Deform the real path so that it is invalid by adding some characters. For
+  // example, if C: maps to \Device\HardDiskVolume8, then we simulate a
+  // request for the drive letter whose native path is
+  // \Device\HardDiskVolume812345 .  We assume such a device does not exist,
+  // because drives are numbered in order and mounting 112345 hard disks will
+  // never happen.
+  const FilePath::StringType kExtraChars = FPL("12345");
+
+  FilePath real_device_path_plus_numbers(
+      actual_device_path.value() + kExtraChars);
+
+  ASSERT_FALSE(DevicePathToDriveLetterPath(
+      real_device_path_plus_numbers,
+      &win32_path));
+
+  ASSERT_FALSE(DevicePathToDriveLetterPath(
+      real_device_path_plus_numbers.Append(kRelativePath),
+      &win32_path));
+}
+
+TEST_F(FileUtilTest, CreateTemporaryFileInDirLongPathTest) {
+  // Test that CreateTemporaryFileInDir() creates a path and returns a long path
+  // if it is available. This test requires that:
+  // - the filesystem at |temp_dir_| supports long filenames.
+  // - the account has FILE_LIST_DIRECTORY permission for all ancestor
+  //   directories of |temp_dir_|.
+  const FilePath::CharType kLongDirName[] = FPL("A long path");
+  const FilePath::CharType kTestSubDirName[] = FPL("test");
+  FilePath long_test_dir = temp_dir_.path().Append(kLongDirName);
+  ASSERT_TRUE(CreateDirectory(long_test_dir));
+
+  // kLongDirName is not a 8.3 component. So GetShortName() should give us a
+  // different short name.
+  WCHAR path_buffer[MAX_PATH];
+  DWORD path_buffer_length = GetShortPathName(long_test_dir.value().c_str(),
+                                              path_buffer, MAX_PATH);
+  ASSERT_LT(path_buffer_length, DWORD(MAX_PATH));
+  ASSERT_NE(DWORD(0), path_buffer_length);
+  FilePath short_test_dir(path_buffer);
+  ASSERT_STRNE(kLongDirName, short_test_dir.BaseName().value().c_str());
+
+  FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(short_test_dir, &temp_file));
+  EXPECT_STREQ(kLongDirName, temp_file.DirName().BaseName().value().c_str());
+  EXPECT_TRUE(PathExists(temp_file));
+
+  // Create a subdirectory of |long_test_dir| and make |long_test_dir|
+  // unreadable. We should still be able to create a temp file in the
+  // subdirectory, but we won't be able to determine the long path for it. This
+  // mimics the environment that some users run where their user profiles reside
+  // in a location where the don't have full access to the higher level
+  // directories. (Note that this assumption is true for NTFS, but not for some
+  // network file systems. E.g. AFS).
+  FilePath access_test_dir = long_test_dir.Append(kTestSubDirName);
+  ASSERT_TRUE(CreateDirectory(access_test_dir));
+  base::FilePermissionRestorer long_test_dir_restorer(long_test_dir);
+  ASSERT_TRUE(base::MakeFileUnreadable(long_test_dir));
+
+  // Use the short form of the directory to create a temporary filename.
+  ASSERT_TRUE(CreateTemporaryFileInDir(
+      short_test_dir.Append(kTestSubDirName), &temp_file));
+  EXPECT_TRUE(PathExists(temp_file));
+  EXPECT_TRUE(short_test_dir.IsParent(temp_file.DirName()));
+
+  // Check that the long path can't be determined for |temp_file|.
+  path_buffer_length = GetLongPathName(temp_file.value().c_str(),
+                                       path_buffer, MAX_PATH);
+  EXPECT_EQ(DWORD(0), path_buffer_length);
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX)
+
+TEST_F(FileUtilTest, CreateAndReadSymlinks) {
+  FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+  FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+  CreateTextFile(link_to, bogus_content);
+
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create file symlink.";
+
+  // If we created the link properly, we should be able to read the contents
+  // through it.
+  std::wstring contents = ReadTextFile(link_from);
+  EXPECT_EQ(bogus_content, contents);
+
+  FilePath result;
+  ASSERT_TRUE(ReadSymbolicLink(link_from, &result));
+  EXPECT_EQ(link_to.value(), result.value());
+
+  // Link to a directory.
+  link_from = temp_dir_.path().Append(FPL("from_dir"));
+  link_to = temp_dir_.path().Append(FPL("to_dir"));
+  ASSERT_TRUE(CreateDirectory(link_to));
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create directory symlink.";
+
+  // Test failures.
+  EXPECT_FALSE(CreateSymbolicLink(link_to, link_to));
+  EXPECT_FALSE(ReadSymbolicLink(link_to, &result));
+  FilePath missing = temp_dir_.path().Append(FPL("missing"));
+  EXPECT_FALSE(ReadSymbolicLink(missing, &result));
+}
+
+// The following test of NormalizeFilePath() require that we create a symlink.
+// This can not be done on Windows before Vista.  On Vista, creating a symlink
+// requires privilege "SeCreateSymbolicLinkPrivilege".
+// TODO(skerner): Investigate the possibility of giving base_unittests the
+// privileges required to create a symlink.
+TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
+  // Link one file to another.
+  FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+  FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+  CreateTextFile(link_to, bogus_content);
+
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create file symlink.";
+
+  // Check that NormalizeFilePath sees the link.
+  FilePath normalized_path;
+  ASSERT_TRUE(NormalizeFilePath(link_from, &normalized_path));
+  EXPECT_NE(link_from, link_to);
+  EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
+  EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
+
+  // Link to a directory.
+  link_from = temp_dir_.path().Append(FPL("from_dir"));
+  link_to = temp_dir_.path().Append(FPL("to_dir"));
+  ASSERT_TRUE(CreateDirectory(link_to));
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create directory symlink.";
+
+  EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path))
+    << "Links to directories should return false.";
+
+  // Test that a loop in the links causes NormalizeFilePath() to return false.
+  link_from = temp_dir_.path().Append(FPL("link_a"));
+  link_to = temp_dir_.path().Append(FPL("link_b"));
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create loop symlink a.";
+  ASSERT_TRUE(CreateSymbolicLink(link_from, link_to))
+    << "Failed to create loop symlink b.";
+
+  // Infinite loop!
+  EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path));
+}
+#endif  // defined(OS_POSIX)
+
+TEST_F(FileUtilTest, DeleteNonExistent) {
+  FilePath non_existent = temp_dir_.path().AppendASCII("bogus_file_dne.foobar");
+  ASSERT_FALSE(PathExists(non_existent));
+
+  EXPECT_TRUE(DeleteFile(non_existent, false));
+  ASSERT_FALSE(PathExists(non_existent));
+  EXPECT_TRUE(DeleteFile(non_existent, true));
+  ASSERT_FALSE(PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteNonExistentWithNonExistentParent) {
+  FilePath non_existent = temp_dir_.path().AppendASCII("bogus_topdir");
+  non_existent = non_existent.AppendASCII("bogus_subdir");
+  ASSERT_FALSE(PathExists(non_existent));
+
+  EXPECT_TRUE(DeleteFile(non_existent, false));
+  ASSERT_FALSE(PathExists(non_existent));
+  EXPECT_TRUE(DeleteFile(non_existent, true));
+  ASSERT_FALSE(PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteFile) {
+  // Create a file
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 1.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+
+  // Test recursive case, create a new file
+  file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(DeleteFile(file_name, true));
+  EXPECT_FALSE(PathExists(file_name));
+}
+
+#if defined(OS_POSIX)
+TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) {
+  // Create a file.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Create a symlink to the file.
+  FilePath file_link = temp_dir_.path().Append("file_link_2");
+  ASSERT_TRUE(CreateSymbolicLink(file_name, file_link))
+      << "Failed to create symlink.";
+
+  // Delete the symbolic link.
+  EXPECT_TRUE(DeleteFile(file_link, false));
+
+  // Make sure original file is not deleted.
+  EXPECT_FALSE(PathExists(file_link));
+  EXPECT_TRUE(PathExists(file_name));
+}
+
+TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) {
+  // Create a non-existent file path.
+  FilePath non_existent = temp_dir_.path().Append(FPL("Test DeleteFile 3.txt"));
+  EXPECT_FALSE(PathExists(non_existent));
+
+  // Create a symlink to the non-existent file.
+  FilePath file_link = temp_dir_.path().Append("file_link_3");
+  ASSERT_TRUE(CreateSymbolicLink(non_existent, file_link))
+      << "Failed to create symlink.";
+
+  // Make sure the symbolic link is exist.
+  EXPECT_TRUE(IsLink(file_link));
+  EXPECT_FALSE(PathExists(file_link));
+
+  // Delete the symbolic link.
+  EXPECT_TRUE(DeleteFile(file_link, false));
+
+  // Make sure the symbolic link is deleted.
+  EXPECT_FALSE(IsLink(file_link));
+}
+
+TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) {
+  // Create a file path.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(PathExists(file_name));
+
+  const std::string kData("hello");
+
+  int buffer_size = kData.length();
+  char* buffer = new char[buffer_size];
+
+  // Write file.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathExists(file_name));
+
+  // Make sure the file is readable.
+  int32 mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
+
+  // Get rid of the read permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_FALSE(mode & FILE_PERMISSION_READ_BY_USER);
+  // Make sure the file can't be read.
+  EXPECT_EQ(-1, ReadFile(file_name, buffer, buffer_size));
+
+  // Give the read permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name, FILE_PERMISSION_READ_BY_USER));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
+  // Make sure the file can be read.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            ReadFile(file_name, buffer, buffer_size));
+
+  // Delete the file.
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+
+  delete[] buffer;
+}
+
+TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) {
+  // Create a file path.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(PathExists(file_name));
+
+  const std::string kData("hello");
+
+  // Write file.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathExists(file_name));
+
+  // Make sure the file is writable.
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER);
+  EXPECT_TRUE(PathIsWritable(file_name));
+
+  // Get rid of the write permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_FALSE(mode & FILE_PERMISSION_WRITE_BY_USER);
+  // Make sure the file can't be write.
+  EXPECT_EQ(-1, WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_FALSE(PathIsWritable(file_name));
+
+  // Give read permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name,
+                                      FILE_PERMISSION_WRITE_BY_USER));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER);
+  // Make sure the file can be write.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathIsWritable(file_name));
+
+  // Delete the file.
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+}
+
+TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) {
+  // Create a directory path.
+  FilePath subdir_path =
+      temp_dir_.path().Append(FPL("PermissionTest1"));
+  CreateDirectory(subdir_path);
+  ASSERT_TRUE(PathExists(subdir_path));
+
+  // Create a dummy file to enumerate.
+  FilePath file_name = subdir_path.Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(PathExists(file_name));
+  const std::string kData("hello");
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathExists(file_name));
+
+  // Make sure the directory has the all permissions.
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK);
+
+  // Get rid of the permissions from the directory.
+  EXPECT_TRUE(SetPosixFilePermissions(subdir_path, 0u));
+  EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_FALSE(mode & FILE_PERMISSION_USER_MASK);
+
+  // Make sure the file in the directory can't be enumerated.
+  FileEnumerator f1(subdir_path, true, FileEnumerator::FILES);
+  EXPECT_TRUE(PathExists(subdir_path));
+  FindResultCollector c1(&f1);
+  EXPECT_EQ(0, c1.size());
+  EXPECT_FALSE(GetPosixFilePermissions(file_name, &mode));
+
+  // Give the permissions to the directory.
+  EXPECT_TRUE(SetPosixFilePermissions(subdir_path, FILE_PERMISSION_USER_MASK));
+  EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK);
+
+  // Make sure the file in the directory can be enumerated.
+  FileEnumerator f2(subdir_path, true, FileEnumerator::FILES);
+  FindResultCollector c2(&f2);
+  EXPECT_TRUE(c2.HasFile(file_name));
+  EXPECT_EQ(1, c2.size());
+
+  // Delete the file.
+  EXPECT_TRUE(DeleteFile(subdir_path, true));
+  EXPECT_FALSE(PathExists(subdir_path));
+}
+
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Tests that the Delete function works for wild cards, especially
+// with the recursion flag.  Also coincidentally tests PathExists.
+// TODO(erikkay): see if anyone's actually using this feature of the API
+TEST_F(FileUtilTest, DeleteWildCard) {
+  // Create a file and a directory
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteWildCard.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  FilePath subdir_path = temp_dir_.path().Append(FPL("DeleteWildCardDir"));
+  CreateDirectory(subdir_path);
+  ASSERT_TRUE(PathExists(subdir_path));
+
+  // Create the wildcard path
+  FilePath directory_contents = temp_dir_.path();
+  directory_contents = directory_contents.Append(FPL("*"));
+
+  // Delete non-recursively and check that only the file is deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, false));
+  EXPECT_FALSE(PathExists(file_name));
+  EXPECT_TRUE(PathExists(subdir_path));
+
+  // Delete recursively and make sure all contents are deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, true));
+  EXPECT_FALSE(PathExists(file_name));
+  EXPECT_FALSE(PathExists(subdir_path));
+}
+
+// TODO(erikkay): see if anyone's actually using this feature of the API
+TEST_F(FileUtilTest, DeleteNonExistantWildCard) {
+  // Create a file and a directory
+  FilePath subdir_path =
+      temp_dir_.path().Append(FPL("DeleteNonExistantWildCard"));
+  CreateDirectory(subdir_path);
+  ASSERT_TRUE(PathExists(subdir_path));
+
+  // Create the wildcard path
+  FilePath directory_contents = subdir_path;
+  directory_contents = directory_contents.Append(FPL("*"));
+
+  // Delete non-recursively and check nothing got deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, false));
+  EXPECT_TRUE(PathExists(subdir_path));
+
+  // Delete recursively and check nothing got deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, true));
+  EXPECT_TRUE(PathExists(subdir_path));
+}
+#endif
+
+// Tests non-recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirNonRecursive) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirNonRecursive"));
+  CreateDirectory(test_subdir);
+  ASSERT_TRUE(PathExists(test_subdir));
+
+  FilePath file_name = test_subdir.Append(FPL("Test DeleteDir.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
+  CreateDirectory(subdir_path1);
+  ASSERT_TRUE(PathExists(subdir_path1));
+
+  FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
+  CreateDirectory(subdir_path2);
+  ASSERT_TRUE(PathExists(subdir_path2));
+
+  // Delete non-recursively and check that the empty dir got deleted
+  EXPECT_TRUE(DeleteFile(subdir_path2, false));
+  EXPECT_FALSE(PathExists(subdir_path2));
+
+  // Delete non-recursively and check that nothing got deleted
+  EXPECT_FALSE(DeleteFile(test_subdir, false));
+  EXPECT_TRUE(PathExists(test_subdir));
+  EXPECT_TRUE(PathExists(file_name));
+  EXPECT_TRUE(PathExists(subdir_path1));
+}
+
+// Tests recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirRecursive) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirRecursive"));
+  CreateDirectory(test_subdir);
+  ASSERT_TRUE(PathExists(test_subdir));
+
+  FilePath file_name = test_subdir.Append(FPL("Test DeleteDirRecursive.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
+  CreateDirectory(subdir_path1);
+  ASSERT_TRUE(PathExists(subdir_path1));
+
+  FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
+  CreateDirectory(subdir_path2);
+  ASSERT_TRUE(PathExists(subdir_path2));
+
+  // Delete recursively and check that the empty dir got deleted
+  EXPECT_TRUE(DeleteFile(subdir_path2, true));
+  EXPECT_FALSE(PathExists(subdir_path2));
+
+  // Delete recursively and check that everything got deleted
+  EXPECT_TRUE(DeleteFile(test_subdir, true));
+  EXPECT_FALSE(PathExists(file_name));
+  EXPECT_FALSE(PathExists(subdir_path1));
+  EXPECT_FALSE(PathExists(test_subdir));
+}
+
+TEST_F(FileUtilTest, MoveFileNew) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination.
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+  ASSERT_FALSE(PathExists(file_name_to));
+
+  EXPECT_TRUE(Move(file_name_from, file_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveFileExists) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination name.
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+  CreateTextFile(file_name_to, L"Old file content");
+  ASSERT_TRUE(PathExists(file_name_to));
+
+  EXPECT_TRUE(Move(file_name_from, file_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveFileDirExists) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination directory
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+  CreateDirectory(dir_name_to);
+  ASSERT_TRUE(PathExists(dir_name_to));
+
+  EXPECT_FALSE(Move(file_name_from, dir_name_to));
+}
+
+
+TEST_F(FileUtilTest, MoveNew) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath txt_file_name(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  FilePath file_name_from = dir_name_from.Append(txt_file_name);
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Move the directory.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(dir_name_from));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+
+  // Test path traversal.
+  file_name_from = dir_name_to.Append(txt_file_name);
+  file_name_to = dir_name_to.Append(FILE_PATH_LITERAL(".."));
+  file_name_to = file_name_to.Append(txt_file_name);
+  EXPECT_FALSE(Move(file_name_from, file_name_to));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_FALSE(PathExists(file_name_to));
+  EXPECT_TRUE(internal::MoveUnsafe(file_name_from, file_name_to));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveExist) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Move the directory
+  FilePath dir_name_exists =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  // Create the destination directory.
+  CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(PathExists(dir_name_exists));
+
+  EXPECT_TRUE(Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(dir_name_from));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(PathExists(subdir_name_to));
+  EXPECT_TRUE(PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_exists =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create the destination directory.
+  CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(PathExists(dir_name_exists));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_exists, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(PathExists(subdir_name_to));
+  EXPECT_TRUE(PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryNew) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_FALSE(PathExists(subdir_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  // Create the destination directory.
+  CreateDirectory(dir_name_to);
+  ASSERT_TRUE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_FALSE(PathExists(subdir_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination name
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+  ASSERT_FALSE(PathExists(file_name_to));
+
+  EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination name
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+  CreateTextFile(file_name_to, L"Old file content");
+  ASSERT_TRUE(PathExists(file_name_to));
+
+  EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+  CreateDirectory(dir_name_to);
+  ASSERT_TRUE(PathExists(dir_name_to));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  EXPECT_TRUE(CopyDirectory(file_name_from, dir_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create from path with trailing separators.
+#if defined(OS_WIN)
+  FilePath from_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir\\\\\\"));
+#elif defined (OS_POSIX)
+  FilePath from_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir///"));
+#endif
+
+  EXPECT_TRUE(CopyDirectory(from_path, dir_name_to, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+// Sets the source file to read-only.
+void SetReadOnly(const FilePath& path, bool read_only) {
+#if defined(OS_WIN)
+  // On Windows, it involves setting/removing the 'readonly' bit.
+  DWORD attrs = GetFileAttributes(path.value().c_str());
+  ASSERT_NE(INVALID_FILE_ATTRIBUTES, attrs);
+  ASSERT_TRUE(SetFileAttributes(
+      path.value().c_str(),
+      read_only ? (attrs | FILE_ATTRIBUTE_READONLY) :
+          (attrs & ~FILE_ATTRIBUTE_READONLY)));
+
+  DWORD expected = read_only ?
+      ((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) |
+          FILE_ATTRIBUTE_READONLY) :
+      (attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY));
+
+  // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED if present.
+  attrs = GetFileAttributes(path.value().c_str()) &
+          ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+  ASSERT_EQ(expected, attrs);
+#else
+  // On all other platforms, it involves removing/setting the write bit.
+  mode_t mode = read_only ? S_IRUSR : (S_IRUSR | S_IWUSR);
+  EXPECT_TRUE(SetPosixFilePermissions(
+      path, DirectoryExists(path) ? (mode | S_IXUSR) : mode));
+#endif
+}
+
+bool IsReadOnly(const FilePath& path) {
+#if defined(OS_WIN)
+  DWORD attrs = GetFileAttributes(path.value().c_str());
+  EXPECT_NE(INVALID_FILE_ATTRIBUTES, attrs);
+  return attrs & FILE_ATTRIBUTE_READONLY;
+#else
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(path, &mode));
+  return !(mode & S_IWUSR);
+#endif
+}
+
+TEST_F(FileUtilTest, CopyDirectoryACL) {
+  // Create source directories.
+  FilePath src = temp_dir_.path().Append(FILE_PATH_LITERAL("src"));
+  FilePath src_subdir = src.Append(FILE_PATH_LITERAL("subdir"));
+  CreateDirectory(src_subdir);
+  ASSERT_TRUE(PathExists(src_subdir));
+
+  // Create a file under the directory.
+  FilePath src_file = src.Append(FILE_PATH_LITERAL("src.txt"));
+  CreateTextFile(src_file, L"Gooooooooooooooooooooogle");
+  SetReadOnly(src_file, true);
+  ASSERT_TRUE(IsReadOnly(src_file));
+
+  // Make directory read-only.
+  SetReadOnly(src_subdir, true);
+  ASSERT_TRUE(IsReadOnly(src_subdir));
+
+  // Copy the directory recursively.
+  FilePath dst = temp_dir_.path().Append(FILE_PATH_LITERAL("dst"));
+  FilePath dst_file = dst.Append(FILE_PATH_LITERAL("src.txt"));
+  EXPECT_TRUE(CopyDirectory(src, dst, true));
+
+  FilePath dst_subdir = dst.Append(FILE_PATH_LITERAL("subdir"));
+  ASSERT_FALSE(IsReadOnly(dst_subdir));
+  ASSERT_FALSE(IsReadOnly(dst_file));
+
+  // Give write permissions to allow deletion.
+  SetReadOnly(src_subdir, false);
+  ASSERT_FALSE(IsReadOnly(src_subdir));
+}
+
+TEST_F(FileUtilTest, CopyFile) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
+  CreateTextFile(file_name_from, file_contents);
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Copy the file.
+  FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt"));
+  ASSERT_TRUE(CopyFile(file_name_from, dest_file));
+
+  // Try to copy the file to another location using '..' in the path.
+  FilePath dest_file2(dir_name_from);
+  dest_file2 = dest_file2.AppendASCII("..");
+  dest_file2 = dest_file2.AppendASCII("DestFile.txt");
+  ASSERT_FALSE(CopyFile(file_name_from, dest_file2));
+
+  FilePath dest_file2_test(dir_name_from);
+  dest_file2_test = dest_file2_test.DirName();
+  dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt");
+
+  // Check expected copy results.
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dest_file));
+  const std::wstring read_contents = ReadTextFile(dest_file);
+  EXPECT_EQ(file_contents, read_contents);
+  EXPECT_FALSE(PathExists(dest_file2_test));
+  EXPECT_FALSE(PathExists(dest_file2));
+}
+
+TEST_F(FileUtilTest, CopyFileACL) {
+  // While FileUtilTest.CopyFile asserts the content is correctly copied over,
+  // this test case asserts the access control bits are meeting expectations in
+  // CopyFile().
+  FilePath src = temp_dir_.path().Append(FILE_PATH_LITERAL("src.txt"));
+  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
+  CreateTextFile(src, file_contents);
+
+  // Set the source file to read-only.
+  ASSERT_FALSE(IsReadOnly(src));
+  SetReadOnly(src, true);
+  ASSERT_TRUE(IsReadOnly(src));
+
+  // Copy the file.
+  FilePath dst = temp_dir_.path().Append(FILE_PATH_LITERAL("dst.txt"));
+  ASSERT_TRUE(CopyFile(src, dst));
+  EXPECT_EQ(file_contents, ReadTextFile(dst));
+
+  ASSERT_FALSE(IsReadOnly(dst));
+}
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest.
+typedef PlatformTest ReadOnlyFileUtilTest;
+
+TEST_F(ReadOnlyFileUtilTest, ContentsEqual) {
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+
+  FilePath original_file =
+      data_dir.Append(FILE_PATH_LITERAL("original.txt"));
+  FilePath same_file =
+      data_dir.Append(FILE_PATH_LITERAL("same.txt"));
+  FilePath same_length_file =
+      data_dir.Append(FILE_PATH_LITERAL("same_length.txt"));
+  FilePath different_file =
+      data_dir.Append(FILE_PATH_LITERAL("different.txt"));
+  FilePath different_first_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
+  FilePath different_last_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
+  FilePath empty1_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
+  FilePath empty2_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
+  FilePath shortened_file =
+      data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
+  FilePath binary_file =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file.bin"));
+  FilePath binary_file_same =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file_same.bin"));
+  FilePath binary_file_diff =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file_diff.bin"));
+
+  EXPECT_TRUE(ContentsEqual(original_file, original_file));
+  EXPECT_TRUE(ContentsEqual(original_file, same_file));
+  EXPECT_FALSE(ContentsEqual(original_file, same_length_file));
+  EXPECT_FALSE(ContentsEqual(original_file, different_file));
+  EXPECT_FALSE(ContentsEqual(FilePath(FILE_PATH_LITERAL("bogusname")),
+                             FilePath(FILE_PATH_LITERAL("bogusname"))));
+  EXPECT_FALSE(ContentsEqual(original_file, different_first_file));
+  EXPECT_FALSE(ContentsEqual(original_file, different_last_file));
+  EXPECT_TRUE(ContentsEqual(empty1_file, empty2_file));
+  EXPECT_FALSE(ContentsEqual(original_file, shortened_file));
+  EXPECT_FALSE(ContentsEqual(shortened_file, original_file));
+  EXPECT_TRUE(ContentsEqual(binary_file, binary_file_same));
+  EXPECT_FALSE(ContentsEqual(binary_file, binary_file_diff));
+}
+
+TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) {
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+
+  FilePath original_file =
+      data_dir.Append(FILE_PATH_LITERAL("original.txt"));
+  FilePath same_file =
+      data_dir.Append(FILE_PATH_LITERAL("same.txt"));
+  FilePath crlf_file =
+      data_dir.Append(FILE_PATH_LITERAL("crlf.txt"));
+  FilePath shortened_file =
+      data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
+  FilePath different_file =
+      data_dir.Append(FILE_PATH_LITERAL("different.txt"));
+  FilePath different_first_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
+  FilePath different_last_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
+  FilePath first1_file =
+      data_dir.Append(FILE_PATH_LITERAL("first1.txt"));
+  FilePath first2_file =
+      data_dir.Append(FILE_PATH_LITERAL("first2.txt"));
+  FilePath empty1_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
+  FilePath empty2_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
+  FilePath blank_line_file =
+      data_dir.Append(FILE_PATH_LITERAL("blank_line.txt"));
+  FilePath blank_line_crlf_file =
+      data_dir.Append(FILE_PATH_LITERAL("blank_line_crlf.txt"));
+
+  EXPECT_TRUE(TextContentsEqual(original_file, same_file));
+  EXPECT_TRUE(TextContentsEqual(original_file, crlf_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, shortened_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, different_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, different_first_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, different_last_file));
+  EXPECT_FALSE(TextContentsEqual(first1_file, first2_file));
+  EXPECT_TRUE(TextContentsEqual(empty1_file, empty2_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, empty1_file));
+  EXPECT_TRUE(TextContentsEqual(blank_line_file, blank_line_crlf_file));
+}
+
+// We don't need equivalent functionality outside of Windows.
+#if defined(OS_WIN)
+TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("CopyAndDelete_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Move the directory by using CopyAndDeleteDirectory
+  FilePath dir_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("CopyAndDelete_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(internal::CopyAndDeleteDirectory(dir_name_from,
+                                                     dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(dir_name_from));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, GetTempDirTest) {
+  static const TCHAR* kTmpKey = _T("TMP");
+  static const TCHAR* kTmpValues[] = {
+    _T(""), _T("C:"), _T("C:\\"), _T("C:\\tmp"), _T("C:\\tmp\\")
+  };
+  // Save the original $TMP.
+  size_t original_tmp_size;
+  TCHAR* original_tmp;
+  ASSERT_EQ(0, ::_tdupenv_s(&original_tmp, &original_tmp_size, kTmpKey));
+  // original_tmp may be NULL.
+
+  for (unsigned int i = 0; i < arraysize(kTmpValues); ++i) {
+    FilePath path;
+    ::_tputenv_s(kTmpKey, kTmpValues[i]);
+    GetTempDir(&path);
+    EXPECT_TRUE(path.IsAbsolute()) << "$TMP=" << kTmpValues[i] <<
+        " result=" << path.value();
+  }
+
+  // Restore the original $TMP.
+  if (original_tmp) {
+    ::_tputenv_s(kTmpKey, original_tmp);
+    free(original_tmp);
+  } else {
+    ::_tputenv_s(kTmpKey, _T(""));
+  }
+}
+#endif  // OS_WIN
+
+TEST_F(FileUtilTest, CreateTemporaryFileTest) {
+  FilePath temp_files[3];
+  for (int i = 0; i < 3; i++) {
+    ASSERT_TRUE(CreateTemporaryFile(&(temp_files[i])));
+    EXPECT_TRUE(PathExists(temp_files[i]));
+    EXPECT_FALSE(DirectoryExists(temp_files[i]));
+  }
+  for (int i = 0; i < 3; i++)
+    EXPECT_FALSE(temp_files[i] == temp_files[(i+1)%3]);
+  for (int i = 0; i < 3; i++)
+    EXPECT_TRUE(DeleteFile(temp_files[i], false));
+}
+
+TEST_F(FileUtilTest, CreateAndOpenTemporaryFileTest) {
+  FilePath names[3];
+  FILE* fps[3];
+  int i;
+
+  // Create; make sure they are open and exist.
+  for (i = 0; i < 3; ++i) {
+    fps[i] = CreateAndOpenTemporaryFile(&(names[i]));
+    ASSERT_TRUE(fps[i]);
+    EXPECT_TRUE(PathExists(names[i]));
+  }
+
+  // Make sure all names are unique.
+  for (i = 0; i < 3; ++i) {
+    EXPECT_FALSE(names[i] == names[(i+1)%3]);
+  }
+
+  // Close and delete.
+  for (i = 0; i < 3; ++i) {
+    EXPECT_TRUE(CloseFile(fps[i]));
+    EXPECT_TRUE(DeleteFile(names[i], false));
+  }
+}
+
+TEST_F(FileUtilTest, FileToFILE) {
+  File file;
+  FILE* stream = FileToFILE(file.Pass(), "w");
+  EXPECT_FALSE(stream);
+
+  FilePath file_name = temp_dir_.path().Append(FPL("The file.txt"));
+  file = File(file_name, File::FLAG_CREATE | File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+
+  stream = FileToFILE(file.Pass(), "w");
+  EXPECT_TRUE(stream);
+  EXPECT_FALSE(file.IsValid());
+  EXPECT_TRUE(CloseFile(stream));
+}
+
+TEST_F(FileUtilTest, CreateNewTempDirectoryTest) {
+  FilePath temp_dir;
+  ASSERT_TRUE(CreateNewTempDirectory(FilePath::StringType(), &temp_dir));
+  EXPECT_TRUE(PathExists(temp_dir));
+  EXPECT_TRUE(DeleteFile(temp_dir, false));
+}
+
+TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) {
+  FilePath new_dir;
+  ASSERT_TRUE(CreateTemporaryDirInDir(
+                  temp_dir_.path(),
+                  FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"),
+                  &new_dir));
+  EXPECT_TRUE(PathExists(new_dir));
+  EXPECT_TRUE(temp_dir_.path().IsParent(new_dir));
+  EXPECT_TRUE(DeleteFile(new_dir, false));
+}
+
+#if defined(OS_POSIX)
+TEST_F(FileUtilTest, GetShmemTempDirTest) {
+  FilePath dir;
+  EXPECT_TRUE(GetShmemTempDir(false, &dir));
+  EXPECT_TRUE(DirectoryExists(dir));
+}
+#endif
+
+TEST_F(FileUtilTest, GetHomeDirTest) {
+#if !defined(OS_ANDROID)  // Not implemented on Android.
+  // We don't actually know what the home directory is supposed to be without
+  // calling some OS functions which would just duplicate the implementation.
+  // So here we just test that it returns something "reasonable".
+  FilePath home = GetHomeDir();
+  ASSERT_FALSE(home.empty());
+  ASSERT_TRUE(home.IsAbsolute());
+#endif
+}
+
+TEST_F(FileUtilTest, CreateDirectoryTest) {
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("create_directory_test"));
+#if defined(OS_WIN)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\"));
+#elif defined(OS_POSIX)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/"));
+#endif
+
+  EXPECT_FALSE(PathExists(test_path));
+  EXPECT_TRUE(CreateDirectory(test_path));
+  EXPECT_TRUE(PathExists(test_path));
+  // CreateDirectory returns true if the DirectoryExists returns true.
+  EXPECT_TRUE(CreateDirectory(test_path));
+
+  // Doesn't work to create it on top of a non-dir
+  test_path = test_path.Append(FILE_PATH_LITERAL("foobar.txt"));
+  EXPECT_FALSE(PathExists(test_path));
+  CreateTextFile(test_path, L"test file");
+  EXPECT_TRUE(PathExists(test_path));
+  EXPECT_FALSE(CreateDirectory(test_path));
+
+  EXPECT_TRUE(DeleteFile(test_root, true));
+  EXPECT_FALSE(PathExists(test_root));
+  EXPECT_FALSE(PathExists(test_path));
+
+  // Verify assumptions made by the Windows implementation:
+  // 1. The current directory always exists.
+  // 2. The root directory always exists.
+  ASSERT_TRUE(DirectoryExists(FilePath(FilePath::kCurrentDirectory)));
+  FilePath top_level = test_root;
+  while (top_level != top_level.DirName()) {
+    top_level = top_level.DirName();
+  }
+  ASSERT_TRUE(DirectoryExists(top_level));
+
+  // Given these assumptions hold, it should be safe to
+  // test that "creating" these directories succeeds.
+  EXPECT_TRUE(CreateDirectory(
+      FilePath(FilePath::kCurrentDirectory)));
+  EXPECT_TRUE(CreateDirectory(top_level));
+
+#if defined(OS_WIN)
+  FilePath invalid_drive(FILE_PATH_LITERAL("o:\\"));
+  FilePath invalid_path =
+      invalid_drive.Append(FILE_PATH_LITERAL("some\\inaccessible\\dir"));
+  if (!PathExists(invalid_drive)) {
+    EXPECT_FALSE(CreateDirectory(invalid_path));
+  }
+#endif
+}
+
+TEST_F(FileUtilTest, DetectDirectoryTest) {
+  // Check a directory
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("detect_directory_test"));
+  EXPECT_FALSE(PathExists(test_root));
+  EXPECT_TRUE(CreateDirectory(test_root));
+  EXPECT_TRUE(PathExists(test_root));
+  EXPECT_TRUE(DirectoryExists(test_root));
+  // Check a file
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("foobar.txt"));
+  EXPECT_FALSE(PathExists(test_path));
+  CreateTextFile(test_path, L"test file");
+  EXPECT_TRUE(PathExists(test_path));
+  EXPECT_FALSE(DirectoryExists(test_path));
+  EXPECT_TRUE(DeleteFile(test_path, false));
+
+  EXPECT_TRUE(DeleteFile(test_root, true));
+}
+
+TEST_F(FileUtilTest, FileEnumeratorTest) {
+  // Test an empty directory.
+  FileEnumerator f0(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_EQ(FPL(""), f0.Next().value());
+  EXPECT_EQ(FPL(""), f0.Next().value());
+
+  // Test an empty directory, non-recursively, including "..".
+  FileEnumerator f0_dotdot(temp_dir_.path(), false,
+      FILES_AND_DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT);
+  EXPECT_EQ(temp_dir_.path().Append(FPL("..")).value(),
+            f0_dotdot.Next().value());
+  EXPECT_EQ(FPL(""), f0_dotdot.Next().value());
+
+  // create the directories
+  FilePath dir1 = temp_dir_.path().Append(FPL("dir1"));
+  EXPECT_TRUE(CreateDirectory(dir1));
+  FilePath dir2 = temp_dir_.path().Append(FPL("dir2"));
+  EXPECT_TRUE(CreateDirectory(dir2));
+  FilePath dir2inner = dir2.Append(FPL("inner"));
+  EXPECT_TRUE(CreateDirectory(dir2inner));
+
+  // create the files
+  FilePath dir2file = dir2.Append(FPL("dir2file.txt"));
+  CreateTextFile(dir2file, std::wstring());
+  FilePath dir2innerfile = dir2inner.Append(FPL("innerfile.txt"));
+  CreateTextFile(dir2innerfile, std::wstring());
+  FilePath file1 = temp_dir_.path().Append(FPL("file1.txt"));
+  CreateTextFile(file1, std::wstring());
+  FilePath file2_rel = dir2.Append(FilePath::kParentDirectory)
+      .Append(FPL("file2.txt"));
+  CreateTextFile(file2_rel, std::wstring());
+  FilePath file2_abs = temp_dir_.path().Append(FPL("file2.txt"));
+
+  // Only enumerate files.
+  FileEnumerator f1(temp_dir_.path(), true, FileEnumerator::FILES);
+  FindResultCollector c1(&f1);
+  EXPECT_TRUE(c1.HasFile(file1));
+  EXPECT_TRUE(c1.HasFile(file2_abs));
+  EXPECT_TRUE(c1.HasFile(dir2file));
+  EXPECT_TRUE(c1.HasFile(dir2innerfile));
+  EXPECT_EQ(4, c1.size());
+
+  // Only enumerate directories.
+  FileEnumerator f2(temp_dir_.path(), true, FileEnumerator::DIRECTORIES);
+  FindResultCollector c2(&f2);
+  EXPECT_TRUE(c2.HasFile(dir1));
+  EXPECT_TRUE(c2.HasFile(dir2));
+  EXPECT_TRUE(c2.HasFile(dir2inner));
+  EXPECT_EQ(3, c2.size());
+
+  // Only enumerate directories non-recursively.
+  FileEnumerator f2_non_recursive(
+      temp_dir_.path(), false, FileEnumerator::DIRECTORIES);
+  FindResultCollector c2_non_recursive(&f2_non_recursive);
+  EXPECT_TRUE(c2_non_recursive.HasFile(dir1));
+  EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
+  EXPECT_EQ(2, c2_non_recursive.size());
+
+  // Only enumerate directories, non-recursively, including "..".
+  FileEnumerator f2_dotdot(temp_dir_.path(), false,
+                           FileEnumerator::DIRECTORIES |
+                           FileEnumerator::INCLUDE_DOT_DOT);
+  FindResultCollector c2_dotdot(&f2_dotdot);
+  EXPECT_TRUE(c2_dotdot.HasFile(dir1));
+  EXPECT_TRUE(c2_dotdot.HasFile(dir2));
+  EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.path().Append(FPL(".."))));
+  EXPECT_EQ(3, c2_dotdot.size());
+
+  // Enumerate files and directories.
+  FileEnumerator f3(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  FindResultCollector c3(&f3);
+  EXPECT_TRUE(c3.HasFile(dir1));
+  EXPECT_TRUE(c3.HasFile(dir2));
+  EXPECT_TRUE(c3.HasFile(file1));
+  EXPECT_TRUE(c3.HasFile(file2_abs));
+  EXPECT_TRUE(c3.HasFile(dir2file));
+  EXPECT_TRUE(c3.HasFile(dir2inner));
+  EXPECT_TRUE(c3.HasFile(dir2innerfile));
+  EXPECT_EQ(7, c3.size());
+
+  // Non-recursive operation.
+  FileEnumerator f4(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
+  FindResultCollector c4(&f4);
+  EXPECT_TRUE(c4.HasFile(dir2));
+  EXPECT_TRUE(c4.HasFile(dir2));
+  EXPECT_TRUE(c4.HasFile(file1));
+  EXPECT_TRUE(c4.HasFile(file2_abs));
+  EXPECT_EQ(4, c4.size());
+
+  // Enumerate with a pattern.
+  FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES, FPL("dir*"));
+  FindResultCollector c5(&f5);
+  EXPECT_TRUE(c5.HasFile(dir1));
+  EXPECT_TRUE(c5.HasFile(dir2));
+  EXPECT_TRUE(c5.HasFile(dir2file));
+  EXPECT_TRUE(c5.HasFile(dir2inner));
+  EXPECT_TRUE(c5.HasFile(dir2innerfile));
+  EXPECT_EQ(5, c5.size());
+
+#if defined(OS_WIN)
+  {
+    // Make dir1 point to dir2.
+    ReparsePoint reparse_point(dir1, dir2);
+    EXPECT_TRUE(reparse_point.IsValid());
+
+    if ((win::GetVersion() >= win::VERSION_VISTA)) {
+      // There can be a delay for the enumeration code to see the change on
+      // the file system so skip this test for XP.
+      // Enumerate the reparse point.
+      FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES);
+      FindResultCollector c6(&f6);
+      FilePath inner2 = dir1.Append(FPL("inner"));
+      EXPECT_TRUE(c6.HasFile(inner2));
+      EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt"))));
+      EXPECT_TRUE(c6.HasFile(dir1.Append(FPL("dir2file.txt"))));
+      EXPECT_EQ(3, c6.size());
+    }
+
+    // No changes for non recursive operation.
+    FileEnumerator f7(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
+    FindResultCollector c7(&f7);
+    EXPECT_TRUE(c7.HasFile(dir2));
+    EXPECT_TRUE(c7.HasFile(dir2));
+    EXPECT_TRUE(c7.HasFile(file1));
+    EXPECT_TRUE(c7.HasFile(file2_abs));
+    EXPECT_EQ(4, c7.size());
+
+    // Should not enumerate inside dir1 when using recursion.
+    FileEnumerator f8(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+    FindResultCollector c8(&f8);
+    EXPECT_TRUE(c8.HasFile(dir1));
+    EXPECT_TRUE(c8.HasFile(dir2));
+    EXPECT_TRUE(c8.HasFile(file1));
+    EXPECT_TRUE(c8.HasFile(file2_abs));
+    EXPECT_TRUE(c8.HasFile(dir2file));
+    EXPECT_TRUE(c8.HasFile(dir2inner));
+    EXPECT_TRUE(c8.HasFile(dir2innerfile));
+    EXPECT_EQ(7, c8.size());
+  }
+#endif
+
+  // Make sure the destructor closes the find handle while in the middle of a
+  // query to allow TearDown to delete the directory.
+  FileEnumerator f9(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_FALSE(f9.Next().value().empty());  // Should have found something
+                                            // (we don't care what).
+}
+
+TEST_F(FileUtilTest, AppendToFile) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (PathExists(data_dir)) {
+    ASSERT_TRUE(DeleteFile(data_dir, true));
+  }
+  ASSERT_TRUE(CreateDirectory(data_dir));
+
+  // Create a fresh, empty copy of this directory.
+  if (PathExists(data_dir)) {
+    ASSERT_TRUE(DeleteFile(data_dir, true));
+  }
+  ASSERT_TRUE(CreateDirectory(data_dir));
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+
+  std::string data("hello");
+  EXPECT_FALSE(AppendToFile(foobar, data.c_str(), data.size()));
+  EXPECT_EQ(static_cast<int>(data.length()),
+            WriteFile(foobar, data.c_str(), data.length()));
+  EXPECT_TRUE(AppendToFile(foobar, data.c_str(), data.size()));
+
+  const std::wstring read_content = ReadTextFile(foobar);
+  EXPECT_EQ(L"hellohello", read_content);
+}
+
+TEST_F(FileUtilTest, ReadFile) {
+  // Create a test file to be read.
+  const std::string kTestData("The quick brown fox jumps over the lazy dog.");
+  FilePath file_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("ReadFileTest"));
+
+  ASSERT_EQ(static_cast<int>(kTestData.size()),
+            WriteFile(file_path, kTestData.data(), kTestData.size()));
+
+  // Make buffers with various size.
+  std::vector<char> small_buffer(kTestData.size() / 2);
+  std::vector<char> exact_buffer(kTestData.size());
+  std::vector<char> large_buffer(kTestData.size() * 2);
+
+  // Read the file with smaller buffer.
+  int bytes_read_small = ReadFile(
+      file_path, &small_buffer[0], static_cast<int>(small_buffer.size()));
+  EXPECT_EQ(static_cast<int>(small_buffer.size()), bytes_read_small);
+  EXPECT_EQ(
+      std::string(kTestData.begin(), kTestData.begin() + small_buffer.size()),
+      std::string(small_buffer.begin(), small_buffer.end()));
+
+  // Read the file with buffer which have exactly same size.
+  int bytes_read_exact = ReadFile(
+      file_path, &exact_buffer[0], static_cast<int>(exact_buffer.size()));
+  EXPECT_EQ(static_cast<int>(kTestData.size()), bytes_read_exact);
+  EXPECT_EQ(kTestData, std::string(exact_buffer.begin(), exact_buffer.end()));
+
+  // Read the file with larger buffer.
+  int bytes_read_large = ReadFile(
+      file_path, &large_buffer[0], static_cast<int>(large_buffer.size()));
+  EXPECT_EQ(static_cast<int>(kTestData.size()), bytes_read_large);
+  EXPECT_EQ(kTestData, std::string(large_buffer.begin(),
+                                   large_buffer.begin() + kTestData.size()));
+
+  // Make sure the return value is -1 if the file doesn't exist.
+  FilePath file_path_not_exist =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("ReadFileNotExistTest"));
+  EXPECT_EQ(-1,
+            ReadFile(file_path_not_exist,
+                     &exact_buffer[0],
+                     static_cast<int>(exact_buffer.size())));
+}
+
+TEST_F(FileUtilTest, ReadFileToString) {
+  const char kTestData[] = "0123";
+  std::string data;
+
+  FilePath file_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
+  FilePath file_path_dangerous =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("..")).
+      Append(temp_dir_.path().BaseName()).
+      Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
+
+  // Create test file.
+  ASSERT_EQ(4, WriteFile(file_path, kTestData, 4));
+
+  EXPECT_TRUE(ReadFileToString(file_path, &data));
+  EXPECT_EQ(kTestData, data);
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 0));
+  EXPECT_EQ(0u, data.length());
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 2));
+  EXPECT_EQ("01", data);
+
+  data.clear();
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 3));
+  EXPECT_EQ("012", data);
+
+  data.clear();
+  EXPECT_TRUE(ReadFileToString(file_path, &data, 4));
+  EXPECT_EQ("0123", data);
+
+  data.clear();
+  EXPECT_TRUE(ReadFileToString(file_path, &data, 6));
+  EXPECT_EQ("0123", data);
+
+  EXPECT_TRUE(ReadFileToString(file_path, NULL, 6));
+
+  EXPECT_TRUE(ReadFileToString(file_path, NULL));
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path_dangerous, &data));
+  EXPECT_EQ(0u, data.length());
+
+  // Delete test file.
+  EXPECT_TRUE(base::DeleteFile(file_path, false));
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data));
+  EXPECT_EQ(0u, data.length());
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 6));
+  EXPECT_EQ(0u, data.length());
+}
+
+TEST_F(FileUtilTest, TouchFile) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (PathExists(data_dir)) {
+    ASSERT_TRUE(DeleteFile(data_dir, true));
+  }
+  ASSERT_TRUE(CreateDirectory(data_dir));
+
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+  std::string data("hello");
+  ASSERT_TRUE(WriteFile(foobar, data.c_str(), data.length()));
+
+  Time access_time;
+  // This timestamp is divisible by one day (in local timezone),
+  // to make it work on FAT too.
+  ASSERT_TRUE(Time::FromString("Wed, 16 Nov 1994, 00:00:00",
+                               &access_time));
+
+  Time modification_time;
+  // Note that this timestamp is divisible by two (seconds) - FAT stores
+  // modification times with 2s resolution.
+  ASSERT_TRUE(Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT",
+              &modification_time));
+
+  ASSERT_TRUE(TouchFile(foobar, access_time, modification_time));
+  File::Info file_info;
+  ASSERT_TRUE(GetFileInfo(foobar, &file_info));
+  EXPECT_EQ(access_time.ToInternalValue(),
+            file_info.last_accessed.ToInternalValue());
+  EXPECT_EQ(modification_time.ToInternalValue(),
+            file_info.last_modified.ToInternalValue());
+}
+
+TEST_F(FileUtilTest, IsDirectoryEmpty) {
+  FilePath empty_dir = temp_dir_.path().Append(FILE_PATH_LITERAL("EmptyDir"));
+
+  ASSERT_FALSE(PathExists(empty_dir));
+
+  ASSERT_TRUE(CreateDirectory(empty_dir));
+
+  EXPECT_TRUE(IsDirectoryEmpty(empty_dir));
+
+  FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt")));
+  std::string bar("baz");
+  ASSERT_TRUE(WriteFile(foo, bar.c_str(), bar.length()));
+
+  EXPECT_FALSE(IsDirectoryEmpty(empty_dir));
+}
+
+#if defined(OS_POSIX)
+
+// Testing VerifyPathControlledByAdmin() is hard, because there is no
+// way a test can make a file owned by root, or change file paths
+// at the root of the file system.  VerifyPathControlledByAdmin()
+// is implemented as a call to VerifyPathControlledByUser, which gives
+// us the ability to test with paths under the test's temp directory,
+// using a user id we control.
+// Pull tests of VerifyPathControlledByUserTest() into a separate test class
+// with a common SetUp() method.
+class VerifyPathControlledByUserTest : public FileUtilTest {
+ protected:
+  void SetUp() override {
+    FileUtilTest::SetUp();
+
+    // Create a basic structure used by each test.
+    // base_dir_
+    //  |-> sub_dir_
+    //       |-> text_file_
+
+    base_dir_ = temp_dir_.path().AppendASCII("base_dir");
+    ASSERT_TRUE(CreateDirectory(base_dir_));
+
+    sub_dir_ = base_dir_.AppendASCII("sub_dir");
+    ASSERT_TRUE(CreateDirectory(sub_dir_));
+
+    text_file_ = sub_dir_.AppendASCII("file.txt");
+    CreateTextFile(text_file_, L"This text file has some text in it.");
+
+    // Get the user and group files are created with from |base_dir_|.
+    struct stat stat_buf;
+    ASSERT_EQ(0, stat(base_dir_.value().c_str(), &stat_buf));
+    uid_ = stat_buf.st_uid;
+    ok_gids_.insert(stat_buf.st_gid);
+    bad_gids_.insert(stat_buf.st_gid + 1);
+
+    ASSERT_EQ(uid_, getuid());  // This process should be the owner.
+
+    // To ensure that umask settings do not cause the initial state
+    // of permissions to be different from what we expect, explicitly
+    // set permissions on the directories we create.
+    // Make all files and directories non-world-writable.
+
+    // Users and group can read, write, traverse
+    int enabled_permissions =
+        FILE_PERMISSION_USER_MASK | FILE_PERMISSION_GROUP_MASK;
+    // Other users can't read, write, traverse
+    int disabled_permissions = FILE_PERMISSION_OTHERS_MASK;
+
+    ASSERT_NO_FATAL_FAILURE(
+        ChangePosixFilePermissions(
+            base_dir_, enabled_permissions, disabled_permissions));
+    ASSERT_NO_FATAL_FAILURE(
+        ChangePosixFilePermissions(
+            sub_dir_, enabled_permissions, disabled_permissions));
+  }
+
+  FilePath base_dir_;
+  FilePath sub_dir_;
+  FilePath text_file_;
+  uid_t uid_;
+
+  std::set<gid_t> ok_gids_;
+  std::set<gid_t> bad_gids_;
+};
+
+TEST_F(VerifyPathControlledByUserTest, BadPaths) {
+  // File does not exist.
+  FilePath does_not_exist = base_dir_.AppendASCII("does")
+                                     .AppendASCII("not")
+                                     .AppendASCII("exist");
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, does_not_exist, uid_, ok_gids_));
+
+  // |base| not a subpath of |path|.
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          empty, base_dir_, uid_, ok_gids_));
+
+  // Finding that a bad call fails proves nothing unless a good call succeeds.
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, Symlinks) {
+  // Symlinks in the path should cause failure.
+
+  // Symlink to the file at the end of the path.
+  FilePath file_link =  base_dir_.AppendASCII("file_link");
+  ASSERT_TRUE(CreateSymbolicLink(text_file_, file_link))
+      << "Failed to create symlink.";
+
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, file_link, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          file_link, file_link, uid_, ok_gids_));
+
+  // Symlink from one directory to another within the path.
+  FilePath link_to_sub_dir =  base_dir_.AppendASCII("link_to_sub_dir");
+  ASSERT_TRUE(CreateSymbolicLink(sub_dir_, link_to_sub_dir))
+    << "Failed to create symlink.";
+
+  FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt");
+  ASSERT_TRUE(PathExists(file_path_with_link));
+
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, file_path_with_link, uid_, ok_gids_));
+
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          link_to_sub_dir, file_path_with_link, uid_, ok_gids_));
+
+  // Symlinks in parents of base path are allowed.
+  EXPECT_TRUE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Another user does not control these paths.
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, bad_uid, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, bad_uid, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          sub_dir_, text_file_, bad_uid, ok_gids_));
+
+  // Another group does not control the paths.
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_TRUE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, no_gids));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, no_gids));
+  EXPECT_TRUE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, multiple_gids));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, multiple_gids));
+  EXPECT_TRUE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      base::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(
+      base::VerifyPathControlledByUser(
+          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      base::VerifyPathControlledByUser(
+          sub_dir_, text_file_, uid_, ok_gids_));
+}
+
+#if defined(OS_ANDROID)
+TEST_F(FileUtilTest, ValidContentUriTest) {
+  // Get the test image path.
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+  FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
+  int64 image_size;
+  GetFileSize(image_file, &image_size);
+  EXPECT_LT(0, image_size);
+
+  // Insert the image into MediaStore. MediaStore will do some conversions, and
+  // return the content URI.
+  FilePath path = base::InsertImageIntoMediaStore(image_file);
+  EXPECT_TRUE(path.IsContentUri());
+  EXPECT_TRUE(PathExists(path));
+  // The file size may not equal to the input image as MediaStore may convert
+  // the image.
+  int64 content_uri_size;
+  GetFileSize(path, &content_uri_size);
+  EXPECT_EQ(image_size, content_uri_size);
+
+  // We should be able to read the file.
+  char* buffer = new char[image_size];
+  File file = OpenContentUriForRead(path);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_TRUE(file.ReadAtCurrentPos(buffer, image_size));
+  delete[] buffer;
+}
+
+TEST_F(FileUtilTest, NonExistentContentUriTest) {
+  FilePath path("content://foo.bar");
+  EXPECT_TRUE(path.IsContentUri());
+  EXPECT_FALSE(PathExists(path));
+  // Size should be smaller than 0.
+  int64 size;
+  EXPECT_FALSE(GetFileSize(path, &size));
+
+  // We should not be able to read the file.
+  File file = OpenContentUriForRead(path);
+  EXPECT_FALSE(file.IsValid());
+}
+#endif
+
+TEST(ScopedFD, ScopedFDDoesClose) {
+  int fds[2];
+  char c = 0;
+  ASSERT_EQ(0, pipe(fds));
+  const int write_end = fds[1];
+  base::ScopedFD read_end_closer(fds[0]);
+  {
+    base::ScopedFD write_end_closer(fds[1]);
+  }
+  // This is the only thread. This file descriptor should no longer be valid.
+  int ret = close(write_end);
+  EXPECT_EQ(-1, ret);
+  EXPECT_EQ(EBADF, errno);
+  // Make sure read(2) won't block.
+  ASSERT_EQ(0, fcntl(fds[0], F_SETFL, O_NONBLOCK));
+  // Reading the pipe should EOF.
+  EXPECT_EQ(0, read(fds[0], &c, 1));
+}
+
+#if defined(GTEST_HAS_DEATH_TEST)
+void CloseWithScopedFD(int fd) {
+  base::ScopedFD fd_closer(fd);
+}
+#endif
+
+TEST(ScopedFD, ScopedFDCrashesOnCloseFailure) {
+  int fds[2];
+  ASSERT_EQ(0, pipe(fds));
+  base::ScopedFD read_end_closer(fds[0]);
+  EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
+#if defined(GTEST_HAS_DEATH_TEST)
+  // This is the only thread. This file descriptor should no longer be valid.
+  // Trying to close it should crash. This is important for security.
+  EXPECT_DEATH(CloseWithScopedFD(fds[1]), "");
+#endif
+}
+
+#endif  // defined(OS_POSIX)
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
new file mode 100644
index 0000000..e254232
--- /dev/null
+++ b/base/files/file_util_win.cc
@@ -0,0 +1,810 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+
+#include <windows.h>
+#include <io.h>
+#include <psapi.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <time.h>
+
+#include <algorithm>
+#include <limits>
+#include <string>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/process/process_handle.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+namespace {
+
+const DWORD kFileShareAll =
+    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+}  // namespace
+
+FilePath MakeAbsoluteFilePath(const FilePath& input) {
+  ThreadRestrictions::AssertIOAllowed();
+  wchar_t file_path[MAX_PATH];
+  if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH))
+    return FilePath();
+  return FilePath(file_path);
+}
+
+bool DeleteFile(const FilePath& path, bool recursive) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (path.value().length() >= MAX_PATH)
+    return false;
+
+  // On XP SHFileOperation will return ERROR_ACCESS_DENIED instead of
+  // ERROR_FILE_NOT_FOUND, so just shortcut this here.
+  if (path.empty())
+    return true;
+
+  if (!recursive) {
+    // If not recursing, then first check to see if |path| is a directory.
+    // If it is, then remove it with RemoveDirectory.
+    File::Info file_info;
+    if (GetFileInfo(path, &file_info) && file_info.is_directory)
+      return RemoveDirectory(path.value().c_str()) != 0;
+
+    // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
+    // because it should be faster. If DeleteFile fails, then we fall through
+    // to SHFileOperation, which will do the right thing.
+    if (::DeleteFile(path.value().c_str()) != 0)
+      return true;
+  }
+
+  // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
+  // so we have to use wcscpy because wcscpy_s writes non-NULLs
+  // into the rest of the buffer.
+  wchar_t double_terminated_path[MAX_PATH + 1] = {0};
+#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
+  wcscpy(double_terminated_path, path.value().c_str());
+
+  SHFILEOPSTRUCT file_operation = {0};
+  file_operation.wFunc = FO_DELETE;
+  file_operation.pFrom = double_terminated_path;
+  file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
+  if (!recursive)
+    file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
+  int err = SHFileOperation(&file_operation);
+
+  // Since we're passing flags to the operation telling it to be silent,
+  // it's possible for the operation to be aborted/cancelled without err
+  // being set (although MSDN doesn't give any scenarios for how this can
+  // happen).  See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
+  if (file_operation.fAnyOperationsAborted)
+    return false;
+
+  // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
+  // an empty directory and some return 0x402 when they should be returning
+  // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.  Windows 7
+  // can return DE_INVALIDFILES (0x7C) for nonexistent directories.
+  return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 ||
+          err == 0x7C);
+}
+
+bool DeleteFileAfterReboot(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (path.value().length() >= MAX_PATH)
+    return false;
+
+  return MoveFileEx(path.value().c_str(), NULL,
+                    MOVEFILE_DELAY_UNTIL_REBOOT |
+                        MOVEFILE_REPLACE_EXISTING) != FALSE;
+}
+
+bool ReplaceFile(const FilePath& from_path,
+                 const FilePath& to_path,
+                 File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();
+  // Try a simple move first.  It will only succeed when |to_path| doesn't
+  // already exist.
+  if (::MoveFile(from_path.value().c_str(), to_path.value().c_str()))
+    return true;
+  // Try the full-blown replace if the move fails, as ReplaceFile will only
+  // succeed when |to_path| does exist. When writing to a network share, we may
+  // not be able to change the ACLs. Ignore ACL errors then
+  // (REPLACEFILE_IGNORE_MERGE_ERRORS).
+  if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL,
+                    REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
+    return true;
+  }
+  if (error)
+    *error = File::OSErrorToFileError(GetLastError());
+  return false;
+}
+
+bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
+                   bool recursive) {
+  // NOTE(maruel): Previous version of this function used to call
+  // SHFileOperation().  This used to copy the file attributes and extended
+  // attributes, OLE structured storage, NTFS file system alternate data
+  // streams, SECURITY_DESCRIPTOR. In practice, this is not what we want, we
+  // want the containing directory to propagate its SECURITY_DESCRIPTOR.
+  ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+
+  // This function does not properly handle destinations within the source.
+  FilePath real_to_path = to_path;
+  if (PathExists(real_to_path)) {
+    real_to_path = MakeAbsoluteFilePath(real_to_path);
+    if (real_to_path.empty())
+      return false;
+  } else {
+    real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
+    if (real_to_path.empty())
+      return false;
+  }
+  FilePath real_from_path = MakeAbsoluteFilePath(from_path);
+  if (real_from_path.empty())
+    return false;
+  if (real_to_path.value().size() >= real_from_path.value().size() &&
+      real_to_path.value().compare(0, real_from_path.value().size(),
+                                   real_from_path.value()) == 0) {
+    return false;
+  }
+
+  int traverse_type = FileEnumerator::FILES;
+  if (recursive)
+    traverse_type |= FileEnumerator::DIRECTORIES;
+  FileEnumerator traversal(from_path, recursive, traverse_type);
+
+  if (!PathExists(from_path)) {
+    DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
+                << from_path.value().c_str();
+    return false;
+  }
+  // TODO(maruel): This is not necessary anymore.
+  DCHECK(recursive || DirectoryExists(from_path));
+
+  FilePath current = from_path;
+  bool from_is_dir = DirectoryExists(from_path);
+  bool success = true;
+  FilePath from_path_base = from_path;
+  if (recursive && DirectoryExists(to_path)) {
+    // If the destination already exists and is a directory, then the
+    // top level of source needs to be copied.
+    from_path_base = from_path.DirName();
+  }
+
+  while (success && !current.empty()) {
+    // current is the source path, including from_path, so append
+    // the suffix after from_path to to_path to create the target_path.
+    FilePath target_path(to_path);
+    if (from_path_base != current) {
+      if (!from_path_base.AppendRelativePath(current, &target_path)) {
+        success = false;
+        break;
+      }
+    }
+
+    if (from_is_dir) {
+      if (!DirectoryExists(target_path) &&
+          !::CreateDirectory(target_path.value().c_str(), NULL)) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
+                    << target_path.value().c_str();
+        success = false;
+      }
+    } else if (!CopyFile(current, target_path)) {
+      DLOG(ERROR) << "CopyDirectory() couldn't create file: "
+                  << target_path.value().c_str();
+      success = false;
+    }
+
+    current = traversal.Next();
+    if (!current.empty())
+      from_is_dir = traversal.GetInfo().IsDirectory();
+  }
+
+  return success;
+}
+
+bool PathExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
+}
+
+bool PathIsWritable(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  HANDLE dir =
+      CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
+                 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+  if (dir == INVALID_HANDLE_VALUE)
+    return false;
+
+  CloseHandle(dir);
+  return true;
+}
+
+bool DirectoryExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  DWORD fileattr = GetFileAttributes(path.value().c_str());
+  if (fileattr != INVALID_FILE_ATTRIBUTES)
+    return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  return false;
+}
+
+bool GetTempDir(FilePath* path) {
+  wchar_t temp_path[MAX_PATH + 1];
+  DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
+  if (path_len >= MAX_PATH || path_len <= 0)
+    return false;
+  // TODO(evanm): the old behavior of this function was to always strip the
+  // trailing slash.  We duplicate this here, but it shouldn't be necessary
+  // when everyone is using the appropriate FilePath APIs.
+  *path = FilePath(temp_path).StripTrailingSeparators();
+  return true;
+}
+
+FilePath GetHomeDir() {
+  char16 result[MAX_PATH];
+  if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
+                                result)) &&
+      result[0]) {
+    return FilePath(result);
+  }
+
+  // Fall back to the temporary directory on failure.
+  FilePath temp;
+  if (GetTempDir(&temp))
+    return temp;
+
+  // Last resort.
+  return FilePath(L"C:\\");
+}
+
+bool CreateTemporaryFile(FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  FilePath temp_file;
+
+  if (!GetTempDir(path))
+    return false;
+
+  if (CreateTemporaryFileInDir(*path, &temp_file)) {
+    *path = temp_file;
+    return true;
+  }
+
+  return false;
+}
+
+// On POSIX we have semantics to create and open a temporary file
+// atomically.
+// TODO(jrg): is there equivalent call to use on Windows instead of
+// going 2-step?
+FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (!CreateTemporaryFileInDir(dir, path)) {
+    return NULL;
+  }
+  // Open file in binary mode, to avoid problems with fwrite. On Windows
+  // it replaces \n's with \r\n's, which may surprise you.
+  // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
+  return OpenFile(*path, "wb+");
+}
+
+bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t temp_name[MAX_PATH + 1];
+
+  if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
+    DPLOG(WARNING) << "Failed to get temporary file name in "
+                   << UTF16ToUTF8(dir.value());
+    return false;
+  }
+
+  wchar_t long_temp_name[MAX_PATH + 1];
+  DWORD long_name_len = GetLongPathName(temp_name, long_temp_name, MAX_PATH);
+  if (long_name_len > MAX_PATH || long_name_len == 0) {
+    // GetLongPathName() failed, but we still have a temporary file.
+    *temp_file = FilePath(temp_name);
+    return true;
+  }
+
+  FilePath::StringType long_temp_name_str;
+  long_temp_name_str.assign(long_temp_name, long_name_len);
+  *temp_file = FilePath(long_temp_name_str);
+  return true;
+}
+
+bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                             const FilePath::StringType& prefix,
+                             FilePath* new_dir) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  FilePath path_to_create;
+
+  for (int count = 0; count < 50; ++count) {
+    // Try create a new temporary directory with random generated name. If
+    // the one exists, keep trying another path name until we reach some limit.
+    string16 new_dir_name;
+    new_dir_name.assign(prefix);
+    new_dir_name.append(IntToString16(GetCurrentProcId()));
+    new_dir_name.push_back('_');
+    new_dir_name.append(IntToString16(RandInt(0, kint16max)));
+
+    path_to_create = base_dir.Append(new_dir_name);
+    if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
+      *new_dir = path_to_create;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                            FilePath* new_temp_path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  FilePath system_temp_dir;
+  if (!GetTempDir(&system_temp_dir))
+    return false;
+
+  return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path);
+}
+
+bool CreateDirectoryAndGetError(const FilePath& full_path,
+                                File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  // If the path exists, we've succeeded if it's a directory, failed otherwise.
+  const wchar_t* full_path_str = full_path.value().c_str();
+  DWORD fileattr = ::GetFileAttributes(full_path_str);
+  if (fileattr != INVALID_FILE_ATTRIBUTES) {
+    if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+      DVLOG(1) << "CreateDirectory(" << full_path_str << "), "
+               << "directory already exists.";
+      return true;
+    }
+    DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
+                  << "conflicts with existing file.";
+    if (error) {
+      *error = File::FILE_ERROR_NOT_A_DIRECTORY;
+    }
+    return false;
+  }
+
+  // Invariant:  Path does not exist as file or directory.
+
+  // Attempt to create the parent recursively.  This will immediately return
+  // true if it already exists, otherwise will create all required parent
+  // directories starting with the highest-level missing parent.
+  FilePath parent_path(full_path.DirName());
+  if (parent_path.value() == full_path.value()) {
+    if (error) {
+      *error = File::FILE_ERROR_NOT_FOUND;
+    }
+    return false;
+  }
+  if (!CreateDirectoryAndGetError(parent_path, error)) {
+    DLOG(WARNING) << "Failed to create one of the parent directories.";
+    if (error) {
+      DCHECK(*error != File::FILE_OK);
+    }
+    return false;
+  }
+
+  if (!::CreateDirectory(full_path_str, NULL)) {
+    DWORD error_code = ::GetLastError();
+    if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
+      // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
+      // were racing with someone creating the same directory, or a file
+      // with the same path.  If DirectoryExists() returns true, we lost the
+      // race to create the same directory.
+      return true;
+    } else {
+      if (error)
+        *error = File::OSErrorToFileError(error_code);
+      DLOG(WARNING) << "Failed to create directory " << full_path_str
+                    << ", last error is " << error_code << ".";
+      return false;
+    }
+  } else {
+    return true;
+  }
+}
+
+bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  FilePath mapped_file;
+  if (!NormalizeToNativeFilePath(path, &mapped_file))
+    return false;
+  // NormalizeToNativeFilePath() will return a path that starts with
+  // "\Device\Harddisk...".  Helper DevicePathToDriveLetterPath()
+  // will find a drive letter which maps to the path's device, so
+  // that we return a path starting with a drive letter.
+  return DevicePathToDriveLetterPath(mapped_file, real_path);
+}
+
+bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
+                                 FilePath* out_drive_letter_path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  // Get the mapping of drive letters to device paths.
+  const int kDriveMappingSize = 1024;
+  wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
+  if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
+    DLOG(ERROR) << "Failed to get drive mapping.";
+    return false;
+  }
+
+  // The drive mapping is a sequence of null terminated strings.
+  // The last string is empty.
+  wchar_t* drive_map_ptr = drive_mapping;
+  wchar_t device_path_as_string[MAX_PATH];
+  wchar_t drive[] = L" :";
+
+  // For each string in the drive mapping, get the junction that links
+  // to it.  If that junction is a prefix of |device_path|, then we
+  // know that |drive| is the real path prefix.
+  while (*drive_map_ptr) {
+    drive[0] = drive_map_ptr[0];  // Copy the drive letter.
+
+    if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
+      FilePath device_path(device_path_as_string);
+      if (device_path == nt_device_path ||
+          device_path.IsParent(nt_device_path)) {
+        *out_drive_letter_path = FilePath(drive +
+            nt_device_path.value().substr(wcslen(device_path_as_string)));
+        return true;
+      }
+    }
+    // Move to the next drive letter string, which starts one
+    // increment after the '\0' that terminates the current string.
+    while (*drive_map_ptr++) {}
+  }
+
+  // No drive matched.  The path does not start with a device junction
+  // that is mounted as a drive letter.  This means there is no drive
+  // letter path to the volume that holds |device_path|, so fail.
+  return false;
+}
+
+bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  // In Vista, GetFinalPathNameByHandle() would give us the real path
+  // from a file handle.  If we ever deprecate XP, consider changing the
+  // code below to a call to GetFinalPathNameByHandle().  The method this
+  // function uses is explained in the following msdn article:
+  // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
+  win::ScopedHandle file_handle(
+      ::CreateFile(path.value().c_str(),
+                   GENERIC_READ,
+                   kFileShareAll,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_ATTRIBUTE_NORMAL,
+                   NULL));
+  if (!file_handle.IsValid())
+    return false;
+
+  // Create a file mapping object.  Can't easily use MemoryMappedFile, because
+  // we only map the first byte, and need direct access to the handle. You can
+  // not map an empty file, this call fails in that case.
+  win::ScopedHandle file_map_handle(
+      ::CreateFileMapping(file_handle.Get(),
+                          NULL,
+                          PAGE_READONLY,
+                          0,
+                          1,  // Just one byte.  No need to look at the data.
+                          NULL));
+  if (!file_map_handle.IsValid())
+    return false;
+
+  // Use a view of the file to get the path to the file.
+  void* file_view = MapViewOfFile(file_map_handle.Get(),
+                                  FILE_MAP_READ, 0, 0, 1);
+  if (!file_view)
+    return false;
+
+  // The expansion of |path| into a full path may make it longer.
+  // GetMappedFileName() will fail if the result is longer than MAX_PATH.
+  // Pad a bit to be safe.  If kMaxPathLength is ever changed to be less
+  // than MAX_PATH, it would be nessisary to test that GetMappedFileName()
+  // not return kMaxPathLength.  This would mean that only part of the
+  // path fit in |mapped_file_path|.
+  const int kMaxPathLength = MAX_PATH + 10;
+  wchar_t mapped_file_path[kMaxPathLength];
+  bool success = false;
+  HANDLE cp = GetCurrentProcess();
+  if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
+    *nt_path = FilePath(mapped_file_path);
+    success = true;
+  }
+  ::UnmapViewOfFile(file_view);
+  return success;
+}
+
+// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
+// them if we do decide to.
+bool IsLink(const FilePath& file_path) {
+  return false;
+}
+
+bool GetFileInfo(const FilePath& file_path, File::Info* results) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  WIN32_FILE_ATTRIBUTE_DATA attr;
+  if (!GetFileAttributesEx(file_path.value().c_str(),
+                           GetFileExInfoStandard, &attr)) {
+    return false;
+  }
+
+  ULARGE_INTEGER size;
+  size.HighPart = attr.nFileSizeHigh;
+  size.LowPart = attr.nFileSizeLow;
+  results->size = size.QuadPart;
+
+  results->is_directory =
+      (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  results->last_modified = Time::FromFileTime(attr.ftLastWriteTime);
+  results->last_accessed = Time::FromFileTime(attr.ftLastAccessTime);
+  results->creation_time = Time::FromFileTime(attr.ftCreationTime);
+
+  return true;
+}
+
+FILE* OpenFile(const FilePath& filename, const char* mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  string16 w_mode = ASCIIToUTF16(mode);
+  return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
+}
+
+FILE* FileToFILE(File file, const char* mode) {
+  if (!file.IsValid())
+    return NULL;
+  int fd =
+      _open_osfhandle(reinterpret_cast<intptr_t>(file.GetPlatformFile()), 0);
+  if (fd < 0)
+    return NULL;
+  file.TakePlatformFile();
+  FILE* stream = _fdopen(fd, mode);
+  if (!stream)
+    _close(fd);
+  return stream;
+}
+
+int ReadFile(const FilePath& filename, char* data, int max_size) {
+  ThreadRestrictions::AssertIOAllowed();
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    GENERIC_READ,
+                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    FILE_FLAG_SEQUENTIAL_SCAN,
+                                    NULL));
+  if (!file.IsValid())
+    return -1;
+
+  DWORD read;
+  if (::ReadFile(file.Get(), data, max_size, &read, NULL))
+    return read;
+
+  return -1;
+}
+
+int WriteFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    GENERIC_WRITE,
+                                    0,
+                                    NULL,
+                                    CREATE_ALWAYS,
+                                    0,
+                                    NULL));
+  if (!file.IsValid()) {
+    DPLOG(WARNING) << "CreateFile failed for path "
+                   << UTF16ToUTF8(filename.value());
+    return -1;
+  }
+
+  DWORD written;
+  BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL);
+  if (result && static_cast<int>(written) == size)
+    return written;
+
+  if (!result) {
+    // WriteFile failed.
+    DPLOG(WARNING) << "writing file " << UTF16ToUTF8(filename.value())
+                   << " failed";
+  } else {
+    // Didn't write all the bytes.
+    DLOG(WARNING) << "wrote" << written << " bytes to "
+                  << UTF16ToUTF8(filename.value()) << " expected " << size;
+  }
+  return -1;
+}
+
+bool AppendToFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    FILE_APPEND_DATA,
+                                    0,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    0,
+                                    NULL));
+  if (!file.IsValid()) {
+    VPLOG(1) << "CreateFile failed for path " << UTF16ToUTF8(filename.value());
+    return false;
+  }
+
+  DWORD written;
+  BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL);
+  if (result && static_cast<int>(written) == size)
+    return true;
+
+  if (!result) {
+    // WriteFile failed.
+    VPLOG(1) << "Writing file " << UTF16ToUTF8(filename.value()) << " failed";
+  } else {
+    // Didn't write all the bytes.
+    VPLOG(1) << "Only wrote " << written << " out of " << size << " byte(s) to "
+             << UTF16ToUTF8(filename.value());
+  }
+  return false;
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(FilePath* dir) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+  DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
+  if (len == 0 || len > MAX_PATH)
+    return false;
+  // TODO(evanm): the old behavior of this function was to always strip the
+  // trailing slash.  We duplicate this here, but it shouldn't be necessary
+  // when everyone is using the appropriate FilePath APIs.
+  std::wstring dir_str(system_buffer);
+  *dir = FilePath(dir_str).StripTrailingSeparators();
+  return true;
+}
+
+// Sets the current working directory for the process.
+bool SetCurrentDirectory(const FilePath& directory) {
+  ThreadRestrictions::AssertIOAllowed();
+  BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
+  return ret != 0;
+}
+
+int GetMaximumPathComponentLength(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t volume_path[MAX_PATH];
+  if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(),
+                          volume_path,
+                          arraysize(volume_path))) {
+    return -1;
+  }
+
+  DWORD max_length = 0;
+  if (!GetVolumeInformationW(volume_path, NULL, 0, NULL, &max_length, NULL,
+                             NULL, 0)) {
+    return -1;
+  }
+
+  // Length of |path| with path separator appended.
+  size_t prefix = path.StripTrailingSeparators().value().size() + 1;
+  // The whole path string must be shorter than MAX_PATH. That is, it must be
+  // prefix + component_length < MAX_PATH (or equivalently, <= MAX_PATH - 1).
+  int whole_path_limit = std::max(0, MAX_PATH - 1 - static_cast<int>(prefix));
+  return std::min(whole_path_limit, static_cast<int>(max_length));
+}
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (from_path.ReferencesParent() || to_path.ReferencesParent())
+    return false;
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+
+  // Unlike the posix implementation that copies the file manually and discards
+  // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
+  // bits, which is usually not what we want. We can't do much about the
+  // SECURITY_DESCRIPTOR but at least remove the read only bit.
+  const wchar_t* dest = to_path.value().c_str();
+  if (!::CopyFile(from_path.value().c_str(), dest, false)) {
+    // Copy failed.
+    return false;
+  }
+  DWORD attrs = GetFileAttributes(dest);
+  if (attrs == INVALID_FILE_ATTRIBUTES) {
+    return false;
+  }
+  if (attrs & FILE_ATTRIBUTE_READONLY) {
+    SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
+  }
+  return true;
+}
+
+// -----------------------------------------------------------------------------
+
+namespace internal {
+
+bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+  if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
+                 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
+    return true;
+
+  // Keep the last error value from MoveFileEx around in case the below
+  // fails.
+  bool ret = false;
+  DWORD last_error = ::GetLastError();
+
+  if (DirectoryExists(from_path)) {
+    // MoveFileEx fails if moving directory across volumes. We will simulate
+    // the move by using Copy and Delete. Ideally we could check whether
+    // from_path and to_path are indeed in different volumes.
+    ret = internal::CopyAndDeleteDirectory(from_path, to_path);
+  }
+
+  if (!ret) {
+    // Leave a clue about what went wrong so that it can be (at least) picked
+    // up by a PLOG entry.
+    ::SetLastError(last_error);
+  }
+
+  return ret;
+}
+
+bool CopyAndDeleteDirectory(const FilePath& from_path,
+                            const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (CopyDirectory(from_path, to_path, true)) {
+    if (DeleteFile(from_path, true))
+      return true;
+
+    // Like Move, this function is not transactional, so we just
+    // leave the copied bits behind if deleting from_path fails.
+    // If to_path exists previously then we have already overwritten
+    // it by now, we don't get better off by deleting the new bits.
+  }
+  return false;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
new file mode 100644
index 0000000..200ea29
--- /dev/null
+++ b/base/files/file_win.cc
@@ -0,0 +1,375 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file.h"
+
+#include <io.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+// Make sure our Whence mappings match the system headers.
+COMPILE_ASSERT(File::FROM_BEGIN   == FILE_BEGIN &&
+               File::FROM_CURRENT == FILE_CURRENT &&
+               File::FROM_END     == FILE_END, whence_matches_system);
+
+bool File::IsValid() const {
+  return file_.IsValid();
+}
+
+PlatformFile File::GetPlatformFile() const {
+  return file_.Get();
+}
+
+PlatformFile File::TakePlatformFile() {
+  return file_.Take();
+}
+
+void File::Close() {
+  if (file_.IsValid()) {
+    ThreadRestrictions::AssertIOAllowed();
+    file_.Close();
+  }
+}
+
+int64 File::Seek(Whence whence, int64 offset) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  LARGE_INTEGER distance, res;
+  distance.QuadPart = offset;
+  DWORD move_method = static_cast<DWORD>(whence);
+  if (!SetFilePointerEx(file_.Get(), distance, &res, move_method))
+    return -1;
+  return res.QuadPart;
+}
+
+int File::Read(int64 offset, char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+  if (size < 0)
+    return -1;
+
+  LARGE_INTEGER offset_li;
+  offset_li.QuadPart = offset;
+
+  OVERLAPPED overlapped = {0};
+  overlapped.Offset = offset_li.LowPart;
+  overlapped.OffsetHigh = offset_li.HighPart;
+
+  DWORD bytes_read;
+  if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped))
+    return bytes_read;
+  if (ERROR_HANDLE_EOF == GetLastError())
+    return 0;
+
+  return -1;
+}
+
+int File::ReadAtCurrentPos(char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+  if (size < 0)
+    return -1;
+
+  DWORD bytes_read;
+  if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL))
+    return bytes_read;
+  if (ERROR_HANDLE_EOF == GetLastError())
+    return 0;
+
+  return -1;
+}
+
+int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+  return Read(offset, data, size);
+}
+
+int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
+  return ReadAtCurrentPos(data, size);
+}
+
+int File::Write(int64 offset, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+
+  LARGE_INTEGER offset_li;
+  offset_li.QuadPart = offset;
+
+  OVERLAPPED overlapped = {0};
+  overlapped.Offset = offset_li.LowPart;
+  overlapped.OffsetHigh = offset_li.HighPart;
+
+  DWORD bytes_written;
+  if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped))
+    return bytes_written;
+
+  return -1;
+}
+
+int File::WriteAtCurrentPos(const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+  if (size < 0)
+    return -1;
+
+  DWORD bytes_written;
+  if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL))
+    return bytes_written;
+
+  return -1;
+}
+
+int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
+  return WriteAtCurrentPos(data, size);
+}
+
+int64 File::GetLength() {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  LARGE_INTEGER size;
+  if (!::GetFileSizeEx(file_.Get(), &size))
+    return -1;
+
+  return static_cast<int64>(size.QuadPart);
+}
+
+bool File::SetLength(int64 length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  // Get the current file pointer.
+  LARGE_INTEGER file_pointer;
+  LARGE_INTEGER zero;
+  zero.QuadPart = 0;
+  if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT))
+    return false;
+
+  LARGE_INTEGER length_li;
+  length_li.QuadPart = length;
+  // If length > file size, SetFilePointerEx() should extend the file
+  // with zeroes on all Windows standard file systems (NTFS, FATxx).
+  if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN))
+    return false;
+
+  // Set the new file length and move the file pointer to its old position.
+  // This is consistent with ftruncate()'s behavior, even when the file
+  // pointer points to a location beyond the end of the file.
+  // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
+  // promised by the interface (nor was promised by PlatformFile). See if this
+  // implementation detail can be removed.
+  return ((::SetEndOfFile(file_.Get()) != FALSE) &&
+          (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) !=
+           FALSE));
+}
+
+bool File::SetTimes(Time last_access_time, Time last_modified_time) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  FILETIME last_access_filetime = last_access_time.ToFileTime();
+  FILETIME last_modified_filetime = last_modified_time.ToFileTime();
+  return (::SetFileTime(file_.Get(), NULL, &last_access_filetime,
+                        &last_modified_filetime) != FALSE);
+}
+
+bool File::GetInfo(Info* info) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  BY_HANDLE_FILE_INFORMATION file_info;
+  if (!GetFileInformationByHandle(file_.Get(), &file_info))
+    return false;
+
+  LARGE_INTEGER size;
+  size.HighPart = file_info.nFileSizeHigh;
+  size.LowPart = file_info.nFileSizeLow;
+  info->size = size.QuadPart;
+  info->is_directory =
+      (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  info->is_symbolic_link = false;  // Windows doesn't have symbolic links.
+  info->last_modified = Time::FromFileTime(file_info.ftLastWriteTime);
+  info->last_accessed = Time::FromFileTime(file_info.ftLastAccessTime);
+  info->creation_time = Time::FromFileTime(file_info.ftCreationTime);
+  return true;
+}
+
+File::Error File::Lock() {
+  DCHECK(IsValid());
+  BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
+  if (!result)
+    return OSErrorToFileError(GetLastError());
+  return FILE_OK;
+}
+
+File::Error File::Unlock() {
+  DCHECK(IsValid());
+  BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
+  if (!result)
+    return OSErrorToFileError(GetLastError());
+  return FILE_OK;
+}
+
+File File::Duplicate() {
+  if (!IsValid())
+    return File();
+
+  HANDLE other_handle = nullptr;
+
+  if (!::DuplicateHandle(GetCurrentProcess(),  // hSourceProcessHandle
+                         GetPlatformFile(),
+                         GetCurrentProcess(),  // hTargetProcessHandle
+                         &other_handle,
+                         0,  // dwDesiredAccess ignored due to SAME_ACCESS
+                         FALSE,  // !bInheritHandle
+                         DUPLICATE_SAME_ACCESS)) {
+    return File(OSErrorToFileError(GetLastError()));
+  }
+
+  File other(other_handle);
+  if (async())
+    other.async_ = true;
+  return other.Pass();
+}
+
+// Static.
+File::Error File::OSErrorToFileError(DWORD last_error) {
+  switch (last_error) {
+    case ERROR_SHARING_VIOLATION:
+      return FILE_ERROR_IN_USE;
+    case ERROR_FILE_EXISTS:
+      return FILE_ERROR_EXISTS;
+    case ERROR_FILE_NOT_FOUND:
+    case ERROR_PATH_NOT_FOUND:
+      return FILE_ERROR_NOT_FOUND;
+    case ERROR_ACCESS_DENIED:
+      return FILE_ERROR_ACCESS_DENIED;
+    case ERROR_TOO_MANY_OPEN_FILES:
+      return FILE_ERROR_TOO_MANY_OPENED;
+    case ERROR_OUTOFMEMORY:
+    case ERROR_NOT_ENOUGH_MEMORY:
+      return FILE_ERROR_NO_MEMORY;
+    case ERROR_HANDLE_DISK_FULL:
+    case ERROR_DISK_FULL:
+    case ERROR_DISK_RESOURCES_EXHAUSTED:
+      return FILE_ERROR_NO_SPACE;
+    case ERROR_USER_MAPPED_FILE:
+      return FILE_ERROR_INVALID_OPERATION;
+    case ERROR_NOT_READY:
+    case ERROR_SECTOR_NOT_FOUND:
+    case ERROR_DEV_NOT_EXIST:
+    case ERROR_IO_DEVICE:
+    case ERROR_FILE_CORRUPT:
+    case ERROR_DISK_CORRUPT:
+      return FILE_ERROR_IO;
+    default:
+      UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
+                                  last_error);
+      return FILE_ERROR_FAILED;
+  }
+}
+
+void File::DoInitialize(const FilePath& name, uint32 flags) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsValid());
+
+  DWORD disposition = 0;
+
+  if (flags & FLAG_OPEN)
+    disposition = OPEN_EXISTING;
+
+  if (flags & FLAG_CREATE) {
+    DCHECK(!disposition);
+    disposition = CREATE_NEW;
+  }
+
+  if (flags & FLAG_OPEN_ALWAYS) {
+    DCHECK(!disposition);
+    disposition = OPEN_ALWAYS;
+  }
+
+  if (flags & FLAG_CREATE_ALWAYS) {
+    DCHECK(!disposition);
+    DCHECK(flags & FLAG_WRITE);
+    disposition = CREATE_ALWAYS;
+  }
+
+  if (flags & FLAG_OPEN_TRUNCATED) {
+    DCHECK(!disposition);
+    DCHECK(flags & FLAG_WRITE);
+    disposition = TRUNCATE_EXISTING;
+  }
+
+  if (!disposition) {
+    NOTREACHED();
+    return;
+  }
+
+  DWORD access = 0;
+  if (flags & FLAG_WRITE)
+    access = GENERIC_WRITE;
+  if (flags & FLAG_APPEND) {
+    DCHECK(!access);
+    access = FILE_APPEND_DATA;
+  }
+  if (flags & FLAG_READ)
+    access |= GENERIC_READ;
+  if (flags & FLAG_WRITE_ATTRIBUTES)
+    access |= FILE_WRITE_ATTRIBUTES;
+  if (flags & FLAG_EXECUTE)
+    access |= GENERIC_EXECUTE;
+
+  DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
+  if (!(flags & FLAG_EXCLUSIVE_WRITE))
+    sharing |= FILE_SHARE_WRITE;
+  if (flags & FLAG_SHARE_DELETE)
+    sharing |= FILE_SHARE_DELETE;
+
+  DWORD create_flags = 0;
+  if (flags & FLAG_ASYNC)
+    create_flags |= FILE_FLAG_OVERLAPPED;
+  if (flags & FLAG_TEMPORARY)
+    create_flags |= FILE_ATTRIBUTE_TEMPORARY;
+  if (flags & FLAG_HIDDEN)
+    create_flags |= FILE_ATTRIBUTE_HIDDEN;
+  if (flags & FLAG_DELETE_ON_CLOSE)
+    create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
+  if (flags & FLAG_BACKUP_SEMANTICS)
+    create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
+
+  file_.Set(CreateFile(name.value().c_str(), access, sharing, NULL,
+                       disposition, create_flags, NULL));
+
+  if (file_.IsValid()) {
+    error_details_ = FILE_OK;
+    async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
+
+    if (flags & (FLAG_OPEN_ALWAYS))
+      created_ = (ERROR_ALREADY_EXISTS != GetLastError());
+    else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
+      created_ = true;
+  } else {
+    error_details_ = OSErrorToFileError(GetLastError());
+  }
+}
+
+bool File::DoFlush() {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  return ::FlushFileBuffers(file_.Get()) != FALSE;
+}
+
+void File::SetPlatformFile(PlatformFile file) {
+  file_.Set(file);
+}
+
+}  // namespace base
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
new file mode 100644
index 0000000..814fc7b
--- /dev/null
+++ b/base/files/important_file_writer.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/important_file_writer.h"
+
+#include <stdio.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/critical_closure.h"
+#include "base/debug/alias.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+namespace {
+
+const int kDefaultCommitIntervalMs = 10000;
+
+// This enum is used to define the buckets for an enumerated UMA histogram.
+// Hence,
+//   (a) existing enumerated constants should never be deleted or reordered, and
+//   (b) new constants should only be appended at the end of the enumeration.
+enum TempFileFailure {
+  FAILED_CREATING,
+  FAILED_OPENING,
+  FAILED_CLOSING,  // Unused.
+  FAILED_WRITING,
+  FAILED_RENAMING,
+  FAILED_FLUSHING,
+  TEMP_FILE_FAILURE_MAX
+};
+
+void LogFailure(const FilePath& path, TempFileFailure failure_code,
+                const std::string& message) {
+  UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code,
+                            TEMP_FILE_FAILURE_MAX);
+  DPLOG(WARNING) << "temp file failure: " << path.value().c_str()
+                 << " : " << message;
+}
+
+// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
+bool WriteScopedStringToFileAtomically(const FilePath& path,
+                                       scoped_ptr<std::string> data) {
+  return ImportantFileWriter::WriteFileAtomically(path, *data);
+}
+
+}  // namespace
+
+// static
+bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
+                                              const std::string& data) {
+#if defined(OS_CHROMEOS)
+  // On Chrome OS, chrome gets killed when it cannot finish shutdown quickly,
+  // and this function seems to be one of the slowest shutdown steps.
+  // Include some info to the report for investigation. crbug.com/418627
+  // TODO(hashimoto): Remove this.
+  struct {
+    size_t data_size;
+    char path[128];
+  } file_info;
+  file_info.data_size = data.size();
+  base::strlcpy(file_info.path, path.value().c_str(),
+                arraysize(file_info.path));
+  base::debug::Alias(&file_info);
+#endif
+  // Write the data to a temp file then rename to avoid data loss if we crash
+  // while writing the file. Ensure that the temp file is on the same volume
+  // as target file, so it can be moved in one step, and that the temp file
+  // is securely created.
+  FilePath tmp_file_path;
+  if (!base::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
+    LogFailure(path, FAILED_CREATING, "could not create temporary file");
+    return false;
+  }
+
+  File tmp_file(tmp_file_path, File::FLAG_OPEN | File::FLAG_WRITE);
+  if (!tmp_file.IsValid()) {
+    LogFailure(path, FAILED_OPENING, "could not open temporary file");
+    return false;
+  }
+
+  // If this happens in the wild something really bad is going on.
+  CHECK_LE(data.length(), static_cast<size_t>(kint32max));
+  int bytes_written = tmp_file.Write(0, data.data(),
+                                     static_cast<int>(data.length()));
+  bool flush_success = tmp_file.Flush();
+  tmp_file.Close();
+
+  if (bytes_written < static_cast<int>(data.length())) {
+    LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
+               IntToString(bytes_written));
+    base::DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  if (!flush_success) {
+    LogFailure(path, FAILED_FLUSHING, "error flushing");
+    base::DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  if (!base::ReplaceFile(tmp_file_path, path, NULL)) {
+    LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
+    base::DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  return true;
+}
+
+ImportantFileWriter::ImportantFileWriter(
+    const FilePath& path,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    : path_(path),
+      task_runner_(task_runner),
+      serializer_(NULL),
+      commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
+      weak_factory_(this) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(task_runner_);
+}
+
+ImportantFileWriter::~ImportantFileWriter() {
+  // We're usually a member variable of some other object, which also tends
+  // to be our serializer. It may not be safe to call back to the parent object
+  // being destructed.
+  DCHECK(!HasPendingWrite());
+}
+
+bool ImportantFileWriter::HasPendingWrite() const {
+  DCHECK(CalledOnValidThread());
+  return timer_.IsRunning();
+}
+
+void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
+  DCHECK(CalledOnValidThread());
+  if (data->length() > static_cast<size_t>(kint32max)) {
+    NOTREACHED();
+    return;
+  }
+
+  if (HasPendingWrite())
+    timer_.Stop();
+
+  auto task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data));
+  if (!PostWriteTask(task)) {
+    // Posting the task to background message loop is not expected
+    // to fail, but if it does, avoid losing data and just hit the disk
+    // on the current thread.
+    NOTREACHED();
+
+    task.Run();
+  }
+}
+
+void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(serializer);
+  serializer_ = serializer;
+
+  if (!timer_.IsRunning()) {
+    timer_.Start(FROM_HERE, commit_interval_, this,
+                 &ImportantFileWriter::DoScheduledWrite);
+  }
+}
+
+void ImportantFileWriter::DoScheduledWrite() {
+  DCHECK(serializer_);
+  scoped_ptr<std::string> data(new std::string);
+  if (serializer_->SerializeData(data.get())) {
+    WriteNow(data.Pass());
+  } else {
+    DLOG(WARNING) << "failed to serialize data to be saved in "
+                  << path_.value().c_str();
+  }
+  serializer_ = NULL;
+}
+
+void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
+    const base::Closure& on_next_successful_write) {
+  DCHECK(on_next_successful_write_.is_null());
+  on_next_successful_write_ = on_next_successful_write;
+}
+
+bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
+  // TODO(gab): This code could always use PostTaskAndReplyWithResult and let
+  // ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but
+  // PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and
+  // suppressing all of those is unrealistic hence we avoid most of them by
+  // using PostTask() in the typical scenario below.
+  if (!on_next_successful_write_.is_null()) {
+    return base::PostTaskAndReplyWithResult(
+        task_runner_.get(),
+        FROM_HERE,
+        MakeCriticalClosure(task),
+        Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
+             weak_factory_.GetWeakPtr()));
+  }
+  return task_runner_->PostTask(
+      FROM_HERE,
+      MakeCriticalClosure(base::Bind(IgnoreResult(task))));
+}
+
+void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
+  DCHECK(CalledOnValidThread());
+  if (result && !on_next_successful_write_.is_null()) {
+    on_next_successful_write_.Run();
+    on_next_successful_write_.Reset();
+  }
+}
+
+}  // namespace base
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
new file mode 100644
index 0000000..99f1a7c
--- /dev/null
+++ b/base/files/important_file_writer.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_IMPORTANT_FILE_WRITER_H_
+#define BASE_FILES_IMPORTANT_FILE_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+class Thread;
+
+// Helper to ensure that a file won't be corrupted by the write (for example on
+// application crash). Consider a naive way to save an important file F:
+//
+// 1. Open F for writing, truncating it.
+// 2. Write new data to F.
+//
+// It's good when it works, but it gets very bad if step 2. doesn't complete.
+// It can be caused by a crash, a computer hang, or a weird I/O error. And you
+// end up with a broken file.
+//
+// To be safe, we don't start with writing directly to F. Instead, we write to
+// to a temporary file. Only after that write is successful, we rename the
+// temporary file to target filename.
+//
+// If you want to know more about this approach and ext3/ext4 fsync issues, see
+// http://valhenson.livejournal.com/37921.html
+class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
+ public:
+  // Used by ScheduleSave to lazily provide the data to be saved. Allows us
+  // to also batch data serializations.
+  class BASE_EXPORT DataSerializer {
+   public:
+    // Should put serialized string in |data| and return true on successful
+    // serialization. Will be called on the same thread on which
+    // ImportantFileWriter has been created.
+    virtual bool SerializeData(std::string* data) = 0;
+
+   protected:
+    virtual ~DataSerializer() {}
+  };
+
+  // Save |data| to |path| in an atomic manner (see the class comment above).
+  // Blocks and writes data on the current thread.
+  static bool WriteFileAtomically(const FilePath& path,
+                                  const std::string& data);
+
+  // Initialize the writer.
+  // |path| is the name of file to write.
+  // |task_runner| is the SequencedTaskRunner instance where on which we will
+  // execute file I/O operations.
+  // All non-const methods, ctor and dtor must be called on the same thread.
+  ImportantFileWriter(
+      const FilePath& path,
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+  // You have to ensure that there are no pending writes at the moment
+  // of destruction.
+  ~ImportantFileWriter();
+
+  const FilePath& path() const { return path_; }
+
+  // Returns true if there is a scheduled write pending which has not yet
+  // been started.
+  bool HasPendingWrite() const;
+
+  // Save |data| to target filename. Does not block. If there is a pending write
+  // scheduled by ScheduleWrite, it is cancelled.
+  void WriteNow(scoped_ptr<std::string> data);
+
+  // Schedule a save to target filename. Data will be serialized and saved
+  // to disk after the commit interval. If another ScheduleWrite is issued
+  // before that, only one serialization and write to disk will happen, and
+  // the most recent |serializer| will be used. This operation does not block.
+  // |serializer| should remain valid through the lifetime of
+  // ImportantFileWriter.
+  void ScheduleWrite(DataSerializer* serializer);
+
+  // Serialize data pending to be saved and execute write on backend thread.
+  void DoScheduledWrite();
+
+  // Registers |on_next_successful_write| to be called once, on the next
+  // successful write event. Only one callback can be set at once.
+  void RegisterOnNextSuccessfulWriteCallback(
+      const base::Closure& on_next_successful_write);
+
+  TimeDelta commit_interval() const {
+    return commit_interval_;
+  }
+
+  void set_commit_interval(const TimeDelta& interval) {
+    commit_interval_ = interval;
+  }
+
+ private:
+  // Helper method for WriteNow().
+  bool PostWriteTask(const Callback<bool()>& task);
+
+  // If |result| is true and |on_next_successful_write_| is set, invokes
+  // |on_successful_write_| and then resets it; no-ops otherwise.
+  void ForwardSuccessfulWrite(bool result);
+
+  // Invoked once and then reset on the next successful write event.
+  base::Closure on_next_successful_write_;
+
+  // Path being written to.
+  const FilePath path_;
+
+  // TaskRunner for the thread on which file I/O can be done.
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // Timer used to schedule commit after ScheduleWrite.
+  OneShotTimer<ImportantFileWriter> timer_;
+
+  // Serializer which will provide the data to be saved.
+  DataSerializer* serializer_;
+
+  // Time delta after which scheduled data will be written to disk.
+  TimeDelta commit_interval_;
+
+  WeakPtrFactory<ImportantFileWriter> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_IMPORTANT_FILE_WRITER_H_
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
new file mode 100644
index 0000000..d376cdc
--- /dev/null
+++ b/base/files/important_file_writer_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/important_file_writer.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+std::string GetFileContent(const FilePath& path) {
+  std::string content;
+  if (!ReadFileToString(path, &content)) {
+    NOTREACHED();
+  }
+  return content;
+}
+
+class DataSerializer : public ImportantFileWriter::DataSerializer {
+ public:
+  explicit DataSerializer(const std::string& data) : data_(data) {
+  }
+
+  bool SerializeData(std::string* output) override {
+    output->assign(data_);
+    return true;
+  }
+
+ private:
+  const std::string data_;
+};
+
+class SuccessfulWriteObserver {
+ public:
+  SuccessfulWriteObserver() : successful_write_observed_(false) {}
+
+  // Register on_successful_write() to be called on the next successful write
+  // of |writer|.
+  void ObserveNextSuccessfulWrite(ImportantFileWriter* writer);
+
+  // Returns true if a successful write was observed via on_successful_write()
+  // and resets the observation state to false regardless.
+  bool GetAndResetObservationState();
+
+ private:
+  void on_successful_write() {
+    EXPECT_FALSE(successful_write_observed_);
+    successful_write_observed_ = true;
+  }
+
+  bool successful_write_observed_;
+
+  DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteObserver);
+};
+
+void SuccessfulWriteObserver::ObserveNextSuccessfulWrite(
+    ImportantFileWriter* writer) {
+  writer->RegisterOnNextSuccessfulWriteCallback(base::Bind(
+      &SuccessfulWriteObserver::on_successful_write, base::Unretained(this)));
+}
+
+bool SuccessfulWriteObserver::GetAndResetObservationState() {
+  bool was_successful_write_observed = successful_write_observed_;
+  successful_write_observed_ = false;
+  return was_successful_write_observed;
+}
+
+}  // namespace
+
+class ImportantFileWriterTest : public testing::Test {
+ public:
+  ImportantFileWriterTest() { }
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    file_ = temp_dir_.path().AppendASCII("test-file");
+  }
+
+ protected:
+  SuccessfulWriteObserver successful_write_observer_;
+  FilePath file_;
+  MessageLoop loop_;
+
+ private:
+  ScopedTempDir temp_dir_;
+};
+
+TEST_F(ImportantFileWriterTest, Basic) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  EXPECT_FALSE(PathExists(writer.path()));
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  writer.WriteNow(make_scoped_ptr(new std::string("foo")));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  EXPECT_FALSE(PathExists(writer.path()));
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
+  writer.WriteNow(make_scoped_ptr(new std::string("foo")));
+  RunLoop().RunUntilIdle();
+
+  // Confirm that the observer is invoked.
+  EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+
+  // Confirm that re-installing the observer works for another write.
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
+  writer.WriteNow(make_scoped_ptr(new std::string("bar")));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("bar", GetFileContent(writer.path()));
+
+  // Confirm that writing again without re-installing the observer doesn't
+  // result in a notification.
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  writer.WriteNow(make_scoped_ptr(new std::string("baz")));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("baz", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, ScheduleWrite) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  EXPECT_FALSE(writer.HasPendingWrite());
+  DataSerializer serializer("foo");
+  writer.ScheduleWrite(&serializer);
+  EXPECT_TRUE(writer.HasPendingWrite());
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  EXPECT_FALSE(writer.HasPendingWrite());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  EXPECT_FALSE(writer.HasPendingWrite());
+  DataSerializer serializer("foo");
+  writer.ScheduleWrite(&serializer);
+  EXPECT_TRUE(writer.HasPendingWrite());
+  writer.DoScheduledWrite();
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  EXPECT_FALSE(writer.HasPendingWrite());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, BatchingWrites) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  DataSerializer foo("foo"), bar("bar"), baz("baz");
+  writer.ScheduleWrite(&foo);
+  writer.ScheduleWrite(&bar);
+  writer.ScheduleWrite(&baz);
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("baz", GetFileContent(writer.path()));
+}
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file.cc b/base/files/memory_mapped_file.cc
new file mode 100644
index 0000000..891fcff
--- /dev/null
+++ b/base/files/memory_mapped_file.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/sys_info.h"
+
+namespace base {
+
+const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile(
+    base::LINKER_INITIALIZED);
+
+MemoryMappedFile::Region::Region(base::LinkerInitialized) : offset(0), size(0) {
+}
+
+MemoryMappedFile::Region::Region(int64 offset, int64 size)
+    : offset(offset), size(size) {
+  DCHECK_GE(offset, 0);
+  DCHECK_GT(size, 0);
+}
+
+bool MemoryMappedFile::Region::operator==(
+    const MemoryMappedFile::Region& other) const {
+  return other.offset == offset && other.size == size;
+}
+
+MemoryMappedFile::~MemoryMappedFile() {
+  CloseHandles();
+}
+
+#if !defined(OS_NACL)
+bool MemoryMappedFile::Initialize(const FilePath& file_name) {
+  if (IsValid())
+    return false;
+
+  file_.Initialize(file_name, File::FLAG_OPEN | File::FLAG_READ);
+
+  if (!file_.IsValid()) {
+    DLOG(ERROR) << "Couldn't open " << file_name.AsUTF8Unsafe();
+    return false;
+  }
+
+  if (!MapFileRegionToMemory(Region::kWholeFile)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::Initialize(File file) {
+  return Initialize(file.Pass(), Region::kWholeFile);
+}
+
+bool MemoryMappedFile::Initialize(File file, const Region& region) {
+  if (IsValid())
+    return false;
+
+  file_ = file.Pass();
+
+  if (!MapFileRegionToMemory(region)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::IsValid() const {
+  return data_ != NULL;
+}
+
+// static
+void MemoryMappedFile::CalculateVMAlignedBoundaries(int64 start,
+                                                    int64 size,
+                                                    int64* aligned_start,
+                                                    int64* aligned_size,
+                                                    int32* offset) {
+  // Sadly, on Windows, the mmap alignment is not just equal to the page size.
+  const int64 mask = static_cast<int64>(SysInfo::VMAllocationGranularity()) - 1;
+  DCHECK_LT(mask, std::numeric_limits<int32>::max());
+  *offset = start & mask;
+  *aligned_start = start & ~mask;
+  *aligned_size = (size + *offset + mask) & ~mask;
+}
+#endif
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h
new file mode 100644
index 0000000..8a7f045
--- /dev/null
+++ b/base/files/memory_mapped_file.h
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_MEMORY_MAPPED_FILE_H_
+#define BASE_FILES_MEMORY_MAPPED_FILE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+class FilePath;
+
+class BASE_EXPORT MemoryMappedFile {
+ public:
+  // The default constructor sets all members to invalid/null values.
+  MemoryMappedFile();
+  ~MemoryMappedFile();
+
+  // Used to hold information about a region [offset + size] of a file.
+  struct BASE_EXPORT Region {
+    static const Region kWholeFile;
+
+    Region(int64 offset, int64 size);
+
+    bool operator==(const Region& other) const;
+
+    // Start of the region (measured in bytes from the beginning of the file).
+    int64 offset;
+
+    // Length of the region in bytes.
+    int64 size;
+
+   private:
+    // This ctor is used only by kWholeFile, to construct a zero-sized Region
+    // (which is forbidden by the public ctor) and uniquely identify kWholeFile.
+    Region(base::LinkerInitialized);
+  };
+
+  // Opens an existing file and maps it into memory. Access is restricted to
+  // read only. If this object already points to a valid memory mapped file
+  // then this method will fail and return false. If it cannot open the file,
+  // the file does not exist, or the memory mapping fails, it will return false.
+  // Later we may want to allow the user to specify access.
+  bool Initialize(const FilePath& file_name);
+
+  // As above, but works with an already-opened file. MemoryMappedFile takes
+  // ownership of |file| and closes it when done.
+  bool Initialize(File file);
+
+  // As above, but works with a region of an already-opened file.
+  bool Initialize(File file, const Region& region);
+
+#if defined(OS_WIN)
+  // Opens an existing file and maps it as an image section. Please refer to
+  // the Initialize function above for additional information.
+  bool InitializeAsImageSection(const FilePath& file_name);
+#endif  // OS_WIN
+
+  const uint8* data() const { return data_; }
+  size_t length() const { return length_; }
+
+  // Is file_ a valid file handle that points to an open, memory mapped file?
+  bool IsValid() const;
+
+ private:
+  // Given the arbitrarily aligned memory region [start, size], returns the
+  // boundaries of the region aligned to the granularity specified by the OS,
+  // (a page on Linux, ~32k on Windows) as follows:
+  // - |aligned_start| is page aligned and <= |start|.
+  // - |aligned_size| is a multiple of the VM granularity and >= |size|.
+  // - |offset| is the displacement of |start| w.r.t |aligned_start|.
+  static void CalculateVMAlignedBoundaries(int64 start,
+                                           int64 size,
+                                           int64* aligned_start,
+                                           int64* aligned_size,
+                                           int32* offset);
+
+  // Map the file to memory, set data_ to that memory address. Return true on
+  // success, false on any kind of failure. This is a helper for Initialize().
+  bool MapFileRegionToMemory(const Region& region);
+
+  // Closes all open handles.
+  void CloseHandles();
+
+  File file_;
+  uint8* data_;
+  size_t length_;
+
+#if defined(OS_WIN)
+  win::ScopedHandle file_mapping_;
+  bool image_;  // Map as an image.
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_MEMORY_MAPPED_FILE_H_
diff --git a/base/files/memory_mapped_file_posix.cc b/base/files/memory_mapped_file_posix.cc
new file mode 100644
index 0000000..168da92
--- /dev/null
+++ b/base/files/memory_mapped_file_posix.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
+}
+
+#if !defined(OS_NACL)
+bool MemoryMappedFile::MapFileRegionToMemory(
+    const MemoryMappedFile::Region& region) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  off_t map_start = 0;
+  size_t map_size = 0;
+  int32 data_offset = 0;
+
+  if (region == MemoryMappedFile::Region::kWholeFile) {
+    int64 file_len = file_.GetLength();
+    if (file_len == -1) {
+      DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
+      return false;
+    }
+    map_size = static_cast<size_t>(file_len);
+    length_ = map_size;
+  } else {
+    // The region can be arbitrarily aligned. mmap, instead, requires both the
+    // start and size to be page-aligned. Hence, we map here the page-aligned
+    // outer region [|aligned_start|, |aligned_start| + |size|] which contains
+    // |region| and then add up the |data_offset| displacement.
+    int64 aligned_start = 0;
+    int64 aligned_size = 0;
+    CalculateVMAlignedBoundaries(region.offset,
+                                 region.size,
+                                 &aligned_start,
+                                 &aligned_size,
+                                 &data_offset);
+
+    // Ensure that the casts in the mmap call below are sane.
+    if (aligned_start < 0 || aligned_size < 0 ||
+        aligned_start > std::numeric_limits<off_t>::max() ||
+        static_cast<uint64>(aligned_size) >
+            std::numeric_limits<size_t>::max() ||
+        static_cast<uint64>(region.size) > std::numeric_limits<size_t>::max()) {
+      DLOG(ERROR) << "Region bounds are not valid for mmap";
+      return false;
+    }
+
+    map_start = static_cast<off_t>(aligned_start);
+    map_size = static_cast<size_t>(aligned_size);
+    length_ = static_cast<size_t>(region.size);
+  }
+
+  data_ = static_cast<uint8*>(mmap(NULL,
+                                   map_size,
+                                   PROT_READ,
+                                   MAP_SHARED,
+                                   file_.GetPlatformFile(),
+                                   map_start));
+  if (data_ == MAP_FAILED) {
+    DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
+    return false;
+  }
+
+  data_ += data_offset;
+  return true;
+}
+#endif
+
+void MemoryMappedFile::CloseHandles() {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (data_ != NULL)
+    munmap(data_, length_);
+  file_.Close();
+
+  data_ = NULL;
+  length_ = 0;
+}
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file_unittest.cc b/base/files/memory_mapped_file_unittest.cc
new file mode 100644
index 0000000..d0833b5
--- /dev/null
+++ b/base/files/memory_mapped_file_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+
+// Create a temporary buffer and fill it with a watermark sequence.
+scoped_ptr<uint8[]> CreateTestBuffer(size_t size, size_t offset) {
+  scoped_ptr<uint8[]> buf(new uint8[size]);
+  for (size_t i = 0; i < size; ++i)
+    buf.get()[i] = static_cast<uint8>((offset + i) % 253);
+  return buf.Pass();
+}
+
+// Check that the watermark sequence is consistent with the |offset| provided.
+bool CheckBufferContents(const uint8* data, size_t size, size_t offset) {
+  scoped_ptr<uint8[]> test_data(CreateTestBuffer(size, offset));
+  return memcmp(test_data.get(), data, size) == 0;
+}
+
+class MemoryMappedFileTest : public PlatformTest {
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+    CreateTemporaryFile(&temp_file_path_);
+  }
+
+  void TearDown() override { EXPECT_TRUE(DeleteFile(temp_file_path_, false)); }
+
+  void CreateTemporaryTestFile(size_t size) {
+    File file(temp_file_path_,
+              File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE);
+    EXPECT_TRUE(file.IsValid());
+
+    scoped_ptr<uint8[]> test_data(CreateTestBuffer(size, 0));
+    size_t bytes_written =
+        file.Write(0, reinterpret_cast<char*>(test_data.get()), size);
+    EXPECT_EQ(size, bytes_written);
+    file.Close();
+  }
+
+  const FilePath temp_file_path() const { return temp_file_path_; }
+
+ private:
+  FilePath temp_file_path_;
+};
+
+TEST_F(MemoryMappedFileTest, MapWholeFileByPath) {
+  const size_t kFileSize = 68 * 1024;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+  map.Initialize(temp_file_path());
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapWholeFileByFD) {
+  const size_t kFileSize = 68 * 1024;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+  map.Initialize(File(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ));
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapSmallFile) {
+  const size_t kFileSize = 127;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+  map.Initialize(temp_file_path());
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapWholeFileUsingRegion) {
+  const size_t kFileSize = 157 * 1024;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region::kWholeFile);
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapPartialRegionAtBeginning) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kPartialSize = 4 * 1024 + 32;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(0, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapPartialRegionAtEnd) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kPartialSize = 5 * 1024 - 32;
+  const size_t kOffset = kFileSize - kPartialSize;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
+}
+
+TEST_F(MemoryMappedFileTest, MapSmallPartialRegionInTheMiddle) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kOffset = 1024 * 5 + 32;
+  const size_t kPartialSize = 8;
+
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
+}
+
+TEST_F(MemoryMappedFileTest, MapLargePartialRegionInTheMiddle) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kOffset = 1024 * 5 + 32;
+  const size_t kPartialSize = 16 * 1024 - 32;
+
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file_win.cc b/base/files/memory_mapped_file_win.cc
new file mode 100644
index 0000000..4e7e934
--- /dev/null
+++ b/base/files/memory_mapped_file_win.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0), image_(false) {
+}
+
+bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) {
+  image_ = true;
+  return Initialize(file_name);
+}
+
+bool MemoryMappedFile::MapFileRegionToMemory(
+    const MemoryMappedFile::Region& region) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (!file_.IsValid())
+    return false;
+
+  int flags = image_ ? SEC_IMAGE | PAGE_READONLY : PAGE_READONLY;
+
+  file_mapping_.Set(::CreateFileMapping(file_.GetPlatformFile(), NULL,
+                                        flags, 0, 0, NULL));
+  if (!file_mapping_.IsValid())
+    return false;
+
+  LARGE_INTEGER map_start = {0};
+  SIZE_T map_size = 0;
+  int32 data_offset = 0;
+
+  if (region == MemoryMappedFile::Region::kWholeFile) {
+    int64 file_len = file_.GetLength();
+    if (file_len <= 0 || file_len > kint32max)
+      return false;
+    length_ = static_cast<size_t>(file_len);
+  } else {
+    // The region can be arbitrarily aligned. MapViewOfFile, instead, requires
+    // that the start address is aligned to the VM granularity (which is
+    // typically larger than a page size, for instance 32k).
+    // Also, conversely to POSIX's mmap, the |map_size| doesn't have to be
+    // aligned and must be less than or equal the mapped file size.
+    // We map here the outer region [|aligned_start|, |aligned_start+size|]
+    // which contains |region| and then add up the |data_offset| displacement.
+    int64 aligned_start = 0;
+    int64 ignored = 0;
+    CalculateVMAlignedBoundaries(
+        region.offset, region.size, &aligned_start, &ignored, &data_offset);
+    int64 size = region.size + data_offset;
+
+    // Ensure that the casts below in the MapViewOfFile call are sane.
+    if (aligned_start < 0 || size < 0 ||
+        static_cast<uint64>(size) > std::numeric_limits<SIZE_T>::max()) {
+      DLOG(ERROR) << "Region bounds are not valid for MapViewOfFile";
+      return false;
+    }
+    map_start.QuadPart = aligned_start;
+    map_size = static_cast<SIZE_T>(size);
+    length_ = static_cast<size_t>(region.size);
+  }
+
+  data_ = static_cast<uint8*>(::MapViewOfFile(file_mapping_.Get(),
+                                              FILE_MAP_READ,
+                                              map_start.HighPart,
+                                              map_start.LowPart,
+                                              map_size));
+  if (data_ == NULL)
+    return false;
+  data_ += data_offset;
+  return true;
+}
+
+void MemoryMappedFile::CloseHandles() {
+  if (data_)
+    ::UnmapViewOfFile(data_);
+  if (file_mapping_.IsValid())
+    file_mapping_.Close();
+  if (file_.IsValid())
+    file_.Close();
+
+  data_ = NULL;
+  length_ = 0;
+}
+
+}  // namespace base
diff --git a/base/files/scoped_file.cc b/base/files/scoped_file.cc
new file mode 100644
index 0000000..39f064d
--- /dev/null
+++ b/base/files/scoped_file.cc
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_file.h"
+
+#include "base/logging.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+
+#include "base/posix/eintr_wrapper.h"
+#endif
+
+namespace base {
+namespace internal {
+
+#if defined(OS_POSIX)
+
+// static
+void ScopedFDCloseTraits::Free(int fd) {
+  // It's important to crash here.
+  // There are security implications to not closing a file descriptor
+  // properly. As file descriptors are "capabilities", keeping them open
+  // would make the current process keep access to a resource. Much of
+  // Chrome relies on being able to "drop" such access.
+  // It's especially problematic on Linux with the setuid sandbox, where
+  // a single open directory would bypass the entire security model.
+  PCHECK(0 == IGNORE_EINTR(close(fd)));
+}
+
+#endif  // OS_POSIX
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/files/scoped_file.h b/base/files/scoped_file.h
new file mode 100644
index 0000000..106f6ad
--- /dev/null
+++ b/base/files/scoped_file.h
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_SCOPED_FILE_H_
+#define BASE_FILES_SCOPED_FILE_H_
+
+#include <stdio.h>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/scoped_generic.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_POSIX)
+struct BASE_EXPORT ScopedFDCloseTraits {
+  static int InvalidValue() {
+    return -1;
+  }
+  static void Free(int fd);
+};
+#endif
+
+// Functor for |ScopedFILE| (below).
+struct ScopedFILECloser {
+  inline void operator()(FILE* x) const {
+    if (x)
+      fclose(x);
+  }
+};
+
+}  // namespace internal
+
+// -----------------------------------------------------------------------------
+
+#if defined(OS_POSIX)
+// A low-level Posix file descriptor closer class. Use this when writing
+// platform-specific code, especially that does non-file-like things with the
+// FD (like sockets).
+//
+// If you're writing low-level Windows code, see base/win/scoped_handle.h
+// which provides some additional functionality.
+//
+// If you're writing cross-platform code that deals with actual files, you
+// should generally use base::File instead which can be constructed with a
+// handle, and in addition to handling ownership, has convenient cross-platform
+// file manipulation functions on it.
+typedef ScopedGeneric<int, internal::ScopedFDCloseTraits> ScopedFD;
+#endif
+
+// Automatically closes |FILE*|s.
+typedef scoped_ptr<FILE, internal::ScopedFILECloser> ScopedFILE;
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_FILE_H_
diff --git a/base/files/scoped_temp_dir.cc b/base/files/scoped_temp_dir.cc
new file mode 100644
index 0000000..27b758e
--- /dev/null
+++ b/base/files/scoped_temp_dir.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_temp_dir.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+ScopedTempDir::ScopedTempDir() {
+}
+
+ScopedTempDir::~ScopedTempDir() {
+  if (!path_.empty() && !Delete())
+    DLOG(WARNING) << "Could not delete temp dir in dtor.";
+}
+
+bool ScopedTempDir::CreateUniqueTempDir() {
+  if (!path_.empty())
+    return false;
+
+  // This "scoped_dir" prefix is only used on Windows and serves as a template
+  // for the unique name.
+  if (!base::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_dir"), &path_))
+    return false;
+
+  return true;
+}
+
+bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) {
+  if (!path_.empty())
+    return false;
+
+  // If |base_path| does not exist, create it.
+  if (!base::CreateDirectory(base_path))
+    return false;
+
+  // Create a new, uniquely named directory under |base_path|.
+  if (!base::CreateTemporaryDirInDir(base_path,
+                                     FILE_PATH_LITERAL("scoped_dir_"),
+                                     &path_))
+    return false;
+
+  return true;
+}
+
+bool ScopedTempDir::Set(const FilePath& path) {
+  if (!path_.empty())
+    return false;
+
+  if (!DirectoryExists(path) && !base::CreateDirectory(path))
+    return false;
+
+  path_ = path;
+  return true;
+}
+
+bool ScopedTempDir::Delete() {
+  if (path_.empty())
+    return false;
+
+  bool ret = base::DeleteFile(path_, true);
+  if (ret) {
+    // We only clear the path if deleted the directory.
+    path_.clear();
+  }
+
+  return ret;
+}
+
+FilePath ScopedTempDir::Take() {
+  FilePath ret = path_;
+  path_ = FilePath();
+  return ret;
+}
+
+bool ScopedTempDir::IsValid() const {
+  return !path_.empty() && DirectoryExists(path_);
+}
+
+}  // namespace base
diff --git a/base/files/scoped_temp_dir.h b/base/files/scoped_temp_dir.h
new file mode 100644
index 0000000..5f63e09
--- /dev/null
+++ b/base/files/scoped_temp_dir.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_SCOPED_TEMP_DIR_H_
+#define BASE_FILES_SCOPED_TEMP_DIR_H_
+
+// An object representing a temporary / scratch directory that should be cleaned
+// up (recursively) when this object goes out of scope.  Note that since
+// deletion occurs during the destructor, no further error handling is possible
+// if the directory fails to be deleted.  As a result, deletion is not
+// guaranteed by this class.
+//
+// Multiple calls to the methods which establish a temporary directory
+// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have
+// intervening calls to Delete or Take, or the calls will fail.
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+
+namespace base {
+
+class BASE_EXPORT ScopedTempDir {
+ public:
+  // No directory is owned/created initially.
+  ScopedTempDir();
+
+  // Recursively delete path.
+  ~ScopedTempDir();
+
+  // Creates a unique directory in TempPath, and takes ownership of it.
+  // See file_util::CreateNewTemporaryDirectory.
+  bool CreateUniqueTempDir() WARN_UNUSED_RESULT;
+
+  // Creates a unique directory under a given path, and takes ownership of it.
+  bool CreateUniqueTempDirUnderPath(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // Takes ownership of directory at |path|, creating it if necessary.
+  // Don't call multiple times unless Take() has been called first.
+  bool Set(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // Deletes the temporary directory wrapped by this object.
+  bool Delete() WARN_UNUSED_RESULT;
+
+  // Caller takes ownership of the temporary directory so it won't be destroyed
+  // when this object goes out of scope.
+  FilePath Take();
+
+  const FilePath& path() const { return path_; }
+
+  // Returns true if path_ is non-empty and exists.
+  bool IsValid() const;
+
+ private:
+  FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTempDir);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_TEMP_DIR_H_
diff --git a/base/files/scoped_temp_dir_unittest.cc b/base/files/scoped_temp_dir_unittest.cc
new file mode 100644
index 0000000..a19f34d
--- /dev/null
+++ b/base/files/scoped_temp_dir_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedTempDir, FullPath) {
+  FilePath test_path;
+  base::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_temp_dir"),
+                               &test_path);
+
+  // Against an existing dir, it should get destroyed when leaving scope.
+  EXPECT_TRUE(DirectoryExists(test_path));
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+    EXPECT_TRUE(dir.IsValid());
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+    // Now the dir doesn't exist, so ensure that it gets created.
+    EXPECT_TRUE(DirectoryExists(test_path));
+    // When we call Release(), it shouldn't get destroyed when leaving scope.
+    FilePath path = dir.Take();
+    EXPECT_EQ(path.value(), test_path.value());
+    EXPECT_FALSE(dir.IsValid());
+  }
+  EXPECT_TRUE(DirectoryExists(test_path));
+
+  // Clean up.
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, TempDir) {
+  // In this case, just verify that a directory was created and that it's a
+  // child of TempDir.
+  FilePath test_path;
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.CreateUniqueTempDir());
+    test_path = dir.path();
+    EXPECT_TRUE(DirectoryExists(test_path));
+    FilePath tmp_dir;
+    EXPECT_TRUE(base::GetTempDir(&tmp_dir));
+    EXPECT_TRUE(test_path.value().find(tmp_dir.value()) != std::string::npos);
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, UniqueTempDirUnderPath) {
+  // Create a path which will contain a unique temp path.
+  FilePath base_path;
+  ASSERT_TRUE(base::CreateNewTempDirectory(FILE_PATH_LITERAL("base_dir"),
+                                           &base_path));
+
+  FilePath test_path;
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path));
+    test_path = dir.path();
+    EXPECT_TRUE(DirectoryExists(test_path));
+    EXPECT_TRUE(base_path.IsParent(test_path));
+    EXPECT_TRUE(test_path.value().find(base_path.value()) != std::string::npos);
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+  base::DeleteFile(base_path, true);
+}
+
+TEST(ScopedTempDir, MultipleInvocations) {
+  ScopedTempDir dir;
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(dir.CreateUniqueTempDir());
+  EXPECT_TRUE(dir.Delete());
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(dir.CreateUniqueTempDir());
+  ScopedTempDir other_dir;
+  EXPECT_TRUE(other_dir.Set(dir.Take()));
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(other_dir.CreateUniqueTempDir());
+}
+
+#if defined(OS_WIN)
+TEST(ScopedTempDir, LockedTempDir) {
+  ScopedTempDir dir;
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  base::File file(dir.path().Append(FILE_PATH_LITERAL("temp")),
+                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  EXPECT_FALSE(dir.Delete());  // We should not be able to delete.
+  EXPECT_FALSE(dir.path().empty());  // We should still have a valid path.
+  file.Close();
+  // Now, we should be able to delete.
+  EXPECT_TRUE(dir.Delete());
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace base
diff --git a/base/format_macros.h b/base/format_macros.h
new file mode 100644
index 0000000..4d90c59
--- /dev/null
+++ b/base/format_macros.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FORMAT_MACROS_H_
+#define BASE_FORMAT_MACROS_H_
+
+// This file defines the format macros for some integer types.
+
+// To print a 64-bit value in a portable way:
+//   int64_t value;
+//   printf("xyz:%" PRId64, value);
+// The "d" in the macro corresponds to %d; you can also use PRIu64 etc.
+//
+// For wide strings, prepend "Wide" to the macro:
+//   int64_t value;
+//   StringPrintf(L"xyz: %" WidePRId64, value);
+//
+// To print a size_t value in a portable way:
+//   size_t size;
+//   printf("xyz: %" PRIuS, size);
+// The "u" in the macro corresponds to %u, and S is for "size".
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+
+#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
+#error "inttypes.h has already been included before this header file, but "
+#error "without __STDC_FORMAT_MACROS defined."
+#endif
+
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <inttypes.h>
+
+// GCC will concatenate wide and narrow strings correctly, so nothing needs to
+// be done here.
+#define WidePRId64 PRId64
+#define WidePRIu64 PRIu64
+#define WidePRIx64 PRIx64
+
+#if !defined(PRIuS)
+#define PRIuS "zu"
+#endif
+
+// The size of NSInteger and NSUInteger varies between 32-bit and 64-bit
+// architectures and Apple does not provides standard format macros and
+// recommends casting. This has many drawbacks, so instead define macros
+// for formatting those types.
+#if defined(OS_MACOSX)
+#if defined(ARCH_CPU_64_BITS)
+#if !defined(PRIdNS)
+#define PRIdNS "ld"
+#endif
+#if !defined(PRIuNS)
+#define PRIuNS "lu"
+#endif
+#if !defined(PRIxNS)
+#define PRIxNS "lx"
+#endif
+#else  // defined(ARCH_CPU_64_BITS)
+#if !defined(PRIdNS)
+#define PRIdNS "d"
+#endif
+#if !defined(PRIuNS)
+#define PRIuNS "u"
+#endif
+#if !defined(PRIxNS)
+#define PRIxNS "x"
+#endif
+#endif
+#endif  // defined(OS_MACOSX)
+
+#else  // OS_WIN
+
+#if !defined(PRId64)
+#define PRId64 "I64d"
+#endif
+
+#if !defined(PRIu64)
+#define PRIu64 "I64u"
+#endif
+
+#if !defined(PRIx64)
+#define PRIx64 "I64x"
+#endif
+
+#define WidePRId64 L"I64d"
+#define WidePRIu64 L"I64u"
+#define WidePRIx64 L"I64x"
+
+#if !defined(PRIuS)
+#define PRIuS "Iu"
+#endif
+
+#endif
+
+#endif  // BASE_FORMAT_MACROS_H_
diff --git a/base/gmock_unittest.cc b/base/gmock_unittest.cc
new file mode 100644
index 0000000..855380a
--- /dev/null
+++ b/base/gmock_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This test is a simple sanity check to make sure gmock is able to build/link
+// correctly.  It just instantiates a mock object and runs through a couple of
+// the basic mock features.
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Gmock matchers and actions that we use below.
+using testing::AnyOf;
+using testing::Eq;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::WithArg;
+using testing::_;
+
+namespace {
+
+// Simple class that we can mock out the behavior for.  Everything is virtual
+// for easy mocking.
+class SampleClass {
+ public:
+  SampleClass() {}
+  virtual ~SampleClass() {}
+
+  virtual int ReturnSomething() {
+    return -1;
+  }
+
+  virtual void ReturnNothingConstly() const {
+  }
+
+  virtual void OutputParam(int* a) {
+  }
+
+  virtual int ReturnSecond(int a, int b) {
+    return b;
+  }
+};
+
+// Declare a mock for the class.
+class MockSampleClass : public SampleClass {
+ public:
+  MOCK_METHOD0(ReturnSomething, int());
+  MOCK_CONST_METHOD0(ReturnNothingConstly, void());
+  MOCK_METHOD1(OutputParam, void(int* a));
+  MOCK_METHOD2(ReturnSecond, int(int a, int b));
+};
+
+// Create a couple of custom actions.  Custom actions can be used for adding
+// more complex behavior into your mock...though if you start needing these, ask
+// if you're asking your mock to do too much.
+ACTION(ReturnVal) {
+  // Return the first argument received.
+  return arg0;
+}
+ACTION(ReturnSecond) {
+  // Returns the second argument.  This basically implemetns ReturnSecond.
+  return arg1;
+}
+
+TEST(GmockTest, SimpleMatchAndActions) {
+  // Basic test of some simple gmock matchers, actions, and cardinality
+  // expectations.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSomething())
+      .WillOnce(Return(1))
+      .WillOnce(Return(2))
+      .WillOnce(Return(3));
+  EXPECT_EQ(1, mock.ReturnSomething());
+  EXPECT_EQ(2, mock.ReturnSomething());
+  EXPECT_EQ(3, mock.ReturnSomething());
+
+  EXPECT_CALL(mock, ReturnNothingConstly()).Times(2);
+  mock.ReturnNothingConstly();
+  mock.ReturnNothingConstly();
+}
+
+TEST(GmockTest, AssignArgument) {
+  // Capture an argument for examination.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, OutputParam(_))
+      .WillRepeatedly(SetArgumentPointee<0>(5));
+
+  int arg = 0;
+  mock.OutputParam(&arg);
+  EXPECT_EQ(5, arg);
+}
+
+TEST(GmockTest, SideEffects) {
+  // Capture an argument for examination.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, OutputParam(_))
+      .WillRepeatedly(SetArgumentPointee<0>(5));
+
+  int arg = 0;
+  mock.OutputParam(&arg);
+  EXPECT_EQ(5, arg);
+}
+
+TEST(GmockTest, CustomAction_ReturnSecond) {
+  // Test a mock of the ReturnSecond behavior using an action that provides an
+  // alternate implementation of the function.  Danger here though, this is
+  // starting to add too much behavior of the mock, which means the mock
+  // implementation might start to have bugs itself.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
+      .WillRepeatedly(ReturnSecond());
+  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
+  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
+  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
+}
+
+TEST(GmockTest, CustomAction_ReturnVal) {
+  // Alternate implemention of ReturnSecond using a more general custom action,
+  // and a WithArg adapter to bridge the interfaces.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
+      .WillRepeatedly(WithArg<1>(ReturnVal()));
+  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
+  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
+  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
+}
+
+}  // namespace
diff --git a/base/gtest_prod_util.h b/base/gtest_prod_util.h
new file mode 100644
index 0000000..3289e63
--- /dev/null
+++ b/base/gtest_prod_util.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_GTEST_PROD_UTIL_H_
+#define BASE_GTEST_PROD_UTIL_H_
+
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+// This is a wrapper for gtest's FRIEND_TEST macro that friends
+// test with all possible prefixes. This is very helpful when changing the test
+// prefix, because the friend declarations don't need to be updated.
+//
+// Example usage:
+//
+// class MyClass {
+//  private:
+//   void MyMethod();
+//   FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod);
+// };
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+  FRIEND_TEST(test_case_name, test_name); \
+  FRIEND_TEST(test_case_name, DISABLED_##test_name); \
+  FRIEND_TEST(test_case_name, FLAKY_##test_name)
+
+// C++ compilers will refuse to compile the following code:
+//
+// namespace foo {
+// class MyClass {
+//  private:
+//   FRIEND_TEST_ALL_PREFIXES(MyClassTest, TestMethod);
+//   bool private_var;
+// };
+// }  // namespace foo
+//
+// class MyClassTest::TestMethod() {
+//   foo::MyClass foo_class;
+//   foo_class.private_var = true;
+// }
+//
+// Unless you forward declare MyClassTest::TestMethod outside of namespace foo.
+// Use FORWARD_DECLARE_TEST to do so for all possible prefixes.
+//
+// Example usage:
+//
+// FORWARD_DECLARE_TEST(MyClassTest, TestMethod);
+//
+// namespace foo {
+// class MyClass {
+//  private:
+//   FRIEND_TEST_ALL_PREFIXES(::MyClassTest, TestMethod);  // NOTE use of ::
+//   bool private_var;
+// };
+// }  // namespace foo
+//
+// class MyClassTest::TestMethod() {
+//   foo::MyClass foo_class;
+//   foo_class.private_var = true;
+// }
+
+#define FORWARD_DECLARE_TEST(test_case_name, test_name) \
+  class test_case_name##_##test_name##_Test; \
+  class test_case_name##_##DISABLED_##test_name##_Test; \
+  class test_case_name##_##FLAKY_##test_name##_Test
+
+#endif  // BASE_GTEST_PROD_UTIL_H_
diff --git a/base/guid.cc b/base/guid.cc
new file mode 100644
index 0000000..be5c58b
--- /dev/null
+++ b/base/guid.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include "base/strings/string_util.h"
+
+namespace base {
+
+bool IsValidGUID(const std::string& guid) {
+  const size_t kGUIDLength = 36U;
+  if (guid.length() != kGUIDLength)
+    return false;
+
+  for (size_t i = 0; i < guid.length(); ++i) {
+    char current = guid[i];
+    if (i == 8 || i == 13 || i == 18 || i == 23) {
+      if (current != '-')
+        return false;
+    } else {
+      if (!IsHexDigit(current))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/guid.h b/base/guid.h
new file mode 100644
index 0000000..abcc589
--- /dev/null
+++ b/base/guid.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_GUID_H_
+#define BASE_GUID_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
+// If GUID generation fails an empty string is returned.
+// The POSIX implementation uses pseudo random number generation to create
+// the GUID.  The Windows implementation uses system services.
+BASE_EXPORT std::string GenerateGUID();
+
+// Returns true if the input string conforms to the GUID format.
+BASE_EXPORT bool IsValidGUID(const std::string& guid);
+
+#if defined(OS_POSIX)
+// For unit testing purposes only.  Do not use outside of tests.
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_GUID_H_
diff --git a/base/guid_posix.cc b/base/guid_posix.cc
new file mode 100644
index 0000000..f0fedc2
--- /dev/null
+++ b/base/guid_posix.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+std::string GenerateGUID() {
+  uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
+
+  // Set the GUID to version 4 as described in RFC 4122, section 4.4.
+  // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
+  // where y is one of [8, 9, A, B].
+
+  // Clear the version bits and set the version to 4:
+  sixteen_bytes[0] &= 0xffffffffffff0fffULL;
+  sixteen_bytes[0] |= 0x0000000000004000ULL;
+
+  // Set the two most significant bits (bits 6 and 7) of the
+  // clock_seq_hi_and_reserved to zero and one, respectively:
+  sixteen_bytes[1] &= 0x3fffffffffffffffULL;
+  sixteen_bytes[1] |= 0x8000000000000000ULL;
+
+  return RandomDataToGUIDString(sixteen_bytes);
+}
+
+// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
+// use this as well.
+std::string RandomDataToGUIDString(const uint64 bytes[2]) {
+  return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
+                      static_cast<unsigned int>(bytes[0] >> 32),
+                      static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
+                      static_cast<unsigned int>(bytes[0] & 0x0000ffff),
+                      static_cast<unsigned int>(bytes[1] >> 48),
+                      bytes[1] & 0x0000ffffffffffffULL);
+}
+
+}  // namespace base
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc
new file mode 100644
index 0000000..4eda7f6
--- /dev/null
+++ b/base/guid_unittest.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include <limits>
+
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+
+namespace {
+
+bool IsGUIDv4(const std::string& guid) {
+  // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
+  // where y is one of [8, 9, A, B].
+  return base::IsValidGUID(guid) && guid[14] == '4' &&
+         (guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' ||
+          guid[19] == 'a' || guid[19] == 'B' || guid[19] == 'b');
+}
+
+}  // namespace
+
+
+TEST(GUIDTest, GUIDGeneratesAllZeroes) {
+  uint64 bytes[] = { 0, 0 };
+  std::string clientid = 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));
+    EXPECT_TRUE(base::IsValidGUID(base::StringToLowerASCII(guid)));
+    EXPECT_TRUE(base::IsValidGUID(StringToUpperASCII(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);
+#if defined(OS_POSIX)
+    EXPECT_TRUE(IsGUIDv4(guid1));
+    EXPECT_TRUE(IsGUIDv4(guid2));
+#endif
+  }
+}
diff --git a/base/guid_win.cc b/base/guid_win.cc
new file mode 100644
index 0000000..da3453d
--- /dev/null
+++ b/base/guid_win.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/guid.h"
+
+#include <stdlib.h>
+
+#include <objbase.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+std::string GenerateGUID() {
+  const int kGUIDSize = 39;
+
+  GUID guid;
+  HRESULT guid_result = CoCreateGuid(&guid);
+  DCHECK(SUCCEEDED(guid_result));
+  if (!SUCCEEDED(guid_result))
+    return std::string();
+
+  std::wstring guid_string;
+  int result = StringFromGUID2(guid,
+                               WriteInto(&guid_string, kGUIDSize), kGUIDSize);
+  DCHECK(result == kGUIDSize);
+  if (result != kGUIDSize)
+    return std::string();
+
+  return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
+}
+
+}  // namespace base
diff --git a/base/hash.cc b/base/hash.cc
new file mode 100644
index 0000000..a7db64a
--- /dev/null
+++ b/base/hash.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/hash.h"
+
+// Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
+// code did not come with its own header file, so declaring the function here.)
+// Note: This algorithm is also in Blink under Source/wtf/StringHasher.h.
+extern "C" uint32_t SuperFastHash(const char* data, int len);
+
+namespace base {
+
+uint32 SuperFastHash(const char* data, int len) {
+  return ::SuperFastHash(data, len);
+}
+
+}  // namespace base
diff --git a/base/hash.h b/base/hash.h
new file mode 100644
index 0000000..e46f6ac
--- /dev/null
+++ b/base/hash.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_HASH_H_
+#define BASE_HASH_H_
+
+#include <limits>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+
+// WARNING: This hash function should not be used for any cryptographic purpose.
+BASE_EXPORT uint32 SuperFastHash(const char* data, int len);
+
+// Computes a hash of a memory buffer |data| of a given |length|.
+// WARNING: This hash function should not be used for any cryptographic purpose.
+inline uint32 Hash(const char* data, size_t length) {
+  if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    NOTREACHED();
+    return 0;
+  }
+  return SuperFastHash(data, static_cast<int>(length));
+}
+
+// Computes a hash of a string |str|.
+// WARNING: This hash function should not be used for any cryptographic purpose.
+inline uint32 Hash(const std::string& str) {
+  return Hash(str.data(), str.size());
+}
+
+}  // namespace base
+
+#endif  // BASE_HASH_H_
diff --git a/base/hash_unittest.cc b/base/hash_unittest.cc
new file mode 100644
index 0000000..fc8a751
--- /dev/null
+++ b/base/hash_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/hash.h"
+
+#include <string>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(HashTest, String) {
+  std::string str;
+  // Empty string (should hash to 0).
+  str = "";
+  EXPECT_EQ(0u, Hash(str));
+
+  // Simple test.
+  str = "hello world";
+  EXPECT_EQ(2794219650u, Hash(str));
+
+  // Change one bit.
+  str = "helmo world";
+  EXPECT_EQ(1006697176u, Hash(str));
+
+  // Insert a null byte.
+  str = "hello  world";
+  str[5] = '\0';
+  EXPECT_EQ(2319902537u, Hash(str));
+
+  // Test that the bytes after the null contribute to the hash.
+  str = "hello  worle";
+  str[5] = '\0';
+  EXPECT_EQ(553904462u, Hash(str));
+
+  // Extremely long string.
+  // Also tests strings with high bit set, and null byte.
+  std::vector<char> long_string_buffer;
+  for (int i = 0; i < 4096; ++i)
+    long_string_buffer.push_back((i % 256) - 128);
+  str.assign(&long_string_buffer.front(), long_string_buffer.size());
+  EXPECT_EQ(2797962408u, Hash(str));
+
+  // All possible lengths (mod 4). Tests separate code paths. Also test with
+  // final byte high bit set (regression test for http://crbug.com/90659).
+  // Note that the 1 and 3 cases have a weird bug where the final byte is
+  // treated as a signed char. It was decided on the above bug discussion to
+  // enshrine that behaviour as "correct" to avoid invalidating existing hashes.
+
+  // Length mod 4 == 0.
+  str = "hello w\xab";
+  EXPECT_EQ(615571198u, Hash(str));
+  // Length mod 4 == 1.
+  str = "hello wo\xab";
+  EXPECT_EQ(623474296u, Hash(str));
+  // Length mod 4 == 2.
+  str = "hello wor\xab";
+  EXPECT_EQ(4278562408u, Hash(str));
+  // Length mod 4 == 3.
+  str = "hello worl\xab";
+  EXPECT_EQ(3224633008u, Hash(str));
+}
+
+TEST(HashTest, CString) {
+  const char* str;
+  // Empty string (should hash to 0).
+  str = "";
+  EXPECT_EQ(0u, Hash(str, strlen(str)));
+
+  // Simple test.
+  str = "hello world";
+  EXPECT_EQ(2794219650u, Hash(str, strlen(str)));
+
+  // Ensure that it stops reading after the given length, and does not expect a
+  // null byte.
+  str = "hello world; don't read this part";
+  EXPECT_EQ(2794219650u, Hash(str, strlen("hello world")));
+}
+
+}  // namespace base
diff --git a/base/i18n/OWNERS b/base/i18n/OWNERS
new file mode 100644
index 0000000..d717b8d
--- /dev/null
+++ b/base/i18n/OWNERS
@@ -0,0 +1 @@
+jshin@chromium.org
diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h
new file mode 100644
index 0000000..e8a2add
--- /dev/null
+++ b/base/i18n/base_i18n_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_BASE_I18N_EXPORT_H_
+#define BASE_I18N_BASE_I18N_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __declspec(dllexport)
+#else
+#define BASE_I18N_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_I18N_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_I18N_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_I18N_EXPORT
+#endif
+
+#endif  // BASE_I18N_BASE_I18N_EXPORT_H_
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
new file mode 100644
index 0000000..e81a36b
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/bidi_line_iterator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace i18n {
+
+BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
+}
+
+BiDiLineIterator::~BiDiLineIterator() {
+  if (bidi_) {
+    ubidi_close(bidi_);
+    bidi_ = NULL;
+  }
+}
+
+bool BiDiLineIterator::Open(const string16& text,
+                            bool right_to_left,
+                            bool url) {
+  DCHECK(!bidi_);
+  UErrorCode error = U_ZERO_ERROR;
+  bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
+  if (U_FAILURE(error))
+    return false;
+  if (right_to_left && url)
+    ubidi_setReorderingMode(bidi_, UBIDI_REORDER_RUNS_ONLY);
+  ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+                right_to_left ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
+                NULL, &error);
+  return (U_SUCCESS(error) == TRUE);
+}
+
+int BiDiLineIterator::CountRuns() {
+  DCHECK(bidi_ != NULL);
+  UErrorCode error = U_ZERO_ERROR;
+  const int runs = ubidi_countRuns(bidi_, &error);
+  return U_SUCCESS(error) ? runs : 0;
+}
+
+UBiDiDirection BiDiLineIterator::GetVisualRun(int index,
+                                              int* start,
+                                              int* length) {
+  DCHECK(bidi_ != NULL);
+  return ubidi_getVisualRun(bidi_, index, start, length);
+}
+
+void BiDiLineIterator::GetLogicalRun(int start,
+                                     int* end,
+                                     UBiDiLevel* level) {
+  DCHECK(bidi_ != NULL);
+  ubidi_getLogicalRun(bidi_, start, end, level);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
new file mode 100644
index 0000000..d5a2a07
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_BIDI_LINE_ITERATOR_H_
+#define BASE_I18N_BIDI_LINE_ITERATOR_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "third_party/icu/source/common/unicode/ubidi.h"
+
+namespace base {
+namespace i18n {
+
+// A simple wrapper class for the bidirectional iterator of ICU.
+// This class uses the bidirectional iterator of ICU to split a line of
+// bidirectional texts into visual runs in its display order.
+class BASE_I18N_EXPORT BiDiLineIterator {
+ public:
+  BiDiLineIterator();
+  ~BiDiLineIterator();
+
+  // Initializes the bidirectional iterator with the specified text.  Returns
+  // whether initialization succeeded.
+  bool Open(const string16& text, bool right_to_left, bool url);
+
+  // Returns the number of visual runs in the text, or zero on error.
+  int CountRuns();
+
+  // Gets the logical offset, length, and direction of the specified visual run.
+  UBiDiDirection GetVisualRun(int index, int* start, int* length);
+
+  // Given a start position, figure out where the run ends (and the BiDiLevel).
+  void GetLogicalRun(int start, int* end, UBiDiLevel* level);
+
+ private:
+  UBiDi* bidi_;
+
+  DISALLOW_COPY_AND_ASSIGN(BiDiLineIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BIDI_LINE_ITERATOR_H_
diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc
new file mode 100644
index 0000000..e2ed667
--- /dev/null
+++ b/base/i18n/break_iterator.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/break_iterator.h"
+
+#include "base/logging.h"
+#include "third_party/icu/source/common/unicode/ubrk.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+
+namespace base {
+namespace i18n {
+
+const size_t npos = static_cast<size_t>(-1);
+
+BreakIterator::BreakIterator(const StringPiece16& str, BreakType break_type)
+    : iter_(NULL),
+      string_(str),
+      break_type_(break_type),
+      prev_(npos),
+      pos_(0) {
+}
+
+BreakIterator::BreakIterator(const StringPiece16& str, const string16& rules)
+    : iter_(NULL),
+      string_(str),
+      rules_(rules),
+      break_type_(RULE_BASED),
+      prev_(npos),
+      pos_(0) {
+}
+
+BreakIterator::~BreakIterator() {
+  if (iter_)
+    ubrk_close(static_cast<UBreakIterator*>(iter_));
+}
+
+bool BreakIterator::Init() {
+  UErrorCode status = U_ZERO_ERROR;
+  UParseError parse_error;
+  UBreakIteratorType break_type;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+      break_type = UBRK_CHARACTER;
+      break;
+    case BREAK_WORD:
+      break_type = UBRK_WORD;
+      break;
+    case BREAK_LINE:
+    case BREAK_NEWLINE:
+    case RULE_BASED: // (Keep compiler happy, break_type not used in this case)
+      break_type = UBRK_LINE;
+      break;
+    default:
+      NOTREACHED() << "invalid break_type_";
+      return false;
+  }
+  if (break_type_ == RULE_BASED) {
+    iter_ = ubrk_openRules(rules_.c_str(),
+                           static_cast<int32_t>(rules_.length()),
+                           string_.data(),
+                           static_cast<int32_t>(string_.size()),
+                           &parse_error,
+                           &status);
+    if (U_FAILURE(status)) {
+      NOTREACHED() << "ubrk_openRules failed to parse rule string at line "
+          << parse_error.line << ", offset " << parse_error.offset;
+    }
+  } else {
+    iter_ = ubrk_open(break_type,
+                      NULL,
+                      string_.data(),
+                      static_cast<int32_t>(string_.size()),
+                      &status);
+    if (U_FAILURE(status)) {
+      NOTREACHED() << "ubrk_open failed for type " << break_type
+          << " with error " << status;
+    }
+  }
+
+  if (U_FAILURE(status)) {
+    return false;
+  }
+
+  // Move the iterator to the beginning of the string.
+  ubrk_first(static_cast<UBreakIterator*>(iter_));
+  return true;
+}
+
+bool BreakIterator::Advance() {
+  int32_t pos;
+  int32_t status;
+  prev_ = pos_;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+    case BREAK_WORD:
+    case BREAK_LINE:
+    case RULE_BASED:
+      pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+      if (pos == UBRK_DONE) {
+        pos_ = npos;
+        return false;
+      }
+      pos_ = static_cast<size_t>(pos);
+      return true;
+    case BREAK_NEWLINE:
+      do {
+        pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+        if (pos == UBRK_DONE)
+          break;
+        pos_ = static_cast<size_t>(pos);
+        status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+      } while (status >= UBRK_LINE_SOFT && status < UBRK_LINE_SOFT_LIMIT);
+      if (pos == UBRK_DONE && prev_ == pos_) {
+        pos_ = npos;
+        return false;
+      }
+      return true;
+    default:
+      NOTREACHED() << "invalid break_type_";
+      return false;
+  }
+}
+
+bool BreakIterator::SetText(const base::char16* text, const size_t length) {
+  UErrorCode status = U_ZERO_ERROR;
+  ubrk_setText(static_cast<UBreakIterator*>(iter_),
+               text, length, &status);
+  pos_ = 0;  // implicit when ubrk_setText is done
+  prev_ = npos;
+  if (U_FAILURE(status)) {
+    NOTREACHED() << "ubrk_setText failed";
+    return false;
+  }
+  string_ = StringPiece16(text, length);
+  return true;
+}
+
+bool BreakIterator::IsWord() const {
+  int32_t status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+  if (break_type_ != BREAK_WORD && break_type_ != RULE_BASED)
+    return false;
+  return status != UBRK_WORD_NONE;
+}
+
+bool BreakIterator::IsEndOfWord(size_t position) const {
+  if (break_type_ != BREAK_WORD && break_type_ != RULE_BASED)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  UBool boundary = ubrk_isBoundary(iter, static_cast<int32_t>(position));
+  int32_t status = ubrk_getRuleStatus(iter);
+  return (!!boundary && status != UBRK_WORD_NONE);
+}
+
+bool BreakIterator::IsStartOfWord(size_t position) const {
+  if (break_type_ != BREAK_WORD && break_type_ != RULE_BASED)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  UBool boundary = ubrk_isBoundary(iter, static_cast<int32_t>(position));
+  ubrk_next(iter);
+  int32_t next_status = ubrk_getRuleStatus(iter);
+  return (!!boundary && next_status != UBRK_WORD_NONE);
+}
+
+bool BreakIterator::IsGraphemeBoundary(size_t position) const {
+  if (break_type_ != BREAK_CHARACTER)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  return !!ubrk_isBoundary(iter, static_cast<int32_t>(position));
+}
+
+string16 BreakIterator::GetString() const {
+  return GetStringPiece().as_string();
+}
+
+StringPiece16 BreakIterator::GetStringPiece() const {
+  DCHECK(prev_ != npos && pos_ != npos);
+  return string_.substr(prev_, pos_ - prev_);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h
new file mode 100644
index 0000000..19fdbe0
--- /dev/null
+++ b/base/i18n/break_iterator.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_BREAK_ITERATOR_H_
+#define BASE_I18N_BREAK_ITERATOR_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+// The BreakIterator class iterates through the words, word breaks, and
+// line breaks in a UTF-16 string.
+//
+// It provides several modes, BREAK_WORD, BREAK_LINE, and BREAK_NEWLINE,
+// which modify how characters are aggregated into the returned string.
+//
+// Under BREAK_WORD mode, once a word is encountered any non-word
+// characters are not included in the returned string (e.g. in the
+// UTF-16 equivalent of the string " foo bar! ", the word breaks are at
+// the periods in ". .foo. .bar.!. .").
+// Note that Chinese/Japanese/Thai do not use spaces between words so that
+// boundaries can fall in the middle of a continuous run of non-space /
+// non-punctuation characters.
+//
+// Under BREAK_LINE mode, once a line breaking opportunity is encountered,
+// any non-word  characters are included in the returned string, breaking
+// only when a space-equivalent character or a line breaking opportunity
+// is encountered (e.g. in the UTF16-equivalent of the string " foo bar! ",
+// the breaks are at the periods in ". .foo .bar! .").
+//
+// Note that lines can be broken at any character/syllable/grapheme cluster
+// boundary in Chinese/Japanese/Korean and at word boundaries in Thai
+// (Thai does not use spaces between words). Therefore, this is NOT the same
+// as breaking only at space-equivalent characters where its former
+// name (BREAK_SPACE) implied.
+//
+// Under BREAK_NEWLINE mode, all characters are included in the returned
+// string, breaking only when a newline-equivalent character is encountered
+// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line
+// breaks are at the periods in ".foo\n.bar\n.\n.").
+//
+// To extract the words from a string, move a BREAK_WORD BreakIterator
+// through the string and test whether IsWord() is true. E.g.,
+//   BreakIterator iter(str, BreakIterator::BREAK_WORD);
+//   if (!iter.Init())
+//     return false;
+//   while (iter.Advance()) {
+//     if (iter.IsWord()) {
+//       // Region [iter.prev(), iter.pos()) contains a word.
+//       VLOG(1) << "word: " << iter.GetString();
+//     }
+//   }
+
+namespace base {
+namespace i18n {
+
+class BASE_I18N_EXPORT BreakIterator {
+ public:
+  enum BreakType {
+    BREAK_WORD,
+    BREAK_LINE,
+    // TODO(jshin): Remove this after reviewing call sites.
+    // If call sites really need break only on space-like characters
+    // implement it separately.
+    BREAK_SPACE = BREAK_LINE,
+    BREAK_NEWLINE,
+    BREAK_CHARACTER,
+    // But don't remove this one!
+    RULE_BASED,
+  };
+
+  // Requires |str| to live as long as the BreakIterator does.
+  BreakIterator(const StringPiece16& str, BreakType break_type);
+  // Make a rule-based iterator. BreakType == RULE_BASED is implied.
+  // TODO(andrewhayden): This signature could easily be misinterpreted as
+  // "(const string16& str, const string16& locale)". We should do something
+  // better.
+  BreakIterator(const StringPiece16& str, const string16& rules);
+  ~BreakIterator();
+
+  // Init() must be called before any of the iterators are valid.
+  // Returns false if ICU failed to initialize.
+  bool Init();
+
+  // Advance to the next break.  Returns false if we've run past the end of
+  // the string.  (Note that the very last "break" is after the final
+  // character in the string, and when we advance to that position it's the
+  // last time Advance() returns true.)
+  bool Advance();
+
+  // Updates the text used by the iterator, resetting the iterator as if
+  // if Init() had been called again. Any old state is lost. Returns true
+  // unless there is an error setting the text.
+  bool SetText(const base::char16* text, const size_t length);
+
+  // Under BREAK_WORD mode, returns true if the break we just hit is the
+  // end of a word. (Otherwise, the break iterator just skipped over e.g.
+  // whitespace or punctuation.)  Under BREAK_LINE and BREAK_NEWLINE modes,
+  // this distinction doesn't apply and it always returns false.
+  bool IsWord() const;
+
+  // Under BREAK_WORD mode, returns true if |position| is at the end of word or
+  // at the start of word. It always returns false under BREAK_LINE and
+  // BREAK_NEWLINE modes.
+  bool IsEndOfWord(size_t position) const;
+  bool IsStartOfWord(size_t position) const;
+
+  // Under BREAK_CHARACTER mode, returns whether |position| is a Unicode
+  // grapheme boundary.
+  bool IsGraphemeBoundary(size_t position) const;
+
+  // Returns the string between prev() and pos().
+  // Advance() must have been called successfully at least once for pos() to
+  // have advanced to somewhere useful.
+  string16 GetString() const;
+
+  StringPiece16 GetStringPiece() const;
+
+  // Returns the value of pos() returned before Advance() was last called.
+  size_t prev() const { return prev_; }
+
+  // Returns the current break position within the string,
+  // or BreakIterator::npos when done.
+  size_t pos() const { return pos_; }
+
+ private:
+  // ICU iterator, avoiding ICU ubrk.h dependence.
+  // This is actually an ICU UBreakiterator* type, which turns out to be
+  // a typedef for a void* in the ICU headers. Using void* directly prevents
+  // callers from needing access to the ICU public headers directory.
+  void* iter_;
+
+  // The string we're iterating over. Can be changed with SetText(...)
+  StringPiece16 string_;
+
+  // Rules for our iterator. Mutually exclusive with break_type_.
+  const string16 rules_;
+
+  // The breaking style (word/space/newline). Mutually exclusive with rules_
+  BreakType break_type_;
+
+  // Previous and current iterator positions.
+  size_t prev_, pos_;
+
+  DISALLOW_COPY_AND_ASSIGN(BreakIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BREAK_ITERATOR_H_
diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc
new file mode 100644
index 0000000..220a996
--- /dev/null
+++ b/base/i18n/break_iterator_unittest.cc
@@ -0,0 +1,373 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/break_iterator.h"
+
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace i18n {
+
+TEST(BreakIteratorTest, BreakWordEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWord) {
+  string16 space(UTF8ToUTF16(" "));
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide16) {
+  // Two greek words separated by space.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 word1(str.substr(0, 10));
+  const string16 word2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(word1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(word2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char very_wide_char[] = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char)));
+  const string16 very_wide_word(str.substr(0, 2));
+
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(very_wide_word, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpace) {
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceSP) {
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom "));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpacekWide16) {
+  // Two Greek words.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 word1(str.substr(0, 11));
+  const string16 word2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(word1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(word2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char very_wide_char[] = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char)));
+  const string16 very_wide_word(str.substr(0, 3));
+
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(very_wide_word, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLine) {
+  string16 nl(UTF8ToUTF16("\n"));
+  string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineNL) {
+  string16 nl(UTF8ToUTF16("\n"));
+  string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n"));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide16) {
+  // Two Greek words separated by newline.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 line1(str.substr(0, 11));
+  const string16 line2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(line1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(line2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char very_wide_char[] = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s\na", very_wide_char)));
+  const string16 very_wide_line(str.substr(0, 3));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(very_wide_line, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakCharacter) {
+  static const wchar_t* kCharacters[] = {
+    // An English word consisting of four ASCII characters.
+    L"w", L"o", L"r", L"d", L" ",
+    // A Hindi word (which means "Hindi") consisting of three Devanagari
+    // characters.
+    L"\x0939\x093F", L"\x0928\x094D", L"\x0926\x0940", L" ",
+    // A Thai word (which means "feel") consisting of three Thai characters.
+    L"\x0E23\x0E39\x0E49", L"\x0E2A\x0E36", L"\x0E01", L" ",
+  };
+  std::vector<string16> characters;
+  string16 text;
+  for (size_t i = 0; i < arraysize(kCharacters); ++i) {
+    characters.push_back(WideToUTF16(kCharacters[i]));
+    text.append(characters.back());
+  }
+  BreakIterator iter(text, BreakIterator::BREAK_CHARACTER);
+  ASSERT_TRUE(iter.Init());
+  for (size_t i = 0; i < arraysize(kCharacters); ++i) {
+    EXPECT_TRUE(iter.Advance());
+    EXPECT_EQ(characters[i], iter.GetString());
+  }
+}
+
+// Test for https://code.google.com/p/chromium/issues/detail?id=411213
+// We should be able to get valid substrings with GetString() function
+// after setting new content by calling SetText().
+TEST(BreakIteratorTest, GetStringAfterSetText) {
+  const string16 initial_string(ASCIIToUTF16("str"));
+  BreakIterator iter(initial_string, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+
+  const string16 long_string(ASCIIToUTF16("another,string"));
+  EXPECT_TRUE(iter.SetText(long_string.c_str(), long_string.size()));
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.Advance());  // Advance to ',' in |long_string|
+
+  // Check that the current position is out of bounds of the |initial_string|.
+  EXPECT_LT(initial_string.size(), iter.pos());
+
+  // Check that we can get a valid substring of |long_string|.
+  EXPECT_EQ(ASCIIToUTF16(","), iter.GetString());
+}
+
+TEST(BreakIteratorTest, GetStringPiece) {
+  const string16 initial_string(ASCIIToUTF16("some string"));
+  BreakIterator iter(initial_string, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(iter.GetString(), iter.GetStringPiece().as_string());
+  EXPECT_EQ(StringPiece16(ASCIIToUTF16("some")), iter.GetStringPiece());
+
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(iter.GetString(), iter.GetStringPiece().as_string());
+  EXPECT_EQ(StringPiece16(ASCIIToUTF16("string")), iter.GetStringPiece());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/build_utf8_validator_tables.cc b/base/i18n/build_utf8_validator_tables.cc
new file mode 100644
index 0000000..ae5b1a7
--- /dev/null
+++ b/base/i18n/build_utf8_validator_tables.cc
@@ -0,0 +1,466 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Create a state machine for validating UTF-8. The algorithm in brief:
+// 1. Convert the complete unicode range of code points, except for the
+//    surrogate code points, to an ordered array of sequences of bytes in
+//    UTF-8.
+// 2. Convert individual bytes to ranges, starting from the right of each byte
+//    sequence. For each range, ensure the bytes on the left and the ranges
+//    on the right are the identical.
+// 3. Convert the resulting list of ranges into a state machine, collapsing
+//    identical states.
+// 4. Convert the state machine to an array of bytes.
+// 5. Output as a C++ file.
+//
+// To use:
+//  $ ninja -C out/Release build_utf8_validator_tables
+//  $ out/Release/build_utf8_validator_tables
+//                                   --output=base/i18n/utf8_validator_tables.cc
+//  $ git add base/i18n/utf8_validator_tables.cc
+//
+// Because the table is not expected to ever change, it is checked into the
+// repository rather than being regenerated at build time.
+//
+// This code uses type uint8 throughout to represent bytes, to avoid
+// signed/unsigned char confusion.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "third_party/icu/source/common/unicode/utf8.h"
+
+namespace {
+
+const char kHelpText[] =
+    "Usage: build_utf8_validator_tables [ --help ] [ --output=<file> ]\n";
+
+const char kProlog[] =
+    "// Copyright 2013 The Chromium Authors. All rights reserved.\n"
+    "// Use of this source code is governed by a BSD-style license that can "
+    "be\n"
+    "// found in the LICENSE file.\n"
+    "\n"
+    "// This file is auto-generated by build_utf8_validator_tables.\n"
+    "// DO NOT EDIT.\n"
+    "\n"
+    "#include \"base/i18n/utf8_validator_tables.h\"\n"
+    "\n"
+    "namespace base {\n"
+    "namespace internal {\n"
+    "\n"
+    "const uint8 kUtf8ValidatorTables[] = {\n";
+
+const char kEpilog[] =
+    "};\n"
+    "\n"
+    "const size_t kUtf8ValidatorTablesSize = arraysize(kUtf8ValidatorTables);\n"
+    "\n"
+    "}  // namespace internal\n"
+    "}  // namespace base\n";
+
+// Ranges are inclusive at both ends--they represent [from, to]
+class Range {
+ public:
+  // Ranges always start with just one byte.
+  explicit Range(uint8 value) : from_(value), to_(value) {}
+
+  // Range objects are copyable and assignable to be used in STL
+  // containers. Since they only contain non-pointer POD types, the default copy
+  // constructor, assignment operator and destructor will work.
+
+  // Add a byte to the range. We intentionally only support adding a byte at the
+  // end, since that is the only operation the code needs.
+  void AddByte(uint8 to) {
+    CHECK(to == to_ + 1);
+    to_ = to;
+  }
+
+  uint8 from() const { return from_; }
+  uint8 to() const { return to_; }
+
+  bool operator<(const Range& rhs) const {
+    return (from() < rhs.from() || (from() == rhs.from() && to() < rhs.to()));
+  }
+
+  bool operator==(const Range& rhs) const {
+    return from() == rhs.from() && to() == rhs.to();
+  }
+
+ private:
+  uint8 from_;
+  uint8 to_;
+};
+
+// A vector of Ranges is like a simple regular expression--it corresponds to
+// a set of strings of the same length that have bytes in each position in
+// the appropriate range.
+typedef std::vector<Range> StringSet;
+
+// A UTF-8 "character" is represented by a sequence of bytes.
+typedef std::vector<uint8> Character;
+
+// In the second stage of the algorithm, we want to convert a large list of
+// Characters into a small list of StringSets.
+struct Pair {
+  Character character;
+  StringSet set;
+};
+
+typedef std::vector<Pair> PairVector;
+
+// A class to print a table of numbers in the same style as clang-format.
+class TablePrinter {
+ public:
+  explicit TablePrinter(FILE* stream)
+      : stream_(stream), values_on_this_line_(0), current_offset_(0) {}
+
+  void PrintValue(uint8 value) {
+    if (values_on_this_line_ == 0) {
+      fputs("   ", stream_);
+    } else if (values_on_this_line_ == kMaxValuesPerLine) {
+      fprintf(stream_, "  // 0x%02x\n   ", current_offset_);
+      values_on_this_line_ = 0;
+    }
+    fprintf(stream_, " 0x%02x,", static_cast<int>(value));
+    ++values_on_this_line_;
+    ++current_offset_;
+  }
+
+  void NewLine() {
+    while (values_on_this_line_ < kMaxValuesPerLine) {
+      fputs("      ", stream_);
+      ++values_on_this_line_;
+    }
+    fprintf(stream_, "  // 0x%02x\n", current_offset_);
+    values_on_this_line_ = 0;
+  }
+
+ private:
+  // stdio stream. Not owned.
+  FILE* stream_;
+
+  // Number of values so far printed on this line.
+  int values_on_this_line_;
+
+  // Total values printed so far.
+  int current_offset_;
+
+  static const int kMaxValuesPerLine = 8;
+
+  DISALLOW_COPY_AND_ASSIGN(TablePrinter);
+};
+
+// Start by filling a PairVector with characters. The resulting vector goes from
+// "\x00" to "\xf4\x8f\xbf\xbf".
+PairVector InitializeCharacters() {
+  PairVector vector;
+  for (int i = 0; i <= 0x10FFFF; ++i) {
+    if (i >= 0xD800 && i < 0xE000) {
+      // Surrogate codepoints are not permitted. Non-character code points are
+      // explicitly permitted.
+      continue;
+    }
+    uint8 bytes[4];
+    unsigned int offset = 0;
+    UBool is_error = false;
+    U8_APPEND(bytes, offset, arraysize(bytes), i, is_error);
+    DCHECK(!is_error);
+    DCHECK_GT(offset, 0u);
+    DCHECK_LE(offset, arraysize(bytes));
+    Pair pair = {Character(bytes, bytes + offset), StringSet()};
+    vector.push_back(pair);
+  }
+  return vector;
+}
+
+// Construct a new Pair from |character| and the concatenation of |new_range|
+// and |existing_set|, and append it to |pairs|.
+void ConstructPairAndAppend(const Character& character,
+                            const Range& new_range,
+                            const StringSet& existing_set,
+                            PairVector* pairs) {
+  Pair new_pair = {character, StringSet(1, new_range)};
+  new_pair.set.insert(
+      new_pair.set.end(), existing_set.begin(), existing_set.end());
+  pairs->push_back(new_pair);
+}
+
+// Each pass over the PairVector strips one byte off the right-hand-side of the
+// characters and adds a range to the set on the right. For example, the first
+// pass converts the range from "\xe0\xa0\x80" to "\xe0\xa0\xbf" to ("\xe0\xa0",
+// [\x80-\xbf]), then the second pass converts the range from ("\xe0\xa0",
+// [\x80-\xbf]) to ("\xe0\xbf", [\x80-\xbf]) to ("\xe0",
+// [\xa0-\xbf][\x80-\xbf]).
+void MoveRightMostCharToSet(PairVector* pairs) {
+  PairVector new_pairs;
+  PairVector::const_iterator it = pairs->begin();
+  while (it != pairs->end() && it->character.empty()) {
+    new_pairs.push_back(*it);
+    ++it;
+  }
+  CHECK(it != pairs->end());
+  Character unconverted_bytes(it->character.begin(), it->character.end() - 1);
+  Range new_range(it->character.back());
+  StringSet converted = it->set;
+  ++it;
+  while (it != pairs->end()) {
+    const Pair& current_pair = *it++;
+    if (current_pair.character.size() == unconverted_bytes.size() + 1 &&
+        std::equal(unconverted_bytes.begin(),
+                   unconverted_bytes.end(),
+                   current_pair.character.begin()) &&
+        converted == current_pair.set) {
+      // The particular set of UTF-8 codepoints we are validating guarantees
+      // that each byte range will be contiguous. This would not necessarily be
+      // true for an arbitrary set of UTF-8 codepoints.
+      DCHECK_EQ(new_range.to() + 1, current_pair.character.back());
+      new_range.AddByte(current_pair.character.back());
+      continue;
+    }
+    ConstructPairAndAppend(unconverted_bytes, new_range, converted, &new_pairs);
+    unconverted_bytes = Character(current_pair.character.begin(),
+                                  current_pair.character.end() - 1);
+    new_range = Range(current_pair.character.back());
+    converted = current_pair.set;
+  }
+  ConstructPairAndAppend(unconverted_bytes, new_range, converted, &new_pairs);
+  new_pairs.swap(*pairs);
+}
+
+void MoveAllCharsToSets(PairVector* pairs) {
+  // Since each pass of the function moves one character, and UTF-8 sequences
+  // are at most 4 characters long, this simply runs the algorithm four times.
+  for (int i = 0; i < 4; ++i) {
+    MoveRightMostCharToSet(pairs);
+  }
+#if DCHECK_IS_ON()
+  for (PairVector::const_iterator it = pairs->begin(); it != pairs->end();
+       ++it) {
+    DCHECK(it->character.empty());
+  }
+#endif
+}
+
+// Logs the generated string sets in regular-expression style, ie. [\x00-\x7f],
+// [\xc2-\xdf][\x80-\xbf], etc. This can be a useful sanity-check that the
+// algorithm is working. Use the command-line option
+// --vmodule=build_utf8_validator_tables=1 to see this output.
+void LogStringSets(const PairVector& pairs) {
+  for (PairVector::const_iterator pair_it = pairs.begin();
+       pair_it != pairs.end();
+       ++pair_it) {
+    std::string set_as_string;
+    for (StringSet::const_iterator set_it = pair_it->set.begin();
+         set_it != pair_it->set.end();
+         ++set_it) {
+      set_as_string += base::StringPrintf("[\\x%02x-\\x%02x]",
+                                          static_cast<int>(set_it->from()),
+                                          static_cast<int>(set_it->to()));
+    }
+    VLOG(1) << set_as_string;
+  }
+}
+
+// A single state in the state machine is represented by a sorted vector of
+// start bytes and target states. All input bytes in the range between the start
+// byte and the next entry in the vector (or 0xFF) result in a transition to the
+// target state.
+struct StateRange {
+  uint8 from;
+  uint8 target_state;
+};
+
+typedef std::vector<StateRange> State;
+
+// Generates a state where all bytes go to state 1 (invalid). This is also used
+// as an initialiser for other states (since bytes from outside the desired
+// range are invalid).
+State GenerateInvalidState() {
+  const StateRange range = {0, 1};
+  return State(1, range);
+}
+
+// A map from a state (ie. a set of strings which will match from this state) to
+// a number (which is an index into the array of states).
+typedef std::map<StringSet, uint8> StateMap;
+
+// Create a new state corresponding to |set|, add it |states| and |state_map|
+// and return the index it was given in |states|.
+uint8 MakeState(const StringSet& set,
+                std::vector<State>* states,
+                StateMap* state_map) {
+  DCHECK(!set.empty());
+  const Range& range = set.front();
+  const StringSet rest(set.begin() + 1, set.end());
+  const StateMap::const_iterator where = state_map->find(rest);
+  const uint8 target_state = where == state_map->end()
+                                 ? MakeState(rest, states, state_map)
+                                 : where->second;
+  DCHECK_LT(0, range.from());
+  DCHECK_LT(range.to(), 0xFF);
+  const StateRange new_state_initializer[] = {
+      {0, 1}, {range.from(), target_state},
+      {static_cast<uint8>(range.to() + 1), 1}};
+  states->push_back(
+      State(new_state_initializer,
+            new_state_initializer + arraysize(new_state_initializer)));
+  const uint8 new_state_number =
+      base::checked_cast<uint8>(states->size() - 1);
+  CHECK(state_map->insert(std::make_pair(set, new_state_number)).second);
+  return new_state_number;
+}
+
+std::vector<State> GenerateStates(const PairVector& pairs) {
+  // States 0 and 1 are the initial/valid state and invalid state, respectively.
+  std::vector<State> states(2, GenerateInvalidState());
+  StateMap state_map;
+  state_map.insert(std::make_pair(StringSet(), 0));
+  for (PairVector::const_iterator it = pairs.begin(); it != pairs.end(); ++it) {
+    DCHECK(it->character.empty());
+    DCHECK(!it->set.empty());
+    const Range& range = it->set.front();
+    const StringSet rest(it->set.begin() + 1, it->set.end());
+    const StateMap::const_iterator where = state_map.find(rest);
+    const uint8 target_state = where == state_map.end()
+                                   ? MakeState(rest, &states, &state_map)
+                                   : where->second;
+    if (states[0].back().from == range.from()) {
+      DCHECK_EQ(1, states[0].back().target_state);
+      states[0].back().target_state = target_state;
+      DCHECK_LT(range.to(), 0xFF);
+      const StateRange new_range = {static_cast<uint8>(range.to() + 1), 1};
+      states[0].push_back(new_range);
+    } else {
+      DCHECK_LT(range.to(), 0xFF);
+      const StateRange new_range_initializer[] = {{range.from(), target_state},
+           {static_cast<uint8>(range.to() + 1), 1}};
+      states[0]
+          .insert(states[0].end(),
+                  new_range_initializer,
+                  new_range_initializer + arraysize(new_range_initializer));
+    }
+  }
+  return states;
+}
+
+// Output the generated states as a C++ table. Two tricks are used to compact
+// the table: each state in the table starts with a shift value which indicates
+// how many bits we can discard from the right-hand-side of the byte before
+// doing the table lookup. Secondly, only the state-transitions for bytes
+// with the top-bit set are included in the table; bytes without the top-bit set
+// are just ASCII and are handled directly by the code.
+void PrintStates(const std::vector<State>& states, FILE* stream) {
+  // First calculate the start-offset of each state. This allows the state
+  // machine to jump directly to the correct offset, avoiding an extra
+  // indirection. State 0 starts at offset 0.
+  std::vector<uint8> state_offset(1, 0);
+  std::vector<uint8> shifts;
+  uint8 pos = 0;
+
+  for (std::vector<State>::const_iterator state_it = states.begin();
+       state_it != states.end();
+       ++state_it) {
+    // We want to set |shift| to the (0-based) index of the least-significant
+    // set bit in any of the ranges for this state, since this tells us how many
+    // bits we can discard and still determine what range a byte lies in. Sadly
+    // it appears that ffs() is not portable, so we do it clumsily.
+    uint8 shift = 7;
+    for (State::const_iterator range_it = state_it->begin();
+         range_it != state_it->end();
+         ++range_it) {
+      while (shift > 0 && range_it->from % (1 << shift) != 0) {
+        --shift;
+      }
+    }
+    shifts.push_back(shift);
+    pos += 1 + (1 << (7 - shift));
+    state_offset.push_back(pos);
+  }
+
+  DCHECK_EQ(129, state_offset[1]);
+
+  fputs(kProlog, stream);
+  TablePrinter table_printer(stream);
+
+  for (uint8 state_index = 0; state_index < states.size(); ++state_index) {
+    const uint8 shift = shifts[state_index];
+    uint8 next_range = 0;
+    uint8 target_state = 1;
+    fprintf(stream,
+            "    // State %d, offset 0x%02x\n",
+            static_cast<int>(state_index),
+            static_cast<int>(state_offset[state_index]));
+    table_printer.PrintValue(shift);
+    for (int i = 0; i < 0x100; i += (1 << shift)) {
+      if (next_range < states[state_index].size() &&
+          states[state_index][next_range].from == i) {
+        target_state = states[state_index][next_range].target_state;
+        ++next_range;
+      }
+      if (i >= 0x80) {
+        table_printer.PrintValue(state_offset[target_state]);
+      }
+    }
+    table_printer.NewLine();
+  }
+
+  fputs(kEpilog, stream);
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  base::CommandLine::Init(argc, argv);
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch("help")) {
+    fwrite(kHelpText, 1, arraysize(kHelpText), stdout);
+    exit(EXIT_SUCCESS);
+  }
+  base::FilePath filename =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath("output");
+
+  FILE* output = stdout;
+  if (!filename.empty()) {
+    output = base::OpenFile(filename, "wb");
+    if (!output)
+      PLOG(FATAL) << "Couldn't open '" << filename.AsUTF8Unsafe()
+                  << "' for writing";
+  }
+
+  // Step 1: Enumerate the characters
+  PairVector pairs = InitializeCharacters();
+  // Step 2: Convert to sets.
+  MoveAllCharsToSets(&pairs);
+  if (VLOG_IS_ON(1)) {
+    LogStringSets(pairs);
+  }
+  // Step 3: Generate states.
+  std::vector<State> states = GenerateStates(pairs);
+  // Step 4/5: Print output
+  PrintStates(states, output);
+
+  if (!filename.empty()) {
+    if (!base::CloseFile(output))
+      PLOG(FATAL) << "Couldn't finish writing '" << filename.AsUTF8Unsafe()
+                  << "'";
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc
new file mode 100644
index 0000000..5debc2e
--- /dev/null
+++ b/base/i18n/case_conversion.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/case_conversion.h"
+
+#include "base/strings/string16.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+
+namespace base {
+namespace i18n {
+
+string16 ToLower(const StringPiece16& string) {
+  icu::UnicodeString unicode_string(string.data(), string.size());
+  unicode_string.toLower();
+  return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+string16 ToUpper(const StringPiece16& string) {
+  icu::UnicodeString unicode_string(string.data(), string.size());
+  unicode_string.toUpper();
+  return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h
new file mode 100644
index 0000000..5d538cc
--- /dev/null
+++ b/base/i18n/case_conversion.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_CASE_CONVERSION_H_
+#define BASE_I18N_CASE_CONVERSION_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+namespace i18n {
+
+// Returns the lower case equivalent of string. Uses ICU's default locale.
+BASE_I18N_EXPORT string16 ToLower(const StringPiece16& string);
+
+// Returns the upper case equivalent of string. Uses ICU's default locale.
+BASE_I18N_EXPORT string16 ToUpper(const StringPiece16& string);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_CASE_CONVERSION_H_
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc
new file mode 100644
index 0000000..38e2c68
--- /dev/null
+++ b/base/i18n/case_conversion_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/case_conversion.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+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
+}  // namespace base
diff --git a/base/i18n/char_iterator.cc b/base/i18n/char_iterator.cc
new file mode 100644
index 0000000..25efc51
--- /dev/null
+++ b/base/i18n/char_iterator.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/char_iterator.h"
+
+#include "third_party/icu/source/common/unicode/utf8.h"
+#include "third_party/icu/source/common/unicode/utf16.h"
+
+namespace base {
+namespace i18n {
+
+UTF8CharIterator::UTF8CharIterator(const std::string* str)
+    : str_(reinterpret_cast<const uint8_t*>(str->data())),
+      len_(str->size()),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    U8_NEXT(str_, next_pos_, len_, char_);
+}
+
+UTF8CharIterator::~UTF8CharIterator() {
+}
+
+bool UTF8CharIterator::Advance() {
+  if (array_pos_ >= len_)
+    return false;
+
+  array_pos_ = next_pos_;
+  char_pos_++;
+  if (next_pos_ < len_)
+    U8_NEXT(str_, next_pos_, len_, char_);
+
+  return true;
+}
+
+UTF16CharIterator::UTF16CharIterator(const string16* str)
+    : str_(reinterpret_cast<const char16*>(str->data())),
+      len_(str->size()),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    ReadChar();
+}
+
+UTF16CharIterator::UTF16CharIterator(const char16* str, size_t str_len)
+    : str_(str),
+      len_(str_len),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    ReadChar();
+}
+
+UTF16CharIterator::~UTF16CharIterator() {
+}
+
+bool UTF16CharIterator::Advance() {
+  if (array_pos_ >= len_)
+    return false;
+
+  array_pos_ = next_pos_;
+  char_pos_++;
+  if (next_pos_ < len_)
+    ReadChar();
+
+  return true;
+}
+
+void UTF16CharIterator::ReadChar() {
+  // This is actually a huge macro, so is worth having in a separate function.
+  U16_NEXT(str_, next_pos_, len_, char_);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/char_iterator.h b/base/i18n/char_iterator.h
new file mode 100644
index 0000000..8174ef4
--- /dev/null
+++ b/base/i18n/char_iterator.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_CHAR_ITERATOR_H_
+#define BASE_I18N_CHAR_ITERATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+// The CharIterator classes iterate through the characters in UTF8 and
+// UTF16 strings.  Example usage:
+//
+//   UTF8CharIterator iter(&str);
+//   while (!iter.end()) {
+//     VLOG(1) << iter.get();
+//     iter.Advance();
+//   }
+
+#if defined(OS_WIN)
+typedef unsigned char uint8_t;
+#endif
+
+namespace base {
+namespace i18n {
+
+class BASE_I18N_EXPORT UTF8CharIterator {
+ public:
+  // Requires |str| to live as long as the UTF8CharIterator does.
+  explicit UTF8CharIterator(const std::string* str);
+  ~UTF8CharIterator();
+
+  // Return the starting array index of the current character within the
+  // string.
+  int32 array_pos() const { return array_pos_; }
+
+  // Return the logical index of the current character, independent of the
+  // number of bytes each character takes.
+  int32 char_pos() const { return char_pos_; }
+
+  // Return the current char.
+  int32 get() const { return char_; }
+
+  // Returns true if we're at the end of the string.
+  bool end() const { return array_pos_ == len_; }
+
+  // Advance to the next actual character.  Returns false if we're at the
+  // end of the string.
+  bool Advance();
+
+ private:
+  // The string we're iterating over.
+  const uint8_t* str_;
+
+  // The length of the encoded string.
+  int32 len_;
+
+  // Array index.
+  int32 array_pos_;
+
+  // The next array index.
+  int32 next_pos_;
+
+  // Character index.
+  int32 char_pos_;
+
+  // The current character.
+  int32 char_;
+
+  DISALLOW_COPY_AND_ASSIGN(UTF8CharIterator);
+};
+
+class BASE_I18N_EXPORT UTF16CharIterator {
+ public:
+  // Requires |str| to live as long as the UTF16CharIterator does.
+  explicit UTF16CharIterator(const string16* str);
+  UTF16CharIterator(const char16* str, size_t str_len);
+  ~UTF16CharIterator();
+
+  // Return the starting array index of the current character within the
+  // string.
+  int32 array_pos() const { return array_pos_; }
+
+  // Return the logical index of the current character, independent of the
+  // number of codewords each character takes.
+  int32 char_pos() const { return char_pos_; }
+
+  // Return the current char.
+  int32 get() const { return char_; }
+
+  // Returns true if we're at the end of the string.
+  bool end() const { return array_pos_ == len_; }
+
+  // Advance to the next actual character.  Returns false if we're at the
+  // end of the string.
+  bool Advance();
+
+ private:
+  // Fills in the current character we found and advances to the next
+  // character, updating all flags as necessary.
+  void ReadChar();
+
+  // The string we're iterating over.
+  const char16* str_;
+
+  // The length of the encoded string.
+  int32 len_;
+
+  // Array index.
+  int32 array_pos_;
+
+  // The next array index.
+  int32 next_pos_;
+
+  // Character index.
+  int32 char_pos_;
+
+  // The current character.
+  int32 char_;
+
+  DISALLOW_COPY_AND_ASSIGN(UTF16CharIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_CHAR_ITERATOR_H_
diff --git a/base/i18n/char_iterator_unittest.cc b/base/i18n/char_iterator_unittest.cc
new file mode 100644
index 0000000..0cf8e6c
--- /dev/null
+++ b/base/i18n/char_iterator_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/char_iterator.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace i18n {
+
+TEST(CharIteratorsTest, TestUTF8) {
+  std::string empty;
+  UTF8CharIterator empty_iter(&empty);
+  ASSERT_TRUE(empty_iter.end());
+  ASSERT_EQ(0, empty_iter.array_pos());
+  ASSERT_EQ(0, empty_iter.char_pos());
+  ASSERT_FALSE(empty_iter.Advance());
+
+  std::string str("s\303\273r");  // [u with circumflex]
+  UTF8CharIterator iter(&str);
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(0, iter.array_pos());
+  ASSERT_EQ(0, iter.char_pos());
+  ASSERT_EQ('s', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(1, iter.array_pos());
+  ASSERT_EQ(1, iter.char_pos());
+  ASSERT_EQ(251, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(3, iter.array_pos());
+  ASSERT_EQ(2, iter.char_pos());
+  ASSERT_EQ('r', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_TRUE(iter.end());
+  ASSERT_EQ(4, iter.array_pos());
+  ASSERT_EQ(3, iter.char_pos());
+
+  // Don't care what it returns, but this shouldn't crash
+  iter.get();
+
+  ASSERT_FALSE(iter.Advance());
+}
+
+TEST(CharIteratorsTest, TestUTF16) {
+  string16 empty = UTF8ToUTF16("");
+  UTF16CharIterator empty_iter(&empty);
+  ASSERT_TRUE(empty_iter.end());
+  ASSERT_EQ(0, empty_iter.array_pos());
+  ASSERT_EQ(0, empty_iter.char_pos());
+  ASSERT_FALSE(empty_iter.Advance());
+
+  // This test string contains 4 characters:
+  //   x
+  //   u with circumflex - 2 bytes in UTF8, 1 codeword in UTF16
+  //   math double-struck A - 4 bytes in UTF8, 2 codewords in UTF16
+  //   z
+  string16 str = UTF8ToUTF16("x\303\273\360\235\224\270z");
+  UTF16CharIterator iter(&str);
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(0, iter.array_pos());
+  ASSERT_EQ(0, iter.char_pos());
+  ASSERT_EQ('x', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(1, iter.array_pos());
+  ASSERT_EQ(1, iter.char_pos());
+  ASSERT_EQ(251, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(2, iter.array_pos());
+  ASSERT_EQ(2, iter.char_pos());
+  ASSERT_EQ(120120, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(4, iter.array_pos());
+  ASSERT_EQ(3, iter.char_pos());
+  ASSERT_EQ('z', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_TRUE(iter.end());
+  ASSERT_EQ(5, iter.array_pos());
+  ASSERT_EQ(4, iter.char_pos());
+
+  // Don't care what it returns, but this shouldn't crash
+  iter.get();
+
+  ASSERT_FALSE(iter.Advance());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc
new file mode 100644
index 0000000..f6e2c29
--- /dev/null
+++ b/base/i18n/file_util_icu.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// File utilities that use the ICU library go in this file.
+
+#include "base/i18n/file_util_icu.h"
+
+#include "base/files/file_path.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/i18n/string_compare.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "third_party/icu/source/common/unicode/uniset.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace base {
+namespace i18n {
+
+namespace {
+
+class IllegalCharacters {
+ public:
+  static IllegalCharacters* GetInstance() {
+    return Singleton<IllegalCharacters>::get();
+  }
+
+  bool DisallowedEverywhere(UChar32 ucs4) {
+    return !!illegal_anywhere_->contains(ucs4);
+  }
+
+  bool DisallowedLeadingOrTrailing(UChar32 ucs4) {
+    return !!illegal_at_ends_->contains(ucs4);
+  }
+
+  bool IsAllowedName(const string16& s) {
+    return s.empty() || (!!illegal_anywhere_->containsNone(
+                             icu::UnicodeString(s.c_str(), s.size())) &&
+                         !illegal_at_ends_->contains(*s.begin()) &&
+                         !illegal_at_ends_->contains(*s.rbegin()));
+  }
+
+ private:
+  friend class Singleton<IllegalCharacters>;
+  friend struct DefaultSingletonTraits<IllegalCharacters>;
+
+  IllegalCharacters();
+  ~IllegalCharacters() { }
+
+  // set of characters considered invalid anywhere inside a filename.
+  scoped_ptr<icu::UnicodeSet> illegal_anywhere_;
+
+  // set of characters considered invalid at either end of a filename.
+  scoped_ptr<icu::UnicodeSet> illegal_at_ends_;
+
+  DISALLOW_COPY_AND_ASSIGN(IllegalCharacters);
+};
+
+IllegalCharacters::IllegalCharacters() {
+  UErrorCode everywhere_status = U_ZERO_ERROR;
+  UErrorCode ends_status = U_ZERO_ERROR;
+  // Control characters, formatting characters, non-characters, path separators,
+  // and some printable ASCII characters regarded as dangerous ('"*/:<>?\\').
+  // See  http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx
+  // and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx
+  // Note that code points in the "Other, Format" (Cf) category are ignored on
+  // HFS+ despite the ZERO_WIDTH_JOINER and ZERO_WIDTH_NON-JOINER being
+  // legitimate in Arabic and some S/SE Asian scripts. In addition tilde (~) is
+  // also excluded due to the possibility of interacting poorly with short
+  // filenames on VFAT. (Related to CVE-2014-9390)
+  illegal_anywhere_.reset(new icu::UnicodeSet(
+      UNICODE_STRING_SIMPLE("[[\"~*/:<>?\\\\|][:Cc:][:Cf:]]"),
+      everywhere_status));
+  illegal_at_ends_.reset(new icu::UnicodeSet(
+      UNICODE_STRING_SIMPLE("[[:WSpace:][.]]"), ends_status));
+  DCHECK(U_SUCCESS(everywhere_status));
+  DCHECK(U_SUCCESS(ends_status));
+
+  // Add non-characters. If this becomes a performance bottleneck by
+  // any chance, do not add these to |set| and change IsFilenameLegal()
+  // to check |ucs4 & 0xFFFEu == 0xFFFEu|, in addiition to calling
+  // IsAllowedName().
+  illegal_anywhere_->add(0xFDD0, 0xFDEF);
+  for (int i = 0; i <= 0x10; ++i) {
+    int plane_base = 0x10000 * i;
+    illegal_anywhere_->add(plane_base + 0xFFFE, plane_base + 0xFFFF);
+  }
+  illegal_anywhere_->freeze();
+  illegal_at_ends_->freeze();
+}
+
+}  // namespace
+
+bool IsFilenameLegal(const string16& file_name) {
+  return IllegalCharacters::GetInstance()->IsAllowedName(file_name);
+}
+
+void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
+                                    char replace_char) {
+  IllegalCharacters* illegal = IllegalCharacters::GetInstance();
+
+  DCHECK(!(illegal->DisallowedEverywhere(replace_char)));
+  DCHECK(!(illegal->DisallowedLeadingOrTrailing(replace_char)));
+
+  int cursor = 0;  // The ICU macros expect an int.
+  while (cursor < static_cast<int>(file_name->size())) {
+    int char_begin = cursor;
+    uint32 code_point;
+#if defined(OS_MACOSX)
+    // Mac uses UTF-8 encoding for filenames.
+    U8_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
+            code_point);
+#elif defined(OS_WIN)
+    // Windows uses UTF-16 encoding for filenames.
+    U16_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
+             code_point);
+#elif defined(OS_POSIX)
+    // Linux doesn't actually define an encoding. It basically allows anything
+    // except for a few special ASCII characters.
+    unsigned char cur_char = static_cast<unsigned char>((*file_name)[cursor++]);
+    if (cur_char >= 0x80)
+      continue;
+    code_point = cur_char;
+#else
+    NOTREACHED();
+#endif
+
+    if (illegal->DisallowedEverywhere(code_point) ||
+        ((char_begin == 0 || cursor == static_cast<int>(file_name->length())) &&
+         illegal->DisallowedLeadingOrTrailing(code_point))) {
+      file_name->replace(char_begin, cursor - char_begin, 1, replace_char);
+      // We just made the potentially multi-byte/word char into one that only
+      // takes one byte/word, so need to adjust the cursor to point to the next
+      // character again.
+      cursor = char_begin + 1;
+    }
+  }
+}
+
+bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
+  UErrorCode error_code = U_ZERO_ERROR;
+  // Use the default collator. The default locale should have been properly
+  // set by the time this constructor is called.
+  scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error_code));
+  DCHECK(U_SUCCESS(error_code));
+  // Make it case-sensitive.
+  collator->setStrength(icu::Collator::TERTIARY);
+
+#if defined(OS_WIN)
+  return CompareString16WithCollator(*collator, WideToUTF16(a.value()),
+                                     WideToUTF16(b.value())) == UCOL_LESS;
+
+#elif defined(OS_POSIX)
+  // On linux, the file system encoding is not defined. We assume
+  // SysNativeMBToWide takes care of it.
+  return CompareString16WithCollator(
+             *collator, WideToUTF16(SysNativeMBToWide(a.value().c_str())),
+             WideToUTF16(SysNativeMBToWide(b.value().c_str()))) == UCOL_LESS;
+#else
+  #error Not implemented on your system
+#endif
+}
+
+void NormalizeFileNameEncoding(FilePath* file_name) {
+#if defined(OS_CHROMEOS)
+  std::string normalized_str;
+  if (ConvertToUtf8AndNormalize(file_name->BaseName().value(),
+                                kCodepageUTF8,
+                                &normalized_str)) {
+    *file_name = file_name->DirName().Append(FilePath(normalized_str));
+  }
+#endif
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/file_util_icu.h b/base/i18n/file_util_icu.h
new file mode 100644
index 0000000..6d7f2ec
--- /dev/null
+++ b/base/i18n/file_util_icu.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_FILE_UTIL_ICU_H_
+#define BASE_I18N_FILE_UTIL_ICU_H_
+
+// File utilities that use the ICU library go in this file.
+
+#include "base/files/file_path.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace i18n {
+
+// Returns true if file_name does not have any illegal character. The input
+// param has the same restriction as that for ReplaceIllegalCharacters.
+BASE_I18N_EXPORT bool IsFilenameLegal(const string16& file_name);
+
+// Replaces characters in |file_name| that are illegal for file names with
+// |replace_char|. |file_name| must not be a full or relative path, but just the
+// file name component (since slashes are considered illegal). Any leading or
+// trailing whitespace or periods in |file_name| is also replaced with the
+// |replace_char|.
+//
+// Example:
+//   "bad:file*name?.txt" will be turned into "bad_file_name_.txt" when
+//   |replace_char| is '_'.
+//
+// Warning: Do not use this function as the sole means of sanitizing a filename.
+//   While the resulting filename itself would be legal, it doesn't necessarily
+//   mean that the file will behave safely. On Windows, certain reserved names
+//   refer to devices rather than files (E.g. LPT1), and some filenames could be
+//   interpreted as shell namespace extensions (E.g. Foo.{<GUID>}).
+//
+// TODO(asanka): Move full filename sanitization logic here.
+BASE_I18N_EXPORT void ReplaceIllegalCharactersInPath(
+    FilePath::StringType* file_name,
+    char replace_char);
+
+// Compares two filenames using the current locale information. This can be
+// used to sort directory listings. It behaves like "operator<" for use in
+// std::sort.
+BASE_I18N_EXPORT bool LocaleAwareCompareFilenames(const FilePath& a,
+                                                  const FilePath& b);
+
+// Calculates the canonical file-system representation of |file_name| base name.
+// Modifies |file_name| in place. No-op if not on ChromeOS.
+BASE_I18N_EXPORT void NormalizeFileNameEncoding(FilePath* file_name);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_FILE_UTIL_ICU_H_
diff --git a/base/i18n/file_util_icu_unittest.cc b/base/i18n/file_util_icu_unittest.cc
new file mode 100644
index 0000000..8fa7f6a
--- /dev/null
+++ b/base/i18n/file_util_icu_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/file_util_icu.h"
+
+#include "base/files/file_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+namespace i18n {
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+class FileUtilICUTest : public PlatformTest {
+};
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+
+// Linux disallows some evil ASCII characters, but passes all non-ASCII.
+static const struct GoodBadPairLinux {
+  const char* bad_name;
+  const char* good_name;
+} kLinuxIllegalCharacterCases[] = {
+  {"bad*\\/file:name?.jpg", "bad---file-name-.jpg"},
+  {"**********::::.txt", "--------------.txt"},
+  {"\xe9\xf0zzzz.\xff", "\xe9\xf0zzzz.\xff"},
+  {" _ ", "-_-"},
+  {".", "-"},
+  {" .( ). ", "-.( ).-"},
+  {"     ", "-   -"},
+};
+
+TEST_F(FileUtilICUTest, ReplaceIllegalCharacersInPathLinuxTest) {
+  for (size_t i = 0; i < arraysize(kLinuxIllegalCharacterCases); ++i) {
+    std::string bad_name(kLinuxIllegalCharacterCases[i].bad_name);
+    ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(kLinuxIllegalCharacterCases[i].good_name, bad_name);
+  }
+}
+
+#endif
+
+// For Mac & Windows, which both do Unicode validation on filenames. These
+// characters are given as wide strings since its more convenient to specify
+// unicode characters. For Mac they should be converted to UTF-8.
+static const struct goodbad_pair {
+  const wchar_t* bad_name;
+  const wchar_t* good_name;
+} kIllegalCharacterCases[] = {
+    {L"bad*file:name?.jpg", L"bad-file-name-.jpg"},
+    {L"**********::::.txt", L"--------------.txt"},
+    // We can't use UCNs (universal character names) for C0/C1 characters and
+    // U+007F, but \x escape is interpreted by MSVC and gcc as we intend.
+    {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"},
+    {L"bad*file\\?name.jpg", L"bad-file--name.jpg"},
+    {L"\t  bad*file\\name/.jpg", L"-  bad-file-name-.jpg"},
+    {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"},
+    {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"},
+    {L"\u0635\u200C\u0644.mp3", L"\u0635-\u0644.mp3"},
+    {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"},
+    // Unassigned codepoints are ok.
+    {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"},
+    // Non-characters are not allowed.
+    {L"bad\uFFFFfile\U0010FFFEname.jpg", L"bad-file-name.jpg"},
+    {L"bad\uFDD0file\uFDEFname.jpg", L"bad-file-name.jpg"},
+    // CVE-2014-9390
+    {L"(\u200C.\u200D.\u200E.\u200F.\u202A.\u202B.\u202C.\u202D.\u202E.\u206A."
+     L"\u206B.\u206C.\u206D.\u206F.\uFEFF)",
+     L"(-.-.-.-.-.-.-.-.-.-.-.-.-.-.-)"},
+    {L"config~1", L"config-1"},
+    {L" _ ", L"-_-"},
+    {L" ", L"-"},
+    {L"\u2008.(\u2007).\u3000", L"-.(\u2007).-"},
+    {L"     ", L"-   -"},
+    {L".    ", L"-   -"}
+};
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+
+TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) {
+  for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
+#if defined(OS_WIN)
+    std::wstring bad_name(kIllegalCharacterCases[i].bad_name);
+    ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name);
+#elif defined(OS_MACOSX)
+    std::string bad_name(WideToUTF8(kIllegalCharacterCases[i].bad_name));
+    ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(WideToUTF8(kIllegalCharacterCases[i].good_name), bad_name);
+#endif
+  }
+}
+
+#endif
+
+TEST_F(FileUtilICUTest, IsFilenameLegalTest) {
+  EXPECT_TRUE(IsFilenameLegal(string16()));
+
+  for (const auto& test_case : kIllegalCharacterCases) {
+    string16 bad_name = WideToUTF16(test_case.bad_name);
+    string16 good_name = WideToUTF16(test_case.good_name);
+
+    EXPECT_TRUE(IsFilenameLegal(good_name)) << good_name;
+    if (good_name != bad_name)
+      EXPECT_FALSE(IsFilenameLegal(bad_name)) << bad_name;
+  }
+}
+
+#if defined(OS_CHROMEOS)
+static const struct normalize_name_encoding_test_cases {
+  const char* original_path;
+  const char* normalized_path;
+} kNormalizeFileNameEncodingTestCases[] = {
+  { "foo_na\xcc\x88me.foo", "foo_n\xc3\xa4me.foo"},
+  { "foo_dir_na\xcc\x88me/foo_na\xcc\x88me.foo",
+    "foo_dir_na\xcc\x88me/foo_n\xc3\xa4me.foo"},
+  { "", ""},
+  { "foo_dir_na\xcc\x88me/", "foo_dir_n\xc3\xa4me"}
+};
+
+TEST_F(FileUtilICUTest, NormalizeFileNameEncoding) {
+  for (size_t i = 0; i < arraysize(kNormalizeFileNameEncodingTestCases); i++) {
+    FilePath path(kNormalizeFileNameEncodingTestCases[i].original_path);
+    NormalizeFileNameEncoding(&path);
+    EXPECT_EQ(FilePath(kNormalizeFileNameEncodingTestCases[i].normalized_path),
+              path);
+  }
+}
+
+#endif
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/i18n_constants.cc b/base/i18n/i18n_constants.cc
new file mode 100644
index 0000000..7d2f5fc
--- /dev/null
+++ b/base/i18n/i18n_constants.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/i18n_constants.h"
+
+namespace base {
+
+const char kCodepageLatin1[] = "ISO-8859-1";
+const char kCodepageUTF8[] = "UTF-8";
+
+}  // namespace base
+
diff --git a/base/i18n/i18n_constants.h b/base/i18n/i18n_constants.h
new file mode 100644
index 0000000..c1bd87d
--- /dev/null
+++ b/base/i18n/i18n_constants.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_I18N_CONSTANTS_H_
+#define BASE_I18N_I18N_CONSTANTS_H_
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Names of codepages (charsets) understood by icu.
+BASE_I18N_EXPORT extern const char kCodepageLatin1[];  // a.k.a. ISO 8859-1
+BASE_I18N_EXPORT extern const char kCodepageUTF8[];
+
+// The other possible options are UTF-16BE and UTF-16LE, but they are unused in
+// Chromium as of this writing.
+
+}  // namespace base
+
+#endif  // BASE_I18N_I18N_CONSTANTS_H_
diff --git a/base/i18n/icu_encoding_detection.cc b/base/i18n/icu_encoding_detection.cc
new file mode 100644
index 0000000..ccd5cde
--- /dev/null
+++ b/base/i18n/icu_encoding_detection.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_encoding_detection.h"
+
+#include <set>
+
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/i18n/unicode/ucsdet.h"
+
+namespace base {
+
+bool DetectEncoding(const std::string& text, std::string* encoding) {
+  if (IsStringASCII(text)) {
+    *encoding = std::string();
+    return true;
+  }
+
+  UErrorCode status = U_ZERO_ERROR;
+  UCharsetDetector* detector = ucsdet_open(&status);
+  ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+                 &status);
+  const UCharsetMatch* match = ucsdet_detect(detector, &status);
+  if (match == NULL)
+    return false;
+  const char* detected_encoding = ucsdet_getName(match, &status);
+  ucsdet_close(detector);
+
+  if (U_FAILURE(status))
+    return false;
+
+  *encoding = detected_encoding;
+  return true;
+}
+
+bool DetectAllEncodings(const std::string& text,
+                        std::vector<std::string>* encodings) {
+  UErrorCode status = U_ZERO_ERROR;
+  UCharsetDetector* detector = ucsdet_open(&status);
+  ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+                 &status);
+  int matches_count = 0;
+  const UCharsetMatch** matches = ucsdet_detectAll(detector,
+                                                   &matches_count,
+                                                   &status);
+  if (U_FAILURE(status)) {
+    ucsdet_close(detector);
+    return false;
+  }
+
+  // ICU has some heuristics for encoding detection, such that the more likely
+  // encodings should be returned first. However, it doesn't always return
+  // all encodings that properly decode |text|, so we'll append more encodings
+  // later. To make that efficient, keep track of encodings sniffed in this
+  // first phase.
+  std::set<std::string> sniffed_encodings;
+
+  encodings->clear();
+  for (int i = 0; i < matches_count; i++) {
+    UErrorCode get_name_status = U_ZERO_ERROR;
+    const char* encoding_name = ucsdet_getName(matches[i], &get_name_status);
+
+    // If we failed to get the encoding's name, ignore the error.
+    if (U_FAILURE(get_name_status))
+      continue;
+
+    int32_t confidence = ucsdet_getConfidence(matches[i], &get_name_status);
+
+    // We also treat this error as non-fatal.
+    if (U_FAILURE(get_name_status))
+      continue;
+
+    // A confidence level >= 10 means that the encoding is expected to properly
+    // decode the text. Drop all encodings with lower confidence level.
+    if (confidence < 10)
+      continue;
+
+    encodings->push_back(encoding_name);
+    sniffed_encodings.insert(encoding_name);
+  }
+
+  // Append all encodings not included earlier, in arbitrary order.
+  // TODO(jshin): This shouldn't be necessary, possible ICU bug.
+  // See also http://crbug.com/65917.
+  UEnumeration* detectable_encodings = ucsdet_getAllDetectableCharsets(detector,
+                                                                       &status);
+  int detectable_count = uenum_count(detectable_encodings, &status);
+  for (int i = 0; i < detectable_count; i++) {
+    int name_length;
+    const char* name_raw = uenum_next(detectable_encodings,
+                                      &name_length,
+                                      &status);
+    std::string name(name_raw, name_length);
+    if (sniffed_encodings.find(name) == sniffed_encodings.end())
+      encodings->push_back(name);
+  }
+  uenum_close(detectable_encodings);
+
+  ucsdet_close(detector);
+  return !encodings->empty();
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h
new file mode 100644
index 0000000..6d1e71c
--- /dev/null
+++ b/base/i18n/icu_encoding_detection.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_ICU_ENCODING_DETECTION_H_
+#define BASE_I18N_ICU_ENCODING_DETECTION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Detect encoding of |text| and put the name of encoding (as returned by ICU)
+// in |encoding|. For ASCII texts |encoding| will be set to an empty string.
+// Returns true on success.
+BASE_I18N_EXPORT bool DetectEncoding(const std::string& text,
+                                     std::string* encoding);
+
+// Detect all possible encodings of |text| and put their names
+// (as returned by ICU) in |encodings|. Returns true on success.
+// Note: this function may return encodings that may fail to decode |text|,
+// the caller is responsible for handling that.
+BASE_I18N_EXPORT bool DetectAllEncodings(const std::string& text,
+                                         std::vector<std::string>* encodings);
+
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_ENCODING_DETECTION_H_
diff --git a/base/i18n/icu_string_conversions.cc b/base/i18n/icu_string_conversions.cc
new file mode 100644
index 0000000..edb31c3
--- /dev/null
+++ b/base/i18n/icu_string_conversions.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_string_conversions.h"
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/ucnv.h"
+#include "third_party/icu/source/common/unicode/ucnv_cb.h"
+#include "third_party/icu/source/common/unicode/ucnv_err.h"
+#include "third_party/icu/source/common/unicode/unorm.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+
+namespace base {
+
+namespace {
+// ToUnicodeCallbackSubstitute() is based on UCNV_TO_U_CALLBACK_SUBSTITUTE
+// in source/common/ucnv_err.c.
+
+// Copyright (c) 1995-2006 International Business Machines Corporation
+// and others
+//
+// All rights reserved.
+//
+
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, and/or
+// sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, provided that the above copyright notice(s) and
+// this permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice appear in
+// supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+// INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+// OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+// OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Except as contained in this notice, the name of a copyright holder
+// shall not be used in advertising or otherwise to promote the sale, use
+// or other dealings in this Software without prior written authorization
+// of the copyright holder.
+
+//  ___________________________________________________________________________
+//
+// All trademarks and registered trademarks mentioned herein are the property
+// of their respective owners.
+
+void ToUnicodeCallbackSubstitute(const void* context,
+                                 UConverterToUnicodeArgs *to_args,
+                                 const char* code_units,
+                                 int32_t length,
+                                 UConverterCallbackReason reason,
+                                 UErrorCode * err) {
+  static const UChar kReplacementChar = 0xFFFD;
+  if (reason <= UCNV_IRREGULAR) {
+      if (context == NULL ||
+          (*(reinterpret_cast<const char*>(context)) == 'i' &&
+           reason == UCNV_UNASSIGNED)) {
+        *err = U_ZERO_ERROR;
+        ucnv_cbToUWriteUChars(to_args, &kReplacementChar, 1, 0, err);
+      }
+      // else the caller must have set the error code accordingly.
+  }
+  // else ignore the reset, close and clone calls.
+}
+
+bool ConvertFromUTF16(UConverter* converter, const UChar* uchar_src,
+                      int uchar_len, OnStringConversionError::Type on_error,
+                      std::string* encoded) {
+  int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(uchar_len,
+      ucnv_getMaxCharSize(converter));
+  encoded->resize(encoded_max_length);
+
+  UErrorCode status = U_ZERO_ERROR;
+
+  // Setup our error handler.
+  switch (on_error) {
+    case OnStringConversionError::FAIL:
+      ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0,
+                            NULL, NULL, &status);
+      break;
+    case OnStringConversionError::SKIP:
+    case OnStringConversionError::SUBSTITUTE:
+      ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0,
+                            NULL, NULL, &status);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  // ucnv_fromUChars returns size not including terminating null
+  int actual_size = ucnv_fromUChars(converter, &(*encoded)[0],
+      encoded_max_length, uchar_src, uchar_len, &status);
+  encoded->resize(actual_size);
+  ucnv_close(converter);
+  if (U_SUCCESS(status))
+    return true;
+  encoded->clear();  // Make sure the output is empty on error.
+  return false;
+}
+
+// Set up our error handler for ToUTF-16 converters
+void SetUpErrorHandlerForToUChars(OnStringConversionError::Type on_error,
+                                  UConverter* converter, UErrorCode* status) {
+  switch (on_error) {
+    case OnStringConversionError::FAIL:
+      ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_STOP, 0,
+                          NULL, NULL, status);
+      break;
+    case OnStringConversionError::SKIP:
+      ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_SKIP, 0,
+                          NULL, NULL, status);
+      break;
+    case OnStringConversionError::SUBSTITUTE:
+      ucnv_setToUCallBack(converter, ToUnicodeCallbackSubstitute, 0,
+                          NULL, NULL, status);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+}  // namespace
+
+// Codepage <-> Wide/UTF-16  ---------------------------------------------------
+
+bool UTF16ToCodepage(const string16& utf16,
+                     const char* codepage_name,
+                     OnStringConversionError::Type on_error,
+                     std::string* encoded) {
+  encoded->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  return ConvertFromUTF16(converter, utf16.c_str(),
+                          static_cast<int>(utf16.length()), on_error, encoded);
+}
+
+bool CodepageToUTF16(const std::string& encoded,
+                     const char* codepage_name,
+                     OnStringConversionError::Type on_error,
+                     string16* utf16) {
+  utf16->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  // Even in the worst case, the maximum length in 2-byte units of UTF-16
+  // output would be at most the same as the number of bytes in input. There
+  // is no single-byte encoding in which a character is mapped to a
+  // non-BMP character requiring two 2-byte units.
+  //
+  // Moreover, non-BMP characters in legacy multibyte encodings
+  // (e.g. EUC-JP, GB18030) take at least 2 bytes. The only exceptions are
+  // BOCU and SCSU, but we don't care about them.
+  size_t uchar_max_length = encoded.length() + 1;
+
+  SetUpErrorHandlerForToUChars(on_error, converter, &status);
+  scoped_ptr<char16[]> buffer(new char16[uchar_max_length]);
+  int actual_size = ucnv_toUChars(converter, buffer.get(),
+      static_cast<int>(uchar_max_length), encoded.data(),
+      static_cast<int>(encoded.length()), &status);
+  ucnv_close(converter);
+  if (!U_SUCCESS(status)) {
+    utf16->clear();  // Make sure the output is empty on error.
+    return false;
+  }
+
+  utf16->assign(buffer.get(), actual_size);
+  return true;
+}
+
+bool ConvertToUtf8AndNormalize(const std::string& text,
+                               const std::string& charset,
+                               std::string* result) {
+  result->clear();
+  string16 utf16;
+  if (!CodepageToUTF16(
+      text, charset.c_str(), OnStringConversionError::FAIL, &utf16))
+    return false;
+
+  UErrorCode status = U_ZERO_ERROR;
+  size_t max_length = utf16.length() + 1;
+  string16 normalized_utf16;
+  scoped_ptr<char16[]> buffer(new char16[max_length]);
+  int actual_length = unorm_normalize(
+      utf16.c_str(), utf16.length(), UNORM_NFC, 0,
+      buffer.get(), static_cast<int>(max_length), &status);
+  if (!U_SUCCESS(status))
+    return false;
+  normalized_utf16.assign(buffer.get(), actual_length);
+
+  return UTF16ToUTF8(normalized_utf16.data(),
+                     normalized_utf16.length(), result);
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_string_conversions.h b/base/i18n/icu_string_conversions.h
new file mode 100644
index 0000000..9135da8
--- /dev/null
+++ b/base/i18n/icu_string_conversions.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_ICU_STRING_CONVERSIONS_H_
+#define BASE_I18N_ICU_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/i18n/i18n_constants.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// Defines the error handling modes of UTF16ToCodepage and CodepageToUTF16.
+class OnStringConversionError {
+ public:
+  enum Type {
+    // The function will return failure. The output buffer will be empty.
+    FAIL,
+
+    // The offending characters are skipped and the conversion will proceed as
+    // if they did not exist.
+    SKIP,
+
+    // When converting to Unicode, the offending byte sequences are substituted
+    // by Unicode replacement character (U+FFFD). When converting from Unicode,
+    // this is the same as SKIP.
+    SUBSTITUTE,
+  };
+
+ private:
+  OnStringConversionError();
+};
+
+// Converts between UTF-16 strings and the encoding specified.  If the
+// encoding doesn't exist or the encoding fails (when on_error is FAIL),
+// returns false.
+BASE_I18N_EXPORT bool UTF16ToCodepage(const string16& utf16,
+                                      const char* codepage_name,
+                                      OnStringConversionError::Type on_error,
+                                      std::string* encoded);
+BASE_I18N_EXPORT bool CodepageToUTF16(const std::string& encoded,
+                                      const char* codepage_name,
+                                      OnStringConversionError::Type on_error,
+                                      string16* utf16);
+
+// Converts from any codepage to UTF-8 and ensures the resulting UTF-8 is
+// normalized.
+BASE_I18N_EXPORT bool ConvertToUtf8AndNormalize(const std::string& text,
+                                                const std::string& charset,
+                                                std::string* result);
+
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_STRING_CONVERSIONS_H_
diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc
new file mode 100644
index 0000000..821529d
--- /dev/null
+++ b/base/i18n/icu_string_conversions_unittest.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <math.h>
+#include <stdarg.h>
+
+#include <limits>
+#include <sstream>
+
+#include "base/basictypes.h"
+#include "base/format_macros.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Given a null-terminated string of wchar_t with each wchar_t representing
+// a UTF-16 code unit, returns a string16 made up of wchar_t's in the input.
+// Each wchar_t should be <= 0xFFFF and a non-BMP character (> U+FFFF)
+// should be represented as a surrogate pair (two UTF-16 units)
+// *even* where wchar_t is 32-bit (Linux and Mac).
+//
+// This is to help write tests for functions with string16 params until
+// the C++ 0x UTF-16 literal is well-supported by compilers.
+string16 BuildString16(const wchar_t* s) {
+#if defined(WCHAR_T_IS_UTF16)
+  return string16(s);
+#elif defined(WCHAR_T_IS_UTF32)
+  string16 u16;
+  while (*s != 0) {
+    DCHECK_LE(static_cast<unsigned int>(*s), 0xFFFFu);
+    u16.push_back(*s++);
+  }
+  return u16;
+#endif
+}
+
+}  // namespace
+
+// kConverterCodepageCases is not comprehensive. There are a number of cases
+// to add if we really want to have a comprehensive coverage of various
+// codepages and their 'idiosyncrasies'. Currently, the only implementation
+// for CodepageTo* and *ToCodepage uses ICU, which has a very extensive
+// set of tests for the charset conversion. So, we can get away with a
+// relatively small number of cases listed below.
+//
+// Note about |u16_wide| in the following struct.
+// On Windows, the field is always identical to |wide|. On Mac and Linux,
+// it's identical as long as there's no character outside the
+// BMP (<= U+FFFF). When there is, it is different from |wide| and
+// is not a real wide string (UTF-32 string) in that each wchar_t in
+// the string is a UTF-16 code unit zero-extended to be 32-bit
+// even when the code unit belongs to a surrogate pair.
+// For instance, a Unicode string (U+0041 U+010000) is represented as
+// L"\x0041\xD800\xDC00" instead of L"\x0041\x10000".
+// To avoid the clutter, |u16_wide| will be set to NULL
+// if it's identical to |wide| on *all* platforms.
+
+static const struct {
+  const char* codepage_name;
+  const char* encoded;
+  OnStringConversionError::Type on_error;
+  bool success;
+  const wchar_t* wide;
+  const wchar_t* u16_wide;
+} kConvertCodepageCases[] = {
+  // Test a case where the input cannot be decoded, using SKIP, FAIL
+  // and SUBSTITUTE error handling rules. "A7 41" is valid, but "A6" isn't.
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::FAIL,
+   false,
+   L"",
+   NULL},
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::SKIP,
+   true,
+   L"\x4F60",
+   NULL},
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::SUBSTITUTE,
+   true,
+   L"\x4F60\xFFFD",
+   NULL},
+  // Arabic (ISO-8859)
+  {"iso-8859-6",
+   "\xC7\xEE\xE4\xD3\xF1\xEE\xE4\xC7\xE5\xEF" " "
+   "\xD9\xEE\xE4\xEE\xEA\xF2\xE3\xEF\xE5\xF2",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0627\x064E\x0644\x0633\x0651\x064E\x0644\x0627\x0645\x064F" L" "
+   L"\x0639\x064E\x0644\x064E\x064A\x0652\x0643\x064F\x0645\x0652",
+   NULL},
+  // Chinese Simplified (GB2312)
+  {"gb2312",
+   "\xC4\xE3\xBA\xC3",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x4F60\x597D",
+   NULL},
+  // Chinese (GB18030) : 4 byte sequences mapped to BMP characters
+  {"gb18030",
+   "\x81\x30\x84\x36\xA1\xA7",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x00A5\x00A8",
+   NULL},
+  // Chinese (GB18030) : A 4 byte sequence mapped to plane 2 (U+20000)
+  {"gb18030",
+   "\x95\x32\x82\x36\xD2\xBB",
+   OnStringConversionError::FAIL,
+   true,
+#if defined(WCHAR_T_IS_UTF16)
+   L"\xD840\xDC00\x4E00",
+#elif defined(WCHAR_T_IS_UTF32)
+   L"\x20000\x4E00",
+#endif
+   L"\xD840\xDC00\x4E00"},
+  {"big5",
+   "\xA7\x41\xA6\x6E",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x4F60\x597D",
+   NULL},
+  // Greek (ISO-8859)
+  {"iso-8859-7",
+   "\xE3\xE5\xE9\xDC" " " "\xF3\xEF\xF5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5",
+   NULL},
+  // Hebrew (Windows)
+  {"windows-1255",
+   "\xF9\xD1\xC8\xEC\xE5\xC9\xED",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x05E9\x05C1\x05B8\x05DC\x05D5\x05B9\x05DD",
+   NULL},
+  // Korean (EUC)
+  {"euc-kr",
+   "\xBE\xC8\xB3\xE7\xC7\xCF\xBC\xBC\xBF\xE4",
+   OnStringConversionError::FAIL,
+   true,
+   L"\xC548\xB155\xD558\xC138\xC694",
+   NULL},
+  // Japanese (EUC)
+  {"euc-jp",
+   "\xA4\xB3\xA4\xF3\xA4\xCB\xA4\xC1\xA4\xCF\xB0\xEC\x8E\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Japanese (ISO-2022)
+  {"iso-2022-jp",
+   "\x1B$B" "\x24\x33\x24\x73\x24\x4B\x24\x41\x24\x4F\x30\x6C" "\x1B(B"
+   "ab" "\x1B(J" "\x5C\x7E#$" "\x1B(B",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00" L"ab\x00A5\x203E#$",
+   NULL},
+  // Japanese (Shift-JIS)
+  {"sjis",
+   "\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x88\xEA\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Russian (KOI8)
+  {"koi8-r",
+   "\xDA\xC4\xD2\xC1\xD7\xD3\xD4\xD7\xD5\xCA\xD4\xC5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432"
+   L"\x0443\x0439\x0442\x0435",
+   NULL},
+  // Thai (windows-874)
+  {"windows-874",
+   "\xCA\xC7\xD1\xCA\xB4\xD5" "\xA4\xC3\xD1\xBA",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0E2A\x0E27\x0E31\x0E2A\x0E14\x0E35"
+   L"\x0E04\x0E23\x0e31\x0E1A",
+   NULL},
+};
+
+TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) {
+  for (size_t i = 0; i < arraysize(kConvertCodepageCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertCodepageCases[i].encoded,
+                     kConvertCodepageCases[i].codepage_name));
+
+    string16 utf16;
+    bool success = CodepageToUTF16(kConvertCodepageCases[i].encoded,
+                                   kConvertCodepageCases[i].codepage_name,
+                                   kConvertCodepageCases[i].on_error,
+                                   &utf16);
+    string16 utf16_expected;
+    if (kConvertCodepageCases[i].u16_wide == NULL)
+      utf16_expected = BuildString16(kConvertCodepageCases[i].wide);
+    else
+      utf16_expected = BuildString16(kConvertCodepageCases[i].u16_wide);
+    EXPECT_EQ(kConvertCodepageCases[i].success, success);
+    EXPECT_EQ(utf16_expected, utf16);
+
+    // When decoding was successful and nothing was skipped, we also check the
+    // reverse conversion. See also the corresponding comment in
+    // ConvertBetweenCodepageAndWide.
+    if (success &&
+        kConvertCodepageCases[i].on_error == OnStringConversionError::FAIL) {
+      std::string encoded;
+      success = UTF16ToCodepage(utf16, kConvertCodepageCases[i].codepage_name,
+                                kConvertCodepageCases[i].on_error, &encoded);
+      EXPECT_EQ(kConvertCodepageCases[i].success, success);
+      EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded);
+    }
+  }
+}
+
+static const struct {
+  const char* encoded;
+  const char* codepage_name;
+  bool expected_success;
+  const char* expected_value;
+} kConvertAndNormalizeCases[] = {
+  {"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"},
+  {"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"},
+  {"foo-\xe4.html", "foo-bar", false, ""},
+  // HTML Encoding spec treats US-ASCII as synonymous with windows-1252
+  {"foo-\xff.html", "ascii", true, "foo-\xc3\xbf.html"},
+  {"foo.html", "ascii", true, "foo.html"},
+  {"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"},
+  {"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"},
+  {"\xA7\x41\xA6\x6E", "big5", true, "\xE4\xBD\xA0\xE5\xA5\xBD"},
+  // Windows-1258 does have a combining character at xD2 (which is U+0309).
+  // The sequence of (U+00E2, U+0309) is also encoded as U+1EA9.
+  {"foo\xE2\xD2", "windows-1258", true, "foo\xE1\xBA\xA9"},
+  {"", "iso-8859-1", true, ""},
+};
+TEST(ICUStringConversionsTest, ConvertToUtf8AndNormalize) {
+  std::string result;
+  for (size_t i = 0; i < arraysize(kConvertAndNormalizeCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertAndNormalizeCases[i].encoded,
+                     kConvertAndNormalizeCases[i].codepage_name));
+
+    bool success = ConvertToUtf8AndNormalize(
+        kConvertAndNormalizeCases[i].encoded,
+        kConvertAndNormalizeCases[i].codepage_name, &result);
+    EXPECT_EQ(kConvertAndNormalizeCases[i].expected_success, success);
+    EXPECT_EQ(kConvertAndNormalizeCases[i].expected_value, result);
+  }
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
new file mode 100644
index 0000000..a9f0b12
--- /dev/null
+++ b/base/i18n/icu_util.cc
@@ -0,0 +1,205 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_util.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <string>
+
+#include "base/debug/alias.h"
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "third_party/icu/source/common/unicode/putil.h"
+#include "third_party/icu/source/common/unicode/udata.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif
+
+#define ICU_UTIL_DATA_FILE   0
+#define ICU_UTIL_DATA_SHARED 1
+#define ICU_UTIL_DATA_STATIC 2
+
+namespace base {
+namespace i18n {
+
+// Use an unversioned file name to simplify a icu version update down the road.
+// No need to change the filename in multiple places (gyp files, windows
+// build pkg configurations, etc). 'l' stands for Little Endian.
+// This variable is exported through the header file.
+const char kIcuDataFileName[] = "icudtl.dat";
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
+#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
+#if defined(OS_WIN)
+#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll"
+#endif
+#endif
+
+namespace {
+
+#if !defined(NDEBUG)
+// Assert that we are not called more than once.  Even though calling this
+// function isn't harmful (ICU can handle it), being called twice probably
+// indicates a programming error.
+#if !defined(OS_NACL)
+bool g_called_once = false;
+#endif
+bool g_check_called_once = true;
+#endif
+}
+
+#if !defined(OS_NACL)
+bool InitializeICUWithFileDescriptor(
+    PlatformFile data_fd,
+    MemoryMappedFile::Region data_region) {
+#if !defined(NDEBUG)
+  DCHECK(!g_check_called_once || !g_called_once);
+  g_called_once = true;
+#endif
+
+#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
+  // The ICU data is statically linked.
+  return true;
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
+  CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
+  if (!mapped_file.IsValid()) {
+    if (!mapped_file.Initialize(File(data_fd), data_region)) {
+      LOG(ERROR) << "Couldn't mmap icu data file";
+      return false;
+    }
+  }
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+  return err == U_ZERO_ERROR;
+#endif // ICU_UTIL_DATA_FILE
+}
+
+
+bool InitializeICU() {
+#if !defined(NDEBUG)
+  DCHECK(!g_check_called_once || !g_called_once);
+  g_called_once = true;
+#endif
+
+  bool result;
+#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
+  // We expect to find the ICU data module alongside the current module.
+  FilePath data_path;
+  PathService::Get(DIR_MODULE, &data_path);
+  data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME);
+
+  HMODULE module = LoadLibrary(data_path.value().c_str());
+  if (!module) {
+    LOG(ERROR) << "Failed to load " << ICU_UTIL_DATA_SHARED_MODULE_NAME;
+    return false;
+  }
+
+  FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL);
+  if (!addr) {
+    LOG(ERROR) << ICU_UTIL_DATA_SYMBOL << ": not found in "
+               << ICU_UTIL_DATA_SHARED_MODULE_NAME;
+    return false;
+  }
+
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(reinterpret_cast<void*>(addr), &err);
+  result = (err == U_ZERO_ERROR);
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
+  // The ICU data is statically linked.
+  result = true;
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
+  // If the ICU data directory is set, ICU won't actually load the data until
+  // it is needed.  This can fail if the process is sandboxed at that time.
+  // Instead, we map the file in and hand off the data so the sandbox won't
+  // cause any problems.
+
+  // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
+  // be released.
+  CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
+  if (!mapped_file.IsValid()) {
+#if !defined(OS_MACOSX)
+    FilePath data_path;
+#if defined(OS_WIN)
+    // The data file will be in the same directory as the current module.
+    bool path_ok = PathService::Get(DIR_MODULE, &data_path);
+    wchar_t tmp_buffer[_MAX_PATH] = {0};
+    wcscpy_s(tmp_buffer, data_path.value().c_str());
+    debug::Alias(tmp_buffer);
+    CHECK(path_ok);  // TODO(scottmg): http://crbug.com/445616
+#elif defined(OS_ANDROID)
+    bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
+#else
+    // For now, expect the data file to be alongside the executable.
+    // This is sufficient while we work on unit tests, but will eventually
+    // likely live in a data directory.
+    bool path_ok = PathService::Get(DIR_EXE, &data_path);
+#endif
+    DCHECK(path_ok);
+    data_path = data_path.AppendASCII(kIcuDataFileName);
+
+#if defined(OS_WIN)
+    // TODO(scottmg): http://crbug.com/445616
+    wchar_t tmp_buffer2[_MAX_PATH] = {0};
+    wcscpy_s(tmp_buffer2, data_path.value().c_str());
+    debug::Alias(tmp_buffer2);
+#endif
+
+#else
+    // Assume it is in the framework bundle's Resources directory.
+    ScopedCFTypeRef<CFStringRef> data_file_name(
+        SysUTF8ToCFStringRef(kIcuDataFileName));
+    FilePath data_path =
+      mac::PathForFrameworkBundleResource(data_file_name);
+    if (data_path.empty()) {
+      LOG(ERROR) << kIcuDataFileName << " not found in bundle";
+      return false;
+    }
+#endif  // OS check
+    if (!mapped_file.Initialize(data_path)) {
+#if defined(OS_WIN)
+      CHECK(false);  // TODO(scottmg): http://crbug.com/445616
+#endif
+      LOG(ERROR) << "Couldn't mmap " << data_path.AsUTF8Unsafe();
+      return false;
+    }
+  }
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+  result = (err == U_ZERO_ERROR);
+#if defined(OS_WIN)
+  CHECK(result);  // TODO(scottmg): http://crbug.com/445616
+#endif
+#endif
+
+// To respond to the timezone change properly, the default timezone
+// cache in ICU has to be populated on starting up.
+// TODO(jungshik): Some callers do not care about tz at all. If necessary,
+// add a boolean argument to this function to init'd the default tz only
+// when requested.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  if (result)
+    scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+  return result;
+}
+#endif
+
+void AllowMultipleInitializeCallsForTesting() {
+#if !defined(NDEBUG)
+  g_check_called_once = false;
+#endif
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
new file mode 100644
index 0000000..65de0ad
--- /dev/null
+++ b/base/i18n/icu_util.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_ICU_UTIL_H_
+#define BASE_I18N_ICU_UTIL_H_
+
+#include "base/files/memory_mapped_file.h"
+#include "base/i18n/base_i18n_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace i18n {
+
+BASE_I18N_EXPORT extern const char kIcuDataFileName[];
+
+#if !defined(OS_NACL)
+// Call this function to load ICU's data tables for the current process.  This
+// function should be called before ICU is used.
+BASE_I18N_EXPORT bool InitializeICU();
+
+// Android and html_viewer use a file descriptor passed by browser process to
+// initialize ICU in render processes.
+BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
+    PlatformFile data_fd,
+    MemoryMappedFile::Region data_region);
+#endif
+
+// In a test binary, the call above might occur twice.
+BASE_I18N_EXPORT void AllowMultipleInitializeCallsForTesting();
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_UTIL_H_
diff --git a/base/i18n/icu_util_nacl_win64.cc b/base/i18n/icu_util_nacl_win64.cc
new file mode 100644
index 0000000..9ba8640
--- /dev/null
+++ b/base/i18n/icu_util_nacl_win64.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/icu_util.h"
+
+namespace base {
+namespace i18n {
+
+BASE_I18N_EXPORT bool InitializeICU() {
+  return true;
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc
new file mode 100644
index 0000000..47aa14c
--- /dev/null
+++ b/base/i18n/number_formatting.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/number_formatting.h"
+
+#include "base/format_macros.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+#include "third_party/icu/source/i18n/unicode/numfmt.h"
+
+namespace base {
+
+namespace {
+
+// A simple wrapper around icu::NumberFormat that allows for resetting it
+// (as LazyInstance does not).
+struct NumberFormatWrapper {
+  NumberFormatWrapper() {
+    Reset();
+  }
+
+  void Reset() {
+    // There's no ICU call to destroy a NumberFormat object other than
+    // operator delete, so use the default Delete, which calls operator delete.
+    // This can cause problems if a different allocator is used by this file
+    // than by ICU.
+    UErrorCode status = U_ZERO_ERROR;
+    number_format.reset(icu::NumberFormat::createInstance(status));
+    DCHECK(U_SUCCESS(status));
+  }
+
+  scoped_ptr<icu::NumberFormat> number_format;
+};
+
+LazyInstance<NumberFormatWrapper> g_number_format_int =
+    LAZY_INSTANCE_INITIALIZER;
+LazyInstance<NumberFormatWrapper> g_number_format_float =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+string16 FormatNumber(int64 number) {
+  icu::NumberFormat* number_format =
+      g_number_format_int.Get().number_format.get();
+
+  if (!number_format) {
+    // As a fallback, just return the raw number in a string.
+    return UTF8ToUTF16(StringPrintf("%" PRId64, number));
+  }
+  icu::UnicodeString ustr;
+  number_format->format(number, ustr);
+
+  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+string16 FormatDouble(double number, int fractional_digits) {
+  icu::NumberFormat* number_format =
+      g_number_format_float.Get().number_format.get();
+
+  if (!number_format) {
+    // As a fallback, just return the raw number in a string.
+    return UTF8ToUTF16(StringPrintf("%f", number));
+  }
+  number_format->setMaximumFractionDigits(fractional_digits);
+  number_format->setMinimumFractionDigits(fractional_digits);
+  icu::UnicodeString ustr;
+  number_format->format(number, ustr);
+
+  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+namespace testing {
+
+void ResetFormatters() {
+  g_number_format_int.Get().Reset();
+  g_number_format_float.Get().Reset();
+}
+
+}  // namespace testing
+
+}  // namespace base
diff --git a/base/i18n/number_formatting.h b/base/i18n/number_formatting.h
new file mode 100644
index 0000000..556f9c2
--- /dev/null
+++ b/base/i18n/number_formatting.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_NUMBER_FORMATTING_H_
+#define BASE_I18N_NUMBER_FORMATTING_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatNumber(1234567)
+//         => "1,234,567" in English, "1.234.567" in German
+BASE_I18N_EXPORT string16 FormatNumber(int64 number);
+
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatDouble(1234567.8, 1)
+//         => "1,234,567.8" in English, "1.234.567,8" in German
+BASE_I18N_EXPORT string16 FormatDouble(double number, int fractional_digits);
+
+namespace testing {
+
+// Causes cached formatters to be discarded and recreated. Only useful for
+// testing.
+BASE_I18N_EXPORT void ResetFormatters();
+
+}  // namespace testing
+
+}  // namespace base
+
+#endif  // BASE_I18N_NUMBER_FORMATTING_H_
diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc
new file mode 100644
index 0000000..3b0718d
--- /dev/null
+++ b/base/i18n/number_formatting_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/i18n/number_formatting.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(NumberFormattingTest, FormatNumber) {
+  static const struct {
+    int64 number;
+    const char* expected_english;
+    const char* expected_german;
+  } cases[] = {
+    {0, "0", "0"},
+    {1024, "1,024", "1.024"},
+    {std::numeric_limits<int64>::max(),
+        "9,223,372,036,854,775,807", "9.223.372.036.854.775.807"},
+    {std::numeric_limits<int64>::min(),
+        "-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"},
+    {-42, "-42", "-42"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    i18n::SetICUDefaultLocale("en");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_english,
+              UTF16ToUTF8(FormatNumber(cases[i].number)));
+    i18n::SetICUDefaultLocale("de");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_german,
+              UTF16ToUTF8(FormatNumber(cases[i].number)));
+  }
+}
+
+TEST(NumberFormattingTest, FormatDouble) {
+  static const struct {
+    double number;
+    int frac_digits;
+    const char* expected_english;
+    const char* expected_german;
+  } cases[] = {
+    {0.0, 0, "0", "0"},
+#if !defined(OS_ANDROID)
+    // Bionic can't printf negative zero correctly.
+    {-0.0, 4, "-0.0000", "-0,0000"},
+#endif
+    {1024.2, 0, "1,024", "1.024"},
+    {-1024.223, 2, "-1,024.22", "-1.024,22"},
+    {std::numeric_limits<double>::max(), 6,
+        "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000.000000",
+        "179.769.313.486.232.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000,000000"},
+    {std::numeric_limits<double>::min(), 2, "0.00", "0,00"},
+    {-42.7, 3, "-42.700", "-42,700"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    i18n::SetICUDefaultLocale("en");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_english,
+              UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits)));
+    i18n::SetICUDefaultLocale("de");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_german,
+              UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits)));
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
new file mode 100644
index 0000000..1cccae2
--- /dev/null
+++ b/base/i18n/rtl.cc
@@ -0,0 +1,394 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/rtl.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/locid.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace {
+
+// Extract language, country and variant, but ignore keywords.  For example,
+// en-US, ca@valencia, ca-ES@valencia.
+std::string GetLocaleString(const icu::Locale& locale) {
+  const char* language = locale.getLanguage();
+  const char* country = locale.getCountry();
+  const char* variant = locale.getVariant();
+
+  std::string result =
+      (language != NULL && *language != '\0') ? language : "und";
+
+  if (country != NULL && *country != '\0') {
+    result += '-';
+    result += country;
+  }
+
+  if (variant != NULL && *variant != '\0') {
+    std::string variant_str(variant);
+    base::StringToLowerASCII(&variant_str);
+    result += '@' + variant_str;
+  }
+
+  return result;
+}
+
+// Returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if |character| has strong
+// directionality, returns UNKNOWN_DIRECTION if it doesn't. Please refer to
+// http://unicode.org/reports/tr9/ for more information.
+base::i18n::TextDirection GetCharacterDirection(UChar32 character) {
+  // Now that we have the character, we use ICU in order to query for the
+  // appropriate Unicode BiDi character type.
+  int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+  if ((property == U_RIGHT_TO_LEFT) ||
+      (property == U_RIGHT_TO_LEFT_ARABIC) ||
+      (property == U_RIGHT_TO_LEFT_EMBEDDING) ||
+      (property == U_RIGHT_TO_LEFT_OVERRIDE)) {
+    return base::i18n::RIGHT_TO_LEFT;
+  } else if ((property == U_LEFT_TO_RIGHT) ||
+             (property == U_LEFT_TO_RIGHT_EMBEDDING) ||
+             (property == U_LEFT_TO_RIGHT_OVERRIDE)) {
+    return base::i18n::LEFT_TO_RIGHT;
+  }
+  return base::i18n::UNKNOWN_DIRECTION;
+}
+
+}  // namespace
+
+namespace base {
+namespace i18n {
+
+// Represents the locale-specific ICU text direction.
+static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
+
+// Convert the ICU default locale to a string.
+std::string GetConfiguredLocale() {
+  return GetLocaleString(icu::Locale::getDefault());
+}
+
+// Convert the ICU canonicalized locale to a string.
+std::string GetCanonicalLocale(const std::string& locale) {
+  return GetLocaleString(icu::Locale::createCanonical(locale.c_str()));
+}
+
+// Convert Chrome locale name to ICU locale name
+std::string ICULocaleName(const std::string& locale_string) {
+  // If not Spanish, just return it.
+  if (locale_string.substr(0, 2) != "es")
+    return locale_string;
+  // Expand es to es-ES.
+  if (LowerCaseEqualsASCII(locale_string, "es"))
+    return "es-ES";
+  // Map es-419 (Latin American Spanish) to es-FOO depending on the system
+  // locale.  If it's es-RR other than es-ES, map to es-RR. Otherwise, map
+  // to es-MX (the most populous in Spanish-speaking Latin America).
+  if (LowerCaseEqualsASCII(locale_string, "es-419")) {
+    const icu::Locale& locale = icu::Locale::getDefault();
+    std::string language = locale.getLanguage();
+    const char* country = locale.getCountry();
+    if (LowerCaseEqualsASCII(language, "es") &&
+      !LowerCaseEqualsASCII(country, "es")) {
+        language += '-';
+        language += country;
+        return language;
+    }
+    return "es-MX";
+  }
+  // Currently, Chrome has only "es" and "es-419", but later we may have
+  // more specific "es-RR".
+  return locale_string;
+}
+
+void SetICUDefaultLocale(const std::string& locale_string) {
+  icu::Locale locale(ICULocaleName(locale_string).c_str());
+  UErrorCode error_code = U_ZERO_ERROR;
+  icu::Locale::setDefault(locale, error_code);
+  // This return value is actually bogus because Locale object is
+  // an ID and setDefault seems to always succeed (regardless of the
+  // presence of actual locale data). However,
+  // it does not hurt to have it as a sanity check.
+  DCHECK(U_SUCCESS(error_code));
+  g_icu_text_direction = UNKNOWN_DIRECTION;
+}
+
+bool IsRTL() {
+  return ICUIsRTL();
+}
+
+bool ICUIsRTL() {
+  if (g_icu_text_direction == UNKNOWN_DIRECTION) {
+    const icu::Locale& locale = icu::Locale::getDefault();
+    g_icu_text_direction = GetTextDirectionForLocale(locale.getName());
+  }
+  return g_icu_text_direction == RIGHT_TO_LEFT;
+}
+
+TextDirection GetTextDirectionForLocale(const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
+  DCHECK(U_SUCCESS(status));
+  // Treat anything other than RTL as LTR.
+  return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
+}
+
+TextDirection GetFirstStrongCharacterDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+    TextDirection direction = GetCharacterDirection(character);
+    if (direction != UNKNOWN_DIRECTION)
+      return direction;
+    position = next_position;
+  }
+  return LEFT_TO_RIGHT;
+}
+
+TextDirection GetLastStrongCharacterDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t position = text.length();
+  while (position > 0) {
+    UChar32 character;
+    size_t prev_position = position;
+    U16_PREV(string, 0, prev_position, character);
+    TextDirection direction = GetCharacterDirection(character);
+    if (direction != UNKNOWN_DIRECTION)
+      return direction;
+    position = prev_position;
+  }
+  return LEFT_TO_RIGHT;
+}
+
+TextDirection GetStringDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+
+  TextDirection result(UNKNOWN_DIRECTION);
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+    TextDirection direction = GetCharacterDirection(character);
+    if (direction != UNKNOWN_DIRECTION) {
+      if (result != UNKNOWN_DIRECTION && result != direction)
+        return UNKNOWN_DIRECTION;
+      result = direction;
+    }
+    position = next_position;
+  }
+
+  // Handle the case of a string not containing any strong directionality
+  // characters defaulting to LEFT_TO_RIGHT.
+  if (result == UNKNOWN_DIRECTION)
+    return LEFT_TO_RIGHT;
+
+  return result;
+}
+
+#if defined(OS_WIN)
+bool AdjustStringForLocaleDirection(string16* text) {
+  if (!IsRTL() || text->empty())
+    return false;
+
+  // Marking the string as LTR if the locale is RTL and the string does not
+  // contain strong RTL characters. Otherwise, mark the string as RTL.
+  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+  if (!has_rtl_chars)
+    WrapStringWithLTRFormatting(text);
+  else
+    WrapStringWithRTLFormatting(text);
+
+  return true;
+}
+
+bool UnadjustStringForLocaleDirection(string16* text) {
+  if (!IsRTL() || text->empty())
+    return false;
+
+  *text = StripWrappingBidiControlCharacters(*text);
+  return true;
+}
+#else
+bool AdjustStringForLocaleDirection(string16* text) {
+  // On OS X & GTK the directionality of a label is determined by the first
+  // strongly directional character.
+  // However, we want to make sure that in an LTR-language-UI all strings are
+  // left aligned and vice versa.
+  // A problem can arise if we display a string which starts with user input.
+  // User input may be of the opposite directionality to the UI. So the whole
+  // string will be displayed in the opposite directionality, e.g. if we want to
+  // display in an LTR UI [such as US English]:
+  //
+  // EMAN_NOISNETXE is now installed.
+  //
+  // Since EXTENSION_NAME begins with a strong RTL char, the label's
+  // directionality will be set to RTL and the string will be displayed visually
+  // as:
+  //
+  // .is now installed EMAN_NOISNETXE
+  //
+  // In order to solve this issue, we prepend an LRM to the string. An LRM is a
+  // strongly directional LTR char.
+  // We also append an LRM at the end, which ensures that we're in an LTR
+  // context.
+
+  // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the
+  // box so there is no issue with displaying zero-width bidi control characters
+  // on any system.  Thus no need for the !IsRTL() check here.
+  if (text->empty())
+    return false;
+
+  bool ui_direction_is_rtl = IsRTL();
+
+  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+  if (!ui_direction_is_rtl && has_rtl_chars) {
+    WrapStringWithRTLFormatting(text);
+    text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+                 kLeftToRightMark);
+    text->push_back(kLeftToRightMark);
+  } else if (ui_direction_is_rtl && has_rtl_chars) {
+    WrapStringWithRTLFormatting(text);
+    text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+                 kRightToLeftMark);
+    text->push_back(kRightToLeftMark);
+  } else if (ui_direction_is_rtl) {
+    WrapStringWithLTRFormatting(text);
+    text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+                 kRightToLeftMark);
+    text->push_back(kRightToLeftMark);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool UnadjustStringForLocaleDirection(string16* text) {
+  if (text->empty())
+    return false;
+
+  size_t begin_index = 0;
+  char16 begin = text->at(begin_index);
+  if (begin == kLeftToRightMark ||
+      begin == kRightToLeftMark) {
+    ++begin_index;
+  }
+
+  size_t end_index = text->length() - 1;
+  char16 end = text->at(end_index);
+  if (end == kLeftToRightMark ||
+      end == kRightToLeftMark) {
+    --end_index;
+  }
+
+  string16 unmarked_text =
+      text->substr(begin_index, end_index - begin_index + 1);
+  *text = StripWrappingBidiControlCharacters(unmarked_text);
+  return true;
+}
+
+#endif  // !OS_WIN
+
+bool StringContainsStrongRTLChars(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+
+    // Now that we have the character, we use ICU in order to query for the
+    // appropriate Unicode BiDi character type.
+    int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+    if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC))
+      return true;
+
+    position = next_position;
+  }
+
+  return false;
+}
+
+void WrapStringWithLTRFormatting(string16* text) {
+  if (text->empty())
+    return;
+
+  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+  text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+               kLeftToRightEmbeddingMark);
+
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  text->push_back(kPopDirectionalFormatting);
+}
+
+void WrapStringWithRTLFormatting(string16* text) {
+  if (text->empty())
+    return;
+
+  // Inserting an RLE (Right-To-Left Embedding) mark as the first character.
+  text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+               kRightToLeftEmbeddingMark);
+
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  text->push_back(kPopDirectionalFormatting);
+}
+
+void WrapPathWithLTRFormatting(const FilePath& path,
+                               string16* rtl_safe_path) {
+  // Wrap the overall path with LRE-PDF pair which essentialy marks the
+  // string as a Left-To-Right string.
+  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+  rtl_safe_path->push_back(kLeftToRightEmbeddingMark);
+#if defined(OS_MACOSX)
+    rtl_safe_path->append(UTF8ToUTF16(path.value()));
+#elif defined(OS_WIN)
+    rtl_safe_path->append(path.value());
+#else  // defined(OS_POSIX) && !defined(OS_MACOSX)
+    std::wstring wide_path = base::SysNativeMBToWide(path.value());
+    rtl_safe_path->append(WideToUTF16(wide_path));
+#endif
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  rtl_safe_path->push_back(kPopDirectionalFormatting);
+}
+
+string16 GetDisplayStringInLTRDirectionality(const string16& text) {
+  // Always wrap the string in RTL UI (it may be appended to RTL string).
+  // Also wrap strings with an RTL first strong character direction in LTR UI.
+  if (IsRTL() || GetFirstStrongCharacterDirection(text) == RIGHT_TO_LEFT) {
+    string16 text_mutable(text);
+    WrapStringWithLTRFormatting(&text_mutable);
+    return text_mutable;
+  }
+  return text;
+}
+
+string16 StripWrappingBidiControlCharacters(const string16& text) {
+  if (text.empty())
+    return text;
+  size_t begin_index = 0;
+  char16 begin = text[begin_index];
+  if (begin == kLeftToRightEmbeddingMark ||
+      begin == kRightToLeftEmbeddingMark ||
+      begin == kLeftToRightOverride ||
+      begin == kRightToLeftOverride)
+    ++begin_index;
+  size_t end_index = text.length() - 1;
+  if (text[end_index] == kPopDirectionalFormatting)
+    --end_index;
+  return text.substr(begin_index, end_index - begin_index + 1);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
new file mode 100644
index 0000000..9b9a0dc
--- /dev/null
+++ b/base/i18n/rtl.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_RTL_H_
+#define BASE_I18N_RTL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+namespace i18n {
+
+const char16 kRightToLeftMark = 0x200F;
+const char16 kLeftToRightMark = 0x200E;
+const char16 kLeftToRightEmbeddingMark = 0x202A;
+const char16 kRightToLeftEmbeddingMark = 0x202B;
+const char16 kPopDirectionalFormatting = 0x202C;
+const char16 kLeftToRightOverride = 0x202D;
+const char16 kRightToLeftOverride = 0x202E;
+
+// Locale.java mirrored this enum TextDirection. Please keep in sync.
+enum TextDirection {
+  UNKNOWN_DIRECTION = 0,
+  RIGHT_TO_LEFT = 1,
+  LEFT_TO_RIGHT = 2,
+  TEXT_DIRECTION_NUM_DIRECTIONS = 3,
+};
+
+// Get the locale that the currently running process has been configured to use.
+// The return value is of the form language[-country] (e.g., en-US) where the
+// language is the 2 or 3 letter code from ISO-639.
+BASE_I18N_EXPORT std::string GetConfiguredLocale();
+
+// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name.
+BASE_I18N_EXPORT std::string GetCanonicalLocale(const std::string& locale);
+
+// Sets the default locale of ICU.
+// Once the application locale of Chrome in GetApplicationLocale is determined,
+// the default locale of ICU need to be changed to match the application locale
+// so that ICU functions work correctly in a locale-dependent manner.
+// This is handy in that we don't have to call GetApplicationLocale()
+// everytime we call locale-dependent ICU APIs as long as we make sure
+// that this is called before any locale-dependent API is called.
+BASE_I18N_EXPORT void SetICUDefaultLocale(const std::string& locale_string);
+
+// Returns true if the application text direction is right-to-left.
+BASE_I18N_EXPORT bool IsRTL();
+
+// Returns whether the text direction for the default ICU locale is RTL.  This
+// assumes that SetICUDefaultLocale has been called to set the default locale to
+// the UI locale of Chrome.
+// NOTE: Generally, you should call IsRTL() instead of this.
+BASE_I18N_EXPORT bool ICUIsRTL();
+
+// Returns the text direction for |locale_name|.
+BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale(
+    const char* locale_name);
+
+// Given the string in |text|, returns the directionality of the first or last
+// character with strong directionality in the string. If no character in the
+// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi
+// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong
+// directionality characters. Please refer to http://unicode.org/reports/tr9/
+// for more information.
+BASE_I18N_EXPORT TextDirection GetFirstStrongCharacterDirection(
+    const string16& text);
+BASE_I18N_EXPORT TextDirection GetLastStrongCharacterDirection(
+    const string16& text);
+
+// Given the string in |text|, returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if all the
+// strong directionality characters in the string are of the same
+// directionality. It returns UNKNOWN_DIRECTION if the string contains a mix of
+// LTR and RTL strong directionality characters. Defaults to LEFT_TO_RIGHT if
+// the string does not contain directionality characters. Please refer to
+// http://unicode.org/reports/tr9/ for more information.
+BASE_I18N_EXPORT TextDirection GetStringDirection(const string16& text);
+
+// Given the string in |text|, this function modifies the string in place with
+// the appropriate Unicode formatting marks that mark the string direction
+// (either left-to-right or right-to-left). The function checks both the current
+// locale and the contents of the string in order to determine the direction of
+// the returned string. The function returns true if the string in |text| was
+// properly adjusted.
+//
+// Certain LTR strings are not rendered correctly when the context is RTL. For
+// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in
+// an RTL context. Calling this function will make sure the returned localized
+// string is always treated as a right-to-left string. This is done by
+// inserting certain Unicode formatting marks into the returned string.
+//
+// ** Notes about the Windows version of this function:
+// TODO(idana) bug 6806: this function adjusts the string in question only
+// if the current locale is right-to-left. The function does not take care of
+// the opposite case (an RTL string displayed in an LTR context) since
+// adjusting the string involves inserting Unicode formatting characters that
+// Windows does not handle well unless right-to-left language support is
+// installed. Since the English version of Windows doesn't have right-to-left
+// language support installed by default, inserting the direction Unicode mark
+// results in Windows displaying squares.
+BASE_I18N_EXPORT bool AdjustStringForLocaleDirection(string16* text);
+
+// Undoes the actions of the above function (AdjustStringForLocaleDirection).
+BASE_I18N_EXPORT bool UnadjustStringForLocaleDirection(string16* text);
+
+// Returns true if the string contains at least one character with strong right
+// to left directionality; that is, a character with either R or AL Unicode
+// BiDi character type.
+BASE_I18N_EXPORT bool StringContainsStrongRTLChars(const string16& text);
+
+// Wraps a string with an LRE-PDF pair which essentialy marks the string as a
+// Left-To-Right string. Doing this is useful in order to make sure LTR
+// strings are rendered properly in an RTL context.
+BASE_I18N_EXPORT void WrapStringWithLTRFormatting(string16* text);
+
+// Wraps a string with an RLE-PDF pair which essentialy marks the string as a
+// Right-To-Left string. Doing this is useful in order to make sure RTL
+// strings are rendered properly in an LTR context.
+BASE_I18N_EXPORT void WrapStringWithRTLFormatting(string16* text);
+
+// Wraps file path to get it to display correctly in RTL UI. All filepaths
+// should be passed through this function before display in UI for RTL locales.
+BASE_I18N_EXPORT void WrapPathWithLTRFormatting(const FilePath& path,
+                                                string16* rtl_safe_path);
+
+// Return the string in |text| wrapped with LRE (Left-To-Right Embedding) and
+// PDF (Pop Directional Formatting) marks, if needed for UI display purposes.
+BASE_I18N_EXPORT string16 GetDisplayStringInLTRDirectionality(
+    const string16& text) WARN_UNUSED_RESULT;
+
+// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C)
+// explicit bidi control characters from |text|, if there are any. Otherwise,
+// return the text itself. Explicit bidi control characters display and have
+// semantic effect. They can be deleted so they might not always appear in a
+// pair.
+BASE_I18N_EXPORT string16 StripWrappingBidiControlCharacters(
+    const string16& text) WARN_UNUSED_RESULT;
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_RTL_H_
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc
new file mode 100644
index 0000000..87ac87d
--- /dev/null
+++ b/base/i18n/rtl_unittest.cc
@@ -0,0 +1,441 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/rtl.h"
+
+#include <algorithm>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+namespace {
+
+// A test utility function to set the application default text direction.
+void SetRTL(bool rtl) {
+  // Override the current locale/direction.
+  SetICUDefaultLocale(rtl ? "he" : "en");
+  EXPECT_EQ(rtl, IsRTL());
+}
+
+}  // namespace
+
+class RTLTest : public PlatformTest {
+};
+
+TEST_F(RTLTest, GetFirstStrongCharacterDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foo bar", LEFT_TO_RIGHT },
+    // Test pure RTL string.
+    { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT},
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type L.
+    { L"foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type R.
+    { L"\x05d0 foo bar", RIGHT_TO_LEFT },
+    // Test bidi string which starts with a character with weak directionality
+    // and in which the first character with strong directionality is a
+    // character with type L.
+    { L"!foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string which starts with a character with weak directionality
+    // and in which the first character with strong directionality is a
+    // character with type R.
+    { L",\x05d0 foo bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type LRE.
+    { L"\x202a \x05d0 foo  bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type LRO.
+    { L"\x202d \x05d0 foo  bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type RLE.
+    { L"\x202b foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type RLO.
+    { L"\x202e foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type AL.
+    { L"\x0622 foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+    // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+    // information).
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10910" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd802\xdd10" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      RIGHT_TO_LEFT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10401" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd801\xdc01" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetFirstStrongCharacterDirection(WideToUTF16(cases[i].text)));
+}
+
+
+// Note that the cases with LRE, LRO, RLE and RLO are invalid for
+// GetLastStrongCharacterDirection because they should be followed by PDF
+// character.
+TEST_F(RTLTest, GetLastStrongCharacterDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foo bar", LEFT_TO_RIGHT },
+    // Test pure RTL string.
+    { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT},
+    // Test bidi string in which the last character with strong directionality
+    // is a character with type L.
+    { L"foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the last character with strong directionality
+    // is a character with type R.
+    { L"\x05d0 foo bar \x05d3", RIGHT_TO_LEFT },
+    // Test bidi string which ends with a character with weak directionality
+    // and in which the last character with strong directionality is a
+    // character with type L.
+    { L"!foo \x05d0 bar!", LEFT_TO_RIGHT },
+    // Test bidi string which ends with a character with weak directionality
+    // and in which the last character with strong directionality is a
+    // character with type R.
+    { L",\x05d0 foo bar \x05d1,", RIGHT_TO_LEFT },
+    // Test bidi string in which the last character with strong directionality
+    // is a character with type AL.
+    { L"\x0622 foo \x05d0 bar \x0622", RIGHT_TO_LEFT },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+    // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+    // information).
+    {
+#if defined(WCHAR_T_IS_UTF32)
+       L"abc 123" L" ! \x10910 !",
+#elif defined(WCHAR_T_IS_UTF16)
+       L"abc 123" L" ! \xd802\xdd10 !",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      RIGHT_TO_LEFT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+       L"abc 123" L" ! \x10401 !",
+#elif defined(WCHAR_T_IS_UTF16)
+       L"abc 123" L" ! \xd801\xdc01 !",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetLastStrongCharacterDirection(WideToUTF16(cases[i].text)));
+}
+
+TEST_F(RTLTest, GetStringDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foobar", LEFT_TO_RIGHT },
+    { L".foobar", LEFT_TO_RIGHT },
+    { L"foo, bar", LEFT_TO_RIGHT },
+    // Test pure LTR with strong directionality characters of type LRE.
+    { L"\x202a\x202a", LEFT_TO_RIGHT },
+    { L".\x202a\x202a", LEFT_TO_RIGHT },
+    { L"\x202a, \x202a", LEFT_TO_RIGHT },
+    // Test pure LTR with strong directionality characters of type LRO.
+    { L"\x202d\x202d", LEFT_TO_RIGHT },
+    { L".\x202d\x202d", LEFT_TO_RIGHT },
+    { L"\x202d, \x202d", LEFT_TO_RIGHT },
+    // Test pure LTR with various types of strong directionality characters.
+    { L"foo \x202a\x202d", LEFT_TO_RIGHT },
+    { L".\x202d foo \x202a", LEFT_TO_RIGHT },
+    { L"\x202a, \x202d foo", LEFT_TO_RIGHT },
+    // Test pure RTL with strong directionality characters of type R.
+    { L"\x05d0\x05d0", RIGHT_TO_LEFT },
+    { L".\x05d0\x05d0", RIGHT_TO_LEFT },
+    { L"\x05d0, \x05d0", RIGHT_TO_LEFT },
+    // Test pure RTL with strong directionality characters of type RLE.
+    { L"\x202b\x202b", RIGHT_TO_LEFT },
+    { L".\x202b\x202b", RIGHT_TO_LEFT },
+    { L"\x202b, \x202b", RIGHT_TO_LEFT },
+    // Test pure RTL with strong directionality characters of type RLO.
+    { L"\x202e\x202e", RIGHT_TO_LEFT },
+    { L".\x202e\x202e", RIGHT_TO_LEFT },
+    { L"\x202e, \x202e", RIGHT_TO_LEFT },
+    // Test pure RTL with strong directionality characters of type AL.
+    { L"\x0622\x0622", RIGHT_TO_LEFT },
+    { L".\x0622\x0622", RIGHT_TO_LEFT },
+    { L"\x0622, \x0622", RIGHT_TO_LEFT },
+    // Test pure RTL with various types of strong directionality characters.
+    { L"\x05d0\x202b\x202e\x0622", RIGHT_TO_LEFT },
+    { L".\x202b\x202e\x0622\x05d0", RIGHT_TO_LEFT },
+    { L"\x0622\x202e, \x202b\x05d0", RIGHT_TO_LEFT },
+    // Test bidi strings.
+    { L"foo \x05d0 bar", UNKNOWN_DIRECTION },
+    { L"\x202b foo bar", UNKNOWN_DIRECTION },
+    { L"!foo \x0622 bar", UNKNOWN_DIRECTION },
+    { L"\x202a\x202b", UNKNOWN_DIRECTION },
+    { L"\x202e\x202d", UNKNOWN_DIRECTION },
+    { L"\x0622\x202a", UNKNOWN_DIRECTION },
+    { L"\x202d\x05d0", UNKNOWN_DIRECTION },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10910" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd802\xdd10" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      UNKNOWN_DIRECTION },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10401" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd801\xdc01" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetStringDirection(WideToUTF16(cases[i].text)));
+}
+
+TEST_F(RTLTest, WrapPathWithLTRFormatting) {
+  const wchar_t* cases[] = {
+    // Test common path, such as "c:\foo\bar".
+    L"c:/foo/bar",
+    // Test path with file name, such as "c:\foo\bar\test.jpg".
+    L"c:/foo/bar/test.jpg",
+    // Test path ending with punctuation, such as "c:\(foo)\bar.".
+    L"c:/(foo)/bar.",
+    // Test path ending with separator, such as "c:\foo\bar\".
+    L"c:/foo/bar/",
+    // Test path with RTL character.
+    L"c:/\x05d0",
+    // Test path with 2 level RTL directory names.
+    L"c:/\x05d0/\x0622",
+    // Test path with mixed RTL/LTR directory names and ending with punctuation.
+    L"c:/\x05d0/\x0622/(foo)/b.a.r.",
+    // Test path without driver name, such as "/foo/bar/test/jpg".
+    L"/foo/bar/test.jpg",
+    // Test path start with current directory, such as "./foo".
+    L"./foo",
+    // Test path start with parent directory, such as "../foo/bar.jpg".
+    L"../foo/bar.jpg",
+    // Test absolute path, such as "//foo/bar.jpg".
+    L"//foo/bar.jpg",
+    // Test path with mixed RTL/LTR directory names.
+    L"c:/foo/\x05d0/\x0622/\x05d1.jpg",
+    // Test empty path.
+    L""
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath path;
+#if defined(OS_WIN)
+    std::wstring win_path(cases[i]);
+    std::replace(win_path.begin(), win_path.end(), '/', '\\');
+    path = FilePath(win_path);
+    std::wstring wrapped_expected =
+        std::wstring(L"\x202a") + win_path + L"\x202c";
+#else
+    path = FilePath(base::SysWideToNativeMB(cases[i]));
+    std::wstring wrapped_expected =
+        std::wstring(L"\x202a") + cases[i] + L"\x202c";
+#endif
+    string16 localized_file_path_string;
+    WrapPathWithLTRFormatting(path, &localized_file_path_string);
+
+    std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string);
+    EXPECT_EQ(wrapped_expected, wrapped_actual);
+  }
+}
+
+TEST_F(RTLTest, WrapString) {
+  const wchar_t* cases[] = {
+    L" . ",
+    L"abc",
+    L"a" L"\x5d0\x5d1",
+    L"a" L"\x5d1" L"b",
+    L"\x5d0\x5d1\x5d2",
+    L"\x5d0\x5d1" L"a",
+    L"\x5d0" L"a" L"\x5d1",
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+
+    string16 empty;
+    WrapStringWithLTRFormatting(&empty);
+    EXPECT_TRUE(empty.empty());
+    WrapStringWithRTLFormatting(&empty);
+    EXPECT_TRUE(empty.empty());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 input = WideToUTF16(cases[i]);
+      string16 ltr_wrap = input;
+      WrapStringWithLTRFormatting(&ltr_wrap);
+      EXPECT_EQ(ltr_wrap[0], kLeftToRightEmbeddingMark);
+      EXPECT_EQ(ltr_wrap.substr(1, ltr_wrap.length() - 2), input);
+      EXPECT_EQ(ltr_wrap[ltr_wrap.length() -1], kPopDirectionalFormatting);
+
+      string16 rtl_wrap = input;
+      WrapStringWithRTLFormatting(&rtl_wrap);
+      EXPECT_EQ(rtl_wrap[0], kRightToLeftEmbeddingMark);
+      EXPECT_EQ(rtl_wrap.substr(1, rtl_wrap.length() - 2), input);
+      EXPECT_EQ(rtl_wrap[rtl_wrap.length() -1], kPopDirectionalFormatting);
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) {
+  struct {
+    const wchar_t* path;
+    bool wrap_ltr;
+    bool wrap_rtl;
+  } cases[] = {
+    { L"test",                   false, true },
+    { L"test.html",              false, true },
+    { L"\x05d0\x05d1\x05d2",     true,  true },
+    { L"\x05d0\x05d1\x05d2.txt", true,  true },
+    { L"\x05d0" L"abc",          true,  true },
+    { L"\x05d0" L"abc.txt",      true,  true },
+    { L"abc\x05d0\x05d1",        false, true },
+    { L"abc\x05d0\x05d1.jpg",    false, true },
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 input = WideToUTF16(cases[i].path);
+      string16 output = GetDisplayStringInLTRDirectionality(input);
+      // Test the expected wrapping behavior for the current UI directionality.
+      if (IsRTL() ? cases[i].wrap_rtl : cases[i].wrap_ltr)
+        EXPECT_NE(output, input);
+      else
+        EXPECT_EQ(output, input);
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+TEST_F(RTLTest, GetTextDirection) {
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar_EG"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he_IL"));
+  // iw is an obsolete code for Hebrew.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("iw"));
+  // Although we're not yet localized to Farsi and Urdu, we
+  // do have the text layout direction information for them.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("fa"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ur"));
+#if 0
+  // Enable these when we include the minimal locale data for Azerbaijani
+  // written in Arabic and Dhivehi. At the moment, our copy of
+  // ICU data does not have entries for them.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("az_Arab"));
+  // Dhivehi that uses Thaana script.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("dv"));
+#endif
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("en"));
+  // Chinese in China with '-'.
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("zh-CN"));
+  // Filipino : 3-letter code
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("fil"));
+  // Russian
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ru"));
+  // Japanese that uses multiple scripts
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja"));
+}
+
+TEST_F(RTLTest, UnadjustStringForLocaleDirection) {
+  // These test strings are borrowed from WrapPathWithLTRFormatting
+  const wchar_t* cases[] = {
+    L"foo bar",
+    L"foo \x05d0 bar",
+    L"\x05d0 foo bar",
+    L"!foo \x05d0 bar",
+    L",\x05d0 foo bar",
+    L"\x202a \x05d0 foo  bar",
+    L"\x202d \x05d0 foo  bar",
+    L"\x202b foo \x05d0 bar",
+    L"\x202e foo \x05d0 bar",
+    L"\x0622 foo \x05d0 bar",
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 test_case = WideToUTF16(cases[i]);
+      string16 adjusted_string = test_case;
+
+      if (!AdjustStringForLocaleDirection(&adjusted_string))
+        continue;
+
+      EXPECT_NE(test_case, adjusted_string);
+      EXPECT_TRUE(UnadjustStringForLocaleDirection(&adjusted_string));
+      EXPECT_EQ(test_case, adjusted_string) << " for test case [" << test_case
+                                            << "] with IsRTL() == " << IsRTL();
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/streaming_utf8_validator.cc b/base/i18n/streaming_utf8_validator.cc
new file mode 100644
index 0000000..c809985
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator.cc
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This implementation doesn't use ICU. The ICU macros are oriented towards
+// character-at-a-time processing, whereas byte-at-a-time processing is easier
+// with streaming input.
+
+#include "base/i18n/streaming_utf8_validator.h"
+
+#include "base/i18n/utf8_validator_tables.h"
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+uint8 StateTableLookup(uint8 offset) {
+  DCHECK_LT(offset, internal::kUtf8ValidatorTablesSize);
+  return internal::kUtf8ValidatorTables[offset];
+}
+
+}  // namespace
+
+StreamingUtf8Validator::State StreamingUtf8Validator::AddBytes(const char* data,
+                                                               size_t size) {
+  // Copy |state_| into a local variable so that the compiler doesn't have to be
+  // careful of aliasing.
+  uint8 state = state_;
+  for (const char* p = data; p != data + size; ++p) {
+    if ((*p & 0x80) == 0) {
+      if (state == 0)
+        continue;
+      state = internal::I18N_UTF8_VALIDATOR_INVALID_INDEX;
+      break;
+    }
+    const uint8 shift_amount = StateTableLookup(state);
+    const uint8 shifted_char = (*p & 0x7F) >> shift_amount;
+    state = StateTableLookup(state + shifted_char + 1);
+    // State may be INVALID here, but this code is optimised for the case of
+    // valid UTF-8 and it is more efficient (by about 2%) to not attempt an
+    // early loop exit unless we hit an ASCII character.
+  }
+  state_ = state;
+  return state == 0 ? VALID_ENDPOINT
+      : state == internal::I18N_UTF8_VALIDATOR_INVALID_INDEX
+      ? INVALID
+      : VALID_MIDPOINT;
+}
+
+void StreamingUtf8Validator::Reset() {
+  state_ = 0u;
+}
+
+bool StreamingUtf8Validator::Validate(const std::string& string) {
+  return StreamingUtf8Validator().AddBytes(string.data(), string.size()) ==
+         VALID_ENDPOINT;
+}
+
+}  // namespace base
diff --git a/base/i18n/streaming_utf8_validator.h b/base/i18n/streaming_utf8_validator.h
new file mode 100644
index 0000000..f10ac72
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A streaming validator for UTF-8. Validation is based on the definition in
+// RFC-3629. In particular, it does not reject the invalid characters rejected
+// by base::IsStringUTF8().
+//
+// The implementation detects errors on the first possible byte.
+
+#ifndef BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
+#define BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+class BASE_I18N_EXPORT StreamingUtf8Validator {
+ public:
+  // The validator exposes 3 states. It starts in state VALID_ENDPOINT. As it
+  // processes characters it alternates between VALID_ENDPOINT and
+  // VALID_MIDPOINT. If it encounters an invalid byte or UTF-8 sequence the
+  // state changes permanently to INVALID.
+  enum State {
+    VALID_ENDPOINT,
+    VALID_MIDPOINT,
+    INVALID
+  };
+
+  StreamingUtf8Validator() : state_(0u) {}
+  // Trivial destructor intentionally omitted.
+
+  // Validate |size| bytes starting at |data|. If the concatenation of all calls
+  // to AddBytes() since this object was constructed or reset is a valid UTF-8
+  // string, returns VALID_ENDPOINT. If it could be the prefix of a valid UTF-8
+  // string, returns VALID_MIDPOINT. If an invalid byte or UTF-8 sequence was
+  // present, returns INVALID.
+  State AddBytes(const char* data, size_t size);
+
+  // Return the object to a freshly-constructed state so that it can be re-used.
+  void Reset();
+
+  // Validate a complete string using the same criteria. Returns true if the
+  // string only contains complete, valid UTF-8 codepoints.
+  static bool Validate(const std::string& string);
+
+ private:
+  // The current state of the validator. Value 0 is the initial/valid state.
+  // The state is stored as an offset into |kUtf8ValidatorTables|. The special
+  // state |kUtf8InvalidState| is invalid.
+  uint8 state_;
+
+  // This type could be made copyable but there is currently no use-case for
+  // it.
+  DISALLOW_COPY_AND_ASSIGN(StreamingUtf8Validator);
+};
+
+}  // namespace base
+
+#endif  // BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
diff --git a/base/i18n/streaming_utf8_validator_perftest.cc b/base/i18n/streaming_utf8_validator_perftest.cc
new file mode 100644
index 0000000..6b8c17b
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator_perftest.cc
@@ -0,0 +1,238 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// All data that is passed through a WebSocket with type "Text" needs to be
+// validated as UTF8. Since this is done on the IO thread, it needs to be
+// reasonably fast.
+
+// We are only interested in the performance on valid UTF8. Invalid UTF8 will
+// result in a connection failure, so is unlikely to become a source of
+// performance issues.
+
+#include "base/i18n/streaming_utf8_validator.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/perf_time_logger.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// We want to test ranges of valid UTF-8 sequences. These ranges are inclusive.
+// They are intended to be large enough that the validator needs to do
+// meaningful work while being in some sense "realistic" (eg. control characters
+// are not included).
+const char kOneByteSeqRangeStart[] = " ";  // U+0020
+const char kOneByteSeqRangeEnd[] = "~";    // U+007E
+
+const char kTwoByteSeqRangeStart[] = "\xc2\xa0";  // U+00A0 non-breaking space
+const char kTwoByteSeqRangeEnd[] = "\xc9\x8f";    // U+024F small y with stroke
+
+const char kThreeByteSeqRangeStart[] = "\xe3\x81\x82";  // U+3042 Hiragana "a"
+const char kThreeByteSeqRangeEnd[] = "\xe9\xbf\x83";    // U+9FC3 "to blink"
+
+const char kFourByteSeqRangeStart[] = "\xf0\xa0\x80\x8b";  // U+2000B
+const char kFourByteSeqRangeEnd[] = "\xf0\xaa\x9a\xb2";    // U+2A6B2
+
+// The different lengths of strings to test.
+const size_t kTestLengths[] = {1, 32, 256, 32768, 1 << 20};
+
+// Simplest possible byte-at-a-time validator, to provide a baseline
+// for comparison. This is only tried on 1-byte UTF-8 sequences, as
+// the results will not be meaningful with sequences containing
+// top-bit-set bytes.
+bool IsString7Bit(const std::string& s) {
+  for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
+    if (*it & 0x80)
+      return false;
+  }
+  return true;
+}
+
+// Assumes that |previous| is a valid UTF-8 sequence, and attempts to return
+// the next one. Is just barely smart enough to iterate through the ranges
+// defined about.
+std::string NextUtf8Sequence(const std::string& previous) {
+  DCHECK(StreamingUtf8Validator::Validate(previous));
+  std::string next = previous;
+  for (int i = static_cast<int>(previous.length() - 1); i >= 0; --i) {
+    // All bytes in a UTF-8 sequence except the first one are
+    // constrained to the range 0x80 to 0xbf, inclusive. When we
+    // increment past 0xbf, we carry into the previous byte.
+    if (i > 0 && next[i] == '\xbf') {
+      next[i] = '\x80';
+      continue;  // carry
+    }
+    ++next[i];
+    break;  // no carry
+  }
+  DCHECK(StreamingUtf8Validator::Validate(next))
+      << "Result \"" << next << "\" failed validation";
+  return next;
+}
+
+typedef bool (*TestTargetType)(const std::string&);
+
+// Run fuction |target| over |test_string| |times| times, and report the results
+// using |description|.
+bool RunTest(const std::string& description,
+             TestTargetType target,
+             const std::string& test_string,
+             int times) {
+  base::PerfTimeLogger timer(description.c_str());
+  bool result = true;
+  for (int i = 0; i < times; ++i) {
+    result = target(test_string) && result;
+  }
+  timer.Done();
+  return result;
+}
+
+// Construct a string by repeating |input| enough times to equal or exceed
+// |length|.
+std::string ConstructRepeatedTestString(const std::string& input,
+                                        size_t length) {
+  std::string output = input;
+  while (output.length() * 2 < length) {
+    output += output;
+  }
+  if (output.length() < length) {
+    output += ConstructRepeatedTestString(input, length - output.length());
+  }
+  return output;
+}
+
+// Construct a string by expanding the range of UTF-8 sequences
+// between |input_start| and |input_end|, inclusive, and then
+// repeating the resulting string until it equals or exceeds |length|
+// bytes. |input_start| and |input_end| must be valid UTF-8
+// sequences.
+std::string ConstructRangedTestString(const std::string& input_start,
+                                      const std::string& input_end,
+                                      size_t length) {
+  std::string output = input_start;
+  std::string input = input_start;
+  while (output.length() < length && input != input_end) {
+    input = NextUtf8Sequence(input);
+    output += input;
+  }
+  if (output.length() < length) {
+    output = ConstructRepeatedTestString(output, length);
+  }
+  return output;
+}
+
+struct TestFunctionDescription {
+  TestTargetType function;
+  const char* function_name;
+};
+
+bool IsStringUTF8(const std::string& str) {
+  return base::IsStringUTF8(base::StringPiece(str));
+}
+
+// IsString7Bit is intentionally placed last so it can be excluded easily.
+const TestFunctionDescription kTestFunctions[] = {
+    {&StreamingUtf8Validator::Validate, "StreamingUtf8Validator"},
+    {&IsStringUTF8, "IsStringUTF8"}, {&IsString7Bit, "IsString7Bit"}};
+
+// Construct a test string from |construct_test_string| for each of the lengths
+// in |kTestLengths| in turn. For each string, run each test in |test_functions|
+// for a number of iterations such that the total number of bytes validated
+// is around 16MB.
+void RunSomeTests(
+    const char format[],
+    base::Callback<std::string(size_t length)> construct_test_string,
+    const TestFunctionDescription* test_functions,
+    size_t test_count) {
+  for (size_t i = 0; i < arraysize(kTestLengths); ++i) {
+    const size_t length = kTestLengths[i];
+    const std::string test_string = construct_test_string.Run(length);
+    const int real_length = static_cast<int>(test_string.length());
+    const int times = (1 << 24) / real_length;
+    for (size_t test_index = 0; test_index < test_count; ++test_index) {
+      EXPECT_TRUE(RunTest(StringPrintf(format,
+                                       test_functions[test_index].function_name,
+                                       real_length,
+                                       times),
+                          test_functions[test_index].function,
+                          test_string,
+                          times));
+    }
+  }
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, OneByteRepeated) {
+  RunSomeTests("%s: bytes=1 repeated length=%d repeat=%d",
+               base::Bind(ConstructRepeatedTestString, kOneByteSeqRangeStart),
+               kTestFunctions,
+               3);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, OneByteRange) {
+  RunSomeTests("%s: bytes=1 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kOneByteSeqRangeStart,
+                          kOneByteSeqRangeEnd),
+               kTestFunctions,
+               3);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, TwoByteRepeated) {
+  RunSomeTests("%s: bytes=2 repeated length=%d repeat=%d",
+               base::Bind(ConstructRepeatedTestString, kTwoByteSeqRangeStart),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, TwoByteRange) {
+  RunSomeTests("%s: bytes=2 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kTwoByteSeqRangeStart,
+                          kTwoByteSeqRangeEnd),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRepeated) {
+  RunSomeTests(
+      "%s: bytes=3 repeated length=%d repeat=%d",
+      base::Bind(ConstructRepeatedTestString, kThreeByteSeqRangeStart),
+      kTestFunctions,
+      2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRange) {
+  RunSomeTests("%s: bytes=3 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kThreeByteSeqRangeStart,
+                          kThreeByteSeqRangeEnd),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, FourByteRepeated) {
+  RunSomeTests("%s: bytes=4 repeated length=%d repeat=%d",
+               base::Bind(ConstructRepeatedTestString, kFourByteSeqRangeStart),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, FourByteRange) {
+  RunSomeTests("%s: bytes=4 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kFourByteSeqRangeStart,
+                          kFourByteSeqRangeEnd),
+               kTestFunctions,
+               2);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/streaming_utf8_validator_unittest.cc b/base/i18n/streaming_utf8_validator_unittest.cc
new file mode 100644
index 0000000..20ea564
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator_unittest.cc
@@ -0,0 +1,412 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/streaming_utf8_validator.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Define BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST to verify that this class
+// accepts exactly the same set of 4-byte strings as ICU-based validation. This
+// tests every possible 4-byte string, so it is too slow to run routinely on
+// low-powered machines.
+//
+// #define BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "third_party/icu/source/common/unicode/utf8.h"
+
+#endif  // BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+namespace base {
+namespace {
+
+// Avoid having to qualify the enum values in the tests.
+const StreamingUtf8Validator::State VALID_ENDPOINT =
+    StreamingUtf8Validator::VALID_ENDPOINT;
+const StreamingUtf8Validator::State VALID_MIDPOINT =
+    StreamingUtf8Validator::VALID_MIDPOINT;
+const StreamingUtf8Validator::State INVALID = StreamingUtf8Validator::INVALID;
+
+#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+const uint32 kThoroughTestChunkSize = 1 << 24;
+
+class StreamingUtf8ValidatorThoroughTest : public ::testing::Test {
+ protected:
+  StreamingUtf8ValidatorThoroughTest()
+      : all_done_(&lock_), tasks_dispatched_(0), tasks_finished_(0) {}
+
+  // This uses the same logic as base::IsStringUTF8 except it considers
+  // non-characters valid (and doesn't require a string as input).
+  static bool IsStringUtf8(const char* src, int32 src_len) {
+    int32 char_index = 0;
+
+    while (char_index < src_len) {
+      int32 code_point;
+      U8_NEXT(src, char_index, src_len, code_point);
+      if (!base::IsValidCodepoint(code_point))
+        return false;
+    }
+    return true;
+  }
+
+  // Converts the passed-in integer to a 4 byte string and then
+  // verifies that IsStringUtf8 and StreamingUtf8Validator agree on
+  // whether it is valid UTF-8 or not.
+  void TestNumber(uint32 n) const {
+    char test[sizeof n];
+    memcpy(test, &n, sizeof n);
+    StreamingUtf8Validator validator;
+    EXPECT_EQ(IsStringUtf8(test, sizeof n),
+              validator.AddBytes(test, sizeof n) == VALID_ENDPOINT)
+        << "Difference of opinion for \""
+        << base::StringPrintf("\\x%02X\\x%02X\\x%02X\\x%02X",
+                              test[0] & 0xFF,
+                              test[1] & 0xFF,
+                              test[2] & 0xFF,
+                              test[3] & 0xFF) << "\"";
+  }
+
+ public:
+  // Tests the 4-byte sequences corresponding to the |size| integers
+  // starting at |begin|. This is intended to be run from a worker
+  // pool. Signals |all_done_| at the end if it thinks all tasks are
+  // finished.
+  void TestRange(uint32 begin, uint32 size) {
+    for (uint32 i = 0; i < size; ++i) {
+      TestNumber(begin + i);
+    }
+    base::AutoLock al(lock_);
+    ++tasks_finished_;
+    LOG(INFO) << tasks_finished_ << " / " << tasks_dispatched_
+              << " tasks done\n";
+    if (tasks_finished_ >= tasks_dispatched_) {
+      all_done_.Signal();
+    }
+  }
+
+ protected:
+  base::Lock lock_;
+  base::ConditionVariable all_done_;
+  int tasks_dispatched_;
+  int tasks_finished_;
+};
+
+TEST_F(StreamingUtf8ValidatorThoroughTest, TestEverything) {
+  scoped_refptr<base::SequencedWorkerPool> pool =
+      new base::SequencedWorkerPool(32, "TestEverything");
+  base::AutoLock al(lock_);
+  uint32 begin = 0;
+  do {
+    pool->PostWorkerTask(
+        FROM_HERE,
+        base::Bind(&StreamingUtf8ValidatorThoroughTest::TestRange,
+                   base::Unretained(this),
+                   begin,
+                   kThoroughTestChunkSize));
+    ++tasks_dispatched_;
+    begin += kThoroughTestChunkSize;
+  } while (begin != 0);
+  while (tasks_finished_ < tasks_dispatched_)
+    all_done_.Wait();
+}
+
+#endif  // BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+// These valid and invalid UTF-8 sequences are based on the tests from
+// base/strings/string_util_unittest.cc
+
+// All of the strings in |valid| must represent a single codepoint, because
+// partial sequences are constructed by taking non-empty prefixes of these
+// strings.
+const char* const valid[] = {"\r",           "\n",           "a",
+                             "\xc2\x81",     "\xe1\x80\xbf", "\xf1\x80\xa0\xbf",
+                             "\xef\xbb\xbf",  // UTF-8 BOM
+};
+
+const char* const* const valid_end = valid + arraysize(valid);
+
+const char* const invalid[] = {
+    // always invalid bytes
+    "\xc0", "\xc1",
+    "\xf5", "\xf6", "\xf7",
+    "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff",
+    // surrogate code points
+    "\xed\xa0\x80", "\xed\x0a\x8f", "\xed\xbf\xbf",
+    //
+    // overlong sequences
+    "\xc0\x80"               // U+0000
+    "\xc1\x80",              // "A"
+    "\xc1\x81",              // "B"
+    "\xe0\x80\x80",          // U+0000
+    "\xe0\x82\x80",          // U+0080
+    "\xe0\x9f\xbf",          // U+07ff
+    "\xf0\x80\x80\x8D",      // U+000D
+    "\xf0\x80\x82\x91",      // U+0091
+    "\xf0\x80\xa0\x80",      // U+0800
+    "\xf0\x8f\xbb\xbf",      // U+FEFF (BOM)
+    "\xf8\x80\x80\x80\xbf",  // U+003F
+    "\xfc\x80\x80\x80\xa0\xa5",
+    //
+    // Beyond U+10FFFF
+    "\xf4\x90\x80\x80",          // U+110000
+    "\xf8\xa0\xbf\x80\xbf",      // 5 bytes
+    "\xfc\x9c\xbf\x80\xbf\x80",  // 6 bytes
+    //
+    // BOMs in UTF-16(BE|LE)
+    "\xfe\xff", "\xff\xfe",
+};
+
+const char* const* const invalid_end = invalid + arraysize(invalid);
+
+// A ForwardIterator which returns all the non-empty prefixes of the elements of
+// "valid".
+class PartialIterator {
+ public:
+  // The constructor returns the first iterator, ie. it is equivalent to
+  // begin().
+  PartialIterator() : index_(0), prefix_length_(0) { Advance(); }
+  // The trivial destructor left intentionally undefined.
+  // This is a value type; the default copy constructor and assignment operator
+  // generated by the compiler are used.
+
+  static PartialIterator end() { return PartialIterator(arraysize(valid), 1); }
+
+  PartialIterator& operator++() {
+    Advance();
+    return *this;
+  }
+
+  base::StringPiece operator*() const {
+    return base::StringPiece(valid[index_], prefix_length_);
+  }
+
+  bool operator==(const PartialIterator& rhs) const {
+    return index_ == rhs.index_ && prefix_length_ == rhs.prefix_length_;
+  }
+
+  bool operator!=(const PartialIterator& rhs) const { return !(rhs == *this); }
+
+ private:
+  // This constructor is used by the end() method.
+  PartialIterator(size_t index, size_t prefix_length)
+      : index_(index), prefix_length_(prefix_length) {}
+
+  void Advance() {
+    if (index_ < arraysize(valid) && prefix_length_ < strlen(valid[index_]))
+      ++prefix_length_;
+    while (index_ < arraysize(valid) &&
+           prefix_length_ == strlen(valid[index_])) {
+      ++index_;
+      prefix_length_ = 1;
+    }
+  }
+
+  // The UTF-8 sequence, as an offset into the |valid| array.
+  size_t index_;
+  size_t prefix_length_;
+};
+
+// A test fixture for tests which test one UTF-8 sequence (or invalid
+// byte sequence) at a time.
+class StreamingUtf8ValidatorSingleSequenceTest : public ::testing::Test {
+ protected:
+  // Iterator must be convertible when de-referenced to StringPiece.
+  template <typename Iterator>
+  void CheckRange(Iterator begin,
+                  Iterator end,
+                  StreamingUtf8Validator::State expected) {
+    for (Iterator it = begin; it != end; ++it) {
+      StreamingUtf8Validator validator;
+      base::StringPiece sequence = *it;
+      EXPECT_EQ(expected,
+                validator.AddBytes(sequence.data(), sequence.size()))
+          << "Failed for \"" << sequence << "\"";
+    }
+  }
+
+  // Adding input a byte at a time should make absolutely no difference.
+  template <typename Iterator>
+  void CheckRangeByteAtATime(Iterator begin,
+                             Iterator end,
+                             StreamingUtf8Validator::State expected) {
+    for (Iterator it = begin; it != end; ++it) {
+      StreamingUtf8Validator validator;
+      base::StringPiece sequence = *it;
+      StreamingUtf8Validator::State state = VALID_ENDPOINT;
+      for (base::StringPiece::const_iterator cit = sequence.begin();
+           cit != sequence.end();
+           ++cit) {
+        state = validator.AddBytes(&*cit, 1);
+      }
+      EXPECT_EQ(expected, state) << "Failed for \"" << sequence << "\"";
+    }
+  }
+};
+
+// A test fixture for tests which test the concatenation of byte sequences.
+class StreamingUtf8ValidatorDoubleSequenceTest : public ::testing::Test {
+ protected:
+  // Check every possible concatenation of byte sequences from two
+  // ranges, and verify that the combination matches the expected
+  // state.
+  template <typename Iterator1, typename Iterator2>
+  void CheckCombinations(Iterator1 begin1,
+                         Iterator1 end1,
+                         Iterator2 begin2,
+                         Iterator2 end2,
+                         StreamingUtf8Validator::State expected) {
+    StreamingUtf8Validator validator;
+    for (Iterator1 it1 = begin1; it1 != end1; ++it1) {
+      base::StringPiece c1 = *it1;
+      for (Iterator2 it2 = begin2; it2 != end2; ++it2) {
+        base::StringPiece c2 = *it2;
+        validator.AddBytes(c1.data(), c1.size());
+        EXPECT_EQ(expected, validator.AddBytes(c2.data(), c2.size()))
+            << "Failed for \"" << c1 << c2 << "\"";
+        validator.Reset();
+      }
+    }
+  }
+};
+
+TEST(StreamingUtf8ValidatorTest, NothingIsValid) {
+  static const char kNothing[] = "";
+  EXPECT_EQ(VALID_ENDPOINT, StreamingUtf8Validator().AddBytes(kNothing, 0));
+}
+
+// Because the members of the |valid| array need to be non-zero length
+// sequences and are measured with strlen(), |valid| cannot be used it
+// to test the NUL character '\0', so the NUL character gets its own
+// test.
+TEST(StreamingUtf8ValidatorTest, NulIsValid) {
+  static const char kNul[] = "\x00";
+  EXPECT_EQ(VALID_ENDPOINT, StreamingUtf8Validator().AddBytes(kNul, 1));
+}
+
+// Just a basic sanity test before we start getting fancy.
+TEST(StreamingUtf8ValidatorTest, HelloWorld) {
+  static const char kHelloWorld[] = "Hello, World!";
+  EXPECT_EQ(
+      VALID_ENDPOINT,
+      StreamingUtf8Validator().AddBytes(kHelloWorld, strlen(kHelloWorld)));
+}
+
+// Check that the Reset() method works.
+TEST(StreamingUtf8ValidatorTest, ResetWorks) {
+  StreamingUtf8Validator validator;
+  EXPECT_EQ(INVALID, validator.AddBytes("\xC0", 1));
+  EXPECT_EQ(INVALID, validator.AddBytes("a", 1));
+  validator.Reset();
+  EXPECT_EQ(VALID_ENDPOINT, validator.AddBytes("a", 1));
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Valid) {
+  CheckRange(valid, valid_end, VALID_ENDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Partial) {
+  CheckRange(PartialIterator(), PartialIterator::end(), VALID_MIDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Invalid) {
+  CheckRange(invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, ValidByByte) {
+  CheckRangeByteAtATime(valid, valid_end, VALID_ENDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, PartialByByte) {
+  CheckRangeByteAtATime(
+      PartialIterator(), PartialIterator::end(), VALID_MIDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, InvalidByByte) {
+  CheckRangeByteAtATime(invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusValidIsValid) {
+  CheckCombinations(valid, valid_end, valid, valid_end, VALID_ENDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusPartialIsPartial) {
+  CheckCombinations(valid,
+                    valid_end,
+                    PartialIterator(),
+                    PartialIterator::end(),
+                    VALID_MIDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusValidIsInvalid) {
+  CheckCombinations(
+      PartialIterator(), PartialIterator::end(), valid, valid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusPartialIsInvalid) {
+  CheckCombinations(PartialIterator(),
+                    PartialIterator::end(),
+                    PartialIterator(),
+                    PartialIterator::end(),
+                    INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusInvalidIsInvalid) {
+  CheckCombinations(valid, valid_end, invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusValidIsInvalid) {
+  CheckCombinations(invalid, invalid_end, valid, valid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusInvalidIsInvalid) {
+  CheckCombinations(invalid, invalid_end, invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusPartialIsInvalid) {
+  CheckCombinations(
+      invalid, invalid_end, PartialIterator(), PartialIterator::end(), INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusInvalidIsInvalid) {
+  CheckCombinations(
+      PartialIterator(), PartialIterator::end(), invalid, invalid_end, INVALID);
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, EmptyIsValid) {
+  EXPECT_TRUE(StreamingUtf8Validator::Validate(std::string()));
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, SimpleValidCase) {
+  EXPECT_TRUE(StreamingUtf8Validator::Validate("\xc2\x81"));
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, SimpleInvalidCase) {
+  EXPECT_FALSE(StreamingUtf8Validator::Validate("\xc0\x80"));
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, TruncatedIsInvalid) {
+  EXPECT_FALSE(StreamingUtf8Validator::Validate("\xc2"));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/string_compare.cc b/base/i18n/string_compare.cc
new file mode 100644
index 0000000..2851e7d
--- /dev/null
+++ b/base/i18n/string_compare.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/string_compare.h"
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+namespace i18n {
+
+// Compares the character data stored in two different string16 strings by
+// specified Collator instance.
+UCollationResult CompareString16WithCollator(const icu::Collator& collator,
+                                             const string16& lhs,
+                                             const string16& rhs) {
+  UErrorCode error = U_ZERO_ERROR;
+  UCollationResult result = collator.compare(
+      static_cast<const UChar*>(lhs.c_str()), static_cast<int>(lhs.length()),
+      static_cast<const UChar*>(rhs.c_str()), static_cast<int>(rhs.length()),
+      error);
+  DCHECK(U_SUCCESS(error));
+  return result;
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/string_compare.h b/base/i18n/string_compare.h
new file mode 100644
index 0000000..5fcc5fe
--- /dev/null
+++ b/base/i18n/string_compare.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_STRING_COMPARE_H_
+#define BASE_I18N_STRING_COMPARE_H_
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace base {
+namespace i18n {
+
+// Compares the two strings using the specified collator.
+BASE_I18N_EXPORT UCollationResult
+CompareString16WithCollator(const icu::Collator& collator,
+                            const string16& lhs,
+                            const string16& rhs);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_STRING_COMPARE_H_
diff --git a/base/i18n/string_search.cc b/base/i18n/string_search.cc
new file mode 100644
index 0000000..121dfce
--- /dev/null
+++ b/base/i18n/string_search.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/string_search.h"
+#include "base/logging.h"
+
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+FixedPatternStringSearchIgnoringCaseAndAccents::
+FixedPatternStringSearchIgnoringCaseAndAccents(const string16& find_this)
+    : find_this_(find_this) {
+  // usearch_open requires a valid string argument to be searched, even if we
+  // want to set it by usearch_setText afterwards. So, supplying a dummy text.
+  const string16& dummy = find_this_;
+
+  UErrorCode status = U_ZERO_ERROR;
+  search_ = usearch_open(find_this_.data(), find_this_.size(),
+                         dummy.data(), dummy.size(),
+                         uloc_getDefault(),
+                         NULL,  // breakiter
+                         &status);
+  if (U_SUCCESS(status)) {
+    UCollator* collator = usearch_getCollator(search_);
+    ucol_setStrength(collator, UCOL_PRIMARY);
+    usearch_reset(search_);
+  }
+}
+
+FixedPatternStringSearchIgnoringCaseAndAccents::
+~FixedPatternStringSearchIgnoringCaseAndAccents() {
+  if (search_)
+    usearch_close(search_);
+}
+
+bool FixedPatternStringSearchIgnoringCaseAndAccents::Search(
+    const string16& in_this, size_t* match_index, size_t* match_length) {
+  UErrorCode status = U_ZERO_ERROR;
+  usearch_setText(search_, in_this.data(), in_this.size(), &status);
+
+  // Default to basic substring search if usearch fails. According to
+  // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail
+  // if either |find_this| or |in_this| are empty. In either case basic
+  // substring search will give the correct return value.
+  if (!U_SUCCESS(status)) {
+    size_t index = in_this.find(find_this_);
+    if (index == string16::npos) {
+      return false;
+    } else {
+      if (match_index)
+        *match_index = index;
+      if (match_length)
+        *match_length = find_this_.size();
+      return true;
+    }
+  }
+
+  int32_t index = usearch_first(search_, &status);
+  if (!U_SUCCESS(status) || index == USEARCH_DONE)
+    return false;
+  if (match_index)
+    *match_index = static_cast<size_t>(index);
+  if (match_length)
+    *match_length = static_cast<size_t>(usearch_getMatchedLength(search_));
+  return true;
+}
+
+bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
+                                        const string16& in_this,
+                                        size_t* match_index,
+                                        size_t* match_length) {
+  return FixedPatternStringSearchIgnoringCaseAndAccents(find_this).Search(
+      in_this, match_index, match_length);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/string_search.h b/base/i18n/string_search.h
new file mode 100644
index 0000000..138606f
--- /dev/null
+++ b/base/i18n/string_search.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_STRING_SEARCH_H_
+#define BASE_I18N_STRING_SEARCH_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+struct UStringSearch;
+
+namespace base {
+namespace i18n {
+
+// Returns true if |in_this| contains |find_this|. If |match_index| or
+// |match_length| are non-NULL, they are assigned the start position and total
+// length of the match.
+//
+// Only differences between base letters are taken into consideration. Case and
+// accent differences are ignored. Please refer to 'primary level' in
+// http://userguide.icu-project.org/collation/concepts for additional details.
+BASE_I18N_EXPORT
+    bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
+                                            const string16& in_this,
+                                            size_t* match_index,
+                                            size_t* match_length);
+
+// This class is for speeding up multiple StringSearchIgnoringCaseAndAccents()
+// with the same |find_this| argument. |find_this| is passed as the constructor
+// argument, and precomputation for searching is done only at that timing.
+class BASE_I18N_EXPORT FixedPatternStringSearchIgnoringCaseAndAccents {
+ public:
+  explicit FixedPatternStringSearchIgnoringCaseAndAccents(
+      const string16& find_this);
+  ~FixedPatternStringSearchIgnoringCaseAndAccents();
+
+  // Returns true if |in_this| contains |find_this|. If |match_index| or
+  // |match_length| are non-NULL, they are assigned the start position and total
+  // length of the match.
+  bool Search(const string16& in_this,
+              size_t* match_index,
+              size_t* match_length);
+
+ private:
+  string16 find_this_;
+  UStringSearch* search_;
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_STRING_SEARCH_H_
diff --git a/base/i18n/string_search_unittest.cc b/base/i18n/string_search_unittest.cc
new file mode 100644
index 0000000..9419b26
--- /dev/null
+++ b/base/i18n/string_search_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/i18n/rtl.h"
+#include "base/i18n/string_search.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+// Note on setting default locale for testing: The current default locale on
+// the Mac trybot is en_US_POSIX, with which primary-level collation strength
+// string search is case-sensitive, when normally it should be
+// case-insensitive. In other locales (including en_US which English speakers
+// in the U.S. use), this search would be case-insensitive as expected.
+
+TEST(StringSearchTest, ASCII) {
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("hello"), ASCIIToUTF16("hello world"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(5U, length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("h    e l l o"), ASCIIToUTF16("h   e l l o"),
+      &index, &length));
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("aabaaa"), ASCIIToUTF16("aaabaabaaa"), &index, &length));
+  EXPECT_EQ(4U, index);
+  EXPECT_EQ(6U, length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("searching within empty string"), string16(),
+      &index, &length));
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      string16(), ASCIIToUTF16("searching for empty string"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(0U, length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("case insensitivity"), ASCIIToUTF16("CaSe InSeNsItIvItY"),
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(18U, length);
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+TEST(StringSearchTest, UnicodeLocaleIndependent) {
+  // Base characters
+  const string16 e_base = WideToUTF16(L"e");
+  const string16 E_base = WideToUTF16(L"E");
+  const string16 a_base = WideToUTF16(L"a");
+
+  // Composed characters
+  const string16 e_with_acute_accent = WideToUTF16(L"\u00e9");
+  const string16 E_with_acute_accent = WideToUTF16(L"\u00c9");
+  const string16 e_with_grave_accent = WideToUTF16(L"\u00e8");
+  const string16 E_with_grave_accent = WideToUTF16(L"\u00c8");
+  const string16 a_with_acute_accent = WideToUTF16(L"\u00e1");
+
+  // Decomposed characters
+  const string16 e_with_acute_combining_mark = WideToUTF16(L"e\u0301");
+  const string16 E_with_acute_combining_mark = WideToUTF16(L"E\u0301");
+  const string16 e_with_grave_combining_mark = WideToUTF16(L"e\u0300");
+  const string16 E_with_grave_combining_mark = WideToUTF16(L"E\u0300");
+  const string16 a_with_acute_combining_mark = WideToUTF16(L"a\u0301");
+
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_base, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_accent, e_base, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_base.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_base, e_with_acute_combining_mark, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_base, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_base.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_acute_accent,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_accent, e_with_acute_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_grave_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_grave_combining_mark, e_with_acute_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_grave_accent, e_with_acute_combining_mark, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_acute_accent, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_grave_accent, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_acute_combining_mark, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_grave_combining_mark, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_base, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_with_acute_accent, e_with_acute_accent, &index, &length));
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_with_acute_combining_mark, e_with_acute_combining_mark,
+      &index, &length));
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+TEST(StringSearchTest, UnicodeLocaleDependent) {
+  // Base characters
+  const string16 a_base = WideToUTF16(L"a");
+
+  // Composed characters
+  const string16 a_with_ring = WideToUTF16(L"\u00e5");
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      a_base, a_with_ring, NULL, NULL));
+
+  const char* default_locale = uloc_getDefault();
+  SetICUDefaultLocale("da");
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_base, a_with_ring, NULL, NULL));
+
+  SetICUDefaultLocale(default_locale);
+}
+
+TEST(StringSearchTest, FixedPatternMultipleSearch) {
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  // Search "hello" over multiple texts.
+  FixedPatternStringSearchIgnoringCaseAndAccents query(ASCIIToUTF16("hello"));
+  EXPECT_TRUE(query.Search(ASCIIToUTF16("12hello34"), &index, &length));
+  EXPECT_EQ(2U, index);
+  EXPECT_EQ(5U, length);
+  EXPECT_FALSE(query.Search(ASCIIToUTF16("bye"), &index, &length));
+  EXPECT_TRUE(query.Search(ASCIIToUTF16("hELLo"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(5U, length);
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
new file mode 100644
index 0000000..15b34a3
--- /dev/null
+++ b/base/i18n/time_formatting.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/time_formatting.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "third_party/icu/source/i18n/unicode/datefmt.h"
+#include "third_party/icu/source/i18n/unicode/dtptngen.h"
+#include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
+
+namespace base {
+namespace {
+
+string16 TimeFormat(const icu::DateFormat* formatter,
+                    const Time& time) {
+  DCHECK(formatter);
+  icu::UnicodeString date_string;
+
+  formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
+  return string16(date_string.getBuffer(),
+                  static_cast<size_t>(date_string.length()));
+}
+
+string16 TimeFormatWithoutAmPm(const icu::DateFormat* formatter,
+                               const Time& time) {
+  DCHECK(formatter);
+  icu::UnicodeString time_string;
+
+  icu::FieldPosition ampm_field(icu::DateFormat::kAmPmField);
+  formatter->format(
+      static_cast<UDate>(time.ToDoubleT() * 1000), time_string, ampm_field);
+  int ampm_length = ampm_field.getEndIndex() - ampm_field.getBeginIndex();
+  if (ampm_length) {
+    int begin = ampm_field.getBeginIndex();
+    // Doesn't include any spacing before the field.
+    if (begin)
+      begin--;
+    time_string.removeBetween(begin, ampm_field.getEndIndex());
+  }
+  return string16(time_string.getBuffer(),
+                  static_cast<size_t>(time_string.length()));
+}
+
+}  // namespace
+
+string16 TimeFormatTimeOfDay(const Time& time) {
+  // We can omit the locale parameter because the default should match
+  // Chrome's application locale.
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createTimeInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatTimeOfDayWithHourClockType(const Time& time,
+                                              HourClockType type,
+                                              AmPmClockType ampm) {
+  // Just redirect to the normal function if the default type matches the
+  // given type.
+  HourClockType default_type = GetHourClockType();
+  if (default_type == type && (type == k24HourClock || ampm == kKeepAmPm)) {
+    return TimeFormatTimeOfDay(time);
+  }
+
+  // Generate a locale-dependent format pattern. The generator will take
+  // care of locale-dependent formatting issues like which separator to
+  // use (some locales use '.' instead of ':'), and where to put the am/pm
+  // marker.
+  UErrorCode status = U_ZERO_ERROR;
+  scoped_ptr<icu::DateTimePatternGenerator> generator(
+      icu::DateTimePatternGenerator::createInstance(status));
+  DCHECK(U_SUCCESS(status));
+  const char* base_pattern = (type == k12HourClock ? "ahm" : "Hm");
+  icu::UnicodeString generated_pattern =
+      generator->getBestPattern(icu::UnicodeString(base_pattern), status);
+  DCHECK(U_SUCCESS(status));
+
+  // Then, format the time using the generated pattern.
+  icu::SimpleDateFormat formatter(generated_pattern, status);
+  DCHECK(U_SUCCESS(status));
+  if (ampm == kKeepAmPm) {
+    return TimeFormat(&formatter, time);
+  } else {
+    return TimeFormatWithoutAmPm(&formatter, time);
+  }
+}
+
+string16 TimeFormatShortDate(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateNumeric(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateAndTime(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateAndTimeWithTimeZone(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateTimeInstance(
+      icu::DateFormat::kShort, icu::DateFormat::kLong));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatFriendlyDateAndTime(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatFriendlyDate(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateInstance(
+      icu::DateFormat::kFull));
+  return TimeFormat(formatter.get(), time);
+}
+
+HourClockType GetHourClockType() {
+  // TODO(satorux,jshin): Rework this with ures_getByKeyWithFallback()
+  // once it becomes public. The short time format can be found at
+  // "calendar/gregorian/DateTimePatterns/3" in the resources.
+  scoped_ptr<icu::SimpleDateFormat> formatter(
+      static_cast<icu::SimpleDateFormat*>(
+          icu::DateFormat::createTimeInstance(icu::DateFormat::kShort)));
+  // Retrieve the short time format.
+  icu::UnicodeString pattern_unicode;
+  formatter->toPattern(pattern_unicode);
+
+  // Determine what hour clock type the current locale uses, by checking
+  // "a" (am/pm marker) in the short time format. This is reliable as "a"
+  // is used by all of 12-hour clock formats, but not any of 24-hour clock
+  // formats, as shown below.
+  //
+  // % grep -A4 DateTimePatterns third_party/icu/source/data/locales/*.txt |
+  //   grep -B1 -- -- |grep -v -- '--' |
+  //   perl -nle 'print $1 if /^\S+\s+"(.*)"/' |sort -u
+  //
+  // H.mm
+  // H:mm
+  // HH.mm
+  // HH:mm
+  // a h:mm
+  // ah:mm
+  // ahh:mm
+  // h-mm a
+  // h:mm a
+  // hh:mm a
+  //
+  // See http://userguide.icu-project.org/formatparse/datetime for details
+  // about the date/time format syntax.
+  if (pattern_unicode.indexOf('a') == -1) {
+    return k24HourClock;
+  } else {
+    return k12HourClock;
+  }
+}
+
+}  // namespace base
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
new file mode 100644
index 0000000..2053c0b
--- /dev/null
+++ b/base/i18n/time_formatting.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Basic time formatting methods.  These methods use the current locale
+// formatting for displaying the time.
+
+#ifndef BASE_I18N_TIME_FORMATTING_H_
+#define BASE_I18N_TIME_FORMATTING_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+class Time;
+
+// Argument type used to specify the hour clock type.
+enum HourClockType {
+  k12HourClock,  // Uses 1-12. e.g., "3:07 PM"
+  k24HourClock,  // Uses 0-23. e.g., "15:07"
+};
+
+// Argument type used to specify whether or not to include AM/PM sign.
+enum AmPmClockType {
+  kDropAmPm,  // Drops AM/PM sign. e.g., "3:07"
+  kKeepAmPm,  // Keeps AM/PM sign. e.g., "3:07 PM"
+};
+
+// Returns the time of day, e.g., "3:07 PM".
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDay(const Time& time);
+
+// Returns the time of day in the specified hour clock type. e.g.
+// "3:07 PM" (type == k12HourClock, ampm == kKeepAmPm).
+// "3:07"    (type == k12HourClock, ampm == kDropAmPm).
+// "15:07"   (type == k24HourClock).
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDayWithHourClockType(
+    const Time& time,
+    HourClockType type,
+    AmPmClockType ampm);
+
+// Returns a shortened date, e.g. "Nov 7, 2007"
+BASE_I18N_EXPORT string16 TimeFormatShortDate(const Time& time);
+
+// Returns a numeric date such as 12/13/52.
+BASE_I18N_EXPORT string16 TimeFormatShortDateNumeric(const Time& time);
+
+// Returns a numeric date and time such as "12/13/52 2:44:30 PM".
+BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time);
+
+// Returns a numeric date and time with time zone such as
+// "12/13/52 2:44:30 PM PST".
+BASE_I18N_EXPORT string16
+TimeFormatShortDateAndTimeWithTimeZone(const Time& time);
+
+// Formats a time in a friendly sentence format, e.g.
+// "Monday, March 6, 2008 2:44:30 PM".
+BASE_I18N_EXPORT string16 TimeFormatFriendlyDateAndTime(const Time& time);
+
+// Formats a time in a friendly sentence format, e.g.
+// "Monday, March 6, 2008".
+BASE_I18N_EXPORT string16 TimeFormatFriendlyDate(const Time& time);
+
+// Gets the hour clock type of the current locale. e.g.
+// k12HourClock (en-US).
+// k24HourClock (en-GB).
+BASE_I18N_EXPORT HourClockType GetHourClockType();
+
+}  // namespace base
+
+#endif  // BASE_I18N_TIME_FORMATTING_H_
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
new file mode 100644
index 0000000..df0c1ed
--- /dev/null
+++ b/base/i18n/time_formatting_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/time_formatting.h"
+
+#include "base/i18n/rtl.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/common/unicode/uversion.h"
+#include "third_party/icu/source/i18n/unicode/calendar.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace base {
+namespace {
+
+const Time::Exploded kTestDateTimeExploded = {
+  2011, 4, 6, 30, // Sat, Apr 30, 2011
+  15, 42, 7, 0    // 15:42:07.000
+};
+
+base::string16 GetShortTimeZone() {
+  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+  icu::UnicodeString name;
+  zone->getDisplayName(true, icu::TimeZone::SHORT, name);
+  return base::string16(name.getBuffer(), name.length());
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault12h) {
+  // Test for a locale defaulted to 12h clock.
+  // As an instance, we use third_party/icu/source/data/locales/en.txt.
+  i18n::SetICUDefaultLocale("en_US");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(ASCIIToUTF16("3:42 PM"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 12h clock.
+  EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k12HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault24h) {
+  // Test for a locale defaulted to 24h clock.
+  // As an instance, we use third_party/icu/source/data/locales/en_GB.txt.
+  i18n::SetICUDefaultLocale("en_GB");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(ASCIIToUTF16("3:42 pm"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 24h clock.
+  EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k24HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayJP) {
+  // Test for a locale that uses different mark than "AM" and "PM".
+  // As an instance, we use third_party/icu/source/data/locales/ja.txt.
+  i18n::SetICUDefaultLocale("ja_JP");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(WideToUTF16(L"\x5348\x5f8c" L"3:42"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 24h clock.
+  EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k24HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatDateUS) {
+  // See third_party/icu/source/data/locales/en.txt.
+  // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy".
+  i18n::SetICUDefaultLocale("en_US");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+
+  EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatShortDate(time));
+  EXPECT_EQ(ASCIIToUTF16("4/30/11"), TimeFormatShortDateNumeric(time));
+
+  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"),
+            TimeFormatShortDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(),
+            TimeFormatShortDateAndTimeWithTimeZone(time));
+
+  EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"),
+            TimeFormatFriendlyDateAndTime(time));
+
+  EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011"),
+            TimeFormatFriendlyDate(time));
+}
+
+TEST(TimeFormattingTest, TimeFormatDateGB) {
+  // See third_party/icu/source/data/locales/en_GB.txt.
+  // The date patterns are "EEEE, d MMMM y", "d MMM y", and "dd/MM/yyyy".
+  i18n::SetICUDefaultLocale("en_GB");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+
+  EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time));
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time));
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07"),
+            TimeFormatShortDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(),
+            TimeFormatShortDateAndTimeWithTimeZone(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
+            TimeFormatFriendlyDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"),
+            TimeFormatFriendlyDate(time));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/timezone.cc b/base/i18n/timezone.cc
new file mode 100644
index 0000000..f668543
--- /dev/null
+++ b/base/i18n/timezone.cc
@@ -0,0 +1,616 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/timezone.h"
+
+#include <string.h>
+
+#include <map>
+
+#include "base/memory/singleton.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace base {
+
+namespace {
+
+class TimezoneMap {
+ public:
+  static TimezoneMap* GetInstance() {
+    return Singleton<TimezoneMap>::get();
+  }
+
+  std::string CountryCodeForTimezone(const std::string& olson_code) {
+    std::map<const char*, const char*, CompareCStrings>::iterator iter =
+      map_.find(olson_code.c_str());
+    if (iter != map_.end())
+      return iter->second;
+
+    return std::string();
+  }
+
+ private:
+  TimezoneMap() {
+    // These mappings are adapted from zone.tab, which is available at
+    // <http://www.ietf.org/timezones/data/zone.tab> and is a part of public
+    // domain.
+    struct OlsonCodeData {
+      const char* country_code;
+      const char* olson_code;
+    };
+    static const OlsonCodeData olson_code_data[] = {
+        { "AD", "Europe/Andorra" },
+        { "AE", "Asia/Dubai" },
+        { "AF", "Asia/Kabul" },
+        { "AG", "America/Antigua" },
+        { "AI", "America/Anguilla" },
+        { "AL", "Europe/Tirane" },
+        { "AM", "Asia/Yerevan" },
+        { "AO", "Africa/Luanda" },
+        { "AQ", "Antarctica/McMurdo" },
+        { "AQ", "Antarctica/Rothera" },
+        { "AQ", "Antarctica/Palmer" },
+        { "AQ", "Antarctica/Mawson" },
+        { "AQ", "Antarctica/Davis" },
+        { "AQ", "Antarctica/Casey" },
+        { "AQ", "Antarctica/Vostok" },
+        { "AQ", "Antarctica/DumontDUrville" },
+        { "AQ", "Antarctica/Syowa" },
+        { "AR", "America/Argentina/Buenos_Aires" },
+        { "AR", "America/Argentina/Cordoba" },
+        { "AR", "America/Argentina/Salta" },
+        { "AR", "America/Argentina/Jujuy" },
+        { "AR", "America/Argentina/Tucuman" },
+        { "AR", "America/Argentina/Catamarca" },
+        { "AR", "America/Argentina/La_Rioja" },
+        { "AR", "America/Argentina/San_Juan" },
+        { "AR", "America/Argentina/Mendoza" },
+        { "AR", "America/Argentina/San_Luis" },
+        { "AR", "America/Argentina/Rio_Gallegos" },
+        { "AR", "America/Argentina/Ushuaia" },
+        { "AS", "Pacific/Pago_Pago" },
+        { "AT", "Europe/Vienna" },
+        { "AU", "Australia/Lord_Howe" },
+        { "AU", "Antarctica/Macquarie" },
+        { "AU", "Australia/Hobart" },
+        { "AU", "Australia/Currie" },
+        { "AU", "Australia/Melbourne" },
+        { "AU", "Australia/Sydney" },
+        { "AU", "Australia/Broken_Hill" },
+        { "AU", "Australia/Brisbane" },
+        { "AU", "Australia/Lindeman" },
+        { "AU", "Australia/Adelaide" },
+        { "AU", "Australia/Darwin" },
+        { "AU", "Australia/Perth" },
+        { "AU", "Australia/Eucla" },
+        { "AW", "America/Aruba" },
+        { "AX", "Europe/Mariehamn" },
+        { "AZ", "Asia/Baku" },
+        { "BA", "Europe/Sarajevo" },
+        { "BB", "America/Barbados" },
+        { "BD", "Asia/Dhaka" },
+        { "BE", "Europe/Brussels" },
+        { "BF", "Africa/Ouagadougou" },
+        { "BG", "Europe/Sofia" },
+        { "BH", "Asia/Bahrain" },
+        { "BI", "Africa/Bujumbura" },
+        { "BJ", "Africa/Porto-Novo" },
+        { "BL", "America/St_Barthelemy" },
+        { "BM", "Atlantic/Bermuda" },
+        { "BN", "Asia/Brunei" },
+        { "BO", "America/La_Paz" },
+        { "BQ", "America/Kralendijk" },
+        { "BR", "America/Noronha" },
+        { "BR", "America/Belem" },
+        { "BR", "America/Fortaleza" },
+        { "BR", "America/Recife" },
+        { "BR", "America/Araguaina" },
+        { "BR", "America/Maceio" },
+        { "BR", "America/Bahia" },
+        { "BR", "America/Sao_Paulo" },
+        { "BR", "America/Campo_Grande" },
+        { "BR", "America/Cuiaba" },
+        { "BR", "America/Santarem" },
+        { "BR", "America/Porto_Velho" },
+        { "BR", "America/Boa_Vista" },
+        { "BR", "America/Manaus" },
+        { "BR", "America/Eirunepe" },
+        { "BR", "America/Rio_Branco" },
+        { "BS", "America/Nassau" },
+        { "BT", "Asia/Thimphu" },
+        { "BW", "Africa/Gaborone" },
+        { "BY", "Europe/Minsk" },
+        { "BZ", "America/Belize" },
+        { "CA", "America/St_Johns" },
+        { "CA", "America/Halifax" },
+        { "CA", "America/Glace_Bay" },
+        { "CA", "America/Moncton" },
+        { "CA", "America/Goose_Bay" },
+        { "CA", "America/Blanc-Sablon" },
+        { "CA", "America/Toronto" },
+        { "CA", "America/Nipigon" },
+        { "CA", "America/Thunder_Bay" },
+        { "CA", "America/Iqaluit" },
+        { "CA", "America/Pangnirtung" },
+        { "CA", "America/Resolute" },
+        { "CA", "America/Atikokan" },
+        { "CA", "America/Rankin_Inlet" },
+        { "CA", "America/Winnipeg" },
+        { "CA", "America/Rainy_River" },
+        { "CA", "America/Regina" },
+        { "CA", "America/Swift_Current" },
+        { "CA", "America/Edmonton" },
+        { "CA", "America/Cambridge_Bay" },
+        { "CA", "America/Yellowknife" },
+        { "CA", "America/Inuvik" },
+        { "CA", "America/Creston" },
+        { "CA", "America/Dawson_Creek" },
+        { "CA", "America/Vancouver" },
+        { "CA", "America/Whitehorse" },
+        { "CA", "America/Dawson" },
+        { "CC", "Indian/Cocos" },
+        { "CD", "Africa/Kinshasa" },
+        { "CD", "Africa/Lubumbashi" },
+        { "CF", "Africa/Bangui" },
+        { "CG", "Africa/Brazzaville" },
+        { "CH", "Europe/Zurich" },
+        { "CI", "Africa/Abidjan" },
+        { "CK", "Pacific/Rarotonga" },
+        { "CL", "America/Santiago" },
+        { "CL", "Pacific/Easter" },
+        { "CM", "Africa/Douala" },
+        { "CN", "Asia/Shanghai" },
+        { "CN", "Asia/Harbin" },
+        { "CN", "Asia/Chongqing" },
+        { "CN", "Asia/Urumqi" },
+        { "CN", "Asia/Kashgar" },
+        { "CO", "America/Bogota" },
+        { "CR", "America/Costa_Rica" },
+        { "CU", "America/Havana" },
+        { "CV", "Atlantic/Cape_Verde" },
+        { "CW", "America/Curacao" },
+        { "CX", "Indian/Christmas" },
+        { "CY", "Asia/Nicosia" },
+        { "CZ", "Europe/Prague" },
+        { "DE", "Europe/Berlin" },
+        { "DE", "Europe/Busingen" },
+        { "DJ", "Africa/Djibouti" },
+        { "DK", "Europe/Copenhagen" },
+        { "DM", "America/Dominica" },
+        { "DO", "America/Santo_Domingo" },
+        { "DZ", "Africa/Algiers" },
+        { "EC", "America/Guayaquil" },
+        { "EC", "Pacific/Galapagos" },
+        { "EE", "Europe/Tallinn" },
+        { "EG", "Africa/Cairo" },
+        { "EH", "Africa/El_Aaiun" },
+        { "ER", "Africa/Asmara" },
+        { "ES", "Europe/Madrid" },
+        { "ES", "Africa/Ceuta" },
+        { "ES", "Atlantic/Canary" },
+        { "ET", "Africa/Addis_Ababa" },
+        { "FI", "Europe/Helsinki" },
+        { "FJ", "Pacific/Fiji" },
+        { "FK", "Atlantic/Stanley" },
+        { "FM", "Pacific/Chuuk" },
+        { "FM", "Pacific/Pohnpei" },
+        { "FM", "Pacific/Kosrae" },
+        { "FO", "Atlantic/Faroe" },
+        { "FR", "Europe/Paris" },
+        { "GA", "Africa/Libreville" },
+        { "GB", "Europe/London" },
+        { "GD", "America/Grenada" },
+        { "GE", "Asia/Tbilisi" },
+        { "GF", "America/Cayenne" },
+        { "GG", "Europe/Guernsey" },
+        { "GH", "Africa/Accra" },
+        { "GI", "Europe/Gibraltar" },
+        { "GL", "America/Godthab" },
+        { "GL", "America/Danmarkshavn" },
+        { "GL", "America/Scoresbysund" },
+        { "GL", "America/Thule" },
+        { "GM", "Africa/Banjul" },
+        { "GN", "Africa/Conakry" },
+        { "GP", "America/Guadeloupe" },
+        { "GQ", "Africa/Malabo" },
+        { "GR", "Europe/Athens" },
+        { "GS", "Atlantic/South_Georgia" },
+        { "GT", "America/Guatemala" },
+        { "GU", "Pacific/Guam" },
+        { "GW", "Africa/Bissau" },
+        { "GY", "America/Guyana" },
+        { "HK", "Asia/Hong_Kong" },
+        { "HN", "America/Tegucigalpa" },
+        { "HR", "Europe/Zagreb" },
+        { "HT", "America/Port-au-Prince" },
+        { "HU", "Europe/Budapest" },
+        { "ID", "Asia/Jakarta" },
+        { "ID", "Asia/Pontianak" },
+        { "ID", "Asia/Makassar" },
+        { "ID", "Asia/Jayapura" },
+        { "IE", "Europe/Dublin" },
+        { "IL", "Asia/Jerusalem" },
+        { "IM", "Europe/Isle_of_Man" },
+        { "IN", "Asia/Kolkata" },
+        { "IO", "Indian/Chagos" },
+        { "IQ", "Asia/Baghdad" },
+        { "IR", "Asia/Tehran" },
+        { "IS", "Atlantic/Reykjavik" },
+        { "IT", "Europe/Rome" },
+        { "JE", "Europe/Jersey" },
+        { "JM", "America/Jamaica" },
+        { "JO", "Asia/Amman" },
+        { "JP", "Asia/Tokyo" },
+        { "KE", "Africa/Nairobi" },
+        { "KG", "Asia/Bishkek" },
+        { "KH", "Asia/Phnom_Penh" },
+        { "KI", "Pacific/Tarawa" },
+        { "KI", "Pacific/Enderbury" },
+        { "KI", "Pacific/Kiritimati" },
+        { "KM", "Indian/Comoro" },
+        { "KN", "America/St_Kitts" },
+        { "KP", "Asia/Pyongyang" },
+        { "KR", "Asia/Seoul" },
+        { "KW", "Asia/Kuwait" },
+        { "KY", "America/Cayman" },
+        { "KZ", "Asia/Almaty" },
+        { "KZ", "Asia/Qyzylorda" },
+        { "KZ", "Asia/Aqtobe" },
+        { "KZ", "Asia/Aqtau" },
+        { "KZ", "Asia/Oral" },
+        { "LA", "Asia/Vientiane" },
+        { "LB", "Asia/Beirut" },
+        { "LC", "America/St_Lucia" },
+        { "LI", "Europe/Vaduz" },
+        { "LK", "Asia/Colombo" },
+        { "LR", "Africa/Monrovia" },
+        { "LS", "Africa/Maseru" },
+        { "LT", "Europe/Vilnius" },
+        { "LU", "Europe/Luxembourg" },
+        { "LV", "Europe/Riga" },
+        { "LY", "Africa/Tripoli" },
+        { "MA", "Africa/Casablanca" },
+        { "MC", "Europe/Monaco" },
+        { "MD", "Europe/Chisinau" },
+        { "ME", "Europe/Podgorica" },
+        { "MF", "America/Marigot" },
+        { "MG", "Indian/Antananarivo" },
+        { "MH", "Pacific/Majuro" },
+        { "MH", "Pacific/Kwajalein" },
+        { "MK", "Europe/Skopje" },
+        { "ML", "Africa/Bamako" },
+        { "MM", "Asia/Rangoon" },
+        { "MN", "Asia/Ulaanbaatar" },
+        { "MN", "Asia/Hovd" },
+        { "MN", "Asia/Choibalsan" },
+        { "MO", "Asia/Macau" },
+        { "MP", "Pacific/Saipan" },
+        { "MQ", "America/Martinique" },
+        { "MR", "Africa/Nouakchott" },
+        { "MS", "America/Montserrat" },
+        { "MT", "Europe/Malta" },
+        { "MU", "Indian/Mauritius" },
+        { "MV", "Indian/Maldives" },
+        { "MW", "Africa/Blantyre" },
+        { "MX", "America/Mexico_City" },
+        { "MX", "America/Cancun" },
+        { "MX", "America/Merida" },
+        { "MX", "America/Monterrey" },
+        { "MX", "America/Matamoros" },
+        { "MX", "America/Mazatlan" },
+        { "MX", "America/Chihuahua" },
+        { "MX", "America/Ojinaga" },
+        { "MX", "America/Hermosillo" },
+        { "MX", "America/Tijuana" },
+        { "MX", "America/Santa_Isabel" },
+        { "MX", "America/Bahia_Banderas" },
+        { "MY", "Asia/Kuala_Lumpur" },
+        { "MY", "Asia/Kuching" },
+        { "MZ", "Africa/Maputo" },
+        { "NA", "Africa/Windhoek" },
+        { "NC", "Pacific/Noumea" },
+        { "NE", "Africa/Niamey" },
+        { "NF", "Pacific/Norfolk" },
+        { "NG", "Africa/Lagos" },
+        { "NI", "America/Managua" },
+        { "NL", "Europe/Amsterdam" },
+        { "NO", "Europe/Oslo" },
+        { "NP", "Asia/Kathmandu" },
+        { "NR", "Pacific/Nauru" },
+        { "NU", "Pacific/Niue" },
+        { "NZ", "Pacific/Auckland" },
+        { "NZ", "Pacific/Chatham" },
+        { "OM", "Asia/Muscat" },
+        { "PA", "America/Panama" },
+        { "PE", "America/Lima" },
+        { "PF", "Pacific/Tahiti" },
+        { "PF", "Pacific/Marquesas" },
+        { "PF", "Pacific/Gambier" },
+        { "PG", "Pacific/Port_Moresby" },
+        { "PH", "Asia/Manila" },
+        { "PK", "Asia/Karachi" },
+        { "PL", "Europe/Warsaw" },
+        { "PM", "America/Miquelon" },
+        { "PN", "Pacific/Pitcairn" },
+        { "PR", "America/Puerto_Rico" },
+        { "PS", "Asia/Gaza" },
+        { "PS", "Asia/Hebron" },
+        { "PT", "Europe/Lisbon" },
+        { "PT", "Atlantic/Madeira" },
+        { "PT", "Atlantic/Azores" },
+        { "PW", "Pacific/Palau" },
+        { "PY", "America/Asuncion" },
+        { "QA", "Asia/Qatar" },
+        { "RE", "Indian/Reunion" },
+        { "RO", "Europe/Bucharest" },
+        { "RS", "Europe/Belgrade" },
+        { "RU", "Europe/Kaliningrad" },
+        { "RU", "Europe/Moscow" },
+        { "RU", "Europe/Volgograd" },
+        { "RU", "Europe/Samara" },
+        { "RU", "Asia/Yekaterinburg" },
+        { "RU", "Asia/Omsk" },
+        { "RU", "Asia/Novosibirsk" },
+        { "RU", "Asia/Novokuznetsk" },
+        { "RU", "Asia/Krasnoyarsk" },
+        { "RU", "Asia/Irkutsk" },
+        { "RU", "Asia/Yakutsk" },
+        { "RU", "Asia/Khandyga" },
+        { "RU", "Asia/Vladivostok" },
+        { "RU", "Asia/Sakhalin" },
+        { "RU", "Asia/Ust-Nera" },
+        { "RU", "Asia/Magadan" },
+        { "RU", "Asia/Kamchatka" },
+        { "RU", "Asia/Anadyr" },
+        { "RW", "Africa/Kigali" },
+        { "SA", "Asia/Riyadh" },
+        { "SB", "Pacific/Guadalcanal" },
+        { "SC", "Indian/Mahe" },
+        { "SD", "Africa/Khartoum" },
+        { "SE", "Europe/Stockholm" },
+        { "SG", "Asia/Singapore" },
+        { "SH", "Atlantic/St_Helena" },
+        { "SI", "Europe/Ljubljana" },
+        { "SJ", "Arctic/Longyearbyen" },
+        { "SK", "Europe/Bratislava" },
+        { "SL", "Africa/Freetown" },
+        { "SM", "Europe/San_Marino" },
+        { "SN", "Africa/Dakar" },
+        { "SO", "Africa/Mogadishu" },
+        { "SR", "America/Paramaribo" },
+        { "SS", "Africa/Juba" },
+        { "ST", "Africa/Sao_Tome" },
+        { "SV", "America/El_Salvador" },
+        { "SX", "America/Lower_Princes" },
+        { "SY", "Asia/Damascus" },
+        { "SZ", "Africa/Mbabane" },
+        { "TC", "America/Grand_Turk" },
+        { "TD", "Africa/Ndjamena" },
+        { "TF", "Indian/Kerguelen" },
+        { "TG", "Africa/Lome" },
+        { "TH", "Asia/Bangkok" },
+        { "TJ", "Asia/Dushanbe" },
+        { "TK", "Pacific/Fakaofo" },
+        { "TL", "Asia/Dili" },
+        { "TM", "Asia/Ashgabat" },
+        { "TN", "Africa/Tunis" },
+        { "TO", "Pacific/Tongatapu" },
+        { "TR", "Europe/Istanbul" },
+        { "TT", "America/Port_of_Spain" },
+        { "TV", "Pacific/Funafuti" },
+        { "TW", "Asia/Taipei" },
+        { "TZ", "Africa/Dar_es_Salaam" },
+        { "UA", "Europe/Kiev" },
+        { "UA", "Europe/Uzhgorod" },
+        { "UA", "Europe/Zaporozhye" },
+        { "UA", "Europe/Simferopol" },
+        { "UG", "Africa/Kampala" },
+        { "UM", "Pacific/Johnston" },
+        { "UM", "Pacific/Midway" },
+        { "UM", "Pacific/Wake" },
+        { "US", "America/New_York" },
+        { "US", "America/Detroit" },
+        { "US", "America/Kentucky/Louisville" },
+        { "US", "America/Kentucky/Monticello" },
+        { "US", "America/Indiana/Indianapolis" },
+        { "US", "America/Indiana/Vincennes" },
+        { "US", "America/Indiana/Winamac" },
+        { "US", "America/Indiana/Marengo" },
+        { "US", "America/Indiana/Petersburg" },
+        { "US", "America/Indiana/Vevay" },
+        { "US", "America/Chicago" },
+        { "US", "America/Indiana/Tell_City" },
+        { "US", "America/Indiana/Knox" },
+        { "US", "America/Menominee" },
+        { "US", "America/North_Dakota/Center" },
+        { "US", "America/North_Dakota/New_Salem" },
+        { "US", "America/North_Dakota/Beulah" },
+        { "US", "America/Denver" },
+        { "US", "America/Boise" },
+        { "US", "America/Phoenix" },
+        { "US", "America/Los_Angeles" },
+        { "US", "America/Anchorage" },
+        { "US", "America/Juneau" },
+        { "US", "America/Sitka" },
+        { "US", "America/Yakutat" },
+        { "US", "America/Nome" },
+        { "US", "America/Adak" },
+        { "US", "America/Metlakatla" },
+        { "US", "Pacific/Honolulu" },
+        { "UY", "America/Montevideo" },
+        { "UZ", "Asia/Samarkand" },
+        { "UZ", "Asia/Tashkent" },
+        { "VA", "Europe/Vatican" },
+        { "VC", "America/St_Vincent" },
+        { "VE", "America/Caracas" },
+        { "VG", "America/Tortola" },
+        { "VI", "America/St_Thomas" },
+        { "VN", "Asia/Ho_Chi_Minh" },
+        { "VU", "Pacific/Efate" },
+        { "WF", "Pacific/Wallis" },
+        { "WS", "Pacific/Apia" },
+        { "YE", "Asia/Aden" },
+        { "YT", "Indian/Mayotte" },
+        { "ZA", "Africa/Johannesburg" },
+        { "ZM", "Africa/Lusaka" },
+        { "ZW", "Africa/Harare" },
+        // The mappings below are custom additions to zone.tab.
+        { "GB", "Etc/GMT" },
+        { "GB", "Etc/UTC" },
+        { "GB", "Etc/UCT" },
+    };
+
+    for (size_t i = 0; i < arraysize(olson_code_data); ++i)
+      map_[olson_code_data[i].olson_code] = olson_code_data[i].country_code;
+
+    // These are mapping from old codenames to new codenames. They are also
+    // part of public domain, and available at
+    // <http://www.ietf.org/timezones/data/backward>.
+    struct LinkData {
+      const char* old_code;
+      const char* new_code;
+    };
+    static const LinkData link_data[] = {
+        { "Africa/Asmera", "Africa/Asmara" },
+        { "Africa/Timbuktu", "Africa/Bamako" },
+        { "America/Argentina/ComodRivadavia", "America/Argentina/Catamarca" },
+        { "America/Atka", "America/Adak" },
+        { "America/Buenos_Aires", "America/Argentina/Buenos_Aires" },
+        { "America/Catamarca", "America/Argentina/Catamarca" },
+        { "America/Coral_Harbour", "America/Atikokan" },
+        { "America/Cordoba", "America/Argentina/Cordoba" },
+        { "America/Ensenada", "America/Tijuana" },
+        { "America/Fort_Wayne", "America/Indiana/Indianapolis" },
+        { "America/Indianapolis", "America/Indiana/Indianapolis" },
+        { "America/Jujuy", "America/Argentina/Jujuy" },
+        { "America/Knox_IN", "America/Indiana/Knox" },
+        { "America/Louisville", "America/Kentucky/Louisville" },
+        { "America/Mendoza", "America/Argentina/Mendoza" },
+        { "America/Porto_Acre", "America/Rio_Branco" },
+        { "America/Rosario", "America/Argentina/Cordoba" },
+        { "America/Virgin", "America/St_Thomas" },
+        { "Asia/Ashkhabad", "Asia/Ashgabat" },
+        { "Asia/Chungking", "Asia/Chongqing" },
+        { "Asia/Dacca", "Asia/Dhaka" },
+        { "Asia/Katmandu", "Asia/Kathmandu" },
+        { "Asia/Calcutta", "Asia/Kolkata" },
+        { "Asia/Macao", "Asia/Macau" },
+        { "Asia/Tel_Aviv", "Asia/Jerusalem" },
+        { "Asia/Saigon", "Asia/Ho_Chi_Minh" },
+        { "Asia/Thimbu", "Asia/Thimphu" },
+        { "Asia/Ujung_Pandang", "Asia/Makassar" },
+        { "Asia/Ulan_Bator", "Asia/Ulaanbaatar" },
+        { "Atlantic/Faeroe", "Atlantic/Faroe" },
+        { "Atlantic/Jan_Mayen", "Europe/Oslo" },
+        { "Australia/ACT", "Australia/Sydney" },
+        { "Australia/Canberra", "Australia/Sydney" },
+        { "Australia/LHI", "Australia/Lord_Howe" },
+        { "Australia/NSW", "Australia/Sydney" },
+        { "Australia/North", "Australia/Darwin" },
+        { "Australia/Queensland", "Australia/Brisbane" },
+        { "Australia/South", "Australia/Adelaide" },
+        { "Australia/Tasmania", "Australia/Hobart" },
+        { "Australia/Victoria", "Australia/Melbourne" },
+        { "Australia/West", "Australia/Perth" },
+        { "Australia/Yancowinna", "Australia/Broken_Hill" },
+        { "Brazil/Acre", "America/Rio_Branco" },
+        { "Brazil/DeNoronha", "America/Noronha" },
+        { "Brazil/East", "America/Sao_Paulo" },
+        { "Brazil/West", "America/Manaus" },
+        { "Canada/Atlantic", "America/Halifax" },
+        { "Canada/Central", "America/Winnipeg" },
+        { "Canada/East-Saskatchewan", "America/Regina" },
+        { "Canada/Eastern", "America/Toronto" },
+        { "Canada/Mountain", "America/Edmonton" },
+        { "Canada/Newfoundland", "America/St_Johns" },
+        { "Canada/Pacific", "America/Vancouver" },
+        { "Canada/Saskatchewan", "America/Regina" },
+        { "Canada/Yukon", "America/Whitehorse" },
+        { "Chile/Continental", "America/Santiago" },
+        { "Chile/EasterIsland", "Pacific/Easter" },
+        { "Cuba", "America/Havana" },
+        { "Egypt", "Africa/Cairo" },
+        { "Eire", "Europe/Dublin" },
+        { "Europe/Belfast", "Europe/London" },
+        { "Europe/Tiraspol", "Europe/Chisinau" },
+        { "GB", "Europe/London" },
+        { "GB-Eire", "Europe/London" },
+        { "GMT+0", "Etc/GMT" },
+        { "GMT-0", "Etc/GMT" },
+        { "GMT0", "Etc/GMT" },
+        { "Greenwich", "Etc/GMT" },
+        { "Hongkong", "Asia/Hong_Kong" },
+        { "Iceland", "Atlantic/Reykjavik" },
+        { "Iran", "Asia/Tehran" },
+        { "Israel", "Asia/Jerusalem" },
+        { "Jamaica", "America/Jamaica" },
+        { "Japan", "Asia/Tokyo" },
+        { "Kwajalein", "Pacific/Kwajalein" },
+        { "Libya", "Africa/Tripoli" },
+        { "Mexico/BajaNorte", "America/Tijuana" },
+        { "Mexico/BajaSur", "America/Mazatlan" },
+        { "Mexico/General", "America/Mexico_City" },
+        { "NZ", "Pacific/Auckland" },
+        { "NZ-CHAT", "Pacific/Chatham" },
+        { "Navajo", "America/Denver" },
+        { "PRC", "Asia/Shanghai" },
+        { "Pacific/Samoa", "Pacific/Pago_Pago" },
+        { "Pacific/Yap", "Pacific/Chuuk" },
+        { "Pacific/Truk", "Pacific/Chuuk" },
+        { "Pacific/Ponape", "Pacific/Pohnpei" },
+        { "Poland", "Europe/Warsaw" },
+        { "Portugal", "Europe/Lisbon" },
+        { "ROC", "Asia/Taipei" },
+        { "ROK", "Asia/Seoul" },
+        { "Singapore", "Asia/Singapore" },
+        { "Turkey", "Europe/Istanbul" },
+        { "UCT", "Etc/UCT" },
+        { "US/Alaska", "America/Anchorage" },
+        { "US/Aleutian", "America/Adak" },
+        { "US/Arizona", "America/Phoenix" },
+        { "US/Central", "America/Chicago" },
+        { "US/East-Indiana", "America/Indiana/Indianapolis" },
+        { "US/Eastern", "America/New_York" },
+        { "US/Hawaii", "Pacific/Honolulu" },
+        { "US/Indiana-Starke", "America/Indiana/Knox" },
+        { "US/Michigan", "America/Detroit" },
+        { "US/Mountain", "America/Denver" },
+        { "US/Pacific", "America/Los_Angeles" },
+        { "US/Samoa", "Pacific/Pago_Pago" },
+        { "UTC", "Etc/UTC" },
+        { "Universal", "Etc/UTC" },
+        { "W-SU", "Europe/Moscow" },
+        { "Zulu", "Etc/UTC" },
+    };
+
+    for (size_t i = 0; i < arraysize(link_data); ++i)
+      map_[link_data[i].old_code] = map_[link_data[i].new_code];
+  }
+
+  friend struct DefaultSingletonTraits<TimezoneMap>;
+
+  struct CompareCStrings {
+    bool operator()(const char* str1, const char* str2) const {
+      return strcmp(str1, str2) < 0;
+    }
+  };
+  std::map<const char*, const char*, CompareCStrings> map_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimezoneMap);
+};
+
+}  // namespace
+
+std::string CountryCodeForCurrentTimezone() {
+  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+  icu::UnicodeString id;
+  zone->getID(id);
+  string16 olson_code(id.getBuffer(), id.length());
+  return TimezoneMap::GetInstance()->CountryCodeForTimezone(
+      UTF16ToUTF8(olson_code));
+}
+
+}  // namespace base
diff --git a/base/i18n/timezone.h b/base/i18n/timezone.h
new file mode 100644
index 0000000..f7fda94
--- /dev/null
+++ b/base/i18n/timezone.h
@@ -0,0 +1,21 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_TIMEZONE_H_
+#define BASE_I18N_TIMEZONE_H_
+
+#include <string>
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Checks the system timezone and turns it into a two-character ASCII country
+// code. This may fail (for example, it will always fail on Android), in which
+// case it will return an empty string.
+BASE_I18N_EXPORT std::string CountryCodeForCurrentTimezone();
+
+}  // namespace base
+
+#endif  // BASE_I18N_TIMEZONE_H_
diff --git a/base/i18n/timezone_unittest.cc b/base/i18n/timezone_unittest.cc
new file mode 100644
index 0000000..2cdcc42
--- /dev/null
+++ b/base/i18n/timezone_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/timezone.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(TimezoneTest, CountryCodeForCurrentTimezone) {
+  std::string country_code = CountryCodeForCurrentTimezone();
+  // On some systems (such as Android or some flavors of Linux), icu may come up
+  // empty.
+  if (!country_code.empty())
+    EXPECT_EQ(2U, country_code.size());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/utf8_validator_tables.cc b/base/i18n/utf8_validator_tables.cc
new file mode 100644
index 0000000..8dfa10c
--- /dev/null
+++ b/base/i18n/utf8_validator_tables.cc
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated by build_utf8_validator_tables.
+// DO NOT EDIT.
+
+#include "base/i18n/utf8_validator_tables.h"
+
+namespace base {
+namespace internal {
+
+const uint8 kUtf8ValidatorTables[] = {
+    // State 0, offset 0x00
+    0x00, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x08
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x10
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x18
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x20
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x28
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x30
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x38
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x40
+    0x81, 0x81, 0x81, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x48
+    0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x50
+    0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x58
+    0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x60
+    0x83, 0x86, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,  // 0x68
+    0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8e, 0x8b,  // 0x70
+    0x8b, 0x93, 0x9c, 0x9c, 0x9c, 0x9f, 0x81, 0x81,  // 0x78
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x80
+    0x81,                                            // 0x81
+    // State 1, offset 0x81
+    0x07, 0x81,                                      // 0x83
+    // State 2, offset 0x83
+    0x06, 0x00, 0x81,                                // 0x86
+    // State 3, offset 0x86
+    0x05, 0x81, 0x83, 0x81, 0x81,                    // 0x8b
+    // State 4, offset 0x8b
+    0x06, 0x83, 0x81,                                // 0x8e
+    // State 5, offset 0x8e
+    0x05, 0x83, 0x81, 0x81, 0x81,                    // 0x93
+    // State 6, offset 0x93
+    0x04, 0x81, 0x8b, 0x8b, 0x8b, 0x81, 0x81, 0x81,  // 0x9b
+    0x81,                                            // 0x9c
+    // State 7, offset 0x9c
+    0x06, 0x8b, 0x81,                                // 0x9f
+    // State 8, offset 0x9f
+    0x04, 0x8b, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0xa7
+    0x81,                                            // 0xa8
+};
+
+const size_t kUtf8ValidatorTablesSize = arraysize(kUtf8ValidatorTables);
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/i18n/utf8_validator_tables.h b/base/i18n/utf8_validator_tables.h
new file mode 100644
index 0000000..b7db56e
--- /dev/null
+++ b/base/i18n/utf8_validator_tables.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_UTF8_VALIDATOR_TABLES_H_
+#define BASE_I18N_UTF8_VALIDATOR_TABLES_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace internal {
+
+// The tables for all states; a list of entries of the form (right_shift,
+// next_state, next_state, ....). The right_shifts are used to reduce the
+// overall size of the table. The table only covers bytes in the range
+// [0x80, 0xFF] to save space.
+extern const uint8 kUtf8ValidatorTables[];
+
+extern const size_t kUtf8ValidatorTablesSize;
+
+// The offset of the INVALID state in kUtf8ValidatorTables.
+enum {
+  I18N_UTF8_VALIDATOR_INVALID_INDEX = 129
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_I18N_UTF8_VALIDATOR_TABLES_H_
diff --git a/base/id_map.h b/base/id_map.h
new file mode 100644
index 0000000..852c138
--- /dev/null
+++ b/base/id_map.h
@@ -0,0 +1,279 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ID_MAP_H_
+#define BASE_ID_MAP_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/threading/non_thread_safe.h"
+
+// Ownership semantics - own pointer means the pointer is deleted in Remove()
+// & during destruction
+enum IDMapOwnershipSemantics {
+  IDMapExternalPointer,
+  IDMapOwnPointer
+};
+
+// This object maintains a list of IDs that can be quickly converted to
+// pointers to objects. It is implemented as a hash table, optimized for
+// relatively small data sets (in the common case, there will be exactly one
+// item in the list).
+//
+// Items can be inserted into the container with arbitrary ID, but the caller
+// must ensure they are unique. Inserting IDs and relying on automatically
+// generated ones is not allowed because they can collide.
+//
+// This class does not have a virtual destructor, do not inherit from it when
+// ownership semantics are set to own because pointers will leak.
+template<typename T, IDMapOwnershipSemantics OS = IDMapExternalPointer>
+class IDMap : public base::NonThreadSafe {
+ public:
+  typedef int32 KeyType;
+
+ private:
+  typedef base::hash_map<KeyType, T*> HashTable;
+
+ public:
+  IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
+    // A number of consumers of IDMap create it on one thread but always access
+    // it from a different, but consitent, thread post-construction.
+    DetachFromThread();
+  }
+
+  ~IDMap() {
+    // Many IDMap's are static, and hence will be destroyed on the main thread.
+    // However, all the accesses may take place on another thread, such as the
+    // IO thread. Detaching again to clean this up.
+    DetachFromThread();
+    Releaser<OS, 0>::release_all(&data_);
+  }
+
+  // Sets whether Add and Replace should DCHECK if passed in NULL data.
+  // Default is false.
+  void set_check_on_null_data(bool value) { check_on_null_data_ = value; }
+
+  // Adds a view with an automatically generated unique ID. See AddWithID.
+  KeyType Add(T* data) {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!check_on_null_data_ || data);
+    KeyType this_id = next_id_;
+    DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
+    data_[this_id] = data;
+    next_id_++;
+    return this_id;
+  }
+
+  // Adds a new data member with the specified ID. The ID must not be in
+  // the list. The caller either must generate all unique IDs itself and use
+  // this function, or allow this object to generate IDs and call Add. These
+  // two methods may not be mixed, or duplicate IDs may be generated
+  void AddWithID(T* data, KeyType id) {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!check_on_null_data_ || data);
+    DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
+    data_[id] = data;
+  }
+
+  void Remove(KeyType id) {
+    DCHECK(CalledOnValidThread());
+    typename HashTable::iterator i = data_.find(id);
+    if (i == data_.end()) {
+      NOTREACHED() << "Attempting to remove an item not in the list";
+      return;
+    }
+
+    if (iteration_depth_ == 0) {
+      Releaser<OS, 0>::release(i->second);
+      data_.erase(i);
+    } else {
+      removed_ids_.insert(id);
+    }
+  }
+
+  // Replaces the value for |id| with |new_data| and returns a pointer to the
+  // existing value. If there is no entry for |id|, the map is not altered and
+  // nullptr is returned. The OwnershipSemantics of the map have no effect on
+  // how the existing value is treated, the IDMap does not delete the existing
+  // value being replaced.
+  T* Replace(KeyType id, T* new_data) {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!check_on_null_data_ || new_data);
+    typename HashTable::iterator i = data_.find(id);
+    if (i == data_.end()) {
+      NOTREACHED() << "Attempting to replace an item not in the list";
+      return nullptr;
+    }
+
+    T* temp = i->second;
+    i->second = new_data;
+    return temp;
+  }
+
+  void Clear() {
+    DCHECK(CalledOnValidThread());
+    if (iteration_depth_ == 0) {
+      Releaser<OS, 0>::release_all(&data_);
+    } else {
+      for (typename HashTable::iterator i = data_.begin();
+           i != data_.end(); ++i)
+        removed_ids_.insert(i->first);
+    }
+  }
+
+  bool IsEmpty() const {
+    DCHECK(CalledOnValidThread());
+    return size() == 0u;
+  }
+
+  T* Lookup(KeyType id) const {
+    DCHECK(CalledOnValidThread());
+    typename HashTable::const_iterator i = data_.find(id);
+    if (i == data_.end())
+      return NULL;
+    return i->second;
+  }
+
+  size_t size() const {
+    DCHECK(CalledOnValidThread());
+    return data_.size() - removed_ids_.size();
+  }
+
+#if defined(UNIT_TEST)
+  int iteration_depth() const {
+    return iteration_depth_;
+  }
+#endif  // defined(UNIT_TEST)
+
+  // It is safe to remove elements from the map during iteration. All iterators
+  // will remain valid.
+  template<class ReturnType>
+  class Iterator {
+   public:
+    Iterator(IDMap<T, OS>* map)
+        : map_(map),
+          iter_(map_->data_.begin()) {
+      Init();
+    }
+
+    Iterator(const Iterator& iter)
+        : map_(iter.map_),
+          iter_(iter.iter_) {
+      Init();
+    }
+
+    const Iterator& operator=(const Iterator& iter) {
+      map_ = iter.map;
+      iter_ = iter.iter;
+      Init();
+      return *this;
+    }
+
+    ~Iterator() {
+      DCHECK(map_->CalledOnValidThread());
+
+      // We're going to decrement iteration depth. Make sure it's greater than
+      // zero so that it doesn't become negative.
+      DCHECK_LT(0, map_->iteration_depth_);
+
+      if (--map_->iteration_depth_ == 0)
+        map_->Compact();
+    }
+
+    bool IsAtEnd() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_ == map_->data_.end();
+    }
+
+    KeyType GetCurrentKey() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_->first;
+    }
+
+    ReturnType* GetCurrentValue() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_->second;
+    }
+
+    void Advance() {
+      DCHECK(map_->CalledOnValidThread());
+      ++iter_;
+      SkipRemovedEntries();
+    }
+
+   private:
+    void Init() {
+      DCHECK(map_->CalledOnValidThread());
+      ++map_->iteration_depth_;
+      SkipRemovedEntries();
+    }
+
+    void SkipRemovedEntries() {
+      while (iter_ != map_->data_.end() &&
+             map_->removed_ids_.find(iter_->first) !=
+             map_->removed_ids_.end()) {
+        ++iter_;
+      }
+    }
+
+    IDMap<T, OS>* map_;
+    typename HashTable::const_iterator iter_;
+  };
+
+  typedef Iterator<T> iterator;
+  typedef Iterator<const T> const_iterator;
+
+ private:
+
+  // The dummy parameter is there because C++ standard does not allow
+  // explicitly specialized templates inside classes
+  template<IDMapOwnershipSemantics OI, int dummy> struct Releaser {
+    static inline void release(T* ptr) {}
+    static inline void release_all(HashTable* table) {}
+  };
+
+  template<int dummy> struct Releaser<IDMapOwnPointer, dummy> {
+    static inline void release(T* ptr) { delete ptr;}
+    static inline void release_all(HashTable* table) {
+      for (typename HashTable::iterator i = table->begin();
+           i != table->end(); ++i) {
+        delete i->second;
+      }
+      table->clear();
+    }
+  };
+
+  void Compact() {
+    DCHECK_EQ(0, iteration_depth_);
+    for (std::set<KeyType>::const_iterator i = removed_ids_.begin();
+         i != removed_ids_.end(); ++i) {
+      Remove(*i);
+    }
+    removed_ids_.clear();
+  }
+
+  // Keep track of how many iterators are currently iterating on us to safely
+  // handle removing items during iteration.
+  int iteration_depth_;
+
+  // Keep set of IDs that should be removed after the outermost iteration has
+  // finished. This way we manage to not invalidate the iterator when an element
+  // is removed.
+  std::set<KeyType> removed_ids_;
+
+  // The next ID that we will return from Add()
+  KeyType next_id_;
+
+  HashTable data_;
+
+  // See description above setter.
+  bool check_on_null_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(IDMap);
+};
+
+#endif  // BASE_ID_MAP_H_
diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc
new file mode 100644
index 0000000..a9fb2b9
--- /dev/null
+++ b/base/id_map_unittest.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/id_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestObject {
+};
+
+class DestructorCounter {
+ public:
+  explicit DestructorCounter(int* counter) : counter_(counter) {}
+  ~DestructorCounter() { ++(*counter_); }
+
+ private:
+  int* counter_;
+};
+
+TEST(IDMapTest, Basic) {
+  IDMap<TestObject> map;
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  TestObject obj1;
+  TestObject obj2;
+
+  int32 id1 = map.Add(&obj1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+
+  int32 id2 = map.Add(&obj2);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(2U, map.size());
+
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+  EXPECT_EQ(&obj2, map.Lookup(id2));
+
+  map.Remove(id1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+
+  map.Remove(id2);
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  map.AddWithID(&obj1, 1);
+  map.AddWithID(&obj2, 2);
+  EXPECT_EQ(&obj1, map.Lookup(1));
+  EXPECT_EQ(&obj2, map.Lookup(2));
+
+  EXPECT_EQ(&obj2, map.Replace(2, &obj1));
+  EXPECT_EQ(&obj1, map.Lookup(2));
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  {
+    IDMap<TestObject>::const_iterator iter(&map);
+
+    EXPECT_EQ(1, map.iteration_depth());
+
+    while (!iter.IsAtEnd()) {
+      map.Remove(iter.GetCurrentKey());
+      iter.Advance();
+    }
+
+    // Test that while an iterator is still in scope, we get the map emptiness
+    // right (http://crbug.com/35571).
+    EXPECT_TRUE(map.IsEmpty());
+    EXPECT_EQ(0U, map.size());
+  }
+
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+
+  for (int i = 0; i < kCount; i++)
+    map.Add(&obj[i]);
+
+  // IDMap uses a hash_map, which has no predictable iteration order.
+  int32 ids_in_iteration_order[kCount];
+  const TestObject* objs_in_iteration_order[kCount];
+  int counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    ids_in_iteration_order[counter] = iter.GetCurrentKey();
+    objs_in_iteration_order[counter] = iter.GetCurrentValue();
+    counter++;
+  }
+
+  counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    EXPECT_EQ(1, map.iteration_depth());
+
+    switch (counter) {
+      case 0:
+        EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue());
+        map.Remove(ids_in_iteration_order[1]);
+        break;
+      case 1:
+        EXPECT_EQ(ids_in_iteration_order[2], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[2], iter.GetCurrentValue());
+        map.Remove(ids_in_iteration_order[3]);
+        break;
+      case 2:
+        EXPECT_EQ(ids_in_iteration_order[4], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[4], iter.GetCurrentValue());
+        map.Remove(ids_in_iteration_order[0]);
+        break;
+      default:
+        FAIL() << "should not have that many elements";
+        break;
+    }
+
+    counter++;
+  }
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, CopyIterator) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  EXPECT_EQ(0, map.iteration_depth());
+
+  {
+    IDMap<TestObject>::const_iterator iter1(&map);
+    EXPECT_EQ(1, map.iteration_depth());
+
+    // Make sure that copying the iterator correctly increments
+    // map's iteration depth.
+    IDMap<TestObject>::const_iterator iter2(iter1);
+    EXPECT_EQ(2, map.iteration_depth());
+  }
+
+  // Make sure after destroying all iterators the map's iteration depth
+  // returns to initial state.
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, AssignIterator) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  EXPECT_EQ(0, map.iteration_depth());
+
+  {
+    IDMap<TestObject>::const_iterator iter1(&map);
+    EXPECT_EQ(1, map.iteration_depth());
+
+    IDMap<TestObject>::const_iterator iter2(&map);
+    EXPECT_EQ(2, map.iteration_depth());
+
+    // Make sure that assigning the iterator correctly updates
+    // map's iteration depth (-1 for destruction, +1 for assignment).
+    EXPECT_EQ(2, map.iteration_depth());
+  }
+
+  // Make sure after destroying all iterators the map's iteration depth
+  // returns to initial state.
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenClearing) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+
+  for (int i = 0; i < kCount; i++)
+    map.Add(&obj[i]);
+
+  // IDMap uses a hash_map, which has no predictable iteration order.
+  int32 ids_in_iteration_order[kCount];
+  const TestObject* objs_in_iteration_order[kCount];
+  int counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    ids_in_iteration_order[counter] = iter.GetCurrentKey();
+    objs_in_iteration_order[counter] = iter.GetCurrentValue();
+    counter++;
+  }
+
+  counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    switch (counter) {
+      case 0:
+        EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue());
+        break;
+      case 1:
+        EXPECT_EQ(ids_in_iteration_order[1], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[1], iter.GetCurrentValue());
+        map.Clear();
+        EXPECT_TRUE(map.IsEmpty());
+        EXPECT_EQ(0U, map.size());
+        break;
+      default:
+        FAIL() << "should not have that many elements";
+        break;
+    }
+    counter++;
+  }
+
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnRemove) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+  int map_external_ids[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+  int map_owned_ids[kCount];
+
+  IDMap<DestructorCounter> map_external;
+  IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+  for (int i = 0; i < kCount; ++i) {
+    external_obj[i] = new DestructorCounter(&external_del_count);
+    map_external_ids[i] = map_external.Add(external_obj[i]);
+
+    owned_obj[i] = new DestructorCounter(&owned_del_count);
+    map_owned_ids[i] = map_owned.Add(owned_obj[i]);
+  }
+
+  for (int i = 0; i < kCount; ++i) {
+    EXPECT_EQ(external_del_count, 0);
+    EXPECT_EQ(owned_del_count, i);
+
+    map_external.Remove(map_external_ids[i]);
+    map_owned.Remove(map_owned_ids[i]);
+  }
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnClear) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  IDMap<DestructorCounter> map_external;
+  IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+  for (int i = 0; i < kCount; ++i) {
+    external_obj[i] = new DestructorCounter(&external_del_count);
+    map_external.Add(external_obj[i]);
+
+    owned_obj[i] = new DestructorCounter(&owned_del_count);
+    map_owned.Add(owned_obj[i]);
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+  EXPECT_EQ(owned_del_count, 0);
+
+  map_external.Clear();
+  map_owned.Clear();
+
+  EXPECT_EQ(external_del_count, 0);
+  EXPECT_EQ(owned_del_count, kCount);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  {
+    IDMap<DestructorCounter> map_external;
+    IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+    for (int i = 0; i < kCount; ++i) {
+      external_obj[i] = new DestructorCounter(&external_del_count);
+      map_external.Add(external_obj[i]);
+
+      owned_obj[i] = new DestructorCounter(&owned_del_count);
+      map_owned.Add(owned_obj[i]);
+    }
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+}  // namespace
diff --git a/base/ios/OWNERS b/base/ios/OWNERS
new file mode 100644
index 0000000..6256400
--- /dev/null
+++ b/base/ios/OWNERS
@@ -0,0 +1,3 @@
+qsr@chromium.org
+rohitrao@chromium.org
+stuartmorgan@chromium.org
diff --git a/base/ios/block_types.h b/base/ios/block_types.h
new file mode 100644
index 0000000..e4dde79
--- /dev/null
+++ b/base/ios/block_types.h
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_BLOCK_TYPES_H_
+#define BASE_IOS_BLOCK_TYPES_H_
+
+// A generic procedural block type that takes no arguments and returns nothing.
+typedef void (^ProceduralBlock)(void);
+
+// A block that takes no arguments and returns a bool.
+typedef bool (^ConditionBlock)(void);
+
+#endif  // BASE_IOS_BLOCK_TYPES_H_
diff --git a/base/ios/crb_protocol_observers.h b/base/ios/crb_protocol_observers.h
new file mode 100644
index 0000000..15d1656
--- /dev/null
+++ b/base/ios/crb_protocol_observers.h
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
+#define BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
+
+#import <Foundation/Foundation.h>
+
+typedef void (^ExecutionWithObserverBlock)(id);
+
+// Implements a container for observers that implement a specific Objective-C
+// protocol. The container forwards method invocations to its contained
+// observers, so that sending a message to all the observers is as simple as
+// sending the message to the container.
+@interface CRBProtocolObservers : NSObject
+
+// The Objective-C protocol that the observers in this container conform to.
+@property(nonatomic, readonly) Protocol* protocol;
+
+// Returns a CRBProtocolObservers container for observers that conform to
+// |protocol|.
++ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol;
+
+// Adds |observer| to this container.
+- (void)addObserver:(id)observer;
+
+// Remove |observer| from this container.
+- (void)removeObserver:(id)observer;
+
+// Executes callback on every observer. |callback| cannot be nil.
+- (void)executeOnObservers:(ExecutionWithObserverBlock)callback;
+
+@end
+
+#endif  // BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
diff --git a/base/ios/crb_protocol_observers.mm b/base/ios/crb_protocol_observers.mm
new file mode 100644
index 0000000..ee9e23f
--- /dev/null
+++ b/base/ios/crb_protocol_observers.mm
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/ios/crb_protocol_observers.h"
+
+#include <objc/runtime.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+@interface CRBProtocolObservers ()
+
+// Designated initializer.
+- (id)initWithProtocol:(Protocol*)protocol;
+
+@end
+
+@implementation CRBProtocolObservers {
+  base::scoped_nsobject<Protocol> _protocol;
+  base::scoped_nsobject<NSHashTable> _observers;
+}
+
++ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol {
+  return [[[self alloc] initWithProtocol:protocol] autorelease];
+}
+
+- (id)init {
+  NOTREACHED();
+  return nil;
+}
+
+- (id)initWithProtocol:(Protocol*)protocol {
+  self = [super init];
+  if (self) {
+    _protocol.reset([protocol retain]);
+    _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
+  }
+  return self;
+}
+
+- (Protocol*)protocol {
+  return _protocol.get();
+}
+
+- (void)addObserver:(id)observer {
+  DCHECK([observer conformsToProtocol:self.protocol]);
+  [_observers addObject:observer];
+}
+
+- (void)removeObserver:(id)observer {
+  [_observers removeObject:observer];
+}
+
+#pragma mark - NSObject
+
+- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
+  NSMethodSignature* signature = [super methodSignatureForSelector:selector];
+  if (signature)
+    return signature;
+
+  // Look for a required method in the protocol. protocol_getMethodDescription
+  // returns a struct whose fields are null if a method for the selector was
+  // not found.
+  struct objc_method_description description =
+      protocol_getMethodDescription(self.protocol, selector, YES, YES);
+  if (description.types)
+    return [NSMethodSignature signatureWithObjCTypes:description.types];
+
+  // Look for an optional method in the protocol.
+  description = protocol_getMethodDescription(self.protocol, selector, NO, YES);
+  if (description.types)
+    return [NSMethodSignature signatureWithObjCTypes:description.types];
+
+  // There is neither a required nor optional method with this selector in the
+  // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
+  // NSInvalidArgumentException.
+  [self doesNotRecognizeSelector:selector];
+  return nil;
+}
+
+- (void)forwardInvocation:(NSInvocation*)invocation {
+  SEL selector = [invocation selector];
+  base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
+  for (id observer in observers.get()) {
+    if ([observer respondsToSelector:selector])
+      [invocation invokeWithTarget:observer];
+  }
+}
+
+- (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
+  DCHECK(callback);
+  base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
+  for (id observer in observers.get()) {
+    callback(observer);
+  }
+}
+
+@end
diff --git a/base/ios/crb_protocol_observers_unittest.mm b/base/ios/crb_protocol_observers_unittest.mm
new file mode 100644
index 0000000..d235c98
--- /dev/null
+++ b/base/ios/crb_protocol_observers_unittest.mm
@@ -0,0 +1,159 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/ios/crb_protocol_observers.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+@protocol TestObserver
+
+@required
+- (void)requiredMethod;
+- (void)reset;
+
+@optional
+- (void)optionalMethod;
+
+@end
+
+// Implements only the required methods in the TestObserver protocol.
+@interface TestPartialObserver : NSObject<TestObserver>
+@property(nonatomic, readonly) BOOL requiredMethodInvoked;
+@end
+
+// Implements all the methods in the TestObserver protocol.
+@interface TestCompleteObserver : TestPartialObserver<TestObserver>
+@property(nonatomic, readonly) BOOL optionalMethodInvoked;
+@end
+
+namespace {
+
+class CRBProtocolObserversTest : public PlatformTest {
+ public:
+  CRBProtocolObserversTest() {}
+
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+
+    observers_.reset([[CRBProtocolObservers observersWithProtocol:
+        @protocol(TestObserver)] retain]);
+
+    partial_observer_.reset([[TestPartialObserver alloc] init]);
+    EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+    complete_observer_.reset([[TestCompleteObserver alloc] init]);
+    EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
+    EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
+  }
+
+  base::scoped_nsobject<id> observers_;
+  base::scoped_nsobject<TestPartialObserver> partial_observer_;
+  base::scoped_nsobject<TestCompleteObserver> complete_observer_;
+};
+
+// Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
+// -[CRBProtocolObservers removeObserver:].
+TEST_F(CRBProtocolObserversTest, AddRemoveObserver) {
+  // Add an observer and verify that the CRBProtocolObservers instance forwards
+  // an invocation to it.
+  [observers_ addObserver:partial_observer_];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [partial_observer_ reset];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Remove the observer and verify that the CRBProtocolObservers instance no
+  // longer forwards an invocation to it.
+  [observers_ removeObserver:partial_observer_];
+  [observers_ requiredMethod];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers correctly forwards the invocation of a
+// required method in the protocol.
+TEST_F(CRBProtocolObserversTest, RequiredMethods) {
+  [observers_ addObserver:partial_observer_];
+  [observers_ addObserver:complete_observer_];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([complete_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers correctly forwards the invocation of an
+// optional method in the protocol.
+TEST_F(CRBProtocolObserversTest, OptionalMethods) {
+  [observers_ addObserver:partial_observer_];
+  [observers_ addObserver:complete_observer_];
+  [observers_ optionalMethod];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([complete_observer_ optionalMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers only holds a weak reference to an
+// observer.
+TEST_F(CRBProtocolObserversTest, WeakReference) {
+  base::WeakNSObject<TestPartialObserver> weak_observer(
+      partial_observer_);
+  EXPECT_TRUE(weak_observer);
+
+  [observers_ addObserver:partial_observer_];
+
+  {
+    // Need an autorelease pool here, because
+    // -[CRBProtocolObservers forwardInvocation:] creates a temporary
+    // autoreleased array that holds all the observers.
+    base::mac::ScopedNSAutoreleasePool pool;
+    [observers_ requiredMethod];
+    EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+  }
+
+  partial_observer_.reset();
+  EXPECT_FALSE(weak_observer.get());
+}
+
+}  // namespace
+
+@implementation TestPartialObserver {
+  BOOL _requiredMethodInvoked;
+}
+
+- (BOOL)requiredMethodInvoked {
+  return _requiredMethodInvoked;
+}
+
+- (void)requiredMethod {
+  _requiredMethodInvoked = YES;
+}
+
+- (void)reset {
+  _requiredMethodInvoked = NO;
+}
+
+@end
+
+@implementation TestCompleteObserver {
+  BOOL _optionalMethodInvoked;
+}
+
+- (BOOL)optionalMethodInvoked {
+  return _optionalMethodInvoked;
+}
+
+- (void)optionalMethod {
+  _optionalMethodInvoked = YES;
+}
+
+- (void)reset {
+  [super reset];
+  _optionalMethodInvoked = NO;
+}
+
+@end
diff --git a/base/ios/device_util.h b/base/ios/device_util.h
new file mode 100644
index 0000000..1cd9a04
--- /dev/null
+++ b/base/ios/device_util.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_DEVICE_UTIL_H_
+#define BASE_IOS_DEVICE_UTIL_H_
+
+#include <string>
+
+namespace ios {
+namespace device_util {
+
+// Returns the hardware version of the device the app is running on.
+//
+// The returned string is the string returned by sysctlbyname() with name
+// "hw.machine". Possible (known) values include:
+//
+// iPhone1,1 -> iPhone 1G
+// iPhone1,2 -> iPhone 3G
+// iPhone2,1 -> iPhone 3GS
+// iPhone3,1 -> iPhone 4/AT&T
+// iPhone3,2 -> iPhone 4/Other Carrier?
+// iPhone3,3 -> iPhone 4/Other Carrier?
+// iPhone4,1 -> iPhone 4S
+//
+// iPod1,1   -> iPod touch 1G
+// iPod2,1   -> iPod touch 2G
+// iPod2,2   -> ?
+// iPod3,1   -> iPod touch 3G
+// iPod4,1   -> iPod touch 4G
+// iPod5,1   -> ?
+//
+// iPad1,1   -> iPad 1G, WiFi
+// iPad1,?   -> iPad 1G, 3G <- needs 3G owner to test
+// iPad2,1   -> iPad 2G, WiFi
+//
+// AppleTV2,1 -> AppleTV 2
+//
+// i386       -> Simulator
+// x86_64     -> Simulator
+std::string GetPlatform();
+
+// Returns true if the application is running on a device with 512MB or more
+// RAM.
+bool RamIsAtLeast512Mb();
+
+// Returns true if the application is running on a device with 1024MB or more
+// RAM.
+bool RamIsAtLeast1024Mb();
+
+// Returns true if the application is running on a device with |ram_in_mb| MB or
+// more RAM.
+// Use with caution! Actual RAM reported by devices is less than the commonly
+// used powers-of-two values. For example, a 512MB device may report only 502MB
+// RAM. The convenience methods above should be used in most cases because they
+// correctly handle this issue.
+bool RamIsAtLeast(uint64_t ram_in_mb);
+
+// Returns true if the device has only one core.
+bool IsSingleCoreDevice();
+
+// Returns the MAC address of the interface with name |interface_name|.
+std::string GetMacAddress(const std::string& interface_name);
+
+// Returns a random UUID.
+std::string GetRandomId();
+
+// Returns an identifier for the device, using the given |salt|. A global
+// identifier is generated the first time this method is called, and the salt
+// is used to be able to generate distinct identifiers for the same device. If
+// |salt| is NULL, a default value is used. Unless you are using this value for
+// something that should be anonymous, you should probably pass NULL.
+std::string GetDeviceIdentifier(const char* salt);
+
+// Returns a hashed version of |in_string| using |salt| (which must not be
+// zero-length). Different salt values should result in differently hashed
+// strings.
+std::string GetSaltedString(const std::string& in_string,
+                            const std::string& salt);
+
+}  // namespace device_util
+}  // namespace ios
+
+#endif  // BASE_IOS_DEVICE_UTIL_H_
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm
new file mode 100644
index 0000000..1234562
--- /dev/null
+++ b/base/ios/device_util.mm
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/device_util.h"
+
+#include <CommonCrypto/CommonDigest.h>
+#import <UIKit/UIKit.h>
+
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace {
+
+// Client ID key in the user preferences.
+NSString* const kLegacyClientIdPreferenceKey = @"ChromiumClientID";
+NSString* const kClientIdPreferenceKey = @"ChromeClientID";
+// Current hardware type. This is used to detect that a device has been backed
+// up and restored to another device, and allows regenerating a new device id.
+NSString* const kHardwareTypePreferenceKey = @"ClientIDGenerationHardwareType";
+// Default salt for device ids.
+const char kDefaultSalt[] = "Salt";
+// Zero UUID returned on buggy iOS devices.
+NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000";
+
+NSString* GenerateClientId() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+  // Try to migrate from legacy client id.
+  NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey];
+
+  // Some iOS6 devices return a buggy identifierForVendor:
+  // http://openradar.appspot.com/12377282. If this is the case, revert to
+  // generating a new one.
+  if (!client_id || [client_id isEqualToString:kZeroUUID]) {
+    client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
+    if ([client_id isEqualToString:kZeroUUID])
+      client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
+  }
+  return client_id;
+}
+
+}  // namespace
+
+namespace ios {
+namespace device_util {
+
+std::string GetPlatform() {
+  std::string platform;
+  size_t size = 0;
+  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+  sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
+  return platform;
+}
+
+bool RamIsAtLeast512Mb() {
+  // 512MB devices report anywhere from 502-504 MB, use 450 MB just to be safe.
+  return RamIsAtLeast(450);
+}
+
+bool RamIsAtLeast1024Mb() {
+  // 1GB devices report anywhere from 975-999 MB, use 900 MB just to be safe.
+  return RamIsAtLeast(900);
+}
+
+bool RamIsAtLeast(uint64_t ram_in_mb) {
+  uint64_t memory_size = 0;
+  size_t size = sizeof(memory_size);
+  if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
+    // Anything >= 500M, call high ram.
+    return memory_size >= ram_in_mb * 1024 * 1024;
+  }
+  return false;
+}
+
+bool IsSingleCoreDevice() {
+  uint64_t cpu_number = 0;
+  size_t sizes = sizeof(cpu_number);
+  sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
+  return cpu_number == 1;
+}
+
+std::string GetMacAddress(const std::string& interface_name) {
+  std::string mac_string;
+  struct ifaddrs* addresses;
+  if (getifaddrs(&addresses) == 0) {
+    for (struct ifaddrs* address = addresses; address;
+         address = address->ifa_next) {
+      if ((address->ifa_addr->sa_family == AF_LINK) &&
+          strcmp(interface_name.c_str(), address->ifa_name) == 0) {
+        const struct sockaddr_dl* found_address_struct =
+            reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);
+
+        // |found_address_struct->sdl_data| contains the interface name followed
+        // by the interface address. The address part can be accessed based on
+        // the length of the name, that is, |found_address_struct->sdl_nlen|.
+        const unsigned char* found_address =
+            reinterpret_cast<const unsigned char*>(
+                &found_address_struct->sdl_data[
+                    found_address_struct->sdl_nlen]);
+
+        int found_address_length = found_address_struct->sdl_alen;
+        for (int i = 0; i < found_address_length; ++i) {
+          if (i != 0)
+            mac_string.push_back(':');
+          base::StringAppendF(&mac_string, "%02X", found_address[i]);
+        }
+        break;
+      }
+    }
+    freeifaddrs(addresses);
+  }
+  return mac_string;
+}
+
+std::string GetRandomId() {
+  base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
+      CFUUIDCreate(kCFAllocatorDefault));
+  base::ScopedCFTypeRef<CFStringRef> uuid_string(
+      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
+  return base::SysCFStringRefToUTF8(uuid_string);
+}
+
+std::string GetDeviceIdentifier(const char* salt) {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+  NSString* last_seen_hardware =
+      [defaults stringForKey:kHardwareTypePreferenceKey];
+  NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform());
+  if (!last_seen_hardware) {
+    last_seen_hardware = current_hardware;
+    [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
+    [defaults synchronize];
+  }
+
+  NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];
+
+  if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) {
+    client_id = GenerateClientId();
+    [defaults setObject:client_id forKey:kClientIdPreferenceKey];
+    [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
+    [defaults synchronize];
+  }
+
+  return GetSaltedString(base::SysNSStringToUTF8(client_id),
+                         salt ? salt : kDefaultSalt);
+}
+
+std::string GetSaltedString(const std::string& in_string,
+                            const std::string& salt) {
+  DCHECK(salt.length());
+  NSData* hash_data = [base::SysUTF8ToNSString(in_string + salt)
+      dataUsingEncoding:NSUTF8StringEncoding];
+
+  unsigned char hash[CC_SHA256_DIGEST_LENGTH];
+  CC_SHA256([hash_data bytes], [hash_data length], hash);
+  CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);
+
+  base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
+      CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
+  base::ScopedCFTypeRef<CFStringRef> device_id(
+      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
+  return base::SysCFStringRefToUTF8(device_id);
+}
+
+}  // namespace device_util
+}  // namespace ios
diff --git a/base/ios/device_util_unittest.mm b/base/ios/device_util_unittest.mm
new file mode 100644
index 0000000..82d4217
--- /dev/null
+++ b/base/ios/device_util_unittest.mm
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+#include "base/ios/device_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+namespace {
+// The behavior of most of these utility functions depends on what they are run
+// on, so there is not much to unittest them. The APIs are run to make sure they
+// don't choke. Additional checks are added for particular APIs when needed.
+
+typedef PlatformTest DeviceUtilTest;
+
+void CleanNSUserDefaultsForDeviceId() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults removeObjectForKey:@"ChromiumClientID"];
+  [defaults removeObjectForKey:@"ClientIDGenerationHardwareType"];
+  [defaults synchronize];
+}
+
+TEST_F(DeviceUtilTest, GetPlatform) {
+  GTEST_ASSERT_GT(ios::device_util::GetPlatform().length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, IsSingleCoreDevice) {
+  ios::device_util::IsSingleCoreDevice();
+}
+
+TEST_F(DeviceUtilTest, GetMacAddress) {
+  GTEST_ASSERT_GT(ios::device_util::GetMacAddress("en0").length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, GetRandomId) {
+  GTEST_ASSERT_GT(ios::device_util::GetRandomId().length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, GetDeviceIdentifier) {
+  CleanNSUserDefaultsForDeviceId();
+
+  std::string default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  std::string other_id = ios::device_util::GetDeviceIdentifier("ForTest");
+  EXPECT_NE(default_id, other_id);
+
+  CleanNSUserDefaultsForDeviceId();
+
+  std::string new_default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  if (![[[[UIDevice currentDevice] identifierForVendor] UUIDString]
+          isEqualToString:@"00000000-0000-0000-0000-000000000000"]) {
+    EXPECT_EQ(default_id, new_default_id);
+  } else {
+    EXPECT_NE(default_id, new_default_id);
+  }
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, CheckMigration) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string expected_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromiumClientID"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_EQ(expected_id, new_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, CheckMigrationFromZero) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"00000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string zero_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults setObject:@"00000000-0000-0000-0000-000000000000"
+               forKey:@"ChromiumClientID"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_NE(zero_id, new_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, GetSaltedStringEquals) {
+  std::string string1("The quick brown fox jumps over the lazy dog");
+  std::string string2("The quick brown fox jumps over the lazy dog");
+  std::string salt("salt");
+  // Same string and same salt should result in the same salted string.
+  EXPECT_EQ(ios::device_util::GetSaltedString(string1, salt),
+            ios::device_util::GetSaltedString(string2, salt));
+}
+
+TEST_F(DeviceUtilTest, GetSaltedStringNotEquals) {
+  std::string string1("The quick brown fox jumps over the lazy dog");
+  std::string string2("The lazy brown fox jumps over the quick dog");
+  std::string salt("salt");
+  // Different string and same salt should result in different salted strings.
+  EXPECT_NE(ios::device_util::GetSaltedString(string1, salt),
+            ios::device_util::GetSaltedString(string2, salt));
+}
+
+TEST_F(DeviceUtilTest, GetSaltedStringDifferentSalt) {
+  std::string string1("The quick brown fox jumps over the lazy dog");
+  std::string salt1("salt");
+  std::string salt2("pepper");
+  // Same string with different salt should result in different salted strings.
+  EXPECT_NE(ios::device_util::GetSaltedString(string1, salt1),
+            ios::device_util::GetSaltedString(string1, salt2));
+}
+
+TEST_F(DeviceUtilTest, CheckDeviceMigration) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string base_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults setObject:@"Foo" forKey:@"ClientIDGenerationHardwareType"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_NE(new_id, base_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+}  // namespace
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
new file mode 100644
index 0000000..d9d7e19
--- /dev/null
+++ b/base/ios/ios_util.h
@@ -0,0 +1,23 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_IOS_UTIL_H_
+#define BASE_IOS_IOS_UTIL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace ios {
+
+// Returns whether the operating system is iOS 8 or later.
+BASE_EXPORT bool IsRunningOnIOS8OrLater();
+
+// Returns whether the operating system is at the given version or later.
+BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_IOS_UTIL_H_
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
new file mode 100644
index 0000000..ca0a24d
--- /dev/null
+++ b/base/ios/ios_util.mm
@@ -0,0 +1,38 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/ios_util.h"
+
+#include "base/sys_info.h"
+
+namespace {
+// Return a 3 elements array containing the major, minor and bug fix version of
+// the OS.
+const int32* OSVersionAsArray() {
+  int32* digits = new int32[3];
+  base::SysInfo::OperatingSystemVersionNumbers(
+      &digits[0], &digits[1], &digits[2]);
+  return digits;
+}
+}  // namespace
+
+namespace base {
+namespace ios {
+
+bool IsRunningOnIOS8OrLater() {
+  return IsRunningOnOrLater(8, 0, 0);
+}
+
+bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) {
+  static const int32* current_version = OSVersionAsArray();
+  int32 version[] = { major, minor, bug_fix };
+  for (size_t i = 0; i < arraysize(version); i++) {
+    if (current_version[i] != version[i])
+      return current_version[i] > version[i];
+  }
+  return true;
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h
new file mode 100644
index 0000000..803d587
--- /dev/null
+++ b/base/ios/scoped_critical_action.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_SCOPED_CRITICAL_ACTION_H_
+#define BASE_IOS_SCOPED_CRITICAL_ACTION_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace ios {
+
+// This class attempts to allow the application to continue to run for a period
+// of time after it transitions to the background. The construction of an
+// instance of this class marks the beginning of a task that needs background
+// running time when the application is moved to the background and the
+// destruction marks the end of such a task.
+//
+// Note there is no guarantee that the task will continue to finish when the
+// application is moved to the background.
+//
+// This class should be used at times where leaving a task unfinished might be
+// detrimental to user experience. For example, it should be used to ensure that
+// the application has enough time to save important data or at least attempt to
+// save such data.
+class ScopedCriticalAction {
+ public:
+  ScopedCriticalAction();
+  ~ScopedCriticalAction();
+
+ private:
+  // Core logic; ScopedCriticalAction should not be reference counted so
+  // that it follows the normal pattern of stack-allocating ScopedFoo objects,
+  // but the expiration handler needs to have a reference counted object to
+  // refer to.
+  class Core : public base::RefCountedThreadSafe<Core> {
+   public:
+    Core();
+
+    // Informs the OS that the background task has completed.
+    void EndBackgroundTask();
+
+   private:
+    friend base::RefCountedThreadSafe<Core>;
+    ~Core();
+
+    // |UIBackgroundTaskIdentifier| returned by
+    // |beginBackgroundTaskWithExpirationHandler:| when marking the beginning of
+    // a long-running background task. It is defined as an |unsigned int|
+    // instead of a |UIBackgroundTaskIdentifier| so this class can be used in
+    // .cc files.
+    unsigned int background_task_id_;
+    Lock background_task_id_lock_;
+
+    DISALLOW_COPY_AND_ASSIGN(Core);
+  };
+
+  // The instance of the core that drives the background task.
+  scoped_refptr<Core> core_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCriticalAction);
+};
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_SCOPED_CRITICAL_ACTION_H_
diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm
new file mode 100644
index 0000000..9dad70e
--- /dev/null
+++ b/base/ios/scoped_critical_action.mm
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/scoped_critical_action.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace ios {
+
+ScopedCriticalAction::ScopedCriticalAction()
+    : core_(new ScopedCriticalAction::Core()) {
+}
+
+ScopedCriticalAction::~ScopedCriticalAction() {
+  core_->EndBackgroundTask();
+}
+
+// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when
+// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose
+// execution will continue (temporarily) even after the app is backgrounded.
+ScopedCriticalAction::Core::Core() {
+  scoped_refptr<ScopedCriticalAction::Core> core = this;
+  background_task_id_ = [[UIApplication sharedApplication]
+      beginBackgroundTaskWithExpirationHandler:^{
+        DLOG(WARNING) << "Background task with id " << background_task_id_
+                      << " expired.";
+        // Note if |endBackgroundTask:| is not called for each task before time
+        // expires, the system kills the application.
+        core->EndBackgroundTask();
+      }];
+  if (background_task_id_ == UIBackgroundTaskInvalid) {
+    DLOG(WARNING) <<
+        "beginBackgroundTaskWithExpirationHandler: returned an invalid ID";
+  } else {
+    VLOG(3) << "Beginning background task with id " << background_task_id_;
+  }
+}
+
+ScopedCriticalAction::Core::~Core() {
+  DCHECK_EQ(background_task_id_, UIBackgroundTaskInvalid);
+}
+
+void ScopedCriticalAction::Core::EndBackgroundTask() {
+  UIBackgroundTaskIdentifier task_id;
+  {
+    AutoLock lock_scope(background_task_id_lock_);
+    if (background_task_id_ == UIBackgroundTaskInvalid)
+      return;
+    task_id = background_task_id_;
+    background_task_id_ = UIBackgroundTaskInvalid;
+  }
+
+  VLOG(3) << "Ending background task with id " << task_id;
+  [[UIApplication sharedApplication] endBackgroundTask:task_id];
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/ios/weak_nsobject.h b/base/ios/weak_nsobject.h
new file mode 100644
index 0000000..fc3a7c3
--- /dev/null
+++ b/base/ios/weak_nsobject.h
@@ -0,0 +1,189 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_WEAK_NSOBJECT_H_
+#define BASE_IOS_WEAK_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread_checker.h"
+
+// WeakNSObject<> is patterned after scoped_nsobject<>, but instead of
+// maintaining ownership of an NSObject subclass object, it will nil itself out
+// when the object is deallocated.
+//
+// WeakNSProtocol<> has the same behavior as WeakNSObject, but can be used
+// with protocols.
+//
+// Example usage (base::WeakNSObject<T>):
+//   scoped_nsobject<Foo> foo([[Foo alloc] init]);
+//   WeakNSObject<Foo> weak_foo;  // No pointer
+//   weak_foo.reset(foo)  // Now a weak reference is kept.
+//   [weak_foo description];  // Returns [foo description].
+//   foo.reset();  // The reference is released.
+//   [weak_foo description];  // Returns nil, as weak_foo is pointing to nil.
+//
+//
+// Implementation wise a WeakNSObject keeps a reference to a refcounted
+// WeakContainer. There is one unique instance of a WeakContainer per watched
+// NSObject, this relationship is maintained via the ObjectiveC associated
+// object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class.
+//
+// Threading restrictions:
+// - Several WeakNSObject pointing to the same underlying object must all be
+//   created and dereferenced on the same thread;
+// - thread safety is enforced by the implementation, except in two cases:
+//   (1) it is allowed to copy a WeakNSObject on a different thread. However,
+//       that copy must return to the original thread before being dereferenced,
+//   (2) it is allowed to destroy a WeakNSObject on any thread;
+// - the implementation assumes that the tracked object will be released on the
+//   same thread that the WeakNSObject is created on.
+namespace base {
+
+// WeakContainer keeps a weak pointer to an object and clears it when it
+// receives nullify() from the object's sentinel.
+class WeakContainer : public base::RefCountedThreadSafe<WeakContainer> {
+ public:
+  explicit WeakContainer(id object) : object_(object) {}
+
+  id object() {
+    DCHECK(checker_.CalledOnValidThread());
+    return object_;
+  }
+
+  void nullify() {
+    DCHECK(checker_.CalledOnValidThread());
+    object_ = nil;
+  }
+
+ private:
+  friend base::RefCountedThreadSafe<WeakContainer>;
+  ~WeakContainer() {}
+  base::ThreadChecker checker_;
+  id object_;
+};
+
+}  // namespace base
+
+// Sentinel for observing the object contained in the weak pointer. The object
+// will be deleted when the weak object is deleted and will notify its
+// container.
+@interface CRBWeakNSProtocolSentinel : NSObject
+// Return the only associated container for this object. There can be only one.
+// Will return null if object is nil .
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object;
+@end
+
+namespace base {
+
+// Base class for all WeakNSObject derivatives.
+template <typename NST>
+class WeakNSProtocol {
+ public:
+  explicit WeakNSProtocol(NST object = nil) {
+    container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+  }
+
+  WeakNSProtocol(const WeakNSProtocol<NST>& that) {
+    // A WeakNSProtocol object can be copied on one thread and used on
+    // another.
+    checker_.DetachFromThread();
+    container_ = that.container_;
+  }
+
+  ~WeakNSProtocol() {
+    // A WeakNSProtocol object can be used on one thread and released on
+    // another. This is not the case for the contained object.
+    checker_.DetachFromThread();
+  }
+
+  void reset(NST object = nil) {
+    DCHECK(checker_.CalledOnValidThread());
+    container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+  }
+
+  NST get() const {
+    DCHECK(checker_.CalledOnValidThread());
+    if (!container_.get())
+      return nil;
+    return container_->object();
+  }
+
+  WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) {
+    // A WeakNSProtocol object can be copied on one thread and used on
+    // another.
+    checker_.DetachFromThread();
+    container_ = that.container_;
+    return *this;
+  }
+
+  bool operator==(NST that) const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get() == that;
+  }
+
+  bool operator!=(NST that) const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get() != that;
+  }
+
+  operator NST() const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get();
+  }
+
+ private:
+  // Refecounted reference to the container tracking the ObjectiveC object this
+  // class encapsulates.
+  scoped_refptr<base::WeakContainer> container_;
+  base::ThreadChecker checker_;
+};
+
+// Free functions
+template <class NST>
+bool operator==(NST p1, const WeakNSProtocol<NST>& p2) {
+  return p1 == p2.get();
+}
+
+template <class NST>
+bool operator!=(NST p1, const WeakNSProtocol<NST>& p2) {
+  return p1 != p2.get();
+}
+
+template <typename NST>
+class WeakNSObject : public WeakNSProtocol<NST*> {
+ public:
+  explicit WeakNSObject(NST* object = nil) : WeakNSProtocol<NST*>(object) {}
+
+  WeakNSObject(const WeakNSObject<NST>& that) : WeakNSProtocol<NST*>(that) {}
+
+  WeakNSObject& operator=(const WeakNSObject<NST>& that) {
+    WeakNSProtocol<NST*>::operator=(that);
+    return *this;
+  }
+};
+
+// Specialization to make WeakNSObject<id> work.
+template <>
+class WeakNSObject<id> : public WeakNSProtocol<id> {
+ public:
+  explicit WeakNSObject(id object = nil) : WeakNSProtocol<id>(object) {}
+
+  WeakNSObject(const WeakNSObject<id>& that) : WeakNSProtocol<id>(that) {}
+
+  WeakNSObject& operator=(const WeakNSObject<id>& that) {
+    WeakNSProtocol<id>::operator=(that);
+    return *this;
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_IOS_WEAK_NSOBJECT_H_
diff --git a/base/ios/weak_nsobject.mm b/base/ios/weak_nsobject.mm
new file mode 100644
index 0000000..36f9d3e
--- /dev/null
+++ b/base/ios/weak_nsobject.mm
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/weak_nsobject.h"
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace {
+// The key needed by objc_setAssociatedObject.
+char sentinelObserverKey_;
+}
+
+@interface CRBWeakNSProtocolSentinel ()
+// Container to notify on dealloc.
+@property(readonly, assign) scoped_refptr<base::WeakContainer> container;
+// Designed initializer.
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container;
+@end
+
+@implementation CRBWeakNSProtocolSentinel
+
+@synthesize container = container_;
+
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object {
+  if (object == nil)
+    return nullptr;
+  // The autoreleasePool is needed here as the call to objc_getAssociatedObject
+  // returns an autoreleased object which is better released sooner than later.
+  base::mac::ScopedNSAutoreleasePool pool;
+  CRBWeakNSProtocolSentinel* sentinel =
+      objc_getAssociatedObject(object, &sentinelObserverKey_);
+  if (!sentinel) {
+    base::scoped_nsobject<CRBWeakNSProtocolSentinel> newSentinel(
+        [[CRBWeakNSProtocolSentinel alloc]
+            initWithContainer:new base::WeakContainer(object)]);
+    sentinel = newSentinel;
+    objc_setAssociatedObject(object, &sentinelObserverKey_, sentinel,
+                             OBJC_ASSOCIATION_RETAIN);
+    // The retain count is 2. One retain is due to the alloc, the other to the
+    // association with the weak object.
+    DCHECK_EQ(2u, [sentinel retainCount]);
+  }
+  return [sentinel container];
+}
+
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container {
+  DCHECK(container.get());
+  self = [super init];
+  if (self)
+    container_ = container;
+  return self;
+}
+
+- (void)dealloc {
+  self.container->nullify();
+  [super dealloc];
+}
+
+@end
diff --git a/base/ios/weak_nsobject_unittest.mm b/base/ios/weak_nsobject_unittest.mm
new file mode 100644
index 0000000..81de993
--- /dev/null
+++ b/base/ios/weak_nsobject_unittest.mm
@@ -0,0 +1,140 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(WeakNSObjectTest, WeakNSObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  p1.reset();
+  EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, MultipleWeakNSObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2(w1);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  EXPECT_TRUE(w1.get() == w2.get());
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectDies) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  {
+    WeakNSObject<NSObject> w1(p1);
+    EXPECT_TRUE(w1);
+  }
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectReset) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  w1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_TRUE(p1);
+  EXPECT_TRUE([p1 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectResetWithObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p2([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  w1.reset(p2);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE([p1 description]);
+  EXPECT_TRUE([p2 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectEmpty) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1;
+  EXPECT_FALSE(w1);
+  w1.reset(p1);
+  EXPECT_TRUE(w1);
+  p1.reset();
+  EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectCopy) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2(w1);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectAssignment) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2;
+  EXPECT_FALSE(w2);
+  w2 = w1;
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+// Touches |weak_data| by increasing its length by 1. Used to check that the
+// weak object can be dereferenced.
+void TouchWeakData(const WeakNSObject<NSMutableData>& weak_data) {
+  if (!weak_data)
+    return;
+  [weak_data increaseLengthBy:1];
+}
+
+// Makes a copy of |weak_object| on the current thread and posts a task to touch
+// the weak object on its original thread.
+void CopyWeakNSObjectAndPost(const WeakNSObject<NSMutableData>& weak_object,
+                             scoped_refptr<SingleThreadTaskRunner> runner) {
+  // Copy using constructor.
+  WeakNSObject<NSMutableData> weak_copy1(weak_object);
+  runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy1));
+  // Copy using assignment operator.
+  WeakNSObject<NSMutableData> weak_copy2 = weak_object;
+  runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy2));
+}
+
+// Tests that the weak object can be copied on a different thread.
+TEST(WeakNSObjectTest, WeakNSObjectCopyOnOtherThread) {
+  MessageLoop loop;
+  Thread other_thread("WeakNSObjectCopyOnOtherThread");
+  other_thread.Start();
+
+  scoped_nsobject<NSMutableData> data([[NSMutableData alloc] init]);
+  WeakNSObject<NSMutableData> weak(data);
+
+  scoped_refptr<SingleThreadTaskRunner> runner = loop.task_runner();
+  other_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&CopyWeakNSObjectAndPost, weak, runner));
+  other_thread.Stop();
+  loop.RunUntilIdle();
+
+  // Check that TouchWeakData was called and the object touched twice.
+  EXPECT_EQ(2u, [data length]);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/json/BUILD.gn b/base/json/BUILD.gn
new file mode 100644
index 0000000..70830c1
--- /dev/null
+++ b/base/json/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("json") {
+  sources = [
+    "json_file_value_serializer.cc",
+    "json_file_value_serializer.h",
+    "json_parser.cc",
+    "json_parser.h",
+    "json_reader.cc",
+    "json_reader.h",
+    "json_string_value_serializer.cc",
+    "json_string_value_serializer.h",
+    "json_value_converter.cc",
+    "json_value_converter.h",
+    "json_writer.cc",
+    "json_writer.h",
+    "string_escape.cc",
+    "string_escape.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [
+      "json_file_value_serializer.cc",
+      "json_file_value_serializer.h",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/memory",
+  ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
new file mode 100644
index 0000000..72a0970
--- /dev/null
+++ b/base/json/json_file_value_serializer.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_file_value_serializer.h"
+
+#include "base/files/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+
+using base::FilePath;
+
+const char JSONFileValueDeserializer::kAccessDenied[] = "Access denied.";
+const char JSONFileValueDeserializer::kCannotReadFile[] = "Can't read file.";
+const char JSONFileValueDeserializer::kFileLocked[] = "File locked.";
+const char JSONFileValueDeserializer::kNoSuchFile[] = "File doesn't exist.";
+
+JSONFileValueSerializer::JSONFileValueSerializer(
+    const base::FilePath& json_file_path)
+    : json_file_path_(json_file_path) {
+}
+
+JSONFileValueSerializer::~JSONFileValueSerializer() {
+}
+
+bool JSONFileValueSerializer::Serialize(const base::Value& root) {
+  return SerializeInternal(root, false);
+}
+
+bool JSONFileValueSerializer::SerializeAndOmitBinaryValues(
+    const base::Value& root) {
+  return SerializeInternal(root, true);
+}
+
+bool JSONFileValueSerializer::SerializeInternal(const base::Value& root,
+                                                bool omit_binary_values) {
+  std::string json_string;
+  JSONStringValueSerializer serializer(&json_string);
+  serializer.set_pretty_print(true);
+  bool result = omit_binary_values ?
+      serializer.SerializeAndOmitBinaryValues(root) :
+      serializer.Serialize(root);
+  if (!result)
+    return false;
+
+  int data_size = static_cast<int>(json_string.size());
+  if (base::WriteFile(json_file_path_, json_string.data(), data_size) !=
+      data_size)
+    return false;
+
+  return true;
+}
+
+JSONFileValueDeserializer::JSONFileValueDeserializer(
+    const base::FilePath& json_file_path)
+    : json_file_path_(json_file_path),
+      allow_trailing_comma_(false),
+      last_read_size_(0U) {
+}
+
+JSONFileValueDeserializer::~JSONFileValueDeserializer() {
+}
+
+int JSONFileValueDeserializer::ReadFileToString(std::string* json_string) {
+  DCHECK(json_string);
+  if (!base::ReadFileToString(json_file_path_, json_string)) {
+#if defined(OS_WIN)
+    int error = ::GetLastError();
+    if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) {
+      return JSON_FILE_LOCKED;
+    } else if (error == ERROR_ACCESS_DENIED) {
+      return JSON_ACCESS_DENIED;
+    }
+#endif
+    if (!base::PathExists(json_file_path_))
+      return JSON_NO_SUCH_FILE;
+    else
+      return JSON_CANNOT_READ_FILE;
+  }
+
+  last_read_size_ = json_string->size();
+  return JSON_NO_ERROR;
+}
+
+const char* JSONFileValueDeserializer::GetErrorMessageForCode(int error_code) {
+  switch (error_code) {
+    case JSON_NO_ERROR:
+      return "";
+    case JSON_ACCESS_DENIED:
+      return kAccessDenied;
+    case JSON_CANNOT_READ_FILE:
+      return kCannotReadFile;
+    case JSON_FILE_LOCKED:
+      return kFileLocked;
+    case JSON_NO_SUCH_FILE:
+      return kNoSuchFile;
+    default:
+      NOTREACHED();
+      return "";
+  }
+}
+
+base::Value* JSONFileValueDeserializer::Deserialize(int* error_code,
+                                                    std::string* error_str) {
+  std::string json_string;
+  int error = ReadFileToString(&json_string);
+  if (error != JSON_NO_ERROR) {
+    if (error_code)
+      *error_code = error;
+    if (error_str)
+      *error_str = GetErrorMessageForCode(error);
+    return NULL;
+  }
+
+  JSONStringValueDeserializer deserializer(json_string);
+  deserializer.set_allow_trailing_comma(allow_trailing_comma_);
+  return deserializer.Deserialize(error_code, error_str);
+}
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h
new file mode 100644
index 0000000..aab47ee
--- /dev/null
+++ b/base/json/json_file_value_serializer.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+#define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/values.h"
+
+class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
+ public:
+  // |json_file_path_| is the path of a file that will be destination of the
+  // serialization. The serializer will attempt to create the file at the
+  // specified location.
+  explicit JSONFileValueSerializer(const base::FilePath& json_file_path);
+
+  ~JSONFileValueSerializer() override;
+
+  // DO NOT USE except in unit tests to verify the file was written properly.
+  // We should never serialize directly to a file since this will block the
+  // thread. Instead, serialize to a string and write to the file you want on
+  // the file thread.
+  //
+  // Attempt to serialize the data structure represented by Value into
+  // JSON.  If the return value is true, the result will have been written
+  // into the file whose name was passed into the constructor.
+  bool Serialize(const base::Value& root) override;
+
+  // Equivalent to Serialize(root) except binary values are omitted from the
+  // output.
+  bool SerializeAndOmitBinaryValues(const base::Value& root);
+
+ private:
+  bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+  const base::FilePath json_file_path_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
+};
+
+class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
+ public:
+  // |json_file_path_| is the path of a file that will be source of the
+  // deserialization.
+  explicit JSONFileValueDeserializer(const base::FilePath& json_file_path);
+
+  ~JSONFileValueDeserializer() override;
+
+  // Attempt to deserialize the data structure encoded in the file passed
+  // in to the constructor into a structure of Value objects.  If the return
+  // value is NULL, and if |error_code| is non-null, |error_code| will
+  // contain an integer error code (either JsonFileError or JsonParseError).
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  // The caller takes ownership of the returned value.
+  base::Value* Deserialize(int* error_code,
+                           std::string* error_message) override;
+
+  // This enum is designed to safely overlap with JSONReader::JsonParseError.
+  enum JsonFileError {
+    JSON_NO_ERROR = 0,
+    JSON_ACCESS_DENIED = 1000,
+    JSON_CANNOT_READ_FILE,
+    JSON_FILE_LOCKED,
+    JSON_NO_SUCH_FILE
+  };
+
+  // File-specific error messages that can be returned.
+  static const char kAccessDenied[];
+  static const char kCannotReadFile[];
+  static const char kFileLocked[];
+  static const char kNoSuchFile[];
+
+  // Convert an error code into an error message.  |error_code| is assumed to
+  // be a JsonFileError.
+  static const char* GetErrorMessageForCode(int error_code);
+
+  void set_allow_trailing_comma(bool new_value) {
+    allow_trailing_comma_ = new_value;
+  }
+
+  // Returns the size (in bytes) of JSON string read from disk in the last
+  // successful |Deserialize()| call.
+  size_t get_last_read_size() const { return last_read_size_; }
+
+ private:
+  // A wrapper for ReadFileToString which returns a non-zero JsonFileError if
+  // there were file errors.
+  int ReadFileToString(std::string* json_string);
+
+  const base::FilePath json_file_path_;
+  bool allow_trailing_comma_;
+  size_t last_read_size_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueDeserializer);
+};
+
+#endif  // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
new file mode 100644
index 0000000..e9a27bc
--- /dev/null
+++ b/base/json/json_parser.cc
@@ -0,0 +1,966 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_parser.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/values.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+const int kStackMaxDepth = 100;
+
+const int32 kExtendedASCIIStart = 0x80;
+
+// This and the class below are used to own the JSON input string for when
+// string tokens are stored as StringPiece instead of std::string. This
+// optimization avoids about 2/3rds of string memory copies. The constructor
+// takes ownership of the input string. The real root value is Swap()ed into
+// the new instance.
+class DictionaryHiddenRootValue : public base::DictionaryValue {
+ public:
+  DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) {
+    DCHECK(root->IsType(Value::TYPE_DICTIONARY));
+    DictionaryValue::Swap(static_cast<DictionaryValue*>(root));
+  }
+
+  void Swap(DictionaryValue* other) override {
+    DVLOG(1) << "Swap()ing a DictionaryValue inefficiently.";
+
+    // First deep copy to convert JSONStringValue to std::string and swap that
+    // copy with |other|, which contains the new contents of |this|.
+    scoped_ptr<base::DictionaryValue> copy(DeepCopy());
+    copy->Swap(other);
+
+    // Then erase the contents of the current dictionary and swap in the
+    // new contents, originally from |other|.
+    Clear();
+    json_.reset();
+    DictionaryValue::Swap(copy.get());
+  }
+
+  // Not overriding DictionaryValue::Remove because it just calls through to
+  // the method below.
+
+  bool RemoveWithoutPathExpansion(const std::string& key,
+                                  scoped_ptr<Value>* out) override {
+    // If the caller won't take ownership of the removed value, just call up.
+    if (!out)
+      return DictionaryValue::RemoveWithoutPathExpansion(key, out);
+
+    DVLOG(1) << "Remove()ing from a DictionaryValue inefficiently.";
+
+    // Otherwise, remove the value while its still "owned" by this and copy it
+    // to convert any JSONStringValues to std::string.
+    scoped_ptr<Value> out_owned;
+    if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned))
+      return false;
+
+    out->reset(out_owned->DeepCopy());
+
+    return true;
+  }
+
+ private:
+  scoped_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
+};
+
+class ListHiddenRootValue : public base::ListValue {
+ public:
+  ListHiddenRootValue(std::string* json, Value* root) : json_(json) {
+    DCHECK(root->IsType(Value::TYPE_LIST));
+    ListValue::Swap(static_cast<ListValue*>(root));
+  }
+
+  void Swap(ListValue* other) override {
+    DVLOG(1) << "Swap()ing a ListValue inefficiently.";
+
+    // First deep copy to convert JSONStringValue to std::string and swap that
+    // copy with |other|, which contains the new contents of |this|.
+    scoped_ptr<base::ListValue> copy(DeepCopy());
+    copy->Swap(other);
+
+    // Then erase the contents of the current list and swap in the new contents,
+    // originally from |other|.
+    Clear();
+    json_.reset();
+    ListValue::Swap(copy.get());
+  }
+
+  bool Remove(size_t index, scoped_ptr<Value>* out) override {
+    // If the caller won't take ownership of the removed value, just call up.
+    if (!out)
+      return ListValue::Remove(index, out);
+
+    DVLOG(1) << "Remove()ing from a ListValue inefficiently.";
+
+    // Otherwise, remove the value while its still "owned" by this and copy it
+    // to convert any JSONStringValues to std::string.
+    scoped_ptr<Value> out_owned;
+    if (!ListValue::Remove(index, &out_owned))
+      return false;
+
+    out->reset(out_owned->DeepCopy());
+
+    return true;
+  }
+
+ private:
+  scoped_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue);
+};
+
+// A variant on StringValue that uses StringPiece instead of copying the string
+// into the Value. This can only be stored in a child of hidden root (above),
+// otherwise the referenced string will not be guaranteed to outlive it.
+class JSONStringValue : public base::Value {
+ public:
+  explicit JSONStringValue(const base::StringPiece& piece)
+      : Value(TYPE_STRING),
+        string_piece_(piece) {
+  }
+
+  // Overridden from base::Value:
+  bool GetAsString(std::string* out_value) const override {
+    string_piece_.CopyToString(out_value);
+    return true;
+  }
+  bool GetAsString(string16* out_value) const override {
+    *out_value = UTF8ToUTF16(string_piece_);
+    return true;
+  }
+  Value* DeepCopy() const override {
+    return new StringValue(string_piece_.as_string());
+  }
+  bool Equals(const Value* other) const override {
+    std::string other_string;
+    return other->IsType(TYPE_STRING) && other->GetAsString(&other_string) &&
+        StringPiece(other_string) == string_piece_;
+  }
+
+ private:
+  // The location in the original input stream.
+  base::StringPiece string_piece_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValue);
+};
+
+// Simple class that checks for maximum recursion/"stack overflow."
+class StackMarker {
+ public:
+  explicit StackMarker(int* depth) : depth_(depth) {
+    ++(*depth_);
+    DCHECK_LE(*depth_, kStackMaxDepth);
+  }
+  ~StackMarker() {
+    --(*depth_);
+  }
+
+  bool IsTooDeep() const {
+    return *depth_ >= kStackMaxDepth;
+  }
+
+ private:
+  int* const depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackMarker);
+};
+
+}  // namespace
+
+JSONParser::JSONParser(int options)
+    : options_(options),
+      start_pos_(NULL),
+      pos_(NULL),
+      end_pos_(NULL),
+      index_(0),
+      stack_depth_(0),
+      line_number_(0),
+      index_last_line_(0),
+      error_code_(JSONReader::JSON_NO_ERROR),
+      error_line_(0),
+      error_column_(0) {
+}
+
+JSONParser::~JSONParser() {
+}
+
+Value* JSONParser::Parse(const StringPiece& input) {
+  scoped_ptr<std::string> input_copy;
+  // If the children of a JSON root can be detached, then hidden roots cannot
+  // be used, so do not bother copying the input because StringPiece will not
+  // be used anywhere.
+  if (!(options_ & JSON_DETACHABLE_CHILDREN)) {
+    input_copy.reset(new std::string(input.as_string()));
+    start_pos_ = input_copy->data();
+  } else {
+    start_pos_ = input.data();
+  }
+  pos_ = start_pos_;
+  end_pos_ = start_pos_ + input.length();
+  index_ = 0;
+  line_number_ = 1;
+  index_last_line_ = 0;
+
+  error_code_ = JSONReader::JSON_NO_ERROR;
+  error_line_ = 0;
+  error_column_ = 0;
+
+  // When the input JSON string starts with a UTF-8 Byte-Order-Mark
+  // <0xEF 0xBB 0xBF>, advance the start position to avoid the
+  // ParseNextToken function mis-treating a Unicode BOM as an invalid
+  // character and returning NULL.
+  if (CanConsume(3) && static_cast<uint8>(*pos_) == 0xEF &&
+      static_cast<uint8>(*(pos_ + 1)) == 0xBB &&
+      static_cast<uint8>(*(pos_ + 2)) == 0xBF) {
+    NextNChars(3);
+  }
+
+  // Parse the first and any nested tokens.
+  scoped_ptr<Value> root(ParseNextToken());
+  if (!root.get())
+    return NULL;
+
+  // Make sure the input stream is at an end.
+  if (GetNextToken() != T_END_OF_INPUT) {
+    if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) {
+      ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1);
+      return NULL;
+    }
+  }
+
+  // Dictionaries and lists can contain JSONStringValues, so wrap them in a
+  // hidden root.
+  if (!(options_ & JSON_DETACHABLE_CHILDREN)) {
+    if (root->IsType(Value::TYPE_DICTIONARY)) {
+      return new DictionaryHiddenRootValue(input_copy.release(), root.get());
+    } else if (root->IsType(Value::TYPE_LIST)) {
+      return new ListHiddenRootValue(input_copy.release(), root.get());
+    } else if (root->IsType(Value::TYPE_STRING)) {
+      // A string type could be a JSONStringValue, but because there's no
+      // corresponding HiddenRootValue, the memory will be lost. Deep copy to
+      // preserve it.
+      return root->DeepCopy();
+    }
+  }
+
+  // All other values can be returned directly.
+  return root.release();
+}
+
+JSONReader::JsonParseError JSONParser::error_code() const {
+  return error_code_;
+}
+
+std::string JSONParser::GetErrorMessage() const {
+  return FormatErrorMessage(error_line_, error_column_,
+      JSONReader::ErrorCodeToString(error_code_));
+}
+
+// StringBuilder ///////////////////////////////////////////////////////////////
+
+JSONParser::StringBuilder::StringBuilder()
+    : pos_(NULL),
+      length_(0),
+      string_(NULL) {
+}
+
+JSONParser::StringBuilder::StringBuilder(const char* pos)
+    : pos_(pos),
+      length_(0),
+      string_(NULL) {
+}
+
+void JSONParser::StringBuilder::Swap(StringBuilder* other) {
+  std::swap(other->string_, string_);
+  std::swap(other->pos_, pos_);
+  std::swap(other->length_, length_);
+}
+
+JSONParser::StringBuilder::~StringBuilder() {
+  delete string_;
+}
+
+void JSONParser::StringBuilder::Append(const char& c) {
+  DCHECK_GE(c, 0);
+  DCHECK_LT(c, 128);
+
+  if (string_)
+    string_->push_back(c);
+  else
+    ++length_;
+}
+
+void JSONParser::StringBuilder::AppendString(const std::string& str) {
+  DCHECK(string_);
+  string_->append(str);
+}
+
+void JSONParser::StringBuilder::Convert() {
+  if (string_)
+    return;
+  string_  = new std::string(pos_, length_);
+}
+
+bool JSONParser::StringBuilder::CanBeStringPiece() const {
+  return !string_;
+}
+
+StringPiece JSONParser::StringBuilder::AsStringPiece() {
+  if (string_)
+    return StringPiece();
+  return StringPiece(pos_, length_);
+}
+
+const std::string& JSONParser::StringBuilder::AsString() {
+  if (!string_)
+    Convert();
+  return *string_;
+}
+
+// JSONParser private //////////////////////////////////////////////////////////
+
+inline bool JSONParser::CanConsume(int length) {
+  return pos_ + length <= end_pos_;
+}
+
+const char* JSONParser::NextChar() {
+  DCHECK(CanConsume(1));
+  ++index_;
+  ++pos_;
+  return pos_;
+}
+
+void JSONParser::NextNChars(int n) {
+  DCHECK(CanConsume(n));
+  index_ += n;
+  pos_ += n;
+}
+
+JSONParser::Token JSONParser::GetNextToken() {
+  EatWhitespaceAndComments();
+  if (!CanConsume(1))
+    return T_END_OF_INPUT;
+
+  switch (*pos_) {
+    case '{':
+      return T_OBJECT_BEGIN;
+    case '}':
+      return T_OBJECT_END;
+    case '[':
+      return T_ARRAY_BEGIN;
+    case ']':
+      return T_ARRAY_END;
+    case '"':
+      return T_STRING;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '-':
+      return T_NUMBER;
+    case 't':
+      return T_BOOL_TRUE;
+    case 'f':
+      return T_BOOL_FALSE;
+    case 'n':
+      return T_NULL;
+    case ',':
+      return T_LIST_SEPARATOR;
+    case ':':
+      return T_OBJECT_PAIR_SEPARATOR;
+    default:
+      return T_INVALID_TOKEN;
+  }
+}
+
+void JSONParser::EatWhitespaceAndComments() {
+  while (pos_ < end_pos_) {
+    switch (*pos_) {
+      case '\r':
+      case '\n':
+        index_last_line_ = index_;
+        // Don't increment line_number_ twice for "\r\n".
+        if (!(*pos_ == '\n' && pos_ > start_pos_ && *(pos_ - 1) == '\r'))
+          ++line_number_;
+        // Fall through.
+      case ' ':
+      case '\t':
+        NextChar();
+        break;
+      case '/':
+        if (!EatComment())
+          return;
+        break;
+      default:
+        return;
+    }
+  }
+}
+
+bool JSONParser::EatComment() {
+  if (*pos_ != '/' || !CanConsume(1))
+    return false;
+
+  char next_char = *NextChar();
+  if (next_char == '/') {
+    // Single line comment, read to newline.
+    while (CanConsume(1)) {
+      next_char = *NextChar();
+      if (next_char == '\n' || next_char == '\r')
+        return true;
+    }
+  } else if (next_char == '*') {
+    char previous_char = '\0';
+    // Block comment, read until end marker.
+    while (CanConsume(1)) {
+      next_char = *NextChar();
+      if (previous_char == '*' && next_char == '/') {
+        // EatWhitespaceAndComments will inspect pos_, which will still be on
+        // the last / of the comment, so advance once more (which may also be
+        // end of input).
+        NextChar();
+        return true;
+      }
+      previous_char = next_char;
+    }
+
+    // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT.
+  }
+
+  return false;
+}
+
+Value* JSONParser::ParseNextToken() {
+  return ParseToken(GetNextToken());
+}
+
+Value* JSONParser::ParseToken(Token token) {
+  switch (token) {
+    case T_OBJECT_BEGIN:
+      return ConsumeDictionary();
+    case T_ARRAY_BEGIN:
+      return ConsumeList();
+    case T_STRING:
+      return ConsumeString();
+    case T_NUMBER:
+      return ConsumeNumber();
+    case T_BOOL_TRUE:
+    case T_BOOL_FALSE:
+    case T_NULL:
+      return ConsumeLiteral();
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return NULL;
+  }
+}
+
+Value* JSONParser::ConsumeDictionary() {
+  if (*pos_ != '{') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return NULL;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return NULL;
+  }
+
+  scoped_ptr<DictionaryValue> dict(new DictionaryValue);
+
+  NextChar();
+  Token token = GetNextToken();
+  while (token != T_OBJECT_END) {
+    if (token != T_STRING) {
+      ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1);
+      return NULL;
+    }
+
+    // First consume the key.
+    StringBuilder key;
+    if (!ConsumeStringRaw(&key)) {
+      return NULL;
+    }
+
+    // Read the separator.
+    NextChar();
+    token = GetNextToken();
+    if (token != T_OBJECT_PAIR_SEPARATOR) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+
+    // The next token is the value. Ownership transfers to |dict|.
+    NextChar();
+    Value* value = ParseNextToken();
+    if (!value) {
+      // ReportError from deeper level.
+      return NULL;
+    }
+
+    dict->SetWithoutPathExpansion(key.AsString(), value);
+
+    NextChar();
+    token = GetNextToken();
+    if (token == T_LIST_SEPARATOR) {
+      NextChar();
+      token = GetNextToken();
+      if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
+        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
+        return NULL;
+      }
+    } else if (token != T_OBJECT_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+      return NULL;
+    }
+  }
+
+  return dict.release();
+}
+
+Value* JSONParser::ConsumeList() {
+  if (*pos_ != '[') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return NULL;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return NULL;
+  }
+
+  scoped_ptr<ListValue> list(new ListValue);
+
+  NextChar();
+  Token token = GetNextToken();
+  while (token != T_ARRAY_END) {
+    Value* item = ParseToken(token);
+    if (!item) {
+      // ReportError from deeper level.
+      return NULL;
+    }
+
+    list->Append(item);
+
+    NextChar();
+    token = GetNextToken();
+    if (token == T_LIST_SEPARATOR) {
+      NextChar();
+      token = GetNextToken();
+      if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
+        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
+        return NULL;
+      }
+    } else if (token != T_ARRAY_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+  }
+
+  return list.release();
+}
+
+Value* JSONParser::ConsumeString() {
+  StringBuilder string;
+  if (!ConsumeStringRaw(&string))
+    return NULL;
+
+  // Create the Value representation, using a hidden root, if configured
+  // to do so, and if the string can be represented by StringPiece.
+  if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) {
+    return new JSONStringValue(string.AsStringPiece());
+  } else {
+    if (string.CanBeStringPiece())
+      string.Convert();
+    return new StringValue(string.AsString());
+  }
+}
+
+bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
+  if (*pos_ != '"') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return false;
+  }
+
+  // StringBuilder will internally build a StringPiece unless a UTF-16
+  // conversion occurs, at which point it will perform a copy into a
+  // std::string.
+  StringBuilder string(NextChar());
+
+  int length = end_pos_ - start_pos_;
+  int32 next_char = 0;
+
+  while (CanConsume(1)) {
+    pos_ = start_pos_ + index_;  // CBU8_NEXT is postcrement.
+    CBU8_NEXT(start_pos_, index_, length, next_char);
+    if (next_char < 0 || !IsValidCharacter(next_char)) {
+      ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1);
+      return false;
+    }
+
+    // If this character is an escape sequence...
+    if (next_char == '\\') {
+      // The input string will be adjusted (either by combining the two
+      // characters of an encoded escape sequence, or with a UTF conversion),
+      // so using StringPiece isn't possible -- force a conversion.
+      string.Convert();
+
+      if (!CanConsume(1)) {
+        ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+        return false;
+      }
+
+      switch (*NextChar()) {
+        // Allowed esape sequences:
+        case 'x': {  // UTF-8 sequence.
+          // UTF-8 \x escape sequences are not allowed in the spec, but they
+          // are supported here for backwards-compatiblity with the old parser.
+          if (!CanConsume(2)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, 1);
+            return false;
+          }
+
+          int hex_digit = 0;
+          if (!HexStringToInt(StringPiece(NextChar(), 2), &hex_digit)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+          NextChar();
+
+          if (hex_digit < kExtendedASCIIStart)
+            string.Append(static_cast<char>(hex_digit));
+          else
+            DecodeUTF8(hex_digit, &string);
+          break;
+        }
+        case 'u': {  // UTF-16 sequence.
+          // UTF units are of the form \uXXXX.
+          if (!CanConsume(5)) {  // 5 being 'u' and four HEX digits.
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+            return false;
+          }
+
+          // Skip the 'u'.
+          NextChar();
+
+          std::string utf8_units;
+          if (!DecodeUTF16(&utf8_units)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+
+          string.AppendString(utf8_units);
+          break;
+        }
+        case '"':
+          string.Append('"');
+          break;
+        case '\\':
+          string.Append('\\');
+          break;
+        case '/':
+          string.Append('/');
+          break;
+        case 'b':
+          string.Append('\b');
+          break;
+        case 'f':
+          string.Append('\f');
+          break;
+        case 'n':
+          string.Append('\n');
+          break;
+        case 'r':
+          string.Append('\r');
+          break;
+        case 't':
+          string.Append('\t');
+          break;
+        case 'v':  // Not listed as valid escape sequence in the RFC.
+          string.Append('\v');
+          break;
+        // All other escape squences are illegal.
+        default:
+          ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+          return false;
+      }
+    } else if (next_char == '"') {
+      --index_;  // Rewind by one because of CBU8_NEXT.
+      out->Swap(&string);
+      return true;
+    } else {
+      if (next_char < kExtendedASCIIStart)
+        string.Append(static_cast<char>(next_char));
+      else
+        DecodeUTF8(next_char, &string);
+    }
+  }
+
+  ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+  return false;
+}
+
+// Entry is at the first X in \uXXXX.
+bool JSONParser::DecodeUTF16(std::string* dest_string) {
+  if (!CanConsume(4))
+    return false;
+
+  // This is a 32-bit field because the shift operations in the
+  // conversion process below cause MSVC to error about "data loss."
+  // This only stores UTF-16 code units, though.
+  // Consume the UTF-16 code unit, which may be a high surrogate.
+  int code_unit16_high = 0;
+  if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_high))
+    return false;
+
+  // Only add 3, not 4, because at the end of this iteration, the parser has
+  // finished working with the last digit of the UTF sequence, meaning that
+  // the next iteration will advance to the next byte.
+  NextNChars(3);
+
+  // Used to convert the UTF-16 code units to a code point and then to a UTF-8
+  // code unit sequence.
+  char code_unit8[8] = { 0 };
+  size_t offset = 0;
+
+  // If this is a high surrogate, consume the next code unit to get the
+  // low surrogate.
+  if (CBU16_IS_SURROGATE(code_unit16_high)) {
+    // Make sure this is the high surrogate. If not, it's an encoding
+    // error.
+    if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high))
+      return false;
+
+    // Make sure that the token has more characters to consume the
+    // lower surrogate.
+    if (!CanConsume(6))  // 6 being '\' 'u' and four HEX digits.
+      return false;
+    if (*NextChar() != '\\' || *NextChar() != 'u')
+      return false;
+
+    NextChar();  // Read past 'u'.
+    int code_unit16_low = 0;
+    if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_low))
+      return false;
+
+    NextNChars(3);
+
+    if (!CBU16_IS_TRAIL(code_unit16_low)) {
+      return false;
+    }
+
+    uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
+                                                code_unit16_low);
+    offset = 0;
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
+  } else {
+    // Not a surrogate.
+    DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
+  }
+
+  dest_string->append(code_unit8);
+  return true;
+}
+
+void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+  // Anything outside of the basic ASCII plane will need to be decoded from
+  // int32 to a multi-byte sequence.
+  if (point < kExtendedASCIIStart) {
+    dest->Append(static_cast<char>(point));
+  } else {
+    char utf8_units[4] = { 0 };
+    int offset = 0;
+    CBU8_APPEND_UNSAFE(utf8_units, offset, point);
+    dest->Convert();
+    // CBU8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be
+    // zero terminated at this point.  |offset| contains the correct length.
+    dest->AppendString(std::string(utf8_units, offset));
+  }
+}
+
+Value* JSONParser::ConsumeNumber() {
+  const char* num_start = pos_;
+  const int start_index = index_;
+  int end_index = start_index;
+
+  if (*pos_ == '-')
+    NextChar();
+
+  if (!ReadInt(false)) {
+    ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+    return NULL;
+  }
+  end_index = index_;
+
+  // The optional fraction part.
+  if (*pos_ == '.') {
+    if (!CanConsume(1)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    end_index = index_;
+  }
+
+  // Optional exponent part.
+  if (*pos_ == 'e' || *pos_ == 'E') {
+    NextChar();
+    if (*pos_ == '-' || *pos_ == '+')
+      NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    end_index = index_;
+  }
+
+  // ReadInt is greedy because numbers have no easily detectable sentinel,
+  // so save off where the parser should be on exit (see Consume invariant at
+  // the top of the header), then make sure the next token is one which is
+  // valid.
+  const char* exit_pos = pos_ - 1;
+  int exit_index = index_ - 1;
+
+  switch (GetNextToken()) {
+    case T_OBJECT_END:
+    case T_ARRAY_END:
+    case T_LIST_SEPARATOR:
+    case T_END_OF_INPUT:
+      break;
+    default:
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+  }
+
+  pos_ = exit_pos;
+  index_ = exit_index;
+
+  StringPiece num_string(num_start, end_index - start_index);
+
+  int num_int;
+  if (StringToInt(num_string, &num_int))
+    return new FundamentalValue(num_int);
+
+  double num_double;
+  if (base::StringToDouble(num_string.as_string(), &num_double) &&
+      std::isfinite(num_double)) {
+    return new FundamentalValue(num_double);
+  }
+
+  return NULL;
+}
+
+bool JSONParser::ReadInt(bool allow_leading_zeros) {
+  char first = *pos_;
+  int len = 0;
+
+  char c = first;
+  while (CanConsume(1) && IsAsciiDigit(c)) {
+    c = *NextChar();
+    ++len;
+  }
+
+  if (len == 0)
+    return false;
+
+  if (!allow_leading_zeros && len > 1 && first == '0')
+    return false;
+
+  return true;
+}
+
+Value* JSONParser::ConsumeLiteral() {
+  switch (*pos_) {
+    case 't': {
+      const char kTrueLiteral[] = "true";
+      const int kTrueLen = static_cast<int>(strlen(kTrueLiteral));
+      if (!CanConsume(kTrueLen - 1) ||
+          !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kTrueLen - 1);
+      return new FundamentalValue(true);
+    }
+    case 'f': {
+      const char kFalseLiteral[] = "false";
+      const int kFalseLen = static_cast<int>(strlen(kFalseLiteral));
+      if (!CanConsume(kFalseLen - 1) ||
+          !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kFalseLen - 1);
+      return new FundamentalValue(false);
+    }
+    case 'n': {
+      const char kNullLiteral[] = "null";
+      const int kNullLen = static_cast<int>(strlen(kNullLiteral));
+      if (!CanConsume(kNullLen - 1) ||
+          !StringsAreEqual(pos_, kNullLiteral, kNullLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kNullLen - 1);
+      return Value::CreateNullValue();
+    }
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return NULL;
+  }
+}
+
+// static
+bool JSONParser::StringsAreEqual(const char* one, const char* two, size_t len) {
+  return strncmp(one, two, len) == 0;
+}
+
+void JSONParser::ReportError(JSONReader::JsonParseError code,
+                             int column_adjust) {
+  error_code_ = code;
+  error_line_ = line_number_;
+  error_column_ = index_ - index_last_line_ + column_adjust;
+}
+
+// static
+std::string JSONParser::FormatErrorMessage(int line, int column,
+                                           const std::string& description) {
+  if (line || column) {
+    return StringPrintf("Line: %i, column: %i, %s",
+        line, column, description.c_str());
+  }
+  return description;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
new file mode 100644
index 0000000..b4d0b1b
--- /dev/null
+++ b/base/json/json_parser.h
@@ -0,0 +1,271 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_PARSER_H_
+#define BASE_JSON_JSON_PARSER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/json/json_reader.h"
+#include "base/strings/string_piece.h"
+
+#if !defined(OS_CHROMEOS)
+#include "base/gtest_prod_util.h"
+#endif
+
+namespace base {
+class Value;
+}
+
+#if defined(OS_CHROMEOS)
+// Chromium and Chromium OS check out gtest to different places, so this is
+// unable to compile on both if gtest_prod.h is included here. Instead, include
+// its only contents -- this will need to be updated if the macro ever changes.
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+  FRIEND_TEST(test_case_name, test_name); \
+  FRIEND_TEST(test_case_name, DISABLED_##test_name); \
+  FRIEND_TEST(test_case_name, FLAKY_##test_name)
+#endif  // OS_CHROMEOS
+
+namespace base {
+namespace internal {
+
+class JSONParserTest;
+
+// The implementation behind the JSONReader interface. This class is not meant
+// to be used directly; it encapsulates logic that need not be exposed publicly.
+//
+// This parser guarantees O(n) time through the input string. It also optimizes
+// base::StringValue by using StringPiece where possible when returning Value
+// objects by using "hidden roots," discussed in the implementation.
+//
+// Iteration happens on the byte level, with the functions CanConsume and
+// NextChar. The conversion from byte to JSON token happens without advancing
+// the parser in GetNextToken/ParseToken, that is tokenization operates on
+// the current parser position without advancing.
+//
+// Built on top of these are a family of Consume functions that iterate
+// internally. Invariant: on entry of a Consume function, the parser is wound
+// to the first byte of a valid JSON token. On exit, it is on the last byte
+// of a token, such that the next iteration of the parser will be at the byte
+// immediately following the token, which would likely be the first byte of the
+// next token.
+class BASE_EXPORT_PRIVATE JSONParser {
+ public:
+  explicit JSONParser(int options);
+  ~JSONParser();
+
+  // Parses the input string according to the set options and returns the
+  // result as a Value owned by the caller.
+  Value* Parse(const StringPiece& input);
+
+  // Returns the error code.
+  JSONReader::JsonParseError error_code() const;
+
+  // Returns the human-friendly error message.
+  std::string GetErrorMessage() const;
+
+ private:
+  enum Token {
+    T_OBJECT_BEGIN,           // {
+    T_OBJECT_END,             // }
+    T_ARRAY_BEGIN,            // [
+    T_ARRAY_END,              // ]
+    T_STRING,
+    T_NUMBER,
+    T_BOOL_TRUE,              // true
+    T_BOOL_FALSE,             // false
+    T_NULL,                   // null
+    T_LIST_SEPARATOR,         // ,
+    T_OBJECT_PAIR_SEPARATOR,  // :
+    T_END_OF_INPUT,
+    T_INVALID_TOKEN,
+  };
+
+  // A helper class used for parsing strings. One optimization performed is to
+  // create base::Value with a StringPiece to avoid unnecessary std::string
+  // copies. This is not possible if the input string needs to be decoded from
+  // UTF-16 to UTF-8, or if an escape sequence causes characters to be skipped.
+  // This class centralizes that logic.
+  class StringBuilder {
+   public:
+    // Empty constructor. Used for creating a builder with which to Swap().
+    StringBuilder();
+
+    // |pos| is the beginning of an input string, excluding the |"|.
+    explicit StringBuilder(const char* pos);
+
+    ~StringBuilder();
+
+    // Swaps the contents of |other| with this.
+    void Swap(StringBuilder* other);
+
+    // Either increases the |length_| of the string or copies the character if
+    // the StringBuilder has been converted. |c| must be in the basic ASCII
+    // plane; all other characters need to be in UTF-8 units, appended with
+    // AppendString below.
+    void Append(const char& c);
+
+    // Appends a string to the std::string. Must be Convert()ed to use.
+    void AppendString(const std::string& str);
+
+    // Converts the builder from its default StringPiece to a full std::string,
+    // performing a copy. Once a builder is converted, it cannot be made a
+    // StringPiece again.
+    void Convert();
+
+    // Returns whether the builder can be converted to a StringPiece.
+    bool CanBeStringPiece() const;
+
+    // Returns the StringPiece representation. Returns an empty piece if it
+    // cannot be converted.
+    StringPiece AsStringPiece();
+
+    // Returns the builder as a std::string.
+    const std::string& AsString();
+
+   private:
+    // The beginning of the input string.
+    const char* pos_;
+
+    // Number of bytes in |pos_| that make up the string being built.
+    size_t length_;
+
+    // The copied string representation. NULL until Convert() is called.
+    // Strong. scoped_ptr<T> has too much of an overhead here.
+    std::string* string_;
+  };
+
+  // Quick check that the stream has capacity to consume |length| more bytes.
+  bool CanConsume(int length);
+
+  // The basic way to consume a single character in the stream. Consumes one
+  // byte of the input stream and returns a pointer to the rest of it.
+  const char* NextChar();
+
+  // Performs the equivalent of NextChar N times.
+  void NextNChars(int n);
+
+  // Skips over whitespace and comments to find the next token in the stream.
+  // This does not advance the parser for non-whitespace or comment chars.
+  Token GetNextToken();
+
+  // Consumes whitespace characters and comments until the next non-that is
+  // encountered.
+  void EatWhitespaceAndComments();
+  // Helper function that consumes a comment, assuming that the parser is
+  // currently wound to a '/'.
+  bool EatComment();
+
+  // Calls GetNextToken() and then ParseToken(). Caller owns the result.
+  Value* ParseNextToken();
+
+  // Takes a token that represents the start of a Value ("a structural token"
+  // in RFC terms) and consumes it, returning the result as an object the
+  // caller owns.
+  Value* ParseToken(Token token);
+
+  // Assuming that the parser is currently wound to '{', this parses a JSON
+  // object into a DictionaryValue.
+  Value* ConsumeDictionary();
+
+  // Assuming that the parser is wound to '[', this parses a JSON list into a
+  // ListValue.
+  Value* ConsumeList();
+
+  // Calls through ConsumeStringRaw and wraps it in a value.
+  Value* ConsumeString();
+
+  // Assuming that the parser is wound to a double quote, this parses a string,
+  // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on
+  // success and Swap()s the result into |out|. Returns false on failure with
+  // error information set.
+  bool ConsumeStringRaw(StringBuilder* out);
+  // Helper function for ConsumeStringRaw() that consumes the next four or 10
+  // bytes (parser is wound to the first character of a HEX sequence, with the
+  // potential for consuming another \uXXXX for a surrogate). Returns true on
+  // success and places the UTF8 code units in |dest_string|, and false on
+  // failure.
+  bool DecodeUTF16(std::string* dest_string);
+  // Helper function for ConsumeStringRaw() that takes a single code point,
+  // decodes it into UTF-8 units, and appends it to the given builder. The
+  // point must be valid.
+  void DecodeUTF8(const int32& point, StringBuilder* dest);
+
+  // Assuming that the parser is wound to the start of a valid JSON number,
+  // this parses and converts it to either an int or double value.
+  Value* ConsumeNumber();
+  // Helper that reads characters that are ints. Returns true if a number was
+  // read and false on error.
+  bool ReadInt(bool allow_leading_zeros);
+
+  // Consumes the literal values of |true|, |false|, and |null|, assuming the
+  // parser is wound to the first character of any of those.
+  Value* ConsumeLiteral();
+
+  // Compares two string buffers of a given length.
+  static bool StringsAreEqual(const char* left, const char* right, size_t len);
+
+  // Sets the error information to |code| at the current column, based on
+  // |index_| and |index_last_line_|, with an optional positive/negative
+  // adjustment by |column_adjust|.
+  void ReportError(JSONReader::JsonParseError code, int column_adjust);
+
+  // Given the line and column number of an error, formats one of the error
+  // message contants from json_reader.h for human display.
+  static std::string FormatErrorMessage(int line, int column,
+                                        const std::string& description);
+
+  // base::JSONParserOptions that control parsing.
+  int options_;
+
+  // Pointer to the start of the input data.
+  const char* start_pos_;
+
+  // Pointer to the current position in the input data. Equivalent to
+  // |start_pos_ + index_|.
+  const char* pos_;
+
+  // Pointer to the last character of the input data.
+  const char* end_pos_;
+
+  // The index in the input stream to which the parser is wound.
+  int index_;
+
+  // The number of times the parser has recursed (current stack depth).
+  int stack_depth_;
+
+  // The line number that the parser is at currently.
+  int line_number_;
+
+  // The last value of |index_| on the previous line.
+  int index_last_line_;
+
+  // Error information.
+  JSONReader::JsonParseError error_code_;
+  int error_line_;
+  int error_column_;
+
+  friend class JSONParserTest;
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, NextChar);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeDictionary);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeList);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeString);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeLiterals);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeNumbers);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ErrorMessages);
+
+  DISALLOW_COPY_AND_ASSIGN(JSONParser);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_PARSER_H_
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
new file mode 100644
index 0000000..74e2026
--- /dev/null
+++ b/base/json/json_parser_unittest.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "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);
+
+  error_code = 0;
+  error_message = "";
+  // Test line and column counting with "\r\n" line ending
+  const char big_json_crlf[] =
+      "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]";
+  // error here ----------------------^
+  root.reset(JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
+
+  // Test each of the error conditions
+  root.reset(JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
+      JSONReader::kUnexpectedDataAfterRoot), error_message);
+  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code);
+
+  std::string nested_json;
+  for (int i = 0; i < 101; ++i) {
+    nested_json.insert(nested_json.begin(), '[');
+    nested_json.append(1, ']');
+  }
+  root.reset(JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 100, JSONReader::kTooMuchNesting),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code);
+
+  root.reset(JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+
+  root.reset(JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2,
+      JSONReader::kUnquotedDictionaryKey), error_message);
+  EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code);
+
+  root.reset(JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}",
+                                            JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
+            error_message);
+
+  root.reset(JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
+
+  root.reset(JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
+
+  root.reset(JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
+
+  root.reset(JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC,
+                                            &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
+}
+
+TEST_F(JSONParserTest, Decode4ByteUtf8Char) {
+  // This test strings contains a 4 byte unicode character (a smiley!) that the
+  // reader should be able to handle (the character is \xf0\x9f\x98\x87).
+  const char kUtf8Data[] =
+      "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
+  std::string error_message;
+  int error_code = 0;
+  scoped_ptr<Value> root(
+      JSONReader::ReadAndReturnError(kUtf8Data, JSON_PARSE_RFC, &error_code,
+                                     &error_message));
+  EXPECT_TRUE(root.get()) << error_message;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
new file mode 100644
index 0000000..e17d450
--- /dev/null
+++ b/base/json/json_reader.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_reader.h"
+
+#include "base/json/json_parser.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
+COMPILE_ASSERT(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
+               json_reader_error_out_of_bounds);
+
+const char JSONReader::kInvalidEscape[] =
+    "Invalid escape sequence.";
+const char JSONReader::kSyntaxError[] =
+    "Syntax error.";
+const char JSONReader::kUnexpectedToken[] =
+    "Unexpected token.";
+const char JSONReader::kTrailingComma[] =
+    "Trailing comma not allowed.";
+const char JSONReader::kTooMuchNesting[] =
+    "Too much nesting.";
+const char JSONReader::kUnexpectedDataAfterRoot[] =
+    "Unexpected data after root element.";
+const char JSONReader::kUnsupportedEncoding[] =
+    "Unsupported encoding. JSON must be UTF-8.";
+const char JSONReader::kUnquotedDictionaryKey[] =
+    "Dictionary keys must be quoted.";
+
+JSONReader::JSONReader()
+    : JSONReader(JSON_PARSE_RFC) {
+}
+
+JSONReader::JSONReader(int options)
+    : parser_(new internal::JSONParser(options)) {
+}
+
+JSONReader::~JSONReader() {
+}
+
+// static
+Value* JSONReader::Read(const StringPiece& json) {
+  internal::JSONParser parser(JSON_PARSE_RFC);
+  return parser.Parse(json);
+}
+
+// static
+Value* JSONReader::Read(const StringPiece& json,
+                        int options) {
+  internal::JSONParser parser(options);
+  return parser.Parse(json);
+}
+
+// static
+Value* JSONReader::ReadAndReturnError(const StringPiece& json,
+                                      int options,
+                                      int* error_code_out,
+                                      std::string* error_msg_out) {
+  internal::JSONParser parser(options);
+  Value* root = parser.Parse(json);
+  if (root)
+    return root;
+
+  if (error_code_out)
+    *error_code_out = parser.error_code();
+  if (error_msg_out)
+    *error_msg_out = parser.GetErrorMessage();
+
+  return NULL;
+}
+
+// static
+std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
+  switch (error_code) {
+    case JSON_NO_ERROR:
+      return std::string();
+    case JSON_INVALID_ESCAPE:
+      return kInvalidEscape;
+    case JSON_SYNTAX_ERROR:
+      return kSyntaxError;
+    case JSON_UNEXPECTED_TOKEN:
+      return kUnexpectedToken;
+    case JSON_TRAILING_COMMA:
+      return kTrailingComma;
+    case JSON_TOO_MUCH_NESTING:
+      return kTooMuchNesting;
+    case JSON_UNEXPECTED_DATA_AFTER_ROOT:
+      return kUnexpectedDataAfterRoot;
+    case JSON_UNSUPPORTED_ENCODING:
+      return kUnsupportedEncoding;
+    case JSON_UNQUOTED_DICTIONARY_KEY:
+      return kUnquotedDictionaryKey;
+    default:
+      NOTREACHED();
+      return std::string();
+  }
+}
+
+Value* JSONReader::ReadToValue(const std::string& json) {
+  return parser_->Parse(json);
+}
+
+JSONReader::JsonParseError JSONReader::error_code() const {
+  return parser_->error_code();
+}
+
+std::string JSONReader::GetErrorMessage() const {
+  return parser_->GetErrorMessage();
+}
+
+}  // namespace base
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
new file mode 100644
index 0000000..fd053d4
--- /dev/null
+++ b/base/json/json_reader.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A JSON parser.  Converts strings of JSON into a Value object (see
+// base/values.h).
+// http://www.ietf.org/rfc/rfc4627.txt?number=4627
+//
+// Known limitations/deviations from the RFC:
+// - Only knows how to parse ints within the range of a signed 32 bit int and
+//   decimal numbers within a double.
+// - Assumes input is encoded as UTF8.  The spec says we should allow UTF-16
+//   (BE or LE) and UTF-32 (BE or LE) as well.
+// - We limit nesting to 100 levels to prevent stack overflow (this is allowed
+//   by the RFC).
+// - A Unicode FAQ ("http://unicode.org/faq/utf_bom.html") writes a data
+//   stream may start with a Unicode Byte-Order-Mark (U+FEFF), i.e. the input
+//   UTF-8 string for the JSONReader::JsonToValue() function may start with a
+//   UTF-8 BOM (0xEF, 0xBB, 0xBF).
+//   To avoid the function from mis-treating a UTF-8 BOM as an invalid
+//   character, the function skips a Unicode BOM at the beginning of the
+//   Unicode string (converted from the input UTF-8 string) before parsing it.
+//
+// TODO(tc): Add a parsing option to to relax object keys being wrapped in
+//   double quotes
+// TODO(tc): Add an option to disable comment stripping
+
+#ifndef BASE_JSON_JSON_READER_H_
+#define BASE_JSON_JSON_READER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class Value;
+
+namespace internal {
+class JSONParser;
+}
+
+enum JSONParserOptions {
+  // Parses the input strictly according to RFC 4627, except for where noted
+  // above.
+  JSON_PARSE_RFC = 0,
+
+  // Allows commas to exist after the last element in structures.
+  JSON_ALLOW_TRAILING_COMMAS = 1 << 0,
+
+  // The parser can perform optimizations by placing hidden data in the root of
+  // the JSON object, which speeds up certain operations on children. However,
+  // if the child is Remove()d from root, it would result in use-after-free
+  // unless it is DeepCopy()ed or this option is used.
+  JSON_DETACHABLE_CHILDREN = 1 << 1,
+};
+
+class BASE_EXPORT JSONReader {
+ public:
+  // Error codes during parsing.
+  enum JsonParseError {
+    JSON_NO_ERROR = 0,
+    JSON_INVALID_ESCAPE,
+    JSON_SYNTAX_ERROR,
+    JSON_UNEXPECTED_TOKEN,
+    JSON_TRAILING_COMMA,
+    JSON_TOO_MUCH_NESTING,
+    JSON_UNEXPECTED_DATA_AFTER_ROOT,
+    JSON_UNSUPPORTED_ENCODING,
+    JSON_UNQUOTED_DICTIONARY_KEY,
+    JSON_PARSE_ERROR_COUNT
+  };
+
+  // String versions of parse error codes.
+  static const char kInvalidEscape[];
+  static const char kSyntaxError[];
+  static const char kUnexpectedToken[];
+  static const char kTrailingComma[];
+  static const char kTooMuchNesting[];
+  static const char kUnexpectedDataAfterRoot[];
+  static const char kUnsupportedEncoding[];
+  static const char kUnquotedDictionaryKey[];
+
+  // Constructs a reader with the default options, JSON_PARSE_RFC.
+  JSONReader();
+
+  // Constructs a reader with custom options.
+  explicit JSONReader(int options);
+
+  ~JSONReader();
+
+  // Reads and parses |json|, returning a Value. The caller owns the returned
+  // instance. If |json| is not a properly formed JSON string, returns NULL.
+  static Value* Read(const StringPiece& json);
+
+  // Reads and parses |json|, returning a Value owned by the caller. The
+  // parser respects the given |options|. If the input is not properly formed,
+  // returns NULL.
+  static Value* Read(const StringPiece& json, int options);
+
+  // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
+  // are optional. If specified and NULL is returned, they will be populated
+  // an error code and a formatted error message (including error location if
+  // appropriate). Otherwise, they will be unmodified.
+  static Value* ReadAndReturnError(const StringPiece& json,
+                                   int options,  // JSONParserOptions
+                                   int* error_code_out,
+                                   std::string* error_msg_out);
+
+  // Converts a JSON parse error code into a human readable message.
+  // Returns an empty string if error_code is JSON_NO_ERROR.
+  static std::string ErrorCodeToString(JsonParseError error_code);
+
+  // Parses an input string into a Value that is owned by the caller.
+  Value* ReadToValue(const std::string& json);
+
+  // Returns the error code if the last call to ReadToValue() failed.
+  // Returns JSON_NO_ERROR otherwise.
+  JsonParseError error_code() const;
+
+  // Converts error_code_ to a human-readable string, including line and column
+  // numbers if appropriate.
+  std::string GetErrorMessage() const;
+
+ private:
+  scoped_ptr<internal::JSONParser> parser_;
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_READER_H_
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
new file mode 100644
index 0000000..a3ec4f7
--- /dev/null
+++ b/base/json/json_reader_unittest.cc
@@ -0,0 +1,656 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_reader.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONReaderTest, Reading) {
+  // some whitespace checking
+  scoped_ptr<Value> root;
+  root.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());
+  root.reset(JSONReader().ReadToValue("/* comment **/42"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(42, int_val);
+  root.reset(JSONReader().ReadToValue(
+      "/* comment **/\n"
+      "// */ 43\n"
+      "44"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(44, int_val);
+
+  // Test number formats
+  root.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* const cases[] = {
+    "\"\\u123\"",  // Invalid scalar.
+    "\"\\ud83d\"",  // Invalid scalar.
+    "\"\\u$%@!\"",  // Invalid scalar.
+    "\"\\uzz89\"",  // Invalid scalar.
+    "\"\\ud83d\\udca\"",  // Invalid lower surrogate.
+    "\"\\ud83d\\ud83d\"",  // Invalid lower surrogate.
+    "\"\\ud83foo\"",  // No lower surrogate.
+    "\"\\ud83\\foo\""  // No lower surrogate.
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    root.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_TEST_DATA, &path));
+  path = path.AppendASCII("json");
+  ASSERT_TRUE(base::PathExists(path));
+
+  std::string input;
+  ASSERT_TRUE(ReadFileToString(
+      path.Append(FILE_PATH_LITERAL("bom_feff.json")), &input));
+
+  JSONReader reader;
+  scoped_ptr<Value> root(reader.ReadToValue(input));
+  ASSERT_TRUE(root.get()) << reader.GetErrorMessage();
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+}
+
+// Tests that the root of a JSON object can be deleted safely while its
+// children outlive it.
+TEST(JSONReaderTest, StringOptimizations) {
+  scoped_ptr<Value> dict_literal_0;
+  scoped_ptr<Value> dict_literal_1;
+  scoped_ptr<Value> dict_string_0;
+  scoped_ptr<Value> dict_string_1;
+  scoped_ptr<Value> list_value_0;
+  scoped_ptr<Value> list_value_1;
+
+  {
+    scoped_ptr<Value> root(JSONReader::Read(
+        "{"
+        "  \"test\": {"
+        "    \"foo\": true,"
+        "    \"bar\": 3.14,"
+        "    \"baz\": \"bat\","
+        "    \"moo\": \"cow\""
+        "  },"
+        "  \"list\": ["
+        "    \"a\","
+        "    \"b\""
+        "  ]"
+        "}", JSON_DETACHABLE_CHILDREN));
+    ASSERT_TRUE(root.get());
+
+    DictionaryValue* root_dict = NULL;
+    ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+    DictionaryValue* dict = NULL;
+    ListValue* list = NULL;
+
+    ASSERT_TRUE(root_dict->GetDictionary("test", &dict));
+    ASSERT_TRUE(root_dict->GetList("list", &list));
+
+    EXPECT_TRUE(dict->Remove("foo", &dict_literal_0));
+    EXPECT_TRUE(dict->Remove("bar", &dict_literal_1));
+    EXPECT_TRUE(dict->Remove("baz", &dict_string_0));
+    EXPECT_TRUE(dict->Remove("moo", &dict_string_1));
+
+    ASSERT_EQ(2u, list->GetSize());
+    EXPECT_TRUE(list->Remove(0, &list_value_0));
+    EXPECT_TRUE(list->Remove(0, &list_value_1));
+  }
+
+  bool b = false;
+  double d = 0;
+  std::string s;
+
+  EXPECT_TRUE(dict_literal_0->GetAsBoolean(&b));
+  EXPECT_TRUE(b);
+
+  EXPECT_TRUE(dict_literal_1->GetAsDouble(&d));
+  EXPECT_EQ(3.14, d);
+
+  EXPECT_TRUE(dict_string_0->GetAsString(&s));
+  EXPECT_EQ("bat", s);
+
+  EXPECT_TRUE(dict_string_1->GetAsString(&s));
+  EXPECT_EQ("cow", s);
+
+  EXPECT_TRUE(list_value_0->GetAsString(&s));
+  EXPECT_EQ("a", s);
+  EXPECT_TRUE(list_value_1->GetAsString(&s));
+  EXPECT_EQ("b", s);
+}
+
+// A smattering of invalid JSON designed to test specific portions of the
+// parser implementation against buffer overflow. Best run with DCHECKs so
+// that the one in NextChar fires.
+TEST(JSONReaderTest, InvalidSanity) {
+  const char* const invalid_json[] = {
+      "/* test *",
+      "{\"foo\"",
+      "{\"foo\":",
+      "  [",
+      "\"\\u123g\"",
+      "{\n\"eh:\n}",
+  };
+
+  for (size_t i = 0; i < arraysize(invalid_json); ++i) {
+    JSONReader reader;
+    LOG(INFO) << "Sanity test " << i << ": <" << invalid_json[i] << ">";
+    EXPECT_FALSE(reader.ReadToValue(invalid_json[i]));
+    EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code());
+    EXPECT_NE("", reader.GetErrorMessage());
+  }
+}
+
+TEST(JSONReaderTest, IllegalTrailingNull) {
+  const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' };
+  std::string json_string(json, sizeof(json));
+  JSONReader reader;
+  EXPECT_FALSE(reader.ReadToValue(json_string));
+  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code());
+}
+
+}  // namespace base
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
new file mode 100644
index 0000000..debf9f0
--- /dev/null
+++ b/base/json/json_string_value_serializer.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_string_value_serializer.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+
+using base::Value;
+
+JSONStringValueSerializer::JSONStringValueSerializer(std::string* json_string)
+    : json_string_(json_string),
+      pretty_print_(false) {
+}
+
+JSONStringValueSerializer::~JSONStringValueSerializer() {}
+
+bool JSONStringValueSerializer::Serialize(const Value& root) {
+  return SerializeInternal(root, false);
+}
+
+bool JSONStringValueSerializer::SerializeAndOmitBinaryValues(
+    const Value& root) {
+  return SerializeInternal(root, true);
+}
+
+bool JSONStringValueSerializer::SerializeInternal(const Value& root,
+                                                  bool omit_binary_values) {
+  if (!json_string_)
+    return false;
+
+  int options = 0;
+  if (omit_binary_values)
+    options |= base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES;
+  if (pretty_print_)
+    options |= base::JSONWriter::OPTIONS_PRETTY_PRINT;
+
+  return base::JSONWriter::WriteWithOptions(&root, options, json_string_);
+}
+
+JSONStringValueDeserializer::JSONStringValueDeserializer(
+    const base::StringPiece& json_string)
+    : json_string_(json_string),
+      allow_trailing_comma_(false) {
+}
+
+JSONStringValueDeserializer::~JSONStringValueDeserializer() {}
+
+Value* JSONStringValueDeserializer::Deserialize(int* error_code,
+                                                std::string* error_str) {
+  return base::JSONReader::ReadAndReturnError(json_string_,
+      allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS :
+          base::JSON_PARSE_RFC,
+      error_code, error_str);
+}
diff --git a/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h
new file mode 100644
index 0000000..bc0e66d
--- /dev/null
+++ b/base/json/json_string_value_serializer.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
+#define BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+
+class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
+ public:
+  // |json_string| is the string that will be the destination of the
+  // serialization.  The caller of the constructor retains ownership of the
+  // string. |json_string| must not be null.
+  explicit JSONStringValueSerializer(std::string* json_string);
+
+  ~JSONStringValueSerializer() override;
+
+  // Attempt to serialize the data structure represented by Value into
+  // JSON.  If the return value is true, the result will have been written
+  // into the string passed into the constructor.
+  bool Serialize(const base::Value& root) override;
+
+  // Equivalent to Serialize(root) except binary values are omitted from the
+  // output.
+  bool SerializeAndOmitBinaryValues(const base::Value& root);
+
+  void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
+  bool pretty_print() { return pretty_print_; }
+
+ private:
+  bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+  // Owned by the caller of the constructor.
+  std::string* json_string_;
+  bool pretty_print_;  // If true, serialization will span multiple lines.
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer);
+};
+
+class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer {
+ public:
+  // This retains a reference to the contents of |json_string|, so the data
+  // must outlive the JSONStringValueDeserializer.
+  explicit JSONStringValueDeserializer(const base::StringPiece& json_string);
+
+  ~JSONStringValueDeserializer() override;
+
+  // Attempt to deserialize the data structure encoded in the string passed
+  // in to the constructor into a structure of Value objects.  If the return
+  // value is null, and if |error_code| is non-null, |error_code| will
+  // contain an integer error code (a JsonParseError in this case).
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  // The caller takes ownership of the returned value.
+  base::Value* Deserialize(int* error_code,
+                           std::string* error_message) override;
+
+  void set_allow_trailing_comma(bool new_value) {
+    allow_trailing_comma_ = new_value;
+  }
+
+ private:
+  // Data is owned by the caller of the constructor.
+  base::StringPiece json_string_;
+  // If true, deserialization will allow trailing commas.
+  bool allow_trailing_comma_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValueDeserializer);
+};
+
+#endif  // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
diff --git a/base/json/json_value_converter.cc b/base/json/json_value_converter.cc
new file mode 100644
index 0000000..6f772f3
--- /dev/null
+++ b/base/json/json_value_converter.cc
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_value_converter.h"
+
+namespace base {
+namespace internal {
+
+bool BasicValueConverter<int>::Convert(
+    const base::Value& value, int* field) const {
+  return value.GetAsInteger(field);
+}
+
+bool BasicValueConverter<std::string>::Convert(
+    const base::Value& value, std::string* field) const {
+  return value.GetAsString(field);
+}
+
+bool BasicValueConverter<string16>::Convert(
+    const base::Value& value, string16* field) const {
+  return value.GetAsString(field);
+}
+
+bool BasicValueConverter<double>::Convert(
+    const base::Value& value, double* field) const {
+  return value.GetAsDouble(field);
+}
+
+bool BasicValueConverter<bool>::Convert(
+    const base::Value& value, bool* field) const {
+  return value.GetAsBoolean(field);
+}
+
+}  // namespace internal
+}  // namespace base
+
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h
new file mode 100644
index 0000000..f94d46e
--- /dev/null
+++ b/base/json/json_value_converter.h
@@ -0,0 +1,514 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_
+#define BASE_JSON_JSON_VALUE_CONVERTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+
+// JSONValueConverter converts a JSON value into a C++ struct in a
+// lightweight way.
+//
+// Usage:
+// For real examples, you may want to refer to _unittest.cc file.
+//
+// Assume that you have a struct like this:
+//   struct Message {
+//     int foo;
+//     std::string bar;
+//     static void RegisterJSONConverter(
+//         JSONValueConverter<Message>* converter);
+//   };
+//
+// And you want to parse a json data into this struct.  First, you
+// need to declare RegisterJSONConverter() method in your struct.
+//   // static
+//   void Message::RegisterJSONConverter(
+//       JSONValueConverter<Message>* converter) {
+//     converter->RegisterIntField("foo", &Message::foo);
+//     converter->RegisterStringField("bar", &Message::bar);
+//   }
+//
+// Then, you just instantiate your JSONValueConverter of your type and call
+// Convert() method.
+//   Message message;
+//   JSONValueConverter<Message> converter;
+//   converter.Convert(json, &message);
+//
+// Convert() returns false when it fails.  Here "fail" means that the value is
+// structurally different from expected, such like a string value appears
+// for an int field.  Do not report failures for missing fields.
+// Also note that Convert() will modify the passed |message| even when it
+// fails for performance reason.
+//
+// For nested field, the internal message also has to implement the registration
+// method.  Then, just use RegisterNestedField() from the containing struct's
+// RegisterJSONConverter method.
+//   struct Nested {
+//     Message foo;
+//     static void RegisterJSONConverter(...) {
+//       ...
+//       converter->RegisterNestedField("foo", &Nested::foo);
+//     }
+//   };
+//
+// For repeated field, we just assume ScopedVector for its container
+// and you can put RegisterRepeatedInt or some other types.  Use
+// RegisterRepeatedMessage for nested repeated fields.
+//
+// Sometimes JSON format uses string representations for other types such
+// like enum, timestamp, or URL.  You can use RegisterCustomField method
+// and specify a function to convert a StringPiece to your type.
+//   bool ConvertFunc(const StringPiece& s, YourEnum* result) {
+//     // do something and return true if succeed...
+//   }
+//   struct Message {
+//     YourEnum ye;
+//     ...
+//     static void RegisterJSONConverter(...) {
+//       ...
+//       converter->RegsiterCustomField<YourEnum>(
+//           "your_enum", &Message::ye, &ConvertFunc);
+//     }
+//   };
+
+namespace base {
+
+template <typename StructType>
+class JSONValueConverter;
+
+namespace internal {
+
+template<typename StructType>
+class FieldConverterBase {
+ public:
+  explicit FieldConverterBase(const std::string& path) : field_path_(path) {}
+  virtual ~FieldConverterBase() {}
+  virtual bool ConvertField(const base::Value& value, StructType* obj)
+      const = 0;
+  const std::string& field_path() const { return field_path_; }
+
+ private:
+  std::string field_path_;
+  DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
+};
+
+template <typename FieldType>
+class ValueConverter {
+ public:
+  virtual ~ValueConverter() {}
+  virtual bool Convert(const base::Value& value, FieldType* field) const = 0;
+};
+
+template <typename StructType, typename FieldType>
+class FieldConverter : public FieldConverterBase<StructType> {
+ public:
+  explicit FieldConverter(const std::string& path,
+                          FieldType StructType::* field,
+                          ValueConverter<FieldType>* converter)
+      : FieldConverterBase<StructType>(path),
+        field_pointer_(field),
+        value_converter_(converter) {
+  }
+
+  bool ConvertField(const base::Value& value, StructType* dst) const override {
+    return value_converter_->Convert(value, &(dst->*field_pointer_));
+  }
+
+ private:
+  FieldType StructType::* field_pointer_;
+  scoped_ptr<ValueConverter<FieldType> > value_converter_;
+  DISALLOW_COPY_AND_ASSIGN(FieldConverter);
+};
+
+template <typename FieldType>
+class BasicValueConverter;
+
+template <>
+class BASE_EXPORT BasicValueConverter<int> : public ValueConverter<int> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, int* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<std::string>
+    : public ValueConverter<std::string> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, std::string* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<string16>
+    : public ValueConverter<string16> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, string16* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<double> : public ValueConverter<double> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, double* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<bool> : public ValueConverter<bool> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, bool* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <typename FieldType>
+class ValueFieldConverter : public ValueConverter<FieldType> {
+ public:
+  typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field);
+
+  ValueFieldConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  bool Convert(const base::Value& value, FieldType* field) const override {
+    return convert_func_(&value, field);
+  }
+
+ private:
+  ConvertFunc convert_func_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter);
+};
+
+template <typename FieldType>
+class CustomFieldConverter : public ValueConverter<FieldType> {
+ public:
+  typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field);
+
+  CustomFieldConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  bool Convert(const base::Value& value, FieldType* field) const override {
+    std::string string_value;
+    return value.GetAsString(&string_value) &&
+        convert_func_(string_value, field);
+  }
+
+ private:
+  ConvertFunc convert_func_;
+
+  DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
+};
+
+template <typename NestedType>
+class NestedValueConverter : public ValueConverter<NestedType> {
+ public:
+  NestedValueConverter() {}
+
+  bool Convert(const base::Value& value, NestedType* field) const override {
+    return converter_.Convert(value, field);
+  }
+
+ private:
+  JSONValueConverter<NestedType> converter_;
+  DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
+};
+
+template <typename Element>
+class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > {
+ public:
+  RepeatedValueConverter() {}
+
+  bool Convert(const base::Value& value,
+               ScopedVector<Element>* field) const override {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list)) {
+      // The field is not a list.
+      return false;
+    }
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<Element> e(new Element);
+      if (basic_converter_.Convert(*element, e.get())) {
+        field->push_back(e.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  BasicValueConverter<Element> basic_converter_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
+};
+
+template <typename NestedType>
+class RepeatedMessageConverter
+    : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+  RepeatedMessageConverter() {}
+
+  bool Convert(const base::Value& value,
+               ScopedVector<NestedType>* field) const override {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list))
+      return false;
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<NestedType> nested(new NestedType);
+      if (converter_.Convert(*element, nested.get())) {
+        field->push_back(nested.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  JSONValueConverter<NestedType> converter_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
+};
+
+template <typename NestedType>
+class RepeatedCustomValueConverter
+    : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+  typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
+
+  RepeatedCustomValueConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  bool Convert(const base::Value& value,
+               ScopedVector<NestedType>* field) const override {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list))
+      return false;
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<NestedType> nested(new NestedType);
+      if ((*convert_func_)(element, nested.get())) {
+        field->push_back(nested.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  ConvertFunc convert_func_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
+};
+
+
+}  // namespace internal
+
+template <class StructType>
+class JSONValueConverter {
+ public:
+  JSONValueConverter() {
+    StructType::RegisterJSONConverter(this);
+  }
+
+  void RegisterIntField(const std::string& field_name,
+                        int StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, int>(
+        field_name, field, new internal::BasicValueConverter<int>));
+  }
+
+  void RegisterStringField(const std::string& field_name,
+                           std::string StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, std::string>(
+        field_name, field, new internal::BasicValueConverter<std::string>));
+  }
+
+  void RegisterStringField(const std::string& field_name,
+                           string16 StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, string16>(
+        field_name, field, new internal::BasicValueConverter<string16>));
+  }
+
+  void RegisterBoolField(const std::string& field_name,
+                         bool StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, bool>(
+        field_name, field, new internal::BasicValueConverter<bool>));
+  }
+
+  void RegisterDoubleField(const std::string& field_name,
+                           double StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, double>(
+        field_name, field, new internal::BasicValueConverter<double>));
+  }
+
+  template <class NestedType>
+  void RegisterNestedField(
+      const std::string& field_name, NestedType StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, NestedType>(
+            field_name,
+            field,
+            new internal::NestedValueConverter<NestedType>));
+  }
+
+  template <typename FieldType>
+  void RegisterCustomField(
+      const std::string& field_name,
+      FieldType StructType::* field,
+      bool (*convert_func)(const StringPiece&, FieldType*)) {
+    fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+        field_name,
+        field,
+        new internal::CustomFieldConverter<FieldType>(convert_func)));
+  }
+
+  template <typename FieldType>
+  void RegisterCustomValueField(
+      const std::string& field_name,
+      FieldType StructType::* field,
+      bool (*convert_func)(const base::Value*, FieldType*)) {
+    fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+        field_name,
+        field,
+        new internal::ValueFieldConverter<FieldType>(convert_func)));
+  }
+
+  void RegisterRepeatedInt(const std::string& field_name,
+                           ScopedVector<int> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<int> >(
+            field_name, field, new internal::RepeatedValueConverter<int>));
+  }
+
+  void RegisterRepeatedString(const std::string& field_name,
+                              ScopedVector<std::string> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<std::string> >(
+            field_name,
+            field,
+            new internal::RepeatedValueConverter<std::string>));
+  }
+
+  void RegisterRepeatedString(const std::string& field_name,
+                              ScopedVector<string16> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<string16> >(
+            field_name,
+            field,
+            new internal::RepeatedValueConverter<string16>));
+  }
+
+  void RegisterRepeatedDouble(const std::string& field_name,
+                              ScopedVector<double> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<double> >(
+            field_name, field, new internal::RepeatedValueConverter<double>));
+  }
+
+  void RegisterRepeatedBool(const std::string& field_name,
+                            ScopedVector<bool> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<bool> >(
+            field_name, field, new internal::RepeatedValueConverter<bool>));
+  }
+
+  template <class NestedType>
+  void RegisterRepeatedCustomValue(
+      const std::string& field_name,
+      ScopedVector<NestedType> StructType::* field,
+      bool (*convert_func)(const base::Value*, NestedType*)) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+            field_name,
+            field,
+            new internal::RepeatedCustomValueConverter<NestedType>(
+                convert_func)));
+  }
+
+  template <class NestedType>
+  void RegisterRepeatedMessage(const std::string& field_name,
+                               ScopedVector<NestedType> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+            field_name,
+            field,
+            new internal::RepeatedMessageConverter<NestedType>));
+  }
+
+  bool Convert(const base::Value& value, StructType* output) const {
+    const DictionaryValue* dictionary_value = NULL;
+    if (!value.GetAsDictionary(&dictionary_value))
+      return false;
+
+    for(size_t i = 0; i < fields_.size(); ++i) {
+      const internal::FieldConverterBase<StructType>* field_converter =
+          fields_[i];
+      const base::Value* field = NULL;
+      if (dictionary_value->Get(field_converter->field_path(), &field)) {
+        if (!field_converter->ConvertField(*field, output)) {
+          DVLOG(1) << "failure at field " << field_converter->field_path();
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+ private:
+  ScopedVector<internal::FieldConverterBase<StructType> > fields_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_VALUE_CONVERTER_H_
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc
new file mode 100644
index 0000000..7d48f39
--- /dev/null
+++ b/base/json/json_value_converter_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_value_converter.h"
+
+#include <string>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// Very simple messages.
+struct SimpleMessage {
+  enum SimpleEnum {
+    FOO, BAR,
+  };
+  int foo;
+  std::string bar;
+  bool baz;
+  bool bstruct;
+  SimpleEnum simple_enum;
+  ScopedVector<int> ints;
+  ScopedVector<std::string> string_values;
+  SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {}
+
+  static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) {
+    if (value == "foo") {
+      *field = FOO;
+      return true;
+    } else if (value == "bar") {
+      *field = BAR;
+      return true;
+    }
+    return false;
+  }
+
+  static bool HasFieldPresent(const base::Value* value, bool* result) {
+    *result = value != NULL;
+    return true;
+  }
+
+  static bool GetValueString(const base::Value* value, std::string* result) {
+    const base::DictionaryValue* dict = NULL;
+    if (!value->GetAsDictionary(&dict))
+      return false;
+
+    if (!dict->GetString("val", result))
+      return false;
+
+    return true;
+  }
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<SimpleMessage>* converter) {
+    converter->RegisterIntField("foo", &SimpleMessage::foo);
+    converter->RegisterStringField("bar", &SimpleMessage::bar);
+    converter->RegisterBoolField("baz", &SimpleMessage::baz);
+    converter->RegisterCustomField<SimpleEnum>(
+        "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
+    converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
+    converter->RegisterCustomValueField<bool>("bstruct",
+                                              &SimpleMessage::bstruct,
+                                              &HasFieldPresent);
+    converter->RegisterRepeatedCustomValue<std::string>(
+        "string_values",
+        &SimpleMessage::string_values,
+        &GetValueString);
+  }
+};
+
+// For nested messages.
+struct NestedMessage {
+  double foo;
+  SimpleMessage child;
+  ScopedVector<SimpleMessage> children;
+
+  NestedMessage() : foo(0) {}
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<NestedMessage>* converter) {
+    converter->RegisterDoubleField("foo", &NestedMessage::foo);
+    converter->RegisterNestedField("child", &NestedMessage::child);
+    converter->RegisterRepeatedMessage("children", &NestedMessage::children);
+  }
+};
+
+}  // namespace
+
+TEST(JSONValueConverterTest, ParseSimpleMessage) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"bstruct\": {},\n"
+      "  \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
+      "  \"simple_enum\": \"foo\","
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1, message.foo);
+  EXPECT_EQ("bar", message.bar);
+  EXPECT_TRUE(message.baz);
+  EXPECT_EQ(SimpleMessage::FOO, message.simple_enum);
+  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
+  ASSERT_EQ(2U, message.string_values.size());
+  EXPECT_EQ("value_1", *message.string_values[0]);
+  EXPECT_EQ("value_2", *message.string_values[1]);
+  EXPECT_EQ(1, *(message.ints[0]));
+  EXPECT_EQ(2, *(message.ints[1]));
+}
+
+TEST(JSONValueConverterTest, ParseNestedMessage) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1.0,\n"
+      "  \"child\": {\n"
+      "    \"foo\": 1,\n"
+      "    \"bar\": \"bar\",\n"
+      "    \"bstruct\": {},\n"
+      "    \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
+      "    \"baz\": true\n"
+      "  },\n"
+      "  \"children\": [{\n"
+      "    \"foo\": 2,\n"
+      "    \"bar\": \"foobar\",\n"
+      "    \"bstruct\": \"\",\n"
+      "    \"string_values\": [{\"val\": \"value_1\"}],"
+      "    \"baz\": true\n"
+      "  },\n"
+      "  {\n"
+      "    \"foo\": 3,\n"
+      "    \"bar\": \"barbaz\",\n"
+      "    \"baz\": false\n"
+      "  }]\n"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  NestedMessage message;
+  base::JSONValueConverter<NestedMessage> converter;
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1.0, message.foo);
+  EXPECT_EQ(1, message.child.foo);
+  EXPECT_EQ("bar", message.child.bar);
+  EXPECT_TRUE(message.child.baz);
+  EXPECT_TRUE(message.child.bstruct);
+  ASSERT_EQ(2U, message.child.string_values.size());
+  EXPECT_EQ("value_1", *message.child.string_values[0]);
+  EXPECT_EQ("value_2", *message.child.string_values[1]);
+
+  EXPECT_EQ(2, static_cast<int>(message.children.size()));
+  const SimpleMessage* first_child = message.children[0];
+  ASSERT_TRUE(first_child);
+  EXPECT_EQ(2, first_child->foo);
+  EXPECT_EQ("foobar", first_child->bar);
+  EXPECT_TRUE(first_child->baz);
+  EXPECT_TRUE(first_child->bstruct);
+  ASSERT_EQ(1U, first_child->string_values.size());
+  EXPECT_EQ("value_1", *first_child->string_values[0]);
+
+  const SimpleMessage* second_child = message.children[1];
+  ASSERT_TRUE(second_child);
+  EXPECT_EQ(3, second_child->foo);
+  EXPECT_EQ("barbaz", second_child->bar);
+  EXPECT_FALSE(second_child->baz);
+  EXPECT_FALSE(second_child->bstruct);
+  EXPECT_EQ(0U, second_child->string_values.size());
+}
+
+TEST(JSONValueConverterTest, ParseFailures) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": 2,\n" // "bar" is an integer here.
+      "  \"baz\": true,\n"
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // Do not check the values below.  |message| may be modified during
+  // Convert() even it fails.
+}
+
+TEST(JSONValueConverterTest, ParseWithMissingFields) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"baz\": true,\n"
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  // Convert() still succeeds even if the input doesn't have "bar" field.
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1, message.foo);
+  EXPECT_TRUE(message.baz);
+  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
+  EXPECT_EQ(1, *(message.ints[0]));
+  EXPECT_EQ(2, *(message.ints[1]));
+}
+
+TEST(JSONValueConverterTest, EnumParserFails) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"simple_enum\": \"baz\","
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // No check the values as mentioned above.
+}
+
+TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"simple_enum\": \"baz\","
+      "  \"ints\": [1, false]"
+      "}\n";
+
+  scoped_ptr<Value> value(base::JSONReader::Read(normal_data));
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // No check the values as mentioned above.
+}
+
+}  // namespace base
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
new file mode 100644
index 0000000..b8aebe0
--- /dev/null
+++ b/base/json/json_value_serializer_unittest.cc
@@ -0,0 +1,497 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Some proper JSON to test with:
+const char kProperJSON[] =
+    "{\n"
+    "   \"compound\": {\n"
+    "      \"a\": 1,\n"
+    "      \"b\": 2\n"
+    "   },\n"
+    "   \"some_String\": \"1337\",\n"
+    "   \"some_int\": 42,\n"
+    "   \"the_list\": [ \"val1\", \"val2\" ]\n"
+    "}\n";
+
+// Some proper JSON with trailing commas:
+const char kProperJSONWithCommas[] =
+    "{\n"
+    "\t\"some_int\": 42,\n"
+    "\t\"some_String\": \"1337\",\n"
+    "\t\"the_list\": [\"val1\", \"val2\", ],\n"
+    "\t\"compound\": { \"a\": 1, \"b\": 2, },\n"
+    "}\n";
+
+// kProperJSON with a few misc characters at the begin and end.
+const char kProperJSONPadded[] =
+    ")]}'\n"
+    "{\n"
+    "   \"compound\": {\n"
+    "      \"a\": 1,\n"
+    "      \"b\": 2\n"
+    "   },\n"
+    "   \"some_String\": \"1337\",\n"
+    "   \"some_int\": 42,\n"
+    "   \"the_list\": [ \"val1\", \"val2\" ]\n"
+    "}\n"
+    "?!ab\n";
+
+const char kWinLineEnds[] = "\r\n";
+const char kLinuxLineEnds[] = "\n";
+
+// Verifies the generated JSON against the expected output.
+void CheckJSONIsStillTheSame(const Value& value) {
+  // Serialize back the output.
+  std::string serialized_json;
+  JSONStringValueSerializer str_serializer(&serialized_json);
+  str_serializer.set_pretty_print(true);
+  ASSERT_TRUE(str_serializer.Serialize(value));
+  // Unify line endings between platforms.
+  ReplaceSubstringsAfterOffset(&serialized_json, 0,
+                               kWinLineEnds, kLinuxLineEnds);
+  // Now compare the input with the output.
+  ASSERT_EQ(kProperJSON, serialized_json);
+}
+
+void ValidateJsonList(const std::string& json) {
+  scoped_ptr<Value> root(JSONReader::Read(json));
+  ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
+  ListValue* list = static_cast<ListValue*>(root.get());
+  ASSERT_EQ(1U, list->GetSize());
+  Value* elt = NULL;
+  ASSERT_TRUE(list->Get(0, &elt));
+  int value = 0;
+  ASSERT_TRUE(elt && elt->GetAsInteger(&value));
+  ASSERT_EQ(1, value);
+}
+
+// Test proper JSON deserialization from string is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromString) {
+  // Try to deserialize it through the serializer.
+  JSONStringValueDeserializer str_deserializer(kProperJSON);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test proper JSON deserialization from a StringPiece substring.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) {
+  // Create a StringPiece for the substring of kProperJSONPadded that matches
+  // kProperJSON.
+  base::StringPiece proper_json(kProperJSONPadded);
+  proper_json = proper_json.substr(5, proper_json.length() - 10);
+  JSONStringValueDeserializer str_deserializer(proper_json);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test that trialing commas are only properly deserialized from string when
+// the proper flag for that is set.
+TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) {
+  // Try to deserialize it through the serializer.
+  JSONStringValueDeserializer str_deserializer(kProperJSONWithCommas);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_FALSE(value.get());
+  ASSERT_NE(0, error_code);
+  ASSERT_FALSE(error_message.empty());
+  // Now the flag is set and it must pass.
+  str_deserializer.set_allow_trailing_comma(true);
+  value.reset(str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test proper JSON deserialization from file is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromFile) {
+  ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+  // Write it down in the file.
+  FilePath temp_file(tempdir.path().AppendASCII("test.json"));
+  ASSERT_EQ(static_cast<int>(strlen(kProperJSON)),
+            WriteFile(temp_file, kProperJSON, strlen(kProperJSON)));
+
+  // Try to deserialize it through the serializer.
+  JSONFileValueDeserializer file_deserializer(temp_file);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test that trialing commas are only properly deserialized from file when
+// the proper flag for that is set.
+TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) {
+  ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+  // Write it down in the file.
+  FilePath temp_file(tempdir.path().AppendASCII("test.json"));
+  ASSERT_EQ(static_cast<int>(strlen(kProperJSONWithCommas)),
+            WriteFile(temp_file, kProperJSONWithCommas,
+                      strlen(kProperJSONWithCommas)));
+
+  // Try to deserialize it through the serializer.
+  JSONFileValueDeserializer file_deserializer(temp_file);
+  // This must fail without the proper flag.
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_FALSE(value.get());
+  ASSERT_NE(0, error_code);
+  ASSERT_FALSE(error_message.empty());
+  // Now the flag is set and it must pass.
+  file_deserializer.set_allow_trailing_comma(true);
+  value.reset(file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+TEST(JSONValueDeserializerTest, AllowTrailingComma) {
+  scoped_ptr<Value> root;
+  scoped_ptr<Value> root_expected;
+  static const char kTestWithCommas[] = "{\"key\": [true,],}";
+  static const char kTestNoCommas[] = "{\"key\": [true]}";
+
+  JSONStringValueDeserializer deserializer(kTestWithCommas);
+  deserializer.set_allow_trailing_comma(true);
+  JSONStringValueDeserializer deserializer_expected(kTestNoCommas);
+  root.reset(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+  root_expected.reset(deserializer_expected.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root_expected.get());
+  ASSERT_TRUE(root->Equals(root_expected.get()));
+}
+
+TEST(JSONValueSerializerTest, Roundtrip) {
+  static const char kOriginalSerialization[] =
+    "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
+  JSONStringValueDeserializer deserializer(kOriginalSerialization);
+  scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+  DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
+
+  Value* null_value = NULL;
+  ASSERT_TRUE(root_dict->Get("null", &null_value));
+  ASSERT_TRUE(null_value);
+  ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL));
+
+  bool bool_value = false;
+  ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
+  ASSERT_TRUE(bool_value);
+
+  int int_value = 0;
+  ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
+  ASSERT_EQ(42, int_value);
+
+  double double_value = 0.0;
+  ASSERT_TRUE(root_dict->GetDouble("double", &double_value));
+  ASSERT_DOUBLE_EQ(3.14, double_value);
+
+  std::string test_serialization;
+  JSONStringValueSerializer mutable_serializer(&test_serialization);
+  ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
+  ASSERT_EQ(kOriginalSerialization, test_serialization);
+
+  mutable_serializer.set_pretty_print(true);
+  ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
+  // JSON output uses a different newline style on Windows than on other
+  // platforms.
+#if defined(OS_WIN)
+#define JSON_NEWLINE "\r\n"
+#else
+#define JSON_NEWLINE "\n"
+#endif
+  const std::string pretty_serialization =
+    "{" JSON_NEWLINE
+    "   \"bool\": true," JSON_NEWLINE
+    "   \"double\": 3.14," JSON_NEWLINE
+    "   \"int\": 42," JSON_NEWLINE
+    "   \"list\": [ 1, 2 ]," JSON_NEWLINE
+    "   \"null\": null" JSON_NEWLINE
+    "}" JSON_NEWLINE;
+#undef JSON_NEWLINE
+  ASSERT_EQ(pretty_serialization, test_serialization);
+}
+
+TEST(JSONValueSerializerTest, StringEscape) {
+  string16 all_chars;
+  for (int i = 1; i < 256; ++i) {
+    all_chars += static_cast<char16>(i);
+  }
+  // Generated in in Firefox using the following js (with an extra backslash for
+  // double quote):
+  // var s = '';
+  // for (var i = 1; i < 256; ++i) { s += String.fromCharCode(i); }
+  // uneval(s).replace(/\\/g, "\\\\");
+  std::string all_chars_expected =
+      "\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r"
+      "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017"
+      "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,"
+      "-./0123456789:;\\u003C=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcde"
+      "fghijklmnopqrstuvwxyz{|}~\x7F\xC2\x80\xC2\x81\xC2\x82\xC2\x83\xC2\x84"
+      "\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D"
+      "\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96"
+      "\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F"
+      "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7\xC2\xA8"
+      "\xC2\xA9\xC2\xAA\xC2\xAB\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF\xC2\xB0\xC2\xB1"
+      "\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xBA"
+      "\xC2\xBB\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF\xC3\x80\xC3\x81\xC3\x82\xC3\x83"
+      "\xC3\x84\xC3\x85\xC3\x86\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C"
+      "\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91\xC3\x92\xC3\x93\xC3\x94\xC3\x95"
+      "\xC3\x96\xC3\x97\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B\xC3\x9C\xC3\x9D\xC3\x9E"
+      "\xC3\x9F\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7"
+      "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB0"
+      "\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9"
+      "\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
+
+  std::string expected_output = "{\"all_chars\":\"" + all_chars_expected +
+                                 "\"}";
+  // Test JSONWriter interface
+  std::string output_js;
+  DictionaryValue valueRoot;
+  valueRoot.SetString("all_chars", all_chars);
+  JSONWriter::Write(&valueRoot, &output_js);
+  ASSERT_EQ(expected_output, output_js);
+
+  // Test JSONValueSerializer interface (uses JSONWriter).
+  JSONStringValueSerializer serializer(&output_js);
+  ASSERT_TRUE(serializer.Serialize(valueRoot));
+  ASSERT_EQ(expected_output, output_js);
+}
+
+TEST(JSONValueSerializerTest, UnicodeStrings) {
+  // unicode string json -> escaped ascii text
+  DictionaryValue root;
+  string16 test(WideToUTF16(L"\x7F51\x9875"));
+  root.SetString("web", test);
+
+  static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
+
+  std::string actual;
+  JSONStringValueSerializer serializer(&actual);
+  ASSERT_TRUE(serializer.Serialize(root));
+  ASSERT_EQ(kExpected, actual);
+
+  // escaped ascii text -> json
+  JSONStringValueDeserializer deserializer(kExpected);
+  scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(deserial_root.get());
+  DictionaryValue* dict_root =
+      static_cast<DictionaryValue*>(deserial_root.get());
+  string16 web_value;
+  ASSERT_TRUE(dict_root->GetString("web", &web_value));
+  ASSERT_EQ(test, web_value);
+}
+
+TEST(JSONValueSerializerTest, HexStrings) {
+  // hex string json -> escaped ascii text
+  DictionaryValue root;
+  string16 test(WideToUTF16(L"\x01\x02"));
+  root.SetString("test", test);
+
+  static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}";
+
+  std::string actual;
+  JSONStringValueSerializer serializer(&actual);
+  ASSERT_TRUE(serializer.Serialize(root));
+  ASSERT_EQ(kExpected, actual);
+
+  // escaped ascii text -> json
+  JSONStringValueDeserializer deserializer(kExpected);
+  scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(deserial_root.get());
+  DictionaryValue* dict_root =
+      static_cast<DictionaryValue*>(deserial_root.get());
+  string16 test_value;
+  ASSERT_TRUE(dict_root->GetString("test", &test_value));
+  ASSERT_EQ(test, test_value);
+
+  // Test converting escaped regular chars
+  static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
+  JSONStringValueDeserializer deserializer2(kEscapedChars);
+  deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
+  ASSERT_TRUE(deserial_root.get());
+  dict_root = static_cast<DictionaryValue*>(deserial_root.get());
+  ASSERT_TRUE(dict_root->GetString("test", &test_value));
+  ASSERT_EQ(ASCIIToUTF16("go"), test_value);
+}
+
+TEST(JSONValueSerializerTest, JSONReaderComments) {
+  ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]");
+  ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]");
+  ValidateJsonList("//header\n[ // 2, \n// 3, \n1 ]// footer");
+  ValidateJsonList("/*\n[ // 2, \n// 3, \n1 ]*/[1]");
+  ValidateJsonList("[ 1 /* one */ ] /* end */");
+  ValidateJsonList("[ 1 //// ,2\r\n ]");
+
+  scoped_ptr<Value> root;
+
+  // It's ok to have a comment in a string.
+  root.reset(JSONReader::Read("[\"// ok\\n /* foo */ \"]"));
+  ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
+  ListValue* list = static_cast<ListValue*>(root.get());
+  ASSERT_EQ(1U, list->GetSize());
+  Value* elt = NULL;
+  ASSERT_TRUE(list->Get(0, &elt));
+  std::string value;
+  ASSERT_TRUE(elt && elt->GetAsString(&value));
+  ASSERT_EQ("// ok\n /* foo */ ", value);
+
+  // You can't nest comments.
+  root.reset(JSONReader::Read("/* /* inner */ outer */ [ 1 ]"));
+  ASSERT_FALSE(root.get());
+
+  // Not a open comment token.
+  root.reset(JSONReader::Read("/ * * / [1]"));
+  ASSERT_FALSE(root.get());
+}
+
+class JSONFileValueSerializerTest : public testing::Test {
+ protected:
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(JSONFileValueSerializerTest, Roundtrip) {
+  base::FilePath original_file_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
+  original_file_path =
+      original_file_path.Append(FILE_PATH_LITERAL("serializer_test.json"));
+
+  ASSERT_TRUE(PathExists(original_file_path));
+
+  JSONFileValueDeserializer deserializer(original_file_path);
+  scoped_ptr<Value> root;
+  root.reset(deserializer.Deserialize(NULL, NULL));
+
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+  DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
+
+  Value* null_value = NULL;
+  ASSERT_TRUE(root_dict->Get("null", &null_value));
+  ASSERT_TRUE(null_value);
+  ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL));
+
+  bool bool_value = false;
+  ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
+  ASSERT_TRUE(bool_value);
+
+  int int_value = 0;
+  ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
+  ASSERT_EQ(42, int_value);
+
+  std::string string_value;
+  ASSERT_TRUE(root_dict->GetString("string", &string_value));
+  ASSERT_EQ("hello", string_value);
+
+  // Now try writing.
+  const base::FilePath written_file_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("test_output.js"));
+
+  ASSERT_FALSE(PathExists(written_file_path));
+  JSONFileValueSerializer serializer(written_file_path);
+  ASSERT_TRUE(serializer.Serialize(*root));
+  ASSERT_TRUE(PathExists(written_file_path));
+
+  // Now compare file contents.
+  EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path));
+  EXPECT_TRUE(base::DeleteFile(written_file_path, false));
+}
+
+TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
+  base::FilePath original_file_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
+  original_file_path = original_file_path.Append(
+      FILE_PATH_LITERAL("serializer_nested_test.json"));
+
+  ASSERT_TRUE(PathExists(original_file_path));
+
+  JSONFileValueDeserializer deserializer(original_file_path);
+  scoped_ptr<Value> root;
+  root.reset(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+
+  // Now try writing.
+  base::FilePath written_file_path = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("test_output.json"));
+
+  ASSERT_FALSE(PathExists(written_file_path));
+  JSONFileValueSerializer serializer(written_file_path);
+  ASSERT_TRUE(serializer.Serialize(*root));
+  ASSERT_TRUE(PathExists(written_file_path));
+
+  // Now compare file contents.
+  EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path));
+  EXPECT_TRUE(base::DeleteFile(written_file_path, false));
+}
+
+TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
+  base::FilePath source_file_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path));
+  source_file_path = source_file_path.Append(
+      FILE_PATH_LITERAL("serializer_test_nowhitespace.json"));
+  ASSERT_TRUE(PathExists(source_file_path));
+  JSONFileValueDeserializer deserializer(source_file_path);
+  scoped_ptr<Value> root;
+  root.reset(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
new file mode 100644
index 0000000..d14c92c
--- /dev/null
+++ b/base/json/json_writer.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_writer.h"
+
+#include <cmath>
+
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace base {
+
+#if defined(OS_WIN)
+const char kPrettyPrintLineEnding[] = "\r\n";
+#else
+const char kPrettyPrintLineEnding[] = "\n";
+#endif
+
+// static
+bool JSONWriter::Write(const Value* const node, std::string* json) {
+  return WriteWithOptions(node, 0, json);
+}
+
+// static
+bool 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);
+
+  JSONWriter writer(options, json);
+  bool result = writer.BuildJSONString(node, 0U);
+
+  if (options & OPTIONS_PRETTY_PRINT)
+    json->append(kPrettyPrintLineEnding);
+
+  return result;
+}
+
+JSONWriter::JSONWriter(int options, std::string* json)
+    : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0),
+      omit_double_type_preservation_(
+          (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0),
+      pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0),
+      json_string_(json) {
+  DCHECK(json);
+}
+
+bool JSONWriter::BuildJSONString(const Value* const node, size_t depth) {
+  switch (node->GetType()) {
+    case Value::TYPE_NULL: {
+      json_string_->append("null");
+      return true;
+    }
+
+    case Value::TYPE_BOOLEAN: {
+      bool value;
+      bool result = node->GetAsBoolean(&value);
+      DCHECK(result);
+      json_string_->append(value ? "true" : "false");
+      return result;
+    }
+
+    case Value::TYPE_INTEGER: {
+      int value;
+      bool result = node->GetAsInteger(&value);
+      DCHECK(result);
+      json_string_->append(IntToString(value));
+      return result;
+    }
+
+    case Value::TYPE_DOUBLE: {
+      double value;
+      bool result = node->GetAsDouble(&value);
+      DCHECK(result);
+      if (omit_double_type_preservation_ &&
+          value <= kint64max &&
+          value >= kint64min &&
+          std::floor(value) == value) {
+        json_string_->append(Int64ToString(static_cast<int64>(value)));
+        return result;
+      }
+      std::string real = DoubleToString(value);
+      // Ensure that the number has a .0 if there's no decimal or 'e'.  This
+      // makes sure that when we read the JSON back, it's interpreted as a
+      // real rather than an int.
+      if (real.find('.') == std::string::npos &&
+          real.find('e') == std::string::npos &&
+          real.find('E') == std::string::npos) {
+        real.append(".0");
+      }
+      // The JSON spec requires that non-integer values in the range (-1,1)
+      // have a zero before the decimal point - ".52" is not valid, "0.52" is.
+      if (real[0] == '.') {
+        real.insert(static_cast<size_t>(0), static_cast<size_t>(1), '0');
+      } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+        // "-.1" bad "-0.1" good
+        real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0');
+      }
+      json_string_->append(real);
+      return result;
+    }
+
+    case Value::TYPE_STRING: {
+      std::string value;
+      bool result = node->GetAsString(&value);
+      DCHECK(result);
+      EscapeJSONString(value, true, json_string_);
+      return result;
+    }
+
+    case Value::TYPE_LIST: {
+      json_string_->push_back('[');
+      if (pretty_print_)
+        json_string_->push_back(' ');
+
+      const ListValue* list = NULL;
+      bool first_value_has_been_output = false;
+      bool result = node->GetAsList(&list);
+      DCHECK(result);
+      for (ListValue::const_iterator it = list->begin(); it != list->end();
+           ++it) {
+        const Value* value = *it;
+        if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY)
+          continue;
+
+        if (first_value_has_been_output) {
+          json_string_->push_back(',');
+          if (pretty_print_)
+            json_string_->push_back(' ');
+        }
+
+        if (!BuildJSONString(value, depth))
+          result = false;
+
+        first_value_has_been_output = true;
+      }
+
+      if (pretty_print_)
+        json_string_->push_back(' ');
+      json_string_->push_back(']');
+      return result;
+    }
+
+    case Value::TYPE_DICTIONARY: {
+      json_string_->push_back('{');
+      if (pretty_print_)
+        json_string_->append(kPrettyPrintLineEnding);
+
+      const DictionaryValue* dict = NULL;
+      bool first_value_has_been_output = false;
+      bool result = node->GetAsDictionary(&dict);
+      DCHECK(result);
+      for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
+           itr.Advance()) {
+        if (omit_binary_values_ &&
+            itr.value().GetType() == Value::TYPE_BINARY) {
+          continue;
+        }
+
+        if (first_value_has_been_output) {
+          json_string_->push_back(',');
+          if (pretty_print_)
+            json_string_->append(kPrettyPrintLineEnding);
+        }
+
+        if (pretty_print_)
+          IndentLine(depth + 1U);
+
+        EscapeJSONString(itr.key(), true, json_string_);
+        json_string_->push_back(':');
+        if (pretty_print_)
+          json_string_->push_back(' ');
+
+        if (!BuildJSONString(&itr.value(), depth + 1U))
+          result = false;
+
+        first_value_has_been_output = true;
+      }
+
+      if (pretty_print_) {
+        json_string_->append(kPrettyPrintLineEnding);
+        IndentLine(depth);
+      }
+
+      json_string_->push_back('}');
+      return result;
+    }
+
+    case Value::TYPE_BINARY:
+      // Successful only if we're allowed to omit it.
+      DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
+      return omit_binary_values_;
+  }
+  NOTREACHED();
+  return false;
+}
+
+void JSONWriter::IndentLine(size_t depth) {
+  json_string_->append(depth * 3U, ' ');
+}
+
+}  // namespace base
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
new file mode 100644
index 0000000..9709c7e
--- /dev/null
+++ b/base/json/json_writer.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_JSON_JSON_WRITER_H_
+#define BASE_JSON_JSON_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class Value;
+
+class BASE_EXPORT JSONWriter {
+ public:
+  enum Options {
+    // This option instructs the writer that if a Binary value is encountered,
+    // the value (and key if within a dictionary) will be omitted from the
+    // output, and success will be returned. Otherwise, if a binary value is
+    // encountered, failure will be returned.
+    OPTIONS_OMIT_BINARY_VALUES = 1 << 0,
+
+    // This option instructs the writer to write doubles that have no fractional
+    // part as a normal integer (i.e., without using exponential notation
+    // or appending a '.0') as long as the value is within the range of a
+    // 64-bit int.
+    OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
+
+    // Return a slightly nicer formatted json string (pads with whitespace to
+    // help with readability).
+    OPTIONS_PRETTY_PRINT = 1 << 2,
+  };
+
+  // Given a root node, generates a JSON string and puts it into |json|.
+  // TODO(tc): Should we generate json if it would be invalid json (e.g.,
+  // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float
+  // values)? Return true on success and false on failure.
+  static bool Write(const Value* const node, std::string* json);
+
+  // Same as above but with |options| which is a bunch of JSONWriter::Options
+  // bitwise ORed together. Return true on success and false on failure.
+  static bool WriteWithOptions(const Value* const node, int options,
+                               std::string* json);
+
+ private:
+  JSONWriter(int options, std::string* json);
+
+  // Called recursively to build the JSON string. When completed,
+  // |json_string_| will contain the JSON.
+  bool BuildJSONString(const Value* const node, size_t depth);
+
+  // Adds space to json_string_ for the indent level.
+  void IndentLine(size_t depth);
+
+  bool omit_binary_values_;
+  bool omit_double_type_preservation_;
+  bool pretty_print_;
+
+  // Where we write JSON data as we generate it.
+  std::string* json_string_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_WRITER_H_
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
new file mode 100644
index 0000000..ec60b5e
--- /dev/null
+++ b/base/json/json_writer_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_writer.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONWriterTest, BasicTypes) {
+  std::string output_js;
+
+  // Test null.
+  Value* root = Value::CreateNullValue();
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("null", output_js);
+  delete root;
+
+  // Test empty dict.
+  root = new DictionaryValue;
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("{}", output_js);
+  delete root;
+
+  // Test empty list.
+  root = new ListValue;
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("[]", output_js);
+  delete root;
+
+  // Test integer values.
+  root = new FundamentalValue(42);
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("42", output_js);
+  delete root;
+
+  // Test boolean values.
+  root = new FundamentalValue(true);
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("true", output_js);
+  delete root;
+
+  // Test Real values should always have a decimal or an 'e'.
+  root = new FundamentalValue(1.0);
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_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);
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_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);
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("-0.8", output_js);
+  delete root;
+
+  // Test String values.
+  root = new StringValue("foo");
+  EXPECT_TRUE(JSONWriter::Write(root, &output_js));
+  EXPECT_EQ("\"foo\"", output_js);
+  delete root;
+}
+
+
+TEST(JSONWriterTest, NestedTypes) {
+  std::string output_js;
+
+  // Writer unittests like empty list/dict nesting,
+  // list list nesting, etc.
+  DictionaryValue root_dict;
+  scoped_ptr<ListValue> list(new ListValue());
+  scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue());
+  inner_dict->SetInteger("inner int", 10);
+  list->Append(inner_dict.Pass());
+  list->Append(make_scoped_ptr(new ListValue()));
+  list->AppendBoolean(true);
+  root_dict.Set("list", list.Pass());
+
+  // Test the pretty-printer.
+  EXPECT_TRUE(JSONWriter::Write(&root_dict, &output_js));
+  EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js);
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(&root_dict,
+                                           JSONWriter::OPTIONS_PRETTY_PRINT,
+                                           &output_js));
+
+  // The pretty-printer uses a different newline style on Windows than on
+  // other platforms.
+#if defined(OS_WIN)
+#define JSON_NEWLINE "\r\n"
+#else
+#define JSON_NEWLINE "\n"
+#endif
+  EXPECT_EQ("{" JSON_NEWLINE
+            "   \"list\": [ {" JSON_NEWLINE
+            "      \"inner int\": 10" JSON_NEWLINE
+            "   }, [  ], true ]" JSON_NEWLINE
+            "}" JSON_NEWLINE,
+            output_js);
+#undef JSON_NEWLINE
+}
+
+TEST(JSONWriterTest, KeysWithPeriods) {
+  std::string output_js;
+
+  DictionaryValue period_dict;
+  period_dict.SetIntegerWithoutPathExpansion("a.b", 3);
+  period_dict.SetIntegerWithoutPathExpansion("c", 2);
+  scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue());
+  period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1);
+  period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass());
+  EXPECT_TRUE(JSONWriter::Write(&period_dict, &output_js));
+  EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
+
+  DictionaryValue period_dict3;
+  period_dict3.SetInteger("a.b", 2);
+  period_dict3.SetIntegerWithoutPathExpansion("a.b", 1);
+  EXPECT_TRUE(JSONWriter::Write(&period_dict3, &output_js));
+  EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
+}
+
+TEST(JSONWriterTest, BinaryValues) {
+  std::string output_js;
+
+  // Binary values should return errors unless suppressed via the
+  // OPTIONS_OMIT_BINARY_VALUES flag.
+  Value* root = BinaryValue::CreateWithCopiedBuffer("asdf", 4);
+  EXPECT_FALSE(JSONWriter::Write(root, &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+  EXPECT_TRUE(output_js.empty());
+  delete root;
+
+  ListValue binary_list;
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(new FundamentalValue(5));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(new FundamentalValue(2));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  EXPECT_FALSE(JSONWriter::Write(&binary_list, &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      &binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+  EXPECT_EQ("[5,2]", output_js);
+
+  DictionaryValue binary_dict;
+  binary_dict.Set(
+      "a", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+  binary_dict.SetInteger("b", 5);
+  binary_dict.Set(
+      "c", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+  binary_dict.SetInteger("d", 2);
+  binary_dict.Set(
+      "e", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+  EXPECT_FALSE(JSONWriter::Write(&binary_dict, &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      &binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+  EXPECT_EQ("{\"b\":5,\"d\":2}", output_js);
+}
+
+TEST(JSONWriterTest, DoublesAsInts) {
+  std::string output_js;
+
+  // Test allowing a double with no fractional part to be written as an integer.
+  FundamentalValue double_value(1e10);
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      &double_value,
+      JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
+      &output_js));
+  EXPECT_EQ("10000000000", output_js);
+}
+
+}  // namespace base
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
new file mode 100644
index 0000000..a3b0735
--- /dev/null
+++ b/base/json/string_escape.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/string_escape.h"
+
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+// Format string for printing a \uXXXX escape sequence.
+const char kU16EscapeFormat[] = "\\u%04X";
+
+// The code point to output for an invalid input code unit.
+const uint32 kReplacementCodePoint = 0xFFFD;
+
+// Used below in EscapeSpecialCodePoint().
+COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c);
+
+// Try to escape the |code_point| if it is a known special character. If
+// successful, returns true and appends the escape sequence to |dest|. This
+// isn't required by the spec, but it's more readable by humans.
+bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
+  // WARNING: if you add a new case here, you need to update the reader as well.
+  // Note: \v is in the reader, but not here since the JSON spec doesn't
+  // allow it.
+  switch (code_point) {
+    case '\b':
+      dest->append("\\b");
+      break;
+    case '\f':
+      dest->append("\\f");
+      break;
+    case '\n':
+      dest->append("\\n");
+      break;
+    case '\r':
+      dest->append("\\r");
+      break;
+    case '\t':
+      dest->append("\\t");
+      break;
+    case '\\':
+      dest->append("\\\\");
+      break;
+    case '"':
+      dest->append("\\\"");
+      break;
+    // Escape < to prevent script execution; escaping > is not necessary and
+    // not doing so save a few bytes.
+    case '<':
+      dest->append("\\u003C");
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+template <typename S>
+bool EscapeJSONStringImpl(const S& str, bool put_in_quotes, std::string* dest) {
+  bool did_replacement = false;
+
+  if (put_in_quotes)
+    dest->push_back('"');
+
+  // Casting is necessary because ICU uses int32. Try and do so safely.
+  CHECK_LE(str.length(), static_cast<size_t>(kint32max));
+  const int32 length = static_cast<int32>(str.length());
+
+  for (int32 i = 0; i < length; ++i) {
+    uint32 code_point;
+    if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point)) {
+      code_point = kReplacementCodePoint;
+      did_replacement = true;
+    }
+
+    if (EscapeSpecialCodePoint(code_point, dest))
+      continue;
+
+    // Escape non-printing characters.
+    if (code_point < 32)
+      base::StringAppendF(dest, kU16EscapeFormat, code_point);
+    else
+      WriteUnicodeCharacter(code_point, dest);
+  }
+
+  if (put_in_quotes)
+    dest->push_back('"');
+
+  return !did_replacement;
+}
+
+}  // namespace
+
+bool EscapeJSONString(const StringPiece& str,
+                      bool put_in_quotes,
+                      std::string* dest) {
+  return EscapeJSONStringImpl(str, put_in_quotes, dest);
+}
+
+bool EscapeJSONString(const StringPiece16& str,
+                      bool put_in_quotes,
+                      std::string* dest) {
+  return EscapeJSONStringImpl(str, put_in_quotes, dest);
+}
+
+std::string GetQuotedJSONString(const StringPiece& str) {
+  std::string dest;
+  bool ok = EscapeJSONStringImpl(str, true, &dest);
+  DCHECK(ok);
+  return dest;
+}
+
+std::string GetQuotedJSONString(const StringPiece16& str) {
+  std::string dest;
+  bool ok = EscapeJSONStringImpl(str, true, &dest);
+  DCHECK(ok);
+  return dest;
+}
+
+std::string EscapeBytesAsInvalidJSONString(const StringPiece& str,
+                                           bool put_in_quotes) {
+  std::string dest;
+
+  if (put_in_quotes)
+    dest.push_back('"');
+
+  for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
+    ToUnsigned<StringPiece::value_type>::Unsigned c = *it;
+    if (EscapeSpecialCodePoint(c, &dest))
+      continue;
+
+    if (c < 32 || c > 126)
+      base::StringAppendF(&dest, kU16EscapeFormat, c);
+    else
+      dest.push_back(*it);
+  }
+
+  if (put_in_quotes)
+    dest.push_back('"');
+
+  return dest;
+}
+
+}  // namespace base
diff --git a/base/json/string_escape.h b/base/json/string_escape.h
new file mode 100644
index 0000000..b66b7e5
--- /dev/null
+++ b/base/json/string_escape.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines utility functions for escaping strings suitable for JSON.
+
+#ifndef BASE_JSON_STRING_ESCAPE_H_
+#define BASE_JSON_STRING_ESCAPE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Appends to |dest| an escaped version of |str|. Valid UTF-8 code units will
+// pass through from the input to the output. Invalid code units will be
+// replaced with the U+FFFD replacement character. This function returns true
+// if no replacement was necessary and false if there was a lossy replacement.
+// On return, |dest| will contain a valid UTF-8 JSON string.
+//
+// Non-printing control characters will be escaped as \uXXXX sequences for
+// readability.
+//
+// If |put_in_quotes| is true, then a leading and trailing double-quote mark
+// will be appended to |dest| as well.
+BASE_EXPORT bool EscapeJSONString(const StringPiece& str,
+                                  bool put_in_quotes,
+                                  std::string* dest);
+
+// Performs a similar function to the UTF-8 StringPiece version above,
+// converting UTF-16 code units to UTF-8 code units and escaping non-printing
+// control characters. On return, |dest| will contain a valid UTF-8 JSON string.
+BASE_EXPORT bool EscapeJSONString(const StringPiece16& str,
+                                  bool put_in_quotes,
+                                  std::string* dest);
+
+// Helper functions that wrap the above two functions but return the value
+// instead of appending. |put_in_quotes| is always true.
+BASE_EXPORT std::string GetQuotedJSONString(const StringPiece& str);
+BASE_EXPORT std::string GetQuotedJSONString(const StringPiece16& str);
+
+// Given an arbitrary byte string |str|, this will escape all non-ASCII bytes
+// as \uXXXX escape sequences. This function is *NOT* meant to be used with
+// Unicode strings and does not validate |str| as one.
+//
+// CAVEAT CALLER: The output of this function may not be valid JSON, since
+// JSON requires escape sequences to be valid UTF-16 code units. This output
+// will be mangled if passed to to the base::JSONReader, since the reader will
+// interpret it as UTF-16 and convert it to UTF-8.
+//
+// The output of this function takes the *appearance* of JSON but is not in
+// fact valid according to RFC 4627.
+BASE_EXPORT std::string EscapeBytesAsInvalidJSONString(const StringPiece& str,
+                                                       bool put_in_quotes);
+
+}  // namespace base
+
+#endif  // BASE_JSON_STRING_ESCAPE_H_
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
new file mode 100644
index 0000000..3eb4e8e
--- /dev/null
+++ b/base/json/string_escape_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/string_escape.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONStringEscapeTest, EscapeUTF8) {
+  const struct {
+    const char* to_escape;
+    const char* escaped;
+  } cases[] = {
+    {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+    {"a\b\f\n\r\t\v\1\\.\"z",
+        "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+    {"b\x0f\x7f\xf0\xff!",  // \xf0\xff is not a valid UTF-8 unit.
+        "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
+    {"c<>d", "c\\u003C>d"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    const char* in_ptr = cases[i].to_escape;
+    std::string in_str = in_ptr;
+
+    std::string out;
+    EscapeJSONString(in_ptr, false, &out);
+    EXPECT_EQ(std::string(cases[i].escaped), out);
+    EXPECT_TRUE(IsStringUTF8(out));
+
+    out.erase();
+    bool convert_ok = EscapeJSONString(in_str, false, &out);
+    EXPECT_EQ(std::string(cases[i].escaped), out);
+    EXPECT_TRUE(IsStringUTF8(out));
+
+    if (convert_ok) {
+      std::string fooout = GetQuotedJSONString(in_str);
+      EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout);
+      EXPECT_TRUE(IsStringUTF8(out));
+    }
+  }
+
+  std::string in = cases[0].to_escape;
+  std::string out;
+  EscapeJSONString(in, false, &out);
+  EXPECT_TRUE(IsStringUTF8(out));
+
+  // test quoting
+  std::string out_quoted;
+  EscapeJSONString(in, true, &out_quoted);
+  EXPECT_EQ(out.length() + 2, out_quoted.length());
+  EXPECT_EQ(out_quoted.find(out), 1U);
+  EXPECT_TRUE(IsStringUTF8(out_quoted));
+
+  // now try with a NULL in the string
+  std::string null_prepend = "test";
+  null_prepend.push_back(0);
+  in = null_prepend + in;
+  std::string expected = "test\\u0000";
+  expected += cases[0].escaped;
+  out.clear();
+  EscapeJSONString(in, false, &out);
+  EXPECT_EQ(expected, out);
+  EXPECT_TRUE(IsStringUTF8(out));
+}
+
+TEST(JSONStringEscapeTest, EscapeUTF16) {
+  const struct {
+    const wchar_t* to_escape;
+    const char* escaped;
+  } cases[] = {
+    {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
+    {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+    {L"a\b\f\n\r\t\v\1\\.\"z",
+        "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+    {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
+    {L"c<>d", "c\\u003C>d"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    string16 in = WideToUTF16(cases[i].to_escape);
+
+    std::string out;
+    EscapeJSONString(in, false, &out);
+    EXPECT_EQ(std::string(cases[i].escaped), out);
+    EXPECT_TRUE(IsStringUTF8(out));
+
+    out = GetQuotedJSONString(in);
+    EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out);
+    EXPECT_TRUE(IsStringUTF8(out));
+  }
+
+  string16 in = WideToUTF16(cases[0].to_escape);
+  std::string out;
+  EscapeJSONString(in, false, &out);
+  EXPECT_TRUE(IsStringUTF8(out));
+
+  // test quoting
+  std::string out_quoted;
+  EscapeJSONString(in, true, &out_quoted);
+  EXPECT_EQ(out.length() + 2, out_quoted.length());
+  EXPECT_EQ(out_quoted.find(out), 1U);
+  EXPECT_TRUE(IsStringUTF8(out));
+
+  // now try with a NULL in the string
+  string16 null_prepend = WideToUTF16(L"test");
+  null_prepend.push_back(0);
+  in = null_prepend + in;
+  std::string expected = "test\\u0000";
+  expected += cases[0].escaped;
+  out.clear();
+  EscapeJSONString(in, false, &out);
+  EXPECT_EQ(expected, out);
+  EXPECT_TRUE(IsStringUTF8(out));
+}
+
+TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) {
+  {
+    // {a, U+10300, !}, SMP.
+    string16 test;
+    test.push_back('a');
+    test.push_back(0xD800);
+    test.push_back(0xDF00);
+    test.push_back('!');
+    std::string actual;
+    EXPECT_TRUE(EscapeJSONString(test, false, &actual));
+    EXPECT_EQ("a\xF0\x90\x8C\x80!", actual);
+  }
+  {
+    // {U+20021, U+2002B}, SIP.
+    string16 test;
+    test.push_back(0xD840);
+    test.push_back(0xDC21);
+    test.push_back(0xD840);
+    test.push_back(0xDC2B);
+    std::string actual;
+    EXPECT_TRUE(EscapeJSONString(test, false, &actual));
+    EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual);
+  }
+  {
+    // {?, U+D800, @}, lone surrogate.
+    string16 test;
+    test.push_back('?');
+    test.push_back(0xD800);
+    test.push_back('@');
+    std::string actual;
+    EXPECT_FALSE(EscapeJSONString(test, false, &actual));
+    EXPECT_EQ("?\xEF\xBF\xBD@", actual);
+  }
+}
+
+TEST(JSONStringEscapeTest, EscapeBytes) {
+  const struct {
+    const char* to_escape;
+    const char* escaped;
+  } cases[] = {
+    {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
+    {"\xe5\xc4\x4f\x05\xb6\xfd\0", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    std::string in = std::string(cases[i].to_escape);
+    EXPECT_FALSE(IsStringUTF8(in));
+
+    EXPECT_EQ(std::string(cases[i].escaped),
+        EscapeBytesAsInvalidJSONString(in, false));
+    EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"",
+        EscapeBytesAsInvalidJSONString(in, true));
+  }
+
+  const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' };
+  std::string in(kEmbedNull, arraysize(kEmbedNull));
+  EXPECT_FALSE(IsStringUTF8(in));
+  EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"),
+            EscapeBytesAsInvalidJSONString(in, false));
+}
+
+}  // namespace base
diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc
new file mode 100644
index 0000000..594c1fe
--- /dev/null
+++ b/base/lazy_instance.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/lazy_instance.h"
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+// TODO(joth): This function could be shared with Singleton, in place of its
+// WaitForInstance() call.
+bool NeedsLazyInstance(subtle::AtomicWord* state) {
+  // Try to create the instance, if we're the first, will go from 0 to
+  // kLazyInstanceStateCreating, otherwise we've already been beaten here.
+  // The memory access has no memory ordering as state 0 and
+  // kLazyInstanceStateCreating have no associated data (memory barriers are
+  // all about ordering of memory accesses to *associated* data).
+  if (subtle::NoBarrier_CompareAndSwap(state, 0,
+                                       kLazyInstanceStateCreating) == 0)
+    // Caller must create instance
+    return true;
+
+  // It's either in the process of being created, or already created. Spin.
+  // The load has acquire memory ordering as a thread which sees
+  // state_ == STATE_CREATED needs to acquire visibility over
+  // the associated data (buf_). Pairing Release_Store is in
+  // CompleteLazyInstance().
+  while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
+    PlatformThread::YieldCurrentThread();
+  }
+  // Someone else created the instance.
+  return false;
+}
+
+void CompleteLazyInstance(subtle::AtomicWord* state,
+                          subtle::AtomicWord new_instance,
+                          void* lazy_instance,
+                          void (*dtor)(void*)) {
+  // Instance is created, go from CREATING to CREATED.
+  // Releases visibility over private_buf_ to readers. Pairing Acquire_Load's
+  // are in NeedsInstance() and Pointer().
+  subtle::Release_Store(state, new_instance);
+
+  // Make sure that the lazily instantiated object will get destroyed at exit.
+  if (dtor)
+    AtExitManager::RegisterCallback(dtor, lazy_instance);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
new file mode 100644
index 0000000..d52b543
--- /dev/null
+++ b/base/lazy_instance.h
@@ -0,0 +1,208 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The LazyInstance<Type, Traits> class manages a single instance of Type,
+// which will be lazily created on the first time it's accessed.  This class is
+// useful for places you would normally use a function-level static, but you
+// need to have guaranteed thread-safety.  The Type constructor will only ever
+// be called once, even if two threads are racing to create the object.  Get()
+// and Pointer() will always return the same, completely initialized instance.
+// When the instance is constructed it is registered with AtExitManager.  The
+// destructor will be called on program exit.
+//
+// LazyInstance is completely thread safe, assuming that you create it safely.
+// The class was designed to be POD initialized, so it shouldn't require a
+// static constructor.  It really only makes sense to declare a LazyInstance as
+// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
+//
+// LazyInstance is similar to Singleton, except it does not have the singleton
+// property.  You can have multiple LazyInstance's of the same type, and each
+// will manage a unique instance.  It also preallocates the space for Type, as
+// to avoid allocating the Type instance on the heap.  This may help with the
+// performance of creating the instance, and reducing heap fragmentation.  This
+// requires that Type be a complete type so we can determine the size.
+//
+// Example usage:
+//   static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER;
+//   void SomeMethod() {
+//     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()
+//
+//     MyClass* ptr = my_instance.Pointer();
+//     ptr->DoDoDo();  // MyClass::DoDoDo
+//   }
+
+#ifndef BASE_LAZY_INSTANCE_H_
+#define BASE_LAZY_INSTANCE_H_
+
+#include <new>  // For placement new.
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/debug/leak_annotations.h"
+#include "base/logging.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/thread_restrictions.h"
+
+// LazyInstance uses its own struct initializer-list style static
+// initialization, as base's LINKER_INITIALIZED requires a constructor and on
+// some compilers (notably gcc 4.4) this still ends up needing runtime
+// initialization.
+#define LAZY_INSTANCE_INITIALIZER {0}
+
+namespace base {
+
+template <typename Type>
+struct DefaultLazyInstanceTraits {
+  static const bool kRegisterOnExit = true;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+
+  static Type* New(void* instance) {
+    DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (ALIGNOF(Type) - 1), 0u)
+        << ": Bad boy, the buffer passed to placement new is not aligned!\n"
+        "This may break some stuff like SSE-based optimizations assuming the "
+        "<Type> objects are word aligned.";
+    // Use placement new to initialize our instance in our preallocated space.
+    // The parenthesis is very important here to force POD type initialization.
+    return new (instance) Type();
+  }
+  static void Delete(Type* instance) {
+    // Explicitly call the destructor.
+    instance->~Type();
+  }
+};
+
+// We pull out some of the functionality into non-templated functions, so we
+// can implement the more complicated pieces out of line in the .cc file.
+namespace internal {
+
+// Use LazyInstance<T>::Leaky for a less-verbose call-site typedef; e.g.:
+// base::LazyInstance<T>::Leaky my_leaky_lazy_instance;
+// instead of:
+// base::LazyInstance<T, base::internal::LeakyLazyInstanceTraits<T> >
+// my_leaky_lazy_instance;
+// (especially when T is MyLongTypeNameImplClientHolderFactory).
+// Only use this internal::-qualified verbose form to extend this traits class
+// (depending on its implementation details).
+template <typename Type>
+struct LeakyLazyInstanceTraits {
+  static const bool kRegisterOnExit = false;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+
+  static Type* New(void* instance) {
+    ANNOTATE_SCOPED_MEMORY_LEAK;
+    return DefaultLazyInstanceTraits<Type>::New(instance);
+  }
+  static void Delete(Type* instance) {
+  }
+};
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
+
+// Check if instance needs to be created. If so return true otherwise
+// if another thread has beat us, wait for instance to be created and
+// return false.
+BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
+
+// After creating an instance, call this to register the dtor to be called
+// at program exit and to update the atomic state to hold the |new_instance|
+BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
+                                      subtle::AtomicWord new_instance,
+                                      void* lazy_instance,
+                                      void (*dtor)(void*));
+
+}  // namespace internal
+
+template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >
+class LazyInstance {
+ public:
+  // Do not define a destructor, as doing so makes LazyInstance a
+  // non-POD-struct. We don't want that because then a static initializer will
+  // be created to register the (empty) destructor with atexit() under MSVC, for
+  // example. We handle destruction of the contained Type class explicitly via
+  // the OnExit member function, where needed.
+  // ~LazyInstance() {}
+
+  // Convenience typedef to avoid having to repeat Type for leaky lazy
+  // instances.
+  typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;
+
+  Type& Get() {
+    return *Pointer();
+  }
+
+  Type* Pointer() {
+#ifndef NDEBUG
+    // Avoid making TLS lookup on release builds.
+    if (!Traits::kAllowedToAccessOnNonjoinableThread)
+      ThreadRestrictions::AssertSingletonAllowed();
+#endif
+    // If any bit in the created mask is true, the instance has already been
+    // fully constructed.
+    static const subtle::AtomicWord kLazyInstanceCreatedMask =
+        ~internal::kLazyInstanceStateCreating;
+
+    // We will hopefully have fast access when the instance is already created.
+    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
+    // at most once, the load is taken out of NeedsInstance() as a fast-path.
+    // The load has acquire memory ordering as a thread which sees
+    // private_instance_ > creating needs to acquire visibility over
+    // the associated data (private_buf_). Pairing Release_Store is in
+    // CompleteLazyInstance().
+    subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
+    if (!(value & kLazyInstanceCreatedMask) &&
+        internal::NeedsLazyInstance(&private_instance_)) {
+      // Create the instance in the space provided by |private_buf_|.
+      value = reinterpret_cast<subtle::AtomicWord>(
+          Traits::New(private_buf_.void_data()));
+      internal::CompleteLazyInstance(&private_instance_, value, this,
+                                     Traits::kRegisterOnExit ? OnExit : NULL);
+    }
+    return instance();
+  }
+
+  bool operator==(Type* p) {
+    switch (subtle::NoBarrier_Load(&private_instance_)) {
+      case 0:
+        return p == NULL;
+      case internal::kLazyInstanceStateCreating:
+        return static_cast<void*>(p) == private_buf_.void_data();
+      default:
+        return p == instance();
+    }
+  }
+
+  // Effectively private: member data is only public to allow the linker to
+  // statically initialize it and to maintain a POD class. DO NOT USE FROM
+  // OUTSIDE THIS CLASS.
+
+  subtle::AtomicWord private_instance_;
+  // Preallocated space for the Type instance.
+  base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;
+
+ private:
+  Type* instance() {
+    return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
+  }
+
+  // Adapter function for use with AtExit.  This should be called single
+  // threaded, so don't synchronize across threads.
+  // Calling OnExit while the instance is in use by other threads is a mistake.
+  static void OnExit(void* lazy_instance) {
+    LazyInstance<Type, Traits>* me =
+        reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
+    Traits::Delete(me->instance());
+    subtle::NoBarrier_Store(&me->private_instance_, 0);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_LAZY_INSTANCE_H_
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
new file mode 100644
index 0000000..ec9ef26
--- /dev/null
+++ b/base/lazy_instance_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/atomic_sequence_num.h"
+#include "base/lazy_instance.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+base::StaticAtomicSequenceNumber constructed_seq_;
+base::StaticAtomicSequenceNumber destructed_seq_;
+
+class ConstructAndDestructLogger {
+ public:
+  ConstructAndDestructLogger() {
+    constructed_seq_.GetNext();
+  }
+  ~ConstructAndDestructLogger() {
+    destructed_seq_.GetNext();
+  }
+};
+
+class SlowConstructor {
+ public:
+  SlowConstructor() : some_int_(0) {
+    // Sleep for 1 second to try to cause a race.
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+    ++constructed;
+    some_int_ = 12;
+  }
+  int some_int() const { return some_int_; }
+
+  static int constructed;
+ private:
+  int some_int_;
+};
+
+int SlowConstructor::constructed = 0;
+
+class SlowDelegate : public base::DelegateSimpleThread::Delegate {
+ public:
+  explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
+      : lazy_(lazy) {}
+
+  void Run() override {
+    EXPECT_EQ(12, lazy_->Get().some_int());
+    EXPECT_EQ(12, lazy_->Pointer()->some_int());
+  }
+
+ private:
+  base::LazyInstance<SlowConstructor>* lazy_;
+};
+
+}  // namespace
+
+static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
+    LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, Basic) {
+  {
+    base::ShadowingAtExitManager shadow;
+
+    EXPECT_EQ(0, constructed_seq_.GetNext());
+    EXPECT_EQ(0, destructed_seq_.GetNext());
+
+    lazy_logger.Get();
+    EXPECT_EQ(2, constructed_seq_.GetNext());
+    EXPECT_EQ(1, destructed_seq_.GetNext());
+
+    lazy_logger.Pointer();
+    EXPECT_EQ(3, constructed_seq_.GetNext());
+    EXPECT_EQ(2, destructed_seq_.GetNext());
+  }
+  EXPECT_EQ(4, constructed_seq_.GetNext());
+  EXPECT_EQ(4, destructed_seq_.GetNext());
+}
+
+static base::LazyInstance<SlowConstructor> lazy_slow =
+    LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, ConstructorThreadSafety) {
+  {
+    base::ShadowingAtExitManager shadow;
+
+    SlowDelegate delegate(&lazy_slow);
+    EXPECT_EQ(0, SlowConstructor::constructed);
+
+    base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
+    pool.AddWork(&delegate, 20);
+    EXPECT_EQ(0, SlowConstructor::constructed);
+
+    pool.Start();
+    pool.JoinAll();
+    EXPECT_EQ(1, SlowConstructor::constructed);
+  }
+}
+
+namespace {
+
+// DeleteLogger is an object which sets a flag when it's destroyed.
+// It accepts a bool* and sets the bool to true when the dtor runs.
+class DeleteLogger {
+ public:
+  DeleteLogger() : deleted_(NULL) {}
+  ~DeleteLogger() { *deleted_ = true; }
+
+  void SetDeletedPtr(bool* deleted) {
+    deleted_ = deleted;
+  }
+
+ private:
+  bool* deleted_;
+};
+
+}  // anonymous namespace
+
+TEST(LazyInstanceTest, LeakyLazyInstance) {
+  // Check that using a plain LazyInstance causes the dtor to run
+  // when the AtExitManager finishes.
+  bool deleted1 = false;
+  {
+    base::ShadowingAtExitManager shadow;
+    static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
+    test.Get().SetDeletedPtr(&deleted1);
+  }
+  EXPECT_TRUE(deleted1);
+
+  // Check that using a *leaky* LazyInstance makes the dtor not run
+  // when the AtExitManager finishes.
+  bool deleted2 = false;
+  {
+    base::ShadowingAtExitManager shadow;
+    static base::LazyInstance<DeleteLogger>::Leaky
+        test = LAZY_INSTANCE_INITIALIZER;
+    test.Get().SetDeletedPtr(&deleted2);
+  }
+  EXPECT_FALSE(deleted2);
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() {}
+  ~AlignedData() {}
+  base::AlignedMemory<alignment, alignment> data_;
+};
+
+}  // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(LazyInstanceTest, Alignment) {
+  using base::LazyInstance;
+
+  // Create some static instances with increasing sizes and alignment
+  // requirements. By ordering this way, the linker will need to do some work to
+  // ensure proper alignment of the static data.
+  static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
+
+  EXPECT_ALIGNED(align4.Pointer(), 4);
+  EXPECT_ALIGNED(align32.Pointer(), 32);
+  EXPECT_ALIGNED(align4096.Pointer(), 4096);
+}
diff --git a/base/linux_util.cc b/base/linux_util.cc
new file mode 100644
index 0000000..d6cd504
--- /dev/null
+++ b/base/linux_util.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/linux_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/lock.h"
+
+namespace {
+
+// Not needed for OS_CHROMEOS.
+#if defined(OS_LINUX)
+enum LinuxDistroState {
+  STATE_DID_NOT_CHECK  = 0,
+  STATE_CHECK_STARTED  = 1,
+  STATE_CHECK_FINISHED = 2,
+};
+
+// Helper class for GetLinuxDistro().
+class LinuxDistroHelper {
+ public:
+  // Retrieves the Singleton.
+  static LinuxDistroHelper* GetInstance() {
+    return Singleton<LinuxDistroHelper>::get();
+  }
+
+  // The simple state machine goes from:
+  // STATE_DID_NOT_CHECK -> STATE_CHECK_STARTED -> STATE_CHECK_FINISHED.
+  LinuxDistroHelper() : state_(STATE_DID_NOT_CHECK) {}
+  ~LinuxDistroHelper() {}
+
+  // Retrieve the current state, if we're in STATE_DID_NOT_CHECK,
+  // we automatically move to STATE_CHECK_STARTED so nobody else will
+  // do the check.
+  LinuxDistroState State() {
+    base::AutoLock scoped_lock(lock_);
+    if (STATE_DID_NOT_CHECK == state_) {
+      state_ = STATE_CHECK_STARTED;
+      return STATE_DID_NOT_CHECK;
+    }
+    return state_;
+  }
+
+  // Indicate the check finished, move to STATE_CHECK_FINISHED.
+  void CheckFinished() {
+    base::AutoLock scoped_lock(lock_);
+    DCHECK_EQ(STATE_CHECK_STARTED, state_);
+    state_ = STATE_CHECK_FINISHED;
+  }
+
+ private:
+  base::Lock lock_;
+  LinuxDistroState state_;
+};
+#endif  // if defined(OS_LINUX)
+
+}  // namespace
+
+namespace base {
+
+// Account for the terminating null character.
+static const int kDistroSize = 128 + 1;
+
+// We use this static string to hold the Linux distro info. If we
+// crash, the crash handler code will send this in the crash dump.
+char g_linux_distro[kDistroSize] =
+#if defined(OS_CHROMEOS)
+    "CrOS";
+#elif defined(OS_ANDROID)
+    "Android";
+#else  // if defined(OS_LINUX)
+    "Unknown";
+#endif
+
+std::string GetLinuxDistro() {
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+  return g_linux_distro;
+#elif defined(OS_LINUX)
+  LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance();
+  LinuxDistroState state = distro_state_singleton->State();
+  if (STATE_CHECK_FINISHED == state)
+    return g_linux_distro;
+  if (STATE_CHECK_STARTED == state)
+    return "Unknown"; // Don't wait for other thread to finish.
+  DCHECK_EQ(state, STATE_DID_NOT_CHECK);
+  // We do this check only once per process. If it fails, there's
+  // little reason to believe it will work if we attempt to run
+  // lsb_release again.
+  std::vector<std::string> argv;
+  argv.push_back("lsb_release");
+  argv.push_back("-d");
+  std::string output;
+  base::GetAppOutput(CommandLine(argv), &output);
+  if (output.length() > 0) {
+    // lsb_release -d should return: Description:<tab>Distro Info
+    const char field[] = "Description:\t";
+    if (output.compare(0, strlen(field), field) == 0) {
+      SetLinuxDistro(output.substr(strlen(field)));
+    }
+  }
+  distro_state_singleton->CheckFinished();
+  return g_linux_distro;
+#else
+  NOTIMPLEMENTED();
+  return "Unknown";
+#endif
+}
+
+void SetLinuxDistro(const std::string& distro) {
+  std::string trimmed_distro;
+  base::TrimWhitespaceASCII(distro, base::TRIM_ALL, &trimmed_distro);
+  base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
+}
+
+pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
+                              bool* syscall_supported) {
+  char buf[256];
+  snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
+
+  if (syscall_supported != NULL)
+    *syscall_supported = false;
+
+  DIR* task = opendir(buf);
+  if (!task) {
+    DLOG(WARNING) << "Cannot open " << buf;
+    return -1;
+  }
+
+  std::vector<pid_t> tids;
+  struct dirent* dent;
+  while ((dent = readdir(task))) {
+    char* endptr;
+    const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10);
+    if (tid_ul == ULONG_MAX || *endptr)
+      continue;
+    tids.push_back(tid_ul);
+  }
+  closedir(task);
+
+  scoped_ptr<char[]> syscall_data(new char[expected_data.length()]);
+  for (std::vector<pid_t>::const_iterator
+       i = tids.begin(); i != tids.end(); ++i) {
+    const pid_t current_tid = *i;
+    snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid);
+    int fd = open(buf, O_RDONLY);
+    if (fd < 0)
+      continue;
+    if (syscall_supported != NULL)
+      *syscall_supported = true;
+    bool read_ret = ReadFromFD(fd, syscall_data.get(), expected_data.length());
+    close(fd);
+    if (!read_ret)
+      continue;
+
+    if (0 == strncmp(expected_data.c_str(), syscall_data.get(),
+                     expected_data.length())) {
+      return current_tid;
+    }
+  }
+  return -1;
+}
+
+}  // namespace base
diff --git a/base/linux_util.h b/base/linux_util.h
new file mode 100644
index 0000000..83523df
--- /dev/null
+++ b/base/linux_util.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LINUX_UTIL_H_
+#define BASE_LINUX_UTIL_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// This is declared here so the crash reporter can access the memory directly
+// in compromised context without going through the standard library.
+BASE_EXPORT extern char g_linux_distro[];
+
+// Get the Linux Distro if we can, or return "Unknown".
+BASE_EXPORT std::string GetLinuxDistro();
+
+// Set the Linux Distro string.
+BASE_EXPORT void SetLinuxDistro(const std::string& distro);
+
+// For a given process |pid|, look through all its threads and find the first
+// thread with /proc/[pid]/task/[thread_id]/syscall whose first N bytes matches
+// |expected_data|, where N is the length of |expected_data|.
+// Returns the thread id or -1 on error.  If |syscall_supported| is
+// set to false the kernel does not support syscall in procfs.
+BASE_EXPORT pid_t FindThreadIDWithSyscall(pid_t pid,
+                                          const std::string& expected_data,
+                                          bool* syscall_supported);
+
+}  // namespace base
+
+#endif  // BASE_LINUX_UTIL_H_
diff --git a/base/location.cc b/base/location.cc
new file mode 100644
index 0000000..1333e6e
--- /dev/null
+++ b/base/location.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#endif
+
+#include "base/location.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+
+namespace tracked_objects {
+
+Location::Location(const char* function_name,
+                   const char* file_name,
+                   int line_number,
+                   const void* program_counter)
+    : function_name_(function_name),
+      file_name_(file_name),
+      line_number_(line_number),
+      program_counter_(program_counter) {
+}
+
+Location::Location()
+    : function_name_("Unknown"),
+      file_name_("Unknown"),
+      line_number_(-1),
+      program_counter_(NULL) {
+}
+
+Location::Location(const Location& other)
+    : function_name_(other.function_name_),
+      file_name_(other.file_name_),
+      line_number_(other.line_number_),
+      program_counter_(other.program_counter_) {
+}
+
+std::string Location::ToString() const {
+  return std::string(function_name_) + "@" + file_name_ + ":" +
+      base::IntToString(line_number_);
+}
+
+void Location::Write(bool display_filename, bool display_function_name,
+                     std::string* output) const {
+  base::StringAppendF(output, "%s[%d] ",
+      display_filename ? file_name_ : "line",
+      line_number_);
+
+  if (display_function_name) {
+    WriteFunctionName(output);
+    output->push_back(' ');
+  }
+}
+
+void Location::WriteFunctionName(std::string* output) const {
+  // Translate "<" to "&lt;" for HTML safety.
+  // TODO(jar): Support ASCII or html for logging in ASCII.
+  for (const char *p = function_name_; *p; p++) {
+    switch (*p) {
+      case '<':
+        output->append("&lt;");
+        break;
+
+      case '>':
+        output->append("&gt;");
+        break;
+
+      default:
+        output->push_back(*p);
+        break;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+LocationSnapshot::LocationSnapshot() : line_number(-1) {
+}
+
+LocationSnapshot::LocationSnapshot(
+    const tracked_objects::Location& location)
+    : file_name(location.file_name()),
+      function_name(location.function_name()),
+      line_number(location.line_number()) {
+}
+
+LocationSnapshot::~LocationSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+#if defined(COMPILER_MSVC)
+__declspec(noinline)
+#endif
+BASE_EXPORT const void* GetProgramCounter() {
+#if defined(COMPILER_MSVC)
+  return _ReturnAddress();
+#elif defined(COMPILER_GCC) && !defined(OS_NACL)
+  return __builtin_extract_return_addr(__builtin_return_address(0));
+#else
+  return NULL;
+#endif
+}
+
+}  // namespace tracked_objects
diff --git a/base/location.h b/base/location.h
new file mode 100644
index 0000000..477dc02
--- /dev/null
+++ b/base/location.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOCATION_H_
+#define BASE_LOCATION_H_
+
+#include <cassert>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+
+namespace tracked_objects {
+
+// Location provides basic info where of an object was constructed, or was
+// significantly brought to life.
+class BASE_EXPORT Location {
+ public:
+  // Constructor should be called with a long-lived char*, such as __FILE__.
+  // It assumes the provided value will persist as a global constant, and it
+  // will not make a copy of it.
+  Location(const char* function_name,
+           const char* file_name,
+           int line_number,
+           const void* program_counter);
+
+  // Provide a default constructor for easy of debugging.
+  Location();
+
+  // Copy constructor.
+  Location(const Location& other);
+
+  // Comparator for hash map insertion.
+  // No need to use |function_name_| since the other two fields uniquely
+  // identify this location.
+  bool operator==(const Location& other) const {
+    return line_number_ == other.line_number_ &&
+           file_name_ == other.file_name_;
+  }
+
+  const char* function_name()   const { return function_name_; }
+  const char* file_name()       const { return file_name_; }
+  int line_number()             const { return line_number_; }
+  const void* program_counter() const { return program_counter_; }
+
+  std::string ToString() const;
+
+  // Hash operator for hash maps.
+  struct Hash {
+    size_t operator()(const Location& location) const {
+      // Compute the hash value using file name pointer and line number.
+      // No need to use |function_name_| since the other two fields uniquely
+      // identify this location.
+
+      // The file name will always be uniquely identified by its pointer since
+      // it comes from __FILE__, so no need to check the contents of the string.
+      // See the definition of FROM_HERE in location.h, and how it is used
+      // elsewhere.
+
+      // Due to inconsistent definitions of uint64_t and uintptr_t, casting the
+      // file name pointer to a uintptr_t causes a compiler error for some
+      // platforms. The solution is to explicitly cast it to a uint64_t.
+      return base::HashPair(reinterpret_cast<uint64_t>(location.file_name()),
+                            location.line_number());
+    }
+  };
+
+  // Translate the some of the state in this instance into a human readable
+  // string with HTML characters in the function names escaped, and append that
+  // string to |output|.  Inclusion of the file_name_ and function_name_ are
+  // optional, and controlled by the boolean arguments.
+  void Write(bool display_filename, bool display_function_name,
+             std::string* output) const;
+
+  // Write function_name_ in HTML with '<' and '>' properly encoded.
+  void WriteFunctionName(std::string* output) const;
+
+ private:
+  const char* function_name_;
+  const char* file_name_;
+  int line_number_;
+  const void* program_counter_;
+};
+
+// A "snapshotted" representation of the Location class that can safely be
+// passed across process boundaries.
+struct BASE_EXPORT LocationSnapshot {
+  // The default constructor is exposed to support the IPC serialization macros.
+  LocationSnapshot();
+  explicit LocationSnapshot(const tracked_objects::Location& location);
+  ~LocationSnapshot();
+
+  std::string file_name;
+  std::string function_name;
+  int line_number;
+};
+
+BASE_EXPORT const void* GetProgramCounter();
+
+// Define a macro to record the current source location.
+#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__)
+
+#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name)                        \
+    ::tracked_objects::Location(function_name,                                 \
+                                __FILE__,                                      \
+                                __LINE__,                                      \
+                                ::tracked_objects::GetProgramCounter())
+
+}  // namespace tracked_objects
+
+#endif  // BASE_LOCATION_H_
diff --git a/base/logging.cc b/base/logging.cc
new file mode 100644
index 0000000..c7a8881
--- /dev/null
+++ b/base/logging.cc
@@ -0,0 +1,810 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#include <windows.h>
+typedef HANDLE FileHandle;
+typedef HANDLE MutexHandle;
+// Windows warns on using write().  It prefers _write().
+#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
+// Windows doesn't define STDERR_FILENO.  Define it here.
+#define STDERR_FILENO 2
+#elif defined(OS_MACOSX)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h>
+#elif defined(OS_POSIX)
+#if defined(OS_NACL)
+#include <sys/time.h>  // timespec doesn't seem to be in <time.h>
+#else
+#include <sys/syscall.h>
+#endif
+#include <time.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#define MAX_PATH PATH_MAX
+typedef FILE* FileHandle;
+typedef pthread_mutex_t* MutexHandle;
+#endif
+
+#include <algorithm>
+#include <cstring>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+#include <string>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+#include "base/vlog.h"
+#if defined(OS_POSIX)
+#include "base/safe_strerror_posix.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include <android/log.h>
+#endif
+
+namespace logging {
+
+namespace {
+
+VlogInfo* g_vlog_info = NULL;
+VlogInfo* g_vlog_info_prev = NULL;
+
+const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
+  "INFO", "WARNING", "ERROR", "FATAL" };
+
+const char* log_severity_name(int severity) {
+  if (severity >= 0 && severity < LOG_NUM_SEVERITIES)
+    return log_severity_names[severity];
+  return "UNKNOWN";
+}
+
+int min_log_level = 0;
+
+LoggingDestination logging_destination = LOG_DEFAULT;
+
+// For LOG_ERROR and above, always print to stderr.
+const int kAlwaysPrintErrorLevel = LOG_ERROR;
+
+// Which log file to use? This is initialized by InitLogging or
+// will be lazily initialized to the default value when it is
+// first needed.
+#if defined(OS_WIN)
+typedef std::wstring PathString;
+#else
+typedef std::string PathString;
+#endif
+PathString* 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;
+// A log message handler that gets notified of every log message we process.
+LogMessageHandlerFunction log_message_handler = NULL;
+
+// Helper functions to wrap platform differences.
+
+int32 CurrentProcessId() {
+#if defined(OS_WIN)
+  return GetCurrentProcessId();
+#elif defined(OS_POSIX)
+  return getpid();
+#endif
+}
+
+uint64 TickCount() {
+#if defined(OS_WIN)
+  return GetTickCount();
+#elif defined(OS_MACOSX)
+  return mach_absolute_time();
+#elif defined(OS_NACL)
+  // NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h
+  // So we have to use clock() for now.
+  return clock();
+#elif defined(OS_POSIX)
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+
+  uint64 absolute_micro =
+    static_cast<int64>(ts.tv_sec) * 1000000 +
+    static_cast<int64>(ts.tv_nsec) / 1000;
+
+  return absolute_micro;
+#endif
+}
+
+void DeleteFilePath(const PathString& log_name) {
+#if defined(OS_WIN)
+  DeleteFile(log_name.c_str());
+#elif defined(OS_NACL)
+  // Do nothing; unlink() isn't supported on NaCl.
+#else
+  unlink(log_name.c_str());
+#endif
+}
+
+PathString GetDefaultLogFile() {
+#if defined(OS_WIN)
+  // On Windows we use the same path as the exe.
+  wchar_t module_name[MAX_PATH];
+  GetModuleFileName(NULL, module_name, MAX_PATH);
+
+  PathString log_name = module_name;
+  PathString::size_type last_backslash = log_name.rfind('\\', log_name.size());
+  if (last_backslash != PathString::npos)
+    log_name.erase(last_backslash + 1);
+  log_name += L"debug.log";
+  return log_name;
+#elif defined(OS_POSIX)
+  // On other platforms we just use the current directory.
+  return PathString("debug.log");
+#endif
+}
+
+// This class acts as a wrapper for locking the logging files.
+// LoggingLock::Init() should be called from the main thread before any logging
+// is done. Then whenever logging, be sure to have a local LoggingLock
+// instance on the stack. This will ensure that the lock is unlocked upon
+// exiting the frame.
+// LoggingLocks can not be nested.
+class LoggingLock {
+ public:
+  LoggingLock() {
+    LockLogging();
+  }
+
+  ~LoggingLock() {
+    UnlockLogging();
+  }
+
+  static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
+    if (initialized)
+      return;
+    lock_log_file = lock_log;
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      if (!log_mutex) {
+        std::wstring safe_name;
+        if (new_log_file)
+          safe_name = new_log_file;
+        else
+          safe_name = GetDefaultLogFile();
+        // \ is not a legal character in mutex names so we replace \ with /
+        std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
+        std::wstring t(L"Global\\");
+        t.append(safe_name);
+        log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
+
+        if (log_mutex == NULL) {
+#if DEBUG
+          // Keep the error code for debugging
+          int error = GetLastError();  // NOLINT
+          base::debug::BreakDebugger();
+#endif
+          // Return nicely without putting initialized to true.
+          return;
+        }
+      }
+#endif
+    } else {
+      log_lock = new base::internal::LockImpl();
+    }
+    initialized = true;
+  }
+
+ private:
+  static void LockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      ::WaitForSingleObject(log_mutex, INFINITE);
+      // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
+      // abort the process here. UI tests might be crashy sometimes,
+      // and aborting the test binary only makes the problem worse.
+      // We also don't use LOG macros because that might lead to an infinite
+      // loop. For more info see http://crbug.com/18028.
+#elif defined(OS_POSIX)
+      pthread_mutex_lock(&log_mutex);
+#endif
+    } else {
+      // use the lock
+      log_lock->Lock();
+    }
+  }
+
+  static void UnlockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      ReleaseMutex(log_mutex);
+#elif defined(OS_POSIX)
+      pthread_mutex_unlock(&log_mutex);
+#endif
+    } else {
+      log_lock->Unlock();
+    }
+  }
+
+  // The lock is used if log file locking is false. It helps us avoid problems
+  // with multiple threads writing to the log file at the same time.  Use
+  // LockImpl directly instead of using Lock, because Lock makes logging calls.
+  static base::internal::LockImpl* log_lock;
+
+  // When we don't use a lock, we are using a global mutex. We need to do this
+  // because LockFileEx is not thread safe.
+#if defined(OS_WIN)
+  static MutexHandle log_mutex;
+#elif defined(OS_POSIX)
+  static pthread_mutex_t log_mutex;
+#endif
+
+  static bool initialized;
+  static LogLockingState lock_log_file;
+};
+
+// static
+bool LoggingLock::initialized = false;
+// static
+base::internal::LockImpl* LoggingLock::log_lock = NULL;
+// static
+LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
+
+#if defined(OS_WIN)
+// static
+MutexHandle LoggingLock::log_mutex = NULL;
+#elif defined(OS_POSIX)
+pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+// Called by logging functions to ensure that debug_file is initialized
+// and can be used for writing. Returns false if the file could not be
+// initialized. debug_file will be NULL in this case.
+bool InitializeLogFileHandle() {
+  if (log_file)
+    return true;
+
+  if (!log_file_name) {
+    // Nobody has called InitLogging to specify a debug log file, so here we
+    // initialize the log file name to a default.
+    log_file_name = new PathString(GetDefaultLogFile());
+  }
+
+  if ((logging_destination & LOG_TO_FILE) != 0) {
+#if defined(OS_WIN)
+    log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
+                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                          OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
+      // try the current directory
+      log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+      if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
+        log_file = NULL;
+        return false;
+      }
+    }
+    SetFilePointer(log_file, 0, 0, FILE_END);
+#elif defined(OS_POSIX)
+    log_file = fopen(log_file_name->c_str(), "a");
+    if (log_file == NULL)
+      return false;
+#endif
+  }
+
+  return true;
+}
+
+void CloseFile(FileHandle log) {
+#if defined(OS_WIN)
+  CloseHandle(log);
+#else
+  fclose(log);
+#endif
+}
+
+void CloseLogFileUnlocked() {
+  if (!log_file)
+    return;
+
+  CloseFile(log_file);
+  log_file = NULL;
+}
+
+}  // namespace
+
+LoggingSettings::LoggingSettings()
+    : logging_dest(LOG_DEFAULT),
+      log_file(NULL),
+      lock_log(LOCK_LOG_FILE),
+      delete_old(APPEND_TO_OLD_LOG_FILE) {}
+
+bool BaseInitLoggingImpl(const LoggingSettings& settings) {
+#if defined(OS_NACL)
+  // Can log only to the system debug log.
+  CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
+#endif
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  // Don't bother initializing g_vlog_info unless we use one of the
+  // vlog switches.
+  if (command_line->HasSwitch(switches::kV) ||
+      command_line->HasSwitch(switches::kVModule)) {
+    // NOTE: If g_vlog_info has already been initialized, it might be in use
+    // by another thread. Don't delete the old VLogInfo, just create a second
+    // one. We keep track of both to avoid memory leak warnings.
+    CHECK(!g_vlog_info_prev);
+    g_vlog_info_prev = g_vlog_info;
+
+    g_vlog_info =
+        new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
+                     command_line->GetSwitchValueASCII(switches::kVModule),
+                     &min_log_level);
+  }
+
+  logging_destination = settings.logging_dest;
+
+  // ignore file options unless logging to file is set.
+  if ((logging_destination & LOG_TO_FILE) == 0)
+    return true;
+
+  LoggingLock::Init(settings.lock_log, settings.log_file);
+  LoggingLock logging_lock;
+
+  // Calling InitLogging twice or after some log call has already opened the
+  // default log file will re-initialize to the new options.
+  CloseLogFileUnlocked();
+
+  if (!log_file_name)
+    log_file_name = new PathString();
+  *log_file_name = settings.log_file;
+  if (settings.delete_old == DELETE_OLD_LOG_FILE)
+    DeleteFilePath(*log_file_name);
+
+  return InitializeLogFileHandle();
+}
+
+void SetMinLogLevel(int level) {
+  min_log_level = std::min(LOG_FATAL, level);
+}
+
+int GetMinLogLevel() {
+  return min_log_level;
+}
+
+int GetVlogVerbosity() {
+  return std::max(-1, LOG_INFO - GetMinLogLevel());
+}
+
+int GetVlogLevelHelper(const char* file, size_t N) {
+  DCHECK_GT(N, 0U);
+  // Note: g_vlog_info may change on a different thread during startup
+  // (but will always be valid or NULL).
+  VlogInfo* vlog_info = g_vlog_info;
+  return vlog_info ?
+      vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
+      GetVlogVerbosity();
+}
+
+void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                 bool enable_timestamp, bool enable_tickcount) {
+  log_process_id = enable_process_id;
+  log_thread_id = enable_thread_id;
+  log_timestamp = enable_timestamp;
+  log_tickcount = enable_tickcount;
+}
+
+void SetShowErrorDialogs(bool enable_dialogs) {
+  show_error_dialogs = enable_dialogs;
+}
+
+void SetLogAssertHandler(LogAssertHandlerFunction handler) {
+  log_assert_handler = handler;
+}
+
+void SetLogMessageHandler(LogMessageHandlerFunction handler) {
+  log_message_handler = handler;
+}
+
+LogMessageHandlerFunction GetLogMessageHandler() {
+  return log_message_handler;
+}
+
+// Explicit instantiations for commonly used comparisons.
+template std::string* MakeCheckOpString<int, int>(
+    const int&, const int&, const char* names);
+template std::string* MakeCheckOpString<unsigned long, unsigned long>(
+    const unsigned long&, const unsigned long&, const char* names);
+template std::string* MakeCheckOpString<unsigned long, unsigned int>(
+    const unsigned long&, const unsigned int&, const char* names);
+template std::string* MakeCheckOpString<unsigned int, unsigned long>(
+    const unsigned int&, const unsigned long&, const char* names);
+template std::string* MakeCheckOpString<std::string, std::string>(
+    const std::string&, const std::string&, const char* name);
+
+#if !defined(NDEBUG)
+// Displays a message box to the user with the error message in it.
+// Used for fatal messages, where we close the app simultaneously.
+// This is for developers only; we don't use this in circumstances
+// (like release builds) where users could see it, since users don't
+// understand these messages anyway.
+void DisplayDebugMessageInDialog(const std::string& str) {
+  if (str.empty())
+    return;
+
+  if (!show_error_dialogs)
+    return;
+
+#if defined(OS_WIN)
+  // For Windows programs, it's possible that the message loop is
+  // messed up on a fatal error, and creating a MessageBox will cause
+  // that message loop to be run. Instead, we try to spawn another
+  // process that displays its command line. We look for "Debug
+  // Message.exe" in the same directory as the application. If it
+  // exists, we use it, otherwise, we use a regular message box.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(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 = base::UTF8ToWide(str);
+  if (cmdline.empty())
+    return;
+
+  STARTUPINFO startup_info;
+  memset(&startup_info, 0, sizeof(startup_info));
+  startup_info.cb = sizeof(startup_info);
+
+  PROCESS_INFORMATION process_info;
+  if (CreateProcessW(prog_name, &cmdline[0], 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
+}
+#endif  // !defined(NDEBUG)
+
+#if defined(OS_WIN)
+LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
+}
+
+LogMessage::SaveLastError::~SaveLastError() {
+  ::SetLastError(last_error_);
+}
+#endif  // defined(OS_WIN)
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line, std::string* result)
+    : severity_(LOG_FATAL), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << *result;
+  delete result;
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+                       std::string* result)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << *result;
+  delete result;
+}
+
+LogMessage::~LogMessage() {
+#if !defined(NDEBUG) && !defined(OS_NACL) && !defined(__UCLIBC__)
+  if (severity_ == LOG_FATAL) {
+    // Include a stack trace on a fatal.
+    base::debug::StackTrace trace;
+    stream_ << std::endl;  // Newline to separate from log message.
+    trace.OutputToStream(&stream_);
+  }
+#endif
+  stream_ << std::endl;
+  std::string str_newline(stream_.str());
+
+  // Give any log message handler first dibs on the message.
+  if (log_message_handler &&
+      log_message_handler(severity_, file_, line_,
+                          message_start_, str_newline)) {
+    // The handler took care of it, no further processing.
+    return;
+  }
+
+  if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
+#if defined(OS_WIN)
+    OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_ANDROID)
+    android_LogPriority priority =
+        (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
+    switch (severity_) {
+      case LOG_INFO:
+        priority = ANDROID_LOG_INFO;
+        break;
+      case LOG_WARNING:
+        priority = ANDROID_LOG_WARN;
+        break;
+      case LOG_ERROR:
+        priority = ANDROID_LOG_ERROR;
+        break;
+      case LOG_FATAL:
+        priority = ANDROID_LOG_FATAL;
+        break;
+    }
+    __android_log_write(priority, "chromium", str_newline.c_str());
+#endif
+    ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
+    fflush(stderr);
+  } else if (severity_ >= kAlwaysPrintErrorLevel) {
+    // When we're only outputting to a log file, above a certain log level, we
+    // should still output to stderr so that we can better detect and diagnose
+    // problems with unit tests, especially on the buildbots.
+    ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
+    fflush(stderr);
+  }
+
+  // write to log file
+  if ((logging_destination & LOG_TO_FILE) != 0) {
+    // We can have multiple threads and/or processes, so try to prevent them
+    // from clobbering each other's writes.
+    // If the client app did not call InitLogging, and the lock has not
+    // been created do it now. We do this on demand, but if two threads try
+    // to do this at the same time, there will be a race condition to create
+    // the lock. This is why InitLogging should be called from the main
+    // thread at the beginning of execution.
+    LoggingLock::Init(LOCK_LOG_FILE, NULL);
+    LoggingLock logging_lock;
+    if (InitializeLogFileHandle()) {
+#if defined(OS_WIN)
+      SetFilePointer(log_file, 0, 0, SEEK_END);
+      DWORD num_written;
+      WriteFile(log_file,
+                static_cast<const void*>(str_newline.c_str()),
+                static_cast<DWORD>(str_newline.length()),
+                &num_written,
+                NULL);
+#else
+      ignore_result(fwrite(
+          str_newline.data(), str_newline.size(), 1, log_file));
+      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);
+
+    if (log_assert_handler) {
+      // Make a copy of the string for the handler out of paranoia.
+      log_assert_handler(std::string(stream_.str()));
+    } else {
+      // Don't use the string with the newline, get a fresh version to send to
+      // the debug message process. We also don't display assertions to the
+      // user in release mode. The enduser can't do anything with this
+      // information, and displaying message boxes when the application is
+      // hosed can cause additional problems.
+#ifndef NDEBUG
+      DisplayDebugMessageInDialog(stream_.str());
+#endif
+      // Crash the process to generate a dump.
+      base::debug::BreakDebugger();
+    }
+  }
+}
+
+// writes the common header info to the stream
+void LogMessage::Init(const char* file, int line) {
+  base::StringPiece filename(file);
+  size_t last_slash_pos = filename.find_last_of("\\/");
+  if (last_slash_pos != base::StringPiece::npos)
+    filename.remove_prefix(last_slash_pos + 1);
+
+  // TODO(darin): It might be nice if the columns were fixed width.
+
+  stream_ <<  '[';
+  if (log_process_id)
+    stream_ << CurrentProcessId() << ':';
+  if (log_thread_id)
+    stream_ << base::PlatformThread::CurrentId() << ':';
+  if (log_timestamp) {
+    time_t t = time(NULL);
+    struct tm local_time = {0};
+#ifdef _MSC_VER
+    localtime_s(&local_time, &t);
+#else
+    localtime_r(&t, &local_time);
+#endif
+    struct tm* tm_time = &local_time;
+    stream_ << std::setfill('0')
+            << std::setw(2) << 1 + tm_time->tm_mon
+            << std::setw(2) << tm_time->tm_mday
+            << '/'
+            << std::setw(2) << tm_time->tm_hour
+            << std::setw(2) << tm_time->tm_min
+            << std::setw(2) << tm_time->tm_sec
+            << ':';
+  }
+  if (log_tickcount)
+    stream_ << TickCount() << ':';
+  if (severity_ >= 0)
+    stream_ << log_severity_name(severity_);
+  else
+    stream_ << "VERBOSE" << -severity_;
+
+  stream_ << ":" << filename << "(" << line << ")] ";
+
+  message_start_ = stream_.str().length();
+}
+
+#if defined(OS_WIN)
+// This has already been defined in the header, but defining it again as DWORD
+// ensures that the type used in the header is equivalent to DWORD. If not,
+// the redefinition is a compile error.
+typedef DWORD SystemErrorCode;
+#endif
+
+SystemErrorCode GetLastSystemErrorCode() {
+#if defined(OS_WIN)
+  return ::GetLastError();
+#elif defined(OS_POSIX)
+  return errno;
+#else
+#error Not implemented
+#endif
+}
+
+#if defined(OS_WIN)
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+  const int kErrorMessageBufferSize = 256;
+  char msgbuf[kErrorMessageBufferSize];
+  DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+  DWORD len = FormatMessageA(flags, NULL, error_code, 0, msgbuf,
+                             arraysize(msgbuf), NULL);
+  if (len) {
+    // Messages returned by system end with line breaks.
+    return base::CollapseWhitespaceASCII(msgbuf, true) +
+        base::StringPrintf(" (0x%X)", error_code);
+  }
+  return base::StringPrintf("Error (0x%X) while retrieving error. (0x%X)",
+                            GetLastError(), error_code);
+}
+#elif defined(OS_POSIX)
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+  return safe_strerror(error_code);
+}
+#else
+#error Not implemented
+#endif
+
+
+#if defined(OS_WIN)
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+                                           int line,
+                                           LogSeverity severity,
+                                           SystemErrorCode err)
+    : err_(err),
+      log_message_(file, line, severity) {
+}
+
+Win32ErrorLogMessage::~Win32ErrorLogMessage() {
+  stream() << ": " << SystemErrorCodeToString(err_);
+  // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
+  // field) and use Alias in hopes that it makes it into crash dumps.
+  DWORD last_error = err_;
+  base::debug::Alias(&last_error);
+}
+#elif defined(OS_POSIX)
+ErrnoLogMessage::ErrnoLogMessage(const char* file,
+                                 int line,
+                                 LogSeverity severity,
+                                 SystemErrorCode err)
+    : err_(err),
+      log_message_(file, line, severity) {
+}
+
+ErrnoLogMessage::~ErrnoLogMessage() {
+  stream() << ": " << SystemErrorCodeToString(err_);
+}
+#endif  // OS_WIN
+
+void CloseLogFile() {
+  LoggingLock logging_lock;
+  CloseLogFileUnlocked();
+}
+
+void RawLog(int level, const char* message) {
+  if (level >= min_log_level) {
+    size_t bytes_written = 0;
+    const size_t message_len = strlen(message);
+    int rv;
+    while (bytes_written < message_len) {
+      rv = HANDLE_EINTR(
+          write(STDERR_FILENO, message + bytes_written,
+                message_len - bytes_written));
+      if (rv < 0) {
+        // Give up, nothing we can do now.
+        break;
+      }
+      bytes_written += rv;
+    }
+
+    if (message_len > 0 && message[message_len - 1] != '\n') {
+      do {
+        rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
+        if (rv < 0) {
+          // Give up, nothing we can do now.
+          break;
+        }
+      } while (rv != 1);
+    }
+  }
+
+  if (level == LOG_FATAL)
+    base::debug::BreakDebugger();
+}
+
+// This was defined at the beginning of this file.
+#undef write
+
+#if defined(OS_WIN)
+std::wstring GetLogFileFullPath() {
+  if (log_file_name)
+    return *log_file_name;
+  return std::wstring();
+}
+#endif
+
+}  // namespace logging
+
+std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
+  return out << base::WideToUTF8(wstr);
+}
diff --git a/base/logging.h b/base/logging.h
new file mode 100644
index 0000000..cc0a5aa
--- /dev/null
+++ b/base/logging.h
@@ -0,0 +1,935 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_H_
+#define BASE_LOGGING_H_
+
+#include <cassert>
+#include <string>
+#include <cstring>
+#include <sstream>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "build/build_config.h"
+
+//
+// Optional message capabilities
+// -----------------------------
+// Assertion failed messages and fatal errors are displayed in a dialog box
+// before the application exits. However, running this UI creates a message
+// loop, which causes application messages to be processed and potentially
+// dispatched to existing application windows. Since the application is in a
+// bad state when this assertion dialog is displayed, these messages may not
+// get processed and hang the dialog, or the application might go crazy.
+//
+// Therefore, it can be beneficial to display the error dialog in a separate
+// process from the main application. When the logging system needs to display
+// a fatal error dialog box, it will look for a program called
+// "DebugMessage.exe" in the same directory as the application executable. It
+// will run this application with the message as the command line, and will
+// not include the name of the application as is traditional for easier
+// parsing.
+//
+// The code for DebugMessage.exe is only one line. In WinMain, do:
+//   MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
+//
+// If DebugMessage.exe is not found, the logging code will use a normal
+// MessageBox, potentially causing the problems discussed above.
+
+
+// Instructions
+// ------------
+//
+// Make a bunch of macros for logging.  The way to log things is to stream
+// things to LOG(<a particular severity level>).  E.g.,
+//
+//   LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can also do conditional logging:
+//
+//   LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// The CHECK(condition) macro is active in both debug and release builds and
+// effectively performs a LOG(FATAL) which terminates the process and
+// generates a crashdump unless a debugger is attached.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+//   DLOG(INFO) << "Found cookies";
+//
+//   DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.  LOG_IF and development flags also work well together
+// because the code can be compiled away sometimes.
+//
+// We also have
+//
+//   LOG_ASSERT(assertion);
+//   DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros.  They look like
+//
+//   VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+//   VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module.  For instance,
+//    --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
+// will cause:
+//   a. VLOG(2) and lower messages to be printed from profile.{h,cc}
+//   b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
+//   c. VLOG(3) and lower messages to be printed from files prefixed with
+//      "browser"
+//   d. VLOG(4) and lower messages to be printed from files under a
+//     "chromeos" directory.
+//   e. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character)
+// wildcards.  Any pattern containing a forward or backward slash will
+// be tested against the whole pathname and not just the module.
+// E.g., "*/foo/bar/*=2" would change the logging level for all code
+// in source files under a "foo/bar" directory.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+//   if (VLOG_IS_ON(2)) {
+//     // do some logging preparation and logging
+//     // that can't be accomplished with just VLOG(2) << ...;
+//   }
+//
+// There is also a VLOG_IF "verbose level" condition macro for sample
+// cases, when some extra computation and preparation for logs is not
+// needed.
+//
+//   VLOG_IF(1, (size > 1024))
+//      << "I'm printed when size is more than 1024 and when you run the "
+//         "program with --v=1 or more";
+//
+// We also override the standard 'assert' to use 'DLOG_ASSERT'.
+//
+// Lastly, there is:
+//
+//   PLOG(ERROR) << "Couldn't do foo";
+//   DPLOG(ERROR) << "Couldn't do foo";
+//   PLOG_IF(ERROR, cond) << "Couldn't do foo";
+//   DPLOG_IF(ERROR, cond) << "Couldn't do foo";
+//   PCHECK(condition) << "Couldn't do foo";
+//   DPCHECK(condition) << "Couldn't do foo";
+//
+// which append the last system error to the message in string form (taken from
+// GetLastError() on Windows and errno on POSIX).
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// There is the special severity of DFATAL, which logs FATAL in debug mode,
+// ERROR in normal mode.
+
+namespace logging {
+
+// TODO(avi): do we want to do a unification of character types here?
+#if defined(OS_WIN)
+typedef wchar_t PathChar;
+#else
+typedef char PathChar;
+#endif
+
+// Where to record logging output? A flat file and/or system debug log
+// via OutputDebugString.
+enum LoggingDestination {
+  LOG_NONE                = 0,
+  LOG_TO_FILE             = 1 << 0,
+  LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
+
+  LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG,
+
+  // On Windows, use a file next to the exe; on POSIX platforms, where
+  // it may not even be possible to locate the executable on disk, use
+  // stderr.
+#if defined(OS_WIN)
+  LOG_DEFAULT = LOG_TO_FILE,
+#elif defined(OS_POSIX)
+  LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
+#endif
+};
+
+// Indicates that the log file should be locked when being written to.
+// Unless there is only one single-threaded process that is logging to
+// the log file, the file should be locked during writes to make each
+// log output atomic. Other writers will block.
+//
+// All processes writing to the log file must have their locking set for it to
+// work properly. Defaults to LOCK_LOG_FILE.
+enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
+
+// On startup, should we delete or append to an existing log file (if any)?
+// Defaults to APPEND_TO_OLD_LOG_FILE.
+enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+
+struct BASE_EXPORT LoggingSettings {
+  // The defaults values are:
+  //
+  //  logging_dest: LOG_DEFAULT
+  //  log_file:     NULL
+  //  lock_log:     LOCK_LOG_FILE
+  //  delete_old:   APPEND_TO_OLD_LOG_FILE
+  LoggingSettings();
+
+  LoggingDestination logging_dest;
+
+  // The three settings below have an effect only when LOG_TO_FILE is
+  // set in |logging_dest|.
+  const PathChar* log_file;
+  LogLockingState lock_log;
+  OldFileDeletionState delete_old;
+};
+
+// Define different names for the BaseInitLoggingImpl() function depending on
+// whether NDEBUG is defined or not so that we'll fail to link if someone tries
+// to compile logging.cc with NDEBUG but includes logging.h without defining it,
+// or vice versa.
+#if NDEBUG
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG
+#else
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG
+#endif
+
+// Implementation of the InitLogging() method declared below.  We use a
+// more-specific name so we can #define it above without affecting other code
+// that has named stuff "InitLogging".
+BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings);
+
+// Sets the log file name and other global logging state. Calling this function
+// is recommended, and is normally done at the beginning of application init.
+// If you don't call it, all the flags will be initialized to their default
+// values, and there is a race condition that may leak a critical section
+// object if two threads try to do the first log at the same time.
+// See the definition of the enums above for descriptions and default values.
+//
+// The default log file is initialized to "debug.log" in the application
+// directory. You probably don't want this, especially since the program
+// directory may not be writable on an enduser's system.
+//
+// This function may be called a second time to re-direct logging (e.g after
+// loging in to a user partition), however it should never be called more than
+// twice.
+inline bool InitLogging(const LoggingSettings& settings) {
+  return BaseInitLoggingImpl(settings);
+}
+
+// Sets the log level. Anything at or above this level will be written to the
+// log file/displayed to the user (if applicable). Anything below this level
+// will be silently ignored. The log level defaults to 0 (everything is logged
+// up to level INFO) if this function is not called.
+// Note that log messages for VLOG(x) are logged at level -x, so setting
+// the min log level to negative values enables verbose logging.
+BASE_EXPORT void SetMinLogLevel(int level);
+
+// Gets the current log level.
+BASE_EXPORT int GetMinLogLevel();
+
+// Gets the VLOG default verbosity level.
+BASE_EXPORT int GetVlogVerbosity();
+
+// Gets the current vlog level for the given file (usually taken from
+// __FILE__).
+
+// Note that |N| is the size *with* the null terminator.
+BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N);
+
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+  return GetVlogLevelHelper(file, N);
+}
+
+// Sets the common items you want to be prepended to each log message.
+// process and thread IDs default to off, the timestamp defaults to on.
+// If this function is not called, logging defaults to writing the timestamp
+// only.
+BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                             bool enable_timestamp, bool enable_tickcount);
+
+// Sets whether or not you'd like to see fatal debug messages popped up in
+// a dialog box or not.
+// Dialogs are not shown by default.
+BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
+
+// Sets the Log Assert Handler that will be used to notify of check failures.
+// The default handler shows a dialog box and then terminate the process,
+// however clients can use this function to override with their own handling
+// (e.g. a silent one for Unit Tests)
+typedef void (*LogAssertHandlerFunction)(const std::string& str);
+BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler);
+
+// Sets the Log Message Handler that gets passed every log message before
+// it's sent to other log destinations (if any).
+// Returns true to signal that it handled the message and the message
+// should not be sent to other log destinations.
+typedef bool (*LogMessageHandlerFunction)(int severity,
+    const char* file, int line, size_t message_start, const std::string& str);
+BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
+BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
+
+typedef int LogSeverity;
+const LogSeverity LOG_VERBOSE = -1;  // This is level 1 verbosity
+// Note: the log severities are used to index into the array of names,
+// see log_severity_names.
+const LogSeverity LOG_INFO = 0;
+const LogSeverity LOG_WARNING = 1;
+const LogSeverity LOG_ERROR = 2;
+const LogSeverity LOG_FATAL = 3;
+const LogSeverity LOG_NUM_SEVERITIES = 4;
+
+// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+const LogSeverity LOG_DFATAL = LOG_ERROR;
+#else
+const LogSeverity LOG_DFATAL = LOG_FATAL;
+#endif
+
+// A few definitions of macros that don't generate much code. These are used
+// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
+// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__)
+
+#define COMPACT_GOOGLE_LOG_INFO \
+  COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
+#define COMPACT_GOOGLE_LOG_WARNING \
+  COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
+#define COMPACT_GOOGLE_LOG_ERROR \
+  COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
+#define COMPACT_GOOGLE_LOG_FATAL \
+  COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DFATAL \
+  COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
+
+#if defined(OS_WIN)
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
+// the Windows SDK does for consistency.
+#define ERROR 0
+#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity LOG_0 = LOG_ERROR;
+#endif
+
+// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
+// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
+// always fire if they fail.
+#define LOG_IS_ON(severity) \
+  ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
+
+// We can't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it requires GCC extensions.  This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+  ((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
+
+// Helper macro which avoids evaluating the arguments to a stream if
+// the condition doesn't hold. Condition is evaluated once and only once.
+#define LAZY_STREAM(stream, condition)                                  \
+  !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO.  There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+
+#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_IF(severity, condition) \
+  LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+#define SYSLOG(severity) LOG(severity)
+#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+  logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+  LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+  LAZY_STREAM(VLOG_STREAM(verbose_level), \
+      VLOG_IS_ON(verbose_level) && (condition))
+
+#if defined (OS_WIN)
+#define VPLOG_STREAM(verbose_level) \
+  logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+    ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX)
+#define VPLOG_STREAM(verbose_level) \
+  logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+    ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define VPLOG(verbose_level) \
+  LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VPLOG_IF(verbose_level, condition) \
+  LAZY_STREAM(VPLOG_STREAM(verbose_level), \
+    VLOG_IS_ON(verbose_level) && (condition))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
+
+#define LOG_ASSERT(condition)  \
+  LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#define SYSLOG_ASSERT(condition) \
+  SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+
+#if defined(OS_WIN)
+#define PLOG_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX)
+#define PLOG_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define PLOG(severity)                                          \
+  LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
+
+#define PLOG_IF(severity, condition) \
+  LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+// The actual stream used isn't important.
+#define EAT_STREAM_PARAMETERS                                           \
+  true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+
+// CHECK dies with a fatal error if condition is not true.  It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+//
+// We make sure CHECK et al. always evaluates their arguments, as
+// doing CHECK(FunctionWithSideEffect()) is a common idiom.
+
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
+
+// Make all CHECK functions discard their log strings to reduce code
+// bloat for official release builds.
+
+// TODO(akalin): This would be more valuable if there were some way to
+// remove BreakDebugger() from the backtrace, perhaps by turning it
+// into a macro (like __debugbreak() on Windows).
+#define CHECK(condition)                                                \
+  !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS
+
+#define PCHECK(condition) CHECK(condition)
+
+#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
+
+#else
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+// Use __analysis_assume to tell the VC++ static analysis engine that
+// assert conditions are true, to suppress warnings.  The LAZY_STREAM
+// parameter doesn't reference 'condition' in /analyze builds because
+// this evaluation confuses /analyze. The !! before condition is because
+// __analysis_assume gets confused on some conditions:
+// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
+
+#define CHECK(condition)                \
+  __analysis_assume(!!(condition)),     \
+  LAZY_STREAM(LOG_STREAM(FATAL), false) \
+  << "Check failed: " #condition ". "
+
+#define PCHECK(condition)                \
+  __analysis_assume(!!(condition)),      \
+  LAZY_STREAM(PLOG_STREAM(FATAL), false) \
+  << "Check failed: " #condition ". "
+
+#else  // _PREFAST_
+
+#define CHECK(condition)                       \
+  LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
+  << "Check failed: " #condition ". "
+
+#define PCHECK(condition)                       \
+  LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
+  << "Check failed: " #condition ". "
+
+#endif  // _PREFAST_
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+//
+// TODO(akalin): Rewrite this so that constructs like if (...)
+// CHECK_EQ(...) else { ... } work properly.
+#define CHECK_OP(name, op, val1, val2)                          \
+  if (std::string* _result =                                    \
+      logging::Check##name##Impl((val1), (val2),                \
+                                 #val1 " " #op " " #val2))      \
+    logging::LogMessage(__FILE__, __LINE__, _result).stream()
+
+#endif
+
+// Build the error message string.  This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline.  Caller
+// takes ownership of the returned string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+  std::ostringstream ss;
+  ss << names << " (" << v1 << " vs. " << v2 << ")";
+  std::string* msg = new std::string(ss.str());
+  return msg;
+}
+
+// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
+// in logging.cc.
+extern template BASE_EXPORT std::string* MakeCheckOpString<int, int>(
+    const int&, const int&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned long, unsigned long>(
+    const unsigned long&, const unsigned long&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned long, unsigned int>(
+    const unsigned long&, const unsigned int&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned int, unsigned long>(
+    const unsigned int&, const unsigned long&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<std::string, std::string>(
+    const std::string&, const std::string&, const char* name);
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+  template <class t1, class t2> \
+  inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+                                        const char* names) { \
+    if (v1 op v2) return NULL; \
+    else return MakeCheckOpString(v1, v2, names); \
+  } \
+  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+    if (v1 op v2) return NULL; \
+    else return MakeCheckOpString(v1, v2, names); \
+  }
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, < )
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
+#define CHECK_IMPLIES(val1, val2) CHECK(!(val1) || (val2))
+
+#if defined(NDEBUG)
+#define ENABLE_DLOG 0
+#else
+#define ENABLE_DLOG 1
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() 0
+#else
+#define DCHECK_IS_ON() 1
+#endif
+
+// Definitions for DLOG et al.
+
+#if ENABLE_DLOG
+
+#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
+#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
+#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
+
+#else  // ENABLE_DLOG
+
+// If ENABLE_DLOG is off, we want to avoid emitting any references to
+// |condition| (which may reference a variable defined only if NDEBUG
+// is not defined).  Contrast this with DCHECK et al., which has
+// different behavior.
+
+#define DLOG_IS_ON(severity) false
+#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS
+#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+
+#endif  // ENABLE_DLOG
+
+// DEBUG_MODE is for uses like
+//   if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of
+//   #ifndef NDEBUG
+//     foo.CheckThatFoo();
+//   #endif
+//
+// We tie its state to ENABLE_DLOG.
+enum { DEBUG_MODE = ENABLE_DLOG };
+
+#undef ENABLE_DLOG
+
+#define DLOG(severity)                                          \
+  LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DPLOG(severity)                                         \
+  LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DVLOG(verboselevel) DVLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+// Definitions for DCHECK et al.
+
+#if DCHECK_IS_ON()
+
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
+const LogSeverity LOG_DCHECK = LOG_FATAL;
+
+#else  // DCHECK_IS_ON()
+
+// These are just dummy values.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
+const LogSeverity LOG_DCHECK = LOG_INFO;
+
+#endif  // DCHECK_IS_ON()
+
+// DCHECK et al. make sure to reference |condition| regardless of
+// whether DCHECKs are enabled; this is so that we don't get unused
+// variable warnings if the only use of a variable is in a DCHECK.
+// This behavior is different from DLOG_IF et al.
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+// See comments on the previous use of __analysis_assume.
+
+#define DCHECK(condition)                                               \
+  __analysis_assume(!!(condition)),                                     \
+  LAZY_STREAM(LOG_STREAM(DCHECK), false)                                \
+  << "Check failed: " #condition ". "
+
+#define DPCHECK(condition)                                              \
+  __analysis_assume(!!(condition)),                                     \
+  LAZY_STREAM(PLOG_STREAM(DCHECK), false)                               \
+  << "Check failed: " #condition ". "
+
+#else  // _PREFAST_
+
+#define DCHECK(condition)                                                \
+  LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+      << "Check failed: " #condition ". "
+
+#define DPCHECK(condition)                                                \
+  LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+      << "Check failed: " #condition ". "
+
+#endif  // _PREFAST_
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use DCHECK_EQ et al below.
+#define DCHECK_OP(name, op, val1, val2)                                   \
+  if (DCHECK_IS_ON())                                                     \
+    if (std::string* _result = logging::Check##name##Impl(                \
+            (val1), (val2), #val1 " " #op " " #val2))                     \
+  logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \
+      .stream()
+
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected.  The values must have operator<<(ostream, ...)
+// defined.
+//
+// You may append to the error message like so:
+//   DCHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here.  In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+//   DCHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These may not compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
+#define DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2))
+
+#if !DCHECK_IS_ON() && defined(OS_CHROMEOS)
+#define NOTREACHED() LOG(ERROR) << "NOTREACHED() hit in " << \
+    __FUNCTION__ << ". "
+#else
+#define NOTREACHED() DCHECK(false)
+#endif
+
+// Redefine the standard assert to use our nice log files
+#undef assert
+#define assert(x) DLOG_ASSERT(x)
+
+// This class more or less represents a particular log message.  You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though.  You should use the LOG() macro (and variants thereof)
+// above.
+class BASE_EXPORT LogMessage {
+ public:
+  // Used for LOG(severity).
+  LogMessage(const char* file, int line, LogSeverity severity);
+
+  // Used for CHECK_EQ(), etc. Takes ownership of the given string.
+  // Implied severity = LOG_FATAL.
+  LogMessage(const char* file, int line, std::string* result);
+
+  // Used for DCHECK_EQ(), etc. Takes ownership of the given string.
+  LogMessage(const char* file, int line, LogSeverity severity,
+             std::string* result);
+
+  ~LogMessage();
+
+  std::ostream& stream() { return stream_; }
+
+ private:
+  void Init(const char* file, int line);
+
+  LogSeverity severity_;
+  std::ostringstream stream_;
+  size_t message_start_;  // Offset of the start of the message (past prefix
+                          // info).
+  // The file and line information passed in to the constructor.
+  const char* file_;
+  const int line_;
+
+#if defined(OS_WIN)
+  // Stores the current value of GetLastError in the constructor and restores
+  // it in the destructor by calling SetLastError.
+  // This is useful since the LogMessage class uses a lot of Win32 calls
+  // that will lose the value of GLE and the code that called the log function
+  // will have lost the thread error value when the log call returns.
+  class SaveLastError {
+   public:
+    SaveLastError();
+    ~SaveLastError();
+
+    unsigned long get_error() const { return last_error_; }
+
+   protected:
+    unsigned long last_error_;
+  };
+
+  SaveLastError last_error_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const log_level, std::string const &msg) {
+  LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
+}
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros.  This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+  LogMessageVoidify() { }
+  // This has to be an operator with a precedence lower than << but
+  // higher than ?:
+  void operator&(std::ostream&) { }
+};
+
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code);
+
+#if defined(OS_WIN)
+// Appends a formatted system message of the GetLastError() type.
+class BASE_EXPORT Win32ErrorLogMessage {
+ public:
+  Win32ErrorLogMessage(const char* file,
+                       int line,
+                       LogSeverity severity,
+                       SystemErrorCode err);
+
+  // Appends the error message before destructing the encapsulated class.
+  ~Win32ErrorLogMessage();
+
+  std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+  SystemErrorCode err_;
+  LogMessage log_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
+};
+#elif defined(OS_POSIX)
+// Appends a formatted system message of the errno type
+class BASE_EXPORT ErrnoLogMessage {
+ public:
+  ErrnoLogMessage(const char* file,
+                  int line,
+                  LogSeverity severity,
+                  SystemErrorCode err);
+
+  // Appends the error message before destructing the encapsulated class.
+  ~ErrnoLogMessage();
+
+  std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+  SystemErrorCode err_;
+  LogMessage log_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
+};
+#endif  // OS_WIN
+
+// Closes the log file explicitly if open.
+// NOTE: Since the log file is opened as necessary by the action of logging
+//       statements, there's no guarantee that it will stay closed
+//       after this call.
+BASE_EXPORT void CloseLogFile();
+
+// Async signal safe logging mechanism.
+BASE_EXPORT void RawLog(int level, const char* message);
+
+#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message)
+
+#define RAW_CHECK(condition)                                                   \
+  do {                                                                         \
+    if (!(condition))                                                          \
+      logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n");   \
+  } while (0)
+
+#if defined(OS_WIN)
+// Returns the default log file path.
+BASE_EXPORT std::wstring GetLogFileFullPath();
+#endif
+
+}  // namespace logging
+
+// Note that "The behavior of a C++ program is undefined if it adds declarations
+// or definitions to namespace std or to a namespace within namespace std unless
+// otherwise specified." --C++11[namespace.std]
+//
+// We've checked that this particular definition has the intended behavior on
+// our implementations, but it's prone to breaking in the future, and please
+// don't imitate this in your own definitions without checking with some
+// standard library experts.
+namespace std {
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these
+// operators.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+  return out << wstr.c_str();
+}
+}  // namespace std
+
+// The NOTIMPLEMENTED() macro annotates codepaths which have
+// not been implemented yet.
+//
+// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
+//   0 -- Do nothing (stripped by compiler)
+//   1 -- Warn at compile time
+//   2 -- Fail at compile time
+//   3 -- Fail at runtime (DCHECK)
+//   4 -- [default] LOG(ERROR) at runtime
+//   5 -- LOG(ERROR) at runtime, only once per call-site
+
+#ifndef NOTIMPLEMENTED_POLICY
+#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
+#define NOTIMPLEMENTED_POLICY 0
+#else
+// Select default policy: LOG(ERROR)
+#define NOTIMPLEMENTED_POLICY 4
+#endif
+#endif
+
+#if defined(COMPILER_GCC)
+// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
+// of the current function in the NOTIMPLEMENTED message.
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
+#else
+#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
+#endif
+
+#if NOTIMPLEMENTED_POLICY == 0
+#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
+#elif NOTIMPLEMENTED_POLICY == 1
+// TODO, figure out how to generate a warning
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 2
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 3
+#define NOTIMPLEMENTED() NOTREACHED()
+#elif NOTIMPLEMENTED_POLICY == 4
+#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
+#elif NOTIMPLEMENTED_POLICY == 5
+#define NOTIMPLEMENTED() do {\
+  static bool logged_once = false;\
+  LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG;\
+  logged_once = true;\
+} while(0);\
+EAT_STREAM_PARAMETERS
+#endif
+
+#endif  // BASE_LOGGING_H_
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
new file mode 100644
index 0000000..8b9701a
--- /dev/null
+++ b/base/logging_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+using ::testing::Return;
+
+// Needs to be global since log assert handlers can't maintain state.
+int log_sink_call_count = 0;
+
+#if !defined(OFFICIAL_BUILD) || defined(DCHECK_ALWAYS_ON) || !defined(NDEBUG)
+void LogSink(const std::string& str) {
+  ++log_sink_call_count;
+}
+#endif
+
+// Class to make sure any manipulations we do to the min log level are
+// contained (i.e., do not affect other unit tests).
+class LogStateSaver {
+ public:
+  LogStateSaver() : old_min_log_level_(GetMinLogLevel()) {}
+
+  ~LogStateSaver() {
+    SetMinLogLevel(old_min_log_level_);
+    SetLogAssertHandler(NULL);
+    log_sink_call_count = 0;
+  }
+
+ private:
+  int old_min_log_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogStateSaver);
+};
+
+class LoggingTest : public testing::Test {
+ private:
+  LogStateSaver log_state_saver_;
+};
+
+class MockLogSource {
+ public:
+  MOCK_METHOD0(Log, const char*());
+};
+
+TEST_F(LoggingTest, BasicLogging) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(DEBUG_MODE ? 16 : 8).
+      WillRepeatedly(Return("log message"));
+
+  SetMinLogLevel(LOG_INFO);
+
+  EXPECT_TRUE(LOG_IS_ON(INFO));
+  // As of g++-4.5, the first argument to EXPECT_EQ cannot be a
+  // constant expression.
+  const bool kIsDebugMode = (DEBUG_MODE != 0);
+  EXPECT_TRUE(kIsDebugMode == DLOG_IS_ON(INFO));
+  EXPECT_TRUE(VLOG_IS_ON(0));
+
+  LOG(INFO) << mock_log_source.Log();
+  LOG_IF(INFO, true) << mock_log_source.Log();
+  PLOG(INFO) << mock_log_source.Log();
+  PLOG_IF(INFO, true) << mock_log_source.Log();
+  VLOG(0) << mock_log_source.Log();
+  VLOG_IF(0, true) << mock_log_source.Log();
+  VPLOG(0) << mock_log_source.Log();
+  VPLOG_IF(0, true) << mock_log_source.Log();
+
+  DLOG(INFO) << mock_log_source.Log();
+  DLOG_IF(INFO, true) << mock_log_source.Log();
+  DPLOG(INFO) << mock_log_source.Log();
+  DPLOG_IF(INFO, true) << mock_log_source.Log();
+  DVLOG(0) << mock_log_source.Log();
+  DVLOG_IF(0, true) << mock_log_source.Log();
+  DVPLOG(0) << mock_log_source.Log();
+  DVPLOG_IF(0, true) << mock_log_source.Log();
+}
+
+TEST_F(LoggingTest, LogIsOn) {
+#if defined(NDEBUG)
+  const bool kDfatalIsFatal = false;
+#else  // defined(NDEBUG)
+  const bool kDfatalIsFatal = true;
+#endif  // defined(NDEBUG)
+
+  SetMinLogLevel(LOG_INFO);
+  EXPECT_TRUE(LOG_IS_ON(INFO));
+  EXPECT_TRUE(LOG_IS_ON(WARNING));
+  EXPECT_TRUE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  SetMinLogLevel(LOG_WARNING);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_TRUE(LOG_IS_ON(WARNING));
+  EXPECT_TRUE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  SetMinLogLevel(LOG_ERROR);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(LOG_IS_ON(WARNING));
+  EXPECT_TRUE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  // LOG_IS_ON(FATAL) should always be true.
+  SetMinLogLevel(LOG_FATAL + 1);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(LOG_IS_ON(WARNING));
+  EXPECT_FALSE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL));
+}
+
+TEST_F(LoggingTest, LoggingIsLazy) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+
+  SetMinLogLevel(LOG_WARNING);
+
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(DLOG_IS_ON(INFO));
+  EXPECT_FALSE(VLOG_IS_ON(1));
+
+  LOG(INFO) << mock_log_source.Log();
+  LOG_IF(INFO, false) << mock_log_source.Log();
+  PLOG(INFO) << mock_log_source.Log();
+  PLOG_IF(INFO, false) << mock_log_source.Log();
+  VLOG(1) << mock_log_source.Log();
+  VLOG_IF(1, true) << mock_log_source.Log();
+  VPLOG(1) << mock_log_source.Log();
+  VPLOG_IF(1, true) << mock_log_source.Log();
+
+  DLOG(INFO) << mock_log_source.Log();
+  DLOG_IF(INFO, true) << mock_log_source.Log();
+  DPLOG(INFO) << mock_log_source.Log();
+  DPLOG_IF(INFO, true) << mock_log_source.Log();
+  DVLOG(1) << mock_log_source.Log();
+  DVLOG_IF(1, true) << mock_log_source.Log();
+  DVPLOG(1) << mock_log_source.Log();
+  DVPLOG_IF(1, true) << mock_log_source.Log();
+}
+
+// Official builds have CHECKs directly call BreakDebugger.
+#if !defined(OFFICIAL_BUILD)
+
+TEST_F(LoggingTest, CheckStreamsAreLazy) {
+  MockLogSource mock_log_source, uncalled_mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(8).
+      WillRepeatedly(Return("check message"));
+  EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0);
+
+  SetLogAssertHandler(&LogSink);
+
+  CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log();
+  PCHECK(!mock_log_source.Log()) << mock_log_source.Log();
+  CHECK_EQ(mock_log_source.Log(), mock_log_source.Log())
+      << uncalled_mock_log_source.Log();
+  CHECK_NE(mock_log_source.Log(), mock_log_source.Log())
+      << mock_log_source.Log();
+}
+
+#endif
+
+TEST_F(LoggingTest, DebugLoggingReleaseBehavior) {
+#if !defined(NDEBUG)
+  int debug_only_variable = 1;
+#endif
+  // These should avoid emitting references to |debug_only_variable|
+  // in release mode.
+  DLOG_IF(INFO, debug_only_variable) << "test";
+  DLOG_ASSERT(debug_only_variable) << "test";
+  DPLOG_IF(INFO, debug_only_variable) << "test";
+  DVLOG_IF(1, debug_only_variable) << "test";
+}
+
+TEST_F(LoggingTest, DcheckStreamsAreLazy) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+#if DCHECK_IS_ON()
+  DCHECK(true) << mock_log_source.Log();
+  DCHECK_EQ(0, 0) << mock_log_source.Log();
+#else
+  DCHECK(mock_log_source.Log()) << mock_log_source.Log();
+  DPCHECK(mock_log_source.Log()) << mock_log_source.Log();
+  DCHECK_EQ(0, 0) << mock_log_source.Log();
+  DCHECK_EQ(mock_log_source.Log(), static_cast<const char*>(NULL))
+      << mock_log_source.Log();
+#endif
+}
+
+TEST_F(LoggingTest, Dcheck) {
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+  // Release build.
+  EXPECT_FALSE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
+  // Release build with real DCHECKS.
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#else
+  // Debug build.
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
+#endif
+
+  EXPECT_EQ(0, log_sink_call_count);
+  DCHECK(false);
+  EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count);
+  DPCHECK(false);
+  EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count);
+  DCHECK_EQ(0, 1);
+  EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count);
+}
+
+TEST_F(LoggingTest, DcheckReleaseBehavior) {
+  int some_variable = 1;
+  // These should still reference |some_variable| so we don't get
+  // unused variable warnings.
+  DCHECK(some_variable) << "test";
+  DPCHECK(some_variable) << "test";
+  DCHECK_EQ(some_variable, 1) << "test";
+}
+
+// Test that defining an operator<< for a type in a namespace doesn't prevent
+// other code in that namespace from calling the operator<<(ostream, wstring)
+// defined by logging.h. This can fail if operator<<(ostream, wstring) can't be
+// found by ADL, since defining another operator<< prevents name lookup from
+// looking in the global namespace.
+namespace nested_test {
+  class Streamable {};
+  ALLOW_UNUSED_TYPE std::ostream& operator<<(std::ostream& out,
+                                             const Streamable&) {
+    return out << "Streamable";
+  }
+  TEST_F(LoggingTest, StreamingWstringFindsCorrectOperator) {
+    std::wstring wstr = L"Hello World";
+    std::ostringstream ostr;
+    ostr << wstr;
+    EXPECT_EQ("Hello World", ostr.str());
+  }
+}  // namespace nested_test
+
+}  // namespace
+
+}  // namespace logging
diff --git a/base/logging_win.cc b/base/logging_win.cc
new file mode 100644
index 0000000..53cc37c
--- /dev/null
+++ b/base/logging_win.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging_win.h"
+#include "base/memory/singleton.h"
+#include <initguid.h>  // NOLINT
+
+namespace logging {
+
+using base::win::EtwEventLevel;
+using base::win::EtwMofEvent;
+
+DEFINE_GUID(kLogEventId,
+    0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
+
+LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
+}
+
+LogEventProvider* LogEventProvider::GetInstance() {
+  return Singleton<LogEventProvider,
+                   StaticMemorySingletonTraits<LogEventProvider> >::get();
+}
+
+bool LogEventProvider::LogMessage(logging::LogSeverity severity,
+    const char* file, int line, size_t message_start,
+    const std::string& message) {
+  EtwEventLevel level = TRACE_LEVEL_NONE;
+
+  // Convert the log severity to the most appropriate ETW trace level.
+  if (severity >= 0) {
+    switch (severity) {
+      case LOG_INFO:
+        level = TRACE_LEVEL_INFORMATION;
+        break;
+      case LOG_WARNING:
+        level = TRACE_LEVEL_WARNING;
+        break;
+      case LOG_ERROR:
+        level = TRACE_LEVEL_ERROR;
+        break;
+      case LOG_FATAL:
+        level = TRACE_LEVEL_FATAL;
+        break;
+    }
+  } else {  // severity < 0 is VLOG verbosity levels.
+    level = static_cast<EtwEventLevel>(TRACE_LEVEL_INFORMATION - severity);
+  }
+
+  // Bail if we're not logging, not at that level,
+  // or if we're post-atexit handling.
+  LogEventProvider* provider = LogEventProvider::GetInstance();
+  if (provider == NULL || level > provider->enable_level())
+    return false;
+
+  // And now log the event.
+  if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
+    EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
+    event.SetField(0, message.length() + 1 - message_start,
+        message.c_str() + message_start);
+
+    provider->Log(event.get());
+  } else {
+    const size_t kMaxBacktraceDepth = 32;
+    void* backtrace[kMaxBacktraceDepth];
+    DWORD depth = 0;
+
+    // Capture a stack trace if one is requested.
+    // requested per our enable flags.
+    if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
+      depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
+
+    EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
+    if (file == NULL)
+      file = "";
+
+    // Add the stack trace.
+    event.SetField(0, sizeof(depth), &depth);
+    event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
+    // The line.
+    event.SetField(2, sizeof(line), &line);
+    // The file.
+    event.SetField(3, strlen(file) + 1, file);
+    // And finally the message.
+    event.SetField(4, message.length() + 1 - message_start,
+        message.c_str() + message_start);
+
+    provider->Log(event.get());
+  }
+
+  // Don't increase verbosity in other log destinations.
+  if (severity < provider->old_log_level_)
+    return true;
+
+  return false;
+}
+
+void LogEventProvider::Initialize(const GUID& provider_name) {
+  LogEventProvider* provider = LogEventProvider::GetInstance();
+
+  provider->set_provider_name(provider_name);
+  provider->Register();
+
+  // Register our message handler with logging.
+  SetLogMessageHandler(LogMessage);
+}
+
+void LogEventProvider::Uninitialize() {
+  LogEventProvider::GetInstance()->Unregister();
+}
+
+void LogEventProvider::OnEventsEnabled() {
+  // Grab the old log level so we can restore it later.
+  old_log_level_ = GetMinLogLevel();
+
+  // Convert the new trace level to a logging severity
+  // and enable logging at that level.
+  EtwEventLevel level = enable_level();
+  if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
+    SetMinLogLevel(LOG_FATAL);
+  } else if (level == TRACE_LEVEL_ERROR) {
+    SetMinLogLevel(LOG_ERROR);
+  } else if (level == TRACE_LEVEL_WARNING) {
+    SetMinLogLevel(LOG_WARNING);
+  } else if (level == TRACE_LEVEL_INFORMATION) {
+    SetMinLogLevel(LOG_INFO);
+  } else if (level >= TRACE_LEVEL_VERBOSE) {
+    // Above INFO, we enable verbose levels with negative severities.
+    SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
+  }
+}
+
+void LogEventProvider::OnEventsDisabled() {
+  // Restore the old log level.
+  SetMinLogLevel(old_log_level_);
+}
+
+}  // namespace logging
diff --git a/base/logging_win.h b/base/logging_win.h
new file mode 100644
index 0000000..aa48e22
--- /dev/null
+++ b/base/logging_win.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_WIN_H_
+#define BASE_LOGGING_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/win/event_trace_provider.h"
+#include "base/logging.h"
+
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace logging {
+
+// Event ID for the log messages we generate.
+EXTERN_C BASE_EXPORT const GUID kLogEventId;
+
+// Feature enable mask for LogEventProvider.
+enum LogEnableMask {
+  // If this bit is set in our provider enable mask, we will include
+  // a stack trace with every log message.
+  ENABLE_STACK_TRACE_CAPTURE = 0x0001,
+  // If this bit is set in our provider enable mask, the provider will log
+  // a LOG message with only the textual content of the message, and no
+  // stack trace.
+  ENABLE_LOG_MESSAGE_ONLY = 0x0002,
+};
+
+// The message types our log event provider generates.
+// ETW likes user message types to start at 10.
+enum LogMessageTypes {
+  // A textual only log message, contains a zero-terminated string.
+  LOG_MESSAGE = 10,
+  // A message with a stack trace, followed by the zero-terminated
+  // message text.
+  LOG_MESSAGE_WITH_STACKTRACE = 11,
+  // A message with:
+  //  a stack trace,
+  //  the line number as a four byte integer,
+  //  the file as a zero terminated UTF8 string,
+  //  the zero-terminated UTF8 message text.
+  LOG_MESSAGE_FULL = 12,
+};
+
+// Trace provider class to drive log control and transport
+// with Event Tracing for Windows.
+class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider {
+ public:
+  static LogEventProvider* GetInstance();
+
+  static bool LogMessage(logging::LogSeverity severity, const char* file,
+      int line, size_t message_start, const std::string& str);
+
+  static void Initialize(const GUID& provider_name);
+  static void Uninitialize();
+
+ protected:
+  // Overridden to manipulate the log level on ETW control callbacks.
+  void OnEventsEnabled() override;
+  void OnEventsDisabled() override;
+
+ private:
+  LogEventProvider();
+
+  // The log severity prior to OnEventsEnabled,
+  // restored in OnEventsDisabled.
+  logging::LogSeverity old_log_level_;
+
+  friend struct StaticMemorySingletonTraits<LogEventProvider>;
+  DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
+};
+
+}  // namespace logging
+
+#endif  // BASE_LOGGING_WIN_H_
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
new file mode 100644
index 0000000..4aba972
--- /dev/null
+++ b/base/mac/OWNERS
@@ -0,0 +1,14 @@
+mark@chromium.org
+thakis@chromium.org
+
+# sdk_forward_declarations.[h|mm] will likely need to be modified by Cocoa
+# developers in general; keep in sync with OWNERS of //chrome/browser/ui/cocoa.
+per-file sdk_forward_declarations.*=asvitkine@chromium.org
+per-file sdk_forward_declarations.*=avi@chromium.org
+per-file sdk_forward_declarations.*=groby@chromium.org
+per-file sdk_forward_declarations.*=jeremy@chromium.org
+per-file sdk_forward_declarations.*=mark@chromium.org
+per-file sdk_forward_declarations.*=rohitrao@chromium.org
+per-file sdk_forward_declarations.*=rsesek@chromium.org
+per-file sdk_forward_declarations.*=shess@chromium.org
+per-file sdk_forward_declarations.*=thakis@chromium.org
diff --git a/base/mac/authorization_util.h b/base/mac/authorization_util.h
new file mode 100644
index 0000000..4629039
--- /dev/null
+++ b/base/mac/authorization_util.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_AUTHORIZATION_UTIL_H_
+#define BASE_MAC_AUTHORIZATION_UTIL_H_
+
+// AuthorizationExecuteWithPrivileges fork()s and exec()s the tool, but it
+// does not wait() for it.  It also doesn't provide the caller with access to
+// the forked pid.  If used irresponsibly, zombie processes will accumulate.
+//
+// Apple's really gotten us between a rock and a hard place, here.
+//
+// Fortunately, AuthorizationExecuteWithPrivileges does give access to the
+// tool's stdout (and stdin) via a FILE* pipe.  The tool can output its pid
+// to this pipe, and the main program can read it, and then have something
+// that it can wait() for.
+//
+// The contract is that any tool executed by the wrappers declared in this
+// file must print its pid to stdout on a line by itself before doing anything
+// else.
+//
+// http://developer.apple.com/library/mac/#samplecode/BetterAuthorizationSample/Listings/BetterAuthorizationSampleLib_c.html
+// (Look for "What's This About Zombies?")
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Authorization.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// Obtains an AuthorizationRef for the rights indicated by |rights|.  If
+// necessary, prompts the user for authentication. If the user is prompted,
+// |prompt| will be used as the prompt string and an icon appropriate for the
+// application will be displayed in a prompt dialog. Note that the system
+// appends its own text to the prompt string. |extraFlags| will be ORed
+// together with the default flags. Returns NULL on failure.
+BASE_EXPORT
+AuthorizationRef GetAuthorizationRightsWithPrompt(
+    AuthorizationRights* rights,
+    CFStringRef prompt,
+    AuthorizationFlags extraFlags);
+
+// Obtains an AuthorizationRef (using |GetAuthorizationRightsWithPrompt|) that
+// can be used to run commands as root.
+BASE_EXPORT
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt);
+
+// Calls straight through to AuthorizationExecuteWithPrivileges.  If that
+// call succeeds, |pid| will be set to the pid of the executed tool.  If the
+// pid can't be determined, |pid| will be set to -1.  |pid| must not be NULL.
+// |pipe| may be NULL, but the tool will always be executed with a pipe in
+// order to read the pid from its stdout.
+BASE_EXPORT
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+                                        const char* tool_path,
+                                        AuthorizationFlags options,
+                                        const char** arguments,
+                                        FILE** pipe,
+                                        pid_t* pid);
+
+// Calls ExecuteWithPrivilegesAndGetPID, and if that call succeeds, calls
+// waitpid() to wait for the process to exit.  If waitpid() succeeds, the
+// exit status is placed in |exit_status|, otherwise, -1 is stored.
+// |exit_status| may be NULL and this function will still wait for the process
+// to exit.
+BASE_EXPORT
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+                                      const char* tool_path,
+                                      AuthorizationFlags options,
+                                      const char** arguments,
+                                      FILE** pipe,
+                                      int* exit_status);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_AUTHORIZATION_UTIL_H_
diff --git a/base/mac/authorization_util.mm b/base/mac/authorization_util.mm
new file mode 100644
index 0000000..1dfd5a0
--- /dev/null
+++ b/base/mac/authorization_util.mm
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/authorization_util.h"
+
+#import <Foundation/Foundation.h>
+#include <sys/wait.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_authorizationref.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace mac {
+
+AuthorizationRef GetAuthorizationRightsWithPrompt(
+    AuthorizationRights* rights,
+    CFStringRef prompt,
+    AuthorizationFlags extraFlags) {
+  // Create an empty AuthorizationRef.
+  ScopedAuthorizationRef authorization;
+  OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
+                                        kAuthorizationFlagDefaults,
+                                        authorization.get_pointer());
+  if (status != errAuthorizationSuccess) {
+    OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate";
+    return NULL;
+  }
+
+  AuthorizationFlags flags = kAuthorizationFlagDefaults |
+                             kAuthorizationFlagInteractionAllowed |
+                             kAuthorizationFlagExtendRights |
+                             kAuthorizationFlagPreAuthorize |
+                             extraFlags;
+
+  // product_logo_32.png is used instead of app.icns because Authorization
+  // Services can't deal with .icns files.
+  NSString* icon_path =
+      [base::mac::FrameworkBundle() pathForResource:@"product_logo_32"
+                                             ofType:@"png"];
+  const char* icon_path_c = [icon_path fileSystemRepresentation];
+  size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
+
+  // The OS will append " Type an administrator's name and password to allow
+  // <CFBundleDisplayName> to make changes."
+  NSString* prompt_ns = base::mac::CFToNSCast(prompt);
+  const char* prompt_c = [prompt_ns UTF8String];
+  size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
+
+  AuthorizationItem environment_items[] = {
+    {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0},
+    {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0}
+  };
+
+  AuthorizationEnvironment environment = {arraysize(environment_items),
+                                          environment_items};
+
+  status = AuthorizationCopyRights(authorization,
+                                   rights,
+                                   &environment,
+                                   flags,
+                                   NULL);
+
+  if (status != errAuthorizationSuccess) {
+    if (status != errAuthorizationCanceled) {
+      OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights";
+    }
+    return NULL;
+  }
+
+  return authorization.release();
+}
+
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
+  // Specify the "system.privilege.admin" right, which allows
+  // AuthorizationExecuteWithPrivileges to run commands as root.
+  AuthorizationItem right_items[] = {
+    {kAuthorizationRightExecute, 0, NULL, 0}
+  };
+  AuthorizationRights rights = {arraysize(right_items), right_items};
+
+  return GetAuthorizationRightsWithPrompt(&rights, prompt, 0);
+}
+
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+                                        const char* tool_path,
+                                        AuthorizationFlags options,
+                                        const char** arguments,
+                                        FILE** pipe,
+                                        pid_t* pid) {
+  // pipe may be NULL, but this function needs one.  In that case, use a local
+  // pipe.
+  FILE* local_pipe;
+  FILE** pipe_pointer;
+  if (pipe) {
+    pipe_pointer = pipe;
+  } else {
+    pipe_pointer = &local_pipe;
+  }
+
+  // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
+  // but it doesn't actually modify the arguments, and that type is kind of
+  // silly and callers probably aren't dealing with that.  Put the cast here
+  // to make things a little easier on callers.
+  OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
+                                                       tool_path,
+                                                       options,
+                                                       (char* const*)arguments,
+                                                       pipe_pointer);
+  if (status != errAuthorizationSuccess) {
+    return status;
+  }
+
+  int line_pid = -1;
+  size_t line_length = 0;
+  char* line_c = fgetln(*pipe_pointer, &line_length);
+  if (line_c) {
+    if (line_length > 0 && line_c[line_length - 1] == '\n') {
+      // line_c + line_length is the start of the next line if there is one.
+      // Back up one character.
+      --line_length;
+    }
+    std::string line(line_c, line_length);
+    if (!base::StringToInt(line, &line_pid)) {
+      // StringToInt may have set line_pid to something, but if the conversion
+      // was imperfect, use -1.
+      LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line;
+      line_pid = -1;
+    }
+  } else {
+    LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line";
+  }
+
+  if (!pipe) {
+    fclose(*pipe_pointer);
+  }
+
+  if (pid) {
+    *pid = line_pid;
+  }
+
+  return status;
+}
+
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+                                      const char* tool_path,
+                                      AuthorizationFlags options,
+                                      const char** arguments,
+                                      FILE** pipe,
+                                      int* exit_status) {
+  pid_t pid;
+  OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization,
+                                                   tool_path,
+                                                   options,
+                                                   arguments,
+                                                   pipe,
+                                                   &pid);
+  if (status != errAuthorizationSuccess) {
+    return status;
+  }
+
+  // exit_status may be NULL, but this function needs it.  In that case, use a
+  // local version.
+  int local_exit_status;
+  int* exit_status_pointer;
+  if (exit_status) {
+    exit_status_pointer = exit_status;
+  } else {
+    exit_status_pointer = &local_exit_status;
+  }
+
+  if (pid != -1) {
+    pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0));
+    if (wait_result != pid) {
+      PLOG(ERROR) << "waitpid";
+      *exit_status_pointer = -1;
+    }
+  } else {
+    *exit_status_pointer = -1;
+  }
+
+  return status;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/bind_objc_block.h b/base/mac/bind_objc_block.h
new file mode 100644
index 0000000..c31f26e
--- /dev/null
+++ b/base/mac/bind_objc_block.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_BIND_OBJC_BLOCK_H_
+#define BASE_MAC_BIND_OBJC_BLOCK_H_
+
+#include <Block.h>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/mac/scoped_block.h"
+
+// BindBlock builds a callback from an Objective-C block. Example usages:
+//
+// Closure closure = BindBlock(^{DoSomething();});
+//
+// Callback<int(void)> callback = BindBlock(^{return 42;});
+//
+// Callback<void(const std::string&, const std::string&)> callback =
+//     BindBlock(^(const std::string& arg0, const std::string& arg1) {
+//         ...
+//     });
+//
+// These variadic templates will accommodate any number of arguments, however
+// the underlying templates in bind_internal.h and callback.h are limited to
+// seven total arguments, and the bound block itself is used as one of these
+// arguments, so functionally the templates are limited to binding blocks with
+// zero through six arguments.
+
+namespace base {
+
+namespace internal {
+
+// Helper function to run the block contained in the parameter.
+template<typename R, typename... Args>
+R RunBlock(base::mac::ScopedBlock<R(^)(Args...)> block, Args... args) {
+  R(^extracted_block)(Args...) = block.get();
+  return extracted_block(args...);
+}
+
+}  // namespace internal
+
+// Construct a callback from an objective-C block with up to six arguments (see
+// note above).
+template<typename R, typename... Args>
+base::Callback<R(Args...)> BindBlock(R(^block)(Args...)) {
+  return base::Bind(&base::internal::RunBlock<R, Args...>,
+                    base::mac::ScopedBlock<R(^)(Args...)>(Block_copy(block)));
+}
+
+}  // namespace base
+
+#endif  // BASE_MAC_BIND_OBJC_BLOCK_H_
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm
new file mode 100644
index 0000000..5d15eba
--- /dev/null
+++ b/base/mac/bind_objc_block_unittest.mm
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/bind_objc_block.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(BindObjcBlockTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  int* ptr = &run_count;
+  {
+    base::ScopedClosureRunner runner(base::BindBlock(^{
+        (*ptr)++;
+    }));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindObjcBlockTest, TestScopedClosureRunnerRelease) {
+  int run_count = 0;
+  int* ptr = &run_count;
+  base::Closure c;
+  {
+    base::ScopedClosureRunner runner(base::BindBlock(^{
+        (*ptr)++;
+    }));
+    c = runner.Release();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(0, run_count);
+  c.Run();
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindObjcBlockTest, TestReturnValue) {
+  const int kReturnValue = 42;
+  base::Callback<int(void)> c = base::BindBlock(^{return kReturnValue;});
+  EXPECT_EQ(kReturnValue, c.Run());
+}
+
+TEST(BindObjcBlockTest, TestArgument) {
+  const int kArgument = 42;
+  base::Callback<int(int)> c = base::BindBlock(^(int a){return a + 1;});
+  EXPECT_EQ(kArgument + 1, c.Run(kArgument));
+}
+
+TEST(BindObjcBlockTest, TestTwoArguments) {
+  std::string result;
+  std::string* ptr = &result;
+  base::Callback<void(const std::string&, const std::string&)> c =
+      base::BindBlock(^(const std::string& a, const std::string& b) {
+          *ptr = a + b;
+      });
+  c.Run("forty", "two");
+  EXPECT_EQ(result, "fortytwo");
+}
+
+TEST(BindObjcBlockTest, TestThreeArguments) {
+  std::string result;
+  std::string* ptr = &result;
+  base::Callback<void(const std::string&,
+                      const std::string&,
+                      const std::string&)> c =
+      base::BindBlock(^(const std::string& a,
+                        const std::string& b,
+                        const std::string& c) {
+          *ptr = a + b + c;
+      });
+  c.Run("six", "times", "nine");
+  EXPECT_EQ(result, "sixtimesnine");
+}
+
+TEST(BindObjcBlockTest, TestSixArguments) {
+  std::string result1;
+  std::string* ptr = &result1;
+  int result2;
+  int* ptr2 = &result2;
+  base::Callback<void(int, int, const std::string&, const std::string&,
+                      int, const std::string&)> c =
+      base::BindBlock(^(int a, int b, const std::string& c,
+                        const std::string& d, int e, const std::string& f) {
+          *ptr = c + d + f;
+          *ptr2 = a + b + e;
+      });
+  c.Run(1, 2, "infinite", "improbability", 3, "drive");
+  EXPECT_EQ(result1, "infiniteimprobabilitydrive");
+  EXPECT_EQ(result2, 6);
+}
+
+}  // namespace
diff --git a/base/mac/bundle_locations.h b/base/mac/bundle_locations.h
new file mode 100644
index 0000000..276290b
--- /dev/null
+++ b/base/mac/bundle_locations.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_BUNDLE_LOCATIONS_H_
+#define BASE_MAC_BUNDLE_LOCATIONS_H_
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+class NSBundle;
+class NSString;
+#endif  // __OBJC__
+
+namespace base {
+
+class FilePath;
+
+namespace mac {
+
+// This file provides several functions to explicitly request the various
+// component bundles of Chrome.  Please use these methods rather than calling
+// +[NSBundle mainBundle] or CFBundleGetMainBundle().
+//
+// Terminology
+//  - "Outer Bundle" - This is the main bundle for Chrome; it's what
+//  +[NSBundle mainBundle] returns when Chrome is launched normally.
+//
+//  - "Main Bundle" - This is the bundle from which Chrome was launched.
+//  This will be the same as the outer bundle except when Chrome is launched
+//  via an app shortcut, in which case this will return the app shortcut's
+//  bundle rather than the main Chrome bundle.
+//
+//  - "Framework Bundle" - This is the bundle corresponding to the Chrome
+//  framework.
+//
+// Guidelines for use:
+//  - To access a resource, the Framework bundle should be used.
+//  - If the choice is between the Outer or Main bundles then please choose
+//  carefully.  Most often the Outer bundle will be the right choice, but for
+//  cases such as adding an app to the "launch on startup" list, the Main
+//  bundle is probably the one to use.
+
+// Methods for retrieving the various bundles.
+BASE_EXPORT NSBundle* MainBundle();
+BASE_EXPORT FilePath MainBundlePath();
+BASE_EXPORT NSBundle* OuterBundle();
+BASE_EXPORT FilePath OuterBundlePath();
+BASE_EXPORT NSBundle* FrameworkBundle();
+BASE_EXPORT FilePath FrameworkBundlePath();
+
+// Set the bundle that the preceding functions will return, overriding the
+// default values. Restore the default by passing in |nil|.
+BASE_EXPORT void SetOverrideOuterBundle(NSBundle* bundle);
+BASE_EXPORT void SetOverrideFrameworkBundle(NSBundle* bundle);
+
+// Same as above but accepting a FilePath argument.
+BASE_EXPORT void SetOverrideOuterBundlePath(const FilePath& file_path);
+BASE_EXPORT void SetOverrideFrameworkBundlePath(const FilePath& file_path);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_BUNDLE_LOCATIONS_H_
diff --git a/base/mac/bundle_locations.mm b/base/mac/bundle_locations.mm
new file mode 100644
index 0000000..54021b8
--- /dev/null
+++ b/base/mac/bundle_locations.mm
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/bundle_locations.h"
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+// NSBundle isn't threadsafe, all functions in this file must be called on the
+// main thread.
+static NSBundle* g_override_framework_bundle = nil;
+static NSBundle* g_override_outer_bundle = nil;
+
+NSBundle* MainBundle() {
+  return [NSBundle mainBundle];
+}
+
+FilePath MainBundlePath() {
+  NSBundle* bundle = MainBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+NSBundle* OuterBundle() {
+  if (g_override_outer_bundle)
+    return g_override_outer_bundle;
+  return [NSBundle mainBundle];
+}
+
+FilePath OuterBundlePath() {
+  NSBundle* bundle = OuterBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+NSBundle* FrameworkBundle() {
+  if (g_override_framework_bundle)
+    return g_override_framework_bundle;
+  return [NSBundle mainBundle];
+}
+
+FilePath FrameworkBundlePath() {
+  NSBundle* bundle = FrameworkBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+static void AssignOverrideBundle(NSBundle* new_bundle,
+                                 NSBundle** override_bundle) {
+  if (new_bundle != *override_bundle) {
+    [*override_bundle release];
+    *override_bundle = [new_bundle retain];
+  }
+}
+
+static void AssignOverridePath(const FilePath& file_path,
+                               NSBundle** override_bundle) {
+  NSString* path = base::SysUTF8ToNSString(file_path.value());
+  NSBundle* new_bundle = [NSBundle bundleWithPath:path];
+  DCHECK(new_bundle) << "Failed to load the bundle at " << file_path.value();
+  AssignOverrideBundle(new_bundle, override_bundle);
+}
+
+void SetOverrideOuterBundle(NSBundle* bundle) {
+  AssignOverrideBundle(bundle, &g_override_outer_bundle);
+}
+
+void SetOverrideFrameworkBundle(NSBundle* bundle) {
+  AssignOverrideBundle(bundle, &g_override_framework_bundle);
+}
+
+void SetOverrideOuterBundlePath(const FilePath& file_path) {
+  AssignOverridePath(file_path, &g_override_outer_bundle);
+}
+
+void SetOverrideFrameworkBundlePath(const FilePath& file_path) {
+  AssignOverridePath(file_path, &g_override_framework_bundle);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/close_nocancel.cc b/base/mac/close_nocancel.cc
new file mode 100644
index 0000000..8971e73
--- /dev/null
+++ b/base/mac/close_nocancel.cc
@@ -0,0 +1,70 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// http://crbug.com/269623
+// http://openradar.appspot.com/14999594
+//
+// When the default version of close used on Mac OS X fails with EINTR, the
+// file descriptor is not in a deterministic state. It may have been closed,
+// or it may not have been. This makes it impossible to gracefully recover
+// from the error. If the close is retried after the FD has been closed, the
+// subsequent close can report EBADF, or worse, it can close an unrelated FD
+// opened by another thread. If the close is not retried after the FD has been
+// left open, the FD is leaked. Neither of these are good options.
+//
+// Mac OS X provides an alternate version of close, close$NOCANCEL. This
+// version will never fail with EINTR before the FD is actually closed. With
+// this version, it is thus safe to call close without checking for EINTR (as
+// the HANDLE_EINTR macro does) and not risk leaking the FD. In fact, mixing
+// this verison of close with HANDLE_EINTR is hazardous.
+//
+// The $NOCANCEL variants of various system calls are activated by compiling
+// with __DARWIN_NON_CANCELABLE, which prevents them from being pthread
+// cancellation points. Rather than taking such a heavy-handed approach, this
+// file implements an alternative: to use the $NOCANCEL variant of close (thus
+// preventing it from being a pthread cancellation point) without affecting
+// any other system calls.
+//
+// This file operates by providing a close function with the non-$NOCANCEL
+// symbol name expected for the compilation environment as set by <unistd.h>
+// and <sys/cdefs.h> (the DARWIN_ALIAS_C macro). That name is set by an asm
+// label on the declaration of the close function, so the definition of that
+// function receives that name. The function calls the $NOCANCEL variant, which
+// is resolved from libsyscall. By linking with this version of close prior to
+// the libsyscall version, close's implementation is overridden.
+
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+// If the non-cancelable variants of all system calls have already been
+// chosen, do nothing.
+#if !__DARWIN_NON_CANCELABLE
+
+extern "C" {
+
+#if !__DARWIN_ONLY_UNIX_CONFORMANCE
+
+// When there's a choice between UNIX2003 and pre-UNIX2003. There's no
+// close$NOCANCEL symbol in this case, so use close$NOCANCEL$UNIX2003 as the
+// implementation. It does the same thing that close$NOCANCEL would do.
+#define close_implementation close$NOCANCEL$UNIX2003
+
+#else  // __DARWIN_ONLY_UNIX_CONFORMANCE
+
+// When only UNIX2003 is supported:
+#define close_implementation close$NOCANCEL
+
+#endif
+
+int close_implementation(int fd);
+
+int close(int fd) {
+  return close_implementation(fd);
+}
+
+#undef close_implementation
+
+}  // extern "C"
+
+#endif  // !__DARWIN_NON_CANCELABLE
diff --git a/base/mac/cocoa_protocols.h b/base/mac/cocoa_protocols.h
new file mode 100644
index 0000000..a28795c
--- /dev/null
+++ b/base/mac/cocoa_protocols.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_COCOA_PROTOCOLS_H_
+#define BASE_MAC_COCOA_PROTOCOLS_H_
+
+#import <Cocoa/Cocoa.h>
+
+// New Mac OS X SDKs introduce new protocols used for delegates.  These
+// protocol defintions aren't not present in earlier releases of the Mac OS X
+// SDK.  In order to support building against the new SDK, which requires
+// delegates to conform to these protocols, and earlier SDKs, which do not
+// define these protocols at all, this file will provide empty protocol
+// definitions when used with earlier SDK versions.
+
+#define DEFINE_EMPTY_PROTOCOL(p) \
+@protocol p \
+@end
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+DEFINE_EMPTY_PROTOCOL(NSDraggingDestination)
+DEFINE_EMPTY_PROTOCOL(ICCameraDeviceDownloadDelegate)
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#undef DEFINE_EMPTY_PROTOCOL
+
+#endif  // BASE_MAC_COCOA_PROTOCOLS_H_
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
new file mode 100644
index 0000000..353ed7c
--- /dev/null
+++ b/base/mac/foundation_util.h
@@ -0,0 +1,389 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_FOUNDATION_UTIL_H_
+#define BASE_MAC_FOUNDATION_UTIL_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+@class NSFont;
+@class UIFont;
+#else  // __OBJC__
+#include <CoreFoundation/CoreFoundation.h>
+class NSBundle;
+class NSFont;
+class NSString;
+class UIFont;
+#endif  // __OBJC__
+
+#if defined(OS_IOS)
+#include <CoreText/CoreText.h>
+#else
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+// Adapted from NSObjCRuntime.h NS_ENUM definition (used in Foundation starting
+// with the OS X 10.8 SDK and the iOS 6.0 SDK).
+#if __has_extension(cxx_strong_enums) && \
+    (defined(OS_IOS) || (defined(MAC_OS_X_VERSION_10_8) && \
+                         MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8))
+#define CR_FORWARD_ENUM(_type, _name) enum _name : _type _name
+#else
+#define CR_FORWARD_ENUM(_type, _name) _type _name
+#endif
+
+// Adapted from NSPathUtilities.h and NSObjCRuntime.h.
+#if __LP64__ || NS_BUILD_32_LIKE_64
+typedef CR_FORWARD_ENUM(unsigned long, NSSearchPathDirectory);
+typedef unsigned long NSSearchPathDomainMask;
+#else
+typedef CR_FORWARD_ENUM(unsigned int, NSSearchPathDirectory);
+typedef unsigned int NSSearchPathDomainMask;
+#endif
+
+typedef struct OpaqueSecTrustRef* SecACLRef;
+typedef struct OpaqueSecTrustedApplicationRef* SecTrustedApplicationRef;
+
+namespace base {
+
+class FilePath;
+
+namespace mac {
+
+// Returns true if the application is running from a bundle
+BASE_EXPORT bool AmIBundled();
+BASE_EXPORT void SetOverrideAmIBundled(bool value);
+
+#if defined(UNIT_TEST)
+// This is required because instantiating some tests requires checking the
+// directory structure, which sets the AmIBundled cache state. Individual tests
+// may or may not be bundled, and this would trip them up if the cache weren't
+// cleared. This should not be called from individual tests, just from test
+// instantiation code that gets a path from PathService.
+BASE_EXPORT void ClearAmIBundledCache();
+#endif
+
+// Returns true if this process is marked as a "Background only process".
+BASE_EXPORT bool IsBackgroundOnlyProcess();
+
+// Returns the path to a resource within the framework bundle.
+BASE_EXPORT FilePath PathForFrameworkBundleResource(CFStringRef resourceName);
+
+// Returns the creator code associated with the CFBundleRef at bundle.
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle);
+
+// Returns the creator code associated with this application, by calling
+// CreatorCodeForCFBundleRef for the application's main bundle.  If this
+// information cannot be determined, returns kUnknownType ('????').  This
+// does not respect the override app bundle because it's based on CFBundle
+// instead of NSBundle, and because callers probably don't want the override
+// app bundle's creator code anyway.
+BASE_EXPORT OSType CreatorCodeForApplication();
+
+// Searches for directories for the given key in only the given |domain_mask|.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true.  Otherwise, returns false.
+BASE_EXPORT bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+                                        NSSearchPathDomainMask domain_mask,
+                                        FilePath* result);
+
+// Searches for directories for the given key in only the local domain.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true.  Otherwise, returns false.
+BASE_EXPORT bool GetLocalDirectory(NSSearchPathDirectory directory,
+                                   FilePath* result);
+
+// Searches for directories for the given key in only the user domain.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true.  Otherwise, returns false.
+BASE_EXPORT bool GetUserDirectory(NSSearchPathDirectory directory,
+                                  FilePath* result);
+
+// Returns the ~/Library directory.
+BASE_EXPORT FilePath GetUserLibraryPath();
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+//   |exec_name| - path to the binary
+//   returns - path to the application bundle, or empty on error
+BASE_EXPORT FilePath GetAppBundlePath(const FilePath& exec_name);
+
+#define TYPE_NAME_FOR_CF_TYPE_DECL(TypeCF) \
+BASE_EXPORT std::string TypeNameForCFType(TypeCF##Ref);
+
+TYPE_NAME_FOR_CF_TYPE_DECL(CFArray);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFBag);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFBoolean);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFData);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFDate);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFDictionary);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFNull);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFNumber);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFSet);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFString);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFURL);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFUUID);
+
+TYPE_NAME_FOR_CF_TYPE_DECL(CGColor);
+
+TYPE_NAME_FOR_CF_TYPE_DECL(CTFont);
+TYPE_NAME_FOR_CF_TYPE_DECL(CTRun);
+
+#undef TYPE_NAME_FOR_CF_TYPE_DECL
+
+// Retain/release calls for memory management in C++.
+BASE_EXPORT void NSObjectRetain(void* obj);
+BASE_EXPORT void NSObjectRelease(void* obj);
+
+// CFTypeRefToNSObjectAutorelease transfers ownership of a Core Foundation
+// object (one derived from CFTypeRef) to the Foundation memory management
+// system.  In a traditional managed-memory environment, cf_object is
+// autoreleased and returned as an NSObject.  In a garbage-collected
+// environment, cf_object is marked as eligible for garbage collection.
+//
+// This function should only be used to convert a concrete CFTypeRef type to
+// its equivalent "toll-free bridged" NSObject subclass, for example,
+// converting a CFStringRef to NSString.
+//
+// By calling this function, callers relinquish any ownership claim to
+// cf_object.  In a managed-memory environment, the object's ownership will be
+// managed by the innermost NSAutoreleasePool, so after this function returns,
+// callers should not assume that cf_object is valid any longer than the
+// returned NSObject.
+//
+// Returns an id, typed here for C++'s sake as a void*.
+BASE_EXPORT void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object);
+
+// Returns the base bundle ID, which can be set by SetBaseBundleID but
+// defaults to a reasonable string. This never returns NULL. BaseBundleID
+// returns a pointer to static storage that must not be freed.
+BASE_EXPORT const char* BaseBundleID();
+
+// Sets the base bundle ID to override the default. The implementation will
+// make its own copy of new_base_bundle_id.
+BASE_EXPORT void SetBaseBundleID(const char* new_base_bundle_id);
+
+}  // namespace mac
+}  // namespace base
+
+#if !defined(__OBJC__)
+#define OBJC_CPP_CLASS_DECL(x) class x;
+#else  // __OBJC__
+#define OBJC_CPP_CLASS_DECL(x)
+#endif  // __OBJC__
+
+// Convert toll-free bridged CFTypes to NSTypes and vice-versa. This does not
+// autorelease |cf_val|. This is useful for the case where there is a CFType in
+// a call that expects an NSType and the compiler is complaining about const
+// casting problems.
+// The calls are used like this:
+// NSString *foo = CFToNSCast(CFSTR("Hello"));
+// CFStringRef foo2 = NSToCFCast(@"Hello");
+// The macro magic below is to enforce safe casting. It could possibly have
+// been done using template function specialization, but template function
+// specialization doesn't always work intuitively,
+// (http://www.gotw.ca/publications/mill17.htm) so the trusty combination
+// of macros and function overloading is used instead.
+
+#define CF_TO_NS_CAST_DECL(TypeCF, TypeNS) \
+OBJC_CPP_CLASS_DECL(TypeNS) \
+\
+namespace base { \
+namespace mac { \
+BASE_EXPORT TypeNS* CFToNSCast(TypeCF##Ref cf_val); \
+BASE_EXPORT TypeCF##Ref NSToCFCast(TypeNS* ns_val); \
+} \
+}
+
+#define CF_TO_NS_MUTABLE_CAST_DECL(name) \
+CF_TO_NS_CAST_DECL(CF##name, NS##name) \
+OBJC_CPP_CLASS_DECL(NSMutable##name) \
+\
+namespace base { \
+namespace mac { \
+BASE_EXPORT NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val); \
+BASE_EXPORT CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val); \
+} \
+}
+
+// List of toll-free bridged types taken from:
+// http://www.cocoadev.com/index.pl?TollFreeBridged
+
+CF_TO_NS_MUTABLE_CAST_DECL(Array);
+CF_TO_NS_MUTABLE_CAST_DECL(AttributedString);
+CF_TO_NS_CAST_DECL(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DECL(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DECL(Data);
+CF_TO_NS_CAST_DECL(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DECL(Dictionary);
+CF_TO_NS_CAST_DECL(CFError, NSError);
+CF_TO_NS_CAST_DECL(CFLocale, NSLocale);
+CF_TO_NS_CAST_DECL(CFNumber, NSNumber);
+CF_TO_NS_CAST_DECL(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DECL(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DECL(Set);
+CF_TO_NS_CAST_DECL(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DECL(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DECL(String);
+CF_TO_NS_CAST_DECL(CFURL, NSURL);
+
+#if defined(OS_IOS)
+CF_TO_NS_CAST_DECL(CTFont, UIFont);
+#else
+CF_TO_NS_CAST_DECL(CTFont, NSFont);
+#endif
+
+#undef CF_TO_NS_CAST_DECL
+#undef CF_TO_NS_MUTABLE_CAST_DECL
+#undef OBJC_CPP_CLASS_DECL
+
+namespace base {
+namespace mac {
+
+// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more
+// specific CoreFoundation type. The compatibility of the passed
+// object is found by comparing its opaque type against the
+// requested type identifier. If the supplied object is not
+// compatible with the requested return type, CFCast<>() returns
+// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer
+// to either variant results in NULL being returned without
+// triggering any DCHECK.
+//
+// Example usage:
+// CFNumberRef some_number = base::mac::CFCast<CFNumberRef>(
+//     CFArrayGetValueAtIndex(array, index));
+//
+// CFTypeRef hello = CFSTR("hello world");
+// CFStringRef some_string = base::mac::CFCastStrict<CFStringRef>(hello);
+
+template<typename T>
+T CFCast(const CFTypeRef& cf_val);
+
+template<typename T>
+T CFCastStrict(const CFTypeRef& cf_val);
+
+#define CF_CAST_DECL(TypeCF) \
+template<> BASE_EXPORT TypeCF##Ref \
+CFCast<TypeCF##Ref>(const CFTypeRef& cf_val);\
+\
+template<> BASE_EXPORT TypeCF##Ref \
+CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val);
+
+CF_CAST_DECL(CFArray);
+CF_CAST_DECL(CFBag);
+CF_CAST_DECL(CFBoolean);
+CF_CAST_DECL(CFData);
+CF_CAST_DECL(CFDate);
+CF_CAST_DECL(CFDictionary);
+CF_CAST_DECL(CFNull);
+CF_CAST_DECL(CFNumber);
+CF_CAST_DECL(CFSet);
+CF_CAST_DECL(CFString);
+CF_CAST_DECL(CFURL);
+CF_CAST_DECL(CFUUID);
+
+CF_CAST_DECL(CGColor);
+
+CF_CAST_DECL(CTFont);
+CF_CAST_DECL(CTFontDescriptor);
+CF_CAST_DECL(CTRun);
+
+CF_CAST_DECL(SecACL);
+CF_CAST_DECL(SecTrustedApplication);
+
+#undef CF_CAST_DECL
+
+#if defined(__OBJC__)
+
+// ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more
+// specific (NSObject-derived) type. The compatibility of the passed
+// object is found by checking if it's a kind of the requested type
+// identifier. If the supplied object is not compatible with the
+// requested return type, ObjCCast<>() returns nil and
+// ObjCCastStrict<>() will DCHECK. Providing a nil pointer to either
+// variant results in nil being returned without triggering any DCHECK.
+//
+// The strict variant is useful when retrieving a value from a
+// collection which only has values of a specific type, e.g. an
+// NSArray of NSStrings. The non-strict variant is useful when
+// retrieving values from data that you can't fully control. For
+// example, a plist read from disk may be beyond your exclusive
+// control, so you'd only want to check that the values you retrieve
+// from it are of the expected types, but not crash if they're not.
+//
+// Example usage:
+// NSString* version = base::mac::ObjCCast<NSString>(
+//     [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+//
+// NSString* str = base::mac::ObjCCastStrict<NSString>(
+//     [ns_arr_of_ns_strs objectAtIndex:0]);
+template<typename T>
+T* ObjCCast(id objc_val) {
+  if ([objc_val isKindOfClass:[T class]]) {
+    return reinterpret_cast<T*>(objc_val);
+  }
+  return nil;
+}
+
+template<typename T>
+T* ObjCCastStrict(id objc_val) {
+  T* rv = ObjCCast<T>(objc_val);
+  DCHECK(objc_val == nil || rv);
+  return rv;
+}
+
+#endif  // defined(__OBJC__)
+
+// Helper function for GetValueFromDictionary to create the error message
+// that appears when a type mismatch is encountered.
+BASE_EXPORT std::string GetValueFromDictionaryErrorMessage(
+    CFStringRef key, const std::string& expected_type, CFTypeRef value);
+
+// Utility function to pull out a value from a dictionary, check its type, and
+// return it. Returns NULL if the key is not present or of the wrong type.
+template<typename T>
+T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) {
+  CFTypeRef value = CFDictionaryGetValue(dict, key);
+  T value_specific = CFCast<T>(value);
+
+  if (value && !value_specific) {
+    std::string expected_type = TypeNameForCFType(value_specific);
+    DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key,
+                                                        expected_type,
+                                                        value);
+  }
+
+  return value_specific;
+}
+
+// Converts |path| to an autoreleased NSString. Returns nil if |path| is empty.
+BASE_EXPORT NSString* FilePathToNSString(const FilePath& path);
+
+// Converts |str| to a FilePath. Returns an empty path if |str| is nil.
+BASE_EXPORT FilePath NSStringToFilePath(NSString* str);
+
+}  // namespace mac
+}  // namespace base
+
+// Stream operations for CFTypes. They can be used with NSTypes as well
+// by using the NSToCFCast methods above.
+// e.g. LOG(INFO) << base::mac::NSToCFCast(@"foo");
+// Operator << can not be overloaded for ObjectiveC types as the compiler
+// can not distinguish between overloads for id with overloads for void*.
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                            const CFErrorRef err);
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                            const CFStringRef str);
+
+#endif  // BASE_MAC_FOUNDATION_UTIL_H_
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
new file mode 100644
index 0000000..27d6e7c
--- /dev/null
+++ b/base/mac/foundation_util.mm
@@ -0,0 +1,455 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/foundation_util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/mac_logging.h"
+#include "base/strings/sys_string_conversions.h"
+
+#if !defined(OS_IOS)
+extern "C" {
+CFTypeID SecACLGetTypeID();
+CFTypeID SecTrustedApplicationGetTypeID();
+Boolean _CFIsObjC(CFTypeID typeID, CFTypeRef obj);
+}  // extern "C"
+#endif
+
+namespace base {
+namespace mac {
+
+namespace {
+
+bool g_cached_am_i_bundled_called = false;
+bool g_cached_am_i_bundled_value = false;
+bool g_override_am_i_bundled = false;
+bool g_override_am_i_bundled_value = false;
+
+bool UncachedAmIBundled() {
+#if defined(OS_IOS)
+  // All apps are bundled on iOS.
+  return true;
+#else
+  if (g_override_am_i_bundled)
+    return g_override_am_i_bundled_value;
+
+  // Yes, this is cheap.
+  return [[base::mac::OuterBundle() bundlePath] hasSuffix:@".app"];
+#endif
+}
+
+}  // namespace
+
+bool AmIBundled() {
+  // If the return value is not cached, this function will return different
+  // values depending on when it's called. This confuses some client code, see
+  // http://crbug.com/63183 .
+  if (!g_cached_am_i_bundled_called) {
+    g_cached_am_i_bundled_called = true;
+    g_cached_am_i_bundled_value = UncachedAmIBundled();
+  }
+  DCHECK_EQ(g_cached_am_i_bundled_value, UncachedAmIBundled())
+      << "The return value of AmIBundled() changed. This will confuse tests. "
+      << "Call SetAmIBundled() override manually if your test binary "
+      << "delay-loads the framework.";
+  return g_cached_am_i_bundled_value;
+}
+
+void SetOverrideAmIBundled(bool value) {
+#if defined(OS_IOS)
+  // It doesn't make sense not to be bundled on iOS.
+  if (!value)
+    NOTREACHED();
+#endif
+  g_override_am_i_bundled = true;
+  g_override_am_i_bundled_value = value;
+}
+
+BASE_EXPORT void ClearAmIBundledCache() {
+  g_cached_am_i_bundled_called = false;
+}
+
+bool IsBackgroundOnlyProcess() {
+  // This function really does want to examine NSBundle's idea of the main
+  // bundle dictionary.  It needs to look at the actual running .app's
+  // Info.plist to access its LSUIElement property.
+  NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
+  return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
+}
+
+FilePath PathForFrameworkBundleResource(CFStringRef resourceName) {
+  NSBundle* bundle = base::mac::FrameworkBundle();
+  NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName
+                                            ofType:nil];
+  return NSStringToFilePath(resourcePath);
+}
+
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
+  OSType creator = kUnknownType;
+  CFBundleGetPackageInfo(bundle, NULL, &creator);
+  return creator;
+}
+
+OSType CreatorCodeForApplication() {
+  CFBundleRef bundle = CFBundleGetMainBundle();
+  if (!bundle)
+    return kUnknownType;
+
+  return CreatorCodeForCFBundleRef(bundle);
+}
+
+bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+                            NSSearchPathDomainMask domain_mask,
+                            FilePath* result) {
+  DCHECK(result);
+  NSArray* dirs =
+      NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
+  if ([dirs count] < 1) {
+    return false;
+  }
+  *result = NSStringToFilePath([dirs objectAtIndex:0]);
+  return true;
+}
+
+bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
+  return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
+}
+
+bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
+  return GetSearchPathDirectory(directory, NSUserDomainMask, result);
+}
+
+FilePath GetUserLibraryPath() {
+  FilePath user_library_path;
+  if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
+    DLOG(WARNING) << "Could not get user library path";
+  }
+  return user_library_path;
+}
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+//   |exec_name| - path to the binary
+//   returns - path to the application bundle, or empty on error
+FilePath GetAppBundlePath(const FilePath& exec_name) {
+  const char kExt[] = ".app";
+  const size_t kExtLength = arraysize(kExt) - 1;
+
+  // Split the path into components.
+  std::vector<std::string> components;
+  exec_name.GetComponents(&components);
+
+  // It's an error if we don't get any components.
+  if (!components.size())
+    return FilePath();
+
+  // Don't prepend '/' to the first component.
+  std::vector<std::string>::const_iterator it = components.begin();
+  std::string bundle_name = *it;
+  DCHECK_GT(it->length(), 0U);
+  // If the first component ends in ".app", we're already done.
+  if (it->length() > kExtLength &&
+      !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+    return FilePath(bundle_name);
+
+  // The first component may be "/" or "//", etc. Only append '/' if it doesn't
+  // already end in '/'.
+  if (bundle_name[bundle_name.length() - 1] != '/')
+    bundle_name += '/';
+
+  // Go through the remaining components.
+  for (++it; it != components.end(); ++it) {
+    DCHECK_GT(it->length(), 0U);
+
+    bundle_name += *it;
+
+    // If the current component ends in ".app", we're done.
+    if (it->length() > kExtLength &&
+        !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+      return FilePath(bundle_name);
+
+    // Separate this component from the next one.
+    bundle_name += '/';
+  }
+
+  return FilePath();
+}
+
+#define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \
+std::string TypeNameForCFType(TypeCF##Ref) { \
+  return #TypeCF; \
+}
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFData);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFString);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFURL);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID);
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CGColor);
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CTFont);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun);
+
+#undef TYPE_NAME_FOR_CF_TYPE_DEFN
+
+void NSObjectRetain(void* obj) {
+  id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+  [nsobj retain];
+}
+
+void NSObjectRelease(void* obj) {
+  id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+  [nsobj release];
+}
+
+void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object) {
+  // When GC is on, NSMakeCollectable marks cf_object for GC and autorelease
+  // is a no-op.
+  //
+  // In the traditional GC-less environment, NSMakeCollectable is a no-op,
+  // and cf_object is autoreleased, balancing out the caller's ownership claim.
+  //
+  // NSMakeCollectable returns nil when used on a NULL object.
+  return [NSMakeCollectable(cf_object) autorelease];
+}
+
+static const char* base_bundle_id;
+
+const char* BaseBundleID() {
+  if (base_bundle_id) {
+    return base_bundle_id;
+  }
+
+#if defined(GOOGLE_CHROME_BUILD)
+  return "com.google.Chrome";
+#else
+  return "org.chromium.Chromium";
+#endif
+}
+
+void SetBaseBundleID(const char* new_base_bundle_id) {
+  if (new_base_bundle_id != base_bundle_id) {
+    free((void*)base_bundle_id);
+    base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL;
+  }
+}
+
+// Definitions for the corresponding CF_TO_NS_CAST_DECL macros in
+// foundation_util.h.
+#define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \
+\
+TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \
+  DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+  TypeNS* ns_val = \
+      const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
+  return ns_val; \
+} \
+\
+TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
+  TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
+  DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+  return cf_val; \
+}
+
+#define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
+CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
+\
+NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \
+  DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+  NSMutable##name* ns_val = reinterpret_cast<NSMutable##name*>(cf_val); \
+  return ns_val; \
+} \
+\
+CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
+  CFMutable##name##Ref cf_val = \
+      reinterpret_cast<CFMutable##name##Ref>(ns_val); \
+  DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+  return cf_val; \
+}
+
+CF_TO_NS_MUTABLE_CAST_DEFN(Array);
+CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
+CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DEFN(Data);
+CF_TO_NS_CAST_DEFN(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary);
+CF_TO_NS_CAST_DEFN(CFError, NSError);
+CF_TO_NS_CAST_DEFN(CFLocale, NSLocale);
+CF_TO_NS_CAST_DEFN(CFNumber, NSNumber);
+CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DEFN(Set);
+CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DEFN(String);
+CF_TO_NS_CAST_DEFN(CFURL, NSURL);
+
+#if defined(OS_IOS)
+CF_TO_NS_CAST_DEFN(CTFont, UIFont);
+#else
+// The NSFont/CTFont toll-free bridging is broken when it comes to type
+// checking, so do some special-casing.
+// http://www.openradar.me/15341349 rdar://15341349
+NSFont* CFToNSCast(CTFontRef cf_val) {
+  NSFont* ns_val =
+      const_cast<NSFont*>(reinterpret_cast<const NSFont*>(cf_val));
+  DCHECK(!cf_val ||
+         CTFontGetTypeID() == CFGetTypeID(cf_val) ||
+         (_CFIsObjC(CTFontGetTypeID(), cf_val) &&
+          [ns_val isKindOfClass:NSClassFromString(@"NSFont")]));
+  return ns_val;
+}
+
+CTFontRef NSToCFCast(NSFont* ns_val) {
+  CTFontRef cf_val = reinterpret_cast<CTFontRef>(ns_val);
+  DCHECK(!cf_val ||
+         CTFontGetTypeID() == CFGetTypeID(cf_val) ||
+         [ns_val isKindOfClass:NSClassFromString(@"NSFont")]);
+  return cf_val;
+}
+#endif
+
+#undef CF_TO_NS_CAST_DEFN
+#undef CF_TO_NS_MUTABLE_CAST_DEFN
+
+#define CF_CAST_DEFN(TypeCF) \
+template<> TypeCF##Ref \
+CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) { \
+  if (cf_val == NULL) { \
+    return NULL; \
+  } \
+  if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \
+    return (TypeCF##Ref)(cf_val); \
+  } \
+  return NULL; \
+} \
+\
+template<> TypeCF##Ref \
+CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
+  TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val); \
+  DCHECK(cf_val == NULL || rv); \
+  return rv; \
+}
+
+CF_CAST_DEFN(CFArray);
+CF_CAST_DEFN(CFBag);
+CF_CAST_DEFN(CFBoolean);
+CF_CAST_DEFN(CFData);
+CF_CAST_DEFN(CFDate);
+CF_CAST_DEFN(CFDictionary);
+CF_CAST_DEFN(CFNull);
+CF_CAST_DEFN(CFNumber);
+CF_CAST_DEFN(CFSet);
+CF_CAST_DEFN(CFString);
+CF_CAST_DEFN(CFURL);
+CF_CAST_DEFN(CFUUID);
+
+CF_CAST_DEFN(CGColor);
+
+CF_CAST_DEFN(CTFontDescriptor);
+CF_CAST_DEFN(CTRun);
+
+#if defined(OS_IOS)
+CF_CAST_DEFN(CTFont);
+#else
+// The NSFont/CTFont toll-free bridging is broken when it comes to type
+// checking, so do some special-casing.
+// http://www.openradar.me/15341349 rdar://15341349
+template<> CTFontRef
+CFCast<CTFontRef>(const CFTypeRef& cf_val) {
+  if (cf_val == NULL) {
+    return NULL;
+  }
+  if (CFGetTypeID(cf_val) == CTFontGetTypeID()) {
+    return (CTFontRef)(cf_val);
+  }
+
+  if (!_CFIsObjC(CTFontGetTypeID(), cf_val))
+    return NULL;
+
+  id<NSObject> ns_val = reinterpret_cast<id>(const_cast<void*>(cf_val));
+  if ([ns_val isKindOfClass:NSClassFromString(@"NSFont")]) {
+    return (CTFontRef)(cf_val);
+  }
+  return NULL;
+}
+
+template<> CTFontRef
+CFCastStrict<CTFontRef>(const CFTypeRef& cf_val) {
+  CTFontRef rv = CFCast<CTFontRef>(cf_val);
+  DCHECK(cf_val == NULL || rv);
+  return rv;
+}
+#endif
+
+#if !defined(OS_IOS)
+CF_CAST_DEFN(SecACL);
+CF_CAST_DEFN(SecTrustedApplication);
+#endif
+
+#undef CF_CAST_DEFN
+
+std::string GetValueFromDictionaryErrorMessage(
+    CFStringRef key, const std::string& expected_type, CFTypeRef value) {
+  ScopedCFTypeRef<CFStringRef> actual_type_ref(
+      CFCopyTypeIDDescription(CFGetTypeID(value)));
+  return "Expected value for key " +
+      base::SysCFStringRefToUTF8(key) +
+      " to be " +
+      expected_type +
+      " but it was " +
+      base::SysCFStringRefToUTF8(actual_type_ref) +
+      " instead";
+}
+
+NSString* FilePathToNSString(const FilePath& path) {
+  if (path.empty())
+    return nil;
+  return [NSString stringWithUTF8String:path.value().c_str()];
+}
+
+FilePath NSStringToFilePath(NSString* str) {
+  if (![str length])
+    return FilePath();
+  return FilePath([str fileSystemRepresentation]);
+}
+
+}  // namespace mac
+}  // namespace base
+
+std::ostream& operator<<(std::ostream& o, const CFStringRef string) {
+  return o << base::SysCFStringRefToUTF8(string);
+}
+
+std::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
+  base::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
+  base::ScopedCFTypeRef<CFDictionaryRef> user_info(CFErrorCopyUserInfo(err));
+  CFStringRef errorDesc = NULL;
+  if (user_info.get()) {
+    errorDesc = reinterpret_cast<CFStringRef>(
+        CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
+  }
+  o << "Code: " << CFErrorGetCode(err)
+    << " Domain: " << CFErrorGetDomain(err)
+    << " Desc: " << desc.get();
+  if(errorDesc) {
+    o << "(" << errorDesc << ")";
+  }
+  return o;
+}
diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm
new file mode 100644
index 0000000..e60a0f6
--- /dev/null
+++ b/base/mac/foundation_util_unittest.mm
@@ -0,0 +1,391 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/foundation_util.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/format_macros.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+namespace base {
+namespace mac {
+
+TEST(FoundationUtilTest, CFCast) {
+  // Build out the CF types to be tested as empty containers.
+  ScopedCFTypeRef<CFTypeRef> test_array(
+      CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_array_mutable(
+      CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_bag(
+      CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_bag_mutable(
+      CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks));
+  CFTypeRef test_bool = kCFBooleanTrue;
+  ScopedCFTypeRef<CFTypeRef> test_data(
+      CFDataCreate(NULL, NULL, 0));
+  ScopedCFTypeRef<CFTypeRef> test_data_mutable(
+      CFDataCreateMutable(NULL, 0));
+  ScopedCFTypeRef<CFTypeRef> test_date(
+      CFDateCreate(NULL, 0));
+  ScopedCFTypeRef<CFTypeRef> test_dict(
+      CFDictionaryCreate(NULL, NULL, NULL, 0,
+                         &kCFCopyStringDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_dict_mutable(
+      CFDictionaryCreateMutable(NULL, 0,
+                                &kCFCopyStringDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  int int_val = 256;
+  ScopedCFTypeRef<CFTypeRef> test_number(
+      CFNumberCreate(NULL, kCFNumberIntType, &int_val));
+  CFTypeRef test_null = kCFNull;
+  ScopedCFTypeRef<CFTypeRef> test_set(
+      CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_set_mutable(
+      CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_str(
+      CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII, false));
+  CFTypeRef test_str_const = CFSTR("hello");
+  ScopedCFTypeRef<CFTypeRef> test_str_mutable(CFStringCreateMutable(NULL, 0));
+
+  // Make sure the allocations of CF types are good.
+  EXPECT_TRUE(test_array);
+  EXPECT_TRUE(test_array_mutable);
+  EXPECT_TRUE(test_bag);
+  EXPECT_TRUE(test_bag_mutable);
+  EXPECT_TRUE(test_bool);
+  EXPECT_TRUE(test_data);
+  EXPECT_TRUE(test_data_mutable);
+  EXPECT_TRUE(test_date);
+  EXPECT_TRUE(test_dict);
+  EXPECT_TRUE(test_dict_mutable);
+  EXPECT_TRUE(test_number);
+  EXPECT_TRUE(test_null);
+  EXPECT_TRUE(test_set);
+  EXPECT_TRUE(test_set_mutable);
+  EXPECT_TRUE(test_str);
+  EXPECT_TRUE(test_str_const);
+  EXPECT_TRUE(test_str_mutable);
+
+  // Casting the CFTypeRef objects correctly provides the same pointer.
+  EXPECT_EQ(test_array, CFCast<CFArrayRef>(test_array));
+  EXPECT_EQ(test_array_mutable, CFCast<CFArrayRef>(test_array_mutable));
+  EXPECT_EQ(test_bag, CFCast<CFBagRef>(test_bag));
+  EXPECT_EQ(test_bag_mutable, CFCast<CFBagRef>(test_bag_mutable));
+  EXPECT_EQ(test_bool, CFCast<CFBooleanRef>(test_bool));
+  EXPECT_EQ(test_data, CFCast<CFDataRef>(test_data));
+  EXPECT_EQ(test_data_mutable, CFCast<CFDataRef>(test_data_mutable));
+  EXPECT_EQ(test_date, CFCast<CFDateRef>(test_date));
+  EXPECT_EQ(test_dict, CFCast<CFDictionaryRef>(test_dict));
+  EXPECT_EQ(test_dict_mutable, CFCast<CFDictionaryRef>(test_dict_mutable));
+  EXPECT_EQ(test_number, CFCast<CFNumberRef>(test_number));
+  EXPECT_EQ(test_null, CFCast<CFNullRef>(test_null));
+  EXPECT_EQ(test_set, CFCast<CFSetRef>(test_set));
+  EXPECT_EQ(test_set_mutable, CFCast<CFSetRef>(test_set_mutable));
+  EXPECT_EQ(test_str, CFCast<CFStringRef>(test_str));
+  EXPECT_EQ(test_str_const, CFCast<CFStringRef>(test_str_const));
+  EXPECT_EQ(test_str_mutable, CFCast<CFStringRef>(test_str_mutable));
+
+  // When given an incorrect CF cast, provide NULL.
+  EXPECT_FALSE(CFCast<CFStringRef>(test_array));
+  EXPECT_FALSE(CFCast<CFStringRef>(test_array_mutable));
+  EXPECT_FALSE(CFCast<CFStringRef>(test_bag));
+  EXPECT_FALSE(CFCast<CFSetRef>(test_bag_mutable));
+  EXPECT_FALSE(CFCast<CFSetRef>(test_bool));
+  EXPECT_FALSE(CFCast<CFNullRef>(test_data));
+  EXPECT_FALSE(CFCast<CFDictionaryRef>(test_data_mutable));
+  EXPECT_FALSE(CFCast<CFDictionaryRef>(test_date));
+  EXPECT_FALSE(CFCast<CFNumberRef>(test_dict));
+  EXPECT_FALSE(CFCast<CFDateRef>(test_dict_mutable));
+  EXPECT_FALSE(CFCast<CFDataRef>(test_number));
+  EXPECT_FALSE(CFCast<CFDataRef>(test_null));
+  EXPECT_FALSE(CFCast<CFBooleanRef>(test_set));
+  EXPECT_FALSE(CFCast<CFBagRef>(test_set_mutable));
+  EXPECT_FALSE(CFCast<CFBagRef>(test_str));
+  EXPECT_FALSE(CFCast<CFArrayRef>(test_str_const));
+  EXPECT_FALSE(CFCast<CFArrayRef>(test_str_mutable));
+
+  // Giving a NULL provides a NULL.
+  EXPECT_FALSE(CFCast<CFArrayRef>(NULL));
+  EXPECT_FALSE(CFCast<CFBagRef>(NULL));
+  EXPECT_FALSE(CFCast<CFBooleanRef>(NULL));
+  EXPECT_FALSE(CFCast<CFDataRef>(NULL));
+  EXPECT_FALSE(CFCast<CFDateRef>(NULL));
+  EXPECT_FALSE(CFCast<CFDictionaryRef>(NULL));
+  EXPECT_FALSE(CFCast<CFNullRef>(NULL));
+  EXPECT_FALSE(CFCast<CFNumberRef>(NULL));
+  EXPECT_FALSE(CFCast<CFSetRef>(NULL));
+  EXPECT_FALSE(CFCast<CFStringRef>(NULL));
+
+  // CFCastStrict: correct cast results in correct pointer being returned.
+  EXPECT_EQ(test_array, CFCastStrict<CFArrayRef>(test_array));
+  EXPECT_EQ(test_array_mutable, CFCastStrict<CFArrayRef>(test_array_mutable));
+  EXPECT_EQ(test_bag, CFCastStrict<CFBagRef>(test_bag));
+  EXPECT_EQ(test_bag_mutable, CFCastStrict<CFBagRef>(test_bag_mutable));
+  EXPECT_EQ(test_bool, CFCastStrict<CFBooleanRef>(test_bool));
+  EXPECT_EQ(test_data, CFCastStrict<CFDataRef>(test_data));
+  EXPECT_EQ(test_data_mutable, CFCastStrict<CFDataRef>(test_data_mutable));
+  EXPECT_EQ(test_date, CFCastStrict<CFDateRef>(test_date));
+  EXPECT_EQ(test_dict, CFCastStrict<CFDictionaryRef>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            CFCastStrict<CFDictionaryRef>(test_dict_mutable));
+  EXPECT_EQ(test_number, CFCastStrict<CFNumberRef>(test_number));
+  EXPECT_EQ(test_null, CFCastStrict<CFNullRef>(test_null));
+  EXPECT_EQ(test_set, CFCastStrict<CFSetRef>(test_set));
+  EXPECT_EQ(test_set_mutable, CFCastStrict<CFSetRef>(test_set_mutable));
+  EXPECT_EQ(test_str, CFCastStrict<CFStringRef>(test_str));
+  EXPECT_EQ(test_str_const, CFCastStrict<CFStringRef>(test_str_const));
+  EXPECT_EQ(test_str_mutable, CFCastStrict<CFStringRef>(test_str_mutable));
+
+  // CFCastStrict: Giving a NULL provides a NULL.
+  EXPECT_FALSE(CFCastStrict<CFArrayRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFBagRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFBooleanRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFDataRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFDateRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFDictionaryRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFNullRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFNumberRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFSetRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFStringRef>(NULL));
+}
+
+TEST(FoundationUtilTest, ObjCCast) {
+  ScopedNSAutoreleasePool pool;
+
+  id test_array = [NSArray array];
+  id test_array_mutable = [NSMutableArray array];
+  id test_data = [NSData data];
+  id test_data_mutable = [NSMutableData dataWithCapacity:10];
+  id test_date = [NSDate date];
+  id test_dict =
+      [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42]
+                                  forKey:@"meaning"];
+  id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10];
+  id test_number = [NSNumber numberWithInt:42];
+  id test_null = [NSNull null];
+  id test_set = [NSSet setWithObject:@"string object"];
+  id test_set_mutable = [NSMutableSet setWithCapacity:10];
+  id test_str = [NSString string];
+  id test_str_const = @"bonjour";
+  id test_str_mutable = [NSMutableString stringWithCapacity:10];
+
+  // Make sure the allocations of NS types are good.
+  EXPECT_TRUE(test_array);
+  EXPECT_TRUE(test_array_mutable);
+  EXPECT_TRUE(test_data);
+  EXPECT_TRUE(test_data_mutable);
+  EXPECT_TRUE(test_date);
+  EXPECT_TRUE(test_dict);
+  EXPECT_TRUE(test_dict_mutable);
+  EXPECT_TRUE(test_number);
+  EXPECT_TRUE(test_null);
+  EXPECT_TRUE(test_set);
+  EXPECT_TRUE(test_set_mutable);
+  EXPECT_TRUE(test_str);
+  EXPECT_TRUE(test_str_const);
+  EXPECT_TRUE(test_str_mutable);
+
+  // Casting the id correctly provides the same pointer.
+  EXPECT_EQ(test_array, ObjCCast<NSArray>(test_array));
+  EXPECT_EQ(test_array_mutable, ObjCCast<NSArray>(test_array_mutable));
+  EXPECT_EQ(test_data, ObjCCast<NSData>(test_data));
+  EXPECT_EQ(test_data_mutable, ObjCCast<NSData>(test_data_mutable));
+  EXPECT_EQ(test_date, ObjCCast<NSDate>(test_date));
+  EXPECT_EQ(test_dict, ObjCCast<NSDictionary>(test_dict));
+  EXPECT_EQ(test_dict_mutable, ObjCCast<NSDictionary>(test_dict_mutable));
+  EXPECT_EQ(test_number, ObjCCast<NSNumber>(test_number));
+  EXPECT_EQ(test_null, ObjCCast<NSNull>(test_null));
+  EXPECT_EQ(test_set, ObjCCast<NSSet>(test_set));
+  EXPECT_EQ(test_set_mutable, ObjCCast<NSSet>(test_set_mutable));
+  EXPECT_EQ(test_str, ObjCCast<NSString>(test_str));
+  EXPECT_EQ(test_str_const, ObjCCast<NSString>(test_str_const));
+  EXPECT_EQ(test_str_mutable, ObjCCast<NSString>(test_str_mutable));
+
+  // When given an incorrect ObjC cast, provide nil.
+  EXPECT_FALSE(ObjCCast<NSString>(test_array));
+  EXPECT_FALSE(ObjCCast<NSString>(test_array_mutable));
+  EXPECT_FALSE(ObjCCast<NSString>(test_data));
+  EXPECT_FALSE(ObjCCast<NSString>(test_data_mutable));
+  EXPECT_FALSE(ObjCCast<NSSet>(test_date));
+  EXPECT_FALSE(ObjCCast<NSSet>(test_dict));
+  EXPECT_FALSE(ObjCCast<NSNumber>(test_dict_mutable));
+  EXPECT_FALSE(ObjCCast<NSNull>(test_number));
+  EXPECT_FALSE(ObjCCast<NSDictionary>(test_null));
+  EXPECT_FALSE(ObjCCast<NSDictionary>(test_set));
+  EXPECT_FALSE(ObjCCast<NSDate>(test_set_mutable));
+  EXPECT_FALSE(ObjCCast<NSData>(test_str));
+  EXPECT_FALSE(ObjCCast<NSData>(test_str_const));
+  EXPECT_FALSE(ObjCCast<NSArray>(test_str_mutable));
+
+  // Giving a nil provides a nil.
+  EXPECT_FALSE(ObjCCast<NSArray>(nil));
+  EXPECT_FALSE(ObjCCast<NSData>(nil));
+  EXPECT_FALSE(ObjCCast<NSDate>(nil));
+  EXPECT_FALSE(ObjCCast<NSDictionary>(nil));
+  EXPECT_FALSE(ObjCCast<NSNull>(nil));
+  EXPECT_FALSE(ObjCCast<NSNumber>(nil));
+  EXPECT_FALSE(ObjCCast<NSSet>(nil));
+  EXPECT_FALSE(ObjCCast<NSString>(nil));
+
+  // ObjCCastStrict: correct cast results in correct pointer being returned.
+  EXPECT_EQ(test_array, ObjCCastStrict<NSArray>(test_array));
+  EXPECT_EQ(test_array_mutable,
+            ObjCCastStrict<NSArray>(test_array_mutable));
+  EXPECT_EQ(test_data, ObjCCastStrict<NSData>(test_data));
+  EXPECT_EQ(test_data_mutable,
+            ObjCCastStrict<NSData>(test_data_mutable));
+  EXPECT_EQ(test_date, ObjCCastStrict<NSDate>(test_date));
+  EXPECT_EQ(test_dict, ObjCCastStrict<NSDictionary>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            ObjCCastStrict<NSDictionary>(test_dict_mutable));
+  EXPECT_EQ(test_number, ObjCCastStrict<NSNumber>(test_number));
+  EXPECT_EQ(test_null, ObjCCastStrict<NSNull>(test_null));
+  EXPECT_EQ(test_set, ObjCCastStrict<NSSet>(test_set));
+  EXPECT_EQ(test_set_mutable,
+            ObjCCastStrict<NSSet>(test_set_mutable));
+  EXPECT_EQ(test_str, ObjCCastStrict<NSString>(test_str));
+  EXPECT_EQ(test_str_const,
+            ObjCCastStrict<NSString>(test_str_const));
+  EXPECT_EQ(test_str_mutable,
+            ObjCCastStrict<NSString>(test_str_mutable));
+
+  // ObjCCastStrict: Giving a nil provides a nil.
+  EXPECT_FALSE(ObjCCastStrict<NSArray>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSData>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSDate>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSDictionary>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSNull>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSNumber>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSSet>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSString>(nil));
+}
+
+TEST(FoundationUtilTest, GetValueFromDictionary) {
+  int one = 1, two = 2, three = 3;
+
+  ScopedCFTypeRef<CFNumberRef> cf_one(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one));
+  ScopedCFTypeRef<CFNumberRef> cf_two(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two));
+  ScopedCFTypeRef<CFNumberRef> cf_three(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three));
+
+  CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") };
+  CFNumberRef values[] = { cf_one, cf_two, cf_three };
+
+  COMPILE_ASSERT(arraysize(keys) == arraysize(values),
+                 keys_and_values_arraysizes_are_different);
+
+  ScopedCFTypeRef<CFDictionaryRef> test_dict(
+      CFDictionaryCreate(kCFAllocatorDefault,
+                         reinterpret_cast<const void**>(keys),
+                         reinterpret_cast<const void**>(values),
+                         arraysize(values),
+                         &kCFCopyStringDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+
+  // GetValueFromDictionary<>(_, _) should produce the correct
+  // expected output.
+  EXPECT_EQ(values[0],
+            GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("one")));
+  EXPECT_EQ(values[1],
+            GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("two")));
+  EXPECT_EQ(values[2],
+            GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("three")));
+
+  // Bad input should produce bad output.
+  EXPECT_FALSE(GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("four")));
+  EXPECT_FALSE(GetValueFromDictionary<CFStringRef>(test_dict, CFSTR("one")));
+}
+
+TEST(FoundationUtilTest, FilePathToNSString) {
+  EXPECT_NSEQ(nil, FilePathToNSString(FilePath()));
+  EXPECT_NSEQ(@"/a/b", FilePathToNSString(FilePath("/a/b")));
+}
+
+TEST(FoundationUtilTest, NSStringToFilePath) {
+  EXPECT_EQ(FilePath(), NSStringToFilePath(nil));
+  EXPECT_EQ(FilePath(), NSStringToFilePath(@""));
+  EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b"));
+}
+
+TEST(StringNumberConversionsTest, FormatNSInteger) {
+  // The PRI[dxu]NS macro assumes that NSInteger is a typedef to "int" on
+  // 32-bit architecture and a typedef to "long" on 64-bit architecture
+  // (respectively "unsigned int" and "unsigned long" for NSUInteger). Use
+  // pointer incompatibility to validate this at compilation.
+#if defined(ARCH_CPU_64_BITS)
+  typedef long FormatNSIntegerAsType;
+  typedef unsigned long FormatNSUIntegerAsType;
+#else
+  typedef int FormatNSIntegerAsType;
+  typedef unsigned int FormatNSUIntegerAsType;
+#endif  // defined(ARCH_CPU_64_BITS)
+
+  NSInteger some_nsinteger;
+  FormatNSIntegerAsType* pointer_to_some_nsinteger = &some_nsinteger;
+  ALLOW_UNUSED_LOCAL(pointer_to_some_nsinteger);
+
+  NSUInteger some_nsuinteger;
+  FormatNSUIntegerAsType* pointer_to_some_nsuinteger = &some_nsuinteger;
+  ALLOW_UNUSED_LOCAL(pointer_to_some_nsuinteger);
+
+  // Check that format specifier works correctly for NSInteger.
+  const struct {
+    NSInteger value;
+    const char* expected;
+    const char* expected_hex;
+  } nsinteger_cases[] = {
+#if !defined(ARCH_CPU_64_BITS)
+    {12345678, "12345678", "bc614e"},
+    {-12345678, "-12345678", "ff439eb2"},
+#else
+    {12345678, "12345678", "bc614e"},
+    {-12345678, "-12345678", "ffffffffff439eb2"},
+    {137451299150l, "137451299150", "2000bc614e"},
+    {-137451299150l, "-137451299150", "ffffffdfff439eb2"},
+#endif  // !defined(ARCH_CPU_64_BITS)
+  };
+
+  for (size_t i = 0; i < arraysize(nsinteger_cases); ++i) {
+    EXPECT_EQ(nsinteger_cases[i].expected,
+              StringPrintf("%" PRIdNS, nsinteger_cases[i].value));
+    EXPECT_EQ(nsinteger_cases[i].expected_hex,
+              StringPrintf("%" PRIxNS, nsinteger_cases[i].value));
+  }
+
+  // Check that format specifier works correctly for NSUInteger.
+  const struct {
+    NSUInteger value;
+    const char* expected;
+    const char* expected_hex;
+  } nsuinteger_cases[] = {
+#if !defined(ARCH_CPU_64_BITS)
+    {12345678u, "12345678", "bc614e"},
+    {4282621618u, "4282621618", "ff439eb2"},
+#else
+    {12345678u, "12345678", "bc614e"},
+    {4282621618u, "4282621618", "ff439eb2"},
+    {137451299150ul, "137451299150", "2000bc614e"},
+    {18446743936258252466ul, "18446743936258252466", "ffffffdfff439eb2"},
+#endif  // !defined(ARCH_CPU_64_BITS)
+  };
+
+  for (size_t i = 0; i < arraysize(nsuinteger_cases); ++i) {
+    EXPECT_EQ(nsuinteger_cases[i].expected,
+              StringPrintf("%" PRIuNS, nsuinteger_cases[i].value));
+    EXPECT_EQ(nsuinteger_cases[i].expected_hex,
+              StringPrintf("%" PRIxNS, nsuinteger_cases[i].value));
+  }
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launch_services_util.cc b/base/mac/launch_services_util.cc
new file mode 100644
index 0000000..4c3b417
--- /dev/null
+++ b/base/mac/launch_services_util.cc
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/launch_services_util.h"
+
+#include "base/logging.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+bool OpenApplicationWithPath(const base::FilePath& bundle_path,
+                             const CommandLine& command_line,
+                             LSLaunchFlags launch_flags,
+                             ProcessSerialNumber* out_psn) {
+  FSRef app_fsref;
+  if (!base::mac::FSRefFromPath(bundle_path.value(), &app_fsref)) {
+    LOG(ERROR) << "base::mac::FSRefFromPath failed for " << bundle_path.value();
+    return false;
+  }
+
+  std::vector<std::string> argv = command_line.argv();
+  int argc = argv.size();
+  base::ScopedCFTypeRef<CFMutableArrayRef> launch_args(
+      CFArrayCreateMutable(NULL, argc - 1, &kCFTypeArrayCallBacks));
+  if (!launch_args) {
+    LOG(ERROR) << "CFArrayCreateMutable failed, size was " << argc;
+    return false;
+  }
+
+  for (int i = 1; i < argc; ++i) {
+    const std::string& arg(argv[i]);
+
+    base::ScopedCFTypeRef<CFStringRef> arg_cf(base::SysUTF8ToCFStringRef(arg));
+    if (!arg_cf) {
+      LOG(ERROR) << "base::SysUTF8ToCFStringRef failed for " << arg;
+      return false;
+    }
+    CFArrayAppendValue(launch_args, arg_cf);
+  }
+
+  LSApplicationParameters ls_parameters = {
+    0,     // version
+    launch_flags,
+    &app_fsref,
+    NULL,  // asyncLaunchRefCon
+    NULL,  // environment
+    launch_args,
+    NULL   // initialEvent
+  };
+  // TODO(jeremya): this opens a new browser window if Chrome is already
+  // running without any windows open.
+  OSStatus status = LSOpenApplication(&ls_parameters, out_psn);
+  if (status != noErr) {
+    OSSTATUS_LOG(ERROR, status) << "LSOpenApplication";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launch_services_util.h b/base/mac/launch_services_util.h
new file mode 100644
index 0000000..0e64316
--- /dev/null
+++ b/base/mac/launch_services_util.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_LAUNCH_SERVICES_UTIL_H_
+#define BASE_MAC_LAUNCH_SERVICES_UTIL_H_
+
+#include <CoreServices/CoreServices.h>
+
+#include "base/base_export.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+
+struct ProcessSerialNumber;
+
+namespace base {
+namespace mac {
+
+// Launches the application bundle at |bundle_path|, passing argv[1..] from
+// |command_line| as command line arguments if the app isn't already running.
+// |launch_flags| are passed directly to LSApplicationParameters.
+// |out_psn|, if not NULL, will be set to the process serial number of the
+// application's main process if the app was successfully launched.
+// Returns true if the app was successfully launched.
+BASE_EXPORT bool OpenApplicationWithPath(const FilePath& bundle_path,
+                                         const CommandLine& command_line,
+                                         LSLaunchFlags launch_flags,
+                                         ProcessSerialNumber* out_psn);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LAUNCH_SERVICES_UTIL_H_
diff --git a/base/mac/launchd.cc b/base/mac/launchd.cc
new file mode 100644
index 0000000..1d384c9
--- /dev/null
+++ b/base/mac/launchd.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/launchd.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_launch_data.h"
+
+namespace base {
+namespace mac {
+
+// MessageForJob sends a single message to launchd with a simple dictionary
+// mapping |operation| to |job_label|, and returns the result of calling
+// launch_msg to send that message. On failure, returns NULL. The caller
+// assumes ownership of the returned launch_data_t object.
+launch_data_t MessageForJob(const std::string& job_label,
+                            const char* operation) {
+  // launch_data_alloc returns something that needs to be freed.
+  ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY));
+  if (!message) {
+    LOG(ERROR) << "launch_data_alloc";
+    return NULL;
+  }
+
+  // launch_data_new_string returns something that needs to be freed, but
+  // the dictionary will assume ownership when launch_data_dict_insert is
+  // called, so put it in a scoper and .release() it when given to the
+  // dictionary.
+  ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str()));
+  if (!job_label_launchd) {
+    LOG(ERROR) << "launch_data_new_string";
+    return NULL;
+  }
+
+  if (!launch_data_dict_insert(message,
+                               job_label_launchd.release(),
+                               operation)) {
+    return NULL;
+  }
+
+  return launch_msg(message);
+}
+
+pid_t PIDForJob(const std::string& job_label) {
+  ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB));
+  if (!response) {
+    return -1;
+  }
+
+  launch_data_type_t response_type = launch_data_get_type(response);
+  if (response_type != LAUNCH_DATA_DICTIONARY) {
+    if (response_type == LAUNCH_DATA_ERRNO) {
+      LOG(ERROR) << "PIDForJob: error " << launch_data_get_errno(response);
+    } else {
+      LOG(ERROR) << "PIDForJob: expected dictionary, got " << response_type;
+    }
+    return -1;
+  }
+
+  launch_data_t pid_data = launch_data_dict_lookup(response,
+                                                   LAUNCH_JOBKEY_PID);
+  if (!pid_data)
+    return 0;
+
+  if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) {
+    LOG(ERROR) << "PIDForJob: expected integer";
+    return -1;
+  }
+
+  return launch_data_get_integer(pid_data);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launchd.h b/base/mac/launchd.h
new file mode 100644
index 0000000..9e4514e
--- /dev/null
+++ b/base/mac/launchd.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_LAUNCHD_H_
+#define BASE_MAC_LAUNCHD_H_
+
+#include <launch.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// MessageForJob sends a single message to launchd with a simple dictionary
+// mapping |operation| to |job_label|, and returns the result of calling
+// launch_msg to send that message. On failure, returns NULL. The caller
+// assumes ownership of the returned launch_data_t object.
+BASE_EXPORT
+launch_data_t MessageForJob(const std::string& job_label,
+                            const char* operation);
+
+// Returns the process ID for |job_label| if the job is running, 0 if the job
+// is loaded but not running, or -1 on error.
+BASE_EXPORT
+pid_t PIDForJob(const std::string& job_label);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LAUNCHD_H_
diff --git a/base/mac/libdispatch_task_runner.cc b/base/mac/libdispatch_task_runner.cc
new file mode 100644
index 0000000..4b5abaf
--- /dev/null
+++ b/base/mac/libdispatch_task_runner.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/libdispatch_task_runner.h"
+
+#include "base/callback.h"
+
+namespace base {
+namespace mac {
+
+LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name)
+    : queue_(dispatch_queue_create(name, NULL)),
+      queue_finalized_(false, false) {
+  dispatch_set_context(queue_, this);
+  dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer);
+}
+
+bool LibDispatchTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  if (!queue_)
+    return false;
+
+  // The block runtime would implicitly copy the reference, not the object
+  // it's referencing. Copy the closure into block storage so it's available
+  // to run.
+  __block const Closure task_copy = task;
+  void(^run_task)(void) = ^{
+      task_copy.Run();
+  };
+
+  int64 delay_nano =
+      delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
+  if (delay_nano > 0) {
+    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
+    dispatch_after(time, queue_, run_task);
+  } else {
+    dispatch_async(queue_, run_task);
+  }
+  return true;
+}
+
+bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const {
+  return queue_ == dispatch_get_current_queue();
+}
+
+bool LibDispatchTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  return PostDelayedTask(from_here, task, delay);
+}
+
+void LibDispatchTaskRunner::Shutdown() {
+  dispatch_release(queue_);
+  queue_ = NULL;
+  queue_finalized_.Wait();
+}
+
+dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const {
+  return queue_;
+}
+
+LibDispatchTaskRunner::~LibDispatchTaskRunner() {
+  if (queue_) {
+    dispatch_set_context(queue_, NULL);
+    dispatch_set_finalizer_f(queue_, NULL);
+    dispatch_release(queue_);
+  }
+}
+
+void LibDispatchTaskRunner::Finalizer(void* context) {
+  LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context);
+  self->queue_finalized_.Signal();
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/libdispatch_task_runner.h b/base/mac/libdispatch_task_runner.h
new file mode 100644
index 0000000..b479bc7
--- /dev/null
+++ b/base/mac/libdispatch_task_runner.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
+#define BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+namespace mac {
+
+// This is an implementation of the TaskRunner interface that runs closures on
+// a thread managed by Apple's libdispatch. This has the benefit of being able
+// to PostTask() and friends to a dispatch queue, while being reusable as a
+// dispatch_queue_t.
+//
+// One would use this class if an object lives exclusively on one thread but
+// needs a dispatch_queue_t for use in a system API. This ensures all dispatch
+// callbacks happen on the same thread as Closure tasks.
+//
+// A LibDispatchTaskRunner will continue to run until all references to the
+// underlying dispatch queue are released.
+//
+// Important Notes:
+//   - There is no MessageLoop running on this thread, and ::current() returns
+//     NULL.
+//   - No nested loops can be run, and all tasks are run non-nested.
+//   - Work scheduled via libdispatch runs at the same priority as and is
+//     interleaved with posted tasks, though FIFO order is guaranteed.
+//
+class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  // Starts a new serial dispatch queue with a given name.
+  explicit LibDispatchTaskRunner(const char* name);
+
+  // base::TaskRunner:
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       base::TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // base::SequencedTaskRunner:
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  base::TimeDelta delay) override;
+
+  // This blocks the calling thread until all work on the dispatch queue has
+  // been run and the queue has been destroyed. Destroying a queue requires
+  // ALL retained references to it to be released. Any new tasks posted to
+  // this thread after shutdown are dropped.
+  void Shutdown();
+
+  // Returns the dispatch queue associated with this task runner, for use with
+  // system APIs that take dispatch queues. The caller is responsible for
+  // retaining the result.
+  //
+  // All properties (context, finalizer, etc.) are managed by this class, and
+  // clients should only use the result of this for dispatch_async().
+  dispatch_queue_t GetDispatchQueue() const;
+
+ protected:
+  ~LibDispatchTaskRunner() override;
+
+ private:
+  static void Finalizer(void* context);
+
+  dispatch_queue_t queue_;
+
+  // The event on which Shutdown waits until Finalizer runs.
+  base::WaitableEvent queue_finalized_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
diff --git a/base/mac/libdispatch_task_runner_unittest.cc b/base/mac/libdispatch_task_runner_unittest.cc
new file mode 100644
index 0000000..49b0c9a
--- /dev/null
+++ b/base/mac/libdispatch_task_runner_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/libdispatch_task_runner.h"
+
+#include "base/bind.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class LibDispatchTaskRunnerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    task_runner_ = new base::mac::LibDispatchTaskRunner(
+        "org.chromium.LibDispatchTaskRunnerTest");
+  }
+
+  // DispatchLastTask is used to run the main test thread's MessageLoop until
+  // all non-delayed tasks are run on the LibDispatchTaskRunner.
+  void DispatchLastTask() {
+    dispatch_async(task_runner_->GetDispatchQueue(), ^{
+        message_loop_.PostTask(FROM_HERE,
+                               base::MessageLoop::QuitWhenIdleClosure());
+    });
+    message_loop_.Run();
+    task_runner_->Shutdown();
+  }
+
+  // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares
+  // them against the recorded values.
+  void VerifyTaskOrder(const char* const expectations[],
+                       size_t num_expectations) {
+    size_t actual_size = task_order_.size();
+
+    for (size_t i = 0; i < num_expectations; ++i) {
+      if (i >= actual_size) {
+        EXPECT_LE(i, actual_size) << "Expected " << expectations[i];
+        continue;
+      }
+
+      EXPECT_EQ(expectations[i], task_order_[i]);
+    }
+
+    if (actual_size > num_expectations) {
+      EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:";
+      for (size_t i = num_expectations; i < actual_size; ++i) {
+        EXPECT_EQ("<none>", task_order_[i]) << " (i=" << i << ")";
+      }
+    }
+  }
+
+  // The message loop for the test main thread.
+  base::MessageLoop message_loop_;
+
+  // The task runner under test.
+  scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_;
+
+  // Vector that records data from TaskOrderMarker.
+  std::vector<std::string> task_order_;
+};
+
+// Scoper that records the beginning and end of a running task.
+class TaskOrderMarker {
+ public:
+  TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name)
+      : test_(test),
+        name_(name) {
+    test->task_order_.push_back(std::string("BEGIN ") + name);
+  }
+  ~TaskOrderMarker() {
+    test_->task_order_.push_back(std::string("END ") + name_);
+  }
+
+ private:
+  LibDispatchTaskRunnerTest* test_;
+  std::string name_;
+};
+
+void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) {
+  TaskOrderMarker marker(test, name);
+}
+
+// Returns a closure that records the task order.
+base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test,
+                                   const std::string& name) {
+  return base::Bind(&RecordTaskOrder, base::Unretained(test), name);
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostTask) {
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task"));
+  DispatchLastTask();
+  const char* const expectations[] = {
+    "BEGIN Basic Task",
+    "END Basic Task"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Outer");
+      task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner"));
+  }));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN Outer",
+    "END Outer",
+    "BEGIN Inner",
+    "END Inner"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this,
+          base::StringPrintf("MessageLoop = %p", base::MessageLoop::current()));
+  }));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN MessageLoop = 0x0",
+    "END MessageLoop = 0x0"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) {
+  dispatch_async(task_runner_->GetDispatchQueue(), ^{
+      TaskOrderMarker marker(this, "First Block");
+  });
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task"));
+  dispatch_async(task_runner_->GetDispatchQueue(), ^{
+      TaskOrderMarker marker(this, "Second Block");
+  });
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task"));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN First Block",
+    "END First Block",
+    "BEGIN First Task",
+    "END First Task",
+    "BEGIN Second Block",
+    "END Second Block",
+    "BEGIN Second Task",
+    "END Second Task",
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, NonNestable) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "First");
+      task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{
+          TaskOrderMarker marker(this, "Second NonNestable");
+          message_loop_.PostTask(FROM_HERE,
+                                 base::MessageLoop::QuitWhenIdleClosure());
+      }));
+  }));
+  message_loop_.Run();
+  task_runner_->Shutdown();
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second NonNestable",
+    "END Second NonNestable"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostDelayed) {
+  base::TimeTicks post_time;
+  __block base::TimeTicks run_time;
+  const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50);
+
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First"));
+  post_time = base::TimeTicks::Now();
+  task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Timed");
+      run_time = base::TimeTicks::Now();
+      message_loop_.PostTask(FROM_HERE,
+                             base::MessageLoop::QuitWhenIdleClosure());
+  }), delta);
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second"));
+  message_loop_.Run();
+  task_runner_->Shutdown();
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second",
+    "END Second",
+    "BEGIN Timed",
+    "END Timed",
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+
+  EXPECT_GE(run_time, post_time + delta);
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) {
+  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
+      BoundRecordTaskOrder(this, "First")));
+  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
+      BoundRecordTaskOrder(this, "Second")));
+  task_runner_->Shutdown();
+  EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Not Run");
+      ADD_FAILURE() << "Should not run a task after Shutdown";
+  })));
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second",
+    "END Second"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
diff --git a/base/mac/mac_logging.cc b/base/mac/mac_logging.cc
new file mode 100644
index 0000000..d58220f
--- /dev/null
+++ b/base/mac/mac_logging.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mac_logging.h"
+
+#include <iomanip>
+
+#if !defined(OS_IOS)
+#include <CoreServices/CoreServices.h>
+#endif
+
+namespace logging {
+
+OSStatusLogMessage::OSStatusLogMessage(const char* file_path,
+                                       int line,
+                                       LogSeverity severity,
+                                       OSStatus status)
+    : LogMessage(file_path, line, severity),
+      status_(status) {
+}
+
+OSStatusLogMessage::~OSStatusLogMessage() {
+#if defined(OS_IOS)
+  // TODO(ios): Consider using NSError with NSOSStatusErrorDomain to try to
+  // get a description of the failure.
+  stream() << ": " << status_;
+#else
+  stream() << ": "
+           << GetMacOSStatusErrorString(status_)
+           << " ("
+           << status_
+           << ")";
+#endif
+}
+
+}  // namespace logging
diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h
new file mode 100644
index 0000000..5192b20
--- /dev/null
+++ b/base/mac/mac_logging.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_MAC_LOGGING_H_
+#define BASE_MAC_MAC_LOGGING_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_IOS)
+#include <MacTypes.h>
+#else
+#include <libkern/OSTypes.h>
+#endif
+
+// Use the OSSTATUS_LOG family to log messages related to errors in Mac OS X
+// system routines that report status via an OSStatus or OSErr value. It is
+// similar to the PLOG family which operates on errno, but because there is no
+// global (or thread-local) OSStatus or OSErr value, the specific error must
+// be supplied as an argument to the OSSTATUS_LOG macro. The message logged
+// will contain the symbolic constant name corresponding to the status value,
+// along with the value itself.
+//
+// OSErr is just an older 16-bit form of the newer 32-bit OSStatus. Despite
+// the name, OSSTATUS_LOG can be used equally well for OSStatus and OSErr.
+
+namespace logging {
+
+class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage {
+ public:
+  OSStatusLogMessage(const char* file_path,
+                     int line,
+                     LogSeverity severity,
+                     OSStatus status);
+  ~OSStatusLogMessage();
+
+ private:
+  OSStatus status_;
+
+  DISALLOW_COPY_AND_ASSIGN(OSStatusLogMessage);
+};
+
+}  // namespace logging
+
+#if defined(NDEBUG)
+#define MAC_DVLOG_IS_ON(verbose_level) 0
+#else
+#define MAC_DVLOG_IS_ON(verbose_level) VLOG_IS_ON(verbose_level)
+#endif
+
+#define OSSTATUS_LOG_STREAM(severity, status) \
+    COMPACT_GOOGLE_LOG_EX_ ## severity(OSStatusLogMessage, status).stream()
+#define OSSTATUS_VLOG_STREAM(verbose_level, status) \
+    logging::OSStatusLogMessage(__FILE__, __LINE__, \
+                                -verbose_level, status).stream()
+
+#define OSSTATUS_LOG(severity, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), LOG_IS_ON(severity))
+#define OSSTATUS_LOG_IF(severity, condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \
+                LOG_IS_ON(severity) && (condition))
+
+#define OSSTATUS_VLOG(verbose_level, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                VLOG_IS_ON(verbose_level))
+#define OSSTATUS_VLOG_IF(verbose_level, condition, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                VLOG_IS_ON(verbose_level) && (condition))
+
+#define OSSTATUS_CHECK(condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#define OSSTATUS_DLOG(severity, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), DLOG_IS_ON(severity))
+#define OSSTATUS_DLOG_IF(severity, condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \
+                DLOG_IS_ON(severity) && (condition))
+
+#define OSSTATUS_DVLOG(verbose_level, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                MAC_DVLOG_IS_ON(verbose_level))
+#define OSSTATUS_DVLOG_IF(verbose_level, condition, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                MAC_DVLOG_IS_ON(verbose_level) && (condition))
+
+#define OSSTATUS_DCHECK(condition, status)        \
+  LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \
+              DCHECK_IS_ON() && !(condition))     \
+      << "Check failed: " #condition << ". "
+
+#endif  // BASE_MAC_MAC_LOGGING_H_
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
new file mode 100644
index 0000000..f8ffa97
--- /dev/null
+++ b/base/mac/mac_util.h
@@ -0,0 +1,231 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_MAC_UTIL_H_
+#define BASE_MAC_MAC_UTIL_H_
+
+#include <AvailabilityMacros.h>
+#include <Carbon/Carbon.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+class NSImage;
+#endif  // __OBJC__
+
+namespace base {
+
+class FilePath;
+
+namespace mac {
+
+// Full screen modes, in increasing order of priority.  More permissive modes
+// take predecence.
+enum FullScreenMode {
+  kFullScreenModeHideAll = 0,
+  kFullScreenModeHideDock = 1,
+  kFullScreenModeAutoHideAll = 2,
+  kNumFullScreenModes = 3,
+
+  // kFullScreenModeNormal is not a valid FullScreenMode, but it is useful to
+  // other classes, so we include it here.
+  kFullScreenModeNormal = 10,
+};
+
+BASE_EXPORT std::string PathFromFSRef(const FSRef& ref);
+BASE_EXPORT bool FSRefFromPath(const std::string& path, FSRef* ref);
+
+// Returns an sRGB color space.  The return value is a static value; do not
+// release it!
+BASE_EXPORT CGColorSpaceRef GetSRGBColorSpace();
+
+// Returns the generic RGB color space. The return value is a static value; do
+// not release it!
+BASE_EXPORT CGColorSpaceRef GetGenericRGBColorSpace();
+
+// Returns the color space being used by the main display.  The return value
+// is a static value; do not release it!
+BASE_EXPORT CGColorSpaceRef GetSystemColorSpace();
+
+// Add a full screen request for the given |mode|.  Must be paired with a
+// ReleaseFullScreen() call for the same |mode|.  This does not by itself create
+// a fullscreen window; rather, it manages per-application state related to
+// hiding the dock and menubar.  Must be called on the main thread.
+BASE_EXPORT void RequestFullScreen(FullScreenMode mode);
+
+// Release a request for full screen mode.  Must be matched with a
+// RequestFullScreen() call for the same |mode|.  As with RequestFullScreen(),
+// this does not affect windows directly, but rather manages per-application
+// state.  For example, if there are no other outstanding
+// |kFullScreenModeAutoHideAll| requests, this will reshow the menu bar.  Must
+// be called on main thread.
+BASE_EXPORT void ReleaseFullScreen(FullScreenMode mode);
+
+// Convenience method to switch the current fullscreen mode.  This has the same
+// net effect as a ReleaseFullScreen(from_mode) call followed immediately by a
+// RequestFullScreen(to_mode).  Must be called on the main thread.
+BASE_EXPORT void SwitchFullScreenModes(FullScreenMode from_mode,
+                                       FullScreenMode to_mode);
+
+// Set the visibility of the cursor.
+BASE_EXPORT void SetCursorVisibility(bool visible);
+
+// Activates the process with the given PID.
+BASE_EXPORT void ActivateProcess(pid_t pid);
+
+// Returns true if this process is in the foreground, meaning that it's the
+// frontmost process, the one whose menu bar is shown at the top of the main
+// display.
+BASE_EXPORT bool AmIForeground();
+
+// Excludes the file given by |file_path| from being backed up by Time Machine.
+BASE_EXPORT bool SetFileBackupExclusion(const FilePath& file_path);
+
+// Checks if the current application is set as a Login Item, so it will launch
+// on Login. If a non-NULL pointer to is_hidden is passed, the Login Item also
+// is queried for the 'hide on launch' flag.
+BASE_EXPORT bool CheckLoginItemStatus(bool* is_hidden);
+
+// Adds current application to the set of Login Items with specified "hide"
+// flag. This has the same effect as adding/removing the application in
+// SystemPreferences->Accounts->LoginItems or marking Application in the Dock
+// as "Options->Open on Login".
+// Does nothing if the application is already set up as Login Item with
+// specified hide flag.
+BASE_EXPORT void AddToLoginItems(bool hide_on_startup);
+
+// Removes the current application from the list Of Login Items.
+BASE_EXPORT void RemoveFromLoginItems();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' or via Lion's Resume. Used to suppress opening windows.
+BASE_EXPORT bool WasLaunchedAsLoginOrResumeItem();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' or via Resume, and the 'Reopen windows when logging back in'
+// checkbox was selected by the user.  This indicates that the previous
+// session should be restored.
+BASE_EXPORT bool WasLaunchedAsLoginItemRestoreState();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows.
+BASE_EXPORT bool WasLaunchedAsHiddenLoginItem();
+
+// Remove the quarantine xattr from the given file. Returns false if there was
+// an error, or true otherwise.
+BASE_EXPORT bool RemoveQuarantineAttribute(const FilePath& file_path);
+
+// Run-time OS version checks. Use these instead of
+// base::SysInfo::OperatingSystemVersionNumbers. Prefer the "OrEarlier" and
+// "OrLater" variants to those that check for a specific version, unless you
+// know for sure that you need to check for a specific version.
+
+// Snow Leopard is Mac OS X 10.6, Darwin 10.
+BASE_EXPORT bool IsOSSnowLeopard();
+
+// Lion is Mac OS X 10.7, Darwin 11.
+BASE_EXPORT bool IsOSLion();
+BASE_EXPORT bool IsOSLionOrEarlier();
+BASE_EXPORT bool IsOSLionOrLater();
+
+// Mountain Lion is Mac OS X 10.8, Darwin 12.
+BASE_EXPORT bool IsOSMountainLion();
+BASE_EXPORT bool IsOSMountainLionOrEarlier();
+BASE_EXPORT bool IsOSMountainLionOrLater();
+
+// Mavericks is Mac OS X 10.9, Darwin 13.
+BASE_EXPORT bool IsOSMavericks();
+BASE_EXPORT bool IsOSMavericksOrEarlier();
+BASE_EXPORT bool IsOSMavericksOrLater();
+
+// Yosemite is Mac OS X 10.10, Darwin 14.
+BASE_EXPORT bool IsOSYosemite();
+BASE_EXPORT bool IsOSYosemiteOrLater();
+
+// This should be infrequently used. It only makes sense to use this to avoid
+// codepaths that are very likely to break on future (unreleased, untested,
+// unborn) OS releases, or to log when the OS is newer than any known version.
+BASE_EXPORT bool IsOSLaterThanYosemite_DontCallThis();
+
+// Inline functions that are redundant due to version ranges being mutually-
+// exclusive.
+inline bool IsOSLionOrEarlier() { return !IsOSMountainLionOrLater(); }
+inline bool IsOSMountainLionOrEarlier() { return !IsOSMavericksOrLater(); }
+inline bool IsOSMavericksOrEarlier() { return !IsOSYosemiteOrLater(); }
+
+// When the deployment target is set, the code produced cannot run on earlier
+// OS releases. That enables some of the IsOS* family to be implemented as
+// constant-value inline functions. The MAC_OS_X_VERSION_MIN_REQUIRED macro
+// contains the value of the deployment target.
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7
+inline bool IsOSSnowLeopard() { return false; }
+inline bool IsOSLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7
+inline bool IsOSLion() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_8) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8
+inline bool IsOSMountainLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_8) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8
+inline bool IsOSMountainLion() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_9
+inline bool IsOSMavericksOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_9
+inline bool IsOSMavericks() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_10) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_10
+inline bool IsOSYosemiteOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_10) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10
+inline bool IsOSYosemite() { return false; }
+inline bool IsOSLaterThanYosemite_DontCallThis() { return true; }
+#endif
+
+// Retrieve the system's model identifier string from the IOKit registry:
+// for example, "MacPro4,1", "MacBookPro6,1". Returns empty string upon
+// failure.
+BASE_EXPORT std::string GetModelIdentifier();
+
+// Parse a model identifier string; for example, into ("MacBookPro", 6, 1).
+// If any error occurs, none of the input pointers are touched.
+BASE_EXPORT bool ParseModelIdentifier(const std::string& ident,
+                                      std::string* type,
+                                      int32* major,
+                                      int32* minor);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_MAC_UTIL_H_
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
new file mode 100644
index 0000000..bdf45de
--- /dev/null
+++ b/base/mac/mac_util.mm
@@ -0,0 +1,594 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mac_util.h"
+
+#import <Cocoa/Cocoa.h>
+#import <IOKit/IOKitLib.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <sys/xattr.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+// The current count of outstanding requests for full screen mode from browser
+// windows, plugins, etc.
+int g_full_screen_requests[kNumFullScreenModes] = { 0 };
+
+// Sets the appropriate application presentation option based on the current
+// full screen requests.  Since only one presentation option can be active at a
+// given time, full screen requests are ordered by priority.  If there are no
+// outstanding full screen requests, reverts to normal mode.  If the correct
+// presentation option is already set, does nothing.
+void SetUIMode() {
+  NSApplicationPresentationOptions current_options =
+      [NSApp presentationOptions];
+
+  // Determine which mode should be active, based on which requests are
+  // currently outstanding.  More permissive requests take precedence.  For
+  // example, plugins request |kFullScreenModeAutoHideAll|, while browser
+  // windows request |kFullScreenModeHideDock| when the fullscreen overlay is
+  // down.  Precedence goes to plugins in this case, so AutoHideAll wins over
+  // HideDock.
+  NSApplicationPresentationOptions desired_options =
+      NSApplicationPresentationDefault;
+  if (g_full_screen_requests[kFullScreenModeAutoHideAll] > 0) {
+    desired_options = NSApplicationPresentationHideDock |
+                      NSApplicationPresentationAutoHideMenuBar;
+  } else if (g_full_screen_requests[kFullScreenModeHideDock] > 0) {
+    desired_options = NSApplicationPresentationHideDock;
+  } else if (g_full_screen_requests[kFullScreenModeHideAll] > 0) {
+    desired_options = NSApplicationPresentationHideDock |
+                      NSApplicationPresentationHideMenuBar;
+  }
+
+  // Mac OS X bug: if the window is fullscreened (Lion-style) and
+  // NSApplicationPresentationDefault is requested, the result is that the menu
+  // bar doesn't auto-hide. rdar://13576498 http://www.openradar.me/13576498
+  //
+  // As a workaround, in that case, explicitly set the presentation options to
+  // the ones that are set by the system as it fullscreens a window.
+  if (desired_options == NSApplicationPresentationDefault &&
+      current_options & NSApplicationPresentationFullScreen) {
+    desired_options |= NSApplicationPresentationFullScreen |
+                       NSApplicationPresentationAutoHideMenuBar |
+                       NSApplicationPresentationAutoHideDock;
+  }
+
+  if (current_options != desired_options)
+    [NSApp setPresentationOptions:desired_options];
+}
+
+// Looks into Shared File Lists corresponding to Login Items for the item
+// representing the current application.  If such an item is found, returns a
+// retained reference to it. Caller is responsible for releasing the reference.
+LSSharedFileListItemRef GetLoginItemForApp() {
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return NULL;
+  }
+
+  base::scoped_nsobject<NSArray> login_items_array(
+      CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL)));
+
+  NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
+
+  for(NSUInteger i = 0; i < [login_items_array count]; ++i) {
+    LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>(
+        [login_items_array objectAtIndex:i]);
+    CFURLRef item_url_ref = NULL;
+
+    if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr) {
+      ScopedCFTypeRef<CFURLRef> item_url(item_url_ref);
+      if (CFEqual(item_url, url)) {
+        CFRetain(item);
+        return item;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+bool IsHiddenLoginItem(LSSharedFileListItemRef item) {
+  ScopedCFTypeRef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>(
+      LSSharedFileListItemCopyProperty(item,
+          reinterpret_cast<CFStringRef>(kLSSharedFileListLoginItemHidden))));
+
+  return hidden && hidden == kCFBooleanTrue;
+}
+
+}  // namespace
+
+std::string PathFromFSRef(const FSRef& ref) {
+  ScopedCFTypeRef<CFURLRef> url(
+      CFURLCreateFromFSRef(kCFAllocatorDefault, &ref));
+  NSString *path_string = [(NSURL *)url.get() path];
+  return [path_string fileSystemRepresentation];
+}
+
+bool FSRefFromPath(const std::string& path, FSRef* ref) {
+  OSStatus status = FSPathMakeRef((const UInt8*)path.c_str(),
+                                  ref, nil);
+  return status == noErr;
+}
+
+CGColorSpaceRef GetGenericRGBColorSpace() {
+  // Leaked. That's OK, it's scoped to the lifetime of the application.
+  static CGColorSpaceRef g_color_space_generic_rgb(
+      CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+  DLOG_IF(ERROR, !g_color_space_generic_rgb) <<
+      "Couldn't get the generic RGB color space";
+  return g_color_space_generic_rgb;
+}
+
+CGColorSpaceRef GetSRGBColorSpace() {
+  // Leaked.  That's OK, it's scoped to the lifetime of the application.
+  static CGColorSpaceRef g_color_space_sRGB =
+      CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+  DLOG_IF(ERROR, !g_color_space_sRGB) << "Couldn't get the sRGB color space";
+  return g_color_space_sRGB;
+}
+
+CGColorSpaceRef GetSystemColorSpace() {
+  // Leaked.  That's OK, it's scoped to the lifetime of the application.
+  // Try to get the main display's color space.
+  static CGColorSpaceRef g_system_color_space =
+      CGDisplayCopyColorSpace(CGMainDisplayID());
+
+  if (!g_system_color_space) {
+    // Use a generic RGB color space.  This is better than nothing.
+    g_system_color_space = CGColorSpaceCreateDeviceRGB();
+
+    if (g_system_color_space) {
+      DLOG(WARNING) <<
+          "Couldn't get the main display's color space, using generic";
+    } else {
+      DLOG(ERROR) << "Couldn't get any color space";
+    }
+  }
+
+  return g_system_color_space;
+}
+
+// Add a request for full screen mode.  Must be called on the main thread.
+void RequestFullScreen(FullScreenMode mode) {
+  DCHECK_LT(mode, kNumFullScreenModes);
+  if (mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GE(g_full_screen_requests[mode], 0);
+  if (mode < 0)
+    return;
+
+  g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] + 1, 1);
+  SetUIMode();
+}
+
+// Release a request for full screen mode.  Must be called on the main thread.
+void ReleaseFullScreen(FullScreenMode mode) {
+  DCHECK_LT(mode, kNumFullScreenModes);
+  if (mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GE(g_full_screen_requests[mode], 0);
+  if (mode < 0)
+    return;
+
+  g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] - 1, 0);
+  SetUIMode();
+}
+
+// Switches full screen modes.  Releases a request for |from_mode| and adds a
+// new request for |to_mode|.  Must be called on the main thread.
+void SwitchFullScreenModes(FullScreenMode from_mode, FullScreenMode to_mode) {
+  DCHECK_LT(from_mode, kNumFullScreenModes);
+  DCHECK_LT(to_mode, kNumFullScreenModes);
+  if (from_mode >= kNumFullScreenModes || to_mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GT(g_full_screen_requests[from_mode], 0);
+  DCHECK_GE(g_full_screen_requests[to_mode], 0);
+  g_full_screen_requests[from_mode] =
+      std::max(g_full_screen_requests[from_mode] - 1, 0);
+  g_full_screen_requests[to_mode] =
+      std::max(g_full_screen_requests[to_mode] + 1, 1);
+  SetUIMode();
+}
+
+void SetCursorVisibility(bool visible) {
+  if (visible)
+    [NSCursor unhide];
+  else
+    [NSCursor hide];
+}
+
+void ActivateProcess(pid_t pid) {
+  ProcessSerialNumber process;
+  OSStatus status = GetProcessForPID(pid, &process);
+  if (status == noErr) {
+    SetFrontProcess(&process);
+  } else {
+    OSSTATUS_DLOG(WARNING, status) << "Unable to get process for pid " << pid;
+  }
+}
+
+bool AmIForeground() {
+  ProcessSerialNumber foreground_psn = { 0 };
+  OSErr err = GetFrontProcess(&foreground_psn);
+  if (err != noErr) {
+    OSSTATUS_DLOG(WARNING, err) << "GetFrontProcess";
+    return false;
+  }
+
+  ProcessSerialNumber my_psn = { 0, kCurrentProcess };
+
+  Boolean result = FALSE;
+  err = SameProcess(&foreground_psn, &my_psn, &result);
+  if (err != noErr) {
+    OSSTATUS_DLOG(WARNING, err) << "SameProcess";
+    return false;
+  }
+
+  return result;
+}
+
+bool SetFileBackupExclusion(const FilePath& file_path) {
+  NSString* file_path_ns =
+      [NSString stringWithUTF8String:file_path.value().c_str()];
+  NSURL* file_url = [NSURL fileURLWithPath:file_path_ns];
+
+  // When excludeByPath is true the application must be running with root
+  // privileges (admin for 10.6 and earlier) but the URL does not have to
+  // already exist. When excludeByPath is false the URL must already exist but
+  // can be used in non-root (or admin as above) mode. We use false so that
+  // non-root (or admin) users don't get their TimeMachine drive filled up with
+  // unnecessary backups.
+  OSStatus os_err =
+      CSBackupSetItemExcluded(base::mac::NSToCFCast(file_url), TRUE, FALSE);
+  if (os_err != noErr) {
+    OSSTATUS_DLOG(WARNING, os_err)
+        << "Failed to set backup exclusion for file '"
+        << file_path.value().c_str() << "'";
+  }
+  return os_err == noErr;
+}
+
+bool CheckLoginItemStatus(bool* is_hidden) {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get())
+    return false;
+
+  if (is_hidden)
+    *is_hidden = IsHiddenLoginItem(item);
+
+  return true;
+}
+
+void AddToLoginItems(bool hide_on_startup) {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) {
+    return;  // Already is a login item with required hide flag.
+  }
+
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return;
+  }
+
+  // Remove the old item, it has wrong hide flag, we'll create a new one.
+  if (item.get()) {
+    LSSharedFileListItemRemove(login_items, item);
+  }
+
+  NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
+
+  BOOL hide = hide_on_startup ? YES : NO;
+  NSDictionary* properties =
+      [NSDictionary
+        dictionaryWithObject:[NSNumber numberWithBool:hide]
+                      forKey:(NSString*)kLSSharedFileListLoginItemHidden];
+
+  ScopedCFTypeRef<LSSharedFileListItemRef> new_item;
+  new_item.reset(LSSharedFileListInsertItemURL(
+      login_items, kLSSharedFileListItemLast, NULL, NULL,
+      reinterpret_cast<CFURLRef>(url),
+      reinterpret_cast<CFDictionaryRef>(properties), NULL));
+
+  if (!new_item.get()) {
+    DLOG(ERROR) << "Couldn't insert current app into Login Items list.";
+  }
+}
+
+void RemoveFromLoginItems() {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get())
+    return;
+
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return;
+  }
+
+  LSSharedFileListItemRemove(login_items, item);
+}
+
+bool WasLaunchedAsLoginOrResumeItem() {
+  ProcessSerialNumber psn = { 0, kCurrentProcess };
+  ProcessInfoRec info = {};
+  info.processInfoLength = sizeof(info);
+
+  if (GetProcessInformation(&psn, &info) == noErr) {
+    ProcessInfoRec parent_info = {};
+    parent_info.processInfoLength = sizeof(parent_info);
+    if (GetProcessInformation(&info.processLauncher, &parent_info) == noErr)
+      return parent_info.processSignature == 'lgnw';
+  }
+  return false;
+}
+
+bool WasLaunchedAsLoginItemRestoreState() {
+  // "Reopen windows..." option was added for Lion.  Prior OS versions should
+  // not have this behavior.
+  if (IsOSSnowLeopard() || !WasLaunchedAsLoginOrResumeItem())
+    return false;
+
+  CFStringRef app = CFSTR("com.apple.loginwindow");
+  CFStringRef save_state = CFSTR("TALLogoutSavesState");
+  ScopedCFTypeRef<CFPropertyListRef> plist(
+      CFPreferencesCopyAppValue(save_state, app));
+  // According to documentation, com.apple.loginwindow.plist does not exist on a
+  // fresh installation until the user changes a login window setting.  The
+  // "reopen windows" option is checked by default, so the plist would exist had
+  // the user unchecked it.
+  // https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/CustomLogin.html
+  if (!plist)
+    return true;
+
+  if (CFBooleanRef restore_state = base::mac::CFCast<CFBooleanRef>(plist))
+    return CFBooleanGetValue(restore_state);
+
+  return false;
+}
+
+bool WasLaunchedAsHiddenLoginItem() {
+  if (!WasLaunchedAsLoginOrResumeItem())
+    return false;
+
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get()) {
+    // Lion can launch items for the resume feature.  So log an error only for
+    // Snow Leopard or earlier.
+    if (IsOSSnowLeopard())
+      DLOG(ERROR) <<
+          "Process launched at Login but can't access Login Item List.";
+
+    return false;
+  }
+  return IsHiddenLoginItem(item);
+}
+
+bool RemoveQuarantineAttribute(const FilePath& file_path) {
+  const char kQuarantineAttrName[] = "com.apple.quarantine";
+  int status = removexattr(file_path.value().c_str(), kQuarantineAttrName, 0);
+  return status == 0 || errno == ENOATTR;
+}
+
+namespace {
+
+// Returns the running system's Darwin major version. Don't call this, it's
+// an implementation detail and its result is meant to be cached by
+// MacOSXMinorVersion.
+int DarwinMajorVersionInternal() {
+  // base::OperatingSystemVersionNumbers calls Gestalt, which is a
+  // higher-level operation than is needed. It might perform unnecessary
+  // operations. On 10.6, it was observed to be able to spawn threads (see
+  // http://crbug.com/53200). It might also read files or perform other
+  // blocking operations. Actually, nobody really knows for sure just what
+  // Gestalt might do, or what it might be taught to do in the future.
+  //
+  // uname, on the other hand, is implemented as a simple series of sysctl
+  // system calls to obtain the relevant data from the kernel. The data is
+  // compiled right into the kernel, so no threads or blocking or other
+  // funny business is necessary.
+
+  struct utsname uname_info;
+  if (uname(&uname_info) != 0) {
+    DPLOG(ERROR) << "uname";
+    return 0;
+  }
+
+  if (strcmp(uname_info.sysname, "Darwin") != 0) {
+    DLOG(ERROR) << "unexpected uname sysname " << uname_info.sysname;
+    return 0;
+  }
+
+  int darwin_major_version = 0;
+  char* dot = strchr(uname_info.release, '.');
+  if (dot) {
+    if (!base::StringToInt(base::StringPiece(uname_info.release,
+                                             dot - uname_info.release),
+                           &darwin_major_version)) {
+      dot = NULL;
+    }
+  }
+
+  if (!dot) {
+    DLOG(ERROR) << "could not parse uname release " << uname_info.release;
+    return 0;
+  }
+
+  return darwin_major_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the
+// result is meant to be cached by MacOSXMinorVersion.
+int MacOSXMinorVersionInternal() {
+  int darwin_major_version = DarwinMajorVersionInternal();
+
+  // The Darwin major version is always 4 greater than the Mac OS X minor
+  // version for Darwin versions beginning with 6, corresponding to Mac OS X
+  // 10.2. Since this correspondence may change in the future, warn when
+  // encountering a version higher than anything seen before. Older Darwin
+  // versions, or versions that can't be determined, result in
+  // immediate death.
+  CHECK(darwin_major_version >= 6);
+  int mac_os_x_minor_version = darwin_major_version - 4;
+  DLOG_IF(WARNING, darwin_major_version > 14) << "Assuming Darwin "
+      << base::IntToString(darwin_major_version) << " is Mac OS X 10."
+      << base::IntToString(mac_os_x_minor_version);
+
+  return mac_os_x_minor_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z.
+int MacOSXMinorVersion() {
+  static int mac_os_x_minor_version = MacOSXMinorVersionInternal();
+  return mac_os_x_minor_version;
+}
+
+enum {
+  SNOW_LEOPARD_MINOR_VERSION = 6,
+  LION_MINOR_VERSION = 7,
+  MOUNTAIN_LION_MINOR_VERSION = 8,
+  MAVERICKS_MINOR_VERSION = 9,
+  YOSEMITE_MINOR_VERSION = 10,
+};
+
+}  // namespace
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSSnowLeopard() {
+  return MacOSXMinorVersion() == SNOW_LEOPARD_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7)
+bool IsOSLion() {
+  return MacOSXMinorVersion() == LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSLionOrLater() {
+  return MacOSXMinorVersion() >= LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8)
+bool IsOSMountainLion() {
+  return MacOSXMinorVersion() == MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8)
+bool IsOSMountainLionOrLater() {
+  return MacOSXMinorVersion() >= MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_9)
+bool IsOSMavericks() {
+  return MacOSXMinorVersion() == MAVERICKS_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_9)
+bool IsOSMavericksOrLater() {
+  return MacOSXMinorVersion() >= MAVERICKS_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10)
+bool IsOSYosemite() {
+  return MacOSXMinorVersion() == YOSEMITE_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_10)
+bool IsOSYosemiteOrLater() {
+  return MacOSXMinorVersion() >= YOSEMITE_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10)
+bool IsOSLaterThanYosemite_DontCallThis() {
+  return MacOSXMinorVersion() > YOSEMITE_MINOR_VERSION;
+}
+#endif
+
+std::string GetModelIdentifier() {
+  std::string return_string;
+  ScopedIOObject<io_service_t> platform_expert(
+      IOServiceGetMatchingService(kIOMasterPortDefault,
+                                  IOServiceMatching("IOPlatformExpertDevice")));
+  if (platform_expert) {
+    ScopedCFTypeRef<CFDataRef> model_data(
+        static_cast<CFDataRef>(IORegistryEntryCreateCFProperty(
+            platform_expert,
+            CFSTR("model"),
+            kCFAllocatorDefault,
+            0)));
+    if (model_data) {
+      return_string =
+          reinterpret_cast<const char*>(CFDataGetBytePtr(model_data));
+    }
+  }
+  return return_string;
+}
+
+bool ParseModelIdentifier(const std::string& ident,
+                          std::string* type,
+                          int32* major,
+                          int32* minor) {
+  size_t number_loc = ident.find_first_of("0123456789");
+  if (number_loc == std::string::npos)
+    return false;
+  size_t comma_loc = ident.find(',', number_loc);
+  if (comma_loc == std::string::npos)
+    return false;
+  int32 major_tmp, minor_tmp;
+  std::string::const_iterator begin = ident.begin();
+  if (!StringToInt(
+          StringPiece(begin + number_loc, begin + comma_loc), &major_tmp) ||
+      !StringToInt(
+          StringPiece(begin + comma_loc + 1, ident.end()), &minor_tmp))
+    return false;
+  *type = ident.substr(0, number_loc);
+  *major = major_tmp;
+  *minor = minor_tmp;
+  return true;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
new file mode 100644
index 0000000..3982ab0
--- /dev/null
+++ b/base/mac/mac_util_unittest.mm
@@ -0,0 +1,289 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/mac_util.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#include <errno.h>
+#include <sys/xattr.h>
+
+namespace base {
+namespace mac {
+
+namespace {
+
+typedef PlatformTest MacUtilTest;
+
+TEST_F(MacUtilTest, TestFSRef) {
+  FSRef ref;
+  std::string path("/System/Library");
+
+  ASSERT_TRUE(FSRefFromPath(path, &ref));
+  EXPECT_EQ(path, PathFromFSRef(ref));
+}
+
+TEST_F(MacUtilTest, GetUserDirectoryTest) {
+  // Try a few keys, make sure they come back with non-empty paths.
+  FilePath caches_dir;
+  EXPECT_TRUE(GetUserDirectory(NSCachesDirectory, &caches_dir));
+  EXPECT_FALSE(caches_dir.empty());
+
+  FilePath application_support_dir;
+  EXPECT_TRUE(GetUserDirectory(NSApplicationSupportDirectory,
+                               &application_support_dir));
+  EXPECT_FALSE(application_support_dir.empty());
+
+  FilePath library_dir;
+  EXPECT_TRUE(GetUserDirectory(NSLibraryDirectory, &library_dir));
+  EXPECT_FALSE(library_dir.empty());
+}
+
+TEST_F(MacUtilTest, TestLibraryPath) {
+  FilePath library_dir = GetUserLibraryPath();
+  // Make sure the string isn't empty.
+  EXPECT_FALSE(library_dir.value().empty());
+}
+
+TEST_F(MacUtilTest, TestGetAppBundlePath) {
+  FilePath out;
+
+  // Make sure it doesn't crash.
+  out = GetAppBundlePath(FilePath());
+  EXPECT_TRUE(out.empty());
+
+  // Some more invalid inputs.
+  const char* const invalid_inputs[] = {
+    "/", "/foo", "foo", "/foo/bar.", "foo/bar.", "/foo/bar./bazquux",
+    "foo/bar./bazquux", "foo/.app", "//foo",
+  };
+  for (size_t i = 0; i < arraysize(invalid_inputs); i++) {
+    out = GetAppBundlePath(FilePath(invalid_inputs[i]));
+    EXPECT_TRUE(out.empty()) << "loop: " << i;
+  }
+
+  // Some valid inputs; this and |expected_outputs| should be in sync.
+  struct {
+    const char *in;
+    const char *expected_out;
+  } valid_inputs[] = {
+    { "FooBar.app/", "FooBar.app" },
+    { "/FooBar.app", "/FooBar.app" },
+    { "/FooBar.app/", "/FooBar.app" },
+    { "//FooBar.app", "//FooBar.app" },
+    { "/Foo/Bar.app", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/", "/Foo/Bar.app" },
+    { "/F/B.app", "/F/B.app" },
+    { "/F/B.app/", "/F/B.app" },
+    { "/Foo/Bar.app/baz", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/baz/", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/baz/quux.app/quuux", "/Foo/Bar.app" },
+    { "/Applications/Google Foo.app/bar/Foo Helper.app/quux/Foo Helper",
+        "/Applications/Google Foo.app" },
+  };
+  for (size_t i = 0; i < arraysize(valid_inputs); i++) {
+    out = GetAppBundlePath(FilePath(valid_inputs[i].in));
+    EXPECT_FALSE(out.empty()) << "loop: " << i;
+    EXPECT_STREQ(valid_inputs[i].expected_out,
+        out.value().c_str()) << "loop: " << i;
+  }
+}
+
+// http://crbug.com/425745
+TEST_F(MacUtilTest, DISABLED_TestExcludeFileFromBackups) {
+  // The file must already exist in order to set its exclusion property.
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_file_path = temp_dir_.path().Append("DummyFile");
+  const char dummy_data[] = "All your base are belong to us!";
+  // Dump something real into the file.
+  ASSERT_EQ(static_cast<int>(arraysize(dummy_data)),
+            WriteFile(dummy_file_path, dummy_data, arraysize(dummy_data)));
+  NSString* fileURLString =
+      [NSString stringWithUTF8String:dummy_file_path.value().c_str()];
+  NSURL* fileURL = [NSURL URLWithString:fileURLString];
+  // Initial state should be non-excluded.
+  EXPECT_FALSE(CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), NULL));
+  // Exclude the file.
+  EXPECT_TRUE(SetFileBackupExclusion(dummy_file_path));
+  // SetFileBackupExclusion never excludes by path.
+  Boolean excluded_by_path = FALSE;
+  Boolean excluded =
+      CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), &excluded_by_path);
+  EXPECT_TRUE(excluded);
+  EXPECT_FALSE(excluded_by_path);
+}
+
+TEST_F(MacUtilTest, NSObjectRetainRelease) {
+  base::scoped_nsobject<NSArray> array(
+      [[NSArray alloc] initWithObjects:@"foo", nil]);
+  EXPECT_EQ(1U, [array retainCount]);
+
+  NSObjectRetain(array);
+  EXPECT_EQ(2U, [array retainCount]);
+
+  NSObjectRelease(array);
+  EXPECT_EQ(1U, [array retainCount]);
+}
+
+TEST_F(MacUtilTest, IsOSEllipsis) {
+  int32 major, minor, bugfix;
+  base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+
+  if (major == 10) {
+    if (minor == 6) {
+      EXPECT_TRUE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_TRUE(IsOSLionOrEarlier());
+      EXPECT_FALSE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrEarlier());
+      EXPECT_FALSE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_FALSE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 7) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_TRUE(IsOSLion());
+      EXPECT_TRUE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrEarlier());
+      EXPECT_FALSE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_FALSE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 8) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_TRUE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrEarlier());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_FALSE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 9) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_FALSE(IsOSMountainLionOrEarlier());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_TRUE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_TRUE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 10) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_FALSE(IsOSMountainLionOrEarlier());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_FALSE(IsOSMavericksOrEarlier());
+      EXPECT_TRUE(IsOSMavericksOrLater());
+      EXPECT_TRUE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else {
+      // Not six, seven, eight, nine, or ten. Ah, ah, ah.
+      EXPECT_TRUE(false);
+    }
+  } else {
+    // Not ten. What you gonna do?
+    EXPECT_FALSE(true);
+  }
+}
+
+TEST_F(MacUtilTest, ParseModelIdentifier) {
+  std::string model;
+  int32 major = 1, minor = 2;
+
+  EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor));
+  EXPECT_EQ(0U, model.length());
+  EXPECT_EQ(1, major);
+  EXPECT_EQ(2, minor);
+  EXPECT_FALSE(ParseModelIdentifier("FooBar", &model, &major, &minor));
+
+  EXPECT_TRUE(ParseModelIdentifier("MacPro4,1", &model, &major, &minor));
+  EXPECT_EQ(model, "MacPro");
+  EXPECT_EQ(4, major);
+  EXPECT_EQ(1, minor);
+
+  EXPECT_TRUE(ParseModelIdentifier("MacBookPro6,2", &model, &major, &minor));
+  EXPECT_EQ(model, "MacBookPro");
+  EXPECT_EQ(6, major);
+  EXPECT_EQ(2, minor);
+}
+
+TEST_F(MacUtilTest, TestRemoveQuarantineAttribute) {
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder");
+  ASSERT_TRUE(base::CreateDirectory(dummy_folder_path));
+  const char* quarantine_str = "0000;4b392bb2;Chromium;|org.chromium.Chromium";
+  const char* file_path_str = dummy_folder_path.value().c_str();
+  EXPECT_EQ(0, setxattr(file_path_str, "com.apple.quarantine",
+      quarantine_str, strlen(quarantine_str), 0, 0));
+  EXPECT_EQ(static_cast<long>(strlen(quarantine_str)),
+      getxattr(file_path_str, "com.apple.quarantine",
+          NULL, 0, 0, 0));
+  EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path));
+  EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0));
+  EXPECT_EQ(ENOATTR, errno);
+}
+
+TEST_F(MacUtilTest, TestRemoveQuarantineAttributeTwice) {
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder");
+  const char* file_path_str = dummy_folder_path.value().c_str();
+  ASSERT_TRUE(base::CreateDirectory(dummy_folder_path));
+  EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0));
+  // No quarantine attribute to begin with, but RemoveQuarantineAttribute still
+  // succeeds because in the end the folder still doesn't have the quarantine
+  // attribute set.
+  EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path));
+  EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path));
+  EXPECT_EQ(ENOATTR, errno);
+}
+
+TEST_F(MacUtilTest, TestRemoveQuarantineAttributeNonExistentPath) {
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath non_existent_path = temp_dir_.path().Append("DummyPath");
+  ASSERT_FALSE(PathExists(non_existent_path));
+  EXPECT_FALSE(RemoveQuarantineAttribute(non_existent_path));
+}
+
+}  // namespace
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/mach_logging.cc b/base/mac/mach_logging.cc
new file mode 100644
index 0000000..c5ff85e
--- /dev/null
+++ b/base/mac/mach_logging.cc
@@ -0,0 +1,87 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mach_logging.h"
+
+#include <iomanip>
+#include <string>
+
+#include "base/strings/stringprintf.h"
+
+#if !defined(OS_IOS)
+#include <servers/bootstrap.h>
+#endif  // !OS_IOS
+
+namespace {
+
+std::string FormatMachErrorNumber(mach_error_t mach_err) {
+  // For the os/kern subsystem, give the error number in decimal as in
+  // <mach/kern_return.h>. Otherwise, give it in hexadecimal to make it easier
+  // to visualize the various bits. See <mach/error.h>.
+  if (mach_err >= 0 && mach_err < KERN_RETURN_MAX) {
+    return base::StringPrintf(" (%d)", mach_err);
+  }
+  return base::StringPrintf(" (0x%08x)", mach_err);
+}
+
+}  // namespace
+
+namespace logging {
+
+MachLogMessage::MachLogMessage(const char* file_path,
+                               int line,
+                               LogSeverity severity,
+                               mach_error_t mach_err)
+    : LogMessage(file_path, line, severity),
+      mach_err_(mach_err) {
+}
+
+MachLogMessage::~MachLogMessage() {
+  stream() << ": "
+           << mach_error_string(mach_err_)
+           << FormatMachErrorNumber(mach_err_);
+}
+
+#if !defined(OS_IOS)
+
+BootstrapLogMessage::BootstrapLogMessage(const char* file_path,
+                                         int line,
+                                         LogSeverity severity,
+                                         kern_return_t bootstrap_err)
+    : LogMessage(file_path, line, severity),
+      bootstrap_err_(bootstrap_err) {
+}
+
+BootstrapLogMessage::~BootstrapLogMessage() {
+  stream() << ": "
+           << bootstrap_strerror(bootstrap_err_);
+
+  switch (bootstrap_err_) {
+    case BOOTSTRAP_SUCCESS:
+    case BOOTSTRAP_NOT_PRIVILEGED:
+    case BOOTSTRAP_NAME_IN_USE:
+    case BOOTSTRAP_UNKNOWN_SERVICE:
+    case BOOTSTRAP_SERVICE_ACTIVE:
+    case BOOTSTRAP_BAD_COUNT:
+    case BOOTSTRAP_NO_MEMORY:
+    case BOOTSTRAP_NO_CHILDREN: {
+      // Show known bootstrap errors in decimal because that's how they're
+      // defined in <servers/bootstrap.h>.
+      stream() << " (" << bootstrap_err_ << ")";
+      break;
+    }
+
+    default: {
+      // bootstrap_strerror passes unknown errors to mach_error_string, so
+      // format them as they would be if they were handled by
+      // MachErrorMessage.
+      stream() << FormatMachErrorNumber(bootstrap_err_);
+      break;
+    }
+  }
+}
+
+#endif  // !OS_IOS
+
+}  // namespace logging
diff --git a/base/mac/mach_logging.h b/base/mac/mach_logging.h
new file mode 100644
index 0000000..b12e274
--- /dev/null
+++ b/base/mac/mach_logging.h
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_MACH_LOGGING_H_
+#define BASE_MAC_MACH_LOGGING_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+// Use the MACH_LOG family of macros along with a mach_error_t (kern_return_t)
+// containing a Mach error. The error value will be decoded so that logged
+// messages explain the error.
+//
+// Use the BOOTSTRAP_LOG family of macros specifically for errors that occur
+// while interoperating with the bootstrap subsystem. These errors will first
+// be looked up as bootstrap error messages. If no match is found, they will
+// be treated as generic Mach errors, as in MACH_LOG.
+//
+// Examples:
+//
+//   kern_return_t kr = mach_timebase_info(&info);
+//   if (kr != KERN_SUCCESS) {
+//     MACH_LOG(ERROR, kr) << "mach_timebase_info";
+//   }
+//
+//   kr = vm_deallocate(task, address, size);
+//   MACH_DCHECK(kr == KERN_SUCCESS, kr) << "vm_deallocate";
+
+namespace logging {
+
+class BASE_EXPORT MachLogMessage : public logging::LogMessage {
+ public:
+  MachLogMessage(const char* file_path,
+                 int line,
+                 LogSeverity severity,
+                 mach_error_t mach_err);
+  ~MachLogMessage();
+
+ private:
+  mach_error_t mach_err_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachLogMessage);
+};
+
+}  // namespace logging
+
+#if defined(NDEBUG)
+#define MACH_DVLOG_IS_ON(verbose_level) 0
+#else
+#define MACH_DVLOG_IS_ON(verbose_level) VLOG_IS_ON(verbose_level)
+#endif
+
+#define MACH_LOG_STREAM(severity, mach_err) \
+    COMPACT_GOOGLE_LOG_EX_ ## severity(MachLogMessage, mach_err).stream()
+#define MACH_VLOG_STREAM(verbose_level, mach_err) \
+    logging::MachLogMessage(__FILE__, __LINE__, \
+                            -verbose_level, mach_err).stream()
+
+#define MACH_LOG(severity, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), LOG_IS_ON(severity))
+#define MACH_LOG_IF(severity, condition, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), \
+                LOG_IS_ON(severity) && (condition))
+
+#define MACH_VLOG(verbose_level, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                VLOG_IS_ON(verbose_level))
+#define MACH_VLOG_IF(verbose_level, condition, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                VLOG_IS_ON(verbose_level) && (condition))
+
+#define MACH_CHECK(condition, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#define MACH_DLOG(severity, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), DLOG_IS_ON(severity))
+#define MACH_DLOG_IF(severity, condition, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), \
+                DLOG_IS_ON(severity) && (condition))
+
+#define MACH_DVLOG(verbose_level, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                MACH_DVLOG_IS_ON(verbose_level))
+#define MACH_DVLOG_IF(verbose_level, condition, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                MACH_DVLOG_IS_ON(verbose_level) && (condition))
+
+#define MACH_DCHECK(condition, mach_err)        \
+  LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), \
+              DCHECK_IS_ON() && !(condition))   \
+      << "Check failed: " #condition << ". "
+
+#if !defined(OS_IOS)
+
+namespace logging {
+
+class BASE_EXPORT BootstrapLogMessage : public logging::LogMessage {
+ public:
+  BootstrapLogMessage(const char* file_path,
+                      int line,
+                      LogSeverity severity,
+                      kern_return_t bootstrap_err);
+  ~BootstrapLogMessage();
+
+ private:
+  kern_return_t bootstrap_err_;
+
+  DISALLOW_COPY_AND_ASSIGN(BootstrapLogMessage);
+};
+
+}  // namespace logging
+
+#define BOOTSTRAP_DVLOG_IS_ON MACH_DVLOG_IS_ON
+
+#define BOOTSTRAP_LOG_STREAM(severity, bootstrap_err) \
+    COMPACT_GOOGLE_LOG_EX_ ## severity(BootstrapLogMessage, \
+                                       bootstrap_err).stream()
+#define BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err) \
+    logging::BootstrapLogMessage(__FILE__, __LINE__, \
+                                 -verbose_level, bootstrap_err).stream()
+
+#define BOOTSTRAP_LOG(severity, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, \
+                                     bootstrap_err), LOG_IS_ON(severity))
+#define BOOTSTRAP_LOG_IF(severity, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, bootstrap_err), \
+                LOG_IS_ON(severity) && (condition))
+
+#define BOOTSTRAP_VLOG(verbose_level, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                VLOG_IS_ON(verbose_level))
+#define BOOTSTRAP_VLOG_IF(verbose_level, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                VLOG_IS_ON(verbose_level) && (condition))
+
+#define BOOTSTRAP_CHECK(condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#define BOOTSTRAP_DLOG(severity, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, bootstrap_err), \
+                DLOG_IS_ON(severity))
+#define BOOTSTRAP_DLOG_IF(severity, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, bootstrap_err), \
+                DLOG_IS_ON(severity) && (condition))
+
+#define BOOTSTRAP_DVLOG(verbose_level, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                BOOTSTRAP_DVLOG_IS_ON(verbose_level))
+#define BOOTSTRAP_DVLOG_IF(verbose_level, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                BOOTSTRAP_DVLOG_IS_ON(verbose_level) && (condition))
+
+#define BOOTSTRAP_DCHECK(condition, bootstrap_err)        \
+  LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), \
+              DCHECK_IS_ON() && !(condition))             \
+      << "Check failed: " #condition << ". "
+
+#endif  // !OS_IOS
+
+#endif  // BASE_MAC_MACH_LOGGING_H_
diff --git a/base/mac/memory_pressure_monitor_mac.cc b/base/mac/memory_pressure_monitor_mac.cc
new file mode 100644
index 0000000..81727bb
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac.cc
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/memory_pressure_monitor_mac.h"
+
+#include <dlfcn.h>
+#include <sys/sysctl.h>
+
+#include "base/mac/mac_util.h"
+
+namespace base {
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorMac::MemoryPressureLevelForMacMemoryPressure(
+    int mac_memory_pressure) {
+  switch (mac_memory_pressure) {
+    case DISPATCH_MEMORYPRESSURE_NORMAL:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+    case DISPATCH_MEMORYPRESSURE_WARN:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+    case DISPATCH_MEMORYPRESSURE_CRITICAL:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+  }
+  return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void MemoryPressureMonitorMac::NotifyMemoryPressureChanged(
+    dispatch_source_s* event_source) {
+  int mac_memory_pressure = dispatch_source_get_data(event_source);
+  MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
+      MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+  MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
+MemoryPressureMonitorMac::MemoryPressureMonitorMac()
+  : memory_level_event_source_(nullptr) {
+  // _dispatch_source_type_memorypressure is not available prior to 10.9.
+  dispatch_source_type_t dispatch_source_memorypressure =
+      static_cast<dispatch_source_type_t>
+          (dlsym(RTLD_NEXT, "_dispatch_source_type_memorypressure"));
+  if (dispatch_source_memorypressure) {
+    // The MemoryPressureListener doesn't want to know about transitions to
+    // MEMORY_PRESSURE_LEVEL_NONE so don't watch for
+    // DISPATCH_MEMORYPRESSURE_NORMAL notifications.
+    memory_level_event_source_.reset(
+        dispatch_source_create(dispatch_source_memorypressure, 0,
+                               DISPATCH_MEMORYPRESSURE_WARN |
+                                   DISPATCH_MEMORYPRESSURE_CRITICAL,
+                               dispatch_get_global_queue(
+                                   DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
+
+    dispatch_source_set_event_handler(memory_level_event_source_.get(), ^{
+        NotifyMemoryPressureChanged(memory_level_event_source_.get());
+    });
+    dispatch_retain(memory_level_event_source_.get());
+    dispatch_resume(memory_level_event_source_.get());
+  }
+}
+
+MemoryPressureMonitorMac::~MemoryPressureMonitorMac() {
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitorMac::GetCurrentPressureLevel() const {
+  if (base::mac::IsOSMountainLionOrEarlier()) {
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+  }
+  int mac_memory_pressure;
+  size_t length = sizeof(int);
+  sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure,
+               &length, nullptr, 0);
+  return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+}
+
+}  // namespace base
diff --git a/base/mac/memory_pressure_monitor_mac.h b/base/mac/memory_pressure_monitor_mac.h
new file mode 100644
index 0000000..aebdd65
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac.h
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+
+// The following was added to <dispatch/source.h> after 10.8.
+// TODO(shrike): Remove the DISPATCH_MEMORYPRESSURE_NORMAL ifndef once builders
+// reach 10.9 or higher.
+#ifndef DISPATCH_MEMORYPRESSURE_NORMAL
+
+#define DISPATCH_MEMORYPRESSURE_NORMAL    0x01
+#define DISPATCH_MEMORYPRESSURE_WARN      0x02
+#define DISPATCH_MEMORYPRESSURE_CRITICAL  0x04
+
+#endif  // DISPATCH_MEMORYPRESSURE_NORMAL
+
+namespace base {
+
+class TestMemoryPressureMonitorMac;
+
+struct DispatchSourceSDeleter {
+  void operator()(dispatch_source_s* ptr) {
+    dispatch_source_cancel(ptr);
+    dispatch_release(ptr);
+  }
+};
+
+// Declares the interface for the Mac MemoryPressureMonitor, which reports
+// memory pressure events and status.
+class BASE_EXPORT MemoryPressureMonitorMac : public MemoryPressureMonitor {
+ public:
+  using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+  MemoryPressureMonitorMac();
+  ~MemoryPressureMonitorMac() override;
+
+  // Returns the currently-observed memory pressure.
+  MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+ private:
+  friend TestMemoryPressureMonitorMac;
+
+  static MemoryPressureLevel
+      MemoryPressureLevelForMacMemoryPressure(int mac_memory_pressure);
+  static void NotifyMemoryPressureChanged(dispatch_source_s* event_source);
+
+  scoped_ptr<dispatch_source_s, DispatchSourceSDeleter>
+      memory_level_event_source_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitorMac);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
diff --git a/base/mac/memory_pressure_monitor_mac_unittest.cc b/base/mac/memory_pressure_monitor_mac_unittest.cc
new file mode 100644
index 0000000..24ee09a
--- /dev/null
+++ b/base/mac/memory_pressure_monitor_mac_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/memory_pressure_monitor_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class TestMemoryPressureMonitorMac : public MemoryPressureMonitorMac {
+ public:
+  using MemoryPressureMonitorMac::MemoryPressureLevelForMacMemoryPressure;
+
+  TestMemoryPressureMonitorMac() { }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitorMac);
+};
+
+TEST(TestMemoryPressureMonitorMac, MemoryPressureFromMacMemoryPressure) {
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_NORMAL));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_WARN));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_CRITICAL));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(0));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(3));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(5));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitorMac::
+                MemoryPressureLevelForMacMemoryPressure(-1));
+}
+
+TEST(TestMemoryPressureMonitorMac, CurrentMemoryPressure) {
+  TestMemoryPressureMonitorMac monitor;
+  MemoryPressureListener::MemoryPressureLevel memory_pressure =
+      monitor.GetCurrentPressureLevel();
+  EXPECT_TRUE(memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE ||
+              memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE ||
+              memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
+}  // namespace base
diff --git a/base/mac/objc_property_releaser.h b/base/mac/objc_property_releaser.h
new file mode 100644
index 0000000..973d793
--- /dev/null
+++ b/base/mac/objc_property_releaser.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_OBJC_PROPERTY_RELEASER_H_
+#define BASE_MAC_OBJC_PROPERTY_RELEASER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// ObjCPropertyReleaser is a C++ class that can automatically release
+// synthesized Objective-C properties marked "retain" or "copy". The expected
+// use is to place an ObjCPropertyReleaser object within an Objective-C class
+// definition. When built with the -fobjc-call-cxx-cdtors compiler option,
+// the ObjCPropertyReleaser's destructor will be called when the Objective-C
+// object that owns it is deallocated, and it will send a -release message to
+// the instance variables backing the appropriate properties. If
+// -fobjc-call-cxx-cdtors is not in use, ObjCPropertyReleaser's
+// ReleaseProperties method can be called from -dealloc to achieve the same
+// effect.
+//
+// Example usage:
+//
+// @interface AllaysIBF : NSObject {
+//  @private
+//   NSString* string_;
+//   NSMutableDictionary* dictionary_;
+//   NSString* notAProperty_;
+//   IBFDelegate* delegate_;  // weak
+//
+//   // It's recommended to put the class name into the property releaser's
+//   // instance variable name to gracefully handle subclassing, where
+//   // multiple classes in a hierarchy might want their own property
+//   // releasers.
+//   base::mac::ObjCPropertyReleaser propertyReleaser_AllaysIBF_;
+// }
+//
+// @property(retain, nonatomic) NSString* string;
+// @property(copy, nonatomic) NSMutableDictionary* dictionary;
+// @property(assign, nonatomic) IBFDelegate* delegate;
+// @property(retain, nonatomic) NSString* autoProp;
+//
+// @end  // @interface AllaysIBF
+//
+// @implementation AllaysIBF
+//
+// @synthesize string = string_;
+// @synthesize dictionary = dictionary_;
+// @synthesize delegate = delegate_;
+// @synthesize autoProp;
+//
+// - (id)init {
+//   if ((self = [super init])) {
+//     // Initialize with [AllaysIBF class]. Never use [self class] because
+//     // in the case of subclassing, it will return the most specific class
+//     // for |self|, which may not be the same as [AllaysIBF class]. This
+//     // would cause AllaysIBF's -.cxx_destruct or -dealloc to release
+//     // instance variables that only exist in subclasses, likely causing
+//     // mass disaster.
+//     propertyReleaser_AllaysIBF_.Init(self, [AllaysIBF class]);
+//   }
+//   return self;
+// }
+//
+// @end  // @implementation AllaysIBF
+//
+// When an instance of AllaysIBF is deallocated, the ObjCPropertyReleaser will
+// send a -release message to string_, dictionary_, and the compiler-created
+// autoProp instance variables. No -release will be sent to delegate_ as it
+// is marked "assign" and not "retain" or "copy". No -release will be sent to
+// notAProperty_ because it doesn't correspond to any declared @property.
+//
+// Another way of doing this would be to provide a base class that others can
+// inherit from, and to have the base class' -dealloc walk the property lists
+// of all subclasses in an object to send the -release messages. Since this
+// involves a base reaching into its subclasses, it's deemed scary, so don't
+// do it. ObjCPropertyReleaser's design ensures that the property releaser
+// will only operate on instance variables in the immediate object in which
+// the property releaser is placed.
+
+class BASE_EXPORT ObjCPropertyReleaser {
+ public:
+  // ObjCPropertyReleaser can only be owned by an Objective-C object, so its
+  // memory is always guaranteed to be 0-initialized. Not defining the default
+  // constructor can prevent an otherwise no-op -.cxx_construct method from
+  // showing up in Objective-C classes that contain a ObjCPropertyReleaser.
+
+  // Upon destruction (expected to occur from an Objective-C object's
+  // -.cxx_destruct method), release all properties.
+  ~ObjCPropertyReleaser() {
+    ReleaseProperties();
+  }
+
+  // Initialize this object so that it's armed to release the properties of
+  // object |object|, which must be of type |classy|. The class argument must
+  // be supplied separately and cannot be gleaned from the object's own type
+  // because an object will allays identify itself as the most-specific type
+  // that describes it, but the ObjCPropertyReleaser needs to know which class
+  // type in the class hierarchy it's responsible for releasing properties
+  // for. For the same reason, Init must be called with a |classy| argument
+  // initialized using a +class (class) method such as [MyClass class], and
+  // never a -class (instance) method such as [self class].
+  //
+  // -.cxx_construct can only call the default constructor, but
+  // ObjCPropertyReleaser needs to know about the Objective-C object that owns
+  // it, so this can't be handled in a constructor, it needs to be a distinct
+  // Init method.
+  void Init(id object, Class classy);
+
+  // Release all of the properties in object_ defined in class_ as either
+  // "retain" or "copy" and with an identifiable backing instance variable.
+  // Properties must be synthesized to have identifiable instance variables.
+  void ReleaseProperties();
+
+ private:
+  id object_;
+  Class class_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_OBJC_PROPERTY_RELEASER_H_
diff --git a/base/mac/objc_property_releaser.mm b/base/mac/objc_property_releaser.mm
new file mode 100644
index 0000000..f7ee88f
--- /dev/null
+++ b/base/mac/objc_property_releaser.mm
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/objc_property_releaser.h"
+
+#import <objc/runtime.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+// Returns the name of the instance variable backing the property, if known,
+// if the property is marked "retain" or "copy". If the instance variable name
+// is not known (perhaps because it was not automatically associated with the
+// property by @synthesize) or if the property is not "retain" or "copy",
+// returns an empty string.
+std::string ReleasableInstanceName(objc_property_t property) {
+  // TODO(mark): Starting in newer system releases, the Objective-C runtime
+  // provides a function to break the property attribute string into
+  // individual attributes (property_copyAttributeList), as well as a function
+  // to look up the value of a specific attribute
+  // (property_copyAttributeValue). When the SDK defining that interface is
+  // final, this function should be adapted to walk the attribute list as
+  // returned by property_copyAttributeList when that function is available in
+  // preference to scanning through the attribute list manually.
+
+  // The format of the string returned by property_getAttributes is documented
+  // at
+  // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
+  const char* property_attributes = property_getAttributes(property);
+
+  std::string instance_name;
+  bool releasable = false;
+  while (*property_attributes) {
+    char name = *property_attributes;
+
+    const char* value = ++property_attributes;
+    while (*property_attributes && *property_attributes != ',') {
+      ++property_attributes;
+    }
+
+    switch (name) {
+      // It might seem intelligent to check the type ('T') attribute to verify
+      // that it identifies an NSObject-derived type (the attribute value
+      // begins with '@'.) This is a bad idea beacuse it fails to identify
+      // CFTypeRef-based properties declared as __attribute__((NSObject)),
+      // which just show up as pointers to their underlying CFType structs.
+      //
+      // Quoting
+      // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27
+      //
+      // > In Mac OS X v10.6 and later, you can use the __attribute__ keyword
+      // > to specify that a Core Foundation property should be treated like
+      // > an Objective-C object for memory management:
+      // >   @property(retain) __attribute__((NSObject)) CFDictionaryRef
+      // >       myDictionary;
+      case 'C':  // copy
+      case '&':  // retain
+        releasable = true;
+        break;
+      case 'V':  // instance variable name
+        // 'V' is specified as the last attribute to occur in the
+        // documentation, but empirically, it's not always the last. In
+        // GC-supported or GC-required code, the 'P' (GC-eligible) attribute
+        // occurs after 'V'.
+        instance_name.assign(value, property_attributes - value);
+        break;
+    }
+
+    if (*property_attributes) {
+      ++property_attributes;
+    }
+  }
+
+  if (releasable) {
+    return instance_name;
+  }
+
+  return std::string();
+}
+
+}  // namespace
+
+void ObjCPropertyReleaser::Init(id object, Class classy) {
+  DCHECK(!object_);
+  DCHECK(!class_);
+  CHECK([object isKindOfClass:classy]);
+
+  object_ = object;
+  class_ = classy;
+}
+
+void ObjCPropertyReleaser::ReleaseProperties() {
+  DCHECK(object_);
+  DCHECK(class_);
+
+  unsigned int property_count = 0;
+  objc_property_t* properties = class_copyPropertyList(class_, &property_count);
+
+  for (unsigned int property_index = 0;
+       property_index < property_count;
+       ++property_index) {
+    objc_property_t property = properties[property_index];
+    std::string instance_name = ReleasableInstanceName(property);
+    if (!instance_name.empty()) {
+      id instance_value = nil;
+      Ivar instance_variable =
+          object_getInstanceVariable(object_, instance_name.c_str(),
+                                     (void**)&instance_value);
+      DCHECK(instance_variable);
+      [instance_value release];
+    }
+  }
+
+  free(properties);
+
+  // Clear object_ and class_ in case this ObjCPropertyReleaser will live on.
+  // It's only expected to release the properties it supervises once per Init.
+  object_ = nil;
+  class_ = nil;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/objc_property_releaser_unittest.mm b/base/mac/objc_property_releaser_unittest.mm
new file mode 100644
index 0000000..50f81a8
--- /dev/null
+++ b/base/mac/objc_property_releaser_unittest.mm
@@ -0,0 +1,350 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+#import "base/mac/objc_property_releaser.h"
+#import "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// "When I'm alone, I count myself."
+//   --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4
+
+namespace {
+
+// The number of CountVonCounts outstanding.
+int ah_ah_ah;
+
+// NumberHolder exists to exercise the property attribute string parser by
+// providing a named struct and an anonymous union.
+struct NumberHolder {
+  union {
+    long long sixty_four;
+    int thirty_two;
+    short sixteen;
+    char eight;
+  } what;
+  enum {
+    SIXTY_FOUR,
+    THIRTY_TWO,
+    SIXTEEN,
+    EIGHT
+  } how;
+};
+
+}  // namespace
+
+@interface CountVonCount : NSObject<NSCopying>
+
++ (CountVonCount*)countVonCount;
+
+@end  // @interface CountVonCount
+
+@implementation CountVonCount
+
++ (CountVonCount*)countVonCount {
+  return [[[CountVonCount alloc] init] autorelease];
+}
+
+- (id)init {
+  ++ah_ah_ah;
+  return [super init];
+}
+
+- (void)dealloc {
+  --ah_ah_ah;
+  [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone*)zone {
+  return [[CountVonCount allocWithZone:zone] init];
+}
+
+@end  // @implementation CountVonCount
+
+@interface ObjCPropertyTestBase : NSObject {
+ @private
+  CountVonCount* baseCvcRetain_;
+  CountVonCount* baseCvcCopy_;
+  CountVonCount* baseCvcAssign_;
+  CountVonCount* baseCvcNotProperty_;
+  CountVonCount* baseCvcNil_;
+  CountVonCount* baseCvcCustom_;
+  int baseInt_;
+  double baseDouble_;
+  void* basePointer_;
+  NumberHolder baseStruct_;
+
+  base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestBase_;
+}
+
+@property(retain, nonatomic) CountVonCount* baseCvcRetain;
+@property(copy, nonatomic) CountVonCount* baseCvcCopy;
+@property(assign, nonatomic) CountVonCount* baseCvcAssign;
+@property(retain, nonatomic) CountVonCount* baseCvcNil;
+@property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:)
+    CountVonCount* baseCvcCustom;
+@property(retain, nonatomic) CountVonCount* baseCvcDynamic;
+@property(assign, nonatomic) int baseInt;
+@property(assign, nonatomic) double baseDouble;
+@property(assign, nonatomic) void* basePointer;
+@property(assign, nonatomic) NumberHolder baseStruct;
+
+- (void)setBaseCvcNotProperty:(CountVonCount*)cvc;
+
+@end  // @interface ObjCPropertyTestBase
+
+@implementation ObjCPropertyTestBase
+
+@synthesize baseCvcRetain = baseCvcRetain_;
+@synthesize baseCvcCopy = baseCvcCopy_;
+@synthesize baseCvcAssign = baseCvcAssign_;
+@synthesize baseCvcNil = baseCvcNil_;
+@synthesize baseCvcCustom = baseCvcCustom_;
+@dynamic baseCvcDynamic;
+@synthesize baseInt = baseInt_;
+@synthesize baseDouble = baseDouble_;
+@synthesize basePointer = basePointer_;
+@synthesize baseStruct = baseStruct_;
+
+- (id)init {
+  if ((self = [super init])) {
+    propertyReleaser_ObjCPropertyTestBase_.Init(
+        self, [ObjCPropertyTestBase class]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [baseCvcNotProperty_ release];
+  [super dealloc];
+}
+
+- (void)setBaseCvcNotProperty:(CountVonCount*)cvc {
+  if (cvc != baseCvcNotProperty_) {
+    [baseCvcNotProperty_ release];
+    baseCvcNotProperty_ = [cvc retain];
+  }
+}
+
+@end  // @implementation ObjCPropertyTestBase
+
+@protocol ObjCPropertyTestProtocol
+
+@property(retain, nonatomic) CountVonCount* protoCvcRetain;
+@property(copy, nonatomic) CountVonCount* protoCvcCopy;
+@property(assign, nonatomic) CountVonCount* protoCvcAssign;
+@property(retain, nonatomic) CountVonCount* protoCvcNil;
+@property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:)
+    CountVonCount* protoCvcCustom;
+@property(retain, nonatomic) CountVonCount* protoCvcDynamic;
+@property(assign, nonatomic) int protoInt;
+@property(assign, nonatomic) double protoDouble;
+@property(assign, nonatomic) void* protoPointer;
+@property(assign, nonatomic) NumberHolder protoStruct;
+
+@end  // @protocol ObjCPropertyTestProtocol
+
+@interface ObjCPropertyTestDerived
+    : ObjCPropertyTestBase<ObjCPropertyTestProtocol> {
+ @private
+  CountVonCount* derivedCvcRetain_;
+  CountVonCount* derivedCvcCopy_;
+  CountVonCount* derivedCvcAssign_;
+  CountVonCount* derivedCvcNotProperty_;
+  CountVonCount* derivedCvcNil_;
+  CountVonCount* derivedCvcCustom_;
+  int derivedInt_;
+  double derivedDouble_;
+  void* derivedPointer_;
+  NumberHolder derivedStruct_;
+
+  CountVonCount* protoCvcRetain_;
+  CountVonCount* protoCvcCopy_;
+  CountVonCount* protoCvcAssign_;
+  CountVonCount* protoCvcNil_;
+  CountVonCount* protoCvcCustom_;
+  int protoInt_;
+  double protoDouble_;
+  void* protoPointer_;
+  NumberHolder protoStruct_;
+
+  base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestDerived_;
+}
+
+@property(retain, nonatomic) CountVonCount* derivedCvcRetain;
+@property(copy, nonatomic) CountVonCount* derivedCvcCopy;
+@property(assign, nonatomic) CountVonCount* derivedCvcAssign;
+@property(retain, nonatomic) CountVonCount* derivedCvcNil;
+@property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:)
+    CountVonCount* derivedCvcCustom;
+@property(retain, nonatomic) CountVonCount* derivedCvcDynamic;
+@property(assign, nonatomic) int derivedInt;
+@property(assign, nonatomic) double derivedDouble;
+@property(assign, nonatomic) void* derivedPointer;
+@property(assign, nonatomic) NumberHolder derivedStruct;
+
+- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc;
+
+@end  // @interface ObjCPropertyTestDerived
+
+@implementation ObjCPropertyTestDerived
+
+@synthesize derivedCvcRetain = derivedCvcRetain_;
+@synthesize derivedCvcCopy = derivedCvcCopy_;
+@synthesize derivedCvcAssign = derivedCvcAssign_;
+@synthesize derivedCvcNil = derivedCvcNil_;
+@synthesize derivedCvcCustom = derivedCvcCustom_;
+@dynamic derivedCvcDynamic;
+@synthesize derivedInt = derivedInt_;
+@synthesize derivedDouble = derivedDouble_;
+@synthesize derivedPointer = derivedPointer_;
+@synthesize derivedStruct = derivedStruct_;
+
+@synthesize protoCvcRetain = protoCvcRetain_;
+@synthesize protoCvcCopy = protoCvcCopy_;
+@synthesize protoCvcAssign = protoCvcAssign_;
+@synthesize protoCvcNil = protoCvcNil_;
+@synthesize protoCvcCustom = protoCvcCustom_;
+@dynamic protoCvcDynamic;
+@synthesize protoInt = protoInt_;
+@synthesize protoDouble = protoDouble_;
+@synthesize protoPointer = protoPointer_;
+@synthesize protoStruct = protoStruct_;
+
+- (id)init {
+  if ((self = [super init])) {
+    propertyReleaser_ObjCPropertyTestDerived_.Init(
+        self, [ObjCPropertyTestDerived class]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [derivedCvcNotProperty_ release];
+  [super dealloc];
+}
+
+- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc {
+  if (cvc != derivedCvcNotProperty_) {
+    [derivedCvcNotProperty_ release];
+    derivedCvcNotProperty_ = [cvc retain];
+  }
+}
+
+@end  // @implementation ObjCPropertyTestDerived
+
+namespace {
+
+TEST(ObjCPropertyReleaserTest, SesameStreet) {
+  ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init];
+
+  // Assure a clean slate.
+  EXPECT_EQ(0, ah_ah_ah);
+  EXPECT_EQ(1U, [test_object retainCount]);
+
+  CountVonCount* baseAssign = [[CountVonCount alloc] init];
+  CountVonCount* derivedAssign = [[CountVonCount alloc] init];
+  CountVonCount* protoAssign = [[CountVonCount alloc] init];
+
+  // Make sure that worked before things get more involved.
+  EXPECT_EQ(3, ah_ah_ah);
+
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+
+    test_object.baseCvcRetain = [CountVonCount countVonCount];
+    test_object.baseCvcCopy = [CountVonCount countVonCount];
+    test_object.baseCvcAssign = baseAssign;
+    test_object.baseCvcCustom = [CountVonCount countVonCount];
+    [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]];
+
+    // That added 4 objects, plus 1 more that was copied.
+    EXPECT_EQ(8, ah_ah_ah);
+
+    test_object.derivedCvcRetain = [CountVonCount countVonCount];
+    test_object.derivedCvcCopy = [CountVonCount countVonCount];
+    test_object.derivedCvcAssign = derivedAssign;
+    test_object.derivedCvcCustom = [CountVonCount countVonCount];
+    [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]];
+
+    // That added 4 objects, plus 1 more that was copied.
+    EXPECT_EQ(13, ah_ah_ah);
+
+    test_object.protoCvcRetain = [CountVonCount countVonCount];
+    test_object.protoCvcCopy = [CountVonCount countVonCount];
+    test_object.protoCvcAssign = protoAssign;
+    test_object.protoCvcCustom = [CountVonCount countVonCount];
+
+    // That added 3 objects, plus 1 more that was copied.
+    EXPECT_EQ(17, ah_ah_ah);
+  }
+
+  // Now that the autorelease pool has been popped, the 3 objects that were
+  // copied when placed into the test object will have been deallocated.
+  EXPECT_EQ(14, ah_ah_ah);
+
+  // Make sure that the setters work and have the expected semantics.
+  test_object.baseCvcRetain = nil;
+  test_object.baseCvcCopy = nil;
+  test_object.baseCvcAssign = nil;
+  test_object.baseCvcCustom = nil;
+  test_object.derivedCvcRetain = nil;
+  test_object.derivedCvcCopy = nil;
+  test_object.derivedCvcAssign = nil;
+  test_object.derivedCvcCustom = nil;
+  test_object.protoCvcRetain = nil;
+  test_object.protoCvcCopy = nil;
+  test_object.protoCvcAssign = nil;
+  test_object.protoCvcCustom = nil;
+
+  // The CountVonCounts marked "retain" and "copy" should have been
+  // deallocated. Those marked assign should not have been. The only ones that
+  // should exist now are the ones marked "assign" and the ones held in
+  // non-property instance variables.
+  EXPECT_EQ(5, ah_ah_ah);
+
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+
+    // Put things back to how they were.
+    test_object.baseCvcRetain = [CountVonCount countVonCount];
+    test_object.baseCvcCopy = [CountVonCount countVonCount];
+    test_object.baseCvcAssign = baseAssign;
+    test_object.baseCvcCustom = [CountVonCount countVonCount];
+    test_object.derivedCvcRetain = [CountVonCount countVonCount];
+    test_object.derivedCvcCopy = [CountVonCount countVonCount];
+    test_object.derivedCvcAssign = derivedAssign;
+    test_object.derivedCvcCustom = [CountVonCount countVonCount];
+    test_object.protoCvcRetain = [CountVonCount countVonCount];
+    test_object.protoCvcCopy = [CountVonCount countVonCount];
+    test_object.protoCvcAssign = protoAssign;
+    test_object.protoCvcCustom = [CountVonCount countVonCount];
+
+    // 9 more CountVonCounts, 3 of which were copied.
+    EXPECT_EQ(17, ah_ah_ah);
+  }
+
+  // Now that the autorelease pool has been popped, the 3 copies are gone.
+  EXPECT_EQ(14, ah_ah_ah);
+
+  // Releasing the test object should get rid of everything that it owns.
+  [test_object release];
+
+  // The property releaser should have released all of the CountVonCounts
+  // associated with properties marked "retain" or "copy". The -dealloc
+  // methods in each should have released the single non-property objects in
+  // each. Only the CountVonCounts assigned to the properties marked "assign"
+  // should remain.
+  EXPECT_EQ(3, ah_ah_ah);
+
+  [baseAssign release];
+  [derivedAssign release];
+  [protoAssign release];
+
+  // Zero! Zero counts! Ah, ah, ah.
+  EXPECT_EQ(0, ah_ah_ah);
+}
+
+}  // namespace
diff --git a/base/mac/os_crash_dumps.cc b/base/mac/os_crash_dumps.cc
new file mode 100644
index 0000000..5d65b46
--- /dev/null
+++ b/base/mac/os_crash_dumps.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/os_crash_dumps.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+void ExitSignalHandler(int sig) {
+  // A call to exit() can call atexit() handlers.  If we SIGSEGV due
+  // to a corrupt heap, and if we have an atexit handler that
+  // allocates or frees memory, we are in trouble if we do not _exit.
+  _exit(128 + sig);
+}
+
+}  // namespace
+
+void DisableOSCrashDumps() {
+  // These are the POSIX signals corresponding to the Mach exceptions that
+  // Apple Crash Reporter handles.  See ux_exception() in xnu's
+  // bsd/uxkern/ux_exception.c and machine_exception() in xnu's
+  // bsd/dev/*/unix_signal.c.
+  const int signals_to_intercept[] = {
+    // Hardware faults
+    SIGILL,   // EXC_BAD_INSTRUCTION
+    SIGTRAP,  // EXC_BREAKPOINT
+    SIGFPE,   // EXC_ARITHMETIC
+    SIGBUS,   // EXC_BAD_ACCESS
+    SIGSEGV,  // EXC_BAD_ACCESS
+    // Not a hardware fault
+    SIGABRT
+  };
+
+  // For all these signals, just wire things up so we exit immediately.
+  for (size_t i = 0; i < arraysize(signals_to_intercept); ++i) {
+    struct sigaction act = {};
+    act.sa_handler = ExitSignalHandler;
+
+    // It is better to allow the signal handler to run on the stack
+    // registered with sigaltstack(), if one is present.
+    act.sa_flags = SA_ONSTACK;
+
+    if (sigemptyset(&act.sa_mask) != 0)
+      DPLOG(FATAL) << "sigemptyset() failed";
+    if (sigaction(signals_to_intercept[i], &act, NULL) != 0)
+      DPLOG(FATAL) << "sigaction() failed";
+  }
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/os_crash_dumps.h b/base/mac/os_crash_dumps.h
new file mode 100644
index 0000000..31d90fb
--- /dev/null
+++ b/base/mac/os_crash_dumps.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_OS_CRASH_DUMPS_H_
+#define BASE_MAC_OS_CRASH_DUMPS_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// On Mac OS X, it can take a really long time for the OS crash handler to
+// process a Chrome crash when debugging symbols are available.  This
+// translates into a long wait until the process actually dies.  This call
+// disables Apple Crash Reporter entirely.
+BASE_EXPORT void DisableOSCrashDumps();
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_OS_CRASH_DUMPS_H_
diff --git a/base/mac/scoped_aedesc.h b/base/mac/scoped_aedesc.h
new file mode 100644
index 0000000..a1323c0
--- /dev/null
+++ b/base/mac/scoped_aedesc.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_AEDESC_H_
+#define BASE_MAC_SCOPED_AEDESC_H_
+
+#import <CoreServices/CoreServices.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+// The ScopedAEDesc is used to scope AppleEvent descriptors.  On creation,
+// it will store a NULL descriptor.  On destruction, it will dispose of the
+// descriptor.
+//
+// This class is parameterized for additional type safety checks.  You can use
+// the generic AEDesc type by not providing a template parameter:
+//  ScopedAEDesc<> desc;
+template <typename AEDescType = AEDesc>
+class ScopedAEDesc {
+ public:
+  ScopedAEDesc() {
+    AECreateDesc(typeNull, NULL, 0, &desc_);
+  }
+
+  ~ScopedAEDesc() {
+    AEDisposeDesc(&desc_);
+  }
+
+  // Used for in parameters.
+  operator const AEDescType*() {
+    return &desc_;
+  }
+
+  // Used for out parameters.
+  AEDescType* OutPointer() {
+    return &desc_;
+  }
+
+ private:
+  AEDescType desc_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAEDesc);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_AEDESC_H_
diff --git a/base/mac/scoped_authorizationref.h b/base/mac/scoped_authorizationref.h
new file mode 100644
index 0000000..1811488
--- /dev/null
+++ b/base/mac/scoped_authorizationref.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
+#define BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
+
+#include <Security/Authorization.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// ScopedAuthorizationRef maintains ownership of an AuthorizationRef.  It is
+// patterned after the scoped_ptr interface.
+
+namespace base {
+namespace mac {
+
+class ScopedAuthorizationRef {
+ public:
+  explicit ScopedAuthorizationRef(AuthorizationRef authorization = NULL)
+      : authorization_(authorization) {
+  }
+
+  ~ScopedAuthorizationRef() {
+    if (authorization_) {
+      AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+    }
+  }
+
+  void reset(AuthorizationRef authorization = NULL) {
+    if (authorization_ != authorization) {
+      if (authorization_) {
+        AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+      }
+      authorization_ = authorization;
+    }
+  }
+
+  bool operator==(AuthorizationRef that) const {
+    return authorization_ == that;
+  }
+
+  bool operator!=(AuthorizationRef that) const {
+    return authorization_ != that;
+  }
+
+  operator AuthorizationRef() const {
+    return authorization_;
+  }
+
+  AuthorizationRef* get_pointer() { return &authorization_; }
+
+  AuthorizationRef get() const {
+    return authorization_;
+  }
+
+  void swap(ScopedAuthorizationRef& that) {
+    AuthorizationRef temp = that.authorization_;
+    that.authorization_ = authorization_;
+    authorization_ = temp;
+  }
+
+  // ScopedAuthorizationRef::release() is like scoped_ptr<>::release.  It is
+  // NOT a wrapper for AuthorizationFree().  To force a
+  // ScopedAuthorizationRef object to call AuthorizationFree(), use
+  // ScopedAuthorizationRef::reset().
+  AuthorizationRef release() WARN_UNUSED_RESULT {
+    AuthorizationRef temp = authorization_;
+    authorization_ = NULL;
+    return temp;
+  }
+
+ private:
+  AuthorizationRef authorization_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAuthorizationRef);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
diff --git a/base/mac/scoped_block.h b/base/mac/scoped_block.h
new file mode 100644
index 0000000..509a1c2
--- /dev/null
+++ b/base/mac/scoped_block.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_BLOCK_H_
+#define BASE_MAC_SCOPED_BLOCK_H_
+
+#include <Block.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_policy.h"
+
+namespace base {
+namespace mac {
+
+// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
+// Block_release() instead of CFRetain() and CFRelease().
+
+template<typename B>
+class ScopedBlock {
+ public:
+  explicit ScopedBlock(
+      B block = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : block_(block) {
+    if (block_ && policy == base::scoped_policy::RETAIN)
+      block_ = Block_copy(block);
+  }
+
+  ScopedBlock(const ScopedBlock<B>& that)
+      : block_(that.block_) {
+    if (block_)
+      block_ = Block_copy(block_);
+  }
+
+  ~ScopedBlock() {
+    if (block_)
+      Block_release(block_);
+  }
+
+  ScopedBlock& operator=(const ScopedBlock<B>& that) {
+    reset(that.get(), base::scoped_policy::RETAIN);
+    return *this;
+  }
+
+  void reset(B block = NULL,
+             base::scoped_policy::OwnershipPolicy policy =
+                 base::scoped_policy::ASSUME) {
+    if (block && policy == base::scoped_policy::RETAIN)
+      block = Block_copy(block);
+    if (block_)
+      Block_release(block_);
+    block_ = block;
+  }
+
+  bool operator==(B that) const {
+    return block_ == that;
+  }
+
+  bool operator!=(B that) const {
+    return block_ != that;
+  }
+
+  operator B() const {
+    return block_;
+  }
+
+  B get() const {
+    return block_;
+  }
+
+  void swap(ScopedBlock& that) {
+    B temp = that.block_;
+    that.block_ = block_;
+    block_ = temp;
+  }
+
+  B release() WARN_UNUSED_RESULT {
+    B temp = block_;
+    block_ = NULL;
+    return temp;
+  }
+
+ private:
+  B block_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_BLOCK_H_
diff --git a/base/mac/scoped_cffiledescriptorref.h b/base/mac/scoped_cffiledescriptorref.h
new file mode 100644
index 0000000..07196aa
--- /dev/null
+++ b/base/mac/scoped_cffiledescriptorref.h
@@ -0,0 +1,75 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
+#define BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// ScopedCFFileDescriptorRef is designed after ScopedCFTypeRef<>. On
+// destruction, it will invalidate the file descriptor.
+// ScopedCFFileDescriptorRef (unlike ScopedCFTypeRef<>) does not support RETAIN
+// semantics, copying, or assignment, as doing so would increase the chances
+// that a file descriptor is invalidated while still in use.
+class ScopedCFFileDescriptorRef {
+ public:
+  explicit ScopedCFFileDescriptorRef(CFFileDescriptorRef fdref = NULL)
+      : fdref_(fdref) {
+  }
+
+  ~ScopedCFFileDescriptorRef() {
+    if (fdref_) {
+      CFFileDescriptorInvalidate(fdref_);
+      CFRelease(fdref_);
+    }
+  }
+
+  void reset(CFFileDescriptorRef fdref = NULL) {
+    if (fdref_ == fdref)
+      return;
+    if (fdref_) {
+      CFFileDescriptorInvalidate(fdref_);
+      CFRelease(fdref_);
+    }
+    fdref_ = fdref;
+  }
+
+  bool operator==(CFFileDescriptorRef that) const {
+    return fdref_ == that;
+  }
+
+  bool operator!=(CFFileDescriptorRef that) const {
+    return fdref_ != that;
+  }
+
+  operator CFFileDescriptorRef() const {
+    return fdref_;
+  }
+
+  CFFileDescriptorRef get() const {
+    return fdref_;
+  }
+
+  CFFileDescriptorRef release() WARN_UNUSED_RESULT {
+    CFFileDescriptorRef temp = fdref_;
+    fdref_ = NULL;
+    return temp;
+  }
+
+ private:
+  CFFileDescriptorRef fdref_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCFFileDescriptorRef);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
diff --git a/base/mac/scoped_cftyperef.h b/base/mac/scoped_cftyperef.h
new file mode 100644
index 0000000..8567f85
--- /dev/null
+++ b/base/mac/scoped_cftyperef.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_CFTYPEREF_H_
+#define BASE_MAC_SCOPED_CFTYPEREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/mac/scoped_typeref.h"
+
+namespace base {
+
+// ScopedCFTypeRef<> is patterned after scoped_ptr<>, but maintains ownership
+// of a CoreFoundation object: any object that can be represented as a
+// CFTypeRef.  Style deviations here are solely for compatibility with
+// scoped_ptr<>'s interface, with which everyone is already familiar.
+//
+// By default, ScopedCFTypeRef<> takes ownership of an object (in the
+// constructor or in reset()) by taking over the caller's existing ownership
+// claim.  The caller must own the object it gives to ScopedCFTypeRef<>, and
+// relinquishes an ownership claim to that object.  ScopedCFTypeRef<> does not
+// call CFRetain(). This behavior is parameterized by the |OwnershipPolicy|
+// enum. If the value |RETAIN| is passed (in the constructor or in reset()),
+// then ScopedCFTypeRef<> will call CFRetain() on the object, and the initial
+// ownership is not changed.
+
+namespace internal {
+
+struct ScopedCFTypeRefTraits {
+  static void Retain(CFTypeRef object) {
+    CFRetain(object);
+  }
+  static void Release(CFTypeRef object) {
+    CFRelease(object);
+  }
+};
+
+}  // namespace internal
+
+template<typename CFT>
+class ScopedCFTypeRef
+    : public ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits> {
+ public:
+  typedef CFT element_type;
+
+  explicit ScopedCFTypeRef(
+      CFT object = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : ScopedTypeRef<CFT,
+                      internal::ScopedCFTypeRefTraits>(object, policy) {}
+
+  ScopedCFTypeRef(const ScopedCFTypeRef<CFT>& that)
+      : ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits>(that) {}
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFTYPEREF_H_
diff --git a/base/mac/scoped_ioobject.h b/base/mac/scoped_ioobject.h
new file mode 100644
index 0000000..854039b
--- /dev/null
+++ b/base/mac/scoped_ioobject.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_IOOBJECT_H_
+#define BASE_MAC_SCOPED_IOOBJECT_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template<typename IOT>
+class ScopedIOObject {
+ public:
+  typedef IOT element_type;
+
+  explicit ScopedIOObject(IOT object = IO_OBJECT_NULL)
+      : object_(object) {
+  }
+
+  ~ScopedIOObject() {
+    if (object_)
+      IOObjectRelease(object_);
+  }
+
+  void reset(IOT object = IO_OBJECT_NULL) {
+    if (object_)
+      IOObjectRelease(object_);
+    object_ = object;
+  }
+
+  bool operator==(IOT that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(IOT that) const {
+    return object_ != that;
+  }
+
+  operator IOT() const {
+    return object_;
+  }
+
+  IOT get() const {
+    return object_;
+  }
+
+  void swap(ScopedIOObject& that) {
+    IOT temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  IOT release() WARN_UNUSED_RESULT {
+    IOT temp = object_;
+    object_ = IO_OBJECT_NULL;
+    return temp;
+  }
+
+ private:
+  IOT object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIOObject);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOOBJECT_H_
diff --git a/base/mac/scoped_ioplugininterface.h b/base/mac/scoped_ioplugininterface.h
new file mode 100644
index 0000000..503980c
--- /dev/null
+++ b/base/mac/scoped_ioplugininterface.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
+#define BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
+// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
+template<typename T>
+class ScopedIOPluginInterface {
+ public:
+  typedef T** InterfaceT;
+  typedef InterfaceT element_type;
+
+  explicit ScopedIOPluginInterface(InterfaceT object = NULL)
+      : object_(object) {
+  }
+
+  ~ScopedIOPluginInterface() {
+    if (object_)
+      (*object_)->Release(object_);
+  }
+
+  void reset(InterfaceT object = NULL) {
+    if (object_)
+      (*object_)->Release(object_);
+    object_ = object;
+  }
+
+  bool operator==(InterfaceT that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(InterfaceT that) const {
+    return object_ != that;
+  }
+
+  operator InterfaceT() const {
+    return object_;
+  }
+
+  InterfaceT get() const {
+    return object_;
+  }
+
+  void swap(ScopedIOPluginInterface& that) {
+    InterfaceT temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  InterfaceT release() WARN_UNUSED_RESULT {
+    InterfaceT temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  InterfaceT object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIOPluginInterface);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
diff --git a/base/mac/scoped_launch_data.h b/base/mac/scoped_launch_data.h
new file mode 100644
index 0000000..e4343b8
--- /dev/null
+++ b/base/mac/scoped_launch_data.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_LAUNCH_DATA_H_
+#define BASE_MAC_SCOPED_LAUNCH_DATA_H_
+
+#include <launch.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like scoped_ptr<> but for launch_data_t.
+class ScopedLaunchData {
+ public:
+  typedef launch_data_t element_type;
+
+  explicit ScopedLaunchData(launch_data_t object = NULL)
+      : object_(object) {
+  }
+
+  ~ScopedLaunchData() {
+    if (object_)
+      launch_data_free(object_);
+  }
+
+  void reset(launch_data_t object = NULL) {
+    if (object != object_) {
+      if (object_)
+        launch_data_free(object_);
+      object_ = object;
+    }
+  }
+
+  bool operator==(launch_data_t that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(launch_data_t that) const {
+    return object_ != that;
+  }
+
+  operator launch_data_t() const {
+    return object_;
+  }
+
+  launch_data_t get() const {
+    return object_;
+  }
+
+  void swap(ScopedLaunchData& that) {
+    std::swap(object_, that.object_);
+  }
+
+  launch_data_t release() WARN_UNUSED_RESULT {
+    launch_data_t temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  launch_data_t object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_LAUNCH_DATA_H_
diff --git a/base/mac/scoped_mach_port.cc b/base/mac/scoped_mach_port.cc
new file mode 100644
index 0000000..13307f2
--- /dev/null
+++ b/base/mac/scoped_mach_port.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/scoped_mach_port.h"
+
+#include "base/mac/mach_logging.h"
+
+namespace base {
+namespace mac {
+namespace internal {
+
+// static
+void SendRightTraits::Free(mach_port_t port) {
+  kern_return_t kr = mach_port_deallocate(mach_task_self(), port);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ScopedMachSendRight mach_port_deallocate";
+}
+
+// static
+void ReceiveRightTraits::Free(mach_port_t port) {
+  kern_return_t kr =
+      mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ScopedMachReceiveRight mach_port_mod_refs";
+}
+
+// static
+void PortSetTraits::Free(mach_port_t port) {
+  kern_return_t kr =
+      mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, -1);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ScopedMachPortSet mach_port_mod_refs";
+}
+
+}  // namespace internal
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h
new file mode 100644
index 0000000..beb62b0
--- /dev/null
+++ b/base/mac/scoped_mach_port.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_MACH_PORT_H_
+#define BASE_MAC_SCOPED_MACH_PORT_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/scoped_generic.h"
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+struct BASE_EXPORT SendRightTraits {
+  static mach_port_t InvalidValue() {
+    return MACH_PORT_NULL;
+  }
+
+  BASE_EXPORT static void Free(mach_port_t port);
+};
+
+struct BASE_EXPORT ReceiveRightTraits {
+  static mach_port_t InvalidValue() {
+    return MACH_PORT_NULL;
+  }
+
+  BASE_EXPORT static void Free(mach_port_t port);
+};
+
+struct PortSetTraits {
+  static mach_port_t InvalidValue() {
+    return MACH_PORT_NULL;
+  }
+
+  BASE_EXPORT static void Free(mach_port_t port);
+};
+
+}  // namespace internal
+
+// A scoper for handling a Mach port that names a send right. Send rights are
+// reference counted, and this takes ownership of the right on construction
+// and then removes a reference to the right on destruction. If the reference
+// is the last one on the right, the right is deallocated.
+class BASE_EXPORT ScopedMachSendRight :
+    public base::ScopedGeneric<mach_port_t, internal::SendRightTraits> {
+ public:
+  explicit ScopedMachSendRight(mach_port_t port = traits_type::InvalidValue())
+      : ScopedGeneric(port) {}
+
+  operator mach_port_t() const { return get(); }
+};
+
+// A scoper for handling a Mach port's receive right. There is only one
+// receive right per port. This takes ownership of the receive right on
+// construction and then destroys the right on destruction, turning all
+// outstanding send rights into dead names.
+class BASE_EXPORT ScopedMachReceiveRight :
+    public base::ScopedGeneric<mach_port_t, internal::ReceiveRightTraits> {
+ public:
+  explicit ScopedMachReceiveRight(
+      mach_port_t port = traits_type::InvalidValue()) : ScopedGeneric(port) {}
+
+  operator mach_port_t() const { return get(); }
+};
+
+// A scoper for handling a Mach port set. A port set can have only one
+// reference. This takes ownership of that single reference on construction and
+// destroys the port set on destruction. Destroying a port set does not destroy
+// the receive rights that are members of the port set.
+class BASE_EXPORT ScopedMachPortSet :
+    public ScopedGeneric<mach_port_t, internal::PortSetTraits> {
+ public:
+  explicit ScopedMachPortSet(mach_port_t port = traits_type::InvalidValue())
+      : ScopedGeneric(port) {}
+
+  operator mach_port_t() const { return get(); }
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_PORT_H_
diff --git a/base/mac/scoped_mach_vm.cc b/base/mac/scoped_mach_vm.cc
new file mode 100644
index 0000000..d52c77f
--- /dev/null
+++ b/base/mac/scoped_mach_vm.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/scoped_mach_vm.h"
+
+namespace base {
+namespace mac {
+
+void ScopedMachVM::reset(vm_address_t address, vm_size_t size) {
+  DCHECK_EQ(address % PAGE_SIZE, 0u);
+  DCHECK_EQ(size % PAGE_SIZE, 0u);
+
+  if (size_) {
+    if (address_ < address) {
+      vm_deallocate(mach_task_self(),
+                    address_,
+                    std::min(size_, address - address_));
+    }
+    if (address_ + size_ > address + size) {
+      vm_address_t deallocate_start = std::max(address_, address + size);
+      vm_deallocate(mach_task_self(),
+                    deallocate_start,
+                    address_ + size_ - deallocate_start);
+    }
+  }
+
+  address_ = address;
+  size_ = size;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_mach_vm.h b/base/mac/scoped_mach_vm.h
new file mode 100644
index 0000000..ffc00d5
--- /dev/null
+++ b/base/mac/scoped_mach_vm.h
@@ -0,0 +1,92 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_MACH_VM_H_
+#define BASE_MAC_SCOPED_MACH_VM_H_
+
+#include <mach/mach.h>
+
+#include <algorithm>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// Use ScopedMachVM to supervise ownership of pages in the current process
+// through the Mach VM subsystem. Pages allocated with vm_allocate can be
+// released when exiting a scope with ScopedMachVM.
+//
+// The Mach VM subsystem operates on a page-by-page basis, and a single VM
+// allocation managed by a ScopedMachVM object may span multiple pages. As far
+// as Mach is concerned, allocated pages may be deallocated individually. This
+// is in contrast to higher-level allocators such as malloc, where the base
+// address of an allocation implies the size of an allocated block.
+// Consequently, it is not sufficient to just pass the base address of an
+// allocation to ScopedMachVM, it also needs to know the size of the
+// allocation. To avoid any confusion, both the base address and size must
+// be page-aligned.
+//
+// When dealing with Mach VM, base addresses will naturally be page-aligned,
+// but user-specified sizes may not be. If there's a concern that a size is
+// not page-aligned, use the mach_vm_round_page macro to correct it.
+//
+// Example:
+//
+//   vm_address_t address = 0;
+//   vm_size_t size = 12345;  // This requested size is not page-aligned.
+//   kern_return_t kr =
+//       vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE);
+//   if (kr != KERN_SUCCESS) {
+//     return false;
+//   }
+//   ScopedMachVM vm_owner(address, mach_vm_round_page(size));
+
+namespace base {
+namespace mac {
+
+class BASE_EXPORT ScopedMachVM {
+ public:
+  explicit ScopedMachVM(vm_address_t address = 0, vm_size_t size = 0)
+      : address_(address), size_(size) {
+    DCHECK_EQ(address % PAGE_SIZE, 0u);
+    DCHECK_EQ(size % PAGE_SIZE, 0u);
+  }
+
+  ~ScopedMachVM() {
+    if (size_) {
+      vm_deallocate(mach_task_self(), address_, size_);
+    }
+  }
+
+  void reset(vm_address_t address = 0, vm_size_t size = 0);
+
+  vm_address_t address() const {
+    return address_;
+  }
+
+  vm_size_t size() const {
+    return size_;
+  }
+
+  void swap(ScopedMachVM& that) {
+    std::swap(address_, that.address_);
+    std::swap(size_, that.size_);
+  }
+
+  void release() {
+    address_ = 0;
+    size_ = 0;
+  }
+
+ private:
+  vm_address_t address_;
+  vm_size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedMachVM);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_VM_H_
diff --git a/base/mac/scoped_nsautorelease_pool.h b/base/mac/scoped_nsautorelease_pool.h
new file mode 100644
index 0000000..60af71a
--- /dev/null
+++ b/base/mac/scoped_nsautorelease_pool.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
+#define BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(__OBJC__)
+@class NSAutoreleasePool;
+#else  // __OBJC__
+class NSAutoreleasePool;
+#endif  // __OBJC__
+
+namespace base {
+namespace mac {
+
+// ScopedNSAutoreleasePool allocates an NSAutoreleasePool when instantiated and
+// sends it a -drain message when destroyed.  This allows an autorelease pool to
+// be maintained in ordinary C++ code without bringing in any direct Objective-C
+// dependency.
+
+class BASE_EXPORT ScopedNSAutoreleasePool {
+ public:
+  ScopedNSAutoreleasePool();
+  ~ScopedNSAutoreleasePool();
+
+  // Clear out the pool in case its position on the stack causes it to be
+  // alive for long periods of time (such as the entire length of the app).
+  // Only use then when you're certain the items currently in the pool are
+  // no longer needed.
+  void Recycle();
+ private:
+  NSAutoreleasePool* autorelease_pool_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedNSAutoreleasePool);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
diff --git a/base/mac/scoped_nsautorelease_pool.mm b/base/mac/scoped_nsautorelease_pool.mm
new file mode 100644
index 0000000..e542ca8
--- /dev/null
+++ b/base/mac/scoped_nsautorelease_pool.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
+    : autorelease_pool_([[NSAutoreleasePool alloc] init]) {
+  DCHECK(autorelease_pool_);
+}
+
+ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() {
+  [autorelease_pool_ drain];
+}
+
+// Cycle the internal pool, allowing everything there to get cleaned up and
+// start anew.
+void ScopedNSAutoreleasePool::Recycle() {
+  [autorelease_pool_ drain];
+  autorelease_pool_ = [[NSAutoreleasePool alloc] init];
+  DCHECK(autorelease_pool_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_nsexception_enabler.h b/base/mac/scoped_nsexception_enabler.h
new file mode 100644
index 0000000..484dd53
--- /dev/null
+++ b/base/mac/scoped_nsexception_enabler.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
+#define BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+// BrowserCrApplication attempts to restrict throwing of NSExceptions
+// because they interact badly with C++ scoping rules.  Unfortunately,
+// there are some cases where exceptions must be supported, such as
+// when third-party printer drivers are used.  These helpers can be
+// used to enable exceptions for narrow windows.
+
+// Make it easy to safely allow NSException to be thrown in a limited
+// scope.  Note that if an exception is thrown, then this object will
+// not be appropriately destructed!  If the exception ends up in the
+// top-level event loop, things are cleared in -reportException:.  If
+// the exception is caught at a lower level, a higher level scoper
+// should eventually reset things.
+class BASE_EXPORT ScopedNSExceptionEnabler {
+ public:
+  ScopedNSExceptionEnabler();
+  ~ScopedNSExceptionEnabler();
+
+ private:
+  bool was_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNSExceptionEnabler);
+};
+
+// Access the exception setting for the current thread.  This is for
+// the support code in BrowserCrApplication, other code should use
+// the scoper.
+BASE_EXPORT bool GetNSExceptionsAllowed();
+BASE_EXPORT void SetNSExceptionsAllowed(bool allowed);
+
+// Executes |block| with fatal-exceptions turned off, and returns the
+// result.  If an exception is thrown during the perform, nil is
+// returned.
+typedef id (^BlockReturningId)();
+BASE_EXPORT id RunBlockIgnoringExceptions(BlockReturningId block);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
diff --git a/base/mac/scoped_nsexception_enabler.mm b/base/mac/scoped_nsexception_enabler.mm
new file mode 100644
index 0000000..7b8ad92
--- /dev/null
+++ b/base/mac/scoped_nsexception_enabler.mm
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_nsexception_enabler.h"
+
+#import "base/lazy_instance.h"
+#import "base/threading/thread_local.h"
+
+// To make the |g_exceptionsAllowed| declaration readable.
+using base::LazyInstance;
+using base::ThreadLocalBoolean;
+
+// When C++ exceptions are disabled, the C++ library defines |try| and
+// |catch| so as to allow exception-expecting C++ code to build properly when
+// language support for exceptions is not present.  These macros interfere
+// with the use of |@try| and |@catch| in Objective-C files such as this one.
+// Undefine these macros here, after everything has been #included, since
+// there will be no C++ uses and only Objective-C uses from this point on.
+#undef try
+#undef catch
+
+namespace {
+
+// Whether to allow NSExceptions to be raised on the current thread.
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_exceptionsAllowed = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+namespace mac {
+
+bool GetNSExceptionsAllowed() {
+  return g_exceptionsAllowed.Get().Get();
+}
+
+void SetNSExceptionsAllowed(bool allowed) {
+  return g_exceptionsAllowed.Get().Set(allowed);
+}
+
+id RunBlockIgnoringExceptions(BlockReturningId block) {
+  id ret = nil;
+  @try {
+    base::mac::ScopedNSExceptionEnabler enable;
+    ret = block();
+  }
+  @catch(id exception) {
+  }
+  return ret;
+}
+
+ScopedNSExceptionEnabler::ScopedNSExceptionEnabler() {
+  was_enabled_ = GetNSExceptionsAllowed();
+  SetNSExceptionsAllowed(true);
+}
+
+ScopedNSExceptionEnabler::~ScopedNSExceptionEnabler() {
+  SetNSExceptionsAllowed(was_enabled_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
new file mode 100644
index 0000000..836bdcc
--- /dev/null
+++ b/base/mac/scoped_nsobject.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
+#define BASE_MAC_SCOPED_NSOBJECT_H_
+
+// Include NSObject.h directly because Foundation.h pulls in many dependencies.
+// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
+// singled out because it is most typically included from other header files.
+#import <Foundation/NSObject.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+@class NSAutoreleasePool;
+
+namespace base {
+
+// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
+// of an NSObject subclass object.  Style deviations here are solely for
+// compatibility with scoped_ptr<>'s interface, with which everyone is already
+// familiar.
+//
+// scoped_nsobject<> takes ownership of an object (in the constructor or in
+// reset()) by taking over the caller's existing ownership claim.  The caller
+// must own the object it gives to scoped_nsobject<>, and relinquishes an
+// ownership claim to that object.  scoped_nsobject<> does not call -retain,
+// callers have to call this manually if appropriate.
+//
+// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used
+// with protocols.
+//
+// scoped_nsobject<> is not to be used for NSAutoreleasePools. For
+// NSAutoreleasePools use ScopedNSAutoreleasePool from
+// scoped_nsautorelease_pool.h instead.
+// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
+// time with a template specialization (see below).
+
+template<typename NST>
+class scoped_nsprotocol {
+ public:
+  explicit scoped_nsprotocol(NST object = nil) : object_(object) {}
+
+  scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
+      : object_([that.object_ retain]) {
+  }
+
+  template <typename NSU>
+  scoped_nsprotocol(const scoped_nsprotocol<NSU>& that)
+      : object_([that.get() retain]) {
+  }
+
+  ~scoped_nsprotocol() {
+    [object_ release];
+  }
+
+  scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
+    reset([that.get() retain]);
+    return *this;
+  }
+
+  void reset(NST object = nil) {
+    // We intentionally do not check that object != object_ as the caller must
+    // either already have an ownership claim over whatever it passes to this
+    // method, or call it with the |RETAIN| policy which will have ensured that
+    // the object is retained once more when reaching this point.
+    [object_ release];
+    object_ = object;
+  }
+
+  bool operator==(NST that) const { return object_ == that; }
+  bool operator!=(NST that) const { return object_ != that; }
+
+  operator NST() const {
+    return object_;
+  }
+
+  NST get() const {
+    return object_;
+  }
+
+  void swap(scoped_nsprotocol& that) {
+    NST temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // scoped_nsprotocol<>::release() is like scoped_ptr<>::release.  It is NOT a
+  // wrapper for [object_ release].  To force a scoped_nsprotocol<> to call
+  // [object_ release], use scoped_nsprotocol<>::reset().
+  NST release() WARN_UNUSED_RESULT {
+    NST temp = object_;
+    object_ = nil;
+    return temp;
+  }
+
+  // Shift reference to the autorelease pool to be released later.
+  NST autorelease() {
+    return [release() autorelease];
+  }
+
+ private:
+  NST object_;
+};
+
+// Free functions
+template <class C>
+void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C p1, const scoped_nsprotocol<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
+  return p1 != p2.get();
+}
+
+template<typename NST>
+class scoped_nsobject : public scoped_nsprotocol<NST*> {
+ public:
+  explicit scoped_nsobject(NST* object = nil)
+      : scoped_nsprotocol<NST*>(object) {}
+
+  scoped_nsobject(const scoped_nsobject<NST>& that)
+      : scoped_nsprotocol<NST*>(that) {
+  }
+
+  template<typename NSU>
+  scoped_nsobject(const scoped_nsobject<NSU>& that)
+      : scoped_nsprotocol<NST*>(that) {
+  }
+
+  scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
+    scoped_nsprotocol<NST*>::operator=(that);
+    return *this;
+  }
+};
+
+// Specialization to make scoped_nsobject<id> work.
+template<>
+class scoped_nsobject<id> : public scoped_nsprotocol<id> {
+ public:
+  explicit scoped_nsobject(id object = nil) : scoped_nsprotocol<id>(object) {}
+
+  scoped_nsobject(const scoped_nsobject<id>& that)
+      : scoped_nsprotocol<id>(that) {
+  }
+
+  template<typename NSU>
+  scoped_nsobject(const scoped_nsobject<NSU>& that)
+      : scoped_nsprotocol<id>(that) {
+  }
+
+  scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
+    scoped_nsprotocol<id>::operator=(that);
+    return *this;
+  }
+};
+
+// Do not use scoped_nsobject for NSAutoreleasePools, use
+// ScopedNSAutoreleasePool instead. This is a compile time check. See details
+// at top of header.
+template<>
+class scoped_nsobject<NSAutoreleasePool> {
+ private:
+  explicit scoped_nsobject(NSAutoreleasePool* object = nil);
+  DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSOBJECT_H_
diff --git a/base/mac/scoped_nsobject_unittest.mm b/base/mac/scoped_nsobject_unittest.mm
new file mode 100644
index 0000000..f290c3a
--- /dev/null
+++ b/base/mac/scoped_nsobject_unittest.mm
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(ScopedNSObjectTest, ScopedNSObject) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  ASSERT_TRUE(p1.get());
+  ASSERT_EQ(1u, [p1 retainCount]);
+  base::scoped_nsobject<NSObject> p2(p1);
+  ASSERT_EQ(p1.get(), p2.get());
+  ASSERT_EQ(2u, [p1 retainCount]);
+  p2.reset();
+  ASSERT_EQ(nil, p2.get());
+  ASSERT_EQ(1u, [p1 retainCount]);
+  {
+    base::scoped_nsobject<NSObject> p3 = p1;
+    ASSERT_EQ(p1.get(), p3.get());
+    ASSERT_EQ(2u, [p1 retainCount]);
+    p3 = p1;
+    ASSERT_EQ(p1.get(), p3.get());
+    ASSERT_EQ(2u, [p1 retainCount]);
+  }
+  ASSERT_EQ(1u, [p1 retainCount]);
+  base::scoped_nsobject<NSObject> p4([p1.get() retain]);
+  ASSERT_EQ(2u, [p1 retainCount]);
+  ASSERT_TRUE(p1 == p1.get());
+  ASSERT_TRUE(p1 == p1);
+  ASSERT_FALSE(p1 != p1);
+  ASSERT_FALSE(p1 != p1.get());
+  base::scoped_nsobject<NSObject> p5([[NSObject alloc] init]);
+  ASSERT_TRUE(p1 != p5);
+  ASSERT_TRUE(p1 != p5.get());
+  ASSERT_FALSE(p1 == p5);
+  ASSERT_FALSE(p1 == p5.get());
+
+  base::scoped_nsobject<NSObject> p6 = p1;
+  ASSERT_EQ(3u, [p6 retainCount]);
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+    p6.autorelease();
+    ASSERT_EQ(nil, p6.get());
+    ASSERT_EQ(3u, [p1 retainCount]);
+  }
+  ASSERT_EQ(2u, [p1 retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) {
+  base::scoped_nsobject<id> p([[NSObject alloc] init]);
+  ASSERT_TRUE(p.get());
+  ASSERT_EQ(1u, [p retainCount]);
+  {
+    std::vector<base::scoped_nsobject<id>> objects;
+    objects.push_back(p);
+    ASSERT_EQ(2u, [p retainCount]);
+    ASSERT_EQ(p.get(), objects[0].get());
+    objects.push_back(base::scoped_nsobject<id>([[NSObject alloc] init]));
+    ASSERT_TRUE(objects[1].get());
+    ASSERT_EQ(1u, [objects[1] retainCount]);
+  }
+  ASSERT_EQ(1u, [p retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectFreeFunctions) {
+  base::scoped_nsobject<id> p1([[NSObject alloc] init]);
+  id o1 = p1.get();
+  ASSERT_TRUE(o1 == p1);
+  ASSERT_FALSE(o1 != p1);
+  base::scoped_nsobject<id> p2([[NSObject alloc] init]);
+  ASSERT_TRUE(o1 != p2);
+  ASSERT_FALSE(o1 == p2);
+  id o2 = p2.get();
+  swap(p1, p2);
+  ASSERT_EQ(o2, p1.get());
+  ASSERT_EQ(o1, p2.get());
+}
+
+}  // namespace
diff --git a/base/mac/scoped_objc_class_swizzler.h b/base/mac/scoped_objc_class_swizzler.h
new file mode 100644
index 0000000..e18e4ab
--- /dev/null
+++ b/base/mac/scoped_objc_class_swizzler.h
@@ -0,0 +1,49 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_OBJC_CLASS_SWIZZLER_H_
+#define BASE_MAC_SCOPED_OBJC_CLASS_SWIZZLER_H_
+
+#import <objc/runtime.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace mac {
+
+// Within a given scope, swaps method implementations of a class interface, or
+// between two class interfaces. The argument and return types must match.
+class BASE_EXPORT ScopedObjCClassSwizzler {
+ public:
+  // Given two classes that each respond to |selector|, swap the implementations
+  // of those methods.
+  ScopedObjCClassSwizzler(Class target, Class source, SEL selector);
+
+  // Given two selectors on the same class interface, |target| (e.g. via
+  // inheritance or categories), swap the implementations of methods |original|
+  // and |alternate|.
+  ScopedObjCClassSwizzler(Class target, SEL original, SEL alternate);
+
+  ~ScopedObjCClassSwizzler();
+
+  // Return a callable function pointer for the replaced method. To call this
+  // from the replacing function, the first two arguments should be |self| and
+  // |_cmd|. These are followed by the (variadic) method arguments.
+  IMP GetOriginalImplementation();
+
+ private:
+  // Delegated constructor.
+  void Init(Class target, Class source, SEL original, SEL alternate);
+
+  Method old_selector_impl_;
+  Method new_selector_impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedObjCClassSwizzler);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_OBJC_CLASS_SWIZZLER_H_
diff --git a/base/mac/scoped_objc_class_swizzler.mm b/base/mac/scoped_objc_class_swizzler.mm
new file mode 100644
index 0000000..20e5c56
--- /dev/null
+++ b/base/mac/scoped_objc_class_swizzler.mm
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_objc_class_swizzler.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
+                                                 Class source,
+                                                 SEL selector)
+    : old_selector_impl_(NULL), new_selector_impl_(NULL) {
+  Init(target, source, selector, selector);
+}
+
+ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
+                                                 SEL original,
+                                                 SEL alternate)
+    : old_selector_impl_(NULL), new_selector_impl_(NULL) {
+  Init(target, target, original, alternate);
+}
+
+ScopedObjCClassSwizzler::~ScopedObjCClassSwizzler() {
+  if (old_selector_impl_ && new_selector_impl_)
+    method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
+}
+
+IMP ScopedObjCClassSwizzler::GetOriginalImplementation() {
+  // Note that while the swizzle is in effect the "new" method is actually
+  // pointing to the original implementation, since they have been swapped.
+  return method_getImplementation(new_selector_impl_);
+}
+
+void ScopedObjCClassSwizzler::Init(Class target,
+                                   Class source,
+                                   SEL original,
+                                   SEL alternate) {
+  old_selector_impl_ = class_getInstanceMethod(target, original);
+  new_selector_impl_ = class_getInstanceMethod(source, alternate);
+  if (!old_selector_impl_ && !new_selector_impl_) {
+    // Try class methods.
+    old_selector_impl_ = class_getClassMethod(target, original);
+    new_selector_impl_ = class_getClassMethod(source, alternate);
+  }
+
+  DCHECK(old_selector_impl_);
+  DCHECK(new_selector_impl_);
+  if (!old_selector_impl_ || !new_selector_impl_)
+    return;
+
+  // The argument and return types must match exactly.
+  const char* old_types = method_getTypeEncoding(old_selector_impl_);
+  const char* new_types = method_getTypeEncoding(new_selector_impl_);
+  DCHECK(old_types);
+  DCHECK(new_types);
+  DCHECK_EQ(0, strcmp(old_types, new_types));
+  if (!old_types || !new_types || strcmp(old_types, new_types)) {
+    old_selector_impl_ = new_selector_impl_ = NULL;
+    return;
+  }
+
+  method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_objc_class_swizzler_unittest.mm b/base/mac/scoped_objc_class_swizzler_unittest.mm
new file mode 100644
index 0000000..eacd105
--- /dev/null
+++ b/base/mac/scoped_objc_class_swizzler_unittest.mm
@@ -0,0 +1,166 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_objc_class_swizzler.h"
+
+#import "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface ObjCClassSwizzlerTestOne : NSObject
++ (NSInteger)function;
+- (NSInteger)method;
+- (NSInteger)modifier;
+@end
+
+@interface ObjCClassSwizzlerTestTwo : NSObject
++ (NSInteger)function;
+- (NSInteger)method;
+- (NSInteger)modifier;
+@end
+
+@implementation ObjCClassSwizzlerTestOne : NSObject
+
++ (NSInteger)function {
+  return 10;
+}
+
+- (NSInteger)method {
+  // Multiply by a modifier to ensure |self| in a swizzled implementation
+  // refers to the original object.
+  return 1 * [self modifier];
+}
+
+- (NSInteger)modifier {
+  return 3;
+}
+
+@end
+
+@implementation ObjCClassSwizzlerTestTwo : NSObject
+
++ (NSInteger)function {
+  return 20;
+}
+
+- (NSInteger)method {
+  return 2 * [self modifier];
+}
+
+- (NSInteger)modifier {
+  return 7;
+}
+
+@end
+
+@interface ObjCClassSwizzlerTestOne (AlternateCategory)
+- (NSInteger)alternate;
+@end
+
+@implementation ObjCClassSwizzlerTestOne (AlternateCategory)
+- (NSInteger)alternate {
+  return 3 * [self modifier];
+}
+@end
+
+@interface ObjCClassSwizzlerTestOneChild : ObjCClassSwizzlerTestOne
+- (NSInteger)childAlternate;
+@end
+
+@implementation ObjCClassSwizzlerTestOneChild
+- (NSInteger)childAlternate {
+  return 5 * [self modifier];
+}
+@end
+
+namespace base {
+namespace mac {
+
+TEST(ObjCClassSwizzlerTest, SwizzleInstanceMethods) {
+  base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
+      [[ObjCClassSwizzlerTestOne alloc] init]);
+  base::scoped_nsobject<ObjCClassSwizzlerTestTwo> object_two(
+      [[ObjCClassSwizzlerTestTwo alloc] init]);
+  EXPECT_EQ(3, [object_one method]);
+  EXPECT_EQ(14, [object_two method]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOne class],
+        [ObjCClassSwizzlerTestTwo class],
+        @selector(method));
+    EXPECT_EQ(6, [object_one method]);
+    EXPECT_EQ(7, [object_two method]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(3);
+    EXPECT_EQ(expected_result, original(object_one, @selector(method)));
+  }
+
+  EXPECT_EQ(3, [object_one method]);
+  EXPECT_EQ(14, [object_two method]);
+}
+
+TEST(ObjCClassSwizzlerTest, SwizzleClassMethods) {
+  EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
+  EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOne class],
+        [ObjCClassSwizzlerTestTwo class],
+        @selector(function));
+    EXPECT_EQ(20, [ObjCClassSwizzlerTestOne function]);
+    EXPECT_EQ(10, [ObjCClassSwizzlerTestTwo function]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(10);
+    EXPECT_EQ(expected_result, original(nil, @selector(function)));
+  }
+
+  EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
+  EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
+}
+
+TEST(ObjCClassSwizzlerTest, SwizzleViaCategory) {
+  base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
+      [[ObjCClassSwizzlerTestOne alloc] init]);
+  EXPECT_EQ(3, [object_one method]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOne class],
+        @selector(method),
+        @selector(alternate));
+    EXPECT_EQ(9, [object_one method]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(3);
+    EXPECT_EQ(expected_result, original(object_one, @selector(method)));
+  }
+
+  EXPECT_EQ(3, [object_one method]);
+}
+
+TEST(ObjCClassSwizzlerTest, SwizzleViaInheritance) {
+  base::scoped_nsobject<ObjCClassSwizzlerTestOneChild> child(
+      [[ObjCClassSwizzlerTestOneChild alloc] init]);
+  EXPECT_EQ(3, [child method]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOneChild class],
+        @selector(method),
+        @selector(childAlternate));
+    EXPECT_EQ(15, [child method]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(3);
+    EXPECT_EQ(expected_result, original(child, @selector(method)));
+  }
+
+  EXPECT_EQ(3, [child method]);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_sending_event.h b/base/mac/scoped_sending_event.h
new file mode 100644
index 0000000..92c2155
--- /dev/null
+++ b/base/mac/scoped_sending_event.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_SENDING_EVENT_H_
+#define BASE_MAC_SCOPED_SENDING_EVENT_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/message_loop/message_pump_mac.h"
+
+// Nested event loops can pump IPC messages, including
+// script-initiated tab closes, which could release objects that the
+// nested event loop might message.  CrAppProtocol defines how to ask
+// the embedding NSApplication subclass if an event is currently being
+// handled, in which case such closes are deferred to the top-level
+// event loop.
+//
+// ScopedSendingEvent allows script-initiated event loops to work like
+// a nested event loop, as such events do not arrive via -sendEvent:.
+// CrAppControlProtocol lets ScopedSendingEvent tell the embedding
+// NSApplication what to return from -handlingSendEvent.
+
+@protocol CrAppControlProtocol<CrAppProtocol>
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+@end
+
+namespace base {
+namespace mac {
+
+class BASE_EXPORT ScopedSendingEvent {
+ public:
+  ScopedSendingEvent();
+  ~ScopedSendingEvent();
+
+ private:
+  // The NSApp in control at the time the constructor was run, to be
+  // sure the |handling_| setting is restored appropriately.
+  NSObject<CrAppControlProtocol>* app_;
+  BOOL handling_;  // Value of -[app_ handlingSendEvent] at construction.
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_SENDING_EVENT_H_
diff --git a/base/mac/scoped_sending_event.mm b/base/mac/scoped_sending_event.mm
new file mode 100644
index 0000000..c3813d8
--- /dev/null
+++ b/base/mac/scoped_sending_event.mm
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_sending_event.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedSendingEvent::ScopedSendingEvent()
+    : app_(static_cast<NSObject<CrAppControlProtocol>*>(NSApp)) {
+  DCHECK([app_ conformsToProtocol:@protocol(CrAppControlProtocol)]);
+  handling_ = [app_ isHandlingSendEvent];
+  [app_ setHandlingSendEvent:YES];
+}
+
+ScopedSendingEvent::~ScopedSendingEvent() {
+  [app_ setHandlingSendEvent:handling_];
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm
new file mode 100644
index 0000000..02ef2db
--- /dev/null
+++ b/base/mac/scoped_sending_event_unittest.mm
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_sending_event.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface ScopedSendingEventTestCrApp : NSObject <CrAppControlProtocol> {
+ @private
+  BOOL handlingSendEvent_;
+}
+@property(nonatomic, assign, getter=isHandlingSendEvent) BOOL handlingSendEvent;
+@end
+
+@implementation ScopedSendingEventTestCrApp
+@synthesize handlingSendEvent = handlingSendEvent_;
+@end
+
+namespace {
+
+class ScopedSendingEventTest : public testing::Test {
+ public:
+  ScopedSendingEventTest() : app_([[ScopedSendingEventTestCrApp alloc] init]) {
+    NSApp = app_.get();
+  }
+  ~ScopedSendingEventTest() override { NSApp = nil; }
+
+ private:
+  base::scoped_nsobject<ScopedSendingEventTestCrApp> app_;
+};
+
+// Sets the flag within scope, resets when leaving scope.
+TEST_F(ScopedSendingEventTest, SetHandlingSendEvent) {
+  id<CrAppProtocol> app = NSApp;
+  EXPECT_FALSE([app isHandlingSendEvent]);
+  {
+    base::mac::ScopedSendingEvent is_handling_send_event;
+    EXPECT_TRUE([app isHandlingSendEvent]);
+  }
+  EXPECT_FALSE([app isHandlingSendEvent]);
+}
+
+// Nested call restores previous value rather than resetting flag.
+TEST_F(ScopedSendingEventTest, NestedSetHandlingSendEvent) {
+  id<CrAppProtocol> app = NSApp;
+  EXPECT_FALSE([app isHandlingSendEvent]);
+  {
+    base::mac::ScopedSendingEvent is_handling_send_event;
+    EXPECT_TRUE([app isHandlingSendEvent]);
+    {
+      base::mac::ScopedSendingEvent nested_is_handling_send_event;
+      EXPECT_TRUE([app isHandlingSendEvent]);
+    }
+    EXPECT_TRUE([app isHandlingSendEvent]);
+  }
+  EXPECT_FALSE([app isHandlingSendEvent]);
+}
+
+}  // namespace
diff --git a/base/mac/scoped_typeref.h b/base/mac/scoped_typeref.h
new file mode 100644
index 0000000..61ee311
--- /dev/null
+++ b/base/mac/scoped_typeref.h
@@ -0,0 +1,132 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_TYPEREF_H_
+#define BASE_MAC_SCOPED_TYPEREF_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_policy.h"
+
+namespace base {
+
+// ScopedTypeRef<> is patterned after scoped_ptr<>, but maintains a ownership
+// of a reference to any type that is maintained by Retain and Release methods.
+//
+// The Traits structure must provide the Retain and Release methods for type T.
+// A default ScopedTypeRefTraits is used but not defined, and should be defined
+// for each type to use this interface. For example, an appropriate definition
+// of ScopedTypeRefTraits for CGLContextObj would be:
+//
+//   template<>
+//   struct ScopedTypeRefTraits<CGLContextObj> {
+//     void Retain(CGLContextObj object) { CGLContextRetain(object); }
+//     void Release(CGLContextObj object) { CGLContextRelease(object); }
+//   };
+//
+// For the many types that have pass-by-pointer create functions, the function
+// InitializeInto() is provided to allow direct initialization and assumption
+// of ownership of the object. For example, continuing to use the above
+// CGLContextObj specialization:
+//
+//   base::ScopedTypeRef<CGLContextObj> context;
+//   CGLCreateContext(pixel_format, share_group, context.InitializeInto());
+//
+// For initialization with an existing object, the caller may specify whether
+// the ScopedTypeRef<> being initialized is assuming the caller's existing
+// ownership of the object (and should not call Retain in initialization) or if
+// it should not assume this ownership and must create its own (by calling
+// Retain in initialization). This behavior is based on the |policy| parameter,
+// with |ASSUME| for the former and |RETAIN| for the latter. The default policy
+// is to |ASSUME|.
+
+template<typename T>
+struct ScopedTypeRefTraits;
+
+template<typename T, typename Traits = ScopedTypeRefTraits<T>>
+class ScopedTypeRef {
+ public:
+  typedef T element_type;
+
+  ScopedTypeRef(
+      T object = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : object_(object) {
+    if (object_ && policy == base::scoped_policy::RETAIN)
+      Traits::Retain(object_);
+  }
+
+  ScopedTypeRef(const ScopedTypeRef<T, Traits>& that)
+      : object_(that.object_) {
+    if (object_)
+      Traits::Retain(object_);
+  }
+
+  ~ScopedTypeRef() {
+    if (object_)
+      Traits::Release(object_);
+  }
+
+  ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) {
+    reset(that.get(), base::scoped_policy::RETAIN);
+    return *this;
+  }
+
+  // This is to be used only to take ownership of objects that are created
+  // by pass-by-pointer create functions. To enforce this, require that the
+  // object be reset to NULL before this may be used.
+  T* InitializeInto() WARN_UNUSED_RESULT {
+    DCHECK(!object_);
+    return &object_;
+  }
+
+  void reset(T object = NULL,
+             base::scoped_policy::OwnershipPolicy policy =
+                base::scoped_policy::ASSUME) {
+    if (object && policy == base::scoped_policy::RETAIN)
+      Traits::Retain(object);
+    if (object_)
+      Traits::Release(object_);
+    object_ = object;
+  }
+
+  bool operator==(T that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(T that) const {
+    return object_ != that;
+  }
+
+  operator T() const {
+    return object_;
+  }
+
+  T get() const {
+    return object_;
+  }
+
+  void swap(ScopedTypeRef& that) {
+    T temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // ScopedTypeRef<>::release() is like scoped_ptr<>::release.  It is NOT
+  // a wrapper for Release().  To force a ScopedTypeRef<> object to call
+  // Release(), use ScopedTypeRef<>::reset().
+  T release() WARN_UNUSED_RESULT {
+    T temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  T object_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_TYPEREF_H_
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
new file mode 100644
index 0000000..d7be320
--- /dev/null
+++ b/base/mac/sdk_forward_declarations.h
@@ -0,0 +1,535 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains forward declarations for items in later SDKs than the
+// default one with which Chromium is built (currently 10.6).
+// If you call any function from this header, be sure to check at runtime for
+// respondsToSelector: before calling these functions (else your code will crash
+// on older OS X versions that chrome still supports).
+
+#ifndef BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
+#define BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
+
+#import <AppKit/AppKit.h>
+#import <CoreWLAN/CoreWLAN.h>
+#import <ImageCaptureCore/ImageCaptureCore.h>
+#import <IOBluetooth/IOBluetooth.h>
+
+#include "base/base_export.h"
+
+// ----------------------------------------------------------------------------
+// Either define or forward declare classes only available in OSX 10.7+.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface CWChannel : NSObject
+@end
+
+@interface CBPeripheral : NSObject
+@end
+
+@interface CBCentralManager : NSObject
+@end
+
+@interface CBUUID : NSObject
+@end
+
+#else
+
+@class CWChannel;
+@class CBPeripheral;
+@class CBCentralManager;
+@class CBUUID;
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+@interface NSUUID : NSObject
+@end
+
+#else
+
+@class NSUUID;
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+// NSProgress is public API in 10.9, but a version of it exists and is usable
+// in 10.8.
+@interface NSProgress : NSObject
+@end
+
+@interface NSAppearance : NSObject
+@end
+
+#else
+
+@class NSProgress;
+@class NSAppearance;
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity : NSObject
+@end
+
+#else
+
+@class NSUserActivity;
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Define typedefs, enums, and protocols not available in the version of the
+// OSX SDK being compiled against.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+enum {
+  NSEventPhaseNone = 0,  // event not associated with a phase.
+  NSEventPhaseBegan = 0x1 << 0,
+  NSEventPhaseStationary = 0x1 << 1,
+  NSEventPhaseChanged = 0x1 << 2,
+  NSEventPhaseEnded = 0x1 << 3,
+  NSEventPhaseCancelled = 0x1 << 4
+};
+typedef NSUInteger NSEventPhase;
+
+enum {
+  NSFullScreenWindowMask = 1 << 14,
+};
+
+enum {
+  NSApplicationPresentationFullScreen = 1 << 10,
+};
+
+enum {
+  NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
+  NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8,
+};
+
+enum {
+  NSEventSwipeTrackingLockDirection = 0x1 << 0,
+  NSEventSwipeTrackingClampGestureAmount = 0x1 << 1,
+};
+typedef NSUInteger NSEventSwipeTrackingOptions;
+
+enum {
+  NSWindowAnimationBehaviorDefault = 0,
+  NSWindowAnimationBehaviorNone = 2,
+  NSWindowAnimationBehaviorDocumentWindow = 3,
+  NSWindowAnimationBehaviorUtilityWindow = 4,
+  NSWindowAnimationBehaviorAlertPanel = 5
+};
+typedef NSInteger NSWindowAnimationBehavior;
+
+enum {
+  NSWindowDocumentVersionsButton = 6,
+  NSWindowFullScreenButton,
+};
+typedef NSUInteger NSWindowButton;
+
+enum CWChannelBand {
+  kCWChannelBandUnknown = 0,
+  kCWChannelBand2GHz = 1,
+  kCWChannelBand5GHz = 2,
+};
+
+enum {
+  kCWSecurityNone = 0,
+  kCWSecurityWEP = 1,
+  kCWSecurityWPAPersonal = 2,
+  kCWSecurityWPAPersonalMixed = 3,
+  kCWSecurityWPA2Personal = 4,
+  kCWSecurityPersonal = 5,
+  kCWSecurityDynamicWEP = 6,
+  kCWSecurityWPAEnterprise = 7,
+  kCWSecurityWPAEnterpriseMixed = 8,
+  kCWSecurityWPA2Enterprise = 9,
+  kCWSecurityEnterprise = 10,
+  kCWSecurityUnknown = NSIntegerMax,
+};
+
+typedef NSInteger CWSecurity;
+
+enum {
+  kBluetoothFeatureLESupportedController = (1 << 6L),
+};
+
+@protocol IOBluetoothDeviceInquiryDelegate
+- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
+- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
+                          device:(IOBluetoothDevice*)device;
+- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
+                        error:(IOReturn)error
+                      aborted:(BOOL)aborted;
+@end
+
+@protocol NSWindowDelegateFullScreenAdditions
+- (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
+- (void)windowDidFailToExitFullScreen:(NSWindow*)window;
+@end
+
+enum {
+  CBPeripheralStateDisconnected = 0,
+  CBPeripheralStateConnecting,
+  CBPeripheralStateConnected,
+};
+typedef NSInteger CBPeripheralState;
+
+enum {
+  CBCentralManagerStateUnknown = 0,
+  CBCentralManagerStateResetting,
+  CBCentralManagerStateUnsupported,
+  CBCentralManagerStateUnauthorized,
+  CBCentralManagerStatePoweredOff,
+  CBCentralManagerStatePoweredOn,
+};
+typedef NSInteger CBCentralManagerState;
+
+@protocol CBCentralManagerDelegate;
+
+@protocol CBCentralManagerDelegate<NSObject>
+- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
+- (void)centralManager:(CBCentralManager*)central
+    didDiscoverPeripheral:(CBPeripheral*)peripheral
+        advertisementData:(NSDictionary*)advertisementData
+                     RSSI:(NSNumber*)RSSI;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+enum { NSEventPhaseMayBegin = 0x1 << 5 };
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+enum {
+  NSWindowOcclusionStateVisible = 1UL << 1,
+};
+typedef NSUInteger NSWindowOcclusionState;
+
+enum { NSWorkspaceLaunchWithErrorPresentation = 0x00000040 };
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+// ----------------------------------------------------------------------------
+// Define NSStrings only available in newer versions of the OSX SDK to force
+// them to be statically linked.
+// ----------------------------------------------------------------------------
+
+extern "C" {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+BASE_EXPORT extern NSString* const NSWindowWillEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowWillExitFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidExitFullScreenNotification;
+BASE_EXPORT extern NSString* const
+    NSWindowDidChangeBackingPropertiesNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataServiceDataKey;
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern NSString* const NSWindowDidChangeOcclusionStateNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataIsConnectable;
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+BASE_EXPORT extern NSString* const NSUserActivityTypeBrowsingWeb;
+BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
+#endif  // MAC_OS_X_VERSION_10_10
+}  // extern "C"
+
+// ----------------------------------------------------------------------------
+// If compiling against an older version of the OSX SDK, declare functions that
+// are available in newer versions of the OSX SDK. If compiling against a newer
+// version of the OSX SDK, redeclare those same functions to suppress
+// -Wpartial-availability warnings.
+// ----------------------------------------------------------------------------
+
+// Once Chrome no longer supports OSX 10.6, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+
+@interface NSEvent (LionSDK)
++ (BOOL)isSwipeTrackingFromScrollEventsEnabled;
+- (NSEventPhase)momentumPhase;
+- (NSEventPhase)phase;
+- (BOOL)hasPreciseScrollingDeltas;
+- (CGFloat)scrollingDeltaX;
+- (CGFloat)scrollingDeltaY;
+- (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options
+          dampenAmountThresholdMin:(CGFloat)minDampenThreshold
+                               max:(CGFloat)maxDampenThreshold
+                      usingHandler:(void (^)(CGFloat gestureAmount,
+                                             NSEventPhase phase,
+                                             BOOL isComplete,
+                                             BOOL* stop))trackingHandler;
+- (BOOL)isDirectionInvertedFromDevice;
+@end
+
+@interface NSApplication (LionSDK)
+- (void)disableRelaunchOnLogin;
+@end
+
+@interface CALayer (LionSDK)
+- (CGFloat)contentsScale;
+- (void)setContentsScale:(CGFloat)contentsScale;
+@end
+
+@interface NSScreen (LionSDK)
+- (CGFloat)backingScaleFactor;
+- (NSRect)convertRectToBacking:(NSRect)aRect;
+@end
+
+@interface NSWindow (LionSDK)
+- (CGFloat)backingScaleFactor;
+- (NSWindowAnimationBehavior)animationBehavior;
+- (void)setAnimationBehavior:(NSWindowAnimationBehavior)newAnimationBehavior;
+- (void)toggleFullScreen:(id)sender;
+- (void)setRestorable:(BOOL)flag;
+- (NSRect)convertRectFromScreen:(NSRect)aRect;
+@end
+
+@interface NSCursor (LionSDKDeclarations)
++ (NSCursor*)IBeamCursorForVerticalLayout;
+@end
+
+@interface NSAnimationContext (LionSDK)
++ (void)runAnimationGroup:(void (^)(NSAnimationContext* context))changes
+        completionHandler:(void (^)(void))completionHandler;
+@property(copy) void (^completionHandler)(void);
+@end
+
+@interface NSView (LionSDK)
+- (NSSize)convertSizeFromBacking:(NSSize)size;
+- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
+@end
+
+@interface NSObject (ICCameraDeviceDelegateLionSDK)
+- (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device;
+- (void)didDownloadFile:(ICCameraFile*)file
+                  error:(NSError*)error
+                options:(NSDictionary*)options
+            contextInfo:(void*)contextInfo;
+@end
+
+@interface NSScroller (LionSDK)
++ (NSInteger)preferredScrollerStyle;
+@end
+
+@interface CWInterface (LionSDK)
+- (BOOL)associateToNetwork:(CWNetwork*)network
+                  password:(NSString*)password
+                     error:(NSError**)error;
+- (NSSet*)scanForNetworksWithName:(NSString*)networkName error:(NSError**)error;
+@end
+
+@interface CWChannel (LionSDK)
+@property(readonly) CWChannelBand channelBand;
+@end
+
+@interface CWNetwork (LionSDK)
+@property(readonly) CWChannel* wlanChannel;
+@property(readonly) NSInteger rssiValue;
+- (BOOL)supportsSecurity:(CWSecurity)security;
+@end
+
+@interface IOBluetoothHostController (LionSDK)
+- (NSString*)nameAsString;
+- (BluetoothHCIPowerState)powerState;
+@end
+
+@interface IOBluetoothL2CAPChannel (LionSDK)
+@property(readonly) BluetoothL2CAPMTU outgoingMTU;
+@end
+
+@interface IOBluetoothDevice (LionSDK)
+- (NSString*)addressString;
+- (unsigned int)classOfDevice;
+- (BluetoothConnectionHandle)connectionHandle;
+- (BluetoothHCIRSSIValue)rawRSSI;
+- (NSArray*)services;
+- (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids;
+@end
+
+@interface CBPeripheral (LionSDK)
+@property(readonly, nonatomic) CFUUIDRef UUID;
+@property(retain, readonly) NSString* name;
+@property(readonly) BOOL isConnected;
+@end
+
+@interface CBCentralManager (LionSDK)
+@property(readonly) CBCentralManagerState state;
+- (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate
+                 queue:(dispatch_queue_t)queue;
+- (void)scanForPeripheralsWithServices:(NSArray*)serviceUUIDs
+                               options:(NSDictionary*)options;
+- (void)stopScan;
+@end
+
+@interface CBUUID (LionSDK)
+@property(nonatomic, readonly) NSData* data;
++ (CBUUID*)UUIDWithString:(NSString*)theString;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+// Once Chrome no longer supports OSX 10.7, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
+
+@interface NSColor (MountainLionSDK)
+- (CGColorRef)CGColor;
+@end
+
+@interface NSUUID (MountainLionSDK)
+- (NSString*)UUIDString;
+@end
+
+@interface NSControl (MountainLionSDK)
+@property BOOL allowsExpansionToolTips;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+// Once Chrome no longer supports OSX 10.8, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+
+@interface NSProgress (MavericksSDK)
+
+- (instancetype)initWithParent:(NSProgress*)parentProgressOrNil
+                      userInfo:(NSDictionary*)userInfoOrNil;
+@property(copy) NSString* kind;
+
+@property int64_t totalUnitCount;
+@property int64_t completedUnitCount;
+
+@property(getter=isCancellable) BOOL cancellable;
+@property(getter=isPausable) BOOL pausable;
+@property(readonly, getter=isCancelled) BOOL cancelled;
+@property(readonly, getter=isPaused) BOOL paused;
+@property(copy) void (^cancellationHandler)(void);
+@property(copy) void (^pausingHandler)(void);
+- (void)cancel;
+- (void)pause;
+
+- (void)setUserInfoObject:(id)objectOrNil forKey:(NSString*)key;
+- (NSDictionary*)userInfo;
+
+@property(readonly, getter=isIndeterminate) BOOL indeterminate;
+@property(readonly) double fractionCompleted;
+
+- (void)publish;
+- (void)unpublish;
+
+@end
+
+@interface NSScreen (MavericksSDK)
++ (BOOL)screensHaveSeparateSpaces;
+@end
+
+@interface NSView (MavericksSDK)
+- (void)setCanDrawSubviewsIntoLayer:(BOOL)flag;
+- (NSAppearance*)effectiveAppearance;
+@end
+
+@interface NSWindow (MavericksSDK)
+- (NSWindowOcclusionState)occlusionState;
+@end
+
+@interface NSAppearance (MavericksSDK)
++ (id<NSObject>)appearanceNamed:(NSString*)name;
+@end
+
+@interface CBPeripheral (MavericksSDK)
+@property(readonly, nonatomic) NSUUID* identifier;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+// Once Chrome no longer supports OSX 10.9, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity (YosemiteSDK)
+
+@property(readonly, copy) NSString* activityType;
+@property(copy) NSDictionary* userInfo;
+@property(copy) NSURL* webpageURL;
+
+- (instancetype)initWithActivityType:(NSString*)activityType;
+- (void)becomeCurrent;
+- (void)invalidate;
+
+@end
+
+@interface CBUUID (YosemiteSDK)
+- (NSString*)UUIDString;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Chrome uses -[CWNetwork securityMode] and -[CWNetwork rssi] on OSX 10.6. The
+// former method relies on the enum CWSecurityMode which was removed in the OSX
+// 10.9 SDK. In order for Chrome to compile against an OSX 10.9+ SDK, Chrome
+// must define this enum. Chrome must also declare these methods.
+//
+// These declarations and definitions will not be necessary once Chrome no
+// longer runs on OSX 10.6.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6
+typedef enum {
+  kCWSecurityModeOpen = 0,
+  kCWSecurityModeWEP,
+  kCWSecurityModeWPA_PSK,
+  kCWSecurityModeWPA2_PSK,
+  kCWSecurityModeWPA_Enterprise,
+  kCWSecurityModeWPA2_Enterprise,
+  kCWSecurityModeWPS,
+  kCWSecurityModeDynamicWEP
+} CWSecurityMode;
+
+@interface CWNetwork (SnowLeopardSDK)
+@property(readonly) NSNumber* rssi;
+@property(readonly) NSNumber* securityMode;
+@end
+#endif
+
+// ----------------------------------------------------------------------------
+// The symbol for kCWSSIDDidChangeNotification is available in the
+// CoreWLAN.framework for OSX versions 10.6 through 10.10. The symbol is not
+// declared in the OSX 10.9+ SDK, so when compiling against an OSX 10.9+ SDK,
+// declare the symbol.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
+#endif
+#endif  // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
diff --git a/base/mac/sdk_forward_declarations.mm b/base/mac/sdk_forward_declarations.mm
new file mode 100644
index 0000000..347e87c
--- /dev/null
+++ b/base/mac/sdk_forward_declarations.mm
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/sdk_forward_declarations.h"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+NSString* const NSWindowWillEnterFullScreenNotification =
+    @"NSWindowWillEnterFullScreenNotification";
+
+NSString* const NSWindowWillExitFullScreenNotification =
+    @"NSWindowWillExitFullScreenNotification";
+
+NSString* const NSWindowDidEnterFullScreenNotification =
+    @"NSWindowDidEnterFullScreenNotification";
+
+NSString* const NSWindowDidExitFullScreenNotification =
+    @"NSWindowDidExitFullScreenNotification";
+
+NSString* const NSWindowDidChangeBackingPropertiesNotification =
+    @"NSWindowDidChangeBackingPropertiesNotification";
+
+NSString* const CBAdvertisementDataServiceDataKey = @"kCBAdvDataServiceData";
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+NSString* const NSWindowDidChangeOcclusionStateNotification =
+    @"NSWindowDidChangeOcclusionStateNotification";
+
+NSString* const CBAdvertisementDataIsConnectable = @"kCBAdvDataIsConnectable";
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+NSString* const NSUserActivityTypeBrowsingWeb =
+    @"NSUserActivityTypeBrowsingWeb";
+
+NSString* const NSAppearanceNameVibrantDark = @"NSAppearanceNameVibrantDark";
+#endif  // MAC_OS_X_VERSION_10_10
diff --git a/base/macros.h b/base/macros.h
new file mode 100644
index 0000000..d904328
--- /dev/null
+++ b/base/macros.h
@@ -0,0 +1,198 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains macros and macro-like constructs (e.g., templates) that
+// are commonly used throughout Chromium source. (It may also contain things
+// that are closely related to things that are commonly used that belong in this
+// file.)
+
+#ifndef BASE_MACROS_H_
+#define BASE_MACROS_H_
+
+#include <stddef.h>  // For size_t.
+#include <string.h>  // For memcpy.
+
+// Put this in the private: declarations for a class to be uncopyable.
+#define DISALLOW_COPY(TypeName) \
+  TypeName(const TypeName&)
+
+// Put this in the private: declarations for a class to be unassignable.
+#define DISALLOW_ASSIGN(TypeName) \
+  void operator=(const TypeName&)
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+// An older, deprecated, politically incorrect name for the above.
+// NOTE: The usage of this macro was banned from our code base, but some
+// third_party libraries are yet using it.
+// TODO(tfarina): Figure out how to fix the usage of this macro in the
+// third_party libraries and get rid of it.
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.  If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertible to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(arraysize(content_type_names) == CONTENT_NUM_TYPES,
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+#undef COMPILE_ASSERT
+#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
+
+// bit_cast<Dest,Source> is a template function that implements the
+// equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in
+// very low-level functions like the protobuf library and fast math
+// support.
+//
+//   float f = 3.14159265358979;
+//   int i = bit_cast<int32>(f);
+//   // i = 0x40490fdb
+//
+// The classical address-casting method is:
+//
+//   // WRONG
+//   float f = 3.14159265358979;            // WRONG
+//   int i = * reinterpret_cast<int*>(&f);  // WRONG
+//
+// The address-casting method actually produces undefined behavior
+// according to ISO C++ specification section 3.10 -15 -.  Roughly, this
+// section says: if an object in memory has one type, and a program
+// accesses it with a different type, then the result is undefined
+// behavior for most values of "different type".
+//
+// This is true for any cast syntax, either *(int*)&f or
+// *reinterpret_cast<int*>(&f).  And it is particularly true for
+// conversions between integral lvalues and floating-point lvalues.
+//
+// The purpose of 3.10 -15- is to allow optimizing compilers to assume
+// that expressions with different types refer to different memory.  gcc
+// 4.0.1 has an optimizer that takes advantage of this.  So a
+// non-conforming program quietly produces wildly incorrect output.
+//
+// The problem is not the use of reinterpret_cast.  The problem is type
+// punning: holding an object in memory of one type and reading its bits
+// back using a different type.
+//
+// The C++ standard is more subtle and complex than this, but that
+// is the basic idea.
+//
+// Anyways ...
+//
+// bit_cast<> calls memcpy() which is blessed by the standard,
+// especially by the example in section 3.9 .  Also, of course,
+// bit_cast<> wraps up the nasty logic in one place.
+//
+// Fortunately memcpy() is very fast.  In optimized mode, with a
+// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
+// code with the minimal amount of data movement.  On a 32-bit system,
+// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
+// compiles to two loads and two stores.
+//
+// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
+//
+// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
+// is likely to surprise you.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+  COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual);
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+// Used to explicitly mark the return value of a function as unused. If you are
+// really sure you don't want to do anything with the return value of a function
+// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
+//
+//   scoped_ptr<MyType> my_var = ...;
+//   if (TakeOwnership(my_var.get()) == SUCCESS)
+//     ignore_result(my_var.release());
+//
+template<typename T>
+inline void ignore_result(const T&) {
+}
+
+// The following enum should be used only as a constructor argument to indicate
+// that the variable has static storage class, and that the constructor should
+// do nothing to its state.  It indicates to the reader that it is legal to
+// declare a static instance of the class, provided the constructor is given
+// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a
+// static variable that has a constructor or a destructor because invocation
+// order is undefined.  However, IF the type can be initialized by filling with
+// zeroes (which the loader does for static variables), AND the destructor also
+// does nothing to the storage, AND there are no virtual methods, then a
+// constructor declared as
+//       explicit MyClass(base::LinkerInitialized x) {}
+// and invoked as
+//       static MyClass my_variable_name(base::LINKER_INITIALIZED);
+namespace base {
+enum LinkerInitialized { LINKER_INITIALIZED };
+
+// Use these to declare and define a static local variable (static T;) so that
+// it is leaked so that its destructors are not called at exit. If you need
+// thread-safe initialization, use base/lazy_instance.h instead.
+#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
+  static type& name = *new type arguments
+
+}  // base
+
+#endif  // BASE_MACROS_H_
diff --git a/base/md5.cc b/base/md5.cc
new file mode 100644
index 0000000..72c774d
--- /dev/null
+++ b/base/md5.cc
@@ -0,0 +1,299 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The original file was copied from sqlite, and was in the public domain.
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "base/md5.h"
+
+#include <stddef.h>
+
+namespace {
+
+struct Context {
+  uint32_t buf[4];
+  uint32_t bits[2];
+  uint8_t in[64];
+};
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(uint8_t* buf, unsigned longs) {
+  do {
+    uint32_t temp = static_cast<uint32_t>(
+        static_cast<unsigned>(buf[3]) << 8 |
+        buf[2]) << 16 |
+        (static_cast<unsigned>(buf[1]) << 8 | buf[0]);
+    *reinterpret_cast<uint32_t*>(buf) = temp;
+    buf += 4;
+  } while (--longs);
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+  (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32_t buf[4], const uint32_t in[16]) {
+  uint32_t a, b, c, d;
+
+  a = buf[0];
+  b = buf[1];
+  c = buf[2];
+  d = buf[3];
+
+  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+}  // namespace
+
+namespace base {
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(MD5Context* context) {
+  struct Context* ctx = reinterpret_cast<struct Context*>(context);
+  ctx->buf[0] = 0x67452301;
+  ctx->buf[1] = 0xefcdab89;
+  ctx->buf[2] = 0x98badcfe;
+  ctx->buf[3] = 0x10325476;
+  ctx->bits[0] = 0;
+  ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(MD5Context* context, const StringPiece& data) {
+  struct Context* ctx = reinterpret_cast<struct Context*>(context);
+  const uint8_t* buf = reinterpret_cast<const uint8_t*>(data.data());
+  size_t len = data.size();
+
+  /* Update bitcount */
+
+  uint32_t t = ctx->bits[0];
+  if ((ctx->bits[0] = t + (static_cast<uint32_t>(len) << 3)) < t)
+    ctx->bits[1]++; /* Carry from low to high */
+  ctx->bits[1] += static_cast<uint32_t>(len >> 29);
+
+  t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+  /* Handle any leading odd-sized chunks */
+
+  if (t) {
+    uint8_t* p = static_cast<uint8_t*>(ctx->in + t);
+
+    t = 64 - t;
+    if (len < t) {
+      memcpy(p, buf, len);
+      return;
+    }
+    memcpy(p, buf, t);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+    buf += t;
+    len -= t;
+  }
+
+  /* Process data in 64-byte chunks */
+
+  while (len >= 64) {
+    memcpy(ctx->in, buf, 64);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+    buf += 64;
+    len -= 64;
+  }
+
+  /* Handle any remaining bytes of data. */
+
+  memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(MD5Digest* digest, MD5Context* context) {
+  struct Context* ctx = reinterpret_cast<struct Context*>(context);
+  unsigned count;
+  uint8_t* p;
+
+  /* Compute number of bytes mod 64 */
+  count = (ctx->bits[0] >> 3) & 0x3F;
+
+  /* Set the first char of padding to 0x80.  This is safe since there is
+     always at least one byte free */
+  p = ctx->in + count;
+  *p++ = 0x80;
+
+  /* Bytes of padding needed to make 64 bytes */
+  count = 64 - 1 - count;
+
+  /* Pad out to 56 mod 64 */
+  if (count < 8) {
+    /* Two lots of padding:  Pad the first block to 64 bytes */
+    memset(p, 0, count);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+
+    /* Now fill the next block with 56 bytes */
+    memset(ctx->in, 0, 56);
+  } else {
+    /* Pad block to 56 bytes */
+    memset(p, 0, count - 8);
+  }
+  byteReverse(ctx->in, 14);
+
+  /* Append length in bits and transform */
+  memcpy(&ctx->in[14 * sizeof(ctx->bits[0])], &ctx->bits[0],
+         sizeof(ctx->bits[0]));
+  memcpy(&ctx->in[15 * sizeof(ctx->bits[1])], &ctx->bits[1],
+         sizeof(ctx->bits[1]));
+
+  MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+  byteReverse(reinterpret_cast<uint8_t*>(ctx->buf), 4);
+  memcpy(digest->a, ctx->buf, 16);
+  memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+void MD5IntermediateFinal(MD5Digest* digest, const MD5Context* context) {
+  /* MD5Final mutates the MD5Context*. Make a copy for generating the
+     intermediate value. */
+  MD5Context context_copy;
+  memcpy(&context_copy, context, sizeof(context_copy));
+  MD5Final(digest, &context_copy);
+}
+
+std::string MD5DigestToBase16(const MD5Digest& digest) {
+  static char const zEncode[] = "0123456789abcdef";
+
+  std::string ret;
+  ret.resize(32);
+
+  for (int i = 0, j = 0; i < 16; i++, j += 2) {
+    uint8_t a = digest.a[i];
+    ret[j] = zEncode[(a >> 4) & 0xf];
+    ret[j + 1] = zEncode[a & 0xf];
+  }
+  return ret;
+}
+
+void MD5Sum(const void* data, size_t length, MD5Digest* digest) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+  MD5Update(&ctx, StringPiece(reinterpret_cast<const char*>(data), length));
+  MD5Final(digest, &ctx);
+}
+
+std::string MD5String(const StringPiece& str) {
+  MD5Digest digest;
+  MD5Sum(str.data(), str.length(), &digest);
+  return MD5DigestToBase16(digest);
+}
+
+}  // namespace base
diff --git a/base/md5.h b/base/md5.h
new file mode 100644
index 0000000..0b4cbce
--- /dev/null
+++ b/base/md5.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MD5_H_
+#define BASE_MD5_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// MD5 stands for Message Digest algorithm 5.
+// MD5 is a robust hash function, designed for cyptography, but often used
+// for file checksums.  The code is complex and slow, but has few
+// collisions.
+// See Also:
+//   http://en.wikipedia.org/wiki/MD5
+
+// These functions perform MD5 operations. The simplest call is MD5Sum() to
+// generate the MD5 sum of the given data.
+//
+// You can also compute the MD5 sum of data incrementally by making multiple
+// calls to MD5Update():
+//   MD5Context ctx; // intermediate MD5 data: do not use
+//   MD5Init(&ctx);
+//   MD5Update(&ctx, data1, length1);
+//   MD5Update(&ctx, data2, length2);
+//   ...
+//
+//   MD5Digest digest; // the result of the computation
+//   MD5Final(&digest, &ctx);
+//
+// You can call MD5DigestToBase16() to generate a string of the digest.
+
+// The output of an MD5 operation.
+struct MD5Digest {
+  uint8_t a[16];
+};
+
+// Used for storing intermediate data during an MD5 computation. Callers
+// should not access the data.
+typedef char MD5Context[88];
+
+// Initializes the given MD5 context structure for subsequent calls to
+// MD5Update().
+BASE_EXPORT void MD5Init(MD5Context* context);
+
+// For the given buffer of |data| as a StringPiece, updates the given MD5
+// context with the sum of the data. You can call this any number of times
+// during the computation, except that MD5Init() must have been called first.
+BASE_EXPORT void MD5Update(MD5Context* context, const StringPiece& data);
+
+// Finalizes the MD5 operation and fills the buffer with the digest.
+BASE_EXPORT void MD5Final(MD5Digest* digest, MD5Context* context);
+
+// MD5IntermediateFinal() generates a digest without finalizing the MD5
+// operation.  Can be used to generate digests for the input seen thus far,
+// without affecting the digest generated for the entire input.
+BASE_EXPORT void MD5IntermediateFinal(MD5Digest* digest,
+                                      const MD5Context* context);
+
+// Converts a digest into human-readable hexadecimal.
+BASE_EXPORT std::string MD5DigestToBase16(const MD5Digest& digest);
+
+// Computes the MD5 sum of the given data buffer with the given length.
+// The given 'digest' structure will be filled with the result data.
+BASE_EXPORT void MD5Sum(const void* data, size_t length, MD5Digest* digest);
+
+// Returns the MD5 (in hexadecimal) of a string.
+BASE_EXPORT std::string MD5String(const StringPiece& str);
+
+}  // namespace base
+
+#endif  // BASE_MD5_H_
diff --git a/base/md5_unittest.cc b/base/md5_unittest.cc
new file mode 100644
index 0000000..08c99f1
--- /dev/null
+++ b/base/md5_unittest.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/md5.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(MD5, DigestToBase16) {
+  MD5Digest digest;
+
+  int data[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    digest.a[i] = data[i] & 0xff;
+
+  std::string actual = MD5DigestToBase16(digest);
+  std::string expected = "d41d8cd98f00b204e9800998ecf8427e";
+
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5SumEmtpyData) {
+  MD5Digest digest;
+  const char data[] = "";
+
+  MD5Sum(data, strlen(data), &digest);
+
+  int expected[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, MD5SumOneByteData) {
+  MD5Digest digest;
+  const char data[] = "a";
+
+  MD5Sum(data, strlen(data), &digest);
+
+  int expected[] = {
+    0x0c, 0xc1, 0x75, 0xb9,
+    0xc0, 0xf1, 0xb6, 0xa8,
+    0x31, 0xc3, 0x99, 0xe2,
+    0x69, 0x77, 0x26, 0x61
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, MD5SumLongData) {
+  const int length = 10 * 1024 * 1024 + 1;
+  scoped_ptr<char[]> data(new char[length]);
+
+  for (int i = 0; i < length; ++i)
+    data[i] = i & 0xFF;
+
+  MD5Digest digest;
+  MD5Sum(data.get(), length, &digest);
+
+  int expected[] = {
+    0x90, 0xbd, 0x6a, 0xd9,
+    0x0a, 0xce, 0xf5, 0xad,
+    0xaa, 0x92, 0x20, 0x3e,
+    0x21, 0xc7, 0xa1, 0x3e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, ContextWithEmptyData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  int expected[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, ContextWithLongData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  const int length = 10 * 1024 * 1024 + 1;
+  scoped_ptr<char[]> data(new char[length]);
+
+  for (int i = 0; i < length; ++i)
+    data[i] = i & 0xFF;
+
+  int total = 0;
+  while (total < length) {
+    int len = 4097;  // intentionally not 2^k.
+    if (len > length - total)
+      len = length - total;
+
+    MD5Update(&ctx,
+              StringPiece(reinterpret_cast<char*>(data.get() + total), len));
+    total += len;
+  }
+
+  EXPECT_EQ(length, total);
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  int expected[] = {
+    0x90, 0xbd, 0x6a, 0xd9,
+    0x0a, 0xce, 0xf5, 0xad,
+    0xaa, 0x92, 0x20, 0x3e,
+    0x21, 0xc7, 0xa1, 0x3e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+// Example data from http://www.ietf.org/rfc/rfc1321.txt A.5 Test Suite
+TEST(MD5, MD5StringTestSuite1) {
+  std::string actual = MD5String("");
+  std::string expected = "d41d8cd98f00b204e9800998ecf8427e";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite2) {
+  std::string actual = MD5String("a");
+  std::string expected = "0cc175b9c0f1b6a831c399e269772661";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite3) {
+  std::string actual = MD5String("abc");
+  std::string expected = "900150983cd24fb0d6963f7d28e17f72";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite4) {
+  std::string actual = MD5String("message digest");
+  std::string expected = "f96b697d7cb7938d525a2f31aaf161d0";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite5) {
+  std::string actual = MD5String("abcdefghijklmnopqrstuvwxyz");
+  std::string expected = "c3fcd3d76192e4007dfb496cca67e13b";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite6) {
+  std::string actual = MD5String("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                 "abcdefghijklmnopqrstuvwxyz"
+                                 "0123456789");
+  std::string expected = "d174ab98d277d9f5a5611c2c9f419d9f";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite7) {
+  std::string actual = MD5String("12345678901234567890"
+                                 "12345678901234567890"
+                                 "12345678901234567890"
+                                 "12345678901234567890");
+  std::string expected = "57edf4a22be3c955ac49da2e2107b67a";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, ContextWithStringData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  MD5Update(&ctx, "abc");
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  std::string actual = MD5DigestToBase16(digest);
+  std::string expected = "900150983cd24fb0d6963f7d28e17f72";
+
+  EXPECT_EQ(expected, actual);
+}
+
+// Test that a digest generated by MD5IntermediateFinal() gives the same results
+// as an independently-calculated digest, and also does not modify the context.
+TEST(MD5, IntermediateFinal) {
+  // Independent context over the header.
+  MD5Context check_header_context;
+  MD5Init(&check_header_context);
+
+  // Independent context over entire input.
+  MD5Context check_full_context;
+  MD5Init(&check_full_context);
+
+  // Context intermediate digest will be calculated from.
+  MD5Context context;
+  MD5Init(&context);
+
+  static const char kHeader[] = "header data";
+  static const char kBody[] = "payload data";
+
+  MD5Update(&context, kHeader);
+  MD5Update(&check_header_context, kHeader);
+  MD5Update(&check_full_context, kHeader);
+
+  MD5Digest check_header_digest;
+  MD5Final(&check_header_digest, &check_header_context);
+
+  MD5Digest header_digest;
+  MD5IntermediateFinal(&header_digest, &context);
+
+  MD5Update(&context, kBody);
+  MD5Update(&check_full_context, kBody);
+
+  MD5Digest check_full_digest;
+  MD5Final(&check_full_digest, &check_full_context);
+
+  MD5Digest digest;
+  MD5Final(&digest, &context);
+
+  // The header and full digest pairs are the same, and they aren't the same as
+  // each other.
+  EXPECT_TRUE(!memcmp(&header_digest, &check_header_digest,
+                      sizeof(header_digest)));
+  EXPECT_TRUE(!memcmp(&digest, &check_full_digest, sizeof(digest)));
+  EXPECT_TRUE(memcmp(&digest, &header_digest, sizeof(digest)));
+}
+
+}  // namespace base
diff --git a/base/memory/BUILD.gn b/base/memory/BUILD.gn
new file mode 100644
index 0000000..bd864ca
--- /dev/null
+++ b/base/memory/BUILD.gn
@@ -0,0 +1,58 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("memory") {
+  sources = [
+    "aligned_memory.cc",
+    "aligned_memory.h",
+    "discardable_memory.cc",
+    "discardable_memory.h",
+    "discardable_memory_allocator.cc",
+    "discardable_memory_allocator.h",
+    "discardable_shared_memory.cc",
+    "discardable_shared_memory.h",
+    "linked_ptr.h",
+    "manual_constructor.h",
+    "memory_pressure_listener.cc",
+    "memory_pressure_listener.h",
+    "memory_pressure_monitor.cc",
+    "memory_pressure_monitor.h",
+    "raw_scoped_refptr_mismatch_checker.h",
+    "ref_counted.cc",
+    "ref_counted.h",
+    "ref_counted_delete_on_message_loop.h",
+    "ref_counted_memory.cc",
+    "ref_counted_memory.h",
+    "scoped_policy.h",
+    "scoped_ptr.h",
+    "scoped_vector.h",
+    "shared_memory.h",
+    "shared_memory_android.cc",
+    "shared_memory_nacl.cc",
+    "shared_memory_posix.cc",
+    "shared_memory_win.cc",
+    "singleton.cc",
+    "singleton.h",
+    "weak_ptr.cc",
+    "weak_ptr.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [
+      "discardable_memory.cc",
+      "discardable_memory.h",
+      "discardable_memory_allocator.cc",
+      "discardable_memory_allocator.h",
+      "discardable_shared_memory.cc",
+      "discardable_shared_memory.h",
+      "shared_memory_posix.cc",
+    ]
+  } else {
+    sources -= [ "shared_memory_nacl.cc" ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/memory/aligned_memory.cc b/base/memory/aligned_memory.cc
new file mode 100644
index 0000000..5ec88b1
--- /dev/null
+++ b/base/memory/aligned_memory.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/aligned_memory.h"
+
+#include "base/logging.h"
+
+#if defined(OS_ANDROID)
+#include <malloc.h>
+#endif
+
+namespace base {
+
+void* AlignedAlloc(size_t size, size_t alignment) {
+  DCHECK_GT(size, 0U);
+  DCHECK_EQ(alignment & (alignment - 1), 0U);
+  DCHECK_EQ(alignment % sizeof(void*), 0U);
+  void* ptr = NULL;
+#if defined(COMPILER_MSVC)
+  ptr = _aligned_malloc(size, alignment);
+// Android technically supports posix_memalign(), but does not expose it in
+// the current version of the library headers used by Chrome.  Luckily,
+// memalign() on Android returns pointers which can safely be used with
+// free(), so we can use it instead.  Issue filed to document this:
+// http://code.google.com/p/android/issues/detail?id=35391
+#elif defined(OS_ANDROID)
+  ptr = memalign(alignment, size);
+#else
+  if (posix_memalign(&ptr, alignment, size))
+    ptr = NULL;
+#endif
+  // Since aligned allocations may fail for non-memory related reasons, force a
+  // crash if we encounter a failed allocation; maintaining consistent behavior
+  // with a normal allocation failure in Chrome.
+  if (!ptr) {
+    DLOG(ERROR) << "If you crashed here, your aligned allocation is incorrect: "
+                << "size=" << size << ", alignment=" << alignment;
+    CHECK(false);
+  }
+  // Sanity check alignment just to be safe.
+  DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
+  return ptr;
+}
+
+}  // namespace base
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
new file mode 100644
index 0000000..1a4cba9
--- /dev/null
+++ b/base/memory/aligned_memory.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// AlignedMemory is a POD type that gives you a portable way to specify static
+// or local stack data of a given alignment and size. For example, if you need
+// static storage for a class, but you want manual control over when the object
+// is constructed and destructed (you don't want static initialization and
+// destruction), use AlignedMemory:
+//
+//   static AlignedMemory<sizeof(MyClass), ALIGNOF(MyClass)> my_class;
+//
+//   // ... at runtime:
+//   new(my_class.void_data()) MyClass();
+//
+//   // ... use it:
+//   MyClass* mc = my_class.data_as<MyClass>();
+//
+//   // ... later, to destruct my_class:
+//   my_class.data_as<MyClass>()->MyClass::~MyClass();
+//
+// Alternatively, a runtime sized aligned allocation can be created:
+//
+//   float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
+//
+//   // ... later, to release the memory:
+//   AlignedFree(my_array);
+//
+// Or using scoped_ptr:
+//
+//   scoped_ptr<float, AlignedFreeDeleter> my_array(
+//       static_cast<float*>(AlignedAlloc(size, alignment)));
+
+#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
+#define BASE_MEMORY_ALIGNED_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+#if defined(COMPILER_MSVC)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+// AlignedMemory is specialized for all supported alignments.
+// Make sure we get a compiler error if someone uses an unsupported alignment.
+template <size_t Size, size_t ByteAlignment>
+struct AlignedMemory {};
+
+#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
+    template <size_t Size> \
+    class AlignedMemory<Size, byte_alignment> { \
+     public: \
+      ALIGNAS(byte_alignment) uint8 data_[Size]; \
+      void* void_data() { return static_cast<void*>(data_); } \
+      const void* void_data() const { \
+        return static_cast<const void*>(data_); \
+      } \
+      template<typename Type> \
+      Type* data_as() { return static_cast<Type*>(void_data()); } \
+      template<typename Type> \
+      const Type* data_as() const { \
+        return static_cast<const Type*>(void_data()); \
+      } \
+     private: \
+      void* operator new(size_t); \
+      void operator delete(void*); \
+    }
+
+// Specialization for all alignments is required because MSVC (as of VS 2008)
+// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
+// Greater than 4096 alignment is not supported by some compilers, so 4096 is
+// the maximum specified here.
+BASE_DECL_ALIGNED_MEMORY(1);
+BASE_DECL_ALIGNED_MEMORY(2);
+BASE_DECL_ALIGNED_MEMORY(4);
+BASE_DECL_ALIGNED_MEMORY(8);
+BASE_DECL_ALIGNED_MEMORY(16);
+BASE_DECL_ALIGNED_MEMORY(32);
+BASE_DECL_ALIGNED_MEMORY(64);
+BASE_DECL_ALIGNED_MEMORY(128);
+BASE_DECL_ALIGNED_MEMORY(256);
+BASE_DECL_ALIGNED_MEMORY(512);
+BASE_DECL_ALIGNED_MEMORY(1024);
+BASE_DECL_ALIGNED_MEMORY(2048);
+BASE_DECL_ALIGNED_MEMORY(4096);
+
+#undef BASE_DECL_ALIGNED_MEMORY
+
+BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
+
+inline void AlignedFree(void* ptr) {
+#if defined(COMPILER_MSVC)
+  _aligned_free(ptr);
+#else
+  free(ptr);
+#endif
+}
+
+// Deleter for use with scoped_ptr. E.g., use as
+//   scoped_ptr<Foo, base::AlignedFreeDeleter> foo;
+struct AlignedFreeDeleter {
+  inline void operator()(void* ptr) const {
+    AlignedFree(ptr);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_ALIGNED_MEMORY_H_
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
new file mode 100644
index 0000000..5d681f9
--- /dev/null
+++ b/base/memory/aligned_memory_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/aligned_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+namespace {
+
+using base::AlignedMemory;
+
+TEST(AlignedMemoryTest, StaticAlignment) {
+  static AlignedMemory<8, 8> raw8;
+  static AlignedMemory<8, 16> raw16;
+  static AlignedMemory<8, 256> raw256;
+  static AlignedMemory<8, 4096> raw4096;
+
+  EXPECT_EQ(8u, ALIGNOF(raw8));
+  EXPECT_EQ(16u, ALIGNOF(raw16));
+  EXPECT_EQ(256u, ALIGNOF(raw256));
+  EXPECT_EQ(4096u, ALIGNOF(raw4096));
+
+  EXPECT_ALIGNED(raw8.void_data(), 8);
+  EXPECT_ALIGNED(raw16.void_data(), 16);
+  EXPECT_ALIGNED(raw256.void_data(), 256);
+  EXPECT_ALIGNED(raw4096.void_data(), 4096);
+}
+
+TEST(AlignedMemoryTest, StackAlignment) {
+  AlignedMemory<8, 8> raw8;
+  AlignedMemory<8, 16> raw16;
+  AlignedMemory<8, 128> raw128;
+
+  EXPECT_EQ(8u, ALIGNOF(raw8));
+  EXPECT_EQ(16u, ALIGNOF(raw16));
+  EXPECT_EQ(128u, ALIGNOF(raw128));
+
+  EXPECT_ALIGNED(raw8.void_data(), 8);
+  EXPECT_ALIGNED(raw16.void_data(), 16);
+
+  // TODO(ios): __attribute__((aligned(X))) with X >= 128 does not works on
+  // the stack when building for arm64 on iOS, http://crbug.com/349003
+#if !(defined(OS_IOS) && defined(ARCH_CPU_ARM64))
+  EXPECT_ALIGNED(raw128.void_data(), 128);
+
+  // NaCl x86-64 compiler emits non-validating instructions for >128
+  // bytes alignment.
+  // http://www.chromium.org/nativeclient/design-documents/nacl-sfi-model-on-x86-64-systems
+  // TODO(hamaji): Ideally, NaCl compiler for x86-64 should workaround
+  // this limitation and this #if should be removed.
+  // https://code.google.com/p/nativeclient/issues/detail?id=3463
+#if !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
+  AlignedMemory<8, 256> raw256;
+  EXPECT_EQ(256u, ALIGNOF(raw256));
+  EXPECT_ALIGNED(raw256.void_data(), 256);
+
+  // TODO(ios): This test hits an armv7 bug in clang. crbug.com/138066
+#if !(defined(OS_IOS) && defined(ARCH_CPU_ARM_FAMILY))
+  AlignedMemory<8, 4096> raw4096;
+  EXPECT_EQ(4096u, ALIGNOF(raw4096));
+  EXPECT_ALIGNED(raw4096.void_data(), 4096);
+#endif  // !(defined(OS_IOS) && defined(ARCH_CPU_ARM_FAMILY))
+#endif  // !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
+#endif  // !(defined(OS_IOS) && defined(ARCH_CPU_ARM64))
+}
+
+TEST(AlignedMemoryTest, DynamicAllocation) {
+  void* p = base::AlignedAlloc(8, 8);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 8);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 16);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 16);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 256);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 256);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 4096);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 4096);
+  base::AlignedFree(p);
+}
+
+TEST(AlignedMemoryTest, ScopedDynamicAllocation) {
+  scoped_ptr<float, base::AlignedFreeDeleter> p(
+      static_cast<float*>(base::AlignedAlloc(8, 8)));
+  EXPECT_TRUE(p.get());
+  EXPECT_ALIGNED(p.get(), 8);
+}
+
+}  // namespace
diff --git a/base/memory/discardable_memory.cc b/base/memory/discardable_memory.cc
new file mode 100644
index 0000000..d50f185
--- /dev/null
+++ b/base/memory/discardable_memory.cc
@@ -0,0 +1,15 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/discardable_memory.h"
+
+namespace base {
+
+DiscardableMemory::DiscardableMemory() {
+}
+
+DiscardableMemory::~DiscardableMemory() {
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h
new file mode 100644
index 0000000..fc189e7
--- /dev/null
+++ b/base/memory/discardable_memory.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// Discardable memory is used to cache large objects without worrying about
+// blowing out memory, both on mobile devices where there is no swap, and
+// desktop devices where unused free memory should be used to help the user
+// experience. This is preferable to releasing memory in response to an OOM
+// signal because it is simpler and provides system-wide management of
+// purgable memory, though it has less flexibility as to which objects get
+// discarded.
+//
+// Discardable memory has two states: locked and unlocked. While the memory is
+// locked, it will not be discarded. Unlocking the memory allows the
+// discardable memory system and the OS to reclaim it if needed. Locks do not
+// nest.
+//
+// Notes:
+//   - The paging behavior of memory while it is locked is not specified. While
+//     mobile platforms will not swap it out, it may qualify for swapping
+//     on desktop platforms. It is not expected that this will matter, as the
+//     preferred pattern of usage for DiscardableMemory is to lock down the
+//     memory, use it as quickly as possible, and then unlock it.
+//   - Because of memory alignment, the amount of memory allocated can be
+//     larger than the requested memory size. It is not very efficient for
+//     small allocations.
+//   - A discardable memory instance is not thread safe. It is the
+//     responsibility of users of discardable memory to ensure there are no
+//     races.
+//
+class BASE_EXPORT DiscardableMemory {
+ public:
+  DiscardableMemory();
+  virtual ~DiscardableMemory();
+
+  // Locks the memory so that it will not be purged by the system. Returns
+  // true on success. If the return value is false then this object should be
+  // discarded and a new one should be created.
+  virtual bool Lock() WARN_UNUSED_RESULT = 0;
+
+  // Unlocks the memory so that it can be purged by the system. Must be called
+  // after every successful lock call.
+  virtual void Unlock() = 0;
+
+  // Returns the memory address held by this object. The object must be locked
+  // before calling this.
+  virtual void* data() const = 0;
+
+  // Handy method to simplify calling data() with a reinterpret_cast.
+  template<typename T> T* data_as() const {
+    return reinterpret_cast<T*>(data());
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_MEMORY_H_
diff --git a/base/memory/discardable_memory_allocator.cc b/base/memory/discardable_memory_allocator.cc
new file mode 100644
index 0000000..002a3ba
--- /dev/null
+++ b/base/memory/discardable_memory_allocator.cc
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/discardable_memory_allocator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+DiscardableMemoryAllocator* g_allocator = nullptr;
+
+}  // namespace
+
+// static
+void DiscardableMemoryAllocator::SetInstance(
+    DiscardableMemoryAllocator* allocator) {
+  DCHECK(allocator);
+
+  // Make sure this function is only called once before the first call
+  // to GetInstance().
+  DCHECK(!g_allocator);
+
+  g_allocator = allocator;
+}
+
+// static
+DiscardableMemoryAllocator* DiscardableMemoryAllocator::GetInstance() {
+  DCHECK(g_allocator);
+  return g_allocator;
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_memory_allocator.h b/base/memory/discardable_memory_allocator.h
new file mode 100644
index 0000000..400f87a
--- /dev/null
+++ b/base/memory/discardable_memory_allocator.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DiscardableMemory;
+
+class BASE_EXPORT DiscardableMemoryAllocator {
+ public:
+  // Returns the allocator instance.
+  static DiscardableMemoryAllocator* GetInstance();
+
+  // Sets the allocator instance. Can only be called once, e.g. on startup.
+  // Ownership of |instance| remains with the caller.
+  static void SetInstance(DiscardableMemoryAllocator* allocator);
+
+  virtual scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+      size_t size) = 0;
+
+ protected:
+  virtual ~DiscardableMemoryAllocator() {}
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
new file mode 100644
index 0000000..830d6b9
--- /dev/null
+++ b/base/memory/discardable_shared_memory.cc
@@ -0,0 +1,368 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/discardable_shared_memory.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#include <algorithm>
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "base/process/process_metrics.h"
+
+#if defined(OS_ANDROID)
+#include "third_party/ashmem/ashmem.h"
+#endif
+
+namespace base {
+namespace {
+
+// Use a machine-sized pointer as atomic type. It will use the Atomic32 or
+// Atomic64 routines, depending on the architecture.
+typedef intptr_t AtomicType;
+typedef uintptr_t UAtomicType;
+
+// Template specialization for timestamp serialization/deserialization. This
+// is used to serialize timestamps using Unix time on systems where AtomicType
+// does not have enough precision to contain a timestamp in the standard
+// serialized format.
+template <int>
+Time TimeFromWireFormat(int64 value);
+template <int>
+int64 TimeToWireFormat(Time time);
+
+// Serialize to Unix time when using 4-byte wire format.
+// Note: 19 January 2038, this will cease to work.
+template <>
+Time ALLOW_UNUSED_TYPE TimeFromWireFormat<4>(int64 value) {
+  return value ? Time::UnixEpoch() + TimeDelta::FromSeconds(value) : Time();
+}
+template <>
+int64 ALLOW_UNUSED_TYPE TimeToWireFormat<4>(Time time) {
+  return time > Time::UnixEpoch() ? (time - Time::UnixEpoch()).InSeconds() : 0;
+}
+
+// Standard serialization format when using 8-byte wire format.
+template <>
+Time ALLOW_UNUSED_TYPE TimeFromWireFormat<8>(int64 value) {
+  return Time::FromInternalValue(value);
+}
+template <>
+int64 ALLOW_UNUSED_TYPE TimeToWireFormat<8>(Time time) {
+  return time.ToInternalValue();
+}
+
+struct SharedState {
+  enum LockState { UNLOCKED = 0, LOCKED = 1 };
+
+  explicit SharedState(AtomicType ivalue) { value.i = ivalue; }
+  SharedState(LockState lock_state, Time timestamp) {
+    int64 wire_timestamp = TimeToWireFormat<sizeof(AtomicType)>(timestamp);
+    DCHECK_GE(wire_timestamp, 0);
+    DCHECK_EQ(lock_state & ~1, 0);
+    value.u = (static_cast<UAtomicType>(wire_timestamp) << 1) | lock_state;
+  }
+
+  LockState GetLockState() const { return static_cast<LockState>(value.u & 1); }
+
+  Time GetTimestamp() const {
+    return TimeFromWireFormat<sizeof(AtomicType)>(value.u >> 1);
+  }
+
+  // Bit 1: Lock state. Bit is set when locked.
+  // Bit 2..sizeof(AtomicType)*8: Usage timestamp. NULL time when locked or
+  // purged.
+  union {
+    AtomicType i;
+    UAtomicType u;
+  } value;
+};
+
+// Shared state is stored at offset 0 in shared memory segments.
+SharedState* SharedStateFromSharedMemory(const SharedMemory& shared_memory) {
+  DCHECK(shared_memory.memory());
+  return static_cast<SharedState*>(shared_memory.memory());
+}
+
+// Round up |size| to a multiple of alignment, which must be a power of two.
+size_t Align(size_t alignment, size_t size) {
+  DCHECK_EQ(alignment & (alignment - 1), 0u);
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+
+// Round up |size| to a multiple of page size.
+size_t AlignToPageSize(size_t size) {
+  return Align(base::GetPageSize(), size);
+}
+
+}  // namespace
+
+DiscardableSharedMemory::DiscardableSharedMemory()
+    : mapped_size_(0), locked_page_count_(0) {
+}
+
+DiscardableSharedMemory::DiscardableSharedMemory(
+    SharedMemoryHandle shared_memory_handle)
+    : shared_memory_(shared_memory_handle, false),
+      mapped_size_(0),
+      locked_page_count_(0) {
+}
+
+DiscardableSharedMemory::~DiscardableSharedMemory() {
+}
+
+bool DiscardableSharedMemory::CreateAndMap(size_t size) {
+  CheckedNumeric<size_t> checked_size = size;
+  checked_size += AlignToPageSize(sizeof(SharedState));
+  if (!checked_size.IsValid())
+    return false;
+
+  if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
+    return false;
+
+  mapped_size_ =
+      shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
+
+  locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
+#if DCHECK_IS_ON()
+  for (size_t page = 0; page < locked_page_count_; ++page)
+    locked_pages_.insert(page);
+#endif
+
+  DCHECK(last_known_usage_.is_null());
+  SharedState new_state(SharedState::LOCKED, Time());
+  subtle::Release_Store(&SharedStateFromSharedMemory(shared_memory_)->value.i,
+                        new_state.value.i);
+  return true;
+}
+
+bool DiscardableSharedMemory::Map(size_t size) {
+  if (!shared_memory_.Map(AlignToPageSize(sizeof(SharedState)) + size))
+    return false;
+
+  mapped_size_ =
+      shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
+
+  locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
+#if DCHECK_IS_ON()
+  for (size_t page = 0; page < locked_page_count_; ++page)
+    locked_pages_.insert(page);
+#endif
+
+  return true;
+}
+
+DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
+    size_t offset, size_t length) {
+  DCHECK_EQ(AlignToPageSize(offset), offset);
+  DCHECK_EQ(AlignToPageSize(length), length);
+
+  // Calls to this function must be synchronized properly.
+  DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+  DCHECK(shared_memory_.memory());
+
+  // We need to successfully acquire the platform independent lock before
+  // individual pages can be locked.
+  if (!locked_page_count_) {
+    // Return false when instance has been purged or not initialized properly
+    // by checking if |last_known_usage_| is NULL.
+    if (last_known_usage_.is_null())
+      return FAILED;
+
+    SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
+    SharedState new_state(SharedState::LOCKED, Time());
+    SharedState result(subtle::Acquire_CompareAndSwap(
+        &SharedStateFromSharedMemory(shared_memory_)->value.i,
+        old_state.value.i,
+        new_state.value.i));
+    if (result.value.u != old_state.value.u) {
+      // Update |last_known_usage_| in case the above CAS failed because of
+      // an incorrect timestamp.
+      last_known_usage_ = result.GetTimestamp();
+      return FAILED;
+    }
+  }
+
+  // Zero for length means "everything onward".
+  if (!length)
+    length = AlignToPageSize(mapped_size_) - offset;
+
+  size_t start = offset / base::GetPageSize();
+  size_t end = start + length / base::GetPageSize();
+  DCHECK_LT(start, end);
+  DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
+
+  // Add pages to |locked_page_count_|.
+  // Note: Locking a page that is already locked is an error.
+  locked_page_count_ += end - start;
+#if DCHECK_IS_ON()
+  // Detect incorrect usage by keeping track of exactly what pages are locked.
+  for (auto page = start; page < end; ++page) {
+    auto result = locked_pages_.insert(page);
+    DCHECK(result.second);
+  }
+  DCHECK_EQ(locked_pages_.size(), locked_page_count_);
+#endif
+
+#if defined(OS_ANDROID)
+  SharedMemoryHandle handle = shared_memory_.handle();
+  DCHECK(SharedMemory::IsHandleValid(handle));
+  if (ashmem_pin_region(
+          handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+    return PURGED;
+  }
+#endif
+
+  return SUCCESS;
+}
+
+void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
+  DCHECK_EQ(AlignToPageSize(offset), offset);
+  DCHECK_EQ(AlignToPageSize(length), length);
+
+  // Calls to this function must be synchronized properly.
+  DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+  // Zero for length means "everything onward".
+  if (!length)
+    length = AlignToPageSize(mapped_size_) - offset;
+
+  DCHECK(shared_memory_.memory());
+
+#if defined(OS_ANDROID)
+  SharedMemoryHandle handle = shared_memory_.handle();
+  DCHECK(SharedMemory::IsHandleValid(handle));
+  if (ashmem_unpin_region(
+          handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+    DPLOG(ERROR) << "ashmem_unpin_region() failed";
+  }
+#endif
+
+  size_t start = offset / base::GetPageSize();
+  size_t end = start + length / base::GetPageSize();
+  DCHECK_LT(start, end);
+  DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
+
+  // Remove pages from |locked_page_count_|.
+  // Note: Unlocking a page that is not locked is an error.
+  DCHECK_GE(locked_page_count_, end - start);
+  locked_page_count_ -= end - start;
+#if DCHECK_IS_ON()
+  // Detect incorrect usage by keeping track of exactly what pages are locked.
+  for (auto page = start; page < end; ++page) {
+    auto erased_count = locked_pages_.erase(page);
+    DCHECK_EQ(1u, erased_count);
+  }
+  DCHECK_EQ(locked_pages_.size(), locked_page_count_);
+#endif
+
+  // Early out and avoid releasing the platform independent lock if some pages
+  // are still locked.
+  if (locked_page_count_)
+    return;
+
+  Time current_time = Now();
+  DCHECK(!current_time.is_null());
+
+  SharedState old_state(SharedState::LOCKED, Time());
+  SharedState new_state(SharedState::UNLOCKED, current_time);
+  // Note: timestamp cannot be NULL as that is a unique value used when
+  // locked or purged.
+  DCHECK(!new_state.GetTimestamp().is_null());
+  // Timestamp precision should at least be accurate to the second.
+  DCHECK_EQ((new_state.GetTimestamp() - Time::UnixEpoch()).InSeconds(),
+            (current_time - Time::UnixEpoch()).InSeconds());
+  SharedState result(subtle::Release_CompareAndSwap(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i,
+      old_state.value.i,
+      new_state.value.i));
+
+  DCHECK_EQ(old_state.value.u, result.value.u);
+
+  last_known_usage_ = current_time;
+}
+
+void* DiscardableSharedMemory::memory() const {
+  return reinterpret_cast<uint8*>(shared_memory_.memory()) +
+         AlignToPageSize(sizeof(SharedState));
+}
+
+bool DiscardableSharedMemory::Purge(Time current_time) {
+  // Calls to this function must be synchronized properly.
+  DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+  // Early out if not mapped. This can happen if the segment was previously
+  // unmapped using a call to Close().
+  if (!shared_memory_.memory())
+    return true;
+
+  SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
+  SharedState new_state(SharedState::UNLOCKED, Time());
+  SharedState result(subtle::Acquire_CompareAndSwap(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i,
+      old_state.value.i,
+      new_state.value.i));
+
+  // Update |last_known_usage_| to |current_time| if the memory is locked. This
+  // allows the caller to determine if purging failed because last known usage
+  // was incorrect or memory was locked. In the second case, the caller should
+  // most likely wait for some amount of time before attempting to purge the
+  // the memory again.
+  if (result.value.u != old_state.value.u) {
+    last_known_usage_ = result.GetLockState() == SharedState::LOCKED
+                            ? current_time
+                            : result.GetTimestamp();
+    return false;
+  }
+
+  last_known_usage_ = Time();
+  return true;
+}
+
+bool DiscardableSharedMemory::IsMemoryResident() const {
+  DCHECK(shared_memory_.memory());
+
+  SharedState result(subtle::NoBarrier_Load(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i));
+
+  return result.GetLockState() == SharedState::LOCKED ||
+         !result.GetTimestamp().is_null();
+}
+
+void DiscardableSharedMemory::Close() {
+  shared_memory_.Unmap();
+  shared_memory_.Close();
+  mapped_size_ = 0;
+}
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+void DiscardableSharedMemory::Shrink() {
+#if defined(OS_POSIX)
+  SharedMemoryHandle handle = shared_memory_.handle();
+  if (!SharedMemory::IsHandleValid(handle))
+    return;
+
+  // Truncate shared memory to size of SharedState.
+  if (HANDLE_EINTR(
+          ftruncate(handle.fd, AlignToPageSize(sizeof(SharedState)))) != 0) {
+    DPLOG(ERROR) << "ftruncate() failed";
+    return;
+  }
+  mapped_size_ = 0;
+#else
+  NOTIMPLEMENTED();
+#endif
+}
+#endif
+
+Time DiscardableSharedMemory::Now() const {
+  return Time::Now();
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h
new file mode 100644
index 0000000..892d556
--- /dev/null
+++ b/base/memory/discardable_shared_memory.h
@@ -0,0 +1,145 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
+#define BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "base/threading/thread_collision_warner.h"
+#include "base/time/time.h"
+
+#if DCHECK_IS_ON()
+#include <set>
+#endif
+
+// Define DISCARDABLE_SHARED_MEMORY_SHRINKING if platform supports shrinking
+// of discardable shared memory segments.
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#define DISCARDABLE_SHARED_MEMORY_SHRINKING
+#endif
+
+namespace base {
+
+// Platform abstraction for discardable shared memory.
+//
+// This class is not thread-safe. Clients are responsible for synchronizing
+// access to an instance of this class.
+class BASE_EXPORT DiscardableSharedMemory {
+ public:
+  enum LockResult { SUCCESS, PURGED, FAILED };
+
+  DiscardableSharedMemory();
+
+  // Create a new DiscardableSharedMemory object from an existing, open shared
+  // memory file. Memory must be locked.
+  explicit DiscardableSharedMemory(SharedMemoryHandle handle);
+
+  // Closes any open files.
+  virtual ~DiscardableSharedMemory();
+
+  // Creates and maps a locked DiscardableSharedMemory object with |size|.
+  // Returns true on success and false on failure.
+  bool CreateAndMap(size_t size);
+
+  // Maps the locked discardable memory into the caller's address space.
+  // Returns true on success, false otherwise.
+  bool Map(size_t size);
+
+  // The actual size of the mapped memory (may be larger than requested).
+  size_t mapped_size() const { return mapped_size_; }
+
+  // Returns a shared memory handle for this DiscardableSharedMemory object.
+  SharedMemoryHandle handle() const { return shared_memory_.handle(); }
+
+  // Locks a range of memory so that it will not be purged by the system.
+  // The range of memory must be unlocked. The result of trying to lock an
+  // already locked range is undefined. |offset| and |length| must both be
+  // a multiple of the page size as returned by GetPageSize().
+  // Passing 0 for |length| means "everything onward".
+  // Returns SUCCESS if range was successfully locked and the memory is still
+  // resident, PURGED if range was successfully locked but has been purged
+  // since last time it was locked and FAILED if range could not be locked.
+  // Locking can fail for two reasons; object might have been purged, our
+  // last known usage timestamp might be out of date. Last known usage time
+  // is updated to the actual last usage timestamp if memory is still resident
+  // or 0 if not.
+  LockResult Lock(size_t offset, size_t length);
+
+  // Unlock a previously successfully locked range of memory. The range of
+  // memory must be locked. The result of trying to unlock a not
+  // previously locked range is undefined.
+  // |offset| and |length| must both be a multiple of the page size as returned
+  // by GetPageSize().
+  // Passing 0 for |length| means "everything onward".
+  void Unlock(size_t offset, size_t length);
+
+  // Gets a pointer to the opened discardable memory space. Discardable memory
+  // must have been mapped via Map().
+  void* memory() const;
+
+  // Returns the last known usage time for DiscardableSharedMemory object. This
+  // may be earlier than the "true" usage time when memory has been used by a
+  // different process. Returns NULL time if purged.
+  Time last_known_usage() const { return last_known_usage_; }
+
+  // This returns true and sets |last_known_usage_| to 0 if
+  // DiscardableSharedMemory object was successfully purged. Purging can fail
+  // for two reasons; object might be locked or our last known usage timestamp
+  // might be out of date. Last known usage time is updated to |current_time|
+  // if locked or the actual last usage timestamp if unlocked. It is often
+  // necessary to call this function twice for the object to successfully be
+  // purged. First call, updates |last_known_usage_|. Second call, successfully
+  // purges the object using the updated |last_known_usage_|.
+  // Note: there is no guarantee that multiple calls to this function will
+  // successfully purge object. DiscardableSharedMemory object might be locked
+  // or another thread/process might be able to lock and unlock it in between
+  // each call.
+  bool Purge(Time current_time);
+
+  // Returns true if memory is still resident.
+  bool IsMemoryResident() const;
+
+  // Closes the open discardable memory segment.
+  // It is safe to call Close repeatedly.
+  void Close();
+
+  // Shares the discardable memory segment to another process. Attempts to
+  // create a platform-specific |new_handle| which can be used in a remote
+  // process to access the discardable memory segment. |new_handle| is an
+  // output parameter to receive the handle for use in the remote process.
+  // Returns true on success, false otherwise.
+  bool ShareToProcess(ProcessHandle process_handle,
+                      SharedMemoryHandle* new_handle) {
+    return shared_memory_.ShareToProcess(process_handle, new_handle);
+  }
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+  // Release as much memory as possible to the OS. The change in size will
+  // be reflected by the return value of mapped_size().
+  void Shrink();
+#endif
+
+ private:
+  // Virtual for tests.
+  virtual Time Now() const;
+
+  SharedMemory shared_memory_;
+  size_t mapped_size_;
+  size_t locked_page_count_;
+#if DCHECK_IS_ON()
+  std::set<size_t> locked_pages_;
+#endif
+  // Implementation is not thread-safe but still usable if clients are
+  // synchronized somehow. Use a collision warner to detect incorrect usage.
+  DFAKE_MUTEX(thread_collision_warner_);
+  Time last_known_usage_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardableSharedMemory);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc
new file mode 100644
index 0000000..ae7235d
--- /dev/null
+++ b/base/memory/discardable_shared_memory_unittest.cc
@@ -0,0 +1,331 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/memory/discardable_shared_memory.h"
+#include "base/process/process_metrics.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class TestDiscardableSharedMemory : public DiscardableSharedMemory {
+ public:
+  TestDiscardableSharedMemory() {}
+
+  explicit TestDiscardableSharedMemory(SharedMemoryHandle handle)
+      : DiscardableSharedMemory(handle) {}
+
+  void SetNow(Time now) { now_ = now; }
+
+ private:
+  // Overriden from DiscardableSharedMemory:
+  Time Now() const override { return now_; }
+
+  Time now_;
+};
+
+TEST(DiscardableSharedMemoryTest, CreateAndMap) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+  EXPECT_GE(memory.mapped_size(), kDataSize);
+}
+
+TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // Memory is initially locked. Unlock it.
+  memory1.SetNow(Time::FromDoubleT(1));
+  memory1.Unlock(0, 0);
+
+  // Lock and unlock memory.
+  auto lock_rv = memory1.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+  memory1.SetNow(Time::FromDoubleT(2));
+  memory1.Unlock(0, 0);
+
+  // Lock again before duplicating and passing ownership to new instance.
+  lock_rv = memory1.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // Unlock second instance.
+  memory2.SetNow(Time::FromDoubleT(3));
+  memory2.Unlock(0, 0);
+
+  // Lock second instance before passing ownership back to first instance.
+  lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+
+  // Memory should still be resident.
+  rv = memory1.IsMemoryResident();
+  EXPECT_TRUE(rv);
+
+  // Unlock first instance.
+  memory1.SetNow(Time::FromDoubleT(4));
+  memory1.Unlock(0, 0);
+}
+
+TEST(DiscardableSharedMemoryTest, Purge) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // This should fail as memory is locked.
+  rv = memory1.Purge(Time::FromDoubleT(1));
+  EXPECT_FALSE(rv);
+
+  memory2.SetNow(Time::FromDoubleT(2));
+  memory2.Unlock(0, 0);
+
+  ASSERT_TRUE(memory2.IsMemoryResident());
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(3));
+  EXPECT_FALSE(rv);
+
+  ASSERT_TRUE(memory2.IsMemoryResident());
+
+  // Memory is unlocked and our usage timestamp should be correct.
+  rv = memory1.Purge(Time::FromDoubleT(4));
+  EXPECT_TRUE(rv);
+
+  // Lock should fail as memory has been purged.
+  auto lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
+
+  ASSERT_FALSE(memory2.IsMemoryResident());
+}
+
+TEST(DiscardableSharedMemoryTest, LastUsed) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, 0);
+
+  EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1));
+
+  auto lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+
+  // This should fail as memory is locked.
+  rv = memory1.Purge(Time::FromDoubleT(2));
+  ASSERT_FALSE(rv);
+
+  // Last usage should have been updated to timestamp passed to Purge above.
+  EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
+
+  memory2.SetNow(Time::FromDoubleT(3));
+  memory2.Unlock(0, 0);
+
+  // Usage time should be correct for |memory2| instance.
+  EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(3));
+
+  // However, usage time has not changed as far as |memory1| instance knows.
+  EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(4));
+  EXPECT_FALSE(rv);
+
+  // The failed purge attempt should have updated usage time to the correct
+  // value.
+  EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(3));
+
+  // Purge memory through |memory2| instance. The last usage time should be
+  // set to 0 as a result of this.
+  rv = memory2.Purge(Time::FromDoubleT(5));
+  EXPECT_TRUE(rv);
+  EXPECT_TRUE(memory2.last_known_usage().is_null());
+
+  // This should fail as memory has already been purged and |memory1|'s usage
+  // time is incorrect as a result.
+  rv = memory1.Purge(Time::FromDoubleT(6));
+  EXPECT_FALSE(rv);
+
+  // The failed purge attempt should have updated usage time to the correct
+  // value.
+  EXPECT_TRUE(memory1.last_known_usage().is_null());
+
+  // Purge should succeed now that usage time is correct.
+  rv = memory1.Purge(Time::FromDoubleT(7));
+  EXPECT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, 0);
+
+  rv = memory2.Purge(Time::FromDoubleT(2));
+  EXPECT_TRUE(rv);
+
+  // Lock should fail as memory has been purged.
+  auto lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
+  const uint32 kDataSize = 32;
+
+  uint32 data_size_in_bytes = kDataSize * base::GetPageSize();
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(data_size_in_bytes);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(data_size_in_bytes);
+  ASSERT_TRUE(rv);
+
+  // Unlock first page.
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, base::GetPageSize());
+
+  rv = memory1.Purge(Time::FromDoubleT(2));
+  EXPECT_FALSE(rv);
+
+  // Lock first page again.
+  memory2.SetNow(Time::FromDoubleT(3));
+  auto lock_rv = memory2.Lock(0, base::GetPageSize());
+  EXPECT_NE(DiscardableSharedMemory::FAILED, lock_rv);
+
+  // Unlock first page.
+  memory2.SetNow(Time::FromDoubleT(4));
+  memory2.Unlock(0, base::GetPageSize());
+
+  rv = memory1.Purge(Time::FromDoubleT(5));
+  EXPECT_FALSE(rv);
+
+  // Unlock second page.
+  memory2.SetNow(Time::FromDoubleT(6));
+  memory2.Unlock(base::GetPageSize(), base::GetPageSize());
+
+  rv = memory1.Purge(Time::FromDoubleT(7));
+  EXPECT_FALSE(rv);
+
+  // Unlock anything onwards.
+  memory2.SetNow(Time::FromDoubleT(8));
+  memory2.Unlock(2 * base::GetPageSize(), 0);
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(9));
+  EXPECT_FALSE(rv);
+
+  // The failed purge attempt should have updated usage time to the correct
+  // value.
+  EXPECT_EQ(Time::FromDoubleT(8), memory1.last_known_usage());
+
+  // Purge should now succeed.
+  rv = memory1.Purge(Time::FromDoubleT(10));
+  EXPECT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, MappedSize) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  EXPECT_LE(kDataSize, memory.mapped_size());
+
+  // Mapped size should be 0 after memory segment has been closed.
+  memory.Close();
+  EXPECT_EQ(0u, memory.mapped_size());
+}
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+TEST(DiscardableSharedMemoryTest, Shrink) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  EXPECT_NE(0u, memory.mapped_size());
+
+  // Mapped size should be 0 after shrinking memory segment.
+  memory.Shrink();
+  EXPECT_EQ(0u, memory.mapped_size());
+}
+#endif
+
+}  // namespace
+}  // namespace base
diff --git a/base/memory/linked_ptr.h b/base/memory/linked_ptr.h
new file mode 100644
index 0000000..80044ad
--- /dev/null
+++ b/base/memory/linked_ptr.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A "smart" pointer type with reference tracking.  Every pointer to a
+// particular object is kept on a circular linked list.  When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is released, the entire list of pointers to that
+//   object is traversed.  This class is therefore NOT SUITABLE when there
+//   will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+//   will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Thread Safety:
+//   A linked_ptr is NOT thread safe. Copying a linked_ptr object is
+//   effectively a read-write operation.
+//
+// Alternative: to linked_ptr is shared_ptr, which
+//  - is also two pointers in size (8 bytes for 32 bit addresses)
+//  - is thread safe for copying and deletion
+//  - supports weak_ptrs
+
+#ifndef BASE_MEMORY_LINKED_PTR_H_
+#define BASE_MEMORY_LINKED_PTR_H_
+
+#include "base/logging.h"  // for CHECK macros
+
+// This is used internally by all instances of linked_ptr<>.  It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+  // Create a new circle that includes only this instance.
+  void join_new() {
+    next_ = this;
+  }
+
+  // Join an existing circle.
+  void join(linked_ptr_internal const* ptr) {
+    next_ = ptr->next_;
+    ptr->next_ = this;
+  }
+
+  // Leave whatever circle we're part of.  Returns true iff we were the
+  // last member of the circle.  Once this is done, you can join() another.
+  bool depart() {
+    if (next_ == this) return true;
+    linked_ptr_internal const* p = next_;
+    while (p->next_ != this) p = p->next_;
+    p->next_ = next_;
+    return false;
+  }
+
+ private:
+  mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+  typedef T element_type;
+
+  // Take over ownership of a raw pointer.  This should happen as soon as
+  // possible after the object is created.
+  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+  ~linked_ptr() { depart(); }
+
+  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+
+  linked_ptr(linked_ptr const& ptr) {
+    DCHECK_NE(&ptr, this);
+    copy(&ptr);
+  }
+
+  // Assignment releases the old value and acquires the new.
+  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+    depart();
+    copy(&ptr);
+    return *this;
+  }
+
+  linked_ptr& operator=(linked_ptr const& ptr) {
+    if (&ptr != this) {
+      depart();
+      copy(&ptr);
+    }
+    return *this;
+  }
+
+  // Smart pointer members.
+  void reset(T* ptr = NULL) {
+    depart();
+    capture(ptr);
+  }
+  T* get() const { return value_; }
+  T* operator->() const { return value_; }
+  T& operator*() const { return *value_; }
+  // Release ownership of the pointed object and returns it.
+  // Sole ownership by this linked_ptr object is required.
+  T* release() {
+    bool last = link_.depart();
+    CHECK(last);
+    T* v = value_;
+    value_ = NULL;
+    return v;
+  }
+
+  bool operator==(const T* p) const { return value_ == p; }
+  bool operator!=(const T* p) const { return value_ != p; }
+  template <typename U>
+  bool operator==(linked_ptr<U> const& ptr) const {
+    return value_ == ptr.get();
+  }
+  template <typename U>
+  bool operator!=(linked_ptr<U> const& ptr) const {
+    return value_ != ptr.get();
+  }
+
+ private:
+  template <typename U>
+  friend class linked_ptr;
+
+  T* value_;
+  linked_ptr_internal link_;
+
+  void depart() {
+    if (link_.depart()) delete value_;
+  }
+
+  void capture(T* ptr) {
+    value_ = ptr;
+    link_.join_new();
+  }
+
+  template <typename U> void copy(linked_ptr<U> const* ptr) {
+    value_ = ptr->get();
+    if (value_)
+      link_.join(&ptr->link_);
+    else
+      link_.join_new();
+  }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+  return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+  return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+  return linked_ptr<T>(ptr);
+}
+
+#endif  // BASE_MEMORY_LINKED_PTR_H_
diff --git a/base/memory/linked_ptr_unittest.cc b/base/memory/linked_ptr_unittest.cc
new file mode 100644
index 0000000..f6bc410
--- /dev/null
+++ b/base/memory/linked_ptr_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/memory/linked_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int num = 0;
+
+std::string history;
+
+// Class which tracks allocation/deallocation
+struct A {
+  A(): mynum(num++) { history += base::StringPrintf("A%d ctor\n", mynum); }
+  virtual ~A() { history += base::StringPrintf("A%d dtor\n", mynum); }
+  virtual void Use() { history += base::StringPrintf("A%d use\n", mynum); }
+  int mynum;
+};
+
+// Subclass
+struct B: public A {
+  B() { history += base::StringPrintf("B%d ctor\n", mynum); }
+  ~B() override { history += base::StringPrintf("B%d dtor\n", mynum); }
+  void Use() override { history += base::StringPrintf("B%d use\n", mynum); }
+};
+
+}  // namespace
+
+TEST(LinkedPtrTest, Test) {
+  {
+    linked_ptr<A> a0, a1, a2;
+    a0 = a0;
+    a1 = a2;
+    ASSERT_EQ(a0.get(), static_cast<A*>(NULL));
+    ASSERT_EQ(a1.get(), static_cast<A*>(NULL));
+    ASSERT_EQ(a2.get(), static_cast<A*>(NULL));
+    ASSERT_TRUE(a0 == NULL);
+    ASSERT_TRUE(a1 == NULL);
+    ASSERT_TRUE(a2 == NULL);
+
+    {
+      linked_ptr<A> a3(new A);
+      a0 = a3;
+      ASSERT_TRUE(a0 == a3);
+      ASSERT_TRUE(a0 != NULL);
+      ASSERT_TRUE(a0.get() == a3);
+      ASSERT_TRUE(a0 == a3.get());
+      linked_ptr<A> a4(a0);
+      a1 = a4;
+      linked_ptr<A> a5(new A);
+      ASSERT_TRUE(a5.get() != a3);
+      ASSERT_TRUE(a5 != a3.get());
+      a2 = a5;
+      linked_ptr<B> b0(new B);
+      linked_ptr<A> a6(b0);
+      ASSERT_TRUE(b0 == a6);
+      ASSERT_TRUE(a6 == b0);
+      ASSERT_TRUE(b0 != NULL);
+      a5 = b0;
+      a5 = b0;
+      a3->Use();
+      a4->Use();
+      a5->Use();
+      a6->Use();
+      b0->Use();
+      (*b0).Use();
+      b0.get()->Use();
+    }
+
+    a0->Use();
+    a1->Use();
+    a2->Use();
+
+    a1 = a2;
+    a2.reset(new A);
+    a0.reset();
+
+    linked_ptr<A> a7;
+  }
+
+  ASSERT_EQ(history,
+    "A0 ctor\n"
+    "A1 ctor\n"
+    "A2 ctor\n"
+    "B2 ctor\n"
+    "A0 use\n"
+    "A0 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 dtor\n"
+    "A2 dtor\n"
+    "A0 use\n"
+    "A0 use\n"
+    "A1 use\n"
+    "A3 ctor\n"
+    "A0 dtor\n"
+    "A3 dtor\n"
+    "A1 dtor\n"
+  );
+}
diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h
new file mode 100644
index 0000000..56081a1
--- /dev/null
+++ b/base/memory/manual_constructor.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ManualConstructor statically-allocates space in which to store some
+// object, but does not initialize it.  You can then call the constructor
+// and destructor for the object yourself as you see fit.  This is useful
+// for memory management optimizations, where you want to initialize and
+// destroy an object multiple times but only allocate it once.
+//
+// (When I say ManualConstructor statically allocates space, I mean that
+// the ManualConstructor object itself is forced to be the right size.)
+//
+// For example usage, check out base/containers/small_map.h.
+
+#ifndef BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
+#define BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+#include "base/memory/aligned_memory.h"
+
+namespace base {
+
+template <typename Type>
+class ManualConstructor {
+ public:
+  // No constructor or destructor because one of the most useful uses of
+  // this class is as part of a union, and members of a union cannot have
+  // constructors or destructors.  And, anyway, the whole point of this
+  // class is to bypass these.
+
+  // Support users creating arrays of ManualConstructor<>s.  This ensures that
+  // the array itself has the correct alignment.
+  static void* operator new[](size_t size) {
+    return AlignedAlloc(size, ALIGNOF(Type));
+  }
+  static void operator delete[](void* mem) {
+    AlignedFree(mem);
+  }
+
+  inline Type* get() {
+    return space_.template data_as<Type>();
+  }
+  inline const Type* get() const  {
+    return space_.template data_as<Type>();
+  }
+
+  inline Type* operator->() { return get(); }
+  inline const Type* operator->() const { return get(); }
+
+  inline Type& operator*() { return *get(); }
+  inline const Type& operator*() const { return *get(); }
+
+  template <typename... Ts>
+  inline void Init(const Ts&... params) {
+    new(space_.void_data()) Type(params...);
+  }
+
+  inline void Destroy() {
+    get()->~Type();
+  }
+
+ private:
+  AlignedMemory<sizeof(Type), ALIGNOF(Type)> space_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc
new file mode 100644
index 0000000..6a8ed21
--- /dev/null
+++ b/base/memory/memory_pressure_listener.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_listener.h"
+
+#include "base/lazy_instance.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/trace_event/trace_event.h"
+
+namespace {
+
+// ObserverListThreadSafe is RefCountedThreadSafe, this traits is needed
+// to ensure the LazyInstance will hold a reference to it.
+struct LeakyLazyObserverListTraits :
+    base::internal::LeakyLazyInstanceTraits<
+        ObserverListThreadSafe<base::MemoryPressureListener> > {
+  static ObserverListThreadSafe<base::MemoryPressureListener>*
+      New(void* instance) {
+    ObserverListThreadSafe<base::MemoryPressureListener>* ret =
+        base::internal::LeakyLazyInstanceTraits<
+            ObserverListThreadSafe<base::MemoryPressureListener> >::New(
+                instance);
+    // Leaky.
+    ret->AddRef();
+    return ret;
+  }
+};
+
+base::LazyInstance<
+    ObserverListThreadSafe<base::MemoryPressureListener>,
+    LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+namespace base {
+
+MemoryPressureListener::MemoryPressureListener(
+    const MemoryPressureListener::MemoryPressureCallback& callback)
+    : callback_(callback) {
+  g_observers.Get().AddObserver(this);
+}
+
+MemoryPressureListener::~MemoryPressureListener() {
+  g_observers.Get().RemoveObserver(this);
+}
+
+void MemoryPressureListener::Notify(MemoryPressureLevel memory_pressure_level) {
+  callback_.Run(memory_pressure_level);
+}
+
+// static
+void MemoryPressureListener::NotifyMemoryPressure(
+    MemoryPressureLevel memory_pressure_level) {
+  DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
+  TRACE_EVENT1("memory", "MemoryPressureListener::NotifyMemoryPressure",
+      "level", memory_pressure_level);
+  g_observers.Get().Notify(FROM_HERE, &MemoryPressureListener::Notify,
+                           memory_pressure_level);
+}
+
+}  // namespace base
diff --git a/base/memory/memory_pressure_listener.h b/base/memory/memory_pressure_listener.h
new file mode 100644
index 0000000..6adaeee
--- /dev/null
+++ b/base/memory/memory_pressure_listener.h
@@ -0,0 +1,85 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// MemoryPressure provides static APIs for handling memory pressure on
+// platforms that have such signals, such as Android and ChromeOS.
+// The app will try to discard buffers that aren't deemed essential (individual
+// modules will implement their own policy).
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+
+namespace base {
+
+// To start listening, create a new instance, passing a callback to a
+// function that takes a MemoryPressureLevel parameter. To stop listening,
+// simply delete the listener object. The implementation guarantees
+// that the callback will always be called on the thread that created
+// the listener.
+// Note that even on the same thread, the callback is not guaranteed to be
+// called synchronously within the system memory pressure broadcast.
+// Please see notes in MemoryPressureLevel enum below: some levels are
+// absolutely critical, and if not enough memory is returned to the system,
+// it'll potentially kill the app, and then later the app will have to be
+// cold-started.
+//
+// Example:
+//
+//    void OnMemoryPressure(MemoryPressureLevel memory_pressure_level) {
+//       ...
+//    }
+//
+//    // Start listening.
+//    MemoryPressureListener* my_listener =
+//        new MemoryPressureListener(base::Bind(&OnMemoryPressure));
+//
+//    ...
+//
+//    // Stop listening.
+//    delete my_listener;
+//
+class BASE_EXPORT MemoryPressureListener {
+ public:
+  // A Java counterpart will be generated for this enum.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
+  enum MemoryPressureLevel {
+    // No problems, there is enough memory to use. This event is not sent via
+    // callback, but the enum is used in other places to find out the current
+    // state of the system.
+    MEMORY_PRESSURE_LEVEL_NONE = -1,
+
+    // Modules are advised to free buffers that are cheap to re-allocate and not
+    // immediately needed.
+    MEMORY_PRESSURE_LEVEL_MODERATE = 0,
+
+    // At this level, modules are advised to free all possible memory.  The
+    // alternative is to be killed by the system, which means all memory will
+    // have to be re-created, plus the cost of a cold start.
+    MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
+  };
+
+  typedef base::Callback<void(MemoryPressureLevel)> MemoryPressureCallback;
+
+  explicit MemoryPressureListener(
+      const MemoryPressureCallback& memory_pressure_callback);
+  ~MemoryPressureListener();
+
+  // Intended for use by the platform specific implementation.
+  static void NotifyMemoryPressure(MemoryPressureLevel memory_pressure_level);
+
+ private:
+  void Notify(MemoryPressureLevel memory_pressure_level);
+
+  MemoryPressureCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureListener);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
diff --git a/base/memory/memory_pressure_monitor.cc b/base/memory/memory_pressure_monitor.cc
new file mode 100644
index 0000000..00633f1
--- /dev/null
+++ b/base/memory/memory_pressure_monitor.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_monitor.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+MemoryPressureMonitor* g_monitor = nullptr;
+
+}  // namespace
+
+MemoryPressureMonitor::MemoryPressureMonitor() {
+  DCHECK(!g_monitor);
+  g_monitor = this;
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+  DCHECK(g_monitor);
+  g_monitor = nullptr;
+}
+
+// static
+MemoryPressureMonitor* MemoryPressureMonitor::Get() {
+  return g_monitor;
+}
+
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor.h
new file mode 100644
index 0000000..50260c4
--- /dev/null
+++ b/base/memory/memory_pressure_monitor.h
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+
+namespace base {
+
+// Declares the interface for a MemoryPressureMonitor. There are multiple
+// OS specific implementations of this class. An instance of the memory
+// pressure observer is created at the process level, tracks memory usage, and
+// pushes memory state change notifications to the static function
+// base::MemoryPressureListener::NotifyMemoryPressure. This is turn notifies
+// all MemoryPressureListener instances via a callback.
+class BASE_EXPORT MemoryPressureMonitor {
+ public:
+  using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
+  virtual ~MemoryPressureMonitor();
+
+  // Return the singleton MemoryPressureMonitor.
+  static MemoryPressureMonitor* Get();
+
+  // Returns the currently observed memory pressure.
+  virtual MemoryPressureLevel GetCurrentPressureLevel() const = 0;
+
+ protected:
+  MemoryPressureMonitor();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 0000000..0190558
--- /dev/null
+++ b/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/template_util.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+
+// It is dangerous to post a task with a T* argument where T is a subtype of
+// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
+// object may already have been deleted since it was not held with a
+// scoped_refptr. Example: http://crbug.com/27191
+// The following set of traits are designed to generate a compile error
+// whenever this antipattern is attempted.
+
+namespace base {
+
+// This is a base internal implementation file used by task.h and callback.h.
+// Not for public consumption, so we wrap it in namespace internal.
+namespace internal {
+
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr {
+#if defined(OS_WIN)
+  enum {
+    value = base::false_type::value
+  };
+#else
+  enum {
+    // Human readable translation: you needed to be a scoped_refptr if you are a
+    // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
+    // type.
+    value = (is_pointer<T>::value &&
+             (is_convertible<T, subtle::RefCountedBase*>::value ||
+              is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
+  };
+#endif
+};
+
+template <typename Params>
+struct ParamsUseScopedRefptrCorrectly {
+  enum { value = 0 };
+};
+
+template <>
+struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
+  enum { value = 1 };
+};
+
+template <typename A>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A>> {
+  enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
+};
+
+template <typename A, typename B>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value) };
+};
+
+template <typename A, typename B, typename C>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value) };
+};
+
+template <typename A, typename B, typename C, typename D>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F, typename G>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<G>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F, typename G, typename H>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G, H>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<G>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<H>::value) };
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/base/memory/ref_counted.cc b/base/memory/ref_counted.cc
new file mode 100644
index 0000000..f5924d0
--- /dev/null
+++ b/base/memory/ref_counted.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+
+namespace subtle {
+
+bool RefCountedThreadSafeBase::HasOneRef() const {
+  return AtomicRefCountIsOne(
+      &const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
+}
+
+RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
+#ifndef NDEBUG
+  in_dtor_ = false;
+#endif
+}
+
+RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+#ifndef NDEBUG
+  DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
+                      "calling Release()";
+#endif
+}
+
+void RefCountedThreadSafeBase::AddRef() const {
+#ifndef NDEBUG
+  DCHECK(!in_dtor_);
+#endif
+  AtomicRefCountInc(&ref_count_);
+}
+
+bool RefCountedThreadSafeBase::Release() const {
+#ifndef NDEBUG
+  DCHECK(!in_dtor_);
+  DCHECK(!AtomicRefCountIsZero(&ref_count_));
+#endif
+  if (!AtomicRefCountDec(&ref_count_)) {
+#ifndef NDEBUG
+    in_dtor_ = true;
+#endif
+    return true;
+  }
+  return false;
+}
+
+}  // namespace subtle
+
+}  // namespace base
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
new file mode 100644
index 0000000..5f94b4c
--- /dev/null
+++ b/base/memory/ref_counted.h
@@ -0,0 +1,440 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_H_
+#define BASE_MEMORY_REF_COUNTED_H_
+
+#include <cassert>
+#include <iosfwd>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#ifndef NDEBUG
+#include "base/logging.h"
+#endif
+#include "base/move.h"
+#include "base/threading/thread_collision_warner.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace subtle {
+
+class BASE_EXPORT RefCountedBase {
+ public:
+  bool HasOneRef() const { return ref_count_ == 1; }
+
+ protected:
+  RefCountedBase()
+      : ref_count_(0)
+  #ifndef NDEBUG
+      , in_dtor_(false)
+  #endif
+      {
+  }
+
+  ~RefCountedBase() {
+  #ifndef NDEBUG
+    DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
+  #endif
+  }
+
+
+  void AddRef() const {
+    // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+    // Current thread books the critical section "AddRelease"
+    // without release it.
+    // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+  #ifndef NDEBUG
+    DCHECK(!in_dtor_);
+  #endif
+    ++ref_count_;
+  }
+
+  // Returns true if the object should self-delete.
+  bool Release() const {
+    // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+    // Current thread books the critical section "AddRelease"
+    // without release it.
+    // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+  #ifndef NDEBUG
+    DCHECK(!in_dtor_);
+  #endif
+    if (--ref_count_ == 0) {
+  #ifndef NDEBUG
+      in_dtor_ = true;
+  #endif
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  mutable int ref_count_;
+#ifndef NDEBUG
+  mutable bool in_dtor_;
+#endif
+
+  DFAKE_MUTEX(add_release_);
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+class BASE_EXPORT RefCountedThreadSafeBase {
+ public:
+  bool HasOneRef() const;
+
+ protected:
+  RefCountedThreadSafeBase();
+  ~RefCountedThreadSafeBase();
+
+  void AddRef() const;
+
+  // Returns true if the object should self-delete.
+  bool Release() const;
+
+ private:
+  mutable AtomicRefCount ref_count_;
+#ifndef NDEBUG
+  mutable bool in_dtor_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
+};
+
+}  // namespace subtle
+
+//
+// A base class for reference counted classes.  Otherwise, known as a cheap
+// knock-off of WebKit's RefCounted<T> class.  To use this guy just extend your
+// class from it like so:
+//
+//   class MyFoo : public base::RefCounted<MyFoo> {
+//    ...
+//    private:
+//     friend class base::RefCounted<MyFoo>;
+//     ~MyFoo();
+//   };
+//
+// You should always make your destructor private, to avoid any code deleting
+// the object accidently while there are references to it.
+template <class T>
+class RefCounted : public subtle::RefCountedBase {
+ public:
+  RefCounted() {}
+
+  void AddRef() const {
+    subtle::RefCountedBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedBase::Release()) {
+      delete static_cast<const T*>(this);
+    }
+  }
+
+ protected:
+  ~RefCounted() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
+};
+
+// Forward declaration.
+template <class T, typename Traits> class RefCountedThreadSafe;
+
+// Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
+// count reaches 0.  Overload to delete it on a different thread etc.
+template<typename T>
+struct DefaultRefCountedThreadSafeTraits {
+  static void Destruct(const T* x) {
+    // Delete through RefCountedThreadSafe to make child classes only need to be
+    // friend with RefCountedThreadSafe instead of this struct, which is an
+    // implementation detail.
+    RefCountedThreadSafe<T,
+                         DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
+  }
+};
+
+//
+// A thread-safe variant of RefCounted<T>
+//
+//   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
+//    ...
+//   };
+//
+// If you're using the default trait, then you should add compile time
+// asserts that no one else is deleting your object.  i.e.
+//    private:
+//     friend class base::RefCountedThreadSafe<MyFoo>;
+//     ~MyFoo();
+template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
+class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
+ public:
+  RefCountedThreadSafe() {}
+
+  void AddRef() const {
+    subtle::RefCountedThreadSafeBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedThreadSafeBase::Release()) {
+      Traits::Destruct(static_cast<const T*>(this));
+    }
+  }
+
+ protected:
+  ~RefCountedThreadSafe() {}
+
+ private:
+  friend struct DefaultRefCountedThreadSafeTraits<T>;
+  static void DeleteInternal(const T* x) { delete x; }
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
+};
+
+//
+// A thread-safe wrapper for some piece of data so we can place other
+// things in scoped_refptrs<>.
+//
+template<typename T>
+class RefCountedData
+    : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
+ public:
+  RefCountedData() : data() {}
+  RefCountedData(const T& in_value) : data(in_value) {}
+
+  T data;
+
+ private:
+  friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
+  ~RefCountedData() {}
+};
+
+}  // namespace base
+
+//
+// A smart pointer class for reference counted objects.  Use this class instead
+// of calling AddRef and Release manually on a reference counted object to
+// avoid common memory leaks caused by forgetting to Release an object
+// reference.  Sample usage:
+//
+//   class MyFoo : public RefCounted<MyFoo> {
+//    ...
+//   };
+//
+//   void some_function() {
+//     scoped_refptr<MyFoo> foo = new MyFoo();
+//     foo->Method(param);
+//     // |foo| is released when this function returns
+//   }
+//
+//   void some_other_function() {
+//     scoped_refptr<MyFoo> foo = new MyFoo();
+//     ...
+//     foo = NULL;  // explicitly releases |foo|
+//     ...
+//     if (foo)
+//       foo->Method(param);
+//   }
+//
+// The above examples show how scoped_refptr<T> acts like a pointer to T.
+// Given two scoped_refptr<T> classes, it is also possible to exchange
+// references between the two objects, like so:
+//
+//   {
+//     scoped_refptr<MyFoo> a = new MyFoo();
+//     scoped_refptr<MyFoo> b;
+//
+//     b.swap(a);
+//     // now, |b| references the MyFoo object, and |a| references NULL.
+//   }
+//
+// To make both |a| and |b| in the above example reference the same MyFoo
+// object, simply use the assignment operator:
+//
+//   {
+//     scoped_refptr<MyFoo> a = new MyFoo();
+//     scoped_refptr<MyFoo> b;
+//
+//     b = a;
+//     // now, |a| and |b| each own a reference to the same MyFoo object.
+//   }
+//
+template <class T>
+class scoped_refptr {
+  TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
+ public:
+  typedef T element_type;
+
+  scoped_refptr() : ptr_(NULL) {
+  }
+
+  scoped_refptr(T* p) : ptr_(p) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  template <typename U>
+  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  template <typename U>
+  scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
+    r.ptr_ = nullptr;
+  }
+
+  ~scoped_refptr() {
+    if (ptr_)
+      Release(ptr_);
+  }
+
+  T* get() const { return ptr_; }
+
+  T& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+
+  T* operator->() const {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+
+  scoped_refptr<T>& operator=(T* p) {
+    // AddRef first so that self assignment should work
+    if (p)
+      AddRef(p);
+    T* old_ptr = ptr_;
+    ptr_ = p;
+    if (old_ptr)
+      Release(old_ptr);
+    return *this;
+  }
+
+  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
+    return *this = r.ptr_;
+  }
+
+  template <typename U>
+  scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
+    return *this = r.get();
+  }
+
+  scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
+    scoped_refptr<T>(r.Pass()).swap(*this);
+    return *this;
+  }
+
+  template <typename U>
+  scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
+    scoped_refptr<T>(r.Pass()).swap(*this);
+    return *this;
+  }
+
+  void swap(T** pp) {
+    T* p = ptr_;
+    ptr_ = *pp;
+    *pp = p;
+  }
+
+  void swap(scoped_refptr<T>& r) {
+    swap(&r.ptr_);
+  }
+
+ private:
+  template <typename U> friend class scoped_refptr;
+
+  // Allow scoped_refptr<T> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "refptr1 == refptr2"
+  // will compile but do the wrong thing (i.e., convert to Testable
+  // and then do the comparison).
+  typedef T* scoped_refptr::*Testable;
+
+ public:
+  operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
+
+  template <typename U>
+  bool operator==(const scoped_refptr<U>& rhs) const {
+    return ptr_ == rhs.get();
+  }
+
+  template <typename U>
+  bool operator!=(const scoped_refptr<U>& rhs) const {
+    return !operator==(rhs);
+  }
+
+  template <typename U>
+  bool operator<(const scoped_refptr<U>& rhs) const {
+    return ptr_ < rhs.get();
+  }
+
+ protected:
+  T* ptr_;
+
+ private:
+  // Non-inline helpers to allow:
+  //     class Opaque;
+  //     extern template class scoped_refptr<Opaque>;
+  // Otherwise the compiler will complain that Opaque is an incomplete type.
+  static void AddRef(T* ptr);
+  static void Release(T* ptr);
+};
+
+template <typename T>
+void scoped_refptr<T>::AddRef(T* ptr) {
+  ptr->AddRef();
+}
+
+template <typename T>
+void scoped_refptr<T>::Release(T* ptr) {
+  ptr->Release();
+}
+
+// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
+// having to retype all the template arguments
+template <typename T>
+scoped_refptr<T> make_scoped_refptr(T* t) {
+  return scoped_refptr<T>(t);
+}
+
+// Temporary operator overloads to facilitate the transition. See
+// https://crbug.com/110610.
+template <typename T, typename U>
+bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
+  return lhs.get() == rhs;
+}
+
+template <typename T, typename U>
+bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
+  return lhs == rhs.get();
+}
+
+template <typename T, typename U>
+bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
+  return !operator==(lhs, rhs);
+}
+
+template <typename T, typename U>
+bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
+  return !operator==(lhs, rhs);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
+  return out << p.get();
+}
+
+#endif  // BASE_MEMORY_REF_COUNTED_H_
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
new file mode 100644
index 0000000..6a109e8
--- /dev/null
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -0,0 +1,78 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
+#define BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+// TODO(ricea): Remove the following include once all callers have been fixed.
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// RefCountedDeleteOnMessageLoop is similar to RefCountedThreadSafe, and ensures
+// that the object will be deleted on a specified message loop.
+//
+// Sample usage:
+// class Foo : public RefCountedDeleteOnMessageLoop<Foo> {
+//
+//   Foo(const scoped_refptr<SingleThreadTaskRunner>& loop)
+//       : RefCountedDeleteOnMessageLoop<Foo>(loop) {
+//     ...
+//   }
+//   ...
+//  private:
+//   friend class RefCountedDeleteOnMessageLoop<Foo>;
+//   friend class DeleteHelper<Foo>;
+//
+//   ~Foo();
+// };
+
+// TODO(skyostil): Rename this to RefCountedDeleteOnTaskRunner.
+template <class T>
+class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
+ public:
+  // This constructor will accept a MessageL00pProxy object, but new code should
+  // prefer a SingleThreadTaskRunner. A SingleThreadTaskRunner for the
+  // MessageLoop on the current thread can be acquired by calling
+  // MessageLoop::current()->task_runner().
+  RefCountedDeleteOnMessageLoop(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+      : task_runner_(task_runner) {
+    DCHECK(task_runner_);
+  }
+
+  void AddRef() const {
+    subtle::RefCountedThreadSafeBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedThreadSafeBase::Release())
+      DestructOnMessageLoop();
+  }
+
+ protected:
+  friend class DeleteHelper<RefCountedDeleteOnMessageLoop>;
+  ~RefCountedDeleteOnMessageLoop() {}
+
+  void DestructOnMessageLoop() const {
+    const T* t = static_cast<const T*>(this);
+    if (task_runner_->BelongsToCurrentThread())
+      delete t;
+    else
+      task_runner_->DeleteSoon(FROM_HERE, t);
+  }
+
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RefCountedDeleteOnMessageLoop);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc
new file mode 100644
index 0000000..477c941
--- /dev/null
+++ b/base/memory/ref_counted_memory.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted_memory.h"
+
+#include <stdlib.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+bool RefCountedMemory::Equals(
+    const scoped_refptr<RefCountedMemory>& other) const {
+  return other.get() &&
+         size() == other->size() &&
+         (memcmp(front(), other->front(), size()) == 0);
+}
+
+RefCountedMemory::RefCountedMemory() {}
+
+RefCountedMemory::~RefCountedMemory() {}
+
+const unsigned char* RefCountedStaticMemory::front() const {
+  return data_;
+}
+
+size_t RefCountedStaticMemory::size() const {
+  return length_;
+}
+
+RefCountedStaticMemory::~RefCountedStaticMemory() {}
+
+RefCountedBytes::RefCountedBytes() {}
+
+RefCountedBytes::RefCountedBytes(const std::vector<unsigned char>& initializer)
+    : data_(initializer) {
+}
+
+RefCountedBytes::RefCountedBytes(const unsigned char* p, size_t size)
+    : data_(p, p + size) {}
+
+RefCountedBytes* RefCountedBytes::TakeVector(
+    std::vector<unsigned char>* to_destroy) {
+  RefCountedBytes* bytes = new RefCountedBytes;
+  bytes->data_.swap(*to_destroy);
+  return bytes;
+}
+
+const unsigned char* RefCountedBytes::front() const {
+  // STL will assert if we do front() on an empty vector, but calling code
+  // expects a NULL.
+  return size() ? &data_.front() : NULL;
+}
+
+size_t RefCountedBytes::size() const {
+  return data_.size();
+}
+
+RefCountedBytes::~RefCountedBytes() {}
+
+RefCountedString::RefCountedString() {}
+
+RefCountedString::~RefCountedString() {}
+
+// static
+RefCountedString* RefCountedString::TakeString(std::string* to_destroy) {
+  RefCountedString* self = new RefCountedString;
+  to_destroy->swap(self->data_);
+  return self;
+}
+
+const unsigned char* RefCountedString::front() const {
+  return data_.empty() ? NULL :
+         reinterpret_cast<const unsigned char*>(data_.data());
+}
+
+size_t RefCountedString::size() const {
+  return data_.size();
+}
+
+RefCountedMallocedMemory::RefCountedMallocedMemory(
+    void* data, size_t length)
+    : data_(reinterpret_cast<unsigned char*>(data)), length_(length) {
+  DCHECK(data || length == 0);
+}
+
+const unsigned char* RefCountedMallocedMemory::front() const {
+  return length_ ? data_ : NULL;
+}
+
+size_t RefCountedMallocedMemory::size() const {
+  return length_;
+}
+
+RefCountedMallocedMemory::~RefCountedMallocedMemory() {
+  free(data_);
+}
+
+}  //  namespace base
diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h
new file mode 100644
index 0000000..66dc65f
--- /dev/null
+++ b/base/memory/ref_counted_memory.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// A generic interface to memory. This object is reference counted because one
+// of its two subclasses own the data they carry, and we need to have
+// heterogeneous containers of these two types of memory.
+class BASE_EXPORT RefCountedMemory
+    : public base::RefCountedThreadSafe<RefCountedMemory> {
+ public:
+  // Retrieves a pointer to the beginning of the data we point to. If the data
+  // is empty, this will return NULL.
+  virtual const unsigned char* front() const = 0;
+
+  // Size of the memory pointed to.
+  virtual size_t size() const = 0;
+
+  // Returns true if |other| is byte for byte equal.
+  bool Equals(const scoped_refptr<RefCountedMemory>& other) const;
+
+  // Handy method to simplify calling front() with a reinterpret_cast.
+  template<typename T> const T* front_as() const {
+    return reinterpret_cast<const T*>(front());
+  }
+
+ protected:
+  friend class base::RefCountedThreadSafe<RefCountedMemory>;
+  RefCountedMemory();
+  virtual ~RefCountedMemory();
+};
+
+// An implementation of RefCountedMemory, where the ref counting does not
+// matter.
+class BASE_EXPORT RefCountedStaticMemory : public RefCountedMemory {
+ public:
+  RefCountedStaticMemory()
+      : data_(NULL), length_(0) {}
+  RefCountedStaticMemory(const void* data, size_t length)
+      : data_(static_cast<const unsigned char*>(length ? data : NULL)),
+        length_(length) {}
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+ private:
+  ~RefCountedStaticMemory() override;
+
+  const unsigned char* data_;
+  size_t length_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedStaticMemory);
+};
+
+// An implementation of RefCountedMemory, where we own the data in a vector.
+class BASE_EXPORT RefCountedBytes : public RefCountedMemory {
+ public:
+  RefCountedBytes();
+
+  // Constructs a RefCountedBytes object by _copying_ from |initializer|.
+  explicit RefCountedBytes(const std::vector<unsigned char>& initializer);
+
+  // Constructs a RefCountedBytes object by copying |size| bytes from |p|.
+  RefCountedBytes(const unsigned char* p, size_t size);
+
+  // Constructs a RefCountedBytes object by performing a swap. (To non
+  // destructively build a RefCountedBytes, use the constructor that takes a
+  // vector.)
+  static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy);
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+  const std::vector<unsigned char>& data() const { return data_; }
+  std::vector<unsigned char>& data() { return data_; }
+
+ private:
+  ~RefCountedBytes() override;
+
+  std::vector<unsigned char> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedBytes);
+};
+
+// An implementation of RefCountedMemory, where the bytes are stored in an STL
+// string. Use this if your data naturally arrives in that format.
+class BASE_EXPORT RefCountedString : public RefCountedMemory {
+ public:
+  RefCountedString();
+
+  // Constructs a RefCountedString object by performing a swap. (To non
+  // destructively build a RefCountedString, use the default constructor and
+  // copy into object->data()).
+  static RefCountedString* TakeString(std::string* to_destroy);
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+  const std::string& data() const { return data_; }
+  std::string& data() { return data_; }
+
+ private:
+  ~RefCountedString() override;
+
+  std::string data_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedString);
+};
+
+// An implementation of RefCountedMemory that holds a chunk of memory
+// previously allocated with malloc or calloc, and that therefore must be freed
+// using free().
+class BASE_EXPORT RefCountedMallocedMemory : public base::RefCountedMemory {
+ public:
+  RefCountedMallocedMemory(void* data, size_t length);
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+ private:
+  ~RefCountedMallocedMemory() override;
+
+  unsigned char* data_;
+  size_t length_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedMallocedMemory);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc
new file mode 100644
index 0000000..5bfc1c7
--- /dev/null
+++ b/base/memory/ref_counted_memory_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted_memory.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) {
+  scoped_refptr<RefCountedMemory> mem = new RefCountedStaticMemory(
+      "static mem00", 10);
+
+  EXPECT_EQ(10U, mem->size());
+  EXPECT_EQ("static mem", std::string(mem->front_as<char>(), mem->size()));
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedBytes) {
+  std::vector<uint8> data;
+  data.push_back(45);
+  data.push_back(99);
+  scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data);
+
+  EXPECT_EQ(0U, data.size());
+
+  EXPECT_EQ(2U, mem->size());
+  EXPECT_EQ(45U, mem->front()[0]);
+  EXPECT_EQ(99U, mem->front()[1]);
+
+  scoped_refptr<RefCountedMemory> mem2;
+  {
+    unsigned char data2[] = { 12, 11, 99 };
+    mem2 = new RefCountedBytes(data2, 3);
+  }
+  EXPECT_EQ(3U, mem2->size());
+  EXPECT_EQ(12U, mem2->front()[0]);
+  EXPECT_EQ(11U, mem2->front()[1]);
+  EXPECT_EQ(99U, mem2->front()[2]);
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedString) {
+  std::string s("destroy me");
+  scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s);
+
+  EXPECT_EQ(0U, s.size());
+
+  EXPECT_EQ(10U, mem->size());
+  EXPECT_EQ('d', mem->front()[0]);
+  EXPECT_EQ('e', mem->front()[1]);
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedMallocedMemory) {
+  void* data = malloc(6);
+  memcpy(data, "hello", 6);
+
+  scoped_refptr<RefCountedMemory> mem = new RefCountedMallocedMemory(data, 6);
+
+  EXPECT_EQ(6U, mem->size());
+  EXPECT_EQ(0, memcmp("hello", mem->front(), 6));
+}
+
+TEST(RefCountedMemoryUnitTest, Equals) {
+  std::string s1("same");
+  scoped_refptr<RefCountedMemory> mem1 = RefCountedString::TakeString(&s1);
+
+  std::vector<unsigned char> d2;
+  d2.push_back('s');
+  d2.push_back('a');
+  d2.push_back('m');
+  d2.push_back('e');
+  scoped_refptr<RefCountedMemory> mem2 = RefCountedBytes::TakeVector(&d2);
+
+  EXPECT_TRUE(mem1->Equals(mem2));
+
+  std::string s3("diff");
+  scoped_refptr<RefCountedMemory> mem3 = RefCountedString::TakeString(&s3);
+
+  EXPECT_FALSE(mem1->Equals(mem3));
+  EXPECT_FALSE(mem2->Equals(mem3));
+}
+
+TEST(RefCountedMemoryUnitTest, EqualsNull) {
+  std::string s("str");
+  scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s);
+  EXPECT_FALSE(mem->Equals(NULL));
+}
+
+}  //  namespace base
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
new file mode 100644
index 0000000..6f8e599
--- /dev/null
+++ b/base/memory/ref_counted_unittest.cc
@@ -0,0 +1,462 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+
+#include "base/test/opaque_ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SelfAssign : public base::RefCounted<SelfAssign> {
+ protected:
+  virtual ~SelfAssign() {}
+
+ private:
+  friend class base::RefCounted<SelfAssign>;
+};
+
+class Derived : public SelfAssign {
+ protected:
+  ~Derived() override {}
+
+ private:
+  friend class base::RefCounted<Derived>;
+};
+
+class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
+ public:
+  CheckDerivedMemberAccess() {
+    // This shouldn't compile if we don't have access to the member variable.
+    SelfAssign** pptr = &ptr_;
+    EXPECT_EQ(*pptr, ptr_);
+  }
+};
+
+class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> {
+ public:
+  ScopedRefPtrToSelf() : self_ptr_(this) {}
+
+  static bool was_destroyed() { return was_destroyed_; }
+
+  static void reset_was_destroyed() { was_destroyed_ = false; }
+
+  scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrToSelf>;
+  ~ScopedRefPtrToSelf() { was_destroyed_ = true; }
+
+  static bool was_destroyed_;
+};
+
+bool ScopedRefPtrToSelf::was_destroyed_ = false;
+
+class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> {
+ public:
+  ScopedRefPtrCountBase() { ++constructor_count_; }
+
+  static int constructor_count() { return constructor_count_; }
+
+  static int destructor_count() { return destructor_count_; }
+
+  static void reset_count() {
+    constructor_count_ = 0;
+    destructor_count_ = 0;
+  }
+
+ protected:
+  virtual ~ScopedRefPtrCountBase() { ++destructor_count_; }
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrCountBase>;
+
+  static int constructor_count_;
+  static int destructor_count_;
+};
+
+int ScopedRefPtrCountBase::constructor_count_ = 0;
+int ScopedRefPtrCountBase::destructor_count_ = 0;
+
+class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase {
+ public:
+  ScopedRefPtrCountDerived() { ++constructor_count_; }
+
+  static int constructor_count() { return constructor_count_; }
+
+  static int destructor_count() { return destructor_count_; }
+
+  static void reset_count() {
+    constructor_count_ = 0;
+    destructor_count_ = 0;
+  }
+
+ protected:
+  ~ScopedRefPtrCountDerived() override { ++destructor_count_; }
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrCountDerived>;
+
+  static int constructor_count_;
+  static int destructor_count_;
+};
+
+int ScopedRefPtrCountDerived::constructor_count_ = 0;
+int ScopedRefPtrCountDerived::destructor_count_ = 0;
+
+}  // end namespace
+
+TEST(RefCountedUnitTest, TestSelfAssignment) {
+  SelfAssign* p = new SelfAssign;
+  scoped_refptr<SelfAssign> var(p);
+  var = var;
+  EXPECT_EQ(var.get(), p);
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) {
+  CheckDerivedMemberAccess check;
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) {
+  ScopedRefPtrToSelf::reset_was_destroyed();
+
+  ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
+  EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
+  check->self_ptr_ = nullptr;
+  EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) {
+  ScopedRefPtrToSelf::reset_was_destroyed();
+
+  ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
+  EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
+  // Releasing |check->self_ptr_| will delete |check|.
+  // The move assignment operator must assign |check->self_ptr_| first then
+  // release |check->self_ptr_|.
+  check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>();
+  EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToOpaque) {
+  scoped_refptr<base::OpaqueRefCounted> p = base::MakeOpaqueRefCounted();
+  base::TestOpaqueRefCounted(p);
+
+  scoped_refptr<base::OpaqueRefCounted> q;
+  q = p;
+  base::TestOpaqueRefCounted(p);
+  base::TestOpaqueRefCounted(q);
+}
+
+TEST(RefCountedUnitTest, BooleanTesting) {
+  scoped_refptr<SelfAssign> p;
+  EXPECT_FALSE(p);
+  p = new SelfAssign;
+  EXPECT_TRUE(p);
+}
+
+TEST(RefCountedUnitTest, Equality) {
+  scoped_refptr<SelfAssign> p1(new SelfAssign);
+  scoped_refptr<SelfAssign> p2(new SelfAssign);
+
+  EXPECT_EQ(p1, p1);
+  EXPECT_EQ(p2, p2);
+
+  EXPECT_NE(p1, p2);
+  EXPECT_NE(p2, p1);
+}
+
+TEST(RefCountedUnitTest, ConvertibleEquality) {
+  scoped_refptr<Derived> p1(new Derived);
+  scoped_refptr<SelfAssign> p2;
+
+  EXPECT_NE(p1, p2);
+  EXPECT_NE(p2, p1);
+
+  p2 = p1;
+
+  EXPECT_EQ(p1, p2);
+  EXPECT_EQ(p2, p1);
+}
+
+TEST(RefCountedUnitTest, SelfMoveAssignment) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    p = p.Pass();
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(raw, p.get());
+
+    // p goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignment1) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2;
+
+      p2 = p1.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignment2) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1;
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(raw);
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(raw, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1);
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(raw, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1);
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p2 = p1.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase();
+      scoped_refptr<ScopedRefPtrCountBase> p2(raw2);
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(raw2, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentDerived) {
+  ScopedRefPtrCountBase::reset_count();
+  ScopedRefPtrCountDerived::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+    {
+      ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived();
+      scoped_refptr<ScopedRefPtrCountDerived> p2(raw2);
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+      EXPECT_EQ(raw2, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveConstructor) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveConstructorDerived) {
+  ScopedRefPtrCountBase::reset_count();
+  ScopedRefPtrCountDerived::reset_count();
+
+  {
+    ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived();
+    scoped_refptr<ScopedRefPtrCountDerived> p1(raw1);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw1, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+}
+
diff --git a/base/memory/scoped_policy.h b/base/memory/scoped_policy.h
new file mode 100644
index 0000000..5dbf204
--- /dev/null
+++ b/base/memory/scoped_policy.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_POLICY_H_
+#define BASE_MEMORY_SCOPED_POLICY_H_
+
+namespace base {
+namespace scoped_policy {
+
+// Defines the ownership policy for a scoped object.
+enum OwnershipPolicy {
+  // The scoped object takes ownership of an object by taking over an existing
+  // ownership claim.
+  ASSUME,
+
+  // The scoped object will retain the the object and any initial ownership is
+  // not changed.
+  RETAIN
+};
+
+}  // namespace scoped_policy
+}  // namespace base
+
+#endif  // BASE_MEMORY_SCOPED_POLICY_H_
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
new file mode 100644
index 0000000..987ccfa
--- /dev/null
+++ b/base/memory/scoped_ptr.h
@@ -0,0 +1,594 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Scopers help you manage ownership of a pointer, helping you easily manage a
+// pointer within a scope, and automatically destroying the pointer at the end
+// of a scope.  There are two main classes you will use, which correspond to the
+// operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr<T>):
+//   {
+//     scoped_ptr<Foo> foo(new Foo("wee"));
+//   }  // foo goes out of scope, releasing the pointer with it.
+//
+//   {
+//     scoped_ptr<Foo> foo;          // No pointer managed.
+//     foo.reset(new Foo("wee"));    // Now a pointer is managed.
+//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.
+//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.
+//     foo->Method();                // Foo::Method() called.
+//     foo.get()->Method();          // Foo::Method() called.
+//     SomeFunc(foo.release());      // SomeFunc takes ownership, foo no longer
+//                                   // manages a pointer.
+//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.
+//     foo.reset();                  // Foo("wee4") destroyed, foo no longer
+//                                   // manages a pointer.
+//   }  // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_ptr<T[]>):
+//   {
+//     scoped_ptr<Foo[]> foo(new Foo[100]);
+//     foo.get()->Method();  // Foo::Method on the 0th element.
+//     foo[10].Method();     // Foo::Method on the 10th element.
+//   }
+//
+// These scopers also implement part of the functionality of C++11 unique_ptr
+// in that they are "movable but not copyable."  You can use the scopers in
+// the parameter and return types of functions to signify ownership transfer
+// in to and out of a function.  When calling a function that has a scoper
+// as the argument type, it must be called with the result of an analogous
+// scoper's Pass() function or another function that generates a temporary;
+// passing by copy will NOT work.  Here is an example using scoped_ptr:
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {
+//     // Do something with arg
+//   }
+//   scoped_ptr<Foo> CreateFoo() {
+//     // No need for calling Pass() because we are constructing a temporary
+//     // for the return value.
+//     return scoped_ptr<Foo>(new Foo("new"));
+//   }
+//   scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
+//     return arg.Pass();
+//   }
+//
+//   {
+//     scoped_ptr<Foo> ptr(new Foo("yay"));  // ptr manages Foo("yay").
+//     TakesOwnership(ptr.Pass());           // ptr no longer owns Foo("yay").
+//     scoped_ptr<Foo> ptr2 = CreateFoo();   // ptr2 owns the return Foo.
+//     scoped_ptr<Foo> ptr3 =                // ptr3 now owns what was in ptr2.
+//         PassThru(ptr2.Pass());            // ptr2 is correspondingly nullptr.
+//   }
+//
+// Notice that if you do not call Pass() when returning from PassThru(), or
+// when invoking TakesOwnership(), the code will not compile because scopers
+// are not copyable; they only implement move semantics which require calling
+// the Pass() function to signify a destructive transfer of state. CreateFoo()
+// is different though because we are constructing a temporary on the return
+// line and thus can avoid needing to call Pass().
+//
+// Pass() properly handles upcast in initialization, i.e. you can use a
+// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+//
+//   scoped_ptr<Foo> foo(new Foo());
+//   scoped_ptr<FooParent> parent(foo.Pass());
+
+#ifndef BASE_MEMORY_SCOPED_PTR_H_
+#define BASE_MEMORY_SCOPED_PTR_H_
+
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class.
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <algorithm>  // For std::swap().
+#include <iosfwd>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/move.h"
+#include "base/template_util.h"
+
+namespace base {
+
+namespace subtle {
+class RefCountedBase;
+class RefCountedThreadSafeBase;
+}  // namespace subtle
+
+// Function object which deletes its parameter, which must be a pointer.
+// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
+// invokes 'delete'. The default deleter for scoped_ptr<T>.
+template <class T>
+struct DefaultDeleter {
+  DefaultDeleter() {}
+  template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
+    // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
+    // if U* is implicitly convertible to T* and U is not an array type.
+    //
+    // Correct implementation should use SFINAE to disable this
+    // constructor. However, since there are no other 1-argument constructors,
+    // using a COMPILE_ASSERT() based on is_convertible<> and requiring
+    // complete types is simpler and will cause compile failures for equivalent
+    // misuses.
+    //
+    // Note, the is_convertible<U*, T*> check also ensures that U is not an
+    // array. T is guaranteed to be a non-array, so any U* where U is an array
+    // cannot convert to T*.
+    enum { T_must_be_complete = sizeof(T) };
+    enum { U_must_be_complete = sizeof(U) };
+    COMPILE_ASSERT((base::is_convertible<U*, T*>::value),
+                   U_ptr_must_implicitly_convert_to_T_ptr);
+  }
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
+    delete ptr;
+  }
+};
+
+// Specialization of DefaultDeleter for array types.
+template <class T>
+struct DefaultDeleter<T[]> {
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
+    delete[] ptr;
+  }
+
+ private:
+  // Disable this operator for any U != T because it is undefined to execute
+  // an array delete when the static type of the array mismatches the dynamic
+  // type.
+  //
+  // References:
+  //   C++98 [expr.delete]p3
+  //   http://cplusplus.github.com/LWG/lwg-defects.html#938
+  template <typename U> void operator()(U* array) const;
+};
+
+template <class T, int n>
+struct DefaultDeleter<T[n]> {
+  // Never allow someone to declare something like scoped_ptr<int[10]>.
+  COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
+};
+
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
+//
+// scoped_ptr<int, base::FreeDeleter> foo_ptr(
+//     static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+  inline void operator()(void* ptr) const {
+    free(ptr);
+  }
+};
+
+namespace internal {
+
+template <typename T> struct IsNotRefCounted {
+  enum {
+    value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
+        !base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
+            value
+  };
+};
+
+template <typename T>
+struct ShouldAbortOnSelfReset {
+  template <typename U>
+  static NoType Test(const typename U::AllowSelfReset*);
+
+  template <typename U>
+  static YesType Test(...);
+
+  static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
+};
+
+// Minimal implementation of the core logic of scoped_ptr, suitable for
+// reuse in both scoped_ptr and its specializations.
+template <class T, class D>
+class scoped_ptr_impl {
+ public:
+  explicit scoped_ptr_impl(T* p) : data_(p) {}
+
+  // Initializer for deleters that have data parameters.
+  scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
+
+  // Templated constructor that destructively takes the value from another
+  // scoped_ptr_impl.
+  template <typename U, typename V>
+  scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
+      : data_(other->release(), other->get_deleter()) {
+    // We do not support move-only deleters.  We could modify our move
+    // emulation to have base::subtle::move() and base::subtle::forward()
+    // functions that are imperfect emulations of their C++11 equivalents,
+    // but until there's a requirement, just assume deleters are copyable.
+  }
+
+  template <typename U, typename V>
+  void TakeState(scoped_ptr_impl<U, V>* other) {
+    // See comment in templated constructor above regarding lack of support
+    // for move-only deleters.
+    reset(other->release());
+    get_deleter() = other->get_deleter();
+  }
+
+  ~scoped_ptr_impl() {
+    if (data_.ptr != nullptr) {
+      // Not using get_deleter() saves one function call in non-optimized
+      // builds.
+      static_cast<D&>(data_)(data_.ptr);
+    }
+  }
+
+  void reset(T* p) {
+    // This is a self-reset, which is no longer allowed for default deleters:
+    // https://crbug.com/162971
+    assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
+
+    // Note that running data_.ptr = p can lead to undefined behavior if
+    // get_deleter()(get()) deletes this. In order to prevent this, reset()
+    // should update the stored pointer before deleting its old value.
+    //
+    // However, changing reset() to use that behavior may cause current code to
+    // break in unexpected ways. If the destruction of the owned object
+    // dereferences the scoped_ptr when it is destroyed by a call to reset(),
+    // then it will incorrectly dispatch calls to |p| rather than the original
+    // value of |data_.ptr|.
+    //
+    // During the transition period, set the stored pointer to nullptr while
+    // deleting the object. Eventually, this safety check will be removed to
+    // prevent the scenario initially described from occuring and
+    // http://crbug.com/176091 can be closed.
+    T* old = data_.ptr;
+    data_.ptr = nullptr;
+    if (old != nullptr)
+      static_cast<D&>(data_)(old);
+    data_.ptr = p;
+  }
+
+  T* get() const { return data_.ptr; }
+
+  D& get_deleter() { return data_; }
+  const D& get_deleter() const { return data_; }
+
+  void swap(scoped_ptr_impl& p2) {
+    // Standard swap idiom: 'using std::swap' ensures that std::swap is
+    // present in the overload set, but we call swap unqualified so that
+    // any more-specific overloads can be used, if available.
+    using std::swap;
+    swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
+    swap(data_.ptr, p2.data_.ptr);
+  }
+
+  T* release() {
+    T* old_ptr = data_.ptr;
+    data_.ptr = nullptr;
+    return old_ptr;
+  }
+
+ private:
+  // Needed to allow type-converting constructor.
+  template <typename U, typename V> friend class scoped_ptr_impl;
+
+  // Use the empty base class optimization to allow us to have a D
+  // member, while avoiding any space overhead for it when D is an
+  // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
+  // discussion of this technique.
+  struct Data : public D {
+    explicit Data(T* ptr_in) : ptr(ptr_in) {}
+    Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
+    T* ptr;
+  };
+
+  Data data_;
+
+  DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
+// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the thread safety guarantees of T.
+//
+// The size of scoped_ptr is small. On most compilers, when using the
+// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
+// increase the size proportional to whatever state they need to have. See
+// comments inside scoped_ptr_impl<> for details.
+//
+// Current implementation targets having a strict subset of  C++11's
+// unique_ptr<> features. Known deficiencies include not supporting move-only
+// deleteres, function pointers as deleters, and deleters with reference
+// types.
+template <class T, class D = base::DefaultDeleter<T> >
+class scoped_ptr {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+
+  COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
+                 T_is_refcounted_type_and_needs_scoped_refptr);
+
+ public:
+  // The element and deleter types.
+  typedef T element_type;
+  typedef D deleter_type;
+
+  // Constructor.  Defaults to initializing with nullptr.
+  scoped_ptr() : impl_(nullptr) {}
+
+  // Constructor.  Takes ownership of p.
+  explicit scoped_ptr(element_type* p) : impl_(p) {}
+
+  // Constructor.  Allows initialization of a stateful deleter.
+  scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
+
+  // Constructor.  Allows construction from a nullptr.
+  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+
+  // Constructor.  Allows construction from a scoped_ptr rvalue for a
+  // convertible type and deleter.
+  //
+  // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
+  // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
+  // has different post-conditions if D is a reference type. Since this
+  // implementation does not support deleters with reference type,
+  // we do not need a separate move constructor allowing us to avoid one
+  // use of SFINAE. You only need to care about this if you modify the
+  // implementation of scoped_ptr.
+  template <typename U, typename V>
+  scoped_ptr(scoped_ptr<U, V>&& other)
+      : impl_(&other.impl_) {
+    COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+  }
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue for a convertible
+  // type and deleter.
+  //
+  // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
+  // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
+  // form has different requirements on for move-only Deleters. Since this
+  // implementation does not support move-only Deleters, we do not need a
+  // separate move assignment operator allowing us to avoid one use of SFINAE.
+  // You only need to care about this if you modify the implementation of
+  // scoped_ptr.
+  template <typename U, typename V>
+  scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
+    COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+    impl_.TakeState(&rhs.impl_);
+    return *this;
+  }
+
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // object, if any.
+  scoped_ptr& operator=(decltype(nullptr)) {
+    reset();
+    return *this;
+  }
+
+  // Reset.  Deletes the currently owned object, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(element_type* p = nullptr) { impl_.reset(p); }
+
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  element_type& operator*() const {
+    assert(impl_.get() != nullptr);
+    return *impl_.get();
+  }
+  element_type* operator->() const  {
+    assert(impl_.get() != nullptr);
+    return impl_.get();
+  }
+  element_type* get() const { return impl_.get(); }
+
+  // Access to the deleter.
+  deleter_type& get_deleter() { return impl_.get_deleter(); }
+  const deleter_type& get_deleter() const { return impl_.get_deleter(); }
+
+  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "scoped_ptr1 ==
+  // scoped_ptr2" will compile but do the wrong thing (i.e., convert
+  // to Testable and then do the comparison).
+ private:
+  typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
+      scoped_ptr::*Testable;
+
+ public:
+  operator Testable() const {
+    return impl_.get() ? &scoped_ptr::impl_ : nullptr;
+  }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(const element_type* p) const { return impl_.get() == p; }
+  bool operator!=(const element_type* p) const { return impl_.get() != p; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    impl_.swap(p2.impl_);
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object. If this object
+  // holds a nullptr, the return value is nullptr. After this operation, this
+  // object will hold a nullptr, and will not own the object any more.
+  element_type* release() WARN_UNUSED_RESULT {
+    return impl_.release();
+  }
+
+ private:
+  // Needed to reach into |impl_| in the constructor.
+  template <typename U, typename V> friend class scoped_ptr;
+  base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+  // Forbidden for API compatibility with std::unique_ptr.
+  explicit scoped_ptr(int disallow_construction_from_null);
+
+  // Forbid comparison of scoped_ptr types.  If U != T, it totally
+  // doesn't make sense, and if U == T, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // scoped_ptrs.
+  template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+  template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
+};
+
+template <class T, class D>
+class scoped_ptr<T[], D> {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+
+ public:
+  // The element and deleter types.
+  typedef T element_type;
+  typedef D deleter_type;
+
+  // Constructor.  Defaults to initializing with nullptr.
+  scoped_ptr() : impl_(nullptr) {}
+
+  // Constructor. Stores the given array. Note that the argument's type
+  // must exactly match T*. In particular:
+  // - it cannot be a pointer to a type derived from T, because it is
+  //   inherently unsafe in the general case to access an array through a
+  //   pointer whose dynamic type does not match its static type (eg., if
+  //   T and the derived types had different sizes access would be
+  //   incorrectly calculated). Deletion is also always undefined
+  //   (C++98 [expr.delete]p3). If you're doing this, fix your code.
+  // - it cannot be const-qualified differently from T per unique_ptr spec
+  //   (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
+  //   to work around this may use implicit_cast<const T*>().
+  //   However, because of the first bullet in this comment, users MUST
+  //   NOT use implicit_cast<Base*>() to upcast the static type of the array.
+  explicit scoped_ptr(element_type* array) : impl_(array) {}
+
+  // Constructor.  Allows construction from a nullptr.
+  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+
+  // Constructor.  Allows construction from a scoped_ptr rvalue.
+  scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue.
+  scoped_ptr& operator=(scoped_ptr&& rhs) {
+    impl_.TakeState(&rhs.impl_);
+    return *this;
+  }
+
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // array, if any.
+  scoped_ptr& operator=(decltype(nullptr)) {
+    reset();
+    return *this;
+  }
+
+  // Reset.  Deletes the currently owned array, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(element_type* array = nullptr) { impl_.reset(array); }
+
+  // Accessors to get the owned array.
+  element_type& operator[](size_t i) const {
+    assert(impl_.get() != nullptr);
+    return impl_.get()[i];
+  }
+  element_type* get() const { return impl_.get(); }
+
+  // Access to the deleter.
+  deleter_type& get_deleter() { return impl_.get_deleter(); }
+  const deleter_type& get_deleter() const { return impl_.get_deleter(); }
+
+  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+ private:
+  typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
+      scoped_ptr::*Testable;
+
+ public:
+  operator Testable() const {
+    return impl_.get() ? &scoped_ptr::impl_ : nullptr;
+  }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(element_type* array) const { return impl_.get() == array; }
+  bool operator!=(element_type* array) const { return impl_.get() != array; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    impl_.swap(p2.impl_);
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object. If this object
+  // holds a nullptr, the return value is nullptr. After this operation, this
+  // object will hold a nullptr, and will not own the object any more.
+  element_type* release() WARN_UNUSED_RESULT {
+    return impl_.release();
+  }
+
+ private:
+  // Force element_type to be a complete type.
+  enum { type_must_be_complete = sizeof(element_type) };
+
+  // Actually hold the data.
+  base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+  // Disable initialization from any type other than element_type*, by
+  // providing a constructor that matches such an initialization, but is
+  // private and has no definition. This is disabled because it is not safe to
+  // call delete[] on an array whose static type does not match its dynamic
+  // type.
+  template <typename U> explicit scoped_ptr(U* array);
+  explicit scoped_ptr(int disallow_construction_from_null);
+
+  // Disable reset() from any type other than element_type*, for the same
+  // reasons as the constructor above.
+  template <typename U> void reset(U* array);
+  void reset(int disallow_reset_from_null);
+
+  // Forbid comparison of scoped_ptr types.  If U != T, it totally
+  // doesn't make sense, and if U == T, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // scoped_ptrs.
+  template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+  template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
+};
+
+// Free functions
+template <class T, class D>
+void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
+  p1.swap(p2);
+}
+
+template <class T, class D>
+bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
+  return p1 == p2.get();
+}
+
+template <class T, class D>
+bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
+  return p1 != p2.get();
+}
+
+// A function to convert T* into scoped_ptr<T>
+// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+scoped_ptr<T> make_scoped_ptr(T* ptr) {
+  return scoped_ptr<T>(ptr);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) {
+  return out << p.get();
+}
+
+#endif  // BASE_MEMORY_SCOPED_PTR_H_
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
new file mode 100644
index 0000000..766f444
--- /dev/null
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -0,0 +1,695 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+
+#include <sstream>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Used to test depth subtyping.
+class ConDecLoggerParent {
+ public:
+  virtual ~ConDecLoggerParent() {}
+
+  virtual void SetPtr(int* ptr) = 0;
+
+  virtual int SomeMeth(int x) const = 0;
+};
+
+class ConDecLogger : public ConDecLoggerParent {
+ public:
+  ConDecLogger() : ptr_(NULL) { }
+  explicit ConDecLogger(int* ptr) { SetPtr(ptr); }
+  ~ConDecLogger() override { --*ptr_; }
+
+  void SetPtr(int* ptr) override {
+    ptr_ = ptr;
+    ++*ptr_;
+  }
+
+  int SomeMeth(int x) const override { return x; }
+
+ private:
+  int* ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
+};
+
+struct CountingDeleter {
+  explicit CountingDeleter(int* count) : count_(count) {}
+  inline void operator()(double* ptr) const {
+    (*count_)++;
+  }
+  int* count_;
+};
+
+// Used to test assignment of convertible deleters.
+struct CountingDeleterChild : public CountingDeleter {
+  explicit CountingDeleterChild(int* count) : CountingDeleter(count) {}
+};
+
+class OverloadedNewAndDelete {
+ public:
+  void* operator new(size_t size) {
+    g_new_count++;
+    return malloc(size);
+  }
+
+  void operator delete(void* ptr) {
+    g_delete_count++;
+    free(ptr);
+  }
+
+  static void ResetCounters() {
+    g_new_count = 0;
+    g_delete_count = 0;
+  }
+
+  static int new_count() { return g_new_count; }
+  static int delete_count() { return g_delete_count; }
+
+ private:
+  static int g_new_count;
+  static int g_delete_count;
+};
+
+int OverloadedNewAndDelete::g_new_count = 0;
+int OverloadedNewAndDelete::g_delete_count = 0;
+
+scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
+  return logger.Pass();
+}
+
+void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
+}
+
+// Do not delete this function!  It's existence is to test that you can
+// return a temporarily constructed version of the scoper.
+scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) {
+  return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed));
+}
+
+}  // namespace
+
+TEST(ScopedPtrTest, ScopedPtr) {
+  int constructed = 0;
+
+  // Ensure size of scoped_ptr<> doesn't increase unexpectedly.
+  COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
+                 scoped_ptr_larger_than_raw_ptr);
+
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    EXPECT_EQ(10, scoper->SomeMeth(10));
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    ConDecLogger* take = scoper.release();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    delete take;
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), == and !=
+  {
+    scoped_ptr<ConDecLogger> scoper1;
+    scoped_ptr<ConDecLogger> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoper1.reset(logger);
+    EXPECT_EQ(logger, scoper1.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(logger, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
+  int constructed = 0;
+
+  // Test construction from a scoped_ptr to a derived class.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+
+    EXPECT_EQ(10, scoper_parent->SomeMeth(10));
+    EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper_parent).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment from a scoped_ptr to a derived class.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent;
+    scoper_parent = scoper.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test construction of a scoped_ptr with an additional const annotation.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_const.get());
+    EXPECT_FALSE(scoper.get());
+
+    EXPECT_EQ(10, scoper_const->SomeMeth(10));
+    EXPECT_EQ(10, scoper_const.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper_const).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment to a scoped_ptr with an additional const annotation.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<const ConDecLogger> scoper_const;
+    scoper_const = scoper.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_const.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment to a scoped_ptr deleter of parent type.
+  {
+    // Custom deleters never touch these value.
+    double dummy_value, dummy_value2;
+    int deletes = 0;
+    int alternate_deletes = 0;
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    scoped_ptr<double, CountingDeleterChild> scoper_child(
+        &dummy_value2, CountingDeleterChild(&alternate_deletes));
+
+    EXPECT_TRUE(scoper);
+    EXPECT_TRUE(scoper_child);
+    EXPECT_EQ(0, deletes);
+    EXPECT_EQ(0, alternate_deletes);
+
+    // Test this compiles and correctly overwrites the deleter state.
+    scoper = scoper_child.Pass();
+    EXPECT_TRUE(scoper);
+    EXPECT_FALSE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(0, alternate_deletes);
+
+    scoper.reset();
+    EXPECT_FALSE(scoper);
+    EXPECT_FALSE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(1, alternate_deletes);
+
+    scoper_child.reset(&dummy_value);
+    EXPECT_TRUE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(1, alternate_deletes);
+    scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+    EXPECT_TRUE(scoper_construct);
+    EXPECT_FALSE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(1, alternate_deletes);
+
+    scoper_construct.reset();
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(2, alternate_deletes);
+  }
+}
+
+TEST(ScopedPtrTest, ScopedPtrWithArray) {
+  static const int kNumLoggers = 12;
+
+  int constructed = 0;
+
+  {
+    scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]);
+    EXPECT_TRUE(scoper);
+    EXPECT_EQ(&scoper[0], scoper.get());
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, scoper[2].SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    scoped_ptr<ConDecLogger[]> scoper;
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new ConDecLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new ConDecLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    ConDecLogger* ptr = scoper.release();
+    EXPECT_EQ(12, constructed);
+    delete[] ptr;
+    EXPECT_EQ(0, constructed);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), ==, !=, and type-safe Boolean.
+  {
+    scoped_ptr<ConDecLogger[]> scoper1;
+    scoped_ptr<ConDecLogger[]> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+    for (int i = 0; i < kNumLoggers; ++i) {
+      loggers[i].SetPtr(&constructed);
+    }
+    scoper1.reset(loggers);
+    EXPECT_TRUE(scoper1);
+    EXPECT_EQ(loggers, scoper1.get());
+    EXPECT_FALSE(scoper2);
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(loggers, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  {
+    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+    scoped_ptr<ConDecLogger[]> scoper(loggers);
+    EXPECT_TRUE(scoper);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(kNumLoggers, constructed);
+
+    // Test Pass() with constructor;
+    scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+    EXPECT_EQ(kNumLoggers, constructed);
+
+    // Test Pass() with assignment;
+    scoped_ptr<ConDecLogger[]> scoper3;
+    scoper3 = scoper2.Pass();
+    EXPECT_EQ(kNumLoggers, constructed);
+    EXPECT_FALSE(scoper);
+    EXPECT_FALSE(scoper2);
+    EXPECT_TRUE(scoper3);
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, PassBehavior) {
+  int constructed = 0;
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Test Pass() with constructor;
+    scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+
+    // Test Pass() with assignment;
+    scoped_ptr<ConDecLogger> scoper3;
+    scoper3 = scoper2.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_TRUE(scoper3.get());
+  }
+
+  // Test uncaught Pass() does not have side effects.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    scoped_ptr<ConDecLogger>&& rvalue = scoper.Pass();
+    // The Pass() function mimics std::move(), which does not have side-effects.
+    EXPECT_TRUE(scoper.get());
+    EXPECT_TRUE(rvalue);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test that passing to function which does nothing does not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    GrabAndDrop(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ReturnTypeBehavior) {
+  int constructed = 0;
+
+  // Test that we can return a scoped_ptr.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    PassThru(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test uncaught return type not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    PassThru(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Call TestReturnOfType() so the compiler doesn't warn for an unused
+  // function.
+  {
+    TestReturnOfType(&constructed);
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, CustomDeleter) {
+  double dummy_value;  // Custom deleter never touches this value.
+  int deletes = 0;
+  int alternate_deletes = 0;
+
+  // Normal delete support.
+  {
+    deletes = 0;
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    EXPECT_EQ(0, deletes);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(1, deletes);
+
+  // Test reset() and release().
+  deletes = 0;
+  {
+    scoped_ptr<double, CountingDeleter> scoper(NULL,
+                                               CountingDeleter(&deletes));
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+    EXPECT_EQ(0, deletes);
+
+    scoper.reset(&dummy_value);
+    scoper.reset();
+    EXPECT_EQ(1, deletes);
+
+    scoper.reset(&dummy_value);
+    EXPECT_EQ(&dummy_value, scoper.release());
+  }
+  EXPECT_EQ(1, deletes);
+
+  // Test get_deleter().
+  deletes = 0;
+  alternate_deletes = 0;
+  {
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    // Call deleter manually.
+    EXPECT_EQ(0, deletes);
+    scoper.get_deleter()(&dummy_value);
+    EXPECT_EQ(1, deletes);
+
+    // Deleter is still there after reset.
+    scoper.reset();
+    EXPECT_EQ(2, deletes);
+    scoper.get_deleter()(&dummy_value);
+    EXPECT_EQ(3, deletes);
+
+    // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
+    scoper.get_deleter() = CountingDeleter(&alternate_deletes);
+    scoper.reset(&dummy_value);
+    EXPECT_EQ(0, alternate_deletes);
+
+  }
+  EXPECT_EQ(3, deletes);
+  EXPECT_EQ(1, alternate_deletes);
+
+  // Test operator= deleter support.
+  deletes = 0;
+  alternate_deletes = 0;
+  {
+    double dummy_value2;
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    scoped_ptr<double, CountingDeleter> scoper2(
+        &dummy_value2,
+        CountingDeleter(&alternate_deletes));
+    EXPECT_EQ(0, deletes);
+    EXPECT_EQ(0, alternate_deletes);
+
+    // Pass the second deleter through a constructor and an operator=. Then
+    // reinitialize the empty scopers to ensure that each one is deleting
+    // properly.
+    scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass());
+    scoper = scoper3.Pass();
+    EXPECT_EQ(1, deletes);
+
+    scoper2.reset(&dummy_value2);
+    scoper3.reset(&dummy_value2);
+    EXPECT_EQ(0, alternate_deletes);
+
+  }
+  EXPECT_EQ(1, deletes);
+  EXPECT_EQ(3, alternate_deletes);
+
+  // Test swap(), ==, !=, and type-safe Boolean.
+  {
+    scoped_ptr<double, CountingDeleter> scoper1(NULL,
+                                                CountingDeleter(&deletes));
+    scoped_ptr<double, CountingDeleter> scoper2(NULL,
+                                                CountingDeleter(&deletes));
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    scoper1.reset(&dummy_value);
+    EXPECT_TRUE(scoper1);
+    EXPECT_EQ(&dummy_value, scoper1.get());
+    EXPECT_FALSE(scoper2);
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(&dummy_value, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+}
+
+// Sanity check test for overloaded new and delete operators. Does not do full
+// coverage of reset/release/Pass() operations as that is redundant with the
+// above.
+TEST(ScopedPtrTest, OverloadedNewAndDelete) {
+  {
+    OverloadedNewAndDelete::ResetCounters();
+    scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+  }
+  EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
+  EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
+}
+
+scoped_ptr<int> NullIntReturn() {
+  return nullptr;
+}
+
+TEST(ScopedPtrTest, Nullptr) {
+  scoped_ptr<int> scoper1(nullptr);
+  scoped_ptr<int> scoper2(new int);
+  scoper2 = nullptr;
+  scoped_ptr<int> scoper3(NullIntReturn());
+  scoped_ptr<int> scoper4 = NullIntReturn();
+  EXPECT_EQ(nullptr, scoper1.get());
+  EXPECT_EQ(nullptr, scoper2.get());
+  EXPECT_EQ(nullptr, scoper3.get());
+  EXPECT_EQ(nullptr, scoper4.get());
+}
+
+scoped_ptr<int[]> NullIntArrayReturn() {
+  return nullptr;
+}
+
+TEST(ScopedPtrTest, NullptrArray) {
+  scoped_ptr<int[]> scoper1(nullptr);
+  scoped_ptr<int[]> scoper2(new int[3]);
+  scoper2 = nullptr;
+  scoped_ptr<int[]> scoper3(NullIntArrayReturn());
+  scoped_ptr<int[]> scoper4 = NullIntArrayReturn();
+  EXPECT_EQ(nullptr, scoper1.get());
+  EXPECT_EQ(nullptr, scoper2.get());
+  EXPECT_EQ(nullptr, scoper3.get());
+  EXPECT_EQ(nullptr, scoper4.get());
+}
+
+class Super {};
+class Sub : public Super {};
+
+scoped_ptr<Sub> SubClassReturn() {
+  return make_scoped_ptr(new Sub);
+}
+
+TEST(ScopedPtrTest, Conversion) {
+  scoped_ptr<Sub> sub1(new Sub);
+  scoped_ptr<Sub> sub2(new Sub);
+
+  // Upcast with Pass() works.
+  scoped_ptr<Super> super1 = sub1.Pass();
+  super1 = sub2.Pass();
+
+  // Upcast with an rvalue works.
+  scoped_ptr<Super> super2 = SubClassReturn();
+  super2 = SubClassReturn();
+}
+
+// Android death tests don't work properly with assert(). Yay.
+#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+TEST(ScopedPtrTest, SelfResetAbortsWithDefaultDeleter) {
+  scoped_ptr<int> x(new int);
+  EXPECT_DEATH(x.reset(x.get()), "");
+}
+
+TEST(ScopedPtrTest, SelfResetAbortsWithDefaultArrayDeleter) {
+  scoped_ptr<int[]> y(new int[4]);
+  EXPECT_DEATH(y.reset(y.get()), "");
+}
+
+TEST(ScopedPtrTest, SelfResetAbortsWithDefaultFreeDeleter) {
+  scoped_ptr<int, base::FreeDeleter> z(static_cast<int*>(malloc(sizeof(int))));
+  EXPECT_DEATH(z.reset(z.get()), "");
+}
+
+// A custom deleter that doesn't opt out should still crash.
+TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) {
+  struct CustomDeleter {
+    inline void operator()(int* x) { delete x; }
+  };
+  scoped_ptr<int, CustomDeleter> x(new int);
+  EXPECT_DEATH(x.reset(x.get()), "");
+}
+#endif
+
+TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
+  // A custom deleter should be able to opt out of self-reset abort behavior.
+  struct NoOpDeleter {
+#if !defined(NDEBUG)
+    typedef void AllowSelfReset;
+#endif
+    inline void operator()(int*) {}
+  };
+  scoped_ptr<int> owner(new int);
+  scoped_ptr<int, NoOpDeleter> x(owner.get());
+  x.reset(x.get());
+}
+
+// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean
+// value first.
+TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
+  scoped_ptr<int> x(new int);
+  std::stringstream s1;
+  s1 << x;
+
+  std::stringstream s2;
+  s2 << x.get();
+
+  EXPECT_EQ(s2.str(), s1.str());
+}
diff --git a/base/memory/scoped_ptr_unittest.nc b/base/memory/scoped_ptr_unittest.nc
new file mode 100644
index 0000000..b62703c
--- /dev/null
+++ b/base/memory/scoped_ptr_unittest.nc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+
+namespace {
+
+class Parent {
+};
+
+class Child : public Parent {
+};
+
+class RefCountedClass : public base::RefCountedThreadSafe<RefCountedClass> {
+};
+
+}  // namespace
+
+#if defined(NCTEST_NO_PASS_DOWNCAST)  // [r"fatal error: no matching constructor for initialization of 'base::internal::scoped_ptr_impl<\(anonymous namespace\)::Child, base::DefaultDeleter<\(anonymous namespace\)::Child> >::Data'"]
+
+scoped_ptr<Child> DowncastUsingPassAs(scoped_ptr<Parent> object) {
+  return object.Pass();
+}
+
+#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR)  // [r"fatal error: static_assert failed \"T_is_refcounted_type_and_needs_scoped_refptr\""]
+
+// scoped_ptr<> should not work for ref-counted objects.
+void WontCompile() {
+  scoped_ptr<RefCountedClass> x;
+}
+
+#elif defined(NCTEST_NO_ARRAY_WITH_SIZE)  // [r"fatal error: static_assert failed \"do_not_use_array_with_size_as_type\""]
+
+void WontCompile() {
+  scoped_ptr<int[10]> x;
+}
+
+#elif defined(NCTEST_NO_PASS_FROM_ARRAY)  // [r"fatal error: static_assert failed \"U_cannot_be_an_array\""]
+
+void WontCompile() {
+  scoped_ptr<int[]> a;
+  scoped_ptr<int*> b;
+  b = a.Pass();
+}
+
+#elif defined(NCTEST_NO_PASS_TO_ARRAY)  // [r"fatal error: no viable overloaded '='"]
+
+void WontCompile() {
+  scoped_ptr<int*> a;
+  scoped_ptr<int[]> b;
+  b = a.Pass();
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY)  // [r"fatal error: 'impl_' is a private member of 'scoped_ptr<int \[\], base::DefaultDeleter<int \[\]> >'"]
+
+void WontCompile() {
+  scoped_ptr<int[]> a;
+  scoped_ptr<int*> b(a.Pass());
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_TO_ARRAY)  // [r"fatal error: no matching constructor for initialization of 'scoped_ptr<int \[\]>'"]
+
+void WontCompile() {
+  scoped_ptr<int*> a;
+  scoped_ptr<int[]> b(a.Pass());
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_NULL)  // [r"is ambiguous"]
+
+void WontCompile() {
+  scoped_ptr<int[]> x(NULL);
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED)  // [r"fatal error: calling a private constructor of class 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+
+void WontCompile() {
+  scoped_ptr<Parent[]> x(new Child[1]);
+}
+
+#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_NULL)  // [r"is ambiguous"]
+
+void WontCompile() {
+  scoped_ptr<int[]> x;
+  x.reset(NULL);
+}
+
+#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED)  // [r"fatal error: 'reset' is a private member of 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+
+void WontCompile() {
+  scoped_ptr<Parent[]> x;
+  x.reset(new Child[1]);
+}
+
+#elif defined(NCTEST_NO_DELETER_REFERENCE)  // [r"fatal error: base specifier must name a class"]
+
+struct Deleter {
+  void operator()(int*) {}
+};
+
+// Current implementation doesn't support Deleter Reference types. Enabling
+// support would require changes to the behavior of the constructors to match
+// including the use of SFINAE to discard the type-converting constructor
+// as per C++11 20.7.1.2.1.19.
+void WontCompile() {
+  Deleter d;
+  int n;
+  scoped_ptr<int*, Deleter&> a(&n, d);
+}
+
+#endif
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
new file mode 100644
index 0000000..173ea5a
--- /dev/null
+++ b/base/memory/scoped_vector.h
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_VECTOR_H_
+#define BASE_MEMORY_SCOPED_VECTOR_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/move.h"
+#include "base/stl_util.h"
+
+// ScopedVector wraps a vector deleting the elements from its
+// destructor.
+template <class T>
+class ScopedVector {
+  MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+
+ public:
+  typedef typename std::vector<T*>::allocator_type allocator_type;
+  typedef typename std::vector<T*>::size_type size_type;
+  typedef typename std::vector<T*>::difference_type difference_type;
+  typedef typename std::vector<T*>::pointer pointer;
+  typedef typename std::vector<T*>::const_pointer const_pointer;
+  typedef typename std::vector<T*>::reference reference;
+  typedef typename std::vector<T*>::const_reference const_reference;
+  typedef typename std::vector<T*>::value_type value_type;
+  typedef typename std::vector<T*>::iterator iterator;
+  typedef typename std::vector<T*>::const_iterator const_iterator;
+  typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
+  typedef typename std::vector<T*>::const_reverse_iterator
+      const_reverse_iterator;
+
+  ScopedVector() {}
+  ~ScopedVector() { clear(); }
+  ScopedVector(RValue other) { swap(*other.object); }
+
+  ScopedVector& operator=(RValue rhs) {
+    swap(*rhs.object);
+    return *this;
+  }
+
+  reference operator[](size_t index) { return v_[index]; }
+  const_reference operator[](size_t index) const { return v_[index]; }
+
+  bool empty() const { return v_.empty(); }
+  size_t size() const { return v_.size(); }
+
+  reverse_iterator rbegin() { return v_.rbegin(); }
+  const_reverse_iterator rbegin() const { return v_.rbegin(); }
+  reverse_iterator rend() { return v_.rend(); }
+  const_reverse_iterator rend() const { return v_.rend(); }
+
+  iterator begin() { return v_.begin(); }
+  const_iterator begin() const { return v_.begin(); }
+  iterator end() { return v_.end(); }
+  const_iterator end() const { return v_.end(); }
+
+  const_reference front() const { return v_.front(); }
+  reference front() { return v_.front(); }
+  const_reference back() const { return v_.back(); }
+  reference back() { return v_.back(); }
+
+  void push_back(T* elem) { v_.push_back(elem); }
+  void push_back(scoped_ptr<T> elem) { v_.push_back(elem.release()); }
+
+  void pop_back() {
+    DCHECK(!empty());
+    delete v_.back();
+    v_.pop_back();
+  }
+
+  std::vector<T*>& get() { return v_; }
+  const std::vector<T*>& get() const { return v_; }
+  void swap(std::vector<T*>& other) { v_.swap(other); }
+  void swap(ScopedVector<T>& other) { v_.swap(other.v_); }
+  void release(std::vector<T*>* out) {
+    out->swap(v_);
+    v_.clear();
+  }
+
+  void reserve(size_t capacity) { v_.reserve(capacity); }
+
+  // Resize, deleting elements in the disappearing range if we are shrinking.
+  void resize(size_t new_size) {
+    if (v_.size() > new_size)
+      STLDeleteContainerPointers(v_.begin() + new_size, v_.end());
+    v_.resize(new_size);
+  }
+
+  template<typename InputIterator>
+  void assign(InputIterator begin, InputIterator end) {
+    v_.assign(begin, end);
+  }
+
+  void clear() { STLDeleteElements(&v_); }
+
+  // Like |clear()|, but doesn't delete any elements.
+  void weak_clear() { v_.clear(); }
+
+  // Lets the ScopedVector take ownership of |x|.
+  iterator insert(iterator position, T* x) {
+    return v_.insert(position, x);
+  }
+
+  // Lets the ScopedVector take ownership of elements in [first,last).
+  template<typename InputIterator>
+  void insert(iterator position, InputIterator first, InputIterator last) {
+    v_.insert(position, first, last);
+  }
+
+  iterator erase(iterator position) {
+    delete *position;
+    return v_.erase(position);
+  }
+
+  iterator erase(iterator first, iterator last) {
+    STLDeleteContainerPointers(first, last);
+    return v_.erase(first, last);
+  }
+
+  // Like |erase()|, but doesn't delete the element at |position|.
+  iterator weak_erase(iterator position) {
+    return v_.erase(position);
+  }
+
+  // Like |erase()|, but doesn't delete the elements in [first, last).
+  iterator weak_erase(iterator first, iterator last) {
+    return v_.erase(first, last);
+  }
+
+ private:
+  std::vector<T*> v_;
+};
+
+#endif  // BASE_MEMORY_SCOPED_VECTOR_H_
diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc
new file mode 100644
index 0000000..220cfb0
--- /dev/null
+++ b/base/memory/scoped_vector_unittest.cc
@@ -0,0 +1,324 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_vector.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// The LifeCycleObject notifies its Observer upon construction & destruction.
+class LifeCycleObject {
+ public:
+  class Observer {
+   public:
+    virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
+    virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  ~LifeCycleObject() {
+    observer_->OnLifeCycleDestroy(this);
+  }
+
+ private:
+  friend class LifeCycleWatcher;
+
+  explicit LifeCycleObject(Observer* observer)
+      : observer_(observer) {
+    observer_->OnLifeCycleConstruct(this);
+  }
+
+  Observer* observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
+};
+
+// The life cycle states we care about for the purposes of testing ScopedVector
+// against objects.
+enum LifeCycleState {
+  LC_INITIAL,
+  LC_CONSTRUCTED,
+  LC_DESTROYED,
+};
+
+// Because we wish to watch the life cycle of an object being constructed and
+// destroyed, and further wish to test expectations against the state of that
+// object, we cannot save state in that object itself. Instead, we use this
+// pairing of the watcher, which observes the object and notifies of
+// construction & destruction. Since we also may be testing assumptions about
+// things not getting freed, this class also acts like a scoping object and
+// deletes the |constructed_life_cycle_object_|, if any when the
+// LifeCycleWatcher is destroyed. To keep this simple, the only expected state
+// changes are:
+//   INITIAL -> CONSTRUCTED -> DESTROYED.
+// Anything more complicated than that should start another test.
+class LifeCycleWatcher : public LifeCycleObject::Observer {
+ public:
+  LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
+  ~LifeCycleWatcher() override {}
+
+  // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
+  // LifeCycleWatcher.
+  void OnLifeCycleConstruct(LifeCycleObject* object) override {
+    ASSERT_EQ(LC_INITIAL, life_cycle_state_);
+    ASSERT_EQ(NULL, constructed_life_cycle_object_.get());
+    life_cycle_state_ = LC_CONSTRUCTED;
+    constructed_life_cycle_object_.reset(object);
+  }
+
+  // Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the
+  // same one we saw constructed.
+  void OnLifeCycleDestroy(LifeCycleObject* object) override {
+    ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_);
+    LifeCycleObject* constructed_life_cycle_object =
+        constructed_life_cycle_object_.release();
+    ASSERT_EQ(constructed_life_cycle_object, object);
+    life_cycle_state_ = LC_DESTROYED;
+  }
+
+  LifeCycleState life_cycle_state() const { return life_cycle_state_; }
+
+  // Factory method for creating a new LifeCycleObject tied to this
+  // LifeCycleWatcher.
+  LifeCycleObject* NewLifeCycleObject() {
+    return new LifeCycleObject(this);
+  }
+
+  // Returns true iff |object| is the same object that this watcher is tracking.
+  bool IsWatching(LifeCycleObject* object) const {
+    return object == constructed_life_cycle_object_.get();
+  }
+
+ private:
+  LifeCycleState life_cycle_state_;
+  scoped_ptr<LifeCycleObject> constructed_life_cycle_object_;
+
+  DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
+};
+
+TEST(ScopedVectorTest, LifeCycleWatcher) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  LifeCycleObject* object = watcher.NewLifeCycleObject();
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  delete object;
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, PopBack) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  scoped_vector.pop_back();
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+  EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, Clear) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  scoped_vector.clear();
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+  EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, WeakClear) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  scoped_vector.weak_clear();
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, ResizeShrink) {
+  LifeCycleWatcher first_watcher;
+  EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state());
+  LifeCycleWatcher second_watcher;
+  EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+
+  scoped_vector.push_back(first_watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+  EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
+  EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
+  EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0]));
+
+  scoped_vector.push_back(second_watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+  EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state());
+  EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1]));
+  EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1]));
+
+  // Test that shrinking a vector deletes elements in the disappearing range.
+  scoped_vector.resize(1);
+  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+  EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state());
+  EXPECT_EQ(1u, scoped_vector.size());
+  EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
+}
+
+TEST(ScopedVectorTest, ResizeGrow) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+  scoped_vector.resize(5);
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  ASSERT_EQ(5u, scoped_vector.size());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector[0]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[1]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[2]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[3]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[4]));
+}
+
+TEST(ScopedVectorTest, Scope) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.push_back(watcher.NewLifeCycleObject());
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, MoveConstruct) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.push_back(watcher.NewLifeCycleObject());
+    EXPECT_FALSE(scoped_vector.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+    ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
+    EXPECT_TRUE(scoped_vector.empty());
+    EXPECT_FALSE(scoped_vector_copy.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
+
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, MoveAssign) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.push_back(watcher.NewLifeCycleObject());
+    ScopedVector<LifeCycleObject> scoped_vector_assign;
+    EXPECT_FALSE(scoped_vector.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+    scoped_vector_assign = scoped_vector.Pass();
+    EXPECT_TRUE(scoped_vector.empty());
+    EXPECT_FALSE(scoped_vector_assign.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
+
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+class DeleteCounter {
+ public:
+  explicit DeleteCounter(int* deletes)
+      : deletes_(deletes) {
+  }
+
+  ~DeleteCounter() {
+    (*deletes_)++;
+  }
+
+  void VoidMethod0() {}
+
+ private:
+  int* const deletes_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
+};
+
+template <typename T>
+ScopedVector<T> PassThru(ScopedVector<T> scoper) {
+  return scoper.Pass();
+}
+
+TEST(ScopedVectorTest, Passed) {
+  int deletes = 0;
+  ScopedVector<DeleteCounter> deleter_vector;
+  deleter_vector.push_back(new DeleteCounter(&deletes));
+  EXPECT_EQ(0, deletes);
+  base::Callback<ScopedVector<DeleteCounter>(void)> callback =
+      base::Bind(&PassThru<DeleteCounter>, base::Passed(&deleter_vector));
+  EXPECT_EQ(0, deletes);
+  ScopedVector<DeleteCounter> result = callback.Run();
+  EXPECT_EQ(0, deletes);
+  result.clear();
+  EXPECT_EQ(1, deletes);
+};
+
+TEST(ScopedVectorTest, InsertRange) {
+  LifeCycleWatcher watchers[5];
+
+  std::vector<LifeCycleObject*> vec;
+  for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
+      ++it) {
+    EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
+    vec.push_back(it->NewLifeCycleObject());
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  }
+  // Start scope for ScopedVector.
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
+    for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
+        ++it)
+      EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  }
+  for(LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  for(LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
+    EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
+  for(LifeCycleWatcher* it = watchers + 3; it != watchers + arraysize(watchers);
+      ++it)
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+}
+
+// Assertions for push_back(scoped_ptr).
+TEST(ScopedVectorTest, PushBackScopedPtr) {
+  int delete_counter = 0;
+  scoped_ptr<DeleteCounter> elem(new DeleteCounter(&delete_counter));
+  EXPECT_EQ(0, delete_counter);
+  {
+    ScopedVector<DeleteCounter> v;
+    v.push_back(elem.Pass());
+    EXPECT_EQ(0, delete_counter);
+  }
+  EXPECT_EQ(1, delete_counter);
+}
+
+}  // namespace
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
new file mode 100644
index 0000000..d76e01c
--- /dev/null
+++ b/base/memory/shared_memory.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_MEMORY_SHARED_MEMORY_H_
+#define BASE_MEMORY_SHARED_MEMORY_H_
+
+#include "build/build_config.h"
+
+#include <string>
+
+#if defined(OS_POSIX)
+#include <stdio.h>
+#include <sys/types.h>
+#include <semaphore.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/process/process_handle.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#endif
+
+namespace base {
+
+class FilePath;
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+#if defined(OS_WIN)
+typedef HANDLE SharedMemoryHandle;
+#elif defined(OS_POSIX)
+// A SharedMemoryId is sufficient to identify a given shared memory segment on a
+// system, but insufficient to map it.
+typedef FileDescriptor SharedMemoryHandle;
+typedef ino_t SharedMemoryId;
+#endif
+
+// Options for creating a shared memory object.
+struct SharedMemoryCreateOptions {
+  SharedMemoryCreateOptions()
+      : name_deprecated(NULL),
+        size(0),
+        open_existing_deprecated(false),
+        executable(false),
+        share_read_only(false) {}
+
+  // DEPRECATED (crbug.com/345734):
+  // If NULL, the object is anonymous.  This pointer is owned by the caller
+  // and must live through the call to Create().
+  const std::string* name_deprecated;
+
+  // Size of the shared memory object to be created.
+  // When opening an existing object, this has no effect.
+  size_t size;
+
+  // DEPRECATED (crbug.com/345734):
+  // If true, and the shared memory already exists, Create() will open the
+  // existing shared memory and ignore the size parameter.  If false,
+  // shared memory must not exist.  This flag is meaningless unless
+  // name_deprecated is non-NULL.
+  bool open_existing_deprecated;
+
+  // If true, mappings might need to be made executable later.
+  bool executable;
+
+  // If true, the file can be shared read-only to a process.
+  bool share_read_only;
+};
+
+// Platform abstraction for shared memory.  Provides a C++ wrapper
+// around the OS primitive for a memory mapped file.
+class BASE_EXPORT SharedMemory {
+ public:
+  SharedMemory();
+
+#if defined(OS_WIN)
+  // Similar to the default constructor, except that this allows for
+  // calling LockDeprecated() to acquire the named mutex before either Create or
+  // Open are called on Windows.
+  explicit SharedMemory(const std::wstring& name);
+#endif
+
+  // Create a new SharedMemory object from an existing, open
+  // shared memory file.
+  //
+  // WARNING: This does not reduce the OS-level permissions on the handle; it
+  // only affects how the SharedMemory will be mmapped.  Use
+  // ShareReadOnlyToProcess to drop permissions.  TODO(jln,jyasskin): DCHECK
+  // that |read_only| matches the permissions of the handle.
+  SharedMemory(SharedMemoryHandle handle, bool read_only);
+
+  // Create a new SharedMemory object from an existing, open
+  // shared memory file that was created by a remote process and not shared
+  // to the current process.
+  SharedMemory(SharedMemoryHandle handle, bool read_only,
+               ProcessHandle process);
+
+  // Closes any open files.
+  ~SharedMemory();
+
+  // Return true iff the given handle is valid (i.e. not the distingished
+  // invalid value; NULL for a HANDLE and -1 for a file descriptor)
+  static bool IsHandleValid(const SharedMemoryHandle& handle);
+
+  // Returns invalid handle (see comment above for exact definition).
+  static SharedMemoryHandle NULLHandle();
+
+  // Closes a shared memory handle.
+  static void CloseHandle(const SharedMemoryHandle& handle);
+
+  // Returns the maximum number of handles that can be open at once per process.
+  static size_t GetHandleLimit();
+
+  // Creates a shared memory object as described by the options struct.
+  // Returns true on success and false on failure.
+  bool Create(const SharedMemoryCreateOptions& options);
+
+  // Creates and maps an anonymous shared memory segment of size size.
+  // Returns true on success and false on failure.
+  bool CreateAndMapAnonymous(size_t size);
+
+  // Creates an anonymous shared memory segment of size size.
+  // Returns true on success and false on failure.
+  bool CreateAnonymous(size_t size) {
+    SharedMemoryCreateOptions options;
+    options.size = size;
+    return Create(options);
+  }
+
+  // DEPRECATED (crbug.com/345734):
+  // Creates or opens a shared memory segment based on a name.
+  // If open_existing is true, and the shared memory already exists,
+  // opens the existing shared memory and ignores the size parameter.
+  // If open_existing is false, shared memory must not exist.
+  // size is the size of the block to be created.
+  // Returns true on success, false on failure.
+  bool CreateNamedDeprecated(
+      const std::string& name, bool open_existing, size_t size) {
+    SharedMemoryCreateOptions options;
+    options.name_deprecated = &name;
+    options.open_existing_deprecated = open_existing;
+    options.size = size;
+    return Create(options);
+  }
+
+  // Deletes resources associated with a shared memory segment based on name.
+  // Not all platforms require this call.
+  bool Delete(const std::string& name);
+
+  // Opens a shared memory segment based on a name.
+  // If read_only is true, opens for read-only access.
+  // Returns true on success, false on failure.
+  bool Open(const std::string& name, bool read_only);
+
+  // Maps the shared memory into the caller's address space.
+  // Returns true on success, false otherwise.  The memory address
+  // is accessed via the memory() accessor.  The mapped address is guaranteed to
+  // have an alignment of at least MAP_MINIMUM_ALIGNMENT. This method will fail
+  // if this object is currently mapped.
+  bool Map(size_t bytes) {
+    return MapAt(0, bytes);
+  }
+
+  // Same as above, but with |offset| to specify from begining of the shared
+  // memory block to map.
+  // |offset| must be alignent to value of |SysInfo::VMAllocationGranularity()|.
+  bool MapAt(off_t offset, size_t bytes);
+  enum { MAP_MINIMUM_ALIGNMENT = 32 };
+
+  // Unmaps the shared memory from the caller's address space.
+  // Returns true if successful; returns false on error or if the
+  // memory is not mapped.
+  bool Unmap();
+
+  // The size requested when the map is first created.
+  size_t requested_size() const { return requested_size_; }
+
+  // The actual size of the mapped memory (may be larger than requested).
+  size_t mapped_size() const { return mapped_size_; }
+
+  // Gets a pointer to the opened memory space if it has been
+  // Mapped via Map().  Returns NULL if it is not mapped.
+  void *memory() const { return memory_; }
+
+  // Returns the underlying OS handle for this segment.
+  // Use of this handle for anything other than an opaque
+  // identifier is not portable.
+  SharedMemoryHandle handle() const;
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+  // Returns a unique identifier for this shared memory segment. Inode numbers
+  // are technically only unique to a single filesystem. However, we always
+  // allocate shared memory backing files from the same directory, so will end
+  // up on the same filesystem.
+  SharedMemoryId id() const { return inode_; }
+#endif
+
+  // Closes the open shared memory segment. The memory will remain mapped if
+  // it was previously mapped.
+  // It is safe to call Close repeatedly.
+  void Close();
+
+  // Shares the shared memory to another process.  Attempts to create a
+  // platform-specific new_handle which can be used in a remote process to read
+  // the shared memory file.  new_handle is an output parameter to receive the
+  // handle for use in the remote process.
+  //
+  // |*this| must have been initialized using one of the Create*() or Open()
+  // methods with share_read_only=true. If it was constructed from a
+  // SharedMemoryHandle, this call will CHECK-fail.
+  //
+  // Returns true on success, false otherwise.
+  bool ShareReadOnlyToProcess(ProcessHandle process,
+                              SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, false, SHARE_READONLY);
+  }
+
+  // Logically equivalent to:
+  //   bool ok = ShareReadOnlyToProcess(process, new_handle);
+  //   Close();
+  //   return ok;
+  // Note that the memory is unmapped by calling this method, regardless of the
+  // return value.
+  bool GiveReadOnlyToProcess(ProcessHandle process,
+                             SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, true, SHARE_READONLY);
+  }
+
+  // Shares the shared memory to another process.  Attempts
+  // to create a platform-specific new_handle which can be
+  // used in a remote process to access the shared memory
+  // file.  new_handle is an output parameter to receive
+  // the handle for use in the remote process.
+  // Returns true on success, false otherwise.
+  bool ShareToProcess(ProcessHandle process,
+                      SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, false, SHARE_CURRENT_MODE);
+  }
+
+  // Logically equivalent to:
+  //   bool ok = ShareToProcess(process, new_handle);
+  //   Close();
+  //   return ok;
+  // Note that the memory is unmapped by calling this method, regardless of the
+  // return value.
+  bool GiveToProcess(ProcessHandle process,
+                     SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, true, SHARE_CURRENT_MODE);
+  }
+
+  // DEPRECATED (crbug.com/345734):
+  // Locks the shared memory.
+  //
+  // WARNING: on POSIX the memory locking primitive only works across
+  // processes, not across threads.  The LockDeprecated method is not currently
+  // used in inner loops, so we protect against multiple threads in a
+  // critical section using a class global lock.
+  void LockDeprecated();
+
+  // DEPRECATED (crbug.com/345734):
+  // Releases the shared memory lock.
+  void UnlockDeprecated();
+
+ private:
+#if defined(OS_POSIX) && !defined(OS_NACL)
+#if !defined(OS_ANDROID)
+  bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
+  bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
+#endif
+  void LockOrUnlockCommon(int function);
+#endif  // defined(OS_POSIX) && !defined(OS_NACL)
+  enum ShareMode {
+    SHARE_READONLY,
+    SHARE_CURRENT_MODE,
+  };
+  bool ShareToProcessCommon(ProcessHandle process,
+                            SharedMemoryHandle* new_handle,
+                            bool close_self,
+                            ShareMode);
+
+#if defined(OS_WIN)
+  std::wstring       name_;
+  HANDLE             mapped_file_;
+#elif defined(OS_POSIX)
+  int                mapped_file_;
+  int                readonly_mapped_file_;
+  ino_t              inode_;
+#endif
+  size_t             mapped_size_;
+  void*              memory_;
+  bool               read_only_;
+  size_t             requested_size_;
+#if !defined(OS_POSIX)
+  HANDLE             lock_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemory);
+};
+
+// DEPRECATED (crbug.com/345734):
+// A helper class that acquires the shared memory lock while
+// the SharedMemoryAutoLockDeprecated is in scope.
+class SharedMemoryAutoLockDeprecated {
+ public:
+  explicit SharedMemoryAutoLockDeprecated(SharedMemory* shared_memory)
+      : shared_memory_(shared_memory) {
+    shared_memory_->LockDeprecated();
+  }
+
+  ~SharedMemoryAutoLockDeprecated() {
+    shared_memory_->UnlockDeprecated();
+  }
+
+ private:
+  SharedMemory* shared_memory_;
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLockDeprecated);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_H_
diff --git a/base/memory/shared_memory_android.cc b/base/memory/shared_memory_android.cc
new file mode 100644
index 0000000..5ba1bd6
--- /dev/null
+++ b/base/memory/shared_memory_android.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory.h"
+
+#include <sys/mman.h>
+
+#include "base/logging.h"
+#include "third_party/ashmem/ashmem.h"
+
+namespace base {
+
+// For Android, we use ashmem to implement SharedMemory. ashmem_create_region
+// will automatically pin the region. We never explicitly call pin/unpin. When
+// all the file descriptors from different processes associated with the region
+// are closed, the memory buffer will go away.
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  DCHECK_EQ(-1, mapped_file_ );
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  // "name" is just a label in ashmem. It is visible in /proc/pid/maps.
+  mapped_file_ = ashmem_create_region(
+      options.name_deprecated == NULL ? "" : options.name_deprecated->c_str(),
+      options.size);
+  if (-1 == mapped_file_) {
+    DLOG(ERROR) << "Shared memory creation failed";
+    return false;
+  }
+
+  int err = ashmem_set_prot_region(mapped_file_,
+                                   PROT_READ | PROT_WRITE | PROT_EXEC);
+  if (err < 0) {
+    DLOG(ERROR) << "Error " << err << " when setting protection of ashmem";
+    return false;
+  }
+
+  // Android doesn't appear to have a way to drop write access on an ashmem
+  // segment for a single descriptor.  http://crbug.com/320865
+  readonly_mapped_file_ = dup(mapped_file_);
+  if (-1 == readonly_mapped_file_) {
+    DPLOG(ERROR) << "dup() failed";
+    return false;
+  }
+
+  requested_size_ = options.size;
+
+  return true;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  // Like on Windows, this is intentionally returning true as ashmem will
+  // automatically releases the resource when all FDs on it are closed.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  // ashmem doesn't support name mapping
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc
new file mode 100644
index 0000000..8435b2b
--- /dev/null
+++ b/base/memory/shared_memory_nacl.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include "base/logging.h"
+
+namespace base {
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      inode_(0),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle.fd),
+      inode_(0),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(handle.fd),
+      inode_(0),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.fd >= 0;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK_GE(handle.fd, 0);
+  if (close(handle.fd) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  // Untrusted code can't create descriptors or handles.
+  return false;
+}
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // Untrusted code can't create descriptors or handles.
+  return false;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  return false;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  return false;
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, offset);
+
+  bool mmap_succeeded = memory_ != MAP_FAILED && memory_ != NULL;
+  if (mmap_succeeded) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  if (munmap(memory_, mapped_size_) < 0)
+    DPLOG(ERROR) << "munmap";
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return FileDescriptor(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+  if (mapped_file_ > 0) {
+    if (close(mapped_file_) < 0)
+      DPLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+}
+
+void SharedMemory::LockDeprecated() {
+  NOTIMPLEMENTED();
+}
+
+void SharedMemory::UnlockDeprecated() {
+  NOTIMPLEMENTED();
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle *new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  if (share_mode == SHARE_READONLY) {
+    // Untrusted code can't create descriptors or handles, which is needed to
+    // drop permissions.
+    return false;
+  }
+  const int new_fd = dup(mapped_file_);
+  if (new_fd < 0) {
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->fd = new_fd;
+  new_handle->auto_close = true;
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
new file mode 100644
index 0000000..d6c290f
--- /dev/null
+++ b/base/memory/shared_memory_posix.cc
@@ -0,0 +1,501 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/safe_strerror_posix.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif  // OS_MACOSX
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#include "third_party/ashmem/ashmem.h"
+#endif
+
+namespace base {
+
+namespace {
+
+LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
+
+}
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      readonly_mapped_file_(-1),
+      inode_(0),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle.fd),
+      readonly_mapped_file_(-1),
+      inode_(0),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  struct stat st;
+  if (fstat(handle.fd, &st) == 0) {
+    // If fstat fails, then the file descriptor is invalid and we'll learn this
+    // fact when Map() fails.
+    inode_ = st.st_ino;
+  }
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(handle.fd),
+      readonly_mapped_file_(-1),
+      inode_(0),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  // We don't handle this case yet (note the ignored parameter); let's die if
+  // someone comes calling.
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.fd >= 0;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK_GE(handle.fd, 0);
+  if (close(handle.fd) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  return base::GetMaxFds();
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+#if !defined(OS_ANDROID)
+// Chromium mostly only uses the unique/private shmem as specified by
+// "name == L"". The exception is in the StatsTable.
+// TODO(jrg): there is no way to "clean up" all unused named shmem if
+// we restart from a crash.  (That isn't a new problem, but it is a problem.)
+// In case we want to delete it later, it may be useful to save the value
+// of mem_filename after FilePathForMemoryName().
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+  // is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "466437 SharedMemory::Create::Start"));
+  DCHECK_EQ(-1, mapped_file_);
+  if (options.size == 0) return false;
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  ScopedFILE fp;
+  bool fix_size = true;
+  ScopedFD readonly_fd;
+
+  FilePath path;
+  if (options.name_deprecated == NULL || options.name_deprecated->empty()) {
+    // It doesn't make sense to have a open-existing private piece of shmem
+    DCHECK(!options.open_existing_deprecated);
+    // Q: Why not use the shm_open() etc. APIs?
+    // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+    FilePath directory;
+    if (GetShmemTempDir(options.executable, &directory)) {
+      // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+      // is fixed.
+      tracked_objects::ScopedTracker tracking_profile2(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+              "466437 SharedMemory::Create::OpenTemporaryFile"));
+      fp.reset(CreateAndOpenTemporaryFileInDir(directory, &path));
+    }
+
+    if (fp) {
+      if (options.share_read_only) {
+        // TODO(erikchen): Remove ScopedTracker below once
+        // http://crbug.com/466437 is fixed.
+        tracked_objects::ScopedTracker tracking_profile3(
+            FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                "466437 SharedMemory::Create::OpenReadonly"));
+        // Also open as readonly so that we can ShareReadOnlyToProcess.
+        readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+        if (!readonly_fd.is_valid()) {
+          DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+          fp.reset();
+          return false;
+        }
+      }
+
+      // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+      // is fixed.
+      tracked_objects::ScopedTracker tracking_profile4(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+              "466437 SharedMemory::Create::Unlink"));
+      // Deleting the file prevents anyone else from mapping it in (making it
+      // private), and prevents the need for cleanup (once the last fd is
+      // closed, it is truly freed).
+      if (unlink(path.value().c_str()))
+        PLOG(WARNING) << "unlink";
+    }
+  } else {
+    if (!FilePathForMemoryName(*options.name_deprecated, &path))
+      return false;
+
+    // Make sure that the file is opened without any permission
+    // to other users on the system.
+    const mode_t kOwnerOnly = S_IRUSR | S_IWUSR;
+
+    // First, try to create the file.
+    int fd = HANDLE_EINTR(
+        open(path.value().c_str(), O_RDWR | O_CREAT | O_EXCL, kOwnerOnly));
+    if (fd == -1 && options.open_existing_deprecated) {
+      // If this doesn't work, try and open an existing file in append mode.
+      // Opening an existing file in a world writable directory has two main
+      // security implications:
+      // - Attackers could plant a file under their control, so ownership of
+      //   the file is checked below.
+      // - Attackers could plant a symbolic link so that an unexpected file
+      //   is opened, so O_NOFOLLOW is passed to open().
+      fd = HANDLE_EINTR(
+          open(path.value().c_str(), O_RDWR | O_APPEND | O_NOFOLLOW));
+
+      // Check that the current user owns the file.
+      // If uid != euid, then a more complex permission model is used and this
+      // API is not appropriate.
+      const uid_t real_uid = getuid();
+      const uid_t effective_uid = geteuid();
+      struct stat sb;
+      if (fd >= 0 &&
+          (fstat(fd, &sb) != 0 || sb.st_uid != real_uid ||
+           sb.st_uid != effective_uid)) {
+        LOG(ERROR) <<
+            "Invalid owner when opening existing shared memory file.";
+        close(fd);
+        return false;
+      }
+
+      // An existing file was opened, so its size should not be fixed.
+      fix_size = false;
+    }
+
+    if (options.share_read_only) {
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+      if (!readonly_fd.is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+        close(fd);
+        fd = -1;
+        return false;
+      }
+    }
+    if (fd >= 0) {
+      // "a+" is always appropriate: if it's a new file, a+ is similar to w+.
+      fp.reset(fdopen(fd, "a+"));
+    }
+  }
+  if (fp && fix_size) {
+    // Get current size.
+    struct stat stat;
+    if (fstat(fileno(fp.get()), &stat) != 0)
+      return false;
+    const size_t current_size = stat.st_size;
+    if (current_size != options.size) {
+      if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
+        return false;
+    }
+    requested_size_ = options.size;
+  }
+  if (fp == NULL) {
+#if !defined(OS_MACOSX)
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    FilePath dir = path.DirName();
+    if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
+      PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
+      if (dir.value() == "/dev/shm") {
+        LOG(FATAL) << "This is frequently caused by incorrect permissions on "
+                   << "/dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.";
+      }
+    }
+#else
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+#endif
+    return false;
+  }
+
+  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+}
+
+// Our current implementation of shmem is with mmap()ing of files.
+// These files need to be deleted explicitly.
+// In practice this call is only needed for unit tests.
+bool SharedMemory::Delete(const std::string& name) {
+  FilePath path;
+  if (!FilePathForMemoryName(name, &path))
+    return false;
+
+  if (PathExists(path))
+    return base::DeleteFile(path, false);
+
+  // Doesn't exist, so success.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  FilePath path;
+  if (!FilePathForMemoryName(name, &path))
+    return false;
+
+  read_only_ = read_only;
+
+  const char *mode = read_only ? "r" : "r+";
+  ScopedFILE fp(base::OpenFile(path, mode));
+  ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+  if (!readonly_fd.is_valid()) {
+    DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+    return false;
+  }
+  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+}
+#endif  // !defined(OS_ANDROID)
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+#if defined(OS_ANDROID)
+  // On Android, Map can be called with a size and offset of zero to use the
+  // ashmem-determined size.
+  if (bytes == 0) {
+    DCHECK_EQ(0, offset);
+    int ashmem_bytes = ashmem_get_size_region(mapped_file_);
+    if (ashmem_bytes < 0)
+      return false;
+    bytes = ashmem_bytes;
+  }
+#endif
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, offset);
+
+  bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
+  if (mmap_succeeded) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  munmap(memory_, mapped_size_);
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return FileDescriptor(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+  if (mapped_file_ > 0) {
+    if (close(mapped_file_) < 0)
+      PLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+  if (readonly_mapped_file_ > 0) {
+    if (close(readonly_mapped_file_) < 0)
+      PLOG(ERROR) << "close";
+    readonly_mapped_file_ = -1;
+  }
+}
+
+void SharedMemory::LockDeprecated() {
+  g_thread_lock_.Get().Acquire();
+  LockOrUnlockCommon(F_LOCK);
+}
+
+void SharedMemory::UnlockDeprecated() {
+  LockOrUnlockCommon(F_ULOCK);
+  g_thread_lock_.Get().Release();
+}
+
+#if !defined(OS_ANDROID)
+bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
+  DCHECK_EQ(-1, mapped_file_);
+  DCHECK_EQ(-1, readonly_mapped_file_);
+  if (fp == NULL)
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  struct stat st = {};
+  if (fstat(fileno(fp.get()), &st))
+    NOTREACHED();
+  if (readonly_fd.is_valid()) {
+    struct stat readonly_st = {};
+    if (fstat(readonly_fd.get(), &readonly_st))
+      NOTREACHED();
+    if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
+      LOG(ERROR) << "writable and read-only inodes don't match; bailing";
+      return false;
+    }
+  }
+
+  mapped_file_ = dup(fileno(fp.get()));
+  if (mapped_file_ == -1) {
+    if (errno == EMFILE) {
+      LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
+      return false;
+    } else {
+      NOTREACHED() << "Call to dup failed, errno=" << errno;
+    }
+  }
+  inode_ = st.st_ino;
+  readonly_mapped_file_ = readonly_fd.release();
+
+  return true;
+}
+
+// For the given shmem named |mem_name|, return a filename to mmap()
+// (and possibly create).  Modifies |filename|.  Return false on
+// error, or true of we are happy.
+bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
+                                         FilePath* path) {
+  // mem_name will be used for a filename; make sure it doesn't
+  // contain anything which will confuse us.
+  DCHECK_EQ(std::string::npos, mem_name.find('/'));
+  DCHECK_EQ(std::string::npos, mem_name.find('\0'));
+
+  FilePath temp_dir;
+  if (!GetShmemTempDir(false, &temp_dir))
+    return false;
+
+#if !defined(OS_MACOSX)
+#if defined(GOOGLE_CHROME_BUILD)
+  std::string name_base = std::string("com.google.Chrome");
+#else
+  std::string name_base = std::string("org.chromium.Chromium");
+#endif
+#else  // OS_MACOSX
+  std::string name_base = std::string(base::mac::BaseBundleID());
+#endif  // OS_MACOSX
+  *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
+  return true;
+}
+#endif  // !defined(OS_ANDROID)
+
+void SharedMemory::LockOrUnlockCommon(int function) {
+  DCHECK_GE(mapped_file_, 0);
+  while (lockf(mapped_file_, function, 0) < 0) {
+    if (errno == EINTR) {
+      continue;
+    } else if (errno == ENOLCK) {
+      // temporary kernel resource exaustion
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
+      continue;
+    } else {
+      NOTREACHED() << "lockf() failed."
+                   << " function:" << function
+                   << " fd:" << mapped_file_
+                   << " errno:" << errno
+                   << " msg:" << safe_strerror(errno);
+    }
+  }
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  int handle_to_dup = -1;
+  switch(share_mode) {
+    case SHARE_CURRENT_MODE:
+      handle_to_dup = mapped_file_;
+      break;
+    case SHARE_READONLY:
+      // We could imagine re-opening the file from /dev/fd, but that can't make
+      // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
+      CHECK_GE(readonly_mapped_file_, 0);
+      handle_to_dup = readonly_mapped_file_;
+      break;
+  }
+
+  const int new_fd = dup(handle_to_dup);
+  if (new_fd < 0) {
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->fd = new_fd;
+  new_handle->auto_close = true;
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
new file mode 100644
index 0000000..6fe5706
--- /dev/null
+++ b/base/memory/shared_memory_unittest.cc
@@ -0,0 +1,723 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/kill.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
+#include "base/test/multiprocess_test.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+static const int kNumThreads = 5;
+#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+static const int kNumTasks = 5;
+#endif
+
+namespace base {
+
+namespace {
+
+// Each thread will open the shared memory.  Each thread will take a different 4
+// byte int pointer, and keep changing it, with some small pauses in between.
+// Verify that each thread's value in the shared memory is always correct.
+class MultipleThreadMain : public PlatformThread::Delegate {
+ public:
+  explicit MultipleThreadMain(int16 id) : id_(id) {}
+  ~MultipleThreadMain() override {}
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool pool;
+#endif
+    const uint32 kDataSize = 1024;
+    SharedMemory memory;
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
+    EXPECT_TRUE(rv);
+    rv = memory.Map(kDataSize);
+    EXPECT_TRUE(rv);
+    int *ptr = static_cast<int*>(memory.memory()) + id_;
+    EXPECT_EQ(0, *ptr);
+
+    for (int idx = 0; idx < 100; idx++) {
+      *ptr = idx;
+      PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+      EXPECT_EQ(*ptr, idx);
+    }
+    // Reset back to 0 for the next test that uses the same name.
+    *ptr = 0;
+
+    memory.Close();
+  }
+
+ private:
+  int16 id_;
+
+  static const char* const s_test_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
+};
+
+const char* const MultipleThreadMain::s_test_name_ =
+    "SharedMemoryOpenThreadTest";
+
+// TODO(port):
+// This test requires the ability to pass file descriptors between processes.
+// We haven't done that yet in Chrome for POSIX.
+#if defined(OS_WIN)
+// Each thread will open the shared memory.  Each thread will take the memory,
+// and keep changing it while trying to lock it, with some small pauses in
+// between. Verify that each thread's value in the shared memory is always
+// correct.
+class MultipleLockThread : public PlatformThread::Delegate {
+ public:
+  explicit MultipleLockThread(int id) : id_(id) {}
+  ~MultipleLockThread() override {}
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override {
+    const uint32 kDataSize = sizeof(int);
+    SharedMemoryHandle handle = NULL;
+    {
+      SharedMemory memory1;
+      EXPECT_TRUE(memory1.CreateNamedDeprecated(
+          "SharedMemoryMultipleLockThreadTest", true, kDataSize));
+      EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
+      // TODO(paulg): Implement this once we have a posix version of
+      // SharedMemory::ShareToProcess.
+      EXPECT_TRUE(true);
+    }
+
+    SharedMemory memory2(handle, false);
+    EXPECT_TRUE(memory2.Map(kDataSize));
+    volatile int* const ptr = static_cast<int*>(memory2.memory());
+
+    for (int idx = 0; idx < 20; idx++) {
+      memory2.LockDeprecated();
+      int i = (id_ << 16) + idx;
+      *ptr = i;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+      EXPECT_EQ(*ptr, i);
+      memory2.UnlockDeprecated();
+    }
+
+    memory2.Close();
+  }
+
+ private:
+  int id_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
+};
+#endif
+
+}  // namespace
+
+// Android doesn't support SharedMemory::Open/Delete/
+// CreateNamedDeprecated(openExisting=true)
+#if !defined(OS_ANDROID)
+TEST(SharedMemoryTest, OpenClose) {
+  const uint32 kDataSize = 1024;
+  std::string test_name = "SharedMemoryOpenCloseTest";
+
+  // Open two handles to a memory segment, confirm that they are mapped
+  // separately yet point to the same space.
+  SharedMemory memory1;
+  bool rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory1.Open(test_name, false);
+  EXPECT_FALSE(rv);
+  rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize);
+  EXPECT_TRUE(rv);
+  rv = memory1.Map(kDataSize);
+  EXPECT_TRUE(rv);
+  SharedMemory memory2;
+  rv = memory2.Open(test_name, false);
+  EXPECT_TRUE(rv);
+  rv = memory2.Map(kDataSize);
+  EXPECT_TRUE(rv);
+  EXPECT_NE(memory1.memory(), memory2.memory());  // Compare the pointers.
+
+  // Make sure we don't segfault. (it actually happened!)
+  ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
+  ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
+
+  // Write data to the first memory segment, verify contents of second.
+  memset(memory1.memory(), '1', kDataSize);
+  EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
+
+  // Close the first memory segment, and verify the second has the right data.
+  memory1.Close();
+  char *start_ptr = static_cast<char *>(memory2.memory());
+  char *end_ptr = start_ptr + kDataSize;
+  for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
+    EXPECT_EQ(*ptr, '1');
+
+  // Close the second memory segment.
+  memory2.Close();
+
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory2.Delete(test_name);
+  EXPECT_TRUE(rv);
+}
+
+TEST(SharedMemoryTest, OpenExclusive) {
+  const uint32 kDataSize = 1024;
+  const uint32 kDataSize2 = 2048;
+  std::ostringstream test_name_stream;
+  test_name_stream << "SharedMemoryOpenExclusiveTest."
+                   << Time::Now().ToDoubleT();
+  std::string test_name = test_name_stream.str();
+
+  // Open two handles to a memory segment and check that
+  // open_existing_deprecated works as expected.
+  SharedMemory memory1;
+  bool rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize);
+  EXPECT_TRUE(rv);
+
+  // Memory1 knows it's size because it created it.
+  EXPECT_EQ(memory1.requested_size(), kDataSize);
+
+  rv = memory1.Map(kDataSize);
+  EXPECT_TRUE(rv);
+
+  // The mapped memory1 must be at least the size we asked for.
+  EXPECT_GE(memory1.mapped_size(), kDataSize);
+
+  // The mapped memory1 shouldn't exceed rounding for allocation granularity.
+  EXPECT_LT(memory1.mapped_size(),
+            kDataSize + base::SysInfo::VMAllocationGranularity());
+
+  memset(memory1.memory(), 'G', kDataSize);
+
+  SharedMemory memory2;
+  // Should not be able to create if openExisting is false.
+  rv = memory2.CreateNamedDeprecated(test_name, false, kDataSize2);
+  EXPECT_FALSE(rv);
+
+  // Should be able to create with openExisting true.
+  rv = memory2.CreateNamedDeprecated(test_name, true, kDataSize2);
+  EXPECT_TRUE(rv);
+
+  // Memory2 shouldn't know the size because we didn't create it.
+  EXPECT_EQ(memory2.requested_size(), 0U);
+
+  // We should be able to map the original size.
+  rv = memory2.Map(kDataSize);
+  EXPECT_TRUE(rv);
+
+  // The mapped memory2 must be at least the size of the original.
+  EXPECT_GE(memory2.mapped_size(), kDataSize);
+
+  // The mapped memory2 shouldn't exceed rounding for allocation granularity.
+  EXPECT_LT(memory2.mapped_size(),
+            kDataSize2 + base::SysInfo::VMAllocationGranularity());
+
+  // Verify that opening memory2 didn't truncate or delete memory 1.
+  char *start_ptr = static_cast<char *>(memory2.memory());
+  char *end_ptr = start_ptr + kDataSize;
+  for (char* ptr = start_ptr; ptr < end_ptr; ptr++) {
+    EXPECT_EQ(*ptr, 'G');
+  }
+
+  memory1.Close();
+  memory2.Close();
+
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+}
+#endif
+
+// Check that memory is still mapped after its closed.
+TEST(SharedMemoryTest, CloseNoUnmap) {
+  const size_t kDataSize = 4096;
+
+  SharedMemory memory;
+  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+  char* ptr = static_cast<char*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+  memset(ptr, 'G', kDataSize);
+
+  memory.Close();
+
+  EXPECT_EQ(ptr, memory.memory());
+  EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle());
+
+  for (size_t i = 0; i < kDataSize; i++) {
+    EXPECT_EQ('G', ptr[i]);
+  }
+
+  memory.Unmap();
+  EXPECT_EQ(nullptr, memory.memory());
+}
+
+// Create a set of N threads to each open a shared memory segment and write to
+// it. Verify that they are always reading/writing consistent data.
+TEST(SharedMemoryTest, MultipleThreads) {
+  MultipleThreadMain::CleanUp();
+  // On POSIX we have a problem when 2 threads try to create the shmem
+  // (a file) at exactly the same time, since create both creates the
+  // file and zerofills it.  We solve the problem for this unit test
+  // (make it not flaky) by starting with 1 thread, then
+  // intentionally don't clean up its shmem before running with
+  // kNumThreads.
+
+  int threadcounts[] = { 1, kNumThreads };
+  for (size_t i = 0; i < arraysize(threadcounts); i++) {
+    int numthreads = threadcounts[i];
+    scoped_ptr<PlatformThreadHandle[]> thread_handles;
+    scoped_ptr<MultipleThreadMain*[]> thread_delegates;
+
+    thread_handles.reset(new PlatformThreadHandle[numthreads]);
+    thread_delegates.reset(new MultipleThreadMain*[numthreads]);
+
+    // Spawn the threads.
+    for (int16 index = 0; index < numthreads; index++) {
+      PlatformThreadHandle pth;
+      thread_delegates[index] = new MultipleThreadMain(index);
+      EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
+      thread_handles[index] = pth;
+    }
+
+    // Wait for the threads to finish.
+    for (int index = 0; index < numthreads; index++) {
+      PlatformThread::Join(thread_handles[index]);
+      delete thread_delegates[index];
+    }
+  }
+  MultipleThreadMain::CleanUp();
+}
+
+// TODO(port): this test requires the MultipleLockThread class
+// (defined above), which requires the ability to pass file
+// descriptors between processes.  We haven't done that yet in Chrome
+// for POSIX.
+#if defined(OS_WIN)
+// Create a set of threads to each open a shared memory segment and write to it
+// with the lock held. Verify that they are always reading/writing consistent
+// data.
+TEST(SharedMemoryTest, Lock) {
+  PlatformThreadHandle thread_handles[kNumThreads];
+  MultipleLockThread* thread_delegates[kNumThreads];
+
+  // Spawn the threads.
+  for (int index = 0; index < kNumThreads; ++index) {
+    PlatformThreadHandle pth;
+    thread_delegates[index] = new MultipleLockThread(index);
+    EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
+    thread_handles[index] = pth;
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kNumThreads; ++index) {
+    PlatformThread::Join(thread_handles[index]);
+    delete thread_delegates[index];
+  }
+}
+#endif
+
+// Allocate private (unique) shared memory with an empty string for a
+// name.  Make sure several of them don't point to the same thing as
+// we might expect if the names are equal.
+TEST(SharedMemoryTest, AnonymousPrivate) {
+  int i, j;
+  int count = 4;
+  bool rv;
+  const uint32 kDataSize = 8192;
+
+  scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]);
+  scoped_ptr<int*[]> pointers(new int*[count]);
+  ASSERT_TRUE(memories.get());
+  ASSERT_TRUE(pointers.get());
+
+  for (i = 0; i < count; i++) {
+    rv = memories[i].CreateAndMapAnonymous(kDataSize);
+    EXPECT_TRUE(rv);
+    int *ptr = static_cast<int*>(memories[i].memory());
+    EXPECT_TRUE(ptr);
+    pointers[i] = ptr;
+  }
+
+  for (i = 0; i < count; i++) {
+    // zero out the first int in each except for i; for that one, make it 100.
+    for (j = 0; j < count; j++) {
+      if (i == j)
+        pointers[j][0] = 100;
+      else
+        pointers[j][0] = 0;
+    }
+    // make sure there is no bleeding of the 100 into the other pointers
+    for (j = 0; j < count; j++) {
+      if (i == j)
+        EXPECT_EQ(100, pointers[j][0]);
+      else
+        EXPECT_EQ(0, pointers[j][0]);
+    }
+  }
+
+  for (int i = 0; i < count; i++) {
+    memories[i].Close();
+  }
+}
+
+TEST(SharedMemoryTest, ShareReadOnly) {
+  StringPiece contents = "Hello World";
+
+  SharedMemory writable_shmem;
+  SharedMemoryCreateOptions options;
+  options.size = contents.size();
+  options.share_read_only = true;
+  ASSERT_TRUE(writable_shmem.Create(options));
+  ASSERT_TRUE(writable_shmem.Map(options.size));
+  memcpy(writable_shmem.memory(), contents.data(), contents.size());
+  EXPECT_TRUE(writable_shmem.Unmap());
+
+  SharedMemoryHandle readonly_handle;
+  ASSERT_TRUE(writable_shmem.ShareReadOnlyToProcess(GetCurrentProcessHandle(),
+                                                    &readonly_handle));
+  SharedMemory readonly_shmem(readonly_handle, /*readonly=*/true);
+
+  ASSERT_TRUE(readonly_shmem.Map(contents.size()));
+  EXPECT_EQ(contents,
+            StringPiece(static_cast<const char*>(readonly_shmem.memory()),
+                        contents.size()));
+  EXPECT_TRUE(readonly_shmem.Unmap());
+
+  // Make sure the writable instance is still writable.
+  ASSERT_TRUE(writable_shmem.Map(contents.size()));
+  StringPiece new_contents = "Goodbye";
+  memcpy(writable_shmem.memory(), new_contents.data(), new_contents.size());
+  EXPECT_EQ(new_contents,
+            StringPiece(static_cast<const char*>(writable_shmem.memory()),
+                        new_contents.size()));
+
+  // We'd like to check that if we send the read-only segment to another
+  // process, then that other process can't reopen it read/write.  (Since that
+  // would be a security hole.)  Setting up multiple processes is hard in a
+  // unittest, so this test checks that the *current* process can't reopen the
+  // segment read/write.  I think the test here is stronger than we actually
+  // care about, but there's a remote possibility that sending a file over a
+  // pipe would transform it into read/write.
+  SharedMemoryHandle handle = readonly_shmem.handle();
+
+#if defined(OS_ANDROID)
+  // The "read-only" handle is still writable on Android:
+  // http://crbug.com/320865
+  (void)handle;
+#elif defined(OS_POSIX)
+  EXPECT_EQ(O_RDONLY, fcntl(handle.fd, F_GETFL) & O_ACCMODE)
+      << "The descriptor itself should be read-only.";
+
+  errno = 0;
+  void* writable = mmap(
+      NULL, contents.size(), PROT_READ | PROT_WRITE, MAP_SHARED, handle.fd, 0);
+  int mmap_errno = errno;
+  EXPECT_EQ(MAP_FAILED, writable)
+      << "It shouldn't be possible to re-mmap the descriptor writable.";
+  EXPECT_EQ(EACCES, mmap_errno) << strerror(mmap_errno);
+  if (writable != MAP_FAILED)
+    EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size()));
+
+#elif defined(OS_WIN)
+  EXPECT_EQ(NULL, MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0))
+      << "Shouldn't be able to map memory writable.";
+
+  HANDLE temp_handle;
+  BOOL rv = ::DuplicateHandle(GetCurrentProcess(),
+                              handle,
+                              GetCurrentProcess(),
+                              &temp_handle,
+                              FILE_MAP_ALL_ACCESS,
+                              false,
+                              0);
+  EXPECT_EQ(FALSE, rv)
+      << "Shouldn't be able to duplicate the handle into a writable one.";
+  if (rv)
+    base::win::ScopedHandle writable_handle(temp_handle);
+  rv = ::DuplicateHandle(GetCurrentProcess(),
+                         handle,
+                         GetCurrentProcess(),
+                         &temp_handle,
+                         FILE_MAP_READ,
+                         false,
+                         0);
+  EXPECT_EQ(TRUE, rv)
+      << "Should be able to duplicate the handle into a readable one.";
+  if (rv)
+    base::win::ScopedHandle writable_handle(temp_handle);
+#else
+#error Unexpected platform; write a test that tries to make 'handle' writable.
+#endif  // defined(OS_POSIX) || defined(OS_WIN)
+}
+
+TEST(SharedMemoryTest, ShareToSelf) {
+  StringPiece contents = "Hello World";
+
+  SharedMemory shmem;
+  ASSERT_TRUE(shmem.CreateAndMapAnonymous(contents.size()));
+  memcpy(shmem.memory(), contents.data(), contents.size());
+  EXPECT_TRUE(shmem.Unmap());
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  SharedMemory shared(shared_handle, /*readonly=*/false);
+
+  ASSERT_TRUE(shared.Map(contents.size()));
+  EXPECT_EQ(
+      contents,
+      StringPiece(static_cast<const char*>(shared.memory()), contents.size()));
+
+  ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  SharedMemory readonly(shared_handle, /*readonly=*/true);
+
+  ASSERT_TRUE(readonly.Map(contents.size()));
+  EXPECT_EQ(contents,
+            StringPiece(static_cast<const char*>(readonly.memory()),
+                        contents.size()));
+}
+
+TEST(SharedMemoryTest, MapAt) {
+  ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32));
+  const size_t kCount = SysInfo::VMAllocationGranularity();
+  const size_t kDataSize = kCount * sizeof(uint32);
+
+  SharedMemory memory;
+  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+  uint32* ptr = static_cast<uint32*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+
+  for (size_t i = 0; i < kCount; ++i) {
+    ptr[i] = i;
+  }
+
+  memory.Unmap();
+
+  off_t offset = SysInfo::VMAllocationGranularity();
+  ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset));
+  offset /= sizeof(uint32);
+  ptr = static_cast<uint32*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+  for (size_t i = offset; i < kCount; ++i) {
+    EXPECT_EQ(ptr[i - offset], i);
+  }
+}
+
+TEST(SharedMemoryTest, MapTwice) {
+  const uint32 kDataSize = 1024;
+  SharedMemory memory;
+  bool rv = memory.CreateAndMapAnonymous(kDataSize);
+  EXPECT_TRUE(rv);
+
+  void* old_address = memory.memory();
+
+  rv = memory.Map(kDataSize);
+  EXPECT_FALSE(rv);
+  EXPECT_EQ(old_address, memory.memory());
+}
+
+#if defined(OS_POSIX)
+// This test is not applicable for iOS (crbug.com/399384).
+#if !defined(OS_IOS)
+// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
+TEST(SharedMemoryTest, AnonymousExecutable) {
+  const uint32 kTestSize = 1 << 16;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  options.executable = true;
+
+  EXPECT_TRUE(shared_memory.Create(options));
+  EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
+
+  EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(),
+                        PROT_READ | PROT_EXEC));
+}
+#endif  // !defined(OS_IOS)
+
+// Android supports a different permission model than POSIX for its "ashmem"
+// shared memory implementation. So the tests about file permissions are not
+// included on Android.
+#if !defined(OS_ANDROID)
+
+// Set a umask and restore the old mask on destruction.
+class ScopedUmaskSetter {
+ public:
+  explicit ScopedUmaskSetter(mode_t target_mask) {
+    old_umask_ = umask(target_mask);
+  }
+  ~ScopedUmaskSetter() { umask(old_umask_); }
+ private:
+  mode_t old_umask_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
+};
+
+// Create a shared memory object, check its permissions.
+TEST(SharedMemoryTest, FilePermissionsAnonymous) {
+  const uint32 kTestSize = 1 << 8;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  // Set a file mode creation mask that gives all permissions.
+  ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
+
+  EXPECT_TRUE(shared_memory.Create(options));
+
+  int shm_fd = shared_memory.handle().fd;
+  struct stat shm_stat;
+  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
+  // Neither the group, nor others should be able to read the shared memory
+  // file.
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
+}
+
+// Create a shared memory object, check its permissions.
+TEST(SharedMemoryTest, FilePermissionsNamed) {
+  const uint32 kTestSize = 1 << 8;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  std::string shared_mem_name = "shared_perm_test-" + IntToString(getpid()) +
+      "-" + Uint64ToString(RandUint64());
+  options.name_deprecated = &shared_mem_name;
+  // Set a file mode creation mask that gives all permissions.
+  ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
+
+  EXPECT_TRUE(shared_memory.Create(options));
+  // Clean-up the backing file name immediately, we don't need it.
+  EXPECT_TRUE(shared_memory.Delete(shared_mem_name));
+
+  int shm_fd = shared_memory.handle().fd;
+  struct stat shm_stat;
+  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
+  // Neither the group, nor others should have been able to open the shared
+  // memory file while its name existed.
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
+}
+#endif  // !defined(OS_ANDROID)
+
+#endif  // defined(OS_POSIX)
+
+// Map() will return addresses which are aligned to the platform page size, this
+// varies from platform to platform though.  Since we'd like to advertise a
+// minimum alignment that callers can count on, test for it here.
+TEST(SharedMemoryTest, MapMinimumAlignment) {
+  static const int kDataSize = 8192;
+
+  SharedMemory shared_memory;
+  ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize));
+  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
+      shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  shared_memory.Close();
+}
+
+#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+
+// On POSIX it is especially important we test shmem across processes,
+// not just across threads.  But the test is enabled on all platforms.
+class SharedMemoryProcessTest : public MultiProcessTest {
+ public:
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  static int TaskTestMain() {
+    int errors = 0;
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool pool;
+#endif
+    const uint32 kDataSize = 1024;
+    SharedMemory memory;
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    rv = memory.Map(kDataSize);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    int *ptr = static_cast<int*>(memory.memory());
+
+    for (int idx = 0; idx < 20; idx++) {
+      memory.LockDeprecated();
+      int i = (1 << 16) + idx;
+      *ptr = i;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+      if (*ptr != i)
+        errors++;
+      memory.UnlockDeprecated();
+    }
+
+    memory.Close();
+    return errors;
+  }
+
+ private:
+  static const char* const s_test_name_;
+};
+
+const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
+
+TEST_F(SharedMemoryProcessTest, Tasks) {
+  SharedMemoryProcessTest::CleanUp();
+
+  Process processes[kNumTasks];
+  for (int index = 0; index < kNumTasks; ++index) {
+    processes[index] = SpawnChild("SharedMemoryTestMain");
+    ASSERT_TRUE(processes[index].IsValid());
+  }
+
+  int exit_code = 0;
+  for (int index = 0; index < kNumTasks; ++index) {
+    EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+
+  SharedMemoryProcessTest::CleanUp();
+}
+
+MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
+  return SharedMemoryProcessTest::TaskTestMain();
+}
+
+#endif  // !OS_IOS
+
+}  // namespace base
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
new file mode 100644
index 0000000..7e0cf0b
--- /dev/null
+++ b/base/memory/shared_memory_win.cc
@@ -0,0 +1,284 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory.h"
+
+#include <aclapi.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+// Returns the length of the memory section starting at the supplied address.
+size_t GetMemorySectionSize(void* address) {
+  MEMORY_BASIC_INFORMATION memory_info;
+  if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
+    return 0;
+  return memory_info.RegionSize - (static_cast<char*>(address) -
+         static_cast<char*>(memory_info.AllocationBase));
+}
+
+}  // namespace.
+
+namespace base {
+
+SharedMemory::SharedMemory()
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(false),
+      mapped_size_(0),
+      requested_size_(0),
+      lock_(NULL) {
+}
+
+SharedMemory::SharedMemory(const std::wstring& name)
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0),
+      mapped_size_(0),
+      lock_(NULL),
+      name_(name) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0),
+      mapped_size_(0),
+      lock_(NULL) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0),
+      mapped_size_(0),
+      lock_(NULL) {
+  ::DuplicateHandle(process, handle,
+                    GetCurrentProcess(), &mapped_file_,
+                    read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
+                        FILE_MAP_WRITE,
+                    FALSE, 0);
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+  if (lock_ != NULL)
+    CloseHandle(lock_);
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle != NULL;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return NULL;
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK(handle != NULL);
+  ::CloseHandle(handle);
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  // Rounded down from value reported here:
+  // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
+  return static_cast<size_t>(1 << 23);
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here,
+  // wasting 32k per mapping on average.
+  static const size_t kSectionMask = 65536 - 1;
+  DCHECK(!options.executable);
+  DCHECK(!mapped_file_);
+  if (options.size == 0)
+    return false;
+
+  // Check maximum accounting for overflow.
+  if (options.size >
+      static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask)
+    return false;
+
+  size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
+  name_ = options.name_deprecated ?
+      ASCIIToUTF16(*options.name_deprecated) : L"";
+  SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
+  SECURITY_DESCRIPTOR sd;
+  ACL dacl;
+
+  if (options.share_read_only && name_.empty()) {
+    // Add an empty DACL to enforce anonymous read-only sections.
+    sa.lpSecurityDescriptor = &sd;
+    if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION))
+      return false;
+    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
+      return false;
+    if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))
+      return false;
+
+    // Windows ignores DACLs on certain unnamed objects (like shared sections).
+    // So, we generate a random name when we need to enforce read-only.
+    uint64_t rand_values[4];
+    RandBytes(&rand_values, sizeof(rand_values));
+    name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
+                         rand_values[0], rand_values[1],
+                         rand_values[2], rand_values[3]);
+  }
+  mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
+      PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
+      name_.empty() ? nullptr : name_.c_str());
+  if (!mapped_file_)
+    return false;
+
+  requested_size_ = options.size;
+
+  // Check if the shared memory pre-exists.
+  if (GetLastError() == ERROR_ALREADY_EXISTS) {
+    // If the file already existed, set requested_size_ to 0 to show that
+    // we don't know the size.
+    requested_size_ = 0;
+    if (!options.open_existing_deprecated) {
+      Close();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  // intentionally empty -- there is nothing for us to do on Windows.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  DCHECK(!mapped_file_);
+
+  name_ = ASCIIToUTF16(name);
+  read_only_ = read_only;
+  mapped_file_ = OpenFileMapping(
+      read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
+      false, name_.empty() ? NULL : name_.c_str());
+  if (mapped_file_ != NULL) {
+    // Note: size_ is not set in this case.
+    return true;
+  }
+  return false;
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == NULL)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+  memory_ = MapViewOfFile(mapped_file_,
+                          read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
+                              FILE_MAP_WRITE,
+                          static_cast<uint64>(offset) >> 32,
+                          static_cast<DWORD>(offset),
+                          bytes);
+  if (memory_ != NULL) {
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+    mapped_size_ = GetMemorySectionSize(memory_);
+    return true;
+  }
+  return false;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  UnmapViewOfFile(memory_);
+  memory_ = NULL;
+  return true;
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  *new_handle = 0;
+  DWORD access = FILE_MAP_READ;
+  DWORD options = 0;
+  HANDLE mapped_file = mapped_file_;
+  HANDLE result;
+  if (share_mode == SHARE_CURRENT_MODE && !read_only_)
+    access |= FILE_MAP_WRITE;
+  if (close_self) {
+    // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
+    options = DUPLICATE_CLOSE_SOURCE;
+    mapped_file_ = NULL;
+    Unmap();
+  }
+
+  if (process == GetCurrentProcess() && close_self) {
+    *new_handle = mapped_file;
+    return true;
+  }
+
+  if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process,
+      &result, access, FALSE, options))
+    return false;
+  *new_handle = result;
+  return true;
+}
+
+
+void SharedMemory::Close() {
+  if (mapped_file_ != NULL) {
+    CloseHandle(mapped_file_);
+    mapped_file_ = NULL;
+  }
+}
+
+void SharedMemory::LockDeprecated() {
+  if (lock_ == NULL) {
+    std::wstring name = name_;
+    name.append(L"lock");
+    lock_ = CreateMutex(NULL, FALSE, name.c_str());
+    if (lock_ == NULL) {
+      DPLOG(ERROR) << "Could not create mutex.";
+      NOTREACHED();
+      return;  // There is nothing good we can do here.
+    }
+  }
+  DWORD result = WaitForSingleObject(lock_, INFINITE);
+  DCHECK_EQ(result, WAIT_OBJECT_0);
+}
+
+void SharedMemory::UnlockDeprecated() {
+  DCHECK(lock_ != NULL);
+  ReleaseMutex(lock_);
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return mapped_file_;
+}
+
+}  // namespace base
diff --git a/base/memory/singleton.cc b/base/memory/singleton.cc
new file mode 100644
index 0000000..f68ecaa
--- /dev/null
+++ b/base/memory/singleton.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/singleton.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance) {
+  // Handle the race. Another thread beat us and either:
+  // - Has the object in BeingCreated state
+  // - Already has the object created...
+  // We know value != NULL.  It could be kBeingCreatedMarker, or a valid ptr.
+  // Unless your constructor can be very time consuming, it is very unlikely
+  // to hit this race.  When it does, we just spin and yield the thread until
+  // the object has been created.
+  subtle::AtomicWord value;
+  while (true) {
+    // The load has acquire memory ordering as the thread which reads the
+    // instance pointer must acquire visibility over the associated data.
+    // The pairing Release_Store operation is in Singleton::get().
+    value = subtle::Acquire_Load(instance);
+    if (value != kBeingCreatedMarker)
+      break;
+    PlatformThread::YieldCurrentThread();
+  }
+  return value;
+}
+
+}  // namespace internal
+}  // namespace base
+
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
new file mode 100644
index 0000000..e50bdc0
--- /dev/null
+++ b/base/memory/singleton.h
@@ -0,0 +1,283 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// PLEASE READ: Do you really need a singleton?
+//
+// Singletons make it hard to determine the lifetime of an object, which can
+// lead to buggy code and spurious crashes.
+//
+// Instead of adding another singleton into the mix, try to identify either:
+//   a) An existing singleton that can manage your object's lifetime
+//   b) Locations where you can deterministically create the object and pass
+//      into other objects
+//
+// If you absolutely need a singleton, please keep them as trivial as possible
+// and ideally a leaf dependency. Singletons get problematic when they attempt
+// to do too much in their destructor or have circular dependencies.
+
+#ifndef BASE_MEMORY_SINGLETON_H_
+#define BASE_MEMORY_SINGLETON_H_
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+namespace internal {
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kBeingCreatedMarker = 1;
+
+// We pull out some of the functionality into a non-templated function, so that
+// we can implement the more complicated pieces out of line in the .cc file.
+BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
+
+}  // namespace internal
+}  // namespace base
+
+// TODO(joth): Move more of this file into namespace base
+
+// Default traits for Singleton<Type>. Calls operator new and operator delete on
+// the object. Registers automatic deletion at process exit.
+// Overload if you need arguments or another memory allocation function.
+template<typename Type>
+struct DefaultSingletonTraits {
+  // Allocates the object.
+  static Type* New() {
+    // The parenthesis is very important here; it forces POD type
+    // initialization.
+    return new Type();
+  }
+
+  // Destroys the object.
+  static void Delete(Type* x) {
+    delete x;
+  }
+
+  // Set to true to automatically register deletion of the object on process
+  // exit. See below for the required call that makes this happen.
+  static const bool kRegisterAtExit = true;
+
+#ifndef NDEBUG
+  // Set to false to disallow access on a non-joinable thread.  This is
+  // different from kRegisterAtExit because StaticMemorySingletonTraits allows
+  // access on non-joinable threads, and gracefully handles this.
+  static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+};
+
+
+// Alternate traits for use with the Singleton<Type>.  Identical to
+// DefaultSingletonTraits except that the Singleton will not be cleaned up
+// at exit.
+template<typename Type>
+struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
+  static const bool kRegisterAtExit = false;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+};
+
+
+// Alternate traits for use with the Singleton<Type>.  Allocates memory
+// for the singleton instance from a static buffer.  The singleton will
+// be cleaned up at exit, but can't be revived after destruction unless
+// the Resurrect() method is called.
+//
+// This is useful for a certain category of things, notably logging and
+// tracing, where the singleton instance is of a type carefully constructed to
+// be safe to access post-destruction.
+// In logging and tracing you'll typically get stray calls at odd times, like
+// during static destruction, thread teardown and the like, and there's a
+// termination race on the heap-based singleton - e.g. if one thread calls
+// get(), but then another thread initiates AtExit processing, the first thread
+// may call into an object residing in unallocated memory. If the instance is
+// allocated from the data segment, then this is survivable.
+//
+// The destructor is to deallocate system resources, in this case to unregister
+// a callback the system will invoke when logging levels change. Note that
+// this is also used in e.g. Chrome Frame, where you have to allow for the
+// possibility of loading briefly into someone else's process space, and
+// so leaking is not an option, as that would sabotage the state of your host
+// process once you've unloaded.
+template <typename Type>
+struct StaticMemorySingletonTraits {
+  // WARNING: User has to deal with get() in the singleton class
+  // this is traits for returning NULL.
+  static Type* New() {
+    // Only constructs once and returns pointer; otherwise returns NULL.
+    if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1))
+      return NULL;
+
+    return new(buffer_.void_data()) Type();
+  }
+
+  static void Delete(Type* p) {
+    if (p != NULL)
+      p->Type::~Type();
+  }
+
+  static const bool kRegisterAtExit = true;
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+
+  // Exposed for unittesting.
+  static void Resurrect() {
+    base::subtle::NoBarrier_Store(&dead_, 0);
+  }
+
+ private:
+  static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  // Signal the object was already deleted, so it is not revived.
+  static base::subtle::Atomic32 dead_;
+};
+
+template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+    StaticMemorySingletonTraits<Type>::buffer_;
+template <typename Type> base::subtle::Atomic32
+    StaticMemorySingletonTraits<Type>::dead_ = 0;
+
+// The Singleton<Type, Traits, DifferentiatingType> class manages a single
+// instance of Type which will be created on first use and will be destroyed at
+// normal process exit). The Trait::Delete function will not be called on
+// abnormal process exit.
+//
+// DifferentiatingType is used as a key to differentiate two different
+// singletons having the same memory allocation functions but serving a
+// different purpose. This is mainly used for Locks serving different purposes.
+//
+// Example usage:
+//
+// In your header:
+//   template <typename T> struct DefaultSingletonTraits;
+//   class FooClass {
+//    public:
+//     static FooClass* GetInstance();  <-- See comment below on this.
+//     void Bar() { ... }
+//    private:
+//     FooClass() { ... }
+//     friend struct DefaultSingletonTraits<FooClass>;
+//
+//     DISALLOW_COPY_AND_ASSIGN(FooClass);
+//   };
+//
+// In your source file:
+//  #include "base/memory/singleton.h"
+//  FooClass* FooClass::GetInstance() {
+//    return Singleton<FooClass>::get();
+//  }
+//
+// And to call methods on FooClass:
+//   FooClass::GetInstance()->Bar();
+//
+// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance
+// and it is important that FooClass::GetInstance() is not inlined in the
+// header. This makes sure that when source files from multiple targets include
+// this header they don't end up with different copies of the inlined code
+// creating multiple copies of the singleton.
+//
+// Singleton<> has no non-static members and doesn't need to actually be
+// instantiated.
+//
+// This class is itself thread-safe. The underlying Type must of course be
+// thread-safe if you want to use it concurrently. Two parameters may be tuned
+// depending on the user's requirements.
+//
+// Glossary:
+//   RAE = kRegisterAtExit
+//
+// On every platform, if Traits::RAE is true, the singleton will be destroyed at
+// process exit. More precisely it uses base::AtExitManager which requires an
+// object of this type to be instantiated. AtExitManager mimics the semantics
+// of atexit() such as LIFO order but under Windows is safer to call. For more
+// information see at_exit.h.
+//
+// If Traits::RAE is false, the singleton will not be freed at process exit,
+// thus the singleton will be leaked if it is ever accessed. Traits::RAE
+// shouldn't be false unless absolutely necessary. Remember that the heap where
+// the object is allocated may be destroyed by the CRT anyway.
+//
+// Caveats:
+// (a) Every call to get(), operator->() and operator*() incurs some overhead
+//     (16ns on my P4/2.8GHz) to check whether the object has already been
+//     initialized.  You may wish to cache the result of get(); it will not
+//     change.
+//
+// (b) Your factory function must never throw an exception. This class is not
+//     exception-safe.
+//
+template <typename Type,
+          typename Traits = DefaultSingletonTraits<Type>,
+          typename DifferentiatingType = Type>
+class Singleton {
+ private:
+  // Classes using the Singleton<T> pattern should declare a GetInstance()
+  // method and call Singleton::get() from within that.
+  friend Type* Type::GetInstance();
+
+  // Allow TraceLog tests to test tracing after OnExit.
+  friend class DeleteTraceLogForTesting;
+
+  // This class is safe to be constructed and copy-constructed since it has no
+  // member.
+
+  // Return a pointer to the one true instance of the class.
+  static Type* get() {
+#ifndef NDEBUG
+    // Avoid making TLS lookup on release builds.
+    if (!Traits::kAllowedToAccessOnNonjoinableThread)
+      base::ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+    // The load has acquire memory ordering as the thread which reads the
+    // instance_ pointer must acquire visibility over the singleton data.
+    base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
+    if (value != 0 && value != base::internal::kBeingCreatedMarker) {
+      return reinterpret_cast<Type*>(value);
+    }
+
+    // Object isn't created yet, maybe we will get to create it, let's try...
+    if (base::subtle::Acquire_CompareAndSwap(
+          &instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
+      // instance_ was NULL and is now kBeingCreatedMarker.  Only one thread
+      // will ever get here.  Threads might be spinning on us, and they will
+      // stop right after we do this store.
+      Type* newval = Traits::New();
+
+      // Releases the visibility over instance_ to the readers.
+      base::subtle::Release_Store(
+          &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
+
+      if (newval != NULL && Traits::kRegisterAtExit)
+        base::AtExitManager::RegisterCallback(OnExit, NULL);
+
+      return newval;
+    }
+
+    // We hit a race. Wait for the other thread to complete it.
+    value = base::internal::WaitForInstance(&instance_);
+
+    return reinterpret_cast<Type*>(value);
+  }
+
+  // Adapter function for use with AtExit().  This should be called single
+  // threaded, so don't use atomic operations.
+  // Calling OnExit while singleton is in use by other threads is a mistake.
+  static void OnExit(void* /*unused*/) {
+    // AtExit should only ever be register after the singleton instance was
+    // created.  We should only ever get here with a valid instance_ pointer.
+    Traits::Delete(
+        reinterpret_cast<Type*>(base::subtle::NoBarrier_Load(&instance_)));
+    instance_ = 0;
+  }
+  static base::subtle::AtomicWord instance_;
+};
+
+template <typename Type, typename Traits, typename DifferentiatingType>
+base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
+    instance_ = 0;
+
+#endif  // BASE_MEMORY_SINGLETON_H_
diff --git a/base/memory/singleton_objc.h b/base/memory/singleton_objc.h
new file mode 100644
index 0000000..6df3f77
--- /dev/null
+++ b/base/memory/singleton_objc.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Support for using the Singleton<T> pattern with Objective-C objects.  A
+// SingletonObjC is the same as a Singleton, except the default traits are
+// appropriate for Objective-C objects.  A typical Objective-C object of type
+// NSExampleType can be maintained as a singleton and accessed with:
+//
+//   NSExampleType* exampleSingleton = SingletonObjC<NSExampleType>::get();
+//
+// The first time this is used, it will create exampleSingleton as the result
+// of [[NSExampleType alloc] init].  Subsequent calls will return the same
+// NSExampleType* object.  The object will be released by calling
+// -[NSExampleType release] when Singleton's atexit routines run
+// (see singleton.h).
+//
+// For Objective-C objects initialized through means other than the
+// no-parameter -init selector, DefaultSingletonObjCTraits may be extended
+// as needed:
+//
+//   struct FooSingletonTraits : public DefaultSingletonObjCTraits<Foo> {
+//     static Foo* New() {
+//       return [[Foo alloc] initWithName:@"selecty"];
+//     }
+//   };
+//   ...
+//   Foo* widgetSingleton = SingletonObjC<Foo, FooSingletonTraits>::get();
+
+#ifndef BASE_MEMORY_SINGLETON_OBJC_H_
+#define BASE_MEMORY_SINGLETON_OBJC_H_
+
+#import <Foundation/Foundation.h>
+#include "base/memory/singleton.h"
+
+// Singleton traits usable to manage traditional Objective-C objects, which
+// are instantiated by sending |alloc| and |init| messages, and are deallocated
+// in a memory-managed environment when their retain counts drop to 0 by
+// sending |release| messages.
+template<typename Type>
+struct DefaultSingletonObjCTraits : public DefaultSingletonTraits<Type> {
+  static Type* New() {
+    return [[Type alloc] init];
+  }
+
+  static void Delete(Type* object) {
+    [object release];
+  }
+};
+
+// Exactly like Singleton, but without the DefaultSingletonObjCTraits as the
+// default trait class.  This makes it straightforward for Objective-C++ code
+// to hold Objective-C objects as singletons.
+template<typename Type,
+         typename Traits = DefaultSingletonObjCTraits<Type>,
+         typename DifferentiatingType = Type>
+class SingletonObjC : public Singleton<Type, Traits, DifferentiatingType> {
+};
+
+#endif  // BASE_MEMORY_SINGLETON_OBJC_H_
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
new file mode 100644
index 0000000..dbff007
--- /dev/null
+++ b/base/memory/singleton_unittest.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/memory/singleton.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
+
+typedef void (*CallbackFunc)();
+
+class IntSingleton {
+ public:
+  static IntSingleton* GetInstance() {
+    return Singleton<IntSingleton>::get();
+  }
+
+  int value_;
+};
+
+class Init5Singleton {
+ public:
+  struct Trait;
+
+  static Init5Singleton* GetInstance() {
+    return Singleton<Init5Singleton, Trait>::get();
+  }
+
+  int value_;
+};
+
+struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
+  static Init5Singleton* New() {
+    Init5Singleton* instance = new Init5Singleton();
+    instance->value_ = 5;
+    return instance;
+  }
+};
+
+int* SingletonInt() {
+  return &IntSingleton::GetInstance()->value_;
+}
+
+int* SingletonInt5() {
+  return &Init5Singleton::GetInstance()->value_;
+}
+
+template <typename Type>
+struct CallbackTrait : public DefaultSingletonTraits<Type> {
+  static void Delete(Type* instance) {
+    if (instance->callback_)
+      (instance->callback_)();
+    DefaultSingletonTraits<Type>::Delete(instance);
+  }
+};
+
+class CallbackSingleton {
+ public:
+  CallbackSingleton() : callback_(NULL) { }
+  CallbackFunc callback_;
+};
+
+class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
+ public:
+  struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
+
+  CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithNoLeakTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
+  }
+};
+
+class CallbackSingletonWithLeakTrait : public CallbackSingleton {
+ public:
+  struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
+    static const bool kRegisterAtExit = false;
+  };
+
+  CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithLeakTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
+  }
+};
+
+class CallbackSingletonWithStaticTrait : public CallbackSingleton {
+ public:
+  struct Trait;
+
+  CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithStaticTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
+  }
+};
+
+struct CallbackSingletonWithStaticTrait::Trait
+    : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
+  static void Delete(CallbackSingletonWithStaticTrait* instance) {
+    if (instance->callback_)
+      (instance->callback_)();
+    StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
+        instance);
+  }
+};
+
+template <class Type>
+class AlignedTestSingleton {
+ public:
+  AlignedTestSingleton() {}
+  ~AlignedTestSingleton() {}
+  static AlignedTestSingleton* GetInstance() {
+    return Singleton<AlignedTestSingleton,
+        StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+  }
+
+  Type type_;
+};
+
+
+void SingletonNoLeak(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+void SingletonLeak(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+CallbackFunc* GetLeakySingleton() {
+  return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
+}
+
+void DeleteLeakySingleton() {
+  DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
+      CallbackSingletonWithLeakTrait::GetInstance());
+}
+
+void SingletonStatic(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+CallbackFunc* GetStaticSingleton() {
+  return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
+}
+
+}  // namespace
+
+class SingletonTest : public testing::Test {
+ public:
+  SingletonTest() {}
+
+  void SetUp() override {
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+ protected:
+  void VerifiesCallbacks() {
+    EXPECT_TRUE(non_leak_called_);
+    EXPECT_FALSE(leaky_called_);
+    EXPECT_TRUE(static_called_);
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+  void VerifiesCallbacksNotCalled() {
+    EXPECT_FALSE(non_leak_called_);
+    EXPECT_FALSE(leaky_called_);
+    EXPECT_FALSE(static_called_);
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+  static void CallbackNoLeak() {
+    non_leak_called_ = true;
+  }
+
+  static void CallbackLeak() {
+    leaky_called_ = true;
+  }
+
+  static void CallbackStatic() {
+    static_called_ = true;
+  }
+
+ private:
+  static bool non_leak_called_;
+  static bool leaky_called_;
+  static bool static_called_;
+};
+
+bool SingletonTest::non_leak_called_ = false;
+bool SingletonTest::leaky_called_ = false;
+bool SingletonTest::static_called_ = false;
+
+TEST_F(SingletonTest, Basic) {
+  int* singleton_int;
+  int* singleton_int_5;
+  CallbackFunc* leaky_singleton;
+  CallbackFunc* static_singleton;
+
+  {
+    base::ShadowingAtExitManager sem;
+    {
+      singleton_int = SingletonInt();
+    }
+    // Ensure POD type initialization.
+    EXPECT_EQ(*singleton_int, 0);
+    *singleton_int = 1;
+
+    EXPECT_EQ(singleton_int, SingletonInt());
+    EXPECT_EQ(*singleton_int, 1);
+
+    {
+      singleton_int_5 = SingletonInt5();
+    }
+    // Is default initialized to 5.
+    EXPECT_EQ(*singleton_int_5, 5);
+
+    SingletonNoLeak(&CallbackNoLeak);
+    SingletonLeak(&CallbackLeak);
+    SingletonStatic(&CallbackStatic);
+    static_singleton = GetStaticSingleton();
+    leaky_singleton = GetLeakySingleton();
+    EXPECT_TRUE(leaky_singleton);
+  }
+
+  // Verify that only the expected callback has been called.
+  VerifiesCallbacks();
+  // Delete the leaky singleton.
+  DeleteLeakySingleton();
+
+  // The static singleton can't be acquired post-atexit.
+  EXPECT_EQ(NULL, GetStaticSingleton());
+
+  {
+    base::ShadowingAtExitManager sem;
+    // Verifiy that the variables were reset.
+    {
+      singleton_int = SingletonInt();
+      EXPECT_EQ(*singleton_int, 0);
+    }
+    {
+      singleton_int_5 = SingletonInt5();
+      EXPECT_EQ(*singleton_int_5, 5);
+    }
+    {
+      // Resurrect the static singleton, and assert that it
+      // still points to the same (static) memory.
+      CallbackSingletonWithStaticTrait::Trait::Resurrect();
+      EXPECT_EQ(GetStaticSingleton(), static_singleton);
+    }
+  }
+  // The leaky singleton shouldn't leak since SingletonLeak has not been called.
+  VerifiesCallbacksNotCalled();
+}
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST_F(SingletonTest, Alignment) {
+  using base::AlignedMemory;
+
+  // Create some static singletons with increasing sizes and alignment
+  // requirements. By ordering this way, the linker will need to do some work to
+  // ensure proper alignment of the static data.
+  AlignedTestSingleton<int32>* align4 =
+      AlignedTestSingleton<int32>::GetInstance();
+  AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
+      AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
+  AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
+      AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
+  AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
+      AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
+
+  EXPECT_ALIGNED(align4, 4);
+  EXPECT_ALIGNED(align32, 32);
+  EXPECT_ALIGNED(align128, 128);
+  EXPECT_ALIGNED(align4096, 4096);
+}
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc
new file mode 100644
index 0000000..d9ce86a
--- /dev/null
+++ b/base/memory/weak_ptr.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+namespace internal {
+
+WeakReference::Flag::Flag() : is_valid_(true) {
+  // Flags only become bound when checked for validity, or invalidated,
+  // so that we can check that later validity/invalidation operations on
+  // the same Flag take place on the same sequenced thread.
+  sequence_checker_.DetachFromSequence();
+}
+
+void WeakReference::Flag::Invalidate() {
+  // The flag being invalidated with a single ref implies that there are no
+  // weak pointers in existence. Allow deletion on other thread in this case.
+  DCHECK(sequence_checker_.CalledOnValidSequencedThread() || HasOneRef())
+      << "WeakPtrs must be invalidated on the same sequenced thread.";
+  is_valid_ = false;
+}
+
+bool WeakReference::Flag::IsValid() const {
+  DCHECK(sequence_checker_.CalledOnValidSequencedThread())
+      << "WeakPtrs must be checked on the same sequenced thread.";
+  return is_valid_;
+}
+
+WeakReference::Flag::~Flag() {
+}
+
+WeakReference::WeakReference() {
+}
+
+WeakReference::WeakReference(const Flag* flag) : flag_(flag) {
+}
+
+WeakReference::~WeakReference() {
+}
+
+bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); }
+
+WeakReferenceOwner::WeakReferenceOwner() {
+}
+
+WeakReferenceOwner::~WeakReferenceOwner() {
+  Invalidate();
+}
+
+WeakReference WeakReferenceOwner::GetRef() const {
+  // If we hold the last reference to the Flag then create a new one.
+  if (!HasRefs())
+    flag_ = new WeakReference::Flag();
+
+  return WeakReference(flag_.get());
+}
+
+void WeakReferenceOwner::Invalidate() {
+  if (flag_.get()) {
+    flag_->Invalidate();
+    flag_ = NULL;
+  }
+}
+
+WeakPtrBase::WeakPtrBase() {
+}
+
+WeakPtrBase::~WeakPtrBase() {
+}
+
+WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
new file mode 100644
index 0000000..8a43392
--- /dev/null
+++ b/base/memory/weak_ptr.h
@@ -0,0 +1,339 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Weak pointers are pointers to an object that do not affect its lifetime,
+// and which may be invalidated (i.e. reset to NULL) by the object, or its
+// owner, at any time, most commonly when the object is about to be deleted.
+
+// Weak pointers are useful when an object needs to be accessed safely by one
+// or more objects other than its owner, and those callers can cope with the
+// object vanishing and e.g. tasks posted to it being silently dropped.
+// Reference-counting such an object would complicate the ownership graph and
+// make it harder to reason about the object's lifetime.
+
+// EXAMPLE:
+//
+//  class Controller {
+//   public:
+//    void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
+//    void WorkComplete(const Result& result) { ... }
+//   private:
+//    // Member variables should appear before the WeakPtrFactory, to ensure
+//    // that any WeakPtrs to Controller are invalidated before its members
+//    // variable's destructors are executed, rendering them invalid.
+//    WeakPtrFactory<Controller> weak_factory_;
+//  };
+//
+//  class Worker {
+//   public:
+//    static void StartNew(const WeakPtr<Controller>& controller) {
+//      Worker* worker = new Worker(controller);
+//      // Kick off asynchronous processing...
+//    }
+//   private:
+//    Worker(const WeakPtr<Controller>& controller)
+//        : controller_(controller) {}
+//    void DidCompleteAsynchronousProcessing(const Result& result) {
+//      if (controller_)
+//        controller_->WorkComplete(result);
+//    }
+//    WeakPtr<Controller> controller_;
+//  };
+//
+// With this implementation a caller may use SpawnWorker() to dispatch multiple
+// Workers and subsequently delete the Controller, without waiting for all
+// Workers to have completed.
+
+// ------------------------- IMPORTANT: Thread-safety -------------------------
+
+// Weak pointers may be passed safely between threads, but must always be
+// dereferenced and invalidated on the same SequencedTaskRunner otherwise
+// checking the pointer would be racey.
+//
+// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
+// is dereferenced, the factory and its WeakPtrs become bound to the calling
+// thread or current SequencedWorkerPool token, and cannot be dereferenced or
+// invalidated on any other task runner. Bound WeakPtrs can still be handed
+// off to other task runners, e.g. to use to post tasks back to object on the
+// bound sequence.
+//
+// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
+// it to be passed for a different sequence to use or delete it.
+
+#ifndef BASE_MEMORY_WEAK_PTR_H_
+#define BASE_MEMORY_WEAK_PTR_H_
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/template_util.h"
+
+namespace base {
+
+template <typename T> class SupportsWeakPtr;
+template <typename T> class WeakPtr;
+
+namespace internal {
+// These classes are part of the WeakPtr implementation.
+// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
+
+class BASE_EXPORT WeakReference {
+ public:
+  // Although Flag is bound to a specific SequencedTaskRunner, it may be
+  // deleted from another via base::WeakPtr::~WeakPtr().
+  class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
+   public:
+    Flag();
+
+    void Invalidate();
+    bool IsValid() const;
+
+   private:
+    friend class base::RefCountedThreadSafe<Flag>;
+
+    ~Flag();
+
+    SequenceChecker sequence_checker_;
+    bool is_valid_;
+  };
+
+  WeakReference();
+  explicit WeakReference(const Flag* flag);
+  ~WeakReference();
+
+  bool is_valid() const;
+
+ private:
+  scoped_refptr<const Flag> flag_;
+};
+
+class BASE_EXPORT WeakReferenceOwner {
+ public:
+  WeakReferenceOwner();
+  ~WeakReferenceOwner();
+
+  WeakReference GetRef() const;
+
+  bool HasRefs() const {
+    return flag_.get() && !flag_->HasOneRef();
+  }
+
+  void Invalidate();
+
+ private:
+  mutable scoped_refptr<WeakReference::Flag> flag_;
+};
+
+// This class simplifies the implementation of WeakPtr's type conversion
+// constructor by avoiding the need for a public accessor for ref_.  A
+// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
+// base class gives us a way to access ref_ in a protected fashion.
+class BASE_EXPORT WeakPtrBase {
+ public:
+  WeakPtrBase();
+  ~WeakPtrBase();
+
+ protected:
+  explicit WeakPtrBase(const WeakReference& ref);
+
+  WeakReference ref_;
+};
+
+// This class provides a common implementation of common functions that would
+// otherwise get instantiated separately for each distinct instantiation of
+// SupportsWeakPtr<>.
+class SupportsWeakPtrBase {
+ public:
+  // A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This
+  // conversion will only compile if there is exists a Base which inherits
+  // from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper
+  // function that makes calling this easier.
+  template<typename Derived>
+  static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
+    typedef
+        is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
+    COMPILE_ASSERT(convertible::value,
+                   AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+    return AsWeakPtrImpl<Derived>(t, *t);
+  }
+
+ private:
+  // This template function uses type inference to find a Base of Derived
+  // which is an instance of SupportsWeakPtr<Base>. We can then safely
+  // static_cast the Base* to a Derived*.
+  template <typename Derived, typename Base>
+  static WeakPtr<Derived> AsWeakPtrImpl(
+      Derived* t, const SupportsWeakPtr<Base>&) {
+    WeakPtr<Base> ptr = t->Base::AsWeakPtr();
+    return WeakPtr<Derived>(ptr.ref_, static_cast<Derived*>(ptr.ptr_));
+  }
+};
+
+}  // namespace internal
+
+template <typename T> class WeakPtrFactory;
+
+// The WeakPtr class holds a weak reference to |T*|.
+//
+// This class is designed to be used like a normal pointer.  You should always
+// null-test an object of this class before using it or invoking a method that
+// may result in the underlying object being destroyed.
+//
+// EXAMPLE:
+//
+//   class Foo { ... };
+//   WeakPtr<Foo> foo;
+//   if (foo)
+//     foo->method();
+//
+template <typename T>
+class WeakPtr : public internal::WeakPtrBase {
+ public:
+  WeakPtr() : ptr_(NULL) {
+  }
+
+  // Allow conversion from U to T provided U "is a" T. Note that this
+  // is separate from the (implicit) copy constructor.
+  template <typename U>
+  WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
+  }
+
+  T* get() const { return ref_.is_valid() ? ptr_ : NULL; }
+
+  T& operator*() const {
+    DCHECK(get() != NULL);
+    return *get();
+  }
+  T* operator->() const {
+    DCHECK(get() != NULL);
+    return get();
+  }
+
+  // Allow WeakPtr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2"
+  // will compile but do the wrong thing (i.e., convert to Testable
+  // and then do the comparison).
+ private:
+  typedef T* WeakPtr::*Testable;
+
+ public:
+  operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; }
+
+  void reset() {
+    ref_ = internal::WeakReference();
+    ptr_ = NULL;
+  }
+
+ private:
+  // Explicitly declare comparison operators as required by the bool
+  // trick, but keep them private.
+  template <class U> bool operator==(WeakPtr<U> const&) const;
+  template <class U> bool operator!=(WeakPtr<U> const&) const;
+
+  friend class internal::SupportsWeakPtrBase;
+  template <typename U> friend class WeakPtr;
+  friend class SupportsWeakPtr<T>;
+  friend class WeakPtrFactory<T>;
+
+  WeakPtr(const internal::WeakReference& ref, T* ptr)
+      : WeakPtrBase(ref),
+        ptr_(ptr) {
+  }
+
+  // This pointer is only valid when ref_.is_valid() is true.  Otherwise, its
+  // value is undefined (as opposed to NULL).
+  T* ptr_;
+};
+
+// A class may be composed of a WeakPtrFactory and thereby
+// control how it exposes weak pointers to itself.  This is helpful if you only
+// need weak pointers within the implementation of a class.  This class is also
+// useful when working with primitive types.  For example, you could have a
+// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool.
+template <class T>
+class WeakPtrFactory {
+ public:
+  explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {
+  }
+
+  ~WeakPtrFactory() {
+    ptr_ = NULL;
+  }
+
+  WeakPtr<T> GetWeakPtr() {
+    DCHECK(ptr_);
+    return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_);
+  }
+
+  // Call this method to invalidate all existing weak pointers.
+  void InvalidateWeakPtrs() {
+    DCHECK(ptr_);
+    weak_reference_owner_.Invalidate();
+  }
+
+  // Call this method to determine if any weak pointers exist.
+  bool HasWeakPtrs() const {
+    DCHECK(ptr_);
+    return weak_reference_owner_.HasRefs();
+  }
+
+ private:
+  internal::WeakReferenceOwner weak_reference_owner_;
+  T* ptr_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);
+};
+
+// A class may extend from SupportsWeakPtr to let others take weak pointers to
+// it. This avoids the class itself implementing boilerplate to dispense weak
+// pointers.  However, since SupportsWeakPtr's destructor won't invalidate
+// weak pointers to the class until after the derived class' members have been
+// destroyed, its use can lead to subtle use-after-destroy issues.
+template <class T>
+class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
+ public:
+  SupportsWeakPtr() {}
+
+  WeakPtr<T> AsWeakPtr() {
+    return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
+  }
+
+ protected:
+  ~SupportsWeakPtr() {}
+
+ private:
+  internal::WeakReferenceOwner weak_reference_owner_;
+  DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr);
+};
+
+// Helper function that uses type deduction to safely return a WeakPtr<Derived>
+// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it
+// extends a Base that extends SupportsWeakPtr<Base>.
+//
+// EXAMPLE:
+//   class Base : public base::SupportsWeakPtr<Producer> {};
+//   class Derived : public Base {};
+//
+//   Derived derived;
+//   base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived);
+//
+// Note that the following doesn't work (invalid type conversion) since
+// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(),
+// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at
+// the caller.
+//
+//   base::WeakPtr<Derived> ptr = derived.AsWeakPtr();  // Fails.
+
+template <typename Derived>
+WeakPtr<Derived> AsWeakPtr(Derived* t) {
+  return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);
+}
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_WEAK_PTR_H_
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc
new file mode 100644
index 0000000..20e5c7b
--- /dev/null
+++ b/base/memory/weak_ptr_unittest.cc
@@ -0,0 +1,611 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/weak_ptr.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+template <class T>
+class OffThreadObjectCreator {
+ public:
+  static T* NewObject() {
+    T* result;
+    {
+      Thread creator_thread("creator_thread");
+      creator_thread.Start();
+      creator_thread.task_runner()->PostTask(
+          FROM_HERE, base::Bind(OffThreadObjectCreator::CreateObject, &result));
+    }
+    DCHECK(result);  // We synchronized on thread destruction above.
+    return result;
+  }
+ private:
+  static void CreateObject(T** result) {
+    *result = new T;
+  }
+};
+
+struct Base {
+  std::string member;
+};
+struct Derived : public Base {};
+
+struct TargetBase {};
+struct Target : public TargetBase, public SupportsWeakPtr<Target> {
+  virtual ~Target() {}
+};
+struct DerivedTarget : public Target {};
+struct Arrow {
+  WeakPtr<Target> target;
+};
+struct TargetWithFactory : public Target {
+  TargetWithFactory() : factory(this) {}
+  WeakPtrFactory<Target> factory;
+};
+
+// Helper class to create and destroy weak pointer copies
+// and delete objects on a background thread.
+class BackgroundThread : public Thread {
+ public:
+  BackgroundThread() : Thread("owner_thread") {}
+
+  ~BackgroundThread() override { Stop(); }
+
+  void CreateArrowFromTarget(Arrow** arrow, Target* target) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
+                              target, &completion));
+    completion.Wait();
+  }
+
+  void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
+                              other, &completion));
+    completion.Wait();
+  }
+
+  void DeleteTarget(Target* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
+    completion.Wait();
+  }
+
+  void CopyAndAssignArrow(Arrow* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
+                              &completion));
+    completion.Wait();
+  }
+
+  void CopyAndAssignArrowBase(Arrow* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
+                              object, &completion));
+    completion.Wait();
+  }
+
+  void DeleteArrow(Arrow* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
+    completion.Wait();
+  }
+
+  Target* DeRef(const Arrow* arrow) {
+    WaitableEvent completion(true, false);
+    Target* result = NULL;
+    task_runner()->PostTask(FROM_HERE, base::Bind(&BackgroundThread::DoDeRef,
+                                                  arrow, &result, &completion));
+    completion.Wait();
+    return result;
+  }
+
+ protected:
+  static void DoCreateArrowFromArrow(Arrow** arrow,
+                                     const Arrow* other,
+                                     WaitableEvent* completion) {
+    *arrow = new Arrow;
+    **arrow = *other;
+    completion->Signal();
+  }
+
+  static void DoCreateArrowFromTarget(Arrow** arrow,
+                                      Target* target,
+                                      WaitableEvent* completion) {
+    *arrow = new Arrow;
+    (*arrow)->target = target->AsWeakPtr();
+    completion->Signal();
+  }
+
+  static void DoDeRef(const Arrow* arrow,
+                      Target** result,
+                      WaitableEvent* completion) {
+    *result = arrow->target.get();
+    completion->Signal();
+  }
+
+  static void DoDeleteTarget(Target* object, WaitableEvent* completion) {
+    delete object;
+    completion->Signal();
+  }
+
+  static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) {
+    // Copy constructor.
+    Arrow a = *object;
+    // Assignment operator.
+    *object = a;
+    completion->Signal();
+  }
+
+  static void DoCopyAndAssignArrowBase(
+      Arrow* object,
+      WaitableEvent* completion) {
+    // Copy constructor.
+    WeakPtr<TargetBase> b = object->target;
+    // Assignment operator.
+    WeakPtr<TargetBase> c;
+    c = object->target;
+    completion->Signal();
+  }
+
+  static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) {
+    delete object;
+    completion->Signal();
+  }
+};
+
+}  // namespace
+
+TEST(WeakPtrFactoryTest, Basic) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+}
+
+TEST(WeakPtrFactoryTest, Comparison) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  WeakPtr<int> ptr2 = ptr;
+  EXPECT_EQ(ptr.get(), ptr2.get());
+}
+
+TEST(WeakPtrFactoryTest, OutOfScope) {
+  WeakPtr<int> ptr;
+  EXPECT_EQ(NULL, ptr.get());
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    ptr = factory.GetWeakPtr();
+  }
+  EXPECT_EQ(NULL, ptr.get());
+}
+
+TEST(WeakPtrFactoryTest, Multiple) {
+  WeakPtr<int> a, b;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    b = factory.GetWeakPtr();
+    EXPECT_EQ(&data, a.get());
+    EXPECT_EQ(&data, b.get());
+  }
+  EXPECT_EQ(NULL, a.get());
+  EXPECT_EQ(NULL, b.get());
+}
+
+TEST(WeakPtrFactoryTest, MultipleStaged) {
+  WeakPtr<int> a;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    {
+      WeakPtr<int> b = factory.GetWeakPtr();
+    }
+    EXPECT_TRUE(NULL != a.get());
+  }
+  EXPECT_EQ(NULL, a.get());
+}
+
+TEST(WeakPtrFactoryTest, Dereference) {
+  Base data;
+  data.member = "123456";
+  WeakPtrFactory<Base> factory(&data);
+  WeakPtr<Base> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+  EXPECT_EQ(data.member, (*ptr).member);
+  EXPECT_EQ(data.member, ptr->member);
+}
+
+TEST(WeakPtrFactoryTest, UpCast) {
+  Derived data;
+  WeakPtrFactory<Derived> factory(&data);
+  WeakPtr<Base> ptr = factory.GetWeakPtr();
+  ptr = factory.GetWeakPtr();
+  EXPECT_EQ(ptr.get(), &data);
+}
+
+TEST(WeakPtrTest, SupportsWeakPtr) {
+  Target target;
+  WeakPtr<Target> ptr = target.AsWeakPtr();
+  EXPECT_EQ(&target, ptr.get());
+}
+
+TEST(WeakPtrTest, DerivedTarget) {
+  DerivedTarget target;
+  WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
+  EXPECT_EQ(&target, ptr.get());
+}
+
+TEST(WeakPtrTest, InvalidateWeakPtrs) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+  EXPECT_TRUE(factory.HasWeakPtrs());
+  factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, ptr.get());
+  EXPECT_FALSE(factory.HasWeakPtrs());
+
+  // Test that the factory can create new weak pointers after a
+  // InvalidateWeakPtrs call, and they remain valid until the next
+  // InvalidateWeakPtrs call.
+  WeakPtr<int> ptr2 = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr2.get());
+  EXPECT_TRUE(factory.HasWeakPtrs());
+  factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, ptr2.get());
+  EXPECT_FALSE(factory.HasWeakPtrs());
+}
+
+TEST(WeakPtrTest, HasWeakPtrs) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  {
+    WeakPtr<int> ptr = factory.GetWeakPtr();
+    EXPECT_TRUE(factory.HasWeakPtrs());
+  }
+  EXPECT_FALSE(factory.HasWeakPtrs());
+}
+
+TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
+  // Test that it is OK to create an object that supports WeakPtr on one thread,
+  // but use it on another.  This tests that we do not trip runtime checks that
+  // ensure that a WeakPtr is not used by multiple threads.
+  scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
+  WeakPtr<Target> weak_ptr = target->AsWeakPtr();
+  EXPECT_EQ(target.get(), weak_ptr.get());
+}
+
+TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
+  // Test that it is OK to create an object that has a WeakPtr member on one
+  // thread, but use it on another.  This tests that we do not trip runtime
+  // checks that ensure that a WeakPtr is not used by multiple threads.
+  scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
+  Target target;
+  arrow->target = target.AsWeakPtr();
+  EXPECT_EQ(&target, arrow->target.get());
+}
+
+TEST(WeakPtrTest, MoveOwnershipImplicitly) {
+  // Move object ownership to another thread by releasing all weak pointers
+  // on the original thread first, and then establish WeakPtr on a different
+  // thread.
+  BackgroundThread background;
+  background.Start();
+
+  Target* target = new Target();
+  {
+    WeakPtr<Target> weak_ptr = target->AsWeakPtr();
+    // Main thread deletes the WeakPtr, then the thread ownership of the
+    // object can be implicitly moved.
+  }
+  Arrow* arrow;
+
+  // Background thread creates WeakPtr(and implicitly owns the object).
+  background.CreateArrowFromTarget(&arrow, target);
+  EXPECT_EQ(background.DeRef(arrow), target);
+
+  {
+    // Main thread creates another WeakPtr, but this does not trigger implicitly
+    // thread ownership move.
+    Arrow arrow;
+    arrow.target = target->AsWeakPtr();
+
+    // The new WeakPtr is owned by background thread.
+    EXPECT_EQ(target, background.DeRef(&arrow));
+  }
+
+  // Target can only be deleted on background thread.
+  background.DeleteTarget(target);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) {
+  BackgroundThread background;
+  background.Start();
+
+  Arrow* arrow;
+  {
+    Target target;
+    // Background thread creates WeakPtr.
+    background.CreateArrowFromTarget(&arrow, &target);
+
+    // Bind to background thread.
+    EXPECT_EQ(&target, background.DeRef(arrow));
+
+    // Release the only WeakPtr.
+    arrow->target.reset();
+
+    // Now we should be able to create a new reference from this thread.
+    arrow->target = target.AsWeakPtr();
+
+    // Re-bind to main thread.
+    EXPECT_EQ(&target, arrow->target.get());
+
+    // And the main thread can now delete the target.
+  }
+
+  delete arrow;
+}
+
+TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) {
+  BackgroundThread background;
+  background.Start();
+
+  Arrow arrow;
+  scoped_ptr<TargetWithFactory> target(new TargetWithFactory);
+
+  // Bind to main thread.
+  arrow.target = target->factory.GetWeakPtr();
+  EXPECT_EQ(target.get(), arrow.target.get());
+
+  target->factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, arrow.target.get());
+
+  arrow.target = target->factory.GetWeakPtr();
+  // Re-bind to background thread.
+  EXPECT_EQ(target.get(), background.DeRef(&arrow));
+
+  // And the background thread can now delete the target.
+  background.DeleteTarget(target.release());
+}
+
+TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) {
+  // Originating thread has a WeakPtr that outlives others.
+  // - Main thread creates a WeakPtr
+  // - Background thread creates a WeakPtr copy from the one in main thread
+  // - Destruct the WeakPtr on background thread
+  // - Destruct the WeakPtr on main thread
+  BackgroundThread background;
+  background.Start();
+
+  Target target;
+  Arrow arrow;
+  arrow.target = target.AsWeakPtr();
+
+  Arrow* arrow_copy;
+  background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  EXPECT_EQ(arrow_copy->target.get(), &target);
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) {
+  // Originating thread drops all references before another thread.
+  // - Main thread creates a WeakPtr and passes copy to background thread
+  // - Destruct the pointer on main thread
+  // - Destruct the pointer on background thread
+  BackgroundThread background;
+  background.Start();
+
+  Target target;
+  Arrow* arrow_copy;
+  {
+    Arrow arrow;
+    arrow.target = target.AsWeakPtr();
+    background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  }
+  EXPECT_EQ(arrow_copy->target.get(), &target);
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, OwnerThreadDeletesObject) {
+  // Originating thread invalidates WeakPtrs while its held by other thread.
+  // - Main thread creates WeakPtr and passes Copy to background thread
+  // - Object gets destroyed on main thread
+  //   (invalidates WeakPtr on background thread)
+  // - WeakPtr gets destroyed on Thread B
+  BackgroundThread background;
+  background.Start();
+  Arrow* arrow_copy;
+  {
+    Target target;
+    Arrow arrow;
+    arrow.target = target.AsWeakPtr();
+    background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  }
+  EXPECT_EQ(NULL, arrow_copy->target.get());
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) {
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow *arrow = new Arrow();
+  arrow->target = target.AsWeakPtr();
+
+  // Background can copy and assign arrow (as well as the WeakPtr inside).
+  BackgroundThread background;
+  background.Start();
+  background.CopyAndAssignArrow(arrow);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) {
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow *arrow = new Arrow();
+  arrow->target = target.AsWeakPtr();
+
+  // Background can copy and assign arrow's WeakPtr to a base class WeakPtr.
+  BackgroundThread background;
+  background.Start();
+  background.CopyAndAssignArrowBase(arrow);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) {
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow* arrow = new Arrow();
+  arrow->target = target.AsWeakPtr();
+
+  // Background can delete arrow (as well as the WeakPtr inside).
+  BackgroundThread background;
+  background.Start();
+  background.DeleteArrow(arrow);
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  BackgroundThread background;
+  background.Start();
+
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow arrow;
+  arrow.target = target.AsWeakPtr();
+
+  // Background copies the WeakPtr.
+  Arrow* arrow_copy;
+  background.CreateArrowFromArrow(&arrow_copy, &arrow);
+
+  // The copy is still bound to main thread so I can deref.
+  EXPECT_EQ(arrow.target.get(), arrow_copy->target.get());
+
+  // Although background thread created the copy, it can not deref the copied
+  // WeakPtr.
+  ASSERT_DEATH(background.DeRef(arrow_copy), "");
+
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  // Main thread creates a Target object.
+  Target target;
+
+  // Main thread creates an arrow referencing the Target (so target's
+  // thread ownership can not be implicitly moved).
+  Arrow arrow;
+  arrow.target = target.AsWeakPtr();
+  arrow.target.get();
+
+  // Background thread tries to deref target, which violates thread ownership.
+  BackgroundThread background;
+  background.Start();
+  ASSERT_DEATH(background.DeRef(&arrow), "");
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+
+  // Main thread creates an arrow referencing the Target.
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+
+  // Background thread tries to deref target, binding it to the thread.
+  BackgroundThread background;
+  background.Start();
+  background.DeRef(&arrow);
+
+  // Main thread deletes Target, violating thread binding.
+  ASSERT_DEATH(target.reset(), "");
+
+  // |target.reset()| died so |target| still holds the object, so we
+  // must pass it to the background thread to teardown.
+  background.DeleteTarget(target.release());
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+
+  // Main thread creates an arrow referencing the Target, and references it, so
+  // that it becomes bound to the thread.
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+  arrow.target.get();
+
+  // Background thread tries to delete target, volating thread binding.
+  BackgroundThread background;
+  background.Start();
+  ASSERT_DEATH(background.DeleteTarget(target.release()), "");
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+
+  // Main thread creates an arrow referencing the Target.
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+
+  // Background thread tries to delete target, binding the object to the thread.
+  BackgroundThread background;
+  background.Start();
+  background.DeleteTarget(target.release());
+
+  // Main thread attempts to dereference the target, violating thread binding.
+  ASSERT_DEATH(arrow.target.get(), "");
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc
new file mode 100644
index 0000000..2ab428d
--- /dev/null
+++ b/base/memory/weak_ptr_unittest.nc
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+
+struct Producer : SupportsWeakPtr<Producer> {};
+struct DerivedProducer : Producer {};
+struct OtherDerivedProducer : Producer {};
+struct MultiplyDerivedProducer : Producer,
+                                 SupportsWeakPtr<MultiplyDerivedProducer> {};
+struct Unrelated {};
+struct DerivedUnrelated : Unrelated {};
+
+#if defined(NCTEST_AUTO_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer> derived_ptr = ptr;
+}
+
+#elif defined(NCTEST_STATIC_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer> derived_ptr =
+      static_cast<WeakPtr<DerivedProducer> >(ptr);
+}
+
+#elif defined(NCTEST_AUTO_REF_DOWNCAST)  // [r"fatal error: non-const lvalue reference to type 'WeakPtr<base::DerivedProducer>' cannot bind to a value of unrelated type 'WeakPtr<base::Producer>'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer>& derived_ptr = ptr;
+}
+
+#elif defined(NCTEST_STATIC_REF_DOWNCAST)  // [r"fatal error: non-const lvalue reference to type 'WeakPtr<base::DerivedProducer>' cannot bind to a value of unrelated type 'WeakPtr<base::Producer>'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer>& derived_ptr =
+      static_cast<WeakPtr<DerivedProducer>&>(ptr);
+}
+
+#elif defined(NCTEST_STATIC_ASWEAKPTR_DOWNCAST)  // [r"no matching function"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<DerivedProducer> ptr =
+      SupportsWeakPtr<Producer>::StaticAsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_HELPER_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_DOWNCAST)  // [r"no matching function"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_WRONG_INSANTIATED_HELPER_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f; 
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr<Producer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_HELPER_CAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::OtherDerivedProducer \*' with an lvalue of type 'base::DerivedProducer \*const'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_SIDECAST)  // [r"fatal error: no matching function for call to 'AsWeakPtr'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<OtherDerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::OtherDerivedProducer \*' with an lvalue of type 'base::DerivedProducer \*const'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNRELATED_HELPER)  // [r"fatal error: cannot initialize a member subobject of type 'base::Unrelated \*' with an lvalue of type 'base::DerivedProducer \*const'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNRELATED_INSTANTIATED_HELPER)  // [r"no matching function"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr<Unrelated>(&f);
+}
+
+#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER)  // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+
+void WontCompile() {
+  Unrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER)  // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+
+void WontCompile() {
+  DerivedUnrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_AMBIGUOUS_ANCESTORS)  // [r"fatal error: ambiguous conversion from derived class 'base::MultiplyDerivedProducer' to base class 'base::internal::SupportsWeakPtrBase':"]
+
+void WontCompile() {
+  MultiplyDerivedProducer f;
+  WeakPtr<MultiplyDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#endif
+
+}
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
new file mode 100644
index 0000000..c1ce939
--- /dev/null
+++ b/base/message_loop/incoming_task_queue.cc
@@ -0,0 +1,166 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/incoming_task_queue.h"
+
+#include <limits>
+
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+#ifndef NDEBUG
+// Delays larger than this are often bogus, and a warning should be emitted in
+// debug builds to warn developers.  http://crbug.com/450045
+const int kTaskDelayWarningThresholdInSeconds =
+    14 * 24 * 60 * 60;  // 14 days.
+#endif
+
+// Returns true if MessagePump::ScheduleWork() must be called one
+// time for every task that is added to the MessageLoop incoming queue.
+bool AlwaysNotifyPump(MessageLoop::Type type) {
+#if defined(OS_ANDROID)
+  // The Android UI message loop needs to get notified each time a task is
+  // added
+  // to the incoming queue.
+  return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
+#else
+  return false;
+#endif
+}
+
+}  // namespace
+
+IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
+    : high_res_task_count_(0),
+      message_loop_(message_loop),
+      next_sequence_num_(0),
+      message_loop_scheduled_(false),
+      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {
+}
+
+bool IncomingTaskQueue::AddToIncomingQueue(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay,
+    bool nestable) {
+  DLOG_IF(WARNING,
+          delay.InSeconds() > kTaskDelayWarningThresholdInSeconds)
+      << "Requesting super-long task delay period of " << delay.InSeconds()
+      << " seconds from here: " << from_here.ToString();
+
+  AutoLock locked(incoming_queue_lock_);
+  PendingTask pending_task(
+      from_here, task, CalculateDelayedRuntime(delay), nestable);
+#if defined(OS_WIN)
+  // We consider the task needs a high resolution timer if the delay is
+  // more than 0 and less than 32ms. This caps the relative error to
+  // less than 50% : a 33ms wait can wake at 48ms since the default
+  // resolution on Windows is between 10 and 15ms.
+  if (delay > TimeDelta() &&
+      delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) {
+    ++high_res_task_count_;
+    pending_task.is_high_res = true;
+  }
+#endif
+  return PostPendingTask(&pending_task);
+}
+
+bool IncomingTaskQueue::HasHighResolutionTasks() {
+  AutoLock lock(incoming_queue_lock_);
+  return high_res_task_count_ > 0;
+}
+
+bool IncomingTaskQueue::IsIdleForTesting() {
+  AutoLock lock(incoming_queue_lock_);
+  return incoming_queue_.empty();
+}
+
+int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
+  // Make sure no tasks are lost.
+  DCHECK(work_queue->empty());
+
+  // Acquire all we can from the inter-thread queue with one lock acquisition.
+  AutoLock lock(incoming_queue_lock_);
+  if (incoming_queue_.empty()) {
+    // If the loop attempts to reload but there are no tasks in the incoming
+    // queue, that means it will go to sleep waiting for more work. If the
+    // incoming queue becomes nonempty we need to schedule it again.
+    message_loop_scheduled_ = false;
+  } else {
+    incoming_queue_.Swap(work_queue);
+  }
+  // Reset the count of high resolution tasks since our queue is now empty.
+  int high_res_tasks = high_res_task_count_;
+  high_res_task_count_ = 0;
+  return high_res_tasks;
+}
+
+void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
+  AutoLock lock(incoming_queue_lock_);
+  message_loop_ = NULL;
+}
+
+IncomingTaskQueue::~IncomingTaskQueue() {
+  // Verify that WillDestroyCurrentMessageLoop() has been called.
+  DCHECK(!message_loop_);
+}
+
+TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
+  TimeTicks delayed_run_time;
+  if (delay > TimeDelta())
+    delayed_run_time = TimeTicks::Now() + delay;
+  else
+    DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
+  return delayed_run_time;
+}
+
+bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
+  // Warning: Don't try to short-circuit, and handle this thread's tasks more
+  // directly, as it could starve handling of foreign threads.  Put every task
+  // into this queue.
+
+  // This should only be called while the lock is taken.
+  incoming_queue_lock_.AssertAcquired();
+
+  if (!message_loop_) {
+    pending_task->task.Reset();
+    return false;
+  }
+
+  // Initialize the sequence number. The sequence number is used for delayed
+  // tasks (to faciliate FIFO sorting when two tasks have the same
+  // delayed_run_time value) and for identifying the task in about:tracing.
+  pending_task->sequence_num = next_sequence_num_++;
+
+  message_loop_->task_annotator()->DidQueueTask("MessageLoop::PostTask",
+                                                *pending_task);
+
+  bool was_empty = incoming_queue_.empty();
+  incoming_queue_.push(*pending_task);
+  pending_task->task.Reset();
+
+  if (always_schedule_work_ || (!message_loop_scheduled_ && was_empty)) {
+    // Wake up the message loop.
+    message_loop_->ScheduleWork();
+    // After we've scheduled the message loop, we do not need to do so again
+    // until we know it has processed all of the work in our queue and is
+    // waiting for more work again. The message loop will always attempt to
+    // reload from the incoming queue before waiting again so we clear this flag
+    // in ReloadWorkQueue().
+    message_loop_scheduled_ = true;
+  }
+
+  return true;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
new file mode 100644
index 0000000..72e1f30
--- /dev/null
+++ b/base/message_loop/incoming_task_queue.h
@@ -0,0 +1,101 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
+#define BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class MessageLoop;
+class WaitableEvent;
+
+namespace internal {
+
+// Implements a queue of tasks posted to the message loop running on the current
+// thread. This class takes care of synchronizing posting tasks from different
+// threads and together with MessageLoop ensures clean shutdown.
+class BASE_EXPORT IncomingTaskQueue
+    : public RefCountedThreadSafe<IncomingTaskQueue> {
+ public:
+  explicit IncomingTaskQueue(MessageLoop* message_loop);
+
+  // Appends a task to the incoming queue. Posting of all tasks is routed though
+  // AddToIncomingQueue() or TryAddToIncomingQueue() to make sure that posting
+  // task is properly synchronized between different threads.
+  //
+  // Returns true if the task was successfully added to the queue, otherwise
+  // returns false. In all cases, the ownership of |task| is transferred to the
+  // called method.
+  bool AddToIncomingQueue(const tracked_objects::Location& from_here,
+                          const Closure& task,
+                          TimeDelta delay,
+                          bool nestable);
+
+  // Returns true if the queue contains tasks that require higher than default
+  // timer resolution. Currently only needed for Windows.
+  bool HasHighResolutionTasks();
+
+  // Returns true if the message loop is "idle". Provided for testing.
+  bool IsIdleForTesting();
+
+  // Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called
+  // from the thread that is running the loop. Returns the number of tasks that
+  // require high resolution timers.
+  int ReloadWorkQueue(TaskQueue* work_queue);
+
+  // Disconnects |this| from the parent message loop.
+  void WillDestroyCurrentMessageLoop();
+
+ private:
+  friend class RefCountedThreadSafe<IncomingTaskQueue>;
+  virtual ~IncomingTaskQueue();
+
+  // Calculates the time at which a PendingTask should run.
+  TimeTicks CalculateDelayedRuntime(TimeDelta delay);
+
+  // Adds a task to |incoming_queue_|. The caller retains ownership of
+  // |pending_task|, but this function will reset the value of
+  // |pending_task->task|. This is needed to ensure that the posting call stack
+  // does not retain |pending_task->task| beyond this function call.
+  bool PostPendingTask(PendingTask* pending_task);
+
+  // Number of tasks that require high resolution timing. This value is kept
+  // so that ReloadWorkQueue() completes in constant time.
+  int high_res_task_count_;
+
+  // The lock that protects access to the members of this class.
+  base::Lock incoming_queue_lock_;
+
+  // An incoming queue of tasks that are acquired under a mutex for processing
+  // on this instance's thread. These tasks have not yet been been pushed to
+  // |message_loop_|.
+  TaskQueue incoming_queue_;
+
+  // Points to the message loop that owns |this|.
+  MessageLoop* message_loop_;
+
+  // The next sequence number to use for delayed tasks.
+  int next_sequence_num_;
+
+  // True if our message loop has already been scheduled and does not need to be
+  // scheduled again until an empty reload occurs.
+  bool message_loop_scheduled_;
+
+  // True if we always need to call ScheduleWork when receiving a new task, even
+  // if the incoming queue was not empty.
+  const bool always_schedule_work_;
+
+  DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
new file mode 100644
index 0000000..eb0f968
--- /dev/null
+++ b/base/message_loop/message_loop.cc
@@ -0,0 +1,720 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump_default.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/run_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_local.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include "base/message_loop/message_pump_mac.h"
+#endif
+#if defined(OS_POSIX) && !defined(OS_IOS)
+#include "base/message_loop/message_pump_libevent.h"
+#endif
+#if defined(OS_ANDROID)
+#include "base/message_loop/message_pump_android.h"
+#endif
+#if defined(USE_GLIB)
+#include "base/message_loop/message_pump_glib.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// A lazily created thread local storage for quick access to a thread's message
+// loop, if one exists.  This should be safe and free of static constructors.
+LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
+    LAZY_INSTANCE_INITIALIZER;
+
+// Logical events for Histogram profiling. Run with -message-loop-histogrammer
+// to get an accounting of messages and actions taken on each thread.
+const int kTaskRunEvent = 0x1;
+#if !defined(OS_NACL)
+const int kTimerEvent = 0x2;
+
+// Provide range of message IDs for use in histogramming and debug display.
+const int kLeastNonZeroMessageId = 1;
+const int kMaxMessageId = 1099;
+const int kNumberOfDistinctMessagesDisplayed = 1100;
+
+// Provide a macro that takes an expression (such as a constant, or macro
+// constant) and creates a pair to initalize an array of pairs.  In this case,
+// our pair consists of the expressions value, and the "stringized" version
+// of the expression (i.e., the exrpression put in quotes).  For example, if
+// we have:
+//    #define FOO 2
+//    #define BAR 5
+// then the following:
+//    VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
+// will expand to:
+//   {7, "FOO + BAR"}
+// We use the resulting array as an argument to our histogram, which reads the
+// number as a bucket identifier, and proceeds to use the corresponding name
+// in the pair (i.e., the quoted string) when printing out a histogram.
+#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
+
+const LinearHistogram::DescriptionPair event_descriptions_[] = {
+  // Provide some pretty print capability in our histogram for our internal
+  // messages.
+
+  // A few events we handle (kindred to messages), and used to profile actions.
+  VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
+  VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
+
+  {-1, NULL}  // The list must be null terminated, per API to histogram.
+};
+#endif  // !defined(OS_NACL)
+
+bool enable_histogrammer_ = false;
+
+MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
+
+#if defined(OS_IOS)
+typedef MessagePumpIOSForIO MessagePumpForIO;
+#elif defined(OS_NACL_SFI)
+typedef MessagePumpDefault MessagePumpForIO;
+#elif defined(OS_POSIX)
+typedef MessagePumpLibevent MessagePumpForIO;
+#endif
+
+#if !defined(OS_NACL_SFI)
+MessagePumpForIO* ToPumpIO(MessagePump* pump) {
+  return static_cast<MessagePumpForIO*>(pump);
+}
+#endif  // !defined(OS_NACL_SFI)
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+
+MessageLoop::TaskObserver::TaskObserver() {
+}
+
+MessageLoop::TaskObserver::~TaskObserver() {
+}
+
+MessageLoop::DestructionObserver::~DestructionObserver() {
+}
+
+//------------------------------------------------------------------------------
+
+MessageLoop::MessageLoop(Type type)
+    : type_(type),
+#if defined(OS_WIN)
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
+#endif
+      nestable_tasks_allowed_(true),
+#if defined(OS_WIN)
+      os_modal_loop_(false),
+#endif  // OS_WIN
+      message_histogram_(NULL),
+      run_loop_(NULL) {
+  Init();
+
+  pump_ = CreateMessagePumpForType(type).Pass();
+}
+
+MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
+    : pump_(pump.Pass()),
+      type_(TYPE_CUSTOM),
+#if defined(OS_WIN)
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
+#endif
+      nestable_tasks_allowed_(true),
+#if defined(OS_WIN)
+      os_modal_loop_(false),
+#endif  // OS_WIN
+      message_histogram_(NULL),
+      run_loop_(NULL) {
+  DCHECK(pump_.get());
+  Init();
+}
+
+MessageLoop::~MessageLoop() {
+  DCHECK_EQ(this, current());
+
+  // iOS just attaches to the loop, it doesn't Run it.
+  // TODO(stuartmorgan): Consider wiring up a Detach().
+#if !defined(OS_IOS)
+  DCHECK(!run_loop_);
+#endif
+
+#if defined(OS_WIN)
+  if (in_high_res_mode_)
+    Time::ActivateHighResolutionTimer(false);
+#endif
+  // Clean up any unprocessed tasks, but take care: deleting a task could
+  // result in the addition of more tasks (e.g., via DeleteSoon).  We set a
+  // limit on the number of times we will allow a deleted task to generate more
+  // tasks.  Normally, we should only pass through this loop once or twice.  If
+  // we end up hitting the loop limit, then it is probably due to one task that
+  // is being stubborn.  Inspect the queues to see who is left.
+  bool did_work;
+  for (int i = 0; i < 100; ++i) {
+    DeletePendingTasks();
+    ReloadWorkQueue();
+    // If we end up with empty queues, then break out of the loop.
+    did_work = DeletePendingTasks();
+    if (!did_work)
+      break;
+  }
+  DCHECK(!did_work);
+
+  // Let interested parties have one last shot at accessing this.
+  FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
+                    WillDestroyCurrentMessageLoop());
+
+  thread_task_runner_handle_.reset();
+
+  // Tell the incoming queue that we are dying.
+  incoming_task_queue_->WillDestroyCurrentMessageLoop();
+  incoming_task_queue_ = NULL;
+  message_loop_proxy_ = NULL;
+
+  // OK, now make it so that no one can find us.
+  lazy_tls_ptr.Pointer()->Set(NULL);
+}
+
+// static
+MessageLoop* MessageLoop::current() {
+  // TODO(darin): sadly, we cannot enable this yet since people call us even
+  // when they have no intention of using us.
+  // DCHECK(loop) << "Ouch, did you forget to initialize me?";
+  return lazy_tls_ptr.Pointer()->Get();
+}
+
+// static
+void MessageLoop::EnableHistogrammer(bool enable) {
+  enable_histogrammer_ = enable;
+}
+
+// static
+bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
+  if (message_pump_for_ui_factory_)
+    return false;
+
+  message_pump_for_ui_factory_ = factory;
+  return true;
+}
+
+// static
+scoped_ptr<MessagePump> MessageLoop::CreateMessagePumpForType(Type type) {
+// TODO(rvargas): Get rid of the OS guards.
+#if defined(USE_GLIB) && !defined(OS_NACL)
+  typedef MessagePumpGlib MessagePumpForUI;
+#elif defined(OS_LINUX) && !defined(OS_NACL)
+  typedef MessagePumpLibevent MessagePumpForUI;
+#endif
+
+#if defined(OS_IOS) || defined(OS_MACOSX)
+#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(MessagePumpMac::Create())
+#elif defined(OS_NACL)
+// Currently NaCl doesn't have a UI MessageLoop.
+// TODO(abarth): Figure out if we need this.
+#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>()
+#else
+#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(new MessagePumpForUI())
+#endif
+
+#if defined(OS_MACOSX)
+  // Use an OS native runloop on Mac to support timer coalescing.
+  #define MESSAGE_PUMP_DEFAULT \
+      scoped_ptr<MessagePump>(new MessagePumpCFRunLoop())
+#else
+  #define MESSAGE_PUMP_DEFAULT scoped_ptr<MessagePump>(new MessagePumpDefault())
+#endif
+
+  if (type == MessageLoop::TYPE_UI) {
+    if (message_pump_for_ui_factory_)
+      return message_pump_for_ui_factory_();
+    return MESSAGE_PUMP_UI;
+  }
+  if (type == MessageLoop::TYPE_IO)
+    return scoped_ptr<MessagePump>(new MessagePumpForIO());
+
+#if defined(OS_ANDROID)
+  if (type == MessageLoop::TYPE_JAVA)
+    return scoped_ptr<MessagePump>(new MessagePumpForUI());
+#endif
+
+  DCHECK_EQ(MessageLoop::TYPE_DEFAULT, type);
+  return MESSAGE_PUMP_DEFAULT;
+}
+
+void MessageLoop::AddDestructionObserver(
+    DestructionObserver* destruction_observer) {
+  DCHECK_EQ(this, current());
+  destruction_observers_.AddObserver(destruction_observer);
+}
+
+void MessageLoop::RemoveDestructionObserver(
+    DestructionObserver* destruction_observer) {
+  DCHECK_EQ(this, current());
+  destruction_observers_.RemoveObserver(destruction_observer);
+}
+
+void MessageLoop::PostTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  message_loop_proxy_->PostTask(from_here, task);
+}
+
+void MessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  message_loop_proxy_->PostDelayedTask(from_here, task, delay);
+}
+
+void MessageLoop::PostNonNestableTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  message_loop_proxy_->PostNonNestableTask(from_here, task);
+}
+
+void MessageLoop::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  message_loop_proxy_->PostNonNestableDelayedTask(from_here, task, delay);
+}
+
+void MessageLoop::Run() {
+  RunLoop run_loop;
+  run_loop.Run();
+}
+
+void MessageLoop::RunUntilIdle() {
+  RunLoop run_loop;
+  run_loop.RunUntilIdle();
+}
+
+void MessageLoop::QuitWhenIdle() {
+  DCHECK_EQ(this, current());
+  if (run_loop_) {
+    run_loop_->quit_when_idle_received_ = true;
+  } else {
+    NOTREACHED() << "Must be inside Run to call Quit";
+  }
+}
+
+void MessageLoop::QuitNow() {
+  DCHECK_EQ(this, current());
+  if (run_loop_) {
+    pump_->Quit();
+  } else {
+    NOTREACHED() << "Must be inside Run to call Quit";
+  }
+}
+
+bool MessageLoop::IsType(Type type) const {
+  return type_ == type;
+}
+
+static void QuitCurrentWhenIdle() {
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+// static
+Closure MessageLoop::QuitWhenIdleClosure() {
+  return Bind(&QuitCurrentWhenIdle);
+}
+
+void MessageLoop::SetNestableTasksAllowed(bool allowed) {
+  if (allowed) {
+    // Kick the native pump just in case we enter a OS-driven nested message
+    // loop.
+    pump_->ScheduleWork();
+  }
+  nestable_tasks_allowed_ = allowed;
+}
+
+bool MessageLoop::NestableTasksAllowed() const {
+  return nestable_tasks_allowed_;
+}
+
+bool MessageLoop::IsNested() {
+  return run_loop_->run_depth_ > 1;
+}
+
+void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
+  DCHECK_EQ(this, current());
+  task_observers_.AddObserver(task_observer);
+}
+
+void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
+  DCHECK_EQ(this, current());
+  task_observers_.RemoveObserver(task_observer);
+}
+
+bool MessageLoop::is_running() const {
+  DCHECK_EQ(this, current());
+  return run_loop_ != NULL;
+}
+
+bool MessageLoop::HasHighResolutionTasks() {
+  return incoming_task_queue_->HasHighResolutionTasks();
+}
+
+bool MessageLoop::IsIdleForTesting() {
+  // We only check the imcoming queue|, since we don't want to lock the work
+  // queue.
+  return incoming_task_queue_->IsIdleForTesting();
+}
+
+//------------------------------------------------------------------------------
+
+void MessageLoop::Init() {
+  DCHECK(!current()) << "should only have one message loop per thread";
+  lazy_tls_ptr.Pointer()->Set(this);
+
+  incoming_task_queue_ = new internal::IncomingTaskQueue(this);
+  message_loop_proxy_ =
+      new internal::MessageLoopProxyImpl(incoming_task_queue_);
+  thread_task_runner_handle_.reset(
+      new ThreadTaskRunnerHandle(message_loop_proxy_));
+}
+
+void MessageLoop::RunHandler() {
+  DCHECK_EQ(this, current());
+
+  StartHistogrammer();
+
+#if defined(OS_WIN)
+  if (run_loop_->dispatcher_ && type() == TYPE_UI) {
+    static_cast<MessagePumpForUI*>(pump_.get())->
+        RunWithDispatcher(this, run_loop_->dispatcher_);
+    return;
+  }
+#endif
+
+  pump_->Run(this);
+}
+
+bool MessageLoop::ProcessNextDelayedNonNestableTask() {
+  if (run_loop_->run_depth_ != 1)
+    return false;
+
+  if (deferred_non_nestable_work_queue_.empty())
+    return false;
+
+  PendingTask pending_task = deferred_non_nestable_work_queue_.front();
+  deferred_non_nestable_work_queue_.pop();
+
+  RunTask(pending_task);
+  return true;
+}
+
+void MessageLoop::RunTask(const PendingTask& pending_task) {
+  DCHECK(nestable_tasks_allowed_);
+
+#if defined(OS_WIN)
+  if (pending_task.is_high_res) {
+    pending_high_res_tasks_--;
+    CHECK_GE(pending_high_res_tasks_, 0);
+  }
+#endif
+
+  // Execute the task and assume the worst: It is probably not reentrant.
+  nestable_tasks_allowed_ = false;
+
+  HistogramEvent(kTaskRunEvent);
+
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    WillProcessTask(pending_task));
+  task_annotator_.RunTask(
+      "MessageLoop::PostTask", "MessageLoop::RunTask", pending_task);
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    DidProcessTask(pending_task));
+
+  nestable_tasks_allowed_ = true;
+}
+
+bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
+  if (pending_task.nestable || run_loop_->run_depth_ == 1) {
+    RunTask(pending_task);
+    // Show that we ran a task (Note: a new one might arrive as a
+    // consequence!).
+    return true;
+  }
+
+  // We couldn't run the task now because we're in a nested message loop
+  // and the task isn't nestable.
+  deferred_non_nestable_work_queue_.push(pending_task);
+  return false;
+}
+
+void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
+  // Move to the delayed work queue.
+  delayed_work_queue_.push(pending_task);
+}
+
+bool MessageLoop::DeletePendingTasks() {
+  bool did_work = !work_queue_.empty();
+  while (!work_queue_.empty()) {
+    PendingTask pending_task = work_queue_.front();
+    work_queue_.pop();
+    if (!pending_task.delayed_run_time.is_null()) {
+      // We want to delete delayed tasks in the same order in which they would
+      // normally be deleted in case of any funny dependencies between delayed
+      // tasks.
+      AddToDelayedWorkQueue(pending_task);
+    }
+  }
+  did_work |= !deferred_non_nestable_work_queue_.empty();
+  while (!deferred_non_nestable_work_queue_.empty()) {
+    deferred_non_nestable_work_queue_.pop();
+  }
+  did_work |= !delayed_work_queue_.empty();
+
+  // Historically, we always delete the task regardless of valgrind status. It's
+  // not completely clear why we want to leak them in the loops above.  This
+  // code is replicating legacy behavior, and should not be considered
+  // absolutely "correct" behavior.  See TODO above about deleting all tasks
+  // when it's safe.
+  while (!delayed_work_queue_.empty()) {
+    delayed_work_queue_.pop();
+  }
+  return did_work;
+}
+
+void MessageLoop::ReloadWorkQueue() {
+  // We can improve performance of our loading tasks from the incoming queue to
+  // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to
+  // load. That reduces the number of locks-per-task significantly when our
+  // queues get large.
+  if (work_queue_.empty()) {
+#if defined(OS_WIN)
+    pending_high_res_tasks_ +=
+        incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+#else
+    incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+#endif
+  }
+}
+
+void MessageLoop::ScheduleWork() {
+  pump_->ScheduleWork();
+}
+
+//------------------------------------------------------------------------------
+// Method and data for histogramming events and actions taken by each instance
+// on each thread.
+
+void MessageLoop::StartHistogrammer() {
+#if !defined(OS_NACL)  // NaCl build has no metrics code.
+  if (enable_histogrammer_ && !message_histogram_
+      && StatisticsRecorder::IsActive()) {
+    DCHECK(!thread_name_.empty());
+    message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription(
+        "MsgLoop:" + thread_name_,
+        kLeastNonZeroMessageId, kMaxMessageId,
+        kNumberOfDistinctMessagesDisplayed,
+        message_histogram_->kHexRangePrintingFlag,
+        event_descriptions_);
+  }
+#endif
+}
+
+void MessageLoop::HistogramEvent(int event) {
+#if !defined(OS_NACL)
+  if (message_histogram_)
+    message_histogram_->Add(event);
+#endif
+}
+
+bool MessageLoop::DoWork() {
+  if (!nestable_tasks_allowed_) {
+    // Task can't be executed right now.
+    return false;
+  }
+
+  for (;;) {
+    ReloadWorkQueue();
+    if (work_queue_.empty())
+      break;
+
+    // Execute oldest task.
+    do {
+      PendingTask pending_task = work_queue_.front();
+      work_queue_.pop();
+      if (!pending_task.delayed_run_time.is_null()) {
+        AddToDelayedWorkQueue(pending_task);
+        // If we changed the topmost task, then it is time to reschedule.
+        if (delayed_work_queue_.top().task.Equals(pending_task.task))
+          pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
+      } else {
+        if (DeferOrRunPendingTask(pending_task))
+          return true;
+      }
+    } while (!work_queue_.empty());
+  }
+
+  // Nothing happened.
+  return false;
+}
+
+bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
+  if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
+    recent_time_ = *next_delayed_work_time = TimeTicks();
+    return false;
+  }
+
+  // When we "fall behind," there will be a lot of tasks in the delayed work
+  // queue that are ready to run.  To increase efficiency when we fall behind,
+  // we will only call Time::Now() intermittently, and then process all tasks
+  // that are ready to run before calling it again.  As a result, the more we
+  // fall behind (and have a lot of ready-to-run delayed tasks), the more
+  // efficient we'll be at handling the tasks.
+
+  TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
+  if (next_run_time > recent_time_) {
+    recent_time_ = TimeTicks::Now();  // Get a better view of Now();
+    if (next_run_time > recent_time_) {
+      *next_delayed_work_time = next_run_time;
+      return false;
+    }
+  }
+
+  PendingTask pending_task = delayed_work_queue_.top();
+  delayed_work_queue_.pop();
+
+  if (!delayed_work_queue_.empty())
+    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
+
+  return DeferOrRunPendingTask(pending_task);
+}
+
+bool MessageLoop::DoIdleWork() {
+  if (ProcessNextDelayedNonNestableTask())
+    return true;
+
+  if (run_loop_->quit_when_idle_received_)
+    pump_->Quit();
+
+  // When we return we will do a kernel wait for more tasks.
+#if defined(OS_WIN)
+  // On Windows we activate the high resolution timer so that the wait
+  // _if_ triggered by the timer happens with good resolution. If we don't
+  // do this the default resolution is 15ms which might not be acceptable
+  // for some tasks.
+  bool high_res = pending_high_res_tasks_ > 0;
+  if (high_res != in_high_res_mode_) {
+    in_high_res_mode_ = high_res;
+    Time::ActivateHighResolutionTimer(in_high_res_mode_);
+  }
+#endif
+  return false;
+}
+
+void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
+                                     void(*deleter)(const void*),
+                                     const void* object) {
+  PostNonNestableTask(from_here, Bind(deleter, object));
+}
+
+void MessageLoop::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  PostNonNestableTask(from_here, Bind(releaser, object));
+}
+
+#if !defined(OS_NACL)
+//------------------------------------------------------------------------------
+// MessageLoopForUI
+
+#if defined(OS_ANDROID)
+void MessageLoopForUI::Start() {
+  // No Histogram support for UI message loop as it is managed by Java side
+  static_cast<MessagePumpForUI*>(pump_.get())->Start(this);
+}
+#endif
+
+#if defined(OS_IOS)
+void MessageLoopForUI::Attach() {
+  static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this);
+}
+#endif
+
+#if defined(USE_OZONE) || (defined(USE_X11) && !defined(USE_GLIB))
+bool MessageLoopForUI::WatchFileDescriptor(
+    int fd,
+    bool persistent,
+    MessagePumpLibevent::Mode mode,
+    MessagePumpLibevent::FileDescriptorWatcher *controller,
+    MessagePumpLibevent::Watcher *delegate) {
+  return static_cast<MessagePumpLibevent*>(pump_.get())->WatchFileDescriptor(
+      fd,
+      persistent,
+      mode,
+      controller,
+      delegate);
+}
+#endif
+
+#endif  // !defined(OS_NACL)
+
+//------------------------------------------------------------------------------
+// MessageLoopForIO
+
+#if !defined(OS_NACL_SFI)
+void MessageLoopForIO::AddIOObserver(
+    MessageLoopForIO::IOObserver* io_observer) {
+  ToPumpIO(pump_.get())->AddIOObserver(io_observer);
+}
+
+void MessageLoopForIO::RemoveIOObserver(
+    MessageLoopForIO::IOObserver* io_observer) {
+  ToPumpIO(pump_.get())->RemoveIOObserver(io_observer);
+}
+
+#if defined(OS_WIN)
+void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
+  ToPumpIO(pump_.get())->RegisterIOHandler(file, handler);
+}
+
+bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) {
+  return ToPumpIO(pump_.get())->RegisterJobObject(job, handler);
+}
+
+bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+  return ToPumpIO(pump_.get())->WaitForIOCompletion(timeout, filter);
+}
+#elif defined(OS_POSIX)
+bool MessageLoopForIO::WatchFileDescriptor(int fd,
+                                           bool persistent,
+                                           Mode mode,
+                                           FileDescriptorWatcher* controller,
+                                           Watcher* delegate) {
+  return ToPumpIO(pump_.get())->WatchFileDescriptor(
+      fd,
+      persistent,
+      mode,
+      controller,
+      delegate);
+}
+#endif
+
+#endif  // !defined(OS_NACL_SFI)
+
+}  // namespace base
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
new file mode 100644
index 0000000..fd7596a
--- /dev/null
+++ b/base/message_loop/message_loop.h
@@ -0,0 +1,663 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
+
+#include <queue>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/debug/task_annotator.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/incoming_task_queue.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop_proxy_impl.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/observer_list.h"
+#include "base/pending_task.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/tracking_info.h"
+
+// TODO(sky): these includes should not be necessary. Nuke them.
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_win.h"
+#elif defined(OS_IOS)
+#include "base/message_loop/message_pump_io_ios.h"
+#elif defined(OS_POSIX)
+#include "base/message_loop/message_pump_libevent.h"
+#endif
+
+namespace base {
+
+class HistogramBase;
+class RunLoop;
+class ThreadTaskRunnerHandle;
+class WaitableEvent;
+
+// A MessageLoop is used to process events for a particular thread.  There is
+// at most one MessageLoop instance per thread.
+//
+// Events include at a minimum Task instances submitted to PostTask and its
+// variants.  Depending on the type of message pump used by the MessageLoop
+// other events such as UI messages may be processed.  On Windows APC calls (as
+// time permits) and signals sent to a registered set of HANDLEs may also be
+// processed.
+//
+// NOTE: Unless otherwise specified, a MessageLoop's methods may only be called
+// on the thread where the MessageLoop's Run method executes.
+//
+// NOTE: MessageLoop has task reentrancy protection.  This means that if a
+// task is being processed, a second task cannot start until the first task is
+// finished.  Reentrancy can happen when processing a task, and an inner
+// message pump is created.  That inner pump then processes native messages
+// which could implicitly start an inner task.  Inner message pumps are created
+// with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions
+// (DoDragDrop), printer functions (StartDoc) and *many* others.
+//
+// Sample workaround when inner task processing is needed:
+//   HRESULT hr;
+//   {
+//     MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+//     hr = DoDragDrop(...); // Implicitly runs a modal message loop.
+//   }
+//   // Process |hr| (the result returned by DoDragDrop()).
+//
+// Please be SURE your task is reentrant (nestable) and all global variables
+// are stable and accessible before calling SetNestableTasksAllowed(true).
+//
+class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
+ public:
+  // A MessageLoop has a particular type, which indicates the set of
+  // asynchronous events it may process in addition to tasks and timers.
+  //
+  // TYPE_DEFAULT
+  //   This type of ML only supports tasks and timers.
+  //
+  // TYPE_UI
+  //   This type of ML also supports native UI events (e.g., Windows messages).
+  //   See also MessageLoopForUI.
+  //
+  // TYPE_IO
+  //   This type of ML also supports asynchronous IO.  See also
+  //   MessageLoopForIO.
+  //
+  // TYPE_JAVA
+  //   This type of ML is backed by a Java message handler which is responsible
+  //   for running the tasks added to the ML. This is only for use on Android.
+  //   TYPE_JAVA behaves in essence like TYPE_UI, except during construction
+  //   where it does not use the main thread specific pump factory.
+  //
+  // TYPE_CUSTOM
+  //   MessagePump was supplied to constructor.
+  //
+  enum Type {
+    TYPE_DEFAULT,
+    TYPE_UI,
+    TYPE_CUSTOM,
+    TYPE_IO,
+#if defined(OS_ANDROID)
+    TYPE_JAVA,
+#endif  // defined(OS_ANDROID)
+  };
+
+  // Normally, it is not necessary to instantiate a MessageLoop.  Instead, it
+  // is typical to make use of the current thread's MessageLoop instance.
+  explicit MessageLoop(Type type = TYPE_DEFAULT);
+  // Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must
+  // be non-NULL.
+  explicit MessageLoop(scoped_ptr<base::MessagePump> pump);
+  ~MessageLoop() override;
+
+  // Returns the MessageLoop object for the current thread, or null if none.
+  static MessageLoop* current();
+
+  static void EnableHistogrammer(bool enable_histogrammer);
+
+  typedef scoped_ptr<MessagePump> (MessagePumpFactory)();
+  // Uses the given base::MessagePumpForUIFactory to override the default
+  // MessagePump implementation for 'TYPE_UI'. Returns true if the factory
+  // was successfully registered.
+  static bool InitMessagePumpForUIFactory(MessagePumpFactory* factory);
+
+  // Creates the default MessagePump based on |type|. Caller owns return
+  // value.
+  static scoped_ptr<MessagePump> CreateMessagePumpForType(Type type);
+  // A DestructionObserver is notified when the current MessageLoop is being
+  // destroyed.  These observers are notified prior to MessageLoop::current()
+  // being changed to return NULL.  This gives interested parties the chance to
+  // do final cleanup that depends on the MessageLoop.
+  //
+  // NOTE: Any tasks posted to the MessageLoop during this notification will
+  // not be run.  Instead, they will be deleted.
+  //
+  class BASE_EXPORT DestructionObserver {
+   public:
+    virtual void WillDestroyCurrentMessageLoop() = 0;
+
+   protected:
+    virtual ~DestructionObserver();
+  };
+
+  // Add a DestructionObserver, which will start receiving notifications
+  // immediately.
+  void AddDestructionObserver(DestructionObserver* destruction_observer);
+
+  // Remove a DestructionObserver.  It is safe to call this method while a
+  // DestructionObserver is receiving a notification callback.
+  void RemoveDestructionObserver(DestructionObserver* destruction_observer);
+
+  // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces.
+  // TODO(skyostil): Remove these functions (crbug.com/465354).
+  //
+  // The "PostTask" family of methods call the task's Run method asynchronously
+  // from within a message loop at some point in the future.
+  //
+  // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed
+  // with normal UI or IO event processing.  With the PostDelayedTask variant,
+  // tasks are called after at least approximately 'delay_ms' have elapsed.
+  //
+  // The NonNestable variants work similarly except that they promise never to
+  // dispatch the task from a nested invocation of MessageLoop::Run.  Instead,
+  // such tasks get deferred until the top-most MessageLoop::Run is executing.
+  //
+  // The MessageLoop takes ownership of the Task, and deletes it after it has
+  // been Run().
+  //
+  // PostTask(from_here, task) is equivalent to
+  // PostDelayedTask(from_here, task, 0).
+  //
+  // NOTE: These methods may be called on any thread.  The Task will be invoked
+  // on the thread that executes MessageLoop::Run().
+  void PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  void PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay);
+
+  void PostNonNestableTask(const tracked_objects::Location& from_here,
+                           const Closure& task);
+
+  void PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay);
+
+  // A variant on PostTask that deletes the given object.  This is useful
+  // if the object needs to live until the next run of the MessageLoop (for
+  // example, deleting a RenderProcessHost from within an IPC callback is not
+  // good).
+  //
+  // NOTE: This method may be called on any thread.  The object will be deleted
+  // on the thread that executes MessageLoop::Run().
+  template <class T>
+  void DeleteSoon(const tracked_objects::Location& from_here, const T* object) {
+    base::subtle::DeleteHelperInternal<T, void>::DeleteViaSequencedTaskRunner(
+        this, from_here, object);
+  }
+
+  // A variant on PostTask that releases the given reference counted object
+  // (by calling its Release method).  This is useful if the object needs to
+  // live until the next run of the MessageLoop, or if the object needs to be
+  // released on a particular thread.
+  //
+  // A common pattern is to manually increment the object's reference count
+  // (AddRef), clear the pointer, then issue a ReleaseSoon.  The reference count
+  // is incremented manually to ensure clearing the pointer does not trigger a
+  // delete and to account for the upcoming decrement (ReleaseSoon).  For
+  // example:
+  //
+  // scoped_refptr<Foo> foo = ...
+  // foo->AddRef();
+  // Foo* raw_foo = foo.get();
+  // foo = NULL;
+  // message_loop->ReleaseSoon(raw_foo);
+  //
+  // NOTE: This method may be called on any thread.  The object will be
+  // released (and thus possibly deleted) on the thread that executes
+  // MessageLoop::Run().  If this is not the same as the thread that calls
+  // ReleaseSoon(FROM_HERE, ), then T MUST inherit from
+  // RefCountedThreadSafe<T>!
+  template <class T>
+  void ReleaseSoon(const tracked_objects::Location& from_here,
+                   const T* object) {
+    base::subtle::ReleaseHelperInternal<T, void>::ReleaseViaSequencedTaskRunner(
+        this, from_here, object);
+  }
+
+  // Deprecated: use RunLoop instead.
+  // Run the message loop.
+  void Run();
+
+  // Deprecated: use RunLoop instead.
+  // Process all pending tasks, windows messages, etc., but don't wait/sleep.
+  // Return as soon as all items that can be run are taken care of.
+  void RunUntilIdle();
+
+  // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdle().
+  void Quit() { QuitWhenIdle(); }
+
+  // Deprecated: use RunLoop instead.
+  //
+  // Signals the Run method to return when it becomes idle. It will continue to
+  // process pending messages and future messages as long as they are enqueued.
+  // Warning: if the MessageLoop remains busy, it may never quit. Only use this
+  // Quit method when looping procedures (such as web pages) have been shut
+  // down.
+  //
+  // This method may only be called on the same thread that called Run, and Run
+  // must still be on the call stack.
+  //
+  // Use QuitClosure variants if you need to Quit another thread's MessageLoop,
+  // but note that doing so is fairly dangerous if the target thread makes
+  // nested calls to MessageLoop::Run.  The problem being that you won't know
+  // which nested run loop you are quitting, so be careful!
+  void QuitWhenIdle();
+
+  // Deprecated: use RunLoop instead.
+  //
+  // This method is a variant of Quit, that does not wait for pending messages
+  // to be processed before returning from Run.
+  void QuitNow();
+
+  // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdleClosure().
+  static Closure QuitClosure() { return QuitWhenIdleClosure(); }
+
+  // Deprecated: use RunLoop instead.
+  // Construct a Closure that will call QuitWhenIdle(). Useful to schedule an
+  // arbitrary MessageLoop to QuitWhenIdle.
+  static Closure QuitWhenIdleClosure();
+
+  // Set the timer slack for this message loop.
+  void SetTimerSlack(TimerSlack timer_slack) {
+    pump_->SetTimerSlack(timer_slack);
+  }
+
+  // Returns true if this loop is |type|. This allows subclasses (especially
+  // those in tests) to specialize how they are identified.
+  virtual bool IsType(Type type) const;
+
+  // Returns the type passed to the constructor.
+  Type type() const { return type_; }
+
+  // Optional call to connect the thread name with this loop.
+  void set_thread_name(const std::string& thread_name) {
+    DCHECK(thread_name_.empty()) << "Should not rename this thread!";
+    thread_name_ = thread_name;
+  }
+  const std::string& thread_name() const { return thread_name_; }
+
+  // Gets the message loop proxy associated with this message loop.
+  //
+  // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces
+  scoped_refptr<MessageLoopProxy> message_loop_proxy() {
+    return message_loop_proxy_;
+  }
+
+  // Gets the TaskRunner associated with this message loop.
+  // TODO(skyostil): Change this to return a const reference to a refptr
+  // once the internal type matches what is being returned (crbug.com/465354).
+  scoped_refptr<SingleThreadTaskRunner> task_runner() {
+    return message_loop_proxy_;
+  }
+
+  // Enables or disables the recursive task processing. This happens in the case
+  // of recursive message loops. Some unwanted message loop may occurs when
+  // using common controls or printer functions. By default, recursive task
+  // processing is disabled.
+  //
+  // Please utilize |ScopedNestableTaskAllower| instead of calling these methods
+  // directly.  In general nestable message loops are to be avoided.  They are
+  // dangerous and difficult to get right, so please use with extreme caution.
+  //
+  // The specific case where tasks get queued is:
+  // - The thread is running a message loop.
+  // - It receives a task #1 and execute it.
+  // - The task #1 implicitly start a message loop, like a MessageBox in the
+  //   unit test. This can also be StartDoc or GetSaveFileName.
+  // - The thread receives a task #2 before or while in this second message
+  //   loop.
+  // - With NestableTasksAllowed set to true, the task #2 will run right away.
+  //   Otherwise, it will get executed right after task #1 completes at "thread
+  //   message loop level".
+  void SetNestableTasksAllowed(bool allowed);
+  bool NestableTasksAllowed() const;
+
+  // Enables nestable tasks on |loop| while in scope.
+  class ScopedNestableTaskAllower {
+   public:
+    explicit ScopedNestableTaskAllower(MessageLoop* loop)
+        : loop_(loop),
+          old_state_(loop_->NestableTasksAllowed()) {
+      loop_->SetNestableTasksAllowed(true);
+    }
+    ~ScopedNestableTaskAllower() {
+      loop_->SetNestableTasksAllowed(old_state_);
+    }
+
+   private:
+    MessageLoop* loop_;
+    bool old_state_;
+  };
+
+  // Returns true if we are currently running a nested message loop.
+  bool IsNested();
+
+  // A TaskObserver is an object that receives task notifications from the
+  // MessageLoop.
+  //
+  // NOTE: A TaskObserver implementation should be extremely fast!
+  class BASE_EXPORT TaskObserver {
+   public:
+    TaskObserver();
+
+    // This method is called before processing a task.
+    virtual void WillProcessTask(const PendingTask& pending_task) = 0;
+
+    // This method is called after processing a task.
+    virtual void DidProcessTask(const PendingTask& pending_task) = 0;
+
+   protected:
+    virtual ~TaskObserver();
+  };
+
+  // These functions can only be called on the same thread that |this| is
+  // running on.
+  void AddTaskObserver(TaskObserver* task_observer);
+  void RemoveTaskObserver(TaskObserver* task_observer);
+
+#if defined(OS_WIN)
+  void set_os_modal_loop(bool os_modal_loop) {
+    os_modal_loop_ = os_modal_loop;
+  }
+
+  bool os_modal_loop() const {
+    return os_modal_loop_;
+  }
+#endif  // OS_WIN
+
+  // Can only be called from the thread that owns the MessageLoop.
+  bool is_running() const;
+
+  // Returns true if the message loop has high resolution timers enabled.
+  // Provided for testing.
+  bool HasHighResolutionTasks();
+
+  // Returns true if the message loop is "idle". Provided for testing.
+  bool IsIdleForTesting();
+
+  // Wakes up the message pump. Can be called on any thread. The caller is
+  // responsible for synchronizing ScheduleWork() calls.
+  void ScheduleWork();
+
+  // Returns the TaskAnnotator which is used to add debug information to posted
+  // tasks.
+  debug::TaskAnnotator* task_annotator() { return &task_annotator_; }
+
+  // Runs the specified PendingTask.
+  void RunTask(const PendingTask& pending_task);
+
+  //----------------------------------------------------------------------------
+ protected:
+  scoped_ptr<MessagePump> pump_;
+
+ private:
+  friend class RunLoop;
+
+  // Configures various members for the two constructors.
+  void Init();
+
+  // Invokes the actual run loop using the message pump.
+  void RunHandler();
+
+  // Called to process any delayed non-nestable tasks.
+  bool ProcessNextDelayedNonNestableTask();
+
+  // Calls RunTask or queues the pending_task on the deferred task list if it
+  // cannot be run right now.  Returns true if the task was run.
+  bool DeferOrRunPendingTask(const PendingTask& pending_task);
+
+  // Adds the pending task to delayed_work_queue_.
+  void AddToDelayedWorkQueue(const PendingTask& pending_task);
+
+  // Delete tasks that haven't run yet without running them.  Used in the
+  // destructor to make sure all the task's destructors get called.  Returns
+  // true if some work was done.
+  bool DeletePendingTasks();
+
+  // Loads tasks from the incoming queue to |work_queue_| if the latter is
+  // empty.
+  void ReloadWorkQueue();
+
+  // Start recording histogram info about events and action IF it was enabled
+  // and IF the statistics recorder can accept a registration of our histogram.
+  void StartHistogrammer();
+
+  // Add occurrence of event to our histogram, so that we can see what is being
+  // done in a specific MessageLoop instance (i.e., specific thread).
+  // If message_histogram_ is NULL, this is a no-op.
+  void HistogramEvent(int event);
+
+  // MessagePump::Delegate methods:
+  bool DoWork() override;
+  bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
+  bool DoIdleWork() override;
+
+  const Type type_;
+
+  // A list of tasks that need to be processed by this instance.  Note that
+  // this queue is only accessed (push/pop) by our current thread.
+  TaskQueue work_queue_;
+
+#if defined(OS_WIN)
+  // How many high resolution tasks are in the pending task queue. This value
+  // increases by N every time we call ReloadWorkQueue() and decreases by 1
+  // every time we call RunTask() if the task needs a high resolution timer.
+  int pending_high_res_tasks_;
+  // Tracks if we have requested high resolution timers. Its only use is to
+  // turn off the high resolution timer upon loop destruction.
+  bool in_high_res_mode_;
+#endif
+
+  // Contains delayed tasks, sorted by their 'delayed_run_time' property.
+  DelayedTaskQueue delayed_work_queue_;
+
+  // A recent snapshot of Time::Now(), used to check delayed_work_queue_.
+  TimeTicks recent_time_;
+
+  // A queue of non-nestable tasks that we had to defer because when it came
+  // time to execute them we were in a nested message loop.  They will execute
+  // once we're out of nested message loops.
+  TaskQueue deferred_non_nestable_work_queue_;
+
+  ObserverList<DestructionObserver> destruction_observers_;
+
+  // A recursion block that prevents accidentally running additional tasks when
+  // insider a (accidentally induced?) nested message pump.
+  bool nestable_tasks_allowed_;
+
+#if defined(OS_WIN)
+  // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
+  // which enter a modal message loop.
+  bool os_modal_loop_;
+#endif
+
+  std::string thread_name_;
+  // A profiling histogram showing the counts of various messages and events.
+  HistogramBase* message_histogram_;
+
+  RunLoop* run_loop_;
+
+  ObserverList<TaskObserver> task_observers_;
+
+  debug::TaskAnnotator task_annotator_;
+
+  scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
+
+  // The message loop proxy associated with this message loop.
+  scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_;
+  scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
+
+  template <class T, class R> friend class base::subtle::DeleteHelperInternal;
+  template <class T, class R> friend class base::subtle::ReleaseHelperInternal;
+
+  void DeleteSoonInternal(const tracked_objects::Location& from_here,
+                          void(*deleter)(const void*),
+                          const void* object);
+  void ReleaseSoonInternal(const tracked_objects::Location& from_here,
+                           void(*releaser)(const void*),
+                           const void* object);
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoop);
+};
+
+#if !defined(OS_NACL)
+
+//-----------------------------------------------------------------------------
+// MessageLoopForUI extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// This class is typically used like so:
+//   MessageLoopForUI::current()->...call some method...
+//
+class BASE_EXPORT MessageLoopForUI : public MessageLoop {
+ public:
+  MessageLoopForUI() : MessageLoop(TYPE_UI) {
+  }
+
+  // Returns the MessageLoopForUI of the current thread.
+  static MessageLoopForUI* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK(loop);
+    DCHECK_EQ(MessageLoop::TYPE_UI, loop->type());
+    return static_cast<MessageLoopForUI*>(loop);
+  }
+
+  static bool IsCurrent() {
+    MessageLoop* loop = MessageLoop::current();
+    return loop && loop->type() == MessageLoop::TYPE_UI;
+  }
+
+#if defined(OS_IOS)
+  // On iOS, the main message loop cannot be Run().  Instead call Attach(),
+  // which connects this MessageLoop to the UI thread's CFRunLoop and allows
+  // PostTask() to work.
+  void Attach();
+#endif
+
+#if defined(OS_ANDROID)
+  // On Android, the UI message loop is handled by Java side. So Run() should
+  // never be called. Instead use Start(), which will forward all the native UI
+  // events to the Java message loop.
+  void Start();
+#endif
+
+#if defined(USE_OZONE) || (defined(USE_X11) && !defined(USE_GLIB))
+  // Please see MessagePumpLibevent for definition.
+  bool WatchFileDescriptor(
+      int fd,
+      bool persistent,
+      MessagePumpLibevent::Mode mode,
+      MessagePumpLibevent::FileDescriptorWatcher* controller,
+      MessagePumpLibevent::Watcher* delegate);
+#endif
+};
+
+// Do not add any member variables to MessageLoopForUI!  This is important b/c
+// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI).  Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+               MessageLoopForUI_should_not_have_extra_member_variables);
+
+#endif  // !defined(OS_NACL)
+
+//-----------------------------------------------------------------------------
+// MessageLoopForIO extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO.
+//
+// This class is typically used like so:
+//   MessageLoopForIO::current()->...call some method...
+//
+class BASE_EXPORT MessageLoopForIO : public MessageLoop {
+ public:
+  MessageLoopForIO() : MessageLoop(TYPE_IO) {
+  }
+
+  // Returns the MessageLoopForIO of the current thread.
+  static MessageLoopForIO* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
+    return static_cast<MessageLoopForIO*>(loop);
+  }
+
+  static bool IsCurrent() {
+    MessageLoop* loop = MessageLoop::current();
+    return loop && loop->type() == MessageLoop::TYPE_IO;
+  }
+
+#if !defined(OS_NACL_SFI)
+
+#if defined(OS_WIN)
+  typedef MessagePumpForIO::IOHandler IOHandler;
+  typedef MessagePumpForIO::IOContext IOContext;
+  typedef MessagePumpForIO::IOObserver IOObserver;
+#elif defined(OS_IOS)
+  typedef MessagePumpIOSForIO::Watcher Watcher;
+  typedef MessagePumpIOSForIO::FileDescriptorWatcher
+      FileDescriptorWatcher;
+  typedef MessagePumpIOSForIO::IOObserver IOObserver;
+
+  enum Mode {
+    WATCH_READ = MessagePumpIOSForIO::WATCH_READ,
+    WATCH_WRITE = MessagePumpIOSForIO::WATCH_WRITE,
+    WATCH_READ_WRITE = MessagePumpIOSForIO::WATCH_READ_WRITE
+  };
+#elif defined(OS_POSIX)
+  typedef MessagePumpLibevent::Watcher Watcher;
+  typedef MessagePumpLibevent::FileDescriptorWatcher
+      FileDescriptorWatcher;
+  typedef MessagePumpLibevent::IOObserver IOObserver;
+
+  enum Mode {
+    WATCH_READ = MessagePumpLibevent::WATCH_READ,
+    WATCH_WRITE = MessagePumpLibevent::WATCH_WRITE,
+    WATCH_READ_WRITE = MessagePumpLibevent::WATCH_READ_WRITE
+  };
+#endif
+
+  void AddIOObserver(IOObserver* io_observer);
+  void RemoveIOObserver(IOObserver* io_observer);
+
+#if defined(OS_WIN)
+  // Please see MessagePumpWin for definitions of these methods.
+  void RegisterIOHandler(HANDLE file, IOHandler* handler);
+  bool RegisterJobObject(HANDLE job, IOHandler* handler);
+  bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+#elif defined(OS_POSIX)
+  // Please see MessagePumpIOSForIO/MessagePumpLibevent for definition.
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           Mode mode,
+                           FileDescriptorWatcher* controller,
+                           Watcher* delegate);
+#endif  // defined(OS_IOS) || defined(OS_POSIX)
+#endif  // !defined(OS_NACL_SFI)
+};
+
+// Do not add any member variables to MessageLoopForIO!  This is important b/c
+// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO).  Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+               MessageLoopForIO_should_not_have_extra_member_variables);
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
diff --git a/base/message_loop/message_loop_proxy.cc b/base/message_loop/message_loop_proxy.cc
new file mode 100644
index 0000000..e5f0142
--- /dev/null
+++ b/base/message_loop/message_loop_proxy.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_proxy.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+MessageLoopProxy::MessageLoopProxy() {
+}
+
+MessageLoopProxy::~MessageLoopProxy() {
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_proxy.h b/base/message_loop/message_loop_proxy.h
new file mode 100644
index 0000000..d5ecc04
--- /dev/null
+++ b/base/message_loop/message_loop_proxy.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+// MessageLoopProxy is deprecated. Code should prefer to depend on TaskRunner
+// (or the various specializations) for passing task runners around, and should
+// use ThreadTaskRunnerHandle::Get() to get the thread's associated task runner.
+//
+// See http://crbug.com/391045 for more details.
+// Example for these changes:
+//
+// base::MessageLoopProxy::current() -> base::ThreadTaskRunnerHandle::Get()
+// scoped_refptr<base::MessageLoopProxy> ->
+//     scoped_refptr<base::SingleThreadTaskRunner>
+// base::MessageLoopProxy -> base::SingleThreadTaskRunner
+
+namespace base {
+
+// This class provides a thread-safe refcounted interface to the Post* methods
+// of a message loop. This class can outlive the target message loop.
+// MessageLoopProxy objects are constructed automatically for all MessageLoops.
+// So, to access them, you can use any of the following:
+//   Thread::message_loop_proxy()
+//   MessageLoop::current()->message_loop_proxy()
+//   MessageLoopProxy::current()
+//
+// TODO(akalin): Now that we have the *TaskRunner interfaces, we can
+// merge this with MessageLoopProxyImpl.
+class BASE_EXPORT MessageLoopProxy : public SingleThreadTaskRunner {
+ public:
+  // Gets the MessageLoopProxy for the current message loop, creating one if
+  // needed.
+  static scoped_refptr<MessageLoopProxy> current();
+
+ protected:
+  MessageLoopProxy();
+  ~MessageLoopProxy() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc
new file mode 100644
index 0000000..b7abca3
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_impl.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_proxy_impl.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/incoming_task_queue.h"
+#include "base/message_loop/message_loop.h"
+
+namespace base {
+namespace internal {
+
+MessageLoopProxyImpl::MessageLoopProxyImpl(
+    scoped_refptr<IncomingTaskQueue> incoming_queue)
+    : incoming_queue_(incoming_queue),
+      valid_thread_id_(PlatformThread::CurrentId()) {
+}
+
+bool MessageLoopProxyImpl::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true);
+}
+
+bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false);
+}
+
+bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const {
+  return valid_thread_id_ == PlatformThread::CurrentId();
+}
+
+MessageLoopProxyImpl::~MessageLoopProxyImpl() {
+}
+
+}  // namespace internal
+
+scoped_refptr<MessageLoopProxy>
+MessageLoopProxy::current() {
+  MessageLoop* cur_loop = MessageLoop::current();
+  if (!cur_loop)
+    return NULL;
+  return cur_loop->message_loop_proxy();
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h
new file mode 100644
index 0000000..0fe629f
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_impl.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/pending_task.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+class IncomingTaskQueue;
+
+// A stock implementation of MessageLoopProxy that is created and managed by a
+// MessageLoop. For now a MessageLoopProxyImpl can only be created as part of a
+// MessageLoop.
+class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {
+ public:
+  explicit MessageLoopProxyImpl(
+      scoped_refptr<IncomingTaskQueue> incoming_queue);
+
+  // MessageLoopProxy implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  friend class RefCountedThreadSafe<MessageLoopProxyImpl>;
+  ~MessageLoopProxyImpl() override;
+
+  // THe incoming queue receiving all posted tasks.
+  scoped_refptr<IncomingTaskQueue> incoming_queue_;
+
+  // ID of the thread |this| was created on.
+  PlatformThreadId valid_thread_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
diff --git a/base/message_loop/message_loop_proxy_impl_unittest.cc b/base/message_loop/message_loop_proxy_impl_unittest.cc
new file mode 100644
index 0000000..fa25371
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_impl_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_proxy_impl.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class MessageLoopProxyImplTest : public testing::Test {
+ public:
+  void Release() const {
+    AssertOnIOThread();
+    Quit();
+  }
+
+  void Quit() const {
+    loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void AssertOnIOThread() const {
+    ASSERT_TRUE(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+    ASSERT_EQ(io_thread_->message_loop_proxy(),
+              MessageLoopProxy::current());
+  }
+
+  void AssertOnFileThread() const {
+    ASSERT_TRUE(file_thread_->message_loop_proxy()->BelongsToCurrentThread());
+    ASSERT_EQ(file_thread_->message_loop_proxy(),
+              MessageLoopProxy::current());
+  }
+
+ protected:
+  void SetUp() override {
+    io_thread_.reset(new Thread("MessageLoopProxyImplTest_IO"));
+    file_thread_.reset(new Thread("MessageLoopProxyImplTest_File"));
+    io_thread_->Start();
+    file_thread_->Start();
+  }
+
+  void TearDown() override {
+    io_thread_->Stop();
+    file_thread_->Stop();
+  }
+
+  static void BasicFunction(MessageLoopProxyImplTest* test) {
+    test->AssertOnFileThread();
+    test->Quit();
+  }
+
+  static void AssertNotRun() {
+    FAIL() << "Callback Should not get executed.";
+  }
+
+  class DeletedOnFile {
+   public:
+    explicit DeletedOnFile(MessageLoopProxyImplTest* test) : test_(test) {}
+
+    ~DeletedOnFile() {
+      test_->AssertOnFileThread();
+      test_->Quit();
+    }
+
+   private:
+    MessageLoopProxyImplTest* test_;
+  };
+
+  scoped_ptr<Thread> io_thread_;
+  scoped_ptr<Thread> file_thread_;
+
+ private:
+  mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopProxyImplTest, Release) {
+  EXPECT_TRUE(io_thread_->message_loop_proxy()->ReleaseSoon(FROM_HERE, this));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, Delete) {
+  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+  EXPECT_TRUE(file_thread_->message_loop_proxy()->DeleteSoon(
+      FROM_HERE, deleted_on_file));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTask) {
+  EXPECT_TRUE(file_thread_->message_loop_proxy()->PostTask(
+      FROM_HERE, Bind(&MessageLoopProxyImplTest::BasicFunction,
+                            Unretained(this))));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadExits) {
+  scoped_ptr<Thread> test_thread(
+      new Thread("MessageLoopProxyImplTest_Dummy"));
+  test_thread->Start();
+  scoped_refptr<MessageLoopProxy> message_loop_proxy =
+      test_thread->message_loop_proxy();
+  test_thread->Stop();
+
+  bool ret = message_loop_proxy->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoopProxyImplTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadIsDeleted) {
+  scoped_refptr<MessageLoopProxy> message_loop_proxy;
+  {
+    scoped_ptr<Thread> test_thread(
+        new Thread("MessageLoopProxyImplTest_Dummy"));
+    test_thread->Start();
+    message_loop_proxy = test_thread->message_loop_proxy();
+  }
+  bool ret = message_loop_proxy->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoopProxyImplTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_proxy_unittest.cc b/base/message_loop/message_loop_proxy_unittest.cc
new file mode 100644
index 0000000..0b0d9f8
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_unittest.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_proxy.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class MessageLoopProxyTest : public testing::Test {
+ public:
+  MessageLoopProxyTest()
+      : current_loop_(new MessageLoop()),
+        task_thread_("task_thread"),
+        thread_sync_(true, false) {
+  }
+
+  void DeleteCurrentMessageLoop() {
+    current_loop_.reset();
+  }
+
+ protected:
+  void SetUp() override {
+    // Use SetUp() instead of the constructor to avoid posting a task to a
+    // partialy constructed object.
+    task_thread_.Start();
+
+    // Allow us to pause the |task_thread_|'s MessageLoop.
+    task_thread_.message_loop()->PostTask(
+        FROM_HERE,
+        Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
+  }
+
+  void TearDown() override {
+    // Make sure the |task_thread_| is not blocked, and stop the thread
+    // fully before destuction because its tasks may still depend on the
+    // |thread_sync_| event.
+    thread_sync_.Signal();
+    task_thread_.Stop();
+    DeleteCurrentMessageLoop();
+  }
+
+  // Make LoopRecorder threadsafe so that there is defined behavior even if a
+  // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
+  class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
+   public:
+    LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
+                 int* destruct_order)
+        : run_on_(run_on),
+          deleted_on_(deleted_on),
+          destruct_order_(destruct_order) {
+    }
+
+    void RecordRun() {
+      *run_on_ = MessageLoop::current();
+    }
+
+   private:
+    friend class RefCountedThreadSafe<LoopRecorder>;
+    ~LoopRecorder() {
+      *deleted_on_ = MessageLoop::current();
+      *destruct_order_ = g_order.GetNext();
+    }
+
+    MessageLoop** run_on_;
+    MessageLoop** deleted_on_;
+    int* destruct_order_;
+  };
+
+  static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+  }
+
+  static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void UnblockTaskThread() {
+    thread_sync_.Signal();
+  }
+
+  void BlockTaskThreadHelper() {
+    thread_sync_.Wait();
+  }
+
+  static StaticAtomicSequenceNumber g_order;
+
+  scoped_ptr<MessageLoop> current_loop_;
+  Thread task_thread_;
+
+ private:
+  base::WaitableEvent thread_sync_;
+};
+
+StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+  current_loop_->Run();
+
+  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Grab a MessageLoopProxy to a dead MessageLoop.
+  scoped_refptr<MessageLoopProxy> task_loop_proxy =
+      task_thread_.message_loop_proxy();
+  UnblockTaskThread();
+  task_thread_.Stop();
+
+  ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // The relay should have properly deleted its resources leaving us as the only
+  // reference.
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+  ASSERT_TRUE(task_recoder->HasOneRef());
+  ASSERT_TRUE(reply_recoder->HasOneRef());
+
+  // Nothing should have run though.
+  EXPECT_FALSE(task_run_on);
+  EXPECT_FALSE(reply_run_on);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  current_loop_->Run();
+
+  EXPECT_EQ(current_loop_.get(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
+  // Annotate the scope as having memory leaks to suppress heapchecker reports.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  task_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+
+  // Mercilessly whack the current loop before |reply| gets to run.
+  current_loop_.reset();
+
+  // This should ensure the relay has been run.  We need to record the
+  // MessageLoop pointer before stopping the thread because Thread::Stop() will
+  // NULL out its own pointer.
+  MessageLoop* task_loop = task_thread_.message_loop();
+  task_thread_.Stop();
+
+  EXPECT_EQ(task_loop, task_run_on);
+  ASSERT_FALSE(task_deleted_on);
+  EXPECT_FALSE(reply_run_on);
+  ASSERT_FALSE(reply_deleted_on);
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+
+  // The PostTaskAndReplyRelay is leaked here.  Even if we had a reference to
+  // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
+  // checks that MessageLoop::current() is the the same as when the
+  // PostTaskAndReplyRelay object was constructed.  However, this loop must have
+  // aleady been deleted in order to perform this test.  See
+  // http://crbug.com/86301.
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_test.cc b/base/message_loop/message_loop_test.cc
new file mode 100644
index 0000000..eca6c8f
--- /dev/null
+++ b/base/message_loop/message_loop_test.cc
@@ -0,0 +1,1014 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_test.h"
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+
+namespace base {
+namespace test {
+
+namespace {
+
+class Foo : public RefCounted<Foo> {
+ public:
+  Foo() : test_count_(0) {
+  }
+
+  void Test0() {
+    ++test_count_;
+  }
+
+  void Test1ConstRef(const std::string& a) {
+    ++test_count_;
+    result_.append(a);
+  }
+
+  void Test1Ptr(std::string* a) {
+    ++test_count_;
+    result_.append(*a);
+  }
+
+  void Test1Int(int a) {
+    test_count_ += a;
+  }
+
+  void Test2Ptr(std::string* a, std::string* b) {
+    ++test_count_;
+    result_.append(*a);
+    result_.append(*b);
+  }
+
+  void Test2Mixed(const std::string& a, std::string* b) {
+    ++test_count_;
+    result_.append(a);
+    result_.append(*b);
+  }
+
+  int test_count() const { return test_count_; }
+  const std::string& result() const { return result_; }
+
+ private:
+  friend class RefCounted<Foo>;
+
+  ~Foo() {}
+
+  int test_count_;
+  std::string result_;
+
+  DISALLOW_COPY_AND_ASSIGN(Foo);
+};
+
+// This function runs slowly to simulate a large amount of work being done.
+void SlowFunc(TimeDelta pause, int* quit_counter) {
+    PlatformThread::Sleep(pause);
+    if (--(*quit_counter) == 0)
+      MessageLoop::current()->QuitWhenIdle();
+}
+
+// This function records the time when Run was called in a Time object, which is
+// useful for building a variety of MessageLoop tests.
+// TODO(sky): remove?
+void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
+  *run_time = Time::Now();
+
+    // Cause our Run function to take some time to execute.  As a result we can
+    // count on subsequent RecordRunTimeFunc()s running at a future time,
+    // without worry about the resolution of our system clock being an issue.
+  SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
+}
+
+}  // namespace
+
+void RunTest_PostTask(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+  // Add tests to message loop
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a"), b("b"), c("c"), d("d");
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test0, foo.get()));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+    &Foo::Test1ConstRef, foo.get(), a));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test1Ptr, foo.get(), &b));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test1Int, foo.get(), 100));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test2Ptr, foo.get(), &a, &c));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test2Mixed, foo.get(), a, &d));
+  // After all tests, post a message that will shut down the message loop
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &MessageLoop::Quit, Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(foo->test_count(), 105);
+  EXPECT_EQ(foo->result(), "abacad");
+}
+
+void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that PostDelayedTask results in a delayed task.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 1;
+  Time run_time;
+
+  loop.PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      kDelay);
+
+  Time time_before_run = Time::Now();
+  loop.Run();
+  Time time_after_run = Time::Now();
+
+  EXPECT_EQ(0, num_tasks);
+  EXPECT_LT(kDelay, time_after_run - time_before_run);
+}
+
+void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that two tasks with different delays run in the right order.
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromMilliseconds(200));
+  // If we get a large pause in execution (due to a context switch) here, this
+  // test could fail.
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 < run_time1);
+}
+
+void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that two tasks with the same delay run in the order in which they
+  // were posted.
+  //
+  // NOTE: This is actually an approximate test since the API only takes a
+  // "delay" parameter, so we are not exactly simulating two tasks that get
+  // posted at the exact same time.  It would be nice if the API allowed us to
+  // specify the desired run time.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay);
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay);
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time1 < run_time2);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that a delayed task still runs after a normal tasks even if the
+  // normal tasks take a long time to run.
+
+  const TimeDelta kPause = TimeDelta::FromMilliseconds(50);
+
+  int num_tasks = 2;
+  Time run_time;
+
+  loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks));
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time time_before_run = Time::Now();
+  loop.Run();
+  Time time_after_run = Time::Now();
+
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_LT(kPause, time_after_run - time_before_run);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that a delayed task still runs after a pile of normal tasks.  The key
+  // difference between this test and the previous one is that here we return
+  // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
+  // to maybe run the delayed task.  It should know not to do so until the
+  // delayed task's delay has passed.
+
+  int num_tasks = 11;
+  Time run_time1, run_time2;
+
+  // Clutter the ML with tasks.
+  for (int i = 1; i < num_tasks; ++i)
+    loop.PostTask(FROM_HERE,
+                  Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
+
+  loop.PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(1));
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 > run_time1);
+}
+
+void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that the interval of the timer, used to run the next delayed task, is
+  // set to a value corresponding to when the next delayed task should run.
+
+  // By setting num_tasks to 1, we ensure that the first task to run causes the
+  // run loop to exit.
+  int num_tasks = 1;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time start_time = Time::Now();
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  // Ensure that we ran in far less time than the slower timer.
+  TimeDelta total_time = Time::Now() - start_time;
+  EXPECT_GT(5000, total_time.InMilliseconds());
+
+  // In case both timers somehow run at nearly the same time, sleep a little
+  // and then run all pending to force them both to have run.  This is just
+  // encouraging flakiness if there is any.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(run_time1.is_null());
+  EXPECT_FALSE(run_time2.is_null());
+}
+
+// This is used to inject a test point for recording the destructor calls for
+// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
+// are trying to hook the actual destruction, which is not a common operation.
+class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> {
+ public:
+  RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
+      : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
+  }
+  void Run() {}
+
+ private:
+  friend class RefCounted<RecordDeletionProbe>;
+
+  ~RecordDeletionProbe() {
+    *was_deleted_ = true;
+    if (post_on_delete_.get())
+      MessageLoop::current()->PostTask(
+          FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
+  }
+
+  scoped_refptr<RecordDeletionProbe> post_on_delete_;
+  bool* was_deleted_;
+};
+
+void RunTest_EnsureDeletion(MessagePumpFactory factory) {
+  bool a_was_deleted = false;
+  bool b_was_deleted = false;
+  {
+    scoped_ptr<MessagePump> pump(factory());
+    MessageLoop loop(pump.Pass());
+    loop.PostTask(
+        FROM_HERE, Bind(&RecordDeletionProbe::Run,
+                              new RecordDeletionProbe(NULL, &a_was_deleted)));
+    // TODO(ajwong): Do we really need 1000ms here?
+    loop.PostDelayedTask(
+        FROM_HERE, Bind(&RecordDeletionProbe::Run,
+                              new RecordDeletionProbe(NULL, &b_was_deleted)),
+        TimeDelta::FromMilliseconds(1000));
+  }
+  EXPECT_TRUE(a_was_deleted);
+  EXPECT_TRUE(b_was_deleted);
+}
+
+void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory) {
+  bool a_was_deleted = false;
+  bool b_was_deleted = false;
+  bool c_was_deleted = false;
+  {
+    scoped_ptr<MessagePump> pump(factory());
+    MessageLoop loop(pump.Pass());
+    // The scoped_refptr for each of the below is held either by the chained
+    // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
+    RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
+    RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
+    RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
+    loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c));
+  }
+  EXPECT_TRUE(a_was_deleted);
+  EXPECT_TRUE(b_was_deleted);
+  EXPECT_TRUE(c_was_deleted);
+}
+
+void NestingFunc(int* depth) {
+  if (*depth > 0) {
+    *depth -= 1;
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     Bind(&NestingFunc, depth));
+
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->Run();
+  }
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void RunTest_Nesting(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  int depth = 100;
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&NestingFunc, &depth));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(depth, 0);
+}
+
+enum TaskType {
+  MESSAGEBOX,
+  ENDDIALOG,
+  RECURSIVE,
+  TIMEDMESSAGELOOP,
+  QUITMESSAGELOOP,
+  ORDERED,
+  PUMPS,
+  SLEEP,
+  RUNS,
+};
+
+struct TaskItem {
+  TaskItem(TaskType t, int c, bool s)
+      : type(t),
+        cookie(c),
+        start(s) {
+  }
+
+  TaskType type;
+  int cookie;
+  bool start;
+
+  bool operator == (const TaskItem& other) const {
+    return type == other.type && cookie == other.cookie && start == other.start;
+  }
+};
+
+std::ostream& operator <<(std::ostream& os, TaskType type) {
+  switch (type) {
+  case MESSAGEBOX:        os << "MESSAGEBOX"; break;
+  case ENDDIALOG:         os << "ENDDIALOG"; break;
+  case RECURSIVE:         os << "RECURSIVE"; break;
+  case TIMEDMESSAGELOOP:  os << "TIMEDMESSAGELOOP"; break;
+  case QUITMESSAGELOOP:   os << "QUITMESSAGELOOP"; break;
+  case ORDERED:          os << "ORDERED"; break;
+  case PUMPS:             os << "PUMPS"; break;
+  case SLEEP:             os << "SLEEP"; break;
+  default:
+    NOTREACHED();
+    os << "Unknown TaskType";
+    break;
+  }
+  return os;
+}
+
+std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
+  if (item.start)
+    return os << item.type << " " << item.cookie << " starts";
+  else
+    return os << item.type << " " << item.cookie << " ends";
+}
+
+class TaskList {
+ public:
+  void RecordStart(TaskType type, int cookie) {
+    TaskItem item(type, cookie, true);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  void RecordEnd(TaskType type, int cookie) {
+    TaskItem item(type, cookie, false);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  size_t Size() {
+    return task_list_.size();
+  }
+
+  TaskItem Get(int n)  {
+    return task_list_[n];
+  }
+
+ private:
+  std::vector<TaskItem> task_list_;
+};
+
+void RecursiveFunc(TaskList* order, int cookie, int depth,
+                   bool is_reentrant) {
+  order->RecordStart(RECURSIVE, cookie);
+  if (depth > 0) {
+    if (is_reentrant)
+      MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
+  }
+  order->RecordEnd(RECURSIVE, cookie);
+}
+
+void QuitFunc(TaskList* order, int cookie) {
+  order->RecordStart(QUITMESSAGELOOP, cookie);
+  MessageLoop::current()->QuitWhenIdle();
+  order->RecordEnd(QUITMESSAGELOOP, cookie);
+}
+void RunTest_RecursiveDenial1(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&RecursiveFunc, &order, 1, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&RecursiveFunc, &order, 2, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&QuitFunc, &order, 3));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(14U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+  EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
+}
+
+void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
+                       bool is_reentrant) {
+  RecursiveFunc(order, cookie, depth, is_reentrant);
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+}
+
+void OrderedFunc(TaskList* order, int cookie) {
+  order->RecordStart(ORDERED, cookie);
+  order->RecordEnd(ORDERED, cookie);
+}
+
+void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 3),
+      TimeDelta::FromMilliseconds(5));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&QuitFunc, &order, 4),
+      TimeDelta::FromMilliseconds(5));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(16U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
+  EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
+}
+
+void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&QuitFunc, &order, 3));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(14U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+  EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
+}
+
+// Tests that non nestable tasks run in FIFO if there are no nested loops.
+void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  MessageLoop::current()->PostNonNestableTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&QuitFunc, &order, 3));
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(6U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+}
+
+void FuncThatPumps(TaskList* order, int cookie) {
+  order->RecordStart(PUMPS, cookie);
+  {
+    MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+    RunLoop().RunUntilIdle();
+  }
+  order->RecordEnd(PUMPS, cookie);
+}
+
+void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
+  order->RecordStart(SLEEP, cookie);
+  PlatformThread::Sleep(delay);
+  order->RecordEnd(SLEEP, cookie);
+}
+
+// Tests that non nestable tasks don't run when there's code in the call stack.
+void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
+                                     bool use_delayed) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&FuncThatPumps, &order, 1));
+  if (use_delayed) {
+    MessageLoop::current()->PostNonNestableDelayedTask(
+        FROM_HERE,
+        Bind(&OrderedFunc, &order, 2),
+        TimeDelta::FromMilliseconds(1));
+  } else {
+    MessageLoop::current()->PostNonNestableTask(
+        FROM_HERE,
+        Bind(&OrderedFunc, &order, 2));
+  }
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&OrderedFunc, &order, 5));
+  if (use_delayed) {
+    MessageLoop::current()->PostNonNestableDelayedTask(
+        FROM_HERE,
+        Bind(&QuitFunc, &order, 6),
+        TimeDelta::FromMilliseconds(2));
+  } else {
+    MessageLoop::current()->PostNonNestableTask(
+        FROM_HERE,
+        Bind(&QuitFunc, &order, 6));
+  }
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(12U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
+  EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
+  EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true));
+  EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false));
+  EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
+  EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
+}
+
+void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) {
+  order->RecordStart(RUNS, cookie);
+  {
+    MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+    run_loop->Run();
+  }
+  order->RecordEnd(RUNS, cookie);
+}
+
+void FuncThatQuitsNow() {
+  MessageLoop::current()->QuitNow();
+}
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_QuitNow(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs
+
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(6U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+  RunLoop bogus_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, bogus_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_loop1;
+  RunLoop nested_loop2;
+  RunLoop nested_loop3;
+  RunLoop nested_loop4;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 5));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 6));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop1.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 7));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop2.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 8));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop3.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 9));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop4.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 10));
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(18U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit works before RunWithID.
+void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  run_loop.Quit();
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs
+
+  run_loop.Run();
+
+  ASSERT_EQ(0U, order.Size());
+}
+
+// Tests RunLoopQuit works during RunWithID.
+void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs
+
+  run_loop.Run();
+
+  ASSERT_EQ(2U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit works after RunWithID.
+void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, run_loop.QuitClosure()); // has no affect
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 4));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+
+  RunLoop outer_run_loop;
+  outer_run_loop.Run();
+
+  ASSERT_EQ(8U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+void PostNTasksThenQuit(int posts_remaining) {
+  if (posts_remaining > 1) {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&PostNTasksThenQuit, posts_remaining - 1));
+  } else {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+}
+
+// There was a bug in the MessagePumpGLib where posting tasks recursively
+// caused the message loop to hang, due to the buffer of the internal pipe
+// becoming full. Test all MessageLoop types to ensure this issue does not
+// exist in other MessagePumps.
+//
+// On Linux, the pipe buffer size is 64KiB by default. The bug caused one
+// byte accumulated in the pipe per two posts, so we should repeat 128K
+// times to reproduce the bug.
+void RunTest_RecursivePosts(MessagePumpFactory factory) {
+  const int kNumTimes = 1 << 17;
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+  loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
+  loop.Run();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/message_loop/message_loop_test.h b/base/message_loop/message_loop_test.h
new file mode 100644
index 0000000..3d9889c
--- /dev/null
+++ b/base/message_loop/message_loop_test.h
@@ -0,0 +1,133 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_
+
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// This file consists of tests meant to exercise the combination of MessageLoop
+// and MessagePump. To use these define the macro RUN_MESSAGE_LOOP_TESTS using
+// an ID appropriate for your MessagePump, eg
+// RUN_MESSAGE_LOOP_TESTS(UI, factory). Factory is a function called to create
+// the MessagePump.
+namespace base {
+namespace test {
+
+typedef MessageLoop::MessagePumpFactory MessagePumpFactory;
+
+void RunTest_PostTask(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory);
+void RunTest_EnsureDeletion(MessagePumpFactory factory);
+void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory);
+void RunTest_Nesting(MessagePumpFactory factory);
+void RunTest_RecursiveDenial1(MessagePumpFactory factory);
+void RunTest_RecursiveDenial3(MessagePumpFactory factory);
+void RunTest_RecursiveSupport1(MessagePumpFactory factory);
+void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory);
+void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
+                                     bool use_delayed);
+void RunTest_QuitNow(MessagePumpFactory factory);
+void RunTest_RunLoopQuitTop(MessagePumpFactory factory);
+void RunTest_RunLoopQuitNested(MessagePumpFactory factory);
+void RunTest_RunLoopQuitBogus(MessagePumpFactory factory);
+void RunTest_RunLoopQuitDeep(MessagePumpFactory factory);
+void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory);
+void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory);
+void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory);
+void RunTest_RecursivePosts(MessagePumpFactory factory);
+
+}  // namespace test
+}  // namespace base
+
+#define RUN_MESSAGE_LOOP_TESTS(id, factory) \
+  TEST(MessageLoopTestType##id, PostTask) { \
+    base::test::RunTest_PostTask(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_Basic) { \
+    base::test::RunTest_PostDelayedTask_Basic(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InDelayOrder) { \
+    base::test::RunTest_PostDelayedTask_InDelayOrder(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder) { \
+    base::test::RunTest_PostDelayedTask_InPostOrder(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder_2) { \
+    base::test::RunTest_PostDelayedTask_InPostOrder_2(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder_3) { \
+    base::test::RunTest_PostDelayedTask_InPostOrder_3(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_SharedTimer) { \
+    base::test::RunTest_PostDelayedTask_SharedTimer(factory); \
+  } \
+  /* TODO(darin): MessageLoop does not support deleting all tasks in the */ \
+  /* destructor. */ \
+  /* Fails, http://crbug.com/50272. */ \
+  TEST(MessageLoopTestType##id, DISABLED_EnsureDeletion) { \
+    base::test::RunTest_EnsureDeletion(factory); \
+  } \
+  /* TODO(darin): MessageLoop does not support deleting all tasks in the */ \
+  /* destructor. */ \
+  /* Fails, http://crbug.com/50272. */ \
+  TEST(MessageLoopTestType##id, DISABLED_EnsureDeletion_Chain) { \
+    base::test::RunTest_EnsureDeletion_Chain(factory); \
+  } \
+  TEST(MessageLoopTestType##id, Nesting) { \
+    base::test::RunTest_Nesting(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursiveDenial1) { \
+    base::test::RunTest_RecursiveDenial1(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursiveDenial3) { \
+    base::test::RunTest_RecursiveDenial3(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursiveSupport1) { \
+    base::test::RunTest_RecursiveSupport1(factory); \
+  } \
+  TEST(MessageLoopTestType##id, NonNestableWithNoNesting) { \
+    base::test::RunTest_NonNestableWithNoNesting(factory); \
+  } \
+  TEST(MessageLoopTestType##id, NonNestableInNestedLoop) { \
+    base::test::RunTest_NonNestableInNestedLoop(factory, false); \
+  } \
+  TEST(MessageLoopTestType##id, NonNestableDelayedInNestedLoop) { \
+    base::test::RunTest_NonNestableInNestedLoop(factory, true); \
+  } \
+  TEST(MessageLoopTestType##id, QuitNow) { \
+    base::test::RunTest_QuitNow(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitTop) { \
+    base::test::RunTest_RunLoopQuitTop(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitNested) { \
+    base::test::RunTest_RunLoopQuitNested(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitBogus) { \
+    base::test::RunTest_RunLoopQuitBogus(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitDeep) { \
+    base::test::RunTest_RunLoopQuitDeep(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitOrderBefore) { \
+    base::test::RunTest_RunLoopQuitOrderBefore(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitOrderDuring) { \
+    base::test::RunTest_RunLoopQuitOrderDuring(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitOrderAfter) { \
+    base::test::RunTest_RunLoopQuitOrderAfter(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursivePosts) { \
+    base::test::RunTest_RecursivePosts(factory); \
+  } \
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
new file mode 100644
index 0000000..ddde6bb
--- /dev/null
+++ b/base/message_loop/message_loop_unittest.cc
@@ -0,0 +1,1015 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy_impl.h"
+#include "base/message_loop/message_loop_test.h"
+#include "base/pending_task.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/message_loop/message_pump_win.h"
+#include "base/process/memory.h"
+#include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace base {
+
+// TODO(darin): Platform-specific MessageLoop tests should be grouped together
+// to avoid chopping this file up with so many #ifdefs.
+
+namespace {
+
+scoped_ptr<MessagePump> TypeDefaultMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_DEFAULT);
+}
+
+scoped_ptr<MessagePump> TypeIOMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_IO);
+}
+
+scoped_ptr<MessagePump> TypeUIMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_UI);
+}
+
+class Foo : public RefCounted<Foo> {
+ public:
+  Foo() : test_count_(0) {
+  }
+
+  void Test1ConstRef(const std::string& a) {
+    ++test_count_;
+    result_.append(a);
+  }
+
+  int test_count() const { return test_count_; }
+  const std::string& result() const { return result_; }
+
+ private:
+  friend class RefCounted<Foo>;
+
+  ~Foo() {}
+
+  int test_count_;
+  std::string result_;
+};
+
+#if defined(OS_WIN)
+
+// This function runs slowly to simulate a large amount of work being done.
+static void SlowFunc(TimeDelta pause, int* quit_counter) {
+    PlatformThread::Sleep(pause);
+    if (--(*quit_counter) == 0)
+      MessageLoop::current()->QuitWhenIdle();
+}
+
+// This function records the time when Run was called in a Time object, which is
+// useful for building a variety of MessageLoop tests.
+static void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
+  *run_time = Time::Now();
+
+    // Cause our Run function to take some time to execute.  As a result we can
+    // count on subsequent RecordRunTimeFunc()s running at a future time,
+    // without worry about the resolution of our system clock being an issue.
+  SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
+}
+
+void SubPumpFunc() {
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  MSG msg;
+  while (GetMessage(&msg, NULL, 0, 0)) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void RunTest_PostDelayedTask_SharedTimer_SubPump() {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+
+  // Test that the interval of the timer, used to run the next delayed task, is
+  // set to a value corresponding to when the next delayed task should run.
+
+  // By setting num_tasks to 1, we ensure that the first task to run causes the
+  // run loop to exit.
+  int num_tasks = 1;
+  Time run_time;
+
+  loop.PostTask(FROM_HERE, Bind(&SubPumpFunc));
+
+  // This very delayed task should never run.
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+
+  // This slightly delayed task should run from within SubPumpFunc).
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&PostQuitMessage, 0),
+      TimeDelta::FromMilliseconds(10));
+
+  Time start_time = Time::Now();
+
+  loop.Run();
+  EXPECT_EQ(1, num_tasks);
+
+  // Ensure that we ran in far less time than the slower timer.
+  TimeDelta total_time = Time::Now() - start_time;
+  EXPECT_GT(5000, total_time.InMilliseconds());
+
+  // In case both timers somehow run at nearly the same time, sleep a little
+  // and then run all pending to force them both to have run.  This is just
+  // encouraging flakiness if there is any.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(run_time.is_null());
+}
+
+const wchar_t kMessageBoxTitle[] = L"MessageLoop Unit Test";
+
+enum TaskType {
+  MESSAGEBOX,
+  ENDDIALOG,
+  RECURSIVE,
+  TIMEDMESSAGELOOP,
+  QUITMESSAGELOOP,
+  ORDERED,
+  PUMPS,
+  SLEEP,
+  RUNS,
+};
+
+// Saves the order in which the tasks executed.
+struct TaskItem {
+  TaskItem(TaskType t, int c, bool s)
+      : type(t),
+        cookie(c),
+        start(s) {
+  }
+
+  TaskType type;
+  int cookie;
+  bool start;
+
+  bool operator == (const TaskItem& other) const {
+    return type == other.type && cookie == other.cookie && start == other.start;
+  }
+};
+
+std::ostream& operator <<(std::ostream& os, TaskType type) {
+  switch (type) {
+  case MESSAGEBOX:        os << "MESSAGEBOX"; break;
+  case ENDDIALOG:         os << "ENDDIALOG"; break;
+  case RECURSIVE:         os << "RECURSIVE"; break;
+  case TIMEDMESSAGELOOP:  os << "TIMEDMESSAGELOOP"; break;
+  case QUITMESSAGELOOP:   os << "QUITMESSAGELOOP"; break;
+  case ORDERED:          os << "ORDERED"; break;
+  case PUMPS:             os << "PUMPS"; break;
+  case SLEEP:             os << "SLEEP"; break;
+  default:
+    NOTREACHED();
+    os << "Unknown TaskType";
+    break;
+  }
+  return os;
+}
+
+std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
+  if (item.start)
+    return os << item.type << " " << item.cookie << " starts";
+  else
+    return os << item.type << " " << item.cookie << " ends";
+}
+
+class TaskList {
+ public:
+  void RecordStart(TaskType type, int cookie) {
+    TaskItem item(type, cookie, true);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  void RecordEnd(TaskType type, int cookie) {
+    TaskItem item(type, cookie, false);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  size_t Size() {
+    return task_list_.size();
+  }
+
+  TaskItem Get(int n)  {
+    return task_list_[n];
+  }
+
+ private:
+  std::vector<TaskItem> task_list_;
+};
+
+// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
+// common controls (like OpenFile) and StartDoc printing function can cause
+// implicit message loops.
+void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
+  order->RecordStart(MESSAGEBOX, cookie);
+  if (is_reentrant)
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+  MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
+  order->RecordEnd(MESSAGEBOX, cookie);
+}
+
+// Will end the MessageBox.
+void EndDialogFunc(TaskList* order, int cookie) {
+  order->RecordStart(ENDDIALOG, cookie);
+  HWND window = GetActiveWindow();
+  if (window != NULL) {
+    EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
+    // Cheap way to signal that the window wasn't found if RunEnd() isn't
+    // called.
+    order->RecordEnd(ENDDIALOG, cookie);
+  }
+}
+
+void RecursiveFunc(TaskList* order, int cookie, int depth,
+                   bool is_reentrant) {
+  order->RecordStart(RECURSIVE, cookie);
+  if (depth > 0) {
+    if (is_reentrant)
+      MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
+  }
+  order->RecordEnd(RECURSIVE, cookie);
+}
+
+void QuitFunc(TaskList* order, int cookie) {
+  order->RecordStart(QUITMESSAGELOOP, cookie);
+  MessageLoop::current()->QuitWhenIdle();
+  order->RecordEnd(QUITMESSAGELOOP, cookie);
+}
+
+void RecursiveFuncWin(MessageLoop* target,
+                      HANDLE event,
+                      bool expect_window,
+                      TaskList* order,
+                      bool is_reentrant) {
+  target->PostTask(FROM_HERE,
+                   Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
+  target->PostTask(FROM_HERE,
+                   Bind(&MessageBoxFunc, order, 2, is_reentrant));
+  target->PostTask(FROM_HERE,
+                   Bind(&RecursiveFunc, order, 3, 2, is_reentrant));
+  // The trick here is that for recursive task processing, this task will be
+  // ran _inside_ the MessageBox message loop, dismissing the MessageBox
+  // without a chance.
+  // For non-recursive task processing, this will be executed _after_ the
+  // MessageBox will have been dismissed by the code below, where
+  // expect_window_ is true.
+  target->PostTask(FROM_HERE,
+                   Bind(&EndDialogFunc, order, 4));
+  target->PostTask(FROM_HERE,
+                   Bind(&QuitFunc, order, 5));
+
+  // Enforce that every tasks are sent before starting to run the main thread
+  // message loop.
+  ASSERT_TRUE(SetEvent(event));
+
+  // Poll for the MessageBox. Don't do this at home! At the speed we do it,
+  // you will never realize one MessageBox was shown.
+  for (; expect_window;) {
+    HWND window = FindWindow(L"#32770", kMessageBoxTitle);
+    if (window) {
+      // Dismiss it.
+      for (;;) {
+        HWND button = FindWindowEx(window, NULL, L"Button", NULL);
+        if (button != NULL) {
+          EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
+          EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
+          break;
+        }
+      }
+      break;
+    }
+  }
+}
+
+// TODO(darin): These tests need to be ported since they test critical
+// message loop functionality.
+
+// A side effect of this test is the generation a beep. Sorry.
+void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  Thread worker("RecursiveDenial2_worker");
+  Thread::Options options;
+  options.message_loop_type = message_loop_type;
+  ASSERT_EQ(true, worker.StartWithOptions(options));
+  TaskList order;
+  win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
+  worker.message_loop()->PostTask(FROM_HERE,
+                                  Bind(&RecursiveFuncWin,
+                                             MessageLoop::current(),
+                                             event.Get(),
+                                             true,
+                                             &order,
+                                             false));
+  // Let the other thread execute.
+  WaitForSingleObject(event.Get(), INFINITE);
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(order.Size(), 17);
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
+  // When EndDialogFunc is processed, the window is already dismissed, hence no
+  // "end" entry.
+  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
+  EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
+  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
+}
+
+// A side effect of this test is the generation a beep. Sorry.  This test also
+// needs to process windows messages on the current thread.
+void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  Thread worker("RecursiveSupport2_worker");
+  Thread::Options options;
+  options.message_loop_type = message_loop_type;
+  ASSERT_EQ(true, worker.StartWithOptions(options));
+  TaskList order;
+  win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
+  worker.message_loop()->PostTask(FROM_HERE,
+                                  Bind(&RecursiveFuncWin,
+                                             MessageLoop::current(),
+                                             event.Get(),
+                                             false,
+                                             &order,
+                                             true));
+  // Let the other thread execute.
+  WaitForSingleObject(event.Get(), INFINITE);
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(order.Size(), 18);
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+  // Note that this executes in the MessageBox modal loop.
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
+  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
+  EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
+  /* The order can subtly change here. The reason is that when RecursiveFunc(1)
+     is called in the main thread, if it is faster than getting to the
+     PostTask(FROM_HERE, Bind(&QuitFunc) execution, the order of task
+     execution can change. We don't care anyway that the order isn't correct.
+  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
+  EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  */
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
+}
+
+#endif  // defined(OS_WIN)
+
+void PostNTasksThenQuit(int posts_remaining) {
+  if (posts_remaining > 1) {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&PostNTasksThenQuit, posts_remaining - 1));
+  } else {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+}
+
+#if defined(OS_WIN)
+
+class DispatcherImpl : public MessagePumpDispatcher {
+ public:
+  DispatcherImpl() : dispatch_count_(0) {}
+
+  uint32_t Dispatch(const NativeEvent& msg) override {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+    // Do not count WM_TIMER since it is not what we post and it will cause
+    // flakiness.
+    if (msg.message != WM_TIMER)
+      ++dispatch_count_;
+    // We treat WM_LBUTTONUP as the last message.
+    return msg.message == WM_LBUTTONUP ? POST_DISPATCH_QUIT_LOOP
+                                       : POST_DISPATCH_NONE;
+  }
+
+  int dispatch_count_;
+};
+
+void MouseDownUp() {
+  PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
+  PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
+}
+
+void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&MouseDownUp),
+      TimeDelta::FromMilliseconds(100));
+  DispatcherImpl dispatcher;
+  RunLoop run_loop(&dispatcher);
+  run_loop.Run();
+  ASSERT_EQ(2, dispatcher.dispatch_count_);
+}
+
+LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
+  if (code == MessagePumpForUI::kMessageFilterCode) {
+    MSG* msg = reinterpret_cast<MSG*>(lparam);
+    if (msg->message == WM_LBUTTONDOWN)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&MouseDownUp),
+      TimeDelta::FromMilliseconds(100));
+  HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
+                                    MsgFilterProc,
+                                    NULL,
+                                    GetCurrentThreadId());
+  DispatcherImpl dispatcher;
+  RunLoop run_loop(&dispatcher);
+  run_loop.Run();
+  ASSERT_EQ(1, dispatcher.dispatch_count_);
+  UnhookWindowsHookEx(msg_hook);
+}
+
+class TestIOHandler : public MessageLoopForIO::IOHandler {
+ public:
+  TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
+
+  void OnIOCompleted(MessageLoopForIO::IOContext* context,
+                     DWORD bytes_transfered,
+                     DWORD error) override;
+
+  void Init();
+  void WaitForIO();
+  OVERLAPPED* context() { return &context_.overlapped; }
+  DWORD size() { return sizeof(buffer_); }
+
+ private:
+  char buffer_[48];
+  MessageLoopForIO::IOContext context_;
+  HANDLE signal_;
+  win::ScopedHandle file_;
+  bool wait_;
+};
+
+TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
+    : signal_(signal), wait_(wait) {
+  memset(buffer_, 0, sizeof(buffer_));
+  memset(&context_, 0, sizeof(context_));
+  context_.handler = this;
+
+  file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+                       FILE_FLAG_OVERLAPPED, NULL));
+  EXPECT_TRUE(file_.IsValid());
+}
+
+void TestIOHandler::Init() {
+  MessageLoopForIO::current()->RegisterIOHandler(file_.Get(), this);
+
+  DWORD read;
+  EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context()));
+  EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+  if (wait_)
+    WaitForIO();
+}
+
+void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
+                                  DWORD bytes_transfered, DWORD error) {
+  ASSERT_TRUE(context == &context_);
+  ASSERT_TRUE(SetEvent(signal_));
+}
+
+void TestIOHandler::WaitForIO() {
+  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
+  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
+}
+
+void RunTest_IOHandler() {
+  win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
+  ASSERT_TRUE(callback_called.IsValid());
+
+  const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
+  win::ScopedHandle server(
+      CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  ASSERT_TRUE(server.IsValid());
+
+  Thread thread("IOHandler test");
+  Thread::Options options;
+  options.message_loop_type = MessageLoop::TYPE_IO;
+  ASSERT_TRUE(thread.StartWithOptions(options));
+
+  MessageLoop* thread_loop = thread.message_loop();
+  ASSERT_TRUE(NULL != thread_loop);
+
+  TestIOHandler handler(kPipeName, callback_called.Get(), false);
+  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
+                                              Unretained(&handler)));
+  // Make sure the thread runs and sleeps for lack of work.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+
+  const char buffer[] = "Hello there!";
+  DWORD written;
+  EXPECT_TRUE(WriteFile(server.Get(), buffer, sizeof(buffer), &written, NULL));
+
+  DWORD result = WaitForSingleObject(callback_called.Get(), 1000);
+  EXPECT_EQ(WAIT_OBJECT_0, result);
+
+  thread.Stop();
+}
+
+void RunTest_WaitForIO() {
+  win::ScopedHandle callback1_called(
+      CreateEvent(NULL, TRUE, FALSE, NULL));
+  win::ScopedHandle callback2_called(
+      CreateEvent(NULL, TRUE, FALSE, NULL));
+  ASSERT_TRUE(callback1_called.IsValid());
+  ASSERT_TRUE(callback2_called.IsValid());
+
+  const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
+  const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
+  win::ScopedHandle server1(
+      CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  win::ScopedHandle server2(
+      CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  ASSERT_TRUE(server1.IsValid());
+  ASSERT_TRUE(server2.IsValid());
+
+  Thread thread("IOHandler test");
+  Thread::Options options;
+  options.message_loop_type = MessageLoop::TYPE_IO;
+  ASSERT_TRUE(thread.StartWithOptions(options));
+
+  MessageLoop* thread_loop = thread.message_loop();
+  ASSERT_TRUE(NULL != thread_loop);
+
+  TestIOHandler handler1(kPipeName1, callback1_called.Get(), false);
+  TestIOHandler handler2(kPipeName2, callback2_called.Get(), true);
+  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
+                                              Unretained(&handler1)));
+  // TODO(ajwong): Do we really need such long Sleeps in ths function?
+  // Make sure the thread runs and sleeps for lack of work.
+  TimeDelta delay = TimeDelta::FromMilliseconds(100);
+  PlatformThread::Sleep(delay);
+  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
+                                              Unretained(&handler2)));
+  PlatformThread::Sleep(delay);
+
+  // At this time handler1 is waiting to be called, and the thread is waiting
+  // on the Init method of handler2, filtering only handler2 callbacks.
+
+  const char buffer[] = "Hello there!";
+  DWORD written;
+  EXPECT_TRUE(WriteFile(server1.Get(), buffer, sizeof(buffer), &written, NULL));
+  PlatformThread::Sleep(2 * delay);
+  EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called.Get(), 0)) <<
+      "handler1 has not been called";
+
+  EXPECT_TRUE(WriteFile(server2.Get(), buffer, sizeof(buffer), &written, NULL));
+
+  HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
+  DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
+  EXPECT_EQ(WAIT_OBJECT_0, result);
+
+  thread.Stop();
+}
+
+#endif  // defined(OS_WIN)
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop.  That way we are sure
+// that message loops work properly in all configurations.  Of course, in some
+// cases, a unit test may only be for a particular type of loop.
+
+RUN_MESSAGE_LOOP_TESTS(Default, &TypeDefaultMessagePumpFactory);
+RUN_MESSAGE_LOOP_TESTS(UI, &TypeUIMessagePumpFactory);
+RUN_MESSAGE_LOOP_TESTS(IO, &TypeIOMessagePumpFactory);
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
+  RunTest_PostDelayedTask_SharedTimer_SubPump();
+}
+
+// This test occasionally hangs http://crbug.com/44567
+TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveSupport2) {
+  // This test requires a UI loop
+  RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
+}
+#endif  // defined(OS_WIN)
+
+class DummyTaskObserver : public MessageLoop::TaskObserver {
+ public:
+  explicit DummyTaskObserver(int num_tasks)
+      : num_tasks_started_(0),
+        num_tasks_processed_(0),
+        num_tasks_(num_tasks) {}
+
+  ~DummyTaskObserver() override {}
+
+  void WillProcessTask(const PendingTask& pending_task) override {
+    num_tasks_started_++;
+    EXPECT_LE(num_tasks_started_, num_tasks_);
+    EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
+  }
+
+  void DidProcessTask(const PendingTask& pending_task) override {
+    num_tasks_processed_++;
+    EXPECT_LE(num_tasks_started_, num_tasks_);
+    EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
+  }
+
+  int num_tasks_started() const { return num_tasks_started_; }
+  int num_tasks_processed() const { return num_tasks_processed_; }
+
+ private:
+  int num_tasks_started_;
+  int num_tasks_processed_;
+  const int num_tasks_;
+
+  DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
+};
+
+TEST(MessageLoopTest, TaskObserver) {
+  const int kNumPosts = 6;
+  DummyTaskObserver observer(kNumPosts);
+
+  MessageLoop loop;
+  loop.AddTaskObserver(&observer);
+  loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumPosts));
+  loop.Run();
+  loop.RemoveTaskObserver(&observer);
+
+  EXPECT_EQ(kNumPosts, observer.num_tasks_started());
+  EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, Dispatcher) {
+  // This test requires a UI loop
+  RunTest_Dispatcher(MessageLoop::TYPE_UI);
+}
+
+TEST(MessageLoopTest, DispatcherWithMessageHook) {
+  // This test requires a UI loop
+  RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
+}
+
+TEST(MessageLoopTest, IOHandler) {
+  RunTest_IOHandler();
+}
+
+TEST(MessageLoopTest, WaitForIO) {
+  RunTest_WaitForIO();
+}
+
+TEST(MessageLoopTest, HighResolutionTimer) {
+  MessageLoop loop;
+  Time::EnableHighResolutionTimer(true);
+
+  const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
+  const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
+
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  // Post a fast task to enable the high resolution timers.
+  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
+                       kFastTimer);
+  EXPECT_TRUE(loop.HasHighResolutionTasks());
+  loop.Run();
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  EXPECT_FALSE(Time::IsHighResolutionTimerInUse());
+  // Check that a slow task does not trigger the high resolution logic.
+  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
+                       kSlowTimer);
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  loop.Run();
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  Time::EnableHighResolutionTimer(false);
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+
+namespace {
+
+class QuitDelegate : public MessageLoopForIO::Watcher {
+ public:
+  void OnFileCanWriteWithoutBlocking(int fd) override {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+  void OnFileCanReadWithoutBlocking(int fd) override {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+};
+
+TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
+  // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
+  // This could happen when people use the Singleton pattern or atexit.
+
+  // Create a file descriptor.  Doesn't need to be readable or writable,
+  // as we don't need to actually get any notifications.
+  // pipe() is just the easiest way to do it.
+  int pipefds[2];
+  int err = pipe(pipefds);
+  ASSERT_EQ(0, err);
+  int fd = pipefds[1];
+  {
+    // Arrange for controller to live longer than message loop.
+    MessageLoopForIO::FileDescriptorWatcher controller;
+    {
+      MessageLoopForIO message_loop;
+
+      QuitDelegate delegate;
+      message_loop.WatchFileDescriptor(fd,
+          true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
+      // and don't run the message loop, just destroy it.
+    }
+  }
+  if (IGNORE_EINTR(close(pipefds[0])) < 0)
+    PLOG(ERROR) << "close";
+  if (IGNORE_EINTR(close(pipefds[1])) < 0)
+    PLOG(ERROR) << "close";
+}
+
+TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
+  // Verify that it's ok to call StopWatchingFileDescriptor().
+  // (Errors only showed up in valgrind.)
+  int pipefds[2];
+  int err = pipe(pipefds);
+  ASSERT_EQ(0, err);
+  int fd = pipefds[1];
+  {
+    // Arrange for message loop to live longer than controller.
+    MessageLoopForIO message_loop;
+    {
+      MessageLoopForIO::FileDescriptorWatcher controller;
+
+      QuitDelegate delegate;
+      message_loop.WatchFileDescriptor(fd,
+          true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
+      controller.StopWatchingFileDescriptor();
+    }
+  }
+  if (IGNORE_EINTR(close(pipefds[0])) < 0)
+    PLOG(ERROR) << "close";
+  if (IGNORE_EINTR(close(pipefds[1])) < 0)
+    PLOG(ERROR) << "close";
+}
+
+}  // namespace
+
+#endif  // defined(OS_POSIX) && !defined(OS_NACL)
+
+namespace {
+// Inject a test point for recording the destructor calls for Closure objects
+// send to MessageLoop::PostTask(). It is awkward usage since we are trying to
+// hook the actual destruction, which is not a common operation.
+class DestructionObserverProbe :
+  public RefCounted<DestructionObserverProbe> {
+ public:
+  DestructionObserverProbe(bool* task_destroyed,
+                           bool* destruction_observer_called)
+      : task_destroyed_(task_destroyed),
+        destruction_observer_called_(destruction_observer_called) {
+  }
+  virtual void Run() {
+    // This task should never run.
+    ADD_FAILURE();
+  }
+ private:
+  friend class RefCounted<DestructionObserverProbe>;
+
+  virtual ~DestructionObserverProbe() {
+    EXPECT_FALSE(*destruction_observer_called_);
+    *task_destroyed_ = true;
+  }
+
+  bool* task_destroyed_;
+  bool* destruction_observer_called_;
+};
+
+class MLDestructionObserver : public MessageLoop::DestructionObserver {
+ public:
+  MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
+      : task_destroyed_(task_destroyed),
+        destruction_observer_called_(destruction_observer_called),
+        task_destroyed_before_message_loop_(false) {
+  }
+  void WillDestroyCurrentMessageLoop() override {
+    task_destroyed_before_message_loop_ = *task_destroyed_;
+    *destruction_observer_called_ = true;
+  }
+  bool task_destroyed_before_message_loop() const {
+    return task_destroyed_before_message_loop_;
+  }
+ private:
+  bool* task_destroyed_;
+  bool* destruction_observer_called_;
+  bool task_destroyed_before_message_loop_;
+};
+
+}  // namespace
+
+TEST(MessageLoopTest, DestructionObserverTest) {
+  // Verify that the destruction observer gets called at the very end (after
+  // all the pending tasks have been destroyed).
+  MessageLoop* loop = new MessageLoop;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  bool task_destroyed = false;
+  bool destruction_observer_called = false;
+
+  MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
+  loop->AddDestructionObserver(&observer);
+  loop->PostDelayedTask(
+      FROM_HERE,
+      Bind(&DestructionObserverProbe::Run,
+                 new DestructionObserverProbe(&task_destroyed,
+                                              &destruction_observer_called)),
+      kDelay);
+  delete loop;
+  EXPECT_TRUE(observer.task_destroyed_before_message_loop());
+  // The task should have been destroyed when we deleted the loop.
+  EXPECT_TRUE(task_destroyed);
+  EXPECT_TRUE(destruction_observer_called);
+}
+
+
+// Verify that MessageLoop sets ThreadMainTaskRunner::current() and it
+// posts tasks on that message loop.
+TEST(MessageLoopTest, ThreadMainTaskRunner) {
+  MessageLoop loop;
+
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a");
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(
+      &Foo::Test1ConstRef, foo.get(), a));
+
+  // Post quit task;
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &MessageLoop::Quit, Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(foo->test_count(), 1);
+  EXPECT_EQ(foo->result(), "a");
+}
+
+TEST(MessageLoopTest, IsType) {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+  EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI));
+  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO));
+  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT));
+}
+
+#if defined(OS_WIN)
+void EmptyFunction() {}
+
+void PostMultipleTasks() {
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction));
+}
+
+static const int kSignalMsg = WM_USER + 2;
+
+void PostWindowsMessage(HWND message_hwnd) {
+  PostMessage(message_hwnd, kSignalMsg, 0, 2);
+}
+
+void EndTest(bool* did_run, HWND hwnd) {
+  *did_run = true;
+  PostMessage(hwnd, WM_CLOSE, 0, 0);
+}
+
+int kMyMessageFilterCode = 0x5002;
+
+LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message,
+                                  WPARAM wparam, LPARAM lparam) {
+  if (message == WM_CLOSE)
+    EXPECT_TRUE(DestroyWindow(hwnd));
+  if (message != kSignalMsg)
+    return DefWindowProc(hwnd, message, wparam, lparam);
+
+  switch (lparam) {
+  case 1:
+    // First, we post a task that will post multiple no-op tasks to make sure
+    // that the pump's incoming task queue does not become empty during the
+    // test.
+    MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&PostMultipleTasks));
+    // Next, we post a task that posts a windows message to trigger the second
+    // stage of the test.
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     base::Bind(&PostWindowsMessage, hwnd));
+    break;
+  case 2:
+    // Since we're about to enter a modal loop, tell the message loop that we
+    // intend to nest tasks.
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    bool did_run = false;
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     base::Bind(&EndTest, &did_run, hwnd));
+    // Run a nested windows-style message loop and verify that our task runs. If
+    // it doesn't, then we'll loop here until the test times out.
+    MSG msg;
+    while (GetMessage(&msg, 0, 0, 0)) {
+      if (!CallMsgFilter(&msg, kMyMessageFilterCode))
+        DispatchMessage(&msg);
+      // If this message is a WM_CLOSE, explicitly exit the modal loop. Posting
+      // a WM_QUIT should handle this, but unfortunately MessagePumpWin eats
+      // WM_QUIT messages even when running inside a modal loop.
+      if (msg.message == WM_CLOSE)
+        break;
+    }
+    EXPECT_TRUE(did_run);
+    MessageLoop::current()->Quit();
+    break;
+  }
+  return 0;
+}
+
+TEST(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+  HINSTANCE instance = GetModuleFromAddress(&TestWndProcThunk);
+  WNDCLASSEX wc = {0};
+  wc.cbSize = sizeof(wc);
+  wc.lpfnWndProc = TestWndProcThunk;
+  wc.hInstance = instance;
+  wc.lpszClassName = L"MessageLoopTest_HWND";
+  ATOM atom = RegisterClassEx(&wc);
+  ASSERT_TRUE(atom);
+
+  HWND message_hwnd = CreateWindow(MAKEINTATOM(atom), 0, 0, 0, 0, 0, 0,
+                                   HWND_MESSAGE, 0, instance, 0);
+  ASSERT_TRUE(message_hwnd) << GetLastError();
+
+  ASSERT_TRUE(PostMessage(message_hwnd, kSignalMsg, 0, 1));
+
+  loop.Run();
+
+  ASSERT_TRUE(UnregisterClass(MAKEINTATOM(atom), instance));
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace base
diff --git a/base/message_loop/message_pump.cc b/base/message_loop/message_pump.cc
new file mode 100644
index 0000000..3d85b9b
--- /dev/null
+++ b/base/message_loop/message_pump.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump.h"
+
+namespace base {
+
+MessagePump::MessagePump() {
+}
+
+MessagePump::~MessagePump() {
+}
+
+void MessagePump::SetTimerSlack(TimerSlack) {
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
new file mode 100644
index 0000000..a2edb45
--- /dev/null
+++ b/base/message_loop/message_pump.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace base {
+
+class TimeTicks;
+
+class BASE_EXPORT MessagePump : public NonThreadSafe {
+ public:
+  // Please see the comments above the Run method for an illustration of how
+  // these delegate methods are used.
+  class BASE_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Called from within Run in response to ScheduleWork or when the message
+    // pump would otherwise call DoDelayedWork.  Returns true to indicate that
+    // work was done.  DoDelayedWork will still be called if DoWork returns
+    // true, but DoIdleWork will not.
+    virtual bool DoWork() = 0;
+
+    // Called from within Run in response to ScheduleDelayedWork or when the
+    // message pump would otherwise sleep waiting for more work.  Returns true
+    // to indicate that delayed work was done.  DoIdleWork will not be called
+    // if DoDelayedWork returns true.  Upon return |next_delayed_work_time|
+    // indicates the time when DoDelayedWork should be called again.  If
+    // |next_delayed_work_time| is null (per Time::is_null), then the queue of
+    // future delayed work (timer events) is currently empty, and no additional
+    // calls to this function need to be scheduled.
+    virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
+
+    // Called from within Run just before the message pump goes to sleep.
+    // Returns true to indicate that idle work was done. Returning false means
+    // the pump will now wait.
+    virtual bool DoIdleWork() = 0;
+  };
+
+  MessagePump();
+  virtual ~MessagePump();
+
+  // The Run method is called to enter the message pump's run loop.
+  //
+  // Within the method, the message pump is responsible for processing native
+  // messages as well as for giving cycles to the delegate periodically.  The
+  // message pump should take care to mix delegate callbacks with native
+  // message processing so neither type of event starves the other of cycles.
+  //
+  // The anatomy of a typical run loop:
+  //
+  //   for (;;) {
+  //     bool did_work = DoInternalWork();
+  //     if (should_quit_)
+  //       break;
+  //
+  //     did_work |= delegate_->DoWork();
+  //     if (should_quit_)
+  //       break;
+  //
+  //     TimeTicks next_time;
+  //     did_work |= delegate_->DoDelayedWork(&next_time);
+  //     if (should_quit_)
+  //       break;
+  //
+  //     if (did_work)
+  //       continue;
+  //
+  //     did_work = delegate_->DoIdleWork();
+  //     if (should_quit_)
+  //       break;
+  //
+  //     if (did_work)
+  //       continue;
+  //
+  //     WaitForWork();
+  //   }
+  //
+  // Here, DoInternalWork is some private method of the message pump that is
+  // responsible for dispatching the next UI message or notifying the next IO
+  // completion (for example).  WaitForWork is a private method that simply
+  // blocks until there is more work of any type to do.
+  //
+  // Notice that the run loop cycles between calling DoInternalWork, DoWork,
+  // and DoDelayedWork methods.  This helps ensure that none of these work
+  // queues starve the others.  This is important for message pumps that are
+  // used to drive animations, for example.
+  //
+  // Notice also that after each callout to foreign code, the run loop checks
+  // to see if it should quit.  The Quit method is responsible for setting this
+  // flag.  No further work is done once the quit flag is set.
+  //
+  // NOTE: Care must be taken to handle Run being called again from within any
+  // of the callouts to foreign code.  Native message pumps may also need to
+  // deal with other native message pumps being run outside their control
+  // (e.g., the MessageBox API on Windows pumps UI messages!).  To be specific,
+  // the callouts (DoWork and DoDelayedWork) MUST still be provided even in
+  // nested sub-loops that are "seemingly" outside the control of this message
+  // pump.  DoWork in particular must never be starved for time slices unless
+  // it returns false (meaning it has run out of things to do).
+  //
+  virtual void Run(Delegate* delegate) = 0;
+
+  // Quit immediately from the most recently entered run loop.  This method may
+  // only be used on the thread that called Run.
+  virtual void Quit() = 0;
+
+  // Schedule a DoWork callback to happen reasonably soon.  Does nothing if a
+  // DoWork callback is already scheduled.  This method may be called from any
+  // thread.  Once this call is made, DoWork should not be "starved" at least
+  // until it returns a value of false.
+  virtual void ScheduleWork() = 0;
+
+  // Schedule a DoDelayedWork callback to happen at the specified time,
+  // cancelling any pending DoDelayedWork callback.  This method may only be
+  // used on the thread that called Run.
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
+
+  // Sets the timer slack to the specified value.
+  virtual void SetTimerSlack(TimerSlack timer_slack);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc
new file mode 100644
index 0000000..babd17b
--- /dev/null
+++ b/base/message_loop/message_pump_android.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_android.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "jni/SystemMessageHandler_jni.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// ----------------------------------------------------------------------------
+// Native JNI methods called by Java.
+// ----------------------------------------------------------------------------
+// This method can not move to anonymous namespace as it has been declared as
+// 'static' in system_message_handler_jni.h.
+static void DoRunLoopOnce(JNIEnv* env, jobject obj, jlong native_delegate,
+    jlong delayed_scheduled_time_ticks) {
+  base::MessagePump::Delegate* delegate =
+      reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
+  DCHECK(delegate);
+  // This is based on MessagePumpForUI::DoRunLoop() from desktop.
+  // Note however that our system queue is handled in the java side.
+  // In desktop we inspect and process a single system message and then
+  // we call DoWork() / DoDelayedWork().
+  // On Android, the java message queue may contain messages for other handlers
+  // that will be processed before calling here again.
+  bool did_work = delegate->DoWork();
+
+  // In the java side, |SystemMessageHandler| keeps a single "delayed" message.
+  // It's an expensive operation to |removeMessage| there, so this is optimized
+  // to avoid those calls.
+  //
+  // At this stage, |next_delayed_work_time| can be:
+  // 1) The same as previously scheduled: nothing to be done, move along. This
+  // is the typical case, since this method is called for every single message.
+  //
+  // 2) Not previously scheduled: just post a new message in java.
+  //
+  // 3) Shorter than previously scheduled: far less common. In this case,
+  // |removeMessage| and post a new one.
+  //
+  // 4) Longer than previously scheduled (or null): nothing to be done, move
+  // along.
+  //
+  // Side note: base::TimeTicks is a C++ representation and can't be
+  // compared in java. When calling |scheduleDelayedWork|, pass the
+  // |InternalValue()| to java and then back to C++ so the comparisons can be
+  // done here.
+  // This roundtrip allows comparing TimeTicks directly (cheap) and
+  // avoid comparisons with TimeDelta / Now() (expensive).
+  base::TimeTicks next_delayed_work_time;
+  did_work |= delegate->DoDelayedWork(&next_delayed_work_time);
+
+  if (!next_delayed_work_time.is_null()) {
+    // Schedule a new message if there's nothing already scheduled or there's a
+    // shorter delay than previously scheduled (see (2) and (3) above).
+    if (delayed_scheduled_time_ticks == 0 ||
+        next_delayed_work_time < base::TimeTicks::FromInternalValue(
+            delayed_scheduled_time_ticks)) {
+      Java_SystemMessageHandler_scheduleDelayedWork(env, obj,
+          next_delayed_work_time.ToInternalValue(),
+          (next_delayed_work_time -
+           base::TimeTicks::Now()).InMillisecondsRoundedUp());
+    }
+  }
+
+  // This is a major difference between android and other platforms: since we
+  // can't inspect it and process just one single message, instead we'll yeld
+  // the callstack.
+  if (did_work)
+    return;
+
+  delegate->DoIdleWork();
+}
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+    : run_loop_(NULL) {
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+  NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
+      " test_stub_android.h";
+}
+
+void MessagePumpForUI::Start(Delegate* delegate) {
+  run_loop_ = new RunLoop();
+  // Since the RunLoop was just created above, BeforeRun should be guaranteed to
+  // return true (it only returns false if the RunLoop has been Quit already).
+  if (!run_loop_->BeforeRun())
+    NOTREACHED();
+
+  DCHECK(system_message_handler_obj_.is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  system_message_handler_obj_.Reset(
+      Java_SystemMessageHandler_create(
+          env, reinterpret_cast<intptr_t>(delegate)));
+}
+
+void MessagePumpForUI::Quit() {
+  if (!system_message_handler_obj_.is_null()) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    DCHECK(env);
+
+    Java_SystemMessageHandler_removeAllPendingMessages(env,
+        system_message_handler_obj_.obj());
+    system_message_handler_obj_.Reset();
+  }
+
+  if (run_loop_) {
+    run_loop_->AfterRun();
+    delete run_loop_;
+    run_loop_ = NULL;
+  }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  DCHECK(!system_message_handler_obj_.is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_SystemMessageHandler_scheduleWork(env,
+      system_message_handler_obj_.obj());
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  DCHECK(!system_message_handler_obj_.is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  jlong millis =
+      (delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp();
+  // Note that we're truncating to milliseconds as required by the java side,
+  // even though delayed_work_time is microseconds resolution.
+  Java_SystemMessageHandler_scheduleDelayedWork(env,
+      system_message_handler_obj_.obj(),
+      delayed_work_time.ToInternalValue(), millis);
+}
+
+// static
+bool MessagePumpForUI::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h
new file mode 100644
index 0000000..d48050d
--- /dev/null
+++ b/base/message_loop/message_pump_android.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_pump.h"
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// OS_ANDROID platform.
+class BASE_EXPORT MessagePumpForUI : public MessagePump {
+ public:
+  MessagePumpForUI();
+  ~MessagePumpForUI() override;
+
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+  virtual void Start(Delegate* delegate);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  RunLoop* run_loop_;
+  base::android::ScopedJavaGlobalRef<jobject> system_message_handler_obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc
new file mode 100644
index 0000000..27c19e0
--- /dev/null
+++ b/base/message_loop/message_pump_default.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_default.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace base {
+
+MessagePumpDefault::MessagePumpDefault()
+    : keep_running_(true),
+      event_(false, false) {
+}
+
+MessagePumpDefault::~MessagePumpDefault() {
+}
+
+void MessagePumpDefault::Run(Delegate* delegate) {
+  DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+
+  for (;;) {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+    bool did_work = delegate->DoWork();
+    if (!keep_running_)
+      break;
+
+    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    did_work = delegate->DoIdleWork();
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    ThreadRestrictions::ScopedAllowWait allow_wait;
+    if (delayed_work_time_.is_null()) {
+      event_.Wait();
+    } else {
+      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        event_.TimedWait(delay);
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = TimeTicks();
+      }
+    }
+    // Since event_ is auto-reset, we don't need to do anything special here
+    // other than service each delegate method.
+  }
+
+  keep_running_ = true;
+}
+
+void MessagePumpDefault::Quit() {
+  keep_running_ = false;
+}
+
+void MessagePumpDefault::ScheduleWork() {
+  // Since this can be called on any thread, we need to ensure that our Run
+  // loop wakes up.
+  event_.Signal();
+}
+
+void MessagePumpDefault::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h
new file mode 100644
index 0000000..8aeaa62
--- /dev/null
+++ b/base/message_loop/message_pump_default.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+
+#include "base/base_export.h"
+#include "base/message_loop/message_pump.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BASE_EXPORT MessagePumpDefault : public MessagePump {
+ public:
+  MessagePumpDefault();
+  ~MessagePumpDefault() override;
+
+  // MessagePump methods:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  // This flag is set to false when Run should return.
+  bool keep_running_;
+
+  // Used to sleep until there is more work to do.
+  WaitableEvent event_;
+
+  // The time at which we should call DoDelayedWork.
+  TimeTicks delayed_work_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
diff --git a/base/message_loop/message_pump_dispatcher.h b/base/message_loop/message_pump_dispatcher.h
new file mode 100644
index 0000000..5b1bd55
--- /dev/null
+++ b/base/message_loop/message_pump_dispatcher.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/event_types.h"
+
+namespace base {
+
+// Dispatcher is used during a nested invocation of Run to dispatch events when
+// |RunLoop(dispatcher).Run()| is used.  If |RunLoop().Run()| is invoked,
+// MessageLoop does not dispatch events (or invoke TranslateMessage), rather
+// every message is passed to Dispatcher's Dispatch method for dispatch. It is
+// up to the Dispatcher whether or not to dispatch the event.
+//
+// The nested loop is exited by either posting a quit, or setting the
+// POST_DISPATCH_QUIT_LOOP flag on the return value from Dispatch.
+class BASE_EXPORT MessagePumpDispatcher {
+ public:
+  enum PostDispatchAction {
+    POST_DISPATCH_NONE = 0x0,
+    POST_DISPATCH_QUIT_LOOP = 0x1,
+    POST_DISPATCH_PERFORM_DEFAULT = 0x2,
+  };
+
+  virtual ~MessagePumpDispatcher() {}
+
+  // Dispatches the event. The return value can have more than one
+  // PostDispatchAction flags OR'ed together. If POST_DISPATCH_PERFORM_DEFAULT
+  // is set in the returned value, then the message-pump performs the default
+  // action. If POST_DISPATCH_QUIT_LOOP is set, in the return value, then the
+  // nested loop exits immediately.
+  virtual uint32_t Dispatch(const NativeEvent& event) = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc
new file mode 100644
index 0000000..f06f60d
--- /dev/null
+++ b/base/message_loop/message_pump_glib.cc
@@ -0,0 +1,363 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_glib.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+// Return a timeout suitable for the glib loop, -1 to block forever,
+// 0 to return right away, or a timeout in milliseconds from now.
+int GetTimeIntervalMilliseconds(const TimeTicks& from) {
+  if (from.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  int delay = static_cast<int>(
+      ceil((from - TimeTicks::Now()).InMillisecondsF()));
+
+  // If this value is negative, then we need to run delayed work soon.
+  return delay < 0 ? 0 : delay;
+}
+
+// A brief refresher on GLib:
+//     GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
+// On each iteration of the GLib pump, it calls each source's Prepare function.
+// This function should return TRUE if it wants GLib to call its Dispatch, and
+// FALSE otherwise.  It can also set a timeout in this case for the next time
+// Prepare should be called again (it may be called sooner).
+//     After the Prepare calls, GLib does a poll to check for events from the
+// system.  File descriptors can be attached to the sources.  The poll may block
+// if none of the Prepare calls returned TRUE.  It will block indefinitely, or
+// by the minimum time returned by a source in Prepare.
+//     After the poll, GLib calls Check for each source that returned FALSE
+// from Prepare.  The return value of Check has the same meaning as for Prepare,
+// making Check a second chance to tell GLib we are ready for Dispatch.
+//     Finally, GLib calls Dispatch for each source that is ready.  If Dispatch
+// returns FALSE, GLib will destroy the source.  Dispatch calls may be recursive
+// (i.e., you can call Run from them), but Prepare and Check cannot.
+//     Finalize is called when the source is destroyed.
+// NOTE: It is common for subsytems to want to process pending events while
+// doing intensive work, for example the flash plugin. They usually use the
+// following pattern (recommended by the GTK docs):
+// while (gtk_events_pending()) {
+//   gtk_main_iteration();
+// }
+//
+// gtk_events_pending just calls g_main_context_pending, which does the
+// following:
+// - Call prepare on all the sources.
+// - Do the poll with a timeout of 0 (not blocking).
+// - Call check on all the sources.
+// - *Does not* call dispatch on the sources.
+// - Return true if any of prepare() or check() returned true.
+//
+// gtk_main_iteration just calls g_main_context_iteration, which does the whole
+// thing, respecting the timeout for the poll (and block, although it is
+// expected not to if gtk_events_pending returned true), and call dispatch.
+//
+// Thus it is important to only return true from prepare or check if we
+// actually have events or work to do. We also need to make sure we keep
+// internal state consistent so that if prepare/check return true when called
+// from gtk_events_pending, they will still return true when called right
+// after, from gtk_main_iteration.
+//
+// For the GLib pump we try to follow the Windows UI pump model:
+// - Whenever we receive a wakeup event or the timer for delayed work expires,
+// we run DoWork and/or DoDelayedWork. That part will also run in the other
+// event pumps.
+// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main
+// loop, around event handling.
+
+struct WorkSource : public GSource {
+  MessagePumpGlib* pump;
+};
+
+gboolean WorkSourcePrepare(GSource* source,
+                           gint* timeout_ms) {
+  *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare();
+  // We always return FALSE, so that our timeout is honored.  If we were
+  // to return TRUE, the timeout would be considered to be 0 and the poll
+  // would never block.  Once the poll is finished, Check will be called.
+  return FALSE;
+}
+
+gboolean WorkSourceCheck(GSource* source) {
+  // Only return TRUE if Dispatch should be called.
+  return static_cast<WorkSource*>(source)->pump->HandleCheck();
+}
+
+gboolean WorkSourceDispatch(GSource* source,
+                            GSourceFunc unused_func,
+                            gpointer unused_data) {
+
+  static_cast<WorkSource*>(source)->pump->HandleDispatch();
+  // Always return TRUE so our source stays registered.
+  return TRUE;
+}
+
+// I wish these could be const, but g_source_new wants non-const.
+GSourceFuncs WorkSourceFuncs = {
+  WorkSourcePrepare,
+  WorkSourceCheck,
+  WorkSourceDispatch,
+  NULL
+};
+
+// The following is used to make sure we only run the MessagePumpGlib on one
+// thread. X only has one message pump so we can only have one UI loop per
+// process.
+#ifndef NDEBUG
+
+// Tracks the pump the most recent pump that has been run.
+struct ThreadInfo {
+  // The pump.
+  MessagePumpGlib* pump;
+
+  // ID of the thread the pump was run on.
+  PlatformThreadId thread_id;
+};
+
+// Used for accesing |thread_info|.
+static LazyInstance<Lock>::Leaky thread_info_lock = LAZY_INSTANCE_INITIALIZER;
+
+// If non-NULL it means a MessagePumpGlib exists and has been Run. This is
+// destroyed when the MessagePump is destroyed.
+ThreadInfo* thread_info = NULL;
+
+void CheckThread(MessagePumpGlib* pump) {
+  AutoLock auto_lock(thread_info_lock.Get());
+  if (!thread_info) {
+    thread_info = new ThreadInfo;
+    thread_info->pump = pump;
+    thread_info->thread_id = PlatformThread::CurrentId();
+  }
+  DCHECK(thread_info->thread_id == PlatformThread::CurrentId()) <<
+      "Running MessagePumpGlib on two different threads; "
+      "this is unsupported by GLib!";
+}
+
+void PumpDestroyed(MessagePumpGlib* pump) {
+  AutoLock auto_lock(thread_info_lock.Get());
+  if (thread_info && thread_info->pump == pump) {
+    delete thread_info;
+    thread_info = NULL;
+  }
+}
+
+#endif
+
+}  // namespace
+
+struct MessagePumpGlib::RunState {
+  Delegate* delegate;
+
+  // Used to flag that the current Run() invocation should return ASAP.
+  bool should_quit;
+
+  // Used to count how many Run() invocations are on the stack.
+  int run_depth;
+
+  // This keeps the state of whether the pump got signaled that there was new
+  // work to be done. Since we eat the message on the wake up pipe as soon as
+  // we get it, we keep that state here to stay consistent.
+  bool has_work;
+};
+
+MessagePumpGlib::MessagePumpGlib()
+    : state_(NULL),
+      context_(g_main_context_default()),
+      wakeup_gpollfd_(new GPollFD) {
+  // Create our wakeup pipe, which is used to flag when work was scheduled.
+  int fds[2];
+  int ret = pipe(fds);
+  DCHECK_EQ(ret, 0);
+  (void)ret;  // Prevent warning in release mode.
+
+  wakeup_pipe_read_  = fds[0];
+  wakeup_pipe_write_ = fds[1];
+  wakeup_gpollfd_->fd = wakeup_pipe_read_;
+  wakeup_gpollfd_->events = G_IO_IN;
+
+  work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource));
+  static_cast<WorkSource*>(work_source_)->pump = this;
+  g_source_add_poll(work_source_, wakeup_gpollfd_.get());
+  // Use a low priority so that we let other events in the queue go first.
+  g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE);
+  // This is needed to allow Run calls inside Dispatch.
+  g_source_set_can_recurse(work_source_, TRUE);
+  g_source_attach(work_source_, context_);
+}
+
+MessagePumpGlib::~MessagePumpGlib() {
+#ifndef NDEBUG
+  PumpDestroyed(this);
+#endif
+  g_source_destroy(work_source_);
+  g_source_unref(work_source_);
+  close(wakeup_pipe_read_);
+  close(wakeup_pipe_write_);
+}
+
+// Return the timeout we want passed to poll.
+int MessagePumpGlib::HandlePrepare() {
+  // We know we have work, but we haven't called HandleDispatch yet. Don't let
+  // the pump block so that we can do some processing.
+  if (state_ &&  // state_ may be null during tests.
+      state_->has_work)
+    return 0;
+
+  // We don't think we have work to do, but make sure not to block
+  // longer than the next time we need to run delayed work.
+  return GetTimeIntervalMilliseconds(delayed_work_time_);
+}
+
+bool MessagePumpGlib::HandleCheck() {
+  if (!state_)  // state_ may be null during tests.
+    return false;
+
+  // We usually have a single message on the wakeup pipe, since we are only
+  // signaled when the queue went from empty to non-empty, but there can be
+  // two messages if a task posted a task, hence we read at most two bytes.
+  // The glib poll will tell us whether there was data, so this read
+  // shouldn't block.
+  if (wakeup_gpollfd_->revents & G_IO_IN) {
+    char msg[2];
+    const int num_bytes = HANDLE_EINTR(read(wakeup_pipe_read_, msg, 2));
+    if (num_bytes < 1) {
+      NOTREACHED() << "Error reading from the wakeup pipe.";
+    }
+    DCHECK((num_bytes == 1 && msg[0] == '!') ||
+           (num_bytes == 2 && msg[0] == '!' && msg[1] == '!'));
+    // Since we ate the message, we need to record that we have more work,
+    // because HandleCheck() may be called without HandleDispatch being called
+    // afterwards.
+    state_->has_work = true;
+  }
+
+  if (state_->has_work)
+    return true;
+
+  if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) {
+    // The timer has expired. That condition will stay true until we process
+    // that delayed work, so we don't need to record this differently.
+    return true;
+  }
+
+  return false;
+}
+
+void MessagePumpGlib::HandleDispatch() {
+  state_->has_work = false;
+  if (state_->delegate->DoWork()) {
+    // NOTE: on Windows at this point we would call ScheduleWork (see
+    // MessagePumpGlib::HandleWorkMessage in message_pump_win.cc). But here,
+    // instead of posting a message on the wakeup pipe, we can avoid the
+    // syscalls and just signal that we have more work.
+    state_->has_work = true;
+  }
+
+  if (state_->should_quit)
+    return;
+
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+}
+
+void MessagePumpGlib::Run(Delegate* delegate) {
+#ifndef NDEBUG
+  CheckThread(this);
+#endif
+
+  RunState state;
+  state.delegate = delegate;
+  state.should_quit = false;
+  state.run_depth = state_ ? state_->run_depth + 1 : 1;
+  state.has_work = false;
+
+  RunState* previous_state = state_;
+  state_ = &state;
+
+  // We really only do a single task for each iteration of the loop.  If we
+  // have done something, assume there is likely something more to do.  This
+  // will mean that we don't block on the message pump until there was nothing
+  // more to do.  We also set this to true to make sure not to block on the
+  // first iteration of the loop, so RunUntilIdle() works correctly.
+  bool more_work_is_plausible = true;
+
+  // We run our own loop instead of using g_main_loop_quit in one of the
+  // callbacks.  This is so we only quit our own loops, and we don't quit
+  // nested loops run by others.  TODO(deanm): Is this what we want?
+  for (;;) {
+    // Don't block if we think we have more work to do.
+    bool block = !more_work_is_plausible;
+
+    more_work_is_plausible = g_main_context_iteration(context_, block);
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+  }
+
+  state_ = previous_state;
+}
+
+void MessagePumpGlib::Quit() {
+  if (state_) {
+    state_->should_quit = true;
+  } else {
+    NOTREACHED() << "Quit called outside Run!";
+  }
+}
+
+void MessagePumpGlib::ScheduleWork() {
+  // This can be called on any thread, so we don't want to touch any state
+  // variables as we would then need locks all over.  This ensures that if
+  // we are sleeping in a poll that we will wake up.
+  char msg = '!';
+  if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) {
+    NOTREACHED() << "Could not write to the UI message loop wakeup pipe!";
+  }
+}
+
+void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  // We need to wake up the loop in case the poll timeout needs to be
+  // adjusted.  This will cause us to try to do work, but that's ok.
+  delayed_work_time_ = delayed_work_time;
+  ScheduleWork();
+}
+
+bool MessagePumpGlib::ShouldQuit() const {
+  CHECK(state_);
+  return state_->should_quit;
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h
new file mode 100644
index 0000000..9f44571
--- /dev/null
+++ b/base/message_loop/message_pump_glib.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+
+typedef struct _GMainContext GMainContext;
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+
+namespace base {
+
+// This class implements a base MessagePump needed for TYPE_UI MessageLoops on
+// platforms using GLib.
+class BASE_EXPORT MessagePumpGlib : public MessagePump {
+ public:
+  MessagePumpGlib();
+  ~MessagePumpGlib() override;
+
+  // Internal methods used for processing the pump callbacks.  They are
+  // public for simplicity but should not be used directly.  HandlePrepare
+  // is called during the prepare step of glib, and returns a timeout that
+  // will be passed to the poll. HandleCheck is called after the poll
+  // has completed, and returns whether or not HandleDispatch should be called.
+  // HandleDispatch is called if HandleCheck returned true.
+  int HandlePrepare();
+  bool HandleCheck();
+  void HandleDispatch();
+
+  // Overridden from MessagePump:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  bool ShouldQuit() const;
+
+  // We may make recursive calls to Run, so we save state that needs to be
+  // separate between them in this structure type.
+  struct RunState;
+
+  RunState* state_;
+
+  // This is a GLib structure that we can add event sources to.  We use the
+  // default GLib context, which is the one to which all GTK events are
+  // dispatched.
+  GMainContext* context_;
+
+  // This is the time when we need to do delayed work.
+  TimeTicks delayed_work_time_;
+
+  // The work source.  It is shared by all calls to Run and destroyed when
+  // the message pump is destroyed.
+  GSource* work_source_;
+
+  // We use a wakeup pipe to make sure we'll get out of the glib polling phase
+  // when another thread has scheduled us to do some work.  There is a glib
+  // mechanism g_main_context_wakeup, but this won't guarantee that our event's
+  // Dispatch() will be called.
+  int wakeup_pipe_read_;
+  int wakeup_pipe_write_;
+  // Use a scoped_ptr to avoid needing the definition of GPollFD in the header.
+  scoped_ptr<GPollFD> wakeup_gpollfd_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGlib);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
diff --git a/base/message_loop/message_pump_glib_unittest.cc b/base/message_loop/message_pump_glib_unittest.cc
new file mode 100644
index 0000000..7ddd4f0
--- /dev/null
+++ b/base/message_loop/message_pump_glib_unittest.cc
@@ -0,0 +1,534 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_glib.h"
+
+#include <glib.h>
+#include <math.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// This class injects dummy "events" into the GLib loop. When "handled" these
+// events can run tasks. This is intended to mock gtk events (the corresponding
+// GLib source runs at the same priority).
+class EventInjector {
+ public:
+  EventInjector() : processed_events_(0) {
+    source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
+    source_->injector = this;
+    g_source_attach(source_, NULL);
+    g_source_set_can_recurse(source_, TRUE);
+  }
+
+  ~EventInjector() {
+    g_source_destroy(source_);
+    g_source_unref(source_);
+  }
+
+  int HandlePrepare() {
+    // If the queue is empty, block.
+    if (events_.empty())
+      return -1;
+    TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
+    return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
+  }
+
+  bool HandleCheck() {
+    if (events_.empty())
+      return false;
+    return events_[0].time <= Time::NowFromSystemTime();
+  }
+
+  void HandleDispatch() {
+    if (events_.empty())
+      return;
+    Event event = events_[0];
+    events_.erase(events_.begin());
+    ++processed_events_;
+    if (!event.callback.is_null())
+      event.callback.Run();
+    else if (!event.task.is_null())
+      event.task.Run();
+  }
+
+  // Adds an event to the queue. When "handled", executes |callback|.
+  // delay_ms is relative to the last event if any, or to Now() otherwise.
+  void AddEvent(int delay_ms, const Closure& callback) {
+    AddEventHelper(delay_ms, callback, Closure());
+  }
+
+  void AddDummyEvent(int delay_ms) {
+    AddEventHelper(delay_ms, Closure(), Closure());
+  }
+
+  void AddEventAsTask(int delay_ms, const Closure& task) {
+    AddEventHelper(delay_ms, Closure(), task);
+  }
+
+  void Reset() {
+    processed_events_ = 0;
+    events_.clear();
+  }
+
+  int processed_events() const { return processed_events_; }
+
+ private:
+  struct Event {
+    Time time;
+    Closure callback;
+    Closure task;
+  };
+
+  struct Source : public GSource {
+    EventInjector* injector;
+  };
+
+  void AddEventHelper(
+      int delay_ms, const Closure& callback, const Closure& task) {
+    Time last_time;
+    if (!events_.empty())
+      last_time = (events_.end()-1)->time;
+    else
+      last_time = Time::NowFromSystemTime();
+
+    Time future = last_time + TimeDelta::FromMilliseconds(delay_ms);
+    EventInjector::Event event = {future, callback, task};
+    events_.push_back(event);
+  }
+
+  static gboolean Prepare(GSource* source, gint* timeout_ms) {
+    *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
+    return FALSE;
+  }
+
+  static gboolean Check(GSource* source) {
+    return static_cast<Source*>(source)->injector->HandleCheck();
+  }
+
+  static gboolean Dispatch(GSource* source,
+                           GSourceFunc unused_func,
+                           gpointer unused_data) {
+    static_cast<Source*>(source)->injector->HandleDispatch();
+    return TRUE;
+  }
+
+  Source* source_;
+  std::vector<Event> events_;
+  int processed_events_;
+  static GSourceFuncs SourceFuncs;
+  DISALLOW_COPY_AND_ASSIGN(EventInjector);
+};
+
+GSourceFuncs EventInjector::SourceFuncs = {
+  EventInjector::Prepare,
+  EventInjector::Check,
+  EventInjector::Dispatch,
+  NULL
+};
+
+void IncrementInt(int *value) {
+  ++*value;
+}
+
+// Checks how many events have been processed by the injector.
+void ExpectProcessedEvents(EventInjector* injector, int count) {
+  EXPECT_EQ(injector->processed_events(), count);
+}
+
+// Posts a task on the current message loop.
+void PostMessageLoopTask(const tracked_objects::Location& from_here,
+                         const Closure& task) {
+  MessageLoop::current()->PostTask(from_here, task);
+}
+
+// Test fixture.
+class MessagePumpGLibTest : public testing::Test {
+ public:
+  MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { }
+
+  // Overridden from testing::Test:
+  void SetUp() override {
+    loop_ = new MessageLoop(MessageLoop::TYPE_UI);
+    injector_ = new EventInjector();
+  }
+  void TearDown() override {
+    delete injector_;
+    injector_ = NULL;
+    delete loop_;
+    loop_ = NULL;
+  }
+
+  MessageLoop* loop() const { return loop_; }
+  EventInjector* injector() const { return injector_; }
+
+ private:
+  MessageLoop* loop_;
+  EventInjector* injector_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest);
+};
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestQuit) {
+  // Checks that Quit works and that the basic infrastructure is working.
+
+  // Quit from a task
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(0, injector()->processed_events());
+
+  injector()->Reset();
+  // Quit from an event
+  injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+  EXPECT_EQ(1, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
+  // Checks that tasks posted by events are executed before the next event if
+  // the posted task queue is empty.
+  // MessageLoop doesn't make strong guarantees that it is the case, but the
+  // current implementation ensures it and the tests below rely on it.
+  // If changes cause this test to fail, it is reasonable to change it, but
+  // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
+  // changed accordingly, otherwise they can become flaky.
+  injector()->AddEventAsTask(0, Bind(&DoNothing));
+  Closure check_task =
+      Bind(&ExpectProcessedEvents, Unretained(injector()), 2);
+  Closure posted_task =
+      Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(0, posted_task);
+  injector()->AddEventAsTask(0, Bind(&DoNothing));
+  injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+  EXPECT_EQ(4, injector()->processed_events());
+
+  injector()->Reset();
+  injector()->AddEventAsTask(0, Bind(&DoNothing));
+  check_task =
+      Bind(&ExpectProcessedEvents, Unretained(injector()), 2);
+  posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(0, posted_task);
+  injector()->AddEventAsTask(10, Bind(&DoNothing));
+  injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+  EXPECT_EQ(4, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
+  int task_count = 0;
+  // Tests that we process tasks while waiting for new events.
+  // The event queue is empty at first.
+  for (int i = 0; i < 10; ++i) {
+    loop()->PostTask(FROM_HERE, Bind(&IncrementInt, &task_count));
+  }
+  // After all the previous tasks have executed, enqueue an event that will
+  // quit.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&EventInjector::AddEvent, Unretained(injector()), 0,
+                 MessageLoop::QuitWhenIdleClosure()));
+  loop()->Run();
+  ASSERT_EQ(10, task_count);
+  EXPECT_EQ(1, injector()->processed_events());
+
+  // Tests that we process delayed tasks while waiting for new events.
+  injector()->Reset();
+  task_count = 0;
+  for (int i = 0; i < 10; ++i) {
+    loop()->PostDelayedTask(
+        FROM_HERE,
+        Bind(&IncrementInt, &task_count),
+        TimeDelta::FromMilliseconds(10*i));
+  }
+  // After all the previous tasks have executed, enqueue an event that will
+  // quit.
+  // This relies on the fact that delayed tasks are executed in delay order.
+  // That is verified in message_loop_unittest.cc.
+  loop()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&EventInjector::AddEvent, Unretained(injector()), 10,
+                 MessageLoop::QuitWhenIdleClosure()),
+      TimeDelta::FromMilliseconds(150));
+  loop()->Run();
+  ASSERT_EQ(10, task_count);
+  EXPECT_EQ(1, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
+  // Tests that we process events while waiting for work.
+  // The event queue is empty at first.
+  for (int i = 0; i < 10; ++i) {
+    injector()->AddDummyEvent(0);
+  }
+  // After all the events have been processed, post a task that will check that
+  // the events have been processed (note: the task executes after the event
+  // that posted it has been handled, so we expect 11 at that point).
+  Closure check_task =
+      Bind(&ExpectProcessedEvents, Unretained(injector()), 11);
+  Closure posted_task =
+      Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(10, posted_task);
+
+  // And then quit (relies on the condition tested by TestEventTaskInterleave).
+  injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+
+  EXPECT_EQ(12, injector()->processed_events());
+}
+
+namespace {
+
+// This class is a helper for the concurrent events / posted tasks test below.
+// It will quit the main loop once enough tasks and events have been processed,
+// while making sure there is always work to do and events in the queue.
+class ConcurrentHelper : public RefCounted<ConcurrentHelper>  {
+ public:
+  explicit ConcurrentHelper(EventInjector* injector)
+      : injector_(injector),
+        event_count_(kStartingEventCount),
+        task_count_(kStartingTaskCount) {
+  }
+
+  void FromTask() {
+    if (task_count_ > 0) {
+      --task_count_;
+    }
+    if (task_count_ == 0 && event_count_ == 0) {
+        MessageLoop::current()->QuitWhenIdle();
+    } else {
+      MessageLoop::current()->PostTask(
+          FROM_HERE, Bind(&ConcurrentHelper::FromTask, this));
+    }
+  }
+
+  void FromEvent() {
+    if (event_count_ > 0) {
+      --event_count_;
+    }
+    if (task_count_ == 0 && event_count_ == 0) {
+        MessageLoop::current()->QuitWhenIdle();
+    } else {
+      injector_->AddEventAsTask(
+          0, Bind(&ConcurrentHelper::FromEvent, this));
+    }
+  }
+
+  int event_count() const { return event_count_; }
+  int task_count() const { return task_count_; }
+
+ private:
+  friend class RefCounted<ConcurrentHelper>;
+
+  ~ConcurrentHelper() {}
+
+  static const int kStartingEventCount = 20;
+  static const int kStartingTaskCount = 20;
+
+  EventInjector* injector_;
+  int event_count_;
+  int task_count_;
+};
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
+  // Tests that posted tasks don't starve events, nor the opposite.
+  // We use the helper class above. We keep both event and posted task queues
+  // full, the helper verifies that both tasks and events get processed.
+  // If that is not the case, either event_count_ or task_count_ will not get
+  // to 0, and MessageLoop::QuitWhenIdle() will never be called.
+  scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector());
+
+  // Add 2 events to the queue to make sure it is always full (when we remove
+  // the event before processing it).
+  injector()->AddEventAsTask(
+      0, Bind(&ConcurrentHelper::FromEvent, helper.get()));
+  injector()->AddEventAsTask(
+      0, Bind(&ConcurrentHelper::FromEvent, helper.get()));
+
+  // Similarly post 2 tasks.
+  loop()->PostTask(
+      FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get()));
+  loop()->PostTask(
+      FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get()));
+
+  loop()->Run();
+  EXPECT_EQ(0, helper->event_count());
+  EXPECT_EQ(0, helper->task_count());
+}
+
+namespace {
+
+void AddEventsAndDrainGLib(EventInjector* injector) {
+  // Add a couple of dummy events
+  injector->AddDummyEvent(0);
+  injector->AddDummyEvent(0);
+  // Then add an event that will quit the main loop.
+  injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+
+  // Drain the events
+  while (g_main_context_pending(NULL)) {
+    g_main_context_iteration(NULL, FALSE);
+  }
+}
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
+  // Tests that draining events using GLib works.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&AddEventsAndDrainGLib, Unretained(injector())));
+  loop()->Run();
+
+  EXPECT_EQ(3, injector()->processed_events());
+}
+
+namespace {
+
+// Helper class that lets us run the GLib message loop.
+class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
+ public:
+  GLibLoopRunner() : quit_(false) { }
+
+  void RunGLib() {
+    while (!quit_) {
+      g_main_context_iteration(NULL, TRUE);
+    }
+  }
+
+  void RunLoop() {
+    while (!quit_) {
+      g_main_context_iteration(NULL, TRUE);
+    }
+  }
+
+  void Quit() {
+    quit_ = true;
+  }
+
+  void Reset() {
+    quit_ = false;
+  }
+
+ private:
+  friend class RefCounted<GLibLoopRunner>;
+
+  ~GLibLoopRunner() {}
+
+  bool quit_;
+};
+
+void TestGLibLoopInternal(EventInjector* injector) {
+  // Allow tasks to be processed from 'native' event loops.
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
+
+  int task_count = 0;
+  // Add a couple of dummy events
+  injector->AddDummyEvent(0);
+  injector->AddDummyEvent(0);
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  // Delayed events
+  injector->AddDummyEvent(10);
+  injector->AddDummyEvent(10);
+  // Delayed work
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&IncrementInt, &task_count),
+      TimeDelta::FromMilliseconds(30));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&GLibLoopRunner::Quit, runner.get()),
+      TimeDelta::FromMilliseconds(40));
+
+  // Run a nested, straight GLib message loop.
+  runner->RunGLib();
+
+  ASSERT_EQ(3, task_count);
+  EXPECT_EQ(4, injector->processed_events());
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void TestGtkLoopInternal(EventInjector* injector) {
+  // Allow tasks to be processed from 'native' event loops.
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
+
+  int task_count = 0;
+  // Add a couple of dummy events
+  injector->AddDummyEvent(0);
+  injector->AddDummyEvent(0);
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  // Delayed events
+  injector->AddDummyEvent(10);
+  injector->AddDummyEvent(10);
+  // Delayed work
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&IncrementInt, &task_count),
+      TimeDelta::FromMilliseconds(30));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&GLibLoopRunner::Quit, runner.get()),
+      TimeDelta::FromMilliseconds(40));
+
+  // Run a nested, straight Gtk message loop.
+  runner->RunLoop();
+
+  ASSERT_EQ(3, task_count);
+  EXPECT_EQ(4, injector->processed_events());
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestGLibLoop) {
+  // Tests that events and posted tasks are correctly executed if the message
+  // loop is not run by MessageLoop::Run() but by a straight GLib loop.
+  // Note that in this case we don't make strong guarantees about niceness
+  // between events and posted tasks.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&TestGLibLoopInternal, Unretained(injector())));
+  loop()->Run();
+}
+
+TEST_F(MessagePumpGLibTest, TestGtkLoop) {
+  // Tests that events and posted tasks are correctly executed if the message
+  // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
+  // Note that in this case we don't make strong guarantees about niceness
+  // between events and posted tasks.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&TestGtkLoopInternal, Unretained(injector())));
+  loop()->Run();
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_io_ios.cc b/base/message_loop/message_pump_io_ios.cc
new file mode 100644
index 0000000..cd5ffed
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios.cc
@@ -0,0 +1,209 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_io_ios.h"
+
+namespace base {
+
+MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher()
+    : is_persistent_(false),
+      fdref_(NULL),
+      callback_types_(0),
+      fd_source_(NULL),
+      watcher_(NULL) {
+}
+
+MessagePumpIOSForIO::FileDescriptorWatcher::~FileDescriptorWatcher() {
+  StopWatchingFileDescriptor();
+}
+
+bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+  if (fdref_ == NULL)
+    return true;
+
+  CFFileDescriptorDisableCallBacks(fdref_, callback_types_);
+  if (pump_)
+    pump_->RemoveRunLoopSource(fd_source_);
+  fd_source_.reset();
+  fdref_.reset();
+  callback_types_ = 0;
+  pump_.reset();
+  watcher_ = NULL;
+  return true;
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::Init(
+    CFFileDescriptorRef fdref,
+    CFOptionFlags callback_types,
+    CFRunLoopSourceRef fd_source,
+    bool is_persistent) {
+  DCHECK(fdref);
+  DCHECK(!fdref_);
+
+  is_persistent_ = is_persistent;
+  fdref_.reset(fdref);
+  callback_types_ = callback_types;
+  fd_source_.reset(fd_source);
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+    int fd,
+    MessagePumpIOSForIO* pump) {
+  DCHECK(callback_types_ & kCFFileDescriptorReadCallBack);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanReadWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+    int fd,
+    MessagePumpIOSForIO* pump) {
+  DCHECK(callback_types_ & kCFFileDescriptorWriteCallBack);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanWriteWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+MessagePumpIOSForIO::MessagePumpIOSForIO() : weak_factory_(this) {
+}
+
+MessagePumpIOSForIO::~MessagePumpIOSForIO() {
+}
+
+bool MessagePumpIOSForIO::WatchFileDescriptor(
+    int fd,
+    bool persistent,
+    int mode,
+    FileDescriptorWatcher *controller,
+    Watcher *delegate) {
+  DCHECK_GE(fd, 0);
+  DCHECK(controller);
+  DCHECK(delegate);
+  DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+
+  // WatchFileDescriptor should be called on the pump thread. It is not
+  // threadsafe, and your watcher may never be registered.
+  DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
+
+  CFFileDescriptorContext source_context = {0};
+  source_context.info = controller;
+
+  CFOptionFlags callback_types = 0;
+  if (mode & WATCH_READ) {
+    callback_types |= kCFFileDescriptorReadCallBack;
+  }
+  if (mode & WATCH_WRITE) {
+    callback_types |= kCFFileDescriptorWriteCallBack;
+  }
+
+  CFFileDescriptorRef fdref = controller->fdref_;
+  if (fdref == NULL) {
+    base::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
+        CFFileDescriptorCreate(
+            kCFAllocatorDefault, fd, false, HandleFdIOEvent, &source_context));
+    if (scoped_fdref == NULL) {
+      NOTREACHED() << "CFFileDescriptorCreate failed";
+      return false;
+    }
+
+    CFFileDescriptorEnableCallBacks(scoped_fdref, callback_types);
+
+    // TODO(wtc): what should the 'order' argument be?
+    base::ScopedCFTypeRef<CFRunLoopSourceRef> scoped_fd_source(
+        CFFileDescriptorCreateRunLoopSource(
+            kCFAllocatorDefault, scoped_fdref, 0));
+    if (scoped_fd_source == NULL) {
+      NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed";
+      return false;
+    }
+    CFRunLoopAddSource(run_loop(), scoped_fd_source, kCFRunLoopCommonModes);
+
+    // Transfer ownership of scoped_fdref and fd_source to controller.
+    controller->Init(scoped_fdref.release(), callback_types,
+                     scoped_fd_source.release(), persistent);
+  } else {
+    // It's illegal to use this function to listen on 2 separate fds with the
+    // same |controller|.
+    if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) {
+      NOTREACHED() << "FDs don't match: "
+                   << CFFileDescriptorGetNativeDescriptor(fdref)
+                   << " != " << fd;
+      return false;
+    }
+    if (persistent != controller->is_persistent_) {
+      NOTREACHED() << "persistent doesn't match";
+      return false;
+    }
+
+    // Combine old/new event masks.
+    CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_);
+    controller->callback_types_ |= callback_types;
+    CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_);
+  }
+
+  controller->set_watcher(delegate);
+  controller->set_pump(weak_factory_.GetWeakPtr());
+
+  return true;
+}
+
+void MessagePumpIOSForIO::RemoveRunLoopSource(CFRunLoopSourceRef source) {
+  CFRunLoopRemoveSource(run_loop(), source, kCFRunLoopCommonModes);
+}
+
+void MessagePumpIOSForIO::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpIOSForIO::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpIOSForIO::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpIOSForIO::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
+                                          CFOptionFlags callback_types,
+                                          void* context) {
+  FileDescriptorWatcher* controller =
+      static_cast<FileDescriptorWatcher*>(context);
+  DCHECK_EQ(fdref, controller->fdref_);
+
+  // Ensure that |fdref| will remain live for the duration of this function
+  // call even if |controller| is deleted or |StopWatchingFileDescriptor()| is
+  // called, either of which will cause |fdref| to be released.
+  ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
+      fdref, base::scoped_policy::RETAIN);
+
+  int fd = CFFileDescriptorGetNativeDescriptor(fdref);
+  MessagePumpIOSForIO* pump = controller->pump().get();
+  DCHECK(pump);
+  if (callback_types & kCFFileDescriptorWriteCallBack)
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+
+  // Perform the read callback only if the file descriptor has not been
+  // invalidated in the write callback. As |FileDescriptorWatcher| invalidates
+  // its file descriptor on destruction, the file descriptor being valid also
+  // guarantees that |controller| has not been deleted.
+  if (callback_types & kCFFileDescriptorReadCallBack &&
+      CFFileDescriptorIsValid(fdref)) {
+    DCHECK_EQ(fdref, controller->fdref_);
+    controller->OnFileCanReadWithoutBlocking(fd, pump);
+  }
+
+  // Re-enable callbacks after the read/write if the file descriptor is still
+  // valid and the controller is persistent.
+  if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) {
+    DCHECK_EQ(fdref, controller->fdref_);
+    CFFileDescriptorEnableCallBacks(fdref, callback_types);
+  }
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_io_ios.h b/base/message_loop/message_pump_io_ios.h
new file mode 100644
index 0000000..317a59c
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios.h
@@ -0,0 +1,144 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
+
+#include "base/base_export.h"
+#include "base/mac/scoped_cffiledescriptorref.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_pump_mac.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+// This file introduces a class to monitor sockets and issue callbacks when
+// sockets are ready for I/O on iOS.
+class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop {
+ public:
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    // An IOObserver is an object that receives IO notifications from the
+    // MessagePump.
+    //
+    // NOTE: An IOObserver implementation should be extremely fast!
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
+  // of a file descriptor.
+  class Watcher {
+   public:
+    // Called from MessageLoop::Run when an FD can be read from/written to
+    // without blocking
+    virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+    virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+
+   protected:
+    virtual ~Watcher() {}
+  };
+
+  // Object returned by WatchFileDescriptor to manage further watching.
+  class FileDescriptorWatcher {
+   public:
+    FileDescriptorWatcher();
+    ~FileDescriptorWatcher();  // Implicitly calls StopWatchingFileDescriptor.
+
+    // NOTE: These methods aren't called StartWatching()/StopWatching() to
+    // avoid confusion with the win32 ObjectWatcher class.
+
+    // Stop watching the FD, always safe to call.  No-op if there's nothing
+    // to do.
+    bool StopWatchingFileDescriptor();
+
+   private:
+    friend class MessagePumpIOSForIO;
+    friend class MessagePumpIOSForIOTest;
+
+    // Called by MessagePumpIOSForIO, ownership of |fdref| and |fd_source|
+    // is transferred to this object.
+    void Init(CFFileDescriptorRef fdref,
+              CFOptionFlags callback_types,
+              CFRunLoopSourceRef fd_source,
+              bool is_persistent);
+
+    void set_pump(base::WeakPtr<MessagePumpIOSForIO> pump) { pump_ = pump; }
+    const base::WeakPtr<MessagePumpIOSForIO>& pump() const { return pump_; }
+
+    void set_watcher(Watcher* watcher) { watcher_ = watcher; }
+
+    void OnFileCanReadWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
+    void OnFileCanWriteWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
+
+    bool is_persistent_;  // false if this event is one-shot.
+    base::mac::ScopedCFFileDescriptorRef fdref_;
+    CFOptionFlags callback_types_;
+    base::ScopedCFTypeRef<CFRunLoopSourceRef> fd_source_;
+    base::WeakPtr<MessagePumpIOSForIO> pump_;
+    Watcher* watcher_;
+
+    DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+  };
+
+  enum Mode {
+    WATCH_READ = 1 << 0,
+    WATCH_WRITE = 1 << 1,
+    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+  };
+
+  MessagePumpIOSForIO();
+  ~MessagePumpIOSForIO() override;
+
+  // Have the current thread's message loop watch for a a situation in which
+  // reading/writing to the FD can be performed without blocking.
+  // Callers must provide a preallocated FileDescriptorWatcher object which
+  // can later be used to manage the lifetime of this event.
+  // If a FileDescriptorWatcher is passed in which is already attached to
+  // an event, then the effect is cumulative i.e. after the call |controller|
+  // will watch both the previous event and the new one.
+  // If an error occurs while calling this method in a cumulative fashion, the
+  // event previously attached to |controller| is aborted.
+  // Returns true on success.
+  // Must be called on the same thread the message_pump is running on.
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           int mode,
+                           FileDescriptorWatcher *controller,
+                           Watcher *delegate);
+
+  void RemoveRunLoopSource(CFRunLoopSourceRef source);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+ private:
+  friend class MessagePumpIOSForIOTest;
+
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  static void HandleFdIOEvent(CFFileDescriptorRef fdref,
+                              CFOptionFlags callback_types,
+                              void* context);
+
+  ObserverList<IOObserver> io_observers_;
+  ThreadChecker watch_file_descriptor_caller_checker_;
+
+  base::WeakPtrFactory<MessagePumpIOSForIO> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIO);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc
new file mode 100644
index 0000000..ba96f83
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_io_ios.h"
+
+#include <unistd.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class MessagePumpIOSForIOTest : public testing::Test {
+ protected:
+  MessagePumpIOSForIOTest()
+      : ui_loop_(MessageLoop::TYPE_UI),
+        io_thread_("MessagePumpIOSForIOTestIOThread") {}
+  ~MessagePumpIOSForIOTest() override {}
+
+  void SetUp() override {
+    Thread::Options options(MessageLoop::TYPE_IO, 0);
+    ASSERT_TRUE(io_thread_.StartWithOptions(options));
+    ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
+    int ret = pipe(pipefds_);
+    ASSERT_EQ(0, ret);
+    ret = pipe(alternate_pipefds_);
+    ASSERT_EQ(0, ret);
+  }
+
+  void TearDown() override {
+    if (IGNORE_EINTR(close(pipefds_[0])) < 0)
+      PLOG(ERROR) << "close";
+    if (IGNORE_EINTR(close(pipefds_[1])) < 0)
+      PLOG(ERROR) << "close";
+  }
+
+  MessageLoop* ui_loop() { return &ui_loop_; }
+  MessageLoopForIO* io_loop() const {
+    return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  void HandleFdIOEvent(MessageLoopForIO::FileDescriptorWatcher* watcher) {
+    MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_,
+        kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack,
+        watcher);
+  }
+
+  int pipefds_[2];
+  int alternate_pipefds_[2];
+
+ private:
+  MessageLoop ui_loop_;
+  Thread io_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest);
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpIOSForIO::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpIOSForIO::Watcher {
+ public:
+  ~StupidWatcher() override {}
+
+  // base:MessagePumpIOSForIO::Watcher interface
+  void OnFileCanReadWithoutBlocking(int fd) override {}
+  void OnFileCanWriteWithoutBlocking(int fd) override {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+//  wrong thread.
+TEST_F(MessagePumpIOSForIOTest, TestWatchingFromBadThread) {
+  MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+  StupidWatcher delegate;
+
+  ASSERT_DEBUG_DEATH(io_loop()->WatchFileDescriptor(
+      STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+      "Check failed: "
+      "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpIOSForIO::Watcher {
+ public:
+  BaseWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller)
+      : controller_(controller) {
+    DCHECK(controller_);
+  }
+  ~BaseWatcher() override {}
+
+  // MessagePumpIOSForIO::Watcher interface
+  void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+ protected:
+  MessagePumpIOSForIO::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+  explicit DeleteWatcher(
+      MessagePumpIOSForIO::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  ~DeleteWatcher() override { DCHECK(!controller_); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    DCHECK(controller_);
+    delete controller_;
+    controller_ = NULL;
+  }
+};
+
+TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) {
+  scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+  MessagePumpIOSForIO::FileDescriptorWatcher* watcher =
+      new MessagePumpIOSForIO::FileDescriptorWatcher;
+  DeleteWatcher delegate(watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate);
+
+  // Spoof a callback.
+  HandleFdIOEvent(watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+  StopWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller,
+              MessagePumpIOSForIO* pump,
+              int fd_to_start_watching = -1)
+      : BaseWatcher(controller),
+        pump_(pump),
+        fd_to_start_watching_(fd_to_start_watching) {}
+
+  ~StopWatcher() override {}
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    controller_->StopWatchingFileDescriptor();
+    if (fd_to_start_watching_ >= 0) {
+      pump_->WatchFileDescriptor(fd_to_start_watching_,
+          false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this);
+    }
+  }
+
+ private:
+  MessagePumpIOSForIO* pump_;
+  int fd_to_start_watching_;
+};
+
+TEST_F(MessagePumpIOSForIOTest, StopWatcher) {
+  scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+  MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher, pump.get());
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a callback.
+  HandleFdIOEvent(&watcher);
+}
+
+TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) {
+  scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+  MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a callback.
+  HandleFdIOEvent(&watcher);
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc
new file mode 100644
index 0000000..b5b1fb7
--- /dev/null
+++ b/base/message_loop/message_pump_libevent.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_libevent.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/libevent/event.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+// Lifecycle of struct event
+// Libevent uses two main data structures:
+// struct event_base (of which there is one per message pump), and
+// struct event (of which there is roughly one per socket).
+// The socket's struct event is created in
+// MessagePumpLibevent::WatchFileDescriptor(),
+// is owned by the FileDescriptorWatcher, and is destroyed in
+// StopWatchingFileDescriptor().
+// It is moved into and out of lists in struct event_base by
+// the libevent functions event_add() and event_del().
+//
+// TODO(dkegel):
+// At the moment bad things happen if a FileDescriptorWatcher
+// is active after its MessagePumpLibevent has been destroyed.
+// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
+// Not clear yet whether that situation occurs in practice,
+// but if it does, we need to fix it.
+
+namespace base {
+
+// Return 0 on success
+// Too small a function to bother putting in a library?
+static int SetNonBlocking(int fd) {
+  int flags = fcntl(fd, F_GETFL, 0);
+  if (flags == -1)
+    flags = 0;
+  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
+    : event_(NULL),
+      pump_(NULL),
+      watcher_(NULL),
+      weak_factory_(this) {
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
+  if (event_) {
+    StopWatchingFileDescriptor();
+  }
+}
+
+bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+  event* e = ReleaseEvent();
+  if (e == NULL)
+    return true;
+
+  // event_del() is a no-op if the event isn't active.
+  int rv = event_del(e);
+  delete e;
+  pump_ = NULL;
+  watcher_ = NULL;
+  return (rv == 0);
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e) {
+  DCHECK(e);
+  DCHECK(!event_);
+
+  event_ = e;
+}
+
+event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
+  struct event *e = event_;
+  event_ = NULL;
+  return e;
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+    int fd, MessagePumpLibevent* pump) {
+  // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
+  // watching the file descriptor.
+  if (!watcher_)
+    return;
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanReadWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+    int fd, MessagePumpLibevent* pump) {
+  DCHECK(watcher_);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanWriteWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+MessagePumpLibevent::MessagePumpLibevent()
+    : keep_running_(true),
+      in_run_(false),
+      processed_io_events_(false),
+      event_base_(event_base_new()),
+      wakeup_pipe_in_(-1),
+      wakeup_pipe_out_(-1) {
+  if (!Init())
+     NOTREACHED();
+}
+
+MessagePumpLibevent::~MessagePumpLibevent() {
+  DCHECK(wakeup_event_);
+  DCHECK(event_base_);
+  event_del(wakeup_event_);
+  delete wakeup_event_;
+  if (wakeup_pipe_in_ >= 0) {
+    if (IGNORE_EINTR(close(wakeup_pipe_in_)) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  if (wakeup_pipe_out_ >= 0) {
+    if (IGNORE_EINTR(close(wakeup_pipe_out_)) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  event_base_free(event_base_);
+}
+
+bool MessagePumpLibevent::WatchFileDescriptor(int fd,
+                                              bool persistent,
+                                              int mode,
+                                              FileDescriptorWatcher *controller,
+                                              Watcher *delegate) {
+  DCHECK_GE(fd, 0);
+  DCHECK(controller);
+  DCHECK(delegate);
+  DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+  // WatchFileDescriptor should be called on the pump thread. It is not
+  // threadsafe, and your watcher may never be registered.
+  DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
+
+  int event_mask = persistent ? EV_PERSIST : 0;
+  if (mode & WATCH_READ) {
+    event_mask |= EV_READ;
+  }
+  if (mode & WATCH_WRITE) {
+    event_mask |= EV_WRITE;
+  }
+
+  scoped_ptr<event> evt(controller->ReleaseEvent());
+  if (evt.get() == NULL) {
+    // Ownership is transferred to the controller.
+    evt.reset(new event);
+  } else {
+    // Make sure we don't pick up any funky internal libevent masks.
+    int old_interest_mask = evt.get()->ev_events &
+        (EV_READ | EV_WRITE | EV_PERSIST);
+
+    // Combine old/new event masks.
+    event_mask |= old_interest_mask;
+
+    // Must disarm the event before we can reuse it.
+    event_del(evt.get());
+
+    // It's illegal to use this function to listen on 2 separate fds with the
+    // same |controller|.
+    if (EVENT_FD(evt.get()) != fd) {
+      NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd;
+      return false;
+    }
+  }
+
+  // Set current interest mask and message pump for this event.
+  event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
+
+  // Tell libevent which message pump this socket will belong to when we add it.
+  if (event_base_set(event_base_, evt.get())) {
+    return false;
+  }
+
+  // Add this socket to the list of monitored sockets.
+  if (event_add(evt.get(), NULL)) {
+    return false;
+  }
+
+  // Transfer ownership of evt to controller.
+  controller->Init(evt.release());
+
+  controller->set_watcher(delegate);
+  controller->set_pump(this);
+
+  return true;
+}
+
+void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+// Tell libevent to break out of inner loop.
+static void timer_callback(int fd, short events, void *context)
+{
+  event_base_loopbreak((struct event_base *)context);
+}
+
+// Reentrant!
+void MessagePumpLibevent::Run(Delegate* delegate) {
+  AutoReset<bool> auto_reset_keep_running(&keep_running_, true);
+  AutoReset<bool> auto_reset_in_run(&in_run_, true);
+
+  // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641.
+  // Instead, make our own timer and reuse it on each call to event_base_loop().
+  scoped_ptr<event> timer_event(new event);
+
+  for (;;) {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+    bool did_work = delegate->DoWork();
+    if (!keep_running_)
+      break;
+
+    event_base_loop(event_base_, EVLOOP_NONBLOCK);
+    did_work |= processed_io_events_;
+    processed_io_events_ = false;
+    if (!keep_running_)
+      break;
+
+    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    did_work = delegate->DoIdleWork();
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    // EVLOOP_ONCE tells libevent to only block once,
+    // but to service all pending events when it wakes up.
+    if (delayed_work_time_.is_null()) {
+      event_base_loop(event_base_, EVLOOP_ONCE);
+    } else {
+      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        struct timeval poll_tv;
+        poll_tv.tv_sec = delay.InSeconds();
+        poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
+        event_set(timer_event.get(), -1, 0, timer_callback, event_base_);
+        event_base_set(event_base_, timer_event.get());
+        event_add(timer_event.get(), &poll_tv);
+        event_base_loop(event_base_, EVLOOP_ONCE);
+        event_del(timer_event.get());
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = TimeTicks();
+      }
+    }
+
+    if (!keep_running_)
+      break;
+  }
+}
+
+void MessagePumpLibevent::Quit() {
+  DCHECK(in_run_) << "Quit was called outside of Run!";
+  // Tell both libevent and Run that they should break out of their loops.
+  keep_running_ = false;
+  ScheduleWork();
+}
+
+void MessagePumpLibevent::ScheduleWork() {
+  // Tell libevent (in a threadsafe way) that it should break out of its loop.
+  char buf = 0;
+  int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
+  DCHECK(nwrite == 1 || errno == EAGAIN)
+      << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
+}
+
+void MessagePumpLibevent::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpLibevent::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpLibevent::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+bool MessagePumpLibevent::Init() {
+  int fds[2];
+  if (pipe(fds)) {
+    DLOG(ERROR) << "pipe() failed, errno: " << errno;
+    return false;
+  }
+  if (SetNonBlocking(fds[0])) {
+    DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+    return false;
+  }
+  if (SetNonBlocking(fds[1])) {
+    DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
+    return false;
+  }
+  wakeup_pipe_out_ = fds[0];
+  wakeup_pipe_in_ = fds[1];
+
+  wakeup_event_ = new event;
+  event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
+            OnWakeup, this);
+  event_base_set(event_base_, wakeup_event_);
+
+  if (event_add(wakeup_event_, 0))
+    return false;
+  return true;
+}
+
+// static
+void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+                                                 void* context) {
+  WeakPtr<FileDescriptorWatcher> controller =
+      static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
+  DCHECK(controller.get());
+  TRACE_EVENT1("toplevel", "MessagePumpLibevent::OnLibeventNotification",
+               "fd", fd);
+
+  MessagePumpLibevent* pump = controller->pump();
+  pump->processed_io_events_ = true;
+
+  if (flags & EV_WRITE) {
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+  }
+  // Check |controller| in case it's been deleted in
+  // controller->OnFileCanWriteWithoutBlocking().
+  if (controller.get() && flags & EV_READ) {
+    controller->OnFileCanReadWithoutBlocking(fd, pump);
+  }
+}
+
+// Called if a byte is received on the wakeup pipe.
+// static
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+  MessagePumpLibevent* that = static_cast<MessagePumpLibevent*>(context);
+  DCHECK(that->wakeup_pipe_out_ == socket);
+
+  // Remove and discard the wakeup byte.
+  char buf;
+  int nread = HANDLE_EINTR(read(socket, &buf, 1));
+  DCHECK_EQ(nread, 1);
+  that->processed_io_events_ = true;
+  // Tell libevent to break out of inner loop.
+  event_base_loopbreak(that->event_base_);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h
new file mode 100644
index 0000000..3f5ad51
--- /dev/null
+++ b/base/message_loop/message_pump_libevent.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class BASE_EXPORT MessagePumpLibevent : public MessagePump {
+ public:
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    // An IOObserver is an object that receives IO notifications from the
+    // MessagePump.
+    //
+    // NOTE: An IOObserver implementation should be extremely fast!
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
+  // of a file descriptor.
+  class Watcher {
+   public:
+    // Called from MessageLoop::Run when an FD can be read from/written to
+    // without blocking
+    virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+    virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+
+   protected:
+    virtual ~Watcher() {}
+  };
+
+  // Object returned by WatchFileDescriptor to manage further watching.
+  class FileDescriptorWatcher {
+   public:
+    FileDescriptorWatcher();
+    ~FileDescriptorWatcher();  // Implicitly calls StopWatchingFileDescriptor.
+
+    // NOTE: These methods aren't called StartWatching()/StopWatching() to
+    // avoid confusion with the win32 ObjectWatcher class.
+
+    // Stop watching the FD, always safe to call.  No-op if there's nothing
+    // to do.
+    bool StopWatchingFileDescriptor();
+
+   private:
+    friend class MessagePumpLibevent;
+    friend class MessagePumpLibeventTest;
+
+    // Called by MessagePumpLibevent, ownership of |e| is transferred to this
+    // object.
+    void Init(event* e);
+
+    // Used by MessagePumpLibevent to take ownership of event_.
+    event* ReleaseEvent();
+
+    void set_pump(MessagePumpLibevent* pump) { pump_ = pump; }
+    MessagePumpLibevent* pump() const { return pump_; }
+
+    void set_watcher(Watcher* watcher) { watcher_ = watcher; }
+
+    void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump);
+    void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump);
+
+    event* event_;
+    MessagePumpLibevent* pump_;
+    Watcher* watcher_;
+    WeakPtrFactory<FileDescriptorWatcher> weak_factory_;
+
+    DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+  };
+
+  enum Mode {
+    WATCH_READ = 1 << 0,
+    WATCH_WRITE = 1 << 1,
+    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+  };
+
+  MessagePumpLibevent();
+  ~MessagePumpLibevent() override;
+
+  // Have the current thread's message loop watch for a a situation in which
+  // reading/writing to the FD can be performed without blocking.
+  // Callers must provide a preallocated FileDescriptorWatcher object which
+  // can later be used to manage the lifetime of this event.
+  // If a FileDescriptorWatcher is passed in which is already attached to
+  // an event, then the effect is cumulative i.e. after the call |controller|
+  // will watch both the previous event and the new one.
+  // If an error occurs while calling this method in a cumulative fashion, the
+  // event previously attached to |controller| is aborted.
+  // Returns true on success.
+  // Must be called on the same thread the message_pump is running on.
+  // TODO(dkegel): switch to edge-triggered readiness notification
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           int mode,
+                           FileDescriptorWatcher *controller,
+                           Watcher *delegate);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+  // MessagePump methods:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  friend class MessagePumpLibeventTest;
+
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  // Risky part of constructor.  Returns true on success.
+  bool Init();
+
+  // Called by libevent to tell us a registered FD can be read/written to.
+  static void OnLibeventNotification(int fd, short flags,
+                                     void* context);
+
+  // Unix pipe used to implement ScheduleWork()
+  // ... callback; called by libevent inside Run() when pipe is ready to read
+  static void OnWakeup(int socket, short flags, void* context);
+
+  // This flag is set to false when Run should return.
+  bool keep_running_;
+
+  // This flag is set when inside Run.
+  bool in_run_;
+
+  // This flag is set if libevent has processed I/O events.
+  bool processed_io_events_;
+
+  // The time at which we should call DoDelayedWork.
+  TimeTicks delayed_work_time_;
+
+  // Libevent dispatcher.  Watches all sockets registered with it, and sends
+  // readiness callbacks when a socket is ready for I/O.
+  event_base* event_base_;
+
+  // ... write end; ScheduleWork() writes a single byte to it
+  int wakeup_pipe_in_;
+  // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+  int wakeup_pipe_out_;
+  // ... libevent wrapper for read end
+  event* wakeup_event_;
+
+  ObserverList<IOObserver> io_observers_;
+  ThreadChecker watch_file_descriptor_caller_checker_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
new file mode 100644
index 0000000..65d7217
--- /dev/null
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_libevent.h"
+
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/waitable_event_watcher.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libevent/event.h"
+
+namespace base {
+
+class MessagePumpLibeventTest : public testing::Test {
+ protected:
+  MessagePumpLibeventTest()
+      : ui_loop_(new MessageLoop(MessageLoop::TYPE_UI)),
+        io_thread_("MessagePumpLibeventTestIOThread") {}
+  ~MessagePumpLibeventTest() override {}
+
+  void SetUp() override {
+    Thread::Options options(MessageLoop::TYPE_IO, 0);
+    ASSERT_TRUE(io_thread_.StartWithOptions(options));
+    ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
+    int ret = pipe(pipefds_);
+    ASSERT_EQ(0, ret);
+  }
+
+  void TearDown() override {
+    if (IGNORE_EINTR(close(pipefds_[0])) < 0)
+      PLOG(ERROR) << "close";
+    if (IGNORE_EINTR(close(pipefds_[1])) < 0)
+      PLOG(ERROR) << "close";
+  }
+
+  MessageLoopForIO* io_loop() const {
+    return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  void OnLibeventNotification(
+      MessagePumpLibevent* pump,
+      MessagePumpLibevent::FileDescriptorWatcher* controller) {
+    pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller);
+  }
+
+  int pipefds_[2];
+  scoped_ptr<MessageLoop> ui_loop_;
+
+ private:
+  Thread io_thread_;
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpLibevent::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  ~StupidWatcher() override {}
+
+  // base:MessagePumpLibevent::Watcher interface
+  void OnFileCanReadWithoutBlocking(int fd) override {}
+  void OnFileCanWriteWithoutBlocking(int fd) override {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+// wrong thread.
+TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  StupidWatcher delegate;
+
+  ASSERT_DEATH(io_loop()->WatchFileDescriptor(
+      STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+      "Check failed: "
+      "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)");
+}
+
+TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  ASSERT_DEATH(pump->Quit(), "Check failed: in_run_. "
+                             "Quit was called outside of Run!");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : controller_(controller) {
+    DCHECK(controller_);
+  }
+  ~BaseWatcher() override {}
+
+  // base:MessagePumpLibevent::Watcher interface
+  void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+ protected:
+  MessagePumpLibevent::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+  explicit DeleteWatcher(
+      MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  ~DeleteWatcher() override { DCHECK(!controller_); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    DCHECK(controller_);
+    delete controller_;
+    controller_ = NULL;
+  }
+};
+
+TEST_F(MessagePumpLibeventTest, DeleteWatcher) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher* watcher =
+      new MessagePumpLibevent::FileDescriptorWatcher;
+  DeleteWatcher delegate(watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump.get(), watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+  explicit StopWatcher(
+      MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  ~StopWatcher() override {}
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    controller_->StopWatchingFileDescriptor();
+  }
+};
+
+TEST_F(MessagePumpLibeventTest, StopWatcher) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump.get(), &watcher);
+}
+
+void QuitMessageLoopAndStart(const Closure& quit_closure) {
+  quit_closure.Run();
+
+  MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+  RunLoop runloop;
+  MessageLoop::current()->PostTask(FROM_HERE, runloop.QuitClosure());
+  runloop.Run();
+}
+
+class NestedPumpWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  NestedPumpWatcher() {}
+  ~NestedPumpWatcher() override {}
+
+  void OnFileCanReadWithoutBlocking(int /* fd */) override {
+    RunLoop runloop;
+    MessageLoop::current()->PostTask(FROM_HERE, Bind(&QuitMessageLoopAndStart,
+                                                     runloop.QuitClosure()));
+    runloop.Run();
+  }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {}
+};
+
+TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  NestedPumpWatcher delegate;
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ, &watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump.get(), &watcher);
+}
+
+void FatalClosure() {
+  FAIL() << "Reached fatal closure.";
+}
+
+class QuitWatcher : public BaseWatcher {
+ public:
+  QuitWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller,
+              RunLoop* run_loop)
+      : BaseWatcher(controller), run_loop_(run_loop) {}
+  ~QuitWatcher() override {}
+
+  void OnFileCanReadWithoutBlocking(int /* fd */) override {
+    // Post a fatal closure to the MessageLoop before we quit it.
+    MessageLoop::current()->PostTask(FROM_HERE, Bind(&FatalClosure));
+
+    // Now quit the MessageLoop.
+    run_loop_->Quit();
+  }
+
+ private:
+  RunLoop* run_loop_;  // weak
+};
+
+void WriteFDWrapper(const int fd,
+                    const char* buf,
+                    int size,
+                    WaitableEvent* event) {
+  ASSERT_TRUE(WriteFileDescriptor(fd, buf, size));
+}
+
+// Tests that MessagePumpLibevent quits immediately when it is quit from
+// libevent's event_base_loop().
+TEST_F(MessagePumpLibeventTest, QuitWatcher) {
+  // Delete the old MessageLoop so that we can manage our own one here.
+  ui_loop_.reset();
+
+  MessagePumpLibevent* pump = new MessagePumpLibevent;  // owned by |loop|.
+  MessageLoop loop(make_scoped_ptr(pump));
+  RunLoop run_loop;
+  MessagePumpLibevent::FileDescriptorWatcher controller;
+  QuitWatcher delegate(&controller, &run_loop);
+  WaitableEvent event(false /* manual_reset */, false /* initially_signaled */);
+  WaitableEventWatcher watcher;
+
+  // Tell the pump to watch the pipe.
+  pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpLibevent::WATCH_READ,
+                            &controller, &delegate);
+
+  // Make the IO thread wait for |event| before writing to pipefds[1].
+  const char buf = 0;
+  const WaitableEventWatcher::EventCallback write_fd_task =
+      Bind(&WriteFDWrapper, pipefds_[1], &buf, 1);
+  io_loop()->PostTask(FROM_HERE,
+                      Bind(IgnoreResult(&WaitableEventWatcher::StartWatching),
+                           Unretained(&watcher), &event, write_fd_task));
+
+  // Queue |event| to signal on |loop|.
+  loop.PostTask(FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
+
+  // Now run the MessageLoop.
+  run_loop.Run();
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h
new file mode 100644
index 0000000..c853202
--- /dev/null
+++ b/base/message_loop/message_pump_mac.h
@@ -0,0 +1,353 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The basis for all native run loops on the Mac is the CFRunLoop.  It can be
+// used directly, it can be used as the driving force behind the similar
+// Foundation NSRunLoop, and it can be used to implement higher-level event
+// loops such as the NSApplication event loop.
+//
+// This file introduces a basic CFRunLoop-based implementation of the
+// MessagePump interface called CFRunLoopBase.  CFRunLoopBase contains all
+// of the machinery necessary to dispatch events to a delegate, but does not
+// implement the specific run loop.  Concrete subclasses must provide their
+// own DoRun and Quit implementations.
+//
+// A concrete subclass that just runs a CFRunLoop loop is provided in
+// MessagePumpCFRunLoop.  For an NSRunLoop, the similar MessagePumpNSRunLoop
+// is provided.
+//
+// For the application's event loop, an implementation based on AppKit's
+// NSApplication event system is provided in MessagePumpNSApplication.
+//
+// Typically, MessagePumpNSApplication only makes sense on a Cocoa
+// application's main thread.  If a CFRunLoop-based message pump is needed on
+// any other thread, one of the other concrete subclasses is preferrable.
+// MessagePumpMac::Create is defined, which returns a new NSApplication-based
+// or NSRunLoop-based MessagePump subclass depending on which thread it is
+// called on.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
+
+#include "base/message_loop/message_pump.h"
+
+#include "base/basictypes.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/timer_slack.h"
+
+#if defined(__OBJC__)
+#if defined(OS_IOS)
+#import <Foundation/Foundation.h>
+#else
+#import <AppKit/AppKit.h>
+
+// Clients must subclass NSApplication and implement this protocol if they use
+// MessagePumpMac.
+@protocol CrAppProtocol
+// Must return true if -[NSApplication sendEvent:] is currently on the stack.
+// See the comment for |CreateAutoreleasePool()| in the cc file for why this is
+// necessary.
+- (BOOL)isHandlingSendEvent;
+@end
+#endif  // !defined(OS_IOS)
+#endif  // defined(__OBJC__)
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+// AutoreleasePoolType is a proxy type for autorelease pools. Its definition
+// depends on the translation unit (TU) in which this header appears. In pure
+// C++ TUs, it is defined as a forward C++ class declaration (that is never
+// defined), because autorelease pools are an Objective-C concept. In Automatic
+// Reference Counting (ARC) Objective-C TUs, it is similarly defined as a
+// forward C++ class declaration, because clang will not allow the type
+// "NSAutoreleasePool" in such TUs. Finally, in Manual Retain Release (MRR)
+// Objective-C TUs, it is a type alias for NSAutoreleasePool. In all cases, a
+// method that takes or returns an NSAutoreleasePool* can use
+// AutoreleasePoolType* instead.
+#if !defined(__OBJC__) || __has_feature(objc_arc)
+class AutoreleasePoolType;
+#else   // !defined(__OBJC__) || __has_feature(objc_arc)
+typedef NSAutoreleasePool AutoreleasePoolType;
+#endif  // !defined(__OBJC__) || __has_feature(objc_arc)
+
+class MessagePumpCFRunLoopBase : public MessagePump {
+  // Needs access to CreateAutoreleasePool.
+  friend class MessagePumpScopedAutoreleasePool;
+ public:
+  MessagePumpCFRunLoopBase();
+  ~MessagePumpCFRunLoopBase() override;
+
+  // Subclasses should implement the work they need to do in MessagePump::Run
+  // in the DoRun method.  MessagePumpCFRunLoopBase::Run calls DoRun directly.
+  // This arrangement is used because MessagePumpCFRunLoopBase needs to set
+  // up and tear down things before and after the "meat" of DoRun.
+  void Run(Delegate* delegate) override;
+  virtual void DoRun(Delegate* delegate) = 0;
+
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+  void SetTimerSlack(TimerSlack timer_slack) override;
+
+ protected:
+  // Accessors for private data members to be used by subclasses.
+  CFRunLoopRef run_loop() const { return run_loop_; }
+  int nesting_level() const { return nesting_level_; }
+  int run_nesting_level() const { return run_nesting_level_; }
+
+  // Sets this pump's delegate.  Signals the appropriate sources if
+  // |delegateless_work_| is true.  |delegate| can be NULL.
+  void SetDelegate(Delegate* delegate);
+
+  // Return an autorelease pool to wrap around any work being performed.
+  // In some cases, CreateAutoreleasePool may return nil intentionally to
+  // preventing an autorelease pool from being created, allowing any
+  // objects autoreleased by work to fall into the current autorelease pool.
+  virtual AutoreleasePoolType* CreateAutoreleasePool();
+
+ private:
+  // Timer callback scheduled by ScheduleDelayedWork.  This does not do any
+  // work, but it signals work_source_ so that delayed work can be performed
+  // within the appropriate priority constraints.
+  static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
+
+  // Perform highest-priority work.  This is associated with work_source_
+  // signalled by ScheduleWork or RunDelayedWorkTimer.  The static method calls
+  // the instance method; the instance method returns true if it resignalled
+  // work_source_ to be called again from the loop.
+  static void RunWorkSource(void* info);
+  bool RunWork();
+
+  // Perform idle-priority work.  This is normally called by PreWaitObserver,
+  // but is also associated with idle_work_source_.  When this function
+  // actually does perform idle work, it will resignal that source.  The
+  // static method calls the instance method; the instance method returns
+  // true if idle work was done.
+  static void RunIdleWorkSource(void* info);
+  bool RunIdleWork();
+
+  // Perform work that may have been deferred because it was not runnable
+  // within a nested run loop.  This is associated with
+  // nesting_deferred_work_source_ and is signalled by
+  // MaybeScheduleNestingDeferredWork when returning from a nested loop,
+  // so that an outer loop will be able to perform the necessary tasks if it
+  // permits nestable tasks.
+  static void RunNestingDeferredWorkSource(void* info);
+  bool RunNestingDeferredWork();
+
+  // Schedules possible nesting-deferred work to be processed before the run
+  // loop goes to sleep, exits, or begins processing sources at the top of its
+  // loop.  If this function detects that a nested loop had run since the
+  // previous attempt to schedule nesting-deferred work, it will schedule a
+  // call to RunNestingDeferredWorkSource.
+  void MaybeScheduleNestingDeferredWork();
+
+  // Observer callback responsible for performing idle-priority work, before
+  // the run loop goes to sleep.  Associated with idle_work_observer_.
+  static void PreWaitObserver(CFRunLoopObserverRef observer,
+                              CFRunLoopActivity activity, void* info);
+
+  // Observer callback called before the run loop processes any sources.
+  // Associated with pre_source_observer_.
+  static void PreSourceObserver(CFRunLoopObserverRef observer,
+                                CFRunLoopActivity activity, void* info);
+
+  // Observer callback called when the run loop starts and stops, at the
+  // beginning and end of calls to CFRunLoopRun.  This is used to maintain
+  // nesting_level_.  Associated with enter_exit_observer_.
+  static void EnterExitObserver(CFRunLoopObserverRef observer,
+                                CFRunLoopActivity activity, void* info);
+
+  // Called by EnterExitObserver after performing maintenance on nesting_level_.
+  // This allows subclasses an opportunity to perform additional processing on
+  // the basis of run loops starting and stopping.
+  virtual void EnterExitRunLoop(CFRunLoopActivity activity);
+
+  // The thread's run loop.
+  CFRunLoopRef run_loop_;
+
+  // The timer, sources, and observers are described above alongside their
+  // callbacks.
+  CFRunLoopTimerRef delayed_work_timer_;
+  CFRunLoopSourceRef work_source_;
+  CFRunLoopSourceRef idle_work_source_;
+  CFRunLoopSourceRef nesting_deferred_work_source_;
+  CFRunLoopObserverRef pre_wait_observer_;
+  CFRunLoopObserverRef pre_source_observer_;
+  CFRunLoopObserverRef enter_exit_observer_;
+
+  // (weak) Delegate passed as an argument to the innermost Run call.
+  Delegate* delegate_;
+
+  // The time that delayed_work_timer_ is scheduled to fire.  This is tracked
+  // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_)
+  // to be able to reset the timer properly after waking from system sleep.
+  // See PowerStateNotification.
+  CFAbsoluteTime delayed_work_fire_time_;
+
+  base::TimerSlack timer_slack_;
+
+  // The recursion depth of the currently-executing CFRunLoopRun loop on the
+  // run loop's thread.  0 if no run loops are running inside of whatever scope
+  // the object was created in.
+  int nesting_level_;
+
+  // The recursion depth (calculated in the same way as nesting_level_) of the
+  // innermost executing CFRunLoopRun loop started by a call to Run.
+  int run_nesting_level_;
+
+  // The deepest (numerically highest) recursion depth encountered since the
+  // most recent attempt to run nesting-deferred work.
+  int deepest_nesting_level_;
+
+  // "Delegateless" work flags are set when work is ready to be performed but
+  // must wait until a delegate is available to process it.  This can happen
+  // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
+  // any call to Run on the stack.  The Run method will check for delegateless
+  // work on entry and redispatch it as needed once a delegate is available.
+  bool delegateless_work_;
+  bool delegateless_idle_work_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
+};
+
+class BASE_EXPORT MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpCFRunLoop();
+  ~MessagePumpCFRunLoop() override;
+
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+ private:
+  void EnterExitRunLoop(CFRunLoopActivity activity) override;
+
+  // True if Quit is called to stop the innermost MessagePump
+  // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
+  // is running inside the MessagePump's innermost Run call.
+  bool quit_pending_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
+};
+
+class BASE_EXPORT MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpNSRunLoop();
+  ~MessagePumpNSRunLoop() override;
+
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+ private:
+  // A source that doesn't do anything but provide something signalable
+  // attached to the run loop.  This source will be signalled when Quit
+  // is called, to cause the loop to wake up so that it can stop.
+  CFRunLoopSourceRef quit_source_;
+
+  // False after Quit is called.
+  bool keep_running_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
+};
+
+#if defined(OS_IOS)
+// This is a fake message pump.  It attaches sources to the main thread's
+// CFRunLoop, so PostTask() will work, but it is unable to drive the loop
+// directly, so calling Run() or Quit() are errors.
+class MessagePumpUIApplication : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpUIApplication();
+  ~MessagePumpUIApplication() override;
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+  // This message pump can not spin the main message loop directly.  Instead,
+  // call |Attach()| to set up a delegate.  It is an error to call |Run()|.
+  virtual void Attach(Delegate* delegate);
+
+ private:
+  RunLoop* run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication);
+};
+
+#else
+
+class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpNSApplication();
+  ~MessagePumpNSApplication() override;
+
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+ private:
+  // False after Quit is called.
+  bool keep_running_;
+
+  // True if DoRun is managing its own run loop as opposed to letting
+  // -[NSApplication run] handle it.  The outermost run loop in the application
+  // is managed by -[NSApplication run], inner run loops are handled by a loop
+  // in DoRun.
+  bool running_own_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
+};
+
+class MessagePumpCrApplication : public MessagePumpNSApplication {
+ public:
+  MessagePumpCrApplication();
+  ~MessagePumpCrApplication() override;
+
+ protected:
+  // Returns nil if NSApp is currently in the middle of calling
+  // -sendEvent.  Requires NSApp implementing CrAppProtocol.
+  AutoreleasePoolType* CreateAutoreleasePool() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication);
+};
+#endif  // !defined(OS_IOS)
+
+class BASE_EXPORT MessagePumpMac {
+ public:
+  // If not on the main thread, returns a new instance of
+  // MessagePumpNSRunLoop.
+  //
+  // On the main thread, if NSApp exists and conforms to
+  // CrAppProtocol, creates an instances of MessagePumpCrApplication.
+  //
+  // Otherwise creates an instance of MessagePumpNSApplication using a
+  // default NSApplication.
+  static MessagePump* Create();
+
+#if !defined(OS_IOS)
+  // If a pump is created before the required CrAppProtocol is
+  // created, the wrong MessagePump subclass could be used.
+  // UsingCrApp() returns false if the message pump was created before
+  // NSApp was initialized, or if NSApp does not implement
+  // CrAppProtocol.  NSApp must be initialized before calling.
+  static bool UsingCrApp();
+
+  // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code.
+  // Requires NSApp to implement CrAppProtocol.
+  static bool IsHandlingSendEvent();
+#endif  // !defined(OS_IOS)
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
+};
+
+// Tasks posted to the message loop are posted under this mode, as well
+// as kCFRunLoopCommonModes.
+extern const CFStringRef BASE_EXPORT kMessageLoopExclusiveRunLoopMode;
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
new file mode 100644
index 0000000..914977b
--- /dev/null
+++ b/base/message_loop/message_pump_mac.mm
@@ -0,0 +1,777 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/message_loop/message_pump_mac.h"
+
+#include <dlfcn.h>
+#import <Foundation/Foundation.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+
+#if !defined(OS_IOS)
+#import <AppKit/AppKit.h>
+#endif  // !defined(OS_IOS)
+
+namespace base {
+
+namespace {
+
+void CFRunLoopAddSourceToAllModes(CFRunLoopRef rl, CFRunLoopSourceRef source) {
+  CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
+  CFRunLoopAddSource(rl, source, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopRemoveSourceFromAllModes(CFRunLoopRef rl,
+                                       CFRunLoopSourceRef source) {
+  CFRunLoopRemoveSource(rl, source, kCFRunLoopCommonModes);
+  CFRunLoopRemoveSource(rl, source, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopAddTimerToAllModes(CFRunLoopRef rl, CFRunLoopTimerRef timer) {
+  CFRunLoopAddTimer(rl, timer, kCFRunLoopCommonModes);
+  CFRunLoopAddTimer(rl, timer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopRemoveTimerFromAllModes(CFRunLoopRef rl,
+                                      CFRunLoopTimerRef timer) {
+  CFRunLoopRemoveTimer(rl, timer, kCFRunLoopCommonModes);
+  CFRunLoopRemoveTimer(rl, timer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopAddObserverToAllModes(CFRunLoopRef rl,
+                                    CFRunLoopObserverRef observer) {
+  CFRunLoopAddObserver(rl, observer, kCFRunLoopCommonModes);
+  CFRunLoopAddObserver(rl, observer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopRemoveObserverFromAllModes(CFRunLoopRef rl,
+                                         CFRunLoopObserverRef observer) {
+  CFRunLoopRemoveObserver(rl, observer, kCFRunLoopCommonModes);
+  CFRunLoopRemoveObserver(rl, observer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void NoOp(void* info) {
+}
+
+const CFTimeInterval kCFTimeIntervalMax =
+    std::numeric_limits<CFTimeInterval>::max();
+
+#if !defined(OS_IOS)
+// Set to true if MessagePumpMac::Create() is called before NSApp is
+// initialized.  Only accessed from the main thread.
+bool g_not_using_cr_app = false;
+#endif
+
+// Call through to CFRunLoopTimerSetTolerance(), which is only available on
+// OS X 10.9.
+void SetTimerTolerance(CFRunLoopTimerRef timer, CFTimeInterval tolerance) {
+  typedef void (*CFRunLoopTimerSetTolerancePtr)(CFRunLoopTimerRef timer,
+      CFTimeInterval tolerance);
+
+  static CFRunLoopTimerSetTolerancePtr settimertolerance_function_ptr;
+
+  static dispatch_once_t get_timer_tolerance_function_ptr_once;
+  dispatch_once(&get_timer_tolerance_function_ptr_once, ^{
+      NSBundle* bundle =[NSBundle
+        bundleWithPath:@"/System/Library/Frameworks/CoreFoundation.framework"];
+      const char* path = [[bundle executablePath] fileSystemRepresentation];
+      CHECK(path);
+      void* library_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
+      CHECK(library_handle) << dlerror();
+      settimertolerance_function_ptr =
+          reinterpret_cast<CFRunLoopTimerSetTolerancePtr>(
+              dlsym(library_handle, "CFRunLoopTimerSetTolerance"));
+
+      dlclose(library_handle);
+  });
+
+  if (settimertolerance_function_ptr)
+    settimertolerance_function_ptr(timer, tolerance);
+}
+
+}  // namespace
+
+// static
+const CFStringRef kMessageLoopExclusiveRunLoopMode =
+    CFSTR("kMessageLoopExclusiveRunLoopMode");
+
+// A scoper for autorelease pools created from message pump run loops.
+// Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare
+// case where an autorelease pool needs to be passed in.
+class MessagePumpScopedAutoreleasePool {
+ public:
+  explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) :
+      pool_(pump->CreateAutoreleasePool()) {
+  }
+   ~MessagePumpScopedAutoreleasePool() {
+    [pool_ drain];
+  }
+
+ private:
+  NSAutoreleasePool* pool_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
+};
+
+// Must be called on the run loop thread.
+MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
+    : delegate_(NULL),
+      delayed_work_fire_time_(kCFTimeIntervalMax),
+      timer_slack_(base::TIMER_SLACK_NONE),
+      nesting_level_(0),
+      run_nesting_level_(0),
+      deepest_nesting_level_(0),
+      delegateless_work_(false),
+      delegateless_idle_work_(false) {
+  run_loop_ = CFRunLoopGetCurrent();
+  CFRetain(run_loop_);
+
+  // Set a repeating timer with a preposterous firing time and interval.  The
+  // timer will effectively never fire as-is.  The firing time will be adjusted
+  // as needed when ScheduleDelayedWork is called.
+  CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
+  timer_context.info = this;
+  delayed_work_timer_ = CFRunLoopTimerCreate(NULL,                // allocator
+                                             kCFTimeIntervalMax,  // fire time
+                                             kCFTimeIntervalMax,  // interval
+                                             0,                   // flags
+                                             0,                   // priority
+                                             RunDelayedWorkTimer,
+                                             &timer_context);
+  CFRunLoopAddTimerToAllModes(run_loop_, delayed_work_timer_);
+
+  CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+  source_context.info = this;
+  source_context.perform = RunWorkSource;
+  work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                       1,     // priority
+                                       &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop_, work_source_);
+
+  source_context.perform = RunIdleWorkSource;
+  idle_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                            2,     // priority
+                                            &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop_, idle_work_source_);
+
+  source_context.perform = RunNestingDeferredWorkSource;
+  nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                                        0,     // priority
+                                                        &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop_, nesting_deferred_work_source_);
+
+  CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+  observer_context.info = this;
+  pre_wait_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                               kCFRunLoopBeforeWaiting,
+                                               true,  // repeat
+                                               0,     // priority
+                                               PreWaitObserver,
+                                               &observer_context);
+  CFRunLoopAddObserverToAllModes(run_loop_, pre_wait_observer_);
+
+  pre_source_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                                 kCFRunLoopBeforeSources,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 PreSourceObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserverToAllModes(run_loop_, pre_source_observer_);
+
+  enter_exit_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                                 kCFRunLoopEntry |
+                                                     kCFRunLoopExit,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 EnterExitObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserverToAllModes(run_loop_, enter_exit_observer_);
+}
+
+// Ideally called on the run loop thread.  If other run loops were running
+// lower on the run loop thread's stack when this object was created, the
+// same number of run loops must be running when this object is destroyed.
+MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
+  CFRunLoopRemoveObserverFromAllModes(run_loop_, enter_exit_observer_);
+  CFRelease(enter_exit_observer_);
+
+  CFRunLoopRemoveObserverFromAllModes(run_loop_, pre_source_observer_);
+  CFRelease(pre_source_observer_);
+
+  CFRunLoopRemoveObserverFromAllModes(run_loop_, pre_wait_observer_);
+  CFRelease(pre_wait_observer_);
+
+  CFRunLoopRemoveSourceFromAllModes(run_loop_, nesting_deferred_work_source_);
+  CFRelease(nesting_deferred_work_source_);
+
+  CFRunLoopRemoveSourceFromAllModes(run_loop_, idle_work_source_);
+  CFRelease(idle_work_source_);
+
+  CFRunLoopRemoveSourceFromAllModes(run_loop_, work_source_);
+  CFRelease(work_source_);
+
+  CFRunLoopRemoveTimerFromAllModes(run_loop_, delayed_work_timer_);
+  CFRelease(delayed_work_timer_);
+
+  CFRelease(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
+  // nesting_level_ will be incremented in EnterExitRunLoop, so set
+  // run_nesting_level_ accordingly.
+  int last_run_nesting_level = run_nesting_level_;
+  run_nesting_level_ = nesting_level_ + 1;
+
+  Delegate* last_delegate = delegate_;
+  SetDelegate(delegate);
+
+  DoRun(delegate);
+
+  // Restore the previous state of the object.
+  SetDelegate(last_delegate);
+  run_nesting_level_ = last_run_nesting_level;
+}
+
+void MessagePumpCFRunLoopBase::SetDelegate(Delegate* delegate) {
+  delegate_ = delegate;
+
+  if (delegate) {
+    // If any work showed up but could not be dispatched for want of a
+    // delegate, set it up for dispatch again now that a delegate is
+    // available.
+    if (delegateless_work_) {
+      CFRunLoopSourceSignal(work_source_);
+      delegateless_work_ = false;
+    }
+    if (delegateless_idle_work_) {
+      CFRunLoopSourceSignal(idle_work_source_);
+      delegateless_idle_work_ = false;
+    }
+  }
+}
+
+// May be called on any thread.
+void MessagePumpCFRunLoopBase::ScheduleWork() {
+  CFRunLoopSourceSignal(work_source_);
+  CFRunLoopWakeUp(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  TimeDelta delta = delayed_work_time - TimeTicks::Now();
+  delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
+  CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
+  if (timer_slack_ == TIMER_SLACK_MAXIMUM) {
+    SetTimerTolerance(delayed_work_timer_, delta.InSecondsF() * 0.5);
+  } else {
+    SetTimerTolerance(delayed_work_timer_, 0);
+  }
+}
+
+void MessagePumpCFRunLoopBase::SetTimerSlack(TimerSlack timer_slack) {
+  timer_slack_ = timer_slack;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
+                                                   void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // The timer won't fire again until it's reset.
+  self->delayed_work_fire_time_ = kCFTimeIntervalMax;
+
+  // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
+  // In order to establish the proper priority in which work and delayed work
+  // are processed one for one, the timer used to schedule delayed work must
+  // signal a CFRunLoopSource used to dispatch both work and delayed work.
+  CFRunLoopSourceSignal(self->work_source_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunWorkSource.
+bool MessagePumpCFRunLoopBase::RunWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_work_ = true;
+    return false;
+  }
+
+  // The NSApplication-based run loop only drains the autorelease pool at each
+  // UI event (NSEvent).  The autorelease pool is not drained for each
+  // CFRunLoopSource target that's run.  Use a local pool for any autoreleased
+  // objects if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+  // Call DoWork and DoDelayedWork once, and if something was done, arrange to
+  // come back here again as long as the loop is still running.
+  bool did_work = delegate_->DoWork();
+  bool resignal_work_source = did_work;
+
+  TimeTicks next_time;
+  delegate_->DoDelayedWork(&next_time);
+  if (!did_work) {
+    // Determine whether there's more delayed work, and if so, if it needs to
+    // be done at some point in the future or if it's already time to do it.
+    // Only do these checks if did_work is false. If did_work is true, this
+    // function, and therefore any additional delayed work, will get another
+    // chance to run before the loop goes to sleep.
+    bool more_delayed_work = !next_time.is_null();
+    if (more_delayed_work) {
+      TimeDelta delay = next_time - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        // There's more delayed work to be done in the future.
+        ScheduleDelayedWork(next_time);
+      } else {
+        // There's more delayed work to be done, and its time is in the past.
+        // Arrange to come back here directly as long as the loop is still
+        // running.
+        resignal_work_source = true;
+      }
+    }
+  }
+
+  if (resignal_work_source) {
+    CFRunLoopSourceSignal(work_source_);
+  }
+
+  return resignal_work_source;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunIdleWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
+bool MessagePumpCFRunLoopBase::RunIdleWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_idle_work_ = true;
+    return false;
+  }
+
+  // The NSApplication-based run loop only drains the autorelease pool at each
+  // UI event (NSEvent).  The autorelease pool is not drained for each
+  // CFRunLoopSource target that's run.  Use a local pool for any autoreleased
+  // objects if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+  // Call DoIdleWork once, and if something was done, arrange to come back here
+  // again as long as the loop is still running.
+  bool did_work = delegate_->DoIdleWork();
+  if (did_work) {
+    CFRunLoopSourceSignal(idle_work_source_);
+  }
+
+  return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunNestingDeferredWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
+bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  There's no sense in
+    // attempting to do any work or signalling the work sources because
+    // without a delegate, work is not possible.
+    return false;
+  }
+
+  // Immediately try work in priority order.
+  if (!RunWork()) {
+    if (!RunIdleWork()) {
+      return false;
+    }
+  } else {
+    // Work was done.  Arrange for the loop to try non-nestable idle work on
+    // a subsequent pass.
+    CFRunLoopSourceSignal(idle_work_source_);
+  }
+
+  return true;
+}
+
+// Called before the run loop goes to sleep or exits, or processes sources.
+void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
+  // deepest_nesting_level_ is set as run loops are entered.  If the deepest
+  // level encountered is deeper than the current level, a nested loop
+  // (relative to the current level) ran since the last time nesting-deferred
+  // work was scheduled.  When that situation is encountered, schedule
+  // nesting-deferred work in case any work was deferred because nested work
+  // was disallowed.
+  if (deepest_nesting_level_ > nesting_level_) {
+    deepest_nesting_level_ = nesting_level_;
+    CFRunLoopSourceSignal(nesting_deferred_work_source_);
+  }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
+                                               CFRunLoopActivity activity,
+                                               void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // Attempt to do some idle work before going to sleep.
+  self->RunIdleWork();
+
+  // The run loop is about to go to sleep.  If any of the work done since it
+  // started or woke up resulted in a nested run loop running,
+  // nesting-deferred work may have accumulated.  Schedule it for processing
+  // if appropriate.
+  self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
+                                                 CFRunLoopActivity activity,
+                                                 void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // The run loop has reached the top of the loop and is about to begin
+  // processing sources.  If the last iteration of the loop at this nesting
+  // level did not sleep or exit, nesting-deferred work may have accumulated
+  // if a nested loop ran.  Schedule nesting-deferred work for processing if
+  // appropriate.
+  self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
+                                                 CFRunLoopActivity activity,
+                                                 void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  switch (activity) {
+    case kCFRunLoopEntry:
+      ++self->nesting_level_;
+      if (self->nesting_level_ > self->deepest_nesting_level_) {
+        self->deepest_nesting_level_ = self->nesting_level_;
+      }
+      break;
+
+    case kCFRunLoopExit:
+      // Not all run loops go to sleep.  If a run loop is stopped before it
+      // goes to sleep due to a CFRunLoopStop call, or if the timeout passed
+      // to CFRunLoopRunInMode expires, the run loop may proceed directly from
+      // handling sources to exiting without any sleep.  This most commonly
+      // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it
+      // to make a single pass through the loop and exit without sleep.  Some
+      // native loops use CFRunLoop in this way.  Because PreWaitObserver will
+      // not be called in these case, MaybeScheduleNestingDeferredWork needs
+      // to be called here, as the run loop exits.
+      //
+      // MaybeScheduleNestingDeferredWork consults self->nesting_level_
+      // to determine whether to schedule nesting-deferred work.  It expects
+      // the nesting level to be set to the depth of the loop that is going
+      // to sleep or exiting.  It must be called before decrementing the
+      // value so that the value still corresponds to the level of the exiting
+      // loop.
+      self->MaybeScheduleNestingDeferredWork();
+      --self->nesting_level_;
+      break;
+
+    default:
+      break;
+  }
+
+  self->EnterExitRunLoop(activity);
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop.  The default
+// implementation is a no-op.
+void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {
+}
+
+// Base version returns a standard NSAutoreleasePool.
+AutoreleasePoolType* MessagePumpCFRunLoopBase::CreateAutoreleasePool() {
+  return [[NSAutoreleasePool alloc] init];
+}
+
+MessagePumpCFRunLoop::MessagePumpCFRunLoop()
+    : quit_pending_(false) {
+}
+
+MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {}
+
+// Called by MessagePumpCFRunLoopBase::DoRun.  If other CFRunLoopRun loops were
+// running lower on the run loop thread's stack when this object was created,
+// the same number of CFRunLoopRun loops must be running for the outermost call
+// to Run.  Run/DoRun are reentrant after that point.
+void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
+  // This is completely identical to calling CFRunLoopRun(), except autorelease
+  // pool management is introduced.
+  int result;
+  do {
+    MessagePumpScopedAutoreleasePool autorelease_pool(this);
+    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+                                kCFTimeIntervalMax,
+                                false);
+  } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoop::Quit() {
+  // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
+  if (nesting_level() == run_nesting_level()) {
+    // This object is running the innermost loop, just stop it.
+    CFRunLoopStop(run_loop());
+  } else {
+    // There's another loop running inside the loop managed by this object.
+    // In other words, someone else called CFRunLoopRunInMode on the same
+    // thread, deeper on the stack than the deepest Run call.  Don't preempt
+    // other run loops, just mark this object to quit the innermost Run as
+    // soon as the other inner loops not managed by Run are done.
+    quit_pending_ = true;
+  }
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
+void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
+  if (activity == kCFRunLoopExit &&
+      nesting_level() == run_nesting_level() &&
+      quit_pending_) {
+    // Quit was called while loops other than those managed by this object
+    // were running further inside a run loop managed by this object.  Now
+    // that all unmanaged inner run loops are gone, stop the loop running
+    // just inside Run.
+    CFRunLoopStop(run_loop());
+    quit_pending_ = false;
+  }
+}
+
+MessagePumpNSRunLoop::MessagePumpNSRunLoop()
+    : keep_running_(true) {
+  CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+  source_context.perform = NoOp;
+  quit_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                       0,     // priority
+                                       &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop(), quit_source_);
+}
+
+MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
+  CFRunLoopRemoveSourceFromAllModes(run_loop(), quit_source_);
+  CFRelease(quit_source_);
+}
+
+void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
+  while (keep_running_) {
+    // NSRunLoop manages autorelease pools itself.
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+                             beforeDate:[NSDate distantFuture]];
+  }
+
+  keep_running_ = true;
+}
+
+void MessagePumpNSRunLoop::Quit() {
+  keep_running_ = false;
+  CFRunLoopSourceSignal(quit_source_);
+  CFRunLoopWakeUp(run_loop());
+}
+
+#if defined(OS_IOS)
+MessagePumpUIApplication::MessagePumpUIApplication()
+    : run_loop_(NULL) {
+}
+
+MessagePumpUIApplication::~MessagePumpUIApplication() {}
+
+void MessagePumpUIApplication::DoRun(Delegate* delegate) {
+  NOTREACHED();
+}
+
+void MessagePumpUIApplication::Quit() {
+  NOTREACHED();
+}
+
+void MessagePumpUIApplication::Attach(Delegate* delegate) {
+  DCHECK(!run_loop_);
+  run_loop_ = new RunLoop();
+  CHECK(run_loop_->BeforeRun());
+  SetDelegate(delegate);
+}
+
+#else
+
+MessagePumpNSApplication::MessagePumpNSApplication()
+    : keep_running_(true),
+      running_own_loop_(false) {
+}
+
+MessagePumpNSApplication::~MessagePumpNSApplication() {}
+
+void MessagePumpNSApplication::DoRun(Delegate* delegate) {
+  bool last_running_own_loop_ = running_own_loop_;
+
+  // NSApp must be initialized by calling:
+  // [{some class which implements CrAppProtocol} sharedApplication]
+  // Most likely candidates are CrApplication or BrowserCrApplication.
+  // These can be initialized from C++ code by calling
+  // RegisterCrApp() or RegisterBrowserCrApp().
+  CHECK(NSApp);
+
+  if (![NSApp isRunning]) {
+    running_own_loop_ = false;
+    // NSApplication manages autorelease pools itself when run this way.
+    [NSApp run];
+  } else {
+    running_own_loop_ = true;
+    NSDate* distant_future = [NSDate distantFuture];
+    while (keep_running_) {
+      MessagePumpScopedAutoreleasePool autorelease_pool(this);
+      NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                          untilDate:distant_future
+                                             inMode:NSDefaultRunLoopMode
+                                            dequeue:YES];
+      if (event) {
+        [NSApp sendEvent:event];
+      }
+    }
+    keep_running_ = true;
+  }
+
+  running_own_loop_ = last_running_own_loop_;
+}
+
+void MessagePumpNSApplication::Quit() {
+  if (!running_own_loop_) {
+    [[NSApplication sharedApplication] stop:nil];
+  } else {
+    keep_running_ = false;
+  }
+
+  // Send a fake event to wake the loop up.
+  [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
+                                      location:NSZeroPoint
+                                 modifierFlags:0
+                                     timestamp:0
+                                  windowNumber:0
+                                       context:NULL
+                                       subtype:0
+                                         data1:0
+                                         data2:0]
+           atStart:NO];
+}
+
+MessagePumpCrApplication::MessagePumpCrApplication() {
+}
+
+MessagePumpCrApplication::~MessagePumpCrApplication() {
+}
+
+// Prevents an autorelease pool from being created if the app is in the midst of
+// handling a UI event because various parts of AppKit depend on objects that
+// are created while handling a UI event to be autoreleased in the event loop.
+// An example of this is NSWindowController. When a window with a window
+// controller is closed it goes through a stack like this:
+// (Several stack frames elided for clarity)
+//
+// #0 [NSWindowController autorelease]
+// #1 DoAClose
+// #2 MessagePumpCFRunLoopBase::DoWork()
+// #3 [NSRunLoop run]
+// #4 [NSButton performClick:]
+// #5 [NSWindow sendEvent:]
+// #6 [NSApp sendEvent:]
+// #7 [NSApp run]
+//
+// -performClick: spins a nested run loop. If the pool created in DoWork was a
+// standard NSAutoreleasePool, it would release the objects that were
+// autoreleased into it once DoWork released it. This would cause the window
+// controller, which autoreleased itself in frame #0, to release itself, and
+// possibly free itself. Unfortunately this window controller controls the
+// window in frame #5. When the stack is unwound to frame #5, the window would
+// no longer exists and crashes may occur. Apple gets around this by never
+// releasing the pool it creates in frame #4, and letting frame #7 clean it up
+// when it cleans up the pool that wraps frame #7. When an autorelease pool is
+// released it releases all other pools that were created after it on the
+// autorelease pool stack.
+//
+// CrApplication is responsible for setting handlingSendEvent to true just
+// before it sends the event through the event handling mechanism, and
+// returning it to its previous value once the event has been sent.
+AutoreleasePoolType* MessagePumpCrApplication::CreateAutoreleasePool() {
+  if (MessagePumpMac::IsHandlingSendEvent())
+    return nil;
+  return MessagePumpNSApplication::CreateAutoreleasePool();
+}
+
+// static
+bool MessagePumpMac::UsingCrApp() {
+  DCHECK([NSThread isMainThread]);
+
+  // If NSApp is still not initialized, then the subclass used cannot
+  // be determined.
+  DCHECK(NSApp);
+
+  // The pump was created using MessagePumpNSApplication.
+  if (g_not_using_cr_app)
+    return false;
+
+  return [NSApp conformsToProtocol:@protocol(CrAppProtocol)];
+}
+
+// static
+bool MessagePumpMac::IsHandlingSendEvent() {
+  DCHECK([NSApp conformsToProtocol:@protocol(CrAppProtocol)]);
+  NSObject<CrAppProtocol>* app = static_cast<NSObject<CrAppProtocol>*>(NSApp);
+  return [app isHandlingSendEvent];
+}
+#endif  // !defined(OS_IOS)
+
+// static
+MessagePump* MessagePumpMac::Create() {
+  if ([NSThread isMainThread]) {
+#if defined(OS_IOS)
+    return new MessagePumpUIApplication;
+#else
+    if ([NSApp conformsToProtocol:@protocol(CrAppProtocol)])
+      return new MessagePumpCrApplication;
+
+    // The main-thread MessagePump implementations REQUIRE an NSApp.
+    // Executables which have specific requirements for their
+    // NSApplication subclass should initialize appropriately before
+    // creating an event loop.
+    [NSApplication sharedApplication];
+    g_not_using_cr_app = true;
+    return new MessagePumpNSApplication;
+#endif
+  }
+
+  return new MessagePumpNSRunLoop;
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
new file mode 100644
index 0000000..b3e5604
--- /dev/null
+++ b/base/message_loop/message_pump_perftest.cc
@@ -0,0 +1,293 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/format_macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/java_handler_thread.h"
+#endif
+
+namespace base {
+namespace {
+
+class ScheduleWorkTest : public testing::Test {
+ public:
+  ScheduleWorkTest() : counter_(0) {}
+
+  void Increment(uint64_t amount) { counter_ += amount; }
+
+  void Schedule(int index) {
+    base::TimeTicks start = base::TimeTicks::Now();
+    base::TimeTicks thread_start;
+    if (TimeTicks::IsThreadNowSupported())
+      thread_start = base::TimeTicks::ThreadNow();
+    base::TimeDelta minimum = base::TimeDelta::Max();
+    base::TimeDelta maximum = base::TimeDelta();
+    base::TimeTicks now, lastnow = start;
+    uint64_t schedule_calls = 0u;
+    do {
+      for (size_t i = 0; i < kBatchSize; ++i) {
+        target_message_loop()->ScheduleWork();
+        schedule_calls++;
+      }
+      now = base::TimeTicks::Now();
+      base::TimeDelta laptime = now - lastnow;
+      lastnow = now;
+      minimum = std::min(minimum, laptime);
+      maximum = std::max(maximum, laptime);
+    } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
+
+    scheduling_times_[index] = now - start;
+    if (TimeTicks::IsThreadNowSupported())
+      scheduling_thread_times_[index] =
+          base::TimeTicks::ThreadNow() - thread_start;
+    min_batch_times_[index] = minimum;
+    max_batch_times_[index] = maximum;
+    target_message_loop()->PostTask(FROM_HERE,
+                                    base::Bind(&ScheduleWorkTest::Increment,
+                                               base::Unretained(this),
+                                               schedule_calls));
+  }
+
+  void ScheduleWork(MessageLoop::Type target_type, int num_scheduling_threads) {
+#if defined(OS_ANDROID)
+    if (target_type == MessageLoop::TYPE_JAVA) {
+      java_thread_.reset(new android::JavaHandlerThread("target"));
+      java_thread_->Start();
+    } else
+#endif
+    {
+      target_.reset(new Thread("target"));
+      target_->StartWithOptions(Thread::Options(target_type, 0u));
+    }
+
+    ScopedVector<Thread> scheduling_threads;
+    scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+    scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+    min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+    max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      scheduling_threads.push_back(new Thread("posting thread"));
+      scheduling_threads[i]->Start();
+    }
+
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      scheduling_threads[i]->message_loop()->PostTask(
+          FROM_HERE,
+          base::Bind(&ScheduleWorkTest::Schedule, base::Unretained(this), i));
+    }
+
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      scheduling_threads[i]->Stop();
+    }
+#if defined(OS_ANDROID)
+    if (target_type == MessageLoop::TYPE_JAVA) {
+      java_thread_->Stop();
+      java_thread_.reset();
+    } else
+#endif
+    {
+      target_->Stop();
+      target_.reset();
+    }
+    base::TimeDelta total_time;
+    base::TimeDelta total_thread_time;
+    base::TimeDelta min_batch_time = base::TimeDelta::Max();
+    base::TimeDelta max_batch_time = base::TimeDelta();
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      total_time += scheduling_times_[i];
+      total_thread_time += scheduling_thread_times_[i];
+      min_batch_time = std::min(min_batch_time, min_batch_times_[i]);
+      max_batch_time = std::max(max_batch_time, max_batch_times_[i]);
+    }
+    std::string trace = StringPrintf(
+        "%d_threads_scheduling_to_%s_pump",
+        num_scheduling_threads,
+        target_type == MessageLoop::TYPE_IO
+            ? "io"
+            : (target_type == MessageLoop::TYPE_UI ? "ui" : "default"));
+    perf_test::PrintResult(
+        "task",
+        "",
+        trace,
+        total_time.InMicroseconds() / static_cast<double>(counter_),
+        "us/task",
+        true);
+    perf_test::PrintResult(
+        "task",
+        "_min_batch_time",
+        trace,
+        min_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
+        "us/task",
+        false);
+    perf_test::PrintResult(
+        "task",
+        "_max_batch_time",
+        trace,
+        max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
+        "us/task",
+        false);
+    if (TimeTicks::IsThreadNowSupported()) {
+      perf_test::PrintResult(
+          "task",
+          "_thread_time",
+          trace,
+          total_thread_time.InMicroseconds() / static_cast<double>(counter_),
+          "us/task",
+          true);
+    }
+  }
+
+  MessageLoop* target_message_loop() {
+#if defined(OS_ANDROID)
+    if (java_thread_)
+      return java_thread_->message_loop();
+#endif
+    return target_->message_loop();
+  }
+
+ private:
+  scoped_ptr<Thread> target_;
+#if defined(OS_ANDROID)
+  scoped_ptr<android::JavaHandlerThread> java_thread_;
+#endif
+  scoped_ptr<base::TimeDelta[]> scheduling_times_;
+  scoped_ptr<base::TimeDelta[]> scheduling_thread_times_;
+  scoped_ptr<base::TimeDelta[]> min_batch_times_;
+  scoped_ptr<base::TimeDelta[]> max_batch_times_;
+  uint64_t counter_;
+
+  static const size_t kTargetTimeSec = 5;
+  static const size_t kBatchSize = 1000;
+};
+
+TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_IO, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_IO, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_IO, 4);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_UI, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_UI, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_UI, 4);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_DEFAULT, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_DEFAULT, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_DEFAULT, 4);
+}
+
+#if defined(OS_ANDROID)
+TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_JAVA, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_JAVA, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_JAVA, 4);
+}
+#endif
+
+static void DoNothing() {
+}
+
+class FakeMessagePump : public MessagePump {
+ public:
+  FakeMessagePump() {}
+  ~FakeMessagePump() override {}
+
+  void Run(Delegate* delegate) override {}
+
+  void Quit() override {}
+  void ScheduleWork() override {}
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override {}
+};
+
+class PostTaskTest : public testing::Test {
+ public:
+  void Run(int batch_size, int tasks_per_reload) {
+    base::TimeTicks start = base::TimeTicks::Now();
+    base::TimeTicks now;
+    MessageLoop loop(scoped_ptr<MessagePump>(new FakeMessagePump));
+    scoped_refptr<internal::IncomingTaskQueue> queue(
+        new internal::IncomingTaskQueue(&loop));
+    uint32_t num_posted = 0;
+    do {
+      for (int i = 0; i < batch_size; ++i) {
+        for (int j = 0; j < tasks_per_reload; ++j) {
+          queue->AddToIncomingQueue(
+              FROM_HERE, base::Bind(&DoNothing), base::TimeDelta(), false);
+          num_posted++;
+        }
+        TaskQueue loop_local_queue;
+        queue->ReloadWorkQueue(&loop_local_queue);
+        while (!loop_local_queue.empty()) {
+          PendingTask t = loop_local_queue.front();
+          loop_local_queue.pop();
+          loop.RunTask(t);
+        }
+      }
+
+      now = base::TimeTicks::Now();
+    } while (now - start < base::TimeDelta::FromSeconds(5));
+    std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
+    perf_test::PrintResult(
+        "task",
+        "",
+        trace,
+        (now - start).InMicroseconds() / static_cast<double>(num_posted),
+        "us/task",
+        true);
+  }
+};
+
+TEST_F(PostTaskTest, OneTaskPerReload) {
+  Run(10000, 1);
+}
+
+TEST_F(PostTaskTest, TenTasksPerReload) {
+  Run(10000, 10);
+}
+
+TEST_F(PostTaskTest, OneHundredTasksPerReload) {
+  Run(1000, 100);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
new file mode 100644
index 0000000..27b47e1
--- /dev/null
+++ b/base/message_loop/message_pump_win.cc
@@ -0,0 +1,699 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_pump_win.h"
+
+#include <limits>
+#include <math.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/win/wrapped_window_proc.h"
+
+namespace base {
+
+namespace {
+
+enum MessageLoopProblems {
+  MESSAGE_POST_ERROR,
+  COMPLETION_POST_ERROR,
+  SET_TIMER_ERROR,
+  MESSAGE_LOOP_PROBLEM_MAX,
+};
+
+}  // namespace
+
+static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p";
+
+// Message sent to get an additional time slice for pumping (processing) another
+// task (a series of such messages creates a continuous task pump).
+static const int kMsgHaveWork = WM_USER + 1;
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin public:
+
+void MessagePumpWin::RunWithDispatcher(
+    Delegate* delegate, MessagePumpDispatcher* dispatcher) {
+  RunState s;
+  s.delegate = delegate;
+  s.dispatcher = dispatcher;
+  s.should_quit = false;
+  s.run_depth = state_ ? state_->run_depth + 1 : 1;
+
+  RunState* previous_state = state_;
+  state_ = &s;
+
+  DoRunLoop();
+
+  state_ = previous_state;
+}
+
+void MessagePumpWin::Run(Delegate* delegate) {
+  RunWithDispatcher(delegate, NULL);
+}
+
+void MessagePumpWin::Quit() {
+  DCHECK(state_);
+  state_->should_quit = true;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin protected:
+
+int MessagePumpWin::GetCurrentDelay() const {
+  if (delayed_work_time_.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  double timeout =
+      ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
+
+  // Range check the |timeout| while converting to an integer.  If the |timeout|
+  // is negative, then we need to run delayed work soon.  If the |timeout| is
+  // "overflowingly" large, that means a delayed task was posted with a
+  // super-long delay.
+  return timeout < 0 ? 0 :
+      (timeout > std::numeric_limits<int>::max() ?
+       std::numeric_limits<int>::max() : static_cast<int>(timeout));
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI public:
+
+MessagePumpForUI::MessagePumpForUI()
+    : atom_(0) {
+  InitMessageWnd();
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+  DestroyWindow(message_hwnd_);
+  UnregisterClass(MAKEINTATOM(atom_),
+                  GetModuleFromAddress(&WndProcThunk));
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  if (InterlockedExchange(&have_work_, 1))
+    return;  // Someone else continued the pumping.
+
+  // Make sure the MessagePump does some work for us.
+  BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork,
+                         reinterpret_cast<WPARAM>(this), 0);
+  if (ret)
+    return;  // There was room in the Window Message queue.
+
+  // We have failed to insert a have-work message, so there is a chance that we
+  // will starve tasks/timers while sitting in a nested message loop.  Nested
+  // loops only look at Windows Message queues, and don't look at *our* task
+  // queues, etc., so we might not get a time slice in such. :-(
+  // We could abort here, but the fear is that this failure mode is plausibly
+  // common (queue is full, of about 2000 messages), so we'll do a near-graceful
+  // recovery.  Nested loops are pretty transient (we think), so this will
+  // probably be recoverable.
+  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't really insert.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  //
+  // We would *like* to provide high resolution timers.  Windows timers using
+  // SetTimer() have a 10ms granularity.  We have to use WM_TIMER as a wakeup
+  // mechanism because the application can enter modal windows loops where it
+  // is not running our MessageLoop; the only way to have our timers fire in
+  // these cases is to post messages there.
+  //
+  // To provide sub-10ms timers, we process timers directly from our run loop.
+  // For the common case, timers will be processed there as the run loop does
+  // its normal work.  However, we *also* set the system timer so that WM_TIMER
+  // events fire.  This mops up the case of timers not being able to work in
+  // modal message loops.  It is possible for the SetTimer to pop and have no
+  // pending timers, because they could have already been processed by the
+  // run loop itself.
+  //
+  // We use a single SetTimer corresponding to the timer that will expire
+  // soonest.  As new timers are created and destroyed, we update SetTimer.
+  // Getting a spurrious SetTimer event firing is benign, as we'll just be
+  // processing an empty timer queue.
+  //
+  delayed_work_time_ = delayed_work_time;
+
+  int delay_msec = GetCurrentDelay();
+  DCHECK_GE(delay_msec, 0);
+  if (delay_msec < USER_TIMER_MINIMUM)
+    delay_msec = USER_TIMER_MINIMUM;
+
+  // Create a WM_TIMER event that will wake us up to check for any pending
+  // timers (in case we are running within a nested, external sub-pump).
+  BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
+                      delay_msec, NULL);
+  if (ret)
+    return;
+  // If we can't set timers, we are in big trouble... but cross our fingers for
+  // now.
+  // TODO(jar): If we don't see this error, use a CHECK() here instead.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI private:
+
+// static
+LRESULT CALLBACK MessagePumpForUI::WndProcThunk(
+    HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::WndProcThunk1"));
+
+  switch (message) {
+    case kMsgHaveWork:
+      reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
+      break;
+    case WM_TIMER:
+      reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
+      break;
+  }
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::WndProcThunk2"));
+
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+void MessagePumpForUI::DoRunLoop() {
+  // IF this was just a simple PeekMessage() loop (servicing all possible work
+  // queues), then Windows would try to achieve the following order according
+  // to MSDN documentation about PeekMessage with no filter):
+  //    * Sent messages
+  //    * Posted messages
+  //    * Sent messages (again)
+  //    * WM_PAINT messages
+  //    * WM_TIMER messages
+  //
+  // Summary: none of the above classes is starved, and sent messages has twice
+  // the chance of being processed (i.e., reduced service time).
+
+  for (;;) {
+    // If we do any work, we may create more messages etc., and more work may
+    // possibly be waiting in another task group.  When we (for example)
+    // ProcessNextWindowsMessage(), there is a good chance there are still more
+    // messages waiting.  On the other hand, when any of these methods return
+    // having done no work, then it is pretty unlikely that calling them again
+    // quickly will find any work to do.  Finally, if they all say they had no
+    // work, then it is a good time to consider sleeping (waiting) for more
+    // work.
+
+    bool more_work_is_plausible = ProcessNextWindowsMessage();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    // If we did not process any delayed work, then we can assume that our
+    // existing WM_TIMER if any will fire when delayed work should run.  We
+    // don't want to disturb that timer if it is already in flight.  However,
+    // if we did do all remaining delayed work, then lets kill the WM_TIMER.
+    if (more_work_is_plausible && delayed_work_time_.is_null())
+      KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+void MessagePumpForUI::InitMessageWnd() {
+  // Generate a unique window class name.
+  string16 class_name = StringPrintf(kWndClassFormat, this);
+
+  HINSTANCE instance = GetModuleFromAddress(&WndProcThunk);
+  WNDCLASSEX wc = {0};
+  wc.cbSize = sizeof(wc);
+  wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>;
+  wc.hInstance = instance;
+  wc.lpszClassName = class_name.c_str();
+  atom_ = RegisterClassEx(&wc);
+  DCHECK(atom_);
+
+  message_hwnd_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0,
+                               HWND_MESSAGE, 0, instance, 0);
+  DCHECK(message_hwnd_);
+}
+
+void MessagePumpForUI::WaitForWork() {
+  // Wait until a message is available, up to the time needed by the timer
+  // manager to fire the next set of timers.
+  int delay = GetCurrentDelay();
+  if (delay < 0)  // Negative value means no timers waiting.
+    delay = INFINITE;
+
+  DWORD result;
+  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
+                                       MWMO_INPUTAVAILABLE);
+
+  if (WAIT_OBJECT_0 == result) {
+    // A WM_* message is available.
+    // If a parent child relationship exists between windows across threads
+    // then their thread inputs are implicitly attached.
+    // This causes the MsgWaitForMultipleObjectsEx API to return indicating
+    // that messages are ready for processing (Specifically, mouse messages
+    // intended for the child window may appear if the child window has
+    // capture).
+    // The subsequent PeekMessages call may fail to return any messages thus
+    // causing us to enter a tight loop at times.
+    // The WaitMessage call below is a workaround to give the child window
+    // some time to process its input messages.
+    MSG msg = {0};
+    DWORD queue_status = GetQueueStatus(QS_MOUSE);
+    if (HIWORD(queue_status) & QS_MOUSE &&
+        !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
+      WaitMessage();
+    }
+    return;
+  }
+
+  DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+}
+
+void MessagePumpForUI::HandleWorkMessage() {
+  // If we are being called outside of the context of Run, then don't try to do
+  // any work.  This could correspond to a MessageBox call or something of that
+  // sort.
+  if (!state_) {
+    // Since we handled a kMsgHaveWork message, we must still update this flag.
+    InterlockedExchange(&have_work_, 0);
+    return;
+  }
+
+  // Let whatever would have run had we not been putting messages in the queue
+  // run now.  This is an attempt to make our dummy message not starve other
+  // messages that may be in the Windows message queue.
+  ProcessPumpReplacementMessage();
+
+  // Now give the delegate a chance to do some work.  He'll let us know if he
+  // needs to do more work.
+  if (state_->delegate->DoWork())
+    ScheduleWork();
+}
+
+void MessagePumpForUI::HandleTimerMessage() {
+  KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+
+  // If we are being called outside of the context of Run, then don't do
+  // anything.  This could correspond to a MessageBox call or something of
+  // that sort.
+  if (!state_)
+    return;
+
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+  if (!delayed_work_time_.is_null()) {
+    // A bit gratuitous to set delayed_work_time_ again, but oh well.
+    ScheduleDelayedWork(delayed_work_time_);
+  }
+}
+
+bool MessagePumpForUI::ProcessNextWindowsMessage() {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessNextWindowsMessage1"));
+
+  // If there are sent messages in the queue then PeekMessage internally
+  // dispatches the message and returns false. We return true in this
+  // case to ensure that the message loop peeks again instead of calling
+  // MsgWaitForMultipleObjectsEx again.
+  bool sent_messages_in_queue = false;
+  DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
+  if (HIWORD(queue_status) & QS_SENDMESSAGE)
+    sent_messages_in_queue = true;
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessNextWindowsMessage2"));
+
+  MSG msg;
+  if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE)
+    return ProcessMessageHelper(msg);
+
+  return sent_messages_in_queue;
+}
+
+bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessMessageHelper1"));
+
+  TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
+               "message", msg.message);
+  if (WM_QUIT == msg.message) {
+    // Repost the QUIT message so that it will be retrieved by the primary
+    // GetMessage() loop.
+    state_->should_quit = true;
+    PostQuitMessage(static_cast<int>(msg.wParam));
+    return false;
+  }
+
+  // While running our main message pump, we discard kMsgHaveWork messages.
+  if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
+    return ProcessPumpReplacementMessage();
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessMessageHelper2"));
+
+  if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
+    return true;
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile3(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessMessageHelper3"));
+
+  uint32_t action = MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT;
+  if (state_->dispatcher) {
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+    tracked_objects::ScopedTracker tracking_profile4(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "440919 MessagePumpForUI::ProcessMessageHelper4"));
+
+    action = state_->dispatcher->Dispatch(msg);
+  }
+  if (action & MessagePumpDispatcher::POST_DISPATCH_QUIT_LOOP)
+    state_->should_quit = true;
+  if (action & MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT) {
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+    tracked_objects::ScopedTracker tracking_profile5(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "440919 MessagePumpForUI::ProcessMessageHelper5"));
+
+    TranslateMessage(&msg);
+
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+    tracked_objects::ScopedTracker tracking_profile6(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "440919 MessagePumpForUI::ProcessMessageHelper6"));
+
+    DispatchMessage(&msg);
+  }
+
+  return true;
+}
+
+bool MessagePumpForUI::ProcessPumpReplacementMessage() {
+  // When we encounter a kMsgHaveWork message, this method is called to peek
+  // and process a replacement message, such as a WM_PAINT or WM_TIMER.  The
+  // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
+  // a continuous stream of such messages are posted.  This method carefully
+  // peeks a message while there is no chance for a kMsgHaveWork to be pending,
+  // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
+  // possibly be posted), and finally dispatches that peeked replacement.  Note
+  // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
+
+  bool have_message = false;
+  MSG msg;
+  // We should not process all window messages if we are in the context of an
+  // OS modal loop, i.e. in the context of a windows API call like MessageBox.
+  // This is to ensure that these messages are peeked out by the OS modal loop.
+  if (MessageLoop::current()->os_modal_loop()) {
+    // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
+    have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
+                   PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
+  } else {
+    have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE;
+  }
+
+  DCHECK(!have_message || kMsgHaveWork != msg.message ||
+         msg.hwnd != message_hwnd_);
+
+  // Since we discarded a kMsgHaveWork message, we must update the flag.
+  int old_have_work = InterlockedExchange(&have_work_, 0);
+  DCHECK(old_have_work);
+
+  // We don't need a special time slice if we didn't have_message to process.
+  if (!have_message)
+    return false;
+
+  // Guarantee we'll get another time slice in the case where we go into native
+  // windows code.   This ScheduleWork() may hurt performance a tiny bit when
+  // tasks appear very infrequently, but when the event queue is busy, the
+  // kMsgHaveWork events get (percentage wise) rarer and rarer.
+  ScheduleWork();
+  return ProcessMessageHelper(msg);
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO public:
+
+MessagePumpForIO::MessagePumpForIO() {
+  port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
+  DCHECK(port_.IsValid());
+}
+
+MessagePumpForIO::~MessagePumpForIO() {
+}
+
+void MessagePumpForIO::ScheduleWork() {
+  if (InterlockedExchange(&have_work_, 1))
+    return;  // Someone else continued the pumping.
+
+  // Make sure the MessagePump does some work for us.
+  BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0,
+                                        reinterpret_cast<ULONG_PTR>(this),
+                                        reinterpret_cast<OVERLAPPED*>(this));
+  if (ret)
+    return;  // Post worked perfectly.
+
+  // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
+  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't succeed.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked right now since this method can only be
+  // called on the same thread as Run, so we only need to update our record of
+  // how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
+                                         IOHandler* handler) {
+  ULONG_PTR key = HandlerToKey(handler, true);
+  HANDLE port = CreateIoCompletionPort(file_handle, port_.Get(), key, 1);
+  DPCHECK(port);
+}
+
+bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle,
+                                         IOHandler* handler) {
+  // Job object notifications use the OVERLAPPED pointer to carry the message
+  // data. Mark the completion key correspondingly, so we will not try to
+  // convert OVERLAPPED* to IOContext*.
+  ULONG_PTR key = HandlerToKey(handler, false);
+  JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
+  info.CompletionKey = reinterpret_cast<void*>(key);
+  info.CompletionPort = port_.Get();
+  return SetInformationJobObject(job_handle,
+                                 JobObjectAssociateCompletionPortInformation,
+                                 &info,
+                                 sizeof(info)) != FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO private:
+
+void MessagePumpForIO::DoRunLoop() {
+  for (;;) {
+    // If we do any work, we may create more messages etc., and more work may
+    // possibly be waiting in another task group.  When we (for example)
+    // WaitForIOCompletion(), there is a good chance there are still more
+    // messages waiting.  On the other hand, when any of these methods return
+    // having done no work, then it is pretty unlikely that calling them
+    // again quickly will find any work to do.  Finally, if they all say they
+    // had no work, then it is a good time to consider sleeping (waiting) for
+    // more work.
+
+    bool more_work_is_plausible = state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= WaitForIOCompletion(0, NULL);
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+// Wait until IO completes, up to the time needed by the timer manager to fire
+// the next set of timers.
+void MessagePumpForIO::WaitForWork() {
+  // We do not support nested IO message loops. This is to avoid messy
+  // recursion problems.
+  DCHECK_EQ(1, state_->run_depth) << "Cannot nest an IO message loop!";
+
+  int timeout = GetCurrentDelay();
+  if (timeout < 0)  // Negative value means no timers waiting.
+    timeout = INFINITE;
+
+  WaitForIOCompletion(timeout, NULL);
+}
+
+bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+  IOItem item;
+  if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) {
+    // We have to ask the system for another IO completion.
+    if (!GetIOItem(timeout, &item))
+      return false;
+
+    if (ProcessInternalIOItem(item))
+      return true;
+  }
+
+  // If |item.has_valid_io_context| is false then |item.context| does not point
+  // to a context structure, and so should not be dereferenced, although it may
+  // still hold valid non-pointer data.
+  if (!item.has_valid_io_context || item.context->handler) {
+    if (filter && item.handler != filter) {
+      // Save this item for later
+      completed_io_.push_back(item);
+    } else {
+      DCHECK(!item.has_valid_io_context ||
+             (item.context->handler == item.handler));
+      WillProcessIOEvent();
+      item.handler->OnIOCompleted(item.context, item.bytes_transfered,
+                                  item.error);
+      DidProcessIOEvent();
+    }
+  } else {
+    // The handler must be gone by now, just cleanup the mess.
+    delete item.context;
+  }
+  return true;
+}
+
+// Asks the OS for another IO completion result.
+bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
+  memset(item, 0, sizeof(*item));
+  ULONG_PTR key = NULL;
+  OVERLAPPED* overlapped = NULL;
+  if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key,
+                                 &overlapped, timeout)) {
+    if (!overlapped)
+      return false;  // Nothing in the queue.
+    item->error = GetLastError();
+    item->bytes_transfered = 0;
+  }
+
+  item->handler = KeyToHandler(key, &item->has_valid_io_context);
+  item->context = reinterpret_cast<IOContext*>(overlapped);
+  return true;
+}
+
+bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
+  if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
+      this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
+    // This is our internal completion.
+    DCHECK(!item.bytes_transfered);
+    InterlockedExchange(&have_work_, 0);
+    return true;
+  }
+  return false;
+}
+
+// Returns a completion item that was previously received.
+bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
+  DCHECK(!completed_io_.empty());
+  for (std::list<IOItem>::iterator it = completed_io_.begin();
+       it != completed_io_.end(); ++it) {
+    if (!filter || it->handler == filter) {
+      *item = *it;
+      completed_io_.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
+void MessagePumpForIO::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpForIO::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpForIO::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpForIO::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler,
+                                         bool has_valid_io_context) {
+  ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
+
+  // |IOHandler| is at least pointer-size aligned, so the lowest two bits are
+  // always cleared. We use the lowest bit to distinguish completion keys with
+  // and without the associated |IOContext|.
+  DCHECK_EQ(key & 1, 0u);
+
+  // Mark the completion key as context-less.
+  if (!has_valid_io_context)
+    key = key | 1;
+  return key;
+}
+
+// static
+MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
+    ULONG_PTR key,
+    bool* has_valid_io_context) {
+  *has_valid_io_context = ((key & 1) == 0);
+  return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
new file mode 100644
index 0000000..00f1287
--- /dev/null
+++ b/base/message_loop/message_pump_win.h
@@ -0,0 +1,340 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
+
+#include <windows.h>
+
+#include <list>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+// MessagePumpWin serves as the base for specialized versions of the MessagePump
+// for Windows. It provides basic functionality like handling of observers and
+// controlling the lifetime of the message pump.
+class BASE_EXPORT MessagePumpWin : public MessagePump {
+ public:
+  MessagePumpWin() : have_work_(0), state_(NULL) {}
+
+  // Like MessagePump::Run, but MSG objects are routed through dispatcher.
+  void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher);
+
+  // MessagePump methods:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+
+ protected:
+  struct RunState {
+    Delegate* delegate;
+    MessagePumpDispatcher* dispatcher;
+
+    // Used to flag that the current Run() invocation should return ASAP.
+    bool should_quit;
+
+    // Used to count how many Run() invocations are on the stack.
+    int run_depth;
+  };
+
+  virtual void DoRunLoop() = 0;
+  int GetCurrentDelay() const;
+
+  // The time at which delayed work should run.
+  TimeTicks delayed_work_time_;
+
+  // A boolean value used to indicate if there is a kMsgDoWork message pending
+  // in the Windows Message queue.  There is at most one such message, and it
+  // can drive execution of tasks when a native message pump is running.
+  LONG have_work_;
+
+  // State for the current invocation of Run.
+  RunState* state_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// MessagePumpForUI implements a "traditional" Windows message pump. It contains
+// a nearly infinite loop that peeks out messages, and then dispatches them.
+// Intermixed with those peeks are callouts to DoWork for pending tasks, and
+// DoDelayedWork for pending timers. When there are no events to be serviced,
+// this pump goes into a wait state. In most cases, this message pump handles
+// all processing.
+//
+// However, when a task, or windows event, invokes on the stack a native dialog
+// box or such, that window typically provides a bare bones (native?) message
+// pump.  That bare-bones message pump generally supports little more than a
+// peek of the Windows message queue, followed by a dispatch of the peeked
+// message.  MessageLoop extends that bare-bones message pump to also service
+// Tasks, at the cost of some complexity.
+//
+// The basic structure of the extension (refered to as a sub-pump) is that a
+// special message, kMsgHaveWork, is repeatedly injected into the Windows
+// Message queue.  Each time the kMsgHaveWork message is peeked, checks are
+// made for an extended set of events, including the availability of Tasks to
+// run.
+//
+// After running a task, the special message kMsgHaveWork is again posted to
+// the Windows Message queue, ensuring a future time slice for processing a
+// future event.  To prevent flooding the Windows Message queue, care is taken
+// to be sure that at most one kMsgHaveWork message is EVER pending in the
+// Window's Message queue.
+//
+// There are a few additional complexities in this system where, when there are
+// no Tasks to run, this otherwise infinite stream of messages which drives the
+// sub-pump is halted.  The pump is automatically re-started when Tasks are
+// queued.
+//
+// A second complexity is that the presence of this stream of posted tasks may
+// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER.
+// Such paint and timer events always give priority to a posted message, such as
+// kMsgHaveWork messages.  As a result, care is taken to do some peeking in
+// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork
+// is peeked, and before a replacement kMsgHaveWork is posted).
+//
+// NOTE: Although it may seem odd that messages are used to start and stop this
+// flow (as opposed to signaling objects, etc.), it should be understood that
+// the native message pump will *only* respond to messages.  As a result, it is
+// an excellent choice.  It is also helpful that the starter messages that are
+// placed in the queue when new task arrive also awakens DoRunLoop.
+//
+class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
+ public:
+  // The application-defined code passed to the hook procedure.
+  static const int kMessageFilterCode = 0x5001;
+
+  MessagePumpForUI();
+  ~MessagePumpForUI() override;
+
+  // MessagePump methods:
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  static LRESULT CALLBACK WndProcThunk(HWND window_handle,
+                                       UINT message,
+                                       WPARAM wparam,
+                                       LPARAM lparam);
+  void DoRunLoop() override;
+  void InitMessageWnd();
+  void WaitForWork();
+  void HandleWorkMessage();
+  void HandleTimerMessage();
+  bool ProcessNextWindowsMessage();
+  bool ProcessMessageHelper(const MSG& msg);
+  bool ProcessPumpReplacementMessage();
+
+  // Atom representing the registered window class.
+  ATOM atom_;
+
+  // A hidden message-only window.
+  HWND message_hwnd_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO. This version of MessagePump does not
+// deal with Windows mesagges, and instead has a Run loop based on Completion
+// Ports so it is better suited for IO operations.
+//
+class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
+ public:
+  struct IOContext;
+
+  // Clients interested in receiving OS notifications when asynchronous IO
+  // operations complete should implement this interface and register themselves
+  // with the message pump.
+  //
+  // Typical use #1:
+  //   // Use only when there are no user's buffers involved on the actual IO,
+  //   // so that all the cleanup can be done by the message pump.
+  //   class MyFile : public IOHandler {
+  //     MyFile() {
+  //       ...
+  //       context_ = new IOContext;
+  //       context_->handler = this;
+  //       message_pump->RegisterIOHandler(file_, this);
+  //     }
+  //     ~MyFile() {
+  //       if (pending_) {
+  //         // By setting the handler to NULL, we're asking for this context
+  //         // to be deleted when received, without calling back to us.
+  //         context_->handler = NULL;
+  //       } else {
+  //         delete context_;
+  //      }
+  //     }
+  //     virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+  //                                DWORD error) {
+  //         pending_ = false;
+  //     }
+  //     void DoSomeIo() {
+  //       ...
+  //       // The only buffer required for this operation is the overlapped
+  //       // structure.
+  //       ConnectNamedPipe(file_, &context_->overlapped);
+  //       pending_ = true;
+  //     }
+  //     bool pending_;
+  //     IOContext* context_;
+  //     HANDLE file_;
+  //   };
+  //
+  // Typical use #2:
+  //   class MyFile : public IOHandler {
+  //     MyFile() {
+  //       ...
+  //       message_pump->RegisterIOHandler(file_, this);
+  //     }
+  //     // Plus some code to make sure that this destructor is not called
+  //     // while there are pending IO operations.
+  //     ~MyFile() {
+  //     }
+  //     virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+  //                                DWORD error) {
+  //       ...
+  //       delete context;
+  //     }
+  //     void DoSomeIo() {
+  //       ...
+  //       IOContext* context = new IOContext;
+  //       // This is not used for anything. It just prevents the context from
+  //       // being considered "abandoned".
+  //       context->handler = this;
+  //       ReadFile(file_, buffer, num_bytes, &read, &context->overlapped);
+  //     }
+  //     HANDLE file_;
+  //   };
+  //
+  // Typical use #3:
+  // Same as the previous example, except that in order to deal with the
+  // requirement stated for the destructor, the class calls WaitForIOCompletion
+  // from the destructor to block until all IO finishes.
+  //     ~MyFile() {
+  //       while(pending_)
+  //         message_pump->WaitForIOCompletion(INFINITE, this);
+  //     }
+  //
+  class IOHandler {
+   public:
+    virtual ~IOHandler() {}
+    // This will be called once the pending IO operation associated with
+    // |context| completes. |error| is the Win32 error code of the IO operation
+    // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
+    // on error.
+    virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+                               DWORD error) = 0;
+  };
+
+  // An IOObserver is an object that receives IO notifications from the
+  // MessagePump.
+  //
+  // NOTE: An IOObserver implementation should be extremely fast!
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // The extended context that should be used as the base structure on every
+  // overlapped IO operation. |handler| must be set to the registered IOHandler
+  // for the given file when the operation is started, and it can be set to NULL
+  // before the operation completes to indicate that the handler should not be
+  // called anymore, and instead, the IOContext should be deleted when the OS
+  // notifies the completion of this operation. Please remember that any buffers
+  // involved with an IO operation should be around until the callback is
+  // received, so this technique can only be used for IO that do not involve
+  // additional buffers (other than the overlapped structure itself).
+  struct IOContext {
+    OVERLAPPED overlapped;
+    IOHandler* handler;
+  };
+
+  MessagePumpForIO();
+  ~MessagePumpForIO() override;
+
+  // MessagePump methods:
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+  // Register the handler to be used when asynchronous IO for the given file
+  // completes. The registration persists as long as |file_handle| is valid, so
+  // |handler| must be valid as long as there is pending IO for the given file.
+  void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
+
+  // Register the handler to be used to process job events. The registration
+  // persists as long as the job object is live, so |handler| must be valid
+  // until the job object is destroyed. Returns true if the registration
+  // succeeded, and false otherwise.
+  bool RegisterJobObject(HANDLE job_handle, IOHandler* handler);
+
+  // Waits for the next IO completion that should be processed by |filter|, for
+  // up to |timeout| milliseconds. Return true if any IO operation completed,
+  // regardless of the involved handler, and false if the timeout expired. If
+  // the completion port received any message and the involved IO handler
+  // matches |filter|, the callback is called before returning from this code;
+  // if the handler is not the one that we are looking for, the callback will
+  // be postponed for another time, so reentrancy problems can be avoided.
+  // External use of this method should be reserved for the rare case when the
+  // caller is willing to allow pausing regular task dispatching on this thread.
+  bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+ private:
+  struct IOItem {
+    IOHandler* handler;
+    IOContext* context;
+    DWORD bytes_transfered;
+    DWORD error;
+
+    // In some cases |context| can be a non-pointer value casted to a pointer.
+    // |has_valid_io_context| is true if |context| is a valid IOContext
+    // pointer, and false otherwise.
+    bool has_valid_io_context;
+  };
+
+  void DoRunLoop() override;
+  void WaitForWork();
+  bool MatchCompletedIOItem(IOHandler* filter, IOItem* item);
+  bool GetIOItem(DWORD timeout, IOItem* item);
+  bool ProcessInternalIOItem(const IOItem& item);
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  // Converts an IOHandler pointer to a completion port key.
+  // |has_valid_io_context| specifies whether completion packets posted to
+  // |handler| will have valid OVERLAPPED pointers.
+  static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context);
+
+  // Converts a completion port key to an IOHandler pointer.
+  static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context);
+
+  // The completion port associated with this thread.
+  win::ScopedHandle port_;
+  // This list will be empty almost always. It stores IO completions that have
+  // not been delivered yet because somebody was doing cleanup.
+  std::list<IOItem> completed_io_;
+
+  ObserverList<IOObserver> io_observers_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
diff --git a/base/message_loop/timer_slack.h b/base/message_loop/timer_slack.h
new file mode 100644
index 0000000..1ad6ca9
--- /dev/null
+++ b/base/message_loop/timer_slack.h
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_TIMER_SLACK_H_
+#define BASE_MESSAGE_LOOP_TIMER_SLACK_H_
+
+namespace base {
+
+// Amount of timer slack to use for delayed timers.  Increasing timer slack
+// allows the OS to coalesce timers more effectively.
+enum TimerSlack {
+  // Lowest value for timer slack allowed by OS.
+  TIMER_SLACK_NONE,
+
+  // Maximal value for timer slack allowed by OS.
+  TIMER_SLACK_MAXIMUM
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_TIMER_SLACK_H_
diff --git a/base/metrics/BUILD.gn b/base/metrics/BUILD.gn
new file mode 100644
index 0000000..845ac4f
--- /dev/null
+++ b/base/metrics/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("metrics") {
+  sources = [
+    "bucket_ranges.cc",
+    "bucket_ranges.h",
+    "field_trial.cc",
+    "field_trial.h",
+    "histogram.cc",
+    "histogram.h",
+    "histogram_base.cc",
+    "histogram_base.h",
+    "histogram_delta_serialization.cc",
+    "histogram_delta_serialization.h",
+    "histogram_flattener.h",
+    "histogram_macros.h",
+    "histogram_samples.cc",
+    "histogram_samples.h",
+    "histogram_snapshot_manager.cc",
+    "histogram_snapshot_manager.h",
+    "sample_map.cc",
+    "sample_map.h",
+    "sample_vector.cc",
+    "sample_vector.h",
+    "sparse_histogram.cc",
+    "sparse_histogram.h",
+    "statistics_recorder.cc",
+    "statistics_recorder.h",
+    "user_metrics.cc",
+    "user_metrics.h",
+    "user_metrics_action.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [ "field_trial.cc" ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/debug",
+    "//base/json",
+    "//base/memory",
+  ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS
new file mode 100644
index 0000000..3fd7c0d
--- /dev/null
+++ b/base/metrics/OWNERS
@@ -0,0 +1,3 @@
+asvitkine@chromium.org
+isherman@chromium.org
+jar@chromium.org
diff --git a/base/metrics/bucket_ranges.cc b/base/metrics/bucket_ranges.cc
new file mode 100644
index 0000000..949c813
--- /dev/null
+++ b/base/metrics/bucket_ranges.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/bucket_ranges.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Static table of checksums for all possible 8 bit bytes.
+const uint32 kCrcTable[256] = { 0x0, 0x77073096L, 0xee0e612cL,
+0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
+0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
+0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
+0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
+0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
+0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
+0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
+0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
+0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
+0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
+0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
+0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
+0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
+0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
+0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
+0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
+0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
+0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
+0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
+0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
+0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
+0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
+0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
+0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
+0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
+0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
+0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
+0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
+0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
+0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
+0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
+0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
+0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
+0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
+0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
+0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+0x2d02ef8dL,
+};
+
+// We generate the CRC-32 using the low order bits to select whether to XOR in
+// the reversed polynomial 0xedb88320L.  This is nice and simple, and allows us
+// to keep the quotient in a uint32.  Since we're not concerned about the nature
+// of corruptions (i.e., we don't care about bit sequencing, since we are
+// handling memory changes, which are more grotesque) so we don't bother to
+// get the CRC correct for big-endian vs little-ending calculations.  All we
+// need is a nice hash, that tends to depend on all the bits of the sample, with
+// very little chance of changes in one place impacting changes in another
+// place.
+static uint32 Crc32(uint32 sum, HistogramBase::Sample value) {
+  // TODO(jar): Switch to false and watch stats.
+  const bool kUseRealCrc = true;
+
+  if (kUseRealCrc) {
+    union {
+      HistogramBase::Sample range;
+      unsigned char bytes[sizeof(HistogramBase::Sample)];
+    } converter;
+    converter.range = value;
+    for (size_t i = 0; i < sizeof(converter); ++i)
+      sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
+  } else {
+    // Use hash techniques provided in ReallyFastHash, except we don't care
+    // about "avalanching" (which would worsten the hash, and add collisions),
+    // and we don't care about edge cases since we have an even number of bytes.
+    union {
+      HistogramBase::Sample range;
+      uint16 ints[sizeof(HistogramBase::Sample) / 2];
+    } converter;
+    DCHECK_EQ(sizeof(HistogramBase::Sample), sizeof(converter));
+    converter.range = value;
+    sum += converter.ints[0];
+    sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
+    sum += sum >> 11;
+  }
+  return sum;
+}
+
+BucketRanges::BucketRanges(size_t num_ranges)
+    : ranges_(num_ranges, 0),
+      checksum_(0) {}
+
+BucketRanges::~BucketRanges() {}
+
+void BucketRanges::set_range(size_t i, HistogramBase::Sample value) {
+  DCHECK_LT(i, ranges_.size());
+  CHECK_GE(value, 0);
+  ranges_[i] = value;
+}
+
+uint32 BucketRanges::CalculateChecksum() const {
+  // Seed checksum.
+  uint32 checksum = static_cast<uint32>(ranges_.size());
+
+  for (size_t index = 0; index < ranges_.size(); ++index)
+    checksum = Crc32(checksum, ranges_[index]);
+  return checksum;
+}
+
+bool BucketRanges::HasValidChecksum() const {
+  return CalculateChecksum() == checksum_;
+}
+
+void BucketRanges::ResetChecksum() {
+  checksum_ = CalculateChecksum();
+}
+
+bool BucketRanges::Equals(const BucketRanges* other) const {
+  if (checksum_ != other->checksum_)
+    return false;
+  if (ranges_.size() != other->ranges_.size())
+    return false;
+  for (size_t index = 0; index < ranges_.size(); ++index) {
+    if (ranges_[index] != other->ranges_[index])
+      return false;
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h
new file mode 100644
index 0000000..fe1152f
--- /dev/null
+++ b/base/metrics/bucket_ranges.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// BucketRanges stores the vector of ranges that delimit what samples are
+// tallied in the corresponding buckets of a histogram. Histograms that have
+// same ranges for all their corresponding buckets should share the same
+// BucketRanges object.
+//
+// E.g. A 5 buckets LinearHistogram with 1 as minimal value and 4 as maximal
+// value will need a BucketRanges with 6 ranges:
+// 0, 1, 2, 3, 4, INT_MAX
+//
+// TODO(kaiwang): Currently we keep all negative values in 0~1 bucket. Consider
+// changing 0 to INT_MIN.
+
+#ifndef BASE_METRICS_BUCKET_RANGES_H_
+#define BASE_METRICS_BUCKET_RANGES_H_
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class BASE_EXPORT BucketRanges {
+ public:
+  typedef std::vector<HistogramBase::Sample> Ranges;
+
+  explicit BucketRanges(size_t num_ranges);
+  ~BucketRanges();
+
+  size_t size() const { return ranges_.size(); }
+  HistogramBase::Sample range(size_t i) const { return ranges_[i]; }
+  void set_range(size_t i, HistogramBase::Sample value);
+  uint32 checksum() const { return checksum_; }
+  void set_checksum(uint32 checksum) { checksum_ = checksum; }
+
+  // A bucket is defined by a consecutive pair of entries in |ranges|, so there
+  // is one fewer bucket than there are ranges.  For example, if |ranges| is
+  // [0, 1, 3, 7, INT_MAX], then the buckets in this histogram are
+  // [0, 1), [1, 3), [3, 7), and [7, INT_MAX).
+  size_t bucket_count() const { return ranges_.size() - 1; }
+
+  // Checksum methods to verify whether the ranges are corrupted (e.g. bad
+  // memory access).
+  uint32 CalculateChecksum() const;
+  bool HasValidChecksum() const;
+  void ResetChecksum();
+
+  // Return true iff |other| object has same ranges_ as |this| object's ranges_.
+  bool Equals(const BucketRanges* other) const;
+
+ private:
+  // A monotonically increasing list of values which determine which bucket to
+  // put a sample into.  For each index, show the smallest sample that can be
+  // added to the corresponding bucket.
+  Ranges ranges_;
+
+  // Checksum for the conntents of ranges_.  Used to detect random over-writes
+  // of our data, and to quickly see if some other BucketRanges instance is
+  // possibly Equal() to this instance.
+  // TODO(kaiwang): Consider change this to uint64. Because we see a lot of
+  // noise on UMA dashboard.
+  uint32 checksum_;
+
+  DISALLOW_COPY_AND_ASSIGN(BucketRanges);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Expose only for test.
+BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+
+}  // namespace base
+
+#endif  // BASE_METRICS_BUCKET_RANGES_H_
diff --git a/base/metrics/bucket_ranges_unittest.cc b/base/metrics/bucket_ranges_unittest.cc
new file mode 100644
index 0000000..fc0699c
--- /dev/null
+++ b/base/metrics/bucket_ranges_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/bucket_ranges.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(BucketRangesTest, NormalSetup) {
+  BucketRanges ranges(5);
+  ASSERT_EQ(5u, ranges.size());
+  ASSERT_EQ(4u, ranges.bucket_count());
+
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_EQ(0, ranges.range(i));
+  }
+  EXPECT_EQ(0u, ranges.checksum());
+
+  ranges.set_range(3, 100);
+  EXPECT_EQ(100, ranges.range(3));
+}
+
+TEST(BucketRangesTest, Equals) {
+  // Compare empty ranges.
+  BucketRanges ranges1(3);
+  BucketRanges ranges2(3);
+  BucketRanges ranges3(5);
+
+  EXPECT_TRUE(ranges1.Equals(&ranges2));
+  EXPECT_FALSE(ranges1.Equals(&ranges3));
+  EXPECT_FALSE(ranges2.Equals(&ranges3));
+
+  // Compare full filled ranges.
+  ranges1.set_range(0, 0);
+  ranges1.set_range(1, 1);
+  ranges1.set_range(2, 2);
+  ranges1.set_checksum(100);
+  ranges2.set_range(0, 0);
+  ranges2.set_range(1, 1);
+  ranges2.set_range(2, 2);
+  ranges2.set_checksum(100);
+
+  EXPECT_TRUE(ranges1.Equals(&ranges2));
+
+  // Checksum does not match.
+  ranges1.set_checksum(99);
+  EXPECT_FALSE(ranges1.Equals(&ranges2));
+  ranges1.set_checksum(100);
+
+  // Range does not match.
+  ranges1.set_range(1, 3);
+  EXPECT_FALSE(ranges1.Equals(&ranges2));
+}
+
+TEST(BucketRangesTest, Checksum) {
+  BucketRanges ranges(3);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+
+  ranges.ResetChecksum();
+  EXPECT_EQ(289217253u, ranges.checksum());
+
+  ranges.set_range(2, 3);
+  EXPECT_FALSE(ranges.HasValidChecksum());
+
+  ranges.ResetChecksum();
+  EXPECT_EQ(2843835776u, ranges.checksum());
+  EXPECT_TRUE(ranges.HasValidChecksum());
+}
+
+// Table was generated similarly to sample code for CRC-32 given on:
+// http://www.w3.org/TR/PNG/#D-CRCAppendix.
+TEST(BucketRangesTest, Crc32TableTest) {
+  for (int i = 0; i < 256; ++i) {
+    uint32 checksum = i;
+    for (int j = 0; j < 8; ++j) {
+      const uint32 kReversedPolynomial = 0xedb88320L;
+      if (checksum & 1)
+        checksum = kReversedPolynomial ^ (checksum >> 1);
+      else
+        checksum >>= 1;
+    }
+    EXPECT_EQ(kCrcTable[i], checksum);
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
new file mode 100644
index 0000000..639f6d3
--- /dev/null
+++ b/base/metrics/field_trial.cc
@@ -0,0 +1,593 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/field_trial.h"
+
+#include <algorithm>
+
+#include "base/build_time.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/sha1.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_byteorder.h"
+
+namespace base {
+
+namespace {
+
+// Created a time value based on |year|, |month| and |day_of_month| parameters.
+Time CreateTimeFromParams(int year, int month, int day_of_month) {
+  DCHECK_GT(year, 1970);
+  DCHECK_GT(month, 0);
+  DCHECK_LT(month, 13);
+  DCHECK_GT(day_of_month, 0);
+  DCHECK_LT(day_of_month, 32);
+
+  Time::Exploded exploded;
+  exploded.year = year;
+  exploded.month = month;
+  exploded.day_of_week = 0;  // Should be unused.
+  exploded.day_of_month = day_of_month;
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+
+  return Time::FromLocalExploded(exploded);
+}
+
+// Returns the boundary value for comparing against the FieldTrial's added
+// groups for a given |divisor| (total probability) and |entropy_value|.
+FieldTrial::Probability GetGroupBoundaryValue(
+    FieldTrial::Probability divisor,
+    double entropy_value) {
+  // Add a tiny epsilon value to get consistent results when converting floating
+  // points to int. Without it, boundary values have inconsistent results, e.g.:
+  //
+  //   static_cast<FieldTrial::Probability>(100 * 0.56) == 56
+  //   static_cast<FieldTrial::Probability>(100 * 0.57) == 56
+  //   static_cast<FieldTrial::Probability>(100 * 0.58) == 57
+  //   static_cast<FieldTrial::Probability>(100 * 0.59) == 59
+  const double kEpsilon = 1e-8;
+  const FieldTrial::Probability result =
+      static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon);
+  // Ensure that adding the epsilon still results in a value < |divisor|.
+  return std::min(result, divisor - 1);
+}
+
+}  // namespace
+
+// statics
+const int FieldTrial::kNotFinalized = -1;
+const int FieldTrial::kDefaultGroupNumber = 0;
+bool FieldTrial::enable_benchmarking_ = false;
+
+const char FieldTrialList::kPersistentStringSeparator('/');
+const char FieldTrialList::kActivationMarker('*');
+int FieldTrialList::kNoExpirationYear = 0;
+
+//------------------------------------------------------------------------------
+// FieldTrial methods and members.
+
+FieldTrial::EntropyProvider::~EntropyProvider() {
+}
+
+void FieldTrial::Disable() {
+  DCHECK(!group_reported_);
+  enable_field_trial_ = false;
+
+  // In case we are disabled after initialization, we need to switch
+  // the trial to the default group.
+  if (group_ != kNotFinalized) {
+    // Only reset when not already the default group, because in case we were
+    // forced to the default group, the group number may not be
+    // kDefaultGroupNumber, so we should keep it as is.
+    if (group_name_ != default_group_name_)
+      SetGroupChoice(default_group_name_, kDefaultGroupNumber);
+  }
+}
+
+int FieldTrial::AppendGroup(const std::string& name,
+                            Probability group_probability) {
+  // When the group choice was previously forced, we only need to return the
+  // the id of the chosen group, and anything can be returned for the others.
+  if (forced_) {
+    DCHECK(!group_name_.empty());
+    if (name == group_name_) {
+      // Note that while |group_| may be equal to |kDefaultGroupNumber| on the
+      // forced trial, it will not have the same value as the default group
+      // number returned from the non-forced |FactoryGetFieldTrial()| call,
+      // which takes care to ensure that this does not happen.
+      return group_;
+    }
+    DCHECK_NE(next_group_number_, group_);
+    // We still return different numbers each time, in case some caller need
+    // them to be different.
+    return next_group_number_++;
+  }
+
+  DCHECK_LE(group_probability, divisor_);
+  DCHECK_GE(group_probability, 0);
+
+  if (enable_benchmarking_ || !enable_field_trial_)
+    group_probability = 0;
+
+  accumulated_group_probability_ += group_probability;
+
+  DCHECK_LE(accumulated_group_probability_, divisor_);
+  if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
+    // This is the group that crossed the random line, so we do the assignment.
+    SetGroupChoice(name, next_group_number_);
+  }
+  return next_group_number_++;
+}
+
+int FieldTrial::group() {
+  FinalizeGroupChoice();
+  if (trial_registered_)
+    FieldTrialList::NotifyFieldTrialGroupSelection(this);
+  return group_;
+}
+
+const std::string& FieldTrial::group_name() {
+  // Call |group()| to ensure group gets assigned and observers are notified.
+  group();
+  DCHECK(!group_name_.empty());
+  return group_name_;
+}
+
+void FieldTrial::SetForced() {
+  // We might have been forced before (e.g., by CreateFieldTrial) and it's
+  // first come first served, e.g., command line switch has precedence.
+  if (forced_)
+    return;
+
+  // And we must finalize the group choice before we mark ourselves as forced.
+  FinalizeGroupChoice();
+  forced_ = true;
+}
+
+// static
+void FieldTrial::EnableBenchmarking() {
+  DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
+  enable_benchmarking_ = true;
+}
+
+// static
+FieldTrial* FieldTrial::CreateSimulatedFieldTrial(
+    const std::string& trial_name,
+    Probability total_probability,
+    const std::string& default_group_name,
+    double entropy_value) {
+  return new FieldTrial(trial_name, total_probability, default_group_name,
+                        entropy_value);
+}
+
+FieldTrial::FieldTrial(const std::string& trial_name,
+                       const Probability total_probability,
+                       const std::string& default_group_name,
+                       double entropy_value)
+    : trial_name_(trial_name),
+      divisor_(total_probability),
+      default_group_name_(default_group_name),
+      random_(GetGroupBoundaryValue(total_probability, entropy_value)),
+      accumulated_group_probability_(0),
+      next_group_number_(kDefaultGroupNumber + 1),
+      group_(kNotFinalized),
+      enable_field_trial_(true),
+      forced_(false),
+      group_reported_(false),
+      trial_registered_(false) {
+  DCHECK_GT(total_probability, 0);
+  DCHECK(!trial_name_.empty());
+  DCHECK(!default_group_name_.empty());
+}
+
+FieldTrial::~FieldTrial() {}
+
+void FieldTrial::SetTrialRegistered() {
+  DCHECK_EQ(kNotFinalized, group_);
+  DCHECK(!trial_registered_);
+  trial_registered_ = true;
+}
+
+void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
+  group_ = number;
+  if (group_name.empty())
+    StringAppendF(&group_name_, "%d", group_);
+  else
+    group_name_ = group_name;
+  DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_;
+}
+
+void FieldTrial::FinalizeGroupChoice() {
+  if (group_ != kNotFinalized)
+    return;
+  accumulated_group_probability_ = divisor_;
+  // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not
+  // finalized.
+  DCHECK(!forced_);
+  SetGroupChoice(default_group_name_, kDefaultGroupNumber);
+}
+
+bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
+  if (!group_reported_ || !enable_field_trial_)
+    return false;
+  DCHECK_NE(group_, kNotFinalized);
+  active_group->trial_name = trial_name_;
+  active_group->group_name = group_name_;
+  return true;
+}
+
+bool FieldTrial::GetState(FieldTrialState* field_trial_state) const {
+  if (!enable_field_trial_)
+    return false;
+  field_trial_state->trial_name = trial_name_;
+  // If the group name is empty (hasn't been finalized yet), use the default
+  // group name instead.
+  if (!group_name_.empty())
+    field_trial_state->group_name = group_name_;
+  else
+    field_trial_state->group_name = default_group_name_;
+  field_trial_state->activated = group_reported_;
+  return true;
+}
+
+//------------------------------------------------------------------------------
+// FieldTrialList methods and members.
+
+// static
+FieldTrialList* FieldTrialList::global_ = NULL;
+
+// static
+bool FieldTrialList::used_without_global_ = false;
+
+FieldTrialList::Observer::~Observer() {
+}
+
+FieldTrialList::FieldTrialList(
+    const FieldTrial::EntropyProvider* entropy_provider)
+    : entropy_provider_(entropy_provider),
+      observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>(
+          ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) {
+  DCHECK(!global_);
+  DCHECK(!used_without_global_);
+  global_ = this;
+
+  Time two_years_from_build_time = GetBuildTime() + TimeDelta::FromDays(730);
+  Time::Exploded exploded;
+  two_years_from_build_time.LocalExplode(&exploded);
+  kNoExpirationYear = exploded.year;
+}
+
+FieldTrialList::~FieldTrialList() {
+  AutoLock auto_lock(lock_);
+  while (!registered_.empty()) {
+    RegistrationMap::iterator it = registered_.begin();
+    it->second->Release();
+    registered_.erase(it->first);
+  }
+  DCHECK_EQ(this, global_);
+  global_ = NULL;
+}
+
+// static
+FieldTrial* FieldTrialList::FactoryGetFieldTrial(
+    const std::string& trial_name,
+    FieldTrial::Probability total_probability,
+    const std::string& default_group_name,
+    const int year,
+    const int month,
+    const int day_of_month,
+    FieldTrial::RandomizationType randomization_type,
+    int* default_group_number) {
+  return FactoryGetFieldTrialWithRandomizationSeed(
+      trial_name, total_probability, default_group_name,
+      year, month, day_of_month, randomization_type, 0, default_group_number);
+}
+
+// static
+FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
+    const std::string& trial_name,
+    FieldTrial::Probability total_probability,
+    const std::string& default_group_name,
+    const int year,
+    const int month,
+    const int day_of_month,
+    FieldTrial::RandomizationType randomization_type,
+    uint32 randomization_seed,
+    int* default_group_number) {
+  if (default_group_number)
+    *default_group_number = FieldTrial::kDefaultGroupNumber;
+  // Check if the field trial has already been created in some other way.
+  FieldTrial* existing_trial = Find(trial_name);
+  if (existing_trial) {
+    CHECK(existing_trial->forced_);
+    // If the default group name differs between the existing forced trial
+    // and this trial, then use a different value for the default group number.
+    if (default_group_number &&
+        default_group_name != existing_trial->default_group_name()) {
+      // If the new default group number corresponds to the group that was
+      // chosen for the forced trial (which has been finalized when it was
+      // forced), then set the default group number to that.
+      if (default_group_name == existing_trial->group_name_internal()) {
+        *default_group_number = existing_trial->group_;
+      } else {
+        // Otherwise, use |kNonConflictingGroupNumber| (-2) for the default
+        // group number, so that it does not conflict with the |AppendGroup()|
+        // result for the chosen group.
+        const int kNonConflictingGroupNumber = -2;
+        COMPILE_ASSERT(
+            kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
+            conflicting_default_group_number);
+        COMPILE_ASSERT(
+            kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
+            conflicting_default_group_number);
+        *default_group_number = kNonConflictingGroupNumber;
+      }
+    }
+    return existing_trial;
+  }
+
+  double entropy_value;
+  if (randomization_type == FieldTrial::ONE_TIME_RANDOMIZED) {
+    const FieldTrial::EntropyProvider* entropy_provider =
+        GetEntropyProviderForOneTimeRandomization();
+    CHECK(entropy_provider);
+    entropy_value = entropy_provider->GetEntropyForTrial(trial_name,
+                                                         randomization_seed);
+  } else {
+    DCHECK_EQ(FieldTrial::SESSION_RANDOMIZED, randomization_type);
+    DCHECK_EQ(0U, randomization_seed);
+    entropy_value = RandDouble();
+  }
+
+  FieldTrial* field_trial = new FieldTrial(trial_name, total_probability,
+                                           default_group_name, entropy_value);
+  if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month))
+    field_trial->Disable();
+  FieldTrialList::Register(field_trial);
+  return field_trial;
+}
+
+// static
+FieldTrial* FieldTrialList::Find(const std::string& name) {
+  if (!global_)
+    return NULL;
+  AutoLock auto_lock(global_->lock_);
+  return global_->PreLockedFind(name);
+}
+
+// static
+int FieldTrialList::FindValue(const std::string& name) {
+  FieldTrial* field_trial = Find(name);
+  if (field_trial)
+    return field_trial->group();
+  return FieldTrial::kNotFinalized;
+}
+
+// static
+std::string FieldTrialList::FindFullName(const std::string& name) {
+  FieldTrial* field_trial = Find(name);
+  if (field_trial)
+    return field_trial->group_name();
+  return std::string();
+}
+
+// static
+bool FieldTrialList::TrialExists(const std::string& name) {
+  return Find(name) != NULL;
+}
+
+// static
+void FieldTrialList::StatesToString(std::string* output) {
+  FieldTrial::ActiveGroups active_groups;
+  GetActiveFieldTrialGroups(&active_groups);
+  for (FieldTrial::ActiveGroups::const_iterator it = active_groups.begin();
+       it != active_groups.end(); ++it) {
+    DCHECK_EQ(std::string::npos,
+              it->trial_name.find(kPersistentStringSeparator));
+    DCHECK_EQ(std::string::npos,
+              it->group_name.find(kPersistentStringSeparator));
+    output->append(it->trial_name);
+    output->append(1, kPersistentStringSeparator);
+    output->append(it->group_name);
+    output->append(1, kPersistentStringSeparator);
+  }
+}
+
+// static
+void FieldTrialList::AllStatesToString(std::string* output) {
+  if (!global_)
+    return;
+  AutoLock auto_lock(global_->lock_);
+
+  for (const auto& registered : global_->registered_) {
+    FieldTrial::FieldTrialState trial;
+    if (!registered.second->GetState(&trial))
+      continue;
+    DCHECK_EQ(std::string::npos,
+              trial.trial_name.find(kPersistentStringSeparator));
+    DCHECK_EQ(std::string::npos,
+              trial.group_name.find(kPersistentStringSeparator));
+    if (trial.activated)
+      output->append(1, kActivationMarker);
+    output->append(trial.trial_name);
+    output->append(1, kPersistentStringSeparator);
+    output->append(trial.group_name);
+    output->append(1, kPersistentStringSeparator);
+  }
+}
+
+// static
+void FieldTrialList::GetActiveFieldTrialGroups(
+    FieldTrial::ActiveGroups* active_groups) {
+  DCHECK(active_groups->empty());
+  if (!global_)
+    return;
+  AutoLock auto_lock(global_->lock_);
+
+  for (RegistrationMap::iterator it = global_->registered_.begin();
+       it != global_->registered_.end(); ++it) {
+    FieldTrial::ActiveGroup active_group;
+    if (it->second->GetActiveGroup(&active_group))
+      active_groups->push_back(active_group);
+  }
+}
+
+// static
+bool FieldTrialList::CreateTrialsFromString(
+    const std::string& trials_string,
+    FieldTrialActivationMode mode,
+    const std::set<std::string>& ignored_trial_names) {
+  DCHECK(global_);
+  if (trials_string.empty() || !global_)
+    return true;
+
+  size_t next_item = 0;
+  while (next_item < trials_string.length()) {
+    size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
+    if (name_end == trials_string.npos || next_item == name_end)
+      return false;
+    size_t group_name_end = trials_string.find(kPersistentStringSeparator,
+                                               name_end + 1);
+    if (name_end + 1 == group_name_end)
+      return false;
+    if (group_name_end == trials_string.npos)
+      group_name_end = trials_string.length();
+
+    // Verify if the trial should be activated or not.
+    std::string name;
+    bool force_activation = false;
+    if (trials_string[next_item] == kActivationMarker) {
+      // Name cannot be only the indicator.
+      if (name_end - next_item == 1)
+        return false;
+      next_item++;
+      force_activation = true;
+    }
+    name.append(trials_string, next_item, name_end - next_item);
+    std::string group_name(trials_string, name_end + 1,
+                           group_name_end - name_end - 1);
+    next_item = group_name_end + 1;
+
+    if (ignored_trial_names.find(name) != ignored_trial_names.end())
+      continue;
+
+    FieldTrial* trial = CreateFieldTrial(name, group_name);
+    if (!trial)
+      return false;
+    if (mode == ACTIVATE_TRIALS || force_activation) {
+      // Call |group()| to mark the trial as "used" and notify observers, if
+      // any. This is useful to ensure that field trials created in child
+      // processes are properly reported in crash reports.
+      trial->group();
+    }
+  }
+  return true;
+}
+
+// static
+FieldTrial* FieldTrialList::CreateFieldTrial(
+    const std::string& name,
+    const std::string& group_name) {
+  DCHECK(global_);
+  DCHECK_GE(name.size(), 0u);
+  DCHECK_GE(group_name.size(), 0u);
+  if (name.empty() || group_name.empty() || !global_)
+    return NULL;
+
+  FieldTrial* field_trial = FieldTrialList::Find(name);
+  if (field_trial) {
+    // In single process mode, or when we force them from the command line,
+    // we may have already created the field trial.
+    if (field_trial->group_name_internal() != group_name)
+      return NULL;
+    return field_trial;
+  }
+  const int kTotalProbability = 100;
+  field_trial = new FieldTrial(name, kTotalProbability, group_name, 0);
+  FieldTrialList::Register(field_trial);
+  // Force the trial, which will also finalize the group choice.
+  field_trial->SetForced();
+  return field_trial;
+}
+
+// static
+void FieldTrialList::AddObserver(Observer* observer) {
+  if (!global_)
+    return;
+  global_->observer_list_->AddObserver(observer);
+}
+
+// static
+void FieldTrialList::RemoveObserver(Observer* observer) {
+  if (!global_)
+    return;
+  global_->observer_list_->RemoveObserver(observer);
+}
+
+// static
+void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
+  if (!global_)
+    return;
+
+  {
+    AutoLock auto_lock(global_->lock_);
+    if (field_trial->group_reported_)
+      return;
+    field_trial->group_reported_ = true;
+  }
+
+  if (!field_trial->enable_field_trial_)
+    return;
+
+  global_->observer_list_->Notify(
+      FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
+      field_trial->trial_name(), field_trial->group_name_internal());
+}
+
+// static
+size_t FieldTrialList::GetFieldTrialCount() {
+  if (!global_)
+    return 0;
+  AutoLock auto_lock(global_->lock_);
+  return global_->registered_.size();
+}
+
+// static
+const FieldTrial::EntropyProvider*
+    FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
+  if (!global_) {
+    used_without_global_ = true;
+    return NULL;
+  }
+
+  return global_->entropy_provider_.get();
+}
+
+FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
+  RegistrationMap::iterator it = registered_.find(name);
+  if (registered_.end() == it)
+    return NULL;
+  return it->second;
+}
+
+// static
+void FieldTrialList::Register(FieldTrial* trial) {
+  if (!global_) {
+    used_without_global_ = true;
+    return;
+  }
+  AutoLock auto_lock(global_->lock_);
+  DCHECK(!global_->PreLockedFind(trial->trial_name()));
+  trial->AddRef();
+  trial->SetTrialRegistered();
+  global_->registered_[trial->trial_name()] = trial;
+}
+
+}  // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
new file mode 100644
index 0000000..26257ab
--- /dev/null
+++ b/base/metrics/field_trial.h
@@ -0,0 +1,520 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// FieldTrial is a class for handling details of statistical experiments
+// performed by actual users in the field (i.e., in a shipped or beta product).
+// All code is called exclusively on the UI thread currently.
+//
+// The simplest example is an experiment to see whether one of two options
+// produces "better" results across our user population.  In that scenario, UMA
+// data is uploaded to aggregate the test results, and this FieldTrial class
+// manages the state of each such experiment (state == which option was
+// pseudo-randomly selected).
+//
+// States are typically generated randomly, either based on a one time
+// randomization (which will yield the same results, in terms of selecting
+// the client for a field trial or not, for every run of the program on a
+// given machine), or by a session randomization (generated each time the
+// application starts up, but held constant during the duration of the
+// process).
+
+//------------------------------------------------------------------------------
+// Example:  Suppose we have an experiment involving memory, such as determining
+// the impact of some pruning algorithm.
+// We assume that we already have a histogram of memory usage, such as:
+
+//   UMA_HISTOGRAM_COUNTS("Memory.RendererTotal", count);
+
+// Somewhere in main thread initialization code, we'd probably define an
+// instance of a FieldTrial, with code such as:
+
+// // FieldTrials are reference counted, and persist automagically until
+// // process teardown, courtesy of their automatic registration in
+// // FieldTrialList.
+// // Note: This field trial will run in Chrome instances compiled through
+// //       8 July, 2015, and after that all instances will be in "StandardMem".
+// scoped_refptr<base::FieldTrial> trial(
+//     base::FieldTrialList::FactoryGetFieldTrial(
+//         "MemoryExperiment", 1000, "StandardMem", 2015, 7, 8,
+//         base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
+//
+// const int high_mem_group =
+//     trial->AppendGroup("HighMem", 20);  // 2% in HighMem group.
+// const int low_mem_group =
+//     trial->AppendGroup("LowMem", 20);   // 2% in LowMem group.
+// // Take action depending of which group we randomly land in.
+// if (trial->group() == high_mem_group)
+//   SetPruningAlgorithm(kType1);  // Sample setting of browser state.
+// else if (trial->group() == low_mem_group)
+//   SetPruningAlgorithm(kType2);  // Sample alternate setting.
+
+//------------------------------------------------------------------------------
+
+#ifndef BASE_METRICS_FIELD_TRIAL_H_
+#define BASE_METRICS_FIELD_TRIAL_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class FieldTrialList;
+
+class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
+ public:
+  typedef int Probability;  // Probability type for being selected in a trial.
+
+  // Specifies the persistence of the field trial group choice.
+  enum RandomizationType {
+    // One time randomized trials will persist the group choice between
+    // restarts, which is recommended for most trials, especially those that
+    // change user visible behavior.
+    ONE_TIME_RANDOMIZED,
+    // Session randomized trials will roll the dice to select a group on every
+    // process restart.
+    SESSION_RANDOMIZED,
+  };
+
+  // EntropyProvider is an interface for providing entropy for one-time
+  // randomized (persistent) field trials.
+  class BASE_EXPORT EntropyProvider {
+   public:
+    virtual ~EntropyProvider();
+
+    // Returns a double in the range of [0, 1) to be used for the dice roll for
+    // the specified field trial. If |randomization_seed| is not 0, it will be
+    // used in preference to |trial_name| for generating the entropy by entropy
+    // providers that support it. A given instance should always return the same
+    // value given the same input |trial_name| and |randomization_seed| values.
+    virtual double GetEntropyForTrial(const std::string& trial_name,
+                                      uint32 randomization_seed) const = 0;
+  };
+
+  // A pair representing a Field Trial and its selected group.
+  struct ActiveGroup {
+    std::string trial_name;
+    std::string group_name;
+  };
+
+  // A triplet representing a FieldTrial, its selected group and whether it's
+  // active.
+  struct FieldTrialState {
+    std::string trial_name;
+    std::string group_name;
+    bool activated;
+  };
+
+  typedef std::vector<ActiveGroup> ActiveGroups;
+
+  // A return value to indicate that a given instance has not yet had a group
+  // assignment (and hence is not yet participating in the trial).
+  static const int kNotFinalized;
+
+  // Disables this trial, meaning it always determines the default group
+  // has been selected. May be called immediately after construction, or
+  // at any time after initialization (should not be interleaved with
+  // AppendGroup calls). Once disabled, there is no way to re-enable a
+  // trial.
+  // TODO(mad): http://code.google.com/p/chromium/issues/detail?id=121446
+  // This doesn't properly reset to Default when a group was forced.
+  void Disable();
+
+  // Establish the name and probability of the next group in this trial.
+  // Sometimes, based on construction randomization, this call may cause the
+  // provided group to be *THE* group selected for use in this instance.
+  // The return value is the group number of the new group.
+  int AppendGroup(const std::string& name, Probability group_probability);
+
+  // Return the name of the FieldTrial (excluding the group name).
+  const std::string& trial_name() const { return trial_name_; }
+
+  // Return the randomly selected group number that was assigned, and notify
+  // any/all observers that this finalized group number has presumably been used
+  // (queried), and will never change. Note that this will force an instance to
+  // participate, and make it illegal to attempt to probabilistically add any
+  // other groups to the trial.
+  int group();
+
+  // If the group's name is empty, a string version containing the group number
+  // is used as the group name. This causes a winner to be chosen if none was.
+  const std::string& group_name();
+
+  // Set the field trial as forced, meaning that it was setup earlier than
+  // the hard coded registration of the field trial to override it.
+  // This allows the code that was hard coded to register the field trial to
+  // still succeed even though the field trial has already been registered.
+  // This must be called after appending all the groups, since we will make
+  // the group choice here. Note that this is a NOOP for already forced trials.
+  // And, as the rest of the FieldTrial code, this is not thread safe and must
+  // be done from the UI thread.
+  void SetForced();
+
+  // Enable benchmarking sets field trials to a common setting.
+  static void EnableBenchmarking();
+
+  // Creates a FieldTrial object with the specified parameters, to be used for
+  // simulation of group assignment without actually affecting global field
+  // trial state in the running process. Group assignment will be done based on
+  // |entropy_value|, which must have a range of [0, 1).
+  //
+  // Note: Using this function will not register the field trial globally in the
+  // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
+  //
+  // The ownership of the returned FieldTrial is transfered to the caller which
+  // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
+  static FieldTrial* CreateSimulatedFieldTrial(
+      const std::string& trial_name,
+      Probability total_probability,
+      const std::string& default_group_name,
+      double entropy_value);
+
+ private:
+  // Allow tests to access our innards for testing purposes.
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability);
+
+  friend class base::FieldTrialList;
+
+  friend class RefCounted<FieldTrial>;
+
+  // This is the group number of the 'default' group when a choice wasn't forced
+  // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that
+  // consumers don't use it by mistake in cases where the group was forced.
+  static const int kDefaultGroupNumber;
+
+  // Creates a field trial with the specified parameters. Group assignment will
+  // be done based on |entropy_value|, which must have a range of [0, 1).
+  FieldTrial(const std::string& trial_name,
+             Probability total_probability,
+             const std::string& default_group_name,
+             double entropy_value);
+  virtual ~FieldTrial();
+
+  // Return the default group name of the FieldTrial.
+  std::string default_group_name() const { return default_group_name_; }
+
+  // Marks this trial as having been registered with the FieldTrialList. Must be
+  // called no more than once and before any |group()| calls have occurred.
+  void SetTrialRegistered();
+
+  // Sets the chosen group name and number.
+  void SetGroupChoice(const std::string& group_name, int number);
+
+  // Ensures that a group is chosen, if it hasn't yet been. The field trial
+  // might yet be disabled, so this call will *not* notify observers of the
+  // status.
+  void FinalizeGroupChoice();
+
+  // Returns the trial name and selected group name for this field trial via
+  // the output parameter |active_group|, but only if the group has already
+  // been chosen and has been externally observed via |group()| and the trial
+  // has not been disabled. In that case, true is returned and |active_group|
+  // is filled in; otherwise, the result is false and |active_group| is left
+  // untouched.
+  bool GetActiveGroup(ActiveGroup* active_group) const;
+
+  // Returns the trial name and selected group name for this field trial via
+  // the output parameter |field_trial_state|, but only if the trial has not
+  // been disabled. In that case, true is returned and |field_trial_state| is
+  // filled in; otherwise, the result is false and |field_trial_state| is left
+  // untouched.
+  bool GetState(FieldTrialState* field_trial_state) const;
+
+  // Returns the group_name. A winner need not have been chosen.
+  std::string group_name_internal() const { return group_name_; }
+
+  // The name of the field trial, as can be found via the FieldTrialList.
+  const std::string trial_name_;
+
+  // The maximum sum of all probabilities supplied, which corresponds to 100%.
+  // This is the scaling factor used to adjust supplied probabilities.
+  const Probability divisor_;
+
+  // The name of the default group.
+  const std::string default_group_name_;
+
+  // The randomly selected probability that is used to select a group (or have
+  // the instance not participate).  It is the product of divisor_ and a random
+  // number between [0, 1).
+  Probability random_;
+
+  // Sum of the probabilities of all appended groups.
+  Probability accumulated_group_probability_;
+
+  // The number that will be returned by the next AppendGroup() call.
+  int next_group_number_;
+
+  // The pseudo-randomly assigned group number.
+  // This is kNotFinalized if no group has been assigned.
+  int group_;
+
+  // A textual name for the randomly selected group. Valid after |group()|
+  // has been called.
+  std::string group_name_;
+
+  // When enable_field_trial_ is false, field trial reverts to the 'default'
+  // group.
+  bool enable_field_trial_;
+
+  // When forced_ is true, we return the chosen group from AppendGroup when
+  // appropriate.
+  bool forced_;
+
+  // Specifies whether the group choice has been reported to observers.
+  bool group_reported_;
+
+  // Whether this trial is registered with the global FieldTrialList and thus
+  // should notify it when its group is queried.
+  bool trial_registered_;
+
+  // When benchmarking is enabled, field trials all revert to the 'default'
+  // group.
+  static bool enable_benchmarking_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrial);
+};
+
+//------------------------------------------------------------------------------
+// Class with a list of all active field trials.  A trial is active if it has
+// been registered, which includes evaluating its state based on its probaility.
+// Only one instance of this class exists.
+class BASE_EXPORT FieldTrialList {
+ public:
+  // Specifies whether field trials should be activated (marked as "used"), when
+  // created using |CreateTrialsFromString()|. Has no effect on trials that are
+  // prefixed with |kActivationMarker|, which will always be activated."
+  enum FieldTrialActivationMode {
+    DONT_ACTIVATE_TRIALS,
+    ACTIVATE_TRIALS,
+  };
+
+  // Define a separator character to use when creating a persistent form of an
+  // instance.  This is intended for use as a command line argument, passed to a
+  // second process to mimic our state (i.e., provide the same group name).
+  static const char kPersistentStringSeparator;  // Currently a slash.
+
+  // Define a marker character to be used as a prefix to a trial name on the
+  // command line which forces its activation.
+  static const char kActivationMarker;  // Currently an asterisk.
+
+  // Year that is guaranteed to not be expired when instantiating a field trial
+  // via |FactoryGetFieldTrial()|.  Set to two years from the build date.
+  static int kNoExpirationYear;
+
+  // Observer is notified when a FieldTrial's group is selected.
+  class BASE_EXPORT Observer {
+   public:
+    // Notify observers when FieldTrials's group is selected.
+    virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
+                                            const std::string& group_name) = 0;
+
+   protected:
+    virtual ~Observer();
+  };
+
+  // This singleton holds the global list of registered FieldTrials.
+  //
+  // To support one-time randomized field trials, specify a non-NULL
+  // |entropy_provider| which should be a source of uniformly distributed
+  // entropy values. Takes ownership of |entropy_provider|. If one time
+  // randomization is not desired, pass in NULL for |entropy_provider|.
+  explicit FieldTrialList(const FieldTrial::EntropyProvider* entropy_provider);
+
+  // Destructor Release()'s references to all registered FieldTrial instances.
+  ~FieldTrialList();
+
+  // Get a FieldTrial instance from the factory.
+  //
+  // |name| is used to register the instance with the FieldTrialList class,
+  // and can be used to find the trial (only one trial can be present for each
+  // name). |default_group_name| is the name of the default group which will
+  // be chosen if none of the subsequent appended groups get to be chosen.
+  // |default_group_number| can receive the group number of the default group as
+  // AppendGroup returns the number of the subsequence groups. |trial_name| and
+  // |default_group_name| may not be empty but |default_group_number| can be
+  // NULL if the value is not needed.
+  //
+  // Group probabilities that are later supplied must sum to less than or equal
+  // to the |total_probability|. Arguments |year|, |month| and |day_of_month|
+  // specify the expiration time. If the build time is after the expiration time
+  // then the field trial reverts to the 'default' group.
+  //
+  // Use this static method to get a startup-randomized FieldTrial or a
+  // previously created forced FieldTrial.
+  static FieldTrial* FactoryGetFieldTrial(
+      const std::string& trial_name,
+      FieldTrial::Probability total_probability,
+      const std::string& default_group_name,
+      const int year,
+      const int month,
+      const int day_of_month,
+      FieldTrial::RandomizationType randomization_type,
+      int* default_group_number);
+
+  // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be
+  // used on one-time randomized field trials (instead of a hash of the trial
+  // name, which is used otherwise or if |randomization_seed| has value 0). The
+  // |randomization_seed| value (other than 0) should never be the same for two
+  // trials, else this would result in correlated group assignments.
+  // Note: Using a custom randomization seed is only supported by the
+  // PermutedEntropyProvider (which is used when UMA is not enabled).
+  static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
+      const std::string& trial_name,
+      FieldTrial::Probability total_probability,
+      const std::string& default_group_name,
+      const int year,
+      const int month,
+      const int day_of_month,
+      FieldTrial::RandomizationType randomization_type,
+      uint32 randomization_seed,
+      int* default_group_number);
+
+  // The Find() method can be used to test to see if a named Trial was already
+  // registered, or to retrieve a pointer to it from the global map.
+  static FieldTrial* Find(const std::string& name);
+
+  // Returns the group number chosen for the named trial, or
+  // FieldTrial::kNotFinalized if the trial does not exist.
+  static int FindValue(const std::string& name);
+
+  // Returns the group name chosen for the named trial, or the
+  // empty string if the trial does not exist.
+  static std::string FindFullName(const std::string& name);
+
+  // Returns true if the named trial has been registered.
+  static bool TrialExists(const std::string& name);
+
+  // Creates a persistent representation of active FieldTrial instances for
+  // resurrection in another process. This allows randomization to be done in
+  // one process, and secondary processes can be synchronized on the result.
+  // The resulting string contains the name and group name pairs of all
+  // registered FieldTrials for which the group has been chosen and externally
+  // observed (via |group()|) and which have not been disabled, with "/" used
+  // to separate all names and to terminate the string. This string is parsed
+  // by |CreateTrialsFromString()|.
+  static void StatesToString(std::string* output);
+
+  // Creates a persistent representation of all FieldTrial instances for
+  // resurrection in another process. This allows randomization to be done in
+  // one process, and secondary processes can be synchronized on the result.
+  // The resulting string contains the name and group name pairs of all
+  // registered FieldTrials which have not been disabled, with "/" used
+  // to separate all names and to terminate the string. All activated trials
+  // have their name prefixed with "*". This string is parsed by
+  // |CreateTrialsFromString()|.
+  static void AllStatesToString(std::string* output);
+
+  // Fills in the supplied vector |active_groups| (which must be empty when
+  // called) with a snapshot of all registered FieldTrials for which the group
+  // has been chosen and externally observed (via |group()|) and which have
+  // not been disabled.
+  static void GetActiveFieldTrialGroups(
+      FieldTrial::ActiveGroups* active_groups);
+
+  // Use a state string (re: StatesToString()) to augment the current list of
+  // field trials to include the supplied trials, and using a 100% probability
+  // for each trial, force them to have the same group string. This is commonly
+  // used in a non-browser process, to carry randomly selected state in a
+  // browser process into this non-browser process, but could also be invoked
+  // through a command line argument to the browser process. The created field
+  // trials are all marked as "used" for the purposes of active trial reporting
+  // if |mode| is ACTIVATE_TRIALS, otherwise each trial will be marked as "used"
+  // if it is prefixed with |kActivationMarker|. Trial names in
+  // |ignored_trial_names| are ignored when parsing |prior_trials|.
+  static bool CreateTrialsFromString(
+      const std::string& prior_trials,
+      FieldTrialActivationMode mode,
+      const std::set<std::string>& ignored_trial_names);
+
+  // Create a FieldTrial with the given |name| and using 100% probability for
+  // the FieldTrial, force FieldTrial to have the same group string as
+  // |group_name|. This is commonly used in a non-browser process, to carry
+  // randomly selected state in a browser process into this non-browser process.
+  // It returns NULL if there is a FieldTrial that is already registered with
+  // the same |name| but has different finalized group string (|group_name|).
+  static FieldTrial* CreateFieldTrial(const std::string& name,
+                                      const std::string& group_name);
+
+  // Add an observer to be notified when a field trial is irrevocably committed
+  // to being part of some specific field_group (and hence the group_name is
+  // also finalized for that field_trial).
+  static void AddObserver(Observer* observer);
+
+  // Remove an observer.
+  static void RemoveObserver(Observer* observer);
+
+  // Notify all observers that a group has been finalized for |field_trial|.
+  static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
+
+  // Return the number of active field trials.
+  static size_t GetFieldTrialCount();
+
+ private:
+  // A map from FieldTrial names to the actual instances.
+  typedef std::map<std::string, FieldTrial*> RegistrationMap;
+
+  // If one-time randomization is enabled, returns a weak pointer to the
+  // corresponding EntropyProvider. Otherwise, returns NULL.
+  static const FieldTrial::EntropyProvider*
+      GetEntropyProviderForOneTimeRandomization();
+
+  // Helper function should be called only while holding lock_.
+  FieldTrial* PreLockedFind(const std::string& name);
+
+  // Register() stores a pointer to the given trial in a global map.
+  // This method also AddRef's the indicated trial.
+  // This should always be called after creating a new FieldTrial instance.
+  static void Register(FieldTrial* trial);
+
+  static FieldTrialList* global_;  // The singleton of this class.
+
+  // This will tell us if there is an attempt to register a field
+  // trial or check if one-time randomization is enabled without
+  // creating the FieldTrialList. This is not an error, unless a
+  // FieldTrialList is created after that.
+  static bool used_without_global_;
+
+  // Lock for access to registered_.
+  base::Lock lock_;
+  RegistrationMap registered_;
+
+  // Entropy provider to be used for one-time randomized field trials. If NULL,
+  // one-time randomization is not supported.
+  scoped_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
+
+  // List of observers to be notified when a group is selected for a FieldTrial.
+  scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_FIELD_TRIAL_H_
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
new file mode 100644
index 0000000..f1a1042
--- /dev/null
+++ b/base/metrics/field_trial_unittest.cc
@@ -0,0 +1,1133 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/field_trial.h"
+
+#include "base/build_time.h"
+#include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Default group name used by several tests.
+const char kDefaultGroupName[] = "DefaultGroup";
+
+// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date.
+scoped_refptr<base::FieldTrial> CreateFieldTrial(
+    const std::string& trial_name,
+    int total_probability,
+    const std::string& default_group_name,
+    int* default_group_number) {
+  return FieldTrialList::FactoryGetFieldTrial(
+      trial_name, total_probability, default_group_name,
+      base::FieldTrialList::kNoExpirationYear, 1, 1,
+      base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
+}
+
+int OneYearBeforeBuildTime() {
+  Time one_year_before_build_time = GetBuildTime() - TimeDelta::FromDays(365);
+  Time::Exploded exploded;
+  one_year_before_build_time.LocalExplode(&exploded);
+  return exploded.year;
+}
+
+// FieldTrialList::Observer implementation for testing.
+class TestFieldTrialObserver : public FieldTrialList::Observer {
+ public:
+  TestFieldTrialObserver() {
+    FieldTrialList::AddObserver(this);
+  }
+
+  ~TestFieldTrialObserver() override { FieldTrialList::RemoveObserver(this); }
+
+  void OnFieldTrialGroupFinalized(const std::string& trial,
+                                  const std::string& group) override {
+    trial_name_ = trial;
+    group_name_ = group;
+  }
+
+  const std::string& trial_name() const { return trial_name_; }
+  const std::string& group_name() const { return group_name_; }
+
+ private:
+  std::string trial_name_;
+  std::string group_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver);
+};
+
+}  // namespace
+
+class FieldTrialTest : public testing::Test {
+ public:
+  FieldTrialTest() : trial_list_(NULL) {}
+
+ private:
+  MessageLoop message_loop_;
+  FieldTrialList trial_list_;
+};
+
+// Test registration, and also check that destructors are called for trials
+// (and that Valgrind doesn't catch us leaking).
+TEST_F(FieldTrialTest, Registration) {
+  const char name1[] = "name 1 test";
+  const char name2[] = "name 2 test";
+  EXPECT_FALSE(FieldTrialList::Find(name1));
+  EXPECT_FALSE(FieldTrialList::Find(name2));
+
+  scoped_refptr<FieldTrial> trial1 =
+      CreateFieldTrial(name1, 10, "default name 1 test", NULL);
+  EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
+  EXPECT_EQ(name1, trial1->trial_name());
+  EXPECT_EQ("", trial1->group_name_internal());
+
+  trial1->AppendGroup(std::string(), 7);
+
+  EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
+  EXPECT_FALSE(FieldTrialList::Find(name2));
+
+  scoped_refptr<FieldTrial> trial2 =
+      CreateFieldTrial(name2, 10, "default name 2 test", NULL);
+  EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
+  EXPECT_EQ(name2, trial2->trial_name());
+  EXPECT_EQ("", trial2->group_name_internal());
+
+  trial2->AppendGroup("a first group", 7);
+
+  EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
+  EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2));
+  // Note: FieldTrialList should delete the objects at shutdown.
+}
+
+TEST_F(FieldTrialTest, AbsoluteProbabilities) {
+  char always_true[] = " always true";
+  char default_always_true[] = " default always true";
+  char always_false[] = " always false";
+  char default_always_false[] = " default always false";
+  for (int i = 1; i < 250; ++i) {
+    // Try lots of names, by changing the first character of the name.
+    char c = static_cast<char>(i);
+    always_true[0] = c;
+    default_always_true[0] = c;
+    always_false[0] = c;
+    default_always_false[0] = c;
+
+    scoped_refptr<FieldTrial> trial_true =
+        CreateFieldTrial(always_true, 10, default_always_true, NULL);
+    const std::string winner = "TheWinner";
+    int winner_group = trial_true->AppendGroup(winner, 10);
+
+    EXPECT_EQ(winner_group, trial_true->group());
+    EXPECT_EQ(winner, trial_true->group_name());
+
+    scoped_refptr<FieldTrial> trial_false =
+        CreateFieldTrial(always_false, 10, default_always_false, NULL);
+    int loser_group = trial_false->AppendGroup("ALoser", 0);
+
+    EXPECT_NE(loser_group, trial_false->group());
+  }
+}
+
+TEST_F(FieldTrialTest, RemainingProbability) {
+  // First create a test that hasn't had a winner yet.
+  const std::string winner = "Winner";
+  const std::string loser = "Loser";
+  scoped_refptr<FieldTrial> trial;
+  int counter = 0;
+  int default_group_number = -1;
+  do {
+    std::string name = StringPrintf("trial%d", ++counter);
+    trial = CreateFieldTrial(name, 10, winner, &default_group_number);
+    trial->AppendGroup(loser, 5);  // 50% chance of not being chosen.
+    // If a group is not assigned, group_ will be kNotFinalized.
+  } while (trial->group_ != FieldTrial::kNotFinalized);
+
+  // And that 'default' group (winner) should always win.
+  EXPECT_EQ(default_group_number, trial->group());
+
+  // And that winner should ALWAYS win.
+  EXPECT_EQ(winner, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, FiftyFiftyProbability) {
+  // Check that even with small divisors, we have the proper probabilities, and
+  // all outcomes are possible.  Since this is a 50-50 test, it should get both
+  // outcomes in a few tries, but we'll try no more than 100 times (and be flaky
+  // with probability around 1 in 2^99).
+  bool first_winner = false;
+  bool second_winner = false;
+  int counter = 0;
+  do {
+    std::string name = base::StringPrintf("FiftyFifty%d", ++counter);
+    std::string default_group_name = base::StringPrintf("Default FiftyFifty%d",
+                                                        ++counter);
+    scoped_refptr<FieldTrial> trial =
+        CreateFieldTrial(name, 2, default_group_name, NULL);
+    trial->AppendGroup("first", 1);  // 50% chance of being chosen.
+    // If group_ is kNotFinalized, then a group assignement hasn't been done.
+    if (trial->group_ != FieldTrial::kNotFinalized) {
+      first_winner = true;
+      continue;
+    }
+    trial->AppendGroup("second", 1);  // Always chosen at this point.
+    EXPECT_NE(FieldTrial::kNotFinalized, trial->group());
+    second_winner = true;
+  } while ((!second_winner || !first_winner) && counter < 100);
+  EXPECT_TRUE(second_winner);
+  EXPECT_TRUE(first_winner);
+}
+
+TEST_F(FieldTrialTest, MiddleProbabilities) {
+  char name[] = " same name";
+  char default_group_name[] = " default same name";
+  bool false_event_seen = false;
+  bool true_event_seen = false;
+  for (int i = 1; i < 250; ++i) {
+    char c = static_cast<char>(i);
+    name[0] = c;
+    default_group_name[0] = c;
+    scoped_refptr<FieldTrial> trial =
+        CreateFieldTrial(name, 10, default_group_name, NULL);
+    int might_win = trial->AppendGroup("MightWin", 5);
+
+    if (trial->group() == might_win) {
+      true_event_seen = true;
+    } else {
+      false_event_seen = true;
+    }
+    if (false_event_seen && true_event_seen)
+      return;  // Successful test!!!
+  }
+  // Very surprising to get here. Probability should be around 1 in 2 ** 250.
+  // One of the following will fail.
+  EXPECT_TRUE(false_event_seen);
+  EXPECT_TRUE(true_event_seen);
+}
+
+TEST_F(FieldTrialTest, OneWinner) {
+  char name[] = "Some name";
+  char default_group_name[] = "Default some name";
+  int group_count(10);
+
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(name, group_count, default_group_name, NULL);
+  int winner_index(-2);
+  std::string winner_name;
+
+  for (int i = 1; i <= group_count; ++i) {
+    int might_win = trial->AppendGroup(std::string(), 1);
+
+    // Because we keep appending groups, we want to see if the last group that
+    // was added has been assigned or not.
+    if (trial->group_ == might_win) {
+      EXPECT_EQ(-2, winner_index);
+      winner_index = might_win;
+      StringAppendF(&winner_name, "%d", might_win);
+      EXPECT_EQ(winner_name, trial->group_name());
+    }
+  }
+  EXPECT_GE(winner_index, 0);
+  // Since all groups cover the total probability, we should not have
+  // chosen the default group.
+  EXPECT_NE(trial->group(), default_group_number);
+  EXPECT_EQ(trial->group(), winner_index);
+  EXPECT_EQ(trial->group_name(), winner_name);
+}
+
+TEST_F(FieldTrialTest, DisableProbability) {
+  const std::string default_group_name = "Default group";
+  const std::string loser = "Loser";
+  const std::string name = "Trial";
+
+  // Create a field trail that has expired.
+  int default_group_number = -1;
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      name, 1000000000, default_group_name, OneYearBeforeBuildTime(), 1, 1,
+      FieldTrial::SESSION_RANDOMIZED,
+      &default_group_number);
+  trial->AppendGroup(loser, 999999999);  // 99.9999999% chance of being chosen.
+
+  // Because trial has expired, we should always be in the default group.
+  EXPECT_EQ(default_group_number, trial->group());
+
+  // And that default_group_name should ALWAYS win.
+  EXPECT_EQ(default_group_name, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, ActiveGroups) {
+  std::string no_group("No Group");
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(no_group, 10, "Default", NULL);
+
+  // There is no winner yet, so no NameGroupId should be returned.
+  FieldTrial::ActiveGroup active_group;
+  EXPECT_FALSE(trial->GetActiveGroup(&active_group));
+
+  // Create a single winning group.
+  std::string one_winner("One Winner");
+  trial = CreateFieldTrial(one_winner, 10, "Default", NULL);
+  std::string winner("Winner");
+  trial->AppendGroup(winner, 10);
+  EXPECT_FALSE(trial->GetActiveGroup(&active_group));
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  EXPECT_TRUE(trial->GetActiveGroup(&active_group));
+  EXPECT_EQ(one_winner, active_group.trial_name);
+  EXPECT_EQ(winner, active_group.group_name);
+
+  std::string multi_group("MultiGroup");
+  scoped_refptr<FieldTrial> multi_group_trial =
+      CreateFieldTrial(multi_group, 9, "Default", NULL);
+
+  multi_group_trial->AppendGroup("Me", 3);
+  multi_group_trial->AppendGroup("You", 3);
+  multi_group_trial->AppendGroup("Them", 3);
+  EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group));
+  // Finalize the group selection by accessing the selected group.
+  multi_group_trial->group();
+  EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group));
+  EXPECT_EQ(multi_group, active_group.trial_name);
+  EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name);
+
+  // Now check if the list is built properly...
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(2U, active_groups.size());
+  for (size_t i = 0; i < active_groups.size(); ++i) {
+    // Order is not guaranteed, so check all values.
+    EXPECT_NE(no_group, active_groups[i].trial_name);
+    EXPECT_TRUE(one_winner != active_groups[i].trial_name ||
+                winner == active_groups[i].group_name);
+    EXPECT_TRUE(multi_group != active_groups[i].trial_name ||
+                multi_group_trial->group_name() == active_groups[i].group_name);
+  }
+}
+
+TEST_F(FieldTrialTest, AllGroups) {
+  FieldTrial::FieldTrialState field_trial_state;
+  std::string one_winner("One Winner");
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(one_winner, 10, "Default", NULL);
+  std::string winner("Winner");
+  trial->AppendGroup(winner, 10);
+  EXPECT_TRUE(trial->GetState(&field_trial_state));
+  EXPECT_EQ(one_winner, field_trial_state.trial_name);
+  EXPECT_EQ(winner, field_trial_state.group_name);
+  trial->group();
+  EXPECT_TRUE(trial->GetState(&field_trial_state));
+  EXPECT_EQ(one_winner, field_trial_state.trial_name);
+  EXPECT_EQ(winner, field_trial_state.group_name);
+
+  std::string multi_group("MultiGroup");
+  scoped_refptr<FieldTrial> multi_group_trial =
+      CreateFieldTrial(multi_group, 9, "Default", NULL);
+
+  multi_group_trial->AppendGroup("Me", 3);
+  multi_group_trial->AppendGroup("You", 3);
+  multi_group_trial->AppendGroup("Them", 3);
+  EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
+  // Finalize the group selection by accessing the selected group.
+  multi_group_trial->group();
+  EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
+  EXPECT_EQ(multi_group, field_trial_state.trial_name);
+  EXPECT_EQ(multi_group_trial->group_name(), field_trial_state.group_name);
+}
+
+TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
+  const char kTrialName[] = "TestTrial";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
+
+  // Before |group()| is called, |GetActiveGroup()| should return false.
+  FieldTrial::ActiveGroup active_group;
+  EXPECT_FALSE(trial->GetActiveGroup(&active_group));
+
+  // |GetActiveFieldTrialGroups()| should also not include the trial.
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+
+  // After |group()| has been called, both APIs should succeed.
+  const int chosen_group = trial->group();
+  EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
+
+  EXPECT_TRUE(trial->GetActiveGroup(&active_group));
+  EXPECT_EQ(kTrialName, active_group.trial_name);
+  if (chosen_group == default_group)
+    EXPECT_EQ(kDefaultGroupName, active_group.group_name);
+  else
+    EXPECT_EQ(kSecondaryGroupName, active_group.group_name);
+
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(1U, active_groups.size());
+  EXPECT_EQ(kTrialName, active_groups[0].trial_name);
+  EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
+}
+
+TEST_F(FieldTrialTest, Save) {
+  std::string save_string;
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some name", 10, "Default some name", NULL);
+  // There is no winner yet, so no textual group name is associated with trial.
+  // In this case, the trial should not be included.
+  EXPECT_EQ("", trial->group_name_internal());
+  FieldTrialList::StatesToString(&save_string);
+  EXPECT_EQ("", save_string);
+  save_string.clear();
+
+  // Create a winning group.
+  trial->AppendGroup("Winner", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  FieldTrialList::StatesToString(&save_string);
+  EXPECT_EQ("Some name/Winner/", save_string);
+  save_string.clear();
+
+  // Create a second trial and winning group.
+  scoped_refptr<FieldTrial> trial2 =
+      CreateFieldTrial("xxx", 10, "Default xxx", NULL);
+  trial2->AppendGroup("yyyy", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial2->group();
+
+  FieldTrialList::StatesToString(&save_string);
+  // We assume names are alphabetized... though this is not critical.
+  EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string);
+  save_string.clear();
+
+  // Create a third trial with only the default group.
+  scoped_refptr<FieldTrial> trial3 =
+      CreateFieldTrial("zzz", 10, "default", NULL);
+  // Finalize the group selection by accessing the selected group.
+  trial3->group();
+
+  FieldTrialList::StatesToString(&save_string);
+  EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string);
+}
+
+TEST_F(FieldTrialTest, SaveAll) {
+  std::string save_string;
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some name", 10, "Default some name", NULL);
+  EXPECT_EQ("", trial->group_name_internal());
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("Some name/Default some name/", save_string);
+  save_string.clear();
+
+  // Create a winning group.
+  trial->AppendGroup("Winner", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("*Some name/Winner/", save_string);
+  save_string.clear();
+
+  // Create a second trial and winning group.
+  scoped_refptr<FieldTrial> trial2 =
+      CreateFieldTrial("xxx", 10, "Default xxx", NULL);
+  trial2->AppendGroup("yyyy", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial2->group();
+
+  FieldTrialList::AllStatesToString(&save_string);
+  // We assume names are alphabetized... though this is not critical.
+  EXPECT_EQ("*Some name/Winner/*xxx/yyyy/", save_string);
+  save_string.clear();
+
+  // Create a third trial with only the default group.
+  scoped_refptr<FieldTrial> trial3 =
+      CreateFieldTrial("zzz", 10, "default", NULL);
+
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("*Some name/Winner/*xxx/yyyy/zzz/default/", save_string);
+}
+
+TEST_F(FieldTrialTest, Restore) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("xxx"));
+
+  FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/",
+                                         FieldTrialList::DONT_ACTIVATE_TRIALS,
+                                         std::set<std::string>());
+
+  FieldTrial* trial = FieldTrialList::Find("Some_name");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Winner", trial->group_name());
+  EXPECT_EQ("Some_name", trial->trial_name());
+
+  trial = FieldTrialList::Find("xxx");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("yyyy", trial->group_name());
+  EXPECT_EQ("xxx", trial->trial_name());
+}
+
+TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) {
+  EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "tname/gname", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial* trial = FieldTrialList::Find("tname");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("gname", trial->group_name());
+  EXPECT_EQ("tname", trial->trial_name());
+}
+
+TEST_F(FieldTrialTest, BogusRestore) {
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "MissingSlash", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "MissingGroupName/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "noname, only group/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "/emptyname", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "*/emptyname", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+}
+
+TEST_F(FieldTrialTest, DuplicateRestore) {
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some name", 10, "Default", NULL);
+  trial->AppendGroup("Winner", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  std::string save_string;
+  FieldTrialList::StatesToString(&save_string);
+  EXPECT_EQ("Some name/Winner/", save_string);
+
+  // It is OK if we redundantly specify a winner.
+  EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
+      save_string, FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  // But it is an error to try to change to a different winner.
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "Some name/Loser/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringActive) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/Xyz/zyx/", FieldTrialList::ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("def", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_TRUE(active_groups.empty());
+
+  // Check that the values still get returned and querying them activates them.
+  EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
+  EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
+
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("def", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringForceActivation) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("def"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "*Abc/cba/def/fed/*Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("cba", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringActiveObserver) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+
+  TestFieldTrialObserver observer;
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/", FieldTrialList::ACTIVATE_TRIALS, std::set<std::string>()));
+
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ("Abc", observer.trial_name());
+  EXPECT_EQ("def", observer.group_name());
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+
+  TestFieldTrialObserver observer;
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  RunLoop().RunUntilIdle();
+  // Observer shouldn't be notified.
+  EXPECT_TRUE(observer.trial_name().empty());
+
+  // Check that the values still get returned and querying them activates them.
+  EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
+
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ("Abc", observer.trial_name());
+  EXPECT_EQ("def", observer.group_name());
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringWithIgnoredFieldTrials) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Foo"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Bar"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
+
+  std::set<std::string> ignored_trial_names;
+  ignored_trial_names.insert("Unaccepted1");
+  ignored_trial_names.insert("Unaccepted2");
+  ignored_trial_names.insert("Unaccepted3");
+
+  FieldTrialList::CreateTrialsFromString(
+      "Unaccepted1/Unaccepted1_name/"
+      "Foo/Foo_name/"
+      "Unaccepted2/Unaccepted2_name/"
+      "Bar/Bar_name/"
+      "Unaccepted3/Unaccepted3_name/",
+      FieldTrialList::DONT_ACTIVATE_TRIALS,
+      ignored_trial_names);
+
+  EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
+  EXPECT_TRUE(FieldTrialList::TrialExists("Foo"));
+  EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
+  EXPECT_TRUE(FieldTrialList::TrialExists("Bar"));
+  EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+
+  FieldTrial* trial = FieldTrialList::Find("Foo");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Foo", trial->trial_name());
+  EXPECT_EQ("Foo_name", trial->group_name());
+
+  trial = FieldTrialList::Find("Bar");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Bar", trial->trial_name());
+  EXPECT_EQ("Bar_name", trial->group_name());
+}
+
+TEST_F(FieldTrialTest, CreateFieldTrial) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
+
+  FieldTrialList::CreateFieldTrial("Some_name", "Winner");
+
+  FieldTrial* trial = FieldTrialList::Find("Some_name");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Winner", trial->group_name());
+  EXPECT_EQ("Some_name", trial->trial_name());
+}
+
+TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) {
+  const char kTrialName[] = "CreateFieldTrialIsActiveTrial";
+  const char kWinnerGroup[] = "Winner";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+  FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup);
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+}
+
+TEST_F(FieldTrialTest, DuplicateFieldTrial) {
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some_name", 10, "Default", NULL);
+  trial->AppendGroup("Winner", 10);
+
+  // It is OK if we redundantly specify a winner.
+  FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner");
+  EXPECT_TRUE(trial1 != NULL);
+
+  // But it is an error to try to change to a different winner.
+  FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser");
+  EXPECT_TRUE(trial2 == NULL);
+}
+
+TEST_F(FieldTrialTest, DisableImmediately) {
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("trial", 100, "default", &default_group_number);
+  trial->Disable();
+  ASSERT_EQ("default", trial->group_name());
+  ASSERT_EQ(default_group_number, trial->group());
+}
+
+TEST_F(FieldTrialTest, DisableAfterInitialization) {
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("trial", 100, "default", NULL);
+  trial->AppendGroup("non_default", 100);
+  trial->Disable();
+  ASSERT_EQ("default", trial->group_name());
+}
+
+TEST_F(FieldTrialTest, ForcedFieldTrials) {
+  // Validate we keep the forced choice.
+  FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the",
+                                                              "Force");
+  EXPECT_STREQ("Force", forced_trial->group_name().c_str());
+
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> factory_trial =
+      CreateFieldTrial("Use the", 1000, "default", &default_group_number);
+  EXPECT_EQ(factory_trial.get(), forced_trial);
+
+  int chosen_group = factory_trial->AppendGroup("Force", 100);
+  EXPECT_EQ(chosen_group, factory_trial->group());
+  int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100);
+  EXPECT_NE(chosen_group, not_chosen_group);
+
+  // Since we didn't force the default group, we should not be returned the
+  // chosen group as the default group.
+  EXPECT_NE(default_group_number, chosen_group);
+  int new_group = factory_trial->AppendGroup("Duck Tape", 800);
+  EXPECT_NE(chosen_group, new_group);
+  // The new group should not be the default group either.
+  EXPECT_NE(default_group_number, new_group);
+}
+
+TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) {
+  // Forcing the default should use the proper group ID.
+  FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name",
+                                                              "Default");
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> factory_trial =
+      CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number);
+  EXPECT_EQ(forced_trial, factory_trial.get());
+
+  int other_group = factory_trial->AppendGroup("Not Default", 100);
+  EXPECT_STREQ("Default", factory_trial->group_name().c_str());
+  EXPECT_EQ(default_group_number, factory_trial->group());
+  EXPECT_NE(other_group, factory_trial->group());
+
+  int new_other_group = factory_trial->AppendGroup("Not Default Either", 800);
+  EXPECT_NE(new_other_group, factory_trial->group());
+}
+
+TEST_F(FieldTrialTest, SetForced) {
+  // Start by setting a trial for which we ensure a winner...
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial("Use the", 1, "default", &default_group_number);
+  EXPECT_EQ(forced_trial, forced_trial);
+
+  int forced_group = forced_trial->AppendGroup("Force", 1);
+  EXPECT_EQ(forced_group, forced_trial->group());
+
+  // Now force it.
+  forced_trial->SetForced();
+
+  // Now try to set it up differently as a hard coded registration would.
+  scoped_refptr<FieldTrial> hard_coded_trial =
+      CreateFieldTrial("Use the", 1, "default", &default_group_number);
+  EXPECT_EQ(hard_coded_trial, forced_trial);
+
+  int would_lose_group = hard_coded_trial->AppendGroup("Force", 0);
+  EXPECT_EQ(forced_group, hard_coded_trial->group());
+  EXPECT_EQ(forced_group, would_lose_group);
+
+  // Same thing if we would have done it to win again.
+  scoped_refptr<FieldTrial> other_hard_coded_trial =
+      CreateFieldTrial("Use the", 1, "default", &default_group_number);
+  EXPECT_EQ(other_hard_coded_trial, forced_trial);
+
+  int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1);
+  EXPECT_EQ(forced_group, other_hard_coded_trial->group());
+  EXPECT_EQ(forced_group, would_win_group);
+}
+
+TEST_F(FieldTrialTest, SetForcedDefaultOnly) {
+  const char kTrialName[] = "SetForcedDefaultOnly";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->SetForced();
+
+  trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  EXPECT_EQ(default_group, trial->group());
+  EXPECT_EQ(kDefaultGroupName, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) {
+  const char kTrialName[] = "SetForcedDefaultWithExtraGroup";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->SetForced();
+
+  trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  const int extra_group = trial->AppendGroup("Extra", 100);
+  EXPECT_EQ(default_group, trial->group());
+  EXPECT_NE(extra_group, trial->group());
+  EXPECT_EQ(kDefaultGroupName, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) {
+  const char kTrialName[] = "SetForcedTurnFeatureOn";
+  const char kExtraGroupName[] = "Extra";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that turns the feature on when the
+  // original hard-coded config had it disabled.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  forced_trial->AppendGroup(kExtraGroupName, 100);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(extra_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kExtraGroupName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) {
+  const char kTrialName[] = "SetForcedTurnFeatureOff";
+  const char kExtraGroupName[] = "Extra";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that turns the feature off when the
+  // original hard-coded config had it enabled.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  forced_trial->AppendGroup(kExtraGroupName, 0);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(default_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) {
+  const char kTrialName[] = "SetForcedDefaultGroupChange";
+  const char kGroupAName[] = "A";
+  const char kGroupBName[] = "B";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that switches which group is default
+  // and ensures that the non-forced code receives the correct group numbers.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
+  forced_trial->AppendGroup(kGroupBName, 100);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(default_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kGroupBName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) {
+  const char kTrialName[] = "SetForcedDefaultGroupChange";
+  const char kGroupAName[] = "A";
+  const char kGroupBName[] = "B";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that switches which group is default
+  // and ensures that the non-forced code receives the correct group numbers.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
+  forced_trial->AppendGroup(kGroupBName, 0);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(extra_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kGroupAName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, Observe) {
+  const char kTrialName[] = "TrialToObserve1";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
+  const int chosen_group = trial->group();
+  EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
+
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(kTrialName, observer.trial_name());
+  if (chosen_group == default_group)
+    EXPECT_EQ(kDefaultGroupName, observer.group_name());
+  else
+    EXPECT_EQ(kSecondaryGroupName, observer.group_name());
+}
+
+TEST_F(FieldTrialTest, ObserveDisabled) {
+  const char kTrialName[] = "TrialToObserve2";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->AppendGroup("A", 25);
+  trial->AppendGroup("B", 25);
+  trial->AppendGroup("C", 25);
+  trial->Disable();
+
+  // Observer shouldn't be notified of a disabled trial.
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+
+  // Observer shouldn't be notified even after a |group()| call.
+  EXPECT_EQ(default_group, trial->group());
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+}
+
+TEST_F(FieldTrialTest, ObserveForcedDisabled) {
+  const char kTrialName[] = "TrialToObserve3";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->AppendGroup("A", 25);
+  trial->AppendGroup("B", 25);
+  trial->AppendGroup("C", 25);
+  trial->SetForced();
+  trial->Disable();
+
+  // Observer shouldn't be notified of a disabled trial, even when forced.
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+
+  // Observer shouldn't be notified even after a |group()| call.
+  EXPECT_EQ(default_group, trial->group());
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+}
+
+TEST_F(FieldTrialTest, DisabledTrialNotActive) {
+  const char kTrialName[] = "DisabledTrial";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  trial->AppendGroup("X", 50);
+  trial->Disable();
+
+  // Ensure the trial is not listed as active.
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+
+  // Ensure the trial is not listed in the |StatesToString()| result.
+  std::string states;
+  FieldTrialList::StatesToString(&states);
+  EXPECT_TRUE(states.empty());
+}
+
+TEST_F(FieldTrialTest, ExpirationYearNotExpired) {
+  const char kTrialName[] = "NotExpired";
+  const char kGroupName[] = "Group2";
+  const int kProbability = 100;
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, NULL);
+  trial->AppendGroup(kGroupName, kProbability);
+  EXPECT_EQ(kGroupName, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
+  const int kBucketCount = 100;
+
+  // Try each boundary value |i / 100.0| as the entropy value.
+  for (int i = 0; i < kBucketCount; ++i) {
+    const double entropy = i / static_cast<double>(kBucketCount);
+
+    scoped_refptr<base::FieldTrial> trial(
+        new base::FieldTrial("test", kBucketCount, "default", entropy));
+    for (int j = 0; j < kBucketCount; ++j)
+      trial->AppendGroup(base::StringPrintf("%d", j), 1);
+
+    EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name());
+  }
+}
+
+TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) {
+  const double kEntropyValue = 1.0 - 1e-9;
+  ASSERT_LT(kEntropyValue, 1.0);
+
+  scoped_refptr<base::FieldTrial> trial(
+      new base::FieldTrial("test", 2, "default", kEntropyValue));
+  trial->AppendGroup("1", 1);
+  trial->AppendGroup("2", 1);
+
+  EXPECT_EQ("2", trial->group_name());
+}
+
+TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
+  const char kTrialName[] = "CreateSimulatedFieldTrial";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Different cases to test, e.g. default vs. non default group being chosen.
+  struct {
+    double entropy_value;
+    const char* expected_group;
+  } test_cases[] = {
+    { 0.4, "A" },
+    { 0.85, "B" },
+    { 0.95, kDefaultGroupName },
+  };
+
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    TestFieldTrialObserver observer;
+    scoped_refptr<FieldTrial> trial(
+       FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                             test_cases[i].entropy_value));
+    trial->AppendGroup("A", 80);
+    trial->AppendGroup("B", 10);
+    EXPECT_EQ(test_cases[i].expected_group, trial->group_name());
+
+    // Field trial shouldn't have been registered with the list.
+    EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
+    EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
+
+    // Observer shouldn't have been notified.
+    RunLoop().RunUntilIdle();
+    EXPECT_TRUE(observer.trial_name().empty());
+
+    // The trial shouldn't be in the active set of trials.
+    FieldTrial::ActiveGroups active_groups;
+    FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+    EXPECT_TRUE(active_groups.empty());
+
+    // The trial shouldn't be listed in the |StatesToString()| result.
+    std::string states;
+    FieldTrialList::StatesToString(&states);
+    EXPECT_TRUE(states.empty());
+  }
+}
+
+TEST(FieldTrialTestWithoutList, StatesStringFormat) {
+  std::string save_string;
+
+  // Scoping the first FieldTrialList, as we need another one to test the
+  // importing function.
+  {
+    FieldTrialList field_trial_list(NULL);
+    scoped_refptr<FieldTrial> trial =
+        CreateFieldTrial("Abc", 10, "Default some name", NULL);
+    trial->AppendGroup("cba", 10);
+    trial->group();
+    scoped_refptr<FieldTrial> trial2 =
+        CreateFieldTrial("Xyz", 10, "Default xxx", NULL);
+    trial2->AppendGroup("zyx", 10);
+    trial2->group();
+    scoped_refptr<FieldTrial> trial3 =
+        CreateFieldTrial("zzz", 10, "default", NULL);
+
+    FieldTrialList::AllStatesToString(&save_string);
+  }
+
+  // Starting with a new blank FieldTrialList.
+  FieldTrialList field_trial_list(NULL);
+  ASSERT_TRUE(field_trial_list.CreateTrialsFromString(
+      save_string, FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  field_trial_list.GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("cba", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+  EXPECT_TRUE(field_trial_list.TrialExists("zzz"));
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(FieldTrialDeathTest, OneTimeRandomizedTrialWithoutFieldTrialList) {
+  // Trying to instantiate a one-time randomized field trial before the
+  // FieldTrialList is created should crash.
+  EXPECT_DEATH(FieldTrialList::FactoryGetFieldTrial(
+      "OneTimeRandomizedTrialWithoutFieldTrialList", 100, kDefaultGroupName,
+      base::FieldTrialList::kNoExpirationYear, 1, 1,
+      base::FieldTrial::ONE_TIME_RANDOMIZED, NULL), "");
+}
+#endif
+
+}  // namespace base
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
new file mode 100644
index 0000000..42ced3d
--- /dev/null
+++ b/base/metrics/histogram.cc
@@ -0,0 +1,846 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+// See header file for details and examples.
+
+#include "base/metrics/histogram.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+
+using std::string;
+using std::vector;
+
+namespace base {
+
+namespace {
+
+bool ReadHistogramArguments(PickleIterator* iter,
+                            string* histogram_name,
+                            int* flags,
+                            int* declared_min,
+                            int* declared_max,
+                            size_t* bucket_count,
+                            uint32* range_checksum) {
+  if (!iter->ReadString(histogram_name) ||
+      !iter->ReadInt(flags) ||
+      !iter->ReadInt(declared_min) ||
+      !iter->ReadInt(declared_max) ||
+      !iter->ReadSizeT(bucket_count) ||
+      !iter->ReadUInt32(range_checksum)) {
+    DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
+    return false;
+  }
+
+  // Since these fields may have come from an untrusted renderer, do additional
+  // checks above and beyond those in Histogram::Initialize()
+  if (*declared_max <= 0 ||
+      *declared_min <= 0 ||
+      *declared_max < *declared_min ||
+      INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count ||
+      *bucket_count < 2) {
+    DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
+    return false;
+  }
+
+  // We use the arguments to find or create the local version of the histogram
+  // in this process, so we need to clear the IPC flag.
+  DCHECK(*flags & HistogramBase::kIPCSerializationSourceFlag);
+  *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+  return true;
+}
+
+bool ValidateRangeChecksum(const HistogramBase& histogram,
+                           uint32 range_checksum) {
+  const Histogram& casted_histogram =
+      static_cast<const Histogram&>(histogram);
+
+  return casted_histogram.bucket_ranges()->checksum() == range_checksum;
+}
+
+}  // namespace
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+// static
+const size_t Histogram::kBucketCount_MAX = 16384u;
+
+HistogramBase* Histogram::FactoryGet(const string& name,
+                                     Sample minimum,
+                                     Sample maximum,
+                                     size_t bucket_count,
+                                     int32 flags) {
+  bool valid_arguments =
+      InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    InitializeBucketRanges(minimum, maximum, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    Histogram* tentative_histogram =
+        new Histogram(name, minimum, maximum, registered_ranges);
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType());
+  if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) {
+    // The construction arguments do not match the existing histogram.  This can
+    // come about if an extension updates in the middle of a chrome run and has
+    // changed one of them, or simply by bad code within Chrome itself.  We
+    // return NULL here with the expectation that bad code in Chrome will crash
+    // on dereference, but extension/Pepper APIs will guard against NULL and not
+    // crash.
+    DLOG(ERROR) << "Histogram " << name << " has bad construction arguments";
+    return NULL;
+  }
+  return histogram;
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const string& name,
+                                         TimeDelta minimum,
+                                         TimeDelta maximum,
+                                         size_t bucket_count,
+                                         int32 flags) {
+  return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
+                    static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
+                    flags);
+}
+
+// Calculate what range of values are held in each bucket.
+// We have to be careful that we don't pick a ratio between starting points in
+// consecutive buckets that is sooo small, that the integer bounds are the same
+// (effectively making one bucket get no values).  We need to avoid:
+//   ranges(i) == ranges(i + 1)
+// To avoid that, we just do a fine-grained bucket width as far as we need to
+// until we get a ratio that moves us along at least 2 units at a time.  From
+// that bucket onward we do use the exponential growth of buckets.
+//
+// static
+void Histogram::InitializeBucketRanges(Sample minimum,
+                                       Sample maximum,
+                                       BucketRanges* ranges) {
+  double log_max = log(static_cast<double>(maximum));
+  double log_ratio;
+  double log_next;
+  size_t bucket_index = 1;
+  Sample current = minimum;
+  ranges->set_range(bucket_index, current);
+  size_t bucket_count = ranges->bucket_count();
+  while (bucket_count > ++bucket_index) {
+    double log_current;
+    log_current = log(static_cast<double>(current));
+    // Calculate the count'th root of the range.
+    log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
+    // See where the next bucket would start.
+    log_next = log_current + log_ratio;
+    Sample next;
+    next = static_cast<int>(floor(exp(log_next) + 0.5));
+    if (next > current)
+      current = next;
+    else
+      ++current;  // Just do a narrow bucket, and keep trying.
+    ranges->set_range(bucket_index, current);
+  }
+  ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
+  ranges->ResetChecksum();
+}
+
+// static
+const int Histogram::kCommonRaceBasedCountMismatch = 5;
+
+int Histogram::FindCorruption(const HistogramSamples& samples) const {
+  int inconsistencies = NO_INCONSISTENCIES;
+  Sample previous_range = -1;  // Bottom range is always 0.
+  for (size_t index = 0; index < bucket_count(); ++index) {
+    int new_range = ranges(index);
+    if (previous_range >= new_range)
+      inconsistencies |= BUCKET_ORDER_ERROR;
+    previous_range = new_range;
+  }
+
+  if (!bucket_ranges()->HasValidChecksum())
+    inconsistencies |= RANGE_CHECKSUM_ERROR;
+
+  int64 delta64 = samples.redundant_count() - samples.TotalCount();
+  if (delta64 != 0) {
+    int delta = static_cast<int>(delta64);
+    if (delta != delta64)
+      delta = INT_MAX;  // Flag all giant errors as INT_MAX.
+    if (delta > 0) {
+      UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
+      if (delta > kCommonRaceBasedCountMismatch)
+        inconsistencies |= COUNT_HIGH_ERROR;
+    } else {
+      DCHECK_GT(0, delta);
+      UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
+      if (-delta > kCommonRaceBasedCountMismatch)
+        inconsistencies |= COUNT_LOW_ERROR;
+    }
+  }
+  return inconsistencies;
+}
+
+Sample Histogram::ranges(size_t i) const {
+  return bucket_ranges_->range(i);
+}
+
+size_t Histogram::bucket_count() const {
+  return bucket_ranges_->bucket_count();
+}
+
+// static
+bool Histogram::InspectConstructionArguments(const string& name,
+                                             Sample* minimum,
+                                             Sample* maximum,
+                                             size_t* bucket_count) {
+  // Defensive code for backward compatibility.
+  if (*minimum < 1) {
+    DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
+    *minimum = 1;
+  }
+  if (*maximum >= kSampleType_MAX) {
+    DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
+    *maximum = kSampleType_MAX - 1;
+  }
+  if (*bucket_count >= kBucketCount_MAX) {
+    DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
+             << *bucket_count;
+    *bucket_count = kBucketCount_MAX - 1;
+  }
+
+  if (*minimum >= *maximum)
+    return false;
+  if (*bucket_count < 3)
+    return false;
+  if (*bucket_count > static_cast<size_t>(*maximum - *minimum + 2))
+    return false;
+  return true;
+}
+
+HistogramType Histogram::GetHistogramType() const {
+  return HISTOGRAM;
+}
+
+bool Histogram::HasConstructionArguments(Sample expected_minimum,
+                                         Sample expected_maximum,
+                                         size_t expected_bucket_count) const {
+  return ((expected_minimum == declared_min_) &&
+          (expected_maximum == declared_max_) &&
+          (expected_bucket_count == bucket_count()));
+}
+
+void Histogram::Add(int value) {
+  DCHECK_EQ(0, ranges(0));
+  DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
+
+  if (value > kSampleType_MAX - 1)
+    value = kSampleType_MAX - 1;
+  if (value < 0)
+    value = 0;
+  samples_->Accumulate(value, 1);
+}
+
+scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
+  return SnapshotSampleVector().Pass();
+}
+
+void Histogram::AddSamples(const HistogramSamples& samples) {
+  samples_->Add(samples);
+}
+
+bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
+  return samples_->AddFromPickle(iter);
+}
+
+// The following methods provide a graphical histogram display.
+void Histogram::WriteHTMLGraph(string* output) const {
+  // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
+  output->append("<PRE>");
+  WriteAsciiImpl(true, "<br>", output);
+  output->append("</PRE>");
+}
+
+void Histogram::WriteAscii(string* output) const {
+  WriteAsciiImpl(true, "\n", output);
+}
+
+bool Histogram::SerializeInfoImpl(Pickle* pickle) const {
+  DCHECK(bucket_ranges()->HasValidChecksum());
+  return pickle->WriteString(histogram_name()) &&
+      pickle->WriteInt(flags()) &&
+      pickle->WriteInt(declared_min()) &&
+      pickle->WriteInt(declared_max()) &&
+      pickle->WriteSizeT(bucket_count()) &&
+      pickle->WriteUInt32(bucket_ranges()->checksum());
+}
+
+Histogram::Histogram(const string& name,
+                     Sample minimum,
+                     Sample maximum,
+                     const BucketRanges* ranges)
+  : HistogramBase(name),
+    bucket_ranges_(ranges),
+    declared_min_(minimum),
+    declared_max_(maximum) {
+  if (ranges)
+    samples_.reset(new SampleVector(ranges));
+}
+
+Histogram::~Histogram() {
+}
+
+bool Histogram::PrintEmptyBucket(size_t index) const {
+  return true;
+}
+
+// Use the actual bucket widths (like a linear histogram) until the widths get
+// over some transition value, and then use that transition width.  Exponentials
+// get so big so fast (and we don't expect to see a lot of entries in the large
+// buckets), so we need this to make it possible to see what is going on and
+// not have 0-graphical-height buckets.
+double Histogram::GetBucketSize(Count current, size_t i) const {
+  DCHECK_GT(ranges(i + 1), ranges(i));
+  static const double kTransitionWidth = 5;
+  double denominator = ranges(i + 1) - ranges(i);
+  if (denominator > kTransitionWidth)
+    denominator = kTransitionWidth;  // Stop trying to normalize.
+  return current/denominator;
+}
+
+const string Histogram::GetAsciiBucketRange(size_t i) const {
+  return GetSimpleAsciiBucketRange(ranges(i));
+}
+
+//------------------------------------------------------------------------------
+// Private methods
+
+// static
+HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
+  string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  // Find or create the local version of the histogram in this process.
+  HistogramBase* histogram = Histogram::FactoryGet(
+      histogram_name, declared_min, declared_max, bucket_count, flags);
+
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
+  scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
+  samples->Add(*samples_);
+  return samples.Pass();
+}
+
+void Histogram::WriteAsciiImpl(bool graph_it,
+                               const string& newline,
+                               string* output) const {
+  // Get local (stack) copies of all effectively volatile class data so that we
+  // are consistent across our output activities.
+  scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  Count sample_count = snapshot->TotalCount();
+
+  WriteAsciiHeader(*snapshot, sample_count, output);
+  output->append(newline);
+
+  // Prepare to normalize graphical rendering of bucket contents.
+  double max_size = 0;
+  if (graph_it)
+    max_size = GetPeakBucketSize(*snapshot);
+
+  // Calculate space needed to print bucket range numbers.  Leave room to print
+  // nearly the largest bucket range without sliding over the histogram.
+  size_t largest_non_empty_bucket = bucket_count() - 1;
+  while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
+    if (0 == largest_non_empty_bucket)
+      break;  // All buckets are empty.
+    --largest_non_empty_bucket;
+  }
+
+  // Calculate largest print width needed for any of our bucket range displays.
+  size_t print_width = 1;
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    if (snapshot->GetCountAtIndex(i)) {
+      size_t width = GetAsciiBucketRange(i).size() + 1;
+      if (width > print_width)
+        print_width = width;
+    }
+  }
+
+  int64 remaining = sample_count;
+  int64 past = 0;
+  // Output the actual histogram graph.
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    Count current = snapshot->GetCountAtIndex(i);
+    if (!current && !PrintEmptyBucket(i))
+      continue;
+    remaining -= current;
+    string range = GetAsciiBucketRange(i);
+    output->append(range);
+    for (size_t j = 0; range.size() + j < print_width + 1; ++j)
+      output->push_back(' ');
+    if (0 == current && i < bucket_count() - 1 &&
+        0 == snapshot->GetCountAtIndex(i + 1)) {
+      while (i < bucket_count() - 1 &&
+             0 == snapshot->GetCountAtIndex(i + 1)) {
+        ++i;
+      }
+      output->append("... ");
+      output->append(newline);
+      continue;  // No reason to plot emptiness.
+    }
+    double current_size = GetBucketSize(current, i);
+    if (graph_it)
+      WriteAsciiBucketGraph(current_size, max_size, output);
+    WriteAsciiBucketContext(past, current, remaining, i, output);
+    output->append(newline);
+    past += current;
+  }
+  DCHECK_EQ(sample_count, past);
+}
+
+double Histogram::GetPeakBucketSize(const SampleVector& samples) const {
+  double max = 0;
+  for (size_t i = 0; i < bucket_count() ; ++i) {
+    double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
+    if (current_size > max)
+      max = current_size;
+  }
+  return max;
+}
+
+void Histogram::WriteAsciiHeader(const SampleVector& samples,
+                                 Count sample_count,
+                                 string* output) const {
+  StringAppendF(output,
+                "Histogram: %s recorded %d samples",
+                histogram_name().c_str(),
+                sample_count);
+  if (0 == sample_count) {
+    DCHECK_EQ(samples.sum(), 0);
+  } else {
+    double average = static_cast<float>(samples.sum()) / sample_count;
+
+    StringAppendF(output, ", average = %.1f", average);
+  }
+  if (flags() & ~kHexRangePrintingFlag)
+    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+}
+
+void Histogram::WriteAsciiBucketContext(const int64 past,
+                                        const Count current,
+                                        const int64 remaining,
+                                        const size_t i,
+                                        string* output) const {
+  double scaled_sum = (past + current + remaining) / 100.0;
+  WriteAsciiBucketValue(current, scaled_sum, output);
+  if (0 < i) {
+    double percentage = past / scaled_sum;
+    StringAppendF(output, " {%3.1f%%}", percentage);
+  }
+}
+
+void Histogram::GetParameters(DictionaryValue* params) const {
+  params->SetString("type", HistogramTypeToString(GetHistogramType()));
+  params->SetInteger("min", declared_min());
+  params->SetInteger("max", declared_max());
+  params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
+}
+
+void Histogram::GetCountAndBucketData(Count* count,
+                                      int64* sum,
+                                      ListValue* buckets) const {
+  scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  *count = snapshot->TotalCount();
+  *sum = snapshot->sum();
+  size_t index = 0;
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    Sample count_at_index = snapshot->GetCountAtIndex(i);
+    if (count_at_index > 0) {
+      scoped_ptr<DictionaryValue> bucket_value(new DictionaryValue());
+      bucket_value->SetInteger("low", ranges(i));
+      if (i != bucket_count() - 1)
+        bucket_value->SetInteger("high", ranges(i + 1));
+      bucket_value->SetInteger("count", count_at_index);
+      buckets->Set(index, bucket_value.release());
+      ++index;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// LinearHistogram: This histogram uses a traditional set of evenly spaced
+// buckets.
+//------------------------------------------------------------------------------
+
+LinearHistogram::~LinearHistogram() {}
+
+HistogramBase* LinearHistogram::FactoryGet(const string& name,
+                                           Sample minimum,
+                                           Sample maximum,
+                                           size_t bucket_count,
+                                           int32 flags) {
+  return FactoryGetWithRangeDescription(
+      name, minimum, maximum, bucket_count, flags, NULL);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const string& name,
+                                               TimeDelta minimum,
+                                               TimeDelta maximum,
+                                               size_t bucket_count,
+                                               int32 flags) {
+  return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
+                    static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
+                    flags);
+}
+
+HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      size_t bucket_count,
+      int32 flags,
+      const DescriptionPair descriptions[]) {
+  bool valid_arguments = Histogram::InspectConstructionArguments(
+      name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    InitializeBucketRanges(minimum, maximum, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    LinearHistogram* tentative_histogram =
+        new LinearHistogram(name, minimum, maximum, registered_ranges);
+
+    // Set range descriptions.
+    if (descriptions) {
+      for (int i = 0; descriptions[i].description; ++i) {
+        tentative_histogram->bucket_description_[descriptions[i].sample] =
+            descriptions[i].description;
+      }
+    }
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType());
+  if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) {
+    // The construction arguments do not match the existing histogram.  This can
+    // come about if an extension updates in the middle of a chrome run and has
+    // changed one of them, or simply by bad code within Chrome itself.  We
+    // return NULL here with the expectation that bad code in Chrome will crash
+    // on dereference, but extension/Pepper APIs will guard against NULL and not
+    // crash.
+    DLOG(ERROR) << "Histogram " << name << " has bad construction arguments";
+    return NULL;
+  }
+  return histogram;
+}
+
+HistogramType LinearHistogram::GetHistogramType() const {
+  return LINEAR_HISTOGRAM;
+}
+
+LinearHistogram::LinearHistogram(const string& name,
+                                 Sample minimum,
+                                 Sample maximum,
+                                 const BucketRanges* ranges)
+    : Histogram(name, minimum, maximum, ranges) {
+}
+
+double LinearHistogram::GetBucketSize(Count current, size_t i) const {
+  DCHECK_GT(ranges(i + 1), ranges(i));
+  // Adjacent buckets with different widths would have "surprisingly" many (few)
+  // samples in a histogram if we didn't normalize this way.
+  double denominator = ranges(i + 1) - ranges(i);
+  return current/denominator;
+}
+
+const string LinearHistogram::GetAsciiBucketRange(size_t i) const {
+  int range = ranges(i);
+  BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
+  if (it == bucket_description_.end())
+    return Histogram::GetAsciiBucketRange(i);
+  return it->second;
+}
+
+bool LinearHistogram::PrintEmptyBucket(size_t index) const {
+  return bucket_description_.find(ranges(index)) == bucket_description_.end();
+}
+
+// static
+void LinearHistogram::InitializeBucketRanges(Sample minimum,
+                                             Sample maximum,
+                                             BucketRanges* ranges) {
+  double min = minimum;
+  double max = maximum;
+  size_t bucket_count = ranges->bucket_count();
+  for (size_t i = 1; i < bucket_count; ++i) {
+    double linear_range =
+        (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
+    ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
+  }
+  ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
+  ranges->ResetChecksum();
+}
+
+// static
+HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      histogram_name, declared_min, declared_max, bucket_count, flags);
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+//------------------------------------------------------------------------------
+// This section provides implementation for BooleanHistogram.
+//------------------------------------------------------------------------------
+
+HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(4);
+    LinearHistogram::InitializeBucketRanges(1, 2, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    BooleanHistogram* tentative_histogram =
+        new BooleanHistogram(name, registered_ranges);
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType());
+  return histogram;
+}
+
+HistogramType BooleanHistogram::GetHistogramType() const {
+  return BOOLEAN_HISTOGRAM;
+}
+
+BooleanHistogram::BooleanHistogram(const string& name,
+                                   const BucketRanges* ranges)
+    : LinearHistogram(name, 1, 2, ranges) {}
+
+HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  HistogramBase* histogram = BooleanHistogram::FactoryGet(
+      histogram_name, flags);
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+//------------------------------------------------------------------------------
+// CustomHistogram:
+//------------------------------------------------------------------------------
+
+HistogramBase* CustomHistogram::FactoryGet(const string& name,
+                                           const vector<Sample>& custom_ranges,
+                                           int32 flags) {
+  CHECK(ValidateCustomRanges(custom_ranges));
+
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    CustomHistogram* tentative_histogram =
+        new CustomHistogram(name, registered_ranges);
+
+    tentative_histogram->SetFlags(flags);
+
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM);
+  return histogram;
+}
+
+HistogramType CustomHistogram::GetHistogramType() const {
+  return CUSTOM_HISTOGRAM;
+}
+
+// static
+vector<Sample> CustomHistogram::ArrayToCustomRanges(
+    const Sample* values, size_t num_values) {
+  vector<Sample> all_values;
+  for (size_t i = 0; i < num_values; ++i) {
+    Sample value = values[i];
+    all_values.push_back(value);
+
+    // Ensure that a guard bucket is added. If we end up with duplicate
+    // values, FactoryGet will take care of removing them.
+    all_values.push_back(value + 1);
+  }
+  return all_values;
+}
+
+CustomHistogram::CustomHistogram(const string& name,
+                                 const BucketRanges* ranges)
+    : Histogram(name,
+                ranges->range(1),
+                ranges->range(ranges->bucket_count() - 1),
+                ranges) {}
+
+bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
+  if (!Histogram::SerializeInfoImpl(pickle))
+    return false;
+
+  // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
+  // write them.
+  for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
+    if (!pickle->WriteInt(bucket_ranges()->range(i)))
+      return false;
+  }
+  return true;
+}
+
+double CustomHistogram::GetBucketSize(Count current, size_t i) const {
+  return 1;
+}
+
+// static
+HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  // First and last ranges are not serialized.
+  vector<Sample> sample_ranges(bucket_count - 1);
+
+  for (size_t i = 0; i < sample_ranges.size(); ++i) {
+    if (!iter->ReadInt(&sample_ranges[i]))
+      return NULL;
+  }
+
+  HistogramBase* histogram = CustomHistogram::FactoryGet(
+      histogram_name, sample_ranges, flags);
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+// static
+bool CustomHistogram::ValidateCustomRanges(
+    const vector<Sample>& custom_ranges) {
+  bool has_valid_range = false;
+  for (size_t i = 0; i < custom_ranges.size(); i++) {
+    Sample sample = custom_ranges[i];
+    if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
+      return false;
+    if (sample != 0)
+      has_valid_range = true;
+  }
+  return has_valid_range;
+}
+
+// static
+BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges(
+      const vector<Sample>& custom_ranges) {
+  // Remove the duplicates in the custom ranges array.
+  vector<int> ranges = custom_ranges;
+  ranges.push_back(0);  // Ensure we have a zero value.
+  ranges.push_back(HistogramBase::kSampleType_MAX);
+  std::sort(ranges.begin(), ranges.end());
+  ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
+
+  BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
+  for (size_t i = 0; i < ranges.size(); i++) {
+    bucket_ranges->set_range(i, ranges[i]);
+  }
+  bucket_ranges->ResetChecksum();
+  return bucket_ranges;
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
new file mode 100644
index 0000000..9ee172e
--- /dev/null
+++ b/base/metrics/histogram.h
@@ -0,0 +1,402 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+
+// It supports calls to accumulate either time intervals (which are processed
+// as integral number of milliseconds), or arbitrary integral units.
+
+// For Histogram(exponential histogram), LinearHistogram and CustomHistogram,
+// the minimum for a declared range is 1 (instead of 0), while the maximum is
+// (HistogramBase::kSampleType_MAX - 1). Currently you can declare histograms
+// with ranges exceeding those limits (e.g. 0 as minimal or
+// HistogramBase::kSampleType_MAX as maximal), but those excesses will be
+// silently clamped to those limits (for backwards compatibility with existing
+// code). Best practice is to not exceed the limits.
+
+// Each use of a histogram with the same name will reference the same underlying
+// data, so it is safe to record to the same histogram from multiple locations
+// in the code. It is a runtime error if all uses of the same histogram do not
+// agree exactly in type, bucket size and range.
+
+// For Histogram and LinearHistogram, the maximum for a declared range should
+// always be larger (not equal) than minimal range. Zero and
+// HistogramBase::kSampleType_MAX are implicitly added as first and last ranges,
+// so the smallest legal bucket_count is 3. However CustomHistogram can have
+// bucket count as 2 (when you give a custom ranges vector containing only 1
+// range).
+// For these 3 kinds of histograms, the max bucket count is always
+// (Histogram::kBucketCount_MAX - 1).
+
+// The buckets layout of class Histogram is exponential. For example, buckets
+// might contain (sequentially) the count of values in the following intervals:
+// [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
+// That bucket allocation would actually result from construction of a histogram
+// for values between 1 and 64, with 8 buckets, such as:
+// Histogram count("some name", 1, 64, 8);
+// Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
+// are also counted by the constructor in the user supplied "bucket_count"
+// argument.
+// The above example has an exponential ratio of 2 (doubling the bucket width
+// in each consecutive bucket.  The Histogram class automatically calculates
+// the smallest ratio that it can use to construct the number of buckets
+// selected in the constructor.  An another example, if you had 50 buckets,
+// and millisecond time values from 1 to 10000, then the ratio between
+// consecutive bucket widths will be approximately somewhere around the 50th
+// root of 10000.  This approach provides very fine grain (narrow) buckets
+// at the low end of the histogram scale, but allows the histogram to cover a
+// gigantic range with the addition of very few buckets.
+
+// Usually we use macros to define and use a histogram, which are defined in
+// base/metrics/histogram_macros.h. Note: Callers should include that header
+// directly if they only access the histogram APIs through macros.
+//
+// Macros use a pattern involving a function static variable, that is a pointer
+// to a histogram.  This static is explicitly initialized on any thread
+// that detects a uninitialized (NULL) pointer.  The potentially racy
+// initialization is not a problem as it is always set to point to the same
+// value (i.e., the FactoryGet always returns the same value).  FactoryGet
+// is also completely thread safe, which results in a completely thread safe,
+// and relatively fast, set of counters.  To avoid races at shutdown, the static
+// pointer is NOT deleted, and we leak the histograms at process termination.
+
+#ifndef BASE_METRICS_HISTOGRAM_H_
+#define BASE_METRICS_HISTOGRAM_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_base.h"
+// TODO(asvitkine): Migrate callers to to include this directly and remove this.
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/time/time.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace base {
+
+class BooleanHistogram;
+class CustomHistogram;
+class Histogram;
+class LinearHistogram;
+class SampleVector;
+
+class BASE_EXPORT Histogram : public HistogramBase {
+ public:
+  // Initialize maximum number of buckets in histograms as 16,384.
+  static const size_t kBucketCount_MAX;
+
+  typedef std::vector<Count> Counts;
+
+  //----------------------------------------------------------------------------
+  // For a valid histogram, input should follow these restrictions:
+  // minimum > 0 (if a minimum below 1 is specified, it will implicitly be
+  //              normalized up to 1)
+  // maximum > minimum
+  // buckets > 2 [minimum buckets needed: underflow, overflow and the range]
+  // Additionally,
+  // buckets <= (maximum - minimum + 2) - this is to ensure that we don't have
+  // more buckets than the range of numbers; having more buckets than 1 per
+  // value in the range would be nonsensical.
+  static HistogramBase* FactoryGet(const std::string& name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const std::string& name,
+                                       base::TimeDelta minimum,
+                                       base::TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     BucketRanges* ranges);
+
+  // This constant if for FindCorruption. Since snapshots of histograms are
+  // taken asynchronously relative to sampling, and our counting code currently
+  // does not prevent race conditions, it is pretty likely that we'll catch a
+  // redundant count that doesn't match the sample count.  We allow for a
+  // certain amount of slop before flagging this as an inconsistency. Even with
+  // an inconsistency, we'll snapshot it again (for UMA in about a half hour),
+  // so we'll eventually get the data, if it was not the result of a corruption.
+  static const int kCommonRaceBasedCountMismatch;
+
+  // Check to see if bucket ranges, counts and tallies in the snapshot are
+  // consistent with the bucket ranges and checksums in our histogram.  This can
+  // produce a false-alarm if a race occurred in the reading of the data during
+  // a SnapShot process, but should otherwise be false at all times (unless we
+  // have memory over-writes, or DRAM failures).
+  int FindCorruption(const HistogramSamples& samples) const override;
+
+  //----------------------------------------------------------------------------
+  // Accessors for factory construction, serialization and testing.
+  //----------------------------------------------------------------------------
+  Sample declared_min() const { return declared_min_; }
+  Sample declared_max() const { return declared_max_; }
+  virtual Sample ranges(size_t i) const;
+  virtual size_t bucket_count() const;
+  const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
+
+  // This function validates histogram construction arguments. It returns false
+  // if some of the arguments are totally bad.
+  // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
+  // converts it to good input: 1.
+  // TODO(kaiwang): Be more restrict and return false for any bad input, and
+  // make this a readonly validating function.
+  static bool InspectConstructionArguments(const std::string& name,
+                                           Sample* minimum,
+                                           Sample* maximum,
+                                           size_t* bucket_count);
+
+  // HistogramBase implementation:
+  HistogramType GetHistogramType() const override;
+  bool HasConstructionArguments(Sample expected_minimum,
+                                Sample expected_maximum,
+                                size_t expected_bucket_count) const override;
+  void Add(Sample value) override;
+  scoped_ptr<HistogramSamples> SnapshotSamples() const override;
+  void AddSamples(const HistogramSamples& samples) override;
+  bool AddSamplesFromPickle(PickleIterator* iter) override;
+  void WriteHTMLGraph(std::string* output) const override;
+  void WriteAscii(std::string* output) const override;
+
+ protected:
+  // |ranges| should contain the underflow and overflow buckets. See top
+  // comments for example.
+  Histogram(const std::string& name,
+            Sample minimum,
+            Sample maximum,
+            const BucketRanges* ranges);
+
+  ~Histogram() override;
+
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(Pickle* pickle) const override;
+
+  // Method to override to skip the display of the i'th bucket if it's empty.
+  virtual bool PrintEmptyBucket(size_t index) const;
+
+  // Get normalized size, relative to the ranges(i).
+  virtual double GetBucketSize(Count current, size_t i) const;
+
+  // Return a string description of what goes in a given bucket.
+  // Most commonly this is the numeric value, but in derived classes it may
+  // be a name (or string description) given to the bucket.
+  virtual const std::string GetAsciiBucketRange(size_t it) const;
+
+ private:
+  // Allow tests to corrupt our innards for testing purposes.
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);
+
+  friend class StatisticsRecorder;  // To allow it to delete duplicates.
+  friend class StatisticsRecorderTest;
+
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
+  // Implementation of SnapshotSamples function.
+  scoped_ptr<SampleVector> SnapshotSampleVector() const;
+
+  //----------------------------------------------------------------------------
+  // Helpers for emitting Ascii graphic.  Each method appends data to output.
+
+  void WriteAsciiImpl(bool graph_it,
+                      const std::string& newline,
+                      std::string* output) const;
+
+  // Find out how large (graphically) the largest bucket will appear to be.
+  double GetPeakBucketSize(const SampleVector& samples) const;
+
+  // Write a common header message describing this histogram.
+  void WriteAsciiHeader(const SampleVector& samples,
+                        Count sample_count,
+                        std::string* output) const;
+
+  // Write information about previous, current, and next buckets.
+  // Information such as cumulative percentage, etc.
+  void WriteAsciiBucketContext(const int64 past, const Count current,
+                               const int64 remaining, const size_t i,
+                               std::string* output) const;
+
+  // WriteJSON calls these.
+  void GetParameters(DictionaryValue* params) const override;
+
+  void GetCountAndBucketData(Count* count,
+                             int64* sum,
+                             ListValue* buckets) const override;
+
+  // Does not own this object. Should get from StatisticsRecorder.
+  const BucketRanges* bucket_ranges_;
+
+  Sample declared_min_;  // Less than this goes into the first bucket.
+  Sample declared_max_;  // Over this goes into the last bucket.
+
+  // Finally, provide the state that changes with the addition of each new
+  // sample.
+  scoped_ptr<SampleVector> samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(Histogram);
+};
+
+//------------------------------------------------------------------------------
+
+// LinearHistogram is a more traditional histogram, with evenly spaced
+// buckets.
+class BASE_EXPORT LinearHistogram : public Histogram {
+ public:
+  ~LinearHistogram() override;
+
+  /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
+     default underflow bucket. */
+  static HistogramBase* FactoryGet(const std::string& name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const std::string& name,
+                                       TimeDelta minimum,
+                                       TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
+  struct DescriptionPair {
+    Sample sample;
+    const char* description;  // Null means end of a list of pairs.
+  };
+
+  // Create a LinearHistogram and store a list of number/text values for use in
+  // writing the histogram graph.
+  // |descriptions| can be NULL, which means no special descriptions to set. If
+  // it's not NULL, the last element in the array must has a NULL in its
+  // "description" field.
+  static HistogramBase* FactoryGetWithRangeDescription(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      size_t bucket_count,
+      int32 flags,
+      const DescriptionPair descriptions[]);
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     BucketRanges* ranges);
+
+  // Overridden from Histogram:
+  HistogramType GetHistogramType() const override;
+
+ protected:
+  LinearHistogram(const std::string& name,
+                  Sample minimum,
+                  Sample maximum,
+                  const BucketRanges* ranges);
+
+  double GetBucketSize(Count current, size_t i) const override;
+
+  // If we have a description for a bucket, then return that.  Otherwise
+  // let parent class provide a (numeric) description.
+  const std::string GetAsciiBucketRange(size_t i) const override;
+
+  // Skip printing of name for numeric range if we have a name (and if this is
+  // an empty bucket).
+  bool PrintEmptyBucket(size_t index) const override;
+
+ private:
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
+  // For some ranges, we store a printable description of a bucket range.
+  // If there is no description, then GetAsciiBucketRange() uses parent class
+  // to provide a description.
+  typedef std::map<Sample, std::string> BucketDescriptionMap;
+  BucketDescriptionMap bucket_description_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
+};
+
+//------------------------------------------------------------------------------
+
+// BooleanHistogram is a histogram for booleans.
+class BASE_EXPORT BooleanHistogram : public LinearHistogram {
+ public:
+  static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+
+  HistogramType GetHistogramType() const override;
+
+ private:
+  BooleanHistogram(const std::string& name, const BucketRanges* ranges);
+
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
+  DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
+};
+
+//------------------------------------------------------------------------------
+
+// CustomHistogram is a histogram for a set of custom integers.
+class BASE_EXPORT CustomHistogram : public Histogram {
+ public:
+  // |custom_ranges| contains a vector of limits on ranges. Each limit should be
+  // > 0 and < kSampleType_MAX. (Currently 0 is still accepted for backward
+  // compatibility). The limits can be unordered or contain duplication, but
+  // client should not depend on this.
+  static HistogramBase* FactoryGet(const std::string& name,
+                                   const std::vector<Sample>& custom_ranges,
+                                   int32 flags);
+
+  // Overridden from Histogram:
+  HistogramType GetHistogramType() const override;
+
+  // Helper method for transforming an array of valid enumeration values
+  // to the std::vector<int> expected by UMA_HISTOGRAM_CUSTOM_ENUMERATION.
+  // This function ensures that a guard bucket exists right after any
+  // valid sample value (unless the next higher sample is also a valid value),
+  // so that invalid samples never fall into the same bucket as valid samples.
+  // TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
+  static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
+                                                 size_t num_values);
+ protected:
+  CustomHistogram(const std::string& name,
+                  const BucketRanges* ranges);
+
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(Pickle* pickle) const override;
+
+  double GetBucketSize(Count current, size_t i) const override;
+
+ private:
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
+  static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
+  static BucketRanges* CreateBucketRangesFromCustomRanges(
+      const std::vector<Sample>& custom_ranges);
+
+  DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_H_
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
new file mode 100644
index 0000000..de34c79
--- /dev/null
+++ b/base/metrics/histogram_base.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_base.h"
+
+#include <climits>
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/pickle.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+
+namespace base {
+
+std::string HistogramTypeToString(HistogramType type) {
+  switch (type) {
+    case HISTOGRAM:
+      return "HISTOGRAM";
+    case LINEAR_HISTOGRAM:
+      return "LINEAR_HISTOGRAM";
+    case BOOLEAN_HISTOGRAM:
+      return "BOOLEAN_HISTOGRAM";
+    case CUSTOM_HISTOGRAM:
+      return "CUSTOM_HISTOGRAM";
+    case SPARSE_HISTOGRAM:
+      return "SPARSE_HISTOGRAM";
+    default:
+      NOTREACHED();
+  }
+  return "UNKNOWN";
+}
+
+HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) {
+  int type;
+  if (!iter->ReadInt(&type))
+    return NULL;
+
+  switch (type) {
+    case HISTOGRAM:
+      return Histogram::DeserializeInfoImpl(iter);
+    case LINEAR_HISTOGRAM:
+      return LinearHistogram::DeserializeInfoImpl(iter);
+    case BOOLEAN_HISTOGRAM:
+      return BooleanHistogram::DeserializeInfoImpl(iter);
+    case CUSTOM_HISTOGRAM:
+      return CustomHistogram::DeserializeInfoImpl(iter);
+    case SPARSE_HISTOGRAM:
+      return SparseHistogram::DeserializeInfoImpl(iter);
+    default:
+      return NULL;
+  }
+}
+
+const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
+
+HistogramBase::HistogramBase(const std::string& name)
+    : histogram_name_(name),
+      flags_(kNoFlags) {}
+
+HistogramBase::~HistogramBase() {}
+
+void HistogramBase::CheckName(const StringPiece& name) const {
+  DCHECK_EQ(histogram_name(), name);
+}
+
+void HistogramBase::SetFlags(int32 flags) {
+  flags_ |= flags;
+}
+
+void HistogramBase::ClearFlags(int32 flags) {
+  flags_ &= ~flags;
+}
+
+void HistogramBase::AddTime(const TimeDelta& time) {
+  Add(static_cast<Sample>(time.InMilliseconds()));
+}
+
+void HistogramBase::AddBoolean(bool value) {
+  Add(value ? 1 : 0);
+}
+
+bool HistogramBase::SerializeInfo(Pickle* pickle) const {
+  if (!pickle->WriteInt(GetHistogramType()))
+    return false;
+  return SerializeInfoImpl(pickle);
+}
+
+int HistogramBase::FindCorruption(const HistogramSamples& samples) const {
+  // Not supported by default.
+  return NO_INCONSISTENCIES;
+}
+
+void HistogramBase::WriteJSON(std::string* output) const {
+  Count count;
+  int64 sum;
+  scoped_ptr<ListValue> buckets(new ListValue());
+  GetCountAndBucketData(&count, &sum, buckets.get());
+  scoped_ptr<DictionaryValue> parameters(new DictionaryValue());
+  GetParameters(parameters.get());
+
+  JSONStringValueSerializer serializer(output);
+  DictionaryValue root;
+  root.SetString("name", histogram_name());
+  root.SetInteger("count", count);
+  root.SetDouble("sum", static_cast<double>(sum));
+  root.SetInteger("flags", flags());
+  root.Set("params", parameters.Pass());
+  root.Set("buckets", buckets.Pass());
+  root.SetInteger("pid", GetCurrentProcId());
+  serializer.Serialize(root);
+}
+
+void HistogramBase::WriteAsciiBucketGraph(double current_size,
+                                          double max_size,
+                                          std::string* output) const {
+  const int k_line_length = 72;  // Maximal horizontal width of graph.
+  int x_count = static_cast<int>(k_line_length * (current_size / max_size)
+                                 + 0.5);
+  int x_remainder = k_line_length - x_count;
+
+  while (0 < x_count--)
+    output->append("-");
+  output->append("O");
+  while (0 < x_remainder--)
+    output->append(" ");
+}
+
+const std::string HistogramBase::GetSimpleAsciiBucketRange(
+    Sample sample) const {
+  std::string result;
+  if (kHexRangePrintingFlag & flags())
+    StringAppendF(&result, "%#x", sample);
+  else
+    StringAppendF(&result, "%d", sample);
+  return result;
+}
+
+void HistogramBase::WriteAsciiBucketValue(Count current,
+                                          double scaled_sum,
+                                          std::string* output) const {
+  StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
new file mode 100644
index 0000000..c24df24
--- /dev/null
+++ b/base/metrics/histogram_base.h
@@ -0,0 +1,185 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_BASE_H_
+#define BASE_METRICS_HISTOGRAM_BASE_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace base {
+
+class DictionaryValue;
+class HistogramBase;
+class HistogramSamples;
+class ListValue;
+
+////////////////////////////////////////////////////////////////////////////////
+// These enums are used to facilitate deserialization of histograms from other
+// processes into the browser. If you create another class that inherits from
+// HistogramBase, add new histogram types and names below.
+
+enum BASE_EXPORT HistogramType {
+  HISTOGRAM,
+  LINEAR_HISTOGRAM,
+  BOOLEAN_HISTOGRAM,
+  CUSTOM_HISTOGRAM,
+  SPARSE_HISTOGRAM,
+};
+
+std::string HistogramTypeToString(HistogramType type);
+
+// Create or find existing histogram that matches the pickled info.
+// Returns NULL if the pickled data has problems.
+BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+    PickleIterator* iter);
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BASE_EXPORT HistogramBase {
+ public:
+  typedef int32_t Sample;                // Used for samples.
+  typedef subtle::Atomic32 AtomicCount;  // Used to count samples.
+  typedef int32_t Count;  // Used to manipulate counts in temporaries.
+
+  static const Sample kSampleType_MAX;  // INT_MAX
+
+  enum Flags {
+    kNoFlags = 0,
+
+    // Histogram should be UMA uploaded.
+    kUmaTargetedHistogramFlag = 0x1,
+
+    // Indicates that this is a stability histogram. This flag exists to specify
+    // which histograms should be included in the initial stability log. Please
+    // refer to |MetricsService::PrepareInitialStabilityLog|.
+    kUmaStabilityHistogramFlag = kUmaTargetedHistogramFlag | 0x2,
+
+    // Indicates that the histogram was pickled to be sent across an IPC
+    // Channel. If we observe this flag on a histogram being aggregated into
+    // after IPC, then we are running in a single process mode, and the
+    // aggregation should not take place (as we would be aggregating back into
+    // the source histogram!).
+    kIPCSerializationSourceFlag = 0x10,
+
+    // Only for Histogram and its sub classes: fancy bucket-naming support.
+    kHexRangePrintingFlag = 0x8000,
+  };
+
+  // Histogram data inconsistency types.
+  enum Inconsistency {
+    NO_INCONSISTENCIES = 0x0,
+    RANGE_CHECKSUM_ERROR = 0x1,
+    BUCKET_ORDER_ERROR = 0x2,
+    COUNT_HIGH_ERROR = 0x4,
+    COUNT_LOW_ERROR = 0x8,
+
+    NEVER_EXCEEDED_VALUE = 0x10
+  };
+
+  explicit HistogramBase(const std::string& name);
+  virtual ~HistogramBase();
+
+  std::string histogram_name() const { return histogram_name_; }
+
+  // Comapres |name| to the histogram name and triggers a DCHECK if they do not
+  // match. This is a helper function used by histogram macros, which results in
+  // in more compact machine code being generated by the macros.
+  void CheckName(const StringPiece& name) const;
+
+  // Operations with Flags enum.
+  int32_t flags() const { return flags_; }
+  void SetFlags(int32_t flags);
+  void ClearFlags(int32_t flags);
+
+  virtual HistogramType GetHistogramType() const = 0;
+
+  // Whether the histogram has construction arguments as parameters specified.
+  // For histograms that don't have the concept of minimum, maximum or
+  // bucket_count, this function always returns false.
+  virtual bool HasConstructionArguments(Sample expected_minimum,
+                                        Sample expected_maximum,
+                                        size_t expected_bucket_count) const = 0;
+
+  virtual void Add(Sample value) = 0;
+
+  // 2 convenient functions that call Add(Sample).
+  void AddTime(const TimeDelta& time);
+  void AddBoolean(bool value);
+
+  virtual void AddSamples(const HistogramSamples& samples) = 0;
+  virtual bool AddSamplesFromPickle(PickleIterator* iter) = 0;
+
+  // Serialize the histogram info into |pickle|.
+  // Note: This only serializes the construction arguments of the histogram, but
+  // does not serialize the samples.
+  bool SerializeInfo(Pickle* pickle) const;
+
+  // Try to find out data corruption from histogram and the samples.
+  // The returned value is a combination of Inconsistency enum.
+  virtual int FindCorruption(const HistogramSamples& samples) const;
+
+  // Snapshot the current complete set of sample data.
+  // Override with atomic/locked snapshot if needed.
+  virtual scoped_ptr<HistogramSamples> SnapshotSamples() const = 0;
+
+  // The following methods provide graphical histogram displays.
+  virtual void WriteHTMLGraph(std::string* output) const = 0;
+  virtual void WriteAscii(std::string* output) const = 0;
+
+  // Produce a JSON representation of the histogram. This is implemented with
+  // the help of GetParameters and GetCountAndBucketData; overwrite them to
+  // customize the output.
+  void WriteJSON(std::string* output) const;
+
+ protected:
+  // Subclasses should implement this function to make SerializeInfo work.
+  virtual bool SerializeInfoImpl(Pickle* pickle) const = 0;
+
+  // Writes information about the construction parameters in |params|.
+  virtual void GetParameters(DictionaryValue* params) const = 0;
+
+  // Writes information about the current (non-empty) buckets and their sample
+  // counts to |buckets|, the total sample count to |count| and the total sum
+  // to |sum|.
+  virtual void GetCountAndBucketData(Count* count,
+                                     int64* sum,
+                                     ListValue* buckets) const = 0;
+
+  //// Produce actual graph (set of blank vs non blank char's) for a bucket.
+  void WriteAsciiBucketGraph(double current_size,
+                             double max_size,
+                             std::string* output) const;
+
+  // Return a string description of what goes in a given bucket.
+  const std::string GetSimpleAsciiBucketRange(Sample sample) const;
+
+  // Write textual description of the bucket contents (relative to histogram).
+  // Output is the count in the buckets, as well as the percentage.
+  void WriteAsciiBucketValue(Count current,
+                             double scaled_sum,
+                             std::string* output) const;
+
+ private:
+  const std::string histogram_name_;
+  int32_t flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramBase);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_BASE_H_
diff --git a/base/metrics/histogram_base_unittest.cc b/base/metrics/histogram_base_unittest.cc
new file mode 100644
index 0000000..2d6b6df
--- /dev/null
+++ b/base/metrics/histogram_base_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class HistogramBaseTest : public testing::Test {
+ protected:
+  HistogramBaseTest() {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    statistics_recorder_ = NULL;
+    ResetStatisticsRecorder();
+  }
+
+  ~HistogramBaseTest() override { delete statistics_recorder_; }
+
+  void ResetStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+ private:
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(HistogramBaseTest, DeserializeHistogram) {
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10,
+      (HistogramBase::kUmaTargetedHistogramFlag |
+      HistogramBase::kIPCSerializationSourceFlag));
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
+
+  // kIPCSerializationSourceFlag will be cleared.
+  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeLinearHistogram) {
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10,
+      HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) {
+  HistogramBase* histogram = BooleanHistogram::FactoryGet(
+      "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3));
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeCustomHistogram) {
+  std::vector<HistogramBase::Sample> ranges;
+  ranges.push_back(13);
+  ranges.push_back(5);
+  ranges.push_back(9);
+
+  HistogramBase* histogram = CustomHistogram::FactoryGet(
+      "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4));
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeSparseHistogram) {
+  HistogramBase* histogram = SparseHistogram::FactoryGet(
+      "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_delta_serialization.cc b/base/metrics/histogram_delta_serialization.cc
new file mode 100644
index 0000000..e4aad13
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization.cc
@@ -0,0 +1,111 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_delta_serialization.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/pickle.h"
+#include "base/values.h"
+
+namespace base {
+
+namespace {
+
+// Create or find existing histogram and add the samples from pickle.
+// Silently returns when seeing any data problem in the pickle.
+void DeserializeHistogramAndAddSamples(PickleIterator* iter) {
+  HistogramBase* histogram = DeserializeHistogramInfo(iter);
+  if (!histogram)
+    return;
+
+  if (histogram->flags() & HistogramBase::kIPCSerializationSourceFlag) {
+    DVLOG(1) << "Single process mode, histogram observed and not copied: "
+             << histogram->histogram_name();
+    return;
+  }
+  histogram->AddSamplesFromPickle(iter);
+}
+
+}  // namespace
+
+HistogramDeltaSerialization::HistogramDeltaSerialization(
+    const std::string& caller_name)
+    : histogram_snapshot_manager_(this),
+      serialized_deltas_(NULL) {
+  inconsistencies_histogram_ =
+      LinearHistogram::FactoryGet(
+          "Histogram.Inconsistencies" + caller_name, 1,
+          HistogramBase::NEVER_EXCEEDED_VALUE,
+          HistogramBase::NEVER_EXCEEDED_VALUE + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+
+  inconsistencies_unique_histogram_ =
+      LinearHistogram::FactoryGet(
+          "Histogram.Inconsistencies" + caller_name + "Unique", 1,
+          HistogramBase::NEVER_EXCEEDED_VALUE,
+          HistogramBase::NEVER_EXCEEDED_VALUE + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+
+  inconsistent_snapshot_histogram_ =
+      Histogram::FactoryGet(
+          "Histogram.InconsistentSnapshot" + caller_name, 1, 1000000, 50,
+          HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+HistogramDeltaSerialization::~HistogramDeltaSerialization() {
+}
+
+void HistogramDeltaSerialization::PrepareAndSerializeDeltas(
+    std::vector<std::string>* serialized_deltas) {
+  serialized_deltas_ = serialized_deltas;
+  // Note: Before serializing, we set the kIPCSerializationSourceFlag for all
+  // the histograms, so that the receiving process can distinguish them from the
+  // local histograms.
+  histogram_snapshot_manager_.PrepareDeltas(
+      Histogram::kIPCSerializationSourceFlag, Histogram::kNoFlags);
+  serialized_deltas_ = NULL;
+}
+
+// static
+void HistogramDeltaSerialization::DeserializeAndAddSamples(
+    const std::vector<std::string>& serialized_deltas) {
+  for (std::vector<std::string>::const_iterator it = serialized_deltas.begin();
+       it != serialized_deltas.end(); ++it) {
+    Pickle pickle(it->data(), checked_cast<int>(it->size()));
+    PickleIterator iter(pickle);
+    DeserializeHistogramAndAddSamples(&iter);
+  }
+}
+
+void HistogramDeltaSerialization::RecordDelta(
+    const HistogramBase& histogram,
+    const HistogramSamples& snapshot) {
+  DCHECK_NE(0, snapshot.TotalCount());
+
+  Pickle pickle;
+  histogram.SerializeInfo(&pickle);
+  snapshot.Serialize(&pickle);
+  serialized_deltas_->push_back(
+      std::string(static_cast<const char*>(pickle.data()), pickle.size()));
+}
+
+void HistogramDeltaSerialization::InconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  inconsistencies_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::UniqueInconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  inconsistencies_unique_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::InconsistencyDetectedInLoggedCount(
+    int amount) {
+  inconsistent_snapshot_histogram_->Add(std::abs(amount));
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_delta_serialization.h b/base/metrics/histogram_delta_serialization.h
new file mode 100644
index 0000000..a379914
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization.h
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+#define BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+
+namespace base {
+
+class HistogramBase;
+
+// Serializes and restores histograms deltas.
+class BASE_EXPORT HistogramDeltaSerialization : public HistogramFlattener {
+ public:
+  // |caller_name| is string used in histograms for counting inconsistencies.
+  explicit HistogramDeltaSerialization(const std::string& caller_name);
+  ~HistogramDeltaSerialization() override;
+
+  // Computes deltas in histogram bucket counts relative to the previous call to
+  // this method. Stores the deltas in serialized form into |serialized_deltas|.
+  // If |serialized_deltas| is NULL, no data is serialized, though the next call
+  // will compute the deltas relative to this one.
+  void PrepareAndSerializeDeltas(std::vector<std::string>* serialized_deltas);
+
+  // Deserialize deltas and add samples to corresponding histograms, creating
+  // them if necessary. Silently ignores errors in |serialized_deltas|.
+  static void DeserializeAndAddSamples(
+      const std::vector<std::string>& serialized_deltas);
+
+ private:
+  // HistogramFlattener implementation.
+  void RecordDelta(const HistogramBase& histogram,
+                   const HistogramSamples& snapshot) override;
+  void InconsistencyDetected(HistogramBase::Inconsistency problem) override;
+  void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) override;
+  void InconsistencyDetectedInLoggedCount(int amount) override;
+
+  // Calculates deltas in histogram counters.
+  HistogramSnapshotManager histogram_snapshot_manager_;
+
+  // Output buffer for serialized deltas.
+  std::vector<std::string>* serialized_deltas_;
+
+  // Histograms to count inconsistencies in snapshots.
+  HistogramBase* inconsistencies_histogram_;
+  HistogramBase* inconsistencies_unique_histogram_;
+  HistogramBase* inconsistent_snapshot_histogram_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramDeltaSerialization);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
diff --git a/base/metrics/histogram_delta_serialization_unittest.cc b/base/metrics/histogram_delta_serialization_unittest.cc
new file mode 100644
index 0000000..b53520c
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_delta_serialization.h"
+
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(HistogramDeltaSerializationTest, DeserializeHistogramAndAddSamples) {
+  StatisticsRecorder statistic_recorder;
+  HistogramDeltaSerialization serializer("HistogramDeltaSerializationTest");
+  std::vector<std::string> deltas;
+  // Nothing was changed yet.
+  serializer.PrepareAndSerializeDeltas(&deltas);
+  EXPECT_TRUE(deltas.empty());
+
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag);
+  histogram->Add(1);
+  histogram->Add(10);
+  histogram->Add(100);
+  histogram->Add(1000);
+
+  serializer.PrepareAndSerializeDeltas(&deltas);
+  EXPECT_FALSE(deltas.empty());
+
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  // The histogram has kIPCSerializationSourceFlag. So samples will be ignored.
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot->GetCount(1));
+  EXPECT_EQ(1, snapshot->GetCount(10));
+  EXPECT_EQ(1, snapshot->GetCount(100));
+  EXPECT_EQ(1, snapshot->GetCount(1000));
+
+  // Clear kIPCSerializationSourceFlag to emulate multi-process usage.
+  histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag);
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(2, snapshot2->GetCount(1));
+  EXPECT_EQ(2, snapshot2->GetCount(10));
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(2, snapshot2->GetCount(1000));
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_flattener.h b/base/metrics/histogram_flattener.h
new file mode 100644
index 0000000..ca05a4f
--- /dev/null
+++ b/base/metrics/histogram_flattener.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_FLATTENER_H_
+#define BASE_METRICS_HISTOGRAM_FLATTENER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram.h"
+
+namespace base {
+
+class HistogramSamples;
+
+// HistogramFlattener is an interface used by HistogramSnapshotManager, which
+// handles the logistics of gathering up available histograms for recording.
+// The implementors handle the exact lower level recording mechanism, or
+// error report mechanism.
+class BASE_EXPORT HistogramFlattener {
+ public:
+  virtual void RecordDelta(const HistogramBase& histogram,
+                           const HistogramSamples& snapshot) = 0;
+
+  // Will be called each time a type of Inconsistency is seen on a histogram,
+  // during inspections done internally in HistogramSnapshotManager class.
+  virtual void InconsistencyDetected(HistogramBase::Inconsistency problem) = 0;
+
+  // Will be called when a type of Inconsistency is seen for the first time on
+  // a histogram.
+  virtual void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) = 0;
+
+  // Will be called when the total logged sample count of a histogram
+  // differs from the sum of logged sample count in all the buckets.  The
+  // argument |amount| is the non-zero discrepancy.
+  virtual void InconsistencyDetectedInLoggedCount(int amount) = 0;
+
+ protected:
+  HistogramFlattener() {}
+  virtual ~HistogramFlattener() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HistogramFlattener);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_FLATTENER_H_
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
new file mode 100644
index 0000000..2aee1a5
--- /dev/null
+++ b/base/metrics/histogram_macros.h
@@ -0,0 +1,264 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_MACROS_H_
+#define BASE_METRICS_HISTOGRAM_MACROS_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+//------------------------------------------------------------------------------
+// Histograms are often put in areas where they are called many many times, and
+// performance is critical.  As a result, they are designed to have a very low
+// recurring cost of executing (adding additional samples).  Toward that end,
+// the macros declare a static pointer to the histogram in question, and only
+// take a "slow path" to construct (or find) the histogram on the first run
+// through the macro.  We leak the histograms at shutdown time so that we don't
+// have to validate using the pointers at any time during the running of the
+// process.
+
+// The following code is generally what a thread-safe static pointer
+// initialization looks like for a histogram (after a macro is expanded).  This
+// sample is an expansion (with comments) of the code for
+// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
+
+/*
+  do {
+    // The pointer's presence indicates the initialization is complete.
+    // Initialization is idempotent, so it can safely be atomically repeated.
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+
+    // Acquire_Load() ensures that we acquire visibility to the pointed-to data
+    // in the histogram.
+    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
+        base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+
+    if (!histogram_pointer) {
+      // This is the slow path, which will construct OR find the matching
+      // histogram.  FactoryGet includes locks on a global histogram name map
+      // and is completely thread safe.
+      histogram_pointer = base::Histogram::FactoryGet(
+          name, min, max, bucket_count, base::HistogramBase::kNoFlags);
+
+      // Use Release_Store to ensure that the histogram data is made available
+      // globally before we make the pointer visible.
+      // Several threads may perform this store, but the same value will be
+      // stored in all cases (for a given named/spec'ed histogram).
+      // We could do this without any barrier, since FactoryGet entered and
+      // exited a lock after construction, but this barrier makes things clear.
+      base::subtle::Release_Store(&atomic_histogram_pointer,
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+    }
+
+    // Ensure calling contract is upheld, and the name does NOT vary.
+    DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
+
+    histogram_pointer->Add(sample);
+  } while (0);
+*/
+
+// The above pattern is repeated in several macros.  The only elements that
+// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
+// of which FactoryGet method to use.  The different FactoryGet methods have
+// various argument lists, so the function with its argument list is provided as
+// a macro argument here.  The name is only used in a DCHECK, to assure that
+// callers don't try to vary the name of the histogram (which would tend to be
+// ignored by the one-time initialization of the histogtram_pointer).
+#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name,           \
+                                       histogram_add_method_invocation,   \
+                                       histogram_factory_get_invocation)  \
+  do {                                                                    \
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0;         \
+    base::HistogramBase* histogram_pointer(                               \
+        reinterpret_cast<base::HistogramBase*>(                           \
+            base::subtle::Acquire_Load(&atomic_histogram_pointer)));      \
+    if (!histogram_pointer) {                                             \
+      histogram_pointer = histogram_factory_get_invocation;               \
+      base::subtle::Release_Store(                                        \
+          &atomic_histogram_pointer,                                      \
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
+    }                                                                     \
+    if (DCHECK_IS_ON())                                                   \
+      histogram_pointer->CheckName(constant_histogram_name);              \
+    histogram_pointer->histogram_add_method_invocation;                   \
+  } while (0)
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// The first four macros use 50 buckets.
+
+#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+// For folks that need real specific times, use this to select a precise range
+// of times you want plotted, and the number of buckets you want used.
+#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+                                        base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
+    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
+    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
+#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+                                    base::HistogramBase::kNoFlags))
+
+// This is a helper macro used by other macros and shouldn't be used directly.
+#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
+            flag))
+
+#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
+
+// Support histograming of an enumerated value.  The samples should always be
+// strictly less than |boundary_value| -- this prevents you from running into
+// problems down the line if you add additional buckets to the histogram.  Note
+// also that, despite explicitly setting the minimum bucket value to |1| below,
+// it is fine for enumerated histograms to be 0-indexed -- this is because
+// enumerated histograms should never have underflow.
+#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+            boundary_value + 1, base::HistogramBase::kNoFlags))
+
+// Support histograming of an enumerated value. Samples should be one of the
+// std::vector<int> list provided via |custom_ranges|. See comments above
+// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
+// You can use the helper function CustomHistogram::ArrayToCustomRanges to
+// transform a C-style array of valid sample values to a std::vector<int>.
+#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+                                          base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+//------------------------------------------------------------------------------
+// The following macros provide typical usage scenarios for callers that wish
+// to record histogram data, and have the data submitted/uploaded via UMA.
+// Not all systems support such UMA, but if they do, the following macros
+// should work with the service.
+
+#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(10), \
+    base::TimeDelta::FromMinutes(3), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds.
+#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromHours(1), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds and
+// you want 100 buckets.
+#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromHours(1), 100)
+
+#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 100, 50)
+
+#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 10000, 50)
+
+#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000, 50)
+
+#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// The samples should always be strictly less than |boundary_value|.  For more
+// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
+#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+        base::HistogramBase::kUmaTargetedHistogramFlag)
+
+// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
+// histograms.  Use this if recording a histogram that should be part of the
+// initial stability log.
+#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+        base::HistogramBase::kUmaStabilityHistogramFlag)
+
+#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// Scoped class which logs its time on this earth as a UMA statistic. This is
+// recommended for when you want a histogram which measures the time it takes
+// for a method to execute. This measures up to 10 seconds.
+#define SCOPED_UMA_HISTOGRAM_TIMER(name) \
+  SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, false, __COUNTER__)
+
+// Similar scoped histogram timer, but this uses UMA_HISTOGRAM_LONG_TIMES_100,
+// which measures up to an hour, and uses 100 buckets. This is more expensive
+// to store, so only use if this often takes >10 seconds.
+#define SCOPED_UMA_HISTOGRAM_LONG_TIMER(name) \
+  SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, true, __COUNTER__)
+
+// This nested macro is necessary to expand __COUNTER__ to an actual value.
+#define SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, is_long, key) \
+  SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(name, is_long, key)
+
+#define SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \
+  class ScopedHistogramTimer##key { \
+   public: \
+    ScopedHistogramTimer##key() : constructed_(base::TimeTicks::Now()) {} \
+    ~ScopedHistogramTimer##key() { \
+      base::TimeDelta elapsed = base::TimeTicks::Now() - constructed_; \
+      if (is_long) { \
+        UMA_HISTOGRAM_LONG_TIMES_100(name, elapsed); \
+      } else { \
+        UMA_HISTOGRAM_TIMES(name, elapsed); \
+      } \
+    } \
+   private: \
+    base::TimeTicks constructed_; \
+  } scoped_histogram_timer_##key
+
+#endif  // BASE_METRICS_HISTOGRAM_MACROS_H_
diff --git a/base/metrics/histogram_macros_unittest.cc b/base/metrics/histogram_macros_unittest.cc
new file mode 100644
index 0000000..c599161
--- /dev/null
+++ b/base/metrics/histogram_macros_unittest.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedHistogramTimer, TwoTimersOneScope) {
+  SCOPED_UMA_HISTOGRAM_TIMER("TestTimer0");
+  SCOPED_UMA_HISTOGRAM_TIMER("TestTimer1");
+  SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer0");
+  SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer1");
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc
new file mode 100644
index 0000000..f5e03b9
--- /dev/null
+++ b/base/metrics/histogram_samples.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_samples.h"
+
+#include "base/compiler_specific.h"
+#include "base/pickle.h"
+
+namespace base {
+
+namespace {
+
+class SampleCountPickleIterator : public SampleCountIterator {
+ public:
+  explicit SampleCountPickleIterator(PickleIterator* iter);
+
+  bool Done() const override;
+  void Next() override;
+  void Get(HistogramBase::Sample* min,
+           HistogramBase::Sample* max,
+           HistogramBase::Count* count) const override;
+
+ private:
+  PickleIterator* const iter_;
+
+  HistogramBase::Sample min_;
+  HistogramBase::Sample max_;
+  HistogramBase::Count count_;
+  bool is_done_;
+};
+
+SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter)
+    : iter_(iter),
+      is_done_(false) {
+  Next();
+}
+
+bool SampleCountPickleIterator::Done() const {
+  return is_done_;
+}
+
+void SampleCountPickleIterator::Next() {
+  DCHECK(!Done());
+  if (!iter_->ReadInt(&min_) ||
+      !iter_->ReadInt(&max_) ||
+      !iter_->ReadInt(&count_))
+    is_done_ = true;
+}
+
+void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
+                                    HistogramBase::Sample* max,
+                                    HistogramBase::Count* count) const {
+  DCHECK(!Done());
+  *min = min_;
+  *max = max_;
+  *count = count_;
+}
+
+}  // namespace
+
+HistogramSamples::HistogramSamples() : sum_(0), redundant_count_(0) {}
+
+HistogramSamples::~HistogramSamples() {}
+
+void HistogramSamples::Add(const HistogramSamples& other) {
+  sum_ += other.sum();
+  HistogramBase::Count old_redundant_count =
+      subtle::NoBarrier_Load(&redundant_count_);
+  subtle::NoBarrier_Store(&redundant_count_,
+      old_redundant_count + other.redundant_count());
+  bool success = AddSubtractImpl(other.Iterator().get(), ADD);
+  DCHECK(success);
+}
+
+bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
+  int64 sum;
+  HistogramBase::Count redundant_count;
+
+  if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
+    return false;
+  sum_ += sum;
+  HistogramBase::Count old_redundant_count =
+      subtle::NoBarrier_Load(&redundant_count_);
+  subtle::NoBarrier_Store(&redundant_count_,
+                          old_redundant_count + redundant_count);
+
+  SampleCountPickleIterator pickle_iter(iter);
+  return AddSubtractImpl(&pickle_iter, ADD);
+}
+
+void HistogramSamples::Subtract(const HistogramSamples& other) {
+  sum_ -= other.sum();
+  HistogramBase::Count old_redundant_count =
+      subtle::NoBarrier_Load(&redundant_count_);
+  subtle::NoBarrier_Store(&redundant_count_,
+                          old_redundant_count - other.redundant_count());
+  bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
+  DCHECK(success);
+}
+
+bool HistogramSamples::Serialize(Pickle* pickle) const {
+  if (!pickle->WriteInt64(sum_) ||
+      !pickle->WriteInt(subtle::NoBarrier_Load(&redundant_count_)))
+    return false;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  for (scoped_ptr<SampleCountIterator> it = Iterator();
+       !it->Done();
+       it->Next()) {
+    it->Get(&min, &max, &count);
+    if (!pickle->WriteInt(min) ||
+        !pickle->WriteInt(max) ||
+        !pickle->WriteInt(count))
+      return false;
+  }
+  return true;
+}
+
+void HistogramSamples::IncreaseSum(int64 diff) {
+  sum_ += diff;
+}
+
+void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
+  subtle::NoBarrier_Store(&redundant_count_,
+      subtle::NoBarrier_Load(&redundant_count_) + diff);
+}
+
+SampleCountIterator::~SampleCountIterator() {}
+
+bool SampleCountIterator::GetBucketIndex(size_t* index) const {
+  DCHECK(!Done());
+  return false;
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
new file mode 100644
index 0000000..c4c0a98
--- /dev/null
+++ b/base/metrics/histogram_samples.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
+#define BASE_METRICS_HISTOGRAM_SAMPLES_H_
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram_base.h"
+#include "base/memory/scoped_ptr.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace base {
+
+class SampleCountIterator;
+
+// HistogramSamples is a container storing all samples of a histogram.
+class BASE_EXPORT HistogramSamples {
+ public:
+  HistogramSamples();
+  virtual ~HistogramSamples();
+
+  virtual void Accumulate(HistogramBase::Sample value,
+                          HistogramBase::Count count) = 0;
+  virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
+  virtual HistogramBase::Count TotalCount() const = 0;
+
+  virtual void Add(const HistogramSamples& other);
+
+  // Add from serialized samples.
+  virtual bool AddFromPickle(PickleIterator* iter);
+
+  virtual void Subtract(const HistogramSamples& other);
+
+  virtual scoped_ptr<SampleCountIterator> Iterator() const = 0;
+  virtual bool Serialize(Pickle* pickle) const;
+
+  // Accessor fuctions.
+  int64 sum() const { return sum_; }
+  HistogramBase::Count redundant_count() const {
+    return subtle::NoBarrier_Load(&redundant_count_);
+  }
+
+ protected:
+  // Based on |op| type, add or subtract sample counts data from the iterator.
+  enum Operator { ADD, SUBTRACT };
+  virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
+
+  void IncreaseSum(int64 diff);
+  void IncreaseRedundantCount(HistogramBase::Count diff);
+
+ private:
+  int64 sum_;
+
+  // |redundant_count_| helps identify memory corruption. It redundantly stores
+  // the total number of samples accumulated in the histogram. We can compare
+  // this count to the sum of the counts (TotalCount() function), and detect
+  // problems. Note, depending on the implementation of different histogram
+  // types, there might be races during histogram accumulation and snapshotting
+  // that we choose to accept. In this case, the tallies might mismatch even
+  // when no memory corruption has happened.
+  HistogramBase::AtomicCount redundant_count_;
+};
+
+class BASE_EXPORT SampleCountIterator {
+ public:
+  virtual ~SampleCountIterator();
+
+  virtual bool Done() const = 0;
+  virtual void Next() = 0;
+
+  // Get the sample and count at current position.
+  // |min| |max| and |count| can be NULL if the value is not of interest.
+  // Requires: !Done();
+  virtual void Get(HistogramBase::Sample* min,
+                   HistogramBase::Sample* max,
+                   HistogramBase::Count* count) const = 0;
+
+  // Get the index of current histogram bucket.
+  // For histograms that don't use predefined buckets, it returns false.
+  // Requires: !Done();
+  virtual bool GetBucketIndex(size_t* index) const;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
new file mode 100644
index 0000000..b1e26da
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_snapshot_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.h"
+
+using std::map;
+using std::string;
+
+namespace base {
+
+HistogramSnapshotManager::HistogramSnapshotManager(
+    HistogramFlattener* histogram_flattener)
+    : histogram_flattener_(histogram_flattener) {
+  DCHECK(histogram_flattener_);
+}
+
+HistogramSnapshotManager::~HistogramSnapshotManager() {
+  STLDeleteValues(&logged_samples_);
+}
+
+void HistogramSnapshotManager::PrepareDeltas(
+    HistogramBase::Flags flag_to_set,
+    HistogramBase::Flags required_flags) {
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+  for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin();
+       histograms.end() != it;
+       ++it) {
+    (*it)->SetFlags(flag_to_set);
+    if (((*it)->flags() & required_flags) == required_flags)
+      PrepareDelta(**it);
+  }
+}
+
+void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
+  DCHECK(histogram_flattener_);
+
+  // Get up-to-date snapshot of sample stats.
+  scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples());
+  const std::string& histogram_name = histogram.histogram_name();
+
+  int corruption = histogram.FindCorruption(*snapshot);
+
+  // Crash if we detect that our histograms have been overwritten.  This may be
+  // a fair distance from the memory smasher, but we hope to correlate these
+  // crashes with other events, such as plugins, or usage patterns, etc.
+  if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
+    // The checksum should have caught this, so crash separately if it didn't.
+    CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
+    CHECK(false);  // Crash for the bucket order corruption.
+  }
+  // Checksum corruption might not have caused order corruption.
+  CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
+
+  // Note, at this point corruption can only be COUNT_HIGH_ERROR or
+  // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
+  // bits from corruption.
+  if (corruption) {
+    DLOG(ERROR) << "Histogram: " << histogram_name
+                << " has data corruption: " << corruption;
+    histogram_flattener_->InconsistencyDetected(
+        static_cast<HistogramBase::Inconsistency>(corruption));
+    // Don't record corrupt data to metrics services.
+    int old_corruption = inconsistencies_[histogram_name];
+    if (old_corruption == (corruption | old_corruption))
+      return;  // We've already seen this corruption for this histogram.
+    inconsistencies_[histogram_name] |= corruption;
+    histogram_flattener_->UniqueInconsistencyDetected(
+        static_cast<HistogramBase::Inconsistency>(corruption));
+    return;
+  }
+
+  HistogramSamples* to_log;
+  map<string, HistogramSamples*>::iterator it =
+      logged_samples_.find(histogram_name);
+  if (it == logged_samples_.end()) {
+    to_log = snapshot.release();
+
+    // This histogram has not been logged before, add a new entry.
+    logged_samples_[histogram_name] = to_log;
+  } else {
+    HistogramSamples* already_logged = it->second;
+    InspectLoggedSamplesInconsistency(*snapshot, already_logged);
+    snapshot->Subtract(*already_logged);
+    already_logged->Add(*snapshot);
+    to_log = snapshot.get();
+  }
+
+  if (to_log->TotalCount() > 0)
+    histogram_flattener_->RecordDelta(histogram, *to_log);
+}
+
+void HistogramSnapshotManager::InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples) {
+  HistogramBase::Count discrepancy =
+      logged_samples->TotalCount() - logged_samples->redundant_count();
+  if (!discrepancy)
+    return;
+
+  histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy);
+  if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) {
+    // Fix logged_samples.
+    logged_samples->Subtract(*logged_samples);
+    logged_samples->Add(new_snapshot);
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_snapshot_manager.h b/base/metrics/histogram_snapshot_manager.h
new file mode 100644
index 0000000..5a5f2e9
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class HistogramSamples;
+class HistogramFlattener;
+
+// HistogramSnapshotManager handles the logistics of gathering up available
+// histograms for recording either to disk or for transmission (such as from
+// renderer to browser, or from browser to UMA upload). Since histograms can sit
+// in memory for an extended period of time, and are vulnerable to memory
+// corruption, this class also validates as much rendundancy as it can before
+// calling for the marginal change (a.k.a., delta) in a histogram to be
+// recorded.
+class BASE_EXPORT HistogramSnapshotManager {
+ public:
+  explicit HistogramSnapshotManager(HistogramFlattener* histogram_flattener);
+  virtual ~HistogramSnapshotManager();
+
+  // Snapshot all histograms, and ask |histogram_flattener_| to record the
+  // delta. |flags_to_set| is used to set flags for each histogram.
+  // |required_flags| is used to select histograms to be recorded.
+  // Only histograms that have all the flags specified by the argument will be
+  // chosen. If all histograms should be recorded, set it to
+  // |Histogram::kNoFlags|.
+  void PrepareDeltas(HistogramBase::Flags flags_to_set,
+                     HistogramBase::Flags required_flags);
+
+ private:
+  // Snapshot this histogram, and record the delta.
+  void PrepareDelta(const HistogramBase& histogram);
+
+  // Try to detect and fix count inconsistency of logged samples.
+  void InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples);
+
+  // For histograms, track what we've already recorded (as a sample for
+  // each histogram) so that we can record only the delta with the next log.
+  std::map<std::string, HistogramSamples*> logged_samples_;
+
+  // List of histograms found to be corrupt, and their problems.
+  std::map<std::string, int> inconsistencies_;
+
+  // |histogram_flattener_| handles the logistics of recording the histogram
+  // deltas.
+  HistogramFlattener* histogram_flattener_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramSnapshotManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
diff --git a/base/metrics/histogram_snapshot_manager_unittest.cc b/base/metrics/histogram_snapshot_manager_unittest.cc
new file mode 100644
index 0000000..3a1fd40
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_snapshot_manager.h"
+
+#include <string>
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_delta_serialization.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class HistogramFlattenerDeltaRecorder : public HistogramFlattener {
+ public:
+  HistogramFlattenerDeltaRecorder() {}
+
+  void RecordDelta(const HistogramBase& histogram,
+                   const HistogramSamples& snapshot) override {
+    recorded_delta_histogram_names_.push_back(histogram.histogram_name());
+  }
+
+  void InconsistencyDetected(HistogramBase::Inconsistency problem) override {
+    ASSERT_TRUE(false);
+  }
+
+  void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) override {
+    ASSERT_TRUE(false);
+  }
+
+  void InconsistencyDetectedInLoggedCount(int amount) override {
+    ASSERT_TRUE(false);
+  }
+
+  std::vector<std::string> GetRecordedDeltaHistogramNames() {
+    return recorded_delta_histogram_names_;
+  }
+
+ private:
+  std::vector<std::string> recorded_delta_histogram_names_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder);
+};
+
+class HistogramSnapshotManagerTest : public testing::Test {
+ protected:
+  HistogramSnapshotManagerTest()
+      : histogram_snapshot_manager_(&histogram_flattener_delta_recorder_) {}
+
+  ~HistogramSnapshotManagerTest() override {}
+
+  StatisticsRecorder statistics_recorder_;
+  HistogramFlattenerDeltaRecorder histogram_flattener_delta_recorder_;
+  HistogramSnapshotManager histogram_snapshot_manager_;
+};
+
+TEST_F(HistogramSnapshotManagerTest, PrepareDeltasNoFlagsFilter) {
+  // kNoFlags filter should record all histograms.
+  UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 2);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(HistogramBase::kNoFlags,
+                                            HistogramBase::kNoFlags);
+
+  const std::vector<std::string>& histograms =
+      histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames();
+  EXPECT_EQ(2U, histograms.size());
+  EXPECT_EQ("UmaHistogram", histograms[0]);
+  EXPECT_EQ("UmaStabilityHistogram", histograms[1]);
+}
+
+TEST_F(HistogramSnapshotManagerTest, PrepareDeltasUmaHistogramFlagFilter) {
+  // Note that kUmaStabilityHistogramFlag includes kUmaTargetedHistogramFlag.
+  UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 2);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      HistogramBase::kNoFlags, HistogramBase::kUmaTargetedHistogramFlag);
+
+  const std::vector<std::string>& histograms =
+      histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames();
+  EXPECT_EQ(2U, histograms.size());
+  EXPECT_EQ("UmaHistogram", histograms[0]);
+  EXPECT_EQ("UmaStabilityHistogram", histograms[1]);
+}
+
+TEST_F(HistogramSnapshotManagerTest,
+       PrepareDeltasUmaStabilityHistogramFlagFilter) {
+  UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 2);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      HistogramBase::kNoFlags, HistogramBase::kUmaStabilityHistogramFlag);
+
+  const std::vector<std::string>& histograms =
+      histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames();
+  EXPECT_EQ(1U, histograms.size());
+  EXPECT_EQ("UmaStabilityHistogram", histograms[0]);
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
new file mode 100644
index 0000000..df43e65
--- /dev/null
+++ b/base/metrics/histogram_unittest.cc
@@ -0,0 +1,514 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test of Histogram class
+
+#include <climits>
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::vector;
+
+namespace base {
+
+class HistogramTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override { UninitializeStatisticsRecorder(); }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+// Check for basic syntax and use.
+TEST_F(HistogramTest, BasicTest) {
+  // Try basic construction
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  EXPECT_TRUE(linear_histogram);
+
+  vector<int> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(5);
+  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+  EXPECT_TRUE(custom_histogram);
+
+  // Use standard macros (but with fixed samples)
+  LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
+  LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30);
+
+  LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
+}
+
+// Check that the macro correctly matches histograms by name and records their
+// data together.
+TEST_F(HistogramTest, NameMatchTest) {
+  LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags);
+
+  scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  EXPECT_EQ(2, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(10));
+}
+
+TEST_F(HistogramTest, ExponentialRangesTest) {
+  // Check that we got a nice exponential when there was enough rooom.
+  BucketRanges ranges(9);
+  Histogram::InitializeBucketRanges(1, 64, &ranges);
+  EXPECT_EQ(0, ranges.range(0));
+  int power_of_2 = 1;
+  for (int i = 1; i < 8; i++) {
+    EXPECT_EQ(power_of_2, ranges.range(i));
+    power_of_2 *= 2;
+  }
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
+
+  // Check the corresponding Histogram will use the correct ranges.
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
+
+  // When bucket count is limited, exponential ranges will partially look like
+  // linear.
+  BucketRanges ranges2(16);
+  Histogram::InitializeBucketRanges(1, 32, &ranges2);
+
+  EXPECT_EQ(0, ranges2.range(0));
+  EXPECT_EQ(1, ranges2.range(1));
+  EXPECT_EQ(2, ranges2.range(2));
+  EXPECT_EQ(3, ranges2.range(3));
+  EXPECT_EQ(4, ranges2.range(4));
+  EXPECT_EQ(5, ranges2.range(5));
+  EXPECT_EQ(6, ranges2.range(6));
+  EXPECT_EQ(7, ranges2.range(7));
+  EXPECT_EQ(9, ranges2.range(8));
+  EXPECT_EQ(11, ranges2.range(9));
+  EXPECT_EQ(14, ranges2.range(10));
+  EXPECT_EQ(17, ranges2.range(11));
+  EXPECT_EQ(21, ranges2.range(12));
+  EXPECT_EQ(26, ranges2.range(13));
+  EXPECT_EQ(32, ranges2.range(14));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15));
+
+  // Check the corresponding Histogram will use the correct ranges.
+  Histogram* histogram2 = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
+}
+
+TEST_F(HistogramTest, LinearRangesTest) {
+  BucketRanges ranges(9);
+  LinearHistogram::InitializeBucketRanges(1, 7, &ranges);
+  // Gets a nice linear set of bucket ranges.
+  for (int i = 0; i < 8; i++)
+    EXPECT_EQ(i, ranges.range(i));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
+
+  // The correspoding LinearHistogram should use the correct ranges.
+  Histogram* histogram = static_cast<Histogram*>(
+      LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
+
+  // Linear ranges are not divisible.
+  BucketRanges ranges2(6);
+  LinearHistogram::InitializeBucketRanges(1, 6, &ranges2);
+  EXPECT_EQ(0, ranges2.range(0));
+  EXPECT_EQ(1, ranges2.range(1));
+  EXPECT_EQ(3, ranges2.range(2));
+  EXPECT_EQ(4, ranges2.range(3));
+  EXPECT_EQ(6, ranges2.range(4));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5));
+  // The correspoding LinearHistogram should use the correct ranges.
+  Histogram* histogram2 = static_cast<Histogram*>(
+      LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
+}
+
+TEST_F(HistogramTest, ArrayToCustomRangesTest) {
+  const HistogramBase::Sample ranges[3] = {5, 10, 20};
+  vector<HistogramBase::Sample> ranges_vec =
+      CustomHistogram::ArrayToCustomRanges(ranges, 3);
+  ASSERT_EQ(6u, ranges_vec.size());
+  EXPECT_EQ(5, ranges_vec[0]);
+  EXPECT_EQ(6, ranges_vec[1]);
+  EXPECT_EQ(10, ranges_vec[2]);
+  EXPECT_EQ(11, ranges_vec[3]);
+  EXPECT_EQ(20, ranges_vec[4]);
+  EXPECT_EQ(21, ranges_vec[5]);
+}
+
+TEST_F(HistogramTest, CustomHistogramTest) {
+  // A well prepared custom ranges.
+  vector<HistogramBase::Sample> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(2);
+
+  Histogram* histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  const BucketRanges* ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));  // Auto added.
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(2, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));  // Auto added.
+
+  // A unordered custom ranges.
+  custom_ranges.clear();
+  custom_ranges.push_back(2);
+  custom_ranges.push_back(1);
+  histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(2, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
+
+  // A custom ranges with duplicated values.
+  custom_ranges.clear();
+  custom_ranges.push_back(4);
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(4);
+  histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(4, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
+}
+
+TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
+  // This test exploits the fact that the CustomHistogram can have 2 buckets,
+  // while the base class Histogram is *supposed* to have at least 3 buckets.
+  // We should probably change the restriction on the base class (or not inherit
+  // the base class!).
+
+  vector<HistogramBase::Sample> custom_ranges;
+  custom_ranges.push_back(4);
+
+  Histogram* histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  const BucketRanges* ranges = histogram->bucket_ranges();
+  ASSERT_EQ(3u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(4, ranges->range(1));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
+}
+
+// Make sure histogram handles out-of-bounds data gracefully.
+TEST_F(HistogramTest, BoundsTest) {
+  const size_t kBucketCount = 50;
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Bounded", 10, 100, kBucketCount,
+                            HistogramBase::kNoFlags));
+
+  // Put two samples "out of bounds" above and below.
+  histogram->Add(5);
+  histogram->Add(-50);
+
+  histogram->Add(100);
+  histogram->Add(10000);
+
+  // Verify they landed in the underflow, and overflow buckets.
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, samples->GetCountAtIndex(0));
+  EXPECT_EQ(0, samples->GetCountAtIndex(1));
+  size_t array_size = histogram->bucket_count();
+  EXPECT_EQ(kBucketCount, array_size);
+  EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2));
+  EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1));
+
+  vector<int> custom_ranges;
+  custom_ranges.push_back(10);
+  custom_ranges.push_back(50);
+  custom_ranges.push_back(100);
+  Histogram* test_custom_histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram",
+                                  custom_ranges, HistogramBase::kNoFlags));
+
+  // Put two samples "out of bounds" above and below.
+  test_custom_histogram->Add(5);
+  test_custom_histogram->Add(-50);
+  test_custom_histogram->Add(100);
+  test_custom_histogram->Add(1000);
+  test_custom_histogram->Add(INT_MAX);
+
+  // Verify they landed in the underflow, and overflow buckets.
+  scoped_ptr<SampleVector> custom_samples =
+      test_custom_histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, custom_samples->GetCountAtIndex(0));
+  EXPECT_EQ(0, custom_samples->GetCountAtIndex(1));
+  size_t bucket_count = test_custom_histogram->bucket_count();
+  EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2));
+  EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1));
+}
+
+// Check to be sure samples land as expected is "correct" buckets.
+TEST_F(HistogramTest, BucketPlacementTest) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  // Add i+1 samples to the i'th bucket.
+  histogram->Add(0);
+  int power_of_2 = 1;
+  for (int i = 1; i < 8; i++) {
+    for (int j = 0; j <= i; j++)
+      histogram->Add(power_of_2);
+    power_of_2 *= 2;
+  }
+
+  // Check to see that the bucket counts reflect our additions.
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  for (int i = 0; i < 8; i++)
+    EXPECT_EQ(i + 1, samples->GetCountAtIndex(i));
+}
+
+TEST_F(HistogramTest, CorruptSampleCounts) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  // Add some samples.
+  histogram->Add(20);
+  histogram->Add(40);
+
+  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
+  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+  EXPECT_EQ(2, snapshot->redundant_count());
+  EXPECT_EQ(2, snapshot->TotalCount());
+
+  snapshot->counts_[3] += 100;  // Sample count won't match redundant count.
+  EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR,
+            histogram->FindCorruption(*snapshot));
+  snapshot->counts_[2] -= 200;
+  EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  // But we can't spot a corruption if it is compensated for.
+  snapshot->counts_[1] += 100;
+  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+}
+
+TEST_F(HistogramTest, CorruptBucketBounds) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
+  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+
+  BucketRanges* bucket_ranges =
+      const_cast<BucketRanges*>(histogram->bucket_ranges());
+  HistogramBase::Sample tmp = bucket_ranges->range(1);
+  bucket_ranges->set_range(1, bucket_ranges->range(2));
+  bucket_ranges->set_range(2, tmp);
+  EXPECT_EQ(
+      HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR,
+      histogram->FindCorruption(*snapshot));
+
+  bucket_ranges->set_range(2, bucket_ranges->range(1));
+  bucket_ranges->set_range(1, tmp);
+  EXPECT_EQ(0, histogram->FindCorruption(*snapshot));
+
+  // Show that two simple changes don't offset each other
+  bucket_ranges->set_range(3, bucket_ranges->range(3) + 1);
+  EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  bucket_ranges->set_range(4, bucket_ranges->range(4) - 1);
+  EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  // Repair histogram so that destructor won't DCHECK().
+  bucket_ranges->set_range(3, bucket_ranges->range(3) - 1);
+  bucket_ranges->set_range(4, bucket_ranges->range(4) + 1);
+}
+
+TEST_F(HistogramTest, HistogramSerializeInfo) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8,
+                            HistogramBase::kIPCSerializationSourceFlag));
+  Pickle pickle;
+  histogram->SerializeInfo(&pickle);
+
+  PickleIterator iter(pickle);
+
+  int type;
+  EXPECT_TRUE(iter.ReadInt(&type));
+  EXPECT_EQ(HISTOGRAM, type);
+
+  std::string name;
+  EXPECT_TRUE(iter.ReadString(&name));
+  EXPECT_EQ("Histogram", name);
+
+  int flag;
+  EXPECT_TRUE(iter.ReadInt(&flag));
+  EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
+
+  int min;
+  EXPECT_TRUE(iter.ReadInt(&min));
+  EXPECT_EQ(1, min);
+
+  int max;
+  EXPECT_TRUE(iter.ReadInt(&max));
+  EXPECT_EQ(64, max);
+
+  int64 bucket_count;
+  EXPECT_TRUE(iter.ReadInt64(&bucket_count));
+  EXPECT_EQ(8, bucket_count);
+
+  uint32 checksum;
+  EXPECT_TRUE(iter.ReadUInt32(&checksum));
+  EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
+
+  // No more data in the pickle.
+  EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
+  vector<int> custom_ranges;
+  custom_ranges.push_back(10);
+  custom_ranges.push_back(100);
+
+  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+      "TestCustomRangeBoundedHistogram",
+      custom_ranges,
+      HistogramBase::kNoFlags);
+  Pickle pickle;
+  custom_histogram->SerializeInfo(&pickle);
+
+  // Validate the pickle.
+  PickleIterator iter(pickle);
+
+  int i;
+  std::string s;
+  int64 bucket_count;
+  uint32 ui32;
+  EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
+              iter.ReadInt(&i) && iter.ReadInt(&i) &&
+              iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32));
+  EXPECT_EQ(3, bucket_count);
+
+  int range;
+  EXPECT_TRUE(iter.ReadInt(&range));
+  EXPECT_EQ(10, range);
+  EXPECT_TRUE(iter.ReadInt(&range));
+  EXPECT_EQ(100, range);
+
+  // No more data in the pickle.
+  EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+TEST_F(HistogramTest, BadConstruction) {
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8));
+
+  // Try to get the same histogram name with different arguments.
+  HistogramBase* bad_histogram = Histogram::FactoryGet(
+      "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+  bad_histogram = Histogram::FactoryGet(
+      "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags);
+  EXPECT_TRUE(linear_histogram->HasConstructionArguments(1, 100, 8));
+
+  // Try to get the same histogram name with different arguments.
+  bad_histogram = LinearHistogram::FactoryGet(
+      "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+  bad_histogram = LinearHistogram::FactoryGet(
+      "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+}
+
+#if GTEST_HAS_DEATH_TEST
+// For Histogram, LinearHistogram and CustomHistogram, the minimum for a
+// declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
+// 1). But we accept ranges exceeding those limits, and silently clamped to
+// those limits. This is for backwards compatibility.
+TEST(HistogramDeathTest, BadRangesTest) {
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "BadRanges", 0, HistogramBase::kSampleType_MAX, 8,
+      HistogramBase::kNoFlags);
+  EXPECT_TRUE(
+      histogram->HasConstructionArguments(
+          1, HistogramBase::kSampleType_MAX - 1, 8));
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
+      HistogramBase::kNoFlags);
+  EXPECT_TRUE(
+      linear_histogram->HasConstructionArguments(
+          1, HistogramBase::kSampleType_MAX - 1, 8));
+
+  vector<int> custom_ranges;
+  custom_ranges.push_back(0);
+  custom_ranges.push_back(5);
+  Histogram* custom_histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet(
+          "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags));
+  const BucketRanges* ranges = custom_histogram->bucket_ranges();
+  ASSERT_EQ(3u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(5, ranges->range(1));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
+
+  // CustomHistogram does not accepts kSampleType_MAX as range.
+  custom_ranges.push_back(HistogramBase::kSampleType_MAX);
+  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges,
+                                           HistogramBase::kNoFlags),
+               "");
+
+  // CustomHistogram needs at least 1 valid range.
+  custom_ranges.clear();
+  custom_ranges.push_back(0);
+  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
+                                           HistogramBase::kNoFlags),
+               "");
+}
+#endif
+
+}  // namespace base
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
new file mode 100644
index 0000000..42468cb
--- /dev/null
+++ b/base/metrics/sample_map.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/sample_map.h"
+
+#include "base/logging.h"
+
+using std::map;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+SampleMap::SampleMap() {}
+
+SampleMap::~SampleMap() {}
+
+void SampleMap::Accumulate(Sample value, Count count) {
+  sample_counts_[value] += count;
+  IncreaseSum(count * value);
+  IncreaseRedundantCount(count);
+}
+
+Count SampleMap::GetCount(Sample value) const {
+  map<Sample, Count>::const_iterator it = sample_counts_.find(value);
+  if (it == sample_counts_.end())
+    return 0;
+  return it->second;
+}
+
+Count SampleMap::TotalCount() const {
+  Count count = 0;
+  for (map<Sample, Count>::const_iterator it = sample_counts_.begin();
+       it != sample_counts_.end();
+       ++it) {
+    count += it->second;
+  }
+  return count;
+}
+
+scoped_ptr<SampleCountIterator> SampleMap::Iterator() const {
+  return scoped_ptr<SampleCountIterator>(new SampleMapIterator(sample_counts_));
+}
+
+bool SampleMap::AddSubtractImpl(SampleCountIterator* iter,
+                                HistogramSamples::Operator op) {
+  Sample min;
+  Sample max;
+  Count count;
+  for (; !iter->Done(); iter->Next()) {
+    iter->Get(&min, &max, &count);
+    if (min + 1 != max)
+      return false;  // SparseHistogram only supports bucket with size 1.
+    sample_counts_[min] += (op ==  HistogramSamples::ADD) ? count : -count;
+  }
+  return true;
+}
+
+SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts)
+    : iter_(sample_counts.begin()),
+      end_(sample_counts.end()) {}
+
+SampleMapIterator::~SampleMapIterator() {}
+
+bool SampleMapIterator::Done() const {
+  return iter_ == end_;
+}
+
+void SampleMapIterator::Next() {
+  DCHECK(!Done());
+  iter_++;
+}
+
+void SampleMapIterator::Get(Sample* min, Sample* max, Count* count) const {
+  DCHECK(!Done());
+  if (min != NULL)
+    *min = iter_->first;
+  if (max != NULL)
+    *max = iter_->first + 1;
+  if (count != NULL)
+    *count = iter_->second;
+}
+
+}  // namespace base
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
new file mode 100644
index 0000000..7a780ea
--- /dev/null
+++ b/base/metrics/sample_map.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.
+
+// SampleMap implements HistogramSamples interface. It is used by the
+// SparseHistogram class to store samples.
+
+#ifndef BASE_METRICS_SAMPLE_MAP_H_
+#define BASE_METRICS_SAMPLE_MAP_H_
+
+#include <map>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
+ public:
+  SampleMap();
+  ~SampleMap() override;
+
+  // HistogramSamples implementation:
+  void Accumulate(HistogramBase::Sample value,
+                  HistogramBase::Count count) override;
+  HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
+  HistogramBase::Count TotalCount() const override;
+  scoped_ptr<SampleCountIterator> Iterator() const override;
+
+ protected:
+  bool AddSubtractImpl(
+      SampleCountIterator* iter,
+      HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
+
+ private:
+  std::map<HistogramBase::Sample, HistogramBase::Count> sample_counts_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleMap);
+};
+
+class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+ public:
+  typedef std::map<HistogramBase::Sample, HistogramBase::Count>
+      SampleToCountMap;
+
+  explicit SampleMapIterator(const SampleToCountMap& sample_counts);
+  ~SampleMapIterator() override;
+
+  // SampleCountIterator implementation:
+  bool Done() const override;
+  void Next() override;
+  void Get(HistogramBase::Sample* min,
+           HistogramBase::Sample* max,
+           HistogramBase::Count* count) const override;
+
+ private:
+  SampleToCountMap::const_iterator iter_;
+  const SampleToCountMap::const_iterator end_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_MAP_H_
diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc
new file mode 100644
index 0000000..1a53ee7
--- /dev/null
+++ b/base/metrics/sample_map_unittest.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/sample_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(SampleMapTest, AccumulateTest) {
+  SampleMap samples;
+
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(1, -200);
+  EXPECT_EQ(-100, samples.GetCount(1));
+  EXPECT_EQ(200, samples.GetCount(2));
+
+  EXPECT_EQ(300, samples.sum());
+  EXPECT_EQ(100, samples.TotalCount());
+  EXPECT_EQ(samples.redundant_count(), samples.TotalCount());
+}
+
+TEST(SampleMapTest, AddSubtractTest) {
+  SampleMap samples1;
+  SampleMap samples2;
+
+  samples1.Accumulate(1, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(3, 100);
+
+  samples2.Accumulate(1, 200);
+  samples2.Accumulate(2, 200);
+  samples2.Accumulate(4, 200);
+
+  samples1.Add(samples2);
+  EXPECT_EQ(300, samples1.GetCount(1));
+  EXPECT_EQ(300, samples1.GetCount(2));
+  EXPECT_EQ(100, samples1.GetCount(3));
+  EXPECT_EQ(200, samples1.GetCount(4));
+  EXPECT_EQ(2000, samples1.sum());
+  EXPECT_EQ(900, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  samples1.Subtract(samples2);
+  EXPECT_EQ(100, samples1.GetCount(1));
+  EXPECT_EQ(100, samples1.GetCount(2));
+  EXPECT_EQ(100, samples1.GetCount(3));
+  EXPECT_EQ(0, samples1.GetCount(4));
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+}
+
+TEST(SampleMapIteratorTest, IterateTest) {
+  SampleMap samples;
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(4, -300);
+  samples.Accumulate(5, 0);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(1, min);
+  EXPECT_EQ(2, max);
+  EXPECT_EQ(100, count);
+  EXPECT_FALSE(it->GetBucketIndex(NULL));
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(2, min);
+  EXPECT_EQ(3, max);
+  EXPECT_EQ(200, count);
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(4, min);
+  EXPECT_EQ(5, max);
+  EXPECT_EQ(-300, count);
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(5, min);
+  EXPECT_EQ(6, max);
+  EXPECT_EQ(0, count);
+
+  it->Next();
+  EXPECT_TRUE(it->Done());
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleMapIteratorDeathTest, IterateDoneTest) {
+  SampleMap samples;
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  EXPECT_TRUE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  EXPECT_DEATH(it->Get(&min, &max, &count), "");
+
+  EXPECT_DEATH(it->Next(), "");
+
+  samples.Accumulate(1, 100);
+  it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
new file mode 100644
index 0000000..ca3205e
--- /dev/null
+++ b/base/metrics/sample_vector.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/sample_vector.h"
+
+#include "base/logging.h"
+#include "base/metrics/bucket_ranges.h"
+
+using std::vector;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+SampleVector::SampleVector(const BucketRanges* bucket_ranges)
+    : counts_(bucket_ranges->bucket_count()),
+      bucket_ranges_(bucket_ranges) {
+  CHECK_GE(bucket_ranges_->bucket_count(), 1u);
+}
+
+SampleVector::~SampleVector() {}
+
+void SampleVector::Accumulate(Sample value, Count count) {
+  size_t bucket_index = GetBucketIndex(value);
+  subtle::NoBarrier_Store(&counts_[bucket_index],
+      subtle::NoBarrier_Load(&counts_[bucket_index]) + count);
+  IncreaseSum(count * value);
+  IncreaseRedundantCount(count);
+}
+
+Count SampleVector::GetCount(Sample value) const {
+  size_t bucket_index = GetBucketIndex(value);
+  return subtle::NoBarrier_Load(&counts_[bucket_index]);
+}
+
+Count SampleVector::TotalCount() const {
+  Count count = 0;
+  for (size_t i = 0; i < counts_.size(); i++) {
+    count += subtle::NoBarrier_Load(&counts_[i]);
+  }
+  return count;
+}
+
+Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
+  DCHECK(bucket_index < counts_.size());
+  return subtle::NoBarrier_Load(&counts_[bucket_index]);
+}
+
+scoped_ptr<SampleCountIterator> SampleVector::Iterator() const {
+  return scoped_ptr<SampleCountIterator>(
+      new SampleVectorIterator(&counts_, bucket_ranges_));
+}
+
+bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
+                                   HistogramSamples::Operator op) {
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  // Go through the iterator and add the counts into correct bucket.
+  size_t index = 0;
+  while (index < counts_.size() && !iter->Done()) {
+    iter->Get(&min, &max, &count);
+    if (min == bucket_ranges_->range(index) &&
+        max == bucket_ranges_->range(index + 1)) {
+      // Sample matches this bucket!
+      HistogramBase::Count old_counts =
+          subtle::NoBarrier_Load(&counts_[index]);
+      subtle::NoBarrier_Store(&counts_[index],
+          old_counts + ((op ==  HistogramSamples::ADD) ? count : -count));
+      iter->Next();
+    } else if (min > bucket_ranges_->range(index)) {
+      // Sample is larger than current bucket range. Try next.
+      index++;
+    } else {
+      // Sample is smaller than current bucket range. We scan buckets from
+      // smallest to largest, so the sample value must be invalid.
+      return false;
+    }
+  }
+
+  return iter->Done();
+}
+
+// Use simple binary search.  This is very general, but there are better
+// approaches if we knew that the buckets were linearly distributed.
+size_t SampleVector::GetBucketIndex(Sample value) const {
+  size_t bucket_count = bucket_ranges_->bucket_count();
+  CHECK_GE(bucket_count, 1u);
+  CHECK_GE(value, bucket_ranges_->range(0));
+  CHECK_LT(value, bucket_ranges_->range(bucket_count));
+
+  size_t under = 0;
+  size_t over = bucket_count;
+  size_t mid;
+  do {
+    DCHECK_GE(over, under);
+    mid = under + (over - under)/2;
+    if (mid == under)
+      break;
+    if (bucket_ranges_->range(mid) <= value)
+      under = mid;
+    else
+      over = mid;
+  } while (true);
+
+  DCHECK_LE(bucket_ranges_->range(mid), value);
+  CHECK_GT(bucket_ranges_->range(mid + 1), value);
+  return mid;
+}
+
+SampleVectorIterator::SampleVectorIterator(const vector<Count>* counts,
+                                           const BucketRanges* bucket_ranges)
+    : counts_(counts),
+      bucket_ranges_(bucket_ranges),
+      index_(0) {
+  CHECK_GE(bucket_ranges_->bucket_count(), counts_->size());
+  SkipEmptyBuckets();
+}
+
+SampleVectorIterator::~SampleVectorIterator() {}
+
+bool SampleVectorIterator::Done() const {
+  return index_ >= counts_->size();
+}
+
+void SampleVectorIterator::Next() {
+  DCHECK(!Done());
+  index_++;
+  SkipEmptyBuckets();
+}
+
+void SampleVectorIterator::Get(HistogramBase::Sample* min,
+                               HistogramBase::Sample* max,
+                               HistogramBase::Count* count) const {
+  DCHECK(!Done());
+  if (min != NULL)
+    *min = bucket_ranges_->range(index_);
+  if (max != NULL)
+    *max = bucket_ranges_->range(index_ + 1);
+  if (count != NULL)
+    *count = subtle::NoBarrier_Load(&(*counts_)[index_]);
+}
+
+bool SampleVectorIterator::GetBucketIndex(size_t* index) const {
+  DCHECK(!Done());
+  if (index != NULL)
+    *index = index_;
+  return true;
+}
+
+void SampleVectorIterator::SkipEmptyBuckets() {
+  if (Done())
+    return;
+
+  while (index_ < counts_->size()) {
+    if (subtle::NoBarrier_Load(&(*counts_)[index_]) != 0)
+      return;
+    index_++;
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
new file mode 100644
index 0000000..55f9b96
--- /dev/null
+++ b/base/metrics/sample_vector.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// SampleVector implements HistogramSamples interface. It is used by all
+// Histogram based classes to store samples.
+
+#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
+#define BASE_METRICS_SAMPLE_VECTOR_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BucketRanges;
+
+class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+ public:
+  explicit SampleVector(const BucketRanges* bucket_ranges);
+  ~SampleVector() override;
+
+  // HistogramSamples implementation:
+  void Accumulate(HistogramBase::Sample value,
+                  HistogramBase::Count count) override;
+  HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
+  HistogramBase::Count TotalCount() const override;
+  scoped_ptr<SampleCountIterator> Iterator() const override;
+
+  // Get count of a specific bucket.
+  HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
+
+ protected:
+  bool AddSubtractImpl(
+      SampleCountIterator* iter,
+      HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
+
+  virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
+
+  std::vector<HistogramBase::AtomicCount> counts_;
+
+  // Shares the same BucketRanges with Histogram object.
+  const BucketRanges* const bucket_ranges_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleVector);
+};
+
+class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+ public:
+  SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
+                       const BucketRanges* bucket_ranges);
+  ~SampleVectorIterator() override;
+
+  // SampleCountIterator implementation:
+  bool Done() const override;
+  void Next() override;
+  void Get(HistogramBase::Sample* min,
+           HistogramBase::Sample* max,
+           HistogramBase::Count* count) const override;
+
+  // SampleVector uses predefined buckets, so iterator can return bucket index.
+  bool GetBucketIndex(size_t* index) const override;
+
+ private:
+  void SkipEmptyBuckets();
+
+  const std::vector<HistogramBase::AtomicCount>* counts_;
+  const BucketRanges* bucket_ranges_;
+
+  size_t index_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_VECTOR_H_
diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc
new file mode 100644
index 0000000..9c7ba96
--- /dev/null
+++ b/base/metrics/sample_vector_unittest.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sample_vector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::vector;
+
+namespace base {
+namespace {
+
+TEST(SampleVectorTest, AccumulateTest) {
+  // Custom buckets: [1, 5) [5, 10)
+  BucketRanges ranges(3);
+  ranges.set_range(0, 1);
+  ranges.set_range(1, 5);
+  ranges.set_range(2, 10);
+  SampleVector samples(&ranges);
+
+  samples.Accumulate(1, 200);
+  samples.Accumulate(2, -300);
+  EXPECT_EQ(-100, samples.GetCountAtIndex(0));
+
+  samples.Accumulate(5, 200);
+  EXPECT_EQ(200, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(600, samples.sum());
+  EXPECT_EQ(100, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+
+  samples.Accumulate(5, -100);
+  EXPECT_EQ(100, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(100, samples.sum());
+  EXPECT_EQ(0, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+}
+
+TEST(SampleVectorTest, AddSubtractTest) {
+  // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX)
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, INT_MAX);
+
+  SampleVector samples1(&ranges);
+  samples1.Accumulate(0, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(4, 100);
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  SampleVector samples2(&ranges);
+  samples2.Accumulate(1, 200);
+  samples2.Accumulate(2, 200);
+  samples2.Accumulate(4, 200);
+  EXPECT_EQ(1400, samples2.sum());
+  EXPECT_EQ(600, samples2.TotalCount());
+  EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount());
+
+  samples1.Add(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+  EXPECT_EQ(200, samples1.GetCountAtIndex(1));
+  EXPECT_EQ(300, samples1.GetCountAtIndex(2));
+  EXPECT_EQ(300, samples1.GetCountAtIndex(3));
+  EXPECT_EQ(2000, samples1.sum());
+  EXPECT_EQ(900, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  samples1.Subtract(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+  EXPECT_EQ(0, samples1.GetCountAtIndex(1));
+  EXPECT_EQ(100, samples1.GetCountAtIndex(2));
+  EXPECT_EQ(100, samples1.GetCountAtIndex(3));
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+TEST(SampleVectorDeathTest, BucketIndexTest) {
+  // 8 buckets with exponential layout:
+  // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX)
+  BucketRanges ranges(9);
+  Histogram::InitializeBucketRanges(1, 64, &ranges);
+  SampleVector samples(&ranges);
+
+  // Normal case
+  samples.Accumulate(0, 1);
+  samples.Accumulate(3, 2);
+  samples.Accumulate(64, 3);
+  EXPECT_EQ(1, samples.GetCount(0));
+  EXPECT_EQ(2, samples.GetCount(2));
+  EXPECT_EQ(3, samples.GetCount(65));
+
+  // Extreme case.
+  EXPECT_DEATH(samples.Accumulate(INT_MIN, 100), "");
+  EXPECT_DEATH(samples.Accumulate(-1, 100), "");
+  EXPECT_DEATH(samples.Accumulate(INT_MAX, 100), "");
+
+  // Custom buckets: [1, 5) [5, 10)
+  // Note, this is not a valid BucketRanges for Histogram because it does not
+  // have overflow buckets.
+  BucketRanges ranges2(3);
+  ranges2.set_range(0, 1);
+  ranges2.set_range(1, 5);
+  ranges2.set_range(2, 10);
+  SampleVector samples2(&ranges2);
+
+  // Normal case.
+  samples2.Accumulate(1, 1);
+  samples2.Accumulate(4, 1);
+  samples2.Accumulate(5, 2);
+  samples2.Accumulate(9, 2);
+  EXPECT_EQ(2, samples2.GetCount(1));
+  EXPECT_EQ(4, samples2.GetCount(5));
+
+  // Extreme case.
+  EXPECT_DEATH(samples2.Accumulate(0, 100), "");
+  EXPECT_DEATH(samples2.Accumulate(10, 100), "");
+}
+
+TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
+  // Custom buckets 1: [1, 3) [3, 5)
+  BucketRanges ranges1(3);
+  ranges1.set_range(0, 1);
+  ranges1.set_range(1, 3);
+  ranges1.set_range(2, 5);
+  SampleVector samples1(&ranges1);
+
+  // Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7)
+  BucketRanges ranges2(5);
+  ranges2.set_range(0, 0);
+  ranges2.set_range(1, 1);
+  ranges2.set_range(2, 3);
+  ranges2.set_range(3, 6);
+  ranges2.set_range(4, 7);
+  SampleVector samples2(&ranges2);
+
+  samples2.Accumulate(1, 100);
+  samples1.Add(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+
+  // Extra bucket in the beginning.
+  samples2.Accumulate(0, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+
+  // Extra bucket in the end.
+  samples2.Accumulate(0, -100);
+  samples2.Accumulate(6, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+
+  // Bucket not match: [3, 5) VS [3, 6)
+  samples2.Accumulate(6, -100);
+  samples2.Accumulate(3, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleVectorIteratorTest, IterateTest) {
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, 4);
+
+  vector<HistogramBase::Count> counts(3);
+  counts[0] = 1;
+  counts[1] = 0;  // Iterator will bypass this empty bucket.
+  counts[2] = 2;
+
+  // BucketRanges can have larger size than counts.
+  SampleVectorIterator it(&counts, &ranges);
+  size_t index;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  it.Get(&min, &max, &count);
+  EXPECT_EQ(0, min);
+  EXPECT_EQ(1, max);
+  EXPECT_EQ(1, count);
+  EXPECT_TRUE(it.GetBucketIndex(&index));
+  EXPECT_EQ(0u, index);
+
+  it.Next();
+  it.Get(&min, &max, &count);
+  EXPECT_EQ(2, min);
+  EXPECT_EQ(3, max);
+  EXPECT_EQ(2, count);
+  EXPECT_TRUE(it.GetBucketIndex(&index));
+  EXPECT_EQ(2u, index);
+
+  it.Next();
+  EXPECT_TRUE(it.Done());
+
+  // Create iterator from SampleVector.
+  SampleVector samples(&ranges);
+  samples.Accumulate(0, 0);
+  samples.Accumulate(1, 1);
+  samples.Accumulate(2, 2);
+  samples.Accumulate(3, 3);
+  scoped_ptr<SampleCountIterator> it2 = samples.Iterator();
+
+  int i;
+  for (i = 1; !it2->Done(); i++, it2->Next()) {
+    it2->Get(&min, &max, &count);
+    EXPECT_EQ(i, min);
+    EXPECT_EQ(i + 1, max);
+    EXPECT_EQ(i, count);
+
+    size_t index;
+    EXPECT_TRUE(it2->GetBucketIndex(&index));
+    EXPECT_EQ(static_cast<size_t>(i), index);
+  }
+  EXPECT_EQ(4, i);
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, INT_MAX);
+  SampleVector samples(&ranges);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  EXPECT_TRUE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  EXPECT_DEATH(it->Get(&min, &max, &count), "");
+
+  EXPECT_DEATH(it->Next(), "");
+
+  samples.Accumulate(2, 100);
+  it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
new file mode 100644
index 0000000..773eeb6
--- /dev/null
+++ b/base/metrics/sparse_histogram.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/sparse_histogram.h"
+
+#include "base/metrics/sample_map.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+
+using std::map;
+using std::string;
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+// static
+HistogramBase* SparseHistogram::FactoryGet(const string& name, int32 flags) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    HistogramBase* tentative_histogram = new SparseHistogram(name);
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+  DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
+  return histogram;
+}
+
+SparseHistogram::~SparseHistogram() {}
+
+HistogramType SparseHistogram::GetHistogramType() const {
+  return SPARSE_HISTOGRAM;
+}
+
+bool SparseHistogram::HasConstructionArguments(
+    Sample expected_minimum,
+    Sample expected_maximum,
+    size_t expected_bucket_count) const {
+  // SparseHistogram never has min/max/bucket_count limit.
+  return false;
+}
+
+void SparseHistogram::Add(Sample value) {
+  base::AutoLock auto_lock(lock_);
+  samples_.Accumulate(value, 1);
+}
+
+scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
+  scoped_ptr<SampleMap> snapshot(new SampleMap());
+
+  base::AutoLock auto_lock(lock_);
+  snapshot->Add(samples_);
+  return snapshot.Pass();
+}
+
+void SparseHistogram::AddSamples(const HistogramSamples& samples) {
+  base::AutoLock auto_lock(lock_);
+  samples_.Add(samples);
+}
+
+bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
+  base::AutoLock auto_lock(lock_);
+  return samples_.AddFromPickle(iter);
+}
+
+void SparseHistogram::WriteHTMLGraph(string* output) const {
+  output->append("<PRE>");
+  WriteAsciiImpl(true, "<br>", output);
+  output->append("</PRE>");
+}
+
+void SparseHistogram::WriteAscii(string* output) const {
+  WriteAsciiImpl(true, "\n", output);
+}
+
+bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
+  return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
+}
+
+SparseHistogram::SparseHistogram(const string& name)
+    : HistogramBase(name) {}
+
+HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  string histogram_name;
+  int flags;
+  if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
+    DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
+    return NULL;
+  }
+
+  DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag);
+  flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+  return SparseHistogram::FactoryGet(histogram_name, flags);
+}
+
+void SparseHistogram::GetParameters(DictionaryValue* params) const {
+  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
+}
+
+void SparseHistogram::GetCountAndBucketData(Count* count,
+                                            int64* sum,
+                                            ListValue* buckets) const {
+  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
+}
+
+void SparseHistogram::WriteAsciiImpl(bool graph_it,
+                                     const std::string& newline,
+                                     std::string* output) const {
+  // Get a local copy of the data so we are consistent.
+  scoped_ptr<HistogramSamples> snapshot = SnapshotSamples();
+  Count total_count = snapshot->TotalCount();
+  double scaled_total_count = total_count / 100.0;
+
+  WriteAsciiHeader(total_count, output);
+  output->append(newline);
+
+  // Determine how wide the largest bucket range is (how many digits to print),
+  // so that we'll be able to right-align starts for the graphical bars.
+  // Determine which bucket has the largest sample count so that we can
+  // normalize the graphical bar-width relative to that sample count.
+  Count largest_count = 0;
+  Sample largest_sample = 0;
+  scoped_ptr<SampleCountIterator> it = snapshot->Iterator();
+  while (!it->Done())
+  {
+    Sample min;
+    Sample max;
+    Count count;
+    it->Get(&min, &max, &count);
+    if (min > largest_sample)
+      largest_sample = min;
+    if (count > largest_count)
+      largest_count = count;
+    it->Next();
+  }
+  size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1;
+
+  // iterate over each item and display them
+  it = snapshot->Iterator();
+  while (!it->Done())
+  {
+    Sample min;
+    Sample max;
+    Count count;
+    it->Get(&min, &max, &count);
+
+    // value is min, so display it
+    string range = GetSimpleAsciiBucketRange(min);
+    output->append(range);
+    for (size_t j = 0; range.size() + j < print_width + 1; ++j)
+      output->push_back(' ');
+
+    if (graph_it)
+      WriteAsciiBucketGraph(count, largest_count, output);
+    WriteAsciiBucketValue(count, scaled_total_count, output);
+    output->append(newline);
+    it->Next();
+  }
+}
+
+void SparseHistogram::WriteAsciiHeader(const Count total_count,
+                                       std::string* output) const {
+  StringAppendF(output,
+                "Histogram: %s recorded %d samples",
+                histogram_name().c_str(),
+                total_count);
+  if (flags() & ~kHexRangePrintingFlag)
+    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+}
+
+}  // namespace base
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
new file mode 100644
index 0000000..8c05613
--- /dev/null
+++ b/base/metrics/sparse_histogram.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_SPARSE_HISTOGRAM_H_
+#define BASE_METRICS_SPARSE_HISTOGRAM_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/sample_map.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+#define UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample) \
+    do { \
+      base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( \
+          name, base::HistogramBase::kUmaTargetedHistogramFlag); \
+      histogram->Add(sample); \
+    } while (0)
+
+class HistogramSamples;
+
+class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+ public:
+  // If there's one with same name, return the existing one. If not, create a
+  // new one.
+  static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+
+  ~SparseHistogram() override;
+
+  // HistogramBase implementation:
+  HistogramType GetHistogramType() const override;
+  bool HasConstructionArguments(Sample expected_minimum,
+                                Sample expected_maximum,
+                                size_t expected_bucket_count) const override;
+  void Add(Sample value) override;
+  void AddSamples(const HistogramSamples& samples) override;
+  bool AddSamplesFromPickle(PickleIterator* iter) override;
+  scoped_ptr<HistogramSamples> SnapshotSamples() const override;
+  void WriteHTMLGraph(std::string* output) const override;
+  void WriteAscii(std::string* output) const override;
+
+ protected:
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(Pickle* pickle) const override;
+
+ private:
+  // Clients should always use FactoryGet to create SparseHistogram.
+  explicit SparseHistogram(const std::string& name);
+
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
+  void GetParameters(DictionaryValue* params) const override;
+  void GetCountAndBucketData(Count* count,
+                             int64* sum,
+                             ListValue* buckets) const override;
+
+  // Helpers for emitting Ascii graphic.  Each method appends data to output.
+  void WriteAsciiImpl(bool graph_it,
+                      const std::string& newline,
+                      std::string* output) const;
+
+  // Write a common header message describing this histogram.
+  void WriteAsciiHeader(const Count total_count,
+                        std::string* output) const;
+
+  // For constuctor calling.
+  friend class SparseHistogramTest;
+
+  // Protects access to |samples_|.
+  mutable base::Lock lock_;
+
+  SampleMap samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(SparseHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SPARSE_HISTOGRAM_H_
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc
new file mode 100644
index 0000000..c29dd5e
--- /dev/null
+++ b/base/metrics/sparse_histogram_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sample_map.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class SparseHistogramTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override { UninitializeStatisticsRecorder(); }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) {
+    return scoped_ptr<SparseHistogram>(new SparseHistogram(name));
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(SparseHistogramTest, BasicTest) {
+  scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->Add(100);
+  scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot1->TotalCount());
+  EXPECT_EQ(1, snapshot1->GetCount(100));
+
+  histogram->Add(100);
+  histogram->Add(101);
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(3, snapshot2->TotalCount());
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(1, snapshot2->GetCount(101));
+}
+
+TEST_F(SparseHistogramTest, MacroBasicTest) {
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
+
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+
+  ASSERT_EQ(1U, histograms.size());
+  HistogramBase* sparse_histogram = histograms[0];
+
+  EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType());
+  EXPECT_EQ("Sparse", sparse_histogram->histogram_name());
+  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag,
+            sparse_histogram->flags());
+
+  scoped_ptr<HistogramSamples> samples = sparse_histogram->SnapshotSamples();
+  EXPECT_EQ(3, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(100));
+  EXPECT_EQ(1, samples->GetCount(200));
+}
+
+TEST_F(SparseHistogramTest, MacroInLoopTest) {
+  // Unlike the macros in histogram.h, SparseHistogram macros can have a
+  // variable as histogram name.
+  for (int i = 0; i < 2; i++) {
+    std::string name = StringPrintf("Sparse%d", i + 1);
+    UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100);
+  }
+
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+  ASSERT_EQ(2U, histograms.size());
+
+  std::string name1 = histograms[0]->histogram_name();
+  std::string name2 = histograms[1]->histogram_name();
+  EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) ||
+              ("Sparse2" == name1 && "Sparse1" == name2));
+}
+
+TEST_F(SparseHistogramTest, Serialize) {
+  scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  histogram->SerializeInfo(&pickle);
+
+  PickleIterator iter(pickle);
+
+  int type;
+  EXPECT_TRUE(iter.ReadInt(&type));
+  EXPECT_EQ(SPARSE_HISTOGRAM, type);
+
+  std::string name;
+  EXPECT_TRUE(iter.ReadString(&name));
+  EXPECT_EQ("Sparse", name);
+
+  int flag;
+  EXPECT_TRUE(iter.ReadInt(&flag));
+  EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
+
+  // No more data in the pickle.
+  EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
new file mode 100644
index 0000000..39ecc30
--- /dev/null
+++ b/base/metrics/statistics_recorder.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/statistics_recorder.h"
+
+#include "base/at_exit.h"
+#include "base/debug/leak_annotations.h"
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+
+using std::list;
+using std::string;
+
+namespace {
+// Initialize histogram statistics gathering system.
+base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
+    LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+namespace base {
+
+// static
+void StatisticsRecorder::Initialize() {
+  // Ensure that an instance of the StatisticsRecorder object is created.
+  g_statistics_recorder_.Get();
+}
+
+// static
+bool StatisticsRecorder::IsActive() {
+  if (lock_ == NULL)
+    return false;
+  base::AutoLock auto_lock(*lock_);
+  return NULL != histograms_;
+}
+
+// static
+HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
+    HistogramBase* histogram) {
+  // As per crbug.com/79322 the histograms are intentionally leaked, so we need
+  // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once
+  // for an object, the duplicates should not be annotated.
+  // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
+  // twice if (lock_ == NULL) || (!histograms_).
+  if (lock_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+    return histogram;
+  }
+
+  HistogramBase* histogram_to_delete = NULL;
+  HistogramBase* histogram_to_return = NULL;
+  {
+    base::AutoLock auto_lock(*lock_);
+    if (histograms_ == NULL) {
+      histogram_to_return = histogram;
+    } else {
+      const string& name = histogram->histogram_name();
+      HistogramMap::iterator it = histograms_->find(name);
+      if (histograms_->end() == it) {
+        (*histograms_)[name] = histogram;
+        ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+        histogram_to_return = histogram;
+      } else if (histogram == it->second) {
+        // The histogram was registered before.
+        histogram_to_return = histogram;
+      } else {
+        // We already have one histogram with this name.
+        histogram_to_return = it->second;
+        histogram_to_delete = histogram;
+      }
+    }
+  }
+  delete histogram_to_delete;
+  return histogram_to_return;
+}
+
+// static
+const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
+    const BucketRanges* ranges) {
+  DCHECK(ranges->HasValidChecksum());
+  scoped_ptr<const BucketRanges> ranges_deleter;
+
+  if (lock_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
+    return ranges;
+  }
+
+  base::AutoLock auto_lock(*lock_);
+  if (ranges_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
+    return ranges;
+  }
+
+  list<const BucketRanges*>* checksum_matching_list;
+  RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
+  if (ranges_->end() == ranges_it) {
+    // Add a new matching list to map.
+    checksum_matching_list = new list<const BucketRanges*>();
+    ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
+    (*ranges_)[ranges->checksum()] = checksum_matching_list;
+  } else {
+    checksum_matching_list = ranges_it->second;
+  }
+
+  list<const BucketRanges*>::iterator checksum_matching_list_it;
+  for (checksum_matching_list_it = checksum_matching_list->begin();
+       checksum_matching_list_it != checksum_matching_list->end();
+       ++checksum_matching_list_it) {
+    const BucketRanges* existing_ranges = *checksum_matching_list_it;
+    if (existing_ranges->Equals(ranges)) {
+      if (existing_ranges == ranges) {
+        return ranges;
+      } else {
+        ranges_deleter.reset(ranges);
+        return existing_ranges;
+      }
+    }
+  }
+  // We haven't found a BucketRanges which has the same ranges. Register the
+  // new BucketRanges.
+  checksum_matching_list->push_front(ranges);
+  return ranges;
+}
+
+// static
+void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
+                                        std::string* output) {
+  if (!IsActive())
+    return;
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  for (Histograms::iterator it = snapshot.begin();
+       it != snapshot.end();
+       ++it) {
+    (*it)->WriteHTMLGraph(output);
+    output->append("<br><hr><br>");
+  }
+}
+
+// static
+void StatisticsRecorder::WriteGraph(const std::string& query,
+                                    std::string* output) {
+  if (!IsActive())
+    return;
+  if (query.length())
+    StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
+  else
+    output->append("Collections of all histograms\n");
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  for (Histograms::iterator it = snapshot.begin();
+       it != snapshot.end();
+       ++it) {
+    (*it)->WriteAscii(output);
+    output->append("\n");
+  }
+}
+
+// static
+std::string StatisticsRecorder::ToJSON(const std::string& query) {
+  if (!IsActive())
+    return std::string();
+
+  std::string output("{");
+  if (!query.empty()) {
+    output += "\"query\":";
+    EscapeJSONString(query, true, &output);
+    output += ",";
+  }
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  output += "\"histograms\":[";
+  bool first_histogram = true;
+  for (Histograms::const_iterator it = snapshot.begin(); it != snapshot.end();
+       ++it) {
+    if (first_histogram)
+      first_histogram = false;
+    else
+      output += ",";
+    std::string json;
+    (*it)->WriteJSON(&json);
+    output += json;
+  }
+  output += "]}";
+  return output;
+}
+
+// static
+void StatisticsRecorder::GetHistograms(Histograms* output) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  for (HistogramMap::iterator it = histograms_->begin();
+       histograms_->end() != it;
+       ++it) {
+    DCHECK_EQ(it->first, it->second->histogram_name());
+    output->push_back(it->second);
+  }
+}
+
+// static
+void StatisticsRecorder::GetBucketRanges(
+    std::vector<const BucketRanges*>* output) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (ranges_ == NULL)
+    return;
+
+  for (RangesMap::iterator it = ranges_->begin();
+       ranges_->end() != it;
+       ++it) {
+    list<const BucketRanges*>* ranges_list = it->second;
+    list<const BucketRanges*>::iterator ranges_list_it;
+    for (ranges_list_it = ranges_list->begin();
+         ranges_list_it != ranges_list->end();
+         ++ranges_list_it) {
+      output->push_back(*ranges_list_it);
+    }
+  }
+}
+
+// static
+HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) {
+  if (lock_ == NULL)
+    return NULL;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return NULL;
+
+  HistogramMap::iterator it = histograms_->find(name);
+  if (histograms_->end() == it)
+    return NULL;
+  return it->second;
+}
+
+// private static
+void StatisticsRecorder::GetSnapshot(const std::string& query,
+                                     Histograms* snapshot) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  for (HistogramMap::iterator it = histograms_->begin();
+       histograms_->end() != it;
+       ++it) {
+    if (it->first.find(query) != std::string::npos)
+      snapshot->push_back(it->second);
+  }
+}
+
+// This singleton instance should be started during the single threaded portion
+// of main(), and hence it is not thread safe.  It initializes globals to
+// provide support for all future calls.
+StatisticsRecorder::StatisticsRecorder() {
+  DCHECK(!histograms_);
+  if (lock_ == NULL) {
+    // This will leak on purpose. It's the only way to make sure we won't race
+    // against the static uninitialization of the module while one of our
+    // static methods relying on the lock get called at an inappropriate time
+    // during the termination phase. Since it's a static data member, we will
+    // leak one per process, which would be similar to the instance allocated
+    // during static initialization and released only on  process termination.
+    lock_ = new base::Lock;
+  }
+  base::AutoLock auto_lock(*lock_);
+  histograms_ = new HistogramMap;
+  ranges_ = new RangesMap;
+
+  if (VLOG_IS_ON(1))
+    AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
+}
+
+// static
+void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
+  DCHECK(VLOG_IS_ON(1));
+
+  string output;
+  StatisticsRecorder::WriteGraph(std::string(), &output);
+  VLOG(1) << output;
+}
+
+StatisticsRecorder::~StatisticsRecorder() {
+  DCHECK(histograms_ && ranges_ && lock_);
+
+  // Clean up.
+  scoped_ptr<HistogramMap> histograms_deleter;
+  scoped_ptr<RangesMap> ranges_deleter;
+  // We don't delete lock_ on purpose to avoid having to properly protect
+  // against it going away after we checked for NULL in the static methods.
+  {
+    base::AutoLock auto_lock(*lock_);
+    histograms_deleter.reset(histograms_);
+    ranges_deleter.reset(ranges_);
+    histograms_ = NULL;
+    ranges_ = NULL;
+  }
+  // We are going to leak the histograms and the ranges.
+}
+
+
+// static
+StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
+// static
+StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
+// static
+base::Lock* StatisticsRecorder::lock_ = NULL;
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
new file mode 100644
index 0000000..b523057
--- /dev/null
+++ b/base/metrics/statistics_recorder.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// StatisticsRecorder holds all Histograms and BucketRanges that are used by
+// Histograms in the system. It provides a general place for
+// Histograms/BucketRanges to register, and supports a global API for accessing
+// (i.e., dumping, or graphing) the data.
+
+#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
+#define BASE_METRICS_STATISTICS_RECORDER_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+
+namespace base {
+
+class BucketRanges;
+class HistogramBase;
+class Lock;
+
+class BASE_EXPORT StatisticsRecorder {
+ public:
+  typedef std::vector<HistogramBase*> Histograms;
+
+  // Initializes the StatisticsRecorder system. Safe to call multiple times.
+  static void Initialize();
+
+  // Find out if histograms can now be registered into our list.
+  static bool IsActive();
+
+  // Register, or add a new histogram to the collection of statistics. If an
+  // identically named histogram is already registered, then the argument
+  // |histogram| will deleted.  The returned value is always the registered
+  // histogram (either the argument, or the pre-existing registered histogram).
+  static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);
+
+  // Register, or add a new BucketRanges. If an identically BucketRanges is
+  // already registered, then the argument |ranges| will deleted. The returned
+  // value is always the registered BucketRanges (either the argument, or the
+  // pre-existing one).
+  static const BucketRanges* RegisterOrDeleteDuplicateRanges(
+      const BucketRanges* ranges);
+
+  // Methods for appending histogram data to a string.  Only histograms which
+  // have |query| as a substring are written to |output| (an empty string will
+  // process all registered histograms).
+  static void WriteHTMLGraph(const std::string& query, std::string* output);
+  static void WriteGraph(const std::string& query, std::string* output);
+
+  // Returns the histograms with |query| as a substring as JSON text (an empty
+  // |query| will process all registered histograms).
+  static std::string ToJSON(const std::string& query);
+
+  // Method for extracting histograms which were marked for use by UMA.
+  static void GetHistograms(Histograms* output);
+
+  // Method for extracting BucketRanges used by all histograms registered.
+  static void GetBucketRanges(std::vector<const BucketRanges*>* output);
+
+  // Find a histogram by name. It matches the exact name. This method is thread
+  // safe.  It returns NULL if a matching histogram is not found.
+  static HistogramBase* FindHistogram(const std::string& name);
+
+  // GetSnapshot copies some of the pointers to registered histograms into the
+  // caller supplied vector (Histograms). Only histograms which have |query| as
+  // a substring are copied (an empty string will process all registered
+  // histograms).
+  static void GetSnapshot(const std::string& query, Histograms* snapshot);
+
+ private:
+  // We keep all registered histograms in a map, from name to histogram.
+  typedef std::map<std::string, HistogramBase*> HistogramMap;
+
+  // We keep all |bucket_ranges_| in a map, from checksum to a list of
+  // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
+  // |bucket_ranges_|.
+  typedef std::map<uint32, std::list<const BucketRanges*>*> RangesMap;
+
+  friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
+  friend class HistogramBaseTest;
+  friend class HistogramSnapshotManagerTest;
+  friend class HistogramTest;
+  friend class JsonPrefStoreTest;
+  friend class SparseHistogramTest;
+  friend class StatisticsRecorderTest;
+  FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
+                           DeserializeHistogramAndAddSamples);
+
+  // The constructor just initializes static members. Usually client code should
+  // use Initialize to do this. But in test code, you can friend this class and
+  // call destructor/constructor to get a clean StatisticsRecorder.
+  StatisticsRecorder();
+  ~StatisticsRecorder();
+
+  static void DumpHistogramsToVlog(void* instance);
+
+  static HistogramMap* histograms_;
+  static RangesMap* ranges_;
+
+  // Lock protects access to above maps.
+  static base::Lock* lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_STATISTICS_RECORDER_H_
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
new file mode 100644
index 0000000..e653bf3
--- /dev/null
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -0,0 +1,315 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class StatisticsRecorderTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override { UninitializeStatisticsRecorder(); }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  Histogram* CreateHistogram(const std::string& name,
+                             HistogramBase::Sample min,
+                             HistogramBase::Sample max,
+                             size_t bucket_count) {
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    Histogram::InitializeBucketRanges(min, max, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+    return new Histogram(name, min, max, registered_ranges);
+  }
+
+  void DeleteHistogram(HistogramBase* histogram) {
+    delete histogram;
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(StatisticsRecorderTest, NotInitialized) {
+  UninitializeStatisticsRecorder();
+
+  ASSERT_FALSE(StatisticsRecorder::IsActive());
+
+  StatisticsRecorder::Histograms registered_histograms;
+  std::vector<const BucketRanges*> registered_ranges;
+
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(0u, registered_histograms.size());
+
+  Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
+
+  // When StatisticsRecorder is not initialized, register is a noop.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  // Manually delete histogram that was not registered.
+  DeleteHistogram(histogram);
+
+  // RegisterOrDeleteDuplicateRanges is a no-op.
+  BucketRanges* ranges = new BucketRanges(3);;
+  ranges->ResetChecksum();
+  EXPECT_EQ(ranges,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  EXPECT_EQ(0u, registered_ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
+  std::vector<const BucketRanges*> registered_ranges;
+
+  BucketRanges* ranges1 = new BucketRanges(3);;
+  ranges1->ResetChecksum();
+  BucketRanges* ranges2 = new BucketRanges(4);;
+  ranges2->ResetChecksum();
+
+  // Register new ranges.
+  EXPECT_EQ(ranges1,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
+  EXPECT_EQ(ranges2,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2));
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+
+  // Register some ranges again.
+  EXPECT_EQ(ranges1,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
+  registered_ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+  // Make sure the ranges is still the one we know.
+  ASSERT_EQ(3u, ranges1->size());
+  EXPECT_EQ(0, ranges1->range(0));
+  EXPECT_EQ(0, ranges1->range(1));
+  EXPECT_EQ(0, ranges1->range(2));
+
+  // Register ranges with same values.
+  BucketRanges* ranges3 = new BucketRanges(3);;
+  ranges3->ResetChecksum();
+  EXPECT_EQ(ranges1,  // returning ranges1
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
+  registered_ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogram) {
+  // Create a Histogram that was not registered.
+  Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
+
+  StatisticsRecorder::Histograms registered_histograms;
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(0u, registered_histograms.size());
+
+  // Register the Histogram.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+
+  // Register the same Histogram again.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, FindHistogram) {
+  HistogramBase* histogram1 = Histogram::FactoryGet(
+      "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags);
+  HistogramBase* histogram2 = Histogram::FactoryGet(
+      "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags);
+
+  EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
+  EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
+  EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram") == NULL);
+}
+
+TEST_F(StatisticsRecorderTest, GetSnapshot) {
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
+
+  StatisticsRecorder::Histograms snapshot;
+  StatisticsRecorder::GetSnapshot("Test", &snapshot);
+  EXPECT_EQ(3u, snapshot.size());
+
+  snapshot.clear();
+  StatisticsRecorder::GetSnapshot("1", &snapshot);
+  EXPECT_EQ(1u, snapshot.size());
+
+  snapshot.clear();
+  StatisticsRecorder::GetSnapshot("hello", &snapshot);
+  EXPECT_EQ(0u, snapshot.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
+  StatisticsRecorder::Histograms registered_histograms;
+
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  ASSERT_EQ(0u, registered_histograms.size());
+
+  // Create a histogram.
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+
+  // Get an existing histogram.
+  HistogramBase* histogram2 = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+  EXPECT_EQ(histogram, histogram2);
+
+  // Create a LinearHistogram.
+  histogram = LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(2u, registered_histograms.size());
+
+  // Create a BooleanHistogram.
+  histogram = BooleanHistogram::FactoryGet(
+      "TestBooleanHistogram", HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(3u, registered_histograms.size());
+
+  // Create a CustomHistogram.
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(5);
+  histogram = CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(4u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogramWithMacros) {
+  StatisticsRecorder::Histograms registered_histograms;
+
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags);
+
+  // The histogram we got from macro is the same as from FactoryGet.
+  LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  ASSERT_EQ(1u, registered_histograms.size());
+  EXPECT_EQ(histogram, registered_histograms[0]);
+
+  LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1));
+  LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
+
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(3u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, BucketRangesSharing) {
+  std::vector<const BucketRanges*> ranges;
+  StatisticsRecorder::GetBucketRanges(&ranges);
+  EXPECT_EQ(0u, ranges.size());
+
+  Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags);
+  Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags);
+
+  StatisticsRecorder::GetBucketRanges(&ranges);
+  EXPECT_EQ(1u, ranges.size());
+
+  Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags);
+
+  ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&ranges);
+  EXPECT_EQ(2u, ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, ToJSON) {
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 30);
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 40);
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 30);
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 40);
+
+  std::string json(StatisticsRecorder::ToJSON(std::string()));
+
+  // Check for valid JSON.
+  scoped_ptr<Value> root;
+  root.reset(JSONReader::Read(json));
+  ASSERT_TRUE(root.get());
+
+  DictionaryValue* root_dict = NULL;
+  ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+  // No query should be set.
+  ASSERT_FALSE(root_dict->HasKey("query"));
+
+  ListValue* histogram_list = NULL;
+  ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
+  ASSERT_EQ(2u, histogram_list->GetSize());
+
+  // Examine the first histogram.
+  DictionaryValue* histogram_dict = NULL;
+  ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
+
+  int sample_count;
+  ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count));
+  EXPECT_EQ(2, sample_count);
+
+  // Test the query filter.
+  std::string query("TestHistogram2");
+  json = StatisticsRecorder::ToJSON(query);
+
+  root.reset(JSONReader::Read(json));
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+  std::string query_value;
+  ASSERT_TRUE(root_dict->GetString("query", &query_value));
+  EXPECT_EQ(query, query_value);
+
+  ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
+  ASSERT_EQ(1u, histogram_list->GetSize());
+
+  ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
+
+  std::string histogram_name;
+  ASSERT_TRUE(histogram_dict->GetString("name", &histogram_name));
+  EXPECT_EQ("TestHistogram2", histogram_name);
+
+  json.clear();
+  UninitializeStatisticsRecorder();
+
+  // No data should be returned.
+  json = StatisticsRecorder::ToJSON(query);
+  EXPECT_TRUE(json.empty());
+}
+
+}  // namespace base
diff --git a/base/metrics/user_metrics.cc b/base/metrics/user_metrics.cc
new file mode 100644
index 0000000..9db5840
--- /dev/null
+++ b/base/metrics/user_metrics.cc
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/user_metrics.h"
+
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+namespace {
+
+// A helper class for tracking callbacks and ensuring thread-safety.
+class Callbacks {
+ public:
+  Callbacks() {}
+
+  // Records the |action|.
+  void Record(const std::string& action) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    for (size_t i = 0; i < callbacks_.size(); ++i) {
+      callbacks_[i].Run(action);
+    }
+  }
+
+  // Adds |callback| to the list of |callbacks_|.
+  void AddCallback(const ActionCallback& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    callbacks_.push_back(callback);
+  }
+
+  // Removes the first instance of |callback| from the list of |callbacks_|, if
+  // there is one.
+  void RemoveCallback(const ActionCallback& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    for (size_t i = 0; i < callbacks_.size(); ++i) {
+      if (callbacks_[i].Equals(callback)) {
+        callbacks_.erase(callbacks_.begin() + i);
+        return;
+      }
+    }
+  }
+
+ private:
+  base::ThreadChecker thread_checker_;
+  std::vector<ActionCallback> callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(Callbacks);
+};
+
+base::LazyInstance<Callbacks> g_callbacks = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+void RecordAction(const UserMetricsAction& action) {
+  g_callbacks.Get().Record(action.str_);
+}
+
+void RecordComputedAction(const std::string& action) {
+  g_callbacks.Get().Record(action);
+}
+
+void AddActionCallback(const ActionCallback& callback) {
+  g_callbacks.Get().AddCallback(callback);
+}
+
+void RemoveActionCallback(const ActionCallback& callback) {
+  g_callbacks.Get().RemoveCallback(callback);
+
+}
+
+}  // namespace base
diff --git a/base/metrics/user_metrics.h b/base/metrics/user_metrics.h
new file mode 100644
index 0000000..bcfefb8
--- /dev/null
+++ b/base/metrics/user_metrics.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_USER_METRICS_H_
+#define BASE_METRICS_USER_METRICS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/metrics/user_metrics_action.h"
+
+namespace base {
+
+// This module provides some helper functions for logging actions tracked by
+// the user metrics system.
+
+// Record that the user performed an action.
+// This method *must* be called from the main thread.
+//
+// "Action" here means a user-generated event:
+//   good: "Reload", "CloseTab", and "IMEInvoked"
+//   not good: "SSLDialogShown", "PageLoaded", "DiskFull"
+// We use this to gather anonymized information about how users are
+// interacting with the browser.
+// WARNING: In calls to this function, UserMetricsAction and a
+// string literal parameter must be on the same line, e.g.
+//   RecordAction(UserMetricsAction("my extremely long action name"));
+// This ensures that our processing scripts can associate this action's hash
+// with its metric name. Therefore, it will be possible to retrieve the metric
+// name from the hash later on.
+//
+// Once a new recorded action is added, run
+//   tools/metrics/actions/extract_actions.py
+// to add the metric to actions.xml, then update the <owner>s and <description>
+// sections. Make sure to include the actions.xml file when you upload your code
+// for review!
+//
+// For more complicated situations (like when there are many different
+// possible actions), see RecordComputedAction.
+BASE_EXPORT void RecordAction(const UserMetricsAction& action);
+
+// This function has identical input and behavior to RecordAction, but is
+// not automatically found by the action-processing scripts.  It can be used
+// when it's a pain to enumerate all possible actions, but if you use this
+// you need to also update the rules for extracting known actions in
+// tools/metrics/actions/extract_actions.py.
+BASE_EXPORT void RecordComputedAction(const std::string& action);
+
+// Called with the action string.
+typedef base::Callback<void(const std::string&)> ActionCallback;
+
+// Add/remove action callbacks (see above).
+BASE_EXPORT void AddActionCallback(const ActionCallback& callback);
+BASE_EXPORT void RemoveActionCallback(const ActionCallback& callback);
+
+}  // namespace base
+
+#endif  // BASE_METRICS_USER_METRICS_H_
diff --git a/base/metrics/user_metrics_action.h b/base/metrics/user_metrics_action.h
new file mode 100644
index 0000000..8c195b3
--- /dev/null
+++ b/base/metrics/user_metrics_action.h
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_USER_METRICS_ACTION_H_
+#define BASE_METRICS_USER_METRICS_ACTION_H_
+
+namespace base {
+
+// UserMetricsAction exists purely to standardize on the parameters passed to
+// UserMetrics. That way, our toolset can scan the source code reliable for
+// constructors and extract the associated string constants.
+// WARNING: When using UserMetricsAction, UserMetricsAction and a string literal
+// parameter must be on the same line, e.g.
+//   RecordAction(UserMetricsAction("my extremely long action name"));
+// or
+//   RenderThread::Get()->RecordAction(
+//       UserMetricsAction("my extremely long action name"));
+// because otherwise our processing scripts won't pick up on new actions.
+// Please see tools/metrics/actions/extract_actions.py for details.
+struct UserMetricsAction {
+  const char* str_;
+  explicit UserMetricsAction(const char* str) : str_(str) {}
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_USER_METRICS_ACTION_H_
diff --git a/base/move.h b/base/move.h
new file mode 100644
index 0000000..87dc52d
--- /dev/null
+++ b/base/move.h
@@ -0,0 +1,234 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MOVE_H_
+#define BASE_MOVE_H_
+
+#include "base/compiler_specific.h"
+
+// Macro with the boilerplate that makes a type move-only in C++03.
+//
+// USAGE
+//
+// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
+// a "move-only" type.  Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
+// the first line in a class declaration.
+//
+// A class using this macro must call .Pass() (or somehow be an r-value already)
+// before it can be:
+//
+//   * Passed as a function argument
+//   * Used as the right-hand side of an assignment
+//   * Returned from a function
+//
+// Each class will still need to define their own "move constructor" and "move
+// operator=" to make this useful.  Here's an example of the macro, the move
+// constructor, and the move operator= from the scoped_ptr class:
+//
+//  template <typename T>
+//  class scoped_ptr {
+//     MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+//   public:
+//    scoped_ptr(RValue& other) : ptr_(other.release()) { }
+//    scoped_ptr& operator=(RValue& other) {
+//      swap(other);
+//      return *this;
+//    }
+//  };
+//
+// Note that the constructor must NOT be marked explicit.
+//
+// For consistency, the second parameter to the macro should always be RValue
+// unless you have a strong reason to do otherwise.  It is only exposed as a
+// macro parameter so that the move constructor and move operator= don't look
+// like they're using a phantom type.
+//
+//
+// HOW THIS WORKS
+//
+// For a thorough explanation of this technique, see:
+//
+//   http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
+//
+// The summary is that we take advantage of 2 properties:
+//
+//   1) non-const references will not bind to r-values.
+//   2) C++ can apply one user-defined conversion when initializing a
+//      variable.
+//
+// The first lets us disable the copy constructor and assignment operator
+// by declaring private version of them with a non-const reference parameter.
+//
+// For l-values, direct initialization still fails like in
+// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
+// operators are private.
+//
+// For r-values, the situation is different. The copy constructor and
+// assignment operator are not viable due to (1), so we are trying to call
+// a non-existent constructor and non-existing operator= rather than a private
+// one.  Since we have not committed an error quite yet, we can provide an
+// alternate conversion sequence and a constructor.  We add
+//
+//   * a private struct named "RValue"
+//   * a user-defined conversion "operator RValue()"
+//   * a "move constructor" and "move operator=" that take the RValue& as
+//     their sole parameter.
+//
+// Only r-values will trigger this sequence and execute our "move constructor"
+// or "move operator=."  L-values will match the private copy constructor and
+// operator= first giving a "private in this context" error.  This combination
+// gives us a move-only type.
+//
+// For signaling a destructive transfer of data from an l-value, we provide a
+// method named Pass() which creates an r-value for the current instance
+// triggering the move constructor or move operator=.
+//
+// Other ways to get r-values is to use the result of an expression like a
+// function call.
+//
+// Here's an example with comments explaining what gets triggered where:
+//
+//    class Foo {
+//      MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
+//
+//     public:
+//       ... API ...
+//       Foo(RValue other);           // Move constructor.
+//       Foo& operator=(RValue rhs);  // Move operator=
+//    };
+//
+//    Foo MakeFoo();  // Function that returns a Foo.
+//
+//    Foo f;
+//    Foo f_copy(f);  // ERROR: Foo(Foo&) is private in this context.
+//    Foo f_assign;
+//    f_assign = f;   // ERROR: operator=(Foo&) is private in this context.
+//
+//
+//    Foo f(MakeFoo());      // R-value so alternate conversion executed.
+//    Foo f_copy(f.Pass());  // R-value so alternate conversion executed.
+//    f = f_copy.Pass();     // R-value so alternate conversion executed.
+//
+//
+// IMPLEMENTATION SUBTLETIES WITH RValue
+//
+// The RValue struct is just a container for a pointer back to the original
+// object. It should only ever be created as a temporary, and no external
+// class should ever declare it or use it in a parameter.
+//
+// It is tempting to want to use the RValue type in function parameters, but
+// excluding the limited usage here for the move constructor and move
+// operator=, doing so would mean that the function could take both r-values
+// and l-values equially which is unexpected.  See COMPARED To Boost.Move for
+// more details.
+//
+// An alternate, and incorrect, implementation of the RValue class used by
+// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
+// is then used in place of RValue in the various operators.  The RValue& is
+// "created" by doing *reinterpret_cast<RValue*>(this).  This has the appeal
+// of never creating a temporary RValue struct even with optimizations
+// disabled.  Also, by virtue of inheritance you can treat the RValue
+// reference as if it were the move-only type itself.  Unfortunately,
+// using the result of this reinterpret_cast<> is actually undefined behavior
+// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
+// will generate non-working code.
+//
+// In optimized builds, both implementations generate the same assembly so we
+// choose the one that adheres to the standard.
+//
+//
+// WHY HAVE typedef void MoveOnlyTypeForCPP03
+//
+// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
+// to call .Pass() appropriately when it is expected to transfer the value.
+// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
+// easy and automatic in helper templates for Callback<>/Bind().
+// See IsMoveOnlyType template and its usage in base/callback_internal.h
+// for more details.
+//
+//
+// COMPARED TO C++11
+//
+// In C++11, you would implement this functionality using an r-value reference
+// and our .Pass() method would be replaced with a call to std::move().
+//
+// This emulation also has a deficiency where it uses up the single
+// user-defined conversion allowed by C++ during initialization.  This can
+// cause problems in some API edge cases.  For instance, in scoped_ptr, it is
+// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
+// value of type scoped_ptr<Child> even if you add a constructor to
+// scoped_ptr<> that would make it look like it should work.  C++11 does not
+// have this deficiency.
+//
+//
+// COMPARED TO Boost.Move
+//
+// Our implementation similar to Boost.Move, but we keep the RValue struct
+// private to the move-only type, and we don't use the reinterpret_cast<> hack.
+//
+// In Boost.Move, RValue is the boost::rv<> template.  This type can be used
+// when writing APIs like:
+//
+//   void MyFunc(boost::rv<Foo>& f)
+//
+// that can take advantage of rv<> to avoid extra copies of a type.  However you
+// would still be able to call this version of MyFunc with an l-value:
+//
+//   Foo f;
+//   MyFunc(f);  // Uh oh, we probably just destroyed |f| w/o calling Pass().
+//
+// unless someone is very careful to also declare a parallel override like:
+//
+//   void MyFunc(const Foo& f)
+//
+// that would catch the l-values first.  This was declared unsafe in C++11 and
+// a C++11 compiler will explicitly fail MyFunc(f).  Unfortunately, we cannot
+// ensure this in C++03.
+//
+// Since we have no need for writing such APIs yet, our implementation keeps
+// RValue private and uses a .Pass() method to do the conversion instead of
+// trying to write a version of "std::move()." Writing an API like std::move()
+// would require the RValue struct to be public.
+//
+//
+// CAVEATS
+//
+// If you include a move-only type as a field inside a class that does not
+// explicitly declare a copy constructor, the containing class's implicit
+// copy constructor will change from Containing(const Containing&) to
+// Containing(Containing&).  This can cause some unexpected errors.
+//
+//   http://llvm.org/bugs/show_bug.cgi?id=11528
+//
+// The workaround is to explicitly declare your copy constructor.
+//
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+ private: \
+  struct rvalue_type { \
+    explicit rvalue_type(type* object) : object(object) {} \
+    type* object; \
+  }; \
+  type(type&); \
+  void operator=(type&); \
+ public: \
+  operator rvalue_type() { return rvalue_type(this); } \
+  type Pass() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \
+  typedef void MoveOnlyTypeForCPP03; \
+ private:
+
+#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
+ private: \
+  type(const type&); \
+  void operator=(const type&); \
+ public: \
+  type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+  typedef void MoveOnlyTypeForCPP03; \
+ private:
+
+#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
+ public: \
+  type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+ private:
+
+#endif  // BASE_MOVE_H_
diff --git a/base/move_unittest.cc b/base/move_unittest.cc
new file mode 100644
index 0000000..1f4ce84
--- /dev/null
+++ b/base/move_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/move.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MoveOnly {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(MoveOnly)
+
+ public:
+  MoveOnly() {}
+
+  MoveOnly(MoveOnly&& other) {}
+  MoveOnly& operator=(MoveOnly&& other) { return *this; }
+};
+
+class Container {
+ public:
+  Container() = default;
+  Container(const Container& other) = default;
+  Container& operator=(const Container& other) = default;
+
+  Container(Container&& other) { value_ = other.value_.Pass(); }
+
+  Container& operator=(Container&& other) {
+    value_ = other.value_.Pass();
+    return *this;
+  }
+
+ private:
+  MoveOnly value_;
+};
+
+Container GetContainerRvalue() {
+  Container x;
+  return x;
+}
+
+TEST(MoveTest, CopyableContainerCanBeMoved) {
+  // Container should be move-constructible and move-assignable.
+  Container y = GetContainerRvalue();
+  y = GetContainerRvalue();
+}
+
+}  // namespace
diff --git a/base/native_library.h b/base/native_library.h
new file mode 100644
index 0000000..1e764da
--- /dev/null
+++ b/base/native_library.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NATIVE_LIBRARY_H_
+#define BASE_NATIVE_LIBRARY_H_
+
+// This file defines a cross-platform "NativeLibrary" type which represents
+// a loadable module.
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#import <CoreFoundation/CoreFoundation.h>
+#endif  // OS_*
+
+namespace base {
+
+class FilePath;
+
+#if defined(OS_WIN)
+typedef HMODULE NativeLibrary;
+#elif defined(OS_MACOSX)
+enum NativeLibraryType {
+  BUNDLE,
+  DYNAMIC_LIB
+};
+enum NativeLibraryObjCStatus {
+  OBJC_UNKNOWN,
+  OBJC_PRESENT,
+  OBJC_NOT_PRESENT,
+};
+struct NativeLibraryStruct {
+  NativeLibraryType type;
+  CFBundleRefNum bundle_resource_ref;
+  NativeLibraryObjCStatus objc_status;
+  union {
+    CFBundleRef bundle;
+    void* dylib;
+  };
+};
+typedef NativeLibraryStruct* NativeLibrary;
+#elif defined(OS_POSIX)
+typedef void* NativeLibrary;
+#endif  // OS_*
+
+struct BASE_EXPORT NativeLibraryLoadError {
+#if defined(OS_WIN)
+  NativeLibraryLoadError() : code(0) {}
+#endif  // OS_WIN
+
+  // Returns a string representation of the load error.
+  std::string ToString() const;
+
+#if defined(OS_WIN)
+  DWORD code;
+#else
+  std::string message;
+#endif  // OS_WIN
+};
+
+// Loads a native library from disk.  Release it with UnloadNativeLibrary when
+// you're done.  Returns NULL on failure.
+// If |error| is not NULL, it may be filled in on load error.
+BASE_EXPORT NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                            NativeLibraryLoadError* error);
+
+#if defined(OS_WIN)
+// Loads a native library from disk.  Release it with UnloadNativeLibrary when
+// you're done.
+// This function retrieves the LoadLibrary function exported from kernel32.dll
+// and calls it instead of directly calling the LoadLibrary function via the
+// import table.
+BASE_EXPORT NativeLibrary LoadNativeLibraryDynamically(
+    const FilePath& library_path);
+#endif  // OS_WIN
+
+// Unloads a native library.
+BASE_EXPORT void UnloadNativeLibrary(NativeLibrary library);
+
+// Gets a function pointer from a native library.
+BASE_EXPORT void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                                      const char* name);
+
+// Returns the full platform specific name for a native library.
+// For example:
+// "mylib" returns "mylib.dll" on Windows, "libmylib.so" on Linux,
+// "mylib.dylib" on Mac.
+BASE_EXPORT string16 GetNativeLibraryName(const string16& name);
+
+}  // namespace base
+
+#endif  // BASE_NATIVE_LIBRARY_H_
diff --git a/base/native_library_ios.mm b/base/native_library_ios.mm
new file mode 100644
index 0000000..030c171
--- /dev/null
+++ b/base/native_library_ios.mm
@@ -0,0 +1,40 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/native_library.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+std::string NativeLibraryLoadError::ToString() const {
+  return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  NOTIMPLEMENTED();
+  DCHECK(!library);
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name;
+}
+
+}  // namespace base
diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm
new file mode 100644
index 0000000..8122c28
--- /dev/null
+++ b/base/native_library_mac.mm
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/native_library.h"
+
+#include <dlfcn.h>
+#include <mach-o/getsect.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+static NativeLibraryObjCStatus GetObjCStatusForImage(
+    const void* function_pointer) {
+  Dl_info info;
+  if (!dladdr(function_pointer, &info))
+    return OBJC_UNKNOWN;
+
+  // See if the the image contains an "ObjC image info" segment. This method
+  // of testing is used in _CFBundleGrokObjcImageInfoFromFile in
+  // CF-744/CFBundle.c, around lines 2447-2474.
+  //
+  // In 32-bit images, ObjC can be recognized in __OBJC,__image_info, whereas
+  // in 64-bit, the data is in __DATA,__objc_imageinfo.
+#if __LP64__
+  const section_64* section = getsectbynamefromheader_64(
+      reinterpret_cast<const struct mach_header_64*>(info.dli_fbase),
+      SEG_DATA, "__objc_imageinfo");
+#else
+  const section* section = getsectbynamefromheader(
+      reinterpret_cast<const struct mach_header*>(info.dli_fbase),
+      SEG_OBJC, "__image_info");
+#endif
+  return section == NULL ? OBJC_NOT_PRESENT : OBJC_PRESENT;
+}
+
+std::string NativeLibraryLoadError::ToString() const {
+  return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  // dlopen() etc. open the file off disk.
+  if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) {
+    void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
+    if (!dylib) {
+      error->message = dlerror();
+      return NULL;
+    }
+    NativeLibrary native_lib = new NativeLibraryStruct();
+    native_lib->type = DYNAMIC_LIB;
+    native_lib->dylib = dylib;
+    native_lib->objc_status = OBJC_UNKNOWN;
+    return native_lib;
+  }
+  base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
+      kCFAllocatorDefault,
+      (const UInt8*)library_path.value().c_str(),
+      library_path.value().length(),
+      true));
+  if (!url)
+    return NULL;
+  CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
+  if (!bundle)
+    return NULL;
+
+  NativeLibrary native_lib = new NativeLibraryStruct();
+  native_lib->type = BUNDLE;
+  native_lib->bundle = bundle;
+  native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle);
+  native_lib->objc_status = OBJC_UNKNOWN;
+  return native_lib;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  if (library->objc_status == OBJC_NOT_PRESENT) {
+    if (library->type == BUNDLE) {
+      CFBundleCloseBundleResourceMap(library->bundle,
+                                     library->bundle_resource_ref);
+      CFRelease(library->bundle);
+    } else {
+      dlclose(library->dylib);
+    }
+  } else {
+    VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC "
+               "segment. library->objc_status = " << library->objc_status;
+    // Deliberately do not CFRelease the bundle or dlclose the dylib because
+    // doing so can corrupt the ObjC runtime method caches. See
+    // http://crbug.com/172319 for details.
+  }
+  delete library;
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  void* function_pointer = NULL;
+
+  // Get the function pointer using the right API for the type.
+  if (library->type == BUNDLE) {
+    base::ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString(
+        kCFAllocatorDefault, name, kCFStringEncodingUTF8));
+    function_pointer = CFBundleGetFunctionPointerForName(library->bundle,
+                                                         symbol_name);
+  } else {
+    function_pointer = dlsym(library->dylib, name);
+  }
+
+  // If this library hasn't been tested for having ObjC, use the function
+  // pointer to look up the section information for the library.
+  if (function_pointer && library->objc_status == OBJC_UNKNOWN)
+    library->objc_status = GetObjCStatusForImage(function_pointer);
+
+  return function_pointer;
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name + ASCIIToUTF16(".dylib");
+}
+
+}  // namespace base
diff --git a/base/native_library_posix.cc b/base/native_library_posix.cc
new file mode 100644
index 0000000..3179a93
--- /dev/null
+++ b/base/native_library_posix.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/native_library.h"
+
+#include <dlfcn.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+std::string NativeLibraryLoadError::ToString() const {
+  return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  // dlopen() opens the file off disk.
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // We deliberately do not use RTLD_DEEPBIND.  For the history why, please
+  // refer to the bug tracker.  Some useful bug reports to read include:
+  // http://crbug.com/17943, http://crbug.com/17557, http://crbug.com/36892,
+  // and http://crbug.com/40794.
+  void* dl = dlopen(library_path.value().c_str(), RTLD_LAZY);
+  if (!dl && error)
+    error->message = dlerror();
+
+  return dl;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  int ret = dlclose(library);
+  if (ret < 0) {
+    DLOG(ERROR) << "dlclose failed: " << dlerror();
+    NOTREACHED();
+  }
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  return dlsym(library, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return ASCIIToUTF16("lib") + name + ASCIIToUTF16(".so");
+}
+
+}  // namespace base
diff --git a/base/native_library_win.cc b/base/native_library_win.cc
new file mode 100644
index 0000000..1ca3e92
--- /dev/null
+++ b/base/native_library_win.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/native_library.h"
+
+#include <windows.h>
+
+#include "base/files/file_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+namespace {
+
+NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
+                                      LoadLibraryFunction load_library_api,
+                                      NativeLibraryLoadError* error) {
+  // LoadLibrary() opens the file off disk.
+  ThreadRestrictions::AssertIOAllowed();
+
+  // Switch the current directory to the library directory as the library
+  // may have dependencies on DLLs in this directory.
+  bool restore_directory = false;
+  FilePath current_directory;
+  if (GetCurrentDirectory(&current_directory)) {
+    FilePath plugin_path = library_path.DirName();
+    if (!plugin_path.empty()) {
+      SetCurrentDirectory(plugin_path);
+      restore_directory = true;
+    }
+  }
+
+  HMODULE module = (*load_library_api)(library_path.value().c_str());
+  if (!module && error) {
+    // GetLastError() needs to be called immediately after |load_library_api|.
+    error->code = GetLastError();
+  }
+
+  if (restore_directory)
+    SetCurrentDirectory(current_directory);
+
+  return module;
+}
+
+}  // namespace
+
+std::string NativeLibraryLoadError::ToString() const {
+  return StringPrintf("%u", code);
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  return LoadNativeLibraryHelper(library_path, LoadLibraryW, error);
+}
+
+NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) {
+  typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+  LoadLibraryFunction load_library;
+  load_library = reinterpret_cast<LoadLibraryFunction>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"));
+
+  return LoadNativeLibraryHelper(library_path, load_library, NULL);
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  FreeLibrary(library);
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  return GetProcAddress(library, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name + ASCIIToUTF16(".dll");
+}
+
+}  // namespace base
diff --git a/base/nix/mime_util_xdg.cc b/base/nix/mime_util_xdg.cc
new file mode 100644
index 0000000..f78b6ab
--- /dev/null
+++ b/base/nix/mime_util_xdg.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/nix/mime_util_xdg.h"
+
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/third_party/xdg_mime/xdgmime.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+namespace nix {
+
+namespace {
+
+// None of the XDG stuff is thread-safe, so serialize all access under
+// this lock.
+LazyInstance<Lock>::Leaky g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+std::string GetFileMimeType(const FilePath& filepath) {
+  if (filepath.empty())
+    return std::string();
+  ThreadRestrictions::AssertIOAllowed();
+  AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+  return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str());
+}
+
+std::string GetDataMimeType(const std::string& data) {
+  ThreadRestrictions::AssertIOAllowed();
+  AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+  return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL);
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nix/mime_util_xdg.h b/base/nix/mime_util_xdg.h
new file mode 100644
index 0000000..e40415e
--- /dev/null
+++ b/base/nix/mime_util_xdg.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NIX_MIME_UTIL_XDG_H_
+#define BASE_NIX_MIME_UTIL_XDG_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+namespace nix {
+
+// Gets the mime type for a file based on its filename. The file path does not
+// have to exist. Please note because it doesn't touch the disk, this does not
+// work for directories.
+// If the mime type is unknown, this will return application/octet-stream.
+BASE_EXPORT std::string GetFileMimeType(const FilePath& filepath);
+
+// Get the mime type for a byte vector.
+BASE_EXPORT std::string GetDataMimeType(const std::string& data);
+
+}  // namespace nix
+}  // namespace base
+
+#endif  // BASE_NIX_MIME_UTIL_XDG_H_
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc
new file mode 100644
index 0000000..ef04561
--- /dev/null
+++ b/base/nix/xdg_util.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/nix/xdg_util.h"
+
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h"
+
+namespace {
+
+// The KDE session version environment variable used in KDE 4.
+const char kKDE4SessionEnvVar[] = "KDE_SESSION_VERSION";
+
+}  // namespace
+
+namespace base {
+namespace nix {
+
+const char kDotConfigDir[] = ".config";
+const char kXdgConfigHomeEnvVar[] = "XDG_CONFIG_HOME";
+
+FilePath GetXDGDirectory(Environment* env, const char* env_name,
+                         const char* fallback_dir) {
+  FilePath path;
+  std::string env_value;
+  if (env->GetVar(env_name, &env_value) && !env_value.empty()) {
+    path = FilePath(env_value);
+  } else {
+    PathService::Get(DIR_HOME, &path);
+    path = path.Append(fallback_dir);
+  }
+  return path.StripTrailingSeparators();
+}
+
+FilePath GetXDGUserDirectory(const char* dir_name, const char* fallback_dir) {
+  FilePath path;
+  char* xdg_dir = xdg_user_dir_lookup(dir_name);
+  if (xdg_dir) {
+    path = FilePath(xdg_dir);
+    free(xdg_dir);
+  } else {
+    PathService::Get(DIR_HOME, &path);
+    path = path.Append(fallback_dir);
+  }
+  return path.StripTrailingSeparators();
+}
+
+DesktopEnvironment GetDesktopEnvironment(Environment* env) {
+  // XDG_CURRENT_DESKTOP is the newest standard circa 2012.
+  std::string xdg_current_desktop;
+  if (env->GetVar("XDG_CURRENT_DESKTOP", &xdg_current_desktop)) {
+    // Not all desktop environments set this env var as of this writing.
+    if (xdg_current_desktop == "Unity") {
+      // gnome-fallback sessions set XDG_CURRENT_DESKTOP to Unity
+      // DESKTOP_SESSION can be gnome-fallback or gnome-fallback-compiz
+      std::string desktop_session;
+      if (env->GetVar("DESKTOP_SESSION", &desktop_session) &&
+          desktop_session.find("gnome-fallback") != std::string::npos) {
+        return DESKTOP_ENVIRONMENT_GNOME;
+      }
+      return DESKTOP_ENVIRONMENT_UNITY;
+    } else if (xdg_current_desktop == "GNOME") {
+      return DESKTOP_ENVIRONMENT_GNOME;
+    } else if (xdg_current_desktop == "KDE") {
+      return DESKTOP_ENVIRONMENT_KDE4;
+    }
+  }
+
+  // DESKTOP_SESSION was what everyone used in 2010.
+  std::string desktop_session;
+  if (env->GetVar("DESKTOP_SESSION", &desktop_session)) {
+    if (desktop_session == "gnome" || desktop_session =="mate") {
+      return DESKTOP_ENVIRONMENT_GNOME;
+    } else if (desktop_session == "kde4" || desktop_session == "kde-plasma") {
+      return DESKTOP_ENVIRONMENT_KDE4;
+    } else if (desktop_session == "kde") {
+      // This may mean KDE4 on newer systems, so we have to check.
+      if (env->HasVar(kKDE4SessionEnvVar))
+        return DESKTOP_ENVIRONMENT_KDE4;
+      return DESKTOP_ENVIRONMENT_KDE3;
+    } else if (desktop_session.find("xfce") != std::string::npos ||
+               desktop_session == "xubuntu") {
+      return DESKTOP_ENVIRONMENT_XFCE;
+    }
+  }
+
+  // Fall back on some older environment variables.
+  // Useful particularly in the DESKTOP_SESSION=default case.
+  if (env->HasVar("GNOME_DESKTOP_SESSION_ID")) {
+    return DESKTOP_ENVIRONMENT_GNOME;
+  } else if (env->HasVar("KDE_FULL_SESSION")) {
+    if (env->HasVar(kKDE4SessionEnvVar))
+      return DESKTOP_ENVIRONMENT_KDE4;
+    return DESKTOP_ENVIRONMENT_KDE3;
+  }
+
+  return DESKTOP_ENVIRONMENT_OTHER;
+}
+
+const char* GetDesktopEnvironmentName(DesktopEnvironment env) {
+  switch (env) {
+    case DESKTOP_ENVIRONMENT_OTHER:
+      return NULL;
+    case DESKTOP_ENVIRONMENT_GNOME:
+      return "GNOME";
+    case DESKTOP_ENVIRONMENT_KDE3:
+      return "KDE3";
+    case DESKTOP_ENVIRONMENT_KDE4:
+      return "KDE4";
+    case DESKTOP_ENVIRONMENT_UNITY:
+      return "UNITY";
+    case DESKTOP_ENVIRONMENT_XFCE:
+      return "XFCE";
+  }
+  return NULL;
+}
+
+const char* GetDesktopEnvironmentName(Environment* env) {
+  return GetDesktopEnvironmentName(GetDesktopEnvironment(env));
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nix/xdg_util.h b/base/nix/xdg_util.h
new file mode 100644
index 0000000..a8b7784
--- /dev/null
+++ b/base/nix/xdg_util.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NIX_XDG_UTIL_H_
+#define BASE_NIX_XDG_UTIL_H_
+
+// XDG refers to http://en.wikipedia.org/wiki/Freedesktop.org .
+// This file contains utilities found across free desktop environments.
+//
+// TODO(brettw) this file should be in app/x11, but is currently used by
+// net. We should have a net API to allow the embedder to specify the behavior
+// that it uses XDG for, and then move this file.
+
+#include "base/base_export.h"
+
+#ifdef nix
+#error asdf
+#endif
+
+namespace base {
+
+class Environment;
+class FilePath;
+
+namespace nix {
+
+// The default XDG config directory name.
+BASE_EXPORT extern const char kDotConfigDir[];
+
+// The XDG config directory environment variable.
+BASE_EXPORT extern const char kXdgConfigHomeEnvVar[];
+
+// Utility function for getting XDG directories.
+// |env_name| is the name of an environment variable that we want to use to get
+// a directory path. |fallback_dir| is the directory relative to $HOME that we
+// use if |env_name| cannot be found or is empty. |fallback_dir| may be NULL.
+// Examples of |env_name| are XDG_CONFIG_HOME and XDG_DATA_HOME.
+BASE_EXPORT FilePath GetXDGDirectory(Environment* env, const char* env_name,
+                                     const char* fallback_dir);
+
+// Wrapper around xdg_user_dir_lookup() from src/base/third_party/xdg-user-dirs
+// This looks up "well known" user directories like the desktop and music
+// folder. Examples of |dir_name| are DESKTOP and MUSIC.
+BASE_EXPORT FilePath GetXDGUserDirectory(const char* dir_name,
+                                         const char* fallback_dir);
+
+enum DesktopEnvironment {
+  DESKTOP_ENVIRONMENT_OTHER,
+  DESKTOP_ENVIRONMENT_GNOME,
+  // KDE3 and KDE4 are sufficiently different that we count
+  // them as two different desktop environments here.
+  DESKTOP_ENVIRONMENT_KDE3,
+  DESKTOP_ENVIRONMENT_KDE4,
+  DESKTOP_ENVIRONMENT_UNITY,
+  DESKTOP_ENVIRONMENT_XFCE,
+};
+
+// Return an entry from the DesktopEnvironment enum with a best guess
+// of which desktop environment we're using.  We use this to know when
+// to attempt to use preferences from the desktop environment --
+// proxy settings, password manager, etc.
+BASE_EXPORT DesktopEnvironment GetDesktopEnvironment(Environment* env);
+
+// Return a string representation of the given desktop environment.
+// May return NULL in the case of DESKTOP_ENVIRONMENT_OTHER.
+BASE_EXPORT const char* GetDesktopEnvironmentName(DesktopEnvironment env);
+// Convenience wrapper that calls GetDesktopEnvironment() first.
+BASE_EXPORT const char* GetDesktopEnvironmentName(Environment* env);
+
+}  // namespace nix
+}  // namespace base
+
+#endif  // BASE_NIX_XDG_UTIL_H_
diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc
new file mode 100644
index 0000000..136eb5d
--- /dev/null
+++ b/base/nix/xdg_util_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/nix/xdg_util.h"
+
+#include "base/environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+
+namespace base {
+namespace nix {
+
+namespace {
+
+class MockEnvironment : public Environment {
+ public:
+  MOCK_METHOD2(GetVar, bool(const char*, std::string* result));
+  MOCK_METHOD2(SetVar, bool(const char*, const std::string& new_value));
+  MOCK_METHOD1(UnSetVar, bool(const char*));
+};
+
+// Needs to be const char* to make gmock happy.
+const char* const kDesktopGnome = "gnome";
+const char* const kDesktopGnomeFallback = "gnome-fallback";
+const char* const kDesktopMATE = "mate";
+const char* const kDesktopKDE4 = "kde4";
+const char* const kDesktopKDE = "kde";
+const char* const kDesktopXFCE = "xfce";
+const char* const kXdgDesktopGNOME = "GNOME";
+const char* const kXdgDesktopKDE = "KDE";
+const char* const kXdgDesktopUnity = "Unity";
+
+const char kDesktopSession[] = "DESKTOP_SESSION";
+const char kXdgDesktop[] = "XDG_CURRENT_DESKTOP";
+
+}  // namespace
+
+TEST(XDGUtilTest, GetDesktopEnvironmentGnome) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopGnome), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentMATE) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopMATE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopKDE4), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopKDE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopXFCE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopGnome) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopGNOME), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopGnomeFallback) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopUnity), Return(true)));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopGnomeFallback),
+                      Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopKDE4) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopKDE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopUnity) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopUnity), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter));
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/numerics/OWNERS b/base/numerics/OWNERS
new file mode 100644
index 0000000..41f35fc
--- /dev/null
+++ b/base/numerics/OWNERS
@@ -0,0 +1,3 @@
+jschuh@chromium.org
+tsepez@chromium.org
+
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
new file mode 100644
index 0000000..d9b77f7
--- /dev/null
+++ b/base/numerics/safe_conversions.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions_impl.h"
+
+namespace base {
+
+// Convenience function that returns true if the supplied value is in range
+// for the destination type.
+template <typename Dst, typename Src>
+inline bool IsValueInRangeForNumericType(Src value) {
+  return internal::DstRangeRelationToSrcRange<Dst>(value) ==
+         internal::RANGE_VALID;
+}
+
+// checked_cast<> is analogous to static_cast<> for numeric types,
+// except that it CHECKs that the specified numeric conversion will not
+// overflow or underflow. NaN source will always trigger a CHECK.
+template <typename Dst, typename Src>
+inline Dst checked_cast(Src value) {
+  CHECK(IsValueInRangeForNumericType<Dst>(value));
+  return static_cast<Dst>(value);
+}
+
+// saturated_cast<> is analogous to static_cast<> for numeric types, except
+// that the specified numeric conversion will saturate rather than overflow or
+// underflow. NaN assignment to an integral will trigger a CHECK condition.
+template <typename Dst, typename Src>
+inline Dst saturated_cast(Src value) {
+  // Optimization for floating point values, which already saturate.
+  if (std::numeric_limits<Dst>::is_iec559)
+    return static_cast<Dst>(value);
+
+  switch (internal::DstRangeRelationToSrcRange<Dst>(value)) {
+    case internal::RANGE_VALID:
+      return static_cast<Dst>(value);
+
+    case internal::RANGE_UNDERFLOW:
+      return std::numeric_limits<Dst>::min();
+
+    case internal::RANGE_OVERFLOW:
+      return std::numeric_limits<Dst>::max();
+
+    // Should fail only on attempting to assign NaN to a saturated integer.
+    case internal::RANGE_INVALID:
+      CHECK(false);
+      return std::numeric_limits<Dst>::max();
+  }
+
+  NOTREACHED();
+  return static_cast<Dst>(value);
+}
+
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
new file mode 100644
index 0000000..504ce7e
--- /dev/null
+++ b/base/numerics/safe_conversions_impl.h
@@ -0,0 +1,215 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+
+#include <limits>
+
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// The std library doesn't provide a binary max_exponent for integers, however
+// we can compute one by adding one to the number of non-sign bits. This allows
+// for accurate range comparisons between floating point and integer types.
+template <typename NumericType>
+struct MaxExponent {
+  static const int value = std::numeric_limits<NumericType>::is_iec559
+                               ? std::numeric_limits<NumericType>::max_exponent
+                               : (sizeof(NumericType) * 8 + 1 -
+                                  std::numeric_limits<NumericType>::is_signed);
+};
+
+enum IntegerRepresentation {
+  INTEGER_REPRESENTATION_UNSIGNED,
+  INTEGER_REPRESENTATION_SIGNED
+};
+
+// A range for a given nunmeric Src type is contained for a given numeric Dst
+// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
+// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true.
+// We implement this as template specializations rather than simple static
+// comparisons to ensure type correctness in our comparisons.
+enum NumericRangeRepresentation {
+  NUMERIC_RANGE_NOT_CONTAINED,
+  NUMERIC_RANGE_CONTAINED
+};
+
+// Helper templates to statically determine if our destination type can contain
+// maximum and minimum values represented by the source type.
+
+template <
+    typename Dst,
+    typename Src,
+    IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
+                                            ? INTEGER_REPRESENTATION_SIGNED
+                                            : INTEGER_REPRESENTATION_UNSIGNED,
+    IntegerRepresentation SrcSign =
+        std::numeric_limits<Src>::is_signed
+            ? INTEGER_REPRESENTATION_SIGNED
+            : INTEGER_REPRESENTATION_UNSIGNED >
+struct StaticDstRangeRelationToSrcRange;
+
+// Same sign: Dst is guaranteed to contain Src only if its range is equal or
+// larger.
+template <typename Dst, typename Src, IntegerRepresentation Sign>
+struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
+  static const NumericRangeRepresentation value =
+      MaxExponent<Dst>::value >= MaxExponent<Src>::value
+          ? NUMERIC_RANGE_CONTAINED
+          : NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// Unsigned to signed: Dst is guaranteed to contain source only if its range is
+// larger.
+template <typename Dst, typename Src>
+struct StaticDstRangeRelationToSrcRange<Dst,
+                                        Src,
+                                        INTEGER_REPRESENTATION_SIGNED,
+                                        INTEGER_REPRESENTATION_UNSIGNED> {
+  static const NumericRangeRepresentation value =
+      MaxExponent<Dst>::value > MaxExponent<Src>::value
+          ? NUMERIC_RANGE_CONTAINED
+          : NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// Signed to unsigned: Dst cannot be statically determined to contain Src.
+template <typename Dst, typename Src>
+struct StaticDstRangeRelationToSrcRange<Dst,
+                                        Src,
+                                        INTEGER_REPRESENTATION_UNSIGNED,
+                                        INTEGER_REPRESENTATION_SIGNED> {
+  static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+enum RangeConstraint {
+  RANGE_VALID = 0x0,  // Value can be represented by the destination type.
+  RANGE_UNDERFLOW = 0x1,  // Value would overflow.
+  RANGE_OVERFLOW = 0x2,  // Value would underflow.
+  RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW  // Invalid (i.e. NaN).
+};
+
+// Helper function for coercing an int back to a RangeContraint.
+inline RangeConstraint GetRangeConstraint(int integer_range_constraint) {
+  DCHECK(integer_range_constraint >= RANGE_VALID &&
+         integer_range_constraint <= RANGE_INVALID);
+  return static_cast<RangeConstraint>(integer_range_constraint);
+}
+
+// This function creates a RangeConstraint from an upper and lower bound
+// check by taking advantage of the fact that only NaN can be out of range in
+// both directions at once.
+inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
+                                   bool is_in_lower_bound) {
+  return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) |
+                            (is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
+}
+
+template <
+    typename Dst,
+    typename Src,
+    IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
+                                            ? INTEGER_REPRESENTATION_SIGNED
+                                            : INTEGER_REPRESENTATION_UNSIGNED,
+    IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed
+                                            ? INTEGER_REPRESENTATION_SIGNED
+                                            : INTEGER_REPRESENTATION_UNSIGNED,
+    NumericRangeRepresentation DstRange =
+        StaticDstRangeRelationToSrcRange<Dst, Src>::value >
+struct DstRangeRelationToSrcRangeImpl;
+
+// The following templates are for ranges that must be verified at runtime. We
+// split it into checks based on signedness to avoid confusing casts and
+// compiler warnings on signed an unsigned comparisons.
+
+// Dst range is statically determined to contain Src: Nothing to check.
+template <typename Dst,
+          typename Src,
+          IntegerRepresentation DstSign,
+          IntegerRepresentation SrcSign>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      DstSign,
+                                      SrcSign,
+                                      NUMERIC_RANGE_CONTAINED> {
+  static RangeConstraint Check(Src value) { return RANGE_VALID; }
+};
+
+// Signed to signed narrowing: Both the upper and lower boundaries may be
+// exceeded.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return std::numeric_limits<Dst>::is_iec559
+               ? GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
+                                    value >= -std::numeric_limits<Dst>::max())
+               : GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
+                                    value >= std::numeric_limits<Dst>::min());
+  }
+};
+
+// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), true);
+  }
+};
+
+// Unsigned to signed: The upper boundary may be exceeded.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return sizeof(Dst) > sizeof(Src)
+               ? RANGE_VALID
+               : GetRangeConstraint(
+                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     true);
+  }
+};
+
+// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
+// and any negative value exceeds the lower boundary.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
+               ? GetRangeConstraint(true, value >= static_cast<Src>(0))
+               : GetRangeConstraint(
+                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value >= static_cast<Src>(0));
+  }
+};
+
+template <typename Dst, typename Src>
+inline RangeConstraint DstRangeRelationToSrcRange(Src value) {
+  static_assert(std::numeric_limits<Src>::is_specialized,
+                "Argument must be numeric.");
+  static_assert(std::numeric_limits<Dst>::is_specialized,
+                "Result must be numeric.");
+  return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value);
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
new file mode 100644
index 0000000..1309446
--- /dev/null
+++ b/base/numerics/safe_math.h
@@ -0,0 +1,272 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_H_
+#define BASE_NUMERICS_SAFE_MATH_H_
+
+#include "base/numerics/safe_math_impl.h"
+
+namespace base {
+
+namespace internal {
+
+// CheckedNumeric implements all the logic and operators for detecting integer
+// boundary conditions such as overflow, underflow, and invalid conversions.
+// The CheckedNumeric type implicitly converts from floating point and integer
+// data types, and contains overloads for basic arithmetic operations (i.e.: +,
+// -, *, /, %).
+//
+// The following methods convert from CheckedNumeric to standard numeric values:
+// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
+//             has not wrapped and is not the result of an invalid conversion).
+// ValueOrDie() - Returns the underlying value. If the state is not valid this
+//                call will crash on a CHECK.
+// ValueOrDefault() - Returns the current value, or the supplied default if the
+//                    state is not valid.
+// ValueFloating() - Returns the underlying floating point value (valid only
+//                   only for floating point CheckedNumeric types).
+//
+// Bitwise operations are explicitly not supported, because correct
+// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
+// operations are explicitly not supported because they could result in a crash
+// on a CHECK condition. You should use patterns like the following for these
+// operations:
+// Bitwise operation:
+//     CheckedNumeric<int> checked_int = untrusted_input_value;
+//     int x = checked_int.ValueOrDefault(0) | kFlagValues;
+// Comparison:
+//   CheckedNumeric<size_t> checked_size;
+//   CheckedNumeric<int> checked_size = untrusted_input_value;
+//   checked_size = checked_size + HEADER LENGTH;
+//   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
+//     Do stuff...
+template <typename T>
+class CheckedNumeric {
+ public:
+  typedef T type;
+
+  CheckedNumeric() {}
+
+  // Copy constructor.
+  template <typename Src>
+  CheckedNumeric(const CheckedNumeric<Src>& rhs)
+      : state_(rhs.ValueUnsafe(), rhs.validity()) {}
+
+  template <typename Src>
+  CheckedNumeric(Src value, RangeConstraint validity)
+      : state_(value, validity) {}
+
+  // This is not an explicit constructor because we implicitly upgrade regular
+  // numerics to CheckedNumerics to make them easier to use.
+  template <typename Src>
+  CheckedNumeric(Src value)
+      : state_(value) {
+    static_assert(std::numeric_limits<Src>::is_specialized,
+                  "Argument must be numeric.");
+  }
+
+  // IsValid() is the public API to test if a CheckedNumeric is currently valid.
+  bool IsValid() const { return validity() == RANGE_VALID; }
+
+  // ValueOrDie() The primary accessor for the underlying value. If the current
+  // state is not valid it will CHECK and crash.
+  T ValueOrDie() const {
+    CHECK(IsValid());
+    return state_.value();
+  }
+
+  // ValueOrDefault(T default_value) A convenience method that returns the
+  // current value if the state is valid, and the supplied default_value for
+  // any other state.
+  T ValueOrDefault(T default_value) const {
+    return IsValid() ? state_.value() : default_value;
+  }
+
+  // ValueFloating() - Since floating point values include their validity state,
+  // we provide an easy method for extracting them directly, without a risk of
+  // crashing on a CHECK.
+  T ValueFloating() const {
+    static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float.");
+    return CheckedNumeric<T>::cast(*this).ValueUnsafe();
+  }
+
+  // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
+  // tests and to avoid a big matrix of friend operator overloads. But the
+  // values it returns are likely to change in the future.
+  // Returns: current validity state (i.e. valid, overflow, underflow, nan).
+  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
+  // saturation/wrapping so we can expose this state consistently and implement
+  // saturated arithmetic.
+  RangeConstraint validity() const { return state_.validity(); }
+
+  // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
+  // for tests and to avoid a big matrix of friend operator overloads. But the
+  // values it returns are likely to change in the future.
+  // Returns: the raw numeric value, regardless of the current state.
+  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
+  // saturation/wrapping so we can expose this state consistently and implement
+  // saturated arithmetic.
+  T ValueUnsafe() const { return state_.value(); }
+
+  // Prototypes for the supported arithmetic operator overloads.
+  template <typename Src> CheckedNumeric& operator+=(Src rhs);
+  template <typename Src> CheckedNumeric& operator-=(Src rhs);
+  template <typename Src> CheckedNumeric& operator*=(Src rhs);
+  template <typename Src> CheckedNumeric& operator/=(Src rhs);
+  template <typename Src> CheckedNumeric& operator%=(Src rhs);
+
+  CheckedNumeric operator-() const {
+    RangeConstraint validity;
+    T value = CheckedNeg(state_.value(), &validity);
+    // Negation is always valid for floating point.
+    if (std::numeric_limits<T>::is_iec559)
+      return CheckedNumeric<T>(value);
+
+    validity = GetRangeConstraint(state_.validity() | validity);
+    return CheckedNumeric<T>(value, validity);
+  }
+
+  CheckedNumeric Abs() const {
+    RangeConstraint validity;
+    T value = CheckedAbs(state_.value(), &validity);
+    // Absolute value is always valid for floating point.
+    if (std::numeric_limits<T>::is_iec559)
+      return CheckedNumeric<T>(value);
+
+    validity = GetRangeConstraint(state_.validity() | validity);
+    return CheckedNumeric<T>(value, validity);
+  }
+
+  CheckedNumeric& operator++() {
+    *this += 1;
+    return *this;
+  }
+
+  CheckedNumeric operator++(int) {
+    CheckedNumeric value = *this;
+    *this += 1;
+    return value;
+  }
+
+  CheckedNumeric& operator--() {
+    *this -= 1;
+    return *this;
+  }
+
+  CheckedNumeric operator--(int) {
+    CheckedNumeric value = *this;
+    *this -= 1;
+    return value;
+  }
+
+  // These static methods behave like a convenience cast operator targeting
+  // the desired CheckedNumeric type. As an optimization, a reference is
+  // returned when Src is the same type as T.
+  template <typename Src>
+  static CheckedNumeric<T> cast(
+      Src u,
+      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
+          0) {
+    return u;
+  }
+
+  template <typename Src>
+  static CheckedNumeric<T> cast(
+      const CheckedNumeric<Src>& u,
+      typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
+    return u;
+  }
+
+  static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
+
+ private:
+  CheckedNumericState<T> state_;
+};
+
+// This is the boilerplate for the standard arithmetic operator overloads. A
+// macro isn't the prettiest solution, but it beats rewriting these five times.
+// Some details worth noting are:
+//  * We apply the standard arithmetic promotions.
+//  * We skip range checks for floating points.
+//  * We skip range checks for destination integers with sufficient range.
+// TODO(jschuh): extract these out into templates.
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)              \
+  /* Binary arithmetic operator for CheckedNumerics of the same type. */      \
+  template <typename T>                                                       \
+  CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP(          \
+      const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) {           \
+    typedef typename ArithmeticPromotion<T>::type Promotion;                  \
+    /* Floating point always takes the fast path */                           \
+    if (std::numeric_limits<T>::is_iec559)                                    \
+      return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());       \
+    if (IsIntegerArithmeticSafe<Promotion, T, T>::value)                      \
+      return CheckedNumeric<Promotion>(                                       \
+          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
+          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
+    RangeConstraint validity = RANGE_VALID;                                   \
+    T result = static_cast<T>(Checked##NAME(                                  \
+        static_cast<Promotion>(lhs.ValueUnsafe()),                            \
+        static_cast<Promotion>(rhs.ValueUnsafe()),                            \
+        &validity));                                                          \
+    return CheckedNumeric<Promotion>(                                         \
+        result,                                                               \
+        GetRangeConstraint(validity | lhs.validity() | rhs.validity()));      \
+  }                                                                           \
+  /* Assignment arithmetic operator implementation from CheckedNumeric. */    \
+  template <typename T>                                                       \
+  template <typename Src>                                                     \
+  CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) {       \
+    *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
+    return *this;                                                             \
+  }                                                                           \
+  /* Binary arithmetic operator for CheckedNumeric of different type. */      \
+  template <typename T, typename Src>                                         \
+  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
+      const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) {         \
+    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
+    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
+      return CheckedNumeric<Promotion>(                                       \
+          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
+          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
+    return CheckedNumeric<Promotion>::cast(lhs)                               \
+        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+  }                                                                           \
+  /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
+  template <typename T, typename Src>                                         \
+  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
+      const CheckedNumeric<T>& lhs, Src rhs) {                                \
+    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
+    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
+      return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs,              \
+                                       lhs.validity());                       \
+    return CheckedNumeric<Promotion>::cast(lhs)                               \
+        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+  }                                                                           \
+  /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
+  template <typename T, typename Src>                                         \
+  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
+      Src lhs, const CheckedNumeric<T>& rhs) {                                \
+    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
+    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
+      return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(),              \
+                                       rhs.validity());                       \
+    return CheckedNumeric<Promotion>::cast(lhs)                               \
+        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+  }
+
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
+
+#undef BASE_NUMERIC_ARITHMETIC_OPERATORS
+
+}  // namespace internal
+
+using internal::CheckedNumeric;
+
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_MATH_H_
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
new file mode 100644
index 0000000..c845189
--- /dev/null
+++ b/base/numerics/safe_math_impl.h
@@ -0,0 +1,501 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_IMPL_H_
+
+#include <stdint.h>
+
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+
+#include "base/numerics/safe_conversions.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// Everything from here up to the floating point operations is portable C++,
+// but it may not be fast. This code could be split based on
+// platform/architecture and replaced with potentially faster implementations.
+
+// Integer promotion templates used by the portable checked integer arithmetic.
+template <size_t Size, bool IsSigned>
+struct IntegerForSizeAndSign;
+template <>
+struct IntegerForSizeAndSign<1, true> {
+  typedef int8_t type;
+};
+template <>
+struct IntegerForSizeAndSign<1, false> {
+  typedef uint8_t type;
+};
+template <>
+struct IntegerForSizeAndSign<2, true> {
+  typedef int16_t type;
+};
+template <>
+struct IntegerForSizeAndSign<2, false> {
+  typedef uint16_t type;
+};
+template <>
+struct IntegerForSizeAndSign<4, true> {
+  typedef int32_t type;
+};
+template <>
+struct IntegerForSizeAndSign<4, false> {
+  typedef uint32_t type;
+};
+template <>
+struct IntegerForSizeAndSign<8, true> {
+  typedef int64_t type;
+};
+template <>
+struct IntegerForSizeAndSign<8, false> {
+  typedef uint64_t type;
+};
+
+// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
+// support 128-bit math, then the ArithmeticPromotion template below will need
+// to be updated (or more likely replaced with a decltype expression).
+
+template <typename Integer>
+struct UnsignedIntegerForSize {
+  typedef typename enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
+};
+
+template <typename Integer>
+struct SignedIntegerForSize {
+  typedef typename enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
+};
+
+template <typename Integer>
+struct TwiceWiderInteger {
+  typedef typename enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<
+          sizeof(Integer) * 2,
+          std::numeric_limits<Integer>::is_signed>::type>::type type;
+};
+
+template <typename Integer>
+struct PositionOfSignBit {
+  static const typename enable_if<std::numeric_limits<Integer>::is_integer,
+                                  size_t>::type value = 8 * sizeof(Integer) - 1;
+};
+
+// Helper templates for integer manipulations.
+
+template <typename T>
+bool HasSignBit(T x) {
+  // Cast to unsigned since right shift on signed is undefined.
+  return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
+            PositionOfSignBit<T>::value);
+}
+
+// This wrapper undoes the standard integer promotions.
+template <typename T>
+T BinaryComplement(T x) {
+  return ~x;
+}
+
+// Here are the actual portable checked integer math implementations.
+// TODO(jschuh): Break this code out from the enable_if pattern and find a clean
+// way to coalesce things into the CheckedNumericState specializations below.
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+CheckedAdd(T x, T y, RangeConstraint* validity) {
+  // Since the value of x+y is undefined if we have a signed type, we compute
+  // it using the unsigned type of the same size.
+  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
+  UnsignedDst ux = static_cast<UnsignedDst>(x);
+  UnsignedDst uy = static_cast<UnsignedDst>(y);
+  UnsignedDst uresult = ux + uy;
+  // Addition is valid if the sign of (x + y) is equal to either that of x or
+  // that of y.
+  if (std::numeric_limits<T>::is_signed) {
+    if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
+      *validity = RANGE_VALID;
+    else  // Direction of wrap is inverse of result sign.
+      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
+
+  } else {  // Unsigned is either valid or overflow.
+    *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
+  }
+  return static_cast<T>(uresult);
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+CheckedSub(T x, T y, RangeConstraint* validity) {
+  // Since the value of x+y is undefined if we have a signed type, we compute
+  // it using the unsigned type of the same size.
+  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
+  UnsignedDst ux = static_cast<UnsignedDst>(x);
+  UnsignedDst uy = static_cast<UnsignedDst>(y);
+  UnsignedDst uresult = ux - uy;
+  // Subtraction is valid if either x and y have same sign, or (x-y) and x have
+  // the same sign.
+  if (std::numeric_limits<T>::is_signed) {
+    if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
+      *validity = RANGE_VALID;
+    else  // Direction of wrap is inverse of result sign.
+      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
+
+  } else {  // Unsigned is either valid or underflow.
+    *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
+  }
+  return static_cast<T>(uresult);
+}
+
+// Integer multiplication is a bit complicated. In the fast case we just
+// we just promote to a twice wider type, and range check the result. In the
+// slow case we need to manually check that the result won't be truncated by
+// checking with division against the appropriate bound.
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t),
+    T>::type
+CheckedMul(T x, T y, RangeConstraint* validity) {
+  typedef typename TwiceWiderInteger<T>::type IntermediateType;
+  IntermediateType tmp =
+      static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
+  *validity = DstRangeRelationToSrcRange<T>(tmp);
+  return static_cast<T>(tmp);
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits<
+                       T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)),
+                   T>::type
+CheckedMul(T x, T y, RangeConstraint* validity) {
+  // if either side is zero then the result will be zero.
+  if (!(x || y)) {
+    return RANGE_VALID;
+
+  } else if (x > 0) {
+    if (y > 0)
+      *validity =
+          x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
+    else
+      *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
+                                                         : RANGE_UNDERFLOW;
+
+  } else {
+    if (y > 0)
+      *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
+                                                         : RANGE_UNDERFLOW;
+    else
+      *validity =
+          y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
+  }
+
+  return x * y;
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer &&
+                       !std::numeric_limits<T>::is_signed &&
+                       (sizeof(T) * 2 > sizeof(uintmax_t)),
+                   T>::type
+CheckedMul(T x, T y, RangeConstraint* validity) {
+  *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
+                  ? RANGE_VALID
+                  : RANGE_OVERFLOW;
+  return x * y;
+}
+
+// Division just requires a check for an invalid negation on signed min/-1.
+template <typename T>
+T CheckedDiv(
+    T x,
+    T y,
+    RangeConstraint* validity,
+    typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) {
+  if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
+      y == static_cast<T>(-1)) {
+    *validity = RANGE_OVERFLOW;
+    return std::numeric_limits<T>::min();
+  }
+
+  *validity = RANGE_VALID;
+  return x / y;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedMod(T x, T y, RangeConstraint* validity) {
+  *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
+  return x % y;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedMod(T x, T y, RangeConstraint* validity) {
+  *validity = RANGE_VALID;
+  return x % y;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedNeg(T value, RangeConstraint* validity) {
+  *validity =
+      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
+  // The negation of signed min is min, so catch that one.
+  return -value;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedNeg(T value, RangeConstraint* validity) {
+  // The only legal unsigned negation is zero.
+  *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
+  return static_cast<T>(
+      -static_cast<typename SignedIntegerForSize<T>::type>(value));
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedAbs(T value, RangeConstraint* validity) {
+  *validity =
+      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
+  return static_cast<T>(std::abs(value));
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedAbs(T value, RangeConstraint* validity) {
+  // Absolute value of a positive is just its identiy.
+  *validity = RANGE_VALID;
+  return value;
+}
+
+// These are the floating point stubs that the compiler needs to see. Only the
+// negation operation is ever called.
+#define BASE_FLOAT_ARITHMETIC_STUBS(NAME)                        \
+  template <typename T>                                          \
+  typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \
+  Checked##NAME(T, T, RangeConstraint*) {                        \
+    NOTREACHED();                                                \
+    return 0;                                                    \
+  }
+
+BASE_FLOAT_ARITHMETIC_STUBS(Add)
+BASE_FLOAT_ARITHMETIC_STUBS(Sub)
+BASE_FLOAT_ARITHMETIC_STUBS(Mul)
+BASE_FLOAT_ARITHMETIC_STUBS(Div)
+BASE_FLOAT_ARITHMETIC_STUBS(Mod)
+
+#undef BASE_FLOAT_ARITHMETIC_STUBS
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
+    T value,
+    RangeConstraint*) {
+  return -value;
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
+    T value,
+    RangeConstraint*) {
+  return std::abs(value);
+}
+
+// Floats carry around their validity state with them, but integers do not. So,
+// we wrap the underlying value in a specialization in order to hide that detail
+// and expose an interface via accessors.
+enum NumericRepresentation {
+  NUMERIC_INTEGER,
+  NUMERIC_FLOATING,
+  NUMERIC_UNKNOWN
+};
+
+template <typename NumericType>
+struct GetNumericRepresentation {
+  static const NumericRepresentation value =
+      std::numeric_limits<NumericType>::is_integer
+          ? NUMERIC_INTEGER
+          : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
+                                                         : NUMERIC_UNKNOWN);
+};
+
+template <typename T, NumericRepresentation type =
+                          GetNumericRepresentation<T>::value>
+class CheckedNumericState {};
+
+// Integrals require quite a bit of additional housekeeping to manage state.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_INTEGER> {
+ private:
+  T value_;
+  RangeConstraint validity_;
+
+ public:
+  template <typename Src, NumericRepresentation type>
+  friend class CheckedNumericState;
+
+  CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
+
+  template <typename Src>
+  CheckedNumericState(Src value, RangeConstraint validity)
+      : value_(static_cast<T>(value)),
+        validity_(GetRangeConstraint(validity |
+                                     DstRangeRelationToSrcRange<T>(value))) {
+    static_assert(std::numeric_limits<Src>::is_specialized,
+                  "Argument must be numeric.");
+  }
+
+  // Copy constructor.
+  template <typename Src>
+  CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : value_(static_cast<T>(rhs.value())),
+        validity_(GetRangeConstraint(
+            rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
+
+  template <typename Src>
+  explicit CheckedNumericState(
+      Src value,
+      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
+          0)
+      : value_(static_cast<T>(value)),
+        validity_(DstRangeRelationToSrcRange<T>(value)) {}
+
+  RangeConstraint validity() const { return validity_; }
+  T value() const { return value_; }
+};
+
+// Floating points maintain their own validity, but need translation wrappers.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_FLOATING> {
+ private:
+  T value_;
+
+ public:
+  template <typename Src, NumericRepresentation type>
+  friend class CheckedNumericState;
+
+  CheckedNumericState() : value_(0.0) {}
+
+  template <typename Src>
+  CheckedNumericState(
+      Src value,
+      RangeConstraint validity,
+      typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) {
+    switch (DstRangeRelationToSrcRange<T>(value)) {
+      case RANGE_VALID:
+        value_ = static_cast<T>(value);
+        break;
+
+      case RANGE_UNDERFLOW:
+        value_ = -std::numeric_limits<T>::infinity();
+        break;
+
+      case RANGE_OVERFLOW:
+        value_ = std::numeric_limits<T>::infinity();
+        break;
+
+      case RANGE_INVALID:
+        value_ = std::numeric_limits<T>::quiet_NaN();
+        break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+
+  template <typename Src>
+  explicit CheckedNumericState(
+      Src value,
+      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
+          0)
+      : value_(static_cast<T>(value)) {}
+
+  // Copy constructor.
+  template <typename Src>
+  CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : value_(static_cast<T>(rhs.value())) {}
+
+  RangeConstraint validity() const {
+    return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
+                              value_ >= -std::numeric_limits<T>::max());
+  }
+  T value() const { return value_; }
+};
+
+// For integers less than 128-bit and floats 32-bit or larger, we can distil
+// C/C++ arithmetic promotions down to two simple rules:
+// 1. The type with the larger maximum exponent always takes precedence.
+// 2. The resulting type must be promoted to at least an int.
+// The following template specializations implement that promotion logic.
+enum ArithmeticPromotionCategory {
+  LEFT_PROMOTION,
+  RIGHT_PROMOTION,
+  DEFAULT_PROMOTION
+};
+
+template <typename Lhs,
+          typename Rhs = Lhs,
+          ArithmeticPromotionCategory Promotion =
+              (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
+                  ? (MaxExponent<Lhs>::value > MaxExponent<int>::value
+                         ? LEFT_PROMOTION
+                         : DEFAULT_PROMOTION)
+                  : (MaxExponent<Rhs>::value > MaxExponent<int>::value
+                         ? RIGHT_PROMOTION
+                         : DEFAULT_PROMOTION) >
+struct ArithmeticPromotion;
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
+  typedef Lhs type;
+};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+  typedef Rhs type;
+};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
+  typedef int type;
+};
+
+// We can statically check if operations on the provided types can wrap, so we
+// can skip the checked operations if they're not needed. So, for an integer we
+// care if the destination type preserves the sign and is twice the width of
+// the source.
+template <typename T, typename Lhs, typename Rhs>
+struct IsIntegerArithmeticSafe {
+  static const bool value = !std::numeric_limits<T>::is_iec559 &&
+                            StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
+                                NUMERIC_RANGE_CONTAINED &&
+                            sizeof(T) >= (2 * sizeof(Lhs)) &&
+                            StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
+                                NUMERIC_RANGE_CONTAINED &&
+                            sizeof(T) >= (2 * sizeof(Rhs));
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_MATH_IMPL_H_
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
new file mode 100644
index 0000000..bdececb
--- /dev/null
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -0,0 +1,576 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
+#include <mmintrin.h>
+#endif
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math.h"
+#include "base/template_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::numeric_limits;
+using base::CheckedNumeric;
+using base::checked_cast;
+using base::saturated_cast;
+using base::internal::MaxExponent;
+using base::internal::RANGE_VALID;
+using base::internal::RANGE_INVALID;
+using base::internal::RANGE_OVERFLOW;
+using base::internal::RANGE_UNDERFLOW;
+using base::enable_if;
+
+// These tests deliberately cause arithmetic overflows. If the compiler is
+// aggressive enough, it can const fold these overflows. Disable warnings about
+// overflows for const expressions.
+#if defined(OS_WIN)
+#pragma warning(disable:4756)
+#endif
+
+// Helper macros to wrap displaying the conversion types and line numbers.
+#define TEST_EXPECTED_VALIDITY(expected, actual)                           \
+  EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).validity())              \
+      << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst \
+      << " on line " << line;
+
+#define TEST_EXPECTED_VALUE(expected, actual)                                \
+  EXPECT_EQ(static_cast<Dst>(expected),                                      \
+            CheckedNumeric<Dst>(actual).ValueUnsafe())                       \
+      << "Result test: Value " << +((actual).ValueUnsafe()) << " as " << dst \
+      << " on line " << line;
+
+// Signed integer arithmetic.
+template <typename Dst>
+static void TestSpecializedArithmetic(
+    const char* dst,
+    int line,
+    typename enable_if<
+        numeric_limits<Dst>::is_integer&& numeric_limits<Dst>::is_signed,
+        int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
+                         -CheckedNumeric<Dst>(DstLimits::min()));
+  TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::max()) + -1);
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) - 1);
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) - -1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW,
+      CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max());
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) * 2);
+
+  TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) / -1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2);
+
+  // Modulus is legal only for integers.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2);
+  TEST_EXPECTED_VALIDITY(RANGE_INVALID, CheckedNumeric<Dst>(-1) % -2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2);
+  // Test all the different modulus combinations.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  CheckedNumeric<Dst> checked_dst = 1;
+  TEST_EXPECTED_VALUE(0, checked_dst %= 1);
+}
+
+// Unsigned integer arithmetic.
+template <typename Dst>
+static void TestSpecializedArithmetic(
+    const char* dst,
+    int line,
+    typename enable_if<
+        numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed,
+        int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) - 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2);
+
+  // Modulus is legal only for integers.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2);
+  // Test all the different modulus combinations.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  CheckedNumeric<Dst> checked_dst = 1;
+  TEST_EXPECTED_VALUE(0, checked_dst %= 1);
+}
+
+// Floating point arithmetic.
+template <typename Dst>
+void TestSpecializedArithmetic(
+    const char* dst,
+    int line,
+    typename enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::max()) + 1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW,
+      CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max());
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) * 2);
+
+  TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2);
+  EXPECT_EQ(static_cast<Dst>(1.0), CheckedNumeric<Dst>(1.0).ValueFloating());
+}
+
+// Generic arithmetic tests.
+template <typename Dst>
+static void TestArithmetic(const char* dst, int line) {
+  typedef numeric_limits<Dst> DstLimits;
+
+  EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid());
+  EXPECT_EQ(false,
+            CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) *
+                                DstLimits::max()).IsValid());
+  EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDie());
+  EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDefault(1));
+  EXPECT_EQ(static_cast<Dst>(1),
+            CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) *
+                                DstLimits::max()).ValueOrDefault(1));
+
+  // Test the operator combinations.
+  TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1);
+  CheckedNumeric<Dst> checked_dst = 1;
+  TEST_EXPECTED_VALUE(2, checked_dst += 1);
+  checked_dst = 1;
+  TEST_EXPECTED_VALUE(0, checked_dst -= 1);
+  checked_dst = 1;
+  TEST_EXPECTED_VALUE(1, checked_dst *= 1);
+  checked_dst = 1;
+  TEST_EXPECTED_VALUE(1, checked_dst /= 1);
+
+  // Generic negation.
+  TEST_EXPECTED_VALUE(0, -CheckedNumeric<Dst>());
+  TEST_EXPECTED_VALUE(-1, -CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, -CheckedNumeric<Dst>(-1));
+  TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1),
+                      -CheckedNumeric<Dst>(DstLimits::max()));
+
+  // Generic absolute value.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>().Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).Abs());
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      CheckedNumeric<Dst>(DstLimits::max()).Abs());
+
+  // Generic addition.
+  TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>() + 1));
+  TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1));
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) + 1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) + DstLimits::max());
+
+  // Generic subtraction.
+  TEST_EXPECTED_VALUE(-1, (CheckedNumeric<Dst>() - 1));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(1) - 1));
+  TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) - 1));
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::max()) - 1);
+
+  // Generic multiplication.
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1));
+  TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1));
+  TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2));
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max());
+
+  // Generic division.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1);
+  TEST_EXPECTED_VALUE(DstLimits::min() / 2,
+                      CheckedNumeric<Dst>(DstLimits::min()) / 2);
+  TEST_EXPECTED_VALUE(DstLimits::max() / 2,
+                      CheckedNumeric<Dst>(DstLimits::max()) / 2);
+
+  TestSpecializedArithmetic<Dst>(dst, line);
+}
+
+// Helper macro to wrap displaying the conversion types and line numbers.
+#define TEST_ARITHMETIC(Dst) TestArithmetic<Dst>(#Dst, __LINE__)
+
+TEST(SafeNumerics, SignedIntegerMath) {
+  TEST_ARITHMETIC(int8_t);
+  TEST_ARITHMETIC(int);
+  TEST_ARITHMETIC(intptr_t);
+  TEST_ARITHMETIC(intmax_t);
+}
+
+TEST(SafeNumerics, UnsignedIntegerMath) {
+  TEST_ARITHMETIC(uint8_t);
+  TEST_ARITHMETIC(unsigned int);
+  TEST_ARITHMETIC(uintptr_t);
+  TEST_ARITHMETIC(uintmax_t);
+}
+
+TEST(SafeNumerics, FloatingPointMath) {
+  TEST_ARITHMETIC(float);
+  TEST_ARITHMETIC(double);
+}
+
+// Enumerates the five different conversions types we need to test.
+enum NumericConversionType {
+  SIGN_PRESERVING_VALUE_PRESERVING,
+  SIGN_PRESERVING_NARROW,
+  SIGN_TO_UNSIGN_WIDEN_OR_EQUAL,
+  SIGN_TO_UNSIGN_NARROW,
+  UNSIGN_TO_SIGN_NARROW_OR_EQUAL,
+};
+
+// Template covering the different conversion tests.
+template <typename Dst, typename Src, NumericConversionType conversion>
+struct TestNumericConversion {};
+
+// EXPECT_EQ wrappers providing specific detail on test failures.
+#define TEST_EXPECTED_RANGE(expected, actual)                                  \
+  EXPECT_EQ(expected, base::internal::DstRangeRelationToSrcRange<Dst>(actual)) \
+      << "Conversion test: " << src << " value " << actual << " to " << dst    \
+      << " on line " << line;
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+                   // Integral to floating.
+    static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) ||
+                  // Not floating to integral and...
+                  (!(DstLimits::is_integer && SrcLimits::is_iec559) &&
+                   // Same sign, same numeric, source is narrower or same.
+                   ((SrcLimits::is_signed == DstLimits::is_signed &&
+                    sizeof(Dst) >= sizeof(Src)) ||
+                   // Or signed destination and source is smaller
+                    (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))),
+                  "Comparison must be sign preserving and value preserving");
+
+    const CheckedNumeric<Dst> checked_dst = SrcLimits::max();
+    ;
+    TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst);
+    if (MaxExponent<Dst>::value > MaxExponent<Src>::value) {
+      if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) {
+        // At least twice larger type.
+        TEST_EXPECTED_VALIDITY(RANGE_VALID, SrcLimits::max() * checked_dst);
+
+      } else {  // Larger, but not at least twice as large.
+        TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, SrcLimits::max() * checked_dst);
+        TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst + 1);
+      }
+    } else {  // Same width type.
+      TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + 1);
+    }
+
+    TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    if (SrcLimits::is_iec559) {
+      TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast<Src>(-1));
+      TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
+      TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+    } else if (numeric_limits<Src>::is_signed) {
+      TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
+      TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
+    }
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert(SrcLimits::is_signed == DstLimits::is_signed,
+                  "Destination and source sign must be the same");
+    static_assert(sizeof(Dst) < sizeof(Src) ||
+                   (DstLimits::is_integer && SrcLimits::is_iec559),
+                  "Destination must be narrower than source");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst - SrcLimits::max());
+
+    TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    if (SrcLimits::is_iec559) {
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
+      TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
+      TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
+      TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+    } else if (SrcLimits::is_signed) {
+      TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
+      TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
+    } else {
+      TEST_EXPECTED_VALIDITY(RANGE_INVALID, checked_dst - static_cast<Src>(1));
+      TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
+    }
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert(sizeof(Dst) >= sizeof(Src),
+                  "Destination must be equal or wider than source.");
+    static_assert(SrcLimits::is_signed, "Source must be signed");
+    static_assert(!DstLimits::is_signed, "Destination must be unsigned");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max());
+
+    TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
+    TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert((DstLimits::is_integer && SrcLimits::is_iec559) ||
+                   (sizeof(Dst) < sizeof(Src)),
+                  "Destination must be narrower than source.");
+    static_assert(SrcLimits::is_signed, "Source must be signed.");
+    static_assert(!DstLimits::is_signed, "Destination must be unsigned.");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max());
+
+    TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
+    if (SrcLimits::is_iec559) {
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
+      TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
+      TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+    } else {
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
+    }
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert(sizeof(Dst) <= sizeof(Src),
+                  "Destination must be narrower or equal to source.");
+    static_assert(!SrcLimits::is_signed, "Source must be unsigned.");
+    static_assert(DstLimits::is_signed, "Destination must be signed.");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min());
+
+    TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
+    TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+  }
+};
+
+// Helper macro to wrap displaying the conversion types and line numbers
+#define TEST_NUMERIC_CONVERSION(d, s, t) \
+  TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__)
+
+TEST(SafeNumerics, IntMinOperations) {
+  TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW);
+
+  TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+
+  TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW);
+
+  TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, IntOperations) {
+  TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(unsigned int, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(unsigned int, uint8_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW);
+
+  TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+
+  TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW);
+
+  TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, IntMaxOperations) {
+  TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(intmax_t, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW);
+
+  TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+
+  TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW);
+
+  TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, FloatOperations) {
+  TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(float, uintmax_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(float, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW);
+}
+
+TEST(SafeNumerics, DoubleOperations) {
+  TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(double, uintmax_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(double, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+}
+
+TEST(SafeNumerics, SizeTOperations) {
+  TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, CastTests) {
+// MSVC catches and warns that we're forcing saturation in these tests.
+// Since that's intentional, we need to shut this warning off.
+#if defined(COMPILER_MSVC)
+#pragma warning(disable : 4756)
+#endif
+
+  int small_positive = 1;
+  int small_negative = -1;
+  double double_small = 1.0;
+  double double_large = numeric_limits<double>::max();
+  double double_infinity = numeric_limits<float>::infinity();
+
+  // Just test that the cast compiles, since the other tests cover logic.
+  EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0)));
+
+  // Test various saturation corner cases.
+  EXPECT_EQ(saturated_cast<int>(small_negative),
+            static_cast<int>(small_negative));
+  EXPECT_EQ(saturated_cast<int>(small_positive),
+            static_cast<int>(small_positive));
+  EXPECT_EQ(saturated_cast<unsigned>(small_negative),
+            static_cast<unsigned>(0));
+  EXPECT_EQ(saturated_cast<int>(double_small),
+            static_cast<int>(double_small));
+  EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max());
+  EXPECT_EQ(saturated_cast<float>(double_large), double_infinity);
+  EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
+}
+
diff --git a/base/observer_list.h b/base/observer_list.h
new file mode 100644
index 0000000..9ea344d
--- /dev/null
+++ b/base/observer_list.h
@@ -0,0 +1,243 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OBSERVER_LIST_H__
+#define BASE_OBSERVER_LIST_H__
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+//   A container for a list of observers.  Unlike a normal STL vector or list,
+//   this container can be modified during iteration without invalidating the
+//   iterator.  So, it safely handles the case of an observer removing itself
+//   or other observers from the list while observers are being notified.
+//
+// TYPICAL USAGE:
+//
+//   class MyWidget {
+//    public:
+//     ...
+//
+//     class Observer {
+//      public:
+//       virtual void OnFoo(MyWidget* w) = 0;
+//       virtual void OnBar(MyWidget* w, int x, int y) = 0;
+//     };
+//
+//     void AddObserver(Observer* obs) {
+//       observer_list_.AddObserver(obs);
+//     }
+//
+//     void RemoveObserver(Observer* obs) {
+//       observer_list_.RemoveObserver(obs);
+//     }
+//
+//     void NotifyFoo() {
+//       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
+//     }
+//
+//     void NotifyBar(int x, int y) {
+//       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
+//     }
+//
+//    private:
+//     ObserverList<Observer> observer_list_;
+//   };
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename ObserverType>
+class ObserverListThreadSafe;
+
+template <class ObserverType>
+class ObserverListBase
+    : public base::SupportsWeakPtr<ObserverListBase<ObserverType> > {
+ public:
+  // Enumeration of which observers are notified.
+  enum NotificationType {
+    // Specifies that any observers added during notification are notified.
+    // This is the default type if non type is provided to the constructor.
+    NOTIFY_ALL,
+
+    // Specifies that observers added while sending out notification are not
+    // notified.
+    NOTIFY_EXISTING_ONLY
+  };
+
+  // An iterator class that can be used to access the list of observers.  See
+  // also the FOR_EACH_OBSERVER macro defined below.
+  class Iterator {
+   public:
+    explicit Iterator(ObserverListBase<ObserverType>* list);
+    ~Iterator();
+    ObserverType* GetNext();
+
+   private:
+    base::WeakPtr<ObserverListBase<ObserverType> > list_;
+    size_t index_;
+    size_t max_index_;
+  };
+
+  ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
+  explicit ObserverListBase(NotificationType type)
+      : notify_depth_(0), type_(type) {}
+
+  // Add an observer to the list.  An observer should not be added to
+  // the same list more than once.
+  void AddObserver(ObserverType* obs);
+
+  // Remove an observer from the list if it is in the list.
+  void RemoveObserver(ObserverType* obs);
+
+  // Determine whether a particular observer is in the list.
+  bool HasObserver(const ObserverType* observer) const;
+
+  void Clear();
+
+ protected:
+  size_t size() const { return observers_.size(); }
+
+  void Compact();
+
+ private:
+  friend class ObserverListThreadSafe<ObserverType>;
+
+  typedef std::vector<ObserverType*> ListType;
+
+  ListType observers_;
+  int notify_depth_;
+  NotificationType type_;
+
+  friend class ObserverListBase::Iterator;
+
+  DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
+};
+
+template <class ObserverType>
+ObserverListBase<ObserverType>::Iterator::Iterator(
+    ObserverListBase<ObserverType>* list)
+    : list_(list->AsWeakPtr()),
+      index_(0),
+      max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
+                                           : list->observers_.size()) {
+  ++list_->notify_depth_;
+}
+
+template <class ObserverType>
+ObserverListBase<ObserverType>::Iterator::~Iterator() {
+  if (list_.get() && --list_->notify_depth_ == 0)
+    list_->Compact();
+}
+
+template <class ObserverType>
+ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
+  if (!list_.get())
+    return nullptr;
+  ListType& observers = list_->observers_;
+  // Advance if the current element is null
+  size_t max_index = std::min(max_index_, observers.size());
+  while (index_ < max_index && !observers[index_])
+    ++index_;
+  return index_ < max_index ? observers[index_++] : nullptr;
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
+  DCHECK(obs);
+  if (std::find(observers_.begin(), observers_.end(), obs)
+      != observers_.end()) {
+    NOTREACHED() << "Observers can only be added once!";
+    return;
+  }
+  observers_.push_back(obs);
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
+  DCHECK(obs);
+  typename ListType::iterator it =
+    std::find(observers_.begin(), observers_.end(), obs);
+  if (it != observers_.end()) {
+    if (notify_depth_) {
+      *it = nullptr;
+    } else {
+      observers_.erase(it);
+    }
+  }
+}
+
+template <class ObserverType>
+bool ObserverListBase<ObserverType>::HasObserver(
+    const ObserverType* observer) const {
+  for (size_t i = 0; i < observers_.size(); ++i) {
+    if (observers_[i] == observer)
+      return true;
+  }
+  return false;
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::Clear() {
+  if (notify_depth_) {
+    for (typename ListType::iterator it = observers_.begin();
+      it != observers_.end(); ++it) {
+      *it = nullptr;
+    }
+  } else {
+    observers_.clear();
+  }
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::Compact() {
+  observers_.erase(
+      std::remove(observers_.begin(), observers_.end(), nullptr),
+      observers_.end());
+}
+
+template <class ObserverType, bool check_empty = false>
+class ObserverList : public ObserverListBase<ObserverType> {
+ public:
+  typedef typename ObserverListBase<ObserverType>::NotificationType
+      NotificationType;
+
+  ObserverList() {}
+  explicit ObserverList(NotificationType type)
+      : ObserverListBase<ObserverType>(type) {}
+
+  ~ObserverList() {
+    // When check_empty is true, assert that the list is empty on destruction.
+    if (check_empty) {
+      ObserverListBase<ObserverType>::Compact();
+      DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
+    }
+  }
+
+  bool might_have_observers() const {
+    return ObserverListBase<ObserverType>::size() != 0;
+  }
+};
+
+#define FOR_EACH_OBSERVER(ObserverType, observer_list, func)             \
+  do {                                                                   \
+    if ((observer_list).might_have_observers()) {                        \
+      ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \
+          &observer_list);                                               \
+      ObserverType* obs;                                                 \
+      while ((obs = it_inside_observer_macro.GetNext()) != nullptr)         \
+        obs->func;                                                       \
+    }                                                                    \
+  } while (0)
+
+#endif  // BASE_OBSERVER_LIST_H__
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
new file mode 100644
index 0000000..e0ce0da
--- /dev/null
+++ b/base/observer_list_threadsafe.h
@@ -0,0 +1,265 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
+#define BASE_OBSERVER_LIST_THREADSAFE_H_
+
+#include <algorithm>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+//   A thread-safe container for a list of observers.
+//   This is similar to the observer_list (see observer_list.h), but it
+//   is more robust for multi-threaded situations.
+//
+//   The following use cases are supported:
+//    * Observers can register for notifications from any thread.
+//      Callbacks to the observer will occur on the same thread where
+//      the observer initially called AddObserver() from.
+//    * Any thread may trigger a notification via Notify().
+//    * Observers can remove themselves from the observer list inside
+//      of a callback.
+//    * If one thread is notifying observers concurrently with an observer
+//      removing itself from the observer list, the notifications will
+//      be silently dropped.
+//
+//   The drawback of the threadsafe observer list is that notifications
+//   are not as real-time as the non-threadsafe version of this class.
+//   Notifications will always be done via PostTask() to another thread,
+//   whereas with the non-thread-safe observer_list, notifications happen
+//   synchronously and immediately.
+//
+//   IMPLEMENTATION NOTES
+//   The ObserverListThreadSafe maintains an ObserverList for each thread
+//   which uses the ThreadSafeObserver.  When Notifying the observers,
+//   we simply call PostTask to each registered thread, and then each thread
+//   will notify its regular ObserverList.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Forward declaration for ObserverListThreadSafeTraits.
+template <class ObserverType>
+class ObserverListThreadSafe;
+
+// An UnboundMethod is a wrapper for a method where the actual object is
+// provided at Run dispatch time.
+template <class T, class Method, class Params>
+class UnboundMethod {
+ public:
+  UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
+    COMPILE_ASSERT(
+        (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+        badunboundmethodparams);
+  }
+  void Run(T* obj) const {
+    DispatchToMethod(obj, m_, p_);
+  }
+ private:
+  Method m_;
+  Params p_;
+};
+
+// This class is used to work around VS2005 not accepting:
+//
+// friend class
+//     base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
+//
+// Instead of friending the class, we could friend the actual function
+// which calls delete.  However, this ends up being
+// RefCountedThreadSafe::DeleteInternal(), which is private.  So we
+// define our own templated traits class so we can friend it.
+template <class T>
+struct ObserverListThreadSafeTraits {
+  static void Destruct(const ObserverListThreadSafe<T>* x) {
+    delete x;
+  }
+};
+
+template <class ObserverType>
+class ObserverListThreadSafe
+    : public base::RefCountedThreadSafe<
+        ObserverListThreadSafe<ObserverType>,
+        ObserverListThreadSafeTraits<ObserverType> > {
+ public:
+  typedef typename ObserverList<ObserverType>::NotificationType
+      NotificationType;
+
+  ObserverListThreadSafe()
+      : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
+  explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
+
+  // Add an observer to the list.  An observer should not be added to
+  // the same list more than once.
+  void AddObserver(ObserverType* obs) {
+    // If there is not a current MessageLoop, it is impossible to notify on it,
+    // so do not add the observer.
+    if (!base::MessageLoop::current())
+      return;
+
+    ObserverList<ObserverType>* list = nullptr;
+    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+    {
+      base::AutoLock lock(list_lock_);
+      if (observer_lists_.find(thread_id) == observer_lists_.end())
+        observer_lists_[thread_id] = new ObserverListContext(type_);
+      list = &(observer_lists_[thread_id]->list);
+    }
+    list->AddObserver(obs);
+  }
+
+  // Remove an observer from the list if it is in the list.
+  // If there are pending notifications in-transit to the observer, they will
+  // be aborted.
+  // If the observer to be removed is in the list, RemoveObserver MUST
+  // be called from the same thread which called AddObserver.
+  void RemoveObserver(ObserverType* obs) {
+    ObserverListContext* context = nullptr;
+    ObserverList<ObserverType>* list = nullptr;
+    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
+    {
+      base::AutoLock lock(list_lock_);
+      typename ObserversListMap::iterator it = observer_lists_.find(thread_id);
+      if (it == observer_lists_.end()) {
+        // This will happen if we try to remove an observer on a thread
+        // we never added an observer for.
+        return;
+      }
+      context = it->second;
+      list = &context->list;
+
+      // If we're about to remove the last observer from the list,
+      // then we can remove this observer_list entirely.
+      if (list->HasObserver(obs) && list->size() == 1)
+        observer_lists_.erase(it);
+    }
+    list->RemoveObserver(obs);
+
+    // If RemoveObserver is called from a notification, the size will be
+    // nonzero.  Instead of deleting here, the NotifyWrapper will delete
+    // when it finishes iterating.
+    if (list->size() == 0)
+      delete context;
+  }
+
+  // Verifies that the list is currently empty (i.e. there are no observers).
+  void AssertEmpty() const {
+    base::AutoLock lock(list_lock_);
+    DCHECK(observer_lists_.empty());
+  }
+
+  // Notify methods.
+  // Make a thread-safe callback to each Observer in the list.
+  // Note, these calls are effectively asynchronous.  You cannot assume
+  // that at the completion of the Notify call that all Observers have
+  // been Notified.  The notification may still be pending delivery.
+  template <class Method, class... Params>
+  void Notify(const tracked_objects::Location& from_here,
+              Method m,
+              const Params&... params) {
+    UnboundMethod<ObserverType, Method, Tuple<Params...>> method(
+        m, MakeTuple(params...));
+
+    base::AutoLock lock(list_lock_);
+    for (const auto& entry : observer_lists_) {
+      ObserverListContext* context = entry.second;
+      context->task_runner->PostTask(
+          from_here,
+          base::Bind(
+              &ObserverListThreadSafe<ObserverType>::template NotifyWrapper<
+                  Method, Tuple<Params...>>,
+              this, context, method));
+    }
+  }
+
+ private:
+  // See comment above ObserverListThreadSafeTraits' definition.
+  friend struct ObserverListThreadSafeTraits<ObserverType>;
+
+  struct ObserverListContext {
+    explicit ObserverListContext(NotificationType type)
+        : task_runner(base::ThreadTaskRunnerHandle::Get()), list(type) {}
+
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+    ObserverList<ObserverType> list;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
+  };
+
+  ~ObserverListThreadSafe() {
+    STLDeleteValues(&observer_lists_);
+  }
+
+  // Wrapper which is called to fire the notifications for each thread's
+  // ObserverList.  This function MUST be called on the thread which owns
+  // the unsafe ObserverList.
+  template <class Method, class Params>
+  void NotifyWrapper(ObserverListContext* context,
+      const UnboundMethod<ObserverType, Method, Params>& method) {
+    // Check that this list still needs notifications.
+    {
+      base::AutoLock lock(list_lock_);
+      typename ObserversListMap::iterator it =
+          observer_lists_.find(base::PlatformThread::CurrentId());
+
+      // The ObserverList could have been removed already.  In fact, it could
+      // have been removed and then re-added!  If the master list's loop
+      // does not match this one, then we do not need to finish this
+      // notification.
+      if (it == observer_lists_.end() || it->second != context)
+        return;
+    }
+
+    {
+      typename ObserverList<ObserverType>::Iterator it(&context->list);
+      ObserverType* obs;
+      while ((obs = it.GetNext()) != nullptr)
+        method.Run(obs);
+    }
+
+    // If there are no more observers on the list, we can now delete it.
+    if (context->list.size() == 0) {
+      {
+        base::AutoLock lock(list_lock_);
+        // Remove |list| if it's not already removed.
+        // This can happen if multiple observers got removed in a notification.
+        // See http://crbug.com/55725.
+        typename ObserversListMap::iterator it =
+            observer_lists_.find(base::PlatformThread::CurrentId());
+        if (it != observer_lists_.end() && it->second == context)
+          observer_lists_.erase(it);
+      }
+      delete context;
+    }
+  }
+
+  // Key by PlatformThreadId because in tests, clients can attempt to remove
+  // observers without a MessageLoop. If this were keyed by MessageLoop, that
+  // operation would be silently ignored, leaving garbage in the ObserverList.
+  typedef std::map<base::PlatformThreadId, ObserverListContext*>
+      ObserversListMap;
+
+  mutable base::Lock list_lock_;  // Protects the observer_lists_.
+  ObserversListMap observer_lists_;
+  const NotificationType type_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
+};
+
+#endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
new file mode 100644
index 0000000..2e51e45
--- /dev/null
+++ b/base/observer_list_unittest.cc
@@ -0,0 +1,545 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/observer_list.h"
+#include "base/observer_list_threadsafe.h"
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Foo {
+ public:
+  virtual void Observe(int x) = 0;
+  virtual ~Foo() {}
+};
+
+class Adder : public Foo {
+ public:
+  explicit Adder(int scaler) : total(0), scaler_(scaler) {}
+  void Observe(int x) override { total += x * scaler_; }
+  ~Adder() override {}
+  int total;
+
+ private:
+  int scaler_;
+};
+
+class Disrupter : public Foo {
+ public:
+  Disrupter(ObserverList<Foo>* list, Foo* doomed)
+      : list_(list),
+        doomed_(doomed) {
+  }
+  ~Disrupter() override {}
+  void Observe(int x) override { list_->RemoveObserver(doomed_); }
+
+ private:
+  ObserverList<Foo>* list_;
+  Foo* doomed_;
+};
+
+class ThreadSafeDisrupter : public Foo {
+ public:
+  ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed)
+      : list_(list),
+        doomed_(doomed) {
+  }
+  ~ThreadSafeDisrupter() override {}
+  void Observe(int x) override { list_->RemoveObserver(doomed_); }
+
+ private:
+  ObserverListThreadSafe<Foo>* list_;
+  Foo* doomed_;
+};
+
+template <typename ObserverListType>
+class AddInObserve : public Foo {
+ public:
+  explicit AddInObserve(ObserverListType* observer_list)
+      : added(false),
+        observer_list(observer_list),
+        adder(1) {
+  }
+
+  void Observe(int x) override {
+    if (!added) {
+      added = true;
+      observer_list->AddObserver(&adder);
+    }
+  }
+
+  bool added;
+  ObserverListType* observer_list;
+  Adder adder;
+};
+
+
+static const int kThreadRunTime = 2000;  // ms to run the multi-threaded test.
+
+// A thread for use in the ThreadSafeObserver test
+// which will add and remove itself from the notification
+// list repeatedly.
+class AddRemoveThread : public PlatformThread::Delegate,
+                        public Foo {
+ public:
+  AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
+      : list_(list),
+        loop_(nullptr),
+        in_list_(false),
+        start_(Time::Now()),
+        count_observes_(0),
+        count_addtask_(0),
+        do_notifies_(notify),
+        weak_factory_(this) {
+  }
+
+  ~AddRemoveThread() override {}
+
+  void ThreadMain() override {
+    loop_ = new MessageLoop();  // Fire up a message loop.
+    loop_->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
+    loop_->Run();
+    //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
+    //    count_observes_ << ", " << count_addtask_;
+    delete loop_;
+    loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
+    delete this;
+  }
+
+  // This task just keeps posting to itself in an attempt
+  // to race with the notifier.
+  void AddTask() {
+    count_addtask_++;
+
+    if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
+      VLOG(1) << "DONE!";
+      return;
+    }
+
+    if (!in_list_) {
+      list_->AddObserver(this);
+      in_list_ = true;
+    }
+
+    if (do_notifies_) {
+      list_->Notify(FROM_HERE, &Foo::Observe, 10);
+    }
+
+    loop_->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
+  }
+
+  void Quit() {
+    loop_->task_runner()->PostTask(FROM_HERE,
+                                   MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void Observe(int x) override {
+    count_observes_++;
+
+    // If we're getting called after we removed ourselves from
+    // the list, that is very bad!
+    DCHECK(in_list_);
+
+    // This callback should fire on the appropriate thread
+    EXPECT_EQ(loop_, MessageLoop::current());
+
+    list_->RemoveObserver(this);
+    in_list_ = false;
+  }
+
+ private:
+  ObserverListThreadSafe<Foo>* list_;
+  MessageLoop* loop_;
+  bool in_list_;        // Are we currently registered for notifications.
+                        // in_list_ is only used on |this| thread.
+  Time start_;          // The time we started the test.
+
+  int count_observes_;  // Number of times we observed.
+  int count_addtask_;   // Number of times thread AddTask was called
+  bool do_notifies_;    // Whether these threads should do notifications.
+
+  base::WeakPtrFactory<AddRemoveThread> weak_factory_;
+};
+
+TEST(ObserverListTest, BasicTest) {
+  ObserverList<Foo> observer_list;
+  Adder a(1), b(-1), c(1), d(-1), e(-1);
+  Disrupter evil(&observer_list, &c);
+
+  observer_list.AddObserver(&a);
+  observer_list.AddObserver(&b);
+
+  EXPECT_TRUE(observer_list.HasObserver(&a));
+  EXPECT_FALSE(observer_list.HasObserver(&c));
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
+
+  observer_list.AddObserver(&evil);
+  observer_list.AddObserver(&c);
+  observer_list.AddObserver(&d);
+
+  // Removing an observer not in the list should do nothing.
+  observer_list.RemoveObserver(&e);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
+
+  EXPECT_EQ(20, a.total);
+  EXPECT_EQ(-20, b.total);
+  EXPECT_EQ(0, c.total);
+  EXPECT_EQ(-10, d.total);
+  EXPECT_EQ(0, e.total);
+}
+
+TEST(ObserverListThreadSafeTest, BasicTest) {
+  MessageLoop loop;
+
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+  Adder a(1);
+  Adder b(-1);
+  Adder c(1);
+  Adder d(-1);
+  ThreadSafeDisrupter evil(observer_list.get(), &c);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  observer_list->AddObserver(&evil);
+  observer_list->AddObserver(&c);
+  observer_list->AddObserver(&d);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(20, a.total);
+  EXPECT_EQ(-20, b.total);
+  EXPECT_EQ(0, c.total);
+  EXPECT_EQ(-10, d.total);
+}
+
+TEST(ObserverListThreadSafeTest, RemoveObserver) {
+  MessageLoop loop;
+
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+  Adder a(1), b(1);
+
+  // A workaround for the compiler bug. See http://crbug.com/121960.
+  EXPECT_NE(&a, &b);
+
+  // Should do nothing.
+  observer_list->RemoveObserver(&a);
+  observer_list->RemoveObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0, a.total);
+  EXPECT_EQ(0, b.total);
+
+  observer_list->AddObserver(&a);
+
+  // Should also do nothing.
+  observer_list->RemoveObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(10, a.total);
+  EXPECT_EQ(0, b.total);
+}
+
+TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+
+  Adder a(1), b(1), c(1);
+
+  // No MessageLoop, so these should not be added.
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  {
+    // Add c when there's a loop.
+    MessageLoop loop;
+    observer_list->AddObserver(&c);
+
+    observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+    RunLoop().RunUntilIdle();
+
+    EXPECT_EQ(0, a.total);
+    EXPECT_EQ(0, b.total);
+    EXPECT_EQ(10, c.total);
+
+    // Now add a when there's a loop.
+    observer_list->AddObserver(&a);
+
+    // Remove c when there's a loop.
+    observer_list->RemoveObserver(&c);
+
+    // Notify again.
+    observer_list->Notify(FROM_HERE, &Foo::Observe, 20);
+    RunLoop().RunUntilIdle();
+
+    EXPECT_EQ(20, a.total);
+    EXPECT_EQ(0, b.total);
+    EXPECT_EQ(10, c.total);
+  }
+
+  // Removing should always succeed with or without a loop.
+  observer_list->RemoveObserver(&a);
+
+  // Notifying should not fail but should also be a no-op.
+  MessageLoop loop;
+  observer_list->AddObserver(&b);
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 30);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(20, a.total);
+  EXPECT_EQ(30, b.total);
+  EXPECT_EQ(10, c.total);
+}
+
+class FooRemover : public Foo {
+ public:
+  explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
+  ~FooRemover() override {}
+
+  void AddFooToRemove(Foo* foo) {
+    foos_.push_back(foo);
+  }
+
+  void Observe(int x) override {
+    std::vector<Foo*> tmp;
+    tmp.swap(foos_);
+    for (std::vector<Foo*>::iterator it = tmp.begin();
+         it != tmp.end(); ++it) {
+      list_->RemoveObserver(*it);
+    }
+  }
+
+ private:
+  const scoped_refptr<ObserverListThreadSafe<Foo> > list_;
+  std::vector<Foo*> foos_;
+};
+
+TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
+  MessageLoop loop;
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+
+  FooRemover a(observer_list.get());
+  Adder b(1);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  a.AddFooToRemove(&a);
+  a.AddFooToRemove(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+  RunLoop().RunUntilIdle();
+}
+
+// A test driver for a multi-threaded notification loop.  Runs a number
+// of observer threads, each of which constantly adds/removes itself
+// from the observer list.  Optionally, if cross_thread_notifies is set
+// to true, the observer threads will also trigger notifications to
+// all observers.
+static void ThreadSafeObserverHarness(int num_threads,
+                                      bool cross_thread_notifies) {
+  MessageLoop loop;
+
+  const int kMaxThreads = 15;
+  num_threads = num_threads > kMaxThreads ? kMaxThreads : num_threads;
+
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+  Adder a(1);
+  Adder b(-1);
+  Adder c(1);
+  Adder d(-1);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  AddRemoveThread* threaded_observer[kMaxThreads];
+  base::PlatformThreadHandle threads[kMaxThreads];
+  for (int index = 0; index < num_threads; index++) {
+    threaded_observer[index] = new AddRemoveThread(observer_list.get(), false);
+    EXPECT_TRUE(PlatformThread::Create(0,
+                threaded_observer[index], &threads[index]));
+  }
+
+  Time start = Time::Now();
+  while (true) {
+    if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
+      break;
+
+    observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+
+    RunLoop().RunUntilIdle();
+  }
+
+  for (int index = 0; index < num_threads; index++) {
+    threaded_observer[index]->Quit();
+    PlatformThread::Join(threads[index]);
+  }
+}
+
+TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
+  // Use 7 observer threads.  Notifications only come from
+  // the main thread.
+  ThreadSafeObserverHarness(7, false);
+}
+
+TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
+  // Use 3 observer threads.  Notifications will fire from
+  // the main thread and all 3 observer threads.
+  ThreadSafeObserverHarness(3, true);
+}
+
+TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) {
+  MessageLoop* loop = new MessageLoop;
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+
+  Adder a(1);
+  observer_list->AddObserver(&a);
+  delete loop;
+  // Test passes if we don't crash here.
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+}
+
+TEST(ObserverListTest, Existing) {
+  ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
+  Adder a(1);
+  AddInObserve<ObserverList<Foo> > b(&observer_list);
+
+  observer_list.AddObserver(&a);
+  observer_list.AddObserver(&b);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+
+  EXPECT_TRUE(b.added);
+  // B's adder should not have been notified because it was added during
+  // notification.
+  EXPECT_EQ(0, b.adder.total);
+
+  // Notify again to make sure b's adder is notified.
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+  EXPECT_EQ(1, b.adder.total);
+}
+
+// Same as above, but for ObserverListThreadSafe
+TEST(ObserverListThreadSafeTest, Existing) {
+  MessageLoop loop;
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY));
+  Adder a(1);
+  AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get());
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(b.added);
+  // B's adder should not have been notified because it was added during
+  // notification.
+  EXPECT_EQ(0, b.adder.total);
+
+  // Notify again to make sure b's adder is notified.
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, b.adder.total);
+}
+
+class AddInClearObserve : public Foo {
+ public:
+  explicit AddInClearObserve(ObserverList<Foo>* list)
+      : list_(list), added_(false), adder_(1) {}
+
+  void Observe(int /* x */) override {
+    list_->Clear();
+    list_->AddObserver(&adder_);
+    added_ = true;
+  }
+
+  bool added() const { return added_; }
+  const Adder& adder() const { return adder_; }
+
+ private:
+  ObserverList<Foo>* const list_;
+
+  bool added_;
+  Adder adder_;
+};
+
+TEST(ObserverListTest, ClearNotifyAll) {
+  ObserverList<Foo> observer_list;
+  AddInClearObserve a(&observer_list);
+
+  observer_list.AddObserver(&a);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+  EXPECT_TRUE(a.added());
+  EXPECT_EQ(1, a.adder().total)
+      << "Adder should observe once and have sum of 1.";
+}
+
+TEST(ObserverListTest, ClearNotifyExistingOnly) {
+  ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
+  AddInClearObserve a(&observer_list);
+
+  observer_list.AddObserver(&a);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+  EXPECT_TRUE(a.added());
+  EXPECT_EQ(0, a.adder().total)
+      << "Adder should not observe, so sum should still be 0.";
+}
+
+class ListDestructor : public Foo {
+ public:
+  explicit ListDestructor(ObserverList<Foo>* list) : list_(list) {}
+  ~ListDestructor() override {}
+
+  void Observe(int x) override { delete list_; }
+
+ private:
+  ObserverList<Foo>* list_;
+};
+
+
+TEST(ObserverListTest, IteratorOutlivesList) {
+  ObserverList<Foo>* observer_list = new ObserverList<Foo>;
+  ListDestructor a(observer_list);
+  observer_list->AddObserver(&a);
+
+  FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0));
+  // If this test fails, there'll be Valgrind errors when this function goes out
+  // of scope.
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/os_compat_android.cc b/base/os_compat_android.cc
new file mode 100644
index 0000000..b2756b2
--- /dev/null
+++ b/base/os_compat_android.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/os_compat_android.h"
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#if !defined(__LP64__)
+#include <time64.h>
+#endif
+
+#include "base/rand_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+
+extern "C" {
+// There is no futimes() avaiable in Bionic, so we provide our own
+// implementation until it is there.
+int futimes(int fd, const struct timeval tv[2]) {
+  if (tv == NULL)
+    return syscall(__NR_utimensat, fd, NULL, NULL, 0);
+
+  if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 ||
+      tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  // Convert timeval to timespec.
+  struct timespec ts[2];
+  ts[0].tv_sec = tv[0].tv_sec;
+  ts[0].tv_nsec = tv[0].tv_usec * 1000;
+  ts[1].tv_sec = tv[1].tv_sec;
+  ts[1].tv_nsec = tv[1].tv_usec * 1000;
+  return syscall(__NR_utimensat, fd, NULL, ts, 0);
+}
+
+#if !defined(__LP64__)
+// 32-bit Android has only timegm64() and not timegm().
+// We replicate the behaviour of timegm() when the result overflows time_t.
+time_t timegm(struct tm* const t) {
+  // time_t is signed on Android.
+  static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
+  static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
+  time64_t result = timegm64(t);
+  if (result < kTimeMin || result > kTimeMax)
+    return -1;
+  return result;
+}
+#endif
+
+// The following is only needed when building with GCC 4.6 or higher
+// (i.e. not with Android GCC 4.4.3, nor with Clang).
+//
+// GCC is now capable of optimizing successive calls to sin() and cos() into
+// a single call to sincos(). This means that source code that looks like:
+//
+//     double c, s;
+//     c = cos(angle);
+//     s = sin(angle);
+//
+// Will generate machine code that looks like:
+//
+//     double c, s;
+//     sincos(angle, &s, &c);
+//
+// Unfortunately, sincos() and friends are not part of the Android libm.so
+// library provided by the NDK for API level 9. When the optimization kicks
+// in, it makes the final build fail with a puzzling message (puzzling
+// because 'sincos' doesn't appear anywhere in the sources!).
+//
+// To solve this, we provide our own implementation of the sincos() function
+// and related friends. Note that we must also explicitely tell GCC to disable
+// optimizations when generating these. Otherwise, the generated machine code
+// for each function would simply end up calling itself, resulting in a
+// runtime crash due to stack overflow.
+//
+#if defined(__GNUC__) && !defined(__clang__) && \
+    !defined(ANDROID_SINCOS_PROVIDED)
+
+// For the record, Clang does not support the 'optimize' attribute.
+// In the unlikely event that it begins performing this optimization too,
+// we'll have to find a different way to achieve this. NOTE: Tested with O1
+// which still performs the optimization.
+//
+#define GCC_NO_OPTIMIZE  __attribute__((optimize("O0")))
+
+GCC_NO_OPTIMIZE
+void sincos(double angle, double* s, double *c) {
+  *c = cos(angle);
+  *s = sin(angle);
+}
+
+GCC_NO_OPTIMIZE
+void sincosf(float angle, float* s, float* c) {
+  *c = cosf(angle);
+  *s = sinf(angle);
+}
+
+#endif // __GNUC__ && !__clang__
+
+// An implementation of mkdtemp, since it is not exposed by the NDK
+// for native API level 9 that we target.
+//
+// For any changes in the mkdtemp function, you should manually run the unittest
+// OsCompatAndroidTest.DISABLED_TestMkdTemp in your local machine to check if it
+// passes. Please don't enable it, since it creates a directory and may be
+// source of flakyness.
+char* mkdtemp(char* path) {
+  if (path == NULL) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  const int path_len = strlen(path);
+
+  // The last six characters of 'path' must be XXXXXX.
+  const base::StringPiece kSuffix("XXXXXX");
+  const int kSuffixLen = kSuffix.length();
+  if (!base::StringPiece(path, path_len).ends_with(kSuffix)) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure
+  // that /tmp/foo exists, otherwise we're going to loop a really long
+  // time for nothing below
+  char* dirsep = strrchr(path, '/');
+  if (dirsep != NULL) {
+    struct stat st;
+    int ret;
+
+    *dirsep = '\0';  // Terminating directory path temporarily
+
+    ret = stat(path, &st);
+
+    *dirsep = '/';  // Restoring directory separator
+    if (ret < 0)  // Directory probably does not exist
+      return NULL;
+    if (!S_ISDIR(st.st_mode)) {  // Not a directory
+      errno = ENOTDIR;
+      return NULL;
+    }
+  }
+
+  // Max number of tries using different random suffixes.
+  const int kMaxTries = 100;
+
+  // Now loop until we CAN create a directory by that name or we reach the max
+  // number of tries.
+  for (int i = 0; i < kMaxTries; ++i) {
+    // Fill the suffix XXXXXX with a random string composed of a-z chars.
+    for (int pos = 0; pos < kSuffixLen; ++pos) {
+      char rand_char = static_cast<char>(base::RandInt('a', 'z'));
+      path[path_len - kSuffixLen + pos] = rand_char;
+    }
+    if (mkdir(path, 0700) == 0) {
+      // We just created the directory succesfully.
+      return path;
+    }
+    if (errno != EEXIST) {
+      // The directory doesn't exist, but an error occured
+      return NULL;
+    }
+  }
+
+  // We reached the max number of tries.
+  return NULL;
+}
+
+}  // extern "C"
diff --git a/base/os_compat_android.h b/base/os_compat_android.h
new file mode 100644
index 0000000..0f25444
--- /dev/null
+++ b/base/os_compat_android.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OS_COMPAT_ANDROID_H_
+#define BASE_OS_COMPAT_ANDROID_H_
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+
+// Not implemented in Bionic.
+extern "C" int futimes(int fd, const struct timeval tv[2]);
+
+// Not exposed or implemented in Bionic.
+extern "C" char* mkdtemp(char* path);
+
+// Android has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+
+// The lockf() function is not available on Android; we translate to flock().
+#define F_LOCK LOCK_EX
+#define F_ULOCK LOCK_UN
+inline int lockf(int fd, int cmd, off_t ignored_len) {
+  return flock(fd, cmd);
+}
+
+#endif  // BASE_OS_COMPAT_ANDROID_H_
diff --git a/base/os_compat_android_unittest.cc b/base/os_compat_android_unittest.cc
new file mode 100644
index 0000000..7fbdc6d
--- /dev/null
+++ b/base/os_compat_android_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/os_compat_android.h"
+
+#include "base/files/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+typedef testing::Test OsCompatAndroidTest;
+
+// Keep this Unittest DISABLED_ , because it actually creates a directory in the
+// device and it may be source of flakyness. For any changes in the mkdtemp
+// function, you should run this unittest in your local machine to check if it
+// passes.
+TEST_F(OsCompatAndroidTest, DISABLED_TestMkdTemp) {
+  FilePath tmp_dir;
+  EXPECT_TRUE(base::GetTempDir(&tmp_dir));
+
+  // Not six XXXXXX at the suffix of the path.
+  FilePath sub_dir = tmp_dir.Append("XX");
+  std::string sub_dir_string = sub_dir.value();
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer = const_cast<char*>(sub_dir_string.c_str());
+  EXPECT_EQ(NULL, mkdtemp(buffer));
+
+  // Directory does not exist
+  char invalid_path2[] = "doesntoexist/foobarXXXXXX";
+  EXPECT_EQ(NULL, mkdtemp(invalid_path2));
+
+  // Successfully create a tmp dir.
+  FilePath sub_dir2 = tmp_dir.Append("XXXXXX");
+  std::string sub_dir2_string = sub_dir2.value();
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer2 = const_cast<char*>(sub_dir2_string.c_str());
+  EXPECT_TRUE(mkdtemp(buffer2) != NULL);
+}
+
+}  // namespace base
diff --git a/base/os_compat_nacl.cc b/base/os_compat_nacl.cc
new file mode 100644
index 0000000..58fe93e
--- /dev/null
+++ b/base/os_compat_nacl.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/os_compat_nacl.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#if !defined (__GLIBC__)
+
+extern "C" {
+// Native Client has no timegm().
+time_t timegm(struct tm* tm) {
+  time_t ret;
+  char* tz;
+  tz = getenv("TZ");
+  setenv("TZ", "", 1);
+  tzset();
+  ret = mktime(tm);
+  if (tz)
+    setenv("TZ", tz, 1);
+  else
+    unsetenv("TZ");
+  tzset();
+  return ret;
+}
+}  // extern "C"
+
+#endif  // !defined (__GLIBC__)
diff --git a/base/os_compat_nacl.h b/base/os_compat_nacl.h
new file mode 100644
index 0000000..13e0e3f
--- /dev/null
+++ b/base/os_compat_nacl.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OS_COMPAT_NACL_H_
+#define BASE_OS_COMPAT_NACL_H_
+
+#include <sys/types.h>
+
+#if !defined (__GLIBC__)
+// NaCl has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+#endif  // !defined (__GLIBC__)
+
+#endif  // BASE_OS_COMPAT_NACL_H_
+
diff --git a/base/path_service.cc b/base/path_service.cc
new file mode 100644
index 0000000..3c437ee
--- /dev/null
+++ b/base/path_service.cc
@@ -0,0 +1,341 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/path_service.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#endif
+
+#include "base/containers/hash_tables.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+using base::FilePath;
+using base::MakeAbsoluteFilePath;
+
+namespace base {
+  bool PathProvider(int key, FilePath* result);
+#if defined(OS_WIN)
+  bool PathProviderWin(int key, FilePath* result);
+#elif defined(OS_MACOSX)
+  bool PathProviderMac(int key, FilePath* result);
+#elif defined(OS_ANDROID)
+  bool PathProviderAndroid(int key, FilePath* result);
+#elif defined(OS_POSIX)
+  // PathProviderPosix is the default path provider on POSIX OSes other than
+  // Mac and Android.
+  bool PathProviderPosix(int key, FilePath* result);
+#endif
+}  // namespace base
+
+namespace {
+
+typedef base::hash_map<int, FilePath> PathMap;
+
+// We keep a linked list of providers.  In a debug build we ensure that no two
+// providers claim overlapping keys.
+struct Provider {
+  PathService::ProviderFunc func;
+  struct Provider* next;
+#ifndef NDEBUG
+  int key_start;
+  int key_end;
+#endif
+  bool is_static;
+};
+
+Provider base_provider = {
+  base::PathProvider,
+  NULL,
+#ifndef NDEBUG
+  base::PATH_START,
+  base::PATH_END,
+#endif
+  true
+};
+
+#if defined(OS_WIN)
+Provider base_provider_win = {
+  base::PathProviderWin,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_WIN_START,
+  base::PATH_WIN_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_MACOSX)
+Provider base_provider_mac = {
+  base::PathProviderMac,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_MAC_START,
+  base::PATH_MAC_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_ANDROID)
+Provider base_provider_android = {
+  base::PathProviderAndroid,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_ANDROID_START,
+  base::PATH_ANDROID_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+Provider base_provider_posix = {
+  base::PathProviderPosix,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_POSIX_START,
+  base::PATH_POSIX_END,
+#endif
+  true
+};
+#endif
+
+
+struct PathData {
+  base::Lock lock;
+  PathMap cache;        // Cache mappings from path key to path value.
+  PathMap overrides;    // Track path overrides.
+  Provider* providers;  // Linked list of path service providers.
+  bool cache_disabled;  // Don't use cache if true;
+
+  PathData() : cache_disabled(false) {
+#if defined(OS_WIN)
+    providers = &base_provider_win;
+#elif defined(OS_MACOSX)
+    providers = &base_provider_mac;
+#elif defined(OS_ANDROID)
+    providers = &base_provider_android;
+#elif defined(OS_POSIX)
+    providers = &base_provider_posix;
+#endif
+  }
+
+  ~PathData() {
+    Provider* p = providers;
+    while (p) {
+      Provider* next = p->next;
+      if (!p->is_static)
+        delete p;
+      p = next;
+    }
+  }
+};
+
+static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
+
+static PathData* GetPathData() {
+  return g_path_data.Pointer();
+}
+
+// Tries to find |key| in the cache. |path_data| should be locked by the caller!
+bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
+  if (path_data->cache_disabled)
+    return false;
+  // check for a cached version
+  PathMap::const_iterator it = path_data->cache.find(key);
+  if (it != path_data->cache.end()) {
+    *result = it->second;
+    return true;
+  }
+  return false;
+}
+
+// Tries to find |key| in the overrides map. |path_data| should be locked by the
+// caller!
+bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
+  // check for an overridden version.
+  PathMap::const_iterator it = path_data->overrides.find(key);
+  if (it != path_data->overrides.end()) {
+    if (!path_data->cache_disabled)
+      path_data->cache[key] = it->second;
+    *result = it->second;
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
+// characters). This isn't supported very well by Windows right now, so it is
+// moot, but we should keep this in mind for the future.
+// static
+bool PathService::Get(int key, FilePath* result) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK(result);
+  DCHECK_GE(key, base::DIR_CURRENT);
+
+  // special case the current directory because it can never be cached
+  if (key == base::DIR_CURRENT)
+    return base::GetCurrentDirectory(result);
+
+  Provider* provider = NULL;
+  {
+    base::AutoLock scoped_lock(path_data->lock);
+    if (LockedGetFromCache(key, path_data, result))
+      return true;
+
+    if (LockedGetFromOverrides(key, path_data, result))
+      return true;
+
+    // Get the beginning of the list while it is still locked.
+    provider = path_data->providers;
+  }
+
+  FilePath path;
+
+  // Iterating does not need the lock because only the list head might be
+  // modified on another thread.
+  while (provider) {
+    if (provider->func(key, &path))
+      break;
+    DCHECK(path.empty()) << "provider should not have modified path";
+    provider = provider->next;
+  }
+
+  if (path.empty())
+    return false;
+
+  if (path.ReferencesParent()) {
+    // Make sure path service never returns a path with ".." in it.
+    path = MakeAbsoluteFilePath(path);
+    if (path.empty())
+      return false;
+  }
+  *result = path;
+
+  base::AutoLock scoped_lock(path_data->lock);
+  if (!path_data->cache_disabled)
+    path_data->cache[key] = path;
+
+  return true;
+}
+
+// static
+bool PathService::Override(int key, const FilePath& path) {
+  // Just call the full function with true for the value of |create|, and
+  // assume that |path| may not be absolute yet.
+  return OverrideAndCreateIfNeeded(key, path, false, true);
+}
+
+// static
+bool PathService::OverrideAndCreateIfNeeded(int key,
+                                            const FilePath& path,
+                                            bool is_absolute,
+                                            bool create) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
+
+  FilePath file_path = path;
+
+  // For some locations this will fail if called from inside the sandbox there-
+  // fore we protect this call with a flag.
+  if (create) {
+    // Make sure the directory exists. We need to do this before we translate
+    // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
+    // if called on a non-existent path.
+    if (!base::PathExists(file_path) &&
+        !base::CreateDirectory(file_path))
+      return false;
+  }
+
+  // We need to have an absolute path.
+  if (!is_absolute) {
+    file_path = MakeAbsoluteFilePath(file_path);
+    if (file_path.empty())
+      return false;
+  }
+  DCHECK(file_path.IsAbsolute());
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+  // Clear the cache now. Some of its entries could have depended
+  // on the value we are overriding, and are now out of sync with reality.
+  path_data->cache.clear();
+
+  path_data->overrides[key] = file_path;
+
+  return true;
+}
+
+// static
+bool PathService::RemoveOverride(int key) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+  if (path_data->overrides.find(key) == path_data->overrides.end())
+    return false;
+
+  // Clear the cache now. Some of its entries could have depended on the value
+  // we are going to remove, and are now out of sync.
+  path_data->cache.clear();
+
+  path_data->overrides.erase(key);
+
+  return true;
+}
+
+// static
+void PathService::RegisterProvider(ProviderFunc func, int key_start,
+                                   int key_end) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK_GT(key_end, key_start);
+
+  Provider* p;
+
+  p = new Provider;
+  p->is_static = false;
+  p->func = func;
+#ifndef NDEBUG
+  p->key_start = key_start;
+  p->key_end = key_end;
+#endif
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+#ifndef NDEBUG
+  Provider *iter = path_data->providers;
+  while (iter) {
+    DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
+      "path provider collision";
+    iter = iter->next;
+  }
+#endif
+
+  p->next = path_data->providers;
+  path_data->providers = p;
+}
+
+// static
+void PathService::DisableCache() {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+
+  base::AutoLock scoped_lock(path_data->lock);
+  path_data->cache.clear();
+  path_data->cache_disabled = true;
+}
diff --git a/base/path_service.h b/base/path_service.h
new file mode 100644
index 0000000..025550f
--- /dev/null
+++ b/base/path_service.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PATH_SERVICE_H_
+#define BASE_PATH_SERVICE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/base_paths.h"
+#include "base/gtest_prod_util.h"
+#include "build/build_config.h"
+
+namespace base {
+class FilePath;
+class ScopedPathOverride;
+}  // namespace base
+
+// The path service is a global table mapping keys to file system paths.  It is
+// OK to use this service from multiple threads.
+//
+class BASE_EXPORT PathService {
+ public:
+  // Retrieves a path to a special directory or file and places it into the
+  // string pointed to by 'path'. If you ask for a directory it is guaranteed
+  // to NOT have a path separator at the end. For example, "c:\windows\temp"
+  // Directories are also guaranteed to exist when this function succeeds.
+  //
+  // Returns true if the directory or file was successfully retrieved. On
+  // failure, 'path' will not be changed.
+  static bool Get(int key, base::FilePath* path);
+
+  // Overrides the path to a special directory or file.  This cannot be used to
+  // change the value of DIR_CURRENT, but that should be obvious.  Also, if the
+  // path specifies a directory that does not exist, the directory will be
+  // created by this method.  This method returns true if successful.
+  //
+  // If the given path is relative, then it will be resolved against
+  // DIR_CURRENT.
+  //
+  // WARNING: Consumers of PathService::Get may expect paths to be constant
+  // over the lifetime of the app, so this method should be used with caution.
+  //
+  // Unit tests generally should use ScopedPathOverride instead. Overrides from
+  // one test should not carry over to another.
+  static bool Override(int key, const base::FilePath& path);
+
+  // This function does the same as PathService::Override but it takes extra
+  // parameters:
+  // - |is_absolute| indicates that |path| has already been expanded into an
+  // absolute path, otherwise MakeAbsoluteFilePath() will be used. This is
+  // useful to override paths that may not exist yet, since MakeAbsoluteFilePath
+  // fails for those. Note that MakeAbsoluteFilePath also expands symbolic
+  // links, even if path.IsAbsolute() is already true.
+  // - |create| guides whether the directory to be overriden must
+  // be created in case it doesn't exist already.
+  static bool OverrideAndCreateIfNeeded(int key,
+                                        const base::FilePath& path,
+                                        bool is_absolute,
+                                        bool create);
+
+  // To extend the set of supported keys, you can register a path provider,
+  // which is just a function mirroring PathService::Get.  The ProviderFunc
+  // returns false if it cannot provide a non-empty path for the given key.
+  // Otherwise, true is returned.
+  //
+  // WARNING: This function could be called on any thread from which the
+  // PathService is used, so a the ProviderFunc MUST BE THREADSAFE.
+  //
+  typedef bool (*ProviderFunc)(int, base::FilePath*);
+
+  // Call to register a path provider.  You must specify the range "[key_start,
+  // key_end)" of supported path keys.
+  static void RegisterProvider(ProviderFunc provider,
+                               int key_start,
+                               int key_end);
+
+  // Disable internal cache.
+  static void DisableCache();
+
+ private:
+  friend class base::ScopedPathOverride;
+  FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
+
+  // Removes an override for a special directory or file. Returns true if there
+  // was an override to remove or false if none was present.
+  // NOTE: This function is intended to be used by tests only!
+  static bool RemoveOverride(int key);
+};
+
+#endif  // BASE_PATH_SERVICE_H_
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
new file mode 100644
index 0000000..7551d67
--- /dev/null
+++ b/base/path_service_unittest.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/path_service.h"
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+namespace {
+
+// Returns true if PathService::Get returns true and sets the path parameter
+// to non-empty for the given PathService::DirType enumeration value.
+bool ReturnsValidPath(int dir_type) {
+  base::FilePath path;
+  bool result = PathService::Get(dir_type, &path);
+
+  // Some paths might not exist on some platforms in which case confirming
+  // |result| is true and !path.empty() is the best we can do.
+  bool check_path_exists = true;
+#if defined(OS_POSIX)
+  // If chromium has never been started on this account, the cache path may not
+  // exist.
+  if (dir_type == base::DIR_CACHE)
+    check_path_exists = false;
+#endif
+#if defined(OS_LINUX)
+  // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop),
+  // but it doesn't exist.
+  if (dir_type == base::DIR_USER_DESKTOP)
+    check_path_exists = false;
+#endif
+#if defined(OS_WIN)
+  if (dir_type == base::DIR_TASKBAR_PINS) {
+    // There is no pinned-to-taskbar shortcuts prior to Win7.
+    if (base::win::GetVersion() < base::win::VERSION_WIN7)
+      check_path_exists = false;
+  }
+#endif
+#if defined(OS_MACOSX)
+  if (dir_type != base::DIR_EXE && dir_type != base::DIR_MODULE &&
+      dir_type != base::FILE_EXE && dir_type != base::FILE_MODULE) {
+    if (path.ReferencesParent())
+      return false;
+  }
+#else
+  if (path.ReferencesParent())
+    return false;
+#endif
+  return result && !path.empty() && (!check_path_exists ||
+                                     base::PathExists(path));
+}
+
+#if defined(OS_WIN)
+// Function to test any directory keys that are not supported on some versions
+// of Windows. Checks that the function fails and that the returned path is
+// empty.
+bool ReturnsInvalidPath(int dir_type) {
+  base::FilePath path;
+  bool result = PathService::Get(dir_type, &path);
+  return !result && path.empty();
+}
+#endif
+
+}  // namespace
+
+// On the Mac this winds up using some autoreleased objects, so we need to
+// be a PlatformTest.
+typedef PlatformTest PathServiceTest;
+
+// Test that all PathService::Get calls return a value and a true result
+// in the development environment.  (This test was created because a few
+// later changes to Get broke the semantics of the function and yielded the
+// correct value while returning false.)
+TEST_F(PathServiceTest, Get) {
+  for (int key = base::PATH_START + 1; key < base::PATH_END; ++key) {
+#if defined(OS_ANDROID)
+    if (key == base::FILE_MODULE || key == base::DIR_USER_DESKTOP ||
+        key == base::DIR_HOME)
+      continue;  // Android doesn't implement these.
+#elif defined(OS_IOS)
+    if (key == base::DIR_USER_DESKTOP)
+      continue;  // iOS doesn't implement DIR_USER_DESKTOP;
+#endif
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#if defined(OS_WIN)
+  for (int key = base::PATH_WIN_START + 1; key < base::PATH_WIN_END; ++key) {
+    bool valid = true;
+    if (key == base::DIR_APP_SHORTCUTS)
+      valid = base::win::GetVersion() >= base::win::VERSION_WIN8;
+
+    if (valid)
+      EXPECT_TRUE(ReturnsValidPath(key)) << key;
+    else
+      EXPECT_TRUE(ReturnsInvalidPath(key)) << key;
+  }
+#elif defined(OS_MACOSX)
+  for (int key = base::PATH_MAC_START + 1; key < base::PATH_MAC_END; ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#elif defined(OS_ANDROID)
+  for (int key = base::PATH_ANDROID_START + 1; key < base::PATH_ANDROID_END;
+       ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#elif defined(OS_POSIX)
+  for (int key = base::PATH_POSIX_START + 1; key < base::PATH_POSIX_END;
+       ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#endif
+}
+
+// Test that all versions of the Override function of PathService do what they
+// are supposed to do.
+TEST_F(PathServiceTest, Override) {
+  int my_special_key = 666;
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath fake_cache_dir(temp_dir.path().AppendASCII("cache"));
+  // PathService::Override should always create the path provided if it doesn't
+  // exist.
+  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir));
+
+  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("cache2"));
+  // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter.
+  PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                         fake_cache_dir2,
+                                         false,
+                                         false);
+  EXPECT_FALSE(base::PathExists(fake_cache_dir2));
+  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                     fake_cache_dir2,
+                                                     false,
+                                                     true));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
+
+#if defined(OS_POSIX)
+  base::FilePath non_existent(
+      base::MakeAbsoluteFilePath(temp_dir.path()).AppendASCII("non_existent"));
+  EXPECT_TRUE(non_existent.IsAbsolute());
+  EXPECT_FALSE(base::PathExists(non_existent));
+#if !defined(OS_ANDROID)
+  // This fails because MakeAbsoluteFilePath fails for non-existent files.
+  // Earlier versions of Bionic libc don't fail for non-existent files, so
+  // skip this check on Android.
+  EXPECT_FALSE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                      non_existent,
+                                                      false,
+                                                      false));
+#endif
+  // This works because indicating that |non_existent| is absolute skips the
+  // internal MakeAbsoluteFilePath call.
+  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                     non_existent,
+                                                     true,
+                                                     false));
+  // Check that the path has been overridden and no directory was created.
+  EXPECT_FALSE(base::PathExists(non_existent));
+  base::FilePath path;
+  EXPECT_TRUE(PathService::Get(my_special_key, &path));
+  EXPECT_EQ(non_existent, path);
+#endif
+}
+
+// Check if multiple overrides can co-exist.
+TEST_F(PathServiceTest, OverrideMultiple) {
+  int my_special_key = 666;
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath fake_cache_dir1(temp_dir.path().AppendASCII("1"));
+  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir1));
+  ASSERT_EQ(1, base::WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1));
+
+  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("2"));
+  EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
+  ASSERT_EQ(1, base::WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1));
+
+  base::FilePath result;
+  EXPECT_TRUE(PathService::Get(my_special_key, &result));
+  // Override might have changed the path representation but our test file
+  // should be still there.
+  EXPECT_TRUE(base::PathExists(result.AppendASCII("t1")));
+  EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
+  EXPECT_TRUE(base::PathExists(result.AppendASCII("t2")));
+}
+
+TEST_F(PathServiceTest, RemoveOverride) {
+  // Before we start the test we have to call RemoveOverride at least once to
+  // clear any overrides that might have been left from other tests.
+  PathService::RemoveOverride(base::DIR_TEMP);
+
+  base::FilePath original_user_data_dir;
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &original_user_data_dir));
+  EXPECT_FALSE(PathService::RemoveOverride(base::DIR_TEMP));
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(PathService::Override(base::DIR_TEMP, temp_dir.path()));
+  base::FilePath new_user_data_dir;
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
+  EXPECT_NE(original_user_data_dir, new_user_data_dir);
+
+  EXPECT_TRUE(PathService::RemoveOverride(base::DIR_TEMP));
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
+  EXPECT_EQ(original_user_data_dir, new_user_data_dir);
+}
+
+#if defined(OS_WIN)
+TEST_F(PathServiceTest, GetProgramFiles) {
+  base::FilePath programfiles_dir;
+#if defined(_WIN64)
+  // 64-bit on 64-bit.
+  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+      &programfiles_dir));
+  EXPECT_EQ(programfiles_dir.value(),
+      FILE_PATH_LITERAL("C:\\Program Files"));
+  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+      &programfiles_dir));
+  EXPECT_EQ(programfiles_dir.value(),
+      FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+      &programfiles_dir));
+  EXPECT_EQ(programfiles_dir.value(),
+      FILE_PATH_LITERAL("C:\\Program Files"));
+#else
+  if (base::win::OSInfo::GetInstance()->wow64_status() ==
+      base::win::OSInfo::WOW64_ENABLED) {
+    // 32-bit on 64-bit.
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+  } else {
+    // 32-bit on 32-bit.
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+  }
+#endif
+}
+#endif
diff --git a/base/pending_task.cc b/base/pending_task.cc
new file mode 100644
index 0000000..3d78914
--- /dev/null
+++ b/base/pending_task.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/pending_task.h"
+
+#include "base/tracked_objects.h"
+
+namespace base {
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         const base::Closure& task)
+    : base::TrackingInfo(posted_from, TimeTicks()),
+      task(task),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(true),
+      is_high_res(false) {
+}
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         const base::Closure& task,
+                         TimeTicks delayed_run_time,
+                         bool nestable)
+    : base::TrackingInfo(posted_from, delayed_run_time),
+      task(task),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(nestable),
+      is_high_res(false) {
+}
+
+PendingTask::~PendingTask() {
+}
+
+bool PendingTask::operator<(const PendingTask& other) const {
+  // Since the top of a priority queue is defined as the "greatest" element, we
+  // need to invert the comparison here.  We want the smaller time to be at the
+  // top of the heap.
+
+  if (delayed_run_time < other.delayed_run_time)
+    return false;
+
+  if (delayed_run_time > other.delayed_run_time)
+    return true;
+
+  // If the times happen to match, then we use the sequence number to decide.
+  // Compare the difference to support integer roll-over.
+  return (sequence_num - other.sequence_num) > 0;
+}
+
+void TaskQueue::Swap(TaskQueue* queue) {
+  c.swap(queue->c);  // Calls std::deque::swap.
+}
+
+}  // namespace base
diff --git a/base/pending_task.h b/base/pending_task.h
new file mode 100644
index 0000000..fddfc86
--- /dev/null
+++ b/base/pending_task.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PENDING_TASK_H_
+#define BASE_PENDING_TASK_H_
+
+#include <queue>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "base/tracking_info.h"
+
+namespace base {
+
+// Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue
+// for use by classes that queue and execute tasks.
+struct BASE_EXPORT PendingTask : public TrackingInfo {
+  PendingTask(const tracked_objects::Location& posted_from,
+              const Closure& task);
+  PendingTask(const tracked_objects::Location& posted_from,
+              const Closure& task,
+              TimeTicks delayed_run_time,
+              bool nestable);
+  ~PendingTask();
+
+  // Used to support sorting.
+  bool operator<(const PendingTask& other) const;
+
+  // The task to run.
+  Closure task;
+
+  // The site this PendingTask was posted from.
+  tracked_objects::Location posted_from;
+
+  // Secondary sort key for run time.
+  int sequence_num;
+
+  // OK to dispatch from a nested loop.
+  bool nestable;
+
+  // Needs high resolution timers.
+  bool is_high_res;
+};
+
+// Wrapper around std::queue specialized for PendingTask which adds a Swap
+// helper method.
+class BASE_EXPORT TaskQueue : public std::queue<PendingTask> {
+ public:
+  void Swap(TaskQueue* queue);
+};
+
+// PendingTasks are sorted by their |delayed_run_time| property.
+typedef std::priority_queue<base::PendingTask> DelayedTaskQueue;
+
+}  // namespace base
+
+#endif  // BASE_PENDING_TASK_H_
diff --git a/base/pickle.cc b/base/pickle.cc
new file mode 100644
index 0000000..112ddc3
--- /dev/null
+++ b/base/pickle.cc
@@ -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.
+
+#include "base/pickle.h"
+
+#include <stdlib.h>
+
+#include <algorithm>  // for max()
+
+//------------------------------------------------------------------------------
+
+using base::char16;
+using base::string16;
+
+// static
+const int Pickle::kPayloadUnit = 64;
+
+static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
+
+PickleIterator::PickleIterator(const Pickle& pickle)
+    : payload_(pickle.payload()),
+      read_index_(0),
+      end_index_(pickle.payload_size()) {
+}
+
+template <typename Type>
+inline bool PickleIterator::ReadBuiltinType(Type* result) {
+  const char* read_from = GetReadPointerAndAdvance<Type>();
+  if (!read_from)
+    return false;
+  if (sizeof(Type) > sizeof(uint32))
+    memcpy(result, read_from, sizeof(*result));
+  else
+    *result = *reinterpret_cast<const Type*>(read_from);
+  return true;
+}
+
+inline void PickleIterator::Advance(size_t size) {
+  size_t aligned_size = AlignInt(size, sizeof(uint32_t));
+  if (end_index_ - read_index_ < aligned_size) {
+    read_index_ = end_index_;
+  } else {
+    read_index_ += aligned_size;
+  }
+}
+
+template<typename Type>
+inline const char* PickleIterator::GetReadPointerAndAdvance() {
+  if (sizeof(Type) > end_index_ - read_index_) {
+    read_index_ = end_index_;
+    return NULL;
+  }
+  const char* current_read_ptr = payload_ + read_index_;
+  Advance(sizeof(Type));
+  return current_read_ptr;
+}
+
+const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
+  if (num_bytes < 0 ||
+      end_index_ - read_index_ < static_cast<size_t>(num_bytes)) {
+    read_index_ = end_index_;
+    return NULL;
+  }
+  const char* current_read_ptr = payload_ + read_index_;
+  Advance(num_bytes);
+  return current_read_ptr;
+}
+
+inline const char* PickleIterator::GetReadPointerAndAdvance(
+    int num_elements,
+    size_t size_element) {
+  // Check for int32 overflow.
+  int64 num_bytes = static_cast<int64>(num_elements) * size_element;
+  int num_bytes32 = static_cast<int>(num_bytes);
+  if (num_bytes != static_cast<int64>(num_bytes32))
+    return NULL;
+  return GetReadPointerAndAdvance(num_bytes32);
+}
+
+bool PickleIterator::ReadBool(bool* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt(int* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadLong(long* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt16(uint16* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt32(uint32* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt64(int64* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt64(uint64* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadSizeT(size_t* result) {
+  // Always read size_t as a 64-bit value to ensure compatibility between 32-bit
+  // and 64-bit processes.
+  uint64 result_uint64 = 0;
+  bool success = ReadBuiltinType(&result_uint64);
+  *result = static_cast<size_t>(result_uint64);
+  // Fail if the cast above truncates the value.
+  return success && (*result == result_uint64);
+}
+
+bool PickleIterator::ReadFloat(float* result) {
+  // crbug.com/315213
+  // The source data may not be properly aligned, and unaligned float reads
+  // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
+  // into the result.
+  const char* read_from = GetReadPointerAndAdvance<float>();
+  if (!read_from)
+    return false;
+  memcpy(result, read_from, sizeof(*result));
+  return true;
+}
+
+bool PickleIterator::ReadDouble(double* result) {
+  // crbug.com/315213
+  // The source data may not be properly aligned, and unaligned double reads
+  // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
+  // into the result.
+  const char* read_from = GetReadPointerAndAdvance<double>();
+  if (!read_from)
+    return false;
+  memcpy(result, read_from, sizeof(*result));
+  return true;
+}
+
+bool PickleIterator::ReadString(std::string* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len);
+  if (!read_from)
+    return false;
+
+  result->assign(read_from, len);
+  return true;
+}
+
+bool PickleIterator::ReadStringPiece(base::StringPiece* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len);
+  if (!read_from)
+    return false;
+
+  *result = base::StringPiece(read_from, len);
+  return true;
+}
+
+bool PickleIterator::ReadString16(string16* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
+  if (!read_from)
+    return false;
+
+  result->assign(reinterpret_cast<const char16*>(read_from), len);
+  return true;
+}
+
+bool PickleIterator::ReadStringPiece16(base::StringPiece16* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
+  if (!read_from)
+    return false;
+
+  *result = base::StringPiece16(reinterpret_cast<const char16*>(read_from),
+                                len);
+  return true;
+}
+
+bool PickleIterator::ReadData(const char** data, int* length) {
+  *length = 0;
+  *data = 0;
+
+  if (!ReadInt(length))
+    return false;
+
+  return ReadBytes(data, *length);
+}
+
+bool PickleIterator::ReadBytes(const char** data, int length) {
+  const char* read_from = GetReadPointerAndAdvance(length);
+  if (!read_from)
+    return false;
+  *data = read_from;
+  return true;
+}
+
+// Payload is uint32 aligned.
+
+Pickle::Pickle()
+    : header_(NULL),
+      header_size_(sizeof(Header)),
+      capacity_after_header_(0),
+      write_offset_(0) {
+  Resize(kPayloadUnit);
+  header_->payload_size = 0;
+}
+
+Pickle::Pickle(int header_size)
+    : header_(NULL),
+      header_size_(AlignInt(header_size, sizeof(uint32))),
+      capacity_after_header_(0),
+      write_offset_(0) {
+  DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
+  DCHECK_LE(header_size, kPayloadUnit);
+  Resize(kPayloadUnit);
+  header_->payload_size = 0;
+}
+
+Pickle::Pickle(const char* data, int data_len)
+    : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
+      header_size_(0),
+      capacity_after_header_(kCapacityReadOnly),
+      write_offset_(0) {
+  if (data_len >= static_cast<int>(sizeof(Header)))
+    header_size_ = data_len - header_->payload_size;
+
+  if (header_size_ > static_cast<unsigned int>(data_len))
+    header_size_ = 0;
+
+  if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
+    header_size_ = 0;
+
+  // If there is anything wrong with the data, we're not going to use it.
+  if (!header_size_)
+    header_ = NULL;
+}
+
+Pickle::Pickle(const Pickle& other)
+    : header_(NULL),
+      header_size_(other.header_size_),
+      capacity_after_header_(0),
+      write_offset_(other.write_offset_) {
+  size_t payload_size = header_size_ + other.header_->payload_size;
+  Resize(payload_size);
+  memcpy(header_, other.header_, payload_size);
+}
+
+Pickle::~Pickle() {
+  if (capacity_after_header_ != kCapacityReadOnly)
+    free(header_);
+}
+
+Pickle& Pickle::operator=(const Pickle& other) {
+  if (this == &other) {
+    NOTREACHED();
+    return *this;
+  }
+  if (capacity_after_header_ == kCapacityReadOnly) {
+    header_ = NULL;
+    capacity_after_header_ = 0;
+  }
+  if (header_size_ != other.header_size_) {
+    free(header_);
+    header_ = NULL;
+    header_size_ = other.header_size_;
+  }
+  Resize(other.header_->payload_size);
+  memcpy(header_, other.header_,
+         other.header_size_ + other.header_->payload_size);
+  write_offset_ = other.write_offset_;
+  return *this;
+}
+
+bool Pickle::WriteString(const base::StringPiece& value) {
+  if (!WriteInt(static_cast<int>(value.size())))
+    return false;
+
+  return WriteBytes(value.data(), static_cast<int>(value.size()));
+}
+
+bool Pickle::WriteString16(const base::StringPiece16& value) {
+  if (!WriteInt(static_cast<int>(value.size())))
+    return false;
+
+  return WriteBytes(value.data(),
+                    static_cast<int>(value.size()) * sizeof(char16));
+}
+
+bool Pickle::WriteData(const char* data, int length) {
+  return length >= 0 && WriteInt(length) && WriteBytes(data, length);
+}
+
+bool Pickle::WriteBytes(const void* data, int length) {
+  WriteBytesCommon(data, length);
+  return true;
+}
+
+void Pickle::Reserve(size_t length) {
+  size_t data_len = AlignInt(length, sizeof(uint32));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, kuint32max);
+#endif
+  DCHECK_LE(write_offset_, kuint32max - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_)
+    Resize(capacity_after_header_ * 2 + new_size);
+}
+
+void Pickle::Resize(size_t new_capacity) {
+  new_capacity = AlignInt(new_capacity, kPayloadUnit);
+
+  CHECK_NE(capacity_after_header_, kCapacityReadOnly);
+  void* p = realloc(header_, header_size_ + new_capacity);
+  CHECK(p);
+  header_ = reinterpret_cast<Header*>(p);
+  capacity_after_header_ = new_capacity;
+}
+
+// static
+const char* Pickle::FindNext(size_t header_size,
+                             const char* start,
+                             const char* end) {
+  DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
+  DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
+
+  size_t length = static_cast<size_t>(end - start);
+  if (length < sizeof(Header))
+    return NULL;
+
+  const Header* hdr = reinterpret_cast<const Header*>(start);
+  if (length < header_size || length - header_size < hdr->payload_size)
+    return NULL;
+  return start + header_size + hdr->payload_size;
+}
+
+template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
+  WriteBytesCommon(data, length);
+}
+
+template void Pickle::WriteBytesStatic<2>(const void* data);
+template void Pickle::WriteBytesStatic<4>(const void* data);
+template void Pickle::WriteBytesStatic<8>(const void* data);
+
+inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+  DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
+      << "oops: pickle is readonly";
+  MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
+  size_t data_len = AlignInt(length, sizeof(uint32));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, kuint32max);
+#endif
+  DCHECK_LE(write_offset_, kuint32max - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_) {
+    Resize(std::max(capacity_after_header_ * 2, new_size));
+  }
+
+  char* write = mutable_payload() + write_offset_;
+  memcpy(write, data, length);
+  memset(write + length, 0, data_len - length);
+  header_->payload_size = static_cast<uint32>(new_size);
+  write_offset_ = new_size;
+}
diff --git a/base/pickle.h b/base/pickle.h
new file mode 100644
index 0000000..e6b9d81
--- /dev/null
+++ b/base/pickle.h
@@ -0,0 +1,307 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PICKLE_H__
+#define BASE_PICKLE_H__
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+class Pickle;
+
+// PickleIterator reads data from a Pickle. The Pickle object must remain valid
+// while the PickleIterator object is in use.
+class BASE_EXPORT PickleIterator {
+ public:
+  PickleIterator() : payload_(NULL), read_index_(0), end_index_(0) {}
+  explicit PickleIterator(const Pickle& pickle);
+
+  // Methods for reading the payload of the Pickle. To read from the start of
+  // the Pickle, create a PickleIterator from a Pickle. If successful, these
+  // methods return true. Otherwise, false is returned to indicate that the
+  // result could not be extracted. It is not possible to read from the iterator
+  // after that.
+  bool ReadBool(bool* result) WARN_UNUSED_RESULT;
+  bool ReadInt(int* result) WARN_UNUSED_RESULT;
+  bool ReadLong(long* result) WARN_UNUSED_RESULT;
+  bool ReadUInt16(uint16* result) WARN_UNUSED_RESULT;
+  bool ReadUInt32(uint32* result) WARN_UNUSED_RESULT;
+  bool ReadInt64(int64* result) WARN_UNUSED_RESULT;
+  bool ReadUInt64(uint64* result) WARN_UNUSED_RESULT;
+  bool ReadSizeT(size_t* result) WARN_UNUSED_RESULT;
+  bool ReadFloat(float* result) WARN_UNUSED_RESULT;
+  bool ReadDouble(double* result) WARN_UNUSED_RESULT;
+  bool ReadString(std::string* result) WARN_UNUSED_RESULT;
+  // The StringPiece data will only be valid for the lifetime of the message.
+  bool ReadStringPiece(base::StringPiece* result) WARN_UNUSED_RESULT;
+  bool ReadString16(base::string16* result) WARN_UNUSED_RESULT;
+  // The StringPiece16 data will only be valid for the lifetime of the message.
+  bool ReadStringPiece16(base::StringPiece16* result) WARN_UNUSED_RESULT;
+
+  // A pointer to the data will be placed in |*data|, and the length will be
+  // placed in |*length|. The pointer placed into |*data| points into the
+  // message's buffer so it will be scoped to the lifetime of the message (or
+  // until the message data is mutated). Do not keep the pointer around!
+  bool ReadData(const char** data, int* length) WARN_UNUSED_RESULT;
+
+  // A pointer to the data will be placed in |*data|. The caller specifies the
+  // number of bytes to read, and ReadBytes will validate this length. The
+  // pointer placed into |*data| points into the message's buffer so it will be
+  // scoped to the lifetime of the message (or until the message data is
+  // mutated). Do not keep the pointer around!
+  bool ReadBytes(const char** data, int length) WARN_UNUSED_RESULT;
+
+  // A safer version of ReadInt() that checks for the result not being negative.
+  // Use it for reading the object sizes.
+  bool ReadLength(int* result) WARN_UNUSED_RESULT {
+    return ReadInt(result) && *result >= 0;
+  }
+
+  // Skips bytes in the read buffer and returns true if there are at least
+  // num_bytes available. Otherwise, does nothing and returns false.
+  bool SkipBytes(int num_bytes) WARN_UNUSED_RESULT {
+    return !!GetReadPointerAndAdvance(num_bytes);
+  }
+
+ private:
+  // Aligns 'i' by rounding it up to the next multiple of 'alignment'.
+  static size_t AlignInt(size_t i, int alignment) {
+    return i + (alignment - (i % alignment)) % alignment;
+  }
+
+  // Read Type from Pickle.
+  template <typename Type>
+  bool ReadBuiltinType(Type* result);
+
+  // Advance read_index_ but do not allow it to exceed end_index_.
+  // Keeps read_index_ aligned.
+  void Advance(size_t size);
+
+  // Get read pointer for Type and advance read pointer.
+  template<typename Type>
+  const char* GetReadPointerAndAdvance();
+
+  // Get read pointer for |num_bytes| and advance read pointer. This method
+  // checks num_bytes for negativity and wrapping.
+  const char* GetReadPointerAndAdvance(int num_bytes);
+
+  // Get read pointer for (num_elements * size_element) bytes and advance read
+  // pointer. This method checks for int overflow, negativity and wrapping.
+  const char* GetReadPointerAndAdvance(int num_elements,
+                                       size_t size_element);
+
+  const char* payload_;  // Start of our pickle's payload.
+  size_t read_index_;  // Offset of the next readable byte in payload.
+  size_t end_index_;  // Payload size.
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, GetReadPointerAndAdvance);
+};
+
+// This class provides facilities for basic binary value packing and unpacking.
+//
+// The Pickle class supports appending primitive values (ints, strings, etc.)
+// to a pickle instance.  The Pickle instance grows its internal memory buffer
+// dynamically to hold the sequence of primitive values.   The internal memory
+// buffer is exposed as the "data" of the Pickle.  This "data" can be passed
+// to a Pickle object to initialize it for reading.
+//
+// When reading from a Pickle object, it is important for the consumer to know
+// what value types to read and in what order to read them as the Pickle does
+// not keep track of the type of data written to it.
+//
+// The Pickle's data has a header which contains the size of the Pickle's
+// payload.  It can optionally support additional space in the header.  That
+// space is controlled by the header_size parameter passed to the Pickle
+// constructor.
+//
+class BASE_EXPORT Pickle {
+ public:
+  // Initialize a Pickle object using the default header size.
+  Pickle();
+
+  // Initialize a Pickle object with the specified header size in bytes, which
+  // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
+  // will be rounded up to ensure that the header size is 32bit-aligned.
+  explicit Pickle(int header_size);
+
+  // Initializes a Pickle from a const block of data.  The data is not copied;
+  // instead the data is merely referenced by this Pickle.  Only const methods
+  // should be used on the Pickle when initialized this way.  The header
+  // padding size is deduced from the data length.
+  Pickle(const char* data, int data_len);
+
+  // Initializes a Pickle as a deep copy of another Pickle.
+  Pickle(const Pickle& other);
+
+  // Note: There are no virtual methods in this class.  This destructor is
+  // virtual as an element of defensive coding.  Other classes have derived from
+  // this class, and there is a *chance* that they will cast into this base
+  // class before destruction.  At least one such class does have a virtual
+  // destructor, suggesting at least some need to call more derived destructors.
+  virtual ~Pickle();
+
+  // Performs a deep copy.
+  Pickle& operator=(const Pickle& other);
+
+  // Returns the size of the Pickle's data.
+  size_t size() const { return header_size_ + header_->payload_size; }
+
+  // Returns the data for this Pickle.
+  const void* data() const { return header_; }
+
+  // Methods for adding to the payload of the Pickle.  These values are
+  // appended to the end of the Pickle's payload.  When reading values from a
+  // Pickle, it is important to read them in the order in which they were added
+  // to the Pickle.
+
+  bool WriteBool(bool value) {
+    return WriteInt(value ? 1 : 0);
+  }
+  bool WriteInt(int value) {
+    return WritePOD(value);
+  }
+  // WARNING: DO NOT USE THIS METHOD IF PICKLES ARE PERSISTED IN ANY WAY.
+  // It will write whatever a "long" is on this architecture. On 32-bit
+  // platforms, it is 32 bits. On 64-bit platforms, it is 64 bits. If persisted
+  // pickles are still around after upgrading to 64-bit, or if they are copied
+  // between dissimilar systems, YOUR PICKLES WILL HAVE GONE BAD.
+  bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
+    return WritePOD(value);
+  }
+  bool WriteUInt16(uint16 value) {
+    return WritePOD(value);
+  }
+  bool WriteUInt32(uint32 value) {
+    return WritePOD(value);
+  }
+  bool WriteInt64(int64 value) {
+    return WritePOD(value);
+  }
+  bool WriteUInt64(uint64 value) {
+    return WritePOD(value);
+  }
+  bool WriteSizeT(size_t value) {
+    // Always write size_t as a 64-bit value to ensure compatibility between
+    // 32-bit and 64-bit processes.
+    return WritePOD(static_cast<uint64>(value));
+  }
+  bool WriteFloat(float value) {
+    return WritePOD(value);
+  }
+  bool WriteDouble(double value) {
+    return WritePOD(value);
+  }
+  bool WriteString(const base::StringPiece& value);
+  bool WriteString16(const base::StringPiece16& value);
+  // "Data" is a blob with a length. When you read it out you will be given the
+  // length. See also WriteBytes.
+  bool WriteData(const char* data, int length);
+  // "Bytes" is a blob with no length. The caller must specify the length both
+  // when reading and writing. It is normally used to serialize PoD types of a
+  // known size. See also WriteData.
+  bool WriteBytes(const void* data, int length);
+
+  // Reserves space for upcoming writes when multiple writes will be made and
+  // their sizes are computed in advance. It can be significantly faster to call
+  // Reserve() before calling WriteFoo() multiple times.
+  void Reserve(size_t additional_capacity);
+
+  // Payload follows after allocation of Header (header size is customizable).
+  struct Header {
+    uint32 payload_size;  // Specifies the size of the payload.
+  };
+
+  // Returns the header, cast to a user-specified type T.  The type T must be a
+  // subclass of Header and its size must correspond to the header_size passed
+  // to the Pickle constructor.
+  template <class T>
+  T* headerT() {
+    DCHECK_EQ(header_size_, sizeof(T));
+    return static_cast<T*>(header_);
+  }
+  template <class T>
+  const T* headerT() const {
+    DCHECK_EQ(header_size_, sizeof(T));
+    return static_cast<const T*>(header_);
+  }
+
+  // The payload is the pickle data immediately following the header.
+  size_t payload_size() const {
+    return header_ ? header_->payload_size : 0;
+  }
+
+  const char* payload() const {
+    return reinterpret_cast<const char*>(header_) + header_size_;
+  }
+
+  // Returns the address of the byte immediately following the currently valid
+  // header + payload.
+  const char* end_of_payload() const {
+    // This object may be invalid.
+    return header_ ? payload() + payload_size() : NULL;
+  }
+
+ protected:
+  char* mutable_payload() {
+    return reinterpret_cast<char*>(header_) + header_size_;
+  }
+
+  size_t capacity_after_header() const {
+    return capacity_after_header_;
+  }
+
+  // Resize the capacity, note that the input value should not include the size
+  // of the header.
+  void Resize(size_t new_capacity);
+
+  // Aligns 'i' by rounding it up to the next multiple of 'alignment'
+  static size_t AlignInt(size_t i, int alignment) {
+    return i + (alignment - (i % alignment)) % alignment;
+  }
+
+  // Find the end of the pickled data that starts at range_start.  Returns NULL
+  // if the entire Pickle is not found in the given data range.
+  static const char* FindNext(size_t header_size,
+                              const char* range_start,
+                              const char* range_end);
+
+  // The allocation granularity of the payload.
+  static const int kPayloadUnit;
+
+ private:
+  friend class PickleIterator;
+
+  Header* header_;
+  size_t header_size_;  // Supports extra data between header and payload.
+  // Allocation size of payload (or -1 if allocation is const). Note: this
+  // doesn't count the header.
+  size_t capacity_after_header_;
+  // The offset at which we will write the next field. Note: this doesn't count
+  // the header.
+  size_t write_offset_;
+
+  // Just like WriteBytes, but with a compile-time size, for performance.
+  template<size_t length> void BASE_EXPORT WriteBytesStatic(const void* data);
+
+  // Writes a POD by copying its bytes.
+  template <typename T> bool WritePOD(const T& data) {
+    WriteBytesStatic<sizeof(data)>(&data);
+    return true;
+  }
+  inline void WriteBytesCommon(const void* data, size_t length);
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextOverflow);
+};
+
+#endif  // BASE_PICKLE_H__
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
new file mode 100644
index 0000000..a2c405c
--- /dev/null
+++ b/base/pickle_unittest.cc
@@ -0,0 +1,430 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Remove when this file is in the base namespace.
+using base::string16;
+
+namespace {
+
+const bool testbool1 = false;
+const bool testbool2 = true;
+const int testint = 2093847192;
+const long testlong = 1093847192;
+const uint16 testuint16 = 32123;
+const uint32 testuint32 = 1593847192;
+const int64 testint64 = -0x7E8CA9253104BDFCLL;
+const uint64 testuint64 = 0xCE8CA9253104BDF7ULL;
+const size_t testsizet = 0xFEDC7654;
+const float testfloat = 3.1415926935f;
+const double testdouble = 2.71828182845904523;
+const std::string teststring("Hello world");  // note non-aligned string length
+const std::wstring testwstring(L"Hello, world");
+const base::string16 teststring16(base::ASCIIToUTF16("Hello, world"));
+const char testrawstring[] = "Hello new world"; // Test raw string writing
+// Test raw char16 writing, assumes UTF16 encoding is ANSI for alpha chars.
+const base::char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0};
+const char testdata[] = "AAA\0BBB\0";
+const int testdatalen = arraysize(testdata) - 1;
+
+// checks that the results can be read correctly from the Pickle
+void VerifyResult(const Pickle& pickle) {
+  PickleIterator iter(pickle);
+
+  bool outbool;
+  EXPECT_TRUE(iter.ReadBool(&outbool));
+  EXPECT_FALSE(outbool);
+  EXPECT_TRUE(iter.ReadBool(&outbool));
+  EXPECT_TRUE(outbool);
+
+  int outint;
+  EXPECT_TRUE(iter.ReadInt(&outint));
+  EXPECT_EQ(testint, outint);
+
+  long outlong;
+  EXPECT_TRUE(iter.ReadLong(&outlong));
+  EXPECT_EQ(testlong, outlong);
+
+  uint16 outuint16;
+  EXPECT_TRUE(iter.ReadUInt16(&outuint16));
+  EXPECT_EQ(testuint16, outuint16);
+
+  uint32 outuint32;
+  EXPECT_TRUE(iter.ReadUInt32(&outuint32));
+  EXPECT_EQ(testuint32, outuint32);
+
+  int64 outint64;
+  EXPECT_TRUE(iter.ReadInt64(&outint64));
+  EXPECT_EQ(testint64, outint64);
+
+  uint64 outuint64;
+  EXPECT_TRUE(iter.ReadUInt64(&outuint64));
+  EXPECT_EQ(testuint64, outuint64);
+
+  size_t outsizet;
+  EXPECT_TRUE(iter.ReadSizeT(&outsizet));
+  EXPECT_EQ(testsizet, outsizet);
+
+  float outfloat;
+  EXPECT_TRUE(iter.ReadFloat(&outfloat));
+  EXPECT_EQ(testfloat, outfloat);
+
+  double outdouble;
+  EXPECT_TRUE(iter.ReadDouble(&outdouble));
+  EXPECT_EQ(testdouble, outdouble);
+
+  std::string outstring;
+  EXPECT_TRUE(iter.ReadString(&outstring));
+  EXPECT_EQ(teststring, outstring);
+
+  base::string16 outstring16;
+  EXPECT_TRUE(iter.ReadString16(&outstring16));
+  EXPECT_EQ(teststring16, outstring16);
+
+  base::StringPiece outstringpiece;
+  EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece));
+  EXPECT_EQ(testrawstring, outstringpiece);
+
+  base::StringPiece16 outstringpiece16;
+  EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16));
+  EXPECT_EQ(testrawstring16, outstringpiece16);
+
+  const char* outdata;
+  int outdatalen;
+  EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen));
+  EXPECT_EQ(testdatalen, outdatalen);
+  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
+
+  // reads past the end should fail
+  EXPECT_FALSE(iter.ReadInt(&outint));
+}
+
+}  // namespace
+
+TEST(PickleTest, EncodeDecode) {
+  Pickle pickle;
+
+  EXPECT_TRUE(pickle.WriteBool(testbool1));
+  EXPECT_TRUE(pickle.WriteBool(testbool2));
+  EXPECT_TRUE(pickle.WriteInt(testint));
+  EXPECT_TRUE(
+      pickle.WriteLongUsingDangerousNonPortableLessPersistableForm(testlong));
+  EXPECT_TRUE(pickle.WriteUInt16(testuint16));
+  EXPECT_TRUE(pickle.WriteUInt32(testuint32));
+  EXPECT_TRUE(pickle.WriteInt64(testint64));
+  EXPECT_TRUE(pickle.WriteUInt64(testuint64));
+  EXPECT_TRUE(pickle.WriteSizeT(testsizet));
+  EXPECT_TRUE(pickle.WriteFloat(testfloat));
+  EXPECT_TRUE(pickle.WriteDouble(testdouble));
+  EXPECT_TRUE(pickle.WriteString(teststring));
+  EXPECT_TRUE(pickle.WriteString16(teststring16));
+  EXPECT_TRUE(pickle.WriteString(testrawstring));
+  EXPECT_TRUE(pickle.WriteString16(testrawstring16));
+  EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
+  VerifyResult(pickle);
+
+  // test copy constructor
+  Pickle pickle2(pickle);
+  VerifyResult(pickle2);
+
+  // test operator=
+  Pickle pickle3;
+  pickle3 = pickle;
+  VerifyResult(pickle3);
+}
+
+// Tests that reading/writing a size_t works correctly when the source process
+// is 64-bit.  We rely on having both 32- and 64-bit trybots to validate both
+// arms of the conditional in this test.
+TEST(PickleTest, SizeTFrom64Bit) {
+  Pickle pickle;
+  // Under the hood size_t is always written as a 64-bit value, so simulate a
+  // 64-bit size_t even on 32-bit architectures by explicitly writing a uint64.
+  EXPECT_TRUE(pickle.WriteUInt64(testuint64));
+
+  PickleIterator iter(pickle);
+  size_t outsizet;
+  if (sizeof(size_t) < sizeof(uint64)) {
+    // ReadSizeT() should return false when the original written value can't be
+    // represented as a size_t.
+    EXPECT_FALSE(iter.ReadSizeT(&outsizet));
+  } else {
+    EXPECT_TRUE(iter.ReadSizeT(&outsizet));
+    EXPECT_EQ(testuint64, outsizet);
+  }
+}
+
+// Tests that we can handle really small buffers.
+TEST(PickleTest, SmallBuffer) {
+  scoped_ptr<char[]> buffer(new char[1]);
+
+  // We should not touch the buffer.
+  Pickle pickle(buffer.get(), 1);
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(iter.ReadInt(&data));
+}
+
+// Tests that we can handle improper headers.
+TEST(PickleTest, BigSize) {
+  int buffer[] = { 0x56035200, 25, 40, 50 };
+
+  Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer));
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(iter.ReadInt(&data));
+}
+
+TEST(PickleTest, UnalignedSize) {
+  int buffer[] = { 10, 25, 40, 50 };
+
+  Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer));
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(iter.ReadInt(&data));
+}
+
+TEST(PickleTest, ZeroLenStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteString(std::string()));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_TRUE(iter.ReadString(&outstr));
+  EXPECT_EQ("", outstr);
+}
+
+TEST(PickleTest, ZeroLenStr16) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteString16(base::string16()));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_TRUE(iter.ReadString(&outstr));
+  EXPECT_EQ("", outstr);
+}
+
+TEST(PickleTest, BadLenStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(-2));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_FALSE(iter.ReadString(&outstr));
+}
+
+TEST(PickleTest, BadLenStr16) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(-1));
+
+  PickleIterator iter(pickle);
+  base::string16 outstr;
+  EXPECT_FALSE(iter.ReadString16(&outstr));
+}
+
+TEST(PickleTest, FindNext) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(1));
+  EXPECT_TRUE(pickle.WriteString("Domo"));
+
+  const char* start = reinterpret_cast<const char*>(pickle.data());
+  const char* end = start + pickle.size();
+
+  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end));
+  EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1));
+  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
+}
+
+TEST(PickleTest, FindNextWithIncompleteHeader) {
+  size_t header_size = sizeof(Pickle::Header);
+  scoped_ptr<char[]> buffer(new char[header_size - 1]);
+  memset(buffer.get(), 0x1, header_size - 1);
+
+  const char* start = buffer.get();
+  const char* end = start + header_size - 1;
+
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end));
+}
+
+#if defined(COMPILER_MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4146)
+#endif
+TEST(PickleTest, FindNextOverflow) {
+  size_t header_size = sizeof(Pickle::Header);
+  size_t header_size2 = 2 * header_size;
+  size_t payload_received = 100;
+  scoped_ptr<char[]> buffer(new char[header_size2 + payload_received]);
+  const char* start = buffer.get();
+  Pickle::Header* header = reinterpret_cast<Pickle::Header*>(buffer.get());
+  const char* end = start + header_size2 + payload_received;
+  // It is impossible to construct an overflow test otherwise.
+  if (sizeof(size_t) > sizeof(header->payload_size) ||
+      sizeof(uintptr_t) > sizeof(header->payload_size))
+    return;
+
+  header->payload_size = -(reinterpret_cast<uintptr_t>(start) + header_size2);
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
+
+  header->payload_size = -header_size2;
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
+
+  header->payload_size = 0;
+  end = start + header_size;
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
+}
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
+TEST(PickleTest, GetReadPointerAndAdvance) {
+  Pickle pickle;
+
+  PickleIterator iter(pickle);
+  EXPECT_FALSE(iter.GetReadPointerAndAdvance(1));
+
+  EXPECT_TRUE(pickle.WriteInt(1));
+  EXPECT_TRUE(pickle.WriteInt(2));
+  int bytes = sizeof(int) * 2;
+
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0));
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1));
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN));
+}
+
+TEST(PickleTest, Resize) {
+  size_t unit = Pickle::kPayloadUnit;
+  scoped_ptr<char[]> data(new char[unit]);
+  char* data_ptr = data.get();
+  for (size_t i = 0; i < unit; i++)
+    data_ptr[i] = 'G';
+
+  // construct a message that will be exactly the size of one payload unit,
+  // note that any data will have a 4-byte header indicating the size
+  const size_t payload_size_after_header = unit - sizeof(uint32);
+  Pickle pickle;
+  pickle.WriteData(data_ptr,
+      static_cast<int>(payload_size_after_header - sizeof(uint32)));
+  size_t cur_payload = payload_size_after_header;
+
+  // note: we assume 'unit' is a power of 2
+  EXPECT_EQ(unit, pickle.capacity_after_header());
+  EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
+
+  // fill out a full page (noting data header)
+  pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
+  cur_payload += unit;
+  EXPECT_EQ(unit * 2, pickle.capacity_after_header());
+  EXPECT_EQ(cur_payload, pickle.payload_size());
+
+  // one more byte should double the capacity
+  pickle.WriteData(data_ptr, 1);
+  cur_payload += 8;
+  EXPECT_EQ(unit * 4, pickle.capacity_after_header());
+  EXPECT_EQ(cur_payload, pickle.payload_size());
+}
+
+namespace {
+
+struct CustomHeader : Pickle::Header {
+  int blah;
+};
+
+}  // namespace
+
+TEST(PickleTest, HeaderPadding) {
+  const uint32 kMagic = 0x12345678;
+
+  Pickle pickle(sizeof(CustomHeader));
+  pickle.WriteInt(kMagic);
+
+  // this should not overwrite the 'int' payload
+  pickle.headerT<CustomHeader>()->blah = 10;
+
+  PickleIterator iter(pickle);
+  int result;
+  ASSERT_TRUE(iter.ReadInt(&result));
+
+  EXPECT_EQ(static_cast<uint32>(result), kMagic);
+}
+
+TEST(PickleTest, EqualsOperator) {
+  Pickle source;
+  source.WriteInt(1);
+
+  Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()),
+                                 source.size());
+  Pickle copy;
+  copy = copy_refs_source_buffer;
+  ASSERT_EQ(source.size(), copy.size());
+}
+
+TEST(PickleTest, EvilLengths) {
+  Pickle source;
+  std::string str(100000, 'A');
+  EXPECT_TRUE(source.WriteData(str.c_str(), 100000));
+  // ReadString16 used to have its read buffer length calculation wrong leading
+  // to out-of-bounds reading.
+  PickleIterator iter(source);
+  string16 str16;
+  EXPECT_FALSE(iter.ReadString16(&str16));
+
+  // And check we didn't break ReadString16.
+  str16 = (wchar_t) 'A';
+  Pickle str16_pickle;
+  EXPECT_TRUE(str16_pickle.WriteString16(str16));
+  iter = PickleIterator(str16_pickle);
+  EXPECT_TRUE(iter.ReadString16(&str16));
+  EXPECT_EQ(1U, str16.length());
+
+  // Check we don't fail in a length check with invalid String16 size.
+  // (1<<31) * sizeof(char16) == 0, so this is particularly evil.
+  Pickle bad_len;
+  EXPECT_TRUE(bad_len.WriteInt(1 << 31));
+  iter = PickleIterator(bad_len);
+  EXPECT_FALSE(iter.ReadString16(&str16));
+}
+
+// Check we can write zero bytes of data and 'data' can be NULL.
+TEST(PickleTest, ZeroLength) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteData(NULL, 0));
+
+  PickleIterator iter(pickle);
+  const char* outdata;
+  int outdatalen;
+  EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen));
+  EXPECT_EQ(0, outdatalen);
+  // We can't assert that outdata is NULL.
+}
+
+// Check that ReadBytes works properly with an iterator initialized to NULL.
+TEST(PickleTest, ReadBytes) {
+  Pickle pickle;
+  int data = 0x7abcd;
+  EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data)));
+
+  PickleIterator iter(pickle);
+  const char* outdata_char = NULL;
+  EXPECT_TRUE(iter.ReadBytes(&outdata_char, sizeof(data)));
+
+  int outdata;
+  memcpy(&outdata, outdata_char, sizeof(outdata));
+  EXPECT_EQ(data, outdata);
+}
diff --git a/base/port.h b/base/port.h
new file mode 100644
index 0000000..56c4d4e
--- /dev/null
+++ b/base/port.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PORT_H_
+#define BASE_PORT_H_
+
+#include <stdarg.h>
+#include "build/build_config.h"
+
+// DEPRECATED: Use ...LL and ...ULL suffixes.
+// TODO(viettrungluu): Delete these. These are only here until |GG_(U)INT64_C|
+// are deleted (some other header files (re)define |GG_(U)INT64_C|, so our
+// definitions of them must exactly match theirs).
+#ifdef COMPILER_MSVC
+#define GG_LONGLONG(x) x##I64
+#define GG_ULONGLONG(x) x##UI64
+#else
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#endif
+
+// DEPRECATED: In Chromium, we force-define __STDC_CONSTANT_MACROS, so you can
+// just use the regular (U)INTn_C macros from <stdint.h>.
+// TODO(viettrungluu): Remove the remaining GG_(U)INTn_C macros.
+#define GG_INT64_C(x)   GG_LONGLONG(x)
+#define GG_UINT64_C(x)  GG_ULONGLONG(x)
+
+// Define an OS-neutral wrapper for shared library entry points
+#if defined(OS_WIN)
+#define API_CALL __stdcall
+#else
+#define API_CALL
+#endif
+
+#endif  // BASE_PORT_H_
diff --git a/base/posix/eintr_wrapper.h b/base/posix/eintr_wrapper.h
new file mode 100644
index 0000000..5a5dc75
--- /dev/null
+++ b/base/posix/eintr_wrapper.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+// To prevent long-lasting loops (which would likely be a bug, such as a signal
+// that should be masked) to go unnoticed, there is a limit after which the
+// caller will nonetheless see an EINTR in Debug builds.
+//
+// On Windows, this wrapper macro does nothing.
+//
+// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return
+// value of close is significant. See http://crbug.com/269623.
+
+#ifndef BASE_POSIX_EINTR_WRAPPER_H_
+#define BASE_POSIX_EINTR_WRAPPER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+
+#include <errno.h>
+
+#if defined(NDEBUG)
+
+#define HANDLE_EINTR(x) ({ \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+  } while (eintr_wrapper_result == -1 && errno == EINTR); \
+  eintr_wrapper_result; \
+})
+
+#else
+
+#define HANDLE_EINTR(x) ({ \
+  int eintr_wrapper_counter = 0; \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+  } while (eintr_wrapper_result == -1 && errno == EINTR && \
+           eintr_wrapper_counter++ < 100); \
+  eintr_wrapper_result; \
+})
+
+#endif  // NDEBUG
+
+#define IGNORE_EINTR(x) ({ \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+    if (eintr_wrapper_result == -1 && errno == EINTR) { \
+      eintr_wrapper_result = 0; \
+    } \
+  } while (0); \
+  eintr_wrapper_result; \
+})
+
+#else
+
+#define HANDLE_EINTR(x) (x)
+#define IGNORE_EINTR(x) (x)
+
+#endif  // OS_POSIX
+
+#endif  // BASE_POSIX_EINTR_WRAPPER_H_
diff --git a/base/posix/file_descriptor_shuffle.cc b/base/posix/file_descriptor_shuffle.cc
new file mode 100644
index 0000000..d2fd39a
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/posix/file_descriptor_shuffle.h"
+
+#include <unistd.h>
+#include <stddef.h>
+#include <ostream>
+
+#include "base/posix/eintr_wrapper.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* m, InjectionDelegate* delegate) {
+  static const size_t kMaxExtraFDs = 16;
+  int extra_fds[kMaxExtraFDs];
+  unsigned next_extra_fd = 0;
+
+  // DANGER: this function must not allocate or lock.
+  // Cannot use STL iterators here, since debug iterators use locks.
+
+  for (size_t i_index = 0; i_index < m->size(); ++i_index) {
+    InjectiveMultimap::value_type* i = &(*m)[i_index];
+    int temp_fd = -1;
+
+    // We DCHECK the injectiveness of the mapping.
+    for (size_t j_index = i_index + 1; j_index < m->size(); ++j_index) {
+      InjectiveMultimap::value_type* j = &(*m)[j_index];
+      DCHECK(i->dest != j->dest) << "Both fd " << i->source
+          << " and " << j->source << " map to " << i->dest;
+    }
+
+    const bool is_identity = i->source == i->dest;
+
+    for (size_t j_index = i_index + 1; j_index < m->size(); ++j_index) {
+      InjectiveMultimap::value_type* j = &(*m)[j_index];
+      if (!is_identity && i->dest == j->source) {
+        if (temp_fd == -1) {
+          if (!delegate->Duplicate(&temp_fd, i->dest))
+            return false;
+          if (next_extra_fd < kMaxExtraFDs) {
+            extra_fds[next_extra_fd++] = temp_fd;
+          } else {
+            RAW_LOG(ERROR, "PerformInjectiveMultimapDestructive overflowed "
+                           "extra_fds. Leaking file descriptors!");
+          }
+        }
+
+        j->source = temp_fd;
+        j->close = false;
+      }
+
+      if (i->close && i->source == j->dest)
+        i->close = false;
+
+      if (i->close && i->source == j->source) {
+        i->close = false;
+        j->close = true;
+      }
+    }
+
+    if (!is_identity) {
+      if (!delegate->Move(i->source, i->dest))
+        return false;
+    }
+
+    if (!is_identity && i->close)
+      delegate->Close(i->source);
+  }
+
+  for (unsigned i = 0; i < next_extra_fd; i++)
+    delegate->Close(extra_fds[i]);
+
+  return true;
+}
+
+bool PerformInjectiveMultimap(const InjectiveMultimap& m_in,
+                              InjectionDelegate* delegate) {
+  InjectiveMultimap m(m_in);
+  return PerformInjectiveMultimapDestructive(&m, delegate);
+}
+
+bool FileDescriptorTableInjection::Duplicate(int* result, int fd) {
+  *result = HANDLE_EINTR(dup(fd));
+  return *result >= 0;
+}
+
+bool FileDescriptorTableInjection::Move(int src, int dest) {
+  return HANDLE_EINTR(dup2(src, dest)) != -1;
+}
+
+void FileDescriptorTableInjection::Close(int fd) {
+  int ret = IGNORE_EINTR(close(fd));
+  DPCHECK(ret == 0);
+}
+
+}  // namespace base
diff --git a/base/posix/file_descriptor_shuffle.h b/base/posix/file_descriptor_shuffle.h
new file mode 100644
index 0000000..78e3a7d
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+#define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+
+// This code exists to shuffle file descriptors, which is commonly needed when
+// forking subprocesses. The naive approach (just call dup2 to set up the
+// desired descriptors) is very simple, but wrong: it won't handle edge cases
+// (like mapping 0 -> 1, 1 -> 0) correctly.
+//
+// In order to unittest this code, it's broken into the abstract action (an
+// injective multimap) and the concrete code for dealing with file descriptors.
+// Users should use the code like this:
+//   base::InjectiveMultimap file_descriptor_map;
+//   file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true));
+//   file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true));
+//   file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true));
+//   base::ShuffleFileDescriptors(file_descriptor_map);
+//
+// and trust the the Right Thing will get done.
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// A Delegate which performs the actions required to perform an injective
+// multimapping in place.
+class InjectionDelegate {
+ public:
+  // Duplicate |fd|, an element of the domain, and write a fresh element of the
+  // domain into |result|. Returns true iff successful.
+  virtual bool Duplicate(int* result, int fd) = 0;
+  // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff
+  // successful.
+  virtual bool Move(int src, int dest) = 0;
+  // Delete an element of the domain.
+  virtual void Close(int fd) = 0;
+
+ protected:
+  virtual ~InjectionDelegate() {}
+};
+
+// An implementation of the InjectionDelegate interface using the file
+// descriptor table of the current process as the domain.
+class BASE_EXPORT FileDescriptorTableInjection : public InjectionDelegate {
+  bool Duplicate(int* result, int fd) override;
+  bool Move(int src, int dest) override;
+  void Close(int fd) override;
+};
+
+// A single arc of the directed graph which describes an injective multimapping.
+struct InjectionArc {
+  InjectionArc(int in_source, int in_dest, bool in_close)
+      : source(in_source),
+        dest(in_dest),
+        close(in_close) {
+  }
+
+  int source;
+  int dest;
+  bool close;  // if true, delete the source element after performing the
+               // mapping.
+};
+
+typedef std::vector<InjectionArc> InjectiveMultimap;
+
+BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map,
+                                          InjectionDelegate* delegate);
+
+BASE_EXPORT bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* map,
+    InjectionDelegate* delegate);
+
+// This function will not call malloc but will mutate |map|
+static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) {
+  FileDescriptorTableInjection delegate;
+  return PerformInjectiveMultimapDestructive(map, &delegate);
+}
+
+}  // namespace base
+
+#endif  // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
diff --git a/base/posix/file_descriptor_shuffle_unittest.cc b/base/posix/file_descriptor_shuffle_unittest.cc
new file mode 100644
index 0000000..3dfbf7e
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle_unittest.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/posix/file_descriptor_shuffle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// 'Duplicated' file descriptors start at this number
+const int kDuplicateBase = 1000;
+
+}  // namespace
+
+namespace base {
+
+struct Action {
+  enum Type {
+    CLOSE,
+    MOVE,
+    DUPLICATE,
+  };
+
+  Action(Type in_type, int in_fd1, int in_fd2 = -1)
+      : type(in_type),
+        fd1(in_fd1),
+        fd2(in_fd2) {
+  }
+
+  bool operator==(const Action& other) const {
+    return other.type == type &&
+           other.fd1 == fd1 &&
+           other.fd2 == fd2;
+  }
+
+  Type type;
+  int fd1;
+  int fd2;
+};
+
+class InjectionTracer : public InjectionDelegate {
+ public:
+  InjectionTracer()
+      : next_duplicate_(kDuplicateBase) {
+  }
+
+  bool Duplicate(int* result, int fd) override {
+    *result = next_duplicate_++;
+    actions_.push_back(Action(Action::DUPLICATE, *result, fd));
+    return true;
+  }
+
+  bool Move(int src, int dest) override {
+    actions_.push_back(Action(Action::MOVE, src, dest));
+    return true;
+  }
+
+  void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); }
+
+  const std::vector<Action>& actions() const { return actions_; }
+
+ private:
+  int next_duplicate_;
+  std::vector<Action> actions_;
+};
+
+TEST(FileDescriptorShuffleTest, Empty) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, Noop) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, NoopAndClose) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, Simple1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(1u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+}
+
+TEST(FileDescriptorShuffleTest, Simple2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(2, 3, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
+}
+
+TEST(FileDescriptorShuffleTest, Simple3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, Simple4) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(10, 0, true));
+  map.push_back(InjectionArc(1, 1, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
+}
+
+TEST(FileDescriptorShuffleTest, Cycle) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(1, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(1, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(1, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(1, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, Fanout) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(0, 2, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(0, 2, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(0, 2, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(0, 2, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+class FailingDelegate : public InjectionDelegate {
+ public:
+  bool Duplicate(int* result, int fd) override { return false; }
+
+  bool Move(int src, int dest) override { return false; }
+
+  void Close(int fd) override {}
+};
+
+TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, NoopWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
+}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.cc b/base/posix/global_descriptors.cc
new file mode 100644
index 0000000..6c18783
--- /dev/null
+++ b/base/posix/global_descriptors.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/posix/global_descriptors.h"
+
+#include <vector>
+#include <utility>
+
+#include "base/logging.h"
+
+namespace base {
+
+GlobalDescriptors::Descriptor::Descriptor(Key key, int fd)
+    : key(key), fd(fd), region(base::MemoryMappedFile::Region::kWholeFile) {
+}
+
+GlobalDescriptors::Descriptor::Descriptor(Key key,
+                                          int fd,
+                                          base::MemoryMappedFile::Region region)
+    : key(key), fd(fd), region(region) {
+}
+
+// static
+GlobalDescriptors* GlobalDescriptors::GetInstance() {
+  typedef Singleton<base::GlobalDescriptors,
+                    LeakySingletonTraits<base::GlobalDescriptors> >
+      GlobalDescriptorsSingleton;
+  return GlobalDescriptorsSingleton::get();
+}
+
+int GlobalDescriptors::Get(Key key) const {
+  const int ret = MaybeGet(key);
+
+  if (ret == -1)
+    DLOG(FATAL) << "Unknown global descriptor: " << key;
+  return ret;
+}
+
+int GlobalDescriptors::MaybeGet(Key key) const {
+  for (Mapping::const_iterator
+       i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+    if (i->key == key)
+      return i->fd;
+  }
+
+  return -1;
+}
+
+void GlobalDescriptors::Set(Key key, int fd) {
+  Set(key, fd, base::MemoryMappedFile::Region::kWholeFile);
+}
+
+void GlobalDescriptors::Set(Key key,
+                            int fd,
+                            base::MemoryMappedFile::Region region) {
+  for (auto& i : descriptors_) {
+    if (i.key == key) {
+      i.fd = fd;
+      i.region = region;
+      return;
+    }
+  }
+
+  descriptors_.push_back(Descriptor(key, fd, region));
+}
+
+base::MemoryMappedFile::Region GlobalDescriptors::GetRegion(Key key) const {
+  for (const auto& i : descriptors_) {
+    if (i.key == key)
+      return i.region;
+  }
+  DLOG(FATAL) << "Unknown global descriptor: " << key;
+  return base::MemoryMappedFile::Region::kWholeFile;
+}
+
+void GlobalDescriptors::Reset(const Mapping& mapping) {
+  descriptors_ = mapping;
+}
+
+GlobalDescriptors::GlobalDescriptors() {}
+
+GlobalDescriptors::~GlobalDescriptors() {}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h
new file mode 100644
index 0000000..c774634
--- /dev/null
+++ b/base/posix/global_descriptors.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POSIX_GLOBAL_DESCRIPTORS_H_
+#define BASE_POSIX_GLOBAL_DESCRIPTORS_H_
+
+#include "build/build_config.h"
+
+#include <vector>
+#include <utility>
+
+#include <stdint.h>
+
+#include "base/files/memory_mapped_file.h"
+#include "base/memory/singleton.h"
+
+namespace base {
+
+// It's common practice to install file descriptors into well known slot
+// numbers before execing a child; stdin, stdout and stderr are ubiqutous
+// examples.
+//
+// However, when using a zygote model, this becomes troublesome. Since the
+// descriptors which need to be in these slots generally aren't known, any code
+// could open a resource and take one of the reserved descriptors. Simply
+// overwriting the slot isn't a viable solution.
+//
+// We could try to fill the reserved slots as soon as possible, but this is a
+// fragile solution since global constructors etc are able to open files.
+//
+// Instead, we retreat from the idea of installing descriptors in specific
+// slots and add a layer of indirection in the form of this singleton object.
+// It maps from an abstract key to a descriptor. If independent modules each
+// need to define keys, then values should be chosen randomly so as not to
+// collide.
+class BASE_EXPORT GlobalDescriptors {
+ public:
+  typedef uint32_t Key;
+  struct Descriptor {
+    Descriptor(Key key, int fd);
+    Descriptor(Key key, int fd, base::MemoryMappedFile::Region region);
+
+    // Globally unique key.
+    Key key;
+    // Actual FD.
+    int fd;
+    // Optional region, defaults to kWholeFile.
+    base::MemoryMappedFile::Region region;
+  };
+  typedef std::vector<Descriptor> Mapping;
+
+  // Often we want a canonical descriptor for a given Key. In this case, we add
+  // the following constant to the key value:
+#if !defined(OS_ANDROID)
+  static const int kBaseDescriptor = 3;  // 0, 1, 2 are already taken.
+#else
+  static const int kBaseDescriptor = 4;  // 3 used by __android_log_write().
+#endif
+
+  // Return the singleton instance of GlobalDescriptors.
+  static GlobalDescriptors* GetInstance();
+
+  // Get a descriptor given a key. It is a fatal error if the key is not known.
+  int Get(Key key) const;
+
+  // Get a descriptor given a key. Returns -1 on error.
+  int MaybeGet(Key key) const;
+
+  // Get a region given a key. It is a fatal error if the key is not known.
+  base::MemoryMappedFile::Region GetRegion(Key key) const;
+
+  // Set the descriptor for the given |key|. This sets the region associated
+  // with |key| to kWholeFile.
+  void Set(Key key, int fd);
+
+  // Set the descriptor and |region| for the given |key|.
+  void Set(Key key, int fd, base::MemoryMappedFile::Region region);
+
+  void Reset(const Mapping& mapping);
+
+ private:
+  friend struct DefaultSingletonTraits<GlobalDescriptors>;
+  GlobalDescriptors();
+  ~GlobalDescriptors();
+
+  Mapping descriptors_;
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_GLOBAL_DESCRIPTORS_H_
diff --git a/base/posix/unix_domain_socket_linux.cc b/base/posix/unix_domain_socket_linux.cc
new file mode 100644
index 0000000..16d8eaa
--- /dev/null
+++ b/base/posix/unix_domain_socket_linux.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/posix/unix_domain_socket_linux.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+
+#if !defined(OS_NACL_NONSFI)
+#include <sys/uio.h>
+#endif
+
+const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
+
+#if !defined(OS_NACL_NONSFI)
+// Creates a connected pair of UNIX-domain SOCK_SEQPACKET sockets, and passes
+// ownership of the newly allocated file descriptors to |one| and |two|.
+// Returns true on success.
+static bool CreateSocketPair(base::ScopedFD* one, base::ScopedFD* two) {
+  int raw_socks[2];
+  if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks) == -1)
+    return false;
+  one->reset(raw_socks[0]);
+  two->reset(raw_socks[1]);
+  return true;
+}
+
+// static
+bool UnixDomainSocket::EnableReceiveProcessId(int fd) {
+  const int enable = 1;
+  return setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)) == 0;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+// static
+bool UnixDomainSocket::SendMsg(int fd,
+                               const void* buf,
+                               size_t length,
+                               const std::vector<int>& fds) {
+  struct msghdr msg = {};
+  struct iovec iov = { const_cast<void*>(buf), length };
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  char* control_buffer = NULL;
+  if (fds.size()) {
+    const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
+    control_buffer = new char[control_len];
+
+    struct cmsghdr* cmsg;
+    msg.msg_control = control_buffer;
+    msg.msg_controllen = control_len;
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
+    memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
+    msg.msg_controllen = cmsg->cmsg_len;
+  }
+
+  // Avoid a SIGPIPE if the other end breaks the connection.
+  // Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't
+  // regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by
+  // POSIX.
+  const int flags = MSG_NOSIGNAL;
+  const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, flags));
+  const bool ret = static_cast<ssize_t>(length) == r;
+  delete[] control_buffer;
+  return ret;
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsg(int fd,
+                                  void* buf,
+                                  size_t length,
+                                  ScopedVector<base::ScopedFD>* fds) {
+  return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
+                                         void* buf,
+                                         size_t length,
+                                         ScopedVector<base::ScopedFD>* fds,
+                                         base::ProcessId* pid) {
+  return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
+                                           void* buf,
+                                           size_t length,
+                                           int flags,
+                                           ScopedVector<base::ScopedFD>* fds,
+                                           base::ProcessId* out_pid) {
+  fds->clear();
+
+  struct msghdr msg = {};
+  struct iovec iov = { buf, length };
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  const size_t kControlBufferSize =
+      CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)
+#if !defined(OS_NACL_NONSFI)
+      // The PNaCl toolchain for Non-SFI binary build does not support ucred.
+      + CMSG_SPACE(sizeof(struct ucred))
+#endif
+      ;
+  char control_buffer[kControlBufferSize];
+  msg.msg_control = control_buffer;
+  msg.msg_controllen = sizeof(control_buffer);
+
+  const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags));
+  if (r == -1)
+    return -1;
+
+  int* wire_fds = NULL;
+  unsigned wire_fds_len = 0;
+  base::ProcessId pid = -1;
+
+  if (msg.msg_controllen > 0) {
+    struct cmsghdr* cmsg;
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+      const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_RIGHTS) {
+        DCHECK_EQ(payload_len % sizeof(int), 0u);
+        DCHECK_EQ(wire_fds, static_cast<void*>(nullptr));
+        wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+        wire_fds_len = payload_len / sizeof(int);
+      }
+#if !defined(OS_NACL_NONSFI)
+      // The PNaCl toolchain for Non-SFI binary build does not support
+      // SCM_CREDENTIALS.
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_CREDENTIALS) {
+        DCHECK_EQ(payload_len, sizeof(struct ucred));
+        DCHECK_EQ(pid, -1);
+        pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid;
+      }
+#endif
+    }
+  }
+
+  if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
+    for (unsigned i = 0; i < wire_fds_len; ++i)
+      close(wire_fds[i]);
+    errno = EMSGSIZE;
+    return -1;
+  }
+
+  if (wire_fds) {
+    for (unsigned i = 0; i < wire_fds_len; ++i)
+      fds->push_back(new base::ScopedFD(wire_fds[i]));
+  }
+
+  if (out_pid) {
+    // |pid| will legitimately be -1 if we read EOF, so only DCHECK if we
+    // actually received a message.  Unfortunately, Linux allows sending zero
+    // length messages, which are indistinguishable from EOF, so this check
+    // has false negatives.
+    if (r > 0 || msg.msg_controllen > 0)
+      DCHECK_GE(pid, 0);
+
+    *out_pid = pid;
+  }
+
+  return r;
+}
+
+#if !defined(OS_NACL_NONSFI)
+// static
+ssize_t UnixDomainSocket::SendRecvMsg(int fd,
+                                      uint8_t* reply,
+                                      unsigned max_reply_len,
+                                      int* result_fd,
+                                      const Pickle& request) {
+  return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len,
+                                                0,  /* recvmsg_flags */
+                                                result_fd, request);
+}
+
+// static
+ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
+                                               uint8_t* reply,
+                                               unsigned max_reply_len,
+                                               int recvmsg_flags,
+                                               int* result_fd,
+                                               const Pickle& request) {
+  // This socketpair is only used for the IPC and is cleaned up before
+  // returning.
+  base::ScopedFD recv_sock, send_sock;
+  if (!CreateSocketPair(&recv_sock, &send_sock))
+    return -1;
+
+  {
+    std::vector<int> send_fds;
+    send_fds.push_back(send_sock.get());
+    if (!SendMsg(fd, request.data(), request.size(), send_fds))
+      return -1;
+  }
+
+  // Close the sending end of the socket right away so that if our peer closes
+  // it before sending a response (e.g., from exiting), RecvMsgWithFlags() will
+  // return EOF instead of hanging.
+  send_sock.reset();
+
+  ScopedVector<base::ScopedFD> recv_fds;
+  // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
+  // sender might get a SIGPIPE.
+  const ssize_t reply_len = RecvMsgWithFlags(
+      recv_sock.get(), reply, max_reply_len, recvmsg_flags, &recv_fds, NULL);
+  recv_sock.reset();
+  if (reply_len == -1)
+    return -1;
+
+  // If we received more file descriptors than caller expected, then we treat
+  // that as an error.
+  if (recv_fds.size() > (result_fd != NULL ? 1 : 0)) {
+    NOTREACHED();
+    return -1;
+  }
+
+  if (result_fd)
+    *result_fd = recv_fds.empty() ? -1 : recv_fds[0]->release();
+
+  return reply_len;
+}
+#endif  // !defined(OS_NACL_NONSFI)
diff --git a/base/posix/unix_domain_socket_linux.h b/base/posix/unix_domain_socket_linux.h
new file mode 100644
index 0000000..142cb14
--- /dev/null
+++ b/base/posix/unix_domain_socket_linux.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+#define BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_vector.h"
+#include "base/process/process_handle.h"
+
+class Pickle;
+
+class BASE_EXPORT UnixDomainSocket {
+ public:
+  // Maximum number of file descriptors that can be read by RecvMsg().
+  static const size_t kMaxFileDescriptors;
+
+#if !defined(OS_NACL_NONSFI)
+  // Use to enable receiving process IDs in RecvMsgWithPid.  Should be called on
+  // the receiving socket (i.e., the socket passed to RecvMsgWithPid). Returns
+  // true if successful.
+  static bool EnableReceiveProcessId(int fd);
+#endif  // !defined(OS_NACL_NONSFI)
+
+  // Use sendmsg to write the given msg and include a vector of file
+  // descriptors. Returns true if successful.
+  static bool SendMsg(int fd,
+                      const void* msg,
+                      size_t length,
+                      const std::vector<int>& fds);
+
+  // Use recvmsg to read a message and an array of file descriptors. Returns
+  // -1 on failure. Note: will read, at most, |kMaxFileDescriptors| descriptors.
+  static ssize_t RecvMsg(int fd,
+                         void* msg,
+                         size_t length,
+                         ScopedVector<base::ScopedFD>* fds);
+
+  // Same as RecvMsg above, but also returns the sender's process ID (as seen
+  // from the caller's namespace).  However, before using this function to
+  // receive process IDs, EnableReceiveProcessId() should be called on the
+  // receiving socket.
+  static ssize_t RecvMsgWithPid(int fd,
+                                void* msg,
+                                size_t length,
+                                ScopedVector<base::ScopedFD>* fds,
+                                base::ProcessId* pid);
+
+#if !defined(OS_NACL_NONSFI)
+  // Perform a sendmsg/recvmsg pair.
+  //   1. This process creates a UNIX SEQPACKET socketpair. Using
+  //      connection-oriented sockets (SEQPACKET or STREAM) is critical here,
+  //      because if one of the ends closes the other one must be notified.
+  //   2. This process writes a request to |fd| with an SCM_RIGHTS control
+  //      message containing on end of the fresh socket pair.
+  //   3. This process blocks reading from the other end of the fresh
+  //      socketpair.
+  //   4. The target process receives the request, processes it and writes the
+  //      reply to the end of the socketpair contained in the request.
+  //   5. This process wakes up and continues.
+  //
+  //   fd: descriptor to send the request on
+  //   reply: buffer for the reply
+  //   reply_len: size of |reply|
+  //   result_fd: (may be NULL) the file descriptor returned in the reply
+  //              (if any)
+  //   request: the bytes to send in the request
+  static ssize_t SendRecvMsg(int fd,
+                             uint8_t* reply,
+                             unsigned reply_len,
+                             int* result_fd,
+                             const Pickle& request);
+
+  // Similar to SendRecvMsg(), but |recvmsg_flags| allows to control the flags
+  // of the recvmsg(2) call.
+  static ssize_t SendRecvMsgWithFlags(int fd,
+                                      uint8_t* reply,
+                                      unsigned reply_len,
+                                      int recvmsg_flags,
+                                      int* result_fd,
+                                      const Pickle& request);
+#endif  // !defined(OS_NACL_NONSFI)
+ private:
+  // Similar to RecvMsg, but allows to specify |flags| for recvmsg(2).
+  static ssize_t RecvMsgWithFlags(int fd,
+                                  void* msg,
+                                  size_t length,
+                                  int flags,
+                                  ScopedVector<base::ScopedFD>* fds,
+                                  base::ProcessId* pid);
+};
+
+#endif  // BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
new file mode 100644
index 0000000..c05141c
--- /dev/null
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/location.h"
+#include "base/memory/scoped_vector.h"
+#include "base/pickle.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
+  Thread message_thread("UnixDomainSocketTest");
+  ASSERT_TRUE(message_thread.Start());
+
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD scoped_fd0(fds[0]);
+  ScopedFD scoped_fd1(fds[1]);
+
+  // Have the thread send a synchronous message via the socket.
+  Pickle request;
+  message_thread.task_runner()->PostTask(
+      FROM_HERE,
+      Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1],
+           static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
+
+  // Receive the message.
+  ScopedVector<base::ScopedFD> message_fds;
+  uint8_t buffer[16];
+  ASSERT_EQ(static_cast<int>(request.size()),
+            UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer),
+                                      &message_fds));
+  ASSERT_EQ(1U, message_fds.size());
+
+  // Close the reply FD.
+  message_fds.clear();
+
+  // Check that the thread didn't get blocked.
+  WaitableEvent event(false, false);
+  message_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
+  ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000)));
+}
+
+TEST(UnixDomainSocketTest, SendRecvMsgAvoidsSIGPIPE) {
+  // Make sure SIGPIPE isn't being ignored.
+  struct sigaction act = {}, oldact;
+  act.sa_handler = SIG_DFL;
+  ASSERT_EQ(0, sigaction(SIGPIPE, &act, &oldact));
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD scoped_fd1(fds[1]);
+  ASSERT_EQ(0, IGNORE_EINTR(close(fds[0])));
+
+  // Have the thread send a synchronous message via the socket. Unless the
+  // message is sent with MSG_NOSIGNAL, this shall result in SIGPIPE.
+  Pickle request;
+  ASSERT_EQ(-1,
+      UnixDomainSocket::SendRecvMsg(fds[1], static_cast<uint8_t*>(NULL),
+                                    0U, static_cast<int*>(NULL), request));
+  ASSERT_EQ(EPIPE, errno);
+  // Restore the SIGPIPE handler.
+  ASSERT_EQ(0, sigaction(SIGPIPE, &oldact, NULL));
+}
+
+// Simple sanity check within a single process that receiving PIDs works.
+TEST(UnixDomainSocketTest, RecvPid) {
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD recv_sock(fds[0]);
+  base::ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  static const char kHello[] = "hello";
+  ASSERT_TRUE(UnixDomainSocket::SendMsg(
+      send_sock.get(), kHello, sizeof(kHello), std::vector<int>()));
+
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  base::ProcessId sender_pid;
+  ScopedVector<base::ScopedFD> fd_vec;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
+  ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
+  ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  ASSERT_EQ(0U, fd_vec.size());
+
+  ASSERT_EQ(getpid(), sender_pid);
+}
+
+// Same as above, but send the max number of file descriptors too.
+TEST(UnixDomainSocketTest, RecvPidWithMaxDescriptors) {
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD recv_sock(fds[0]);
+  base::ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  static const char kHello[] = "hello";
+  std::vector<int> send_fds(UnixDomainSocket::kMaxFileDescriptors,
+                            send_sock.get());
+  ASSERT_TRUE(UnixDomainSocket::SendMsg(
+      send_sock.get(), kHello, sizeof(kHello), send_fds));
+
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  base::ProcessId sender_pid;
+  ScopedVector<base::ScopedFD> recv_fds;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
+  ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
+  ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  ASSERT_EQ(UnixDomainSocket::kMaxFileDescriptors, recv_fds.size());
+
+  ASSERT_EQ(getpid(), sender_pid);
+}
+
+// Check that RecvMsgWithPid doesn't DCHECK fail when reading EOF from a
+// disconnected socket.
+TEST(UnixDomianSocketTest, RecvPidDisconnectedSocket) {
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD recv_sock(fds[0]);
+  base::ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  send_sock.reset();
+
+  char ch;
+  base::ProcessId sender_pid;
+  ScopedVector<base::ScopedFD> recv_fds;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
+  ASSERT_EQ(0, nread);
+  ASSERT_EQ(-1, sender_pid);
+  ASSERT_EQ(0U, recv_fds.size());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc
new file mode 100644
index 0000000..98c9c68
--- /dev/null
+++ b/base/power_monitor/power_monitor.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+static PowerMonitor* g_power_monitor = NULL;
+
+PowerMonitor::PowerMonitor(scoped_ptr<PowerMonitorSource> source)
+    : observers_(new ObserverListThreadSafe<PowerObserver>()),
+      source_(source.Pass()) {
+  DCHECK(!g_power_monitor);
+  g_power_monitor = this;
+}
+
+PowerMonitor::~PowerMonitor() {
+  DCHECK_EQ(this, g_power_monitor);
+  g_power_monitor = NULL;
+}
+
+// static
+PowerMonitor* PowerMonitor::Get() {
+  return g_power_monitor;
+}
+
+void PowerMonitor::AddObserver(PowerObserver* obs) {
+  observers_->AddObserver(obs);
+}
+
+void PowerMonitor::RemoveObserver(PowerObserver* obs) {
+  observers_->RemoveObserver(obs);
+}
+
+PowerMonitorSource* PowerMonitor::Source() {
+  return source_.get();
+}
+
+bool PowerMonitor::IsOnBatteryPower() {
+  return source_->IsOnBatteryPower();
+}
+
+void PowerMonitor::NotifyPowerStateChange(bool battery_in_use) {
+  DVLOG(1) << "PowerStateChange: " << (battery_in_use ? "On" : "Off")
+           << " battery";
+  observers_->Notify(FROM_HERE, &PowerObserver::OnPowerStateChange,
+                     battery_in_use);
+}
+
+void PowerMonitor::NotifySuspend() {
+  DVLOG(1) << "Power Suspending";
+  observers_->Notify(FROM_HERE, &PowerObserver::OnSuspend);
+}
+
+void PowerMonitor::NotifyResume() {
+  DVLOG(1) << "Power Resuming";
+  observers_->Notify(FROM_HERE, &PowerObserver::OnResume);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor.h b/base/power_monitor/power_monitor.h
new file mode 100644
index 0000000..4acb3bf
--- /dev/null
+++ b/base/power_monitor/power_monitor.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/power_monitor/power_observer.h"
+
+namespace base {
+
+class PowerMonitorSource;
+
+// A class used to monitor the power state change and notify the observers about
+// the change event.
+class BASE_EXPORT PowerMonitor {
+ public:
+  // Takes ownership of |source|.
+  explicit PowerMonitor(scoped_ptr<PowerMonitorSource> source);
+  ~PowerMonitor();
+
+  // Get the process-wide PowerMonitor (if not present, returns NULL).
+  static PowerMonitor* Get();
+
+  // Add and remove an observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void AddObserver(PowerObserver* observer);
+  void RemoveObserver(PowerObserver* observer);
+
+  // Is the computer currently on battery power.
+  bool IsOnBatteryPower();
+
+ private:
+  friend class PowerMonitorSource;
+
+  PowerMonitorSource* Source();
+
+  void NotifyPowerStateChange(bool battery_in_use);
+  void NotifySuspend();
+  void NotifyResume();
+
+  scoped_refptr<ObserverListThreadSafe<PowerObserver> > observers_;
+  scoped_ptr<PowerMonitorSource> source_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_H_
diff --git a/base/power_monitor/power_monitor_device_source.cc b/base/power_monitor/power_monitor_device_source.cc
new file mode 100644
index 0000000..0a39975
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source.cc
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+#include "base/time/time.h"
+
+namespace base {
+
+#if defined(ENABLE_BATTERY_MONITORING)
+// The amount of time (in ms) to wait before running the initial
+// battery check.
+static int kDelayedBatteryCheckMs = 10 * 1000;
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+
+PowerMonitorDeviceSource::PowerMonitorDeviceSource() {
+  DCHECK(MessageLoop::current());
+#if defined(ENABLE_BATTERY_MONITORING)
+  delayed_battery_check_.Start(FROM_HERE,
+      base::TimeDelta::FromMilliseconds(kDelayedBatteryCheckMs), this,
+      &PowerMonitorDeviceSource::BatteryCheck);
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+#if defined(OS_MACOSX)
+  PlatformInit();
+#endif
+}
+
+PowerMonitorDeviceSource::~PowerMonitorDeviceSource() {
+#if defined(OS_MACOSX)
+  PlatformDestroy();
+#endif
+}
+
+void PowerMonitorDeviceSource::BatteryCheck() {
+  ProcessPowerEvent(PowerMonitorSource::POWER_STATE_EVENT);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h
new file mode 100644
index 0000000..29f17c2
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source.h
@@ -0,0 +1,117 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/power_monitor/power_monitor_source.h"
+#include "base/power_monitor/power_observer.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+// Windows HiRes timers drain the battery faster so we need to know the battery
+// status.  This isn't true for other platforms.
+#define ENABLE_BATTERY_MONITORING 1
+#else
+#undef ENABLE_BATTERY_MONITORING
+#endif  // !OS_WIN
+
+#if defined(ENABLE_BATTERY_MONITORING)
+#include "base/timer/timer.h"
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+
+#if defined(OS_IOS)
+#include <objc/runtime.h>
+#endif  // OS_IOS
+
+namespace base {
+
+// A class used to monitor the power state change and notify the observers about
+// the change event.
+class BASE_EXPORT PowerMonitorDeviceSource : public PowerMonitorSource {
+ public:
+  PowerMonitorDeviceSource();
+  ~PowerMonitorDeviceSource() override;
+
+#if defined(OS_MACOSX)
+  // Allocate system resources needed by the PowerMonitor class.
+  //
+  // This function must be called before instantiating an instance of the class
+  // and before the Sandbox is initialized.
+#if !defined(OS_IOS)
+  static void AllocateSystemIOPorts();
+#else
+  static void AllocateSystemIOPorts() {}
+#endif  // OS_IOS
+#endif  // OS_MACOSX
+
+#if defined(OS_CHROMEOS)
+  // On Chrome OS, Chrome receives power-related events from powerd, the system
+  // power daemon, via D-Bus signals received on the UI thread. base can't
+  // directly depend on that code, so this class instead exposes static methods
+  // so that events can be passed in.
+  static void SetPowerSource(bool on_battery);
+  static void HandleSystemSuspending();
+  static void HandleSystemResumed();
+#endif
+
+ private:
+#if defined(OS_WIN)
+  // Represents a message-only window for power message handling on Windows.
+  // Only allow PowerMonitor to create it.
+  class PowerMessageWindow {
+   public:
+    PowerMessageWindow();
+    ~PowerMessageWindow();
+
+   private:
+    static LRESULT CALLBACK WndProcThunk(HWND hwnd,
+                                         UINT message,
+                                         WPARAM wparam,
+                                         LPARAM lparam);
+    // Instance of the module containing the window procedure.
+    HMODULE instance_;
+    // A hidden message-only window.
+    HWND message_hwnd_;
+  };
+#endif  // OS_WIN
+
+#if defined(OS_MACOSX)
+  void PlatformInit();
+  void PlatformDestroy();
+#endif
+
+  // Platform-specific method to check whether the system is currently
+  // running on battery power.  Returns true if running on batteries,
+  // false otherwise.
+  bool IsOnBatteryPowerImpl() override;
+
+  // Checks the battery status and notifies observers if the battery
+  // status has changed.
+  void BatteryCheck();
+
+#if defined(OS_IOS)
+  // Holds pointers to system event notification observers.
+  std::vector<id> notification_observers_;
+#endif
+
+#if defined(ENABLE_BATTERY_MONITORING)
+  base::OneShotTimer<PowerMonitorDeviceSource> delayed_battery_check_;
+#endif
+
+#if defined(OS_WIN)
+  PowerMessageWindow power_message_window_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitorDeviceSource);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
diff --git a/base/power_monitor/power_monitor_device_source_android.cc b/base/power_monitor/power_monitor_device_source_android.cc
new file mode 100644
index 0000000..4d9eb52
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_android.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source_android.h"
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/power_monitor/power_monitor_source.h"
+#include "jni/PowerMonitor_jni.h"
+
+namespace base {
+
+// A helper function which is a friend of PowerMonitorSource.
+void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
+  PowerMonitorSource::ProcessPowerEvent(event);
+}
+
+namespace android {
+
+// Native implementation of PowerMonitor.java.
+void OnBatteryChargingChanged(JNIEnv* env, jclass clazz) {
+  ProcessPowerEventHelper(PowerMonitorSource::POWER_STATE_EVENT);
+}
+
+void OnMainActivityResumed(JNIEnv* env, jclass clazz) {
+  ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT);
+}
+
+void OnMainActivitySuspended(JNIEnv* env, jclass clazz) {
+  ProcessPowerEventHelper(PowerMonitorSource::SUSPEND_EVENT);
+}
+
+}  // namespace android
+
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return base::android::Java_PowerMonitor_isBatteryPower(env);
+}
+
+bool RegisterPowerMonitor(JNIEnv* env) {
+  return base::android::RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_android.h b/base/power_monitor/power_monitor_device_source_android.h
new file mode 100644
index 0000000..024f95a
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_android.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+
+// Registers the JNI bindings for PowerMonitorDeviceSource.
+bool RegisterPowerMonitor(JNIEnv* env);
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_
diff --git a/base/power_monitor/power_monitor_device_source_chromeos.cc b/base/power_monitor/power_monitor_device_source_chromeos.cc
new file mode 100644
index 0000000..c3466ee
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_chromeos.cc
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+namespace {
+
+// The most-recently-seen power source.
+bool g_on_battery = false;
+
+}  // namespace
+
+// static
+void PowerMonitorDeviceSource::SetPowerSource(bool on_battery) {
+  if (on_battery != g_on_battery) {
+    g_on_battery = on_battery;
+    ProcessPowerEvent(POWER_STATE_EVENT);
+  }
+}
+
+// static
+void PowerMonitorDeviceSource::HandleSystemSuspending() {
+  ProcessPowerEvent(SUSPEND_EVENT);
+}
+
+// static
+void PowerMonitorDeviceSource::HandleSystemResumed() {
+  ProcessPowerEvent(RESUME_EVENT);
+}
+
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  return g_on_battery;
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_ios.mm b/base/power_monitor/power_monitor_device_source_ios.mm
new file mode 100644
index 0000000..dc12f1c
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_ios.mm
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+#import <UIKit/UIKit.h>
+
+namespace base {
+
+void PowerMonitorDeviceSource::PlatformInit() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  id foreground =
+      [nc addObserverForName:UIApplicationWillEnterForegroundNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      ProcessPowerEvent(RESUME_EVENT);
+                  }];
+  id background =
+      [nc addObserverForName:UIApplicationDidEnterBackgroundNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      ProcessPowerEvent(SUSPEND_EVENT);
+                  }];
+  notification_observers_.push_back(foreground);
+  notification_observers_.push_back(background);
+}
+
+void PowerMonitorDeviceSource::PlatformDestroy() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  for (std::vector<id>::iterator it = notification_observers_.begin();
+       it != notification_observers_.end(); ++it) {
+    [nc removeObserver:*it];
+  }
+  notification_observers_.clear();
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm
new file mode 100644
index 0000000..61e4396
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_mac.mm
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Implementation based on sample code from
+// http://developer.apple.com/library/mac/#qa/qa1340/_index.html.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/IOMessage.h>
+
+namespace base {
+
+void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
+  PowerMonitorSource::ProcessPowerEvent(event);
+}
+
+namespace {
+
+io_connect_t g_system_power_io_port = 0;
+IONotificationPortRef g_notification_port_ref = 0;
+io_object_t g_notifier_object = 0;
+
+void SystemPowerEventCallback(void*,
+                              io_service_t service,
+                              natural_t message_type,
+                              void* message_argument) {
+  switch (message_type) {
+    // If this message is not handled the system may delay sleep for 30 seconds.
+    case kIOMessageCanSystemSleep:
+      IOAllowPowerChange(g_system_power_io_port,
+          reinterpret_cast<intptr_t>(message_argument));
+      break;
+    case kIOMessageSystemWillSleep:
+      ProcessPowerEventHelper(base::PowerMonitorSource::SUSPEND_EVENT);
+      IOAllowPowerChange(g_system_power_io_port,
+          reinterpret_cast<intptr_t>(message_argument));
+      break;
+
+    case kIOMessageSystemWillPowerOn:
+      ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT);
+      break;
+  }
+}
+
+}  // namespace
+
+// The reason we can't include this code in the constructor is because
+// PlatformInit() requires an active runloop and the IO port needs to be
+// allocated at sandbox initialization time, before there's a runloop.
+// See crbug.com/83783 .
+
+// static
+void PowerMonitorDeviceSource::AllocateSystemIOPorts() {
+  DCHECK_EQ(g_system_power_io_port, 0u);
+
+  // Notification port allocated by IORegisterForSystemPower.
+  g_system_power_io_port = IORegisterForSystemPower(
+      NULL, &g_notification_port_ref, SystemPowerEventCallback,
+      &g_notifier_object);
+
+  DCHECK_NE(g_system_power_io_port, 0u);
+}
+
+void PowerMonitorDeviceSource::PlatformInit() {
+  // Need to call AllocateSystemIOPorts() before creating a PowerMonitor
+  // object.
+  DCHECK_NE(g_system_power_io_port, 0u);
+  if (g_system_power_io_port == 0)
+    return;
+
+  // Add the notification port to the application runloop
+  CFRunLoopAddSource(
+      CFRunLoopGetCurrent(),
+      IONotificationPortGetRunLoopSource(g_notification_port_ref),
+      kCFRunLoopCommonModes);
+}
+
+void PowerMonitorDeviceSource::PlatformDestroy() {
+  DCHECK_NE(g_system_power_io_port, 0u);
+  if (g_system_power_io_port == 0)
+    return;
+
+  // Remove the sleep notification port from the application runloop
+  CFRunLoopRemoveSource(
+      CFRunLoopGetCurrent(),
+      IONotificationPortGetRunLoopSource(g_notification_port_ref),
+      kCFRunLoopCommonModes);
+
+  // Deregister for system sleep notifications
+  IODeregisterForSystemPower(&g_notifier_object);
+
+  // IORegisterForSystemPower implicitly opens the Root Power Domain IOService,
+  // so we close it here.
+  IOServiceClose(g_system_power_io_port);
+
+  g_system_power_io_port = 0;
+
+  // Destroy the notification port allocated by IORegisterForSystemPower.
+  IONotificationPortDestroy(g_notification_port_ref);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_posix.cc b/base/power_monitor/power_monitor_device_source_posix.cc
new file mode 100644
index 0000000..f24e5b2
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_posix.cc
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+namespace base {
+
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_win.cc b/base/power_monitor/power_monitor_device_source_win.cc
new file mode 100644
index 0000000..0e199dc
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_win.cc
@@ -0,0 +1,116 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/power_monitor/power_monitor_source.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/win/wrapped_window_proc.h"
+
+namespace base {
+
+void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
+  PowerMonitorSource::ProcessPowerEvent(event);
+}
+
+namespace {
+
+const wchar_t kWindowClassName[] = L"Base_PowerMessageWindow";
+
+void ProcessWmPowerBroadcastMessage(WPARAM event_id) {
+  PowerMonitorSource::PowerEvent power_event;
+  switch (event_id) {
+    case PBT_APMPOWERSTATUSCHANGE:  // The power status changed.
+      power_event = PowerMonitorSource::POWER_STATE_EVENT;
+      break;
+    case PBT_APMRESUMEAUTOMATIC:  // Resume from suspend.
+      //case PBT_APMRESUMESUSPEND:  // User-initiated resume from suspend.
+      // We don't notify for this latter event
+      // because if it occurs it is always sent as a
+      // second event after PBT_APMRESUMEAUTOMATIC.
+      power_event = PowerMonitorSource::RESUME_EVENT;
+      break;
+    case PBT_APMSUSPEND:  // System has been suspended.
+      power_event = PowerMonitorSource::SUSPEND_EVENT;
+      break;
+    default:
+      return;
+
+      // Other Power Events:
+      // PBT_APMBATTERYLOW - removed in Vista.
+      // PBT_APMOEMEVENT - removed in Vista.
+      // PBT_APMQUERYSUSPEND - removed in Vista.
+      // PBT_APMQUERYSUSPENDFAILED - removed in Vista.
+      // PBT_APMRESUMECRITICAL - removed in Vista.
+      // PBT_POWERSETTINGCHANGE - user changed the power settings.
+  }
+
+  ProcessPowerEventHelper(power_event);
+}
+
+}  // namespace
+
+// Function to query the system to see if it is currently running on
+// battery power.  Returns true if running on battery.
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  SYSTEM_POWER_STATUS status;
+  if (!GetSystemPowerStatus(&status)) {
+    DPLOG(ERROR) << "GetSystemPowerStatus failed";
+    return false;
+  }
+  return (status.ACLineStatus == 0);
+}
+
+PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow()
+    : instance_(NULL), message_hwnd_(NULL) {
+  if (!MessageLoopForUI::IsCurrent()) {
+    // Creating this window in (e.g.) a renderer inhibits shutdown on Windows.
+    // See http://crbug.com/230122. TODO(vandebo): http://crbug.com/236031
+    DLOG(ERROR)
+        << "Cannot create windows on non-UI thread, power monitor disabled!";
+    return;
+  }
+  WNDCLASSEX window_class;
+  base::win::InitializeWindowClass(
+      kWindowClassName,
+      &base::win::WrappedWindowProc<
+          PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk>,
+      0, 0, 0, NULL, NULL, NULL, NULL, NULL,
+      &window_class);
+  instance_ = window_class.hInstance;
+  ATOM clazz = RegisterClassEx(&window_class);
+  DCHECK(clazz);
+
+  message_hwnd_ = CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName,
+      NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, instance_, NULL);
+}
+
+PowerMonitorDeviceSource::PowerMessageWindow::~PowerMessageWindow() {
+  if (message_hwnd_) {
+    DestroyWindow(message_hwnd_);
+    UnregisterClass(kWindowClassName, instance_);
+  }
+}
+
+// static
+LRESULT CALLBACK PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk(
+    HWND hwnd,
+    UINT message,
+    WPARAM wparam,
+    LPARAM lparam) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk"));
+
+  switch (message) {
+    case WM_POWERBROADCAST:
+      ProcessWmPowerBroadcastMessage(wparam);
+      return TRUE;
+    default:
+      return ::DefWindowProc(hwnd, message, wparam, lparam);
+  }
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_source.cc b/base/power_monitor/power_monitor_source.cc
new file mode 100644
index 0000000..6868cb1
--- /dev/null
+++ b/base/power_monitor/power_monitor_source.cc
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_source.h"
+
+#include "base/power_monitor/power_monitor.h"
+
+namespace base {
+
+PowerMonitorSource::PowerMonitorSource()
+    : on_battery_power_(false),
+      suspended_(false) {
+}
+
+PowerMonitorSource::~PowerMonitorSource() {
+}
+
+bool PowerMonitorSource::IsOnBatteryPower() {
+  AutoLock auto_lock(battery_lock_);
+  return on_battery_power_;
+}
+
+void PowerMonitorSource::ProcessPowerEvent(PowerEvent event_id) {
+  PowerMonitor* monitor = PowerMonitor::Get();
+  if (!monitor)
+    return;
+
+  PowerMonitorSource* source = monitor->Source();
+
+  // Suppress duplicate notifications.  Some platforms may
+  // send multiple notifications of the same event.
+  switch (event_id) {
+    case POWER_STATE_EVENT:
+      {
+        bool new_on_battery_power = source->IsOnBatteryPowerImpl();
+        bool changed = false;
+
+        {
+          AutoLock auto_lock(source->battery_lock_);
+          if (source->on_battery_power_ != new_on_battery_power) {
+              changed = true;
+              source->on_battery_power_ = new_on_battery_power;
+          }
+        }
+
+        if (changed)
+          monitor->NotifyPowerStateChange(new_on_battery_power);
+      }
+      break;
+    case RESUME_EVENT:
+      if (source->suspended_) {
+        source->suspended_ = false;
+        monitor->NotifyResume();
+      }
+      break;
+    case SUSPEND_EVENT:
+      if (!source->suspended_) {
+        source->suspended_ = true;
+        monitor->NotifySuspend();
+      }
+      break;
+  }
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_source.h b/base/power_monitor/power_monitor_source.h
new file mode 100644
index 0000000..b8f4185
--- /dev/null
+++ b/base/power_monitor/power_monitor_source.h
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class PowerMonitor;
+
+// Communicates power state changes to the power monitor.
+class BASE_EXPORT PowerMonitorSource {
+ public:
+  PowerMonitorSource();
+  virtual ~PowerMonitorSource();
+
+  // Normalized list of power events.
+  enum PowerEvent {
+    POWER_STATE_EVENT,  // The Power status of the system has changed.
+    SUSPEND_EVENT,      // The system is being suspended.
+    RESUME_EVENT        // The system is being resumed.
+  };
+
+  // Is the computer currently on battery power. Can be called on any thread.
+  bool IsOnBatteryPower();
+
+ protected:
+  friend class PowerMonitorTest;
+
+  // Friend function that is allowed to access the protected ProcessPowerEvent.
+  friend void ProcessPowerEventHelper(PowerEvent);
+
+  // Get the process-wide PowerMonitorSource (if not present, returns NULL).
+  static PowerMonitorSource* Get();
+
+  // ProcessPowerEvent should only be called from a single thread, most likely
+  // the UI thread or, in child processes, the IO thread.
+  static void ProcessPowerEvent(PowerEvent event_id);
+
+  // Platform-specific method to check whether the system is currently
+  // running on battery power.  Returns true if running on batteries,
+  // false otherwise.
+  virtual bool IsOnBatteryPowerImpl() = 0;
+
+ private:
+  bool on_battery_power_;
+  bool suspended_;
+
+  // This lock guards access to on_battery_power_, to ensure that
+  // IsOnBatteryPower can be called from any thread.
+  Lock battery_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitorSource);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc
new file mode 100644
index 0000000..2df8261
--- /dev/null
+++ b/base/power_monitor/power_monitor_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/test/power_monitor_test_base.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class PowerMonitorTest : public testing::Test {
+ protected:
+  PowerMonitorTest() {
+    power_monitor_source_ = new PowerMonitorTestSource();
+    power_monitor_.reset(new PowerMonitor(
+        scoped_ptr<PowerMonitorSource>(power_monitor_source_)));
+  }
+  ~PowerMonitorTest() override{};
+
+  PowerMonitorTestSource* source() { return power_monitor_source_; }
+  PowerMonitor* monitor() { return power_monitor_.get(); }
+
+ private:
+  PowerMonitorTestSource* power_monitor_source_;
+  scoped_ptr<PowerMonitor> power_monitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest);
+};
+
+// PowerMonitorSource is tightly coupled with the PowerMonitor, so this test
+// Will cover both classes
+TEST_F(PowerMonitorTest, PowerNotifications) {
+  const int kObservers = 5;
+
+  PowerMonitorTestObserver observers[kObservers];
+  for (int index = 0; index < kObservers; ++index)
+    monitor()->AddObserver(&observers[index]);
+
+  // Sending resume when not suspended should have no effect.
+  source()->GenerateResumeEvent();
+  EXPECT_EQ(observers[0].resumes(), 0);
+
+  // Pretend we suspended.
+  source()->GenerateSuspendEvent();
+  // Ensure all observers were notified of the event
+  for (int index = 0; index < kObservers; ++index)
+    EXPECT_EQ(observers[index].suspends(), 1);
+
+  // Send a second suspend notification.  This should be suppressed.
+  source()->GenerateSuspendEvent();
+  EXPECT_EQ(observers[0].suspends(), 1);
+
+  // Pretend we were awakened.
+  source()->GenerateResumeEvent();
+  EXPECT_EQ(observers[0].resumes(), 1);
+
+  // Send a duplicate resume notification.  This should be suppressed.
+  source()->GenerateResumeEvent();
+  EXPECT_EQ(observers[0].resumes(), 1);
+
+  // Pretend the device has gone on battery power
+  source()->GeneratePowerStateEvent(true);
+  EXPECT_EQ(observers[0].power_state_changes(), 1);
+  EXPECT_EQ(observers[0].last_power_state(), true);
+
+  // Repeated indications the device is on battery power should be suppressed.
+  source()->GeneratePowerStateEvent(true);
+  EXPECT_EQ(observers[0].power_state_changes(), 1);
+
+  // Pretend the device has gone off battery power
+  source()->GeneratePowerStateEvent(false);
+  EXPECT_EQ(observers[0].power_state_changes(), 2);
+  EXPECT_EQ(observers[0].last_power_state(), false);
+
+  // Repeated indications the device is off battery power should be suppressed.
+  source()->GeneratePowerStateEvent(false);
+  EXPECT_EQ(observers[0].power_state_changes(), 2);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_observer.h b/base/power_monitor/power_observer.h
new file mode 100644
index 0000000..6be70bb
--- /dev/null
+++ b/base/power_monitor/power_observer.h
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_OBSERVER_H_
+#define BASE_POWER_MONITOR_POWER_OBSERVER_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class BASE_EXPORT PowerObserver {
+ public:
+  // Notification of a change in power status of the computer, such
+  // as from switching between battery and A/C power.
+  virtual void OnPowerStateChange(bool on_battery_power) {};
+
+  // Notification that the system is suspending.
+  virtual void OnSuspend() {}
+
+  // Notification that the system is resuming.
+  virtual void OnResume() {}
+
+ protected:
+  virtual ~PowerObserver() {}
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_OBSERVER_H_
diff --git a/base/prefs/OWNERS b/base/prefs/OWNERS
new file mode 100644
index 0000000..97ab695
--- /dev/null
+++ b/base/prefs/OWNERS
@@ -0,0 +1,5 @@
+battre@chromium.org
+bauerb@chromium.org
+gab@chromium.org
+mnissler@chromium.org
+pam@chromium.org
diff --git a/base/prefs/README b/base/prefs/README
new file mode 100644
index 0000000..52d9c43
--- /dev/null
+++ b/base/prefs/README
@@ -0,0 +1,6 @@
+Prefs is a general-purpose key-value store for application preferences.
+
+The Prefs code lives in base/prefs but is not part of the
+'base/base.gyp:base' library because of a desire to keep its use
+optional. If you use Prefs, you should add a GYP dependency on
+base/base.gyp:base_prefs.
diff --git a/base/prefs/base_prefs_export.h b/base/prefs/base_prefs_export.h
new file mode 100644
index 0000000..3d207db
--- /dev/null
+++ b/base/prefs/base_prefs_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_BASE_PREFS_EXPORT_H_
+#define BASE_PREFS_BASE_PREFS_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_PREFS_IMPLEMENTATION)
+#define BASE_PREFS_EXPORT __declspec(dllexport)
+#else
+#define BASE_PREFS_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_PREFS_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_PREFS_IMPLEMENTATION)
+#define BASE_PREFS_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_PREFS_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_PREFS_EXPORT
+#endif
+
+#endif  // BASE_PREFS_BASE_PREFS_EXPORT_H_
diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc
new file mode 100644
index 0000000..92abba1
--- /dev/null
+++ b/base/prefs/default_pref_store.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/default_pref_store.h"
+#include "base/logging.h"
+
+using base::Value;
+
+DefaultPrefStore::DefaultPrefStore() {}
+
+bool DefaultPrefStore::GetValue(const std::string& key,
+                                const Value** result) const {
+  return prefs_.GetValue(key, result);
+}
+
+void DefaultPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void DefaultPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool DefaultPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+void DefaultPrefStore::SetDefaultValue(const std::string& key,
+                                       scoped_ptr<Value> value) {
+  DCHECK(!GetValue(key, NULL));
+  prefs_.SetValue(key, value.release());
+}
+
+void DefaultPrefStore::ReplaceDefaultValue(const std::string& key,
+                                           scoped_ptr<Value> value) {
+  const Value* old_value = NULL;
+  GetValue(key, &old_value);
+  bool notify = !old_value->Equals(value.get());
+  prefs_.SetValue(key, value.release());
+  if (notify)
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+DefaultPrefStore::const_iterator DefaultPrefStore::begin() const {
+  return prefs_.begin();
+}
+
+DefaultPrefStore::const_iterator DefaultPrefStore::end() const {
+  return prefs_.end();
+}
+
+DefaultPrefStore::~DefaultPrefStore() {}
diff --git a/base/prefs/default_pref_store.h b/base/prefs/default_pref_store.h
new file mode 100644
index 0000000..26462da
--- /dev/null
+++ b/base/prefs/default_pref_store.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_DEFAULT_PREF_STORE_H_
+#define BASE_PREFS_DEFAULT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+
+// Used within a PrefRegistry to keep track of default preference values.
+class BASE_PREFS_EXPORT DefaultPrefStore : public PrefStore {
+ public:
+  typedef PrefValueMap::const_iterator const_iterator;
+
+  DefaultPrefStore();
+
+  // PrefStore implementation:
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+
+  // Sets a |value| for |key|. Should only be called if a value has not been
+  // set yet; otherwise call ReplaceDefaultValue().
+  void SetDefaultValue(const std::string& key, scoped_ptr<base::Value> value);
+
+  // Replaces the the value for |key| with a new value. Should only be called
+  // if a value has alreday been set; otherwise call SetDefaultValue().
+  void ReplaceDefaultValue(const std::string& key,
+                           scoped_ptr<base::Value> value);
+
+  const_iterator begin() const;
+  const_iterator end() const;
+
+ private:
+  ~DefaultPrefStore() override;
+
+  PrefValueMap prefs_;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
+};
+
+#endif  // BASE_PREFS_DEFAULT_PREF_STORE_H_
diff --git a/base/prefs/default_pref_store_unittest.cc b/base/prefs/default_pref_store_unittest.cc
new file mode 100644
index 0000000..9299937
--- /dev/null
+++ b/base/prefs/default_pref_store_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/default_pref_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringValue;
+using base::Value;
+
+namespace {
+
+class MockPrefStoreObserver : public PrefStore::Observer {
+ public:
+  explicit MockPrefStoreObserver(DefaultPrefStore* pref_store);
+  ~MockPrefStoreObserver() override;
+
+  int change_count() {
+    return change_count_;
+  }
+
+  // PrefStore::Observer implementation:
+  void OnPrefValueChanged(const std::string& key) override;
+  void OnInitializationCompleted(bool succeeded) override {}
+
+ private:
+  DefaultPrefStore* pref_store_;
+
+  int change_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockPrefStoreObserver);
+};
+
+MockPrefStoreObserver::MockPrefStoreObserver(DefaultPrefStore* pref_store)
+    : pref_store_(pref_store), change_count_(0) {
+  pref_store_->AddObserver(this);
+}
+
+MockPrefStoreObserver::~MockPrefStoreObserver() {
+  pref_store_->RemoveObserver(this);
+}
+
+void MockPrefStoreObserver::OnPrefValueChanged(const std::string& key) {
+  change_count_++;
+}
+
+}  // namespace
+
+TEST(DefaultPrefStoreTest, NotifyPrefValueChanged) {
+  scoped_refptr<DefaultPrefStore> pref_store(new DefaultPrefStore);
+  MockPrefStoreObserver observer(pref_store.get());
+  std::string kPrefKey("pref_key");
+
+  // Setting a default value shouldn't send a change notification.
+  pref_store->SetDefaultValue(kPrefKey,
+                              scoped_ptr<Value>(new StringValue("foo")));
+  EXPECT_EQ(0, observer.change_count());
+
+  // Replacing the default value should send a change notification...
+  pref_store->ReplaceDefaultValue(kPrefKey,
+                                  scoped_ptr<Value>(new StringValue("bar")));
+  EXPECT_EQ(1, observer.change_count());
+
+  // But only if the value actually changed.
+  pref_store->ReplaceDefaultValue(kPrefKey,
+                                  scoped_ptr<Value>(new StringValue("bar")));
+  EXPECT_EQ(1, observer.change_count());
+}
+
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
new file mode 100644
index 0000000..8ce5974
--- /dev/null
+++ b/base/prefs/json_pref_store.cc
@@ -0,0 +1,534 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/json_pref_store.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_filter.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/time/default_clock.h"
+#include "base/values.h"
+
+// Result returned from internal read tasks.
+struct JsonPrefStore::ReadResult {
+ public:
+  ReadResult();
+  ~ReadResult();
+
+  scoped_ptr<base::Value> value;
+  PrefReadError error;
+  bool no_dir;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReadResult);
+};
+
+JsonPrefStore::ReadResult::ReadResult()
+    : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) {
+}
+
+JsonPrefStore::ReadResult::~ReadResult() {
+}
+
+namespace {
+
+// Some extensions we'll tack on to copies of the Preferences files.
+const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad");
+
+PersistentPrefStore::PrefReadError HandleReadErrors(
+    const base::Value* value,
+    const base::FilePath& path,
+    int error_code,
+    const std::string& error_msg) {
+  if (!value) {
+    DVLOG(1) << "Error while loading JSON file: " << error_msg
+             << ", file: " << path.value();
+    switch (error_code) {
+      case JSONFileValueDeserializer::JSON_ACCESS_DENIED:
+        return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
+        break;
+      case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE:
+        return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
+        break;
+      case JSONFileValueDeserializer::JSON_FILE_LOCKED:
+        return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
+        break;
+      case JSONFileValueDeserializer::JSON_NO_SUCH_FILE:
+        return PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
+        break;
+      default:
+        // JSON errors indicate file corruption of some sort.
+        // Since the file is corrupt, move it to the side and continue with
+        // empty preferences.  This will result in them losing their settings.
+        // We keep the old file for possible support and debugging assistance
+        // as well as to detect if they're seeing these errors repeatedly.
+        // TODO(erikkay) Instead, use the last known good file.
+        base::FilePath bad = path.ReplaceExtension(kBadExtension);
+
+        // If they've ever had a parse error before, put them in another bucket.
+        // TODO(erikkay) if we keep this error checking for very long, we may
+        // want to differentiate between recent and long ago errors.
+        bool bad_existed = base::PathExists(bad);
+        base::Move(path, bad);
+        return bad_existed ? PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT
+                           : PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
+    }
+  } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
+    return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
+  }
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+// Records a sample for |size| in the Settings.JsonDataReadSizeKilobytes
+// histogram suffixed with the base name of the JSON file under |path|.
+void RecordJsonDataSizeHistogram(const base::FilePath& path, size_t size) {
+  std::string spaceless_basename;
+  base::ReplaceChars(path.BaseName().MaybeAsASCII(), " ", "_",
+                     &spaceless_basename);
+
+  // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+  // macro adapted to allow for a dynamically suffixed histogram name.
+  // Note: The factory creates and owns the histogram.
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      "Settings.JsonDataReadSizeKilobytes." + spaceless_basename, 1, 10000, 50,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->Add(static_cast<int>(size) / 1024);
+}
+
+scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
+    const base::FilePath& path,
+    const base::FilePath& alternate_path) {
+  if (!base::PathExists(path) && !alternate_path.empty() &&
+      base::PathExists(alternate_path)) {
+    base::Move(alternate_path, path);
+  }
+
+  int error_code;
+  std::string error_msg;
+  scoped_ptr<JsonPrefStore::ReadResult> read_result(
+      new JsonPrefStore::ReadResult);
+  JSONFileValueDeserializer deserializer(path);
+  read_result->value.reset(deserializer.Deserialize(&error_code, &error_msg));
+  read_result->error =
+      HandleReadErrors(read_result->value.get(), path, error_code, error_msg);
+  read_result->no_dir = !base::PathExists(path.DirName());
+
+  if (read_result->error == PersistentPrefStore::PREF_READ_ERROR_NONE)
+    RecordJsonDataSizeHistogram(path, deserializer.get_last_read_size());
+
+  return read_result.Pass();
+}
+
+}  // namespace
+
+// static
+scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile(
+    const base::FilePath& filename,
+    base::SequencedWorkerPool* worker_pool) {
+  std::string token("json_pref_store-");
+  token.append(filename.AsUTF8Unsafe());
+  return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+      worker_pool->GetNamedSequenceToken(token),
+      base::SequencedWorkerPool::BLOCK_SHUTDOWN);
+}
+
+JsonPrefStore::JsonPrefStore(
+    const base::FilePath& filename,
+    const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+    scoped_ptr<PrefFilter> pref_filter)
+    : path_(filename),
+      sequenced_task_runner_(sequenced_task_runner),
+      prefs_(new base::DictionaryValue()),
+      read_only_(false),
+      writer_(filename, sequenced_task_runner),
+      pref_filter_(pref_filter.Pass()),
+      initialized_(false),
+      filtering_in_progress_(false),
+      read_error_(PREF_READ_ERROR_NONE),
+      write_count_histogram_(writer_.commit_interval(), path_) {
+  DCHECK(!path_.empty());
+}
+
+JsonPrefStore::JsonPrefStore(
+    const base::FilePath& filename,
+    const base::FilePath& alternate_filename,
+    const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+    scoped_ptr<PrefFilter> pref_filter)
+    : path_(filename),
+      alternate_path_(alternate_filename),
+      sequenced_task_runner_(sequenced_task_runner),
+      prefs_(new base::DictionaryValue()),
+      read_only_(false),
+      writer_(filename, sequenced_task_runner),
+      pref_filter_(pref_filter.Pass()),
+      initialized_(false),
+      filtering_in_progress_(false),
+      read_error_(PREF_READ_ERROR_NONE),
+      write_count_histogram_(writer_.commit_interval(), path_) {
+  DCHECK(!path_.empty());
+}
+
+bool JsonPrefStore::GetValue(const std::string& key,
+                             const base::Value** result) const {
+  DCHECK(CalledOnValidThread());
+
+  base::Value* tmp = NULL;
+  if (!prefs_->Get(key, &tmp))
+    return false;
+
+  if (result)
+    *result = tmp;
+  return true;
+}
+
+void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
+  DCHECK(CalledOnValidThread());
+
+  observers_.AddObserver(observer);
+}
+
+void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  DCHECK(CalledOnValidThread());
+
+  observers_.RemoveObserver(observer);
+}
+
+bool JsonPrefStore::HasObservers() const {
+  DCHECK(CalledOnValidThread());
+
+  return observers_.might_have_observers();
+}
+
+bool JsonPrefStore::IsInitializationComplete() const {
+  DCHECK(CalledOnValidThread());
+
+  return initialized_;
+}
+
+bool JsonPrefStore::GetMutableValue(const std::string& key,
+                                    base::Value** result) {
+  DCHECK(CalledOnValidThread());
+
+  return prefs_->Get(key, result);
+}
+
+void JsonPrefStore::SetValue(const std::string& key,
+                             base::Value* value,
+                             uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(value);
+  scoped_ptr<base::Value> new_value(value);
+  base::Value* old_value = NULL;
+  prefs_->Get(key, &old_value);
+  if (!old_value || !value->Equals(old_value)) {
+    prefs_->Set(key, new_value.release());
+    ReportValueChanged(key, flags);
+  }
+}
+
+void JsonPrefStore::SetValueSilently(const std::string& key,
+                                     base::Value* value,
+                                     uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(value);
+  scoped_ptr<base::Value> new_value(value);
+  base::Value* old_value = NULL;
+  prefs_->Get(key, &old_value);
+  if (!old_value || !value->Equals(old_value)) {
+    prefs_->Set(key, new_value.release());
+    if (!read_only_)
+      writer_.ScheduleWrite(this);
+  }
+}
+
+void JsonPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  if (prefs_->RemovePath(key, NULL))
+    ReportValueChanged(key, flags);
+}
+
+void JsonPrefStore::RemoveValueSilently(const std::string& key, uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  prefs_->RemovePath(key, NULL);
+  if (!read_only_)
+    writer_.ScheduleWrite(this);
+}
+
+bool JsonPrefStore::ReadOnly() const {
+  DCHECK(CalledOnValidThread());
+
+  return read_only_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
+  DCHECK(CalledOnValidThread());
+
+  return read_error_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
+  DCHECK(CalledOnValidThread());
+
+  OnFileRead(ReadPrefsFromDisk(path_, alternate_path_));
+  return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
+                                : read_error_;
+}
+
+void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
+  DCHECK(CalledOnValidThread());
+
+  initialized_ = false;
+  error_delegate_.reset(error_delegate);
+
+  // Weakly binds the read task so that it doesn't kick in during shutdown.
+  base::PostTaskAndReplyWithResult(
+      sequenced_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&ReadPrefsFromDisk, path_, alternate_path_),
+      base::Bind(&JsonPrefStore::OnFileRead, AsWeakPtr()));
+}
+
+void JsonPrefStore::CommitPendingWrite() {
+  DCHECK(CalledOnValidThread());
+
+  if (writer_.HasPendingWrite() && !read_only_)
+    writer_.DoScheduledWrite();
+}
+
+void JsonPrefStore::ReportValueChanged(const std::string& key, uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  if (pref_filter_)
+    pref_filter_->FilterUpdate(key);
+
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+
+  if (!read_only_)
+    writer_.ScheduleWrite(this);
+}
+
+void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
+    const base::Closure& on_next_successful_write) {
+  DCHECK(CalledOnValidThread());
+
+  writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write);
+}
+
+void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(read_result);
+
+  scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue);
+
+  read_error_ = read_result->error;
+
+  bool initialization_successful = !read_result->no_dir;
+
+  if (initialization_successful) {
+    switch (read_error_) {
+      case PREF_READ_ERROR_ACCESS_DENIED:
+      case PREF_READ_ERROR_FILE_OTHER:
+      case PREF_READ_ERROR_FILE_LOCKED:
+      case PREF_READ_ERROR_JSON_TYPE:
+      case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
+        read_only_ = true;
+        break;
+      case PREF_READ_ERROR_NONE:
+        DCHECK(read_result->value.get());
+        unfiltered_prefs.reset(
+            static_cast<base::DictionaryValue*>(read_result->value.release()));
+        break;
+      case PREF_READ_ERROR_NO_FILE:
+        // If the file just doesn't exist, maybe this is first run.  In any case
+        // there's no harm in writing out default prefs in this case.
+        break;
+      case PREF_READ_ERROR_JSON_PARSE:
+      case PREF_READ_ERROR_JSON_REPEAT:
+        break;
+      case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
+        // This is a special error code to be returned by ReadPrefs when it
+        // can't complete synchronously, it should never be returned by the read
+        // operation itself.
+        NOTREACHED();
+        break;
+      case PREF_READ_ERROR_LEVELDB_IO:
+      case PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY:
+      case PREF_READ_ERROR_LEVELDB_CORRUPTION:
+        // These are specific to LevelDBPrefStore.
+        NOTREACHED();
+      case PREF_READ_ERROR_MAX_ENUM:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  if (pref_filter_) {
+    filtering_in_progress_ = true;
+    const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback(
+        base::Bind(
+            &JsonPrefStore::FinalizeFileRead, AsWeakPtr(),
+            initialization_successful));
+    pref_filter_->FilterOnLoad(post_filter_on_load_callback,
+                               unfiltered_prefs.Pass());
+  } else {
+    FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false);
+  }
+}
+
+JsonPrefStore::~JsonPrefStore() {
+  CommitPendingWrite();
+}
+
+bool JsonPrefStore::SerializeData(std::string* output) {
+  DCHECK(CalledOnValidThread());
+
+  write_count_histogram_.RecordWriteOccured();
+
+  if (pref_filter_)
+    pref_filter_->FilterSerializeData(prefs_.get());
+
+  JSONStringValueSerializer serializer(output);
+  // Not pretty-printing prefs shrinks pref file size by ~30%. To obtain
+  // readable prefs for debugging purposes, you can dump your prefs into any
+  // command-line or online JSON pretty printing tool.
+  serializer.set_pretty_print(false);
+  return serializer.Serialize(*prefs_);
+}
+
+void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
+                                     scoped_ptr<base::DictionaryValue> prefs,
+                                     bool schedule_write) {
+  DCHECK(CalledOnValidThread());
+
+  filtering_in_progress_ = false;
+
+  if (!initialization_successful) {
+    FOR_EACH_OBSERVER(PrefStore::Observer,
+                      observers_,
+                      OnInitializationCompleted(false));
+    return;
+  }
+
+  prefs_ = prefs.Pass();
+
+  initialized_ = true;
+
+  if (schedule_write && !read_only_)
+    writer_.ScheduleWrite(this);
+
+  if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
+    error_delegate_->OnError(read_error_);
+
+  FOR_EACH_OBSERVER(PrefStore::Observer,
+                    observers_,
+                    OnInitializationCompleted(true));
+
+  return;
+}
+
+// NOTE: This value should NOT be changed without renaming the histogram
+// otherwise it will create incompatible buckets.
+const int32_t
+    JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins = 5;
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+    const base::TimeDelta& commit_interval,
+    const base::FilePath& path)
+    : WriteCountHistogram(commit_interval,
+                          path,
+                          scoped_ptr<base::Clock>(new base::DefaultClock)) {
+}
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+    const base::TimeDelta& commit_interval,
+    const base::FilePath& path,
+    scoped_ptr<base::Clock> clock)
+    : commit_interval_(commit_interval),
+      path_(path),
+      clock_(clock.release()),
+      report_interval_(
+          base::TimeDelta::FromMinutes(kHistogramWriteReportIntervalMins)),
+      last_report_time_(clock_->Now()),
+      writes_since_last_report_(0) {
+}
+
+JsonPrefStore::WriteCountHistogram::~WriteCountHistogram() {
+  ReportOutstandingWrites();
+}
+
+void JsonPrefStore::WriteCountHistogram::RecordWriteOccured() {
+  ReportOutstandingWrites();
+
+  ++writes_since_last_report_;
+}
+
+void JsonPrefStore::WriteCountHistogram::ReportOutstandingWrites() {
+  base::Time current_time = clock_->Now();
+  base::TimeDelta time_since_last_report = current_time - last_report_time_;
+
+  if (time_since_last_report <= report_interval_)
+    return;
+
+  // If the time since the last report exceeds the report interval, report all
+  // the writes since the last report. They must have all occurred in the same
+  // report interval.
+  base::HistogramBase* histogram = GetHistogram();
+  histogram->Add(writes_since_last_report_);
+
+  // There may be several report intervals that elapsed that don't have any
+  // writes in them. Report these too.
+  int64 total_num_intervals_elapsed =
+      (time_since_last_report / report_interval_);
+  for (int64 i = 0; i < total_num_intervals_elapsed - 1; ++i)
+    histogram->Add(0);
+
+  writes_since_last_report_ = 0;
+  last_report_time_ += total_num_intervals_elapsed * report_interval_;
+}
+
+base::HistogramBase* JsonPrefStore::WriteCountHistogram::GetHistogram() {
+  std::string spaceless_basename;
+  base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
+                     &spaceless_basename);
+  std::string histogram_name =
+      "Settings.JsonDataWriteCount." + spaceless_basename;
+
+  // The min value for a histogram is 1. The max value is the maximum number of
+  // writes that can occur in the window being recorded. The number of buckets
+  // used is the max value (plus the underflow/overflow buckets).
+  int32_t min_value = 1;
+  int32_t max_value = report_interval_ / commit_interval_;
+  int32_t num_buckets = max_value + 1;
+
+  // NOTE: These values should NOT be changed without renaming the histogram
+  // otherwise it will create incompatible buckets.
+  DCHECK_EQ(30, max_value);
+  DCHECK_EQ(31, num_buckets);
+
+  // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+  // macro adapted to allow for a dynamically suffixed histogram name.
+  // Note: The factory creates and owns the histogram.
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      histogram_name, min_value, max_value, num_buckets,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  return histogram;
+}
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
new file mode 100644
index 0000000..2ad546d
--- /dev/null
+++ b/base/prefs/json_pref_store.h
@@ -0,0 +1,220 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_JSON_PREF_STORE_H_
+#define BASE_PREFS_JSON_PREF_STORE_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/important_file_writer.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/threading/non_thread_safe.h"
+
+class PrefFilter;
+
+namespace base {
+class Clock;
+class DictionaryValue;
+class FilePath;
+class HistogramBase;
+class SequencedTaskRunner;
+class SequencedWorkerPool;
+class Value;
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps);
+}
+
+// A writable PrefStore implementation that is used for user preferences.
+class BASE_PREFS_EXPORT JsonPrefStore
+    : public PersistentPrefStore,
+      public base::ImportantFileWriter::DataSerializer,
+      public base::SupportsWeakPtr<JsonPrefStore>,
+      public base::NonThreadSafe {
+ public:
+  struct ReadResult;
+
+  // Returns instance of SequencedTaskRunner which guarantees that file
+  // operations on the same file will be executed in sequenced order.
+  static scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForFile(
+      const base::FilePath& pref_filename,
+      base::SequencedWorkerPool* worker_pool);
+
+  // Same as the constructor below with no alternate filename.
+  JsonPrefStore(
+      const base::FilePath& pref_filename,
+      const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+      scoped_ptr<PrefFilter> pref_filter);
+
+  // |sequenced_task_runner| must be a shutdown-blocking task runner, ideally
+  // created by the GetTaskRunnerForFile() method above.
+  // |pref_filename| is the path to the file to read prefs from.
+  // |pref_alternate_filename| is the path to an alternate file which the
+  // desired prefs may have previously been written to. If |pref_filename|
+  // doesn't exist and |pref_alternate_filename| does, |pref_alternate_filename|
+  // will be moved to |pref_filename| before the read occurs.
+  JsonPrefStore(
+      const base::FilePath& pref_filename,
+      const base::FilePath& pref_alternate_filename,
+      const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+      scoped_ptr<PrefFilter> pref_filter);
+
+  // PrefStore overrides:
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
+
+  // PersistentPrefStore overrides:
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  // Note this method may be asynchronous if this instance has a |pref_filter_|
+  // in which case it will return PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE.
+  // See details in pref_filter.h.
+  PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+  void CommitPendingWrite() override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+
+  // Just like RemoveValue(), but doesn't notify observers. Used when doing some
+  // cleanup that shouldn't otherwise alert observers.
+  void RemoveValueSilently(const std::string& key, uint32 flags);
+
+  // Registers |on_next_successful_write| to be called once, on the next
+  // successful write event of |writer_|.
+  void RegisterOnNextSuccessfulWriteCallback(
+      const base::Closure& on_next_successful_write);
+
+ private:
+  // Represents a histogram for recording the number of writes to the pref file
+  // that occur every kHistogramWriteReportIntervalInMins minutes.
+  class BASE_PREFS_EXPORT WriteCountHistogram {
+   public:
+    static const int32_t kHistogramWriteReportIntervalMins;
+
+    WriteCountHistogram(const base::TimeDelta& commit_interval,
+                        const base::FilePath& path);
+    // Constructor for testing. |clock| is a test Clock that is used to retrieve
+    // the time.
+    WriteCountHistogram(const base::TimeDelta& commit_interval,
+                        const base::FilePath& path,
+                        scoped_ptr<base::Clock> clock);
+    ~WriteCountHistogram();
+
+    // Record that a write has occured.
+    void RecordWriteOccured();
+
+    // Reports writes (that have not yet been reported) in all of the recorded
+    // intervals that have elapsed up until current time.
+    void ReportOutstandingWrites();
+
+    base::HistogramBase* GetHistogram();
+
+   private:
+    // The minimum interval at which writes can occur.
+    const base::TimeDelta commit_interval_;
+
+    // The path to the file.
+    const base::FilePath path_;
+
+    // Clock which is used to retrieve the current time.
+    scoped_ptr<base::Clock> clock_;
+
+    // The interval at which to report write counts.
+    const base::TimeDelta report_interval_;
+
+    // The time at which the last histogram value was reported for the number
+    // of write counts.
+    base::Time last_report_time_;
+
+    // The number of writes that have occured since the last write count was
+    // reported.
+    uint32_t writes_since_last_report_;
+
+    DISALLOW_COPY_AND_ASSIGN(WriteCountHistogram);
+  };
+
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestBasic);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestSinglePeriod);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestMultiplePeriods);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestPeriodWithGaps);
+
+  ~JsonPrefStore() override;
+
+  // This method is called after the JSON file has been read.  It then hands
+  // |value| (or an empty dictionary in some read error cases) to the
+  // |pref_filter| if one is set. It also gives a callback pointing at
+  // FinalizeFileRead() to that |pref_filter_| which is then responsible for
+  // invoking it when done. If there is no |pref_filter_|, FinalizeFileRead()
+  // is invoked directly.
+  void OnFileRead(scoped_ptr<ReadResult> read_result);
+
+  // ImportantFileWriter::DataSerializer overrides:
+  bool SerializeData(std::string* output) override;
+
+  // This method is called after the JSON file has been read and the result has
+  // potentially been intercepted and modified by |pref_filter_|.
+  // |initialization_successful| is pre-determined by OnFileRead() and should
+  // be used when reporting OnInitializationCompleted().
+  // |schedule_write| indicates whether a write should be immediately scheduled
+  // (typically because the |pref_filter_| has already altered the |prefs|) --
+  // this will be ignored if this store is read-only.
+  void FinalizeFileRead(bool initialization_successful,
+                        scoped_ptr<base::DictionaryValue> prefs,
+                        bool schedule_write);
+
+  const base::FilePath path_;
+  const base::FilePath alternate_path_;
+  const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
+
+  scoped_ptr<base::DictionaryValue> prefs_;
+
+  bool read_only_;
+
+  // Helper for safely writing pref data.
+  base::ImportantFileWriter writer_;
+
+  scoped_ptr<PrefFilter> pref_filter_;
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  scoped_ptr<ReadErrorDelegate> error_delegate_;
+
+  bool initialized_;
+  bool filtering_in_progress_;
+  PrefReadError read_error_;
+
+  std::set<std::string> keys_need_empty_value_;
+
+  WriteCountHistogram write_count_histogram_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
+};
+
+#endif  // BASE_PREFS_JSON_PREF_STORE_H_
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
new file mode 100644
index 0000000..0fab868
--- /dev/null
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -0,0 +1,812 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/json_pref_store.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/path_service.h"
+#include "base/prefs/pref_filter.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+const char kHomePage[] = "homepage";
+
+// Set the time on the given SimpleTestClock to the given time in minutes.
+void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
+  const int32_t kBaseTimeMins = 100;
+  clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
+}
+
+// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
+// to the |prefs| until explicitly asked to release them.
+class InterceptingPrefFilter : public PrefFilter {
+ public:
+  InterceptingPrefFilter();
+  ~InterceptingPrefFilter() override;
+
+  // PrefFilter implementation:
+  void FilterOnLoad(
+      const PostFilterOnLoadCallback& post_filter_on_load_callback,
+      scoped_ptr<base::DictionaryValue> pref_store_contents) override;
+  void FilterUpdate(const std::string& path) override {}
+  void FilterSerializeData(
+      base::DictionaryValue* pref_store_contents) override {}
+
+  bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
+
+  // Finalize an intercepted read, handing |intercepted_prefs_| back to its
+  // JsonPrefStore.
+  void ReleasePrefs();
+
+ private:
+  PostFilterOnLoadCallback post_filter_on_load_callback_;
+  scoped_ptr<base::DictionaryValue> intercepted_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
+};
+
+InterceptingPrefFilter::InterceptingPrefFilter() {}
+InterceptingPrefFilter::~InterceptingPrefFilter() {}
+
+void InterceptingPrefFilter::FilterOnLoad(
+    const PostFilterOnLoadCallback& post_filter_on_load_callback,
+    scoped_ptr<base::DictionaryValue> pref_store_contents) {
+  post_filter_on_load_callback_ = post_filter_on_load_callback;
+  intercepted_prefs_ = pref_store_contents.Pass();
+}
+
+void InterceptingPrefFilter::ReleasePrefs() {
+  EXPECT_FALSE(post_filter_on_load_callback_.is_null());
+  post_filter_on_load_callback_.Run(intercepted_prefs_.Pass(), false);
+  post_filter_on_load_callback_.Reset();
+}
+
+class MockPrefStoreObserver : public PrefStore::Observer {
+ public:
+  MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void (bool));
+};
+
+class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+  MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
+};
+
+}  // namespace
+
+class JsonPrefStoreTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_));
+    data_dir_ = data_dir_.AppendASCII("prefs");
+    ASSERT_TRUE(PathExists(data_dir_));
+  }
+
+  void TearDown() override {
+    // Make sure all pending tasks have been processed (e.g., deleting the
+    // JsonPrefStore may post write tasks).
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          MessageLoop::QuitWhenIdleClosure());
+    message_loop_.Run();
+  }
+
+  // The path to temporary directory used to contain the test operations.
+  base::ScopedTempDir temp_dir_;
+  // The path to the directory where the test data is stored.
+  base::FilePath data_dir_;
+  // A message loop that we can use as the file thread message loop.
+  MessageLoop message_loop_;
+
+ private:
+  // Ensure histograms are reset for each test.
+  StatisticsRecorder statistics_recorder_;
+};
+
+// Test fallback behavior for a nonexistent file.
+TEST_F(JsonPrefStoreTest, NonExistentFile) {
+  base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+  ASSERT_FALSE(PathExists(bogus_input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+// Test fallback behavior for a nonexistent file and alternate file.
+TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
+  base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+  base::FilePath bogus_alternate_input_file =
+      data_dir_.AppendASCII("read_alternate.txt");
+  ASSERT_FALSE(PathExists(bogus_input_file));
+  ASSERT_FALSE(PathExists(bogus_alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+// Test fallback behavior for an invalid file.
+TEST_F(JsonPrefStoreTest, InvalidFile) {
+  base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
+  base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
+  ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+
+  // The file should have been moved aside.
+  EXPECT_FALSE(PathExists(invalid_file));
+  base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
+  EXPECT_TRUE(PathExists(moved_aside));
+  EXPECT_TRUE(TextContentsEqual(invalid_file_original, moved_aside));
+}
+
+// This function is used to avoid code duplication while testing synchronous and
+// asynchronous version of the JsonPrefStore loading.
+void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
+                               const base::FilePath& output_file,
+                               const base::FilePath& golden_output_file) {
+  const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
+  const char kMaxTabs[] = "tabs.max_tabs";
+  const char kLongIntPref[] = "long_int.pref";
+
+  std::string cnn("http://www.cnn.com");
+
+  const Value* actual;
+  EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
+  std::string string_value;
+  EXPECT_TRUE(actual->GetAsString(&string_value));
+  EXPECT_EQ(cnn, string_value);
+
+  const char kSomeDirectory[] = "some_directory";
+
+  EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
+  base::FilePath::StringType path;
+  EXPECT_TRUE(actual->GetAsString(&path));
+  EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
+  base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
+
+  pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
+  EXPECT_TRUE(actual->GetAsString(&path));
+  EXPECT_EQ(some_path.value(), path);
+
+  // Test reading some other data types from sub-dictionaries.
+  EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
+  bool boolean = false;
+  EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+  EXPECT_TRUE(boolean);
+
+  pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
+  EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+  EXPECT_FALSE(boolean);
+
+  EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
+  int integer = 0;
+  EXPECT_TRUE(actual->GetAsInteger(&integer));
+  EXPECT_EQ(20, integer);
+  pref_store->SetValue(kMaxTabs, new FundamentalValue(10),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
+  EXPECT_TRUE(actual->GetAsInteger(&integer));
+  EXPECT_EQ(10, integer);
+
+  pref_store->SetValue(kLongIntPref,
+                       new StringValue(base::Int64ToString(214748364842LL)),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
+  EXPECT_TRUE(actual->GetAsString(&string_value));
+  int64 value;
+  base::StringToInt64(string_value, &value);
+  EXPECT_EQ(214748364842LL, value);
+
+  // Serialize and compare to expected output.
+  ASSERT_TRUE(PathExists(golden_output_file));
+  pref_store->CommitPendingWrite();
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file));
+  ASSERT_TRUE(base::DeleteFile(output_file, false));
+}
+
+TEST_F(JsonPrefStoreTest, Basic) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, BasicAsync) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  {
+    MockPrefStoreObserver mock_observer;
+    pref_store->AddObserver(&mock_observer);
+
+    MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    EXPECT_CALL(*mock_error_delegate,
+                OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    RunLoop().RunUntilIdle();
+    pref_store->RemoveObserver(&mock_observer);
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_TRUE(pref_store->IsInitializationComplete());
+  }
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
+  FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
+
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  // Set some keys with empty values.
+  pref_store->SetValue("list", new base::ListValue,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  pref_store->SetValue("dict", new base::DictionaryValue,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  // Write to file.
+  pref_store->CommitPendingWrite();
+  MessageLoop::current()->RunUntilIdle();
+
+  // Reload.
+  pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
+                                 scoped_ptr<PrefFilter>());
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+  ASSERT_FALSE(pref_store->ReadOnly());
+
+  // Check values.
+  const Value* result = NULL;
+  EXPECT_TRUE(pref_store->GetValue("list", &result));
+  EXPECT_TRUE(ListValue().Equals(result));
+  EXPECT_TRUE(pref_store->GetValue("dict", &result));
+  EXPECT_TRUE(DictionaryValue().Equals(result));
+}
+
+// This test is just documenting some potentially non-obvious behavior. It
+// shouldn't be taken as normative.
+TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
+  FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
+
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  base::DictionaryValue* dict = new base::DictionaryValue;
+  dict->SetString("key", "value");
+  pref_store->SetValue("dict", dict,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  pref_store->RemoveValue("dict.key",
+                          WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  const base::Value* retrieved_dict = NULL;
+  bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
+  EXPECT_FALSE(has_dict);
+}
+
+// Tests asynchronous reading of the file when there is no file.
+TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
+  base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
+  ASSERT_FALSE(PathExists(bogus_input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  MockPrefStoreObserver mock_observer;
+  pref_store->AddObserver(&mock_observer);
+
+  MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
+  pref_store->ReadPrefsAsync(mock_error_delegate);
+
+  EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+  EXPECT_CALL(*mock_error_delegate,
+              OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
+  RunLoop().RunUntilIdle();
+  pref_store->RemoveObserver(&mock_observer);
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+
+  scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
+      new InterceptingPrefFilter());
+  InterceptingPrefFilter* raw_intercepting_pref_filter_ =
+      intercepting_pref_filter.get();
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
+
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+
+  // The store shouldn't be considered initialized until the interceptor
+  // returns.
+  EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+  EXPECT_FALSE(pref_store->IsInitializationComplete());
+  EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
+
+  raw_intercepting_pref_filter_->ReleasePrefs();
+
+  EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+  EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+
+  scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
+      new InterceptingPrefFilter());
+  InterceptingPrefFilter* raw_intercepting_pref_filter_ =
+      intercepting_pref_filter.get();
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
+
+  MockPrefStoreObserver mock_observer;
+  pref_store->AddObserver(&mock_observer);
+
+  // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
+  MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+
+  {
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
+    // EXPECT_CALL(*mock_error_delegate,
+    //             OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    RunLoop().RunUntilIdle();
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+    EXPECT_FALSE(pref_store->IsInitializationComplete());
+    EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
+  }
+
+  {
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    // EXPECT_CALL(*mock_error_delegate,
+    //             OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+
+    raw_intercepting_pref_filter_->ReleasePrefs();
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+    EXPECT_TRUE(pref_store->IsInitializationComplete());
+    EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
+  }
+
+  pref_store->RemoveObserver(&mock_observer);
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, AlternateFile) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("alternate.json")));
+
+  // Test that the alternate file is moved to the main file and read as-is from
+  // there.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("write.json")));
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("invalid.json"),
+                     temp_dir_.path().AppendASCII("alternate.json")));
+
+  // Test that the alternate file is ignored and that the read occurs from the
+  // existing main file. There is no attempt at even deleting the alternate
+  // file as this scenario should never happen in normal user-data-dirs.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the basic read works fine when an alternate file is specified but
+  // does not exist.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("alternate.json")));
+
+  // Test that the alternate file is moved to the main file and read as-is from
+  // there even when the read is made asynchronously.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+
+  {
+    MockPrefStoreObserver mock_observer;
+    pref_store->AddObserver(&mock_observer);
+
+    MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    EXPECT_CALL(*mock_error_delegate,
+                OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    RunLoop().RunUntilIdle();
+    pref_store->RemoveObserver(&mock_observer);
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_TRUE(pref_store->IsInitializationComplete());
+  }
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(1));
+  ASSERT_EQ(1, samples->TotalCount());
+
+  ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
+            histogram.GetHistogram()->histogram_name());
+  ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // Nothing should be recorded until the report period has elapsed.
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(0, samples->TotalCount());
+
+  SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // Now the report period has elapsed.
+  samples = histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(1, samples->TotalCount());
+
+  // The last write won't be recorded because the second count period hasn't
+  // fully elapsed.
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+
+  samples = histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // The last write won't be recorded because the second count period hasn't
+  // fully elapsed
+  SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(2, samples->GetCount(3));
+  ASSERT_EQ(1, samples->GetCount(2));
+  ASSERT_EQ(3, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  // 1 write in the first period.
+  histogram.RecordWriteOccured();
+
+  // No writes in the second and third periods.
+
+  // 2 writes in the fourth period.
+  SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // No writes in the fifth period.
+
+  // 3 writes in the sixth period.
+  SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(3, samples->GetCount(0));
+  ASSERT_EQ(1, samples->GetCount(1));
+  ASSERT_EQ(1, samples->GetCount(2));
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(6, samples->TotalCount());
+}
+
+}  // namespace base
diff --git a/base/prefs/mock_pref_change_callback.cc b/base/prefs/mock_pref_change_callback.cc
new file mode 100644
index 0000000..96b7197
--- /dev/null
+++ b/base/prefs/mock_pref_change_callback.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/mock_pref_change_callback.h"
+
+#include "base/bind.h"
+
+MockPrefChangeCallback::MockPrefChangeCallback(PrefService* prefs)
+    : prefs_(prefs) {
+}
+
+MockPrefChangeCallback::~MockPrefChangeCallback() {}
+
+PrefChangeRegistrar::NamedChangeCallback MockPrefChangeCallback::GetCallback() {
+  return base::Bind(&MockPrefChangeCallback::OnPreferenceChanged,
+                    base::Unretained(this));
+}
+
+void MockPrefChangeCallback::Expect(const std::string& pref_name,
+                                    const base::Value* value) {
+  EXPECT_CALL(*this, OnPreferenceChanged(pref_name))
+      .With(PrefValueMatches(prefs_, pref_name, value));
+}
diff --git a/base/prefs/mock_pref_change_callback.h b/base/prefs/mock_pref_change_callback.h
new file mode 100644
index 0000000..3030fab
--- /dev/null
+++ b/base/prefs/mock_pref_change_callback.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_
+#define BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_
+
+#include <string>
+
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::Pointee;
+using testing::Property;
+using testing::Truly;
+
+// Matcher that checks whether the current value of the preference named
+// |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher
+// checks that the value is not set.
+MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") {
+  const PrefService::Preference* pref = prefs->FindPreference(pref_name);
+  if (!pref)
+    return false;
+
+  const base::Value* actual_value = pref->GetValue();
+  if (!actual_value)
+    return value == NULL;
+  if (!value)
+    return actual_value == NULL;
+  return value->Equals(actual_value);
+}
+
+// A mock for testing preference notifications and easy setup of expectations.
+class MockPrefChangeCallback {
+ public:
+  explicit MockPrefChangeCallback(PrefService* prefs);
+  virtual ~MockPrefChangeCallback();
+
+  PrefChangeRegistrar::NamedChangeCallback GetCallback();
+
+  MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+
+  void Expect(const std::string& pref_name,
+              const base::Value* value);
+
+ private:
+  PrefService* prefs_;
+};
+
+#endif  // BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_
diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc
new file mode 100644
index 0000000..e93dffd
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/overlay_user_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+OverlayUserPrefStore::OverlayUserPrefStore(
+    PersistentPrefStore* underlay)
+    : underlay_(underlay) {
+  underlay_->AddObserver(this);
+}
+
+bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
+  return overlay_.GetValue(key, NULL);
+}
+
+void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool OverlayUserPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+bool OverlayUserPrefStore::IsInitializationComplete() const {
+  return underlay_->IsInitializationComplete();
+}
+
+bool OverlayUserPrefStore::GetValue(const std::string& key,
+                                    const base::Value** result) const {
+  // If the |key| shall NOT be stored in the overlay store, there must not
+  // be an entry.
+  DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL));
+
+  if (overlay_.GetValue(key, result))
+    return true;
+  return underlay_->GetValue(GetUnderlayKey(key), result);
+}
+
+bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
+                                           base::Value** result) {
+  if (!ShallBeStoredInOverlay(key))
+    return underlay_->GetMutableValue(GetUnderlayKey(key), result);
+
+  if (overlay_.GetValue(key, result))
+    return true;
+
+  // Try to create copy of underlay if the overlay does not contain a value.
+  base::Value* underlay_value = NULL;
+  if (!underlay_->GetMutableValue(GetUnderlayKey(key), &underlay_value))
+    return false;
+
+  *result = underlay_value->DeepCopy();
+  overlay_.SetValue(key, *result);
+  return true;
+}
+
+void OverlayUserPrefStore::SetValue(const std::string& key,
+                                    base::Value* value,
+                                    uint32 flags) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->SetValue(GetUnderlayKey(key), value, flags);
+    return;
+  }
+
+  if (overlay_.SetValue(key, value))
+    ReportValueChanged(key, flags);
+}
+
+void OverlayUserPrefStore::SetValueSilently(const std::string& key,
+                                            base::Value* value,
+                                            uint32 flags) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->SetValueSilently(GetUnderlayKey(key), value, flags);
+    return;
+  }
+
+  overlay_.SetValue(key, value);
+}
+
+void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->RemoveValue(GetUnderlayKey(key), flags);
+    return;
+  }
+
+  if (overlay_.RemoveValue(key))
+    ReportValueChanged(key, flags);
+}
+
+bool OverlayUserPrefStore::ReadOnly() const {
+  return false;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const {
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
+  // We do not read intentionally.
+  OnInitializationCompleted(true);
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+void OverlayUserPrefStore::ReadPrefsAsync(
+    ReadErrorDelegate* error_delegate_raw) {
+  scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
+  // We do not read intentionally.
+  OnInitializationCompleted(true);
+}
+
+void OverlayUserPrefStore::CommitPendingWrite() {
+  underlay_->CommitPendingWrite();
+  // We do not write our content intentionally.
+}
+
+void OverlayUserPrefStore::ReportValueChanged(const std::string& key,
+                                              uint32 flags) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+}
+
+void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
+  if (!overlay_.GetValue(GetOverlayKey(key), NULL))
+    ReportValueChanged(GetOverlayKey(key), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
+                    OnInitializationCompleted(succeeded));
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) {
+  RegisterOverlayPref(key, key);
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(
+    const std::string& overlay_key,
+    const std::string& underlay_key) {
+  DCHECK(!overlay_key.empty()) << "Overlay key is empty";
+  DCHECK(overlay_to_underlay_names_map_.find(overlay_key) ==
+         overlay_to_underlay_names_map_.end()) <<
+      "Overlay key already registered";
+  DCHECK(!underlay_key.empty()) << "Underlay key is empty";
+  DCHECK(underlay_to_overlay_names_map_.find(underlay_key) ==
+         underlay_to_overlay_names_map_.end()) <<
+      "Underlay key already registered";
+  overlay_to_underlay_names_map_[overlay_key] = underlay_key;
+  underlay_to_overlay_names_map_[underlay_key] = overlay_key;
+}
+
+OverlayUserPrefStore::~OverlayUserPrefStore() {
+  underlay_->RemoveObserver(this);
+}
+
+const std::string& OverlayUserPrefStore::GetOverlayKey(
+    const std::string& underlay_key) const {
+  NamesMap::const_iterator i =
+      underlay_to_overlay_names_map_.find(underlay_key);
+  return i != underlay_to_overlay_names_map_.end() ? i->second : underlay_key;
+}
+
+const std::string& OverlayUserPrefStore::GetUnderlayKey(
+    const std::string& overlay_key) const {
+  NamesMap::const_iterator i =
+      overlay_to_underlay_names_map_.find(overlay_key);
+  return i != overlay_to_underlay_names_map_.end() ? i->second : overlay_key;
+}
+
+bool OverlayUserPrefStore::ShallBeStoredInOverlay(
+    const std::string& key) const {
+  return overlay_to_underlay_names_map_.find(key) !=
+      overlay_to_underlay_names_map_.end();
+}
diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h
new file mode 100644
index 0000000..04c309d
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+#define BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// PersistentPrefStore that directs all write operations into an in-memory
+// PrefValueMap. Read operations are first answered by the PrefValueMap.
+// If the PrefValueMap does not contain a value for the requested key,
+// the look-up is passed on to an underlying PersistentPrefStore |underlay_|.
+class BASE_PREFS_EXPORT OverlayUserPrefStore : public PersistentPrefStore,
+                                               public PrefStore::Observer {
+ public:
+  explicit OverlayUserPrefStore(PersistentPrefStore* underlay);
+
+  // Returns true if a value has been set for the |key| in this
+  // OverlayUserPrefStore, i.e. if it potentially overrides a value
+  // from the |underlay_|.
+  virtual bool IsSetInOverlay(const std::string& key) const;
+
+  // Methods of PrefStore.
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+
+  // Methods of PersistentPrefStore.
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* delegate) override;
+  void CommitPendingWrite() override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+
+  // Methods of PrefStore::Observer.
+  void OnPrefValueChanged(const std::string& key) override;
+  void OnInitializationCompleted(bool succeeded) override;
+
+  void RegisterOverlayPref(const std::string& key);
+  void RegisterOverlayPref(const std::string& overlay_key,
+                           const std::string& underlay_key);
+
+ protected:
+  ~OverlayUserPrefStore() override;
+
+ private:
+  typedef std::map<std::string, std::string> NamesMap;
+
+  const std::string& GetOverlayKey(const std::string& underlay_key) const;
+  const std::string& GetUnderlayKey(const std::string& overlay_key) const;
+
+  // Returns true if |key| corresponds to a preference that shall be stored in
+  // an in-memory PrefStore that is not persisted to disk.
+  bool ShallBeStoredInOverlay(const std::string& key) const;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+  PrefValueMap overlay_;
+  scoped_refptr<PersistentPrefStore> underlay_;
+  NamesMap overlay_to_underlay_names_map_;
+  NamesMap underlay_to_overlay_names_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(OverlayUserPrefStore);
+};
+
+#endif  // BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc
new file mode 100644
index 0000000..06b4ec9
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store_unittest.cc
@@ -0,0 +1,283 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/overlay_user_pref_store.h"
+
+#include "base/prefs/pref_store_observer_mock.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::StrEq;
+
+namespace base {
+namespace {
+
+const char kBrowserWindowPlacement[] = "browser.window_placement";
+const char kShowBookmarkBar[] = "bookmark_bar.show_on_all_tabs";
+
+const char* const overlay_key = kBrowserWindowPlacement;
+const char* const regular_key = kShowBookmarkBar;
+// With the removal of the kWebKitGlobalXXX prefs, we'll no longer have real
+// prefs using the overlay pref store, so make up keys here.
+const char mapped_overlay_key[] = "test.per_tab.javascript_enabled";
+const char mapped_underlay_key[] = "test.per_profile.javascript_enabled";
+
+}  // namespace
+
+class OverlayUserPrefStoreTest : public testing::Test {
+ protected:
+  OverlayUserPrefStoreTest()
+      : underlay_(new TestingPrefStore()),
+        overlay_(new OverlayUserPrefStore(underlay_.get())) {
+    overlay_->RegisterOverlayPref(overlay_key);
+    overlay_->RegisterOverlayPref(mapped_overlay_key, mapped_underlay_key);
+  }
+
+  ~OverlayUserPrefStoreTest() override {}
+
+  scoped_refptr<TestingPrefStore> underlay_;
+  scoped_refptr<OverlayUserPrefStore> overlay_;
+};
+
+TEST_F(OverlayUserPrefStoreTest, Observer) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  // Check that underlay first value is reported.
+  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that underlay overwriting is reported.
+  underlay_->SetValue(overlay_key, new FundamentalValue(43),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that overwriting change in overlay is reported.
+  overlay_->SetValue(overlay_key, new FundamentalValue(44),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that hidden underlay change is not reported.
+  underlay_->SetValue(overlay_key, new FundamentalValue(45),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  // Check that overlay remove is reported.
+  overlay_->RemoveValue(overlay_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that underlay remove is reported.
+  underlay_->RemoveValue(overlay_key,
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check respecting of silence.
+  overlay_->SetValueSilently(overlay_key, new FundamentalValue(46),
+                             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  underlay_->SetValue(overlay_key, new FundamentalValue(47),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  overlay_->SetValue(overlay_key, new FundamentalValue(48),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+}
+
+TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
+  const Value* value = NULL;
+  EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
+
+  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  // Value shines through:
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  overlay_->SetValue(overlay_key, new FundamentalValue(43),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  overlay_->RemoveValue(overlay_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  // Value shines through:
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+}
+
+// Check that GetMutableValue does not return the dictionary of the underlay.
+TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
+  underlay_->SetValue(overlay_key, new DictionaryValue,
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  Value* modify = NULL;
+  EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modify));
+  ASSERT_TRUE(modify);
+  ASSERT_TRUE(modify->IsType(Value::TYPE_DICTIONARY));
+  static_cast<DictionaryValue*>(modify)->SetInteger(overlay_key, 42);
+
+  Value* original_in_underlay = NULL;
+  EXPECT_TRUE(underlay_->GetMutableValue(overlay_key, &original_in_underlay));
+  ASSERT_TRUE(original_in_underlay);
+  ASSERT_TRUE(original_in_underlay->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(static_cast<DictionaryValue*>(original_in_underlay)->empty());
+
+  Value* modified = NULL;
+  EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modified));
+  ASSERT_TRUE(modified);
+  ASSERT_TRUE(modified->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(Value::Equals(modify, static_cast<DictionaryValue*>(modified)));
+}
+
+// Here we consider a global preference that is not overlayed.
+TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  const Value* value = NULL;
+
+  // Check that underlay first value is reported.
+  underlay_->SetValue(regular_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that underlay overwriting is reported.
+  underlay_->SetValue(regular_key, new FundamentalValue(43),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that we get this value from the overlay
+  EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that overwriting change in overlay is reported.
+  overlay_->SetValue(regular_key, new FundamentalValue(44),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that we get this value from the overlay and the underlay.
+  EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+  EXPECT_TRUE(underlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+
+  // Check that overlay remove is reported.
+  overlay_->RemoveValue(regular_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that value was removed from overlay and underlay
+  EXPECT_FALSE(overlay_->GetValue(regular_key, &value));
+  EXPECT_FALSE(underlay_->GetValue(regular_key, &value));
+
+  // Check respecting of silence.
+  overlay_->SetValueSilently(regular_key, new FundamentalValue(46),
+                             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  underlay_->SetValue(regular_key, new FundamentalValue(47),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  overlay_->SetValue(regular_key, new FundamentalValue(48),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+}
+
+// Check that names mapping works correctly.
+TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  const Value* value = NULL;
+
+  // Check that if there is no override in the overlay, changing underlay value
+  // is reported as changing an overlay value.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that underlay overwriting is reported.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(43),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that we get this value from the overlay with both keys
+  EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+  // In this case, overlay reads directly from the underlay.
+  EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that overwriting change in overlay is reported.
+  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that we get an overriden value from overlay, while reading the
+  // value from underlay still holds an old value.
+  EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+  EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+  EXPECT_TRUE(underlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that hidden underlay change is not reported.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  // Check that overlay remove is reported.
+  overlay_->RemoveValue(mapped_overlay_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that underlay remove is reported.
+  underlay_->RemoveValue(mapped_underlay_key,
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that value was removed.
+  EXPECT_FALSE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value));
+
+  // Check respecting of silence.
+  overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46),
+                             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(47),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+}
+
+}  // namespace base
diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h
new file mode 100644
index 0000000..e70e2a6
--- /dev/null
+++ b/base/prefs/persistent_pref_store.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_PREFS_PERSISTENT_PREF_STORE_H_
+#define BASE_PREFS_PERSISTENT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/writeable_pref_store.h"
+
+// This interface is complementary to the PrefStore interface, declaring
+// additional functionality that adds support for setting values and persisting
+// the data to some backing store.
+class BASE_PREFS_EXPORT PersistentPrefStore : public WriteablePrefStore {
+ public:
+  // Unique integer code for each type of error so we can report them
+  // distinctly in a histogram.
+  // NOTE: Don't change the explicit values of the enums as it will change the
+  // server's meaning of the histogram.
+  enum PrefReadError {
+    PREF_READ_ERROR_NONE = 0,
+    PREF_READ_ERROR_JSON_PARSE = 1,
+    PREF_READ_ERROR_JSON_TYPE = 2,
+    PREF_READ_ERROR_ACCESS_DENIED = 3,
+    PREF_READ_ERROR_FILE_OTHER = 4,
+    PREF_READ_ERROR_FILE_LOCKED = 5,
+    PREF_READ_ERROR_NO_FILE = 6,
+    PREF_READ_ERROR_JSON_REPEAT = 7,
+    // PREF_READ_ERROR_OTHER = 8,  // Deprecated.
+    PREF_READ_ERROR_FILE_NOT_SPECIFIED = 9,
+    // Indicates that ReadPrefs() couldn't complete synchronously and is waiting
+    // for an asynchronous task to complete first.
+    PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE = 10,
+    PREF_READ_ERROR_LEVELDB_IO = 11,
+    PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY = 12,
+    PREF_READ_ERROR_LEVELDB_CORRUPTION = 13,
+    PREF_READ_ERROR_MAX_ENUM
+  };
+
+  class ReadErrorDelegate {
+   public:
+    virtual ~ReadErrorDelegate() {}
+
+    virtual void OnError(PrefReadError error) = 0;
+  };
+
+  // Whether the store is in a pseudo-read-only mode where changes are not
+  // actually persisted to disk.  This happens in some cases when there are
+  // read errors during startup.
+  virtual bool ReadOnly() const = 0;
+
+  // Gets the read error. Only valid if IsInitializationComplete() returns true.
+  virtual PrefReadError GetReadError() const = 0;
+
+  // Reads the preferences from disk. Notifies observers via
+  // "PrefStore::OnInitializationCompleted" when done.
+  virtual PrefReadError ReadPrefs() = 0;
+
+  // Reads the preferences from disk asynchronously. Notifies observers via
+  // "PrefStore::OnInitializationCompleted" when done. Also it fires
+  // |error_delegate| if it is not NULL and reading error has occurred.
+  // Owns |error_delegate|.
+  virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0;
+
+  // Lands any pending writes to disk.
+  virtual void CommitPendingWrite() = 0;
+
+ protected:
+  ~PersistentPrefStore() override {}
+};
+
+#endif  // BASE_PREFS_PERSISTENT_PREF_STORE_H_
diff --git a/base/prefs/pref_change_registrar.cc b/base/prefs/pref_change_registrar.cc
new file mode 100644
index 0000000..1319348
--- /dev/null
+++ b/base/prefs/pref_change_registrar.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_change_registrar.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+
+PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {}
+
+PrefChangeRegistrar::~PrefChangeRegistrar() {
+  // If you see an invalid memory access in this destructor, this
+  // PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that
+  // has been destroyed. This should not happen any more but be warned.
+  // Feel free to contact battre@chromium.org in case this happens.
+  RemoveAll();
+}
+
+void PrefChangeRegistrar::Init(PrefService* service) {
+  DCHECK(IsEmpty() || service_ == service);
+  service_ = service;
+}
+
+void PrefChangeRegistrar::Add(const std::string& path,
+                              const base::Closure& obs) {
+  Add(path, base::Bind(&PrefChangeRegistrar::InvokeUnnamedCallback, obs));
+}
+
+void PrefChangeRegistrar::Add(const std::string& path,
+                              const NamedChangeCallback& obs) {
+  if (!service_) {
+    NOTREACHED();
+    return;
+  }
+  DCHECK(!IsObserved(path)) << "Already had this pref registered.";
+
+  service_->AddPrefObserver(path, this);
+  observers_[path] = obs;
+}
+
+void PrefChangeRegistrar::Remove(const std::string& path) {
+  DCHECK(IsObserved(path));
+
+  observers_.erase(path);
+  service_->RemovePrefObserver(path, this);
+}
+
+void PrefChangeRegistrar::RemoveAll() {
+  for (ObserverMap::const_iterator it = observers_.begin();
+       it != observers_.end(); ++it) {
+    service_->RemovePrefObserver(it->first, this);
+  }
+
+  observers_.clear();
+}
+
+bool PrefChangeRegistrar::IsEmpty() const {
+  return observers_.empty();
+}
+
+bool PrefChangeRegistrar::IsObserved(const std::string& pref) {
+  return observers_.find(pref) != observers_.end();
+}
+
+bool PrefChangeRegistrar::IsManaged() {
+  for (ObserverMap::const_iterator it = observers_.begin();
+       it != observers_.end(); ++it) {
+    const PrefService::Preference* pref = service_->FindPreference(it->first);
+    if (pref && pref->IsManaged())
+      return true;
+  }
+  return false;
+}
+
+void PrefChangeRegistrar::OnPreferenceChanged(PrefService* service,
+                                              const std::string& pref) {
+  if (IsObserved(pref))
+    observers_[pref].Run(pref);
+}
+
+void PrefChangeRegistrar::InvokeUnnamedCallback(const base::Closure& callback,
+                                                const std::string& pref_name) {
+  callback.Run();
+}
+
+PrefService* PrefChangeRegistrar::prefs() {
+  return service_;
+}
+
+const PrefService* PrefChangeRegistrar::prefs() const {
+  return service_;
+}
diff --git a/base/prefs/pref_change_registrar.h b/base/prefs/pref_change_registrar.h
new file mode 100644
index 0000000..acf0a68
--- /dev/null
+++ b/base/prefs/pref_change_registrar.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_CHANGE_REGISTRAR_H_
+#define BASE_PREFS_PREF_CHANGE_REGISTRAR_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_observer.h"
+
+class PrefService;
+
+// Automatically manages the registration of one or more pref change observers
+// with a PrefStore. Functions much like NotificationRegistrar, but specifically
+// manages observers of preference changes. When the Registrar is destroyed,
+// all registered observers are automatically unregistered with the PrefStore.
+class BASE_PREFS_EXPORT PrefChangeRegistrar : public PrefObserver {
+ public:
+  // You can register this type of callback if you need to know the
+  // path of the preference that is changing.
+  typedef base::Callback<void(const std::string&)> NamedChangeCallback;
+
+  PrefChangeRegistrar();
+  virtual ~PrefChangeRegistrar();
+
+  // Must be called before adding or removing observers. Can be called more
+  // than once as long as the value of |service| doesn't change.
+  void Init(PrefService* service);
+
+  // Adds a pref observer for the specified pref |path| and |obs| observer
+  // object. All registered observers will be automatically unregistered
+  // when the registrar's destructor is called.
+  //
+  // The second version binds a callback that will receive the path of
+  // the preference that is changing as its parameter.
+  //
+  // Only one observer may be registered per path.
+  void Add(const std::string& path, const base::Closure& obs);
+  void Add(const std::string& path, const NamedChangeCallback& obs);
+
+  // Removes the pref observer registered for |path|.
+  void Remove(const std::string& path);
+
+  // Removes all observers that have been previously added with a call to Add.
+  void RemoveAll();
+
+  // Returns true if no pref observers are registered.
+  bool IsEmpty() const;
+
+  // Check whether |pref| is in the set of preferences being observed.
+  bool IsObserved(const std::string& pref);
+
+  // Check whether any of the observed preferences has the managed bit set.
+  bool IsManaged();
+
+  // Return the PrefService for this registrar.
+  PrefService* prefs();
+  const PrefService* prefs() const;
+
+ private:
+  // PrefObserver:
+  void OnPreferenceChanged(PrefService* service,
+                           const std::string& pref_name) override;
+
+  static void InvokeUnnamedCallback(const base::Closure& callback,
+                                    const std::string& pref_name);
+
+  typedef std::map<std::string, NamedChangeCallback> ObserverMap;
+
+  ObserverMap observers_;
+  PrefService* service_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefChangeRegistrar);
+};
+
+#endif  // BASE_PREFS_PREF_CHANGE_REGISTRAR_H_
diff --git a/base/prefs/pref_change_registrar_unittest.cc b/base/prefs/pref_change_registrar_unittest.cc
new file mode 100644
index 0000000..da425cf
--- /dev/null
+++ b/base/prefs/pref_change_registrar_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_observer.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::Eq;
+
+namespace base {
+namespace {
+
+const char kHomePage[] = "homepage";
+const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage";
+const char kApplicationLocale[] = "intl.app_locale";
+
+// A mock provider that allows us to capture pref observer changes.
+class MockPrefService : public TestingPrefServiceSimple {
+ public:
+  MockPrefService() {}
+  virtual ~MockPrefService() {}
+
+  MOCK_METHOD2(AddPrefObserver, void(const std::string&, PrefObserver*));
+  MOCK_METHOD2(RemovePrefObserver, void(const std::string&, PrefObserver*));
+};
+
+}  // namespace
+
+class PrefChangeRegistrarTest : public testing::Test {
+ public:
+  PrefChangeRegistrarTest() {}
+  ~PrefChangeRegistrarTest() override {}
+
+ protected:
+  void SetUp() override;
+
+  base::Closure observer() const {
+    return base::Bind(&base::DoNothing);
+  }
+
+  MockPrefService* service() const { return service_.get(); }
+
+ private:
+  scoped_ptr<MockPrefService> service_;
+};
+
+void PrefChangeRegistrarTest::SetUp() {
+  service_.reset(new MockPrefService());
+}
+
+TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  // Test adding.
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.Add("test.pref.1", observer());
+  registrar.Add("test.pref.2", observer());
+  EXPECT_FALSE(registrar.IsEmpty());
+
+  // Test removing.
+  Mock::VerifyAndClearExpectations(service());
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.Remove("test.pref.1");
+  registrar.Remove("test.pref.2");
+  EXPECT_TRUE(registrar.IsEmpty());
+
+  // Explicitly check the expectations now to make sure that the Removes
+  // worked (rather than the registrar destructor doing the work).
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(PrefChangeRegistrarTest, AutoRemove) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  // Setup of auto-remove.
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  registrar.Add("test.pref.1", observer());
+  Mock::VerifyAndClearExpectations(service());
+  EXPECT_FALSE(registrar.IsEmpty());
+
+  // Test auto-removing.
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), &registrar));
+}
+
+TEST_F(PrefChangeRegistrarTest, RemoveAll) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.Add("test.pref.1", observer());
+  registrar.Add("test.pref.2", observer());
+  Mock::VerifyAndClearExpectations(service());
+
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.RemoveAll();
+  EXPECT_TRUE(registrar.IsEmpty());
+
+  // Explicitly check the expectations now to make sure that the RemoveAll
+  // worked (rather than the registrar destructor doing the work).
+  Mock::VerifyAndClearExpectations(service());
+}
+
+class ObserveSetOfPreferencesTest : public testing::Test {
+ public:
+  virtual void SetUp() {
+    pref_service_.reset(new TestingPrefServiceSimple);
+    PrefRegistrySimple* registry = pref_service_->registry();
+    registry->RegisterStringPref(kHomePage, "http://google.com");
+    registry->RegisterBooleanPref(kHomePageIsNewTabPage, false);
+    registry->RegisterStringPref(kApplicationLocale, std::string());
+  }
+
+  PrefChangeRegistrar* CreatePrefChangeRegistrar() {
+    PrefChangeRegistrar* pref_set = new PrefChangeRegistrar();
+    base::Closure callback = base::Bind(&base::DoNothing);
+    pref_set->Init(pref_service_.get());
+    pref_set->Add(kHomePage, callback);
+    pref_set->Add(kHomePageIsNewTabPage, callback);
+    return pref_set;
+  }
+
+  MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+
+  scoped_ptr<TestingPrefServiceSimple> pref_service_;
+};
+
+TEST_F(ObserveSetOfPreferencesTest, IsObserved) {
+  scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar());
+  EXPECT_TRUE(pref_set->IsObserved(kHomePage));
+  EXPECT_TRUE(pref_set->IsObserved(kHomePageIsNewTabPage));
+  EXPECT_FALSE(pref_set->IsObserved(kApplicationLocale));
+}
+
+TEST_F(ObserveSetOfPreferencesTest, IsManaged) {
+  scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar());
+  EXPECT_FALSE(pref_set->IsManaged());
+  pref_service_->SetManagedPref(kHomePage,
+                                new StringValue("http://crbug.com"));
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->SetManagedPref(kHomePageIsNewTabPage,
+                                new FundamentalValue(true));
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->RemoveManagedPref(kHomePage);
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->RemoveManagedPref(kHomePageIsNewTabPage);
+  EXPECT_FALSE(pref_set->IsManaged());
+}
+
+TEST_F(ObserveSetOfPreferencesTest, Observe) {
+  using testing::_;
+  using testing::Mock;
+
+  PrefChangeRegistrar pref_set;
+  PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
+      &ObserveSetOfPreferencesTest::OnPreferenceChanged,
+      base::Unretained(this));
+  pref_set.Init(pref_service_.get());
+  pref_set.Add(kHomePage, callback);
+  pref_set.Add(kHomePageIsNewTabPage, callback);
+
+  EXPECT_CALL(*this, OnPreferenceChanged(kHomePage));
+  pref_service_->SetUserPref(kHomePage, new StringValue("http://crbug.com"));
+  Mock::VerifyAndClearExpectations(this);
+
+  EXPECT_CALL(*this, OnPreferenceChanged(kHomePageIsNewTabPage));
+  pref_service_->SetUserPref(kHomePageIsNewTabPage,
+                             new FundamentalValue(true));
+  Mock::VerifyAndClearExpectations(this);
+
+  EXPECT_CALL(*this, OnPreferenceChanged(_)).Times(0);
+  pref_service_->SetUserPref(kApplicationLocale, new StringValue("en_US.utf8"));
+  Mock::VerifyAndClearExpectations(this);
+}
+
+}  // namespace base
diff --git a/base/prefs/pref_filter.h b/base/prefs/pref_filter.h
new file mode 100644
index 0000000..82a44c6
--- /dev/null
+++ b/base/prefs/pref_filter.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_FILTER_H_
+#define BASE_PREFS_PREF_FILTER_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+}  // namespace base
+
+// Filters preferences as they are loaded from disk or updated at runtime.
+// Currently supported only by JsonPrefStore.
+class BASE_PREFS_EXPORT PrefFilter {
+ public:
+  // A callback to be invoked when |prefs| have been read (and possibly
+  // pre-modified) and are now ready to be handed back to this callback's
+  // builder. |schedule_write| indicates whether a write should be immediately
+  // scheduled (typically because the |prefs| were pre-modified).
+  typedef base::Callback<void(scoped_ptr<base::DictionaryValue> prefs,
+                              bool schedule_write)> PostFilterOnLoadCallback;
+
+  virtual ~PrefFilter() {}
+
+  // This method is given ownership of the |pref_store_contents| read from disk
+  // before the underlying PersistentPrefStore gets to use them. It must hand
+  // them back via |post_filter_on_load_callback|, but may modify them first.
+  // Note: This method is asynchronous, which may make calls like
+  // PersistentPrefStore::ReadPrefs() asynchronous. The owner of filtered
+  // PersistentPrefStores should handle this to make the reads look synchronous
+  // to external users (see SegregatedPrefStore::ReadPrefs() for an example).
+  virtual void FilterOnLoad(
+      const PostFilterOnLoadCallback& post_filter_on_load_callback,
+      scoped_ptr<base::DictionaryValue> pref_store_contents) = 0;
+
+  // Receives notification when a pref store value is changed, before Observers
+  // are notified.
+  virtual void FilterUpdate(const std::string& path) = 0;
+
+  // Receives notification when the pref store is about to serialize data
+  // contained in |pref_store_contents| to a string. Modifications to
+  // |pref_store_contents| will be persisted to disk and also affect the
+  // in-memory state.
+  virtual void FilterSerializeData(
+      base::DictionaryValue* pref_store_contents) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_FILTER_H_
diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc
new file mode 100644
index 0000000..64c3d6a
--- /dev/null
+++ b/base/prefs/pref_member.cc
@@ -0,0 +1,221 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_member.h"
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/prefs/pref_service.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/value_conversions.h"
+
+using base::SingleThreadTaskRunner;
+
+namespace subtle {
+
+PrefMemberBase::PrefMemberBase()
+    : prefs_(NULL),
+      setting_value_(false) {
+}
+
+PrefMemberBase::~PrefMemberBase() {
+  Destroy();
+}
+
+void PrefMemberBase::Init(const std::string& pref_name,
+                          PrefService* prefs,
+                          const NamedChangeCallback& observer) {
+  observer_ = observer;
+  Init(pref_name, prefs);
+}
+
+void PrefMemberBase::Init(const std::string& pref_name, PrefService* prefs) {
+  DCHECK(prefs);
+  DCHECK(pref_name_.empty());  // Check that Init is only called once.
+  prefs_ = prefs;
+  pref_name_ = pref_name;
+  // Check that the preference is registered.
+  DCHECK(prefs_->FindPreference(pref_name_)) << pref_name << " not registered.";
+
+  // Add ourselves as a pref observer so we can keep our local value in sync.
+  prefs_->AddPrefObserver(pref_name, this);
+}
+
+void PrefMemberBase::Destroy() {
+  if (prefs_ && !pref_name_.empty()) {
+    prefs_->RemovePrefObserver(pref_name_, this);
+    prefs_ = NULL;
+  }
+}
+
+void PrefMemberBase::MoveToThread(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  VerifyValuePrefName();
+  // Load the value from preferences if it hasn't been loaded so far.
+  if (!internal())
+    UpdateValueFromPref(base::Closure());
+  internal()->MoveToThread(task_runner.Pass());
+}
+
+void PrefMemberBase::OnPreferenceChanged(PrefService* service,
+                                         const std::string& pref_name) {
+  VerifyValuePrefName();
+  UpdateValueFromPref((!setting_value_ && !observer_.is_null()) ?
+      base::Bind(observer_, pref_name) : base::Closure());
+}
+
+void PrefMemberBase::UpdateValueFromPref(const base::Closure& callback) const {
+  VerifyValuePrefName();
+  const PrefService::Preference* pref = prefs_->FindPreference(pref_name_);
+  DCHECK(pref);
+  if (!internal())
+    CreateInternal();
+  internal()->UpdateValue(pref->GetValue()->DeepCopy(),
+                          pref->IsManaged(),
+                          pref->IsUserModifiable(),
+                          callback);
+}
+
+void PrefMemberBase::VerifyPref() const {
+  VerifyValuePrefName();
+  if (!internal())
+    UpdateValueFromPref(base::Closure());
+}
+
+void PrefMemberBase::InvokeUnnamedCallback(const base::Closure& callback,
+                                           const std::string& pref_name) {
+  callback.Run();
+}
+
+PrefMemberBase::Internal::Internal()
+    : thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      is_managed_(false),
+      is_user_modifiable_(false) {
+}
+PrefMemberBase::Internal::~Internal() { }
+
+bool PrefMemberBase::Internal::IsOnCorrectThread() const {
+  return thread_task_runner_->BelongsToCurrentThread();
+}
+
+void PrefMemberBase::Internal::UpdateValue(
+    base::Value* v,
+    bool is_managed,
+    bool is_user_modifiable,
+    const base::Closure& callback) const {
+  scoped_ptr<base::Value> value(v);
+  base::ScopedClosureRunner closure_runner(callback);
+  if (IsOnCorrectThread()) {
+    bool rv = UpdateValueInternal(*value);
+    DCHECK(rv);
+    is_managed_ = is_managed;
+    is_user_modifiable_ = is_user_modifiable;
+  } else {
+    bool may_run = thread_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
+                              value.release(), is_managed, is_user_modifiable,
+                              closure_runner.Release()));
+    DCHECK(may_run);
+  }
+}
+
+void PrefMemberBase::Internal::MoveToThread(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  CheckOnCorrectThread();
+  thread_task_runner_ = task_runner.Pass();
+}
+
+bool PrefMemberVectorStringUpdate(const base::Value& value,
+                                  std::vector<std::string>* string_vector) {
+  if (!value.IsType(base::Value::TYPE_LIST))
+    return false;
+  const base::ListValue* list = static_cast<const base::ListValue*>(&value);
+
+  std::vector<std::string> local_vector;
+  for (base::ListValue::const_iterator it = list->begin();
+       it != list->end(); ++it) {
+    std::string string_value;
+    if (!(*it)->GetAsString(&string_value))
+      return false;
+
+    local_vector.push_back(string_value);
+  }
+
+  string_vector->swap(local_vector);
+  return true;
+}
+
+}  // namespace subtle
+
+template <>
+void PrefMember<bool>::UpdatePref(const bool& value) {
+  prefs()->SetBoolean(pref_name(), value);
+}
+
+template <>
+bool PrefMember<bool>::Internal::UpdateValueInternal(
+    const base::Value& value) const {
+  return value.GetAsBoolean(&value_);
+}
+
+template <>
+void PrefMember<int>::UpdatePref(const int& value) {
+  prefs()->SetInteger(pref_name(), value);
+}
+
+template <>
+bool PrefMember<int>::Internal::UpdateValueInternal(
+    const base::Value& value) const {
+  return value.GetAsInteger(&value_);
+}
+
+template <>
+void PrefMember<double>::UpdatePref(const double& value) {
+  prefs()->SetDouble(pref_name(), value);
+}
+
+template <>
+bool PrefMember<double>::Internal::UpdateValueInternal(const base::Value& value)
+    const {
+  return value.GetAsDouble(&value_);
+}
+
+template <>
+void PrefMember<std::string>::UpdatePref(const std::string& value) {
+  prefs()->SetString(pref_name(), value);
+}
+
+template <>
+bool PrefMember<std::string>::Internal::UpdateValueInternal(
+    const base::Value& value)
+    const {
+  return value.GetAsString(&value_);
+}
+
+template <>
+void PrefMember<base::FilePath>::UpdatePref(const base::FilePath& value) {
+  prefs()->SetFilePath(pref_name(), value);
+}
+
+template <>
+bool PrefMember<base::FilePath>::Internal::UpdateValueInternal(
+    const base::Value& value)
+    const {
+  return base::GetValueAsFilePath(value, &value_);
+}
+
+template <>
+void PrefMember<std::vector<std::string> >::UpdatePref(
+    const std::vector<std::string>& value) {
+  base::ListValue list_value;
+  list_value.AppendStrings(value);
+  prefs()->Set(pref_name(), list_value);
+}
+
+template <>
+bool PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal(
+    const base::Value& value) const {
+  return subtle::PrefMemberVectorStringUpdate(value, &value_);
+}
diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h
new file mode 100644
index 0000000..6dceb43
--- /dev/null
+++ b/base/prefs/pref_member.h
@@ -0,0 +1,355 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A helper class that stays in sync with a preference (bool, int, real,
+// string or filepath).  For example:
+//
+// class MyClass {
+//  public:
+//   MyClass(PrefService* prefs) {
+//     my_string_.Init(prefs::kHomePage, prefs);
+//   }
+//  private:
+//   StringPrefMember my_string_;
+// };
+//
+// my_string_ should stay in sync with the prefs::kHomePage pref and will
+// update if either the pref changes or if my_string_.SetValue is called.
+//
+// An optional observer can be passed into the Init method which can be used to
+// notify MyClass of changes. Note that if you use SetValue(), the observer
+// will not be notified.
+
+#ifndef BASE_PREFS_PREF_MEMBER_H_
+#define BASE_PREFS_PREF_MEMBER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_observer.h"
+#include "base/single_thread_task_runner.h"
+#include "base/values.h"
+
+class PrefService;
+
+namespace subtle {
+
+class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver {
+ public:
+  // Type of callback you can register if you need to know the name of
+  // the pref that is changing.
+  typedef base::Callback<void(const std::string&)> NamedChangeCallback;
+
+  PrefService* prefs() { return prefs_; }
+  const PrefService* prefs() const { return prefs_; }
+
+ protected:
+  class BASE_PREFS_EXPORT Internal
+      : public base::RefCountedThreadSafe<Internal> {
+   public:
+    Internal();
+
+    // Update the value, either by calling |UpdateValueInternal| directly
+    // or by dispatching to the right thread.
+    // Takes ownership of |value|.
+    void UpdateValue(base::Value* value,
+                     bool is_managed,
+                     bool is_user_modifiable,
+                     const base::Closure& callback) const;
+
+    void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+    // See PrefMember<> for description.
+    bool IsManaged() const {
+      return is_managed_;
+    }
+
+    bool IsUserModifiable() const {
+      return is_user_modifiable_;
+    }
+
+   protected:
+    friend class base::RefCountedThreadSafe<Internal>;
+    virtual ~Internal();
+
+    void CheckOnCorrectThread() const {
+      DCHECK(IsOnCorrectThread());
+    }
+
+   private:
+    // This method actually updates the value. It should only be called from
+    // the thread the PrefMember is on.
+    virtual bool UpdateValueInternal(const base::Value& value) const = 0;
+
+    bool IsOnCorrectThread() const;
+
+    scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
+    mutable bool is_managed_;
+    mutable bool is_user_modifiable_;
+
+    DISALLOW_COPY_AND_ASSIGN(Internal);
+  };
+
+  PrefMemberBase();
+  virtual ~PrefMemberBase();
+
+  // See PrefMember<> for description.
+  void Init(const std::string& pref_name,
+            PrefService* prefs,
+            const NamedChangeCallback& observer);
+  void Init(const std::string& pref_name, PrefService* prefs);
+
+  virtual void CreateInternal() const = 0;
+
+  // See PrefMember<> for description.
+  void Destroy();
+
+  void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+  // PrefObserver
+  void OnPreferenceChanged(PrefService* service,
+                           const std::string& pref_name) override;
+
+  void VerifyValuePrefName() const {
+    DCHECK(!pref_name_.empty());
+  }
+
+  // This method is used to do the actual sync with the preference.
+  // Note: it is logically const, because it doesn't modify the state
+  // seen by the outside world. It is just doing a lazy load behind the scenes.
+  void UpdateValueFromPref(const base::Closure& callback) const;
+
+  // Verifies the preference name, and lazily loads the preference value if
+  // it hasn't been loaded yet.
+  void VerifyPref() const;
+
+  const std::string& pref_name() const { return pref_name_; }
+
+  virtual Internal* internal() const = 0;
+
+  // Used to allow registering plain base::Closure callbacks.
+  static void InvokeUnnamedCallback(const base::Closure& callback,
+                                    const std::string& pref_name);
+
+ private:
+  // Ordered the members to compact the class instance.
+  std::string pref_name_;
+  NamedChangeCallback observer_;
+  PrefService* prefs_;
+
+ protected:
+  bool setting_value_;
+};
+
+// This function implements StringListPrefMember::UpdateValue().
+// It is exposed here for testing purposes.
+bool BASE_PREFS_EXPORT PrefMemberVectorStringUpdate(
+    const base::Value& value,
+    std::vector<std::string>* string_vector);
+
+}  // namespace subtle
+
+template <typename ValueType>
+class PrefMember : public subtle::PrefMemberBase {
+ public:
+  // Defer initialization to an Init method so it's easy to make this class be
+  // a member variable.
+  PrefMember() {}
+  virtual ~PrefMember() {}
+
+  // Do the actual initialization of the class.  Use the two-parameter
+  // version if you don't want any notifications of changes.  This
+  // method should only be called on the UI thread.
+  void Init(const std::string& pref_name,
+            PrefService* prefs,
+            const NamedChangeCallback& observer) {
+    subtle::PrefMemberBase::Init(pref_name, prefs, observer);
+  }
+  void Init(const std::string& pref_name,
+            PrefService* prefs,
+            const base::Closure& observer) {
+    subtle::PrefMemberBase::Init(
+        pref_name, prefs,
+        base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer));
+  }
+  void Init(const std::string& pref_name, PrefService* prefs) {
+    subtle::PrefMemberBase::Init(pref_name, prefs);
+  }
+
+  // Unsubscribes the PrefMember from the PrefService. After calling this
+  // function, the PrefMember may not be used any more on the UI thread.
+  // Assuming |MoveToThread| was previously called, |GetValue|, |IsManaged|,
+  // and |IsUserModifiable| can still be called from the other thread but
+  // the results will no longer update from the PrefService.
+  // This method should only be called on the UI thread.
+  void Destroy() {
+    subtle::PrefMemberBase::Destroy();
+  }
+
+  // Moves the PrefMember to another thread, allowing read accesses from there.
+  // Changes from the PrefService will be propagated asynchronously
+  // via PostTask.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread by default.
+  void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    subtle::PrefMemberBase::MoveToThread(task_runner);
+  }
+
+  // Check whether the pref is managed, i.e. controlled externally through
+  // enterprise configuration management (e.g. windows group policy). Returns
+  // false for unknown prefs.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread unless changed by |MoveToThread|.
+  bool IsManaged() const {
+    VerifyPref();
+    return internal_->IsManaged();
+  }
+
+  // Checks whether the pref can be modified by the user. This returns false
+  // when the pref is managed by a policy or an extension, and when a command
+  // line flag overrides the pref.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread unless changed by |MoveToThread|.
+  bool IsUserModifiable() const {
+    VerifyPref();
+    return internal_->IsUserModifiable();
+  }
+
+  // Retrieve the value of the member variable.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread unless changed by |MoveToThread|.
+  ValueType GetValue() const {
+    VerifyPref();
+    return internal_->value();
+  }
+
+  // Provided as a convenience.
+  ValueType operator*() const {
+    return GetValue();
+  }
+
+  // Set the value of the member variable.
+  // This method should only be called on the UI thread.
+  void SetValue(const ValueType& value) {
+    VerifyValuePrefName();
+    setting_value_ = true;
+    UpdatePref(value);
+    setting_value_ = false;
+  }
+
+  // Returns the pref name.
+  const std::string& GetPrefName() const {
+    return pref_name();
+  }
+
+ private:
+  class Internal : public subtle::PrefMemberBase::Internal {
+   public:
+    Internal() : value_(ValueType()) {}
+
+    ValueType value() {
+      CheckOnCorrectThread();
+      return value_;
+    }
+
+   protected:
+    ~Internal() override {}
+
+    BASE_PREFS_EXPORT bool UpdateValueInternal(
+        const base::Value& value) const override;
+
+    // We cache the value of the pref so we don't have to keep walking the pref
+    // tree.
+    mutable ValueType value_;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Internal);
+  };
+
+  Internal* internal() const override { return internal_.get(); }
+  void CreateInternal() const override { internal_ = new Internal(); }
+
+  // This method is used to do the actual sync with pref of the specified type.
+  void BASE_PREFS_EXPORT UpdatePref(const ValueType& value);
+
+  mutable scoped_refptr<Internal> internal_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefMember);
+};
+
+// Declaration of template specialization need to be repeated here
+// specifically for each specialization (rather than just once above)
+// or at least one of our compilers won't be happy in all cases.
+// Specifically, it was failing on ChromeOS with a complaint about
+// PrefMember<FilePath>::UpdateValueInternal not being defined when
+// built in a chroot with the following parameters:
+//
+// FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting
+// -chrome_internal -chrome_pdf component_build"
+// ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD}
+// --install --runhooks
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<bool>::UpdatePref(const bool& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<bool>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<int>::UpdatePref(const int& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<int>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<double>::UpdatePref(const double& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<double>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<std::string>::UpdatePref(
+    const std::string& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<std::string>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<base::FilePath>::UpdatePref(
+    const base::FilePath& value);
+
+template <>
+BASE_PREFS_EXPORT bool
+PrefMember<base::FilePath>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<std::vector<std::string> >::UpdatePref(
+    const std::vector<std::string>& value);
+
+template <>
+BASE_PREFS_EXPORT bool
+PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+typedef PrefMember<bool> BooleanPrefMember;
+typedef PrefMember<int> IntegerPrefMember;
+typedef PrefMember<double> DoublePrefMember;
+typedef PrefMember<std::string> StringPrefMember;
+typedef PrefMember<base::FilePath> FilePathPrefMember;
+// This preference member is expensive for large string arrays.
+typedef PrefMember<std::vector<std::string> > StringListPrefMember;
+
+#endif  // BASE_PREFS_PREF_MEMBER_H_
diff --git a/base/prefs/pref_member_unittest.cc b/base/prefs/pref_member_unittest.cc
new file mode 100644
index 0000000..a776e2c
--- /dev/null
+++ b/base/prefs/pref_member_unittest.cc
@@ -0,0 +1,325 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_member.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/testing_pref_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kBoolPref[] = "bool";
+const char kIntPref[] = "int";
+const char kDoublePref[] = "double";
+const char kStringPref[] = "string";
+const char kStringListPref[] = "string_list";
+
+void RegisterTestPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(kBoolPref, false);
+  registry->RegisterIntegerPref(kIntPref, 0);
+  registry->RegisterDoublePref(kDoublePref, 0.0);
+  registry->RegisterStringPref(kStringPref, "default");
+  registry->RegisterListPref(kStringListPref, new base::ListValue());
+}
+
+class GetPrefValueHelper
+    : public base::RefCountedThreadSafe<GetPrefValueHelper> {
+ public:
+  GetPrefValueHelper() : value_(false), pref_thread_("pref thread") {
+    pref_thread_.Start();
+  }
+
+  void Init(const std::string& pref_name, PrefService* prefs) {
+    pref_.Init(pref_name, prefs);
+    pref_.MoveToThread(pref_thread_.task_runner());
+  }
+
+  void Destroy() {
+    pref_.Destroy();
+  }
+
+  void FetchValue() {
+    base::WaitableEvent event(true, false);
+    ASSERT_TRUE(pref_thread_.task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
+    event.Wait();
+  }
+
+  // The thread must be stopped on the main thread. GetPrefValueHelper being
+  // ref-counted, the destructor can be called from any thread.
+  void StopThread() {
+    pref_thread_.Stop();
+  }
+
+  bool value() { return value_; }
+
+ private:
+  friend class base::RefCountedThreadSafe<GetPrefValueHelper>;
+  ~GetPrefValueHelper() {}
+
+  void GetPrefValue(base::WaitableEvent* event) {
+    value_ = pref_.GetValue();
+    event->Signal();
+  }
+
+  BooleanPrefMember pref_;
+  bool value_;
+
+  base::Thread pref_thread_;  // The thread |pref_| runs on.
+};
+
+class PrefMemberTestClass {
+ public:
+  explicit PrefMemberTestClass(PrefService* prefs)
+      : observe_cnt_(0), prefs_(prefs) {
+    str_.Init(kStringPref, prefs,
+              base::Bind(&PrefMemberTestClass::OnPreferenceChanged,
+                         base::Unretained(this)));
+  }
+
+  void OnPreferenceChanged(const std::string& pref_name) {
+    EXPECT_EQ(pref_name, kStringPref);
+    EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref));
+    ++observe_cnt_;
+  }
+
+  StringPrefMember str_;
+  int observe_cnt_;
+
+ private:
+  PrefService* prefs_;
+};
+
+}  // anonymous namespace
+
+class PrefMemberTest : public testing::Test {
+  base::MessageLoop message_loop_;
+};
+
+TEST_F(PrefMemberTest, BasicGetAndSet) {
+  TestingPrefServiceSimple prefs;
+  RegisterTestPrefs(prefs.registry());
+
+  // Test bool
+  BooleanPrefMember boolean;
+  boolean.Init(kBoolPref, &prefs);
+
+  // Check the defaults
+  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
+  EXPECT_FALSE(boolean.GetValue());
+  EXPECT_FALSE(*boolean);
+
+  // Try changing through the member variable.
+  boolean.SetValue(true);
+  EXPECT_TRUE(boolean.GetValue());
+  EXPECT_TRUE(prefs.GetBoolean(kBoolPref));
+  EXPECT_TRUE(*boolean);
+
+  // Try changing back through the pref.
+  prefs.SetBoolean(kBoolPref, false);
+  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
+  EXPECT_FALSE(boolean.GetValue());
+  EXPECT_FALSE(*boolean);
+
+  // Test int
+  IntegerPrefMember integer;
+  integer.Init(kIntPref, &prefs);
+
+  // Check the defaults
+  EXPECT_EQ(0, prefs.GetInteger(kIntPref));
+  EXPECT_EQ(0, integer.GetValue());
+  EXPECT_EQ(0, *integer);
+
+  // Try changing through the member variable.
+  integer.SetValue(5);
+  EXPECT_EQ(5, integer.GetValue());
+  EXPECT_EQ(5, prefs.GetInteger(kIntPref));
+  EXPECT_EQ(5, *integer);
+
+  // Try changing back through the pref.
+  prefs.SetInteger(kIntPref, 2);
+  EXPECT_EQ(2, prefs.GetInteger(kIntPref));
+  EXPECT_EQ(2, integer.GetValue());
+  EXPECT_EQ(2, *integer);
+
+  // Test double
+  DoublePrefMember double_member;
+  double_member.Init(kDoublePref, &prefs);
+
+  // Check the defaults
+  EXPECT_EQ(0.0, prefs.GetDouble(kDoublePref));
+  EXPECT_EQ(0.0, double_member.GetValue());
+  EXPECT_EQ(0.0, *double_member);
+
+  // Try changing through the member variable.
+  double_member.SetValue(1.0);
+  EXPECT_EQ(1.0, double_member.GetValue());
+  EXPECT_EQ(1.0, prefs.GetDouble(kDoublePref));
+  EXPECT_EQ(1.0, *double_member);
+
+  // Try changing back through the pref.
+  prefs.SetDouble(kDoublePref, 3.0);
+  EXPECT_EQ(3.0, prefs.GetDouble(kDoublePref));
+  EXPECT_EQ(3.0, double_member.GetValue());
+  EXPECT_EQ(3.0, *double_member);
+
+  // Test string
+  StringPrefMember string;
+  string.Init(kStringPref, &prefs);
+
+  // Check the defaults
+  EXPECT_EQ("default", prefs.GetString(kStringPref));
+  EXPECT_EQ("default", string.GetValue());
+  EXPECT_EQ("default", *string);
+
+  // Try changing through the member variable.
+  string.SetValue("foo");
+  EXPECT_EQ("foo", string.GetValue());
+  EXPECT_EQ("foo", prefs.GetString(kStringPref));
+  EXPECT_EQ("foo", *string);
+
+  // Try changing back through the pref.
+  prefs.SetString(kStringPref, "bar");
+  EXPECT_EQ("bar", prefs.GetString(kStringPref));
+  EXPECT_EQ("bar", string.GetValue());
+  EXPECT_EQ("bar", *string);
+
+  // Test string list
+  base::ListValue expected_list;
+  std::vector<std::string> expected_vector;
+  StringListPrefMember string_list;
+  string_list.Init(kStringListPref, &prefs);
+
+  // Check the defaults
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+
+  // Try changing through the pref member.
+  expected_list.AppendString("foo");
+  expected_vector.push_back("foo");
+  string_list.SetValue(expected_vector);
+
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+
+  // Try adding through the pref.
+  expected_list.AppendString("bar");
+  expected_vector.push_back("bar");
+  prefs.Set(kStringListPref, expected_list);
+
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+
+  // Try removing through the pref.
+  expected_list.Remove(0, NULL);
+  expected_vector.erase(expected_vector.begin());
+  prefs.Set(kStringListPref, expected_list);
+
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+}
+
+TEST_F(PrefMemberTest, InvalidList) {
+  // Set the vector to an initial good value.
+  std::vector<std::string> expected_vector;
+  expected_vector.push_back("foo");
+
+  // Try to add a valid list first.
+  base::ListValue list;
+  list.AppendString("foo");
+  std::vector<std::string> vector;
+  EXPECT_TRUE(subtle::PrefMemberVectorStringUpdate(list, &vector));
+  EXPECT_EQ(expected_vector, vector);
+
+  // Now try to add an invalid list.  |vector| should not be changed.
+  list.AppendInteger(0);
+  EXPECT_FALSE(subtle::PrefMemberVectorStringUpdate(list, &vector));
+  EXPECT_EQ(expected_vector, vector);
+}
+
+TEST_F(PrefMemberTest, TwoPrefs) {
+  // Make sure two DoublePrefMembers stay in sync.
+  TestingPrefServiceSimple prefs;
+  RegisterTestPrefs(prefs.registry());
+
+  DoublePrefMember pref1;
+  pref1.Init(kDoublePref, &prefs);
+  DoublePrefMember pref2;
+  pref2.Init(kDoublePref, &prefs);
+
+  pref1.SetValue(2.3);
+  EXPECT_EQ(2.3, *pref2);
+
+  pref2.SetValue(3.5);
+  EXPECT_EQ(3.5, *pref1);
+
+  prefs.SetDouble(kDoublePref, 4.2);
+  EXPECT_EQ(4.2, *pref1);
+  EXPECT_EQ(4.2, *pref2);
+}
+
+TEST_F(PrefMemberTest, Observer) {
+  TestingPrefServiceSimple prefs;
+  RegisterTestPrefs(prefs.registry());
+
+  PrefMemberTestClass test_obj(&prefs);
+  EXPECT_EQ("default", *test_obj.str_);
+
+  // Calling SetValue should not fire the observer.
+  test_obj.str_.SetValue("hello");
+  EXPECT_EQ(0, test_obj.observe_cnt_);
+  EXPECT_EQ("hello", prefs.GetString(kStringPref));
+
+  // Changing the pref does fire the observer.
+  prefs.SetString(kStringPref, "world");
+  EXPECT_EQ(1, test_obj.observe_cnt_);
+  EXPECT_EQ("world", *(test_obj.str_));
+
+  // Not changing the value should not fire the observer.
+  prefs.SetString(kStringPref, "world");
+  EXPECT_EQ(1, test_obj.observe_cnt_);
+  EXPECT_EQ("world", *(test_obj.str_));
+
+  prefs.SetString(kStringPref, "hello");
+  EXPECT_EQ(2, test_obj.observe_cnt_);
+  EXPECT_EQ("hello", prefs.GetString(kStringPref));
+}
+
+TEST_F(PrefMemberTest, NoInit) {
+  // Make sure not calling Init on a PrefMember doesn't cause problems.
+  IntegerPrefMember pref;
+}
+
+TEST_F(PrefMemberTest, MoveToThread) {
+  TestingPrefServiceSimple prefs;
+  scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper());
+  RegisterTestPrefs(prefs.registry());
+  helper->Init(kBoolPref, &prefs);
+
+  helper->FetchValue();
+  EXPECT_FALSE(helper->value());
+
+  prefs.SetBoolean(kBoolPref, true);
+
+  helper->FetchValue();
+  EXPECT_TRUE(helper->value());
+
+  helper->Destroy();
+
+  helper->FetchValue();
+  EXPECT_TRUE(helper->value());
+
+  helper->StopThread();
+}
diff --git a/base/prefs/pref_notifier.h b/base/prefs/pref_notifier.h
new file mode 100644
index 0000000..e0df260
--- /dev/null
+++ b/base/prefs/pref_notifier.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_NOTIFIER_H_
+#define BASE_PREFS_PREF_NOTIFIER_H_
+
+#include <string>
+
+// Delegate interface used by PrefValueStore to notify its owner about changes
+// to the preference values.
+// TODO(mnissler, danno): Move this declaration to pref_value_store.h once we've
+// cleaned up all public uses of this interface.
+class PrefNotifier {
+ public:
+  virtual ~PrefNotifier() {}
+
+  // Sends out a change notification for the preference identified by
+  // |pref_name|.
+  virtual void OnPreferenceChanged(const std::string& pref_name) = 0;
+
+  // Broadcasts the intialization completed notification.
+  virtual void OnInitializationCompleted(bool succeeded) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_NOTIFIER_H_
diff --git a/base/prefs/pref_notifier_impl.cc b/base/prefs/pref_notifier_impl.cc
new file mode 100644
index 0000000..7ae5fe6
--- /dev/null
+++ b/base/prefs/pref_notifier_impl.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_notifier_impl.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+#include "base/stl_util.h"
+
+PrefNotifierImpl::PrefNotifierImpl()
+    : pref_service_(NULL) {
+}
+
+PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
+    : pref_service_(service) {
+}
+
+PrefNotifierImpl::~PrefNotifierImpl() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Verify that there are no pref observers when we shut down.
+  for (PrefObserverMap::iterator it = pref_observers_.begin();
+       it != pref_observers_.end(); ++it) {
+    PrefObserverList::Iterator obs_iterator(it->second);
+    if (obs_iterator.GetNext()) {
+      LOG(WARNING) << "pref observer found at shutdown " << it->first;
+    }
+  }
+
+  // Same for initialization observers.
+  if (!init_observers_.empty())
+    LOG(WARNING) << "Init observer found at shutdown.";
+
+  STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
+                                       pref_observers_.end());
+  pref_observers_.clear();
+  init_observers_.clear();
+}
+
+void PrefNotifierImpl::AddPrefObserver(const std::string& path,
+                                       PrefObserver* obs) {
+  // Get the pref observer list associated with the path.
+  PrefObserverList* observer_list = NULL;
+  const PrefObserverMap::iterator observer_iterator =
+      pref_observers_.find(path);
+  if (observer_iterator == pref_observers_.end()) {
+    observer_list = new PrefObserverList;
+    pref_observers_[path] = observer_list;
+  } else {
+    observer_list = observer_iterator->second;
+  }
+
+  // Add the pref observer. ObserverList will DCHECK if it already is
+  // in the list.
+  observer_list->AddObserver(obs);
+}
+
+void PrefNotifierImpl::RemovePrefObserver(const std::string& path,
+                                          PrefObserver* obs) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  const PrefObserverMap::iterator observer_iterator =
+      pref_observers_.find(path);
+  if (observer_iterator == pref_observers_.end()) {
+    return;
+  }
+
+  PrefObserverList* observer_list = observer_iterator->second;
+  observer_list->RemoveObserver(obs);
+}
+
+void PrefNotifierImpl::AddInitObserver(base::Callback<void(bool)> obs) {
+  init_observers_.push_back(obs);
+}
+
+void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) {
+  FireObservers(path);
+}
+
+void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // We must make a copy of init_observers_ and clear it before we run
+  // observers, or we can end up in this method re-entrantly before
+  // clearing the observers list.
+  PrefInitObserverList observers(init_observers_);
+  init_observers_.clear();
+
+  for (PrefInitObserverList::iterator it = observers.begin();
+       it != observers.end();
+       ++it) {
+    it->Run(succeeded);
+  }
+}
+
+void PrefNotifierImpl::FireObservers(const std::string& path) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Only send notifications for registered preferences.
+  if (!pref_service_->FindPreference(path))
+    return;
+
+  const PrefObserverMap::iterator observer_iterator =
+      pref_observers_.find(path);
+  if (observer_iterator == pref_observers_.end())
+    return;
+
+  FOR_EACH_OBSERVER(PrefObserver,
+                    *(observer_iterator->second),
+                    OnPreferenceChanged(pref_service_, path));
+}
+
+void PrefNotifierImpl::SetPrefService(PrefService* pref_service) {
+  DCHECK(pref_service_ == NULL);
+  pref_service_ = pref_service;
+}
diff --git a/base/prefs/pref_notifier_impl.h b/base/prefs/pref_notifier_impl.h
new file mode 100644
index 0000000..cfd46ff
--- /dev/null
+++ b/base/prefs/pref_notifier_impl.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_NOTIFIER_IMPL_H_
+#define BASE_PREFS_PREF_NOTIFIER_IMPL_H_
+
+#include <list>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_observer.h"
+#include "base/threading/thread_checker.h"
+
+class PrefService;
+
+// The PrefNotifier implementation used by the PrefService.
+class BASE_PREFS_EXPORT PrefNotifierImpl
+    : public NON_EXPORTED_BASE(PrefNotifier) {
+ public:
+  PrefNotifierImpl();
+  explicit PrefNotifierImpl(PrefService* pref_service);
+  ~PrefNotifierImpl() override;
+
+  // If the pref at the given path changes, we call the observer's
+  // OnPreferenceChanged method.
+  void AddPrefObserver(const std::string& path, PrefObserver* observer);
+  void RemovePrefObserver(const std::string& path, PrefObserver* observer);
+
+  // We run the callback once, when initialization completes. The bool
+  // parameter will be set to true for successful initialization,
+  // false for unsuccessful.
+  void AddInitObserver(base::Callback<void(bool)> observer);
+
+  void SetPrefService(PrefService* pref_service);
+
+ protected:
+  // PrefNotifier overrides.
+  void OnPreferenceChanged(const std::string& pref_name) override;
+  void OnInitializationCompleted(bool succeeded) override;
+
+  // A map from pref names to a list of observers. Observers get fired in the
+  // order they are added. These should only be accessed externally for unit
+  // testing.
+  typedef ObserverList<PrefObserver> PrefObserverList;
+  typedef base::hash_map<std::string, PrefObserverList*> PrefObserverMap;
+
+  typedef std::list<base::Callback<void(bool)> > PrefInitObserverList;
+
+  const PrefObserverMap* pref_observers() const { return &pref_observers_; }
+
+ private:
+  // For the given pref_name, fire any observer of the pref. Virtual so it can
+  // be mocked for unit testing.
+  virtual void FireObservers(const std::string& path);
+
+  // Weak reference; the notifier is owned by the PrefService.
+  PrefService* pref_service_;
+
+  PrefObserverMap pref_observers_;
+  PrefInitObserverList init_observers_;
+
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefNotifierImpl);
+};
+
+#endif  // BASE_PREFS_PREF_NOTIFIER_IMPL_H_
diff --git a/base/prefs/pref_notifier_impl_unittest.cc b/base/prefs/pref_notifier_impl_unittest.cc
new file mode 100644
index 0000000..c3cbf4f
--- /dev/null
+++ b/base/prefs/pref_notifier_impl_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_observer.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Field;
+using testing::Invoke;
+using testing::Mock;
+using testing::Truly;
+
+namespace {
+
+const char kChangedPref[] = "changed_pref";
+const char kUnchangedPref[] = "unchanged_pref";
+
+class MockPrefInitObserver {
+ public:
+  MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+// This is an unmodified PrefNotifierImpl, except we make
+// OnPreferenceChanged public for tests.
+class TestingPrefNotifierImpl : public PrefNotifierImpl {
+ public:
+  explicit TestingPrefNotifierImpl(PrefService* service)
+      : PrefNotifierImpl(service) {
+  }
+
+  // Make public for tests.
+  using PrefNotifierImpl::OnPreferenceChanged;
+};
+
+// Mock PrefNotifier that allows tracking of observers and notifications.
+class MockPrefNotifier : public PrefNotifierImpl {
+ public:
+  explicit MockPrefNotifier(PrefService* pref_service)
+      : PrefNotifierImpl(pref_service) {}
+  virtual ~MockPrefNotifier() {}
+
+  MOCK_METHOD1(FireObservers, void(const std::string& path));
+
+  size_t CountObserver(const std::string& path, PrefObserver* obs) {
+    PrefObserverMap::const_iterator observer_iterator =
+        pref_observers()->find(path);
+    if (observer_iterator == pref_observers()->end())
+      return false;
+
+    PrefObserverList* observer_list = observer_iterator->second;
+    PrefObserverList::Iterator it(observer_list);
+    PrefObserver* existing_obs;
+    size_t count = 0;
+    while ((existing_obs = it.GetNext()) != NULL) {
+      if (existing_obs == obs)
+        count++;
+    }
+
+    return count;
+  }
+
+  // Make public for tests below.
+  using PrefNotifierImpl::OnPreferenceChanged;
+  using PrefNotifierImpl::OnInitializationCompleted;
+};
+
+class PrefObserverMock : public PrefObserver {
+ public:
+  PrefObserverMock() {}
+  virtual ~PrefObserverMock() {}
+
+  MOCK_METHOD2(OnPreferenceChanged, void(PrefService*, const std::string&));
+};
+
+// Test fixture class.
+class PrefNotifierTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    pref_service_.registry()->RegisterBooleanPref(kChangedPref, true);
+    pref_service_.registry()->RegisterBooleanPref(kUnchangedPref, true);
+  }
+
+  TestingPrefServiceSimple pref_service_;
+
+  PrefObserverMock obs1_;
+  PrefObserverMock obs2_;
+};
+
+TEST_F(PrefNotifierTest, OnPreferenceChanged) {
+  MockPrefNotifier notifier(&pref_service_);
+  EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1);
+  notifier.OnPreferenceChanged(kChangedPref);
+}
+
+TEST_F(PrefNotifierTest, OnInitializationCompleted) {
+  MockPrefNotifier notifier(&pref_service_);
+  MockPrefInitObserver observer;
+  notifier.AddInitObserver(
+      base::Bind(&MockPrefInitObserver::OnInitializationCompleted,
+                 base::Unretained(&observer)));
+  EXPECT_CALL(observer, OnInitializationCompleted(true));
+  notifier.OnInitializationCompleted(true);
+}
+
+TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) {
+  const char pref_name[] = "homepage";
+  const char pref_name2[] = "proxy";
+
+  MockPrefNotifier notifier(&pref_service_);
+  notifier.AddPrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  // Re-adding the same observer for the same pref doesn't change anything.
+  // Skip this in debug mode, since it hits a DCHECK and death tests aren't
+  // thread-safe.
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+  notifier.AddPrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+#endif
+
+  // Ensure that we can add the same observer to a different pref.
+  notifier.AddPrefObserver(pref_name2, &obs1_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  // Ensure that we can add another observer to the same pref.
+  notifier.AddPrefObserver(pref_name, &obs2_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  // Ensure that we can remove all observers, and that removing a non-existent
+  // observer is harmless.
+  notifier.RemovePrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  notifier.RemovePrefObserver(pref_name, &obs2_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  notifier.RemovePrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  notifier.RemovePrefObserver(pref_name2, &obs1_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+}
+
+TEST_F(PrefNotifierTest, FireObservers) {
+  TestingPrefNotifierImpl notifier(&pref_service_);
+  notifier.AddPrefObserver(kChangedPref, &obs1_);
+  notifier.AddPrefObserver(kUnchangedPref, &obs1_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  EXPECT_CALL(obs2_, OnPreferenceChanged(_, _)).Times(0);
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  notifier.AddPrefObserver(kChangedPref, &obs2_);
+  notifier.AddPrefObserver(kUnchangedPref, &obs2_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  // Make sure removing an observer from one pref doesn't affect anything else.
+  notifier.RemovePrefObserver(kChangedPref, &obs1_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
+  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  // Make sure removing an observer entirely doesn't affect anything else.
+  notifier.RemovePrefObserver(kUnchangedPref, &obs1_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
+  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  notifier.RemovePrefObserver(kChangedPref, &obs2_);
+  notifier.RemovePrefObserver(kUnchangedPref, &obs2_);
+}
+
+}  // namespace
diff --git a/base/prefs/pref_observer.h b/base/prefs/pref_observer.h
new file mode 100644
index 0000000..5d8f5b6
--- /dev/null
+++ b/base/prefs/pref_observer.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_OBSERVER_H_
+#define BASE_PREFS_PREF_OBSERVER_H_
+
+#include <string>
+
+class PrefService;
+
+// Used internally to the Prefs subsystem to pass preference change
+// notifications between PrefService, PrefNotifierImpl and
+// PrefChangeRegistrar.
+class PrefObserver {
+ public:
+  virtual void OnPreferenceChanged(PrefService* service,
+                                   const std::string& pref_name) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_OBSERVER_H_
diff --git a/base/prefs/pref_registry.cc b/base/prefs/pref_registry.cc
new file mode 100644
index 0000000..74f4b52
--- /dev/null
+++ b/base/prefs/pref_registry.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_registry.h"
+
+#include "base/logging.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/pref_store.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+PrefRegistry::PrefRegistry()
+    : defaults_(new DefaultPrefStore()) {
+}
+
+PrefRegistry::~PrefRegistry() {
+}
+
+uint32 PrefRegistry::GetRegistrationFlags(const std::string& pref_name) const {
+  const auto& it = registration_flags_.find(pref_name);
+  if (it == registration_flags_.end())
+    return NO_REGISTRATION_FLAGS;
+  return it->second;
+}
+
+scoped_refptr<PrefStore> PrefRegistry::defaults() {
+  return defaults_.get();
+}
+
+PrefRegistry::const_iterator PrefRegistry::begin() const {
+  return defaults_->begin();
+}
+
+PrefRegistry::const_iterator PrefRegistry::end() const {
+  return defaults_->end();
+}
+
+void PrefRegistry::SetDefaultPrefValue(const std::string& pref_name,
+                                       base::Value* value) {
+  DCHECK(value);
+  const base::Value* current_value = NULL;
+  DCHECK(defaults_->GetValue(pref_name, &current_value))
+      << "Setting default for unregistered pref: " << pref_name;
+  DCHECK(value->IsType(current_value->GetType()))
+      << "Wrong type for new default: " << pref_name;
+
+  defaults_->ReplaceDefaultValue(pref_name, make_scoped_ptr(value));
+}
+
+void PrefRegistry::RegisterPreference(const std::string& path,
+                                      base::Value* default_value,
+                                      uint32 flags) {
+  base::Value::Type orig_type = default_value->GetType();
+  DCHECK(orig_type != base::Value::TYPE_NULL &&
+         orig_type != base::Value::TYPE_BINARY) <<
+         "invalid preference type: " << orig_type;
+  DCHECK(!defaults_->GetValue(path, NULL)) <<
+      "Trying to register a previously registered pref: " << path;
+  DCHECK(!ContainsKey(registration_flags_, path)) <<
+      "Trying to register a previously registered pref: " << path;
+
+  defaults_->SetDefaultValue(path, make_scoped_ptr(default_value));
+  if (flags != NO_REGISTRATION_FLAGS)
+    registration_flags_[path] = flags;
+}
diff --git a/base/prefs/pref_registry.h b/base/prefs/pref_registry.h
new file mode 100644
index 0000000..caf2a1a
--- /dev/null
+++ b/base/prefs/pref_registry.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_REGISTRY_H_
+#define BASE_PREFS_PREF_REGISTRY_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_value_map.h"
+
+namespace base {
+class Value;
+}
+
+class DefaultPrefStore;
+class PrefStore;
+
+// Preferences need to be registered with a type and default value
+// before they are used.
+//
+// The way you use a PrefRegistry is that you register all required
+// preferences on it (via one of its subclasses), then pass it as a
+// construction parameter to PrefService.
+//
+// Currently, registrations after constructing the PrefService will
+// also work, but this is being deprecated.
+class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
+ public:
+  // Registration flags that can be specified which impact how the pref will
+  // behave or be stored. This will be passed in a bitmask when the pref is
+  // registered. Subclasses of PrefRegistry can specify their own flags. Care
+  // must be taken to ensure none of these overlap with the flags below.
+  enum PrefRegistrationFlags : uint32 {
+    // No flags are specified.
+    NO_REGISTRATION_FLAGS = 0,
+
+    // The first 8 bits are reserved for subclasses of PrefRegistry to use.
+
+    // This marks the pref as "lossy". There is no strict time guarantee on when
+    // a lossy pref will be persisted to permanent storage when it is modified.
+    LOSSY_PREF = 1 << 8,
+  };
+
+  typedef PrefValueMap::const_iterator const_iterator;
+  typedef base::hash_map<std::string, uint32> PrefRegistrationFlagsMap;
+
+  PrefRegistry();
+
+  // Retrieve the set of registration flags for the given preference. The return
+  // value is a bitmask of PrefRegistrationFlags.
+  uint32 GetRegistrationFlags(const std::string& pref_name) const;
+
+  // Gets the registered defaults.
+  scoped_refptr<PrefStore> defaults();
+
+  // Allows iteration over defaults.
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  // Changes the default value for a preference. Takes ownership of |value|.
+  //
+  // |pref_name| must be a previously registered preference.
+  void SetDefaultPrefValue(const std::string& pref_name, base::Value* value);
+
+ protected:
+  friend class base::RefCounted<PrefRegistry>;
+  virtual ~PrefRegistry();
+
+  // Used by subclasses to register a default value and registration flags for
+  // a preference. |flags| is a bitmask of |PrefRegistrationFlags|.
+  void RegisterPreference(const std::string& path,
+                          base::Value* default_value,
+                          uint32 flags);
+
+  scoped_refptr<DefaultPrefStore> defaults_;
+
+  // A map of pref name to a bitmask of PrefRegistrationFlags.
+  PrefRegistrationFlagsMap registration_flags_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefRegistry);
+};
+
+#endif  // BASE_PREFS_PREF_REGISTRY_H_
diff --git a/base/prefs/pref_registry_simple.cc b/base/prefs/pref_registry_simple.cc
new file mode 100644
index 0000000..93c2686
--- /dev/null
+++ b/base/prefs/pref_registry_simple.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_registry_simple.h"
+
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+
+PrefRegistrySimple::PrefRegistrySimple() {
+}
+
+PrefRegistrySimple::~PrefRegistrySimple() {
+}
+
+void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
+                                             bool default_value) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
+                                             int default_value) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
+                                            double default_value) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterStringPref(const std::string& path,
+                                            const std::string& default_value) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterFilePathPref(
+    const std::string& path,
+    const base::FilePath& default_value) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path) {
+  RegisterPrefAndNotify(path, new base::ListValue(), NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+                                          base::ListValue* default_value) {
+  RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path) {
+  RegisterPrefAndNotify(path, new base::DictionaryValue(),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(
+    const std::string& path,
+    base::DictionaryValue* default_value) {
+  RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
+                                           int64 default_value) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Int64ToString(default_value)),
+      NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
+                                            uint64 default_value) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Uint64ToString(default_value)),
+      NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
+                                             bool default_value,
+                                             uint32 flags) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
+                                             int default_value,
+                                             uint32 flags) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
+                                            double default_value,
+                                            uint32 flags) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterStringPref(const std::string& path,
+                                            const std::string& default_value,
+                                            uint32 flags) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterFilePathPref(
+    const std::string& path,
+    const base::FilePath& default_value,
+    uint32 flags) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+                        flags);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+                                          uint32 flags) {
+  RegisterPrefAndNotify(path, new base::ListValue(), flags);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+                                          base::ListValue* default_value,
+                                          uint32 flags) {
+  RegisterPrefAndNotify(path, default_value, flags);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path,
+                                                uint32 flags) {
+  RegisterPrefAndNotify(path, new base::DictionaryValue(), flags);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(
+    const std::string& path,
+    base::DictionaryValue* default_value,
+    uint32 flags) {
+  RegisterPrefAndNotify(path, default_value, flags);
+}
+
+void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
+                                           int64 default_value,
+                                           uint32 flags) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Int64ToString(default_value)), flags);
+}
+
+void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
+                                            uint64 default_value,
+                                            uint32 flags) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Uint64ToString(default_value)), flags);
+}
+
+void PrefRegistrySimple::OnPrefRegistered(const std::string& path,
+                                          base::Value* default_value,
+                                          uint32 flags) {
+}
+
+void PrefRegistrySimple::RegisterPrefAndNotify(const std::string& path,
+                                               base::Value* default_value,
+                                               uint32 flags) {
+  RegisterPreference(path, default_value, flags);
+  OnPrefRegistered(path, default_value, flags);
+}
diff --git a/base/prefs/pref_registry_simple.h b/base/prefs/pref_registry_simple.h
new file mode 100644
index 0000000..6b69e30
--- /dev/null
+++ b/base/prefs/pref_registry_simple.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
+#define BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
+
+#include <string>
+
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_registry.h"
+
+namespace base {
+class DictionaryValue;
+class FilePath;
+class ListValue;
+}
+
+// A simple implementation of PrefRegistry.
+class BASE_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
+ public:
+  PrefRegistrySimple();
+
+  void RegisterBooleanPref(const std::string& path, bool default_value);
+  void RegisterIntegerPref(const std::string& path, int default_value);
+  void RegisterDoublePref(const std::string& path, double default_value);
+  void RegisterStringPref(const std::string& path,
+                          const std::string& default_value);
+  void RegisterFilePathPref(const std::string& path,
+                            const base::FilePath& default_value);
+  void RegisterListPref(const std::string& path);
+  void RegisterDictionaryPref(const std::string& path);
+  void RegisterListPref(const std::string& path,
+                        base::ListValue* default_value);
+  void RegisterDictionaryPref(const std::string& path,
+                              base::DictionaryValue* default_value);
+  void RegisterInt64Pref(const std::string& path, int64 default_value);
+  void RegisterUint64Pref(const std::string&, uint64 default_value);
+
+  // Versions of registration functions that accept PrefRegistrationFlags.
+  // |flags| is a bitmask of PrefRegistrationFlags.
+  void RegisterBooleanPref(const std::string&,
+                           bool default_value,
+                           uint32 flags);
+  void RegisterIntegerPref(const std::string&, int default_value, uint32 flags);
+  void RegisterDoublePref(const std::string&,
+                          double default_value,
+                          uint32 flags);
+  void RegisterStringPref(const std::string&,
+                          const std::string& default_value,
+                          uint32 flags);
+  void RegisterFilePathPref(const std::string&,
+                            const base::FilePath& default_value,
+                            uint32 flags);
+  void RegisterListPref(const std::string&, uint32 flags);
+  void RegisterDictionaryPref(const std::string&, uint32 flags);
+  void RegisterListPref(const std::string&,
+                        base::ListValue* default_value,
+                        uint32 flags);
+  void RegisterDictionaryPref(const std::string&,
+                              base::DictionaryValue* default_value,
+                              uint32 flags);
+  void RegisterInt64Pref(const std::string&, int64 default_value, uint32 flags);
+  void RegisterUint64Pref(const std::string&,
+                          uint64 default_value,
+                          uint32 flags);
+
+ protected:
+  ~PrefRegistrySimple() override;
+
+  // Allows subclasses to hook into pref registration.
+  virtual void OnPrefRegistered(const std::string&,
+                                base::Value* default_value,
+                                uint32 flags);
+
+ private:
+  void RegisterPrefAndNotify(const std::string&,
+                             base::Value* default_value,
+                             uint32 flags);
+
+  DISALLOW_COPY_AND_ASSIGN(PrefRegistrySimple);
+};
+
+#endif  // BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc
new file mode 100644
index 0000000..ad23157
--- /dev/null
+++ b/base/prefs/pref_service.cc
@@ -0,0 +1,610 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_service.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_registry.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/value_conversions.h"
+#include "build/build_config.h"
+
+namespace {
+
+class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+  ReadErrorHandler(base::Callback<void(PersistentPrefStore::PrefReadError)> cb)
+      : callback_(cb) {}
+
+  void OnError(PersistentPrefStore::PrefReadError error) override {
+    callback_.Run(error);
+  }
+
+ private:
+  base::Callback<void(PersistentPrefStore::PrefReadError)> callback_;
+};
+
+// Returns the WriteablePrefStore::PrefWriteFlags for the pref with the given
+// |path|.
+uint32 GetWriteFlags(const PrefService::Preference* pref) {
+  uint32 write_flags = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+
+  if (!pref)
+    return write_flags;
+
+  if (pref->registration_flags() & PrefRegistry::LOSSY_PREF)
+    write_flags |= WriteablePrefStore::LOSSY_PREF_WRITE_FLAG;
+  return write_flags;
+}
+
+}  // namespace
+
+PrefService::PrefService(
+    PrefNotifierImpl* pref_notifier,
+    PrefValueStore* pref_value_store,
+    PersistentPrefStore* user_prefs,
+    PrefRegistry* pref_registry,
+    base::Callback<void(PersistentPrefStore::PrefReadError)>
+        read_error_callback,
+    bool async)
+    : pref_notifier_(pref_notifier),
+      pref_value_store_(pref_value_store),
+      pref_registry_(pref_registry),
+      user_pref_store_(user_prefs),
+      read_error_callback_(read_error_callback) {
+  pref_notifier_->SetPrefService(this);
+
+  // TODO(battre): This is a check for crbug.com/435208 to make sure that
+  // access violations are caused by a use-after-free bug and not by an
+  // initialization bug.
+  CHECK(pref_registry_);
+  CHECK(pref_value_store_);
+
+  InitFromStorage(async);
+}
+
+PrefService::~PrefService() {
+  DCHECK(CalledOnValidThread());
+
+  // Reset pointers so accesses after destruction reliably crash.
+  pref_value_store_.reset();
+  pref_registry_ = NULL;
+  user_pref_store_ = NULL;
+  pref_notifier_.reset();
+}
+
+void PrefService::InitFromStorage(bool async) {
+  if (user_pref_store_->IsInitializationComplete()) {
+    read_error_callback_.Run(user_pref_store_->GetReadError());
+  } else if (!async) {
+    read_error_callback_.Run(user_pref_store_->ReadPrefs());
+  } else {
+    // Guarantee that initialization happens after this function returned.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_.get(),
+                   new ReadErrorHandler(read_error_callback_)));
+  }
+}
+
+void PrefService::CommitPendingWrite() {
+  DCHECK(CalledOnValidThread());
+  user_pref_store_->CommitPendingWrite();
+}
+
+bool PrefService::GetBoolean(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  bool result = false;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsBoolean(&result);
+  DCHECK(rv);
+  return result;
+}
+
+int PrefService::GetInteger(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  int result = 0;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsInteger(&result);
+  DCHECK(rv);
+  return result;
+}
+
+double PrefService::GetDouble(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  double result = 0.0;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsDouble(&result);
+  DCHECK(rv);
+  return result;
+}
+
+std::string PrefService::GetString(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  std::string result;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsString(&result);
+  DCHECK(rv);
+  return result;
+}
+
+base::FilePath PrefService::GetFilePath(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  base::FilePath result;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return base::FilePath(result);
+  }
+  bool rv = base::GetValueAsFilePath(*value, &result);
+  DCHECK(rv);
+  return result;
+}
+
+bool PrefService::HasPrefPath(const std::string& path) const {
+  const Preference* pref = FindPreference(path);
+  return pref && !pref->IsDefaultValue();
+}
+
+scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const {
+  DCHECK(CalledOnValidThread());
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+  for (const auto& it : *pref_registry_) {
+    const base::Value* value = GetPreferenceValue(it.first);
+    out->Set(it.first, value->DeepCopy());
+  }
+  return out.Pass();
+}
+
+scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
+    const {
+  DCHECK(CalledOnValidThread());
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+  for (const auto& it : *pref_registry_) {
+    const Preference* pref = FindPreference(it.first);
+    if (pref->IsDefaultValue())
+      continue;
+    out->Set(it.first, pref->GetValue()->DeepCopy());
+  }
+  return out.Pass();
+}
+
+scoped_ptr<base::DictionaryValue>
+PrefService::GetPreferenceValuesWithoutPathExpansion() const {
+  DCHECK(CalledOnValidThread());
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+  for (const auto& it : *pref_registry_) {
+    const base::Value* value = GetPreferenceValue(it.first);
+    DCHECK(value);
+    out->SetWithoutPathExpansion(it.first, value->DeepCopy());
+  }
+  return out.Pass();
+}
+
+const PrefService::Preference* PrefService::FindPreference(
+    const std::string& pref_name) const {
+  DCHECK(CalledOnValidThread());
+  PreferenceMap::iterator it = prefs_map_.find(pref_name);
+  if (it != prefs_map_.end())
+    return &(it->second);
+  const base::Value* default_value = NULL;
+  if (!pref_registry_->defaults()->GetValue(pref_name, &default_value))
+    return NULL;
+  it = prefs_map_.insert(
+      std::make_pair(pref_name, Preference(
+          this, pref_name, default_value->GetType()))).first;
+  return &(it->second);
+}
+
+bool PrefService::ReadOnly() const {
+  return user_pref_store_->ReadOnly();
+}
+
+PrefService::PrefInitializationStatus PrefService::GetInitializationStatus()
+    const {
+  if (!user_pref_store_->IsInitializationComplete())
+    return INITIALIZATION_STATUS_WAITING;
+
+  switch (user_pref_store_->GetReadError()) {
+    case PersistentPrefStore::PREF_READ_ERROR_NONE:
+      return INITIALIZATION_STATUS_SUCCESS;
+    case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
+      return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
+    default:
+      return INITIALIZATION_STATUS_ERROR;
+  }
+}
+
+bool PrefService::IsManagedPreference(const std::string& pref_name) const {
+  const Preference* pref = FindPreference(pref_name);
+  return pref && pref->IsManaged();
+}
+
+bool PrefService::IsPreferenceManagedByCustodian(
+    const std::string& pref_name) const {
+  const Preference* pref = FindPreference(pref_name);
+  return pref && pref->IsManagedByCustodian();
+}
+
+bool PrefService::IsUserModifiablePreference(
+    const std::string& pref_name) const {
+  const Preference* pref = FindPreference(pref_name);
+  return pref && pref->IsUserModifiable();
+}
+
+const base::DictionaryValue* PrefService::GetDictionary(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return NULL;
+  }
+  if (value->GetType() != base::Value::TYPE_DICTIONARY) {
+    NOTREACHED();
+    return NULL;
+  }
+  return static_cast<const base::DictionaryValue*>(value);
+}
+
+const base::Value* PrefService::GetUserPrefValue(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to get an unregistered pref: " << path;
+    return NULL;
+  }
+
+  // Look for an existing preference in the user store. If it doesn't
+  // exist, return NULL.
+  base::Value* value = NULL;
+  if (!user_pref_store_->GetMutableValue(path, &value))
+    return NULL;
+
+  if (!value->IsType(pref->GetType())) {
+    NOTREACHED() << "Pref value type doesn't match registered type.";
+    return NULL;
+  }
+
+  return value;
+}
+
+void PrefService::SetDefaultPrefValue(const std::string& path,
+                                      base::Value* value) {
+  DCHECK(CalledOnValidThread());
+  pref_registry_->SetDefaultPrefValue(path, value);
+}
+
+const base::Value* PrefService::GetDefaultPrefValue(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+  // Lookup the preference in the default store.
+  const base::Value* value = NULL;
+  if (!pref_registry_->defaults()->GetValue(path, &value)) {
+    NOTREACHED() << "Default value missing for pref: " << path;
+    return NULL;
+  }
+  return value;
+}
+
+const base::ListValue* PrefService::GetList(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return NULL;
+  }
+  if (value->GetType() != base::Value::TYPE_LIST) {
+    NOTREACHED();
+    return NULL;
+  }
+  return static_cast<const base::ListValue*>(value);
+}
+
+void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) {
+  pref_notifier_->AddPrefObserver(path, obs);
+}
+
+void PrefService::RemovePrefObserver(const std::string& path,
+                                     PrefObserver* obs) {
+  pref_notifier_->RemovePrefObserver(path, obs);
+}
+
+void PrefService::AddPrefInitObserver(base::Callback<void(bool)> obs) {
+  pref_notifier_->AddInitObserver(obs);
+}
+
+PrefRegistry* PrefService::DeprecatedGetPrefRegistry() {
+  return pref_registry_.get();
+}
+
+void PrefService::ClearPref(const std::string& path) {
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to clear an unregistered pref: " << path;
+    return;
+  }
+  user_pref_store_->RemoveValue(path, GetWriteFlags(pref));
+}
+
+void PrefService::Set(const std::string& path, const base::Value& value) {
+  SetUserPrefValue(path, value.DeepCopy());
+}
+
+void PrefService::SetBoolean(const std::string& path, bool value) {
+  SetUserPrefValue(path, new base::FundamentalValue(value));
+}
+
+void PrefService::SetInteger(const std::string& path, int value) {
+  SetUserPrefValue(path, new base::FundamentalValue(value));
+}
+
+void PrefService::SetDouble(const std::string& path, double value) {
+  SetUserPrefValue(path, new base::FundamentalValue(value));
+}
+
+void PrefService::SetString(const std::string& path, const std::string& value) {
+  SetUserPrefValue(path, new base::StringValue(value));
+}
+
+void PrefService::SetFilePath(const std::string& path,
+                              const base::FilePath& value) {
+  SetUserPrefValue(path, base::CreateFilePathValue(value));
+}
+
+void PrefService::SetInt64(const std::string& path, int64 value) {
+  SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value)));
+}
+
+int64 PrefService::GetInt64(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return 0;
+  }
+  std::string result("0");
+  bool rv = value->GetAsString(&result);
+  DCHECK(rv);
+
+  int64 val;
+  base::StringToInt64(result, &val);
+  return val;
+}
+
+void PrefService::SetUint64(const std::string& path, uint64 value) {
+  SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value)));
+}
+
+uint64 PrefService::GetUint64(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return 0;
+  }
+  std::string result("0");
+  bool rv = value->GetAsString(&result);
+  DCHECK(rv);
+
+  uint64 val;
+  base::StringToUint64(result, &val);
+  return val;
+}
+
+base::Value* PrefService::GetMutableUserPref(const std::string& path,
+                                             base::Value::Type type) {
+  CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST);
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to get an unregistered pref: " << path;
+    return NULL;
+  }
+  if (pref->GetType() != type) {
+    NOTREACHED() << "Wrong type for GetMutableValue: " << path;
+    return NULL;
+  }
+
+  // Look for an existing preference in the user store. If it doesn't
+  // exist or isn't the correct type, create a new user preference.
+  base::Value* value = NULL;
+  if (!user_pref_store_->GetMutableValue(path, &value) ||
+      !value->IsType(type)) {
+    if (type == base::Value::TYPE_DICTIONARY) {
+      value = new base::DictionaryValue;
+    } else if (type == base::Value::TYPE_LIST) {
+      value = new base::ListValue;
+    } else {
+      NOTREACHED();
+    }
+    user_pref_store_->SetValueSilently(path, value, GetWriteFlags(pref));
+  }
+  return value;
+}
+
+void PrefService::ReportUserPrefChanged(const std::string& key) {
+  DCHECK(CalledOnValidThread());
+  user_pref_store_->ReportValueChanged(key, GetWriteFlags(FindPreference(key)));
+}
+
+void PrefService::SetUserPrefValue(const std::string& path,
+                                   base::Value* new_value) {
+  scoped_ptr<base::Value> owned_value(new_value);
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to write an unregistered pref: " << path;
+    return;
+  }
+  if (pref->GetType() != new_value->GetType()) {
+    NOTREACHED() << "Trying to set pref " << path
+                 << " of type " << pref->GetType()
+                 << " to value of type " << new_value->GetType();
+    return;
+  }
+
+  user_pref_store_->SetValue(path, owned_value.release(), GetWriteFlags(pref));
+}
+
+void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
+  pref_value_store_->UpdateCommandLinePrefStore(command_line_store);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// PrefService::Preference
+
+PrefService::Preference::Preference(const PrefService* service,
+                                    const std::string& name,
+                                    base::Value::Type type)
+    : name_(name), type_(type), pref_service_(service) {
+  DCHECK(service);
+  // Cache the registration flags at creation time to avoid multiple map lookups
+  // later.
+  registration_flags_ = service->pref_registry_->GetRegistrationFlags(name_);
+}
+
+const std::string PrefService::Preference::name() const {
+  return name_;
+}
+
+base::Value::Type PrefService::Preference::GetType() const {
+  return type_;
+}
+
+const base::Value* PrefService::Preference::GetValue() const {
+  const base::Value* result= pref_service_->GetPreferenceValue(name_);
+  DCHECK(result) << "Must register pref before getting its value";
+  return result;
+}
+
+const base::Value* PrefService::Preference::GetRecommendedValue() const {
+  DCHECK(pref_service_->FindPreference(name_))
+      << "Must register pref before getting its value";
+
+  const base::Value* found_value = NULL;
+  if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) {
+    DCHECK(found_value->IsType(type_));
+    return found_value;
+  }
+
+  // The pref has no recommended value.
+  return NULL;
+}
+
+bool PrefService::Preference::IsManaged() const {
+  return pref_value_store()->PrefValueInManagedStore(name_);
+}
+
+bool PrefService::Preference::IsManagedByCustodian() const {
+  return pref_value_store()->PrefValueInSupervisedStore(name_.c_str());
+}
+
+bool PrefService::Preference::IsRecommended() const {
+  return pref_value_store()->PrefValueFromRecommendedStore(name_);
+}
+
+bool PrefService::Preference::HasExtensionSetting() const {
+  return pref_value_store()->PrefValueInExtensionStore(name_);
+}
+
+bool PrefService::Preference::HasUserSetting() const {
+  return pref_value_store()->PrefValueInUserStore(name_);
+}
+
+bool PrefService::Preference::IsExtensionControlled() const {
+  return pref_value_store()->PrefValueFromExtensionStore(name_);
+}
+
+bool PrefService::Preference::IsUserControlled() const {
+  return pref_value_store()->PrefValueFromUserStore(name_);
+}
+
+bool PrefService::Preference::IsDefaultValue() const {
+  return pref_value_store()->PrefValueFromDefaultStore(name_);
+}
+
+bool PrefService::Preference::IsUserModifiable() const {
+  return pref_value_store()->PrefValueUserModifiable(name_);
+}
+
+bool PrefService::Preference::IsExtensionModifiable() const {
+  return pref_value_store()->PrefValueExtensionModifiable(name_);
+}
+
+const base::Value* PrefService::GetPreferenceValue(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  // TODO(battre): This is a check for crbug.com/435208. After analyzing some
+  // crash dumps it looks like the PrefService is accessed even though it has
+  // been cleared already.
+  CHECK(pref_registry_);
+  CHECK(pref_registry_->defaults());
+  CHECK(pref_value_store_);
+
+  const base::Value* default_value = NULL;
+  if (pref_registry_->defaults()->GetValue(path, &default_value)) {
+    const base::Value* found_value = NULL;
+    base::Value::Type default_type = default_value->GetType();
+    if (pref_value_store_->GetValue(path, default_type, &found_value)) {
+      DCHECK(found_value->IsType(default_type));
+      return found_value;
+    } else {
+      // Every registered preference has at least a default value.
+      NOTREACHED() << "no valid value found for registered pref " << path;
+    }
+  }
+
+  return NULL;
+}
diff --git a/base/prefs/pref_service.h b/base/prefs/pref_service.h
new file mode 100644
index 0000000..1fc6c12
--- /dev/null
+++ b/base/prefs/pref_service.h
@@ -0,0 +1,376 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This provides a way to access the application's current preferences.
+
+// Chromium settings and storage represent user-selected preferences and
+// information and MUST not be extracted, overwritten or modified except
+// through Chromium defined APIs.
+
+#ifndef BASE_PREFS_PREF_SERVICE_H_
+#define BASE_PREFS_PREF_SERVICE_H_
+
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
+
+class PrefNotifier;
+class PrefNotifierImpl;
+class PrefObserver;
+class PrefRegistry;
+class PrefValueStore;
+class PrefStore;
+
+namespace base {
+class FilePath;
+}
+
+namespace subtle {
+class PrefMemberBase;
+class ScopedUserPrefUpdateBase;
+}
+
+// Base class for PrefServices. You can use the base class to read and
+// interact with preferences, but not to register new preferences; for
+// that see e.g. PrefRegistrySimple.
+//
+// Settings and storage accessed through this class represent
+// user-selected preferences and information and MUST not be
+// extracted, overwritten or modified except through the defined APIs.
+class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
+ public:
+  enum PrefInitializationStatus {
+    INITIALIZATION_STATUS_WAITING,
+    INITIALIZATION_STATUS_SUCCESS,
+    INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE,
+    INITIALIZATION_STATUS_ERROR
+  };
+
+  // A helper class to store all the information associated with a preference.
+  class BASE_PREFS_EXPORT Preference {
+   public:
+    // The type of the preference is determined by the type with which it is
+    // registered. This type needs to be a boolean, integer, double, string,
+    // dictionary (a branch), or list.  You shouldn't need to construct this on
+    // your own; use the PrefService::Register*Pref methods instead.
+    Preference(const PrefService* service,
+               const std::string& name,
+               base::Value::Type type);
+    ~Preference() {}
+
+    // Returns the name of the Preference (i.e., the key, e.g.,
+    // browser.window_placement).
+    const std::string name() const;
+
+    // Returns the registered type of the preference.
+    base::Value::Type GetType() const;
+
+    // Returns the value of the Preference, falling back to the registered
+    // default value if no other has been set.
+    const base::Value* GetValue() const;
+
+    // Returns the value recommended by the admin, if any.
+    const base::Value* GetRecommendedValue() const;
+
+    // Returns true if the Preference is managed, i.e. set by an admin policy.
+    // Since managed prefs have the highest priority, this also indicates
+    // whether the pref is actually being controlled by the policy setting.
+    bool IsManaged() const;
+
+    // Returns true if the Preference is controlled by the custodian of the
+    // supervised user. Since a supervised user is not expected to have an admin
+    // policy, this is the controlling pref if set.
+    bool IsManagedByCustodian() const;
+
+    // Returns true if the Preference is recommended, i.e. set by an admin
+    // policy but the user is allowed to change it.
+    bool IsRecommended() const;
+
+    // Returns true if the Preference has a value set by an extension, even if
+    // that value is being overridden by a higher-priority source.
+    bool HasExtensionSetting() const;
+
+    // Returns true if the Preference has a user setting, even if that value is
+    // being overridden by a higher-priority source.
+    bool HasUserSetting() const;
+
+    // Returns true if the Preference value is currently being controlled by an
+    // extension, and not by any higher-priority source.
+    bool IsExtensionControlled() const;
+
+    // Returns true if the Preference value is currently being controlled by a
+    // user setting, and not by any higher-priority source.
+    bool IsUserControlled() const;
+
+    // Returns true if the Preference is currently using its default value,
+    // and has not been set by any higher-priority source (even with the same
+    // value).
+    bool IsDefaultValue() const;
+
+    // Returns true if the user can change the Preference value, which is the
+    // case if no higher-priority source than the user store controls the
+    // Preference.
+    bool IsUserModifiable() const;
+
+    // Returns true if an extension can change the Preference value, which is
+    // the case if no higher-priority source than the extension store controls
+    // the Preference.
+    bool IsExtensionModifiable() const;
+
+    // Return the registration flags for this pref as a bitmask of
+    // PrefRegistry::PrefRegistrationFlags.
+    uint32 registration_flags() const { return registration_flags_; }
+
+   private:
+    friend class PrefService;
+
+    PrefValueStore* pref_value_store() const {
+      return pref_service_->pref_value_store_.get();
+    }
+
+    const std::string name_;
+
+    const base::Value::Type type_;
+
+    uint32 registration_flags_;
+
+    // Reference to the PrefService in which this pref was created.
+    const PrefService* pref_service_;
+  };
+
+  // You may wish to use PrefServiceFactory or one of its subclasses
+  // for simplified construction.
+  PrefService(
+      PrefNotifierImpl* pref_notifier,
+      PrefValueStore* pref_value_store,
+      PersistentPrefStore* user_prefs,
+      PrefRegistry* pref_registry,
+      base::Callback<void(PersistentPrefStore::PrefReadError)>
+          read_error_callback,
+      bool async);
+  virtual ~PrefService();
+
+  // Lands pending writes to disk. This should only be used if we need to save
+  // immediately (basically, during shutdown).
+  void CommitPendingWrite();
+
+  // Returns true if the preference for the given preference name is available
+  // and is managed.
+  bool IsManagedPreference(const std::string& pref_name) const;
+
+  // Returns true if the preference for the given preference name is available
+  // and is controlled by the parent/guardian of the child Account.
+  bool IsPreferenceManagedByCustodian(const std::string& pref_name) const;
+
+  // Returns |true| if a preference with the given name is available and its
+  // value can be changed by the user.
+  bool IsUserModifiablePreference(const std::string& pref_name) const;
+
+  // Look up a preference.  Returns NULL if the preference is not
+  // registered.
+  const PrefService::Preference* FindPreference(const std::string& path) const;
+
+  // If the path is valid and the value at the end of the path matches the type
+  // specified, it will return the specified value.  Otherwise, the default
+  // value (set when the pref was registered) will be returned.
+  bool GetBoolean(const std::string& path) const;
+  int GetInteger(const std::string& path) const;
+  double GetDouble(const std::string& path) const;
+  std::string GetString(const std::string& path) const;
+  base::FilePath GetFilePath(const std::string& path) const;
+
+  // Returns the branch if it exists, or the registered default value otherwise.
+  // Note that |path| must point to a registered preference. In that case, these
+  // functions will never return NULL.
+  const base::DictionaryValue* GetDictionary(const std::string& path) const;
+  const base::ListValue* GetList(const std::string& path) const;
+
+  // Removes a user pref and restores the pref to its default value.
+  void ClearPref(const std::string& path);
+
+  // If the path is valid (i.e., registered), update the pref value in the user
+  // prefs.
+  // To set the value of dictionary or list values in the pref tree use
+  // Set(), but to modify the value of a dictionary or list use either
+  // ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h.
+  void Set(const std::string& path, const base::Value& value);
+  void SetBoolean(const std::string& path, bool value);
+  void SetInteger(const std::string& path, int value);
+  void SetDouble(const std::string& path, double value);
+  void SetString(const std::string& path, const std::string& value);
+  void SetFilePath(const std::string& path, const base::FilePath& value);
+
+  // Int64 helper methods that actually store the given value as a string.
+  // Note that if obtaining the named value via GetDictionary or GetList, the
+  // Value type will be TYPE_STRING.
+  void SetInt64(const std::string& path, int64 value);
+  int64 GetInt64(const std::string& path) const;
+
+  // As above, but for unsigned values.
+  void SetUint64(const std::string& path, uint64 value);
+  uint64 GetUint64(const std::string& path) const;
+
+  // Returns the value of the given preference, from the user pref store. If
+  // the preference is not set in the user pref store, returns NULL.
+  const base::Value* GetUserPrefValue(const std::string& path) const;
+
+  // Changes the default value for a preference. Takes ownership of |value|.
+  //
+  // Will cause a pref change notification to be fired if this causes
+  // the effective value to change.
+  void SetDefaultPrefValue(const std::string& path, base::Value* value);
+
+  // Returns the default value of the given preference. |path| must point to a
+  // registered preference. In that case, will never return NULL.
+  const base::Value* GetDefaultPrefValue(const std::string& path) const;
+
+  // Returns true if a value has been set for the specified path.
+  // NOTE: this is NOT the same as FindPreference. In particular
+  // FindPreference returns whether RegisterXXX has been invoked, where as
+  // this checks if a value exists for the path.
+  bool HasPrefPath(const std::string& path) const;
+
+  // Returns a dictionary with effective preference values.
+  scoped_ptr<base::DictionaryValue> GetPreferenceValues() const;
+
+  // Returns a dictionary with effective preference values, omitting prefs that
+  // are at their default values.
+  scoped_ptr<base::DictionaryValue> GetPreferenceValuesOmitDefaults() const;
+
+  // Returns a dictionary with effective preference values. Contrary to
+  // GetPreferenceValues(), the paths of registered preferences are not split on
+  // '.' characters. If a registered preference stores a dictionary, however,
+  // the hierarchical structure inside the preference will be preserved.
+  // For example, if "foo.bar" is a registered preference, the result could look
+  // like this:
+  //   {"foo.bar": {"a": {"b": true}}}.
+  scoped_ptr<base::DictionaryValue> GetPreferenceValuesWithoutPathExpansion()
+      const;
+
+  bool ReadOnly() const;
+
+  PrefInitializationStatus GetInitializationStatus() const;
+
+  // Tell our PrefValueStore to update itself to |command_line_store|.
+  // Takes ownership of the store.
+  virtual void UpdateCommandLinePrefStore(PrefStore* command_line_store);
+
+  // We run the callback once, when initialization completes. The bool
+  // parameter will be set to true for successful initialization,
+  // false for unsuccessful.
+  void AddPrefInitObserver(base::Callback<void(bool)> callback);
+
+  // Returns the PrefRegistry object for this service. You should not
+  // use this; the intent is for no registrations to take place after
+  // PrefService has been constructed.
+  //
+  // Instead of using this method, the recommended approach is to
+  // register all preferences for a class Xyz up front in a static
+  // Xyz::RegisterPrefs function, which gets invoked early in the
+  // application's start-up, before a PrefService is created.
+  //
+  // As an example, prefs registration in Chrome is triggered by the
+  // functions chrome::RegisterPrefs (for global preferences) and
+  // chrome::RegisterProfilePrefs (for user-specific preferences)
+  // implemented in chrome/browser/prefs/browser_prefs.cc.
+  PrefRegistry* DeprecatedGetPrefRegistry();
+
+ protected:
+  // The PrefNotifier handles registering and notifying preference observers.
+  // It is created and owned by this PrefService. Subclasses may access it for
+  // unit testing.
+  scoped_ptr<PrefNotifierImpl> pref_notifier_;
+
+  // The PrefValueStore provides prioritized preference values. It is owned by
+  // this PrefService. Subclasses may access it for unit testing.
+  scoped_ptr<PrefValueStore> pref_value_store_;
+
+  scoped_refptr<PrefRegistry> pref_registry_;
+
+  // Pref Stores and profile that we passed to the PrefValueStore.
+  scoped_refptr<PersistentPrefStore> user_pref_store_;
+
+  // Callback to call when a read error occurs.
+  base::Callback<void(PersistentPrefStore::PrefReadError)> read_error_callback_;
+
+ private:
+  // Hash map expected to be fastest here since it minimises expensive
+  // string comparisons. Order is unimportant, and deletions are rare.
+  // Confirmed on Android where this speeded Chrome startup by roughly 50ms
+  // vs. std::map, and by roughly 180ms vs. std::set of Preference pointers.
+  typedef base::hash_map<std::string, Preference> PreferenceMap;
+
+  // Give access to ReportUserPrefChanged() and GetMutableUserPref().
+  friend class subtle::ScopedUserPrefUpdateBase;
+  friend class PrefServiceTest_WriteablePrefStoreFlags_Test;
+
+  // Registration of pref change observers must be done using the
+  // PrefChangeRegistrar, which is declared as a friend here to grant it
+  // access to the otherwise protected members Add/RemovePrefObserver.
+  // PrefMember registers for preferences changes notification directly to
+  // avoid the storage overhead of the registrar, so its base class must be
+  // declared as a friend, too.
+  friend class PrefChangeRegistrar;
+  friend class subtle::PrefMemberBase;
+
+  // These are protected so they can only be accessed by the friend
+  // classes listed above.
+  //
+  // If the pref at the given path changes, we call the observer's
+  // OnPreferenceChanged method. Note that observers should not call
+  // these methods directly but rather use a PrefChangeRegistrar to
+  // make sure the observer gets cleaned up properly.
+  //
+  // Virtual for testing.
+  virtual void AddPrefObserver(const std::string& path, PrefObserver* obs);
+  virtual void RemovePrefObserver(const std::string& path, PrefObserver* obs);
+
+  // Sends notification of a changed preference. This needs to be called by
+  // a ScopedUserPrefUpdate if a DictionaryValue or ListValue is changed.
+  void ReportUserPrefChanged(const std::string& key);
+
+  // Sets the value for this pref path in the user pref store and informs the
+  // PrefNotifier of the change.
+  void SetUserPrefValue(const std::string& path, base::Value* new_value);
+
+  // Load preferences from storage, attempting to diagnose and handle errors.
+  // This should only be called from the constructor.
+  void InitFromStorage(bool async);
+
+  // Used to set the value of dictionary or list values in the user pref store.
+  // This will create a dictionary or list if one does not exist in the user
+  // pref store. This method returns NULL only if you're requesting an
+  // unregistered pref or a non-dict/non-list pref.
+  // |type| may only be Values::TYPE_DICTIONARY or Values::TYPE_LIST and
+  // |path| must point to a registered preference of type |type|.
+  // Ownership of the returned value remains at the user pref store.
+  base::Value* GetMutableUserPref(const std::string& path,
+                                  base::Value::Type type);
+
+  // GetPreferenceValue is the equivalent of FindPreference(path)->GetValue(),
+  // it has been added for performance. If is faster because it does
+  // not need to find or create a Preference object to get the
+  // value (GetValue() calls back though the preference service to
+  // actually get the value.).
+  const base::Value* GetPreferenceValue(const std::string& path) const;
+
+  // Local cache of registered Preference objects. The pref_registry_
+  // is authoritative with respect to what the types and default values
+  // of registered preferences are.
+  mutable PreferenceMap prefs_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefService);
+};
+
+#endif  // BASE_PREFS_PREF_SERVICE_H_
diff --git a/base/prefs/pref_service_factory.cc b/base/prefs/pref_service_factory.cc
new file mode 100644
index 0000000..8caf073
--- /dev/null
+++ b/base/prefs/pref_service_factory.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_service_factory.h"
+
+#include "base/bind.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/json_pref_store.h"
+#include "base/prefs/pref_filter.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/sequenced_task_runner.h"
+
+namespace base {
+
+namespace {
+
+// Do-nothing default implementation.
+void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {
+}
+
+}  // namespace
+
+PrefServiceFactory::PrefServiceFactory()
+    : managed_prefs_(NULL),
+      supervised_user_prefs_(NULL),
+      extension_prefs_(NULL),
+      command_line_prefs_(NULL),
+      user_prefs_(NULL),
+      recommended_prefs_(NULL),
+      read_error_callback_(base::Bind(&DoNothingHandleReadError)),
+      async_(false) {}
+
+PrefServiceFactory::~PrefServiceFactory() {}
+
+void PrefServiceFactory::SetUserPrefsFile(
+    const base::FilePath& prefs_file,
+    base::SequencedTaskRunner* task_runner) {
+  user_prefs_ = new JsonPrefStore(
+      prefs_file, task_runner, scoped_ptr<PrefFilter>());
+}
+
+scoped_ptr<PrefService> PrefServiceFactory::Create(
+    PrefRegistry* pref_registry) {
+  PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
+  scoped_ptr<PrefService> pref_service(
+      new PrefService(pref_notifier,
+                      new PrefValueStore(managed_prefs_.get(),
+                                         supervised_user_prefs_.get(),
+                                         extension_prefs_.get(),
+                                         command_line_prefs_.get(),
+                                         user_prefs_.get(),
+                                         recommended_prefs_.get(),
+                                         pref_registry->defaults().get(),
+                                         pref_notifier),
+                      user_prefs_.get(),
+                      pref_registry,
+                      read_error_callback_,
+                      async_));
+  return pref_service.Pass();
+}
+
+}  // namespace base
diff --git a/base/prefs/pref_service_factory.h b/base/prefs/pref_service_factory.h
new file mode 100644
index 0000000..ca608c2
--- /dev/null
+++ b/base/prefs/pref_service_factory.h
@@ -0,0 +1,91 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_SERVICE_FACTORY_H_
+#define BASE_PREFS_PREF_SERVICE_FACTORY_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_registry.h"
+#include "base/prefs/pref_store.h"
+
+class PrefService;
+
+namespace base {
+
+class FilePath;
+class SequencedTaskRunner;
+
+// A class that allows convenient building of PrefService.
+class BASE_PREFS_EXPORT PrefServiceFactory {
+ public:
+  PrefServiceFactory();
+  virtual ~PrefServiceFactory();
+
+  // Functions for setting the various parameters of the PrefService to build.
+  void set_managed_prefs(const scoped_refptr<PrefStore>& managed_prefs) {
+    managed_prefs_ = managed_prefs;
+  }
+  void set_supervised_user_prefs(
+      const scoped_refptr<PrefStore>& supervised_user_prefs) {
+    supervised_user_prefs_ = supervised_user_prefs;
+  }
+  void set_extension_prefs(const scoped_refptr<PrefStore>& extension_prefs) {
+    extension_prefs_ = extension_prefs;
+  }
+  void set_command_line_prefs(
+      const scoped_refptr<PrefStore>& command_line_prefs) {
+    command_line_prefs_ = command_line_prefs;
+  }
+  void set_user_prefs(const scoped_refptr<PersistentPrefStore>& user_prefs) {
+    user_prefs_ = user_prefs;
+  }
+  void set_recommended_prefs(
+      const scoped_refptr<PrefStore>& recommended_prefs) {
+    recommended_prefs_ = recommended_prefs;
+  }
+
+  // Sets up error callback for the PrefService.  A do-nothing default
+  // is provided if this is not called.
+  void set_read_error_callback(
+      const base::Callback<void(PersistentPrefStore::PrefReadError)>&
+          read_error_callback) {
+    read_error_callback_ = read_error_callback;
+  }
+
+  // Specifies to use an actual file-backed user pref store.
+  void SetUserPrefsFile(const base::FilePath& prefs_file,
+                        base::SequencedTaskRunner* task_runner);
+
+  void set_async(bool async) {
+    async_ = async;
+  }
+
+  // Creates a PrefService object initialized with the parameters from
+  // this factory.
+  scoped_ptr<PrefService> Create(PrefRegistry* registry);
+
+ protected:
+  scoped_refptr<PrefStore> managed_prefs_;
+  scoped_refptr<PrefStore> supervised_user_prefs_;
+  scoped_refptr<PrefStore> extension_prefs_;
+  scoped_refptr<PrefStore> command_line_prefs_;
+  scoped_refptr<PersistentPrefStore> user_prefs_;
+  scoped_refptr<PrefStore> recommended_prefs_;
+
+  base::Callback<void(PersistentPrefStore::PrefReadError)> read_error_callback_;
+
+  // Defaults to false.
+  bool async_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefServiceFactory);
+};
+
+}  // namespace base
+
+#endif  // BASE_PREFS_PREF_SERVICE_FACTORY_H_
diff --git a/base/prefs/pref_service_unittest.cc b/base/prefs/pref_service_unittest.cc
new file mode 100644
index 0000000..262d7e9
--- /dev/null
+++ b/base/prefs/pref_service_unittest.cc
@@ -0,0 +1,428 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/prefs/json_pref_store.h"
+#include "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service_factory.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/prefs/testing_pref_service.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+const char kPrefName[] = "pref.name";
+
+TEST(PrefServiceTest, NoObserverFire) {
+  TestingPrefServiceSimple prefs;
+
+  const char pref_name[] = "homepage";
+  prefs.registry()->RegisterStringPref(pref_name, std::string());
+
+  const char new_pref_value[] = "http://www.google.com/";
+  MockPrefChangeCallback obs(&prefs);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs);
+  registrar.Add(pref_name, obs.GetCallback());
+
+  // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged.
+  const base::StringValue expected_value(new_pref_value);
+  obs.Expect(pref_name, &expected_value);
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Setting the pref to the same value should not set the pref value a second
+  // time.
+  EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0);
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Clearing the pref should cause the pref to fire.
+  const base::StringValue expected_default_value((std::string()));
+  obs.Expect(pref_name, &expected_default_value);
+  prefs.ClearPref(pref_name);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Clearing the pref again should not cause the pref to fire.
+  EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0);
+  prefs.ClearPref(pref_name);
+  Mock::VerifyAndClearExpectations(&obs);
+}
+
+TEST(PrefServiceTest, HasPrefPath) {
+  TestingPrefServiceSimple prefs;
+
+  const char path[] = "fake.path";
+
+  // Shouldn't initially have a path.
+  EXPECT_FALSE(prefs.HasPrefPath(path));
+
+  // Register the path. This doesn't set a value, so the path still shouldn't
+  // exist.
+  prefs.registry()->RegisterStringPref(path, std::string());
+  EXPECT_FALSE(prefs.HasPrefPath(path));
+
+  // Set a value and make sure we have a path.
+  prefs.SetString(path, "blah");
+  EXPECT_TRUE(prefs.HasPrefPath(path));
+}
+
+TEST(PrefServiceTest, Observers) {
+  const char pref_name[] = "homepage";
+
+  TestingPrefServiceSimple prefs;
+  prefs.SetUserPref(pref_name,
+                    new base::StringValue("http://www.cnn.com"));
+  prefs.registry()->RegisterStringPref(pref_name, std::string());
+
+  const char new_pref_value[] = "http://www.google.com/";
+  const base::StringValue expected_new_pref_value(new_pref_value);
+  MockPrefChangeCallback obs(&prefs);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs);
+  registrar.Add(pref_name, obs.GetCallback());
+
+  PrefChangeRegistrar registrar_two;
+  registrar_two.Init(&prefs);
+
+  // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged.
+  obs.Expect(pref_name, &expected_new_pref_value);
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Now try adding a second pref observer.
+  const char new_pref_value2[] = "http://www.youtube.com/";
+  const base::StringValue expected_new_pref_value2(new_pref_value2);
+  MockPrefChangeCallback obs2(&prefs);
+  obs.Expect(pref_name, &expected_new_pref_value2);
+  obs2.Expect(pref_name, &expected_new_pref_value2);
+  registrar_two.Add(pref_name, obs2.GetCallback());
+  // This should fire the checks in obs and obs2.
+  prefs.SetString(pref_name, new_pref_value2);
+  Mock::VerifyAndClearExpectations(&obs);
+  Mock::VerifyAndClearExpectations(&obs2);
+
+  // Set a recommended value.
+  const base::StringValue recommended_pref_value("http://www.gmail.com/");
+  obs.Expect(pref_name, &expected_new_pref_value2);
+  obs2.Expect(pref_name, &expected_new_pref_value2);
+  // This should fire the checks in obs and obs2 but with an unchanged value
+  // as the recommended value is being overridden by the user-set value.
+  prefs.SetRecommendedPref(pref_name, recommended_pref_value.DeepCopy());
+  Mock::VerifyAndClearExpectations(&obs);
+  Mock::VerifyAndClearExpectations(&obs2);
+
+  // Make sure obs2 still works after removing obs.
+  registrar.Remove(pref_name);
+  EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0);
+  obs2.Expect(pref_name, &expected_new_pref_value);
+  // This should only fire the observer in obs2.
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+  Mock::VerifyAndClearExpectations(&obs2);
+}
+
+// Make sure that if a preference changes type, so the wrong type is stored in
+// the user pref file, it uses the correct fallback value instead.
+TEST(PrefServiceTest, GetValueChangedType) {
+  const int kTestValue = 10;
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterIntegerPref(kPrefName, kTestValue);
+
+  // Check falling back to a recommended value.
+  prefs.SetUserPref(kPrefName,
+                    new base::StringValue("not an integer"));
+  const PrefService::Preference* pref = prefs.FindPreference(kPrefName);
+  ASSERT_TRUE(pref);
+  const base::Value* value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  int actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kTestValue, actual_int_value);
+}
+
+TEST(PrefServiceTest, GetValueAndGetRecommendedValue) {
+  const int kDefaultValue = 5;
+  const int kUserValue = 10;
+  const int kRecommendedValue = 15;
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterIntegerPref(kPrefName, kDefaultValue);
+
+  // Create pref with a default value only.
+  const PrefService::Preference* pref = prefs.FindPreference(kPrefName);
+  ASSERT_TRUE(pref);
+
+  // Check that GetValue() returns the default value.
+  const base::Value* value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  int actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kDefaultValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns no value.
+  value = pref->GetRecommendedValue();
+  ASSERT_FALSE(value);
+
+  // Set a user-set value.
+  prefs.SetUserPref(kPrefName, new base::FundamentalValue(kUserValue));
+
+  // Check that GetValue() returns the user-set value.
+  value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kUserValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns no value.
+  value = pref->GetRecommendedValue();
+  ASSERT_FALSE(value);
+
+  // Set a recommended value.
+  prefs.SetRecommendedPref(kPrefName,
+                           new base::FundamentalValue(kRecommendedValue));
+
+  // Check that GetValue() returns the user-set value.
+  value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kUserValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns the recommended value.
+  value = pref->GetRecommendedValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kRecommendedValue, actual_int_value);
+
+  // Remove the user-set value.
+  prefs.RemoveUserPref(kPrefName);
+
+  // Check that GetValue() returns the recommended value.
+  value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kRecommendedValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns the recommended value.
+  value = pref->GetRecommendedValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kRecommendedValue, actual_int_value);
+}
+
+// A PrefStore which just stores the last write flags that were used to write
+// values to it.
+class WriteFlagChecker : public TestingPrefStore {
+ public:
+  WriteFlagChecker() {}
+
+  void ReportValueChanged(const std::string& key, uint32 flags) override {
+    SetLastWriteFlags(flags);
+  }
+
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override {
+    SetLastWriteFlags(flags);
+    delete value;
+  }
+
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override {
+    SetLastWriteFlags(flags);
+    delete value;
+  }
+
+  void RemoveValue(const std::string& key, uint32 flags) override {
+    SetLastWriteFlags(flags);
+  }
+
+  uint32 GetLastFlagsAndClear() {
+    CHECK(last_write_flags_set_);
+    uint32 result = last_write_flags_;
+    last_write_flags_set_ = false;
+    last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+    return result;
+  }
+
+  bool last_write_flags_set() { return last_write_flags_set_; }
+
+ private:
+  ~WriteFlagChecker() override {}
+
+  void SetLastWriteFlags(uint32 flags) {
+    CHECK(!last_write_flags_set_);
+    last_write_flags_set_ = true;
+    last_write_flags_ = flags;
+  }
+
+  bool last_write_flags_set_ = false;
+  uint32 last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+};
+
+TEST(PrefServiceTest, WriteablePrefStoreFlags) {
+  scoped_refptr<WriteFlagChecker> flag_checker(new WriteFlagChecker);
+  scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple);
+  base::PrefServiceFactory factory;
+  factory.set_user_prefs(flag_checker);
+  scoped_ptr<PrefService> prefs(factory.Create(registry.get()));
+
+  // The first 8 bits of write flags are reserved for subclasses. Create a
+  // custom flag in this range
+  uint32 kCustomRegistrationFlag = 1 << 2;
+
+  // A map of the registration flags that will be tested and the write flags
+  // they are expected to convert to.
+  struct RegistrationToWriteFlags {
+    const char* pref_name;
+    uint32 registration_flags;
+    uint32 write_flags;
+  };
+  const RegistrationToWriteFlags kRegistrationToWriteFlags[] = {
+      {"none",
+       PrefRegistry::NO_REGISTRATION_FLAGS,
+       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS},
+      {"lossy",
+       PrefRegistry::LOSSY_PREF,
+       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG},
+      {"custom",
+       kCustomRegistrationFlag,
+       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS},
+      {"lossyandcustom",
+       PrefRegistry::LOSSY_PREF | kCustomRegistrationFlag,
+       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG}};
+
+  for (size_t i = 0; i < arraysize(kRegistrationToWriteFlags); ++i) {
+    RegistrationToWriteFlags entry = kRegistrationToWriteFlags[i];
+    registry->RegisterDictionaryPref(
+        entry.pref_name, new base::DictionaryValue(), entry.registration_flags);
+
+    SCOPED_TRACE("Currently testing pref with name: " +
+                 std::string(entry.pref_name));
+
+    prefs->GetMutableUserPref(entry.pref_name, base::Value::TYPE_DICTIONARY);
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+    prefs->ReportUserPrefChanged(entry.pref_name);
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+    prefs->ClearPref(entry.pref_name);
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+    prefs->SetUserPrefValue(entry.pref_name, new base::DictionaryValue());
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+  }
+}
+
+class PrefServiceSetValueTest : public testing::Test {
+ protected:
+  static const char kName[];
+  static const char kValue[];
+
+  PrefServiceSetValueTest() : observer_(&prefs_) {}
+
+  TestingPrefServiceSimple prefs_;
+  MockPrefChangeCallback observer_;
+};
+
+const char PrefServiceSetValueTest::kName[] = "name";
+const char PrefServiceSetValueTest::kValue[] = "value";
+
+TEST_F(PrefServiceSetValueTest, SetStringValue) {
+  const char default_string[] = "default";
+  const base::StringValue default_value(default_string);
+  prefs_.registry()->RegisterStringPref(kName, default_string);
+
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs_);
+  registrar.Add(kName, observer_.GetCallback());
+
+  // Changing the controlling store from default to user triggers notification.
+  observer_.Expect(kName, &default_value);
+  prefs_.Set(kName, default_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.Set(kName, default_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::StringValue new_value(kValue);
+  observer_.Expect(kName, &new_value);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
+
+TEST_F(PrefServiceSetValueTest, SetDictionaryValue) {
+  prefs_.registry()->RegisterDictionaryPref(kName);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs_);
+  registrar.Add(kName, observer_.GetCallback());
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.RemoveUserPref(kName);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::DictionaryValue new_value;
+  new_value.SetString(kName, kValue);
+  observer_.Expect(kName, &new_value);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::DictionaryValue empty;
+  observer_.Expect(kName, &empty);
+  prefs_.Set(kName, empty);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
+
+TEST_F(PrefServiceSetValueTest, SetListValue) {
+  prefs_.registry()->RegisterListPref(kName);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs_);
+  registrar.Add(kName, observer_.GetCallback());
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.RemoveUserPref(kName);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::ListValue new_value;
+  new_value.Append(new base::StringValue(kValue));
+  observer_.Expect(kName, &new_value);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::ListValue empty;
+  observer_.Expect(kName, &empty);
+  prefs_.Set(kName, empty);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
diff --git a/base/prefs/pref_store.cc b/base/prefs/pref_store.cc
new file mode 100644
index 0000000..f286a33
--- /dev/null
+++ b/base/prefs/pref_store.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_store.h"
+
+bool PrefStore::HasObservers() const {
+  return false;
+}
+
+bool PrefStore::IsInitializationComplete() const {
+  return true;
+}
diff --git a/base/prefs/pref_store.h b/base/prefs/pref_store.h
new file mode 100644
index 0000000..b736ac3
--- /dev/null
+++ b/base/prefs/pref_store.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_STORE_H_
+#define BASE_PREFS_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class Value;
+}
+
+// This is an abstract interface for reading and writing from/to a persistent
+// preference store, used by PrefService. An implementation using a JSON file
+// can be found in JsonPrefStore, while an implementation without any backing
+// store for testing can be found in TestingPrefStore. Furthermore, there is
+// CommandLinePrefStore, which bridges command line options to preferences and
+// ConfigurationPolicyPrefStore, which is used for hooking up configuration
+// policy with the preference subsystem.
+class BASE_PREFS_EXPORT PrefStore : public base::RefCounted<PrefStore> {
+ public:
+  // Observer interface for monitoring PrefStore.
+  class BASE_PREFS_EXPORT Observer {
+   public:
+    // Called when the value for the given |key| in the store changes.
+    virtual void OnPrefValueChanged(const std::string& key) = 0;
+    // Notification about the PrefStore being fully initialized.
+    virtual void OnInitializationCompleted(bool succeeded) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  PrefStore() {}
+
+  // Add and remove observers.
+  virtual void AddObserver(Observer* observer) {}
+  virtual void RemoveObserver(Observer* observer) {}
+  virtual bool HasObservers() const;
+
+  // Whether the store has completed all asynchronous initialization.
+  virtual bool IsInitializationComplete() const;
+
+  // Get the value for a given preference |key| and stores it in |*result|.
+  // |*result| is only modified if the return value is true and if |result|
+  // is not NULL. Ownership of the |*result| value remains with the PrefStore.
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const = 0;
+
+ protected:
+  friend class base::RefCounted<PrefStore>;
+  virtual ~PrefStore() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefStore);
+};
+
+#endif  // BASE_PREFS_PREF_STORE_H_
diff --git a/base/prefs/pref_store_observer_mock.cc b/base/prefs/pref_store_observer_mock.cc
new file mode 100644
index 0000000..f1a31bb
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_store_observer_mock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+PrefStoreObserverMock::PrefStoreObserverMock()
+    : initialized(false), initialization_success(false) {}
+
+PrefStoreObserverMock::~PrefStoreObserverMock() {}
+
+void PrefStoreObserverMock::VerifyAndResetChangedKey(
+    const std::string& expected) {
+  EXPECT_EQ(1u, changed_keys.size());
+  if (changed_keys.size() >= 1)
+    EXPECT_EQ(expected, changed_keys.front());
+  changed_keys.clear();
+}
+
+void PrefStoreObserverMock::OnPrefValueChanged(const std::string& key) {
+  changed_keys.push_back(key);
+}
+
+void PrefStoreObserverMock::OnInitializationCompleted(bool success) {
+  initialized = true;
+  initialization_success = success;
+}
diff --git a/base/prefs/pref_store_observer_mock.h b/base/prefs/pref_store_observer_mock.h
new file mode 100644
index 0000000..1b24b4e
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+#define BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/prefs/pref_store.h"
+
+// A mock implementation of PrefStore::Observer.
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+  PrefStoreObserverMock();
+  ~PrefStoreObserverMock() override;
+
+  void VerifyAndResetChangedKey(const std::string& expected);
+
+  // PrefStore::Observer implementation
+  void OnPrefValueChanged(const std::string& key) override;
+  void OnInitializationCompleted(bool success) override;
+
+  std::vector<std::string> changed_keys;
+  bool initialized;
+  bool initialization_success;  // Only valid if |initialized|.
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefStoreObserverMock);
+};
+
+#endif  // BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc
new file mode 100644
index 0000000..5f2dc50
--- /dev/null
+++ b/base/prefs/pref_value_map.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_value_map.h"
+
+#include <map>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+PrefValueMap::PrefValueMap() {}
+
+PrefValueMap::~PrefValueMap() {
+  Clear();
+}
+
+bool PrefValueMap::GetValue(const std::string& key,
+                            const base::Value** value) const {
+  const Map::const_iterator entry = prefs_.find(key);
+  if (entry == prefs_.end())
+    return false;
+
+  if (value)
+    *value = entry->second;
+  return true;
+}
+
+bool PrefValueMap::GetValue(const std::string& key, base::Value** value) {
+  const Map::const_iterator entry = prefs_.find(key);
+  if (entry == prefs_.end())
+    return false;
+
+  if (value)
+    *value = entry->second;
+  return true;
+}
+
+bool PrefValueMap::SetValue(const std::string& key, base::Value* value) {
+  DCHECK(value);
+  auto result = prefs_.insert(std::make_pair(key, value));
+  if (result.second)
+    return true;
+
+  scoped_ptr<base::Value> value_ptr(value);
+  const Map::iterator& entry = result.first;
+  if (base::Value::Equals(entry->second, value))
+    return false;
+
+  delete entry->second;
+  entry->second = value_ptr.release();
+
+  return true;
+}
+
+bool PrefValueMap::RemoveValue(const std::string& key) {
+  const Map::iterator entry = prefs_.find(key);
+  if (entry == prefs_.end())
+    return false;
+
+  delete entry->second;
+  prefs_.erase(entry);
+  return true;
+}
+
+void PrefValueMap::Clear() {
+  STLDeleteValues(&prefs_);
+}
+
+void PrefValueMap::Swap(PrefValueMap* other) {
+  prefs_.swap(other->prefs_);
+}
+
+PrefValueMap::iterator PrefValueMap::begin() {
+  return prefs_.begin();
+}
+
+PrefValueMap::iterator PrefValueMap::end() {
+  return prefs_.end();
+}
+
+PrefValueMap::const_iterator PrefValueMap::begin() const {
+  return prefs_.begin();
+}
+
+PrefValueMap::const_iterator PrefValueMap::end() const {
+  return prefs_.end();
+}
+
+bool PrefValueMap::GetBoolean(const std::string& key,
+                              bool* value) const {
+  const base::Value* stored_value = nullptr;
+  return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value);
+}
+
+void PrefValueMap::SetBoolean(const std::string& key, bool value) {
+  SetValue(key, new base::FundamentalValue(value));
+}
+
+bool PrefValueMap::GetString(const std::string& key,
+                             std::string* value) const {
+  const base::Value* stored_value = nullptr;
+  return GetValue(key, &stored_value) && stored_value->GetAsString(value);
+}
+
+void PrefValueMap::SetString(const std::string& key,
+                             const std::string& value) {
+  SetValue(key, new base::StringValue(value));
+}
+
+bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
+  const base::Value* stored_value = nullptr;
+  return GetValue(key, &stored_value) && stored_value->GetAsInteger(value);
+}
+
+void PrefValueMap::SetInteger(const std::string& key, const int value) {
+  SetValue(key, new base::FundamentalValue(value));
+}
+
+void PrefValueMap::SetDouble(const std::string& key, const double value) {
+  SetValue(key, new base::FundamentalValue(value));
+}
+
+void PrefValueMap::GetDifferingKeys(
+    const PrefValueMap* other,
+    std::vector<std::string>* differing_keys) const {
+  differing_keys->clear();
+
+  // Put everything into ordered maps.
+  std::map<std::string, base::Value*> this_prefs(prefs_.begin(), prefs_.end());
+  std::map<std::string, base::Value*> other_prefs(other->prefs_.begin(),
+                                                  other->prefs_.end());
+
+  // Walk over the maps in lockstep, adding everything that is different.
+  auto this_pref(this_prefs.begin());
+  auto other_pref(other_prefs.begin());
+  while (this_pref != this_prefs.end() && other_pref != other_prefs.end()) {
+    const int diff = this_pref->first.compare(other_pref->first);
+    if (diff == 0) {
+      if (!this_pref->second->Equals(other_pref->second))
+        differing_keys->push_back(this_pref->first);
+      ++this_pref;
+      ++other_pref;
+    } else if (diff < 0) {
+      differing_keys->push_back(this_pref->first);
+      ++this_pref;
+    } else if (diff > 0) {
+      differing_keys->push_back(other_pref->first);
+      ++other_pref;
+    }
+  }
+
+  // Add the remaining entries.
+  for ( ; this_pref != this_prefs.end(); ++this_pref)
+      differing_keys->push_back(this_pref->first);
+  for ( ; other_pref != other_prefs.end(); ++other_pref)
+      differing_keys->push_back(other_pref->first);
+}
diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h
new file mode 100644
index 0000000..12b30c6
--- /dev/null
+++ b/base/prefs/pref_value_map.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_VALUE_MAP_H_
+#define BASE_PREFS_PREF_VALUE_MAP_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class Value;
+}
+
+// A generic string to value map used by the PrefStore implementations.
+class BASE_PREFS_EXPORT PrefValueMap {
+ public:
+  using Map = base::hash_map<std::string, base::Value*>;
+  using iterator = Map::iterator;
+  using const_iterator = Map::const_iterator;
+
+  PrefValueMap();
+  virtual ~PrefValueMap();
+
+  // Gets the value for |key| and stores it in |value|. Ownership remains with
+  // the map. Returns true if a value is present. If not, |value| is not
+  // touched.
+  bool GetValue(const std::string& key, const base::Value** value) const;
+  bool GetValue(const std::string& key, base::Value** value);
+
+  // Sets a new |value| for |key|. Takes ownership of |value|, which must be
+  // non-NULL. Returns true if the value changed.
+  bool SetValue(const std::string& key, base::Value* value);
+
+  // Removes the value for |key| from the map. Returns true if a value was
+  // removed.
+  bool RemoveValue(const std::string& key);
+
+  // Clears the map.
+  void Clear();
+
+  // Swaps the contents of two maps.
+  void Swap(PrefValueMap* other);
+
+  iterator begin();
+  iterator end();
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  // Gets a boolean value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Sets the value for |key| to the boolean |value|.
+  void SetBoolean(const std::string& key, bool value);
+
+  // Gets a string value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetString(const std::string& key, std::string* value) const;
+
+  // Sets the value for |key| to the string |value|.
+  void SetString(const std::string& key, const std::string& value);
+
+  // Gets an int value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetInteger(const std::string& key, int* value) const;
+
+  // Sets the value for |key| to the int |value|.
+  void SetInteger(const std::string& key, const int value);
+
+  // Sets the value for |key| to the double |value|.
+  void SetDouble(const std::string& key, const double value);
+
+  // Compares this value map against |other| and stores all key names that have
+  // different values in |differing_keys|. This includes keys that are present
+  // only in one of the maps.
+  void GetDifferingKeys(const PrefValueMap* other,
+                        std::vector<std::string>* differing_keys) const;
+
+ private:
+  Map prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefValueMap);
+};
+
+#endif  // BASE_PREFS_PREF_VALUE_MAP_H_
diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc
new file mode 100644
index 0000000..82499da
--- /dev/null
+++ b/base/prefs/pref_value_map_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_value_map.h"
+
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(PrefValueMapTest, SetValue) {
+  PrefValueMap map;
+  const Value* result = NULL;
+  EXPECT_FALSE(map.GetValue("key", &result));
+  EXPECT_FALSE(result);
+
+  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_FALSE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", new StringValue("hi mom!")));
+
+  EXPECT_TRUE(map.GetValue("key", &result));
+  EXPECT_TRUE(StringValue("hi mom!").Equals(result));
+}
+
+TEST(PrefValueMapTest, GetAndSetIntegerValue) {
+  PrefValueMap map;
+  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5)));
+
+  int int_value = 0;
+  EXPECT_TRUE(map.GetInteger("key", &int_value));
+  EXPECT_EQ(5, int_value);
+
+  map.SetInteger("key", -14);
+  EXPECT_TRUE(map.GetInteger("key", &int_value));
+  EXPECT_EQ(-14, int_value);
+}
+
+TEST(PrefValueMapTest, SetDoubleValue) {
+  PrefValueMap map;
+  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5.5)));
+
+  const Value* result = NULL;
+  ASSERT_TRUE(map.GetValue("key", &result));
+  double double_value = 0.;
+  EXPECT_TRUE(result->GetAsDouble(&double_value));
+  EXPECT_DOUBLE_EQ(5.5, double_value);
+}
+
+TEST(PrefValueMapTest, RemoveValue) {
+  PrefValueMap map;
+  EXPECT_FALSE(map.RemoveValue("key"));
+
+  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.GetValue("key", NULL));
+
+  EXPECT_TRUE(map.RemoveValue("key"));
+  EXPECT_FALSE(map.GetValue("key", NULL));
+
+  EXPECT_FALSE(map.RemoveValue("key"));
+}
+
+TEST(PrefValueMapTest, Clear) {
+  PrefValueMap map;
+  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.GetValue("key", NULL));
+
+  map.Clear();
+
+  EXPECT_FALSE(map.GetValue("key", NULL));
+}
+
+TEST(PrefValueMapTest, GetDifferingKeys) {
+  PrefValueMap reference;
+  EXPECT_TRUE(reference.SetValue("b", new StringValue("test")));
+  EXPECT_TRUE(reference.SetValue("c", new StringValue("test")));
+  EXPECT_TRUE(reference.SetValue("e", new StringValue("test")));
+
+  PrefValueMap check;
+  std::vector<std::string> differing_paths;
+  std::vector<std::string> expected_differing_paths;
+
+  reference.GetDifferingKeys(&check, &differing_paths);
+  expected_differing_paths.push_back("b");
+  expected_differing_paths.push_back("c");
+  expected_differing_paths.push_back("e");
+  EXPECT_EQ(expected_differing_paths, differing_paths);
+
+  EXPECT_TRUE(check.SetValue("a", new StringValue("test")));
+  EXPECT_TRUE(check.SetValue("c", new StringValue("test")));
+  EXPECT_TRUE(check.SetValue("d", new StringValue("test")));
+
+  reference.GetDifferingKeys(&check, &differing_paths);
+  expected_differing_paths.clear();
+  expected_differing_paths.push_back("a");
+  expected_differing_paths.push_back("b");
+  expected_differing_paths.push_back("d");
+  expected_differing_paths.push_back("e");
+  EXPECT_EQ(expected_differing_paths, differing_paths);
+}
+
+TEST(PrefValueMapTest, SwapTwoMaps) {
+  PrefValueMap first_map;
+  EXPECT_TRUE(first_map.SetValue("a", new StringValue("test")));
+  EXPECT_TRUE(first_map.SetValue("b", new StringValue("test")));
+  EXPECT_TRUE(first_map.SetValue("c", new StringValue("test")));
+
+  PrefValueMap second_map;
+  EXPECT_TRUE(second_map.SetValue("d", new StringValue("test")));
+  EXPECT_TRUE(second_map.SetValue("e", new StringValue("test")));
+  EXPECT_TRUE(second_map.SetValue("f", new StringValue("test")));
+
+  first_map.Swap(&second_map);
+
+  EXPECT_TRUE(first_map.GetValue("d", NULL));
+  EXPECT_TRUE(first_map.GetValue("e", NULL));
+  EXPECT_TRUE(first_map.GetValue("f", NULL));
+
+  EXPECT_TRUE(second_map.GetValue("a", NULL));
+  EXPECT_TRUE(second_map.GetValue("b", NULL));
+  EXPECT_TRUE(second_map.GetValue("c", NULL));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/prefs/pref_value_store.cc b/base/prefs/pref_value_store.cc
new file mode 100644
index 0000000..1a0ec08
--- /dev/null
+++ b/base/prefs/pref_value_store.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_value_store.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_observer.h"
+
+PrefValueStore::PrefStoreKeeper::PrefStoreKeeper()
+    : pref_value_store_(NULL),
+      type_(PrefValueStore::INVALID_STORE) {
+}
+
+PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() {
+  if (pref_store_.get()) {
+    pref_store_->RemoveObserver(this);
+    pref_store_ = NULL;
+  }
+  pref_value_store_ = NULL;
+}
+
+void PrefValueStore::PrefStoreKeeper::Initialize(
+    PrefValueStore* store,
+    PrefStore* pref_store,
+    PrefValueStore::PrefStoreType type) {
+  if (pref_store_.get()) {
+    pref_store_->RemoveObserver(this);
+    DCHECK(!pref_store_->HasObservers());
+  }
+  type_ = type;
+  pref_value_store_ = store;
+  pref_store_ = pref_store;
+  if (pref_store_.get())
+    pref_store_->AddObserver(this);
+}
+
+void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged(
+    const std::string& key) {
+  pref_value_store_->OnPrefValueChanged(type_, key);
+}
+
+void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted(
+    bool succeeded) {
+  pref_value_store_->OnInitializationCompleted(type_, succeeded);
+}
+
+PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
+                               PrefStore* supervised_user_prefs,
+                               PrefStore* extension_prefs,
+                               PrefStore* command_line_prefs,
+                               PrefStore* user_prefs,
+                               PrefStore* recommended_prefs,
+                               PrefStore* default_prefs,
+                               PrefNotifier* pref_notifier)
+    : pref_notifier_(pref_notifier),
+      initialization_failed_(false) {
+  InitPrefStore(MANAGED_STORE, managed_prefs);
+  InitPrefStore(SUPERVISED_USER_STORE, supervised_user_prefs);
+  InitPrefStore(EXTENSION_STORE, extension_prefs);
+  InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
+  InitPrefStore(USER_STORE, user_prefs);
+  InitPrefStore(RECOMMENDED_STORE, recommended_prefs);
+  InitPrefStore(DEFAULT_STORE, default_prefs);
+
+  CheckInitializationCompleted();
+}
+
+PrefValueStore::~PrefValueStore() {}
+
+PrefValueStore* PrefValueStore::CloneAndSpecialize(
+    PrefStore* managed_prefs,
+    PrefStore* supervised_user_prefs,
+    PrefStore* extension_prefs,
+    PrefStore* command_line_prefs,
+    PrefStore* user_prefs,
+    PrefStore* recommended_prefs,
+    PrefStore* default_prefs,
+    PrefNotifier* pref_notifier) {
+  DCHECK(pref_notifier);
+  if (!managed_prefs)
+    managed_prefs = GetPrefStore(MANAGED_STORE);
+  if (!supervised_user_prefs)
+    supervised_user_prefs = GetPrefStore(SUPERVISED_USER_STORE);
+  if (!extension_prefs)
+    extension_prefs = GetPrefStore(EXTENSION_STORE);
+  if (!command_line_prefs)
+    command_line_prefs = GetPrefStore(COMMAND_LINE_STORE);
+  if (!user_prefs)
+    user_prefs = GetPrefStore(USER_STORE);
+  if (!recommended_prefs)
+    recommended_prefs = GetPrefStore(RECOMMENDED_STORE);
+  if (!default_prefs)
+    default_prefs = GetPrefStore(DEFAULT_STORE);
+
+  return new PrefValueStore(
+      managed_prefs, supervised_user_prefs, extension_prefs, command_line_prefs,
+      user_prefs, recommended_prefs, default_prefs, pref_notifier);
+}
+
+void PrefValueStore::set_callback(const PrefChangedCallback& callback) {
+  pref_changed_callback_ = callback;
+}
+
+bool PrefValueStore::GetValue(const std::string& name,
+                              base::Value::Type type,
+                              const base::Value** out_value) const {
+  // Check the |PrefStore|s in order of their priority from highest to lowest,
+  // looking for the first preference value with the given |name| and |type|.
+  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+    if (GetValueFromStoreWithType(name, type, static_cast<PrefStoreType>(i),
+                                  out_value))
+      return true;
+  }
+  return false;
+}
+
+bool PrefValueStore::GetRecommendedValue(const std::string& name,
+                                         base::Value::Type type,
+                                         const base::Value** out_value) const {
+  return GetValueFromStoreWithType(name, type, RECOMMENDED_STORE, out_value);
+}
+
+void PrefValueStore::NotifyPrefChanged(
+    const std::string& path,
+    PrefValueStore::PrefStoreType new_store) {
+  DCHECK(new_store != INVALID_STORE);
+  // A notification is sent when the pref value in any store changes. If this
+  // store is currently being overridden by a higher-priority store, the
+  // effective value of the pref will not have changed.
+  pref_notifier_->OnPreferenceChanged(path);
+  if (!pref_changed_callback_.is_null())
+    pref_changed_callback_.Run(path);
+}
+
+bool PrefValueStore::PrefValueInManagedStore(const std::string& name) const {
+  return PrefValueInStore(name, MANAGED_STORE);
+}
+
+bool PrefValueStore::PrefValueInSupervisedStore(const std::string& name) const {
+  return PrefValueInStore(name, SUPERVISED_USER_STORE);
+}
+
+bool PrefValueStore::PrefValueInExtensionStore(const std::string& name) const {
+  return PrefValueInStore(name, EXTENSION_STORE);
+}
+
+bool PrefValueStore::PrefValueInUserStore(const std::string& name) const {
+  return PrefValueInStore(name, USER_STORE);
+}
+
+bool PrefValueStore::PrefValueFromExtensionStore(
+    const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == EXTENSION_STORE;
+}
+
+bool PrefValueStore::PrefValueFromUserStore(const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == USER_STORE;
+}
+
+bool PrefValueStore::PrefValueFromRecommendedStore(
+    const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE;
+}
+
+bool PrefValueStore::PrefValueFromDefaultStore(const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == DEFAULT_STORE;
+}
+
+bool PrefValueStore::PrefValueUserModifiable(const std::string& name) const {
+  PrefStoreType effective_store = ControllingPrefStoreForPref(name);
+  return effective_store >= USER_STORE ||
+         effective_store == INVALID_STORE;
+}
+
+bool PrefValueStore::PrefValueExtensionModifiable(
+    const std::string& name) const {
+  PrefStoreType effective_store = ControllingPrefStoreForPref(name);
+  return effective_store >= EXTENSION_STORE ||
+         effective_store == INVALID_STORE;
+}
+
+void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) {
+  InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
+}
+
+bool PrefValueStore::PrefValueInStore(
+    const std::string& name,
+    PrefValueStore::PrefStoreType store) const {
+  // Declare a temp Value* and call GetValueFromStore,
+  // ignoring the output value.
+  const base::Value* tmp_value = NULL;
+  return GetValueFromStore(name, store, &tmp_value);
+}
+
+bool PrefValueStore::PrefValueInStoreRange(
+    const std::string& name,
+    PrefValueStore::PrefStoreType first_checked_store,
+    PrefValueStore::PrefStoreType last_checked_store) const {
+  if (first_checked_store > last_checked_store) {
+    NOTREACHED();
+    return false;
+  }
+
+  for (size_t i = first_checked_store;
+       i <= static_cast<size_t>(last_checked_store); ++i) {
+    if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
+      return true;
+  }
+  return false;
+}
+
+PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
+    const std::string& name) const {
+  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+    if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
+      return static_cast<PrefStoreType>(i);
+  }
+  return INVALID_STORE;
+}
+
+bool PrefValueStore::GetValueFromStore(const std::string& name,
+                                       PrefValueStore::PrefStoreType store_type,
+                                       const base::Value** out_value) const {
+  // Only return true if we find a value and it is the correct type, so stale
+  // values with the incorrect type will be ignored.
+  const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type));
+  if (store && store->GetValue(name, out_value))
+    return true;
+
+  // No valid value found for the given preference name: set the return value
+  // to false.
+  *out_value = NULL;
+  return false;
+}
+
+bool PrefValueStore::GetValueFromStoreWithType(
+    const std::string& name,
+    base::Value::Type type,
+    PrefStoreType store,
+    const base::Value** out_value) const {
+  if (GetValueFromStore(name, store, out_value)) {
+    if ((*out_value)->IsType(type))
+      return true;
+
+    LOG(WARNING) << "Expected type for " << name << " is " << type
+                 << " but got " << (*out_value)->GetType()
+                 << " in store " << store;
+  }
+
+  *out_value = NULL;
+  return false;
+}
+
+void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type,
+                                        const std::string& key) {
+  NotifyPrefChanged(key, type);
+}
+
+void PrefValueStore::OnInitializationCompleted(
+    PrefValueStore::PrefStoreType type, bool succeeded) {
+  if (initialization_failed_)
+    return;
+  if (!succeeded) {
+    initialization_failed_ = true;
+    pref_notifier_->OnInitializationCompleted(false);
+    return;
+  }
+  CheckInitializationCompleted();
+}
+
+void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type,
+                                   PrefStore* pref_store) {
+  pref_stores_[type].Initialize(this, pref_store, type);
+}
+
+void PrefValueStore::CheckInitializationCompleted() {
+  if (initialization_failed_)
+    return;
+  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+    scoped_refptr<PrefStore> store =
+        GetPrefStore(static_cast<PrefStoreType>(i));
+    if (store.get() && !store->IsInitializationComplete())
+      return;
+  }
+  pref_notifier_->OnInitializationCompleted(true);
+}
diff --git a/base/prefs/pref_value_store.h b/base/prefs/pref_value_store.h
new file mode 100644
index 0000000..5160115
--- /dev/null
+++ b/base/prefs/pref_value_store.h
@@ -0,0 +1,268 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_VALUE_STORE_H_
+#define BASE_PREFS_PREF_VALUE_STORE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+#include "base/values.h"
+
+class PrefNotifier;
+class PrefStore;
+
+// The PrefValueStore manages various sources of values for Preferences
+// (e.g., configuration policies, extensions, and user settings). It returns
+// the value of a Preference from the source with the highest priority, and
+// allows setting user-defined values for preferences that are not managed.
+//
+// Unless otherwise explicitly noted, all of the methods of this class must
+// be called on the UI thread.
+class BASE_PREFS_EXPORT PrefValueStore {
+ public:
+  typedef base::Callback<void(const std::string&)> PrefChangedCallback;
+
+  // In decreasing order of precedence:
+  //   |managed_prefs| contains all preferences from mandatory policies.
+  //   |supervised_user_prefs| contains all preferences from supervised user
+  //        settings, i.e. settings configured for a supervised user by their
+  //        custodian.
+  //   |extension_prefs| contains preference values set by extensions.
+  //   |command_line_prefs| contains preference values set by command-line
+  //        switches.
+  //   |user_prefs| contains all user-set preference values.
+  //   |recommended_prefs| contains all preferences from recommended policies.
+  //   |default_prefs| contains application-default preference values. It must
+  //        be non-null if any preferences are to be registered.
+  //
+  // |pref_notifier| facilitates broadcasting preference change notifications
+  // to the world.
+  PrefValueStore(PrefStore* managed_prefs,
+                 PrefStore* supervised_user_prefs,
+                 PrefStore* extension_prefs,
+                 PrefStore* command_line_prefs,
+                 PrefStore* user_prefs,
+                 PrefStore* recommended_prefs,
+                 PrefStore* default_prefs,
+                 PrefNotifier* pref_notifier);
+  virtual ~PrefValueStore();
+
+  // Creates a clone of this PrefValueStore with PrefStores overwritten
+  // by the parameters passed, if unequal NULL.
+  PrefValueStore* CloneAndSpecialize(PrefStore* managed_prefs,
+                                     PrefStore* supervised_user_prefs,
+                                     PrefStore* extension_prefs,
+                                     PrefStore* command_line_prefs,
+                                     PrefStore* user_prefs,
+                                     PrefStore* recommended_prefs,
+                                     PrefStore* default_prefs,
+                                     PrefNotifier* pref_notifier);
+
+  // A PrefValueStore can have exactly one callback that is directly
+  // notified of preferences changing in the store. This does not
+  // filter through the PrefNotifier mechanism, which may not forward
+  // certain changes (e.g. unregistered prefs).
+  void set_callback(const PrefChangedCallback& callback);
+
+  // Gets the value for the given preference name that has the specified value
+  // type. Values stored in a PrefStore that have the matching |name| but
+  // a non-matching |type| are silently skipped. Returns true if a valid value
+  // was found in any of the available PrefStores. Most callers should use
+  // Preference::GetValue() instead of calling this method directly.
+  bool GetValue(const std::string& name,
+                base::Value::Type type,
+                const base::Value** out_value) const;
+
+  // Gets the recommended value for the given preference name that has the
+  // specified value type. A value stored in the recommended PrefStore that has
+  // the matching |name| but a non-matching |type| is silently ignored. Returns
+  // true if a valid value was found. Most callers should use
+  // Preference::GetRecommendedValue() instead of calling this method directly.
+  bool GetRecommendedValue(const std::string& name,
+                           base::Value::Type type,
+                           const base::Value** out_value) const;
+
+  // These methods return true if a preference with the given name is in the
+  // indicated pref store, even if that value is currently being overridden by
+  // a higher-priority source.
+  bool PrefValueInManagedStore(const std::string& name) const;
+  bool PrefValueInSupervisedStore(const std::string& name) const;
+  bool PrefValueInExtensionStore(const std::string& name) const;
+  bool PrefValueInUserStore(const std::string& name) const;
+
+  // These methods return true if a preference with the given name is actually
+  // being controlled by the indicated pref store and not being overridden by
+  // a higher-priority source.
+  bool PrefValueFromExtensionStore(const std::string& name) const;
+  bool PrefValueFromUserStore(const std::string& name) const;
+  bool PrefValueFromRecommendedStore(const std::string& name) const;
+  bool PrefValueFromDefaultStore(const std::string& name) const;
+
+  // Check whether a Preference value is modifiable by the user, i.e. whether
+  // there is no higher-priority source controlling it.
+  bool PrefValueUserModifiable(const std::string& name) const;
+
+  // Check whether a Preference value is modifiable by an extension, i.e.
+  // whether there is no higher-priority source controlling it.
+  bool PrefValueExtensionModifiable(const std::string& name) const;
+
+  // Update the command line PrefStore with |command_line_prefs|.
+  void UpdateCommandLinePrefStore(PrefStore* command_line_prefs);
+
+ private:
+  // PrefStores must be listed here in order from highest to lowest priority.
+  //   MANAGED contains all managed preference values that are provided by
+  //      mandatory policies (e.g. Windows Group Policy or cloud policy).
+  //   SUPERVISED_USER contains preferences that are valid for supervised users.
+  //   EXTENSION contains preference values set by extensions.
+  //   COMMAND_LINE contains preference values set by command-line switches.
+  //   USER contains all user-set preference values.
+  //   RECOMMENDED contains all preferences that are provided by recommended
+  //      policies.
+  //   DEFAULT contains all application default preference values.
+  enum PrefStoreType {
+    // INVALID_STORE is not associated with an actual PrefStore but used as
+    // an invalid marker, e.g. as a return value.
+    INVALID_STORE = -1,
+    MANAGED_STORE = 0,
+    SUPERVISED_USER_STORE,
+    EXTENSION_STORE,
+    COMMAND_LINE_STORE,
+    USER_STORE,
+    RECOMMENDED_STORE,
+    DEFAULT_STORE,
+    PREF_STORE_TYPE_MAX = DEFAULT_STORE
+  };
+
+  // Keeps a PrefStore reference on behalf of the PrefValueStore and monitors
+  // the PrefStore for changes, forwarding notifications to PrefValueStore. This
+  // indirection is here for the sake of disambiguating notifications from the
+  // individual PrefStores.
+  class PrefStoreKeeper : public PrefStore::Observer {
+   public:
+    PrefStoreKeeper();
+    ~PrefStoreKeeper() override;
+
+    // Takes ownership of |pref_store|.
+    void Initialize(PrefValueStore* store,
+                    PrefStore* pref_store,
+                    PrefStoreType type);
+
+    PrefStore* store() { return pref_store_.get(); }
+    const PrefStore* store() const { return pref_store_.get(); }
+
+   private:
+    // PrefStore::Observer implementation.
+    void OnPrefValueChanged(const std::string& key) override;
+    void OnInitializationCompleted(bool succeeded) override;
+
+    // PrefValueStore this keeper is part of.
+    PrefValueStore* pref_value_store_;
+
+    // The PrefStore managed by this keeper.
+    scoped_refptr<PrefStore> pref_store_;
+
+    // Type of the pref store.
+    PrefStoreType type_;
+
+    DISALLOW_COPY_AND_ASSIGN(PrefStoreKeeper);
+  };
+
+  typedef std::map<std::string, base::Value::Type> PrefTypeMap;
+
+  friend class PrefValueStorePolicyRefreshTest;
+  FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, TestPolicyRefresh);
+  FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest,
+                           TestRefreshPolicyPrefsCompletion);
+  FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest,
+                           TestConcurrentPolicyRefresh);
+
+  // Returns true if the preference with the given name has a value in the
+  // given PrefStoreType, of the same value type as the preference was
+  // registered with.
+  bool PrefValueInStore(const std::string& name, PrefStoreType store) const;
+
+  // Returns true if a preference has an explicit value in any of the
+  // stores in the range specified by |first_checked_store| and
+  // |last_checked_store|, even if that value is currently being
+  // overridden by a higher-priority store.
+  bool PrefValueInStoreRange(const std::string& name,
+                             PrefStoreType first_checked_store,
+                             PrefStoreType last_checked_store) const;
+
+  // Returns the pref store type identifying the source that controls the
+  // Preference identified by |name|. If none of the sources has a value,
+  // INVALID_STORE is returned. In practice, the default PrefStore
+  // should always have a value for any registered preferencem, so INVALID_STORE
+  // indicates an error.
+  PrefStoreType ControllingPrefStoreForPref(const std::string& name) const;
+
+  // Get a value from the specified |store|.
+  bool GetValueFromStore(const std::string& name,
+                         PrefStoreType store,
+                         const base::Value** out_value) const;
+
+  // Get a value from the specified |store| if its |type| matches.
+  bool GetValueFromStoreWithType(const std::string& name,
+                                 base::Value::Type type,
+                                 PrefStoreType store,
+                                 const base::Value** out_value) const;
+
+  // Called upon changes in individual pref stores in order to determine whether
+  // the user-visible pref value has changed. Triggers the change notification
+  // if the effective value of the preference has changed, or if the store
+  // controlling the pref has changed.
+  void NotifyPrefChanged(const std::string& path, PrefStoreType new_store);
+
+  // Called from the PrefStoreKeeper implementation when a pref value for |key|
+  // changed in the pref store for |type|.
+  void OnPrefValueChanged(PrefStoreType type, const std::string& key);
+
+  // Handle the event that the store for |type| has completed initialization.
+  void OnInitializationCompleted(PrefStoreType type, bool succeeded);
+
+  // Initializes a pref store keeper. Sets up a PrefStoreKeeper that will take
+  // ownership of the passed |pref_store|.
+  void InitPrefStore(PrefStoreType type, PrefStore* pref_store);
+
+  // Checks whether initialization is completed and tells the notifier if that
+  // is the case.
+  void CheckInitializationCompleted();
+
+  // Get the PrefStore pointer for the given type. May return NULL if there is
+  // no PrefStore for that type.
+  PrefStore* GetPrefStore(PrefStoreType type) {
+    return pref_stores_[type].store();
+  }
+  const PrefStore* GetPrefStore(PrefStoreType type) const {
+    return pref_stores_[type].store();
+  }
+
+  // Keeps the PrefStore references in order of precedence.
+  PrefStoreKeeper pref_stores_[PREF_STORE_TYPE_MAX + 1];
+
+  PrefChangedCallback pref_changed_callback_;
+
+  // Used for generating notifications. This is a weak reference,
+  // since the notifier is owned by the corresponding PrefService.
+  PrefNotifier* pref_notifier_;
+
+  // A mapping of preference names to their registered types.
+  PrefTypeMap pref_types_;
+
+  // True if not all of the PrefStores were initialized successfully.
+  bool initialization_failed_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefValueStore);
+};
+
+#endif  // BASE_PREFS_PREF_VALUE_STORE_H_
diff --git a/base/prefs/pref_value_store_unittest.cc b/base/prefs/pref_value_store_unittest.cc
new file mode 100644
index 0000000..e214adf
--- /dev/null
+++ b/base/prefs/pref_value_store_unittest.cc
@@ -0,0 +1,670 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::_;
+
+namespace {
+
+// Allows to capture pref notifications through gmock.
+class MockPrefNotifier : public PrefNotifier {
+ public:
+  MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+// Allows to capture sync model associator interaction.
+class MockPrefModelAssociator {
+ public:
+  MOCK_METHOD1(ProcessPrefChange, void(const std::string&));
+};
+
+}  // namespace
+
+// Names of the preferences used in this test.
+namespace prefs {
+const char kManagedPref[] = "this.pref.managed";
+const char kSupervisedUserPref[] = "this.pref.supervised_user";
+const char kCommandLinePref[] = "this.pref.command_line";
+const char kExtensionPref[] = "this.pref.extension";
+const char kUserPref[] = "this.pref.user";
+const char kRecommendedPref[] = "this.pref.recommended";
+const char kDefaultPref[] = "this.pref.default";
+const char kMissingPref[] = "this.pref.does_not_exist";
+}
+
+// Potentially expected values of all preferences used in this test program.
+namespace managed_pref {
+const char kManagedValue[] = "managed:managed";
+}
+
+namespace supervised_user_pref {
+const char kManagedValue[] = "supervised_user:managed";
+const char kSupervisedUserValue[] = "supervised_user:supervised_user";
+}
+
+namespace extension_pref {
+const char kManagedValue[] = "extension:managed";
+const char kSupervisedUserValue[] = "extension:supervised_user";
+const char kExtensionValue[] = "extension:extension";
+}
+
+namespace command_line_pref {
+const char kManagedValue[] = "command_line:managed";
+const char kSupervisedUserValue[] = "command_line:supervised_user";
+const char kExtensionValue[] = "command_line:extension";
+const char kCommandLineValue[] = "command_line:command_line";
+}
+
+namespace user_pref {
+const char kManagedValue[] = "user:managed";
+const char kSupervisedUserValue[] = "supervised_user:supervised_user";
+const char kExtensionValue[] = "user:extension";
+const char kCommandLineValue[] = "user:command_line";
+const char kUserValue[] = "user:user";
+}
+
+namespace recommended_pref {
+const char kManagedValue[] = "recommended:managed";
+const char kSupervisedUserValue[] = "recommended:supervised_user";
+const char kExtensionValue[] = "recommended:extension";
+const char kCommandLineValue[] = "recommended:command_line";
+const char kUserValue[] = "recommended:user";
+const char kRecommendedValue[] = "recommended:recommended";
+}
+
+namespace default_pref {
+const char kManagedValue[] = "default:managed";
+const char kSupervisedUserValue[] = "default:supervised_user";
+const char kExtensionValue[] = "default:extension";
+const char kCommandLineValue[] = "default:command_line";
+const char kUserValue[] = "default:user";
+const char kRecommendedValue[] = "default:recommended";
+const char kDefaultValue[] = "default:default";
+}
+
+class PrefValueStoreTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Create TestingPrefStores.
+    CreateManagedPrefs();
+    CreateSupervisedUserPrefs();
+    CreateExtensionPrefs();
+    CreateCommandLinePrefs();
+    CreateUserPrefs();
+    CreateRecommendedPrefs();
+    CreateDefaultPrefs();
+    sync_associator_.reset(new MockPrefModelAssociator());
+
+    // Create a fresh PrefValueStore.
+    pref_value_store_.reset(
+        new PrefValueStore(managed_pref_store_.get(),
+                           supervised_user_pref_store_.get(),
+                           extension_pref_store_.get(),
+                           command_line_pref_store_.get(),
+                           user_pref_store_.get(),
+                           recommended_pref_store_.get(),
+                           default_pref_store_.get(),
+                           &pref_notifier_));
+
+    pref_value_store_->set_callback(
+        base::Bind(&MockPrefModelAssociator::ProcessPrefChange,
+                   base::Unretained(sync_associator_.get())));
+  }
+
+  void CreateManagedPrefs() {
+    managed_pref_store_ = new TestingPrefStore;
+    managed_pref_store_->SetString(
+        prefs::kManagedPref,
+        managed_pref::kManagedValue);
+  }
+
+  void CreateSupervisedUserPrefs() {
+    supervised_user_pref_store_ = new TestingPrefStore;
+    supervised_user_pref_store_->SetString(
+        prefs::kManagedPref,
+        supervised_user_pref::kManagedValue);
+    supervised_user_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        supervised_user_pref::kSupervisedUserValue);
+  }
+
+  void CreateExtensionPrefs() {
+    extension_pref_store_ = new TestingPrefStore;
+    extension_pref_store_->SetString(
+        prefs::kManagedPref,
+        extension_pref::kManagedValue);
+    extension_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        extension_pref::kSupervisedUserValue);
+    extension_pref_store_->SetString(
+        prefs::kExtensionPref,
+        extension_pref::kExtensionValue);
+  }
+
+  void CreateCommandLinePrefs() {
+    command_line_pref_store_ = new TestingPrefStore;
+    command_line_pref_store_->SetString(
+        prefs::kManagedPref,
+        command_line_pref::kManagedValue);
+    command_line_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        command_line_pref::kSupervisedUserValue);
+    command_line_pref_store_->SetString(
+        prefs::kExtensionPref,
+        command_line_pref::kExtensionValue);
+    command_line_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        command_line_pref::kCommandLineValue);
+  }
+
+  void CreateUserPrefs() {
+    user_pref_store_ = new TestingPrefStore;
+    user_pref_store_->SetString(
+        prefs::kManagedPref,
+        user_pref::kManagedValue);
+    user_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        user_pref::kSupervisedUserValue);
+    user_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        user_pref::kCommandLineValue);
+    user_pref_store_->SetString(
+        prefs::kExtensionPref,
+        user_pref::kExtensionValue);
+    user_pref_store_->SetString(
+        prefs::kUserPref,
+        user_pref::kUserValue);
+  }
+
+  void CreateRecommendedPrefs() {
+    recommended_pref_store_ = new TestingPrefStore;
+    recommended_pref_store_->SetString(
+        prefs::kManagedPref,
+        recommended_pref::kManagedValue);
+    recommended_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        recommended_pref::kSupervisedUserValue);
+    recommended_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        recommended_pref::kCommandLineValue);
+    recommended_pref_store_->SetString(
+        prefs::kExtensionPref,
+        recommended_pref::kExtensionValue);
+    recommended_pref_store_->SetString(
+        prefs::kUserPref,
+        recommended_pref::kUserValue);
+    recommended_pref_store_->SetString(
+        prefs::kRecommendedPref,
+        recommended_pref::kRecommendedValue);
+  }
+
+  void CreateDefaultPrefs() {
+    default_pref_store_ = new TestingPrefStore;
+    default_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        default_pref::kSupervisedUserValue);
+    default_pref_store_->SetString(
+        prefs::kManagedPref,
+        default_pref::kManagedValue);
+    default_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        default_pref::kCommandLineValue);
+    default_pref_store_->SetString(
+        prefs::kExtensionPref,
+        default_pref::kExtensionValue);
+    default_pref_store_->SetString(
+        prefs::kUserPref,
+        default_pref::kUserValue);
+    default_pref_store_->SetString(
+        prefs::kRecommendedPref,
+        default_pref::kRecommendedValue);
+    default_pref_store_->SetString(
+        prefs::kDefaultPref,
+        default_pref::kDefaultValue);
+  }
+
+  void ExpectValueChangeNotifications(const std::string& name) {
+    EXPECT_CALL(pref_notifier_, OnPreferenceChanged(name));
+    EXPECT_CALL(*sync_associator_, ProcessPrefChange(name));
+  }
+
+  void CheckAndClearValueChangeNotifications() {
+    Mock::VerifyAndClearExpectations(&pref_notifier_);
+    Mock::VerifyAndClearExpectations(sync_associator_.get());
+  }
+
+  MockPrefNotifier pref_notifier_;
+  scoped_ptr<MockPrefModelAssociator> sync_associator_;
+  scoped_ptr<PrefValueStore> pref_value_store_;
+
+  scoped_refptr<TestingPrefStore> managed_pref_store_;
+  scoped_refptr<TestingPrefStore> supervised_user_pref_store_;
+  scoped_refptr<TestingPrefStore> extension_pref_store_;
+  scoped_refptr<TestingPrefStore> command_line_pref_store_;
+  scoped_refptr<TestingPrefStore> user_pref_store_;
+  scoped_refptr<TestingPrefStore> recommended_pref_store_;
+  scoped_refptr<TestingPrefStore> default_pref_store_;
+};
+
+TEST_F(PrefValueStoreTest, GetValue) {
+  const base::Value* value;
+
+  // The following tests read a value from the PrefService. The preferences are
+  // set in a way such that all lower-priority stores have a value and we can
+  // test whether overrides work correctly.
+
+  // Test getting a managed value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kManagedPref,
+                                          base::Value::TYPE_STRING, &value));
+  std::string actual_str_value;
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(managed_pref::kManagedValue, actual_str_value);
+
+  // Test getting a supervised user value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kSupervisedUserPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(supervised_user_pref::kSupervisedUserValue, actual_str_value);
+
+  // Test getting an extension value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kExtensionPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(extension_pref::kExtensionValue, actual_str_value);
+
+  // Test getting a command-line value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kCommandLinePref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(command_line_pref::kCommandLineValue, actual_str_value);
+
+  // Test getting a user-set value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kUserPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(user_pref::kUserValue, actual_str_value);
+
+  // Test getting a user set value overwriting a recommended value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kRecommendedPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kRecommendedValue,
+            actual_str_value);
+
+  // Test getting a default value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kDefaultPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(default_pref::kDefaultValue, actual_str_value);
+
+  // Test getting a preference value that the |PrefValueStore|
+  // does not contain.
+  base::FundamentalValue tmp_dummy_value(true);
+  value = &tmp_dummy_value;
+  ASSERT_FALSE(pref_value_store_->GetValue(prefs::kMissingPref,
+                                           base::Value::TYPE_STRING, &value));
+  ASSERT_FALSE(value);
+}
+
+TEST_F(PrefValueStoreTest, GetRecommendedValue) {
+  const base::Value* value;
+
+  // The following tests read a value from the PrefService. The preferences are
+  // set in a way such that all lower-priority stores have a value and we can
+  // test whether overrides do not clutter the recommended value.
+
+  // Test getting recommended value when a managed value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kManagedPref,
+      base::Value::TYPE_STRING, &value));
+  std::string actual_str_value;
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kManagedValue, actual_str_value);
+
+  // Test getting recommended value when a supervised user value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kSupervisedUserPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kSupervisedUserValue, actual_str_value);
+
+  // Test getting recommended value when an extension value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kExtensionPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kExtensionValue, actual_str_value);
+
+  // Test getting recommended value when a command-line value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kCommandLinePref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kCommandLineValue, actual_str_value);
+
+  // Test getting recommended value when a user-set value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kUserPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kUserValue, actual_str_value);
+
+  // Test getting recommended value when no higher-priority value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kRecommendedPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kRecommendedValue,
+            actual_str_value);
+
+  // Test getting recommended value when no recommended value is present.
+  base::FundamentalValue tmp_dummy_value(true);
+  value = &tmp_dummy_value;
+  ASSERT_FALSE(pref_value_store_->GetRecommendedValue(
+      prefs::kDefaultPref,
+      base::Value::TYPE_STRING, &value));
+  ASSERT_FALSE(value);
+
+  // Test getting a preference value that the |PrefValueStore|
+  // does not contain.
+  value = &tmp_dummy_value;
+  ASSERT_FALSE(pref_value_store_->GetRecommendedValue(
+      prefs::kMissingPref,
+      base::Value::TYPE_STRING, &value));
+  ASSERT_FALSE(value);
+}
+
+TEST_F(PrefValueStoreTest, PrefChanges) {
+  // Check pref controlled by highest-priority store.
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  managed_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  supervised_user_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  extension_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  command_line_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  user_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  recommended_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  default_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  // Check pref controlled by user store.
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  managed_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  extension_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  command_line_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  user_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  recommended_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  default_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  // Check pref controlled by default-pref store.
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  managed_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  extension_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  command_line_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  user_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  recommended_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  default_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+}
+
+TEST_F(PrefValueStoreTest, OnInitializationCompleted) {
+  EXPECT_CALL(pref_notifier_, OnInitializationCompleted(true)).Times(0);
+  managed_pref_store_->SetInitializationCompleted();
+  supervised_user_pref_store_->SetInitializationCompleted();
+  extension_pref_store_->SetInitializationCompleted();
+  command_line_pref_store_->SetInitializationCompleted();
+  recommended_pref_store_->SetInitializationCompleted();
+  default_pref_store_->SetInitializationCompleted();
+  Mock::VerifyAndClearExpectations(&pref_notifier_);
+
+  // The notification should only be triggered after the last store is done.
+  EXPECT_CALL(pref_notifier_, OnInitializationCompleted(true)).Times(1);
+  user_pref_store_->SetInitializationCompleted();
+  Mock::VerifyAndClearExpectations(&pref_notifier_);
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInManagedStore) {
+  EXPECT_TRUE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) {
+  EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kManagedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInUserStore) {
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kManagedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kExtensionPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromExtensionStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromUserStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromRecommendedStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kRecommendedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueUserModifiable) {
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kRecommendedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kDefaultPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueExtensionModifiable) {
+  EXPECT_FALSE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kExtensionPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kRecommendedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kDefaultPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kMissingPref));
+}
diff --git a/base/prefs/scoped_user_pref_update.cc b/base/prefs/scoped_user_pref_update.cc
new file mode 100644
index 0000000..1440a57
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.cc
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/scoped_user_pref_update.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_service.h"
+
+namespace subtle {
+
+ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service,
+                                                   const std::string& path)
+    : service_(service), path_(path), value_(NULL) {
+  DCHECK(service_->CalledOnValidThread());
+}
+
+ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() {
+  Notify();
+}
+
+base::Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) {
+  DCHECK(CalledOnValidThread());
+  if (!value_)
+    value_ = service_->GetMutableUserPref(path_, type);
+  return value_;
+}
+
+void ScopedUserPrefUpdateBase::Notify() {
+  if (value_) {
+    service_->ReportUserPrefChanged(path_);
+    value_ = NULL;
+  }
+}
+
+}  // namespace subtle
diff --git a/base/prefs/scoped_user_pref_update.h b/base/prefs/scoped_user_pref_update.h
new file mode 100644
index 0000000..f8bebfe
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.h
@@ -0,0 +1,108 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A helper class that assists preferences in firing notifications when lists
+// or dictionaries are changed.
+
+#ifndef BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+#define BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_service.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
+
+class PrefService;
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace subtle {
+
+// Base class for ScopedUserPrefUpdateTemplate that contains the parts
+// that do not depend on ScopedUserPrefUpdateTemplate's template parameter.
+//
+// We need this base class mostly for making it a friend of PrefService
+// and getting access to PrefService::GetMutableUserPref and
+// PrefService::ReportUserPrefChanged.
+class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe {
+ protected:
+  ScopedUserPrefUpdateBase(PrefService* service, const std::string& path);
+
+  // Calls Notify().
+  ~ScopedUserPrefUpdateBase();
+
+  // Sets |value_| to |service_|->GetMutableUserPref and returns it.
+  base::Value* GetValueOfType(base::Value::Type type);
+
+ private:
+  // If |value_| is not null, triggers a notification of PrefObservers and
+  // resets |value_|.
+  void Notify();
+
+  // Weak pointer.
+  PrefService* service_;
+  // Path of the preference being updated.
+  std::string path_;
+  // Cache of value from user pref store (set between Get() and Notify() calls).
+  base::Value* value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdateBase);
+};
+
+}  // namespace subtle
+
+// Class to support modifications to DictionaryValues and ListValues while
+// guaranteeing that PrefObservers are notified of changed values.
+//
+// This class may only be used on the UI thread as it requires access to the
+// PrefService.
+template <typename T, base::Value::Type type_enum_value>
+class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
+ public:
+  ScopedUserPrefUpdate(PrefService* service, const std::string& path)
+      : ScopedUserPrefUpdateBase(service, path) {}
+
+  // Triggers an update notification if Get() was called.
+  virtual ~ScopedUserPrefUpdate() {}
+
+  // Returns a mutable |T| instance that
+  // - is already in the user pref store, or
+  // - is (silently) created and written to the user pref store if none existed
+  //   before.
+  //
+  // Calling Get() implies that an update notification is necessary at
+  // destruction time.
+  //
+  // The ownership of the return value remains with the user pref store.
+  // Virtual so it can be overriden in subclasses that transform the value
+  // before returning it (for example to return a subelement of a dictionary).
+  virtual T* Get() {
+    return static_cast<T*>(GetValueOfType(type_enum_value));
+  }
+
+  T& operator*() {
+    return *Get();
+  }
+
+  T* operator->() {
+    return Get();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate);
+};
+
+typedef ScopedUserPrefUpdate<base::DictionaryValue,
+                             base::Value::TYPE_DICTIONARY>
+    DictionaryPrefUpdate;
+typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST>
+    ListPrefUpdate;
+
+#endif  // BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/base/prefs/scoped_user_pref_update_unittest.cc b/base/prefs/scoped_user_pref_update_unittest.cc
new file mode 100644
index 0000000..48e3dc4
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+class ScopedUserPrefUpdateTest : public testing::Test {
+ public:
+  ScopedUserPrefUpdateTest() : observer_(&prefs_) {}
+  ~ScopedUserPrefUpdateTest() override {}
+
+ protected:
+  void SetUp() override {
+    prefs_.registry()->RegisterDictionaryPref(kPref);
+    registrar_.Init(&prefs_);
+    registrar_.Add(kPref, observer_.GetCallback());
+  }
+
+  static const char kPref[];
+  static const char kKey[];
+  static const char kValue[];
+
+  TestingPrefServiceSimple prefs_;
+  MockPrefChangeCallback observer_;
+  PrefChangeRegistrar registrar_;
+};
+
+const char ScopedUserPrefUpdateTest::kPref[] = "name";
+const char ScopedUserPrefUpdateTest::kKey[] = "key";
+const char ScopedUserPrefUpdateTest::kValue[] = "value";
+
+TEST_F(ScopedUserPrefUpdateTest, RegularUse) {
+  // Dictionary that will be expected to be set at the end.
+  base::DictionaryValue expected_dictionary;
+  expected_dictionary.SetString(kKey, kValue);
+
+  {
+    EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+    DictionaryPrefUpdate update(&prefs_, kPref);
+    base::DictionaryValue* value = update.Get();
+    ASSERT_TRUE(value);
+    value->SetString(kKey, kValue);
+
+    // The dictionary was created for us but the creation should have happened
+    // silently without notifications.
+    Mock::VerifyAndClearExpectations(&observer_);
+
+    // Modifications happen online and are instantly visible, though.
+    const base::DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+    ASSERT_TRUE(current_value);
+    EXPECT_TRUE(expected_dictionary.Equals(current_value));
+
+    // Now we are leaving the scope of the update so we should be notified.
+    observer_.Expect(kPref, &expected_dictionary);
+  }
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  const base::DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+  ASSERT_TRUE(current_value);
+  EXPECT_TRUE(expected_dictionary.Equals(current_value));
+}
+
+TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) {
+  const base::DictionaryValue* old_value = prefs_.GetDictionary(kPref);
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  {
+    DictionaryPrefUpdate update(&prefs_, kPref);
+  }
+  const base::DictionaryValue* new_value = prefs_.GetDictionary(kPref);
+  EXPECT_EQ(old_value, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
diff --git a/base/prefs/testing_pref_service.cc b/base/prefs/testing_pref_service.cc
new file mode 100644
index 0000000..5899376
--- /dev/null
+++ b/base/prefs/testing_pref_service.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/testing_pref_service.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_value_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <>
+TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
+    TestingPrefStore* managed_prefs,
+    TestingPrefStore* user_prefs,
+    TestingPrefStore* recommended_prefs,
+    PrefRegistry* pref_registry,
+    PrefNotifierImpl* pref_notifier)
+    : PrefService(
+          pref_notifier,
+          new PrefValueStore(managed_prefs,
+                             NULL,
+                             NULL,
+                             NULL,
+                             user_prefs,
+                             recommended_prefs,
+                             pref_registry->defaults().get(),
+                             pref_notifier),
+          user_prefs,
+          pref_registry,
+          base::Bind(&TestingPrefServiceBase<PrefService,
+                                             PrefRegistry>::HandleReadError),
+          false),
+      managed_prefs_(managed_prefs),
+      user_prefs_(user_prefs),
+      recommended_prefs_(recommended_prefs) {}
+
+TestingPrefServiceSimple::TestingPrefServiceSimple()
+    : TestingPrefServiceBase<PrefService, PrefRegistry>(
+          new TestingPrefStore(),
+          new TestingPrefStore(),
+          new TestingPrefStore(),
+          new PrefRegistrySimple(),
+          new PrefNotifierImpl()) {}
+
+TestingPrefServiceSimple::~TestingPrefServiceSimple() {
+}
+
+PrefRegistrySimple* TestingPrefServiceSimple::registry() {
+  return static_cast<PrefRegistrySimple*>(DeprecatedGetPrefRegistry());
+}
diff --git a/base/prefs/testing_pref_service.h b/base/prefs/testing_pref_service.h
new file mode 100644
index 0000000..7587383
--- /dev/null
+++ b/base/prefs/testing_pref_service.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_TESTING_PREF_SERVICE_H_
+#define BASE_PREFS_TESTING_PREF_SERVICE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_registry.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/testing_pref_store.h"
+
+class PrefNotifierImpl;
+class PrefRegistrySimple;
+class TestingPrefStore;
+
+// A PrefService subclass for testing. It operates totally in memory and
+// provides additional API for manipulating preferences at the different levels
+// (managed, extension, user) conveniently.
+//
+// Use this via its specializations, e.g. TestingPrefServiceSimple.
+template <class SuperPrefService, class ConstructionPrefRegistry>
+class TestingPrefServiceBase : public SuperPrefService {
+ public:
+  virtual ~TestingPrefServiceBase();
+
+  // Read the value of a preference from the managed layer. Returns NULL if the
+  // preference is not defined at the managed layer.
+  const base::Value* GetManagedPref(const std::string& path) const;
+
+  // Set a preference on the managed layer and fire observers if the preference
+  // changed. Assumes ownership of |value|.
+  void SetManagedPref(const std::string& path, base::Value* value);
+
+  // Clear the preference on the managed layer and fire observers if the
+  // preference has been defined previously.
+  void RemoveManagedPref(const std::string& path);
+
+  // Similar to the above, but for user preferences.
+  const base::Value* GetUserPref(const std::string& path) const;
+  void SetUserPref(const std::string& path, base::Value* value);
+  void RemoveUserPref(const std::string& path);
+
+  // Similar to the above, but for recommended policy preferences.
+  const base::Value* GetRecommendedPref(const std::string& path) const;
+  void SetRecommendedPref(const std::string& path, base::Value* value);
+  void RemoveRecommendedPref(const std::string& path);
+
+  // Do-nothing implementation for TestingPrefService.
+  static void HandleReadError(PersistentPrefStore::PrefReadError error) {}
+
+ protected:
+  TestingPrefServiceBase(
+      TestingPrefStore* managed_prefs,
+      TestingPrefStore* user_prefs,
+      TestingPrefStore* recommended_prefs,
+      ConstructionPrefRegistry* pref_registry,
+      PrefNotifierImpl* pref_notifier);
+
+ private:
+  // Reads the value of the preference indicated by |path| from |pref_store|.
+  // Returns NULL if the preference was not found.
+  const base::Value* GetPref(TestingPrefStore* pref_store,
+                             const std::string& path) const;
+
+  // Sets the value for |path| in |pref_store|.
+  void SetPref(TestingPrefStore* pref_store,
+               const std::string& path,
+               base::Value* value);
+
+  // Removes the preference identified by |path| from |pref_store|.
+  void RemovePref(TestingPrefStore* pref_store, const std::string& path);
+
+  // Pointers to the pref stores our value store uses.
+  scoped_refptr<TestingPrefStore> managed_prefs_;
+  scoped_refptr<TestingPrefStore> user_prefs_;
+  scoped_refptr<TestingPrefStore> recommended_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceBase);
+};
+
+// Test version of PrefService.
+class TestingPrefServiceSimple
+    : public TestingPrefServiceBase<PrefService, PrefRegistry> {
+ public:
+  TestingPrefServiceSimple();
+  ~TestingPrefServiceSimple() override;
+
+  // This is provided as a convenience for registering preferences on
+  // an existing TestingPrefServiceSimple instance. On a production
+  // PrefService you would do all registrations before constructing
+  // it, passing it a PrefRegistry via its constructor (or via
+  // e.g. PrefServiceFactory).
+  PrefRegistrySimple* registry();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceSimple);
+};
+
+template<>
+TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
+    TestingPrefStore* managed_prefs,
+    TestingPrefStore* user_prefs,
+    TestingPrefStore* recommended_prefs,
+    PrefRegistry* pref_registry,
+    PrefNotifierImpl* pref_notifier);
+
+template<class SuperPrefService, class ConstructionPrefRegistry>
+TestingPrefServiceBase<
+    SuperPrefService, ConstructionPrefRegistry>::~TestingPrefServiceBase() {
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value* TestingPrefServiceBase<
+    SuperPrefService,
+    ConstructionPrefRegistry>::GetManagedPref(const std::string& path) const {
+  return GetPref(managed_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetManagedPref(const std::string& path, base::Value* value) {
+  SetPref(managed_prefs_.get(), path, value);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemoveManagedPref(const std::string& path) {
+  RemovePref(managed_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetUserPref(
+    const std::string& path) const {
+  return GetPref(user_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetUserPref(const std::string& path, base::Value* value) {
+  SetPref(user_prefs_.get(), path, value);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemoveUserPref(const std::string& path) {
+  RemovePref(user_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    GetRecommendedPref(const std::string& path) const {
+  return GetPref(recommended_prefs_, path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetRecommendedPref(const std::string& path, base::Value* value) {
+  SetPref(recommended_prefs_.get(), path, value);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemoveRecommendedPref(const std::string& path) {
+  RemovePref(recommended_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetPref(
+    TestingPrefStore* pref_store,
+    const std::string& path) const {
+  const base::Value* res;
+  return pref_store->GetValue(path, &res) ? res : NULL;
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetPref(TestingPrefStore* pref_store,
+            const std::string& path,
+            base::Value* value) {
+  pref_store->SetValue(path, value,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemovePref(TestingPrefStore* pref_store, const std::string& path) {
+  pref_store->RemoveValue(path, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+#endif  // BASE_PREFS_TESTING_PREF_SERVICE_H_
diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc
new file mode 100644
index 0000000..35c9763
--- /dev/null
+++ b/base/prefs/testing_pref_store.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/testing_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+TestingPrefStore::TestingPrefStore()
+    : read_only_(true),
+      read_success_(true),
+      read_error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
+      block_async_read_(false),
+      pending_async_read_(false),
+      init_complete_(false),
+      committed_(true) {}
+
+bool TestingPrefStore::GetValue(const std::string& key,
+                                const base::Value** value) const {
+  return prefs_.GetValue(key, value);
+}
+
+bool TestingPrefStore::GetMutableValue(const std::string& key,
+                                       base::Value** value) {
+  return prefs_.GetValue(key, value);
+}
+
+void TestingPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool TestingPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+bool TestingPrefStore::IsInitializationComplete() const {
+  return init_complete_;
+}
+
+void TestingPrefStore::SetValue(const std::string& key,
+                                base::Value* value,
+                                uint32 flags) {
+  if (prefs_.SetValue(key, value)) {
+    committed_ = false;
+    NotifyPrefValueChanged(key);
+  }
+}
+
+void TestingPrefStore::SetValueSilently(const std::string& key,
+                                        base::Value* value,
+                                        uint32 flags) {
+  if (prefs_.SetValue(key, value))
+    committed_ = false;
+}
+
+void TestingPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  if (prefs_.RemoveValue(key)) {
+    committed_ = false;
+    NotifyPrefValueChanged(key);
+  }
+}
+
+bool TestingPrefStore::ReadOnly() const {
+  return read_only_;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const {
+  return read_error_;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() {
+  NotifyInitializationCompleted();
+  return read_error_;
+}
+
+void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
+  DCHECK(!pending_async_read_);
+  error_delegate_.reset(error_delegate);
+  if (block_async_read_)
+    pending_async_read_ = true;
+  else
+    NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::CommitPendingWrite() { committed_ = true; }
+
+void TestingPrefStore::SetInitializationCompleted() {
+  NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::NotifyPrefValueChanged(const std::string& key) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::NotifyInitializationCompleted() {
+  DCHECK(!init_complete_);
+  init_complete_ = true;
+  if (read_success_ && read_error_ != PREF_READ_ERROR_NONE && error_delegate_)
+    error_delegate_->OnError(read_error_);
+  FOR_EACH_OBSERVER(
+      Observer, observers_, OnInitializationCompleted(read_success_));
+}
+
+void TestingPrefStore::ReportValueChanged(const std::string& key,
+                                          uint32 flags) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::SetString(const std::string& key,
+                                 const std::string& value) {
+  SetValue(key, new base::StringValue(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void TestingPrefStore::SetInteger(const std::string& key, int value) {
+  SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
+  SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+bool TestingPrefStore::GetString(const std::string& key,
+                                 std::string* value) const {
+  const base::Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsString(value);
+}
+
+bool TestingPrefStore::GetInteger(const std::string& key, int* value) const {
+  const base::Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsInteger(value);
+}
+
+bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const {
+  const base::Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsBoolean(value);
+}
+
+void TestingPrefStore::SetBlockAsyncRead(bool block_async_read) {
+  DCHECK(!init_complete_);
+  block_async_read_ = block_async_read;
+  if (pending_async_read_ && !block_async_read_)
+    NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::set_read_only(bool read_only) {
+  read_only_ = read_only;
+}
+
+void TestingPrefStore::set_read_success(bool read_success) {
+  DCHECK(!init_complete_);
+  read_success_ = read_success;
+}
+
+void TestingPrefStore::set_read_error(
+    PersistentPrefStore::PrefReadError read_error) {
+  DCHECK(!init_complete_);
+  read_error_ = read_error;
+}
+
+TestingPrefStore::~TestingPrefStore() {}
diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h
new file mode 100644
index 0000000..3de5cac
--- /dev/null
+++ b/base/prefs/testing_pref_store.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_TESTING_PREF_STORE_H_
+#define BASE_PREFS_TESTING_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// |TestingPrefStore| is a preference store implementation that allows tests to
+// explicitly manipulate the contents of the store, triggering notifications
+// where appropriate.
+class TestingPrefStore : public PersistentPrefStore {
+ public:
+  TestingPrefStore();
+
+  // Overriden from PrefStore.
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
+
+  // PersistentPrefStore overrides:
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  PersistentPrefStore::PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+  void CommitPendingWrite() override;
+
+  // Marks the store as having completed initialization.
+  void SetInitializationCompleted();
+
+  // Used for tests to trigger notifications explicitly.
+  void NotifyPrefValueChanged(const std::string& key);
+  void NotifyInitializationCompleted();
+
+  // Some convenience getters/setters.
+  void SetString(const std::string& key, const std::string& value);
+  void SetInteger(const std::string& key, int value);
+  void SetBoolean(const std::string& key, bool value);
+
+  bool GetString(const std::string& key, std::string* value) const;
+  bool GetInteger(const std::string& key, int* value) const;
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Determines whether ReadPrefsAsync completes immediately. Defaults to false
+  // (non-blocking). To block, invoke this with true (blocking) before the call
+  // to ReadPrefsAsync. To unblock, invoke again with false (non-blocking) after
+  // the call to ReadPrefsAsync.
+  void SetBlockAsyncRead(bool block_async_read);
+
+  // Getter and Setter methods for setting and getting the state of the
+  // |TestingPrefStore|.
+  virtual void set_read_only(bool read_only);
+  void set_read_success(bool read_success);
+  void set_read_error(PersistentPrefStore::PrefReadError read_error);
+  bool committed() { return committed_; }
+
+ protected:
+  ~TestingPrefStore() override;
+
+ private:
+  // Stores the preference values.
+  PrefValueMap prefs_;
+
+  // Flag that indicates if the PrefStore is read-only
+  bool read_only_;
+
+  // The result to pass to PrefStore::Observer::OnInitializationCompleted
+  bool read_success_;
+
+  // The result to return from ReadPrefs or ReadPrefsAsync.
+  PersistentPrefStore::PrefReadError read_error_;
+
+  // Whether a call to ReadPrefsAsync should block.
+  bool block_async_read_;
+
+  // Whether there is a pending call to ReadPrefsAsync.
+  bool pending_async_read_;
+
+  // Whether initialization has been completed.
+  bool init_complete_;
+
+  // Whether the store contents have been committed to disk since the last
+  // mutation.
+  bool committed_;
+
+  scoped_ptr<ReadErrorDelegate> error_delegate_;
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefStore);
+};
+
+#endif  // BASE_PREFS_TESTING_PREF_STORE_H_
diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc
new file mode 100644
index 0000000..d850150
--- /dev/null
+++ b/base/prefs/value_map_pref_store.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/value_map_pref_store.h"
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+
+ValueMapPrefStore::ValueMapPrefStore() {}
+
+bool ValueMapPrefStore::GetValue(const std::string& key,
+                                 const base::Value** value) const {
+  return prefs_.GetValue(key, value);
+}
+
+void ValueMapPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ValueMapPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool ValueMapPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+void ValueMapPrefStore::SetValue(const std::string& key,
+                                 base::Value* value,
+                                 uint32 flags) {
+  if (prefs_.SetValue(key, value))
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  if (prefs_.RemoveValue(key))
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+bool ValueMapPrefStore::GetMutableValue(const std::string& key,
+                                        base::Value** value) {
+  return prefs_.GetValue(key, value);
+}
+
+void ValueMapPrefStore::ReportValueChanged(const std::string& key,
+                                           uint32 flags) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::SetValueSilently(const std::string& key,
+                                         base::Value* value,
+                                         uint32 flags) {
+  prefs_.SetValue(key, value);
+}
+
+ValueMapPrefStore::~ValueMapPrefStore() {}
+
+void ValueMapPrefStore::NotifyInitializationCompleted() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true));
+}
diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h
new file mode 100644
index 0000000..86c94bb
--- /dev/null
+++ b/base/prefs/value_map_pref_store.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+#define BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/prefs/writeable_pref_store.h"
+
+// A basic PrefStore implementation that uses a simple name-value map for
+// storing the preference values.
+class BASE_PREFS_EXPORT ValueMapPrefStore : public WriteablePrefStore {
+ public:
+  ValueMapPrefStore();
+
+  // PrefStore overrides:
+  bool GetValue(const std::string& key,
+                const base::Value** value) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+
+  // WriteablePrefStore overrides:
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool GetMutableValue(const std::string& key, base::Value** value) override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+
+ protected:
+  ~ValueMapPrefStore() override;
+
+  // Notify observers about the initialization completed event.
+  void NotifyInitializationCompleted();
+
+ private:
+  PrefValueMap prefs_;
+
+  ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore);
+};
+
+#endif  // BASE_PREFS_VALUE_MAP_PREF_STORE_H_
diff --git a/base/prefs/writeable_pref_store.h b/base/prefs/writeable_pref_store.h
new file mode 100644
index 0000000..d85b4c8
--- /dev/null
+++ b/base/prefs/writeable_pref_store.h
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_WRITEABLE_PREF_STORE_H_
+#define BASE_PREFS_WRITEABLE_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/pref_store.h"
+
+namespace base {
+class Value;
+}
+
+// A pref store that can be written to as well as read from.
+class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
+ public:
+  // PrefWriteFlags can be used to change the way a pref will be written to
+  // storage.
+  enum PrefWriteFlags : uint32 {
+    // No flags are specified.
+    DEFAULT_PREF_WRITE_FLAGS = 0,
+
+    // This marks the pref as "lossy". There is no strict time guarantee on when
+    // a lossy pref will be persisted to permanent storage when it is modified.
+    LOSSY_PREF_WRITE_FLAG = 1 << 1
+  };
+
+  WriteablePrefStore() {}
+
+  // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
+  // must be non-NULL. |flags| is a bitmask of PrefWriteFlags.
+  virtual void SetValue(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) = 0;
+
+  // Removes the value for |key|.
+  virtual void RemoveValue(const std::string& key, uint32 flags) = 0;
+
+  // Equivalent to PrefStore::GetValue but returns a mutable value.
+  virtual bool GetMutableValue(const std::string& key,
+                               base::Value** result) = 0;
+
+  // Triggers a value changed notification. This function needs to be called
+  // if one retrieves a list or dictionary with GetMutableValue and change its
+  // value. SetValue takes care of notifications itself. Note that
+  // ReportValueChanged will trigger notifications even if nothing has changed.
+  // |flags| is a bitmask of PrefWriteFlags.
+  virtual void ReportValueChanged(const std::string& key, uint32 flags) = 0;
+
+  // Same as SetValue, but doesn't generate notifications. This is used by
+  // PrefService::GetMutableUserPref() in order to put empty entries
+  // into the user pref store. Using SetValue is not an option since existing
+  // tests rely on the number of notifications generated. |flags| is a bitmask
+  // of PrefWriteFlags.
+  virtual void SetValueSilently(const std::string& key,
+                                base::Value* value,
+                                uint32 flags) = 0;
+
+ protected:
+  ~WriteablePrefStore() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WriteablePrefStore);
+};
+
+#endif  // BASE_PREFS_WRITEABLE_PREF_STORE_H_
diff --git a/base/process/BUILD.gn b/base/process/BUILD.gn
new file mode 100644
index 0000000..e570647
--- /dev/null
+++ b/base/process/BUILD.gn
@@ -0,0 +1,107 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("process") {
+  sources = [
+    "internal_linux.cc",
+    "internal_linux.h",
+    "kill.cc",
+    "kill.h",
+    "kill_mac.cc",
+    "kill_posix.cc",
+    "kill_win.cc",
+    "launch.cc",
+    "launch.h",
+    "launch_ios.cc",
+    "launch_mac.cc",
+    "launch_posix.cc",
+    "launch_win.cc",
+    "memory.cc",
+    "memory.h",
+    "memory_linux.cc",
+    "memory_mac.mm",
+    "memory_win.cc",
+    "process.h",
+    "process_handle_freebsd.cc",
+    "process_handle_linux.cc",
+    "process_handle_mac.cc",
+    "process_handle_openbsd.cc",
+    "process_handle_posix.cc",
+    "process_handle_win.cc",
+    "process_info.h",
+    "process_info_linux.cc",
+    "process_info_mac.cc",
+    "process_info_win.cc",
+    "process_iterator.cc",
+    "process_iterator.h",
+    "process_iterator_freebsd.cc",
+    "process_iterator_linux.cc",
+    "process_iterator_mac.cc",
+    "process_iterator_openbsd.cc",
+    "process_iterator_win.cc",
+    "process_linux.cc",
+    "process_metrics.cc",
+    "process_metrics.h",
+    "process_metrics_freebsd.cc",
+    "process_metrics_ios.cc",
+    "process_metrics_linux.cc",
+    "process_metrics_mac.cc",
+    "process_metrics_openbsd.cc",
+    "process_metrics_posix.cc",
+    "process_metrics_win.cc",
+    "process_posix.cc",
+    "process_win.cc",
+  ]
+
+  sources -= [
+    "process_handle_freebsd.cc",
+    "process_handle_openbsd.cc",
+    "process_iterator_freebsd.cc",
+    "process_iterator_openbsd.cc",
+    "process_metrics_freebsd.cc",
+    "process_metrics_openbsd.cc",
+  ]
+
+  if (is_android) {
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [
+      "internal_linux.cc",
+      "memory_linux.cc",
+      "process_handle_linux.cc",
+      "process_iterator_linux.cc",
+      "process_metrics_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (is_nacl) {
+    sources -= [
+      "kill.cc",
+      "kill.h",
+      "kill_posix.cc",
+      "launch.cc",
+      "launch.h",
+      "launch_posix.cc",
+      "memory.cc",
+      "memory.h",
+      "process_iterator.cc",
+      "process_iterator.h",
+      "process_metrics.cc",
+      "process_metrics_posix.cc",
+      "process_posix.cc",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/memory",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  allow_circular_includes_from = [ "//base/memory" ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
new file mode 100644
index 0000000..d2e9ec5
--- /dev/null
+++ b/base/process/internal_linux.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/internal_linux.h"
+
+#include <unistd.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+const char kProcDir[] = "/proc";
+
+const char kStatFile[] = "stat";
+
+base::FilePath GetProcPidDir(pid_t pid) {
+  return base::FilePath(kProcDir).Append(IntToString(pid));
+}
+
+pid_t ProcDirSlotToPid(const char* d_name) {
+  int i;
+  for (i = 0; i < NAME_MAX && d_name[i]; ++i) {
+    if (!IsAsciiDigit(d_name[i])) {
+      return 0;
+    }
+  }
+  if (i == NAME_MAX)
+    return 0;
+
+  // Read the process's command line.
+  pid_t pid;
+  std::string pid_string(d_name);
+  if (!StringToInt(pid_string, &pid)) {
+    NOTREACHED();
+    return 0;
+  }
+  return pid;
+}
+
+bool ReadProcFile(const FilePath& file, std::string* buffer) {
+  buffer->clear();
+  // Synchronously reading files in /proc is safe.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  if (!ReadFileToString(file, buffer)) {
+    DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII();
+    return false;
+  }
+  return !buffer->empty();
+}
+
+bool ReadProcStats(pid_t pid, std::string* buffer) {
+  FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile);
+  return ReadProcFile(stat_file, buffer);
+}
+
+bool ParseProcStats(const std::string& stats_data,
+                    std::vector<std::string>* proc_stats) {
+  // |stats_data| may be empty if the process disappeared somehow.
+  // e.g. http://crbug.com/145811
+  if (stats_data.empty())
+    return false;
+
+  // The stat file is formatted as:
+  // pid (process name) data1 data2 .... dataN
+  // Look for the closing paren by scanning backwards, to avoid being fooled by
+  // processes with ')' in the name.
+  size_t open_parens_idx = stats_data.find(" (");
+  size_t close_parens_idx = stats_data.rfind(") ");
+  if (open_parens_idx == std::string::npos ||
+      close_parens_idx == std::string::npos ||
+      open_parens_idx > close_parens_idx) {
+    DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'";
+    NOTREACHED();
+    return false;
+  }
+  open_parens_idx++;
+
+  proc_stats->clear();
+  // PID.
+  proc_stats->push_back(stats_data.substr(0, open_parens_idx));
+  // Process name without parentheses.
+  proc_stats->push_back(
+      stats_data.substr(open_parens_idx + 1,
+                        close_parens_idx - (open_parens_idx + 1)));
+
+  // Split the rest.
+  std::vector<std::string> other_stats;
+  SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
+  for (size_t i = 0; i < other_stats.size(); ++i)
+    proc_stats->push_back(other_stats[i]);
+  return true;
+}
+
+typedef std::map<std::string, std::string> ProcStatMap;
+void ParseProcStat(const std::string& contents, ProcStatMap* output) {
+  base::StringPairs key_value_pairs;
+  SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
+  for (size_t i = 0; i < key_value_pairs.size(); ++i) {
+    output->insert(key_value_pairs[i]);
+  }
+}
+
+int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+                               ProcStatsFields field_num) {
+  DCHECK_GE(field_num, VM_PPID);
+  CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
+
+  int64 value;
+  return StringToInt64(proc_stats[field_num], &value) ? value : 0;
+}
+
+size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
+                                ProcStatsFields field_num) {
+  DCHECK_GE(field_num, VM_PPID);
+  CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
+
+  size_t value;
+  return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
+}
+
+int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
+  std::string stats_data;
+  if (!ReadProcStats(pid, &stats_data))
+    return 0;
+  std::vector<std::string> proc_stats;
+  if (!ParseProcStats(stats_data, &proc_stats))
+    return 0;
+  return GetProcStatsFieldAsInt64(proc_stats, field_num);
+}
+
+size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
+                                       ProcStatsFields field_num) {
+  std::string stats_data;
+  if (!ReadProcStats(pid, &stats_data))
+    return 0;
+  std::vector<std::string> proc_stats;
+  if (!ParseProcStats(stats_data, &proc_stats))
+    return 0;
+  return GetProcStatsFieldAsSizeT(proc_stats, field_num);
+}
+
+Time GetBootTime() {
+  FilePath path("/proc/stat");
+  std::string contents;
+  if (!ReadProcFile(path, &contents))
+    return Time();
+  ProcStatMap proc_stat;
+  ParseProcStat(contents, &proc_stat);
+  ProcStatMap::const_iterator btime_it = proc_stat.find("btime");
+  if (btime_it == proc_stat.end())
+    return Time();
+  int btime;
+  if (!StringToInt(btime_it->second, &btime))
+    return Time();
+  return Time::FromTimeT(btime);
+}
+
+TimeDelta ClockTicksToTimeDelta(int clock_ticks) {
+  // This queries the /proc-specific scaling factor which is
+  // conceptually the system hertz.  To dump this value on another
+  // system, try
+  //   od -t dL /proc/self/auxv
+  // and look for the number after 17 in the output; mine is
+  //   0000040          17         100           3   134512692
+  // which means the answer is 100.
+  // It may be the case that this value is always 100.
+  static const int kHertz = sysconf(_SC_CLK_TCK);
+
+  return TimeDelta::FromMicroseconds(
+      Time::kMicrosecondsPerSecond * clock_ticks / kHertz);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/process/internal_linux.h b/base/process/internal_linux.h
new file mode 100644
index 0000000..1837f94
--- /dev/null
+++ b/base/process/internal_linux.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains internal routines that are called by other files in
+// base/process/.
+
+#ifndef BASE_PROCESS_INTERNAL_LINUX_H_
+#define BASE_PROCESS_INTERNAL_LINUX_H_
+
+#include <unistd.h>
+
+#include "base/files/file_path.h"
+
+namespace base {
+
+class Time;
+class TimeDelta;
+
+namespace internal {
+
+// "/proc"
+extern const char kProcDir[];
+
+// "stat"
+extern const char kStatFile[];
+
+// Returns a FilePath to "/proc/pid".
+base::FilePath GetProcPidDir(pid_t pid);
+
+// Take a /proc directory entry named |d_name|, and if it is the directory for
+// a process, convert it to a pid_t.
+// Returns 0 on failure.
+// e.g. /proc/self/ will return 0, whereas /proc/1234 will return 1234.
+pid_t ProcDirSlotToPid(const char* d_name);
+
+// Reads /proc/<pid>/stat into |buffer|. Returns true if the file can be read
+// and is non-empty.
+bool ReadProcStats(pid_t pid, std::string* buffer);
+
+// Takes |stats_data| and populates |proc_stats| with the values split by
+// spaces. Taking into account the 2nd field may, in itself, contain spaces.
+// Returns true if successful.
+bool ParseProcStats(const std::string& stats_data,
+                    std::vector<std::string>* proc_stats);
+
+// Fields from /proc/<pid>/stat, 0-based. See man 5 proc.
+// If the ordering ever changes, carefully review functions that use these
+// values.
+enum ProcStatsFields {
+  VM_COMM           = 1,   // Filename of executable, without parentheses.
+  VM_STATE          = 2,   // Letter indicating the state of the process.
+  VM_PPID           = 3,   // PID of the parent.
+  VM_PGRP           = 4,   // Process group id.
+  VM_UTIME          = 13,  // Time scheduled in user mode in clock ticks.
+  VM_STIME          = 14,  // Time scheduled in kernel mode in clock ticks.
+  VM_NUMTHREADS     = 19,  // Number of threads.
+  VM_STARTTIME      = 21,  // The time the process started in clock ticks.
+  VM_VSIZE          = 22,  // Virtual memory size in bytes.
+  VM_RSS            = 23,  // Resident Set Size in pages.
+};
+
+// Reads the |field_num|th field from |proc_stats|. Returns 0 on failure.
+// This version does not handle the first 3 values, since the first value is
+// simply |pid|, and the next two values are strings.
+int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+                               ProcStatsFields field_num);
+
+// Same as GetProcStatsFieldAsInt64(), but for size_t values.
+size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
+                                ProcStatsFields field_num);
+
+// Convenience wrapper around GetProcStatsFieldAsInt64(), ParseProcStats() and
+// ReadProcStats(). See GetProcStatsFieldAsInt64() for details.
+int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
+
+// Same as ReadProcStatsAndGetFieldAsInt64() but for size_t values.
+size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
+                                       ProcStatsFields field_num);
+
+// Returns the time that the OS started. Clock ticks are relative to this.
+Time GetBootTime();
+
+// Converts Linux clock ticks to a wall time delta.
+TimeDelta ClockTicksToTimeDelta(int clock_ticks);
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_PROCESS_INTERNAL_LINUX_H_
diff --git a/base/process/kill.cc b/base/process/kill.cc
new file mode 100644
index 0000000..5d8ba6a
--- /dev/null
+++ b/base/process/kill.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+bool KillProcesses(const FilePath::StringType& executable_name,
+                   int exit_code,
+                   const ProcessFilter* filter) {
+  bool result = true;
+  NamedProcessIterator iter(executable_name, filter);
+  while (const ProcessEntry* entry = iter.NextProcessEntry()) {
+    Process process = Process::Open(entry->pid());
+    result &= process.Terminate(exit_code, true);
+  }
+  return result;
+}
+
+}  // namespace base
diff --git a/base/process/kill.h b/base/process/kill.h
new file mode 100644
index 0000000..af00b03
--- /dev/null
+++ b/base/process/kill.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains routines to kill processes and get the exit code and
+// termination status.
+
+#ifndef BASE_PROCESS_KILL_H_
+#define BASE_PROCESS_KILL_H_
+
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class ProcessFilter;
+
+// Return status values from GetTerminationStatus.  Don't use these as
+// exit code arguments to KillProcess*(), use platform/application
+// specific values instead.
+enum TerminationStatus {
+  TERMINATION_STATUS_NORMAL_TERMINATION,   // zero exit status
+  TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
+  TERMINATION_STATUS_PROCESS_WAS_KILLED,   // e.g. SIGKILL or task manager kill
+  TERMINATION_STATUS_PROCESS_CRASHED,      // e.g. Segmentation fault
+  TERMINATION_STATUS_STILL_RUNNING,        // child hasn't exited yet
+#if defined(OS_ANDROID)
+  // On Android processes are spawned from the system Zygote and we do not get
+  // the termination status.  We can't know if the termination was a crash or an
+  // oom kill for sure, but we can use status of the strong process bindings as
+  // a hint.
+  TERMINATION_STATUS_OOM_PROTECTED,        // child was protected from oom kill
+#endif
+  TERMINATION_STATUS_MAX_ENUM
+};
+
+// Attempts to kill all the processes on the current machine that were launched
+// from the given executable name, ending them with the given exit code.  If
+// filter is non-null, then only processes selected by the filter are killed.
+// Returns true if all processes were able to be killed off, false if at least
+// one couldn't be killed.
+BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name,
+                               int exit_code,
+                               const ProcessFilter* filter);
+
+#if defined(OS_POSIX)
+// Attempts to kill the process group identified by |process_group_id|. Returns
+// true on success.
+BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id);
+#endif  // defined(OS_POSIX)
+
+// Get the termination status of the process by interpreting the
+// circumstances of the child process' death. |exit_code| is set to
+// the status returned by waitpid() on POSIX, and from
+// GetExitCodeProcess() on Windows.  |exit_code| may be NULL if the
+// caller is not interested in it.  Note that on Linux, this function
+// will only return a useful result the first time it is called after
+// the child exits (because it will reap the child and the information
+// will no longer be available).
+BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle,
+                                                   int* exit_code);
+
+#if defined(OS_POSIX)
+// Send a kill signal to the process and then wait for the process to exit
+// and get the termination status.
+//
+// This is used in situations where it is believed that the process is dead
+// or dying (because communication with the child process has been cut).
+// In order to avoid erroneously returning that the process is still running
+// because the kernel is still cleaning it up, this will wait for the process
+// to terminate. In order to avoid the risk of hanging while waiting for the
+// process to terminate, send a SIGKILL to the process before waiting for the
+// termination status.
+//
+// Note that it is not an option to call WaitForExitCode and then
+// GetTerminationStatus as the child will be reaped when WaitForExitCode
+// returns, and this information will be lost.
+//
+BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus(
+    ProcessHandle handle, int* exit_code);
+#endif  // defined(OS_POSIX)
+
+// Wait for all the processes based on the named executable to exit.  If filter
+// is non-null, then only processes selected by the filter are waited on.
+// Returns after all processes have exited or wait_milliseconds have expired.
+// Returns true if all the processes exited, false otherwise.
+BASE_EXPORT bool WaitForProcessesToExit(
+    const FilePath::StringType& executable_name,
+    base::TimeDelta wait,
+    const ProcessFilter* filter);
+
+// Waits a certain amount of time (can be 0) for all the processes with a given
+// executable name to exit, then kills off any of them that are still around.
+// If filter is non-null, then only processes selected by the filter are waited
+// on.  Killed processes are ended with the given exit code.  Returns false if
+// any processes needed to be killed, true if they all exited cleanly within
+// the wait_milliseconds delay.
+BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
+                                  base::TimeDelta wait,
+                                  int exit_code,
+                                  const ProcessFilter* filter);
+
+// This method ensures that the specified process eventually terminates, and
+// then it closes the given process handle.
+//
+// It assumes that the process has already been signalled to exit, and it
+// begins by waiting a small amount of time for it to exit.  If the process
+// does not appear to have exited, then this function starts to become
+// aggressive about ensuring that the process terminates.
+//
+// On Linux this method does not block the calling thread.
+// On OS X this method may block for up to 2 seconds.
+//
+// NOTE: The process must have been opened with the PROCESS_TERMINATE and
+// SYNCHRONIZE permissions.
+//
+BASE_EXPORT void EnsureProcessTerminated(Process process);
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+// The nicer version of EnsureProcessTerminated() that is patient and will
+// wait for |pid| to finish and then reap it.
+BASE_EXPORT void EnsureProcessGetsReaped(ProcessId pid);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_KILL_H_
diff --git a/base/process/kill_mac.cc b/base/process/kill_mac.cc
new file mode 100644
index 0000000..a4e0a14
--- /dev/null
+++ b/base/process/kill_mac.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include <signal.h>
+#include <sys/event.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+namespace {
+
+const int kWaitBeforeKillSeconds = 2;
+
+// Reap |child| process. This call blocks until completion.
+void BlockingReap(pid_t child) {
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, 0));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << child << ", NULL, 0)";
+  }
+}
+
+// Waits for |timeout| seconds for the given |child| to exit and reap it. If
+// the child doesn't exit within the time specified, kills it.
+//
+// This function takes two approaches: first, it tries to use kqueue to
+// observe when the process exits. kevent can monitor a kqueue with a
+// timeout, so this method is preferred to wait for a specified period of
+// time. Once the kqueue indicates the process has exited, waitpid will reap
+// the exited child. If the kqueue doesn't provide an exit event notification,
+// before the timeout expires, or if the kqueue fails or misbehaves, the
+// process will be mercilessly killed and reaped.
+//
+// A child process passed to this function may be in one of several states:
+// running, terminated and not yet reaped, and (apparently, and unfortunately)
+// terminated and already reaped. Normally, a process will at least have been
+// asked to exit before this function is called, but this is not required.
+// If a process is terminating and unreaped, there may be a window between the
+// time that kqueue will no longer recognize it and when it becomes an actual
+// zombie that a non-blocking (WNOHANG) waitpid can reap. This condition is
+// detected when kqueue indicates that the process is not running and a
+// non-blocking waitpid fails to reap the process but indicates that it is
+// still running. In this event, a blocking attempt to reap the process
+// collects the known-dying child, preventing zombies from congregating.
+//
+// In the event that the kqueue misbehaves entirely, as it might under a
+// EMFILE condition ("too many open files", or out of file descriptors), this
+// function will forcibly kill and reap the child without delay. This
+// eliminates another potential zombie vector. (If you're out of file
+// descriptors, you're probably deep into something else, but that doesn't
+// mean that zombies be allowed to kick you while you're down.)
+//
+// The fact that this function seemingly can be called to wait on a child
+// that's not only already terminated but already reaped is a bit of a
+// problem: a reaped child's pid can be reclaimed and may refer to a distinct
+// process in that case. The fact that this function can seemingly be called
+// to wait on a process that's not even a child is also a problem: kqueue will
+// work in that case, but waitpid won't, and killing a non-child might not be
+// the best approach.
+void WaitForChildToDie(pid_t child, int timeout) {
+  DCHECK_GT(child, 0);
+  DCHECK_GT(timeout, 0);
+
+  // DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that
+  // |child| has been reaped. Specifically, even if a kqueue, kevent, or other
+  // call fails, this function should fall back to the last resort of trying
+  // to kill and reap the process. Not observing this rule will resurrect
+  // zombies.
+
+  int result;
+
+  ScopedFD kq(HANDLE_EINTR(kqueue()));
+  if (!kq.is_valid()) {
+    DPLOG(ERROR) << "kqueue()";
+  } else {
+    struct kevent change = {0};
+    EV_SET(&change, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+    result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
+
+    if (result == -1) {
+      if (errno != ESRCH) {
+        DPLOG(ERROR) << "kevent (setup " << child << ")";
+      } else {
+        // At this point, one of the following has occurred:
+        // 1. The process has died but has not yet been reaped.
+        // 2. The process has died and has already been reaped.
+        // 3. The process is in the process of dying. It's no longer
+        //    kqueueable, but it may not be waitable yet either. Mark calls
+        //    this case the "zombie death race".
+
+        result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+
+        if (result != 0) {
+          // A positive result indicates case 1. waitpid succeeded and reaped
+          // the child. A result of -1 indicates case 2. The child has already
+          // been reaped. In both of these cases, no further action is
+          // necessary.
+          return;
+        }
+
+        // |result| is 0, indicating case 3. The process will be waitable in
+        // short order. Fall back out of the kqueue code to kill it (for good
+        // measure) and reap it.
+      }
+    } else {
+      // Keep track of the elapsed time to be able to restart kevent if it's
+      // interrupted.
+      TimeDelta remaining_delta = TimeDelta::FromSeconds(timeout);
+      TimeTicks deadline = TimeTicks::Now() + remaining_delta;
+      result = -1;
+      struct kevent event = {0};
+      while (remaining_delta.InMilliseconds() > 0) {
+        const struct timespec remaining_timespec = remaining_delta.ToTimeSpec();
+        result = kevent(kq.get(), NULL, 0, &event, 1, &remaining_timespec);
+        if (result == -1 && errno == EINTR) {
+          remaining_delta = deadline - TimeTicks::Now();
+          result = 0;
+        } else {
+          break;
+        }
+      }
+
+      if (result == -1) {
+        DPLOG(ERROR) << "kevent (wait " << child << ")";
+      } else if (result > 1) {
+        DLOG(ERROR) << "kevent (wait " << child << "): unexpected result "
+                    << result;
+      } else if (result == 1) {
+        if ((event.fflags & NOTE_EXIT) &&
+            (event.ident == static_cast<uintptr_t>(child))) {
+          // The process is dead or dying. This won't block for long, if at
+          // all.
+          BlockingReap(child);
+          return;
+        } else {
+          DLOG(ERROR) << "kevent (wait " << child
+                      << "): unexpected event: fflags=" << event.fflags
+                      << ", ident=" << event.ident;
+        }
+      }
+    }
+  }
+
+  // The child is still alive, or is very freshly dead. Be sure by sending it
+  // a signal. This is safe even if it's freshly dead, because it will be a
+  // zombie (or on the way to zombiedom) and kill will return 0 even if the
+  // signal is not delivered to a live process.
+  result = kill(child, SIGKILL);
+  if (result == -1) {
+    DPLOG(ERROR) << "kill(" << child << ", SIGKILL)";
+  } else {
+    // The child is definitely on the way out now. BlockingReap won't need to
+    // wait for long, if at all.
+    BlockingReap(child);
+  }
+}
+
+}  // namespace
+
+void EnsureProcessTerminated(Process process) {
+  WaitForChildToDie(process.Pid(), kWaitBeforeKillSeconds);
+}
+
+}  // namespace base
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
new file mode 100644
index 0000000..0e303c6
--- /dev/null
+++ b/base/process/kill_posix.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_iterator.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
+                                           bool can_block,
+                                           int* exit_code) {
+  int status = 0;
+  const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
+                                            can_block ? 0 : WNOHANG));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << handle << ")";
+    if (exit_code)
+      *exit_code = 0;
+    return TERMINATION_STATUS_NORMAL_TERMINATION;
+  } else if (result == 0) {
+    // the child hasn't exited yet.
+    if (exit_code)
+      *exit_code = 0;
+    return TERMINATION_STATUS_STILL_RUNNING;
+  }
+
+  if (exit_code)
+    *exit_code = status;
+
+  if (WIFSIGNALED(status)) {
+    switch (WTERMSIG(status)) {
+      case SIGABRT:
+      case SIGBUS:
+      case SIGFPE:
+      case SIGILL:
+      case SIGSEGV:
+        return TERMINATION_STATUS_PROCESS_CRASHED;
+      case SIGINT:
+      case SIGKILL:
+      case SIGTERM:
+        return TERMINATION_STATUS_PROCESS_WAS_KILLED;
+      default:
+        break;
+    }
+  }
+
+  if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
+
+  return TERMINATION_STATUS_NORMAL_TERMINATION;
+}
+
+}  // namespace
+
+#if !defined(OS_NACL_NONSFI)
+bool KillProcessGroup(ProcessHandle process_group_id) {
+  bool result = kill(-1 * process_group_id, SIGKILL) == 0;
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
+  return result;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+  return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
+}
+
+TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
+                                                int* exit_code) {
+  bool result = kill(handle, SIGKILL) == 0;
+
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process " << handle;
+
+  return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
+                            TimeDelta wait,
+                            const ProcessFilter* filter) {
+  bool result = false;
+
+  // TODO(port): This is inefficient, but works if there are multiple procs.
+  // TODO(port): use waitpid to avoid leaving zombies around
+
+  TimeTicks end_time = TimeTicks::Now() + wait;
+  do {
+    NamedProcessIterator iter(executable_name, filter);
+    if (!iter.NextProcessEntry()) {
+      result = true;
+      break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  } while ((end_time - TimeTicks::Now()) > TimeDelta());
+
+  return result;
+}
+
+bool CleanupProcesses(const FilePath::StringType& executable_name,
+                      TimeDelta wait,
+                      int exit_code,
+                      const ProcessFilter* filter) {
+  bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
+  if (!exited_cleanly)
+    KillProcesses(executable_name, exit_code, filter);
+  return exited_cleanly;
+}
+
+#if !defined(OS_MACOSX)
+
+namespace {
+
+// Return true if the given child is dead. This will also reap the process.
+// Doesn't block.
+static bool IsChildDead(pid_t child) {
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << child << ")";
+    NOTREACHED();
+  } else if (result > 0) {
+    // The child has died.
+    return true;
+  }
+
+  return false;
+}
+
+// A thread class which waits for the given child to exit and reaps it.
+// If the child doesn't exit within a couple of seconds, kill it.
+class BackgroundReaper : public PlatformThread::Delegate {
+ public:
+  BackgroundReaper(pid_t child, unsigned timeout)
+      : child_(child),
+        timeout_(timeout) {
+  }
+
+  // Overridden from PlatformThread::Delegate:
+  void ThreadMain() override {
+    WaitForChildToDie();
+    delete this;
+  }
+
+  void WaitForChildToDie() {
+    // Wait forever case.
+    if (timeout_ == 0) {
+      pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0));
+      if (r != child_) {
+        DPLOG(ERROR) << "While waiting for " << child_
+                     << " to terminate, we got the following result: " << r;
+      }
+      return;
+    }
+
+    // There's no good way to wait for a specific child to exit in a timed
+    // fashion. (No kqueue on Linux), so we just loop and sleep.
+
+    // Wait for 2 * timeout_ 500 milliseconds intervals.
+    for (unsigned i = 0; i < 2 * timeout_; ++i) {
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+      if (IsChildDead(child_))
+        return;
+    }
+
+    if (kill(child_, SIGKILL) == 0) {
+      // SIGKILL is uncatchable. Since the signal was delivered, we can
+      // just wait for the process to die now in a blocking manner.
+      if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0)
+        DPLOG(WARNING) << "waitpid";
+    } else {
+      DLOG(ERROR) << "While waiting for " << child_ << " to terminate we"
+                  << " failed to deliver a SIGKILL signal (" << errno << ").";
+    }
+  }
+
+ private:
+  const pid_t child_;
+  // Number of seconds to wait, if 0 then wait forever and do not attempt to
+  // kill |child_|.
+  const unsigned timeout_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
+};
+
+}  // namespace
+
+void EnsureProcessTerminated(Process process) {
+  // If the child is already dead, then there's nothing to do.
+  if (IsChildDead(process.Pid()))
+    return;
+
+  const unsigned timeout = 2;  // seconds
+  BackgroundReaper* reaper = new BackgroundReaper(process.Pid(), timeout);
+  PlatformThread::CreateNonJoinable(0, reaper);
+}
+
+void EnsureProcessGetsReaped(ProcessId pid) {
+  // If the child is already dead, then there's nothing to do.
+  if (IsChildDead(pid))
+    return;
+
+  BackgroundReaper* reaper = new BackgroundReaper(pid, 0);
+  PlatformThread::CreateNonJoinable(0, reaper);
+}
+
+#endif  // !defined(OS_MACOSX)
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
new file mode 100644
index 0000000..0da3a26
--- /dev/null
+++ b/base/process/kill_win.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include <io.h>
+#include <windows.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/process_iterator.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+namespace {
+
+// Exit codes with special meanings on Windows.
+const DWORD kNormalTerminationExitCode = 0;
+const DWORD kDebuggerInactiveExitCode = 0xC0000354;
+const DWORD kKeyboardInterruptExitCode = 0xC000013A;
+const DWORD kDebuggerTerminatedExitCode = 0x40010004;
+
+// This exit code is used by the Windows task manager when it kills a
+// process.  It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
+// Maximum amount of time (in milliseconds) to wait for the process to exit.
+static const int kWaitInterval = 2000;
+
+class TimerExpiredTask : public win::ObjectWatcher::Delegate {
+ public:
+  explicit TimerExpiredTask(Process process);
+  ~TimerExpiredTask() override;
+
+  void TimedOut();
+
+  // MessageLoop::Watcher -----------------------------------------------------
+  void OnObjectSignaled(HANDLE object) override;
+
+ private:
+  void KillProcess();
+
+  // The process that we are watching.
+  Process process_;
+
+  win::ObjectWatcher watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
+};
+
+TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) {
+  watcher_.StartWatching(process_.Handle(), this);
+}
+
+TimerExpiredTask::~TimerExpiredTask() {
+  TimedOut();
+}
+
+void TimerExpiredTask::TimedOut() {
+  if (process_.IsValid())
+    KillProcess();
+}
+
+void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
+  process_.Close();
+}
+
+void TimerExpiredTask::KillProcess() {
+  // Stop watching the process handle since we're killing it.
+  watcher_.StopWatching();
+
+  // OK, time to get frisky.  We don't actually care when the process
+  // terminates.  We just care that it eventually terminates, and that's what
+  // TerminateProcess should do for us. Don't check for the result code since
+  // it fails quite often. This should be investigated eventually.
+  process_.Terminate(kProcessKilledExitCode, false);
+
+  // Now, just cleanup as if the process exited normally.
+  OnObjectSignaled(process_.Handle());
+}
+
+}  // namespace
+
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+  DWORD tmp_exit_code = 0;
+
+  if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
+    DPLOG(FATAL) << "GetExitCodeProcess() failed";
+    if (exit_code) {
+      // This really is a random number.  We haven't received any
+      // information about the exit code, presumably because this
+      // process doesn't have permission to get the exit code, or
+      // because of some other cause for GetExitCodeProcess to fail
+      // (MSDN docs don't give the possible failure error codes for
+      // this function, so it could be anything).  But we don't want
+      // to leave exit_code uninitialized, since that could cause
+      // random interpretations of the exit code.  So we assume it
+      // terminated "normally" in this case.
+      *exit_code = kNormalTerminationExitCode;
+    }
+    // Assume the child has exited normally if we can't get the exit
+    // code.
+    return TERMINATION_STATUS_NORMAL_TERMINATION;
+  }
+  if (tmp_exit_code == STILL_ACTIVE) {
+    DWORD wait_result = WaitForSingleObject(handle, 0);
+    if (wait_result == WAIT_TIMEOUT) {
+      if (exit_code)
+        *exit_code = wait_result;
+      return TERMINATION_STATUS_STILL_RUNNING;
+    }
+
+    if (wait_result == WAIT_FAILED) {
+      DPLOG(ERROR) << "WaitForSingleObject() failed";
+    } else {
+      DCHECK_EQ(WAIT_OBJECT_0, wait_result);
+
+      // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
+      NOTREACHED();
+    }
+
+    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
+  }
+
+  if (exit_code)
+    *exit_code = tmp_exit_code;
+
+  switch (tmp_exit_code) {
+    case kNormalTerminationExitCode:
+      return TERMINATION_STATUS_NORMAL_TERMINATION;
+    case kDebuggerInactiveExitCode:  // STATUS_DEBUGGER_INACTIVE.
+    case kKeyboardInterruptExitCode:  // Control-C/end session.
+    case kDebuggerTerminatedExitCode:  // Debugger terminated process.
+    case kProcessKilledExitCode:  // Task manager kill.
+      return TERMINATION_STATUS_PROCESS_WAS_KILLED;
+    default:
+      // All other exit codes indicate crashes.
+      return TERMINATION_STATUS_PROCESS_CRASHED;
+  }
+}
+
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
+                            TimeDelta wait,
+                            const ProcessFilter* filter) {
+  bool result = true;
+  DWORD start_time = GetTickCount();
+
+  NamedProcessIterator iter(executable_name, filter);
+  for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
+       entry = iter.NextProcessEntry()) {
+    DWORD remaining_wait = static_cast<DWORD>(std::max(
+        static_cast<int64>(0),
+        wait.InMilliseconds() - (GetTickCount() - start_time)));
+    HANDLE process = OpenProcess(SYNCHRONIZE,
+                                 FALSE,
+                                 entry->th32ProcessID);
+    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
+    CloseHandle(process);
+    result &= (wait_result == WAIT_OBJECT_0);
+  }
+
+  return result;
+}
+
+bool CleanupProcesses(const FilePath::StringType& executable_name,
+                      TimeDelta wait,
+                      int exit_code,
+                      const ProcessFilter* filter) {
+  if (WaitForProcessesToExit(executable_name, wait, filter))
+    return true;
+  KillProcesses(executable_name, exit_code, filter);
+  return false;
+}
+
+void EnsureProcessTerminated(Process process) {
+  DCHECK(!process.is_current());
+
+  // If already signaled, then we are done!
+  if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) {
+    return;
+  }
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&TimerExpiredTask::TimedOut,
+           Owned(new TimerExpiredTask(process.Pass()))),
+      TimeDelta::FromMilliseconds(kWaitInterval));
+}
+
+}  // namespace base
diff --git a/base/process/launch.cc b/base/process/launch.cc
new file mode 100644
index 0000000..c179b2f
--- /dev/null
+++ b/base/process/launch.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/launch.h"
+
+namespace base {
+
+LaunchOptions::LaunchOptions()
+    : wait(false),
+#if defined(OS_WIN)
+      start_hidden(false),
+      handles_to_inherit(NULL),
+      inherit_handles(false),
+      as_user(NULL),
+      empty_desktop_name(false),
+      job_handle(NULL),
+      stdin_handle(NULL),
+      stdout_handle(NULL),
+      stderr_handle(NULL),
+      force_breakaway_from_job_(false)
+#else
+      clear_environ(false),
+      fds_to_remap(NULL),
+      maximize_rlimits(NULL),
+      new_process_group(false)
+#if defined(OS_LINUX)
+      , clone_flags(0)
+      , allow_new_privs(false)
+      , kill_on_parent_death(false)
+#endif  // OS_LINUX
+#if defined(OS_POSIX)
+      , pre_exec_delegate(NULL)
+#endif  // OS_POSIX
+#if defined(OS_CHROMEOS)
+      , ctrl_terminal_fd(-1)
+#endif  // OS_CHROMEOS
+#endif  // !defined(OS_WIN)
+    {
+}
+
+LaunchOptions::~LaunchOptions() {
+}
+
+LaunchOptions LaunchOptionsForTest() {
+  LaunchOptions options;
+#if defined(OS_LINUX)
+  // To prevent accidental privilege sharing to an untrusted child, processes
+  // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this
+  // new child will be used for testing only.
+  options.allow_new_privs = true;
+#endif
+  return options;
+}
+
+}  // namespace base
diff --git a/base/process/launch.h b/base/process/launch.h
new file mode 100644
index 0000000..56f27a8
--- /dev/null
+++ b/base/process/launch.h
@@ -0,0 +1,321 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains functions for launching subprocesses.
+
+#ifndef BASE_PROCESS_LAUNCH_H_
+#define BASE_PROCESS_LAUNCH_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/environment.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_piece.h"
+
+#if defined(OS_POSIX)
+#include "base/posix/file_descriptor_shuffle.h"
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+class CommandLine;
+
+#if defined(OS_WIN)
+typedef std::vector<HANDLE> HandlesToInheritVector;
+#endif
+// TODO(viettrungluu): Only define this on POSIX?
+typedef std::vector<std::pair<int, int> > FileHandleMappingVector;
+
+// Options for launching a subprocess that are passed to LaunchProcess().
+// The default constructor constructs the object with default options.
+struct BASE_EXPORT LaunchOptions {
+#if defined(OS_POSIX)
+  // Delegate to be run in between fork and exec in the subprocess (see
+  // pre_exec_delegate below)
+  class BASE_EXPORT PreExecDelegate {
+   public:
+    PreExecDelegate() {}
+    virtual ~PreExecDelegate() {}
+
+    // Since this is to be run between fork and exec, and fork may have happened
+    // while multiple threads were running, this function needs to be async
+    // safe.
+    virtual void RunAsyncSafe() = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PreExecDelegate);
+  };
+#endif  // defined(OS_POSIX)
+
+  LaunchOptions();
+  ~LaunchOptions();
+
+  // If true, wait for the process to complete.
+  bool wait;
+
+#if defined(OS_WIN)
+  bool start_hidden;
+
+  // If non-null, inherit exactly the list of handles in this vector (these
+  // handles must be inheritable). This is only supported on Vista and higher.
+  HandlesToInheritVector* handles_to_inherit;
+
+  // If true, the new process inherits handles from the parent. In production
+  // code this flag should be used only when running short-lived, trusted
+  // binaries, because open handles from other libraries and subsystems will
+  // leak to the child process, causing errors such as open socket hangs.
+  // Note: If |handles_to_inherit| is non-null, this flag is ignored and only
+  // those handles will be inherited (on Vista and higher).
+  bool inherit_handles;
+
+  // If non-null, runs as if the user represented by the token had launched it.
+  // Whether the application is visible on the interactive desktop depends on
+  // the token belonging to an interactive logon session.
+  //
+  // To avoid hard to diagnose problems, when specified this loads the
+  // environment variables associated with the user and if this operation fails
+  // the entire call fails as well.
+  UserTokenHandle as_user;
+
+  // If true, use an empty string for the desktop name.
+  bool empty_desktop_name;
+
+  // If non-null, launches the application in that job object. The process will
+  // be terminated immediately and LaunchProcess() will fail if assignment to
+  // the job object fails.
+  HANDLE job_handle;
+
+  // Handles for the redirection of stdin, stdout and stderr. The handles must
+  // be inheritable. Caller should either set all three of them or none (i.e.
+  // there is no way to redirect stderr without redirecting stdin). The
+  // |inherit_handles| flag must be set to true when redirecting stdio stream.
+  HANDLE stdin_handle;
+  HANDLE stdout_handle;
+  HANDLE stderr_handle;
+
+  // If set to true, ensures that the child process is launched with the
+  // CREATE_BREAKAWAY_FROM_JOB flag which allows it to breakout of the parent
+  // job if any.
+  bool force_breakaway_from_job_;
+#else
+  // Set/unset environment variables. These are applied on top of the parent
+  // process environment.  Empty (the default) means to inherit the same
+  // environment. See AlterEnvironment().
+  EnvironmentMap environ;
+
+  // Clear the environment for the new process before processing changes from
+  // |environ|.
+  bool clear_environ;
+
+  // If non-null, remap file descriptors according to the mapping of
+  // src fd->dest fd to propagate FDs into the child process.
+  // This pointer is owned by the caller and must live through the
+  // call to LaunchProcess().
+  const FileHandleMappingVector* fds_to_remap;
+
+  // Each element is an RLIMIT_* constant that should be raised to its
+  // rlim_max.  This pointer is owned by the caller and must live through
+  // the call to LaunchProcess().
+  const std::vector<int>* maximize_rlimits;
+
+  // If true, start the process in a new process group, instead of
+  // inheriting the parent's process group.  The pgid of the child process
+  // will be the same as its pid.
+  bool new_process_group;
+
+#if defined(OS_LINUX)
+  // If non-zero, start the process using clone(), using flags as provided.
+  // Unlike in clone, clone_flags may not contain a custom termination signal
+  // that is sent to the parent when the child dies. The termination signal will
+  // always be set to SIGCHLD.
+  int clone_flags;
+
+  // By default, child processes will have the PR_SET_NO_NEW_PRIVS bit set. If
+  // true, then this bit will not be set in the new child process.
+  bool allow_new_privs;
+
+  // Sets parent process death signal to SIGKILL.
+  bool kill_on_parent_death;
+#endif  // defined(OS_LINUX)
+
+#if defined(OS_POSIX)
+  // If not empty, change to this directory before execing the new process.
+  base::FilePath current_directory;
+
+  // If non-null, a delegate to be run immediately prior to executing the new
+  // program in the child process.
+  //
+  // WARNING: If LaunchProcess is called in the presence of multiple threads,
+  // code running in this delegate essentially needs to be async-signal safe
+  // (see man 7 signal for a list of allowed functions).
+  PreExecDelegate* pre_exec_delegate;
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_CHROMEOS)
+  // If non-negative, the specified file descriptor will be set as the launched
+  // process' controlling terminal.
+  int ctrl_terminal_fd;
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_MACOSX)
+  // If this name is non-empty, the new child, after fork() but before exec(),
+  // will look up this server name in the bootstrap namespace. The resulting
+  // service port will be replaced as the bootstrap port in the child. Because
+  // the process's IPC space is cleared on exec(), any rights to the old
+  // bootstrap port will not be transferred to the new process.
+  std::string replacement_bootstrap_name;
+#endif
+
+#endif  // !defined(OS_WIN)
+};
+
+// Launch a process via the command line |cmdline|.
+// See the documentation of LaunchOptions for details on |options|.
+//
+// Returns a valid Process upon success.
+//
+// Unix-specific notes:
+// - All file descriptors open in the parent process will be closed in the
+//   child process except for any preserved by options::fds_to_remap, and
+//   stdin, stdout, and stderr. If not remapped by options::fds_to_remap,
+//   stdin is reopened as /dev/null, and the child is allowed to inherit its
+//   parent's stdout and stderr.
+// - If the first argument on the command line does not contain a slash,
+//   PATH will be searched.  (See man execvp.)
+BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline,
+                                  const LaunchOptions& options);
+
+#if defined(OS_WIN)
+// Windows-specific LaunchProcess that takes the command line as a
+// string.  Useful for situations where you need to control the
+// command line arguments directly, but prefer the CommandLine version
+// if launching Chrome itself.
+//
+// The first command line argument should be the path to the process,
+// and don't forget to quote it.
+//
+// Example (including literal quotes)
+//  cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
+BASE_EXPORT Process LaunchProcess(const string16& cmdline,
+                                  const LaunchOptions& options);
+
+// Launches a process with elevated privileges.  This does not behave exactly
+// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
+// create the process.  This means the process will have elevated privileges
+// and thus some common operations like OpenProcess will fail. Currently the
+// only supported LaunchOptions are |start_hidden| and |wait|.
+BASE_EXPORT Process LaunchElevatedProcess(const CommandLine& cmdline,
+                                          const LaunchOptions& options);
+
+#elif defined(OS_POSIX)
+// A POSIX-specific version of LaunchProcess that takes an argv array
+// instead of a CommandLine.  Useful for situations where you need to
+// control the command line arguments directly, but prefer the
+// CommandLine version if launching Chrome itself.
+BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv,
+                                  const LaunchOptions& options);
+
+// Close all file descriptors, except those which are a destination in the
+// given multimap. Only call this function in a child process where you know
+// that there aren't any other threads.
+BASE_EXPORT void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Set |job_object|'s JOBOBJECT_EXTENDED_LIMIT_INFORMATION
+// BasicLimitInformation.LimitFlags to |limit_flags|.
+BASE_EXPORT bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags);
+
+// Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran
+// chrome. This is not thread-safe: only call from main thread.
+BASE_EXPORT void RouteStdioToConsole();
+#endif  // defined(OS_WIN)
+
+// Executes the application specified by |cl| and wait for it to exit. Stores
+// the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true
+// on success (application launched and exited cleanly, with exit code
+// indicating success).
+BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output);
+
+#if defined(OS_WIN)
+// A Windows-specific version of GetAppOutput that takes a command line string
+// instead of a CommandLine object. Useful for situations where you need to
+// control the command line arguments directly.
+BASE_EXPORT bool GetAppOutput(const StringPiece16& cl, std::string* output);
+#endif
+
+#if defined(OS_POSIX)
+// A POSIX-specific version of GetAppOutput that takes an argv array
+// instead of a CommandLine.  Useful for situations where you need to
+// control the command line arguments directly.
+BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv,
+                              std::string* output);
+
+// A restricted version of |GetAppOutput()| which (a) clears the environment,
+// and (b) stores at most |max_output| bytes; also, it doesn't search the path
+// for the command.
+BASE_EXPORT bool GetAppOutputRestricted(const CommandLine& cl,
+                                        std::string* output, size_t max_output);
+
+// A version of |GetAppOutput()| which also returns the exit code of the
+// executed command. Returns true if the application runs and exits cleanly. If
+// this is the case the exit code of the application is available in
+// |*exit_code|.
+BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl,
+                                          std::string* output, int* exit_code);
+#endif  // defined(OS_POSIX)
+
+// If supported on the platform, and the user has sufficent rights, increase
+// the current process's scheduling priority to a high priority.
+BASE_EXPORT void RaiseProcessToHighPriority();
+
+#if defined(OS_MACOSX)
+// Restore the default exception handler, setting it to Apple Crash Reporter
+// (ReportCrash).  When forking and execing a new process, the child will
+// inherit the parent's exception ports, which may be set to the Breakpad
+// instance running inside the parent.  The parent's Breakpad instance should
+// not handle the child's exceptions.  Calling RestoreDefaultExceptionHandler
+// in the child after forking will restore the standard exception handler.
+// See http://crbug.com/20371/ for more details.
+void RestoreDefaultExceptionHandler();
+
+// Look up the bootstrap server named |replacement_bootstrap_name| via the
+// current |bootstrap_port|. Then replace the task's bootstrap port with the
+// received right.
+void ReplaceBootstrapPort(const std::string& replacement_bootstrap_name);
+#endif  // defined(OS_MACOSX)
+
+// Creates a LaunchOptions object suitable for launching processes in a test
+// binary. This should not be called in production/released code.
+BASE_EXPORT LaunchOptions LaunchOptionsForTest();
+
+#if defined(OS_LINUX)
+// A wrapper for clone with fork-like behavior, meaning that it returns the
+// child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
+// as in the clone system call (the CLONE_VM flag is not supported).
+//
+// This function uses the libc clone wrapper (which updates libc's pid cache)
+// internally, so callers may expect things like getpid() to work correctly
+// after in both the child and parent. An exception is when this code is run
+// under Valgrind. Valgrind does not support the libc clone wrapper, so the libc
+// pid cache may be incorrect after this function is called under Valgrind.
+//
+// As with fork(), callers should be extremely careful when calling this while
+// multiple threads are running, since at the time the fork happened, the
+// threads could have been in any state (potentially holding locks, etc.).
+// Callers should most likely call execve() in the child soon after calling
+// this.
+BASE_EXPORT pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_LAUNCH_H_
diff --git a/base/process/launch_ios.cc b/base/process/launch_ios.cc
new file mode 100644
index 0000000..3c700f8
--- /dev/null
+++ b/base/process/launch_ios.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/launch.h"
+
+namespace base {
+
+void RaiseProcessToHighPriority() {
+  // Impossible on iOS. Do nothing.
+}
+
+}  // namespace base
diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc
new file mode 100644
index 0000000..ce02475
--- /dev/null
+++ b/base/process/launch_mac.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/launch.h"
+
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+void RestoreDefaultExceptionHandler() {
+  // This function is tailored to remove the Breakpad exception handler.
+  // exception_mask matches s_exception_mask in
+  // breakpad/src/client/mac/handler/exception_handler.cc
+  const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS |
+                                          EXC_MASK_BAD_INSTRUCTION |
+                                          EXC_MASK_ARITHMETIC |
+                                          EXC_MASK_BREAKPOINT;
+
+  // Setting the exception port to MACH_PORT_NULL may not be entirely
+  // kosher to restore the default exception handler, but in practice,
+  // it results in the exception port being set to Apple Crash Reporter,
+  // the desired behavior.
+  task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL,
+                           EXCEPTION_DEFAULT, THREAD_STATE_NONE);
+}
+
+void ReplaceBootstrapPort(const std::string& new_bootstrap_name) {
+  // This function is called between fork() and exec(), so it should take care
+  // to run properly in that situation.
+
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = bootstrap_look_up(bootstrap_port,
+      new_bootstrap_name.c_str(), &port);
+  if (kr != KERN_SUCCESS) {
+    RAW_LOG(FATAL, "Failed to look up replacement bootstrap port.");
+  }
+
+  kr = task_set_bootstrap_port(mach_task_self(), port);
+  if (kr != KERN_SUCCESS) {
+    RAW_LOG(FATAL, "Failed to replace bootstrap port.");
+  }
+}
+
+}  // namespace base
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
new file mode 100644
index 0000000..77edc12
--- /dev/null
+++ b/base/process/launch_posix.cc
@@ -0,0 +1,785 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/launch.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iterator>
+#include <limits>
+#include <set>
+
+#include "base/allocator/type_profiler_control.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/dir_reader_posix.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <sys/prctl.h>
+#endif
+
+#if defined(OS_CHROMEOS)
+#include <sys/ioctl.h>
+#endif
+
+#if defined(OS_FREEBSD)
+#include <sys/event.h>
+#include <sys/ucontext.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <crt_externs.h>
+#include <sys/event.h>
+#else
+extern char** environ;
+#endif
+
+namespace base {
+
+namespace {
+
+// Get the process's "environment" (i.e. the thing that setenv/getenv
+// work with).
+char** GetEnvironment() {
+#if defined(OS_MACOSX)
+  return *_NSGetEnviron();
+#else
+  return environ;
+#endif
+}
+
+// Set the process's "environment" (i.e. the thing that setenv/getenv
+// work with).
+void SetEnvironment(char** env) {
+#if defined(OS_MACOSX)
+  *_NSGetEnviron() = env;
+#else
+  environ = env;
+#endif
+}
+
+// Set the calling thread's signal mask to new_sigmask and return
+// the previous signal mask.
+sigset_t SetSignalMask(const sigset_t& new_sigmask) {
+  sigset_t old_sigmask;
+#if defined(OS_ANDROID)
+  // POSIX says pthread_sigmask() must be used in multi-threaded processes,
+  // but Android's pthread_sigmask() was broken until 4.1:
+  // https://code.google.com/p/android/issues/detail?id=15337
+  // http://stackoverflow.com/questions/13777109/pthread-sigmask-on-android-not-working
+  RAW_CHECK(sigprocmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0);
+#else
+  RAW_CHECK(pthread_sigmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0);
+#endif
+  return old_sigmask;
+}
+
+#if !defined(OS_LINUX) || \
+    (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
+void ResetChildSignalHandlersToDefaults() {
+  // The previous signal handlers are likely to be meaningless in the child's
+  // context so we reset them to the defaults for now. http://crbug.com/44953
+  // These signal handlers are set up at least in browser_main_posix.cc:
+  // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc:
+  // EnableInProcessStackDumping.
+  signal(SIGHUP, SIG_DFL);
+  signal(SIGINT, SIG_DFL);
+  signal(SIGILL, SIG_DFL);
+  signal(SIGABRT, SIG_DFL);
+  signal(SIGFPE, SIG_DFL);
+  signal(SIGBUS, SIG_DFL);
+  signal(SIGSEGV, SIG_DFL);
+  signal(SIGSYS, SIG_DFL);
+  signal(SIGTERM, SIG_DFL);
+}
+
+#else
+
+// TODO(jln): remove the Linux special case once kernels are fixed.
+
+// Internally the kernel makes sigset_t an array of long large enough to have
+// one bit per signal.
+typedef uint64_t kernel_sigset_t;
+
+// This is what struct sigaction looks like to the kernel at least on X86 and
+// ARM. MIPS, for instance, is very different.
+struct kernel_sigaction {
+  void* k_sa_handler;  // For this usage it only needs to be a generic pointer.
+  unsigned long k_sa_flags;
+  void* k_sa_restorer;  // For this usage it only needs to be a generic pointer.
+  kernel_sigset_t k_sa_mask;
+};
+
+// glibc's sigaction() will prevent access to sa_restorer, so we need to roll
+// our own.
+int sys_rt_sigaction(int sig, const struct kernel_sigaction* act,
+                     struct kernel_sigaction* oact) {
+  return syscall(SYS_rt_sigaction, sig, act, oact, sizeof(kernel_sigset_t));
+}
+
+// This function is intended to be used in between fork() and execve() and will
+// reset all signal handlers to the default.
+// The motivation for going through all of them is that sa_restorer can leak
+// from parents and help defeat ASLR on buggy kernels.  We reset it to NULL.
+// See crbug.com/177956.
+void ResetChildSignalHandlersToDefaults(void) {
+  for (int signum = 1; ; ++signum) {
+    struct kernel_sigaction act = {0};
+    int sigaction_get_ret = sys_rt_sigaction(signum, NULL, &act);
+    if (sigaction_get_ret && errno == EINVAL) {
+#if !defined(NDEBUG)
+      // Linux supports 32 real-time signals from 33 to 64.
+      // If the number of signals in the Linux kernel changes, someone should
+      // look at this code.
+      const int kNumberOfSignals = 64;
+      RAW_CHECK(signum == kNumberOfSignals + 1);
+#endif  // !defined(NDEBUG)
+      break;
+    }
+    // All other failures are fatal.
+    if (sigaction_get_ret) {
+      RAW_LOG(FATAL, "sigaction (get) failed.");
+    }
+
+    // The kernel won't allow to re-set SIGKILL or SIGSTOP.
+    if (signum != SIGSTOP && signum != SIGKILL) {
+      act.k_sa_handler = reinterpret_cast<void*>(SIG_DFL);
+      act.k_sa_restorer = NULL;
+      if (sys_rt_sigaction(signum, &act, NULL)) {
+        RAW_LOG(FATAL, "sigaction (set) failed.");
+      }
+    }
+#if !defined(NDEBUG)
+    // Now ask the kernel again and check that no restorer will leak.
+    if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) {
+      RAW_LOG(FATAL, "Cound not fix sa_restorer.");
+    }
+#endif  // !defined(NDEBUG)
+  }
+}
+#endif  // !defined(OS_LINUX) ||
+        // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
+
+#if defined(OS_LINUX)
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+// This function runs on the stack specified on the clone call. It uses longjmp
+// to switch back to the original stack so the child can return from sys_clone.
+int CloneHelper(void* arg) {
+  jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg);
+  longjmp(*env_ptr, 1);
+
+  // Should not be reached.
+  RAW_CHECK(false);
+  return 1;
+}
+
+// This function is noinline to ensure that stack_buf is below the stack pointer
+// that is saved when setjmp is called below. This is needed because when
+// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved
+// upwards. See crbug.com/442912 for more details.
+#if defined(ADDRESS_SANITIZER)
+// Disable AddressSanitizer instrumentation for this function to make sure
+// |stack_buf| is allocated on thread stack instead of ASan's fake stack.
+// Under ASan longjmp() will attempt to clean up the area between the old and
+// new stack pointers and print a warning that may confuse the user.
+__attribute__((no_sanitize_address))
+#endif
+NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags,
+                                      pid_t* ptid,
+                                      pid_t* ctid,
+                                      jmp_buf* env) {
+  // We use the libc clone wrapper instead of making the syscall
+  // directly because making the syscall may fail to update the libc's
+  // internal pid cache. The libc interface unfortunately requires
+  // specifying a new stack, so we use setjmp/longjmp to emulate
+  // fork-like behavior.
+  char stack_buf[PTHREAD_STACK_MIN];
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+  // The stack grows downward.
+  void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+  return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid);
+}
+#endif  // defined(OS_LINUX)
+
+}  // anonymous namespace
+
+// Functor for |ScopedDIR| (below).
+struct ScopedDIRClose {
+  inline void operator()(DIR* x) const {
+    if (x)
+      closedir(x);
+  }
+};
+
+// Automatically closes |DIR*|s.
+typedef scoped_ptr<DIR, ScopedDIRClose> ScopedDIR;
+
+#if defined(OS_LINUX)
+static const char kFDDir[] = "/proc/self/fd";
+#elif defined(OS_MACOSX)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_SOLARIS)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_FREEBSD)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_OPENBSD)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_ANDROID)
+static const char kFDDir[] = "/proc/self/fd";
+#endif
+
+void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
+  // DANGER: no calls to malloc or locks are allowed from now on:
+  // http://crbug.com/36678
+
+  // Get the maximum number of FDs possible.
+  size_t max_fds = GetMaxFds();
+
+  DirReaderPosix fd_dir(kFDDir);
+  if (!fd_dir.IsValid()) {
+    // Fallback case: Try every possible fd.
+    for (size_t i = 0; i < max_fds; ++i) {
+      const int fd = static_cast<int>(i);
+      if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
+        continue;
+      // Cannot use STL iterators here, since debug iterators use locks.
+      size_t j;
+      for (j = 0; j < saved_mapping.size(); j++) {
+        if (fd == saved_mapping[j].dest)
+          break;
+      }
+      if (j < saved_mapping.size())
+        continue;
+
+      // Since we're just trying to close anything we can find,
+      // ignore any error return values of close().
+      close(fd);
+    }
+    return;
+  }
+
+  const int dir_fd = fd_dir.fd();
+
+  for ( ; fd_dir.Next(); ) {
+    // Skip . and .. entries.
+    if (fd_dir.name()[0] == '.')
+      continue;
+
+    char *endptr;
+    errno = 0;
+    const long int fd = strtol(fd_dir.name(), &endptr, 10);
+    if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
+      continue;
+    if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
+      continue;
+    // Cannot use STL iterators here, since debug iterators use locks.
+    size_t i;
+    for (i = 0; i < saved_mapping.size(); i++) {
+      if (fd == saved_mapping[i].dest)
+        break;
+    }
+    if (i < saved_mapping.size())
+      continue;
+    if (fd == dir_fd)
+      continue;
+
+    // When running under Valgrind, Valgrind opens several FDs for its
+    // own use and will complain if we try to close them.  All of
+    // these FDs are >= |max_fds|, so we can check against that here
+    // before closing.  See https://bugs.kde.org/show_bug.cgi?id=191758
+    if (fd < static_cast<int>(max_fds)) {
+      int ret = IGNORE_EINTR(close(fd));
+      DPCHECK(ret == 0);
+    }
+  }
+}
+
+Process LaunchProcess(const CommandLine& cmdline,
+                      const LaunchOptions& options) {
+  return LaunchProcess(cmdline.argv(), options);
+}
+
+Process LaunchProcess(const std::vector<std::string>& argv,
+                      const LaunchOptions& options) {
+  size_t fd_shuffle_size = 0;
+  if (options.fds_to_remap) {
+    fd_shuffle_size = options.fds_to_remap->size();
+  }
+
+  InjectiveMultimap fd_shuffle1;
+  InjectiveMultimap fd_shuffle2;
+  fd_shuffle1.reserve(fd_shuffle_size);
+  fd_shuffle2.reserve(fd_shuffle_size);
+
+  scoped_ptr<char* []> argv_cstr(new char* [argv.size() + 1]);
+  for (size_t i = 0; i < argv.size(); i++) {
+    argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+  }
+  argv_cstr[argv.size()] = NULL;
+
+  scoped_ptr<char*[]> new_environ;
+  char* const empty_environ = NULL;
+  char* const* old_environ = GetEnvironment();
+  if (options.clear_environ)
+    old_environ = &empty_environ;
+  if (!options.environ.empty())
+    new_environ = AlterEnvironment(old_environ, options.environ);
+
+  sigset_t full_sigset;
+  sigfillset(&full_sigset);
+  const sigset_t orig_sigmask = SetSignalMask(full_sigset);
+
+  const char* current_directory = nullptr;
+  if (!options.current_directory.empty()) {
+    current_directory = options.current_directory.value().c_str();
+  }
+
+  pid_t pid;
+#if defined(OS_LINUX)
+  if (options.clone_flags) {
+    // Signal handling in this function assumes the creation of a new
+    // process, so we check that a thread is not being created by mistake
+    // and that signal handling follows the process-creation rules.
+    RAW_CHECK(
+        !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM)));
+
+    // We specify a null ptid and ctid.
+    RAW_CHECK(
+        !(options.clone_flags &
+          (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT_SETTID)));
+
+    // Since we use waitpid, we do not support custom termination signals in the
+    // clone flags.
+    RAW_CHECK((options.clone_flags & 0xff) == 0);
+
+    pid = ForkWithFlags(options.clone_flags | SIGCHLD, nullptr, nullptr);
+  } else
+#endif
+  {
+    pid = fork();
+  }
+
+  // Always restore the original signal mask in the parent.
+  if (pid != 0) {
+    SetSignalMask(orig_sigmask);
+  }
+
+  if (pid < 0) {
+    DPLOG(ERROR) << "fork";
+    return Process();
+  } else if (pid == 0) {
+    // Child process
+
+    // DANGER: no calls to malloc or locks are allowed from now on:
+    // http://crbug.com/36678
+
+    // DANGER: fork() rule: in the child, if you don't end up doing exec*(),
+    // you call _exit() instead of exit(). This is because _exit() does not
+    // call any previously-registered (in the parent) exit handlers, which
+    // might do things like block waiting for threads that don't even exist
+    // in the child.
+
+    // If a child process uses the readline library, the process block forever.
+    // In BSD like OSes including OS X it is safe to assign /dev/null as stdin.
+    // See http://crbug.com/56596.
+    base::ScopedFD null_fd(HANDLE_EINTR(open("/dev/null", O_RDONLY)));
+    if (!null_fd.is_valid()) {
+      RAW_LOG(ERROR, "Failed to open /dev/null");
+      _exit(127);
+    }
+
+    int new_fd = HANDLE_EINTR(dup2(null_fd.get(), STDIN_FILENO));
+    if (new_fd != STDIN_FILENO) {
+      RAW_LOG(ERROR, "Failed to dup /dev/null for stdin");
+      _exit(127);
+    }
+
+    if (options.new_process_group) {
+      // Instead of inheriting the process group ID of the parent, the child
+      // starts off a new process group with pgid equal to its process ID.
+      if (setpgid(0, 0) < 0) {
+        RAW_LOG(ERROR, "setpgid failed");
+        _exit(127);
+      }
+    }
+
+    // Stop type-profiler.
+    // The profiler should be stopped between fork and exec since it inserts
+    // locks at new/delete expressions.  See http://crbug.com/36678.
+    base::type_profiler::Controller::Stop();
+
+    if (options.maximize_rlimits) {
+      // Some resource limits need to be maximal in this child.
+      for (size_t i = 0; i < options.maximize_rlimits->size(); ++i) {
+        const int resource = (*options.maximize_rlimits)[i];
+        struct rlimit limit;
+        if (getrlimit(resource, &limit) < 0) {
+          RAW_LOG(WARNING, "getrlimit failed");
+        } else if (limit.rlim_cur < limit.rlim_max) {
+          limit.rlim_cur = limit.rlim_max;
+          if (setrlimit(resource, &limit) < 0) {
+            RAW_LOG(WARNING, "setrlimit failed");
+          }
+        }
+      }
+    }
+
+#if defined(OS_MACOSX)
+    RestoreDefaultExceptionHandler();
+    if (!options.replacement_bootstrap_name.empty())
+      ReplaceBootstrapPort(options.replacement_bootstrap_name);
+#endif  // defined(OS_MACOSX)
+
+    ResetChildSignalHandlersToDefaults();
+    SetSignalMask(orig_sigmask);
+
+#if 0
+    // When debugging it can be helpful to check that we really aren't making
+    // any hidden calls to malloc.
+    void *malloc_thunk =
+        reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095);
+    mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
+    memset(reinterpret_cast<void*>(malloc), 0xff, 8);
+#endif  // 0
+
+#if defined(OS_CHROMEOS)
+    if (options.ctrl_terminal_fd >= 0) {
+      // Set process' controlling terminal.
+      if (HANDLE_EINTR(setsid()) != -1) {
+        if (HANDLE_EINTR(
+                ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) {
+          RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set");
+        }
+      } else {
+        RAW_LOG(WARNING, "setsid failed, ctrl terminal not set");
+      }
+    }
+#endif  // defined(OS_CHROMEOS)
+
+    if (options.fds_to_remap) {
+      // Cannot use STL iterators here, since debug iterators use locks.
+      for (size_t i = 0; i < options.fds_to_remap->size(); ++i) {
+        const FileHandleMappingVector::value_type& value =
+            (*options.fds_to_remap)[i];
+        fd_shuffle1.push_back(InjectionArc(value.first, value.second, false));
+        fd_shuffle2.push_back(InjectionArc(value.first, value.second, false));
+      }
+    }
+
+    if (!options.environ.empty() || options.clear_environ)
+      SetEnvironment(new_environ.get());
+
+    // fd_shuffle1 is mutated by this call because it cannot malloc.
+    if (!ShuffleFileDescriptors(&fd_shuffle1))
+      _exit(127);
+
+    CloseSuperfluousFds(fd_shuffle2);
+
+    // Set NO_NEW_PRIVS by default. Since NO_NEW_PRIVS only exists in kernel
+    // 3.5+, do not check the return value of prctl here.
+#if defined(OS_LINUX)
+#ifndef PR_SET_NO_NEW_PRIVS
+#define PR_SET_NO_NEW_PRIVS 38
+#endif
+    if (!options.allow_new_privs) {
+      if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) && errno != EINVAL) {
+        // Only log if the error is not EINVAL (i.e. not supported).
+        RAW_LOG(FATAL, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+      }
+    }
+
+    if (options.kill_on_parent_death) {
+      if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) {
+        RAW_LOG(ERROR, "prctl(PR_SET_PDEATHSIG) failed");
+        _exit(127);
+      }
+    }
+#endif
+
+    if (current_directory != nullptr) {
+      RAW_CHECK(chdir(current_directory) == 0);
+    }
+
+    if (options.pre_exec_delegate != nullptr) {
+      options.pre_exec_delegate->RunAsyncSafe();
+    }
+
+    execvp(argv_cstr[0], argv_cstr.get());
+
+    RAW_LOG(ERROR, "LaunchProcess: failed to execvp:");
+    RAW_LOG(ERROR, argv_cstr[0]);
+    _exit(127);
+  } else {
+    // Parent process
+    if (options.wait) {
+      // While this isn't strictly disk IO, waiting for another process to
+      // finish is the sort of thing ThreadRestrictions is trying to prevent.
+      base::ThreadRestrictions::AssertIOAllowed();
+      pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
+      DPCHECK(ret > 0);
+    }
+  }
+
+  return Process(pid);
+}
+
+void RaiseProcessToHighPriority() {
+  // On POSIX, we don't actually do anything here.  We could try to nice() or
+  // setpriority() or sched_getscheduler, but these all require extra rights.
+}
+
+// Return value used by GetAppOutputInternal to encapsulate the various exit
+// scenarios from the function.
+enum GetAppOutputInternalResult {
+  EXECUTE_FAILURE,
+  EXECUTE_SUCCESS,
+  GOT_MAX_OUTPUT,
+};
+
+// Executes the application specified by |argv| and wait for it to exit. Stores
+// the output (stdout) in |output|. If |do_search_path| is set, it searches the
+// path for the application; in that case, |envp| must be null, and it will use
+// the current environment. If |do_search_path| is false, |argv[0]| should fully
+// specify the path of the application, and |envp| will be used as the
+// environment. Redirects stderr to /dev/null.
+// If we successfully start the application and get all requested output, we
+// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting
+// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS.
+// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited
+// output can treat this as a success, despite having an exit code of SIG_PIPE
+// due to us closing the output pipe.
+// In the case of EXECUTE_SUCCESS, the application exit code will be returned
+// in |*exit_code|, which should be checked to determine if the application
+// ran successfully.
+static GetAppOutputInternalResult GetAppOutputInternal(
+    const std::vector<std::string>& argv,
+    char* const envp[],
+    std::string* output,
+    size_t max_output,
+    bool do_search_path,
+    int* exit_code) {
+  // Doing a blocking wait for another command to finish counts as IO.
+  base::ThreadRestrictions::AssertIOAllowed();
+  // exit_code must be supplied so calling function can determine success.
+  DCHECK(exit_code);
+  *exit_code = EXIT_FAILURE;
+
+  int pipe_fd[2];
+  pid_t pid;
+  InjectiveMultimap fd_shuffle1, fd_shuffle2;
+  scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]);
+
+  fd_shuffle1.reserve(3);
+  fd_shuffle2.reserve(3);
+
+  // Either |do_search_path| should be false or |envp| should be null, but not
+  // both.
+  DCHECK(!do_search_path ^ !envp);
+
+  if (pipe(pipe_fd) < 0)
+    return EXECUTE_FAILURE;
+
+  switch (pid = fork()) {
+    case -1:  // error
+      close(pipe_fd[0]);
+      close(pipe_fd[1]);
+      return EXECUTE_FAILURE;
+    case 0:  // child
+      {
+        // DANGER: no calls to malloc or locks are allowed from now on:
+        // http://crbug.com/36678
+
+#if defined(OS_MACOSX)
+        RestoreDefaultExceptionHandler();
+#endif
+
+        // Obscure fork() rule: in the child, if you don't end up doing exec*(),
+        // you call _exit() instead of exit(). This is because _exit() does not
+        // call any previously-registered (in the parent) exit handlers, which
+        // might do things like block waiting for threads that don't even exist
+        // in the child.
+        int dev_null = open("/dev/null", O_WRONLY);
+        if (dev_null < 0)
+          _exit(127);
+
+        // Stop type-profiler.
+        // The profiler should be stopped between fork and exec since it inserts
+        // locks at new/delete expressions.  See http://crbug.com/36678.
+        base::type_profiler::Controller::Stop();
+
+        fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
+        // Adding another element here? Remeber to increase the argument to
+        // reserve(), above.
+
+        for (size_t i = 0; i < fd_shuffle1.size(); ++i)
+          fd_shuffle2.push_back(fd_shuffle1[i]);
+
+        if (!ShuffleFileDescriptors(&fd_shuffle1))
+          _exit(127);
+
+        CloseSuperfluousFds(fd_shuffle2);
+
+        for (size_t i = 0; i < argv.size(); i++)
+          argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+        argv_cstr[argv.size()] = NULL;
+        if (do_search_path)
+          execvp(argv_cstr[0], argv_cstr.get());
+        else
+          execve(argv_cstr[0], argv_cstr.get(), envp);
+        _exit(127);
+      }
+    default:  // parent
+      {
+        // Close our writing end of pipe now. Otherwise later read would not
+        // be able to detect end of child's output (in theory we could still
+        // write to the pipe).
+        close(pipe_fd[1]);
+
+        output->clear();
+        char buffer[256];
+        size_t output_buf_left = max_output;
+        ssize_t bytes_read = 1;  // A lie to properly handle |max_output == 0|
+                                 // case in the logic below.
+
+        while (output_buf_left > 0) {
+          bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer,
+                                    std::min(output_buf_left, sizeof(buffer))));
+          if (bytes_read <= 0)
+            break;
+          output->append(buffer, bytes_read);
+          output_buf_left -= static_cast<size_t>(bytes_read);
+        }
+        close(pipe_fd[0]);
+
+        // Always wait for exit code (even if we know we'll declare
+        // GOT_MAX_OUTPUT).
+        Process process(pid);
+        bool success = process.WaitForExit(exit_code);
+
+        // If we stopped because we read as much as we wanted, we return
+        // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
+        if (!output_buf_left && bytes_read > 0)
+          return GOT_MAX_OUTPUT;
+        else if (success)
+          return EXECUTE_SUCCESS;
+        return EXECUTE_FAILURE;
+      }
+  }
+}
+
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+  return GetAppOutput(cl.argv(), output);
+}
+
+bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      argv, NULL, output, std::numeric_limits<std::size_t>::max(), true,
+      &exit_code);
+  return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
+}
+
+// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we
+// don't hang if what we're calling hangs.
+bool GetAppOutputRestricted(const CommandLine& cl,
+                            std::string* output, size_t max_output) {
+  // Run |execve()| with the empty environment.
+  char* const empty_environ = NULL;
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), &empty_environ, output, max_output, false, &exit_code);
+  return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
+                                      exit_code == EXIT_SUCCESS);
+}
+
+bool GetAppOutputWithExitCode(const CommandLine& cl,
+                              std::string* output,
+                              int* exit_code) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true,
+      exit_code);
+  return result == EXECUTE_SUCCESS;
+}
+
+#if defined(OS_LINUX)
+pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) {
+  const bool clone_tls_used = flags & CLONE_SETTLS;
+  const bool invalid_ctid =
+      (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
+  const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid;
+
+  // We do not support CLONE_VM.
+  const bool clone_vm_used = flags & CLONE_VM;
+
+  if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) {
+    RAW_LOG(FATAL, "Invalid usage of ForkWithFlags");
+  }
+
+  // Valgrind's clone implementation does not support specifiying a child_stack
+  // without CLONE_VM, so we cannot use libc's clone wrapper when running under
+  // Valgrind. As a result, the libc pid cache may be incorrect under Valgrind.
+  // See crbug.com/442817 for more details.
+  if (IsRunningOnValgrind()) {
+    // See kernel/fork.c in Linux. There is different ordering of sys_clone
+    // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options.
+#if defined(ARCH_CPU_X86_64)
+    return syscall(__NR_clone, flags, nullptr, ptid, ctid, nullptr);
+#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)
+    // CONFIG_CLONE_BACKWARDS defined.
+    return syscall(__NR_clone, flags, nullptr, ptid, nullptr, ctid);
+#else
+#error "Unsupported architecture"
+#endif
+  }
+
+  jmp_buf env;
+  if (setjmp(env) == 0) {
+    return CloneAndLongjmpInChild(flags, ptid, ctid, &env);
+  }
+
+  return 0;
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace base
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
new file mode 100644
index 0000000..ebc19b8
--- /dev/null
+++ b/base/process/launch_win.cc
@@ -0,0 +1,353 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/launch.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <shellapi.h>
+#include <windows.h>
+#include <userenv.h>
+#include <psapi.h>
+
+#include <ios>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process/kill.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+
+// userenv.dll is required for CreateEnvironmentBlock().
+#pragma comment(lib, "userenv.lib")
+
+namespace base {
+
+namespace {
+
+// This exit code is used by the Windows task manager when it kills a
+// process.  It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
+}  // namespace
+
+void RouteStdioToConsole() {
+  // Don't change anything if stdout or stderr already point to a
+  // valid stream.
+  //
+  // If we are running under Buildbot or under Cygwin's default
+  // terminal (mintty), stderr and stderr will be pipe handles.  In
+  // that case, we don't want to open CONOUT$, because its output
+  // likely does not go anywhere.
+  //
+  // We don't use GetStdHandle() to check stdout/stderr here because
+  // it can return dangling IDs of handles that were never inherited
+  // by this process.  These IDs could have been reused by the time
+  // this function is called.  The CRT checks the validity of
+  // stdout/stderr on startup (before the handle IDs can be reused).
+  // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was
+  // invalid.
+  if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0)
+    return;
+
+  if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
+    unsigned int result = GetLastError();
+    // Was probably already attached.
+    if (result == ERROR_ACCESS_DENIED)
+      return;
+    // Don't bother creating a new console for each child process if the
+    // parent process is invalid (eg: crashed).
+    if (result == ERROR_GEN_FAILURE)
+      return;
+    // Make a new console if attaching to parent fails with any other error.
+    // It should be ERROR_INVALID_HANDLE at this point, which means the browser
+    // was likely not started from a console.
+    AllocConsole();
+  }
+
+  // Arbitrary byte count to use when buffering output lines.  More
+  // means potential waste, less means more risk of interleaved
+  // log-lines in output.
+  enum { kOutputBufferSize = 64 * 1024 };
+
+  if (freopen("CONOUT$", "w", stdout)) {
+    setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize);
+    // Overwrite FD 1 for the benefit of any code that uses this FD
+    // directly.  This is safe because the CRT allocates FDs 0, 1 and
+    // 2 at startup even if they don't have valid underlying Windows
+    // handles.  This means we won't be overwriting an FD created by
+    // _open() after startup.
+    _dup2(_fileno(stdout), 1);
+  }
+  if (freopen("CONOUT$", "w", stderr)) {
+    setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize);
+    _dup2(_fileno(stderr), 2);
+  }
+
+  // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
+  std::ios::sync_with_stdio();
+}
+
+Process LaunchProcess(const CommandLine& cmdline,
+                      const LaunchOptions& options) {
+  return LaunchProcess(cmdline.GetCommandLineString(), options);
+}
+
+Process LaunchProcess(const string16& cmdline,
+                      const LaunchOptions& options) {
+  win::StartupInformation startup_info_wrapper;
+  STARTUPINFO* startup_info = startup_info_wrapper.startup_info();
+
+  bool inherit_handles = options.inherit_handles;
+  DWORD flags = 0;
+  if (options.handles_to_inherit) {
+    if (options.handles_to_inherit->empty()) {
+      inherit_handles = false;
+    } else {
+      if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+        DLOG(ERROR) << "Specifying handles to inherit requires Vista or later.";
+        return Process();
+      }
+
+      if (options.handles_to_inherit->size() >
+              std::numeric_limits<DWORD>::max() / sizeof(HANDLE)) {
+        DLOG(ERROR) << "Too many handles to inherit.";
+        return Process();
+      }
+
+      if (!startup_info_wrapper.InitializeProcThreadAttributeList(1)) {
+        DPLOG(ERROR);
+        return Process();
+      }
+
+      if (!startup_info_wrapper.UpdateProcThreadAttribute(
+              PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+              const_cast<HANDLE*>(&options.handles_to_inherit->at(0)),
+              static_cast<DWORD>(options.handles_to_inherit->size() *
+                  sizeof(HANDLE)))) {
+        DPLOG(ERROR);
+        return Process();
+      }
+
+      inherit_handles = true;
+      flags |= EXTENDED_STARTUPINFO_PRESENT;
+    }
+  }
+
+  if (options.empty_desktop_name)
+    startup_info->lpDesktop = const_cast<wchar_t*>(L"");
+  startup_info->dwFlags = STARTF_USESHOWWINDOW;
+  startup_info->wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
+
+  if (options.stdin_handle || options.stdout_handle || options.stderr_handle) {
+    DCHECK(inherit_handles);
+    DCHECK(options.stdin_handle);
+    DCHECK(options.stdout_handle);
+    DCHECK(options.stderr_handle);
+    startup_info->dwFlags |= STARTF_USESTDHANDLES;
+    startup_info->hStdInput = options.stdin_handle;
+    startup_info->hStdOutput = options.stdout_handle;
+    startup_info->hStdError = options.stderr_handle;
+  }
+
+  if (options.job_handle) {
+    flags |= CREATE_SUSPENDED;
+
+    // If this code is run under a debugger, the launched process is
+    // automatically associated with a job object created by the debugger.
+    // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+  }
+
+  if (options.force_breakaway_from_job_)
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+
+  PROCESS_INFORMATION temp_process_info = {};
+
+  string16 writable_cmdline(cmdline);
+  if (options.as_user) {
+    flags |= CREATE_UNICODE_ENVIRONMENT;
+    void* enviroment_block = NULL;
+
+    if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) {
+      DPLOG(ERROR);
+      return Process();
+    }
+
+    BOOL launched =
+        CreateProcessAsUser(options.as_user, NULL,
+                            &writable_cmdline[0],
+                            NULL, NULL, inherit_handles, flags,
+                            enviroment_block, NULL, startup_info,
+                            &temp_process_info);
+    DestroyEnvironmentBlock(enviroment_block);
+    if (!launched) {
+      DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
+                   << std::endl;;
+      return Process();
+    }
+  } else {
+    if (!CreateProcess(NULL,
+                       &writable_cmdline[0], NULL, NULL,
+                       inherit_handles, flags, NULL, NULL,
+                       startup_info, &temp_process_info)) {
+      DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
+                   << std::endl;;
+      return Process();
+    }
+  }
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  if (options.job_handle) {
+    if (0 == AssignProcessToJobObject(options.job_handle,
+                                      process_info.process_handle())) {
+      DLOG(ERROR) << "Could not AssignProcessToObject.";
+      Process scoped_process(process_info.TakeProcessHandle());
+      scoped_process.Terminate(kProcessKilledExitCode, true);
+      return Process();
+    }
+
+    ResumeThread(process_info.thread_handle());
+  }
+
+  if (options.wait)
+    WaitForSingleObject(process_info.process_handle(), INFINITE);
+
+  return Process(process_info.TakeProcessHandle());
+}
+
+Process LaunchElevatedProcess(const CommandLine& cmdline,
+                              const LaunchOptions& options) {
+  const string16 file = cmdline.GetProgram().value();
+  const string16 arguments = cmdline.GetArgumentsString();
+
+  SHELLEXECUTEINFO shex_info = {0};
+  shex_info.cbSize = sizeof(shex_info);
+  shex_info.fMask = SEE_MASK_NOCLOSEPROCESS;
+  shex_info.hwnd = GetActiveWindow();
+  shex_info.lpVerb = L"runas";
+  shex_info.lpFile = file.c_str();
+  shex_info.lpParameters = arguments.c_str();
+  shex_info.lpDirectory = NULL;
+  shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW;
+  shex_info.hInstApp = NULL;
+
+  if (!ShellExecuteEx(&shex_info)) {
+    DPLOG(ERROR);
+    return Process();
+  }
+
+  if (options.wait)
+    WaitForSingleObject(shex_info.hProcess, INFINITE);
+
+  return Process(shex_info.hProcess);
+}
+
+bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) {
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
+  limit_info.BasicLimitInformation.LimitFlags = limit_flags;
+  return 0 != SetInformationJobObject(
+      job_object,
+      JobObjectExtendedLimitInformation,
+      &limit_info,
+      sizeof(limit_info));
+}
+
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+  return GetAppOutput(cl.GetCommandLineString(), output);
+}
+
+bool GetAppOutput(const StringPiece16& cl, std::string* output) {
+  HANDLE out_read = NULL;
+  HANDLE out_write = NULL;
+
+  SECURITY_ATTRIBUTES sa_attr;
+  // Set the bInheritHandle flag so pipe handles are inherited.
+  sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+  sa_attr.bInheritHandle = TRUE;
+  sa_attr.lpSecurityDescriptor = NULL;
+
+  // Create the pipe for the child process's STDOUT.
+  if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) {
+    NOTREACHED() << "Failed to create pipe";
+    return false;
+  }
+
+  // Ensure we don't leak the handles.
+  win::ScopedHandle scoped_out_read(out_read);
+  win::ScopedHandle scoped_out_write(out_write);
+
+  // Ensure the read handle to the pipe for STDOUT is not inherited.
+  if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
+    NOTREACHED() << "Failed to disabled pipe inheritance";
+    return false;
+  }
+
+  FilePath::StringType writable_command_line_string;
+  writable_command_line_string.assign(cl.data(), cl.size());
+
+  STARTUPINFO start_info = {};
+
+  start_info.cb = sizeof(STARTUPINFO);
+  start_info.hStdOutput = out_write;
+  // Keep the normal stdin and stderr.
+  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+  start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+  start_info.dwFlags |= STARTF_USESTDHANDLES;
+
+  // Create the child process.
+  PROCESS_INFORMATION temp_process_info = {};
+  if (!CreateProcess(NULL,
+                     &writable_command_line_string[0],
+                     NULL, NULL,
+                     TRUE,  // Handles are inherited.
+                     0, NULL, NULL, &start_info, &temp_process_info)) {
+    NOTREACHED() << "Failed to start process";
+    return false;
+  }
+  base::win::ScopedProcessInformation proc_info(temp_process_info);
+
+  // Close our writing end of pipe now. Otherwise later read would not be able
+  // to detect end of child's output.
+  scoped_out_write.Close();
+
+  // Read output from the child process's pipe for STDOUT
+  const int kBufferSize = 1024;
+  char buffer[kBufferSize];
+
+  for (;;) {
+    DWORD bytes_read = 0;
+    BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL);
+    if (!success || bytes_read == 0)
+      break;
+    output->append(buffer, bytes_read);
+  }
+
+  // Let's wait for the process to finish.
+  WaitForSingleObject(proc_info.process_handle(), INFINITE);
+
+  return true;
+}
+
+void RaiseProcessToHighPriority() {
+  SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+}
+
+}  // namespace base
diff --git a/base/process/memory.cc b/base/process/memory.cc
new file mode 100644
index 0000000..133a72a
--- /dev/null
+++ b/base/process/memory.cc
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/process/memory.h"
+
+namespace base {
+
+namespace {
+
+// Breakpad server classifies base::`anonymous namespace'::OnNoMemory as
+// out-of-memory crash.
+NOINLINE void OnNoMemory(size_t size) {
+  size_t tmp_size = size;
+  base::debug::Alias(&tmp_size);
+  LOG(FATAL) << "Out of memory. size=" << tmp_size;
+}
+
+}  // namespace
+
+void TerminateBecauseOutOfMemory(size_t size) {
+  OnNoMemory(size);
+}
+
+// Defined in memory_mac.mm for Mac.
+#if !defined(OS_MACOSX)
+
+bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
+  const size_t alloc_size = num_items * size;
+
+  // Overflow check
+  if (size && ((alloc_size / size) != num_items)) {
+    *result = NULL;
+    return false;
+  }
+
+  if (!UncheckedMalloc(alloc_size, result))
+    return false;
+
+  memset(*result, 0, alloc_size);
+  return true;
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/process/memory.h b/base/process/memory.h
new file mode 100644
index 0000000..da27151
--- /dev/null
+++ b/base/process/memory.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_MEMORY_H_
+#define BASE_PROCESS_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#ifdef PVALLOC_AVAILABLE
+// Build config explicitly tells us whether or not pvalloc is available.
+#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
+#define PVALLOC_AVAILABLE 1
+#else
+#define PVALLOC_AVAILABLE 0
+#endif
+
+namespace base {
+
+// Enables low fragmentation heap (LFH) for every heaps of this process. This
+// won't have any effect on heaps created after this function call. It will not
+// modify data allocated in the heaps before calling this function. So it is
+// better to call this function early in initialization and again before
+// entering the main loop.
+// Note: Returns true on Windows 2000 without doing anything.
+BASE_EXPORT bool EnableLowFragmentationHeap();
+
+// Enables 'terminate on heap corruption' flag. Helps protect against heap
+// overflow. Has no effect if the OS doesn't provide the necessary facility.
+BASE_EXPORT void EnableTerminationOnHeapCorruption();
+
+// Turns on process termination if memory runs out.
+BASE_EXPORT void EnableTerminationOnOutOfMemory();
+
+// Terminates process. Should be called only for out of memory errors.
+// Crash reporting classifies such crashes as OOM.
+BASE_EXPORT void TerminateBecauseOutOfMemory(size_t size);
+
+#if defined(OS_WIN)
+// Returns the module handle to which an address belongs. The reference count
+// of the module is not incremented.
+BASE_EXPORT HMODULE GetModuleFromAddress(void* address);
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+BASE_EXPORT extern size_t g_oom_size;
+
+// The maximum allowed value for the OOM score.
+const int kMaxOomScore = 1000;
+
+// This adjusts /proc/<pid>/oom_score_adj so the Linux OOM killer will
+// prefer to kill certain process types over others. The range for the
+// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
+// If the Linux system doesn't support the newer oom_score_adj range
+// of [0, 1000], then we revert to using the older oom_adj, and
+// translate the given value into [0, 15].  Some aliasing of values
+// may occur in that case, of course.
+BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score);
+#endif
+
+// Special allocator functions for callers that want to check for OOM.
+// These will not abort if the allocation fails even if
+// EnableTerminationOnOutOfMemory has been called.
+// This can be useful for huge and/or unpredictable size memory allocations.
+// Please only use this if you really handle the case when the allocation
+// fails. Doing otherwise would risk security.
+// These functions may still crash on OOM when running under memory tools,
+// specifically ASan and other sanitizers.
+// Return value tells whether the allocation succeeded. If it fails |result| is
+// set to NULL, otherwise it holds the memory address.
+BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedMalloc(size_t size,
+                                                    void** result);
+BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedCalloc(size_t num_items,
+                                                    size_t size,
+                                                    void** result);
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_MEMORY_H_
diff --git a/base/process/memory_linux.cc b/base/process/memory_linux.cc
new file mode 100644
index 0000000..6dbe8b7
--- /dev/null
+++ b/base/process/memory_linux.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+#include <new>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_number_conversions.h"
+
+#if defined(USE_TCMALLOC)
+// Used by UncheckedMalloc. If tcmalloc is linked to the executable
+// this will be replaced by a strong symbol that actually implement
+// the semantics and don't call new handler in case the allocation fails.
+extern "C" {
+
+__attribute__((weak, visibility("default")))
+void* tc_malloc_skip_new_handler_weak(size_t size);
+
+void* tc_malloc_skip_new_handler_weak(size_t size) {
+  return malloc(size);
+}
+
+}
+#endif
+
+namespace base {
+
+size_t g_oom_size = 0U;
+
+namespace {
+
+#if !defined(OS_ANDROID)
+void OnNoMemorySize(size_t size) {
+  g_oom_size = size;
+
+  if (size != 0)
+    LOG(FATAL) << "Out of memory, size = " << size;
+  LOG(FATAL) << "Out of memory.";
+}
+
+void OnNoMemory() {
+  OnNoMemorySize(0);
+}
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace
+
+#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+    !defined(THREAD_SANITIZER) && !defined(LEAK_SANITIZER)
+
+#if defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
+
+extern "C" {
+void* __libc_malloc(size_t size);
+void* __libc_realloc(void* ptr, size_t size);
+void* __libc_calloc(size_t nmemb, size_t size);
+void* __libc_valloc(size_t size);
+#if PVALLOC_AVAILABLE == 1
+void* __libc_pvalloc(size_t size);
+#endif
+void* __libc_memalign(size_t alignment, size_t size);
+
+// Overriding the system memory allocation functions:
+//
+// For security reasons, we want malloc failures to be fatal. Too much code
+// doesn't check for a NULL return value from malloc and unconditionally uses
+// the resulting pointer. If the first offset that they try to access is
+// attacker controlled, then the attacker can direct the code to access any
+// part of memory.
+//
+// Thus, we define all the standard malloc functions here and mark them as
+// visibility 'default'. This means that they replace the malloc functions for
+// all Chromium code and also for all code in shared libraries. There are tests
+// for this in process_util_unittest.cc.
+//
+// If we are using tcmalloc, then the problem is moot since tcmalloc handles
+// this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
+//
+// If we are testing the binary with AddressSanitizer, we should not
+// redefine malloc and let AddressSanitizer do it instead.
+//
+// We call the real libc functions in this code by using __libc_malloc etc.
+// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
+// the link order. Since ld.so needs calloc during symbol resolution, it
+// defines its own versions of several of these functions in dl-minimal.c.
+// Depending on the runtime library order, dlsym ended up giving us those
+// functions and bad things happened. See crbug.com/31809
+//
+// This means that any code which calls __libc_* gets the raw libc versions of
+// these functions.
+
+#define DIE_ON_OOM_1(function_name) \
+  void* function_name(size_t) __attribute__ ((visibility("default"))); \
+  \
+  void* function_name(size_t size) { \
+    void* ret = __libc_##function_name(size); \
+    if (ret == NULL && size != 0) \
+      OnNoMemorySize(size); \
+    return ret; \
+  }
+
+#define DIE_ON_OOM_2(function_name, arg1_type) \
+  void* function_name(arg1_type, size_t) \
+      __attribute__ ((visibility("default"))); \
+  \
+  void* function_name(arg1_type arg1, size_t size) { \
+    void* ret = __libc_##function_name(arg1, size); \
+    if (ret == NULL && size != 0) \
+      OnNoMemorySize(size); \
+    return ret; \
+  }
+
+DIE_ON_OOM_1(malloc)
+DIE_ON_OOM_1(valloc)
+#if PVALLOC_AVAILABLE == 1
+DIE_ON_OOM_1(pvalloc)
+#endif
+
+DIE_ON_OOM_2(calloc, size_t)
+DIE_ON_OOM_2(realloc, void*)
+DIE_ON_OOM_2(memalign, size_t)
+
+// posix_memalign has a unique signature and doesn't have a __libc_ variant.
+int posix_memalign(void** ptr, size_t alignment, size_t size)
+    __attribute__ ((visibility("default")));
+
+int posix_memalign(void** ptr, size_t alignment, size_t size) {
+  // This will use the safe version of memalign, above.
+  *ptr = memalign(alignment, size);
+  return 0;
+}
+
+}  // extern C
+
+#else
+
+// TODO(mostynb@opera.com): dlsym dance
+
+#endif  // LIBC_GLIBC && !USE_TCMALLOC
+
+#endif  // !*_SANITIZER
+
+void EnableTerminationOnHeapCorruption() {
+  // On Linux, there nothing to do AFAIK.
+}
+
+void EnableTerminationOnOutOfMemory() {
+#if defined(OS_ANDROID)
+  // Android doesn't support setting a new handler.
+  DLOG(WARNING) << "Not feasible.";
+#else
+  // Set the new-out of memory handler.
+  std::set_new_handler(&OnNoMemory);
+  // If we're using glibc's allocator, the above functions will override
+  // malloc and friends and make them die on out of memory.
+#endif
+}
+
+// NOTE: This is not the only version of this function in the source:
+// the setuid sandbox (in process_util_linux.c, in the sandbox source)
+// also has its own C version.
+bool AdjustOOMScore(ProcessId process, int score) {
+  if (score < 0 || score > kMaxOomScore)
+    return false;
+
+  FilePath oom_path(internal::GetProcPidDir(process));
+
+  // Attempt to write the newer oom_score_adj file first.
+  FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
+  if (PathExists(oom_file)) {
+    std::string score_str = IntToString(score);
+    DVLOG(1) << "Adjusting oom_score_adj of " << process << " to "
+             << score_str;
+    int score_len = static_cast<int>(score_str.length());
+    return (score_len == WriteFile(oom_file, score_str.c_str(), score_len));
+  }
+
+  // If the oom_score_adj file doesn't exist, then we write the old
+  // style file and translate the oom_adj score to the range 0-15.
+  oom_file = oom_path.AppendASCII("oom_adj");
+  if (PathExists(oom_file)) {
+    // Max score for the old oom_adj range.  Used for conversion of new
+    // values to old values.
+    const int kMaxOldOomScore = 15;
+
+    int converted_score = score * kMaxOldOomScore / kMaxOomScore;
+    std::string score_str = IntToString(converted_score);
+    DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
+    int score_len = static_cast<int>(score_str.length());
+    return (score_len == WriteFile(oom_file, score_str.c_str(), score_len));
+  }
+
+  return false;
+}
+
+bool UncheckedMalloc(size_t size, void** result) {
+#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) || \
+    (!defined(LIBC_GLIBC) && !defined(USE_TCMALLOC))
+  *result = malloc(size);
+#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
+  *result = __libc_malloc(size);
+#elif defined(USE_TCMALLOC)
+  *result = tc_malloc_skip_new_handler_weak(size);
+#endif
+  return *result != NULL;
+}
+
+}  // namespace base
diff --git a/base/process/memory_mac.mm b/base/process/memory_mac.mm
new file mode 100644
index 0000000..4d719f8
--- /dev/null
+++ b/base/process/memory_mac.mm
@@ -0,0 +1,561 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <malloc/malloc.h>
+#import <objc/runtime.h>
+
+#include <new>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/scoped_clear_errno.h"
+#include "third_party/apple_apsl/CFBase.h"
+#include "third_party/apple_apsl/malloc.h"
+
+namespace base {
+
+void EnableTerminationOnHeapCorruption() {
+#if !ARCH_CPU_64_BITS
+  DLOG(WARNING) << "EnableTerminationOnHeapCorruption only works on 64-bit";
+#endif
+}
+
+// ------------------------------------------------------------------------
+
+namespace {
+
+bool g_oom_killer_enabled;
+
+#if !defined(ADDRESS_SANITIZER)
+
+// Starting with Mac OS X 10.7, the zone allocators set up by the system are
+// read-only, to prevent them from being overwritten in an attack. However,
+// blindly unprotecting and reprotecting the zone allocators fails with
+// GuardMalloc because GuardMalloc sets up its zone allocator using a block of
+// memory in its bss. Explicit saving/restoring of the protection is required.
+//
+// This function takes a pointer to a malloc zone, de-protects it if necessary,
+// and returns (in the out parameters) a region of memory (if any) to be
+// re-protected when modifications are complete. This approach assumes that
+// there is no contention for the protection of this memory.
+void DeprotectMallocZone(ChromeMallocZone* default_zone,
+                         mach_vm_address_t* reprotection_start,
+                         mach_vm_size_t* reprotection_length,
+                         vm_prot_t* reprotection_value) {
+  mach_port_t unused;
+  *reprotection_start = reinterpret_cast<mach_vm_address_t>(default_zone);
+  struct vm_region_basic_info_64 info;
+  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+  kern_return_t result =
+      mach_vm_region(mach_task_self(),
+                     reprotection_start,
+                     reprotection_length,
+                     VM_REGION_BASIC_INFO_64,
+                     reinterpret_cast<vm_region_info_t>(&info),
+                     &count,
+                     &unused);
+  MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_region";
+
+  // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
+  // balance it with a deallocate in case this ever changes. See 10.9.2
+  // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
+  mach_port_deallocate(mach_task_self(), unused);
+
+  // Does the region fully enclose the zone pointers? Possibly unwarranted
+  // simplification used: using the size of a full version 8 malloc zone rather
+  // than the actual smaller size if the passed-in zone is not version 8.
+  CHECK(*reprotection_start <=
+            reinterpret_cast<mach_vm_address_t>(default_zone));
+  mach_vm_size_t zone_offset = reinterpret_cast<mach_vm_size_t>(default_zone) -
+      reinterpret_cast<mach_vm_size_t>(*reprotection_start);
+  CHECK(zone_offset + sizeof(ChromeMallocZone) <= *reprotection_length);
+
+  if (info.protection & VM_PROT_WRITE) {
+    // No change needed; the zone is already writable.
+    *reprotection_start = 0;
+    *reprotection_length = 0;
+    *reprotection_value = VM_PROT_NONE;
+  } else {
+    *reprotection_value = info.protection;
+    result = mach_vm_protect(mach_task_self(),
+                             *reprotection_start,
+                             *reprotection_length,
+                             false,
+                             info.protection | VM_PROT_WRITE);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+}
+
+// === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+typedef void* (*malloc_type)(struct _malloc_zone_t* zone,
+                             size_t size);
+typedef void* (*calloc_type)(struct _malloc_zone_t* zone,
+                             size_t num_items,
+                             size_t size);
+typedef void* (*valloc_type)(struct _malloc_zone_t* zone,
+                             size_t size);
+typedef void (*free_type)(struct _malloc_zone_t* zone,
+                          void* ptr);
+typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
+                              void* ptr,
+                              size_t size);
+typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
+                               size_t alignment,
+                               size_t size);
+
+malloc_type g_old_malloc;
+calloc_type g_old_calloc;
+valloc_type g_old_valloc;
+free_type g_old_free;
+realloc_type g_old_realloc;
+memalign_type g_old_memalign;
+
+malloc_type g_old_malloc_purgeable;
+calloc_type g_old_calloc_purgeable;
+valloc_type g_old_valloc_purgeable;
+free_type g_old_free_purgeable;
+realloc_type g_old_realloc_purgeable;
+memalign_type g_old_memalign_purgeable;
+
+void* oom_killer_malloc(struct _malloc_zone_t* zone,
+                        size_t size) {
+  void* result = g_old_malloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_calloc(struct _malloc_zone_t* zone,
+                        size_t num_items,
+                        size_t size) {
+  void* result = g_old_calloc(zone, num_items, size);
+  if (!result && num_items && size)
+    TerminateBecauseOutOfMemory(num_items * size);
+  return result;
+}
+
+void* oom_killer_valloc(struct _malloc_zone_t* zone,
+                        size_t size) {
+  void* result = g_old_valloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void oom_killer_free(struct _malloc_zone_t* zone,
+                     void* ptr) {
+  g_old_free(zone, ptr);
+}
+
+void* oom_killer_realloc(struct _malloc_zone_t* zone,
+                         void* ptr,
+                         size_t size) {
+  void* result = g_old_realloc(zone, ptr, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_memalign(struct _malloc_zone_t* zone,
+                          size_t alignment,
+                          size_t size) {
+  void* result = g_old_memalign(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*) &&
+      (alignment & (alignment - 1)) == 0) {
+    TerminateBecauseOutOfMemory(size);
+  }
+  return result;
+}
+
+void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t size) {
+  void* result = g_old_malloc_purgeable(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t num_items,
+                                  size_t size) {
+  void* result = g_old_calloc_purgeable(zone, num_items, size);
+  if (!result && num_items && size)
+    TerminateBecauseOutOfMemory(num_items * size);
+  return result;
+}
+
+void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t size) {
+  void* result = g_old_valloc_purgeable(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void oom_killer_free_purgeable(struct _malloc_zone_t* zone,
+                               void* ptr) {
+  g_old_free_purgeable(zone, ptr);
+}
+
+void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
+                                   void* ptr,
+                                   size_t size) {
+  void* result = g_old_realloc_purgeable(zone, ptr, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
+                                    size_t alignment,
+                                    size_t size) {
+  void* result = g_old_memalign_purgeable(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*)
+      && (alignment & (alignment - 1)) == 0) {
+    TerminateBecauseOutOfMemory(size);
+  }
+  return result;
+}
+
+#endif  // !defined(ADDRESS_SANITIZER)
+
+// === C++ operator new ===
+
+void oom_killer_new() {
+  TerminateBecauseOutOfMemory(0);
+}
+
+#if !defined(ADDRESS_SANITIZER)
+
+// === Core Foundation CFAllocators ===
+
+bool CanGetContextForCFAllocator() {
+  return !base::mac::IsOSLaterThanYosemite_DontCallThis();
+}
+
+CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
+  if (base::mac::IsOSSnowLeopard()) {
+    ChromeCFAllocatorLeopards* our_allocator =
+        const_cast<ChromeCFAllocatorLeopards*>(
+            reinterpret_cast<const ChromeCFAllocatorLeopards*>(allocator));
+    return &our_allocator->_context;
+  } else if (base::mac::IsOSLion() ||
+             base::mac::IsOSMountainLion() ||
+             base::mac::IsOSMavericks() ||
+             base::mac::IsOSYosemite()) {
+    ChromeCFAllocatorLions* our_allocator =
+        const_cast<ChromeCFAllocatorLions*>(
+            reinterpret_cast<const ChromeCFAllocatorLions*>(allocator));
+    return &our_allocator->_context;
+  } else {
+    return NULL;
+  }
+}
+
+CFAllocatorAllocateCallBack g_old_cfallocator_system_default;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone;
+
+void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
+                                            CFOptionFlags hint,
+                                            void* info) {
+  void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
+                                    CFOptionFlags hint,
+                                    void* info) {
+  void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
+                                         CFOptionFlags hint,
+                                         void* info) {
+  void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+#endif  // !defined(ADDRESS_SANITIZER)
+
+// === Cocoa NSObject allocation ===
+
+typedef id (*allocWithZone_t)(id, SEL, NSZone*);
+allocWithZone_t g_old_allocWithZone;
+
+id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone)
+{
+  id result = g_old_allocWithZone(self, _cmd, zone);
+  if (!result)
+    TerminateBecauseOutOfMemory(0);
+  return result;
+}
+
+}  // namespace
+
+bool UncheckedMalloc(size_t size, void** result) {
+#if defined(ADDRESS_SANITIZER)
+  *result = malloc(size);
+#else
+  if (g_old_malloc) {
+    *result = g_old_malloc(malloc_default_zone(), size);
+  } else {
+    *result = malloc(size);
+  }
+#endif  // defined(ADDRESS_SANITIZER)
+
+  return *result != NULL;
+}
+
+bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
+#if defined(ADDRESS_SANITIZER)
+  *result = calloc(num_items, size);
+#else
+  if (g_old_calloc) {
+    *result = g_old_calloc(malloc_default_zone(), num_items, size);
+  } else {
+    *result = calloc(num_items, size);
+  }
+#endif  // defined(ADDRESS_SANITIZER)
+
+  return *result != NULL;
+}
+
+void* UncheckedMalloc(size_t size) {
+  void* address;
+  return UncheckedMalloc(size, &address) ? address : NULL;
+}
+
+void* UncheckedCalloc(size_t num_items, size_t size) {
+  void* address;
+  return UncheckedCalloc(num_items, size, &address) ? address : NULL;
+}
+
+void EnableTerminationOnOutOfMemory() {
+  if (g_oom_killer_enabled)
+    return;
+
+  g_oom_killer_enabled = true;
+
+  // === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+  // This approach is not perfect, as requests for amounts of memory larger than
+  // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will
+  // still fail with a NULL rather than dying (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details).
+  // Unfortunately, it's the best we can do. Also note that this does not affect
+  // allocations from non-default zones.
+
+#if !defined(ADDRESS_SANITIZER)
+  // Don't do anything special on OOM for the malloc zones replaced by
+  // AddressSanitizer, as modifying or protecting them may not work correctly.
+
+  CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc &&
+        !g_old_memalign) << "Old allocators unexpectedly non-null";
+
+  CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable &&
+        !g_old_valloc_purgeable && !g_old_realloc_purgeable &&
+        !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
+
+  ChromeMallocZone* default_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
+  ChromeMallocZone* purgeable_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone());
+
+  mach_vm_address_t default_reprotection_start = 0;
+  mach_vm_size_t default_reprotection_length = 0;
+  vm_prot_t default_reprotection_value = VM_PROT_NONE;
+  DeprotectMallocZone(default_zone,
+                      &default_reprotection_start,
+                      &default_reprotection_length,
+                      &default_reprotection_value);
+
+  mach_vm_address_t purgeable_reprotection_start = 0;
+  mach_vm_size_t purgeable_reprotection_length = 0;
+  vm_prot_t purgeable_reprotection_value = VM_PROT_NONE;
+  if (purgeable_zone) {
+    DeprotectMallocZone(purgeable_zone,
+                        &purgeable_reprotection_start,
+                        &purgeable_reprotection_length,
+                        &purgeable_reprotection_value);
+  }
+
+  // Default zone
+
+  g_old_malloc = default_zone->malloc;
+  g_old_calloc = default_zone->calloc;
+  g_old_valloc = default_zone->valloc;
+  g_old_free = default_zone->free;
+  g_old_realloc = default_zone->realloc;
+  CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free &&
+        g_old_realloc)
+      << "Failed to get system allocation functions.";
+
+  default_zone->malloc = oom_killer_malloc;
+  default_zone->calloc = oom_killer_calloc;
+  default_zone->valloc = oom_killer_valloc;
+  default_zone->free = oom_killer_free;
+  default_zone->realloc = oom_killer_realloc;
+
+  if (default_zone->version >= 5) {
+    g_old_memalign = default_zone->memalign;
+    if (g_old_memalign)
+      default_zone->memalign = oom_killer_memalign;
+  }
+
+  // Purgeable zone (if it exists)
+
+  if (purgeable_zone) {
+    g_old_malloc_purgeable = purgeable_zone->malloc;
+    g_old_calloc_purgeable = purgeable_zone->calloc;
+    g_old_valloc_purgeable = purgeable_zone->valloc;
+    g_old_free_purgeable = purgeable_zone->free;
+    g_old_realloc_purgeable = purgeable_zone->realloc;
+    CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable &&
+          g_old_valloc_purgeable && g_old_free_purgeable &&
+          g_old_realloc_purgeable)
+        << "Failed to get system allocation functions.";
+
+    purgeable_zone->malloc = oom_killer_malloc_purgeable;
+    purgeable_zone->calloc = oom_killer_calloc_purgeable;
+    purgeable_zone->valloc = oom_killer_valloc_purgeable;
+    purgeable_zone->free = oom_killer_free_purgeable;
+    purgeable_zone->realloc = oom_killer_realloc_purgeable;
+
+    if (purgeable_zone->version >= 5) {
+      g_old_memalign_purgeable = purgeable_zone->memalign;
+      if (g_old_memalign_purgeable)
+        purgeable_zone->memalign = oom_killer_memalign_purgeable;
+    }
+  }
+
+  // Restore protection if it was active.
+
+  if (default_reprotection_start) {
+    kern_return_t result = mach_vm_protect(mach_task_self(),
+                                           default_reprotection_start,
+                                           default_reprotection_length,
+                                           false,
+                                           default_reprotection_value);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+
+  if (purgeable_reprotection_start) {
+    kern_return_t result = mach_vm_protect(mach_task_self(),
+                                           purgeable_reprotection_start,
+                                           purgeable_reprotection_length,
+                                           false,
+                                           purgeable_reprotection_value);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+#endif
+
+  // === C malloc_zone_batch_malloc ===
+
+  // batch_malloc is omitted because the default malloc zone's implementation
+  // only supports batch_malloc for "tiny" allocations from the free list. It
+  // will fail for allocations larger than "tiny", and will only allocate as
+  // many blocks as it's able to from the free list. These factors mean that it
+  // can return less than the requested memory even in a non-out-of-memory
+  // situation. There's no good way to detect whether a batch_malloc failure is
+  // due to these other factors, or due to genuine memory or address space
+  // exhaustion. The fact that it only allocates space from the "tiny" free list
+  // means that it's likely that a failure will not be due to memory exhaustion.
+  // Similarly, these constraints on batch_malloc mean that callers must always
+  // be expecting to receive less memory than was requested, even in situations
+  // where memory pressure is not a concern. Finally, the only public interface
+  // to batch_malloc is malloc_zone_batch_malloc, which is specific to the
+  // system's malloc implementation. It's unlikely that anyone's even heard of
+  // it.
+
+  // === C++ operator new ===
+
+  // Yes, operator new does call through to malloc, but this will catch failures
+  // that our imperfect handling of malloc cannot.
+
+  std::set_new_handler(oom_killer_new);
+
+#ifndef ADDRESS_SANITIZER
+  // === Core Foundation CFAllocators ===
+
+  // This will not catch allocation done by custom allocators, but will catch
+  // all allocation done by system-provided ones.
+
+  CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc &&
+        !g_old_cfallocator_malloc_zone)
+      << "Old allocators unexpectedly non-null";
+
+  bool cf_allocator_internals_known = CanGetContextForCFAllocator();
+
+  if (cf_allocator_internals_known) {
+    CFAllocatorContext* context =
+        ContextForCFAllocator(kCFAllocatorSystemDefault);
+    CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault.";
+    g_old_cfallocator_system_default = context->allocate;
+    CHECK(g_old_cfallocator_system_default)
+        << "Failed to get kCFAllocatorSystemDefault allocation function.";
+    context->allocate = oom_killer_cfallocator_system_default;
+
+    context = ContextForCFAllocator(kCFAllocatorMalloc);
+    CHECK(context) << "Failed to get context for kCFAllocatorMalloc.";
+    g_old_cfallocator_malloc = context->allocate;
+    CHECK(g_old_cfallocator_malloc)
+        << "Failed to get kCFAllocatorMalloc allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc;
+
+    context = ContextForCFAllocator(kCFAllocatorMallocZone);
+    CHECK(context) << "Failed to get context for kCFAllocatorMallocZone.";
+    g_old_cfallocator_malloc_zone = context->allocate;
+    CHECK(g_old_cfallocator_malloc_zone)
+        << "Failed to get kCFAllocatorMallocZone allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc_zone;
+  } else {
+    DLOG(WARNING) << "Internals of CFAllocator not known; out-of-memory "
+                     "failures via CFAllocator will not result in termination. "
+                     "http://crbug.com/45650";
+  }
+#endif
+
+  // === Cocoa NSObject allocation ===
+
+  // Note that both +[NSObject new] and +[NSObject alloc] call through to
+  // +[NSObject allocWithZone:].
+
+  CHECK(!g_old_allocWithZone)
+      << "Old allocator unexpectedly non-null";
+
+  Class nsobject_class = [NSObject class];
+  Method orig_method = class_getClassMethod(nsobject_class,
+                                            @selector(allocWithZone:));
+  g_old_allocWithZone = reinterpret_cast<allocWithZone_t>(
+      method_getImplementation(orig_method));
+  CHECK(g_old_allocWithZone)
+      << "Failed to get allocWithZone allocation function.";
+  method_setImplementation(orig_method,
+                           reinterpret_cast<IMP>(oom_killer_allocWithZone));
+}
+
+}  // namespace base
diff --git a/base/process/memory_stubs.cc b/base/process/memory_stubs.cc
new file mode 100644
index 0000000..b06c7d5
--- /dev/null
+++ b/base/process/memory_stubs.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+namespace base {
+
+void EnableTerminationOnOutOfMemory() {
+}
+
+void EnableTerminationOnHeapCorruption() {
+}
+
+bool AdjustOOMScore(ProcessId process, int score) {
+  return false;
+}
+
+}  // namespace base
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc
new file mode 100644
index 0000000..0276b49
--- /dev/null
+++ b/base/process/memory_unittest.cc
@@ -0,0 +1,419 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "base/process/memory.h"
+
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#if defined(OS_POSIX)
+#include <errno.h>
+#endif
+#if defined(OS_MACOSX)
+#include <malloc/malloc.h>
+#include "base/mac/mac_util.h"
+#include "base/process/memory_unittest_mac.h"
+#endif
+#if defined(OS_LINUX)
+#include <malloc.h>
+#include "base/test/malloc_wrapper.h"
+#endif
+
+#if defined(OS_WIN)
+// HeapQueryInformation function pointer.
+typedef BOOL (WINAPI* HeapQueryFn)  \
+    (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
+
+const int kConstantInModule = 42;
+
+TEST(ProcessMemoryTest, GetModuleFromAddress) {
+  // Since the unit tests are their own EXE, this should be
+  // equivalent to the EXE's HINSTANCE.
+  //
+  // kConstantInModule is a constant in this file and
+  // therefore within the unit test EXE.
+  EXPECT_EQ(::GetModuleHandle(NULL),
+            base::GetModuleFromAddress(
+                const_cast<int*>(&kConstantInModule)));
+
+  // Any address within the kernel32 module should return
+  // kernel32's HMODULE.  Our only assumption here is that
+  // kernel32 is larger than 4 bytes.
+  HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
+  HMODULE kernel32_from_address =
+      base::GetModuleFromAddress(reinterpret_cast<DWORD*>(kernel32) + 1);
+  EXPECT_EQ(kernel32, kernel32_from_address);
+}
+
+TEST(ProcessMemoryTest, EnableLFH) {
+  ASSERT_TRUE(base::EnableLowFragmentationHeap());
+  if (IsDebuggerPresent()) {
+    // Under these conditions, LFH can't be enabled. There's no point to test
+    // anything.
+    const char* no_debug_env = getenv("_NO_DEBUG_HEAP");
+    if (!no_debug_env || strcmp(no_debug_env, "1"))
+      return;
+  }
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  ASSERT_TRUE(kernel32 != NULL);
+  HeapQueryFn heap_query = reinterpret_cast<HeapQueryFn>(GetProcAddress(
+      kernel32,
+      "HeapQueryInformation"));
+
+  // On Windows 2000, the function is not exported. This is not a reason to
+  // fail but we won't be able to retrieves information about the heap, so we
+  // should stop here.
+  if (heap_query == NULL)
+    return;
+
+  HANDLE heaps[1024] = { 0 };
+  unsigned number_heaps = GetProcessHeaps(1024, heaps);
+  EXPECT_GT(number_heaps, 0u);
+  for (unsigned i = 0; i < number_heaps; ++i) {
+    ULONG flag = 0;
+    SIZE_T length;
+    ASSERT_NE(0, heap_query(heaps[i],
+                            HeapCompatibilityInformation,
+                            &flag,
+                            sizeof(flag),
+                            &length));
+    // If flag is 0, the heap is a standard heap that does not support
+    // look-asides. If flag is 1, the heap supports look-asides. If flag is 2,
+    // the heap is a low-fragmentation heap (LFH). Note that look-asides are not
+    // supported on the LFH.
+
+    // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag.
+    EXPECT_LE(flag, 2u);
+    EXPECT_NE(flag, 1u);
+  }
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+
+// For the following Mac tests:
+// Note that base::EnableTerminationOnHeapCorruption() is called as part of
+// test suite setup and does not need to be done again, else mach_override
+// will fail.
+
+TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) {
+  // Assert that freeing an unallocated pointer will crash the process.
+  char buf[9];
+  asm("" : "=r" (buf));  // Prevent clang from being too smart.
+#if ARCH_CPU_64_BITS
+  // On 64 bit Macs, the malloc system automatically abort()s on heap corruption
+  // but does not output anything.
+  ASSERT_DEATH(free(buf), "");
+#elif defined(ADDRESS_SANITIZER)
+  // AddressSanitizer replaces malloc() and prints a different error message on
+  // heap corruption.
+  ASSERT_DEATH(free(buf), "attempting free on address which "
+      "was not malloc\\(\\)-ed");
+#else
+  ADD_FAILURE() << "This test is not supported in this build configuration.";
+#endif
+}
+
+#endif  // defined(OS_MACOSX)
+
+// Android doesn't implement set_new_handler, so we can't use the
+// OutOfMemoryTest cases. OpenBSD does not support these tests either.
+// Don't test these on ASan/TSan/MSan configurations: only test the real
+// allocator.
+// TODO(vandebo) make this work on Windows too.
+#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && \
+    !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+
+#if defined(USE_TCMALLOC)
+extern "C" {
+int tc_set_new_mode(int mode);
+}
+#endif  // defined(USE_TCMALLOC)
+
+namespace {
+const char *kOomRegex = "Out of memory";
+}  // namespace
+
+class OutOfMemoryTest : public testing::Test {
+ public:
+  OutOfMemoryTest()
+    : value_(NULL),
+    // Make test size as large as possible minus a few pages so
+    // that alignment or other rounding doesn't make it wrap.
+    test_size_(std::numeric_limits<std::size_t>::max() - 12 * 1024),
+    signed_test_size_(std::numeric_limits<ssize_t>::max()) {
+  }
+
+#if defined(USE_TCMALLOC)
+  void SetUp() override { tc_set_new_mode(1); }
+
+  void TearDown() override { tc_set_new_mode(0); }
+#endif  // defined(USE_TCMALLOC)
+
+ protected:
+  void* value_;
+  size_t test_size_;
+  ssize_t signed_test_size_;
+};
+
+class OutOfMemoryDeathTest : public OutOfMemoryTest {
+ public:
+  void SetUpInDeathAssert() {
+    // Must call EnableTerminationOnOutOfMemory() because that is called from
+    // chrome's main function and therefore hasn't been called yet.
+    // Since this call may result in another thread being created and death
+    // tests shouldn't be started in a multithread environment, this call
+    // should be done inside of the ASSERT_DEATH.
+    base::EnableTerminationOnOutOfMemory();
+  }
+};
+
+TEST_F(OutOfMemoryDeathTest, New) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = operator new(test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, NewArray) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = new char[test_size_];
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Malloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc(test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Realloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = realloc(NULL, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Calloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = calloc(1024, test_size_ / 1024L);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Valloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = valloc(test_size_);
+    }, kOomRegex);
+}
+
+#if defined(OS_LINUX)
+
+#if PVALLOC_AVAILABLE == 1
+TEST_F(OutOfMemoryDeathTest, Pvalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = pvalloc(test_size_);
+    }, kOomRegex);
+}
+#endif  // PVALLOC_AVAILABLE == 1
+
+TEST_F(OutOfMemoryDeathTest, Memalign) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = memalign(4, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
+  // This tests that the run-time symbol resolution is overriding malloc for
+  // shared libraries as well as for our code.
+  ASSERT_DEATH({
+    SetUpInDeathAssert();
+    value_ = MallocWrapper(test_size_);
+  }, kOomRegex);
+}
+#endif  // OS_LINUX
+
+// Android doesn't implement posix_memalign().
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
+  // Grab the return value of posix_memalign to silence a compiler warning
+  // about unused return values. We don't actually care about the return
+  // value, since we're asserting death.
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
+    }, kOomRegex);
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+#if defined(OS_MACOSX)
+
+// Purgeable zone tests
+
+TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_malloc(zone, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_realloc(zone, NULL, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_valloc(zone, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_memalign(zone, 8, test_size_);
+    }, kOomRegex);
+}
+
+// Since these allocation functions take a signed size, it's possible that
+// calling them just once won't be enough to exhaust memory. In the 32-bit
+// environment, it's likely that these allocation attempts will fail because
+// not enough contiguous address space is available. In the 64-bit environment,
+// it's likely that they'll fail because they would require a preposterous
+// amount of (virtual) memory.
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
+    }, kOomRegex);
+}
+
+#if !defined(ARCH_CPU_64_BITS)
+
+// See process_util_unittest_mac.mm for an explanation of why this test isn't
+// run in the 64-bit environment.
+
+TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
+    }, kOomRegex);
+}
+
+#endif  // !ARCH_CPU_64_BITS
+#endif  // OS_MACOSX
+
+class OutOfMemoryHandledTest : public OutOfMemoryTest {
+ public:
+  static const size_t kSafeMallocSize = 512;
+  static const size_t kSafeCallocSize = 128;
+  static const size_t kSafeCallocItems = 4;
+
+  void SetUp() override {
+    OutOfMemoryTest::SetUp();
+
+    // We enable termination on OOM - just as Chrome does at early
+    // initialization - and test that UncheckedMalloc and  UncheckedCalloc
+    // properly by-pass this in order to allow the caller to handle OOM.
+    base::EnableTerminationOnOutOfMemory();
+  }
+};
+
+// TODO(b.kelemen): make UncheckedMalloc and UncheckedCalloc work
+// on Windows as well.
+// UncheckedMalloc() and UncheckedCalloc() work as regular malloc()/calloc()
+// under sanitizer tools.
+#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) {
+#if defined(OS_MACOSX) && ARCH_CPU_32_BITS
+  // The Mavericks malloc library changed in a way which breaks the tricks used
+  // to implement EnableTerminationOnOutOfMemory() with UncheckedMalloc() under
+  // 32-bit.  The 64-bit malloc library works as desired without tricks.
+  if (base::mac::IsOSMavericksOrLater())
+    return;
+#endif
+  EXPECT_TRUE(base::UncheckedMalloc(kSafeMallocSize, &value_));
+  EXPECT_TRUE(value_ != NULL);
+  free(value_);
+
+  EXPECT_FALSE(base::UncheckedMalloc(test_size_, &value_));
+  EXPECT_TRUE(value_ == NULL);
+}
+
+TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) {
+#if defined(OS_MACOSX) && ARCH_CPU_32_BITS
+  // The Mavericks malloc library changed in a way which breaks the tricks used
+  // to implement EnableTerminationOnOutOfMemory() with UncheckedCalloc() under
+  // 32-bit.  The 64-bit malloc library works as desired without tricks.
+  if (base::mac::IsOSMavericksOrLater())
+    return;
+#endif
+  EXPECT_TRUE(base::UncheckedCalloc(1, kSafeMallocSize, &value_));
+  EXPECT_TRUE(value_ != NULL);
+  const char* bytes = static_cast<const char*>(value_);
+  for (size_t i = 0; i < kSafeMallocSize; ++i)
+    EXPECT_EQ(0, bytes[i]);
+  free(value_);
+
+  EXPECT_TRUE(
+      base::UncheckedCalloc(kSafeCallocItems, kSafeCallocSize, &value_));
+  EXPECT_TRUE(value_ != NULL);
+  bytes = static_cast<const char*>(value_);
+  for (size_t i = 0; i < (kSafeCallocItems * kSafeCallocSize); ++i)
+    EXPECT_EQ(0, bytes[i]);
+  free(value_);
+
+  EXPECT_FALSE(base::UncheckedCalloc(1, test_size_, &value_));
+  EXPECT_TRUE(value_ == NULL);
+}
+#endif  // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+#endif  // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) &&
+        // !defined(ADDRESS_SANITIZER)
diff --git a/base/process/memory_unittest_mac.h b/base/process/memory_unittest_mac.h
new file mode 100644
index 0000000..472d2c5
--- /dev/null
+++ b/base/process/memory_unittest_mac.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains helpers for the process_util_unittest to allow it to fully
+// test the Mac code.
+
+#ifndef BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
+#define BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Allocates memory via system allocators. Alas, they take a _signed_ size for
+// allocation.
+void* AllocateViaCFAllocatorSystemDefault(ssize_t size);
+void* AllocateViaCFAllocatorMalloc(ssize_t size);
+void* AllocateViaCFAllocatorMallocZone(ssize_t size);
+
+#if !defined(ARCH_CPU_64_BITS)
+// See process_util_unittest_mac.mm for an explanation of why this function
+// isn't implemented for the 64-bit environment.
+
+// Allocates a huge Objective C object.
+void* AllocatePsychoticallyBigObjCObject();
+
+#endif  // !ARCH_CPU_64_BITS
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
diff --git a/base/process/memory_unittest_mac.mm b/base/process/memory_unittest_mac.mm
new file mode 100644
index 0000000..bc4bf65
--- /dev/null
+++ b/base/process/memory_unittest_mac.mm
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory_unittest_mac.h"
+
+#import <Foundation/Foundation.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#if !defined(ARCH_CPU_64_BITS)
+
+// In the 64-bit environment, the Objective-C 2.0 Runtime Reference states
+// that sizeof(anInstance) is constrained to 32 bits. That's not necessarily
+// "psychotically big" and in fact a 64-bit program is expected to be able to
+// successfully allocate an object that large, likely reserving a good deal of
+// swap space. The only way to test the behavior of memory exhaustion for
+// Objective-C allocation in this environment would be to loop over allocation
+// of these large objects, but that would slowly consume all available memory
+// and cause swap file proliferation. That's bad, so this behavior isn't
+// tested in the 64-bit environment.
+
+@interface PsychoticallyBigObjCObject : NSObject
+{
+  // In the 32-bit environment, the compiler limits Objective-C objects to
+  // < 2GB in size.
+  int justUnder2Gigs_[(2U * 1024 * 1024 * 1024 - 1) / sizeof(int)];
+}
+
+@end
+
+@implementation PsychoticallyBigObjCObject
+
+@end
+
+namespace base {
+
+void* AllocatePsychoticallyBigObjCObject() {
+  return [[PsychoticallyBigObjCObject alloc] init];
+}
+
+}  // namespace base
+
+#endif  // ARCH_CPU_64_BITS
+
+namespace base {
+
+void* AllocateViaCFAllocatorSystemDefault(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0);
+}
+
+void* AllocateViaCFAllocatorMalloc(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorMalloc, size, 0);
+}
+
+void* AllocateViaCFAllocatorMallocZone(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorMallocZone, size, 0);
+}
+
+}  // namespace base
diff --git a/base/process/memory_win.cc b/base/process/memory_win.cc
new file mode 100644
index 0000000..fc57b48
--- /dev/null
+++ b/base/process/memory_win.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+#include <new.h>
+#include <psapi.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+namespace {
+
+#pragma warning(push)
+#pragma warning(disable: 4702)
+
+int OnNoMemory(size_t) {
+  // Kill the process. This is important for security since most of code
+  // does not check the result of memory allocation.
+  __debugbreak();
+  _exit(1);
+  return 0;
+}
+
+#pragma warning(pop)
+
+// HeapSetInformation function pointer.
+typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
+
+}  // namespace
+
+bool EnableLowFragmentationHeap() {
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
+      kernel32,
+      "HeapSetInformation"));
+
+  // On Windows 2000, the function is not exported. This is not a reason to
+  // fail.
+  if (!heap_set)
+    return true;
+
+  unsigned number_heaps = GetProcessHeaps(0, NULL);
+  if (!number_heaps)
+    return false;
+
+  // Gives us some extra space in the array in case a thread is creating heaps
+  // at the same time we're querying them.
+  static const int MARGIN = 8;
+  scoped_ptr<HANDLE[]> heaps(new HANDLE[number_heaps + MARGIN]);
+  number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
+  if (!number_heaps)
+    return false;
+
+  for (unsigned i = 0; i < number_heaps; ++i) {
+    ULONG lfh_flag = 2;
+    // Don't bother with the result code. It may fails on heaps that have the
+    // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
+    heap_set(heaps[i],
+             HeapCompatibilityInformation,
+             &lfh_flag,
+             sizeof(lfh_flag));
+  }
+  return true;
+}
+
+void EnableTerminationOnHeapCorruption() {
+  // Ignore the result code. Supported on XP SP3 and Vista.
+  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
+}
+
+void EnableTerminationOnOutOfMemory() {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+}
+
+HMODULE GetModuleFromAddress(void* address) {
+  HMODULE instance = NULL;
+  if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                            GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                            static_cast<char*>(address),
+                            &instance)) {
+    NOTREACHED();
+  }
+  return instance;
+}
+
+// TODO(b.kelemen): implement it with the required semantics. On Linux this is
+// implemented with a weak symbol that is overridden by tcmalloc. This is
+// neccessary because base cannot have a direct dependency on tcmalloc. Since
+// weak symbols are not supported on Windows this will involve some build time
+// magic, much like what is done for libcrt in order to override the allocation
+// functions.
+bool UncheckedMalloc(size_t size, void** result) {
+  *result = malloc(size);
+  return *result != NULL;
+}
+
+}  // namespace base
diff --git a/base/process/process.h b/base/process/process.h
new file mode 100644
index 0000000..808baeb
--- /dev/null
+++ b/base/process/process.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PROCESS_H_
+#define BASE_PROCESS_PROCESS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/move.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace base {
+
+// Provides a move-only encapsulation of a process.
+//
+// This object is not tied to the lifetime of the underlying process: the
+// process may be killed and this object may still around, and it will still
+// claim to be valid. The actual behavior in that case is OS dependent like so:
+//
+// Windows: The underlying ProcessHandle will be valid after the process dies
+// and can be used to gather some information about that process, but most
+// methods will obviously fail.
+//
+// POSIX: The underlying PorcessHandle is not guaranteed to remain valid after
+// the process dies, and it may be reused by the system, which means that it may
+// end up pointing to the wrong process.
+class BASE_EXPORT Process {
+  MOVE_ONLY_TYPE_FOR_CPP_03(Process, RValue)
+
+ public:
+  explicit Process(ProcessHandle handle = kNullProcessHandle);
+
+  // Move constructor for C++03 move emulation of this type.
+  Process(RValue other);
+
+  // The destructor does not terminate the process.
+  ~Process();
+
+  // Move operator= for C++03 move emulation of this type.
+  Process& operator=(RValue other);
+
+  // Returns an object for the current process.
+  static Process Current();
+
+  // Returns a Process for the given |pid|.
+  static Process Open(ProcessId pid);
+
+  // Returns a Process for the given |pid|. On Windows the handle is opened
+  // with more access rights and must only be used by trusted code (can read the
+  // address space and duplicate handles).
+  static Process OpenWithExtraPrivileges(ProcessId pid);
+
+#if defined(OS_WIN)
+  // Returns a Process for the given |pid|, using some |desired_access|.
+  // See ::OpenProcess documentation for valid |desired_access|.
+  static Process OpenWithAccess(ProcessId pid, DWORD desired_access);
+#endif
+
+  // Creates an object from a |handle| owned by someone else.
+  // Don't use this for new code. It is only intended to ease the migration to
+  // a strict ownership model.
+  // TODO(rvargas) crbug.com/417532: Remove this code.
+  static Process DeprecatedGetProcessFromHandle(ProcessHandle handle);
+
+  // Returns true if processes can be backgrounded.
+  static bool CanBackgroundProcesses();
+
+  // Returns true if this objects represents a valid process.
+  bool IsValid() const;
+
+  // Returns a handle for this process. There is no guarantee about when that
+  // handle becomes invalid because this object retains ownership.
+  ProcessHandle Handle() const;
+
+  // Returns a second object that represents this process.
+  Process Duplicate() const;
+
+  // Get the PID for this process.
+  ProcessId Pid() const;
+
+  // Returns true if this process is the current process.
+  bool is_current() const;
+
+  // Close the process handle. This will not terminate the process.
+  void Close();
+
+  // Terminates the process with extreme prejudice. The given |exit_code| will
+  // be the exit code of the process. If |wait| is true, this method will wait
+  // for up to one minute for the process to actually terminate.
+  // Returns true if the process terminates within the allowed time.
+  // NOTE: On POSIX |exit_code| is ignored.
+  bool Terminate(int exit_code, bool wait) const;
+
+  // Waits for the process to exit. Returns true on success.
+  // On POSIX, if the process has been signaled then |exit_code| is set to -1.
+  // On Linux this must be a child process, however on Mac and Windows it can be
+  // any process.
+  bool WaitForExit(int* exit_code);
+
+  // Same as WaitForExit() but only waits for up to |timeout|.
+  bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
+
+  // A process is backgrounded when it's priority is lower than normal.
+  // Return true if this process is backgrounded, false otherwise.
+  bool IsProcessBackgrounded() const;
+
+  // Set a process as backgrounded. If value is true, the priority of the
+  // process will be lowered. If value is false, the priority of the process
+  // will be made "normal" - equivalent to default process priority.
+  // Returns true if the priority was changed, false otherwise.
+  bool SetProcessBackgrounded(bool value);
+
+  // Returns an integer representing the priority of a process. The meaning
+  // of this value is OS dependent.
+  int GetPriority() const;
+
+ private:
+#if defined(OS_WIN)
+  bool is_current_process_;
+  win::ScopedHandle process_;
+#else
+  ProcessHandle process_;
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_H_
diff --git a/base/process/process_handle.h b/base/process/process_handle.h
new file mode 100644
index 0000000..77f2c58
--- /dev/null
+++ b/base/process/process_handle.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PROCESS_HANDLE_H_
+#define BASE_PROCESS_PROCESS_HANDLE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "build/build_config.h"
+
+#include <sys/types.h>
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// ProcessHandle is a platform specific type which represents the underlying OS
+// handle to a process.
+// ProcessId is a number which identifies the process in the OS.
+#if defined(OS_WIN)
+typedef HANDLE ProcessHandle;
+typedef DWORD ProcessId;
+typedef HANDLE UserTokenHandle;
+const ProcessHandle kNullProcessHandle = NULL;
+const ProcessId kNullProcessId = 0;
+#elif defined(OS_POSIX)
+// On POSIX, our ProcessHandle will just be the PID.
+typedef pid_t ProcessHandle;
+typedef pid_t ProcessId;
+const ProcessHandle kNullProcessHandle = 0;
+const ProcessId kNullProcessId = 0;
+#endif  // defined(OS_WIN)
+
+// Returns the id of the current process.
+BASE_EXPORT ProcessId GetCurrentProcId();
+
+// Returns the ProcessHandle of the current process.
+BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
+
+// Returns the unique ID for the specified process. This is functionally the
+// same as Windows' GetProcessId(), but works on versions of Windows before
+// Win XP SP1 as well.
+// DEPRECATED. New code should be using Process::Pid() instead.
+BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+
+#if defined(OS_POSIX)
+// Returns the path to the executable of the given process.
+BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
+
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_HANDLE_H_
diff --git a/base/process/process_handle_freebsd.cc b/base/process/process_handle_freebsd.cc
new file mode 100644
index 0000000..e465a85
--- /dev/null
+++ b/base/process/process_handle_freebsd.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.ki_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  char pathname[PATH_MAX];
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process };
+
+  length = sizeof(pathname);
+
+  if (sysctl(mib, arraysize(mib), pathname, &length, NULL, 0) < 0 ||
+      length == 0) {
+    return FilePath();
+  }
+
+  return FilePath(std::string(pathname));
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_linux.cc b/base/process/process_handle_linux.cc
new file mode 100644
index 0000000..950b888
--- /dev/null
+++ b/base/process/process_handle_linux.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include "base/files/file_util.h"
+#include "base/process/internal_linux.h"
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  ProcessId pid =
+      internal::ReadProcStatsAndGetFieldAsInt64(process, internal::VM_PPID);
+  if (pid)
+    return pid;
+  return -1;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  FilePath stat_file = internal::GetProcPidDir(process).Append("exe");
+  FilePath exe_name;
+  if (!ReadSymbolicLink(stat_file, &exe_name)) {
+    // No such process.  Happens frequently in e.g. TerminateAllChromeProcesses
+    return FilePath();
+  }
+  return exe_name;
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_mac.cc b/base/process/process_handle_mac.cc
new file mode 100644
index 0000000..cbf0bc5
--- /dev/null
+++ b/base/process/process_handle_mac.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <libproc.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length = sizeof(struct kinfo_proc);
+  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+  if (sysctl(mib, 4, &info, &length, NULL, 0) < 0) {
+    DPLOG(ERROR) << "sysctl";
+    return -1;
+  }
+  if (length == 0)
+    return -1;
+  return info.kp_eproc.e_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+  if (!proc_pidpath(process, pathbuf, sizeof(pathbuf)))
+    return FilePath();
+
+  return FilePath(pathbuf);
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_openbsd.cc b/base/process/process_handle_openbsd.cc
new file mode 100644
index 0000000..3508ccb
--- /dev/null
+++ b/base/process/process_handle_openbsd.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.p_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  struct kinfo_proc kp;
+  size_t len;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) == -1)
+    return FilePath();
+  mib[5] = (len / sizeof(struct kinfo_proc));
+  if (sysctl(mib, arraysize(mib), &kp, &len, NULL, 0) < 0)
+    return FilePath();
+  if ((kp.p_flag & P_SYSTEM) != 0)
+    return FilePath();
+  if (strcmp(kp.p_comm, "chrome") == 0)
+    return FilePath(kp.p_comm);
+
+  return FilePath();
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_posix.cc b/base/process/process_handle_posix.cc
new file mode 100644
index 0000000..4e332df
--- /dev/null
+++ b/base/process/process_handle_posix.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <unistd.h>
+
+namespace base {
+
+ProcessId GetCurrentProcId() {
+  return getpid();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return GetCurrentProcId();
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+  return process;
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_win.cc b/base/process/process_handle_win.cc
new file mode 100644
index 0000000..f2ffff8
--- /dev/null
+++ b/base/process/process_handle_win.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <windows.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+ProcessId GetCurrentProcId() {
+  return ::GetCurrentProcessId();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return ::GetCurrentProcess();
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+  // This returns 0 if we have insufficient rights to query the process handle.
+  return GetProcessId(process);
+}
+
+}  // namespace base
diff --git a/base/process/process_info.h b/base/process/process_info.h
new file mode 100644
index 0000000..85f204d
--- /dev/null
+++ b/base/process/process_info.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PROCESS_INFO_H_
+#define BASE_PROCESS_PROCESS_INFO_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class Time;
+
+// Vends information about the current process.
+class BASE_EXPORT CurrentProcessInfo {
+ public:
+  // Returns the time at which the process was launched. May be empty if an
+  // error occurred retrieving the information.
+  static const Time CreationTime();
+};
+
+#if defined(OS_WIN)
+
+enum IntegrityLevel {
+  INTEGRITY_UNKNOWN,
+  LOW_INTEGRITY,
+  MEDIUM_INTEGRITY,
+  HIGH_INTEGRITY,
+};
+
+// Returns the integrity level of the process. Returns INTEGRITY_UNKNOWN if the
+// system does not support integrity levels (pre-Vista) or in the case of an
+// underlying system failure.
+BASE_EXPORT IntegrityLevel GetCurrentProcessIntegrityLevel();
+
+#endif  // defined(OS_WIN)
+
+
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_INFO_H_
diff --git a/base/process/process_info_linux.cc b/base/process/process_info_linux.cc
new file mode 100644
index 0000000..9ec2313
--- /dev/null
+++ b/base/process/process_info_linux.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_info.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+
+//static
+const Time CurrentProcessInfo::CreationTime() {
+  ProcessHandle pid = GetCurrentProcessHandle();
+  int64 start_ticks =
+      internal::ReadProcStatsAndGetFieldAsInt64(pid, internal::VM_STARTTIME);
+  DCHECK(start_ticks);
+  TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks);
+  Time boot_time = internal::GetBootTime();
+  DCHECK(!boot_time.is_null());
+  return Time(boot_time + start_offset);
+}
+
+}  // namespace base
diff --git a/base/process/process_info_mac.cc b/base/process/process_info_mac.cc
new file mode 100644
index 0000000..b7cfdce
--- /dev/null
+++ b/base/process/process_info_mac.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_info.h"
+
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+
+namespace base {
+
+//static
+const Time CurrentProcessInfo::CreationTime() {
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
+  size_t len = 0;
+  if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0)
+    return Time();
+
+  scoped_ptr<struct kinfo_proc, base::FreeDeleter>
+      proc(static_cast<struct kinfo_proc*>(malloc(len)));
+  if (sysctl(mib, arraysize(mib), proc.get(), &len, NULL, 0) < 0)
+    return Time();
+  return Time::FromTimeVal(proc->kp_proc.p_un.__p_starttime);
+}
+
+}  // namespace base
diff --git a/base/process/process_info_win.cc b/base/process/process_info_win.cc
new file mode 100644
index 0000000..2b9c406
--- /dev/null
+++ b/base/process/process_info_win.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_info.h"
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+// static
+const Time CurrentProcessInfo::CreationTime() {
+  FILETIME creation_time = {};
+  FILETIME ignore = {};
+  if (::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore,
+      &ignore, &ignore) == false)
+    return Time();
+
+  return Time::FromFileTime(creation_time);
+}
+
+IntegrityLevel GetCurrentProcessIntegrityLevel() {
+  if (win::GetVersion() < base::win::VERSION_VISTA)
+    return INTEGRITY_UNKNOWN;
+
+  HANDLE process_token;
+  if (!::OpenProcessToken(::GetCurrentProcess(),
+                          TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
+    return INTEGRITY_UNKNOWN;
+  }
+  win::ScopedHandle scoped_process_token(process_token);
+
+  DWORD token_info_length = 0;
+  if (::GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
+                            &token_info_length) ||
+      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return INTEGRITY_UNKNOWN;
+  }
+
+  scoped_ptr<char[]> token_label_bytes(new char[token_info_length]);
+  if (!token_label_bytes.get())
+    return INTEGRITY_UNKNOWN;
+
+  TOKEN_MANDATORY_LABEL* token_label =
+      reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
+  if (!token_label)
+    return INTEGRITY_UNKNOWN;
+
+  if (!::GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
+                             token_info_length, &token_info_length)) {
+    return INTEGRITY_UNKNOWN;
+  }
+
+  DWORD integrity_level = *::GetSidSubAuthority(
+      token_label->Label.Sid,
+      static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid)-1));
+
+  if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID)
+    return LOW_INTEGRITY;
+
+  if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
+      integrity_level < SECURITY_MANDATORY_HIGH_RID) {
+    return MEDIUM_INTEGRITY;
+  }
+
+  if (integrity_level >= SECURITY_MANDATORY_HIGH_RID)
+    return HIGH_INTEGRITY;
+
+  NOTREACHED();
+  return INTEGRITY_UNKNOWN;
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator.cc b/base/process/process_iterator.cc
new file mode 100644
index 0000000..b9ef047
--- /dev/null
+++ b/base/process/process_iterator.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+#if defined(OS_POSIX)
+ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {}
+ProcessEntry::~ProcessEntry() {}
+#endif
+
+const ProcessEntry* ProcessIterator::NextProcessEntry() {
+  bool result = false;
+  do {
+    result = CheckForNextProcess();
+  } while (result && !IncludeEntry());
+  if (result)
+    return &entry_;
+  return NULL;
+}
+
+ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
+  ProcessEntries found;
+  while (const ProcessEntry* process_entry = NextProcessEntry()) {
+    found.push_back(*process_entry);
+  }
+  return found;
+}
+
+bool ProcessIterator::IncludeEntry() {
+  return !filter_ || filter_->Includes(entry_);
+}
+
+NamedProcessIterator::NamedProcessIterator(
+    const FilePath::StringType& executable_name,
+    const ProcessFilter* filter) : ProcessIterator(filter),
+                                   executable_name_(executable_name) {
+#if defined(OS_ANDROID)
+  // On Android, the process name contains only the last 15 characters, which
+  // is in file /proc/<pid>/stat, the string between open parenthesis and close
+  // parenthesis. Please See ProcessIterator::CheckForNextProcess for details.
+  // Now if the length of input process name is greater than 15, only save the
+  // last 15 characters.
+  if (executable_name_.size() > 15) {
+    executable_name_ = FilePath::StringType(executable_name_,
+                                            executable_name_.size() - 15, 15);
+  }
+#endif
+}
+
+NamedProcessIterator::~NamedProcessIterator() {
+}
+
+int GetProcessCount(const FilePath::StringType& executable_name,
+                    const ProcessFilter* filter) {
+  int count = 0;
+  NamedProcessIterator iter(executable_name, filter);
+  while (iter.NextProcessEntry())
+    ++count;
+  return count;
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator.h b/base/process/process_iterator.h
new file mode 100644
index 0000000..ec6500e
--- /dev/null
+++ b/base/process/process_iterator.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains methods to iterate over processes on the system.
+
+#ifndef BASE_PROCESS_PROCESS_ITERATOR_H_
+#define BASE_PROCESS_PROCESS_ITERATOR_H_
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <tlhelp32.h>
+#elif defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include <sys/sysctl.h>
+#elif defined(OS_FREEBSD)
+#include <sys/user.h>
+#elif defined(OS_POSIX)
+#include <dirent.h>
+#endif
+
+namespace base {
+
+#if defined(OS_WIN)
+struct ProcessEntry : public PROCESSENTRY32 {
+  ProcessId pid() const { return th32ProcessID; }
+  ProcessId parent_pid() const { return th32ParentProcessID; }
+  const wchar_t* exe_file() const { return szExeFile; }
+};
+#elif defined(OS_POSIX)
+struct BASE_EXPORT ProcessEntry {
+  ProcessEntry();
+  ~ProcessEntry();
+
+  ProcessId pid() const { return pid_; }
+  ProcessId parent_pid() const { return ppid_; }
+  ProcessId gid() const { return gid_; }
+  const char* exe_file() const { return exe_file_.c_str(); }
+  const std::vector<std::string>& cmd_line_args() const {
+    return cmd_line_args_;
+  }
+
+  ProcessId pid_;
+  ProcessId ppid_;
+  ProcessId gid_;
+  std::string exe_file_;
+  std::vector<std::string> cmd_line_args_;
+};
+#endif  // defined(OS_POSIX)
+
+// Used to filter processes by process ID.
+class ProcessFilter {
+ public:
+  // Returns true to indicate set-inclusion and false otherwise.  This method
+  // should not have side-effects and should be idempotent.
+  virtual bool Includes(const ProcessEntry& entry) const = 0;
+
+ protected:
+  virtual ~ProcessFilter() {}
+};
+
+// This class provides a way to iterate through a list of processes on the
+// current machine with a specified filter.
+// To use, create an instance and then call NextProcessEntry() until it returns
+// false.
+class BASE_EXPORT ProcessIterator {
+ public:
+  typedef std::list<ProcessEntry> ProcessEntries;
+
+  explicit ProcessIterator(const ProcessFilter* filter);
+  virtual ~ProcessIterator();
+
+  // If there's another process that matches the given executable name,
+  // returns a const pointer to the corresponding PROCESSENTRY32.
+  // If there are no more matching processes, returns NULL.
+  // The returned pointer will remain valid until NextProcessEntry()
+  // is called again or this NamedProcessIterator goes out of scope.
+  const ProcessEntry* NextProcessEntry();
+
+  // Takes a snapshot of all the ProcessEntry found.
+  ProcessEntries Snapshot();
+
+ protected:
+  virtual bool IncludeEntry();
+  const ProcessEntry& entry() { return entry_; }
+
+ private:
+  // Determines whether there's another process (regardless of executable)
+  // left in the list of all processes.  Returns true and sets entry_ to
+  // that process's info if there is one, false otherwise.
+  bool CheckForNextProcess();
+
+  // Initializes a PROCESSENTRY32 data structure so that it's ready for
+  // use with Process32First/Process32Next.
+  void InitProcessEntry(ProcessEntry* entry);
+
+#if defined(OS_WIN)
+  HANDLE snapshot_;
+  bool started_iteration_;
+#elif defined(OS_MACOSX) || defined(OS_BSD)
+  std::vector<kinfo_proc> kinfo_procs_;
+  size_t index_of_kinfo_proc_;
+#elif defined(OS_POSIX)
+  DIR* procfs_dir_;
+#endif
+  ProcessEntry entry_;
+  const ProcessFilter* filter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessIterator);
+};
+
+// This class provides a way to iterate through the list of processes
+// on the current machine that were started from the given executable
+// name.  To use, create an instance and then call NextProcessEntry()
+// until it returns false.
+class BASE_EXPORT NamedProcessIterator : public ProcessIterator {
+ public:
+  NamedProcessIterator(const FilePath::StringType& executable_name,
+                       const ProcessFilter* filter);
+  ~NamedProcessIterator() override;
+
+ protected:
+  bool IncludeEntry() override;
+
+ private:
+  FilePath::StringType executable_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
+};
+
+// Returns the number of processes on the machine that are running from the
+// given executable name.  If filter is non-null, then only processes selected
+// by the filter will be counted.
+BASE_EXPORT int GetProcessCount(const FilePath::StringType& executable_name,
+                                const ProcessFilter* filter);
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_ITERATOR_H_
diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc
new file mode 100644
index 0000000..5b1e2ab
--- /dev/null
+++ b/base/process/process_iterator_freebsd.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(),
+      filter_(filter) {
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
+
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+
+  do {
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          LOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    LOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    size_t length;
+    struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
+    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
+
+    if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
+      continue;
+
+    length = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to figure out the buffer size for a command line";
+      continue;
+    }
+
+    data.resize(length);
+
+    if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to fetch a commandline";
+      continue;
+    }
+
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      LOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.ki_pid;
+    entry_.ppid_ = kinfo.ki_ppid;
+    entry_.gid_ = kinfo.ki_pgid;
+
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos) {
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    } else {
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    }
+
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  if (executable_name_ != entry().exe_file())
+    return false;
+
+  return ProcessIterator::IncludeEntry();
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc
new file mode 100644
index 0000000..3319552
--- /dev/null
+++ b/base/process/process_iterator_linux.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+// Reads the |field_num|th field from |proc_stats|.
+// Returns an empty string on failure.
+// This version only handles VM_COMM and VM_STATE, which are the only fields
+// that are strings.
+std::string GetProcStatsFieldAsString(
+    const std::vector<std::string>& proc_stats,
+    internal::ProcStatsFields field_num) {
+  if (field_num < internal::VM_COMM || field_num > internal::VM_STATE) {
+    NOTREACHED();
+    return std::string();
+  }
+
+  if (proc_stats.size() > static_cast<size_t>(field_num))
+    return proc_stats[field_num];
+
+  NOTREACHED();
+  return 0;
+}
+
+// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
+// line arguments. Returns true if successful.
+// Note: /proc/<pid>/cmdline contains command line arguments separated by single
+// null characters. We tokenize it into a vector of strings using '\0' as a
+// delimiter.
+bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
+  // Synchronously reading files in /proc is safe.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath cmd_line_file = internal::GetProcPidDir(pid).Append("cmdline");
+  std::string cmd_line;
+  if (!ReadFileToString(cmd_line_file, &cmd_line))
+    return false;
+  std::string delimiters;
+  delimiters.push_back('\0');
+  Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+  return true;
+}
+
+}  // namespace
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : filter_(filter) {
+  procfs_dir_ = opendir(internal::kProcDir);
+}
+
+ProcessIterator::~ProcessIterator() {
+  if (procfs_dir_) {
+    closedir(procfs_dir_);
+    procfs_dir_ = NULL;
+  }
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  // TODO(port): skip processes owned by different UID
+
+  pid_t pid = kNullProcessId;
+  std::vector<std::string> cmd_line_args;
+  std::string stats_data;
+  std::vector<std::string> proc_stats;
+
+  // Arbitrarily guess that there will never be more than 200 non-process
+  // files in /proc.  Hardy has 53 and Lucid has 61.
+  int skipped = 0;
+  const int kSkipLimit = 200;
+  while (skipped < kSkipLimit) {
+    dirent* slot = readdir(procfs_dir_);
+    // all done looking through /proc?
+    if (!slot)
+      return false;
+
+    // If not a process, keep looking for one.
+    pid = internal::ProcDirSlotToPid(slot->d_name);
+    if (!pid) {
+      skipped++;
+      continue;
+    }
+
+    if (!GetProcCmdline(pid, &cmd_line_args))
+      continue;
+
+    if (!internal::ReadProcStats(pid, &stats_data))
+      continue;
+    if (!internal::ParseProcStats(stats_data, &proc_stats))
+      continue;
+
+    std::string runstate =
+        GetProcStatsFieldAsString(proc_stats, internal::VM_STATE);
+    if (runstate.size() != 1) {
+      NOTREACHED();
+      continue;
+    }
+
+    // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
+    // Allowed values: D R S T Z
+    if (runstate[0] != 'Z')
+      break;
+
+    // Nope, it's a zombie; somebody isn't cleaning up after their children.
+    // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
+    // There could be a lot of zombies, can't really decrement i here.
+  }
+  if (skipped >= kSkipLimit) {
+    NOTREACHED();
+    return false;
+  }
+
+  entry_.pid_ = pid;
+  entry_.ppid_ = GetProcStatsFieldAsInt64(proc_stats, internal::VM_PPID);
+  entry_.gid_ = GetProcStatsFieldAsInt64(proc_stats, internal::VM_PGRP);
+  entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
+  entry_.exe_file_ = GetProcessExecutablePath(pid).BaseName().value();
+  return true;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  if (executable_name_ != entry().exe_file())
+    return false;
+  return ProcessIterator::IncludeEntry();
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
new file mode 100644
index 0000000..e35c2ae
--- /dev/null
+++ b/base/process/process_iterator_mac.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(0),
+      filter_(filter) {
+  // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
+  // but trying to find where we were in a constantly changing list is basically
+  // impossible.
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
+
+  // Since more processes could start between when we get the size and when
+  // we get the list, we do a loop to keep trying until we get it.
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+  do {
+    // Get the size of the buffer
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      DLOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      // Load the list of processes
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          DLOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    DLOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+    // Skip processes just awaiting collection
+    if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB))
+      continue;
+
+    int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
+
+    // Find out what size buffer we need.
+    size_t data_len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+      continue;
+    }
+
+    data.resize(data_len);
+    if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to fetch a commandline";
+      continue;
+    }
+
+    // |data| contains all the command line parameters of the process, separated
+    // by blocks of one or more null characters. We tokenize |data| into a
+    // vector of strings using '\0' as a delimiter and populate
+    // |entry_.cmd_line_args_|.
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    // |data| starts with the full executable path followed by a null character.
+    // We search for the first instance of '\0' and extract everything before it
+    // to populate |entry_.exe_file_|.
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      DLOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.kp_proc.p_pid;
+    entry_.ppid_ = kinfo.kp_eproc.e_ppid;
+    entry_.gid_ = kinfo.kp_eproc.e_pgid;
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos)
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    else
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+    // Done
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return (executable_name_ == entry().exe_file() &&
+          ProcessIterator::IncludeEntry());
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc
new file mode 100644
index 0000000..7c44eb1
--- /dev/null
+++ b/base/process/process_iterator_openbsd.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(),
+      filter_(filter) {
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(),
+                sizeof(struct kinfo_proc), 0 };
+
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+
+  do {
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      DLOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          DLOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    DLOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+    // Skip processes just awaiting collection
+    if ((kinfo.p_pid > 0) && (kinfo.p_stat == SZOMB))
+      continue;
+
+    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.p_pid };
+
+    // Find out what size buffer we need.
+    size_t data_len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+      continue;
+    }
+
+    data.resize(data_len);
+    if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to fetch a commandline";
+      continue;
+    }
+
+    // |data| contains all the command line parameters of the process, separated
+    // by blocks of one or more null characters. We tokenize |data| into a
+    // vector of strings using '\0' as a delimiter and populate
+    // |entry_.cmd_line_args_|.
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    // |data| starts with the full executable path followed by a null character.
+    // We search for the first instance of '\0' and extract everything before it
+    // to populate |entry_.exe_file_|.
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      DLOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.p_pid;
+    entry_.ppid_ = kinfo.p_ppid;
+    entry_.gid_ = kinfo.p__pgid;
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos)
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    else
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+    // Done
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return (executable_name_ == entry().exe_file() &&
+          ProcessIterator::IncludeEntry());
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_win.cc b/base/process/process_iterator_win.cc
new file mode 100644
index 0000000..9d5a970
--- /dev/null
+++ b/base/process/process_iterator_win.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : started_iteration_(false),
+      filter_(filter) {
+  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+}
+
+ProcessIterator::~ProcessIterator() {
+  CloseHandle(snapshot_);
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  InitProcessEntry(&entry_);
+
+  if (!started_iteration_) {
+    started_iteration_ = true;
+    return !!Process32First(snapshot_, &entry_);
+  }
+
+  return !!Process32Next(snapshot_, &entry_);
+}
+
+void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
+  memset(entry, 0, sizeof(*entry));
+  entry->dwSize = sizeof(*entry);
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  // Case insensitive.
+  return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
+         ProcessIterator::IncludeEntry();
+}
+
+}  // namespace base
diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc
new file mode 100644
index 0000000..88a310e
--- /dev/null
+++ b/base/process/process_linux.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+namespace {
+
+const int kForegroundPriority = 0;
+
+#if defined(OS_CHROMEOS)
+// We are more aggressive in our lowering of background process priority
+// for chromeos as we have much more control over other processes running
+// on the machine.
+//
+// TODO(davemoore) Refactor this by adding support for higher levels to set
+// the foregrounding / backgrounding process so we don't have to keep
+// chrome / chromeos specific logic here.
+const int kBackgroundPriority = 19;
+const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs";
+const char kForeground[] = "/chrome_renderers/foreground";
+const char kBackground[] = "/chrome_renderers/background";
+const char kProcPath[] = "/proc/%d/cgroup";
+
+struct CGroups {
+  // Check for cgroups files. ChromeOS supports these by default. It creates
+  // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups,
+  // one contains at most a single foreground renderer and the other contains
+  // all background renderers. This allows us to limit the impact of background
+  // renderers on foreground ones to a greater level than simple renicing.
+  bool enabled;
+  base::FilePath foreground_file;
+  base::FilePath background_file;
+
+  CGroups() {
+    foreground_file =
+        base::FilePath(base::StringPrintf(kControlPath, kForeground));
+    background_file =
+        base::FilePath(base::StringPrintf(kControlPath, kBackground));
+    base::FileSystemType foreground_type;
+    base::FileSystemType background_type;
+    enabled =
+        base::GetFileSystemType(foreground_file, &foreground_type) &&
+        base::GetFileSystemType(background_file, &background_type) &&
+        foreground_type == FILE_SYSTEM_CGROUP &&
+        background_type == FILE_SYSTEM_CGROUP;
+  }
+};
+
+base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
+#else
+const int kBackgroundPriority = 5;
+#endif
+
+struct CheckForNicePermission {
+  CheckForNicePermission() : can_reraise_priority(false) {
+    // We won't be able to raise the priority if we don't have the right rlimit.
+    // The limit may be adjusted in /etc/security/limits.conf for PAM systems.
+    struct rlimit rlim;
+    if ((getrlimit(RLIMIT_NICE, &rlim) == 0) &&
+        (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur)) {
+        can_reraise_priority = true;
+    }
+  };
+
+  bool can_reraise_priority;
+};
+
+}  // namespace
+
+// static
+bool Process::CanBackgroundProcesses() {
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled)
+    return true;
+#endif
+
+  static LazyInstance<CheckForNicePermission> check_for_nice_permission =
+      LAZY_INSTANCE_INITIALIZER;
+  return check_for_nice_permission.Get().can_reraise_priority;
+}
+
+bool Process::IsProcessBackgrounded() const {
+  DCHECK(IsValid());
+
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled) {
+    std::string proc;
+    if (base::ReadFileToString(
+            base::FilePath(StringPrintf(kProcPath, process_)),
+            &proc)) {
+      std::vector<std::string> proc_parts;
+      base::SplitString(proc, ':', &proc_parts);
+      DCHECK_EQ(proc_parts.size(), 3u);
+      bool ret = proc_parts[2] == std::string(kBackground);
+      return ret;
+    } else {
+      return false;
+    }
+  }
+#endif
+  return GetPriority() == kBackgroundPriority;
+}
+
+bool Process::SetProcessBackgrounded(bool background) {
+  DCHECK(IsValid());
+
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled) {
+    std::string pid = StringPrintf("%d", process_);
+    const base::FilePath file =
+        background ?
+            cgroups.Get().background_file : cgroups.Get().foreground_file;
+    return base::WriteFile(file, pid.c_str(), pid.size()) > 0;
+  }
+#endif // OS_CHROMEOS
+
+  if (!CanBackgroundProcesses())
+    return false;
+
+  int priority = background ? kBackgroundPriority : kForegroundPriority;
+  int result = setpriority(PRIO_PROCESS, process_, priority);
+  DPCHECK(result == 0);
+  return result == 0;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
new file mode 100644
index 0000000..e486339
--- /dev/null
+++ b/base/process/process_metrics.cc
@@ -0,0 +1,87 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace base {
+
+SystemMetrics::SystemMetrics() {
+  committed_memory_ = 0;
+}
+
+SystemMetrics SystemMetrics::Sample() {
+  SystemMetrics system_metrics;
+
+  system_metrics.committed_memory_ = GetSystemCommitCharge();
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  GetSystemMemoryInfo(&system_metrics.memory_info_);
+  GetSystemDiskInfo(&system_metrics.disk_info_);
+#endif
+#if defined(OS_CHROMEOS)
+  GetSwapInfo(&system_metrics.swap_info_);
+#endif
+
+  return system_metrics;
+}
+
+scoped_ptr<Value> SystemMetrics::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  res->SetInteger("committed_memory", static_cast<int>(committed_memory_));
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  res->Set("meminfo", memory_info_.ToValue());
+  res->Set("diskinfo", disk_info_.ToValue());
+#endif
+#if defined(OS_CHROMEOS)
+  res->Set("swapinfo", swap_info_.ToValue());
+#endif
+
+  return res.Pass();
+}
+
+double ProcessMetrics::GetPlatformIndependentCPUUsage() {
+#if defined(OS_WIN)
+  return GetCPUUsage() * processor_count_;
+#else
+  return GetCPUUsage();
+#endif
+}
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+int ProcessMetrics::CalculateIdleWakeupsPerSecond(
+    uint64 absolute_idle_wakeups) {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_absolute_idle_wakeups_ == 0) {
+    // First call, just set the last values.
+    last_idle_wakeups_time_ = time;
+    last_absolute_idle_wakeups_ = absolute_idle_wakeups;
+    return 0;
+  }
+
+  int64 wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
+  int64 time_delta = (time - last_idle_wakeups_time_).InMicroseconds();
+  if (time_delta == 0) {
+    NOTREACHED();
+    return 0;
+  }
+
+  last_idle_wakeups_time_ = time;
+  last_absolute_idle_wakeups_ = absolute_idle_wakeups;
+
+  // Round to average wakeups per second.
+  int64 wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond;
+  return (wakeups_delta_for_ms + time_delta / 2) / time_delta;
+}
+#else
+int ProcessMetrics::GetIdleWakeupsPerSecond() {
+  NOTIMPLEMENTED();  // http://crbug.com/120488
+  return 0;
+}
+#endif  // defined(OS_MACOSX) || defined(OS_LINUX)
+
+}  // namespace base
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
new file mode 100644
index 0000000..5916b94
--- /dev/null
+++ b/base/process/process_metrics.h
@@ -0,0 +1,392 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains routines for gathering resource statistics for processes
+// running on the system.
+
+#ifndef BASE_PROCESS_PROCESS_METRICS_H_
+#define BASE_PROCESS_PROCESS_METRICS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "base/values.h"
+
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#endif
+
+namespace base {
+
+#if defined(OS_WIN)
+struct IoCounters : public IO_COUNTERS {
+};
+#elif defined(OS_POSIX)
+struct IoCounters {
+  uint64_t ReadOperationCount;
+  uint64_t WriteOperationCount;
+  uint64_t OtherOperationCount;
+  uint64_t ReadTransferCount;
+  uint64_t WriteTransferCount;
+  uint64_t OtherTransferCount;
+};
+#endif
+
+// Working Set (resident) memory usage broken down by
+//
+// On Windows:
+// priv (private): These pages (kbytes) cannot be shared with any other process.
+// shareable:      These pages (kbytes) can be shared with other processes under
+//                 the right circumstances.
+// shared :        These pages (kbytes) are currently shared with at least one
+//                 other process.
+//
+// On Linux:
+// priv:           Pages mapped only by this process.
+// shared:         PSS or 0 if the kernel doesn't support this.
+// shareable:      0
+
+// On ChromeOS:
+// priv:           Pages mapped only by this process.
+// shared:         PSS or 0 if the kernel doesn't support this.
+// shareable:      0
+// swapped         Pages swapped out to zram.
+//
+// On OS X: TODO(thakis): Revise.
+// priv:           Memory.
+// shared:         0
+// shareable:      0
+//
+struct WorkingSetKBytes {
+  WorkingSetKBytes() : priv(0), shareable(0), shared(0) {}
+  size_t priv;
+  size_t shareable;
+  size_t shared;
+#if defined(OS_CHROMEOS)
+  size_t swapped;
+#endif
+};
+
+// Committed (resident + paged) memory usage broken down by
+// private: These pages cannot be shared with any other process.
+// mapped:  These pages are mapped into the view of a section (backed by
+//          pagefile.sys)
+// image:   These pages are mapped into the view of an image section (backed by
+//          file system)
+struct CommittedKBytes {
+  CommittedKBytes() : priv(0), mapped(0), image(0) {}
+  size_t priv;
+  size_t mapped;
+  size_t image;
+};
+
+// Convert a POSIX timeval to microseconds.
+BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv);
+
+// Provides performance metrics for a specified process (CPU usage, memory and
+// IO counters). To use it, invoke CreateProcessMetrics() to get an instance
+// for a specific process, then access the information with the different get
+// methods.
+class BASE_EXPORT ProcessMetrics {
+ public:
+  ~ProcessMetrics();
+
+  // Creates a ProcessMetrics for the specified process.
+  // The caller owns the returned object.
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  static ProcessMetrics* CreateProcessMetrics(ProcessHandle process);
+#else
+  class PortProvider {
+   public:
+    virtual ~PortProvider() {}
+
+    // Should return the mach task for |process| if possible, or else
+    // |MACH_PORT_NULL|. Only processes that this returns tasks for will have
+    // metrics on OS X (except for the current process, which always gets
+    // metrics).
+    virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+  };
+
+  // The port provider needs to outlive the ProcessMetrics object returned by
+  // this function. If NULL is passed as provider, the returned object
+  // only returns valid metrics if |process| is the current process.
+  static ProcessMetrics* CreateProcessMetrics(ProcessHandle process,
+                                              PortProvider* port_provider);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+  // Returns the current space allocated for the pagefile, in bytes (these pages
+  // may or may not be in memory).  On Linux, this returns the total virtual
+  // memory size.
+  size_t GetPagefileUsage() const;
+  // Returns the peak space allocated for the pagefile, in bytes.
+  size_t GetPeakPagefileUsage() const;
+  // Returns the current working set size, in bytes.  On Linux, this returns
+  // the resident set size.
+  size_t GetWorkingSetSize() const;
+  // Returns the peak working set size, in bytes.
+  size_t GetPeakWorkingSetSize() const;
+  // Returns private and sharedusage, in bytes. Private bytes is the amount of
+  // memory currently allocated to a process that cannot be shared. Returns
+  // false on platform specific error conditions.  Note: |private_bytes|
+  // returns 0 on unsupported OSes: prior to XP SP2.
+  bool GetMemoryBytes(size_t* private_bytes,
+                      size_t* shared_bytes);
+  // Fills a CommittedKBytes with both resident and paged
+  // memory usage as per definition of CommittedBytes.
+  void GetCommittedKBytes(CommittedKBytes* usage) const;
+  // Fills a WorkingSetKBytes containing resident private and shared memory
+  // usage in bytes, as per definition of WorkingSetBytes.
+  bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
+
+#if defined(OS_MACOSX)
+  // Fills both CommitedKBytes and WorkingSetKBytes in a single operation. This
+  // is more efficient on Mac OS X, as the two can be retrieved with a single
+  // system call.
+  bool GetCommittedAndWorkingSetKBytes(CommittedKBytes* usage,
+                                       WorkingSetKBytes* ws_usage) const;
+#endif
+
+  // Returns the CPU usage in percent since the last time this method or
+  // GetPlatformIndependentCPUUsage() was called. The first time this method
+  // is called it returns 0 and will return the actual CPU info on subsequent
+  // calls. On Windows, the CPU usage value is for all CPUs. So if you have
+  // 2 CPUs and your process is using all the cycles of 1 CPU and not the other
+  // CPU, this method returns 50.
+  double GetCPUUsage();
+
+  // Returns the number of average idle cpu wakeups per second since the last
+  // call.
+  int GetIdleWakeupsPerSecond();
+
+  // Same as GetCPUUsage(), but will return consistent values on all platforms
+  // (cancelling the Windows exception mentioned above) by returning a value in
+  // the range of 0 to (100 * numCPUCores) everywhere.
+  double GetPlatformIndependentCPUUsage();
+
+  // Retrieves accounting information for all I/O operations performed by the
+  // process.
+  // If IO information is retrieved successfully, the function returns true
+  // and fills in the IO_COUNTERS passed in. The function returns false
+  // otherwise.
+  bool GetIOCounters(IoCounters* io_counters) const;
+
+ private:
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  explicit ProcessMetrics(ProcessHandle process);
+#else
+  ProcessMetrics(ProcessHandle process, PortProvider* port_provider);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  bool GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) const;
+#endif
+
+#if defined(OS_CHROMEOS)
+  bool GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) const;
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+  int CalculateIdleWakeupsPerSecond(uint64 absolute_idle_wakeups);
+#endif
+
+  ProcessHandle process_;
+
+  int processor_count_;
+
+  // Used to store the previous times and CPU usage counts so we can
+  // compute the CPU usage between calls.
+  TimeTicks last_cpu_time_;
+  int64 last_system_time_;
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+  // Same thing for idle wakeups.
+  TimeTicks last_idle_wakeups_time_;
+  uint64 last_absolute_idle_wakeups_;
+#endif
+
+#if !defined(OS_IOS)
+#if defined(OS_MACOSX)
+  // Queries the port provider if it's set.
+  mach_port_t TaskForPid(ProcessHandle process) const;
+
+  PortProvider* port_provider_;
+#elif defined(OS_POSIX)
+  // Jiffie count at the last_cpu_time_ we updated.
+  int last_cpu_;
+#endif  // defined(OS_POSIX)
+#endif  // !defined(OS_IOS)
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMetrics);
+};
+
+// Returns the memory committed by the system in KBytes.
+// Returns 0 if it can't compute the commit charge.
+BASE_EXPORT size_t GetSystemCommitCharge();
+
+// Returns the number of bytes in a memory page.
+BASE_EXPORT size_t GetPageSize();
+
+#if defined(OS_POSIX)
+// Returns the maximum number of file descriptors that can be open by a process
+// at once. If the number is unavailable, a conservative best guess is returned.
+BASE_EXPORT size_t GetMaxFds();
+
+// Sets the file descriptor soft limit to |max_descriptors| or the OS hard
+// limit, whichever is lower.
+BASE_EXPORT void SetFdLimit(unsigned int max_descriptors);
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// Parse the data found in /proc/<pid>/stat and return the sum of the
+// CPU-related ticks.  Returns -1 on parse error.
+// Exposed for testing.
+BASE_EXPORT int ParseProcStatCPU(const std::string& input);
+
+// Get the number of threads of |process| as available in /proc/<pid>/stat.
+// This should be used with care as no synchronization with running threads is
+// done. This is mostly useful to guarantee being single-threaded.
+// Returns 0 on failure.
+BASE_EXPORT int GetNumberOfThreads(ProcessHandle process);
+
+// /proc/self/exe refers to the current executable.
+BASE_EXPORT extern const char kProcSelfExe[];
+
+// Data from /proc/meminfo about system-wide memory consumption.
+// Values are in KB.
+struct BASE_EXPORT SystemMemoryInfoKB {
+  SystemMemoryInfoKB();
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  int total;
+  int free;
+  int buffers;
+  int cached;
+  int active_anon;
+  int inactive_anon;
+  int active_file;
+  int inactive_file;
+  int swap_total;
+  int swap_free;
+  int dirty;
+
+  // vmstats data.
+  int pswpin;
+  int pswpout;
+  int pgmajfault;
+
+#ifdef OS_CHROMEOS
+  int shmem;
+  int slab;
+  // Gem data will be -1 if not supported.
+  int gem_objects;
+  long long gem_size;
+#endif
+};
+
+// Parses a string containing the contents of /proc/meminfo
+// returns true on success or false for a parsing error
+BASE_EXPORT bool ParseProcMeminfo(const std::string& input,
+                                  SystemMemoryInfoKB* meminfo);
+
+// Parses a string containing the contents of /proc/vmstat
+// returns true on success or false for a parsing error
+BASE_EXPORT bool ParseProcVmstat(const std::string& input,
+                                 SystemMemoryInfoKB* meminfo);
+
+// Retrieves data from /proc/meminfo and /proc/vmstat
+// about system-wide memory consumption.
+// Fills in the provided |meminfo| structure. Returns true on success.
+// Exposed for memory debugging widget.
+BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
+
+// Data from /proc/diskstats about system-wide disk I/O.
+struct BASE_EXPORT SystemDiskInfo {
+  SystemDiskInfo();
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  uint64 reads;
+  uint64 reads_merged;
+  uint64 sectors_read;
+  uint64 read_time;
+  uint64 writes;
+  uint64 writes_merged;
+  uint64 sectors_written;
+  uint64 write_time;
+  uint64 io;
+  uint64 io_time;
+  uint64 weighted_io_time;
+};
+
+// Checks whether the candidate string is a valid disk name, [hsv]d[a-z]+
+// for a generic disk or mmcblk[0-9]+ for the MMC case.
+// Names of disk partitions (e.g. sda1) are not valid.
+BASE_EXPORT bool IsValidDiskName(const std::string& candidate);
+
+// Retrieves data from /proc/diskstats about system-wide disk I/O.
+// Fills in the provided |diskinfo| structure. Returns true on success.
+BASE_EXPORT bool GetSystemDiskInfo(SystemDiskInfo* diskinfo);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+// Data from files in directory /sys/block/zram0 about ZRAM usage.
+struct BASE_EXPORT SwapInfo {
+  SwapInfo()
+      : num_reads(0),
+        num_writes(0),
+        compr_data_size(0),
+        orig_data_size(0),
+        mem_used_total(0) {
+  }
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  uint64 num_reads;
+  uint64 num_writes;
+  uint64 compr_data_size;
+  uint64 orig_data_size;
+  uint64 mem_used_total;
+};
+
+// In ChromeOS, reads files from /sys/block/zram0 that contain ZRAM usage data.
+// Fills in the provided |swap_data| structure.
+BASE_EXPORT void GetSwapInfo(SwapInfo* swap_info);
+#endif  // defined(OS_CHROMEOS)
+
+// Collects and holds performance metrics for system memory and disk.
+// Provides functionality to retrieve the data on various platforms and
+// to serialize the stored data.
+class SystemMetrics {
+ public:
+  SystemMetrics();
+
+  static SystemMetrics Sample();
+
+  // Serializes the system metrics to value.
+  scoped_ptr<Value> ToValue() const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(SystemMetricsTest, SystemMetrics);
+
+  size_t committed_memory_;
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  SystemMemoryInfoKB memory_info_;
+  SystemDiskInfo disk_info_;
+#endif
+#if defined(OS_CHROMEOS)
+  SwapInfo swap_info_;
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_METRICS_H_
diff --git a/base/process/process_metrics_freebsd.cc b/base/process/process_metrics_freebsd.cc
new file mode 100644
index 0000000..9d4149d
--- /dev/null
+++ b/base/process/process_metrics_freebsd.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+#include "base/sys_info.h"
+
+namespace base {
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_system_time_(0),
+      last_cpu_(0) {
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.ki_size;
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.ki_rssize * getpagesize();
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv << 10;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+// TODO(bapt) be sure we can't be precise
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return (info.ki_pctcpu / FSCALE) * 100.0;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+size_t GetSystemCommitCharge() {
+  int mib[2], pagesize;
+  unsigned long mem_total, mem_free, mem_inactive;
+  size_t length = sizeof(mem_total);
+
+  if (sysctl(mib, arraysize(mib), &mem_total, &length, NULL, 0) < 0)
+    return 0;
+
+  length = sizeof(mem_free);
+  if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &length, NULL, 0) < 0)
+    return 0;
+
+  length = sizeof(mem_inactive);
+  if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &length,
+      NULL, 0) < 0) {
+    return 0;
+  }
+
+  pagesize = getpagesize();
+
+  return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize);
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_ios.cc b/base/process/process_metrics_ios.cc
new file mode 100644
index 0000000..07f2c8d
--- /dev/null
+++ b/base/process/process_metrics_ios.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <mach/task.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace {
+
+bool GetTaskInfo(task_basic_info_64* task_info_data) {
+  mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+  kern_return_t kr = task_info(mach_task_self(),
+                               TASK_BASIC_INFO_64,
+                               reinterpret_cast<task_info_t>(task_info_data),
+                               &count);
+  return kr == KERN_SUCCESS;
+}
+
+}  // namespace
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process) {}
+
+ProcessMetrics::~ProcessMetrics() {}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(&task_info_data))
+    return 0;
+  return task_info_data.virtual_size;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(&task_info_data))
+    return 0;
+  return task_info_data.resident_size;
+}
+
+size_t GetMaxFds() {
+  static const rlim_t kSystemDefaultMaxFds = 256;
+  rlim_t max_fds;
+  struct rlimit nofile;
+  if (getrlimit(RLIMIT_NOFILE, &nofile)) {
+    // Error case: Take a best guess.
+    max_fds = kSystemDefaultMaxFds;
+  } else {
+    max_fds = nofile.rlim_cur;
+  }
+
+  if (max_fds > INT_MAX)
+    max_fds = INT_MAX;
+
+  return static_cast<size_t>(max_fds);
+}
+
+void SetFdLimit(unsigned int max_descriptors) {
+  // Unimplemented.
+}
+
+size_t GetPageSize() {
+  return getpagesize();
+}
+
+// Bytes committed by the system.
+size_t GetSystemCommitCharge() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
new file mode 100644
index 0000000..2d54c4c
--- /dev/null
+++ b/base/process/process_metrics_linux.cc
@@ -0,0 +1,916 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+void TrimKeyValuePairs(StringPairs* pairs) {
+  DCHECK(pairs);
+  StringPairs& p_ref = *pairs;
+  for (size_t i = 0; i < p_ref.size(); ++i) {
+    TrimWhitespaceASCII(p_ref[i].first, TRIM_ALL, &p_ref[i].first);
+    TrimWhitespaceASCII(p_ref[i].second, TRIM_ALL, &p_ref[i].second);
+  }
+}
+
+#if defined(OS_CHROMEOS)
+// Read a file with a single number string and return the number as a uint64.
+static uint64 ReadFileToUint64(const FilePath file) {
+  std::string file_as_string;
+  if (!ReadFileToString(file, &file_as_string))
+    return 0;
+  TrimWhitespaceASCII(file_as_string, TRIM_ALL, &file_as_string);
+  uint64 file_as_uint64 = 0;
+  if (!StringToUint64(file_as_string, &file_as_uint64))
+    return 0;
+  return file_as_uint64;
+}
+#endif
+
+// Read /proc/<pid>/status and return the value for |field|, or 0 on failure.
+// Only works for fields in the form of "Field: value kB".
+size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
+  std::string status;
+  {
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    FilePath stat_file = internal::GetProcPidDir(pid).Append("status");
+    if (!ReadFileToString(stat_file, &status))
+      return 0;
+  }
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs);
+  TrimKeyValuePairs(&pairs);
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    const std::string& key = pairs[i].first;
+    const std::string& value_str = pairs[i].second;
+    if (key == field) {
+      std::vector<std::string> split_value_str;
+      SplitString(value_str, ' ', &split_value_str);
+      if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
+        NOTREACHED();
+        return 0;
+      }
+      size_t value;
+      if (!StringToSizeT(split_value_str[0], &value)) {
+        NOTREACHED();
+        return 0;
+      }
+      return value;
+    }
+  }
+  NOTREACHED();
+  return 0;
+}
+
+#if defined(OS_LINUX)
+// Read /proc/<pid>/sched and look for |field|. On succes, return true and
+// write the value for |field| into |result|.
+// Only works for fields in the form of "field    :     uint_value"
+bool ReadProcSchedAndGetFieldAsUint64(pid_t pid,
+                                      const std::string& field,
+                                      uint64* result) {
+  std::string sched_data;
+  {
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    FilePath sched_file = internal::GetProcPidDir(pid).Append("sched");
+    if (!ReadFileToString(sched_file, &sched_data))
+      return false;
+  }
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(sched_data, ':', '\n', &pairs);
+  TrimKeyValuePairs(&pairs);
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    const std::string& key = pairs[i].first;
+    const std::string& value_str = pairs[i].second;
+    if (key == field) {
+      uint64 value;
+      if (!StringToUint64(value_str, &value))
+        return false;
+      *result = value;
+      return true;
+    }
+  }
+  return false;
+}
+#endif  // defined(OS_LINUX)
+
+// Get the total CPU of a single process.  Return value is number of jiffies
+// on success or -1 on error.
+int GetProcessCPU(pid_t pid) {
+  // Use /proc/<pid>/task to find all threads and parse their /stat file.
+  FilePath task_path = internal::GetProcPidDir(pid).Append("task");
+
+  DIR* dir = opendir(task_path.value().c_str());
+  if (!dir) {
+    DPLOG(ERROR) << "opendir(" << task_path.value() << ")";
+    return -1;
+  }
+
+  int total_cpu = 0;
+  while (struct dirent* ent = readdir(dir)) {
+    pid_t tid = internal::ProcDirSlotToPid(ent->d_name);
+    if (!tid)
+      continue;
+
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+
+    std::string stat;
+    FilePath stat_path =
+        task_path.Append(ent->d_name).Append(internal::kStatFile);
+    if (ReadFileToString(stat_path, &stat)) {
+      int cpu = ParseProcStatCPU(stat);
+      if (cpu > 0)
+        total_cpu += cpu;
+    }
+  }
+  closedir(dir);
+
+  return total_cpu;
+}
+
+}  // namespace
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+// On linux, we return vsize.
+size_t ProcessMetrics::GetPagefileUsage() const {
+  return internal::ReadProcStatsAndGetFieldAsSizeT(process_,
+                                                   internal::VM_VSIZE);
+}
+
+// On linux, we return the high water mark of vsize.
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return ReadProcStatusAndGetFieldAsSizeT(process_, "VmPeak") * 1024;
+}
+
+// On linux, we return RSS.
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) *
+      getpagesize();
+}
+
+// On linux, we return the high water mark of RSS.
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return ReadProcStatusAndGetFieldAsSizeT(process_, "VmHWM") * 1024;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv * 1024;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+#if defined(OS_CHROMEOS)
+  if (GetWorkingSetKBytesTotmaps(ws_usage))
+    return true;
+#endif
+  return GetWorkingSetKBytesStatm(ws_usage);
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_cpu_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_cpu_ = GetProcessCPU(process_);
+    return 0;
+  }
+
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+  DCHECK_NE(time_delta, 0);
+  if (time_delta == 0)
+    return 0;
+
+  int cpu = GetProcessCPU(process_);
+
+  // We have the number of jiffies in the time period.  Convert to percentage.
+  // Note this means we will go *over* 100 in the case where multiple threads
+  // are together adding to more than one CPU's worth.
+  TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu);
+  TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_);
+  int percentage = 100 * (cpu_time - last_cpu_time).InSecondsF() /
+      TimeDelta::FromMicroseconds(time_delta).InSecondsF();
+
+  last_cpu_time_ = time;
+  last_cpu_ = cpu;
+
+  return percentage;
+}
+
+// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
+// in your kernel configuration.
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  // Synchronously reading files in /proc does not hit the disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  std::string proc_io_contents;
+  FilePath io_file = internal::GetProcPidDir(process_).Append("io");
+  if (!ReadFileToString(io_file, &proc_io_contents))
+    return false;
+
+  io_counters->OtherOperationCount = 0;
+  io_counters->OtherTransferCount = 0;
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(proc_io_contents, ':', '\n', &pairs);
+  TrimKeyValuePairs(&pairs);
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    const std::string& key = pairs[i].first;
+    const std::string& value_str = pairs[i].second;
+    uint64* target_counter = NULL;
+    if (key == "syscr")
+      target_counter = &io_counters->ReadOperationCount;
+    else if (key == "syscw")
+      target_counter = &io_counters->WriteOperationCount;
+    else if (key == "rchar")
+      target_counter = &io_counters->ReadTransferCount;
+    else if (key == "wchar")
+      target_counter = &io_counters->WriteTransferCount;
+    if (!target_counter)
+      continue;
+    bool converted = StringToUint64(value_str, target_counter);
+    DCHECK(converted);
+  }
+  return true;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_system_time_(0),
+#if defined(OS_LINUX)
+      last_absolute_idle_wakeups_(0),
+#endif
+      last_cpu_(0) {
+  processor_count_ = SysInfo::NumberOfProcessors();
+}
+
+#if defined(OS_CHROMEOS)
+// Private, Shared and Proportional working set sizes are obtained from
+// /proc/<pid>/totmaps
+bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage)
+  const {
+  // The format of /proc/<pid>/totmaps is:
+  //
+  // Rss:                6120 kB
+  // Pss:                3335 kB
+  // Shared_Clean:       1008 kB
+  // Shared_Dirty:       4012 kB
+  // Private_Clean:         4 kB
+  // Private_Dirty:      1096 kB
+  // Referenced:          XXX kB
+  // Anonymous:           XXX kB
+  // AnonHugePages:       XXX kB
+  // Swap:                XXX kB
+  // Locked:              XXX kB
+  const size_t kPssIndex = (1 * 3) + 1;
+  const size_t kPrivate_CleanIndex = (4 * 3) + 1;
+  const size_t kPrivate_DirtyIndex = (5 * 3) + 1;
+  const size_t kSwapIndex = (9 * 3) + 1;
+
+  std::string totmaps_data;
+  {
+    FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps");
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    bool ret = ReadFileToString(totmaps_file, &totmaps_data);
+    if (!ret || totmaps_data.length() == 0)
+      return false;
+  }
+
+  std::vector<std::string> totmaps_fields;
+  SplitStringAlongWhitespace(totmaps_data, &totmaps_fields);
+
+  DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]);
+  DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]);
+  DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex - 1]);
+  DCHECK_EQ("Swap:", totmaps_fields[kSwapIndex-1]);
+
+  int pss = 0;
+  int private_clean = 0;
+  int private_dirty = 0;
+  int swap = 0;
+  bool ret = true;
+  ret &= StringToInt(totmaps_fields[kPssIndex], &pss);
+  ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean);
+  ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty);
+  ret &= StringToInt(totmaps_fields[kSwapIndex], &swap);
+
+  // On ChromeOS swap is to zram. We count this as private / shared, as
+  // increased swap decreases available RAM to user processes, which would
+  // otherwise create surprising results.
+  ws_usage->priv = private_clean + private_dirty + swap;
+  ws_usage->shared = pss + swap;
+  ws_usage->shareable = 0;
+  ws_usage->swapped = swap;
+  return ret;
+}
+#endif
+
+// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
+bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage)
+    const {
+  // Use statm instead of smaps because smaps is:
+  // a) Large and slow to parse.
+  // b) Unavailable in the SUID sandbox.
+
+  // First we need to get the page size, since everything is measured in pages.
+  // For details, see: man 5 proc.
+  const int page_size_kb = getpagesize() / 1024;
+  if (page_size_kb <= 0)
+    return false;
+
+  std::string statm;
+  {
+    FilePath statm_file = internal::GetProcPidDir(process_).Append("statm");
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    bool ret = ReadFileToString(statm_file, &statm);
+    if (!ret || statm.length() == 0)
+      return false;
+  }
+
+  std::vector<std::string> statm_vec;
+  SplitString(statm, ' ', &statm_vec);
+  if (statm_vec.size() != 7)
+    return false;  // Not the format we expect.
+
+  int statm_rss, statm_shared;
+  bool ret = true;
+  ret &= StringToInt(statm_vec[1], &statm_rss);
+  ret &= StringToInt(statm_vec[2], &statm_shared);
+
+  ws_usage->priv = (statm_rss - statm_shared) * page_size_kb;
+  ws_usage->shared = statm_shared * page_size_kb;
+
+  // Sharable is not calculated, as it does not provide interesting data.
+  ws_usage->shareable = 0;
+
+#if defined(OS_CHROMEOS)
+  // Can't get swapped memory from statm.
+  ws_usage->swapped = 0;
+#endif
+
+  return ret;
+}
+
+size_t GetSystemCommitCharge() {
+  SystemMemoryInfoKB meminfo;
+  if (!GetSystemMemoryInfo(&meminfo))
+    return 0;
+  return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
+}
+
+int ParseProcStatCPU(const std::string& input) {
+  // |input| may be empty if the process disappeared somehow.
+  // e.g. http://crbug.com/145811.
+  if (input.empty())
+    return -1;
+
+  size_t start = input.find_last_of(')');
+  if (start == input.npos)
+    return -1;
+
+  // Number of spaces remaining until reaching utime's index starting after the
+  // last ')'.
+  int num_spaces_remaining = internal::VM_UTIME - 1;
+
+  size_t i = start;
+  while ((i = input.find(' ', i + 1)) != input.npos) {
+    // Validate the assumption that there aren't any contiguous spaces
+    // in |input| before utime.
+    DCHECK_NE(input[i - 1], ' ');
+    if (--num_spaces_remaining == 0) {
+      int utime = 0;
+      int stime = 0;
+      if (sscanf(&input.data()[i], "%d %d", &utime, &stime) != 2)
+        return -1;
+
+      return utime + stime;
+    }
+  }
+
+  return -1;
+}
+
+const char kProcSelfExe[] = "/proc/self/exe";
+
+int GetNumberOfThreads(ProcessHandle process) {
+  return internal::ReadProcStatsAndGetFieldAsInt64(process,
+                                                   internal::VM_NUMTHREADS);
+}
+
+namespace {
+
+// The format of /proc/diskstats is:
+//  Device major number
+//  Device minor number
+//  Device name
+//  Field  1 -- # of reads completed
+//      This is the total number of reads completed successfully.
+//  Field  2 -- # of reads merged, field 6 -- # of writes merged
+//      Reads and writes which are adjacent to each other may be merged for
+//      efficiency.  Thus two 4K reads may become one 8K read before it is
+//      ultimately handed to the disk, and so it will be counted (and queued)
+//      as only one I/O.  This field lets you know how often this was done.
+//  Field  3 -- # of sectors read
+//      This is the total number of sectors read successfully.
+//  Field  4 -- # of milliseconds spent reading
+//      This is the total number of milliseconds spent by all reads (as
+//      measured from __make_request() to end_that_request_last()).
+//  Field  5 -- # of writes completed
+//      This is the total number of writes completed successfully.
+//  Field  6 -- # of writes merged
+//      See the description of field 2.
+//  Field  7 -- # of sectors written
+//      This is the total number of sectors written successfully.
+//  Field  8 -- # of milliseconds spent writing
+//      This is the total number of milliseconds spent by all writes (as
+//      measured from __make_request() to end_that_request_last()).
+//  Field  9 -- # of I/Os currently in progress
+//      The only field that should go to zero. Incremented as requests are
+//      given to appropriate struct request_queue and decremented as they
+//      finish.
+//  Field 10 -- # of milliseconds spent doing I/Os
+//      This field increases so long as field 9 is nonzero.
+//  Field 11 -- weighted # of milliseconds spent doing I/Os
+//      This field is incremented at each I/O start, I/O completion, I/O
+//      merge, or read of these stats by the number of I/Os in progress
+//      (field 9) times the number of milliseconds spent doing I/O since the
+//      last update of this field.  This can provide an easy measure of both
+//      I/O completion time and the backlog that may be accumulating.
+
+const size_t kDiskDriveName = 2;
+const size_t kDiskReads = 3;
+const size_t kDiskReadsMerged = 4;
+const size_t kDiskSectorsRead = 5;
+const size_t kDiskReadTime = 6;
+const size_t kDiskWrites = 7;
+const size_t kDiskWritesMerged = 8;
+const size_t kDiskSectorsWritten = 9;
+const size_t kDiskWriteTime = 10;
+const size_t kDiskIO = 11;
+const size_t kDiskIOTime = 12;
+const size_t kDiskWeightedIOTime = 13;
+
+}  // namespace
+
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+  total = 0;
+  free = 0;
+  buffers = 0;
+  cached = 0;
+  active_anon = 0;
+  inactive_anon = 0;
+  active_file = 0;
+  inactive_file = 0;
+  swap_total = 0;
+  swap_free = 0;
+  dirty = 0;
+
+  pswpin = 0;
+  pswpout = 0;
+  pgmajfault = 0;
+
+#ifdef OS_CHROMEOS
+  shmem = 0;
+  slab = 0;
+  gem_objects = -1;
+  gem_size = -1;
+#endif
+}
+
+scoped_ptr<Value> SystemMemoryInfoKB::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  res->SetInteger("total", total);
+  res->SetInteger("free", free);
+  res->SetInteger("buffers", buffers);
+  res->SetInteger("cached", cached);
+  res->SetInteger("active_anon", active_anon);
+  res->SetInteger("inactive_anon", inactive_anon);
+  res->SetInteger("active_file", active_file);
+  res->SetInteger("inactive_file", inactive_file);
+  res->SetInteger("swap_total", swap_total);
+  res->SetInteger("swap_free", swap_free);
+  res->SetInteger("swap_used", swap_total - swap_free);
+  res->SetInteger("dirty", dirty);
+  res->SetInteger("pswpin", pswpin);
+  res->SetInteger("pswpout", pswpout);
+  res->SetInteger("pgmajfault", pgmajfault);
+#ifdef OS_CHROMEOS
+  res->SetInteger("shmem", shmem);
+  res->SetInteger("slab", slab);
+  res->SetInteger("gem_objects", gem_objects);
+  res->SetInteger("gem_size", gem_size);
+#endif
+
+  return res.Pass();
+}
+
+// exposed for testing
+bool ParseProcMeminfo(const std::string& meminfo_data,
+                      SystemMemoryInfoKB* meminfo) {
+  // The format of /proc/meminfo is:
+  //
+  // MemTotal:      8235324 kB
+  // MemFree:       1628304 kB
+  // Buffers:        429596 kB
+  // Cached:        4728232 kB
+  // ...
+  // There is no guarantee on the ordering or position
+  // though it doesn't appear to change very often
+
+  // As a basic sanity check, let's make sure we at least get non-zero
+  // MemTotal value
+  meminfo->total = 0;
+
+  std::vector<std::string> meminfo_lines;
+  Tokenize(meminfo_data, "\n", &meminfo_lines);
+  for (std::vector<std::string>::iterator it = meminfo_lines.begin();
+       it != meminfo_lines.end(); ++it) {
+    std::vector<std::string> tokens;
+    SplitStringAlongWhitespace(*it, &tokens);
+    // HugePages_* only has a number and no suffix so we can't rely on
+    // there being exactly 3 tokens.
+    if (tokens.size() <= 1) {
+      DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
+                    << " malformed line: " << *it;
+      continue;
+    }
+
+    int* target = NULL;
+    if (tokens[0] == "MemTotal:")
+      target = &meminfo->total;
+    else if (tokens[0] == "MemFree:")
+      target = &meminfo->free;
+    else if (tokens[0] == "Buffers:")
+      target = &meminfo->buffers;
+    else if (tokens[0] == "Cached:")
+      target = &meminfo->cached;
+    else if (tokens[0] == "Active(anon):")
+      target = &meminfo->active_anon;
+    else if (tokens[0] == "Inactive(anon):")
+      target = &meminfo->inactive_anon;
+    else if (tokens[0] == "Active(file):")
+      target = &meminfo->active_file;
+    else if (tokens[0] == "Inactive(file):")
+      target = &meminfo->inactive_file;
+    else if (tokens[0] == "SwapTotal:")
+      target = &meminfo->swap_total;
+    else if (tokens[0] == "SwapFree:")
+      target = &meminfo->swap_free;
+    else if (tokens[0] == "Dirty:")
+      target = &meminfo->dirty;
+#if defined(OS_CHROMEOS)
+    // Chrome OS has a tweaked kernel that allows us to query Shmem, which is
+    // usually video memory otherwise invisible to the OS.
+    else if (tokens[0] == "Shmem:")
+      target = &meminfo->shmem;
+    else if (tokens[0] == "Slab:")
+      target = &meminfo->slab;
+#endif
+    if (target)
+      StringToInt(tokens[1], target);
+  }
+
+  // Make sure we got a valid MemTotal.
+  return meminfo->total > 0;
+}
+
+// exposed for testing
+bool ParseProcVmstat(const std::string& vmstat_data,
+                     SystemMemoryInfoKB* meminfo) {
+  // The format of /proc/vmstat is:
+  //
+  // nr_free_pages 299878
+  // nr_inactive_anon 239863
+  // nr_active_anon 1318966
+  // nr_inactive_file 2015629
+  // ...
+  //
+  // We iterate through the whole file because the position of the
+  // fields are dependent on the kernel version and configuration.
+
+  std::vector<std::string> vmstat_lines;
+  Tokenize(vmstat_data, "\n", &vmstat_lines);
+  for (std::vector<std::string>::iterator it = vmstat_lines.begin();
+       it != vmstat_lines.end(); ++it) {
+    std::vector<std::string> tokens;
+    SplitString(*it, ' ', &tokens);
+    if (tokens.size() != 2)
+      continue;
+
+    if (tokens[0] == "pswpin") {
+      StringToInt(tokens[1], &meminfo->pswpin);
+    } else if (tokens[0] == "pswpout") {
+      StringToInt(tokens[1], &meminfo->pswpout);
+    } else if (tokens[0] == "pgmajfault") {
+      StringToInt(tokens[1], &meminfo->pgmajfault);
+    }
+  }
+
+  return true;
+}
+
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  // Synchronously reading files in /proc and /sys are safe.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  // Used memory is: total - free - buffers - caches
+  FilePath meminfo_file("/proc/meminfo");
+  std::string meminfo_data;
+  if (!ReadFileToString(meminfo_file, &meminfo_data)) {
+    DLOG(WARNING) << "Failed to open " << meminfo_file.value();
+    return false;
+  }
+
+  if (!ParseProcMeminfo(meminfo_data, meminfo)) {
+    DLOG(WARNING) << "Failed to parse " << meminfo_file.value();
+    return false;
+  }
+
+#if defined(OS_CHROMEOS)
+  // Report on Chrome OS GEM object graphics memory. /run/debugfs_gpu is a
+  // bind mount into /sys/kernel/debug and synchronously reading the in-memory
+  // files in /sys is fast.
+#if defined(ARCH_CPU_ARM_FAMILY)
+  FilePath geminfo_file("/run/debugfs_gpu/exynos_gem_objects");
+#else
+  FilePath geminfo_file("/run/debugfs_gpu/i915_gem_objects");
+#endif
+  std::string geminfo_data;
+  meminfo->gem_objects = -1;
+  meminfo->gem_size = -1;
+  if (ReadFileToString(geminfo_file, &geminfo_data)) {
+    int gem_objects = -1;
+    long long gem_size = -1;
+    int num_res = sscanf(geminfo_data.c_str(),
+                         "%d objects, %lld bytes",
+                         &gem_objects, &gem_size);
+    if (num_res == 2) {
+      meminfo->gem_objects = gem_objects;
+      meminfo->gem_size = gem_size;
+    }
+  }
+
+#if defined(ARCH_CPU_ARM_FAMILY)
+  // Incorporate Mali graphics memory if present.
+  FilePath mali_memory_file("/sys/class/misc/mali0/device/memory");
+  std::string mali_memory_data;
+  if (ReadFileToString(mali_memory_file, &mali_memory_data)) {
+    long long mali_size = -1;
+    int num_res = sscanf(mali_memory_data.c_str(), "%lld bytes", &mali_size);
+    if (num_res == 1)
+      meminfo->gem_size += mali_size;
+  }
+#endif  // defined(ARCH_CPU_ARM_FAMILY)
+#endif  // defined(OS_CHROMEOS)
+
+  FilePath vmstat_file("/proc/vmstat");
+  std::string vmstat_data;
+  if (!ReadFileToString(vmstat_file, &vmstat_data)) {
+    DLOG(WARNING) << "Failed to open " << vmstat_file.value();
+    return false;
+  }
+  if (!ParseProcVmstat(vmstat_data, meminfo)) {
+    DLOG(WARNING) << "Failed to parse " << vmstat_file.value();
+    return false;
+  }
+
+  return true;
+}
+
+SystemDiskInfo::SystemDiskInfo() {
+  reads = 0;
+  reads_merged = 0;
+  sectors_read = 0;
+  read_time = 0;
+  writes = 0;
+  writes_merged = 0;
+  sectors_written = 0;
+  write_time = 0;
+  io = 0;
+  io_time = 0;
+  weighted_io_time = 0;
+}
+
+scoped_ptr<Value> SystemDiskInfo::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  // Write out uint64 variables as doubles.
+  // Note: this may discard some precision, but for JS there's no other option.
+  res->SetDouble("reads", static_cast<double>(reads));
+  res->SetDouble("reads_merged", static_cast<double>(reads_merged));
+  res->SetDouble("sectors_read", static_cast<double>(sectors_read));
+  res->SetDouble("read_time", static_cast<double>(read_time));
+  res->SetDouble("writes", static_cast<double>(writes));
+  res->SetDouble("writes_merged", static_cast<double>(writes_merged));
+  res->SetDouble("sectors_written", static_cast<double>(sectors_written));
+  res->SetDouble("write_time", static_cast<double>(write_time));
+  res->SetDouble("io", static_cast<double>(io));
+  res->SetDouble("io_time", static_cast<double>(io_time));
+  res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
+
+  return res.Pass();
+}
+
+bool IsValidDiskName(const std::string& candidate) {
+  if (candidate.length() < 3)
+    return false;
+  if (candidate[1] == 'd' &&
+      (candidate[0] == 'h' || candidate[0] == 's' || candidate[0] == 'v')) {
+    // [hsv]d[a-z]+ case
+    for (size_t i = 2; i < candidate.length(); ++i) {
+      if (!islower(candidate[i]))
+        return false;
+    }
+    return true;
+  }
+
+  const char kMMCName[] = "mmcblk";
+  const size_t kMMCNameLen = strlen(kMMCName);
+  if (candidate.length() < kMMCNameLen + 1)
+    return false;
+  if (candidate.compare(0, kMMCNameLen, kMMCName) != 0)
+    return false;
+
+  // mmcblk[0-9]+ case
+  for (size_t i = kMMCNameLen; i < candidate.length(); ++i) {
+    if (!isdigit(candidate[i]))
+      return false;
+  }
+  return true;
+}
+
+bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
+  // Synchronously reading files in /proc does not hit the disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath diskinfo_file("/proc/diskstats");
+  std::string diskinfo_data;
+  if (!ReadFileToString(diskinfo_file, &diskinfo_data)) {
+    DLOG(WARNING) << "Failed to open " << diskinfo_file.value();
+    return false;
+  }
+
+  std::vector<std::string> diskinfo_lines;
+  size_t line_count = Tokenize(diskinfo_data, "\n", &diskinfo_lines);
+  if (line_count == 0) {
+    DLOG(WARNING) << "No lines found";
+    return false;
+  }
+
+  diskinfo->reads = 0;
+  diskinfo->reads_merged = 0;
+  diskinfo->sectors_read = 0;
+  diskinfo->read_time = 0;
+  diskinfo->writes = 0;
+  diskinfo->writes_merged = 0;
+  diskinfo->sectors_written = 0;
+  diskinfo->write_time = 0;
+  diskinfo->io = 0;
+  diskinfo->io_time = 0;
+  diskinfo->weighted_io_time = 0;
+
+  uint64 reads = 0;
+  uint64 reads_merged = 0;
+  uint64 sectors_read = 0;
+  uint64 read_time = 0;
+  uint64 writes = 0;
+  uint64 writes_merged = 0;
+  uint64 sectors_written = 0;
+  uint64 write_time = 0;
+  uint64 io = 0;
+  uint64 io_time = 0;
+  uint64 weighted_io_time = 0;
+
+  for (size_t i = 0; i < line_count; i++) {
+    std::vector<std::string> disk_fields;
+    SplitStringAlongWhitespace(diskinfo_lines[i], &disk_fields);
+
+    // Fields may have overflowed and reset to zero.
+    if (IsValidDiskName(disk_fields[kDiskDriveName])) {
+      StringToUint64(disk_fields[kDiskReads], &reads);
+      StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
+      StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
+      StringToUint64(disk_fields[kDiskReadTime], &read_time);
+      StringToUint64(disk_fields[kDiskWrites], &writes);
+      StringToUint64(disk_fields[kDiskWritesMerged], &writes_merged);
+      StringToUint64(disk_fields[kDiskSectorsWritten], &sectors_written);
+      StringToUint64(disk_fields[kDiskWriteTime], &write_time);
+      StringToUint64(disk_fields[kDiskIO], &io);
+      StringToUint64(disk_fields[kDiskIOTime], &io_time);
+      StringToUint64(disk_fields[kDiskWeightedIOTime], &weighted_io_time);
+
+      diskinfo->reads += reads;
+      diskinfo->reads_merged += reads_merged;
+      diskinfo->sectors_read += sectors_read;
+      diskinfo->read_time += read_time;
+      diskinfo->writes += writes;
+      diskinfo->writes_merged += writes_merged;
+      diskinfo->sectors_written += sectors_written;
+      diskinfo->write_time += write_time;
+      diskinfo->io += io;
+      diskinfo->io_time += io_time;
+      diskinfo->weighted_io_time += weighted_io_time;
+    }
+  }
+
+  return true;
+}
+
+#if defined(OS_CHROMEOS)
+scoped_ptr<Value> SwapInfo::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  // Write out uint64 variables as doubles.
+  // Note: this may discard some precision, but for JS there's no other option.
+  res->SetDouble("num_reads", static_cast<double>(num_reads));
+  res->SetDouble("num_writes", static_cast<double>(num_writes));
+  res->SetDouble("orig_data_size", static_cast<double>(orig_data_size));
+  res->SetDouble("compr_data_size", static_cast<double>(compr_data_size));
+  res->SetDouble("mem_used_total", static_cast<double>(mem_used_total));
+  if (compr_data_size > 0)
+    res->SetDouble("compression_ratio", static_cast<double>(orig_data_size) /
+                                        static_cast<double>(compr_data_size));
+  else
+    res->SetDouble("compression_ratio", 0);
+
+  return res.Pass();
+}
+
+void GetSwapInfo(SwapInfo* swap_info) {
+  // Synchronously reading files in /sys/block/zram0 does not hit the disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath zram_path("/sys/block/zram0");
+  uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size"));
+  if (orig_data_size <= 4096) {
+    // A single page is compressed at startup, and has a high compression
+    // ratio. We ignore this as it doesn't indicate any real swapping.
+    swap_info->orig_data_size = 0;
+    swap_info->num_reads = 0;
+    swap_info->num_writes = 0;
+    swap_info->compr_data_size = 0;
+    swap_info->mem_used_total = 0;
+    return;
+  }
+  swap_info->orig_data_size = orig_data_size;
+  swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads"));
+  swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes"));
+  swap_info->compr_data_size =
+      ReadFileToUint64(zram_path.Append("compr_data_size"));
+  swap_info->mem_used_total =
+      ReadFileToUint64(zram_path.Append("mem_used_total"));
+}
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_LINUX)
+int ProcessMetrics::GetIdleWakeupsPerSecond() {
+  uint64 wake_ups;
+  const char kWakeupStat[] = "se.statistics.nr_wakeups";
+  return ReadProcSchedAndGetFieldAsUint64(process_, kWakeupStat, &wake_ups) ?
+      CalculateIdleWakeupsPerSecond(wake_ups) : 0;
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace base
diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc
new file mode 100644
index 0000000..f84b435
--- /dev/null
+++ b/base/process/process_metrics_mac.cc
@@ -0,0 +1,361 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <mach/shared_region.h>
+#include <sys/sysctl.h>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/sys_info.h"
+
+#if !defined(TASK_POWER_INFO)
+// Doesn't exist in the 10.6 or 10.7 SDKs.
+#define TASK_POWER_INFO        21
+struct task_power_info {
+        uint64_t                total_user;
+        uint64_t                total_system;
+        uint64_t                task_interrupt_wakeups;
+        uint64_t                task_platform_idle_wakeups;
+        uint64_t                task_timer_wakeups_bin_1;
+        uint64_t                task_timer_wakeups_bin_2;
+};
+typedef struct task_power_info        task_power_info_data_t;
+typedef struct task_power_info        *task_power_info_t;
+#define TASK_POWER_INFO_COUNT        ((mach_msg_type_number_t) \
+                (sizeof (task_power_info_data_t) / sizeof (natural_t)))
+#endif
+
+namespace base {
+
+namespace {
+
+bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) {
+  if (task == MACH_PORT_NULL)
+    return false;
+  mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+  kern_return_t kr = task_info(task,
+                               TASK_BASIC_INFO_64,
+                               reinterpret_cast<task_info_t>(task_info_data),
+                               &count);
+  // Most likely cause for failure: |task| is a zombie.
+  return kr == KERN_SUCCESS;
+}
+
+bool GetCPUTypeForProcess(pid_t pid, cpu_type_t* cpu_type) {
+  size_t len = sizeof(*cpu_type);
+  int result = sysctlbyname("sysctl.proc_cputype",
+                            cpu_type,
+                            &len,
+                            NULL,
+                            0);
+  if (result != 0) {
+    DPLOG(ERROR) << "sysctlbyname(""sysctl.proc_cputype"")";
+    return false;
+  }
+
+  return true;
+}
+
+bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) {
+  if (type == CPU_TYPE_I386) {
+    return addr >= SHARED_REGION_BASE_I386 &&
+           addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386);
+  } else if (type == CPU_TYPE_X86_64) {
+    return addr >= SHARED_REGION_BASE_X86_64 &&
+           addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
+  } else {
+    return false;
+  }
+}
+
+}  // namespace
+
+// Getting a mach task from a pid for another process requires permissions in
+// general, so there doesn't really seem to be a way to do these (and spinning
+// up ps to fetch each stats seems dangerous to put in a base api for anyone to
+// call). Child processes ipc their port, so return something if available,
+// otherwise return 0.
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
+    ProcessHandle process,
+    ProcessMetrics::PortProvider* port_provider) {
+  return new ProcessMetrics(process, port_provider);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+    return 0;
+  return task_info_data.virtual_size;
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+    return 0;
+  return task_info_data.resident_size;
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+// This is a rough approximation of the algorithm that libtop uses.
+// private_bytes is the size of private resident memory.
+// shared_bytes is the size of shared resident memory.
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  size_t private_pages_count = 0;
+  size_t shared_pages_count = 0;
+
+  if (!private_bytes && !shared_bytes)
+    return true;
+
+  mach_port_t task = TaskForPid(process_);
+  if (task == MACH_PORT_NULL) {
+    DLOG(ERROR) << "Invalid process";
+    return false;
+  }
+
+  cpu_type_t cpu_type;
+  if (!GetCPUTypeForProcess(process_, &cpu_type))
+    return false;
+
+  // The same region can be referenced multiple times. To avoid double counting
+  // we need to keep track of which regions we've already counted.
+  base::hash_set<int> seen_objects;
+
+  // We iterate through each VM region in the task's address map. For shared
+  // memory we add up all the pages that are marked as shared. Like libtop we
+  // try to avoid counting pages that are also referenced by other tasks. Since
+  // we don't have access to the VM regions of other tasks the only hint we have
+  // is if the address is in the shared region area.
+  //
+  // Private memory is much simpler. We simply count the pages that are marked
+  // as private or copy on write (COW).
+  //
+  // See libtop_update_vm_regions in
+  // http://www.opensource.apple.com/source/top/top-67/libtop.c
+  mach_vm_size_t size = 0;
+  for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) {
+    vm_region_top_info_data_t info;
+    mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT;
+    mach_port_t object_name;
+    kern_return_t kr = mach_vm_region(task,
+                                      &address,
+                                      &size,
+                                      VM_REGION_TOP_INFO,
+                                      reinterpret_cast<vm_region_info_t>(&info),
+                                      &info_count,
+                                      &object_name);
+    if (kr == KERN_INVALID_ADDRESS) {
+      // We're at the end of the address space.
+      break;
+    } else if (kr != KERN_SUCCESS) {
+      MACH_DLOG(ERROR, kr) << "mach_vm_region";
+      return false;
+    }
+
+    // The kernel always returns a null object for VM_REGION_TOP_INFO, but
+    // balance it with a deallocate in case this ever changes. See 10.9.2
+    // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
+    mach_port_deallocate(mach_task_self(), object_name);
+
+    if (IsAddressInSharedRegion(address, cpu_type) &&
+        info.share_mode != SM_PRIVATE)
+      continue;
+
+    if (info.share_mode == SM_COW && info.ref_count == 1)
+      info.share_mode = SM_PRIVATE;
+
+    switch (info.share_mode) {
+      case SM_PRIVATE:
+        private_pages_count += info.private_pages_resident;
+        private_pages_count += info.shared_pages_resident;
+        break;
+      case SM_COW:
+        private_pages_count += info.private_pages_resident;
+        // Fall through
+      case SM_SHARED:
+        if (seen_objects.count(info.obj_id) == 0) {
+          // Only count the first reference to this region.
+          seen_objects.insert(info.obj_id);
+          shared_pages_count += info.shared_pages_resident;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  if (private_bytes)
+    *private_bytes = private_pages_count * PAGE_SIZE;
+  if (shared_bytes)
+    *shared_bytes = shared_pages_count * PAGE_SIZE;
+
+  return true;
+}
+
+void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
+  WorkingSetKBytes unused;
+  if (!GetCommittedAndWorkingSetKBytes(usage, &unused)) {
+    *usage = CommittedKBytes();
+  }
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  CommittedKBytes unused;
+  return GetCommittedAndWorkingSetKBytes(&unused, ws_usage);
+}
+
+bool ProcessMetrics::GetCommittedAndWorkingSetKBytes(
+    CommittedKBytes* usage,
+    WorkingSetKBytes* ws_usage) const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+    return false;
+
+  usage->priv = task_info_data.virtual_size / 1024;
+  usage->mapped = 0;
+  usage->image = 0;
+
+  ws_usage->priv = task_info_data.resident_size / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+#define TIME_VALUE_TO_TIMEVAL(a, r) do {  \
+  (r)->tv_sec = (a)->seconds;             \
+  (r)->tv_usec = (a)->microseconds;       \
+} while (0)
+
+double ProcessMetrics::GetCPUUsage() {
+  mach_port_t task = TaskForPid(process_);
+  if (task == MACH_PORT_NULL)
+    return 0;
+
+  // Libtop explicitly loops over the threads (libtop_pinfo_update_cpu_usage()
+  // in libtop.c), but this is more concise and gives the same results:
+  task_thread_times_info thread_info_data;
+  mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
+  kern_return_t kr = task_info(task,
+                               TASK_THREAD_TIMES_INFO,
+                               reinterpret_cast<task_info_t>(&thread_info_data),
+                               &thread_info_count);
+  if (kr != KERN_SUCCESS) {
+    // Most likely cause: |task| is a zombie.
+    return 0;
+  }
+
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(task, &task_info_data))
+    return 0;
+
+  /* Set total_time. */
+  // thread info contains live time...
+  struct timeval user_timeval, system_timeval, task_timeval;
+  TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval);
+  TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval);
+  timeradd(&user_timeval, &system_timeval, &task_timeval);
+
+  // ... task info contains terminated time.
+  TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
+  TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
+  timeradd(&user_timeval, &task_timeval, &task_timeval);
+  timeradd(&system_timeval, &task_timeval, &task_timeval);
+
+  TimeTicks time = TimeTicks::Now();
+  int64 task_time = TimeValToMicroseconds(task_timeval);
+
+  if (last_system_time_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_system_time_ = task_time;
+    return 0;
+  }
+
+  int64 system_time_delta = task_time - last_system_time_;
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+  DCHECK_NE(0U, time_delta);
+  if (time_delta == 0)
+    return 0;
+
+  last_cpu_time_ = time;
+  last_system_time_ = task_time;
+
+  return static_cast<double>(system_time_delta * 100.0) / time_delta;
+}
+
+int ProcessMetrics::GetIdleWakeupsPerSecond() {
+  mach_port_t task = TaskForPid(process_);
+  if (task == MACH_PORT_NULL)
+    return 0;
+
+  task_power_info power_info_data;
+  mach_msg_type_number_t power_info_count = TASK_POWER_INFO_COUNT;
+  kern_return_t kr = task_info(task,
+                               TASK_POWER_INFO,
+                               reinterpret_cast<task_info_t>(&power_info_data),
+                               &power_info_count);
+  if (kr != KERN_SUCCESS) {
+    // Most likely cause: |task| is a zombie, or this is on a pre-10.8.4 system
+    // where TASK_POWER_INFO isn't supported yet.
+    return 0;
+  }
+  return CalculateIdleWakeupsPerSecond(
+      power_info_data.task_platform_idle_wakeups);
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process,
+                               ProcessMetrics::PortProvider* port_provider)
+    : process_(process),
+      last_system_time_(0),
+      last_absolute_idle_wakeups_(0),
+      port_provider_(port_provider) {
+  processor_count_ = SysInfo::NumberOfProcessors();
+}
+
+mach_port_t ProcessMetrics::TaskForPid(ProcessHandle process) const {
+  mach_port_t task = MACH_PORT_NULL;
+  if (port_provider_)
+    task = port_provider_->TaskForPid(process_);
+  if (task == MACH_PORT_NULL && process_ == getpid())
+    task = mach_task_self();
+  return task;
+}
+
+// Bytes committed by the system.
+size_t GetSystemCommitCharge() {
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+  vm_statistics_data_t data;
+  kern_return_t kr = host_statistics(host, HOST_VM_INFO,
+                                     reinterpret_cast<host_info_t>(&data),
+                                     &count);
+  if (kr != KERN_SUCCESS) {
+    MACH_DLOG(WARNING, kr) << "host_statistics";
+    return 0;
+  }
+
+  return (data.active_count * PAGE_SIZE) / 1024;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_openbsd.cc b/base/process/process_metrics_openbsd.cc
new file mode 100644
index 0000000..72927a1
--- /dev/null
+++ b/base/process/process_metrics_openbsd.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+namespace base {
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return (info.p_vm_tsize + info.p_vm_dsize + info.p_vm_ssize);
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.p_vm_rssize * getpagesize();
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv << 10;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  // TODO(bapt): be sure we can't be precise
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+static int GetProcessCPU(pid_t pid) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.p_pctcpu;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_cpu_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_cpu_ = GetProcessCPU(process_);
+    return 0;
+  }
+
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+  DCHECK_NE(time_delta, 0);
+
+  if (time_delta == 0)
+    return 0;
+
+  int cpu = GetProcessCPU(process_);
+
+  last_cpu_time_ = time;
+  last_cpu_ = cpu;
+
+  double percentage = static_cast<double>((cpu * 100.0) / FSCALE);
+
+  return percentage;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_system_time_(0),
+      last_cpu_(0) {
+
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+size_t GetSystemCommitCharge() {
+  int mib[] = { CTL_VM, VM_METER };
+  int pagesize;
+  struct vmtotal vmtotal;
+  unsigned long mem_total, mem_free, mem_inactive;
+  size_t len = sizeof(vmtotal);
+
+  if (sysctl(mib, arraysize(mib), &vmtotal, &len, NULL, 0) < 0)
+    return 0;
+
+  mem_total = vmtotal.t_vm;
+  mem_free = vmtotal.t_free;
+  mem_inactive = vmtotal.t_vm - vmtotal.t_avm;
+
+  pagesize = getpagesize();
+
+  return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize);
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc
new file mode 100644
index 0000000..42b3f2d
--- /dev/null
+++ b/base/process/process_metrics_posix.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+int64 TimeValToMicroseconds(const struct timeval& tv) {
+  int64 ret = tv.tv_sec;  // Avoid (int * int) integer overflow.
+  ret *= Time::kMicrosecondsPerSecond;
+  ret += tv.tv_usec;
+  return ret;
+}
+
+ProcessMetrics::~ProcessMetrics() { }
+
+#if defined(OS_LINUX)
+static const rlim_t kSystemDefaultMaxFds = 8192;
+#elif defined(OS_MACOSX)
+static const rlim_t kSystemDefaultMaxFds = 256;
+#elif defined(OS_SOLARIS)
+static const rlim_t kSystemDefaultMaxFds = 8192;
+#elif defined(OS_FREEBSD)
+static const rlim_t kSystemDefaultMaxFds = 8192;
+#elif defined(OS_OPENBSD)
+static const rlim_t kSystemDefaultMaxFds = 256;
+#elif defined(OS_ANDROID)
+static const rlim_t kSystemDefaultMaxFds = 1024;
+#endif
+
+size_t GetMaxFds() {
+  rlim_t max_fds;
+  struct rlimit nofile;
+  if (getrlimit(RLIMIT_NOFILE, &nofile)) {
+    // getrlimit failed. Take a best guess.
+    max_fds = kSystemDefaultMaxFds;
+    RAW_LOG(ERROR, "getrlimit(RLIMIT_NOFILE) failed");
+  } else {
+    max_fds = nofile.rlim_cur;
+  }
+
+  if (max_fds > INT_MAX)
+    max_fds = INT_MAX;
+
+  return static_cast<size_t>(max_fds);
+}
+
+
+void SetFdLimit(unsigned int max_descriptors) {
+  struct rlimit limits;
+  if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
+    unsigned int new_limit = max_descriptors;
+    if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
+      new_limit = limits.rlim_max;
+    }
+    limits.rlim_cur = new_limit;
+    if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
+      PLOG(INFO) << "Failed to set file descriptor limit";
+    }
+  } else {
+    PLOG(INFO) << "Failed to get file descriptor limit";
+  }
+}
+
+size_t GetPageSize() {
+  return getpagesize();
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
new file mode 100644
index 0000000..76767b0
--- /dev/null
+++ b/base/process/process_metrics_unittest.cc
@@ -0,0 +1,363 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace base {
+namespace debug {
+
+// Tests for SystemMetrics.
+// Exists as a class so it can be a friend of SystemMetrics.
+class SystemMetricsTest : public testing::Test {
+ public:
+  SystemMetricsTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SystemMetricsTest);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST_F(SystemMetricsTest, IsValidDiskName) {
+  std::string invalid_input1 = "";
+  std::string invalid_input2 = "s";
+  std::string invalid_input3 = "sdz+";
+  std::string invalid_input4 = "hda0";
+  std::string invalid_input5 = "mmcbl";
+  std::string invalid_input6 = "mmcblka";
+  std::string invalid_input7 = "mmcblkb";
+  std::string invalid_input8 = "mmmblk0";
+
+  EXPECT_FALSE(IsValidDiskName(invalid_input1));
+  EXPECT_FALSE(IsValidDiskName(invalid_input2));
+  EXPECT_FALSE(IsValidDiskName(invalid_input3));
+  EXPECT_FALSE(IsValidDiskName(invalid_input4));
+  EXPECT_FALSE(IsValidDiskName(invalid_input5));
+  EXPECT_FALSE(IsValidDiskName(invalid_input6));
+  EXPECT_FALSE(IsValidDiskName(invalid_input7));
+  EXPECT_FALSE(IsValidDiskName(invalid_input8));
+
+  std::string valid_input1 = "sda";
+  std::string valid_input2 = "sdaaaa";
+  std::string valid_input3 = "hdz";
+  std::string valid_input4 = "mmcblk0";
+  std::string valid_input5 = "mmcblk999";
+
+  EXPECT_TRUE(IsValidDiskName(valid_input1));
+  EXPECT_TRUE(IsValidDiskName(valid_input2));
+  EXPECT_TRUE(IsValidDiskName(valid_input3));
+  EXPECT_TRUE(IsValidDiskName(valid_input4));
+  EXPECT_TRUE(IsValidDiskName(valid_input5));
+}
+
+TEST_F(SystemMetricsTest, ParseMeminfo) {
+  struct SystemMemoryInfoKB meminfo;
+  std::string invalid_input1 = "abc";
+  std::string invalid_input2 = "MemTotal:";
+  // Partial file with no MemTotal
+  std::string invalid_input3 =
+    "MemFree:         3913968 kB\n"
+    "Buffers:         2348340 kB\n"
+    "Cached:         49071596 kB\n"
+    "SwapCached:           12 kB\n"
+    "Active:         36393900 kB\n"
+    "Inactive:       21221496 kB\n"
+    "Active(anon):    5674352 kB\n"
+    "Inactive(anon):   633992 kB\n";
+  EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo));
+  EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo));
+  EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo));
+
+  std::string valid_input1 =
+    "MemTotal:        3981504 kB\n"
+    "MemFree:          140764 kB\n"
+    "Buffers:          116480 kB\n"
+    "Cached:           406160 kB\n"
+    "SwapCached:        21304 kB\n"
+    "Active:          3152040 kB\n"
+    "Inactive:         472856 kB\n"
+    "Active(anon):    2972352 kB\n"
+    "Inactive(anon):   270108 kB\n"
+    "Active(file):     179688 kB\n"
+    "Inactive(file):   202748 kB\n"
+    "Unevictable:           0 kB\n"
+    "Mlocked:               0 kB\n"
+    "SwapTotal:       5832280 kB\n"
+    "SwapFree:        3672368 kB\n"
+    "Dirty:               184 kB\n"
+    "Writeback:             0 kB\n"
+    "AnonPages:       3101224 kB\n"
+    "Mapped:           142296 kB\n"
+    "Shmem:            140204 kB\n"
+    "Slab:              54212 kB\n"
+    "SReclaimable:      30936 kB\n"
+    "SUnreclaim:        23276 kB\n"
+    "KernelStack:        2464 kB\n"
+    "PageTables:        24812 kB\n"
+    "NFS_Unstable:          0 kB\n"
+    "Bounce:                0 kB\n"
+    "WritebackTmp:          0 kB\n"
+    "CommitLimit:     7823032 kB\n"
+    "Committed_AS:    7973536 kB\n"
+    "VmallocTotal:   34359738367 kB\n"
+    "VmallocUsed:      375940 kB\n"
+    "VmallocChunk:   34359361127 kB\n"
+    "DirectMap4k:       72448 kB\n"
+    "DirectMap2M:     4061184 kB\n";
+  // output from a much older kernel where the Active and Inactive aren't
+  // broken down into anon and file and Huge Pages are enabled
+  std::string valid_input2 =
+    "MemTotal:       255908 kB\n"
+    "MemFree:         69936 kB\n"
+    "Buffers:         15812 kB\n"
+    "Cached:         115124 kB\n"
+    "SwapCached:          0 kB\n"
+    "Active:          92700 kB\n"
+    "Inactive:        63792 kB\n"
+    "HighTotal:           0 kB\n"
+    "HighFree:            0 kB\n"
+    "LowTotal:       255908 kB\n"
+    "LowFree:         69936 kB\n"
+    "SwapTotal:      524280 kB\n"
+    "SwapFree:       524200 kB\n"
+    "Dirty:               4 kB\n"
+    "Writeback:           0 kB\n"
+    "Mapped:          42236 kB\n"
+    "Slab:            25912 kB\n"
+    "Committed_AS:   118680 kB\n"
+    "PageTables:       1236 kB\n"
+    "VmallocTotal:  3874808 kB\n"
+    "VmallocUsed:      1416 kB\n"
+    "VmallocChunk:  3872908 kB\n"
+    "HugePages_Total:     0\n"
+    "HugePages_Free:      0\n"
+    "Hugepagesize:     4096 kB\n";
+
+  EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo));
+  EXPECT_EQ(meminfo.total, 3981504);
+  EXPECT_EQ(meminfo.free, 140764);
+  EXPECT_EQ(meminfo.buffers, 116480);
+  EXPECT_EQ(meminfo.cached, 406160);
+  EXPECT_EQ(meminfo.active_anon, 2972352);
+  EXPECT_EQ(meminfo.active_file, 179688);
+  EXPECT_EQ(meminfo.inactive_anon, 270108);
+  EXPECT_EQ(meminfo.inactive_file, 202748);
+  EXPECT_EQ(meminfo.swap_total, 5832280);
+  EXPECT_EQ(meminfo.swap_free, 3672368);
+  EXPECT_EQ(meminfo.dirty, 184);
+#if defined(OS_CHROMEOS)
+  EXPECT_EQ(meminfo.shmem, 140204);
+  EXPECT_EQ(meminfo.slab, 54212);
+#endif
+  EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo));
+  EXPECT_EQ(meminfo.total, 255908);
+  EXPECT_EQ(meminfo.free, 69936);
+  EXPECT_EQ(meminfo.buffers, 15812);
+  EXPECT_EQ(meminfo.cached, 115124);
+  EXPECT_EQ(meminfo.swap_total, 524280);
+  EXPECT_EQ(meminfo.swap_free, 524200);
+  EXPECT_EQ(meminfo.dirty, 4);
+}
+
+TEST_F(SystemMetricsTest, ParseVmstat) {
+  struct SystemMemoryInfoKB meminfo;
+  // part of vmstat from a 3.2 kernel with numa enabled
+  std::string valid_input1 =
+    "nr_free_pages 905104\n"
+    "nr_inactive_anon 142478"
+    "nr_active_anon 1520046\n"
+    "nr_inactive_file 4481001\n"
+    "nr_active_file 8313439\n"
+    "nr_unevictable 5044\n"
+    "nr_mlock 5044\n"
+    "nr_anon_pages 1633780\n"
+    "nr_mapped 104742\n"
+    "nr_file_pages 12828218\n"
+    "nr_dirty 245\n"
+    "nr_writeback 0\n"
+    "nr_slab_reclaimable 831609\n"
+    "nr_slab_unreclaimable 41164\n"
+    "nr_page_table_pages 31470\n"
+    "nr_kernel_stack 1735\n"
+    "nr_unstable 0\n"
+    "nr_bounce 0\n"
+    "nr_vmscan_write 406\n"
+    "nr_vmscan_immediate_reclaim 281\n"
+    "nr_writeback_temp 0\n"
+    "nr_isolated_anon 0\n"
+    "nr_isolated_file 0\n"
+    "nr_shmem 28820\n"
+    "nr_dirtied 84674644\n"
+    "nr_written 75307109\n"
+    "nr_anon_transparent_hugepages 0\n"
+    "nr_dirty_threshold 1536206\n"
+    "nr_dirty_background_threshold 768103\n"
+    "pgpgin 30777108\n"
+    "pgpgout 319023278\n"
+    "pswpin 179\n"
+    "pswpout 406\n"
+    "pgalloc_dma 0\n"
+    "pgalloc_dma32 20833399\n"
+    "pgalloc_normal 1622609290\n"
+    "pgalloc_movable 0\n"
+    "pgfree 1644355583\n"
+    "pgactivate 75391882\n"
+    "pgdeactivate 4121019\n"
+    "pgfault 2542879679\n"
+    "pgmajfault 487192\n";
+  std::string valid_input2 =
+    "nr_free_pages 180125\n"
+    "nr_inactive_anon 51\n"
+    "nr_active_anon 38832\n"
+    "nr_inactive_file 50171\n"
+    "nr_active_file 47510\n"
+    "nr_unevictable 0\n"
+    "nr_mlock 0\n"
+    "nr_anon_pages 38825\n"
+    "nr_mapped 24043\n"
+    "nr_file_pages 97733\n"
+    "nr_dirty 0\n"
+    "nr_writeback 0\n"
+    "nr_slab_reclaimable 4032\n"
+    "nr_slab_unreclaimable 2848\n"
+    "nr_page_table_pages 1505\n"
+    "nr_kernel_stack 626\n"
+    "nr_unstable 0\n"
+    "nr_bounce 0\n"
+    "nr_vmscan_write 0\n"
+    "nr_vmscan_immediate_reclaim 0\n"
+    "nr_writeback_temp 0\n"
+    "nr_isolated_anon 0\n"
+    "nr_isolated_file 0\n"
+    "nr_shmem 58\n"
+    "nr_dirtied 435358\n"
+    "nr_written 401258\n"
+    "nr_anon_transparent_hugepages 0\n"
+    "nr_dirty_threshold 18566\n"
+    "nr_dirty_background_threshold 4641\n"
+    "pgpgin 299464\n"
+    "pgpgout 2437788\n"
+    "pswpin 12\n"
+    "pswpout 901\n"
+    "pgalloc_normal 144213030\n"
+    "pgalloc_high 164501274\n"
+    "pgalloc_movable 0\n"
+    "pgfree 308894908\n"
+    "pgactivate 239320\n"
+    "pgdeactivate 1\n"
+    "pgfault 716044601\n"
+    "pgmajfault 2023\n"
+    "pgrefill_normal 0\n"
+    "pgrefill_high 0\n"
+    "pgrefill_movable 0\n";
+  EXPECT_TRUE(ParseProcVmstat(valid_input1, &meminfo));
+  EXPECT_EQ(meminfo.pswpin, 179);
+  EXPECT_EQ(meminfo.pswpout, 406);
+  EXPECT_EQ(meminfo.pgmajfault, 487192);
+  EXPECT_TRUE(ParseProcVmstat(valid_input2, &meminfo));
+  EXPECT_EQ(meminfo.pswpin, 12);
+  EXPECT_EQ(meminfo.pswpout, 901);
+  EXPECT_EQ(meminfo.pgmajfault, 2023);
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
+  base::SystemMemoryInfoKB info;
+  EXPECT_TRUE(base::GetSystemMemoryInfo(&info));
+
+  // Ensure each field received a value.
+  EXPECT_GT(info.total, 0);
+  EXPECT_GT(info.free, 0);
+  EXPECT_GT(info.buffers, 0);
+  EXPECT_GT(info.cached, 0);
+  EXPECT_GT(info.active_anon, 0);
+  EXPECT_GT(info.inactive_anon, 0);
+  EXPECT_GT(info.active_file, 0);
+  EXPECT_GT(info.inactive_file, 0);
+
+  // All the values should be less than the total amount of memory.
+  EXPECT_LT(info.free, info.total);
+  EXPECT_LT(info.buffers, info.total);
+  EXPECT_LT(info.cached, info.total);
+  EXPECT_LT(info.active_anon, info.total);
+  EXPECT_LT(info.inactive_anon, info.total);
+  EXPECT_LT(info.active_file, info.total);
+  EXPECT_LT(info.inactive_file, info.total);
+
+#if defined(OS_CHROMEOS)
+  // Chrome OS exposes shmem.
+  EXPECT_GT(info.shmem, 0);
+  EXPECT_LT(info.shmem, info.total);
+  // Chrome unit tests are not run on actual Chrome OS hardware, so gem_objects
+  // and gem_size cannot be tested here.
+#endif
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST(ProcessMetricsTest, ParseProcStatCPU) {
+  // /proc/self/stat for a process running "top".
+  const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
+      "4202496 471 0 0 0 "
+      "12 16 0 0 "  // <- These are the goods.
+      "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
+      "4246868 140733983044336 18446744073709551615 140244213071219 "
+      "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
+  EXPECT_EQ(12 + 16, base::ParseProcStatCPU(kTopStat));
+
+  // cat /proc/self/stat on a random other machine I have.
+  const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
+      "0 142 0 0 0 "
+      "0 0 0 0 "  // <- No CPU, apparently.
+      "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
+      "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
+
+  EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
+
+  // Some weird long-running process with a weird name that I created for the
+  // purposes of this test.
+  const char kWeirdNameStat[] = "26115 (Hello) You ()))  ) R 24614 26115 24614"
+      " 34839 26115 4218880 227 0 0 0 "
+      "5186 11 0 0 "
+      "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 "
+      "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
+      "6295056 6295616 16519168 140735857770710 140735857770737 "
+      "140735857770737 140735857774557 0";
+  EXPECT_EQ(5186 + 11, base::ParseProcStatCPU(kWeirdNameStat));
+}
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// Disable on Android because base_unittests runs inside a Dalvik VM that
+// starts and stop threads (crbug.com/175563).
+#if defined(OS_LINUX)
+// http://crbug.com/396455
+TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
+  const base::ProcessHandle current = base::GetCurrentProcessHandle();
+  const int initial_threads = base::GetNumberOfThreads(current);
+  ASSERT_GT(initial_threads, 0);
+  const int kNumAdditionalThreads = 10;
+  {
+    scoped_ptr<base::Thread> my_threads[kNumAdditionalThreads];
+    for (int i = 0; i < kNumAdditionalThreads; ++i) {
+      my_threads[i].reset(new base::Thread("GetNumberOfThreadsTest"));
+      my_threads[i]->Start();
+      ASSERT_EQ(base::GetNumberOfThreads(current), initial_threads + 1 + i);
+    }
+  }
+  // The Thread destructor will stop them.
+  ASSERT_EQ(initial_threads, base::GetNumberOfThreads(current));
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/process/process_metrics_unittest_ios.cc b/base/process/process_metrics_unittest_ios.cc
new file mode 100644
index 0000000..3e1ca35
--- /dev/null
+++ b/base/process/process_metrics_unittest_ios.cc
@@ -0,0 +1,16 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ProcessMetricsTestIos, Memory) {
+  scoped_ptr<base::ProcessMetrics> process_metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+          base::GetCurrentProcessHandle()));
+
+  ASSERT_NE(0u, process_metrics->GetWorkingSetSize());
+}
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc
new file mode 100644
index 0000000..1dd97e6
--- /dev/null
+++ b/base/process/process_metrics_win.cc
@@ -0,0 +1,291 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <windows.h>
+#include <psapi.h>
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+
+namespace base {
+
+// System pagesize. This value remains constant on x86/64 architectures.
+const int PAGESIZE_KB = 4;
+
+ProcessMetrics::~ProcessMetrics() { }
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PagefileUsage;
+  }
+  return 0;
+}
+
+// Returns the peak space allocated for the pagefile, in bytes.
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PeakPagefileUsage;
+  }
+  return 0;
+}
+
+// Returns the current working set size, in bytes.
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.WorkingSetSize;
+  }
+  return 0;
+}
+
+// Returns the peak working set size, in bytes.
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PeakWorkingSetSize;
+  }
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
+  // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
+  // information is simply not available. Hence, we will return 0 on unsupported
+  // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
+  PROCESS_MEMORY_COUNTERS_EX pmcx;
+  if (private_bytes &&
+      GetProcessMemoryInfo(process_,
+                           reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx),
+                           sizeof(pmcx))) {
+    *private_bytes = pmcx.PrivateUsage;
+  }
+
+  if (shared_bytes) {
+    WorkingSetKBytes ws_usage;
+    if (!GetWorkingSetKBytes(&ws_usage))
+      return false;
+
+    *shared_bytes = ws_usage.shared * 1024;
+  }
+
+  return true;
+}
+
+void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
+  MEMORY_BASIC_INFORMATION mbi = {0};
+  size_t committed_private = 0;
+  size_t committed_mapped = 0;
+  size_t committed_image = 0;
+  void* base_address = NULL;
+  while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) ==
+      sizeof(mbi)) {
+    if (mbi.State == MEM_COMMIT) {
+      if (mbi.Type == MEM_PRIVATE) {
+        committed_private += mbi.RegionSize;
+      } else if (mbi.Type == MEM_MAPPED) {
+        committed_mapped += mbi.RegionSize;
+      } else if (mbi.Type == MEM_IMAGE) {
+        committed_image += mbi.RegionSize;
+      } else {
+        NOTREACHED();
+      }
+    }
+    void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize;
+    // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
+    // If we query 64bit processes in a 32bit process, VirtualQueryEx()
+    // returns such data.
+    if (new_base <= base_address) {
+      usage->image = 0;
+      usage->mapped = 0;
+      usage->priv = 0;
+      return;
+    }
+    base_address = new_base;
+  }
+  usage->image = committed_image / 1024;
+  usage->mapped = committed_mapped / 1024;
+  usage->priv = committed_private / 1024;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  size_t ws_private = 0;
+  size_t ws_shareable = 0;
+  size_t ws_shared = 0;
+
+  DCHECK(ws_usage);
+  memset(ws_usage, 0, sizeof(*ws_usage));
+
+  DWORD number_of_entries = 4096;  // Just a guess.
+  PSAPI_WORKING_SET_INFORMATION* buffer = NULL;
+  int retries = 5;
+  for (;;) {
+    DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
+                        (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
+
+    // if we can't expand the buffer, don't leak the previous
+    // contents or pass a NULL pointer to QueryWorkingSet
+    PSAPI_WORKING_SET_INFORMATION* new_buffer =
+        reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
+            realloc(buffer, buffer_size));
+    if (!new_buffer) {
+      free(buffer);
+      return false;
+    }
+    buffer = new_buffer;
+
+    // Call the function once to get number of items
+    if (QueryWorkingSet(process_, buffer, buffer_size))
+      break;  // Success
+
+    if (GetLastError() != ERROR_BAD_LENGTH) {
+      free(buffer);
+      return false;
+    }
+
+    number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
+
+    // Maybe some entries are being added right now. Increase the buffer to
+    // take that into account.
+    number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
+
+    if (--retries == 0) {
+      free(buffer);  // If we're looping, eventually fail.
+      return false;
+    }
+  }
+
+  // On windows 2000 the function returns 1 even when the buffer is too small.
+  // The number of entries that we are going to parse is the minimum between the
+  // size we allocated and the real number of entries.
+  number_of_entries =
+      std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
+  for (unsigned int i = 0; i < number_of_entries; i++) {
+    if (buffer->WorkingSetInfo[i].Shared) {
+      ws_shareable++;
+      if (buffer->WorkingSetInfo[i].ShareCount > 1)
+        ws_shared++;
+    } else {
+      ws_private++;
+    }
+  }
+
+  ws_usage->priv = ws_private * PAGESIZE_KB;
+  ws_usage->shareable = ws_shareable * PAGESIZE_KB;
+  ws_usage->shared = ws_shared * PAGESIZE_KB;
+  free(buffer);
+  return true;
+}
+
+static uint64 FileTimeToUTC(const FILETIME& ftime) {
+  LARGE_INTEGER li;
+  li.LowPart = ftime.dwLowDateTime;
+  li.HighPart = ftime.dwHighDateTime;
+  return li.QuadPart;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  FILETIME creation_time;
+  FILETIME exit_time;
+  FILETIME kernel_time;
+  FILETIME user_time;
+
+  if (!GetProcessTimes(process_, &creation_time, &exit_time,
+                       &kernel_time, &user_time)) {
+    // We don't assert here because in some cases (such as in the Task Manager)
+    // we may call this function on a process that has just exited but we have
+    // not yet received the notification.
+    return 0;
+  }
+  int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
+                        processor_count_;
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_system_time_ == 0) {
+    // First call, just set the last values.
+    last_system_time_ = system_time;
+    last_cpu_time_ = time;
+    return 0;
+  }
+
+  int64 system_time_delta = system_time - last_system_time_;
+  // FILETIME is in 100-nanosecond units, so this needs microseconds times 10.
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds() * 10;
+  DCHECK_NE(0U, time_delta);
+  if (time_delta == 0)
+    return 0;
+
+  // We add time_delta / 2 so the result is rounded.
+  int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
+                             time_delta);
+
+  last_system_time_ = system_time;
+  last_cpu_time_ = time;
+
+  return cpu;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return GetProcessIoCounters(process_, io_counters) != FALSE;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      processor_count_(base::SysInfo::NumberOfProcessors()),
+      last_system_time_(0) {
+}
+
+// GetPerformanceInfo is not available on WIN2K.  So we'll
+// load it on-the-fly.
+const wchar_t kPsapiDllName[] = L"psapi.dll";
+typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
+    PPERFORMANCE_INFORMATION pPerformanceInformation,
+    DWORD cb);
+
+// Beware of races if called concurrently from multiple threads.
+static BOOL InternalGetPerformanceInfo(
+    PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) {
+  static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL;
+  if (!GetPerformanceInfo_func) {
+    HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName);
+    if (psapi_dll)
+      GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>(
+          GetProcAddress(psapi_dll, "GetPerformanceInfo"));
+
+    if (!GetPerformanceInfo_func) {
+      // The function could be loaded!
+      memset(pPerformanceInformation, 0, cb);
+      return FALSE;
+    }
+  }
+  return GetPerformanceInfo_func(pPerformanceInformation, cb);
+}
+
+size_t GetSystemCommitCharge() {
+  // Get the System Page Size.
+  SYSTEM_INFO system_info;
+  GetSystemInfo(&system_info);
+
+  PERFORMANCE_INFORMATION info;
+  if (!InternalGetPerformanceInfo(&info, sizeof(info))) {
+    DLOG(ERROR) << "Failed to fetch internal performance info.";
+    return 0;
+  }
+  return (info.CommitTotal * system_info.dwPageSize) / 1024;
+}
+
+size_t GetPageSize() {
+  return PAGESIZE_KB * 1024;
+}
+
+}  // namespace base
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
new file mode 100644
index 0000000..a7d16f8
--- /dev/null
+++ b/base/process/process_posix.cc
@@ -0,0 +1,377 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/kill.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#if defined(OS_MACOSX)
+#include <sys/event.h>
+#endif
+
+namespace {
+
+#if !defined(OS_NACL_NONSFI)
+
+bool WaitpidWithTimeout(base::ProcessHandle handle,
+                        int* status,
+                        base::TimeDelta wait) {
+  // This POSIX version of this function only guarantees that we wait no less
+  // than |wait| for the process to exit.  The child process may
+  // exit sometime before the timeout has ended but we may still block for up
+  // to 256 milliseconds after the fact.
+  //
+  // waitpid() has no direct support on POSIX for specifying a timeout, you can
+  // either ask it to block indefinitely or return immediately (WNOHANG).
+  // When a child process terminates a SIGCHLD signal is sent to the parent.
+  // Catching this signal would involve installing a signal handler which may
+  // affect other parts of the application and would be difficult to debug.
+  //
+  // Our strategy is to call waitpid() once up front to check if the process
+  // has already exited, otherwise to loop for |wait|, sleeping for
+  // at most 256 milliseconds each time using usleep() and then calling
+  // waitpid().  The amount of time we sleep starts out at 1 milliseconds, and
+  // we double it every 4 sleep cycles.
+  //
+  // usleep() is speced to exit if a signal is received for which a handler
+  // has been installed.  This means that when a SIGCHLD is sent, it will exit
+  // depending on behavior external to this function.
+  //
+  // This function is used primarily for unit tests, if we want to use it in
+  // the application itself it would probably be best to examine other routes.
+
+  if (wait == base::TimeDelta::Max()) {
+    return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
+  }
+
+  pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
+  static const int64 kMaxSleepInMicroseconds = 1 << 18;  // ~256 milliseconds.
+  int64 max_sleep_time_usecs = 1 << 10;  // ~1 milliseconds.
+  int64 double_sleep_time = 0;
+
+  // If the process hasn't exited yet, then sleep and try again.
+  base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait;
+  while (ret_pid == 0) {
+    base::TimeTicks now = base::TimeTicks::Now();
+    if (now > wakeup_time)
+      break;
+    // Guaranteed to be non-negative!
+    int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
+    // Sleep for a bit while we wait for the process to finish.
+    if (sleep_time_usecs > max_sleep_time_usecs)
+      sleep_time_usecs = max_sleep_time_usecs;
+
+    // usleep() will return 0 and set errno to EINTR on receipt of a signal
+    // such as SIGCHLD.
+    usleep(sleep_time_usecs);
+    ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
+
+    if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
+        (double_sleep_time++ % 4 == 0)) {
+      max_sleep_time_usecs *= 2;
+    }
+  }
+
+  return ret_pid > 0;
+}
+
+#if defined(OS_MACOSX)
+// Using kqueue on Mac so that we can wait on non-child processes.
+// We can't use kqueues on child processes because we need to reap
+// our own children using wait.
+static bool WaitForSingleNonChildProcess(base::ProcessHandle handle,
+                                         base::TimeDelta wait) {
+  DCHECK_GT(handle, 0);
+  DCHECK_GT(wait, base::TimeDelta());
+
+  base::ScopedFD kq(kqueue());
+  if (!kq.is_valid()) {
+    DPLOG(ERROR) << "kqueue";
+    return false;
+  }
+
+  struct kevent change = {0};
+  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
+  if (result == -1) {
+    if (errno == ESRCH) {
+      // If the process wasn't found, it must be dead.
+      return true;
+    }
+
+    DPLOG(ERROR) << "kevent (setup " << handle << ")";
+    return false;
+  }
+
+  // Keep track of the elapsed time to be able to restart kevent if it's
+  // interrupted.
+  bool wait_forever = (wait == base::TimeDelta::Max());
+  base::TimeDelta remaining_delta;
+  base::TimeTicks deadline;
+  if (!wait_forever) {
+    remaining_delta = wait;
+    deadline = base::TimeTicks::Now() + remaining_delta;
+  }
+
+  result = -1;
+  struct kevent event = {0};
+
+  while (wait_forever || remaining_delta > base::TimeDelta()) {
+    struct timespec remaining_timespec;
+    struct timespec* remaining_timespec_ptr;
+    if (wait_forever) {
+      remaining_timespec_ptr = NULL;
+    } else {
+      remaining_timespec = remaining_delta.ToTimeSpec();
+      remaining_timespec_ptr = &remaining_timespec;
+    }
+
+    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
+
+    if (result == -1 && errno == EINTR) {
+      if (!wait_forever) {
+        remaining_delta = deadline - base::TimeTicks::Now();
+      }
+      result = 0;
+    } else {
+      break;
+    }
+  }
+
+  if (result < 0) {
+    DPLOG(ERROR) << "kevent (wait " << handle << ")";
+    return false;
+  } else if (result > 1) {
+    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
+                << result;
+    return false;
+  } else if (result == 0) {
+    // Timed out.
+    return false;
+  }
+
+  DCHECK_EQ(result, 1);
+
+  if (event.filter != EVFILT_PROC ||
+      (event.fflags & NOTE_EXIT) == 0 ||
+      event.ident != static_cast<uintptr_t>(handle)) {
+    DLOG(ERROR) << "kevent (wait " << handle
+                << "): unexpected event: filter=" << event.filter
+                << ", fflags=" << event.fflags
+                << ", ident=" << event.ident;
+    return false;
+  }
+
+  return true;
+}
+#endif  // OS_MACOSX
+
+bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle,
+                                int* exit_code,
+                                base::TimeDelta timeout) {
+  base::ProcessHandle parent_pid = base::GetParentProcessId(handle);
+  base::ProcessHandle our_pid = base::GetCurrentProcessHandle();
+  if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+    // On Mac we can wait on non child processes.
+    return WaitForSingleNonChildProcess(handle, timeout);
+#else
+    // Currently on Linux we can't handle non child processes.
+    NOTIMPLEMENTED();
+#endif  // OS_MACOSX
+  }
+
+  int status;
+  if (!WaitpidWithTimeout(handle, &status, timeout))
+    return false;
+  if (WIFSIGNALED(status)) {
+    *exit_code = -1;
+    return true;
+  }
+  if (WIFEXITED(status)) {
+    *exit_code = WEXITSTATUS(status);
+    return true;
+  }
+  return false;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace
+
+namespace base {
+
+Process::Process(ProcessHandle handle) : process_(handle) {
+}
+
+Process::~Process() {
+}
+
+Process::Process(RValue other)
+    : process_(other.object->process_) {
+  other.object->Close();
+}
+
+Process& Process::operator=(RValue other) {
+  if (this != other.object) {
+    process_ = other.object->process_;
+    other.object->Close();
+  }
+  return *this;
+}
+
+// static
+Process Process::Current() {
+  return Process(GetCurrentProcessHandle());
+}
+
+// static
+Process Process::Open(ProcessId pid) {
+  if (pid == GetCurrentProcId())
+    return Current();
+
+  // On POSIX process handles are the same as PIDs.
+  return Process(pid);
+}
+
+// static
+Process Process::OpenWithExtraPrivileges(ProcessId pid) {
+  // On POSIX there are no privileges to set.
+  return Open(pid);
+}
+
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+  DCHECK_NE(handle, GetCurrentProcessHandle());
+  return Process(handle);
+}
+
+#if !defined(OS_LINUX)
+// static
+bool Process::CanBackgroundProcesses() {
+  return false;
+}
+#endif  // !defined(OS_LINUX)
+
+bool Process::IsValid() const {
+  return process_ != kNullProcessHandle;
+}
+
+ProcessHandle Process::Handle() const {
+  return process_;
+}
+
+Process Process::Duplicate() const {
+  if (is_current())
+    return Current();
+
+  return Process(process_);
+}
+
+ProcessId Process::Pid() const {
+  DCHECK(IsValid());
+  return GetProcId(process_);
+}
+
+bool Process::is_current() const {
+  return process_ == GetCurrentProcessHandle();
+}
+
+void Process::Close() {
+  process_ = kNullProcessHandle;
+  // if the process wasn't terminated (so we waited) or the state
+  // wasn't already collected w/ a wait from process_utils, we're gonna
+  // end up w/ a zombie when it does finally exit.
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool Process::Terminate(int exit_code, bool wait) const {
+  // result_code isn't supportable.
+  DCHECK(IsValid());
+  DCHECK_GT(process_, 1);
+  bool result = kill(process_, SIGTERM) == 0;
+  if (result && wait) {
+    int tries = 60;
+
+    if (RunningOnValgrind()) {
+      // Wait for some extra time when running under Valgrind since the child
+      // processes may take some time doing leak checking.
+      tries *= 2;
+    }
+
+    unsigned sleep_ms = 4;
+
+    // The process may not end immediately due to pending I/O
+    bool exited = false;
+    while (tries-- > 0) {
+      pid_t pid = HANDLE_EINTR(waitpid(process_, NULL, WNOHANG));
+      if (pid == process_) {
+        exited = true;
+        break;
+      }
+      if (pid == -1) {
+        if (errno == ECHILD) {
+          // The wait may fail with ECHILD if another process also waited for
+          // the same pid, causing the process state to get cleaned up.
+          exited = true;
+          break;
+        }
+        DPLOG(ERROR) << "Error waiting for process " << process_;
+      }
+
+      usleep(sleep_ms * 1000);
+      const unsigned kMaxSleepMs = 1000;
+      if (sleep_ms < kMaxSleepMs)
+        sleep_ms *= 2;
+    }
+
+    // If we're waiting and the child hasn't died by now, force it
+    // with a SIGKILL.
+    if (!exited)
+      result = kill(process_, SIGKILL) == 0;
+  }
+
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process " << process_;
+
+  return result;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool Process::WaitForExit(int* exit_code) {
+  return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+  return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
+}
+
+#if !defined(OS_LINUX)
+bool Process::IsProcessBackgrounded() const {
+  // See SetProcessBackgrounded().
+  DCHECK(IsValid());
+  return false;
+}
+
+bool Process::SetProcessBackgrounded(bool value) {
+  // POSIX only allows lowering the priority of a process, so if we
+  // were to lower it we wouldn't be able to raise it back to its initial
+  // priority.
+  DCHECK(IsValid());
+  return false;
+}
+#endif  // !defined(OS_LINUX)
+
+int Process::GetPriority() const {
+  DCHECK(IsValid());
+  return getpriority(PRIO_PROCESS, process_);
+}
+
+}  // namespace base
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
new file mode 100644
index 0000000..ba8e4e6
--- /dev/null
+++ b/base/process/process_unittest.cc
@@ -0,0 +1,204 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process.h"
+
+#include "base/process/kill.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace {
+
+#if defined(OS_WIN)
+const int kExpectedStillRunningExitCode = 0x102;
+#else
+const int kExpectedStillRunningExitCode = 0;
+#endif
+
+}  // namespace
+
+namespace base {
+
+class ProcessTest : public MultiProcessTest {
+};
+
+TEST_F(ProcessTest, Create) {
+  Process process(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+  ASSERT_FALSE(process.is_current());
+  process.Close();
+  ASSERT_FALSE(process.IsValid());
+}
+
+TEST_F(ProcessTest, CreateCurrent) {
+  Process process = Process::Current();
+  ASSERT_TRUE(process.IsValid());
+  ASSERT_TRUE(process.is_current());
+  process.Close();
+  ASSERT_FALSE(process.IsValid());
+}
+
+TEST_F(ProcessTest, Move) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  EXPECT_TRUE(process1.IsValid());
+
+  Process process2;
+  EXPECT_FALSE(process2.IsValid());
+
+  process2 = process1.Pass();
+  EXPECT_TRUE(process2.IsValid());
+  EXPECT_FALSE(process1.IsValid());
+  EXPECT_FALSE(process2.is_current());
+
+  Process process3 = Process::Current();
+  process2 = process3.Pass();
+  EXPECT_TRUE(process2.is_current());
+  EXPECT_TRUE(process2.IsValid());
+  EXPECT_FALSE(process3.IsValid());
+}
+
+TEST_F(ProcessTest, Duplicate) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = process1.Duplicate();
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.Pid(), process2.Pid());
+  EXPECT_FALSE(process1.is_current());
+  EXPECT_FALSE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
+TEST_F(ProcessTest, DuplicateCurrent) {
+  Process process1 = Process::Current();
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = process1.Duplicate();
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.Pid(), process2.Pid());
+  EXPECT_TRUE(process1.is_current());
+  EXPECT_TRUE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
+TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle());
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.Pid(), process2.Pid());
+  EXPECT_FALSE(process1.is_current());
+  EXPECT_FALSE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
+MULTIPROCESS_TEST_MAIN(SleepyChildProcess) {
+  PlatformThread::Sleep(TestTimeouts::action_max_timeout());
+  return 0;
+}
+
+TEST_F(ProcessTest, Terminate) {
+  Process process(SpawnChild("SleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
+            GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  exit_code = kDummyExitCode;
+  int kExpectedExitCode = 250;
+  process.Terminate(kExpectedExitCode, false);
+  process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+                                 &exit_code);
+
+  EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING,
+            GetTerminationStatus(process.Handle(), &exit_code));
+#if !defined(OS_POSIX)
+  // The POSIX implementation actually ignores the exit_code.
+  EXPECT_EQ(kExpectedExitCode, exit_code);
+#endif
+}
+
+MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) {
+  PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10);
+  return 0;
+}
+
+TEST_F(ProcessTest, WaitForExit) {
+  Process process(SpawnChild("FastSleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(0, exit_code);
+}
+
+TEST_F(ProcessTest, WaitForExitWithTimeout) {
+  Process process(SpawnChild("SleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  TimeDelta timeout = TestTimeouts::tiny_timeout();
+  EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code));
+  EXPECT_EQ(kDummyExitCode, exit_code);
+
+  process.Terminate(kDummyExitCode, false);
+}
+
+// Ensure that the priority of a process is restored correctly after
+// backgrounding and restoring.
+// Note: a platform may not be willing or able to lower the priority of
+// a process. The calls to SetProcessBackground should be noops then.
+TEST_F(ProcessTest, SetProcessBackgrounded) {
+  Process process(SpawnChild("SimpleChildProcess"));
+  int old_priority = process.GetPriority();
+#if defined(OS_WIN)
+  EXPECT_TRUE(process.SetProcessBackgrounded(true));
+  EXPECT_TRUE(process.IsProcessBackgrounded());
+  EXPECT_TRUE(process.SetProcessBackgrounded(false));
+  EXPECT_FALSE(process.IsProcessBackgrounded());
+#else
+  process.SetProcessBackgrounded(true);
+  process.SetProcessBackgrounded(false);
+#endif
+  int new_priority = process.GetPriority();
+  EXPECT_EQ(old_priority, new_priority);
+}
+
+// Same as SetProcessBackgrounded but to this very process. It uses
+// a different code path at least for Windows.
+TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
+  Process process = Process::Current();
+  int old_priority = process.GetPriority();
+#if defined(OS_WIN)
+  EXPECT_TRUE(process.SetProcessBackgrounded(true));
+  EXPECT_TRUE(process.IsProcessBackgrounded());
+  EXPECT_TRUE(process.SetProcessBackgrounded(false));
+  EXPECT_FALSE(process.IsProcessBackgrounded());
+#else
+  process.SetProcessBackgrounded(true);
+  process.SetProcessBackgrounded(false);
+#endif
+  int new_priority = process.GetPriority();
+  EXPECT_EQ(old_priority, new_priority);
+}
+
+}  // namespace base
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
new file mode 100644
index 0000000..11d8874
--- /dev/null
+++ b/base/process/process_util_unittest.cc
@@ -0,0 +1,1067 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <limits>
+
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/process/memory.h"
+#include "base/process/process.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_LINUX)
+#include <malloc.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#endif
+#if defined(OS_POSIX)
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/win/windows_version.h"
+#endif
+#if defined(OS_MACOSX)
+#include <mach/vm_param.h>
+#include <malloc/malloc.h>
+#include "base/mac/mac_util.h"
+#endif
+
+using base::FilePath;
+
+namespace {
+
+#if defined(OS_ANDROID)
+const char kShellPath[] = "/system/bin/sh";
+const char kPosixShell[] = "sh";
+#else
+const char kShellPath[] = "/bin/sh";
+const char kPosixShell[] = "bash";
+#endif
+
+const char kSignalFileSlow[] = "SlowChildProcess.die";
+const char kSignalFileKill[] = "KilledChildProcess.die";
+
+#if defined(OS_WIN)
+const int kExpectedStillRunningExitCode = 0x102;
+const int kExpectedKilledExitCode = 1;
+#else
+const int kExpectedStillRunningExitCode = 0;
+#endif
+
+// Sleeps until file filename is created.
+void WaitToDie(const char* filename) {
+  FILE* fp;
+  do {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    fp = fopen(filename, "r");
+  } while (!fp);
+  fclose(fp);
+}
+
+// Signals children they should die now.
+void SignalChildren(const char* filename) {
+  FILE* fp = fopen(filename, "w");
+  fclose(fp);
+}
+
+// Using a pipe to the child to wait for an event was considered, but
+// there were cases in the past where pipes caused problems (other
+// libraries closing the fds, child deadlocking). This is a simple
+// case, so it's not worth the risk.  Using wait loops is discouraged
+// in most instances.
+base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
+                                                int* exit_code) {
+  // Now we wait until the result is something other than STILL_RUNNING.
+  base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
+  const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(20);
+  base::TimeDelta waited;
+  do {
+    status = base::GetTerminationStatus(handle, exit_code);
+    base::PlatformThread::Sleep(kInterval);
+    waited += kInterval;
+  } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
+           waited < TestTimeouts::action_max_timeout());
+
+  return status;
+}
+
+}  // namespace
+
+class ProcessUtilTest : public base::MultiProcessTest {
+ public:
+#if defined(OS_POSIX)
+  // Spawn a child process that counts how many file descriptors are open.
+  int CountOpenFDsInChild();
+#endif
+  // Converts the filename to a platform specific filepath.
+  // On Android files can not be created in arbitrary directories.
+  static std::string GetSignalFilePath(const char* filename);
+};
+
+std::string ProcessUtilTest::GetSignalFilePath(const char* filename) {
+#if !defined(OS_ANDROID)
+  return filename;
+#else
+  FilePath tmp_dir;
+  PathService::Get(base::DIR_CACHE, &tmp_dir);
+  tmp_dir = tmp_dir.Append(filename);
+  return tmp_dir.value();
+#endif
+}
+
+MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
+  return 0;
+}
+
+// TODO(viettrungluu): This should be in a "MultiProcessTestTest".
+TEST_F(ProcessUtilTest, SpawnChild) {
+  base::Process process = SpawnChild("SimpleChildProcess");
+  ASSERT_TRUE(process.IsValid());
+  int exit_code;
+  EXPECT_TRUE(process.WaitForExitWithTimeout(
+                  TestTimeouts::action_max_timeout(), &exit_code));
+}
+
+MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileSlow).c_str());
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, KillSlowChild) {
+  const std::string signal_file =
+      ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("SlowChildProcess");
+  ASSERT_TRUE(process.IsValid());
+  SignalChildren(signal_file.c_str());
+  int exit_code;
+  EXPECT_TRUE(process.WaitForExitWithTimeout(
+                  TestTimeouts::action_max_timeout(), &exit_code));
+  remove(signal_file.c_str());
+}
+
+// Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058
+TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) {
+  const std::string signal_file =
+      ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("SlowChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
+  EXPECT_EQ(0, exit_code);
+  remove(signal_file.c_str());
+}
+
+#if defined(OS_WIN)
+// TODO(cpu): figure out how to test this in other platforms.
+TEST_F(ProcessUtilTest, GetProcId) {
+  base::ProcessId id1 = base::GetProcId(GetCurrentProcess());
+  EXPECT_NE(0ul, id1);
+  base::Process process = SpawnChild("SimpleChildProcess");
+  ASSERT_TRUE(process.IsValid());
+  base::ProcessId id2 = process.Pid();
+  EXPECT_NE(0ul, id2);
+  EXPECT_NE(id1, id2);
+}
+#endif
+
+#if !defined(OS_MACOSX)
+// This test is disabled on Mac, since it's flaky due to ReportCrash
+// taking a variable amount of time to parse and load the debug and
+// symbol data for this unit test's executable before firing the
+// signal handler.
+//
+// TODO(gspencer): turn this test process into a very small program
+// with no symbols (instead of using the multiprocess testing
+// framework) to reduce the ReportCrash overhead.
+const char kSignalFileCrash[] = "CrashingChildProcess.die";
+
+MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str());
+#if defined(OS_POSIX)
+  // Have to disable to signal handler for segv so we can get a crash
+  // instead of an abnormal termination through the crash dump handler.
+  ::signal(SIGSEGV, SIG_DFL);
+#endif
+  // Make this process have a segmentation fault.
+  volatile int* oops = NULL;
+  *oops = 0xDEAD;
+  return 1;
+}
+
+// This test intentionally crashes, so we don't need to run it under
+// AddressSanitizer.
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+#define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash
+#else
+#define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileCrash);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("CrashingChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
+
+#if defined(OS_WIN)
+  EXPECT_EQ(0xc0000005, exit_code);
+#elif defined(OS_POSIX)
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGSEGV, signal);
+#endif
+
+  // Reset signal handlers back to "normal".
+  base::debug::EnableInProcessStackDumping();
+  remove(signal_file.c_str());
+}
+#endif  // !defined(OS_MACOSX)
+
+MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str());
+#if defined(OS_WIN)
+  // Kill ourselves.
+  HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
+  ::TerminateProcess(handle, kExpectedKilledExitCode);
+#elif defined(OS_POSIX)
+  // Send a SIGKILL to this process, just like the OOM killer would.
+  ::kill(getpid(), SIGKILL);
+#endif
+  return 1;
+}
+
+TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("KilledChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+#if defined(OS_WIN)
+  EXPECT_EQ(kExpectedKilledExitCode, exit_code);
+#elif defined(OS_POSIX)
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGKILL, signal);
+#endif
+  remove(signal_file.c_str());
+}
+
+#if defined(OS_WIN)
+// TODO(estade): if possible, port this test.
+TEST_F(ProcessUtilTest, GetAppOutput) {
+  // Let's create a decently long message.
+  std::string message;
+  for (int i = 0; i < 1025; i++) {  // 1025 so it does not end on a kilo-byte
+                                    // boundary.
+    message += "Hello!";
+  }
+  // cmd.exe's echo always adds a \r\n to its output.
+  std::string expected(message);
+  expected += "\r\n";
+
+  FilePath cmd(L"cmd.exe");
+  base::CommandLine cmd_line(cmd);
+  cmd_line.AppendArg("/c");
+  cmd_line.AppendArg("echo " + message + "");
+  std::string output;
+  ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
+  EXPECT_EQ(expected, output);
+
+  // Let's make sure stderr is ignored.
+  base::CommandLine other_cmd_line(cmd);
+  other_cmd_line.AppendArg("/c");
+  // http://msdn.microsoft.com/library/cc772622.aspx
+  cmd_line.AppendArg("echo " + message + " >&2");
+  output.clear();
+  ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output));
+  EXPECT_EQ("", output);
+}
+
+// TODO(estade): if possible, port this test.
+TEST_F(ProcessUtilTest, LaunchAsUser) {
+  base::UserTokenHandle token;
+  ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
+  base::LaunchOptions options;
+  options.as_user = token;
+  EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"),
+                                  options).IsValid());
+}
+
+static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle";
+
+MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) {
+  std::string handle_value_string =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          kEventToTriggerHandleSwitch);
+  CHECK(!handle_value_string.empty());
+
+  uint64 handle_value_uint64;
+  CHECK(base::StringToUint64(handle_value_string, &handle_value_uint64));
+  // Give ownership of the handle to |event|.
+  base::WaitableEvent event(base::win::ScopedHandle(
+      reinterpret_cast<HANDLE>(handle_value_uint64)));
+
+  event.Signal();
+
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, InheritSpecifiedHandles) {
+  // Manually create the event, so that it can be inheritable.
+  SECURITY_ATTRIBUTES security_attributes = {};
+  security_attributes.nLength = static_cast<DWORD>(sizeof(security_attributes));
+  security_attributes.lpSecurityDescriptor = NULL;
+  security_attributes.bInheritHandle = true;
+
+  // Takes ownership of the event handle.
+  base::WaitableEvent event(base::win::ScopedHandle(
+      CreateEvent(&security_attributes, true, false, NULL)));
+  base::HandlesToInheritVector handles_to_inherit;
+  handles_to_inherit.push_back(event.handle());
+  base::LaunchOptions options;
+  options.handles_to_inherit = &handles_to_inherit;
+
+  base::CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess");
+  cmd_line.AppendSwitchASCII(kEventToTriggerHandleSwitch,
+      base::Uint64ToString(reinterpret_cast<uint64>(event.handle())));
+
+  // This functionality actually requires Vista or later. Make sure that it
+  // fails properly on XP.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    EXPECT_FALSE(base::LaunchProcess(cmd_line, options).IsValid());
+    return;
+  }
+
+  // Launch the process and wait for it to trigger the event.
+  ASSERT_TRUE(base::LaunchProcess(cmd_line, options).IsValid());
+  EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX)
+
+namespace {
+
+// Returns the maximum number of files that a process can have open.
+// Returns 0 on error.
+int GetMaxFilesOpenInProcess() {
+  struct rlimit rlim;
+  if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+    return 0;
+  }
+
+  // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
+  // which are all 32 bits on the supported platforms.
+  rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
+  if (rlim.rlim_cur > max_int) {
+    return max_int;
+  }
+
+  return rlim.rlim_cur;
+}
+
+const int kChildPipe = 20;  // FD # for write end of pipe in child process.
+
+#if defined(OS_MACOSX)
+
+// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h>
+#if !defined(_GUARDID_T)
+#define _GUARDID_T
+typedef __uint64_t guardid_t;
+#endif  // _GUARDID_T
+
+// From .../MacOSX10.9.sdk/usr/include/sys/syscall.h
+#if !defined(SYS_change_fdguard_np)
+#define SYS_change_fdguard_np 444
+#endif
+
+// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h>
+#if !defined(GUARD_DUP)
+#define GUARD_DUP (1u << 1)
+#endif
+
+// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/kern/kern_guarded.c?txt>
+//
+// Atomically replaces |guard|/|guardflags| with |nguard|/|nguardflags| on |fd|.
+int change_fdguard_np(int fd,
+                      const guardid_t *guard, u_int guardflags,
+                      const guardid_t *nguard, u_int nguardflags,
+                      int *fdflagsp) {
+  return syscall(SYS_change_fdguard_np, fd, guard, guardflags,
+                 nguard, nguardflags, fdflagsp);
+}
+
+// Attempt to set a file-descriptor guard on |fd|.  In case of success, remove
+// it and return |true| to indicate that it can be guarded.  Returning |false|
+// means either that |fd| is guarded by some other code, or more likely EBADF.
+//
+// Starting with 10.9, libdispatch began setting GUARD_DUP on a file descriptor.
+// Unfortunately, it is spun up as part of +[NSApplication initialize], which is
+// not really something that Chromium can avoid using on OSX.  See
+// <http://crbug.com/338157>.  This function allows querying whether the file
+// descriptor is guarded before attempting to close it.
+bool CanGuardFd(int fd) {
+  // The syscall is first provided in 10.9/Mavericks.
+  if (!base::mac::IsOSMavericksOrLater())
+    return true;
+
+  // Saves the original flags to reset later.
+  int original_fdflags = 0;
+
+  // This can be any value at all, it just has to match up between the two
+  // calls.
+  const guardid_t kGuard = 15;
+
+  // Attempt to change the guard.  This can fail with EBADF if the file
+  // descriptor is bad, or EINVAL if the fd already has a guard set.
+  int ret =
+      change_fdguard_np(fd, NULL, 0, &kGuard, GUARD_DUP, &original_fdflags);
+  if (ret == -1)
+    return false;
+
+  // Remove the guard.  It should not be possible to fail in removing the guard
+  // just added.
+  ret = change_fdguard_np(fd, &kGuard, GUARD_DUP, NULL, 0, &original_fdflags);
+  DPCHECK(ret == 0);
+
+  return true;
+}
+#endif  // OS_MACOSX
+
+}  // namespace
+
+MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
+  // This child process counts the number of open FDs, it then writes that
+  // number out to a pipe connected to the parent.
+  int num_open_files = 0;
+  int write_pipe = kChildPipe;
+  int max_files = GetMaxFilesOpenInProcess();
+  for (int i = STDERR_FILENO + 1; i < max_files; i++) {
+#if defined(OS_MACOSX)
+    // Ignore guarded or invalid file descriptors.
+    if (!CanGuardFd(i))
+      continue;
+#endif
+
+    if (i != kChildPipe) {
+      int fd;
+      if ((fd = HANDLE_EINTR(dup(i))) != -1) {
+        close(fd);
+        num_open_files += 1;
+      }
+    }
+  }
+
+  int written = HANDLE_EINTR(write(write_pipe, &num_open_files,
+                                   sizeof(num_open_files)));
+  DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files));
+  int ret = IGNORE_EINTR(close(write_pipe));
+  DPCHECK(ret == 0);
+
+  return 0;
+}
+
+int ProcessUtilTest::CountOpenFDsInChild() {
+  int fds[2];
+  if (pipe(fds) < 0)
+    NOTREACHED();
+
+  base::FileHandleMappingVector fd_mapping_vec;
+  fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe));
+  base::LaunchOptions options;
+  options.fds_to_remap = &fd_mapping_vec;
+  base::Process process =
+      SpawnChildWithOptions("ProcessUtilsLeakFDChildProcess", options);
+  CHECK(process.IsValid());
+  int ret = IGNORE_EINTR(close(fds[1]));
+  DPCHECK(ret == 0);
+
+  // Read number of open files in client process from pipe;
+  int num_open_files = -1;
+  ssize_t bytes_read =
+      HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files)));
+  CHECK_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files)));
+
+#if defined(THREAD_SANITIZER)
+  // Compiler-based ThreadSanitizer makes this test slow.
+  base::TimeDelta timeout = base::TimeDelta::FromSeconds(3);
+#else
+  base::TimeDelta timeout = base::TimeDelta::FromSeconds(1);
+#endif
+  int exit_code;
+  CHECK(process.WaitForExitWithTimeout(timeout, &exit_code));
+  ret = IGNORE_EINTR(close(fds[0]));
+  DPCHECK(ret == 0);
+
+  return num_open_files;
+}
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
+// ProcessUtilTest.FDRemapping is flaky when ran under xvfb-run on Precise.
+// The problem is 100% reproducible with both ASan and TSan.
+// See http://crbug.com/136720.
+#define MAYBE_FDRemapping DISABLED_FDRemapping
+#else
+#define MAYBE_FDRemapping FDRemapping
+#endif
+TEST_F(ProcessUtilTest, MAYBE_FDRemapping) {
+  int fds_before = CountOpenFDsInChild();
+
+  // open some dummy fds to make sure they don't propagate over to the
+  // child process.
+  int dev_null = open("/dev/null", O_RDONLY);
+  int sockets[2];
+  socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
+
+  int fds_after = CountOpenFDsInChild();
+
+  ASSERT_EQ(fds_after, fds_before);
+
+  int ret;
+  ret = IGNORE_EINTR(close(sockets[0]));
+  DPCHECK(ret == 0);
+  ret = IGNORE_EINTR(close(sockets[1]));
+  DPCHECK(ret == 0);
+  ret = IGNORE_EINTR(close(dev_null));
+  DPCHECK(ret == 0);
+}
+
+namespace {
+
+std::string TestLaunchProcess(const std::vector<std::string>& args,
+                              const base::EnvironmentMap& env_changes,
+                              const bool clear_environ,
+                              const int clone_flags) {
+  base::FileHandleMappingVector fds_to_remap;
+
+  int fds[2];
+  PCHECK(pipe(fds) == 0);
+
+  fds_to_remap.push_back(std::make_pair(fds[1], 1));
+  base::LaunchOptions options;
+  options.wait = true;
+  options.environ = env_changes;
+  options.clear_environ = clear_environ;
+  options.fds_to_remap = &fds_to_remap;
+#if defined(OS_LINUX)
+  options.clone_flags = clone_flags;
+#else
+  CHECK_EQ(0, clone_flags);
+#endif  // OS_LINUX
+  EXPECT_TRUE(base::LaunchProcess(args, options).IsValid());
+  PCHECK(IGNORE_EINTR(close(fds[1])) == 0);
+
+  char buf[512];
+  const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
+
+  PCHECK(IGNORE_EINTR(close(fds[0])) == 0);
+
+  return std::string(buf, n);
+}
+
+const char kLargeString[] =
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789";
+
+}  // namespace
+
+TEST_F(ProcessUtilTest, LaunchProcess) {
+  base::EnvironmentMap env_changes;
+  std::vector<std::string> echo_base_test;
+  echo_base_test.push_back(kPosixShell);
+  echo_base_test.push_back("-c");
+  echo_base_test.push_back("echo $BASE_TEST");
+
+  std::vector<std::string> print_env;
+  print_env.push_back("/usr/bin/env");
+  const int no_clone_flags = 0;
+  const bool no_clear_environ = false;
+
+  const char kBaseTest[] = "BASE_TEST";
+
+  env_changes[kBaseTest] = "bar";
+  EXPECT_EQ("bar\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+  env_changes.clear();
+
+  EXPECT_EQ(0, setenv(kBaseTest, "testing", 1 /* override */));
+  EXPECT_EQ("testing\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes[kBaseTest] = std::string();
+  EXPECT_EQ("\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes[kBaseTest] = "foo";
+  EXPECT_EQ("foo\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes.clear();
+  EXPECT_EQ(0, setenv(kBaseTest, kLargeString, 1 /* override */));
+  EXPECT_EQ(std::string(kLargeString) + "\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes[kBaseTest] = "wibble";
+  EXPECT_EQ("wibble\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+#if defined(OS_LINUX)
+  // Test a non-trival value for clone_flags.
+  // Don't test on Valgrind as it has limited support for clone().
+  if (!RunningOnValgrind()) {
+    EXPECT_EQ("wibble\n", TestLaunchProcess(echo_base_test, env_changes,
+                                            no_clear_environ, CLONE_FS));
+  }
+
+  EXPECT_EQ(
+      "BASE_TEST=wibble\n",
+      TestLaunchProcess(
+          print_env, env_changes, true /* clear_environ */, no_clone_flags));
+  env_changes.clear();
+  EXPECT_EQ(
+      "",
+      TestLaunchProcess(
+          print_env, env_changes, true /* clear_environ */, no_clone_flags));
+#endif
+}
+
+TEST_F(ProcessUtilTest, GetAppOutput) {
+  std::string output;
+
+#if defined(OS_ANDROID)
+  std::vector<std::string> argv;
+  argv.push_back("sh");  // Instead of /bin/sh, force path search to find it.
+  argv.push_back("-c");
+
+  argv.push_back("exit 0");
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "exit 1";
+  EXPECT_FALSE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "echo foobar42";
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("foobar42\n", output.c_str());
+#else
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(FilePath("true")),
+                                 &output));
+  EXPECT_STREQ("", output.c_str());
+
+  EXPECT_FALSE(base::GetAppOutput(base::CommandLine(FilePath("false")),
+                                  &output));
+
+  std::vector<std::string> argv;
+  argv.push_back("/bin/echo");
+  argv.push_back("-n");
+  argv.push_back("foobar42");
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("foobar42", output.c_str());
+#endif  // defined(OS_ANDROID)
+}
+
+// Flakes on Android, crbug.com/375840
+#if defined(OS_ANDROID)
+#define MAYBE_GetAppOutputRestricted DISABLED_GetAppOutputRestricted
+#else
+#define MAYBE_GetAppOutputRestricted GetAppOutputRestricted
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestricted) {
+  // Unfortunately, since we can't rely on the path, we need to know where
+  // everything is. So let's use /bin/sh, which is on every POSIX system, and
+  // its built-ins.
+  std::vector<std::string> argv;
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+
+  // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of
+  // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we
+  // need absolute paths).
+  argv.push_back("exit 0");   // argv[2]; equivalent to "true"
+  std::string output = "abc";
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           100));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "exit 1";  // equivalent to "false"
+  output = "before";
+  EXPECT_FALSE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                            100));
+  EXPECT_STREQ("", output.c_str());
+
+  // Amount of output exactly equal to space allowed.
+  argv[2] = "echo 123456789";  // (the sh built-in doesn't take "-n")
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           10));
+  EXPECT_STREQ("123456789\n", output.c_str());
+
+  // Amount of output greater than space allowed.
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           5));
+  EXPECT_STREQ("12345", output.c_str());
+
+  // Amount of output less than space allowed.
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           15));
+  EXPECT_STREQ("123456789\n", output.c_str());
+
+  // Zero space allowed.
+  output = "abc";
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           0));
+  EXPECT_STREQ("", output.c_str());
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+// TODO(benwells): GetAppOutputRestricted should terminate applications
+// with SIGPIPE when we have enough output. http://crbug.com/88502
+TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) {
+  std::vector<std::string> argv;
+  std::string output;
+
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");
+#if defined(OS_ANDROID)
+  argv.push_back("while echo 12345678901234567890; do :; done");
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           10));
+  EXPECT_STREQ("1234567890", output.c_str());
+#else
+  argv.push_back("yes");
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           10));
+  EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str());
+#endif
+}
+#endif
+
+#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX) && \
+    defined(ARCH_CPU_64_BITS)
+// Times out under AddressSanitizer on 64-bit OS X, see
+// http://crbug.com/298197.
+#define MAYBE_GetAppOutputRestrictedNoZombies \
+    DISABLED_GetAppOutputRestrictedNoZombies
+#else
+#define MAYBE_GetAppOutputRestrictedNoZombies GetAppOutputRestrictedNoZombies
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestrictedNoZombies) {
+  std::vector<std::string> argv;
+
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+  argv.push_back("echo 123456789012345678901234567890");  // argv[2]
+
+  // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS
+  // 10.5) times with an output buffer big enough to capture all output.
+  for (int i = 0; i < 300; i++) {
+    std::string output;
+    EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                             100));
+    EXPECT_STREQ("123456789012345678901234567890\n", output.c_str());
+  }
+
+  // Ditto, but with an output buffer too small to capture all output.
+  for (int i = 0; i < 300; i++) {
+    std::string output;
+    EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                             10));
+    EXPECT_STREQ("1234567890", output.c_str());
+  }
+}
+
+TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
+  // Test getting output from a successful application.
+  std::vector<std::string> argv;
+  std::string output;
+  int exit_code;
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+  argv.push_back("echo foo");  // argv[2];
+  EXPECT_TRUE(base::GetAppOutputWithExitCode(base::CommandLine(argv), &output,
+                                             &exit_code));
+  EXPECT_STREQ("foo\n", output.c_str());
+  EXPECT_EQ(exit_code, 0);
+
+  // Test getting output from an application which fails with a specific exit
+  // code.
+  output.clear();
+  argv[2] = "echo foo; exit 2";
+  EXPECT_TRUE(base::GetAppOutputWithExitCode(base::CommandLine(argv), &output,
+                                             &exit_code));
+  EXPECT_STREQ("foo\n", output.c_str());
+  EXPECT_EQ(exit_code, 2);
+}
+
+TEST_F(ProcessUtilTest, GetParentProcessId) {
+  base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId());
+  EXPECT_EQ(ppid, getppid());
+}
+
+// TODO(port): port those unit tests.
+bool IsProcessDead(base::ProcessHandle child) {
+  // waitpid() will actually reap the process which is exactly NOT what we
+  // want to test for.  The good thing is that if it can't find the process
+  // we'll get a nice value for errno which we can test for.
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+  return result == -1 && errno == ECHILD;
+}
+
+TEST_F(ProcessUtilTest, DelayedTermination) {
+  base::Process child_process = SpawnChild("process_util_test_never_die");
+  ASSERT_TRUE(child_process.IsValid());
+  base::EnsureProcessTerminated(child_process.Duplicate());
+  int exit_code;
+  child_process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5),
+                                       &exit_code);
+
+  // Check that process was really killed.
+  EXPECT_TRUE(IsProcessDead(child_process.Handle()));
+}
+
+MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
+  while (1) {
+    sleep(500);
+  }
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, ImmediateTermination) {
+  base::Process child_process = SpawnChild("process_util_test_die_immediately");
+  ASSERT_TRUE(child_process.IsValid());
+  // Give it time to die.
+  sleep(2);
+  base::EnsureProcessTerminated(child_process.Duplicate());
+
+  // Check that process was really killed.
+  EXPECT_TRUE(IsProcessDead(child_process.Handle()));
+}
+
+MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
+  return 0;
+}
+
+#if !defined(OS_ANDROID)
+const char kPipeValue = '\xcc';
+
+class ReadFromPipeDelegate : public base::LaunchOptions::PreExecDelegate {
+ public:
+  explicit ReadFromPipeDelegate(int fd) : fd_(fd) {}
+  ~ReadFromPipeDelegate() override {}
+  void RunAsyncSafe() override {
+    char c;
+    RAW_CHECK(HANDLE_EINTR(read(fd_, &c, 1)) == 1);
+    RAW_CHECK(IGNORE_EINTR(close(fd_)) == 0);
+    RAW_CHECK(c == kPipeValue);
+  }
+
+ private:
+  int fd_;
+  DISALLOW_COPY_AND_ASSIGN(ReadFromPipeDelegate);
+};
+
+TEST_F(ProcessUtilTest, PreExecHook) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+
+  base::ScopedFD read_fd(pipe_fds[0]);
+  base::ScopedFD write_fd(pipe_fds[1]);
+  base::FileHandleMappingVector fds_to_remap;
+  fds_to_remap.push_back(std::make_pair(read_fd.get(), read_fd.get()));
+
+  ReadFromPipeDelegate read_from_pipe_delegate(read_fd.get());
+  base::LaunchOptions options;
+  options.fds_to_remap = &fds_to_remap;
+  options.pre_exec_delegate = &read_from_pipe_delegate;
+  base::Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  read_fd.reset();
+  ASSERT_EQ(1, HANDLE_EINTR(write(write_fd.get(), &kPipeValue, 1)));
+
+  int exit_code = 42;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(0, exit_code);
+}
+#endif  // !defined(OS_ANDROID)
+
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_LINUX)
+const int kSuccess = 0;
+
+MULTIPROCESS_TEST_MAIN(CheckPidProcess) {
+  const pid_t kInitPid = 1;
+  const pid_t pid = syscall(__NR_getpid);
+  CHECK(pid == kInitPid);
+  CHECK(getpid() == pid);
+  return kSuccess;
+}
+
+TEST_F(ProcessUtilTest, CloneFlags) {
+  if (RunningOnValgrind() ||
+      !base::PathExists(FilePath("/proc/self/ns/user")) ||
+      !base::PathExists(FilePath("/proc/self/ns/pid"))) {
+    // User or PID namespaces are not supported.
+    return;
+  }
+
+  base::LaunchOptions options;
+  options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID;
+
+  base::Process process(SpawnChildWithOptions("CheckPidProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(kSuccess, exit_code);
+}
+
+TEST(ForkWithFlagsTest, UpdatesPidCache) {
+  // The libc clone function, which allows ForkWithFlags to keep the pid cache
+  // up to date, does not work on Valgrind.
+  if (RunningOnValgrind()) {
+    return;
+  }
+
+  // Warm up the libc pid cache, if there is one.
+  ASSERT_EQ(syscall(__NR_getpid), getpid());
+
+  pid_t ctid = 0;
+  const pid_t pid =
+      base::ForkWithFlags(SIGCHLD | CLONE_CHILD_SETTID, nullptr, &ctid);
+  if (pid == 0) {
+    // In child.  Check both the raw getpid syscall and the libc getpid wrapper
+    // (which may rely on a pid cache).
+    RAW_CHECK(syscall(__NR_getpid) == ctid);
+    RAW_CHECK(getpid() == ctid);
+    _exit(kSuccess);
+  }
+
+  ASSERT_NE(-1, pid);
+  int status = 42;
+  ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(kSuccess, WEXITSTATUS(status));
+}
+
+MULTIPROCESS_TEST_MAIN(CheckCwdProcess) {
+  base::FilePath expected;
+  CHECK(base::GetTempDir(&expected));
+  base::FilePath actual;
+  CHECK(base::GetCurrentDirectory(&actual));
+  CHECK(actual == expected);
+  return kSuccess;
+}
+
+TEST_F(ProcessUtilTest, CurrentDirectory) {
+  // TODO(rickyz): Add support for passing arguments to multiprocess children,
+  // then create a special directory for this test.
+  base::FilePath tmp_dir;
+  ASSERT_TRUE(base::GetTempDir(&tmp_dir));
+
+  base::LaunchOptions options;
+  options.current_directory = tmp_dir;
+
+  base::Process process(SpawnChildWithOptions("CheckCwdProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(kSuccess, exit_code);
+}
+
+TEST_F(ProcessUtilTest, InvalidCurrentDirectory) {
+  base::LaunchOptions options;
+  options.current_directory = base::FilePath("/dev/null");
+
+  base::Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = kSuccess;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_NE(kSuccess, exit_code);
+}
+#endif
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
new file mode 100644
index 0000000..0d312a3
--- /dev/null
+++ b/base/process/process_win.cc
@@ -0,0 +1,205 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/process/kill.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+DWORD kBasicProcessAccess =
+  PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
+
+} // namespace
+
+namespace base {
+
+Process::Process(ProcessHandle handle)
+    : is_current_process_(false),
+      process_(handle) {
+  CHECK_NE(handle, ::GetCurrentProcess());
+}
+
+Process::Process(RValue other)
+    : is_current_process_(other.object->is_current_process_),
+      process_(other.object->process_.Take()) {
+  other.object->Close();
+}
+
+Process::~Process() {
+}
+
+Process& Process::operator=(RValue other) {
+  if (this != other.object) {
+    process_.Set(other.object->process_.Take());
+    is_current_process_ = other.object->is_current_process_;
+    other.object->Close();
+  }
+  return *this;
+}
+
+// static
+Process Process::Current() {
+  Process process;
+  process.is_current_process_ = true;
+  return process.Pass();
+}
+
+// static
+Process Process::Open(ProcessId pid) {
+  return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
+}
+
+// static
+Process Process::OpenWithExtraPrivileges(ProcessId pid) {
+  DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
+  return Process(::OpenProcess(access, FALSE, pid));
+}
+
+// static
+Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
+  return Process(::OpenProcess(desired_access, FALSE, pid));
+}
+
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+  DCHECK_NE(handle, ::GetCurrentProcess());
+  ProcessHandle out_handle;
+  if (!::DuplicateHandle(GetCurrentProcess(), handle,
+                         GetCurrentProcess(), &out_handle,
+                         0, FALSE, DUPLICATE_SAME_ACCESS)) {
+    return Process();
+  }
+  return Process(out_handle);
+}
+
+// static
+bool Process::CanBackgroundProcesses() {
+  return true;
+}
+
+bool Process::IsValid() const {
+  return process_.IsValid() || is_current();
+}
+
+ProcessHandle Process::Handle() const {
+  return is_current_process_ ? GetCurrentProcess() : process_.Get();
+}
+
+Process Process::Duplicate() const {
+  if (is_current())
+    return Current();
+
+  ProcessHandle out_handle;
+  if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
+                                       Handle(),
+                                       GetCurrentProcess(),
+                                       &out_handle,
+                                       0,
+                                       FALSE,
+                                       DUPLICATE_SAME_ACCESS)) {
+    return Process();
+  }
+  return Process(out_handle);
+}
+
+ProcessId Process::Pid() const {
+  DCHECK(IsValid());
+  return GetProcId(Handle());
+}
+
+bool Process::is_current() const {
+  return is_current_process_;
+}
+
+void Process::Close() {
+  is_current_process_ = false;
+  if (!process_.IsValid())
+    return;
+
+  process_.Close();
+}
+
+bool Process::Terminate(int exit_code, bool wait) const {
+  DCHECK(IsValid());
+  bool result = (::TerminateProcess(Handle(), exit_code) != FALSE);
+  if (result && wait) {
+    // The process may not end immediately due to pending I/O
+    if (::WaitForSingleObject(Handle(), 60 * 1000) != WAIT_OBJECT_0)
+      DPLOG(ERROR) << "Error waiting for process exit";
+  } else if (!result) {
+    DPLOG(ERROR) << "Unable to terminate process";
+  }
+  return result;
+}
+
+bool Process::WaitForExit(int* exit_code) {
+  return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE),
+                                exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+  // Limit timeout to INFINITE.
+  DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
+  if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0)
+    return false;
+
+  DWORD temp_code;  // Don't clobber out-parameters in case of failure.
+  if (!::GetExitCodeProcess(Handle(), &temp_code))
+    return false;
+
+  *exit_code = temp_code;
+  return true;
+}
+
+bool Process::IsProcessBackgrounded() const {
+  DCHECK(IsValid());
+  DWORD priority = GetPriority();
+  if (priority == 0)
+    return false;  // Failure case.
+  return ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
+          (priority == IDLE_PRIORITY_CLASS));
+}
+
+bool Process::SetProcessBackgrounded(bool value) {
+  DCHECK(IsValid());
+  // Vista and above introduce a real background mode, which not only
+  // sets the priority class on the threads but also on the IO generated
+  // by it. Unfortunately it can only be set for the calling process.
+  DWORD priority;
+  if ((base::win::GetVersion() >= base::win::VERSION_VISTA) && (is_current())) {
+    priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
+                       PROCESS_MODE_BACKGROUND_END;
+  } else {
+    // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a
+    // background priority for background renderers (this code path is
+    // technically for more than just the renderers but they're the only use
+    // case in practice and experimenting here direclty is thus easier -- plus
+    // it doesn't really hurt as above we already state our intent of using
+    // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially
+    // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the
+    // asbence of field trials to get coverage on the perf waterfall.
+    DWORD background_priority = IDLE_PRIORITY_CLASS;
+    base::FieldTrial* trial =
+        base::FieldTrialList::Find("BackgroundRendererProcesses");
+    if (trial && trial->group_name() == "AllowBelowNormalFromBrowser")
+      background_priority = BELOW_NORMAL_PRIORITY_CLASS;
+
+    priority = value ? background_priority : NORMAL_PRIORITY_CLASS;
+  }
+
+  return (::SetPriorityClass(Handle(), priority) != 0);
+}
+
+int Process::GetPriority() const {
+  DCHECK(IsValid());
+  return ::GetPriorityClass(Handle());
+}
+
+}  // namespace base
diff --git a/base/profiler/alternate_timer.cc b/base/profiler/alternate_timer.cc
new file mode 100644
index 0000000..02763cd
--- /dev/null
+++ b/base/profiler/alternate_timer.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/alternate_timer.h"
+
+#include "base/basictypes.h"
+
+namespace {
+
+tracked_objects::NowFunction* g_time_function = NULL;
+tracked_objects::TimeSourceType g_time_source_type =
+    tracked_objects::TIME_SOURCE_TYPE_WALL_TIME;
+
+}  // anonymous namespace
+
+namespace tracked_objects {
+
+const char kAlternateProfilerTime[] = "CHROME_PROFILER_TIME";
+
+// Set an alternate timer function to replace the OS time function when
+// profiling.
+void SetAlternateTimeSource(NowFunction* now_function, TimeSourceType type) {
+  g_time_function = now_function;
+  g_time_source_type = type;
+}
+
+NowFunction* GetAlternateTimeSource() {
+  return g_time_function;
+}
+
+TimeSourceType GetTimeSourceType() {
+  return g_time_source_type;
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/alternate_timer.h b/base/profiler/alternate_timer.h
new file mode 100644
index 0000000..fdc75dc
--- /dev/null
+++ b/base/profiler/alternate_timer.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a glue file, which allows third party code to call into our profiler
+// without having to include most any functions from base.
+
+#ifndef BASE_PROFILER_ALTERNATE_TIMER_H_
+#define BASE_PROFILER_ALTERNATE_TIMER_H_
+
+#include "base/base_export.h"
+
+namespace tracked_objects {
+
+enum TimeSourceType {
+  TIME_SOURCE_TYPE_WALL_TIME,
+  TIME_SOURCE_TYPE_TCMALLOC
+};
+
+// Provide type for an alternate timer function.
+typedef unsigned int NowFunction();
+
+// Environment variable name that is used to activate alternate timer profiling
+// (such as using TCMalloc allocations to provide a pseudo-timer) for tasks
+// instead of wall clock profiling.
+BASE_EXPORT extern const char kAlternateProfilerTime[];
+
+// Set an alternate timer function to replace the OS time function when
+// profiling.  Typically this is called by an allocator that is providing a
+// function that indicates how much memory has been allocated on any given
+// thread.
+BASE_EXPORT void SetAlternateTimeSource(NowFunction* now_function,
+                                        TimeSourceType type);
+
+// Gets the pointer to a function that was set via SetAlternateTimeSource().
+// Returns NULL if no set was done prior to calling GetAlternateTimeSource.
+NowFunction* GetAlternateTimeSource();
+
+// Returns the type of the currently set time source.
+BASE_EXPORT TimeSourceType GetTimeSourceType();
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_ALTERNATE_TIMER_H_
diff --git a/base/profiler/native_stack_sampler.cc b/base/profiler/native_stack_sampler.cc
new file mode 100644
index 0000000..8b4731b
--- /dev/null
+++ b/base/profiler/native_stack_sampler.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/native_stack_sampler.h"
+
+namespace base {
+
+NativeStackSampler::NativeStackSampler() {}
+
+NativeStackSampler::~NativeStackSampler() {}
+
+}  // namespace base
diff --git a/base/profiler/native_stack_sampler.h b/base/profiler/native_stack_sampler.h
new file mode 100644
index 0000000..bc170dc
--- /dev/null
+++ b/base/profiler/native_stack_sampler.h
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+#define BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// NativeStackSampler is an implementation detail of StackSamplingProfiler. It
+// abstracts the native implementation required to record a stack sample for a
+// given thread.
+class NativeStackSampler {
+ public:
+  virtual ~NativeStackSampler();
+
+  // Creates a stack sampler that records samples for |thread_handle|. Returns
+  // null if this platform does not support stack sampling.
+  static scoped_ptr<NativeStackSampler> Create(PlatformThreadId thread_id);
+
+  // The following functions are all called on the SamplingThread (not the
+  // thread being sampled).
+
+  // Notifies the sampler that we're starting to record a new profile. Modules
+  // shared across samples in the profile should be recorded in |modules|.
+  virtual void ProfileRecordingStarting(
+      std::vector<StackSamplingProfiler::Module>* modules) = 0;
+
+  // Records a stack sample to |sample|.
+  virtual void RecordStackSample(StackSamplingProfiler::Sample* sample) = 0;
+
+  // Notifies the sampler that we've stopped recording the current
+  // profile.
+  virtual void ProfileRecordingStopped() = 0;
+
+ protected:
+  NativeStackSampler();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
+};
+
+}  // namespace base
+
+#endif  // BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
new file mode 100644
index 0000000..f06a8c6
--- /dev/null
+++ b/base/profiler/scoped_profile.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/scoped_profile.h"
+
+#include "base/location.h"
+#include "base/tracked_objects.h"
+
+
+namespace tracked_objects {
+
+
+ScopedProfile::ScopedProfile(const Location& location, Mode mode)
+    : birth_(NULL) {
+  if (mode == DISABLED)
+    return;
+
+  birth_ = ThreadData::TallyABirthIfActive(location);
+  if (!birth_)
+    return;
+
+  stopwatch_.Start();
+}
+
+ScopedProfile::~ScopedProfile() {
+  if (!birth_)
+    return;
+
+  stopwatch_.Stop();
+  ThreadData::TallyRunInAScopedRegionIfTracking(birth_, stopwatch_);
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
new file mode 100644
index 0000000..6b0c800
--- /dev/null
+++ b/base/profiler/scoped_profile.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#ifndef BASE_PROFILER_SCOPED_PROFILE_H_
+#define BASE_PROFILER_SCOPED_PROFILE_H_
+
+//------------------------------------------------------------------------------
+// ScopedProfile provides basic helper functions for profiling a short
+// region of code within a scope.  It is separate from the related ThreadData
+// class so that it can be included without much other cruft, and provide the
+// macros listed below.
+
+#include "base/base_export.h"
+#include "base/location.h"
+#include "base/profiler/tracked_time.h"
+#include "base/tracked_objects.h"
+
+#define PASTE_LINE_NUMBER_ON_NAME(name, line) name##line
+
+#define LINE_BASED_VARIABLE_NAME_FOR_PROFILING                                 \
+    PASTE_LINE_NUMBER_ON_NAME(some_profiler_variable_, __LINE__)
+
+// Defines the containing scope as a profiled region. This allows developers to
+// profile their code and see results on their about:profiler page, as well as
+// on the UMA dashboard.
+#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name)            \
+  ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name),           \
+      ::tracked_objects::ScopedProfile::ENABLED)
+
+// Same as TRACK_RUN_IN_THIS_SCOPED_REGION except that there's an extra param
+// which is concatenated with the function name for better filtering.
+#define TRACK_SCOPED_REGION(category_name, dispatch_function_name)         \
+  ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(                                    \
+          "[" category_name "]" dispatch_function_name),                   \
+      ::tracked_objects::ScopedProfile::ENABLED)
+
+namespace tracked_objects {
+class Births;
+
+class BASE_EXPORT ScopedProfile {
+ public:
+  // Mode of operation. Specifies whether ScopedProfile should be a no-op or
+  // needs to create and tally a task.
+  enum Mode {
+    DISABLED,  // Do nothing.
+    ENABLED    // Create and tally a task.
+  };
+
+  ScopedProfile(const Location& location, Mode mode);
+  ~ScopedProfile();
+
+ private:
+  Births* birth_;  // Place in code where tracking started.
+  TaskStopwatch stopwatch_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedProfile);
+};
+
+}  // namespace tracked_objects
+
+#endif   // BASE_PROFILER_SCOPED_PROFILE_H_
diff --git a/base/profiler/scoped_tracker.cc b/base/profiler/scoped_tracker.cc
new file mode 100644
index 0000000..d15b7de
--- /dev/null
+++ b/base/profiler/scoped_tracker.cc
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/scoped_tracker.h"
+
+#include "base/bind.h"
+
+namespace tracked_objects {
+
+namespace {
+
+ScopedProfile::Mode g_scoped_profile_mode = ScopedProfile::DISABLED;
+
+}  // namespace
+
+// static
+void ScopedTracker::Enable() {
+  g_scoped_profile_mode = ScopedProfile::ENABLED;
+}
+
+ScopedTracker::ScopedTracker(const Location& location)
+    : scoped_profile_(location, g_scoped_profile_mode) {
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/scoped_tracker.h b/base/profiler/scoped_tracker.h
new file mode 100644
index 0000000..23e2f07
--- /dev/null
+++ b/base/profiler/scoped_tracker.h
@@ -0,0 +1,76 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROFILER_SCOPED_TRACKER_H_
+#define BASE_PROFILER_SCOPED_TRACKER_H_
+
+//------------------------------------------------------------------------------
+// Utilities for temporarily instrumenting code to dig into issues that were
+// found using profiler data.
+
+#include "base/base_export.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/profiler/scoped_profile.h"
+
+namespace tracked_objects {
+
+// ScopedTracker instruments a region within the code if the instrumentation is
+// enabled. It can be used, for example, to find out if a source of jankiness is
+// inside the instrumented code region.
+// Details:
+// 1. This class creates a task (like ones created by PostTask calls or IPC
+// message handlers). This task can be seen in chrome://profiler and is sent as
+// a part of profiler data to the UMA server. See profiler_event.proto.
+// 2. That task's lifetime is same as the lifetime of the ScopedTracker
+// instance.
+// 3. The execution time associated with the task is the wallclock time between
+// its constructor and destructor, minus wallclock times of directly nested
+// tasks.
+// 4. Task creation that this class utilizes is highly optimized.
+// 5. The class doesn't create a task unless this was enabled for the current
+// process. Search for ScopedTracker::Enable for the current list of processes
+// and channels where it's activated.
+// 6. The class is designed for temporarily instrumenting code to find
+// performance problems, after which the instrumentation must be removed.
+class BASE_EXPORT ScopedTracker {
+ public:
+  ScopedTracker(const Location& location);
+
+  // Enables instrumentation for the remainder of the current process' life. If
+  // this function is not called, all profiler instrumentations are no-ops.
+  static void Enable();
+
+  // Augments a |callback| with provided |location|. This is useful for
+  // instrumenting cases when we know that a jank is in a callback and there are
+  // many possible callbacks, but they come from a relatively small number of
+  // places. We can instrument these few places and at least know which one
+  // passes the janky callback.
+  template <typename P1>
+  static base::Callback<void(P1)> TrackCallback(
+      const Location& location,
+      const base::Callback<void(P1)>& callback) {
+    return base::Bind(&ScopedTracker::ExecuteAndTrackCallback<P1>, location,
+                      callback);
+  }
+
+ private:
+  // Executes |callback|, augmenting it with provided |location|.
+  template <typename P1>
+  static void ExecuteAndTrackCallback(const Location& location,
+                                      const base::Callback<void(P1)>& callback,
+                                      P1 p1) {
+    ScopedTracker tracking_profile(location);
+    callback.Run(p1);
+  }
+
+  const ScopedProfile scoped_profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTracker);
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_SCOPED_TRACKER_H_
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
new file mode 100644
index 0000000..9da6628
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -0,0 +1,311 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/stack_sampling_profiler.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/singleton.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/synchronization/lock.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+// DefaultProfileProcessor ----------------------------------------------------
+
+namespace {
+
+// Singleton class responsible for providing the default processing for profiles
+// (i.e. for profiles generated by profilers without their own completed
+// callback).
+class DefaultProfileProcessor {
+ public:
+  using CompletedCallback = StackSamplingProfiler::CompletedCallback;
+
+  ~DefaultProfileProcessor();
+
+  static DefaultProfileProcessor* GetInstance();
+
+  // Sets the callback to use for processing profiles captured without a
+  // per-profiler completed callback. Pending completed profiles are stored in
+  // this object until a non-null callback is provided here. This function is
+  // thread-safe.
+  void SetCompletedCallback(CompletedCallback callback);
+
+  // Processes |profiles|. This function is thread safe.
+  void ProcessProfiles(
+      const StackSamplingProfiler::CallStackProfiles& profiles);
+
+ private:
+  friend struct DefaultSingletonTraits<DefaultProfileProcessor>;
+
+  DefaultProfileProcessor();
+
+  // Copies the pending profiles from |profiles_| into |profiles|, and clears
+  // |profiles_|. This function may be called on any thread.
+  void GetAndClearPendingProfiles(
+      StackSamplingProfiler::CallStackProfiles* profiles);
+
+  // Gets the current completed callback, with proper locking.
+  CompletedCallback GetCompletedCallback() const;
+
+  mutable Lock callback_lock_;
+  CompletedCallback default_completed_callback_;
+
+  Lock profiles_lock_;
+  StackSamplingProfiler::CallStackProfiles profiles_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultProfileProcessor);
+};
+
+DefaultProfileProcessor::~DefaultProfileProcessor() {}
+
+// static
+DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() {
+  return Singleton<DefaultProfileProcessor>::get();
+}
+
+void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) {
+  {
+    AutoLock scoped_lock(callback_lock_);
+    default_completed_callback_ = callback;
+  }
+
+  if (!callback.is_null()) {
+    // Provide any pending profiles to the callback immediately.
+    StackSamplingProfiler::CallStackProfiles profiles;
+    GetAndClearPendingProfiles(&profiles);
+    if (!profiles.empty())
+      callback.Run(profiles);
+  }
+}
+
+void DefaultProfileProcessor::ProcessProfiles(
+    const StackSamplingProfiler::CallStackProfiles& profiles) {
+  CompletedCallback callback = GetCompletedCallback();
+
+  // Store pending profiles if we don't have a valid callback.
+  if (!callback.is_null()) {
+    callback.Run(profiles);
+  } else {
+    AutoLock scoped_lock(profiles_lock_);
+    profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
+  }
+}
+
+DefaultProfileProcessor::DefaultProfileProcessor() {}
+
+void DefaultProfileProcessor::GetAndClearPendingProfiles(
+    StackSamplingProfiler::CallStackProfiles* profiles) {
+  profiles->clear();
+
+  AutoLock scoped_lock(profiles_lock_);
+  profiles_.swap(*profiles);
+}
+
+DefaultProfileProcessor::CompletedCallback
+DefaultProfileProcessor::GetCompletedCallback() const {
+  AutoLock scoped_lock(callback_lock_);
+  return default_completed_callback_;
+}
+
+}  // namespace
+
+// StackSamplingProfiler::Module ----------------------------------------------
+
+StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
+StackSamplingProfiler::Module::Module(const void* base_address,
+                                      const std::string& id,
+                                      const FilePath& filename)
+    : base_address(base_address), id(id), filename(filename) {}
+
+StackSamplingProfiler::Module::~Module() {}
+
+// StackSamplingProfiler::Frame -----------------------------------------------
+
+StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
+                                    size_t module_index)
+    : instruction_pointer(instruction_pointer),
+      module_index(module_index) {}
+
+StackSamplingProfiler::Frame::~Frame() {}
+
+// StackSamplingProfiler::CallStackProfile ------------------------------------
+
+StackSamplingProfiler::CallStackProfile::CallStackProfile()
+    : preserve_sample_ordering(false), user_data(0) {}
+
+StackSamplingProfiler::CallStackProfile::~CallStackProfile() {}
+
+// StackSamplingProfiler::SamplingThread --------------------------------------
+
+StackSamplingProfiler::SamplingThread::SamplingThread(
+    scoped_ptr<NativeStackSampler> native_sampler,
+    const SamplingParams& params,
+    CompletedCallback completed_callback)
+    : native_sampler_(native_sampler.Pass()),
+      params_(params),
+      stop_event_(false, false),
+      completed_callback_(completed_callback) {
+}
+
+StackSamplingProfiler::SamplingThread::~SamplingThread() {}
+
+void StackSamplingProfiler::SamplingThread::ThreadMain() {
+  PlatformThread::SetName("Chrome_SamplingProfilerThread");
+
+  CallStackProfiles profiles;
+  CollectProfiles(&profiles);
+  completed_callback_.Run(profiles);
+}
+
+// Depending on how long the sampling takes and the length of the sampling
+// interval, a burst of samples could take arbitrarily longer than
+// samples_per_burst * sampling_interval. In this case, we (somewhat
+// arbitrarily) honor the number of samples requested rather than strictly
+// adhering to the sampling intervals. Once we have established users for the
+// StackSamplingProfiler and the collected data to judge, we may go the other
+// way or make this behavior configurable.
+bool StackSamplingProfiler::SamplingThread::CollectProfile(
+    CallStackProfile* profile,
+    TimeDelta* elapsed_time) {
+  ElapsedTimer profile_timer;
+  CallStackProfile current_profile;
+  native_sampler_->ProfileRecordingStarting(&current_profile.modules);
+  current_profile.sampling_period = params_.sampling_interval;
+  bool burst_completed = true;
+  TimeDelta previous_elapsed_sample_time;
+  for (int i = 0; i < params_.samples_per_burst; ++i) {
+    if (i != 0) {
+      // Always wait, even if for 0 seconds, so we can observe a signal on
+      // stop_event_.
+      if (stop_event_.TimedWait(
+              std::max(params_.sampling_interval - previous_elapsed_sample_time,
+                       TimeDelta()))) {
+        burst_completed = false;
+        break;
+      }
+    }
+    ElapsedTimer sample_timer;
+    current_profile.samples.push_back(Sample());
+    native_sampler_->RecordStackSample(&current_profile.samples.back());
+    previous_elapsed_sample_time = sample_timer.Elapsed();
+  }
+
+  *elapsed_time = profile_timer.Elapsed();
+  current_profile.profile_duration = *elapsed_time;
+  current_profile.preserve_sample_ordering = params_.preserve_sample_ordering;
+  current_profile.user_data = params_.user_data;
+  native_sampler_->ProfileRecordingStopped();
+
+  if (burst_completed)
+    *profile = current_profile;
+
+  return burst_completed;
+}
+
+// In an analogous manner to CollectProfile() and samples exceeding the expected
+// total sampling time, bursts may also exceed the burst_interval. We adopt the
+// same wait-and-see approach here.
+void StackSamplingProfiler::SamplingThread::CollectProfiles(
+    CallStackProfiles* profiles) {
+  if (stop_event_.TimedWait(params_.initial_delay))
+    return;
+
+  TimeDelta previous_elapsed_profile_time;
+  for (int i = 0; i < params_.bursts; ++i) {
+    if (i != 0) {
+      // Always wait, even if for 0 seconds, so we can observe a signal on
+      // stop_event_.
+      if (stop_event_.TimedWait(
+              std::max(params_.burst_interval - previous_elapsed_profile_time,
+                       TimeDelta())))
+        return;
+    }
+
+    CallStackProfile profile;
+    if (!CollectProfile(&profile, &previous_elapsed_profile_time))
+      return;
+    profiles->push_back(profile);
+  }
+}
+
+void StackSamplingProfiler::SamplingThread::Stop() {
+  stop_event_.Signal();
+}
+
+// StackSamplingProfiler ------------------------------------------------------
+
+StackSamplingProfiler::SamplingParams::SamplingParams()
+    : initial_delay(TimeDelta::FromMilliseconds(0)),
+      bursts(1),
+      burst_interval(TimeDelta::FromMilliseconds(10000)),
+      samples_per_burst(300),
+      sampling_interval(TimeDelta::FromMilliseconds(100)),
+      preserve_sample_ordering(false),
+      user_data(0) {
+}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+                                             const SamplingParams& params)
+    : thread_id_(thread_id), params_(params) {}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+                                             const SamplingParams& params,
+                                             CompletedCallback callback)
+    : thread_id_(thread_id), params_(params), completed_callback_(callback) {}
+
+StackSamplingProfiler::~StackSamplingProfiler() {
+  Stop();
+  if (!sampling_thread_handle_.is_null())
+    PlatformThread::Join(sampling_thread_handle_);
+}
+
+void StackSamplingProfiler::Start() {
+  scoped_ptr<NativeStackSampler> native_sampler =
+      NativeStackSampler::Create(thread_id_);
+  if (!native_sampler)
+    return;
+
+  CompletedCallback callback =
+      !completed_callback_.is_null() ? completed_callback_ :
+      Bind(&DefaultProfileProcessor::ProcessProfiles,
+           Unretained(DefaultProfileProcessor::GetInstance()));
+  sampling_thread_.reset(
+      new SamplingThread(native_sampler.Pass(), params_, callback));
+  if (!PlatformThread::Create(0, sampling_thread_.get(),
+                              &sampling_thread_handle_))
+    sampling_thread_.reset();
+}
+
+void StackSamplingProfiler::Stop() {
+  if (sampling_thread_)
+    sampling_thread_->Stop();
+}
+
+// static
+void StackSamplingProfiler::SetDefaultCompletedCallback(
+    CompletedCallback callback) {
+  DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback);
+}
+
+// StackSamplingProfiler::Frame global functions ------------------------------
+
+bool operator==(const StackSamplingProfiler::Frame &a,
+                const StackSamplingProfiler::Frame &b) {
+  return a.instruction_pointer == b.instruction_pointer &&
+      a.module_index == b.module_index;
+}
+
+bool operator<(const StackSamplingProfiler::Frame &a,
+               const StackSamplingProfiler::Frame &b) {
+  return (a.module_index < b.module_index) ||
+      (a.module_index == b.module_index &&
+       a.instruction_pointer < b.instruction_pointer);
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler.h b/base/profiler/stack_sampling_profiler.h
new file mode 100644
index 0000000..9d52f27
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler.h
@@ -0,0 +1,264 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class NativeStackSampler;
+
+// StackSamplingProfiler periodically stops a thread to sample its stack, for
+// the purpose of collecting information about which code paths are
+// executing. This information is used in aggregate by UMA to identify hot
+// and/or janky code paths.
+//
+// Sample StackSamplingProfiler usage:
+//
+//   // Create and customize params as desired.
+//   base::StackStackSamplingProfiler::SamplingParams params;
+//   // Any thread's ID may be passed as the target.
+//   base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+//       params);
+//
+//   // Or, to process the profiles within Chrome rather than via UMA, use a
+//   // custom completed callback:
+//   base::StackStackSamplingProfiler::CompletedCallback
+//       thread_safe_callback = ...;
+//   base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+//       params, thread_safe_callback);
+//
+//   profiler.Start();
+//   // ... work being done on the target thread here ...
+//   profiler.Stop();  // optional, stops collection before complete per params
+//
+// The default SamplingParams causes stacks to be recorded in a single burst at
+// a 10Hz interval for a total of 30 seconds. All of these parameters may be
+// altered as desired.
+//
+// When all call stack profiles are complete or the profiler is stopped, if the
+// custom completed callback was set it is called from a thread created by the
+// profiler with the completed profiles. A profile is considered complete if all
+// requested samples were recorded for the profile (i.e. it was not stopped
+// prematurely).  If no callback was set, the default completed callback will be
+// called with the profiles. It is expected that the the default completed
+// callback is set by the metrics system to allow profiles to be provided via
+// UMA.
+//
+// The results of the profiling are passed to the completed callback and consist
+// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
+// burst as specified in SamplingParams and contains a set of Samples and
+// Modules. One Sample corresponds to a single recorded stack, and the Modules
+// record those modules associated with the recorded stack frames.
+class BASE_EXPORT StackSamplingProfiler {
+ public:
+  // Module represents the module (DLL or exe) corresponding to a stack frame.
+  struct BASE_EXPORT Module {
+    Module();
+    Module(const void* base_address, const std::string& id,
+           const FilePath& filename);
+    ~Module();
+
+    // Points to the base address of the module.
+    const void* base_address;
+
+    // An opaque binary string that uniquely identifies a particular program
+    // version with high probability. This is parsed from headers of the loaded
+    // module.
+    // For binaries generated by GNU tools:
+    //   Contents of the .note.gnu.build-id field.
+    // On Windows:
+    //   GUID + AGE in the debug image headers of a module.
+    std::string id;
+
+    // The filename of the module.
+    FilePath filename;
+  };
+
+  // Frame represents an individual sampled stack frame with module information.
+  struct BASE_EXPORT Frame {
+    // Identifies an unknown module.
+    static const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
+
+    Frame(const void* instruction_pointer, size_t module_index);
+    ~Frame();
+
+    // The sampled instruction pointer within the function.
+    const void* instruction_pointer;
+
+    // Index of the module in CallStackProfile::modules. We don't represent
+    // module state directly here to save space.
+    size_t module_index;
+  };
+
+  // Sample represents a set of stack frames.
+  using Sample = std::vector<Frame>;
+
+  // CallStackProfile represents a set of samples.
+  struct BASE_EXPORT CallStackProfile {
+    CallStackProfile();
+    ~CallStackProfile();
+
+    std::vector<Module> modules;
+    std::vector<Sample> samples;
+
+    // Duration of this profile.
+    TimeDelta profile_duration;
+
+    // Time between samples.
+    TimeDelta sampling_period;
+
+    // True if sample ordering is important and should be preserved if and when
+    // this profile is compressed and processed.
+    bool preserve_sample_ordering;
+
+    // User data associated with this profile.
+    uintptr_t user_data;
+  };
+
+  using CallStackProfiles = std::vector<CallStackProfile>;
+
+  // Represents parameters that configure the sampling.
+  struct BASE_EXPORT SamplingParams {
+    SamplingParams();
+
+    // Time to delay before first samples are taken. Defaults to 0.
+    TimeDelta initial_delay;
+
+    // Number of sampling bursts to perform. Defaults to 1.
+    int bursts;
+
+    // Interval between sampling bursts. This is the desired duration from the
+    // start of one burst to the start of the next burst. Defaults to 10s.
+    TimeDelta burst_interval;
+
+    // Number of samples to record per burst. Defaults to 300.
+    int samples_per_burst;
+
+    // Interval between samples during a sampling burst. This is the desired
+    // duration from the start of one sample to the start of the next
+    // sample. Defaults to 100ms.
+    TimeDelta sampling_interval;
+
+    // True if sample ordering is important and should be preserved if and when
+    // this profile is compressed and processed. Defaults to false.
+    bool preserve_sample_ordering;
+
+    // User data associated with this profile.
+    uintptr_t user_data;
+  };
+
+  // The callback type used to collect completed profiles.
+  //
+  // IMPORTANT NOTE: the callback is invoked on a thread the profiler
+  // constructs, rather than on the thread used to construct the profiler and
+  // set the callback, and thus the callback must be callable on any thread. For
+  // threads with message loops that create StackSamplingProfilers, posting a
+  // task to the message loop with a copy of the profiles is the recommended
+  // thread-safe callback implementation.
+  using CompletedCallback = Callback<void(const CallStackProfiles&)>;
+
+  // Creates a profiler that sends completed profiles to the default completed
+  // callback.
+  StackSamplingProfiler(PlatformThreadId thread_id,
+                        const SamplingParams& params);
+  // Creates a profiler that sends completed profiles to |completed_callback|.
+  StackSamplingProfiler(PlatformThreadId thread_id,
+                        const SamplingParams& params,
+                        CompletedCallback callback);
+  ~StackSamplingProfiler();
+
+  // Initializes the profiler and starts sampling.
+  void Start();
+
+  // Stops the profiler and any ongoing sampling. Calling this function is
+  // optional; if not invoked profiling terminates when all the profiling bursts
+  // specified in the SamplingParams are completed.
+  void Stop();
+
+  // Sets a callback to process profiles collected by profiler instances without
+  // a completed callback. Profiles are queued internally until a non-null
+  // callback is provided to this function,
+  //
+  // The callback is typically called on a thread created by the profiler.  If
+  // completed profiles are queued when set, however, it will also be called
+  // immediately on the calling thread.
+  static void SetDefaultCompletedCallback(CompletedCallback callback);
+
+ private:
+  // SamplingThread is a separate thread used to suspend and sample stacks from
+  // the target thread.
+  class SamplingThread : public PlatformThread::Delegate {
+   public:
+    // Samples stacks using |native_sampler|. When complete, invokes
+    // |completed_callback| with the collected call stack profiles.
+    // |completed_callback| must be callable on any thread.
+    SamplingThread(scoped_ptr<NativeStackSampler> native_sampler,
+                   const SamplingParams& params,
+                   CompletedCallback completed_callback);
+    ~SamplingThread() override;
+
+    // PlatformThread::Delegate:
+    void ThreadMain() override;
+
+    void Stop();
+
+   private:
+    // Collects a call stack profile from a single burst. Returns true if the
+    // profile was collected, or false if collection was stopped before it
+    // completed.
+    bool CollectProfile(CallStackProfile* profile, TimeDelta* elapsed_time);
+
+    // Collects call stack profiles from all bursts, or until the sampling is
+    // stopped. If stopped before complete, |call_stack_profiles| will contain
+    // only full bursts.
+    void CollectProfiles(CallStackProfiles* profiles);
+
+    scoped_ptr<NativeStackSampler> native_sampler_;
+    const SamplingParams params_;
+
+    // If Stop() is called, it signals this event to force the sampling to
+    // terminate before all the samples specified in |params_| are collected.
+    WaitableEvent stop_event_;
+
+    const CompletedCallback completed_callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(SamplingThread);
+  };
+
+  // The thread whose stack will be sampled.
+  PlatformThreadId thread_id_;
+
+  const SamplingParams params_;
+
+  scoped_ptr<SamplingThread> sampling_thread_;
+  PlatformThreadHandle sampling_thread_handle_;
+
+  const CompletedCallback completed_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
+};
+
+// The metrics provider code wants to put Samples in a map and compare them,
+// which requires us to define a few operators.
+BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
+                            const StackSamplingProfiler::Frame& b);
+BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
+                           const StackSamplingProfiler::Frame& b);
+
+}  // namespace base
+
+#endif  // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
diff --git a/base/profiler/stack_sampling_profiler_posix.cc b/base/profiler/stack_sampling_profiler_posix.cc
new file mode 100644
index 0000000..bce37e1
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_posix.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/native_stack_sampler.h"
+
+namespace base {
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+    PlatformThreadId thread_id) {
+  return scoped_ptr<NativeStackSampler>();
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
new file mode 100644
index 0000000..5ade15a
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -0,0 +1,445 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/path_service.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+using SamplingParams = StackSamplingProfiler::SamplingParams;
+using Frame = StackSamplingProfiler::Frame;
+using Module = StackSamplingProfiler::Module;
+using Sample = StackSamplingProfiler::Sample;
+using CallStackProfile = StackSamplingProfiler::CallStackProfile;
+using CallStackProfiles = StackSamplingProfiler::CallStackProfiles;
+
+namespace {
+
+// A thread to target for profiling, whose stack is guaranteed to contain
+// SignalAndWaitUntilSignaled() when coordinated with the main thread.
+class TargetThread : public PlatformThread::Delegate {
+ public:
+  TargetThread();
+
+  // PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  // Waits for the thread to have started and be executing in
+  // SignalAndWaitUntilSignaled().
+  void WaitForThreadStart();
+
+  // Allows the thread to return from SignalAndWaitUntilSignaled() and finish
+  // execution.
+  void SignalThreadToFinish();
+
+  // This function is guaranteed to be executing between calls to
+  // WaitForThreadStart() and SignalThreadToFinish(). This function is static so
+  // that we can get a straightforward address for it in one of the tests below,
+  // rather than dealing with the complexity of a member function pointer
+  // representation.
+  static void SignalAndWaitUntilSignaled(WaitableEvent* thread_started_event,
+                                         WaitableEvent* finish_event);
+
+  PlatformThreadId id() const { return id_; }
+
+ private:
+  WaitableEvent thread_started_event_;
+  WaitableEvent finish_event_;
+  PlatformThreadId id_;
+
+  DISALLOW_COPY_AND_ASSIGN(TargetThread);
+};
+
+TargetThread::TargetThread()
+    : thread_started_event_(false, false), finish_event_(false, false),
+      id_(0) {}
+
+void TargetThread::ThreadMain() {
+  id_ = PlatformThread::CurrentId();
+  SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_);
+}
+
+void TargetThread::WaitForThreadStart() {
+  thread_started_event_.Wait();
+}
+
+void TargetThread::SignalThreadToFinish() {
+  finish_event_.Signal();
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
+    WaitableEvent* thread_started_event,
+    WaitableEvent* finish_event) {
+  thread_started_event->Signal();
+  volatile int x = 1;
+  finish_event->Wait();
+  x = 0;  // Prevent tail call to WaitableEvent::Wait().
+  ALLOW_UNUSED_LOCAL(x);
+}
+
+// Called on the profiler thread when complete, to collect profiles.
+void SaveProfiles(CallStackProfiles* profiles,
+                  const CallStackProfiles& pending_profiles) {
+  *profiles = pending_profiles;
+}
+
+// Called on the profiler thread when complete. Collects profiles produced by
+// the profiler, and signals an event to allow the main thread to know that that
+// the profiler is done.
+void SaveProfilesAndSignalEvent(CallStackProfiles* profiles,
+                                WaitableEvent* event,
+                                const CallStackProfiles& pending_profiles) {
+  *profiles = pending_profiles;
+  event->Signal();
+}
+
+// Executes the function with the target thread running and executing within
+// SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
+// and shutdown work before and afterward.
+template <class Function>
+void WithTargetThread(Function function) {
+  TargetThread target_thread;
+  PlatformThreadHandle target_thread_handle;
+  EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
+
+  target_thread.WaitForThreadStart();
+
+  function(target_thread.id());
+
+  target_thread.SignalThreadToFinish();
+
+  PlatformThread::Join(target_thread_handle);
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Waits up to |profiler_wait_time| for the profiler to
+// complete.
+void CaptureProfilesWithObjectCallback(const SamplingParams& params,
+                                       CallStackProfiles* profiles,
+                                       TimeDelta profiler_wait_time) {
+  profiles->clear();
+
+  WithTargetThread([&params, profiles, profiler_wait_time](
+      PlatformThreadId target_thread_id) {
+    WaitableEvent sampling_thread_completed(true, false);
+    const StackSamplingProfiler::CompletedCallback callback =
+        Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+             Unretained(&sampling_thread_completed));
+    StackSamplingProfiler profiler(target_thread_id, params, callback);
+    profiler.Start();
+    sampling_thread_completed.TimedWait(profiler_wait_time);
+    profiler.Stop();
+    sampling_thread_completed.Wait();
+  });
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Uses the default callback rather than a per-object
+// callback.
+void CaptureProfilesWithDefaultCallback(const SamplingParams& params,
+                                        CallStackProfiles* profiles) {
+  profiles->clear();
+
+  WithTargetThread([&params, profiles](PlatformThreadId target_thread_id) {
+    WaitableEvent sampling_thread_completed(false, false);
+    StackSamplingProfiler::SetDefaultCompletedCallback(
+        Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+             Unretained(&sampling_thread_completed)));
+
+    StackSamplingProfiler profiler(target_thread_id, params);
+    profiler.Start();
+    sampling_thread_completed.Wait();
+
+    StackSamplingProfiler::SetDefaultCompletedCallback(
+        StackSamplingProfiler::CompletedCallback());
+  });
+}
+
+// Runs the profiler with |params| on the TargetThread, with no default or
+// per-object callback.
+void RunProfilerWithNoCallback(const SamplingParams& params,
+                               TimeDelta profiler_wait_time) {
+  WithTargetThread([&params, profiler_wait_time](
+      PlatformThreadId target_thread_id) {
+    StackSamplingProfiler profiler(target_thread_id, params);
+    profiler.Start();
+    // Since we don't specify a callback, we don't have a synchronization
+    // mechanism with the sampling thread. Just sleep instead.
+    PlatformThread::Sleep(profiler_wait_time);
+    profiler.Stop();
+  });
+}
+
+// If this executable was linked with /INCREMENTAL (the default for non-official
+// debug and release builds on Windows), function addresses do not correspond to
+// function code itself, but instead to instructions in the Incremental Link
+// Table that jump to the functions. Checks for a jump instruction and if
+// present does a little decompilation to find the function's actual starting
+// address.
+const void* MaybeFixupFunctionAddressForILT(const void* function_address) {
+#if defined(_WIN64)
+  const unsigned char* opcode =
+      reinterpret_cast<const unsigned char*>(function_address);
+  if (*opcode == 0xe9) {
+    // This is a relative jump instruction. Assume we're in the ILT and compute
+    // the function start address from the instruction offset.
+    const int32* offset = reinterpret_cast<const int32*>(opcode + 1);
+    const unsigned char* next_instruction =
+        reinterpret_cast<const unsigned char*>(offset + 1);
+    return next_instruction + *offset;
+  }
+#endif
+  return function_address;
+}
+
+// Searches through the frames in |sample|, returning an iterator to the first
+// frame that has an instruction pointer between |function_address| and
+// |function_address| + |size|. Returns sample.end() if no such frames are
+// found.
+Sample::const_iterator FindFirstFrameWithinFunction(
+    const Sample& sample,
+    const void* function_address,
+    int function_size) {
+  function_address = MaybeFixupFunctionAddressForILT(function_address);
+  for (auto it = sample.begin(); it != sample.end(); ++it) {
+    if ((it->instruction_pointer >= function_address) &&
+        (it->instruction_pointer <
+         (static_cast<const unsigned char*>(function_address) + function_size)))
+      return it;
+  }
+  return sample.end();
+}
+
+// Formats a sample into a string that can be output for test diagnostics.
+std::string FormatSampleForDiagnosticOutput(
+    const Sample& sample,
+    const std::vector<Module>& modules) {
+  std::string output;
+  for (const Frame& frame: sample) {
+    output += StringPrintf(
+        "0x%p %s\n", frame.instruction_pointer,
+        modules[frame.module_index].filename.AsUTF8Unsafe().c_str());
+  }
+  return output;
+}
+
+// Returns a duration that is longer than the test timeout. We would use
+// TimeDelta::Max() but https://crbug.com/465948.
+TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
+
+}  // namespace
+
+
+// The tests below are enabled for Win x64 only, pending implementation of the
+// tested functionality on other platforms/architectures.
+
+// Checks that the basic expected information is present in a sampled call stack
+// profile.
+#if defined(_WIN64)
+#define MAYBE_Basic Basic
+#else
+#define MAYBE_Basic DISABLED_Basic
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_Basic) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_burst = 1;
+  params.user_data = 100;
+  params.preserve_sample_ordering = true;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+
+  // Check that the profile and samples sizes are correct, and the module
+  // indices are in range.
+  ASSERT_EQ(1u, profiles.size());
+  const CallStackProfile& profile = profiles[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  EXPECT_EQ(params.sampling_interval, profile.sampling_period);
+  const Sample& sample = profile.samples[0];
+  for (const auto& frame : sample) {
+    ASSERT_GE(frame.module_index, 0u);
+    ASSERT_LT(frame.module_index, profile.modules.size());
+  }
+  EXPECT_EQ(100u, profile.user_data);
+  EXPECT_EQ(true, profile.preserve_sample_ordering);
+
+  // Check that the stack contains a frame for
+  // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
+  // executable's module.
+  //
+  // Since we don't have a good way to know the function size, use 100 bytes as
+  // a reasonable window to locate the instruction pointer.
+  Sample::const_iterator loc = FindFirstFrameWithinFunction(
+      sample,
+      reinterpret_cast<const void*>(&TargetThread::SignalAndWaitUntilSignaled),
+      100);
+  ASSERT_TRUE(loc != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(
+          reinterpret_cast<const void*>(
+              &TargetThread::SignalAndWaitUntilSignaled))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+  FilePath executable_path;
+  EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path));
+  EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
+}
+
+// Checks that the expected number of profiles and samples are present in the
+// call stack profiles produced.
+#if defined(_WIN64)
+#define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
+#else
+#define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) {
+  SamplingParams params;
+  params.burst_interval = params.sampling_interval =
+      TimeDelta::FromMilliseconds(0);
+  params.bursts = 2;
+  params.samples_per_burst = 3;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+
+  ASSERT_EQ(2u, profiles.size());
+  EXPECT_EQ(3u, profiles[0].samples.size());
+  EXPECT_EQ(3u, profiles[1].samples.size());
+}
+
+// Checks that no call stack profiles are captured if the profiling is stopped
+// during the initial delay.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
+#else
+#define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) {
+  SamplingParams params;
+  params.initial_delay = TimeDelta::FromSeconds(60);
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles,
+                                    TimeDelta::FromMilliseconds(0));
+
+  EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that the single completed call stack profile is captured if the
+// profiling is stopped between bursts.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
+#else
+#define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.burst_interval = TimeDelta::FromSeconds(60);
+  params.bursts = 2;
+  params.samples_per_burst = 1;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles,
+                                    TimeDelta::FromMilliseconds(50));
+
+  ASSERT_EQ(1u, profiles.size());
+  EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that only completed call stack profiles are captured.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
+#else
+#define MAYBE_StopDuringInterSampleInterval \
+  DISABLED_StopDuringInterSampleInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromSeconds(60);
+  params.samples_per_burst = 2;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles,
+                                    TimeDelta::FromMilliseconds(50));
+
+  EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that profiles are captured via the default completed callback.
+#if defined(_WIN64)
+#define MAYBE_DefaultCallback DefaultCallback
+#else
+#define MAYBE_DefaultCallback DISABLED_DefaultCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DefaultCallback) {
+  SamplingParams params;
+  params.samples_per_burst = 1;
+
+  CallStackProfiles profiles;
+  CaptureProfilesWithDefaultCallback(params, &profiles);
+
+  EXPECT_EQ(1u, profiles.size());
+  EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that profiles are queued until a default callback is set, then
+// delivered.
+#if defined(_WIN64)
+#define MAYBE_ProfilesQueuedWithNoCallback ProfilesQueuedWithNoCallback
+#else
+#define MAYBE_ProfilesQueuedWithNoCallback DISABLED_ProfilesQueuedWithNoCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_ProfilesQueuedWithNoCallback) {
+  SamplingParams params;
+  params.samples_per_burst = 1;
+
+  RunProfilerWithNoCallback(params, TimeDelta::FromMilliseconds(50));
+
+  CallStackProfiles profiles;
+  // This should immediately call SaveProfiles on this thread.
+  StackSamplingProfiler::SetDefaultCompletedCallback(
+      Bind(&SaveProfiles, Unretained(&profiles)));
+  EXPECT_EQ(1u, profiles.size());
+  EXPECT_EQ(1u, profiles[0].samples.size());
+  StackSamplingProfiler::SetDefaultCompletedCallback(
+      StackSamplingProfiler::CompletedCallback());
+}
+
+// Checks that we can destroy the profiler while profiling.
+#if defined(_WIN64)
+#define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling
+#else
+#define MAYBE_DestroyProfilerWhileProfiling \
+  DISABLED_DestroyProfilerWhileProfiling
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DestroyProfilerWhileProfiling) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(10);
+
+  CallStackProfiles profiles;
+  WithTargetThread([&params, &profiles](PlatformThreadId target_thread_id) {
+    scoped_ptr<StackSamplingProfiler> profiler;
+    profiler.reset(new StackSamplingProfiler(
+        target_thread_id, params, Bind(&SaveProfiles, Unretained(&profiles))));
+    profiler->Start();
+    profiler.reset();
+
+    // Wait longer than a sample interval to catch any use-after-free actions by
+    // the profiler thread.
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
+  });
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler_win.cc b/base/profiler/stack_sampling_profiler_win.cc
new file mode 100644
index 0000000..1ccd134
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_win.cc
@@ -0,0 +1,357 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <objbase.h>
+#include <windows.h>
+
+#include <map>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/win/pe_image.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+namespace {
+
+// Walks the stack represented by |context| from the current frame downwards,
+// recording the instruction pointers for each frame in |instruction_pointers|.
+int RecordStack(CONTEXT* context,
+                int max_stack_size,
+                const void* instruction_pointers[],
+                bool* last_frame_is_unknown_function) {
+#ifdef _WIN64
+  *last_frame_is_unknown_function = false;
+
+  int i = 0;
+  for (; (i < max_stack_size) && context->Rip; ++i) {
+    // Try to look up unwind metadata for the current function.
+    ULONG64 image_base;
+    PRUNTIME_FUNCTION runtime_function =
+        RtlLookupFunctionEntry(context->Rip, &image_base, nullptr);
+
+    instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
+
+    if (runtime_function) {
+      KNONVOLATILE_CONTEXT_POINTERS nvcontext = {0};
+      void* handler_data;
+      ULONG64 establisher_frame;
+      RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
+                       &handler_data, &establisher_frame, &nvcontext);
+    } else {
+      // If we don't have a RUNTIME_FUNCTION, then in theory this should be a
+      // leaf function whose frame contains only a return address, at
+      // RSP. However, crash data also indicates that some third party libraries
+      // do not provide RUNTIME_FUNCTION information for non-leaf functions. We
+      // could manually unwind the stack in the former case, but attempting to
+      // do so in the latter case would produce wrong results and likely crash,
+      // so just bail out.
+      //
+      // Ad hoc runs with instrumentation show that ~5% of stack traces end with
+      // a valid leaf function. To avoid selectively omitting these traces it
+      // makes sense to ultimately try to distinguish these two cases and
+      // selectively unwind the stack for legitimate leaf functions. For the
+      // purposes of avoiding crashes though, just ignore them all for now.
+      return i;
+    }
+  }
+  return i;
+#else
+  return 0;
+#endif
+}
+
+// Fills in |module_handles| corresponding to the pointers to code in
+// |addresses|. The module handles are returned with reference counts
+// incremented and should be freed with FreeModuleHandles. See note in
+// SuspendThreadAndRecordStack for why |addresses| and |module_handles| are
+// arrays.
+void FindModuleHandlesForAddresses(const void* const addresses[],
+                             HMODULE module_handles[], int stack_depth,
+                             bool last_frame_is_unknown_function) {
+  const int module_frames =
+      last_frame_is_unknown_function ? stack_depth - 1 : stack_depth;
+  for (int i = 0; i < module_frames; ++i) {
+    HMODULE module_handle = NULL;
+    if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                          reinterpret_cast<LPCTSTR>(addresses[i]),
+                          &module_handle)) {
+      // HMODULE actually represents the base address of the module, so we can
+      // use it directly as an address.
+      DCHECK_LE(reinterpret_cast<const void*>(module_handle), addresses[i]);
+      module_handles[i] = module_handle;
+    }
+  }
+}
+
+// Frees the modules handles returned by FindModuleHandlesForAddresses. See note
+// in SuspendThreadAndRecordStack for why |module_handles| is an array.
+void FreeModuleHandles(int stack_depth, HMODULE module_handles[]) {
+  for (int i = 0; i < stack_depth; ++i) {
+    if (module_handles[i])
+      ::FreeLibrary(module_handles[i]);
+  }
+}
+
+// Gets the unique build ID for a module. Windows build IDs are created by a
+// concatenation of a GUID and AGE fields found in the headers of a module. The
+// GUID is stored in the first 16 bytes and the AGE is stored in the last 4
+// bytes. Returns the empty string if the function fails to get the build ID.
+//
+// Example:
+// dumpbin chrome.exe /headers | find "Format:"
+//   ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
+//
+// The resulting buildID string of this instance of chrome.exe is
+// "16B2A4281DED442E9A36FCE8CBD2972610".
+//
+// Note that the AGE field is encoded in decimal, not hex.
+std::string GetBuildIDForModule(HMODULE module_handle) {
+  GUID guid;
+  DWORD age;
+  win::PEImage(module_handle).GetDebugId(&guid, &age);
+  const int kGUIDSize = 39;
+  std::wstring build_id;
+  int result =
+      ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize);
+  if (result != kGUIDSize)
+    return std::string();
+  RemoveChars(build_id, L"{}-", &build_id);
+  build_id += StringPrintf(L"%d", age);
+  return WideToUTF8(build_id);
+}
+
+// Disables priority boost on a thread for the lifetime of the object.
+class ScopedDisablePriorityBoost {
+ public:
+  ScopedDisablePriorityBoost(HANDLE thread_handle);
+  ~ScopedDisablePriorityBoost();
+
+ private:
+  HANDLE thread_handle_;
+  BOOL got_previous_boost_state_;
+  BOOL boost_state_was_disabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedDisablePriorityBoost);
+};
+
+ScopedDisablePriorityBoost::ScopedDisablePriorityBoost(HANDLE thread_handle)
+    : thread_handle_(thread_handle),
+      got_previous_boost_state_(false),
+      boost_state_was_disabled_(false) {
+  got_previous_boost_state_ =
+      ::GetThreadPriorityBoost(thread_handle_, &boost_state_was_disabled_);
+  if (got_previous_boost_state_) {
+    // Confusingly, TRUE disables priority boost.
+    ::SetThreadPriorityBoost(thread_handle_, TRUE);
+  }
+}
+
+ScopedDisablePriorityBoost::~ScopedDisablePriorityBoost() {
+  if (got_previous_boost_state_)
+    ::SetThreadPriorityBoost(thread_handle_, boost_state_was_disabled_);
+}
+
+// Suspends the thread with |thread_handle|, records the stack into
+// |instruction_pointers|, then resumes the thread. Returns the size of the
+// stack.
+//
+// IMPORTANT NOTE: No heap allocations may occur between SuspendThread and
+// ResumeThread. Otherwise this code can deadlock on heap locks acquired by the
+// target thread before it was suspended. This is why we pass instruction
+// pointers and module handles as preallocated arrays rather than vectors, since
+// vectors make it too easy to subtly allocate memory.
+int SuspendThreadAndRecordStack(HANDLE thread_handle, int max_stack_size,
+                                const void* instruction_pointers[],
+                                bool* last_frame_is_unknown_function) {
+  if (::SuspendThread(thread_handle) == -1)
+    return 0;
+
+  int stack_depth = 0;
+  CONTEXT thread_context = {0};
+  thread_context.ContextFlags = CONTEXT_FULL;
+  if (::GetThreadContext(thread_handle, &thread_context)) {
+    stack_depth = RecordStack(&thread_context, max_stack_size,
+                              instruction_pointers,
+                              last_frame_is_unknown_function);
+  }
+
+  // Disable the priority boost that the thread would otherwise receive on
+  // resume. We do this to avoid artificially altering the dynamics of the
+  // executing application any more than we already are by suspending and
+  // resuming the thread.
+  //
+  // Note that this can racily disable a priority boost that otherwise would
+  // have been given to the thread, if the thread is waiting on other wait
+  // conditions at the time of SuspendThread and those conditions are satisfied
+  // before priority boost is reenabled. The measured length of this window is
+  // ~100us, so this should occur fairly rarely.
+  ScopedDisablePriorityBoost disable_priority_boost(thread_handle);
+  bool resume_thread_succeeded = ::ResumeThread(thread_handle) != -1;
+  CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
+
+  return stack_depth;
+}
+
+class NativeStackSamplerWin : public NativeStackSampler {
+ public:
+  explicit NativeStackSamplerWin(win::ScopedHandle thread_handle);
+  ~NativeStackSamplerWin() override;
+
+  // StackSamplingProfiler::NativeStackSampler:
+  void ProfileRecordingStarting(
+      std::vector<StackSamplingProfiler::Module>* modules) override;
+  void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
+  void ProfileRecordingStopped() override;
+
+ private:
+  // Attempts to query the module filename, base address, and id for
+  // |module_handle|, and store them in |module|. Returns true if it succeeded.
+  static bool GetModuleForHandle(HMODULE module_handle,
+                                 StackSamplingProfiler::Module* module);
+
+  // Gets the index for the Module corresponding to |module_handle| in
+  // |modules|, adding it if it's not already present. Returns
+  // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
+  // determined for |module|.
+  size_t GetModuleIndex(HMODULE module_handle,
+                        std::vector<StackSamplingProfiler::Module>* modules);
+
+  // Copies the stack information represented by |instruction_pointers| into
+  // |sample| and |modules|.
+  void CopyToSample(const void* const instruction_pointers[],
+                    const HMODULE module_handles[],
+                    int stack_depth,
+                    StackSamplingProfiler::Sample* sample,
+                    std::vector<StackSamplingProfiler::Module>* modules);
+
+  win::ScopedHandle thread_handle_;
+  // Weak. Points to the modules associated with the profile being recorded
+  // between ProfileRecordingStarting() and ProfileRecordingStopped().
+  std::vector<StackSamplingProfiler::Module>* current_modules_;
+  // Maps a module handle to the corresponding Module's index within
+  // current_modules_.
+  std::map<HMODULE, size_t> profile_module_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
+};
+
+NativeStackSamplerWin::NativeStackSamplerWin(win::ScopedHandle thread_handle)
+    : thread_handle_(thread_handle.Take()) {
+}
+
+NativeStackSamplerWin::~NativeStackSamplerWin() {
+}
+
+void NativeStackSamplerWin::ProfileRecordingStarting(
+    std::vector<StackSamplingProfiler::Module>* modules) {
+  current_modules_ = modules;
+  profile_module_index_.clear();
+}
+
+void NativeStackSamplerWin::RecordStackSample(
+    StackSamplingProfiler::Sample* sample) {
+  DCHECK(current_modules_);
+
+  const int max_stack_size = 64;
+  const void* instruction_pointers[max_stack_size] = {0};
+  HMODULE module_handles[max_stack_size] = {0};
+
+  bool last_frame_is_unknown_function = false;
+  int stack_depth = SuspendThreadAndRecordStack(
+      thread_handle_.Get(), max_stack_size, instruction_pointers,
+      &last_frame_is_unknown_function);
+  FindModuleHandlesForAddresses(instruction_pointers, module_handles,
+                                stack_depth, last_frame_is_unknown_function);
+  CopyToSample(instruction_pointers, module_handles, stack_depth, sample,
+               current_modules_);
+  FreeModuleHandles(stack_depth, module_handles);
+}
+
+void NativeStackSamplerWin::ProfileRecordingStopped() {
+  current_modules_ = nullptr;
+}
+
+// static
+bool NativeStackSamplerWin::GetModuleForHandle(
+    HMODULE module_handle,
+    StackSamplingProfiler::Module* module) {
+  wchar_t module_name[MAX_PATH];
+  DWORD result_length =
+      GetModuleFileName(module_handle, module_name, arraysize(module_name));
+  if (result_length == 0)
+    return false;
+
+  module->filename = base::FilePath(module_name);
+
+  module->base_address = reinterpret_cast<const void*>(module_handle);
+
+  module->id = GetBuildIDForModule(module_handle);
+  if (module->id.empty())
+    return false;
+
+  return true;
+}
+
+size_t NativeStackSamplerWin::GetModuleIndex(
+    HMODULE module_handle,
+    std::vector<StackSamplingProfiler::Module>* modules) {
+  if (!module_handle)
+    return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+
+  auto loc = profile_module_index_.find(module_handle);
+  if (loc == profile_module_index_.end()) {
+    StackSamplingProfiler::Module module;
+    if (!GetModuleForHandle(module_handle, &module))
+      return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+    modules->push_back(module);
+    loc = profile_module_index_.insert(std::make_pair(
+        module_handle, modules->size() - 1)).first;
+  }
+
+  return loc->second;
+}
+
+void NativeStackSamplerWin::CopyToSample(
+    const void* const instruction_pointers[],
+    const HMODULE module_handles[],
+    int stack_depth,
+    StackSamplingProfiler::Sample* sample,
+    std::vector<StackSamplingProfiler::Module>* module) {
+  sample->clear();
+  sample->reserve(stack_depth);
+
+  for (int i = 0; i < stack_depth; ++i) {
+    sample->push_back(StackSamplingProfiler::Frame(
+        instruction_pointers[i],
+        GetModuleIndex(module_handles[i], module)));
+  }
+}
+
+}  // namespace
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+    PlatformThreadId thread_id) {
+#if _WIN64
+  // Get the thread's handle.
+  HANDLE thread_handle = ::OpenThread(
+      THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
+      FALSE,
+      thread_id);
+
+  if (thread_handle) {
+    return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin(
+        win::ScopedHandle(thread_handle)));
+  }
+#endif
+  return scoped_ptr<NativeStackSampler>();
+}
+
+}  // namespace base
diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc
new file mode 100644
index 0000000..e5da68f
--- /dev/null
+++ b/base/profiler/tracked_time.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/tracked_time.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <mmsystem.h>  // Declare timeGetTime()... after including build_config.
+#endif
+
+namespace tracked_objects {
+
+Duration::Duration() : ms_(0) {}
+Duration::Duration(int32 duration) : ms_(duration) {}
+
+Duration& Duration::operator+=(const Duration& other) {
+  ms_ += other.ms_;
+  return *this;
+}
+
+Duration Duration::operator+(const Duration& other) const {
+  return Duration(ms_ + other.ms_);
+}
+
+bool Duration::operator==(const Duration& other) const {
+  return ms_ == other.ms_;
+}
+
+bool Duration::operator!=(const Duration& other) const {
+  return ms_ != other.ms_;
+}
+
+bool Duration::operator>(const Duration& other) const {
+  return ms_ > other.ms_;
+}
+
+// static
+Duration Duration::FromMilliseconds(int ms) { return Duration(ms); }
+
+int32 Duration::InMilliseconds() const { return ms_; }
+
+//------------------------------------------------------------------------------
+
+TrackedTime::TrackedTime() : ms_(0) {}
+TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
+TrackedTime::TrackedTime(const base::TimeTicks& time)
+    : ms_(static_cast<int32>((time - base::TimeTicks()).InMilliseconds())) {
+}
+
+// static
+TrackedTime TrackedTime::Now() {
+  return TrackedTime(base::TimeTicks::Now());
+}
+
+Duration TrackedTime::operator-(const TrackedTime& other) const {
+  return Duration(ms_ - other.ms_);
+}
+
+TrackedTime TrackedTime::operator+(const Duration& other) const {
+  return TrackedTime(ms_ + other.ms_);
+}
+
+bool TrackedTime::is_null() const { return ms_ == 0; }
+
+}  // namespace tracked_objects
diff --git a/base/profiler/tracked_time.h b/base/profiler/tracked_time.h
new file mode 100644
index 0000000..2363274
--- /dev/null
+++ b/base/profiler/tracked_time.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROFILER_TRACKED_TIME_H_
+#define BASE_PROFILER_TRACKED_TIME_H_
+
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/time/time.h"
+
+namespace tracked_objects {
+
+//------------------------------------------------------------------------------
+
+// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on
+// windows, a 64 bit timer is expensive to even obtain. We use a simple
+// millisecond counter for most of our time values, as well as millisecond units
+// of duration between those values.  This means we can only handle durations
+// up to 49 days (range), or 24 days (non-negative time durations).
+// We only define enough methods to service the needs of the tracking classes,
+// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we
+// can swap them into place if we want to use the "real" classes).
+
+class BASE_EXPORT Duration {  // Similar to base::TimeDelta.
+ public:
+  Duration();
+
+  Duration& operator+=(const Duration& other);
+  Duration operator+(const Duration& other) const;
+
+  bool operator==(const Duration& other) const;
+  bool operator!=(const Duration& other) const;
+  bool operator>(const Duration& other) const;
+
+  static Duration FromMilliseconds(int ms);
+
+  int32 InMilliseconds() const;
+
+ private:
+  friend class TrackedTime;
+  explicit Duration(int32 duration);
+
+  // Internal time is stored directly in milliseconds.
+  int32 ms_;
+};
+
+class BASE_EXPORT TrackedTime {  // Similar to base::TimeTicks.
+ public:
+  TrackedTime();
+  explicit TrackedTime(const base::TimeTicks& time);
+
+  static TrackedTime Now();
+  Duration operator-(const TrackedTime& other) const;
+  TrackedTime operator+(const Duration& other) const;
+  bool is_null() const;
+
+  static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
+
+ private:
+  friend class Duration;
+  explicit TrackedTime(int32 ms);
+
+  // Internal duration is stored directly in milliseconds.
+  uint32 ms_;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_TRACKED_TIME_H_
diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc
new file mode 100644
index 0000000..c105688
--- /dev/null
+++ b/base/profiler/tracked_time_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test of classes in tracked_time.cc
+
+#include "base/profiler/tracked_time.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracked_objects {
+
+TEST(TrackedTimeTest, TrackedTimerMilliseconds) {
+  // First make sure we basicallly transfer simple milliseconds values as
+  // expected.  Most critically, things should not become null.
+  int32 kSomeMilliseconds = 243;  // Some example times.
+  int64 kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds;
+
+  TrackedTime some = TrackedTime() +
+      Duration::FromMilliseconds(kSomeMilliseconds);
+  EXPECT_EQ(kSomeMilliseconds, (some - TrackedTime()).InMilliseconds());
+  EXPECT_FALSE(some.is_null());
+
+  // Now create a big time, to check that it is wrapped modulo 2^32.
+  base::TimeTicks big = base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(kReallyBigMilliseconds);
+  EXPECT_EQ(kReallyBigMilliseconds, (big - base::TimeTicks()).InMilliseconds());
+
+  TrackedTime wrapped_big(big);
+  // Expect wrapping at 32 bits.
+  EXPECT_EQ(kSomeMilliseconds, (wrapped_big - TrackedTime()).InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerDuration) {
+  int kFirstMilliseconds = 793;
+  int kSecondMilliseconds = 14889;
+
+  Duration first = Duration::FromMilliseconds(kFirstMilliseconds);
+  Duration second = Duration::FromMilliseconds(kSecondMilliseconds);
+
+  EXPECT_EQ(kFirstMilliseconds, first.InMilliseconds());
+  EXPECT_EQ(kSecondMilliseconds, second.InMilliseconds());
+
+  Duration sum = first + second;
+  EXPECT_EQ(kFirstMilliseconds + kSecondMilliseconds, sum.InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerVsTimeTicks) {
+  // Make sure that our 32 bit timer is aligned with the TimeTicks() timer.
+
+  // First get a 64 bit timer (which should not be null).
+  base::TimeTicks ticks_before = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_before.is_null());
+
+  // Then get a 32 bit timer that can be be null when it wraps.
+  TrackedTime now = TrackedTime::Now();
+
+  // Then get a bracketing time.
+  base::TimeTicks ticks_after = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_after.is_null());
+
+  // Now make sure that we bracketed our tracked time nicely.
+  Duration before = now - TrackedTime(ticks_before);
+  EXPECT_LE(0, before.InMilliseconds());
+  Duration after = now - TrackedTime(ticks_after);
+  EXPECT_GE(0, after.InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerDisabled) {
+  // Check to be sure disabling the collection of data induces a null time
+  // (which we know will return much faster).
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+  // Since we disabled tracking, we should get a null response.
+  TrackedTime track_now = ThreadData::Now();
+  EXPECT_TRUE(track_now.is_null());
+}
+
+TEST(TrackedTimeTest, TrackedTimerEnabled) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+  // Make sure that when we enable tracking, we get a real timer result.
+
+  // First get a 64 bit timer (which should not be null).
+  base::TimeTicks ticks_before = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_before.is_null());
+
+  // Then get a 32 bit timer that can be null when it wraps.
+  // Crtical difference from  the TrackedTimerVsTimeTicks test, is that we use
+  // ThreadData::Now().  It can sometimes return the null time.
+  TrackedTime now = ThreadData::Now();
+
+  // Then get a bracketing time.
+  base::TimeTicks ticks_after = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_after.is_null());
+
+  // Now make sure that we bracketed our tracked time nicely.
+  Duration before = now - TrackedTime(ticks_before);
+  EXPECT_LE(0, before.InMilliseconds());
+  Duration after = now - TrackedTime(ticks_after);
+  EXPECT_GE(0, after.InMilliseconds());
+}
+
+}  // namespace tracked_objects
diff --git a/base/rand_util.cc b/base/rand_util.cc
new file mode 100644
index 0000000..1525b91
--- /dev/null
+++ b/base/rand_util.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+int RandInt(int min, int max) {
+  DCHECK_LE(min, max);
+
+  uint64 range = static_cast<uint64>(max) - min + 1;
+  int result = min + static_cast<int>(base::RandGenerator(range));
+  DCHECK_GE(result, min);
+  DCHECK_LE(result, max);
+  return result;
+}
+
+double RandDouble() {
+  return BitsToOpenEndedUnitInterval(base::RandUint64());
+}
+
+double BitsToOpenEndedUnitInterval(uint64 bits) {
+  // We try to get maximum precision by masking out as many bits as will fit
+  // in the target type's mantissa, and raising it to an appropriate power to
+  // produce output in the range [0, 1).  For IEEE 754 doubles, the mantissa
+  // is expected to accommodate 53 bits.
+
+  COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn);
+  static const int kBits = std::numeric_limits<double>::digits;
+  uint64 random_bits = bits & ((GG_UINT64_C(1) << kBits) - 1);
+  double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
+  DCHECK_GE(result, 0.0);
+  DCHECK_LT(result, 1.0);
+  return result;
+}
+
+uint64 RandGenerator(uint64 range) {
+  DCHECK_GT(range, 0u);
+  // We must discard random results above this number, as they would
+  // make the random generator non-uniform (consider e.g. if
+  // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice
+  // as likely as a result of 3 or 4).
+  uint64 max_acceptable_value =
+      (std::numeric_limits<uint64>::max() / range) * range - 1;
+
+  uint64 value;
+  do {
+    value = base::RandUint64();
+  } while (value > max_acceptable_value);
+
+  return value % range;
+}
+
+std::string RandBytesAsString(size_t length) {
+  DCHECK_GT(length, 0u);
+  std::string result;
+  RandBytes(WriteInto(&result, length + 1), length);
+  return result;
+}
+
+}  // namespace base
diff --git a/base/rand_util.h b/base/rand_util.h
new file mode 100644
index 0000000..6130c12
--- /dev/null
+++ b/base/rand_util.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_RAND_UTIL_H_
+#define BASE_RAND_UTIL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+// Returns a random number in range [0, kuint64max]. Thread-safe.
+BASE_EXPORT uint64 RandUint64();
+
+// Returns a random number between min and max (inclusive). Thread-safe.
+BASE_EXPORT int RandInt(int min, int max);
+
+// Returns a random number in range [0, range).  Thread-safe.
+//
+// Note that this can be used as an adapter for std::random_shuffle():
+// Given a pre-populated |std::vector<int> myvector|, shuffle it as
+//   std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
+BASE_EXPORT uint64 RandGenerator(uint64 range);
+
+// Returns a random double in range [0, 1). Thread-safe.
+BASE_EXPORT double RandDouble();
+
+// Given input |bits|, convert with maximum precision to a double in
+// the range [0, 1). Thread-safe.
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
+
+// Fills |output_length| bytes of |output| with random data.
+//
+// WARNING:
+// Do not use for security-sensitive purposes.
+// See crypto/ for cryptographically secure random number generation APIs.
+BASE_EXPORT void RandBytes(void* output, size_t output_length);
+
+// Fills a string of length |length| with random data and returns it.
+// |length| should be nonzero.
+//
+// Note that this is a variation of |RandBytes| with a different return type.
+// The returned string is likely not ASCII/UTF-8. Use with care.
+//
+// WARNING:
+// Do not use for security-sensitive purposes.
+// See crypto/ for cryptographically secure random number generation APIs.
+BASE_EXPORT std::string RandBytesAsString(size_t length);
+
+#if defined(OS_POSIX)
+BASE_EXPORT int GetUrandomFD();
+#endif
+
+}  // namespace base
+
+#endif  // BASE_RAND_UTIL_H_
diff --git a/base/rand_util_nacl.cc b/base/rand_util_nacl.cc
new file mode 100644
index 0000000..b771dc4
--- /dev/null
+++ b/base/rand_util_nacl.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <nacl/nacl_random.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace {
+
+void GetRandomBytes(void* output, size_t num_bytes) {
+  char* output_ptr = static_cast<char*>(output);
+  while (num_bytes > 0) {
+    size_t nread;
+    const int error = nacl_secure_random(output_ptr, num_bytes, &nread);
+    CHECK_EQ(error, 0);
+    CHECK_LE(nread, num_bytes);
+    output_ptr += nread;
+    num_bytes -= nread;
+  }
+}
+
+}  // namespace
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 result;
+  GetRandomBytes(&result, sizeof(result));
+  return result;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  GetRandomBytes(output, output_length);
+}
+
+}  // namespace base
diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc
new file mode 100644
index 0000000..fe73b96
--- /dev/null
+++ b/base/rand_util_posix.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+
+namespace {
+
+// We keep the file descriptor for /dev/urandom around so we don't need to
+// reopen it (which is expensive), and since we may not even be able to reopen
+// it if we are later put in a sandbox. This class wraps the file descriptor so
+// we can use LazyInstance to handle opening it on the first access.
+class URandomFd {
+ public:
+  URandomFd() : fd_(open("/dev/urandom", O_RDONLY)) {
+    DCHECK_GE(fd_, 0) << "Cannot open /dev/urandom: " << errno;
+  }
+
+  ~URandomFd() { close(fd_); }
+
+  int fd() const { return fd_; }
+
+ private:
+  const int fd_;
+};
+
+base::LazyInstance<URandomFd>::Leaky g_urandom_fd = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 number;
+  RandBytes(&number, sizeof(number));
+  return number;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  const int urandom_fd = g_urandom_fd.Pointer()->fd();
+  const bool success =
+      ReadFromFD(urandom_fd, static_cast<char*>(output), output_length);
+  CHECK(success);
+}
+
+int GetUrandomFD(void) {
+  return g_urandom_fd.Pointer()->fd();
+}
+
+}  // namespace base
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
new file mode 100644
index 0000000..90690ec
--- /dev/null
+++ b/base/rand_util_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kIntMin = std::numeric_limits<int>::min();
+const int kIntMax = std::numeric_limits<int>::max();
+
+}  // namespace
+
+TEST(RandUtilTest, SameMinAndMax) {
+  EXPECT_EQ(base::RandInt(0, 0), 0);
+  EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
+  EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+}
+
+TEST(RandUtilTest, RandDouble) {
+  // Force 64-bit precision, making sure we're not in a 80-bit FPU register.
+  volatile double number = base::RandDouble();
+  EXPECT_GT(1.0, number);
+  EXPECT_LE(0.0, number);
+}
+
+TEST(RandUtilTest, RandBytes) {
+  const size_t buffer_size = 50;
+  char buffer[buffer_size];
+  memset(buffer, 0, buffer_size);
+  base::RandBytes(buffer, buffer_size);
+  std::sort(buffer, buffer + buffer_size);
+  // Probability of occurrence of less than 25 unique bytes in 50 random bytes
+  // is below 10^-25.
+  EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25);
+}
+
+TEST(RandUtilTest, RandBytesAsString) {
+  std::string random_string = base::RandBytesAsString(1);
+  EXPECT_EQ(1U, random_string.size());
+  random_string = base::RandBytesAsString(145);
+  EXPECT_EQ(145U, random_string.size());
+  char accumulator = 0;
+  for (size_t i = 0; i < random_string.size(); ++i)
+    accumulator |= random_string[i];
+  // In theory this test can fail, but it won't before the universe dies of
+  // heat death.
+  EXPECT_NE(0, accumulator);
+}
+
+// Make sure that it is still appropriate to use RandGenerator in conjunction
+// with std::random_shuffle().
+TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
+  EXPECT_EQ(base::RandGenerator(1), 0U);
+  EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
+            std::numeric_limits<int64>::max());
+}
+
+TEST(RandUtilTest, RandGeneratorIsUniform) {
+  // Verify that RandGenerator has a uniform distribution. This is a
+  // regression test that consistently failed when RandGenerator was
+  // implemented this way:
+  //
+  //   return base::RandUint64() % max;
+  //
+  // A degenerate case for such an implementation is e.g. a top of
+  // range that is 2/3rds of the way to MAX_UINT64, in which case the
+  // bottom half of the range would be twice as likely to occur as the
+  // top half. A bit of calculus care of jar@ shows that the largest
+  // measurable delta is when the top of the range is 3/4ths of the
+  // way, so that's what we use in the test.
+  const uint64 kTopOfRange = (std::numeric_limits<uint64>::max() / 4ULL) * 3ULL;
+  const uint64 kExpectedAverage = kTopOfRange / 2ULL;
+  const uint64 kAllowedVariance = kExpectedAverage / 50ULL;  // +/- 2%
+  const int kMinAttempts = 1000;
+  const int kMaxAttempts = 1000000;
+
+  double cumulative_average = 0.0;
+  int count = 0;
+  while (count < kMaxAttempts) {
+    uint64 value = base::RandGenerator(kTopOfRange);
+    cumulative_average = (count * cumulative_average + value) / (count + 1);
+
+    // Don't quit too quickly for things to start converging, or we may have
+    // a false positive.
+    if (count > kMinAttempts &&
+        kExpectedAverage - kAllowedVariance < cumulative_average &&
+        cumulative_average < kExpectedAverage + kAllowedVariance) {
+      break;
+    }
+
+    ++count;
+  }
+
+  ASSERT_LT(count, kMaxAttempts) << "Expected average was " <<
+      kExpectedAverage << ", average ended at " << cumulative_average;
+}
+
+TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) {
+  // This tests to see that our underlying random generator is good
+  // enough, for some value of good enough.
+  uint64 kAllZeros = 0ULL;
+  uint64 kAllOnes = ~kAllZeros;
+  uint64 found_ones = kAllZeros;
+  uint64 found_zeros = kAllOnes;
+
+  for (size_t i = 0; i < 1000; ++i) {
+    uint64 value = base::RandUint64();
+    found_ones |= value;
+    found_zeros &= value;
+
+    if (found_zeros == kAllZeros && found_ones == kAllOnes)
+      return;
+  }
+
+  FAIL() << "Didn't achieve all bit values in maximum number of tries.";
+}
+
+// Benchmark test for RandBytes().  Disabled since it's intentionally slow and
+// does not test anything that isn't already tested by the existing RandBytes()
+// tests.
+TEST(RandUtilTest, DISABLED_RandBytesPerf) {
+  // Benchmark the performance of |kTestIterations| of RandBytes() using a
+  // buffer size of |kTestBufferSize|.
+  const int kTestIterations = 10;
+  const size_t kTestBufferSize = 1 * 1024 * 1024;
+
+  scoped_ptr<uint8[]> buffer(new uint8[kTestBufferSize]);
+  const base::TimeTicks now = base::TimeTicks::Now();
+  for (int i = 0; i < kTestIterations; ++i)
+    base::RandBytes(buffer.get(), kTestBufferSize);
+  const base::TimeTicks end = base::TimeTicks::Now();
+
+  LOG(INFO) << "RandBytes(" << kTestBufferSize << ") took: "
+            << (end - now).InMicroseconds() << "µs";
+}
diff --git a/base/rand_util_win.cc b/base/rand_util_win.cc
new file mode 100644
index 0000000..8573b6b
--- /dev/null
+++ b/base/rand_util_win.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <windows.h>
+
+// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036.  See the
+// "Community Additions" comment on MSDN here:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+#define SystemFunction036 NTAPI SystemFunction036
+#include <NTSecAPI.h>
+#undef SystemFunction036
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 number;
+  RandBytes(&number, sizeof(number));
+  return number;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  char* output_ptr = static_cast<char*>(output);
+  while (output_length > 0) {
+    const ULONG output_bytes_this_pass = static_cast<ULONG>(std::min(
+        output_length, static_cast<size_t>(std::numeric_limits<ULONG>::max())));
+    const bool success =
+        RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE;
+    CHECK(success);
+    output_length -= output_bytes_this_pass;
+    output_ptr += output_bytes_this_pass;
+  }
+}
+
+}  // namespace base
diff --git a/base/run_loop.cc b/base/run_loop.cc
new file mode 100644
index 0000000..2aa4def
--- /dev/null
+++ b/base/run_loop.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+
+#include "base/bind.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_dispatcher.h"
+#endif
+
+namespace base {
+
+RunLoop::RunLoop()
+    : loop_(MessageLoop::current()),
+      previous_run_loop_(NULL),
+      run_depth_(0),
+      run_called_(false),
+      quit_called_(false),
+      running_(false),
+      quit_when_idle_received_(false),
+      weak_factory_(this) {
+#if defined(OS_WIN)
+   dispatcher_ = NULL;
+#endif
+}
+
+#if defined(OS_WIN)
+RunLoop::RunLoop(MessagePumpDispatcher* dispatcher)
+    : loop_(MessageLoop::current()),
+      previous_run_loop_(NULL),
+      dispatcher_(dispatcher),
+      run_depth_(0),
+      run_called_(false),
+      quit_called_(false),
+      running_(false),
+      quit_when_idle_received_(false),
+      weak_factory_(this) {
+}
+#endif
+
+RunLoop::~RunLoop() {
+}
+
+void RunLoop::Run() {
+  if (!BeforeRun())
+    return;
+
+  // Use task stopwatch to exclude the loop run time from the current task, if
+  // any.
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  loop_->RunHandler();
+  stopwatch.Stop();
+
+  AfterRun();
+}
+
+void RunLoop::RunUntilIdle() {
+  quit_when_idle_received_ = true;
+  Run();
+}
+
+void RunLoop::Quit() {
+  quit_called_ = true;
+  if (running_ && loop_->run_loop_ == this) {
+    // This is the inner-most RunLoop, so quit now.
+    loop_->QuitNow();
+  }
+}
+
+base::Closure RunLoop::QuitClosure() {
+  return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
+}
+
+bool RunLoop::BeforeRun() {
+  DCHECK(!run_called_);
+  run_called_ = true;
+
+  // Allow Quit to be called before Run.
+  if (quit_called_)
+    return false;
+
+  // Push RunLoop stack:
+  previous_run_loop_ = loop_->run_loop_;
+  run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
+  loop_->run_loop_ = this;
+
+  running_ = true;
+  return true;
+}
+
+void RunLoop::AfterRun() {
+  running_ = false;
+
+  // Pop RunLoop stack:
+  loop_->run_loop_ = previous_run_loop_;
+
+  // Execute deferred QuitNow, if any:
+  if (previous_run_loop_ && previous_run_loop_->quit_called_)
+    loop_->QuitNow();
+}
+
+}  // namespace base
diff --git a/base/run_loop.h b/base/run_loop.h
new file mode 100644
index 0000000..0024108
--- /dev/null
+++ b/base/run_loop.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_RUN_LOOP_H_
+#define BASE_RUN_LOOP_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+
+namespace base {
+#if defined(OS_ANDROID)
+class MessagePumpForUI;
+#endif
+
+#if defined(OS_WIN)
+class MessagePumpDispatcher;
+#endif
+
+#if defined(OS_IOS)
+class MessagePumpUIApplication;
+#endif
+
+// Helper class to Run a nested MessageLoop. Please do not use nested
+// MessageLoops in production code! If you must, use this class instead of
+// calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once
+// per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run
+// a nested MessageLoop.
+class BASE_EXPORT RunLoop {
+ public:
+  RunLoop();
+#if defined(OS_WIN)
+  explicit RunLoop(MessagePumpDispatcher* dispatcher);
+#endif
+  ~RunLoop();
+
+  // Run the current MessageLoop. This blocks until Quit is called. Before
+  // calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to
+  // stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will
+  // also trigger a return from Run, but those are deprecated.
+  void Run();
+
+  // Run the current MessageLoop until it doesn't find any tasks or messages in
+  // the queue (it goes idle). WARNING: This may never return! Only use this
+  // when repeating tasks such as animated web pages have been shut down.
+  void RunUntilIdle();
+
+  bool running() const { return running_; }
+
+  // Quit an earlier call to Run(). There can be other nested RunLoops servicing
+  // the same task queue (MessageLoop); Quitting one RunLoop has no bearing on
+  // the others. Quit can be called before, during or after Run. If called
+  // before Run, Run will return immediately when called. Calling Quit after the
+  // RunLoop has already finished running has no effect.
+  //
+  // WARNING: You must NEVER assume that a call to Quit will terminate the
+  // targetted message loop. If a nested message loop continues running, the
+  // target may NEVER terminate. It is very easy to livelock (run forever) in
+  // such a case.
+  void Quit();
+
+  // Convenience method to get a closure that safely calls Quit (has no effect
+  // if the RunLoop instance is gone).
+  //
+  // Example:
+  //   RunLoop run_loop;
+  //   PostTask(run_loop.QuitClosure());
+  //   run_loop.Run();
+  base::Closure QuitClosure();
+
+ private:
+  friend class MessageLoop;
+#if defined(OS_ANDROID)
+  // Android doesn't support the blocking MessageLoop::Run, so it calls
+  // BeforeRun and AfterRun directly.
+  friend class base::MessagePumpForUI;
+#endif
+
+#if defined(OS_IOS)
+  // iOS doesn't support the blocking MessageLoop::Run, so it calls
+  // BeforeRun directly.
+  friend class base::MessagePumpUIApplication;
+#endif
+
+  // Return false to abort the Run.
+  bool BeforeRun();
+  void AfterRun();
+
+  MessageLoop* loop_;
+
+  // Parent RunLoop or NULL if this is the top-most RunLoop.
+  RunLoop* previous_run_loop_;
+
+#if defined(OS_WIN)
+  MessagePumpDispatcher* dispatcher_;
+#endif
+
+  // Used to count how many nested Run() invocations are on the stack.
+  int run_depth_;
+
+  bool run_called_;
+  bool quit_called_;
+  bool running_;
+
+  // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
+  // that we should quit Run once it becomes idle.
+  bool quit_when_idle_received_;
+
+  // WeakPtrFactory for QuitClosure safety.
+  base::WeakPtrFactory<RunLoop> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RunLoop);
+};
+
+}  // namespace base
+
+#endif  // BASE_RUN_LOOP_H_
diff --git a/base/safe_strerror_posix.cc b/base/safe_strerror_posix.cc
new file mode 100644
index 0000000..9da7aee
--- /dev/null
+++ b/base/safe_strerror_posix.cc
@@ -0,0 +1,119 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(__ANDROID__)
+// Post-L versions of bionic define the GNU-specific strerror_r if _GNU_SOURCE
+// is defined, but the symbol is renamed to __gnu_strerror_r which only exists
+// on those later versions. To preserve ABI compatibility with older versions,
+// undefine _GNU_SOURCE and use the POSIX version.
+#undef _GNU_SOURCE
+#endif
+
+#include "build/build_config.h"
+#include "base/safe_strerror_posix.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
+
+#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if USE_HISTORICAL_STRERRO_R
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    char *(*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  // GNU version.
+  char *rc = (*strerror_r_ptr)(err, buf, len);
+  if (rc != buf) {
+    // glibc did not use buf and returned a static string instead. Copy it
+    // into buf.
+    buf[0] = '\0';
+    strncat(buf, rc, len - 1);
+  }
+  // The GNU version never fails. Unknown errors get an "unknown error" message.
+  // The result is always null terminated.
+}
+#endif  // USE_HISTORICAL_STRERRO_R
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    int (*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  int old_errno = errno;
+  // Have to cast since otherwise we get an error if this is the GNU version
+  // (but in such a scenario this function is never called). Sadly we can't use
+  // C++-style casts because the appropriate one is reinterpret_cast but it's
+  // considered illegal to reinterpret_cast a type to itself, so we get an
+  // error in the opposite case.
+  int result = (*strerror_r_ptr)(err, buf, len);
+  if (result == 0) {
+    // POSIX is vague about whether the string will be terminated, although
+    // it indirectly implies that typically ERANGE will be returned, instead
+    // of truncating the string. We play it safe by always terminating the
+    // string explicitly.
+    buf[len - 1] = '\0';
+  } else {
+    // Error. POSIX is vague about whether the return value is itself a system
+    // error code or something else. On Linux currently it is -1 and errno is
+    // set. On BSD-derived systems it is a system error and errno is unchanged.
+    // We try and detect which case it is so as to put as much useful info as
+    // we can into our message.
+    int strerror_error;  // The error encountered in strerror
+    int new_errno = errno;
+    if (new_errno != old_errno) {
+      // errno was changed, so probably the return value is just -1 or something
+      // else that doesn't provide any info, and errno is the error.
+      strerror_error = new_errno;
+    } else {
+      // Either the error from strerror_r was the same as the previous value, or
+      // errno wasn't used. Assume the latter.
+      strerror_error = result;
+    }
+    // snprintf truncates and always null-terminates.
+    snprintf(buf,
+             len,
+             "Error %d while retrieving error %d",
+             strerror_error,
+             err);
+  }
+  errno = old_errno;
+}
+
+void safe_strerror_r(int err, char *buf, size_t len) {
+  if (buf == NULL || len <= 0) {
+    return;
+  }
+  // If using glibc (i.e., Linux), the compiler will automatically select the
+  // appropriate overloaded function based on the function type of strerror_r.
+  // The other one will be elided from the translation unit since both are
+  // static.
+  wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+  const int buffer_size = 256;
+  char buf[buffer_size];
+  safe_strerror_r(err, buf, sizeof(buf));
+  return std::string(buf);
+}
diff --git a/base/safe_strerror_posix.h b/base/safe_strerror_posix.h
new file mode 100644
index 0000000..2f77d84
--- /dev/null
+++ b/base/safe_strerror_posix.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SAFE_STRERROR_POSIX_H_
+#define BASE_SAFE_STRERROR_POSIX_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+// BEFORE using anything from this file, first look at PLOG and friends in
+// logging.h and use them instead if applicable.
+//
+// This file declares safe, portable alternatives to the POSIX strerror()
+// function. strerror() is inherently unsafe in multi-threaded apps and should
+// never be used. Doing so can cause crashes. Additionally, the thread-safe
+// alternative strerror_r varies in semantics across platforms. Use these
+// functions instead.
+
+// Thread-safe strerror function with dependable semantics that never fails.
+// It will write the string form of error "err" to buffer buf of length len.
+// If there is an error calling the OS's strerror_r() function then a message to
+// that effect will be printed into buf, truncating if necessary. The final
+// result is always null-terminated. The value of errno is never changed.
+//
+// Use this instead of strerror_r().
+BASE_EXPORT void safe_strerror_r(int err, char *buf, size_t len);
+
+// Calls safe_strerror_r with a buffer of suitable size and returns the result
+// in a C++ string.
+//
+// Use this instead of strerror(). Note though that safe_strerror_r will be
+// more robust in the case of heap corruption errors, since it doesn't need to
+// allocate a string.
+BASE_EXPORT std::string safe_strerror(int err);
+
+#endif  // BASE_SAFE_STRERROR_POSIX_H_
diff --git a/base/scoped_clear_errno.h b/base/scoped_clear_errno.h
new file mode 100644
index 0000000..7b972fc
--- /dev/null
+++ b/base/scoped_clear_errno.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_CLEAR_ERRNO_H_
+#define BASE_SCOPED_CLEAR_ERRNO_H_
+
+#include <errno.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Simple scoper that saves the current value of errno, resets it to 0, and on
+// destruction puts the old value back.
+class ScopedClearErrno {
+ public:
+  ScopedClearErrno() : old_errno_(errno) {
+    errno = 0;
+  }
+  ~ScopedClearErrno() {
+    if (errno == 0)
+      errno = old_errno_;
+  }
+
+ private:
+  const int old_errno_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno);
+};
+
+}  // namespace base
+
+#endif  // BASE_SCOPED_CLEAR_ERRNO_H_
diff --git a/base/scoped_clear_errno_unittest.cc b/base/scoped_clear_errno_unittest.cc
new file mode 100644
index 0000000..8afb33e
--- /dev/null
+++ b/base/scoped_clear_errno_unittest.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+
+#include "base/scoped_clear_errno.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedClearErrno, TestNoError) {
+  errno = 1;
+  {
+    ScopedClearErrno clear_error;
+    EXPECT_EQ(0, errno);
+  }
+  EXPECT_EQ(1, errno);
+}
+
+TEST(ScopedClearErrno, TestError) {
+  errno = 1;
+  {
+    ScopedClearErrno clear_error;
+    errno = 2;
+  }
+  EXPECT_EQ(2, errno);
+}
+
+}  // namespace base
diff --git a/base/scoped_generic.h b/base/scoped_generic.h
new file mode 100644
index 0000000..f6807e2
--- /dev/null
+++ b/base/scoped_generic.h
@@ -0,0 +1,182 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_GENERIC_H_
+#define BASE_SCOPED_GENERIC_H_
+
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "base/compiler_specific.h"
+#include "base/move.h"
+
+namespace base {
+
+// This class acts like ScopedPtr with a custom deleter (although is slightly
+// less fancy in some of the more escoteric respects) except that it keeps a
+// copy of the object rather than a pointer, and we require that the contained
+// object has some kind of "invalid" value.
+//
+// Defining a scoper based on this class allows you to get a scoper for
+// non-pointer types without having to write custom code for set, reset, and
+// move, etc. and get almost identical semantics that people are used to from
+// scoped_ptr.
+//
+// It is intended that you will typedef this class with an appropriate deleter
+// to implement clean up tasks for objects that act like pointers from a
+// resource management standpoint but aren't, such as file descriptors and
+// various types of operating system handles. Using scoped_ptr for these
+// things requires that you keep a pointer to the handle valid for the lifetime
+// of the scoper (which is easy to mess up).
+//
+// For an object to be able to be put into a ScopedGeneric, it must support
+// standard copyable semantics and have a specific "invalid" value. The traits
+// must define a free function and also the invalid value to assign for
+// default-constructed and released objects.
+//
+//   struct FooScopedTraits {
+//     // It's assumed that this is a fast inline function with little-to-no
+//     // penalty for duplicate calls. This must be a static function even
+//     // for stateful traits.
+//     static int InvalidValue() {
+//       return 0;
+//     }
+//
+//     // This free function will not be called if f == InvalidValue()!
+//     static void Free(int f) {
+//       ::FreeFoo(f);
+//     }
+//   };
+//
+//   typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo;
+template<typename T, typename Traits>
+class ScopedGeneric {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedGeneric)
+
+ private:
+  // This must be first since it's used inline below.
+  //
+  // Use the empty base class optimization to allow us to have a D
+  // member, while avoiding any space overhead for it when D is an
+  // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
+  // discussion of this technique.
+  struct Data : public Traits {
+    explicit Data(const T& in) : generic(in) {}
+    Data(const T& in, const Traits& other) : Traits(other), generic(in) {}
+    T generic;
+  };
+
+ public:
+  typedef T element_type;
+  typedef Traits traits_type;
+
+  ScopedGeneric() : data_(traits_type::InvalidValue()) {}
+
+  // Constructor. Takes responsibility for freeing the resource associated with
+  // the object T.
+  explicit ScopedGeneric(const element_type& value) : data_(value) {}
+
+  // Constructor. Allows initialization of a stateful traits object.
+  ScopedGeneric(const element_type& value, const traits_type& traits)
+      : data_(value, traits) {
+  }
+
+  // Move constructor. Allows initialization from a ScopedGeneric rvalue.
+  ScopedGeneric(ScopedGeneric<T, Traits>&& rvalue)
+      : data_(rvalue.release(), rvalue.get_traits()) {
+  }
+
+  ~ScopedGeneric() {
+    FreeIfNecessary();
+  }
+
+  // operator=. Allows assignment from a ScopedGeneric rvalue.
+  ScopedGeneric& operator=(ScopedGeneric<T, Traits>&& rvalue) {
+    reset(rvalue.release());
+    return *this;
+  }
+
+  // Frees the currently owned object, if any. Then takes ownership of a new
+  // object, if given. Self-resets are not allowd as on scoped_ptr. See
+  // http://crbug.com/162971
+  void reset(const element_type& value = traits_type::InvalidValue()) {
+    if (data_.generic != traits_type::InvalidValue() && data_.generic == value)
+      abort();
+    FreeIfNecessary();
+    data_.generic = value;
+  }
+
+  void swap(ScopedGeneric& other) {
+    // Standard swap idiom: 'using std::swap' ensures that std::swap is
+    // present in the overload set, but we call swap unqualified so that
+    // any more-specific overloads can be used, if available.
+    using std::swap;
+    swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_));
+    swap(data_.generic, other.data_.generic);
+  }
+
+  // Release the object. The return value is the current object held by this
+  // object. After this operation, this object will hold a null value, and
+  // will not own the object any more.
+  element_type release() WARN_UNUSED_RESULT {
+    element_type old_generic = data_.generic;
+    data_.generic = traits_type::InvalidValue();
+    return old_generic;
+  }
+
+  const element_type& get() const { return data_.generic; }
+
+  // Returns true if this object doesn't hold the special null value for the
+  // associated data type.
+  bool is_valid() const { return data_.generic != traits_type::InvalidValue(); }
+
+  bool operator==(const element_type& value) const {
+    return data_.generic == value;
+  }
+  bool operator!=(const element_type& value) const {
+    return data_.generic != value;
+  }
+
+  Traits& get_traits() { return data_; }
+  const Traits& get_traits() const { return data_; }
+
+ private:
+  void FreeIfNecessary() {
+    if (data_.generic != traits_type::InvalidValue()) {
+      data_.Free(data_.generic);
+      data_.generic = traits_type::InvalidValue();
+    }
+  }
+
+  // Forbid comparison. If U != T, it totally doesn't make sense, and if U ==
+  // T, it still doesn't make sense because you should never have the same
+  // object owned by two different ScopedGenerics.
+  template <typename T2, typename Traits2> bool operator==(
+      const ScopedGeneric<T2, Traits2>& p2) const;
+  template <typename T2, typename Traits2> bool operator!=(
+      const ScopedGeneric<T2, Traits2>& p2) const;
+
+  Data data_;
+};
+
+template<class T, class Traits>
+void swap(const ScopedGeneric<T, Traits>& a,
+          const ScopedGeneric<T, Traits>& b) {
+  a.swap(b);
+}
+
+template<class T, class Traits>
+bool operator==(const T& value, const ScopedGeneric<T, Traits>& scoped) {
+  return value == scoped.get();
+}
+
+template<class T, class Traits>
+bool operator!=(const T& value, const ScopedGeneric<T, Traits>& scoped) {
+  return value != scoped.get();
+}
+
+}  // namespace base
+
+#endif  // BASE_SCOPED_GENERIC_H_
diff --git a/base/scoped_generic_unittest.cc b/base/scoped_generic_unittest.cc
new file mode 100644
index 0000000..b28e154
--- /dev/null
+++ b/base/scoped_generic_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/scoped_generic.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+struct IntTraits {
+  IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
+
+  static int InvalidValue() {
+    return -1;
+  }
+  void Free(int value) {
+    freed_ints->push_back(value);
+  }
+
+  std::vector<int>* freed_ints;
+};
+
+typedef ScopedGeneric<int, IntTraits> ScopedInt;
+
+}  // namespace
+
+TEST(ScopedGenericTest, ScopedGeneric) {
+  std::vector<int> values_freed;
+  IntTraits traits(&values_freed);
+
+  // Invalid case, delete should not be called.
+  {
+    ScopedInt a(IntTraits::InvalidValue(), traits);
+  }
+  EXPECT_TRUE(values_freed.empty());
+
+  // Simple deleting case.
+  static const int kFirst = 0;
+  {
+    ScopedInt a(kFirst, traits);
+  }
+  ASSERT_EQ(1u, values_freed.size());
+  ASSERT_EQ(kFirst, values_freed[0]);
+  values_freed.clear();
+
+  // Release should return the right value and leave the object empty.
+  {
+    ScopedInt a(kFirst, traits);
+    EXPECT_EQ(kFirst, a.release());
+
+    ScopedInt b(IntTraits::InvalidValue(), traits);
+    EXPECT_EQ(IntTraits::InvalidValue(), b.release());
+  }
+  ASSERT_TRUE(values_freed.empty());
+
+  // Reset should free the old value, then the new one should go away when
+  // it goes out of scope.
+  static const int kSecond = 1;
+  {
+    ScopedInt b(kFirst, traits);
+    b.reset(kSecond);
+    ASSERT_EQ(1u, values_freed.size());
+    ASSERT_EQ(kFirst, values_freed[0]);
+  }
+  ASSERT_EQ(2u, values_freed.size());
+  ASSERT_EQ(kSecond, values_freed[1]);
+  values_freed.clear();
+
+  // Swap.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kSecond, traits);
+    a.swap(b);
+    EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
+    EXPECT_EQ(kSecond, a.get());
+    EXPECT_EQ(kFirst, b.get());
+  }
+  // Values should be deleted in the opposite order.
+  ASSERT_EQ(2u, values_freed.size());
+  EXPECT_EQ(kFirst, values_freed[0]);
+  EXPECT_EQ(kSecond, values_freed[1]);
+  values_freed.clear();
+
+  // Pass constructor.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(a.Pass());
+    EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
+    ASSERT_EQ(IntTraits::InvalidValue(), a.get());
+    ASSERT_EQ(kFirst, b.get());
+  }
+
+  ASSERT_EQ(1u, values_freed.size());
+  ASSERT_EQ(kFirst, values_freed[0]);
+  values_freed.clear();
+
+  // Pass assign.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kSecond, traits);
+    b = a.Pass();
+    ASSERT_EQ(1u, values_freed.size());
+    EXPECT_EQ(kSecond, values_freed[0]);
+    ASSERT_EQ(IntTraits::InvalidValue(), a.get());
+    ASSERT_EQ(kFirst, b.get());
+  }
+
+  ASSERT_EQ(2u, values_freed.size());
+  EXPECT_EQ(kFirst, values_freed[1]);
+  values_freed.clear();
+}
+
+TEST(ScopedGenericTest, Operators) {
+  std::vector<int> values_freed;
+  IntTraits traits(&values_freed);
+
+  static const int kFirst = 0;
+  static const int kSecond = 1;
+  {
+    ScopedInt a(kFirst, traits);
+    EXPECT_TRUE(a == kFirst);
+    EXPECT_FALSE(a != kFirst);
+    EXPECT_FALSE(a == kSecond);
+    EXPECT_TRUE(a != kSecond);
+
+    EXPECT_TRUE(kFirst == a);
+    EXPECT_FALSE(kFirst != a);
+    EXPECT_FALSE(kSecond == a);
+    EXPECT_TRUE(kSecond != a);
+  }
+
+  // is_valid().
+  {
+    ScopedInt a(kFirst, traits);
+    EXPECT_TRUE(a.is_valid());
+    a.reset();
+    EXPECT_FALSE(a.is_valid());
+  }
+}
+
+// Cheesy manual "no compile" test for manually validating changes.
+#if 0
+TEST(ScopedGenericTest, NoCompile) {
+  // Assignment shouldn't work.
+  /*{
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(a);
+  }*/
+
+  // Comparison shouldn't work.
+  /*{
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kFirst, traits);
+    if (a == b) {
+    }
+  }*/
+
+  // Implicit conversion to bool shouldn't work.
+  /*{
+    ScopedInt a(kFirst, traits);
+    bool result = a;
+  }*/
+}
+#endif
+
+}  // namespace base
diff --git a/base/scoped_native_library.cc b/base/scoped_native_library.cc
new file mode 100644
index 0000000..7290d29
--- /dev/null
+++ b/base/scoped_native_library.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_native_library.h"
+
+namespace base {
+
+ScopedNativeLibrary::ScopedNativeLibrary() : library_(NULL) {
+}
+
+ScopedNativeLibrary::ScopedNativeLibrary(NativeLibrary library)
+    : library_(library) {
+}
+
+ScopedNativeLibrary::ScopedNativeLibrary(const FilePath& library_path) {
+  library_ = base::LoadNativeLibrary(library_path, NULL);
+}
+
+ScopedNativeLibrary::~ScopedNativeLibrary() {
+  if (library_)
+    base::UnloadNativeLibrary(library_);
+}
+
+void* ScopedNativeLibrary::GetFunctionPointer(
+    const char* function_name) const {
+  if (!library_)
+    return NULL;
+  return base::GetFunctionPointerFromNativeLibrary(library_, function_name);
+}
+
+void ScopedNativeLibrary::Reset(NativeLibrary library) {
+  if (library_)
+    base::UnloadNativeLibrary(library_);
+  library_ = library;
+}
+
+NativeLibrary ScopedNativeLibrary::Release() {
+  NativeLibrary result = library_;
+  library_ = NULL;
+  return result;
+}
+
+}  // namespace base
diff --git a/base/scoped_native_library.h b/base/scoped_native_library.h
new file mode 100644
index 0000000..c0e93f3
--- /dev/null
+++ b/base/scoped_native_library.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_NATIVE_LIBRARY_H_
+#define BASE_SCOPED_NATIVE_LIBRARY_H_
+
+#include "base/base_export.h"
+#include "base/native_library.h"
+
+namespace base {
+
+class FilePath;
+
+// A class which encapsulates a base::NativeLibrary object available only in a
+// scope.
+// This class automatically unloads the loaded library in its destructor.
+class BASE_EXPORT ScopedNativeLibrary {
+ public:
+  // Initializes with a NULL library.
+  ScopedNativeLibrary();
+
+  // Takes ownership of the given library handle.
+  explicit ScopedNativeLibrary(NativeLibrary library);
+
+  // Opens the given library and manages its lifetime.
+  explicit ScopedNativeLibrary(const FilePath& library_path);
+
+  ~ScopedNativeLibrary();
+
+  // Returns true if there's a valid library loaded.
+  bool is_valid() const { return !!library_; }
+
+  void* GetFunctionPointer(const char* function_name) const;
+
+  // Takes ownership of the given library handle. Any existing handle will
+  // be freed.
+  void Reset(NativeLibrary library);
+
+  // Returns the native library handle and removes it from this object. The
+  // caller must manage the lifetime of the handle.
+  NativeLibrary Release();
+
+ private:
+  NativeLibrary library_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNativeLibrary);
+};
+
+}  // namespace base
+
+#endif  // BASE_SCOPED_NATIVE_LIBRARY_H_
diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc
new file mode 100644
index 0000000..035faa0
--- /dev/null
+++ b/base/scoped_native_library_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_native_library.h"
+#if defined(OS_WIN)
+#include "base/files/file_path.h"
+#endif
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Tests whether or not a function pointer retrieved via ScopedNativeLibrary
+// is available only in a scope.
+TEST(ScopedNativeLibrary, Basic) {
+#if defined(OS_WIN)
+  // Get the pointer to DirectDrawCreate() from "ddraw.dll" and verify it
+  // is valid only in this scope.
+  // FreeLibrary() doesn't actually unload a DLL until its reference count
+  // becomes zero, i.e. function pointer is still valid if the DLL used
+  // in this test is also used by another part of this executable.
+  // So, this test uses "ddraw.dll", which is not used by Chrome at all but
+  // installed on all versions of Windows.
+  const char kFunctionName[] = "DirectDrawCreate";
+  NativeLibrary native_library;
+  {
+    FilePath path(GetNativeLibraryName(L"ddraw"));
+    native_library = LoadNativeLibrary(path, NULL);
+    ScopedNativeLibrary library(native_library);
+    FARPROC test_function =
+        reinterpret_cast<FARPROC>(library.GetFunctionPointer(kFunctionName));
+    EXPECT_EQ(0, IsBadCodePtr(test_function));
+    EXPECT_EQ(
+        GetFunctionPointerFromNativeLibrary(native_library, kFunctionName),
+        test_function);
+  }
+  EXPECT_EQ(NULL,
+            GetFunctionPointerFromNativeLibrary(native_library, kFunctionName));
+#endif
+}
+
+}  // namespace base
diff --git a/base/scoped_observer.h b/base/scoped_observer.h
new file mode 100644
index 0000000..422701b
--- /dev/null
+++ b/base/scoped_observer.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_OBSERVER_H_
+#define BASE_SCOPED_OBSERVER_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// ScopedObserver is used to keep track of the set of sources an object has
+// attached itself to as an observer. When ScopedObserver is destroyed it
+// removes the object as an observer from all sources it has been added to.
+template <class Source, class Observer>
+class ScopedObserver {
+ public:
+  explicit ScopedObserver(Observer* observer) : observer_(observer) {}
+
+  ~ScopedObserver() {
+    RemoveAll();
+  }
+
+  // Adds the object passed to the constructor as an observer on |source|.
+  void Add(Source* source) {
+    sources_.push_back(source);
+    source->AddObserver(observer_);
+  }
+
+  // Remove the object passed to the constructor as an observer from |source|.
+  void Remove(Source* source) {
+    auto it = std::find(sources_.begin(), sources_.end(), source);
+    DCHECK(it != sources_.end());
+    sources_.erase(it);
+    source->RemoveObserver(observer_);
+  }
+
+  void RemoveAll() {
+    for (size_t i = 0; i < sources_.size(); ++i)
+      sources_[i]->RemoveObserver(observer_);
+    sources_.clear();
+  }
+
+  bool IsObserving(Source* source) const {
+    return std::find(sources_.begin(), sources_.end(), source) !=
+        sources_.end();
+  }
+
+  bool IsObservingSources() const { return !sources_.empty(); }
+
+ private:
+  Observer* observer_;
+
+  std::vector<Source*> sources_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedObserver);
+};
+
+#endif  // BASE_SCOPED_OBSERVER_H_
diff --git a/base/security_unittest.cc b/base/security_unittest.cc
new file mode 100644
index 0000000..07ba6f5
--- /dev/null
+++ b/base/security_unittest.cc
@@ -0,0 +1,376 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN)
+#include <new.h>
+#endif
+
+using std::nothrow;
+using std::numeric_limits;
+
+namespace {
+
+#if defined(OS_WIN)
+// This is a permitted size but exhausts memory pretty quickly.
+const size_t kLargePermittedAllocation = 0x7FFFE000;
+
+int OnNoMemory(size_t) {
+  _exit(1);
+}
+
+void ExhaustMemoryWithMalloc() {
+  for (;;) {
+    // Without the |volatile|, clang optimizes away the allocation.
+    void* volatile buf = malloc(kLargePermittedAllocation);
+    if (!buf)
+      break;
+  }
+}
+
+void ExhaustMemoryWithRealloc() {
+  size_t size = kLargePermittedAllocation;
+  void* buf = malloc(size);
+  if (!buf)
+    return;
+  for (;;) {
+    size += kLargePermittedAllocation;
+    void* new_buf = realloc(buf, size);
+    if (!buf)
+      break;
+    buf = new_buf;
+  }
+}
+#endif
+
+// This function acts as a compiler optimization barrier. We use it to
+// prevent the compiler from making an expression a compile-time constant.
+// We also use it so that the compiler doesn't discard certain return values
+// as something we don't need (see the comment with calloc below).
+template <typename Type>
+NOINLINE Type HideValueFromCompiler(volatile Type value) {
+#if defined(__GNUC__)
+  // In a GCC compatible compiler (GCC or Clang), make this compiler barrier
+  // more robust than merely using "volatile".
+  __asm__ volatile ("" : "+r" (value));
+#endif  // __GNUC__
+  return value;
+}
+
+// Tcmalloc and Windows allocator shim support setting malloc limits.
+// - NO_TCMALLOC (should be defined if compiled with use_allocator!="tcmalloc")
+// - ADDRESS_SANITIZER and SYZYASAN because they have their own memory allocator
+// - IOS does not use tcmalloc
+// - OS_MACOSX does not use tcmalloc
+// - Windows allocator shim defines ALLOCATOR_SHIM
+#if (!defined(NO_TCMALLOC) || defined(ALLOCATOR_SHIM)) &&                     \
+    !defined(ADDRESS_SANITIZER) && !defined(OS_IOS) && !defined(OS_MACOSX) && \
+    !defined(SYZYASAN)
+#define MALLOC_OVERFLOW_TEST(function) function
+#else
+#define MALLOC_OVERFLOW_TEST(function) DISABLED_##function
+#endif
+
+// TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
+// C++11.
+const size_t kTooBigAllocSize = INT_MAX;
+
+// Detect runtime TCMalloc bypasses.
+bool IsTcMallocBypassed() {
+#if defined(OS_LINUX)
+  // This should detect a TCMalloc bypass from Valgrind.
+  char* g_slice = getenv("G_SLICE");
+  if (g_slice && !strcmp(g_slice, "always-malloc"))
+    return true;
+#endif
+  return false;
+}
+
+bool CallocDiesOnOOM() {
+// The sanitizers' calloc dies on OOM instead of returning NULL.
+// The wrapper function in base/process_util_linux.cc that is used when we
+// compile without TCMalloc will just die on OOM instead of returning NULL.
+#if defined(ADDRESS_SANITIZER) || \
+    defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER) || \
+    (defined(OS_LINUX) && defined(NO_TCMALLOC))
+  return true;
+#else
+  return false;
+#endif
+}
+
+// Fake test that allow to know the state of TCMalloc by looking at bots.
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(IsTCMallocDynamicallyBypassed)) {
+  printf("Malloc is dynamically bypassed: %s\n",
+         IsTcMallocBypassed() ? "yes." : "no.");
+}
+
+// The MemoryAllocationRestrictions* tests test that we can not allocate a
+// memory range that cannot be indexed via an int. This is used to mitigate
+// vulnerabilities in libraries that use int instead of size_t.  See
+// crbug.com/169327.
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsMalloc)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
+        HideValueFromCompiler(malloc(kTooBigAllocSize))));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationMallocDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+  {
+    scoped_ptr<char, base::FreeDeleter> ptr;
+    EXPECT_DEATH(ptr.reset(static_cast<char*>(
+                      HideValueFromCompiler(malloc(kTooBigAllocSize)))),
+                  "");
+    ASSERT_TRUE(!ptr);
+  }
+  _set_new_handler(NULL);
+  _set_new_mode(0);
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationExhaustDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+  {
+    ASSERT_DEATH(ExhaustMemoryWithMalloc(), "");
+  }
+  _set_new_handler(NULL);
+  _set_new_mode(0);
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryReallocationExhaustDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+  {
+    ASSERT_DEATH(ExhaustMemoryWithRealloc(), "");
+  }
+  _set_new_handler(NULL);
+  _set_new_mode(0);
+}
+#endif
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsCalloc)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
+        HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsRealloc)) {
+  if (!IsTcMallocBypassed()) {
+    char* orig_ptr = static_cast<char*>(malloc(1));
+    ASSERT_TRUE(orig_ptr);
+    scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
+        HideValueFromCompiler(realloc(orig_ptr, kTooBigAllocSize))));
+    ASSERT_TRUE(!ptr);
+    // If realloc() did not succeed, we need to free orig_ptr.
+    free(orig_ptr);
+  }
+}
+
+typedef struct {
+  char large_array[kTooBigAllocSize];
+} VeryLargeStruct;
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNew)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<VeryLargeStruct> ptr(
+        HideValueFromCompiler(new (nothrow) VeryLargeStruct));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationNewDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  {
+    scoped_ptr<VeryLargeStruct> ptr;
+    EXPECT_DEATH(
+        ptr.reset(HideValueFromCompiler(new (nothrow) VeryLargeStruct)), "");
+    ASSERT_TRUE(!ptr);
+  }
+  _set_new_handler(NULL);
+}
+#endif
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNewArray)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<char[]> ptr(
+        HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+// The tests bellow check for overflows in new[] and calloc().
+
+// There are platforms where these tests are known to fail. We would like to
+// be able to easily check the status on the bots, but marking tests as
+// FAILS_ is too clunky.
+void OverflowTestsSoftExpectTrue(bool overflow_detected) {
+  if (!overflow_detected) {
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
+    // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't
+    // fail the test, but report.
+    printf("Platform has overflow: %s\n",
+           !overflow_detected ? "yes." : "no.");
+#else
+    // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT
+    // aren't).
+    EXPECT_TRUE(overflow_detected);
+#endif
+  }
+}
+
+#if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER) || defined(OS_MACOSX)
+#define MAYBE_NewOverflow DISABLED_NewOverflow
+#else
+#define MAYBE_NewOverflow NewOverflow
+#endif
+// Test array[TooBig][X] and array[X][TooBig] allocations for int overflows.
+// IOS doesn't honor nothrow, so disable the test there.
+// Crashes on Windows Dbg builds, disable there as well.
+// Fails on Mac 10.8 http://crbug.com/227092
+TEST(SecurityTest, MAYBE_NewOverflow) {
+  const size_t kArraySize = 4096;
+  // We want something "dynamic" here, so that the compiler doesn't
+  // immediately reject crazy arrays.
+  const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize);
+  // numeric_limits are still not constexpr until we switch to C++11, so we
+  // use an ugly cast.
+  const size_t kMaxSizeT = ~static_cast<size_t>(0);
+  ASSERT_EQ(numeric_limits<size_t>::max(), kMaxSizeT);
+  const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+  const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2);
+  {
+    scoped_ptr<char[][kArraySize]> array_pointer(new (nothrow)
+        char[kDynamicArraySize2][kArraySize]);
+    OverflowTestsSoftExpectTrue(!array_pointer);
+  }
+  // On windows, the compiler prevents static array sizes of more than
+  // 0x7fffffff (error C2148).
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+  ALLOW_UNUSED_LOCAL(kDynamicArraySize);
+#else
+  {
+    scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow)
+        char[kDynamicArraySize][kArraySize2]);
+    OverflowTestsSoftExpectTrue(!array_pointer);
+  }
+#endif  // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
+}
+
+// Call calloc(), eventually free the memory and return whether or not
+// calloc() did succeed.
+bool CallocReturnsNull(size_t nmemb, size_t size) {
+  scoped_ptr<char, base::FreeDeleter> array_pointer(
+      static_cast<char*>(calloc(nmemb, size)));
+  // We need the call to HideValueFromCompiler(): we have seen LLVM
+  // optimize away the call to calloc() entirely and assume the pointer to not
+  // be NULL.
+  return HideValueFromCompiler(array_pointer.get()) == NULL;
+}
+
+// Test if calloc() can overflow.
+TEST(SecurityTest, CallocOverflow) {
+  const size_t kArraySize = 4096;
+  const size_t kMaxSizeT = numeric_limits<size_t>::max();
+  const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+  if (!CallocDiesOnOOM()) {
+    EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2));
+    EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize));
+  } else {
+    // It's also ok for calloc to just terminate the process.
+#if defined(GTEST_HAS_DEATH_TEST)
+    EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), "");
+    EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), "");
+#endif  // GTEST_HAS_DEATH_TEST
+  }
+}
+
+#if defined(OS_LINUX) && defined(__x86_64__)
+// Check if ptr1 and ptr2 are separated by less than size chars.
+bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
+  ptrdiff_t ptr_diff = reinterpret_cast<char*>(std::max(ptr1, ptr2)) -
+                       reinterpret_cast<char*>(std::min(ptr1, ptr2));
+  return static_cast<size_t>(ptr_diff) <= size;
+}
+
+// Check if TCMalloc uses an underlying random memory allocator.
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(RandomMemoryAllocations)) {
+  if (IsTcMallocBypassed())
+    return;
+  size_t kPageSize = 4096;  // We support x86_64 only.
+  // Check that malloc() returns an address that is neither the kernel's
+  // un-hinted mmap area, nor the current brk() area. The first malloc() may
+  // not be at a random address because TCMalloc will first exhaust any memory
+  // that it has allocated early on, before starting the sophisticated
+  // allocators.
+  void* default_mmap_heap_address =
+      mmap(0, kPageSize, PROT_READ|PROT_WRITE,
+           MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(default_mmap_heap_address,
+            static_cast<void*>(MAP_FAILED));
+  ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0);
+  void* brk_heap_address = sbrk(0);
+  ASSERT_NE(brk_heap_address, reinterpret_cast<void*>(-1));
+  ASSERT_TRUE(brk_heap_address != NULL);
+  // 1 MB should get us past what TCMalloc pre-allocated before initializing
+  // the sophisticated allocators.
+  size_t kAllocSize = 1<<20;
+  scoped_ptr<char, base::FreeDeleter> ptr(
+      static_cast<char*>(malloc(kAllocSize)));
+  ASSERT_TRUE(ptr != NULL);
+  // If two pointers are separated by less than 512MB, they are considered
+  // to be in the same area.
+  // Our random pointer could be anywhere within 0x3fffffffffff (46bits),
+  // and we are checking that it's not withing 1GB (30 bits) from two
+  // addresses (brk and mmap heap). We have roughly one chance out of
+  // 2^15 to flake.
+  const size_t kAreaRadius = 1<<29;
+  bool in_default_mmap_heap = ArePointersToSameArea(
+      ptr.get(), default_mmap_heap_address, kAreaRadius);
+  EXPECT_FALSE(in_default_mmap_heap);
+
+  bool in_default_brk_heap = ArePointersToSameArea(
+      ptr.get(), brk_heap_address, kAreaRadius);
+  EXPECT_FALSE(in_default_brk_heap);
+
+  // In the implementation, we always mask our random addresses with
+  // kRandomMask, so we use it as an additional detection mechanism.
+  const uintptr_t kRandomMask = 0x3fffffffffffULL;
+  bool impossible_random_address =
+      reinterpret_cast<uintptr_t>(ptr.get()) & ~kRandomMask;
+  EXPECT_FALSE(impossible_random_address);
+}
+
+#endif  // defined(OS_LINUX) && defined(__x86_64__)
+
+}  // namespace
diff --git a/base/sequence_checker.h b/base/sequence_checker.h
new file mode 100644
index 0000000..ad01828
--- /dev/null
+++ b/base/sequence_checker.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCE_CHECKER_H_
+#define BASE_SEQUENCE_CHECKER_H_
+
+// See comments for the similar block in thread_checker.h.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_SEQUENCE_CHECKER 1
+#else
+#define ENABLE_SEQUENCE_CHECKER 0
+#endif
+
+#include "base/sequence_checker_impl.h"
+
+namespace base {
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the SequenceChecker class to get
+// the right version for your build configuration.
+class SequenceCheckerDoNothing {
+ public:
+  bool CalledOnValidSequencedThread() const {
+    return true;
+  }
+
+  void DetachFromSequence() {}
+};
+
+// SequenceChecker is a helper class used to help verify that some
+// methods of a class are called in sequence -- that is, called from
+// the same SequencedTaskRunner. It is a generalization of
+// ThreadChecker; see comments in sequence_checker_impl.h for details.
+//
+// Example:
+// class MyClass {
+//  public:
+//   void Foo() {
+//     DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+//     ... (do stuff) ...
+//   }
+//
+//  private:
+//   SequenceChecker sequence_checker_;
+// }
+//
+// In Release mode, CalledOnValidSequencedThread() will always return true.
+#if ENABLE_SEQUENCE_CHECKER
+class SequenceChecker : public SequenceCheckerImpl {
+};
+#else
+class SequenceChecker : public SequenceCheckerDoNothing {
+};
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+#undef ENABLE_SEQUENCE_CHECKER
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCE_CHECKER_H_
diff --git a/base/sequence_checker_impl.cc b/base/sequence_checker_impl.cc
new file mode 100644
index 0000000..e95b8ee
--- /dev/null
+++ b/base/sequence_checker_impl.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sequence_checker_impl.h"
+
+namespace base {
+
+SequenceCheckerImpl::SequenceCheckerImpl()
+    : sequence_token_assigned_(false) {
+  AutoLock auto_lock(lock_);
+  EnsureSequenceTokenAssigned();
+}
+
+SequenceCheckerImpl::~SequenceCheckerImpl() {}
+
+bool SequenceCheckerImpl::CalledOnValidSequencedThread() const {
+  AutoLock auto_lock(lock_);
+  EnsureSequenceTokenAssigned();
+
+  // If this thread is not associated with a SequencedWorkerPool,
+  // SequenceChecker behaves as a ThreadChecker. See header for details.
+  if (!sequence_token_.IsValid())
+    return thread_checker_.CalledOnValidThread();
+
+  return sequence_token_.Equals(
+      SequencedWorkerPool::GetSequenceTokenForCurrentThread());
+}
+
+void SequenceCheckerImpl::DetachFromSequence() {
+  AutoLock auto_lock(lock_);
+  thread_checker_.DetachFromThread();
+  sequence_token_assigned_ = false;
+  sequence_token_ = SequencedWorkerPool::SequenceToken();
+}
+
+void SequenceCheckerImpl::EnsureSequenceTokenAssigned() const {
+  lock_.AssertAcquired();
+  if (sequence_token_assigned_)
+    return;
+
+  sequence_token_assigned_ = true;
+  sequence_token_ = SequencedWorkerPool::GetSequenceTokenForCurrentThread();
+}
+
+}  // namespace base
diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h
new file mode 100644
index 0000000..741aafe
--- /dev/null
+++ b/base/sequence_checker_impl.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCE_CHECKER_IMPL_H_
+#define BASE_SEQUENCE_CHECKER_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// SequenceCheckerImpl is used to help verify that some methods of a
+// class are called in sequence -- that is, called from the same
+// SequencedTaskRunner. It is a generalization of ThreadChecker; in
+// particular, it behaves exactly like ThreadChecker if constructed
+// on a thread that is not part of a SequencedWorkerPool.
+class BASE_EXPORT SequenceCheckerImpl {
+ public:
+  SequenceCheckerImpl();
+  ~SequenceCheckerImpl();
+
+  // Returns whether the we are being called on the same sequence token
+  // as previous calls. If there is no associated sequence, then returns
+  // whether we are being called on the underlying ThreadChecker's thread.
+  bool CalledOnValidSequencedThread() const;
+
+  // Unbinds the checker from the currently associated sequence. The
+  // checker will be re-bound on the next call to CalledOnValidSequence().
+  void DetachFromSequence();
+
+ private:
+  void EnsureSequenceTokenAssigned() const;
+
+  // Guards all variables below.
+  mutable Lock lock_;
+
+  // Used if |sequence_token_| is not valid.
+  ThreadCheckerImpl thread_checker_;
+  mutable bool sequence_token_assigned_;
+
+  mutable SequencedWorkerPool::SequenceToken sequence_token_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl);
+};
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCE_CHECKER_IMPL_H_
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
new file mode 100644
index 0000000..0aa0f9c
--- /dev/null
+++ b/base/sequence_checker_unittest.cc
@@ -0,0 +1,333 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/sequence_checker.h so that we can be good citizens
+// there and undef the macro.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_SEQUENCE_CHECKER 1
+#else
+#define ENABLE_SEQUENCE_CHECKER 0
+#endif
+
+namespace base {
+
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Simple class to exercise the basics of SequenceChecker.
+// DoStuff should verify that it's called on a valid sequenced thread.
+// SequenceCheckedObject can be destroyed on any thread (like WeakPtr).
+class SequenceCheckedObject {
+ public:
+  SequenceCheckedObject() {}
+  ~SequenceCheckedObject() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+  }
+
+  void DetachFromSequence() {
+    sequence_checker_.DetachFromSequence();
+  }
+
+ private:
+  SequenceChecker sequence_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequenceCheckedObject);
+};
+
+class SequenceCheckerTest : public testing::Test {
+ public:
+  SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {}
+
+  void SetUp() override {
+    other_thread_.Start();
+    ResetPool();
+  }
+
+  void TearDown() override {
+    other_thread_.Stop();
+    pool()->Shutdown();
+  }
+
+ protected:
+  base::Thread* other_thread() { return &other_thread_; }
+
+  const scoped_refptr<SequencedWorkerPool>& pool() {
+    return pool_owner_->pool();
+  }
+
+  void PostDoStuffToWorkerPool(SequenceCheckedObject* sequence_checked_object,
+                               const std::string& token_name) {
+    pool()->PostNamedSequencedWorkerTask(
+        token_name,
+        FROM_HERE,
+        base::Bind(&SequenceCheckedObject::DoStuff,
+                   base::Unretained(sequence_checked_object)));
+  }
+
+  void PostDoStuffToOtherThread(
+      SequenceCheckedObject* sequence_checked_object) {
+    other_thread()->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&SequenceCheckedObject::DoStuff,
+                              base::Unretained(sequence_checked_object)));
+  }
+
+  void PostDeleteToOtherThread(
+      scoped_ptr<SequenceCheckedObject> sequence_checked_object) {
+    other_thread()->message_loop()->DeleteSoon(
+        FROM_HERE,
+        sequence_checked_object.release());
+  }
+
+  // Destroys the SequencedWorkerPool instance, blocking until it is fully shut
+  // down, and creates a new instance.
+  void ResetPool() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test"));
+  }
+
+  void MethodOnDifferentThreadDeathTest();
+  void DetachThenCallFromDifferentThreadDeathTest();
+  void DifferentSequenceTokensDeathTest();
+  void WorkerPoolAndSimpleThreadDeathTest();
+  void TwoDifferentWorkerPoolsDeathTest();
+
+ private:
+  MessageLoop message_loop_;  // Needed by SequencedWorkerPool to function.
+  base::Thread other_thread_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+};
+
+TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify that DoStuff doesn't assert.
+  sequence_checked_object->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  sequence_checked_object.reset();
+}
+
+TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify the destructor doesn't assert when called on a different thread.
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, DetachFromSequence) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify that DoStuff doesn't assert when called on a different thread after
+  // a call to DetachFromSequence.
+  sequence_checked_object->DetachFromSequence();
+
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, SameSequenceTokenValid) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  pool()->FlushForTesting();
+
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // DoStuff should assert in debug builds only when called on a
+  // different thread.
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    MethodOnDifferentThreadDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, MethodAllowedOnDifferentThreadDeathTestInRelease) {
+  MethodOnDifferentThreadDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::DetachThenCallFromDifferentThreadDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // DoStuff doesn't assert when called on a different thread
+  // after a call to DetachFromSequence.
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+
+  // DoStuff should assert in debug builds only after moving to
+  // another thread.
+  sequence_checked_object->DoStuff();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, DetachFromSequenceDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    DetachThenCallFromDifferentThreadDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, DetachFromThreadDeathTestInRelease) {
+  DetachThenCallFromDifferentThreadDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::DifferentSequenceTokensDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  pool()->FlushForTesting();
+
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    DifferentSequenceTokensDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInRelease) {
+  DifferentSequenceTokensDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::WorkerPoolAndSimpleThreadDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    WorkerPoolAndSimpleThreadDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInRelease) {
+  WorkerPoolAndSimpleThreadDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2");
+  second_pool_owner.pool()->PostNamedSequencedWorkerTask(
+      "A",
+      FROM_HERE,
+      base::Bind(&SequenceCheckedObject::DoStuff,
+                 base::Unretained(sequence_checked_object.get())));
+  second_pool_owner.pool()->FlushForTesting();
+  second_pool_owner.pool()->Shutdown();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    TwoDifferentWorkerPoolsDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInRelease) {
+  TwoDifferentWorkerPoolsDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
+
+}  // namespace
+
+}  // namespace base
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_SEQUENCE_CHECKER
diff --git a/base/sequenced_task_runner.cc b/base/sequenced_task_runner.cc
new file mode 100644
index 0000000..00d4048
--- /dev/null
+++ b/base/sequenced_task_runner.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sequenced_task_runner.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+bool SequencedTaskRunner::PostNonNestableTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return PostNonNestableDelayedTask(from_here, task, base::TimeDelta());
+}
+
+bool SequencedTaskRunner::DeleteSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*deleter)(const void*),
+    const void* object) {
+  return PostNonNestableTask(from_here, Bind(deleter, object));
+}
+
+bool SequencedTaskRunner::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  return PostNonNestableTask(from_here, Bind(releaser, object));
+}
+
+}  // namespace base
diff --git a/base/sequenced_task_runner.h b/base/sequenced_task_runner.h
new file mode 100644
index 0000000..6bb3f2b
--- /dev/null
+++ b/base/sequenced_task_runner.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCED_TASK_RUNNER_H_
+#define BASE_SEQUENCED_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/task_runner.h"
+
+namespace base {
+
+// A SequencedTaskRunner is a subclass of TaskRunner that provides
+// additional guarantees on the order that tasks are started, as well
+// as guarantees on when tasks are in sequence, i.e. one task finishes
+// before the other one starts.
+//
+// Summary
+// -------
+// Non-nested tasks with the same delay will run one by one in FIFO
+// order.
+//
+// Detailed guarantees
+// -------------------
+//
+// SequencedTaskRunner also adds additional methods for posting
+// non-nestable tasks.  In general, an implementation of TaskRunner
+// may expose task-running methods which are themselves callable from
+// within tasks.  A non-nestable task is one that is guaranteed to not
+// be run from within an already-running task.  Conversely, a nestable
+// task (the default) is a task that can be run from within an
+// already-running task.
+//
+// The guarantees of SequencedTaskRunner are as follows:
+//
+//   - Given two tasks T2 and T1, T2 will start after T1 starts if:
+//
+//       * T2 is posted after T1; and
+//       * T2 has equal or higher delay than T1; and
+//       * T2 is non-nestable or T1 is nestable.
+//
+//   - If T2 will start after T1 starts by the above guarantee, then
+//     T2 will start after T1 finishes and is destroyed if:
+//
+//       * T2 is non-nestable, or
+//       * T1 doesn't call any task-running methods.
+//
+//   - If T2 will start after T1 finishes by the above guarantee, then
+//     all memory changes in T1 and T1's destruction will be visible
+//     to T2.
+//
+//   - If T2 runs nested within T1 via a call to the task-running
+//     method M, then all memory changes in T1 up to the call to M
+//     will be visible to T2, and all memory changes in T2 will be
+//     visible to T1 from the return from M.
+//
+// Note that SequencedTaskRunner does not guarantee that tasks are run
+// on a single dedicated thread, although the above guarantees provide
+// most (but not all) of the same guarantees.  If you do need to
+// guarantee that tasks are run on a single dedicated thread, see
+// SingleThreadTaskRunner (in single_thread_task_runner.h).
+//
+// Some corollaries to the above guarantees, assuming the tasks in
+// question don't call any task-running methods:
+//
+//   - Tasks posted via PostTask are run in FIFO order.
+//
+//   - Tasks posted via PostNonNestableTask are run in FIFO order.
+//
+//   - Tasks posted with the same delay and the same nestable state
+//     are run in FIFO order.
+//
+//   - A list of tasks with the same nestable state posted in order of
+//     non-decreasing delay is run in FIFO order.
+//
+//   - A list of tasks posted in order of non-decreasing delay with at
+//     most a single change in nestable state from nestable to
+//     non-nestable is run in FIFO order. (This is equivalent to the
+//     statement of the first guarantee above.)
+//
+// Some theoretical implementations of SequencedTaskRunner:
+//
+//   - A SequencedTaskRunner that wraps a regular TaskRunner but makes
+//     sure that only one task at a time is posted to the TaskRunner,
+//     with appropriate memory barriers in between tasks.
+//
+//   - A SequencedTaskRunner that, for each task, spawns a joinable
+//     thread to run that task and immediately quit, and then
+//     immediately joins that thread.
+//
+//   - A SequencedTaskRunner that stores the list of posted tasks and
+//     has a method Run() that runs each runnable task in FIFO order
+//     that can be called from any thread, but only if another
+//     (non-nested) Run() call isn't already happening.
+class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
+ public:
+  // The two PostNonNestable*Task methods below are like their
+  // nestable equivalents in TaskRunner, but they guarantee that the
+  // posted task will not run nested within an already-running task.
+  //
+  // A simple corollary is that posting a task as non-nestable can
+  // only delay when the task gets run.  That is, posting a task as
+  // non-nestable may not affect when the task gets run, or it could
+  // make it run later than it normally would, but it won't make it
+  // run earlier than it normally would.
+
+  // TODO(akalin): Get rid of the boolean return value for the methods
+  // below.
+
+  bool PostNonNestableTask(const tracked_objects::Location& from_here,
+                           const Closure& task);
+
+  virtual bool PostNonNestableDelayedTask(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      base::TimeDelta delay) = 0;
+
+  // Submits a non-nestable task to delete the given object.  Returns
+  // true if the object may be deleted at some point in the future,
+  // and false if the object definitely will not be deleted.
+  template <class T>
+  bool DeleteSoon(const tracked_objects::Location& from_here,
+                  const T* object) {
+    return
+        subtle::DeleteHelperInternal<T, bool>::DeleteViaSequencedTaskRunner(
+            this, from_here, object);
+  }
+
+  // Submits a non-nestable task to release the given object.  Returns
+  // true if the object may be released at some point in the future,
+  // and false if the object definitely will not be released.
+  template <class T>
+  bool ReleaseSoon(const tracked_objects::Location& from_here,
+                   T* object) {
+    return
+        subtle::ReleaseHelperInternal<T, bool>::ReleaseViaSequencedTaskRunner(
+            this, from_here, object);
+  }
+
+ protected:
+  ~SequencedTaskRunner() override {}
+
+ private:
+  template <class T, class R> friend class subtle::DeleteHelperInternal;
+  template <class T, class R> friend class subtle::ReleaseHelperInternal;
+
+  bool DeleteSoonInternal(const tracked_objects::Location& from_here,
+                          void(*deleter)(const void*),
+                          const void* object);
+
+  bool ReleaseSoonInternal(const tracked_objects::Location& from_here,
+                           void(*releaser)(const void*),
+                           const void* object);
+};
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCED_TASK_RUNNER_H_
diff --git a/base/sequenced_task_runner_helpers.h b/base/sequenced_task_runner_helpers.h
new file mode 100644
index 0000000..da519bf
--- /dev/null
+++ b/base/sequenced_task_runner_helpers.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/debug/alias.h"
+
+// TODO(akalin): Investigate whether it's possible to just have
+// SequencedTaskRunner use these helpers (instead of MessageLoop).
+// Then we can just move these to sequenced_task_runner.h.
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace base {
+
+namespace subtle {
+template <class T, class R> class DeleteHelperInternal;
+template <class T, class R> class ReleaseHelperInternal;
+}
+
+// Template helpers which use function indirection to erase T from the
+// function signature while still remembering it so we can call the
+// correct destructor/release function.
+//
+// We use this trick so we don't need to include bind.h in a header
+// file like sequenced_task_runner.h. We also wrap the helpers in a
+// templated class to make it easier for users of DeleteSoon to
+// declare the helper as a friend.
+template <class T>
+class DeleteHelper {
+ private:
+  template <class T2, class R> friend class subtle::DeleteHelperInternal;
+
+  static void DoDelete(const void* object) {
+    delete reinterpret_cast<const T*>(object);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteHelper);
+};
+
+template <class T>
+class ReleaseHelper {
+ private:
+  template <class T2, class R> friend class subtle::ReleaseHelperInternal;
+
+  static void DoRelease(const void* object) {
+    reinterpret_cast<const T*>(object)->Release();
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ReleaseHelper);
+};
+
+namespace subtle {
+
+// An internal SequencedTaskRunner-like class helper for DeleteHelper
+// and ReleaseHelper.  We don't want to expose the Do*() functions
+// directly directly since the void* argument makes it possible to
+// pass/ an object of the wrong type to delete.  Instead, we force
+// callers to go through these internal helpers for type
+// safety. SequencedTaskRunner-like classes which expose DeleteSoon or
+// ReleaseSoon methods should friend the appropriate helper and
+// implement a corresponding *Internal method with the following
+// signature:
+//
+// bool(const tracked_objects::Location&,
+//      void(*function)(const void*),
+//      void* object)
+//
+// An implementation of this function should simply create a
+// base::Closure from (function, object) and return the result of
+// posting the task.
+template <class T, class ReturnType>
+class DeleteHelperInternal {
+ public:
+  template <class SequencedTaskRunnerType>
+  static ReturnType DeleteViaSequencedTaskRunner(
+      SequencedTaskRunnerType* sequenced_task_runner,
+      const tracked_objects::Location& from_here,
+      const T* object) {
+    return sequenced_task_runner->DeleteSoonInternal(
+        from_here, &DeleteHelper<T>::DoDelete, object);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeleteHelperInternal);
+};
+
+template <class T, class ReturnType>
+class ReleaseHelperInternal {
+ public:
+  template <class SequencedTaskRunnerType>
+  static ReturnType ReleaseViaSequencedTaskRunner(
+      SequencedTaskRunnerType* sequenced_task_runner,
+      const tracked_objects::Location& from_here,
+      const T* object) {
+    return sequenced_task_runner->ReleaseSoonInternal(
+        from_here, &ReleaseHelper<T>::DoRelease, object);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReleaseHelperInternal);
+};
+
+}  // namespace subtle
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
diff --git a/base/sha1.h b/base/sha1.h
new file mode 100644
index 0000000..998cccb
--- /dev/null
+++ b/base/sha1.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SHA1_H_
+#define BASE_SHA1_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// These functions perform SHA-1 operations.
+
+static const size_t kSHA1Length = 20;  // Length in bytes of a SHA-1 hash.
+
+// Computes the SHA-1 hash of the input string |str| and returns the full
+// hash.
+BASE_EXPORT std::string SHA1HashString(const std::string& str);
+
+// Computes the SHA-1 hash of the |len| bytes in |data| and puts the hash
+// in |hash|. |hash| must be kSHA1Length bytes long.
+BASE_EXPORT void SHA1HashBytes(const unsigned char* data, size_t len,
+                               unsigned char* hash);
+
+}  // namespace base
+
+#endif  // BASE_SHA1_H_
diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc
new file mode 100644
index 0000000..0b9df83
--- /dev/null
+++ b/base/sha1_portable.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include <string.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Implementation of SHA-1. Only handles data in byte-sized blocks,
+// which simplifies the code a fair bit.
+
+// Identifier names follow notation in FIPS PUB 180-3, where you'll
+// also find a description of the algorithm:
+// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
+
+// Usage example:
+//
+// SecureHashAlgorithm sha;
+// while(there is data to hash)
+//   sha.Update(moredata, size of data);
+// sha.Final();
+// memcpy(somewhere, sha.Digest(), 20);
+//
+// to reuse the instance of sha, call sha.Init();
+
+// TODO(jhawkins): Replace this implementation with a per-platform
+// implementation using each platform's crypto library.  See
+// http://crbug.com/47218
+
+class SecureHashAlgorithm {
+ public:
+  SecureHashAlgorithm() { Init(); }
+
+  static const int kDigestSizeBytes;
+
+  void Init();
+  void Update(const void* data, size_t nbytes);
+  void Final();
+
+  // 20 bytes of message digest.
+  const unsigned char* Digest() const {
+    return reinterpret_cast<const unsigned char*>(H);
+  }
+
+ private:
+  void Pad();
+  void Process();
+
+  uint32 A, B, C, D, E;
+
+  uint32 H[5];
+
+  union {
+    uint32 W[80];
+    uint8 M[64];
+  };
+
+  uint32 cursor;
+  uint64 l;
+};
+
+static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
+  if (t < 20) {
+    return (B & C) | ((~B) & D);
+  } else if (t < 40) {
+    return B ^ C ^ D;
+  } else if (t < 60) {
+    return (B & C) | (B & D) | (C & D);
+  } else {
+    return B ^ C ^ D;
+  }
+}
+
+static inline uint32 S(uint32 n, uint32 X) {
+  return (X << n) | (X >> (32-n));
+}
+
+static inline uint32 K(uint32 t) {
+  if (t < 20) {
+    return 0x5a827999;
+  } else if (t < 40) {
+    return 0x6ed9eba1;
+  } else if (t < 60) {
+    return 0x8f1bbcdc;
+  } else {
+    return 0xca62c1d6;
+  }
+}
+
+static inline void swapends(uint32* t) {
+  *t = (*t >> 24) | ((*t >> 8) & 0xff00) | ((*t & 0xff00) << 8) | (*t << 24);
+}
+
+const int SecureHashAlgorithm::kDigestSizeBytes = 20;
+
+void SecureHashAlgorithm::Init() {
+  A = 0;
+  B = 0;
+  C = 0;
+  D = 0;
+  E = 0;
+  cursor = 0;
+  l = 0;
+  H[0] = 0x67452301;
+  H[1] = 0xefcdab89;
+  H[2] = 0x98badcfe;
+  H[3] = 0x10325476;
+  H[4] = 0xc3d2e1f0;
+}
+
+void SecureHashAlgorithm::Final() {
+  Pad();
+  Process();
+
+  for (int t = 0; t < 5; ++t)
+    swapends(&H[t]);
+}
+
+void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
+  const uint8* d = reinterpret_cast<const uint8*>(data);
+  while (nbytes--) {
+    M[cursor++] = *d++;
+    if (cursor >= 64)
+      Process();
+    l += 8;
+  }
+}
+
+void SecureHashAlgorithm::Pad() {
+  M[cursor++] = 0x80;
+
+  if (cursor > 64-8) {
+    // pad out to next block
+    while (cursor < 64)
+      M[cursor++] = 0;
+
+    Process();
+  }
+
+  while (cursor < 64-8)
+    M[cursor++] = 0;
+
+  M[cursor++] = (l >> 56) & 0xff;
+  M[cursor++] = (l >> 48) & 0xff;
+  M[cursor++] = (l >> 40) & 0xff;
+  M[cursor++] = (l >> 32) & 0xff;
+  M[cursor++] = (l >> 24) & 0xff;
+  M[cursor++] = (l >> 16) & 0xff;
+  M[cursor++] = (l >> 8) & 0xff;
+  M[cursor++] = l & 0xff;
+}
+
+void SecureHashAlgorithm::Process() {
+  uint32 t;
+
+  // Each a...e corresponds to a section in the FIPS 180-3 algorithm.
+
+  // a.
+  //
+  // W and M are in a union, so no need to memcpy.
+  // memcpy(W, M, sizeof(M));
+  for (t = 0; t < 16; ++t)
+    swapends(&W[t]);
+
+  // b.
+  for (t = 16; t < 80; ++t)
+    W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
+
+  // c.
+  A = H[0];
+  B = H[1];
+  C = H[2];
+  D = H[3];
+  E = H[4];
+
+  // d.
+  for (t = 0; t < 80; ++t) {
+    uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
+    E = D;
+    D = C;
+    C = S(30, B);
+    B = A;
+    A = TEMP;
+  }
+
+  // e.
+  H[0] += A;
+  H[1] += B;
+  H[2] += C;
+  H[3] += D;
+  H[4] += E;
+
+  cursor = 0;
+}
+
+std::string SHA1HashString(const std::string& str) {
+  char hash[SecureHashAlgorithm::kDigestSizeBytes];
+  SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.c_str()),
+                str.length(), reinterpret_cast<unsigned char*>(hash));
+  return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes);
+}
+
+void SHA1HashBytes(const unsigned char* data, size_t len,
+                   unsigned char* hash) {
+  SecureHashAlgorithm sha;
+  sha.Update(data, len);
+  sha.Final();
+
+  memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes);
+}
+
+}  // namespace base
diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc
new file mode 100644
index 0000000..b29fe46
--- /dev/null
+++ b/base/sha1_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SHA1Test, Test1) {
+  // Example A.1 from FIPS 180-2: one-block message.
+  std::string input = "abc";
+
+  int expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+                     0x47, 0x06, 0x81, 0x6a,
+                     0xba, 0x3e, 0x25, 0x71,
+                     0x78, 0x50, 0xc2, 0x6c,
+                     0x9c, 0xd0, 0xd8, 0x9d };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test2) {
+  // Example A.2 from FIPS 180-2: multi-block message.
+  std::string input =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+
+  int expected[] = { 0x84, 0x98, 0x3e, 0x44,
+                     0x1c, 0x3b, 0xd2, 0x6e,
+                     0xba, 0xae, 0x4a, 0xa1,
+                     0xf9, 0x51, 0x29, 0xe5,
+                     0xe5, 0x46, 0x70, 0xf1 };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test3) {
+  // Example A.3 from FIPS 180-2: long message.
+  std::string input(1000000, 'a');
+
+  int expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+                     0xd4, 0xc4, 0xda, 0xa4,
+                     0xf6, 0x1e, 0xeb, 0x2b,
+                     0xdb, 0xad, 0x27, 0x31,
+                     0x65, 0x34, 0x01, 0x6f };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test1Bytes) {
+  // Example A.1 from FIPS 180-2: one-block message.
+  std::string input = "abc";
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+                               0x47, 0x06, 0x81, 0x6a,
+                               0xba, 0x3e, 0x25, 0x71,
+                               0x78, 0x50, 0xc2, 0x6c,
+                               0x9c, 0xd0, 0xd8, 0x9d };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
+
+TEST(SHA1Test, Test2Bytes) {
+  // Example A.2 from FIPS 180-2: multi-block message.
+  std::string input =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0x84, 0x98, 0x3e, 0x44,
+                               0x1c, 0x3b, 0xd2, 0x6e,
+                               0xba, 0xae, 0x4a, 0xa1,
+                               0xf9, 0x51, 0x29, 0xe5,
+                               0xe5, 0x46, 0x70, 0xf1 };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
+
+TEST(SHA1Test, Test3Bytes) {
+  // Example A.3 from FIPS 180-2: long message.
+  std::string input(1000000, 'a');
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+                               0xd4, 0xc4, 0xda, 0xa4,
+                               0xf6, 0x1e, 0xeb, 0x2b,
+                               0xdb, 0xad, 0x27, 0x31,
+                               0x65, 0x34, 0x01, 0x6f };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
diff --git a/base/sha1_win.cc b/base/sha1_win.cc
new file mode 100644
index 0000000..b64c9eb
--- /dev/null
+++ b/base/sha1_win.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sha1.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+// This file is not being compiled at the moment (see bug 47218). If we keep
+// sha1 inside base, we cannot depend on src/crypto.
+// #include "crypto/scoped_capi_types.h"
+#include "base/logging.h"
+
+namespace base {
+
+std::string SHA1HashString(const std::string& str) {
+  ScopedHCRYPTPROV provider;
+  if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL,
+                           CRYPT_VERIFYCONTEXT)) {
+    DPLOG(ERROR) << "CryptAcquireContext failed";
+    return std::string(kSHA1Length, '\0');
+  }
+
+  {
+    ScopedHCRYPTHASH hash;
+    if (!CryptCreateHash(provider, CALG_SHA1, 0, 0, hash.receive())) {
+      DPLOG(ERROR) << "CryptCreateHash failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    if (!CryptHashData(hash, reinterpret_cast<CONST BYTE*>(str.data()),
+                       static_cast<DWORD>(str.length()), 0)) {
+      DPLOG(ERROR) << "CryptHashData failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    DWORD hash_len = 0;
+    DWORD buffer_size = sizeof hash_len;
+    if (!CryptGetHashParam(hash, HP_HASHSIZE,
+                           reinterpret_cast<unsigned char*>(&hash_len),
+                           &buffer_size, 0)) {
+      DPLOG(ERROR) << "CryptGetHashParam(HP_HASHSIZE) failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    std::string result;
+    if (!CryptGetHashParam(hash, HP_HASHVAL,
+        // We need the + 1 here not because the call will write a trailing \0,
+        // but so that result.length() is correctly set to |hash_len|.
+        reinterpret_cast<BYTE*>(WriteInto(&result, hash_len + 1)), &hash_len,
+        0))) {
+      DPLOG(ERROR) << "CryptGetHashParam(HP_HASHVAL) failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    if (hash_len != kSHA1Length) {
+      DLOG(ERROR) << "Returned hash value is wrong length: " << hash_len
+                  << " should be " << kSHA1Length;
+      return std::string(kSHA1Length, '\0');
+    }
+
+    return result;
+  }
+}
+
+}  // namespace base
diff --git a/base/single_thread_task_runner.h b/base/single_thread_task_runner.h
new file mode 100644
index 0000000..6e93193
--- /dev/null
+++ b/base/single_thread_task_runner.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SINGLE_THREAD_TASK_RUNNER_H_
+#define BASE_SINGLE_THREAD_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/sequenced_task_runner.h"
+
+namespace base {
+
+// A SingleThreadTaskRunner is a SequencedTaskRunner with one more
+// guarantee; namely, that all tasks are run on a single dedicated
+// thread.  Most use cases require only a SequencedTaskRunner, unless
+// there is a specific need to run tasks on only a single thread.
+//
+// SingleThreadTaskRunner implementations might:
+//   - Post tasks to an existing thread's MessageLoop (see
+//     MessageLoop::task_runner()).
+//   - Create their own worker thread and MessageLoop to post tasks to.
+//   - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
+//     be processed. This allows TaskRunner-oriented code run on threads
+//     running other kinds of message loop, e.g. Jingle threads.
+class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner {
+ public:
+  // A more explicit alias to RunsTasksOnCurrentThread().
+  bool BelongsToCurrentThread() const {
+    return RunsTasksOnCurrentThread();
+  }
+
+ protected:
+  ~SingleThreadTaskRunner() override {}
+};
+
+}  // namespace base
+
+#endif  // BASE_SINGLE_THREAD_TASK_RUNNER_H_
diff --git a/base/stl_util.h b/base/stl_util.h
new file mode 100644
index 0000000..e937d2f
--- /dev/null
+++ b/base/stl_util.h
@@ -0,0 +1,275 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Derived from google3/util/gtl/stl_util.h
+
+#ifndef BASE_STL_UTIL_H_
+#define BASE_STL_UTIL_H_
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+
+// Clears internal memory of an STL object.
+// STL clear()/reserve(0) does not always free internal memory allocated
+// This function uses swap/destructor to ensure the internal memory is freed.
+template<class T>
+void STLClearObject(T* obj) {
+  T tmp;
+  tmp.swap(*obj);
+  // Sometimes "T tmp" allocates objects with memory (arena implementation?).
+  // Hence using additional reserve(0) even if it doesn't always work.
+  obj->reserve(0);
+}
+
+// For a range within a container of pointers, calls delete (non-array version)
+// on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete *temp;
+  }
+}
+
+// For a range within a container of pairs, calls delete (non-array version) on
+// BOTH items in the pairs.
+// NOTE: Like STLDeleteContainerPointers, it is important that this deletes
+// behind the iterator because if both the key and value are deleted, the
+// container may call the hash function on the iterator when it is advanced,
+// which could result in the hash function trying to dereference a stale
+// pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPairPointers(ForwardIterator begin,
+                                    ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete temp->first;
+    delete temp->second;
+  }
+}
+
+// For a range within a container of pairs, calls delete (non-array version) on
+// the FIRST item in the pairs.
+// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+template <class ForwardIterator>
+void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
+                                         ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete temp->first;
+  }
+}
+
+// For a range within a container of pairs, calls delete.
+// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+// Deleting the value does not always invalidate the iterator, but it may
+// do so if the key is a pointer into the value object.
+template <class ForwardIterator>
+void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
+                                          ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete temp->second;
+  }
+}
+
+// Counts the number of instances of val in a container.
+template <typename Container, typename T>
+typename std::iterator_traits<
+    typename Container::const_iterator>::difference_type
+STLCount(const Container& container, const T& val) {
+  return std::count(container.begin(), container.end(), val);
+}
+
+// To treat a possibly-empty vector as an array, use these functions.
+// If you know the array will never be empty, you can use &*v.begin()
+// directly, but that is undefined behaviour if |v| is empty.
+template<typename T>
+inline T* vector_as_array(std::vector<T>* v) {
+  return v->empty() ? NULL : &*v->begin();
+}
+
+template<typename T>
+inline const T* vector_as_array(const std::vector<T>* v) {
+  return v->empty() ? NULL : &*v->begin();
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(std::string* str) {
+  // DO NOT USE const_cast<char*>(str->data())
+  return str->empty() ? NULL : &*str->begin();
+}
+
+// The following functions are useful for cleaning up STL containers whose
+// elements point to allocated memory.
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container.  This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// STLElementDeleter (defined below), which ensures that your container's
+// elements are deleted when the STLElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T* container) {
+  if (!container)
+    return;
+  STLDeleteContainerPointers(container->begin(), container->end());
+  container->clear();
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container.  Does nothing
+// in the case it's given a NULL pointer.
+template <class T>
+void STLDeleteValues(T* container) {
+  if (!container)
+    return;
+  STLDeleteContainerPairSecondPointers(container->begin(), container->end());
+  container->clear();
+}
+
+
+// The following classes provide a convenient way to delete all elements or
+// values from STL containers when they goes out of scope.  This greatly
+// simplifies code that creates temporary objects and has multiple return
+// statements.  Example:
+//
+// vector<MyProto *> tmp_proto;
+// STLElementDeleter<vector<MyProto *> > d(&tmp_proto);
+// if (...) return false;
+// ...
+// return success;
+
+// Given a pointer to an STL container this class will delete all the element
+// pointers when it goes out of scope.
+template<class T>
+class STLElementDeleter {
+ public:
+  STLElementDeleter<T>(T* container) : container_(container) {}
+  ~STLElementDeleter<T>() { STLDeleteElements(container_); }
+
+ private:
+  T* container_;
+};
+
+// Given a pointer to an STL container this class will delete all the value
+// pointers when it goes out of scope.
+template<class T>
+class STLValueDeleter {
+ public:
+  STLValueDeleter<T>(T* container) : container_(container) {}
+  ~STLValueDeleter<T>() { STLDeleteValues(container_); }
+
+ private:
+  T* container_;
+};
+
+// Test to see if a set, map, hash_set or hash_map contains a particular key.
+// Returns true if the key is in the collection.
+template <typename Collection, typename Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+  return collection.find(key) != collection.end();
+}
+
+// Test to see if a collection like a vector contains a particular value.
+// Returns true if the value is in the collection.
+template <typename Collection, typename Value>
+bool ContainsValue(const Collection& collection, const Value& value) {
+  return std::find(collection.begin(), collection.end(), value) !=
+      collection.end();
+}
+
+namespace base {
+
+// Returns true if the container is sorted.
+template <typename Container>
+bool STLIsSorted(const Container& cont) {
+  // Note: Use reverse iterator on container to ensure we only require
+  // value_type to implement operator<.
+  return std::adjacent_find(cont.rbegin(), cont.rend(),
+                            std::less<typename Container::value_type>())
+      == cont.rend();
+}
+
+// Returns a new ResultType containing the difference of two sorted containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  ResultType difference;
+  std::set_difference(a1.begin(), a1.end(),
+                      a2.begin(), a2.end(),
+                      std::inserter(difference, difference.end()));
+  return difference;
+}
+
+// Returns a new ResultType containing the union of two sorted containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  ResultType result;
+  std::set_union(a1.begin(), a1.end(),
+                 a2.begin(), a2.end(),
+                 std::inserter(result, result.end()));
+  return result;
+}
+
+// Returns a new ResultType containing the intersection of two sorted
+// containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  ResultType result;
+  std::set_intersection(a1.begin(), a1.end(),
+                        a2.begin(), a2.end(),
+                        std::inserter(result, result.end()));
+  return result;
+}
+
+// Returns true if the sorted container |a1| contains all elements of the sorted
+// container |a2|.
+template <typename Arg1, typename Arg2>
+bool STLIncludes(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  return std::includes(a1.begin(), a1.end(),
+                       a2.begin(), a2.end());
+}
+
+}  // namespace base
+
+#endif  // BASE_STL_UTIL_H_
diff --git a/base/stl_util_unittest.cc b/base/stl_util_unittest.cc
new file mode 100644
index 0000000..42004eb
--- /dev/null
+++ b/base/stl_util_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+
+#include <set>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Used as test case to ensure the various base::STLXxx functions don't require
+// more than operators "<" and "==" on values stored in containers.
+class ComparableValue {
+ public:
+  explicit ComparableValue(int value) : value_(value) {}
+
+  bool operator==(const ComparableValue& rhs) const {
+    return value_ == rhs.value_;
+  }
+
+  bool operator<(const ComparableValue& rhs) const {
+    return value_ < rhs.value_;
+  }
+
+ private:
+  int value_;
+};
+
+}  // namespace
+
+namespace base {
+namespace {
+
+TEST(STLUtilTest, STLIsSorted) {
+  {
+    std::set<int> set;
+    set.insert(24);
+    set.insert(1);
+    set.insert(12);
+    EXPECT_TRUE(STLIsSorted(set));
+  }
+
+  {
+    std::set<ComparableValue> set;
+    set.insert(ComparableValue(24));
+    set.insert(ComparableValue(1));
+    set.insert(ComparableValue(12));
+    EXPECT_TRUE(STLIsSorted(set));
+  }
+
+  {
+    std::vector<int> vector;
+    vector.push_back(1);
+    vector.push_back(1);
+    vector.push_back(4);
+    vector.push_back(64);
+    vector.push_back(12432);
+    EXPECT_TRUE(STLIsSorted(vector));
+    vector.back() = 1;
+    EXPECT_FALSE(STLIsSorted(vector));
+  }
+}
+
+TEST(STLUtilTest, STLSetDifference) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+  a2.insert(5);
+  a2.insert(6);
+  a2.insert(7);
+
+  {
+    std::set<int> difference;
+    difference.insert(1);
+    difference.insert(2);
+    EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a1, a2));
+  }
+
+  {
+    std::set<int> difference;
+    difference.insert(5);
+    difference.insert(6);
+    difference.insert(7);
+    EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a2, a1));
+  }
+
+  {
+    std::vector<int> difference;
+    difference.push_back(1);
+    difference.push_back(2);
+    EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a1, a2));
+  }
+
+  {
+    std::vector<int> difference;
+    difference.push_back(5);
+    difference.push_back(6);
+    difference.push_back(7);
+    EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a2, a1));
+  }
+}
+
+TEST(STLUtilTest, STLSetUnion) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+  a2.insert(5);
+  a2.insert(6);
+  a2.insert(7);
+
+  {
+    std::set<int> result;
+    result.insert(1);
+    result.insert(2);
+    result.insert(3);
+    result.insert(4);
+    result.insert(5);
+    result.insert(6);
+    result.insert(7);
+    EXPECT_EQ(result, STLSetUnion<std::set<int> >(a1, a2));
+  }
+
+  {
+    std::set<int> result;
+    result.insert(1);
+    result.insert(2);
+    result.insert(3);
+    result.insert(4);
+    result.insert(5);
+    result.insert(6);
+    result.insert(7);
+    EXPECT_EQ(result, STLSetUnion<std::set<int> >(a2, a1));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(1);
+    result.push_back(2);
+    result.push_back(3);
+    result.push_back(4);
+    result.push_back(5);
+    result.push_back(6);
+    result.push_back(7);
+    EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a1, a2));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(1);
+    result.push_back(2);
+    result.push_back(3);
+    result.push_back(4);
+    result.push_back(5);
+    result.push_back(6);
+    result.push_back(7);
+    EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a2, a1));
+  }
+}
+
+TEST(STLUtilTest, STLSetIntersection) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+  a2.insert(5);
+  a2.insert(6);
+  a2.insert(7);
+
+  {
+    std::set<int> result;
+    result.insert(3);
+    result.insert(4);
+    EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a1, a2));
+  }
+
+  {
+    std::set<int> result;
+    result.insert(3);
+    result.insert(4);
+    EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a2, a1));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(3);
+    result.push_back(4);
+    EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a1, a2));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(3);
+    result.push_back(4);
+    EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a2, a1));
+  }
+}
+
+TEST(STLUtilTest, STLIncludes) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+
+  std::set<int> a3;
+  a3.insert(3);
+  a3.insert(4);
+  a3.insert(5);
+
+  EXPECT_TRUE(STLIncludes<std::set<int> >(a1, a2));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a1, a3));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a1));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a3));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a3, a1));
+  EXPECT_TRUE(STLIncludes<std::set<int> >(a3, a2));
+}
+
+TEST(StringAsArrayTest, Empty) {
+  std::string empty;
+  EXPECT_EQ(nullptr, string_as_array(&empty));
+}
+
+TEST(StringAsArrayTest, NullTerminated) {
+  // If any std::string implementation is not null-terminated, this should
+  // fail. All compilers we use return a null-terminated buffer, but please do
+  // not rely on this fact in your code.
+  std::string str("abcde");
+  str.resize(3);
+  EXPECT_STREQ("abc", string_as_array(&str));
+}
+
+TEST(StringAsArrayTest, WriteCopy) {
+  // With a COW implementation, this test will fail if
+  // string_as_array(&str) is implemented as
+  // const_cast<char*>(str->data()).
+  std::string s1("abc");
+  const std::string s2(s1);
+  string_as_array(&s1)[1] = 'x';
+  EXPECT_EQ("axc", s1);
+  EXPECT_EQ("abc", s2);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/strings/OWNERS b/base/strings/OWNERS
new file mode 100644
index 0000000..5381872
--- /dev/null
+++ b/base/strings/OWNERS
@@ -0,0 +1,2 @@
+per-file safe_sprintf*=jln@chromium.org
+per-file safe_sprintf*=mdempsky@chromium.org
diff --git a/base/strings/latin1_string_conversions.cc b/base/strings/latin1_string_conversions.cc
new file mode 100644
index 0000000..dca62ce
--- /dev/null
+++ b/base/strings/latin1_string_conversions.cc
@@ -0,0 +1,19 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/latin1_string_conversions.h"
+
+namespace base {
+
+string16 Latin1OrUTF16ToUTF16(size_t length,
+                              const Latin1Char* latin1,
+                              const char16* utf16) {
+  if (!length)
+    return string16();
+  if (latin1)
+    return string16(latin1, latin1 + length);
+  return string16(utf16, utf16 + length);
+}
+
+}  // namespace base
diff --git a/base/strings/latin1_string_conversions.h b/base/strings/latin1_string_conversions.h
new file mode 100644
index 0000000..387cb65
--- /dev/null
+++ b/base/strings/latin1_string_conversions.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// This definition of Latin1Char matches the definition of LChar in Blink. We
+// use unsigned char rather than char to make less tempting to mix and match
+// Latin-1 and UTF-8 characters..
+typedef unsigned char Latin1Char;
+
+// This somewhat odd function is designed to help us convert from Blink Strings
+// to string16. A Blink string is either backed by an array of Latin-1
+// characters or an array of UTF-16 characters. This function is called by
+// WebString::operator string16() to convert one or the other character array
+// to string16. This function is defined here rather than in WebString.h to
+// avoid binary bloat in all the callers of the conversion operator.
+BASE_EXPORT string16 Latin1OrUTF16ToUTF16(size_t length,
+                                          const Latin1Char* latin1,
+                                          const char16* utf16);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
diff --git a/base/strings/nullable_string16.cc b/base/strings/nullable_string16.cc
new file mode 100644
index 0000000..07f81d4
--- /dev/null
+++ b/base/strings/nullable_string16.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/nullable_string16.h"
+
+#include <ostream>
+
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+std::ostream& operator<<(std::ostream& out, const NullableString16& value) {
+  return value.is_null() ? out << "(null)" : out << UTF16ToUTF8(value.string());
+}
+
+}  // namespace base
diff --git a/base/strings/nullable_string16.h b/base/strings/nullable_string16.h
new file mode 100644
index 0000000..016c25c
--- /dev/null
+++ b/base/strings/nullable_string16.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_NULLABLE_STRING16_H_
+#define BASE_STRINGS_NULLABLE_STRING16_H_
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// This class is a simple wrapper for string16 which also contains a null
+// state.  This should be used only where the difference between null and
+// empty is meaningful.
+class NullableString16 {
+ public:
+  NullableString16() : is_null_(true) { }
+  NullableString16(const string16& string, bool is_null)
+      : string_(string), is_null_(is_null) {
+  }
+
+  const string16& string() const { return string_; }
+  bool is_null() const { return is_null_; }
+
+ private:
+  string16 string_;
+  bool is_null_;
+};
+
+inline bool operator==(const NullableString16& a, const NullableString16& b) {
+  return a.is_null() == b.is_null() && a.string() == b.string();
+}
+
+inline bool operator!=(const NullableString16& a, const NullableString16& b) {
+  return !(a == b);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+                                     const NullableString16& value);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_NULLABLE_STRING16_H_
diff --git a/base/strings/nullable_string16_unittest.cc b/base/strings/nullable_string16_unittest.cc
new file mode 100644
index 0000000..f02fdce
--- /dev/null
+++ b/base/strings/nullable_string16_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/nullable_string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(NullableString16Test, DefaultConstructor) {
+  NullableString16 s;
+  EXPECT_TRUE(s.is_null());
+  EXPECT_EQ(string16(), s.string());
+}
+
+TEST(NullableString16Test, Equals) {
+  NullableString16 a(ASCIIToUTF16("hello"), false);
+  NullableString16 b(ASCIIToUTF16("hello"), false);
+  EXPECT_EQ(a, b);
+}
+
+TEST(NullableString16Test, NotEquals) {
+  NullableString16 a(ASCIIToUTF16("hello"), false);
+  NullableString16 b(ASCIIToUTF16("world"), false);
+  EXPECT_NE(a, b);
+}
+
+TEST(NullableString16Test, NotEqualsNull) {
+  NullableString16 a(ASCIIToUTF16("hello"), false);
+  NullableString16 b;
+  EXPECT_NE(a, b);
+}
+
+}  // namespace base
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
new file mode 100644
index 0000000..b1fcf45
--- /dev/null
+++ b/base/strings/safe_sprintf.cc
@@ -0,0 +1,685 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/safe_sprintf.h"
+
+#include <limits>
+
+#if !defined(NDEBUG)
+// In debug builds, we use RAW_CHECK() to print useful error messages, if
+// SafeSPrintf() is called with broken arguments.
+// As our contract promises that SafeSPrintf() can be called from any
+// restricted run-time context, it is not actually safe to call logging
+// functions from it; and we only ever do so for debug builds and hope for the
+// best. We should _never_ call any logging function other than RAW_CHECK(),
+// and we should _never_ include any logging code that is active in production
+// builds. Most notably, we should not include these logging functions in
+// unofficial release builds, even though those builds would otherwise have
+// DCHECKS() enabled.
+// In other words; please do not remove the #ifdef around this #include.
+// Instead, in production builds we opt for returning a degraded result,
+// whenever an error is encountered.
+// E.g. The broken function call
+//        SafeSPrintf("errno = %d (%x)", errno, strerror(errno))
+//      will print something like
+//        errno = 13, (%x)
+//      instead of
+//        errno = 13 (Access denied)
+//      In most of the anticipated use cases, that's probably the preferred
+//      behavior.
+#include "base/logging.h"
+#define DEBUG_CHECK RAW_CHECK
+#else
+#define DEBUG_CHECK(x) do { if (x) { } } while (0)
+#endif
+
+namespace base {
+namespace strings {
+
+// The code in this file is extremely careful to be async-signal-safe.
+//
+// Most obviously, we avoid calling any code that could dynamically allocate
+// memory. Doing so would almost certainly result in bugs and dead-locks.
+// We also avoid calling any other STL functions that could have unintended
+// side-effects involving memory allocation or access to other shared
+// resources.
+//
+// But on top of that, we also avoid calling other library functions, as many
+// of them have the side-effect of calling getenv() (in order to deal with
+// localization) or accessing errno. The latter sounds benign, but there are
+// several execution contexts where it isn't even possible to safely read let
+// alone write errno.
+//
+// The stated design goal of the SafeSPrintf() function is that it can be
+// called from any context that can safely call C or C++ code (i.e. anything
+// that doesn't require assembly code).
+//
+// For a brief overview of some but not all of the issues with async-signal-
+// safety, refer to:
+// http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+
+namespace {
+const size_t kSSizeMaxConst = ((size_t)(ssize_t)-1) >> 1;
+
+const char kUpCaseHexDigits[]   = "0123456789ABCDEF";
+const char kDownCaseHexDigits[] = "0123456789abcdef";
+}
+
+#if defined(NDEBUG)
+// We would like to define kSSizeMax as std::numeric_limits<ssize_t>::max(),
+// but C++ doesn't allow us to do that for constants. Instead, we have to
+// use careful casting and shifting. We later use a COMPILE_ASSERT to
+// verify that this worked correctly.
+namespace {
+const size_t kSSizeMax = kSSizeMaxConst;
+}
+#else  // defined(NDEBUG)
+// For efficiency, we really need kSSizeMax to be a constant. But for unit
+// tests, it should be adjustable. This allows us to verify edge cases without
+// having to fill the entire available address space. As a compromise, we make
+// kSSizeMax adjustable in debug builds, and then only compile that particular
+// part of the unit test in debug builds.
+namespace {
+static size_t kSSizeMax = kSSizeMaxConst;
+}
+
+namespace internal {
+void SetSafeSPrintfSSizeMaxForTest(size_t max) {
+  kSSizeMax = max;
+}
+
+size_t GetSafeSPrintfSSizeMaxForTest() {
+  return kSSizeMax;
+}
+}
+#endif  // defined(NDEBUG)
+
+namespace {
+class Buffer {
+ public:
+  // |buffer| is caller-allocated storage that SafeSPrintf() writes to. It
+  // has |size| bytes of writable storage. It is the caller's responsibility
+  // to ensure that the buffer is at least one byte in size, so that it fits
+  // the trailing NUL that will be added by the destructor. The buffer also
+  // must be smaller or equal to kSSizeMax in size.
+  Buffer(char* buffer, size_t size)
+      : buffer_(buffer),
+        size_(size - 1),  // Account for trailing NUL byte
+        count_(0) {
+// The following assertion does not build on Mac and Android. This is because
+// static_assert only works with compile-time constants, but mac uses
+// libstdc++4.2 and android uses stlport, which both don't mark
+// numeric_limits::max() as constexp.  Likewise, MSVS2013's standard library
+// also doesn't mark max() as constexpr yet. cl.exe supports static_cast but
+// doesn't really implement constexpr yet so it doesn't complain, but clang
+// does.
+#if __cplusplus >= 201103 && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
+    !defined(OS_IOS) && !(defined(__clang__) && defined(OS_WIN))
+    COMPILE_ASSERT(kSSizeMaxConst == \
+                   static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+                   kSSizeMax_is_the_max_value_of_an_ssize_t);
+#endif
+    DEBUG_CHECK(size > 0);
+    DEBUG_CHECK(size <= kSSizeMax);
+  }
+
+  ~Buffer() {
+    // The code calling the constructor guaranteed that there was enough space
+    // to store a trailing NUL -- and in debug builds, we are actually
+    // verifying this with DEBUG_CHECK()s in the constructor. So, we can
+    // always unconditionally write the NUL byte in the destructor.  We do not
+    // need to adjust the count_, as SafeSPrintf() copies snprintf() in not
+    // including the NUL byte in its return code.
+    *GetInsertionPoint() = '\000';
+  }
+
+  // Returns true, iff the buffer is filled all the way to |kSSizeMax-1|. The
+  // caller can now stop adding more data, as GetCount() has reached its
+  // maximum possible value.
+  inline bool OutOfAddressableSpace() const {
+    return count_ == static_cast<size_t>(kSSizeMax - 1);
+  }
+
+  // Returns the number of bytes that would have been emitted to |buffer_|
+  // if it was sized sufficiently large. This number can be larger than
+  // |size_|, if the caller provided an insufficiently large output buffer.
+  // But it will never be bigger than |kSSizeMax-1|.
+  inline ssize_t GetCount() const {
+    DEBUG_CHECK(count_ < kSSizeMax);
+    return static_cast<ssize_t>(count_);
+  }
+
+  // Emits one |ch| character into the |buffer_| and updates the |count_| of
+  // characters that are currently supposed to be in the buffer.
+  // Returns "false", iff the buffer was already full.
+  // N.B. |count_| increases even if no characters have been written. This is
+  // needed so that GetCount() can return the number of bytes that should
+  // have been allocated for the |buffer_|.
+  inline bool Out(char ch) {
+    if (size_ >= 1 && count_ < size_) {
+      buffer_[count_] = ch;
+      return IncrementCountByOne();
+    }
+    // |count_| still needs to be updated, even if the buffer has been
+    // filled completely. This allows SafeSPrintf() to return the number of
+    // bytes that should have been emitted.
+    IncrementCountByOne();
+    return false;
+  }
+
+  // Inserts |padding|-|len| bytes worth of padding into the |buffer_|.
+  // |count_| will also be incremented by the number of bytes that were meant
+  // to be emitted. The |pad| character is typically either a ' ' space
+  // or a '0' zero, but other non-NUL values are legal.
+  // Returns "false", iff the the |buffer_| filled up (i.e. |count_|
+  // overflowed |size_|) at any time during padding.
+  inline bool Pad(char pad, size_t padding, size_t len) {
+    DEBUG_CHECK(pad);
+    DEBUG_CHECK(padding <= kSSizeMax);
+    for (; padding > len; --padding) {
+      if (!Out(pad)) {
+        if (--padding) {
+          IncrementCount(padding-len);
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // POSIX doesn't define any async-signal-safe function for converting
+  // an integer to ASCII. Define our own version.
+  //
+  // This also gives us the ability to make the function a little more
+  // powerful and have it deal with |padding|, with truncation, and with
+  // predicting the length of the untruncated output.
+  //
+  // IToASCII() converts an integer |i| to ASCII.
+  //
+  // Unlike similar functions in the standard C library, it never appends a
+  // NUL character. This is left for the caller to do.
+  //
+  // While the function signature takes a signed int64_t, the code decides at
+  // run-time whether to treat the argument as signed (int64_t) or as unsigned
+  // (uint64_t) based on the value of |sign|.
+  //
+  // It supports |base|s 2 through 16. Only a |base| of 10 is allowed to have
+  // a |sign|. Otherwise, |i| is treated as unsigned.
+  //
+  // For bases larger than 10, |upcase| decides whether lower-case or upper-
+  // case letters should be used to designate digits greater than 10.
+  //
+  // Padding can be done with either '0' zeros or ' ' spaces. Padding has to
+  // be positive and will always be applied to the left of the output.
+  //
+  // Prepends a |prefix| to the number (e.g. "0x"). This prefix goes to
+  // the left of |padding|, if |pad| is '0'; and to the right of |padding|
+  // if |pad| is ' '.
+  //
+  // Returns "false", if the |buffer_| overflowed at any time.
+  bool IToASCII(bool sign, bool upcase, int64_t i, int base,
+                char pad, size_t padding, const char* prefix);
+
+ private:
+  // Increments |count_| by |inc| unless this would cause |count_| to
+  // overflow |kSSizeMax-1|. Returns "false", iff an overflow was detected;
+  // it then clamps |count_| to |kSSizeMax-1|.
+  inline bool IncrementCount(size_t inc) {
+    // "inc" is either 1 or a "padding" value. Padding is clamped at
+    // run-time to at most kSSizeMax-1. So, we know that "inc" is always in
+    // the range 1..kSSizeMax-1.
+    // This allows us to compute "kSSizeMax - 1 - inc" without incurring any
+    // integer overflows.
+    DEBUG_CHECK(inc <= kSSizeMax - 1);
+    if (count_ > kSSizeMax - 1 - inc) {
+      count_ = kSSizeMax - 1;
+      return false;
+    } else {
+      count_ += inc;
+      return true;
+    }
+  }
+
+  // Convenience method for the common case of incrementing |count_| by one.
+  inline bool IncrementCountByOne() {
+    return IncrementCount(1);
+  }
+
+  // Return the current insertion point into the buffer. This is typically
+  // at |buffer_| + |count_|, but could be before that if truncation
+  // happened. It always points to one byte past the last byte that was
+  // successfully placed into the |buffer_|.
+  inline char* GetInsertionPoint() const {
+    size_t idx = count_;
+    if (idx > size_) {
+      idx = size_;
+    }
+    return buffer_ + idx;
+  }
+
+  // User-provided buffer that will receive the fully formatted output string.
+  char* buffer_;
+
+  // Number of bytes that are available in the buffer excluding the trailing
+  // NUL byte that will be added by the destructor.
+  const size_t size_;
+
+  // Number of bytes that would have been emitted to the buffer, if the buffer
+  // was sufficiently big. This number always excludes the trailing NUL byte
+  // and it is guaranteed to never grow bigger than kSSizeMax-1.
+  size_t count_;
+
+  DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+
+bool Buffer::IToASCII(bool sign, bool upcase, int64_t i, int base,
+                      char pad, size_t padding, const char* prefix) {
+  // Sanity check for parameters. None of these should ever fail, but see
+  // above for the rationale why we can't call CHECK().
+  DEBUG_CHECK(base >= 2);
+  DEBUG_CHECK(base <= 16);
+  DEBUG_CHECK(!sign || base == 10);
+  DEBUG_CHECK(pad == '0' || pad == ' ');
+  DEBUG_CHECK(padding <= kSSizeMax);
+  DEBUG_CHECK(!(sign && prefix && *prefix));
+
+  // Handle negative numbers, if the caller indicated that |i| should be
+  // treated as a signed number; otherwise treat |i| as unsigned (even if the
+  // MSB is set!)
+  // Details are tricky, because of limited data-types, but equivalent pseudo-
+  // code would look like:
+  //   if (sign && i < 0)
+  //     prefix = "-";
+  //   num = abs(i);
+  int minint = 0;
+  uint64_t num;
+  if (sign && i < 0) {
+    prefix = "-";
+
+    // Turn our number positive.
+    if (i == std::numeric_limits<int64_t>::min()) {
+      // The most negative integer needs special treatment.
+      minint = 1;
+      num = static_cast<uint64_t>(-(i + 1));
+    } else {
+      // "Normal" negative numbers are easy.
+      num = static_cast<uint64_t>(-i);
+    }
+  } else {
+    num = static_cast<uint64_t>(i);
+  }
+
+  // If padding with '0' zero, emit the prefix or '-' character now. Otherwise,
+  // make the prefix accessible in reverse order, so that we can later output
+  // it right between padding and the number.
+  // We cannot choose the easier approach of just reversing the number, as that
+  // fails in situations where we need to truncate numbers that have padding
+  // and/or prefixes.
+  const char* reverse_prefix = NULL;
+  if (prefix && *prefix) {
+    if (pad == '0') {
+      while (*prefix) {
+        if (padding) {
+          --padding;
+        }
+        Out(*prefix++);
+      }
+      prefix = NULL;
+    } else {
+      for (reverse_prefix = prefix; *reverse_prefix; ++reverse_prefix) {
+      }
+    }
+  } else
+    prefix = NULL;
+  const size_t prefix_length = reverse_prefix - prefix;
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  size_t start = count_;
+  size_t discarded = 0;
+  bool started = false;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (count_ >= size_) {
+      if (start < size_) {
+        // It is rare that we need to output a partial number. But if asked
+        // to do so, we will still make sure we output the correct number of
+        // leading digits.
+        // Since we are generating the digits in reverse order, we actually
+        // have to discard digits in the order that we have already emitted
+        // them. This is essentially equivalent to:
+        //   memmove(buffer_ + start, buffer_ + start + 1, size_ - start - 1)
+        for (char* move = buffer_ + start, *end = buffer_ + size_ - 1;
+             move < end;
+             ++move) {
+          *move = move[1];
+        }
+        ++discarded;
+        --count_;
+      } else if (count_ - size_ > 1) {
+        // Need to increment either |count_| or |discarded| to make progress.
+        // The latter is more efficient, as it eventually triggers fast
+        // handling of padding. But we have to ensure we don't accidentally
+        // change the overall state (i.e. switch the state-machine from
+        // discarding to non-discarding). |count_| needs to always stay
+        // bigger than |size_|.
+        --count_;
+        ++discarded;
+      }
+    }
+
+    // Output the next digit and (if necessary) compensate for the most
+    // negative integer needing special treatment. This works because,
+    // no matter the bit width of the integer, the lowest-most decimal
+    // integer always ends in 2, 4, 6, or 8.
+    if (!num && started) {
+      if (reverse_prefix > prefix) {
+        Out(*--reverse_prefix);
+      } else {
+        Out(pad);
+      }
+    } else {
+      started = true;
+      Out((upcase ? kUpCaseHexDigits : kDownCaseHexDigits)[num%base + minint]);
+    }
+
+    minint = 0;
+    num /= base;
+
+    // Add padding, if requested.
+    if (padding > 0) {
+      --padding;
+
+      // Performance optimization for when we are asked to output excessive
+      // padding, but our output buffer is limited in size.  Even if we output
+      // a 64bit number in binary, we would never write more than 64 plus
+      // prefix non-padding characters. So, once this limit has been passed,
+      // any further state change can be computed arithmetically; we know that
+      // by this time, our entire final output consists of padding characters
+      // that have all already been output.
+      if (discarded > 8*sizeof(num) + prefix_length) {
+        IncrementCount(padding);
+        padding = 0;
+      }
+    }
+  } while (num || padding || (reverse_prefix > prefix));
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible '-' sign).
+  char* front = buffer_ + start;
+  char* back = GetInsertionPoint();
+  while (--back > front) {
+    char ch = *back;
+    *back = *front;
+    *front++ = ch;
+  }
+
+  IncrementCount(discarded);
+  return !discarded;
+}
+
+}  // anonymous namespace
+
+namespace internal {
+
+ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args,
+                     const size_t max_args) {
+  // Make sure that at least one NUL byte can be written, and that the buffer
+  // never overflows kSSizeMax. Not only does that use up most or all of the
+  // address space, it also would result in a return code that cannot be
+  // represented.
+  if (static_cast<ssize_t>(sz) < 1) {
+    return -1;
+  } else if (sz > kSSizeMax) {
+    sz = kSSizeMax;
+  }
+
+  // Iterate over format string and interpret '%' arguments as they are
+  // encountered.
+  Buffer buffer(buf, sz);
+  size_t padding;
+  char pad;
+  for (unsigned int cur_arg = 0; *fmt && !buffer.OutOfAddressableSpace(); ) {
+    if (*fmt++ == '%') {
+      padding = 0;
+      pad = ' ';
+      char ch = *fmt++;
+    format_character_found:
+      switch (ch) {
+      case '0': case '1': case '2': case '3': case '4':
+      case '5': case '6': case '7': case '8': case '9':
+        // Found a width parameter. Convert to an integer value and store in
+        // "padding". If the leading digit is a zero, change the padding
+        // character from a space ' ' to a zero '0'.
+        pad = ch == '0' ? '0' : ' ';
+        for (;;) {
+          // The maximum allowed padding fills all the available address
+          // space and leaves just enough space to insert the trailing NUL.
+          const size_t max_padding = kSSizeMax - 1;
+          if (padding > max_padding/10 ||
+              10*padding > max_padding - (ch - '0')) {
+            DEBUG_CHECK(padding <= max_padding/10 &&
+                        10*padding <= max_padding - (ch - '0'));
+            // Integer overflow detected. Skip the rest of the width until
+            // we find the format character, then do the normal error handling.
+          padding_overflow:
+            padding = max_padding;
+            while ((ch = *fmt++) >= '0' && ch <= '9') {
+            }
+            if (cur_arg < max_args) {
+              ++cur_arg;
+            }
+            goto fail_to_expand;
+          }
+          padding = 10*padding + ch - '0';
+          if (padding > max_padding) {
+            // This doesn't happen for "sane" values of kSSizeMax. But once
+            // kSSizeMax gets smaller than about 10, our earlier range checks
+            // are incomplete. Unittests do trigger this artificial corner
+            // case.
+            DEBUG_CHECK(padding <= max_padding);
+            goto padding_overflow;
+          }
+          ch = *fmt++;
+          if (ch < '0' || ch > '9') {
+            // Reached the end of the width parameter. This is where the format
+            // character is found.
+            goto format_character_found;
+          }
+        }
+        break;
+      case 'c': {  // Output an ASCII character.
+        // Check that there are arguments left to be inserted.
+        if (cur_arg >= max_args) {
+          DEBUG_CHECK(cur_arg < max_args);
+          goto fail_to_expand;
+        }
+
+        // Check that the argument has the expected type.
+        const Arg& arg = args[cur_arg++];
+        if (arg.type != Arg::INT && arg.type != Arg::UINT) {
+          DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
+          goto fail_to_expand;
+        }
+
+        // Apply padding, if needed.
+        buffer.Pad(' ', padding, 1);
+
+        // Convert the argument to an ASCII character and output it.
+        char as_char = static_cast<char>(arg.integer.i);
+        if (!as_char) {
+          goto end_of_output_buffer;
+        }
+        buffer.Out(as_char);
+        break; }
+      case 'd':    // Output a possibly signed decimal value.
+      case 'o':    // Output an unsigned octal value.
+      case 'x':    // Output an unsigned hexadecimal value.
+      case 'X':
+      case 'p': {  // Output a pointer value.
+        // Check that there are arguments left to be inserted.
+        if (cur_arg >= max_args) {
+          DEBUG_CHECK(cur_arg < max_args);
+          goto fail_to_expand;
+        }
+
+        const Arg& arg = args[cur_arg++];
+        int64_t i;
+        const char* prefix = NULL;
+        if (ch != 'p') {
+          // Check that the argument has the expected type.
+          if (arg.type != Arg::INT && arg.type != Arg::UINT) {
+            DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
+            goto fail_to_expand;
+          }
+          i = arg.integer.i;
+
+          if (ch != 'd') {
+            // The Arg() constructor automatically performed sign expansion on
+            // signed parameters. This is great when outputting a %d decimal
+            // number, but can result in unexpected leading 0xFF bytes when
+            // outputting a %x hexadecimal number. Mask bits, if necessary.
+            // We have to do this here, instead of in the Arg() constructor, as
+            // the Arg() constructor cannot tell whether we will output a %d
+            // or a %x. Only the latter should experience masking.
+            if (arg.integer.width < sizeof(int64_t)) {
+              i &= (1LL << (8*arg.integer.width)) - 1;
+            }
+          }
+        } else {
+          // Pointer values require an actual pointer or a string.
+          if (arg.type == Arg::POINTER) {
+            i = reinterpret_cast<uintptr_t>(arg.ptr);
+          } else if (arg.type == Arg::STRING) {
+            i = reinterpret_cast<uintptr_t>(arg.str);
+          } else if (arg.type == Arg::INT &&
+                     arg.integer.width == sizeof(NULL) &&
+                     arg.integer.i == 0) {  // Allow C++'s version of NULL
+            i = 0;
+          } else {
+            DEBUG_CHECK(arg.type == Arg::POINTER || arg.type == Arg::STRING);
+            goto fail_to_expand;
+          }
+
+          // Pointers always include the "0x" prefix.
+          prefix = "0x";
+        }
+
+        // Use IToASCII() to convert to ASCII representation. For decimal
+        // numbers, optionally print a sign. For hexadecimal numbers,
+        // distinguish between upper and lower case. %p addresses are always
+        // printed as upcase. Supports base 8, 10, and 16. Prints padding
+        // and/or prefixes, if so requested.
+        buffer.IToASCII(ch == 'd' && arg.type == Arg::INT,
+                        ch != 'x', i,
+                        ch == 'o' ? 8 : ch == 'd' ? 10 : 16,
+                        pad, padding, prefix);
+        break; }
+      case 's': {
+        // Check that there are arguments left to be inserted.
+        if (cur_arg >= max_args) {
+          DEBUG_CHECK(cur_arg < max_args);
+          goto fail_to_expand;
+        }
+
+        // Check that the argument has the expected type.
+        const Arg& arg = args[cur_arg++];
+        const char *s;
+        if (arg.type == Arg::STRING) {
+          s = arg.str ? arg.str : "<NULL>";
+        } else if (arg.type == Arg::INT && arg.integer.width == sizeof(NULL) &&
+                   arg.integer.i == 0) {  // Allow C++'s version of NULL
+          s = "<NULL>";
+        } else {
+          DEBUG_CHECK(arg.type == Arg::STRING);
+          goto fail_to_expand;
+        }
+
+        // Apply padding, if needed. This requires us to first check the
+        // length of the string that we are outputting.
+        if (padding) {
+          size_t len = 0;
+          for (const char* src = s; *src++; ) {
+            ++len;
+          }
+          buffer.Pad(' ', padding, len);
+        }
+
+        // Printing a string involves nothing more than copying it into the
+        // output buffer and making sure we don't output more bytes than
+        // available space; Out() takes care of doing that.
+        for (const char* src = s; *src; ) {
+          buffer.Out(*src++);
+        }
+        break; }
+      case '%':
+        // Quoted percent '%' character.
+        goto copy_verbatim;
+      fail_to_expand:
+        // C++ gives us tools to do type checking -- something that snprintf()
+        // could never really do. So, whenever we see arguments that don't
+        // match up with the format string, we refuse to output them. But
+        // since we have to be extremely conservative about being async-
+        // signal-safe, we are limited in the type of error handling that we
+        // can do in production builds (in debug builds we can use
+        // DEBUG_CHECK() and hope for the best). So, all we do is pass the
+        // format string unchanged. That should eventually get the user's
+        // attention; and in the meantime, it hopefully doesn't lose too much
+        // data.
+      default:
+        // Unknown or unsupported format character. Just copy verbatim to
+        // output.
+        buffer.Out('%');
+        DEBUG_CHECK(ch);
+        if (!ch) {
+          goto end_of_format_string;
+        }
+        buffer.Out(ch);
+        break;
+      }
+    } else {
+  copy_verbatim:
+    buffer.Out(fmt[-1]);
+    }
+  }
+ end_of_format_string:
+ end_of_output_buffer:
+  return buffer.GetCount();
+}
+
+}  // namespace internal
+
+ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt) {
+  // Make sure that at least one NUL byte can be written, and that the buffer
+  // never overflows kSSizeMax. Not only does that use up most or all of the
+  // address space, it also would result in a return code that cannot be
+  // represented.
+  if (static_cast<ssize_t>(sz) < 1) {
+    return -1;
+  } else if (sz > kSSizeMax) {
+    sz = kSSizeMax;
+  }
+
+  Buffer buffer(buf, sz);
+
+  // In the slow-path, we deal with errors by copying the contents of
+  // "fmt" unexpanded. This means, if there are no arguments passed, the
+  // SafeSPrintf() function always degenerates to a version of strncpy() that
+  // de-duplicates '%' characters.
+  const char* src = fmt;
+  for (; *src; ++src) {
+    buffer.Out(*src);
+    DEBUG_CHECK(src[0] != '%' || src[1] == '%');
+    if (src[0] == '%' && src[1] == '%') {
+      ++src;
+    }
+  }
+  return buffer.GetCount();
+}
+
+}  // namespace strings
+}  // namespace base
diff --git a/base/strings/safe_sprintf.h b/base/strings/safe_sprintf.h
new file mode 100644
index 0000000..2d17320
--- /dev/null
+++ b/base/strings/safe_sprintf.h
@@ -0,0 +1,247 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_SAFE_SPRINTF_H_
+#define BASE_STRINGS_SAFE_SPRINTF_H_
+
+#include "build/build_config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(OS_POSIX)
+// For ssize_t
+#include <unistd.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace strings {
+
+#if defined(_MSC_VER)
+// Define ssize_t inside of our namespace.
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#else
+typedef long ssize_t;
+#endif
+#endif
+
+// SafeSPrintf() is a type-safe and completely self-contained version of
+// snprintf().
+//
+// SafeSNPrintf() is an alternative function signature that can be used when
+// not dealing with fixed-sized buffers. When possible, SafeSPrintf() should
+// always be used instead of SafeSNPrintf()
+//
+// These functions allow for formatting complicated messages from contexts that
+// require strict async-signal-safety. In fact, it is safe to call them from
+// any low-level execution context, as they are guaranteed to make no library
+// or system calls. It deliberately never touches "errno", either.
+//
+// The only exception to this rule is that in debug builds the code calls
+// RAW_CHECK() to help diagnose problems when the format string does not
+// match the rest of the arguments. In release builds, no CHECK()s are used,
+// and SafeSPrintf() instead returns an output string that expands only
+// those arguments that match their format characters. Mismatched arguments
+// are ignored.
+//
+// The code currently only supports a subset of format characters:
+//   %c, %o, %d, %x, %X, %p, and %s.
+//
+// SafeSPrintf() aims to be as liberal as reasonably possible. Integer-like
+// values of arbitrary width can be passed to all of the format characters
+// that expect integers. Thus, it is explicitly legal to pass an "int" to
+// "%c", and output will automatically look at the LSB only. It is also
+// explicitly legal to pass either signed or unsigned values, and the format
+// characters will automatically interpret the arguments accordingly.
+//
+// It is still not legal to mix-and-match integer-like values with pointer
+// values. For instance, you cannot pass a pointer to %x, nor can you pass an
+// integer to %p.
+//
+// The one exception is "0" zero being accepted by "%p". This works-around
+// the problem of C++ defining NULL as an integer-like value.
+//
+// All format characters take an optional width parameter. This must be a
+// positive integer. For %d, %o, %x, %X and %p, if the width starts with
+// a leading '0', padding is done with '0' instead of ' ' characters.
+//
+// There are a few features of snprintf()-style format strings, that
+// SafeSPrintf() does not support at this time.
+//
+// If an actual user showed up, there is no particularly strong reason they
+// couldn't be added. But that assumes that the trade-offs between complexity
+// and utility are favorable.
+//
+// For example, adding support for negative padding widths, and for %n are all
+// likely to be viewed positively. They are all clearly useful, low-risk, easy
+// to test, don't jeopardize the async-signal-safety of the code, and overall
+// have little impact on other parts of SafeSPrintf() function.
+//
+// On the other hands, adding support for alternate forms, positional
+// arguments, grouping, wide characters, localization or floating point numbers
+// are all unlikely to ever be added.
+//
+// SafeSPrintf() and SafeSNPrintf() mimic the behavior of snprintf() and they
+// return the number of bytes needed to store the untruncated output. This
+// does *not* include the terminating NUL byte.
+//
+// They return -1, iff a fatal error happened. This typically can only happen,
+// if the buffer size is a) negative, or b) zero (i.e. not even the NUL byte
+// can be written). The return value can never be larger than SSIZE_MAX-1.
+// This ensures that the caller can always add one to the signed return code
+// in order to determine the amount of storage that needs to be allocated.
+//
+// While the code supports type checking and while it is generally very careful
+// to avoid printing incorrect values, it tends to be conservative in printing
+// as much as possible, even when given incorrect parameters. Typically, in
+// case of an error, the format string will not be expanded. (i.e. something
+// like SafeSPrintf(buf, "%p %d", 1, 2) results in "%p 2"). See above for
+// the use of RAW_CHECK() in debug builds, though.
+//
+// Basic example:
+//   char buf[20];
+//   base::strings::SafeSPrintf(buf, "The answer: %2d", 42);
+//
+// Example with dynamically sized buffer (async-signal-safe). This code won't
+// work on Visual studio, as it requires dynamically allocating arrays on the
+// stack. Consider picking a smaller value for |kMaxSize| if stack size is
+// limited and known. On the other hand, if the parameters to SafeSNPrintf()
+// are trusted and not controllable by the user, you can consider eliminating
+// the check for |kMaxSize| altogether. The current value of SSIZE_MAX is
+// essentially a no-op that just illustrates how to implement an upper bound:
+//   const size_t kInitialSize = 128;
+//   const size_t kMaxSize = std::numeric_limits<ssize_t>::max();
+//   size_t size = kInitialSize;
+//   for (;;) {
+//     char buf[size];
+//     size = SafeSNPrintf(buf, size, "Error message \"%s\"\n", err) + 1;
+//     if (sizeof(buf) < kMaxSize && size > kMaxSize) {
+//       size = kMaxSize;
+//       continue;
+//     } else if (size > sizeof(buf))
+//       continue;
+//     write(2, buf, size-1);
+//     break;
+//   }
+
+namespace internal {
+// Helpers that use C++ overloading, templates, and specializations to deduce
+// and record type information from function arguments. This allows us to
+// later write a type-safe version of snprintf().
+
+struct Arg {
+  enum Type { INT, UINT, STRING, POINTER };
+
+  // Any integer-like value.
+  Arg(signed char c) : type(INT) {
+    integer.i = c;
+    integer.width = sizeof(char);
+  }
+  Arg(unsigned char c) : type(UINT) {
+    integer.i = c;
+    integer.width = sizeof(char);
+  }
+  Arg(signed short j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(short);
+  }
+  Arg(unsigned short j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(short);
+  }
+  Arg(signed int j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(int);
+  }
+  Arg(unsigned int j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(int);
+  }
+  Arg(signed long j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(long);
+  }
+  Arg(unsigned long j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(long);
+  }
+  Arg(signed long long j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(long long);
+  }
+  Arg(unsigned long long j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(long long);
+  }
+
+  // A C-style text string.
+  Arg(const char* s) : str(s), type(STRING) { }
+  Arg(char* s)       : str(s), type(STRING) { }
+
+  // Any pointer value that can be cast to a "void*".
+  template<class T> Arg(T* p) : ptr((void*)p), type(POINTER) { }
+
+  union {
+    // An integer-like value.
+    struct {
+      int64_t       i;
+      unsigned char width;
+    } integer;
+
+    // A C-style text string.
+    const char* str;
+
+    // A pointer to an arbitrary object.
+    const void* ptr;
+  };
+  const enum Type type;
+};
+
+// This is the internal function that performs the actual formatting of
+// an snprintf()-style format string.
+BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt,
+                                 const Arg* args, size_t max_args);
+
+#if !defined(NDEBUG)
+// In debug builds, allow unit tests to artificially lower the kSSizeMax
+// constant that is used as a hard upper-bound for all buffers. In normal
+// use, this constant should always be std::numeric_limits<ssize_t>::max().
+BASE_EXPORT void SetSafeSPrintfSSizeMaxForTest(size_t max);
+BASE_EXPORT size_t GetSafeSPrintfSSizeMaxForTest();
+#endif
+
+}  // namespace internal
+
+template<typename... Args>
+ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args... args) {
+  // Use Arg() object to record type information and then copy arguments to an
+  // array to make it easier to iterate over them.
+  const internal::Arg arg_array[] = { args... };
+  return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
+}
+
+template<size_t N, typename... Args>
+ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, Args... args) {
+  // Use Arg() object to record type information and then copy arguments to an
+  // array to make it easier to iterate over them.
+  const internal::Arg arg_array[] = { args... };
+  return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
+}
+
+// Fast-path when we don't actually need to substitute any arguments.
+BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt);
+template<size_t N>
+inline ssize_t SafeSPrintf(char (&buf)[N], const char* fmt) {
+  return SafeSNPrintf(buf, N, fmt);
+}
+
+}  // namespace strings
+}  // namespace base
+
+#endif  // BASE_STRINGS_SAFE_SPRINTF_H_
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc
new file mode 100644
index 0000000..ff05c6e
--- /dev/null
+++ b/base/strings/safe_sprintf_unittest.cc
@@ -0,0 +1,759 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/safe_sprintf.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Death tests on Android are currently very flaky. No need to add more flaky
+// tests, as they just make it hard to spot real problems.
+// TODO(markus): See if the restrictions on Android can eventually be lifted.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+#define ALLOW_DEATH_TEST
+#endif
+
+namespace base {
+namespace strings {
+
+TEST(SafeSPrintfTest, Empty) {
+  char buf[2] = { 'X', 'X' };
+
+  // Negative buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), ""));
+  EXPECT_EQ('X', buf[0]);
+  EXPECT_EQ('X', buf[1]);
+
+  // Zero buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, 0, ""));
+  EXPECT_EQ('X', buf[0]);
+  EXPECT_EQ('X', buf[1]);
+
+  // A one-byte buffer should always print a single NUL byte.
+  EXPECT_EQ(0, SafeSNPrintf(buf, 1, ""));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_EQ('X', buf[1]);
+  buf[0] = 'X';
+
+  // A larger buffer should leave the trailing bytes unchanged.
+  EXPECT_EQ(0, SafeSNPrintf(buf, 2, ""));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_EQ('X', buf[1]);
+  buf[0] = 'X';
+
+  // The same test using SafeSPrintf() instead of SafeSNPrintf().
+  EXPECT_EQ(0, SafeSPrintf(buf, ""));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_EQ('X', buf[1]);
+  buf[0] = 'X';
+}
+
+TEST(SafeSPrintfTest, NoArguments) {
+  // Output a text message that doesn't require any substitutions. This
+  // is roughly equivalent to calling strncpy() (but unlike strncpy(), it does
+  // always add a trailing NUL; it always deduplicates '%' characters).
+  static const char text[] = "hello world";
+  char ref[20], buf[20];
+  memset(ref, 'X', sizeof(ref));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A negative buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), text));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // Zero buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, 0, text));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // A one-byte buffer should always print a single NUL byte.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 1, text));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A larger (but limited) buffer should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 2, text));
+  EXPECT_EQ(text[0], buf[0]);
+  EXPECT_EQ(0, buf[1]);
+  EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A unrestricted buffer length should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, sizeof(buf), text));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // The same test using SafeSPrintf() instead of SafeSNPrintf().
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, text));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // Check for deduplication of '%' percent characters.
+  EXPECT_EQ(1, SafeSPrintf(buf, "%%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%X"));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%%X"));
+#if defined(NDEBUG)
+  EXPECT_EQ(1, SafeSPrintf(buf, "%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%X"));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%X"));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%X"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%X"), "src.1. == '%'");
+#endif
+}
+
+TEST(SafeSPrintfTest, OneArgument) {
+  // Test basic single-argument single-character substitution.
+  const char text[] = "hello world";
+  const char fmt[]  = "hello%cworld";
+  char ref[20], buf[20];
+  memset(ref, 'X', sizeof(buf));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A negative buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), fmt, ' '));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // Zero buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, 0, fmt, ' '));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // A one-byte buffer should always print a single NUL byte.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, 1, fmt, ' '));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A larger (but limited) buffer should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, 2, fmt, ' '));
+  EXPECT_EQ(text[0], buf[0]);
+  EXPECT_EQ(0, buf[1]);
+  EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A unrestricted buffer length should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, sizeof(buf), fmt, ' '));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // The same test using SafeSPrintf() instead of SafeSNPrintf().
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, fmt, ' '));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // Check for deduplication of '%' percent characters.
+  EXPECT_EQ(1, SafeSPrintf(buf, "%%", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%%", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%Y", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%Y", 0));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%Y", 0));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%%Y", 0));
+#if defined(NDEBUG)
+  EXPECT_EQ(1, SafeSPrintf(buf, "%", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%", 0), "ch");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
+#endif
+}
+
+TEST(SafeSPrintfTest, MissingArg) {
+#if defined(NDEBUG)
+  char buf[20];
+  EXPECT_EQ(3, SafeSPrintf(buf, "%c%c", 'A'));
+  EXPECT_EQ("A%c", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  char buf[20];
+  EXPECT_DEATH(SafeSPrintf(buf, "%c%c", 'A'), "cur_arg < max_args");
+#endif
+}
+
+TEST(SafeSPrintfTest, ASANFriendlyBufferTest) {
+  // Print into a buffer that is sized exactly to size. ASAN can verify that
+  // nobody attempts to write past the end of the buffer.
+  // There is a more complicated test in PrintLongString() that covers a lot
+  // more edge case, but it is also harder to debug in case of a failure.
+  const char kTestString[] = "This is a test";
+  scoped_ptr<char[]> buf(new char[sizeof(kTestString)]);
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
+            SafeSNPrintf(buf.get(), sizeof(kTestString), kTestString));
+  EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
+            SafeSNPrintf(buf.get(), sizeof(kTestString), "%s", kTestString));
+  EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
+}
+
+TEST(SafeSPrintfTest, NArgs) {
+  // Pre-C++11 compilers have a different code path, that can only print
+  // up to ten distinct arguments.
+  // We test both SafeSPrintf() and SafeSNPrintf(). This makes sure we don't
+  // have typos in the copy-n-pasted code that is needed to deal with various
+  // numbers of arguments.
+  char buf[12];
+  EXPECT_EQ(1, SafeSPrintf(buf, "%c", 1));
+  EXPECT_EQ("\1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%c%c", 1, 2));
+  EXPECT_EQ("\1\2", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%c%c%c", 1, 2, 3));
+  EXPECT_EQ("\1\2\3", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%c%c%c%c", 1, 2, 3, 4));
+  EXPECT_EQ("\1\2\3\4", std::string(buf));
+  EXPECT_EQ(5, SafeSPrintf(buf, "%c%c%c%c%c", 1, 2, 3, 4, 5));
+  EXPECT_EQ("\1\2\3\4\5", std::string(buf));
+  EXPECT_EQ(6, SafeSPrintf(buf, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
+  EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
+  EXPECT_EQ(7, SafeSPrintf(buf, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
+  EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
+  EXPECT_EQ(8, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7, 8));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
+  EXPECT_EQ(9, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c",
+                           1, 2, 3, 4, 5, 6, 7, 8, 9));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
+  EXPECT_EQ(10, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+
+  // Repeat all the tests with SafeSNPrintf() instead of SafeSPrintf().
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
+  EXPECT_EQ(1, SafeSNPrintf(buf, 11, "%c", 1));
+  EXPECT_EQ("\1", std::string(buf));
+  EXPECT_EQ(2, SafeSNPrintf(buf, 11, "%c%c", 1, 2));
+  EXPECT_EQ("\1\2", std::string(buf));
+  EXPECT_EQ(3, SafeSNPrintf(buf, 11, "%c%c%c", 1, 2, 3));
+  EXPECT_EQ("\1\2\3", std::string(buf));
+  EXPECT_EQ(4, SafeSNPrintf(buf, 11, "%c%c%c%c", 1, 2, 3, 4));
+  EXPECT_EQ("\1\2\3\4", std::string(buf));
+  EXPECT_EQ(5, SafeSNPrintf(buf, 11, "%c%c%c%c%c", 1, 2, 3, 4, 5));
+  EXPECT_EQ("\1\2\3\4\5", std::string(buf));
+  EXPECT_EQ(6, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
+  EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
+  EXPECT_EQ(7, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
+  EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
+  EXPECT_EQ(8, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
+  EXPECT_EQ(9, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8, 9));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
+  EXPECT_EQ(10, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c%c",
+                             1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
+
+  EXPECT_EQ(11, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
+  EXPECT_EQ(11, SafeSNPrintf(buf, 12, "%c%c%c%c%c%c%c%c%c%c%c",
+                             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
+}
+
+TEST(SafeSPrintfTest, DataTypes) {
+  char buf[40];
+
+  // Bytes
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint8_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%d", (uint8_t)-1));
+  EXPECT_EQ("255", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int8_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int8_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%d", (int8_t)-128));
+  EXPECT_EQ("-128", std::string(buf));
+
+  // Half-words
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint16_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(5, SafeSPrintf(buf, "%d", (uint16_t)-1));
+  EXPECT_EQ("65535", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int16_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int16_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  EXPECT_EQ(6, SafeSPrintf(buf, "%d", (int16_t)-32768));
+  EXPECT_EQ("-32768", std::string(buf));
+
+  // Words
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint32_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(10, SafeSPrintf(buf, "%d", (uint32_t)-1));
+  EXPECT_EQ("4294967295", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int32_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int32_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  // Work-around for an limitation of C90
+  EXPECT_EQ(11, SafeSPrintf(buf, "%d", (int32_t)-2147483647-1));
+  EXPECT_EQ("-2147483648", std::string(buf));
+
+  // Quads
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint64_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(20, SafeSPrintf(buf, "%d", (uint64_t)-1));
+  EXPECT_EQ("18446744073709551615", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int64_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int64_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  // Work-around for an limitation of C90
+  EXPECT_EQ(20, SafeSPrintf(buf, "%d", (int64_t)-9223372036854775807LL-1));
+  EXPECT_EQ("-9223372036854775808", std::string(buf));
+
+  // Strings (both const and mutable).
+  EXPECT_EQ(4, SafeSPrintf(buf, "test"));
+  EXPECT_EQ("test", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, buf));
+  EXPECT_EQ("test", std::string(buf));
+
+  // Pointer
+  char addr[20];
+  sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
+  SafeSPrintf(buf, "%p", buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+  SafeSPrintf(buf, "%p", (const char *)buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+  sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)sprintf);
+  SafeSPrintf(buf, "%p", sprintf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+
+  // Padding for pointers is a little more complicated because of the "0x"
+  // prefix. Padding with '0' zeros is relatively straight-forward, but
+  // padding with ' ' spaces requires more effort.
+  sprintf(addr, "0x%017llX", (unsigned long long)(uintptr_t)buf);
+  SafeSPrintf(buf, "%019p", buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+  sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
+  memset(addr, ' ',
+         (char*)memmove(addr + sizeof(addr) - strlen(addr) - 1,
+                        addr, strlen(addr)+1) - addr);
+  SafeSPrintf(buf, "%19p", buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+}
+
+namespace {
+void PrintLongString(char* buf, size_t sz) {
+  // Output a reasonably complex expression into a limited-size buffer.
+  // At least one byte is available for writing the NUL character.
+  CHECK_GT(sz, static_cast<size_t>(0));
+
+  // Allocate slightly more space, so that we can verify that SafeSPrintf()
+  // never writes past the end of the buffer.
+  scoped_ptr<char[]> tmp(new char[sz+2]);
+  memset(tmp.get(), 'X', sz+2);
+
+  // Use SafeSPrintf() to output a complex list of arguments:
+  // - test padding and truncating %c single characters.
+  // - test truncating %s simple strings.
+  // - test mismatching arguments and truncating (for %d != %s).
+  // - test zero-padding and truncating %x hexadecimal numbers.
+  // - test outputting and truncating %d MININT.
+  // - test outputting and truncating %p arbitrary pointer values.
+  // - test outputting, padding and truncating NULL-pointer %s strings.
+  char* out = tmp.get();
+  size_t out_sz = sz;
+  size_t len;
+  for (scoped_ptr<char[]> perfect_buf;;) {
+    size_t needed = SafeSNPrintf(out, out_sz,
+#if defined(NDEBUG)
+                            "A%2cong %s: %d %010X %d %p%7s", 'l', "string", "",
+#else
+                            "A%2cong %s: %%d %010X %d %p%7s", 'l', "string",
+#endif
+                            0xDEADBEEF, std::numeric_limits<intptr_t>::min(),
+                            PrintLongString, static_cast<char*>(NULL)) + 1;
+
+    // Various sanity checks:
+    // The numbered of characters needed to print the full string should always
+    // be bigger or equal to the bytes that have actually been output.
+    len = strlen(tmp.get());
+    CHECK_GE(needed, len+1);
+
+    // The number of characters output should always fit into the buffer that
+    // was passed into SafeSPrintf().
+    CHECK_LT(len, out_sz);
+
+    // The output is always terminated with a NUL byte (actually, this test is
+    // always going to pass, as strlen() already verified this)
+    EXPECT_FALSE(tmp[len]);
+
+    // ASAN can check that we are not overwriting buffers, iff we make sure the
+    // buffer is exactly the size that we are expecting to be written. After
+    // running SafeSNPrintf() the first time, it is possible to compute the
+    // correct buffer size for this test. So, allocate a second buffer and run
+    // the exact same SafeSNPrintf() command again.
+    if (!perfect_buf.get()) {
+      out_sz = std::min(needed, sz);
+      out = new char[out_sz];
+      perfect_buf.reset(out);
+    } else {
+      break;
+    }
+  }
+
+  // All trailing bytes are unchanged.
+  for (size_t i = len+1; i < sz+2; ++i)
+    EXPECT_EQ('X', tmp[i]);
+
+  // The text that was generated by SafeSPrintf() should always match the
+  // equivalent text generated by sprintf(). Please note that the format
+  // string for sprintf() is not complicated, as it does not have the
+  // benefit of getting type information from the C++ compiler.
+  //
+  // N.B.: It would be so much cleaner to use snprintf(). But unfortunately,
+  //       Visual Studio doesn't support this function, and the work-arounds
+  //       are all really awkward.
+  char ref[256];
+  CHECK_LE(sz, sizeof(ref));
+  sprintf(ref, "A long string: %%d 00DEADBEEF %lld 0x%llX <NULL>",
+          static_cast<long long>(std::numeric_limits<intptr_t>::min()),
+          static_cast<unsigned long long>(
+            reinterpret_cast<uintptr_t>(PrintLongString)));
+  ref[sz-1] = '\000';
+
+#if defined(NDEBUG)
+  const size_t kSSizeMax = std::numeric_limits<ssize_t>::max();
+#else
+  const size_t kSSizeMax = internal::GetSafeSPrintfSSizeMaxForTest();
+#endif
+
+  // Compare the output from SafeSPrintf() to the one from sprintf().
+  EXPECT_EQ(std::string(ref).substr(0, kSSizeMax-1), std::string(tmp.get()));
+
+  // We allocated a slightly larger buffer, so that we could perform some
+  // extra sanity checks. Now that the tests have all passed, we copy the
+  // data to the output buffer that the caller provided.
+  memcpy(buf, tmp.get(), len+1);
+}
+
+#if !defined(NDEBUG)
+class ScopedSafeSPrintfSSizeMaxSetter {
+ public:
+  ScopedSafeSPrintfSSizeMaxSetter(size_t sz) {
+    old_ssize_max_ = internal::GetSafeSPrintfSSizeMaxForTest();
+    internal::SetSafeSPrintfSSizeMaxForTest(sz);
+  }
+
+  ~ScopedSafeSPrintfSSizeMaxSetter() {
+    internal::SetSafeSPrintfSSizeMaxForTest(old_ssize_max_);
+  }
+
+ private:
+  size_t old_ssize_max_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSafeSPrintfSSizeMaxSetter);
+};
+#endif
+
+}  // anonymous namespace
+
+TEST(SafeSPrintfTest, Truncation) {
+  // We use PrintLongString() to print a complex long string and then
+  // truncate to all possible lengths. This ends up exercising a lot of
+  // different code paths in SafeSPrintf() and IToASCII(), as truncation can
+  // happen in a lot of different states.
+  char ref[256];
+  PrintLongString(ref, sizeof(ref));
+  for (size_t i = strlen(ref)+1; i; --i) {
+    char buf[sizeof(ref)];
+    PrintLongString(buf, i);
+    EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
+  }
+
+  // When compiling in debug mode, we have the ability to fake a small
+  // upper limit for the maximum value that can be stored in an ssize_t.
+  // SafeSPrintf() uses this upper limit to determine how many bytes it will
+  // write to the buffer, even if the caller claimed a bigger buffer size.
+  // Repeat the truncation test and verify that this other code path in
+  // SafeSPrintf() works correctly, too.
+#if !defined(NDEBUG)
+  for (size_t i = strlen(ref)+1; i > 1; --i) {
+    ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(i);
+    char buf[sizeof(ref)];
+    PrintLongString(buf, sizeof(buf));
+    EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
+  }
+
+  // kSSizeMax is also used to constrain the maximum amount of padding, before
+  // SafeSPrintf() detects an error in the format string.
+  ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(100);
+  char buf[256];
+  EXPECT_EQ(99, SafeSPrintf(buf, "%99c", ' '));
+  EXPECT_EQ(std::string(99, ' '), std::string(buf));
+  *buf = '\000';
+#if defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%100c", ' '), "padding <= max_padding");
+#endif
+  EXPECT_EQ(0, *buf);
+#endif
+}
+
+TEST(SafeSPrintfTest, Padding) {
+  char buf[40], fmt[40];
+
+  // Chars %c
+  EXPECT_EQ(1, SafeSPrintf(buf, "%c", 'A'));
+  EXPECT_EQ("A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2c", 'A'));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02c", 'A'));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2c", 'A'));
+  EXPECT_EQ("%-2c", std::string(buf));
+  SafeSPrintf(fmt, "%%%dc", std::numeric_limits<ssize_t>::max() - 1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, SafeSPrintf(buf, fmt, 'A'));
+  SafeSPrintf(fmt, "%%%dc",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 'A'));
+  EXPECT_EQ("%c", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 'A'), "padding <= max_padding");
+#endif
+
+  // Octal %o
+  EXPECT_EQ(1, SafeSPrintf(buf, "%o", 1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2o", 1));
+  EXPECT_EQ(" 1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02o", 1));
+  EXPECT_EQ("01", std::string(buf));
+  EXPECT_EQ(12, SafeSPrintf(buf, "%12o", -1));
+  EXPECT_EQ(" 37777777777", std::string(buf));
+  EXPECT_EQ(12, SafeSPrintf(buf, "%012o", -1));
+  EXPECT_EQ("037777777777", std::string(buf));
+  EXPECT_EQ(23, SafeSPrintf(buf, "%23o", -1LL));
+  EXPECT_EQ(" 1777777777777777777777", std::string(buf));
+  EXPECT_EQ(23, SafeSPrintf(buf, "%023o", -1LL));
+  EXPECT_EQ("01777777777777777777777", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2o", 0111));
+  EXPECT_EQ("111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2o", 1));
+  EXPECT_EQ("%-2o", std::string(buf));
+  SafeSPrintf(fmt, "%%%do", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%do", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("000", std::string(buf));
+  SafeSPrintf(fmt, "%%%do",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%o", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // Decimals %d
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", 1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2d", 1));
+  EXPECT_EQ(" 1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02d", 1));
+  EXPECT_EQ("01", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%3d", -1));
+  EXPECT_EQ(" -1", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%03d", -1));
+  EXPECT_EQ("-01", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2d", 111));
+  EXPECT_EQ("111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%2d", -111));
+  EXPECT_EQ("-111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2d", 1));
+  EXPECT_EQ("%-2d", std::string(buf));
+  SafeSPrintf(fmt, "%%%dd", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%dd", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("000", std::string(buf));
+  SafeSPrintf(fmt, "%%%dd",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%d", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // Hex %X
+  EXPECT_EQ(1, SafeSPrintf(buf, "%X", 1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2X", 1));
+  EXPECT_EQ(" 1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02X", 1));
+  EXPECT_EQ("01", std::string(buf));
+  EXPECT_EQ(9, SafeSPrintf(buf, "%9X", -1));
+  EXPECT_EQ(" FFFFFFFF", std::string(buf));
+  EXPECT_EQ(9, SafeSPrintf(buf, "%09X", -1));
+  EXPECT_EQ("0FFFFFFFF", std::string(buf));
+  EXPECT_EQ(17, SafeSPrintf(buf, "%17X", -1LL));
+  EXPECT_EQ(" FFFFFFFFFFFFFFFF", std::string(buf));
+  EXPECT_EQ(17, SafeSPrintf(buf, "%017X", -1LL));
+  EXPECT_EQ("0FFFFFFFFFFFFFFFF", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2X", 0x111));
+  EXPECT_EQ("111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2X", 1));
+  EXPECT_EQ("%-2X", std::string(buf));
+  SafeSPrintf(fmt, "%%%dX", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%dX", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("000", std::string(buf));
+  SafeSPrintf(fmt, "%%%dX",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%X", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // Pointer %p
+  EXPECT_EQ(3, SafeSPrintf(buf, "%p", (void*)1));
+  EXPECT_EQ("0x1", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%4p", (void*)1));
+  EXPECT_EQ(" 0x1", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%04p", (void*)1));
+  EXPECT_EQ("0x01", std::string(buf));
+  EXPECT_EQ(5, SafeSPrintf(buf, "%4p", (void*)0x111));
+  EXPECT_EQ("0x111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2p", (void*)1));
+  EXPECT_EQ("%-2p", std::string(buf));
+  SafeSPrintf(fmt, "%%%dp", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, (void*)1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%dp", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, (void*)1));
+  EXPECT_EQ("0x0", std::string(buf));
+  SafeSPrintf(fmt, "%%%dp",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%p", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // String
+  EXPECT_EQ(1, SafeSPrintf(buf, "%s", "A"));
+  EXPECT_EQ("A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2s", "A"));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02s", "A"));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2s", "AAA"));
+  EXPECT_EQ("AAA", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2s", "A"));
+  EXPECT_EQ("%-2s", std::string(buf));
+  SafeSPrintf(fmt, "%%%ds", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, "A"));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%ds", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, "A"));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%%ds",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, "A"));
+  EXPECT_EQ("%s", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, "A"), "padding <= max_padding");
+#endif
+}
+
+TEST(SafeSPrintfTest, EmbeddedNul) {
+  char buf[] = { 'X', 'X', 'X', 'X' };
+  EXPECT_EQ(2, SafeSPrintf(buf, "%3c", 0));
+  EXPECT_EQ(' ', buf[0]);
+  EXPECT_EQ(' ', buf[1]);
+  EXPECT_EQ(0,   buf[2]);
+  EXPECT_EQ('X', buf[3]);
+
+  // Check handling of a NUL format character. N.B. this takes two different
+  // code paths depending on whether we are actually passing arguments. If
+  // we don't have any arguments, we are running in the fast-path code, that
+  // looks (almost) like a strncpy().
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
+  EXPECT_EQ("%%", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
+  EXPECT_EQ("%%", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
+#endif
+}
+
+TEST(SafeSPrintfTest, EmitNULL) {
+  char buf[40];
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion-null"
+#endif
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", NULL));
+  EXPECT_EQ("0", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%p", NULL));
+  EXPECT_EQ("0x0", std::string(buf));
+  EXPECT_EQ(6, SafeSPrintf(buf, "%s", NULL));
+  EXPECT_EQ("<NULL>", std::string(buf));
+#if defined(__GCC__)
+#pragma GCC diagnostic pop
+#endif
+}
+
+TEST(SafeSPrintfTest, PointerSize) {
+  // The internal data representation is a 64bit value, independent of the
+  // native word size. We want to perform sign-extension for signed integers,
+  // but we want to avoid doing so for pointer types. This could be a
+  // problem on systems, where pointers are only 32bit. This tests verifies
+  // that there is no such problem.
+  char *str = reinterpret_cast<char *>(0x80000000u);
+  void *ptr = str;
+  char buf[40];
+  EXPECT_EQ(10, SafeSPrintf(buf, "%p", str));
+  EXPECT_EQ("0x80000000", std::string(buf));
+  EXPECT_EQ(10, SafeSPrintf(buf, "%p", ptr));
+  EXPECT_EQ("0x80000000", std::string(buf));
+}
+
+}  // namespace strings
+}  // namespace base
diff --git a/base/strings/string16.cc b/base/strings/string16.cc
new file mode 100644
index 0000000..f4c8cf7
--- /dev/null
+++ b/base/strings/string16.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string16.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+#error This file should not be used on 2-byte wchar_t systems
+// If this winds up being needed on 2-byte wchar_t systems, either the
+// definitions below can be used, or the host system's wide character
+// functions like wmemcmp can be wrapped.
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+#include <ostream>
+
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+int c16memcmp(const char16* s1, const char16* s2, size_t n) {
+  // We cannot call memcmp because that changes the semantics.
+  while (n-- > 0) {
+    if (*s1 != *s2) {
+      // We cannot use (*s1 - *s2) because char16 is unsigned.
+      return ((*s1 < *s2) ? -1 : 1);
+    }
+    ++s1;
+    ++s2;
+  }
+  return 0;
+}
+
+size_t c16len(const char16* s) {
+  const char16 *s_orig = s;
+  while (*s) {
+    ++s;
+  }
+  return s - s_orig;
+}
+
+const char16* c16memchr(const char16* s, char16 c, size_t n) {
+  while (n-- > 0) {
+    if (*s == c) {
+      return s;
+    }
+    ++s;
+  }
+  return 0;
+}
+
+char16* c16memmove(char16* s1, const char16* s2, size_t n) {
+  return static_cast<char16*>(memmove(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memcpy(char16* s1, const char16* s2, size_t n) {
+  return static_cast<char16*>(memcpy(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memset(char16* s, char16 c, size_t n) {
+  char16 *s_orig = s;
+  while (n-- > 0) {
+    *s = c;
+    ++s;
+  }
+  return s_orig;
+}
+
+std::ostream& operator<<(std::ostream& out, const string16& str) {
+  return out << UTF16ToUTF8(str);
+}
+
+void PrintTo(const string16& str, std::ostream* out) {
+  *out << str;
+}
+
+}  // namespace base
+
+template class std::basic_string<base::char16, base::string16_char_traits>;
+
+#endif  // WCHAR_T_IS_UTF32
diff --git a/base/strings/string16.h b/base/strings/string16.h
new file mode 100644
index 0000000..1a01a96
--- /dev/null
+++ b/base/strings/string16.h
@@ -0,0 +1,184 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING16_H_
+#define BASE_STRINGS_STRING16_H_
+
+// WHAT:
+// A version of std::basic_string that provides 2-byte characters even when
+// wchar_t is not implemented as a 2-byte type. You can access this class as
+// string16. We also define char16, which string16 is based upon.
+//
+// WHY:
+// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2
+// data. Plenty of existing code operates on strings encoded as UTF-16.
+//
+// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make
+// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails
+// at run time, because it calls some functions (like wcslen) that come from
+// the system's native C library -- which was built with a 4-byte wchar_t!
+// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's
+// entirely improper on those systems where the encoding of wchar_t is defined
+// as UTF-32.
+//
+// Here, we define string16, which is similar to std::wstring but replaces all
+// libc functions with custom, 2-byte-char compatible routines. It is capable
+// of carrying UTF-16-encoded data.
+
+#include <stdio.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+namespace base {
+
+typedef wchar_t char16;
+typedef std::wstring string16;
+typedef std::char_traits<wchar_t> string16_char_traits;
+
+}  // namespace base
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+namespace base {
+
+typedef uint16 char16;
+
+// char16 versions of the functions required by string16_char_traits; these
+// are based on the wide character functions of similar names ("w" or "wcs"
+// instead of "c16").
+BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
+BASE_EXPORT size_t c16len(const char16* s);
+BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
+BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
+
+struct string16_char_traits {
+  typedef char16 char_type;
+  typedef int int_type;
+
+  // int_type needs to be able to hold each possible value of char_type, and in
+  // addition, the distinct value of eof().
+  COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width);
+
+  typedef std::streamoff off_type;
+  typedef mbstate_t state_type;
+  typedef std::fpos<state_type> pos_type;
+
+  static void assign(char_type& c1, const char_type& c2) {
+    c1 = c2;
+  }
+
+  static bool eq(const char_type& c1, const char_type& c2) {
+    return c1 == c2;
+  }
+  static bool lt(const char_type& c1, const char_type& c2) {
+    return c1 < c2;
+  }
+
+  static int compare(const char_type* s1, const char_type* s2, size_t n) {
+    return c16memcmp(s1, s2, n);
+  }
+
+  static size_t length(const char_type* s) {
+    return c16len(s);
+  }
+
+  static const char_type* find(const char_type* s, size_t n,
+                               const char_type& a) {
+    return c16memchr(s, a, n);
+  }
+
+  static char_type* move(char_type* s1, const char_type* s2, size_t n) {
+    return c16memmove(s1, s2, n);
+  }
+
+  static char_type* copy(char_type* s1, const char_type* s2, size_t n) {
+    return c16memcpy(s1, s2, n);
+  }
+
+  static char_type* assign(char_type* s, size_t n, char_type a) {
+    return c16memset(s, a, n);
+  }
+
+  static int_type not_eof(const int_type& c) {
+    return eq_int_type(c, eof()) ? 0 : c;
+  }
+
+  static char_type to_char_type(const int_type& c) {
+    return char_type(c);
+  }
+
+  static int_type to_int_type(const char_type& c) {
+    return int_type(c);
+  }
+
+  static bool eq_int_type(const int_type& c1, const int_type& c2) {
+    return c1 == c2;
+  }
+
+  static int_type eof() {
+    return static_cast<int_type>(EOF);
+  }
+};
+
+typedef std::basic_string<char16, base::string16_char_traits> string16;
+
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& out,
+                                            const string16& str);
+
+// This is required by googletest to print a readable output on test failures.
+BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out);
+
+}  // namespace base
+
+// The string class will be explicitly instantiated only once, in string16.cc.
+//
+// std::basic_string<> in GNU libstdc++ contains a static data member,
+// _S_empty_rep_storage, to represent empty strings.  When an operation such
+// as assignment or destruction is performed on a string, causing its existing
+// data member to be invalidated, it must not be freed if this static data
+// member is being used.  Otherwise, it counts as an attempt to free static
+// (and not allocated) data, which is a memory error.
+//
+// Generally, due to C++ template magic, _S_empty_rep_storage will be marked
+// as a coalesced symbol, meaning that the linker will combine multiple
+// instances into a single one when generating output.
+//
+// If a string class is used by multiple shared libraries, a problem occurs.
+// Each library will get its own copy of _S_empty_rep_storage.  When strings
+// are passed across a library boundary for alteration or destruction, memory
+// errors will result.  GNU libstdc++ contains a configuration option,
+// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which
+// disables the static data member optimization, but it's a good optimization
+// and non-STL code is generally at the mercy of the system's STL
+// configuration.  Fully-dynamic strings are not the default for GNU libstdc++
+// libstdc++ itself or for the libstdc++ installations on the systems we care
+// about, such as Mac OS X and relevant flavors of Linux.
+//
+// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 .
+//
+// To avoid problems, string classes need to be explicitly instantiated only
+// once, in exactly one library.  All other string users see it via an "extern"
+// declaration.  This is precisely how GNU libstdc++ handles
+// std::basic_string<char> (string) and std::basic_string<wchar_t> (wstring).
+//
+// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2),
+// in which the linker does not fully coalesce symbols when dead code
+// stripping is enabled.  This bug causes the memory errors described above
+// to occur even when a std::basic_string<> does not cross shared library
+// boundaries, such as in statically-linked executables.
+//
+// TODO(mark): File this bug with Apple and update this note with a bug number.
+
+extern template
+class BASE_EXPORT std::basic_string<base::char16, base::string16_char_traits>;
+
+#endif  // WCHAR_T_IS_UTF32
+
+#endif  // BASE_STRINGS_STRING16_H_
diff --git a/base/strings/string16_unittest.cc b/base/strings/string16_unittest.cc
new file mode 100644
index 0000000..4e58218
--- /dev/null
+++ b/base/strings/string16_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "base/strings/string16.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+#if defined(WCHAR_T_IS_UTF32)
+
+// We define a custom operator<< for string16 so we can use it with logging.
+// This tests that conversion.
+TEST(String16Test, OutputStream) {
+  // Basic stream test.
+  {
+    std::ostringstream stream;
+    stream << "Empty '" << string16() << "' standard '"
+           << string16(ASCIIToUTF16("Hello, world")) << "'";
+    EXPECT_STREQ("Empty '' standard 'Hello, world'",
+                 stream.str().c_str());
+  }
+
+  // Interesting edge cases.
+  {
+    // These should each get converted to the invalid character: EF BF BD.
+    string16 initial_surrogate;
+    initial_surrogate.push_back(0xd800);
+    string16 final_surrogate;
+    final_surrogate.push_back(0xdc00);
+
+    // Old italic A = U+10300, will get converted to: F0 90 8C 80 'z'.
+    string16 surrogate_pair;
+    surrogate_pair.push_back(0xd800);
+    surrogate_pair.push_back(0xdf00);
+    surrogate_pair.push_back('z');
+
+    // Will get converted to the invalid char + 's': EF BF BD 's'.
+    string16 unterminated_surrogate;
+    unterminated_surrogate.push_back(0xd800);
+    unterminated_surrogate.push_back('s');
+
+    std::ostringstream stream;
+    stream << initial_surrogate << "," << final_surrogate << ","
+           << surrogate_pair << "," << unterminated_surrogate;
+
+    EXPECT_STREQ("\xef\xbf\xbd,\xef\xbf\xbd,\xf0\x90\x8c\x80z,\xef\xbf\xbds",
+                 stream.str().c_str());
+  }
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc
new file mode 100644
index 0000000..642d24e
--- /dev/null
+++ b/base/strings/string_number_conversions.cc
@@ -0,0 +1,529 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_number_conversions.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <wctype.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/scoped_clear_errno.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/dmg_fp/dmg_fp.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT, typename UINT, bool NEG>
+struct IntToStringT {
+  // This is to avoid a compiler warning about unary minus on unsigned type.
+  // For example, say you had the following code:
+  //   template <typename INT>
+  //   INT abs(INT value) { return value < 0 ? -value : value; }
+  // Even though if INT is unsigned, it's impossible for value < 0, so the
+  // unary minus will never be taken, the compiler will still generate a
+  // warning.  We do a little specialization dance...
+  template <typename INT2, typename UINT2, bool NEG2>
+  struct ToUnsignedT {};
+
+  template <typename INT2, typename UINT2>
+  struct ToUnsignedT<INT2, UINT2, false> {
+    static UINT2 ToUnsigned(INT2 value) {
+      return static_cast<UINT2>(value);
+    }
+  };
+
+  template <typename INT2, typename UINT2>
+  struct ToUnsignedT<INT2, UINT2, true> {
+    static UINT2 ToUnsigned(INT2 value) {
+      return static_cast<UINT2>(value < 0 ? -value : value);
+    }
+  };
+
+  // This set of templates is very similar to the above templates, but
+  // for testing whether an integer is negative.
+  template <typename INT2, bool NEG2>
+  struct TestNegT {};
+  template <typename INT2>
+  struct TestNegT<INT2, false> {
+    static bool TestNeg(INT2 value) {
+      // value is unsigned, and can never be negative.
+      return false;
+    }
+  };
+  template <typename INT2>
+  struct TestNegT<INT2, true> {
+    static bool TestNeg(INT2 value) {
+      return value < 0;
+    }
+  };
+
+  static STR IntToString(INT value) {
+    // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+    // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+    const int kOutputBufSize = 3 * sizeof(INT) + 1;
+
+    // Allocate the whole string right away, we will right back to front, and
+    // then return the substr of what we ended up using.
+    STR outbuf(kOutputBufSize, 0);
+
+    bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
+    // Even though is_neg will never be true when INT is parameterized as
+    // unsigned, even the presence of the unary operation causes a warning.
+    UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
+
+    typename STR::iterator it(outbuf.end());
+    do {
+      --it;
+      DCHECK(it != outbuf.begin());
+      *it = static_cast<typename STR::value_type>((res % 10) + '0');
+      res /= 10;
+    } while (res != 0);
+    if (is_neg) {
+      --it;
+      DCHECK(it != outbuf.begin());
+      *it = static_cast<typename STR::value_type>('-');
+    }
+    return STR(it, outbuf.end());
+  }
+};
+
+// Utility to convert a character to a digit in a given base
+template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
+};
+
+// Faster specialization for bases <= 10
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
+ public:
+  static bool Convert(CHAR c, uint8* digit) {
+    if (c >= '0' && c < '0' + BASE) {
+      *digit = static_cast<uint8>(c - '0');
+      return true;
+    }
+    return false;
+  }
+};
+
+// Specialization for bases where 10 < base <= 36
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
+ public:
+  static bool Convert(CHAR c, uint8* digit) {
+    if (c >= '0' && c <= '9') {
+      *digit = c - '0';
+    } else if (c >= 'a' && c < 'a' + BASE - 10) {
+      *digit = c - 'a' + 10;
+    } else if (c >= 'A' && c < 'A' + BASE - 10) {
+      *digit = c - 'A' + 10;
+    } else {
+      return false;
+    }
+    return true;
+  }
+};
+
+template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
+  return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
+}
+
+// There is an IsWhitespace for wchars defined in string_util.h, but it is
+// locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not introduce
+// a change in behaviour.
+template<typename CHAR> class WhitespaceHelper {
+};
+
+template<> class WhitespaceHelper<char> {
+ public:
+  static bool Invoke(char c) {
+    return 0 != isspace(static_cast<unsigned char>(c));
+  }
+};
+
+template<> class WhitespaceHelper<char16> {
+ public:
+  static bool Invoke(char16 c) {
+    return 0 != iswspace(c);
+  }
+};
+
+template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
+  return WhitespaceHelper<CHAR>::Invoke(c);
+}
+
+// IteratorRangeToNumberTraits should provide:
+//  - a typedef for iterator_type, the iterator type used as input.
+//  - a typedef for value_type, the target numeric type.
+//  - static functions min, max (returning the minimum and maximum permitted
+//    values)
+//  - constant kBase, the base in which to interpret the input
+template<typename IteratorRangeToNumberTraits>
+class IteratorRangeToNumber {
+ public:
+  typedef IteratorRangeToNumberTraits traits;
+  typedef typename traits::iterator_type const_iterator;
+  typedef typename traits::value_type value_type;
+
+  // Generalized iterator-range-to-number conversion.
+  //
+  static bool Invoke(const_iterator begin,
+                     const_iterator end,
+                     value_type* output) {
+    bool valid = true;
+
+    while (begin != end && LocalIsWhitespace(*begin)) {
+      valid = false;
+      ++begin;
+    }
+
+    if (begin != end && *begin == '-') {
+      if (!std::numeric_limits<value_type>::is_signed) {
+        valid = false;
+      } else if (!Negative::Invoke(begin + 1, end, output)) {
+        valid = false;
+      }
+    } else {
+      if (begin != end && *begin == '+') {
+        ++begin;
+      }
+      if (!Positive::Invoke(begin, end, output)) {
+        valid = false;
+      }
+    }
+
+    return valid;
+  }
+
+ private:
+  // Sign provides:
+  //  - a static function, CheckBounds, that determines whether the next digit
+  //    causes an overflow/underflow
+  //  - a static function, Increment, that appends the next digit appropriately
+  //    according to the sign of the number being parsed.
+  template<typename Sign>
+  class Base {
+   public:
+    static bool Invoke(const_iterator begin, const_iterator end,
+                       typename traits::value_type* output) {
+      *output = 0;
+
+      if (begin == end) {
+        return false;
+      }
+
+      // Note: no performance difference was found when using template
+      // specialization to remove this check in bases other than 16
+      if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
+          (*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
+        begin += 2;
+      }
+
+      for (const_iterator current = begin; current != end; ++current) {
+        uint8 new_digit = 0;
+
+        if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
+          return false;
+        }
+
+        if (current != begin) {
+          if (!Sign::CheckBounds(output, new_digit)) {
+            return false;
+          }
+          *output *= traits::kBase;
+        }
+
+        Sign::Increment(new_digit, output);
+      }
+      return true;
+    }
+  };
+
+  class Positive : public Base<Positive> {
+   public:
+    static bool CheckBounds(value_type* output, uint8 new_digit) {
+      if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
+          (*output == static_cast<value_type>(traits::max() / traits::kBase) &&
+           new_digit > traits::max() % traits::kBase)) {
+        *output = traits::max();
+        return false;
+      }
+      return true;
+    }
+    static void Increment(uint8 increment, value_type* output) {
+      *output += increment;
+    }
+  };
+
+  class Negative : public Base<Negative> {
+   public:
+    static bool CheckBounds(value_type* output, uint8 new_digit) {
+      if (*output < traits::min() / traits::kBase ||
+          (*output == traits::min() / traits::kBase &&
+           new_digit > 0 - traits::min() % traits::kBase)) {
+        *output = traits::min();
+        return false;
+      }
+      return true;
+    }
+    static void Increment(uint8 increment, value_type* output) {
+      *output -= increment;
+    }
+  };
+};
+
+template<typename ITERATOR, typename VALUE, int BASE>
+class BaseIteratorRangeToNumberTraits {
+ public:
+  typedef ITERATOR iterator_type;
+  typedef VALUE value_type;
+  static value_type min() {
+    return std::numeric_limits<value_type>::min();
+  }
+  static value_type max() {
+    return std::numeric_limits<value_type>::max();
+  }
+  static const int kBase = BASE;
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToIntTraits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToUIntTraits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToInt64Traits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToUInt64Traits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
+};
+
+typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
+    HexIteratorRangeToIntTraits;
+
+typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator>
+    HexIteratorRangeToUIntTraits;
+
+typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
+    HexIteratorRangeToInt64Traits;
+
+typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
+    HexIteratorRangeToUInt64Traits;
+
+template<typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+  DCHECK_EQ(output->size(), 0u);
+  size_t count = input.size();
+  if (count == 0 || (count % 2) != 0)
+    return false;
+  for (uintptr_t i = 0; i < count / 2; ++i) {
+    uint8 msb = 0;  // most significant 4 bits
+    uint8 lsb = 0;  // least significant 4 bits
+    if (!CharToDigit<16>(input[i * 2], &msb) ||
+        !CharToDigit<16>(input[i * 2 + 1], &lsb))
+      return false;
+    output->push_back((msb << 4) | lsb);
+  }
+  return true;
+}
+
+template <typename VALUE, int BASE>
+class StringPieceToNumberTraits
+    : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator,
+                                             VALUE,
+                                             BASE> {
+};
+
+template <typename VALUE>
+bool StringToIntImpl(const StringPiece& input, VALUE* output) {
+  return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke(
+      input.begin(), input.end(), output);
+}
+
+template <typename VALUE, int BASE>
+class StringPiece16ToNumberTraits
+    : public BaseIteratorRangeToNumberTraits<StringPiece16::const_iterator,
+                                             VALUE,
+                                             BASE> {
+};
+
+template <typename VALUE>
+bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
+  return IteratorRangeToNumber<StringPiece16ToNumberTraits<VALUE, 10> >::Invoke(
+      input.begin(), input.end(), output);
+}
+
+}  // namespace
+
+std::string IntToString(int value) {
+  return IntToStringT<std::string, int, unsigned int, true>::
+      IntToString(value);
+}
+
+string16 IntToString16(int value) {
+  return IntToStringT<string16, int, unsigned int, true>::
+      IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+  return IntToStringT<std::string, unsigned int, unsigned int, false>::
+      IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+  return IntToStringT<string16, unsigned int, unsigned int, false>::
+      IntToString(value);
+}
+
+std::string Int64ToString(int64 value) {
+  return IntToStringT<std::string, int64, uint64, true>::IntToString(value);
+}
+
+string16 Int64ToString16(int64 value) {
+  return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64 value) {
+  return IntToStringT<std::string, uint64, uint64, false>::IntToString(value);
+}
+
+string16 Uint64ToString16(uint64 value) {
+  return IntToStringT<string16, uint64, uint64, false>::IntToString(value);
+}
+
+std::string SizeTToString(size_t value) {
+  return IntToStringT<std::string, size_t, size_t, false>::IntToString(value);
+}
+
+string16 SizeTToString16(size_t value) {
+  return IntToStringT<string16, size_t, size_t, false>::IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+  // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+  char buffer[32];
+  dmg_fp::g_fmt(buffer, value);
+  return std::string(buffer);
+}
+
+bool StringToInt(const StringPiece& input, int* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt(const StringPiece16& input, int* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint(const StringPiece& input, unsigned* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint(const StringPiece16& input, unsigned* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece& input, int64* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece16& input, int64* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece& input, uint64* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece16& input, uint64* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToSizeT(const StringPiece& input, size_t* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToSizeT(const StringPiece16& input, size_t* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToDouble(const std::string& input, double* output) {
+  // Thread-safe?  It is on at least Mac, Linux, and Windows.
+  ScopedClearErrno clear_errno;
+
+  char* endptr = NULL;
+  *output = dmg_fp::strtod(input.c_str(), &endptr);
+
+  // Cases to return false:
+  //  - If errno is ERANGE, there was an overflow or underflow.
+  //  - If the input string is empty, there was nothing to parse.
+  //  - If endptr does not point to the end of the string, there are either
+  //    characters remaining in the string after a parsed number, or the string
+  //    does not begin with a parseable number.  endptr is compared to the
+  //    expected end given the string's stated length to correctly catch cases
+  //    where the string contains embedded NUL characters.
+  //  - If the first character is a space, there was leading whitespace
+  return errno == 0 &&
+         !input.empty() &&
+         input.c_str() + input.length() == endptr &&
+         !isspace(input[0]);
+}
+
+// Note: if you need to add String16ToDouble, first ask yourself if it's
+// really necessary. If it is, probably the best implementation here is to
+// convert to 8-bit and then use the 8-bit version.
+
+// Note: if you need to add an iterator range version of StringToDouble, first
+// ask yourself if it's really necessary. If it is, probably the best
+// implementation here is to instantiate a string and use the string version.
+
+std::string HexEncode(const void* bytes, size_t size) {
+  static const char kHexChars[] = "0123456789ABCDEF";
+
+  // Each input byte creates two output hex characters.
+  std::string ret(size * 2, '\0');
+
+  for (size_t i = 0; i < size; ++i) {
+    char b = reinterpret_cast<const char*>(bytes)[i];
+    ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+    ret[(i * 2) + 1] = kHexChars[b & 0xf];
+  }
+  return ret;
+}
+
+bool HexStringToInt(const StringPiece& input, int* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
+    input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt(const StringPiece& input, uint32* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
+bool HexStringToInt64(const StringPiece& input, int64* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
+    input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt64(const StringPiece& input, uint64* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+  return HexStringToBytesT(input, output);
+}
+
+}  // namespace base
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
new file mode 100644
index 0000000..050e627
--- /dev/null
+++ b/base/strings/string_number_conversions.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+BASE_EXPORT std::string IntToString(int value);
+BASE_EXPORT string16 IntToString16(int value);
+
+BASE_EXPORT std::string UintToString(unsigned value);
+BASE_EXPORT string16 UintToString16(unsigned value);
+
+BASE_EXPORT std::string Int64ToString(int64 value);
+BASE_EXPORT string16 Int64ToString16(int64 value);
+
+BASE_EXPORT std::string Uint64ToString(uint64 value);
+BASE_EXPORT string16 Uint64ToString16(uint64 value);
+
+BASE_EXPORT std::string SizeTToString(size_t value);
+BASE_EXPORT string16 SizeTToString16(size_t value);
+
+// DoubleToString converts the double to a string format that ignores the
+// locale. If you want to use locale specific formatting, use ICU.
+BASE_EXPORT std::string DoubleToString(double value);
+
+// String -> number conversions ------------------------------------------------
+
+// Perform a best-effort conversion of the input string to a numeric type,
+// setting |*output| to the result of the conversion.  Returns true for
+// "perfect" conversions; returns false in the following cases:
+//  - Overflow. |*output| will be set to the maximum value supported
+//    by the data type.
+//  - Underflow. |*output| will be set to the minimum value supported
+//    by the data type.
+//  - Trailing characters in the string after parsing the number.  |*output|
+//    will be set to the value of the number that was parsed.
+//  - Leading whitespace in the string before parsing the number. |*output| will
+//    be set to the value of the number that was parsed.
+//  - No characters parseable as a number at the beginning of the string.
+//    |*output| will be set to 0.
+//  - Empty string.  |*output| will be set to 0.
+BASE_EXPORT bool StringToInt(const StringPiece& input, int* output);
+BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
+
+BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output);
+BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output);
+
+BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output);
+BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output);
+
+BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
+BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
+
+BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
+BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work.  Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-fininte values (such as
+// NaN and inf) is undefined.  Otherwise, these behave the same as the integral
+// variants.  This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind.  If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+//   std::numeric_limits<size_t>::max() / 2
+BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// -0x80000000 < |input| < 0x7FFFFFFF.
+BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// 0x00000000 < |input| < 0xFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
+BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output);
+
+// Similar to the previous functions, except that output is a vector of bytes.
+// |*output| will contain as many bytes as were successfully parsed prior to the
+// error.  There is no overflow, but input.size() must be evenly divisible by 2.
+// Leading 0x or +/- are not allowed.
+BASE_EXPORT bool HexStringToBytes(const std::string& input,
+                                  std::vector<uint8>* output);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
new file mode 100644
index 0000000..4787614
--- /dev/null
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -0,0 +1,795 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cmath>
+#include <limits>
+
+#include "base/format_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+template <typename INT>
+struct IntToStringTest {
+  INT num;
+  const char* sexpected;
+  const char* uexpected;
+};
+
+}  // namespace
+
+TEST(StringNumberConversionsTest, IntToString) {
+  static const IntToStringTest<int> int_tests[] = {
+      { 0, "0", "0" },
+      { -1, "-1", "4294967295" },
+      { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
+      { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
+  };
+  static const IntToStringTest<int64> int64_tests[] = {
+      { 0, "0", "0" },
+      { -1, "-1", "18446744073709551615" },
+      { std::numeric_limits<int64>::max(),
+        "9223372036854775807",
+        "9223372036854775807", },
+      { std::numeric_limits<int64>::min(),
+        "-9223372036854775808",
+        "9223372036854775808" },
+  };
+
+  for (size_t i = 0; i < arraysize(int_tests); ++i) {
+    const IntToStringTest<int>* test = &int_tests[i];
+    EXPECT_EQ(IntToString(test->num), test->sexpected);
+    EXPECT_EQ(IntToString16(test->num), UTF8ToUTF16(test->sexpected));
+    EXPECT_EQ(UintToString(test->num), test->uexpected);
+    EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
+  }
+  for (size_t i = 0; i < arraysize(int64_tests); ++i) {
+    const IntToStringTest<int64>* test = &int64_tests[i];
+    EXPECT_EQ(Int64ToString(test->num), test->sexpected);
+    EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected));
+    EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
+    EXPECT_EQ(Uint64ToString16(test->num), UTF8ToUTF16(test->uexpected));
+  }
+}
+
+TEST(StringNumberConversionsTest, Uint64ToString) {
+  static const struct {
+    uint64 input;
+    std::string output;
+  } cases[] = {
+    {0, "0"},
+    {42, "42"},
+    {INT_MAX, "2147483647"},
+    {kuint64max, "18446744073709551615"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
+}
+
+TEST(StringNumberConversionsTest, SizeTToString) {
+  size_t size_t_max = std::numeric_limits<size_t>::max();
+  std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max);
+
+  static const struct {
+    size_t input;
+    std::string output;
+  } cases[] = {
+    {0, "0"},
+    {9, "9"},
+    {42, "42"},
+    {INT_MAX, "2147483647"},
+    {2147483648U, "2147483648"},
+#if SIZE_MAX > 4294967295U
+    {99999999999U, "99999999999"},
+#endif
+    {size_t_max, size_t_max_string},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
+}
+
+TEST(StringNumberConversionsTest, StringToInt) {
+  static const struct {
+    std::string input;
+    int output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"42\x99", 42, false},
+    {"\x99" "42\x99", 0, false},
+    {"-2147483648", INT_MIN, true},
+    {"2147483647", INT_MAX, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", -273, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-2147483649", INT_MIN, false},
+    {"-99999999999", INT_MIN, false},
+    {"2147483648", INT_MAX, false},
+    {"99999999999", INT_MAX, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  int output;
+  EXPECT_FALSE(StringToInt(input_string, &output));
+  EXPECT_EQ(6, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToInt(utf16_input, &output));
+  EXPECT_EQ(6, output);
+
+  output = 0;
+  const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0};
+  EXPECT_FALSE(StringToInt(string16(negative_wide_input), &output));
+  EXPECT_EQ(0, output);
+}
+
+TEST(StringNumberConversionsTest, StringToUint) {
+  static const struct {
+    std::string input;
+    unsigned output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"42\x99", 42, false},
+    {"\x99" "42\x99", 0, false},
+    {"-2147483648", 0, false},
+    {"2147483647", INT_MAX, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", 0, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-2147483649", 0, false},
+    {"-99999999999", 0, false},
+    {"4294967295", UINT_MAX, true},
+    {"4294967296", UINT_MAX, false},
+    {"99999999999", UINT_MAX, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    unsigned output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  unsigned output;
+  EXPECT_FALSE(StringToUint(input_string, &output));
+  EXPECT_EQ(6U, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToUint(utf16_input, &output));
+  EXPECT_EQ(6U, output);
+
+  output = 0;
+  const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0};
+  EXPECT_FALSE(StringToUint(string16(negative_wide_input), &output));
+  EXPECT_EQ(0U, output);
+}
+
+TEST(StringNumberConversionsTest, StringToInt64) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", INT_MIN, true},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", GG_INT64_C(-2147483649), true},
+    {"-99999999999", GG_INT64_C(-99999999999), true},
+    {"2147483648", GG_INT64_C(2147483648), true},
+    {"99999999999", GG_INT64_C(99999999999), true},
+    {"9223372036854775807", kint64max, true},
+    {"-9223372036854775808", kint64min, true},
+    {"09", 9, true},
+    {"-09", -9, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", -273, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", kint64min, false},
+    {"-99999999999999999999", kint64min, false},
+    {"9223372036854775808", kint64max, false},
+    {"99999999999999999999", kint64max, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int64 output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  int64 output;
+  EXPECT_FALSE(StringToInt64(input_string, &output));
+  EXPECT_EQ(6, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToInt64(utf16_input, &output));
+  EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, StringToUint64) {
+  static const struct {
+    std::string input;
+    uint64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", 0, false},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", 0, false},
+    {"-99999999999", 0, false},
+    {"2147483648", GG_UINT64_C(2147483648), true},
+    {"99999999999", GG_UINT64_C(99999999999), true},
+    {"9223372036854775807", kint64max, true},
+    {"-9223372036854775808", 0, false},
+    {"09", 9, true},
+    {"-09", 0, false},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", 0, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", 0, false},
+    {"-99999999999999999999", 0, false},
+    {"9223372036854775808", GG_UINT64_C(9223372036854775808), true},
+    {"99999999999999999999", kuint64max, false},
+    {"18446744073709551615", kuint64max, true},
+    {"18446744073709551616", kuint64max, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64 output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint64(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  uint64 output;
+  EXPECT_FALSE(StringToUint64(input_string, &output));
+  EXPECT_EQ(6U, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToUint64(utf16_input, &output));
+  EXPECT_EQ(6U, output);
+}
+
+TEST(StringNumberConversionsTest, StringToSizeT) {
+  size_t size_t_max = std::numeric_limits<size_t>::max();
+  std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max);
+
+  static const struct {
+    std::string input;
+    size_t output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", 0, false},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", 0, false},
+    {"-99999999999", 0, false},
+    {"2147483648", 2147483648U, true},
+#if SIZE_MAX > 4294967295U
+    {"99999999999", 99999999999U, true},
+#endif
+    {"-9223372036854775808", 0, false},
+    {"09", 9, true},
+    {"-09", 0, false},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", 0, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", 0, false},
+    {"-99999999999999999999", 0, false},
+    {"999999999999999999999999", size_t_max, false},
+    {size_t_max_string, size_t_max, true},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    size_t output = 0;
+    EXPECT_EQ(cases[i].success, StringToSizeT(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToSizeT(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  size_t output;
+  EXPECT_FALSE(StringToSizeT(input_string, &output));
+  EXPECT_EQ(6U, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToSizeT(utf16_input, &output));
+  EXPECT_EQ(6U, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", -66, true},
+    {"+42", 66, true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", INT_MIN, true},
+    {"80000000", INT_MAX, false},  // Overflow test.
+    {"-80000001", INT_MIN, false},  // Underflow test.
+    {"0x42", 66, true},
+    {"-0x42", -66, true},
+    {"+0x42", 66, true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", INT_MIN, true},
+    {"-80000000", INT_MIN, true},
+    {"80000000", INT_MAX, false},  // Overflow test.
+    {"-80000001", INT_MIN, false},  // Underflow test.
+    {"0x0f", 15, true},
+    {"0f", 15, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  int output;
+  EXPECT_FALSE(HexStringToInt(input_string, &output));
+  EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToUInt) {
+  static const struct {
+    std::string input;
+    uint32 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 0x42, true},
+    {"-42", 0, false},
+    {"+42", 0x42, true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", 0, false},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 0x42, true},
+    {"-0x42", 0, false},
+    {"+0x42", 0x42, true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", 0, false},
+    {"0xffffffff", kuint32max, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kuint32max, false},  // Overflow test.
+    {"-0x8000000000000000", 0, false},
+    {"0x8000000000000000", kuint32max, false},  // Overflow test.
+    {"-0x8000000000000001", 0, false},
+    {"0xFFFFFFFFFFFFFFFF", kuint32max, false},  // Overflow test.
+    {"FFFFFFFFFFFFFFFF", kuint32max, false},  // Overflow test.
+    {"0x0000000000000000", 0, true},
+    {"0000000000000000", 0, true},
+    {"1FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
+    {"0x0f", 0x0f, true},
+    {"0f", 0x0f, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint32 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  uint32 output;
+  EXPECT_FALSE(HexStringToUInt(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt64) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", -66, true},
+    {"+42", 66, true},
+    {"40acd88557b", GG_INT64_C(4444444448123), true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", INT_MIN, true},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 66, true},
+    {"-0x42", -66, true},
+    {"+0x42", 66, true},
+    {"0x40acd88557b", GG_INT64_C(4444444448123), true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", INT_MIN, true},
+    {"0xffffffff", 0xffffffff, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kint64max, true},
+    {"-0x8000000000000000", kint64min, true},
+    {"0x8000000000000000", kint64max, false},  // Overflow test.
+    {"-0x8000000000000001", kint64min, false},  // Underflow test.
+    {"0x0f", 15, true},
+    {"0f", 15, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int64 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  int64 output;
+  EXPECT_FALSE(HexStringToInt64(input_string, &output));
+  EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToUInt64) {
+  static const struct {
+    std::string input;
+    uint64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", 0, false},
+    {"+42", 66, true},
+    {"40acd88557b", GG_INT64_C(4444444448123), true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", 0, false},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 66, true},
+    {"-0x42", 0, false},
+    {"+0x42", 66, true},
+    {"0x40acd88557b", GG_INT64_C(4444444448123), true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", 0, false},
+    {"0xffffffff", 0xffffffff, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kint64max, true},
+    {"-0x8000000000000000", 0, false},
+    {"0x8000000000000000", GG_UINT64_C(0x8000000000000000), true},
+    {"-0x8000000000000001", 0, false},
+    {"0xFFFFFFFFFFFFFFFF", kuint64max, true},
+    {"FFFFFFFFFFFFFFFF", kuint64max, true},
+    {"0x0000000000000000", 0, true},
+    {"0000000000000000", 0, true},
+    {"1FFFFFFFFFFFFFFFF", kuint64max, false}, // Overflow test.
+    {"0x0f", 15, true},
+    {"0f", 15, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  uint64 output;
+  EXPECT_FALSE(HexStringToUInt64(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToBytes) {
+  static const struct {
+    const std::string input;
+    const char* output;
+    size_t output_len;
+    bool success;
+  } cases[] = {
+    {"0", "", 0, false},  // odd number of characters fails
+    {"00", "\0", 1, true},
+    {"42", "\x42", 1, true},
+    {"-42", "", 0, false},  // any non-hex value fails
+    {"+42", "", 0, false},
+    {"7fffffff", "\x7f\xff\xff\xff", 4, true},
+    {"80000000", "\x80\0\0\0", 4, true},
+    {"deadbeef", "\xde\xad\xbe\xef", 4, true},
+    {"DeadBeef", "\xde\xad\xbe\xef", 4, true},
+    {"0x42", "", 0, false},  // leading 0x fails (x is not hex)
+    {"0f", "\xf", 1, true},
+    {"45  ", "\x45", 1, false},
+    {"efgh", "\xef", 1, false},
+    {"", "", 0, false},
+    {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true},
+    {"0123456789ABCDEF012345",
+     "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true},
+  };
+
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    std::vector<uint8> output;
+    std::vector<uint8> compare;
+    EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
+        i << ": " << cases[i].input;
+    for (size_t j = 0; j < cases[i].output_len; ++j)
+      compare.push_back(static_cast<uint8>(cases[i].output[j]));
+    ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
+    EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
+        i << ": " << cases[i].input;
+  }
+}
+
+TEST(StringNumberConversionsTest, StringToDouble) {
+  static const struct {
+    std::string input;
+    double output;
+    bool success;
+  } cases[] = {
+    {"0", 0.0, true},
+    {"42", 42.0, true},
+    {"-42", -42.0, true},
+    {"123.45", 123.45, true},
+    {"-123.45", -123.45, true},
+    {"+123.45", 123.45, true},
+    {"2.99792458e8", 299792458.0, true},
+    {"149597870.691E+3", 149597870691.0, true},
+    {"6.", 6.0, true},
+    {"9e99999999999999999999", HUGE_VAL, false},
+    {"-9e99999999999999999999", -HUGE_VAL, false},
+    {"1e-2", 0.01, true},
+    {"42 ", 42.0, false},
+    {" 1e-2", 0.01, false},
+    {"1e-2 ", 0.01, false},
+    {"-1E-7", -0.0000001, true},
+    {"01e02", 100, true},
+    {"2.3e15", 2.3e15, true},
+    {"\t\n\v\f\r -123.45e2", -12345.0, false},
+    {"+123 e4", 123.0, false},
+    {"123e ", 123.0, false},
+    {"123e", 123.0, false},
+    {" 2.99", 2.99, false},
+    {"1e3.4", 1000.0, false},
+    {"nothing", 0.0, false},
+    {"-", 0.0, false},
+    {"+", 0.0, false},
+    {"", 0.0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    double output;
+    errno = 1;
+    EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
+    if (cases[i].success)
+      EXPECT_EQ(1, errno) << i;  // confirm that errno is unchanged.
+    EXPECT_DOUBLE_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "3.14\0" "159";
+  std::string input_string(input, arraysize(input) - 1);
+  double output;
+  EXPECT_FALSE(StringToDouble(input_string, &output));
+  EXPECT_DOUBLE_EQ(3.14, output);
+}
+
+TEST(StringNumberConversionsTest, DoubleToString) {
+  static const struct {
+    double input;
+    const char* expected;
+  } cases[] = {
+    {0.0, "0"},
+    {1.25, "1.25"},
+    {1.33518e+012, "1.33518e+12"},
+    {1.33489e+012, "1.33489e+12"},
+    {1.33505e+012, "1.33505e+12"},
+    {1.33545e+009, "1335450000"},
+    {1.33503e+009, "1335030000"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    EXPECT_EQ(cases[i].expected, DoubleToString(cases[i].input));
+  }
+
+  // The following two values were seen in crashes in the wild.
+  const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'};
+  double input = 0;
+  memcpy(&input, input_bytes, arraysize(input_bytes));
+  EXPECT_EQ("1335179083776", DoubleToString(input));
+  const char input_bytes2[8] =
+      {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'};
+  input = 0;
+  memcpy(&input, input_bytes2, arraysize(input_bytes2));
+  EXPECT_EQ("1334890332160", DoubleToString(input));
+}
+
+TEST(StringNumberConversionsTest, HexEncode) {
+  std::string hex(HexEncode(NULL, 0));
+  EXPECT_EQ(hex.length(), 0U);
+  unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
+  hex = HexEncode(bytes, sizeof(bytes));
+  EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
+}
+
+}  // namespace base
diff --git a/base/strings/string_piece.cc b/base/strings/string_piece.cc
new file mode 100644
index 0000000..4c7f112
--- /dev/null
+++ b/base/strings/string_piece.cc
@@ -0,0 +1,437 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Copied from strings/stringpiece.cc with modifications
+
+#include "base/strings/string_piece.h"
+
+#include <algorithm>
+#include <ostream>
+
+namespace base {
+namespace {
+
+// For each character in characters_wanted, sets the index corresponding
+// to the ASCII code of that character to 1 in table.  This is used by
+// the find_.*_of methods below to tell whether or not a character is in
+// the lookup table in constant time.
+// The argument `table' must be an array that is large enough to hold all
+// the possible values of an unsigned char.  Thus it should be be declared
+// as follows:
+//   bool table[UCHAR_MAX + 1]
+inline void BuildLookupTable(const StringPiece& characters_wanted,
+                             bool* table) {
+  const size_t length = characters_wanted.length();
+  const char* const data = characters_wanted.data();
+  for (size_t i = 0; i < length; ++i) {
+    table[static_cast<unsigned char>(data[i])] = true;
+  }
+}
+
+}  // namespace
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+template class BasicStringPiece<std::string>;
+template class BasicStringPiece<string16>;
+#endif
+
+bool operator==(const StringPiece& x, const StringPiece& y) {
+  if (x.size() != y.size())
+    return false;
+
+  return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
+  o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
+  return o;
+}
+
+namespace internal {
+
+template<typename STR>
+void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) {
+  if (self.empty())
+    target->clear();
+  else
+    target->assign(self.data(), self.size());
+}
+
+void CopyToString(const StringPiece& self, std::string* target) {
+  CopyToStringT(self, target);
+}
+
+void CopyToString(const StringPiece16& self, string16* target) {
+  CopyToStringT(self, target);
+}
+
+template<typename STR>
+void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
+  if (!self.empty())
+    target->append(self.data(), self.size());
+}
+
+void AppendToString(const StringPiece& self, std::string* target) {
+  AppendToStringT(self, target);
+}
+
+void AppendToString(const StringPiece16& self, string16* target) {
+  AppendToStringT(self, target);
+}
+
+template<typename STR>
+size_t copyT(const BasicStringPiece<STR>& self,
+             typename STR::value_type* buf,
+             size_t n,
+             size_t pos) {
+  size_t ret = std::min(self.size() - pos, n);
+  memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
+  return ret;
+}
+
+size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
+  return copyT(self, buf, n, pos);
+}
+
+size_t copy(const StringPiece16& self, char16* buf, size_t n, size_t pos) {
+  return copyT(self, buf, n, pos);
+}
+
+template<typename STR>
+size_t findT(const BasicStringPiece<STR>& self,
+             const BasicStringPiece<STR>& s,
+             size_t pos) {
+  if (pos > self.size())
+    return BasicStringPiece<STR>::npos;
+
+  typename BasicStringPiece<STR>::const_iterator result =
+      std::search(self.begin() + pos, self.end(), s.begin(), s.end());
+  const size_t xpos =
+    static_cast<size_t>(result - self.begin());
+  return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
+}
+
+size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
+  return findT(self, s, pos);
+}
+
+size_t find(const StringPiece16& self, const StringPiece16& s, size_t pos) {
+  return findT(self, s, pos);
+}
+
+template<typename STR>
+size_t findT(const BasicStringPiece<STR>& self,
+             typename STR::value_type c,
+             size_t pos) {
+  if (pos >= self.size())
+    return BasicStringPiece<STR>::npos;
+
+  typename BasicStringPiece<STR>::const_iterator result =
+      std::find(self.begin() + pos, self.end(), c);
+  return result != self.end() ?
+      static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
+}
+
+size_t find(const StringPiece& self, char c, size_t pos) {
+  return findT(self, c, pos);
+}
+
+size_t find(const StringPiece16& self, char16 c, size_t pos) {
+  return findT(self, c, pos);
+}
+
+template<typename STR>
+size_t rfindT(const BasicStringPiece<STR>& self,
+              const BasicStringPiece<STR>& s,
+              size_t pos) {
+  if (self.size() < s.size())
+    return BasicStringPiece<STR>::npos;
+
+  if (s.empty())
+    return std::min(self.size(), pos);
+
+  typename BasicStringPiece<STR>::const_iterator last =
+      self.begin() + std::min(self.size() - s.size(), pos) + s.size();
+  typename BasicStringPiece<STR>::const_iterator result =
+      std::find_end(self.begin(), last, s.begin(), s.end());
+  return result != last ?
+      static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
+}
+
+size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
+  return rfindT(self, s, pos);
+}
+
+size_t rfind(const StringPiece16& self, const StringPiece16& s, size_t pos) {
+  return rfindT(self, s, pos);
+}
+
+template<typename STR>
+size_t rfindT(const BasicStringPiece<STR>& self,
+              typename STR::value_type c,
+              size_t pos) {
+  if (self.size() == 0)
+    return BasicStringPiece<STR>::npos;
+
+  for (size_t i = std::min(pos, self.size() - 1); ;
+       --i) {
+    if (self.data()[i] == c)
+      return i;
+    if (i == 0)
+      break;
+  }
+  return BasicStringPiece<STR>::npos;
+}
+
+size_t rfind(const StringPiece& self, char c, size_t pos) {
+  return rfindT(self, c, pos);
+}
+
+size_t rfind(const StringPiece16& self, char16 c, size_t pos) {
+  return rfindT(self, c, pos);
+}
+
+// 8-bit version using lookup table.
+size_t find_first_of(const StringPiece& self,
+                     const StringPiece& s,
+                     size_t pos) {
+  if (self.size() == 0 || s.size() == 0)
+    return StringPiece::npos;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return find(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_t i = pos; i < self.size(); ++i) {
+    if (lookup[static_cast<unsigned char>(self.data()[i])]) {
+      return i;
+    }
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute force version.
+size_t find_first_of(const StringPiece16& self,
+                     const StringPiece16& s,
+                     size_t pos) {
+  StringPiece16::const_iterator found =
+      std::find_first_of(self.begin() + pos, self.end(), s.begin(), s.end());
+  if (found == self.end())
+    return StringPiece16::npos;
+  return found - self.begin();
+}
+
+// 8-bit version using lookup table.
+size_t find_first_not_of(const StringPiece& self,
+                         const StringPiece& s,
+                         size_t pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  if (s.size() == 0)
+    return 0;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return find_first_not_of(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_t i = pos; i < self.size(); ++i) {
+    if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
+      return i;
+    }
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+                                     const StringPiece16& s,
+                                     size_t pos) {
+  if (self.size() == 0)
+    return StringPiece16::npos;
+
+  for (size_t self_i = pos; self_i < self.size(); ++self_i) {
+    bool found = false;
+    for (size_t s_i = 0; s_i < s.size(); ++s_i) {
+      if (self[self_i] == s[s_i]) {
+        found = true;
+        break;
+      }
+    }
+    if (!found)
+      return self_i;
+  }
+  return StringPiece16::npos;
+}
+
+template<typename STR>
+size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
+                          typename STR::value_type c,
+                          size_t pos) {
+  if (self.size() == 0)
+    return BasicStringPiece<STR>::npos;
+
+  for (; pos < self.size(); ++pos) {
+    if (self.data()[pos] != c) {
+      return pos;
+    }
+  }
+  return BasicStringPiece<STR>::npos;
+}
+
+size_t find_first_not_of(const StringPiece& self,
+                         char c,
+                         size_t pos) {
+  return find_first_not_ofT(self, c, pos);
+}
+
+size_t find_first_not_of(const StringPiece16& self,
+                         char16 c,
+                         size_t pos) {
+  return find_first_not_ofT(self, c, pos);
+}
+
+// 8-bit version using lookup table.
+size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
+  if (self.size() == 0 || s.size() == 0)
+    return StringPiece::npos;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return rfind(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_t i = std::min(pos, self.size() - 1); ; --i) {
+    if (lookup[static_cast<unsigned char>(self.data()[i])])
+      return i;
+    if (i == 0)
+      break;
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+size_t find_last_of(const StringPiece16& self,
+                    const StringPiece16& s,
+                    size_t pos) {
+  if (self.size() == 0)
+    return StringPiece16::npos;
+
+  for (size_t self_i = std::min(pos, self.size() - 1); ;
+       --self_i) {
+    for (size_t s_i = 0; s_i < s.size(); s_i++) {
+      if (self.data()[self_i] == s[s_i])
+        return self_i;
+    }
+    if (self_i == 0)
+      break;
+  }
+  return StringPiece16::npos;
+}
+
+// 8-bit version using lookup table.
+size_t find_last_not_of(const StringPiece& self,
+                        const StringPiece& s,
+                        size_t pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  size_t i = std::min(pos, self.size() - 1);
+  if (s.size() == 0)
+    return i;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return find_last_not_of(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (; ; --i) {
+    if (!lookup[static_cast<unsigned char>(self.data()[i])])
+      return i;
+    if (i == 0)
+      break;
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+size_t find_last_not_of(const StringPiece16& self,
+                        const StringPiece16& s,
+                        size_t pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  for (size_t self_i = std::min(pos, self.size() - 1); ; --self_i) {
+    bool found = false;
+    for (size_t s_i = 0; s_i < s.size(); s_i++) {
+      if (self.data()[self_i] == s[s_i]) {
+        found = true;
+        break;
+      }
+    }
+    if (!found)
+      return self_i;
+    if (self_i == 0)
+      break;
+  }
+  return StringPiece16::npos;
+}
+
+template<typename STR>
+size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
+                         typename STR::value_type c,
+                         size_t pos) {
+  if (self.size() == 0)
+    return BasicStringPiece<STR>::npos;
+
+  for (size_t i = std::min(pos, self.size() - 1); ; --i) {
+    if (self.data()[i] != c)
+      return i;
+    if (i == 0)
+      break;
+  }
+  return BasicStringPiece<STR>::npos;
+}
+
+size_t find_last_not_of(const StringPiece& self,
+                        char c,
+                        size_t pos) {
+  return find_last_not_ofT(self, c, pos);
+}
+
+size_t find_last_not_of(const StringPiece16& self,
+                        char16 c,
+                        size_t pos) {
+  return find_last_not_ofT(self, c, pos);
+}
+
+template<typename STR>
+BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
+                              size_t pos,
+                              size_t n) {
+  if (pos > self.size()) pos = self.size();
+  if (n > self.size() - pos) n = self.size() - pos;
+  return BasicStringPiece<STR>(self.data() + pos, n);
+}
+
+StringPiece substr(const StringPiece& self,
+                   size_t pos,
+                   size_t n) {
+  return substrT(self, pos, n);
+}
+
+StringPiece16 substr(const StringPiece16& self,
+                     size_t pos,
+                     size_t n) {
+  return substrT(self, pos, n);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
new file mode 100644
index 0000000..349018b
--- /dev/null
+++ b/base/strings/string_piece.h
@@ -0,0 +1,458 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Copied from strings/stringpiece.h with modifications
+//
+// A string-like object that points to a sized piece of memory.
+//
+// You can use StringPiece as a function or method parameter.  A StringPiece
+// parameter can receive a double-quoted string literal argument, a "const
+// char*" argument, a string argument, or a StringPiece argument with no data
+// copying.  Systematic use of StringPiece for arguments reduces data
+// copies and strlen() calls.
+//
+// Prefer passing StringPieces by value:
+//   void MyFunction(StringPiece arg);
+// If circumstances require, you may also pass by const reference:
+//   void MyFunction(const StringPiece& arg);  // not preferred
+// Both of these have the same lifetime semantics.  Passing by value
+// generates slightly smaller code.  For more discussion, Googlers can see
+// the thread go/stringpiecebyvalue on c-users.
+//
+// StringPiece16 is similar to StringPiece but for base::string16 instead of
+// std::string. We do not define as large of a subset of the STL functions
+// from basic_string as in StringPiece, but this can be changed if these
+// functions (find, find_first_of, etc.) are found to be useful in this context.
+//
+
+#ifndef BASE_STRINGS_STRING_PIECE_H_
+#define BASE_STRINGS_STRING_PIECE_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+template <typename STRING_TYPE> class BasicStringPiece;
+typedef BasicStringPiece<std::string> StringPiece;
+typedef BasicStringPiece<string16> StringPiece16;
+
+// internal --------------------------------------------------------------------
+
+// Many of the StringPiece functions use different implementations for the
+// 8-bit and 16-bit versions, and we don't want lots of template expansions in
+// this (very common) header that will slow down compilation.
+//
+// So here we define overloaded functions called by the StringPiece template.
+// For those that share an implementation, the two versions will expand to a
+// template internal to the .cc file.
+namespace internal {
+
+BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
+BASE_EXPORT void CopyToString(const StringPiece16& self, string16* target);
+
+BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
+BASE_EXPORT void AppendToString(const StringPiece16& self, string16* target);
+
+BASE_EXPORT size_t copy(const StringPiece& self,
+                        char* buf,
+                        size_t n,
+                        size_t pos);
+BASE_EXPORT size_t copy(const StringPiece16& self,
+                        char16* buf,
+                        size_t n,
+                        size_t pos);
+
+BASE_EXPORT size_t find(const StringPiece& self,
+                        const StringPiece& s,
+                        size_t pos);
+BASE_EXPORT size_t find(const StringPiece16& self,
+                        const StringPiece16& s,
+                        size_t pos);
+BASE_EXPORT size_t find(const StringPiece& self,
+                        char c,
+                        size_t pos);
+BASE_EXPORT size_t find(const StringPiece16& self,
+                        char16 c,
+                        size_t pos);
+
+BASE_EXPORT size_t rfind(const StringPiece& self,
+                         const StringPiece& s,
+                         size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece16& self,
+                         const StringPiece16& s,
+                         size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece& self,
+                         char c,
+                         size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece16& self,
+                         char16 c,
+                         size_t pos);
+
+BASE_EXPORT size_t find_first_of(const StringPiece& self,
+                                 const StringPiece& s,
+                                 size_t pos);
+BASE_EXPORT size_t find_first_of(const StringPiece16& self,
+                                 const StringPiece16& s,
+                                 size_t pos);
+
+BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
+                                     const StringPiece& s,
+                                     size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+                                     const StringPiece16& s,
+                                     size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
+                                     char c,
+                                     size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+                                     char16 c,
+                                     size_t pos);
+
+BASE_EXPORT size_t find_last_of(const StringPiece& self,
+                                const StringPiece& s,
+                                size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece16& self,
+                                const StringPiece16& s,
+                                size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece& self,
+                                char c,
+                                size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece16& self,
+                                char16 c,
+                                size_t pos);
+
+BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
+                                    const StringPiece& s,
+                                    size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
+                                    const StringPiece16& s,
+                                    size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
+                                    char16 c,
+                                    size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
+                                    char c,
+                                    size_t pos);
+
+BASE_EXPORT StringPiece substr(const StringPiece& self,
+                               size_t pos,
+                               size_t n);
+BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
+                                 size_t pos,
+                                 size_t n);
+
+}  // namespace internal
+
+// BasicStringPiece ------------------------------------------------------------
+
+// Defines the types, methods, operators, and data members common to both
+// StringPiece and StringPiece16. Do not refer to this class directly, but
+// rather to BasicStringPiece, StringPiece, or StringPiece16.
+//
+// This is templatized by string class type rather than character type, so
+// BasicStringPiece<std::string> or BasicStringPiece<base::string16>.
+template <typename STRING_TYPE> class BasicStringPiece {
+ public:
+  // Standard STL container boilerplate.
+  typedef size_t size_type;
+  typedef typename STRING_TYPE::value_type value_type;
+  typedef const value_type* pointer;
+  typedef const value_type& reference;
+  typedef const value_type& const_reference;
+  typedef ptrdiff_t difference_type;
+  typedef const value_type* const_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  static const size_type npos;
+
+ public:
+  // We provide non-explicit singleton constructors so users can pass
+  // in a "const char*" or a "string" wherever a "StringPiece" is
+  // expected (likewise for char16, string16, StringPiece16).
+  BasicStringPiece() : ptr_(NULL), length_(0) {}
+  BasicStringPiece(const value_type* str)
+      : ptr_(str),
+        length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
+  BasicStringPiece(const STRING_TYPE& str)
+      : ptr_(str.data()), length_(str.size()) {}
+  BasicStringPiece(const value_type* offset, size_type len)
+      : ptr_(offset), length_(len) {}
+  BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
+                    const typename STRING_TYPE::const_iterator& end)
+      : ptr_((end > begin) ? &(*begin) : NULL),
+        length_((end > begin) ? (size_type)(end - begin) : 0) {}
+
+  // data() may return a pointer to a buffer with embedded NULs, and the
+  // returned buffer may or may not be null terminated.  Therefore it is
+  // typically a mistake to pass data() to a routine that expects a NUL
+  // terminated string.
+  const value_type* data() const { return ptr_; }
+  size_type size() const { return length_; }
+  size_type length() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  void clear() {
+    ptr_ = NULL;
+    length_ = 0;
+  }
+  void set(const value_type* data, size_type len) {
+    ptr_ = data;
+    length_ = len;
+  }
+  void set(const value_type* str) {
+    ptr_ = str;
+    length_ = str ? STRING_TYPE::traits_type::length(str) : 0;
+  }
+
+  value_type operator[](size_type i) const { return ptr_[i]; }
+
+  void remove_prefix(size_type n) {
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  void remove_suffix(size_type n) {
+    length_ -= n;
+  }
+
+  int compare(const BasicStringPiece<STRING_TYPE>& x) const {
+    int r = wordmemcmp(
+        ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
+    if (r == 0) {
+      if (length_ < x.length_) r = -1;
+      else if (length_ > x.length_) r = +1;
+    }
+    return r;
+  }
+
+  STRING_TYPE as_string() const {
+    // std::string doesn't like to take a NULL pointer even with a 0 size.
+    return empty() ? STRING_TYPE() : STRING_TYPE(data(), size());
+  }
+
+  const_iterator begin() const { return ptr_; }
+  const_iterator end() const { return ptr_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(ptr_ + length_);
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(ptr_);
+  }
+
+  size_type max_size() const { return length_; }
+  size_type capacity() const { return length_; }
+
+  static int wordmemcmp(const value_type* p,
+                        const value_type* p2,
+                        size_type N) {
+    return STRING_TYPE::traits_type::compare(p, p2, N);
+  }
+
+  // Sets the value of the given string target type to be the current string.
+  // This saves a temporary over doing |a = b.as_string()|
+  void CopyToString(STRING_TYPE* target) const {
+    internal::CopyToString(*this, target);
+  }
+
+  void AppendToString(STRING_TYPE* target) const {
+    internal::AppendToString(*this, target);
+  }
+
+  size_type copy(value_type* buf, size_type n, size_type pos = 0) const {
+    return internal::copy(*this, buf, n, pos);
+  }
+
+  // Does "this" start with "x"
+  bool starts_with(const BasicStringPiece& x) const {
+    return ((this->length_ >= x.length_) &&
+            (wordmemcmp(this->ptr_, x.ptr_, x.length_) == 0));
+  }
+
+  // Does "this" end with "x"
+  bool ends_with(const BasicStringPiece& x) const {
+    return ((this->length_ >= x.length_) &&
+            (wordmemcmp(this->ptr_ + (this->length_-x.length_),
+                        x.ptr_, x.length_) == 0));
+  }
+
+  // find: Search for a character or substring at a given offset.
+  size_type find(const BasicStringPiece<STRING_TYPE>& s,
+                 size_type pos = 0) const {
+    return internal::find(*this, s, pos);
+  }
+  size_type find(value_type c, size_type pos = 0) const {
+    return internal::find(*this, c, pos);
+  }
+
+  // rfind: Reverse find.
+  size_type rfind(const BasicStringPiece& s,
+                  size_type pos = BasicStringPiece::npos) const {
+    return internal::rfind(*this, s, pos);
+  }
+  size_type rfind(value_type c, size_type pos = BasicStringPiece::npos) const {
+    return internal::rfind(*this, c, pos);
+  }
+
+  // find_first_of: Find the first occurence of one of a set of characters.
+  size_type find_first_of(const BasicStringPiece& s,
+                          size_type pos = 0) const {
+    return internal::find_first_of(*this, s, pos);
+  }
+  size_type find_first_of(value_type c, size_type pos = 0) const {
+    return find(c, pos);
+  }
+
+  // find_first_not_of: Find the first occurence not of a set of characters.
+  size_type find_first_not_of(const BasicStringPiece& s,
+                              size_type pos = 0) const {
+    return internal::find_first_not_of(*this, s, pos);
+  }
+  size_type find_first_not_of(value_type c, size_type pos = 0) const {
+    return internal::find_first_not_of(*this, c, pos);
+  }
+
+  // find_last_of: Find the last occurence of one of a set of characters.
+  size_type find_last_of(const BasicStringPiece& s,
+                         size_type pos = BasicStringPiece::npos) const {
+    return internal::find_last_of(*this, s, pos);
+  }
+  size_type find_last_of(value_type c,
+                         size_type pos = BasicStringPiece::npos) const {
+    return rfind(c, pos);
+  }
+
+  // find_last_not_of: Find the last occurence not of a set of characters.
+  size_type find_last_not_of(const BasicStringPiece& s,
+                             size_type pos = BasicStringPiece::npos) const {
+    return internal::find_last_not_of(*this, s, pos);
+  }
+  size_type find_last_not_of(value_type c,
+                             size_type pos = BasicStringPiece::npos) const {
+    return internal::find_last_not_of(*this, c, pos);
+  }
+
+  // substr.
+  BasicStringPiece substr(size_type pos,
+                          size_type n = BasicStringPiece::npos) const {
+    return internal::substr(*this, pos, n);
+  }
+
+ protected:
+  const value_type* ptr_;
+  size_type     length_;
+};
+
+template <typename STRING_TYPE>
+const typename BasicStringPiece<STRING_TYPE>::size_type
+BasicStringPiece<STRING_TYPE>::npos =
+    typename BasicStringPiece<STRING_TYPE>::size_type(-1);
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+extern template class BASE_EXPORT BasicStringPiece<std::string>;
+extern template class BASE_EXPORT BasicStringPiece<string16>;
+#endif
+
+// StingPiece operators --------------------------------------------------------
+
+BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y);
+
+inline bool operator!=(const StringPiece& x, const StringPiece& y) {
+  return !(x == y);
+}
+
+inline bool operator<(const StringPiece& x, const StringPiece& y) {
+  const int r = StringPiece::wordmemcmp(
+      x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece& x, const StringPiece& y) {
+  return y < x;
+}
+
+inline bool operator<=(const StringPiece& x, const StringPiece& y) {
+  return !(x > y);
+}
+
+inline bool operator>=(const StringPiece& x, const StringPiece& y) {
+  return !(x < y);
+}
+
+// StringPiece16 operators -----------------------------------------------------
+
+inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
+  if (x.size() != y.size())
+    return false;
+
+  return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+inline bool operator!=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x == y);
+}
+
+inline bool operator<(const StringPiece16& x, const StringPiece16& y) {
+  const int r = StringPiece16::wordmemcmp(
+      x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece16& x, const StringPiece16& y) {
+  return y < x;
+}
+
+inline bool operator<=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x > y);
+}
+
+inline bool operator>=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x < y);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& o,
+                                     const StringPiece& piece);
+
+}  // namespace base
+
+// Hashing ---------------------------------------------------------------------
+
+// We provide appropriate hash functions so StringPiece and StringPiece16 can
+// be used as keys in hash sets and maps.
+
+// This hash function is copied from base/containers/hash_tables.h. We don't
+// use the ones already defined for string and string16 directly because it
+// would require the string constructors to be called, which we don't want.
+#define HASH_STRING_PIECE(StringPieceType, string_piece)                \
+  std::size_t result = 0;                                               \
+  for (StringPieceType::const_iterator i = string_piece.begin();        \
+       i != string_piece.end(); ++i)                                    \
+    result = (result * 131) + *i;                                       \
+  return result;                                                        \
+
+namespace BASE_HASH_NAMESPACE {
+
+template<>
+struct hash<base::StringPiece> {
+  std::size_t operator()(const base::StringPiece& sp) const {
+    HASH_STRING_PIECE(base::StringPiece, sp);
+  }
+};
+template<>
+struct hash<base::StringPiece16> {
+  std::size_t operator()(const base::StringPiece16& sp16) const {
+    HASH_STRING_PIECE(base::StringPiece16, sp16);
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_STRINGS_STRING_PIECE_H_
diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc
new file mode 100644
index 0000000..5336603
--- /dev/null
+++ b/base/strings/string_piece_unittest.cc
@@ -0,0 +1,689 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+template <typename T>
+class CommonStringPieceTest : public ::testing::Test {
+ public:
+  static const T as_string(const char* input) {
+    return T(input);
+  }
+  static const T& as_string(const T& input) {
+    return input;
+  }
+};
+
+template <>
+class CommonStringPieceTest<string16> : public ::testing::Test {
+ public:
+  static const string16 as_string(const char* input) {
+    return ASCIIToUTF16(input);
+  }
+  static const string16 as_string(const std::string& input) {
+    return ASCIIToUTF16(input);
+  }
+};
+
+typedef ::testing::Types<std::string, string16> SupportedStringTypes;
+
+TYPED_TEST_CASE(CommonStringPieceTest, SupportedStringTypes);
+
+TYPED_TEST(CommonStringPieceTest, CheckComparisonOperators) {
+#define CMP_Y(op, x, y)                                                    \
+  {                                                                        \
+    TypeParam lhs(TestFixture::as_string(x));                              \
+    TypeParam rhs(TestFixture::as_string(y));                              \
+    ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())) op            \
+                  BasicStringPiece<TypeParam>((rhs.c_str()))));            \
+    ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare(      \
+                      BasicStringPiece<TypeParam>((rhs.c_str()))) op 0));  \
+  }
+
+#define CMP_N(op, x, y)                                                    \
+  {                                                                        \
+    TypeParam lhs(TestFixture::as_string(x));                              \
+    TypeParam rhs(TestFixture::as_string(y));                              \
+    ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())) op           \
+                  BasicStringPiece<TypeParam>((rhs.c_str()))));            \
+    ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare(     \
+                      BasicStringPiece<TypeParam>((rhs.c_str()))) op 0));  \
+  }
+
+  CMP_Y(==, "",   "");
+  CMP_Y(==, "a",  "a");
+  CMP_Y(==, "aa", "aa");
+  CMP_N(==, "a",  "");
+  CMP_N(==, "",   "a");
+  CMP_N(==, "a",  "b");
+  CMP_N(==, "a",  "aa");
+  CMP_N(==, "aa", "a");
+
+  CMP_N(!=, "",   "");
+  CMP_N(!=, "a",  "a");
+  CMP_N(!=, "aa", "aa");
+  CMP_Y(!=, "a",  "");
+  CMP_Y(!=, "",   "a");
+  CMP_Y(!=, "a",  "b");
+  CMP_Y(!=, "a",  "aa");
+  CMP_Y(!=, "aa", "a");
+
+  CMP_Y(<, "a",  "b");
+  CMP_Y(<, "a",  "aa");
+  CMP_Y(<, "aa", "b");
+  CMP_Y(<, "aa", "bb");
+  CMP_N(<, "a",  "a");
+  CMP_N(<, "b",  "a");
+  CMP_N(<, "aa", "a");
+  CMP_N(<, "b",  "aa");
+  CMP_N(<, "bb", "aa");
+
+  CMP_Y(<=, "a",  "a");
+  CMP_Y(<=, "a",  "b");
+  CMP_Y(<=, "a",  "aa");
+  CMP_Y(<=, "aa", "b");
+  CMP_Y(<=, "aa", "bb");
+  CMP_N(<=, "b",  "a");
+  CMP_N(<=, "aa", "a");
+  CMP_N(<=, "b",  "aa");
+  CMP_N(<=, "bb", "aa");
+
+  CMP_N(>=, "a",  "b");
+  CMP_N(>=, "a",  "aa");
+  CMP_N(>=, "aa", "b");
+  CMP_N(>=, "aa", "bb");
+  CMP_Y(>=, "a",  "a");
+  CMP_Y(>=, "b",  "a");
+  CMP_Y(>=, "aa", "a");
+  CMP_Y(>=, "b",  "aa");
+  CMP_Y(>=, "bb", "aa");
+
+  CMP_N(>, "a",  "a");
+  CMP_N(>, "a",  "b");
+  CMP_N(>, "a",  "aa");
+  CMP_N(>, "aa", "b");
+  CMP_N(>, "aa", "bb");
+  CMP_Y(>, "b",  "a");
+  CMP_Y(>, "aa", "a");
+  CMP_Y(>, "b",  "aa");
+  CMP_Y(>, "bb", "aa");
+
+  std::string x;
+  for (int i = 0; i < 256; i++) {
+    x += 'a';
+    std::string y = x;
+    CMP_Y(==, x, y);
+    for (int j = 0; j < i; j++) {
+      std::string z = x;
+      z[j] = 'b';       // Differs in position 'j'
+      CMP_N(==, x, z);
+    }
+  }
+
+#undef CMP_Y
+#undef CMP_N
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckSTL) {
+  TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz"));
+  TypeParam abc(TestFixture::as_string("abc"));
+  TypeParam xyz(TestFixture::as_string("xyz"));
+  TypeParam foobar(TestFixture::as_string("foobar"));
+
+  BasicStringPiece<TypeParam> a(alphabet);
+  BasicStringPiece<TypeParam> b(abc);
+  BasicStringPiece<TypeParam> c(xyz);
+  BasicStringPiece<TypeParam> d(foobar);
+  BasicStringPiece<TypeParam> e;
+  TypeParam temp(TestFixture::as_string("123"));
+  temp += static_cast<typename TypeParam::value_type>(0);
+  temp += TestFixture::as_string("456");
+  BasicStringPiece<TypeParam> f(temp);
+
+  ASSERT_EQ(a[6], static_cast<typename TypeParam::value_type>('g'));
+  ASSERT_EQ(b[0], static_cast<typename TypeParam::value_type>('a'));
+  ASSERT_EQ(c[2], static_cast<typename TypeParam::value_type>('z'));
+  ASSERT_EQ(f[3], static_cast<typename TypeParam::value_type>('\0'));
+  ASSERT_EQ(f[5], static_cast<typename TypeParam::value_type>('5'));
+
+  ASSERT_EQ(*d.data(), static_cast<typename TypeParam::value_type>('f'));
+  ASSERT_EQ(d.data()[5], static_cast<typename TypeParam::value_type>('r'));
+  ASSERT_TRUE(e.data() == NULL);
+
+  ASSERT_EQ(*a.begin(), static_cast<typename TypeParam::value_type>('a'));
+  ASSERT_EQ(*(b.begin() + 2), static_cast<typename TypeParam::value_type>('c'));
+  ASSERT_EQ(*(c.end() - 1), static_cast<typename TypeParam::value_type>('z'));
+
+  ASSERT_EQ(*a.rbegin(), static_cast<typename TypeParam::value_type>('z'));
+  ASSERT_EQ(*(b.rbegin() + 2),
+            static_cast<typename TypeParam::value_type>('a'));
+  ASSERT_EQ(*(c.rend() - 1), static_cast<typename TypeParam::value_type>('x'));
+  ASSERT_TRUE(a.rbegin() + 26 == a.rend());
+
+  ASSERT_EQ(a.size(), 26U);
+  ASSERT_EQ(b.size(), 3U);
+  ASSERT_EQ(c.size(), 3U);
+  ASSERT_EQ(d.size(), 6U);
+  ASSERT_EQ(e.size(), 0U);
+  ASSERT_EQ(f.size(), 7U);
+
+  ASSERT_TRUE(!d.empty());
+  ASSERT_TRUE(d.begin() != d.end());
+  ASSERT_TRUE(d.begin() + 6 == d.end());
+
+  ASSERT_TRUE(e.empty());
+  ASSERT_TRUE(e.begin() == e.end());
+
+  d.clear();
+  ASSERT_EQ(d.size(), 0U);
+  ASSERT_TRUE(d.empty());
+  ASSERT_TRUE(d.data() == NULL);
+  ASSERT_TRUE(d.begin() == d.end());
+
+  ASSERT_GE(a.max_size(), a.capacity());
+  ASSERT_GE(a.capacity(), a.size());
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckFind) {
+  typedef BasicStringPiece<TypeParam> Piece;
+
+  TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz"));
+  TypeParam abc(TestFixture::as_string("abc"));
+  TypeParam xyz(TestFixture::as_string("xyz"));
+  TypeParam foobar(TestFixture::as_string("foobar"));
+
+  BasicStringPiece<TypeParam> a(alphabet);
+  BasicStringPiece<TypeParam> b(abc);
+  BasicStringPiece<TypeParam> c(xyz);
+  BasicStringPiece<TypeParam> d(foobar);
+
+  d.clear();
+  Piece e;
+  TypeParam temp(TestFixture::as_string("123"));
+  temp.push_back('\0');
+  temp += TestFixture::as_string("456");
+  Piece f(temp);
+
+  typename TypeParam::value_type buf[4] = { '%', '%', '%', '%' };
+  ASSERT_EQ(a.copy(buf, 4), 4U);
+  ASSERT_EQ(buf[0], a[0]);
+  ASSERT_EQ(buf[1], a[1]);
+  ASSERT_EQ(buf[2], a[2]);
+  ASSERT_EQ(buf[3], a[3]);
+  ASSERT_EQ(a.copy(buf, 3, 7), 3U);
+  ASSERT_EQ(buf[0], a[7]);
+  ASSERT_EQ(buf[1], a[8]);
+  ASSERT_EQ(buf[2], a[9]);
+  ASSERT_EQ(buf[3], a[3]);
+  ASSERT_EQ(c.copy(buf, 99), 3U);
+  ASSERT_EQ(buf[0], c[0]);
+  ASSERT_EQ(buf[1], c[1]);
+  ASSERT_EQ(buf[2], c[2]);
+  ASSERT_EQ(buf[3], a[3]);
+
+  ASSERT_EQ(Piece::npos, TypeParam::npos);
+
+  ASSERT_EQ(a.find(b), 0U);
+  ASSERT_EQ(a.find(b, 1), Piece::npos);
+  ASSERT_EQ(a.find(c), 23U);
+  ASSERT_EQ(a.find(c, 9), 23U);
+  ASSERT_EQ(a.find(c, Piece::npos), Piece::npos);
+  ASSERT_EQ(b.find(c), Piece::npos);
+  ASSERT_EQ(b.find(c, Piece::npos), Piece::npos);
+  ASSERT_EQ(a.find(d), 0U);
+  ASSERT_EQ(a.find(e), 0U);
+  ASSERT_EQ(a.find(d, 12), 12U);
+  ASSERT_EQ(a.find(e, 17), 17U);
+  TypeParam not_found(TestFixture::as_string("xx not found bb"));
+  Piece g(not_found);
+  ASSERT_EQ(a.find(g), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.find(b), Piece::npos);
+  ASSERT_EQ(e.find(b), Piece::npos);
+  ASSERT_EQ(d.find(b, 4), Piece::npos);
+  ASSERT_EQ(e.find(b, 7), Piece::npos);
+
+  size_t empty_search_pos = TypeParam().find(TypeParam());
+  ASSERT_EQ(d.find(d), empty_search_pos);
+  ASSERT_EQ(d.find(e), empty_search_pos);
+  ASSERT_EQ(e.find(d), empty_search_pos);
+  ASSERT_EQ(e.find(e), empty_search_pos);
+  ASSERT_EQ(d.find(d, 4), std::string().find(std::string(), 4));
+  ASSERT_EQ(d.find(e, 4), std::string().find(std::string(), 4));
+  ASSERT_EQ(e.find(d, 4), std::string().find(std::string(), 4));
+  ASSERT_EQ(e.find(e, 4), std::string().find(std::string(), 4));
+
+  ASSERT_EQ(a.find('a'), 0U);
+  ASSERT_EQ(a.find('c'), 2U);
+  ASSERT_EQ(a.find('z'), 25U);
+  ASSERT_EQ(a.find('$'), Piece::npos);
+  ASSERT_EQ(a.find('\0'), Piece::npos);
+  ASSERT_EQ(f.find('\0'), 3U);
+  ASSERT_EQ(f.find('3'), 2U);
+  ASSERT_EQ(f.find('5'), 5U);
+  ASSERT_EQ(g.find('o'), 4U);
+  ASSERT_EQ(g.find('o', 4), 4U);
+  ASSERT_EQ(g.find('o', 5), 8U);
+  ASSERT_EQ(a.find('b', 5), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.find('\0'), Piece::npos);
+  ASSERT_EQ(e.find('\0'), Piece::npos);
+  ASSERT_EQ(d.find('\0', 4), Piece::npos);
+  ASSERT_EQ(e.find('\0', 7), Piece::npos);
+  ASSERT_EQ(d.find('x'), Piece::npos);
+  ASSERT_EQ(e.find('x'), Piece::npos);
+  ASSERT_EQ(d.find('x', 4), Piece::npos);
+  ASSERT_EQ(e.find('x', 7), Piece::npos);
+
+  ASSERT_EQ(a.rfind(b), 0U);
+  ASSERT_EQ(a.rfind(b, 1), 0U);
+  ASSERT_EQ(a.rfind(c), 23U);
+  ASSERT_EQ(a.rfind(c, 22U), Piece::npos);
+  ASSERT_EQ(a.rfind(c, 1U), Piece::npos);
+  ASSERT_EQ(a.rfind(c, 0U), Piece::npos);
+  ASSERT_EQ(b.rfind(c), Piece::npos);
+  ASSERT_EQ(b.rfind(c, 0U), Piece::npos);
+  ASSERT_EQ(a.rfind(d), static_cast<size_t>(a.as_string().rfind(TypeParam())));
+  ASSERT_EQ(a.rfind(e), a.as_string().rfind(TypeParam()));
+  ASSERT_EQ(a.rfind(d, 12), 12U);
+  ASSERT_EQ(a.rfind(e, 17), 17U);
+  ASSERT_EQ(a.rfind(g), Piece::npos);
+  ASSERT_EQ(d.rfind(b), Piece::npos);
+  ASSERT_EQ(e.rfind(b), Piece::npos);
+  ASSERT_EQ(d.rfind(b, 4), Piece::npos);
+  ASSERT_EQ(e.rfind(b, 7), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.rfind(d, 4), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(d, 7), std::string().rfind(std::string()));
+  ASSERT_EQ(d.rfind(e, 4), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
+  ASSERT_EQ(d.rfind(d), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(d), std::string().rfind(std::string()));
+  ASSERT_EQ(d.rfind(e), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(e), std::string().rfind(std::string()));
+
+  ASSERT_EQ(g.rfind('o'), 8U);
+  ASSERT_EQ(g.rfind('q'), Piece::npos);
+  ASSERT_EQ(g.rfind('o', 8), 8U);
+  ASSERT_EQ(g.rfind('o', 7), 4U);
+  ASSERT_EQ(g.rfind('o', 3), Piece::npos);
+  ASSERT_EQ(f.rfind('\0'), 3U);
+  ASSERT_EQ(f.rfind('\0', 12), 3U);
+  ASSERT_EQ(f.rfind('3'), 2U);
+  ASSERT_EQ(f.rfind('5'), 5U);
+  // empty string nonsense
+  ASSERT_EQ(d.rfind('o'), Piece::npos);
+  ASSERT_EQ(e.rfind('o'), Piece::npos);
+  ASSERT_EQ(d.rfind('o', 4), Piece::npos);
+  ASSERT_EQ(e.rfind('o', 7), Piece::npos);
+
+  TypeParam one_two_three_four(TestFixture::as_string("one,two:three;four"));
+  TypeParam comma_colon(TestFixture::as_string(",:"));
+  ASSERT_EQ(3U, Piece(one_two_three_four).find_first_of(comma_colon));
+  ASSERT_EQ(a.find_first_of(b), 0U);
+  ASSERT_EQ(a.find_first_of(b, 0), 0U);
+  ASSERT_EQ(a.find_first_of(b, 1), 1U);
+  ASSERT_EQ(a.find_first_of(b, 2), 2U);
+  ASSERT_EQ(a.find_first_of(b, 3), Piece::npos);
+  ASSERT_EQ(a.find_first_of(c), 23U);
+  ASSERT_EQ(a.find_first_of(c, 23), 23U);
+  ASSERT_EQ(a.find_first_of(c, 24), 24U);
+  ASSERT_EQ(a.find_first_of(c, 25), 25U);
+  ASSERT_EQ(a.find_first_of(c, 26), Piece::npos);
+  ASSERT_EQ(g.find_first_of(b), 13U);
+  ASSERT_EQ(g.find_first_of(c), 0U);
+  ASSERT_EQ(a.find_first_of(f), Piece::npos);
+  ASSERT_EQ(f.find_first_of(a), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(a.find_first_of(d), Piece::npos);
+  ASSERT_EQ(a.find_first_of(e), Piece::npos);
+  ASSERT_EQ(d.find_first_of(b), Piece::npos);
+  ASSERT_EQ(e.find_first_of(b), Piece::npos);
+  ASSERT_EQ(d.find_first_of(d), Piece::npos);
+  ASSERT_EQ(e.find_first_of(d), Piece::npos);
+  ASSERT_EQ(d.find_first_of(e), Piece::npos);
+  ASSERT_EQ(e.find_first_of(e), Piece::npos);
+
+  ASSERT_EQ(a.find_first_not_of(b), 3U);
+  ASSERT_EQ(a.find_first_not_of(c), 0U);
+  ASSERT_EQ(b.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(c.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(f.find_first_not_of(a), 0U);
+  ASSERT_EQ(a.find_first_not_of(f), 0U);
+  ASSERT_EQ(a.find_first_not_of(d), 0U);
+  ASSERT_EQ(a.find_first_not_of(e), 0U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(d.find_first_not_of(d), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of(d), Piece::npos);
+  ASSERT_EQ(d.find_first_not_of(e), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of(e), Piece::npos);
+
+  TypeParam equals(TestFixture::as_string("===="));
+  Piece h(equals);
+  ASSERT_EQ(h.find_first_not_of('='), Piece::npos);
+  ASSERT_EQ(h.find_first_not_of('=', 3), Piece::npos);
+  ASSERT_EQ(h.find_first_not_of('\0'), 0U);
+  ASSERT_EQ(g.find_first_not_of('x'), 2U);
+  ASSERT_EQ(f.find_first_not_of('\0'), 0U);
+  ASSERT_EQ(f.find_first_not_of('\0', 3), 4U);
+  ASSERT_EQ(f.find_first_not_of('\0', 2), 2U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_first_not_of('x'), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of('x'), Piece::npos);
+  ASSERT_EQ(d.find_first_not_of('\0'), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of('\0'), Piece::npos);
+
+  //  Piece g("xx not found bb");
+  TypeParam fifty_six(TestFixture::as_string("56"));
+  Piece i(fifty_six);
+  ASSERT_EQ(h.find_last_of(a), Piece::npos);
+  ASSERT_EQ(g.find_last_of(a), g.size()-1);
+  ASSERT_EQ(a.find_last_of(b), 2U);
+  ASSERT_EQ(a.find_last_of(c), a.size()-1);
+  ASSERT_EQ(f.find_last_of(i), 6U);
+  ASSERT_EQ(a.find_last_of('a'), 0U);
+  ASSERT_EQ(a.find_last_of('b'), 1U);
+  ASSERT_EQ(a.find_last_of('z'), 25U);
+  ASSERT_EQ(a.find_last_of('a', 5), 0U);
+  ASSERT_EQ(a.find_last_of('b', 5), 1U);
+  ASSERT_EQ(a.find_last_of('b', 0), Piece::npos);
+  ASSERT_EQ(a.find_last_of('z', 25), 25U);
+  ASSERT_EQ(a.find_last_of('z', 24), Piece::npos);
+  ASSERT_EQ(f.find_last_of(i, 5), 5U);
+  ASSERT_EQ(f.find_last_of(i, 6), 6U);
+  ASSERT_EQ(f.find_last_of(a, 4), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(f.find_last_of(d), Piece::npos);
+  ASSERT_EQ(f.find_last_of(e), Piece::npos);
+  ASSERT_EQ(f.find_last_of(d, 4), Piece::npos);
+  ASSERT_EQ(f.find_last_of(e, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_of(d), Piece::npos);
+  ASSERT_EQ(d.find_last_of(e), Piece::npos);
+  ASSERT_EQ(e.find_last_of(d), Piece::npos);
+  ASSERT_EQ(e.find_last_of(e), Piece::npos);
+  ASSERT_EQ(d.find_last_of(f), Piece::npos);
+  ASSERT_EQ(e.find_last_of(f), Piece::npos);
+  ASSERT_EQ(d.find_last_of(d, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_of(e, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_of(d, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_of(e, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_of(f, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_of(f, 4), Piece::npos);
+
+  ASSERT_EQ(a.find_last_not_of(b), a.size()-1);
+  ASSERT_EQ(a.find_last_not_of(c), 22U);
+  ASSERT_EQ(b.find_last_not_of(a), Piece::npos);
+  ASSERT_EQ(b.find_last_not_of(b), Piece::npos);
+  ASSERT_EQ(f.find_last_not_of(i), 4U);
+  ASSERT_EQ(a.find_last_not_of(c, 24), 22U);
+  ASSERT_EQ(a.find_last_not_of(b, 3), 3U);
+  ASSERT_EQ(a.find_last_not_of(b, 2), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(f.find_last_not_of(d), f.size()-1);
+  ASSERT_EQ(f.find_last_not_of(e), f.size()-1);
+  ASSERT_EQ(f.find_last_not_of(d, 4), 4U);
+  ASSERT_EQ(f.find_last_not_of(e, 4), 4U);
+  ASSERT_EQ(d.find_last_not_of(d), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(e), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(d), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(e), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(f), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(f), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(d, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(e, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(d, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(e, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(f, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(f, 4), Piece::npos);
+
+  ASSERT_EQ(h.find_last_not_of('x'), h.size() - 1);
+  ASSERT_EQ(h.find_last_not_of('='), Piece::npos);
+  ASSERT_EQ(b.find_last_not_of('c'), 1U);
+  ASSERT_EQ(h.find_last_not_of('x', 2), 2U);
+  ASSERT_EQ(h.find_last_not_of('=', 2), Piece::npos);
+  ASSERT_EQ(b.find_last_not_of('b', 1), 0U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_last_not_of('x'), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of('x'), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of('\0'), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of('\0'), Piece::npos);
+
+  ASSERT_EQ(a.substr(0, 3), b);
+  ASSERT_EQ(a.substr(23), c);
+  ASSERT_EQ(a.substr(23, 3), c);
+  ASSERT_EQ(a.substr(23, 99), c);
+  ASSERT_EQ(a.substr(0), a);
+  ASSERT_EQ(a.substr(3, 2), TestFixture::as_string("de"));
+  // empty string nonsense
+  ASSERT_EQ(a.substr(99, 2), e);
+  ASSERT_EQ(d.substr(99), e);
+  ASSERT_EQ(d.substr(0, 99), e);
+  ASSERT_EQ(d.substr(99, 99), e);
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckCustom) {
+  TypeParam foobar(TestFixture::as_string("foobar"));
+  BasicStringPiece<TypeParam> a(foobar);
+  TypeParam s1(TestFixture::as_string("123"));
+  s1 += static_cast<typename TypeParam::value_type>('\0');
+  s1 += TestFixture::as_string("456");
+  BasicStringPiece<TypeParam> b(s1);
+  BasicStringPiece<TypeParam> e;
+  TypeParam s2;
+
+  // remove_prefix
+  BasicStringPiece<TypeParam> c(a);
+  c.remove_prefix(3);
+  ASSERT_EQ(c, TestFixture::as_string("bar"));
+  c = a;
+  c.remove_prefix(0);
+  ASSERT_EQ(c, a);
+  c.remove_prefix(c.size());
+  ASSERT_EQ(c, e);
+
+  // remove_suffix
+  c = a;
+  c.remove_suffix(3);
+  ASSERT_EQ(c, TestFixture::as_string("foo"));
+  c = a;
+  c.remove_suffix(0);
+  ASSERT_EQ(c, a);
+  c.remove_suffix(c.size());
+  ASSERT_EQ(c, e);
+
+  // set
+  c.set(foobar.c_str());
+  ASSERT_EQ(c, a);
+  c.set(foobar.c_str(), 6);
+  ASSERT_EQ(c, a);
+  c.set(foobar.c_str(), 0);
+  ASSERT_EQ(c, e);
+  c.set(foobar.c_str(), 7);  // Note, has an embedded NULL
+  ASSERT_NE(c, a);
+
+  // as_string
+  TypeParam s3(a.as_string().c_str(), 7);  // Note, has an embedded NULL
+  ASSERT_TRUE(c == s3);
+  TypeParam s4(e.as_string());
+  ASSERT_TRUE(s4.empty());
+}
+
+TEST(StringPieceTest, CheckCustom) {
+  StringPiece a("foobar");
+  std::string s1("123");
+  s1 += '\0';
+  s1 += "456";
+  StringPiece b(s1);
+  StringPiece e;
+  std::string s2;
+
+  // CopyToString
+  a.CopyToString(&s2);
+  ASSERT_EQ(s2.size(), 6U);
+  ASSERT_EQ(s2, "foobar");
+  b.CopyToString(&s2);
+  ASSERT_EQ(s2.size(), 7U);
+  ASSERT_EQ(s1, s2);
+  e.CopyToString(&s2);
+  ASSERT_TRUE(s2.empty());
+
+  // AppendToString
+  s2.erase();
+  a.AppendToString(&s2);
+  ASSERT_EQ(s2.size(), 6U);
+  ASSERT_EQ(s2, "foobar");
+  a.AppendToString(&s2);
+  ASSERT_EQ(s2.size(), 12U);
+  ASSERT_EQ(s2, "foobarfoobar");
+
+  // starts_with
+  ASSERT_TRUE(a.starts_with(a));
+  ASSERT_TRUE(a.starts_with("foo"));
+  ASSERT_TRUE(a.starts_with(e));
+  ASSERT_TRUE(b.starts_with(s1));
+  ASSERT_TRUE(b.starts_with(b));
+  ASSERT_TRUE(b.starts_with(e));
+  ASSERT_TRUE(e.starts_with(""));
+  ASSERT_TRUE(!a.starts_with(b));
+  ASSERT_TRUE(!b.starts_with(a));
+  ASSERT_TRUE(!e.starts_with(a));
+
+  // ends with
+  ASSERT_TRUE(a.ends_with(a));
+  ASSERT_TRUE(a.ends_with("bar"));
+  ASSERT_TRUE(a.ends_with(e));
+  ASSERT_TRUE(b.ends_with(s1));
+  ASSERT_TRUE(b.ends_with(b));
+  ASSERT_TRUE(b.ends_with(e));
+  ASSERT_TRUE(e.ends_with(""));
+  ASSERT_TRUE(!a.ends_with(b));
+  ASSERT_TRUE(!b.ends_with(a));
+  ASSERT_TRUE(!e.ends_with(a));
+
+  StringPiece c;
+  c.set("foobar", 6);
+  ASSERT_EQ(c, a);
+  c.set("foobar", 0);
+  ASSERT_EQ(c, e);
+  c.set("foobar", 7);
+  ASSERT_NE(c, a);
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckNULL) {
+  // we used to crash here, but now we don't.
+  BasicStringPiece<TypeParam> s(NULL);
+  ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL);
+  ASSERT_EQ(s.size(), 0U);
+
+  s.set(NULL);
+  ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL);
+  ASSERT_EQ(s.size(), 0U);
+
+  TypeParam str = s.as_string();
+  ASSERT_EQ(str.length(), 0U);
+  ASSERT_EQ(str, TypeParam());
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckComparisons2) {
+  TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz"));
+  TypeParam alphabet_z(TestFixture::as_string("abcdefghijklmnopqrstuvwxyzz"));
+  TypeParam alphabet_y(TestFixture::as_string("abcdefghijklmnopqrstuvwxyy"));
+  BasicStringPiece<TypeParam> abc(alphabet);
+
+  // check comparison operations on strings longer than 4 bytes.
+  ASSERT_TRUE(abc == BasicStringPiece<TypeParam>(alphabet));
+  ASSERT_EQ(abc.compare(BasicStringPiece<TypeParam>(alphabet)), 0);
+
+  ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z));
+  ASSERT_LT(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)), 0);
+
+  ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y));
+  ASSERT_GT(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)), 0);
+}
+
+// Test operations only supported by std::string version.
+TEST(StringPieceTest, CheckComparisons2) {
+  StringPiece abc("abcdefghijklmnopqrstuvwxyz");
+
+  // starts_with
+  ASSERT_TRUE(abc.starts_with(abc));
+  ASSERT_TRUE(abc.starts_with("abcdefghijklm"));
+  ASSERT_TRUE(!abc.starts_with("abcdefguvwxyz"));
+
+  // ends_with
+  ASSERT_TRUE(abc.ends_with(abc));
+  ASSERT_TRUE(!abc.ends_with("abcdefguvwxyz"));
+  ASSERT_TRUE(abc.ends_with("nopqrstuvwxyz"));
+}
+
+TYPED_TEST(CommonStringPieceTest, StringCompareNotAmbiguous) {
+  ASSERT_TRUE(TestFixture::as_string("hello").c_str() ==
+              TestFixture::as_string("hello"));
+  ASSERT_TRUE(TestFixture::as_string("hello").c_str() <
+              TestFixture::as_string("world"));
+}
+
+TYPED_TEST(CommonStringPieceTest, HeterogenousStringPieceEquals) {
+  TypeParam hello(TestFixture::as_string("hello"));
+
+  ASSERT_TRUE(BasicStringPiece<TypeParam>(hello) == hello);
+  ASSERT_TRUE(hello.c_str() == BasicStringPiece<TypeParam>(hello));
+}
+
+// string16-specific stuff
+TEST(StringPiece16Test, CheckSTL) {
+  // Check some non-ascii characters.
+  string16 fifth(ASCIIToUTF16("123"));
+  fifth.push_back(0x0000);
+  fifth.push_back(0xd8c5);
+  fifth.push_back(0xdffe);
+  StringPiece16 f(fifth);
+
+  ASSERT_EQ(f[3], '\0');
+  ASSERT_EQ(f[5], static_cast<char16>(0xdffe));
+
+  ASSERT_EQ(f.size(), 6U);
+}
+
+
+
+TEST(StringPiece16Test, CheckConversion) {
+  // Make sure that we can convert from UTF8 to UTF16 and back. We use a two
+  // byte character (G clef) to test this.
+  ASSERT_EQ(
+      UTF16ToUTF8(
+          StringPiece16(UTF8ToUTF16("\xf0\x9d\x84\x9e")).as_string()),
+      "\xf0\x9d\x84\x9e");
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckConstructors) {
+  TypeParam str(TestFixture::as_string("hello world"));
+  TypeParam empty;
+
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str));
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.c_str()));
+  ASSERT_TRUE(TestFixture::as_string("hello") ==
+              BasicStringPiece<TypeParam>(str.c_str(), 5));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.c_str(),
+      static_cast<typename BasicStringPiece<TypeParam>::size_type>(0)));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL,
+      static_cast<typename BasicStringPiece<TypeParam>::size_type>(0)));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>());
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.begin(), str.end()));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.begin(), str.begin()));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty.begin(), empty.end()));
+}
+
+}  // namespace base
diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc
new file mode 100644
index 0000000..88a6236
--- /dev/null
+++ b/base/strings/string_split.cc
@@ -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.
+
+#include "base/strings/string_split.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR>
+void SplitStringT(const STR& str,
+                  const typename STR::value_type s,
+                  bool trim_whitespace,
+                  std::vector<STR>* r) {
+  r->clear();
+  size_t last = 0;
+  size_t c = str.size();
+  for (size_t i = 0; i <= c; ++i) {
+    if (i == c || str[i] == s) {
+      STR tmp(str, last, i - last);
+      if (trim_whitespace)
+        TrimWhitespace(tmp, TRIM_ALL, &tmp);
+      // Avoid converting an empty or all-whitespace source string into a vector
+      // of one empty string.
+      if (i != c || !r->empty() || !tmp.empty())
+        r->push_back(tmp);
+      last = i + 1;
+    }
+  }
+}
+
+bool SplitStringIntoKeyValue(const std::string& line,
+                             char key_value_delimiter,
+                             std::string* key,
+                             std::string* value) {
+  key->clear();
+  value->clear();
+
+  // Find the delimiter.
+  size_t end_key_pos = line.find_first_of(key_value_delimiter);
+  if (end_key_pos == std::string::npos) {
+    DVLOG(1) << "cannot find delimiter in: " << line;
+    return false;    // no delimiter
+  }
+  key->assign(line, 0, end_key_pos);
+
+  // Find the value string.
+  std::string remains(line, end_key_pos, line.size() - end_key_pos);
+  size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter);
+  if (begin_value_pos == std::string::npos) {
+    DVLOG(1) << "cannot parse value from line: " << line;
+    return false;   // no value
+  }
+  value->assign(remains, begin_value_pos, remains.size() - begin_value_pos);
+  return true;
+}
+
+template <typename STR>
+void SplitStringUsingSubstrT(const STR& str,
+                                    const STR& s,
+                                    std::vector<STR>* r) {
+  r->clear();
+  typename STR::size_type begin_index = 0;
+  while (true) {
+    const typename STR::size_type end_index = str.find(s, begin_index);
+    if (end_index == STR::npos) {
+      const STR term = str.substr(begin_index);
+      STR tmp;
+      TrimWhitespace(term, TRIM_ALL, &tmp);
+      r->push_back(tmp);
+      return;
+    }
+    const STR term = str.substr(begin_index, end_index - begin_index);
+    STR tmp;
+    TrimWhitespace(term, TRIM_ALL, &tmp);
+    r->push_back(tmp);
+    begin_index = end_index + s.size();
+  }
+}
+
+template<typename STR>
+void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) {
+  result->clear();
+  const size_t length = str.length();
+  if (!length)
+    return;
+
+  bool last_was_ws = false;
+  size_t last_non_ws_start = 0;
+  for (size_t i = 0; i < length; ++i) {
+    switch (str[i]) {
+      // HTML 5 defines whitespace as: space, tab, LF, line tab, FF, or CR.
+      case L' ':
+      case L'\t':
+      case L'\xA':
+      case L'\xB':
+      case L'\xC':
+      case L'\xD':
+        if (!last_was_ws) {
+          if (i > 0) {
+            result->push_back(
+                str.substr(last_non_ws_start, i - last_non_ws_start));
+          }
+          last_was_ws = true;
+        }
+        break;
+
+      default:  // Not a space character.
+        if (last_was_ws) {
+          last_was_ws = false;
+          last_non_ws_start = i;
+        }
+        break;
+    }
+  }
+  if (!last_was_ws) {
+    result->push_back(
+        str.substr(last_non_ws_start, length - last_non_ws_start));
+  }
+}
+
+}  // namespace
+
+void SplitString(const string16& str,
+                 char16 c,
+                 std::vector<string16>* r) {
+  DCHECK(CBU16_IS_SINGLE(c));
+  SplitStringT(str, c, true, r);
+}
+
+void SplitString(const std::string& str,
+                 char c,
+                 std::vector<std::string>* r) {
+#if CHAR_MIN < 0
+  DCHECK_GE(c, 0);
+#endif
+  DCHECK_LT(c, 0x7F);
+  SplitStringT(str, c, true, r);
+}
+
+bool SplitStringIntoKeyValuePairs(const std::string& line,
+                                  char key_value_delimiter,
+                                  char key_value_pair_delimiter,
+                                  StringPairs* key_value_pairs) {
+  key_value_pairs->clear();
+
+  std::vector<std::string> pairs;
+  SplitString(line, key_value_pair_delimiter, &pairs);
+
+  bool success = true;
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    // Don't add empty pairs into the result.
+    if (pairs[i].empty())
+      continue;
+
+    std::string key;
+    std::string value;
+    if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) {
+      // Don't return here, to allow for pairs without associated
+      // value or key; just record that the split failed.
+      success = false;
+    }
+    key_value_pairs->push_back(make_pair(key, value));
+  }
+  return success;
+}
+
+void SplitStringUsingSubstr(const string16& str,
+                            const string16& s,
+                            std::vector<string16>* r) {
+  SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringUsingSubstr(const std::string& str,
+                            const std::string& s,
+                            std::vector<std::string>* r) {
+  SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringDontTrim(const string16& str,
+                         char16 c,
+                         std::vector<string16>* r) {
+  DCHECK(CBU16_IS_SINGLE(c));
+  SplitStringT(str, c, false, r);
+}
+
+void SplitStringDontTrim(const std::string& str,
+                         char c,
+                         std::vector<std::string>* r) {
+#if CHAR_MIN < 0
+  DCHECK_GE(c, 0);
+#endif
+  DCHECK_LT(c, 0x7F);
+  SplitStringT(str, c, false, r);
+}
+
+void SplitStringAlongWhitespace(const string16& str,
+                                std::vector<string16>* result) {
+  SplitStringAlongWhitespaceT(str, result);
+}
+
+void SplitStringAlongWhitespace(const std::string& str,
+                                std::vector<std::string>* result) {
+  SplitStringAlongWhitespaceT(str, result);
+}
+
+}  // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
new file mode 100644
index 0000000..55d8cb3
--- /dev/null
+++ b/base/strings/string_split.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_SPLIT_H_
+#define BASE_STRINGS_STRING_SPLIT_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// Splits |str| into a vector of strings delimited by |c|, placing the results
+// in |r|. If several instances of |c| are contiguous, or if |str| begins with
+// or ends with |c|, then an empty string is inserted.
+//
+// Every substring is trimmed of any leading or trailing white space.
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+BASE_EXPORT void SplitString(const string16& str,
+                             char16 c,
+                             std::vector<string16>* r);
+
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+BASE_EXPORT void SplitString(const std::string& str,
+                             char c,
+                             std::vector<std::string>* r);
+
+typedef std::vector<std::pair<std::string, std::string> > StringPairs;
+
+// Splits |line| into key value pairs according to the given delimiters and
+// removes whitespace leading each key and trailing each value. Returns true
+// only if each pair has a non-empty key and value. |key_value_pairs| will
+// include ("","") pairs for entries without |key_value_delimiter|.
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
+                                              char key_value_delimiter,
+                                              char key_value_pair_delimiter,
+                                              StringPairs* key_value_pairs);
+
+// The same as SplitString, but use a substring delimiter instead of a char.
+BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
+                                        const string16& s,
+                                        std::vector<string16>* r);
+BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
+                                        const std::string& s,
+                                        std::vector<std::string>* r);
+
+// The same as SplitString, but don't trim white space.
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+BASE_EXPORT void SplitStringDontTrim(const string16& str,
+                                     char16 c,
+                                     std::vector<string16>* r);
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+BASE_EXPORT void SplitStringDontTrim(const std::string& str,
+                                     char c,
+                                     std::vector<std::string>* r);
+
+// WARNING: this uses whitespace as defined by the HTML5 spec. If you need
+// a function similar to this but want to trim all types of whitespace, then
+// factor this out into a function that takes a string containing the characters
+// that are treated as whitespace.
+//
+// Splits the string along whitespace (where whitespace is the five space
+// characters defined by HTML 5). Each contiguous block of non-whitespace
+// characters is added to result.
+BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
+                                            std::vector<string16>* result);
+BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
+                                            std::vector<std::string>* result);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_SPLIT_H_
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc
new file mode 100644
index 0000000..32bbe28
--- /dev/null
+++ b/base/strings/string_split_unittest.cc
@@ -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.
+
+#include "base/strings/string_split.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+
+namespace base {
+
+namespace {
+
+#if !defined(WCHAR_T_IS_UTF16)
+// Overload SplitString with a wide-char version to make it easier to
+// test the string16 version with wide character literals.
+void SplitString(const std::wstring& str,
+                 wchar_t c,
+                 std::vector<std::wstring>* result) {
+  std::vector<string16> result16;
+  SplitString(WideToUTF16(str), c, &result16);
+  for (size_t i = 0; i < result16.size(); ++i)
+    result->push_back(UTF16ToWide(result16[i]));
+}
+#endif
+
+}  // anonymous namespace
+
+class SplitStringIntoKeyValuePairsTest : public testing::Test {
+ protected:
+  base::StringPairs kv_pairs;
+};
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyString) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(std::string(),
+                                           ':',  // Key-value delimiter
+                                           ',',  // Key-value pair delimiter
+                                           &kv_pairs));
+  EXPECT_TRUE(kv_pairs.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, MissingKeyValueDelimiter) {
+  EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1,key2:value2",
+                                            ':',  // Key-value delimiter
+                                            ',',  // Key-value pair delimiter
+                                            &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_TRUE(kv_pairs[0].first.empty());
+  EXPECT_TRUE(kv_pairs[0].second.empty());
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyKeyWithKeyValueDelimiter) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(":value1,key2:value2",
+                                           ':',  // Key-value delimiter
+                                           ',',  // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_TRUE(kv_pairs[0].first.empty());
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, TrailingAndLeadingPairDelimiter) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(",key1:value1,key2:value2,",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyPair) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1,,key3:value3",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key3", kv_pairs[1].first);
+  EXPECT_EQ("value3", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyValue) {
+  EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1:,key2:value2",
+                                            ':',   // Key-value delimiter
+                                            ',',   // Key-value pair delimiter
+                                            &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, UntrimmedWhitespace) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1 : value1",
+                                           ':',  // Key-value delimiter
+                                           ',',  // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(1U, kv_pairs.size());
+  EXPECT_EQ("key1 ", kv_pairs[0].first);
+  EXPECT_EQ(" value1", kv_pairs[0].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, TrimmedWhitespace) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1 , key2:value2",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, MultipleKeyValueDelimiters) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:::value1,key2:value2",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, OnlySplitAtGivenSeparator) {
+  std::string a("a ?!@#$%^&*()_+:/{}\\\t\nb");
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(a + "X" + a + "Y" + a + "X" + a,
+                                           'X',  // Key-value delimiter
+                                           'Y',  // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ(a, kv_pairs[0].first);
+  EXPECT_EQ(a, kv_pairs[0].second);
+  EXPECT_EQ(a, kv_pairs[1].first);
+  EXPECT_EQ(a, kv_pairs[1].second);
+}
+
+
+TEST_F(SplitStringIntoKeyValuePairsTest, DelimiterInValue) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:va:ue1,key2:value2",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("va:ue1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST(SplitStringUsingSubstrTest, EmptyString) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(std::string(), "DELIMITER", &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre(""));
+}
+
+TEST(StringUtilTest, SplitString) {
+  std::vector<std::wstring> r;
+
+  SplitString(std::wstring(), L',', &r);
+  EXPECT_EQ(0U, r.size());
+  r.clear();
+
+  SplitString(L"a,b,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a, b, c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a,,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"   ", L'*', &r);
+  EXPECT_EQ(0U, r.size());
+  r.clear();
+
+  SplitString(L"foo", L'*', &r);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], L"foo");
+  r.clear();
+
+  SplitString(L"foo ,", L',', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"foo");
+  EXPECT_EQ(r[1], L"");
+  r.clear();
+
+  SplitString(L",", L',', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"");
+  EXPECT_EQ(r[1], L"");
+  r.clear();
+
+  SplitString(L"\t\ta\t", L'\t', &r);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], L"");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"a");
+  EXPECT_EQ(r[3], L"");
+  r.clear();
+
+  SplitString(L"\ta\t\nb\tcc", L'\n', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b\tcc");
+  r.clear();
+}
+
+TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(6u, results.size());
+  EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(
+      results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(StringSplitTest, StringSplitDontTrim) {
+  std::vector<std::string> r;
+
+  SplitStringDontTrim("   ", '*', &r);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], "   ");
+
+  SplitStringDontTrim("\t  \ta\t ", '\t', &r);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], "");
+  EXPECT_EQ(r[1], "  ");
+  EXPECT_EQ(r[2], "a");
+  EXPECT_EQ(r[3], " ");
+
+  SplitStringDontTrim("\ta\t\nb\tcc", '\n', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], "\ta\t");
+  EXPECT_EQ(r[1], "b\tcc");
+}
+
+TEST(StringSplitTest, SplitStringAlongWhitespace) {
+  struct TestData {
+    const char* input;
+    const size_t expected_result_count;
+    const char* output1;
+    const char* output2;
+  } data[] = {
+    { "a",       1, "a",  ""   },
+    { " ",       0, "",   ""   },
+    { " a",      1, "a",  ""   },
+    { " ab ",    1, "ab", ""   },
+    { " ab c",   2, "ab", "c"  },
+    { " ab c ",  2, "ab", "c"  },
+    { " ab cd",  2, "ab", "cd" },
+    { " ab cd ", 2, "ab", "cd" },
+    { " \ta\t",  1, "a",  ""   },
+    { " b\ta\t", 2, "b",  "a"  },
+    { " b\tat",  2, "b",  "at" },
+    { "b\tat",   2, "b",  "at" },
+    { "b\t at",  2, "b",  "at" },
+  };
+  for (size_t i = 0; i < arraysize(data); ++i) {
+    std::vector<std::string> results;
+    SplitStringAlongWhitespace(data[i].input, &results);
+    ASSERT_EQ(data[i].expected_result_count, results.size());
+    if (data[i].expected_result_count > 0)
+      ASSERT_EQ(data[i].output1, results[0]);
+    if (data[i].expected_result_count > 1)
+      ASSERT_EQ(data[i].output2, results[1]);
+  }
+}
+
+}  // namespace base
diff --git a/base/strings/string_tokenizer.h b/base/strings/string_tokenizer.h
new file mode 100644
index 0000000..8defbac
--- /dev/null
+++ b/base/strings/string_tokenizer.h
@@ -0,0 +1,260 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_TOKENIZER_H_
+#define BASE_STRINGS_STRING_TOKENIZER_H_
+
+#include <algorithm>
+#include <string>
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// StringTokenizerT is a simple string tokenizer class.  It works like an
+// iterator that with each step (see the Advance method) updates members that
+// refer to the next token in the input string.  The user may optionally
+// configure the tokenizer to return delimiters.
+//
+// Warning: be careful not to pass a C string into the 2-arg constructor:
+// StringTokenizer t("this is a test", " ");  // WRONG
+// This will create a temporary std::string, save the begin() and end()
+// iterators, and then the string will be freed before we actually start
+// tokenizing it.
+// Instead, use a std::string or use the 3 arg constructor of CStringTokenizer.
+//
+//
+// EXAMPLE 1:
+//
+//   char input[] = "this is a test";
+//   CStringTokenizer t(input, input + strlen(input), " ");
+//   while (t.GetNext()) {
+//     printf("%s\n", t.token().c_str());
+//   }
+//
+// Output:
+//
+//   this
+//   is
+//   a
+//   test
+//
+//
+// EXAMPLE 2:
+//
+//   std::string input = "no-cache=\"foo, bar\", private";
+//   StringTokenizer t(input, ", ");
+//   t.set_quote_chars("\"");
+//   while (t.GetNext()) {
+//     printf("%s\n", t.token().c_str());
+//   }
+//
+// Output:
+//
+//   no-cache="foo, bar"
+//   private
+//
+//
+// EXAMPLE 3:
+//
+//   bool next_is_option = false, next_is_value = false;
+//   std::string input = "text/html; charset=UTF-8; foo=bar";
+//   StringTokenizer t(input, "; =");
+//   t.set_options(StringTokenizer::RETURN_DELIMS);
+//   while (t.GetNext()) {
+//     if (t.token_is_delim()) {
+//       switch (*t.token_begin()) {
+//         case ';':
+//           next_is_option = true;
+//           break;
+//         case '=':
+//           next_is_value = true;
+//           break;
+//       }
+//     } else {
+//       const char* label;
+//       if (next_is_option) {
+//         label = "option-name";
+//         next_is_option = false;
+//       } else if (next_is_value) {
+//         label = "option-value";
+//         next_is_value = false;
+//       } else {
+//         label = "mime-type";
+//       }
+//       printf("%s: %s\n", label, t.token().c_str());
+//     }
+//   }
+//
+//
+template <class str, class const_iterator>
+class StringTokenizerT {
+ public:
+  typedef typename str::value_type char_type;
+
+  // Options that may be pass to set_options()
+  enum {
+    // Specifies the delimiters should be returned as tokens
+    RETURN_DELIMS = 1 << 0,
+  };
+
+  // The string object must live longer than the tokenizer.  (In particular this
+  // should not be constructed with a temporary.)
+  StringTokenizerT(const str& string,
+                   const str& delims) {
+    Init(string.begin(), string.end(), delims);
+  }
+
+  StringTokenizerT(const_iterator string_begin,
+                   const_iterator string_end,
+                   const str& delims) {
+    Init(string_begin, string_end, delims);
+  }
+
+  // Set the options for this tokenizer.  By default, this is 0.
+  void set_options(int options) { options_ = options; }
+
+  // Set the characters to regard as quotes.  By default, this is empty.  When
+  // a quote char is encountered, the tokenizer will switch into a mode where
+  // it ignores delimiters that it finds.  It switches out of this mode once it
+  // finds another instance of the quote char.  If a backslash is encountered
+  // within a quoted string, then the next character is skipped.
+  void set_quote_chars(const str& quotes) { quotes_ = quotes; }
+
+  // Call this method to advance the tokenizer to the next delimiter.  This
+  // returns false if the tokenizer is complete.  This method must be called
+  // before calling any of the token* methods.
+  bool GetNext() {
+    if (quotes_.empty() && options_ == 0)
+      return QuickGetNext();
+    else
+      return FullGetNext();
+  }
+
+  // Start iterating through tokens from the beginning of the string.
+  void Reset() {
+    token_end_ = start_pos_;
+  }
+
+  // Returns true if token is a delimiter.  When the tokenizer is constructed
+  // with the RETURN_DELIMS option, this method can be used to check if the
+  // returned token is actually a delimiter.
+  bool token_is_delim() const { return token_is_delim_; }
+
+  // If GetNext() returned true, then these methods may be used to read the
+  // value of the token.
+  const_iterator token_begin() const { return token_begin_; }
+  const_iterator token_end() const { return token_end_; }
+  str token() const { return str(token_begin_, token_end_); }
+  base::StringPiece token_piece() const {
+    return base::StringPiece(&*token_begin_,
+                             std::distance(token_begin_, token_end_));
+  }
+
+ private:
+  void Init(const_iterator string_begin,
+            const_iterator string_end,
+            const str& delims) {
+    start_pos_ = string_begin;
+    token_begin_ = string_begin;
+    token_end_ = string_begin;
+    end_ = string_end;
+    delims_ = delims;
+    options_ = 0;
+    token_is_delim_ = false;
+  }
+
+  // Implementation of GetNext() for when we have no quote characters. We have
+  // two separate implementations because AdvanceOne() is a hot spot in large
+  // text files with large tokens.
+  bool QuickGetNext() {
+    token_is_delim_ = false;
+    for (;;) {
+      token_begin_ = token_end_;
+      if (token_end_ == end_)
+        return false;
+      ++token_end_;
+      if (delims_.find(*token_begin_) == str::npos)
+        break;
+      // else skip over delimiter.
+    }
+    while (token_end_ != end_ && delims_.find(*token_end_) == str::npos)
+      ++token_end_;
+    return true;
+  }
+
+  // Implementation of GetNext() for when we have to take quotes into account.
+  bool FullGetNext() {
+    AdvanceState state;
+    token_is_delim_ = false;
+    for (;;) {
+      token_begin_ = token_end_;
+      if (token_end_ == end_)
+        return false;
+      ++token_end_;
+      if (AdvanceOne(&state, *token_begin_))
+        break;
+      if (options_ & RETURN_DELIMS) {
+        token_is_delim_ = true;
+        return true;
+      }
+      // else skip over delimiter.
+    }
+    while (token_end_ != end_ && AdvanceOne(&state, *token_end_))
+      ++token_end_;
+    return true;
+  }
+
+  bool IsDelim(char_type c) const {
+    return delims_.find(c) != str::npos;
+  }
+
+  bool IsQuote(char_type c) const {
+    return quotes_.find(c) != str::npos;
+  }
+
+  struct AdvanceState {
+    bool in_quote;
+    bool in_escape;
+    char_type quote_char;
+    AdvanceState() : in_quote(false), in_escape(false), quote_char('\0') {}
+  };
+
+  // Returns true if a delimiter was not hit.
+  bool AdvanceOne(AdvanceState* state, char_type c) {
+    if (state->in_quote) {
+      if (state->in_escape) {
+        state->in_escape = false;
+      } else if (c == '\\') {
+        state->in_escape = true;
+      } else if (c == state->quote_char) {
+        state->in_quote = false;
+      }
+    } else {
+      if (IsDelim(c))
+        return false;
+      state->in_quote = IsQuote(state->quote_char = c);
+    }
+    return true;
+  }
+
+  const_iterator start_pos_;
+  const_iterator token_begin_;
+  const_iterator token_end_;
+  const_iterator end_;
+  str delims_;
+  str quotes_;
+  int options_;
+  bool token_is_delim_;
+};
+
+typedef StringTokenizerT<std::string, std::string::const_iterator>
+    StringTokenizer;
+typedef StringTokenizerT<std::wstring, std::wstring::const_iterator>
+    WStringTokenizer;
+typedef StringTokenizerT<std::string, const char*> CStringTokenizer;
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_TOKENIZER_H_
diff --git a/base/strings/string_tokenizer_unittest.cc b/base/strings/string_tokenizer_unittest.cc
new file mode 100644
index 0000000..d391845
--- /dev/null
+++ b/base/strings/string_tokenizer_unittest.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_tokenizer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace base {
+
+namespace {
+
+TEST(StringTokenizerTest, Simple) {
+  string input = "this is a test";
+  StringTokenizer t(input, " ");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("this"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("is"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("a"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("test"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, Reset) {
+  string input = "this is a test";
+  StringTokenizer t(input, " ");
+
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("this"), t.token());
+
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("is"), t.token());
+
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("a"), t.token());
+
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("test"), t.token());
+
+    EXPECT_FALSE(t.GetNext());
+    t.Reset();
+  }
+}
+
+TEST(StringTokenizerTest, RetDelims) {
+  string input = "this is a test";
+  StringTokenizer t(input, " ");
+  t.set_options(StringTokenizer::RETURN_DELIMS);
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("this"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("is"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("a"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("test"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ManyDelims) {
+  string input = "this: is, a-test";
+  StringTokenizer t(input, ": ,-");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("this"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("is"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("a"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("test"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseHeader) {
+  string input = "Content-Type: text/html ; charset=UTF-8";
+  StringTokenizer t(input, ": ;=");
+  t.set_options(StringTokenizer::RETURN_DELIMS);
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("Content-Type"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(":"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("text/html"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(";"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("charset"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string("="), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("UTF-8"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString) {
+  string input = "foo bar 'hello world' baz";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("foo"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'hello world'"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("baz"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_Malformed) {
+  string input = "bar 'hello wo";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'hello wo"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_Multiple) {
+  string input = "bar 'hel\"lo\" wo' baz\"";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'\"");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'hel\"lo\" wo'"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("baz\""), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes) {
+  string input = "foo 'don\\'t do that'";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("foo"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'don\\'t do that'"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes2) {
+  string input = "foo='a, b', bar";
+  StringTokenizer t(input, ", ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("foo='a, b'"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
new file mode 100644
index 0000000..6f6d6e2
--- /dev/null
+++ b/base/strings/string_util.cc
@@ -0,0 +1,1034 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "build/build_config.h"
+
+// Remove when this entire file is in the base namespace.
+using base::char16;
+using base::string16;
+
+namespace {
+
+// Force the singleton used by EmptyString[16] to be a unique type. This
+// prevents other code that might accidentally use Singleton<string> from
+// getting our internal one.
+struct EmptyStrings {
+  EmptyStrings() {}
+  const std::string s;
+  const string16 s16;
+
+  static EmptyStrings* GetInstance() {
+    return Singleton<EmptyStrings>::get();
+  }
+};
+
+// Used by ReplaceStringPlaceholders to track the position in the string of
+// replaced parameters.
+struct ReplacementOffset {
+  ReplacementOffset(uintptr_t parameter, size_t offset)
+      : parameter(parameter),
+        offset(offset) {}
+
+  // Index of the parameter.
+  uintptr_t parameter;
+
+  // Starting position in the string.
+  size_t offset;
+};
+
+static bool CompareParameter(const ReplacementOffset& elem1,
+                             const ReplacementOffset& elem2) {
+  return elem1.parameter < elem2.parameter;
+}
+
+// Assuming that a pointer is the size of a "machine word", then
+// uintptr_t is an integer type that is also a machine word.
+typedef uintptr_t MachineWord;
+const uintptr_t kMachineWordAlignmentMask = sizeof(MachineWord) - 1;
+
+inline bool IsAlignedToMachineWord(const void* pointer) {
+  return !(reinterpret_cast<MachineWord>(pointer) & kMachineWordAlignmentMask);
+}
+
+template<typename T> inline T* AlignToMachineWord(T* pointer) {
+  return reinterpret_cast<T*>(reinterpret_cast<MachineWord>(pointer) &
+                              ~kMachineWordAlignmentMask);
+}
+
+template<size_t size, typename CharacterType> struct NonASCIIMask;
+template<> struct NonASCIIMask<4, base::char16> {
+    static inline uint32_t value() { return 0xFF80FF80U; }
+};
+template<> struct NonASCIIMask<4, char> {
+    static inline uint32_t value() { return 0x80808080U; }
+};
+template<> struct NonASCIIMask<8, base::char16> {
+    static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
+};
+template<> struct NonASCIIMask<8, char> {
+    static inline uint64_t value() { return 0x8080808080808080ULL; }
+};
+#if defined(WCHAR_T_IS_UTF32)
+template<> struct NonASCIIMask<4, wchar_t> {
+    static inline uint32_t value() { return 0xFFFFFF80U; }
+};
+template<> struct NonASCIIMask<8, wchar_t> {
+    static inline uint64_t value() { return 0xFFFFFF80FFFFFF80ULL; }
+};
+#endif  // WCHAR_T_IS_UTF32
+
+}  // namespace
+
+namespace base {
+
+bool IsWprintfFormatPortable(const wchar_t* format) {
+  for (const wchar_t* position = format; *position != '\0'; ++position) {
+    if (*position == '%') {
+      bool in_specification = true;
+      bool modifier_l = false;
+      while (in_specification) {
+        // Eat up characters until reaching a known specifier.
+        if (*++position == '\0') {
+          // The format string ended in the middle of a specification.  Call
+          // it portable because no unportable specifications were found.  The
+          // string is equally broken on all platforms.
+          return true;
+        }
+
+        if (*position == 'l') {
+          // 'l' is the only thing that can save the 's' and 'c' specifiers.
+          modifier_l = true;
+        } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
+                   *position == 'S' || *position == 'C' || *position == 'F' ||
+                   *position == 'D' || *position == 'O' || *position == 'U') {
+          // Not portable.
+          return false;
+        }
+
+        if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
+          // Portable, keep scanning the rest of the format string.
+          in_specification = false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+const std::string& EmptyString() {
+  return EmptyStrings::GetInstance()->s;
+}
+
+const string16& EmptyString16() {
+  return EmptyStrings::GetInstance()->s16;
+}
+
+template<typename STR>
+bool ReplaceCharsT(const STR& input,
+                   const STR& replace_chars,
+                   const STR& replace_with,
+                   STR* output) {
+  bool removed = false;
+  size_t replace_length = replace_with.length();
+
+  *output = input;
+
+  size_t found = output->find_first_of(replace_chars);
+  while (found != STR::npos) {
+    removed = true;
+    output->replace(found, 1, replace_with);
+    found = output->find_first_of(replace_chars, found + replace_length);
+  }
+
+  return removed;
+}
+
+bool ReplaceChars(const string16& input,
+                  const base::StringPiece16& replace_chars,
+                  const string16& replace_with,
+                  string16* output) {
+  return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
+}
+
+bool ReplaceChars(const std::string& input,
+                  const base::StringPiece& replace_chars,
+                  const std::string& replace_with,
+                  std::string* output) {
+  return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
+}
+
+bool RemoveChars(const string16& input,
+                 const base::StringPiece16& remove_chars,
+                 string16* output) {
+  return ReplaceChars(input, remove_chars.as_string(), string16(), output);
+}
+
+bool RemoveChars(const std::string& input,
+                 const base::StringPiece& remove_chars,
+                 std::string* output) {
+  return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
+}
+
+template<typename STR>
+TrimPositions TrimStringT(const STR& input,
+                          const STR& trim_chars,
+                          TrimPositions positions,
+                          STR* output) {
+  // Find the edges of leading/trailing whitespace as desired.
+  const size_t last_char = input.length() - 1;
+  const size_t first_good_char = (positions & TRIM_LEADING) ?
+      input.find_first_not_of(trim_chars) : 0;
+  const size_t last_good_char = (positions & TRIM_TRAILING) ?
+      input.find_last_not_of(trim_chars) : last_char;
+
+  // When the string was all whitespace, report that we stripped off whitespace
+  // from whichever position the caller was interested in.  For empty input, we
+  // stripped no whitespace, but we still need to clear |output|.
+  if (input.empty() ||
+      (first_good_char == STR::npos) || (last_good_char == STR::npos)) {
+    bool input_was_empty = input.empty();  // in case output == &input
+    output->clear();
+    return input_was_empty ? TRIM_NONE : positions;
+  }
+
+  // Trim the whitespace.
+  *output =
+      input.substr(first_good_char, last_good_char - first_good_char + 1);
+
+  // Return where we trimmed from.
+  return static_cast<TrimPositions>(
+      ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
+      ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
+}
+
+bool TrimString(const string16& input,
+                const base::StringPiece16& trim_chars,
+                string16* output) {
+  return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
+      TRIM_NONE;
+}
+
+bool TrimString(const std::string& input,
+                const base::StringPiece& trim_chars,
+                std::string* output) {
+  return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) !=
+      TRIM_NONE;
+}
+
+void TruncateUTF8ToByteSize(const std::string& input,
+                            const size_t byte_size,
+                            std::string* output) {
+  DCHECK(output);
+  if (byte_size > input.length()) {
+    *output = input;
+    return;
+  }
+  DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
+  // Note: This cast is necessary because CBU8_NEXT uses int32s.
+  int32 truncation_length = static_cast<int32>(byte_size);
+  int32 char_index = truncation_length - 1;
+  const char* data = input.data();
+
+  // Using CBU8, we will move backwards from the truncation point
+  // to the beginning of the string looking for a valid UTF8
+  // character.  Once a full UTF8 character is found, we will
+  // truncate the string to the end of that character.
+  while (char_index >= 0) {
+    int32 prev = char_index;
+    base_icu::UChar32 code_point = 0;
+    CBU8_NEXT(data, char_index, truncation_length, code_point);
+    if (!IsValidCharacter(code_point) ||
+        !IsValidCodepoint(code_point)) {
+      char_index = prev - 1;
+    } else {
+      break;
+    }
+  }
+
+  if (char_index >= 0 )
+    *output = input.substr(0, char_index);
+  else
+    output->clear();
+}
+
+TrimPositions TrimWhitespace(const string16& input,
+                             TrimPositions positions,
+                             string16* output) {
+  return TrimStringT(input, base::string16(kWhitespaceUTF16), positions,
+                     output);
+}
+
+TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                  TrimPositions positions,
+                                  std::string* output) {
+  return TrimStringT(input, std::string(kWhitespaceASCII), positions, output);
+}
+
+// This function is only for backward-compatibility.
+// To be removed when all callers are updated.
+TrimPositions TrimWhitespace(const std::string& input,
+                             TrimPositions positions,
+                             std::string* output) {
+  return TrimWhitespaceASCII(input, positions, output);
+}
+
+template<typename STR>
+STR CollapseWhitespaceT(const STR& text,
+                        bool trim_sequences_with_line_breaks) {
+  STR result;
+  result.resize(text.size());
+
+  // Set flags to pretend we're already in a trimmed whitespace sequence, so we
+  // will trim any leading whitespace.
+  bool in_whitespace = true;
+  bool already_trimmed = true;
+
+  int chars_written = 0;
+  for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
+    if (IsWhitespace(*i)) {
+      if (!in_whitespace) {
+        // Reduce all whitespace sequences to a single space.
+        in_whitespace = true;
+        result[chars_written++] = L' ';
+      }
+      if (trim_sequences_with_line_breaks && !already_trimmed &&
+          ((*i == '\n') || (*i == '\r'))) {
+        // Whitespace sequences containing CR or LF are eliminated entirely.
+        already_trimmed = true;
+        --chars_written;
+      }
+    } else {
+      // Non-whitespace chracters are copied straight across.
+      in_whitespace = false;
+      already_trimmed = false;
+      result[chars_written++] = *i;
+    }
+  }
+
+  if (in_whitespace && !already_trimmed) {
+    // Any trailing whitespace is eliminated.
+    --chars_written;
+  }
+
+  result.resize(chars_written);
+  return result;
+}
+
+string16 CollapseWhitespace(const string16& text,
+                            bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+std::string CollapseWhitespaceASCII(const std::string& text,
+                                    bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+bool ContainsOnlyChars(const StringPiece& input,
+                       const StringPiece& characters) {
+  return input.find_first_not_of(characters) == StringPiece::npos;
+}
+
+bool ContainsOnlyChars(const StringPiece16& input,
+                       const StringPiece16& characters) {
+  return input.find_first_not_of(characters) == StringPiece16::npos;
+}
+
+template <class Char>
+inline bool DoIsStringASCII(const Char* characters, size_t length) {
+  MachineWord all_char_bits = 0;
+  const Char* end = characters + length;
+
+  // Prologue: align the input.
+  while (!IsAlignedToMachineWord(characters) && characters != end) {
+    all_char_bits |= *characters;
+    ++characters;
+  }
+
+  // Compare the values of CPU word size.
+  const Char* word_end = AlignToMachineWord(end);
+  const size_t loop_increment = sizeof(MachineWord) / sizeof(Char);
+  while (characters < word_end) {
+    all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
+    characters += loop_increment;
+  }
+
+  // Process the remaining bytes.
+  while (characters != end) {
+    all_char_bits |= *characters;
+    ++characters;
+  }
+
+  MachineWord non_ascii_bit_mask =
+      NonASCIIMask<sizeof(MachineWord), Char>::value();
+  return !(all_char_bits & non_ascii_bit_mask);
+}
+
+bool IsStringASCII(const StringPiece& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+
+bool IsStringASCII(const StringPiece16& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+
+bool IsStringASCII(const string16& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool IsStringASCII(const std::wstring& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+#endif
+
+bool IsStringUTF8(const StringPiece& str) {
+  const char *src = str.data();
+  int32 src_len = static_cast<int32>(str.length());
+  int32 char_index = 0;
+
+  while (char_index < src_len) {
+    int32 code_point;
+    CBU8_NEXT(src, char_index, src_len, code_point);
+    if (!IsValidCharacter(code_point))
+      return false;
+  }
+  return true;
+}
+
+}  // namespace base
+
+template<typename Iter>
+static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
+                                          Iter a_end,
+                                          const char* b) {
+  for (Iter it = a_begin; it != a_end; ++it, ++b) {
+    if (!*b || base::ToLowerASCII(*it) != *b)
+      return false;
+  }
+  return *b == 0;
+}
+
+// Front-ends for LowerCaseEqualsASCII.
+bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+
+bool LowerCaseEqualsASCII(const string16& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+
+bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                          std::string::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
+                          string16::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(const char16* a_begin,
+                          const char16* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool EqualsASCII(const string16& a, const base::StringPiece& b) {
+  if (a.length() != b.length())
+    return false;
+  return std::equal(b.begin(), b.end(), a.begin());
+}
+
+bool StartsWithASCII(const std::string& str,
+                     const std::string& search,
+                     bool case_sensitive) {
+  if (case_sensitive)
+    return str.compare(0, search.length(), search) == 0;
+  else
+    return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
+}
+
+template <typename STR>
+bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
+  if (case_sensitive) {
+    return str.compare(0, search.length(), search) == 0;
+  } else {
+    if (search.size() > str.size())
+      return false;
+    return std::equal(search.begin(), search.end(), str.begin(),
+                      base::CaseInsensitiveCompare<typename STR::value_type>());
+  }
+}
+
+bool StartsWith(const string16& str, const string16& search,
+                bool case_sensitive) {
+  return StartsWithT(str, search, case_sensitive);
+}
+
+template <typename STR>
+bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
+  size_t str_length = str.length();
+  size_t search_length = search.length();
+  if (search_length > str_length)
+    return false;
+  if (case_sensitive)
+    return str.compare(str_length - search_length, search_length, search) == 0;
+  return std::equal(search.begin(), search.end(),
+                    str.begin() + (str_length - search_length),
+                    base::CaseInsensitiveCompare<typename STR::value_type>());
+}
+
+bool EndsWith(const std::string& str, const std::string& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+
+bool EndsWith(const string16& str, const string16& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+
+static const char* const kByteStringsUnlocalized[] = {
+  " B",
+  " kB",
+  " MB",
+  " GB",
+  " TB",
+  " PB"
+};
+
+string16 FormatBytesUnlocalized(int64 bytes) {
+  double unit_amount = static_cast<double>(bytes);
+  size_t dimension = 0;
+  const int kKilo = 1024;
+  while (unit_amount >= kKilo &&
+         dimension < arraysize(kByteStringsUnlocalized) - 1) {
+    unit_amount /= kKilo;
+    dimension++;
+  }
+
+  char buf[64];
+  if (bytes != 0 && dimension > 0 && unit_amount < 100) {
+    base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
+                   kByteStringsUnlocalized[dimension]);
+  } else {
+    base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
+                   kByteStringsUnlocalized[dimension]);
+  }
+
+  return base::ASCIIToUTF16(buf);
+}
+
+// Runs in O(n) time in the length of |str|.
+template<class StringType>
+void DoReplaceSubstringsAfterOffset(StringType* str,
+                                    size_t offset,
+                                    const StringType& find_this,
+                                    const StringType& replace_with,
+                                    bool replace_all) {
+  DCHECK(!find_this.empty());
+
+  // If the find string doesn't appear, there's nothing to do.
+  offset = str->find(find_this, offset);
+  if (offset == StringType::npos)
+    return;
+
+  // If we're only replacing one instance, there's no need to do anything
+  // complicated.
+  size_t find_length = find_this.length();
+  if (!replace_all) {
+    str->replace(offset, find_length, replace_with);
+    return;
+  }
+
+  // If the find and replace strings are the same length, we can simply use
+  // replace() on each instance, and finish the entire operation in O(n) time.
+  size_t replace_length = replace_with.length();
+  if (find_length == replace_length) {
+    do {
+      str->replace(offset, find_length, replace_with);
+      offset = str->find(find_this, offset + replace_length);
+    } while (offset != StringType::npos);
+    return;
+  }
+
+  // Since the find and replace strings aren't the same length, a loop like the
+  // one above would be O(n^2) in the worst case, as replace() will shift the
+  // entire remaining string each time.  We need to be more clever to keep
+  // things O(n).
+  //
+  // If we're shortening the string, we can alternate replacements with shifting
+  // forward the intervening characters using memmove().
+  size_t str_length = str->length();
+  if (find_length > replace_length) {
+    size_t write_offset = offset;
+    do {
+      if (replace_length) {
+        str->replace(write_offset, replace_length, replace_with);
+        write_offset += replace_length;
+      }
+      size_t read_offset = offset + find_length;
+      offset = std::min(str->find(find_this, read_offset), str_length);
+      size_t length = offset - read_offset;
+      if (length) {
+        memmove(&(*str)[write_offset], &(*str)[read_offset],
+                length * sizeof(typename StringType::value_type));
+        write_offset += length;
+      }
+    } while (offset < str_length);
+    str->resize(write_offset);
+    return;
+  }
+
+  // We're lengthening the string.  We can use alternating replacements and
+  // memmove() calls like above, but we need to precalculate the final string
+  // length and then expand from back-to-front to avoid overwriting the string
+  // as we're reading it, needing to shift, or having to copy to a second string
+  // temporarily.
+  size_t first_match = offset;
+
+  // First, calculate the final length and resize the string.
+  size_t final_length = str_length;
+  size_t expansion = replace_length - find_length;
+  size_t current_match;
+  do {
+    final_length += expansion;
+    // Minor optimization: save this offset into |current_match|, so that on
+    // exit from the loop, |current_match| will point at the last instance of
+    // the find string, and we won't need to find() it again immediately.
+    current_match = offset;
+    offset = str->find(find_this, offset + find_length);
+  } while (offset != StringType::npos);
+  str->resize(final_length);
+
+  // Now do the replacement loop, working backwards through the string.
+  for (size_t prev_match = str_length, write_offset = final_length; ;
+       current_match = str->rfind(find_this, current_match - 1)) {
+    size_t read_offset = current_match + find_length;
+    size_t length = prev_match - read_offset;
+    if (length) {
+      write_offset -= length;
+      memmove(&(*str)[write_offset], &(*str)[read_offset],
+              length * sizeof(typename StringType::value_type));
+    }
+    write_offset -= replace_length;
+    str->replace(write_offset, replace_length, replace_with);
+    if (current_match == first_match)
+      return;
+    prev_match = current_match;
+  }
+}
+
+void ReplaceFirstSubstringAfterOffset(string16* str,
+                                      size_t start_offset,
+                                      const string16& find_this,
+                                      const string16& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 false);  // replace first instance
+}
+
+void ReplaceFirstSubstringAfterOffset(std::string* str,
+                                      size_t start_offset,
+                                      const std::string& find_this,
+                                      const std::string& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 false);  // replace first instance
+}
+
+void ReplaceSubstringsAfterOffset(string16* str,
+                                  size_t start_offset,
+                                  const string16& find_this,
+                                  const string16& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 true);  // replace all instances
+}
+
+void ReplaceSubstringsAfterOffset(std::string* str,
+                                  size_t start_offset,
+                                  const std::string& find_this,
+                                  const std::string& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 true);  // replace all instances
+}
+
+
+template<typename STR>
+static size_t TokenizeT(const STR& str,
+                        const STR& delimiters,
+                        std::vector<STR>* tokens) {
+  tokens->clear();
+
+  size_t start = str.find_first_not_of(delimiters);
+  while (start != STR::npos) {
+    size_t end = str.find_first_of(delimiters, start + 1);
+    if (end == STR::npos) {
+      tokens->push_back(str.substr(start));
+      break;
+    } else {
+      tokens->push_back(str.substr(start, end - start));
+      start = str.find_first_not_of(delimiters, end + 1);
+    }
+  }
+
+  return tokens->size();
+}
+
+size_t Tokenize(const string16& str,
+                const string16& delimiters,
+                std::vector<string16>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+
+size_t Tokenize(const std::string& str,
+                const std::string& delimiters,
+                std::vector<std::string>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+
+size_t Tokenize(const base::StringPiece& str,
+                const base::StringPiece& delimiters,
+                std::vector<base::StringPiece>* tokens) {
+  return TokenizeT(str, delimiters, tokens);
+}
+
+template<typename STR>
+static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
+  if (parts.empty())
+    return STR();
+
+  STR result(parts[0]);
+  typename std::vector<STR>::const_iterator iter = parts.begin();
+  ++iter;
+
+  for (; iter != parts.end(); ++iter) {
+    result += sep;
+    result += *iter;
+  }
+
+  return result;
+}
+
+std::string JoinString(const std::vector<std::string>& parts, char sep) {
+  return JoinStringT(parts, std::string(1, sep));
+}
+
+string16 JoinString(const std::vector<string16>& parts, char16 sep) {
+  return JoinStringT(parts, string16(1, sep));
+}
+
+std::string JoinString(const std::vector<std::string>& parts,
+                       const std::string& separator) {
+  return JoinStringT(parts, separator);
+}
+
+string16 JoinString(const std::vector<string16>& parts,
+                    const string16& separator) {
+  return JoinStringT(parts, separator);
+}
+
+template<class FormatStringType, class OutStringType>
+OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
+    const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
+  size_t substitutions = subst.size();
+
+  size_t sub_length = 0;
+  for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
+       iter != subst.end(); ++iter) {
+    sub_length += iter->length();
+  }
+
+  OutStringType formatted;
+  formatted.reserve(format_string.length() + sub_length);
+
+  std::vector<ReplacementOffset> r_offsets;
+  for (typename FormatStringType::const_iterator i = format_string.begin();
+       i != format_string.end(); ++i) {
+    if ('$' == *i) {
+      if (i + 1 != format_string.end()) {
+        ++i;
+        DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
+        if ('$' == *i) {
+          while (i != format_string.end() && '$' == *i) {
+            formatted.push_back('$');
+            ++i;
+          }
+          --i;
+        } else {
+          uintptr_t index = 0;
+          while (i != format_string.end() && '0' <= *i && *i <= '9') {
+            index *= 10;
+            index += *i - '0';
+            ++i;
+          }
+          --i;
+          index -= 1;
+          if (offsets) {
+            ReplacementOffset r_offset(index,
+                static_cast<int>(formatted.size()));
+            r_offsets.insert(std::lower_bound(r_offsets.begin(),
+                                              r_offsets.end(),
+                                              r_offset,
+                                              &CompareParameter),
+                             r_offset);
+          }
+          if (index < substitutions)
+            formatted.append(subst.at(index));
+        }
+      }
+    } else {
+      formatted.push_back(*i);
+    }
+  }
+  if (offsets) {
+    for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
+         i != r_offsets.end(); ++i) {
+      offsets->push_back(i->offset);
+    }
+  }
+  return formatted;
+}
+
+string16 ReplaceStringPlaceholders(const string16& format_string,
+                                   const std::vector<string16>& subst,
+                                   std::vector<size_t>* offsets) {
+  return DoReplaceStringPlaceholders(format_string, subst, offsets);
+}
+
+std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
+                                      const std::vector<std::string>& subst,
+                                      std::vector<size_t>* offsets) {
+  return DoReplaceStringPlaceholders(format_string, subst, offsets);
+}
+
+string16 ReplaceStringPlaceholders(const string16& format_string,
+                                   const string16& a,
+                                   size_t* offset) {
+  std::vector<size_t> offsets;
+  std::vector<string16> subst;
+  subst.push_back(a);
+  string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets);
+
+  DCHECK_EQ(1U, offsets.size());
+  if (offset)
+    *offset = offsets[0];
+  return result;
+}
+
+static bool IsWildcard(base_icu::UChar32 character) {
+  return character == '*' || character == '?';
+}
+
+// Move the strings pointers to the point where they start to differ.
+template <typename CHAR, typename NEXT>
+static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
+                         const CHAR** string, const CHAR* string_end,
+                         NEXT next) {
+  const CHAR* escape = NULL;
+  while (*pattern != pattern_end && *string != string_end) {
+    if (!escape && IsWildcard(**pattern)) {
+      // We don't want to match wildcard here, except if it's escaped.
+      return;
+    }
+
+    // Check if the escapement char is found. If so, skip it and move to the
+    // next character.
+    if (!escape && **pattern == '\\') {
+      escape = *pattern;
+      next(pattern, pattern_end);
+      continue;
+    }
+
+    // Check if the chars match, if so, increment the ptrs.
+    const CHAR* pattern_next = *pattern;
+    const CHAR* string_next = *string;
+    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+    if (pattern_char == next(&string_next, string_end) &&
+        pattern_char != CBU_SENTINEL) {
+      *pattern = pattern_next;
+      *string = string_next;
+    } else {
+      // Uh oh, it did not match, we are done. If the last char was an
+      // escapement, that means that it was an error to advance the ptr here,
+      // let's put it back where it was. This also mean that the MatchPattern
+      // function will return false because if we can't match an escape char
+      // here, then no one will.
+      if (escape) {
+        *pattern = escape;
+      }
+      return;
+    }
+
+    escape = NULL;
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+  while (*pattern != end) {
+    if (!IsWildcard(**pattern))
+      return;
+    next(pattern, end);
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
+                          const CHAR* pattern, const CHAR* pattern_end,
+                          int depth,
+                          NEXT next) {
+  const int kMaxDepth = 16;
+  if (depth > kMaxDepth)
+    return false;
+
+  // Eat all the matching chars.
+  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
+
+  // If the string is empty, then the pattern must be empty too, or contains
+  // only wildcards.
+  if (eval == eval_end) {
+    EatWildcard(&pattern, pattern_end, next);
+    return pattern == pattern_end;
+  }
+
+  // Pattern is empty but not string, this is not a match.
+  if (pattern == pattern_end)
+    return false;
+
+  // If this is a question mark, then we need to compare the rest with
+  // the current string or the string with one character eaten.
+  const CHAR* next_pattern = pattern;
+  next(&next_pattern, pattern_end);
+  if (pattern[0] == '?') {
+    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+    const CHAR* next_eval = eval;
+    next(&next_eval, eval_end);
+    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+  }
+
+  // This is a *, try to match all the possible substrings with the remainder
+  // of the pattern.
+  if (pattern[0] == '*') {
+    // Collapse duplicate wild cards (********** into *) so that the
+    // method does not recurse unnecessarily. http://crbug.com/52839
+    EatWildcard(&next_pattern, pattern_end, next);
+
+    while (eval != eval_end) {
+      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                        depth + 1, next))
+        return true;
+      eval++;
+    }
+
+    // We reached the end of the string, let see if the pattern contains only
+    // wildcards.
+    if (eval == eval_end) {
+      EatWildcard(&pattern, pattern_end, next);
+      if (pattern != pattern_end)
+        return false;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+struct NextCharUTF8 {
+  base_icu::UChar32 operator()(const char** p, const char* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU8_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+struct NextCharUTF16 {
+  base_icu::UChar32 operator()(const char16** p, const char16* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU16_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+bool MatchPattern(const base::StringPiece& eval,
+                  const base::StringPiece& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF8());
+}
+
+bool MatchPattern(const string16& eval, const string16& pattern) {
+  return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
+                       pattern.c_str(), pattern.c_str() + pattern.size(),
+                       0, NextCharUTF16());
+}
+
+// The following code is compatible with the OpenBSD lcpy interface.  See:
+//   http://www.gratisoft.us/todd/papers/strlcpy.html
+//   ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
+
+namespace {
+
+template <typename CHAR>
+size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
+  for (size_t i = 0; i < dst_size; ++i) {
+    if ((dst[i] = src[i]) == 0)  // We hit and copied the terminating NULL.
+      return i;
+  }
+
+  // We were left off at dst_size.  We over copied 1 byte.  Null terminate.
+  if (dst_size != 0)
+    dst[dst_size - 1] = 0;
+
+  // Count the rest of the |src|, and return it's length in characters.
+  while (src[dst_size]) ++dst_size;
+  return dst_size;
+}
+
+}  // namespace
+
+size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+  return lcpyT<char>(dst, src, dst_size);
+}
+size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+  return lcpyT<wchar_t>(dst, src, dst_size);
+}
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
new file mode 100644
index 0000000..5ab2ad5
--- /dev/null
+++ b/base/strings/string_util.h
@@ -0,0 +1,532 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file defines utility functions for working with strings.
+
+#ifndef BASE_STRINGS_STRING_UTIL_H_
+#define BASE_STRINGS_STRING_UTIL_H_
+
+#include <ctype.h>
+#include <stdarg.h>   // va_list
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"  // For implicit conversions.
+
+namespace base {
+
+// C standard-library functions like "strncasecmp" and "snprintf" that aren't
+// cross-platform are provided as "base::strncasecmp", and their prototypes
+// are listed below.  These functions are then implemented as inline calls
+// to the platform-specific equivalents in the platform-specific headers.
+
+// Compares the two strings s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strcasecmp(const char* s1, const char* s2);
+
+// Compares up to count characters of s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strncasecmp(const char* s1, const char* s2, size_t count);
+
+// Same as strncmp but for char16 strings.
+int strncmp16(const char16* s1, const char16* s2, size_t count);
+
+// Wrapper for vsnprintf that always null-terminates and always returns the
+// number of characters that would be in an untruncated formatted
+// string, even when truncation occurs.
+int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
+    PRINTF_FORMAT(3, 0);
+
+// Some of these implementations need to be inlined.
+
+// We separate the declaration from the implementation of this inline
+// function just so the PRINTF_FORMAT works.
+inline int snprintf(char* buffer, size_t size, const char* format, ...)
+    PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer, size_t size, const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  int result = vsnprintf(buffer, size, format, arguments);
+  va_end(arguments);
+  return result;
+}
+
+// BSD-style safe and consistent string copy functions.
+// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
+// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
+// long as |dst_size| is not 0.  Returns the length of |src| in characters.
+// If the return value is >= dst_size, then the output was truncated.
+// NOTE: All sizes are in number of characters, NOT in bytes.
+BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size);
+BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
+
+// Scan a wprintf format string to determine whether it's portable across a
+// variety of systems.  This function only checks that the conversion
+// specifiers used by the format string are supported and have the same meaning
+// on a variety of systems.  It doesn't check for other errors that might occur
+// within a format string.
+//
+// Nonportable conversion specifiers for wprintf are:
+//  - 's' and 'c' without an 'l' length modifier.  %s and %c operate on char
+//     data on all systems except Windows, which treat them as wchar_t data.
+//     Use %ls and %lc for wchar_t data instead.
+//  - 'S' and 'C', which operate on wchar_t data on all systems except Windows,
+//     which treat them as char data.  Use %ls and %lc for wchar_t data
+//     instead.
+//  - 'F', which is not identified by Windows wprintf documentation.
+//  - 'D', 'O', and 'U', which are deprecated and not available on all systems.
+//     Use %ld, %lo, and %lu instead.
+//
+// Note that there is no portable conversion specifier for char data when
+// working with wprintf.
+//
+// This function is intended to be called from base::vswprintf.
+BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format);
+
+// ASCII-specific tolower.  The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToLowerASCII(Char c) {
+  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+
+// ASCII-specific toupper.  The standard library's toupper is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToUpperASCII(Char c) {
+  return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+
+// Function objects to aid in comparing/searching strings.
+
+template<typename Char> struct CaseInsensitiveCompare {
+ public:
+  bool operator()(Char x, Char y) const {
+    // TODO(darin): Do we really want to do locale sensitive comparisons here?
+    // See http://crbug.com/24917
+    return tolower(x) == tolower(y);
+  }
+};
+
+template<typename Char> struct CaseInsensitiveCompareASCII {
+ public:
+  bool operator()(Char x, Char y) const {
+    return ToLowerASCII(x) == ToLowerASCII(y);
+  }
+};
+
+// These threadsafe functions return references to globally unique empty
+// strings.
+//
+// It is likely faster to construct a new empty string object (just a few
+// instructions to set the length to 0) than to get the empty string singleton
+// returned by these functions (which requires threadsafe singleton access).
+//
+// Therefore, DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT
+// CONSTRUCTORS. There is only one case where you should use these: functions
+// which need to return a string by reference (e.g. as a class member
+// accessor), and don't have an empty string to use (e.g. in an error case).
+// These should not be used as initializers, function arguments, or return
+// values for functions which return by value or outparam.
+BASE_EXPORT const std::string& EmptyString();
+BASE_EXPORT const string16& EmptyString16();
+
+// Contains the set of characters representing whitespace in the corresponding
+// encoding. Null-terminated.
+BASE_EXPORT extern const wchar_t kWhitespaceWide[];
+BASE_EXPORT extern const char16 kWhitespaceUTF16[];
+BASE_EXPORT extern const char kWhitespaceASCII[];
+
+// Null-terminated string representing the UTF-8 byte order mark.
+BASE_EXPORT extern const char kUtf8ByteOrderMark[];
+
+// Removes characters in |remove_chars| from anywhere in |input|.  Returns true
+// if any characters were removed.  |remove_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool RemoveChars(const string16& input,
+                             const base::StringPiece16& remove_chars,
+                             string16* output);
+BASE_EXPORT bool RemoveChars(const std::string& input,
+                             const base::StringPiece& remove_chars,
+                             std::string* output);
+
+// Replaces characters in |replace_chars| from anywhere in |input| with
+// |replace_with|.  Each character in |replace_chars| will be replaced with
+// the |replace_with| string.  Returns true if any characters were replaced.
+// |replace_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool ReplaceChars(const string16& input,
+                              const base::StringPiece16& replace_chars,
+                              const string16& replace_with,
+                              string16* output);
+BASE_EXPORT bool ReplaceChars(const std::string& input,
+                              const base::StringPiece& replace_chars,
+                              const std::string& replace_with,
+                              std::string* output);
+
+// Removes characters in |trim_chars| from the beginning and end of |input|.
+// |trim_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool TrimString(const string16& input,
+                            const base::StringPiece16& trim_chars,
+                            string16* output);
+BASE_EXPORT bool TrimString(const std::string& input,
+                            const base::StringPiece& trim_chars,
+                            std::string* output);
+
+// Truncates a string to the nearest UTF-8 character that will leave
+// the string less than or equal to the specified byte size.
+BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
+                                        const size_t byte_size,
+                                        std::string* output);
+
+// Trims any whitespace from either end of the input string.  Returns where
+// whitespace was found.
+// The non-wide version has two functions:
+// * TrimWhitespaceASCII()
+//   This function is for ASCII strings and only looks for ASCII whitespace;
+// Please choose the best one according to your usage.
+// NOTE: Safe to use the same variable for both input and output.
+enum TrimPositions {
+  TRIM_NONE     = 0,
+  TRIM_LEADING  = 1 << 0,
+  TRIM_TRAILING = 1 << 1,
+  TRIM_ALL      = TRIM_LEADING | TRIM_TRAILING,
+};
+BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
+                                         TrimPositions positions,
+                                         base::string16* output);
+BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                              TrimPositions positions,
+                                              std::string* output);
+
+// Deprecated. This function is only for backward compatibility and calls
+// TrimWhitespaceASCII().
+BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
+                                         TrimPositions positions,
+                                         std::string* output);
+
+// Searches  for CR or LF characters.  Removes all contiguous whitespace
+// strings that contain them.  This is useful when trying to deal with text
+// copied from terminals.
+// Returns |text|, with the following three transformations:
+// (1) Leading and trailing whitespace is trimmed.
+// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
+//     sequences containing a CR or LF are trimmed.
+// (3) All other whitespace sequences are converted to single spaces.
+BASE_EXPORT string16 CollapseWhitespace(
+    const string16& text,
+    bool trim_sequences_with_line_breaks);
+BASE_EXPORT std::string CollapseWhitespaceASCII(
+    const std::string& text,
+    bool trim_sequences_with_line_breaks);
+
+// Returns true if |input| is empty or contains only characters found in
+// |characters|.
+BASE_EXPORT bool ContainsOnlyChars(const StringPiece& input,
+                                   const StringPiece& characters);
+BASE_EXPORT bool ContainsOnlyChars(const StringPiece16& input,
+                                   const StringPiece16& characters);
+
+// Returns true if the specified string matches the criteria. How can a wide
+// string be 8-bit or UTF8? It contains only characters that are < 256 (in the
+// first case) or characters that use only 8-bits and whose 8-bit
+// representation looks like a UTF-8 string (the second case).
+//
+// Note that IsStringUTF8 checks not only if the input is structurally
+// valid but also if it doesn't contain any non-character codepoint
+// (e.g. U+FFFE). It's done on purpose because all the existing callers want
+// to have the maximum 'discriminating' power from other encodings. If
+// there's a use case for just checking the structural validity, we have to
+// add a new function for that.
+//
+// IsStringASCII assumes the input is likely all ASCII, and does not leave early
+// if it is not the case.
+BASE_EXPORT bool IsStringUTF8(const StringPiece& str);
+BASE_EXPORT bool IsStringASCII(const StringPiece& str);
+BASE_EXPORT bool IsStringASCII(const StringPiece16& str);
+// A convenience adaptor for WebStrings, as they don't convert into
+// StringPieces directly.
+BASE_EXPORT bool IsStringASCII(const string16& str);
+#if defined(WCHAR_T_IS_UTF32)
+BASE_EXPORT bool IsStringASCII(const std::wstring& str);
+#endif
+
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToLowerASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = ToLowerASCII(*i);
+}
+
+template <class str> inline str StringToLowerASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToLowerASCII(&output);
+  return output;
+}
+
+}  // namespace base
+
+#if defined(OS_WIN)
+#include "base/strings/string_util_win.h"
+#elif defined(OS_POSIX)
+#include "base/strings/string_util_posix.h"
+#else
+#error Define string operations appropriately for your platform
+#endif
+
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToUpperASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = base::ToUpperASCII(*i);
+}
+
+template <class str> inline str StringToUpperASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToUpperASCII(&output);
+  return output;
+}
+
+// Compare the lower-case form of the given string against the given ASCII
+// string.  This is useful for doing checking if an input string matches some
+// token, and it is optimized to avoid intermediate string copies.  This API is
+// borrowed from the equivalent APIs in Mozilla.
+BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const base::string16& a, const char* b);
+
+// Same thing, but with string iterators instead.
+BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                                      std::string::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(base::string16::const_iterator a_begin,
+                                      base::string16::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                      const char* a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const base::char16* a_begin,
+                                      const base::char16* a_end,
+                                      const char* b);
+
+// Performs a case-sensitive string compare. The behavior is undefined if both
+// strings are not ASCII.
+BASE_EXPORT bool EqualsASCII(const base::string16& a, const base::StringPiece& b);
+
+// Returns true if str starts with search, or false otherwise.
+BASE_EXPORT bool StartsWithASCII(const std::string& str,
+                                 const std::string& search,
+                                 bool case_sensitive);
+BASE_EXPORT bool StartsWith(const base::string16& str,
+                            const base::string16& search,
+                            bool case_sensitive);
+
+// Returns true if str ends with search, or false otherwise.
+BASE_EXPORT bool EndsWith(const std::string& str,
+                          const std::string& search,
+                          bool case_sensitive);
+BASE_EXPORT bool EndsWith(const base::string16& str,
+                          const base::string16& search,
+                          bool case_sensitive);
+
+
+// Determines the type of ASCII character, independent of locale (the C
+// library versions will change based on locale).
+template <typename Char>
+inline bool IsAsciiWhitespace(Char c) {
+  return c == ' ' || c == '\r' || c == '\n' || c == '\t';
+}
+template <typename Char>
+inline bool IsAsciiAlpha(Char c) {
+  return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
+}
+template <typename Char>
+inline bool IsAsciiDigit(Char c) {
+  return c >= '0' && c <= '9';
+}
+
+template <typename Char>
+inline bool IsHexDigit(Char c) {
+  return (c >= '0' && c <= '9') ||
+         (c >= 'A' && c <= 'F') ||
+         (c >= 'a' && c <= 'f');
+}
+
+template <typename Char>
+inline char HexDigitToInt(Char c) {
+  DCHECK(IsHexDigit(c));
+  if (c >= '0' && c <= '9')
+    return static_cast<char>(c - '0');
+  if (c >= 'A' && c <= 'F')
+    return static_cast<char>(c - 'A' + 10);
+  if (c >= 'a' && c <= 'f')
+    return static_cast<char>(c - 'a' + 10);
+  return 0;
+}
+
+// Returns true if it's a whitespace character.
+inline bool IsWhitespace(wchar_t c) {
+  return wcschr(base::kWhitespaceWide, c) != NULL;
+}
+
+// Return a byte string in human-readable format with a unit suffix. Not
+// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
+// highly recommended instead. TODO(avi): Figure out how to get callers to use
+// FormatBytes instead; remove this.
+BASE_EXPORT base::string16 FormatBytesUnlocalized(int64 bytes);
+
+// Starting at |start_offset| (usually 0), replace the first instance of
+// |find_this| with |replace_with|.
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    base::string16* str,
+    size_t start_offset,
+    const base::string16& find_this,
+    const base::string16& replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    std::string* str,
+    size_t start_offset,
+    const std::string& find_this,
+    const std::string& replace_with);
+
+// Starting at |start_offset| (usually 0), look through |str| and replace all
+// instances of |find_this| with |replace_with|.
+//
+// This does entire substrings; use std::replace in <algorithm> for single
+// characters, for example:
+//   std::replace(str.begin(), str.end(), 'a', 'b');
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+    base::string16* str,
+    size_t start_offset,
+    const base::string16& find_this,
+    const base::string16& replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
+                                              size_t start_offset,
+                                              const std::string& find_this,
+                                              const std::string& replace_with);
+
+// Reserves enough memory in |str| to accommodate |length_with_null| characters,
+// sets the size of |str| to |length_with_null - 1| characters, and returns a
+// pointer to the underlying contiguous array of characters.  This is typically
+// used when calling a function that writes results into a character array, but
+// the caller wants the data to be managed by a string-like object.  It is
+// convenient in that is can be used inline in the call, and fast in that it
+// avoids copying the results of the call from a char* into a string.
+//
+// |length_with_null| must be at least 2, since otherwise the underlying string
+// would have size 0, and trying to access &((*str)[0]) in that case can result
+// in a number of problems.
+//
+// Internally, this takes linear time because the resize() call 0-fills the
+// underlying array for potentially all
+// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes.  Ideally we
+// could avoid this aspect of the resize() call, as we expect the caller to
+// immediately write over this memory, but there is no other way to set the size
+// of the string, and not doing that will mean people who access |str| rather
+// than str.c_str() will get back a string of whatever size |str| had on entry
+// to this function (probably 0).
+template <class string_type>
+inline typename string_type::value_type* WriteInto(string_type* str,
+                                                   size_t length_with_null) {
+  DCHECK_GT(length_with_null, 1u);
+  str->reserve(length_with_null);
+  str->resize(length_with_null - 1);
+  return &((*str)[0]);
+}
+
+//-----------------------------------------------------------------------------
+
+// Splits a string into its fields delimited by any of the characters in
+// |delimiters|.  Each field is added to the |tokens| vector.  Returns the
+// number of tokens found.
+BASE_EXPORT size_t Tokenize(const base::string16& str,
+                            const base::string16& delimiters,
+                            std::vector<base::string16>* tokens);
+BASE_EXPORT size_t Tokenize(const std::string& str,
+                            const std::string& delimiters,
+                            std::vector<std::string>* tokens);
+BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
+                            const base::StringPiece& delimiters,
+                            std::vector<base::StringPiece>* tokens);
+
+// Does the opposite of SplitString().
+BASE_EXPORT base::string16 JoinString(const std::vector<base::string16>& parts,
+                                      base::char16 s);
+BASE_EXPORT std::string JoinString(
+    const std::vector<std::string>& parts, char s);
+
+// Join |parts| using |separator|.
+BASE_EXPORT std::string JoinString(
+    const std::vector<std::string>& parts,
+    const std::string& separator);
+BASE_EXPORT base::string16 JoinString(
+    const std::vector<base::string16>& parts,
+    const base::string16& separator);
+
+// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
+// Additionally, any number of consecutive '$' characters is replaced by that
+// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
+// NULL. This only allows you to use up to nine replacements.
+BASE_EXPORT base::string16 ReplaceStringPlaceholders(
+    const base::string16& format_string,
+    const std::vector<base::string16>& subst,
+    std::vector<size_t>* offsets);
+
+BASE_EXPORT std::string ReplaceStringPlaceholders(
+    const base::StringPiece& format_string,
+    const std::vector<std::string>& subst,
+    std::vector<size_t>* offsets);
+
+// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
+BASE_EXPORT base::string16 ReplaceStringPlaceholders(
+    const base::string16& format_string,
+    const base::string16& a,
+    size_t* offset);
+
+// Returns true if the string passed in matches the pattern. The pattern
+// string can contain wildcards like * and ?
+// The backslash character (\) is an escape character for * and ?
+// We limit the patterns to having a max of 16 * or ? characters.
+// ? matches 0 or 1 character, while * matches 0 or more characters.
+BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
+                              const base::StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const base::string16& string,
+                              const base::string16& pattern);
+
+// Hack to convert any char-like type to its unsigned counterpart.
+// For example, it will convert char, signed char and unsigned char to unsigned
+// char.
+template<typename T>
+struct ToUnsigned {
+  typedef T Unsigned;
+};
+
+template<>
+struct ToUnsigned<char> {
+  typedef unsigned char Unsigned;
+};
+template<>
+struct ToUnsigned<signed char> {
+  typedef unsigned char Unsigned;
+};
+template<>
+struct ToUnsigned<wchar_t> {
+#if defined(WCHAR_T_IS_UTF16)
+  typedef unsigned short Unsigned;
+#elif defined(WCHAR_T_IS_UTF32)
+  typedef uint32 Unsigned;
+#endif
+};
+template<>
+struct ToUnsigned<short> {
+  typedef unsigned short Unsigned;
+};
+
+#endif  // BASE_STRINGS_STRING_UTIL_H_
diff --git a/base/strings/string_util_constants.cc b/base/strings/string_util_constants.cc
new file mode 100644
index 0000000..146e5fd
--- /dev/null
+++ b/base/strings/string_util_constants.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+namespace base {
+
+#define WHITESPACE_UNICODE \
+  0x0009, /* CHARACTER TABULATION */      \
+  0x000A, /* LINE FEED (LF) */            \
+  0x000B, /* LINE TABULATION */           \
+  0x000C, /* FORM FEED (FF) */            \
+  0x000D, /* CARRIAGE RETURN (CR) */      \
+  0x0020, /* SPACE */                     \
+  0x0085, /* NEXT LINE (NEL) */           \
+  0x00A0, /* NO-BREAK SPACE */            \
+  0x1680, /* OGHAM SPACE MARK */          \
+  0x2000, /* EN QUAD */                   \
+  0x2001, /* EM QUAD */                   \
+  0x2002, /* EN SPACE */                  \
+  0x2003, /* EM SPACE */                  \
+  0x2004, /* THREE-PER-EM SPACE */        \
+  0x2005, /* FOUR-PER-EM SPACE */         \
+  0x2006, /* SIX-PER-EM SPACE */          \
+  0x2007, /* FIGURE SPACE */              \
+  0x2008, /* PUNCTUATION SPACE */         \
+  0x2009, /* THIN SPACE */                \
+  0x200A, /* HAIR SPACE */                \
+  0x2028, /* LINE SEPARATOR */            \
+  0x2029, /* PARAGRAPH SEPARATOR */       \
+  0x202F, /* NARROW NO-BREAK SPACE */     \
+  0x205F, /* MEDIUM MATHEMATICAL SPACE */ \
+  0x3000, /* IDEOGRAPHIC SPACE */         \
+  0
+
+const wchar_t kWhitespaceWide[] = {
+  WHITESPACE_UNICODE
+};
+
+const char16 kWhitespaceUTF16[] = {
+  WHITESPACE_UNICODE
+};
+
+const char kWhitespaceASCII[] = {
+  0x09,    // CHARACTER TABULATION
+  0x0A,    // LINE FEED (LF)
+  0x0B,    // LINE TABULATION
+  0x0C,    // FORM FEED (FF)
+  0x0D,    // CARRIAGE RETURN (CR)
+  0x20,    // SPACE
+  0
+};
+
+const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
+
+}  // namespace base
diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h
new file mode 100644
index 0000000..f4009d4
--- /dev/null
+++ b/base/strings/string_util_posix.h
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_POSIX_H_
+#define BASE_STRINGS_STRING_UTIL_POSIX_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+  return ::strdup(str);
+}
+
+inline int strcasecmp(const char* string1, const char* string2) {
+  return ::strcasecmp(string1, string2);
+}
+
+inline int strncasecmp(const char* string1, const char* string2, size_t count) {
+  return ::strncasecmp(string1, string2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  return ::vsnprintf(buffer, size, format, arguments);
+}
+
+inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
+#if defined(WCHAR_T_IS_UTF16)
+  return ::wcsncmp(s1, s2, count);
+#elif defined(WCHAR_T_IS_UTF32)
+  return c16memcmp(s1, s2, count);
+#endif
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+                     const wchar_t* format, va_list arguments) {
+  DCHECK(IsWprintfFormatPortable(format));
+  return ::vswprintf(buffer, size, format, arguments);
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_UTIL_POSIX_H_
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
new file mode 100644
index 0000000..d887c0b
--- /dev/null
+++ b/base/strings/string_util_unittest.cc
@@ -0,0 +1,1235 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+#include <math.h>
+#include <stdarg.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+
+namespace base {
+
+static const struct trim_case {
+  const wchar_t* input;
+  const TrimPositions positions;
+  const wchar_t* output;
+  const TrimPositions return_value;
+} trim_cases[] = {
+  {L" Google Video ", TRIM_LEADING, L"Google Video ", TRIM_LEADING},
+  {L" Google Video ", TRIM_TRAILING, L" Google Video", TRIM_TRAILING},
+  {L" Google Video ", TRIM_ALL, L"Google Video", TRIM_ALL},
+  {L"Google Video", TRIM_ALL, L"Google Video", TRIM_NONE},
+  {L"", TRIM_ALL, L"", TRIM_NONE},
+  {L"  ", TRIM_LEADING, L"", TRIM_LEADING},
+  {L"  ", TRIM_TRAILING, L"", TRIM_TRAILING},
+  {L"  ", TRIM_ALL, L"", TRIM_ALL},
+  {L"\t\rTest String\n", TRIM_ALL, L"Test String", TRIM_ALL},
+  {L"\x2002Test String\x00A0\x3000", TRIM_ALL, L"Test String", TRIM_ALL},
+};
+
+static const struct trim_case_ascii {
+  const char* input;
+  const TrimPositions positions;
+  const char* output;
+  const TrimPositions return_value;
+} trim_cases_ascii[] = {
+  {" Google Video ", TRIM_LEADING, "Google Video ", TRIM_LEADING},
+  {" Google Video ", TRIM_TRAILING, " Google Video", TRIM_TRAILING},
+  {" Google Video ", TRIM_ALL, "Google Video", TRIM_ALL},
+  {"Google Video", TRIM_ALL, "Google Video", TRIM_NONE},
+  {"", TRIM_ALL, "", TRIM_NONE},
+  {"  ", TRIM_LEADING, "", TRIM_LEADING},
+  {"  ", TRIM_TRAILING, "", TRIM_TRAILING},
+  {"  ", TRIM_ALL, "", TRIM_ALL},
+  {"\t\rTest String\n", TRIM_ALL, "Test String", TRIM_ALL},
+};
+
+namespace {
+
+// Helper used to test TruncateUTF8ToByteSize.
+bool Truncated(const std::string& input,
+               const size_t byte_size,
+               std::string* output) {
+    size_t prev = input.length();
+    TruncateUTF8ToByteSize(input, byte_size, output);
+    return prev != output->length();
+}
+
+}  // namespace
+
+TEST(StringUtilTest, TruncateUTF8ToByteSize) {
+  std::string output;
+
+  // Empty strings and invalid byte_size arguments
+  EXPECT_FALSE(Truncated(std::string(), 0, &output));
+  EXPECT_EQ(output, "");
+  EXPECT_TRUE(Truncated("\xe1\x80\xbf", 0, &output));
+  EXPECT_EQ(output, "");
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", static_cast<size_t>(-1), &output));
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", 4, &output));
+
+  // Testing the truncation of valid UTF8 correctly
+  EXPECT_TRUE(Truncated("abc", 2, &output));
+  EXPECT_EQ(output, "ab");
+  EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 2, &output));
+  EXPECT_EQ(output.compare("\xc2\x81"), 0);
+  EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 3, &output));
+  EXPECT_EQ(output.compare("\xc2\x81"), 0);
+  EXPECT_FALSE(Truncated("\xc2\x81\xc2\x81", 4, &output));
+  EXPECT_EQ(output.compare("\xc2\x81\xc2\x81"), 0);
+
+  {
+    const char array[] = "\x00\x00\xc2\x81\xc2\x81";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\x00\xc2\x81", 4)), 0);
+  }
+
+  {
+    const char array[] = "\x00\xc2\x81\xc2\x81";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\xc2\x81", 3)), 0);
+  }
+
+  // Testing invalid UTF8
+  EXPECT_TRUE(Truncated("\xed\xa0\x80\xed\xbf\xbf", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xed\xa0\x8f", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xed\xbf\xbf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Testing invalid UTF8 mixed with valid UTF8
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", 3, &output));
+  EXPECT_EQ(output.compare("\xe1\x80\xbf"), 0);
+  EXPECT_FALSE(Truncated("\xf1\x80\xa0\xbf", 4, &output));
+  EXPECT_EQ(output.compare("\xf1\x80\xa0\xbf"), 0);
+  EXPECT_FALSE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf",
+              10, &output));
+  EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"), 0);
+  EXPECT_TRUE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1""a""\x80\xa0",
+              10, &output));
+  EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1""a"), 0);
+  EXPECT_FALSE(Truncated("\xef\xbb\xbf" "abc", 6, &output));
+  EXPECT_EQ(output.compare("\xef\xbb\xbf" "abc"), 0);
+
+  // Overlong sequences
+  EXPECT_TRUE(Truncated("\xc0\x80", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xc1\x80\xc1\x81", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x80\x80", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x82\x80", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x9f\xbf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\x80\x8D", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\x82\x91", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\xa0\x80", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x8f\xbb\xbf", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf8\x80\x80\x80\xbf", 5, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xfc\x80\x80\x80\xa0\xa5", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Beyond U+10FFFF (the upper limit of Unicode codespace)
+  EXPECT_TRUE(Truncated("\xf4\x90\x80\x80", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf8\xa0\xbf\x80\xbf", 5, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xfc\x9c\xbf\x80\xbf\x80", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE)
+  EXPECT_TRUE(Truncated("\xfe\xff", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xff\xfe", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  {
+    const char array[] = "\x00\x00\xfe\xff";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\x00", 2)), 0);
+  }
+
+  // Variants on the previous test
+  {
+    const char array[] = "\xff\xfe\x00\x00";
+    const std::string array_string(array, 4);
+    EXPECT_FALSE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\xff\xfe\x00\x00", 4)), 0);
+  }
+  {
+    const char array[] = "\xff\x00\x00\xfe";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\xff\x00\x00", 3)), 0);
+  }
+
+  // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF>
+  EXPECT_TRUE(Truncated("\xef\xbf\xbe", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x8f\xbf\xbe", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf3\xbf\xbf\xbf", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xef\xb7\x90", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xef\xb7\xaf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Strings in legacy encodings that are valid in UTF-8, but
+  // are invalid as UTF-8 in real data.
+  EXPECT_TRUE(Truncated("caf\xe9", 4, &output));
+  EXPECT_EQ(output.compare("caf"), 0);
+  EXPECT_TRUE(Truncated("\xb0\xa1\xb0\xa2", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_FALSE(Truncated("\xa7\x41\xa6\x6e", 4, &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+  EXPECT_TRUE(Truncated("\xa7\x41\xa6\x6e\xd9\xee\xe4\xee", 7,
+              &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+
+  // Testing using the same string as input and output.
+  EXPECT_FALSE(Truncated(output, 4, &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+  EXPECT_TRUE(Truncated(output, 3, &output));
+  EXPECT_EQ(output.compare("\xa7\x41"), 0);
+
+  // "abc" with U+201[CD] in windows-125[0-8]
+  EXPECT_TRUE(Truncated("\x93" "abc\x94", 5, &output));
+  EXPECT_EQ(output.compare("\x93" "abc"), 0);
+
+  // U+0639 U+064E U+0644 U+064E in ISO-8859-6
+  EXPECT_TRUE(Truncated("\xd9\xee\xe4\xee", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7
+  EXPECT_TRUE(Truncated("\xe3\xe5\xe9\xdC", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+}
+
+TEST(StringUtilTest, TrimWhitespace) {
+  string16 output;  // Allow contents to carry over to next testcase
+  for (size_t i = 0; i < arraysize(trim_cases); ++i) {
+    const trim_case& value = trim_cases[i];
+    EXPECT_EQ(value.return_value,
+              TrimWhitespace(WideToUTF16(value.input), value.positions,
+                             &output));
+    EXPECT_EQ(WideToUTF16(value.output), output);
+  }
+
+  // Test that TrimWhitespace() can take the same string for input and output
+  output = ASCIIToUTF16("  This is a test \r\n");
+  EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output));
+  EXPECT_EQ(ASCIIToUTF16("This is a test"), output);
+
+  // Once more, but with a string of whitespace
+  output = ASCIIToUTF16("  \r\n");
+  EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output));
+  EXPECT_EQ(string16(), output);
+
+  std::string output_ascii;
+  for (size_t i = 0; i < arraysize(trim_cases_ascii); ++i) {
+    const trim_case_ascii& value = trim_cases_ascii[i];
+    EXPECT_EQ(value.return_value,
+              TrimWhitespace(value.input, value.positions, &output_ascii));
+    EXPECT_EQ(value.output, output_ascii);
+  }
+}
+
+static const struct collapse_case {
+  const wchar_t* input;
+  const bool trim;
+  const wchar_t* output;
+} collapse_cases[] = {
+  {L" Google Video ", false, L"Google Video"},
+  {L"Google Video", false, L"Google Video"},
+  {L"", false, L""},
+  {L"  ", false, L""},
+  {L"\t\rTest String\n", false, L"Test String"},
+  {L"\x2002Test String\x00A0\x3000", false, L"Test String"},
+  {L"    Test     \n  \t String    ", false, L"Test String"},
+  {L"\x2002Test\x1680 \x2028 \tString\x00A0\x3000", false, L"Test String"},
+  {L"   Test String", false, L"Test String"},
+  {L"Test String    ", false, L"Test String"},
+  {L"Test String", false, L"Test String"},
+  {L"", true, L""},
+  {L"\n", true, L""},
+  {L"  \r  ", true, L""},
+  {L"\nFoo", true, L"Foo"},
+  {L"\r  Foo  ", true, L"Foo"},
+  {L" Foo bar ", true, L"Foo bar"},
+  {L"  \tFoo  bar  \n", true, L"Foo bar"},
+  {L" a \r b\n c \r\n d \t\re \t f \n ", true, L"abcde f"},
+};
+
+TEST(StringUtilTest, CollapseWhitespace) {
+  for (size_t i = 0; i < arraysize(collapse_cases); ++i) {
+    const collapse_case& value = collapse_cases[i];
+    EXPECT_EQ(WideToUTF16(value.output),
+              CollapseWhitespace(WideToUTF16(value.input), value.trim));
+  }
+}
+
+static const struct collapse_case_ascii {
+  const char* input;
+  const bool trim;
+  const char* output;
+} collapse_cases_ascii[] = {
+  {" Google Video ", false, "Google Video"},
+  {"Google Video", false, "Google Video"},
+  {"", false, ""},
+  {"  ", false, ""},
+  {"\t\rTest String\n", false, "Test String"},
+  {"    Test     \n  \t String    ", false, "Test String"},
+  {"   Test String", false, "Test String"},
+  {"Test String    ", false, "Test String"},
+  {"Test String", false, "Test String"},
+  {"", true, ""},
+  {"\n", true, ""},
+  {"  \r  ", true, ""},
+  {"\nFoo", true, "Foo"},
+  {"\r  Foo  ", true, "Foo"},
+  {" Foo bar ", true, "Foo bar"},
+  {"  \tFoo  bar  \n", true, "Foo bar"},
+  {" a \r b\n c \r\n d \t\re \t f \n ", true, "abcde f"},
+};
+
+TEST(StringUtilTest, CollapseWhitespaceASCII) {
+  for (size_t i = 0; i < arraysize(collapse_cases_ascii); ++i) {
+    const collapse_case_ascii& value = collapse_cases_ascii[i];
+    EXPECT_EQ(value.output, CollapseWhitespaceASCII(value.input, value.trim));
+  }
+}
+
+TEST(StringUtilTest, IsStringUTF8) {
+  EXPECT_TRUE(IsStringUTF8("abc"));
+  EXPECT_TRUE(IsStringUTF8("\xc2\x81"));
+  EXPECT_TRUE(IsStringUTF8("\xe1\x80\xbf"));
+  EXPECT_TRUE(IsStringUTF8("\xf1\x80\xa0\xbf"));
+  EXPECT_TRUE(IsStringUTF8("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"));
+  EXPECT_TRUE(IsStringUTF8("\xef\xbb\xbf" "abc"));  // UTF-8 BOM
+
+  // surrogate code points
+  EXPECT_FALSE(IsStringUTF8("\xed\xa0\x80\xed\xbf\xbf"));
+  EXPECT_FALSE(IsStringUTF8("\xed\xa0\x8f"));
+  EXPECT_FALSE(IsStringUTF8("\xed\xbf\xbf"));
+
+  // overlong sequences
+  EXPECT_FALSE(IsStringUTF8("\xc0\x80"));  // U+0000
+  EXPECT_FALSE(IsStringUTF8("\xc1\x80\xc1\x81"));  // "AB"
+  EXPECT_FALSE(IsStringUTF8("\xe0\x80\x80"));  // U+0000
+  EXPECT_FALSE(IsStringUTF8("\xe0\x82\x80"));  // U+0080
+  EXPECT_FALSE(IsStringUTF8("\xe0\x9f\xbf"));  // U+07ff
+  EXPECT_FALSE(IsStringUTF8("\xf0\x80\x80\x8D"));  // U+000D
+  EXPECT_FALSE(IsStringUTF8("\xf0\x80\x82\x91"));  // U+0091
+  EXPECT_FALSE(IsStringUTF8("\xf0\x80\xa0\x80"));  // U+0800
+  EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbb\xbf"));  // U+FEFF (BOM)
+  EXPECT_FALSE(IsStringUTF8("\xf8\x80\x80\x80\xbf"));  // U+003F
+  EXPECT_FALSE(IsStringUTF8("\xfc\x80\x80\x80\xa0\xa5"));  // U+00A5
+
+  // Beyond U+10FFFF (the upper limit of Unicode codespace)
+  EXPECT_FALSE(IsStringUTF8("\xf4\x90\x80\x80"));  // U+110000
+  EXPECT_FALSE(IsStringUTF8("\xf8\xa0\xbf\x80\xbf"));  // 5 bytes
+  EXPECT_FALSE(IsStringUTF8("\xfc\x9c\xbf\x80\xbf\x80"));  // 6 bytes
+
+  // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE)
+  EXPECT_FALSE(IsStringUTF8("\xfe\xff"));
+  EXPECT_FALSE(IsStringUTF8("\xff\xfe"));
+  EXPECT_FALSE(IsStringUTF8(std::string("\x00\x00\xfe\xff", 4)));
+  EXPECT_FALSE(IsStringUTF8("\xff\xfe\x00\x00"));
+
+  // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF>
+  EXPECT_FALSE(IsStringUTF8("\xef\xbf\xbe"));  // U+FFFE)
+  EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbf\xbe"));  // U+1FFFE
+  EXPECT_FALSE(IsStringUTF8("\xf3\xbf\xbf\xbf"));  // U+10FFFF
+  EXPECT_FALSE(IsStringUTF8("\xef\xb7\x90"));  // U+FDD0
+  EXPECT_FALSE(IsStringUTF8("\xef\xb7\xaf"));  // U+FDEF
+  // Strings in legacy encodings. We can certainly make up strings
+  // in a legacy encoding that are valid in UTF-8, but in real data,
+  // most of them are invalid as UTF-8.
+  EXPECT_FALSE(IsStringUTF8("caf\xe9"));  // cafe with U+00E9 in ISO-8859-1
+  EXPECT_FALSE(IsStringUTF8("\xb0\xa1\xb0\xa2"));  // U+AC00, U+AC001 in EUC-KR
+  EXPECT_FALSE(IsStringUTF8("\xa7\x41\xa6\x6e"));  // U+4F60 U+597D in Big5
+  // "abc" with U+201[CD] in windows-125[0-8]
+  EXPECT_FALSE(IsStringUTF8("\x93" "abc\x94"));
+  // U+0639 U+064E U+0644 U+064E in ISO-8859-6
+  EXPECT_FALSE(IsStringUTF8("\xd9\xee\xe4\xee"));
+  // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7
+  EXPECT_FALSE(IsStringUTF8("\xe3\xe5\xe9\xdC"));
+
+  // Check that we support Embedded Nulls. The first uses the canonical UTF-8
+  // representation, and the second uses a 2-byte sequence. The second version
+  // is invalid UTF-8 since UTF-8 states that the shortest encoding for a
+  // given codepoint must be used.
+  static const char kEmbeddedNull[] = "embedded\0null";
+  EXPECT_TRUE(IsStringUTF8(
+      std::string(kEmbeddedNull, sizeof(kEmbeddedNull))));
+  EXPECT_FALSE(IsStringUTF8("embedded\xc0\x80U+0000"));
+}
+
+TEST(StringUtilTest, IsStringASCII) {
+  static char char_ascii[] =
+      "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
+  static char16 char16_ascii[] = {
+      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A',
+      'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6',
+      '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 0 };
+  static std::wstring wchar_ascii(
+      L"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF");
+
+  // Test a variety of the fragment start positions and lengths in order to make
+  // sure that bit masking in IsStringASCII works correctly.
+  // Also, test that a non-ASCII character will be detected regardless of its
+  // position inside the string.
+  {
+    const size_t string_length = arraysize(char_ascii) - 1;
+    for (size_t offset = 0; offset < 8; ++offset) {
+      for (size_t len = 0, max_len = string_length - offset; len < max_len;
+           ++len) {
+        EXPECT_TRUE(IsStringASCII(StringPiece(char_ascii + offset, len)));
+        for (size_t char_pos = offset; char_pos < len; ++char_pos) {
+          char_ascii[char_pos] |= '\x80';
+          EXPECT_FALSE(IsStringASCII(StringPiece(char_ascii + offset, len)));
+          char_ascii[char_pos] &= ~'\x80';
+        }
+      }
+    }
+  }
+
+  {
+    const size_t string_length = arraysize(char16_ascii) - 1;
+    for (size_t offset = 0; offset < 4; ++offset) {
+      for (size_t len = 0, max_len = string_length - offset; len < max_len;
+           ++len) {
+        EXPECT_TRUE(IsStringASCII(StringPiece16(char16_ascii + offset, len)));
+        for (size_t char_pos = offset; char_pos < len; ++char_pos) {
+          char16_ascii[char_pos] |= 0x80;
+          EXPECT_FALSE(
+              IsStringASCII(StringPiece16(char16_ascii + offset, len)));
+          char16_ascii[char_pos] &= ~0x80;
+          // Also test when the upper half is non-zero.
+          char16_ascii[char_pos] |= 0x100;
+          EXPECT_FALSE(
+              IsStringASCII(StringPiece16(char16_ascii + offset, len)));
+          char16_ascii[char_pos] &= ~0x100;
+        }
+      }
+    }
+  }
+
+  {
+    const size_t string_length = wchar_ascii.length();
+    for (size_t len = 0; len < string_length; ++len) {
+      EXPECT_TRUE(IsStringASCII(wchar_ascii.substr(0, len)));
+      for (size_t char_pos = 0; char_pos < len; ++char_pos) {
+        wchar_ascii[char_pos] |= 0x80;
+        EXPECT_FALSE(
+            IsStringASCII(wchar_ascii.substr(0, len)));
+        wchar_ascii[char_pos] &= ~0x80;
+        wchar_ascii[char_pos] |= 0x100;
+        EXPECT_FALSE(
+            IsStringASCII(wchar_ascii.substr(0, len)));
+        wchar_ascii[char_pos] &= ~0x100;
+#if defined(WCHAR_T_IS_UTF32)
+        wchar_ascii[char_pos] |= 0x10000;
+        EXPECT_FALSE(
+            IsStringASCII(wchar_ascii.substr(0, len)));
+        wchar_ascii[char_pos] &= ~0x10000;
+#endif  // WCHAR_T_IS_UTF32
+      }
+    }
+  }
+}
+
+TEST(StringUtilTest, ConvertASCII) {
+  static const char* const char_cases[] = {
+    "Google Video",
+    "Hello, world\n",
+    "0123ABCDwxyz \a\b\t\r\n!+,.~"
+  };
+
+  static const wchar_t* const wchar_cases[] = {
+    L"Google Video",
+    L"Hello, world\n",
+    L"0123ABCDwxyz \a\b\t\r\n!+,.~"
+  };
+
+  for (size_t i = 0; i < arraysize(char_cases); ++i) {
+    EXPECT_TRUE(IsStringASCII(char_cases[i]));
+    string16 utf16 = ASCIIToUTF16(char_cases[i]);
+    EXPECT_EQ(WideToUTF16(wchar_cases[i]), utf16);
+
+    std::string ascii = UTF16ToASCII(WideToUTF16(wchar_cases[i]));
+    EXPECT_EQ(char_cases[i], ascii);
+  }
+
+  EXPECT_FALSE(IsStringASCII("Google \x80Video"));
+
+  // Convert empty strings.
+  string16 empty16;
+  std::string empty;
+  EXPECT_EQ(empty, UTF16ToASCII(empty16));
+  EXPECT_EQ(empty16, ASCIIToUTF16(empty));
+
+  // Convert strings with an embedded NUL character.
+  const char chars_with_nul[] = "test\0string";
+  const int length_with_nul = arraysize(chars_with_nul) - 1;
+  std::string string_with_nul(chars_with_nul, length_with_nul);
+  base::string16 string16_with_nul = ASCIIToUTF16(string_with_nul);
+  EXPECT_EQ(static_cast<base::string16::size_type>(length_with_nul),
+            string16_with_nul.length());
+  std::string narrow_with_nul = UTF16ToASCII(string16_with_nul);
+  EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul),
+            narrow_with_nul.length());
+  EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul));
+}
+
+TEST(StringUtilTest, ToUpperASCII) {
+  EXPECT_EQ('C', ToUpperASCII('C'));
+  EXPECT_EQ('C', ToUpperASCII('c'));
+  EXPECT_EQ('2', ToUpperASCII('2'));
+
+  EXPECT_EQ(L'C', ToUpperASCII(L'C'));
+  EXPECT_EQ(L'C', ToUpperASCII(L'c'));
+  EXPECT_EQ(L'2', ToUpperASCII(L'2'));
+
+  std::string in_place_a("Cc2");
+  StringToUpperASCII(&in_place_a);
+  EXPECT_EQ("CC2", in_place_a);
+
+  std::wstring in_place_w(L"Cc2");
+  StringToUpperASCII(&in_place_w);
+  EXPECT_EQ(L"CC2", in_place_w);
+
+  std::string original_a("Cc2");
+  std::string upper_a = StringToUpperASCII(original_a);
+  EXPECT_EQ("CC2", upper_a);
+
+  std::wstring original_w(L"Cc2");
+  std::wstring upper_w = StringToUpperASCII(original_w);
+  EXPECT_EQ(L"CC2", upper_w);
+}
+
+TEST(StringUtilTest, LowerCaseEqualsASCII) {
+  static const struct {
+    const char*    src_a;
+    const char*    dst;
+  } lowercase_cases[] = {
+    { "FoO", "foo" },
+    { "foo", "foo" },
+    { "FOO", "foo" },
+  };
+
+  for (size_t i = 0; i < arraysize(lowercase_cases); ++i) {
+    EXPECT_TRUE(LowerCaseEqualsASCII(ASCIIToUTF16(lowercase_cases[i].src_a),
+                                     lowercase_cases[i].dst));
+    EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_a,
+                                     lowercase_cases[i].dst));
+  }
+}
+
+TEST(StringUtilTest, FormatBytesUnlocalized) {
+  static const struct {
+    int64 bytes;
+    const char* expected;
+  } cases[] = {
+    // Expected behavior: we show one post-decimal digit when we have
+    // under two pre-decimal digits, except in cases where it makes no
+    // sense (zero or bytes).
+    // Since we switch units once we cross the 1000 mark, this keeps
+    // the display of file sizes or bytes consistently around three
+    // digits.
+    {0, "0 B"},
+    {512, "512 B"},
+    {1024*1024, "1.0 MB"},
+    {1024*1024*1024, "1.0 GB"},
+    {10LL*1024*1024*1024, "10.0 GB"},
+    {99LL*1024*1024*1024, "99.0 GB"},
+    {105LL*1024*1024*1024, "105 GB"},
+    {105LL*1024*1024*1024 + 500LL*1024*1024, "105 GB"},
+    {~(1LL << 63), "8192 PB"},
+
+    {99*1024 + 103, "99.1 kB"},
+    {1024*1024 + 103, "1.0 MB"},
+    {1024*1024 + 205 * 1024, "1.2 MB"},
+    {1024*1024*1024 + (927 * 1024*1024), "1.9 GB"},
+    {10LL*1024*1024*1024, "10.0 GB"},
+    {100LL*1024*1024*1024, "100 GB"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    EXPECT_EQ(ASCIIToUTF16(cases[i].expected),
+              FormatBytesUnlocalized(cases[i].bytes));
+  }
+}
+TEST(StringUtilTest, ReplaceSubstringsAfterOffset) {
+  static const struct {
+    const char* str;
+    string16::size_type start_offset;
+    const char* find_this;
+    const char* replace_with;
+    const char* expected;
+  } cases[] = {
+    {"aaa", 0, "a", "b", "bbb"},
+    {"abb", 0, "ab", "a", "ab"},
+    {"Removing some substrings inging", 0, "ing", "", "Remov some substrs "},
+    {"Not found", 0, "x", "0", "Not found"},
+    {"Not found again", 5, "x", "0", "Not found again"},
+    {" Making it much longer ", 0, " ", "Four score and seven years ago",
+     "Four score and seven years agoMakingFour score and seven years agoit"
+     "Four score and seven years agomuchFour score and seven years agolonger"
+     "Four score and seven years ago"},
+    {"Invalid offset", 9999, "t", "foobar", "Invalid offset"},
+    {"Replace me only me once", 9, "me ", "", "Replace me only once"},
+    {"abababab", 2, "ab", "c", "abccc"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); i++) {
+    string16 str = ASCIIToUTF16(cases[i].str);
+    ReplaceSubstringsAfterOffset(&str, cases[i].start_offset,
+                                 ASCIIToUTF16(cases[i].find_this),
+                                 ASCIIToUTF16(cases[i].replace_with));
+    EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str);
+  }
+}
+
+TEST(StringUtilTest, ReplaceFirstSubstringAfterOffset) {
+  static const struct {
+    const char* str;
+    string16::size_type start_offset;
+    const char* find_this;
+    const char* replace_with;
+    const char* expected;
+  } cases[] = {
+    {"aaa", 0, "a", "b", "baa"},
+    {"abb", 0, "ab", "a", "ab"},
+    {"Removing some substrings inging", 0, "ing", "",
+      "Remov some substrings inging"},
+    {"Not found", 0, "x", "0", "Not found"},
+    {"Not found again", 5, "x", "0", "Not found again"},
+    {" Making it much longer ", 0, " ", "Four score and seven years ago",
+     "Four score and seven years agoMaking it much longer "},
+    {"Invalid offset", 9999, "t", "foobar", "Invalid offset"},
+    {"Replace me only me once", 4, "me ", "", "Replace only me once"},
+    {"abababab", 2, "ab", "c", "abcabab"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); i++) {
+    string16 str = ASCIIToUTF16(cases[i].str);
+    ReplaceFirstSubstringAfterOffset(&str, cases[i].start_offset,
+                                     ASCIIToUTF16(cases[i].find_this),
+                                     ASCIIToUTF16(cases[i].replace_with));
+    EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str);
+  }
+}
+
+TEST(StringUtilTest, HexDigitToInt) {
+  EXPECT_EQ(0, HexDigitToInt('0'));
+  EXPECT_EQ(1, HexDigitToInt('1'));
+  EXPECT_EQ(2, HexDigitToInt('2'));
+  EXPECT_EQ(3, HexDigitToInt('3'));
+  EXPECT_EQ(4, HexDigitToInt('4'));
+  EXPECT_EQ(5, HexDigitToInt('5'));
+  EXPECT_EQ(6, HexDigitToInt('6'));
+  EXPECT_EQ(7, HexDigitToInt('7'));
+  EXPECT_EQ(8, HexDigitToInt('8'));
+  EXPECT_EQ(9, HexDigitToInt('9'));
+  EXPECT_EQ(10, HexDigitToInt('A'));
+  EXPECT_EQ(11, HexDigitToInt('B'));
+  EXPECT_EQ(12, HexDigitToInt('C'));
+  EXPECT_EQ(13, HexDigitToInt('D'));
+  EXPECT_EQ(14, HexDigitToInt('E'));
+  EXPECT_EQ(15, HexDigitToInt('F'));
+
+  // Verify the lower case as well.
+  EXPECT_EQ(10, HexDigitToInt('a'));
+  EXPECT_EQ(11, HexDigitToInt('b'));
+  EXPECT_EQ(12, HexDigitToInt('c'));
+  EXPECT_EQ(13, HexDigitToInt('d'));
+  EXPECT_EQ(14, HexDigitToInt('e'));
+  EXPECT_EQ(15, HexDigitToInt('f'));
+}
+
+// Test for Tokenize
+template <typename STR>
+void TokenizeTest() {
+  std::vector<STR> r;
+  size_t size;
+
+  size = Tokenize(STR("This is a string"), STR(" "), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("This"));
+  EXPECT_EQ(r[1], STR("is"));
+  EXPECT_EQ(r[2], STR("a"));
+  EXPECT_EQ(r[3], STR("string"));
+  r.clear();
+
+  size = Tokenize(STR("one,two,three"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three"));
+  r.clear();
+
+  size = Tokenize(STR("one,two:three;four"), STR(",:"), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three;four"));
+  r.clear();
+
+  size = Tokenize(STR("one,two:three;four"), STR(";,:"), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three"));
+  EXPECT_EQ(r[3], STR("four"));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three, "), STR(","), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  EXPECT_EQ(r[3], STR(" "));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three,"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  r.clear();
+
+  size = Tokenize(STR(), STR(","), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR(","), STR(","), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR(",;:."), STR(".:;,"), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR("\t\ta\t"), STR("\t"), &r);
+  EXPECT_EQ(1U, size);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], STR("a"));
+  r.clear();
+
+  size = Tokenize(STR("\ta\t\nb\tcc"), STR("\n"), &r);
+  EXPECT_EQ(2U, size);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], STR("\ta\t"));
+  EXPECT_EQ(r[1], STR("b\tcc"));
+  r.clear();
+}
+
+TEST(StringUtilTest, TokenizeStdString) {
+  TokenizeTest<std::string>();
+}
+
+TEST(StringUtilTest, TokenizeStringPiece) {
+  TokenizeTest<base::StringPiece>();
+}
+
+// Test for JoinString
+TEST(StringUtilTest, JoinString) {
+  std::vector<std::string> in;
+  EXPECT_EQ("", JoinString(in, ','));
+
+  in.push_back("a");
+  EXPECT_EQ("a", JoinString(in, ','));
+
+  in.push_back("b");
+  in.push_back("c");
+  EXPECT_EQ("a,b,c", JoinString(in, ','));
+
+  in.push_back(std::string());
+  EXPECT_EQ("a,b,c,", JoinString(in, ','));
+  in.push_back(" ");
+  EXPECT_EQ("a|b|c|| ", JoinString(in, '|'));
+}
+
+// Test for JoinString overloaded with std::string separator
+TEST(StringUtilTest, JoinStringWithString) {
+  std::string separator(", ");
+  std::vector<std::string> parts;
+  EXPECT_EQ(std::string(), JoinString(parts, separator));
+
+  parts.push_back("a");
+  EXPECT_EQ("a", JoinString(parts, separator));
+
+  parts.push_back("b");
+  parts.push_back("c");
+  EXPECT_EQ("a, b, c", JoinString(parts, separator));
+
+  parts.push_back(std::string());
+  EXPECT_EQ("a, b, c, ", JoinString(parts, separator));
+  parts.push_back(" ");
+  EXPECT_EQ("a|b|c|| ", JoinString(parts, "|"));
+}
+
+// Test for JoinString overloaded with string16 separator
+TEST(StringUtilTest, JoinStringWithString16) {
+  string16 separator = ASCIIToUTF16(", ");
+  std::vector<string16> parts;
+  EXPECT_EQ(string16(), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16("a"));
+  EXPECT_EQ(ASCIIToUTF16("a"), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16("b"));
+  parts.push_back(ASCIIToUTF16("c"));
+  EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16(""));
+  EXPECT_EQ(ASCIIToUTF16("a, b, c, "), JoinString(parts, separator));
+  parts.push_back(ASCIIToUTF16(" "));
+  EXPECT_EQ(ASCIIToUTF16("a|b|c|| "), JoinString(parts, ASCIIToUTF16("|")));
+}
+
+TEST(StringUtilTest, StartsWith) {
+  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", true));
+  EXPECT_FALSE(StartsWithASCII("JavaScript:url", "javascript", true));
+  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", false));
+  EXPECT_TRUE(StartsWithASCII("JavaScript:url", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII("java", "javascript", true));
+  EXPECT_FALSE(StartsWithASCII("java", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", false));
+  EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", true));
+  EXPECT_TRUE(StartsWithASCII("java", std::string(), false));
+  EXPECT_TRUE(StartsWithASCII("java", std::string(), true));
+
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
+                         ASCIIToUTF16("javascript"), true));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"),
+                          ASCIIToUTF16("javascript"), true));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
+                         ASCIIToUTF16("javascript"), false));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("JavaScript:url"),
+                         ASCIIToUTF16("javascript"), false));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
+                          ASCIIToUTF16("javascript"), true));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
+                          ASCIIToUTF16("javascript"), false));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), false));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), true));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), false));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), true));
+}
+
+TEST(StringUtilTest, EndsWith) {
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
+                       ASCIIToUTF16(".plugin"), true));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
+                        ASCIIToUTF16(".plugin"), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
+                       ASCIIToUTF16(".plugin"), false));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
+                       ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), true));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
+                        ASCIIToUTF16(".plugin"), true));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
+                        ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), false));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"),
+                       ASCIIToUTF16(".plugin"), false));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"), true));
+  EXPECT_TRUE(EndsWith(string16(), string16(), false));
+  EXPECT_TRUE(EndsWith(string16(), string16(), true));
+}
+
+TEST(StringUtilTest, GetStringFWithOffsets) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("1"));
+  subst.push_back(ASCIIToUTF16("2"));
+  std::vector<size_t> offsets;
+
+  ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $1. Your number is $2."),
+                            subst,
+                            &offsets);
+  EXPECT_EQ(2U, offsets.size());
+  EXPECT_EQ(7U, offsets[0]);
+  EXPECT_EQ(25U, offsets[1]);
+  offsets.clear();
+
+  ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $2. Your number is $1."),
+                            subst,
+                            &offsets);
+  EXPECT_EQ(2U, offsets.size());
+  EXPECT_EQ(25U, offsets[0]);
+  EXPECT_EQ(7U, offsets[1]);
+  offsets.clear();
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersTooFew) {
+  // Test whether replacestringplaceholders works as expected when there
+  // are fewer inputs than outputs.
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$1g,$2h,$3i"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci"));
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholders) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+  subst.push_back(ASCIIToUTF16("6d"));
+  subst.push_back(ASCIIToUTF16("5e"));
+  subst.push_back(ASCIIToUTF16("4f"));
+  subst.push_back(ASCIIToUTF16("3g"));
+  subst.push_back(ASCIIToUTF16("2h"));
+  subst.push_back(ASCIIToUTF16("1i"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii"));
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersMoreThan9Replacements) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+  subst.push_back(ASCIIToUTF16("6d"));
+  subst.push_back(ASCIIToUTF16("5e"));
+  subst.push_back(ASCIIToUTF16("4f"));
+  subst.push_back(ASCIIToUTF16("3g"));
+  subst.push_back(ASCIIToUTF16("2h"));
+  subst.push_back(ASCIIToUTF16("1i"));
+  subst.push_back(ASCIIToUTF16("0j"));
+  subst.push_back(ASCIIToUTF16("-1k"));
+  subst.push_back(ASCIIToUTF16("-2l"));
+  subst.push_back(ASCIIToUTF16("-3m"));
+  subst.push_back(ASCIIToUTF16("-4n"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i,"
+                       "$10j,$11k,$12l,$13m,$14n,$1"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,"
+                                    "1ii,0jj,-1kk,-2ll,-3mm,-4nn,9a"));
+}
+
+TEST(StringUtilTest, StdStringReplaceStringPlaceholders) {
+  std::vector<std::string> subst;
+  subst.push_back("9a");
+  subst.push_back("8b");
+  subst.push_back("7c");
+  subst.push_back("6d");
+  subst.push_back("5e");
+  subst.push_back("4f");
+  subst.push_back("3g");
+  subst.push_back("2h");
+  subst.push_back("1i");
+
+  std::string formatted =
+      ReplaceStringPlaceholders(
+          "$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i", subst, NULL);
+
+  EXPECT_EQ(formatted, "9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii");
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) {
+  std::vector<std::string> subst;
+  subst.push_back("a");
+  subst.push_back("b");
+  subst.push_back("c");
+  EXPECT_EQ(ReplaceStringPlaceholders("$$1 $$$2 $$$$3", subst, NULL),
+            "$1 $$2 $$$3");
+}
+
+TEST(StringUtilTest, MatchPatternTest) {
+  EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
+  EXPECT_TRUE(MatchPattern("www.google.com", "*"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
+  EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
+  EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
+  EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
+  EXPECT_FALSE(MatchPattern("", "*.*"));
+  EXPECT_TRUE(MatchPattern("", "*"));
+  EXPECT_TRUE(MatchPattern("", "?"));
+  EXPECT_TRUE(MatchPattern("", ""));
+  EXPECT_FALSE(MatchPattern("Hello", ""));
+  EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
+  // Stop after a certain recursion depth.
+  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+
+  // Test UTF8 matching.
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
+  EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
+  // Invalid sequences should be handled as a single invalid character.
+  EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
+  // If the pattern has invalid characters, it shouldn't match anything.
+  EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
+
+  // Test UTF16 character matching.
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"),
+                           UTF8ToUTF16("*.com")));
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
+                           UTF8ToUTF16("He??o\\*1*")));
+
+  // This test verifies that consecutive wild cards are collapsed into 1
+  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
+  // recursion depth).
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
+                           UTF8ToUTF16("He********************************o")));
+}
+
+TEST(StringUtilTest, LcpyTest) {
+  // Test the normal case where we fit in our buffer.
+  {
+    char dst[10];
+    wchar_t wdst[10];
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
+    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
+  }
+
+  // Test dst_size == 0, nothing should be written to |dst| and we should
+  // have the equivalent of strlen(src).
+  {
+    char dst[2] = {1, 2};
+    wchar_t wdst[2] = {1, 2};
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", 0));
+    EXPECT_EQ(1, dst[0]);
+    EXPECT_EQ(2, dst[1]);
+    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", 0));
+    EXPECT_EQ(static_cast<wchar_t>(1), wdst[0]);
+    EXPECT_EQ(static_cast<wchar_t>(2), wdst[1]);
+  }
+
+  // Test the case were we _just_ competely fit including the null.
+  {
+    char dst[8];
+    wchar_t wdst[8];
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
+    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
+  }
+
+  // Test the case were we we are one smaller, so we can't fit the null.
+  {
+    char dst[7];
+    wchar_t wdst[7];
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdef", 7));
+    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7));
+  }
+
+  // Test the case were we are just too small.
+  {
+    char dst[3];
+    wchar_t wdst[3];
+    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "ab", 3));
+    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3));
+  }
+}
+
+TEST(StringUtilTest, WprintfFormatPortabilityTest) {
+  static const struct {
+    const wchar_t* input;
+    bool portable;
+  } cases[] = {
+    { L"%ls", true },
+    { L"%s", false },
+    { L"%S", false },
+    { L"%lS", false },
+    { L"Hello, %s", false },
+    { L"%lc", true },
+    { L"%c", false },
+    { L"%C", false },
+    { L"%lC", false },
+    { L"%ls %s", false },
+    { L"%s %ls", false },
+    { L"%s %ls %s", false },
+    { L"%f", true },
+    { L"%f %F", false },
+    { L"%d %D", false },
+    { L"%o %O", false },
+    { L"%u %U", false },
+    { L"%f %d %o %u", true },
+    { L"%-8d (%02.1f%)", true },
+    { L"% 10s", false },
+    { L"% 10ls", true }
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].portable, base::IsWprintfFormatPortable(cases[i].input));
+}
+
+TEST(StringUtilTest, RemoveChars) {
+  const char kRemoveChars[] = "-/+*";
+  std::string input = "A-+bc/d!*";
+  EXPECT_TRUE(RemoveChars(input, kRemoveChars, &input));
+  EXPECT_EQ("Abcd!", input);
+
+  // No characters match kRemoveChars.
+  EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input));
+  EXPECT_EQ("Abcd!", input);
+
+  // Empty string.
+  input.clear();
+  EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input));
+  EXPECT_EQ(std::string(), input);
+}
+
+TEST(StringUtilTest, ReplaceChars) {
+  struct TestData {
+    const char* input;
+    const char* replace_chars;
+    const char* replace_with;
+    const char* output;
+    bool result;
+  } cases[] = {
+    { "", "", "", "", false },
+    { "test", "", "", "test", false },
+    { "test", "", "!", "test", false },
+    { "test", "z", "!", "test", false },
+    { "test", "e", "!", "t!st", true },
+    { "test", "e", "!?", "t!?st", true },
+    { "test", "ez", "!", "t!st", true },
+    { "test", "zed", "!?", "t!?st", true },
+    { "test", "t", "!?", "!?es!?", true },
+    { "test", "et", "!>", "!>!>s!>", true },
+    { "test", "zest", "!", "!!!!", true },
+    { "test", "szt", "!", "!e!!", true },
+    { "test", "t", "test", "testestest", true },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    std::string output;
+    bool result = ReplaceChars(cases[i].input,
+                               cases[i].replace_chars,
+                               cases[i].replace_with,
+                               &output);
+    EXPECT_EQ(cases[i].result, result);
+    EXPECT_EQ(cases[i].output, output);
+  }
+}
+
+TEST(StringUtilTest, ContainsOnlyChars) {
+  // Providing an empty list of characters should return false but for the empty
+  // string.
+  EXPECT_TRUE(ContainsOnlyChars(std::string(), std::string()));
+  EXPECT_FALSE(ContainsOnlyChars("Hello", std::string()));
+
+  EXPECT_TRUE(ContainsOnlyChars(std::string(), "1234"));
+  EXPECT_TRUE(ContainsOnlyChars("1", "1234"));
+  EXPECT_TRUE(ContainsOnlyChars("1", "4321"));
+  EXPECT_TRUE(ContainsOnlyChars("123", "4321"));
+  EXPECT_FALSE(ContainsOnlyChars("123a", "4321"));
+
+  EXPECT_TRUE(ContainsOnlyChars(std::string(), kWhitespaceASCII));
+  EXPECT_TRUE(ContainsOnlyChars(" ", kWhitespaceASCII));
+  EXPECT_TRUE(ContainsOnlyChars("\t", kWhitespaceASCII));
+  EXPECT_TRUE(ContainsOnlyChars("\t \r \n  ", kWhitespaceASCII));
+  EXPECT_FALSE(ContainsOnlyChars("a", kWhitespaceASCII));
+  EXPECT_FALSE(ContainsOnlyChars("\thello\r \n  ", kWhitespaceASCII));
+
+  EXPECT_TRUE(ContainsOnlyChars(string16(), kWhitespaceUTF16));
+  EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16(" "), kWhitespaceUTF16));
+  EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16("\t"), kWhitespaceUTF16));
+  EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16("\t \r \n  "), kWhitespaceUTF16));
+  EXPECT_FALSE(ContainsOnlyChars(ASCIIToUTF16("a"), kWhitespaceUTF16));
+  EXPECT_FALSE(ContainsOnlyChars(ASCIIToUTF16("\thello\r \n  "),
+                                  kWhitespaceUTF16));
+}
+
+class WriteIntoTest : public testing::Test {
+ protected:
+  static void WritesCorrectly(size_t num_chars) {
+    std::string buffer;
+    char kOriginal[] = "supercali";
+    strncpy(WriteInto(&buffer, num_chars + 1), kOriginal, num_chars);
+    // Using std::string(buffer.c_str()) instead of |buffer| truncates the
+    // string at the first \0.
+    EXPECT_EQ(std::string(kOriginal,
+                          std::min(num_chars, arraysize(kOriginal) - 1)),
+              std::string(buffer.c_str()));
+    EXPECT_EQ(num_chars, buffer.size());
+  }
+};
+
+TEST_F(WriteIntoTest, WriteInto) {
+  // Validate that WriteInto reserves enough space and
+  // sizes a string correctly.
+  WritesCorrectly(1);
+  WritesCorrectly(2);
+  WritesCorrectly(5000);
+
+  // Validate that WriteInto doesn't modify other strings
+  // when using a Copy-on-Write implementation.
+  const char kLive[] = "live";
+  const char kDead[] = "dead";
+  const std::string live = kLive;
+  std::string dead = live;
+  strncpy(WriteInto(&dead, 5), kDead, 4);
+  EXPECT_EQ(kDead, dead);
+  EXPECT_EQ(4u, dead.size());
+  EXPECT_EQ(kLive, live);
+  EXPECT_EQ(4u, live.size());
+}
+
+}  // namespace base
diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h
new file mode 100644
index 0000000..61eda20
--- /dev/null
+++ b/base/strings/string_util_win.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_WIN_H_
+#define BASE_STRINGS_STRING_UTIL_WIN_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+  return _strdup(str);
+}
+
+inline int strcasecmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+
+inline int strncasecmp(const char* s1, const char* s2, size_t count) {
+  return _strnicmp(s1, s2, count);
+}
+
+inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
+  return ::wcsncmp(s1, s2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
+  if (length < 0)
+    return _vscprintf(format, arguments);
+  return length;
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+                     const wchar_t* format, va_list arguments) {
+  DCHECK(IsWprintfFormatPortable(format));
+
+  int length = _vsnwprintf_s(buffer, size, size - 1, format, arguments);
+  if (length < 0)
+    return _vscwprintf(format, arguments);
+  return length;
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_UTIL_WIN_H_
diff --git a/base/strings/stringize_macros.h b/base/strings/stringize_macros.h
new file mode 100644
index 0000000..d4e2707
--- /dev/null
+++ b/base/strings/stringize_macros.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file defines preprocessor macros for stringizing preprocessor
+// symbols (or their output) and manipulating preprocessor symbols
+// that define strings.
+
+#ifndef BASE_STRINGS_STRINGIZE_MACROS_H_
+#define BASE_STRINGS_STRINGIZE_MACROS_H_
+
+#include "build/build_config.h"
+
+// This is not very useful as it does not expand defined symbols if
+// called directly. Use its counterpart without the _NO_EXPANSION
+// suffix, below.
+#define STRINGIZE_NO_EXPANSION(x) #x
+
+// Use this to quote the provided parameter, first expanding it if it
+// is a preprocessor symbol.
+//
+// For example, if:
+//   #define A FOO
+//   #define B(x) myobj->FunctionCall(x)
+//
+// Then:
+//   STRINGIZE(A) produces "FOO"
+//   STRINGIZE(B(y)) produces "myobj->FunctionCall(y)"
+#define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x)
+
+#endif  // BASE_STRINGS_STRINGIZE_MACROS_H_
diff --git a/base/strings/stringize_macros_unittest.cc b/base/strings/stringize_macros_unittest.cc
new file mode 100644
index 0000000..d7f9e56
--- /dev/null
+++ b/base/strings/stringize_macros_unittest.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringize_macros.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Macros as per documentation in header file.
+#define PREPROCESSOR_UTIL_UNITTEST_A FOO
+#define PREPROCESSOR_UTIL_UNITTEST_B(x) myobj->FunctionCall(x)
+#define PREPROCESSOR_UTIL_UNITTEST_C "foo"
+
+TEST(StringizeTest, Ansi) {
+  EXPECT_STREQ(
+      "PREPROCESSOR_UTIL_UNITTEST_A",
+      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ(
+      "PREPROCESSOR_UTIL_UNITTEST_B(y)",
+      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ(
+      "PREPROCESSOR_UTIL_UNITTEST_C",
+      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C));
+
+  EXPECT_STREQ("FOO", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ("myobj->FunctionCall(y)",
+               STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ("\"foo\"", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_C));
+}
diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc
new file mode 100644
index 0000000..537873d
--- /dev/null
+++ b/base/strings/stringprintf.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+
+#include <errno.h>
+
+#include <vector>
+
+#include "base/scoped_clear_errno.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
+// is the size of the buffer. These return the number of characters in the
+// formatted string excluding the NUL terminator. If the buffer is not
+// large enough to accommodate the formatted string without truncation, they
+// return the number of characters that would be in the fully-formatted string
+// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
+inline int vsnprintfT(char* buffer,
+                      size_t buf_size,
+                      const char* format,
+                      va_list argptr) {
+  return base::vsnprintf(buffer, buf_size, format, argptr);
+}
+
+#if defined(OS_WIN)
+inline int vsnprintfT(wchar_t* buffer,
+                      size_t buf_size,
+                      const wchar_t* format,
+                      va_list argptr) {
+  return base::vswprintf(buffer, buf_size, format, argptr);
+}
+#endif
+
+// Templatized backend for StringPrintF/StringAppendF. This does not finalize
+// the va_list, the caller is expected to do that.
+template <class StringType>
+static void StringAppendVT(StringType* dst,
+                           const typename StringType::value_type* format,
+                           va_list ap) {
+  // First try with a small fixed size buffer.
+  // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
+  // and StringUtilTest.StringPrintfBounds.
+  typename StringType::value_type stack_buf[1024];
+
+  va_list ap_copy;
+  va_copy(ap_copy, ap);
+
+#if !defined(OS_WIN)
+  ScopedClearErrno clear_errno;
+#endif
+  int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
+  va_end(ap_copy);
+
+  if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
+    // It fit.
+    dst->append(stack_buf, result);
+    return;
+  }
+
+  // Repeatedly increase buffer size until it fits.
+  int mem_length = arraysize(stack_buf);
+  while (true) {
+    if (result < 0) {
+#if defined(OS_WIN)
+      // On Windows, vsnprintfT always returns the number of characters in a
+      // fully-formatted string, so if we reach this point, something else is
+      // wrong and no amount of buffer-doubling is going to fix it.
+      return;
+#else
+      if (errno != 0 && errno != EOVERFLOW)
+        return;
+      // Try doubling the buffer size.
+      mem_length *= 2;
+#endif
+    } else {
+      // We need exactly "result + 1" characters.
+      mem_length = result + 1;
+    }
+
+    if (mem_length > 32 * 1024 * 1024) {
+      // That should be plenty, don't try anything larger.  This protects
+      // against huge allocations when using vsnprintfT implementations that
+      // return -1 for reasons other than overflow without setting errno.
+      DLOG(WARNING) << "Unable to printf the requested string due to size.";
+      return;
+    }
+
+    std::vector<typename StringType::value_type> mem_buf(mem_length);
+
+    // NOTE: You can only use a va_list once.  Since we're in a while loop, we
+    // need to make a new copy each time so we don't use up the original.
+    va_copy(ap_copy, ap);
+    result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
+    va_end(ap_copy);
+
+    if ((result >= 0) && (result < mem_length)) {
+      // It fit.
+      dst->append(&mem_buf[0], result);
+      return;
+    }
+  }
+}
+
+}  // namespace
+
+std::string StringPrintf(const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+
+#if defined(OS_WIN)
+std::wstring StringPrintf(const wchar_t* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::wstring result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+#endif
+
+std::string StringPrintV(const char* format, va_list ap) {
+  std::string result;
+  StringAppendV(&result, format, ap);
+  return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+
+#if defined(OS_WIN)
+const std::wstring& SStringPrintf(std::wstring* dst,
+                                  const wchar_t* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+#endif
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+
+#if defined(OS_WIN)
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+#endif
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+  StringAppendVT(dst, format, ap);
+}
+
+#if defined(OS_WIN)
+void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
+  StringAppendVT(dst, format, ap);
+}
+#endif
+
+}  // namespace base
diff --git a/base/strings/stringprintf.h b/base/strings/stringprintf.h
new file mode 100644
index 0000000..523f7ee
--- /dev/null
+++ b/base/strings/stringprintf.h
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRINGPRINTF_H_
+#define BASE_STRINGS_STRINGPRINTF_H_
+
+#include <stdarg.h>   // va_list
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// Return a C++ string given printf-like input.
+BASE_EXPORT std::string StringPrintf(const char* format, ...)
+    PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#if defined(OS_WIN)
+BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
+    WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#endif
+
+// Return a C++ string given vprintf-like input.
+BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
+    PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
+
+// Store result into a supplied string and return it.
+BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
+                                             const char* format, ...)
+    PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
+                                              const wchar_t* format, ...)
+    WPRINTF_FORMAT(2, 3);
+#endif
+
+// Append result to a supplied string.
+BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
+    PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
+    WPRINTF_FORMAT(2, 3);
+#endif
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string.  All other routines are just convenience wrappers around it.
+BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
+    PRINTF_FORMAT(2, 0);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendV(std::wstring* dst,
+                               const wchar_t* format, va_list ap)
+    WPRINTF_FORMAT(2, 0);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRINGPRINTF_H_
diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc
new file mode 100644
index 0000000..c49637c
--- /dev/null
+++ b/base/strings/stringprintf_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+
+#include <errno.h>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// A helper for the StringAppendV test that follows.
+//
+// Just forwards its args to StringAppendV.
+static void StringAppendVTestHelper(std::string* out, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(out, format, ap);
+  va_end(ap);
+}
+
+}  // namespace
+
+TEST(StringPrintfTest, StringPrintfEmpty) {
+  EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringPrintfTest, StringPrintfMisc) {
+  EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
+#if defined(OS_WIN)
+  EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
+#endif
+}
+
+TEST(StringPrintfTest, StringAppendfEmptyString) {
+  std::string value("Hello");
+  StringAppendF(&value, "%s", "");
+  EXPECT_EQ("Hello", value);
+
+#if defined(OS_WIN)
+  std::wstring valuew(L"Hello");
+  StringAppendF(&valuew, L"%ls", L"");
+  EXPECT_EQ(L"Hello", valuew);
+#endif
+}
+
+TEST(StringPrintfTest, StringAppendfString) {
+  std::string value("Hello");
+  StringAppendF(&value, " %s", "World");
+  EXPECT_EQ("Hello World", value);
+
+#if defined(OS_WIN)
+  std::wstring valuew(L"Hello");
+  StringAppendF(&valuew, L" %ls", L"World");
+  EXPECT_EQ(L"Hello World", valuew);
+#endif
+}
+
+TEST(StringPrintfTest, StringAppendfInt) {
+  std::string value("Hello");
+  StringAppendF(&value, " %d", 123);
+  EXPECT_EQ("Hello 123", value);
+
+#if defined(OS_WIN)
+  std::wstring valuew(L"Hello");
+  StringAppendF(&valuew, L" %d", 123);
+  EXPECT_EQ(L"Hello 123", valuew);
+#endif
+}
+
+// Make sure that lengths exactly around the initial buffer size are handled
+// correctly.
+TEST(StringPrintfTest, StringPrintfBounds) {
+  const int kSrcLen = 1026;
+  char src[kSrcLen];
+  for (size_t i = 0; i < arraysize(src); i++)
+    src[i] = 'A';
+
+  wchar_t srcw[kSrcLen];
+  for (size_t i = 0; i < arraysize(srcw); i++)
+    srcw[i] = 'A';
+
+  for (int i = 1; i < 3; i++) {
+    src[kSrcLen - i] = 0;
+    std::string out;
+    SStringPrintf(&out, "%s", src);
+    EXPECT_STREQ(src, out.c_str());
+
+#if defined(OS_WIN)
+    srcw[kSrcLen - i] = 0;
+    std::wstring outw;
+    SStringPrintf(&outw, L"%ls", srcw);
+    EXPECT_STREQ(srcw, outw.c_str());
+#endif
+  }
+}
+
+// Test very large sprintfs that will cause the buffer to grow.
+TEST(StringPrintfTest, Grow) {
+  char src[1026];
+  for (size_t i = 0; i < arraysize(src); i++)
+    src[i] = 'A';
+  src[1025] = 0;
+
+  const char fmt[] = "%sB%sB%sB%sB%sB%sB%s";
+
+  std::string out;
+  SStringPrintf(&out, fmt, src, src, src, src, src, src, src);
+
+  const int kRefSize = 320000;
+  char* ref = new char[kRefSize];
+#if defined(OS_WIN)
+  sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src);
+#elif defined(OS_POSIX)
+  snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src);
+#endif
+
+  EXPECT_STREQ(ref, out.c_str());
+  delete[] ref;
+}
+
+TEST(StringPrintfTest, StringAppendV) {
+  std::string out;
+  StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
+  EXPECT_EQ("1 foo bar", out);
+}
+
+// Test the boundary condition for the size of the string_util's
+// internal buffer.
+TEST(StringPrintfTest, GrowBoundary) {
+  const int kStringUtilBufLen = 1024;
+  // Our buffer should be one larger than the size of StringAppendVT's stack
+  // buffer.
+  // And need extra one for NULL-terminator.
+  const int kBufLen = kStringUtilBufLen + 1 + 1;
+  char src[kBufLen];
+  for (int i = 0; i < kBufLen - 1; ++i)
+    src[i] = 'a';
+  src[kBufLen - 1] = 0;
+
+  std::string out;
+  SStringPrintf(&out, "%s", src);
+
+  EXPECT_STREQ(src, out.c_str());
+}
+
+// TODO(evanm): what's the proper cross-platform test here?
+#if defined(OS_WIN)
+// sprintf in Visual Studio fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled.
+TEST(StringPrintfTest, Invalid) {
+  wchar_t invalid[2];
+  invalid[0] = 0xffff;
+  invalid[1] = 0;
+
+  std::wstring out;
+  SStringPrintf(&out, L"%ls", invalid);
+  EXPECT_STREQ(L"", out.c_str());
+}
+#endif
+
+// Test that StringPrintf and StringAppendV do not change errno.
+TEST(StringPrintfTest, StringPrintfErrno) {
+  errno = 1;
+  EXPECT_EQ("", StringPrintf("%s", ""));
+  EXPECT_EQ(1, errno);
+  std::string out;
+  StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
+  EXPECT_EQ(1, errno);
+}
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions.h b/base/strings/sys_string_conversions.h
new file mode 100644
index 0000000..42f2389
--- /dev/null
+++ b/base/strings/sys_string_conversions.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_SYS_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_SYS_STRING_CONVERSIONS_H_
+
+// Provides system-dependent string type conversions for cases where it's
+// necessary to not use ICU. Generally, you should not need this in Chrome,
+// but it is used in some shared code. Dependencies should be minimal.
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+#endif  // OS_MACOSX
+
+namespace base {
+
+// Converts between wide and UTF-8 representations of a string. On error, the
+// result is system-dependent.
+BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide);
+BASE_EXPORT std::wstring SysUTF8ToWide(const StringPiece& utf8);
+
+// Converts between wide and the system multi-byte representations of a string.
+// DANGER: This will lose information and can change (on Windows, this can
+// change between reboots).
+BASE_EXPORT std::string SysWideToNativeMB(const std::wstring& wide);
+BASE_EXPORT std::wstring SysNativeMBToWide(const StringPiece& native_mb);
+
+// Windows-specific ------------------------------------------------------------
+
+#if defined(OS_WIN)
+
+// Converts between 8-bit and wide strings, using the given code page. The
+// code page identifier is one accepted by the Windows function
+// MultiByteToWideChar().
+BASE_EXPORT std::wstring SysMultiByteToWide(const StringPiece& mb,
+                                            uint32 code_page);
+BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
+                                           uint32 code_page);
+
+#endif  // defined(OS_WIN)
+
+// Mac-specific ----------------------------------------------------------------
+
+#if defined(OS_MACOSX)
+
+// Converts between STL strings and CFStringRefs/NSStrings.
+
+// Creates a string, and returns it with a refcount of 1. You are responsible
+// for releasing it. Returns NULL on failure.
+BASE_EXPORT CFStringRef SysUTF8ToCFStringRef(const std::string& utf8);
+BASE_EXPORT CFStringRef SysUTF16ToCFStringRef(const string16& utf16);
+
+// Same, but returns an autoreleased NSString.
+BASE_EXPORT NSString* SysUTF8ToNSString(const std::string& utf8);
+BASE_EXPORT NSString* SysUTF16ToNSString(const string16& utf16);
+
+// Converts a CFStringRef to an STL string. Returns an empty string on failure.
+BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref);
+BASE_EXPORT string16 SysCFStringRefToUTF16(CFStringRef ref);
+
+// Same, but accepts NSString input. Converts nil NSString* to the appropriate
+// string type of length 0.
+BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref);
+BASE_EXPORT string16 SysNSStringToUTF16(NSString* ref);
+
+#endif  // defined(OS_MACOSX)
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_SYS_STRING_CONVERSIONS_H_
diff --git a/base/strings/sys_string_conversions_mac.mm b/base/strings/sys_string_conversions_mac.mm
new file mode 100644
index 0000000..9479e78
--- /dev/null
+++ b/base/strings/sys_string_conversions_mac.mm
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/sys_string_conversions.h"
+
+#import <Foundation/Foundation.h>
+
+#include <vector>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+namespace {
+
+// Convert the supplied CFString into the specified encoding, and return it as
+// an STL string of the template type.  Returns an empty string on failure.
+//
+// Do not assert in this function since it is used by the asssertion code!
+template<typename StringType>
+static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
+                                                   CFStringEncoding encoding) {
+  CFIndex length = CFStringGetLength(cfstring);
+  if (length == 0)
+    return StringType();
+
+  CFRange whole_string = CFRangeMake(0, length);
+  CFIndex out_size;
+  CFIndex converted = CFStringGetBytes(cfstring,
+                                       whole_string,
+                                       encoding,
+                                       0,      // lossByte
+                                       false,  // isExternalRepresentation
+                                       NULL,   // buffer
+                                       0,      // maxBufLen
+                                       &out_size);
+  if (converted == 0 || out_size == 0)
+    return StringType();
+
+  // out_size is the number of UInt8-sized units needed in the destination.
+  // A buffer allocated as UInt8 units might not be properly aligned to
+  // contain elements of StringType::value_type.  Use a container for the
+  // proper value_type, and convert out_size by figuring the number of
+  // value_type elements per UInt8.  Leave room for a NUL terminator.
+  typename StringType::size_type elements =
+      out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
+
+  std::vector<typename StringType::value_type> out_buffer(elements);
+  converted = CFStringGetBytes(cfstring,
+                               whole_string,
+                               encoding,
+                               0,      // lossByte
+                               false,  // isExternalRepresentation
+                               reinterpret_cast<UInt8*>(&out_buffer[0]),
+                               out_size,
+                               NULL);  // usedBufLen
+  if (converted == 0)
+    return StringType();
+
+  out_buffer[elements - 1] = '\0';
+  return StringType(&out_buffer[0], elements - 1);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// convert it to |out_encoding| and return it as an STL string of the
+// |OutStringType| template type.  Returns an empty string on failure.
+//
+// Do not assert in this function since it is used by the asssertion code!
+template<typename InStringType, typename OutStringType>
+static OutStringType STLStringToSTLStringWithEncodingsT(
+    const InStringType& in,
+    CFStringEncoding in_encoding,
+    CFStringEncoding out_encoding) {
+  typename InStringType::size_type in_length = in.length();
+  if (in_length == 0)
+    return OutStringType();
+
+  base::ScopedCFTypeRef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
+      NULL,
+      reinterpret_cast<const UInt8*>(in.data()),
+      in_length * sizeof(typename InStringType::value_type),
+      in_encoding,
+      false,
+      kCFAllocatorNull));
+  if (!cfstring)
+    return OutStringType();
+
+  return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring,
+                                                         out_encoding);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// return it as a CFStringRef.  Returns NULL on failure.
+template<typename StringType>
+static CFStringRef STLStringToCFStringWithEncodingsT(
+    const StringType& in,
+    CFStringEncoding in_encoding) {
+  typename StringType::size_type in_length = in.length();
+  if (in_length == 0)
+    return CFSTR("");
+
+  return CFStringCreateWithBytes(kCFAllocatorDefault,
+                                 reinterpret_cast<const UInt8*>(in.data()),
+                                 in_length *
+                                   sizeof(typename StringType::value_type),
+                                 in_encoding,
+                                 false);
+}
+
+// Specify the byte ordering explicitly, otherwise CFString will be confused
+// when strings don't carry BOMs, as they typically won't.
+static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
+#ifdef __BIG_ENDIAN__
+static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16BE;
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE;
+#elif defined(__LITTLE_ENDIAN__)
+static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16LE;
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
+#endif  // __LITTLE_ENDIAN__
+
+}  // namespace
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+  return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
+      wide, kWideStringEncoding, kNarrowStringEncoding);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
+      utf8, kNarrowStringEncoding, kWideStringEncoding);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return SysWideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysUTF8ToWide(native_mb);
+}
+
+CFStringRef SysUTF8ToCFStringRef(const std::string& utf8) {
+  return STLStringToCFStringWithEncodingsT(utf8, kNarrowStringEncoding);
+}
+
+CFStringRef SysUTF16ToCFStringRef(const string16& utf16) {
+  return STLStringToCFStringWithEncodingsT(utf16, kMediumStringEncoding);
+}
+
+NSString* SysUTF8ToNSString(const std::string& utf8) {
+  return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease(
+      SysUTF8ToCFStringRef(utf8));
+}
+
+NSString* SysUTF16ToNSString(const string16& utf16) {
+  return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease(
+      SysUTF16ToCFStringRef(utf16));
+}
+
+std::string SysCFStringRefToUTF8(CFStringRef ref) {
+  return CFStringToSTLStringWithEncodingT<std::string>(ref,
+                                                       kNarrowStringEncoding);
+}
+
+string16 SysCFStringRefToUTF16(CFStringRef ref) {
+  return CFStringToSTLStringWithEncodingT<string16>(ref,
+                                                    kMediumStringEncoding);
+}
+
+std::string SysNSStringToUTF8(NSString* nsstring) {
+  if (!nsstring)
+    return std::string();
+  return SysCFStringRefToUTF8(reinterpret_cast<CFStringRef>(nsstring));
+}
+
+string16 SysNSStringToUTF16(NSString* nsstring) {
+  if (!nsstring)
+    return string16();
+  return SysCFStringRefToUTF16(reinterpret_cast<CFStringRef>(nsstring));
+}
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_mac_unittest.mm b/base/strings/sys_string_conversions_mac_unittest.mm
new file mode 100644
index 0000000..4750a9a
--- /dev/null
+++ b/base/strings/sys_string_conversions_mac_unittest.mm
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+#include "base/strings/string16.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(SysStrings, ConversionsFromNSString) {
+  EXPECT_STREQ("Hello, world!", SysNSStringToUTF8(@"Hello, world!").c_str());
+
+  // Conversions should be able to handle a NULL value without crashing.
+  EXPECT_STREQ("", SysNSStringToUTF8(nil).c_str());
+  EXPECT_EQ(string16(), SysNSStringToUTF16(nil));
+}
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_posix.cc b/base/strings/sys_string_conversions_posix.cc
new file mode 100644
index 0000000..3b18456
--- /dev/null
+++ b/base/strings/sys_string_conversions_posix.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/sys_string_conversions.h"
+
+#include <wchar.h>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+std::string SysWideToUTF8(const std::wstring& wide) {
+  // In theory this should be using the system-provided conversion rather
+  // than our ICU, but this will do for now.
+  return WideToUTF8(wide);
+}
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  // In theory this should be using the system-provided conversion rather
+  // than our ICU, but this will do for now.
+  std::wstring out;
+  UTF8ToWide(utf8.data(), utf8.size(), &out);
+  return out;
+}
+
+#if defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID)
+// TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb()
+// support and a better understanding of what calls these routines.
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return WideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysUTF8ToWide(native_mb);
+}
+
+#else
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  mbstate_t ps;
+
+  // Calculate the number of multi-byte characters.  We walk through the string
+  // without writing the output, counting the number of multi-byte characters.
+  size_t num_out_chars = 0;
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0; i < wide.size(); ++i) {
+    const wchar_t src = wide[i];
+    // Use a temp buffer since calling wcrtomb with an output of NULL does not
+    // calculate the output length.
+    char buf[16];
+    // Skip NULLs to avoid wcrtomb's special handling of them.
+    size_t res = src ? wcrtomb(buf, src, &ps) : 0;
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-1):
+        return std::string();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        ++num_out_chars;
+        break;
+      default:
+        num_out_chars += res;
+        break;
+    }
+  }
+
+  if (num_out_chars == 0)
+    return std::string();
+
+  std::string out;
+  out.resize(num_out_chars);
+
+  // We walk the input string again, with |i| tracking the index of the
+  // wide input, and |j| tracking the multi-byte output.
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0, j = 0; i < wide.size(); ++i) {
+    const wchar_t src = wide[i];
+    // We don't want wcrtomb to do its funkiness for embedded NULLs.
+    size_t res = src ? wcrtomb(&out[j], src, &ps) : 0;
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-1):
+        return std::string();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        ++j;  // Output is already zeroed.
+        break;
+      default:
+        j += res;
+        break;
+    }
+  }
+
+  return out;
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  mbstate_t ps;
+
+  // Calculate the number of wide characters.  We walk through the string
+  // without writing the output, counting the number of wide characters.
+  size_t num_out_chars = 0;
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0; i < native_mb.size(); ) {
+    const char* src = native_mb.data() + i;
+    size_t res = mbrtowc(NULL, src, native_mb.size() - i, &ps);
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-2):
+      case static_cast<size_t>(-1):
+        return std::wstring();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        i += 1;  // Fall through.
+      default:
+        i += res;
+        ++num_out_chars;
+        break;
+    }
+  }
+
+  if (num_out_chars == 0)
+    return std::wstring();
+
+  std::wstring out;
+  out.resize(num_out_chars);
+
+  memset(&ps, 0, sizeof(ps));  // Clear the shift state.
+  // We walk the input string again, with |i| tracking the index of the
+  // multi-byte input, and |j| tracking the wide output.
+  for (size_t i = 0, j = 0; i < native_mb.size(); ++j) {
+    const char* src = native_mb.data() + i;
+    wchar_t* dst = &out[j];
+    size_t res = mbrtowc(dst, src, native_mb.size() - i, &ps);
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-2):
+      case static_cast<size_t>(-1):
+        return std::wstring();
+        break;
+      case 0:
+        i += 1;  // Skip null byte.
+        break;
+      default:
+        i += res;
+        break;
+    }
+  }
+
+  return out;
+}
+
+#endif  // OS_CHROMEOS
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc
new file mode 100644
index 0000000..0cdd428
--- /dev/null
+++ b/base/strings/sys_string_conversions_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_locale.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#ifdef WCHAR_T_IS_UTF32
+static const std::wstring kSysWideOldItalicLetterA = L"\x10300";
+#else
+static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00";
+#endif
+
+namespace base {
+
+TEST(SysStrings, SysWideToUTF8) {
+  EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world"));
+  EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d"));
+
+  // >16 bits
+  EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA));
+
+  // Error case. When Windows finds a UTF-16 character going off the end of
+  // a string, it just converts that literal value to UTF-8, even though this
+  // is invalid.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
+  //           SysWideToUTF8(L"\x4f60\xd800zyxw"));
+
+  // Test embedded NULLs.
+  std::wstring wide_null(L"a");
+  wide_null.push_back(0);
+  wide_null.push_back('b');
+
+  std::string expected_null("a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysWideToUTF8(wide_null));
+}
+
+TEST(SysStrings, SysUTF8ToWide) {
+  EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world"));
+  EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
+  // >16 bits
+  EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80"));
+
+  // Error case. When Windows finds an invalid UTF-8 character, it just skips
+  // it. This seems weird because it's inconsistent with the reverse conversion.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
+
+  // Test embedded NULLs.
+  std::string utf8_null("a");
+  utf8_null.push_back(0);
+  utf8_null.push_back('b');
+
+  std::wstring expected_null(L"a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
+}
+
+#if defined(OS_LINUX)  // Tests depend on setting a specific Linux locale.
+
+TEST(SysStrings, SysWideToNativeMB) {
+#if !defined(SYSTEM_NATIVE_UTF8)
+  ScopedLocale locale("en_US.utf-8");
+#endif
+  EXPECT_EQ("Hello, world", SysWideToNativeMB(L"Hello, world"));
+  EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToNativeMB(L"\x4f60\x597d"));
+
+  // >16 bits
+  EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToNativeMB(kSysWideOldItalicLetterA));
+
+  // Error case. When Windows finds a UTF-16 character going off the end of
+  // a string, it just converts that literal value to UTF-8, even though this
+  // is invalid.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
+  //           SysWideToNativeMB(L"\x4f60\xd800zyxw"));
+
+  // Test embedded NULLs.
+  std::wstring wide_null(L"a");
+  wide_null.push_back(0);
+  wide_null.push_back('b');
+
+  std::string expected_null("a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysWideToNativeMB(wide_null));
+}
+
+// We assume the test is running in a UTF8 locale.
+TEST(SysStrings, SysNativeMBToWide) {
+#if !defined(SYSTEM_NATIVE_UTF8)
+  ScopedLocale locale("en_US.utf-8");
+#endif
+  EXPECT_EQ(L"Hello, world", SysNativeMBToWide("Hello, world"));
+  EXPECT_EQ(L"\x4f60\x597d", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
+  // >16 bits
+  EXPECT_EQ(kSysWideOldItalicLetterA, SysNativeMBToWide("\xF0\x90\x8C\x80"));
+
+  // Error case. When Windows finds an invalid UTF-8 character, it just skips
+  // it. This seems weird because it's inconsistent with the reverse conversion.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ(L"\x4f60zyxw", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
+
+  // Test embedded NULLs.
+  std::string utf8_null("a");
+  utf8_null.push_back(0);
+  utf8_null.push_back('b');
+
+  std::wstring expected_null(L"a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysNativeMBToWide(utf8_null));
+}
+
+static const wchar_t* const kConvertRoundtripCases[] = {
+  L"Google Video",
+  // "网页 图片 资讯更多 »"
+  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
+  //  "Παγκόσμιος Ιστός"
+  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
+  // "Поиск страниц на русском"
+  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
+  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
+  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
+  // "전체서비스"
+  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
+
+  // Test characters that take more than 16 bits. This will depend on whether
+  // wchar_t is 16 or 32 bits.
+#if defined(WCHAR_T_IS_UTF16)
+  L"\xd800\xdf00",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
+#elif defined(WCHAR_T_IS_UTF32)
+  L"\x10300",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
+#endif
+};
+
+
+TEST(SysStrings, SysNativeMBAndWide) {
+#if !defined(SYSTEM_NATIVE_UTF8)
+  ScopedLocale locale("en_US.utf-8");
+#endif
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = SysNativeMBToWide(SysWideToNativeMB(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+
+  // We assume our test is running in UTF-8, so double check through ICU.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = SysNativeMBToWide(WideToUTF8(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = UTF8ToWide(SysWideToNativeMB(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+}
+#endif  // OS_LINUX
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_win.cc b/base/strings/sys_string_conversions_win.cc
new file mode 100644
index 0000000..94d4466
--- /dev/null
+++ b/base/strings/sys_string_conversions_win.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/sys_string_conversions.h"
+
+#include <windows.h>
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+  return SysWideToMultiByte(wide, CP_UTF8);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  return SysMultiByteToWide(utf8, CP_UTF8);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return SysWideToMultiByte(wide, CP_ACP);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysMultiByteToWide(native_mb, CP_ACP);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysMultiByteToWide(const StringPiece& mb, uint32 code_page) {
+  if (mb.empty())
+    return std::wstring();
+
+  int mb_length = static_cast<int>(mb.length());
+  // Compute the length of the buffer.
+  int charcount = MultiByteToWideChar(code_page, 0,
+                                      mb.data(), mb_length, NULL, 0);
+  if (charcount == 0)
+    return std::wstring();
+
+  std::wstring wide;
+  wide.resize(charcount);
+  MultiByteToWideChar(code_page, 0, mb.data(), mb_length, &wide[0], charcount);
+
+  return wide;
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToMultiByte(const std::wstring& wide, uint32 code_page) {
+  int wide_length = static_cast<int>(wide.length());
+  if (wide_length == 0)
+    return std::string();
+
+  // Compute the length of the buffer we'll need.
+  int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+                                      NULL, 0, NULL, NULL);
+  if (charcount == 0)
+    return std::string();
+
+  std::string mb;
+  mb.resize(charcount);
+  WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+                      &mb[0], charcount, NULL, NULL);
+
+  return mb;
+}
+
+}  // namespace base
diff --git a/base/strings/utf_offset_string_conversions.cc b/base/strings/utf_offset_string_conversions.cc
new file mode 100644
index 0000000..c2270bf
--- /dev/null
+++ b/base/strings/utf_offset_string_conversions.cc
@@ -0,0 +1,260 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_offset_string_conversions.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversion_utils.h"
+
+namespace base {
+
+OffsetAdjuster::Adjustment::Adjustment(size_t original_offset,
+                                       size_t original_length,
+                                       size_t output_length)
+    : original_offset(original_offset),
+      original_length(original_length),
+      output_length(output_length) {
+}
+
+// static
+void OffsetAdjuster::AdjustOffsets(
+    const Adjustments& adjustments,
+    std::vector<size_t>* offsets_for_adjustment) {
+  if (!offsets_for_adjustment || adjustments.empty())
+    return;
+  for (std::vector<size_t>::iterator i(offsets_for_adjustment->begin());
+       i != offsets_for_adjustment->end(); ++i)
+    AdjustOffset(adjustments, &(*i));
+}
+
+// static
+void OffsetAdjuster::AdjustOffset(const Adjustments& adjustments,
+                                  size_t* offset) {
+  if (*offset == string16::npos)
+    return;
+  int adjustment = 0;
+  for (Adjustments::const_iterator i = adjustments.begin();
+       i != adjustments.end(); ++i) {
+    if (*offset <= i->original_offset)
+      break;
+    if (*offset < (i->original_offset + i->original_length)) {
+      *offset = string16::npos;
+      return;
+    }
+    adjustment += static_cast<int>(i->original_length - i->output_length);
+  }
+  *offset -= adjustment;
+}
+
+// static
+void OffsetAdjuster::UnadjustOffsets(
+    const Adjustments& adjustments,
+    std::vector<size_t>* offsets_for_unadjustment) {
+  if (!offsets_for_unadjustment || adjustments.empty())
+    return;
+  for (std::vector<size_t>::iterator i(offsets_for_unadjustment->begin());
+       i != offsets_for_unadjustment->end(); ++i)
+    UnadjustOffset(adjustments, &(*i));
+}
+
+// static
+void OffsetAdjuster::UnadjustOffset(const Adjustments& adjustments,
+                                    size_t* offset) {
+  if (*offset == string16::npos)
+    return;
+  int adjustment = 0;
+  for (Adjustments::const_iterator i = adjustments.begin();
+       i != adjustments.end(); ++i) {
+    if (*offset + adjustment <= i->original_offset)
+      break;
+    adjustment += static_cast<int>(i->original_length - i->output_length);
+    if ((*offset + adjustment) <
+        (i->original_offset + i->original_length)) {
+      *offset = string16::npos;
+      return;
+    }
+  }
+  *offset += adjustment;
+}
+
+// static
+void OffsetAdjuster::MergeSequentialAdjustments(
+    const Adjustments& first_adjustments,
+    Adjustments* adjustments_on_adjusted_string) {
+  Adjustments::iterator adjusted_iter = adjustments_on_adjusted_string->begin();
+  Adjustments::const_iterator first_iter = first_adjustments.begin();
+  // Simultaneously iterate over all |adjustments_on_adjusted_string| and
+  // |first_adjustments|, adding adjustments to or correcting the adjustments
+  // in |adjustments_on_adjusted_string| as we go.  |shift| keeps track of the
+  // current number of characters collapsed by |first_adjustments| up to this
+  // point.  |currently_collapsing| keeps track of the number of characters
+  // collapsed by |first_adjustments| into the current |adjusted_iter|'s
+  // length.  These are characters that will change |shift| as soon as we're
+  // done processing the current |adjusted_iter|; they are not yet reflected in
+  // |shift|.
+  size_t shift = 0;
+  size_t currently_collapsing = 0;
+  while (adjusted_iter != adjustments_on_adjusted_string->end()) {
+    if ((first_iter == first_adjustments.end()) ||
+        ((adjusted_iter->original_offset + shift +
+          adjusted_iter->original_length) <= first_iter->original_offset)) {
+      // Entire |adjusted_iter| (accounting for its shift and including its
+      // whole original length) comes before |first_iter|.
+      //
+      // Correct the offset at |adjusted_iter| and move onto the next
+      // adjustment that needs revising.
+      adjusted_iter->original_offset += shift;
+      shift += currently_collapsing;
+      currently_collapsing = 0;
+      ++adjusted_iter;
+    } else if ((adjusted_iter->original_offset + shift) >
+               first_iter->original_offset) {
+      // |first_iter| comes before the |adjusted_iter| (as adjusted by |shift|).
+
+      // It's not possible for the adjustments to overlap.  (It shouldn't
+      // be possible that we have an |adjusted_iter->original_offset| that,
+      // when adjusted by the computed |shift|, is in the middle of
+      // |first_iter|'s output's length.  After all, that would mean the
+      // current adjustment_on_adjusted_string somehow points to an offset
+      // that was supposed to have been eliminated by the first set of
+      // adjustments.)
+      DCHECK_LE(first_iter->original_offset + first_iter->output_length,
+                adjusted_iter->original_offset + shift);
+
+      // Add the |first_adjustment_iter| to the full set of adjustments while
+      // making sure |adjusted_iter| continues pointing to the same element.
+      // We do this by inserting the |first_adjustment_iter| right before
+      // |adjusted_iter|, then incrementing |adjusted_iter| so it points to
+      // the following element.
+      shift += first_iter->original_length - first_iter->output_length;
+      adjusted_iter = adjustments_on_adjusted_string->insert(
+          adjusted_iter, *first_iter);
+      ++adjusted_iter;
+      ++first_iter;
+    } else {
+      // The first adjustment adjusted something that then got further adjusted
+      // by the second set of adjustments.  In other words, |first_iter| points
+      // to something in the range covered by |adjusted_iter|'s length (after
+      // accounting for |shift|).  Precisely,
+      //   adjusted_iter->original_offset + shift
+      //   <=
+      //   first_iter->original_offset
+      //   <=
+      //   adjusted_iter->original_offset + shift +
+      //       adjusted_iter->original_length
+
+      // Modify the current |adjusted_iter| to include whatever collapsing
+      // happened in |first_iter|, then advance to the next |first_adjustments|
+      // because we dealt with the current one.
+      const int collapse = static_cast<int>(first_iter->original_length) -
+          static_cast<int>(first_iter->output_length);
+      // This function does not know how to deal with a string that expands and
+      // then gets modified, only strings that collapse and then get modified.
+      DCHECK_GT(collapse, 0);
+      adjusted_iter->original_length += collapse;
+      currently_collapsing += collapse;
+      ++first_iter;
+    }
+  }
+  DCHECK_EQ(0u, currently_collapsing);
+  if (first_iter != first_adjustments.end()) {
+    // Only first adjustments are left.  These do not need to be modified.
+    // (Their offsets are already correct with respect to the original string.)
+    // Append them all.
+    DCHECK(adjusted_iter == adjustments_on_adjusted_string->end());
+    adjustments_on_adjusted_string->insert(
+        adjustments_on_adjusted_string->end(), first_iter,
+        first_adjustments.end());
+  }
+}
+
+// Converts the given source Unicode character type to the given destination
+// Unicode character type as a STL string. The given input buffer and size
+// determine the source, and the given output STL string will be replaced by
+// the result.  If non-NULL, |adjustments| is set to reflect the all the
+// alterations to the string that are not one-character-to-one-character.
+// It will always be sorted by increasing offset.
+template<typename SrcChar, typename DestStdString>
+bool ConvertUnicode(const SrcChar* src,
+                    size_t src_len,
+                    DestStdString* output,
+                    OffsetAdjuster::Adjustments* adjustments) {
+  if (adjustments)
+    adjustments->clear();
+  // ICU requires 32-bit numbers.
+  bool success = true;
+  int32 src_len32 = static_cast<int32>(src_len);
+  for (int32 i = 0; i < src_len32; i++) {
+    uint32 code_point;
+    size_t original_i = i;
+    size_t chars_written = 0;
+    if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
+      chars_written = WriteUnicodeCharacter(code_point, output);
+    } else {
+      chars_written = WriteUnicodeCharacter(0xFFFD, output);
+      success = false;
+    }
+
+    // Only bother writing an adjustment if this modification changed the
+    // length of this character.
+    // NOTE: ReadUnicodeCharacter() adjusts |i| to point _at_ the last
+    // character read, not after it (so that incrementing it in the loop
+    // increment will place it at the right location), so we need to account
+    // for that in determining the amount that was read.
+    if (adjustments && ((i - original_i + 1) != chars_written)) {
+      adjustments->push_back(OffsetAdjuster::Adjustment(
+          original_i, i - original_i + 1, chars_written));
+    }
+  }
+  return success;
+}
+
+bool UTF8ToUTF16WithAdjustments(
+    const char* src,
+    size_t src_len,
+    string16* output,
+    base::OffsetAdjuster::Adjustments* adjustments) {
+  PrepareForUTF16Or32Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output, adjustments);
+}
+
+string16 UTF8ToUTF16WithAdjustments(
+    const base::StringPiece& utf8,
+    base::OffsetAdjuster::Adjustments* adjustments) {
+  string16 result;
+  UTF8ToUTF16WithAdjustments(utf8.data(), utf8.length(), &result, adjustments);
+  return result;
+}
+
+string16 UTF8ToUTF16AndAdjustOffsets(
+    const base::StringPiece& utf8,
+    std::vector<size_t>* offsets_for_adjustment) {
+  std::for_each(offsets_for_adjustment->begin(),
+                offsets_for_adjustment->end(),
+                LimitOffset<base::StringPiece>(utf8.length()));
+  OffsetAdjuster::Adjustments adjustments;
+  string16 result = UTF8ToUTF16WithAdjustments(utf8, &adjustments);
+  OffsetAdjuster::AdjustOffsets(adjustments, offsets_for_adjustment);
+  return result;
+}
+
+std::string UTF16ToUTF8AndAdjustOffsets(
+    const base::StringPiece16& utf16,
+    std::vector<size_t>* offsets_for_adjustment) {
+  std::for_each(offsets_for_adjustment->begin(),
+                offsets_for_adjustment->end(),
+                LimitOffset<base::StringPiece16>(utf16.length()));
+  std::string result;
+  PrepareForUTF8Output(utf16.data(), utf16.length(), &result);
+  OffsetAdjuster::Adjustments adjustments;
+  ConvertUnicode(utf16.data(), utf16.length(), &result, &adjustments);
+  OffsetAdjuster::AdjustOffsets(adjustments, offsets_for_adjustment);
+  return result;
+}
+
+}  // namespace base
diff --git a/base/strings/utf_offset_string_conversions.h b/base/strings/utf_offset_string_conversions.h
new file mode 100644
index 0000000..d449489
--- /dev/null
+++ b/base/strings/utf_offset_string_conversions.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// A helper class and associated data structures to adjust offsets into a
+// string in response to various adjustments one might do to that string
+// (e.g., eliminating a range).  For details on offsets, see the comments by
+// the AdjustOffsets() function below.
+class BASE_EXPORT OffsetAdjuster {
+ public:
+  struct BASE_EXPORT Adjustment {
+    Adjustment(size_t original_offset,
+               size_t original_length,
+               size_t output_length);
+
+    size_t original_offset;
+    size_t original_length;
+    size_t output_length;
+  };
+  typedef std::vector<Adjustment> Adjustments;
+
+  // Adjusts all offsets in |offsets_for_adjustment| to reflect the adjustments
+  // recorded in |adjustments|.
+  //
+  // Offsets represents insertion/selection points between characters: if |src|
+  // is "abcd", then 0 is before 'a', 2 is between 'b' and 'c', and 4 is at the
+  // end of the string.  Valid input offsets range from 0 to |src_len|.  On
+  // exit, each offset will have been modified to point at the same logical
+  // position in the output string.  If an offset cannot be successfully
+  // adjusted (e.g., because it points into the middle of a multibyte sequence),
+  // it will be set to string16::npos.
+  static void AdjustOffsets(const Adjustments& adjustments,
+                            std::vector<size_t>* offsets_for_adjustment);
+
+  // Adjusts the single |offset| to reflect the adjustments recorded in
+  // |adjustments|.
+  static void AdjustOffset(const Adjustments& adjustments,
+                           size_t* offset);
+
+  // Adjusts all offsets in |offsets_for_unadjustment| to reflect the reverse
+  // of the adjustments recorded in |adjustments|.  In other words, the offsets
+  // provided represent offsets into an adjusted string and the caller wants
+  // to know the offsets they correspond to in the original string.  If an
+  // offset cannot be successfully unadjusted (e.g., because it points into
+  // the middle of a multibyte sequence), it will be set to string16::npos.
+  static void UnadjustOffsets(const Adjustments& adjustments,
+                              std::vector<size_t>* offsets_for_unadjustment);
+
+  // Adjusts the single |offset| to reflect the reverse of the adjustments
+  // recorded in |adjustments|.
+  static void UnadjustOffset(const Adjustments& adjustments,
+                             size_t* offset);
+
+  // Combines two sequential sets of adjustments, storing the combined revised
+  // adjustments in |adjustments_on_adjusted_string|.  That is, suppose a
+  // string was altered in some way, with the alterations recorded as
+  // adjustments in |first_adjustments|.  Then suppose the resulting string is
+  // further altered, with the alterations recorded as adjustments scored in
+  // |adjustments_on_adjusted_string|, with the offsets recorded in these
+  // adjustments being with respect to the intermediate string.  This function
+  // combines the two sets of adjustments into one, storing the result in
+  // |adjustments_on_adjusted_string|, whose offsets are correct with respect
+  // to the original string.
+  //
+  // Assumes both parameters are sorted by increasing offset.
+  //
+  // WARNING: Only supports |first_adjustments| that involve collapsing ranges
+  // of text, not expanding ranges.
+  static void MergeSequentialAdjustments(
+      const Adjustments& first_adjustments,
+      Adjustments* adjustments_on_adjusted_string);
+};
+
+// Like the conversions in utf_string_conversions.h, but also fills in an
+// |adjustments| parameter that reflects the alterations done to the string.
+// It may be NULL.
+BASE_EXPORT bool UTF8ToUTF16WithAdjustments(
+    const char* src,
+    size_t src_len,
+    string16* output,
+    base::OffsetAdjuster::Adjustments* adjustments);
+BASE_EXPORT string16 UTF8ToUTF16WithAdjustments(
+    const base::StringPiece& utf8,
+    base::OffsetAdjuster::Adjustments* adjustments);
+// As above, but instead internally examines the adjustments and applies them
+// to |offsets_for_adjustment|.  See comments by AdjustOffsets().
+BASE_EXPORT string16 UTF8ToUTF16AndAdjustOffsets(
+    const base::StringPiece& utf8,
+    std::vector<size_t>* offsets_for_adjustment);
+
+BASE_EXPORT std::string UTF16ToUTF8AndAdjustOffsets(
+    const base::StringPiece16& utf16,
+    std::vector<size_t>* offsets_for_adjustment);
+
+// Limiting function callable by std::for_each which will replace any value
+// which is greater than |limit| with npos.  Typically this is called with a
+// string length to clamp offsets into the string to [0, length] (as opposed to
+// [0, length); see comments above).
+template <typename T>
+struct LimitOffset {
+  explicit LimitOffset(size_t limit)
+    : limit_(limit) {}
+
+  void operator()(size_t& offset) {
+    if (offset > limit_)
+      offset = T::npos;
+  }
+
+  size_t limit_;
+};
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
diff --git a/base/strings/utf_offset_string_conversions_unittest.cc b/base/strings/utf_offset_string_conversions_unittest.cc
new file mode 100644
index 0000000..9398a56
--- /dev/null
+++ b/base/strings/utf_offset_string_conversions_unittest.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_offset_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+static const size_t kNpos = string16::npos;
+
+}  // namespace
+
+TEST(UTFOffsetStringConversionsTest, AdjustOffset) {
+  struct UTF8ToUTF16Case {
+    const char* utf8;
+    size_t input_offset;
+    size_t output_offset;
+  } utf8_to_utf16_cases[] = {
+    {"", 0, 0},
+    {"", kNpos, kNpos},
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", 1, kNpos},
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", 3, 1},
+    {"\xed\xb0\x80z", 3, 1},
+    {"A\xF0\x90\x8C\x80z", 1, 1},
+    {"A\xF0\x90\x8C\x80z", 2, kNpos},
+    {"A\xF0\x90\x8C\x80z", 5, 3},
+    {"A\xF0\x90\x8C\x80z", 6, 4},
+    {"A\xF0\x90\x8C\x80z", kNpos, kNpos},
+  };
+  for (size_t i = 0; i < arraysize(utf8_to_utf16_cases); ++i) {
+    const size_t offset = utf8_to_utf16_cases[i].input_offset;
+    std::vector<size_t> offsets;
+    offsets.push_back(offset);
+    UTF8ToUTF16AndAdjustOffsets(utf8_to_utf16_cases[i].utf8, &offsets);
+    EXPECT_EQ(utf8_to_utf16_cases[i].output_offset, offsets[0]);
+  }
+
+  struct UTF16ToUTF8Case {
+    char16 utf16[10];
+    size_t input_offset;
+    size_t output_offset;
+  } utf16_to_utf8_cases[] = {
+      {{}, 0, 0},
+      // Converted to 3-byte utf-8 sequences
+      {{0x5909, 0x63DB}, 3, kNpos},
+      {{0x5909, 0x63DB}, 2, 6},
+      {{0x5909, 0x63DB}, 1, 3},
+      {{0x5909, 0x63DB}, 0, 0},
+      // Converted to 2-byte utf-8 sequences
+      {{'A', 0x00bc, 0x00be, 'z'}, 1, 1},
+      {{'A', 0x00bc, 0x00be, 'z'}, 2, 3},
+      {{'A', 0x00bc, 0x00be, 'z'}, 3, 5},
+      {{'A', 0x00bc, 0x00be, 'z'}, 4, 6},
+      // Surrogate pair
+      {{'A', 0xd800, 0xdf00, 'z'}, 1, 1},
+      {{'A', 0xd800, 0xdf00, 'z'}, 2, kNpos},
+      {{'A', 0xd800, 0xdf00, 'z'}, 3, 5},
+      {{'A', 0xd800, 0xdf00, 'z'}, 4, 6},
+  };
+  for (size_t i = 0; i < arraysize(utf16_to_utf8_cases); ++i) {
+    size_t offset = utf16_to_utf8_cases[i].input_offset;
+    std::vector<size_t> offsets;
+    offsets.push_back(offset);
+    UTF16ToUTF8AndAdjustOffsets(utf16_to_utf8_cases[i].utf16, &offsets);
+    EXPECT_EQ(utf16_to_utf8_cases[i].output_offset, offsets[0]) << i;
+  }
+}
+
+TEST(UTFOffsetStringConversionsTest, LimitOffsets) {
+  const size_t kLimit = 10;
+  const size_t kItems = 20;
+  std::vector<size_t> size_ts;
+  for (size_t t = 0; t < kItems; ++t)
+    size_ts.push_back(t);
+  std::for_each(size_ts.begin(), size_ts.end(),
+                LimitOffset<string16>(kLimit));
+  size_t unlimited_count = 0;
+  for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end();
+       ++ti) {
+    if (*ti != kNpos)
+      ++unlimited_count;
+  }
+  EXPECT_EQ(11U, unlimited_count);
+
+  // Reverse the values in the vector and try again.
+  size_ts.clear();
+  for (size_t t = kItems; t > 0; --t)
+    size_ts.push_back(t - 1);
+  std::for_each(size_ts.begin(), size_ts.end(),
+                LimitOffset<string16>(kLimit));
+  unlimited_count = 0;
+  for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end();
+       ++ti) {
+    if (*ti != kNpos)
+      ++unlimited_count;
+  }
+  EXPECT_EQ(11U, unlimited_count);
+}
+
+TEST(UTFOffsetStringConversionsTest, AdjustOffsets) {
+  // Imagine we have strings as shown in the following cases where the
+  // X's represent encoded characters.
+  // 1: abcXXXdef ==> abcXdef
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 9; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1));
+    OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
+    size_t expected_1[] = {0, 1, 2, 3, kNpos, kNpos, 4, 5, 6, 7};
+    EXPECT_EQ(offsets.size(), arraysize(expected_1));
+    for (size_t i = 0; i < arraysize(expected_1); ++i)
+      EXPECT_EQ(expected_1[i], offsets[i]);
+  }
+
+  // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 23; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 1));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 2));
+    adjustments.push_back(OffsetAdjuster::Adjustment(10, 7, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(20, 3, 1));
+    OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
+    size_t expected_2[] = {
+      0, kNpos, kNpos, 1, 2, kNpos, kNpos, kNpos, 4, 5, 6, kNpos, kNpos, kNpos,
+      kNpos, kNpos, kNpos, 10, 11, 12, 13, kNpos, kNpos, 14
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_2));
+    for (size_t i = 0; i < arraysize(expected_2); ++i)
+      EXPECT_EQ(expected_2[i], offsets[i]);
+  }
+
+  // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 17; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 0));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(11, 3, 3));
+    adjustments.push_back(OffsetAdjuster::Adjustment(15, 2, 0));
+    OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
+    size_t expected_3[] = {
+      0, kNpos, kNpos, 0, 1, kNpos, kNpos, kNpos, 5, 6, 7, 8, kNpos, kNpos, 11,
+      12, kNpos, 12
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_3));
+    for (size_t i = 0; i < arraysize(expected_3); ++i)
+      EXPECT_EQ(expected_3[i], offsets[i]);
+  }
+}
+
+TEST(UTFOffsetStringConversionsTest, UnadjustOffsets) {
+  // Imagine we have strings as shown in the following cases where the
+  // X's represent encoded characters.
+  // 1: abcXXXdef ==> abcXdef
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 7; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1));
+    OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
+    size_t expected_1[] = {0, 1, 2, 3, 6, 7, 8, 9};
+    EXPECT_EQ(offsets.size(), arraysize(expected_1));
+    for (size_t i = 0; i < arraysize(expected_1); ++i)
+      EXPECT_EQ(expected_1[i], offsets[i]);
+  }
+
+  // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 14; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 1));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 2));
+    adjustments.push_back(OffsetAdjuster::Adjustment(10, 7, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(20, 3, 1));
+    OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
+    size_t expected_2[] = {
+      0, 3, 4, kNpos, 8, 9, 10, kNpos, kNpos, kNpos, 17, 18, 19, 20, 23
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_2));
+    for (size_t i = 0; i < arraysize(expected_2); ++i)
+      EXPECT_EQ(expected_2[i], offsets[i]);
+  }
+
+  // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 12; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 0));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(11, 3, 3));
+    adjustments.push_back(OffsetAdjuster::Adjustment(15, 2, 0));
+    OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
+    size_t expected_3[] = {
+      0,  // this could just as easily be 3
+      4, kNpos, kNpos, kNpos, 8, 9, 10, 11, kNpos, kNpos, 14,
+      15  // this could just as easily be 17
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_3));
+    for (size_t i = 0; i < arraysize(expected_3); ++i)
+      EXPECT_EQ(expected_3[i], offsets[i]);
+  }
+}
+
+// MergeSequentialAdjustments is used by net/base/escape.{h,cc} and
+// net/base/net_util.{h,cc}.  The two tests EscapeTest.AdjustOffset and
+// NetUtilTest.FormatUrlWithOffsets test its behavior extensively.  This
+// is simply a short, additional test.
+TEST(UTFOffsetStringConversionsTest, MergeSequentialAdjustments) {
+  // Pretend the input string is "abcdefghijklmnopqrstuvwxyz".
+
+  // Set up |first_adjustments| to
+  // - remove the leading "a"
+  // - combine the "bc" into one character (call it ".")
+  // - remove the "f"
+  // - remove the "tuv"
+  // The resulting string should be ".deghijklmnopqrswxyz".
+  OffsetAdjuster::Adjustments first_adjustments;
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(0, 1, 0));
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(1, 2, 1));
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(5, 1, 0));
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(19, 3, 0));
+
+  // Set up |adjustments_on_adjusted_string| to
+  // - combine the "." character that replaced "bc" with "d" into one character
+  //   (call it "?")
+  // - remove the "egh"
+  // - expand the "i" into two characters (call them "12")
+  // - combine the "jkl" into one character (call it "@")
+  // - expand the "z" into two characters (call it "34")
+  // The resulting string should be "?12@mnopqrswxy34".
+  OffsetAdjuster::Adjustments adjustments_on_adjusted_string;
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      0, 2, 1));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      2, 3, 0));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      5, 1, 2));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      6, 3, 1));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      19, 1, 2));
+
+  // Now merge the adjustments and check the results.
+  OffsetAdjuster::MergeSequentialAdjustments(first_adjustments,
+                                             &adjustments_on_adjusted_string);
+  // The merged adjustments should look like
+  // - combine abcd into "?"
+  //   - note: it's also reasonable for the Merge function to instead produce
+  //     two adjustments instead of this, one to remove a and another to
+  //     combine bcd into "?".  This test verifies the current behavior.
+  // - remove efgh
+  // - expand i into "12"
+  // - combine jkl into "@"
+  // - remove tuv
+  // - expand z into "34"
+  ASSERT_EQ(6u, adjustments_on_adjusted_string.size());
+  EXPECT_EQ(0u, adjustments_on_adjusted_string[0].original_offset);
+  EXPECT_EQ(4u, adjustments_on_adjusted_string[0].original_length);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[0].output_length);
+  EXPECT_EQ(4u, adjustments_on_adjusted_string[1].original_offset);
+  EXPECT_EQ(4u, adjustments_on_adjusted_string[1].original_length);
+  EXPECT_EQ(0u, adjustments_on_adjusted_string[1].output_length);
+  EXPECT_EQ(8u, adjustments_on_adjusted_string[2].original_offset);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[2].original_length);
+  EXPECT_EQ(2u, adjustments_on_adjusted_string[2].output_length);
+  EXPECT_EQ(9u, adjustments_on_adjusted_string[3].original_offset);
+  EXPECT_EQ(3u, adjustments_on_adjusted_string[3].original_length);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[3].output_length);
+  EXPECT_EQ(19u, adjustments_on_adjusted_string[4].original_offset);
+  EXPECT_EQ(3u, adjustments_on_adjusted_string[4].original_length);
+  EXPECT_EQ(0u, adjustments_on_adjusted_string[4].output_length);
+  EXPECT_EQ(25u, adjustments_on_adjusted_string[5].original_offset);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[5].original_length);
+  EXPECT_EQ(2u, adjustments_on_adjusted_string[5].output_length);
+}
+
+}  // namespace base
diff --git a/base/strings/utf_string_conversion_utils.cc b/base/strings/utf_string_conversion_utils.cc
new file mode 100644
index 0000000..022c0df
--- /dev/null
+++ b/base/strings/utf_string_conversion_utils.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversion_utils.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+bool ReadUnicodeCharacter(const char* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point_out) {
+  // U8_NEXT expects to be able to use -1 to signal an error, so we must
+  // use a signed type for code_point.  But this function returns false
+  // on error anyway, so code_point_out is unsigned.
+  int32 code_point;
+  CBU8_NEXT(src, *char_index, src_len, code_point);
+  *code_point_out = static_cast<uint32>(code_point);
+
+  // The ICU macro above moves to the next char, we want to point to the last
+  // char consumed.
+  (*char_index)--;
+
+  // Validate the decoded value.
+  return IsValidCodepoint(code_point);
+}
+
+bool ReadUnicodeCharacter(const char16* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point) {
+  if (CBU16_IS_SURROGATE(src[*char_index])) {
+    if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
+        *char_index + 1 >= src_len ||
+        !CBU16_IS_TRAIL(src[*char_index + 1])) {
+      // Invalid surrogate pair.
+      return false;
+    }
+
+    // Valid surrogate pair.
+    *code_point = CBU16_GET_SUPPLEMENTARY(src[*char_index],
+                                          src[*char_index + 1]);
+    (*char_index)++;
+  } else {
+    // Not a surrogate, just one 16-bit word.
+    *code_point = src[*char_index];
+  }
+
+  return IsValidCodepoint(*code_point);
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool ReadUnicodeCharacter(const wchar_t* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point) {
+  // Conversion is easy since the source is 32-bit.
+  *code_point = src[*char_index];
+
+  // Validate the value.
+  return IsValidCodepoint(*code_point);
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
+  if (code_point <= 0x7f) {
+    // Fast path the common case of one byte.
+    output->push_back(static_cast<char>(code_point));
+    return 1;
+  }
+
+
+  // CBU8_APPEND_UNSAFE can append up to 4 bytes.
+  size_t char_offset = output->length();
+  size_t original_char_offset = char_offset;
+  output->resize(char_offset + CBU8_MAX_LENGTH);
+
+  CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+
+  // CBU8_APPEND_UNSAFE will advance our pointer past the inserted character, so
+  // it will represent the new length of the string.
+  output->resize(char_offset);
+  return char_offset - original_char_offset;
+}
+
+size_t WriteUnicodeCharacter(uint32 code_point, string16* output) {
+  if (CBU16_LENGTH(code_point) == 1) {
+    // Thie code point is in the Basic Multilingual Plane (BMP).
+    output->push_back(static_cast<char16>(code_point));
+    return 1;
+  }
+  // Non-BMP characters use a double-character encoding.
+  size_t char_offset = output->length();
+  output->resize(char_offset + CBU16_MAX_LENGTH);
+  CBU16_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+  return CBU16_MAX_LENGTH;
+}
+
+// Generalized Unicode converter -----------------------------------------------
+
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src,
+                          size_t src_len,
+                          std::string* output) {
+  output->clear();
+  if (src_len == 0)
+    return;
+  if (src[0] < 0x80) {
+    // Assume that the entire input will be ASCII.
+    output->reserve(src_len);
+  } else {
+    // Assume that the entire input is non-ASCII and will have 3 bytes per char.
+    output->reserve(src_len * 3);
+  }
+}
+
+// Instantiate versions we know callers will need.
+template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*);
+template void PrepareForUTF8Output(const char16*, size_t, std::string*);
+
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src,
+                               size_t src_len,
+                               STRING* output) {
+  output->clear();
+  if (src_len == 0)
+    return;
+  if (static_cast<unsigned char>(src[0]) < 0x80) {
+    // Assume the input is all ASCII, which means 1:1 correspondence.
+    output->reserve(src_len);
+  } else {
+    // Otherwise assume that the UTF-8 sequences will have 2 bytes for each
+    // character.
+    output->reserve(src_len / 2);
+  }
+}
+
+// Instantiate versions we know callers will need.
+template void PrepareForUTF16Or32Output(const char*, size_t, std::wstring*);
+template void PrepareForUTF16Or32Output(const char*, size_t, string16*);
+
+}  // namespace base
diff --git a/base/strings/utf_string_conversion_utils.h b/base/strings/utf_string_conversion_utils.h
new file mode 100644
index 0000000..22abbbc
--- /dev/null
+++ b/base/strings/utf_string_conversion_utils.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
+
+// This should only be used by the various UTF string conversion files.
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+inline bool IsValidCodepoint(uint32 code_point) {
+  // Excludes the surrogate code points ([0xD800, 0xDFFF]) and
+  // codepoints larger than 0x10FFFF (the highest codepoint allowed).
+  // Non-characters and unassigned codepoints are allowed.
+  return code_point < 0xD800u ||
+         (code_point >= 0xE000u && code_point <= 0x10FFFFu);
+}
+
+inline bool IsValidCharacter(uint32 code_point) {
+  // Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in
+  // 0xFFFE or 0xFFFF) from the set of valid code points.
+  return code_point < 0xD800u || (code_point >= 0xE000u &&
+      code_point < 0xFDD0u) || (code_point > 0xFDEFu &&
+      code_point <= 0x10FFFFu && (code_point & 0xFFFEu) != 0xFFFEu);
+}
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+// Reads a UTF-8 stream, placing the next code point into the given output
+// |*code_point|. |src| represents the entire string to read, and |*char_index|
+// is the character offset within the string to start reading at. |*char_index|
+// will be updated to index the last character read, such that incrementing it
+// (as in a for loop) will take the reader to the next character.
+//
+// Returns true on success. On false, |*code_point| will be invalid.
+BASE_EXPORT bool ReadUnicodeCharacter(const char* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point_out);
+
+// Reads a UTF-16 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const char16* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Reads UTF-32 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point);
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+// Appends a UTF-8 character to the given 8-bit string.  Returns the number of
+// bytes written.
+// TODO(brettw) Bug 79631: This function should not be exposed.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point,
+                                         std::string* output);
+
+// Appends the given code point as a UTF-16 character to the given 16-bit
+// string.  Returns the number of 16-bit values written.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, string16* output);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Appends the given UTF-32 character to the given 32-bit string.  Returns the
+// number of 32-bit values written.
+inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) {
+  // This is the easy case, just append the character.
+  output->push_back(code_point);
+  return 1;
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Guesses the length of the output in UTF-8 in bytes, clears that output
+// string, and reserves that amount of space.  We assume that the input
+// character types are unsigned, which will be true for UTF-16 and -32 on our
+// systems.
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src, size_t src_len, std::string* output);
+
+// Prepares an output buffer (containing either UTF-16 or -32 data) given some
+// UTF-8 input that will be converted to it.  See PrepareForUTF8Output().
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src, size_t src_len, STRING* output);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
diff --git a/base/strings/utf_string_conversions.cc b/base/strings/utf_string_conversions.cc
new file mode 100644
index 0000000..1480d48
--- /dev/null
+++ b/base/strings/utf_string_conversions.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversions.h"
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversion_utils.h"
+
+namespace base {
+
+namespace {
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Converts the given source Unicode character type to the given destination
+// Unicode character type as a STL string. The given input buffer and size
+// determine the source, and the given output STL string will be replaced by
+// the result.
+template<typename SRC_CHAR, typename DEST_STRING>
+bool ConvertUnicode(const SRC_CHAR* src,
+                    size_t src_len,
+                    DEST_STRING* output) {
+  // ICU requires 32-bit numbers.
+  bool success = true;
+  int32 src_len32 = static_cast<int32>(src_len);
+  for (int32 i = 0; i < src_len32; i++) {
+    uint32 code_point;
+    if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
+      WriteUnicodeCharacter(code_point, output);
+    } else {
+      WriteUnicodeCharacter(0xFFFD, output);
+      success = false;
+    }
+  }
+
+  return success;
+}
+
+}  // namespace
+
+// UTF-8 <-> Wide --------------------------------------------------------------
+
+bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output) {
+  if (IsStringASCII(std::wstring(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF8Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+std::string WideToUTF8(const std::wstring& wide) {
+  if (IsStringASCII(wide)) {
+    return std::string(wide.data(), wide.data() + wide.length());
+  }
+
+  std::string ret;
+  PrepareForUTF8Output(wide.data(), wide.length(), &ret);
+  ConvertUnicode(wide.data(), wide.length(), &ret);
+  return ret;
+}
+
+bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) {
+  if (IsStringASCII(StringPiece(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF16Or32Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+std::wstring UTF8ToWide(const StringPiece& utf8) {
+  if (IsStringASCII(utf8)) {
+    return std::wstring(utf8.begin(), utf8.end());
+  }
+
+  std::wstring ret;
+  PrepareForUTF16Or32Output(utf8.data(), utf8.length(), &ret);
+  ConvertUnicode(utf8.data(), utf8.length(), &ret);
+  return ret;
+}
+
+// UTF-16 <-> Wide -------------------------------------------------------------
+
+#if defined(WCHAR_T_IS_UTF16)
+
+// When wide == UTF-16, then conversions are a NOP.
+bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) {
+  output->assign(src, src_len);
+  return true;
+}
+
+string16 WideToUTF16(const std::wstring& wide) {
+  return wide;
+}
+
+bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) {
+  output->assign(src, src_len);
+  return true;
+}
+
+std::wstring UTF16ToWide(const string16& utf16) {
+  return utf16;
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) {
+  output->clear();
+  // Assume that normally we won't have any non-BMP characters so the counts
+  // will be the same.
+  output->reserve(src_len);
+  return ConvertUnicode(src, src_len, output);
+}
+
+string16 WideToUTF16(const std::wstring& wide) {
+  string16 ret;
+  WideToUTF16(wide.data(), wide.length(), &ret);
+  return ret;
+}
+
+bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) {
+  output->clear();
+  // Assume that normally we won't have any non-BMP characters so the counts
+  // will be the same.
+  output->reserve(src_len);
+  return ConvertUnicode(src, src_len, output);
+}
+
+std::wstring UTF16ToWide(const string16& utf16) {
+  std::wstring ret;
+  UTF16ToWide(utf16.data(), utf16.length(), &ret);
+  return ret;
+}
+
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// UTF16 <-> UTF8 --------------------------------------------------------------
+
+#if defined(WCHAR_T_IS_UTF32)
+
+bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
+  if (IsStringASCII(StringPiece(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF16Or32Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+string16 UTF8ToUTF16(const StringPiece& utf8) {
+  if (IsStringASCII(utf8)) {
+    return string16(utf8.begin(), utf8.end());
+  }
+
+  string16 ret;
+  PrepareForUTF16Or32Output(utf8.data(), utf8.length(), &ret);
+  // Ignore the success flag of this call, it will do the best it can for
+  // invalid input, which is what we want here.
+  ConvertUnicode(utf8.data(), utf8.length(), &ret);
+  return ret;
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+  if (IsStringASCII(StringPiece16(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF8Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+std::string UTF16ToUTF8(const string16& utf16) {
+  if (IsStringASCII(utf16)) {
+    return std::string(utf16.begin(), utf16.end());
+  }
+
+  std::string ret;
+  // Ignore the success flag of this call, it will do the best it can for
+  // invalid input, which is what we want here.
+  UTF16ToUTF8(utf16.data(), utf16.length(), &ret);
+  return ret;
+}
+
+#elif defined(WCHAR_T_IS_UTF16)
+// Easy case since we can use the "wide" versions we already wrote above.
+
+bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
+  return UTF8ToWide(src, src_len, output);
+}
+
+string16 UTF8ToUTF16(const StringPiece& utf8) {
+  return UTF8ToWide(utf8);
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+  return WideToUTF8(src, src_len, output);
+}
+
+std::string UTF16ToUTF8(const string16& utf16) {
+  return WideToUTF8(utf16);
+}
+
+#endif
+
+string16 ASCIIToUTF16(const StringPiece& ascii) {
+  DCHECK(IsStringASCII(ascii)) << ascii;
+  return string16(ascii.begin(), ascii.end());
+}
+
+std::string UTF16ToASCII(const string16& utf16) {
+  DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
+  return std::string(utf16.begin(), utf16.end());
+}
+
+}  // namespace base
diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h
new file mode 100644
index 0000000..06a3bc6
--- /dev/null
+++ b/base/strings/utf_string_conversions.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// These convert between UTF-8, -16, and -32 strings. They are potentially slow,
+// so avoid unnecessary conversions. The low-level versions return a boolean
+// indicating whether the conversion was 100% valid. In this case, it will still
+// do the best it can and put the result in the output buffer. The versions that
+// return strings ignore this error and just return the best conversion
+// possible.
+BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
+                            std::string* output);
+BASE_EXPORT std::string WideToUTF8(const std::wstring& wide);
+BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len,
+                            std::wstring* output);
+BASE_EXPORT std::wstring UTF8ToWide(const StringPiece& utf8);
+
+BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
+                             string16* output);
+BASE_EXPORT string16 WideToUTF16(const std::wstring& wide);
+BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len,
+                             std::wstring* output);
+BASE_EXPORT std::wstring UTF16ToWide(const string16& utf16);
+
+BASE_EXPORT bool UTF8ToUTF16(const char* src, size_t src_len, string16* output);
+BASE_EXPORT string16 UTF8ToUTF16(const StringPiece& utf8);
+BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
+                             std::string* output);
+BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
+
+// This converts an ASCII string, typically a hardcoded constant, to a UTF16
+// string.
+BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
+
+// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
+// beforehand.
+BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
new file mode 100644
index 0000000..a7b12ff
--- /dev/null
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const wchar_t* const kConvertRoundtripCases[] = {
+  L"Google Video",
+  // "网页 图片 资讯更多 »"
+  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
+  //  "Παγκόσμιος Ιστός"
+  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
+  // "Поиск страниц на русском"
+  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
+  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
+  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
+  // "전체서비스"
+  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
+
+  // Test characters that take more than 16 bits. This will depend on whether
+  // wchar_t is 16 or 32 bits.
+#if defined(WCHAR_T_IS_UTF16)
+  L"\xd800\xdf00",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
+#elif defined(WCHAR_T_IS_UTF32)
+  L"\x10300",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
+#endif
+};
+
+}  // namespace
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
+  // we round-trip all the wide strings through UTF-8 to make sure everything
+  // agrees on the conversion. This uses the stream operators to test them
+  // simultaneously.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::ostringstream utf8;
+    utf8 << WideToUTF8(kConvertRoundtripCases[i]);
+    std::wostringstream wide;
+    wide << UTF8ToWide(utf8.str());
+
+    EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
+  }
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
+  // An empty std::wstring should be converted to an empty std::string,
+  // and vice versa.
+  std::wstring wempty;
+  std::string empty;
+  EXPECT_EQ(empty, WideToUTF8(wempty));
+  EXPECT_EQ(wempty, UTF8ToWide(empty));
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
+  struct UTF8ToWideCase {
+    const char* utf8;
+    const wchar_t* wide;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-8 input.
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
+    // Non-character is passed through.
+    {"\xef\xbf\xbfHello", L"\xffffHello", true},
+    // Truncated UTF-8 sequence.
+    {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // Truncated off the end.
+    {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
+    // Non-shortest-form UTF-8.
+    {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
+    {"\xed\xb0\x80", L"\xfffd", false},
+    // Non-BMP characters. The second is a non-character regarded as valid.
+    // The result will either be in UTF-16 or UTF-32.
+#if defined(WCHAR_T_IS_UTF16)
+    {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
+#elif defined(WCHAR_T_IS_UTF32)
+    {"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::wstring converted;
+    EXPECT_EQ(convert_cases[i].success,
+              UTF8ToWide(convert_cases[i].utf8,
+                         strlen(convert_cases[i].utf8),
+                         &converted));
+    std::wstring expected(convert_cases[i].wide);
+    EXPECT_EQ(expected, converted);
+  }
+
+  // Manually test an embedded NULL.
+  std::wstring converted;
+  EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
+  ASSERT_EQ(3U, converted.length());
+  EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
+  EXPECT_EQ('Z', converted[1]);
+  EXPECT_EQ('\t', converted[2]);
+
+  // Make sure that conversion replaces, not appends.
+  EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
+  ASSERT_EQ(1U, converted.length());
+  EXPECT_EQ('B', converted[0]);
+}
+
+#if defined(WCHAR_T_IS_UTF16)
+// This test is only valid when wchar_t == UTF-16.
+TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf16;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-16 input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    // Truncated at the end.
+    {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false},
+  };
+
+  for (int i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf16,
+                         wcslen(convert_cases[i].utf16),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+// This test is only valid when wchar_t == UTF-32.
+TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf32;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular 16-bit input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // Invalid Unicode code points.
+    {L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    {L"\xdc01Hello", "\xef\xbf\xbdHello", false},
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf32,
+                         wcslen(convert_cases[i].utf32),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+TEST(UTFStringConversionsTest, ConvertMultiString) {
+  static wchar_t wmulti[] = {
+    L'f', L'o', L'o', L'\0',
+    L'b', L'a', L'r', L'\0',
+    L'b', L'a', L'z', L'\0',
+    L'\0'
+  };
+  static char multi[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  std::wstring wmultistring;
+  memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti));
+  EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length());
+  std::string expected;
+  memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
+  EXPECT_EQ(arraysize(multi) - 1, expected.length());
+  const std::string& converted = WideToUTF8(wmultistring);
+  EXPECT_EQ(arraysize(multi) - 1, converted.length());
+  EXPECT_EQ(expected, converted);
+}
+
+}  // namespace base
diff --git a/base/supports_user_data.cc b/base/supports_user_data.cc
new file mode 100644
index 0000000..9689014
--- /dev/null
+++ b/base/supports_user_data.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/supports_user_data.h"
+
+namespace base {
+
+SupportsUserData::SupportsUserData() {
+  // Harmless to construct on a different thread to subsequent usage.
+  thread_checker_.DetachFromThread();
+}
+
+SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DataMap::const_iterator found = user_data_.find(key);
+  if (found != user_data_.end())
+    return found->second.get();
+  return NULL;
+}
+
+void SupportsUserData::SetUserData(const void* key, Data* data) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  user_data_[key] = linked_ptr<Data>(data);
+}
+
+void SupportsUserData::RemoveUserData(const void* key) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  user_data_.erase(key);
+}
+
+void SupportsUserData::DetachUserDataThread() {
+  thread_checker_.DetachFromThread();
+}
+
+SupportsUserData::~SupportsUserData() {
+  DCHECK(thread_checker_.CalledOnValidThread() || user_data_.empty());
+  DataMap local_user_data;
+  user_data_.swap(local_user_data);
+  // Now this->user_data_ is empty, and any destructors called transitively from
+  // the destruction of |local_user_data| will see it that way instead of
+  // examining a being-destroyed object.
+}
+
+}  // namespace base
diff --git a/base/supports_user_data.h b/base/supports_user_data.h
new file mode 100644
index 0000000..711ee7d
--- /dev/null
+++ b/base/supports_user_data.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SUPPORTS_USER_DATA_H_
+#define BASE_SUPPORTS_USER_DATA_H_
+
+#include <map>
+
+#include "base/base_export.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+// This is a helper for classes that want to allow users to stash random data by
+// key. At destruction all the objects will be destructed.
+class BASE_EXPORT SupportsUserData {
+ public:
+  SupportsUserData();
+
+  // Derive from this class and add your own data members to associate extra
+  // information with this object. Alternatively, add this as a public base
+  // class to any class with a virtual destructor.
+  class BASE_EXPORT Data {
+   public:
+    virtual ~Data() {}
+  };
+
+  // The user data allows the clients to associate data with this object.
+  // Multiple user data values can be stored under different keys.
+  // This object will TAKE OWNERSHIP of the given data pointer, and will
+  // delete the object if it is changed or the object is destroyed.
+  Data* GetUserData(const void* key) const;
+  void SetUserData(const void* key, Data* data);
+  void RemoveUserData(const void* key);
+
+  // SupportsUserData is not thread-safe, and on debug build will assert it is
+  // only used on one thread. Calling this method allows the caller to hand
+  // the SupportsUserData instance across threads. Use only if you are taking
+  // full control of the synchronization of that hand over.
+  void DetachUserDataThread();
+
+ protected:
+  virtual ~SupportsUserData();
+
+ private:
+  typedef std::map<const void*, linked_ptr<Data> > DataMap;
+
+  // Externally-defined data accessible by key.
+  DataMap user_data_;
+  // Guards usage of |user_data_|
+  ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(SupportsUserData);
+};
+
+// Adapter class that releases a refcounted object when the
+// SupportsUserData::Data object is deleted.
+template <typename T>
+class UserDataAdapter : public base::SupportsUserData::Data {
+ public:
+  static T* Get(const SupportsUserData* supports_user_data, const void* key) {
+    UserDataAdapter* data =
+      static_cast<UserDataAdapter*>(supports_user_data->GetUserData(key));
+    return data ? static_cast<T*>(data->object_.get()) : NULL;
+  }
+
+  UserDataAdapter(T* object) : object_(object) {}
+  T* release() { return object_.release(); }
+
+ private:
+  scoped_refptr<T> object_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserDataAdapter);
+};
+
+}  // namespace base
+
+#endif  // BASE_SUPPORTS_USER_DATA_H_
diff --git a/base/supports_user_data_unittest.cc b/base/supports_user_data_unittest.cc
new file mode 100644
index 0000000..faa8140
--- /dev/null
+++ b/base/supports_user_data_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/supports_user_data.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct TestSupportsUserData : public SupportsUserData {};
+
+struct UsesItself : public SupportsUserData::Data {
+  UsesItself(SupportsUserData* supports_user_data, const void* key)
+      : supports_user_data_(supports_user_data),
+        key_(key) {
+  }
+
+  ~UsesItself() override {
+    EXPECT_EQ(NULL, supports_user_data_->GetUserData(key_));
+  }
+
+  SupportsUserData* supports_user_data_;
+  const void* key_;
+};
+
+TEST(SupportsUserDataTest, ClearWorksRecursively) {
+  TestSupportsUserData supports_user_data;
+  char key = 0;
+  supports_user_data.SetUserData(&key,
+                                 new UsesItself(&supports_user_data, &key));
+  // Destruction of supports_user_data runs the actual test.
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/sync_socket.h b/base/sync_socket.h
new file mode 100644
index 0000000..36d6bc1
--- /dev/null
+++ b/base/sync_socket.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNC_SOCKET_H_
+#define BASE_SYNC_SOCKET_H_
+
+// A socket abstraction used for sending and receiving plain
+// data.  Because the receiving is blocking, they can be used to perform
+// rudimentary cross-process synchronization with low latency.
+
+#include "base/basictypes.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <sys/types.h>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace base {
+
+class BASE_EXPORT SyncSocket {
+ public:
+#if defined(OS_WIN)
+  typedef HANDLE Handle;
+  typedef Handle TransitDescriptor;
+#else
+  typedef int Handle;
+  typedef FileDescriptor TransitDescriptor;
+#endif
+  static const Handle kInvalidHandle;
+
+  SyncSocket();
+
+  // Creates a SyncSocket from a Handle.  Used in transport.
+  explicit SyncSocket(Handle handle) : handle_(handle)  {}
+  virtual ~SyncSocket();
+
+  // Initializes and connects a pair of sockets.
+  // |socket_a| and |socket_b| must not hold a valid handle.  Upon successful
+  // return, the sockets will both be valid and connected.
+  static bool CreatePair(SyncSocket* socket_a, SyncSocket* socket_b);
+
+  // Returns |Handle| wrapped in a |TransitDescriptor|.
+  static Handle UnwrapHandle(const TransitDescriptor& descriptor);
+
+  // Prepares a |TransitDescriptor| which wraps |Handle| used for transit.
+  // This is used to prepare the underlying shared resource before passing back
+  // the handle to be used by the peer process.
+  bool PrepareTransitDescriptor(ProcessHandle peer_process_handle,
+                                TransitDescriptor* descriptor);
+
+  // Closes the SyncSocket.  Returns true on success, false on failure.
+  virtual bool Close();
+
+  // Sends the message to the remote peer of the SyncSocket.
+  // Note it is not safe to send messages from the same socket handle by
+  // multiple threads simultaneously.
+  // buffer is a pointer to the data to send.
+  // length is the length of the data to send (must be non-zero).
+  // Returns the number of bytes sent, or 0 upon failure.
+  virtual size_t Send(const void* buffer, size_t length);
+
+  // Receives a message from an SyncSocket.
+  // buffer is a pointer to the buffer to receive data.
+  // length is the number of bytes of data to receive (must be non-zero).
+  // Returns the number of bytes received, or 0 upon failure.
+  virtual size_t Receive(void* buffer, size_t length);
+
+  // Same as Receive() but only blocks for data until |timeout| has elapsed or
+  // |buffer| |length| is exhausted.  Currently only timeouts less than one
+  // second are allowed.  Return the amount of data read.
+  virtual size_t ReceiveWithTimeout(void* buffer,
+                                    size_t length,
+                                    TimeDelta timeout);
+
+  // Returns the number of bytes available. If non-zero, Receive() will not
+  // not block when called. NOTE: Some implementations cannot reliably
+  // determine the number of bytes available so avoid using the returned
+  // size as a promise and simply test against zero.
+  size_t Peek();
+
+  // Extracts the contained handle.  Used for transferring between
+  // processes.
+  Handle handle() const { return handle_; }
+
+ protected:
+  Handle handle_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncSocket);
+};
+
+// Derives from SyncSocket and adds support for shutting down the socket from
+// another thread while a blocking Receive or Send is being done from the
+// thread that owns the socket.
+class BASE_EXPORT CancelableSyncSocket : public SyncSocket {
+ public:
+  CancelableSyncSocket();
+  explicit CancelableSyncSocket(Handle handle);
+  ~CancelableSyncSocket() override {}
+
+  // Initializes a pair of cancelable sockets.  See documentation for
+  // SyncSocket::CreatePair for more details.
+  static bool CreatePair(CancelableSyncSocket* socket_a,
+                         CancelableSyncSocket* socket_b);
+
+  // A way to shut down a socket even if another thread is currently performing
+  // a blocking Receive or Send.
+  bool Shutdown();
+
+#if defined(OS_WIN)
+  // Since the Linux and Mac implementations actually use a socket, shutting
+  // them down from another thread is pretty simple - we can just call
+  // shutdown().  However, the Windows implementation relies on named pipes
+  // and there isn't a way to cancel a blocking synchronous Read that is
+  // supported on <Vista. So, for Windows only, we override these
+  // SyncSocket methods in order to support shutting down the 'socket'.
+  bool Close() override;
+  size_t Receive(void* buffer, size_t length) override;
+  size_t ReceiveWithTimeout(void* buffer,
+                            size_t length,
+                            TimeDelta timeout) override;
+#endif
+
+  // Send() is overridden to catch cases where the remote end is not responding
+  // and we fill the local socket buffer. When the buffer is full, this
+  // implementation of Send() will not block indefinitely as
+  // SyncSocket::Send will, but instead return 0, as no bytes could be sent.
+  // Note that the socket will not be closed in this case.
+  size_t Send(const void* buffer, size_t length) override;
+
+ private:
+#if defined(OS_WIN)
+  WaitableEvent shutdown_event_;
+  WaitableEvent file_operation_;
+#endif
+  DISALLOW_COPY_AND_ASSIGN(CancelableSyncSocket);
+};
+
+#if defined(OS_WIN) && !defined(COMPONENT_BUILD)
+// TODO(cpu): remove this once chrome is split in two dlls.
+__declspec(selectany)
+    const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE;
+#endif
+
+}  // namespace base
+
+#endif  // BASE_SYNC_SOCKET_H_
diff --git a/base/sync_socket_nacl.cc b/base/sync_socket_nacl.cc
new file mode 100644
index 0000000..9e9243d
--- /dev/null
+++ b/base/sync_socket_nacl.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sync_socket.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {
+}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  return false;
+}
+
+// static
+SyncSocket::Handle SyncSocket::UnwrapHandle(
+    const SyncSocket::TransitDescriptor& descriptor) {
+  // TODO(xians): Still unclear how NaCl uses SyncSocket.
+  // See http://crbug.com/409656
+  NOTIMPLEMENTED();
+  return SyncSocket::kInvalidHandle;
+}
+
+bool SyncSocket::PrepareTransitDescriptor(
+    ProcessHandle peer_process_handle,
+    SyncSocket::TransitDescriptor* descriptor) {
+  // TODO(xians): Still unclear how NaCl uses SyncSocket.
+  // See http://crbug.com/409656
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool SyncSocket::Close() {
+  if (handle_ != kInvalidHandle) {
+    if (close(handle_) < 0)
+      DPLOG(ERROR) << "close";
+    handle_ = kInvalidHandle;
+  }
+  return true;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  const ssize_t bytes_written = write(handle_, buffer, length);
+  return bytes_written > 0 ? bytes_written : 0;
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  const ssize_t bytes_read = read(handle_, buffer, length);
+  return bytes_read > 0 ? bytes_read : 0;
+}
+
+size_t SyncSocket::ReceiveWithTimeout(void* buffer, size_t length, TimeDelta) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+size_t SyncSocket::Peek() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+CancelableSyncSocket::CancelableSyncSocket() {
+}
+
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle) {
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  return SyncSocket::Send(buffer, length);
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  return SyncSocket::Close();
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return SyncSocket::CreatePair(socket_a, socket_b);
+}
+
+}  // namespace base
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc
new file mode 100644
index 0000000..51b38a5
--- /dev/null
+++ b/base/sync_socket_posix.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sync_socket.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#if defined(OS_SOLARIS)
+#include <sys/filio.h>
+#endif
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+// To avoid users sending negative message lengths to Send/Receive
+// we clamp message lengths, which are size_t, to no more than INT_MAX.
+const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
+
+// Writes |length| of |buffer| into |handle|.  Returns the number of bytes
+// written or zero on error.  |length| must be greater than 0.
+size_t SendHelper(SyncSocket::Handle handle,
+                  const void* buffer,
+                  size_t length) {
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle, SyncSocket::kInvalidHandle);
+  const char* charbuffer = static_cast<const char*>(buffer);
+  return WriteFileDescriptor(handle, charbuffer, length)
+             ? static_cast<size_t>(length)
+             : 0;
+}
+
+bool CloseHandle(SyncSocket::Handle handle) {
+  if (handle != SyncSocket::kInvalidHandle && close(handle) < 0) {
+    DPLOG(ERROR) << "close";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  DCHECK_NE(socket_a, socket_b);
+  DCHECK_EQ(socket_a->handle_, kInvalidHandle);
+  DCHECK_EQ(socket_b->handle_, kInvalidHandle);
+
+#if defined(OS_MACOSX)
+  int nosigpipe = 1;
+#endif  // defined(OS_MACOSX)
+
+  Handle handles[2] = { kInvalidHandle, kInvalidHandle };
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+    CloseHandle(handles[0]);
+    CloseHandle(handles[1]);
+    return false;
+  }
+
+#if defined(OS_MACOSX)
+  // On OSX an attempt to read or write to a closed socket may generate a
+  // SIGPIPE rather than returning -1.  setsockopt will shut this off.
+  if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE,
+                      &nosigpipe, sizeof nosigpipe) ||
+      0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE,
+                      &nosigpipe, sizeof nosigpipe)) {
+    CloseHandle(handles[0]);
+    CloseHandle(handles[1]);
+    return false;
+  }
+#endif
+
+  // Copy the handles out for successful return.
+  socket_a->handle_ = handles[0];
+  socket_b->handle_ = handles[1];
+
+  return true;
+}
+
+// static
+SyncSocket::Handle SyncSocket::UnwrapHandle(
+    const TransitDescriptor& descriptor) {
+  return descriptor.fd;
+}
+
+bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle,
+                                          TransitDescriptor* descriptor) {
+  descriptor->fd = handle();
+  descriptor->auto_close = false;
+  return descriptor->fd != kInvalidHandle;
+}
+
+bool SyncSocket::Close() {
+  const bool retval = CloseHandle(handle_);
+  handle_ = kInvalidHandle;
+  return retval;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  return SendHelper(handle_, buffer, length);
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+  char* charbuffer = static_cast<char*>(buffer);
+  if (ReadFromFD(handle_, charbuffer, length))
+    return length;
+  return 0;
+}
+
+size_t SyncSocket::ReceiveWithTimeout(void* buffer,
+                                      size_t length,
+                                      TimeDelta timeout) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+
+  // TODO(dalecurtis): There's an undiagnosed issue on OSX where we're seeing
+  // large numbers of open files which prevents select() from being used.  In
+  // this case, the best we can do is Peek() to see if we can Receive() now or
+  // return a timeout error (0) if not.  See http://crbug.com/314364.
+  if (handle_ >= FD_SETSIZE)
+    return Peek() < length ? 0 : Receive(buffer, length);
+
+  // Only timeouts greater than zero and less than one second are allowed.
+  DCHECK_GT(timeout.InMicroseconds(), 0);
+  DCHECK_LT(timeout.InMicroseconds(),
+            base::TimeDelta::FromSeconds(1).InMicroseconds());
+
+  // Track the start time so we can reduce the timeout as data is read.
+  TimeTicks start_time = TimeTicks::Now();
+  const TimeTicks finish_time = start_time + timeout;
+
+  fd_set read_fds;
+  size_t bytes_read_total;
+  for (bytes_read_total = 0;
+       bytes_read_total < length && timeout.InMicroseconds() > 0;
+       timeout = finish_time - base::TimeTicks::Now()) {
+    FD_ZERO(&read_fds);
+    FD_SET(handle_, &read_fds);
+
+    // Wait for data to become available.
+    struct timeval timeout_struct =
+        { 0, static_cast<suseconds_t>(timeout.InMicroseconds()) };
+    const int select_result =
+        select(handle_ + 1, &read_fds, NULL, NULL, &timeout_struct);
+    // Handle EINTR manually since we need to update the timeout value.
+    if (select_result == -1 && errno == EINTR)
+      continue;
+    if (select_result <= 0)
+      return bytes_read_total;
+
+    // select() only tells us that data is ready for reading, not how much.  We
+    // must Peek() for the amount ready for reading to avoid blocking.
+    DCHECK(FD_ISSET(handle_, &read_fds));
+    const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total);
+
+    // There may be zero bytes to read if the socket at the other end closed.
+    if (!bytes_to_read)
+      return bytes_read_total;
+
+    const size_t bytes_received =
+        Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read);
+    bytes_read_total += bytes_received;
+    if (bytes_received != bytes_to_read)
+      return bytes_read_total;
+  }
+
+  return bytes_read_total;
+}
+
+size_t SyncSocket::Peek() {
+  DCHECK_NE(handle_, kInvalidHandle);
+  int number_chars = 0;
+  if (ioctl(handle_, FIONREAD, &number_chars) == -1) {
+    // If there is an error in ioctl, signal that the channel would block.
+    return 0;
+  }
+  DCHECK_GE(number_chars, 0);
+  return number_chars;
+}
+
+CancelableSyncSocket::CancelableSyncSocket() {}
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle) {
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  DCHECK_NE(handle_, kInvalidHandle);
+  return HANDLE_EINTR(shutdown(handle_, SHUT_RDWR)) >= 0;
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+
+  const long flags = fcntl(handle_, F_GETFL, NULL);
+  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
+    // Set the socket to non-blocking mode for sending if its original mode
+    // is blocking.
+    fcntl(handle_, F_SETFL, flags | O_NONBLOCK);
+  }
+
+  const size_t len = SendHelper(handle_, buffer, length);
+
+  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
+    // Restore the original flags.
+    fcntl(handle_, F_SETFL, flags);
+  }
+
+  return len;
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return SyncSocket::CreatePair(socket_a, socket_b);
+}
+
+}  // namespace base
diff --git a/base/sync_socket_unittest.cc b/base/sync_socket_unittest.cc
new file mode 100644
index 0000000..7c8c97c
--- /dev/null
+++ b/base/sync_socket_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/sync_socket.h"
+#include "base/threading/simple_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kReceiveTimeoutInMilliseconds = 750;
+
+class HangingReceiveThread : public base::DelegateSimpleThread::Delegate {
+ public:
+  explicit HangingReceiveThread(base::SyncSocket* socket)
+      : socket_(socket),
+        thread_(this, "HangingReceiveThread") {
+    thread_.Start();
+  }
+
+  ~HangingReceiveThread() override {}
+
+  void Run() override {
+    int data = 0;
+    ASSERT_EQ(socket_->Peek(), 0u);
+
+    // Use receive with timeout so we don't hang the test harness indefinitely.
+    ASSERT_EQ(0u, socket_->ReceiveWithTimeout(
+        &data, sizeof(data), base::TimeDelta::FromMilliseconds(
+            kReceiveTimeoutInMilliseconds)));
+  }
+
+  void Stop() {
+    thread_.Join();
+  }
+
+ private:
+  base::SyncSocket* socket_;
+  base::DelegateSimpleThread thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(HangingReceiveThread);
+};
+
+// Tests sending data between two SyncSockets.  Uses ASSERT() and thus will exit
+// early upon failure.  Callers should use ASSERT_NO_FATAL_FAILURE() if testing
+// continues after return.
+void SendReceivePeek(base::SyncSocket* socket_a, base::SyncSocket* socket_b) {
+  int received = 0;
+  const int kSending = 123;
+  COMPILE_ASSERT(sizeof(kSending) == sizeof(received), Invalid_Data_Size);
+
+  ASSERT_EQ(0u, socket_a->Peek());
+  ASSERT_EQ(0u, socket_b->Peek());
+
+  // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from
+  // |socket_a|.
+  ASSERT_EQ(sizeof(kSending), socket_a->Send(&kSending, sizeof(kSending)));
+  ASSERT_EQ(sizeof(kSending), socket_b->Peek());
+  ASSERT_EQ(sizeof(kSending), socket_b->Receive(&received, sizeof(kSending)));
+  ASSERT_EQ(kSending, received);
+
+  ASSERT_EQ(0u, socket_a->Peek());
+  ASSERT_EQ(0u, socket_b->Peek());
+
+  // Now verify the reverse.
+  received = 0;
+  ASSERT_EQ(sizeof(kSending), socket_b->Send(&kSending, sizeof(kSending)));
+  ASSERT_EQ(sizeof(kSending), socket_a->Peek());
+  ASSERT_EQ(sizeof(kSending), socket_a->Receive(&received, sizeof(kSending)));
+  ASSERT_EQ(kSending, received);
+
+  ASSERT_EQ(0u, socket_a->Peek());
+  ASSERT_EQ(0u, socket_b->Peek());
+
+  ASSERT_TRUE(socket_a->Close());
+  ASSERT_TRUE(socket_b->Close());
+}
+
+template <class SocketType>
+void NormalSendReceivePeek() {
+  SocketType socket_a, socket_b;
+  ASSERT_TRUE(SocketType::CreatePair(&socket_a, &socket_b));
+  SendReceivePeek(&socket_a, &socket_b);
+}
+
+template <class SocketType>
+void ClonedSendReceivePeek() {
+  SocketType socket_a, socket_b;
+  ASSERT_TRUE(SocketType::CreatePair(&socket_a, &socket_b));
+
+  // Create new SyncSockets from the paired handles.
+  SocketType socket_c(socket_a.handle()), socket_d(socket_b.handle());
+  SendReceivePeek(&socket_c, &socket_d);
+}
+
+}  // namespace
+
+TEST(SyncSocket, NormalSendReceivePeek) {
+  NormalSendReceivePeek<base::SyncSocket>();
+}
+
+TEST(SyncSocket, ClonedSendReceivePeek) {
+  ClonedSendReceivePeek<base::SyncSocket>();
+}
+
+TEST(CancelableSyncSocket, NormalSendReceivePeek) {
+  NormalSendReceivePeek<base::CancelableSyncSocket>();
+}
+
+TEST(CancelableSyncSocket, ClonedSendReceivePeek) {
+  ClonedSendReceivePeek<base::CancelableSyncSocket>();
+}
+
+TEST(CancelableSyncSocket, CancelReceiveShutdown) {
+  base::CancelableSyncSocket socket_a, socket_b;
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&socket_a, &socket_b));
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  HangingReceiveThread thread(&socket_b);
+  ASSERT_TRUE(socket_b.Shutdown());
+  thread.Stop();
+
+  // Ensure the receive didn't just timeout.
+  ASSERT_LT((base::TimeTicks::Now() - start).InMilliseconds(),
+            kReceiveTimeoutInMilliseconds);
+
+  ASSERT_TRUE(socket_a.Close());
+  ASSERT_TRUE(socket_b.Close());
+}
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc
new file mode 100644
index 0000000..e508816
--- /dev/null
+++ b/base/sync_socket_win.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sync_socket.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+using win::ScopedHandle;
+
+namespace {
+// IMPORTANT: do not change how this name is generated because it will break
+// in sandboxed scenarios as we might have by-name policies that allow pipe
+// creation. Also keep the secure random number generation.
+const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu";
+const size_t kPipePathMax =  arraysize(kPipeNameFormat) + (3 * 10) + 1;
+
+// To avoid users sending negative message lengths to Send/Receive
+// we clamp message lengths, which are size_t, to no more than INT_MAX.
+const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
+
+const int kOutBufferSize = 4096;
+const int kInBufferSize = 4096;
+const int kDefaultTimeoutMilliSeconds = 1000;
+
+bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) {
+  DCHECK_NE(socket_a, socket_b);
+  DCHECK_EQ(*socket_a, SyncSocket::kInvalidHandle);
+  DCHECK_EQ(*socket_b, SyncSocket::kInvalidHandle);
+
+  wchar_t name[kPipePathMax];
+  ScopedHandle handle_a;
+  DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE;
+  if (overlapped)
+    flags |= FILE_FLAG_OVERLAPPED;
+
+  do {
+    unsigned int rnd_name;
+    if (rand_s(&rnd_name) != 0)
+      return false;
+
+    swprintf(name, kPipePathMax,
+             kPipeNameFormat,
+             GetCurrentProcessId(),
+             GetCurrentThreadId(),
+             rnd_name);
+
+    handle_a.Set(CreateNamedPipeW(
+        name,
+        flags,
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+        1,
+        kOutBufferSize,
+        kInBufferSize,
+        kDefaultTimeoutMilliSeconds,
+        NULL));
+  } while (!handle_a.IsValid() &&
+           (GetLastError() == ERROR_PIPE_BUSY));
+
+  if (!handle_a.IsValid()) {
+    NOTREACHED();
+    return false;
+  }
+
+  // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot
+  // impersonate the client (handle_b). This allows us not to care which side
+  // ends up in which side of a privilege boundary.
+  flags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
+  if (overlapped)
+    flags |= FILE_FLAG_OVERLAPPED;
+
+  ScopedHandle handle_b(CreateFileW(name,
+                                    GENERIC_READ | GENERIC_WRITE,
+                                    0,          // no sharing.
+                                    NULL,       // default security attributes.
+                                    OPEN_EXISTING,  // opens existing pipe.
+                                    flags,
+                                    NULL));     // no template file.
+  if (!handle_b.IsValid()) {
+    DPLOG(ERROR) << "CreateFileW failed";
+    return false;
+  }
+
+  if (!ConnectNamedPipe(handle_a.Get(), NULL)) {
+    DWORD error = GetLastError();
+    if (error != ERROR_PIPE_CONNECTED) {
+      DPLOG(ERROR) << "ConnectNamedPipe failed";
+      return false;
+    }
+  }
+
+  *socket_a = handle_a.Take();
+  *socket_b = handle_b.Take();
+
+  return true;
+}
+
+// Inline helper to avoid having the cast everywhere.
+DWORD GetNextChunkSize(size_t current_pos, size_t max_size) {
+  // The following statement is for 64 bit portability.
+  return static_cast<DWORD>(((max_size - current_pos) <= UINT_MAX) ?
+      (max_size - current_pos) : UINT_MAX);
+}
+
+// Template function that supports calling ReadFile or WriteFile in an
+// overlapped fashion and waits for IO completion.  The function also waits
+// on an event that can be used to cancel the operation.  If the operation
+// is cancelled, the function returns and closes the relevant socket object.
+template <typename BufferType, typename Function>
+size_t CancelableFileOperation(Function operation,
+                               HANDLE file,
+                               BufferType* buffer,
+                               size_t length,
+                               WaitableEvent* io_event,
+                               WaitableEvent* cancel_event,
+                               CancelableSyncSocket* socket,
+                               DWORD timeout_in_ms) {
+  ThreadRestrictions::AssertIOAllowed();
+  // The buffer must be byte size or the length check won't make much sense.
+  COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type);
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(file, SyncSocket::kInvalidHandle);
+
+  // Track the finish time so we can calculate the timeout as data is read.
+  TimeTicks current_time, finish_time;
+  if (timeout_in_ms != INFINITE) {
+    current_time = TimeTicks::Now();
+    finish_time =
+        current_time + base::TimeDelta::FromMilliseconds(timeout_in_ms);
+  }
+
+  size_t count = 0;
+  do {
+    // The OVERLAPPED structure will be modified by ReadFile or WriteFile.
+    OVERLAPPED ol = { 0 };
+    ol.hEvent = io_event->handle();
+
+    const DWORD chunk = GetNextChunkSize(count, length);
+    // This is either the ReadFile or WriteFile call depending on whether
+    // we're receiving or sending data.
+    DWORD len = 0;
+    const BOOL operation_ok = operation(
+        file, static_cast<BufferType*>(buffer) + count, chunk, &len, &ol);
+    if (!operation_ok) {
+      if (::GetLastError() == ERROR_IO_PENDING) {
+        HANDLE events[] = { io_event->handle(), cancel_event->handle() };
+        const int wait_result = WaitForMultipleObjects(
+            arraysize(events), events, FALSE,
+            timeout_in_ms == INFINITE ?
+                timeout_in_ms :
+                static_cast<DWORD>(
+                    (finish_time - current_time).InMilliseconds()));
+        if (wait_result != WAIT_OBJECT_0 + 0) {
+          // CancelIo() doesn't synchronously cancel outstanding IO, only marks
+          // outstanding IO for cancellation. We must call GetOverlappedResult()
+          // below to ensure in flight writes complete before returning.
+          CancelIo(file);
+        }
+
+        // We set the |bWait| parameter to TRUE for GetOverlappedResult() to
+        // ensure writes are complete before returning.
+        if (!GetOverlappedResult(file, &ol, &len, TRUE))
+          len = 0;
+
+        if (wait_result == WAIT_OBJECT_0 + 1) {
+          DVLOG(1) << "Shutdown was signaled. Closing socket.";
+          socket->Close();
+          return count;
+        }
+
+        // Timeouts will be handled by the while() condition below since
+        // GetOverlappedResult() may complete successfully after CancelIo().
+        DCHECK(wait_result == WAIT_OBJECT_0 + 0 || wait_result == WAIT_TIMEOUT);
+      } else {
+        break;
+      }
+    }
+
+    count += len;
+
+    // Quit the operation if we can't write/read anymore.
+    if (len != chunk)
+      break;
+
+    // Since TimeTicks::Now() is expensive, only bother updating the time if we
+    // have more work to do.
+    if (timeout_in_ms != INFINITE && count < length)
+      current_time = base::TimeTicks::Now();
+  } while (count < length &&
+           (timeout_in_ms == INFINITE || current_time < finish_time));
+
+  return count;
+}
+
+}  // namespace
+
+#if defined(COMPONENT_BUILD)
+const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE;
+#endif
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false);
+}
+
+// static
+SyncSocket::Handle SyncSocket::UnwrapHandle(
+    const TransitDescriptor& descriptor) {
+  return descriptor;
+}
+
+bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle,
+                                          TransitDescriptor* descriptor) {
+  DCHECK(descriptor);
+  if (!::DuplicateHandle(GetCurrentProcess(), handle(), peer_process_handle,
+                         descriptor, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+    DPLOG(ERROR) << "Cannot duplicate socket handle for peer process.";
+    return false;
+  }
+  return true;
+}
+
+bool SyncSocket::Close() {
+  if (handle_ == kInvalidHandle)
+    return true;
+
+  const BOOL result = CloseHandle(handle_);
+  handle_ = kInvalidHandle;
+  return result == TRUE;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+  size_t count = 0;
+  while (count < length) {
+    DWORD len;
+    DWORD chunk = GetNextChunkSize(count, length);
+    if (WriteFile(handle_, static_cast<const char*>(buffer) + count,
+                  chunk, &len, NULL) == FALSE) {
+      return count;
+    }
+    count += len;
+  }
+  return count;
+}
+
+size_t SyncSocket::ReceiveWithTimeout(void* buffer,
+                                      size_t length,
+                                      TimeDelta timeout) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+  size_t count = 0;
+  while (count < length) {
+    DWORD len;
+    DWORD chunk = GetNextChunkSize(count, length);
+    if (ReadFile(handle_, static_cast<char*>(buffer) + count,
+                 chunk, &len, NULL) == FALSE) {
+      return count;
+    }
+    count += len;
+  }
+  return count;
+}
+
+size_t SyncSocket::Peek() {
+  DWORD available = 0;
+  PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL);
+  return available;
+}
+
+CancelableSyncSocket::CancelableSyncSocket()
+    : shutdown_event_(true, false), file_operation_(true, false) {
+}
+
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle), shutdown_event_(true, false),
+      file_operation_(true, false) {
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  // This doesn't shut down the pipe immediately, but subsequent Receive or Send
+  // methods will fail straight away.
+  shutdown_event_.Signal();
+  return true;
+}
+
+bool CancelableSyncSocket::Close() {
+  const bool result = SyncSocket::Close();
+  shutdown_event_.Reset();
+  return result;
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  static const DWORD kWaitTimeOutInMs = 500;
+  return CancelableFileOperation(
+      &WriteFile, handle_, reinterpret_cast<const char*>(buffer),
+      length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs);
+}
+
+size_t CancelableSyncSocket::Receive(void* buffer, size_t length) {
+  return CancelableFileOperation(
+      &ReadFile, handle_, reinterpret_cast<char*>(buffer), length,
+      &file_operation_, &shutdown_event_, this, INFINITE);
+}
+
+size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer,
+                                                size_t length,
+                                                TimeDelta timeout) {
+  return CancelableFileOperation(
+      &ReadFile, handle_, reinterpret_cast<char*>(buffer), length,
+      &file_operation_, &shutdown_event_, this,
+      static_cast<DWORD>(timeout.InMilliseconds()));
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true);
+}
+
+}  // namespace base
diff --git a/base/synchronization/cancellation_flag.cc b/base/synchronization/cancellation_flag.cc
new file mode 100644
index 0000000..ca5c0a8
--- /dev/null
+++ b/base/synchronization/cancellation_flag.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/cancellation_flag.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+void CancellationFlag::Set() {
+#if !defined(NDEBUG)
+  DCHECK_EQ(set_on_, PlatformThread::CurrentId());
+#endif
+  base::subtle::Release_Store(&flag_, 1);
+}
+
+bool CancellationFlag::IsSet() const {
+  return base::subtle::Acquire_Load(&flag_) != 0;
+}
+
+void CancellationFlag::UnsafeResetForTesting() {
+  base::subtle::Release_Store(&flag_, 0);
+}
+
+}  // namespace base
diff --git a/base/synchronization/cancellation_flag.h b/base/synchronization/cancellation_flag.h
new file mode 100644
index 0000000..0f0f08e
--- /dev/null
+++ b/base/synchronization/cancellation_flag.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+
+#include "base/base_export.h"
+#include "base/atomicops.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// CancellationFlag allows one thread to cancel jobs executed on some worker
+// thread. Calling Set() from one thread and IsSet() from a number of threads
+// is thread-safe.
+//
+// This class IS NOT intended for synchronization between threads.
+class BASE_EXPORT CancellationFlag {
+ public:
+  CancellationFlag() : flag_(false) {
+#if !defined(NDEBUG)
+    set_on_ = PlatformThread::CurrentId();
+#endif
+  }
+  ~CancellationFlag() {}
+
+  // Set the flag. May only be called on the thread which owns the object.
+  void Set();
+  bool IsSet() const;  // Returns true iff the flag was set.
+
+  // For subtle reasons that may be different on different architectures,
+  // a different thread testing IsSet() may erroneously read 'true' after
+  // this method has been called.
+  void UnsafeResetForTesting();
+
+ private:
+  base::subtle::Atomic32 flag_;
+#if !defined(NDEBUG)
+  PlatformThreadId set_on_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(CancellationFlag);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
diff --git a/base/synchronization/cancellation_flag_unittest.cc b/base/synchronization/cancellation_flag_unittest.cc
new file mode 100644
index 0000000..13c74bc
--- /dev/null
+++ b/base/synchronization/cancellation_flag_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests of CancellationFlag class.
+
+#include "base/synchronization/cancellation_flag.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Define our test class.
+//------------------------------------------------------------------------------
+
+void CancelHelper(CancellationFlag* flag) {
+#if GTEST_HAS_DEATH_TEST
+  ASSERT_DEBUG_DEATH(flag->Set(), "");
+#endif
+}
+
+TEST(CancellationFlagTest, SimpleSingleThreadedTest) {
+  CancellationFlag flag;
+  ASSERT_FALSE(flag.IsSet());
+  flag.Set();
+  ASSERT_TRUE(flag.IsSet());
+}
+
+TEST(CancellationFlagTest, DoubleSetTest) {
+  CancellationFlag flag;
+  ASSERT_FALSE(flag.IsSet());
+  flag.Set();
+  ASSERT_TRUE(flag.IsSet());
+  flag.Set();
+  ASSERT_TRUE(flag.IsSet());
+}
+
+TEST(CancellationFlagTest, SetOnDifferentThreadDeathTest) {
+  // Checks that Set() can't be called from any other thread.
+  // CancellationFlag should die on a DCHECK if Set() is called from
+  // other thread.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  Thread t("CancellationFlagTest.SetOnDifferentThreadDeathTest");
+  ASSERT_TRUE(t.Start());
+  ASSERT_TRUE(t.message_loop());
+  ASSERT_TRUE(t.IsRunning());
+
+  CancellationFlag flag;
+  t.task_runner()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h
new file mode 100644
index 0000000..5d8507d
--- /dev/null
+++ b/base/synchronization/condition_variable.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ConditionVariable wraps pthreads condition variable synchronization or, on
+// Windows, simulates it.  This functionality is very helpful for having
+// several threads wait for an event, as is common with a thread pool managed
+// by a master.  The meaning of such an event in the (worker) thread pool
+// scenario is that additional tasks are now available for processing.  It is
+// used in Chrome in the DNS prefetching system to notify worker threads that
+// a queue now has items (tasks) which need to be tended to.  A related use
+// would have a pool manager waiting on a ConditionVariable, waiting for a
+// thread in the pool to announce (signal) that there is now more room in a
+// (bounded size) communications queue for the manager to deposit tasks, or,
+// as a second example, that the queue of tasks is completely empty and all
+// workers are waiting.
+//
+// USAGE NOTE 1: spurious signal events are possible with this and
+// most implementations of condition variables.  As a result, be
+// *sure* to retest your condition before proceeding.  The following
+// is a good example of doing this correctly:
+//
+// while (!work_to_be_done()) Wait(...);
+//
+// In contrast do NOT do the following:
+//
+// if (!work_to_be_done()) Wait(...);  // Don't do this.
+//
+// Especially avoid the above if you are relying on some other thread only
+// issuing a signal up *if* there is work-to-do.  There can/will
+// be spurious signals.  Recheck state on waiting thread before
+// assuming the signal was intentional. Caveat caller ;-).
+//
+// USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
+// which leads to contention for the locks they all held when they
+// called Wait().  This results in POOR performance.  A much better
+// approach to getting a lot of threads out of Wait() is to have each
+// thread (upon exiting Wait()) call Signal() to free up another
+// Wait'ing thread.  Look at condition_variable_unittest.cc for
+// both examples.
+//
+// Broadcast() can be used nicely during teardown, as it gets the job
+// done, and leaves no sleeping threads... and performance is less
+// critical at that point.
+//
+// The semantics of Broadcast() are carefully crafted so that *all*
+// threads that were waiting when the request was made will indeed
+// get signaled.  Some implementations mess up, and don't signal them
+// all, while others allow the wait to be effectively turned off (for
+// a while while waiting threads come around).  This implementation
+// appears correct, as it will not "lose" any signals, and will guarantee
+// that all threads get signaled by Broadcast().
+//
+// This implementation offers support for "performance" in its selection of
+// which thread to revive.  Performance, in direct contrast with "fairness,"
+// assures that the thread that most recently began to Wait() is selected by
+// Signal to revive.  Fairness would (if publicly supported) assure that the
+// thread that has Wait()ed the longest is selected. The default policy
+// may improve performance, as the selected thread may have a greater chance of
+// having some of its stack data in various CPU caches.
+//
+// For a discussion of the many very subtle implementation details, see the FAQ
+// at the end of condition_variable_win.cc.
+
+#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class ConditionVarImpl;
+class TimeDelta;
+
+class BASE_EXPORT ConditionVariable {
+ public:
+  // Construct a cv for use with ONLY one user lock.
+  explicit ConditionVariable(Lock* user_lock);
+
+  ~ConditionVariable();
+
+  // Wait() releases the caller's critical section atomically as it starts to
+  // sleep, and the reacquires it when it is signaled.
+  void Wait();
+  void TimedWait(const TimeDelta& max_time);
+
+  // Broadcast() revives all waiting threads.
+  void Broadcast();
+  // Signal() revives one waiting thread.
+  void Signal();
+
+ private:
+
+#if defined(OS_WIN)
+  ConditionVarImpl* impl_;
+#elif defined(OS_POSIX)
+  pthread_cond_t condition_;
+  pthread_mutex_t* user_mutex_;
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  base::Lock* user_lock_;     // Needed to adjust shadow lock state on wait.
+#endif
+
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc
new file mode 100644
index 0000000..013284c
--- /dev/null
+++ b/base/synchronization/condition_variable_posix.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/condition_variable.h"
+
+#include <errno.h>
+#include <sys/time.h>
+
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace base {
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : user_mutex_(user_lock->lock_.native_handle())
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+    , user_lock_(user_lock)
+#endif
+{
+  int rv = 0;
+  // http://crbug.com/293736
+  // NaCl doesn't support monotonic clock based absolute deadlines.
+  // On older Android platform versions, it's supported through the
+  // non-standard pthread_cond_timedwait_monotonic_np. Newer platform
+  // versions have pthread_condattr_setclock.
+  // Mac can use relative time deadlines.
+#if !defined(OS_MACOSX) && !defined(OS_NACL) && \
+      !(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+  pthread_condattr_t attrs;
+  rv = pthread_condattr_init(&attrs);
+  DCHECK_EQ(0, rv);
+  pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+  rv = pthread_cond_init(&condition_, &attrs);
+  pthread_condattr_destroy(&attrs);
+#else
+  rv = pthread_cond_init(&condition_, NULL);
+#endif
+  DCHECK_EQ(0, rv);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int rv = pthread_cond_destroy(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckHeldAndUnmark();
+#endif
+  int rv = pthread_cond_wait(&condition_, user_mutex_);
+  DCHECK_EQ(0, rv);
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  int64 usecs = max_time.InMicroseconds();
+  struct timespec relative_time;
+  relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
+  relative_time.tv_nsec =
+      (usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckHeldAndUnmark();
+#endif
+
+#if defined(OS_MACOSX)
+  int rv = pthread_cond_timedwait_relative_np(
+      &condition_, user_mutex_, &relative_time);
+#else
+  // The timeout argument to pthread_cond_timedwait is in absolute time.
+  struct timespec absolute_time;
+#if defined(OS_NACL)
+  // See comment in constructor for why this is different in NaCl.
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  absolute_time.tv_sec = now.tv_sec;
+  absolute_time.tv_nsec = now.tv_usec * Time::kNanosecondsPerMicrosecond;
+#else
+  struct timespec now;
+  clock_gettime(CLOCK_MONOTONIC, &now);
+  absolute_time.tv_sec = now.tv_sec;
+  absolute_time.tv_nsec = now.tv_nsec;
+#endif
+
+  absolute_time.tv_sec += relative_time.tv_sec;
+  absolute_time.tv_nsec += relative_time.tv_nsec;
+  absolute_time.tv_sec += absolute_time.tv_nsec / Time::kNanosecondsPerSecond;
+  absolute_time.tv_nsec %= Time::kNanosecondsPerSecond;
+  DCHECK_GE(absolute_time.tv_sec, now.tv_sec);  // Overflow paranoia
+
+#if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+  int rv = pthread_cond_timedwait_monotonic_np(
+      &condition_, user_mutex_, &absolute_time);
+#else
+  int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time);
+#endif  // OS_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+#endif  // OS_MACOSX
+
+  DCHECK(rv == 0 || rv == ETIMEDOUT);
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::Broadcast() {
+  int rv = pthread_cond_broadcast(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Signal() {
+  int rv = pthread_cond_signal(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
new file mode 100644
index 0000000..e63a723
--- /dev/null
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -0,0 +1,765 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Multi-threaded tests of ConditionVariable class.
+
+#include <time.h>
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_collision_warner.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+//------------------------------------------------------------------------------
+// Define our test class, with several common variables.
+//------------------------------------------------------------------------------
+
+class ConditionVariableTest : public PlatformTest {
+ public:
+  const TimeDelta kZeroMs;
+  const TimeDelta kTenMs;
+  const TimeDelta kThirtyMs;
+  const TimeDelta kFortyFiveMs;
+  const TimeDelta kSixtyMs;
+  const TimeDelta kOneHundredMs;
+
+  ConditionVariableTest()
+      : kZeroMs(TimeDelta::FromMilliseconds(0)),
+        kTenMs(TimeDelta::FromMilliseconds(10)),
+        kThirtyMs(TimeDelta::FromMilliseconds(30)),
+        kFortyFiveMs(TimeDelta::FromMilliseconds(45)),
+        kSixtyMs(TimeDelta::FromMilliseconds(60)),
+        kOneHundredMs(TimeDelta::FromMilliseconds(100)) {
+  }
+};
+
+//------------------------------------------------------------------------------
+// Define a class that will control activities an several multi-threaded tests.
+// The general structure of multi-threaded tests is that a test case will
+// construct an instance of a WorkQueue.  The WorkQueue will spin up some
+// threads and control them throughout their lifetime, as well as maintaining
+// a central repository of the work thread's activity.  Finally, the WorkQueue
+// will command the the worker threads to terminate.  At that point, the test
+// cases will validate that the WorkQueue has records showing that the desired
+// activities were performed.
+//------------------------------------------------------------------------------
+
+// Callers are responsible for synchronizing access to the following class.
+// The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for
+// all synchronized access.
+class WorkQueue : public PlatformThread::Delegate {
+ public:
+  explicit WorkQueue(int thread_count);
+  ~WorkQueue() override;
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override;
+
+  //----------------------------------------------------------------------------
+  // Worker threads only call the following methods.
+  // They should use the lock to get exclusive access.
+  int GetThreadId();  // Get an ID assigned to a thread..
+  bool EveryIdWasAllocated() const;  // Indicates that all IDs were handed out.
+  TimeDelta GetAnAssignment(int thread_id);  // Get a work task duration.
+  void WorkIsCompleted(int thread_id);
+
+  int task_count() const;
+  bool allow_help_requests() const;  // Workers can signal more workers.
+  bool shutdown() const;  // Check if shutdown has been requested.
+
+  void thread_shutting_down();
+
+
+  //----------------------------------------------------------------------------
+  // Worker threads can call them but not needed to acquire a lock.
+  Lock* lock();
+
+  ConditionVariable* work_is_available();
+  ConditionVariable* all_threads_have_ids();
+  ConditionVariable* no_more_tasks();
+
+  //----------------------------------------------------------------------------
+  // The rest of the methods are for use by the controlling master thread (the
+  // test case code).
+  void ResetHistory();
+  int GetMinCompletionsByWorkerThread() const;
+  int GetMaxCompletionsByWorkerThread() const;
+  int GetNumThreadsTakingAssignments() const;
+  int GetNumThreadsCompletingTasks() const;
+  int GetNumberOfCompletedTasks() const;
+
+  void SetWorkTime(TimeDelta delay);
+  void SetTaskCount(int count);
+  void SetAllowHelp(bool allow);
+
+  // The following must be called without locking, and will spin wait until the
+  // threads are all in a wait state.
+  void SpinUntilAllThreadsAreWaiting();
+  void SpinUntilTaskCountLessThan(int task_count);
+
+  // Caller must acquire lock before calling.
+  void SetShutdown();
+
+  // Compares the |shutdown_task_count_| to the |thread_count| and returns true
+  // if they are equal.  This check will acquire the |lock_| so the caller
+  // should not hold the lock when calling this method.
+  bool ThreadSafeCheckShutdown(int thread_count);
+
+ private:
+  // Both worker threads and controller use the following to synchronize.
+  Lock lock_;
+  ConditionVariable work_is_available_;  // To tell threads there is work.
+
+  // Conditions to notify the controlling process (if it is interested).
+  ConditionVariable all_threads_have_ids_;  // All threads are running.
+  ConditionVariable no_more_tasks_;  // Task count is zero.
+
+  const int thread_count_;
+  int waiting_thread_count_;
+  scoped_ptr<PlatformThreadHandle[]> thread_handles_;
+  std::vector<int> assignment_history_;  // Number of assignment per worker.
+  std::vector<int> completion_history_;  // Number of completions per worker.
+  int thread_started_counter_;  // Used to issue unique id to workers.
+  int shutdown_task_count_;  // Number of tasks told to shutdown
+  int task_count_;  // Number of assignment tasks waiting to be processed.
+  TimeDelta worker_delay_;  // Time each task takes to complete.
+  bool allow_help_requests_;  // Workers can signal more workers.
+  bool shutdown_;  // Set when threads need to terminate.
+
+  DFAKE_MUTEX(locked_methods_);
+};
+
+//------------------------------------------------------------------------------
+// The next section contains the actual tests.
+//------------------------------------------------------------------------------
+
+TEST_F(ConditionVariableTest, StartupShutdownTest) {
+  Lock lock;
+
+  // First try trivial startup/shutdown.
+  {
+    ConditionVariable cv1(&lock);
+  }  // Call for cv1 destruction.
+
+  // Exercise with at least a few waits.
+  ConditionVariable cv(&lock);
+
+  lock.Acquire();
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  lock.Release();
+
+  lock.Acquire();
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  lock.Release();
+}  // Call for cv destruction.
+
+TEST_F(ConditionVariableTest, TimeoutTest) {
+  Lock lock;
+  ConditionVariable cv(&lock);
+  lock.Acquire();
+
+  TimeTicks start = TimeTicks::Now();
+  const TimeDelta WAIT_TIME = TimeDelta::FromMilliseconds(300);
+  // Allow for clocking rate granularity.
+  const TimeDelta FUDGE_TIME = TimeDelta::FromMilliseconds(50);
+
+  cv.TimedWait(WAIT_TIME + FUDGE_TIME);
+  TimeDelta duration = TimeTicks::Now() - start;
+  // We can't use EXPECT_GE here as the TimeDelta class does not support the
+  // required stream conversion.
+  EXPECT_TRUE(duration >= WAIT_TIME);
+
+  lock.Release();
+}
+
+#if defined(OS_POSIX)
+const int kDiscontinuitySeconds = 2;
+
+void BackInTime(Lock* lock) {
+  AutoLock auto_lock(*lock);
+
+  timeval tv;
+  gettimeofday(&tv, NULL);
+  tv.tv_sec -= kDiscontinuitySeconds;
+  settimeofday(&tv, NULL);
+}
+
+// Tests that TimedWait ignores changes to the system clock.
+// Test is disabled by default, because it needs to run as root to muck with the
+// system clock.
+// http://crbug.com/293736
+TEST_F(ConditionVariableTest, DISABLED_TimeoutAcrossSetTimeOfDay) {
+  timeval tv;
+  gettimeofday(&tv, NULL);
+  tv.tv_sec += kDiscontinuitySeconds;
+  if (settimeofday(&tv, NULL) < 0) {
+    PLOG(ERROR) << "Could not set time of day. Run as root?";
+    return;
+  }
+
+  Lock lock;
+  ConditionVariable cv(&lock);
+  lock.Acquire();
+
+  Thread thread("Helper");
+  thread.Start();
+  thread.task_runner()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
+
+  TimeTicks start = TimeTicks::Now();
+  const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300);
+  // Allow for clocking rate granularity.
+  const TimeDelta kFudgeTime = TimeDelta::FromMilliseconds(50);
+
+  cv.TimedWait(kWaitTime + kFudgeTime);
+  TimeDelta duration = TimeTicks::Now() - start;
+
+  thread.Stop();
+  // We can't use EXPECT_GE here as the TimeDelta class does not support the
+  // required stream conversion.
+  EXPECT_TRUE(duration >= kWaitTime);
+  EXPECT_TRUE(duration <= TimeDelta::FromSeconds(kDiscontinuitySeconds));
+
+  lock.Release();
+}
+#endif
+
+
+// Suddenly got flaky on Win, see http://crbug.com/10607 (starting at
+// comment #15).
+#if defined(OS_WIN)
+#define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest
+#else
+#define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest
+#endif
+// Test serial task servicing, as well as two parallel task servicing methods.
+TEST_F(ConditionVariableTest, MAYBE_MultiThreadConsumerTest) {
+  const int kThreadCount = 10;
+  WorkQueue queue(kThreadCount);  // Start the threads.
+
+  const int kTaskCount = 10;  // Number of tasks in each mini-test here.
+
+  Time start_time;  // Used to time task processing.
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (!queue.EveryIdWasAllocated())
+      queue.all_threads_have_ids()->Wait();
+  }
+
+  // If threads aren't in a wait state, they may start to gobble up tasks in
+  // parallel, short-circuiting (breaking) this test.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // Since we have no tasks yet, all threads should be waiting by now.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make each task include getting help from another worker, so
+    // so that the work gets done in paralell.
+    queue.ResetHistory();
+    queue.SetTaskCount(kTaskCount);
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);
+
+    start_time = Time::Now();
+  }
+
+  queue.work_is_available()->Signal();  // But each worker can signal another.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(kTaskCount);
+  // Wait to allow the all workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // Wait until all work tasks have at least been assigned.
+    base::AutoLock auto_lock(*queue.lock());
+    while (queue.task_count())
+      queue.no_more_tasks()->Wait();
+
+    // To avoid racy assumptions, we'll just assert that at least 2 threads
+    // did work.  We know that the first worker should have gone to sleep, and
+    // hence a second worker should have gotten an assignment.
+    EXPECT_LE(2, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
+
+    // Try to ask all workers to help, and only a few will do the work.
+    queue.ResetHistory();
+    queue.SetTaskCount(3);
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(false);
+  }
+  queue.work_is_available()->Broadcast();  // Make them all try.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(3);
+  // Wait to allow the 3 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make each task get help from another worker.
+    queue.ResetHistory();
+    queue.SetTaskCount(3);
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);  // Allow (unnecessary) help requests.
+  }
+  queue.work_is_available()->Broadcast();  // Signal all threads.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(3);
+  // Wait to allow the 3 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make each task get help from another worker.
+    queue.ResetHistory();
+    queue.SetTaskCount(20);  // 2 tasks per thread.
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);
+  }
+  queue.work_is_available()->Signal();  // But each worker can signal another.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(20);
+  // Wait to allow the 10 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();  // Should take about 60 ms.
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
+
+    // Same as last test, but with Broadcast().
+    queue.ResetHistory();
+    queue.SetTaskCount(20);  // 2 tasks per thread.
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);
+  }
+  queue.work_is_available()->Broadcast();
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(20);
+  // Wait to allow the 10 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();  // Should take about 60 ms.
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
+
+    queue.SetShutdown();
+  }
+  queue.work_is_available()->Broadcast();  // Force check for shutdown.
+
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
+                                   queue.ThreadSafeCheckShutdown(kThreadCount));
+}
+
+TEST_F(ConditionVariableTest, LargeFastTaskTest) {
+  const int kThreadCount = 200;
+  WorkQueue queue(kThreadCount);  // Start the threads.
+
+  Lock private_lock;  // Used locally for master to wait.
+  base::AutoLock private_held_lock(private_lock);
+  ConditionVariable private_cv(&private_lock);
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (!queue.EveryIdWasAllocated())
+      queue.all_threads_have_ids()->Wait();
+  }
+
+  // Wait a bit more to allow threads to reach their wait state.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // Since we have no tasks, all threads should be waiting by now.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make all workers do (an average of) 20 tasks.
+    queue.ResetHistory();
+    queue.SetTaskCount(20 * kThreadCount);
+    queue.SetWorkTime(kFortyFiveMs);
+    queue.SetAllowHelp(false);
+  }
+  queue.work_is_available()->Broadcast();  // Start up all threads.
+  // Wait until we've handed out all tasks.
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (queue.task_count() != 0)
+      queue.no_more_tasks()->Wait();
+  }
+
+  // Wait till the last of the tasks complete.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // With Broadcast(), every thread should have participated.
+    // but with racing.. they may not all have done equal numbers of tasks.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_LE(20, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(20 * kThreadCount, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make all workers do (an average of) 4 tasks.
+    queue.ResetHistory();
+    queue.SetTaskCount(kThreadCount * 4);
+    queue.SetWorkTime(kFortyFiveMs);
+    queue.SetAllowHelp(true);  // Might outperform Broadcast().
+  }
+  queue.work_is_available()->Signal();  // Start up one thread.
+
+  // Wait until we've handed out all tasks
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (queue.task_count() != 0)
+      queue.no_more_tasks()->Wait();
+  }
+
+  // Wait till the last of the tasks complete.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // With Signal(), every thread should have participated.
+    // but with racing.. they may not all have done four tasks.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks());
+
+    queue.SetShutdown();
+  }
+  queue.work_is_available()->Broadcast();  // Force check for shutdown.
+
+  // Wait for shutdowns to complete.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
+                                   queue.ThreadSafeCheckShutdown(kThreadCount));
+}
+
+//------------------------------------------------------------------------------
+// Finally we provide the implementation for the methods in the WorkQueue class.
+//------------------------------------------------------------------------------
+
+WorkQueue::WorkQueue(int thread_count)
+  : lock_(),
+    work_is_available_(&lock_),
+    all_threads_have_ids_(&lock_),
+    no_more_tasks_(&lock_),
+    thread_count_(thread_count),
+    waiting_thread_count_(0),
+    thread_handles_(new PlatformThreadHandle[thread_count]),
+    assignment_history_(thread_count),
+    completion_history_(thread_count),
+    thread_started_counter_(0),
+    shutdown_task_count_(0),
+    task_count_(0),
+    allow_help_requests_(false),
+    shutdown_(false) {
+  EXPECT_GE(thread_count_, 1);
+  ResetHistory();
+  SetTaskCount(0);
+  SetWorkTime(TimeDelta::FromMilliseconds(30));
+
+  for (int i = 0; i < thread_count_; ++i) {
+    PlatformThreadHandle pth;
+    EXPECT_TRUE(PlatformThread::Create(0, this, &pth));
+    thread_handles_[i] = pth;
+  }
+}
+
+WorkQueue::~WorkQueue() {
+  {
+    base::AutoLock auto_lock(lock_);
+    SetShutdown();
+  }
+  work_is_available_.Broadcast();  // Tell them all to terminate.
+
+  for (int i = 0; i < thread_count_; ++i) {
+    PlatformThread::Join(thread_handles_[i]);
+  }
+  EXPECT_EQ(0, waiting_thread_count_);
+}
+
+int WorkQueue::GetThreadId() {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  DCHECK(!EveryIdWasAllocated());
+  return thread_started_counter_++;  // Give out Unique IDs.
+}
+
+bool WorkQueue::EveryIdWasAllocated() const {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return thread_count_ == thread_started_counter_;
+}
+
+TimeDelta WorkQueue::GetAnAssignment(int thread_id) {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  DCHECK_LT(0, task_count_);
+  assignment_history_[thread_id]++;
+  if (0 == --task_count_) {
+    no_more_tasks_.Signal();
+  }
+  return worker_delay_;
+}
+
+void WorkQueue::WorkIsCompleted(int thread_id) {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  completion_history_[thread_id]++;
+}
+
+int WorkQueue::task_count() const {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return task_count_;
+}
+
+bool WorkQueue::allow_help_requests() const {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return allow_help_requests_;
+}
+
+bool WorkQueue::shutdown() const {
+  lock_.AssertAcquired();
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return shutdown_;
+}
+
+// Because this method is called from the test's main thread we need to actually
+// take the lock.  Threads will call the thread_shutting_down() method with the
+// lock already acquired.
+bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) {
+  bool all_shutdown;
+  base::AutoLock auto_lock(lock_);
+  {
+    // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock.
+    DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+    all_shutdown = (shutdown_task_count_ == thread_count);
+  }
+  return all_shutdown;
+}
+
+void WorkQueue::thread_shutting_down() {
+  lock_.AssertAcquired();
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  shutdown_task_count_++;
+}
+
+Lock* WorkQueue::lock() {
+  return &lock_;
+}
+
+ConditionVariable* WorkQueue::work_is_available() {
+  return &work_is_available_;
+}
+
+ConditionVariable* WorkQueue::all_threads_have_ids() {
+  return &all_threads_have_ids_;
+}
+
+ConditionVariable* WorkQueue::no_more_tasks() {
+  return &no_more_tasks_;
+}
+
+void WorkQueue::ResetHistory() {
+  for (int i = 0; i < thread_count_; ++i) {
+    assignment_history_[i] = 0;
+    completion_history_[i] = 0;
+  }
+}
+
+int WorkQueue::GetMinCompletionsByWorkerThread() const {
+  int minumum = completion_history_[0];
+  for (int i = 0; i < thread_count_; ++i)
+    minumum = std::min(minumum, completion_history_[i]);
+  return minumum;
+}
+
+int WorkQueue::GetMaxCompletionsByWorkerThread() const {
+  int maximum = completion_history_[0];
+  for (int i = 0; i < thread_count_; ++i)
+    maximum = std::max(maximum, completion_history_[i]);
+  return maximum;
+}
+
+int WorkQueue::GetNumThreadsTakingAssignments() const {
+  int count = 0;
+  for (int i = 0; i < thread_count_; ++i)
+    if (assignment_history_[i])
+      count++;
+  return count;
+}
+
+int WorkQueue::GetNumThreadsCompletingTasks() const {
+  int count = 0;
+  for (int i = 0; i < thread_count_; ++i)
+    if (completion_history_[i])
+      count++;
+  return count;
+}
+
+int WorkQueue::GetNumberOfCompletedTasks() const {
+  int total = 0;
+  for (int i = 0; i < thread_count_; ++i)
+    total += completion_history_[i];
+  return total;
+}
+
+void WorkQueue::SetWorkTime(TimeDelta delay) {
+  worker_delay_ = delay;
+}
+
+void WorkQueue::SetTaskCount(int count) {
+  task_count_ = count;
+}
+
+void WorkQueue::SetAllowHelp(bool allow) {
+  allow_help_requests_ = allow;
+}
+
+void WorkQueue::SetShutdown() {
+  lock_.AssertAcquired();
+  shutdown_ = true;
+}
+
+void WorkQueue::SpinUntilAllThreadsAreWaiting() {
+  while (true) {
+    {
+      base::AutoLock auto_lock(lock_);
+      if (waiting_thread_count_ == thread_count_)
+        break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
+  }
+}
+
+void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
+  while (true) {
+    {
+      base::AutoLock auto_lock(lock_);
+      if (task_count_ < task_count)
+        break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Define the standard worker task. Several tests will spin out many of these
+// threads.
+//------------------------------------------------------------------------------
+
+// The multithread tests involve several threads with a task to perform as
+// directed by an instance of the class WorkQueue.
+// The task is to:
+// a) Check to see if there are more tasks (there is a task counter).
+//    a1) Wait on condition variable if there are no tasks currently.
+// b) Call a function to see what should be done.
+// c) Do some computation based on the number of milliseconds returned in (b).
+// d) go back to (a).
+
+// WorkQueue::ThreadMain() implements the above task for all threads.
+// It calls the controlling object to tell the creator about progress, and to
+// ask about tasks.
+
+void WorkQueue::ThreadMain() {
+  int thread_id;
+  {
+    base::AutoLock auto_lock(lock_);
+    thread_id = GetThreadId();
+    if (EveryIdWasAllocated())
+      all_threads_have_ids()->Signal();  // Tell creator we're ready.
+  }
+
+  Lock private_lock;  // Used to waste time on "our work".
+  while (1) {  // This is the main consumer loop.
+    TimeDelta work_time;
+    bool could_use_help;
+    {
+      base::AutoLock auto_lock(lock_);
+      while (0 == task_count() && !shutdown()) {
+        ++waiting_thread_count_;
+        work_is_available()->Wait();
+        --waiting_thread_count_;
+      }
+      if (shutdown()) {
+        // Ack the notification of a shutdown message back to the controller.
+        thread_shutting_down();
+        return;  // Terminate.
+      }
+      // Get our task duration from the queue.
+      work_time = GetAnAssignment(thread_id);
+      could_use_help = (task_count() > 0) && allow_help_requests();
+    }  // Release lock
+
+    // Do work (outside of locked region.
+    if (could_use_help)
+      work_is_available()->Signal();  // Get help from other threads.
+
+    if (work_time > TimeDelta::FromMilliseconds(0)) {
+      // We could just sleep(), but we'll instead further exercise the
+      // condition variable class, and do a timed wait.
+      base::AutoLock auto_lock(private_lock);
+      ConditionVariable private_cv(&private_lock);
+      private_cv.TimedWait(work_time);  // Unsynchronized waiting.
+    }
+
+    {
+      base::AutoLock auto_lock(lock_);
+      // Send notification that we completed our "work."
+      WorkIsCompleted(thread_id);
+    }
+  }
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc
new file mode 100644
index 0000000..5f165c8
--- /dev/null
+++ b/base/synchronization/condition_variable_win.cc
@@ -0,0 +1,669 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/condition_variable.h"
+
+#include <windows.h>
+#include <stack>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace {
+// We can't use the linker supported delay-load for kernel32 so all this
+// cruft here is to manually late-bind the needed functions.
+typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE,
+                                                  PCRITICAL_SECTION, DWORD);
+typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE);
+
+InitializeConditionVariableFn initialize_condition_variable_fn;
+SleepConditionVariableCSFn sleep_condition_variable_fn;
+WakeConditionVariableFn wake_condition_variable_fn;
+WakeAllConditionVariableFn wake_all_condition_variable_fn;
+
+bool BindVistaCondVarFunctions() {
+  HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
+  initialize_condition_variable_fn =
+      reinterpret_cast<InitializeConditionVariableFn>(
+          GetProcAddress(kernel32, "InitializeConditionVariable"));
+  if (!initialize_condition_variable_fn)
+    return false;
+  sleep_condition_variable_fn =
+      reinterpret_cast<SleepConditionVariableCSFn>(
+          GetProcAddress(kernel32, "SleepConditionVariableCS"));
+  if (!sleep_condition_variable_fn)
+    return false;
+  wake_condition_variable_fn =
+      reinterpret_cast<WakeConditionVariableFn>(
+          GetProcAddress(kernel32, "WakeConditionVariable"));
+  if (!wake_condition_variable_fn)
+    return false;
+  wake_all_condition_variable_fn =
+      reinterpret_cast<WakeAllConditionVariableFn>(
+          GetProcAddress(kernel32, "WakeAllConditionVariable"));
+  if (!wake_all_condition_variable_fn)
+    return false;
+  return true;
+}
+
+}  // namespace.
+
+namespace base {
+// Abstract base class of the pimpl idiom.
+class ConditionVarImpl {
+ public:
+  virtual ~ConditionVarImpl() {};
+  virtual void Wait() = 0;
+  virtual void TimedWait(const TimeDelta& max_time) = 0;
+  virtual void Broadcast() = 0;
+  virtual void Signal() = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows Vista and Win7 implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinVistaCondVar: public ConditionVarImpl {
+ public:
+  WinVistaCondVar(Lock* user_lock);
+  ~WinVistaCondVar() override {}
+  // Overridden from ConditionVarImpl.
+  void Wait() override;
+  void TimedWait(const TimeDelta& max_time) override;
+  void Broadcast() override;
+  void Signal() override;
+
+ private:
+  base::Lock& user_lock_;
+  CONDITION_VARIABLE cv_;
+};
+
+WinVistaCondVar::WinVistaCondVar(Lock* user_lock)
+    : user_lock_(*user_lock) {
+  initialize_condition_variable_fn(&cv_);
+  DCHECK(user_lock);
+}
+
+void WinVistaCondVar::Wait() {
+  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinVistaCondVar::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
+  CRITICAL_SECTION* cs = user_lock_.lock_.native_handle();
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_.CheckHeldAndUnmark();
+#endif
+
+  if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) {
+    DCHECK(GetLastError() != WAIT_TIMEOUT);
+  }
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_.CheckUnheldAndMark();
+#endif
+}
+
+void WinVistaCondVar::Broadcast() {
+  wake_all_condition_variable_fn(&cv_);
+}
+
+void WinVistaCondVar::Signal() {
+  wake_condition_variable_fn(&cv_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows XP implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinXPCondVar : public ConditionVarImpl {
+ public:
+  WinXPCondVar(Lock* user_lock);
+  ~WinXPCondVar() override;
+  // Overridden from ConditionVarImpl.
+  void Wait() override;
+  void TimedWait(const TimeDelta& max_time) override;
+  void Broadcast() override;
+  void Signal() override;
+
+  // Define Event class that is used to form circularly linked lists.
+  // The list container is an element with NULL as its handle_ value.
+  // The actual list elements have a non-zero handle_ value.
+  // All calls to methods MUST be done under protection of a lock so that links
+  // can be validated.  Without the lock, some links might asynchronously
+  // change, and the assertions would fail (as would list change operations).
+  class Event {
+   public:
+    // Default constructor with no arguments creates a list container.
+    Event();
+    ~Event();
+
+    // InitListElement transitions an instance from a container, to an element.
+    void InitListElement();
+
+    // Methods for use on lists.
+    bool IsEmpty() const;
+    void PushBack(Event* other);
+    Event* PopFront();
+    Event* PopBack();
+
+    // Methods for use on list elements.
+    // Accessor method.
+    HANDLE handle() const;
+    // Pull an element from a list (if it's in one).
+    Event* Extract();
+
+    // Method for use on a list element or on a list.
+    bool IsSingleton() const;
+
+   private:
+    // Provide pre/post conditions to validate correct manipulations.
+    bool ValidateAsDistinct(Event* other) const;
+    bool ValidateAsItem() const;
+    bool ValidateAsList() const;
+    bool ValidateLinks() const;
+
+    HANDLE handle_;
+    Event* next_;
+    Event* prev_;
+    DISALLOW_COPY_AND_ASSIGN(Event);
+  };
+
+  // Note that RUNNING is an unlikely number to have in RAM by accident.
+  // This helps with defensive destructor coding in the face of user error.
+  enum RunState { SHUTDOWN = 0, RUNNING = 64213 };
+
+  // Internal implementation methods supporting Wait().
+  Event* GetEventForWaiting();
+  void RecycleEvent(Event* used_event);
+
+  RunState run_state_;
+
+  // Private critical section for access to member data.
+  base::Lock internal_lock_;
+
+  // Lock that is acquired before calling Wait().
+  base::Lock& user_lock_;
+
+  // Events that threads are blocked on.
+  Event waiting_list_;
+
+  // Free list for old events.
+  Event recycling_list_;
+  int recycling_list_size_;
+
+  // The number of allocated, but not yet deleted events.
+  int allocation_counter_;
+};
+
+WinXPCondVar::WinXPCondVar(Lock* user_lock)
+    : user_lock_(*user_lock),
+      run_state_(RUNNING),
+      allocation_counter_(0),
+      recycling_list_size_(0) {
+  DCHECK(user_lock);
+}
+
+WinXPCondVar::~WinXPCondVar() {
+  AutoLock auto_lock(internal_lock_);
+  run_state_ = SHUTDOWN;  // Prevent any more waiting.
+
+  DCHECK_EQ(recycling_list_size_, allocation_counter_);
+  if (recycling_list_size_ != allocation_counter_) {  // Rare shutdown problem.
+    // There are threads of execution still in this->TimedWait() and yet the
+    // caller has instigated the destruction of this instance :-/.
+    // A common reason for such "overly hasty" destruction is that the caller
+    // was not willing to wait for all the threads to terminate.  Such hasty
+    // actions are a violation of our usage contract, but we'll give the
+    // waiting thread(s) one last chance to exit gracefully (prior to our
+    // destruction).
+    // Note: waiting_list_ *might* be empty, but recycling is still pending.
+    AutoUnlock auto_unlock(internal_lock_);
+    Broadcast();  // Make sure all waiting threads have been signaled.
+    Sleep(10);  // Give threads a chance to grab internal_lock_.
+    // All contained threads should be blocked on user_lock_ by now :-).
+  }  // Reacquire internal_lock_.
+
+  DCHECK_EQ(recycling_list_size_, allocation_counter_);
+}
+
+void WinXPCondVar::Wait() {
+  // Default to "wait forever" timing, which means have to get a Signal()
+  // or Broadcast() to come out of this wait state.
+  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinXPCondVar::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  Event* waiting_event;
+  HANDLE handle;
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (RUNNING != run_state_) return;  // Destruction in progress.
+    waiting_event = GetEventForWaiting();
+    handle = waiting_event->handle();
+    DCHECK(handle);
+  }  // Release internal_lock.
+
+  {
+    AutoUnlock unlock(user_lock_);  // Release caller's lock
+    WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds()));
+    // Minimize spurious signal creation window by recycling asap.
+    AutoLock auto_lock(internal_lock_);
+    RecycleEvent(waiting_event);
+    // Release internal_lock_
+  }  // Reacquire callers lock to depth at entry.
+}
+
+// Broadcast() is guaranteed to signal all threads that were waiting (i.e., had
+// a cv_event internally allocated for them) before Broadcast() was called.
+void WinXPCondVar::Broadcast() {
+  std::stack<HANDLE> handles;  // See FAQ-question-10.
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (waiting_list_.IsEmpty())
+      return;
+    while (!waiting_list_.IsEmpty())
+      // This is not a leak from waiting_list_.  See FAQ-question 12.
+      handles.push(waiting_list_.PopBack()->handle());
+  }  // Release internal_lock_.
+  while (!handles.empty()) {
+    SetEvent(handles.top());
+    handles.pop();
+  }
+}
+
+// Signal() will select one of the waiting threads, and signal it (signal its
+// cv_event).  For better performance we signal the thread that went to sleep
+// most recently (LIFO).  If we want fairness, then we wake the thread that has
+// been sleeping the longest (FIFO).
+void WinXPCondVar::Signal() {
+  HANDLE handle;
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (waiting_list_.IsEmpty())
+      return;  // No one to signal.
+    // Only performance option should be used.
+    // This is not a leak from waiting_list.  See FAQ-question 12.
+     handle = waiting_list_.PopBack()->handle();  // LIFO.
+  }  // Release internal_lock_.
+  SetEvent(handle);
+}
+
+// GetEventForWaiting() provides a unique cv_event for any caller that needs to
+// wait.  This means that (worst case) we may over time create as many cv_event
+// objects as there are threads simultaneously using this instance's Wait()
+// functionality.
+WinXPCondVar::Event* WinXPCondVar::GetEventForWaiting() {
+  // We hold internal_lock, courtesy of Wait().
+  Event* cv_event;
+  if (0 == recycling_list_size_) {
+    DCHECK(recycling_list_.IsEmpty());
+    cv_event = new Event();
+    cv_event->InitListElement();
+    allocation_counter_++;
+    DCHECK(cv_event->handle());
+  } else {
+    cv_event = recycling_list_.PopFront();
+    recycling_list_size_--;
+  }
+  waiting_list_.PushBack(cv_event);
+  return cv_event;
+}
+
+// RecycleEvent() takes a cv_event that was previously used for Wait()ing, and
+// recycles it for use in future Wait() calls for this or other threads.
+// Note that there is a tiny chance that the cv_event is still signaled when we
+// obtain it, and that can cause spurious signals (if/when we re-use the
+// cv_event), but such is quite rare (see FAQ-question-5).
+void WinXPCondVar::RecycleEvent(Event* used_event) {
+  // We hold internal_lock, courtesy of Wait().
+  // If the cv_event timed out, then it is necessary to remove it from
+  // waiting_list_.  If it was selected by Broadcast() or Signal(), then it is
+  // already gone.
+  used_event->Extract();  // Possibly redundant
+  recycling_list_.PushBack(used_event);
+  recycling_list_size_++;
+}
+//------------------------------------------------------------------------------
+// The next section provides the implementation for the private Event class.
+//------------------------------------------------------------------------------
+
+// Event provides a doubly-linked-list of events for use exclusively by the
+// ConditionVariable class.
+
+// This custom container was crafted because no simple combination of STL
+// classes appeared to support the functionality required.  The specific
+// unusual requirement for a linked-list-class is support for the Extract()
+// method, which can remove an element from a list, potentially for insertion
+// into a second list.  Most critically, the Extract() method is idempotent,
+// turning the indicated element into an extracted singleton whether it was
+// contained in a list or not.  This functionality allows one (or more) of
+// threads to do the extraction.  The iterator that identifies this extractable
+// element (in this case, a pointer to the list element) can be used after
+// arbitrary manipulation of the (possibly) enclosing list container.  In
+// general, STL containers do not provide iterators that can be used across
+// modifications (insertions/extractions) of the enclosing containers, and
+// certainly don't provide iterators that can be used if the identified
+// element is *deleted* (removed) from the container.
+
+// It is possible to use multiple redundant containers, such as an STL list,
+// and an STL map, to achieve similar container semantics.  This container has
+// only O(1) methods, while the corresponding (multiple) STL container approach
+// would have more complex O(log(N)) methods (yeah... N isn't that large).
+// Multiple containers also makes correctness more difficult to assert, as
+// data is redundantly stored and maintained, which is generally evil.
+
+WinXPCondVar::Event::Event() : handle_(0) {
+  next_ = prev_ = this;  // Self referencing circular.
+}
+
+WinXPCondVar::Event::~Event() {
+  if (0 == handle_) {
+    // This is the list holder
+    while (!IsEmpty()) {
+      Event* cv_event = PopFront();
+      DCHECK(cv_event->ValidateAsItem());
+      delete cv_event;
+    }
+  }
+  DCHECK(IsSingleton());
+  if (0 != handle_) {
+    int ret_val = CloseHandle(handle_);
+    DCHECK(ret_val);
+  }
+}
+
+// Change a container instance permanently into an element of a list.
+void WinXPCondVar::Event::InitListElement() {
+  DCHECK(!handle_);
+  handle_ = CreateEvent(NULL, false, false, NULL);
+  DCHECK(handle_);
+}
+
+// Methods for use on lists.
+bool WinXPCondVar::Event::IsEmpty() const {
+  DCHECK(ValidateAsList());
+  return IsSingleton();
+}
+
+void WinXPCondVar::Event::PushBack(Event* other) {
+  DCHECK(ValidateAsList());
+  DCHECK(other->ValidateAsItem());
+  DCHECK(other->IsSingleton());
+  // Prepare other for insertion.
+  other->prev_ = prev_;
+  other->next_ = this;
+  // Cut into list.
+  prev_->next_ = other;
+  prev_ = other;
+  DCHECK(ValidateAsDistinct(other));
+}
+
+WinXPCondVar::Event* WinXPCondVar::Event::PopFront() {
+  DCHECK(ValidateAsList());
+  DCHECK(!IsSingleton());
+  return next_->Extract();
+}
+
+WinXPCondVar::Event* WinXPCondVar::Event::PopBack() {
+  DCHECK(ValidateAsList());
+  DCHECK(!IsSingleton());
+  return prev_->Extract();
+}
+
+// Methods for use on list elements.
+// Accessor method.
+HANDLE WinXPCondVar::Event::handle() const {
+  DCHECK(ValidateAsItem());
+  return handle_;
+}
+
+// Pull an element from a list (if it's in one).
+WinXPCondVar::Event* WinXPCondVar::Event::Extract() {
+  DCHECK(ValidateAsItem());
+  if (!IsSingleton()) {
+    // Stitch neighbors together.
+    next_->prev_ = prev_;
+    prev_->next_ = next_;
+    // Make extractee into a singleton.
+    prev_ = next_ = this;
+  }
+  DCHECK(IsSingleton());
+  return this;
+}
+
+// Method for use on a list element or on a list.
+bool WinXPCondVar::Event::IsSingleton() const {
+  DCHECK(ValidateLinks());
+  return next_ == this;
+}
+
+// Provide pre/post conditions to validate correct manipulations.
+bool WinXPCondVar::Event::ValidateAsDistinct(Event* other) const {
+  return ValidateLinks() && other->ValidateLinks() && (this != other);
+}
+
+bool WinXPCondVar::Event::ValidateAsItem() const {
+  return (0 != handle_) && ValidateLinks();
+}
+
+bool WinXPCondVar::Event::ValidateAsList() const {
+  return (0 == handle_) && ValidateLinks();
+}
+
+bool WinXPCondVar::Event::ValidateLinks() const {
+  // Make sure both of our neighbors have links that point back to us.
+  // We don't do the O(n) check and traverse the whole loop, and instead only
+  // do a local check to (and returning from) our immediate neighbors.
+  return (next_->prev_ == this) && (prev_->next_ == this);
+}
+
+
+/*
+FAQ On WinXPCondVar subtle implementation details:
+
+1) What makes this problem subtle?  Please take a look at "Strategies
+for Implementing POSIX Condition Variables on Win32" by Douglas
+C. Schmidt and Irfan Pyarali.
+http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes
+discussions of numerous flawed strategies for implementing this
+functionality.  I'm not convinced that even the final proposed
+implementation has semantics that are as nice as this implementation
+(especially with regard to Broadcast() and the impact on threads that
+try to Wait() after a Broadcast() has been called, but before all the
+original waiting threads have been signaled).
+
+2) Why can't you use a single wait_event for all threads that call
+Wait()?  See FAQ-question-1, or consider the following: If a single
+event were used, then numerous threads calling Wait() could release
+their cs locks, and be preempted just before calling
+WaitForSingleObject().  If a call to Broadcast() was then presented on
+a second thread, it would be impossible to actually signal all
+waiting(?) threads.  Some number of SetEvent() calls *could* be made,
+but there could be no guarantee that those led to to more than one
+signaled thread (SetEvent()'s may be discarded after the first!), and
+there could be no guarantee that the SetEvent() calls didn't just
+awaken "other" threads that hadn't even started waiting yet (oops).
+Without any limit on the number of requisite SetEvent() calls, the
+system would be forced to do many such calls, allowing many new waits
+to receive spurious signals.
+
+3) How does this implementation cause spurious signal events?  The
+cause in this implementation involves a race between a signal via
+time-out and a signal via Signal() or Broadcast().  The series of
+actions leading to this are:
+
+a) Timer fires, and a waiting thread exits the line of code:
+
+    WaitForSingleObject(waiting_event, max_time.InMilliseconds());
+
+b) That thread (in (a)) is randomly pre-empted after the above line,
+leaving the waiting_event reset (unsignaled) and still in the
+waiting_list_.
+
+c) A call to Signal() (or Broadcast()) on a second thread proceeds, and
+selects the waiting cv_event (identified in step (b)) as the event to revive
+via a call to SetEvent().
+
+d) The Signal() method (step c) calls SetEvent() on waiting_event (step b).
+
+e) The waiting cv_event (step b) is now signaled, but no thread is
+waiting on it.
+
+f) When that waiting_event (step b) is reused, it will immediately
+be signaled (spuriously).
+
+
+4) Why do you recycle events, and cause spurious signals?  First off,
+the spurious events are very rare.  They can only (I think) appear
+when the race described in FAQ-question-3 takes place.  This should be
+very rare.  Most(?)  uses will involve only timer expiration, or only
+Signal/Broadcast() actions.  When both are used, it will be rare that
+the race will appear, and it would require MANY Wait() and signaling
+activities.  If this implementation did not recycle events, then it
+would have to create and destroy events for every call to Wait().
+That allocation/deallocation and associated construction/destruction
+would be costly (per wait), and would only be a rare benefit (when the
+race was "lost" and a spurious signal took place). That would be bad
+(IMO) optimization trade-off.  Finally, such spurious events are
+allowed by the specification of condition variables (such as
+implemented in Vista), and hence it is better if any user accommodates
+such spurious events (see usage note in condition_variable.h).
+
+5) Why don't you reset events when you are about to recycle them, or
+about to reuse them, so that the spurious signals don't take place?
+The thread described in FAQ-question-3 step c may be pre-empted for an
+arbitrary length of time before proceeding to step d.  As a result,
+the wait_event may actually be re-used *before* step (e) is reached.
+As a result, calling reset would not help significantly.
+
+6) How is it that the callers lock is released atomically with the
+entry into a wait state?  We commit to the wait activity when we
+allocate the wait_event for use in a given call to Wait().  This
+allocation takes place before the caller's lock is released (and
+actually before our internal_lock_ is released).  That allocation is
+the defining moment when "the wait state has been entered," as that
+thread *can* now be signaled by a call to Broadcast() or Signal().
+Hence we actually "commit to wait" before releasing the lock, making
+the pair effectively atomic.
+
+8) Why do you need to lock your data structures during waiting, as the
+caller is already in possession of a lock?  We need to Acquire() and
+Release() our internal lock during Signal() and Broadcast().  If we tried
+to use a callers lock for this purpose, we might conflict with their
+external use of the lock.  For example, the caller may use to consistently
+hold a lock on one thread while calling Signal() on another, and that would
+block Signal().
+
+9) Couldn't a more efficient implementation be provided if you
+preclude using more than one external lock in conjunction with a
+single ConditionVariable instance?  Yes, at least it could be viewed
+as a simpler API (since you don't have to reiterate the lock argument
+in each Wait() call).  One of the constructors now takes a specific
+lock as an argument, and a there are corresponding Wait() calls that
+don't specify a lock now.  It turns that the resulting implmentation
+can't be made more efficient, as the internal lock needs to be used by
+Signal() and Broadcast(), to access internal data structures.  As a
+result, I was not able to utilize the user supplied lock (which is
+being used by the user elsewhere presumably) to protect the private
+member access.
+
+9) Since you have a second lock, how can be be sure that there is no
+possible deadlock scenario?  Our internal_lock_ is always the last
+lock acquired, and the first one released, and hence a deadlock (due
+to critical section problems) is impossible as a consequence of our
+lock.
+
+10) When doing a Broadcast(), why did you copy all the events into
+an STL queue, rather than making a linked-loop, and iterating over it?
+The iterating during Broadcast() is done so outside the protection
+of the internal lock. As a result, other threads, such as the thread
+wherein a related event is waiting, could asynchronously manipulate
+the links around a cv_event.  As a result, the link structure cannot
+be used outside a lock.  Broadcast() could iterate over waiting
+events by cycling in-and-out of the protection of the internal_lock,
+but that appears more expensive than copying the list into an STL
+stack.
+
+11) Why did the lock.h file need to be modified so much for this
+change?  Central to a Condition Variable is the atomic release of a
+lock during a Wait().  This places Wait() functionality exactly
+mid-way between the two classes, Lock and Condition Variable.  Given
+that there can be nested Acquire()'s of locks, and Wait() had to
+Release() completely a held lock, it was necessary to augment the Lock
+class with a recursion counter. Even more subtle is the fact that the
+recursion counter (in a Lock) must be protected, as many threads can
+access it asynchronously.  As a positive fallout of this, there are
+now some DCHECKS to be sure no one Release()s a Lock more than they
+Acquire()ed it, and there is ifdef'ed functionality that can detect
+nested locks (legal under windows, but not under Posix).
+
+12) Why is it that the cv_events removed from list in Broadcast() and Signal()
+are not leaked?  How are they recovered??  The cv_events that appear to leak are
+taken from the waiting_list_.  For each element in that list, there is currently
+a thread in or around the WaitForSingleObject() call of Wait(), and those
+threads have references to these otherwise leaked events. They are passed as
+arguments to be recycled just aftre returning from WaitForSingleObject().
+
+13) Why did you use a custom container class (the linked list), when STL has
+perfectly good containers, such as an STL list?  The STL list, as with any
+container, does not guarantee the utility of an iterator across manipulation
+(such as insertions and deletions) of the underlying container.  The custom
+double-linked-list container provided that assurance.  I don't believe any
+combination of STL containers provided the services that were needed at the same
+O(1) efficiency as the custom linked list.  The unusual requirement
+for the container class is that a reference to an item within a container (an
+iterator) needed to be maintained across an arbitrary manipulation of the
+container.  This requirement exposes itself in the Wait() method, where a
+waiting_event must be selected prior to the WaitForSingleObject(), and then it
+must be used as part of recycling to remove the related instance from the
+waiting_list.  A hash table (STL map) could be used, but I was embarrased to
+use a complex and relatively low efficiency container when a doubly linked list
+provided O(1) performance in all required operations.  Since other operations
+to provide performance-and/or-fairness required queue (FIFO) and list (LIFO)
+containers, I would also have needed to use an STL list/queue as well as an STL
+map.  In the end I decided it would be "fun" to just do it right, and I
+put so many assertions (DCHECKs) into the container class that it is trivial to
+code review and validate its correctness.
+
+*/
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : impl_(NULL) {
+  static bool use_vista_native_cv = BindVistaCondVarFunctions();
+  if (use_vista_native_cv)
+    impl_= new WinVistaCondVar(user_lock);
+  else
+    impl_ = new WinXPCondVar(user_lock);
+}
+
+ConditionVariable::~ConditionVariable() {
+  delete impl_;
+}
+
+void ConditionVariable::Wait() {
+  impl_->Wait();
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  impl_->TimedWait(max_time);
+}
+
+void ConditionVariable::Broadcast() {
+  impl_->Broadcast();
+}
+
+void ConditionVariable::Signal() {
+  impl_->Signal();
+}
+
+}  // namespace base
diff --git a/base/synchronization/lock.cc b/base/synchronization/lock.cc
new file mode 100644
index 0000000..b1576c5
--- /dev/null
+++ b/base/synchronization/lock.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used for debugging assertion support.  The Lock class
+// is functionally a wrapper around the LockImpl class, so the only
+// real intelligence in the class is in the debugging logic.
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+
+#include "base/synchronization/lock.h"
+#include "base/logging.h"
+
+namespace base {
+
+Lock::Lock() : lock_() {
+}
+
+Lock::~Lock() {
+  DCHECK(owning_thread_ref_.is_null());
+}
+
+void Lock::AssertAcquired() const {
+  DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+}
+
+void Lock::CheckHeldAndUnmark() {
+  DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+  owning_thread_ref_ = PlatformThreadRef();
+}
+
+void Lock::CheckUnheldAndMark() {
+  DCHECK(owning_thread_ref_.is_null());
+  owning_thread_ref_ = PlatformThread::CurrentRef();
+}
+
+}  // namespace base
+
+#endif  // !NDEBUG || DCHECK_ALWAYS_ON
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
new file mode 100644
index 0000000..f384e41
--- /dev/null
+++ b/base/synchronization/lock.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_H_
+#define BASE_SYNCHRONIZATION_LOCK_H_
+
+#include "base/base_export.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A convenient wrapper for an OS specific critical section.  The only real
+// intelligence in this class is in debug mode for the support for the
+// AssertAcquired() method.
+class BASE_EXPORT Lock {
+ public:
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+   // Optimized wrapper implementation
+  Lock() : lock_() {}
+  ~Lock() {}
+  void Acquire() { lock_.Lock(); }
+  void Release() { lock_.Unlock(); }
+
+  // If the lock is not held, take it and return true. If the lock is already
+  // held by another thread, immediately return false. This must not be called
+  // by a thread already holding the lock (what happens is undefined and an
+  // assertion may fail).
+  bool Try() { return lock_.Try(); }
+
+  // Null implementation if not debug.
+  void AssertAcquired() const {}
+#else
+  Lock();
+  ~Lock();
+
+  // NOTE: Although windows critical sections support recursive locks, we do not
+  // allow this, and we will commonly fire a DCHECK() if a thread attempts to
+  // acquire the lock a second time (while already holding it).
+  void Acquire() {
+    lock_.Lock();
+    CheckUnheldAndMark();
+  }
+  void Release() {
+    CheckHeldAndUnmark();
+    lock_.Unlock();
+  }
+
+  bool Try() {
+    bool rv = lock_.Try();
+    if (rv) {
+      CheckUnheldAndMark();
+    }
+    return rv;
+  }
+
+  void AssertAcquired() const;
+#endif  // NDEBUG && !DCHECK_ALWAYS_ON
+
+#if defined(OS_POSIX)
+  // The posix implementation of ConditionVariable needs to be able
+  // to see our lock and tweak our debugging counters, as it releases
+  // and acquires locks inside of pthread_cond_{timed,}wait.
+  friend class ConditionVariable;
+#elif defined(OS_WIN)
+  // The Windows Vista implementation of ConditionVariable needs the
+  // native handle of the critical section.
+  friend class WinVistaCondVar;
+#endif
+
+ private:
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  // Members and routines taking care of locks assertions.
+  // Note that this checks for recursive locks and allows them
+  // if the variable is set.  This is allowed by the underlying implementation
+  // on windows but not on Posix, so we're doing unneeded checks on Posix.
+  // It's worth it to share the code.
+  void CheckHeldAndUnmark();
+  void CheckUnheldAndMark();
+
+  // All private data is implicitly protected by lock_.
+  // Be VERY careful to only access members under that lock.
+  base::PlatformThreadRef owning_thread_ref_;
+#endif  // !NDEBUG || DCHECK_ALWAYS_ON
+
+  // Platform specific underlying lock implementation.
+  internal::LockImpl lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+class AutoLock {
+ public:
+  struct AlreadyAcquired {};
+
+  explicit AutoLock(Lock& lock) : lock_(lock) {
+    lock_.Acquire();
+  }
+
+  AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
+    lock_.AssertAcquired();
+  }
+
+  ~AutoLock() {
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+ private:
+  Lock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoLock);
+};
+
+// AutoUnlock is a helper that will Release() the |lock| argument in the
+// constructor, and re-Acquire() it in the destructor.
+class AutoUnlock {
+ public:
+  explicit AutoUnlock(Lock& lock) : lock_(lock) {
+    // We require our caller to have the lock.
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+  ~AutoUnlock() {
+    lock_.Acquire();
+  }
+
+ private:
+  Lock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_LOCK_H_
diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h
new file mode 100644
index 0000000..42e2f99
--- /dev/null
+++ b/base/synchronization/lock_impl.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace internal {
+
+// This class implements the underlying platform-specific spin-lock mechanism
+// used for the Lock class.  Most users should not use LockImpl directly, but
+// should instead use Lock.
+class BASE_EXPORT LockImpl {
+ public:
+#if defined(OS_WIN)
+  typedef CRITICAL_SECTION NativeHandle;
+#elif defined(OS_POSIX)
+  typedef pthread_mutex_t NativeHandle;
+#endif
+
+  LockImpl();
+  ~LockImpl();
+
+  // If the lock is not held, take it and return true.  If the lock is already
+  // held by something else, immediately return false.
+  bool Try();
+
+  // Take the lock, blocking until it is available if necessary.
+  void Lock();
+
+  // Release the lock.  This must only be called by the lock's holder: after
+  // a successful call to Try, or a call to Lock.
+  void Unlock();
+
+  // Return the native underlying lock.
+  // TODO(awalker): refactor lock and condition variables so that this is
+  // unnecessary.
+  NativeHandle* native_handle() { return &native_handle_; }
+
+ private:
+  NativeHandle native_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_LOCK_IMPL_H_
diff --git a/base/synchronization/lock_impl_posix.cc b/base/synchronization/lock_impl_posix.cc
new file mode 100644
index 0000000..5619ada
--- /dev/null
+++ b/base/synchronization/lock_impl_posix.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock_impl.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() {
+#ifndef NDEBUG
+  // In debug, setup attributes for lock error checking.
+  pthread_mutexattr_t mta;
+  int rv = pthread_mutexattr_init(&mta);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+  rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+  rv = pthread_mutex_init(&native_handle_, &mta);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+  rv = pthread_mutexattr_destroy(&mta);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+#else
+  // In release, go with the default lock attributes.
+  pthread_mutex_init(&native_handle_, NULL);
+#endif
+}
+
+LockImpl::~LockImpl() {
+  int rv = pthread_mutex_destroy(&native_handle_);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+bool LockImpl::Try() {
+  int rv = pthread_mutex_trylock(&native_handle_);
+  DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
+  return rv == 0;
+}
+
+void LockImpl::Lock() {
+  int rv = pthread_mutex_lock(&native_handle_);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+void LockImpl::Unlock() {
+  int rv = pthread_mutex_unlock(&native_handle_);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/synchronization/lock_impl_win.cc b/base/synchronization/lock_impl_win.cc
new file mode 100644
index 0000000..fbc1bdd
--- /dev/null
+++ b/base/synchronization/lock_impl_win.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock_impl.h"
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() {
+  // The second parameter is the spin count, for short-held locks it avoid the
+  // contending thread from going to sleep which helps performance greatly.
+  ::InitializeCriticalSectionAndSpinCount(&native_handle_, 2000);
+}
+
+LockImpl::~LockImpl() {
+  ::DeleteCriticalSection(&native_handle_);
+}
+
+bool LockImpl::Try() {
+  if (::TryEnterCriticalSection(&native_handle_) != FALSE) {
+    return true;
+  }
+  return false;
+}
+
+void LockImpl::Lock() {
+  ::EnterCriticalSection(&native_handle_);
+}
+
+void LockImpl::Unlock() {
+  ::LeaveCriticalSection(&native_handle_);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc
new file mode 100644
index 0000000..967efb8
--- /dev/null
+++ b/base/synchronization/lock_unittest.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock.h"
+
+#include <stdlib.h>
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
+
+class BasicLockTestThread : public PlatformThread::Delegate {
+ public:
+  explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
+
+  void ThreadMain() override {
+    for (int i = 0; i < 10; i++) {
+      lock_->Acquire();
+      acquired_++;
+      lock_->Release();
+    }
+    for (int i = 0; i < 10; i++) {
+      lock_->Acquire();
+      acquired_++;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+      lock_->Release();
+    }
+    for (int i = 0; i < 10; i++) {
+      if (lock_->Try()) {
+        acquired_++;
+        PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+        lock_->Release();
+      }
+    }
+  }
+
+  int acquired() const { return acquired_; }
+
+ private:
+  Lock* lock_;
+  int acquired_;
+
+  DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
+};
+
+TEST(LockTest, Basic) {
+  Lock lock;
+  BasicLockTestThread thread(&lock);
+  PlatformThreadHandle handle;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+  int acquired = 0;
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    lock.Release();
+  }
+  for (int i = 0; i < 10; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+    lock.Release();
+  }
+  for (int i = 0; i < 10; i++) {
+    if (lock.Try()) {
+      acquired++;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+      lock.Release();
+    }
+  }
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+    lock.Release();
+  }
+
+  PlatformThread::Join(handle);
+
+  EXPECT_GE(acquired, 20);
+  EXPECT_GE(thread.acquired(), 20);
+}
+
+// Test that Try() works as expected -------------------------------------------
+
+class TryLockTestThread : public PlatformThread::Delegate {
+ public:
+  explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
+
+  void ThreadMain() override {
+    got_lock_ = lock_->Try();
+    if (got_lock_)
+      lock_->Release();
+  }
+
+  bool got_lock() const { return got_lock_; }
+
+ private:
+  Lock* lock_;
+  bool got_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
+};
+
+TEST(LockTest, TryLock) {
+  Lock lock;
+
+  ASSERT_TRUE(lock.Try());
+  // We now have the lock....
+
+  // This thread will not be able to get the lock.
+  {
+    TryLockTestThread thread(&lock);
+    PlatformThreadHandle handle;
+
+    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+    PlatformThread::Join(handle);
+
+    ASSERT_FALSE(thread.got_lock());
+  }
+
+  lock.Release();
+
+  // This thread will....
+  {
+    TryLockTestThread thread(&lock);
+    PlatformThreadHandle handle;
+
+    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+    PlatformThread::Join(handle);
+
+    ASSERT_TRUE(thread.got_lock());
+    // But it released it....
+    ASSERT_TRUE(lock.Try());
+  }
+
+  lock.Release();
+}
+
+// Tests that locks actually exclude -------------------------------------------
+
+class MutexLockTestThread : public PlatformThread::Delegate {
+ public:
+  MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
+
+  // Static helper which can also be called from the main thread.
+  static void DoStuff(Lock* lock, int* value) {
+    for (int i = 0; i < 40; i++) {
+      lock->Acquire();
+      int v = *value;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
+      *value = v + 1;
+      lock->Release();
+    }
+  }
+
+  void ThreadMain() override { DoStuff(lock_, value_); }
+
+ private:
+  Lock* lock_;
+  int* value_;
+
+  DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
+};
+
+TEST(LockTest, MutexTwoThreads) {
+  Lock lock;
+  int value = 0;
+
+  MutexLockTestThread thread(&lock, &value);
+  PlatformThreadHandle handle;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle);
+
+  EXPECT_EQ(2 * 40, value);
+}
+
+TEST(LockTest, MutexFourThreads) {
+  Lock lock;
+  int value = 0;
+
+  MutexLockTestThread thread1(&lock, &value);
+  MutexLockTestThread thread2(&lock, &value);
+  MutexLockTestThread thread3(&lock, &value);
+  PlatformThreadHandle handle1;
+  PlatformThreadHandle handle2;
+  PlatformThreadHandle handle3;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
+  ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
+  ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle1);
+  PlatformThread::Join(handle2);
+  PlatformThread::Join(handle3);
+
+  EXPECT_EQ(4 * 40, value);
+}
+
+}  // namespace base
diff --git a/base/synchronization/spin_wait.h b/base/synchronization/spin_wait.h
new file mode 100644
index 0000000..9b147cd
--- /dev/null
+++ b/base/synchronization/spin_wait.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides a macro ONLY for use in testing.
+// DO NOT USE IN PRODUCTION CODE.  There are much better ways to wait.
+
+// This code is very helpful in testing multi-threaded code, without depending
+// on almost any primitives.  This is especially helpful if you are testing
+// those primitive multi-threaded constructs.
+
+// We provide a simple one argument spin wait (for 1 second), and a generic
+// spin wait (for longer periods of time).
+
+#ifndef BASE_SYNCHRONIZATION_SPIN_WAIT_H_
+#define BASE_SYNCHRONIZATION_SPIN_WAIT_H_
+
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+// Provide a macro that will wait no longer than 1 second for an asynchronous
+// change is the value of an expression.
+// A typical use would be:
+//
+//   SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 == f(x));
+//
+// The expression will be evaluated repeatedly until it is true, or until
+// the time (1 second) expires.
+// Since tests generally have a 5 second watch dog timer, this spin loop is
+// typically used to get the padding needed on a given test platform to assure
+// that the test passes, even if load varies, and external events vary.
+
+#define SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(expression) \
+    SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(base::TimeDelta::FromSeconds(1), \
+                                     (expression))
+
+#define SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(delta, expression) do { \
+  base::TimeTicks start = base::TimeTicks::Now(); \
+  const base::TimeDelta kTimeout = delta; \
+    while (!(expression)) { \
+      if (kTimeout < base::TimeTicks::Now() - start) { \
+      EXPECT_LE((base::TimeTicks::Now() - start).InMilliseconds(), \
+                kTimeout.InMilliseconds()) << "Timed out"; \
+        break; \
+      } \
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); \
+    } \
+  } while (0)
+
+#endif  // BASE_SYNCHRONIZATION_SPIN_WAIT_H_
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
new file mode 100644
index 0000000..c35af54
--- /dev/null
+++ b/base/synchronization/waitable_event.h
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+#if defined(OS_POSIX)
+#include <list>
+#include <utility>
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace base {
+
+class TimeDelta;
+
+// A WaitableEvent can be a useful thread synchronization tool when you want to
+// allow one thread to wait for another thread to finish some work. For
+// non-Windows systems, this can only be used from within a single address
+// space.
+//
+// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
+// protect a simple boolean value.  However, if you find yourself using a
+// WaitableEvent in conjunction with a Lock to wait for a more complex state
+// change (e.g., for an item to be added to a queue), then you should probably
+// be using a ConditionVariable instead of a WaitableEvent.
+//
+// NOTE: On Windows, this class provides a subset of the functionality afforded
+// by a Windows event object.  This is intentional.  If you are writing Windows
+// specific code and you need other features of a Windows event, then you might
+// be better off just using an Windows event directly.
+class BASE_EXPORT WaitableEvent {
+ public:
+  // If manual_reset is true, then to set the event state to non-signaled, a
+  // consumer must call the Reset method.  If this parameter is false, then the
+  // system automatically resets the event state to non-signaled after a single
+  // waiting thread has been released.
+  WaitableEvent(bool manual_reset, bool initially_signaled);
+
+#if defined(OS_WIN)
+  // Create a WaitableEvent from an Event HANDLE which has already been
+  // created. This objects takes ownership of the HANDLE and will close it when
+  // deleted.
+  explicit WaitableEvent(win::ScopedHandle event_handle);
+#endif
+
+  ~WaitableEvent();
+
+  // Put the event in the un-signaled state.
+  void Reset();
+
+  // Put the event in the signaled state.  Causing any thread blocked on Wait
+  // to be woken up.
+  void Signal();
+
+  // Returns true if the event is in the signaled state, else false.  If this
+  // is not a manual reset event, then this test will cause a reset.
+  bool IsSignaled();
+
+  // Wait indefinitely for the event to be signaled. Wait's return "happens
+  // after" |Signal| has completed. This means that it's safe for a
+  // WaitableEvent to synchronise its own destruction, like this:
+  //
+  //   WaitableEvent *e = new WaitableEvent;
+  //   SendToOtherThread(e);
+  //   e->Wait();
+  //   delete e;
+  void Wait();
+
+  // Wait up until max_time has passed for the event to be signaled.  Returns
+  // true if the event was signaled.  If this method returns false, then it
+  // does not necessarily mean that max_time was exceeded.
+  //
+  // TimedWait can synchronise its own destruction like |Wait|.
+  bool TimedWait(const TimeDelta& max_time);
+
+#if defined(OS_WIN)
+  HANDLE handle() const { return handle_.Get(); }
+#endif
+
+  // Wait, synchronously, on multiple events.
+  //   waitables: an array of WaitableEvent pointers
+  //   count: the number of elements in @waitables
+  //
+  // returns: the index of a WaitableEvent which has been signaled.
+  //
+  // You MUST NOT delete any of the WaitableEvent objects while this wait is
+  // happening, however WaitMany's return "happens after" the |Signal| call
+  // that caused it has completed, like |Wait|.
+  static size_t WaitMany(WaitableEvent** waitables, size_t count);
+
+  // For asynchronous waiting, see WaitableEventWatcher
+
+  // This is a private helper class. It's here because it's used by friends of
+  // this class (such as WaitableEventWatcher) to be able to enqueue elements
+  // of the wait-list
+  class Waiter {
+   public:
+    // Signal the waiter to wake up.
+    //
+    // Consider the case of a Waiter which is in multiple WaitableEvent's
+    // wait-lists. Each WaitableEvent is automatic-reset and two of them are
+    // signaled at the same time. Now, each will wake only the first waiter in
+    // the wake-list before resetting. However, if those two waiters happen to
+    // be the same object (as can happen if another thread didn't have a chance
+    // to dequeue the waiter from the other wait-list in time), two auto-resets
+    // will have happened, but only one waiter has been signaled!
+    //
+    // Because of this, a Waiter may "reject" a wake by returning false. In
+    // this case, the auto-reset WaitableEvent shouldn't act as if anything has
+    // been notified.
+    virtual bool Fire(WaitableEvent* signaling_event) = 0;
+
+    // Waiters may implement this in order to provide an extra condition for
+    // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
+    // pointers match then this function is called as a final check. See the
+    // comments in ~Handle for why.
+    virtual bool Compare(void* tag) = 0;
+
+   protected:
+    virtual ~Waiter() {}
+  };
+
+ private:
+  friend class WaitableEventWatcher;
+
+#if defined(OS_WIN)
+  win::ScopedHandle handle_;
+#else
+  // On Windows, one can close a HANDLE which is currently being waited on. The
+  // MSDN documentation says that the resulting behaviour is 'undefined', but
+  // it doesn't crash. However, if we were to include the following members
+  // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
+  // event which gets deleted. This mismatch has bitten us several times now,
+  // so we have a kernel of the WaitableEvent, which is reference counted.
+  // WaitableEventWatchers may then take a reference and thus match the Windows
+  // behaviour.
+  struct WaitableEventKernel :
+      public RefCountedThreadSafe<WaitableEventKernel> {
+   public:
+    WaitableEventKernel(bool manual_reset, bool initially_signaled);
+
+    bool Dequeue(Waiter* waiter, void* tag);
+
+    base::Lock lock_;
+    const bool manual_reset_;
+    bool signaled_;
+    std::list<Waiter*> waiters_;
+
+   private:
+    friend class RefCountedThreadSafe<WaitableEventKernel>;
+    ~WaitableEventKernel();
+  };
+
+  typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+
+  // When dealing with arrays of WaitableEvent*, we want to sort by the address
+  // of the WaitableEvent in order to have a globally consistent locking order.
+  // In that case we keep them, in sorted order, in an array of pairs where the
+  // second element is the index of the WaitableEvent in the original,
+  // unsorted, array.
+  static size_t EnqueueMany(WaiterAndIndex* waitables,
+                            size_t count, Waiter* waiter);
+
+  bool SignalAll();
+  bool SignalOne();
+  void Enqueue(Waiter* waiter);
+
+  scoped_refptr<WaitableEventKernel> kernel_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc
new file mode 100644
index 0000000..696ffc7
--- /dev/null
+++ b/base/synchronization/waitable_event_posix.cc
@@ -0,0 +1,415 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+
+// -----------------------------------------------------------------------------
+// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
+// support cross-process events (where one process can signal an event which
+// others are waiting on). Because of this, we can avoid having one thread per
+// listener in several cases.
+//
+// The WaitableEvent maintains a list of waiters, protected by a lock. Each
+// waiter is either an async wait, in which case we have a Task and the
+// MessageLoop to run it on, or a blocking wait, in which case we have the
+// condition variable to signal.
+//
+// Waiting involves grabbing the lock and adding oneself to the wait list. Async
+// waits can be canceled, which means grabbing the lock and removing oneself
+// from the list.
+//
+// Waiting on multiple events is handled by adding a single, synchronous wait to
+// the wait-list of many events. An event passes a pointer to itself when
+// firing a waiter and so we can store that pointer to find out which event
+// triggered.
+// -----------------------------------------------------------------------------
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// This is just an abstract base class for waking the two types of waiters
+// -----------------------------------------------------------------------------
+WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
+    : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) {
+}
+
+WaitableEvent::~WaitableEvent() {
+}
+
+void WaitableEvent::Reset() {
+  base::AutoLock locked(kernel_->lock_);
+  kernel_->signaled_ = false;
+}
+
+void WaitableEvent::Signal() {
+  base::AutoLock locked(kernel_->lock_);
+
+  if (kernel_->signaled_)
+    return;
+
+  if (kernel_->manual_reset_) {
+    SignalAll();
+    kernel_->signaled_ = true;
+  } else {
+    // In the case of auto reset, if no waiters were woken, we remain
+    // signaled.
+    if (!SignalOne())
+      kernel_->signaled_ = true;
+  }
+}
+
+bool WaitableEvent::IsSignaled() {
+  base::AutoLock locked(kernel_->lock_);
+
+  const bool result = kernel_->signaled_;
+  if (result && !kernel_->manual_reset_)
+    kernel_->signaled_ = false;
+  return result;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waits
+
+// -----------------------------------------------------------------------------
+// This is a synchronous waiter. The thread is waiting on the given condition
+// variable and the fired flag in this object.
+// -----------------------------------------------------------------------------
+class SyncWaiter : public WaitableEvent::Waiter {
+ public:
+  SyncWaiter()
+      : fired_(false),
+        signaling_event_(NULL),
+        lock_(),
+        cv_(&lock_) {
+  }
+
+  bool Fire(WaitableEvent* signaling_event) override {
+    base::AutoLock locked(lock_);
+
+    if (fired_)
+      return false;
+
+    fired_ = true;
+    signaling_event_ = signaling_event;
+
+    cv_.Broadcast();
+
+    // Unlike AsyncWaiter objects, SyncWaiter objects are stack-allocated on
+    // the blocking thread's stack.  There is no |delete this;| in Fire.  The
+    // SyncWaiter object is destroyed when it goes out of scope.
+
+    return true;
+  }
+
+  WaitableEvent* signaling_event() const {
+    return signaling_event_;
+  }
+
+  // ---------------------------------------------------------------------------
+  // These waiters are always stack allocated and don't delete themselves. Thus
+  // there's no problem and the ABA tag is the same as the object pointer.
+  // ---------------------------------------------------------------------------
+  bool Compare(void* tag) override { return this == tag; }
+
+  // ---------------------------------------------------------------------------
+  // Called with lock held.
+  // ---------------------------------------------------------------------------
+  bool fired() const {
+    return fired_;
+  }
+
+  // ---------------------------------------------------------------------------
+  // During a TimedWait, we need a way to make sure that an auto-reset
+  // WaitableEvent doesn't think that this event has been signaled between
+  // unlocking it and removing it from the wait-list. Called with lock held.
+  // ---------------------------------------------------------------------------
+  void Disable() {
+    fired_ = true;
+  }
+
+  base::Lock* lock() {
+    return &lock_;
+  }
+
+  base::ConditionVariable* cv() {
+    return &cv_;
+  }
+
+ private:
+  bool fired_;
+  WaitableEvent* signaling_event_;  // The WaitableEvent which woke us
+  base::Lock lock_;
+  base::ConditionVariable cv_;
+};
+
+void WaitableEvent::Wait() {
+  bool result = TimedWait(TimeDelta::FromSeconds(-1));
+  DCHECK(result) << "TimedWait() should never fail with infinite timeout";
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  const TimeTicks end_time(TimeTicks::Now() + max_time);
+  const bool finite_time = max_time.ToInternalValue() >= 0;
+
+  kernel_->lock_.Acquire();
+  if (kernel_->signaled_) {
+    if (!kernel_->manual_reset_) {
+      // In this case we were signaled when we had no waiters. Now that
+      // someone has waited upon us, we can automatically reset.
+      kernel_->signaled_ = false;
+    }
+
+    kernel_->lock_.Release();
+    return true;
+  }
+
+  SyncWaiter sw;
+  sw.lock()->Acquire();
+
+  Enqueue(&sw);
+  kernel_->lock_.Release();
+  // We are violating locking order here by holding the SyncWaiter lock but not
+  // the WaitableEvent lock. However, this is safe because we don't lock @lock_
+  // again before unlocking it.
+
+  for (;;) {
+    const TimeTicks current_time(TimeTicks::Now());
+
+    if (sw.fired() || (finite_time && current_time >= end_time)) {
+      const bool return_value = sw.fired();
+
+      // We can't acquire @lock_ before releasing the SyncWaiter lock (because
+      // of locking order), however, in between the two a signal could be fired
+      // and @sw would accept it, however we will still return false, so the
+      // signal would be lost on an auto-reset WaitableEvent. Thus we call
+      // Disable which makes sw::Fire return false.
+      sw.Disable();
+      sw.lock()->Release();
+
+      // This is a bug that has been enshrined in the interface of
+      // WaitableEvent now: |Dequeue| is called even when |sw.fired()| is true,
+      // even though it'll always return false in that case. However, taking
+      // the lock ensures that |Signal| has completed before we return and
+      // means that a WaitableEvent can synchronise its own destruction.
+      kernel_->lock_.Acquire();
+      kernel_->Dequeue(&sw, &sw);
+      kernel_->lock_.Release();
+
+      return return_value;
+    }
+
+    if (finite_time) {
+      const TimeDelta max_wait(end_time - current_time);
+      sw.cv()->TimedWait(max_wait);
+    } else {
+      sw.cv()->Wait();
+    }
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waiting on multiple objects.
+
+static bool  // StrictWeakOrdering
+cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a,
+             const std::pair<WaitableEvent*, unsigned> &b) {
+  return a.first < b.first;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
+                               size_t count) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DCHECK(count) << "Cannot wait on no events";
+
+  // We need to acquire the locks in a globally consistent order. Thus we sort
+  // the array of waitables by address. We actually sort a pairs so that we can
+  // map back to the original index values later.
+  std::vector<std::pair<WaitableEvent*, size_t> > waitables;
+  waitables.reserve(count);
+  for (size_t i = 0; i < count; ++i)
+    waitables.push_back(std::make_pair(raw_waitables[i], i));
+
+  DCHECK_EQ(count, waitables.size());
+
+  sort(waitables.begin(), waitables.end(), cmp_fst_addr);
+
+  // The set of waitables must be distinct. Since we have just sorted by
+  // address, we can check this cheaply by comparing pairs of consecutive
+  // elements.
+  for (size_t i = 0; i < waitables.size() - 1; ++i) {
+    DCHECK(waitables[i].first != waitables[i+1].first);
+  }
+
+  SyncWaiter sw;
+
+  const size_t r = EnqueueMany(&waitables[0], count, &sw);
+  if (r) {
+    // One of the events is already signaled. The SyncWaiter has not been
+    // enqueued anywhere. EnqueueMany returns the count of remaining waitables
+    // when the signaled one was seen, so the index of the signaled event is
+    // @count - @r.
+    return waitables[count - r].second;
+  }
+
+  // At this point, we hold the locks on all the WaitableEvents and we have
+  // enqueued our waiter in them all.
+  sw.lock()->Acquire();
+    // Release the WaitableEvent locks in the reverse order
+    for (size_t i = 0; i < count; ++i) {
+      waitables[count - (1 + i)].first->kernel_->lock_.Release();
+    }
+
+    for (;;) {
+      if (sw.fired())
+        break;
+
+      sw.cv()->Wait();
+    }
+  sw.lock()->Release();
+
+  // The address of the WaitableEvent which fired is stored in the SyncWaiter.
+  WaitableEvent *const signaled_event = sw.signaling_event();
+  // This will store the index of the raw_waitables which fired.
+  size_t signaled_index = 0;
+
+  // Take the locks of each WaitableEvent in turn (except the signaled one) and
+  // remove our SyncWaiter from the wait-list
+  for (size_t i = 0; i < count; ++i) {
+    if (raw_waitables[i] != signaled_event) {
+      raw_waitables[i]->kernel_->lock_.Acquire();
+        // There's no possible ABA issue with the address of the SyncWaiter here
+        // because it lives on the stack. Thus the tag value is just the pointer
+        // value again.
+        raw_waitables[i]->kernel_->Dequeue(&sw, &sw);
+      raw_waitables[i]->kernel_->lock_.Release();
+    } else {
+      // By taking this lock here we ensure that |Signal| has completed by the
+      // time we return, because |Signal| holds this lock. This matches the
+      // behaviour of |Wait| and |TimedWait|.
+      raw_waitables[i]->kernel_->lock_.Acquire();
+      raw_waitables[i]->kernel_->lock_.Release();
+      signaled_index = i;
+    }
+  }
+
+  return signaled_index;
+}
+
+// -----------------------------------------------------------------------------
+// If return value == 0:
+//   The locks of the WaitableEvents have been taken in order and the Waiter has
+//   been enqueued in the wait-list of each. None of the WaitableEvents are
+//   currently signaled
+// else:
+//   None of the WaitableEvent locks are held. The Waiter has not been enqueued
+//   in any of them and the return value is the index of the first WaitableEvent
+//   which was signaled, from the end of the array.
+// -----------------------------------------------------------------------------
+// static
+size_t WaitableEvent::EnqueueMany
+    (std::pair<WaitableEvent*, size_t>* waitables,
+     size_t count, Waiter* waiter) {
+  if (!count)
+    return 0;
+
+  waitables[0].first->kernel_->lock_.Acquire();
+    if (waitables[0].first->kernel_->signaled_) {
+      if (!waitables[0].first->kernel_->manual_reset_)
+        waitables[0].first->kernel_->signaled_ = false;
+      waitables[0].first->kernel_->lock_.Release();
+      return count;
+    }
+
+    const size_t r = EnqueueMany(waitables + 1, count - 1, waiter);
+    if (r) {
+      waitables[0].first->kernel_->lock_.Release();
+    } else {
+      waitables[0].first->Enqueue(waiter);
+    }
+
+    return r;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// Private functions...
+
+WaitableEvent::WaitableEventKernel::WaitableEventKernel(bool manual_reset,
+                                                        bool initially_signaled)
+    : manual_reset_(manual_reset),
+      signaled_(initially_signaled) {
+}
+
+WaitableEvent::WaitableEventKernel::~WaitableEventKernel() {
+}
+
+// -----------------------------------------------------------------------------
+// Wake all waiting waiters. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::SignalAll() {
+  bool signaled_at_least_one = false;
+
+  for (std::list<Waiter*>::iterator
+       i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) {
+    if ((*i)->Fire(this))
+      signaled_at_least_one = true;
+  }
+
+  kernel_->waiters_.clear();
+  return signaled_at_least_one;
+}
+
+// ---------------------------------------------------------------------------
+// Try to wake a single waiter. Return true if one was woken. Called with lock
+// held.
+// ---------------------------------------------------------------------------
+bool WaitableEvent::SignalOne() {
+  for (;;) {
+    if (kernel_->waiters_.empty())
+      return false;
+
+    const bool r = (*kernel_->waiters_.begin())->Fire(this);
+    kernel_->waiters_.pop_front();
+    if (r)
+      return true;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Add a waiter to the list of those waiting. Called with lock held.
+// -----------------------------------------------------------------------------
+void WaitableEvent::Enqueue(Waiter* waiter) {
+  kernel_->waiters_.push_back(waiter);
+}
+
+// -----------------------------------------------------------------------------
+// Remove a waiter from the list of those waiting. Return true if the waiter was
+// actually removed. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
+  for (std::list<Waiter*>::iterator
+       i = waiters_.begin(); i != waiters_.end(); ++i) {
+    if (*i == waiter && (*i)->Compare(tag)) {
+      waiters_.erase(i);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// -----------------------------------------------------------------------------
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_unittest.cc b/base/synchronization/waitable_event_unittest.cc
new file mode 100644
index 0000000..be56cf1
--- /dev/null
+++ b/base/synchronization/waitable_event_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/waitable_event.h"
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(WaitableEventTest, ManualBasics) {
+  WaitableEvent event(true, false);
+
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Signal();
+  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_TRUE(event.IsSignaled());
+
+  event.Reset();
+  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  event.Wait();
+  EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+}
+
+TEST(WaitableEventTest, AutoBasics) {
+  WaitableEvent event(false, false);
+
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Signal();
+  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Reset();
+  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  event.Wait();
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+}
+
+TEST(WaitableEventTest, WaitManyShortcut) {
+  WaitableEvent* ev[5];
+  for (unsigned i = 0; i < 5; ++i)
+    ev[i] = new WaitableEvent(false, false);
+
+  ev[3]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+  ev[3]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+  ev[4]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u);
+
+  ev[0]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u);
+
+  for (unsigned i = 0; i < 5; ++i)
+    delete ev[i];
+}
+
+class WaitableEventSignaler : public PlatformThread::Delegate {
+ public:
+  WaitableEventSignaler(TimeDelta delay, WaitableEvent* event)
+      : delay_(delay),
+        event_(event) {
+  }
+
+  void ThreadMain() override {
+    PlatformThread::Sleep(delay_);
+    event_->Signal();
+  }
+
+ private:
+  const TimeDelta delay_;
+  WaitableEvent* event_;
+};
+
+// Tests that a WaitableEvent can be safely deleted when |Wait| is done without
+// additional synchronization.
+TEST(WaitableEventTest, WaitAndDelete) {
+  WaitableEvent* ev = new WaitableEvent(false, false);
+
+  WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev);
+  PlatformThreadHandle thread;
+  PlatformThread::Create(0, &signaler, &thread);
+
+  ev->Wait();
+  delete ev;
+
+  PlatformThread::Join(thread);
+}
+
+// Tests that a WaitableEvent can be safely deleted when |WaitMany| is done
+// without additional synchronization.
+TEST(WaitableEventTest, WaitMany) {
+  WaitableEvent* ev[5];
+  for (unsigned i = 0; i < 5; ++i)
+    ev[i] = new WaitableEvent(false, false);
+
+  WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev[2]);
+  PlatformThreadHandle thread;
+  PlatformThread::Create(0, &signaler, &thread);
+
+  size_t index = WaitableEvent::WaitMany(ev, 5);
+
+  for (unsigned i = 0; i < 5; ++i)
+    delete ev[i];
+
+  PlatformThread::Join(thread);
+  EXPECT_EQ(2u, index);
+}
+
+// Tests that using TimeDelta::Max() on TimedWait() is not the same as passing
+// a timeout of 0. (crbug.com/465948)
+#if defined(OS_POSIX)
+// crbug.com/465948 not fixed yet.
+#define MAYBE_TimedWait DISABLED_TimedWait
+#else
+#define MAYBE_TimedWait TimedWait
+#endif
+TEST(WaitableEventTest, MAYBE_TimedWait) {
+  WaitableEvent* ev = new WaitableEvent(false, false);
+
+  TimeDelta thread_delay = TimeDelta::FromMilliseconds(10);
+  WaitableEventSignaler signaler(thread_delay, ev);
+  PlatformThreadHandle thread;
+  TimeTicks start = TimeTicks::Now();
+  PlatformThread::Create(0, &signaler, &thread);
+
+  ev->TimedWait(TimeDelta::Max());
+  EXPECT_GE(TimeTicks::Now() - start, thread_delay);
+  delete ev;
+
+  PlatformThread::Join(thread);
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher.h b/base/synchronization/waitable_event_watcher.h
new file mode 100644
index 0000000..eb51eff
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/object_watcher.h"
+#else
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#endif
+
+namespace base {
+
+class Flag;
+class AsyncWaiter;
+class AsyncCallbackTask;
+class WaitableEvent;
+
+// This class provides a way to wait on a WaitableEvent asynchronously.
+//
+// Each instance of this object can be waiting on a single WaitableEvent. When
+// the waitable event is signaled, a callback is made in the thread of a given
+// MessageLoop. This callback can be deleted by deleting the waiter.
+//
+// Typical usage:
+//
+//   class MyClass {
+//    public:
+//     void DoStuffWhenSignaled(WaitableEvent *waitable_event) {
+//       watcher_.StartWatching(waitable_event,
+//           base::Bind(&MyClass::OnWaitableEventSignaled, this);
+//     }
+//    private:
+//     void OnWaitableEventSignaled(WaitableEvent* waitable_event) {
+//       // OK, time to do stuff!
+//     }
+//     base::WaitableEventWatcher watcher_;
+//   };
+//
+// In the above example, MyClass wants to "do stuff" when waitable_event
+// becomes signaled. WaitableEventWatcher makes this task easy. When MyClass
+// goes out of scope, the watcher_ will be destroyed, and there is no need to
+// worry about OnWaitableEventSignaled being called on a deleted MyClass
+// pointer.
+//
+// BEWARE: With automatically reset WaitableEvents, a signal may be lost if it
+// occurs just before a WaitableEventWatcher is deleted. There is currently no
+// safe way to stop watching an automatic reset WaitableEvent without possibly
+// missing a signal.
+//
+// NOTE: you /are/ allowed to delete the WaitableEvent while still waiting on
+// it with a Watcher. It will act as if the event was never signaled.
+
+class BASE_EXPORT WaitableEventWatcher
+#if defined(OS_WIN)
+    : public win::ObjectWatcher::Delegate {
+#else
+    : public MessageLoop::DestructionObserver {
+#endif
+ public:
+  typedef Callback<void(WaitableEvent*)> EventCallback;
+  WaitableEventWatcher();
+  ~WaitableEventWatcher() override;
+
+  // When @event is signaled, the given callback is called on the thread of the
+  // current message loop when StartWatching is called.
+  bool StartWatching(WaitableEvent* event, const EventCallback& callback);
+
+  // Cancel the current watch. Must be called from the same thread which
+  // started the watch.
+  //
+  // Does nothing if no event is being watched, nor if the watch has completed.
+  // The callback will *not* be called for the current watch after this
+  // function returns. Since the callback runs on the same thread as this
+  // function, it cannot be called during this function either.
+  void StopWatching();
+
+  // Return the currently watched event, or NULL if no object is currently being
+  // watched.
+  WaitableEvent* GetWatchedEvent();
+
+  // Return the callback that will be invoked when the event is
+  // signaled.
+  const EventCallback& callback() const { return callback_; }
+
+ private:
+#if defined(OS_WIN)
+  void OnObjectSignaled(HANDLE h) override;
+  win::ObjectWatcher watcher_;
+#else
+  // Implementation of MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
+  MessageLoop* message_loop_;
+  scoped_refptr<Flag> cancel_flag_;
+  AsyncWaiter* waiter_;
+  base::Closure internal_callback_;
+  scoped_refptr<WaitableEvent::WaitableEventKernel> kernel_;
+#endif
+
+  WaitableEvent* event_;
+  EventCallback callback_;
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
diff --git a/base/synchronization/waitable_event_watcher_posix.cc b/base/synchronization/waitable_event_watcher_posix.cc
new file mode 100644
index 0000000..ad66a4c
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_posix.cc
@@ -0,0 +1,269 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/waitable_event_watcher.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// WaitableEventWatcher (async waits).
+//
+// The basic design is that we add an AsyncWaiter to the wait-list of the event.
+// That AsyncWaiter has a pointer to MessageLoop, and a Task to be posted to it.
+// The MessageLoop ends up running the task, which calls the delegate.
+//
+// Since the wait can be canceled, we have a thread-safe Flag object which is
+// set when the wait has been canceled. At each stage in the above, we check the
+// flag before going onto the next stage. Since the wait may only be canceled in
+// the MessageLoop which runs the Task, we are assured that the delegate cannot
+// be called after canceling...
+
+// -----------------------------------------------------------------------------
+// A thread-safe, reference-counted, write-once flag.
+// -----------------------------------------------------------------------------
+class Flag : public RefCountedThreadSafe<Flag> {
+ public:
+  Flag() { flag_ = false; }
+
+  void Set() {
+    AutoLock locked(lock_);
+    flag_ = true;
+  }
+
+  bool value() const {
+    AutoLock locked(lock_);
+    return flag_;
+  }
+
+ private:
+  friend class RefCountedThreadSafe<Flag>;
+  ~Flag() {}
+
+  mutable Lock lock_;
+  bool flag_;
+
+  DISALLOW_COPY_AND_ASSIGN(Flag);
+};
+
+// -----------------------------------------------------------------------------
+// This is an asynchronous waiter which posts a task to a MessageLoop when
+// fired. An AsyncWaiter may only be in a single wait-list.
+// -----------------------------------------------------------------------------
+class AsyncWaiter : public WaitableEvent::Waiter {
+ public:
+  AsyncWaiter(MessageLoop* message_loop,
+              const base::Closure& callback,
+              Flag* flag)
+      : message_loop_(message_loop),
+        callback_(callback),
+        flag_(flag) { }
+
+  bool Fire(WaitableEvent* event) override {
+    // Post the callback if we haven't been cancelled.
+    if (!flag_->value()) {
+      message_loop_->task_runner()->PostTask(FROM_HERE, callback_);
+    }
+
+    // We are removed from the wait-list by the WaitableEvent itself. It only
+    // remains to delete ourselves.
+    delete this;
+
+    // We can always return true because an AsyncWaiter is never in two
+    // different wait-lists at the same time.
+    return true;
+  }
+
+  // See StopWatching for discussion
+  bool Compare(void* tag) override { return tag == flag_.get(); }
+
+ private:
+  MessageLoop *const message_loop_;
+  base::Closure callback_;
+  scoped_refptr<Flag> flag_;
+};
+
+// -----------------------------------------------------------------------------
+// For async waits we need to make a callback in a MessageLoop thread. We do
+// this by posting a callback, which calls the delegate and keeps track of when
+// the event is canceled.
+// -----------------------------------------------------------------------------
+void AsyncCallbackHelper(Flag* flag,
+                         const WaitableEventWatcher::EventCallback& callback,
+                         WaitableEvent* event) {
+  // Runs in MessageLoop thread.
+  if (!flag->value()) {
+    // This is to let the WaitableEventWatcher know that the event has occured
+    // because it needs to be able to return NULL from GetWatchedObject
+    flag->Set();
+    callback.Run(event);
+  }
+}
+
+WaitableEventWatcher::WaitableEventWatcher()
+    : message_loop_(NULL),
+      cancel_flag_(NULL),
+      waiter_(NULL),
+      event_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+  StopWatching();
+}
+
+// -----------------------------------------------------------------------------
+// The Handle is how the user cancels a wait. After deleting the Handle we
+// insure that the delegate cannot be called.
+// -----------------------------------------------------------------------------
+bool WaitableEventWatcher::StartWatching(
+    WaitableEvent* event,
+    const EventCallback& callback) {
+  MessageLoop *const current_ml = MessageLoop::current();
+  DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a "
+                        "current MessageLoop";
+
+  // A user may call StartWatching from within the callback function. In this
+  // case, we won't know that we have finished watching, expect that the Flag
+  // will have been set in AsyncCallbackHelper().
+  if (cancel_flag_.get() && cancel_flag_->value()) {
+    if (message_loop_) {
+      message_loop_->RemoveDestructionObserver(this);
+      message_loop_ = NULL;
+    }
+
+    cancel_flag_ = NULL;
+  }
+
+  DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching";
+
+  cancel_flag_ = new Flag;
+  callback_ = callback;
+  internal_callback_ =
+      base::Bind(&AsyncCallbackHelper, cancel_flag_, callback_, event);
+  WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get();
+
+  AutoLock locked(kernel->lock_);
+
+  event_ = event;
+
+  if (kernel->signaled_) {
+    if (!kernel->manual_reset_)
+      kernel->signaled_ = false;
+
+    // No hairpinning - we can't call the delegate directly here. We have to
+    // enqueue a task on the MessageLoop as normal.
+    current_ml->task_runner()->PostTask(FROM_HERE, internal_callback_);
+    return true;
+  }
+
+  message_loop_ = current_ml;
+  current_ml->AddDestructionObserver(this);
+
+  kernel_ = kernel;
+  waiter_ = new AsyncWaiter(current_ml, internal_callback_, cancel_flag_.get());
+  event->Enqueue(waiter_);
+
+  return true;
+}
+
+void WaitableEventWatcher::StopWatching() {
+  callback_.Reset();
+
+  if (message_loop_) {
+    message_loop_->RemoveDestructionObserver(this);
+    message_loop_ = NULL;
+  }
+
+  if (!cancel_flag_.get())  // if not currently watching...
+    return;
+
+  if (cancel_flag_->value()) {
+    // In this case, the event has fired, but we haven't figured that out yet.
+    // The WaitableEvent may have been deleted too.
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  if (!kernel_.get()) {
+    // We have no kernel. This means that we never enqueued a Waiter on an
+    // event because the event was already signaled when StartWatching was
+    // called.
+    //
+    // In this case, a task was enqueued on the MessageLoop and will run.
+    // We set the flag in case the task hasn't yet run. The flag will stop the
+    // delegate getting called. If the task has run then we have the last
+    // reference to the flag and it will be deleted immedately after.
+    cancel_flag_->Set();
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  AutoLock locked(kernel_->lock_);
+  // We have a lock on the kernel. No one else can signal the event while we
+  // have it.
+
+  // We have a possible ABA issue here. If Dequeue was to compare only the
+  // pointer values then it's possible that the AsyncWaiter could have been
+  // fired, freed and the memory reused for a different Waiter which was
+  // enqueued in the same wait-list. We would think that that waiter was our
+  // AsyncWaiter and remove it.
+  //
+  // To stop this, Dequeue also takes a tag argument which is passed to the
+  // virtual Compare function before the two are considered a match. So we need
+  // a tag which is good for the lifetime of this handle: the Flag. Since we
+  // have a reference to the Flag, its memory cannot be reused while this object
+  // still exists. So if we find a waiter with the correct pointer value, and
+  // which shares a Flag pointer, we have a real match.
+  if (kernel_->Dequeue(waiter_, cancel_flag_.get())) {
+    // Case 2: the waiter hasn't been signaled yet; it was still on the wait
+    // list. We've removed it, thus we can delete it and the task (which cannot
+    // have been enqueued with the MessageLoop because the waiter was never
+    // signaled)
+    delete waiter_;
+    internal_callback_.Reset();
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  // Case 3: the waiter isn't on the wait-list, thus it was signaled. It may
+  // not have run yet, so we set the flag to tell it not to bother enqueuing the
+  // task on the MessageLoop, but to delete it instead. The Waiter deletes
+  // itself once run.
+  cancel_flag_->Set();
+  cancel_flag_ = NULL;
+
+  // If the waiter has already run then the task has been enqueued. If the Task
+  // hasn't yet run, the flag will stop the delegate from getting called. (This
+  // is thread safe because one may only delete a Handle from the MessageLoop
+  // thread.)
+  //
+  // If the delegate has already been called then we have nothing to do. The
+  // task has been deleted by the MessageLoop.
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+  if (!cancel_flag_.get())
+    return NULL;
+
+  if (cancel_flag_->value())
+    return NULL;
+
+  return event_;
+}
+
+// -----------------------------------------------------------------------------
+// This is called when the MessageLoop which the callback will be run it is
+// deleted. We need to cancel the callback as if we had been deleted, but we
+// will still be deleted at some point in the future.
+// -----------------------------------------------------------------------------
+void WaitableEventWatcher::WillDestroyCurrentMessageLoop() {
+  StopWatching();
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc
new file mode 100644
index 0000000..5319d1e
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/waitable_event_watcher.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// The message loops on which each waitable event timer should be tested.
+const MessageLoop::Type testing_message_loops[] = {
+  MessageLoop::TYPE_DEFAULT,
+  MessageLoop::TYPE_IO,
+#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
+  MessageLoop::TYPE_UI,
+#endif
+};
+
+const int kNumTestingMessageLoops = arraysize(testing_message_loops);
+
+void QuitWhenSignaled(WaitableEvent* event) {
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+class DecrementCountContainer {
+ public:
+  explicit DecrementCountContainer(int* counter) : counter_(counter) {
+  }
+  void OnWaitableEventSignaled(WaitableEvent* object) {
+    --(*counter_);
+  }
+ private:
+  int* counter_;
+};
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
+
+  watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
+  EXPECT_EQ(&event, watcher.GetWatchedEvent());
+
+  event.Signal();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+
+  watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
+
+  watcher.StopWatching();
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+
+  int counter = 1;
+  DecrementCountContainer delegate(&counter);
+  WaitableEventWatcher::EventCallback callback =
+      Bind(&DecrementCountContainer::OnWaitableEventSignaled,
+           Unretained(&delegate));
+  watcher.StartWatching(&event, callback);
+
+  event.Signal();
+
+  // Let the background thread do its business
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
+
+  watcher.StopWatching();
+
+  RunLoop().RunUntilIdle();
+
+  // Our delegate should not have fired.
+  EXPECT_EQ(1, counter);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+  // Simulate a MessageLoop that dies before an WaitableEventWatcher.  This
+  // ordinarily doesn't happen when people use the Thread class, but it can
+  // happen when people use the Singleton pattern or atexit.
+  WaitableEvent event(true, false);
+  {
+    WaitableEventWatcher watcher;
+    {
+      MessageLoop message_loop(message_loop_type);
+
+      watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
+    }
+  }
+}
+
+void RunTest_DeleteUnder(MessageLoop::Type message_loop_type) {
+  // Delete the WaitableEvent out from under the Watcher. This is explictly
+  // allowed by the interface.
+
+  MessageLoop message_loop(message_loop_type);
+
+  {
+    WaitableEventWatcher watcher;
+
+    WaitableEvent* event = new WaitableEvent(false, false);
+
+    watcher.StartWatching(event, Bind(&QuitWhenSignaled));
+    delete event;
+  }
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(WaitableEventWatcherTest, BasicSignal) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_BasicSignal(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, BasicCancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_BasicCancel(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, CancelAfterSet) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_CancelAfterSet(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, OutlivesMessageLoop) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OutlivesMessageLoop(testing_message_loops[i]);
+  }
+}
+
+#if defined(OS_WIN)
+// Crashes sometimes on vista.  http://crbug.com/62119
+#define MAYBE_DeleteUnder DISABLED_DeleteUnder
+#else
+#define MAYBE_DeleteUnder DeleteUnder
+#endif
+TEST(WaitableEventWatcherTest, MAYBE_DeleteUnder) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DeleteUnder(testing_message_loops[i]);
+  }
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher_win.cc b/base/synchronization/waitable_event_watcher_win.cc
new file mode 100644
index 0000000..46d47ac
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_win.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/waitable_event_watcher.h"
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+WaitableEventWatcher::WaitableEventWatcher()
+    : event_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+}
+
+bool WaitableEventWatcher::StartWatching(
+    WaitableEvent* event,
+    const EventCallback& callback) {
+  callback_ = callback;
+  event_ = event;
+  return watcher_.StartWatching(event->handle(), this);
+}
+
+void WaitableEventWatcher::StopWatching() {
+  callback_.Reset();
+  event_ = NULL;
+  watcher_.StopWatching();
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+  return event_;
+}
+
+void WaitableEventWatcher::OnObjectSignaled(HANDLE h) {
+  WaitableEvent* event = event_;
+  EventCallback callback = callback_;
+  event_ = NULL;
+  callback_.Reset();
+  DCHECK(event);
+
+  callback.Run(event);
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
new file mode 100644
index 0000000..4db5627
--- /dev/null
+++ b/base/synchronization/waitable_event_win.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/waitable_event.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace base {
+
+WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
+    : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
+  // We're probably going to crash anyways if this is ever NULL, so we might as
+  // well make our stack reports more informative by crashing here.
+  CHECK(handle_.IsValid());
+}
+
+WaitableEvent::WaitableEvent(win::ScopedHandle handle)
+    : handle_(handle.Pass()) {
+  CHECK(handle_.IsValid()) << "Tried to create WaitableEvent from NULL handle";
+}
+
+WaitableEvent::~WaitableEvent() {
+}
+
+void WaitableEvent::Reset() {
+  ResetEvent(handle_.Get());
+}
+
+void WaitableEvent::Signal() {
+  SetEvent(handle_.Get());
+}
+
+bool WaitableEvent::IsSignaled() {
+  return TimedWait(TimeDelta());
+}
+
+void WaitableEvent::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DWORD result = WaitForSingleObject(handle_.Get(), INFINITE);
+  // It is most unexpected that this should ever fail.  Help consumers learn
+  // about it if it should ever fail.
+  DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed";
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DCHECK_GE(max_time, TimeDelta());
+  // Truncate the timeout to milliseconds. The API specifies that this method
+  // can return in less than |max_time| (when returning false), as the argument
+  // is the maximum time that a caller is willing to wait.
+  DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds());
+
+  DWORD result = WaitForSingleObject(handle_.Get(), timeout);
+  switch (result) {
+    case WAIT_OBJECT_0:
+      return true;
+    case WAIT_TIMEOUT:
+      return false;
+  }
+  // It is most unexpected that this should ever fail.  Help consumers learn
+  // about it if it should ever fail.
+  NOTREACHED() << "WaitForSingleObject failed";
+  return false;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+  CHECK_LE(count, MAXIMUM_WAIT_OBJECTS)
+      << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
+
+  for (size_t i = 0; i < count; ++i)
+    handles[i] = events[i]->handle();
+
+  // The cast is safe because count is small - see the CHECK above.
+  DWORD result =
+      WaitForMultipleObjects(static_cast<DWORD>(count),
+                             handles,
+                             FALSE,      // don't wait for all the objects
+                             INFINITE);  // no timeout
+  if (result >= WAIT_OBJECT_0 + count) {
+    DPLOG(FATAL) << "WaitForMultipleObjects failed";
+    return 0;
+  }
+
+  return result - WAIT_OBJECT_0;
+}
+
+}  // namespace base
diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h
new file mode 100644
index 0000000..704ed56
--- /dev/null
+++ b/base/sys_byteorder.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header defines cross-platform ByteSwap() implementations for 16, 32 and
+// 64-bit values, and NetToHostXX() / HostToNextXX() functions equivalent to
+// the traditional ntohX() and htonX() functions.
+// Use the functions defined here rather than using the platform-specific
+// functions directly.
+
+#ifndef BASE_SYS_BYTEORDER_H_
+#define BASE_SYS_BYTEORDER_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+namespace base {
+
+// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
+inline uint16 ByteSwap(uint16 x) {
+  return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
+}
+
+inline uint32 ByteSwap(uint32 x) {
+  return ((x & 0x000000fful) << 24) | ((x & 0x0000ff00ul) << 8) |
+      ((x & 0x00ff0000ul) >> 8) | ((x & 0xff000000ul) >> 24);
+}
+
+inline uint64 ByteSwap(uint64 x) {
+  return ((x & 0x00000000000000ffull) << 56) |
+      ((x & 0x000000000000ff00ull) << 40) |
+      ((x & 0x0000000000ff0000ull) << 24) |
+      ((x & 0x00000000ff000000ull) << 8) |
+      ((x & 0x000000ff00000000ull) >> 8) |
+      ((x & 0x0000ff0000000000ull) >> 24) |
+      ((x & 0x00ff000000000000ull) >> 40) |
+      ((x & 0xff00000000000000ull) >> 56);
+}
+
+// Converts the bytes in |x| from host order (endianness) to little endian, and
+// returns the result.
+inline uint16 ByteSwapToLE16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint32 ByteSwapToLE32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint64 ByteSwapToLE64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+
+// Converts the bytes in |x| from network to host order (endianness), and
+// returns the result.
+inline uint16 NetToHost16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32 NetToHost32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64 NetToHost64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+// Converts the bytes in |x| from host to network order (endianness), and
+// returns the result.
+inline uint16 HostToNet16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32 HostToNet32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64 HostToNet64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+}  // namespace base
+
+#endif  // BASE_SYS_BYTEORDER_H_
diff --git a/base/sys_info.cc b/base/sys_info.cc
new file mode 100644
index 0000000..8640dc1
--- /dev/null
+++ b/base/sys_info.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info_internal.h"
+#include "base/time/time.h"
+
+namespace base {
+
+#if !defined(OS_ANDROID)
+
+static const int kLowMemoryDeviceThresholdMB = 512;
+
+bool DetectLowEndDevice() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableLowEndDeviceMode))
+    return true;
+  if (command_line->HasSwitch(switches::kDisableLowEndDeviceMode))
+    return false;
+
+  int ram_size_mb = SysInfo::AmountOfPhysicalMemoryMB();
+  return (ram_size_mb > 0 && ram_size_mb < kLowMemoryDeviceThresholdMB);
+}
+
+static LazyInstance<
+  internal::LazySysInfoValue<bool, DetectLowEndDevice> >::Leaky
+  g_lazy_low_end_device = LAZY_INSTANCE_INITIALIZER;
+
+// static
+bool SysInfo::IsLowEndDevice() {
+  const std::string group_name =
+      base::FieldTrialList::FindFullName("MemoryReduction");
+
+  // Low End Device Mode will be enabled if this client is assigned to
+  // one of those EnabledXXX groups.
+  if (StartsWithASCII(group_name, "Enabled", true))
+    return true;
+
+  return g_lazy_low_end_device.Get().value();
+}
+#endif
+
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+std::string SysInfo::HardwareModelName() {
+  return std::string();
+}
+#endif
+
+// static
+int64 SysInfo::Uptime() {
+  // This code relies on an implementation detail of TimeTicks::Now() - that
+  // its return value happens to coincide with the system uptime value in
+  // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
+  int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+  return uptime_in_microseconds / 1000;
+}
+
+}  // namespace base
diff --git a/base/sys_info.h b/base/sys_info.h
new file mode 100644
index 0000000..654d694
--- /dev/null
+++ b/base/sys_info.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYS_INFO_H_
+#define BASE_SYS_INFO_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class BASE_EXPORT SysInfo {
+ public:
+  // Return the number of logical processors/cores on the current machine.
+  static int NumberOfProcessors();
+
+  // Return the number of bytes of physical memory on the current machine.
+  static int64 AmountOfPhysicalMemory();
+
+  // Return the number of bytes of current available physical memory on the
+  // machine.
+  static int64 AmountOfAvailablePhysicalMemory();
+
+  // Return the number of bytes of virtual memory of this process. A return
+  // value of zero means that there is no limit on the available virtual
+  // memory.
+  static int64 AmountOfVirtualMemory();
+
+  // Return the number of megabytes of physical memory on the current machine.
+  static int AmountOfPhysicalMemoryMB() {
+    return static_cast<int>(AmountOfPhysicalMemory() / 1024 / 1024);
+  }
+
+  // Return the number of megabytes of available virtual memory, or zero if it
+  // is unlimited.
+  static int AmountOfVirtualMemoryMB() {
+    return static_cast<int>(AmountOfVirtualMemory() / 1024 / 1024);
+  }
+
+  // Return the available disk space in bytes on the volume containing |path|,
+  // or -1 on failure.
+  static int64 AmountOfFreeDiskSpace(const FilePath& path);
+
+  // Returns system uptime in milliseconds.
+  static int64 Uptime();
+
+  // Returns a descriptive string for the current machine model or an empty
+  // string if machime model is unknown or an error occured.
+  // e.g. MacPro1,1 on Mac.
+  // Only implemented on OS X, will return an empty string on other platforms.
+  static std::string HardwareModelName();
+
+  // Returns the name of the host operating system.
+  static std::string OperatingSystemName();
+
+  // Returns the version of the host operating system.
+  static std::string OperatingSystemVersion();
+
+  // Retrieves detailed numeric values for the OS version.
+  // TODO(port): Implement a Linux version of this method and enable the
+  // corresponding unit test.
+  // DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release
+  // for OS version-specific feature checks and workarounds. If you must use
+  // an OS version check instead of a feature check, use the base::mac::IsOS*
+  // family from base/mac/mac_util.h, or base::win::GetVersion from
+  // base/win/windows_version.h.
+  static void OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version);
+
+  // Returns the architecture of the running operating system.
+  // Exact return value may differ across platforms.
+  // e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86",
+  //      whereas a x86-64 kernel on the same CPU will return "x86_64"
+  static std::string OperatingSystemArchitecture();
+
+  // Avoid using this. Use base/cpu.h to get information about the CPU instead.
+  // http://crbug.com/148884
+  // Returns the CPU model name of the system. If it can not be figured out,
+  // an empty string is returned.
+  static std::string CPUModelName();
+
+  // Return the smallest amount of memory (in bytes) which the VM system will
+  // allocate.
+  static size_t VMAllocationGranularity();
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+  // Returns the maximum SysV shared memory segment size, or zero if there is no
+  // limit.
+  static uint64 MaxSharedMemorySize();
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
+
+#if defined(OS_CHROMEOS)
+  typedef std::map<std::string, std::string> LsbReleaseMap;
+
+  // Returns the contents of /etc/lsb-release as a map.
+  static const LsbReleaseMap& GetLsbReleaseMap();
+
+  // If |key| is present in the LsbReleaseMap, sets |value| and returns true.
+  static bool GetLsbReleaseValue(const std::string& key, std::string* value);
+
+  // Convenience function for GetLsbReleaseValue("CHROMEOS_RELEASE_BOARD",...).
+  // Returns "unknown" if CHROMEOS_RELEASE_BOARD is not set.
+  static std::string GetLsbReleaseBoard();
+
+  // Returns the creation time of /etc/lsb-release. (Used to get the date and
+  // time of the Chrome OS build).
+  static Time GetLsbReleaseTime();
+
+  // Returns true when actually running in a Chrome OS environment.
+  static bool IsRunningOnChromeOS();
+
+  // Test method to force re-parsing of lsb-release.
+  static void SetChromeOSVersionInfoForTest(const std::string& lsb_release,
+                                            const Time& lsb_release_time);
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+  // Returns the Android build's codename.
+  static std::string GetAndroidBuildCodename();
+
+  // Returns the Android build ID.
+  static std::string GetAndroidBuildID();
+
+  // Returns the device's name.
+  static std::string GetDeviceName();
+
+  static int DalvikHeapSizeMB();
+  static int DalvikHeapGrowthLimitMB();
+#endif  // defined(OS_ANDROID)
+
+  // Returns true if this is a low-end device.
+  // Low-end device refers to devices having less than 512M memory in the
+  // current implementation.
+  static bool IsLowEndDevice();
+};
+
+}  // namespace base
+
+#endif  // BASE_SYS_INFO_H_
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
new file mode 100644
index 0000000..245097f
--- /dev/null
+++ b/base/sys_info_android.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <dlfcn.h>
+#include <sys/system_properties.h>
+
+#include "base/android/sys_utils.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info_internal.h"
+
+#if (__ANDROID_API__ >= 21 /* 5.0 - Lollipop */)
+
+namespace {
+
+typedef int (SystemPropertyGetFunction)(const char*, char*);
+
+SystemPropertyGetFunction* DynamicallyLoadRealSystemPropertyGet() {
+  // libc.so should already be open, get a handle to it.
+  void* handle = dlopen("libc.so", RTLD_NOLOAD);
+  if (!handle) {
+    LOG(FATAL) << "Cannot dlopen libc.so: " << dlerror();
+  }
+  SystemPropertyGetFunction* real_system_property_get =
+      reinterpret_cast<SystemPropertyGetFunction*>(
+          dlsym(handle, "__system_property_get"));
+  if (!real_system_property_get) {
+    LOG(FATAL) << "Cannot resolve __system_property_get(): " << dlerror();
+  }
+  return real_system_property_get;
+}
+
+static base::LazyInstance<base::internal::LazySysInfoValue<
+    SystemPropertyGetFunction*, DynamicallyLoadRealSystemPropertyGet> >::Leaky
+    g_lazy_real_system_property_get = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Android 'L' removes __system_property_get from the NDK, however it is still
+// a hidden symbol in libc. Until we remove all calls of __system_property_get
+// from Chrome we work around this by defining a weak stub here, which uses
+// dlsym to but ensures that Chrome uses the real system
+// implementatation when loaded.  http://crbug.com/392191.
+BASE_EXPORT int __system_property_get(const char* name, char* value) {
+  return g_lazy_real_system_property_get.Get().value()(name, value);
+}
+
+#endif
+
+namespace {
+
+// Default version of Android to fall back to when actual version numbers
+// cannot be acquired. Use the latest Android release with a higher bug fix
+// version to avoid unnecessarily comparison errors with the latest release.
+// This should be manually kept up-to-date on each Android release.
+const int kDefaultAndroidMajorVersion = 5;
+const int kDefaultAndroidMinorVersion = 1;
+const int kDefaultAndroidBugfixVersion = 99;
+
+// Parse out the OS version numbers from the system properties.
+void ParseOSVersionNumbers(const char* os_version_str,
+                           int32 *major_version,
+                           int32 *minor_version,
+                           int32 *bugfix_version) {
+  if (os_version_str[0]) {
+    // Try to parse out the version numbers from the string.
+    int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
+                          minor_version, bugfix_version);
+
+    if (num_read > 0) {
+      // If we don't have a full set of version numbers, make the extras 0.
+      if (num_read < 2) *minor_version = 0;
+      if (num_read < 3) *bugfix_version = 0;
+      return;
+    }
+  }
+
+  // For some reason, we couldn't parse the version number string.
+  *major_version = kDefaultAndroidMajorVersion;
+  *minor_version = kDefaultAndroidMinorVersion;
+  *bugfix_version = kDefaultAndroidBugfixVersion;
+}
+
+// Parses a system property (specified with unit 'k','m' or 'g').
+// Returns a value in bytes.
+// Returns -1 if the string could not be parsed.
+int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
+  const int64 KB = 1024;
+  const int64 MB = 1024 * KB;
+  const int64 GB = 1024 * MB;
+  if (str.size() == 0u)
+    return -1;
+  int64 unit_multiplier = 1;
+  size_t length = str.size();
+  if (str[length - 1] == 'k') {
+    unit_multiplier = KB;
+    length--;
+  } else if (str[length - 1] == 'm') {
+    unit_multiplier = MB;
+    length--;
+  } else if (str[length - 1] == 'g') {
+    unit_multiplier = GB;
+    length--;
+  }
+  int64 result = 0;
+  bool parsed = base::StringToInt64(str.substr(0, length), &result);
+  bool negative = result <= 0;
+  bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier;
+  if (!parsed || negative || overflow)
+    return -1;
+  return result * unit_multiplier;
+}
+
+int GetDalvikHeapSizeMB() {
+  char heap_size_str[PROP_VALUE_MAX];
+  __system_property_get("dalvik.vm.heapsize", heap_size_str);
+  // dalvik.vm.heapsize property is writable by a root user.
+  // Clamp it to reasonable range as a sanity check,
+  // a typical android device will never have less than 48MB.
+  const int64 MB = 1024 * 1024;
+  int64 result = ParseSystemPropertyBytes(heap_size_str);
+  if (result == -1) {
+     // We should consider not exposing these values if they are not reliable.
+     LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str;
+     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3;
+  }
+  result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB;
+  return static_cast<int>(result);
+}
+
+int GetDalvikHeapGrowthLimitMB() {
+  char heap_size_str[PROP_VALUE_MAX];
+  __system_property_get("dalvik.vm.heapgrowthlimit", heap_size_str);
+  // dalvik.vm.heapgrowthlimit property is writable by a root user.
+  // Clamp it to reasonable range as a sanity check,
+  // a typical android device will never have less than 24MB.
+  const int64 MB = 1024 * 1024;
+  int64 result = ParseSystemPropertyBytes(heap_size_str);
+  if (result == -1) {
+     // We should consider not exposing these values if they are not reliable.
+     LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str;
+     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6;
+  }
+  result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB;
+  return static_cast<int>(result);
+}
+
+}  // anonymous namespace
+
+namespace base {
+
+std::string SysInfo::OperatingSystemName() {
+  return "Android";
+}
+
+std::string SysInfo::GetAndroidBuildCodename() {
+  char os_version_codename_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.codename", os_version_codename_str);
+  return std::string(os_version_codename_str);
+}
+
+std::string SysInfo::GetAndroidBuildID() {
+  char os_build_id_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.id", os_build_id_str);
+  return std::string(os_build_id_str);
+}
+
+std::string SysInfo::GetDeviceName() {
+  char device_model_str[PROP_VALUE_MAX];
+  __system_property_get("ro.product.model", device_model_str);
+  return std::string(device_model_str);
+}
+
+std::string SysInfo::OperatingSystemVersion() {
+  int32 major, minor, bugfix;
+  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+  return StringPrintf("%d.%d.%d", major, minor, bugfix);
+}
+
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  // Read the version number string out from the properties.
+  char os_version_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.release", os_version_str);
+
+  // Parse out the numbers.
+  ParseOSVersionNumbers(os_version_str, major_version, minor_version,
+                        bugfix_version);
+}
+
+int SysInfo::DalvikHeapSizeMB() {
+  static int heap_size = GetDalvikHeapSizeMB();
+  return heap_size;
+}
+
+int SysInfo::DalvikHeapGrowthLimitMB() {
+  static int heap_growth_limit = GetDalvikHeapGrowthLimitMB();
+  return heap_growth_limit;
+}
+
+static base::LazyInstance<
+    base::internal::LazySysInfoValue<bool,
+        android::SysUtils::IsLowEndDeviceFromJni> >::Leaky
+    g_lazy_low_end_device = LAZY_INSTANCE_INITIALIZER;
+
+bool SysInfo::IsLowEndDevice() {
+  return g_lazy_low_end_device.Get().value();
+}
+
+
+}  // namespace base
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
new file mode 100644
index 0000000..9915055
--- /dev/null
+++ b/base/sys_info_chromeos.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include "base/basictypes.h"
+#include "base/environment.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+const char* const kLinuxStandardBaseVersionKeys[] = {
+  "CHROMEOS_RELEASE_VERSION",
+  "GOOGLE_RELEASE",
+  "DISTRIB_RELEASE",
+};
+
+const char kChromeOsReleaseNameKey[] = "CHROMEOS_RELEASE_NAME";
+
+const char* const kChromeOsReleaseNames[] = {
+  "Chrome OS",
+  "Chromium OS",
+};
+
+const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
+
+const char kLsbReleaseKey[] = "LSB_RELEASE";
+const char kLsbReleaseTimeKey[] = "LSB_RELEASE_TIME";  // Seconds since epoch
+
+const char kLsbReleaseSourceKey[] = "lsb-release";
+const char kLsbReleaseSourceEnv[] = "env";
+const char kLsbReleaseSourceFile[] = "file";
+
+class ChromeOSVersionInfo {
+ public:
+  ChromeOSVersionInfo() {
+    Parse();
+  }
+
+  void Parse() {
+    lsb_release_map_.clear();
+    major_version_ = 0;
+    minor_version_ = 0;
+    bugfix_version_ = 0;
+    is_running_on_chromeos_ = false;
+
+    std::string lsb_release, lsb_release_time_str;
+    scoped_ptr<Environment> env(Environment::Create());
+    bool parsed_from_env =
+        env->GetVar(kLsbReleaseKey, &lsb_release) &&
+        env->GetVar(kLsbReleaseTimeKey, &lsb_release_time_str);
+    if (parsed_from_env) {
+      double us = 0;
+      if (StringToDouble(lsb_release_time_str, &us))
+        lsb_release_time_ = Time::FromDoubleT(us);
+    } else {
+      // If the LSB_RELEASE and LSB_RELEASE_TIME environment variables are not
+      // set, fall back to a blocking read of the lsb_release file. This should
+      // only happen in non Chrome OS environments.
+      ThreadRestrictions::ScopedAllowIO allow_io;
+      FilePath path(kLinuxStandardBaseReleaseFile);
+      ReadFileToString(path, &lsb_release);
+      File::Info fileinfo;
+      if (GetFileInfo(path, &fileinfo))
+        lsb_release_time_ = fileinfo.creation_time;
+    }
+    ParseLsbRelease(lsb_release);
+    // For debugging:
+    lsb_release_map_[kLsbReleaseSourceKey] =
+        parsed_from_env ? kLsbReleaseSourceEnv : kLsbReleaseSourceFile;
+  }
+
+  bool GetLsbReleaseValue(const std::string& key, std::string* value) {
+    SysInfo::LsbReleaseMap::const_iterator iter = lsb_release_map_.find(key);
+    if (iter == lsb_release_map_.end())
+      return false;
+    *value = iter->second;
+    return true;
+  }
+
+  void GetVersionNumbers(int32* major_version,
+                         int32* minor_version,
+                         int32* bugfix_version) {
+    *major_version = major_version_;
+    *minor_version = minor_version_;
+    *bugfix_version = bugfix_version_;
+  }
+
+  const Time& lsb_release_time() const { return lsb_release_time_; }
+  const SysInfo::LsbReleaseMap& lsb_release_map() const {
+    return lsb_release_map_;
+  }
+  bool is_running_on_chromeos() const { return is_running_on_chromeos_; }
+
+ private:
+  void ParseLsbRelease(const std::string& lsb_release) {
+    // Parse and cache lsb_release key pairs. There should only be a handful
+    // of entries so the overhead for this will be small, and it can be
+    // useful for debugging.
+    base::StringPairs pairs;
+    SplitStringIntoKeyValuePairs(lsb_release, '=', '\n', &pairs);
+    for (size_t i = 0; i < pairs.size(); ++i) {
+      std::string key, value;
+      TrimWhitespaceASCII(pairs[i].first, TRIM_ALL, &key);
+      TrimWhitespaceASCII(pairs[i].second, TRIM_ALL, &value);
+      if (key.empty())
+        continue;
+      lsb_release_map_[key] = value;
+    }
+    // Parse the version from the first matching recognized version key.
+    std::string version;
+    for (size_t i = 0; i < arraysize(kLinuxStandardBaseVersionKeys); ++i) {
+      std::string key = kLinuxStandardBaseVersionKeys[i];
+      if (GetLsbReleaseValue(key, &version) && !version.empty())
+        break;
+    }
+    StringTokenizer tokenizer(version, ".");
+    if (tokenizer.GetNext()) {
+      StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()),
+                  &major_version_);
+    }
+    if (tokenizer.GetNext()) {
+      StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()),
+                  &minor_version_);
+    }
+    if (tokenizer.GetNext()) {
+      StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()),
+                  &bugfix_version_);
+    }
+
+    // Check release name for Chrome OS.
+    std::string release_name;
+    if (GetLsbReleaseValue(kChromeOsReleaseNameKey, &release_name)) {
+      for (size_t i = 0; i < arraysize(kChromeOsReleaseNames); ++i) {
+        if (release_name == kChromeOsReleaseNames[i]) {
+          is_running_on_chromeos_ = true;
+          break;
+        }
+      }
+    }
+  }
+
+  Time lsb_release_time_;
+  SysInfo::LsbReleaseMap lsb_release_map_;
+  int32 major_version_;
+  int32 minor_version_;
+  int32 bugfix_version_;
+  bool is_running_on_chromeos_;
+};
+
+static LazyInstance<ChromeOSVersionInfo>
+    g_chrome_os_version_info = LAZY_INSTANCE_INITIALIZER;
+
+ChromeOSVersionInfo& GetChromeOSVersionInfo() {
+  return g_chrome_os_version_info.Get();
+}
+
+}  // namespace
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  return GetChromeOSVersionInfo().GetVersionNumbers(
+      major_version, minor_version, bugfix_version);
+}
+
+// static
+const SysInfo::LsbReleaseMap& SysInfo::GetLsbReleaseMap() {
+  return GetChromeOSVersionInfo().lsb_release_map();
+}
+
+// static
+bool SysInfo::GetLsbReleaseValue(const std::string& key, std::string* value) {
+  return GetChromeOSVersionInfo().GetLsbReleaseValue(key, value);
+}
+
+// static
+std::string SysInfo::GetLsbReleaseBoard() {
+  const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD";
+  std::string board;
+  if (!GetLsbReleaseValue(kMachineInfoBoard, &board))
+    board = "unknown";
+  return board;
+}
+
+// static
+Time SysInfo::GetLsbReleaseTime() {
+  return GetChromeOSVersionInfo().lsb_release_time();
+}
+
+// static
+bool SysInfo::IsRunningOnChromeOS() {
+  return GetChromeOSVersionInfo().is_running_on_chromeos();
+}
+
+// static
+void SysInfo::SetChromeOSVersionInfoForTest(const std::string& lsb_release,
+                                            const Time& lsb_release_time) {
+  scoped_ptr<Environment> env(Environment::Create());
+  env->SetVar(kLsbReleaseKey, lsb_release);
+  env->SetVar(kLsbReleaseTimeKey,
+              DoubleToString(lsb_release_time.ToDoubleT()));
+  g_chrome_os_version_info.Get().Parse();
+}
+
+}  // namespace base
diff --git a/base/sys_info_freebsd.cc b/base/sys_info_freebsd.cc
new file mode 100644
index 0000000..515b59d
--- /dev/null
+++ b/base/sys_info_freebsd.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+int64 SysInfo::AmountOfPhysicalMemory() {
+  int pages, page_size;
+  size_t size = sizeof(pages);
+  sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
+  sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+// static
+uint64 SysInfo::MaxSharedMemorySize() {
+  size_t limit;
+  size_t size = sizeof(limit);
+  if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<uint64>(limit);
+}
+
+}  // namespace base
diff --git a/base/sys_info_internal.h b/base/sys_info_internal.h
new file mode 100644
index 0000000..e7674d5
--- /dev/null
+++ b/base/sys_info_internal.h
@@ -0,0 +1,34 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYS_INFO_INTERNAL_H_
+#define BASE_SYS_INFO_INTERNAL_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+
+namespace internal {
+
+template<typename T, T (*F)(void)>
+class LazySysInfoValue {
+ public:
+  LazySysInfoValue()
+      : value_(F()) { }
+
+  ~LazySysInfoValue() { }
+
+  T value() { return value_; }
+
+ private:
+  const T value_;
+
+  DISALLOW_COPY_AND_ASSIGN(LazySysInfoValue);
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_SYS_INFO_INTERNAL_H_
diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm
new file mode 100644
index 0000000..49d618c
--- /dev/null
+++ b/base/sys_info_ios.mm
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#import <UIKit/UIKit.h>
+#include <mach/mach.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  static dispatch_once_t get_system_name_once;
+  static std::string* system_name;
+  dispatch_once(&get_system_name_once, ^{
+      base::mac::ScopedNSAutoreleasePool pool;
+      system_name = new std::string(
+          SysNSStringToUTF8([[UIDevice currentDevice] systemName]));
+  });
+  // Examples of returned value: 'iPhone OS' on iPad 5.1.1
+  // and iPhone 5.1.1.
+  return *system_name;
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  static dispatch_once_t get_system_version_once;
+  static std::string* system_version;
+  dispatch_once(&get_system_version_once, ^{
+      base::mac::ScopedNSAutoreleasePool pool;
+      system_version = new std::string(
+          SysNSStringToUTF8([[UIDevice currentDevice] systemVersion]));
+  });
+  return *system_version;
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  base::mac::ScopedNSAutoreleasePool pool;
+  std::string system_version = OperatingSystemVersion();
+  if (!system_version.empty()) {
+    // Try to parse out the version numbers from the string.
+    int num_read = sscanf(system_version.c_str(), "%d.%d.%d", major_version,
+                          minor_version, bugfix_version);
+    if (num_read < 1)
+      *major_version = 0;
+    if (num_read < 2)
+      *minor_version = 0;
+    if (num_read < 3)
+      *bugfix_version = 0;
+  }
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  int result = host_info(host,
+                         HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo),
+                         &count);
+  if (result != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  return static_cast<int64>(hostinfo.max_mem);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  vm_statistics_data_t vm_info;
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+  if (host_statistics(host.get(),
+                      HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(
+      vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0)
+    return name;
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc
new file mode 100644
index 0000000..1bbfe9c
--- /dev/null
+++ b/base/sys_info_linux.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <limits>
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/sys_info_internal.h"
+
+namespace {
+
+int64 AmountOfMemory(int pages_name) {
+  long pages = sysconf(pages_name);
+  long page_size = sysconf(_SC_PAGESIZE);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+int64 AmountOfPhysicalMemory() {
+  return AmountOfMemory(_SC_PHYS_PAGES);
+}
+
+uint64 MaxSharedMemorySize() {
+  std::string contents;
+  base::ReadFileToString(base::FilePath("/proc/sys/kernel/shmmax"), &contents);
+  DCHECK(!contents.empty());
+  if (!contents.empty() && contents[contents.length() - 1] == '\n') {
+    contents.erase(contents.length() - 1);
+  }
+
+  uint64 limit;
+  if (!base::StringToUint64(contents, &limit)) {
+    limit = 0;
+  }
+  DCHECK_GT(limit, 0u);
+  return limit;
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int64, AmountOfPhysicalMemory> >::Leaky
+    g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<
+    base::internal::LazySysInfoValue<uint64, MaxSharedMemorySize> >::Leaky
+    g_lazy_max_shared_memory = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(_SC_AVPHYS_PAGES);
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  return g_lazy_physical_memory.Get().value();
+}
+
+// static
+uint64 SysInfo::MaxSharedMemorySize() {
+  return g_lazy_max_shared_memory.Get().value();
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
+  const char kCpuModelPrefix[] = "Hardware";
+#else
+  const char kCpuModelPrefix[] = "model name";
+#endif
+  std::string contents;
+  ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
+  DCHECK(!contents.empty());
+  if (!contents.empty()) {
+    std::istringstream iss(contents);
+    std::string line;
+    while (std::getline(iss, line)) {
+      if (line.compare(0, strlen(kCpuModelPrefix), kCpuModelPrefix) == 0) {
+        size_t pos = line.find(": ");
+        return line.substr(pos + 2);
+      }
+    }
+  }
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
new file mode 100644
index 0000000..18df624
--- /dev/null
+++ b/base/sys_info_mac.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreServices/CoreServices.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  return "Mac OS X";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  int32 major, minor, bugfix;
+  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+  return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  Gestalt(gestaltSystemVersionMajor,
+      reinterpret_cast<SInt32*>(major_version));
+  Gestalt(gestaltSystemVersionMinor,
+      reinterpret_cast<SInt32*>(minor_version));
+  Gestalt(gestaltSystemVersionBugFix,
+      reinterpret_cast<SInt32*>(bugfix_version));
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  int result = host_info(host,
+                         HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo),
+                         &count);
+  if (result != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  return static_cast<int64>(hostinfo.max_mem);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  vm_statistics_data_t vm_info;
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+
+  if (host_statistics(host.get(),
+                      HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(
+      vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0)
+    return name;
+  return std::string();
+}
+
+std::string SysInfo::HardwareModelName() {
+  char model[256];
+  size_t len = sizeof(model);
+  if (sysctlbyname("hw.model", model, &len, NULL, 0) == 0)
+    return std::string(model, 0, len);
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_openbsd.cc b/base/sys_info_openbsd.cc
new file mode 100644
index 0000000..595291b
--- /dev/null
+++ b/base/sys_info_openbsd.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <sys/param.h>
+#include <sys/shm.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+
+namespace {
+
+int64 AmountOfMemory(int pages_name) {
+  long pages = sysconf(pages_name);
+  long page_size = sysconf(_SC_PAGESIZE);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+}  // namespace
+
+namespace base {
+
+// static
+int SysInfo::NumberOfProcessors() {
+  int mib[] = { CTL_HW, HW_NCPU };
+  int ncpu;
+  size_t size = sizeof(ncpu);
+  if (sysctl(mib, arraysize(mib), &ncpu, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 1;
+  }
+  return ncpu;
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  return AmountOfMemory(_SC_PHYS_PAGES);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(_SC_AVPHYS_PAGES);
+}
+
+// static
+uint64 SysInfo::MaxSharedMemorySize() {
+  int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
+  size_t limit;
+  size_t size = sizeof(limit);
+  if (sysctl(mib, arraysize(mib), &limit, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<uint64>(limit);
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  int mib[] = { CTL_HW, HW_MODEL };
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctl(mib, arraysize(mib), name, &len, NULL, 0) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  return name;
+}
+
+}  // namespace base
diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc
new file mode 100644
index 0000000..3d49bf9
--- /dev/null
+++ b/base/sys_info_posix.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info_internal.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_ANDROID)
+#include <sys/vfs.h>
+#define statvfs statfs  // Android uses a statvfs-like statfs struct and call.
+#else
+#include <sys/statvfs.h>
+#endif
+
+namespace {
+
+#if !defined(OS_OPENBSD)
+int NumberOfProcessors() {
+  // sysconf returns the number of "logical" (not "physical") processors on both
+  // Mac and Linux.  So we get the number of max available "logical" processors.
+  //
+  // Note that the number of "currently online" processors may be fewer than the
+  // returned value of NumberOfProcessors(). On some platforms, the kernel may
+  // make some processors offline intermittently, to save power when system
+  // loading is low.
+  //
+  // One common use case that needs to know the processor count is to create
+  // optimal number of threads for optimization. It should make plan according
+  // to the number of "max available" processors instead of "currently online"
+  // ones. The kernel should be smart enough to make all processors online when
+  // it has sufficient number of threads waiting to run.
+  long res = sysconf(_SC_NPROCESSORS_CONF);
+  if (res == -1) {
+    NOTREACHED();
+    return 1;
+  }
+
+  return static_cast<int>(res);
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int, NumberOfProcessors> >::Leaky
+    g_lazy_number_of_processors = LAZY_INSTANCE_INITIALIZER;
+#endif
+
+int64 AmountOfVirtualMemory() {
+  struct rlimit limit;
+  int result = getrlimit(RLIMIT_DATA, &limit);
+  if (result != 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return limit.rlim_cur == RLIM_INFINITY ? 0 : limit.rlim_cur;
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int64, AmountOfVirtualMemory> >::Leaky
+    g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+#if !defined(OS_OPENBSD)
+int SysInfo::NumberOfProcessors() {
+  return g_lazy_number_of_processors.Get().value();
+}
+#endif
+
+// static
+int64 SysInfo::AmountOfVirtualMemory() {
+  return g_lazy_virtual_memory.Get().value();
+}
+
+// static
+int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  struct statvfs stats;
+  if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0)
+    return -1;
+  return static_cast<int64>(stats.f_bavail) * stats.f_frsize;
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+// static
+std::string SysInfo::OperatingSystemName() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  return std::string(info.sysname);
+}
+#endif
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  return std::string(info.release);
+}
+#endif
+
+// static
+std::string SysInfo::OperatingSystemArchitecture() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  std::string arch(info.machine);
+  if (arch == "i386" || arch == "i486" || arch == "i586" || arch == "i686") {
+    arch = "x86";
+  } else if (arch == "amd64") {
+    arch = "x86_64";
+  }
+  return arch;
+}
+
+// static
+size_t SysInfo::VMAllocationGranularity() {
+  return getpagesize();
+}
+
+}  // namespace base
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
new file mode 100644
index 0000000..15ae098
--- /dev/null
+++ b/base/sys_info_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/environment.h"
+#include "base/files/file_util.h"
+#include "base/sys_info.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest SysInfoTest;
+using base::FilePath;
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+TEST_F(SysInfoTest, MaxSharedMemorySize) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GT(base::SysInfo::MaxSharedMemorySize(), 0u);
+}
+#endif
+
+TEST_F(SysInfoTest, NumProcs) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GE(base::SysInfo::NumberOfProcessors(), 1);
+}
+
+TEST_F(SysInfoTest, AmountOfMem) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GT(base::SysInfo::AmountOfPhysicalMemory(), 0);
+  EXPECT_GT(base::SysInfo::AmountOfPhysicalMemoryMB(), 0);
+  // The maxmimal amount of virtual memory can be zero which means unlimited.
+  EXPECT_GE(base::SysInfo::AmountOfVirtualMemory(), 0);
+}
+
+TEST_F(SysInfoTest, AmountOfFreeDiskSpace) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  FilePath tmp_path;
+  ASSERT_TRUE(base::GetTempDir(&tmp_path));
+  EXPECT_GT(base::SysInfo::AmountOfFreeDiskSpace(tmp_path), 0)
+            << tmp_path.value();
+}
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_GT(os_major_version, -1);
+  EXPECT_GT(os_minor_version, -1);
+  EXPECT_GT(os_bugfix_version, -1);
+}
+#endif
+
+TEST_F(SysInfoTest, Uptime) {
+  int64 up_time_1 = base::SysInfo::Uptime();
+  // UpTime() is implemented internally using TimeTicks::Now(), which documents
+  // system resolution as being 1-15ms. Sleep a little longer than that.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+  int64 up_time_2 = base::SysInfo::Uptime();
+  EXPECT_GT(up_time_1, 0);
+  EXPECT_GT(up_time_2, up_time_1);
+}
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+TEST_F(SysInfoTest, HardwareModelName) {
+  std::string hardware_model = base::SysInfo::HardwareModelName();
+  EXPECT_FALSE(hardware_model.empty());
+}
+#endif
+
+#if defined(OS_CHROMEOS)
+
+TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  const char kLsbRelease[] =
+      "FOO=1234123.34.5\n"
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_EQ(1, os_major_version);
+  EXPECT_EQ(2, os_minor_version);
+  EXPECT_EQ(3, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  const char kLsbRelease[] =
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
+      "FOO=1234123.34.5\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_EQ(1, os_major_version);
+  EXPECT_EQ(2, os_minor_version);
+  EXPECT_EQ(3, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  const char kLsbRelease[] = "FOO=1234123.34.5\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_EQ(0, os_major_version);
+  EXPECT_EQ(0, os_minor_version);
+  EXPECT_EQ(0, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSLsbReleaseTime) {
+  const char kLsbRelease[] = "CHROMEOS_RELEASE_VERSION=1.2.3.4";
+  // Use a fake time that can be safely displayed as a string.
+  const base::Time lsb_release_time(base::Time::FromDoubleT(12345.6));
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, lsb_release_time);
+  base::Time parsed_lsb_release_time = base::SysInfo::GetLsbReleaseTime();
+  EXPECT_DOUBLE_EQ(lsb_release_time.ToDoubleT(),
+                   parsed_lsb_release_time.ToDoubleT());
+}
+
+TEST_F(SysInfoTest, IsRunningOnChromeOS) {
+  base::SysInfo::SetChromeOSVersionInfoForTest("", base::Time());
+  EXPECT_FALSE(base::SysInfo::IsRunningOnChromeOS());
+
+  const char kLsbRelease1[] =
+      "CHROMEOS_RELEASE_NAME=Non Chrome OS\n"
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease1, base::Time());
+  EXPECT_FALSE(base::SysInfo::IsRunningOnChromeOS());
+
+  const char kLsbRelease2[] =
+      "CHROMEOS_RELEASE_NAME=Chrome OS\n"
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease2, base::Time());
+  EXPECT_TRUE(base::SysInfo::IsRunningOnChromeOS());
+
+  const char kLsbRelease3[] =
+      "CHROMEOS_RELEASE_NAME=Chromium OS\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease3, base::Time());
+  EXPECT_TRUE(base::SysInfo::IsRunningOnChromeOS());
+}
+
+#endif  // OS_CHROMEOS
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
new file mode 100644
index 0000000..c8314c7
--- /dev/null
+++ b/base/sys_info_win.cc
@@ -0,0 +1,125 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_info.h"
+
+#include <windows.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {
+  MEMORYSTATUSEX memory_info;
+  memory_info.dwLength = sizeof(memory_info);
+  if (!GlobalMemoryStatusEx(&memory_info)) {
+    NOTREACHED();
+    return 0;
+  }
+
+  int64 rv = static_cast<int64>(memory_info.*memory_field);
+  return rv < 0 ? kint64max : rv;
+}
+
+}  // namespace
+
+namespace base {
+
+// static
+int SysInfo::NumberOfProcessors() {
+  return win::OSInfo::GetInstance()->processors();
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(&MEMORYSTATUSEX::ullAvailPhys);
+}
+
+// static
+int64 SysInfo::AmountOfVirtualMemory() {
+  return 0;
+}
+
+// static
+int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  ULARGE_INTEGER available, total, free;
+  if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
+    return -1;
+
+  int64 rv = static_cast<int64>(available.QuadPart);
+  return rv < 0 ? kint64max : rv;
+}
+
+std::string SysInfo::OperatingSystemName() {
+  return "Windows NT";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  win::OSInfo* os_info = win::OSInfo::GetInstance();
+  win::OSInfo::VersionNumber version_number = os_info->version_number();
+  std::string version(StringPrintf("%d.%d", version_number.major,
+                                   version_number.minor));
+  win::OSInfo::ServicePack service_pack = os_info->service_pack();
+  if (service_pack.major != 0) {
+    version += StringPrintf(" SP%d", service_pack.major);
+    if (service_pack.minor != 0)
+      version += StringPrintf(".%d", service_pack.minor);
+  }
+  return version;
+}
+
+// TODO: Implement OperatingSystemVersionComplete, which would include
+// patchlevel/service pack number.
+// See chrome/browser/feedback/feedback_util.h, FeedbackUtil::SetOSVersion.
+
+// static
+std::string SysInfo::OperatingSystemArchitecture() {
+  win::OSInfo::WindowsArchitecture arch =
+      win::OSInfo::GetInstance()->architecture();
+  switch (arch) {
+    case win::OSInfo::X86_ARCHITECTURE:
+      return "x86";
+    case win::OSInfo::X64_ARCHITECTURE:
+      return "x86_64";
+    case win::OSInfo::IA64_ARCHITECTURE:
+      return "ia64";
+    default:
+      return "";
+  }
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  return win::OSInfo::GetInstance()->processor_model_name();
+}
+
+// static
+size_t SysInfo::VMAllocationGranularity() {
+  return win::OSInfo::GetInstance()->allocation_granularity();
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  win::OSInfo* os_info = win::OSInfo::GetInstance();
+  *major_version = os_info->version_number().major;
+  *minor_version = os_info->version_number().minor;
+  *bugfix_version = 0;
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor.cc b/base/system_monitor/system_monitor.cc
new file mode 100644
index 0000000..99152ab
--- /dev/null
+++ b/base/system_monitor/system_monitor.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+
+namespace base {
+
+static SystemMonitor* g_system_monitor = NULL;
+
+SystemMonitor::SystemMonitor()
+    :  devices_changed_observer_list_(
+          new ObserverListThreadSafe<DevicesChangedObserver>()) {
+  DCHECK(!g_system_monitor);
+  g_system_monitor = this;
+}
+
+SystemMonitor::~SystemMonitor() {
+  DCHECK_EQ(this, g_system_monitor);
+  g_system_monitor = NULL;
+}
+
+// static
+SystemMonitor* SystemMonitor::Get() {
+  return g_system_monitor;
+}
+
+void SystemMonitor::ProcessDevicesChanged(DeviceType device_type) {
+  NotifyDevicesChanged(device_type);
+}
+
+void SystemMonitor::AddDevicesChangedObserver(DevicesChangedObserver* obs) {
+  devices_changed_observer_list_->AddObserver(obs);
+}
+
+void SystemMonitor::RemoveDevicesChangedObserver(DevicesChangedObserver* obs) {
+  devices_changed_observer_list_->RemoveObserver(obs);
+}
+
+void SystemMonitor::NotifyDevicesChanged(DeviceType device_type) {
+  DVLOG(1) << "DevicesChanged with device type " << device_type;
+  devices_changed_observer_list_->Notify(
+      FROM_HERE, &DevicesChangedObserver::OnDevicesChanged, device_type);
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor.h b/base/system_monitor/system_monitor.h
new file mode 100644
index 0000000..5dd849f
--- /dev/null
+++ b/base/system_monitor/system_monitor.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Class for monitoring various system-related subsystems
+// such as power management, network status, etc.
+// TODO(mbelshe):  Add support beyond just power management.
+class BASE_EXPORT SystemMonitor {
+ public:
+  // Type of devices whose change need to be monitored, such as add/remove.
+  enum DeviceType {
+    DEVTYPE_AUDIO_CAPTURE,  // Audio capture device, e.g., microphone.
+    DEVTYPE_VIDEO_CAPTURE,  // Video capture device, e.g., webcam.
+    DEVTYPE_UNKNOWN,  // Other devices.
+  };
+
+  // Create SystemMonitor. Only one SystemMonitor instance per application
+  // is allowed.
+  SystemMonitor();
+  ~SystemMonitor();
+
+  // Get the application-wide SystemMonitor (if not present, returns NULL).
+  static SystemMonitor* Get();
+
+  class BASE_EXPORT DevicesChangedObserver {
+   public:
+    // Notification that the devices connected to the system have changed.
+    // This is only implemented on Windows currently.
+    virtual void OnDevicesChanged(DeviceType device_type) {}
+
+   protected:
+    virtual ~DevicesChangedObserver() {}
+  };
+
+  // Add a new observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void AddDevicesChangedObserver(DevicesChangedObserver* obs);
+
+  // Remove an existing observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void RemoveDevicesChangedObserver(DevicesChangedObserver* obs);
+
+  // The ProcessFoo() style methods are a broken pattern and should not
+  // be copied. Any significant addition to this class is blocked on
+  // refactoring to improve the state of affairs. See http://crbug.com/149059
+
+  // Cross-platform handling of a device change event.
+  void ProcessDevicesChanged(DeviceType device_type);
+
+ private:
+  // Functions to trigger notifications.
+  void NotifyDevicesChanged(DeviceType device_type);
+
+  scoped_refptr<ObserverListThreadSafe<DevicesChangedObserver> >
+      devices_changed_observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc
new file mode 100644
index 0000000..f3db4c7
--- /dev/null
+++ b/base/system_monitor/system_monitor_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/system_monitor/system_monitor.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/mock_devices_changed_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class SystemMonitorTest : public testing::Test {
+ protected:
+  SystemMonitorTest() {
+    system_monitor_.reset(new SystemMonitor);
+  }
+
+  MessageLoop message_loop_;
+  scoped_ptr<SystemMonitor> system_monitor_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SystemMonitorTest);
+};
+
+TEST_F(SystemMonitorTest, DeviceChangeNotifications) {
+  const int kObservers = 5;
+
+  testing::Sequence mock_sequencer[kObservers];
+  MockDevicesChangedObserver observers[kObservers];
+  for (int index = 0; index < kObservers; ++index) {
+    system_monitor_->AddDevicesChangedObserver(&observers[index]);
+
+    EXPECT_CALL(observers[index],
+                OnDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN))
+        .Times(3)
+        .InSequence(mock_sequencer[index]);
+  }
+
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  RunLoop().RunUntilIdle();
+
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  RunLoop().RunUntilIdle();
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc
new file mode 100644
index 0000000..a2e4799
--- /dev/null
+++ b/base/task/cancelable_task_tracker.cc
@@ -0,0 +1,188 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task/cancelable_task_tracker.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
+
+using base::Bind;
+using base::CancellationFlag;
+using base::Closure;
+using base::hash_map;
+using base::TaskRunner;
+
+namespace {
+
+void RunIfNotCanceled(const CancellationFlag* flag, const Closure& task) {
+  if (!flag->IsSet())
+    task.Run();
+}
+
+void RunIfNotCanceledThenUntrack(const CancellationFlag* flag,
+                                 const Closure& task,
+                                 const Closure& untrack) {
+  RunIfNotCanceled(flag, task);
+  untrack.Run();
+}
+
+bool IsCanceled(const CancellationFlag* flag,
+                base::ScopedClosureRunner* cleanup_runner) {
+  return flag->IsSet();
+}
+
+void RunAndDeleteFlag(const Closure& closure, const CancellationFlag* flag) {
+  closure.Run();
+  delete flag;
+}
+
+void RunOrPostToTaskRunner(TaskRunner* task_runner, const Closure& closure) {
+  if (task_runner->RunsTasksOnCurrentThread())
+    closure.Run();
+  else
+    task_runner->PostTask(FROM_HERE, closure);
+}
+
+}  // namespace
+
+namespace base {
+
+// static
+const CancelableTaskTracker::TaskId CancelableTaskTracker::kBadTaskId = 0;
+
+CancelableTaskTracker::CancelableTaskTracker()
+    : next_id_(1),weak_factory_(this) {}
+
+CancelableTaskTracker::~CancelableTaskTracker() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TryCancelAll();
+}
+
+CancelableTaskTracker::TaskId CancelableTaskTracker::PostTask(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  return PostTaskAndReply(task_runner, from_here, task, Bind(&base::DoNothing));
+}
+
+CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // We need a MessageLoop to run reply.
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
+
+  // Owned by reply callback below.
+  CancellationFlag* flag = new CancellationFlag();
+
+  TaskId id = next_id_;
+  next_id_++;  // int64 is big enough that we ignore the potential overflow.
+
+  const Closure& untrack_closure =
+      Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
+  bool success =
+      task_runner->PostTaskAndReply(from_here,
+                                    Bind(&RunIfNotCanceled, flag, task),
+                                    Bind(&RunIfNotCanceledThenUntrack,
+                                         base::Owned(flag),
+                                         reply,
+                                         untrack_closure));
+
+  if (!success)
+    return kBadTaskId;
+
+  Track(id, flag);
+  return id;
+}
+
+CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
+    IsCanceledCallback* is_canceled_cb) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
+
+  TaskId id = next_id_;
+  next_id_++;  // int64 is big enough that we ignore the potential overflow.
+
+  // Will be deleted by |untrack_and_delete_flag| after Untrack().
+  CancellationFlag* flag = new CancellationFlag();
+
+  Closure untrack_and_delete_flag = Bind(
+      &RunAndDeleteFlag,
+      Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id),
+      flag);
+
+  // Will always run |untrack_and_delete_flag| on current MessageLoop.
+  base::ScopedClosureRunner* untrack_and_delete_flag_runner =
+      new base::ScopedClosureRunner(Bind(&RunOrPostToTaskRunner,
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         untrack_and_delete_flag));
+
+  *is_canceled_cb =
+      Bind(&IsCanceled, flag, base::Owned(untrack_and_delete_flag_runner));
+
+  Track(id, flag);
+  return id;
+}
+
+void CancelableTaskTracker::TryCancel(TaskId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  hash_map<TaskId, CancellationFlag*>::const_iterator it = task_flags_.find(id);
+  if (it == task_flags_.end()) {
+    // Two possibilities:
+    //
+    //   1. The task has already been untracked.
+    //   2. The TaskId is bad or unknown.
+    //
+    // Since this function is best-effort, it's OK to ignore these.
+    return;
+  }
+  it->second->Set();
+}
+
+void CancelableTaskTracker::TryCancelAll() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  for (hash_map<TaskId, CancellationFlag*>::const_iterator it =
+           task_flags_.begin();
+       it != task_flags_.end();
+       ++it) {
+    it->second->Set();
+  }
+}
+
+bool CancelableTaskTracker::HasTrackedTasks() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return !task_flags_.empty();
+}
+
+void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  bool success = task_flags_.insert(std::make_pair(id, flag)).second;
+  DCHECK(success);
+}
+
+void CancelableTaskTracker::Untrack(TaskId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  size_t num = task_flags_.erase(id);
+  DCHECK_EQ(1u, num);
+}
+
+}  // namespace base
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h
new file mode 100644
index 0000000..b8a8b70
--- /dev/null
+++ b/base/task/cancelable_task_tracker.h
@@ -0,0 +1,140 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// CancelableTaskTracker posts tasks (in the form of a Closure) to a
+// TaskRunner, and is able to cancel the task later if it's not needed
+// anymore.  On destruction, CancelableTaskTracker will cancel all
+// tracked tasks.
+//
+// Each cancelable task can be associated with a reply (also a Closure). After
+// the task is run on the TaskRunner, |reply| will be posted back to
+// originating TaskRunner.
+//
+// NOTE:
+//
+// CancelableCallback (base/cancelable_callback.h) and WeakPtr binding are
+// preferred solutions for canceling a task. However, they don't support
+// cancelation from another thread. This is sometimes a performance critical
+// requirement. E.g. We need to cancel database lookup task on DB thread when
+// user changes inputed text. If it is performance critical to do a best effort
+// cancelation of a task, then CancelableTaskTracker is appropriate,
+// otherwise use one of the other mechanisms.
+//
+// THREAD-SAFETY:
+//
+// 1. CancelableTaskTracker objects are not thread safe. They must
+// be created, used, and destroyed on the originating thread that posts the
+// task. It's safe to destroy a CancelableTaskTracker while there
+// are outstanding tasks. This is commonly used to cancel all outstanding
+// tasks.
+//
+// 2. Both task and reply are deleted on the originating thread.
+//
+// 3. IsCanceledCallback is thread safe and can be run or deleted on any
+// thread.
+#ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_
+#define BASE_TASK_CANCELABLE_TASK_TRACKER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_checker.h"
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class CancellationFlag;
+class TaskRunner;
+
+class BASE_EXPORT CancelableTaskTracker {
+ public:
+  // All values except kBadTaskId are valid.
+  typedef int64 TaskId;
+  static const TaskId kBadTaskId;
+
+  typedef base::Callback<bool()> IsCanceledCallback;
+
+  CancelableTaskTracker();
+
+  // Cancels all tracked tasks.
+  ~CancelableTaskTracker();
+
+  TaskId PostTask(base::TaskRunner* task_runner,
+                  const tracked_objects::Location& from_here,
+                  const base::Closure& task);
+
+  TaskId PostTaskAndReply(base::TaskRunner* task_runner,
+                          const tracked_objects::Location& from_here,
+                          const base::Closure& task,
+                          const base::Closure& reply);
+
+  template <typename TaskReturnType, typename ReplyArgType>
+  TaskId PostTaskAndReplyWithResult(
+      base::TaskRunner* task_runner,
+      const tracked_objects::Location& from_here,
+      const base::Callback<TaskReturnType(void)>& task,
+      const base::Callback<void(ReplyArgType)>& reply) {
+    TaskReturnType* result = new TaskReturnType();
+    return PostTaskAndReply(
+        task_runner,
+        from_here,
+        base::Bind(&base::internal::ReturnAsParamAdapter<TaskReturnType>,
+                   task,
+                   base::Unretained(result)),
+        base::Bind(&base::internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
+                   reply,
+                   base::Owned(result)));
+  }
+
+  // Creates a tracked TaskId and an associated IsCanceledCallback. Client can
+  // later call TryCancel() with the returned TaskId, and run |is_canceled_cb|
+  // from any thread to check whether the TaskId is canceled.
+  //
+  // The returned task ID is tracked until the last copy of
+  // |is_canceled_cb| is destroyed.
+  //
+  // Note. This function is used to address some special cancelation requirement
+  // in existing code. You SHOULD NOT need this function in new code.
+  TaskId NewTrackedTaskId(IsCanceledCallback* is_canceled_cb);
+
+  // After calling this function, |task| and |reply| will not run. If the
+  // cancelation happens when |task| is running or has finished running, |reply|
+  // will not run. If |reply| is running or has finished running, cancellation
+  // is a noop.
+  //
+  // Note. It's OK to cancel a |task| for more than once. The later calls are
+  // noops.
+  void TryCancel(TaskId id);
+
+  // It's OK to call this function for more than once. The later calls are
+  // noops.
+  void TryCancelAll();
+
+  // Returns true iff there are in-flight tasks that are still being
+  // tracked.
+  bool HasTrackedTasks() const;
+
+ private:
+  void Track(TaskId id, base::CancellationFlag* flag);
+  void Untrack(TaskId id);
+
+  base::hash_map<TaskId, base::CancellationFlag*> task_flags_;
+
+  TaskId next_id_;
+  base::ThreadChecker thread_checker_;
+
+  base::WeakPtrFactory<CancelableTaskTracker> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CancelableTaskTracker);
+};
+
+}  // namespace base
+
+#endif  // BASE_TASK_CANCELABLE_TASK_TRACKER_H_
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc
new file mode 100644
index 0000000..ff9e40b
--- /dev/null
+++ b/base/task/cancelable_task_tracker_unittest.cc
@@ -0,0 +1,424 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task/cancelable_task_tracker.h"
+
+#include <cstddef>
+#include <deque>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class CancelableTaskTrackerTest : public testing::Test {
+ protected:
+  ~CancelableTaskTrackerTest() override { RunCurrentLoopUntilIdle(); }
+
+  void RunCurrentLoopUntilIdle() {
+    RunLoop run_loop;
+    run_loop.RunUntilIdle();
+  }
+
+  CancelableTaskTracker task_tracker_;
+
+ private:
+  // Needed by CancelableTaskTracker methods.
+  MessageLoop message_loop_;
+};
+
+void AddFailureAt(const tracked_objects::Location& location) {
+  ADD_FAILURE_AT(location.file_name(), location.line_number());
+}
+
+// Returns a closure that fails if run.
+Closure MakeExpectedNotRunClosure(const tracked_objects::Location& location) {
+  return Bind(&AddFailureAt, location);
+}
+
+// A helper class for MakeExpectedRunClosure() that fails if it is
+// destroyed without Run() having been called.  This class may be used
+// from multiple threads as long as Run() is called at most once
+// before destruction.
+class RunChecker {
+ public:
+  explicit RunChecker(const tracked_objects::Location& location)
+      : location_(location), called_(false) {}
+
+  ~RunChecker() {
+    if (!called_) {
+      ADD_FAILURE_AT(location_.file_name(), location_.line_number());
+    }
+  }
+
+  void Run() { called_ = true; }
+
+ private:
+  tracked_objects::Location location_;
+  bool called_;
+};
+
+// Returns a closure that fails on destruction if it hasn't been run.
+Closure MakeExpectedRunClosure(const tracked_objects::Location& location) {
+  return Bind(&RunChecker::Run, Owned(new RunChecker(location)));
+}
+
+}  // namespace
+
+// With the task tracker, post a task, a task with a reply, and get a
+// new task id without canceling any of them.  The tasks and the reply
+// should run and the "is canceled" callback should return false.
+TEST_F(CancelableTaskTrackerTest, NoCancel) {
+  Thread worker_thread("worker thread");
+  ASSERT_TRUE(worker_thread.Start());
+
+  ignore_result(task_tracker_.PostTask(worker_thread.task_runner().get(),
+                                       FROM_HERE,
+                                       MakeExpectedRunClosure(FROM_HERE)));
+
+  ignore_result(task_tracker_.PostTaskAndReply(
+      worker_thread.task_runner().get(), FROM_HERE,
+      MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE)));
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+
+  worker_thread.Stop();
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(is_canceled.Run());
+}
+
+// Post a task with the task tracker but cancel it before running the
+// task runner.  The task should not run.
+TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  EXPECT_EQ(1U, test_task_runner->GetPendingTasks().size());
+
+  task_tracker_.TryCancel(task_id);
+
+  test_task_runner->RunUntilIdle();
+}
+
+// Post a task with reply with the task tracker and cancel it before
+// running the task runner.  Neither the task nor the reply should
+// run.
+TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::TaskId task_id =
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedNotRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  task_tracker_.TryCancel(task_id);
+
+  test_task_runner->RunUntilIdle();
+}
+
+// Post a task with reply with the task tracker and cancel it after
+// running the task runner but before running the current message
+// loop.  The task should run but the reply should not.
+TEST_F(CancelableTaskTrackerTest, CancelReply) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::TaskId task_id =
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  test_task_runner->RunUntilIdle();
+
+  task_tracker_.TryCancel(task_id);
+}
+
+// Post a task with reply with the task tracker on a worker thread and
+// cancel it before running the current message loop.  The task should
+// run but the reply should not.
+TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
+  Thread worker_thread("worker thread");
+  ASSERT_TRUE(worker_thread.Start());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply(
+      worker_thread.task_runner().get(), FROM_HERE, Bind(&DoNothing),
+      MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  task_tracker_.TryCancel(task_id);
+
+  worker_thread.Stop();
+}
+
+void ExpectIsCanceled(
+    const CancelableTaskTracker::IsCanceledCallback& is_canceled,
+    bool expected_is_canceled) {
+  EXPECT_EQ(expected_is_canceled, is_canceled.Run());
+}
+
+// Create a new task ID and check its status on a separate thread
+// before and after canceling.  The is-canceled callback should be
+// thread-safe (i.e., nothing should blow up).
+TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  CancelableTaskTracker::TaskId task_id =
+      task_tracker_.NewTrackedTaskId(&is_canceled);
+
+  EXPECT_FALSE(is_canceled.Run());
+
+  Thread other_thread("other thread");
+  ASSERT_TRUE(other_thread.Start());
+  other_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, false));
+  other_thread.Stop();
+
+  task_tracker_.TryCancel(task_id);
+
+  ASSERT_TRUE(other_thread.Start());
+  other_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, true));
+  other_thread.Stop();
+}
+
+// With the task tracker, post a task, a task with a reply, get a new
+// task id, and then cancel all of them.  None of the tasks nor the
+// reply should run and the "is canceled" callback should return
+// true.
+TEST_F(CancelableTaskTrackerTest, CancelAll) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  ignore_result(task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
+
+  ignore_result(
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedNotRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE)));
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+
+  task_tracker_.TryCancelAll();
+
+  test_task_runner->RunUntilIdle();
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_TRUE(is_canceled.Run());
+}
+
+// With the task tracker, post a task, a task with a reply, get a new
+// task id, and then cancel all of them.  None of the tasks nor the
+// reply should run and the "is canceled" callback should return
+// true.
+TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+
+  {
+    // Create another task tracker with a smaller scope.
+    CancelableTaskTracker task_tracker;
+
+    ignore_result(task_tracker.PostTask(test_task_runner.get(),
+                                        FROM_HERE,
+                                        MakeExpectedNotRunClosure(FROM_HERE)));
+
+    ignore_result(
+        task_tracker.PostTaskAndReply(test_task_runner.get(),
+                                      FROM_HERE,
+                                      MakeExpectedNotRunClosure(FROM_HERE),
+                                      MakeExpectedNotRunClosure(FROM_HERE)));
+
+    ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+  }
+
+  test_task_runner->RunUntilIdle();
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(is_canceled.Run());
+}
+
+// Post a task and cancel it.  HasTrackedTasks() should return true
+// from when the task is posted until the (do-nothing) reply task is
+// flushed.
+TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPost) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+
+  ignore_result(task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
+
+  task_tracker_.TryCancelAll();
+
+  test_task_runner->RunUntilIdle();
+
+  EXPECT_TRUE(task_tracker_.HasTrackedTasks());
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+}
+
+// Post a task with a reply and cancel it.  HasTrackedTasks() should
+// return true from when the task is posted until it is canceled.
+TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostWithReply) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+
+  ignore_result(
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedNotRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE)));
+
+  task_tracker_.TryCancelAll();
+
+  test_task_runner->RunUntilIdle();
+
+  EXPECT_TRUE(task_tracker_.HasTrackedTasks());
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+}
+
+// Create a new tracked task ID.  HasTrackedTasks() should return true
+// until the IsCanceledCallback is destroyed.
+TEST_F(CancelableTaskTrackerTest, HasTrackedTasksIsCancelled) {
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+
+  task_tracker_.TryCancelAll();
+
+  EXPECT_TRUE(task_tracker_.HasTrackedTasks());
+
+  is_canceled.Reset();
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+}
+
+// The death tests below make sure that calling task tracker member
+// functions from a thread different from its owner thread DCHECKs in
+// debug mode.
+
+class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
+ protected:
+  CancelableTaskTrackerDeathTest() {
+    // The default style "fast" does not support multi-threaded tests.
+    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  }
+};
+
+// Duplicated from base/threading/thread_checker.h so that we can be
+// good citizens there and undef the macro.
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+// Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
+void MaybeRunDeadlyTaskTrackerMemberFunction(
+    CancelableTaskTracker* task_tracker,
+    const Callback<void(CancelableTaskTracker*)>& fn) {
+// CancelableTask uses DCHECKs with its ThreadChecker (itself only
+// enabled in debug mode).
+#if ENABLE_THREAD_CHECKER
+  EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
+#endif
+}
+
+void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
+  ignore_result(task_tracker->PostTask(
+      scoped_refptr<TestSimpleTaskRunner>(new TestSimpleTaskRunner()).get(),
+      FROM_HERE,
+      Bind(&DoNothing)));
+}
+
+TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
+  Thread bad_thread("bad thread");
+  ASSERT_TRUE(bad_thread.Start());
+
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+                      Unretained(&task_tracker_), Bind(&PostDoNothingTask)));
+}
+
+void TryCancel(CancelableTaskTracker::TaskId task_id,
+               CancelableTaskTracker* task_tracker) {
+  task_tracker->TryCancel(task_id);
+}
+
+TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  Thread bad_thread("bad thread");
+  ASSERT_TRUE(bad_thread.Start());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+                      Unretained(&task_tracker_), Bind(&TryCancel, task_id)));
+
+  test_task_runner->RunUntilIdle();
+}
+
+TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  Thread bad_thread("bad thread");
+  ASSERT_TRUE(bad_thread.Start());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_),
+           Bind(&CancelableTaskTracker::TryCancelAll)));
+
+  test_task_runner->RunUntilIdle();
+}
+
+}  // namespace base
diff --git a/base/task_runner.cc b/base/task_runner.cc
new file mode 100644
index 0000000..262e1f8
--- /dev/null
+++ b/base/task_runner.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task_runner.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/threading/post_task_and_reply_impl.h"
+
+namespace base {
+
+namespace {
+
+// TODO(akalin): There's only one other implementation of
+// PostTaskAndReplyImpl in WorkerPool.  Investigate whether it'll be
+// possible to merge the two.
+class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl {
+ public:
+  explicit PostTaskAndReplyTaskRunner(TaskRunner* destination);
+
+ private:
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task) override;
+
+  // Non-owning.
+  TaskRunner* destination_;
+};
+
+PostTaskAndReplyTaskRunner::PostTaskAndReplyTaskRunner(
+    TaskRunner* destination) : destination_(destination) {
+  DCHECK(destination_);
+}
+
+bool PostTaskAndReplyTaskRunner::PostTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return destination_->PostTask(from_here, task);
+}
+
+}  // namespace
+
+bool TaskRunner::PostTask(const tracked_objects::Location& from_here,
+                          const Closure& task) {
+  return PostDelayedTask(from_here, task, base::TimeDelta());
+}
+
+bool TaskRunner::PostTaskAndReply(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  return PostTaskAndReplyTaskRunner(this).PostTaskAndReply(
+      from_here, task, reply);
+}
+
+TaskRunner::TaskRunner() {}
+
+TaskRunner::~TaskRunner() {}
+
+void TaskRunner::OnDestruct() const {
+  delete this;
+}
+
+void TaskRunnerTraits::Destruct(const TaskRunner* task_runner) {
+  task_runner->OnDestruct();
+}
+
+}  // namespace base
diff --git a/base/task_runner.h b/base/task_runner.h
new file mode 100644
index 0000000..7d07b8c
--- /dev/null
+++ b/base/task_runner.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_RUNNER_H_
+#define BASE_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+
+namespace tracked_objects {
+class Location;
+} // namespace tracked_objects
+
+namespace base {
+
+struct TaskRunnerTraits;
+
+// A TaskRunner is an object that runs posted tasks (in the form of
+// Closure objects).  The TaskRunner interface provides a way of
+// decoupling task posting from the mechanics of how each task will be
+// run.  TaskRunner provides very weak guarantees as to how posted
+// tasks are run (or if they're run at all).  In particular, it only
+// guarantees:
+//
+//   - Posting a task will not run it synchronously.  That is, no
+//     Post*Task method will call task.Run() directly.
+//
+//   - Increasing the delay can only delay when the task gets run.
+//     That is, increasing the delay may not affect when the task gets
+//     run, or it could make it run later than it normally would, but
+//     it won't make it run earlier than it normally would.
+//
+// TaskRunner does not guarantee the order in which posted tasks are
+// run, whether tasks overlap, or whether they're run on a particular
+// thread.  Also it does not guarantee a memory model for shared data
+// between tasks.  (In other words, you should use your own
+// synchronization/locking primitives if you need to share data
+// between tasks.)
+//
+// Implementations of TaskRunner should be thread-safe in that all
+// methods must be safe to call on any thread.  Ownership semantics
+// for TaskRunners are in general not clear, which is why the
+// interface itself is RefCountedThreadSafe.
+//
+// Some theoretical implementations of TaskRunner:
+//
+//   - A TaskRunner that uses a thread pool to run posted tasks.
+//
+//   - A TaskRunner that, for each task, spawns a non-joinable thread
+//     to run that task and immediately quit.
+//
+//   - A TaskRunner that stores the list of posted tasks and has a
+//     method Run() that runs each runnable task in random order.
+class BASE_EXPORT TaskRunner
+    : public RefCountedThreadSafe<TaskRunner, TaskRunnerTraits> {
+ public:
+  // Posts the given task to be run.  Returns true if the task may be
+  // run at some point in the future, and false if the task definitely
+  // will not be run.
+  //
+  // Equivalent to PostDelayedTask(from_here, task, 0).
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  // Like PostTask, but tries to run the posted task only after
+  // |delay_ms| has passed.
+  //
+  // It is valid for an implementation to ignore |delay_ms|; that is,
+  // to have PostDelayedTask behave the same as PostTask.
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               base::TimeDelta delay) = 0;
+
+  // Returns true if the current thread is a thread on which a task
+  // may be run, and false if no task will be run on the current
+  // thread.
+  //
+  // It is valid for an implementation to always return true, or in
+  // general to use 'true' as a default value.
+  virtual bool RunsTasksOnCurrentThread() const = 0;
+
+  // Posts |task| on the current TaskRunner.  On completion, |reply|
+  // is posted to the thread that called PostTaskAndReply().  Both
+  // |task| and |reply| are guaranteed to be deleted on the thread
+  // from which PostTaskAndReply() is invoked.  This allows objects
+  // that must be deleted on the originating thread to be bound into
+  // the |task| and |reply| Closures.  In particular, it can be useful
+  // to use WeakPtr<> in the |reply| Closure so that the reply
+  // operation can be canceled. See the following pseudo-code:
+  //
+  // class DataBuffer : public RefCountedThreadSafe<DataBuffer> {
+  //  public:
+  //   // Called to add data into a buffer.
+  //   void AddData(void* buf, size_t length);
+  //   ...
+  // };
+  //
+  //
+  // class DataLoader : public SupportsWeakPtr<DataLoader> {
+  //  public:
+  //    void GetData() {
+  //      scoped_refptr<DataBuffer> buffer = new DataBuffer();
+  //      target_thread_.message_loop_proxy()->PostTaskAndReply(
+  //          FROM_HERE,
+  //          base::Bind(&DataBuffer::AddData, buffer),
+  //          base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
+  //    }
+  //
+  //  private:
+  //    void OnDataReceived(scoped_refptr<DataBuffer> buffer) {
+  //      // Do something with buffer.
+  //    }
+  // };
+  //
+  //
+  // Things to notice:
+  //   * Results of |task| are shared with |reply| by binding a shared argument
+  //     (a DataBuffer instance).
+  //   * The DataLoader object has no special thread safety.
+  //   * The DataLoader object can be deleted while |task| is still running,
+  //     and the reply will cancel itself safely because it is bound to a
+  //     WeakPtr<>.
+  bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply);
+
+ protected:
+  friend struct TaskRunnerTraits;
+
+  // Only the Windows debug build seems to need this: see
+  // http://crbug.com/112250.
+  friend class RefCountedThreadSafe<TaskRunner, TaskRunnerTraits>;
+
+  TaskRunner();
+  virtual ~TaskRunner();
+
+  // Called when this object should be destroyed.  By default simply
+  // deletes |this|, but can be overridden to do something else, like
+  // delete on a certain thread.
+  virtual void OnDestruct() const;
+};
+
+struct BASE_EXPORT TaskRunnerTraits {
+  static void Destruct(const TaskRunner* task_runner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_H_
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
new file mode 100644
index 0000000..b6dd0f3
--- /dev/null
+++ b/base/task_runner_util.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_RUNNER_UTIL_H_
+#define BASE_TASK_RUNNER_UTIL_H_
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/logging.h"
+#include "base/task_runner.h"
+
+namespace base {
+
+namespace internal {
+
+// Adapts a function that produces a result via a return value to
+// one that returns via an output parameter.
+template <typename ReturnType>
+void ReturnAsParamAdapter(const Callback<ReturnType(void)>& func,
+                          ReturnType* result) {
+  *result = func.Run();
+}
+
+// Adapts a T* result to a callblack that expects a T.
+template <typename TaskReturnType, typename ReplyArgType>
+void ReplyAdapter(const Callback<void(ReplyArgType)>& callback,
+                  TaskReturnType* result) {
+  // TODO(ajwong): Remove this conditional and add a DCHECK to enforce that
+  // |reply| must be non-null in PostTaskAndReplyWithResult() below after
+  // current code that relies on this API softness has been removed.
+  // http://crbug.com/162712
+  if (!callback.is_null())
+    callback.Run(CallbackForward(*result));
+}
+
+}  // namespace internal
+
+// When you have these methods
+//
+//   R DoWorkAndReturn();
+//   void Callback(const R& result);
+//
+// and want to call them in a PostTaskAndReply kind of fashion where the
+// result of DoWorkAndReturn is passed to the Callback, you can use
+// PostTaskAndReplyWithResult as in this example:
+//
+// PostTaskAndReplyWithResult(
+//     target_thread_.message_loop_proxy(),
+//     FROM_HERE,
+//     Bind(&DoWorkAndReturn),
+//     Bind(&Callback));
+template <typename TaskReturnType, typename ReplyArgType>
+bool PostTaskAndReplyWithResult(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Callback<TaskReturnType(void)>& task,
+    const Callback<void(ReplyArgType)>& reply) {
+  TaskReturnType* result = new TaskReturnType();
+  return task_runner->PostTaskAndReply(
+      from_here,
+      base::Bind(&internal::ReturnAsParamAdapter<TaskReturnType>, task,
+                 result),
+      base::Bind(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, reply,
+                 base::Owned(result)));
+}
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_UTIL_H_
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
new file mode 100644
index 0000000..8245cfc
--- /dev/null
+++ b/base/task_runner_util_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/task_runner_util.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+int ReturnFourtyTwo() {
+  return 42;
+}
+
+void StoreValue(int* destination, int value) {
+  *destination = value;
+}
+
+void StoreDoubleValue(double* destination, double value) {
+  *destination = value;
+}
+
+int g_foo_destruct_count = 0;
+int g_foo_free_count = 0;
+
+struct Foo {
+  ~Foo() {
+    ++g_foo_destruct_count;
+  }
+};
+
+scoped_ptr<Foo> CreateFoo() {
+  return scoped_ptr<Foo>(new Foo);
+}
+
+void ExpectFoo(scoped_ptr<Foo> foo) {
+  EXPECT_TRUE(foo.get());
+  scoped_ptr<Foo> local_foo(foo.Pass());
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+struct FooDeleter {
+  void operator()(Foo* foo) const {
+    ++g_foo_free_count;
+    delete foo;
+  };
+};
+
+scoped_ptr<Foo, FooDeleter> CreateScopedFoo() {
+  return scoped_ptr<Foo, FooDeleter>(new Foo);
+}
+
+void ExpectScopedFoo(scoped_ptr<Foo, FooDeleter> foo) {
+  EXPECT_TRUE(foo.get());
+  scoped_ptr<Foo, FooDeleter> local_foo(foo.Pass());
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+}  // namespace
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
+  int result = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&ReturnFourtyTwo),
+                             Bind(&StoreValue, &result));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(42, result);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultImplicitConvert) {
+  double result = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&ReturnFourtyTwo),
+                             Bind(&StoreDoubleValue, &result));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_DOUBLE_EQ(42.0, result);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) {
+  g_foo_destruct_count = 0;
+  g_foo_free_count = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&CreateFoo), Bind(&ExpectFoo));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, g_foo_destruct_count);
+  EXPECT_EQ(0, g_foo_free_count);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassedFreeProc) {
+  g_foo_destruct_count = 0;
+  g_foo_free_count = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, g_foo_destruct_count);
+  EXPECT_EQ(1, g_foo_free_count);
+}
+
+}  // namespace base
diff --git a/base/template_util.h b/base/template_util.h
new file mode 100644
index 0000000..83fa322
--- /dev/null
+++ b/base/template_util.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEMPLATE_UTIL_H_
+#define BASE_TEMPLATE_UTIL_H_
+
+#include <cstddef>  // For size_t.
+
+#include "build/build_config.h"
+
+namespace base {
+
+// template definitions from tr1
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class T> struct is_pointer : false_type {};
+template <class T> struct is_pointer<T*> : true_type {};
+
+// Member function pointer detection. This is built-in to C++ 11's stdlib, and
+// we can remove this when we switch to it.
+template<typename T>
+struct is_member_function_pointer : false_type {};
+
+template <typename R, typename Z, typename... A>
+struct is_member_function_pointer<R(Z::*)(A...)> : true_type {};
+template <typename R, typename Z, typename... A>
+struct is_member_function_pointer<R(Z::*)(A...) const> : true_type {};
+
+
+template <class T, class U> struct is_same : public false_type {};
+template <class T> struct is_same<T,T> : true_type {};
+
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
+template <class T> struct is_const : false_type {};
+template <class T> struct is_const<const T> : true_type {};
+
+template <class T> struct is_void : false_type {};
+template <> struct is_void<void> : true_type {};
+
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+  YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+  template <typename To>
+  static YesType Test(To);
+
+  template <typename To>
+  static NoType Test(...);
+
+  template <typename From>
+  static From& Create();
+};
+
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+  template <typename C>
+  static YesType Test(void(C::*)(void));
+
+  template <typename C>
+  static NoType Test(...);
+};
+
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper::Test<To>(
+                                   internal::ConvertHelper::Create<From>())) ==
+                        sizeof(internal::YesType)> {
+};
+
+template <typename T>
+struct is_class
+    : integral_constant<bool,
+                        sizeof(internal::IsClassHelper::Test<T>(0)) ==
+                            sizeof(internal::YesType)> {
+};
+
+template<bool B, class T = void>
+struct enable_if {};
+
+template<class T>
+struct enable_if<true, T> { typedef T type; };
+
+}  // namespace base
+
+#endif  // BASE_TEMPLATE_UTIL_H_
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
new file mode 100644
index 0000000..3ec3887
--- /dev/null
+++ b/base/template_util_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/template_util.h"
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct AStruct {};
+class AClass {};
+enum AnEnum {};
+
+class Parent {};
+class Child : public Parent {};
+
+// is_pointer<Type>
+COMPILE_ASSERT(!is_pointer<int>::value, IsPointer);
+COMPILE_ASSERT(!is_pointer<int&>::value, IsPointer);
+COMPILE_ASSERT(is_pointer<int*>::value, IsPointer);
+COMPILE_ASSERT(is_pointer<const int*>::value, IsPointer);
+
+// is_array<Type>
+COMPILE_ASSERT(!is_array<int>::value, IsArray);
+COMPILE_ASSERT(!is_array<int*>::value, IsArray);
+COMPILE_ASSERT(!is_array<int(*)[3]>::value, IsArray);
+COMPILE_ASSERT(is_array<int[]>::value, IsArray);
+COMPILE_ASSERT(is_array<const int[]>::value, IsArray);
+COMPILE_ASSERT(is_array<int[3]>::value, IsArray);
+
+// is_non_const_reference<Type>
+COMPILE_ASSERT(!is_non_const_reference<int>::value, IsNonConstReference);
+COMPILE_ASSERT(!is_non_const_reference<const int&>::value, IsNonConstReference);
+COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
+
+// is_convertible<From, To>
+
+// Extra parens needed to make preprocessor macro parsing happy. Otherwise,
+// it sees the equivalent of:
+//
+//     (is_convertible < Child), (Parent > ::value)
+//
+// Silly C++.
+COMPILE_ASSERT( (is_convertible<Child, Parent>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<Parent, Child>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<Parent, AStruct>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int, double>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int*, void*>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<void*, int*>::value), IsConvertible);
+
+// Array types are an easy corner case.  Make sure to test that
+// it does indeed compile.
+COMPILE_ASSERT(!(is_convertible<int[10], double>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<double, int[10]>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int[10], int*>::value), IsConvertible);
+
+// is_same<Type1, Type2>
+COMPILE_ASSERT(!(is_same<Child, Parent>::value), IsSame);
+COMPILE_ASSERT(!(is_same<Parent, Child>::value), IsSame);
+COMPILE_ASSERT( (is_same<Parent, Parent>::value), IsSame);
+COMPILE_ASSERT( (is_same<int*, int*>::value), IsSame);
+COMPILE_ASSERT( (is_same<int, int>::value), IsSame);
+COMPILE_ASSERT( (is_same<void, void>::value), IsSame);
+COMPILE_ASSERT(!(is_same<int, double>::value), IsSame);
+
+
+// is_class<Type>
+COMPILE_ASSERT(is_class<AStruct>::value, IsClass);
+COMPILE_ASSERT(is_class<AClass>::value, IsClass);
+COMPILE_ASSERT(!is_class<AnEnum>::value, IsClass);
+COMPILE_ASSERT(!is_class<int>::value, IsClass);
+COMPILE_ASSERT(!is_class<char*>::value, IsClass);
+COMPILE_ASSERT(!is_class<int&>::value, IsClass);
+COMPILE_ASSERT(!is_class<char[3]>::value, IsClass);
+
+
+COMPILE_ASSERT(!is_member_function_pointer<int>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<int*>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<void*>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<AStruct>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<AStruct*>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<void(*)()>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<int(*)(int)>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<int(*)(int, int)>::value,
+               IsMemberFunctionPointer);
+
+COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)()>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)(int)>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int)>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int) const>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
+               IsMemberFunctionPointer);
+
+}  // namespace
+}  // namespace base
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
new file mode 100644
index 0000000..91456db
--- /dev/null
+++ b/base/test/BUILD.gn
@@ -0,0 +1,209 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+source_set("test_config") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "test_switches.cc",
+    "test_switches.h",
+    "test_timeouts.cc",
+    "test_timeouts.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+# GYP: //base/base.gyp:test_support_base
+source_set("test_support") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "expectations/expectation.cc",
+    "expectations/expectation.h",
+    "expectations/parser.cc",
+    "expectations/parser.h",
+    "gtest_util.cc",
+    "gtest_util.h",
+    "gtest_xml_util.cc",
+    "gtest_xml_util.h",
+    "histogram_tester.cc",
+    "histogram_tester.h",
+    "launcher/test_launcher.cc",
+    "launcher/test_launcher.h",
+    "launcher/test_result.cc",
+    "launcher/test_result.h",
+    "launcher/test_results_tracker.cc",
+    "launcher/test_results_tracker.h",
+    "launcher/unit_test_launcher.cc",
+    "launcher/unit_test_launcher.h",
+    "launcher/unit_test_launcher_ios.cc",
+    "mock_chrome_application_mac.h",
+    "mock_chrome_application_mac.mm",
+    "mock_devices_changed_observer.cc",
+    "mock_devices_changed_observer.h",
+    "mock_entropy_provider.cc",
+    "mock_entropy_provider.h",
+    "mock_log.cc",
+    "mock_log.h",
+    "multiprocess_test.cc",
+    "multiprocess_test.h",
+    "multiprocess_test_android.cc",
+    "null_task_runner.cc",
+    "null_task_runner.h",
+    "opaque_ref_counted.cc",
+    "opaque_ref_counted.h",
+    "perf_log.cc",
+    "perf_log.h",
+    "perf_test_suite.cc",
+    "perf_test_suite.h",
+    "perf_time_logger.cc",
+    "perf_time_logger.h",
+    "power_monitor_test_base.cc",
+    "power_monitor_test_base.h",
+    "scoped_locale.cc",
+    "scoped_locale.h",
+    "scoped_path_override.cc",
+    "scoped_path_override.h",
+    "sequenced_task_runner_test_template.cc",
+    "sequenced_task_runner_test_template.h",
+    "sequenced_worker_pool_owner.cc",
+    "sequenced_worker_pool_owner.h",
+    "simple_test_clock.cc",
+    "simple_test_clock.h",
+    "simple_test_tick_clock.cc",
+    "simple_test_tick_clock.h",
+    "task_runner_test_template.cc",
+    "task_runner_test_template.h",
+    "test_discardable_memory_allocator.cc",
+    "test_discardable_memory_allocator.h",
+    "test_file_util.cc",
+    "test_file_util.h",
+    "test_file_util_android.cc",
+    "test_file_util_linux.cc",
+    "test_file_util_mac.cc",
+    "test_file_util_posix.cc",
+    "test_file_util_win.cc",
+    "test_io_thread.cc",
+    "test_io_thread.h",
+    "test_listener_ios.h",
+    "test_listener_ios.mm",
+    "test_mock_time_task_runner.cc",
+    "test_mock_time_task_runner.h",
+    "test_pending_task.cc",
+    "test_pending_task.h",
+    "test_reg_util_win.cc",
+    "test_reg_util_win.h",
+    "test_shortcut_win.cc",
+    "test_shortcut_win.h",
+    "test_simple_task_runner.cc",
+    "test_simple_task_runner.h",
+    "test_suite.cc",
+    "test_suite.h",
+    "test_support_android.cc",
+    "test_support_android.h",
+    "test_support_ios.h",
+    "test_support_ios.mm",
+    "thread_test_helper.cc",
+    "thread_test_helper.h",
+    "trace_event_analyzer.cc",
+    "trace_event_analyzer.h",
+    "trace_to_file.cc",
+    "trace_to_file.h",
+    "user_action_tester.cc",
+    "user_action_tester.h",
+    "values_test_util.cc",
+    "values_test_util.h",
+  ]
+
+  public_deps = [
+    ":test_config",
+    "//base",
+    "//base:i18n",
+    "//base:base_static",
+  ]
+  deps = [
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/libxml",
+    "//third_party/icu:icuuc",
+  ]
+
+  if (!is_posix) {
+    sources -= [
+      "scoped_locale.cc",
+      "scoped_locale.h",
+    ]
+  }
+  if (is_ios) {
+    # iOS uses its own unit test launcher.
+    sources -= [ "launcher/unit_test_launcher.cc" ]
+
+    # Pull in specific Mac files for iOS (which have been filtered out
+    # by file name rules).
+    set_sources_assignment_filter([])
+    sources += [ "test_file_util_mac.cc" ]
+  }
+
+  if (is_android) {
+    deps += [ ":base_unittests_jni_headers" ]
+  }
+}
+
+config("perf_test_config") {
+  defines = [ "PERF_TEST" ]
+}
+
+source_set("test_support_perf") {
+  testonly = true
+  sources = [
+    "run_all_perftests.cc",
+  ]
+  deps = [
+    ":test_support",
+    "//base",
+    "//testing/gtest",
+  ]
+
+  public_configs = [ ":perf_test_config" ]
+}
+
+source_set("run_all_unittests") {
+  testonly = true
+  sources = [
+    "run_all_unittests.cc",
+  ]
+  deps = [
+    ":test_support",
+  ]
+}
+
+if (is_linux) {
+  shared_library("malloc_wrapper") {
+    testonly = true
+    sources = [
+      "malloc_wrapper.cc",
+    ]
+    deps = [
+      "//base",
+    ]
+  }
+}
+
+if (is_android) {
+  generate_jni("base_unittests_jni_headers") {
+    sources = [
+      "android/java/src/org/chromium/base/ContentUriTestUtils.java",
+    ]
+    jni_package = "base"
+  }
+}
diff --git a/base/test/DEPS b/base/test/DEPS
new file mode 100644
index 0000000..5827c26
--- /dev/null
+++ b/base/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/libxml",
+]
diff --git a/base/test/OWNERS b/base/test/OWNERS
new file mode 100644
index 0000000..92ecc88
--- /dev/null
+++ b/base/test/OWNERS
@@ -0,0 +1 @@
+phajdan.jr@chromium.org
diff --git a/base/test/android/OWNERS b/base/test/android/OWNERS
new file mode 100644
index 0000000..3c9067c
--- /dev/null
+++ b/base/test/android/OWNERS
@@ -0,0 +1,3 @@
+feng@chromium.org
+nyquist@chromium.org
+yfriedman@chromium.org
diff --git a/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
new file mode 100644
index 0000000..4a1613b
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.MediaStore;
+
+/**
+ * Utilities for testing operations on content URI.
+ */
+public class ContentUriTestUtils {
+    /**
+     * Insert an image into the MediaStore, and return the content URI. If the
+     * image already exists in the MediaStore, just retrieve the URI.
+     *
+     * @param context Application context.
+     * @param path Path to the image file.
+     * @return Content URI of the image.
+     */
+    @CalledByNative
+    private static String insertImageIntoMediaStore(Context context, String path) {
+        // Check whether the content URI exists.
+        Cursor c = context.getContentResolver().query(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                new String[] { MediaStore.Video.VideoColumns._ID },
+                MediaStore.Images.Media.DATA + " LIKE ?",
+                new String[] { path },
+                null);
+        if (c != null && c.getCount() > 0) {
+            c.moveToFirst();
+            int id = c.getInt(0);
+            return Uri.withAppendedPath(
+                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + id).toString();
+        }
+
+        // Insert the content URI into MediaStore.
+        ContentValues values = new ContentValues();
+        values.put(MediaStore.MediaColumns.DATA, path);
+        Uri uri = context.getContentResolver().insert(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+        return uri.toString();
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
new file mode 100644
index 0000000..53dee4a
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
@@ -0,0 +1,118 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.CommandLine;
+import org.chromium.base.test.util.CommandLineFlags;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Base class for all Activity-based Instrumentation tests.
+ *
+ * @param <T> The Activity type.
+ */
+public class BaseActivityInstrumentationTestCase<T extends Activity>
+        extends ActivityInstrumentationTestCase2<T> {
+
+    private static final String TAG = "BaseActivityInstrumentationTestCase";
+
+    private static final int SLEEP_INTERVAL = 50; // milliseconds
+    private static final int WAIT_DURATION = 5000; // milliseconds
+
+    /**
+     * Creates a instance for running tests against an Activity of the given class.
+     *
+     * @param activityClass The type of activity that will be tested.
+     */
+    public BaseActivityInstrumentationTestCase(Class<T> activityClass) {
+        super(activityClass);
+    }
+
+    /**
+     * Sets up the CommandLine with the appropriate flags.
+     *
+     * This will add the difference of the sets of flags specified by {@link CommandLineFlags.Add}
+     * and {@link CommandLineFlags.Remove} to the {@link org.chromium.base.CommandLine}. Note that
+     * trying to remove a flag set externally, i.e. by the command-line flags file, will not work.
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        CommandLine.reset();
+        Context targetContext = getTargetContext();
+        assertNotNull("Unable to get a non-null target context.", targetContext);
+
+        BaseChromiumApplication.initCommandLine(targetContext);
+        Set<String> flags = getFlags(getClass().getMethod(getName()));
+        for (String flag : flags) {
+            CommandLine.getInstance().appendSwitch(flag);
+        }
+    }
+
+    /**
+     * Gets the target context.
+     *
+     * On older versions of Android, getTargetContext() may initially return null, so we have to
+     * wait for it to become available.
+     *
+     * @return The target {@link android.content.Context} if available; null otherwise.
+     */
+    private Context getTargetContext() {
+        Context targetContext = getInstrumentation().getTargetContext();
+        try {
+            long startTime = SystemClock.uptimeMillis();
+            // TODO(jbudorick): Convert this to CriteriaHelper once that moves to base/.
+            while (targetContext == null
+                    && SystemClock.uptimeMillis() - startTime < WAIT_DURATION) {
+                Thread.sleep(SLEEP_INTERVAL);
+                targetContext = getInstrumentation().getTargetContext();
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while attempting to initialize the command line.");
+        }
+        return targetContext;
+    }
+
+    private static Set<String> getFlags(AnnotatedElement element) {
+        AnnotatedElement parent = (element instanceof Method)
+                ? ((Method) element).getDeclaringClass()
+                : ((Class) element).getSuperclass();
+        Set<String> flags = (parent == null) ? new HashSet<String>() : getFlags(parent);
+
+        if (element.isAnnotationPresent(CommandLineFlags.Add.class)) {
+            flags.addAll(
+                    Arrays.asList(element.getAnnotation(CommandLineFlags.Add.class).value()));
+        }
+
+        if (element.isAnnotationPresent(CommandLineFlags.Remove.class)) {
+            List<String> flagsToRemove =
+                    Arrays.asList(element.getAnnotation(CommandLineFlags.Remove.class).value());
+            for (String flagToRemove : flagsToRemove) {
+                // If your test fails here, you have tried to remove a command-line flag via
+                // CommandLineFlags.Remove that was loaded into CommandLine via something other
+                // than CommandLineFlags.Add (probably the command-line flag file).
+                assertFalse("Unable to remove command-line flag \"" + flagToRemove + "\".",
+                        CommandLine.getInstance().hasSwitch(flagToRemove));
+            }
+            flags.removeAll(flagsToRemove);
+        }
+
+        return flags;
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
new file mode 100644
index 0000000..8a3395a
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -0,0 +1,133 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test;
+
+import android.os.Build;
+import android.os.Bundle;
+import android.test.AndroidTestRunner;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.test.reporter.TestStatusListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+// TODO(jbudorick): Add support for on-device handling of timeouts.
+/**
+ *  An Instrumentation test runner that checks SDK level for tests with specific requirements.
+ */
+public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
+
+    private static final String TAG = "BaseInstrumentationTestRunner";
+
+    /**
+     * An interface for classes that check whether a test case should be skipped.
+     */
+    public interface SkipCheck {
+        /**
+         * Checks whether the given test case should be skipped.
+         *
+         * @param testCase The test case to check.
+         * @return Whether the test case should be skipped.
+         */
+        public boolean shouldSkip(TestCase testCase);
+    }
+
+    /**
+     * A test result that can skip tests.
+     */
+    public class SkippingTestResult extends TestResult {
+
+        private final List<SkipCheck> mSkipChecks;
+
+        /**
+         * Creates an instance of SkippingTestResult.
+         */
+        public SkippingTestResult() {
+            mSkipChecks = new ArrayList<SkipCheck>();
+        }
+
+        /**
+         * Adds a check for whether a test should run.
+         *
+         * @param skipCheck The check to add.
+         */
+        public void addSkipCheck(SkipCheck skipCheck) {
+            mSkipChecks.add(skipCheck);
+        }
+
+        private boolean shouldSkip(final TestCase test) {
+            for (SkipCheck s : mSkipChecks) {
+                if (s.shouldSkip(test)) return true;
+            }
+            return false;
+        }
+
+        @Override
+        protected void run(final TestCase test) {
+            if (shouldSkip(test)) {
+                startTest(test);
+
+                Bundle skipResult = new Bundle();
+                skipResult.putString("class", test.getClass().getName());
+                skipResult.putString("test", test.getName());
+                skipResult.putBoolean("test_skipped", true);
+                sendStatus(0, skipResult);
+
+                endTest(test);
+            } else {
+                super.run(test);
+            }
+        }
+    }
+
+    @Override
+    protected AndroidTestRunner getAndroidTestRunner() {
+        AndroidTestRunner runner = new AndroidTestRunner() {
+            @Override
+            protected TestResult createTestResult() {
+                SkippingTestResult r = new SkippingTestResult();
+                r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+                return r;
+            }
+        };
+        runner.addTestListener(new TestStatusListener(getContext()));
+        return runner;
+    }
+
+    /**
+     * Checks the device's SDK level against any specified minimum requirement.
+     */
+    public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
+
+        /**
+         * If {@link org.chromium.base.test.util.MinAndroidSdkLevel} is present, checks its value
+         * against the device's SDK level.
+         *
+         * @param testCase The test to check.
+         * @return true if the device's SDK level is below the specified minimum.
+         */
+        @Override
+        public boolean shouldSkip(TestCase testCase) {
+            Class<?> testClass = testCase.getClass();
+            if (testClass.isAnnotationPresent(MinAndroidSdkLevel.class)) {
+                MinAndroidSdkLevel v = testClass.getAnnotation(MinAndroidSdkLevel.class);
+                if (Build.VERSION.SDK_INT < v.value()) {
+                    Log.i(TAG, "Test " + testClass.getName() + "#" + testCase.getName()
+                            + " is not enabled at SDK level " + Build.VERSION.SDK_INT
+                            + ".");
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
new file mode 100644
index 0000000..c8117f7
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
@@ -0,0 +1,118 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.content.ComponentCallbacks;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ContextWrapper that adds functionality for SharedPreferences and a way to set and retrieve flags.
+ */
+public class AdvancedMockContext extends ContextWrapper {
+
+    private final MockContentResolver mMockContentResolver = new MockContentResolver();
+
+    private final Map<String, SharedPreferences> mSharedPreferences =
+            new HashMap<String, SharedPreferences>();
+
+    private final Map<String, Boolean> mFlags = new HashMap<String, Boolean>();
+
+    public AdvancedMockContext(Context base) {
+        super(base);
+    }
+
+    public AdvancedMockContext() {
+        super(new MockContext());
+    }
+
+    @Override
+    public String getPackageName() {
+        return getBaseContext().getPackageName();
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        return this;
+    }
+
+    @Override
+    public ContentResolver getContentResolver() {
+        return mMockContentResolver;
+    }
+
+    public MockContentResolver getMockContentResolver() {
+        return mMockContentResolver;
+    }
+
+    @Override
+    public SharedPreferences getSharedPreferences(String name, int mode) {
+        synchronized (mSharedPreferences) {
+            if (!mSharedPreferences.containsKey(name)) {
+                // Auto-create shared preferences to mimic Android Context behavior
+                mSharedPreferences.put(name, new InMemorySharedPreferences());
+            }
+            return mSharedPreferences.get(name);
+        }
+    }
+
+    @Override
+    public void registerComponentCallbacks(ComponentCallbacks callback) {
+        getBaseContext().registerComponentCallbacks(callback);
+    }
+
+    @Override
+    public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+        getBaseContext().unregisterComponentCallbacks(callback);
+    }
+
+    public void addSharedPreferences(String name, Map<String, Object> data) {
+        synchronized (mSharedPreferences) {
+            mSharedPreferences.put(name, new InMemorySharedPreferences(data));
+        }
+    }
+
+    public void setFlag(String key) {
+        mFlags.put(key, true);
+    }
+
+    public void clearFlag(String key) {
+        mFlags.remove(key);
+    }
+
+    public boolean isFlagSet(String key) {
+        return mFlags.containsKey(key) && mFlags.get(key);
+    }
+
+    /**
+     * Builder for maps of type Map<String, Object> to be used with
+     * {@link #addSharedPreferences(String, java.util.Map)}.
+     */
+    public static class MapBuilder {
+
+        private final Map<String, Object> mData = new HashMap<String, Object>();
+
+        public static MapBuilder create() {
+            return new MapBuilder();
+        }
+
+        public MapBuilder add(String key, Object value) {
+            mData.put(key, value);
+            return this;
+        }
+
+        public Map<String, Object> build() {
+            return mData;
+        }
+
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
new file mode 100644
index 0000000..2feb83d
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Provides annotations related to command-line flag handling.
+ *
+ * Uses of these annotations on a derived class will take precedence over uses on its base classes,
+ * so a derived class can add a command-line flag that a base class has removed (or vice versa).
+ * Similarly, uses of these annotations on a test method will take precedence over uses on the
+ * containing class.
+ *
+ * Note that this class should never be instantiated.
+ */
+public final class CommandLineFlags {
+
+    /**
+     * Adds command-line flags to the {@link org.chromium.base.CommandLine} for this test.
+     */
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.TYPE})
+    public @interface Add {
+        String[] value();
+    }
+
+    /**
+     * Removes command-line flags from the {@link org.chromium.base.CommandLine} from this test.
+     *
+     * Note that this can only remove flags added via {@link Add} above.
+     */
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.TYPE})
+    public @interface Remove {
+        String[] value();
+    }
+
+    private CommandLineFlags() {}
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
new file mode 100644
index 0000000..0dfb4be
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
@@ -0,0 +1,21 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for disabled tests.
+ * <p>
+ * Tests with this annotation will not be run on any of the normal bots.
+ * Please note that they might eventually run on a special bot.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DisabledTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
new file mode 100644
index 0000000..af483ec
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
@@ -0,0 +1,24 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for enormous tests.
+ * <p>
+ * Examples of enormous tests are tests that depend on external web sites or
+ * tests that are long running.
+ * <p>
+ * Such tests are likely NOT reliable enough to run on tree closing bots and
+ * should only be run on FYI bots.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnormousTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
new file mode 100644
index 0000000..1bc9226
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
@@ -0,0 +1,29 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The java instrumentation tests are normally fairly large (in terms of
+ * dependencies), and the test suite ends up containing a large amount of
+ * tests that are not trivial to filter / group just by their names.
+ * Instead, we use this annotation: each test should be annotated as:
+ *     @Feature({"Foo", "Bar"})
+ * in order for the test runner scripts to be able to filter and group
+ * them accordingly (for instance, this enable us to run all tests that exercise
+ * feature Foo).
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Feature {
+    /**
+     * @return A list of feature names.
+     */
+    public String[] value();
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java
new file mode 100644
index 0000000..b52fb2c
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java
@@ -0,0 +1,22 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for host-driven tests.
+ * <p>
+ * Tests with these annotations are run explicitly by HostDrivenTestCase-derived
+ * python tests on the host and are excluded from regular instrumentation test runs.
+ * <p>
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostDrivenTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
new file mode 100644
index 0000000..2587d72
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
@@ -0,0 +1,238 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.content.SharedPreferences;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An implementation of SharedPreferences that can be used in tests.
+ * <p/>
+ * It keeps all state in memory, and there is no difference between apply() and commit().
+ */
+public class InMemorySharedPreferences implements SharedPreferences {
+
+    // Guarded on its own monitor.
+    private final Map<String, Object> mData;
+
+    public InMemorySharedPreferences() {
+        mData = new HashMap<String, Object>();
+    }
+
+    public InMemorySharedPreferences(Map<String, Object> data) {
+        mData = data;
+    }
+
+    @Override
+    public Map<String, ?> getAll() {
+        synchronized (mData) {
+            return Collections.unmodifiableMap(mData);
+        }
+    }
+
+    @Override
+    public String getString(String key, String defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (String) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<String> getStringSet(String key, Set<String> defValues) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return Collections.unmodifiableSet((Set<String>) mData.get(key));
+            }
+        }
+        return defValues;
+    }
+
+    @Override
+    public int getInt(String key, int defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Integer) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public long getLong(String key, long defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Long) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public float getFloat(String key, float defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Float) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public boolean getBoolean(String key, boolean defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Boolean) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public boolean contains(String key) {
+        synchronized (mData) {
+            return mData.containsKey(key);
+        }
+    }
+
+    @Override
+    public SharedPreferences.Editor edit() {
+        return new InMemoryEditor();
+    }
+
+    @Override
+    public void registerOnSharedPreferenceChangeListener(
+            SharedPreferences.OnSharedPreferenceChangeListener
+                    listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterOnSharedPreferenceChangeListener(
+            SharedPreferences.OnSharedPreferenceChangeListener listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    private class InMemoryEditor implements SharedPreferences.Editor {
+
+        // All guarded by |mChanges|
+        private boolean mClearCalled;
+        private volatile boolean mApplyCalled;
+        private final Map<String, Object> mChanges = new HashMap<String, Object>();
+
+        @Override
+        public SharedPreferences.Editor putString(String key, String value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putStringSet(String key, Set<String> values) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, values);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putInt(String key, int value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putLong(String key, long value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putFloat(String key, float value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putBoolean(String key, boolean value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor remove(String key) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                // Magic value for removes
+                mChanges.put(key, this);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor clear() {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mClearCalled = true;
+                return this;
+            }
+        }
+
+        @Override
+        public boolean commit() {
+            apply();
+            return true;
+        }
+
+        @Override
+        public void apply() {
+            synchronized (mData) {
+                synchronized (mChanges) {
+                    if (mApplyCalled) throw new IllegalStateException();
+                    if (mClearCalled) {
+                        mData.clear();
+                    }
+                    for (Map.Entry<String, Object> entry : mChanges.entrySet()) {
+                        String key = entry.getKey();
+                        Object value = entry.getValue();
+                        if (value == this) {
+                            // Special value for removal
+                            mData.remove(key);
+                        } else {
+                            mData.put(key, value);
+                        }
+                    }
+                    // The real shared prefs clears out the temporaries allowing the caller to
+                    // reuse the Editor instance, however this is undocumented behavior and subtle
+                    // to read, so instead we just ban any future use of this instance.
+                    mApplyCalled = true;
+                }
+            }
+        }
+    }
+
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
new file mode 100644
index 0000000..20cfd9d
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
@@ -0,0 +1,32 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.app.Instrumentation;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Utility methods built around the android.app.Instrumentation class.
+ */
+public final class InstrumentationUtils {
+
+    private InstrumentationUtils() {
+    }
+
+    public static <R> R runOnMainSyncAndGetResult(Instrumentation instrumentation,
+            Callable<R> callable) throws Throwable {
+        FutureTask<R> task = new FutureTask<R>(callable);
+        instrumentation.runOnMainSync(task);
+        try {
+            return task.get();
+        } catch (ExecutionException e) {
+            // Unwrap the cause of the exception and re-throw it.
+            throw e.getCause();
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java
new file mode 100644
index 0000000..8b6550d
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for integration tests.
+ * <p>
+ * Examples of integration tests are tests that rely on real instances of the
+ * application's services and components (e.g. Search) to test the system as
+ * a whole. These tests may use additional command-line flags to configure the
+ * existing backends to use.
+ * <p>
+ * Such tests are likely NOT reliable enough to run on tree closing bots and
+ * should only be run on FYI bots.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface IntegrationTest {
+}
\ No newline at end of file
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java b/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java
new file mode 100644
index 0000000..31f3977
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java
@@ -0,0 +1,21 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used to mark a test that should only be run manually.
+ * <p>
+ * Tests with this annotation will not be run on bots, because they take too long
+ * or need manual monitoring.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Manual {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java
new file mode 100644
index 0000000..c4664d6
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+/**
+ * Helpers for testing UMA metrics.
+ */
+public class MetricsUtils {
+    /**
+     * Helper class that snapshots the given bucket of the given UMA histogram on its creation,
+     * allowing to inspect the number of samples recorded during its lifetime.
+     */
+    public static class HistogramDelta {
+        private final String mHistogram;
+        private final int mSampleValue;
+
+        private final int mInitialCount;
+
+        private int get() {
+            return RecordHistogram.getHistogramValueCountForTesting(mHistogram, mSampleValue);
+        }
+
+        /**
+         * Snapshots the given bucket of the given histogram.
+         * @param histogram name of the histogram to snapshot
+         * @param sampleValue the bucket that contains this value will be snapshot
+         */
+        public HistogramDelta(String histogram, int sampleValue) {
+            mHistogram = histogram;
+            mSampleValue = sampleValue;
+            mInitialCount = get();
+        }
+
+        /** Returns the number of samples of the snapshot bucket recorded since creation */
+        public int getDelta() {
+            return get() - mInitialCount;
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java b/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java
new file mode 100644
index 0000000..d7c45e7
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface MinAndroidSdkLevel {
+    int value() default 0;
+}
+
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java
new file mode 100644
index 0000000..9b3495c
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation tells the test harness that this method will be used in a performance test.
+ * This means that the test harness will use the parameters here to figure out which trace calls
+ * to track specifically for this test.
+ * <p>
+ * Each of the lists ({@link #traceNames()}, {@link #graphNames()},
+ * and {@link #seriesNames()}) should have the same number of
+ * elements.
+ * <p>
+ * To write a performance test, you need to do the following:
+ * <p><ol>
+ * <li>Add TraceEvent calls to the code that you want to track.
+ *   <ul>
+ *   <li> For FPS, add a TraceEvent.instant call where you want to time and detect calls.
+ *   <li> For code segment timing, add {@link org.chromium.base.TraceEvent#begin()}/
+ * {@link org.chromium.base.TraceEvent#end()} calls around the code
+ * segment (does not have to be in the same method).
+ *   </ul>
+ * <li> Write a Java Automated UI Test that instruments this code.
+ * <li> Add this PerfTest annotation to the test method.
+ *   <ul>
+ *   <li> traceNames must be a list of the names of all of the TraceEvent calls you want to track.
+ *   <li> graphNames must be a list, one for each traceName, of which graph the trace data should be
+ *   placed in (does not have to be unique).
+ *   <li> seriesNames must be a list, one for each traceName, of what the series should be called
+ *   for this trace data (has to be unique per graphName).
+ * <li> When checked in, the buildbots will automatically run this test and the results will show up
+ * under the Java Automation UI Performance graph, where there will be tabs for each graphName
+ * specified.
+ * <li> To test your performance test, run the following command and you should see the performance
+ * numbers printed to the console.
+ * </ol>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface PerfTest {
+    /**
+     * @return A list of the trace calls to track.
+     */
+    public String[] traceNames();
+
+    /**
+     * @return A list, one for each traceName, that represents which graph this trace call should
+     *         be output on.  This does not have to be unique if there are multiple series per
+     *         graph.
+     */
+    public String[] graphNames();
+
+    /**
+     * @return A list, one for each traceName, that represents the series this trace call should be
+     *         on the corresponding graph.  This should be unique.
+     */
+    public String[] seriesNames();
+
+    /**
+     * @return Whether or not we should automatically start and stop tracing for the test.  This
+     *         makes it easier to run some tests where tracing is started and stopped at the
+     *         beginning and end of that particular test.
+     */
+    public boolean autoTrace() default false;
+
+    /**
+     * @return Whether this performance test should track memory usage in addition to time.  If
+     *         true, this will track memory usage when tracking time deltas or instants.  With each
+     *         graph defined in the annotation for tracking time, this will add an additional graph
+     *         suffixed with a memory identifier containing the same series as those tracking the
+     *         timing performance but instead will be tracking memory consumption.
+     */
+    public boolean traceMemory() default true;
+
+    /**
+     * @return Whether this performance test should track time or (optionally) only memory.  If
+     *         false, this will not automatically track time deltas or instants when logging
+     *         memory info.
+     */
+    public boolean traceTiming() default true;
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
new file mode 100644
index 0000000..11026ef
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation for listing restrictions for a test method. For example, if a test method is only
+ * applicable on a phone with small memory:
+ *     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_SMALL_MEMORY})
+ * Test classes are free to define restrictions and enforce them using reflection at runtime.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Restriction {
+    /** Specifies the test is only valid on phone form factors. */
+    public static final String RESTRICTION_TYPE_PHONE = "Phone";
+
+    /** Specifies the test is only valid on tablet form factors. */
+    public static final String RESTRICTION_TYPE_TABLET = "Tablet";
+
+    /** Specifies the test is only valid on low end devices that have less memory. */
+    public static final String RESTRICTION_TYPE_LOW_END_DEVICE = "Low_End_Device";
+
+    /** Specifies the test is only valid on non-low end devices. */
+    public static final String RESTRICTION_TYPE_NON_LOW_END_DEVICE = "Non_Low_End_Device";
+
+    /**
+     * @return A list of restrictions.
+     */
+    public String[] value();
+}
\ No newline at end of file
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
new file mode 100644
index 0000000..c21bff9
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
@@ -0,0 +1,28 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+/**
+ * Utility class for scaling various timeouts by a common factor.
+ * For example, to run tests under Valgrind, you might want the following:
+ *   adb shell "echo 20.0 > /data/local/tmp/chrome_timeout_scale"
+ */
+public class ScalableTimeout {
+    private static Double sTimeoutScale = null;
+    private static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale";
+
+    public static long scaleTimeout(long timeout) {
+        if (sTimeoutScale == null) {
+            try {
+                char[] data = TestFileUtil.readUtf8File(PROPERTY_FILE, 32);
+                sTimeoutScale = Double.parseDouble(new String(data));
+            } catch (Exception e) {
+                // NumberFormatException, FileNotFoundException, IOException
+                sTimeoutScale = 1.0;
+            }
+        }
+        return (long) (timeout * sTimeoutScale);
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
new file mode 100644
index 0000000..8765def
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
@@ -0,0 +1,78 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * Utility class for dealing with files for test.
+ */
+public class TestFileUtil {
+    public static void createNewHtmlFile(String name, String title, String body)
+            throws IOException {
+        File file = new File(name);
+        if (!file.createNewFile()) {
+            throw new IOException("File \"" + name + "\" already exists");
+        }
+
+        Writer writer = null;
+        try {
+            writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
+            writer.write("<html><meta charset=\"UTF-8\" />"
+                    + "     <head><title>" + title + "</title></head>"
+                    + "     <body>"
+                    + (body != null ? body : "")
+                    + "     </body>"
+                    + "   </html>");
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    public static void deleteFile(String name) {
+        File file = new File(name);
+        boolean deleted = file.delete();
+        assert (deleted || !file.exists());
+    }
+
+    /**
+     * @param fileName the file to read in.
+     * @param sizeLimit cap on the file size: will throw an exception if exceeded
+     * @return Array of chars read from the file
+     * @throws FileNotFoundException file does not exceed
+     * @throws IOException error encountered accessing the file
+     */
+    public static char[] readUtf8File(String fileName, int sizeLimit) throws
+            FileNotFoundException, IOException {
+        Reader reader = null;
+        try {
+            File f = new File(fileName);
+            if (f.length() > sizeLimit) {
+                throw new IOException("File " + fileName + " length " + f.length()
+                        + " exceeds limit " + sizeLimit);
+            }
+            char[] buffer = new char[(int) f.length()];
+            reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+            int charsRead = reader.read(buffer);
+            // Debug check that we've exhausted the input stream (will fail e.g. if the
+            // file grew after we inspected its length).
+            assert !reader.ready();
+            return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
+        } finally {
+            if (reader != null) reader.close();
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
new file mode 100644
index 0000000..93c23f7
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
@@ -0,0 +1,143 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class is usefull when writing instrumentation tests that exercise code that posts tasks
+ * (to the same thread).
+ * Since the test code is run in a single thread, the posted tasks are never executed.
+ * The TestThread class lets you run that code on a specific thread synchronously and flush the
+ * message loop on that thread.
+ *
+ * Example of test using this:
+ *
+ * public void testMyAwesomeClass() {
+ *   TestThread testThread = new TestThread();
+ *   testThread.startAndWaitForReadyState();
+ *
+ *   testThread.runOnTestThreadSyncAndProcessPendingTasks(new Runnable() {
+ *       @Override
+ *       public void run() {
+ *           MyAwesomeClass.doStuffAsync();
+ *       }
+ *   });
+ *   // Once we get there we know doStuffAsync has been executed and all the tasks it posted.
+ *   assertTrue(MyAwesomeClass.stuffWasDone());
+ * }
+ *
+ * Notes:
+ * - this is only for tasks posted to the same thread. Anyway if you were posting to a different
+ *   thread, you'd probably need to set that other thread up.
+ * - this only supports tasks posted using Handler.post(), it won't work with postDelayed and
+ *   postAtTime.
+ * - if your test instanciates an object and that object is the one doing the posting of tasks, you
+ *   probably want to instanciate it on the test thread as it might create the Handler it posts
+ *   tasks to in the constructor.
+ */
+
+public class TestThread extends Thread {
+    private Object mThreadReadyLock;
+    private AtomicBoolean mThreadReady;
+    private Handler mMainThreadHandler;
+    private Handler mTestThreadHandler;
+
+    public TestThread() {
+        mMainThreadHandler = new Handler();
+        // We can't use the AtomicBoolean as the lock or findbugs will freak out...
+        mThreadReadyLock = new Object();
+        mThreadReady = new AtomicBoolean();
+    }
+
+    @Override
+    public void run() {
+        Looper.prepare();
+        mTestThreadHandler = new Handler();
+        mTestThreadHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (mThreadReadyLock) {
+                    mThreadReady.set(true);
+                    mThreadReadyLock.notify();
+                }
+            }
+        });
+        Looper.loop();
+    }
+
+    /**
+     * Starts this TestThread and blocks until it's ready to accept calls.
+     */
+    public void startAndWaitForReadyState() {
+        checkOnMainThread();
+        start();
+        synchronized (mThreadReadyLock) {
+            try {
+                // Note the mThreadReady and while are not really needed.
+                // There are there so findbugs don't report warnings.
+                while (!mThreadReady.get()) {
+                    mThreadReadyLock.wait();
+                }
+            } catch (InterruptedException ie) {
+                System.err.println("Error starting TestThread.");
+                ie.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Runs the passed Runnable synchronously on the TestThread and returns when all pending
+     * runnables have been excuted.
+     * Should be called from the main thread.
+     */
+    public void runOnTestThreadSyncAndProcessPendingTasks(Runnable r) {
+        checkOnMainThread();
+
+        runOnTestThreadSync(r);
+
+        // Run another task, when it's done it means all pendings tasks have executed.
+        runOnTestThreadSync(null);
+    }
+
+    /**
+     * Runs the passed Runnable on the test thread and blocks until it has finished executing.
+     * Should be called from the main thread.
+     * @param r The runnable to be executed.
+     */
+    public void runOnTestThreadSync(final Runnable r) {
+        checkOnMainThread();
+        final Object lock = new Object();
+        // Task executed is not really needed since we are only on one thread, it is here to appease
+        // findbugs.
+        final AtomicBoolean taskExecuted = new AtomicBoolean();
+        mTestThreadHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (r != null) r.run();
+                synchronized (lock) {
+                    taskExecuted.set(true);
+                    lock.notify();
+                }
+            }
+        });
+        synchronized (lock) {
+            try {
+                while (!taskExecuted.get()) {
+                    lock.wait();
+                }
+            } catch (InterruptedException ie) {
+                ie.printStackTrace();
+            }
+        }
+    }
+
+    private void checkOnMainThread() {
+        assert Looper.myLooper() == mMainThreadHandler.getLooper();
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java b/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java
new file mode 100644
index 0000000..5aee05e
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java
@@ -0,0 +1,22 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used to scale a specific test timeout.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TimeoutScale {
+    /**
+     * @return A number to scale the test timeout.
+     */
+    public int value();
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
new file mode 100644
index 0000000..797585f
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
@@ -0,0 +1,73 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import junit.framework.Assert;
+
+import org.chromium.base.PathUtils;
+
+/**
+ * Collection of URL utilities.
+ */
+public class UrlUtils {
+    private static final String DATA_DIR = "/chrome/test/data/";
+
+    /**
+     * Construct the full path of a test data file.
+     * @param path Pathname relative to external/chrome/test/data
+     */
+    public static String getTestFilePath(String path) {
+        // TODO(jbudorick): Remove DATA_DIR once everything has been isolated. crbug/400499
+        return PathUtils.getExternalStorageDirectory() + DATA_DIR + path;
+    }
+
+    // TODO(jbudorick): Remove this function once everything has been isolated and switched back
+    // to getTestFilePath. crbug/400499
+    /**
+     * Construct the full path of a test data file.
+     * @param path Pathname relative to external/
+     */
+    public static String getIsolatedTestFilePath(String path) {
+        return PathUtils.getExternalStorageDirectory() + "/" + path;
+    }
+
+    /**
+     * Construct a suitable URL for loading a test data file.
+     * @param path Pathname relative to external/chrome/test/data
+     */
+    public static String getTestFileUrl(String path) {
+        return "file://" + getTestFilePath(path);
+    }
+
+    // TODO(jbudorick): Remove this function once everything has been isolated and switched back
+    // to getTestFileUrl. crbug/400499
+    /**
+     * Construct a suitable URL for loading a test data file.
+     * @param path Pathname relative to external/
+     */
+    public static String getIsolatedTestFileUrl(String path) {
+        return "file://" + getIsolatedTestFilePath(path);
+    }
+
+    /**
+     * Construct a data:text/html URI for loading from an inline HTML.
+     * @param html An unencoded HTML
+     * @return String An URI that contains the given HTML
+     */
+    public static String encodeHtmlDataUri(String html) {
+        try {
+            // URLEncoder encodes into application/x-www-form-encoded, so
+            // ' '->'+' needs to be undone and replaced with ' '->'%20'
+            // to match the Data URI requirements.
+            String encoded =
+                    "data:text/html;utf-8," + java.net.URLEncoder.encode(html, "UTF-8");
+            encoded = encoded.replace("+", "%20");
+            return encoded;
+        } catch (java.io.UnsupportedEncodingException e) {
+            Assert.fail("Unsupported encoding: " + e.getMessage());
+            return null;
+        }
+    }
+}
diff --git a/base/test/data/file_util/binary_file.bin b/base/test/data/file_util/binary_file.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/base/test/data/file_util/binary_file.bin
Binary files differ
diff --git a/base/test/data/file_util/binary_file_diff.bin b/base/test/data/file_util/binary_file_diff.bin
new file mode 100644
index 0000000..103b26d
--- /dev/null
+++ b/base/test/data/file_util/binary_file_diff.bin
Binary files differ
diff --git a/base/test/data/file_util/binary_file_same.bin b/base/test/data/file_util/binary_file_same.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/base/test/data/file_util/binary_file_same.bin
Binary files differ
diff --git a/base/test/data/file_util/blank_line.txt b/base/test/data/file_util/blank_line.txt
new file mode 100644
index 0000000..8892069
--- /dev/null
+++ b/base/test/data/file_util/blank_line.txt
@@ -0,0 +1,3 @@
+The next line is blank.
+
+But this one isn't.
diff --git a/base/test/data/file_util/blank_line_crlf.txt b/base/test/data/file_util/blank_line_crlf.txt
new file mode 100644
index 0000000..3aefe52
--- /dev/null
+++ b/base/test/data/file_util/blank_line_crlf.txt
@@ -0,0 +1,3 @@
+The next line is blank.

+

+But this one isn't.

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

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

+  "appName": {

+    "message": "Gmail",

+    "description": "App name."

+  },

+  "appDesc": {

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

+    "description":"App description."

+  }

+}
\ No newline at end of file
diff --git a/base/test/data/pe_image/pe_image_test_32.dll b/base/test/data/pe_image/pe_image_test_32.dll
new file mode 100755
index 0000000..118ce11
--- /dev/null
+++ b/base/test/data/pe_image/pe_image_test_32.dll
Binary files differ
diff --git a/base/test/data/pe_image/pe_image_test_64.dll b/base/test/data/pe_image/pe_image_test_64.dll
new file mode 100755
index 0000000..70f8ea4
--- /dev/null
+++ b/base/test/data/pe_image/pe_image_test_64.dll
Binary files differ
diff --git a/base/test/data/prefs/invalid.json b/base/test/data/prefs/invalid.json
new file mode 100644
index 0000000..43392a9
--- /dev/null
+++ b/base/test/data/prefs/invalid.json
@@ -0,0 +1 @@
+!@#$%^&
\ No newline at end of file
diff --git a/base/test/data/prefs/read.json b/base/test/data/prefs/read.json
new file mode 100644
index 0000000..ea578a4
--- /dev/null
+++ b/base/test/data/prefs/read.json
@@ -0,0 +1,8 @@
+{
+  "homepage": "http://www.cnn.com",
+  "some_directory": "/usr/local/",
+  "tabs": {
+    "new_windows_in_tabs": true,
+    "max_tabs": 20
+  }
+}
diff --git a/base/test/data/prefs/write.golden.json b/base/test/data/prefs/write.golden.json
new file mode 100644
index 0000000..fb1fff1
--- /dev/null
+++ b/base/test/data/prefs/write.golden.json
@@ -0,0 +1 @@
+{"homepage":"http://www.cnn.com","long_int":{"pref":"214748364842"},"some_directory":"/usr/sbin/","tabs":{"max_tabs":10,"new_windows_in_tabs":false}}
\ No newline at end of file
diff --git a/base/test/data/serializer_nested_test.json b/base/test/data/serializer_nested_test.json
new file mode 100644
index 0000000..cfea8e8
--- /dev/null
+++ b/base/test/data/serializer_nested_test.json
@@ -0,0 +1,17 @@
+{
+   "bool": true,
+   "dict": {
+      "bool": true,
+      "dict": {
+         "bees": "knees",
+         "cats": "meow"
+      },
+      "foos": "bar",
+      "list": [ 3.4, "second", null ]
+   },
+   "int": 42,
+   "list": [ 1, 2 ],
+   "null": null,
+   "real": 3.14,
+   "string": "hello"
+}
diff --git a/base/test/data/serializer_test.json b/base/test/data/serializer_test.json
new file mode 100644
index 0000000..446925e
--- /dev/null
+++ b/base/test/data/serializer_test.json
@@ -0,0 +1,8 @@
+{
+   "bool": true,
+   "int": 42,
+   "list": [ 1, 2 ],
+   "null": null,
+   "real": 3.14,
+   "string": "hello"
+}
diff --git a/base/test/data/serializer_test_nowhitespace.json b/base/test/data/serializer_test_nowhitespace.json
new file mode 100644
index 0000000..a1afdc5
--- /dev/null
+++ b/base/test/data/serializer_test_nowhitespace.json
@@ -0,0 +1 @@
+{"bool":true,"int":42,"list":[1,2],"null":null,"real":3.14,"string":"hello"}
\ No newline at end of file
diff --git a/base/test/expectations/OWNERS b/base/test/expectations/OWNERS
new file mode 100644
index 0000000..14fce2a
--- /dev/null
+++ b/base/test/expectations/OWNERS
@@ -0,0 +1 @@
+rsesek@chromium.org
diff --git a/base/test/expectations/expectation.cc b/base/test/expectations/expectation.cc
new file mode 100644
index 0000000..3081779
--- /dev/null
+++ b/base/test/expectations/expectation.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/expectation.h"
+
+#include "base/logging.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/mac/mac_util.h"
+#elif defined(OS_LINUX)
+#include "base/sys_info.h"
+#endif
+
+namespace test_expectations {
+
+bool ResultFromString(const base::StringPiece& result, Result* out_result) {
+  if (result == "Failure")
+    *out_result = RESULT_FAILURE;
+  else if (result == "Timeout")
+    *out_result = RESULT_TIMEOUT;
+  else if (result == "Crash")
+    *out_result = RESULT_CRASH;
+  else if (result == "Skip")
+    *out_result = RESULT_SKIP;
+  else if (result == "Pass")
+    *out_result = RESULT_PASS;
+  else
+    return false;
+
+  return true;
+}
+
+static bool IsValidPlatform(const Platform* platform) {
+  const std::string& name = platform->name;
+  const std::string& variant = platform->variant;
+
+  if (name == "Win") {
+    if (!variant.empty() &&
+        variant != "XP" &&
+        variant != "Vista" &&
+        variant != "7" &&
+        variant != "8") {
+      return false;
+    }
+  } else if (name == "Mac") {
+    if (!variant.empty() &&
+        variant != "10.6" &&
+        variant != "10.7" &&
+        variant != "10.8" &&
+        variant != "10.9" &&
+        variant != "10.10") {
+      return false;
+    }
+  } else if (name == "Linux") {
+    if (!variant.empty() &&
+        variant != "32" &&
+        variant != "64") {
+      return false;
+    }
+  } else if (name == "ChromeOS") {
+    // TODO(rsesek): Figure out what ChromeOS needs.
+  } else if (name == "iOS") {
+    // TODO(rsesek): Figure out what iOS needs. Probably Device and Simulator.
+  } else if (name == "Android") {
+    // TODO(rsesek): Figure out what Android needs.
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool PlatformFromString(const base::StringPiece& modifier,
+                        Platform* out_platform) {
+  size_t sep = modifier.find('-');
+  if (sep == std::string::npos) {
+    out_platform->name = modifier.as_string();
+    out_platform->variant.clear();
+  } else {
+    out_platform->name = modifier.substr(0, sep).as_string();
+    out_platform->variant = modifier.substr(sep + 1).as_string();
+  }
+
+  return IsValidPlatform(out_platform);
+}
+
+Platform GetCurrentPlatform() {
+  Platform platform;
+#if defined(OS_WIN)
+  platform.name = "Win";
+  base::win::Version version = base::win::GetVersion();
+  if (version == base::win::VERSION_XP)
+    platform.variant = "XP";
+  else if (version == base::win::VERSION_VISTA)
+    platform.variant = "Vista";
+  else if (version == base::win::VERSION_WIN7)
+    platform.variant = "7";
+  else if (version == base::win::VERSION_WIN8)
+    platform.variant = "8";
+#elif defined(OS_IOS)
+  platform.name = "iOS";
+#elif defined(OS_MACOSX)
+  platform.name = "Mac";
+  if (base::mac::IsOSSnowLeopard())
+    platform.variant = "10.6";
+  else if (base::mac::IsOSLion())
+    platform.variant = "10.7";
+  else if (base::mac::IsOSMountainLion())
+    platform.variant = "10.8";
+  else if (base::mac::IsOSMavericks())
+    platform.variant = "10.9";
+  else if (base::mac::IsOSYosemite())
+    platform.variant = "10.10";
+#elif defined(OS_CHROMEOS)
+  platform.name = "ChromeOS";
+#elif defined(OS_ANDROID)
+  platform.name = "Android";
+#elif defined(OS_LINUX)
+  platform.name = "Linux";
+  std::string arch = base::SysInfo::OperatingSystemArchitecture();
+  if (arch == "x86")
+    platform.variant = "32";
+  else if (arch == "x86_64")
+    platform.variant = "64";
+#else
+  NOTREACHED();
+#endif
+  return platform;
+}
+
+bool ConfigurationFromString(const base::StringPiece& modifier,
+                             Configuration* out_configuration) {
+  if (modifier == "Debug")
+    *out_configuration = CONFIGURATION_DEBUG;
+  else if (modifier == "Release")
+    *out_configuration = CONFIGURATION_RELEASE;
+  else
+    return false;
+
+  return true;
+}
+
+Configuration GetCurrentConfiguration() {
+#if NDEBUG
+  return CONFIGURATION_RELEASE;
+#else
+  return CONFIGURATION_DEBUG;
+#endif
+}
+
+Expectation::Expectation()
+    : configuration(CONFIGURATION_UNSPECIFIED),
+      result(RESULT_PASS) {
+}
+
+Expectation::~Expectation() {}
+
+}  // namespace test_expectations
diff --git a/base/test/expectations/expectation.h b/base/test/expectations/expectation.h
new file mode 100644
index 0000000..be5a9d7
--- /dev/null
+++ b/base/test/expectations/expectation.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_EXPECTATIONS_EXPECTATION_H_
+#define BASE_TEST_EXPECTATIONS_EXPECTATION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+
+namespace test_expectations {
+
+// A Result is the expectation of a test's behavior.
+enum Result {
+  // The test has a failing assertion.
+  RESULT_FAILURE,
+
+  // The test does not complete within the test runner's alloted duration.
+  RESULT_TIMEOUT,
+
+  // The test crashes during the course of its execution.
+  RESULT_CRASH,
+
+  // The test should not be run ever.
+  RESULT_SKIP,
+
+  // The test passes, used to override a more general expectation.
+  RESULT_PASS,
+};
+
+// Converts a text string form of a |result| to its enum value, written to
+// |out_result|. Returns true on success and false on error.
+bool ResultFromString(const base::StringPiece& result,
+                      Result* out_result) WARN_UNUSED_RESULT;
+
+// A Platform stores information about the OS environment.
+struct Platform {
+  // The name of the platform. E.g., "Win", or "Mac".
+  std::string name;
+
+  // The variant of the platform, either an OS version like "XP" or "10.8", or
+  // "Device" or "Simulator" in the case of mobile.
+  std::string variant;
+};
+
+// Converts a text string |modifier| to a Platform struct, written to
+// |out_platform|. Returns true on success and false on failure.
+bool PlatformFromString(const base::StringPiece& modifier,
+                        Platform* out_platform) WARN_UNUSED_RESULT;
+
+// Returns the Platform for the currently running binary.
+Platform GetCurrentPlatform();
+
+// The build configuration.
+enum Configuration {
+  CONFIGURATION_UNSPECIFIED,
+  CONFIGURATION_DEBUG,
+  CONFIGURATION_RELEASE,
+};
+
+// Converts the |modifier| to a Configuration constant, writing the value to
+// |out_configuration|. Returns true on success or false on failure.
+bool ConfigurationFromString(const base::StringPiece& modifier,
+    Configuration* out_configuration) WARN_UNUSED_RESULT;
+
+// Returns the Configuration for the currently running binary.
+Configuration GetCurrentConfiguration();
+
+// An Expectation is records what the result for a given test name should be on
+// the specified platforms and configuration.
+struct Expectation {
+  Expectation();
+  ~Expectation();
+
+  // The name of the test, like FooBarTest.BarIsBaz.
+  std::string test_name;
+
+  // The set of platforms for which this expectation is applicable.
+  std::vector<Platform> platforms;
+
+  // The build configuration.
+  Configuration configuration;
+
+  // The expected result of this test.
+  Result result;
+};
+
+}  // namespace test_expectations
+
+#endif  // BASE_TEST_EXPECTATIONS_EXPECTATION_H_
diff --git a/base/test/expectations/expectation_unittest.cc b/base/test/expectations/expectation_unittest.cc
new file mode 100644
index 0000000..c0f55a1
--- /dev/null
+++ b/base/test/expectations/expectation_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/expectation.h"
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(TestExpectationsFunctionsTest, ResultFromString) {
+  test_expectations::Result result = test_expectations::RESULT_PASS;
+
+  EXPECT_TRUE(ResultFromString("Failure", &result));
+  EXPECT_EQ(test_expectations::RESULT_FAILURE, result);
+
+  EXPECT_TRUE(ResultFromString("Timeout", &result));
+  EXPECT_EQ(test_expectations::RESULT_TIMEOUT, result);
+
+  EXPECT_TRUE(ResultFromString("Crash", &result));
+  EXPECT_EQ(test_expectations::RESULT_CRASH, result);
+
+  EXPECT_TRUE(ResultFromString("Skip", &result));
+  EXPECT_EQ(test_expectations::RESULT_SKIP, result);
+
+  EXPECT_TRUE(ResultFromString("Pass", &result));
+  EXPECT_EQ(test_expectations::RESULT_PASS, result);
+
+  // Case sensitive.
+  EXPECT_FALSE(ResultFromString("failure", &result));
+  EXPECT_EQ(test_expectations::RESULT_PASS, result);
+}
+
+TEST(TestExpectationsFunctionsTest, ConfigurationFromString) {
+  test_expectations::Configuration config =
+      test_expectations::CONFIGURATION_UNSPECIFIED;
+
+  EXPECT_TRUE(ConfigurationFromString("Debug", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_DEBUG, config);
+
+  EXPECT_TRUE(ConfigurationFromString("Release", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config);
+
+  EXPECT_FALSE(ConfigurationFromString("NotAConfig", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config);
+
+  // Case sensitive.
+  EXPECT_FALSE(ConfigurationFromString("debug", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config);
+}
+
+TEST(TestExpectationsFunctionsTest, PlatformFromString) {
+  test_expectations::Platform platform;
+
+  EXPECT_TRUE(PlatformFromString("Win", &platform));
+  EXPECT_EQ("Win", platform.name);
+  EXPECT_EQ("", platform.variant);
+
+  EXPECT_TRUE(PlatformFromString("Mac-10.6", &platform));
+  EXPECT_EQ("Mac", platform.name);
+  EXPECT_EQ("10.6", platform.variant);
+
+  EXPECT_TRUE(PlatformFromString("ChromeOS", &platform));
+  EXPECT_EQ("ChromeOS", platform.name);
+  EXPECT_EQ("", platform.variant);
+
+  EXPECT_TRUE(PlatformFromString("Linux-", &platform));
+  EXPECT_EQ("Linux", platform.name);
+  EXPECT_EQ("", platform.variant);
+
+  EXPECT_FALSE(PlatformFromString("", &platform));
+}
+
+TEST(TestExpectationsFunctionsTest, IsValidPlatform) {
+  const char* const kValidPlatforms[] = {
+    "Win",
+    "Win-XP",
+    "Win-Vista",
+    "Win-7",
+    "Win-8",
+    "Mac",
+    "Mac-10.6",
+    "Mac-10.7",
+    "Mac-10.8",
+    "Linux",
+    "Linux-32",
+    "Linux-64",
+    "ChromeOS",
+    "iOS",
+    "Android",
+  };
+
+  const char* const kInvalidPlatforms[] = {
+    "Solaris",
+    "Plan9",
+  };
+
+  for (size_t i = 0; i < arraysize(kValidPlatforms); ++i) {
+    test_expectations::Platform platform;
+    EXPECT_TRUE(test_expectations::PlatformFromString(
+        kValidPlatforms[i], &platform)) << kValidPlatforms[i];
+  }
+
+  for (size_t i = 0; i < arraysize(kInvalidPlatforms); ++i) {
+    test_expectations::Platform platform;
+    EXPECT_FALSE(test_expectations::PlatformFromString(
+        kInvalidPlatforms[i], &platform)) << kInvalidPlatforms[i];
+  }
+}
+
+TEST(TestExpectationsFunctionsTest, CurrentPlatform) {
+  test_expectations::Platform current =
+      test_expectations::GetCurrentPlatform();
+  EXPECT_FALSE(current.name.empty());
+}
+
+TEST(TestExpectationsFunctionsTest, CurrentConfiguration) {
+  test_expectations::Configuration current =
+      test_expectations::GetCurrentConfiguration();
+  EXPECT_NE(test_expectations::CONFIGURATION_UNSPECIFIED, current);
+}
diff --git a/base/test/expectations/parser.cc b/base/test/expectations/parser.cc
new file mode 100644
index 0000000..c7132e5
--- /dev/null
+++ b/base/test/expectations/parser.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/parser.h"
+
+#include "base/strings/string_util.h"
+
+namespace test_expectations {
+
+Parser::Parser(Delegate* delegate, const std::string& input)
+    : delegate_(delegate),
+      input_(input),
+      pos_(NULL),
+      end_(NULL),
+      line_number_(0),
+      data_error_(false) {
+}
+
+Parser::~Parser() {
+}
+
+void Parser::Parse() {
+  pos_ = &input_[0];
+  end_ = pos_ + input_.length();
+
+  line_number_ = 1;
+
+  StateFuncPtr state = &Parser::Start;
+  while (state) {
+    state = (this->*state)();
+  }
+}
+
+inline bool Parser::HasNext() {
+  return pos_ < end_;
+}
+
+Parser::StateFunc Parser::Start() {
+  // If at the start of a line is whitespace, skip it and arrange to come back
+  // here.
+  if (IsAsciiWhitespace(*pos_))
+    return SkipWhitespaceAndNewLines(&Parser::Start);
+
+  // Handle comments at the start of lines.
+  if (*pos_ == '#')
+    return &Parser::ParseComment;
+
+  // After arranging to come back here from skipping whitespace and comments,
+  // the parser may be at the end of the input.
+  if (pos_ >= end_)
+    return NULL;
+
+  current_ = Expectation();
+  data_error_ = false;
+
+  return &Parser::ParseBugURL;
+}
+
+Parser::StateFunc Parser::ParseComment() {
+  if (*pos_ != '#')
+    return SyntaxError("Invalid start of comment");
+
+  do {
+    ++pos_;
+  } while (HasNext() && *pos_ != '\n');
+
+  return &Parser::Start;
+}
+
+Parser::StateFunc Parser::ParseBugURL() {
+  return SkipWhitespace(ExtractString(
+      &Parser::BeginModifiers));
+}
+
+Parser::StateFunc Parser::BeginModifiers() {
+  if (*pos_ != '[' || !HasNext())
+    return SyntaxError("Expected '[' for start of modifiers");
+
+  ++pos_;
+  return SkipWhitespace(&Parser::InModifiers);
+}
+
+Parser::StateFunc Parser::InModifiers() {
+  if (*pos_ == ']')
+    return &Parser::EndModifiers;
+
+  return ExtractString(SkipWhitespace(
+      &Parser::SaveModifier));
+}
+
+Parser::StateFunc Parser::SaveModifier() {
+  if (extracted_string_.empty())
+    return SyntaxError("Invalid modifier list");
+
+  Configuration config;
+  if (ConfigurationFromString(extracted_string_, &config)) {
+    if (current_.configuration != CONFIGURATION_UNSPECIFIED)
+      DataError("Cannot use more than one configuration modifier");
+    else
+      current_.configuration = config;
+  } else {
+    Platform platform;
+    if (PlatformFromString(extracted_string_, &platform))
+      current_.platforms.push_back(platform);
+    else
+      DataError("Invalid modifier string");
+  }
+
+  return SkipWhitespace(&Parser::InModifiers);
+}
+
+Parser::StateFunc Parser::EndModifiers() {
+ if (*pos_ != ']' || !HasNext())
+    return SyntaxError("Expected ']' for end of modifiers list");
+
+  ++pos_;
+  return SkipWhitespace(&Parser::ParseTestName);
+}
+
+Parser::StateFunc Parser::ParseTestName() {
+  return ExtractString(&Parser::SaveTestName);
+}
+
+Parser::StateFunc Parser::SaveTestName() {
+  if (extracted_string_.empty())
+    return SyntaxError("Invalid test name");
+
+  current_.test_name = extracted_string_.as_string();
+  return SkipWhitespace(&Parser::ParseExpectation);
+}
+
+Parser::StateFunc Parser::ParseExpectation() {
+  if (*pos_ != '=' || !HasNext())
+    return SyntaxError("Expected '=' for expectation result");
+
+  ++pos_;
+  return SkipWhitespace(&Parser::ParseExpectationType);
+}
+
+Parser::StateFunc Parser::ParseExpectationType() {
+  return ExtractString(&Parser::SaveExpectationType);
+}
+
+Parser::StateFunc Parser::SaveExpectationType() {
+  if (!ResultFromString(extracted_string_, &current_.result))
+    DataError("Unknown expectation type");
+
+  return SkipWhitespace(&Parser::End);
+}
+
+Parser::StateFunc Parser::End() {
+  if (!data_error_)
+    delegate_->EmitExpectation(current_);
+
+  if (HasNext())
+    return SkipWhitespaceAndNewLines(&Parser::Start);
+
+  return NULL;
+}
+
+Parser::StateFunc Parser::ExtractString(StateFunc success) {
+  const char* start = pos_;
+  while (!IsAsciiWhitespace(*pos_) && *pos_ != ']' && HasNext()) {
+    ++pos_;
+    if (*pos_ == '#') {
+      return SyntaxError("Unexpected start of comment");
+    }
+  }
+  extracted_string_ = base::StringPiece(start, pos_ - start);
+  return success;
+}
+
+Parser::StateFunc Parser::SkipWhitespace(Parser::StateFunc next) {
+  while ((*pos_ == ' ' || *pos_ == '\t') && HasNext()) {
+    ++pos_;
+  }
+  return next;
+}
+
+Parser::StateFunc Parser::SkipWhitespaceAndNewLines(Parser::StateFunc next) {
+  while (IsAsciiWhitespace(*pos_) && HasNext()) {
+    if (*pos_ == '\n') {
+      ++line_number_;
+    }
+    ++pos_;
+  }
+  return next;
+}
+
+Parser::StateFunc Parser::SyntaxError(const std::string& message) {
+  delegate_->OnSyntaxError(message);
+  return NULL;
+}
+
+void Parser::DataError(const std::string& error) {
+  data_error_ = true;
+  delegate_->OnDataError(error);
+}
+
+}  // namespace test_expectations
diff --git a/base/test/expectations/parser.h b/base/test/expectations/parser.h
new file mode 100644
index 0000000..69a741a
--- /dev/null
+++ b/base/test/expectations/parser.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_EXPECTATIONS_PARSER_H_
+#define BASE_TEST_EXPECTATIONS_PARSER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "base/test/expectations/expectation.h"
+
+namespace test_expectations {
+
+// This is the internal parser for test expectations. It parses an input
+// string and reports information to its Delegate as it's processing the
+// input.
+//
+// The input format is documented here:
+// https://docs.google.com/a/chromium.org/document/d/1edhMJ5doY_dzfbKNCzeJJ-8XxPrexTbNL2Y_jVvLB8Q/view
+//
+// Basic format:
+// "http://bug/1234 [ OS-Version ] Test.Name = Result"
+//
+// The parser is implemented as a state machine, with each state returning a
+// function pointer to the next state.
+class Parser {
+ public:
+  // The parser will call these methods on its delegate during a Parse()
+  // operation.
+  class Delegate {
+   public:
+    // When a well-formed and valid Expectation has been parsed from the input,
+    // it is reported to the delegate via this method.
+    virtual void EmitExpectation(const Expectation& expectation) = 0;
+
+    // Called when the input string is not well-formed. Parsing will stop after
+    // this method is called.
+    virtual void OnSyntaxError(const std::string& message) = 0;
+
+    // Called when an Expectation has been parsed because it is well-formed but
+    // contains invalid data (i.e. the modifiers or result are not valid
+    // keywords). This Expectation will not be reported via EmitExpectation.
+    virtual void OnDataError(const std::string& message) = 0;
+  };
+
+  // Creates a new parser for |input| that will send data to |delegate|.
+  Parser(Delegate* delegate, const std::string& input);
+  ~Parser();
+
+  // Runs the parser of the input string.
+  void Parse();
+
+ private:
+  // This bit of hackery is used to implement a function pointer type that
+  // returns a pointer to a function of the same signature. Since a definition
+  // like that is inherently recursive, it's impossible to do:
+  //     type StateFunc(*StateFunc)(StateData*);
+  // However, this approach works without the need to use void*. Inspired by
+  // <http://www.gotw.ca/gotw/057.htm>.
+  struct StateFunc;
+  typedef StateFunc(Parser::*StateFuncPtr)();
+  struct StateFunc {
+    StateFunc(StateFuncPtr pf) : pf_(pf) {}
+    operator StateFuncPtr() {
+      return pf_;
+    }
+    StateFuncPtr pf_;
+  };
+
+  // Tests whether there is at least one more character at pos_ before end_.
+  bool HasNext();
+
+  // The parser state functions. On entry, the parser state is at the beginning
+  // of the token. Each returns a function pointer to the next state function,
+  // or NULL to end parsing. On return, the parser is at the beginning of the
+  // next token.
+  StateFunc Start();
+  StateFunc ParseComment();
+  StateFunc ParseBugURL();
+  StateFunc BeginModifiers();
+  StateFunc InModifiers();
+  StateFunc SaveModifier();
+  StateFunc EndModifiers();
+  StateFunc ParseTestName();
+  StateFunc SaveTestName();
+  StateFunc ParseExpectation();
+  StateFunc ParseExpectationType();
+  StateFunc SaveExpectationType();
+  StateFunc End();
+
+  // A state function that collects character data from the current position
+  // to the next whitespace character. Returns the |success| function when at
+  // the end of the string, with the data stored in |extracted_string_|.
+  StateFunc ExtractString(StateFunc success);
+
+  // Function that skips over horizontal whitespace characters and then returns
+  // the |next| state.
+  StateFunc SkipWhitespace(StateFunc next);
+
+  // Does the same as SkipWhitespace but includes newlines.
+  StateFunc SkipWhitespaceAndNewLines(StateFunc next);
+
+  // State function that reports the given syntax error |message| to the
+  // delegate and then returns NULL, ending the parse loop.
+  StateFunc SyntaxError(const std::string& message);
+
+  // Function that reports the data |error| to the delegate without stopping
+  // parsing.
+  void DataError(const std::string& error);
+
+  // Parser delegate.
+  Delegate* delegate_;
+
+  // The input string.
+  std::string input_;
+
+  // Current location in the |input_|.
+  const char* pos_;
+
+  // Pointer to the end of the |input_|.
+  const char* end_;
+
+  // Current line number, as updated by SkipWhitespace().
+  int line_number_;
+
+  // The character data extracted from |input_| as a result of the
+  // ExtractString() state.
+  base::StringPiece extracted_string_;
+
+  // The Expectation object that is currently being processed by the parser.
+  // Reset in Start().
+  Expectation current_;
+
+  // If DataError() has been called during the course of parsing |current_|.
+  // If true, then |current_| will not be emitted to the Delegate.
+  bool data_error_;
+};
+
+}  // namespace test_expectations
+
+#endif  // BASE_TEST_EXPECTATIONS_PARSER_H_
diff --git a/base/test/expectations/parser_unittest.cc b/base/test/expectations/parser_unittest.cc
new file mode 100644
index 0000000..074d634
--- /dev/null
+++ b/base/test/expectations/parser_unittest.cc
@@ -0,0 +1,209 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using test_expectations::Parser;
+
+class TestExpectationParserTest : public testing::Test,
+                                  public Parser::Delegate {
+ public:
+  void EmitExpectation(
+      const test_expectations::Expectation& expectation) override {
+    expectations_.push_back(expectation);
+  }
+
+  void OnSyntaxError(const std::string& message) override {
+    syntax_error_ = message;
+  }
+
+  void OnDataError(const std::string& error) override {
+    data_errors_.push_back(error);
+  }
+
+ protected:
+  std::vector<test_expectations::Expectation> expectations_;
+  std::string syntax_error_;
+  std::vector<std::string> data_errors_;
+};
+
+TEST_F(TestExpectationParserTest, Basic) {
+  Parser(this,
+      "http://crbug.com/1234 [ Win-8 ] DouglasTest.PoopsOk = Timeout").
+          Parse();
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(1u, expectations_.size());
+  EXPECT_EQ("DouglasTest.PoopsOk", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_TIMEOUT, expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(1u, expectations_[0].platforms.size());
+  EXPECT_EQ("Win", expectations_[0].platforms[0].name);
+  EXPECT_EQ("8", expectations_[0].platforms[0].variant);
+}
+
+TEST_F(TestExpectationParserTest, MultiModifier) {
+  Parser(this, "BUG [ Win-XP Mac ] OhMy.MeOhMy = Failure").Parse();
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(1u, expectations_.size());
+  EXPECT_EQ("OhMy.MeOhMy", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_FAILURE,
+            expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(2u, expectations_[0].platforms.size());
+
+  EXPECT_EQ("Win", expectations_[0].platforms[0].name);
+  EXPECT_EQ("XP", expectations_[0].platforms[0].variant);
+
+  EXPECT_EQ("Mac", expectations_[0].platforms[1].name);
+  EXPECT_EQ("", expectations_[0].platforms[1].variant);
+}
+
+TEST_F(TestExpectationParserTest, EmptyModifier) {
+  Parser(this,
+      "BUG [] First.Test = Failure\n"
+      "BUG2 [   ] Second.Test = Crash").Parse();
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(2u, expectations_.size());
+
+  EXPECT_EQ("First.Test", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_FAILURE,
+            expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+  EXPECT_EQ(0u, expectations_[0].platforms.size());
+
+  EXPECT_EQ("Second.Test", expectations_[1].test_name);
+  EXPECT_EQ(test_expectations::RESULT_CRASH,
+            expectations_[1].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[1].configuration);
+  EXPECT_EQ(0u, expectations_[1].platforms.size());
+}
+
+TEST_F(TestExpectationParserTest, MultiLine) {
+  Parser(this,
+      "BUG [ Linux ] Line.First = Failure\n"
+      "\n"
+      "# A test comment.\n"
+      "BUG2 [ Release ] Line.Second = Skip").Parse();
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(2u, expectations_.size());
+  EXPECT_EQ("Line.First", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_FAILURE, expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(1u, expectations_[0].platforms.size());
+  EXPECT_EQ("Linux", expectations_[0].platforms[0].name);
+  EXPECT_EQ("", expectations_[0].platforms[0].variant);
+
+  EXPECT_EQ("Line.Second", expectations_[1].test_name);
+  EXPECT_EQ(test_expectations::RESULT_SKIP, expectations_[1].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE,
+            expectations_[1].configuration);
+  EXPECT_EQ(0u, expectations_[1].platforms.size());
+}
+
+TEST_F(TestExpectationParserTest, MultiLineWithComments) {
+  Parser(this,
+      "  # Comment for your thoughts\n"
+      "  \t \n"
+      "BUG [ Mac-10.8 Debug] Foo=Bar =Skip   # Why not another comment?\n"
+      "BUG2 [Win-XP\tWin-Vista ] Cow.GoesMoo   =\tTimeout\n\n").Parse();
+  EXPECT_TRUE(syntax_error_.empty()) << syntax_error_;
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(2u, expectations_.size());
+  EXPECT_EQ("Foo=Bar", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_SKIP, expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_DEBUG,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(1u, expectations_[0].platforms.size());
+  EXPECT_EQ("Mac", expectations_[0].platforms[0].name);
+  EXPECT_EQ("10.8", expectations_[0].platforms[0].variant);
+
+  EXPECT_EQ("Cow.GoesMoo", expectations_[1].test_name);
+  EXPECT_EQ(test_expectations::RESULT_TIMEOUT, expectations_[1].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[1].configuration);
+
+  ASSERT_EQ(2u, expectations_[1].platforms.size());
+  EXPECT_EQ("Win", expectations_[1].platforms[0].name);
+  EXPECT_EQ("XP", expectations_[1].platforms[0].variant);
+  EXPECT_EQ("Win", expectations_[1].platforms[0].name);
+  EXPECT_EQ("Vista", expectations_[1].platforms[1].variant);
+}
+
+TEST_F(TestExpectationParserTest, WeirdSpaces) {
+  Parser(this, "   BUG       [Linux]        Weird  = Skip    ").Parse();
+  EXPECT_EQ(1u, expectations_.size());
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+}
+
+TEST_F(TestExpectationParserTest, SyntaxErrors) {
+  const char* const kErrors[] = {
+    "Foo [ dfasd",
+    "Foo [Linux] # This is an illegal comment",
+    "Foo [Linux] Bar # Another illegal comment.",
+    "Foo [Linux] Bar = # Another illegal comment.",
+    "Foo[Linux]Bar=Failure",
+    "Foo\n[Linux] Bar = Failure",
+    "Foo [\nLinux] Bar = Failure",
+    "Foo [Linux\n] Bar = Failure",
+    "Foo [ Linux ] \n Bar = Failure",
+    "Foo [ Linux ] Bar =\nFailure",
+    "Foo [ Linux \n ] Bar =\nFailure",
+  };
+
+  for (size_t i = 0; i < arraysize(kErrors); ++i) {
+    Parser(this, kErrors[i]).Parse();
+    EXPECT_FALSE(syntax_error_.empty())
+        << "Should have error for #" << i << ": " << kErrors[i];
+    syntax_error_.clear();
+  }
+}
+
+TEST_F(TestExpectationParserTest, DataErrors) {
+  const char* const kOneError[] = {
+    "http://crbug.com/1234 [MagicBrowzR] BadModifier = Timeout",
+    "________ [Linux] BadResult = WhatNow",
+    "http://wkb.ug/1234 [Debug Release Win-7] MultipleConfigs = Skip",
+  };
+
+  for (size_t i = 0; i < arraysize(kOneError); ++i) {
+    Parser(this, kOneError[i]).Parse();
+    EXPECT_EQ(1u, data_errors_.size()) << kOneError[i];
+    data_errors_.clear();
+  }
+
+  const char* const kTwoErrors[] = {
+    ". [Mac-TurningIntoiOS] BadModifierVariant.BadResult = Foobar",
+    "1234 [ Debug Release OS/2 ] MultipleConfigs.BadModifier = Pass",
+  };
+
+  for (size_t i = 0; i < arraysize(kTwoErrors); ++i) {
+    Parser(this, kTwoErrors[i]).Parse();
+    EXPECT_EQ(2u, data_errors_.size()) << kTwoErrors[i];
+    data_errors_.clear();
+  }
+}
diff --git a/base/test/gtest_util.cc b/base/test/gtest_util.cc
new file mode 100644
index 0000000..b811194
--- /dev/null
+++ b/base/test/gtest_util.cc
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_util.h"
+
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+std::string FormatFullTestName(const std::string& test_case_name,
+                               const std::string& test_name) {
+  return test_case_name + "." + test_name;
+}
+
+std::vector<SplitTestName> GetCompiledInTests() {
+  testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
+
+  std::vector<SplitTestName> tests;
+  for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
+    const testing::TestCase* test_case = unit_test->GetTestCase(i);
+    for (int j = 0; j < test_case->total_test_count(); ++j) {
+      const testing::TestInfo* test_info = test_case->GetTestInfo(j);
+      tests.push_back(std::make_pair(test_case->name(), test_info->name()));
+    }
+  }
+  return tests;
+}
+
+bool WriteCompiledInTestsToFile(const FilePath& path) {
+  std::vector<SplitTestName> tests(GetCompiledInTests());
+
+  ListValue root;
+  for (size_t i = 0; i < tests.size(); ++i) {
+    DictionaryValue* test_info = new DictionaryValue;
+    test_info->SetString("test_case_name", tests[i].first);
+    test_info->SetString("test_name", tests[i].second);
+    root.Append(test_info);
+  }
+
+  JSONFileValueSerializer serializer(path);
+  return serializer.Serialize(root);
+}
+
+bool ReadTestNamesFromFile(const FilePath& path,
+                           std::vector<SplitTestName>* output) {
+  JSONFileValueDeserializer deserializer(path);
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<base::Value> value(
+      deserializer.Deserialize(&error_code, &error_message));
+  if (!value.get())
+    return false;
+
+  base::ListValue* tests = nullptr;
+  if (!value->GetAsList(&tests))
+    return false;
+
+  std::vector<base::SplitTestName> result;
+  for (base::ListValue::iterator i = tests->begin(); i != tests->end(); ++i) {
+    base::DictionaryValue* test = nullptr;
+    if (!(*i)->GetAsDictionary(&test))
+      return false;
+
+    std::string test_case_name;
+    if (!test->GetStringASCII("test_case_name", &test_case_name))
+      return false;
+
+    std::string test_name;
+    if (!test->GetStringASCII("test_name", &test_name))
+      return false;
+
+    result.push_back(std::make_pair(test_case_name, test_name));
+  }
+
+  output->swap(result);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/gtest_util.h b/base/test/gtest_util.h
new file mode 100644
index 0000000..77cc924
--- /dev/null
+++ b/base/test/gtest_util.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_UTIL_H_
+#define BASE_TEST_GTEST_UTIL_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class FilePath;
+
+// First value is test case name, second one is test name.
+typedef std::pair<std::string, std::string> SplitTestName;
+
+// Constructs a full test name given a test case name and a test name,
+// e.g. for test case "A" and test name "B" returns "A.B".
+std::string FormatFullTestName(const std::string& test_case_name,
+                               const std::string& test_name);
+
+// Returns a vector of gtest-based tests compiled into
+// current executable.
+std::vector<SplitTestName> GetCompiledInTests();
+
+// Writes the list of gtest-based tests compiled into
+// current executable as a JSON file. Returns true on success.
+bool WriteCompiledInTestsToFile(const FilePath& path) WARN_UNUSED_RESULT;
+
+// Reads the list of gtest-based tests from |path| into |output|.
+// Returns true on success.
+bool ReadTestNamesFromFile(
+    const FilePath& path,
+    std::vector<SplitTestName>* output) WARN_UNUSED_RESULT;
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_UTIL_H_
diff --git a/base/test/gtest_xml_util.cc b/base/test/gtest_xml_util.cc
new file mode 100644
index 0000000..db8cc2d
--- /dev/null
+++ b/base/test/gtest_xml_util.cc
@@ -0,0 +1,229 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_xml_util.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/gtest_util.h"
+#include "base/test/launcher/test_launcher.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
+
+namespace base {
+
+namespace {
+
+// This is used for the xml parser to report errors. This assumes the context
+// is a pointer to a std::string where the error message should be appended.
+static void XmlErrorFunc(void *context, const char *message, ...) {
+  va_list args;
+  va_start(args, message);
+  std::string* error = static_cast<std::string*>(context);
+  base::StringAppendV(error, message, args);
+  va_end(args);
+}
+
+}  // namespace
+
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter() : output_file_(NULL) {
+}
+
+XmlUnitTestResultPrinter::~XmlUnitTestResultPrinter() {
+  if (output_file_) {
+    fprintf(output_file_, "</testsuites>\n");
+    fflush(output_file_);
+    base::CloseFile(output_file_);
+  }
+}
+
+bool XmlUnitTestResultPrinter::Initialize(const FilePath& output_file_path) {
+  DCHECK(!output_file_);
+  output_file_ = OpenFile(output_file_path, "w");
+  if (!output_file_)
+    return false;
+
+  fprintf(output_file_,
+          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n");
+  fflush(output_file_);
+
+  return true;
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseStart(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  <testsuite>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestStart(const testing::TestInfo& test_info) {
+  // This is our custom extension - it helps to recognize which test was running
+  // when the test binary crashed. Note that we cannot even open the <testcase>
+  // tag here - it requires e.g. run time of the test to be known.
+  fprintf(output_file_,
+          "    <x-teststart name=\"%s\" classname=\"%s\" />\n",
+          test_info.name(),
+          test_info.test_case_name());
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestEnd(const testing::TestInfo& test_info) {
+  fprintf(output_file_,
+          "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+          " classname=\"%s\">\n",
+          test_info.name(),
+          static_cast<double>(test_info.result()->elapsed_time()) /
+              Time::kMillisecondsPerSecond,
+          test_info.test_case_name());
+  if (test_info.result()->Failed())
+    fprintf(output_file_, "      <failure message=\"\" type=\"\"></failure>\n");
+  fprintf(output_file_, "    </testcase>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseEnd(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  </testsuite>\n");
+  fflush(output_file_);
+}
+
+bool ProcessGTestOutput(const base::FilePath& output_file,
+                        std::vector<TestResult>* results,
+                        bool* crashed) {
+  DCHECK(results);
+
+  std::string xml_contents;
+  if (!ReadFileToString(output_file, &xml_contents))
+    return false;
+
+  // Silence XML errors - otherwise they go to stderr.
+  std::string xml_errors;
+  ScopedXmlErrorFunc error_func(&xml_errors, &XmlErrorFunc);
+
+  XmlReader xml_reader;
+  if (!xml_reader.Load(xml_contents))
+    return false;
+
+  enum {
+    STATE_INIT,
+    STATE_TESTSUITE,
+    STATE_TESTCASE,
+    STATE_FAILURE,
+    STATE_END,
+  } state = STATE_INIT;
+
+  while (xml_reader.Read()) {
+    xml_reader.SkipToElement();
+    std::string node_name(xml_reader.NodeName());
+
+    switch (state) {
+      case STATE_INIT:
+        if (node_name == "testsuites" && !xml_reader.IsClosingElement())
+          state = STATE_TESTSUITE;
+        else
+          return false;
+        break;
+      case STATE_TESTSUITE:
+        if (node_name == "testsuites" && xml_reader.IsClosingElement())
+          state = STATE_END;
+        else if (node_name == "testsuite" && !xml_reader.IsClosingElement())
+          state = STATE_TESTCASE;
+        else
+          return false;
+        break;
+      case STATE_TESTCASE:
+        if (node_name == "testsuite" && xml_reader.IsClosingElement()) {
+          state = STATE_TESTSUITE;
+        } else if (node_name == "x-teststart" &&
+                   !xml_reader.IsClosingElement()) {
+          // This is our custom extension that helps recognize which test was
+          // running when the test binary crashed.
+          TestResult result;
+
+          std::string test_case_name;
+          if (!xml_reader.NodeAttribute("classname", &test_case_name))
+            return false;
+          std::string test_name;
+          if (!xml_reader.NodeAttribute("name", &test_name))
+            return false;
+          result.full_name = FormatFullTestName(test_case_name, test_name);
+
+          result.elapsed_time = TimeDelta();
+
+          // Assume the test crashed - we can correct that later.
+          result.status = TestResult::TEST_CRASH;
+
+          results->push_back(result);
+        } else if (node_name == "testcase" && !xml_reader.IsClosingElement()) {
+          std::string test_status;
+          if (!xml_reader.NodeAttribute("status", &test_status))
+            return false;
+
+          if (test_status != "run" && test_status != "notrun")
+            return false;
+          if (test_status != "run")
+            break;
+
+          TestResult result;
+
+          std::string test_case_name;
+          if (!xml_reader.NodeAttribute("classname", &test_case_name))
+            return false;
+          std::string test_name;
+          if (!xml_reader.NodeAttribute("name", &test_name))
+            return false;
+          result.full_name = test_case_name + "." + test_name;
+
+          std::string test_time_str;
+          if (!xml_reader.NodeAttribute("time", &test_time_str))
+            return false;
+          result.elapsed_time = TimeDelta::FromMicroseconds(
+              static_cast<int64>(strtod(test_time_str.c_str(), NULL) *
+                  Time::kMicrosecondsPerSecond));
+
+          result.status = TestResult::TEST_SUCCESS;
+
+          if (!results->empty() &&
+              results->at(results->size() - 1).full_name == result.full_name &&
+              results->at(results->size() - 1).status ==
+                  TestResult::TEST_CRASH) {
+            // Erase the fail-safe "crashed" result - now we know the test did
+            // not crash.
+            results->pop_back();
+          }
+
+          results->push_back(result);
+        } else if (node_name == "failure" && !xml_reader.IsClosingElement()) {
+          std::string failure_message;
+          if (!xml_reader.NodeAttribute("message", &failure_message))
+            return false;
+
+          DCHECK(!results->empty());
+          results->at(results->size() - 1).status = TestResult::TEST_FAILURE;
+
+          state = STATE_FAILURE;
+        } else if (node_name == "testcase" && xml_reader.IsClosingElement()) {
+          // Deliberately empty.
+        } else {
+          return false;
+        }
+        break;
+      case STATE_FAILURE:
+        if (node_name == "failure" && xml_reader.IsClosingElement())
+          state = STATE_TESTCASE;
+        else
+          return false;
+        break;
+      case STATE_END:
+        // If we are here and there are still XML elements, the file has wrong
+        // format.
+        return false;
+    }
+  }
+
+  *crashed = (state != STATE_END);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/gtest_xml_util.h b/base/test/gtest_xml_util.h
new file mode 100644
index 0000000..9ff2406
--- /dev/null
+++ b/base/test/gtest_xml_util.h
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_XML_UTIL_H_
+#define BASE_TEST_GTEST_XML_UTIL_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FilePath;
+struct TestResult;
+
+// Generates an XML output file. Format is very close to GTest, but has
+// extensions needed by the test launcher.
+class XmlUnitTestResultPrinter : public testing::EmptyTestEventListener {
+ public:
+  XmlUnitTestResultPrinter();
+  ~XmlUnitTestResultPrinter() override;
+
+  // Must be called before adding as a listener. Returns true on success.
+  bool Initialize(const FilePath& output_file_path) WARN_UNUSED_RESULT;
+
+ private:
+  // testing::EmptyTestEventListener:
+  void OnTestCaseStart(const testing::TestCase& test_case) override;
+  void OnTestStart(const testing::TestInfo& test_info) override;
+  void OnTestEnd(const testing::TestInfo& test_info) override;
+  void OnTestCaseEnd(const testing::TestCase& test_case) override;
+
+  FILE* output_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
+};
+
+// Produces a vector of test results based on GTest output file.
+// Returns true iff the output file exists and has been successfully parsed.
+// On successful return |crashed| is set to true if the test results
+// are valid but incomplete.
+bool ProcessGTestOutput(const base::FilePath& output_file,
+                        std::vector<TestResult>* results,
+                        bool* crashed) WARN_UNUSED_RESULT;
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_XML_UTIL_H_
diff --git a/base/test/histogram_tester.cc b/base/test/histogram_tester.cc
new file mode 100644
index 0000000..ea738b0
--- /dev/null
+++ b/base/test/histogram_tester.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/histogram_tester.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+HistogramTester::HistogramTester() {
+  StatisticsRecorder::Initialize();  // Safe to call multiple times.
+
+  // Record any histogram data that exists when the object is created so it can
+  // be subtracted later.
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetSnapshot(std::string(), &histograms);
+  for (size_t i = 0; i < histograms.size(); ++i) {
+    histograms_snapshot_[histograms[i]->histogram_name()] =
+        histograms[i]->SnapshotSamples().release();
+  }
+}
+
+HistogramTester::~HistogramTester() {
+  STLDeleteValues(&histograms_snapshot_);
+}
+
+void HistogramTester::ExpectUniqueSample(
+    const std::string& name,
+    base::HistogramBase::Sample sample,
+    base::HistogramBase::Count expected_count) const {
+  base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(name);
+  EXPECT_NE(static_cast<base::HistogramBase*>(NULL), histogram)
+      << "Histogram \"" << name << "\" does not exist.";
+
+  if (histogram) {
+    scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
+    CheckBucketCount(name, sample, expected_count, *samples);
+    CheckTotalCount(name, expected_count, *samples);
+  }
+}
+
+void HistogramTester::ExpectBucketCount(
+    const std::string& name,
+    base::HistogramBase::Sample sample,
+    base::HistogramBase::Count expected_count) const {
+  base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(name);
+  EXPECT_NE(static_cast<base::HistogramBase*>(NULL), histogram)
+      << "Histogram \"" << name << "\" does not exist.";
+
+  if (histogram) {
+    scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
+    CheckBucketCount(name, sample, expected_count, *samples);
+  }
+}
+
+void HistogramTester::ExpectTotalCount(const std::string& name,
+                                       base::HistogramBase::Count count) const {
+  base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(name);
+  if (histogram) {
+    scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
+    CheckTotalCount(name, count, *samples);
+  } else {
+    // No histogram means there were zero samples.
+    EXPECT_EQ(count, 0) << "Histogram \"" << name << "\" does not exist.";
+  }
+}
+
+scoped_ptr<HistogramSamples> HistogramTester::GetHistogramSamplesSinceCreation(
+    const std::string& histogram_name) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(histogram_name);
+  if (!histogram)
+    return scoped_ptr<HistogramSamples>();
+  scoped_ptr<HistogramSamples> named_samples(histogram->SnapshotSamples());
+  HistogramSamples* named_original_samples =
+      histograms_snapshot_[histogram_name];
+  if (named_original_samples)
+    named_samples->Subtract(*named_original_samples);
+  return named_samples.Pass();
+}
+
+void HistogramTester::CheckBucketCount(
+    const std::string& name,
+    base::HistogramBase::Sample sample,
+    base::HistogramBase::Count expected_count,
+    const base::HistogramSamples& samples) const {
+  int actual_count = samples.GetCount(sample);
+  std::map<std::string, HistogramSamples*>::const_iterator histogram_data;
+  histogram_data = histograms_snapshot_.find(name);
+  if (histogram_data != histograms_snapshot_.end())
+    actual_count -= histogram_data->second->GetCount(sample);
+
+  EXPECT_EQ(expected_count, actual_count)
+      << "Histogram \"" << name
+      << "\" does not have the right number of samples (" << expected_count
+      << ") in the expected bucket (" << sample << "). It has (" << actual_count
+      << ").";
+}
+
+void HistogramTester::CheckTotalCount(
+    const std::string& name,
+    base::HistogramBase::Count expected_count,
+    const base::HistogramSamples& samples) const {
+  int actual_count = samples.TotalCount();
+  std::map<std::string, HistogramSamples*>::const_iterator histogram_data;
+  histogram_data = histograms_snapshot_.find(name);
+  if (histogram_data != histograms_snapshot_.end())
+    actual_count -= histogram_data->second->TotalCount();
+
+  EXPECT_EQ(expected_count, actual_count)
+      << "Histogram \"" << name
+      << "\" does not have the right total number of samples ("
+      << expected_count << "). It has (" << actual_count << ").";
+}
+
+}  // namespace base
diff --git a/base/test/histogram_tester.h b/base/test/histogram_tester.h
new file mode 100644
index 0000000..96317f9
--- /dev/null
+++ b/base/test/histogram_tester.h
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_HISTOGRAM_TESTER_H_
+#define BASE_TEST_HISTOGRAM_TESTER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class HistogramSamples;
+
+// HistogramTester provides a simple interface for examining histograms, UMA
+// or otherwise. Tests can use this interface to verify that histogram data is
+// getting logged as intended.
+class HistogramTester {
+ public:
+  // The constructor will call StatisticsRecorder::Initialize() for you. Also,
+  // this takes a snapshot of all current histograms counts.
+  HistogramTester();
+  ~HistogramTester();
+
+  // We know the exact number of samples in a bucket, and that no other bucket
+  // should have samples. Measures the diff from the snapshot taken when this
+  // object was constructed.
+  void ExpectUniqueSample(const std::string& name,
+                          base::HistogramBase::Sample sample,
+                          base::HistogramBase::Count expected_count) const;
+
+  // We know the exact number of samples in a bucket, but other buckets may
+  // have samples as well. Measures the diff from the snapshot taken when this
+  // object was constructed.
+  void ExpectBucketCount(const std::string& name,
+                         base::HistogramBase::Sample sample,
+                         base::HistogramBase::Count expected_count) const;
+
+  // We don't know the values of the samples, but we know how many there are.
+  // This measures the diff from the snapshot taken when this object was
+  // constructed.
+  void ExpectTotalCount(const std::string& name,
+                        base::HistogramBase::Count count) const;
+
+  // Access a modified HistogramSamples containing only what has been logged
+  // to the histogram since the creation of this object.
+  scoped_ptr<HistogramSamples> GetHistogramSamplesSinceCreation(
+      const std::string& histogram_name);
+
+ private:
+  // Verifies and asserts that value in the |sample| bucket matches the
+  // |expected_count|. The bucket's current value is determined from |samples|
+  // and is modified based on the snapshot stored for histogram |name|.
+  void CheckBucketCount(const std::string& name,
+                        base::HistogramBase::Sample sample,
+                        base::Histogram::Count expected_count,
+                        const base::HistogramSamples& samples) const;
+
+  // Verifies that the total number of values recorded for the histogram |name|
+  // is |expected_count|. This is checked against |samples| minus the snapshot
+  // that was taken for |name|.
+  void CheckTotalCount(const std::string& name,
+                       base::Histogram::Count expected_count,
+                       const base::HistogramSamples& samples) const;
+
+  // Used to determine the histogram changes made during this instance's
+  // lifecycle. This instance takes ownership of the samples, which are deleted
+  // when the instance is destroyed.
+  std::map<std::string, HistogramSamples*> histograms_snapshot_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramTester);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_HISTOGRAM_TESTER_H_
diff --git a/base/test/histogram_tester_unittest.cc b/base/test/histogram_tester_unittest.cc
new file mode 100644
index 0000000..a03ee13
--- /dev/null
+++ b/base/test/histogram_tester_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/histogram_tester.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+const std::string kHistogram1 = "Test1";
+const std::string kHistogram2 = "Test2";
+const std::string kHistogram3 = "Test3";
+const std::string kHistogram4 = "Test4";
+
+typedef testing::Test HistogramTesterTest;
+
+TEST_F(HistogramTesterTest, Scope) {
+  // Record a histogram before the creation of the recorder.
+  UMA_HISTOGRAM_BOOLEAN(kHistogram1, true);
+
+  HistogramTester tester;
+
+  // Verify that no histogram is recorded.
+  scoped_ptr<HistogramSamples> samples(
+      tester.GetHistogramSamplesSinceCreation(kHistogram1));
+  EXPECT_FALSE(samples);
+
+  // Record a histogram after the creation of the recorder.
+  UMA_HISTOGRAM_BOOLEAN(kHistogram1, true);
+
+  // Verify that one histogram is recorded.
+  samples = tester.GetHistogramSamplesSinceCreation(kHistogram1);
+  EXPECT_TRUE(samples);
+  EXPECT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(HistogramTesterTest, TestUniqueSample) {
+  HistogramTester tester;
+
+  // Record into a sample thrice
+  UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2);
+
+  tester.ExpectUniqueSample(kHistogram2, 2, 3);
+}
+
+TEST_F(HistogramTesterTest, TestBucketsSample) {
+  HistogramTester tester;
+
+  // Record into a sample twice
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 3);
+
+  tester.ExpectBucketCount(kHistogram3, 2, 4);
+  tester.ExpectBucketCount(kHistogram3, 3, 1);
+
+  tester.ExpectTotalCount(kHistogram3, 5);
+}
+
+TEST_F(HistogramTesterTest, TestBucketsSampleWithScope) {
+  // Record into a sample twice, once before the tester creation and once after.
+  UMA_HISTOGRAM_COUNTS_100(kHistogram4, 2);
+
+  HistogramTester tester;
+  UMA_HISTOGRAM_COUNTS_100(kHistogram4, 3);
+
+  tester.ExpectBucketCount(kHistogram4, 2, 0);
+  tester.ExpectBucketCount(kHistogram4, 3, 1);
+
+  tester.ExpectTotalCount(kHistogram4, 1);
+}
+
+}  // namespace base
diff --git a/base/test/ios/OWNERS b/base/test/ios/OWNERS
new file mode 100644
index 0000000..1b3348e
--- /dev/null
+++ b/base/test/ios/OWNERS
@@ -0,0 +1,2 @@
+rohitrao@chromium.org
+stuartmorgan@chromium.org
diff --git a/base/test/ios/wait_util.h b/base/test/ios/wait_util.h
new file mode 100644
index 0000000..01c6fe7
--- /dev/null
+++ b/base/test/ios/wait_util.h
@@ -0,0 +1,49 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_IOS_WAIT_UTIL_H_
+#define BASE_TEST_IOS_WAIT_UTIL_H_
+
+#include "base/ios/block_types.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class MessageLoop;
+
+namespace test {
+namespace ios {
+
+// Returns the time spent in running |action| plus waiting until |condition| is
+// met.
+// Performs |action| and then spins run loop and runs the |message_loop| until
+// |condition| block returns true.
+// |action| may be nil if no action needs to be performed before the wait loop.
+// |message_loop| can be null if there is no need to spin the message loop.
+// |condition| may be nil if there is no condition to wait for: the run loop
+// will spin until timeout is reached.
+// |timeout| parameter sets the maximum wait time. If |timeout| is zero,
+// a reasonable default will be used.
+TimeDelta TimeUntilCondition(ProceduralBlock action,
+                             ConditionBlock condition,
+                             MessageLoop* message_loop,
+                             TimeDelta timeout);
+
+// Waits until |condition| is met. A |message_loop| to spin and a |timeout| can
+// be optionally passed; if |timeout| is zero, a reasonable default will be
+// used.
+void WaitUntilCondition(ConditionBlock condition,
+                        MessageLoop* message_loop,
+                        TimeDelta timeout);
+void WaitUntilCondition(ConditionBlock condition);
+
+// Lets the run loop of the current thread process other messages
+// within the given maximum delay.
+void SpinRunLoopWithMaxDelay(TimeDelta max_delay);
+
+}  // namespace ios
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_IOS_WAIT_UTIL_H_
diff --git a/base/test/ios/wait_util.mm b/base/test/ios/wait_util.mm
new file mode 100644
index 0000000..e8b3a0f
--- /dev/null
+++ b/base/test/ios/wait_util.mm
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/test/ios/wait_util.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+namespace test {
+namespace ios {
+
+TimeDelta TimeUntilCondition(ProceduralBlock action,
+                             ConditionBlock condition,
+                             MessageLoop* message_loop,
+                             TimeDelta timeout) {
+  ElapsedTimer timer;
+  if (action)
+    action();
+  if (timeout == TimeDelta())
+    timeout = TestTimeouts::action_timeout();
+  const TimeDelta spin_delay(TimeDelta::FromMilliseconds(10));
+  while (timer.Elapsed() < timeout && (!condition || !condition())) {
+    SpinRunLoopWithMaxDelay(spin_delay);
+    if (message_loop) {
+      message_loop->RunUntilIdle();
+    }
+  }
+  TimeDelta elapsed = timer.Elapsed();
+  // If DCHECK is ever hit, check if |action| is doing something that is
+  // taking an unreasonably long time, or if |condition| does not come
+  // true quickly enough. Increase |timeout| only if necessary.
+  DCHECK(!condition || condition());
+  return elapsed;
+}
+
+void WaitUntilCondition(ConditionBlock condition,
+                        MessageLoop* message_loop,
+                        TimeDelta timeout) {
+  TimeUntilCondition(nil, condition, message_loop, timeout);
+}
+
+void WaitUntilCondition(ConditionBlock condition) {
+  WaitUntilCondition(condition, nullptr, TimeDelta());
+}
+
+void SpinRunLoopWithMaxDelay(TimeDelta max_delay) {
+  scoped_nsobject<NSDate> beforeDate(
+      [[NSDate alloc] initWithTimeIntervalSinceNow:max_delay.InSecondsF()]);
+  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+                           beforeDate:beforeDate];
+}
+
+}  // namespace ios
+}  // namespace test
+}  // namespace base
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
new file mode 100644
index 0000000..7f258f5
--- /dev/null
+++ b/base/test/launcher/test_launcher.cc
@@ -0,0 +1,1079 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_launcher.h"
+
+#if defined(OS_POSIX)
+#include <fcntl.h>
+#endif
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/format_macros.h"
+#include "base/hash.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringize_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/gtest_util.h"
+#include "base/test/launcher/test_results_tracker.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+namespace base {
+
+// See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/uT3FaE_sgkAJ .
+using ::operator<<;
+
+// The environment variable name for the total number of test shards.
+const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard index.
+const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+
+namespace {
+
+// Global tag for test runs where the results are incomplete or unreliable
+// for any reason, e.g. early exit because of too many broken tests.
+const char kUnreliableResultsTag[] = "UNRELIABLE_RESULTS";
+
+// Maximum time of no output after which we print list of processes still
+// running. This deliberately doesn't use TestTimeouts (which is otherwise
+// a recommended solution), because they can be increased. This would defeat
+// the purpose of this timeout, which is 1) to avoid buildbot "no output for
+// X seconds" timeout killing the process 2) help communicate status of
+// the test launcher to people looking at the output (no output for a long
+// time is mysterious and gives no info about what is happening) 3) help
+// debugging in case the process hangs anyway.
+const int kOutputTimeoutSeconds = 15;
+
+// Limit of output snippet lines when printing to stdout.
+// Avoids flooding the logs with amount of output that gums up
+// the infrastructure.
+const size_t kOutputSnippetLinesLimit = 5000;
+
+// Set of live launch test processes with corresponding lock (it is allowed
+// for callers to launch processes on different threads).
+LazyInstance<std::map<ProcessHandle, CommandLine> > g_live_processes
+    = LAZY_INSTANCE_INITIALIZER;
+LazyInstance<Lock> g_live_processes_lock = LAZY_INSTANCE_INITIALIZER;
+
+#if defined(OS_POSIX)
+// Self-pipe that makes it possible to do complex shutdown handling
+// outside of the signal handler.
+int g_shutdown_pipe[2] = { -1, -1 };
+
+void ShutdownPipeSignalHandler(int signal) {
+  HANDLE_EINTR(write(g_shutdown_pipe[1], "q", 1));
+}
+
+void KillSpawnedTestProcesses() {
+  // Keep the lock until exiting the process to prevent further processes
+  // from being spawned.
+  AutoLock lock(g_live_processes_lock.Get());
+
+  fprintf(stdout,
+          "Sending SIGTERM to %" PRIuS " child processes... ",
+          g_live_processes.Get().size());
+  fflush(stdout);
+
+  for (std::map<ProcessHandle, CommandLine>::iterator i =
+           g_live_processes.Get().begin();
+       i != g_live_processes.Get().end();
+       ++i) {
+    // Send the signal to entire process group.
+    kill((-1) * (i->first), SIGTERM);
+  }
+
+  fprintf(stdout,
+          "done.\nGiving processes a chance to terminate cleanly... ");
+  fflush(stdout);
+
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+
+  fprintf(stdout, "done.\n");
+  fflush(stdout);
+
+  fprintf(stdout,
+          "Sending SIGKILL to %" PRIuS " child processes... ",
+          g_live_processes.Get().size());
+  fflush(stdout);
+
+  for (std::map<ProcessHandle, CommandLine>::iterator i =
+           g_live_processes.Get().begin();
+       i != g_live_processes.Get().end();
+       ++i) {
+    // Send the signal to entire process group.
+    kill((-1) * (i->first), SIGKILL);
+  }
+
+  fprintf(stdout, "done.\n");
+  fflush(stdout);
+}
+
+// I/O watcher for the reading end of the self-pipe above.
+// Terminates any launched child processes and exits the process.
+class SignalFDWatcher : public MessageLoopForIO::Watcher {
+ public:
+  SignalFDWatcher() {
+  }
+
+  void OnFileCanReadWithoutBlocking(int fd) override {
+    fprintf(stdout, "\nCaught signal. Killing spawned test processes...\n");
+    fflush(stdout);
+
+    KillSpawnedTestProcesses();
+
+    // The signal would normally kill the process, so exit now.
+    _exit(1);
+  }
+
+  void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SignalFDWatcher);
+};
+#endif  // defined(OS_POSIX)
+
+// Parses the environment variable var as an Int32.  If it is unset, returns
+// true.  If it is set, unsets it then converts it to Int32 before
+// returning it in |result|.  Returns true on success.
+bool TakeInt32FromEnvironment(const char* const var, int32* result) {
+  scoped_ptr<Environment> env(Environment::Create());
+  std::string str_val;
+
+  if (!env->GetVar(var, &str_val))
+    return true;
+
+  if (!env->UnSetVar(var)) {
+    LOG(ERROR) << "Invalid environment: we could not unset " << var << ".\n";
+    return false;
+  }
+
+  if (!StringToInt(str_val, result)) {
+    LOG(ERROR) << "Invalid environment: " << var << " is not an integer.\n";
+    return false;
+  }
+
+  return true;
+}
+
+// Unsets the environment variable |name| and returns true on success.
+// Also returns true if the variable just doesn't exist.
+bool UnsetEnvironmentVariableIfExists(const std::string& name) {
+  scoped_ptr<Environment> env(Environment::Create());
+  std::string str_val;
+
+  if (!env->GetVar(name.c_str(), &str_val))
+    return true;
+
+  return env->UnSetVar(name.c_str());
+}
+
+// Returns true if bot mode has been requested, i.e. defaults optimized
+// for continuous integration bots. This way developers don't have to remember
+// special command-line flags.
+bool BotModeEnabled() {
+  scoped_ptr<Environment> env(Environment::Create());
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kTestLauncherBotMode) ||
+      env->HasVar("CHROMIUM_TEST_LAUNCHER_BOT_MODE");
+}
+
+// Returns command line command line after gtest-specific processing
+// and applying |wrapper|.
+CommandLine PrepareCommandLineForGTest(const CommandLine& command_line,
+                                       const std::string& wrapper) {
+  CommandLine new_command_line(command_line.GetProgram());
+  CommandLine::SwitchMap switches = command_line.GetSwitches();
+
+  // Strip out gtest_repeat flag - this is handled by the launcher process.
+  switches.erase(kGTestRepeatFlag);
+
+  // Don't try to write the final XML report in child processes.
+  switches.erase(kGTestOutputFlag);
+
+  for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
+       iter != switches.end(); ++iter) {
+    new_command_line.AppendSwitchNative((*iter).first, (*iter).second);
+  }
+
+  // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine
+  // does not really support removing switches well, and trying to do that
+  // on a CommandLine with a wrapper is known to break.
+  // TODO(phajdan.jr): Give it a try to support CommandLine removing switches.
+#if defined(OS_WIN)
+  new_command_line.PrependWrapper(ASCIIToUTF16(wrapper));
+#elif defined(OS_POSIX)
+  new_command_line.PrependWrapper(wrapper);
+#endif
+
+  return new_command_line;
+}
+
+// Launches a child process using |command_line|. If the child process is still
+// running after |timeout|, it is terminated and |*was_timeout| is set to true.
+// Returns exit code of the process.
+int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
+                                      const LaunchOptions& options,
+                                      int flags,
+                                      TimeDelta timeout,
+                                      bool* was_timeout) {
+#if defined(OS_POSIX)
+  // Make sure an option we rely on is present - see LaunchChildGTestProcess.
+  DCHECK(options.new_process_group);
+#endif
+
+  LaunchOptions new_options(options);
+
+#if defined(OS_WIN)
+  DCHECK(!new_options.job_handle);
+
+  win::ScopedHandle job_handle;
+  if (flags & TestLauncher::USE_JOB_OBJECTS) {
+    job_handle.Set(CreateJobObject(NULL, NULL));
+    if (!job_handle.IsValid()) {
+      LOG(ERROR) << "Could not create JobObject.";
+      return -1;
+    }
+
+    DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+    // Allow break-away from job since sandbox and few other places rely on it
+    // on Windows versions prior to Windows 8 (which supports nested jobs).
+    if (win::GetVersion() < win::VERSION_WIN8 &&
+        flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) {
+      job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
+    }
+
+    if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) {
+      LOG(ERROR) << "Could not SetJobObjectLimitFlags.";
+      return -1;
+    }
+
+    new_options.job_handle = job_handle.Get();
+  }
+#endif  // defined(OS_WIN)
+
+#if defined(OS_LINUX)
+  // To prevent accidental privilege sharing to an untrusted child, processes
+  // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this
+  // new child will be privileged and trusted.
+  new_options.allow_new_privs = true;
+#endif
+
+  Process process;
+
+  {
+    // Note how we grab the lock before the process possibly gets created.
+    // This ensures that when the lock is held, ALL the processes are registered
+    // in the set.
+    AutoLock lock(g_live_processes_lock.Get());
+
+    process = LaunchProcess(command_line, new_options);
+    if (!process.IsValid())
+      return -1;
+
+    // TODO(rvargas) crbug.com/417532: Don't store process handles.
+    g_live_processes.Get().insert(std::make_pair(process.Handle(),
+                                                 command_line));
+  }
+
+  int exit_code = 0;
+  if (!process.WaitForExitWithTimeout(timeout, &exit_code)) {
+    *was_timeout = true;
+    exit_code = -1;  // Set a non-zero exit code to signal a failure.
+
+    // Ensure that the process terminates.
+    process.Terminate(-1, true);
+  }
+
+  {
+    // Note how we grab the log before issuing a possibly broad process kill.
+    // Other code parts that grab the log kill processes, so avoid trying
+    // to do that twice and trigger all kinds of log messages.
+    AutoLock lock(g_live_processes_lock.Get());
+
+#if defined(OS_POSIX)
+    if (exit_code != 0) {
+      // On POSIX, in case the test does not exit cleanly, either due to a crash
+      // or due to it timing out, we need to clean up any child processes that
+      // it might have created. On Windows, child processes are automatically
+      // cleaned up using JobObjects.
+      KillProcessGroup(process.Handle());
+    }
+#endif
+
+    g_live_processes.Get().erase(process.Handle());
+  }
+
+  return exit_code;
+}
+
+void RunCallback(
+    const TestLauncher::LaunchChildGTestProcessCallback& callback,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  callback.Run(exit_code, elapsed_time, was_timeout, output);
+}
+
+void DoLaunchChildTestProcess(
+    const CommandLine& command_line,
+    TimeDelta timeout,
+    int flags,
+    bool redirect_stdio,
+    SingleThreadTaskRunner* task_runner,
+    const TestLauncher::LaunchChildGTestProcessCallback& callback) {
+  TimeTicks start_time = TimeTicks::Now();
+
+  // Redirect child process output to a file.
+  FilePath output_file;
+  CHECK(CreateTemporaryFile(&output_file));
+
+  LaunchOptions options;
+#if defined(OS_WIN)
+  win::ScopedHandle handle;
+
+  if (redirect_stdio) {
+    // Make the file handle inheritable by the child.
+    SECURITY_ATTRIBUTES sa_attr;
+    sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    sa_attr.lpSecurityDescriptor = NULL;
+    sa_attr.bInheritHandle = TRUE;
+
+    handle.Set(CreateFile(output_file.value().c_str(),
+                          GENERIC_WRITE,
+                          FILE_SHARE_READ | FILE_SHARE_DELETE,
+                          &sa_attr,
+                          OPEN_EXISTING,
+                          FILE_ATTRIBUTE_TEMPORARY,
+                          NULL));
+    CHECK(handle.IsValid());
+    options.inherit_handles = true;
+    options.stdin_handle = INVALID_HANDLE_VALUE;
+    options.stdout_handle = handle.Get();
+    options.stderr_handle = handle.Get();
+  }
+#elif defined(OS_POSIX)
+  options.new_process_group = true;
+#if defined(OS_LINUX)
+  options.kill_on_parent_death = true;
+#endif  // defined(OS_LINUX)
+
+  FileHandleMappingVector fds_mapping;
+  ScopedFD output_file_fd;
+
+  if (redirect_stdio) {
+    output_file_fd.reset(open(output_file.value().c_str(), O_RDWR));
+    CHECK(output_file_fd.is_valid());
+
+    fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO));
+    fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO));
+    options.fds_to_remap = &fds_mapping;
+  }
+#endif
+
+  bool was_timeout = false;
+  int exit_code = LaunchChildTestProcessWithOptions(
+      command_line, options, flags, timeout, &was_timeout);
+
+  if (redirect_stdio) {
+#if defined(OS_WIN)
+    FlushFileBuffers(handle.Get());
+    handle.Close();
+#elif defined(OS_POSIX)
+    output_file_fd.reset();
+#endif
+  }
+
+  std::string output_file_contents;
+  CHECK(ReadFileToString(output_file, &output_file_contents));
+
+  if (!DeleteFile(output_file, false)) {
+    // This needs to be non-fatal at least for Windows.
+    LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe();
+  }
+
+  // Run target callback on the thread it was originating from, not on
+  // a worker pool thread.
+  task_runner->PostTask(FROM_HERE, Bind(&RunCallback, callback, exit_code,
+                                        TimeTicks::Now() - start_time,
+                                        was_timeout, output_file_contents));
+}
+
+}  // namespace
+
+const char kGTestFilterFlag[] = "gtest_filter";
+const char kGTestHelpFlag[]   = "gtest_help";
+const char kGTestListTestsFlag[] = "gtest_list_tests";
+const char kGTestRepeatFlag[] = "gtest_repeat";
+const char kGTestRunDisabledTestsFlag[] = "gtest_also_run_disabled_tests";
+const char kGTestOutputFlag[] = "gtest_output";
+
+TestLauncherDelegate::~TestLauncherDelegate() {
+}
+
+TestLauncher::TestLauncher(TestLauncherDelegate* launcher_delegate,
+                           size_t parallel_jobs)
+    : launcher_delegate_(launcher_delegate),
+      total_shards_(1),
+      shard_index_(0),
+      cycles_(1),
+      test_started_count_(0),
+      test_finished_count_(0),
+      test_success_count_(0),
+      test_broken_count_(0),
+      retry_count_(0),
+      retry_limit_(0),
+      run_result_(true),
+      watchdog_timer_(FROM_HERE,
+                      TimeDelta::FromSeconds(kOutputTimeoutSeconds),
+                      this,
+                      &TestLauncher::OnOutputTimeout),
+      parallel_jobs_(parallel_jobs) {
+}
+
+TestLauncher::~TestLauncher() {
+  if (worker_pool_owner_)
+    worker_pool_owner_->pool()->Shutdown();
+}
+
+bool TestLauncher::Run() {
+  if (!Init())
+    return false;
+
+  // Value of |cycles_| changes after each iteration. Keep track of the
+  // original value.
+  int requested_cycles = cycles_;
+
+#if defined(OS_POSIX)
+  CHECK_EQ(0, pipe(g_shutdown_pipe));
+
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = &ShutdownPipeSignalHandler;
+
+  CHECK_EQ(0, sigaction(SIGINT, &action, NULL));
+  CHECK_EQ(0, sigaction(SIGQUIT, &action, NULL));
+  CHECK_EQ(0, sigaction(SIGTERM, &action, NULL));
+
+  MessageLoopForIO::FileDescriptorWatcher controller;
+  SignalFDWatcher watcher;
+
+  CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
+            g_shutdown_pipe[0],
+            true,
+            MessageLoopForIO::WATCH_READ,
+            &controller,
+            &watcher));
+#endif  // defined(OS_POSIX)
+
+  // Start the watchdog timer.
+  watchdog_timer_.Reset();
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+
+  MessageLoop::current()->Run();
+
+  if (requested_cycles != 1)
+    results_tracker_.PrintSummaryOfAllIterations();
+
+  MaybeSaveSummaryAsJSON();
+
+  return run_result_;
+}
+
+void TestLauncher::LaunchChildGTestProcess(
+    const CommandLine& command_line,
+    const std::string& wrapper,
+    TimeDelta timeout,
+    int flags,
+    const LaunchChildGTestProcessCallback& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Record the exact command line used to launch the child.
+  CommandLine new_command_line(
+      PrepareCommandLineForGTest(command_line, wrapper));
+
+  // When running in parallel mode we need to redirect stdio to avoid mixed-up
+  // output. We also always redirect on the bots to get the test output into
+  // JSON summary.
+  bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled();
+
+  worker_pool_owner_->pool()->PostWorkerTask(
+      FROM_HERE, Bind(&DoLaunchChildTestProcess, new_command_line, timeout,
+                      flags, redirect_stdio, ThreadTaskRunnerHandle::Get(),
+                      Bind(&TestLauncher::OnLaunchTestProcessFinished,
+                           Unretained(this), callback)));
+}
+
+void TestLauncher::OnTestFinished(const TestResult& result) {
+  ++test_finished_count_;
+
+  bool print_snippet = false;
+  std::string print_test_stdio("auto");
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherPrintTestStdio)) {
+    print_test_stdio = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+        switches::kTestLauncherPrintTestStdio);
+  }
+  if (print_test_stdio == "auto") {
+    print_snippet = (result.status != TestResult::TEST_SUCCESS);
+  } else if (print_test_stdio == "always") {
+    print_snippet = true;
+  } else if (print_test_stdio == "never") {
+    print_snippet = false;
+  } else {
+    LOG(WARNING) << "Invalid value of " << switches::kTestLauncherPrintTestStdio
+                 << ": " << print_test_stdio;
+  }
+  if (print_snippet) {
+    std::vector<std::string> snippet_lines;
+    SplitStringDontTrim(result.output_snippet, '\n', &snippet_lines);
+    if (snippet_lines.size() > kOutputSnippetLinesLimit) {
+      size_t truncated_size = snippet_lines.size() - kOutputSnippetLinesLimit;
+      snippet_lines.erase(
+          snippet_lines.begin(),
+          snippet_lines.begin() + truncated_size);
+      snippet_lines.insert(snippet_lines.begin(), "<truncated>");
+    }
+    fprintf(stdout, "%s", JoinString(snippet_lines, "\n").c_str());
+    fflush(stdout);
+  }
+
+  if (result.status == TestResult::TEST_SUCCESS) {
+    ++test_success_count_;
+  } else {
+    tests_to_retry_.insert(result.full_name);
+  }
+
+  results_tracker_.AddTestResult(result);
+
+  // TODO(phajdan.jr): Align counter (padding).
+  std::string status_line(
+      StringPrintf("[%" PRIuS "/%" PRIuS "] %s ",
+                   test_finished_count_,
+                   test_started_count_,
+                   result.full_name.c_str()));
+  if (result.completed()) {
+    status_line.append(StringPrintf("(%" PRId64 " ms)",
+                                    result.elapsed_time.InMilliseconds()));
+  } else if (result.status == TestResult::TEST_TIMEOUT) {
+    status_line.append("(TIMED OUT)");
+  } else if (result.status == TestResult::TEST_CRASH) {
+    status_line.append("(CRASHED)");
+  } else if (result.status == TestResult::TEST_SKIPPED) {
+    status_line.append("(SKIPPED)");
+  } else if (result.status == TestResult::TEST_UNKNOWN) {
+    status_line.append("(UNKNOWN)");
+  } else {
+    // Fail very loudly so it's not ignored.
+    CHECK(false) << "Unhandled test result status: " << result.status;
+  }
+  fprintf(stdout, "%s\n", status_line.c_str());
+  fflush(stdout);
+
+  // We just printed a status line, reset the watchdog timer.
+  watchdog_timer_.Reset();
+
+  // Do not waste time on timeouts. We include tests with unknown results here
+  // because sometimes (e.g. hang in between unit tests) that's how a timeout
+  // gets reported.
+  if (result.status == TestResult::TEST_TIMEOUT ||
+      result.status == TestResult::TEST_UNKNOWN) {
+    test_broken_count_++;
+  }
+  size_t broken_threshold =
+      std::max(static_cast<size_t>(20), test_started_count_ / 10);
+  if (test_broken_count_ >= broken_threshold) {
+    fprintf(stdout, "Too many badly broken tests (%" PRIuS "), exiting now.\n",
+            test_broken_count_);
+    fflush(stdout);
+
+#if defined(OS_POSIX)
+    KillSpawnedTestProcesses();
+#endif  // defined(OS_POSIX)
+
+    results_tracker_.AddGlobalTag("BROKEN_TEST_EARLY_EXIT");
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+    MaybeSaveSummaryAsJSON();
+
+    exit(1);
+  }
+
+  if (test_finished_count_ != test_started_count_)
+    return;
+
+  if (tests_to_retry_.empty() || retry_count_ >= retry_limit_) {
+    OnTestIterationFinished();
+    return;
+  }
+
+  if (tests_to_retry_.size() >= broken_threshold) {
+    fprintf(stdout,
+            "Too many failing tests (%" PRIuS "), skipping retries.\n",
+            tests_to_retry_.size());
+    fflush(stdout);
+
+    results_tracker_.AddGlobalTag("BROKEN_TEST_SKIPPED_RETRIES");
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+
+    OnTestIterationFinished();
+    return;
+  }
+
+  retry_count_++;
+
+  std::vector<std::string> test_names(tests_to_retry_.begin(),
+                                      tests_to_retry_.end());
+
+  tests_to_retry_.clear();
+
+  size_t retry_started_count = launcher_delegate_->RetryTests(this, test_names);
+  if (retry_started_count == 0) {
+    // Signal failure, but continue to run all requested test iterations.
+    // With the summary of all iterations at the end this is a good default.
+    run_result_ = false;
+
+    OnTestIterationFinished();
+    return;
+  }
+
+  fprintf(stdout, "Retrying %" PRIuS " test%s (retry #%" PRIuS ")\n",
+          retry_started_count,
+          retry_started_count > 1 ? "s" : "",
+          retry_count_);
+  fflush(stdout);
+
+  test_started_count_ += retry_started_count;
+}
+
+bool TestLauncher::Init() {
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+  // Initialize sharding. Command line takes precedence over legacy environment
+  // variables.
+  if (command_line->HasSwitch(switches::kTestLauncherTotalShards) &&
+      command_line->HasSwitch(switches::kTestLauncherShardIndex)) {
+    if (!StringToInt(
+            command_line->GetSwitchValueASCII(
+                switches::kTestLauncherTotalShards),
+            &total_shards_)) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherTotalShards;
+      return false;
+    }
+    if (!StringToInt(
+            command_line->GetSwitchValueASCII(
+                switches::kTestLauncherShardIndex),
+            &shard_index_)) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherShardIndex;
+      return false;
+    }
+    fprintf(stdout,
+            "Using sharding settings from command line. This is shard %d/%d\n",
+            shard_index_, total_shards_);
+    fflush(stdout);
+  } else {
+    if (!TakeInt32FromEnvironment(kTestTotalShards, &total_shards_))
+      return false;
+    if (!TakeInt32FromEnvironment(kTestShardIndex, &shard_index_))
+      return false;
+    fprintf(stdout,
+            "Using sharding settings from environment. This is shard %d/%d\n",
+            shard_index_, total_shards_);
+    fflush(stdout);
+  }
+  if (shard_index_ < 0 ||
+      total_shards_ < 0 ||
+      shard_index_ >= total_shards_) {
+    LOG(ERROR) << "Invalid sharding settings: we require 0 <= "
+               << kTestShardIndex << " < " << kTestTotalShards
+               << ", but you have " << kTestShardIndex << "=" << shard_index_
+               << ", " << kTestTotalShards << "=" << total_shards_ << ".\n";
+    return false;
+  }
+
+  // Make sure we don't pass any sharding-related environment to the child
+  // processes. This test launcher implements the sharding completely.
+  CHECK(UnsetEnvironmentVariableIfExists("GTEST_TOTAL_SHARDS"));
+  CHECK(UnsetEnvironmentVariableIfExists("GTEST_SHARD_INDEX"));
+
+  if (command_line->HasSwitch(kGTestRepeatFlag) &&
+      !StringToInt(command_line->GetSwitchValueASCII(kGTestRepeatFlag),
+                   &cycles_)) {
+    LOG(ERROR) << "Invalid value for " << kGTestRepeatFlag;
+    return false;
+  }
+
+  if (command_line->HasSwitch(switches::kTestLauncherRetryLimit)) {
+    int retry_limit = -1;
+    if (!StringToInt(command_line->GetSwitchValueASCII(
+                         switches::kTestLauncherRetryLimit), &retry_limit) ||
+        retry_limit < 0) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherRetryLimit;
+      return false;
+    }
+
+    retry_limit_ = retry_limit;
+  } else if (!command_line->HasSwitch(kGTestFilterFlag) || BotModeEnabled()) {
+    // Retry failures 3 times by default if we are running all of the tests or
+    // in bot mode.
+    retry_limit_ = 3;
+  }
+
+  if (command_line->HasSwitch(switches::kTestLauncherJobs)) {
+    int jobs = -1;
+    if (!StringToInt(command_line->GetSwitchValueASCII(
+                         switches::kTestLauncherJobs), &jobs) ||
+        jobs < 0) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherJobs;
+      return false;
+    }
+
+    parallel_jobs_ = jobs;
+  } else if (command_line->HasSwitch(kGTestFilterFlag) && !BotModeEnabled()) {
+    // Do not run jobs in parallel by default if we are running a subset of
+    // the tests and if bot mode is off.
+    parallel_jobs_ = 1;
+  }
+
+  fprintf(stdout, "Using %" PRIuS " parallel jobs.\n", parallel_jobs_);
+  fflush(stdout);
+  worker_pool_owner_.reset(
+      new SequencedWorkerPoolOwner(parallel_jobs_, "test_launcher"));
+
+  if (command_line->HasSwitch(switches::kTestLauncherFilterFile) &&
+      command_line->HasSwitch(kGTestFilterFlag)) {
+    LOG(ERROR) << "Only one of --test-launcher-filter-file and --gtest_filter "
+               << "at a time is allowed.";
+    return false;
+  }
+
+  if (command_line->HasSwitch(switches::kTestLauncherFilterFile)) {
+    std::string filter;
+    if (!ReadFileToString(
+            command_line->GetSwitchValuePath(switches::kTestLauncherFilterFile),
+            &filter)) {
+      LOG(ERROR) << "Failed to read the filter file.";
+      return false;
+    }
+
+    std::vector<std::string> filter_lines;
+    SplitString(filter, '\n', &filter_lines);
+    for (size_t i = 0; i < filter_lines.size(); i++) {
+      if (filter_lines[i].empty())
+        continue;
+
+      if (filter_lines[i][0] == '-')
+        negative_test_filter_.push_back(filter_lines[i].substr(1));
+      else
+        positive_test_filter_.push_back(filter_lines[i]);
+    }
+  } else {
+    // Split --gtest_filter at '-', if there is one, to separate into
+    // positive filter and negative filter portions.
+    std::string filter = command_line->GetSwitchValueASCII(kGTestFilterFlag);
+    size_t dash_pos = filter.find('-');
+    if (dash_pos == std::string::npos) {
+      SplitString(filter, ':', &positive_test_filter_);
+    } else {
+      // Everything up to the dash.
+      SplitString(filter.substr(0, dash_pos), ':', &positive_test_filter_);
+
+      // Everything after the dash.
+      SplitString(filter.substr(dash_pos + 1), ':', &negative_test_filter_);
+    }
+  }
+
+  if (!launcher_delegate_->GetTests(&tests_)) {
+    LOG(ERROR) << "Failed to get list of tests.";
+    return false;
+  }
+
+  if (!results_tracker_.Init(*command_line)) {
+    LOG(ERROR) << "Failed to initialize test results tracker.";
+    return 1;
+  }
+
+#if defined(NDEBUG)
+  results_tracker_.AddGlobalTag("MODE_RELEASE");
+#else
+  results_tracker_.AddGlobalTag("MODE_DEBUG");
+#endif
+
+  // Operating systems (sorted alphabetically).
+  // Note that they can deliberately overlap, e.g. OS_LINUX is a subset
+  // of OS_POSIX.
+#if defined(OS_ANDROID)
+  results_tracker_.AddGlobalTag("OS_ANDROID");
+#endif
+
+#if defined(OS_BSD)
+  results_tracker_.AddGlobalTag("OS_BSD");
+#endif
+
+#if defined(OS_FREEBSD)
+  results_tracker_.AddGlobalTag("OS_FREEBSD");
+#endif
+
+#if defined(OS_IOS)
+  results_tracker_.AddGlobalTag("OS_IOS");
+#endif
+
+#if defined(OS_LINUX)
+  results_tracker_.AddGlobalTag("OS_LINUX");
+#endif
+
+#if defined(OS_MACOSX)
+  results_tracker_.AddGlobalTag("OS_MACOSX");
+#endif
+
+#if defined(OS_NACL)
+  results_tracker_.AddGlobalTag("OS_NACL");
+#endif
+
+#if defined(OS_OPENBSD)
+  results_tracker_.AddGlobalTag("OS_OPENBSD");
+#endif
+
+#if defined(OS_POSIX)
+  results_tracker_.AddGlobalTag("OS_POSIX");
+#endif
+
+#if defined(OS_SOLARIS)
+  results_tracker_.AddGlobalTag("OS_SOLARIS");
+#endif
+
+#if defined(OS_WIN)
+  results_tracker_.AddGlobalTag("OS_WIN");
+#endif
+
+  // CPU-related tags.
+#if defined(ARCH_CPU_32_BITS)
+  results_tracker_.AddGlobalTag("CPU_32_BITS");
+#endif
+
+#if defined(ARCH_CPU_64_BITS)
+  results_tracker_.AddGlobalTag("CPU_64_BITS");
+#endif
+
+  return true;
+}
+
+void TestLauncher::RunTests() {
+  std::vector<std::string> test_names;
+  for (size_t i = 0; i < tests_.size(); i++) {
+    std::string test_name = FormatFullTestName(
+        tests_[i].first, tests_[i].second);
+
+    results_tracker_.AddTest(test_name);
+
+    const CommandLine* command_line = CommandLine::ForCurrentProcess();
+    if (test_name.find("DISABLED") != std::string::npos) {
+      results_tracker_.AddDisabledTest(test_name);
+
+      // Skip disabled tests unless explicitly requested.
+      if (!command_line->HasSwitch(kGTestRunDisabledTestsFlag))
+        continue;
+    }
+
+    if (!launcher_delegate_->ShouldRunTest(tests_[i].first, tests_[i].second))
+      continue;
+
+    // Skip the test that doesn't match the filter (if given).
+    if (!positive_test_filter_.empty()) {
+      bool found = false;
+      for (size_t k = 0; k < positive_test_filter_.size(); ++k) {
+        if (MatchPattern(test_name, positive_test_filter_[k])) {
+          found = true;
+          break;
+        }
+      }
+
+      if (!found)
+        continue;
+    }
+    bool excluded = false;
+    for (size_t k = 0; k < negative_test_filter_.size(); ++k) {
+      if (MatchPattern(test_name, negative_test_filter_[k])) {
+        excluded = true;
+        break;
+      }
+    }
+    if (excluded)
+      continue;
+
+    if (Hash(test_name) % total_shards_ != static_cast<uint32>(shard_index_))
+      continue;
+
+    test_names.push_back(test_name);
+  }
+
+  test_started_count_ = launcher_delegate_->RunTests(this, test_names);
+
+  if (test_started_count_ == 0) {
+    fprintf(stdout, "0 tests run\n");
+    fflush(stdout);
+
+    // No tests have actually been started, so kick off the next iteration.
+    ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+  }
+}
+
+void TestLauncher::RunTestIteration() {
+  if (cycles_ == 0) {
+    MessageLoop::current()->Quit();
+    return;
+  }
+
+  // Special value "-1" means "repeat indefinitely".
+  cycles_ = (cycles_ == -1) ? cycles_ : cycles_ - 1;
+
+  test_started_count_ = 0;
+  test_finished_count_ = 0;
+  test_success_count_ = 0;
+  test_broken_count_ = 0;
+  retry_count_ = 0;
+  tests_to_retry_.clear();
+  results_tracker_.OnTestIterationStarting();
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTests, Unretained(this)));
+}
+
+void TestLauncher::MaybeSaveSummaryAsJSON() {
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherSummaryOutput)) {
+    FilePath summary_path(command_line->GetSwitchValuePath(
+                              switches::kTestLauncherSummaryOutput));
+    if (!results_tracker_.SaveSummaryAsJSON(summary_path)) {
+      LOG(ERROR) << "Failed to save test launcher output summary.";
+    }
+  }
+}
+
+void TestLauncher::OnLaunchTestProcessFinished(
+    const LaunchChildGTestProcessCallback& callback,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  callback.Run(exit_code, elapsed_time, was_timeout, output);
+}
+
+void TestLauncher::OnTestIterationFinished() {
+  TestResultsTracker::TestStatusMap tests_by_status(
+      results_tracker_.GetTestStatusMapForCurrentIteration());
+  if (!tests_by_status[TestResult::TEST_UNKNOWN].empty())
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+
+  // When we retry tests, success is determined by having nothing more
+  // to retry (everything eventually passed), as opposed to having
+  // no failures at all.
+  if (tests_to_retry_.empty()) {
+    fprintf(stdout, "SUCCESS: all tests passed.\n");
+    fflush(stdout);
+  } else {
+    // Signal failure, but continue to run all requested test iterations.
+    // With the summary of all iterations at the end this is a good default.
+    run_result_ = false;
+  }
+
+  results_tracker_.PrintSummaryOfCurrentIteration();
+
+  // Kick off the next iteration.
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+}
+
+void TestLauncher::OnOutputTimeout() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  AutoLock lock(g_live_processes_lock.Get());
+
+  fprintf(stdout, "Still waiting for the following processes to finish:\n");
+
+  for (std::map<ProcessHandle, CommandLine>::iterator i =
+           g_live_processes.Get().begin();
+       i != g_live_processes.Get().end();
+       ++i) {
+#if defined(OS_WIN)
+    fwprintf(stdout, L"\t%s\n", i->second.GetCommandLineString().c_str());
+#else
+    fprintf(stdout, "\t%s\n", i->second.GetCommandLineString().c_str());
+#endif
+  }
+
+  fflush(stdout);
+
+  // Arm the timer again - otherwise it would fire only once.
+  watchdog_timer_.Reset();
+}
+
+std::string GetTestOutputSnippet(const TestResult& result,
+                                 const std::string& full_output) {
+  size_t run_pos = full_output.find(std::string("[ RUN      ] ") +
+                                    result.full_name);
+  if (run_pos == std::string::npos)
+    return std::string();
+
+  size_t end_pos = full_output.find(std::string("[  FAILED  ] ") +
+                                    result.full_name,
+                                    run_pos);
+  // Only clip the snippet to the "OK" message if the test really
+  // succeeded. It still might have e.g. crashed after printing it.
+  if (end_pos == std::string::npos &&
+      result.status == TestResult::TEST_SUCCESS) {
+    end_pos = full_output.find(std::string("[       OK ] ") +
+                               result.full_name,
+                               run_pos);
+  }
+  if (end_pos != std::string::npos) {
+    size_t newline_pos = full_output.find("\n", end_pos);
+    if (newline_pos != std::string::npos)
+      end_pos = newline_pos + 1;
+  }
+
+  std::string snippet(full_output.substr(run_pos));
+  if (end_pos != std::string::npos)
+    snippet = full_output.substr(run_pos, end_pos - run_pos);
+
+  return snippet;
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h
new file mode 100644
index 0000000..544df63
--- /dev/null
+++ b/base/test/launcher/test_launcher.h
@@ -0,0 +1,210 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
+#define BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/test/gtest_util.h"
+#include "base/test/launcher/test_result.h"
+#include "base/test/launcher/test_results_tracker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace testing {
+class TestCase;
+class TestInfo;
+}
+
+namespace base {
+
+class CommandLine;
+struct LaunchOptions;
+class SequencedWorkerPoolOwner;
+class TestLauncher;
+
+// Constants for GTest command-line flags.
+extern const char kGTestFilterFlag[];
+extern const char kGTestHelpFlag[];
+extern const char kGTestListTestsFlag[];
+extern const char kGTestRepeatFlag[];
+extern const char kGTestRunDisabledTestsFlag[];
+extern const char kGTestOutputFlag[];
+
+// Interface for use with LaunchTests that abstracts away exact details
+// which tests and how are run.
+class TestLauncherDelegate {
+ public:
+  // Called to get names of tests available for running. The delegate
+  // must put the result in |output| and return true on success.
+  virtual bool GetTests(std::vector<SplitTestName>* output) = 0;
+
+  // Called before a test is considered for running. If it returns false,
+  // the test is not run. If it returns true, the test will be run provided
+  // it is part of the current shard.
+  virtual bool ShouldRunTest(const std::string& test_case_name,
+                             const std::string& test_name) = 0;
+
+  // Called to make the delegate run the specified tests. The delegate must
+  // return the number of actual tests it's going to run (can be smaller,
+  // equal to, or larger than size of |test_names|). It must also call
+  // |test_launcher|'s OnTestFinished method once per every run test,
+  // regardless of its success.
+  virtual size_t RunTests(TestLauncher* test_launcher,
+                          const std::vector<std::string>& test_names) = 0;
+
+  // Called to make the delegate retry the specified tests. The delegate must
+  // return the number of actual tests it's going to retry (can be smaller,
+  // equal to, or larger than size of |test_names|). It must also call
+  // |test_launcher|'s OnTestFinished method once per every retried test,
+  // regardless of its success.
+  virtual size_t RetryTests(TestLauncher* test_launcher,
+                            const std::vector<std::string>& test_names) = 0;
+
+ protected:
+  virtual ~TestLauncherDelegate();
+};
+
+// Launches tests using a TestLauncherDelegate.
+class TestLauncher {
+ public:
+  // Flags controlling behavior of LaunchChildGTestProcess.
+  enum LaunchChildGTestProcessFlags {
+    // Allows usage of job objects on Windows. Helps properly clean up child
+    // processes.
+    USE_JOB_OBJECTS = (1 << 0),
+
+    // Allows breakaway from job on Windows. May result in some child processes
+    // not being properly terminated after launcher dies if these processes
+    // fail to cooperate.
+    ALLOW_BREAKAWAY_FROM_JOB = (1 << 1),
+  };
+
+  // Constructor. |parallel_jobs| is the limit of simultaneous parallel test
+  // jobs.
+  TestLauncher(TestLauncherDelegate* launcher_delegate, size_t parallel_jobs);
+  ~TestLauncher();
+
+  // Runs the launcher. Must be called at most once.
+  bool Run() WARN_UNUSED_RESULT;
+
+  // Callback called after a child process finishes. First argument is the exit
+  // code, second one is child process elapsed time, third one is true if
+  // the child process was terminated because of a timeout, and fourth one
+  // contains output of the child (stdout and stderr together).
+  typedef Callback<void(int, const TimeDelta&, bool, const std::string&)>
+      LaunchChildGTestProcessCallback;
+
+  // Launches a child process (assumed to be gtest-based binary) using
+  // |command_line|. If |wrapper| is not empty, it is prepended to the final
+  // command line. If the child process is still running after |timeout|, it
+  // is terminated. After the child process finishes |callback| is called
+  // on the same thread this method was called.
+  void LaunchChildGTestProcess(const CommandLine& command_line,
+                               const std::string& wrapper,
+                               base::TimeDelta timeout,
+                               int flags,
+                               const LaunchChildGTestProcessCallback& callback);
+
+  // Called when a test has finished running.
+  void OnTestFinished(const TestResult& result);
+
+ private:
+  bool Init() WARN_UNUSED_RESULT;
+
+  // Runs all tests in current iteration. Uses callbacks to communicate success.
+  void RunTests();
+
+  void RunTestIteration();
+
+  // Saves test results summary as JSON if requested from command line.
+  void MaybeSaveSummaryAsJSON();
+
+  // Called on a worker thread after a child process finishes.
+  void OnLaunchTestProcessFinished(
+      const LaunchChildGTestProcessCallback& callback,
+      int exit_code,
+      const TimeDelta& elapsed_time,
+      bool was_timeout,
+      const std::string& output);
+
+  // Called when a test iteration is finished.
+  void OnTestIterationFinished();
+
+  // Called by the delay timer when no output was made for a while.
+  void OnOutputTimeout();
+
+  // Make sure we don't accidentally call the wrong methods e.g. on the worker
+  // pool thread. With lots of callbacks used this is non-trivial.
+  // Should be the first member so that it's destroyed last: when destroying
+  // other members, especially the worker pool, we may check the code is running
+  // on the correct thread.
+  ThreadChecker thread_checker_;
+
+  TestLauncherDelegate* launcher_delegate_;
+
+  // Support for outer sharding, just like gtest does.
+  int32 total_shards_;  // Total number of outer shards, at least one.
+  int32 shard_index_;   // Index of shard the launcher is to run.
+
+  int cycles_;  // Number of remaining test itreations, or -1 for infinite.
+
+  // Test filters (empty means no filter).
+  std::vector<std::string> positive_test_filter_;
+  std::vector<std::string> negative_test_filter_;
+
+  // Tests to use (cached result of TestLauncherDelegate::GetTests).
+  std::vector<SplitTestName> tests_;
+
+  // Number of tests started in this iteration.
+  size_t test_started_count_;
+
+  // Number of tests finished in this iteration.
+  size_t test_finished_count_;
+
+  // Number of tests successfully finished in this iteration.
+  size_t test_success_count_;
+
+  // Number of tests either timing out or having an unknown result,
+  // likely indicating a more systemic problem if widespread.
+  size_t test_broken_count_;
+
+  // Number of retries in this iteration.
+  size_t retry_count_;
+
+  // Maximum number of retries per iteration.
+  size_t retry_limit_;
+
+  // Tests to retry in this iteration.
+  std::set<std::string> tests_to_retry_;
+
+  // Result to be returned from Run.
+  bool run_result_;
+
+  TestResultsTracker results_tracker_;
+
+  // Watchdog timer to make sure we do not go without output for too long.
+  DelayTimer<TestLauncher> watchdog_timer_;
+
+  // Number of jobs to run in parallel.
+  size_t parallel_jobs_;
+
+  // Worker pool used to launch processes in parallel.
+  scoped_ptr<SequencedWorkerPoolOwner> worker_pool_owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestLauncher);
+};
+
+// Extract part from |full_output| that applies to |result|.
+std::string GetTestOutputSnippet(const TestResult& result,
+                                 const std::string& full_output);
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
diff --git a/base/test/launcher/test_launcher_ios.cc b/base/test/launcher/test_launcher_ios.cc
new file mode 100644
index 0000000..ecd31ae
--- /dev/null
+++ b/base/test/launcher/test_launcher_ios.cc
@@ -0,0 +1,187 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_launcher.h"
+
+#include "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+
+namespace {
+
+const char kHelpFlag[] = "help";
+
+void PrintUsage() {
+  fprintf(stdout,
+          "Runs tests using the gtest framework, each batch of tests being\n"
+          "run in their own process. Supported command-line flags:\n"
+          "\n"
+          " Common flags:\n"
+          "  --gtest_filter=...\n"
+          "    Runs a subset of tests (see --gtest_help for more info).\n"
+          "\n"
+          "  --help\n"
+          "    Shows this message.\n"
+          "\n"
+          " Other flags:\n"
+          "  --test-launcher-retry-limit=N\n"
+          "    Sets the limit of test retries on failures to N.\n"
+          "\n"
+          "  --test-launcher-summary-output=PATH\n"
+          "    Saves a JSON machine-readable summary of the run.\n"
+          "\n"
+          "  --test-launcher-print-test-stdio=auto|always|never\n"
+          "    Controls when full test output is printed.\n"
+          "    auto means to print it when the test failed.\n"
+          "\n"
+          "  --test-launcher-total-shards=N\n"
+          "    Sets the total number of shards to N.\n"
+          "\n"
+          "  --test-launcher-shard-index=N\n"
+          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
+  fflush(stdout);
+}
+
+class IOSUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
+ public:
+  IOSUnitTestPlatformDelegate() {
+  }
+
+  bool Init() WARN_UNUSED_RESULT {
+    if (!PathService::Get(base::DIR_EXE, &dir_exe_)) {
+      LOG(ERROR) << "Failed to get directory of current executable.";
+      return false;
+    }
+
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    std::vector<std::string> args(command_line->GetArgs());
+    if (args.size() < 1) {
+      LOG(ERROR) << "Arguments expected.";
+      return false;
+    }
+    test_name_ = args[0];
+
+    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
+    cmd_line.AppendSwitch(switches::kTestLauncherPrintWritablePath);
+    cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value());
+
+    std::string raw_output;
+    if (!base::GetAppOutput(cmd_line, &raw_output)) {
+      LOG(ERROR) << "GetAppOutput failed.";
+      return false;
+    }
+    writable_path_ = base::FilePath(raw_output);
+
+    return true;
+  }
+
+  bool GetTests(std::vector<base::SplitTestName>* output) override {
+    base::ScopedTempDir temp_dir;
+    if (!temp_dir.CreateUniqueTempDirUnderPath(writable_path_))
+      return false;
+    base::FilePath test_list_path(
+        temp_dir.path().AppendASCII("test_list.json"));
+
+    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
+    cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, test_list_path);
+    cmd_line.PrependWrapper(dir_exe_.AppendASCII("iossim").value());
+
+    base::LaunchOptions launch_options;
+    launch_options.wait = true;
+
+    if (!base::LaunchProcess(cmd_line, launch_options).IsValid())
+      return false;
+
+    return base::ReadTestNamesFromFile(test_list_path, output);
+  }
+
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!CreateTemporaryDirInDir(writable_path_, std::string(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  base::CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
+    cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
+    cmd_line.AppendSwitchASCII(base::kGTestFilterFlag,
+                               JoinString(test_names, ":"));
+    return cmd_line;
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return dir_exe_.AppendASCII("iossim").value();
+  }
+
+  void RelaunchTests(base::TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    // Relaunch all tests in one big batch, since overhead of smaller batches
+    // is too big for serialized runs inside ios simulator.
+    RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
+  }
+
+ private:
+  // Directory containing test launcher's executable.
+  base::FilePath dir_exe_;
+
+  // Name of the test executable to run.
+  std::string test_name_;
+
+  // Path that launched test binary can write to.
+  base::FilePath writable_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSUnitTestPlatformDelegate);
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+
+  base::CommandLine::Init(argc, argv);
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  TestTimeouts::Initialize();
+
+  base::MessageLoopForIO message_loop;
+
+  IOSUnitTestPlatformDelegate platform_delegate;
+  if (!platform_delegate.Init()) {
+    fprintf(stderr, "Failed to intialize test launcher platform delegate.\n");
+    fflush(stderr);
+    return 1;
+  }
+  base::UnitTestLauncherDelegate delegate(&platform_delegate, 0, false);
+  // Force one job since we can't run multiple simulators in parallel.
+  base::TestLauncher launcher(&delegate, 1);
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+
+  return (success ? 0 : 1);
+}
diff --git a/base/test/launcher/test_result.cc b/base/test/launcher/test_result.cc
new file mode 100644
index 0000000..70d7a80
--- /dev/null
+++ b/base/test/launcher/test_result.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_result.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+TestResult::TestResult() : status(TEST_UNKNOWN) {
+}
+
+TestResult::~TestResult() {
+}
+
+std::string TestResult::StatusAsString() const {
+  switch (status) {
+    case TEST_UNKNOWN:
+      return "UNKNOWN";
+    case TEST_SUCCESS:
+      return "SUCCESS";
+    case TEST_FAILURE:
+      return "FAILURE";
+    case TEST_FAILURE_ON_EXIT:
+      return "FAILURE_ON_EXIT";
+    case TEST_CRASH:
+      return "CRASH";
+    case TEST_TIMEOUT:
+      return "TIMEOUT";
+    case TEST_SKIPPED:
+      return "SKIPPED";
+     // Rely on compiler warnings to ensure all possible values are handled.
+  }
+
+  NOTREACHED();
+  return std::string();
+}
+
+std::string TestResult::GetTestName() const {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  return full_name.substr(dot_pos + 1);
+}
+
+std::string TestResult::GetTestCaseName() const {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  return full_name.substr(0, dot_pos);
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_result.h b/base/test/launcher/test_result.h
new file mode 100644
index 0000000..b61cdd4
--- /dev/null
+++ b/base/test/launcher/test_result.h
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_RESULT_H_
+#define BASE_TEST_LAUNCHER_TEST_RESULT_H_
+
+#include <string>
+
+#include "base/time/time.h"
+
+namespace base {
+
+// Structure containing result of a single test.
+struct TestResult {
+  enum Status {
+    TEST_UNKNOWN,          // Status not set.
+    TEST_SUCCESS,          // Test passed.
+    TEST_FAILURE,          // Assertion failure (think EXPECT_TRUE, not DCHECK).
+    TEST_FAILURE_ON_EXIT,  // Test passed but executable exit code was non-zero.
+    TEST_TIMEOUT,          // Test timed out and was killed.
+    TEST_CRASH,            // Test crashed (includes CHECK/DCHECK failures).
+    TEST_SKIPPED,          // Test skipped (not run at all).
+  };
+
+  TestResult();
+  ~TestResult();
+
+  // Returns the test status as string (e.g. for display).
+  std::string StatusAsString() const;
+
+  // Returns the test name (e.g. "B" for "A.B").
+  std::string GetTestName() const;
+
+  // Returns the test case name (e.g. "A" for "A.B").
+  std::string GetTestCaseName() const;
+
+  // Returns true if the test has completed (i.e. the test binary exited
+  // normally, possibly with an exit code indicating failure, but didn't crash
+  // or time out in the middle of the test).
+  bool completed() const {
+    return status == TEST_SUCCESS ||
+        status == TEST_FAILURE ||
+        status == TEST_FAILURE_ON_EXIT;
+  }
+
+  // Full name of the test (e.g. "A.B").
+  std::string full_name;
+
+  Status status;
+
+  // Time it took to run the test.
+  base::TimeDelta elapsed_time;
+
+  // Output of just this test (optional).
+  std::string output_snippet;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_RESULT_H_
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
new file mode 100644
index 0000000..c4cb233
--- /dev/null
+++ b/base/test/launcher/test_results_tracker.cc
@@ -0,0 +1,353 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_results_tracker.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/format_macros.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/values.h"
+
+namespace base {
+
+namespace {
+
+// The default output file for XML output.
+const FilePath::CharType kDefaultOutputFile[] = FILE_PATH_LITERAL(
+    "test_detail.xml");
+
+// Utility function to print a list of test names. Uses iterator to be
+// compatible with different containers, like vector and set.
+template<typename InputIterator>
+void PrintTests(InputIterator first,
+                InputIterator last,
+                const std::string& description) {
+  size_t count = std::distance(first, last);
+  if (count == 0)
+    return;
+
+  fprintf(stdout,
+          "%" PRIuS " test%s %s:\n",
+          count,
+          count != 1 ? "s" : "",
+          description.c_str());
+  for (InputIterator i = first; i != last; ++i)
+    fprintf(stdout, "    %s\n", (*i).c_str());
+  fflush(stdout);
+}
+
+std::string TestNameWithoutDisabledPrefix(const std::string& test_name) {
+  std::string test_name_no_disabled(test_name);
+  ReplaceSubstringsAfterOffset(&test_name_no_disabled, 0, "DISABLED_", "");
+  return test_name_no_disabled;
+}
+
+}  // namespace
+
+TestResultsTracker::TestResultsTracker() : iteration_(-1), out_(NULL) {
+}
+
+TestResultsTracker::~TestResultsTracker() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!out_)
+    return;
+  fprintf(out_, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+  fprintf(out_, "<testsuites name=\"AllTests\" tests=\"\" failures=\"\""
+          " disabled=\"\" errors=\"\" time=\"\">\n");
+
+  // Maps test case names to test results.
+  typedef std::map<std::string, std::vector<TestResult> > TestCaseMap;
+  TestCaseMap test_case_map;
+
+  for (PerIterationData::ResultsMap::iterator i =
+           per_iteration_data_[iteration_].results.begin();
+       i != per_iteration_data_[iteration_].results.end();
+       ++i) {
+    // Use the last test result as the final one.
+    TestResult result = i->second.test_results.back();
+    test_case_map[result.GetTestCaseName()].push_back(result);
+  }
+  for (TestCaseMap::iterator i = test_case_map.begin();
+       i != test_case_map.end();
+       ++i) {
+    fprintf(out_, "  <testsuite name=\"%s\" tests=\"%" PRIuS "\" failures=\"\""
+            " disabled=\"\" errors=\"\" time=\"\">\n",
+            i->first.c_str(), i->second.size());
+    for (size_t j = 0; j < i->second.size(); ++j) {
+      const TestResult& result = i->second[j];
+      fprintf(out_, "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+              " classname=\"%s\">\n",
+              result.GetTestName().c_str(),
+              result.elapsed_time.InSecondsF(),
+              result.GetTestCaseName().c_str());
+      if (result.status != TestResult::TEST_SUCCESS)
+        fprintf(out_, "      <failure message=\"\" type=\"\"></failure>\n");
+      fprintf(out_, "    </testcase>\n");
+    }
+    fprintf(out_, "  </testsuite>\n");
+  }
+  fprintf(out_, "</testsuites>\n");
+  fclose(out_);
+}
+
+bool TestResultsTracker::Init(const CommandLine& command_line) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Prevent initializing twice.
+  if (out_) {
+    NOTREACHED();
+    return false;
+  }
+
+  if (!command_line.HasSwitch(kGTestOutputFlag))
+    return true;
+
+  std::string flag = command_line.GetSwitchValueASCII(kGTestOutputFlag);
+  size_t colon_pos = flag.find(':');
+  FilePath path;
+  if (colon_pos != std::string::npos) {
+    FilePath flag_path =
+        command_line.GetSwitchValuePath(kGTestOutputFlag);
+    FilePath::StringType path_string = flag_path.value();
+    path = FilePath(path_string.substr(colon_pos + 1));
+    // If the given path ends with '/', consider it is a directory.
+    // Note: This does NOT check that a directory (or file) actually exists
+    // (the behavior is same as what gtest does).
+    if (path.EndsWithSeparator()) {
+      FilePath executable = command_line.GetProgram().BaseName();
+      path = path.Append(executable.ReplaceExtension(
+                             FilePath::StringType(FILE_PATH_LITERAL("xml"))));
+    }
+  }
+  if (path.value().empty())
+    path = FilePath(kDefaultOutputFile);
+  FilePath dir_name = path.DirName();
+  if (!DirectoryExists(dir_name)) {
+    LOG(WARNING) << "The output directory does not exist. "
+                 << "Creating the directory: " << dir_name.value();
+    // Create the directory if necessary (because the gtest does the same).
+    if (!base::CreateDirectory(dir_name)) {
+      LOG(ERROR) << "Failed to created directory " << dir_name.value();
+      return false;
+    }
+  }
+  out_ = OpenFile(path, "w");
+  if (!out_) {
+    LOG(ERROR) << "Cannot open output file: "
+               << path.value() << ".";
+    return false;
+  }
+
+  return true;
+}
+
+void TestResultsTracker::OnTestIterationStarting() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Start with a fresh state for new iteration.
+  iteration_++;
+  per_iteration_data_.push_back(PerIterationData());
+}
+
+void TestResultsTracker::AddTest(const std::string& test_name) {
+  // Record disabled test names without DISABLED_ prefix so that they are easy
+  // to compare with regular test names, e.g. before or after disabling.
+  all_tests_.insert(TestNameWithoutDisabledPrefix(test_name));
+}
+
+void TestResultsTracker::AddDisabledTest(const std::string& test_name) {
+  // Record disabled test names without DISABLED_ prefix so that they are easy
+  // to compare with regular test names, e.g. before or after disabling.
+  disabled_tests_.insert(TestNameWithoutDisabledPrefix(test_name));
+}
+
+void TestResultsTracker::AddTestResult(const TestResult& result) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  per_iteration_data_[iteration_].results[
+      result.full_name].test_results.push_back(result);
+}
+
+void TestResultsTracker::PrintSummaryOfCurrentIteration() const {
+  TestStatusMap tests_by_status(GetTestStatusMapForCurrentIteration());
+
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE].begin(),
+             tests_by_status[TestResult::TEST_FAILURE].end(),
+             "failed");
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].begin(),
+             tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].end(),
+             "failed on exit");
+  PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
+             tests_by_status[TestResult::TEST_TIMEOUT].end(),
+             "timed out");
+  PrintTests(tests_by_status[TestResult::TEST_CRASH].begin(),
+             tests_by_status[TestResult::TEST_CRASH].end(),
+             "crashed");
+  PrintTests(tests_by_status[TestResult::TEST_SKIPPED].begin(),
+             tests_by_status[TestResult::TEST_SKIPPED].end(),
+             "skipped");
+  PrintTests(tests_by_status[TestResult::TEST_UNKNOWN].begin(),
+             tests_by_status[TestResult::TEST_UNKNOWN].end(),
+             "had unknown result");
+}
+
+void TestResultsTracker::PrintSummaryOfAllIterations() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TestStatusMap tests_by_status(GetTestStatusMapForAllIterations());
+
+  fprintf(stdout, "Summary of all test iterations:\n");
+  fflush(stdout);
+
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE].begin(),
+             tests_by_status[TestResult::TEST_FAILURE].end(),
+             "failed");
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].begin(),
+             tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].end(),
+             "failed on exit");
+  PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
+             tests_by_status[TestResult::TEST_TIMEOUT].end(),
+             "timed out");
+  PrintTests(tests_by_status[TestResult::TEST_CRASH].begin(),
+             tests_by_status[TestResult::TEST_CRASH].end(),
+             "crashed");
+  PrintTests(tests_by_status[TestResult::TEST_SKIPPED].begin(),
+             tests_by_status[TestResult::TEST_SKIPPED].end(),
+             "skipped");
+  PrintTests(tests_by_status[TestResult::TEST_UNKNOWN].begin(),
+             tests_by_status[TestResult::TEST_UNKNOWN].end(),
+             "had unknown result");
+
+  fprintf(stdout, "End of the summary.\n");
+  fflush(stdout);
+}
+
+void TestResultsTracker::AddGlobalTag(const std::string& tag) {
+  global_tags_.insert(tag);
+}
+
+bool TestResultsTracker::SaveSummaryAsJSON(const FilePath& path) const {
+  scoped_ptr<DictionaryValue> summary_root(new DictionaryValue);
+
+  scoped_ptr<ListValue> global_tags(new ListValue);
+  for (const auto& global_tag : global_tags_) {
+    global_tags->AppendString(global_tag);
+  }
+  summary_root->Set("global_tags", global_tags.Pass());
+
+  scoped_ptr<ListValue> all_tests(new ListValue);
+  for (const auto& test : all_tests_) {
+    all_tests->AppendString(test);
+  }
+  summary_root->Set("all_tests", all_tests.Pass());
+
+  scoped_ptr<ListValue> disabled_tests(new ListValue);
+  for (const auto& disabled_test : disabled_tests_) {
+    disabled_tests->AppendString(disabled_test);
+  }
+  summary_root->Set("disabled_tests", disabled_tests.Pass());
+
+  scoped_ptr<ListValue> per_iteration_data(new ListValue);
+
+  for (int i = 0; i <= iteration_; i++) {
+    scoped_ptr<DictionaryValue> current_iteration_data(new DictionaryValue);
+
+    for (PerIterationData::ResultsMap::const_iterator j =
+             per_iteration_data_[i].results.begin();
+         j != per_iteration_data_[i].results.end();
+         ++j) {
+      scoped_ptr<ListValue> test_results(new ListValue);
+
+      for (size_t k = 0; k < j->second.test_results.size(); k++) {
+        const TestResult& test_result = j->second.test_results[k];
+
+        scoped_ptr<DictionaryValue> test_result_value(new DictionaryValue);
+
+        test_result_value->SetString("status", test_result.StatusAsString());
+        test_result_value->SetInteger(
+            "elapsed_time_ms",
+            static_cast<int>(test_result.elapsed_time.InMilliseconds()));
+
+        // There are no guarantees about character encoding of the output
+        // snippet. Escape it and record whether it was losless.
+        // It's useful to have the output snippet as string in the summary
+        // for easy viewing.
+        std::string escaped_output_snippet;
+        bool losless_snippet = EscapeJSONString(
+            test_result.output_snippet, false, &escaped_output_snippet);
+        test_result_value->SetString("output_snippet",
+                                     escaped_output_snippet);
+        test_result_value->SetBoolean("losless_snippet", losless_snippet);
+
+        // Also include the raw version (base64-encoded so that it can be safely
+        // JSON-serialized - there are no guarantees about character encoding
+        // of the snippet). This can be very useful piece of information when
+        // debugging a test failure related to character encoding.
+        std::string base64_output_snippet;
+        Base64Encode(test_result.output_snippet, &base64_output_snippet);
+        test_result_value->SetString("output_snippet_base64",
+                                     base64_output_snippet);
+        test_results->Append(test_result_value.Pass());
+      }
+
+      current_iteration_data->SetWithoutPathExpansion(j->first,
+                                                      test_results.Pass());
+    }
+    per_iteration_data->Append(current_iteration_data.Pass());
+    summary_root->Set("per_iteration_data", per_iteration_data.Pass());
+  }
+
+  JSONFileValueSerializer serializer(path);
+  return serializer.Serialize(*summary_root);
+}
+
+TestResultsTracker::TestStatusMap
+    TestResultsTracker::GetTestStatusMapForCurrentIteration() const {
+  TestStatusMap tests_by_status;
+  GetTestStatusForIteration(iteration_, &tests_by_status);
+  return tests_by_status;
+}
+
+TestResultsTracker::TestStatusMap
+    TestResultsTracker::GetTestStatusMapForAllIterations() const {
+  TestStatusMap tests_by_status;
+  for (int i = 0; i <= iteration_; i++)
+    GetTestStatusForIteration(i, &tests_by_status);
+  return tests_by_status;
+}
+
+void TestResultsTracker::GetTestStatusForIteration(
+    int iteration, TestStatusMap* map) const {
+  for (PerIterationData::ResultsMap::const_iterator j =
+           per_iteration_data_[iteration].results.begin();
+       j != per_iteration_data_[iteration].results.end();
+       ++j) {
+    // Use the last test result as the final one.
+    const TestResult& result = j->second.test_results.back();
+    (*map)[result.status].insert(result.full_name);
+  }
+}
+
+TestResultsTracker::AggregateTestResult::AggregateTestResult() {
+}
+
+TestResultsTracker::AggregateTestResult::~AggregateTestResult() {
+}
+
+TestResultsTracker::PerIterationData::PerIterationData() {
+}
+
+TestResultsTracker::PerIterationData::~PerIterationData() {
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_results_tracker.h b/base/test/launcher/test_results_tracker.h
new file mode 100644
index 0000000..2bddebc
--- /dev/null
+++ b/base/test/launcher/test_results_tracker.h
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_RESULTS_TRACKER_H_
+#define BASE_TEST_LAUNCHER_TEST_RESULTS_TRACKER_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/test/launcher/test_result.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+class CommandLine;
+class FilePath;
+
+// A helper class to output results.
+// Note: as currently XML is the only supported format by gtest, we don't
+// check output format (e.g. "xml:" prefix) here and output an XML file
+// unconditionally.
+// Note: we don't output per-test-case or total summary info like
+// total failed_test_count, disabled_test_count, elapsed_time and so on.
+// Only each test (testcase element in the XML) will have the correct
+// failed/disabled/elapsed_time information. Each test won't include
+// detailed failure messages either.
+class TestResultsTracker {
+ public:
+  TestResultsTracker();
+  ~TestResultsTracker();
+
+  // Initialize the result tracker. Must be called exactly once before
+  // calling any other methods. Returns true on success.
+  bool Init(const CommandLine& command_line) WARN_UNUSED_RESULT;
+
+  // Called when a test iteration is starting.
+  void OnTestIterationStarting();
+
+  // Adds |test_name| to the set of discovered tests (this includes all tests
+  // present in the executable, not necessarily run).
+  void AddTest(const std::string& test_name);
+
+  // Adds |test_name| to the set of disabled tests.
+  void AddDisabledTest(const std::string& test_name);
+
+  // Adds |result| to the stored test results.
+  void AddTestResult(const TestResult& result);
+
+  // Prints a summary of current test iteration to stdout.
+  void PrintSummaryOfCurrentIteration() const;
+
+  // Prints a summary of all test iterations (not just the last one) to stdout.
+  void PrintSummaryOfAllIterations() const;
+
+  // Adds a string tag to the JSON summary. This is intended to indicate
+  // conditions that affect the entire test run, as opposed to individual tests.
+  void AddGlobalTag(const std::string& tag);
+
+  // Saves a JSON summary of all test iterations results to |path|. Returns
+  // true on success.
+  bool SaveSummaryAsJSON(const FilePath& path) const WARN_UNUSED_RESULT;
+
+  // Map where keys are test result statuses, and values are sets of tests
+  // which finished with that status.
+  typedef std::map<TestResult::Status, std::set<std::string> > TestStatusMap;
+
+  // Returns a test status map (see above) for current test iteration.
+  TestStatusMap GetTestStatusMapForCurrentIteration() const;
+
+  // Returns a test status map (see above) for all test iterations.
+  TestStatusMap GetTestStatusMapForAllIterations() const;
+
+ private:
+  void GetTestStatusForIteration(int iteration, TestStatusMap* map) const;
+
+  struct AggregateTestResult {
+    AggregateTestResult();
+    ~AggregateTestResult();
+
+    std::vector<TestResult> test_results;
+  };
+
+  struct PerIterationData {
+    PerIterationData();
+    ~PerIterationData();
+
+    // Aggregate test results grouped by full test name.
+    typedef std::map<std::string, AggregateTestResult> ResultsMap;
+    ResultsMap results;
+  };
+
+  ThreadChecker thread_checker_;
+
+  // Set of global tags, i.e. strings indicating conditions that apply to
+  // the entire test run.
+  std::set<std::string> global_tags_;
+
+  // Set of all test names discovered in the current executable.
+  std::set<std::string> all_tests_;
+
+  // Set of all disabled tests in the current executable.
+  std::set<std::string> disabled_tests_;
+
+  // Store test results for each iteration.
+  std::vector<PerIterationData> per_iteration_data_;
+
+  // Index of current iteration (starting from 0). -1 before the first
+  // iteration.
+  int iteration_;
+
+  // File handle of output file (can be NULL if no file).
+  FILE* out_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestResultsTracker);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_RESULTS_TRACKER_H_
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
new file mode 100644
index 0000000..ab6fa72
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -0,0 +1,586 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/unit_test_launcher.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// This constant controls how many tests are run in a single batch by default.
+const size_t kDefaultTestBatchLimit = 10;
+
+const char kHelpFlag[] = "help";
+
+// Flag to run all tests in a single process.
+const char kSingleProcessTestsFlag[] = "single-process-tests";
+
+void PrintUsage() {
+  fprintf(stdout,
+          "Runs tests using the gtest framework, each batch of tests being\n"
+          "run in their own process. Supported command-line flags:\n"
+          "\n"
+          " Common flags:\n"
+          "  --gtest_filter=...\n"
+          "    Runs a subset of tests (see --gtest_help for more info).\n"
+          "\n"
+          "  --help\n"
+          "    Shows this message.\n"
+          "\n"
+          "  --gtest_help\n"
+          "    Shows the gtest help message.\n"
+          "\n"
+          "  --test-launcher-jobs=N\n"
+          "    Sets the number of parallel test jobs to N.\n"
+          "\n"
+          "  --single-process-tests\n"
+          "    Runs the tests and the launcher in the same process. Useful\n"
+          "    for debugging a specific test in a debugger.\n"
+          "\n"
+          " Other flags:\n"
+          "  --test-launcher-batch-limit=N\n"
+          "    Sets the limit of test batch to run in a single process to N.\n"
+          "\n"
+          "  --test-launcher-debug-launcher\n"
+          "    Disables autodetection of debuggers and similar tools,\n"
+          "    making it possible to use them to debug launcher itself.\n"
+          "\n"
+          "  --test-launcher-retry-limit=N\n"
+          "    Sets the limit of test retries on failures to N.\n"
+          "\n"
+          "  --test-launcher-summary-output=PATH\n"
+          "    Saves a JSON machine-readable summary of the run.\n"
+          "\n"
+          "  --test-launcher-print-test-stdio=auto|always|never\n"
+          "    Controls when full test output is printed.\n"
+          "    auto means to print it when the test failed.\n"
+          "\n"
+          "  --test-launcher-total-shards=N\n"
+          "    Sets the total number of shards to N.\n"
+          "\n"
+          "  --test-launcher-shard-index=N\n"
+          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
+  fflush(stdout);
+}
+
+class DefaultUnitTestPlatformDelegate : public UnitTestPlatformDelegate {
+ public:
+  DefaultUnitTestPlatformDelegate() {
+  }
+
+ private:
+  // UnitTestPlatformDelegate:
+  bool GetTests(std::vector<SplitTestName>* output) override {
+    *output = GetCompiledInTests();
+    return true;
+  }
+
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!CreateNewTempDirectory(FilePath::StringType(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    CommandLine new_cmd_line(*CommandLine::ForCurrentProcess());
+
+    new_cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
+    new_cmd_line.AppendSwitchASCII(kGTestFilterFlag,
+                                   JoinString(test_names, ":"));
+    new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
+
+    return new_cmd_line;
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return std::string();
+  }
+
+  void RelaunchTests(TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    // Relaunch requested tests in parallel, but only use single
+    // test per batch for more precise results (crashes, etc).
+    for (const std::string& test_name : test_names) {
+      std::vector<std::string> batch;
+      batch.push_back(test_name);
+      RunUnitTestsBatch(test_launcher, this, batch, launch_flags);
+    }
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultUnitTestPlatformDelegate);
+};
+
+bool GetSwitchValueAsInt(const std::string& switch_name, int* result) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switch_name))
+    return true;
+
+  std::string switch_value =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name);
+  if (!StringToInt(switch_value, result) || *result < 1) {
+    LOG(ERROR) << "Invalid value for " << switch_name << ": " << switch_value;
+    return false;
+  }
+
+  return true;
+}
+
+int LaunchUnitTestsInternal(const RunTestSuiteCallback& run_test_suite,
+                            int default_jobs,
+                            bool use_job_objects,
+                            const Closure& gtest_init) {
+#if defined(OS_ANDROID)
+  // We can't easily fork on Android, just run the test suite directly.
+  return run_test_suite.Run();
+#else
+  bool force_single_process = false;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherDebugLauncher)) {
+    fprintf(stdout, "Forcing test launcher debugging mode.\n");
+    fflush(stdout);
+  } else {
+    if (base::debug::BeingDebugged()) {
+      fprintf(stdout,
+              "Debugger detected, switching to single process mode.\n"
+              "Pass --test-launcher-debug-launcher to debug the launcher "
+              "itself.\n");
+      fflush(stdout);
+      force_single_process = true;
+    }
+  }
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestHelpFlag) ||
+      CommandLine::ForCurrentProcess()->HasSwitch(kGTestListTestsFlag) ||
+      CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
+      force_single_process) {
+    return run_test_suite.Run();
+  }
+#endif
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  gtest_init.Run();
+  TestTimeouts::Initialize();
+
+  int batch_limit = kDefaultTestBatchLimit;
+  if (!GetSwitchValueAsInt(switches::kTestLauncherBatchLimit, &batch_limit))
+    return 1;
+
+  fprintf(stdout,
+          "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their\n"
+          "own process. For debugging a test inside a debugger, use the\n"
+          "--gtest_filter=<your_test_name> flag along with\n"
+          "--single-process-tests.\n");
+  fflush(stdout);
+
+  MessageLoopForIO message_loop;
+
+  DefaultUnitTestPlatformDelegate platform_delegate;
+  UnitTestLauncherDelegate delegate(
+      &platform_delegate, batch_limit, use_job_objects);
+  base::TestLauncher launcher(&delegate, default_jobs);
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+
+  return (success ? 0 : 1);
+}
+
+void InitGoogleTestChar(int* argc, char** argv) {
+  testing::InitGoogleTest(argc, argv);
+}
+
+#if defined(OS_WIN)
+void InitGoogleTestWChar(int* argc, wchar_t** argv) {
+  testing::InitGoogleTest(argc, argv);
+}
+#endif  // defined(OS_WIN)
+
+// Interprets test results and reports to the test launcher. Returns true
+// on success.
+bool ProcessTestResults(
+    TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names,
+    const base::FilePath& output_file,
+    const std::string& output,
+    int exit_code,
+    bool was_timeout,
+    std::vector<std::string>* tests_to_relaunch) {
+  std::vector<TestResult> test_results;
+  bool crashed = false;
+  bool have_test_results =
+      ProcessGTestOutput(output_file, &test_results, &crashed);
+
+  bool called_any_callback = false;
+
+  if (have_test_results) {
+    // TODO(phajdan.jr): Check for duplicates and mismatches between
+    // the results we got from XML file and tests we intended to run.
+    std::map<std::string, TestResult> results_map;
+    for (size_t i = 0; i < test_results.size(); i++)
+      results_map[test_results[i].full_name] = test_results[i];
+
+    bool had_interrupted_test = false;
+
+    // Results to be reported back to the test launcher.
+    std::vector<TestResult> final_results;
+
+    for (size_t i = 0; i < test_names.size(); i++) {
+      if (ContainsKey(results_map, test_names[i])) {
+        TestResult test_result = results_map[test_names[i]];
+        if (test_result.status == TestResult::TEST_CRASH) {
+          had_interrupted_test = true;
+
+          if (was_timeout) {
+            // Fix up the test status: we forcibly kill the child process
+            // after the timeout, so from XML results it looks just like
+            // a crash.
+            test_result.status = TestResult::TEST_TIMEOUT;
+          }
+        } else if (test_result.status == TestResult::TEST_SUCCESS ||
+                   test_result.status == TestResult::TEST_FAILURE) {
+          // We run multiple tests in a batch with a timeout applied
+          // to the entire batch. It is possible that with other tests
+          // running quickly some tests take longer than the per-test timeout.
+          // For consistent handling of tests independent of order and other
+          // factors, mark them as timing out.
+          if (test_result.elapsed_time >
+              TestTimeouts::test_launcher_timeout()) {
+            test_result.status = TestResult::TEST_TIMEOUT;
+          }
+        }
+        test_result.output_snippet = GetTestOutputSnippet(test_result, output);
+        final_results.push_back(test_result);
+      } else if (had_interrupted_test) {
+        tests_to_relaunch->push_back(test_names[i]);
+      } else {
+        // TODO(phajdan.jr): Explicitly pass the info that the test didn't
+        // run for a mysterious reason.
+        LOG(ERROR) << "no test result for " << test_names[i];
+        TestResult test_result;
+        test_result.full_name = test_names[i];
+        test_result.status = TestResult::TEST_UNKNOWN;
+        test_result.output_snippet = GetTestOutputSnippet(test_result, output);
+        final_results.push_back(test_result);
+      }
+    }
+
+    // TODO(phajdan.jr): Handle the case where processing XML output
+    // indicates a crash but none of the test results is marked as crashing.
+
+    if (final_results.empty())
+      return false;
+
+    bool has_non_success_test = false;
+    for (size_t i = 0; i < final_results.size(); i++) {
+      if (final_results[i].status != TestResult::TEST_SUCCESS) {
+        has_non_success_test = true;
+        break;
+      }
+    }
+
+    if (!has_non_success_test && exit_code != 0) {
+      // This is a bit surprising case: all tests are marked as successful,
+      // but the exit code was not zero. This can happen e.g. under memory
+      // tools that report leaks this way. Mark all tests as a failure on exit,
+      // and for more precise info they'd need to be retried serially.
+      for (size_t i = 0; i < final_results.size(); i++)
+        final_results[i].status = TestResult::TEST_FAILURE_ON_EXIT;
+    }
+
+    for (size_t i = 0; i < final_results.size(); i++) {
+      // Fix the output snippet after possible changes to the test result.
+      final_results[i].output_snippet =
+          GetTestOutputSnippet(final_results[i], output);
+      test_launcher->OnTestFinished(final_results[i]);
+      called_any_callback = true;
+    }
+  } else {
+    fprintf(stdout,
+            "Failed to get out-of-band test success data, "
+            "dumping full stdio below:\n%s\n",
+            output.c_str());
+    fflush(stdout);
+
+    // We do not have reliable details about test results (parsing test
+    // stdout is known to be unreliable), apply the executable exit code
+    // to all tests.
+    // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
+    // individually.
+    for (size_t i = 0; i < test_names.size(); i++) {
+      TestResult test_result;
+      test_result.full_name = test_names[i];
+      test_result.status = TestResult::TEST_UNKNOWN;
+      test_launcher->OnTestFinished(test_result);
+      called_any_callback = true;
+    }
+  }
+
+  return called_any_callback;
+}
+
+// TODO(phajdan.jr): Pass parameters directly with C++11 variadic templates.
+struct GTestCallbackState {
+  TestLauncher* test_launcher;
+  UnitTestPlatformDelegate* platform_delegate;
+  std::vector<std::string> test_names;
+  int launch_flags;
+  FilePath output_file;
+};
+
+void GTestCallback(
+    const GTestCallbackState& callback_state,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  std::vector<std::string> tests_to_relaunch;
+  ProcessTestResults(callback_state.test_launcher, callback_state.test_names,
+                     callback_state.output_file, output, exit_code, was_timeout,
+                     &tests_to_relaunch);
+
+  if (!tests_to_relaunch.empty()) {
+    callback_state.platform_delegate->RelaunchTests(
+        callback_state.test_launcher,
+        tests_to_relaunch,
+        callback_state.launch_flags);
+  }
+
+  // The temporary file's directory is also temporary.
+  DeleteFile(callback_state.output_file.DirName(), true);
+}
+
+void SerialGTestCallback(
+    const GTestCallbackState& callback_state,
+    const std::vector<std::string>& test_names,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  std::vector<std::string> tests_to_relaunch;
+  bool called_any_callbacks =
+      ProcessTestResults(callback_state.test_launcher,
+                         callback_state.test_names, callback_state.output_file,
+                         output, exit_code, was_timeout, &tests_to_relaunch);
+
+  // There is only one test, there cannot be other tests to relaunch
+  // due to a crash.
+  DCHECK(tests_to_relaunch.empty());
+
+  // There is only one test, we should have called back with its result.
+  DCHECK(called_any_callbacks);
+
+  // The temporary file's directory is also temporary.
+  DeleteFile(callback_state.output_file.DirName(), true);
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&RunUnitTestsSerially, callback_state.test_launcher,
+                      callback_state.platform_delegate, test_names,
+                      callback_state.launch_flags));
+}
+
+}  // namespace
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CommandLine::Init(argc, argv);
+  return LaunchUnitTestsInternal(run_test_suite, SysInfo::NumberOfProcessors(),
+                                 true, Bind(&InitGoogleTestChar, &argc, argv));
+}
+
+int LaunchUnitTestsSerially(int argc,
+                            char** argv,
+                            const RunTestSuiteCallback& run_test_suite) {
+  CommandLine::Init(argc, argv);
+  return LaunchUnitTestsInternal(run_test_suite, 1, true,
+                                 Bind(&InitGoogleTestChar, &argc, argv));
+}
+
+#if defined(OS_WIN)
+int LaunchUnitTests(int argc,
+                    wchar_t** argv,
+                    bool use_job_objects,
+                    const RunTestSuiteCallback& run_test_suite) {
+  // Windows CommandLine::Init ignores argv anyway.
+  CommandLine::Init(argc, NULL);
+  return LaunchUnitTestsInternal(run_test_suite, SysInfo::NumberOfProcessors(),
+                                 use_job_objects,
+                                 Bind(&InitGoogleTestWChar, &argc, argv));
+}
+#endif  // defined(OS_WIN)
+
+void RunUnitTestsSerially(
+    TestLauncher* test_launcher,
+    UnitTestPlatformDelegate* platform_delegate,
+    const std::vector<std::string>& test_names,
+    int launch_flags) {
+  if (test_names.empty())
+    return;
+
+  std::vector<std::string> new_test_names(test_names);
+  std::string test_name(new_test_names.back());
+  new_test_names.pop_back();
+
+  // Create a dedicated temporary directory to store the xml result data
+  // per run to ensure clean state and make it possible to launch multiple
+  // processes in parallel.
+  base::FilePath output_file;
+  CHECK(platform_delegate->CreateTemporaryFile(&output_file));
+
+  std::vector<std::string> current_test_names;
+  current_test_names.push_back(test_name);
+  CommandLine cmd_line(platform_delegate->GetCommandLineForChildGTestProcess(
+      current_test_names, output_file));
+
+  GTestCallbackState callback_state;
+  callback_state.test_launcher = test_launcher;
+  callback_state.platform_delegate = platform_delegate;
+  callback_state.test_names = current_test_names;
+  callback_state.launch_flags = launch_flags;
+  callback_state.output_file = output_file;
+
+  test_launcher->LaunchChildGTestProcess(
+      cmd_line,
+      platform_delegate->GetWrapperForChildGTestProcess(),
+      TestTimeouts::test_launcher_timeout(),
+      launch_flags,
+      Bind(&SerialGTestCallback, callback_state, new_test_names));
+}
+
+void RunUnitTestsBatch(
+    TestLauncher* test_launcher,
+    UnitTestPlatformDelegate* platform_delegate,
+    const std::vector<std::string>& test_names,
+    int launch_flags) {
+  if (test_names.empty())
+    return;
+
+  // Create a dedicated temporary directory to store the xml result data
+  // per run to ensure clean state and make it possible to launch multiple
+  // processes in parallel.
+  base::FilePath output_file;
+  CHECK(platform_delegate->CreateTemporaryFile(&output_file));
+
+  CommandLine cmd_line(platform_delegate->GetCommandLineForChildGTestProcess(
+      test_names, output_file));
+
+  // Adjust the timeout depending on how many tests we're running
+  // (note that e.g. the last batch of tests will be smaller).
+  // TODO(phajdan.jr): Consider an adaptive timeout, which can change
+  // depending on how many tests ran and how many remain.
+  // Note: do NOT parse child's stdout to do that, it's known to be
+  // unreliable (e.g. buffering issues can mix up the output).
+  base::TimeDelta timeout =
+      test_names.size() * TestTimeouts::test_launcher_timeout();
+
+  GTestCallbackState callback_state;
+  callback_state.test_launcher = test_launcher;
+  callback_state.platform_delegate = platform_delegate;
+  callback_state.test_names = test_names;
+  callback_state.launch_flags = launch_flags;
+  callback_state.output_file = output_file;
+
+  test_launcher->LaunchChildGTestProcess(
+      cmd_line,
+      platform_delegate->GetWrapperForChildGTestProcess(),
+      timeout,
+      launch_flags,
+      Bind(&GTestCallback, callback_state));
+}
+
+UnitTestLauncherDelegate::UnitTestLauncherDelegate(
+    UnitTestPlatformDelegate* platform_delegate,
+    size_t batch_limit,
+    bool use_job_objects)
+    : platform_delegate_(platform_delegate),
+      batch_limit_(batch_limit),
+      use_job_objects_(use_job_objects) {
+}
+
+UnitTestLauncherDelegate::~UnitTestLauncherDelegate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return platform_delegate_->GetTests(output);
+}
+
+bool UnitTestLauncherDelegate::ShouldRunTest(const std::string& test_case_name,
+                                             const std::string& test_name) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // There is no additional logic to disable specific tests.
+  return true;
+}
+
+size_t UnitTestLauncherDelegate::RunTests(
+    TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  int launch_flags = use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0;
+
+  std::vector<std::string> batch;
+  for (size_t i = 0; i < test_names.size(); i++) {
+    batch.push_back(test_names[i]);
+
+    // Use 0 to indicate unlimited batch size.
+    if (batch.size() >= batch_limit_ && batch_limit_ != 0) {
+      RunUnitTestsBatch(test_launcher, platform_delegate_, batch, launch_flags);
+      batch.clear();
+    }
+  }
+
+  RunUnitTestsBatch(test_launcher, platform_delegate_, batch, launch_flags);
+
+  return test_names.size();
+}
+
+size_t UnitTestLauncherDelegate::RetryTests(
+    TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names) {
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      Bind(&RunUnitTestsSerially, test_launcher, platform_delegate_, test_names,
+           use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0));
+  return test_names.size();
+}
+
+}  // namespace base
diff --git a/base/test/launcher/unit_test_launcher.h b/base/test/launcher/unit_test_launcher.h
new file mode 100644
index 0000000..ca00f10
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher.h
@@ -0,0 +1,112 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_UNIT_TEST_LAUNCHER_H_
+#define BASE_TEST_LAUNCHER_UNIT_TEST_LAUNCHER_H_
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/test/launcher/test_launcher.h"
+
+namespace base {
+
+// Callback that runs a test suite and returns exit code.
+typedef base::Callback<int(void)> RunTestSuiteCallback;
+
+// Launches unit tests in given test suite. Returns exit code.
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite);
+
+// Same as above, but always runs tests serially.
+int LaunchUnitTestsSerially(int argc,
+                            char** argv,
+                            const RunTestSuiteCallback& run_test_suite);
+
+#if defined(OS_WIN)
+// Launches unit tests in given test suite. Returns exit code.
+// |use_job_objects| determines whether to use job objects.
+int LaunchUnitTests(int argc,
+                    wchar_t** argv,
+                    bool use_job_objects,
+                    const RunTestSuiteCallback& run_test_suite);
+#endif  // defined(OS_WIN)
+
+// Delegate to abstract away platform differences for unit tests.
+class UnitTestPlatformDelegate {
+ public:
+  // Called to get names of tests available for running. The delegate
+  // must put the result in |output| and return true on success.
+  virtual bool GetTests(std::vector<SplitTestName>* output) = 0;
+
+  // Called to create a temporary file. The delegate must put the resulting
+  // path in |path| and return true on success.
+  virtual bool CreateTemporaryFile(base::FilePath* path) = 0;
+
+  // Returns command line for child GTest process based on the command line
+  // of current process. |test_names| is a vector of test full names
+  // (e.g. "A.B"), |output_file| is path to the GTest XML output file.
+  virtual CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) = 0;
+
+  // Returns wrapper to use for child GTest process. Empty string means
+  // no wrapper.
+  virtual std::string GetWrapperForChildGTestProcess() = 0;
+
+  // Relaunch tests, e.g. after a crash.
+  virtual void RelaunchTests(TestLauncher* test_launcher,
+                             const std::vector<std::string>& test_names,
+                             int launch_flags) = 0;
+
+ protected:
+  ~UnitTestPlatformDelegate() {}
+};
+
+// Runs tests serially, each in its own process.
+void RunUnitTestsSerially(TestLauncher* test_launcher,
+                          UnitTestPlatformDelegate* platform_delegate,
+                          const std::vector<std::string>& test_names,
+                          int launch_flags);
+
+// Runs tests in batches (each batch in its own process).
+void RunUnitTestsBatch(TestLauncher* test_launcher,
+                       UnitTestPlatformDelegate* platform_delegate,
+                       const std::vector<std::string>& test_names,
+                       int launch_flags);
+
+// Test launcher delegate for unit tests (mostly to support batching).
+class UnitTestLauncherDelegate : public TestLauncherDelegate {
+ public:
+  UnitTestLauncherDelegate(UnitTestPlatformDelegate* delegate,
+                           size_t batch_limit,
+                           bool use_job_objects);
+  ~UnitTestLauncherDelegate() override;
+
+ private:
+  // TestLauncherDelegate:
+  bool GetTests(std::vector<SplitTestName>* output) override;
+  bool ShouldRunTest(const std::string& test_case_name,
+                     const std::string& test_name) override;
+  size_t RunTests(TestLauncher* test_launcher,
+                  const std::vector<std::string>& test_names) override;
+  size_t RetryTests(TestLauncher* test_launcher,
+                    const std::vector<std::string>& test_names) override;
+
+  ThreadChecker thread_checker_;
+
+  UnitTestPlatformDelegate* platform_delegate_;
+
+  // Maximum number of tests to run in a single batch.
+  size_t batch_limit_;
+
+  // Determines whether we use job objects on Windows.
+  bool use_job_objects_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnitTestLauncherDelegate);
+};
+
+}   // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_UNIT_TEST_LAUNCHER_H_
diff --git a/base/test/launcher/unit_test_launcher_ios.cc b/base/test/launcher/unit_test_launcher_ios.cc
new file mode 100644
index 0000000..acb6c71
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher_ios.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/unit_test_launcher.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/test_switches.h"
+
+namespace base {
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CHECK(CommandLine::InitializedForCurrentProcess() ||
+        CommandLine::Init(argc, argv));
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherListTests)) {
+    FilePath list_path(command_line->GetSwitchValuePath(
+        switches::kTestLauncherListTests));
+    if (WriteCompiledInTestsToFile(list_path)) {
+      return 0;
+    } else {
+      LOG(ERROR) << "Failed to write list of tests.";
+      return 1;
+    }
+  } else if (command_line->HasSwitch(
+                 switches::kTestLauncherPrintWritablePath)) {
+    fprintf(stdout, "%s", mac::GetUserLibraryPath().value().c_str());
+    fflush(stdout);
+    return 0;
+  }
+
+  return run_test_suite.Run();
+}
+
+}  // namespace base
diff --git a/base/test/malloc_wrapper.cc b/base/test/malloc_wrapper.cc
new file mode 100644
index 0000000..eb280a3
--- /dev/null
+++ b/base/test/malloc_wrapper.cc
@@ -0,0 +1,11 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "malloc_wrapper.h"
+
+#include <stdlib.h>
+
+void* MallocWrapper(size_t size) {
+  return malloc(size);
+}
diff --git a/base/test/malloc_wrapper.h b/base/test/malloc_wrapper.h
new file mode 100644
index 0000000..0fa7dbb
--- /dev/null
+++ b/base/test/malloc_wrapper.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MALLOC_WRAPPER_H_
+#define BASE_TEST_MALLOC_WRAPPER_H_
+
+#include "base/basictypes.h"
+
+// BASE_EXPORT depends on COMPONENT_BUILD.
+// This will always be a separate shared library, so don't use BASE_EXPORT here.
+#if defined(WIN32)
+#define MALLOC_WRAPPER_EXPORT __declspec(dllexport)
+#else
+#define MALLOC_WRAPPER_EXPORT __attribute__((visibility("default")))
+#endif  // defined(WIN32)
+
+// Calls malloc directly.
+MALLOC_WRAPPER_EXPORT void* MallocWrapper(size_t size);
+
+#endif  // BASE_TEST_MALLOC_WRAPPER_H_
diff --git a/base/test/mock_chrome_application_mac.h b/base/test/mock_chrome_application_mac.h
new file mode 100644
index 0000000..ffa3080
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+#define BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+
+#if defined(__OBJC__)
+
+#import <AppKit/AppKit.h>
+
+#include "base/mac/scoped_sending_event.h"
+#include "base/message_loop/message_pump_mac.h"
+
+// A basic implementation of CrAppProtocol and
+// CrAppControlProtocol. This can be used in tests that need an
+// NSApplication and use a runloop, or which need a ScopedSendingEvent
+// when handling a nested event loop.
+@interface MockCrApp : NSApplication<CrAppProtocol,
+                                     CrAppControlProtocol> {
+ @private
+  BOOL handlingSendEvent_;
+}
+@end
+
+#endif
+
+// To be used to instantiate MockCrApp from C++ code.
+namespace mock_cr_app {
+void RegisterMockCrApp();
+}  // namespace mock_cr_app
+
+#endif  // BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
diff --git a/base/test/mock_chrome_application_mac.mm b/base/test/mock_chrome_application_mac.mm
new file mode 100644
index 0000000..0890553
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.mm
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_chrome_application_mac.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+
+@implementation MockCrApp
+
++ (NSApplication*)sharedApplication {
+  NSApplication* app = [super sharedApplication];
+  DCHECK([app conformsToProtocol:@protocol(CrAppControlProtocol)])
+      << "Existing NSApp (class " << [[app className] UTF8String]
+      << ") does not conform to required protocol.";
+  DCHECK(base::MessagePumpMac::UsingCrApp())
+      << "MessagePumpMac::Create() was called before "
+      << "+[MockCrApp sharedApplication]";
+  return app;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+  base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
+  [super sendEvent:event];
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+  handlingSendEvent_ = handlingSendEvent;
+}
+
+- (BOOL)isHandlingSendEvent {
+  return handlingSendEvent_;
+}
+
+@end
+
+namespace mock_cr_app {
+
+void RegisterMockCrApp() {
+  [MockCrApp sharedApplication];
+}
+
+}  // namespace mock_cr_app
diff --git a/base/test/mock_devices_changed_observer.cc b/base/test/mock_devices_changed_observer.cc
new file mode 100644
index 0000000..c05f26a
--- /dev/null
+++ b/base/test/mock_devices_changed_observer.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_devices_changed_observer.h"
+
+namespace base {
+
+MockDevicesChangedObserver::MockDevicesChangedObserver() {
+}
+
+MockDevicesChangedObserver::~MockDevicesChangedObserver() {
+}
+
+}  // namespace base
diff --git a/base/test/mock_devices_changed_observer.h b/base/test/mock_devices_changed_observer.h
new file mode 100644
index 0000000..3255002
--- /dev/null
+++ b/base/test/mock_devices_changed_observer.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+#define BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+
+#include <string>
+
+#include "base/system_monitor/system_monitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+class MockDevicesChangedObserver
+    : public base::SystemMonitor::DevicesChangedObserver {
+ public:
+  MockDevicesChangedObserver();
+  ~MockDevicesChangedObserver();
+
+  MOCK_METHOD1(OnDevicesChanged,
+               void(base::SystemMonitor::DeviceType device_type));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockDevicesChangedObserver);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
diff --git a/base/test/mock_entropy_provider.cc b/base/test/mock_entropy_provider.cc
new file mode 100644
index 0000000..75186a5
--- /dev/null
+++ b/base/test/mock_entropy_provider.cc
@@ -0,0 +1,16 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_entropy_provider.h"
+
+namespace base {
+
+MockEntropyProvider::~MockEntropyProvider() {}
+
+double MockEntropyProvider::GetEntropyForTrial(
+    const std::string& trial_name, uint32 randomization_seed) const {
+  return 0.5;
+}
+
+}  // namespace base
diff --git a/base/test/mock_entropy_provider.h b/base/test/mock_entropy_provider.h
new file mode 100644
index 0000000..c55bea6
--- /dev/null
+++ b/base/test/mock_entropy_provider.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
+#define BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
+
+#include "base/metrics/field_trial.h"
+
+namespace base {
+
+class MockEntropyProvider : public base::FieldTrial::EntropyProvider {
+ public:
+  ~MockEntropyProvider() override;
+
+  // base::FieldTrial::EntropyProvider:
+  double GetEntropyForTrial(const std::string& trial_name,
+                            uint32 randomization_seed) const override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
diff --git a/base/test/mock_log.cc b/base/test/mock_log.cc
new file mode 100644
index 0000000..fa511d4
--- /dev/null
+++ b/base/test/mock_log.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/mock_log.h"
+
+namespace base {
+namespace test {
+
+// static
+MockLog* MockLog::g_instance_ = nullptr;
+Lock MockLog::g_lock;
+
+MockLog::MockLog() : is_capturing_logs_(false) {
+}
+
+MockLog::~MockLog() {
+  if (is_capturing_logs_) {
+    StopCapturingLogs();
+  }
+}
+
+void MockLog::StartCapturingLogs() {
+  AutoLock scoped_lock(g_lock);
+
+  // We don't use CHECK(), which can generate a new LOG message, and
+  // thus can confuse MockLog objects or other registered
+  // LogSinks.
+  RAW_CHECK(!is_capturing_logs_);
+  RAW_CHECK(!g_instance_);
+
+  is_capturing_logs_ = true;
+  g_instance_ = this;
+  previous_handler_ = logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(LogMessageHandler);
+}
+
+void MockLog::StopCapturingLogs() {
+  AutoLock scoped_lock(g_lock);
+
+  // We don't use CHECK(), which can generate a new LOG message, and
+  // thus can confuse MockLog objects or other registered
+  // LogSinks.
+  RAW_CHECK(is_capturing_logs_);
+  RAW_CHECK(g_instance_ == this);
+
+  is_capturing_logs_ = false;
+  logging::SetLogMessageHandler(previous_handler_);
+  g_instance_ = nullptr;
+}
+
+// static
+bool MockLog::LogMessageHandler(int severity,
+                                const char* file,
+                                int line,
+                                size_t message_start,
+                                const std::string& str) {
+  // gMock guarantees thread-safety for calling a mocked method
+  // (https://code.google.com/p/googlemock/wiki/CookBook#Using_Google_Mock_and_Threads)
+  // but we also need to make sure that Start/StopCapturingLogs are synchronized
+  // with LogMessageHandler.
+  AutoLock scoped_lock(g_lock);
+
+  return g_instance_->Log(severity, file, line, message_start, str);
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/mock_log.h b/base/test/mock_log.h
new file mode 100644
index 0000000..315ef1f
--- /dev/null
+++ b/base/test/mock_log.h
@@ -0,0 +1,98 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MOCK_LOG_H_
+#define BASE_TEST_MOCK_LOG_H_
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+namespace test {
+
+// A MockLog object intercepts LOG() messages issued during its lifespan.  Using
+// this together with gMock, it's very easy to test how a piece of code calls
+// LOG().  The typical usage:
+//
+//   TEST(FooTest, LogsCorrectly) {
+//     MockLog log;
+//
+//     // We expect the WARNING "Something bad!" exactly twice.
+//     EXPECT_CALL(log, Log(WARNING, _, "Something bad!"))
+//         .Times(2);
+//
+//     // We allow foo.cc to call LOG(INFO) any number of times.
+//     EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _))
+//         .Times(AnyNumber());
+//
+//     log.StartCapturingLogs();  // Call this after done setting expectations.
+//     Foo();  // Exercises the code under test.
+//   }
+//
+// CAVEAT: base/logging does not allow a thread to call LOG() again when it's
+// already inside a LOG() call.  Doing so will cause a deadlock.  Therefore,
+// it's the user's responsibility to not call LOG() in an action triggered by
+// MockLog::Log().  You may call RAW_LOG() instead.
+class MockLog {
+ public:
+  // Creates a MockLog object that is not capturing logs.  If it were to start
+  // to capture logs, it could be a problem if some other threads already exist
+  // and are logging, as the user hasn't had a chance to set up expectation on
+  // this object yet (calling a mock method before setting the expectation is
+  // UNDEFINED behavior).
+  MockLog();
+
+  // When the object is destructed, it stops intercepting logs.
+  ~MockLog();
+
+  // Starts log capturing if the object isn't already doing so.
+  // Otherwise crashes.
+  void StartCapturingLogs();
+
+  // Stops log capturing if the object is capturing logs.  Otherwise crashes.
+  void StopCapturingLogs();
+
+  // Log method is invoked for every log message before it's sent to other log
+  // destinations (if any).  The method should return true to signal that it
+  // handled the message and the message should not be sent to other log
+  // destinations.
+  MOCK_METHOD5(Log,
+               bool(int severity,
+                    const char* file,
+                    int line,
+                    size_t message_start,
+                    const std::string& str));
+
+ private:
+  // The currently active mock log.
+  static MockLog* g_instance_;
+
+  // Lock protecting access to g_instance_.
+  static Lock g_lock;
+
+  // Static function which is set as the logging message handler.
+  // Called once for each message.
+  static bool LogMessageHandler(int severity,
+                                const char* file,
+                                int line,
+                                size_t message_start,
+                                const std::string& str);
+
+  // True if this object is currently capturing logs.
+  bool is_capturing_logs_;
+
+  // The previous handler to restore when the MockLog is destroyed.
+  logging::LogMessageHandlerFunction previous_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockLog);
+};
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_LOG_H_
diff --git a/base/test/multiprocess_test.cc b/base/test/multiprocess_test.cc
new file mode 100644
index 0000000..2cd6d8c
--- /dev/null
+++ b/base/test/multiprocess_test.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/multiprocess_test.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+
+namespace base {
+
+#if !defined(OS_ANDROID)
+Process SpawnMultiProcessTestChild(
+    const std::string& procname,
+    const CommandLine& base_command_line,
+    const LaunchOptions& options) {
+  CommandLine command_line(base_command_line);
+  // TODO(viettrungluu): See comment above |MakeCmdLine()| in the header file.
+  // This is a temporary hack, since |MakeCmdLine()| has to provide a full
+  // command line.
+  if (!command_line.HasSwitch(switches::kTestChildProcess))
+    command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+
+  return LaunchProcess(command_line, options);
+}
+#endif  // !defined(OS_ANDROID)
+
+CommandLine GetMultiProcessTestChildBaseCommandLine() {
+  CommandLine cmd_line = *CommandLine::ForCurrentProcess();
+  cmd_line.SetProgram(MakeAbsoluteFilePath(cmd_line.GetProgram()));
+  return cmd_line;
+}
+
+// MultiProcessTest ------------------------------------------------------------
+
+MultiProcessTest::MultiProcessTest() {
+}
+
+Process MultiProcessTest::SpawnChild(const std::string& procname) {
+  LaunchOptions options;
+#if defined(OS_WIN)
+  options.start_hidden = true;
+#endif
+  return SpawnChildWithOptions(procname, options);
+}
+
+Process MultiProcessTest::SpawnChildWithOptions(
+    const std::string& procname,
+    const LaunchOptions& options) {
+  return SpawnMultiProcessTestChild(procname, MakeCmdLine(procname), options);
+}
+
+CommandLine MultiProcessTest::MakeCmdLine(const std::string& procname) {
+  CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
+  command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+  return command_line;
+}
+
+}  // namespace base
diff --git a/base/test/multiprocess_test.h b/base/test/multiprocess_test.h
new file mode 100644
index 0000000..b1c73df
--- /dev/null
+++ b/base/test/multiprocess_test.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MULTIPROCESS_TEST_H_
+#define BASE_TEST_MULTIPROCESS_TEST_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "build/build_config.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class CommandLine;
+
+// Helpers to spawn a child for a multiprocess test and execute a designated
+// function. Use these when you already have another base class for your test
+// fixture, but you want (some) of your tests to be multiprocess (otherwise you
+// may just want to derive your fixture from |MultiProcessTest|, below).
+//
+// Use these helpers as follows:
+//
+//   TEST_F(MyTest, ATest) {
+//     CommandLine command_line(
+//         base::GetMultiProcessTestChildBaseCommandLine());
+//     // Maybe add our own switches to |command_line|....
+//
+//     LaunchOptions options;
+//     // Maybe set some options (e.g., |start_hidden| on Windows)....
+//
+//     // Start a child process and run |a_test_func|.
+//     base::Process test_child_process =
+//         base::SpawnMultiProcessTestChild("a_test_func", command_line,
+//                                          options);
+//
+//     // Do stuff involving |test_child_process| and the child process....
+//
+//     int rv = -1;
+//     ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
+//         TestTimeouts::action_timeout(), &rv));
+//     EXPECT_EQ(0, rv);
+//   }
+//
+//   // Note: |MULTIPROCESS_TEST_MAIN()| is defined in
+//   // testing/multi_process_function_list.h.
+//   MULTIPROCESS_TEST_MAIN(a_test_func) {
+//     // Code here runs in a child process....
+//     return 0;
+//   }
+
+// Spawns a child process and executes the function |procname| declared using
+// |MULTIPROCESS_TEST_MAIN()| or |MULTIPROCESS_TEST_MAIN_WITH_SETUP()|.
+// |command_line| should be as provided by
+// |GetMultiProcessTestChildBaseCommandLine()| (below), possibly with arguments
+// added. Note: On Windows, you probably want to set |options.start_hidden|.
+Process SpawnMultiProcessTestChild(
+    const std::string& procname,
+    const CommandLine& command_line,
+    const LaunchOptions& options);
+
+// Gets the base command line for |SpawnMultiProcessTestChild()|. To this, you
+// may add any flags needed for your child process.
+CommandLine GetMultiProcessTestChildBaseCommandLine();
+
+// MultiProcessTest ------------------------------------------------------------
+
+// A MultiProcessTest is a test class which makes it easier to
+// write a test which requires code running out of process.
+//
+// To create a multiprocess test simply follow these steps:
+//
+// 1) Derive your test from MultiProcessTest. Example:
+//
+//    class MyTest : public MultiProcessTest {
+//    };
+//
+//    TEST_F(MyTest, TestCaseName) {
+//      ...
+//    }
+//
+// 2) Create a mainline function for the child processes and include
+//    testing/multiprocess_func_list.h.
+//    See the declaration of the MULTIPROCESS_TEST_MAIN macro
+//    in that file for an example.
+// 3) Call SpawnChild("foo"), where "foo" is the name of
+//    the function you wish to run in the child processes.
+// That's it!
+class MultiProcessTest : public PlatformTest {
+ public:
+  MultiProcessTest();
+
+ protected:
+  // Run a child process.
+  // 'procname' is the name of a function which the child will
+  // execute.  It must be exported from this library in order to
+  // run.
+  //
+  // Example signature:
+  //    extern "C" int __declspec(dllexport) FooBar() {
+  //         // do client work here
+  //    }
+  //
+  // Returns the child process.
+  Process SpawnChild(const std::string& procname);
+
+  // Run a child process using the given launch options.
+  //
+  // Note: On Windows, you probably want to set |options.start_hidden|.
+  Process SpawnChildWithOptions(const std::string& procname,
+                                const LaunchOptions& options);
+
+  // Set up the command line used to spawn the child process.
+  // Override this to add things to the command line (calling this first in the
+  // override).
+  // Note that currently some tests rely on this providing a full command line,
+  // which they then use directly with |LaunchProcess()|.
+  // TODO(viettrungluu): Remove this and add a virtual
+  // |ModifyChildCommandLine()|; make the two divergent uses more sane.
+  virtual CommandLine MakeCmdLine(const std::string& procname);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MultiProcessTest);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MULTIPROCESS_TEST_H_
diff --git a/base/test/multiprocess_test_android.cc b/base/test/multiprocess_test_android.cc
new file mode 100644
index 0000000..dc489d1
--- /dev/null
+++ b/base/test/multiprocess_test_android.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/multiprocess_test.h"
+
+#include <unistd.h>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/posix/global_descriptors.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+// A very basic implementation for Android. On Android tests can run in an APK
+// and we don't have an executable to exec*. This implementation does the bare
+// minimum to execute the method specified by procname (in the child process).
+//  - All options except |fds_to_remap| are ignored.
+Process SpawnMultiProcessTestChild(const std::string& procname,
+                                   const CommandLine& base_command_line,
+                                   const LaunchOptions& options) {
+  // TODO(viettrungluu): The FD-remapping done below is wrong in the presence of
+  // cycles (e.g., fd1 -> fd2, fd2 -> fd1). crbug.com/326576
+  FileHandleMappingVector empty;
+  const FileHandleMappingVector* fds_to_remap =
+      options.fds_to_remap ? options.fds_to_remap : &empty;
+
+  pid_t pid = fork();
+
+  if (pid < 0) {
+    PLOG(ERROR) << "fork";
+    return Process();
+  }
+  if (pid > 0) {
+    // Parent process.
+    return Process(pid);
+  }
+  // Child process.
+  base::hash_set<int> fds_to_keep_open;
+  for (FileHandleMappingVector::const_iterator it = fds_to_remap->begin();
+       it != fds_to_remap->end(); ++it) {
+    fds_to_keep_open.insert(it->first);
+  }
+  // Keep standard FDs (stdin, stdout, stderr, etc.) open since this
+  // is not meant to spawn a daemon.
+  int base = GlobalDescriptors::kBaseDescriptor;
+  for (int fd = base; fd < sysconf(_SC_OPEN_MAX); ++fd) {
+    if (fds_to_keep_open.find(fd) == fds_to_keep_open.end()) {
+      close(fd);
+    }
+  }
+  for (FileHandleMappingVector::const_iterator it = fds_to_remap->begin();
+       it != fds_to_remap->end(); ++it) {
+    int old_fd = it->first;
+    int new_fd = it->second;
+    if (dup2(old_fd, new_fd) < 0) {
+      PLOG(FATAL) << "dup2";
+    }
+    close(old_fd);
+  }
+  CommandLine::Reset();
+  CommandLine::Init(0, nullptr);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->InitFromArgv(base_command_line.argv());
+  if (!command_line->HasSwitch(switches::kTestChildProcess))
+    command_line->AppendSwitchASCII(switches::kTestChildProcess, procname);
+
+  _exit(multi_process_function_list::InvokeChildProcessTest(procname));
+  return Process();
+}
+
+}  // namespace base
diff --git a/base/test/null_task_runner.cc b/base/test/null_task_runner.cc
new file mode 100644
index 0000000..ffa6bdf
--- /dev/null
+++ b/base/test/null_task_runner.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/null_task_runner.h"
+
+namespace base {
+
+NullTaskRunner::NullTaskRunner() {}
+
+NullTaskRunner::~NullTaskRunner() {}
+
+bool NullTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return false;
+}
+
+bool NullTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return false;
+}
+
+bool NullTaskRunner::RunsTasksOnCurrentThread() const {
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/null_task_runner.h b/base/test/null_task_runner.h
new file mode 100644
index 0000000..0f44751
--- /dev/null
+++ b/base/test/null_task_runner.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_NULL_TASK_RUNNER_H_
+#define BASE_TEST_NULL_TASK_RUNNER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// Helper class for tests that need to provide an implementation of a
+// *TaskRunner class but don't actually care about tasks being run.
+
+class NullTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  NullTaskRunner();
+
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override;
+  // Always returns true to avoid triggering DCHECKs.
+  bool RunsTasksOnCurrentThread() const override;
+
+ protected:
+  ~NullTaskRunner() override;
+
+  DISALLOW_COPY_AND_ASSIGN(NullTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_NULL_TASK_RUNNER_H_
diff --git a/base/test/opaque_ref_counted.cc b/base/test/opaque_ref_counted.cc
new file mode 100644
index 0000000..ed6c36f
--- /dev/null
+++ b/base/test/opaque_ref_counted.cc
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/opaque_ref_counted.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class OpaqueRefCounted : public RefCounted<OpaqueRefCounted> {
+ public:
+  OpaqueRefCounted() {}
+
+  int Return42() { return 42; }
+
+ private:
+  virtual ~OpaqueRefCounted() {}
+
+  friend RefCounted<OpaqueRefCounted>;
+  DISALLOW_COPY_AND_ASSIGN(OpaqueRefCounted);
+};
+
+scoped_refptr<OpaqueRefCounted> MakeOpaqueRefCounted() {
+  return new OpaqueRefCounted();
+}
+
+void TestOpaqueRefCounted(scoped_refptr<OpaqueRefCounted> p) {
+  EXPECT_EQ(42, p->Return42());
+}
+
+}  // namespace base
+
+template class scoped_refptr<base::OpaqueRefCounted>;
diff --git a/base/test/opaque_ref_counted.h b/base/test/opaque_ref_counted.h
new file mode 100644
index 0000000..faf6a65
--- /dev/null
+++ b/base/test/opaque_ref_counted.h
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_OPAQUE_REF_COUNTED_H_
+#define BASE_TEST_OPAQUE_REF_COUNTED_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// OpaqueRefCounted is a test class for scoped_refptr to ensure it still works
+// when the pointed-to type is opaque (i.e., incomplete).
+class OpaqueRefCounted;
+
+// Test functions that return and accept scoped_refptr<OpaqueRefCounted> values.
+scoped_refptr<OpaqueRefCounted> MakeOpaqueRefCounted();
+void TestOpaqueRefCounted(scoped_refptr<OpaqueRefCounted> p);
+
+}  // namespace base
+
+extern template class scoped_refptr<base::OpaqueRefCounted>;
+
+#endif  // BASE_TEST_OPAQUE_REF_COUNTED_H_
diff --git a/base/test/perf_log.cc b/base/test/perf_log.cc
new file mode 100644
index 0000000..22884b8
--- /dev/null
+++ b/base/test/perf_log.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_log.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+static FILE* perf_log_file = NULL;
+
+bool InitPerfLog(const FilePath& log_file) {
+  if (perf_log_file) {
+    // trying to initialize twice
+    NOTREACHED();
+    return false;
+  }
+
+  perf_log_file = OpenFile(log_file, "w");
+  return perf_log_file != NULL;
+}
+
+void FinalizePerfLog() {
+  if (!perf_log_file) {
+    // trying to cleanup without initializing
+    NOTREACHED();
+    return;
+  }
+  base::CloseFile(perf_log_file);
+}
+
+void LogPerfResult(const char* test_name, double value, const char* units) {
+  if (!perf_log_file) {
+    NOTREACHED();
+    return;
+  }
+
+  fprintf(perf_log_file, "%s\t%g\t%s\n", test_name, value, units);
+  printf("%s\t%g\t%s\n", test_name, value, units);
+  fflush(stdout);
+}
+
+}  // namespace base
diff --git a/base/test/perf_log.h b/base/test/perf_log.h
new file mode 100644
index 0000000..5d6ed9f
--- /dev/null
+++ b/base/test/perf_log.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_LOG_H_
+#define BASE_TEST_PERF_LOG_H_
+
+namespace base {
+
+class FilePath;
+
+// Initializes and finalizes the perf log. These functions should be
+// called at the beginning and end (respectively) of running all the
+// performance tests. The init function returns true on success.
+bool InitPerfLog(const FilePath& log_path);
+void FinalizePerfLog();
+
+// Writes to the perf result log the given 'value' resulting from the
+// named 'test'. The units are to aid in reading the log by people.
+void LogPerfResult(const char* test_name, double value, const char* units);
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_LOG_H_
diff --git a/base/test/perf_test_suite.cc b/base/test/perf_test_suite.cc
new file mode 100644
index 0000000..415aaef
--- /dev/null
+++ b/base/test/perf_test_suite.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_test_suite.h"
+
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/test/perf_log.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+PerfTestSuite::PerfTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
+
+void PerfTestSuite::Initialize() {
+  TestSuite::Initialize();
+
+  // Initialize the perf timer log
+  FilePath log_path =
+      CommandLine::ForCurrentProcess()->GetSwitchValuePath("log-file");
+  if (log_path.empty()) {
+    PathService::Get(FILE_EXE, &log_path);
+#if defined(OS_ANDROID)
+    base::FilePath tmp_dir;
+    PathService::Get(base::DIR_CACHE, &tmp_dir);
+    log_path = tmp_dir.Append(log_path.BaseName());
+#endif
+    log_path = log_path.ReplaceExtension(FILE_PATH_LITERAL("log"));
+    log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
+  }
+  ASSERT_TRUE(InitPerfLog(log_path));
+
+  // Raise to high priority to have more precise measurements. Since we don't
+  // aim at 1% precision, it is not necessary to run at realtime level.
+  if (!debug::BeingDebugged())
+    RaiseProcessToHighPriority();
+}
+
+void PerfTestSuite::Shutdown() {
+  TestSuite::Shutdown();
+  FinalizePerfLog();
+}
+
+}  // namespace base
diff --git a/base/test/perf_test_suite.h b/base/test/perf_test_suite.h
new file mode 100644
index 0000000..52528f0
--- /dev/null
+++ b/base/test/perf_test_suite.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_TEST_SUITE_H_
+#define BASE_TEST_PERF_TEST_SUITE_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+class PerfTestSuite : public TestSuite {
+ public:
+  PerfTestSuite(int argc, char** argv);
+
+  void Initialize() override;
+  void Shutdown() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_TEST_SUITE_H_
diff --git a/base/test/perf_time_logger.cc b/base/test/perf_time_logger.cc
new file mode 100644
index 0000000..c05ba51
--- /dev/null
+++ b/base/test/perf_time_logger.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_time_logger.h"
+
+#include "base/test/perf_log.h"
+
+namespace base {
+
+PerfTimeLogger::PerfTimeLogger(const char* test_name)
+    : logged_(false), test_name_(test_name) {}
+
+PerfTimeLogger::~PerfTimeLogger() {
+  if (!logged_)
+    Done();
+}
+
+void PerfTimeLogger::Done() {
+  // we use a floating-point millisecond value because it is more
+  // intuitive than microseconds and we want more precision than
+  // integer milliseconds
+  LogPerfResult(test_name_.c_str(), timer_.Elapsed().InMillisecondsF(), "ms");
+  logged_ = true;
+}
+
+}  // namespace base
diff --git a/base/test/perf_time_logger.h b/base/test/perf_time_logger.h
new file mode 100644
index 0000000..403b272
--- /dev/null
+++ b/base/test/perf_time_logger.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_TIME_LOGGER_H_
+#define BASE_TEST_PERF_TIME_LOGGER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+// Automates calling LogPerfResult for the common case where you want
+// to measure the time that something took. Call Done() when the test
+// is complete if you do extra work after the test or there are stack
+// objects with potentially expensive constructors. Otherwise, this
+// class with automatically log on destruction.
+class PerfTimeLogger {
+ public:
+  explicit PerfTimeLogger(const char* test_name);
+  ~PerfTimeLogger();
+
+  void Done();
+
+ private:
+  bool logged_;
+  std::string test_name_;
+  ElapsedTimer timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PerfTimeLogger);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_TIME_LOGGER_H_
diff --git a/base/test/power_monitor_test_base.cc b/base/test/power_monitor_test_base.cc
new file mode 100644
index 0000000..73438ea
--- /dev/null
+++ b/base/test/power_monitor_test_base.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/power_monitor_test_base.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+PowerMonitorTestSource::PowerMonitorTestSource()
+    : test_on_battery_power_(false) {
+}
+
+PowerMonitorTestSource::~PowerMonitorTestSource() {
+}
+
+void PowerMonitorTestSource::GeneratePowerStateEvent(bool on_battery_power) {
+  test_on_battery_power_ = on_battery_power;
+  ProcessPowerEvent(POWER_STATE_EVENT);
+  message_loop_.RunUntilIdle();
+}
+
+void PowerMonitorTestSource::GenerateSuspendEvent() {
+  ProcessPowerEvent(SUSPEND_EVENT);
+  message_loop_.RunUntilIdle();
+}
+
+void PowerMonitorTestSource::GenerateResumeEvent() {
+  ProcessPowerEvent(RESUME_EVENT);
+  message_loop_.RunUntilIdle();
+}
+
+bool PowerMonitorTestSource::IsOnBatteryPowerImpl() {
+  return test_on_battery_power_;
+};
+
+PowerMonitorTestObserver::PowerMonitorTestObserver()
+    : last_power_state_(false),
+      power_state_changes_(0),
+      suspends_(0),
+      resumes_(0) {
+}
+
+PowerMonitorTestObserver::~PowerMonitorTestObserver() {
+}
+
+// PowerObserver callbacks.
+void PowerMonitorTestObserver::OnPowerStateChange(bool on_battery_power) {
+  last_power_state_ = on_battery_power;
+  power_state_changes_++;
+}
+
+void PowerMonitorTestObserver::OnSuspend() {
+  suspends_++;
+}
+
+void PowerMonitorTestObserver::OnResume() {
+  resumes_++;
+}
+
+}  // namespace base
diff --git a/base/test/power_monitor_test_base.h b/base/test/power_monitor_test_base.h
new file mode 100644
index 0000000..4655eae
--- /dev/null
+++ b/base/test/power_monitor_test_base.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_POWER_MONITOR_TEST_BASE_H_
+#define BASE_TEST_POWER_MONITOR_TEST_BASE_H_
+
+#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+class PowerMonitorTestSource : public PowerMonitorSource {
+ public:
+  PowerMonitorTestSource();
+  ~PowerMonitorTestSource() override;
+
+  void GeneratePowerStateEvent(bool on_battery_power);
+  void GenerateSuspendEvent();
+  void GenerateResumeEvent();
+
+ protected:
+  bool IsOnBatteryPowerImpl() override;
+
+  bool test_on_battery_power_;
+  MessageLoop message_loop_;
+};
+
+class PowerMonitorTestObserver : public PowerObserver {
+ public:
+  PowerMonitorTestObserver();
+  ~PowerMonitorTestObserver() override;
+
+  // PowerObserver callbacks.
+  void OnPowerStateChange(bool on_battery_power) override;
+  void OnSuspend() override;
+  void OnResume() override;
+
+  // Test status counts.
+  bool last_power_state() { return last_power_state_; }
+  int power_state_changes() { return power_state_changes_; }
+  int suspends() { return suspends_; }
+  int resumes() { return resumes_; }
+
+ private:
+  bool last_power_state_; // Last power state we were notified of.
+  int power_state_changes_;  // Count of OnPowerStateChange notifications.
+  int suspends_;  // Count of OnSuspend notifications.
+  int resumes_;  // Count of OnResume notifications.
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_POWER_MONITOR_TEST_BASE_H_
diff --git a/base/test/run_all_perftests.cc b/base/test/run_all_perftests.cc
new file mode 100644
index 0000000..6e38109
--- /dev/null
+++ b/base/test/run_all_perftests.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_test_suite.h"
+
+int main(int argc, char** argv) {
+  return base::PerfTestSuite(argc, argv).Run();
+}
diff --git a/base/test/run_all_unittests.cc b/base/test/run_all_unittests.cc
new file mode 100644
index 0000000..93cb8cb
--- /dev/null
+++ b/base/test/run_all_unittests.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#include "base/test/test_file_util.h"
+#endif
+
+namespace {
+
+class NoAtExitBaseTestSuite : public base::TestSuite {
+ public:
+  NoAtExitBaseTestSuite(int argc, char** argv)
+      : base::TestSuite(argc, argv, false) {
+  }
+};
+
+int RunTestSuite(int argc, char** argv) {
+  return NoAtExitBaseTestSuite(argc, argv).Run();
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+#if defined(OS_ANDROID)
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::RegisterContentUriTestUtils(env);
+#else
+  base::AtExitManager at_exit;
+#endif
+  return base::LaunchUnitTests(argc,
+                               argv,
+                               base::Bind(&RunTestSuite, argc, argv));
+}
diff --git a/base/test/scoped_locale.cc b/base/test/scoped_locale.cc
new file mode 100644
index 0000000..35b3fbe
--- /dev/null
+++ b/base/test/scoped_locale.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_locale.h"
+
+#include <locale.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+ScopedLocale::ScopedLocale(const std::string& locale) {
+  prev_locale_ = setlocale(LC_ALL, NULL);
+  EXPECT_TRUE(setlocale(LC_ALL, locale.c_str()) != NULL) <<
+      "Failed to set locale: " << locale;
+}
+
+ScopedLocale::~ScopedLocale() {
+  EXPECT_STREQ(prev_locale_.c_str(), setlocale(LC_ALL, prev_locale_.c_str()));
+}
+
+}  // namespace base
diff --git a/base/test/scoped_locale.h b/base/test/scoped_locale.h
new file mode 100644
index 0000000..a9f9348
--- /dev/null
+++ b/base/test/scoped_locale.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_LOCALE_H_
+#define BASE_TEST_SCOPED_LOCALE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Sets the given |locale| on construction, and restores the previous locale
+// on destruction.
+class ScopedLocale {
+ public:
+  explicit ScopedLocale(const std::string& locale);
+  ~ScopedLocale();
+
+ private:
+  std::string prev_locale_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedLocale);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_LOCALE_H_
diff --git a/base/test/scoped_path_override.cc b/base/test/scoped_path_override.cc
new file mode 100644
index 0000000..9a77611
--- /dev/null
+++ b/base/test/scoped_path_override.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_path_override.h"
+
+#include "base/logging.h"
+#include "base/path_service.h"
+
+namespace base {
+
+ScopedPathOverride::ScopedPathOverride(int key) : key_(key) {
+  bool result = temp_dir_.CreateUniqueTempDir();
+  CHECK(result);
+  result = PathService::Override(key, temp_dir_.path());
+  CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key, const base::FilePath& dir)
+    : key_(key) {
+  bool result = PathService::Override(key, dir);
+  CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key,
+                                       const FilePath& path,
+                                       bool is_absolute,
+                                       bool create)
+    : key_(key) {
+  bool result =
+      PathService::OverrideAndCreateIfNeeded(key, path, is_absolute, create);
+  CHECK(result);
+}
+
+ScopedPathOverride::~ScopedPathOverride() {
+   bool result = PathService::RemoveOverride(key_);
+   CHECK(result) << "The override seems to have been removed already!";
+}
+
+}  // namespace base
diff --git a/base/test/scoped_path_override.h b/base/test/scoped_path_override.h
new file mode 100644
index 0000000..c6cffe2
--- /dev/null
+++ b/base/test/scoped_path_override.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SCOPED_PATH_OVERRIDE_H_
+#define BASE_TEST_SCOPED_PATH_OVERRIDE_H_
+
+#include "base/basictypes.h"
+#include "base/files/scoped_temp_dir.h"
+
+namespace base {
+
+class FilePath;
+
+// Sets a path override on construction, and removes it when the object goes out
+// of scope. This class is intended to be used by tests that need to override
+// paths to ensure their overrides are properly handled and reverted when the
+// scope of the test is left.
+class ScopedPathOverride {
+ public:
+  // Contructor that initializes the override to a scoped temp directory.
+  explicit ScopedPathOverride(int key);
+
+  // Constructor that would use a path provided by the user.
+  ScopedPathOverride(int key, const FilePath& dir);
+
+  // See PathService::OverrideAndCreateIfNeeded.
+  ScopedPathOverride(int key,
+                     const FilePath& path,
+                     bool is_absolute,
+                     bool create);
+  ~ScopedPathOverride();
+
+ private:
+  int key_;
+  ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPathOverride);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_PATH_OVERRIDE_H_
diff --git a/base/test/sequenced_task_runner_test_template.cc b/base/test/sequenced_task_runner_test_template.cc
new file mode 100644
index 0000000..010f439
--- /dev/null
+++ b/base/test/sequenced_task_runner_test_template.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/sequenced_task_runner_test_template.h"
+
+#include <ostream>
+
+#include "base/location.h"
+
+namespace base {
+
+namespace internal {
+
+TaskEvent::TaskEvent(int i, Type type)
+  : i(i), type(type) {
+}
+
+SequencedTaskTracker::SequencedTaskTracker()
+    : next_post_i_(0),
+      task_end_count_(0),
+      task_end_cv_(&lock_) {
+}
+
+void SequencedTaskTracker::PostWrappedNonNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostNonNestableTask(FROM_HERE, wrapped_task);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostTask(FROM_HERE, wrapped_task);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostNonNestableTasks(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    int task_count) {
+  for (int i = 0; i < task_count; ++i) {
+    PostWrappedNonNestableTask(task_runner, Closure());
+  }
+}
+
+void SequencedTaskTracker::RunTask(const Closure& task, int task_i) {
+  TaskStarted(task_i);
+  if (!task.is_null())
+    task.Run();
+  TaskEnded(task_i);
+}
+
+void SequencedTaskTracker::TaskPosted(int i) {
+  // Caller must own |lock_|.
+  events_.push_back(TaskEvent(i, TaskEvent::POST));
+}
+
+void SequencedTaskTracker::TaskStarted(int i) {
+  AutoLock lock(lock_);
+  events_.push_back(TaskEvent(i, TaskEvent::START));
+}
+
+void SequencedTaskTracker::TaskEnded(int i) {
+  AutoLock lock(lock_);
+  events_.push_back(TaskEvent(i, TaskEvent::END));
+  ++task_end_count_;
+  task_end_cv_.Signal();
+}
+
+const std::vector<TaskEvent>&
+SequencedTaskTracker::GetTaskEvents() const {
+  return events_;
+}
+
+void SequencedTaskTracker::WaitForCompletedTasks(int count) {
+  AutoLock lock(lock_);
+  while (task_end_count_ < count)
+    task_end_cv_.Wait();
+}
+
+SequencedTaskTracker::~SequencedTaskTracker() {
+}
+
+void PrintTo(const TaskEvent& event, std::ostream* os) {
+  *os << "(i=" << event.i << ", type=";
+  switch (event.type) {
+    case TaskEvent::POST: *os << "POST"; break;
+    case TaskEvent::START: *os << "START"; break;
+    case TaskEvent::END: *os << "END"; break;
+  }
+  *os << ")";
+}
+
+namespace {
+
+// Returns the task ordinals for the task event type |type| in the order that
+// they were recorded.
+std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
+                                   TaskEvent::Type type) {
+  std::vector<int> tasks;
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    if (event->type == type)
+      tasks.push_back(event->i);
+  }
+  return tasks;
+}
+
+// Returns all task events for task |task_i|.
+std::vector<TaskEvent::Type> GetEventsForTask(
+    const std::vector<TaskEvent>& events,
+    int task_i) {
+  std::vector<TaskEvent::Type> task_event_orders;
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    if (event->i == task_i)
+      task_event_orders.push_back(event->type);
+  }
+  return task_event_orders;
+}
+
+// Checks that the task events for each task in |events| occur in the order
+// {POST, START, END}, and that there is only one instance of each event type
+// per task.
+::testing::AssertionResult CheckEventOrdersForEachTask(
+    const std::vector<TaskEvent>& events,
+    int task_count) {
+  std::vector<TaskEvent::Type> expected_order;
+  expected_order.push_back(TaskEvent::POST);
+  expected_order.push_back(TaskEvent::START);
+  expected_order.push_back(TaskEvent::END);
+
+  // This is O(n^2), but it runs fast enough currently so is not worth
+  // optimizing.
+  for (int i = 0; i < task_count; ++i) {
+    const std::vector<TaskEvent::Type> task_events =
+        GetEventsForTask(events, i);
+    if (task_events != expected_order) {
+      return ::testing::AssertionFailure()
+          << "Events for task " << i << " are out of order; expected: "
+          << ::testing::PrintToString(expected_order) << "; actual: "
+          << ::testing::PrintToString(task_events);
+    }
+  }
+  return ::testing::AssertionSuccess();
+}
+
+// Checks that no two tasks were running at the same time. I.e. the only
+// events allowed between the START and END of a task are the POSTs of other
+// tasks.
+::testing::AssertionResult CheckNoTaskRunsOverlap(
+    const std::vector<TaskEvent>& events) {
+  // If > -1, we're currently inside a START, END pair.
+  int current_task_i = -1;
+
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    bool spurious_event_found = false;
+
+    if (current_task_i == -1) {  // Not inside a START, END pair.
+      switch (event->type) {
+        case TaskEvent::POST:
+          break;
+        case TaskEvent::START:
+          current_task_i = event->i;
+          break;
+        case TaskEvent::END:
+          spurious_event_found = true;
+          break;
+      }
+
+    } else {  // Inside a START, END pair.
+      bool interleaved_task_detected = false;
+
+      switch (event->type) {
+        case TaskEvent::POST:
+          if (event->i == current_task_i)
+            spurious_event_found = true;
+          break;
+        case TaskEvent::START:
+          interleaved_task_detected = true;
+          break;
+        case TaskEvent::END:
+          if (event->i != current_task_i)
+            interleaved_task_detected = true;
+          else
+            current_task_i = -1;
+          break;
+      }
+
+      if (interleaved_task_detected) {
+        return ::testing::AssertionFailure()
+            << "Found event " << ::testing::PrintToString(*event)
+            << " between START and END events for task " << current_task_i
+            << "; event dump: " << ::testing::PrintToString(events);
+      }
+    }
+
+    if (spurious_event_found) {
+      const int event_i = event - events.begin();
+      return ::testing::AssertionFailure()
+          << "Spurious event " << ::testing::PrintToString(*event)
+          << " at position " << event_i << "; event dump: "
+          << ::testing::PrintToString(events);
+    }
+  }
+
+  return ::testing::AssertionSuccess();
+}
+
+}  // namespace
+
+::testing::AssertionResult CheckNonNestableInvariants(
+    const std::vector<TaskEvent>& events,
+    int task_count) {
+  const std::vector<int> post_order =
+      GetEventTypeOrder(events, TaskEvent::POST);
+  const std::vector<int> start_order =
+      GetEventTypeOrder(events, TaskEvent::START);
+  const std::vector<int> end_order =
+      GetEventTypeOrder(events, TaskEvent::END);
+
+  if (start_order != post_order) {
+    return ::testing::AssertionFailure()
+        << "Expected START order (which equals actual POST order): \n"
+        << ::testing::PrintToString(post_order)
+        << "\n Actual START order:\n"
+        << ::testing::PrintToString(start_order);
+  }
+
+  if (end_order != post_order) {
+    return ::testing::AssertionFailure()
+        << "Expected END order (which equals actual POST order): \n"
+        << ::testing::PrintToString(post_order)
+        << "\n Actual END order:\n"
+        << ::testing::PrintToString(end_order);
+  }
+
+  const ::testing::AssertionResult result =
+      CheckEventOrdersForEachTask(events, task_count);
+  if (!result)
+    return result;
+
+  return CheckNoTaskRunsOverlap(events);
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/test/sequenced_task_runner_test_template.h b/base/test/sequenced_task_runner_test_template.h
new file mode 100644
index 0000000..c208d3c
--- /dev/null
+++ b/base/test/sequenced_task_runner_test_template.h
@@ -0,0 +1,341 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This class defines tests that implementations of SequencedTaskRunner should
+// pass in order to be conformant. See task_runner_test_template.h for a
+// description of how to use the constructs in this file; these work the same.
+
+#ifndef BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <iosfwd>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+struct TaskEvent {
+  enum Type { POST, START, END };
+  TaskEvent(int i, Type type);
+  int i;
+  Type type;
+};
+
+// Utility class used in the tests below.
+class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
+ public:
+  SequencedTaskTracker();
+
+  // Posts the non-nestable task |task|, and records its post event.
+  void PostWrappedNonNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task);
+
+  // Posts the nestable task |task|, and records its post event.
+  void PostWrappedNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task);
+
+  // Posts the delayed non-nestable task |task|, and records its post event.
+  void PostWrappedDelayedNonNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task,
+      TimeDelta delay);
+
+  // Posts |task_count| non-nestable tasks.
+  void PostNonNestableTasks(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      int task_count);
+
+  const std::vector<TaskEvent>& GetTaskEvents() const;
+
+  // Returns after the tracker observes a total of |count| task completions.
+  void WaitForCompletedTasks(int count);
+
+ private:
+  friend class RefCountedThreadSafe<SequencedTaskTracker>;
+
+  ~SequencedTaskTracker();
+
+  // A task which runs |task|, recording the start and end events.
+  void RunTask(const Closure& task, int task_i);
+
+  // Records a post event for task |i|. The owner is expected to be holding
+  // |lock_| (unlike |TaskStarted| and |TaskEnded|).
+  void TaskPosted(int i);
+
+  // Records a start event for task |i|.
+  void TaskStarted(int i);
+
+  // Records a end event for task |i|.
+  void TaskEnded(int i);
+
+  // Protects events_, next_post_i_, task_end_count_ and task_end_cv_.
+  Lock lock_;
+
+  // The events as they occurred for each task (protected by lock_).
+  std::vector<TaskEvent> events_;
+
+  // The ordinal to be used for the next task-posting task (protected by
+  // lock_).
+  int next_post_i_;
+
+  // The number of task end events we've received.
+  int task_end_count_;
+  ConditionVariable task_end_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
+};
+
+void PrintTo(const TaskEvent& event, std::ostream* os);
+
+// Checks the non-nestable task invariants for all tasks in |events|.
+//
+// The invariants are:
+// 1) Events started and ended in the same order that they were posted.
+// 2) Events for an individual tasks occur in the order {POST, START, END},
+//    and there is only one instance of each event type for a task.
+// 3) The only events between a task's START and END events are the POSTs of
+//    other tasks. I.e. tasks were run sequentially, not interleaved.
+::testing::AssertionResult CheckNonNestableInvariants(
+    const std::vector<TaskEvent>& events,
+    int task_count);
+
+}  // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class SequencedTaskRunnerTest : public testing::Test {
+ protected:
+  SequencedTaskRunnerTest()
+      : task_tracker_(new internal::SequencedTaskTracker()) {}
+
+  const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
+  TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_CASE_P(SequencedTaskRunnerTest);
+
+// This test posts N non-nestable tasks in sequence, and expects them to run
+// in FIFO order, with no part of any two tasks' execution
+// overlapping. I.e. that each task starts only after the previously-posted
+// one has finished.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
+  const int kTaskCount = 1000;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNonNestableTask(
+      task_runner, Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+  for (int i = 1; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner, Closure());
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts N nestable tasks in sequence. It has the same expectations
+// as SequentialNonNestable because even though the tasks are nestable, they
+// will not be run nestedly in this case.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
+  const int kTaskCount = 1000;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNestableTask(
+      task_runner,
+      Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+  for (int i = 1; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedNestableTask(task_runner, Closure());
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts non-nestable tasks in order of increasing delay, and checks
+// that that the tasks are run in FIFO order and that there is no execution
+// overlap whatsoever between any two tasks.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
+  const int kTaskCount = 20;
+  const int kDelayIncrementMs = 50;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedDelayedNonNestableTask(
+        task_runner,
+        Closure(),
+        TimeDelta::FromMilliseconds(kDelayIncrementMs * i));
+  }
+
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts a fast, non-nestable task from within each of a number of
+// slow, non-nestable tasks and checks that they all run in the sequence they
+// were posted in and that there is no execution overlap whatsoever.
+TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
+  const int kParentCount = 10;
+  const int kChildrenPerParent = 10;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kParentCount; ++i) {
+    Closure task = Bind(
+        &internal::SequencedTaskTracker::PostNonNestableTasks,
+        this->task_tracker_,
+        task_runner,
+        kChildrenPerParent);
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner, task);
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(
+      this->task_tracker_->GetTaskEvents(),
+      kParentCount * (kChildrenPerParent + 1)));
+}
+
+// This test posts a delayed task, and checks that the task is run later than
+// the specified time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskBasic) {
+  const int kTaskCount = 1;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  Time time_before_run = Time::Now();
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+  Time time_after_run = Time::Now();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+  EXPECT_LE(kDelay, time_after_run - time_before_run);
+}
+
+// This test posts two tasks with the same delay, and checks that the tasks are
+// run in the order in which they were posted.
+//
+// NOTE: This is actually an approximate test since the API only takes a
+// "delay" parameter, so we are not exactly simulating two tasks that get
+// posted at the exact same time. It would be nice if the API allowed us to
+// specify the desired run time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTasksSameDelay) {
+  const int kTaskCount = 2;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts a normal task and a delayed task, and checks that the
+// delayed task runs after the normal task even if the normal task takes
+// a long time to run.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterLongTask) {
+  const int kTaskCount = 2;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNonNestableTask(
+      task_runner, base::Bind(&PlatformThread::Sleep,
+                              TimeDelta::FromMilliseconds(50)));
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// Test that a pile of normal tasks and a delayed task run in the
+// time-to-run order.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterManyLongTasks) {
+  const int kTaskCount = 11;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kTaskCount - 1; i++) {
+    this->task_tracker_->PostWrappedNonNestableTask(
+        task_runner, base::Bind(&PlatformThread::Sleep,
+                                TimeDelta::FromMilliseconds(50)));
+  }
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+
+// TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs
+// some tasked nestedly (which should be implemented in the test
+// delegate). Also add, to the the test delegate, a predicate which checks
+// whether the implementation supports nested tasks.
+//
+
+REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
+                           SequentialNonNestable,
+                           SequentialNestable,
+                           SequentialDelayedNonNestable,
+                           NonNestablePostFromNonNestableTask,
+                           DelayedTaskBasic,
+                           DelayedTasksSameDelay,
+                           DelayedTaskAfterLongTask,
+                           DelayedTaskAfterManyLongTasks);
+
+}  // namespace base
+
+#endif  // BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc
new file mode 100644
index 0000000..b0d8b7a
--- /dev/null
+++ b/base/test/sequenced_worker_pool_owner.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/sequenced_worker_pool_owner.h"
+
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+SequencedWorkerPoolOwner::SequencedWorkerPoolOwner(
+    size_t max_threads,
+    const std::string& thread_name_prefix)
+    : constructor_message_loop_(MessageLoop::current()),
+      pool_(new SequencedWorkerPool(max_threads, thread_name_prefix, this)),
+      has_work_call_count_(0) {}
+
+SequencedWorkerPoolOwner::~SequencedWorkerPoolOwner() {
+  pool_ = NULL;
+  MessageLoop::current()->Run();
+}
+
+const scoped_refptr<SequencedWorkerPool>& SequencedWorkerPoolOwner::pool() {
+  return pool_;
+}
+
+void SequencedWorkerPoolOwner::SetWillWaitForShutdownCallback(
+    const Closure& callback) {
+  will_wait_for_shutdown_callback_ = callback;
+}
+
+int SequencedWorkerPoolOwner::has_work_call_count() const {
+  AutoLock lock(has_work_lock_);
+  return has_work_call_count_;
+}
+
+void SequencedWorkerPoolOwner::OnHasWork() {
+  AutoLock lock(has_work_lock_);
+  ++has_work_call_count_;
+}
+
+void SequencedWorkerPoolOwner::WillWaitForShutdown() {
+  if (!will_wait_for_shutdown_callback_.is_null()) {
+    will_wait_for_shutdown_callback_.Run();
+
+    // Release the reference to the callback to prevent retain cycles.
+    will_wait_for_shutdown_callback_ = Closure();
+  }
+}
+
+void SequencedWorkerPoolOwner::OnDestruct() {
+  constructor_message_loop_->task_runner()->PostTask(
+      FROM_HERE, constructor_message_loop_->QuitWhenIdleClosure());
+}
+
+}  // namespace base
diff --git a/base/test/sequenced_worker_pool_owner.h b/base/test/sequenced_worker_pool_owner.h
new file mode 100644
index 0000000..bf5f2f7
--- /dev/null
+++ b/base/test/sequenced_worker_pool_owner.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+#define BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+
+#include <cstddef>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+
+namespace base {
+
+class MessageLoop;
+
+// Wrapper around SequencedWorkerPool for testing that blocks destruction
+// until the pool is actually destroyed.  This is so that a
+// SequencedWorkerPool from one test doesn't outlive its test and cause
+// strange races with other tests that touch global stuff (like histograms and
+// logging).  However, this requires that nothing else on this thread holds a
+// ref to the pool when the SequencedWorkerPoolOwner is destroyed.
+class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver {
+ public:
+  SequencedWorkerPoolOwner(size_t max_threads,
+                           const std::string& thread_name_prefix);
+
+  ~SequencedWorkerPoolOwner() override;
+
+  // Don't change the returned pool's testing observer.
+  const scoped_refptr<SequencedWorkerPool>& pool();
+
+  // The given callback will be called on WillWaitForShutdown().
+  void SetWillWaitForShutdownCallback(const Closure& callback);
+
+  int has_work_call_count() const;
+
+ private:
+  // SequencedWorkerPool::TestingObserver implementation.
+  void OnHasWork() override;
+  void WillWaitForShutdown() override;
+  void OnDestruct() override;
+
+  MessageLoop* const constructor_message_loop_;
+  scoped_refptr<SequencedWorkerPool> pool_;
+  Closure will_wait_for_shutdown_callback_;
+
+  mutable Lock has_work_lock_;
+  int has_work_call_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolOwner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
diff --git a/base/test/simple_test_clock.cc b/base/test/simple_test_clock.cc
new file mode 100644
index 0000000..a2bdc2a
--- /dev/null
+++ b/base/test/simple_test_clock.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/simple_test_clock.h"
+
+namespace base {
+
+SimpleTestClock::SimpleTestClock() {}
+
+SimpleTestClock::~SimpleTestClock() {}
+
+Time SimpleTestClock::Now() {
+  AutoLock lock(lock_);
+  return now_;
+}
+
+void SimpleTestClock::Advance(TimeDelta delta) {
+  AutoLock lock(lock_);
+  now_ += delta;
+}
+
+void SimpleTestClock::SetNow(Time now) {
+  AutoLock lock(lock_);
+  now_ = now;
+}
+
+}  // namespace base
diff --git a/base/test/simple_test_clock.h b/base/test/simple_test_clock.h
new file mode 100644
index 0000000..a70f99c
--- /dev/null
+++ b/base/test/simple_test_clock.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SIMPLE_TEST_CLOCK_H_
+#define BASE_TEST_SIMPLE_TEST_CLOCK_H_
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// SimpleTestClock is a Clock implementation that gives control over
+// the returned Time objects.  All methods may be called from any
+// thread.
+class SimpleTestClock : public Clock {
+ public:
+  // Starts off with a clock set to Time().
+  SimpleTestClock();
+  ~SimpleTestClock() override;
+
+  Time Now() override;
+
+  // Advances the clock by |delta|.
+  void Advance(TimeDelta delta);
+
+  // Sets the clock to the given time.
+  void SetNow(Time now);
+
+ private:
+  // Protects |now_|.
+  Lock lock_;
+
+  Time now_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SIMPLE_TEST_CLOCK_H_
diff --git a/base/test/simple_test_tick_clock.cc b/base/test/simple_test_tick_clock.cc
new file mode 100644
index 0000000..1b4696f
--- /dev/null
+++ b/base/test/simple_test_tick_clock.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/simple_test_tick_clock.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+SimpleTestTickClock::SimpleTestTickClock() {}
+
+SimpleTestTickClock::~SimpleTestTickClock() {}
+
+TimeTicks SimpleTestTickClock::NowTicks() {
+  AutoLock lock(lock_);
+  return now_ticks_;
+}
+
+void SimpleTestTickClock::Advance(TimeDelta delta) {
+  AutoLock lock(lock_);
+  DCHECK(delta >= TimeDelta());
+  now_ticks_ += delta;
+}
+
+}  // namespace base
diff --git a/base/test/simple_test_tick_clock.h b/base/test/simple_test_tick_clock.h
new file mode 100644
index 0000000..aebdebc
--- /dev/null
+++ b/base/test/simple_test_tick_clock.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
+#define BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// SimpleTestTickClock is a TickClock implementation that gives
+// control over the returned TimeTicks objects.  All methods may be
+// called from any thread.
+class SimpleTestTickClock : public TickClock {
+ public:
+  // Starts off with a clock set to TimeTicks().
+  SimpleTestTickClock();
+  ~SimpleTestTickClock() override;
+
+  TimeTicks NowTicks() override;
+
+  // Advances the clock by |delta|, which must not be negative.
+  void Advance(TimeDelta delta);
+
+ private:
+  // Protects |now_ticks_|.
+  Lock lock_;
+
+  TimeTicks now_ticks_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
diff --git a/base/test/task_runner_test_template.cc b/base/test/task_runner_test_template.cc
new file mode 100644
index 0000000..b756203
--- /dev/null
+++ b/base/test/task_runner_test_template.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/task_runner_test_template.h"
+
+namespace base {
+
+namespace internal {
+
+TaskTracker::TaskTracker() : task_runs_(0), task_runs_cv_(&lock_) {}
+
+TaskTracker::~TaskTracker() {}
+
+Closure TaskTracker::WrapTask(const Closure& task, int i) {
+  return Bind(&TaskTracker::RunTask, this, task, i);
+}
+
+void TaskTracker::RunTask(const Closure& task, int i) {
+  AutoLock lock(lock_);
+  if (!task.is_null()) {
+    task.Run();
+  }
+  ++task_run_counts_[i];
+  ++task_runs_;
+  task_runs_cv_.Signal();
+}
+
+std::map<int, int> TaskTracker::GetTaskRunCounts() const {
+  AutoLock lock(lock_);
+  return task_run_counts_;
+}
+
+void TaskTracker::WaitForCompletedTasks(int count) {
+  AutoLock lock(lock_);
+  while (task_runs_ < count)
+    task_runs_cv_.Wait();
+}
+
+void ExpectRunsTasksOnCurrentThread(
+    bool expected_value,
+    const scoped_refptr<TaskRunner>& task_runner) {
+  EXPECT_EQ(expected_value, task_runner->RunsTasksOnCurrentThread());
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
new file mode 100644
index 0000000..ee2b876
--- /dev/null
+++ b/base/test/task_runner_test_template.h
@@ -0,0 +1,217 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This class defines tests that implementations of TaskRunner should
+// pass in order to be conformant.  Here's how you use it to test your
+// implementation.
+//
+// Say your class is called MyTaskRunner.  Then you need to define a
+// class called MyTaskRunnerTestDelegate in my_task_runner_unittest.cc
+// like this:
+//
+//   class MyTaskRunnerTestDelegate {
+//    public:
+//     // Tasks posted to the task runner after this and before
+//     // StopTaskRunner() is called is called should run successfully.
+//     void StartTaskRunner() {
+//       ...
+//     }
+//
+//     // Should return the task runner implementation.  Only called
+//     // after StartTaskRunner and before StopTaskRunner.
+//     scoped_refptr<MyTaskRunner> GetTaskRunner() {
+//       ...
+//     }
+//
+//     // Stop the task runner and make sure all tasks posted before
+//     // this is called are run. Caveat: delayed tasks are not run,
+       // they're simply deleted.
+//     void StopTaskRunner() {
+//       ...
+//     }
+//   };
+//
+// The TaskRunnerTest test harness will have a member variable of
+// this delegate type and will call its functions in the various
+// tests.
+//
+// Then you simply #include this file as well as gtest.h and add the
+// following statement to my_task_runner_unittest.cc:
+//
+//   INSTANTIATE_TYPED_TEST_CASE_P(
+//       MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
+//
+// Easy!
+
+#ifndef BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+// Utility class that keeps track of how many times particular tasks
+// are run.
+class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
+ public:
+  TaskTracker();
+
+  // Returns a closure that runs the given task and increments the run
+  // count of |i| by one.  |task| may be null.  It is guaranteed that
+  // only one task wrapped by a given tracker will be run at a time.
+  Closure WrapTask(const Closure& task, int i);
+
+  std::map<int, int> GetTaskRunCounts() const;
+
+  // Returns after the tracker observes a total of |count| task completions.
+  void WaitForCompletedTasks(int count);
+
+ private:
+  friend class RefCountedThreadSafe<TaskTracker>;
+
+  ~TaskTracker();
+
+  void RunTask(const Closure& task, int i);
+
+  mutable Lock lock_;
+  std::map<int, int> task_run_counts_;
+  int task_runs_;
+  ConditionVariable task_runs_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskTracker);
+};
+
+}  // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class TaskRunnerTest : public testing::Test {
+ protected:
+  TaskRunnerTest() : task_tracker_(new internal::TaskTracker()) {}
+
+  const scoped_refptr<internal::TaskTracker> task_tracker_;
+  TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_CASE_P(TaskRunnerTest);
+
+// We can't really test much, since TaskRunner provides very few
+// guarantees.
+
+// Post a bunch of tasks to the task runner.  They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Basic) {
+  std::map<int, int> expected_task_run_counts;
+
+  this->delegate_.StartTaskRunner();
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostTask(FROM_HERE, ith_task);
+      ++expected_task_run_counts[i];
+    }
+  }
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+// Post a bunch of delayed tasks to the task runner.  They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Delayed) {
+  std::map<int, int> expected_task_run_counts;
+  int expected_total_tasks = 0;
+
+  this->delegate_.StartTaskRunner();
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times with delays from 0-i.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostDelayedTask(
+          FROM_HERE, ith_task, base::TimeDelta::FromMilliseconds(j));
+      ++expected_task_run_counts[i];
+      ++expected_total_tasks;
+    }
+  }
+  this->task_tracker_->WaitForCompletedTasks(expected_total_tasks);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+namespace internal {
+
+// Calls RunsTasksOnCurrentThread() on |task_runner| and expects it to
+// equal |expected_value|.
+void ExpectRunsTasksOnCurrentThread(
+    bool expected_value,
+    const scoped_refptr<TaskRunner>& task_runner);
+
+}  // namespace internal
+
+// Post a bunch of tasks to the task runner as well as to a separate
+// thread, each checking the value of RunsTasksOnCurrentThread(),
+// which should return true for the tasks posted on the task runner
+// and false for the tasks posted on the separate thread.
+TYPED_TEST_P(TaskRunnerTest, RunsTasksOnCurrentThread) {
+  std::map<int, int> expected_task_run_counts;
+
+  Thread thread("Non-task-runner thread");
+  ASSERT_TRUE(thread.Start());
+  this->delegate_.StartTaskRunner();
+
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times on the task runner and i+1 times on
+  // the non-task-runner thread.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task_runner_task =
+        this->task_tracker_->WrapTask(
+            Bind(&internal::ExpectRunsTasksOnCurrentThread,
+                 true, task_runner),
+            i);
+    const Closure& ith_non_task_runner_task =
+        this->task_tracker_->WrapTask(
+            Bind(&internal::ExpectRunsTasksOnCurrentThread,
+                 false, task_runner),
+            i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostTask(FROM_HERE, ith_task_runner_task);
+      thread.task_runner()->PostTask(FROM_HERE, ith_non_task_runner_task);
+      expected_task_run_counts[i] += 2;
+    }
+  }
+
+  this->delegate_.StopTaskRunner();
+  thread.Stop();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+REGISTER_TYPED_TEST_CASE_P(
+    TaskRunnerTest, Basic, Delayed, RunsTasksOnCurrentThread);
+
+}  // namespace base
+
+#endif  // BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/test_discardable_memory_allocator.cc b/base/test/test_discardable_memory_allocator.cc
new file mode 100644
index 0000000..23d529c
--- /dev/null
+++ b/base/test/test_discardable_memory_allocator.cc
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_discardable_memory_allocator.h"
+
+#include <stdint.h>
+
+#include "base/memory/discardable_memory.h"
+
+namespace base {
+namespace {
+
+class DiscardableMemoryImpl : public DiscardableMemory {
+ public:
+  explicit DiscardableMemoryImpl(size_t size) : data_(new uint8_t[size]) {}
+
+  // Overridden from DiscardableMemory:
+  bool Lock() override { return false; }
+  void Unlock() override {}
+  void* data() const override { return data_.get(); }
+
+ private:
+  scoped_ptr<uint8_t[]> data_;
+};
+
+}  // namespace
+
+TestDiscardableMemoryAllocator::TestDiscardableMemoryAllocator() {
+}
+
+TestDiscardableMemoryAllocator::~TestDiscardableMemoryAllocator() {
+}
+
+scoped_ptr<DiscardableMemory>
+TestDiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
+  return make_scoped_ptr(new DiscardableMemoryImpl(size));
+}
+
+}  // namespace base
diff --git a/base/test/test_discardable_memory_allocator.h b/base/test/test_discardable_memory_allocator.h
new file mode 100644
index 0000000..df9d469
--- /dev/null
+++ b/base/test/test_discardable_memory_allocator.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/memory/discardable_memory_allocator.h"
+
+namespace base {
+
+// TestDiscardableMemoryAllocator is a simple DiscardableMemoryAllocator
+// implementation that can be used for testing. It allocates one-shot
+// DiscardableMemory instances backed by heap memory.
+class TestDiscardableMemoryAllocator : public DiscardableMemoryAllocator {
+ public:
+  TestDiscardableMemoryAllocator();
+  ~TestDiscardableMemoryAllocator() override;
+
+  // Overridden from DiscardableMemoryAllocator:
+  scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+      size_t size) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestDiscardableMemoryAllocator);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/base/test/test_file_util.cc b/base/test/test_file_util.cc
new file mode 100644
index 0000000..8dafc58
--- /dev/null
+++ b/base/test/test_file_util.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+bool EvictFileFromSystemCacheWithRetry(const FilePath& path) {
+  const int kCycles = 10;
+  const TimeDelta kDelay = TestTimeouts::action_timeout() / kCycles;
+  for (int i = 0; i < kCycles; i++) {
+    if (EvictFileFromSystemCache(path))
+      return true;
+    PlatformThread::Sleep(kDelay);
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
new file mode 100644
index 0000000..27197f2
--- /dev/null
+++ b/base/test/test_file_util.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_FILE_UTIL_H_
+#define BASE_TEST_TEST_FILE_UTIL_H_
+
+// File utility functions used only by tests.
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+
+#if defined(OS_ANDROID)
+#include <jni.h>
+#include "base/basictypes.h"
+#endif
+
+namespace base {
+
+class FilePath;
+
+// Clear a specific file from the system cache like EvictFileFromSystemCache,
+// but on failure it will sleep and retry. On the Windows buildbots, eviction
+// can fail if the file is marked in use, and this will throw off timings that
+// rely on uncached files.
+bool EvictFileFromSystemCacheWithRetry(const FilePath& file);
+
+// Wrapper over base::Delete. On Windows repeatedly invokes Delete in case
+// of failure to workaround Windows file locking semantics. Returns true on
+// success.
+bool DieFileDie(const FilePath& file, bool recurse);
+
+// Clear a specific file from the system cache. After this call, trying
+// to access this file will result in a cold load from the hard drive.
+bool EvictFileFromSystemCache(const FilePath& file);
+
+#if defined(OS_WIN)
+// Returns true if the volume supports Alternate Data Streams.
+bool VolumeSupportsADS(const FilePath& path);
+
+// Returns true if the ZoneIdentifier is correctly set to "Internet" (3).
+// Note that this function must be called from the same process as
+// the one that set the zone identifier.  I.e. don't use it in UI/automation
+// based tests.
+bool HasInternetZoneIdentifier(const FilePath& full_path);
+#endif  // defined(OS_WIN)
+
+// For testing, make the file unreadable or unwritable.
+// In POSIX, this does not apply to the root user.
+bool MakeFileUnreadable(const FilePath& path) WARN_UNUSED_RESULT;
+bool MakeFileUnwritable(const FilePath& path) WARN_UNUSED_RESULT;
+
+// Saves the current permissions for a path, and restores it on destruction.
+class FilePermissionRestorer {
+ public:
+  explicit FilePermissionRestorer(const FilePath& path);
+  ~FilePermissionRestorer();
+
+ private:
+  const FilePath path_;
+  void* info_;  // The opaque stored permission information.
+  size_t length_;  // The length of the stored permission information.
+
+  DISALLOW_COPY_AND_ASSIGN(FilePermissionRestorer);
+};
+
+#if defined(OS_ANDROID)
+// Register the ContentUriTestUrils JNI bindings.
+bool RegisterContentUriTestUtils(JNIEnv* env);
+
+// Insert an image file into the MediaStore, and retrieve the content URI for
+// testing purpose.
+FilePath InsertImageIntoMediaStore(const FilePath& path);
+#endif  // defined(OS_ANDROID)
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_FILE_UTIL_H_
diff --git a/base/test/test_file_util_android.cc b/base/test/test_file_util_android.cc
new file mode 100644
index 0000000..b8fd50c
--- /dev/null
+++ b/base/test/test_file_util_android.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "jni/ContentUriTestUtils_jni.h"
+
+namespace base {
+
+bool RegisterContentUriTestUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+FilePath InsertImageIntoMediaStore(const FilePath& path) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_path =
+      base::android::ConvertUTF8ToJavaString(env, path.value());
+  ScopedJavaLocalRef<jstring> j_uri =
+      Java_ContentUriTestUtils_insertImageIntoMediaStore(
+          env, base::android::GetApplicationContext(), j_path.obj());
+  std::string uri = base::android::ConvertJavaStringToUTF8(j_uri);
+  return FilePath(uri);
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_linux.cc b/base/test/test_file_util_linux.cc
new file mode 100644
index 0000000..0ef5c0a
--- /dev/null
+++ b/base/test/test_file_util_linux.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+
+namespace base {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  ScopedFD fd(open(file.value().c_str(), O_RDONLY));
+  if (!fd.is_valid())
+    return false;
+  if (fdatasync(fd.get()) != 0)
+    return false;
+  if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_DONTNEED) != 0)
+    return false;
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_mac.cc b/base/test/test_file_util_mac.cc
new file mode 100644
index 0000000..11592c3
--- /dev/null
+++ b/base/test/test_file_util_mac.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // There aren't any really direct ways to purge a file from the UBC.  From
+  // talking with Amit Singh, the safest is to mmap the file with MAP_FILE (the
+  // default) + MAP_SHARED, then do an msync to invalidate the memory.  The next
+  // open should then have to load the file from disk.
+
+  int64 length;
+  if (!GetFileSize(file, &length)) {
+    DLOG(ERROR) << "failed to get size of " << file.value();
+    return false;
+  }
+
+  // When a file is empty, we do not need to evict it from cache.
+  // In fact, an attempt to map it to memory will result in error.
+  if (length == 0) {
+    DLOG(WARNING) << "file size is zero, will not attempt to map to memory";
+    return true;
+  }
+
+  MemoryMappedFile mapped_file;
+  if (!mapped_file.Initialize(file)) {
+    DLOG(WARNING) << "failed to memory map " << file.value();
+    return false;
+  }
+
+  if (msync(const_cast<uint8*>(mapped_file.data()), mapped_file.length(),
+            MS_INVALIDATE) != 0) {
+    DLOG(WARNING) << "failed to invalidate memory map of " << file.value()
+                  << ", errno: " << errno;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_posix.cc b/base/test/test_file_util_posix.cc
new file mode 100644
index 0000000..12b892c
--- /dev/null
+++ b/base/test/test_file_util_posix.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Deny |permission| on the file |path|.
+bool DenyFilePermission(const FilePath& path, mode_t permission) {
+  struct stat stat_buf;
+  if (stat(path.value().c_str(), &stat_buf) != 0)
+    return false;
+  stat_buf.st_mode &= ~permission;
+
+  int rv = HANDLE_EINTR(chmod(path.value().c_str(), stat_buf.st_mode));
+  return rv == 0;
+}
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob.  Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+  DCHECK(length);
+  *length = 0;
+
+  struct stat stat_buf;
+  if (stat(path.value().c_str(), &stat_buf) != 0)
+    return NULL;
+
+  *length = sizeof(mode_t);
+  mode_t* mode = new mode_t;
+  *mode = stat_buf.st_mode & ~S_IFMT;  // Filter out file/path kind.
+
+  return mode;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+  if (!info || (length == 0))
+    return false;
+
+  DCHECK_EQ(sizeof(mode_t), length);
+  mode_t* mode = reinterpret_cast<mode_t*>(info);
+
+  int rv = HANDLE_EINTR(chmod(path.value().c_str(), *mode));
+
+  delete mode;
+
+  return rv == 0;
+}
+
+}  // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+  // There is no need to workaround Windows problems on POSIX.
+  // Just pass-through.
+  return DeleteFile(file, recurse);
+}
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // There doesn't seem to be a POSIX way to cool the disk cache.
+  NOTIMPLEMENTED();
+  return false;
+}
+#endif
+
+bool MakeFileUnreadable(const FilePath& path) {
+  return DenyFilePermission(path, S_IRUSR | S_IRGRP | S_IROTH);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+  return DenyFilePermission(path, S_IWUSR | S_IWGRP | S_IWOTH);
+}
+
+FilePermissionRestorer::FilePermissionRestorer(const FilePath& path)
+    : path_(path), info_(NULL), length_(0) {
+  info_ = GetPermissionInfo(path_, &length_);
+  DCHECK(info_ != NULL);
+  DCHECK_NE(0u, length_);
+}
+
+FilePermissionRestorer::~FilePermissionRestorer() {
+  if (!RestorePermissionInfo(path_, info_, length_))
+    NOTREACHED();
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
new file mode 100644
index 0000000..5496a55
--- /dev/null
+++ b/base/test/test_file_util_win.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <windows.h>
+#include <aclapi.h>
+#include <shlwapi.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+static const ptrdiff_t kOneMB = 1024 * 1024;
+
+namespace {
+
+struct PermissionInfo {
+  PSECURITY_DESCRIPTOR security_descriptor;
+  ACL dacl;
+};
+
+// Deny |permission| on the file |path|, for the current user.
+bool DenyFilePermission(const FilePath& path, DWORD permission) {
+  PACL old_dacl;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  EXPLICIT_ACCESS change;
+  change.grfAccessPermissions = permission;
+  change.grfAccessMode = DENY_ACCESS;
+  change.grfInheritance = 0;
+  change.Trustee.pMultipleTrustee = NULL;
+  change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
+  change.Trustee.TrusteeType = TRUSTEE_IS_USER;
+  change.Trustee.ptstrName = const_cast<wchar_t*>(L"CURRENT_USER");
+
+  PACL new_dacl;
+  if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
+    LocalFree(security_descriptor);
+    return false;
+  }
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, new_dacl, NULL);
+  LocalFree(security_descriptor);
+  LocalFree(new_dacl);
+
+  return rc == ERROR_SUCCESS;
+}
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob.  Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+  DCHECK(length != NULL);
+  *length = 0;
+  PACL dacl = NULL;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS) {
+    return NULL;
+  }
+  DCHECK(dacl != NULL);
+
+  *length = sizeof(PSECURITY_DESCRIPTOR) + dacl->AclSize;
+  PermissionInfo* info = reinterpret_cast<PermissionInfo*>(new char[*length]);
+  info->security_descriptor = security_descriptor;
+  memcpy(&info->dacl, dacl, dacl->AclSize);
+
+  return info;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+  if (!info || !length)
+    return false;
+
+  PermissionInfo* perm = reinterpret_cast<PermissionInfo*>(info);
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, &perm->dacl, NULL);
+  LocalFree(perm->security_descriptor);
+
+  char* char_array = reinterpret_cast<char*>(info);
+  delete [] char_array;
+
+  return rc == ERROR_SUCCESS;
+}
+
+}  // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+  // It turns out that to not induce flakiness a long timeout is needed.
+  const int kIterations = 25;
+  const TimeDelta kTimeout = TimeDelta::FromSeconds(10) / kIterations;
+
+  if (!PathExists(file))
+    return true;
+
+  // Sometimes Delete fails, so try a few more times. Divide the timeout
+  // into short chunks, so that if a try succeeds, we won't delay the test
+  // for too long.
+  for (int i = 0; i < kIterations; ++i) {
+    if (DeleteFile(file, recurse))
+      return true;
+    PlatformThread::Sleep(kTimeout);
+  }
+  return false;
+}
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // Request exclusive access to the file and overwrite it with no buffering.
+  base::win::ScopedHandle file_handle(
+      CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                 OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL));
+  if (!file_handle.IsValid())
+    return false;
+
+  // Get some attributes to restore later.
+  BY_HANDLE_FILE_INFORMATION bhi = {0};
+  CHECK(::GetFileInformationByHandle(file_handle.Get(), &bhi));
+
+  // Execute in chunks. It could be optimized. We want to do few of these since
+  // these operations will be slow without the cache.
+
+  // Allocate a buffer for the reads and the writes.
+  char* buffer = reinterpret_cast<char*>(VirtualAlloc(NULL,
+                                                      kOneMB,
+                                                      MEM_COMMIT | MEM_RESERVE,
+                                                      PAGE_READWRITE));
+
+  // If the file size isn't a multiple of kOneMB, we'll need special
+  // processing.
+  bool file_is_aligned = true;
+  int total_bytes = 0;
+  DWORD bytes_read, bytes_written;
+  for (;;) {
+    bytes_read = 0;
+    ::ReadFile(file_handle.Get(), buffer, kOneMB, &bytes_read, NULL);
+    if (bytes_read == 0)
+      break;
+
+    if (bytes_read < kOneMB) {
+      // Zero out the remaining part of the buffer.
+      // WriteFile will fail if we provide a buffer size that isn't a
+      // sector multiple, so we'll have to write the entire buffer with
+      // padded zeros and then use SetEndOfFile to truncate the file.
+      ZeroMemory(buffer + bytes_read, kOneMB - bytes_read);
+      file_is_aligned = false;
+    }
+
+    // Move back to the position we just read from.
+    // Note that SetFilePointer will also fail if total_bytes isn't sector
+    // aligned, but that shouldn't happen here.
+    DCHECK_EQ(total_bytes % kOneMB, 0);
+    SetFilePointer(file_handle.Get(), total_bytes, NULL, FILE_BEGIN);
+    if (!::WriteFile(file_handle.Get(), buffer, kOneMB, &bytes_written, NULL) ||
+        bytes_written != kOneMB) {
+      BOOL freed = VirtualFree(buffer, 0, MEM_RELEASE);
+      DCHECK(freed);
+      NOTREACHED();
+      return false;
+    }
+
+    total_bytes += bytes_read;
+
+    // If this is false, then we just processed the last portion of the file.
+    if (!file_is_aligned)
+      break;
+  }
+
+  BOOL freed = VirtualFree(buffer, 0, MEM_RELEASE);
+  DCHECK(freed);
+
+  if (!file_is_aligned) {
+    // The size of the file isn't a multiple of 1 MB, so we'll have
+    // to open the file again, this time without the FILE_FLAG_NO_BUFFERING
+    // flag and use SetEndOfFile to mark EOF.
+    file_handle.Set(NULL);
+    file_handle.Set(CreateFile(file.value().c_str(), GENERIC_WRITE, 0, NULL,
+                               OPEN_EXISTING, 0, NULL));
+    CHECK_NE(SetFilePointer(file_handle.Get(), total_bytes, NULL, FILE_BEGIN),
+             INVALID_SET_FILE_POINTER);
+    CHECK(::SetEndOfFile(file_handle.Get()));
+  }
+
+  // Restore the file attributes.
+  CHECK(::SetFileTime(file_handle.Get(), &bhi.ftCreationTime,
+                      &bhi.ftLastAccessTime, &bhi.ftLastWriteTime));
+
+  return true;
+}
+
+// Checks if the volume supports Alternate Data Streams. This is required for
+// the Zone Identifier implementation.
+bool VolumeSupportsADS(const FilePath& path) {
+  wchar_t drive[MAX_PATH] = {0};
+  wcscpy_s(drive, MAX_PATH, path.value().c_str());
+
+  if (!PathStripToRootW(drive))
+    return false;
+
+  DWORD fs_flags = 0;
+  if (!GetVolumeInformationW(drive, NULL, 0, 0, NULL, &fs_flags, NULL, 0))
+    return false;
+
+  if (fs_flags & FILE_NAMED_STREAMS)
+    return true;
+
+  return false;
+}
+
+// Return whether the ZoneIdentifier is correctly set to "Internet" (3)
+// Only returns a valid result when called from same process as the
+// one that (was supposed to have) set the zone identifier.
+bool HasInternetZoneIdentifier(const FilePath& full_path) {
+  FilePath zone_path(full_path.value() + L":Zone.Identifier");
+  std::string zone_path_contents;
+  if (!ReadFileToString(zone_path, &zone_path_contents))
+    return false;
+
+  std::vector<std::string> lines;
+  // This call also trims whitespaces, including carriage-returns (\r).
+  SplitString(zone_path_contents, '\n', &lines);
+
+  switch (lines.size()) {
+    case 3:
+      // optional empty line at end of file:
+      if (!lines[2].empty())
+        return false;
+      // fall through:
+    case 2:
+      return lines[0] == "[ZoneTransfer]" && lines[1] == "ZoneId=3";
+    default:
+      return false;
+  }
+}
+
+bool MakeFileUnreadable(const FilePath& path) {
+  return DenyFilePermission(path, GENERIC_READ);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+  return DenyFilePermission(path, GENERIC_WRITE);
+}
+
+FilePermissionRestorer::FilePermissionRestorer(const FilePath& path)
+    : path_(path), info_(NULL), length_(0) {
+  info_ = GetPermissionInfo(path_, &length_);
+  DCHECK(info_ != NULL);
+  DCHECK_NE(0u, length_);
+}
+
+FilePermissionRestorer::~FilePermissionRestorer() {
+  if (!RestorePermissionInfo(path_, info_, length_))
+    NOTREACHED();
+}
+
+}  // namespace base
diff --git a/base/test/test_io_thread.cc b/base/test/test_io_thread.cc
new file mode 100644
index 0000000..48c1e16
--- /dev/null
+++ b/base/test/test_io_thread.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_io_thread.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace {
+
+void PostTaskAndWaitHelper(base::WaitableEvent* event,
+                           const base::Closure& task) {
+  task.Run();
+  event->Signal();
+}
+
+}  // namespace
+
+namespace base {
+
+TestIOThread::TestIOThread(Mode mode)
+    : io_thread_("test_io_thread"), io_thread_started_(false) {
+  switch (mode) {
+    case kAutoStart:
+      Start();
+      return;
+    case kManualStart:
+      return;
+  }
+  CHECK(false) << "Invalid mode";
+}
+
+TestIOThread::~TestIOThread() {
+  Stop();
+}
+
+void TestIOThread::Start() {
+  CHECK(!io_thread_started_);
+  io_thread_started_ = true;
+  CHECK(io_thread_.StartWithOptions(
+      base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+}
+
+void TestIOThread::Stop() {
+  // Note: It's okay to call |Stop()| even if the thread isn't running.
+  io_thread_.Stop();
+  io_thread_started_ = false;
+}
+
+void TestIOThread::PostTask(const tracked_objects::Location& from_here,
+                            const base::Closure& task) {
+  task_runner()->PostTask(from_here, task);
+}
+
+void TestIOThread::PostTaskAndWait(const tracked_objects::Location& from_here,
+                                   const base::Closure& task) {
+  base::WaitableEvent event(false, false);
+  task_runner()->PostTask(from_here,
+                          base::Bind(&PostTaskAndWaitHelper, &event, task));
+  event.Wait();
+}
+
+}  // namespace base
diff --git a/base/test/test_io_thread.h b/base/test/test_io_thread.h
new file mode 100644
index 0000000..c2ed187
--- /dev/null
+++ b/base/test/test_io_thread.h
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_IO_THREAD_H_
+#define BASE_TEST_TEST_IO_THREAD_H_
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// Create and run an IO thread with a MessageLoop, and
+// making the MessageLoop accessible from its client.
+// It also provides some ideomatic API like PostTaskAndWait().
+class TestIOThread {
+ public:
+  enum Mode { kAutoStart, kManualStart };
+  explicit TestIOThread(Mode mode);
+  // Stops the I/O thread if necessary.
+  ~TestIOThread();
+
+  // |Start()|/|Stop()| should only be called from the main (creation) thread.
+  // After |Stop()|, |Start()| may be called again to start a new I/O thread.
+  // |Stop()| may be called even when the I/O thread is not started.
+  void Start();
+  void Stop();
+
+  // Post |task| to the IO thread.
+  void PostTask(const tracked_objects::Location& from_here,
+                const base::Closure& task);
+  // Posts |task| to the IO-thread with an WaitableEvent associated blocks on
+  // it until the posted |task| is executed, then returns.
+  void PostTaskAndWait(const tracked_objects::Location& from_here,
+                       const base::Closure& task);
+
+  base::MessageLoopForIO* message_loop() {
+    return static_cast<base::MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  scoped_refptr<SingleThreadTaskRunner> task_runner() {
+    return message_loop()->task_runner();
+  }
+
+ private:
+  base::Thread io_thread_;
+  bool io_thread_started_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestIOThread);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_IO_THREAD_H_
diff --git a/base/test/test_listener_ios.h b/base/test/test_listener_ios.h
new file mode 100644
index 0000000..c312250
--- /dev/null
+++ b/base/test/test_listener_ios.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_LISTENER_IOS_H_
+#define BASE_TEST_TEST_LISTENER_IOS_H_
+
+namespace base {
+namespace test_listener_ios {
+
+// Register an IOSRunLoopListener.
+void RegisterTestEndListener();
+
+}  // namespace test_listener_ios
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_LISTENER_IOS_H_
diff --git a/base/test/test_listener_ios.mm b/base/test/test_listener_ios.mm
new file mode 100644
index 0000000..12cf5bb
--- /dev/null
+++ b/base/test/test_listener_ios.mm
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_listener_ios.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// The iOS watchdog timer will kill an app that doesn't spin the main event
+// loop often enough. This uses a Gtest TestEventListener to spin the current
+// loop after each test finishes. However, if any individual test takes too
+// long, it is still possible that the app will get killed.
+
+namespace {
+
+class IOSRunLoopListener : public testing::EmptyTestEventListener {
+ public:
+  virtual void OnTestEnd(const testing::TestInfo& test_info);
+};
+
+void IOSRunLoopListener::OnTestEnd(const testing::TestInfo& test_info) {
+  base::mac::ScopedNSAutoreleasePool scoped_pool;
+
+  // At the end of the test, spin the default loop for a moment.
+  NSDate* stop_date = [NSDate dateWithTimeIntervalSinceNow:0.001];
+  [[NSRunLoop currentRunLoop] runUntilDate:stop_date];
+}
+
+}  // namespace
+
+
+namespace base {
+namespace test_listener_ios {
+
+void RegisterTestEndListener() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new IOSRunLoopListener);
+}
+
+}  // namespace test_listener_ios
+}  // namespace base
diff --git a/base/test/test_mock_time_task_runner.cc b/base/test/test_mock_time_task_runner.cc
new file mode 100644
index 0000000..f2e18a3
--- /dev/null
+++ b/base/test/test_mock_time_task_runner.cc
@@ -0,0 +1,263 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_mock_time_task_runner.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+
+namespace base {
+
+namespace {
+
+// MockTickClock --------------------------------------------------------------
+
+// TickClock that always returns the then-current mock time ticks of
+// |task_runner| as the current time ticks.
+class MockTickClock : public TickClock {
+ public:
+  explicit MockTickClock(
+      scoped_refptr<const TestMockTimeTaskRunner> task_runner);
+
+  // TickClock:
+  TimeTicks NowTicks() override;
+
+ private:
+  scoped_refptr<const TestMockTimeTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockTickClock);
+};
+
+MockTickClock::MockTickClock(
+    scoped_refptr<const TestMockTimeTaskRunner> task_runner)
+    : task_runner_(task_runner) {
+}
+
+TimeTicks MockTickClock::NowTicks() {
+  return task_runner_->NowTicks();
+}
+
+// MockClock ------------------------------------------------------------------
+
+// Clock that always returns the then-current mock time of |task_runner| as the
+// current time.
+class MockClock : public Clock {
+ public:
+  explicit MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner);
+
+  // Clock:
+  Time Now() override;
+
+ private:
+  scoped_refptr<const TestMockTimeTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockClock);
+};
+
+MockClock::MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner)
+    : task_runner_(task_runner) {
+}
+
+Time MockClock::Now() {
+  return task_runner_->Now();
+}
+
+}  // namespace
+
+// TestMockTimeTaskRunner::TestOrderedPendingTask -----------------------------
+
+// Subclass of TestPendingTask which has a strictly monotonically increasing ID
+// for every task, so that tasks posted with the same 'time to run' can be run
+// in the order of being posted.
+struct TestMockTimeTaskRunner::TestOrderedPendingTask
+    : public base::TestPendingTask {
+  TestOrderedPendingTask();
+  TestOrderedPendingTask(const tracked_objects::Location& location,
+                         const Closure& task,
+                         TimeTicks post_time,
+                         TimeDelta delay,
+                         size_t ordinal,
+                         TestNestability nestability);
+  ~TestOrderedPendingTask();
+
+  size_t ordinal;
+};
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask()
+    : ordinal(0) {
+}
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
+    const tracked_objects::Location& location,
+    const Closure& task,
+    TimeTicks post_time,
+    TimeDelta delay,
+    size_t ordinal,
+    TestNestability nestability)
+    : base::TestPendingTask(location, task, post_time, delay, nestability),
+      ordinal(ordinal) {
+}
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::~TestOrderedPendingTask() {
+}
+
+// TestMockTimeTaskRunner -----------------------------------------------------
+
+bool TestMockTimeTaskRunner::TemporalOrder::operator()(
+    const TestOrderedPendingTask& first_task,
+    const TestOrderedPendingTask& second_task) const {
+  if (first_task.GetTimeToRun() == second_task.GetTimeToRun())
+    return first_task.ordinal > second_task.ordinal;
+  return first_task.GetTimeToRun() > second_task.GetTimeToRun();
+}
+
+TestMockTimeTaskRunner::TestMockTimeTaskRunner()
+    : now_(Time::UnixEpoch()), next_task_ordinal_(0) {
+}
+
+TestMockTimeTaskRunner::~TestMockTimeTaskRunner() {
+}
+
+void TestMockTimeTaskRunner::FastForwardBy(TimeDelta delta) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_GE(delta, TimeDelta());
+
+  const TimeTicks original_now_ticks = now_ticks_;
+  ProcessAllTasksNoLaterThan(delta);
+  ForwardClocksUntilTickTime(original_now_ticks + delta);
+}
+
+void TestMockTimeTaskRunner::RunUntilIdle() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ProcessAllTasksNoLaterThan(TimeDelta());
+}
+
+void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ProcessAllTasksNoLaterThan(TimeDelta::Max());
+}
+
+void TestMockTimeTaskRunner::ClearPendingTasks() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  AutoLock scoped_lock(tasks_lock_);
+  while (!tasks_.empty())
+    tasks_.pop();
+}
+
+Time TestMockTimeTaskRunner::Now() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return now_;
+}
+
+TimeTicks TestMockTimeTaskRunner::NowTicks() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return now_ticks_;
+}
+
+scoped_ptr<Clock> TestMockTimeTaskRunner::GetMockClock() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return make_scoped_ptr(new MockClock(this));
+}
+
+scoped_ptr<TickClock> TestMockTimeTaskRunner::GetMockTickClock() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return make_scoped_ptr(new MockTickClock(this));
+}
+
+bool TestMockTimeTaskRunner::HasPendingTask() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return !tasks_.empty();
+}
+
+size_t TestMockTimeTaskRunner::GetPendingTaskCount() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return tasks_.size();
+}
+
+TimeDelta TestMockTimeTaskRunner::NextPendingTaskDelay() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return tasks_.empty() ? TimeDelta::Max()
+                        : tasks_.top().GetTimeToRun() - now_ticks_;
+}
+
+bool TestMockTimeTaskRunner::RunsTasksOnCurrentThread() const {
+  return thread_checker_.CalledOnValidThread();
+}
+
+bool TestMockTimeTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock scoped_lock(tasks_lock_);
+  tasks_.push(TestOrderedPendingTask(from_here, task, now_ticks_, delay,
+                                     next_task_ordinal_++,
+                                     TestPendingTask::NESTABLE));
+  return true;
+}
+
+bool TestMockTimeTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedTask(from_here, task, delay);
+}
+
+bool TestMockTimeTaskRunner::IsElapsingStopped() {
+  return false;
+}
+
+void TestMockTimeTaskRunner::OnBeforeSelectingTask() {
+  // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::OnAfterTimePassed() {
+  // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::OnAfterTaskRun() {
+  // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::ProcessAllTasksNoLaterThan(TimeDelta max_delta) {
+  DCHECK_GE(max_delta, TimeDelta());
+  const TimeTicks original_now_ticks = now_ticks_;
+  while (!IsElapsingStopped()) {
+    OnBeforeSelectingTask();
+    TestPendingTask task_info;
+    if (!DequeueNextTask(original_now_ticks, max_delta, &task_info))
+      break;
+    // If tasks were posted with a negative delay, task_info.GetTimeToRun() will
+    // be less than |now_ticks_|. ForwardClocksUntilTickTime() takes care of not
+    // moving the clock backwards in this case.
+    ForwardClocksUntilTickTime(task_info.GetTimeToRun());
+    task_info.task.Run();
+    OnAfterTaskRun();
+  }
+}
+
+void TestMockTimeTaskRunner::ForwardClocksUntilTickTime(TimeTicks later_ticks) {
+  if (later_ticks <= now_ticks_)
+    return;
+
+  now_ += later_ticks - now_ticks_;
+  now_ticks_ = later_ticks;
+  OnAfterTimePassed();
+}
+
+bool TestMockTimeTaskRunner::DequeueNextTask(const TimeTicks& reference,
+                                             const TimeDelta& max_delta,
+                                             TestPendingTask* next_task) {
+  AutoLock scoped_lock(tasks_lock_);
+  if (!tasks_.empty() &&
+      (tasks_.top().GetTimeToRun() - reference) <= max_delta) {
+    *next_task = tasks_.top();
+    tasks_.pop();
+    return true;
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/test/test_mock_time_task_runner.h b/base/test/test_mock_time_task_runner.h
new file mode 100644
index 0000000..6319e0c
--- /dev/null
+++ b/base/test/test_mock_time_task_runner.h
@@ -0,0 +1,165 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
+#define BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class Clock;
+class TickClock;
+
+// Runs pending tasks in the order of the tasks' post time + delay, and keeps
+// track of a mock (virtual) tick clock time that can be fast-forwarded.
+//
+// TestMockTimeTaskRunner has the following properties:
+//
+//   - Methods RunsTasksOnCurrentThread() and Post[Delayed]Task() can be called
+//     from any thread, but the rest of the methods must be called on the same
+//     thread the TaskRunner was created on.
+//   - It allows for reentrancy, in that it handles the running of tasks that in
+//     turn call back into it (e.g., to post more tasks).
+//   - Tasks are stored in a priority queue, and executed in the increasing
+//     order of post time + delay, but ignoring nestability.
+//   - It does not check for overflow when doing time arithmetic. A sufficient
+//     condition for preventing overflows is to make sure that the sum of all
+//     posted task delays and fast-forward increments is still representable by
+//     a TimeDelta, and that adding this delta to the starting values of Time
+//     and TickTime is still within their respective range.
+//   - Tasks aren't guaranteed to be destroyed immediately after they're run.
+//
+// This is a slightly more sophisticated version of TestSimpleTaskRunner, in
+// that it supports running delayed tasks in the correct temporal order.
+class TestMockTimeTaskRunner : public SingleThreadTaskRunner {
+ public:
+  // Constructs an instance whose virtual time will start at the Unix epoch, and
+  // whose time ticks will start at zero.
+  TestMockTimeTaskRunner();
+
+  // Fast-forwards virtual time by |delta|, causing all tasks with a remaining
+  // delay less than or equal to |delta| to be executed. |delta| must be
+  // non-negative.
+  void FastForwardBy(TimeDelta delta);
+
+  // Fast-forwards virtual time just until all tasks are executed.
+  void FastForwardUntilNoTasksRemain();
+
+  // Executes all tasks that have no remaining delay. Tasks with a remaining
+  // delay greater than zero will remain enqueued, and no virtual time will
+  // elapse.
+  void RunUntilIdle();
+
+  // Clears the queue of pending tasks without running them.
+  void ClearPendingTasks();
+
+  // Returns the current virtual time (initially starting at the Unix epoch).
+  Time Now() const;
+
+  // Returns the current virtual tick time (initially starting at 0).
+  TimeTicks NowTicks() const;
+
+  // Returns a Clock that uses the virtual time of |this| as its time source.
+  // The returned Clock will hold a reference to |this|.
+  scoped_ptr<Clock> GetMockClock() const;
+
+  // Returns a TickClock that uses the virtual time ticks of |this| as its tick
+  // source. The returned TickClock will hold a reference to |this|.
+  scoped_ptr<TickClock> GetMockTickClock() const;
+
+  bool HasPendingTask() const;
+  size_t GetPendingTaskCount() const;
+  TimeDelta NextPendingTaskDelay() const;
+
+  // SingleThreadTaskRunner:
+  bool RunsTasksOnCurrentThread() const override;
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+ protected:
+  ~TestMockTimeTaskRunner() override;
+
+  // Whether the elapsing of virtual time is stopped or not. Subclasses can
+  // override this method to perform early exits from a running task runner.
+  // Defaults to always return false.
+  virtual bool IsElapsingStopped();
+
+  // Called before the next task to run is selected, so that subclasses have a
+  // last chance to make sure all tasks are posted.
+  virtual void OnBeforeSelectingTask();
+
+  // Called after the current mock time has been incremented so that subclasses
+  // can react to the passing of time.
+  virtual void OnAfterTimePassed();
+
+  // Called after each task is run so that subclasses may perform additional
+  // activities, e.g., pump additional task runners.
+  virtual void OnAfterTaskRun();
+
+ private:
+  struct TestOrderedPendingTask;
+
+  // Predicate that defines a strict weak temporal ordering of tasks.
+  class TemporalOrder {
+   public:
+    bool operator()(const TestOrderedPendingTask& first_task,
+                    const TestOrderedPendingTask& second_task) const;
+  };
+
+  typedef std::priority_queue<TestOrderedPendingTask,
+                              std::vector<TestOrderedPendingTask>,
+                              TemporalOrder> TaskPriorityQueue;
+
+  // Core of the implementation for all flavors of fast-forward methods. Given a
+  // non-negative |max_delta|, runs all tasks with a remaining delay less than
+  // or equal to |max_delta|, and moves virtual time forward as needed for each
+  // processed task. Pass in TimeDelta::Max() as |max_delta| to run all tasks.
+  void ProcessAllTasksNoLaterThan(TimeDelta max_delta);
+
+  // Forwards |now_ticks_| until it equals |later_ticks|, and forwards |now_| by
+  // the same amount. Calls OnAfterTimePassed() if |later_ticks| > |now_ticks_|.
+  // Does nothing if |later_ticks| <= |now_ticks_|.
+  void ForwardClocksUntilTickTime(TimeTicks later_ticks);
+
+  // Returns the |next_task| to run if there is any with a running time that is
+  // at most |reference| + |max_delta|. This additional complexity is required
+  // so that |max_delta| == TimeDelta::Max() can be supported.
+  bool DequeueNextTask(const TimeTicks& reference,
+                       const TimeDelta& max_delta,
+                       TestPendingTask* next_task);
+
+  ThreadChecker thread_checker_;
+  Time now_;
+  TimeTicks now_ticks_;
+
+  // Temporally ordered heap of pending tasks. Must only be accessed while the
+  // |tasks_lock_| is held.
+  TaskPriorityQueue tasks_;
+
+  // The ordinal to use for the next task. Must only be accessed while the
+  // |tasks_lock_| is held.
+  size_t next_task_ordinal_;
+
+  Lock tasks_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMockTimeTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
diff --git a/base/test/test_pending_task.cc b/base/test/test_pending_task.cc
new file mode 100644
index 0000000..3f2c79d
--- /dev/null
+++ b/base/test/test_pending_task.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/test/test_pending_task.h"
+
+namespace base {
+
+TestPendingTask::TestPendingTask() : nestability(NESTABLE) {}
+
+TestPendingTask::TestPendingTask(
+    const tracked_objects::Location& location,
+    const Closure& task,
+    TimeTicks post_time,
+    TimeDelta delay,
+    TestNestability nestability)
+    : location(location),
+      task(task),
+      post_time(post_time),
+      delay(delay),
+      nestability(nestability) {}
+
+TimeTicks TestPendingTask::GetTimeToRun() const {
+  return post_time + delay;
+}
+
+bool TestPendingTask::ShouldRunBefore(const TestPendingTask& other) const {
+  if (nestability != other.nestability)
+    return (nestability == NESTABLE);
+  return GetTimeToRun() < other.GetTimeToRun();
+}
+
+TestPendingTask::~TestPendingTask() {}
+
+void TestPendingTask::AsValueInto(base::trace_event::TracedValue* state) const {
+  state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
+  state->SetString("posting_function", location.ToString());
+  state->SetInteger("post_time", post_time.ToInternalValue());
+  state->SetInteger("delay", delay.ToInternalValue());
+  switch (nestability) {
+    case NESTABLE:
+      state->SetString("nestability", "NESTABLE");
+      break;
+    case NON_NESTABLE:
+      state->SetString("nestability", "NON_NESTABLE");
+      break;
+  }
+  state->SetInteger("delay", delay.ToInternalValue());
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+TestPendingTask::AsValue() const {
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
+  AsValueInto(state.get());
+  return state;
+}
+
+std::string TestPendingTask::ToString() const {
+  std::string output("TestPendingTask(");
+  AsValue()->AppendAsTraceFormat(&output);
+  output += ")";
+  return output;
+}
+
+std::ostream& operator<<(std::ostream& os, const TestPendingTask& task) {
+  PrintTo(task, &os);
+  return os;
+}
+
+void PrintTo(const TestPendingTask& task, std::ostream* os) {
+  *os << task.ToString();
+}
+
+}  // namespace base
diff --git a/base/test/test_pending_task.h b/base/test/test_pending_task.h
new file mode 100644
index 0000000..829baa6
--- /dev/null
+++ b/base/test/test_pending_task.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_PENDING_TASK_H_
+#define BASE_TEST_TEST_PENDING_TASK_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+
+// TestPendingTask is a helper class for test TaskRunner
+// implementations.  See test_simple_task_runner.h for example usage.
+
+struct TestPendingTask {
+  enum TestNestability { NESTABLE, NON_NESTABLE };
+
+  TestPendingTask();
+  TestPendingTask(const tracked_objects::Location& location,
+                  const Closure& task,
+                  TimeTicks post_time,
+                  TimeDelta delay,
+                  TestNestability nestability);
+  ~TestPendingTask();
+
+  // Returns post_time + delay.
+  TimeTicks GetTimeToRun() const;
+
+  // Returns true if this task is nestable and |other| isn't, or if
+  // this task's time to run is strictly earlier than |other|'s time
+  // to run.
+  //
+  // Note that two tasks may both have the same nestability and delay.
+  // In that case, the caller must use some other criterion (probably
+  // the position in some queue) to break the tie.  Conveniently, the
+  // following STL functions already do so:
+  //
+  //   - std::min_element
+  //   - std::stable_sort
+  //
+  // but the following STL functions don't:
+  //
+  //   - std::max_element
+  //   - std::sort.
+  bool ShouldRunBefore(const TestPendingTask& other) const;
+
+  tracked_objects::Location location;
+  Closure task;
+  TimeTicks post_time;
+  TimeDelta delay;
+  TestNestability nestability;
+
+  // Functions for using test pending task with tracing, useful in unit
+  // testing.
+  void AsValueInto(base::trace_event::TracedValue* state) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  std::string ToString() const;
+};
+
+// gtest helpers which allow pretty printing of the tasks, very useful in unit
+// testing.
+std::ostream& operator<<(std::ostream& os, const TestPendingTask& task);
+void PrintTo(const TestPendingTask& task, std::ostream* os);
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_PENDING_TASK_H_
diff --git a/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc
new file mode 100644
index 0000000..32502f2
--- /dev/null
+++ b/base/test/test_pending_task_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_pending_task.h"
+
+#include "base/bind.h"
+#include "base/trace_event/trace_event.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(TestPendingTaskTest, TraceSupport) {
+  base::TestPendingTask task;
+
+  // Check that TestPendingTask can be sent to the trace subsystem.
+  TRACE_EVENT1("test", "TestPendingTask::TraceSupport", "task", task.AsValue());
+
+  // Just a basic check that the trace output has *something* in it.
+  EXPECT_THAT(task.AsValue()->ToString(), ::testing::HasSubstr("post_time"));
+}
+
+TEST(TestPendingTaskTest, ToString) {
+  base::TestPendingTask task;
+
+  // Just a basic check that ToString has *something* in it.
+  EXPECT_THAT(task.ToString(), ::testing::StartsWith("TestPendingTask("));
+}
+
+TEST(TestPendingTaskTest, GTestPrettyPrint) {
+  base::TestPendingTask task;
+
+  // Check that gtest is calling the TestPendingTask's PrintTo method.
+  EXPECT_THAT(::testing::PrintToString(task),
+              ::testing::StartsWith("TestPendingTask("));
+
+  // Check that pretty printing works with the gtest iostreams operator.
+  EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << task, "TestPendingTask(");
+}
+
+TEST(TestPendingTaskTest, ShouldRunBefore) {
+  base::TestPendingTask task_first;
+  task_first.delay = base::TimeDelta::FromMilliseconds(1);
+  base::TestPendingTask task_after;
+  task_after.delay = base::TimeDelta::FromMilliseconds(2);
+
+  EXPECT_FALSE(task_after.ShouldRunBefore(task_first))
+      << task_after << ".ShouldRunBefore(" << task_first << ")\n";
+  EXPECT_TRUE(task_first.ShouldRunBefore(task_after))
+      << task_first << ".ShouldRunBefore(" << task_after << ")\n";
+}
+
+}  // namespace
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
new file mode 100644
index 0000000..e3b1ffc
--- /dev/null
+++ b/base/test/test_reg_util_win.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_reg_util_win.h"
+
+#include "base/guid.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace registry_util {
+
+namespace {
+
+const wchar_t kTimestampDelimiter[] = L"$";
+const wchar_t kTempTestKeyPath[] = L"Software\\Chromium\\TempTestKeys";
+
+void DeleteStaleTestKeys(const base::Time& now,
+                         const base::string16& test_key_root) {
+  base::win::RegKey test_root_key;
+  if (test_root_key.Open(HKEY_CURRENT_USER,
+                         test_key_root.c_str(),
+                         KEY_ALL_ACCESS) != ERROR_SUCCESS) {
+    // This will occur on first-run, but is harmless.
+    return;
+  }
+
+  base::win::RegistryKeyIterator iterator_test_root_key(HKEY_CURRENT_USER,
+                                                        test_key_root.c_str());
+  for (; iterator_test_root_key.Valid(); ++iterator_test_root_key) {
+    base::string16 key_name = iterator_test_root_key.Name();
+    std::vector<base::string16> tokens;
+    if (!Tokenize(key_name, base::string16(kTimestampDelimiter), &tokens))
+      continue;
+    int64 key_name_as_number = 0;
+
+    if (!base::StringToInt64(tokens[0], &key_name_as_number)) {
+      test_root_key.DeleteKey(key_name.c_str());
+      continue;
+    }
+
+    base::Time key_time = base::Time::FromInternalValue(key_name_as_number);
+    base::TimeDelta age = now - key_time;
+
+    if (age > base::TimeDelta::FromHours(24))
+      test_root_key.DeleteKey(key_name.c_str());
+  }
+}
+
+base::string16 GenerateTempKeyPath(const base::string16& test_key_root,
+                                   const base::Time& timestamp) {
+  base::string16 key_path = test_key_root;
+  key_path += L"\\" + base::Int64ToString16(timestamp.ToInternalValue());
+  key_path += kTimestampDelimiter + base::ASCIIToUTF16(base::GenerateGUID());
+
+  return key_path;
+}
+
+}  // namespace
+
+RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride(
+    HKEY override,
+    const base::string16& key_path)
+    : override_(override) {
+  EXPECT_EQ(
+      ERROR_SUCCESS,
+      temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
+  EXPECT_EQ(ERROR_SUCCESS,
+            ::RegOverridePredefKey(override_, temp_key_.Handle()));
+}
+
+RegistryOverrideManager::
+    ScopedRegistryKeyOverride::~ScopedRegistryKeyOverride() {
+  ::RegOverridePredefKey(override_, NULL);
+  temp_key_.DeleteKey(L"");
+}
+
+RegistryOverrideManager::RegistryOverrideManager()
+    : timestamp_(base::Time::Now()), test_key_root_(kTempTestKeyPath) {
+  DeleteStaleTestKeys(timestamp_, test_key_root_);
+}
+
+RegistryOverrideManager::RegistryOverrideManager(
+    const base::Time& timestamp,
+    const base::string16& test_key_root)
+    : timestamp_(timestamp), test_key_root_(test_key_root) {
+  DeleteStaleTestKeys(timestamp_, test_key_root_);
+}
+
+RegistryOverrideManager::~RegistryOverrideManager() {}
+
+void RegistryOverrideManager::OverrideRegistry(HKEY override) {
+  base::string16 key_path = GenerateTempKeyPath(test_key_root_, timestamp_);
+  overrides_.push_back(new ScopedRegistryKeyOverride(override, key_path));
+}
+
+base::string16 GenerateTempKeyPath() {
+  return GenerateTempKeyPath(base::string16(kTempTestKeyPath),
+                             base::Time::Now());
+}
+
+}  // namespace registry_util
diff --git a/base/test/test_reg_util_win.h b/base/test/test_reg_util_win.h
new file mode 100644
index 0000000..5f23b7f
--- /dev/null
+++ b/base/test/test_reg_util_win.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_REG_UTIL_WIN_H_
+#define BASE_TEST_TEST_REG_UTIL_WIN_H_
+
+// Registry utility functions used only by tests.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "base/win/registry.h"
+
+namespace registry_util {
+
+// Allows a test to easily override registry hives so that it can start from a
+// known good state, or make sure to not leave any side effects once the test
+// completes. This supports parallel tests. All the overrides are scoped to the
+// lifetime of the override manager. Destroy the manager to undo the overrides.
+//
+// Overridden hives use keys stored at, for instance:
+//   HKCU\Software\Chromium\TempTestKeys\
+//       13028145911617809$02AB211C-CF73-478D-8D91-618E11998AED
+// The key path are comprises of:
+//   - The test key root, HKCU\Software\Chromium\TempTestKeys\
+//   - The base::Time::ToInternalValue of the creation time. This is used to
+//     delete stale keys left over from crashed tests.
+//   - A GUID used for preventing name collisions (although unlikely) between
+//     two RegistryOverrideManagers created with the same timestamp.
+class RegistryOverrideManager {
+ public:
+  RegistryOverrideManager();
+  ~RegistryOverrideManager();
+
+  // Override the given registry hive using a randomly generated temporary key.
+  // Multiple overrides to the same hive are not supported and lead to undefined
+  // behavior.
+  void OverrideRegistry(HKEY override);
+
+ private:
+  friend class RegistryOverrideManagerTest;
+
+  // Keeps track of one override.
+  class ScopedRegistryKeyOverride {
+   public:
+    ScopedRegistryKeyOverride(HKEY override, const base::string16& key_path);
+    ~ScopedRegistryKeyOverride();
+
+   private:
+    HKEY override_;
+    base::win::RegKey temp_key_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedRegistryKeyOverride);
+  };
+
+  // Used for testing only.
+  RegistryOverrideManager(const base::Time& timestamp,
+                          const base::string16& test_key_root);
+
+  base::Time timestamp_;
+  base::string16 guid_;
+
+  base::string16 test_key_root_;
+  ScopedVector<ScopedRegistryKeyOverride> overrides_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryOverrideManager);
+};
+
+// Generates a temporary key path that will be eventually deleted
+// automatically if the process crashes.
+base::string16 GenerateTempKeyPath();
+
+}  // namespace registry_util
+
+#endif  // BASE_TEST_TEST_REG_UTIL_WIN_H_
diff --git a/base/test/test_reg_util_win_unittest.cc b/base/test/test_reg_util_win_unittest.cc
new file mode 100644
index 0000000..216d58e
--- /dev/null
+++ b/base/test/test_reg_util_win_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace registry_util {
+
+namespace {
+const wchar_t kTestKeyPath[] = L"Software\\Chromium\\Foo\\Baz\\TestKey";
+const wchar_t kTestValueName[] = L"TestValue";
+}  // namespace
+
+class RegistryOverrideManagerTest : public testing::Test {
+ protected:
+  RegistryOverrideManagerTest() {
+    // We assign a fake test key path to our test RegistryOverrideManager
+    // so we don't interfere with any actual RegistryOverrideManagers running
+    // on the system. This fake path will be auto-deleted by other
+    // RegistryOverrideManagers in case we crash.
+    fake_test_key_root_ = registry_util::GenerateTempKeyPath();
+
+    // Ensure a clean test environment.
+    base::win::RegKey key(HKEY_CURRENT_USER);
+    key.DeleteKey(fake_test_key_root_.c_str());
+    key.DeleteKey(kTestKeyPath);
+  }
+
+  ~RegistryOverrideManagerTest() override {
+    base::win::RegKey key(HKEY_CURRENT_USER);
+    key.DeleteKey(fake_test_key_root_.c_str());
+  }
+
+  void AssertKeyExists(const base::string16& key_path) {
+    base::win::RegKey key;
+    ASSERT_EQ(ERROR_SUCCESS,
+              key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ))
+        << key_path << " does not exist.";
+  }
+
+  void AssertKeyAbsent(const base::string16& key_path) {
+    base::win::RegKey key;
+    ASSERT_NE(ERROR_SUCCESS,
+              key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ))
+        << key_path << " exists but it should not.";
+  }
+
+  void CreateKey(const base::string16& key_path) {
+    base::win::RegKey key;
+    EXPECT_EQ(ERROR_SUCCESS,
+              key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
+  }
+
+  base::string16 FakeOverrideManagerPath(const base::Time& time) {
+    return fake_test_key_root_ + L"\\" +
+           base::Int64ToString16(time.ToInternalValue());
+  }
+
+  void CreateManager(const base::Time& timestamp) {
+    manager_.reset(new RegistryOverrideManager(timestamp, fake_test_key_root_));
+    manager_->OverrideRegistry(HKEY_CURRENT_USER);
+  }
+
+  base::string16 fake_test_key_root_;
+  scoped_ptr<RegistryOverrideManager> manager_;
+};
+
+TEST_F(RegistryOverrideManagerTest, Basic) {
+  CreateManager(base::Time::Now());
+
+  base::win::RegKey create_key;
+  EXPECT_EQ(ERROR_SUCCESS,
+            create_key.Create(HKEY_CURRENT_USER, kTestKeyPath, KEY_ALL_ACCESS));
+  EXPECT_TRUE(create_key.Valid());
+  EXPECT_EQ(ERROR_SUCCESS, create_key.WriteValue(kTestValueName, 42));
+  create_key.Close();
+
+  AssertKeyExists(kTestKeyPath);
+
+  DWORD value;
+  base::win::RegKey read_key;
+  EXPECT_EQ(ERROR_SUCCESS,
+            read_key.Open(HKEY_CURRENT_USER, kTestKeyPath, KEY_READ));
+  EXPECT_TRUE(read_key.Valid());
+  EXPECT_EQ(ERROR_SUCCESS, read_key.ReadValueDW(kTestValueName, &value));
+  EXPECT_EQ(42, value);
+  read_key.Close();
+
+  manager_.reset();
+
+  AssertKeyAbsent(kTestKeyPath);
+}
+
+TEST_F(RegistryOverrideManagerTest, DeleteStaleKeys) {
+  base::Time::Exploded kTestTimeExploded = {2013, 11, 1, 4, 0, 0, 0, 0};
+  base::Time kTestTime = base::Time::FromUTCExploded(kTestTimeExploded);
+
+  base::string16 path_garbage = fake_test_key_root_ + L"\\Blah";
+  base::string16 path_very_stale =
+      FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(100));
+  base::string16 path_stale =
+      FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(5));
+  base::string16 path_current =
+      FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromMinutes(1));
+  base::string16 path_future =
+      FakeOverrideManagerPath(kTestTime + base::TimeDelta::FromMinutes(1));
+
+  CreateKey(path_garbage);
+  CreateKey(path_very_stale);
+  CreateKey(path_stale);
+  CreateKey(path_current);
+  CreateKey(path_future);
+
+  CreateManager(kTestTime);
+  manager_.reset();
+
+  AssertKeyAbsent(path_garbage);
+  AssertKeyAbsent(path_very_stale);
+  AssertKeyAbsent(path_stale);
+  AssertKeyExists(path_current);
+  AssertKeyExists(path_future);
+}
+
+}  // namespace registry_util
diff --git a/base/test/test_shortcut_win.cc b/base/test/test_shortcut_win.cc
new file mode 100644
index 0000000..eb074a3
--- /dev/null
+++ b/base/test/test_shortcut_win.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_shortcut_win.h"
+
+#include <windows.h>
+#include <shlobj.h>
+#include <propkey.h>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_propvariant.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+void ValidatePathsAreEqual(const base::FilePath& expected_path,
+                           const base::FilePath& actual_path) {
+  wchar_t long_expected_path_chars[MAX_PATH] = {0};
+  wchar_t long_actual_path_chars[MAX_PATH] = {0};
+
+  // If |expected_path| is empty confirm immediately that |actual_path| is also
+  // empty.
+  if (expected_path.empty()) {
+    EXPECT_TRUE(actual_path.empty());
+    return;
+  }
+
+  // Proceed with LongPathName matching which will also confirm the paths exist.
+  EXPECT_NE(0U, ::GetLongPathName(
+      expected_path.value().c_str(), long_expected_path_chars, MAX_PATH))
+          << "Failed to get LongPathName of " << expected_path.value();
+  EXPECT_NE(0U, ::GetLongPathName(
+      actual_path.value().c_str(), long_actual_path_chars, MAX_PATH))
+          << "Failed to get LongPathName of " << actual_path.value();
+
+  base::FilePath long_expected_path(long_expected_path_chars);
+  base::FilePath long_actual_path(long_actual_path_chars);
+  EXPECT_FALSE(long_expected_path.empty());
+  EXPECT_FALSE(long_actual_path.empty());
+
+  EXPECT_EQ(long_expected_path, long_actual_path);
+}
+
+void ValidateShortcut(const base::FilePath& shortcut_path,
+                      const ShortcutProperties& properties) {
+  ScopedComPtr<IShellLink> i_shell_link;
+  ScopedComPtr<IPersistFile> i_persist_file;
+
+  wchar_t read_target[MAX_PATH] = {0};
+  wchar_t read_working_dir[MAX_PATH] = {0};
+  wchar_t read_arguments[MAX_PATH] = {0};
+  wchar_t read_description[MAX_PATH] = {0};
+  wchar_t read_icon[MAX_PATH] = {0};
+  int read_icon_index = 0;
+
+  HRESULT hr;
+
+  // Initialize the shell interfaces.
+  EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.CreateInstance(
+      CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER)));
+  if (FAILED(hr))
+    return;
+
+  EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link.get())));
+  if (FAILED(hr))
+    return;
+
+  // Load the shortcut.
+  EXPECT_TRUE(SUCCEEDED(hr = i_persist_file->Load(
+      shortcut_path.value().c_str(), 0))) << "Failed to load shortcut at "
+                                          << shortcut_path.value();
+  if (FAILED(hr))
+    return;
+
+  if (properties.options & ShortcutProperties::PROPERTIES_TARGET) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH)));
+    ValidatePathsAreEqual(properties.target, base::FilePath(read_target));
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH)));
+    ValidatePathsAreEqual(properties.working_dir,
+                          base::FilePath(read_working_dir));
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetArguments(read_arguments, MAX_PATH)));
+    EXPECT_EQ(properties.arguments, read_arguments);
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetDescription(read_description, MAX_PATH)));
+    EXPECT_EQ(properties.description, read_description);
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ICON) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index)));
+    ValidatePathsAreEqual(properties.icon, base::FilePath(read_icon));
+    EXPECT_EQ(properties.icon_index, read_icon_index);
+  }
+
+  if (GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link.get())));
+    if (FAILED(hr))
+      return;
+
+    if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) {
+      ScopedPropVariant pv_app_id;
+      EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID,
+                                               pv_app_id.Receive()));
+      switch (pv_app_id.get().vt) {
+        case VT_EMPTY:
+          EXPECT_TRUE(properties.app_id.empty());
+          break;
+        case VT_LPWSTR:
+          EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal);
+          break;
+        default:
+          ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt;
+      }
+    }
+
+    if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+      ScopedPropVariant pv_dual_mode;
+      EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+                                               pv_dual_mode.Receive()));
+      switch (pv_dual_mode.get().vt) {
+        case VT_EMPTY:
+          EXPECT_FALSE(properties.dual_mode);
+          break;
+        case VT_BOOL:
+          EXPECT_EQ(properties.dual_mode,
+                    static_cast<bool>(pv_dual_mode.get().boolVal));
+          break;
+        default:
+          ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt;
+      }
+    }
+  }
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/test/test_shortcut_win.h b/base/test/test_shortcut_win.h
new file mode 100644
index 0000000..b828e8b
--- /dev/null
+++ b/base/test/test_shortcut_win.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SHORTCUT_WIN_H_
+#define BASE_TEST_TEST_SHORTCUT_WIN_H_
+
+#include "base/files/file_path.h"
+#include "base/win/shortcut.h"
+
+// Windows shortcut functions used only by tests.
+
+namespace base {
+namespace win {
+
+// Validates |actual_path|'s LongPathName case-insensitively matches
+// |expected_path|'s LongPathName.
+void ValidatePathsAreEqual(const base::FilePath& expected_path,
+                           const base::FilePath& actual_path);
+
+// Validates that a shortcut exists at |shortcut_path| with the expected
+// |properties|.
+// Logs gtest failures on failed verifications.
+void ValidateShortcut(const FilePath& shortcut_path,
+                      const ShortcutProperties& properties);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SHORTCUT_WIN_H_
diff --git a/base/test/test_simple_task_runner.cc b/base/test/test_simple_task_runner.cc
new file mode 100644
index 0000000..cc39fab
--- /dev/null
+++ b/base/test/test_simple_task_runner.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_simple_task_runner.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+TestSimpleTaskRunner::TestSimpleTaskRunner() {}
+
+TestSimpleTaskRunner::~TestSimpleTaskRunner() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool TestSimpleTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  pending_tasks_.push_back(
+      TestPendingTask(from_here, task, TimeTicks(), delay,
+                      TestPendingTask::NESTABLE));
+  return true;
+}
+
+bool TestSimpleTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  pending_tasks_.push_back(
+      TestPendingTask(from_here, task, TimeTicks(), delay,
+                      TestPendingTask::NON_NESTABLE));
+  return true;
+}
+
+bool TestSimpleTaskRunner::RunsTasksOnCurrentThread() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return true;
+}
+
+const std::deque<TestPendingTask>&
+TestSimpleTaskRunner::GetPendingTasks() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return pending_tasks_;
+}
+
+bool TestSimpleTaskRunner::HasPendingTask() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return !pending_tasks_.empty();
+}
+
+base::TimeDelta TestSimpleTaskRunner::NextPendingTaskDelay() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return pending_tasks_.front().GetTimeToRun() - base::TimeTicks();
+}
+
+void TestSimpleTaskRunner::ClearPendingTasks() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  pending_tasks_.clear();
+}
+
+void TestSimpleTaskRunner::RunPendingTasks() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // Swap with a local variable to avoid re-entrancy problems.
+  std::deque<TestPendingTask> tasks_to_run;
+  tasks_to_run.swap(pending_tasks_);
+  for (std::deque<TestPendingTask>::iterator it = tasks_to_run.begin();
+       it != tasks_to_run.end(); ++it) {
+    it->task.Run();
+  }
+}
+
+void TestSimpleTaskRunner::RunUntilIdle() {
+  while (!pending_tasks_.empty()) {
+    RunPendingTasks();
+  }
+}
+
+}  // namespace base
diff --git a/base/test/test_simple_task_runner.h b/base/test/test_simple_task_runner.h
new file mode 100644
index 0000000..7481b6d
--- /dev/null
+++ b/base/test/test_simple_task_runner.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
+#define BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
+
+#include <deque>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+class TimeDelta;
+
+// TestSimpleTaskRunner is a simple TaskRunner implementation that can
+// be used for testing.  It implements SingleThreadTaskRunner as that
+// interface implements SequencedTaskRunner, which in turn implements
+// TaskRunner, so TestSimpleTaskRunner can be passed in to a function
+// that accepts any *TaskRunner object.
+//
+// TestSimpleTaskRunner has the following properties which make it simple:
+//
+//   - It is non-thread safe; all member functions must be called on
+//     the same thread.
+//   - Tasks are simply stored in a queue in FIFO order, ignoring delay
+//     and nestability.
+//   - Tasks aren't guaranteed to be destroyed immediately after
+//     they're run.
+//
+// However, TestSimpleTaskRunner allows for reentrancy, in that it
+// handles the running of tasks that in turn call back into itself
+// (e.g., to post more tasks).
+//
+// If you need more complicated properties, consider using this class
+// as a template for writing a test TaskRunner implementation using
+// TestPendingTask.
+//
+// Note that, like any TaskRunner, TestSimpleTaskRunner is
+// ref-counted.
+class TestSimpleTaskRunner : public SingleThreadTaskRunner {
+ public:
+  TestSimpleTaskRunner();
+
+  // SingleThreadTaskRunner implementation.
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+  bool RunsTasksOnCurrentThread() const override;
+
+  const std::deque<TestPendingTask>& GetPendingTasks() const;
+  bool HasPendingTask() const;
+  base::TimeDelta NextPendingTaskDelay() const;
+
+  // Clears the queue of pending tasks without running them.
+  void ClearPendingTasks();
+
+  // Runs each current pending task in order and clears the queue.
+  // Any tasks posted by the tasks are not run.
+  virtual void RunPendingTasks();
+
+  // Runs pending tasks until the queue is empty.
+  void RunUntilIdle();
+
+ protected:
+  ~TestSimpleTaskRunner() override;
+
+  std::deque<TestPendingTask> pending_tasks_;
+  ThreadChecker thread_checker_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestSimpleTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
new file mode 100644
index 0000000..6c766eb
--- /dev/null
+++ b/base/test/test_suite.cc
@@ -0,0 +1,357 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_suite.h"
+
+#include "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/process/memory.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#if defined(OS_IOS)
+#include "base/test/test_listener_ios.h"
+#endif  // OS_IOS
+#endif  // OS_MACOSX
+
+#if !defined(OS_WIN)
+#include "base/i18n/rtl.h"
+#if !defined(OS_IOS)
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#endif
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/test/test_support_android.h"
+#endif
+
+#if defined(OS_IOS)
+#include "base/test/test_support_ios.h"
+#endif
+
+namespace base {
+
+namespace {
+
+class MaybeTestDisabler : public testing::EmptyTestEventListener {
+ public:
+  void OnTestStart(const testing::TestInfo& test_info) override {
+    ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info))
+        << "Probably the OS #ifdefs don't include all of the necessary "
+           "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
+           "after the code is preprocessed.";
+  }
+};
+
+class TestClientInitializer : public testing::EmptyTestEventListener {
+ public:
+  TestClientInitializer()
+      : old_command_line_(CommandLine::NO_PROGRAM) {
+  }
+
+  void OnTestStart(const testing::TestInfo& test_info) override {
+    old_command_line_ = *CommandLine::ForCurrentProcess();
+  }
+
+  void OnTestEnd(const testing::TestInfo& test_info) override {
+    *CommandLine::ForCurrentProcess() = old_command_line_;
+  }
+
+ private:
+  CommandLine old_command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestClientInitializer);
+};
+
+}  // namespace
+
+int RunUnitTestsUsingBaseTestSuite(int argc, char **argv) {
+  TestSuite test_suite(argc, argv);
+  return LaunchUnitTests(argc, argv,
+                         Bind(&TestSuite::Run, Unretained(&test_suite)));
+}
+
+TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) {
+  PreInitialize(true);
+  InitializeFromCommandLine(argc, argv);
+}
+
+#if defined(OS_WIN)
+TestSuite::TestSuite(int argc, wchar_t** argv)
+    : initialized_command_line_(false) {
+  PreInitialize(true);
+  InitializeFromCommandLine(argc, argv);
+}
+#endif  // defined(OS_WIN)
+
+TestSuite::TestSuite(int argc, char** argv, bool create_at_exit_manager)
+    : initialized_command_line_(false) {
+  PreInitialize(create_at_exit_manager);
+  InitializeFromCommandLine(argc, argv);
+}
+
+TestSuite::~TestSuite() {
+  if (initialized_command_line_)
+    CommandLine::Reset();
+}
+
+void TestSuite::InitializeFromCommandLine(int argc, char** argv) {
+  initialized_command_line_ = CommandLine::Init(argc, argv);
+  testing::InitGoogleTest(&argc, argv);
+  testing::InitGoogleMock(&argc, argv);
+
+#if defined(OS_IOS)
+  InitIOSRunHook(this, argc, argv);
+#endif
+}
+
+#if defined(OS_WIN)
+void TestSuite::InitializeFromCommandLine(int argc, wchar_t** argv) {
+  // Windows CommandLine::Init ignores argv anyway.
+  initialized_command_line_ = CommandLine::Init(argc, NULL);
+  testing::InitGoogleTest(&argc, argv);
+  testing::InitGoogleMock(&argc, argv);
+}
+#endif  // defined(OS_WIN)
+
+void TestSuite::PreInitialize(bool create_at_exit_manager) {
+#if defined(OS_WIN)
+  testing::GTEST_FLAG(catch_exceptions) = false;
+#endif
+  EnableTerminationOnHeapCorruption();
+#if defined(OS_LINUX) && defined(USE_AURA)
+  // When calling native char conversion functions (e.g wrctomb) we need to
+  // have the locale set. In the absence of such a call the "C" locale is the
+  // default. In the gtk code (below) gtk_init() implicitly sets a locale.
+  setlocale(LC_ALL, "");
+#endif  // defined(OS_LINUX) && defined(USE_AURA)
+
+  // On Android, AtExitManager is created in
+  // testing/android/native_test_wrapper.cc before main() is called.
+#if !defined(OS_ANDROID)
+  if (create_at_exit_manager)
+    at_exit_manager_.reset(new AtExitManager);
+#endif
+
+  // Don't add additional code to this function.  Instead add it to
+  // Initialize().  See bug 6436.
+}
+
+
+// static
+bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) {
+  return strncmp(test.name(), "MAYBE_", 6) == 0;
+}
+
+void TestSuite::CatchMaybeTests() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new MaybeTestDisabler);
+}
+
+void TestSuite::ResetCommandLine() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new TestClientInitializer);
+}
+
+void TestSuite::AddTestLauncherResultPrinter() {
+  // Only add the custom printer if requested.
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherOutput)) {
+    return;
+  }
+
+  FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+      switches::kTestLauncherOutput));
+
+  // Do not add the result printer if output path already exists. It's an
+  // indicator there is a process printing to that file, and we're likely
+  // its child. Do not clobber the results in that case.
+  if (PathExists(output_path)) {
+    LOG(WARNING) << "Test launcher output path " << output_path.AsUTF8Unsafe()
+                 << " exists. Not adding test launcher result printer.";
+    return;
+  }
+
+  XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
+  CHECK(printer->Initialize(output_path));
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(printer);
+}
+
+// Don't add additional code to this method.  Instead add it to
+// Initialize().  See bug 6436.
+int TestSuite::Run() {
+#if defined(OS_IOS)
+  RunTestsFromIOSApp();
+#endif
+
+#if defined(OS_MACOSX)
+  mac::ScopedNSAutoreleasePool scoped_pool;
+#endif
+
+  Initialize();
+  std::string client_func =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kTestChildProcess);
+
+  // Check to see if we are being run as a client process.
+  if (!client_func.empty())
+    return multi_process_function_list::InvokeChildProcessTest(client_func);
+#if defined(OS_IOS)
+  test_listener_ios::RegisterTestEndListener();
+#endif
+  int result = RUN_ALL_TESTS();
+
+#if defined(OS_MACOSX)
+  // This MUST happen before Shutdown() since Shutdown() tears down
+  // objects (such as NotificationService::current()) that Cocoa
+  // objects use to remove themselves as observers.
+  scoped_pool.Recycle();
+#endif
+
+  Shutdown();
+
+  return result;
+}
+
+// static
+void TestSuite::UnitTestAssertHandler(const std::string& str) {
+#if defined(OS_ANDROID)
+  // Correlating test stdio with logcat can be difficult, so we emit this
+  // helpful little hint about what was running.  Only do this for Android
+  // because other platforms don't separate out the relevant logs in the same
+  // way.
+  const ::testing::TestInfo* const test_info =
+      ::testing::UnitTest::GetInstance()->current_test_info();
+  if (test_info) {
+    LOG(ERROR) << "Currently running: " << test_info->test_case_name() << "."
+               << test_info->name();
+    fflush(stderr);
+  }
+#endif  // defined(OS_ANDROID)
+
+  // The logging system actually prints the message before calling the assert
+  // handler. Just exit now to avoid printing too many stack traces.
+  _exit(1);
+}
+
+void TestSuite::SuppressErrorDialogs() {
+#if defined(OS_WIN)
+  UINT new_flags = SEM_FAILCRITICALERRORS |
+                   SEM_NOGPFAULTERRORBOX |
+                   SEM_NOOPENFILEERRORBOX;
+
+  // Preserve existing error mode, as discussed at
+  // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
+  UINT existing_flags = SetErrorMode(new_flags);
+  SetErrorMode(existing_flags | new_flags);
+
+#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
+  // Suppress the "Debug Assertion Failed" dialog.
+  // TODO(hbono): remove this code when gtest has it.
+  // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion
+  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+#endif  // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
+#endif  // defined(OS_WIN)
+}
+
+void TestSuite::Initialize() {
+#if !defined(OS_IOS)
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWaitForDebugger)) {
+    debug::WaitForDebugger(60, true);
+  }
+#endif
+
+#if defined(OS_IOS)
+  InitIOSTestMessageLoop();
+#endif  // OS_IOS
+
+#if defined(OS_ANDROID)
+  InitAndroidTest();
+#else
+  // Initialize logging.
+  FilePath exe;
+  PathService::Get(FILE_EXE, &exe);
+  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_ALL;
+  settings.log_file = log_filename.value().c_str();
+  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
+  logging::InitLogging(settings);
+  // We want process and thread IDs because we may have multiple processes.
+  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
+  logging::SetLogItems(true, true, true, true);
+#endif  // else defined(OS_ANDROID)
+
+  CHECK(debug::EnableInProcessStackDumping());
+#if defined(OS_WIN)
+  // Make sure we run with high resolution timer to minimize differences
+  // between production code and test code.
+  Time::EnableHighResolutionTimer(true);
+#endif  // defined(OS_WIN)
+
+  // In some cases, we do not want to see standard error dialogs.
+  if (!debug::BeingDebugged() &&
+      !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
+    SuppressErrorDialogs();
+    debug::SetSuppressDebugUI(true);
+    logging::SetLogAssertHandler(UnitTestAssertHandler);
+  }
+
+  i18n::InitializeICU();
+  // On the Mac OS X command line, the default locale is *_POSIX. In Chromium,
+  // the locale is set via an OS X locale API and is never *_POSIX.
+  // Some tests (such as those involving word break iterator) will behave
+  // differently and fail if we use *POSIX locale. Setting it to en_US here
+  // does not affect tests that explicitly overrides the locale for testing.
+  // This can be an issue on all platforms other than Windows.
+  // TODO(jshin): Should we set the locale via an OS X locale API here?
+#if !defined(OS_WIN)
+#if defined(OS_IOS)
+  i18n::SetICUDefaultLocale("en_US");
+#else
+  std::string default_locale(uloc_getDefault());
+  if (EndsWith(default_locale, "POSIX", false))
+    i18n::SetICUDefaultLocale("en_US");
+#endif
+#endif
+
+  CatchMaybeTests();
+  ResetCommandLine();
+  AddTestLauncherResultPrinter();
+
+  TestTimeouts::Initialize();
+
+  trace_to_file_.BeginTracingFromCommandLineOptions();
+}
+
+void TestSuite::Shutdown() {
+}
+
+}  // namespace base
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
new file mode 100644
index 0000000..cf0dd3a
--- /dev/null
+++ b/base/test/test_suite.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUITE_H_
+#define BASE_TEST_TEST_SUITE_H_
+
+// Defines a basic test suite framework for running gtest based tests.  You can
+// instantiate this class in your main function and call its Run method to run
+// any gtest based tests that are linked into your executable.
+
+#include <string>
+
+#include "base/at_exit.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/trace_to_file.h"
+
+namespace testing {
+class TestInfo;
+}
+
+namespace base {
+
+// Instantiates TestSuite, runs it and returns exit code.
+int RunUnitTestsUsingBaseTestSuite(int argc, char **argv);
+
+class TestSuite {
+ public:
+  // Match function used by the GetTestCount method.
+  typedef bool (*TestMatch)(const testing::TestInfo&);
+
+  TestSuite(int argc, char** argv);
+#if defined(OS_WIN)
+  TestSuite(int argc, wchar_t** argv);
+#endif  // defined(OS_WIN)
+  virtual ~TestSuite();
+
+  // Returns true if the test is marked as "MAYBE_".
+  // When using different prefixes depending on platform, we use MAYBE_ and
+  // preprocessor directives to replace MAYBE_ with the target prefix.
+  static bool IsMarkedMaybe(const testing::TestInfo& test);
+
+  void CatchMaybeTests();
+
+  void ResetCommandLine();
+
+  void AddTestLauncherResultPrinter();
+
+  int Run();
+
+ protected:
+  // This constructor is only accessible to specialized test suite
+  // implementations which need to control the creation of an AtExitManager
+  // instance for the duration of the test.
+  TestSuite(int argc, char** argv, bool create_at_exit_manager);
+
+  // By default fatal log messages (e.g. from DCHECKs) result in error dialogs
+  // which gum up buildbots. Use a minimalistic assert handler which just
+  // terminates the process.
+  static void UnitTestAssertHandler(const std::string& str);
+
+  // Disable crash dialogs so that it doesn't gum up the buildbot
+  virtual void SuppressErrorDialogs();
+
+  // Override these for custom initialization and shutdown handling.  Use these
+  // instead of putting complex code in your constructor/destructor.
+
+  virtual void Initialize();
+  virtual void Shutdown();
+
+  // Make sure that we setup an AtExitManager so Singleton objects will be
+  // destroyed.
+  scoped_ptr<base::AtExitManager> at_exit_manager_;
+
+ private:
+  void InitializeFromCommandLine(int argc, char** argv);
+#if defined(OS_WIN)
+  void InitializeFromCommandLine(int argc, wchar_t** argv);
+#endif  // defined(OS_WIN)
+
+  // Basic initialization for the test suite happens here.
+  void PreInitialize(bool create_at_exit_manager);
+
+  test::TraceToFile trace_to_file_;
+
+  bool initialized_command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSuite);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUITE_H_
diff --git a/base/test/test_support_android.cc b/base/test/test_support_android.cc
new file mode 100644
index 0000000..11a0871
--- /dev/null
+++ b/base/test/test_support_android.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "base/android/path_utils.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_android.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace {
+
+struct RunState {
+  RunState(base::MessagePump::Delegate* delegate, int run_depth)
+      : delegate(delegate),
+        run_depth(run_depth),
+        should_quit(false) {
+  }
+
+  base::MessagePump::Delegate* delegate;
+
+  // Used to count how many Run() invocations are on the stack.
+  int run_depth;
+
+  // Used to flag that the current Run() invocation should return ASAP.
+  bool should_quit;
+};
+
+RunState* g_state = NULL;
+
+// A singleton WaitableEvent wrapper so we avoid a busy loop in
+// MessagePumpForUIStub. Other platforms use the native event loop which blocks
+// when there are no pending messages.
+class Waitable {
+ public:
+   static Waitable* GetInstance() {
+     return Singleton<Waitable>::get();
+   }
+
+   // Signals that there are more work to do.
+   void Signal() {
+     waitable_event_.Signal();
+   }
+
+   // Blocks until more work is scheduled.
+   void Block() {
+     waitable_event_.Wait();
+   }
+
+   void Quit() {
+     g_state->should_quit = true;
+     Signal();
+   }
+
+ private:
+  friend struct DefaultSingletonTraits<Waitable>;
+
+  Waitable()
+      : waitable_event_(false, false) {
+  }
+
+  base::WaitableEvent waitable_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(Waitable);
+};
+
+// The MessagePumpForUI implementation for test purpose.
+class MessagePumpForUIStub : public base::MessagePumpForUI {
+  ~MessagePumpForUIStub() override {}
+
+  void Start(base::MessagePump::Delegate* delegate) override {
+    NOTREACHED() << "The Start() method shouldn't be called in test, using"
+        " Run() method should be used.";
+  }
+
+  void Run(base::MessagePump::Delegate* delegate) override {
+    // The following was based on message_pump_glib.cc, except we're using a
+    // WaitableEvent since there are no native message loop to use.
+    RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
+
+    RunState* previous_state = g_state;
+    g_state = &state;
+
+    bool more_work_is_plausible = true;
+
+    for (;;) {
+      if (!more_work_is_plausible) {
+        Waitable::GetInstance()->Block();
+        if (g_state->should_quit)
+          break;
+      }
+
+      more_work_is_plausible = g_state->delegate->DoWork();
+      if (g_state->should_quit)
+        break;
+
+      base::TimeTicks delayed_work_time;
+      more_work_is_plausible |=
+          g_state->delegate->DoDelayedWork(&delayed_work_time);
+      if (g_state->should_quit)
+        break;
+
+      if (more_work_is_plausible)
+        continue;
+
+      more_work_is_plausible = g_state->delegate->DoIdleWork();
+      if (g_state->should_quit)
+        break;
+
+      more_work_is_plausible |= !delayed_work_time.is_null();
+    }
+
+    g_state = previous_state;
+  }
+
+  void Quit() override { Waitable::GetInstance()->Quit(); }
+
+  void ScheduleWork() override { Waitable::GetInstance()->Signal(); }
+
+  void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override {
+    Waitable::GetInstance()->Signal();
+  }
+};
+
+scoped_ptr<base::MessagePump> CreateMessagePumpForUIStub() {
+  return scoped_ptr<base::MessagePump>(new MessagePumpForUIStub());
+};
+
+// Provides the test path for DIR_MODULE and DIR_ANDROID_APP_DATA.
+bool GetTestProviderPath(int key, base::FilePath* result) {
+  switch (key) {
+    case base::DIR_ANDROID_APP_DATA: {
+      // For tests, app data is put in external storage.
+      return base::android::GetExternalStorageDirectory(result);
+    }
+    default:
+      return false;
+  }
+}
+
+void InitPathProvider(int key) {
+  base::FilePath path;
+  // If failed to override the key, that means the way has not been registered.
+  if (GetTestProviderPath(key, &path) && !PathService::Override(key, path))
+    PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
+}
+
+}  // namespace
+
+namespace base {
+
+void InitAndroidTestLogging() {
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+  // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+  logging::SetLogItems(false,    // Process ID
+                       false,    // Thread ID
+                       false,    // Timestamp
+                       false);   // Tick count
+}
+
+void InitAndroidTestPaths() {
+  InitPathProvider(DIR_MODULE);
+  InitPathProvider(DIR_ANDROID_APP_DATA);
+}
+
+void InitAndroidTestMessageLoop() {
+  if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub))
+    LOG(INFO) << "MessagePumpForUIFactory already set, unable to override.";
+}
+
+void InitAndroidTest() {
+  InitAndroidTestLogging();
+  InitAndroidTestPaths();
+  InitAndroidTestMessageLoop();
+}
+}  // namespace base
diff --git a/base/test/test_support_android.h b/base/test/test_support_android.h
new file mode 100644
index 0000000..062785e
--- /dev/null
+++ b/base/test/test_support_android.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUPPORT_ANDROID_H_
+#define BASE_TEST_TEST_SUPPORT_ANDROID_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Init logging for tests on Android. Logs will be output into Android's logcat.
+BASE_EXPORT void InitAndroidTestLogging();
+
+// Init path providers for tests on Android.
+BASE_EXPORT void InitAndroidTestPaths();
+
+// Init the message loop for tests on Android.
+BASE_EXPORT void InitAndroidTestMessageLoop();
+
+// Do all of the initializations above.
+BASE_EXPORT void InitAndroidTest();
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUPPORT_ANDROID_H_
diff --git a/base/test/test_support_ios.h b/base/test/test_support_ios.h
new file mode 100644
index 0000000..c71cf0d
--- /dev/null
+++ b/base/test/test_support_ios.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SUPPORT_IOS_H_
+#define BASE_TEST_TEST_SUPPORT_IOS_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+// Inits the message loop for tests on iOS.
+void InitIOSTestMessageLoop();
+
+// Inits the run hook for tests on iOS.
+void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]);
+
+// Launches an iOS app that runs the tests in the suite passed to
+// InitIOSRunHook.
+void RunTestsFromIOSApp();
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUPPORT_IOS_H_
diff --git a/base/test/test_support_ios.mm b/base/test/test_support_ios.mm
new file mode 100644
index 0000000..3b31da6
--- /dev/null
+++ b/base/test/test_support_ios.mm
@@ -0,0 +1,216 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_default.h"
+#include "base/test/test_suite.h"
+#include "testing/coverage_util_ios.h"
+
+// Springboard will kill any iOS app that fails to check in after launch within
+// a given time. Starting a UIApplication before invoking TestSuite::Run
+// prevents this from happening.
+
+// InitIOSRunHook saves the TestSuite and argc/argv, then invoking
+// RunTestsFromIOSApp calls UIApplicationMain(), providing an application
+// delegate class: ChromeUnitTestDelegate. The delegate implements
+// application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run
+// method.
+
+// Since the executable isn't likely to be a real iOS UI, the delegate puts up a
+// window displaying the app name. If a bunch of apps using MainHook are being
+// run in a row, this provides an indication of which one is currently running.
+
+static base::TestSuite* g_test_suite = NULL;
+static int g_argc;
+static char** g_argv;
+
+@interface UIApplication (Testing)
+- (void) _terminateWithStatus:(int)status;
+@end
+
+#if TARGET_IPHONE_SIMULATOR
+// Xcode 6 introduced behavior in the iOS Simulator where the software
+// keyboard does not appear if a hardware keyboard is connected. The following
+// declaration allows this behavior to be overriden when the app starts up.
+@interface UIKeyboardImpl
++ (instancetype)sharedInstance;
+- (void)setAutomaticMinimizationEnabled:(BOOL)enabled;
+- (void)setSoftwareKeyboardShownByTouch:(BOOL)enabled;
+@end
+#endif  // TARGET_IPHONE_SIMULATOR
+
+@interface ChromeUnitTestDelegate : NSObject {
+ @private
+  base::scoped_nsobject<UIWindow> window_;
+}
+- (void)runTests;
+@end
+
+@implementation ChromeUnitTestDelegate
+
+- (BOOL)application:(UIApplication *)application
+    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+#if TARGET_IPHONE_SIMULATOR
+  // Xcode 6 introduced behavior in the iOS Simulator where the software
+  // keyboard does not appear if a hardware keyboard is connected. The following
+  // calls override this behavior by ensuring that the software keyboard is
+  // always shown.
+  [[UIKeyboardImpl sharedInstance] setAutomaticMinimizationEnabled:NO];
+  [[UIKeyboardImpl sharedInstance] setSoftwareKeyboardShownByTouch:YES];
+#endif  // TARGET_IPHONE_SIMULATOR
+
+  CGRect bounds = [[UIScreen mainScreen] bounds];
+
+  // Yes, this is leaked, it's just to make what's running visible.
+  window_.reset([[UIWindow alloc] initWithFrame:bounds]);
+  [window_ setBackgroundColor:[UIColor whiteColor]];
+  [window_ makeKeyAndVisible];
+
+  // Add a label with the app name.
+  UILabel* label = [[[UILabel alloc] initWithFrame:bounds] autorelease];
+  label.text = [[NSProcessInfo processInfo] processName];
+  label.textAlignment = NSTextAlignmentCenter;
+  [window_ addSubview:label];
+
+  if ([self shouldRedirectOutputToFile])
+    [self redirectOutput];
+
+  // Queue up the test run.
+  [self performSelector:@selector(runTests)
+             withObject:nil
+             afterDelay:0.1];
+  return YES;
+}
+
+// Returns true if the gtest output should be redirected to a file, then sent
+// to NSLog when compleete. This redirection is used because gtest only writes
+// output to stdout, but results must be written to NSLog in order to show up in
+// the device log that is retrieved from the device by the host.
+- (BOOL)shouldRedirectOutputToFile {
+#if !TARGET_IPHONE_SIMULATOR
+  return !base::debug::BeingDebugged();
+#endif  // TARGET_IPHONE_SIMULATOR
+  return NO;
+}
+
+// Returns the path to the directory to store gtest output files.
+- (NSString*)outputPath {
+  NSArray* searchPath =
+      NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
+                                          NSUserDomainMask,
+                                          YES);
+  CHECK([searchPath count] > 0) << "Failed to get the Documents folder";
+  return [searchPath objectAtIndex:0];
+}
+
+// Returns the path to file that stdout is redirected to.
+- (NSString*)stdoutPath {
+  return [[self outputPath] stringByAppendingPathComponent:@"stdout.log"];
+}
+
+// Returns the path to file that stderr is redirected to.
+- (NSString*)stderrPath {
+  return [[self outputPath] stringByAppendingPathComponent:@"stderr.log"];
+}
+
+// Redirects stdout and stderr to files in the Documents folder in the app's
+// sandbox.
+- (void)redirectOutput {
+  freopen([[self stdoutPath] UTF8String], "w+", stdout);
+  freopen([[self stderrPath] UTF8String], "w+", stderr);
+}
+
+// Reads the redirected gtest output from a file and writes it to NSLog.
+- (void)writeOutputToNSLog {
+  // Close the redirected stdout and stderr files so that the content written to
+  // NSLog doesn't end up in these files.
+  fclose(stdout);
+  fclose(stderr);
+  for (NSString* path in @[ [self stdoutPath], [self stderrPath]]) {
+    NSString* content = [NSString stringWithContentsOfFile:path
+                                                  encoding:NSUTF8StringEncoding
+                                                     error:NULL];
+    NSArray* lines = [content componentsSeparatedByCharactersInSet:
+        [NSCharacterSet newlineCharacterSet]];
+
+    NSLog(@"Writing contents of %@ to NSLog", path);
+    for (NSString* line in lines) {
+      NSLog(@"%@", line);
+    }
+  }
+}
+
+- (void)runTests {
+  int exitStatus = g_test_suite->Run();
+
+  if ([self shouldRedirectOutputToFile])
+    [self writeOutputToNSLog];
+
+  // If a test app is too fast, it will exit before Instruments has has a
+  // a chance to initialize and no test results will be seen.
+  // TODO(ios): crbug.com/137010 Figure out how much time is actually needed,
+  // and sleep only to make sure that much time has elapsed since launch.
+  [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
+  window_.reset();
+
+  // Use the hidden selector to try and cleanly take down the app (otherwise
+  // things can think the app crashed even on a zero exit status).
+  UIApplication* application = [UIApplication sharedApplication];
+  [application _terminateWithStatus:exitStatus];
+
+  coverage_util::FlushCoverageDataIfNecessary();
+
+  exit(exitStatus);
+}
+
+@end
+
+namespace {
+
+scoped_ptr<base::MessagePump> CreateMessagePumpForUIForTests() {
+  // A default MessagePump will do quite nicely in tests.
+  return scoped_ptr<base::MessagePump>(new base::MessagePumpDefault());
+}
+
+}  // namespace
+
+namespace base {
+
+void InitIOSTestMessageLoop() {
+  MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIForTests);
+}
+
+void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]) {
+  g_test_suite = suite;
+  g_argc = argc;
+  g_argv = argv;
+}
+
+void RunTestsFromIOSApp() {
+  // When TestSuite::Run is invoked it calls RunTestsFromIOSApp(). On the first
+  // invocation, this method fires up an iOS app via UIApplicationMain. Since
+  // UIApplicationMain does not return until the app exits, control does not
+  // return to the initial TestSuite::Run invocation, so the app invokes
+  // TestSuite::Run a second time and since |ran_hook| is true at this point,
+  // this method is a no-op and control returns to TestSuite:Run so that test
+  // are executed. Once the app exits, RunTestsFromIOSApp calls exit() so that
+  // control is not returned to the initial invocation of TestSuite::Run.
+  static bool ran_hook = false;
+  if (!ran_hook) {
+    ran_hook = true;
+    mac::ScopedNSAutoreleasePool pool;
+    int exit_status = UIApplicationMain(g_argc, g_argv, nil,
+                                        @"ChromeUnitTestDelegate");
+    exit(exit_status);
+  }
+}
+
+}  // namespace base
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
new file mode 100644
index 0000000..84aa53c
--- /dev/null
+++ b/base/test/test_switches.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_switches.h"
+
+// Maximum number of tests to run in a single batch.
+const char switches::kTestLauncherBatchLimit[] = "test-launcher-batch-limit";
+
+// Sets defaults desirable for the continuous integration bots, e.g. parallel
+// test execution and test retries.
+const char switches::kTestLauncherBotMode[] =
+    "test-launcher-bot-mode";
+
+// Makes it possible to debug the launcher itself. By default the launcher
+// automatically switches to single process mode when it detects presence
+// of debugger.
+const char switches::kTestLauncherDebugLauncher[] =
+    "test-launcher-debug-launcher";
+
+// Path to file containing test filter (one pattern per line).
+const char switches::kTestLauncherFilterFile[] = "test-launcher-filter-file";
+
+// Number of parallel test launcher jobs.
+const char switches::kTestLauncherJobs[] = "test-launcher-jobs";
+
+// Path to list of compiled in tests.
+const char switches::kTestLauncherListTests[] = "test-launcher-list-tests";
+
+// Path to test results file in our custom test launcher format.
+const char switches::kTestLauncherOutput[] = "test-launcher-output";
+
+// Maximum number of times to retry a test after failure.
+const char switches::kTestLauncherRetryLimit[] = "test-launcher-retry-limit";
+
+// Path to test results file with all the info from the test launcher.
+const char switches::kTestLauncherSummaryOutput[] =
+    "test-launcher-summary-output";
+
+// Flag controlling when test stdio is displayed as part of the launcher's
+// standard output.
+const char switches::kTestLauncherPrintTestStdio[] =
+    "test-launcher-print-test-stdio";
+
+// Print a writable path and exit (for internal use).
+const char switches::kTestLauncherPrintWritablePath[] =
+    "test-launcher-print-writable-path";
+
+// Index of the test shard to run, starting from 0 (first shard) to total shards
+// minus one (last shard).
+const char switches::kTestLauncherShardIndex[] =
+    "test-launcher-shard-index";
+
+// Total number of shards. Must be the same for all shards.
+const char switches::kTestLauncherTotalShards[] =
+    "test-launcher-total-shards";
+
+// Time (in milliseconds) that the tests should wait before timing out.
+const char switches::kTestLauncherTimeout[] = "test-launcher-timeout";
+// TODO(phajdan.jr): Clean up the switch names.
+const char switches::kTestTinyTimeout[] = "test-tiny-timeout";
+const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout";
+const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
new file mode 100644
index 0000000..f145f1e
--- /dev/null
+++ b/base/test/test_switches.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_SWITCHES_H_
+#define BASE_TEST_TEST_SWITCHES_H_
+
+namespace switches {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kTestLauncherBatchLimit[];
+extern const char kTestLauncherBotMode[];
+extern const char kTestLauncherDebugLauncher[];
+extern const char kTestLauncherFilterFile[];
+extern const char kTestLauncherJobs[];
+extern const char kTestLauncherListTests[];
+extern const char kTestLauncherOutput[];
+extern const char kTestLauncherRetryLimit[];
+extern const char kTestLauncherSummaryOutput[];
+extern const char kTestLauncherPrintTestStdio[];
+extern const char kTestLauncherPrintWritablePath[];
+extern const char kTestLauncherShardIndex[];
+extern const char kTestLauncherTotalShards[];
+extern const char kTestLauncherTimeout[];
+extern const char kTestTinyTimeout[];
+extern const char kUiTestActionTimeout[];
+extern const char kUiTestActionMaxTimeout[];
+
+}  // namespace switches
+
+#endif  // BASE_TEST_TEST_SWITCHES_H_
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
new file mode 100644
index 0000000..b30d6c3
--- /dev/null
+++ b/base/test/test_timeouts.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_timeouts.h"
+
+#include <algorithm>
+
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/test_switches.h"
+
+namespace {
+
+// ASan/TSan/MSan instrument each memory access. This may slow the execution
+// down significantly.
+#if defined(MEMORY_SANITIZER)
+// For MSan the slowdown depends heavily on the value of msan_track_origins GYP
+// flag. The multiplier below corresponds to msan_track_origins=1.
+static const int kTimeoutMultiplier = 6;
+#elif defined(ADDRESS_SANITIZER) && defined(OS_WIN)
+// Asan/Win has not been optimized yet, give it a higher
+// timeout multiplier. See http://crbug.com/412471
+static const int kTimeoutMultiplier = 3;
+#elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
+    defined(SYZYASAN)
+static const int kTimeoutMultiplier = 2;
+#else
+static const int kTimeoutMultiplier = 1;
+#endif
+
+const int kAlmostInfiniteTimeoutMs = 100000000;
+
+// Sets value to the greatest of:
+// 1) value's current value multiplied by kTimeoutMultiplier (assuming
+// InitializeTimeout is called only once per value).
+// 2) min_value.
+// 3) the numerical value given by switch_name on the command line multiplied
+// by kTimeoutMultiplier.
+void InitializeTimeout(const char* switch_name, int min_value, int* value) {
+  DCHECK(value);
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
+    std::string string_value(base::CommandLine::ForCurrentProcess()->
+         GetSwitchValueASCII(switch_name));
+    int timeout;
+    base::StringToInt(string_value, &timeout);
+    *value = std::max(*value, timeout);
+  }
+  *value *= kTimeoutMultiplier;
+  *value = std::max(*value, min_value);
+}
+
+// Sets value to the greatest of:
+// 1) value's current value multiplied by kTimeoutMultiplier.
+// 2) 0
+// 3) the numerical value given by switch_name on the command line multiplied
+// by kTimeoutMultiplier.
+void InitializeTimeout(const char* switch_name, int* value) {
+  InitializeTimeout(switch_name, 0, value);
+}
+
+}  // namespace
+
+// static
+bool TestTimeouts::initialized_ = false;
+
+// The timeout values should increase in the order they appear in this block.
+// static
+int TestTimeouts::tiny_timeout_ms_ = 100;
+int TestTimeouts::action_timeout_ms_ = 10000;
+#ifndef NDEBUG
+int TestTimeouts::action_max_timeout_ms_ = 45000;
+#else
+int TestTimeouts::action_max_timeout_ms_ = 30000;
+#endif  // NDEBUG
+
+int TestTimeouts::test_launcher_timeout_ms_ = 45000;
+
+// static
+void TestTimeouts::Initialize() {
+  if (initialized_) {
+    NOTREACHED();
+    return;
+  }
+  initialized_ = true;
+
+  if (base::debug::BeingDebugged()) {
+    fprintf(stdout,
+        "Detected presence of a debugger, running without test timeouts.\n");
+  }
+
+  // Note that these timeouts MUST be initialized in the correct order as
+  // per the CHECKS below.
+  InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
+  InitializeTimeout(switches::kUiTestActionTimeout,
+                    base::debug::BeingDebugged() ? kAlmostInfiniteTimeoutMs
+                                                 : tiny_timeout_ms_,
+                    &action_timeout_ms_);
+  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
+                    &action_max_timeout_ms_);
+
+  // Test launcher timeout is independent from anything above action timeout.
+  InitializeTimeout(switches::kTestLauncherTimeout, action_timeout_ms_,
+                    &test_launcher_timeout_ms_);
+
+  // The timeout values should be increasing in the right order.
+  CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
+  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
+
+  CHECK(action_timeout_ms_ <= test_launcher_timeout_ms_);
+}
diff --git a/base/test/test_timeouts.h b/base/test/test_timeouts.h
new file mode 100644
index 0000000..2819e4a
--- /dev/null
+++ b/base/test/test_timeouts.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_TIMEOUTS_H_
+#define BASE_TEST_TEST_TIMEOUTS_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+// Returns common timeouts to use in tests. Makes it possible to adjust
+// the timeouts for different environments (like Valgrind).
+class TestTimeouts {
+ public:
+  // Initializes the timeouts. Non thread-safe. Should be called exactly once
+  // by the test suite.
+  static void Initialize();
+
+  // Timeout for actions that are expected to finish "almost instantly".
+  static base::TimeDelta tiny_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(tiny_timeout_ms_);
+  }
+
+  // Timeout to wait for something to happen. If you are not sure
+  // which timeout to use, this is the one you want.
+  static base::TimeDelta action_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(action_timeout_ms_);
+  }
+
+  // Timeout longer than the above, but still suitable to use
+  // multiple times in a single test. Use if the timeout above
+  // is not sufficient.
+  static base::TimeDelta action_max_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(action_max_timeout_ms_);
+  }
+
+  // Timeout for a single test launched used built-in test launcher.
+  // Do not use outside of the test launcher.
+  static base::TimeDelta test_launcher_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(test_launcher_timeout_ms_);
+  }
+
+ private:
+  static bool initialized_;
+
+  static int tiny_timeout_ms_;
+  static int action_timeout_ms_;
+  static int action_max_timeout_ms_;
+  static int test_launcher_timeout_ms_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TestTimeouts);
+};
+
+#endif  // BASE_TEST_TEST_TIMEOUTS_H_
diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc
new file mode 100644
index 0000000..6a12190
--- /dev/null
+++ b/base/test/thread_test_helper.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/thread_test_helper.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+ThreadTestHelper::ThreadTestHelper(
+    scoped_refptr<SingleThreadTaskRunner> target_thread)
+    : test_result_(false),
+      target_thread_(target_thread.Pass()),
+      done_event_(false, false) {
+}
+
+bool ThreadTestHelper::Run() {
+  if (!target_thread_->PostTask(
+          FROM_HERE, base::Bind(&ThreadTestHelper::RunInThread, this))) {
+    return false;
+  }
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  done_event_.Wait();
+  return test_result_;
+}
+
+void ThreadTestHelper::RunTest() { set_test_result(true); }
+
+ThreadTestHelper::~ThreadTestHelper() {}
+
+void ThreadTestHelper::RunInThread() {
+  RunTest();
+  done_event_.Signal();
+}
+
+}  // namespace base
diff --git a/base/test/thread_test_helper.h b/base/test/thread_test_helper.h
new file mode 100644
index 0000000..926da73
--- /dev/null
+++ b/base/test/thread_test_helper.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_THREAD_TEST_HELPER_H_
+#define BASE_TEST_THREAD_TEST_HELPER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// Helper class that executes code on a given thread while blocking on the
+// invoking thread. To use, derive from this class and overwrite RunTest. An
+// alternative use of this class is to use it directly.  It will then block
+// until all pending tasks on a given thread have been executed.
+class ThreadTestHelper : public RefCountedThreadSafe<ThreadTestHelper> {
+ public:
+  explicit ThreadTestHelper(
+      scoped_refptr<SingleThreadTaskRunner> target_thread);
+
+  // True if RunTest() was successfully executed on the target thread.
+  bool Run() WARN_UNUSED_RESULT;
+
+  virtual void RunTest();
+
+ protected:
+  friend class RefCountedThreadSafe<ThreadTestHelper>;
+
+  virtual ~ThreadTestHelper();
+
+  // Use this method to store the result of RunTest().
+  void set_test_result(bool test_result) { test_result_ = test_result; }
+
+ private:
+  void RunInThread();
+
+  bool test_result_;
+  scoped_refptr<SingleThreadTaskRunner> target_thread_;
+  WaitableEvent done_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadTestHelper);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_THREAD_TEST_HELPER_H_
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
new file mode 100644
index 0000000..3de58e7
--- /dev/null
+++ b/base/test/trace_event_analyzer.cc
@@ -0,0 +1,968 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/trace_event_analyzer.h"
+
+#include <algorithm>
+#include <math.h>
+#include <set>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+namespace trace_analyzer {
+
+// TraceEvent
+
+TraceEvent::TraceEvent()
+    : thread(0, 0),
+      timestamp(0),
+      duration(0),
+      phase(TRACE_EVENT_PHASE_BEGIN),
+      other_event(NULL) {
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+bool TraceEvent::SetFromJSON(const base::Value* event_value) {
+  if (event_value->GetType() != base::Value::TYPE_DICTIONARY) {
+    LOG(ERROR) << "Value must be TYPE_DICTIONARY";
+    return false;
+  }
+  const base::DictionaryValue* dictionary =
+      static_cast<const base::DictionaryValue*>(event_value);
+
+  std::string phase_str;
+  const base::DictionaryValue* args = NULL;
+
+  if (!dictionary->GetString("ph", &phase_str)) {
+    LOG(ERROR) << "ph is missing from TraceEvent JSON";
+    return false;
+  }
+
+  phase = *phase_str.data();
+
+  bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
+  bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
+  bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_END);
+
+  if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
+    LOG(ERROR) << "pid is missing from TraceEvent JSON";
+    return false;
+  }
+  if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
+    LOG(ERROR) << "tid is missing from TraceEvent JSON";
+    return false;
+  }
+  if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
+    LOG(ERROR) << "ts is missing from TraceEvent JSON";
+    return false;
+  }
+  if (may_have_duration) {
+    dictionary->GetDouble("dur", &duration);
+  }
+  if (!dictionary->GetString("cat", &category)) {
+    LOG(ERROR) << "cat is missing from TraceEvent JSON";
+    return false;
+  }
+  if (!dictionary->GetString("name", &name)) {
+    LOG(ERROR) << "name is missing from TraceEvent JSON";
+    return false;
+  }
+  if (!dictionary->GetDictionary("args", &args)) {
+    LOG(ERROR) << "args is missing from TraceEvent JSON";
+    return false;
+  }
+  if (require_id && !dictionary->GetString("id", &id)) {
+    LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
+    return false;
+  }
+
+  // For each argument, copy the type and create a trace_analyzer::TraceValue.
+  for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
+       it.Advance()) {
+    std::string str;
+    bool boolean = false;
+    int int_num = 0;
+    double double_num = 0.0;
+    if (it.value().GetAsString(&str)) {
+      arg_strings[it.key()] = str;
+    } else if (it.value().GetAsInteger(&int_num)) {
+      arg_numbers[it.key()] = static_cast<double>(int_num);
+    } else if (it.value().GetAsBoolean(&boolean)) {
+      arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0);
+    } else if (it.value().GetAsDouble(&double_num)) {
+      arg_numbers[it.key()] = double_num;
+    } else {
+      LOG(WARNING) << "Value type of argument is not supported: " <<
+          static_cast<int>(it.value().GetType());
+      continue;  // Skip non-supported arguments.
+    }
+  }
+
+  return true;
+}
+
+double TraceEvent::GetAbsTimeToOtherEvent() const {
+  return fabs(other_event->timestamp - timestamp);
+}
+
+bool TraceEvent::GetArgAsString(const std::string& name,
+                                std::string* arg) const {
+  std::map<std::string, std::string>::const_iterator i = arg_strings.find(name);
+  if (i != arg_strings.end()) {
+    *arg = i->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::GetArgAsNumber(const std::string& name,
+                                double* arg) const {
+  std::map<std::string, double>::const_iterator i = arg_numbers.find(name);
+  if (i != arg_numbers.end()) {
+    *arg = i->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::HasStringArg(const std::string& name) const {
+  return (arg_strings.find(name) != arg_strings.end());
+}
+
+bool TraceEvent::HasNumberArg(const std::string& name) const {
+  return (arg_numbers.find(name) != arg_numbers.end());
+}
+
+std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
+  std::string arg_string;
+  bool result = GetArgAsString(name, &arg_string);
+  DCHECK(result);
+  return arg_string;
+}
+
+double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
+  double arg_double = 0;
+  bool result = GetArgAsNumber(name, &arg_double);
+  DCHECK(result);
+  return arg_double;
+}
+
+int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
+  double arg_double = 0;
+  bool result = GetArgAsNumber(name, &arg_double);
+  DCHECK(result);
+  return static_cast<int>(arg_double);
+}
+
+bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
+  double arg_double = 0;
+  bool result = GetArgAsNumber(name, &arg_double);
+  DCHECK(result);
+  return (arg_double != 0.0);
+}
+
+// QueryNode
+
+QueryNode::QueryNode(const Query& query) : query_(query) {
+}
+
+QueryNode::~QueryNode() {
+}
+
+// Query
+
+Query::Query(TraceEventMember member)
+    : type_(QUERY_EVENT_MEMBER),
+      operator_(OP_INVALID),
+      member_(member),
+      number_(0),
+      is_pattern_(false) {
+}
+
+Query::Query(TraceEventMember member, const std::string& arg_name)
+    : type_(QUERY_EVENT_MEMBER),
+      operator_(OP_INVALID),
+      member_(member),
+      number_(0),
+      string_(arg_name),
+      is_pattern_(false) {
+}
+
+Query::Query(const Query& query)
+    : type_(query.type_),
+      operator_(query.operator_),
+      left_(query.left_),
+      right_(query.right_),
+      member_(query.member_),
+      number_(query.number_),
+      string_(query.string_),
+      is_pattern_(query.is_pattern_) {
+}
+
+Query::~Query() {
+}
+
+Query Query::String(const std::string& str) {
+  return Query(str);
+}
+
+Query Query::Double(double num) {
+  return Query(num);
+}
+
+Query Query::Int(int32 num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Uint(uint32 num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Bool(bool boolean) {
+  return Query(boolean ? 1.0 : 0.0);
+}
+
+Query Query::Phase(char phase) {
+  return Query(static_cast<double>(phase));
+}
+
+Query Query::Pattern(const std::string& pattern) {
+  Query query(pattern);
+  query.is_pattern_ = true;
+  return query;
+}
+
+bool Query::Evaluate(const TraceEvent& event) const {
+  // First check for values that can convert to bool.
+
+  // double is true if != 0:
+  double bool_value = 0.0;
+  bool is_bool = GetAsDouble(event, &bool_value);
+  if (is_bool)
+    return (bool_value != 0.0);
+
+  // string is true if it is non-empty:
+  std::string str_value;
+  bool is_str = GetAsString(event, &str_value);
+  if (is_str)
+    return !str_value.empty();
+
+  DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
+      << "Invalid query: missing boolean expression";
+  DCHECK(left_.get());
+  DCHECK(right_.get() || is_unary_operator());
+
+  if (is_comparison_operator()) {
+    DCHECK(left().is_value() && right().is_value())
+        << "Invalid query: comparison operator used between event member and "
+           "value.";
+    bool compare_result = false;
+    if (CompareAsDouble(event, &compare_result))
+      return compare_result;
+    if (CompareAsString(event, &compare_result))
+      return compare_result;
+    return false;
+  }
+  // It's a logical operator.
+  switch (operator_) {
+    case OP_AND:
+      return left().Evaluate(event) && right().Evaluate(event);
+    case OP_OR:
+      return left().Evaluate(event) || right().Evaluate(event);
+    case OP_NOT:
+      return !left().Evaluate(event);
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
+  double lhs, rhs;
+  if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
+    return false;
+  switch (operator_) {
+    case OP_EQ:
+      *result = (lhs == rhs);
+      return true;
+    case OP_NE:
+      *result = (lhs != rhs);
+      return true;
+    case OP_LT:
+      *result = (lhs < rhs);
+      return true;
+    case OP_LE:
+      *result = (lhs <= rhs);
+      return true;
+    case OP_GT:
+      *result = (lhs > rhs);
+      return true;
+    case OP_GE:
+      *result = (lhs >= rhs);
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
+  std::string lhs, rhs;
+  if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
+    return false;
+  switch (operator_) {
+    case OP_EQ:
+      if (right().is_pattern_)
+        *result = MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = MatchPattern(rhs, lhs);
+      else
+        *result = (lhs == rhs);
+      return true;
+    case OP_NE:
+      if (right().is_pattern_)
+        *result = !MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = !MatchPattern(rhs, lhs);
+      else
+        *result = (lhs != rhs);
+      return true;
+    case OP_LT:
+      *result = (lhs < rhs);
+      return true;
+    case OP_LE:
+      *result = (lhs <= rhs);
+      return true;
+    case OP_GT:
+      *result = (lhs > rhs);
+      return true;
+    case OP_GE:
+      *result = (lhs >= rhs);
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
+                                       double* num) const {
+  DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
+  DCHECK(left_.get());
+  DCHECK(right_.get() || is_unary_operator());
+
+  double lhs = 0, rhs = 0;
+  if (!left().GetAsDouble(event, &lhs))
+    return false;
+  if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
+    return false;
+
+  switch (operator_) {
+    case OP_ADD:
+      *num = lhs + rhs;
+      return true;
+    case OP_SUB:
+      *num = lhs - rhs;
+      return true;
+    case OP_MUL:
+      *num = lhs * rhs;
+      return true;
+    case OP_DIV:
+      *num = lhs / rhs;
+      return true;
+    case OP_MOD:
+      *num = static_cast<double>(static_cast<int64>(lhs) %
+                                 static_cast<int64>(rhs));
+      return true;
+    case OP_NEGATE:
+      *num = -lhs;
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
+  switch (type_) {
+    case QUERY_ARITHMETIC_OPERATOR:
+      return EvaluateArithmeticOperator(event, num);
+    case QUERY_EVENT_MEMBER:
+      return GetMemberValueAsDouble(event, num);
+    case QUERY_NUMBER:
+      *num = number_;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
+  switch (type_) {
+    case QUERY_EVENT_MEMBER:
+      return GetMemberValueAsString(event, str);
+    case QUERY_STRING:
+      *str = string_;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetMemberValueAsDouble(const TraceEvent& event,
+                                   double* num) const {
+  DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
+
+  // This could be a request for a member of |event| or a member of |event|'s
+  // associated event. Store the target event in the_event:
+  const TraceEvent* the_event = (member_ < OTHER_PID) ?
+      &event : event.other_event;
+
+  // Request for member of associated event, but there is no associated event.
+  if (!the_event)
+    return false;
+
+  switch (member_) {
+    case EVENT_PID:
+    case OTHER_PID:
+      *num = static_cast<double>(the_event->thread.process_id);
+      return true;
+    case EVENT_TID:
+    case OTHER_TID:
+      *num = static_cast<double>(the_event->thread.thread_id);
+      return true;
+    case EVENT_TIME:
+    case OTHER_TIME:
+      *num = the_event->timestamp;
+      return true;
+    case EVENT_DURATION:
+      if (!the_event->has_other_event())
+        return false;
+      *num = the_event->GetAbsTimeToOtherEvent();
+      return true;
+    case EVENT_COMPLETE_DURATION:
+      if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
+        return false;
+      *num = the_event->duration;
+      return true;
+    case EVENT_PHASE:
+    case OTHER_PHASE:
+      *num = static_cast<double>(the_event->phase);
+      return true;
+    case EVENT_HAS_STRING_ARG:
+    case OTHER_HAS_STRING_ARG:
+      *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
+      return true;
+    case EVENT_HAS_NUMBER_ARG:
+    case OTHER_HAS_NUMBER_ARG:
+      *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
+      return true;
+    case EVENT_ARG:
+    case OTHER_ARG: {
+      // Search for the argument name and return its value if found.
+      std::map<std::string, double>::const_iterator num_i =
+          the_event->arg_numbers.find(string_);
+      if (num_i == the_event->arg_numbers.end())
+        return false;
+      *num = num_i->second;
+      return true;
+    }
+    case EVENT_HAS_OTHER:
+      // return 1.0 (true) if the other event exists
+      *num = event.other_event ? 1.0 : 0.0;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetMemberValueAsString(const TraceEvent& event,
+                                   std::string* str) const {
+  DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
+
+  // This could be a request for a member of |event| or a member of |event|'s
+  // associated event. Store the target event in the_event:
+  const TraceEvent* the_event = (member_ < OTHER_PID) ?
+      &event : event.other_event;
+
+  // Request for member of associated event, but there is no associated event.
+  if (!the_event)
+    return false;
+
+  switch (member_) {
+    case EVENT_CATEGORY:
+    case OTHER_CATEGORY:
+      *str = the_event->category;
+      return true;
+    case EVENT_NAME:
+    case OTHER_NAME:
+      *str = the_event->name;
+      return true;
+    case EVENT_ID:
+    case OTHER_ID:
+      *str = the_event->id;
+      return true;
+    case EVENT_ARG:
+    case OTHER_ARG: {
+      // Search for the argument name and return its value if found.
+      std::map<std::string, std::string>::const_iterator str_i =
+          the_event->arg_strings.find(string_);
+      if (str_i == the_event->arg_strings.end())
+        return false;
+      *str = str_i->second;
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+
+Query::Query(const std::string& str)
+    : type_(QUERY_STRING),
+      operator_(OP_INVALID),
+      member_(EVENT_INVALID),
+      number_(0),
+      string_(str),
+      is_pattern_(false) {
+}
+
+Query::Query(double num)
+    : type_(QUERY_NUMBER),
+      operator_(OP_INVALID),
+      member_(EVENT_INVALID),
+      number_(num),
+      is_pattern_(false) {
+}
+const Query& Query::left() const {
+  return left_->query();
+}
+
+const Query& Query::right() const {
+  return right_->query();
+}
+
+Query Query::operator==(const Query& rhs) const {
+  return Query(*this, rhs, OP_EQ);
+}
+
+Query Query::operator!=(const Query& rhs) const {
+  return Query(*this, rhs, OP_NE);
+}
+
+Query Query::operator<(const Query& rhs) const {
+  return Query(*this, rhs, OP_LT);
+}
+
+Query Query::operator<=(const Query& rhs) const {
+  return Query(*this, rhs, OP_LE);
+}
+
+Query Query::operator>(const Query& rhs) const {
+  return Query(*this, rhs, OP_GT);
+}
+
+Query Query::operator>=(const Query& rhs) const {
+  return Query(*this, rhs, OP_GE);
+}
+
+Query Query::operator&&(const Query& rhs) const {
+  return Query(*this, rhs, OP_AND);
+}
+
+Query Query::operator||(const Query& rhs) const {
+  return Query(*this, rhs, OP_OR);
+}
+
+Query Query::operator!() const {
+  return Query(*this, OP_NOT);
+}
+
+Query Query::operator+(const Query& rhs) const {
+  return Query(*this, rhs, OP_ADD);
+}
+
+Query Query::operator-(const Query& rhs) const {
+  return Query(*this, rhs, OP_SUB);
+}
+
+Query Query::operator*(const Query& rhs) const {
+  return Query(*this, rhs, OP_MUL);
+}
+
+Query Query::operator/(const Query& rhs) const {
+  return Query(*this, rhs, OP_DIV);
+}
+
+Query Query::operator%(const Query& rhs) const {
+  return Query(*this, rhs, OP_MOD);
+}
+
+Query Query::operator-() const {
+  return Query(*this, OP_NEGATE);
+}
+
+
+Query::Query(const Query& left, const Query& right, Operator binary_op)
+    : operator_(binary_op),
+      left_(new QueryNode(left)),
+      right_(new QueryNode(right)),
+      member_(EVENT_INVALID),
+      number_(0) {
+  type_ = (binary_op < OP_ADD ?
+           QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
+}
+
+Query::Query(const Query& left, Operator unary_op)
+    : operator_(unary_op),
+      left_(new QueryNode(left)),
+      member_(EVENT_INVALID),
+      number_(0) {
+  type_ = (unary_op < OP_ADD ?
+           QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
+}
+
+namespace {
+
+// Search |events| for |query| and add matches to |output|.
+size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
+                          const Query& query,
+                          TraceEventVector* output,
+                          bool ignore_metadata_events) {
+  for (size_t i = 0; i < events.size(); ++i) {
+    if (ignore_metadata_events && events[i].phase == TRACE_EVENT_PHASE_METADATA)
+      continue;
+    if (query.Evaluate(events[i]))
+      output->push_back(&events[i]);
+  }
+  return output->size();
+}
+
+bool ParseEventsFromJson(const std::string& json,
+                         std::vector<TraceEvent>* output) {
+  scoped_ptr<base::Value> root;
+  root.reset(base::JSONReader::Read(json));
+
+  base::ListValue* root_list = NULL;
+  if (!root.get() || !root->GetAsList(&root_list))
+    return false;
+
+  for (size_t i = 0; i < root_list->GetSize(); ++i) {
+    base::Value* item = NULL;
+    if (root_list->Get(i, &item)) {
+      TraceEvent event;
+      if (event.SetFromJSON(item))
+        output->push_back(event);
+      else
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// TraceAnalyzer
+
+TraceAnalyzer::TraceAnalyzer()
+    : ignore_metadata_events_(false),
+      allow_assocation_changes_(true) {}
+
+TraceAnalyzer::~TraceAnalyzer() {
+}
+
+// static
+TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
+  scoped_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
+  if (analyzer->SetEvents(json_events))
+    return analyzer.release();
+  return NULL;
+}
+
+bool TraceAnalyzer::SetEvents(const std::string& json_events) {
+  raw_events_.clear();
+  if (!ParseEventsFromJson(json_events, &raw_events_))
+    return false;
+  std::stable_sort(raw_events_.begin(), raw_events_.end());
+  ParseMetadata();
+  return true;
+}
+
+void TraceAnalyzer::AssociateBeginEndEvents() {
+  using trace_analyzer::Query;
+
+  Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
+  Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
+  Query match(Query::EventName() == Query::OtherName() &&
+              Query::EventCategory() == Query::OtherCategory() &&
+              Query::EventTid() == Query::OtherTid() &&
+              Query::EventPid() == Query::OtherPid());
+
+  AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateAsyncBeginEndEvents() {
+  using trace_analyzer::Query;
+
+  Query begin(
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
+  Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
+  Query match(Query::EventName() == Query::OtherName() &&
+              Query::EventCategory() == Query::OtherCategory() &&
+              Query::EventId() == Query::OtherId());
+
+  AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateEvents(const Query& first,
+                                    const Query& second,
+                                    const Query& match) {
+  DCHECK(allow_assocation_changes_)
+      << "AssociateEvents not allowed after FindEvents";
+
+  // Search for matching begin/end event pairs. When a matching end is found,
+  // it is associated with the begin event.
+  std::vector<TraceEvent*> begin_stack;
+  for (size_t event_index = 0; event_index < raw_events_.size();
+       ++event_index) {
+
+    TraceEvent& this_event = raw_events_[event_index];
+
+    if (second.Evaluate(this_event)) {
+      // Search stack for matching begin, starting from end.
+      for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
+           stack_index >= 0; --stack_index) {
+        TraceEvent& begin_event = *begin_stack[stack_index];
+
+        // Temporarily set other to test against the match query.
+        const TraceEvent* other_backup = begin_event.other_event;
+        begin_event.other_event = &this_event;
+        if (match.Evaluate(begin_event)) {
+          // Found a matching begin/end pair.
+          // Erase the matching begin event index from the stack.
+          begin_stack.erase(begin_stack.begin() + stack_index);
+          break;
+        }
+
+        // Not a match, restore original other and continue.
+        begin_event.other_event = other_backup;
+      }
+    }
+    // Even if this_event is a |second| event that has matched an earlier
+    // |first| event, it can still also be a |first| event and be associated
+    // with a later |second| event.
+    if (first.Evaluate(this_event)) {
+      begin_stack.push_back(&this_event);
+    }
+  }
+}
+
+void TraceAnalyzer::MergeAssociatedEventArgs() {
+  for (size_t i = 0; i < raw_events_.size(); ++i) {
+    // Merge all associated events with the first event.
+    const TraceEvent* other = raw_events_[i].other_event;
+    // Avoid looping by keeping set of encountered TraceEvents.
+    std::set<const TraceEvent*> encounters;
+    encounters.insert(&raw_events_[i]);
+    while (other && encounters.find(other) == encounters.end()) {
+      encounters.insert(other);
+      raw_events_[i].arg_numbers.insert(
+          other->arg_numbers.begin(),
+          other->arg_numbers.end());
+      raw_events_[i].arg_strings.insert(
+          other->arg_strings.begin(),
+          other->arg_strings.end());
+      other = other->other_event;
+    }
+  }
+}
+
+size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
+  allow_assocation_changes_ = false;
+  output->clear();
+  return FindMatchingEvents(
+      raw_events_, query, output, ignore_metadata_events_);
+}
+
+const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
+  TraceEventVector output;
+  if (FindEvents(query, &output) > 0)
+    return output.front();
+  return NULL;
+}
+
+const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
+  TraceEventVector output;
+  if (FindEvents(query, &output) > 0)
+    return output.back();
+  return NULL;
+}
+
+const std::string& TraceAnalyzer::GetThreadName(
+    const TraceEvent::ProcessThreadID& thread) {
+  // If thread is not found, just add and return empty string.
+  return thread_names_[thread];
+}
+
+void TraceAnalyzer::ParseMetadata() {
+  for (size_t i = 0; i < raw_events_.size(); ++i) {
+    TraceEvent& this_event = raw_events_[i];
+    // Check for thread name metadata.
+    if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
+        this_event.name != "thread_name")
+      continue;
+    std::map<std::string, std::string>::const_iterator string_it =
+        this_event.arg_strings.find("name");
+    if (string_it != this_event.arg_strings.end())
+      thread_names_[this_event.thread] = string_it->second;
+  }
+}
+
+// TraceEventVector utility functions.
+
+bool GetRateStats(const TraceEventVector& events,
+                  RateStats* stats,
+                  const RateStatsOptions* options) {
+  DCHECK(stats);
+  // Need at least 3 events to calculate rate stats.
+  const size_t kMinEvents = 3;
+  if (events.size() < kMinEvents) {
+    LOG(ERROR) << "Not enough events: " << events.size();
+    return false;
+  }
+
+  std::vector<double> deltas;
+  size_t num_deltas = events.size() - 1;
+  for (size_t i = 0; i < num_deltas; ++i) {
+    double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
+    if (delta < 0.0) {
+      LOG(ERROR) << "Events are out of order";
+      return false;
+    }
+    deltas.push_back(delta);
+  }
+
+  std::sort(deltas.begin(), deltas.end());
+
+  if (options) {
+    if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
+      LOG(ERROR) << "Attempt to trim too many events";
+      return false;
+    }
+    deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
+    deltas.erase(deltas.end() - options->trim_max, deltas.end());
+  }
+
+  num_deltas = deltas.size();
+  double delta_sum = 0.0;
+  for (size_t i = 0; i < num_deltas; ++i)
+    delta_sum += deltas[i];
+
+  stats->min_us = *std::min_element(deltas.begin(), deltas.end());
+  stats->max_us = *std::max_element(deltas.begin(), deltas.end());
+  stats->mean_us = delta_sum / static_cast<double>(num_deltas);
+
+  double sum_mean_offsets_squared = 0.0;
+  for (size_t i = 0; i < num_deltas; ++i) {
+    double offset = fabs(deltas[i] - stats->mean_us);
+    sum_mean_offsets_squared += offset * offset;
+  }
+  stats->standard_deviation_us =
+      sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
+
+  return true;
+}
+
+bool FindFirstOf(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_index) {
+  DCHECK(return_index);
+  for (size_t i = position; i < events.size(); ++i) {
+    if (query.Evaluate(*events[i])) {
+      *return_index = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FindLastOf(const TraceEventVector& events,
+                const Query& query,
+                size_t position,
+                size_t* return_index) {
+  DCHECK(return_index);
+  for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
+    if (query.Evaluate(*events[i - 1])) {
+      *return_index = i - 1;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FindClosest(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_closest,
+                 size_t* return_second_closest) {
+  DCHECK(return_closest);
+  if (events.empty() || position >= events.size())
+    return false;
+  size_t closest = events.size();
+  size_t second_closest = events.size();
+  for (size_t i = 0; i < events.size(); ++i) {
+    if (!query.Evaluate(*events.at(i)))
+      continue;
+    if (closest == events.size()) {
+      closest = i;
+      continue;
+    }
+    if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
+        fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
+      second_closest = closest;
+      closest = i;
+    } else if (second_closest == events.size()) {
+      second_closest = i;
+    }
+  }
+
+  if (closest < events.size() &&
+      (!return_second_closest || second_closest < events.size())) {
+    *return_closest = closest;
+    if (return_second_closest)
+      *return_second_closest = second_closest;
+    return true;
+  }
+
+  return false;
+}
+
+size_t CountMatches(const TraceEventVector& events,
+                    const Query& query,
+                    size_t begin_position,
+                    size_t end_position) {
+  if (begin_position >= events.size())
+    return 0u;
+  end_position = (end_position < events.size()) ? end_position : events.size();
+  size_t count = 0u;
+  for (size_t i = begin_position; i < end_position; ++i) {
+    if (query.Evaluate(*events.at(i)))
+      ++count;
+  }
+  return count;
+}
+
+}  // namespace trace_analyzer
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
new file mode 100644
index 0000000..57ff2b5
--- /dev/null
+++ b/base/test/trace_event_analyzer.h
@@ -0,0 +1,706 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use trace_analyzer::Query and trace_analyzer::TraceAnalyzer to search for
+// specific trace events that were generated by the trace_event.h API.
+//
+// Basic procedure:
+// - Get trace events JSON string from base::trace_event::TraceLog.
+// - Create TraceAnalyzer with JSON string.
+// - Call TraceAnalyzer::AssociateBeginEndEvents (optional).
+// - Call TraceAnalyzer::AssociateEvents (zero or more times).
+// - Call TraceAnalyzer::FindEvents with queries to find specific events.
+//
+// A Query is a boolean expression tree that evaluates to true or false for a
+// given trace event. Queries can be combined into a tree using boolean,
+// arithmetic and comparison operators that refer to data of an individual trace
+// event.
+//
+// The events are returned as trace_analyzer::TraceEvent objects.
+// TraceEvent contains a single trace event's data, as well as a pointer to
+// a related trace event. The related trace event is typically the matching end
+// of a begin event or the matching begin of an end event.
+//
+// The following examples use this basic setup code to construct TraceAnalyzer
+// with the json trace string retrieved from TraceLog and construct an event
+// vector for retrieving events:
+//
+// TraceAnalyzer analyzer(json_events);
+// TraceEventVector events;
+//
+// EXAMPLE 1: Find events named "my_event".
+//
+// analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events);
+//
+// EXAMPLE 2: Find begin events named "my_event" with duration > 1 second.
+//
+// Query q = (Query(EVENT_NAME) == Query::String("my_event") &&
+//            Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) &&
+//            Query(EVENT_DURATION) > Query::Double(1000000.0));
+// analyzer.FindEvents(q, &events);
+//
+// EXAMPLE 3: Associating event pairs across threads.
+//
+// If the test needs to analyze something that starts and ends on different
+// threads, the test needs to use INSTANT events. The typical procedure is to
+// specify the same unique ID as a TRACE_EVENT argument on both the start and
+// finish INSTANT events. Then use the following procedure to associate those
+// events.
+//
+// Step 1: instrument code with custom begin/end trace events.
+//   [Thread 1 tracing code]
+//   TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3);
+//   [Thread 2 tracing code]
+//   TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3);
+//
+// Step 2: associate these custom begin/end pairs.
+//   Query begin(Query(EVENT_NAME) == Query::String("timing1_begin"));
+//   Query end(Query(EVENT_NAME) == Query::String("timing1_end"));
+//   Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
+//   analyzer.AssociateEvents(begin, end, match);
+//
+// Step 3: search for "timing1_begin" events with existing other event.
+//   Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") &&
+//              Query(EVENT_HAS_OTHER));
+//   analyzer.FindEvents(q, &events);
+//
+// Step 4: analyze events, such as checking durations.
+//   for (size_t i = 0; i < events.size(); ++i) {
+//     double duration;
+//     EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration));
+//     EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
+//   }
+
+
+#ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
+#define BASE_TEST_TRACE_EVENT_ANALYZER_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+class Value;
+}
+
+namespace trace_analyzer {
+class QueryNode;
+
+// trace_analyzer::TraceEvent is a more convenient form of the
+// base::trace_event::TraceEvent class to make tracing-based tests easier to
+// write.
+struct TraceEvent {
+  // ProcessThreadID contains a Process ID and Thread ID.
+  struct ProcessThreadID {
+    ProcessThreadID() : process_id(0), thread_id(0) {}
+    ProcessThreadID(int process_id, int thread_id)
+        : process_id(process_id), thread_id(thread_id) {}
+    bool operator< (const ProcessThreadID& rhs) const {
+      if (process_id != rhs.process_id)
+        return process_id < rhs.process_id;
+      return thread_id < rhs.thread_id;
+    }
+    int process_id;
+    int thread_id;
+  };
+
+  TraceEvent();
+  ~TraceEvent();
+
+  bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
+
+  bool operator< (const TraceEvent& rhs) const {
+    return timestamp < rhs.timestamp;
+  }
+
+  bool has_other_event() const { return other_event; }
+
+  // Returns absolute duration in microseconds between this event and other
+  // event. Must have already verified that other_event exists by
+  // Query(EVENT_HAS_OTHER) or by calling has_other_event().
+  double GetAbsTimeToOtherEvent() const;
+
+  // Return the argument value if it exists and it is a string.
+  bool GetArgAsString(const std::string& name, std::string* arg) const;
+  // Return the argument value if it exists and it is a number.
+  bool GetArgAsNumber(const std::string& name, double* arg) const;
+
+  // Check if argument exists and is string.
+  bool HasStringArg(const std::string& name) const;
+  // Check if argument exists and is number (double, int or bool).
+  bool HasNumberArg(const std::string& name) const;
+
+  // Get known existing arguments as specific types.
+  // Useful when you have already queried the argument with
+  // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG).
+  std::string GetKnownArgAsString(const std::string& name) const;
+  double GetKnownArgAsDouble(const std::string& name) const;
+  int GetKnownArgAsInt(const std::string& name) const;
+  bool GetKnownArgAsBool(const std::string& name) const;
+
+  // Process ID and Thread ID.
+  ProcessThreadID thread;
+
+  // Time since epoch in microseconds.
+  // Stored as double to match its JSON representation.
+  double timestamp;
+
+  double duration;
+
+  char phase;
+
+  std::string category;
+
+  std::string name;
+
+  std::string id;
+
+  // All numbers and bool values from TraceEvent args are cast to double.
+  // bool becomes 1.0 (true) or 0.0 (false).
+  std::map<std::string, double> arg_numbers;
+
+  std::map<std::string, std::string> arg_strings;
+
+  // The other event associated with this event (or NULL).
+  const TraceEvent* other_event;
+};
+
+typedef std::vector<const TraceEvent*> TraceEventVector;
+
+class Query {
+ public:
+  Query(const Query& query);
+
+  ~Query();
+
+  ////////////////////////////////////////////////////////////////
+  // Query literal values
+
+  // Compare with the given string.
+  static Query String(const std::string& str);
+
+  // Compare with the given number.
+  static Query Double(double num);
+  static Query Int(int32 num);
+  static Query Uint(uint32 num);
+
+  // Compare with the given bool.
+  static Query Bool(bool boolean);
+
+  // Compare with the given phase.
+  static Query Phase(char phase);
+
+  // Compare with the given string pattern. Only works with == and != operators.
+  // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
+  static Query Pattern(const std::string& pattern);
+
+  ////////////////////////////////////////////////////////////////
+  // Query event members
+
+  static Query EventPid() { return Query(EVENT_PID); }
+
+  static Query EventTid() { return Query(EVENT_TID); }
+
+  // Return the timestamp of the event in microseconds since epoch.
+  static Query EventTime() { return Query(EVENT_TIME); }
+
+  // Return the absolute time between event and other event in microseconds.
+  // Only works if Query::EventHasOther() == true.
+  static Query EventDuration() { return Query(EVENT_DURATION); }
+
+  // Return the duration of a COMPLETE event.
+  static Query EventCompleteDuration() {
+    return Query(EVENT_COMPLETE_DURATION);
+  }
+
+  static Query EventPhase() { return Query(EVENT_PHASE); }
+
+  static Query EventCategory() { return Query(EVENT_CATEGORY); }
+
+  static Query EventName() { return Query(EVENT_NAME); }
+
+  static Query EventId() { return Query(EVENT_ID); }
+
+  static Query EventPidIs(int process_id) {
+    return Query(EVENT_PID) == Query::Int(process_id);
+  }
+
+  static Query EventTidIs(int thread_id) {
+    return Query(EVENT_TID) == Query::Int(thread_id);
+  }
+
+  static Query EventThreadIs(const TraceEvent::ProcessThreadID& thread) {
+    return EventPidIs(thread.process_id) && EventTidIs(thread.thread_id);
+  }
+
+  static Query EventTimeIs(double timestamp) {
+    return Query(EVENT_TIME) == Query::Double(timestamp);
+  }
+
+  static Query EventDurationIs(double duration) {
+    return Query(EVENT_DURATION) == Query::Double(duration);
+  }
+
+  static Query EventPhaseIs(char phase) {
+    return Query(EVENT_PHASE) == Query::Phase(phase);
+  }
+
+  static Query EventCategoryIs(const std::string& category) {
+    return Query(EVENT_CATEGORY) == Query::String(category);
+  }
+
+  static Query EventNameIs(const std::string& name) {
+    return Query(EVENT_NAME) == Query::String(name);
+  }
+
+  static Query EventIdIs(const std::string& id) {
+    return Query(EVENT_ID) == Query::String(id);
+  }
+
+  // Evaluates to true if arg exists and is a string.
+  static Query EventHasStringArg(const std::string& arg_name) {
+    return Query(EVENT_HAS_STRING_ARG, arg_name);
+  }
+
+  // Evaluates to true if arg exists and is a number.
+  // Number arguments include types double, int and bool.
+  static Query EventHasNumberArg(const std::string& arg_name) {
+    return Query(EVENT_HAS_NUMBER_ARG, arg_name);
+  }
+
+  // Evaluates to arg value (string or number).
+  static Query EventArg(const std::string& arg_name) {
+    return Query(EVENT_ARG, arg_name);
+  }
+
+  // Return true if associated event exists.
+  static Query EventHasOther() { return Query(EVENT_HAS_OTHER); }
+
+  // Access the associated other_event's members:
+
+  static Query OtherPid() { return Query(OTHER_PID); }
+
+  static Query OtherTid() { return Query(OTHER_TID); }
+
+  static Query OtherTime() { return Query(OTHER_TIME); }
+
+  static Query OtherPhase() { return Query(OTHER_PHASE); }
+
+  static Query OtherCategory() { return Query(OTHER_CATEGORY); }
+
+  static Query OtherName() { return Query(OTHER_NAME); }
+
+  static Query OtherId() { return Query(OTHER_ID); }
+
+  static Query OtherPidIs(int process_id) {
+    return Query(OTHER_PID) == Query::Int(process_id);
+  }
+
+  static Query OtherTidIs(int thread_id) {
+    return Query(OTHER_TID) == Query::Int(thread_id);
+  }
+
+  static Query OtherThreadIs(const TraceEvent::ProcessThreadID& thread) {
+    return OtherPidIs(thread.process_id) && OtherTidIs(thread.thread_id);
+  }
+
+  static Query OtherTimeIs(double timestamp) {
+    return Query(OTHER_TIME) == Query::Double(timestamp);
+  }
+
+  static Query OtherPhaseIs(char phase) {
+    return Query(OTHER_PHASE) == Query::Phase(phase);
+  }
+
+  static Query OtherCategoryIs(const std::string& category) {
+    return Query(OTHER_CATEGORY) == Query::String(category);
+  }
+
+  static Query OtherNameIs(const std::string& name) {
+    return Query(OTHER_NAME) == Query::String(name);
+  }
+
+  static Query OtherIdIs(const std::string& id) {
+    return Query(OTHER_ID) == Query::String(id);
+  }
+
+  // Evaluates to true if arg exists and is a string.
+  static Query OtherHasStringArg(const std::string& arg_name) {
+    return Query(OTHER_HAS_STRING_ARG, arg_name);
+  }
+
+  // Evaluates to true if arg exists and is a number.
+  // Number arguments include types double, int and bool.
+  static Query OtherHasNumberArg(const std::string& arg_name) {
+    return Query(OTHER_HAS_NUMBER_ARG, arg_name);
+  }
+
+  // Evaluates to arg value (string or number).
+  static Query OtherArg(const std::string& arg_name) {
+    return Query(OTHER_ARG, arg_name);
+  }
+
+  ////////////////////////////////////////////////////////////////
+  // Common queries:
+
+  // Find BEGIN events that have a corresponding END event.
+  static Query MatchBeginWithEnd() {
+    return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN)) &&
+           Query(EVENT_HAS_OTHER);
+  }
+
+  // Find COMPLETE events.
+  static Query MatchComplete() {
+    return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_COMPLETE));
+  }
+
+  // Find ASYNC_BEGIN events that have a corresponding ASYNC_END event.
+  static Query MatchAsyncBeginWithNext() {
+    return (Query(EVENT_PHASE) ==
+            Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN)) &&
+           Query(EVENT_HAS_OTHER);
+  }
+
+  // Find BEGIN events of given |name| which also have associated END events.
+  static Query MatchBeginName(const std::string& name) {
+    return (Query(EVENT_NAME) == Query(name)) && MatchBeginWithEnd();
+  }
+
+  // Find COMPLETE events of given |name|.
+  static Query MatchCompleteName(const std::string& name) {
+    return (Query(EVENT_NAME) == Query(name)) && MatchComplete();
+  }
+
+  // Match given Process ID and Thread ID.
+  static Query MatchThread(const TraceEvent::ProcessThreadID& thread) {
+    return (Query(EVENT_PID) == Query::Int(thread.process_id)) &&
+           (Query(EVENT_TID) == Query::Int(thread.thread_id));
+  }
+
+  // Match event pair that spans multiple threads.
+  static Query MatchCrossThread() {
+    return (Query(EVENT_PID) != Query(OTHER_PID)) ||
+           (Query(EVENT_TID) != Query(OTHER_TID));
+  }
+
+  ////////////////////////////////////////////////////////////////
+  // Operators:
+
+  // Boolean operators:
+  Query operator==(const Query& rhs) const;
+  Query operator!=(const Query& rhs) const;
+  Query operator< (const Query& rhs) const;
+  Query operator<=(const Query& rhs) const;
+  Query operator> (const Query& rhs) const;
+  Query operator>=(const Query& rhs) const;
+  Query operator&&(const Query& rhs) const;
+  Query operator||(const Query& rhs) const;
+  Query operator!() const;
+
+  // Arithmetic operators:
+  // Following operators are applied to double arguments:
+  Query operator+(const Query& rhs) const;
+  Query operator-(const Query& rhs) const;
+  Query operator*(const Query& rhs) const;
+  Query operator/(const Query& rhs) const;
+  Query operator-() const;
+  // Mod operates on int64 args (doubles are casted to int64 beforehand):
+  Query operator%(const Query& rhs) const;
+
+  // Return true if the given event matches this query tree.
+  // This is a recursive method that walks the query tree.
+  bool Evaluate(const TraceEvent& event) const;
+
+ private:
+  enum TraceEventMember {
+    EVENT_INVALID,
+    EVENT_PID,
+    EVENT_TID,
+    EVENT_TIME,
+    EVENT_DURATION,
+    EVENT_COMPLETE_DURATION,
+    EVENT_PHASE,
+    EVENT_CATEGORY,
+    EVENT_NAME,
+    EVENT_ID,
+    EVENT_HAS_STRING_ARG,
+    EVENT_HAS_NUMBER_ARG,
+    EVENT_ARG,
+    EVENT_HAS_OTHER,
+    OTHER_PID,
+    OTHER_TID,
+    OTHER_TIME,
+    OTHER_PHASE,
+    OTHER_CATEGORY,
+    OTHER_NAME,
+    OTHER_ID,
+    OTHER_HAS_STRING_ARG,
+    OTHER_HAS_NUMBER_ARG,
+    OTHER_ARG,
+  };
+
+  enum Operator {
+    OP_INVALID,
+    // Boolean operators:
+    OP_EQ,
+    OP_NE,
+    OP_LT,
+    OP_LE,
+    OP_GT,
+    OP_GE,
+    OP_AND,
+    OP_OR,
+    OP_NOT,
+    // Arithmetic operators:
+    OP_ADD,
+    OP_SUB,
+    OP_MUL,
+    OP_DIV,
+    OP_MOD,
+    OP_NEGATE
+  };
+
+  enum QueryType {
+    QUERY_BOOLEAN_OPERATOR,
+    QUERY_ARITHMETIC_OPERATOR,
+    QUERY_EVENT_MEMBER,
+    QUERY_NUMBER,
+    QUERY_STRING
+  };
+
+  // Compare with the given member.
+  explicit Query(TraceEventMember member);
+
+  // Compare with the given member argument value.
+  Query(TraceEventMember member, const std::string& arg_name);
+
+  // Compare with the given string.
+  explicit Query(const std::string& str);
+
+  // Compare with the given number.
+  explicit Query(double num);
+
+  // Construct a boolean Query that returns (left <binary_op> right).
+  Query(const Query& left, const Query& right, Operator binary_op);
+
+  // Construct a boolean Query that returns (<binary_op> left).
+  Query(const Query& left, Operator unary_op);
+
+  // Try to compare left_ against right_ based on operator_.
+  // If either left or right does not convert to double, false is returned.
+  // Otherwise, true is returned and |result| is set to the comparison result.
+  bool CompareAsDouble(const TraceEvent& event, bool* result) const;
+
+  // Try to compare left_ against right_ based on operator_.
+  // If either left or right does not convert to string, false is returned.
+  // Otherwise, true is returned and |result| is set to the comparison result.
+  bool CompareAsString(const TraceEvent& event, bool* result) const;
+
+  // Attempt to convert this Query to a double. On success, true is returned
+  // and the double value is stored in |num|.
+  bool GetAsDouble(const TraceEvent& event, double* num) const;
+
+  // Attempt to convert this Query to a string. On success, true is returned
+  // and the string value is stored in |str|.
+  bool GetAsString(const TraceEvent& event, std::string* str) const;
+
+  // Evaluate this Query as an arithmetic operator on left_ and right_.
+  bool EvaluateArithmeticOperator(const TraceEvent& event,
+                                  double* num) const;
+
+  // For QUERY_EVENT_MEMBER Query: attempt to get the double value of the Query.
+  bool GetMemberValueAsDouble(const TraceEvent& event, double* num) const;
+
+  // For QUERY_EVENT_MEMBER Query: attempt to get the string value of the Query.
+  bool GetMemberValueAsString(const TraceEvent& event, std::string* num) const;
+
+  // Does this Query represent a value?
+  bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
+
+  bool is_unary_operator() const {
+    return operator_ == OP_NOT || operator_ == OP_NEGATE;
+  }
+
+  bool is_comparison_operator() const {
+    return operator_ != OP_INVALID && operator_ < OP_AND;
+  }
+
+  const Query& left() const;
+  const Query& right() const;
+
+  QueryType type_;
+  Operator operator_;
+  scoped_refptr<QueryNode> left_;
+  scoped_refptr<QueryNode> right_;
+  TraceEventMember member_;
+  double number_;
+  std::string string_;
+  bool is_pattern_;
+};
+
+// Implementation detail:
+// QueryNode allows Query to store a ref-counted query tree.
+class QueryNode : public base::RefCounted<QueryNode> {
+ public:
+  explicit QueryNode(const Query& query);
+  const Query& query() const { return query_; }
+
+ private:
+  friend class base::RefCounted<QueryNode>;
+  ~QueryNode();
+
+  Query query_;
+};
+
+// TraceAnalyzer helps tests search for trace events.
+class TraceAnalyzer {
+ public:
+  ~TraceAnalyzer();
+
+  // Use trace events from JSON string generated by tracing API.
+  // Returns non-NULL if the JSON is successfully parsed.
+  static TraceAnalyzer* Create(const std::string& json_events)
+                               WARN_UNUSED_RESULT;
+
+  void SetIgnoreMetadataEvents(bool ignore) { ignore_metadata_events_ = true; }
+
+  // Associate BEGIN and END events with each other. This allows Query(OTHER_*)
+  // to access the associated event and enables Query(EVENT_DURATION).
+  // An end event will match the most recent begin event with the same name,
+  // category, process ID and thread ID. This matches what is shown in
+  // about:tracing. After association, the BEGIN event will point to the
+  // matching END event, but the END event will not point to the BEGIN event.
+  void AssociateBeginEndEvents();
+
+  // Associate ASYNC_BEGIN, ASYNC_STEP and ASYNC_END events with each other.
+  // An ASYNC_END event will match the most recent ASYNC_BEGIN or ASYNC_STEP
+  // event with the same name, category, and ID. This creates a singly linked
+  // list of ASYNC_BEGIN->ASYNC_STEP...->ASYNC_END.
+  void AssociateAsyncBeginEndEvents();
+
+  // AssociateEvents can be used to customize event associations by setting the
+  // other_event member of TraceEvent. This should be used to associate two
+  // INSTANT events.
+  //
+  // The assumptions are:
+  // - |first| events occur before |second| events.
+  // - the closest matching |second| event is the correct match.
+  //
+  // |first|  - Eligible |first| events match this query.
+  // |second| - Eligible |second| events match this query.
+  // |match|  - This query is run on the |first| event. The OTHER_* EventMember
+  //            queries will point to an eligible |second| event. The query
+  //            should evaluate to true if the |first|/|second| pair is a match.
+  //
+  // When a match is found, the pair will be associated by having the first
+  // event's other_event member point to the other. AssociateEvents does not
+  // clear previous associations, so it is possible to associate multiple pairs
+  // of events by calling AssociateEvents more than once with different queries.
+  //
+  // NOTE: AssociateEvents will overwrite existing other_event associations if
+  // the queries pass for events that already had a previous association.
+  //
+  // After calling any Find* method, it is not allowed to call AssociateEvents
+  // again.
+  void AssociateEvents(const Query& first,
+                       const Query& second,
+                       const Query& match);
+
+  // For each event, copy its arguments to the other_event argument map. If
+  // argument name already exists, it will not be overwritten.
+  void MergeAssociatedEventArgs();
+
+  // Find all events that match query and replace output vector.
+  size_t FindEvents(const Query& query, TraceEventVector* output);
+
+  // Find first event that matches query or NULL if not found.
+  const TraceEvent* FindFirstOf(const Query& query);
+
+  // Find last event that matches query or NULL if not found.
+  const TraceEvent* FindLastOf(const Query& query);
+
+  const std::string& GetThreadName(const TraceEvent::ProcessThreadID& thread);
+
+ private:
+  TraceAnalyzer();
+
+  bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT;
+
+  // Read metadata (thread names, etc) from events.
+  void ParseMetadata();
+
+  std::map<TraceEvent::ProcessThreadID, std::string> thread_names_;
+  std::vector<TraceEvent> raw_events_;
+  bool ignore_metadata_events_;
+  bool allow_assocation_changes_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer);
+};
+
+// Utility functions for TraceEventVector.
+
+struct RateStats {
+  double min_us;
+  double max_us;
+  double mean_us;
+  double standard_deviation_us;
+};
+
+struct RateStatsOptions {
+  RateStatsOptions() : trim_min(0u), trim_max(0u) {}
+  // After the times between events are sorted, the number of specified elements
+  // will be trimmed before calculating the RateStats. This is useful in cases
+  // where extreme outliers are tolerable and should not skew the overall
+  // average.
+  size_t trim_min;  // Trim this many minimum times.
+  size_t trim_max;  // Trim this many maximum times.
+};
+
+// Calculate min/max/mean and standard deviation from the times between
+// adjacent events.
+bool GetRateStats(const TraceEventVector& events,
+                  RateStats* stats,
+                  const RateStatsOptions* options);
+
+// Starting from |position|, find the first event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindFirstOf(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_index);
+
+// Starting from |position|, find the last event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindLastOf(const TraceEventVector& events,
+                const Query& query,
+                size_t position,
+                size_t* return_index);
+
+// Find the closest events to |position| in time that match |query|.
+// return_second_closest may be NULL. Closeness is determined by comparing
+// with the event timestamp.
+// Returns true if found, false otherwise. If both return parameters are
+// requested, both must be found for a successful result.
+bool FindClosest(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_closest,
+                 size_t* return_second_closest);
+
+// Count matches, inclusive of |begin_position|, exclusive of |end_position|.
+size_t CountMatches(const TraceEventVector& events,
+                    const Query& query,
+                    size_t begin_position,
+                    size_t end_position);
+
+// Count all matches.
+static inline size_t CountMatches(const TraceEventVector& events,
+                                  const Query& query) {
+  return CountMatches(events, query, 0u, events.size());
+}
+
+}  // namespace trace_analyzer
+
+#endif  // BASE_TEST_TRACE_EVENT_ANALYZER_H_
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
new file mode 100644
index 0000000..4bdb941
--- /dev/null
+++ b/base/test/trace_event_analyzer_unittest.cc
@@ -0,0 +1,895 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace trace_analyzer {
+
+namespace {
+
+class TraceEventAnalyzerTest : public testing::Test {
+ public:
+  void ManualSetUp();
+  void OnTraceDataCollected(
+      base::WaitableEvent* flush_complete_event,
+      const scoped_refptr<base::RefCountedString>& json_events_str,
+      bool has_more_events);
+  void BeginTracing();
+  void EndTracing();
+
+  base::trace_event::TraceResultBuffer::SimpleOutput output_;
+  base::trace_event::TraceResultBuffer buffer_;
+};
+
+void TraceEventAnalyzerTest::ManualSetUp() {
+  ASSERT_TRUE(base::trace_event::TraceLog::GetInstance());
+  buffer_.SetOutputCallback(output_.GetCallback());
+  output_.json_output.clear();
+}
+
+void TraceEventAnalyzerTest::OnTraceDataCollected(
+    base::WaitableEvent* flush_complete_event,
+    const scoped_refptr<base::RefCountedString>& json_events_str,
+    bool has_more_events) {
+  buffer_.AddFragment(json_events_str->data());
+  if (!has_more_events)
+    flush_complete_event->Signal();
+}
+
+void TraceEventAnalyzerTest::BeginTracing() {
+  output_.json_output.clear();
+  buffer_.Start();
+  base::trace_event::TraceLog::GetInstance()->SetEnabled(
+      base::trace_event::CategoryFilter("*"),
+      base::trace_event::TraceLog::RECORDING_MODE,
+      base::trace_event::TraceOptions());
+}
+
+void TraceEventAnalyzerTest::EndTracing() {
+  base::trace_event::TraceLog::GetInstance()->SetDisabled();
+  base::WaitableEvent flush_complete_event(false, false);
+  base::trace_event::TraceLog::GetInstance()->Flush(
+      base::Bind(&TraceEventAnalyzerTest::OnTraceDataCollected,
+                 base::Unretained(this),
+                 base::Unretained(&flush_complete_event)));
+  flush_complete_event.Wait();
+  buffer_.Finish();
+}
+
+}  // namespace
+
+TEST_F(TraceEventAnalyzerTest, NoEvents) {
+  ManualSetUp();
+
+  // Create an empty JSON event string:
+  buffer_.Start();
+  buffer_.Finish();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  // Search for all events and verify that nothing is returned.
+  TraceEventVector found;
+  analyzer->FindEvents(Query::Bool(true), &found);
+  EXPECT_EQ(0u, found.size());
+}
+
+TEST_F(TraceEventAnalyzerTest, TraceEvent) {
+  ManualSetUp();
+
+  int int_num = 2;
+  double double_num = 3.5;
+  const char str[] = "the string";
+
+  TraceEvent event;
+  event.arg_numbers["false"] = 0.0;
+  event.arg_numbers["true"] = 1.0;
+  event.arg_numbers["int"] = static_cast<double>(int_num);
+  event.arg_numbers["double"] = double_num;
+  event.arg_strings["string"] = str;
+
+  ASSERT_TRUE(event.HasNumberArg("false"));
+  ASSERT_TRUE(event.HasNumberArg("true"));
+  ASSERT_TRUE(event.HasNumberArg("int"));
+  ASSERT_TRUE(event.HasNumberArg("double"));
+  ASSERT_TRUE(event.HasStringArg("string"));
+  ASSERT_FALSE(event.HasNumberArg("notfound"));
+  ASSERT_FALSE(event.HasStringArg("notfound"));
+
+  EXPECT_FALSE(event.GetKnownArgAsBool("false"));
+  EXPECT_TRUE(event.GetKnownArgAsBool("true"));
+  EXPECT_EQ(int_num, event.GetKnownArgAsInt("int"));
+  EXPECT_EQ(double_num, event.GetKnownArgAsDouble("double"));
+  EXPECT_STREQ(str, event.GetKnownArgAsString("string").c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, QueryEventMember) {
+  ManualSetUp();
+
+  TraceEvent event;
+  event.thread.process_id = 3;
+  event.thread.thread_id = 4;
+  event.timestamp = 1.5;
+  event.phase = TRACE_EVENT_PHASE_BEGIN;
+  event.category = "category";
+  event.name = "name";
+  event.id = "1";
+  event.arg_numbers["num"] = 7.0;
+  event.arg_strings["str"] = "the string";
+
+  // Other event with all different members:
+  TraceEvent other;
+  other.thread.process_id = 5;
+  other.thread.thread_id = 6;
+  other.timestamp = 2.5;
+  other.phase = TRACE_EVENT_PHASE_END;
+  other.category = "category2";
+  other.name = "name2";
+  other.id = "2";
+  other.arg_numbers["num2"] = 8.0;
+  other.arg_strings["str2"] = "the string 2";
+
+  event.other_event = &other;
+  ASSERT_TRUE(event.has_other_event());
+  double duration = event.GetAbsTimeToOtherEvent();
+
+  Query event_pid = Query::EventPidIs(event.thread.process_id);
+  Query event_tid = Query::EventTidIs(event.thread.thread_id);
+  Query event_time = Query::EventTimeIs(event.timestamp);
+  Query event_duration = Query::EventDurationIs(duration);
+  Query event_phase = Query::EventPhaseIs(event.phase);
+  Query event_category = Query::EventCategoryIs(event.category);
+  Query event_name = Query::EventNameIs(event.name);
+  Query event_id = Query::EventIdIs(event.id);
+  Query event_has_arg1 = Query::EventHasNumberArg("num");
+  Query event_has_arg2 = Query::EventHasStringArg("str");
+  Query event_arg1 =
+      (Query::EventArg("num") == Query::Double(event.arg_numbers["num"]));
+  Query event_arg2 =
+      (Query::EventArg("str") == Query::String(event.arg_strings["str"]));
+  Query event_has_other = Query::EventHasOther();
+  Query other_pid = Query::OtherPidIs(other.thread.process_id);
+  Query other_tid = Query::OtherTidIs(other.thread.thread_id);
+  Query other_time = Query::OtherTimeIs(other.timestamp);
+  Query other_phase = Query::OtherPhaseIs(other.phase);
+  Query other_category = Query::OtherCategoryIs(other.category);
+  Query other_name = Query::OtherNameIs(other.name);
+  Query other_id = Query::OtherIdIs(other.id);
+  Query other_has_arg1 = Query::OtherHasNumberArg("num2");
+  Query other_has_arg2 = Query::OtherHasStringArg("str2");
+  Query other_arg1 =
+      (Query::OtherArg("num2") == Query::Double(other.arg_numbers["num2"]));
+  Query other_arg2 =
+      (Query::OtherArg("str2") == Query::String(other.arg_strings["str2"]));
+
+  EXPECT_TRUE(event_pid.Evaluate(event));
+  EXPECT_TRUE(event_tid.Evaluate(event));
+  EXPECT_TRUE(event_time.Evaluate(event));
+  EXPECT_TRUE(event_duration.Evaluate(event));
+  EXPECT_TRUE(event_phase.Evaluate(event));
+  EXPECT_TRUE(event_category.Evaluate(event));
+  EXPECT_TRUE(event_name.Evaluate(event));
+  EXPECT_TRUE(event_id.Evaluate(event));
+  EXPECT_TRUE(event_has_arg1.Evaluate(event));
+  EXPECT_TRUE(event_has_arg2.Evaluate(event));
+  EXPECT_TRUE(event_arg1.Evaluate(event));
+  EXPECT_TRUE(event_arg2.Evaluate(event));
+  EXPECT_TRUE(event_has_other.Evaluate(event));
+  EXPECT_TRUE(other_pid.Evaluate(event));
+  EXPECT_TRUE(other_tid.Evaluate(event));
+  EXPECT_TRUE(other_time.Evaluate(event));
+  EXPECT_TRUE(other_phase.Evaluate(event));
+  EXPECT_TRUE(other_category.Evaluate(event));
+  EXPECT_TRUE(other_name.Evaluate(event));
+  EXPECT_TRUE(other_id.Evaluate(event));
+  EXPECT_TRUE(other_has_arg1.Evaluate(event));
+  EXPECT_TRUE(other_has_arg2.Evaluate(event));
+  EXPECT_TRUE(other_arg1.Evaluate(event));
+  EXPECT_TRUE(other_arg2.Evaluate(event));
+
+  // Evaluate event queries against other to verify the queries fail when the
+  // event members are wrong.
+  EXPECT_FALSE(event_pid.Evaluate(other));
+  EXPECT_FALSE(event_tid.Evaluate(other));
+  EXPECT_FALSE(event_time.Evaluate(other));
+  EXPECT_FALSE(event_duration.Evaluate(other));
+  EXPECT_FALSE(event_phase.Evaluate(other));
+  EXPECT_FALSE(event_category.Evaluate(other));
+  EXPECT_FALSE(event_name.Evaluate(other));
+  EXPECT_FALSE(event_id.Evaluate(other));
+  EXPECT_FALSE(event_has_arg1.Evaluate(other));
+  EXPECT_FALSE(event_has_arg2.Evaluate(other));
+  EXPECT_FALSE(event_arg1.Evaluate(other));
+  EXPECT_FALSE(event_arg2.Evaluate(other));
+  EXPECT_FALSE(event_has_other.Evaluate(other));
+}
+
+TEST_F(TraceEventAnalyzerTest, BooleanOperators) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_INSTANT1("cat1", "name1", TRACE_EVENT_SCOPE_THREAD, "num", 1);
+    TRACE_EVENT_INSTANT1("cat1", "name2", TRACE_EVENT_SCOPE_THREAD, "num", 2);
+    TRACE_EVENT_INSTANT1("cat2", "name3", TRACE_EVENT_SCOPE_THREAD, "num", 3);
+    TRACE_EVENT_INSTANT1("cat2", "name4", TRACE_EVENT_SCOPE_THREAD, "num", 4);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(!!analyzer.get());
+  analyzer->SetIgnoreMetadataEvents(true);
+
+  TraceEventVector found;
+
+  // ==
+
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1"), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+
+  analyzer->FindEvents(Query::EventArg("num") == Query::Int(2), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+
+  // !=
+
+  analyzer->FindEvents(Query::EventCategory() != Query::String("cat1"), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name3", found[0]->name.c_str());
+  EXPECT_STREQ("name4", found[1]->name.c_str());
+
+  analyzer->FindEvents(Query::EventArg("num") != Query::Int(2), &found);
+  ASSERT_EQ(3u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+  EXPECT_STREQ("name4", found[2]->name.c_str());
+
+  // <
+  analyzer->FindEvents(Query::EventArg("num") < Query::Int(2), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+
+  // <=
+  analyzer->FindEvents(Query::EventArg("num") <= Query::Int(2), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+
+  // >
+  analyzer->FindEvents(Query::EventArg("num") > Query::Int(3), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name4", found[0]->name.c_str());
+
+  // >=
+  analyzer->FindEvents(Query::EventArg("num") >= Query::Int(4), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name4", found[0]->name.c_str());
+
+  // &&
+  analyzer->FindEvents(Query::EventName() != Query::String("name1") &&
+                       Query::EventArg("num") < Query::Int(3), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+
+  // ||
+  analyzer->FindEvents(Query::EventName() == Query::String("name1") ||
+                       Query::EventArg("num") == Query::Int(3), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+
+  // !
+  analyzer->FindEvents(!(Query::EventName() == Query::String("name1") ||
+                         Query::EventArg("num") == Query::Int(3)), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+  EXPECT_STREQ("name4", found[1]->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, ArithmeticOperators) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    // These events are searched for:
+    TRACE_EVENT_INSTANT2("cat1", "math1", TRACE_EVENT_SCOPE_THREAD,
+                         "a", 10, "b", 5);
+    TRACE_EVENT_INSTANT2("cat1", "math2", TRACE_EVENT_SCOPE_THREAD,
+                         "a", 10, "b", 10);
+    // Extra events that never match, for noise:
+    TRACE_EVENT_INSTANT2("noise", "math3", TRACE_EVENT_SCOPE_THREAD,
+                         "a", 1,  "b", 3);
+    TRACE_EVENT_INSTANT2("noise", "math4", TRACE_EVENT_SCOPE_THREAD,
+                         "c", 10, "d", 5);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  TraceEventVector found;
+
+  // Verify that arithmetic operators function:
+
+  // +
+  analyzer->FindEvents(Query::EventArg("a") + Query::EventArg("b") ==
+                       Query::Int(20), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math2", found.front()->name.c_str());
+
+  // -
+  analyzer->FindEvents(Query::EventArg("a") - Query::EventArg("b") ==
+                       Query::Int(5), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // *
+  analyzer->FindEvents(Query::EventArg("a") * Query::EventArg("b") ==
+                       Query::Int(50), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // /
+  analyzer->FindEvents(Query::EventArg("a") / Query::EventArg("b") ==
+                       Query::Int(2), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // %
+  analyzer->FindEvents(Query::EventArg("a") % Query::EventArg("b") ==
+                       Query::Int(0), &found);
+  EXPECT_EQ(2u, found.size());
+
+  // - (negate)
+  analyzer->FindEvents(-Query::EventArg("b") == Query::Int(-10), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math2", found.front()->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, StringPattern) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_INSTANT0("cat1", "name2", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_INSTANT0("cat1", "no match", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_INSTANT0("cat1", "name3x", TRACE_EVENT_SCOPE_THREAD);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->SetIgnoreMetadataEvents(true);
+
+  TraceEventVector found;
+
+  analyzer->FindEvents(Query::EventName() == Query::Pattern("name?"), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+
+  analyzer->FindEvents(Query::EventName() == Query::Pattern("name*"), &found);
+  ASSERT_EQ(3u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+  EXPECT_STREQ("name3x", found[2]->name.c_str());
+
+  analyzer->FindEvents(Query::EventName() != Query::Pattern("name*"), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("no match", found[0]->name.c_str());
+}
+
+// Test that duration queries work.
+TEST_F(TraceEventAnalyzerTest, BeginEndDuration) {
+  ManualSetUp();
+
+  const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
+  // We will search for events that have a duration of greater than 90% of the
+  // sleep time, so that there is no flakiness.
+  int64 duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+
+  BeginTracing();
+  {
+    TRACE_EVENT_BEGIN0("cat1", "name1"); // found by duration query
+    TRACE_EVENT_BEGIN0("noise", "name2"); // not searched for, just noise
+    {
+      TRACE_EVENT_BEGIN0("cat2", "name3"); // found by duration query
+      // next event not searched for, just noise
+      TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
+      base::PlatformThread::Sleep(kSleepTime);
+      TRACE_EVENT_BEGIN0("cat2", "name5"); // not found (duration too short)
+      TRACE_EVENT_END0("cat2", "name5"); // not found (duration too short)
+      TRACE_EVENT_END0("cat2", "name3"); // found by duration query
+    }
+    TRACE_EVENT_END0("noise", "name2"); // not searched for, just noise
+    TRACE_EVENT_END0("cat1", "name1"); // found by duration query
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(
+      Query::MatchBeginWithEnd() &&
+      Query::EventDuration() >
+          Query::Int(static_cast<int>(duration_cutoff_us)) &&
+      (Query::EventCategory() == Query::String("cat1") ||
+       Query::EventCategory() == Query::String("cat2") ||
+       Query::EventCategory() == Query::String("cat3")),
+      &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+}
+
+// Test that duration queries work.
+TEST_F(TraceEventAnalyzerTest, CompleteDuration) {
+  ManualSetUp();
+
+  const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
+  // We will search for events that have a duration of greater than 90% of the
+  // sleep time, so that there is no flakiness.
+  int64 duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+
+  BeginTracing();
+  {
+    TRACE_EVENT0("cat1", "name1"); // found by duration query
+    TRACE_EVENT0("noise", "name2"); // not searched for, just noise
+    {
+      TRACE_EVENT0("cat2", "name3"); // found by duration query
+      // next event not searched for, just noise
+      TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
+      base::PlatformThread::Sleep(kSleepTime);
+      TRACE_EVENT0("cat2", "name5"); // not found (duration too short)
+    }
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(
+      Query::EventCompleteDuration() >
+          Query::Int(static_cast<int>(duration_cutoff_us)) &&
+      (Query::EventCategory() == Query::String("cat1") ||
+       Query::EventCategory() == Query::String("cat2") ||
+       Query::EventCategory() == Query::String("cat3")),
+      &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+}
+
+// Test AssociateBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, BeginEndAssocations) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_END0("cat1", "name1"); // does not match out of order begin
+    TRACE_EVENT_BEGIN0("cat1", "name2");
+    TRACE_EVENT_INSTANT0("cat1", "name3", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_BEGIN0("cat1", "name1");
+    TRACE_EVENT_END0("cat1", "name2");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchBeginWithEnd(), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+}
+
+// Test MergeAssociatedEventArgs
+TEST_F(TraceEventAnalyzerTest, MergeAssociatedEventArgs) {
+  ManualSetUp();
+
+  const char arg_string[] = "arg_string";
+  BeginTracing();
+  {
+    TRACE_EVENT_BEGIN0("cat1", "name1");
+    TRACE_EVENT_END1("cat1", "name1", "arg", arg_string);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchBeginName("name1"), &found);
+  ASSERT_EQ(1u, found.size());
+  std::string arg_actual;
+  EXPECT_FALSE(found[0]->GetArgAsString("arg", &arg_actual));
+
+  analyzer->MergeAssociatedEventArgs();
+  EXPECT_TRUE(found[0]->GetArgAsString("arg", &arg_actual));
+  EXPECT_STREQ(arg_string, arg_actual.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocations) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xA); // no match / out of order
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xB);
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xC);
+    TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD); // noise
+    TRACE_EVENT0("cat1", "name1"); // noise
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xB);
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xC);
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xA); // no match / out of order
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateAsyncBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
+  EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocationsWithSteps) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s1");
+    TRACE_EVENT_ASYNC_END0("c", "n", 0xA);
+    TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xB);
+    TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xC);
+    TRACE_EVENT_ASYNC_STEP_PAST0("c", "n", 0xB, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xC, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO1("c", "n", 0xC, "s2", "a", 1);
+    TRACE_EVENT_ASYNC_END0("c", "n", 0xB);
+    TRACE_EVENT_ASYNC_END0("c", "n", 0xC);
+    TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xA);
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s2");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateAsyncBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+  ASSERT_EQ(3u, found.size());
+
+  EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, found[0]->other_event->phase);
+  EXPECT_TRUE(found[0]->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
+            found[0]->other_event->other_event->phase);
+
+  EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[1]->other_event->phase);
+  EXPECT_TRUE(found[1]->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO,
+            found[1]->other_event->other_event->phase);
+  double arg_actual = 0;
+  EXPECT_TRUE(found[1]->other_event->other_event->GetArgAsNumber(
+                  "a", &arg_actual));
+  EXPECT_EQ(1.0, arg_actual);
+  EXPECT_TRUE(found[1]->other_event->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
+            found[1]->other_event->other_event->other_event->phase);
+
+  EXPECT_STRCASEEQ("0xa", found[2]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[2]->other_event->phase);
+}
+
+// Test that the TraceAnalyzer custom associations work.
+TEST_F(TraceEventAnalyzerTest, CustomAssociations) {
+  ManualSetUp();
+
+  // Add events that begin/end in pipelined ordering with unique ID parameter
+  // to match up the begin/end pairs.
+  BeginTracing();
+  {
+    // no begin match
+    TRACE_EVENT_INSTANT1("cat1", "end", TRACE_EVENT_SCOPE_THREAD, "id", 1);
+    // end is cat4
+    TRACE_EVENT_INSTANT1("cat2", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 2);
+    // end is cat5
+    TRACE_EVENT_INSTANT1("cat3", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 3);
+    TRACE_EVENT_INSTANT1("cat4", "end", TRACE_EVENT_SCOPE_THREAD, "id", 2);
+    TRACE_EVENT_INSTANT1("cat5", "end", TRACE_EVENT_SCOPE_THREAD, "id", 3);
+    // no end match
+    TRACE_EVENT_INSTANT1("cat6", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 1);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  // begin, end, and match queries to find proper begin/end pairs.
+  Query begin(Query::EventName() == Query::String("begin"));
+  Query end(Query::EventName() == Query::String("end"));
+  Query match(Query::EventArg("id") == Query::OtherArg("id"));
+  analyzer->AssociateEvents(begin, end, match);
+
+  TraceEventVector found;
+
+  // cat1 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+                       Query::EventHasOther(), &found);
+  EXPECT_EQ(0u, found.size());
+
+  // cat1 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+                       !Query::EventHasOther(), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat6 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat6") &&
+                       !Query::EventHasOther(), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat2 and cat4 are associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat2") &&
+                       Query::OtherCategory() == Query::String("cat4"), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat4 and cat2 are not associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat4") &&
+                       Query::OtherCategory() == Query::String("cat2"), &found);
+  EXPECT_EQ(0u, found.size());
+
+  // cat3 and cat5 are associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat3") &&
+                       Query::OtherCategory() == Query::String("cat5"), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat5 and cat3 are not associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat5") &&
+                       Query::OtherCategory() == Query::String("cat3"), &found);
+  EXPECT_EQ(0u, found.size());
+}
+
+// Verify that Query literals and types are properly casted.
+TEST_F(TraceEventAnalyzerTest, Literals) {
+  ManualSetUp();
+
+  // Since these queries don't refer to the event data, the dummy event below
+  // will never be accessed.
+  TraceEvent dummy;
+  char char_num = 5;
+  short short_num = -5;
+  EXPECT_TRUE((Query::Double(5.0) == Query::Int(char_num)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(-5.0) == Query::Int(short_num)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Uint(1u)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Int(1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(-1.0) == Query::Int(-1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Double(1.0f)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(true) == Query::Int(1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(false) == Query::Int(0)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(true) == Query::Double(1.0f)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(false) == Query::Double(0.0f)).Evaluate(dummy));
+}
+
+// Test GetRateStats.
+TEST_F(TraceEventAnalyzerTest, RateStats) {
+  std::vector<TraceEvent> events;
+  events.reserve(100);
+  TraceEventVector event_ptrs;
+  TraceEvent event;
+  event.timestamp = 0.0;
+  double little_delta = 1.0;
+  double big_delta = 10.0;
+  double tiny_delta = 0.1;
+  RateStats stats;
+  RateStatsOptions options;
+
+  // Insert 10 events, each apart by little_delta.
+  for (int i = 0; i < 10; ++i) {
+    event.timestamp += little_delta;
+    events.push_back(event);
+    event_ptrs.push_back(&events.back());
+  }
+
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Add an event apart by big_delta.
+  event.timestamp += big_delta;
+  events.push_back(event);
+  event_ptrs.push_back(&events.back());
+
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
+  EXPECT_LT(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(big_delta, stats.max_us);
+  EXPECT_LT(0.0, stats.standard_deviation_us);
+
+  // Trim off the biggest delta and verify stats.
+  options.trim_min = 0;
+  options.trim_max = 1;
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Add an event apart by tiny_delta.
+  event.timestamp += tiny_delta;
+  events.push_back(event);
+  event_ptrs.push_back(&events.back());
+
+  // Trim off both the biggest and tiniest delta and verify stats.
+  options.trim_min = 1;
+  options.trim_max = 1;
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Verify smallest allowed number of events.
+  TraceEventVector few_event_ptrs;
+  few_event_ptrs.push_back(&event);
+  few_event_ptrs.push_back(&event);
+  ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, NULL));
+  few_event_ptrs.push_back(&event);
+  ASSERT_TRUE(GetRateStats(few_event_ptrs, &stats, NULL));
+
+  // Trim off more than allowed and verify failure.
+  options.trim_min = 0;
+  options.trim_max = 1;
+  ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, &options));
+}
+
+// Test FindFirstOf and FindLastOf.
+TEST_F(TraceEventAnalyzerTest, FindOf) {
+  size_t num_events = 100;
+  size_t index = 0;
+  TraceEventVector event_ptrs;
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 10, &index));
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 10, &index));
+
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i)
+    event_ptrs.push_back(&events[i]);
+  size_t bam_index = num_events/2;
+  events[bam_index].name = "bam";
+  Query query_bam = Query::EventName() == Query::String(events[bam_index].name);
+
+  // FindFirstOf
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(false), 0, &index));
+  EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_EQ(0u, index);
+  EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 5, &index));
+  EXPECT_EQ(5u, index);
+
+  EXPECT_FALSE(FindFirstOf(event_ptrs, query_bam, bam_index + 1, &index));
+  EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, 0, &index));
+  EXPECT_EQ(bam_index, index);
+  EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, bam_index, &index));
+  EXPECT_EQ(bam_index, index);
+
+  // FindLastOf
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(false), 1000, &index));
+  EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), 1000, &index));
+  EXPECT_EQ(num_events - 1, index);
+  EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), num_events - 5,
+                         &index));
+  EXPECT_EQ(num_events - 5, index);
+
+  EXPECT_FALSE(FindLastOf(event_ptrs, query_bam, bam_index - 1, &index));
+  EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, num_events, &index));
+  EXPECT_EQ(bam_index, index);
+  EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, bam_index, &index));
+  EXPECT_EQ(bam_index, index);
+}
+
+// Test FindClosest.
+TEST_F(TraceEventAnalyzerTest, FindClosest) {
+  size_t index_1 = 0;
+  size_t index_2 = 0;
+  TraceEventVector event_ptrs;
+  EXPECT_FALSE(FindClosest(event_ptrs, Query::Bool(true), 0,
+                           &index_1, &index_2));
+
+  size_t num_events = 5;
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i) {
+    // timestamps go up exponentially so the lower index is always closer in
+    // time than the higher index.
+    events[i].timestamp = static_cast<double>(i) * static_cast<double>(i);
+    event_ptrs.push_back(&events[i]);
+  }
+  events[0].name = "one";
+  events[2].name = "two";
+  events[4].name = "three";
+  Query query_named = Query::EventName() != Query::String(std::string());
+  Query query_one = Query::EventName() == Query::String("one");
+
+  // Only one event matches query_one, so two closest can't be found.
+  EXPECT_FALSE(FindClosest(event_ptrs, query_one, 0, &index_1, &index_2));
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_one, 3, &index_1, NULL));
+  EXPECT_EQ(0u, index_1);
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_named, 1, &index_1, &index_2));
+  EXPECT_EQ(0u, index_1);
+  EXPECT_EQ(2u, index_2);
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_named, 4, &index_1, &index_2));
+  EXPECT_EQ(4u, index_1);
+  EXPECT_EQ(2u, index_2);
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_named, 3, &index_1, &index_2));
+  EXPECT_EQ(2u, index_1);
+  EXPECT_EQ(0u, index_2);
+}
+
+// Test CountMatches.
+TEST_F(TraceEventAnalyzerTest, CountMatches) {
+  TraceEventVector event_ptrs;
+  EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(true), 0, 10));
+
+  size_t num_events = 5;
+  size_t num_named = 3;
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i)
+    event_ptrs.push_back(&events[i]);
+  events[0].name = "one";
+  events[2].name = "two";
+  events[4].name = "three";
+  Query query_named = Query::EventName() != Query::String(std::string());
+  Query query_one = Query::EventName() == Query::String("one");
+
+  EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(false)));
+  EXPECT_EQ(num_events, CountMatches(event_ptrs, Query::Bool(true)));
+  EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, Query::Bool(true),
+                                         1, num_events));
+  EXPECT_EQ(1u, CountMatches(event_ptrs, query_one));
+  EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, !query_one));
+  EXPECT_EQ(num_named, CountMatches(event_ptrs, query_named));
+}
+
+
+}  // namespace trace_analyzer
diff --git a/base/test/trace_to_file.cc b/base/test/trace_to_file.cc
new file mode 100644
index 0000000..4e2a332
--- /dev/null
+++ b/base/test/trace_to_file.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/trace_to_file.h"
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace test {
+
+TraceToFile::TraceToFile() : started_(false) {
+}
+
+TraceToFile::~TraceToFile() {
+  EndTracingIfNeeded();
+}
+
+void TraceToFile::BeginTracingFromCommandLineOptions() {
+  DCHECK(CommandLine::InitializedForCurrentProcess());
+  DCHECK(!started_);
+
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFile))
+    return;
+
+  // Empty filter (i.e. just --trace-to-file) turns into default categories in
+  // TraceEventImpl
+  std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+      switches::kTraceToFile);
+
+  FilePath path;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFileName)) {
+    path = FilePath(CommandLine::ForCurrentProcess()
+                        ->GetSwitchValuePath(switches::kTraceToFileName));
+  } else {
+    path = FilePath(FILE_PATH_LITERAL("trace.json"));
+  }
+
+  BeginTracing(path, filter);
+}
+
+void TraceToFile::BeginTracing(const FilePath& path,
+                               const std::string& categories) {
+  DCHECK(!started_);
+  started_ = true;
+  path_ = path;
+  WriteFileHeader();
+
+  trace_event::TraceLog::GetInstance()->SetEnabled(
+      trace_event::CategoryFilter(categories),
+      trace_event::TraceLog::RECORDING_MODE,
+      trace_event::TraceOptions(trace_event::RECORD_UNTIL_FULL));
+}
+
+void TraceToFile::WriteFileHeader() {
+  const char str[] = "{\"traceEvents\": [";
+  WriteFile(path_, str, static_cast<int>(strlen(str)));
+}
+
+void TraceToFile::AppendFileFooter() {
+  const char str[] = "]}";
+  AppendToFile(path_, str, static_cast<int>(strlen(str)));
+}
+
+void TraceToFile::TraceOutputCallback(const std::string& data) {
+  bool ret = AppendToFile(path_, data.c_str(), static_cast<int>(data.size()));
+  DCHECK(ret);
+}
+
+static void OnTraceDataCollected(
+    Closure quit_closure,
+    trace_event::TraceResultBuffer* buffer,
+    const scoped_refptr<RefCountedString>& json_events_str,
+    bool has_more_events) {
+  buffer->AddFragment(json_events_str->data());
+  if (!has_more_events)
+    quit_closure.Run();
+}
+
+void TraceToFile::EndTracingIfNeeded() {
+  if (!started_)
+    return;
+  started_ = false;
+
+  trace_event::TraceLog::GetInstance()->SetDisabled();
+
+  trace_event::TraceResultBuffer buffer;
+  buffer.SetOutputCallback(
+      Bind(&TraceToFile::TraceOutputCallback, Unretained(this)));
+
+  RunLoop run_loop;
+  trace_event::TraceLog::GetInstance()->Flush(
+      Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+  run_loop.Run();
+
+  AppendFileFooter();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/trace_to_file.h b/base/test/trace_to_file.h
new file mode 100644
index 0000000..4308736
--- /dev/null
+++ b/base/test/trace_to_file.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TRACE_TO_FILE_H_
+#define BASE_TEST_TRACE_TO_FILE_H_
+
+#include "base/files/file_path.h"
+
+namespace base {
+namespace test {
+
+class TraceToFile {
+ public:
+  TraceToFile();
+  ~TraceToFile();
+
+  void BeginTracingFromCommandLineOptions();
+  void BeginTracing(const base::FilePath& path, const std::string& categories);
+  void EndTracingIfNeeded();
+
+ private:
+  void WriteFileHeader();
+  void AppendFileFooter();
+
+  void TraceOutputCallback(const std::string& data);
+
+  base::FilePath path_;
+  bool started_;
+};
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_TRACE_TO_FILE_H_
diff --git a/base/test/user_action_tester.cc b/base/test/user_action_tester.cc
new file mode 100644
index 0000000..3fdab12
--- /dev/null
+++ b/base/test/user_action_tester.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/user_action_tester.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+
+namespace base {
+
+UserActionTester::UserActionTester()
+    : action_callback_(
+          base::Bind(&UserActionTester::OnUserAction, base::Unretained(this))) {
+  base::AddActionCallback(action_callback_);
+}
+
+UserActionTester::~UserActionTester() {
+  base::RemoveActionCallback(action_callback_);
+}
+
+int UserActionTester::GetActionCount(const std::string& user_action) const {
+  UserActionCountMap::const_iterator iter = count_map_.find(user_action);
+  return iter == count_map_.end() ? 0 : iter->second;
+}
+
+void UserActionTester::ResetCounts() {
+  count_map_.clear();
+}
+
+void UserActionTester::OnUserAction(const std::string& user_action) {
+  ++(count_map_[user_action]);
+}
+
+}  // namespace base
diff --git a/base/test/user_action_tester.h b/base/test/user_action_tester.h
new file mode 100644
index 0000000..6b0efc5
--- /dev/null
+++ b/base/test/user_action_tester.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_USER_ACTION_TESTER_H_
+#define BASE_TEST_USER_ACTION_TESTER_H_
+
+#include <map>
+#include <string>
+
+#include "base/metrics/user_metrics.h"
+
+namespace base {
+
+// This class observes and collects user action notifications that are sent
+// by the tests, so that they can be examined afterwards for correctness.
+// Note: This class is NOT thread-safe.
+class UserActionTester {
+ public:
+  UserActionTester();
+  ~UserActionTester();
+
+  // Returns the number of times the given |user_action| occurred.
+  int GetActionCount(const std::string& user_action) const;
+
+  // Resets all user action counts to 0.
+  void ResetCounts();
+
+ private:
+  typedef std::map<std::string, int> UserActionCountMap;
+
+  // The callback that is notified when a user actions occurs.
+  void OnUserAction(const std::string& user_action);
+
+  // A map that tracks the number of times a user action has occurred.
+  UserActionCountMap count_map_;
+
+  // The callback that is added to the global action callback list.
+  base::ActionCallback action_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserActionTester);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_USER_ACTION_TESTER_H_
diff --git a/base/test/user_action_tester_unittest.cc b/base/test/user_action_tester_unittest.cc
new file mode 100644
index 0000000..a51849f
--- /dev/null
+++ b/base/test/user_action_tester_unittest.cc
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/user_action_tester.h"
+
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const char kUserAction1[] = "user.action.1";
+const char kUserAction2[] = "user.action.2";
+const char kUserAction3[] = "user.action.3";
+
+// Record an action and cause all ActionCallback observers to be notified.
+void RecordAction(const char user_action[]) {
+  base::RecordAction(base::UserMetricsAction(user_action));
+}
+
+}  // namespace
+
+// Verify user action counts are zero initially.
+TEST(UserActionTesterTest, GetActionCountWhenNoActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1));
+}
+
+// Verify user action counts are tracked properly.
+TEST(UserActionTesterTest, GetActionCountWhenActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+
+  RecordAction(kUserAction1);
+  RecordAction(kUserAction2);
+  RecordAction(kUserAction2);
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1));
+  EXPECT_EQ(2, user_action_tester.GetActionCount(kUserAction2));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3));
+}
+
+// Verify no seg faults occur when resetting action counts when none have been
+// recorded.
+TEST(UserActionTesterTest, ResetCountsWhenNoActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+  user_action_tester.ResetCounts();
+}
+
+// Verify user action counts are set to zero on a ResetCounts.
+TEST(UserActionTesterTest, ResetCountsWhenActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+
+  RecordAction(kUserAction1);
+  RecordAction(kUserAction1);
+  RecordAction(kUserAction2);
+  user_action_tester.ResetCounts();
+
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction2));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3));
+}
+
+// Verify the UserActionsTester is notified when base::RecordAction is called.
+TEST(UserActionTesterTest, VerifyUserActionTesterListensForUserActions) {
+  UserActionTester user_action_tester;
+
+  base::RecordAction(base::UserMetricsAction(kUserAction1));
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1));
+}
+
+// Verify the UserActionsTester is notified when base::RecordComputedAction is
+// called.
+TEST(UserActionTesterTest,
+     VerifyUserActionTesterListensForComputedUserActions) {
+  UserActionTester user_action_tester;
+
+  base::RecordComputedAction(kUserAction1);
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1));
+}
+
+}  // namespace base
diff --git a/base/test/values_test_util.cc b/base/test/values_test_util.cc
new file mode 100644
index 0000000..c5dfd79
--- /dev/null
+++ b/base/test/values_test_util.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/test/values_test_util.h"
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+void ExpectDictBooleanValue(bool expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key) {
+  bool boolean_value = false;
+  EXPECT_TRUE(value.GetBoolean(key, &boolean_value)) << key;
+  EXPECT_EQ(expected_value, boolean_value) << key;
+}
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+                               const DictionaryValue& value,
+                               const std::string& key) {
+  const DictionaryValue* dict_value = NULL;
+  EXPECT_TRUE(value.GetDictionary(key, &dict_value)) << key;
+  EXPECT_TRUE(Value::Equals(dict_value, &expected_value)) << key;
+}
+
+void ExpectDictIntegerValue(int expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key) {
+  int integer_value = 0;
+  EXPECT_TRUE(value.GetInteger(key, &integer_value)) << key;
+  EXPECT_EQ(expected_value, integer_value) << key;
+}
+
+void ExpectDictListValue(const ListValue& expected_value,
+                         const DictionaryValue& value,
+                         const std::string& key) {
+  const ListValue* list_value = NULL;
+  EXPECT_TRUE(value.GetList(key, &list_value)) << key;
+  EXPECT_TRUE(Value::Equals(list_value, &expected_value)) << key;
+}
+
+void ExpectDictStringValue(const std::string& expected_value,
+                           const DictionaryValue& value,
+                           const std::string& key) {
+  std::string string_value;
+  EXPECT_TRUE(value.GetString(key, &string_value)) << key;
+  EXPECT_EQ(expected_value, string_value) << key;
+}
+
+void ExpectStringValue(const std::string& expected_str,
+                       StringValue* actual) {
+  scoped_ptr<StringValue> scoped_actual(actual);
+  std::string actual_str;
+  EXPECT_TRUE(scoped_actual->GetAsString(&actual_str));
+  EXPECT_EQ(expected_str, actual_str);
+}
+
+namespace test {
+
+scoped_ptr<Value> ParseJson(base::StringPiece json) {
+  std::string error_msg;
+  scoped_ptr<Value> result(base::JSONReader::ReadAndReturnError(
+      json, base::JSON_ALLOW_TRAILING_COMMAS,
+      NULL, &error_msg));
+  if (!result) {
+    ADD_FAILURE() << "Failed to parse \"" << json << "\": " << error_msg;
+    result.reset(Value::CreateNullValue());
+  }
+  return result.Pass();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/values_test_util.h b/base/test/values_test_util.h
new file mode 100644
index 0000000..86d91c3
--- /dev/null
+++ b/base/test/values_test_util.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_VALUES_TEST_UTIL_H_
+#define BASE_TEST_VALUES_TEST_UTIL_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class StringValue;
+class Value;
+
+// All the functions below expect that the value for the given key in
+// the given dictionary equals the given expected value.
+
+void ExpectDictBooleanValue(bool expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key);
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+                               const DictionaryValue& value,
+                               const std::string& key);
+
+void ExpectDictIntegerValue(int expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key);
+
+void ExpectDictListValue(const ListValue& expected_value,
+                         const DictionaryValue& value,
+                         const std::string& key);
+
+void ExpectDictStringValue(const std::string& expected_value,
+                           const DictionaryValue& value,
+                           const std::string& key);
+
+// Takes ownership of |actual|.
+void ExpectStringValue(const std::string& expected_str,
+                       StringValue* actual);
+
+namespace test {
+
+// Parses |json| as JSON, allowing trailing commas, and returns the
+// resulting value.  If the json fails to parse, causes an EXPECT
+// failure and returns the Null Value (but never a NULL pointer).
+scoped_ptr<Value> ParseJson(base::StringPiece json);
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_VALUES_TEST_UTIL_H_
diff --git a/base/third_party/dmg_fp/LICENSE b/base/third_party/dmg_fp/LICENSE
new file mode 100644
index 0000000..716f1ef
--- /dev/null
+++ b/base/third_party/dmg_fp/LICENSE
@@ -0,0 +1,18 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
diff --git a/base/third_party/dmg_fp/README.chromium b/base/third_party/dmg_fp/README.chromium
new file mode 100644
index 0000000..4538b7e
--- /dev/null
+++ b/base/third_party/dmg_fp/README.chromium
@@ -0,0 +1,20 @@
+Name: David M. Gay's floating point routines
+URL: http://www.netlib.org/fp/
+License: MIT-like
+
+Original dtoa.c file can be found at <http://www.netlib.org/fp/dtoa.c>.
+Original g_fmt.c file can be found at <http://www.netlib.org/fp/g_fmt.c>.
+
+List of changes made to original code:
+  - wrapped functions in dmg_fp namespace
+  - renamed .c files to .cc
+  - added dmg_fp.h header
+  - added #define IEEE_8087 to dtoa.cc
+  - added #define NO_HEX_FP to dtoa.cc
+  - made some minor changes to allow clean compilation under g++ -Wall, see
+    gcc_warnings.patch.
+  - made some minor changes to build on 64-bit, see gcc_64_bit.patch.
+  - made minor changes for -Wextra for Mac build, see mac_wextra.patch
+  - crash fix for running with reduced CPU float precision, see
+    float_precision_crash.patch and crbug.com/123157
+  - fixed warnings under msvc, see msvc_warnings.patch
\ No newline at end of file
diff --git a/base/third_party/dmg_fp/dmg_fp.h b/base/third_party/dmg_fp/dmg_fp.h
new file mode 100644
index 0000000..4795397
--- /dev/null
+++ b/base/third_party/dmg_fp/dmg_fp.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_DMG_FP_H_
+#define THIRD_PARTY_DMG_FP_H_
+
+namespace dmg_fp {
+
+// Return a nearest machine number to the input decimal
+// string (or set errno to ERANGE). With IEEE arithmetic, ties are
+// broken by the IEEE round-even rule.  Otherwise ties are broken by
+// biased rounding (add half and chop).
+double strtod(const char* s00, char** se);
+
+// Convert double to ASCII string. For meaning of parameters
+// see dtoa.cc file.
+char* dtoa(double d, int mode, int ndigits,
+           int* decpt, int* sign, char** rve);
+
+// Must be used to free values returned by dtoa.
+void freedtoa(char* s);
+
+// Store the closest decimal approximation to x in b (null terminated).
+// Returns a pointer to b.  It is sufficient for |b| to be 32 characters.
+char* g_fmt(char* b, double x);
+
+}  // namespace dmg_fp
+
+#endif  // THIRD_PARTY_DMG_FP_H_
diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
new file mode 100644
index 0000000..502c16c
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa.cc
@@ -0,0 +1,4234 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and strtod and dtoa should round accordingly.  Unless Trust_FLT_ROUNDS
+ *	is also #defined, fegetround() will be queried for the rounding mode.
+ *	Note that both FLT_ROUNDS and fegetround() are specified by the C99
+ *	standard (and are specified to be consistent, with fesetround()
+ *	affecting the value of FLT_ROUNDS), but that some (Linux) systems
+ *	do not work correctly in this regard, so using fegetround() is more
+ *	portable than using FLT_FOUNDS directly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a dtoa call after a dtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  The longest string dtoa can return is about 751 bytes
+ *	long.  For conversions by strtod of strings of 800 digits and
+ *	all dtoa conversions in single-threaded executions with 8-byte
+ *	pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ *	pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).  On some systems
+ *	(e.g., some HP systems), it may be necessary to #define NAN_WORD0
+ *	appropriately -- to the most significant word of a quiet NaN.
+ *	(On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtod also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits and spaces;
+ *	if there is only one string of hexadecimal digits, it is taken
+ *	for the 52 fraction bits of the resulting NaN; if there are two
+ *	or more strings of hex digits, the first is for the high 20 bits,
+ *	the second and subsequent for the low 32 bits, with intervening
+ *	white space ignored; but if this results in none of the 52
+ *	fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ *	and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ *	avoids underflows on inputs whose result does not underflow.
+ *	If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ *	floating-point numbers and flushes underflows to zero rather
+ *	than implementing gradual underflow, then you must also #define
+ *	Sudden_Underflow.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ *	computation should be done to set the inexact flag when the
+ *	result is inexact and avoid setting inexact when the result
+ *	is exact.  In this case, dtoa.c must be compiled in
+ *	an environment, perhaps provided by #include "dtoa.c" in a
+ *	suitable wrapper, that defines two functions,
+ *		int get_inexact(void);
+ *		void clear_inexact(void);
+ *	such that get_inexact() returns a nonzero value if the
+ *	inexact bit is already set, and clear_inexact() sets the
+ *	inexact bit to 0.  When SET_INEXACT is #defined, strtod
+ *	also does extra computations to set the underflow and overflow
+ *	flags when appropriate (i.e., when the result is tiny and
+ *	inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ *	the result overflows to +-Infinity or underflows to 0.
+ * #define NO_HEX_FP to omit recognition of hexadecimal floating-point
+ *	values by strtod.
+ * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now)
+ *	to disable logic for "fast" testing of very long input strings
+ *	to strtod.  This testing proceeds by initially truncating the
+ *	input string, then if necessary comparing the whole string with
+ *	a decimal expansion to decide close cases. This logic is only
+ *	used for input more than STRTOD_DIGLIM digits long (default 40).
+ */
+
+#define IEEE_8087
+#define NO_HEX_FP
+
+#ifndef Long
+#if __LP64__
+#define Long int
+#else
+#define Long long
+#endif
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+#ifdef Honor_FLT_ROUNDS
+#ifndef Trust_FLT_ROUNDS
+#include <fenv.h>
+#endif
+#endif
+
+#ifdef MALLOC
+#ifdef KR_headers
+extern char *MALLOC();
+#else
+extern void *MALLOC(size_t);
+#endif
+#else
+#define MALLOC malloc
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#else
+#undef INFNAN_CHECK
+#define NO_STRTOD_BIGCOMP
+#endif
+
+#include "errno.h"
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+namespace dmg_fp {
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+#ifndef STRTOD_DIGLIM
+#define STRTOD_DIGLIM 40
+#endif
+
+#ifdef DIGLIM_DEBUG
+extern int strtod_diglim;
+#else
+#define strtod_diglim STRTOD_DIGLIM
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Nbits 53
+#define Bias 1023
+#define Emax 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm	/* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Nbits 56
+#define Bias 65
+#define Emax 248
+#define Emin (-260)
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Nbits 56
+#define Bias 129
+#define Emax 126
+#define Emin (-129)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+typedef struct BCinfo BCinfo;
+ struct
+BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; };
+
+#ifdef KR_headers
+#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
+#else
+#define FFFFFFFF 0xffffffffUL
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#endif
+
+#define Kmax 7
+
+double strtod(const char *s00, char **se);
+char *dtoa(double d, int mode, int ndigits,
+			int *decpt, int *sign, char **rve);
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+ static Bigint *freelist[Kmax+1];
+
+ static Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && freelist[k]) {
+		rv = freelist[k];
+		freelist[k] = rv->next;
+		}
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ static void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE((void*)v);
+#else
+			free((void*)v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(Long) + 2*sizeof(int))
+
+ static Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = (ULong)carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ static Bigint *
+s2b
+#ifdef KR_headers
+	(s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9;
+#else
+	(CONST char *s, int nd0, int nd, ULong y9, int dplen)
+#endif
+{
+	Bigint *b;
+	int i, k;
+	Long x, y;
+
+	x = (nd + 8) / 9;
+	for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+	b = Balloc(k);
+	b->x[0] = y9;
+	b->wds = 1;
+#else
+	b = Balloc(k+1);
+	b->x[0] = y9 & 0xffff;
+	b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+	i = 9;
+	if (9 < nd0) {
+		s += 9;
+		do b = multadd(b, 10, *s++ - '0');
+			while(++i < nd0);
+		s += dplen;
+		}
+	else
+		s += dplen + 9;
+	for(; i < nd; i++)
+		b = multadd(b, 10, *s++ - '0');
+	return b;
+	}
+
+ static int
+hi0bits
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ static int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ static Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ static Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		y = *xb++;
+		if (y) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & FFFFFFFF;
+				}
+				while(x < xae);
+			*xc = (ULong)carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if (y = *xb & 0xffff) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if (y = *xb >> 16) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if (y = *xb++) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ static Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	i = k & 3;
+	if (i)
+		b = multadd(b, p05[i-1], 0);
+
+	if (!(k >>= 2))
+		return b;
+	p5 = p5s;
+	if (!p5) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		p5 = p5s;
+		if (!p5) {
+			p5 = p5s = i2b(625);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		p51 = p5->next;
+		if (!p51) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			p51 = p5->next;
+			if (!p51) {
+				p51 = p5->next = mult(p5,p5);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ static Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+	n = k >> 5;
+#else
+	n = k >> 4;
+#endif
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+#ifdef Pack_32
+	if (k &= 0x1f) {
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		*x1 = z;
+		if (*x1)
+			++n1;
+		}
+#else
+	if (k &= 0xf) {
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+		}
+#endif
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ static int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ static Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ static double
+ulp
+#ifdef KR_headers
+	(x) U *x;
+#else
+	(U *x)
+#endif
+{
+	Long L;
+	U u;
+
+	L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+	if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+		L |= Exp_msk1 >> 4;
+#endif
+		word0(&u) = L;
+		word1(&u) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+		}
+	else {
+		L = -L >> Exp_shift;
+		if (L < Exp_shift) {
+			word0(&u) = 0x80000 >> L;
+			word1(&u) = 0;
+			}
+		else {
+			word0(&u) = 0;
+			L -= Exp_shift;
+			word1(&u) = L >= 31 ? 1 : 1 << 31 - L;
+			}
+		}
+#endif
+#endif
+	return dval(&u);
+	}
+
+ static double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+	return dval(&d);
+	}
+
+ static Bigint *
+d2b
+#ifdef KR_headers
+	(d, e, bits) U *d; int *e, *bits;
+#else
+	(U *d, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	int de, k;
+	ULong *x, y, z;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+#ifdef VAX
+	ULong d0, d1;
+	d0 = word0(d) >> 16 | word0(d) << 16;
+	d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	de = (int)(d0 >> Exp_shift);
+	if (de)
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	y = d1;
+	if (y) {
+		k = lo0bits(&y);
+		if (k) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+		x[1] = z;
+		b->wds = x[1] ? 2 : 1;
+#ifndef Sudden_Underflow
+		i = b->wds;
+#endif
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if (y = d1) {
+		if (k = lo0bits(&y))
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ static double
+ratio
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	U da, db;
+	int k, ka, kb;
+
+	dval(&da) = b2d(a, &ka);
+	dval(&db) = b2d(b, &kb);
+#ifdef Pack_32
+	k = ka - kb + 32*(a->wds - b->wds);
+#else
+	k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+	if (k > 0) {
+		word0(&da) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(&da) *= 1 << k;
+		}
+	else {
+		k = -k;
+		word0(&db) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(&db) *= 1 << k;
+		}
+#else
+	if (k > 0)
+		word0(&da) += k*Exp_msk1;
+	else {
+		k = -k;
+		word0(&db) += k*Exp_msk1;
+		}
+#endif
+	return dval(&da) / dval(&db);
+	}
+
+ static CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+ static CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+		9007199254740992.*9007199254740992.e-256
+		/* = 2^106 * 1e-256 */
+#else
+		1e-256
+#endif
+		};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static CONST double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#undef Need_Hexdig
+#ifdef INFNAN_CHECK
+#ifndef No_Hex_NaN
+#define Need_Hexdig
+#endif
+#endif
+
+#ifndef Need_Hexdig
+#ifndef NO_HEX_FP
+#define Need_Hexdig
+#endif
+#endif
+
+#ifdef Need_Hexdig /*{*/
+static unsigned char hexdig[256];
+
+ static void
+#ifdef KR_headers
+htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc;
+#else
+htinit(unsigned char *h, unsigned char *s, int inc)
+#endif
+{
+	int i, j;
+	for(i = 0; (j = s[i]) !=0; i++)
+		h[j] = (unsigned char)(i + inc);
+	}
+
+ static void
+#ifdef KR_headers
+hexdig_init()
+#else
+hexdig_init(void)
+#endif
+{
+#define USC (unsigned char *)
+	htinit(hexdig, USC "0123456789", 0x10);
+	htinit(hexdig, USC "abcdef", 0x10 + 10);
+	htinit(hexdig, USC "ABCDEF", 0x10 + 10);
+	}
+#endif /* } Need_Hexdig */
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+ static int
+match
+#ifdef KR_headers
+	(sp, t) char **sp, *t;
+#else
+	(CONST char **sp, CONST char *t)
+#endif
+{
+	int c, d;
+	CONST char *s = *sp;
+
+	for(d = *t++; d; d = *t++) {
+		if ((c = *++s) >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+		if (c != d)
+			return 0;
+		}
+	*sp = s + 1;
+	return 1;
+	}
+
+#ifndef No_Hex_NaN
+ static void
+hexnan
+#ifdef KR_headers
+	(rvp, sp) U *rvp; CONST char **sp;
+#else
+	(U *rvp, CONST char **sp)
+#endif
+{
+	ULong c, x[2];
+	CONST char *s;
+	int c1, havedig, udx0, xshift;
+
+	if (!hexdig['0'])
+		hexdig_init();
+	x[0] = x[1] = 0;
+	havedig = xshift = 0;
+	udx0 = 1;
+	s = *sp;
+	/* allow optional initial 0x or 0X */
+	for(c = *(CONST unsigned char*)(s+1); c && c <= ' '; c = *(CONST unsigned char*)(s+1))
+		++s;
+	if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
+		s += 2;
+	for(c = *(CONST unsigned char*)++s; c; c = *(CONST unsigned char*)++s) {
+		c1 = hexdig[c];
+		if (c1)
+			c  = c1 & 0xf;
+		else if (c <= ' ') {
+			if (udx0 && havedig) {
+				udx0 = 0;
+				xshift = 1;
+				}
+			continue;
+			}
+#ifdef GDTOA_NON_PEDANTIC_NANCHECK
+		else if (/*(*/ c == ')' && havedig) {
+			*sp = s + 1;
+			break;
+			}
+		else
+			return;	/* invalid form: don't change *sp */
+#else
+		else {
+			do {
+				if (/*(*/ c == ')') {
+					*sp = s + 1;
+					break;
+					}
+				c = *++s;
+				} while(c);
+			break;
+			}
+#endif
+		havedig = 1;
+		if (xshift) {
+			xshift = 0;
+			x[0] = x[1];
+			x[1] = 0;
+			}
+		if (udx0)
+			x[0] = (x[0] << 4) | (x[1] >> 28);
+		x[1] = (x[1] << 4) | c;
+		}
+	if ((x[0] &= 0xfffff) || x[1]) {
+		word0(rvp) = Exp_mask | x[0];
+		word1(rvp) = x[1];
+		}
+	}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#endif
+#ifndef NO_HEX_FP /*{*/
+
+ static void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = 32 - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & 0xffffffff;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ static ULong
+#ifdef KR_headers
+any_on(b, k) Bigint *b; int k;
+#else
+any_on(Bigint *b, int k)
+#endif
+{
+	int n, nwds;
+	ULong *x, *x0, x1, x2;
+
+	x = b->x;
+	nwds = b->wds;
+	n = k >> kshift;
+	if (n > nwds)
+		n = nwds;
+	else if (n < nwds && (k &= kmask)) {
+		x1 = x2 = x[n];
+		x1 >>= k;
+		x1 <<= k;
+		if (x1 != x2)
+			return 1;
+		}
+	x0 = x;
+	x += n;
+	while(x > x0)
+		if (*--x)
+			return 1;
+	return 0;
+	}
+
+enum {	/* rounding values: same as FLT_ROUNDS */
+	Round_zero = 0,
+	Round_near = 1,
+	Round_up = 2,
+	Round_down = 3
+	};
+
+ static Bigint *
+#ifdef KR_headers
+increment(b) Bigint *b;
+#else
+increment(Bigint *b)
+#endif
+{
+	ULong *x, *xe;
+	Bigint *b1;
+
+	x = b->x;
+	xe = x + b->wds;
+	do {
+		if (*x < (ULong)0xffffffffL) {
+			++*x;
+			return b;
+			}
+		*x++ = 0;
+		} while(x < xe);
+	{
+		if (b->wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1,b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[b->wds++] = 1;
+		}
+	return b;
+	}
+
+ void
+#ifdef KR_headers
+gethex(sp, rvp, rounding, sign)
+	CONST char **sp; U *rvp; int rounding, sign;
+#else
+gethex( CONST char **sp, U *rvp, int rounding, int sign)
+#endif
+{
+	Bigint *b;
+	CONST unsigned char *decpt, *s0, *s, *s1;
+	Long e, e1;
+	ULong L, lostbits, *x;
+	int big, denorm, esign, havedig, k, n, nbits, up, zret;
+#ifdef IBM
+	int j;
+#endif
+	enum {
+#ifdef IEEE_Arith /*{{*/
+		emax = 0x7fe - Bias - P + 1,
+		emin = Emin - P + 1
+#else /*}{*/
+		emin = Emin - P,
+#ifdef VAX
+		emax = 0x7ff - Bias - P + 1
+#endif
+#ifdef IBM
+		emax = 0x7f - Bias - P
+#endif
+#endif /*}}*/
+		};
+#ifdef USE_LOCALE
+	int i;
+#ifdef NO_LOCALE_CACHE
+	const unsigned char *decimalpoint = (unsigned char*)
+		localeconv()->decimal_point;
+#else
+	const unsigned char *decimalpoint;
+	static unsigned char *decimalpoint_cache;
+	if (!(s0 = decimalpoint_cache)) {
+		s0 = (unsigned char*)localeconv()->decimal_point;
+		if ((decimalpoint_cache = (unsigned char*)
+				MALLOC(strlen((CONST char*)s0) + 1))) {
+			strcpy((char*)decimalpoint_cache, (CONST char*)s0);
+			s0 = decimalpoint_cache;
+			}
+		}
+	decimalpoint = s0;
+#endif
+#endif
+
+	if (!hexdig['0'])
+		hexdig_init();
+	havedig = 0;
+	s0 = *(CONST unsigned char **)sp + 2;
+	while(s0[havedig] == '0')
+		havedig++;
+	s0 += havedig;
+	s = s0;
+	decpt = 0;
+	zret = 0;
+	e = 0;
+	if (hexdig[*s])
+		havedig++;
+	else {
+		zret = 1;
+#ifdef USE_LOCALE
+		for(i = 0; decimalpoint[i]; ++i) {
+			if (s[i] != decimalpoint[i])
+				goto pcheck;
+			}
+		decpt = s += i;
+#else
+		if (*s != '.')
+			goto pcheck;
+		decpt = ++s;
+#endif
+		if (!hexdig[*s])
+			goto pcheck;
+		while(*s == '0')
+			s++;
+		if (hexdig[*s])
+			zret = 0;
+		havedig = 1;
+		s0 = s;
+		}
+	while(hexdig[*s])
+		s++;
+#ifdef USE_LOCALE
+	if (*s == *decimalpoint && !decpt) {
+		for(i = 1; decimalpoint[i]; ++i) {
+			if (s[i] != decimalpoint[i])
+				goto pcheck;
+			}
+		decpt = s += i;
+#else
+	if (*s == '.' && !decpt) {
+		decpt = ++s;
+#endif
+		while(hexdig[*s])
+			s++;
+		}/*}*/
+	if (decpt)
+		e = -(((Long)(s-decpt)) << 2);
+ pcheck:
+	s1 = s;
+	big = esign = 0;
+	switch(*s) {
+	  case 'p':
+	  case 'P':
+		switch(*++s) {
+		  case '-':
+			esign = 1;
+			/* no break */
+		  case '+':
+			s++;
+		  }
+		if ((n = hexdig[*s]) == 0 || n > 0x19) {
+			s = s1;
+			break;
+			}
+		e1 = n - 0x10;
+		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
+			if (e1 & 0xf8000000)
+				big = 1;
+			e1 = 10*e1 + n - 0x10;
+			}
+		if (esign)
+			e1 = -e1;
+		e += e1;
+	  }
+	*sp = (char*)s;
+	if (!havedig)
+		*sp = (char*)s0 - 1;
+	if (zret)
+		goto retz1;
+	if (big) {
+		if (esign) {
+#ifdef IEEE_Arith
+			switch(rounding) {
+			  case Round_up:
+				if (sign)
+					break;
+				goto ret_tiny;
+			  case Round_down:
+				if (!sign)
+					break;
+				goto ret_tiny;
+			  }
+#endif
+			goto retz;
+#ifdef IEEE_Arith
+ ret_tiny:
+#ifndef NO_ERRNO
+			errno = ERANGE;
+#endif
+			word0(rvp) = 0;
+			word1(rvp) = 1;
+			return;
+#endif /* IEEE_Arith */
+			}
+		switch(rounding) {
+		  case Round_near:
+			goto ovfl1;
+		  case Round_up:
+			if (!sign)
+				goto ovfl1;
+			goto ret_big;
+		  case Round_down:
+			if (sign)
+				goto ovfl1;
+			goto ret_big;
+		  }
+ ret_big:
+		word0(rvp) = Big0;
+		word1(rvp) = Big1;
+		return;
+		}
+	n = s1 - s0 - 1;
+	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
+		k++;
+	b = Balloc(k);
+	x = b->x;
+	n = 0;
+	L = 0;
+#ifdef USE_LOCALE
+	for(i = 0; decimalpoint[i+1]; ++i);
+#endif
+	while(s1 > s0) {
+#ifdef USE_LOCALE
+		if (*--s1 == decimalpoint[i]) {
+			s1 -= i;
+			continue;
+			}
+#else
+		if (*--s1 == '.')
+			continue;
+#endif
+		if (n == ULbits) {
+			*x++ = L;
+			L = 0;
+			n = 0;
+			}
+		L |= (hexdig[*s1] & 0x0f) << n;
+		n += 4;
+		}
+	*x++ = L;
+	b->wds = n = x - b->x;
+	n = ULbits*n - hi0bits(L);
+	nbits = Nbits;
+	lostbits = 0;
+	x = b->x;
+	if (n > nbits) {
+		n -= nbits;
+		if (any_on(b,n)) {
+			lostbits = 1;
+			k = n - 1;
+			if (x[k>>kshift] & 1 << (k & kmask)) {
+				lostbits = 2;
+				if (k > 0 && any_on(b,k))
+					lostbits = 3;
+				}
+			}
+		rshift(b, n);
+		e += n;
+		}
+	else if (n < nbits) {
+		n = nbits - n;
+		b = lshift(b, n);
+		e -= n;
+		x = b->x;
+		}
+	if (e > Emax) {
+ ovfl:
+		Bfree(b);
+ ovfl1:
+#ifndef NO_ERRNO
+		errno = ERANGE;
+#endif
+		word0(rvp) = Exp_mask;
+		word1(rvp) = 0;
+		return;
+		}
+	denorm = 0;
+	if (e < emin) {
+		denorm = 1;
+		n = emin - e;
+		if (n >= nbits) {
+#ifdef IEEE_Arith /*{*/
+			switch (rounding) {
+			  case Round_near:
+				if (n == nbits && (n < 2 || any_on(b,n-1)))
+					goto ret_tiny;
+				break;
+			  case Round_up:
+				if (!sign)
+					goto ret_tiny;
+				break;
+			  case Round_down:
+				if (sign)
+					goto ret_tiny;
+			  }
+#endif /* } IEEE_Arith */
+			Bfree(b);
+ retz:
+#ifndef NO_ERRNO
+			errno = ERANGE;
+#endif
+ retz1:
+			rvp->d = 0.;
+			return;
+			}
+		k = n - 1;
+		if (lostbits)
+			lostbits = 1;
+		else if (k > 0)
+			lostbits = any_on(b,k);
+		if (x[k>>kshift] & 1 << (k & kmask))
+			lostbits |= 2;
+		nbits -= n;
+		rshift(b,n);
+		e = emin;
+		}
+	if (lostbits) {
+		up = 0;
+		switch(rounding) {
+		  case Round_zero:
+			break;
+		  case Round_near:
+			if (lostbits & 2
+			 && (lostbits & 1) | (x[0] & 1))
+				up = 1;
+			break;
+		  case Round_up:
+			up = 1 - sign;
+			break;
+		  case Round_down:
+			up = sign;
+		  }
+		if (up) {
+			k = b->wds;
+			b = increment(b);
+			x = b->x;
+			if (denorm) {
+#if 0
+				if (nbits == Nbits - 1
+				 && x[nbits >> kshift] & 1 << (nbits & kmask))
+					denorm = 0; /* not currently used */
+#endif
+				}
+			else if (b->wds > k
+			 || ((n = nbits & kmask) !=0
+			     && hi0bits(x[k-1]) < 32-n)) {
+				rshift(b,1);
+				if (++e > Emax)
+					goto ovfl;
+				}
+			}
+		}
+#ifdef IEEE_Arith
+	if (denorm)
+		word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0;
+	else
+		word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20);
+	word1(rvp) = b->x[0];
+#endif
+#ifdef IBM
+	if ((j = e & 3)) {
+		k = b->x[0] & ((1 << j) - 1);
+		rshift(b,j);
+		if (k) {
+			switch(rounding) {
+			  case Round_up:
+				if (!sign)
+					increment(b);
+				break;
+			  case Round_down:
+				if (sign)
+					increment(b);
+				break;
+			  case Round_near:
+				j = 1 << (j-1);
+				if (k & j && ((k & (j-1)) | lostbits))
+					increment(b);
+			  }
+			}
+		}
+	e >>= 2;
+	word0(rvp) = b->x[1] | ((e + 65 + 13) << 24);
+	word1(rvp) = b->x[0];
+#endif
+#ifdef VAX
+	/* The next two lines ignore swap of low- and high-order 2 bytes. */
+	/* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */
+	/* word1(rvp) = b->x[0]; */
+	word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16);
+	word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16);
+#endif
+	Bfree(b);
+	}
+#endif /*}!NO_HEX_FP*/
+
+ static int
+#ifdef KR_headers
+dshift(b, p2) Bigint *b; int p2;
+#else
+dshift(Bigint *b, int p2)
+#endif
+{
+	int rv = hi0bits(b->x[b->wds-1]) - 4;
+	if (p2 > 0)
+		rv -= p2;
+	return rv & kmask;
+	}
+
+ static int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
+
+#ifndef NO_STRTOD_BIGCOMP
+
+ static void
+bigcomp
+#ifdef KR_headers
+	(rv, s0, bc)
+	U *rv; CONST char *s0; BCinfo *bc;
+#else
+	(U *rv, CONST char *s0, BCinfo *bc)
+#endif
+{
+	Bigint *b, *d;
+	int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase;
+
+	dsign = bc->dsign;
+	nd = bc->nd;
+	nd0 = bc->nd0;
+	p5 = nd + bc->e0 - 1;
+	dd = speccase = 0;
+#ifndef Sudden_Underflow
+	if (rv->d == 0.) {	/* special case: value near underflow-to-zero */
+				/* threshold was rounded to zero */
+		b = i2b(1);
+		p2 = Emin - P + 1;
+		bbits = 1;
+#ifdef Avoid_Underflow
+		word0(rv) = (P+2) << Exp_shift;
+#else
+		word1(rv) = 1;
+#endif
+		i = 0;
+#ifdef Honor_FLT_ROUNDS
+		if (bc->rounding == 1)
+#endif
+			{
+			speccase = 1;
+			--p2;
+			dsign = 0;
+			goto have_i;
+			}
+		}
+	else
+#endif
+		b = d2b(rv, &p2, &bbits);
+#ifdef Avoid_Underflow
+	p2 -= bc->scale;
+#endif
+	/* floor(log2(rv)) == bbits - 1 + p2 */
+	/* Check for denormal case. */
+	i = P - bbits;
+	if (i > (j = P - Emin - 1 + p2)) {
+#ifdef Sudden_Underflow
+		Bfree(b);
+		b = i2b(1);
+		p2 = Emin;
+		i = P - 1;
+#ifdef Avoid_Underflow
+		word0(rv) = (1 + bc->scale) << Exp_shift;
+#else
+		word0(rv) = Exp_msk1;
+#endif
+		word1(rv) = 0;
+#else
+		i = j;
+#endif
+		}
+#ifdef Honor_FLT_ROUNDS
+	if (bc->rounding != 1) {
+		if (i > 0)
+			b = lshift(b, i);
+		if (dsign)
+			b = increment(b);
+		}
+	else
+#endif
+		{
+		b = lshift(b, ++i);
+		b->x[0] |= 1;
+		}
+#ifndef Sudden_Underflow
+ have_i:
+#endif
+	p2 -= p5 + i;
+	d = i2b(1);
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 */
+	if (p5 > 0)
+		d = pow5mult(d, p5);
+	else if (p5 < 0)
+		b = pow5mult(b, -p5);
+	if (p2 > 0) {
+		b2 = p2;
+		d2 = 0;
+		}
+	else {
+		b2 = 0;
+		d2 = -p2;
+		}
+	i = dshift(d, d2);
+	if ((b2 += i) > 0)
+		b = lshift(b, b2);
+	if ((d2 += i) > 0)
+		d = lshift(d, d2);
+
+	/* Now b/d = exactly half-way between the two floating-point values */
+	/* on either side of the input string.  Compute first digit of b/d. */
+
+	dig = quorem(b,d);
+	if (!dig) {
+		b = multadd(b, 10, 0);	/* very unlikely */
+		dig = quorem(b,d);
+		}
+
+	/* Compare b/d with s0 */
+
+	for(i = 0; i < nd0; ) {
+		dd = s0[i++] - '0' - dig;
+		if (dd)
+			goto ret;
+		if (!b->x[0] && b->wds == 1) {
+			if (i < nd)
+				dd = 1;
+			goto ret;
+			}
+		b = multadd(b, 10, 0);
+		dig = quorem(b,d);
+		}
+	for(j = bc->dp1; i++ < nd;) {
+		dd = s0[j++] - '0' - dig;
+		if (dd)
+			goto ret;
+		if (!b->x[0] && b->wds == 1) {
+			if (i < nd)
+				dd = 1;
+			goto ret;
+			}
+		b = multadd(b, 10, 0);
+		dig = quorem(b,d);
+		}
+	if (b->x[0] || b->wds > 1)
+		dd = -1;
+ ret:
+	Bfree(b);
+	Bfree(d);
+#ifdef Honor_FLT_ROUNDS
+	if (bc->rounding != 1) {
+		if (dd < 0) {
+			if (bc->rounding == 0) {
+				if (!dsign)
+					goto retlow1;
+				}
+			else if (dsign)
+				goto rethi1;
+			}
+		else if (dd > 0) {
+			if (bc->rounding == 0) {
+				if (dsign)
+					goto rethi1;
+				goto ret1;
+				}
+			if (!dsign)
+				goto rethi1;
+			dval(rv) += 2.*ulp(rv);
+			}
+		else {
+			bc->inexact = 0;
+			if (dsign)
+				goto rethi1;
+			}
+		}
+	else
+#endif
+	if (speccase) {
+		if (dd <= 0)
+			rv->d = 0.;
+		}
+	else if (dd < 0) {
+		if (!dsign)	/* does not happen for round-near */
+retlow1:
+			dval(rv) -= ulp(rv);
+		}
+	else if (dd > 0) {
+		if (dsign) {
+ rethi1:
+			dval(rv) += ulp(rv);
+			}
+		}
+	else {
+		/* Exact half-way case:  apply round-even rule. */
+		if (word1(rv) & 1) {
+			if (dsign)
+				goto rethi1;
+			goto retlow1;
+			}
+		}
+
+#ifdef Honor_FLT_ROUNDS
+ ret1:
+#endif
+	return;
+	}
+#endif /* NO_STRTOD_BIGCOMP */
+
+ double
+strtod
+#ifdef KR_headers
+	(s00, se) CONST char *s00; char **se;
+#else
+	(CONST char *s00, char **se)
+#endif
+{
+	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;
+	int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+	CONST char *s, *s0, *s1;
+	double aadj, aadj1;
+	Long L;
+	U aadj2, adj, rv, rv0;
+	ULong y, z;
+	BCinfo bc;
+	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+	int oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	bc.rounding = Flt_Rounds;
+#else /*}{*/
+	bc.rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	bc.rounding = 0; break;
+	  case FE_UPWARD:	bc.rounding = 2; break;
+	  case FE_DOWNWARD:	bc.rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+#ifdef USE_LOCALE
+	CONST char *s2;
+#endif
+
+	sign = nz0 = nz = bc.dplen = bc.uflchk = 0;
+	dval(&rv) = 0.;
+	for(s = s00;;s++) switch(*s) {
+		case '-':
+			sign = 1;
+			/* no break */
+		case '+':
+			if (*++s)
+				goto break2;
+			/* no break */
+		case 0:
+			goto ret0;
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			continue;
+		default:
+			goto break2;
+		}
+ break2:
+	if (*s == '0') {
+#ifndef NO_HEX_FP /*{*/
+		switch(s[1]) {
+		  case 'x':
+		  case 'X':
+#ifdef Honor_FLT_ROUNDS
+			gethex(&s, &rv, bc.rounding, sign);
+#else
+			gethex(&s, &rv, 1, sign);
+#endif
+			goto ret;
+		  }
+#endif /*}*/
+		nz0 = 1;
+		while(*++s == '0') ;
+		if (!*s)
+			goto ret;
+		}
+	s0 = s;
+	y = z = 0;
+	for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+		if (nd < 9)
+			y = 10*y + c - '0';
+		else if (nd < 16)
+			z = 10*z + c - '0';
+	nd0 = nd;
+	bc.dp0 = bc.dp1 = s - s0;
+#ifdef USE_LOCALE
+	s1 = localeconv()->decimal_point;
+	if (c == *s1) {
+		c = '.';
+		if (*++s1) {
+			s2 = s;
+			for(;;) {
+				if (*++s2 != *s1) {
+					c = 0;
+					break;
+					}
+				if (!*++s1) {
+					s = s2;
+					break;
+					}
+				}
+			}
+		}
+#endif
+	if (c == '.') {
+		c = *++s;
+		bc.dp1 = s - s0;
+		bc.dplen = bc.dp1 - bc.dp0;
+		if (!nd) {
+			for(; c == '0'; c = *++s)
+				nz++;
+			if (c > '0' && c <= '9') {
+				s0 = s;
+				nf += nz;
+				nz = 0;
+				goto have_dig;
+				}
+			goto dig_done;
+			}
+		for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+			nz++;
+			if (c -= '0') {
+				nf += nz;
+				for(i = 1; i < nz; i++)
+					if (nd++ < 9)
+						y *= 10;
+					else if (nd <= DBL_DIG + 1)
+						z *= 10;
+				if (nd++ < 9)
+					y = 10*y + c;
+				else if (nd <= DBL_DIG + 1)
+					z = 10*z + c;
+				nz = 0;
+				}
+			}
+		}
+ dig_done:
+	e = 0;
+	if (c == 'e' || c == 'E') {
+		if (!nd && !nz && !nz0) {
+			goto ret0;
+			}
+		s00 = s;
+		esign = 0;
+		switch(c = *++s) {
+			case '-':
+				esign = 1;
+			case '+':
+				c = *++s;
+			}
+		if (c >= '0' && c <= '9') {
+			while(c == '0')
+				c = *++s;
+			if (c > '0' && c <= '9') {
+				L = c - '0';
+				s1 = s;
+				while((c = *++s) >= '0' && c <= '9')
+					L = 10*L + c - '0';
+				if (s - s1 > 8 || L > 19999)
+					/* Avoid confusion from exponents
+					 * so large that e might overflow.
+					 */
+					e = 19999; /* safe for 16 bit ints */
+				else
+					e = (int)L;
+				if (esign)
+					e = -e;
+				}
+			else
+				e = 0;
+			}
+		else
+			s = s00;
+		}
+	if (!nd) {
+		if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+			/* Check for Nan and Infinity */
+			if (!bc.dplen)
+			 switch(c) {
+			  case 'i':
+			  case 'I':
+				if (match(&s,"nf")) {
+					--s;
+					if (!match(&s,"inity"))
+						++s;
+					word0(&rv) = 0x7ff00000;
+					word1(&rv) = 0;
+					goto ret;
+					}
+				break;
+			  case 'n':
+			  case 'N':
+				if (match(&s, "an")) {
+					word0(&rv) = NAN_WORD0;
+					word1(&rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+					if (*s == '(') /*)*/
+						hexnan(&rv, &s);
+#endif
+					goto ret;
+					}
+			  }
+#endif /* INFNAN_CHECK */
+ ret0:
+			s = s00;
+			sign = 0;
+			}
+		goto ret;
+		}
+	bc.e0 = e1 = e -= nf;
+
+	/* Now we have nd0 digits, starting at s0, followed by a
+	 * decimal point, followed by nd-nd0 digits.  The number we're
+	 * after is the integer represented by those digits times
+	 * 10**e */
+
+	if (!nd0)
+		nd0 = nd;
+	k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+	dval(&rv) = y;
+	if (k > 9) {
+#ifdef SET_INEXACT
+		if (k > DBL_DIG)
+			oldinexact = get_inexact();
+#endif
+		dval(&rv) = tens[k - 9] * dval(&rv) + z;
+		}
+	bd0 = 0;
+	if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+		&& Flt_Rounds == 1
+#endif
+#endif
+			) {
+		if (!e)
+			goto ret;
+		if (e > 0) {
+			if (e <= Ten_pmax) {
+#ifdef VAX
+				goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv.d = -rv.d;
+					sign = 0;
+					}
+#endif
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+				goto ret;
+#endif
+				}
+			i = DBL_DIG - nd;
+			if (e <= Ten_pmax + i) {
+				/* A fancier test would sometimes let us do
+				 * this for larger i values.
+				 */
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv.d = -rv.d;
+					sign = 0;
+					}
+#endif
+				e -= i;
+				dval(&rv) *= tens[i];
+#ifdef VAX
+				/* VAX exponent range is so narrow we must
+				 * worry about overflow here...
+				 */
+ vax_ovfl_check:
+				word0(&rv) -= P*Exp_msk1;
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+				if ((word0(&rv) & Exp_mask)
+				 > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+					goto ovfl;
+				word0(&rv) += P*Exp_msk1;
+#else
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+#endif
+				goto ret;
+				}
+			}
+#ifndef Inaccurate_Divide
+		else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+			/* round correctly FLT_ROUNDS = 2 or 3 */
+			if (sign) {
+				rv.d = -rv.d;
+				sign = 0;
+				}
+#endif
+			/* rv = */ rounded_quotient(dval(&rv), tens[-e]);
+			goto ret;
+			}
+#endif
+		}
+	e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+	bc.inexact = 1;
+	if (k <= DBL_DIG)
+		oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+	bc.scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (bc.rounding >= 2) {
+		if (sign)
+			bc.rounding = bc.rounding == 2 ? 0 : 2;
+		else
+			if (bc.rounding != 2)
+				bc.rounding = 0;
+		}
+#endif
+#endif /*IEEE_Arith*/
+
+	/* Get starting approximation = rv * 10**e1 */
+
+	if (e1 > 0) {
+		i = e1 & 15;
+		if (i)
+			dval(&rv) *= tens[i];
+		if (e1 &= ~15) {
+			if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+#ifndef NO_ERRNO
+				errno = ERANGE;
+#endif
+				/* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+				switch(bc.rounding) {
+				  case 0: /* toward 0 */
+				  case 3: /* toward -infinity */
+					word0(&rv) = Big0;
+					word1(&rv) = Big1;
+					break;
+				  default:
+					word0(&rv) = Exp_mask;
+					word1(&rv) = 0;
+				  }
+#else /*Honor_FLT_ROUNDS*/
+				word0(&rv) = Exp_mask;
+				word1(&rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+				/* set overflow bit */
+				dval(&rv0) = 1e300;
+				dval(&rv0) *= dval(&rv0);
+#endif
+#else /*IEEE_Arith*/
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+#endif /*IEEE_Arith*/
+				goto ret;
+				}
+			e1 >>= 4;
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= bigtens[j];
+		/* The last multiplication could overflow. */
+			word0(&rv) -= P*Exp_msk1;
+			dval(&rv) *= bigtens[j];
+			if ((z = word0(&rv) & Exp_mask)
+			 > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+				goto ovfl;
+			if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+				/* set to largest number */
+				/* (Can't trust DBL_MAX) */
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+				}
+			else
+				word0(&rv) += P*Exp_msk1;
+			}
+		}
+	else if (e1 < 0) {
+		e1 = -e1;
+		i = e1 & 15;
+		if (i)
+			dval(&rv) /= tens[i];
+		if (e1 >>= 4) {
+			if (e1 >= 1 << n_bigtens)
+				goto undfl;
+#ifdef Avoid_Underflow
+			if (e1 & Scale_Bit)
+				bc.scale = 2*P;
+			for(j = 0; e1 > 0; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= tinytens[j];
+			if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask)
+						>> Exp_shift)) > 0) {
+				/* scaled rv is denormal; clear j low bits */
+				if (j >= 32) {
+					word1(&rv) = 0;
+					if (j >= 53)
+					 word0(&rv) = (P+2)*Exp_msk1;
+					else
+					 word0(&rv) &= 0xffffffff << (j-32);
+					}
+				else
+					word1(&rv) &= 0xffffffff << j;
+				}
+#else
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= tinytens[j];
+			/* The last multiplication could underflow. */
+			dval(&rv0) = dval(&rv);
+			dval(&rv) *= tinytens[j];
+			if (!dval(&rv)) {
+				dval(&rv) = 2.*dval(&rv0);
+				dval(&rv) *= tinytens[j];
+#endif
+				if (!dval(&rv)) {
+ undfl:
+					dval(&rv) = 0.;
+#ifndef NO_ERRNO
+					errno = ERANGE;
+#endif
+					goto ret;
+					}
+#ifndef Avoid_Underflow
+				word0(&rv) = Tiny0;
+				word1(&rv) = Tiny1;
+				/* The refinement below will clean
+				 * this approximation up.
+				 */
+				}
+#endif
+			}
+		}
+
+	/* Now the hard part -- adjusting rv to the correct value.*/
+
+	/* Put digits into bd: true value = bd * 10^e */
+
+	bc.nd = nd;
+#ifndef NO_STRTOD_BIGCOMP
+	bc.nd0 = nd0;	/* Only needed if nd > strtod_diglim, but done here */
+			/* to silence an erroneous warning about bc.nd0 */
+			/* possibly not being initialized. */
+	if (nd > strtod_diglim) {
+		/* ASSERT(strtod_diglim >= 18); 18 == one more than the */
+		/* minimum number of decimal digits to distinguish double values */
+		/* in IEEE arithmetic. */
+		i = j = 18;
+		if (i > nd0)
+			j += bc.dplen;
+		for(;;) {
+			if (--j <= bc.dp1 && j >= bc.dp0)
+				j = bc.dp0 - 1;
+			if (s0[j] != '0')
+				break;
+			--i;
+			}
+		e += nd - i;
+		nd = i;
+		if (nd0 > nd)
+			nd0 = nd;
+		if (nd < 9) { /* must recompute y */
+			y = 0;
+			for(i = 0; i < nd0; ++i)
+				y = 10*y + s0[i] - '0';
+			for(j = bc.dp1; i < nd; ++i)
+				y = 10*y + s0[j++] - '0';
+			}
+		}
+#endif
+	bd0 = s2b(s0, nd0, nd, y, bc.dplen);
+
+	for(;;) {
+		bd = Balloc(bd0->k);
+		Bcopy(bd, bd0);
+		bb = d2b(&rv, &bbe, &bbbits);	/* rv = bb * 2^bbe */
+		bs = i2b(1);
+
+		if (e >= 0) {
+			bb2 = bb5 = 0;
+			bd2 = bd5 = e;
+			}
+		else {
+			bb2 = bb5 = -e;
+			bd2 = bd5 = 0;
+			}
+		if (bbe >= 0)
+			bb2 += bbe;
+		else
+			bd2 -= bbe;
+		bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+		if (bc.rounding != 1)
+			bs2++;
+#endif
+#ifdef Avoid_Underflow
+		j = bbe - bc.scale;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+		j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+		j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+		j = bbe;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+		bb2 += j;
+		bd2 += j;
+#ifdef Avoid_Underflow
+		bd2 += bc.scale;
+#endif
+		i = bb2 < bd2 ? bb2 : bd2;
+		if (i > bs2)
+			i = bs2;
+		if (i > 0) {
+			bb2 -= i;
+			bd2 -= i;
+			bs2 -= i;
+			}
+		if (bb5 > 0) {
+			bs = pow5mult(bs, bb5);
+			bb1 = mult(bs, bb);
+			Bfree(bb);
+			bb = bb1;
+			}
+		if (bb2 > 0)
+			bb = lshift(bb, bb2);
+		if (bd5 > 0)
+			bd = pow5mult(bd, bd5);
+		if (bd2 > 0)
+			bd = lshift(bd, bd2);
+		if (bs2 > 0)
+			bs = lshift(bs, bs2);
+		delta = diff(bb, bd);
+		bc.dsign = delta->sign;
+		delta->sign = 0;
+		i = cmp(delta, bs);
+#ifndef NO_STRTOD_BIGCOMP
+		if (bc.nd > nd && i <= 0) {
+			if (bc.dsign)
+				break;	/* Must use bigcomp(). */
+#ifdef Honor_FLT_ROUNDS
+			if (bc.rounding != 1) {
+				if (i < 0)
+					break;
+				}
+			else
+#endif
+				{
+				bc.nd = nd;
+				i = -1;	/* Discarded digits make delta smaller. */
+				}
+			}
+#endif
+#ifdef Honor_FLT_ROUNDS
+		if (bc.rounding != 1) {
+			if (i < 0) {
+				/* Error is less than an ulp */
+				if (!delta->x[0] && delta->wds <= 1) {
+					/* exact */
+#ifdef SET_INEXACT
+					bc.inexact = 0;
+#endif
+					break;
+					}
+				if (bc.rounding) {
+					if (bc.dsign) {
+						adj.d = 1.;
+						goto apply_adj;
+						}
+					}
+				else if (!bc.dsign) {
+					adj.d = -1.;
+					if (!word1(&rv)
+					 && !(word0(&rv) & Frac_mask)) {
+						y = word0(&rv) & Exp_mask;
+#ifdef Avoid_Underflow
+						if (!bc.scale || y > 2*P*Exp_msk1)
+#else
+						if (y)
+#endif
+						  {
+						  delta = lshift(delta,Log2P);
+						  if (cmp(delta, bs) <= 0)
+							adj.d = -0.5;
+						  }
+						}
+ apply_adj:
+#ifdef Avoid_Underflow
+					if (bc.scale && (y = word0(&rv) & Exp_mask)
+						<= 2*P*Exp_msk1)
+					  word0(&adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+					if ((word0(&rv) & Exp_mask) <=
+							P*Exp_msk1) {
+						word0(&rv) += P*Exp_msk1;
+						dval(&rv) += adj.d*ulp(dval(&rv));
+						word0(&rv) -= P*Exp_msk1;
+						}
+					else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+					dval(&rv) += adj.d*ulp(&rv);
+					}
+				break;
+				}
+			adj.d = ratio(delta, bs);
+			if (adj.d < 1.)
+				adj.d = 1.;
+			if (adj.d <= 0x7ffffffe) {
+				/* adj = rounding ? ceil(adj) : floor(adj); */
+				y = adj.d;
+				if (y != adj.d) {
+					if (!((bc.rounding>>1) ^ bc.dsign))
+						y++;
+					adj.d = y;
+					}
+				}
+#ifdef Avoid_Underflow
+			if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+				word0(&adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+				word0(&rv) += P*Exp_msk1;
+				adj.d *= ulp(dval(&rv));
+				if (bc.dsign)
+					dval(&rv) += adj.d;
+				else
+					dval(&rv) -= adj.d;
+				word0(&rv) -= P*Exp_msk1;
+				goto cont;
+				}
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			adj.d *= ulp(&rv);
+			if (bc.dsign) {
+				if (word0(&rv) == Big0 && word1(&rv) == Big1)
+					goto ovfl;
+				dval(&rv) += adj.d;
+				}
+			else
+				dval(&rv) -= adj.d;
+			goto cont;
+			}
+#endif /*Honor_FLT_ROUNDS*/
+
+		if (i < 0) {
+			/* Error is less than half an ulp -- check for
+			 * special case of mantissa a power of two.
+			 */
+			if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+			 || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+			 || (word0(&rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+				) {
+#ifdef SET_INEXACT
+				if (!delta->x[0] && delta->wds <= 1)
+					bc.inexact = 0;
+#endif
+				break;
+				}
+			if (!delta->x[0] && delta->wds <= 1) {
+				/* exact result */
+#ifdef SET_INEXACT
+				bc.inexact = 0;
+#endif
+				break;
+				}
+			delta = lshift(delta,Log2P);
+			if (cmp(delta, bs) > 0)
+				goto drop_down;
+			break;
+			}
+		if (i == 0) {
+			/* exactly half-way between */
+			if (bc.dsign) {
+				if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
+				 &&  word1(&rv) == (
+#ifdef Avoid_Underflow
+			(bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+		? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+						   0xffffffff)) {
+					/*boundary case -- increment exponent*/
+					word0(&rv) = (word0(&rv) & Exp_mask)
+						+ Exp_msk1
+#ifdef IBM
+						| Exp_msk1 >> 4
+#endif
+						;
+					word1(&rv) = 0;
+#ifdef Avoid_Underflow
+					bc.dsign = 0;
+#endif
+					break;
+					}
+				}
+			else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
+ drop_down:
+				/* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+				L = word0(&rv) & Exp_mask;
+#ifdef IBM
+				if (L <  Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+				if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+				if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+					{
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+				L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+				if (bc.scale) {
+					L = word0(&rv) & Exp_mask;
+					if (L <= (2*P+1)*Exp_msk1) {
+						if (L > (P+2)*Exp_msk1)
+							/* round even ==> */
+							/* accept rv */
+							break;
+						/* rv = smallest denormal */
+						if (bc.nd >nd) {
+							bc.uflchk = 1;
+							break;
+							}
+						goto undfl;
+						}
+					}
+#endif /*Avoid_Underflow*/
+				L = (word0(&rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+				word0(&rv) = L | Bndry_mask1;
+				word1(&rv) = 0xffffffff;
+#ifdef IBM
+				goto cont;
+#else
+				break;
+#endif
+				}
+#ifndef ROUND_BIASED
+			if (!(word1(&rv) & LSB))
+				break;
+#endif
+			if (bc.dsign)
+				dval(&rv) += ulp(&rv);
+#ifndef ROUND_BIASED
+			else {
+				dval(&rv) -= ulp(&rv);
+#ifndef Sudden_Underflow
+				if (!dval(&rv)) {
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+#endif
+				}
+#ifdef Avoid_Underflow
+			bc.dsign = 1 - bc.dsign;
+#endif
+#endif
+			break;
+			}
+		if ((aadj = ratio(delta, bs)) <= 2.) {
+			if (bc.dsign)
+				aadj = aadj1 = 1.;
+			else if (word1(&rv) || word0(&rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+				if (word1(&rv) == Tiny1 && !word0(&rv)) {
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+#endif
+				aadj = 1.;
+				aadj1 = -1.;
+				}
+			else {
+				/* special case -- power of FLT_RADIX to be */
+				/* rounded down... */
+
+				if (aadj < 2./FLT_RADIX)
+					aadj = 1./FLT_RADIX;
+				else
+					aadj *= 0.5;
+				aadj1 = -aadj;
+				}
+			}
+		else {
+			aadj *= 0.5;
+			aadj1 = bc.dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+			switch(bc.rounding) {
+				case 2: /* towards +infinity */
+					aadj1 -= 0.5;
+					break;
+				case 0: /* towards 0 */
+				case 3: /* towards -infinity */
+					aadj1 += 0.5;
+				}
+#else
+			if (Flt_Rounds == 0)
+				aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+			}
+		y = word0(&rv) & Exp_mask;
+
+		/* Check for overflow */
+
+		if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+			dval(&rv0) = dval(&rv);
+			word0(&rv) -= P*Exp_msk1;
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+			if ((word0(&rv) & Exp_mask) >=
+					Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+				if (word0(&rv0) == Big0 && word1(&rv0) == Big1)
+					goto ovfl;
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+				goto cont;
+				}
+			else
+				word0(&rv) += P*Exp_msk1;
+			}
+		else {
+#ifdef Avoid_Underflow
+			if (bc.scale && y <= 2*P*Exp_msk1) {
+				if (aadj <= 0x7fffffff) {
+					if ((z = (ULong)aadj) <= 0)
+						z = 1;
+					aadj = z;
+					aadj1 = bc.dsign ? aadj : -aadj;
+					}
+				dval(&aadj2) = aadj1;
+				word0(&aadj2) += (2*P+1)*Exp_msk1 - y;
+				aadj1 = dval(&aadj2);
+				}
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+				dval(&rv0) = dval(&rv);
+				word0(&rv) += P*Exp_msk1;
+				adj.d = aadj1 * ulp(&rv);
+				dval(&rv) += adj.d;
+#ifdef IBM
+				if ((word0(&rv) & Exp_mask) <  P*Exp_msk1)
+#else
+				if ((word0(&rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+					{
+					if (word0(&rv0) == Tiny0
+					 && word1(&rv0) == Tiny1) {
+						if (bc.nd >nd) {
+							bc.uflchk = 1;
+							break;
+							}
+						goto undfl;
+						}
+					word0(&rv) = Tiny0;
+					word1(&rv) = Tiny1;
+					goto cont;
+					}
+				else
+					word0(&rv) -= P*Exp_msk1;
+				}
+			else {
+				adj.d = aadj1 * ulp(&rv);
+				dval(&rv) += adj.d;
+				}
+#else /*Sudden_Underflow*/
+			/* Compute adj so that the IEEE rounding rules will
+			 * correctly round rv + adj in some half-way cases.
+			 * If rv * ulp(rv) is denormalized (i.e.,
+			 * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+			 * trouble from bits lost to denormalization;
+			 * example: 1.2e-307 .
+			 */
+			if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+				aadj1 = (double)(int)(aadj + 0.5);
+				if (!bc.dsign)
+					aadj1 = -aadj1;
+				}
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			}
+		z = word0(&rv) & Exp_mask;
+#ifndef SET_INEXACT
+		if (bc.nd == nd) {
+#ifdef Avoid_Underflow
+		if (!bc.scale)
+#endif
+		if (y == z) {
+			/* Can we stop now? */
+			L = (Long)aadj;
+			aadj -= L;
+			/* The tolerances below are conservative. */
+			if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
+				if (aadj < .4999999 || aadj > .5000001)
+					break;
+				}
+			else if (aadj < .4999999/FLT_RADIX)
+				break;
+			}
+		}
+#endif
+ cont:
+		Bfree(bb);
+		Bfree(bd);
+		Bfree(bs);
+		Bfree(delta);
+		}
+	Bfree(bb);
+	Bfree(bd);
+	Bfree(bs);
+	Bfree(bd0);
+	Bfree(delta);
+#ifndef NO_STRTOD_BIGCOMP
+	if (bc.nd > nd)
+		bigcomp(&rv, s0, &bc);
+#endif
+#ifdef SET_INEXACT
+	if (bc.inexact) {
+		if (!oldinexact) {
+			word0(&rv0) = Exp_1 + (70 << Exp_shift);
+			word1(&rv0) = 0;
+			dval(&rv0) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+	if (bc.scale) {
+		word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
+		word1(&rv0) = 0;
+		dval(&rv) *= dval(&rv0);
+#ifndef NO_ERRNO
+		/* try to avoid the bug of testing an 8087 register value */
+#ifdef IEEE_Arith
+		if (!(word0(&rv) & Exp_mask))
+#else
+		if (word0(&rv) == 0 && word1(&rv) == 0)
+#endif
+			errno = ERANGE;
+#endif
+		}
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+	if (bc.inexact && !(word0(&rv) & Exp_mask)) {
+		/* set underflow bit */
+		dval(&rv0) = 1e-300;
+		dval(&rv0) *= dval(&rv0);
+		}
+#endif
+ ret:
+	if (se)
+		*se = (char *)s;
+	return sign ? -dval(&rv) : dval(&rv);
+	}
+
+#ifndef MULTIPLE_THREADS
+ static char *dtoa_result;
+#endif
+
+ static char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ static char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(CONST char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	for(*t = *s++; *t; *t = *s++) t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+dtoa
+#ifdef KR_headers
+	(dd, mode, ndigits, decpt, sign, rve)
+	double dd; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+	U d2, eps, u;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+
+	u.d = dd;
+	if (word0(&u) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&u) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&u) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&u)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&u) && !(word0(&u) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&u) += 0; /* normalize */
+#endif
+	if (!dval(&u)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(&u, &be, &bbits);
+	i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#ifndef Sudden_Underflow
+	if (i) {
+#endif
+		dval(&d2) = dval(&u);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (j = 11 - hi0bits(word0(&d2) & Frac_mask))
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+		 *
+		 * This suggests computing an approximation k to log10(d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&u) << (64 - i) | word1(&u) >> (i - 32)
+			    : word1(&u) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&u) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&u);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&u) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&u) /= ds;
+			}
+		else {
+			j1 = -k;
+			if (j1) {
+				dval(&u) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(&u) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(&u) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&u) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&u) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&u) -= 5.;
+			if (dval(&u) > dval(&eps))
+				goto one_digit;
+			if (dval(&u) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = (long)dval(&u);
+				dval(&u) -= L;
+				*s++ = '0' + (char)L;
+				if (dval(&u) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&u) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&u) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&u) *= 10.) {
+				L = (Long)(dval(&u));
+				if (!(dval(&u) -= L))
+					ilim = i;
+				*s++ = '0' + (char)L;
+				if (i == ilim) {
+					if (dval(&u) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&u) < 0.5 - dval(&eps)) {
+						while(*--s == '0') {}
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&u) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&u) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
+			L = (Long)(dval(&u) / ds);
+			dval(&u) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&u) < 0) {
+				L--;
+				dval(&u) += ds;
+				}
+#endif
+			*s++ = '0' + (char)L;
+			if (!dval(&u)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&u) += dval(&u);
+				if (dval(&u) > ds || (dval(&u) == ds && L & 1)) {
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				b1 = mult(mhi, b);
+				Bfree(b);
+				b = b1;
+				}
+			j = b5 - m5;
+			if (j)
+				b = pow5mult(b, j);
+			}
+		else
+			b = pow5mult(b, b5);
+		}
+	S = i2b(1);
+	if (s5 > 0)
+		S = pow5mult(S, s5);
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&u) && !(word0(&u) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&u) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f;
+	if (i)
+		i = 32 - i;
+#define iInc 28
+#else
+	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+		i = 16 - i;
+#define iInc 12
+#endif
+	i = dshift(S, s2);
+	b2 += i;
+	m2 += i;
+	s2 += i;
+	if (b2 > 0)
+		b = lshift(b, b2);
+	if (s2 > 0)
+		S = lshift(S, s2);
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (leftright)
+				mhi = multadd(mhi, 10, 0);
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0)
+			mhi = lshift(mhi, m2);
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&u) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = (char)dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&u) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					j1 = cmp(b, S);
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = (char)dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = (char)dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = (char)dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (mlo == mhi)
+				mlo = mhi = multadd(mhi, 10, 0);
+			else {
+				mlo = multadd(mlo, 10, 0);
+				mhi = multadd(mhi, 10, 0);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			dig = quorem(b,S) + '0';
+			*s++ = (char)dig;
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	j = cmp(b, S);
+	if (j > 0 || (j == 0 && dig & 1)) {
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0') {}
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&u) = Exp_1 + (70 << Exp_shift);
+			word1(&u) = 0;
+			dval(&u) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+	}
+
+}  // namespace dmg_fp
diff --git a/base/third_party/dmg_fp/dtoa_wrapper.cc b/base/third_party/dmg_fp/dtoa_wrapper.cc
new file mode 100644
index 0000000..c314c59
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa_wrapper.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The purpose of this file is to supply the macro definintions necessary
+// to make third_party/dmg_fp/dtoa.cc threadsafe.
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+// We need two locks because they're sometimes grabbed at the same time.
+// A single lock would lead to an attempted recursive grab.
+static base::LazyInstance<base::Lock>::Leaky
+    dtoa_lock_0 = LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<base::Lock>::Leaky
+    dtoa_lock_1 = LAZY_INSTANCE_INITIALIZER;
+
+/*
+ * This define and the code below is to trigger thread-safe behavior
+ * in dtoa.cc, per this comment from the file:
+ *
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ */
+#define MULTIPLE_THREADS
+
+inline static void ACQUIRE_DTOA_LOCK(size_t n) {
+  DCHECK(n < 2);
+  base::Lock* lock = n == 0 ? dtoa_lock_0.Pointer() : dtoa_lock_1.Pointer();
+  lock->Acquire();
+}
+
+inline static void FREE_DTOA_LOCK(size_t n) {
+  DCHECK(n < 2);
+  base::Lock* lock = n == 0 ? dtoa_lock_0.Pointer() : dtoa_lock_1.Pointer();
+  lock->Release();
+}
+
+#include "base/third_party/dmg_fp/dtoa.cc"
diff --git a/base/third_party/dmg_fp/float_precision_crash.patch b/base/third_party/dmg_fp/float_precision_crash.patch
new file mode 100644
index 0000000..df64e7e
--- /dev/null
+++ b/base/third_party/dmg_fp/float_precision_crash.patch
@@ -0,0 +1,13 @@
+diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
+index 3f7e794..3312fa4 100644
+--- dtoa.cc
++++ dtoa.cc
+@@ -3891,7 +3891,7 @@ dtoa
+ 				goto no_digits;
+ 			goto one_digit;
+ 			}
+-		for(i = 1;; i++, dval(&u) *= 10.) {
++		for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
+ 			L = (Long)(dval(&u) / ds);
+ 			dval(&u) -= L*ds;
+ #ifdef Check_FLT_ROUNDS
diff --git a/base/third_party/dmg_fp/g_fmt.cc b/base/third_party/dmg_fp/g_fmt.cc
new file mode 100644
index 0000000..bfa358d
--- /dev/null
+++ b/base/third_party/dmg_fp/g_fmt.cc
@@ -0,0 +1,102 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 1996 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
+ * it suffices to declare buf
+ *	char buf[32];
+ */
+
+#include "dmg_fp.h"
+
+namespace dmg_fp {
+
+ char *
+g_fmt(register char *b, double x)
+{
+	register int i, k;
+	register char *s;
+	int decpt, j, sign;
+	char *b0, *s0, *se;
+
+	b0 = b;
+#ifdef IGNORE_ZERO_SIGN
+	if (!x) {
+		*b++ = '0';
+		*b = 0;
+		goto done;
+		}
+#endif
+	s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
+	if (sign)
+		*b++ = '-';
+	if (decpt == 9999) /* Infinity or Nan */ {
+		for(*b = *s++; *b++; *b = *s++) {}
+		goto done0;
+		}
+	if (decpt <= -4 || decpt > se - s + 5) {
+		*b++ = *s++;
+		if (*s) {
+			*b++ = '.';
+			for(*b = *s++; *b; *b = *s++)
+				b++;
+			}
+		*b++ = 'e';
+		/* sprintf(b, "%+.2d", decpt - 1); */
+		if (--decpt < 0) {
+			*b++ = '-';
+			decpt = -decpt;
+			}
+		else
+			*b++ = '+';
+		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+		for(;;) {
+			i = decpt / k;
+			*b++ = (char)i + '0';
+			if (--j <= 0)
+				break;
+			decpt -= i*k;
+			decpt *= 10;
+			}
+		*b = 0;
+		}
+	else if (decpt <= 0) {
+		*b++ = '.';
+		for(; decpt < 0; decpt++)
+			*b++ = '0';
+		for(*b = *s++; *b++; *b = *s++) {}
+		}
+	else {
+		for(*b = *s++; *b; *b = *s++) {
+			b++;
+			if (--decpt == 0 && *s)
+				*b++ = '.';
+			}
+		for(; decpt > 0; decpt--)
+			*b++ = '0';
+		*b = 0;
+		}
+ done0:
+	freedtoa(s0);
+#ifdef IGNORE_ZERO_SIGN
+ done:
+#endif
+	return b0;
+	}
+
+}  // namespace dmg_fp
diff --git a/base/third_party/dmg_fp/gcc_64_bit.patch b/base/third_party/dmg_fp/gcc_64_bit.patch
new file mode 100644
index 0000000..ab943c0
--- /dev/null
+++ b/base/third_party/dmg_fp/gcc_64_bit.patch
@@ -0,0 +1,25 @@
+Index: dtoa.cc
+--- dtoa.cc    (old copy)
++++ dtoa.cc    (working copy)
+@@ -183,8 +183,12 @@
+ #define NO_HEX_FP
+ 
+ #ifndef Long
++#if __LP64__
++#define Long int
++#else
+ #define Long long
+ #endif
++#endif
+ #ifndef ULong
+ typedef unsigned Long ULong;
+ #endif
+@@ -221,7 +225,7 @@ extern void *MALLOC(size_t);
+ #ifndef PRIVATE_MEM
+ #define PRIVATE_MEM 2304
+ #endif
+-#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
++#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)))
+ static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+ #endif
+ 
diff --git a/base/third_party/dmg_fp/gcc_warnings.patch b/base/third_party/dmg_fp/gcc_warnings.patch
new file mode 100644
index 0000000..4262237
--- /dev/null
+++ b/base/third_party/dmg_fp/gcc_warnings.patch
@@ -0,0 +1,126 @@
+Index: dtoa.cc
+--- dtoa.cc    (old copy)
++++ dtoa.cc    (working copy)
+@@ -179,6 +179,9 @@
+  *	used for input more than STRTOD_DIGLIM digits long (default 40).
+  */
+ 
++#define IEEE_8087
++#define NO_HEX_FP
++
+ #ifndef Long
+ #define Long long
+ #endif
+@@ -280,9 +283,7 @@
+ #include "math.h"
+ #endif
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
++namespace dmg_fp {
+ 
+ #ifndef CONST
+ #ifdef KR_headers
+@@ -511,11 +512,9 @@
+ 
+ #define Kmax 7
+ 
+-#ifdef __cplusplus
+-extern "C" double strtod(const char *s00, char **se);
+-extern "C" char *dtoa(double d, int mode, int ndigits,
++double strtod(const char *s00, char **se);
++char *dtoa(double d, int mode, int ndigits,
+ 			int *decpt, int *sign, char **rve);
+-#endif
+ 
+  struct
+ Bigint {
+@@ -1527,7 +1526,7 @@
+ #ifdef KR_headers
+ 	(sp, t) char **sp, *t;
+ #else
+-	(CONST char **sp, char *t)
++	(CONST char **sp, CONST char *t)
+ #endif
+ {
+ 	int c, d;
+@@ -2234,7 +2234,7 @@ bigcomp
+ 	nd = bc->nd;
+ 	nd0 = bc->nd0;
+ 	p5 = nd + bc->e0 - 1;
+-	speccase = 0;
++	dd = speccase = 0;
+ #ifndef Sudden_Underflow
+ 	if (rv->d == 0.) {	/* special case: value near underflow-to-zero */
+ 				/* threshold was rounded to zero */
+@@ -3431,7 +3430,7 @@
+ 
+ 	j = sizeof(ULong);
+ 	for(k = 0;
+-		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
++		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i;
+ 		j <<= 1)
+ 			k++;
+ 	r = (int*)Balloc(k);
+@@ -3447,7 +3446,7 @@
+ #ifdef KR_headers
+ nrv_alloc(s, rve, n) char *s, **rve; int n;
+ #else
+-nrv_alloc(char *s, char **rve, int n)
++nrv_alloc(CONST char *s, char **rve, int n)
+ #endif
+ {
+ 	char *rv, *t;
+@@ -4202,6 +4201,5 @@
+ 		*rve = s;
+ 	return s0;
+ 	}
+-#ifdef __cplusplus
+-}
+-#endif
++
++}  // namespace dmg_fp
+Index: g_fmt.cc
+--- g_fmt.cc   (old copy)
++++ g_fmt.cc   (new copy)
+@@ -46,14 +46,14 @@ g_fmt(register char *b, double x)
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while(*b++ = *s++);
++		while((*b++ = *s++));
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+ 		*b++ = *s++;
+ 		if (*s) {
+ 			*b++ = '.';
+-			while(*b = *s++)
++			while((*b = *s++))
+ 				b++;
+ 			}
+ 		*b++ = 'e';
+@@ -79,10 +79,10 @@ g_fmt(register char *b, double x)
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while(*b++ = *s++);
++		while((*b++ = *s++));
+ 		}
+ 	else {
+-		while(*b = *s++) {
++		while((*b = *s++)) {
+ 			b++;
+ 			if (--decpt == 0 && *s)
+ 				*b++ = '.';
+@@ -93,7 +93,9 @@ g_fmt(register char *b, double x)
+ 		}
+  done0:
+ 	freedtoa(s0);
++#ifdef IGNORE_ZERO_SIGN
+  done:
++#endif
+ 	return b0;
+ 	}
+ 
diff --git a/base/third_party/dmg_fp/mac_wextra.patch b/base/third_party/dmg_fp/mac_wextra.patch
new file mode 100644
index 0000000..15340f2
--- /dev/null
+++ b/base/third_party/dmg_fp/mac_wextra.patch
@@ -0,0 +1,53 @@
+Index: g_fmt.cc
+===================================================================
+--- g_fmt.cc	(revision 49784)
++++ g_fmt.cc	(working copy)
+@@ -46,7 +46,7 @@
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while((*b++ = *s++));
++		while((*b++ = *s++)) {}
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+@@ -64,7 +64,7 @@
+ 			}
+ 		else
+ 			*b++ = '+';
+-		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
++		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+ 		for(;;) {
+ 			i = decpt / k;
+ 			*b++ = i + '0';
+@@ -79,7 +79,7 @@
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while((*b++ = *s++));
++		while((*b++ = *s++)) {}
+ 		}
+ 	else {
+ 		while((*b = *s++)) {
+Index: dtoa.cc
+===================================================================
+--- dtoa.cc	(revision 49784)
++++ dtoa.cc	(working copy)
+@@ -3863,7 +3863,7 @@
+ 					if (dval(&u) > 0.5 + dval(&eps))
+ 						goto bump_up;
+ 					else if (dval(&u) < 0.5 - dval(&eps)) {
+-						while(*--s == '0');
++						while(*--s == '0') {}
+ 						s++;
+ 						goto ret1;
+ 						}
+@@ -4176,7 +4176,7 @@
+ #ifdef Honor_FLT_ROUNDS
+  trimzeros:
+ #endif
+-		while(*--s == '0');
++		while(*--s == '0') {}
+ 		s++;
+ 		}
+  ret:
diff --git a/base/third_party/dmg_fp/msvc_warnings.patch b/base/third_party/dmg_fp/msvc_warnings.patch
new file mode 100644
index 0000000..22e89cd
--- /dev/null
+++ b/base/third_party/dmg_fp/msvc_warnings.patch
@@ -0,0 +1,419 @@
+diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
+index 3312fa4..502c16c 100644
+--- a/base/third_party/dmg_fp/dtoa.cc
++++ b/base/third_party/dmg_fp/dtoa.cc
+@@ -548,8 +548,10 @@ Balloc
+ 	ACQUIRE_DTOA_LOCK(0);
+ 	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+ 	/* but this case seems very unlikely. */
+-	if (k <= Kmax && (rv = freelist[k]))
++	if (k <= Kmax && freelist[k]) {
++		rv = freelist[k];
+ 		freelist[k] = rv->next;
++		}
+ 	else {
+ 		x = 1 << k;
+ #ifdef Omit_Private_Memory
+@@ -650,7 +652,7 @@ multadd
+ 			Bfree(b);
+ 			b = b1;
+ 			}
+-		b->x[wds++] = carry;
++		b->x[wds++] = (ULong)carry;
+ 		b->wds = wds;
+ 		}
+ 	return b;
+@@ -834,7 +836,8 @@ mult
+ 	xc0 = c->x;
+ #ifdef ULLong
+ 	for(; xb < xbe; xc0++) {
+-		if ((y = *xb++)) {
++		y = *xb++;
++		if (y) {
+ 			x = xa;
+ 			xc = xc0;
+ 			carry = 0;
+@@ -844,7 +847,7 @@ mult
+ 				*xc++ = z & FFFFFFFF;
+ 				}
+ 				while(x < xae);
+-			*xc = carry;
++			*xc = (ULong)carry;
+ 			}
+ 		}
+ #else
+@@ -916,16 +919,19 @@ pow5mult
+ 	int i;
+ 	static int p05[3] = { 5, 25, 125 };
+ 
+-	if ((i = k & 3))
++	i = k & 3;
++	if (i)
+ 		b = multadd(b, p05[i-1], 0);
+ 
+ 	if (!(k >>= 2))
+ 		return b;
+-	if (!(p5 = p5s)) {
++	p5 = p5s;
++	if (!p5) {
+ 		/* first time */
+ #ifdef MULTIPLE_THREADS
+ 		ACQUIRE_DTOA_LOCK(1);
+-		if (!(p5 = p5s)) {
++		p5 = p5s;
++		if (!p5) {
+ 			p5 = p5s = i2b(625);
+ 			p5->next = 0;
+ 			}
+@@ -943,10 +949,12 @@ pow5mult
+ 			}
+ 		if (!(k >>= 1))
+ 			break;
+-		if (!(p51 = p5->next)) {
++		p51 = p5->next;
++		if (!p51) {
+ #ifdef MULTIPLE_THREADS
+ 			ACQUIRE_DTOA_LOCK(1);
+-			if (!(p51 = p5->next)) {
++			p51 = p5->next;
++			if (!p51) {
+ 				p51 = p5->next = mult(p5,p5);
+ 				p51->next = 0;
+ 				}
+@@ -997,7 +1005,8 @@ lshift
+ 			z = *x++ >> k1;
+ 			}
+ 			while(x < xe);
+-		if ((*x1 = z))
++		*x1 = z;
++		if (*x1)
+ 			++n1;
+ 		}
+ #else
+@@ -1299,21 +1308,25 @@ d2b
+ 	z |= Exp_msk11;
+ #endif
+ #else
+-	if ((de = (int)(d0 >> Exp_shift)))
++	de = (int)(d0 >> Exp_shift);
++	if (de)
+ 		z |= Exp_msk1;
+ #endif
+ #ifdef Pack_32
+-	if ((y = d1)) {
+-		if ((k = lo0bits(&y))) {
++	y = d1;
++	if (y) {
++		k = lo0bits(&y);
++		if (k) {
+ 			x[0] = y | z << (32 - k);
+ 			z >>= k;
+ 			}
+ 		else
+ 			x[0] = y;
++		x[1] = z;
++		b->wds = x[1] ? 2 : 1;
+ #ifndef Sudden_Underflow
+-		i =
++		i = b->wds;
+ #endif
+-		    b->wds = (x[1] = z) ? 2 : 1;
+ 		}
+ 	else {
+ 		k = lo0bits(&z);
+@@ -1498,7 +1511,7 @@ htinit(unsigned char *h, unsigned char *s, int inc)
+ {
+ 	int i, j;
+ 	for(i = 0; (j = s[i]) !=0; i++)
+-		h[j] = i + inc;
++		h[j] = (unsigned char)(i + inc);
+ 	}
+ 
+  static void
+@@ -1536,7 +1549,7 @@ match
+ 	int c, d;
+ 	CONST char *s = *sp;
+ 
+-	while((d = *t++)) {
++	for(d = *t++; d; d = *t++) {
+ 		if ((c = *++s) >= 'A' && c <= 'Z')
+ 			c += 'a' - 'A';
+ 		if (c != d)
+@@ -1566,12 +1579,13 @@ hexnan
+ 	udx0 = 1;
+ 	s = *sp;
+ 	/* allow optional initial 0x or 0X */
+-	while((c = *(CONST unsigned char*)(s+1)) && c <= ' ')
++	for(c = *(CONST unsigned char*)(s+1); c && c <= ' '; c = *(CONST unsigned char*)(s+1))
+ 		++s;
+ 	if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
+ 		s += 2;
+-	while((c = *(CONST unsigned char*)++s)) {
+-		if ((c1 = hexdig[c]))
++	for(c = *(CONST unsigned char*)++s; c; c = *(CONST unsigned char*)++s) {
++		c1 = hexdig[c];
++		if (c1)
+ 			c  = c1 & 0xf;
+ 		else if (c <= ' ') {
+ 			if (udx0 && havedig) {
+@@ -1594,7 +1608,8 @@ hexnan
+ 					*sp = s + 1;
+ 					break;
+ 					}
+-				} while((c = *++s));
++				c = *++s;
++				} while(c);
+ 			break;
+ 			}
+ #endif
+@@ -2328,7 +2343,8 @@ bigcomp
+ 	/* Now b/d = exactly half-way between the two floating-point values */
+ 	/* on either side of the input string.  Compute first digit of b/d. */
+ 
+-	if (!(dig = quorem(b,d))) {
++	dig = quorem(b,d);
++	if (!dig) {
+ 		b = multadd(b, 10, 0);	/* very unlikely */
+ 		dig = quorem(b,d);
+ 		}
+@@ -2336,7 +2352,8 @@ bigcomp
+ 	/* Compare b/d with s0 */
+ 
+ 	for(i = 0; i < nd0; ) {
+-		if ((dd = s0[i++] - '0' - dig))
++		dd = s0[i++] - '0' - dig;
++		if (dd)
+ 			goto ret;
+ 		if (!b->x[0] && b->wds == 1) {
+ 			if (i < nd)
+@@ -2347,7 +2364,8 @@ bigcomp
+ 		dig = quorem(b,d);
+ 		}
+ 	for(j = bc->dp1; i++ < nd;) {
+-		if ((dd = s0[j++] - '0' - dig))
++		dd = s0[j++] - '0' - dig;
++		if (dd)
+ 			goto ret;
+ 		if (!b->x[0] && b->wds == 1) {
+ 			if (i < nd)
+@@ -2747,7 +2765,8 @@ strtod
+ 	/* Get starting approximation = rv * 10**e1 */
+ 
+ 	if (e1 > 0) {
+-		if ((i = e1 & 15))
++		i = e1 & 15;
++		if (i)
+ 			dval(&rv) *= tens[i];
+ 		if (e1 &= ~15) {
+ 			if (e1 > DBL_MAX_10_EXP) {
+@@ -2805,7 +2824,8 @@ strtod
+ 		}
+ 	else if (e1 < 0) {
+ 		e1 = -e1;
+-		if ((i = e1 & 15))
++		i = e1 & 15;
++		if (i)
+ 			dval(&rv) /= tens[i];
+ 		if (e1 >>= 4) {
+ 			if (e1 >= 1 << n_bigtens)
+@@ -3283,7 +3303,7 @@ strtod
+ #ifdef Avoid_Underflow
+ 			if (bc.scale && y <= 2*P*Exp_msk1) {
+ 				if (aadj <= 0x7fffffff) {
+-					if ((z = aadj) <= 0)
++					if ((z = (ULong)aadj) <= 0)
+ 						z = 1;
+ 					aadj = z;
+ 					aadj1 = bc.dsign ? aadj : -aadj;
+@@ -3456,7 +3476,7 @@ nrv_alloc(CONST char *s, char **rve, int n)
+ 	char *rv, *t;
+ 
+ 	t = rv = rv_alloc(n);
+-	while((*t = *s++)) t++;
++	for(*t = *s++; *t; *t = *s++) t++;
+ 	if (rve)
+ 		*rve = t;
+ 	return rv;
+@@ -3569,7 +3589,7 @@ dtoa
+ 	int denorm;
+ 	ULong x;
+ #endif
+-	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
++	Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+ 	U d2, eps, u;
+ 	double ds;
+ 	char *s, *s0;
+@@ -3645,10 +3665,9 @@ dtoa
+ #endif
+ 
+ 	b = d2b(&u, &be, &bbits);
+-#ifdef Sudden_Underflow
+ 	i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+-#else
+-	if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
++#ifndef Sudden_Underflow
++	if (i) {
+ #endif
+ 		dval(&d2) = dval(&u);
+ 		word0(&d2) &= Frac_mask1;
+@@ -3803,13 +3822,16 @@ dtoa
+ 					}
+ 			dval(&u) /= ds;
+ 			}
+-		else if ((j1 = -k)) {
+-			dval(&u) *= tens[j1 & 0xf];
+-			for(j = j1 >> 4; j; j >>= 1, i++)
+-				if (j & 1) {
+-					ieps++;
+-					dval(&u) *= bigtens[i];
+-					}
++		else {
++			j1 = -k;
++			if (j1) {
++				dval(&u) *= tens[j1 & 0xf];
++				for(j = j1 >> 4; j; j >>= 1, i++)
++					if (j & 1) {
++						ieps++;
++						dval(&u) *= bigtens[i];
++						}
++				}
+ 			}
+ 		if (k_check && dval(&u) < 1. && ilim > 0) {
+ 			if (ilim1 <= 0)
+@@ -3837,9 +3859,9 @@ dtoa
+ 			 */
+ 			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+ 			for(i = 0;;) {
+-				L = dval(&u);
++				L = (long)dval(&u);
+ 				dval(&u) -= L;
+-				*s++ = '0' + (int)L;
++				*s++ = '0' + (char)L;
+ 				if (dval(&u) < dval(&eps))
+ 					goto ret1;
+ 				if (1. - dval(&u) < dval(&eps))
+@@ -3858,7 +3880,7 @@ dtoa
+ 				L = (Long)(dval(&u));
+ 				if (!(dval(&u) -= L))
+ 					ilim = i;
+-				*s++ = '0' + (int)L;
++				*s++ = '0' + (char)L;
+ 				if (i == ilim) {
+ 					if (dval(&u) > 0.5 + dval(&eps))
+ 						goto bump_up;
+@@ -3901,7 +3923,7 @@ dtoa
+ 				dval(&u) += ds;
+ 				}
+ #endif
+-			*s++ = '0' + (int)L;
++			*s++ = '0' + (char)L;
+ 			if (!dval(&u)) {
+ #ifdef SET_INEXACT
+ 				inexact = 0;
+@@ -3964,7 +3986,8 @@ dtoa
+ 				Bfree(b);
+ 				b = b1;
+ 				}
+-			if ((j = b5 - m5))
++			j = b5 - m5;
++			if (j)
+ 				b = pow5mult(b, j);
+ 			}
+ 		else
+@@ -4002,7 +4025,8 @@ dtoa
+ 	 * can do shifts and ors to compute the numerator for q.
+ 	 */
+ #ifdef Pack_32
+-	if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f))
++	i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f;
++	if (i)
+ 		i = 32 - i;
+ #define iInc 28
+ #else
+@@ -4077,7 +4101,7 @@ dtoa
+ 				else if (!b->x[0] && b->wds <= 1)
+ 					inexact = 0;
+ #endif
+-				*s++ = dig;
++				*s++ = (char)dig;
+ 				goto ret;
+ 				}
+ #endif
+@@ -4107,7 +4131,7 @@ dtoa
+ 						goto round_9_up;
+ 					}
+  accept_dig:
+-				*s++ = dig;
++				*s++ = (char)dig;
+ 				goto ret;
+ 				}
+ 			if (j1 > 0) {
+@@ -4120,13 +4144,13 @@ dtoa
+ 					*s++ = '9';
+ 					goto roundoff;
+ 					}
+-				*s++ = dig + 1;
++				*s++ = (char)dig + 1;
+ 				goto ret;
+ 				}
+ #ifdef Honor_FLT_ROUNDS
+  keep_dig:
+ #endif
+-			*s++ = dig;
++			*s++ = (char)dig;
+ 			if (i == ilim)
+ 				break;
+ 			b = multadd(b, 10, 0);
+@@ -4140,7 +4164,8 @@ dtoa
+ 		}
+ 	else
+ 		for(i = 1;; i++) {
+-			*s++ = dig = quorem(b,S) + '0';
++			dig = quorem(b,S) + '0';
++			*s++ = (char)dig;
+ 			if (!b->x[0] && b->wds <= 1) {
+ #ifdef SET_INEXACT
+ 				inexact = 0;
+diff --git a/base/third_party/dmg_fp/g_fmt.cc b/base/third_party/dmg_fp/g_fmt.cc
+index d864eb7..bfa358d 100644
+--- a/base/third_party/dmg_fp/g_fmt.cc
++++ b/base/third_party/dmg_fp/g_fmt.cc
+@@ -46,14 +46,14 @@ g_fmt(register char *b, double x)
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while((*b++ = *s++)) {}
++		for(*b = *s++; *b++; *b = *s++) {}
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+ 		*b++ = *s++;
+ 		if (*s) {
+ 			*b++ = '.';
+-			while((*b = *s++))
++			for(*b = *s++; *b; *b = *s++)
+ 				b++;
+ 			}
+ 		*b++ = 'e';
+@@ -67,7 +67,7 @@ g_fmt(register char *b, double x)
+ 		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+ 		for(;;) {
+ 			i = decpt / k;
+-			*b++ = i + '0';
++			*b++ = (char)i + '0';
+ 			if (--j <= 0)
+ 				break;
+ 			decpt -= i*k;
+@@ -79,10 +79,10 @@ g_fmt(register char *b, double x)
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while((*b++ = *s++)) {}
++		for(*b = *s++; *b++; *b = *s++) {}
+ 		}
+ 	else {
+-		while((*b = *s++)) {
++		for(*b = *s++; *b; *b = *s++) {
+ 			b++;
+ 			if (--decpt == 0 && *s)
+ 				*b++ = '.';
diff --git a/base/third_party/dynamic_annotations/BUILD.gn b/base/third_party/dynamic_annotations/BUILD.gn
new file mode 100644
index 0000000..bc324ae
--- /dev/null
+++ b/base/third_party/dynamic_annotations/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_nacl) {
+  # Native client doesn't need dynamic annotations, so we provide a
+  # dummy target in order for clients to not have to special-case the
+  # dependency.
+  source_set("dynamic_annotations") {
+    sources = [
+      "dynamic_annotations.h",
+    ]
+  }
+} else {
+  source_set("dynamic_annotations") {
+    sources = [
+      "../valgrind/valgrind.h",
+      "dynamic_annotations.c",
+      "dynamic_annotations.h",
+    ]
+    if (is_android && !is_debug) {
+      configs -= [ "//build/config/compiler:optimize" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
+  }
+}
diff --git a/base/third_party/dynamic_annotations/LICENSE b/base/third_party/dynamic_annotations/LICENSE
new file mode 100644
index 0000000..5c581a9
--- /dev/null
+++ b/base/third_party/dynamic_annotations/LICENSE
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Kostya Serebryany
+ */
diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium
new file mode 100644
index 0000000..ff21b19
--- /dev/null
+++ b/base/third_party/dynamic_annotations/README.chromium
@@ -0,0 +1,20 @@
+Name: dynamic annotations
+URL: http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
+Version: 4384
+License: BSD
+
+ATTENTION: please avoid using these annotations in Chromium code.
+They were mainly intended to instruct the Valgrind-based version of
+ThreadSanitizer to handle atomic operations. The new version of ThreadSanitizer
+based on compiler instrumentation understands atomic operations out of the box,
+so normally you don't need the annotations.
+If you still think you do, please consider writing a comment at http://crbug.com/349861
+
+One header and one source file (dynamic_annotations.h and dynamic_annotations.c)
+in this directory define runtime macros useful for annotating synchronization
+utilities and benign data races so data race detectors can handle Chromium code
+with better precision.
+
+These files were taken from
+http://code.google.com/p/data-race-test/source/browse/?#svn/trunk/dynamic_annotations
+The files are covered under BSD license as described within the files.
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c
new file mode 100644
index 0000000..f57cb12
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.c
@@ -0,0 +1,269 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _MSC_VER
+# include <windows.h>
+#endif
+
+#ifdef __cplusplus
+# error "This file should be built as pure C to avoid name mangling"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#ifdef __GNUC__
+/* valgrind.h uses gcc extensions so it won't build with other compilers */
+# include "base/third_party/valgrind/valgrind.h"
+#endif
+
+/* Compiler-based ThreadSanitizer defines
+   DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
+   and provides its own definitions of the functions. */
+
+#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
+# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
+#endif
+
+/* Each function is empty and called (via a macro) only in debug mode.
+   The arguments are captured by dynamic tools at runtime. */
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1 \
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+
+/* Identical code folding(-Wl,--icf=all) countermeasures.
+   This makes all Annotate* functions different, which prevents the linker from
+   folding them. */
+#ifdef __COUNTER__
+#define DYNAMIC_ANNOTATIONS_IMPL \
+  volatile short lineno = (__LINE__ << 8) + __COUNTER__; (void)lineno;
+#else
+#define DYNAMIC_ANNOTATIONS_IMPL \
+  volatile short lineno = (__LINE__ << 8); (void)lineno;
+#endif
+
+/* WARNING: always add new annotations to the end of the list.
+   Otherwise, lineno (see above) numbers for different Annotate* functions may
+   conflict. */
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+    const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+    const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+    const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+    const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+    const char *file, int line, const volatile void *barrier, long count,
+    long reinitialization_allowed)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+    const char *file, int line, const volatile void *cv,
+    const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+    const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+    const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+    const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+    const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+    const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+    const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+    const char *file, int line, const volatile void *mem, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+    const char *file, int line, const volatile void *mem, long size,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+    const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+    const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+    const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+    const char *file, int line, const char *name)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+    const char *file, int line, int enable)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+    const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+#endif  /* DYNAMIC_ANNOTATIONS_ENABLED == 1
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 \
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+static int GetRunningOnValgrind(void) {
+#ifdef RUNNING_ON_VALGRIND
+  if (RUNNING_ON_VALGRIND) return 1;
+#endif
+
+#ifndef _MSC_VER
+  char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
+  if (running_on_valgrind_str) {
+    return strcmp(running_on_valgrind_str, "0") != 0;
+  }
+#else
+  /* Visual Studio issues warnings if we use getenv,
+   * so we use GetEnvironmentVariableA instead.
+   */
+  char value[100] = "1";
+  int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND",
+                                    value, sizeof(value));
+  /* value will remain "1" if res == 0 or res >= sizeof(value). The latter
+   * can happen only if the given value is long, in this case it can't be "0".
+   */
+  if (res > 0 && strcmp(value, "0") != 0)
+    return 1;
+#endif
+  return 0;
+}
+
+/* See the comments in dynamic_annotations.h */
+int RunningOnValgrind(void) {
+  static volatile int running_on_valgrind = -1;
+  /* C doesn't have thread-safe initialization of statics, and we
+     don't want to depend on pthread_once here, so hack it. */
+  int local_running_on_valgrind = running_on_valgrind;
+  if (local_running_on_valgrind == -1)
+    running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
+  return local_running_on_valgrind;
+}
+
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
new file mode 100644
index 0000000..8d2e9ec
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
@@ -0,0 +1,50 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'dynamic_annotations',
+      'type': 'static_library',
+      'toolsets': ['host', 'target'],
+      'include_dirs': [
+        '../../../',
+      ],
+      'sources': [
+        '../valgrind/valgrind.h',
+        'dynamic_annotations.c',
+        'dynamic_annotations.h',
+      ],
+      'includes': [
+        '../../../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS == "win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'dynamic_annotations_win64',
+          'type': 'static_library',
+          # We can't use dynamic_annotations target for win64 build since it is
+          # a 32-bit library.
+          # TODO(gregoryd): merge with dynamic_annotations when
+          # the win32/64 targets are merged.
+          'include_dirs': [
+              '../../../',
+          ],
+          'sources': [
+            'dynamic_annotations.c',
+            'dynamic_annotations.h',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.h b/base/third_party/dynamic_annotations/dynamic_annotations.h
new file mode 100644
index 0000000..8d7f052
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.h
@@ -0,0 +1,595 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file defines dynamic annotations for use with dynamic analysis
+   tool such as valgrind, PIN, etc.
+
+   Dynamic annotation is a source code annotation that affects
+   the generated code (that is, the annotation is not a comment).
+   Each such annotation is attached to a particular
+   instruction and/or to a particular object (address) in the program.
+
+   The annotations that should be used by users are macros in all upper-case
+   (e.g., ANNOTATE_NEW_MEMORY).
+
+   Actual implementation of these macros may differ depending on the
+   dynamic analysis tool being used.
+
+   See http://code.google.com/p/data-race-test/  for more information.
+
+   This file supports the following dynamic analysis tools:
+   - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero).
+      Macros are defined empty.
+   - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1).
+      Macros are defined as calls to non-inlinable empty functions
+      that are intercepted by Valgrind. */
+
+#ifndef __DYNAMIC_ANNOTATIONS_H__
+#define __DYNAMIC_ANNOTATIONS_H__
+
+#ifndef DYNAMIC_ANNOTATIONS_PREFIX
+# define DYNAMIC_ANNOTATIONS_PREFIX
+#endif
+
+#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND
+# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1
+#endif
+
+#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK
+# ifdef __GNUC__
+#  define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak))
+# else
+/* TODO(glider): for Windows support we may want to change this macro in order
+   to prepend __declspec(selectany) to the annotations' declarations. */
+#  error weak annotations are not supported for your compiler
+# endif
+#else
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK
+#endif
+
+/* The following preprocessor magic prepends the value of
+   DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */
+#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B
+#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B)
+#define DYNAMIC_ANNOTATIONS_NAME(name) \
+  DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name)
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+# define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing condition variables such as CondVar,
+     using conditional critical sections (Await/LockWhen) and when constructing
+     user-defined synchronization mechanisms.
+
+     The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can
+     be used to define happens-before arcs in user-defined synchronization
+     mechanisms:  the race detector will infer an arc from the former to the
+     latter when they share the same argument pointer.
+
+     Example 1 (reference counting):
+
+     void Unref() {
+       ANNOTATE_HAPPENS_BEFORE(&refcount_);
+       if (AtomicDecrementByOne(&refcount_) == 0) {
+         ANNOTATE_HAPPENS_AFTER(&refcount_);
+         delete this;
+       }
+     }
+
+     Example 2 (message queue):
+
+     void MyQueue::Put(Type *e) {
+       MutexLock lock(&mu_);
+       ANNOTATE_HAPPENS_BEFORE(e);
+       PutElementIntoMyQueue(e);
+     }
+
+     Type *MyQueue::Get() {
+       MutexLock lock(&mu_);
+       Type *e = GetElementFromMyQueue();
+       ANNOTATE_HAPPENS_AFTER(e);
+       return e;
+     }
+
+     Note: when possible, please use the existing reference counting and message
+     queue implementations instead of inventing new ones. */
+
+  /* Report that wait on the condition variable at address "cv" has succeeded
+     and the lock at address "lock" is held. */
+  #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock)
+
+  /* Report that wait on the condition variable at "cv" has succeeded.  Variant
+     w/o lock. */
+  #define ANNOTATE_CONDVAR_WAIT(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL)
+
+  /* Report that we are about to signal on the condition variable at address
+     "cv". */
+  #define ANNOTATE_CONDVAR_SIGNAL(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv)
+
+  /* Report that we are about to signal_all on the condition variable at address
+     "cv". */
+  #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv)
+
+  /* Annotations for user-defined synchronization mechanisms. */
+  #define ANNOTATE_HAPPENS_BEFORE(obj) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj)
+  #define ANNOTATE_HAPPENS_AFTER(obj) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \
+        pointer, size)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \
+        pointer, size)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size)   \
+    do {                                              \
+      ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \
+      ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size);   \
+    } while (0)
+
+  /* Instruct the tool to create a happens-before arc between mu->Unlock() and
+     mu->Lock(). This annotation may slow down the race detector and hide real
+     races. Normally it is used only when it would be difficult to annotate each
+     of the mutex's critical sections individually using the annotations above.
+     This annotation makes sense only for hybrid race detectors. For pure
+     happens-before detectors this is a no-op. For more details see
+     http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */
+  #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+        mu)
+
+  /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
+     Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in
+     pure happens-before mode. For a hybrid mode this is a no-op. */
+  #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu)
+
+  /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
+  #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+        mu)
+
+  /* -------------------------------------------------------------
+     Annotations useful when defining memory allocators, or when memory that
+     was protected in one way starts to be protected in another. */
+
+  /* Report that a new memory at "address" of size "size" has been allocated.
+     This might be used when the memory has been retrieved from a free list and
+     is about to be reused, or when a the locking discipline for a variable
+     changes. */
+  #define ANNOTATE_NEW_MEMORY(address, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \
+        size)
+
+  /* -------------------------------------------------------------
+     Annotations useful when defining FIFO queues that transfer data between
+     threads. */
+
+  /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at
+     address "pcq" has been created.  The ANNOTATE_PCQ_* annotations
+     should be used only for FIFO queues.  For non-FIFO queues use
+     ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */
+  #define ANNOTATE_PCQ_CREATE(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq)
+
+  /* Report that the queue at address "pcq" is about to be destroyed. */
+  #define ANNOTATE_PCQ_DESTROY(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq)
+
+  /* Report that we are about to put an element into a FIFO queue at address
+     "pcq". */
+  #define ANNOTATE_PCQ_PUT(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq)
+
+  /* Report that we've just got an element from a FIFO queue at address
+     "pcq". */
+  #define ANNOTATE_PCQ_GET(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq)
+
+  /* -------------------------------------------------------------
+     Annotations that suppress errors.  It is usually better to express the
+     program's synchronization using the other annotations, but these can
+     be used when all else fails. */
+
+  /* Report that we may have a benign race at "pointer", with size
+     "sizeof(*(pointer))". "pointer" must be a non-void* pointer.  Insert at the
+     point where "pointer" has been allocated, preferably close to the point
+     where the race happens.  See also ANNOTATE_BENIGN_RACE_STATIC. */
+  #define ANNOTATE_BENIGN_RACE(pointer, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+        pointer, sizeof(*(pointer)), description)
+
+  /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
+     the memory range [address, address+size). */
+  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+        address, size, description)
+
+  /* Request the analysis tool to ignore all reads in the current thread
+     until ANNOTATE_IGNORE_READS_END is called.
+     Useful to ignore intentional racey reads, while still checking
+     other reads and all writes.
+     See also ANNOTATE_UNPROTECTED_READ. */
+  #define ANNOTATE_IGNORE_READS_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring reads. */
+  #define ANNOTATE_IGNORE_READS_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
+  #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring writes. */
+  #define ANNOTATE_IGNORE_WRITES_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+  /* Start ignoring all memory accesses (reads and writes). */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+    do {\
+      ANNOTATE_IGNORE_READS_BEGIN();\
+      ANNOTATE_IGNORE_WRITES_BEGIN();\
+    }while(0)\
+
+  /* Stop ignoring all memory accesses. */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+    do {\
+      ANNOTATE_IGNORE_WRITES_END();\
+      ANNOTATE_IGNORE_READS_END();\
+    }while(0)\
+
+  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events:
+     RWLOCK* and CONDVAR*. */
+  #define ANNOTATE_IGNORE_SYNC_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring sync events. */
+  #define ANNOTATE_IGNORE_SYNC_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__)
+
+
+  /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
+     This annotation could be useful if you want to skip expensive race analysis
+     during some period of program execution, e.g. during initialization. */
+  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \
+        enable)
+
+  /* -------------------------------------------------------------
+     Annotations useful for debugging. */
+
+  /* Request to trace every access to "address". */
+  #define ANNOTATE_TRACE_MEMORY(address) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address)
+
+  /* Report the current thread name to a race detector. */
+  #define ANNOTATE_THREAD_NAME(name) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing locks.  They are not
+     normally needed by modules that merely use locks.
+     The "lock" argument is a pointer to the lock object. */
+
+  /* Report that a lock has been created at address "lock". */
+  #define ANNOTATE_RWLOCK_CREATE(lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" is about to be destroyed. */
+  #define ANNOTATE_RWLOCK_DESTROY(lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" has been acquired.
+     is_w=1 for writer lock, is_w=0 for reader lock. */
+  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \
+        is_w)
+
+  /* Report that the lock at address "lock" is about to be released. */
+  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \
+        is_w)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing barriers.  They are not
+     normally needed by modules that merely use barriers.
+     The "barrier" argument is a pointer to the barrier object. */
+
+  /* Report that the "barrier" has been initialized with initial "count".
+   If 'reinitialization_allowed' is true, initialization is allowed to happen
+   multiple times w/o calling barrier_destroy() */
+  #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \
+        count, reinitialization_allowed)
+
+  /* Report that we are about to enter barrier_wait("barrier"). */
+  #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \
+        barrier)
+
+  /* Report that we just exited barrier_wait("barrier"). */
+  #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \
+        barrier)
+
+  /* Report that the "barrier" has been destroyed. */
+  #define ANNOTATE_BARRIER_DESTROY(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \
+        barrier)
+
+  /* -------------------------------------------------------------
+     Annotations useful for testing race detectors. */
+
+  /* Report that we expect a race on the variable at "address".
+     Use only in unit tests for a race detector. */
+  #define ANNOTATE_EXPECT_RACE(address, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \
+        description)
+
+  #define ANNOTATE_FLUSH_EXPECTED_RACES() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__)
+
+  /* A no-op. Insert where you like to test the interceptors. */
+  #define ANNOTATE_NO_OP(arg) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg)
+
+  /* Force the race detector to flush its state. The actual effect depends on
+   * the implementation of the detector. */
+  #define ANNOTATE_FLUSH_STATE() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__)
+
+
+#else  /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+  #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+  #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */
+  #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */
+  #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */
+  #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */
+  #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */
+  #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */
+  #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */
+  #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */
+  #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */
+  #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */
+  #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */
+  #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size)  /* empty */
+  #define ANNOTATE_SWAP_MEMORY_RANGE(address, size)  /* empty */
+  #define ANNOTATE_PCQ_CREATE(pcq) /* empty */
+  #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */
+  #define ANNOTATE_PCQ_PUT(pcq) /* empty */
+  #define ANNOTATE_PCQ_GET(pcq) /* empty */
+  #define ANNOTATE_NEW_MEMORY(address, size) /* empty */
+  #define ANNOTATE_EXPECT_RACE(address, description) /* empty */
+  #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */
+  #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
+  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+  #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */
+  #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */
+  #define ANNOTATE_TRACE_MEMORY(arg) /* empty */
+  #define ANNOTATE_THREAD_NAME(name) /* empty */
+  #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_READS_END() /* empty */
+  #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_WRITES_END() /* empty */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
+  #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_SYNC_END() /* empty */
+  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+  #define ANNOTATE_NO_OP(arg) /* empty */
+  #define ANNOTATE_FLUSH_STATE() /* empty */
+
+#endif  /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* Use the macros above rather than using these functions directly. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+    const char *file, int line,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+    const char *file, int line,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+    const char *file, int line,
+    const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+    const char *file, int line,
+    const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+    const char *file, int line, const volatile void *barrier, long count,
+    long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+    const char *file, int line, const volatile void *cv,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+    const char *file, int line,
+    const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+    const char *file, int line,
+    const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+    const char *file, int line,
+    const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+    const char *file, int line,
+    const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+    const char *file, int line,
+    const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+    const char *file, int line,
+    const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+    const char *file, int line,
+    const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+    const char *file, int line, const volatile void *mem, long size,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+    const char *file, int line,
+    const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+    const char *file, int line,
+    const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+    const char *file, int line,
+    const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+    const char *file, int line,
+    const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+    const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+    const char *file, int line,
+    const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+/* Return non-zero value if running under valgrind.
+
+  If "valgrind.h" is included into dynamic_annotations.c,
+  the regular valgrind mechanism will be used.
+  See http://valgrind.org/docs/manual/manual-core-adv.html about
+  RUNNING_ON_VALGRIND and other valgrind "client requests".
+  The file "valgrind.h" may be obtained by doing
+     svn co svn://svn.valgrind.org/valgrind/trunk/include
+
+  If for some reason you can't use "valgrind.h" or want to fake valgrind,
+  there are two ways to make this function return non-zero:
+    - Use environment variable: export RUNNING_ON_VALGRIND=1
+    - Make your tool intercept the function RunningOnValgrind() and
+      change its return value.
+ */
+int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+
+  /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+     Instead of doing
+        ANNOTATE_IGNORE_READS_BEGIN();
+        ... = x;
+        ANNOTATE_IGNORE_READS_END();
+     one can use
+        ... = ANNOTATE_UNPROTECTED_READ(x); */
+  template <class T>
+  inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) {
+    ANNOTATE_IGNORE_READS_BEGIN();
+    T res = x;
+    ANNOTATE_IGNORE_READS_END();
+    return res;
+  }
+  /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)        \
+    namespace {                                                       \
+      class static_var ## _annotator {                                \
+       public:                                                        \
+        static_var ## _annotator() {                                  \
+          ANNOTATE_BENIGN_RACE_SIZED(&static_var,                     \
+                                      sizeof(static_var),             \
+            # static_var ": " description);                           \
+        }                                                             \
+      };                                                              \
+      static static_var ## _annotator the ## static_var ## _annotator;\
+    }
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ANNOTATE_UNPROTECTED_READ(x) (x)
+  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)  /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+#endif  /* __DYNAMIC_ANNOTATIONS_H__ */
diff --git a/base/third_party/icu/LICENSE b/base/third_party/icu/LICENSE
new file mode 100644
index 0000000..40282f4
--- /dev/null
+++ b/base/third_party/icu/LICENSE
@@ -0,0 +1,32 @@
+ICU License - ICU 1.8.1 and later
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2009 International Business Machines Corporation and others
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
diff --git a/base/third_party/icu/README.chromium b/base/third_party/icu/README.chromium
new file mode 100644
index 0000000..6a9a15a
--- /dev/null
+++ b/base/third_party/icu/README.chromium
@@ -0,0 +1,16 @@
+Name: ICU
+URL: http://site.icu-project.org/
+License: MIT
+License File: NOT_SHIPPED
+
+This file has the relevant components from ICU copied to handle basic
+UTF8/16/32 conversions. Components are copied from utf.h utf8.h utf16.h and
+utf_impl.c
+
+The same module appears in third_party/icu, so we don't repeat the license
+file here.
+
+The main change is that U_/U8_/U16_ prefixes have been replaced with
+CBU_/CBU8_/CBU16_ (for "Chrome Base") to avoid confusion with the "real" ICU
+macros should ICU be in use on the system. For the same reason, the functions
+and types have been put in the "base_icu" namespace.
diff --git a/base/third_party/icu/icu_utf.cc b/base/third_party/icu/icu_utf.cc
new file mode 100644
index 0000000..b47c8ac
--- /dev/null
+++ b/base/third_party/icu/icu_utf.cc
@@ -0,0 +1,228 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utf_impl.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep13
+*   created by: Markus W. Scherer
+*
+*   This file provides implementation functions for macros in the utfXX.h
+*   that would otherwise be too long as macros.
+*/
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base_icu {
+
+/**
+ * UTF8_ERROR_VALUE_1 and UTF8_ERROR_VALUE_2 are special error values for UTF-8,
+ * which need 1 or 2 bytes in UTF-8:
+ * \code
+ * U+0015 = NAK = Negative Acknowledge, C0 control character
+ * U+009f = highest C1 control character
+ * \endcode
+ *
+ * These are used by UTF8_..._SAFE macros so that they can return an error value
+ * that needs the same number of code units (bytes) as were seen by
+ * a macro. They should be tested with UTF_IS_ERROR() or UTF_IS_VALID().
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF8_ERROR_VALUE_1 0x15
+
+/**
+ * See documentation on UTF8_ERROR_VALUE_1 for details.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF8_ERROR_VALUE_2 0x9f
+
+
+/**
+ * Error value for all UTFs. This code point value will be set by macros with e>
+ * checking if an error is detected.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF_ERROR_VALUE 0xffff
+
+/*
+ * This table could be replaced on many machines by
+ * a few lines of assembler code using an
+ * "index of first 0-bit from msb" instruction and
+ * one or two more integer instructions.
+ *
+ * For example, on an i386, do something like
+ * - MOV AL, leadByte
+ * - NOT AL         (8-bit, leave b15..b8==0..0, reverse only b7..b0)
+ * - MOV AH, 0
+ * - BSR BX, AX     (16-bit)
+ * - MOV AX, 6      (result)
+ * - JZ finish      (ZF==1 if leadByte==0xff)
+ * - SUB AX, BX (result)
+ * -finish:
+ * (BSR: Bit Scan Reverse, scans for a 1-bit, starting from the MSB)
+ *
+ * In Unicode, all UTF-8 byte sequences with more than 4 bytes are illegal;
+ * lead bytes above 0xf4 are illegal.
+ * We keep them in this table for skipping long ISO 10646-UTF-8 sequences.
+ */
+const uint8
+utf8_countTrailBytes[256]={
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3,
+    3, 3, 3,    /* illegal in Unicode */
+    4, 4, 4, 4, /* illegal in Unicode */
+    5, 5,       /* illegal in Unicode */
+    0, 0        /* illegal bytes 0xfe and 0xff */
+};
+
+static const UChar32
+utf8_minLegal[4]={ 0, 0x80, 0x800, 0x10000 };
+
+static const UChar32
+utf8_errorValue[6]={
+    CBUTF8_ERROR_VALUE_1, CBUTF8_ERROR_VALUE_2, CBUTF_ERROR_VALUE, 0x10ffff,
+    0x3ffffff, 0x7fffffff
+};
+
+/*
+ * Handle the non-inline part of the U8_NEXT() macro and its obsolete sibling
+ * UTF8_NEXT_CHAR_SAFE().
+ *
+ * The "strict" parameter controls the error behavior:
+ * <0  "Safe" behavior of U8_NEXT(): All illegal byte sequences yield a negative
+ *     code point result.
+ *  0  Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE):
+ *     All illegal byte sequences yield a positive code point such that this
+ *     result code point would be encoded with the same number of bytes as
+ *     the illegal sequence.
+ * >0  Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE):
+ *     Same as the obsolete "safe" behavior, but non-characters are also treated
+ *     like illegal sequences.
+ *
+ * The special negative (<0) value -2 is used for lenient treatment of surrogate
+ * code points as legal. Some implementations use this for roundtripping of
+ * Unicode 16-bit strings that are not well-formed UTF-16, that is, they
+ * contain unpaired surrogates.
+ *
+ * Note that a UBool is the same as an int8_t.
+ */
+UChar32
+utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict) {
+    int32 i=*pi;
+    uint8 count=CBU8_COUNT_TRAIL_BYTES(c);
+    if((i)+count<=(length)) {
+        uint8 trail, illegal=0;
+
+        CBU8_MASK_LEAD_BYTE((c), count);
+        /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
+        switch(count) {
+        /* each branch falls through to the next one */
+        case 5:
+        case 4:
+            /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */
+            illegal=1;
+            break;
+        case 3:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            if(c<0x110) {
+                illegal|=(trail&0xc0)^0x80;
+            } else {
+                /* code point>0x10ffff, outside Unicode */
+                illegal=1;
+                break;
+            }
+        case 2:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+        case 1:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+            break;
+        case 0:
+            if(strict>=0) {
+                return CBUTF8_ERROR_VALUE_1;
+            } else {
+                return CBU_SENTINEL;
+            }
+        /* no default branch to optimize switch()  - all values are covered */
+        }
+
+        /*
+         * All the error handling should return a value
+         * that needs count bytes so that UTF8_GET_CHAR_SAFE() works right.
+         *
+         * Starting with Unicode 3.0.1, non-shortest forms are illegal.
+         * Starting with Unicode 3.2, surrogate code points must not be
+         * encoded in UTF-8, and there are no irregular sequences any more.
+         *
+         * U8_ macros (new in ICU 2.4) return negative values for error conditions.
+         */
+
+        /* correct sequence - all trail bytes have (b7..b6)==(10)? */
+        /* illegal is also set if count>=4 */
+        if(illegal || (c)<utf8_minLegal[count] || (CBU_IS_SURROGATE(c) && strict!=-2)) {
+            /* error handling */
+            uint8 errorCount=count;
+            /* don't go beyond this sequence */
+            i=*pi;
+            while(count>0 && CBU8_IS_TRAIL(s[i])) {
+                ++(i);
+                --count;
+            }
+            if(strict>=0) {
+                c=utf8_errorValue[errorCount-count];
+            } else {
+                c=CBU_SENTINEL;
+            }
+        } else if((strict)>0 && CBU_IS_UNICODE_NONCHAR(c)) {
+            /* strict: forbid non-characters like U+fffe */
+            c=utf8_errorValue[count];
+        }
+    } else /* too few bytes left */ {
+        /* error handling */
+        int32 i0=i;
+        /* don't just set (i)=(length) in case there is an illegal sequence */
+        while((i)<(length) && CBU8_IS_TRAIL(s[i])) {
+            ++(i);
+        }
+        if(strict>=0) {
+            c=utf8_errorValue[i-i0];
+        } else {
+            c=CBU_SENTINEL;
+        }
+    }
+    *pi=i;
+    return c;
+}
+
+}  // namespace base_icu
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
new file mode 100644
index 0000000..2b993b0
--- /dev/null
+++ b/base/third_party/icu/icu_utf.h
@@ -0,0 +1,391 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep09
+*   created by: Markus W. Scherer
+*/
+
+#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+
+#include "base/basictypes.h"
+
+namespace base_icu {
+
+typedef int32 UChar32;
+typedef uint16 UChar;
+typedef int8 UBool;
+
+// General ---------------------------------------------------------------------
+// from utf.h
+
+/**
+ * This value is intended for sentinel values for APIs that
+ * (take or) return single code points (UChar32).
+ * It is outside of the Unicode code point range 0..0x10ffff.
+ *
+ * For example, a "done" or "error" value in a new API
+ * could be indicated with CBU_SENTINEL.
+ *
+ * ICU APIs designed before ICU 2.4 usually define service-specific "done"
+ * values, mostly 0xffff.
+ * Those may need to be distinguished from
+ * actual U+ffff text contents by calling functions like
+ * CharacterIterator::hasNext() or UnicodeString::length().
+ *
+ * @return -1
+ * @see UChar32
+ * @stable ICU 2.4
+ */
+#define CBU_SENTINEL (-1)
+
+/**
+ * Is this code point a Unicode noncharacter?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_NONCHAR(c) \
+    ((c)>=0xfdd0 && \
+     ((uint32)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
+     (uint32)(c)<=0x10ffff)
+
+/**
+ * Is c a Unicode code point value (0..U+10ffff)
+ * that can be assigned a character?
+ *
+ * Code points that are not characters include:
+ * - single surrogate code points (U+d800..U+dfff, 2048 code points)
+ * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points)
+ * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points)
+ * - the highest Unicode code point value is U+10ffff
+ *
+ * This means that all code points below U+d800 are character code points,
+ * and that boundary is tested first for performance.
+ *
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_CHAR(c) \
+    ((uint32)(c)<0xd800 || \
+        ((uint32)(c)>0xdfff && \
+         (uint32)(c)<=0x10ffff && \
+         !CBU_IS_UNICODE_NONCHAR(c)))
+
+/**
+ * Is this code point a surrogate (U+d800..U+dfff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+
+/**
+ * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+
+// UTF-8 macros ----------------------------------------------------------------
+// from utf8.h
+
+extern const uint8 utf8_countTrailBytes[256];
+
+/**
+ * Count the trail bytes for a UTF-8 lead byte.
+ * @internal
+ */
+#define CBU8_COUNT_TRAIL_BYTES(leadByte) (base_icu::utf8_countTrailBytes[(uint8)leadByte])
+
+/**
+ * Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
+ * @internal
+ */
+#define CBU8_MASK_LEAD_BYTE(leadByte, countTrailBytes) ((leadByte)&=(1<<(6-(countTrailBytes)))-1)
+
+/**
+ * Does this code unit (byte) encode a code point by itself (US-ASCII 0..0x7f)?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_SINGLE(c) (((c)&0x80)==0)
+
+/**
+ * Is this code unit (byte) a UTF-8 lead byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_LEAD(c) ((uint8)((c)-0xc0)<0x3e)
+
+/**
+ * Is this code unit (byte) a UTF-8 trail byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_TRAIL(c) (((c)&0xc0)==0x80)
+
+/**
+ * How many code units (bytes) are used for the UTF-8 encoding
+ * of this Unicode code point?
+ * @param c 32-bit code point
+ * @return 1..4, or 0 if c is a surrogate or not a Unicode code point
+ * @stable ICU 2.4
+ */
+#define CBU8_LENGTH(c) \
+    ((uint32)(c)<=0x7f ? 1 : \
+        ((uint32)(c)<=0x7ff ? 2 : \
+            ((uint32)(c)<=0xd7ff ? 3 : \
+                ((uint32)(c)<=0xdfff || (uint32)(c)>0x10ffff ? 0 : \
+                    ((uint32)(c)<=0xffff ? 3 : 4)\
+                ) \
+            ) \
+        ) \
+    )
+
+/**
+ * The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
+ * @return 4
+ * @stable ICU 2.4
+ */
+#define CBU8_MAX_LENGTH 4
+
+/**
+ * Function for handling "next code point" with error-checking.
+ * @internal
+ */
+UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict);
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * The offset may point to the lead byte of a multi-byte sequence,
+ * in which case the macro will read the whole sequence.
+ * If the offset points to a trail byte or an illegal UTF-8 sequence, then
+ * c is set to a negative value.
+ *
+ * @param s const uint8 * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see CBU8_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define CBU8_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(((uint8)(c))>=0x80) { \
+        if(CBU8_IS_LEAD(c)) { \
+            (c)=base_icu::utf8_nextCharSafeBody((const uint8 *)s, &(i), (int32)(length), c, -1); \
+        } else { \
+            (c)=CBU_SENTINEL; \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 to 4 bytes.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const uint8 * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see CBU8_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU8_APPEND_UNSAFE(s, i, c) { \
+    if((uint32)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8)(c); \
+    } else { \
+        if((uint32)(c)<=0x7ff) { \
+            (s)[(i)++]=(uint8)(((c)>>6)|0xc0); \
+        } else { \
+            if((uint32)(c)<=0xffff) { \
+                (s)[(i)++]=(uint8)(((c)>>12)|0xe0); \
+            } else { \
+                (s)[(i)++]=(uint8)(((c)>>18)|0xf0); \
+                (s)[(i)++]=(uint8)((((c)>>12)&0x3f)|0x80); \
+            } \
+            (s)[(i)++]=(uint8)((((c)>>6)&0x3f)|0x80); \
+        } \
+        (s)[(i)++]=(uint8)(((c)&0x3f)|0x80); \
+    } \
+}
+
+// UTF-16 macros ---------------------------------------------------------------
+// from utf16.h
+
+/**
+ * Does this code unit alone encode a code point (BMP, not a surrogate)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SINGLE(c) !CBU_IS_SURROGATE(c)
+
+/**
+ * Is this code unit a lead surrogate (U+d800..U+dbff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+
+/**
+ * Is this code unit a trail surrogate (U+dc00..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+
+/**
+ * Is this code unit a surrogate (U+d800..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE(c) CBU_IS_SURROGATE(c)
+
+/**
+ * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+/**
+ * Helper constant for CBU16_GET_SUPPLEMENTARY.
+ * @internal
+ */
+#define CBU16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+
+/**
+ * Get a supplementary code point value (U+10000..U+10ffff)
+ * from its lead and trail surrogates.
+ * The result is undefined if the input values are not
+ * lead and trail surrogates.
+ *
+ * @param lead lead surrogate (U+d800..U+dbff)
+ * @param trail trail surrogate (U+dc00..U+dfff)
+ * @return supplementary code point (U+10000..U+10ffff)
+ * @stable ICU 2.4
+ */
+#define CBU16_GET_SUPPLEMENTARY(lead, trail) \
+    (((base_icu::UChar32)(lead)<<10UL)+(base_icu::UChar32)(trail)-CBU16_SURROGATE_OFFSET)
+
+
+/**
+ * Get the lead surrogate (0xd800..0xdbff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return lead surrogate (U+d800..U+dbff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_LEAD(supplementary) \
+    (base_icu::UChar)(((supplementary)>>10)+0xd7c0)
+
+/**
+ * Get the trail surrogate (0xdc00..0xdfff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return trail surrogate (U+dc00..U+dfff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_TRAIL(supplementary) \
+    (base_icu::UChar)(((supplementary)&0x3ff)|0xdc00)
+
+/**
+ * How many 16-bit code units are used to encode this Unicode code point? (1 or 2)
+ * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff).
+ * @param c 32-bit code point
+ * @return 1 or 2
+ * @stable ICU 2.4
+ */
+#define CBU16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2)
+
+/**
+ * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
+ * @return 2
+ * @stable ICU 2.4
+ */
+#define CBU16_MAX_LENGTH 2
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate or
+ * to a single, unpaired lead surrogate, then that itself
+ * will be returned as the code point.
+ *
+ * @param s const UChar * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @stable ICU 2.4
+ */
+#define CBU16_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(CBU16_IS_LEAD(c)) { \
+        uint16 __c2; \
+        if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
+            ++(i); \
+            (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 or 2 code units.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const UChar * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see CBU16_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU16_APPEND_UNSAFE(s, i, c) { \
+    if((uint32)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16)(c); \
+    } else { \
+        (s)[(i)++]=(uint16)(((c)>>10)+0xd7c0); \
+        (s)[(i)++]=(uint16)(((c)&0x3ff)|0xdc00); \
+    } \
+}
+
+}  // namesapce base_icu
+
+#endif  // BASE_THIRD_PARTY_ICU_ICU_UTF_H_
diff --git a/base/third_party/nspr/LICENSE b/base/third_party/nspr/LICENSE
new file mode 100644
index 0000000..eba7b77
--- /dev/null
+++ b/base/third_party/nspr/LICENSE
@@ -0,0 +1,35 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
diff --git a/base/third_party/nspr/OWNERS b/base/third_party/nspr/OWNERS
new file mode 100644
index 0000000..20ba660
--- /dev/null
+++ b/base/third_party/nspr/OWNERS
@@ -0,0 +1,2 @@
+rsleevi@chromium.org
+wtc@chromium.org
diff --git a/base/third_party/nspr/README.chromium b/base/third_party/nspr/README.chromium
new file mode 100644
index 0000000..3659a2c
--- /dev/null
+++ b/base/third_party/nspr/README.chromium
@@ -0,0 +1,3 @@
+Name: Netscape Portable Runtime (NSPR)
+URL: http://www.mozilla.org/projects/nspr/
+License: MPL 1.1/GPL 2.0/LGPL 2.1
diff --git a/base/third_party/nspr/prtime.cc b/base/third_party/nspr/prtime.cc
new file mode 100644
index 0000000..9335b01
--- /dev/null
+++ b/base/third_party/nspr/prtime.cc
@@ -0,0 +1,1252 @@
+/* Portions are Copyright (C) 2011 Google Inc */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * prtime.cc --
+ * NOTE: The original nspr file name is prtime.c
+ *
+ *     NSPR date and time functions
+ *
+ * CVS revision 3.37
+ */
+
+/*
+ * The following functions were copied from the NSPR prtime.c file.
+ * PR_ParseTimeString
+ *   We inlined the new PR_ParseTimeStringToExplodedTime function to avoid
+ *   copying PR_ExplodeTime and PR_LocalTimeParameters.  (The PR_ExplodeTime
+ *   and PR_ImplodeTime calls cancel each other out.)
+ * PR_NormalizeTime
+ * PR_GMTParameters
+ * PR_ImplodeTime
+ *   This was modified to use the Win32 SYSTEMTIME/FILETIME structures
+ *   and the timezone offsets are applied to the FILETIME structure.
+ * All types and macros are defined in the base/third_party/prtime.h file.
+ * These have been copied from the following nspr files. We have only copied
+ * over the types we need.
+ * 1. prtime.h
+ * 2. prtypes.h
+ * 3. prlong.h
+ *
+ * Unit tests are in base/time/pr_time_unittest.cc.
+ */
+
+#include "base/logging.h"
+#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#elif defined(OS_ANDROID)
+#include <ctype.h>
+#include "base/os_compat_android.h"  // For timegm()
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"  // For timegm()
+#endif
+#include <errno.h>  /* for EINVAL */
+#include <time.h>
+
+/* Implements the Unix localtime_r() function for windows */
+#if defined(OS_WIN)
+static void localtime_r(const time_t* secs, struct tm* time) {
+  (void) localtime_s(time, secs);
+}
+#endif
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_ImplodeTime --
+ *
+ *     Cf. time_t mktime(struct tm *tp)
+ *     Note that 1 year has < 2^25 seconds.  So an PRInt32 is large enough.
+ *
+ *------------------------------------------------------------------------
+ */
+PRTime
+PR_ImplodeTime(const PRExplodedTime *exploded)
+{
+    // This is important, we want to make sure multiplications are
+    // done with the correct precision.
+    static const PRTime kSecondsToMicroseconds = static_cast<PRTime>(1000000);
+#if defined(OS_WIN)
+   // Create the system struct representing our exploded time.
+    SYSTEMTIME st = {0};
+    FILETIME ft = {0};
+    ULARGE_INTEGER uli = {0};
+
+    st.wYear = exploded->tm_year;
+    st.wMonth = static_cast<WORD>(exploded->tm_month + 1);
+    st.wDayOfWeek = exploded->tm_wday;
+    st.wDay = static_cast<WORD>(exploded->tm_mday);
+    st.wHour = static_cast<WORD>(exploded->tm_hour);
+    st.wMinute = static_cast<WORD>(exploded->tm_min);
+    st.wSecond = static_cast<WORD>(exploded->tm_sec);
+    st.wMilliseconds = static_cast<WORD>(exploded->tm_usec/1000);
+     // Convert to FILETIME.
+    if (!SystemTimeToFileTime(&st, &ft)) {
+      NOTREACHED() << "Unable to convert time";
+      return 0;
+    }
+    // Apply offsets.
+    uli.LowPart = ft.dwLowDateTime;
+    uli.HighPart = ft.dwHighDateTime;
+    // Convert from Windows epoch to NSPR epoch, and 100-nanoseconds units
+    // to microsecond units.
+    PRTime result =
+        static_cast<PRTime>((uli.QuadPart / 10) - 11644473600000000i64);
+    // Adjust for time zone and dst.  Convert from seconds to microseconds.
+    result -= (exploded->tm_params.tp_gmt_offset +
+               exploded->tm_params.tp_dst_offset) * kSecondsToMicroseconds;
+    // Add microseconds that cannot be represented in |st|.
+    result += exploded->tm_usec % 1000;
+    return result;
+#elif defined(OS_MACOSX)
+    // Create the system struct representing our exploded time.
+    CFGregorianDate gregorian_date;
+    gregorian_date.year = exploded->tm_year;
+    gregorian_date.month = exploded->tm_month + 1;
+    gregorian_date.day = exploded->tm_mday;
+    gregorian_date.hour = exploded->tm_hour;
+    gregorian_date.minute = exploded->tm_min;
+    gregorian_date.second = exploded->tm_sec;
+
+    // Compute |absolute_time| in seconds, correct for gmt and dst
+    // (note the combined offset will be negative when we need to add it), then
+    // convert to microseconds which is what PRTime expects.
+    CFAbsoluteTime absolute_time =
+        CFGregorianDateGetAbsoluteTime(gregorian_date, NULL);
+    PRTime result = static_cast<PRTime>(absolute_time);
+    result -= exploded->tm_params.tp_gmt_offset +
+              exploded->tm_params.tp_dst_offset;
+    result += kCFAbsoluteTimeIntervalSince1970;  // PRTime epoch is 1970
+    result *= kSecondsToMicroseconds;
+    result += exploded->tm_usec;
+    return result;
+#elif defined(OS_POSIX)
+    struct tm exp_tm = {0};
+    exp_tm.tm_sec  = exploded->tm_sec;
+    exp_tm.tm_min  = exploded->tm_min;
+    exp_tm.tm_hour = exploded->tm_hour;
+    exp_tm.tm_mday = exploded->tm_mday;
+    exp_tm.tm_mon  = exploded->tm_month;
+    exp_tm.tm_year = exploded->tm_year - 1900;
+
+    time_t absolute_time = timegm(&exp_tm);
+
+    // If timegm returned -1.  Since we don't pass it a time zone, the only
+    // valid case of returning -1 is 1 second before Epoch (Dec 31, 1969).
+    if (absolute_time == -1 &&
+        !(exploded->tm_year == 1969 && exploded->tm_month == 11 &&
+        exploded->tm_mday == 31 && exploded->tm_hour == 23 &&
+        exploded->tm_min == 59 && exploded->tm_sec == 59)) {
+      // If we get here, time_t must be 32 bits.
+      // Date was possibly too far in the future and would overflow.  Return
+      // the most future date possible (year 2038).
+      if (exploded->tm_year >= 1970)
+        return INT_MAX * kSecondsToMicroseconds;
+      // Date was possibly too far in the past and would underflow.  Return
+      // the most past date possible (year 1901).
+      return INT_MIN * kSecondsToMicroseconds;
+    }
+
+    PRTime result = static_cast<PRTime>(absolute_time);
+    result -= exploded->tm_params.tp_gmt_offset +
+              exploded->tm_params.tp_dst_offset;
+    result *= kSecondsToMicroseconds;
+    result += exploded->tm_usec;
+    return result;
+#else
+#error No PR_ImplodeTime implemented on your platform.
+#endif
+}
+
+/* 
+ * The COUNT_LEAPS macro counts the number of leap years passed by
+ * till the start of the given year Y.  At the start of the year 4
+ * A.D. the number of leap years passed by is 0, while at the start of
+ * the year 5 A.D. this count is 1. The number of years divisible by
+ * 100 but not divisible by 400 (the non-leap years) is deducted from
+ * the count to get the correct number of leap years.
+ *
+ * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
+ * start of the given year Y. The number of days at the start of the year
+ * 1 is 0 while the number of days at the start of the year 2 is 365
+ * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
+ * midnight 00:00:00.
+ */
+
+#define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
+#define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
+#define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
+
+/*
+ * Static variables used by functions in this file
+ */
+
+/*
+ * The following array contains the day of year for the last day of
+ * each month, where index 1 is January, and day 0 is January 1.
+ */
+
+static const int lastDayOfMonth[2][13] = {
+    {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
+    {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}
+};
+
+/*
+ * The number of days in a month
+ */
+
+static const PRInt8 nDays[2][12] = {
+    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * IsLeapYear --
+ *
+ *     Returns 1 if the year is a leap year, 0 otherwise.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int IsLeapYear(PRInt16 year)
+{
+    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * 'secOffset' should be less than 86400 (i.e., a day).
+ * 'time' should point to a normalized PRExplodedTime.
+ */
+
+static void
+ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset)
+{
+    time->tm_sec += secOffset;
+
+    /* Note that in this implementation we do not count leap seconds */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0) {
+        /* Decrement mday, yday, and wday */
+        time->tm_hour += 24;
+        time->tm_mday--;
+        time->tm_yday--;
+        if (time->tm_mday < 1) {
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+                if (IsLeapYear(time->tm_year))
+                    time->tm_yday = 365;
+                else
+                    time->tm_yday = 364;
+            }
+            time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+        time->tm_wday--;
+        if (time->tm_wday < 0)
+            time->tm_wday = 6;
+    } else if (time->tm_hour > 23) {
+        /* Increment mday, yday, and wday */
+        time->tm_hour -= 24;
+        time->tm_mday++;
+        time->tm_yday++;
+        if (time->tm_mday >
+                nDays[IsLeapYear(time->tm_year)][time->tm_month]) {
+            time->tm_mday = 1;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+                time->tm_yday = 0;
+            }
+        }
+        time->tm_wday++;
+        if (time->tm_wday > 6)
+            time->tm_wday = 0;
+    }
+}
+
+void
+PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params)
+{
+    int daysInMonth;
+    PRInt32 numDays;
+
+    /* Get back to GMT */
+    time->tm_sec -= time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset;
+    time->tm_params.tp_gmt_offset = 0;
+    time->tm_params.tp_dst_offset = 0;
+
+    /* Now normalize GMT */
+
+    if (time->tm_usec < 0 || time->tm_usec >= 1000000) {
+        time->tm_sec +=  time->tm_usec / 1000000;
+        time->tm_usec %= 1000000;
+        if (time->tm_usec < 0) {
+            time->tm_usec += 1000000;
+            time->tm_sec--;
+        }
+    }
+
+    /* Note that we do not count leap seconds in this implementation */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0 || time->tm_hour >= 24) {
+        time->tm_mday += time->tm_hour / 24;
+        time->tm_hour %= 24;
+        if (time->tm_hour < 0) {
+            time->tm_hour += 24;
+            time->tm_mday--;
+        }
+    }
+
+    /* Normalize month and year before mday */
+    if (time->tm_month < 0 || time->tm_month >= 12) {
+        time->tm_year += static_cast<PRInt16>(time->tm_month / 12);
+        time->tm_month %= 12;
+        if (time->tm_month < 0) {
+            time->tm_month += 12;
+            time->tm_year--;
+        }
+    }
+
+    /* Now that month and year are in proper range, normalize mday */
+
+    if (time->tm_mday < 1) {
+        /* mday too small */
+        do {
+            /* the previous month */
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+            }
+            time->tm_mday += nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        } while (time->tm_mday < 1);
+    } else {
+        daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        while (time->tm_mday > daysInMonth) {
+            /* mday too large */
+            time->tm_mday -= daysInMonth;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+            }
+            daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+    }
+
+    /* Recompute yday and wday */
+    time->tm_yday = static_cast<PRInt16>(time->tm_mday +
+            lastDayOfMonth[IsLeapYear(time->tm_year)][time->tm_month]);
+
+    numDays = DAYS_BETWEEN_YEARS(1970, time->tm_year) + time->tm_yday;
+    time->tm_wday = (numDays + 4) % 7;
+    if (time->tm_wday < 0) {
+        time->tm_wday += 7;
+    }
+
+    /* Recompute time parameters */
+
+    time->tm_params = params(time);
+
+    ApplySecOffset(time, time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset);
+}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_GMTParameters --
+ *
+ *     Returns the PRTimeParameters for Greenwich Mean Time.
+ *     Trivially, both the tp_gmt_offset and tp_dst_offset fields are 0.
+ *
+ *------------------------------------------------------------------------
+ */
+
+PRTimeParameters
+PR_GMTParameters(const PRExplodedTime *gmt)
+{
+    PRTimeParameters retVal = { 0, 0 };
+    return retVal;
+}
+
+/*
+ * The following code implements PR_ParseTimeString().  It is based on
+ * ns/lib/xp/xp_time.c, revision 1.25, by Jamie Zawinski <jwz@netscape.com>.
+ */
+
+/*
+ * We only recognize the abbreviations of a small subset of time zones
+ * in North America, Europe, and Japan.
+ *
+ * PST/PDT: Pacific Standard/Daylight Time
+ * MST/MDT: Mountain Standard/Daylight Time
+ * CST/CDT: Central Standard/Daylight Time
+ * EST/EDT: Eastern Standard/Daylight Time
+ * AST: Atlantic Standard Time
+ * NST: Newfoundland Standard Time
+ * GMT: Greenwich Mean Time
+ * BST: British Summer Time
+ * MET: Middle Europe Time
+ * EET: Eastern Europe Time
+ * JST: Japan Standard Time
+ */
+
+typedef enum
+{
+  TT_UNKNOWN,
+
+  TT_SUN, TT_MON, TT_TUE, TT_WED, TT_THU, TT_FRI, TT_SAT,
+
+  TT_JAN, TT_FEB, TT_MAR, TT_APR, TT_MAY, TT_JUN,
+  TT_JUL, TT_AUG, TT_SEP, TT_OCT, TT_NOV, TT_DEC,
+
+  TT_PST, TT_PDT, TT_MST, TT_MDT, TT_CST, TT_CDT, TT_EST, TT_EDT,
+  TT_AST, TT_NST, TT_GMT, TT_BST, TT_MET, TT_EET, TT_JST
+} TIME_TOKEN;
+
+/*
+ * This parses a time/date string into a PRTime
+ * (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ *
+ * Many formats are handled, including:
+ *
+ *   14 Apr 89 03:20:12
+ *   14 Apr 89 03:20 GMT
+ *   Fri, 17 Mar 89 4:01:33
+ *   Fri, 17 Mar 89 4:01 GMT
+ *   Mon Jan 16 16:12 PDT 1989
+ *   Mon Jan 16 16:12 +0130 1989
+ *   6 May 1992 16:41-JST (Wednesday)
+ *   22-AUG-1993 10:59:12.82
+ *   22-AUG-1993 10:59pm
+ *   22-AUG-1993 12:59am
+ *   22-AUG-1993 12:59 PM
+ *   Friday, August 04, 1995 3:54 PM
+ *   06/21/95 04:24:34 PM
+ *   20/06/95 21:07
+ *   95-06-08 19:32:48 EDT
+ *   1995-06-17T23:11:25.342156Z
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+PRStatus
+PR_ParseTimeString(
+        const char *string,
+        PRBool default_to_gmt,
+        PRTime *result_imploded)
+{
+  PRExplodedTime tm;
+  PRExplodedTime *result = &tm;
+  TIME_TOKEN dotw = TT_UNKNOWN;
+  TIME_TOKEN month = TT_UNKNOWN;
+  TIME_TOKEN zone = TT_UNKNOWN;
+  int zone_offset = -1;
+  int dst_offset = 0;
+  int date = -1;
+  PRInt32 year = -1;
+  int hour = -1;
+  int min = -1;
+  int sec = -1;
+  int usec = -1;
+
+  const char *rest = string;
+
+  int iterations = 0;
+
+  PR_ASSERT(string && result);
+  if (!string || !result) return PR_FAILURE;
+
+  while (*rest)
+        {
+
+          if (iterations++ > 1000)
+                {
+                  return PR_FAILURE;
+                }
+
+          switch (*rest)
+                {
+                case 'a': case 'A':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'p' || rest[1] == 'P') &&
+                          (rest[2] == 'r' || rest[2] == 'R'))
+                        month = TT_APR;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_AST;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'g' || rest[2] == 'G'))
+                        month = TT_AUG;
+                  break;
+                case 'b': case 'B':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 's' || rest[1] == 'S') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_BST;
+                  break;
+                case 'c': case 'C':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_CDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_CST;
+                  break;
+                case 'd': case 'D':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'c' || rest[2] == 'C'))
+                        month = TT_DEC;
+                  break;
+                case 'e': case 'E':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EET;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EST;
+                  break;
+                case 'f': case 'F':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'b' || rest[2] == 'B'))
+                        month = TT_FEB;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'r' || rest[1] == 'R') &&
+                                   (rest[2] == 'i' || rest[2] == 'I'))
+                        dotw = TT_FRI;
+                  break;
+                case 'g': case 'G':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'm' || rest[1] == 'M') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_GMT;
+                  break;
+                case 'j': case 'J':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 'n' || rest[2] == 'N'))
+                        month = TT_JAN;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_JST;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'l' || rest[2] == 'L'))
+                        month = TT_JUL;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        month = TT_JUN;
+                  break;
+                case 'm': case 'M':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 'r' || rest[2] == 'R'))
+                        month = TT_MAR;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'a' || rest[1] == 'A') &&
+                                   (rest[2] == 'y' || rest[2] == 'Y'))
+                        month = TT_MAY;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'd' || rest[1] == 'D') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MET;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'o' || rest[1] == 'O') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        dotw = TT_MON;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MST;
+                  break;
+                case 'n': case 'N':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'o' || rest[1] == 'O') &&
+                          (rest[2] == 'v' || rest[2] == 'V'))
+                        month = TT_NOV;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_NST;
+                  break;
+                case 'o': case 'O':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'c' || rest[1] == 'C') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        month = TT_OCT;
+                  break;
+                case 'p': case 'P':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_PDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_PST;
+                  break;
+                case 's': case 'S':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        dotw = TT_SAT;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 'p' || rest[2] == 'P'))
+                        month = TT_SEP;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        dotw = TT_SUN;
+                  break;
+                case 't': case 'T':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'h' || rest[1] == 'H') &&
+                          (rest[2] == 'u' || rest[2] == 'U'))
+                        dotw = TT_THU;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'e' || rest[2] == 'E'))
+                        dotw = TT_TUE;
+                  break;
+                case 'u': case 'U':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 't' || rest[1] == 'T') &&
+                          !(rest[2] >= 'A' && rest[2] <= 'Z') &&
+                          !(rest[2] >= 'a' && rest[2] <= 'z'))
+                        /* UT is the same as GMT but UTx is not. */
+                        zone = TT_GMT;
+                  break;
+                case 'w': case 'W':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'd' || rest[2] == 'D'))
+                        dotw = TT_WED;
+                  break;
+
+                case '+': case '-':
+                  {
+                        const char *end;
+                        int sign;
+                        if (zone_offset != -1)
+                          {
+                                /* already got one... */
+                                rest++;
+                                break;
+                          }
+                        if (zone != TT_UNKNOWN && zone != TT_GMT)
+                          {
+                                /* GMT+0300 is legal, but PST+0300 is not. */
+                                rest++;
+                                break;
+                          }
+
+                        sign = ((*rest == '+') ? 1 : -1);
+                        rest++; /* move over sign */
+                        end = rest;
+                        while (*end >= '0' && *end <= '9')
+                          end++;
+                        if (rest == end) /* no digits here */
+                          break;
+
+                        if ((end - rest) == 4)
+                          /* offset in HHMM */
+                          zone_offset = (((((rest[0]-'0')*10) + (rest[1]-'0')) * 60) +
+                                                         (((rest[2]-'0')*10) + (rest[3]-'0')));
+                        else if ((end - rest) == 2)
+                          /* offset in hours */
+                          zone_offset = (((rest[0]-'0')*10) + (rest[1]-'0')) * 60;
+                        else if ((end - rest) == 1)
+                          /* offset in hours */
+                          zone_offset = (rest[0]-'0') * 60;
+                        else
+                          /* 3 or >4 */
+                          break;
+
+                        zone_offset *= sign;
+                        zone = TT_GMT;
+                        break;
+                  }
+
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                  {
+                        int tmp_hour = -1;
+                        int tmp_min = -1;
+                        int tmp_sec = -1;
+                        int tmp_usec = -1;
+                        const char *end = rest + 1;
+                        while (*end >= '0' && *end <= '9')
+                          end++;
+
+                        /* end is now the first character after a range of digits. */
+
+                        if (*end == ':')
+                          {
+                                if (hour >= 0 && min >= 0) /* already got it */
+                                  break;
+
+                                /* We have seen "[0-9]+:", so this is probably HH:MM[:SS] */
+                                if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_hour = ((rest[0]-'0')*10 +
+                                                          (rest[1]-'0'));
+                                else
+                                  tmp_hour = (rest[0]-'0');
+
+                                /* move over the colon, and parse minutes */
+
+                                rest = ++end;
+                                while (*end >= '0' && *end <= '9')
+                                  end++;
+
+                                if (end == rest)
+                                  /* no digits after first colon? */
+                                  break;
+                                else if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_min = ((rest[0]-'0')*10 +
+                                                         (rest[1]-'0'));
+                                else
+                                  tmp_min = (rest[0]-'0');
+
+                                /* now go for seconds */
+                                rest = end;
+                                if (*rest == ':')
+                                  rest++;
+                                end = rest;
+                                while (*end >= '0' && *end <= '9')
+                                  end++;
+
+                                if (end == rest)
+                                  /* no digits after second colon - that's ok. */
+                                  ;
+                                else if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_sec = ((rest[0]-'0')*10 +
+                                                         (rest[1]-'0'));
+                                else
+                                  tmp_sec = (rest[0]-'0');
+
+                                /* fractional second */
+                                rest = end;
+                                if (*rest == '.')
+                                  {
+                                    rest++;
+                                    end++;
+                                    tmp_usec = 0;
+                                    /* use up to 6 digits, skip over the rest */
+                                    while (*end >= '0' && *end <= '9')
+                                      {
+                                        if (end - rest < 6)
+                                          tmp_usec = tmp_usec * 10 + *end - '0';
+                                        end++;
+                                      }
+                                    int ndigits = end - rest;
+                                    while (ndigits++ < 6)
+                                      tmp_usec *= 10;
+                                    rest = end;
+                                  }
+
+                                if (*rest == 'Z')
+                                  {
+                                    zone = TT_GMT;
+                                    rest++;
+                                  }
+                                else if (tmp_hour <= 12)
+                                  {
+                                    /* If we made it here, we've parsed hour and min,
+                                       and possibly sec, so the current token is a time.
+                                       Now skip over whitespace and see if there's an AM
+                                       or PM directly following the time.
+                                    */
+                                        const char *s = end;
+                                        while (*s && (*s == ' ' || *s == '\t'))
+                                          s++;
+                                        if ((s[0] == 'p' || s[0] == 'P') &&
+                                                (s[1] == 'm' || s[1] == 'M'))
+                                          /* 10:05pm == 22:05, and 12:05pm == 12:05 */
+                                          tmp_hour = (tmp_hour == 12 ? 12 : tmp_hour + 12);
+                                        else if (tmp_hour == 12 &&
+                                                         (s[0] == 'a' || s[0] == 'A') &&
+                                                         (s[1] == 'm' || s[1] == 'M'))
+                                          /* 12:05am == 00:05 */
+                                          tmp_hour = 0;
+                                  }
+
+                                hour = tmp_hour;
+                                min = tmp_min;
+                                sec = tmp_sec;
+                                usec = tmp_usec;
+                                rest = end;
+                                break;
+                          }
+                        else if ((*end == '/' || *end == '-') &&
+                                         end[1] >= '0' && end[1] <= '9')
+                          {
+                                /* Perhaps this is 6/16/95, 16/6/95, 6-16-95, or 16-6-95
+                                   or even 95-06-05 or 1995-06-22.
+                                 */
+                                int n1, n2, n3;
+                                const char *s;
+
+                                if (month != TT_UNKNOWN)
+                                  /* if we saw a month name, this can't be. */
+                                  break;
+
+                                s = rest;
+
+                                n1 = (*s++ - '0');                                /* first 1, 2 or 4 digits */
+                                if (*s >= '0' && *s <= '9')
+                                  {
+                                    n1 = n1*10 + (*s++ - '0');
+
+                                    if (*s >= '0' && *s <= '9')            /* optional digits 3 and 4 */
+                                      {
+                                        n1 = n1*10 + (*s++ - '0');
+                                        if (*s < '0' || *s > '9')
+                                          break;
+                                        n1 = n1*10 + (*s++ - '0');
+                                      }
+                                  }
+
+                                if (*s != '/' && *s != '-')                /* slash */
+                                  break;
+                                s++;
+
+                                if (*s < '0' || *s > '9')                /* second 1 or 2 digits */
+                                  break;
+                                n2 = (*s++ - '0');
+                                if (*s >= '0' && *s <= '9')
+                                  n2 = n2*10 + (*s++ - '0');
+
+                                if (*s != '/' && *s != '-')                /* slash */
+                                  break;
+                                s++;
+
+                                if (*s < '0' || *s > '9')                /* third 1, 2, 4, or 5 digits */
+                                  break;
+                                n3 = (*s++ - '0');
+                                if (*s >= '0' && *s <= '9')
+                                  n3 = n3*10 + (*s++ - '0');
+
+                                if (*s >= '0' && *s <= '9')            /* optional digits 3, 4, and 5 */
+                                  {
+                                        n3 = n3*10 + (*s++ - '0');
+                                        if (*s < '0' || *s > '9')
+                                          break;
+                                        n3 = n3*10 + (*s++ - '0');
+                                        if (*s >= '0' && *s <= '9')
+                                          n3 = n3*10 + (*s++ - '0');
+                                  }
+
+                                if (*s == 'T' && s[1] >= '0' && s[1] <= '9')
+                                  /* followed by ISO 8601 T delimiter and number is ok */
+                                  ;
+                                else if ((*s >= '0' && *s <= '9') ||
+                                         (*s >= 'A' && *s <= 'Z') ||
+                                         (*s >= 'a' && *s <= 'z'))
+                                  /* but other alphanumerics are not ok */
+                                  break;
+
+                                /* Ok, we parsed three multi-digit numbers, with / or -
+                                   between them.  Now decide what the hell they are
+                                   (DD/MM/YY or MM/DD/YY or [YY]YY/MM/DD.)
+                                 */
+
+                                if (n1 > 31 || n1 == 0)  /* must be [YY]YY/MM/DD */
+                                  {
+                                        if (n2 > 12) break;
+                                        if (n3 > 31) break;
+                                        year = n1;
+                                        if (year < 70)
+                                            year += 2000;
+                                        else if (year < 100)
+                                            year += 1900;
+                                        month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
+                                        date = n3;
+                                        rest = s;
+                                        break;
+                                  }
+
+                                if (n1 > 12 && n2 > 12)  /* illegal */
+                                  {
+                                        rest = s;
+                                        break;
+                                  }
+
+                                if (n3 < 70)
+                                    n3 += 2000;
+                                else if (n3 < 100)
+                                    n3 += 1900;
+
+                                if (n1 > 12)  /* must be DD/MM/YY */
+                                  {
+                                        date = n1;
+                                        month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
+                                        year = n3;
+                                  }
+                                else                  /* assume MM/DD/YY */
+                                  {
+                                        /* #### In the ambiguous case, should we consult the
+                                           locale to find out the local default? */
+                                        month = (TIME_TOKEN)(n1 + ((int)TT_JAN) - 1);
+                                        date = n2;
+                                        year = n3;
+                                  }
+                                rest = s;
+                          }
+                        else if ((*end >= 'A' && *end <= 'Z') ||
+                                         (*end >= 'a' && *end <= 'z'))
+                          /* Digits followed by non-punctuation - what's that? */
+                          ;
+                        else if ((end - rest) == 5)                /* five digits is a year */
+                          year = (year < 0
+                                          ? ((rest[0]-'0')*10000L +
+                                                 (rest[1]-'0')*1000L +
+                                                 (rest[2]-'0')*100L +
+                                                 (rest[3]-'0')*10L +
+                                                 (rest[4]-'0'))
+                                          : year);
+                        else if ((end - rest) == 4)                /* four digits is a year */
+                          year = (year < 0
+                                          ? ((rest[0]-'0')*1000L +
+                                                 (rest[1]-'0')*100L +
+                                                 (rest[2]-'0')*10L +
+                                                 (rest[3]-'0'))
+                                          : year);
+                        else if ((end - rest) == 2)                /* two digits - date or year */
+                          {
+                                int n = ((rest[0]-'0')*10 +
+                                                 (rest[1]-'0'));
+                                /* If we don't have a date (day of the month) and we see a number
+                                     less than 32, then assume that is the date.
+
+                                         Otherwise, if we have a date and not a year, assume this is the
+                                         year.  If it is less than 70, then assume it refers to the 21st
+                                         century.  If it is two digits (>= 70), assume it refers to this
+                                         century.  Otherwise, assume it refers to an unambiguous year.
+
+                                         The world will surely end soon.
+                                   */
+                                if (date < 0 && n < 32)
+                                  date = n;
+                                else if (year < 0)
+                                  {
+                                        if (n < 70)
+                                          year = 2000 + n;
+                                        else if (n < 100)
+                                          year = 1900 + n;
+                                        else
+                                          year = n;
+                                  }
+                                /* else what the hell is this. */
+                          }
+                        else if ((end - rest) == 1)                /* one digit - date */
+                          date = (date < 0 ? (rest[0]-'0') : date);
+                        /* else, three or more than five digits - what's that? */
+
+                        break;
+                  }   /* case '0' .. '9' */
+                }   /* switch */
+
+          /* Skip to the end of this token, whether we parsed it or not.
+             Tokens are delimited by whitespace, or ,;-+/()[] but explicitly not .:
+             'T' is also treated as delimiter when followed by a digit (ISO 8601).
+           */
+          while (*rest &&
+                         *rest != ' ' && *rest != '\t' &&
+                         *rest != ',' && *rest != ';' &&
+                         *rest != '-' && *rest != '+' &&
+                         *rest != '/' &&
+                         *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']' &&
+                         !(*rest == 'T' && rest[1] >= '0' && rest[1] <= '9')
+                )
+                rest++;
+          /* skip over uninteresting chars. */
+        SKIP_MORE:
+          while (*rest == ' ' || *rest == '\t' ||
+                 *rest == ',' || *rest == ';' || *rest == '/' ||
+                 *rest == '(' || *rest == ')' || *rest == '[' || *rest == ']')
+                rest++;
+
+          /* "-" is ignored at the beginning of a token if we have not yet
+                 parsed a year (e.g., the second "-" in "30-AUG-1966"), or if
+                 the character after the dash is not a digit. */         
+          if (*rest == '-' && ((rest > string &&
+              isalpha((unsigned char)rest[-1]) && year < 0) ||
+              rest[1] < '0' || rest[1] > '9'))
+                {
+                  rest++;
+                  goto SKIP_MORE;
+                }
+
+          /* Skip T that may precede ISO 8601 time. */
+          if (*rest == 'T' && rest[1] >= '0' && rest[1] <= '9')
+            rest++;
+        }   /* while */
+
+  if (zone != TT_UNKNOWN && zone_offset == -1)
+        {
+          switch (zone)
+                {
+                case TT_PST: zone_offset = -8 * 60; break;
+                case TT_PDT: zone_offset = -8 * 60; dst_offset = 1 * 60; break;
+                case TT_MST: zone_offset = -7 * 60; break;
+                case TT_MDT: zone_offset = -7 * 60; dst_offset = 1 * 60; break;
+                case TT_CST: zone_offset = -6 * 60; break;
+                case TT_CDT: zone_offset = -6 * 60; dst_offset = 1 * 60; break;
+                case TT_EST: zone_offset = -5 * 60; break;
+                case TT_EDT: zone_offset = -5 * 60; dst_offset = 1 * 60; break;
+                case TT_AST: zone_offset = -4 * 60; break;
+                case TT_NST: zone_offset = -3 * 60 - 30; break;
+                case TT_GMT: zone_offset =  0 * 60; break;
+                case TT_BST: zone_offset =  0 * 60; dst_offset = 1 * 60; break;
+                case TT_MET: zone_offset =  1 * 60; break;
+                case TT_EET: zone_offset =  2 * 60; break;
+                case TT_JST: zone_offset =  9 * 60; break;
+                default:
+                  PR_ASSERT (0);
+                  break;
+                }
+        }
+
+  /* If we didn't find a year, month, or day-of-the-month, we can't
+         possibly parse this, and in fact, mktime() will do something random
+         (I'm seeing it return "Tue Feb  5 06:28:16 2036", which is no doubt
+         a numerologically significant date... */
+  if (month == TT_UNKNOWN || date == -1 || year == -1 || year > PR_INT16_MAX)
+      return PR_FAILURE;
+
+  memset(result, 0, sizeof(*result));
+  if (usec != -1)
+        result->tm_usec = usec;
+  if (sec != -1)
+        result->tm_sec = sec;
+  if (min != -1)
+        result->tm_min = min;
+  if (hour != -1)
+        result->tm_hour = hour;
+  if (date != -1)
+        result->tm_mday = date;
+  if (month != TT_UNKNOWN)
+        result->tm_month = (((int)month) - ((int)TT_JAN));
+  if (year != -1)
+        result->tm_year = static_cast<PRInt16>(year);
+  if (dotw != TT_UNKNOWN)
+        result->tm_wday = static_cast<PRInt8>(((int)dotw) - ((int)TT_SUN));
+  /*
+   * Mainly to compute wday and yday, but normalized time is also required
+   * by the check below that works around a Visual C++ 2005 mktime problem.
+   */
+  PR_NormalizeTime(result, PR_GMTParameters);
+  /* The remaining work is to set the gmt and dst offsets in tm_params. */
+
+  if (zone == TT_UNKNOWN && default_to_gmt)
+        {
+          /* No zone was specified, so pretend the zone was GMT. */
+          zone = TT_GMT;
+          zone_offset = 0;
+        }
+
+  if (zone_offset == -1)
+         {
+           /* no zone was specified, and we're to assume that everything
+             is local. */
+          struct tm localTime;
+          time_t secs;
+
+          PR_ASSERT(result->tm_month > -1 &&
+                    result->tm_mday > 0 &&
+                    result->tm_hour > -1 &&
+                    result->tm_min > -1 &&
+                    result->tm_sec > -1);
+
+            /*
+             * To obtain time_t from a tm structure representing the local
+             * time, we call mktime().  However, we need to see if we are
+             * on 1-Jan-1970 or before.  If we are, we can't call mktime()
+             * because mktime() will crash on win16. In that case, we
+             * calculate zone_offset based on the zone offset at
+             * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the
+             * date we are parsing to transform the date to GMT.  We also
+             * do so if mktime() returns (time_t) -1 (time out of range).
+           */
+
+          /* month, day, hours, mins and secs are always non-negative
+             so we dont need to worry about them. */
+          if (result->tm_year >= 1970)
+                {
+                  localTime.tm_sec = result->tm_sec;
+                  localTime.tm_min = result->tm_min;
+                  localTime.tm_hour = result->tm_hour;
+                  localTime.tm_mday = result->tm_mday;
+                  localTime.tm_mon = result->tm_month;
+                  localTime.tm_year = result->tm_year - 1900;
+                  /* Set this to -1 to tell mktime "I don't care".  If you set
+                     it to 0 or 1, you are making assertions about whether the
+                     date you are handing it is in daylight savings mode or not;
+                     and if you're wrong, it will "fix" it for you. */
+                  localTime.tm_isdst = -1;
+
+#if _MSC_VER == 1400  /* 1400 = Visual C++ 2005 (8.0) */
+                  /*
+                   * mktime will return (time_t) -1 if the input is a date
+                   * after 23:59:59, December 31, 3000, US Pacific Time (not
+                   * UTC as documented): 
+                   * http://msdn.microsoft.com/en-us/library/d1y53h2a(VS.80).aspx
+                   * But if the year is 3001, mktime also invokes the invalid
+                   * parameter handler, causing the application to crash.  This
+                   * problem has been reported in
+                   * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=266036.
+                   * We avoid this crash by not calling mktime if the date is
+                   * out of range.  To use a simple test that works in any time
+                   * zone, we consider year 3000 out of range as well.  (See
+                   * bug 480740.)
+                   */
+                  if (result->tm_year >= 3000) {
+                      /* Emulate what mktime would have done. */
+                      errno = EINVAL;
+                      secs = (time_t) -1;
+                  } else {
+                      secs = mktime(&localTime);
+                  }
+#else
+                  secs = mktime(&localTime);
+#endif
+                  if (secs != (time_t) -1)
+                    {
+                      *result_imploded = (PRInt64)secs * PR_USEC_PER_SEC;
+                      *result_imploded += result->tm_usec;
+                      return PR_SUCCESS;
+                    }
+                }
+                
+                /* So mktime() can't handle this case.  We assume the
+                   zone_offset for the date we are parsing is the same as
+                   the zone offset on 00:00:00 2 Jan 1970 GMT. */
+                secs = 86400;
+                localtime_r(&secs, &localTime);
+                zone_offset = localTime.tm_min
+                              + 60 * localTime.tm_hour
+                              + 1440 * (localTime.tm_mday - 2);
+        }
+
+  result->tm_params.tp_gmt_offset = zone_offset * 60;
+  result->tm_params.tp_dst_offset = dst_offset * 60;
+
+  *result_imploded = PR_ImplodeTime(result);
+  return PR_SUCCESS;
+}
diff --git a/base/third_party/nspr/prtime.h b/base/third_party/nspr/prtime.h
new file mode 100644
index 0000000..01a4e54
--- /dev/null
+++ b/base/third_party/nspr/prtime.h
@@ -0,0 +1,252 @@
+/* Portions are Copyright (C) 2011 Google Inc */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * prtime.h --
+ *
+ *     NSPR date and time functions
+ * CVS revision 3.10
+ * This file contains definitions of NSPR's basic types required by
+ * prtime.cc. These types have been copied over from the following NSPR
+ * files prtime.h, prtypes.h(CVS revision 3.35), prlong.h(CVS revision 3.13)
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef BASE_PRTIME_H__
+#define BASE_PRTIME_H__
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+
+typedef int8_t PRInt8;
+typedef int16_t PRInt16;
+typedef int32_t PRInt32;
+typedef int64_t PRInt64;
+typedef int PRIntn;
+
+typedef PRIntn PRBool;
+#define PR_TRUE 1
+#define PR_FALSE 0
+
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+#define PR_ASSERT DCHECK
+#define PR_CALLBACK
+#define PR_INT16_MAX 32767
+#define NSPR_API(__type) extern __type
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+#define PR_MSEC_PER_SEC		1000UL
+#define PR_USEC_PER_SEC		1000000UL
+#define PR_NSEC_PER_SEC		1000000000UL
+#define PR_USEC_PER_MSEC	1000UL
+#define PR_NSEC_PER_MSEC	1000000UL
+
+/*
+ * PRTime --
+ *
+ *     NSPR represents basic time as 64-bit signed integers relative
+ *     to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT).
+ *     (GMT is also known as Coordinated Universal Time, UTC.)
+ *     The units of time are in microseconds. Negative times are allowed
+ *     to represent times prior to the January 1970 epoch. Such values are
+ *     intended to be exported to other systems or converted to human
+ *     readable form.
+ *
+ *     Notes on porting: PRTime corresponds to time_t in ANSI C.  NSPR 1.0
+ *     simply uses PRInt64.
+ */
+
+typedef PRInt64 PRTime;
+
+/*
+ * Time zone and daylight saving time corrections applied to GMT to
+ * obtain the local time of some geographic location
+ */
+
+typedef struct PRTimeParameters {
+    PRInt32 tp_gmt_offset;     /* the offset from GMT in seconds */
+    PRInt32 tp_dst_offset;     /* contribution of DST in seconds */
+} PRTimeParameters;
+
+/*
+ * PRExplodedTime --
+ *
+ *     Time broken down into human-readable components such as year, month,
+ *     day, hour, minute, second, and microsecond.  Time zone and daylight
+ *     saving time corrections may be applied.  If they are applied, the
+ *     offsets from the GMT must be saved in the 'tm_params' field so that
+ *     all the information is available to reconstruct GMT.
+ *
+ *     Notes on porting: PRExplodedTime corrresponds to struct tm in
+ *     ANSI C, with the following differences:
+ *       - an additional field tm_usec;
+ *       - replacing tm_isdst by tm_params;
+ *       - the month field is spelled tm_month, not tm_mon;
+ *       - we use absolute year, AD, not the year since 1900.
+ *     The corresponding type in NSPR 1.0 is called PRTime.  Below is
+ *     a table of date/time type correspondence in the three APIs:
+ *         API          time since epoch          time in components
+ *       ANSI C             time_t                  struct tm
+ *       NSPR 1.0           PRInt64                   PRTime
+ *       NSPR 2.0           PRTime                  PRExplodedTime
+ */
+
+typedef struct PRExplodedTime {
+    PRInt32 tm_usec;		    /* microseconds past tm_sec (0-99999)  */
+    PRInt32 tm_sec;             /* seconds past tm_min (0-61, accomodating
+                                   up to two leap seconds) */	
+    PRInt32 tm_min;             /* minutes past tm_hour (0-59) */
+    PRInt32 tm_hour;            /* hours past tm_day (0-23) */
+    PRInt32 tm_mday;            /* days past tm_mon (1-31, note that it
+				                starts from 1) */
+    PRInt32 tm_month;           /* months past tm_year (0-11, Jan = 0) */
+    PRInt16 tm_year;            /* absolute year, AD (note that we do not
+				                count from 1900) */
+
+    PRInt8 tm_wday;		        /* calculated day of the week
+				                (0-6, Sun = 0) */
+    PRInt16 tm_yday;            /* calculated day of the year
+				                (0-365, Jan 1 = 0) */
+
+    PRTimeParameters tm_params;  /* time parameters used by conversion */
+} PRExplodedTime;
+
+/*
+ * PRTimeParamFn --
+ *
+ *     A function of PRTimeParamFn type returns the time zone and
+ *     daylight saving time corrections for some geographic location,
+ *     given the current time in GMT.  The input argument gmt should
+ *     point to a PRExplodedTime that is in GMT, i.e., whose
+ *     tm_params contains all 0's.
+ *
+ *     For any time zone other than GMT, the computation is intended to
+ *     consist of two steps:
+ *       - Figure out the time zone correction, tp_gmt_offset.  This number
+ *         usually depends on the geographic location only.  But it may
+ *         also depend on the current time.  For example, all of China
+ *         is one time zone right now.  But this situation may change
+ *         in the future.
+ *       - Figure out the daylight saving time correction, tp_dst_offset.
+ *         This number depends on both the geographic location and the
+ *         current time.  Most of the DST rules are expressed in local
+ *         current time.  If so, one should apply the time zone correction
+ *         to GMT before applying the DST rules.
+ */
+
+typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt);
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+NSPR_API(PRTime)
+PR_ImplodeTime(const PRExplodedTime *exploded);
+
+/*
+ * Adjust exploded time to normalize field overflows after manipulation.
+ * Note that the following fields of PRExplodedTime should not be
+ * manipulated:
+ *   - tm_month and tm_year: because the number of days in a month and
+ *     number of days in a year are not constant, it is ambiguous to
+ *     manipulate the month and year fields, although one may be tempted
+ *     to.  For example, what does "a month from January 31st" mean?
+ *   - tm_wday and tm_yday: these fields are calculated by NSPR.  Users
+ *     should treat them as "read-only".
+ */
+
+NSPR_API(void) PR_NormalizeTime(
+    PRExplodedTime *exploded, PRTimeParamFn params);
+
+/**********************************************************************/
+/*********************** TIME PARAMETER FUNCTIONS *********************/
+/**********************************************************************/
+
+/* Time parameters that represent Greenwich Mean Time */
+NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt);
+
+/*
+ * This parses a time/date string into a PRTime
+ * (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ *
+ * Many formats are handled, including:
+ *
+ *   14 Apr 89 03:20:12
+ *   14 Apr 89 03:20 GMT
+ *   Fri, 17 Mar 89 4:01:33
+ *   Fri, 17 Mar 89 4:01 GMT
+ *   Mon Jan 16 16:12 PDT 1989
+ *   Mon Jan 16 16:12 +0130 1989
+ *   6 May 1992 16:41-JST (Wednesday)
+ *   22-AUG-1993 10:59:12.82
+ *   22-AUG-1993 10:59pm
+ *   22-AUG-1993 12:59am
+ *   22-AUG-1993 12:59 PM
+ *   Friday, August 04, 1995 3:54 PM
+ *   06/21/95 04:24:34 PM
+ *   20/06/95 21:07
+ *   95-06-08 19:32:48 EDT
+ *   1995-06-17T23:11:25.342156Z
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+/*
+ * This is the only funtion that should be called from outside base, and only
+ * from the unit test.
+ */
+
+BASE_EXPORT PRStatus PR_ParseTimeString (
+	const char *string,
+	PRBool default_to_gmt,
+	PRTime *result);
+
+#endif  // BASE_PRTIME_H__
diff --git a/base/third_party/superfasthash/LICENSE b/base/third_party/superfasthash/LICENSE
new file mode 100644
index 0000000..3c40a3e
--- /dev/null
+++ b/base/third_party/superfasthash/LICENSE
@@ -0,0 +1,27 @@
+Paul Hsieh OLD BSD license
+
+Copyright (c) 2010, Paul Hsieh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+* Neither my name, Paul Hsieh, nor the names of any other contributors to the
+  code use may not be used to endorse or promote products derived from this
+  software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/superfasthash/OWNERS b/base/third_party/superfasthash/OWNERS
new file mode 100644
index 0000000..f34cfb1
--- /dev/null
+++ b/base/third_party/superfasthash/OWNERS
@@ -0,0 +1,2 @@
+mgiuca@chromium.org
+rvargas@chromium.org
diff --git a/base/third_party/superfasthash/README.chromium b/base/third_party/superfasthash/README.chromium
new file mode 100644
index 0000000..d41ed77
--- /dev/null
+++ b/base/third_party/superfasthash/README.chromium
@@ -0,0 +1,29 @@
+Name: Paul Hsieh's SuperFastHash
+Short Name: SuperFastHash
+URL: http://www.azillionmonkeys.com/qed/hash.html
+Version: 0
+Date: 2012-02-21
+License: BSD
+License File: LICENSE
+Security Critical: yes
+
+Description:
+A fast string hashing algorithm.
+
+Local Modifications:
+- Added LICENSE.
+- Added license text as a comment to the top of superfasthash.c.
+- #include <stdint.h> instead of "pstdint.h".
+- #include <stdlib.h>.
+
+The license is a standard 3-clause BSD license with the following minor changes:
+
+"nor the names of its contributors may be used"
+is replaced with:
+"nor the names of any other contributors to the code use may not be used"
+
+and
+
+"IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE"
+is replaced with:
+"IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE"
diff --git a/base/third_party/superfasthash/superfasthash.c b/base/third_party/superfasthash/superfasthash.c
new file mode 100644
index 0000000..6e7687e
--- /dev/null
+++ b/base/third_party/superfasthash/superfasthash.c
@@ -0,0 +1,84 @@
+// Copyright (c) 2010, Paul Hsieh
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither my name, Paul Hsieh, nor the names of any other contributors to the
+//   code use may not be used to endorse or promote products derived from this
+//   software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdint.h>
+#include <stdlib.h>
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t SuperFastHash (const char * data, int len) {
+uint32_t hash = len, tmp;
+int rem;
+
+    if (len <= 0 || data == NULL) return 0;
+
+    rem = len & 3;
+    len >>= 2;
+
+    /* Main loop */
+    for (;len > 0; len--) {
+        hash  += get16bits (data);
+        tmp    = (get16bits (data+2) << 11) ^ hash;
+        hash   = (hash << 16) ^ tmp;
+        data  += 2*sizeof (uint16_t);
+        hash  += hash >> 11;
+    }
+
+    /* Handle end cases */
+    switch (rem) {
+        case 3: hash += get16bits (data);
+                hash ^= hash << 16;
+                hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
+                hash += hash >> 11;
+                break;
+        case 2: hash += get16bits (data);
+                hash ^= hash << 11;
+                hash += hash >> 17;
+                break;
+        case 1: hash += (signed char)*data;
+                hash ^= hash << 10;
+                hash += hash >> 1;
+    }
+
+    /* Force "avalanching" of final 127 bits */
+    hash ^= hash << 3;
+    hash += hash >> 5;
+    hash ^= hash << 4;
+    hash += hash >> 17;
+    hash ^= hash << 25;
+    hash += hash >> 6;
+
+    return hash;
+}
diff --git a/base/third_party/symbolize/BUILD.gn b/base/third_party/symbolize/BUILD.gn
new file mode 100644
index 0000000..ddcb789
--- /dev/null
+++ b/base/third_party/symbolize/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("symbolize") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "config.h",
+    "demangle.cc",
+    "demangle.h",
+    "glog/logging.h",
+    "glog/raw_logging.h",
+    "symbolize.cc",
+    "symbolize.h",
+    "utilities.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/base/third_party/symbolize/DEPS b/base/third_party/symbolize/DEPS
new file mode 100644
index 0000000..73eab50
--- /dev/null
+++ b/base/third_party/symbolize/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+glog",
+]
diff --git a/base/third_party/symbolize/LICENSE b/base/third_party/symbolize/LICENSE
new file mode 100644
index 0000000..433a3d1
--- /dev/null
+++ b/base/third_party/symbolize/LICENSE
@@ -0,0 +1,28 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
new file mode 100644
index 0000000..de92794
--- /dev/null
+++ b/base/third_party/symbolize/README.chromium
@@ -0,0 +1,18 @@
+Name: google-glog's symbolization library
+URL: http://code.google.com/p/google-glog/
+License: BSD
+
+The following files are copied AS-IS from:
+http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r141)
+
+- demangle.cc
+- demangle.h
+- symbolize.cc
+- symbolize.h
+
+The following files are minimal stubs created for use in Chromium:
+
+- config.h
+- glog/logging.h
+- glog/raw_logging.h
+- utilities.h
diff --git a/base/third_party/symbolize/config.h b/base/third_party/symbolize/config.h
new file mode 100644
index 0000000..945f5a6
--- /dev/null
+++ b/base/third_party/symbolize/config.h
@@ -0,0 +1,7 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define GOOGLE_NAMESPACE google
+#define _END_GOOGLE_NAMESPACE_ }
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
new file mode 100644
index 0000000..e858181
--- /dev/null
+++ b/base/third_party/symbolize/demangle.cc
@@ -0,0 +1,1304 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// For reference check out:
+// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
+//
+// Note that we only have partial C++0x support yet.
+
+#include <stdio.h>  // for NULL
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+typedef struct {
+  const char *abbrev;
+  const char *real_name;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+  { "nw", "new" },
+  { "na", "new[]" },
+  { "dl", "delete" },
+  { "da", "delete[]" },
+  { "ps", "+" },
+  { "ng", "-" },
+  { "ad", "&" },
+  { "de", "*" },
+  { "co", "~" },
+  { "pl", "+" },
+  { "mi", "-" },
+  { "ml", "*" },
+  { "dv", "/" },
+  { "rm", "%" },
+  { "an", "&" },
+  { "or", "|" },
+  { "eo", "^" },
+  { "aS", "=" },
+  { "pL", "+=" },
+  { "mI", "-=" },
+  { "mL", "*=" },
+  { "dV", "/=" },
+  { "rM", "%=" },
+  { "aN", "&=" },
+  { "oR", "|=" },
+  { "eO", "^=" },
+  { "ls", "<<" },
+  { "rs", ">>" },
+  { "lS", "<<=" },
+  { "rS", ">>=" },
+  { "eq", "==" },
+  { "ne", "!=" },
+  { "lt", "<" },
+  { "gt", ">" },
+  { "le", "<=" },
+  { "ge", ">=" },
+  { "nt", "!" },
+  { "aa", "&&" },
+  { "oo", "||" },
+  { "pp", "++" },
+  { "mm", "--" },
+  { "cm", "," },
+  { "pm", "->*" },
+  { "pt", "->" },
+  { "cl", "()" },
+  { "ix", "[]" },
+  { "qu", "?" },
+  { "st", "sizeof" },
+  { "sz", "sizeof" },
+  { NULL, NULL },
+};
+
+// List of builtin types from Itanium C++ ABI.
+static const AbbrevPair kBuiltinTypeList[] = {
+  { "v", "void" },
+  { "w", "wchar_t" },
+  { "b", "bool" },
+  { "c", "char" },
+  { "a", "signed char" },
+  { "h", "unsigned char" },
+  { "s", "short" },
+  { "t", "unsigned short" },
+  { "i", "int" },
+  { "j", "unsigned int" },
+  { "l", "long" },
+  { "m", "unsigned long" },
+  { "x", "long long" },
+  { "y", "unsigned long long" },
+  { "n", "__int128" },
+  { "o", "unsigned __int128" },
+  { "f", "float" },
+  { "d", "double" },
+  { "e", "long double" },
+  { "g", "__float128" },
+  { "z", "ellipsis" },
+  { NULL, NULL }
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+  { "St", "" },
+  { "Sa", "allocator" },
+  { "Sb", "basic_string" },
+  // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+  { "Ss", "string"},
+  // std::basic_istream<char, std::char_traits<char> >
+  { "Si", "istream" },
+  // std::basic_ostream<char, std::char_traits<char> >
+  { "So", "ostream" },
+  // std::basic_iostream<char, std::char_traits<char> >
+  { "Sd", "iostream" },
+  { NULL, NULL }
+};
+
+// State needed for demangling.
+typedef struct {
+  const char *mangled_cur;  // Cursor of mangled name.
+  char *out_cur;            // Cursor of output string.
+  const char *out_begin;    // Beginning of output string.
+  const char *out_end;      // End of output string.
+  const char *prev_name;    // For constructors/destructors.
+  int prev_name_length;     // For constructors/destructors.
+  short nest_level;         // For nested names.
+  bool append;              // Append flag.
+  bool overflowed;          // True if output gets overflowed.
+} State;
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+  size_t len = 0;
+  while (*str != '\0') {
+    ++str;
+    ++len;
+  }
+  return len;
+}
+
+// Returns true if "str" has at least "n" characters remaining.
+static bool AtLeastNumCharsRemaining(const char *str, int n) {
+  for (int i = 0; i < n; ++i) {
+    if (str[i] == '\0') {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+  size_t i = 0;
+  while (str[i] != '\0' && prefix[i] != '\0' &&
+         str[i] == prefix[i]) {
+    ++i;
+  }
+  return prefix[i] == '\0';  // Consumed everything in "prefix".
+}
+
+static void InitState(State *state, const char *mangled,
+                      char *out, int out_size) {
+  state->mangled_cur = mangled;
+  state->out_cur = out;
+  state->out_begin = out;
+  state->out_end = out + out_size;
+  state->prev_name  = NULL;
+  state->prev_name_length = -1;
+  state->nest_level = -1;
+  state->append = true;
+  state->overflowed = false;
+}
+
+// Returns true and advances "mangled_cur" if we find "one_char_token"
+// at "mangled_cur" position.  It is assumed that "one_char_token" does
+// not contain '\0'.
+static bool ParseOneCharToken(State *state, const char one_char_token) {
+  if (state->mangled_cur[0] == one_char_token) {
+    ++state->mangled_cur;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find "two_char_token"
+// at "mangled_cur" position.  It is assumed that "two_char_token" does
+// not contain '\0'.
+static bool ParseTwoCharToken(State *state, const char *two_char_token) {
+  if (state->mangled_cur[0] == two_char_token[0] &&
+      state->mangled_cur[1] == two_char_token[1]) {
+    state->mangled_cur += 2;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find any character in
+// "char_class" at "mangled_cur" position.
+static bool ParseCharClass(State *state, const char *char_class) {
+  const char *p = char_class;
+  for (; *p != '\0'; ++p) {
+    if (state->mangled_cur[0] == *p) {
+      ++state->mangled_cur;
+      return true;
+    }
+  }
+  return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool) {
+  return true;
+}
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+  if (parse_func(state)) {
+    while (parse_func(state)) {
+    }
+    return true;
+  }
+  return false;
+}
+
+// This function is used for handling <non-terminal>* syntax. The function
+// always returns true and must be followed by a termination token or a
+// terminating sequence not handled by parse_func (e.g.
+// ParseOneCharToken(state, 'E')).
+static bool ZeroOrMore(ParseFunc parse_func, State *state) {
+  while (parse_func(state)) {
+  }
+  return true;
+}
+
+// Append "str" at "out_cur".  If there is an overflow, "overflowed"
+// is set to true for later use.  The output string is ensured to
+// always terminate with '\0' as long as there is no overflow.
+static void Append(State *state, const char * const str, const int length) {
+  int i;
+  for (i = 0; i < length; ++i) {
+    if (state->out_cur + 1 < state->out_end) {  // +1 for '\0'
+      *state->out_cur = str[i];
+      ++state->out_cur;
+    } else {
+      state->overflowed = true;
+      break;
+    }
+  }
+  if (!state->overflowed) {
+    *state->out_cur = '\0';  // Terminate it with '\0'
+  }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) {
+  return c >= 'a' && c <= 'z';
+}
+
+static bool IsAlpha(char c) {
+  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+static bool IsDigit(char c) {
+  return c >= '0' && c <= '9';
+}
+
+// Returns true if "str" is a function clone suffix.  These suffixes are used
+// by GCC 4.5.x and later versions to indicate functions which have been
+// cloned during optimization.  We treat any sequence (.<alpha>+.<digit>+)+ as
+// a function clone suffix.
+static bool IsFunctionCloneSuffix(const char *str) {
+  size_t i = 0;
+  while (str[i] != '\0') {
+    // Consume a single .<alpha>+.<digit>+ sequence.
+    if (str[i] != '.' || !IsAlpha(str[i + 1])) {
+      return false;
+    }
+    i += 2;
+    while (IsAlpha(str[i])) {
+      ++i;
+    }
+    if (str[i] != '.' || !IsDigit(str[i + 1])) {
+      return false;
+    }
+    i += 2;
+    while (IsDigit(str[i])) {
+      ++i;
+    }
+  }
+  return true;  // Consumed everything in "str".
+}
+
+// Append "str" with some tweaks, iff "append" state is true.
+// Returns true so that it can be placed in "if" conditions.
+static void MaybeAppendWithLength(State *state, const char * const str,
+                                  const int length) {
+  if (state->append && length > 0) {
+    // Append a space if the output buffer ends with '<' and "str"
+    // starts with '<' to avoid <<<.
+    if (str[0] == '<' && state->out_begin < state->out_cur  &&
+        state->out_cur[-1] == '<') {
+      Append(state, " ", 1);
+    }
+    // Remember the last identifier name for ctors/dtors.
+    if (IsAlpha(str[0]) || str[0] == '_') {
+      state->prev_name = state->out_cur;
+      state->prev_name_length = length;
+    }
+    Append(state, str, length);
+  }
+}
+
+// A convenient wrapper arount MaybeAppendWithLength().
+static bool MaybeAppend(State *state, const char * const str) {
+  if (state->append) {
+    int length = StrLen(str);
+    MaybeAppendWithLength(state, str, length);
+  }
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+  state->nest_level = 0;
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, short prev_value) {
+  state->nest_level = prev_value;
+  return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+  state->append = false;
+  return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+  state->append = prev_value;
+  return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+  if (state->nest_level > -1) {
+    ++state->nest_level;
+  }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+  if (state->nest_level >= 1) {
+    MaybeAppend(state, "::");
+  }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+  if (state->nest_level >= 1 && state->append &&
+      state->out_begin <= state->out_cur - 2) {
+    state->out_cur -= 2;
+    *state->out_cur = '\0';
+  }
+}
+
+// Returns true if the identifier of the given length pointed to by
+// "mangled_cur" is anonymous namespace.
+static bool IdentifierIsAnonymousNamespace(State *state, int length) {
+  static const char anon_prefix[] = "_GLOBAL__N_";
+  return (length > (int)sizeof(anon_prefix) - 1 &&  // Should be longer.
+          StrPrefix(state->mangled_cur, anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseUnscopedTemplateName(State *state);
+static bool ParseNestedName(State *state);
+static bool ParsePrefix(State *state);
+static bool ParseUnqualifiedName(State *state);
+static bool ParseSourceName(State *state);
+static bool ParseLocalSourceName(State *state);
+static bool ParseNumber(State *state, int *number_out);
+static bool ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state, int length);
+static bool ParseOperatorName(State *state);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+//   We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the state and returns true on
+// success.  Otherwise, don't change the state and returns false.  To
+// ensure that the state isn't changed in the latter case, we save the
+// original state before we call more than one parsing functions
+// consecutively with &&, and restore the state if unsuccessful.  See
+// ParseEncoding() as an example of this convention.  We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments.  Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+//   <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
+
+// <mangled-name> ::= _Z <encoding>
+static bool ParseMangledName(State *state) {
+  return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+//            ::= <(data) name>
+//            ::= <special-name>
+static bool ParseEncoding(State *state) {
+  State copy = *state;
+  if (ParseName(state) && ParseBareFunctionType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseName(state) || ParseSpecialName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <name> ::= <nested-name>
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//        ::= <local-name>
+static bool ParseName(State *state) {
+  if (ParseNestedName(state) || ParseLocalName(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseUnscopedTemplateName(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Less greedy than <unscoped-template-name> <template-args>.
+  if (ParseUnscopedName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+  if (ParseUnqualifiedName(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseTwoCharToken(state, "St") &&
+      MaybeAppend(state, "std::") &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+static bool ParseUnscopedTemplateName(State *state) {
+  return ParseUnscopedName(state) || ParseSubstitution(state);
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+//               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+static bool ParseNestedName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'N') &&
+      EnterNestedName(state) &&
+      Optional(ParseCVQualifiers(state)) &&
+      ParsePrefix(state) &&
+      LeaveNestedName(state, copy.nest_level) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// This part is tricky.  If we literally translate them to code, we'll
+// end up infinite loop.  Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <substitution>
+//          ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+static bool ParsePrefix(State *state) {
+  bool has_something = false;
+  while (true) {
+    MaybeAppendSeparator(state);
+    if (ParseTemplateParam(state) ||
+        ParseSubstitution(state) ||
+        ParseUnscopedName(state)) {
+      has_something = true;
+      MaybeIncreaseNestLevel(state);
+      continue;
+    }
+    MaybeCancelLastSeparator(state);
+    if (has_something && ParseTemplateArgs(state)) {
+      return ParsePrefix(state);
+    } else {
+      break;
+    }
+  }
+  return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <local-source-name>
+static bool ParseUnqualifiedName(State *state) {
+  return (ParseOperatorName(state) ||
+          ParseCtorDtorName(state) ||
+          ParseSourceName(state) ||
+          ParseLocalSourceName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+  State copy = *state;
+  int length = -1;
+  if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+//   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+//   http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+// If "number_out" is non-null, then *number_out is set to the value of the
+// parsed number on success.
+static bool ParseNumber(State *state, int *number_out) {
+  int sign = 1;
+  if (ParseOneCharToken(state, 'n')) {
+    sign = -1;
+  }
+  const char *p = state->mangled_cur;
+  int number = 0;
+  for (;*p != '\0'; ++p) {
+    if (IsDigit(*p)) {
+      number = number * 10 + (*p - '0');
+    } else {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    if (number_out != NULL) {
+      *number_out = number * sign;
+    }
+    return true;
+  }
+  return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// hexadecimal string.
+static bool ParseFloatNumber(State *state) {
+  const char *p = state->mangled_cur;
+  for (;*p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    return true;
+  }
+  return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// using digits and upper case letters
+static bool ParseSeqId(State *state) {
+  const char *p = state->mangled_cur;
+  for (;*p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    return true;
+  }
+  return false;
+}
+
+// <identifier> ::= <unqualified source code identifier> (of given length)
+static bool ParseIdentifier(State *state, int length) {
+  if (length == -1 ||
+      !AtLeastNumCharsRemaining(state->mangled_cur, length)) {
+    return false;
+  }
+  if (IdentifierIsAnonymousNamespace(state, length)) {
+    MaybeAppend(state, "(anonymous namespace)");
+  } else {
+    MaybeAppendWithLength(state, state->mangled_cur, length);
+  }
+  state->mangled_cur += length;
+  return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+//                 ::= cv <type>  # (cast)
+//                 ::= v  <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state) {
+  if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
+    return false;
+  }
+  // First check with "cv" (cast) case.
+  State copy = *state;
+  if (ParseTwoCharToken(state, "cv") &&
+      MaybeAppend(state, "operator ") &&
+      EnterNestedName(state) &&
+      ParseType(state) &&
+      LeaveNestedName(state, copy.nest_level)) {
+    return true;
+  }
+  *state = copy;
+
+  // Then vendor extended operators.
+  if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") &&
+      ParseSourceName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Other operator names should start with a lower alphabet followed
+  // by a lower/upper alphabet.
+  if (!(IsLower(state->mangled_cur[0]) &&
+        IsAlpha(state->mangled_cur[1]))) {
+    return false;
+  }
+  // We may want to perform a binary search if we really need speed.
+  const AbbrevPair *p;
+  for (p = kOperatorList; p->abbrev != NULL; ++p) {
+    if (state->mangled_cur[0] == p->abbrev[0] &&
+        state->mangled_cur[1] == p->abbrev[1]) {
+      MaybeAppend(state, "operator");
+      if (IsLower(*p->real_name)) {  // new, delete, etc.
+        MaybeAppend(state, " ");
+      }
+      MaybeAppend(state, p->real_name);
+      state->mangled_cur += 2;
+      return true;
+    }
+  }
+  return false;
+}
+
+// <special-name> ::= TV <type>
+//                ::= TT <type>
+//                ::= TI <type>
+//                ::= TS <type>
+//                ::= Tc <call-offset> <call-offset> <(base) encoding>
+//                ::= GV <(object) name>
+//                ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+//                ::= TC <type> <(offset) number> _ <(base) type>
+//                ::= TF <type>
+//                ::= TJ <type>
+//                ::= GR <name>
+//                ::= GA <encoding>
+//                ::= Th <call-offset> <(base) encoding>
+//                ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces.  The are special data.
+static bool ParseSpecialName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'T') &&
+      ParseCharClass(state, "VTIS") &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "GV") &&
+      ParseName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
+      ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // G++ extensions
+  if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
+      ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
+      DisableAppend(state) &&
+      ParseType(state)) {
+    RestoreAppend(state, copy.append);
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'h') &&
+      ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'v') &&
+      ParseVOffset(state) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  *state = copy;
+
+  return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+  return ParseNumber(state, NULL);
+}
+
+// <v-offset>  ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+  State copy = *state;
+  if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
+      ParseNumber(state, NULL)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3
+//                  ::= D0 | D1 | D2
+static bool ParseCtorDtorName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'C') &&
+      ParseCharClass(state, "123")) {
+    const char * const prev_name = state->prev_name;
+    const int prev_name_length = state->prev_name_length;
+    MaybeAppendWithLength(state, prev_name, prev_name_length);
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'D') &&
+      ParseCharClass(state, "012")) {
+    const char * const prev_name = state->prev_name;
+    const int prev_name_length = state->prev_name_length;
+    MaybeAppend(state, "~");
+    MaybeAppendWithLength(state, prev_name, prev_name_length);
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+//        ::= P <type>   # pointer-to
+//        ::= R <type>   # reference-to
+//        ::= O <type>   # rvalue reference-to (C++0x)
+//        ::= C <type>   # complex pair (C 2000)
+//        ::= G <type>   # imaginary (C 2000)
+//        ::= U <source-name> <type>  # vendor extended type qualifier
+//        ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-template-param> <template-args>
+//        ::= <template-param>
+//        ::= <substitution>
+//        ::= Dp <type>          # pack expansion of (C++0x)
+//        ::= Dt <expression> E  # decltype of an id-expression or class
+//                               # member access (C++0x)
+//        ::= DT <expression> E  # decltype of an expression (C++0x)
+//
+static bool ParseType(State *state) {
+  // We should check CV-qualifers, and PRGC things first.
+  State copy = *state;
+  if (ParseCVQualifiers(state) && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseCharClass(state, "OPRCG") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
+      ParseExpression(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseBuiltinType(state) ||
+      ParseFunctionType(state) ||
+      ParseClassEnumType(state) ||
+      ParseArrayType(state) ||
+      ParsePointerToMemberType(state) ||
+      ParseSubstitution(state)) {
+    return true;
+  }
+
+  if (ParseTemplateTemplateParam(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Less greedy than <template-template-param> <template-args>.
+  if (ParseTemplateParam(state)) {
+    return true;
+  }
+
+  return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// ParseType().
+static bool ParseCVQualifiers(State *state) {
+  int num_cv_qualifiers = 0;
+  num_cv_qualifiers += ParseOneCharToken(state, 'r');
+  num_cv_qualifiers += ParseOneCharToken(state, 'V');
+  num_cv_qualifiers += ParseOneCharToken(state, 'K');
+  return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.
+//                ::= u <source-name>
+static bool ParseBuiltinType(State *state) {
+  const AbbrevPair *p;
+  for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) {
+    if (state->mangled_cur[0] == p->abbrev[0]) {
+      MaybeAppend(state, p->real_name);
+      ++state->mangled_cur;
+      return true;
+    }
+  }
+
+  State copy = *state;
+  if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <function-type> ::= F [Y] <bare-function-type> E
+static bool ParseFunctionType(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'F') &&
+      Optional(ParseOneCharToken(state, 'Y')) &&
+      ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+  State copy = *state;
+  DisableAppend(state);
+  if (OneOrMore(ParseType, state)) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "()");
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+  return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+//              ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'M') && ParseType(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <template-param> ::= T_
+//                  ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+  if (ParseTwoCharToken(state, "T_")) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+
+// <template-template-param> ::= <template-param>
+//                           ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+  return (ParseTemplateParam(state) ||
+          ParseSubstitution(state));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+  State copy = *state;
+  DisableAppend(state);
+  if (ParseOneCharToken(state, 'I') &&
+      OneOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "<>");
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <template-arg>  ::= <type>
+//                 ::= <expr-primary>
+//                 ::= I <template-arg>* E        # argument pack
+//                 ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'I') &&
+      ZeroOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseType(state) ||
+      ParseExprPrimary(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <expression> ::= <template-param>
+//              ::= <expr-primary>
+//              ::= <unary operator-name> <expression>
+//              ::= <binary operator-name> <expression> <expression>
+//              ::= <trinary operator-name> <expression> <expression>
+//                  <expression>
+//              ::= st <type>
+//              ::= sr <type> <unqualified-name> <template-args>
+//              ::= sr <type> <unqualified-name>
+static bool ParseExpression(State *state) {
+  if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOperatorName(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOperatorName(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOperatorName(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "st") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
+      ParseUnqualifiedName(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+//                ::= L <type> <(value) float> E
+//                ::= L <mangled-name> E
+//                // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+//                ::= LZ <encoding> E
+static bool ParseExprPrimary(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+      ParseNumber(state, NULL) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+      ParseFloatNumber(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  return false;
+}
+
+// <local-name> := Z <(function) encoding> E <(entity) name>
+//                 [<discriminator>]
+//              := Z <(function) encoding> E s [<discriminator>]
+static bool ParseLocalName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+      ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") &&
+      ParseName(state) && Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+      ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <substitution> ::= S_
+//                ::= S <seq-id> _
+//                ::= St, etc.
+static bool ParseSubstitution(State *state) {
+  if (ParseTwoCharToken(state, "S_")) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+  *state = copy;
+
+  // Expand abbreviations like "St" => "std".
+  if (ParseOneCharToken(state, 'S')) {
+    const AbbrevPair *p;
+    for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
+      if (state->mangled_cur[0] == p->abbrev[1]) {
+        MaybeAppend(state, "std");
+        if (p->real_name[0] != '\0') {
+          MaybeAppend(state, "::");
+          MaybeAppend(state, p->real_name);
+        }
+        ++state->mangled_cur;
+        return true;
+      }
+    }
+  }
+  *state = copy;
+  return false;
+}
+
+// Parse <mangled-name>, optionally followed by either a function-clone suffix
+// or version suffix.  Returns true only if all of "mangled_cur" was consumed.
+static bool ParseTopLevelMangledName(State *state) {
+  if (ParseMangledName(state)) {
+    if (state->mangled_cur[0] != '\0') {
+      // Drop trailing function clone suffix, if any.
+      if (IsFunctionCloneSuffix(state->mangled_cur)) {
+        return true;
+      }
+      // Append trailing version suffix if any.
+      // ex. _Z3foo@@GLIBCXX_3.4
+      if (state->mangled_cur[0] == '@') {
+        MaybeAppend(state, state->mangled_cur);
+        return true;
+      }
+      return false;  // Unconsumed suffix.
+    }
+    return true;
+  }
+  return false;
+}
+
+// The demangler entry point.
+bool Demangle(const char *mangled, char *out, int out_size) {
+  State state;
+  InitState(&state, mangled, out, out_size);
+  return ParseTopLevelMangledName(&state) && !state.overflowed;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/base/third_party/symbolize/demangle.h b/base/third_party/symbolize/demangle.h
new file mode 100644
index 0000000..9c75915
--- /dev/null
+++ b/base/third_party/symbolize/demangle.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces.  We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling.  More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments.  It just skips them.  However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name  | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv         | f()           | f()
+// | _Z1fi         | f()           | f(int)
+// | _Z3foo3bar    | foo()         | foo(bar)
+// | _Z1fIiEvi     | f<>()         | void f<int>(int)
+// | _ZN1N1fE      | N::f          | N::f
+// | _ZN3Foo3BarEv | Foo::Bar()    | Foo::Bar()
+// | _Zrm1XS_"     | operator%()   | operator%(X, X)
+// | _ZN3FooC1Ev   | Foo::Foo()    | Foo::Foo()
+// | _Z1fSs        | f()           | f(std::basic_string<char,
+// |               |               |   std::char_traits<char>,
+// |               |               |   std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef BASE_DEMANGLE_H_
+#define BASE_DEMANGLE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Demangle "mangled".  On success, return true and write the
+// demangled symbol name to "out".  Otherwise, return false.
+// "out" is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_DEMANGLE_H_
diff --git a/base/third_party/symbolize/glog/logging.h b/base/third_party/symbolize/glog/logging.h
new file mode 100644
index 0000000..a42c306
--- /dev/null
+++ b/base/third_party/symbolize/glog/logging.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Empty.
diff --git a/base/third_party/symbolize/glog/raw_logging.h b/base/third_party/symbolize/glog/raw_logging.h
new file mode 100644
index 0000000..f5515c4
--- /dev/null
+++ b/base/third_party/symbolize/glog/raw_logging.h
@@ -0,0 +1,6 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#define WARNING 1;
+#define RAW_LOG(severity, ...);  // Do nothing.
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
new file mode 100644
index 0000000..b25f747
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.cc
@@ -0,0 +1,848 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+// Stack-footprint reduction work done by Raksit Ashok
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks.  We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym)  = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym)  = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses
+// some functions which are not guaranteed to be so, such as memchr()
+// and memmove().  We assume they are async-signal-safe.
+//
+// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
+// macro to add platform specific defines (e.g. OS_OPENBSD).
+
+#ifdef GLOG_BUILD_CONFIG_INCLUDE
+#include GLOG_BUILD_CONFIG_INCLUDE
+#endif  // GLOG_BUILD_CONFIG_INCLUDE
+
+#include "utilities.h"
+
+#if defined(HAVE_SYMBOLIZE)
+
+#include <limits>
+
+#include "symbolize.h"
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe.  Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+
+// A wrapper for abort() to make it callable in ? :.
+static int AssertFail() {
+  abort();
+  return 0;  // Should not reach.
+}
+
+#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
+
+static SymbolizeCallback g_symbolize_callback = NULL;
+void InstallSymbolizeCallback(SymbolizeCallback callback) {
+  g_symbolize_callback = callback;
+}
+
+static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
+    NULL;
+void InstallSymbolizeOpenObjectFileCallback(
+    SymbolizeOpenObjectFileCallback callback) {
+  g_symbolize_open_object_file_callback = callback;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
+  char demangled[256];  // Big enough for sane demangled symbols.
+  if (Demangle(out, demangled, sizeof(demangled))) {
+    // Demangling succeeded. Copy to out if the space allows.
+    size_t len = strlen(demangled);
+    if (len + 1 <= (size_t)out_size) {  // +1 for '\0'.
+      SAFE_ASSERT(len < sizeof(demangled));
+      memmove(out, demangled, len + 1);
+    }
+  }
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#if defined(__ELF__)
+
+#include <dlfcn.h>
+#if defined(OS_OPENBSD)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "symbolize.h"
+#include "config.h"
+#include "glog/raw_logging.h"
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)
+
+_START_GOOGLE_NAMESPACE_
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR.  On
+// success, return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+  SAFE_ASSERT(fd >= 0);
+  SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
+  char *buf0 = reinterpret_cast<char *>(buf);
+  ssize_t num_bytes = 0;
+  while (num_bytes < count) {
+    ssize_t len;
+    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+    if (len < 0) {  // There was an error other than EINTR.
+      return -1;
+    }
+    if (len == 0) {  // Reached EOF.
+      break;
+    }
+    num_bytes += len;
+  }
+  SAFE_ASSERT(num_bytes <= count);
+  return num_bytes;
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf".  On success,
+// return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf,
+                              const size_t count, const off_t offset) {
+  off_t off = lseek(fd, offset, SEEK_SET);
+  if (off == (off_t)-1) {
+    return -1;
+  }
+  return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR.  On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf,
+                                const size_t count, const off_t offset) {
+  ssize_t len = ReadFromOffset(fd, buf, count, offset);
+  return len == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return -1;
+  }
+  if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+    return -1;
+  }
+  return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
+                       ElfW(Word) type, ElfW(Shdr) *out) {
+  // Read at most 16 section headers at a time to save read calls.
+  ElfW(Shdr) buf[16];
+  for (int i = 0; i < sh_num;) {
+    const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+    const ssize_t num_bytes_to_read =
+        (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
+    const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
+                                       sh_offset + i * sizeof(buf[0]));
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
+    for (int j = 0; j < num_headers_in_buf; ++j) {
+      if (buf[j].sh_type == type) {
+        *out = buf[j];
+        return true;
+      }
+    }
+    i += num_headers_in_buf;
+  }
+  return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset = (elf_header.e_shoff +
+                           elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    off_t section_header_offset = (elf_header.e_shoff +
+                                   elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+      return false;
+    }
+    char header_name[kMaxSectionNameLen];
+    if (sizeof(header_name) < name_len) {
+      RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
+              "section will not be found (even if present).", name, name_len);
+      // No point in even trying.
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out->sh_name;
+    ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+    if (n_read == -1) {
+      return false;
+    } else if (n_read != name_len) {
+      // Short read -- name could be at end of file.
+      continue;
+    }
+    if (memcmp(header_name, name, name_len) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc".  On success, return true and write the symbol name
+// to out.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
+           uint64_t symbol_offset, const ElfW(Shdr) *strtab,
+           const ElfW(Shdr) *symtab) {
+  if (symtab == NULL) {
+    return false;
+  }
+  const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+  for (int i = 0; i < num_symbols;) {
+    off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+
+    // If we are reading Elf64_Sym's, we want to limit this array to
+    // 32 elements (to keep stack consumption low), otherwise we can
+    // have a 64 element Elf32_Sym array.
+#if __WORDSIZE == 64
+#define NUM_SYMBOLS 32
+#else
+#define NUM_SYMBOLS 64
+#endif
+
+    // Read at most NUM_SYMBOLS symbols at once to save read() calls.
+    ElfW(Sym) buf[NUM_SYMBOLS];
+    const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+    for (int j = 0; j < num_symbols_in_buf; ++j) {
+      const ElfW(Sym)& symbol = buf[j];
+      uint64_t start_address = symbol.st_value;
+      start_address += symbol_offset;
+      uint64_t end_address = start_address + symbol.st_size;
+      if (symbol.st_value != 0 &&  // Skip null value symbols.
+          symbol.st_shndx != 0 &&  // Skip undefined symbols.
+          start_address <= pc && pc < end_address) {
+        ssize_t len1 = ReadFromOffset(fd, out, out_size,
+                                      strtab->sh_offset + symbol.st_name);
+        if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+          return false;
+        }
+        return true;  // Obtained the symbol name.
+      }
+    }
+    i += num_symbols_in_buf;
+  }
+  return false;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd".  Process
+// both regular and dynamic symbol tables if necessary.  On success,
+// write the symbol name to "out" and return true.  Otherwise, return
+// false.
+static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
+                                    char *out, int out_size,
+                                    uint64_t map_start_address) {
+  // Read the ELF header.
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  uint64_t symbol_offset = 0;
+  if (elf_header.e_type == ET_DYN) {  // DSO needs offset adjustment.
+    symbol_offset = map_start_address;
+  }
+
+  ElfW(Shdr) symtab, strtab;
+
+  // Consult a regular symbol table first.
+  if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+                             SHT_SYMTAB, &symtab)) {
+    if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+                             symtab.sh_link * sizeof(symtab))) {
+      return false;
+    }
+    if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+                   &strtab, &symtab)) {
+      return true;  // Found the symbol in a regular symbol table.
+    }
+  }
+
+  // If the symbol is not found, then consult a dynamic symbol table.
+  if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+                             SHT_DYNSYM, &symtab)) {
+    if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+                             symtab.sh_link * sizeof(symtab))) {
+      return false;
+    }
+    if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+                   &strtab, &symtab)) {
+      return true;  // Found the symbol in a dynamic symbol table.
+    }
+  }
+
+  return false;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+struct FileDescriptor {
+  const int fd_;
+  explicit FileDescriptor(int fd) : fd_(fd) {}
+  ~FileDescriptor() {
+    if (fd_ >= 0) {
+      NO_INTR(close(fd_));
+    }
+  }
+  int get() { return fd_; }
+
+ private:
+  explicit FileDescriptor(const FileDescriptor&);
+  void operator=(const FileDescriptor&);
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+  explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
+    buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
+  }
+
+  // Read '\n'-terminated line from file.  On success, modify "bol"
+  // and "eol", then return true.  Otherwise, return false.
+  //
+  // Note: if the last line doesn't end with '\n', the line will be
+  // dropped.  It's an intentional behavior to make the code simple.
+  bool ReadLine(const char **bol, const char **eol) {
+    if (BufferIsEmpty()) {  // First time.
+      const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+      if (num_bytes <= 0) {  // EOF or error.
+        return false;
+      }
+      eod_ = buf_ + num_bytes;
+      bol_ = buf_;
+    } else {
+      bol_ = eol_ + 1;  // Advance to the next line in the buffer.
+      SAFE_ASSERT(bol_ <= eod_);  // "bol_" can point to "eod_".
+      if (!HasCompleteLine()) {
+        const int incomplete_line_length = eod_ - bol_;
+        // Move the trailing incomplete line to the beginning.
+        memmove(buf_, bol_, incomplete_line_length);
+        // Read text from file and append it.
+        char * const append_pos = buf_ + incomplete_line_length;
+        const int capacity_left = buf_len_ - incomplete_line_length;
+        const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
+                                                 capacity_left);
+        if (num_bytes <= 0) {  // EOF or error.
+          return false;
+        }
+        eod_ = append_pos + num_bytes;
+        bol_ = buf_;
+      }
+    }
+    eol_ = FindLineFeed();
+    if (eol_ == NULL) {  // '\n' not found.  Malformed line.
+      return false;
+    }
+    *eol_ = '\0';  // Replace '\n' with '\0'.
+
+    *bol = bol_;
+    *eol = eol_;
+    return true;
+  }
+
+  // Beginning of line.
+  const char *bol() {
+    return bol_;
+  }
+
+  // End of line.
+  const char *eol() {
+    return eol_;
+  }
+
+ private:
+  explicit LineReader(const LineReader&);
+  void operator=(const LineReader&);
+
+  char *FindLineFeed() {
+    return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+  }
+
+  bool BufferIsEmpty() {
+    return buf_ == eod_;
+  }
+
+  bool HasCompleteLine() {
+    return !BufferIsEmpty() && FindLineFeed() != NULL;
+  }
+
+  const int fd_;
+  char * const buf_;
+  const int buf_len_;
+  char *bol_;
+  char *eol_;
+  const char *eod_;  // End of data in "buf_".
+};
+}  // namespace
+
+// Place the hex number read from "start" into "*hex".  The pointer to
+// the first non-hex character or "end" is returned.
+static char *GetHex(const char *start, const char *end, uint64_t *hex) {
+  *hex = 0;
+  const char *p;
+  for (p = start; p < end; ++p) {
+    int ch = *p;
+    if ((ch >= '0' && ch <= '9') ||
+        (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
+      *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+    } else {  // Encountered the first non-hex character.
+      break;
+    }
+  }
+  SAFE_ASSERT(p <= end);
+  return const_cast<char *>(p);
+}
+
+// Searches for the object file (from /proc/self/maps) that contains
+// the specified pc.  If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file.  If the object
+// file is opened successfully, returns the file descriptor.  Otherwise,
+// returns -1.  |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
+static ATTRIBUTE_NOINLINE int
+OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
+                                             uint64_t &start_address,
+                                             uint64_t &base_address,
+                                             char *out_file_name,
+                                             int out_file_name_size) {
+  int object_fd;
+
+  // Open /proc/self/maps.
+  int maps_fd;
+  NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
+  FileDescriptor wrapped_maps_fd(maps_fd);
+  if (wrapped_maps_fd.get() < 0) {
+    return -1;
+  }
+
+  // Iterate over maps and look for the map containing the pc.  Then
+  // look into the symbol tables inside.
+  char buf[1024];  // Big enough for line of sane /proc/self/maps
+  int num_maps = 0;
+  LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+  while (true) {
+    num_maps++;
+    const char *cursor;
+    const char *eol;
+    if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.
+      return -1;
+    }
+
+    // Start parsing line in /proc/self/maps.  Here is an example:
+    //
+    // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat
+    //
+    // We want start address (08048000), end address (0804c000), flags
+    // (r-xp) and file name (/bin/cat).
+
+    // Read start address.
+    cursor = GetHex(cursor, eol, &start_address);
+    if (cursor == eol || *cursor != '-') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip '-'.
+
+    // Read end address.
+    uint64_t end_address;
+    cursor = GetHex(cursor, eol, &end_address);
+    if (cursor == eol || *cursor != ' ') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Check start and end addresses.
+    if (!(start_address <= pc && pc < end_address)) {
+      continue;  // We skip this map.  PC isn't in this map.
+    }
+
+    // Read flags.  Skip flags until we encounter a space or eol.
+    const char * const flags_start = cursor;
+    while (cursor < eol && *cursor != ' ') {
+      ++cursor;
+    }
+    // We expect at least four letters for flags (ex. "r-xp").
+    if (cursor == eol || cursor < flags_start + 4) {
+      return -1;  // Malformed line.
+    }
+
+    // Check flags.  We are only interested in "r-x" maps.
+    if (memcmp(flags_start, "r-x", 3) != 0) {  // Not a "r-x" map.
+      continue;  // We skip this map.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Read file offset.
+    uint64_t file_offset;
+    cursor = GetHex(cursor, eol, &file_offset);
+    if (cursor == eol || *cursor != ' ') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Don't subtract 'start_address' from the first entry:
+    // * If a binary is compiled w/o -pie, then the first entry in
+    //   process maps is likely the binary itself (all dynamic libs
+    //   are mapped higher in address space). For such a binary,
+    //   instruction offset in binary coincides with the actual
+    //   instruction address in virtual memory (as code section
+    //   is mapped to a fixed memory range).
+    // * If a binary is compiled with -pie, all the modules are
+    //   mapped high at address space (in particular, higher than
+    //   shadow memory of the tool), so the module can't be the
+    //   first entry.
+    base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
+
+    // Skip to file name.  "cursor" now points to dev.  We need to
+    // skip at least two spaces for dev and inode.
+    int num_spaces = 0;
+    while (cursor < eol) {
+      if (*cursor == ' ') {
+        ++num_spaces;
+      } else if (num_spaces >= 2) {
+        // The first non-space character after skipping two spaces
+        // is the beginning of the file name.
+        break;
+      }
+      ++cursor;
+    }
+    if (cursor == eol) {
+      return -1;  // Malformed line.
+    }
+
+    // Finally, "cursor" now points to file name of our interest.
+    NO_INTR(object_fd = open(cursor, O_RDONLY));
+    if (object_fd < 0) {
+      // Failed to open object file.  Copy the object file name to
+      // |out_file_name|.
+      strncpy(out_file_name, cursor, out_file_name_size);
+      // Making sure |out_file_name| is always null-terminated.
+      out_file_name[out_file_name_size - 1] = '\0';
+      return -1;
+    }
+    return object_fd;
+  }
+}
+
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+  // Make sure we can write at least one NUL byte.
+  size_t n = 1;
+  if (n > sz)
+    return NULL;
+
+  if (base < 2 || base > 16) {
+    buf[0] = '\000';
+    return NULL;
+  }
+
+  char *start = buf;
+
+  uintptr_t j = i;
+
+  // Handle negative numbers (only for base 10).
+  if (i < 0 && base == 10) {
+    j = -i;
+
+    // Make sure we can write the '-' character.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+    *start++ = '-';
+  }
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  char *ptr = start;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+
+    // Output the next digit.
+    *ptr++ = "0123456789abcdef"[j % base];
+    j /= base;
+
+    if (padding > 0)
+      padding--;
+  } while (j > 0 || padding > 0);
+
+  // Terminate the output with a NUL character.
+  *ptr = '\000';
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible "-" sign).
+  while (--ptr > start) {
+    char ch = *ptr;
+    *ptr = *start;
+    *start++ = ch;
+  }
+  return buf;
+}
+
+// Safely appends string |source| to string |dest|.  Never writes past the
+// buffer size |dest_size| and guarantees that |dest| is null-terminated.
+void SafeAppendString(const char* source, char* dest, int dest_size) {
+  int dest_string_length = strlen(dest);
+  SAFE_ASSERT(dest_string_length < dest_size);
+  dest += dest_string_length;
+  dest_size -= dest_string_length;
+  strncpy(dest, source, dest_size);
+  // Making sure |dest| is always null-terminated.
+  dest[dest_size - 1] = '\0';
+}
+
+// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
+// Never writes past the buffer size |dest_size| and guarantees that |dest| is
+// null-terminated.
+void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
+  // 64-bit numbers in hex can have up to 16 digits.
+  char buf[17] = {'\0'};
+  SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
+}
+
+// The implementation of our symbolization routine.  If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns true and write the symbol name to "out".
+// Otherwise, returns false. If Callback function is installed via
+// InstallSymbolizeCallback(), the function is also called in this function,
+// and "out" is used as its output.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+                                                    int out_size) {
+  uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
+  uint64_t start_address = 0;
+  uint64_t base_address = 0;
+  int object_fd = -1;
+
+  if (out_size < 1) {
+    return false;
+  }
+  out[0] = '\0';
+  SafeAppendString("(", out, out_size);
+
+  if (g_symbolize_open_object_file_callback) {
+    object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
+                                                      base_address, out + 1,
+                                                      out_size - 1);
+  } else {
+    object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
+                                                             base_address,
+                                                             out + 1,
+                                                             out_size - 1);
+  }
+
+  // Check whether a file name was returned.
+  if (object_fd < 0) {
+    if (out[1]) {
+      // The object file containing PC was determined successfully however the
+      // object file was not opened successfully.  This is still considered
+      // success because the object file name and offset are known and tools
+      // like asan_symbolize.py can be used for the symbolization.
+      out[out_size - 1] = '\0';  // Making sure |out| is always null-terminated.
+      SafeAppendString("+0x", out, out_size);
+      SafeAppendHexNumber(pc0 - base_address, out, out_size);
+      SafeAppendString(")", out, out_size);
+      return true;
+    }
+    // Failed to determine the object file containing PC.  Bail out.
+    return false;
+  }
+  FileDescriptor wrapped_object_fd(object_fd);
+  int elf_type = FileGetElfType(wrapped_object_fd.get());
+  if (elf_type == -1) {
+    return false;
+  }
+  if (g_symbolize_callback) {
+    // Run the call back if it's installed.
+    // Note: relocation (and much of the rest of this code) will be
+    // wrong for prelinked shared libraries and PIE executables.
+    uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+    int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
+                                                 pc, out, out_size,
+                                                 relocation);
+    if (num_bytes_written > 0) {
+      out += num_bytes_written;
+      out_size -= num_bytes_written;
+    }
+  }
+  if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
+                               out, out_size, start_address)) {
+    return false;
+  }
+
+  // Symbolization succeeded.  Now we try to demangle the symbol.
+  DemangleInplace(out, out_size);
+  return true;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+
+#include <dlfcn.h>
+#include <string.h>
+
+_START_GOOGLE_NAMESPACE_
+
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+                                                    int out_size) {
+  Dl_info info;
+  if (dladdr(pc, &info)) {
+    if ((int)strlen(info.dli_sname) < out_size) {
+      strcpy(out, info.dli_sname);
+      // Symbolization succeeded.  Now we try to demangle the symbol.
+      DemangleInplace(out, out_size);
+      return true;
+    }
+  }
+  return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else
+# error BUG: HAVE_SYMBOLIZE was wrongly set
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+bool Symbolize(void *pc, char *out, int out_size) {
+  SAFE_ASSERT(out_size >= 0);
+  return SymbolizeAndDemangle(pc, out, out_size);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else  /* HAVE_SYMBOLIZE */
+
+#include <assert.h>
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// TODO: Support other environments.
+bool Symbolize(void *pc, char *out, int out_size) {
+  assert(0);
+  return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
new file mode 100644
index 0000000..f617184
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+//   1. Go through a list of maps in /proc/self/maps and find the map
+//   containing the program counter.
+//
+//   2. Open the mapped file and find a regular symbol table inside.
+//   Iterate over symbols in the symbol table and look for the symbol
+//   containing the program counter.  If such a symbol is found,
+//   obtain the symbol name, and demangle the symbol if possible.
+//   If the symbol isn't found in the regular symbol table (binary is
+//   stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// FailureSignalHandler() in base/google.cc.  Hence it doesn't use
+// malloc() and other unsafe operations.  It should be both
+// thread-safe and async-signal-safe.
+
+#ifndef BASE_SYMBOLIZE_H_
+#define BASE_SYMBOLIZE_H_
+
+#include "utilities.h"
+#include "config.h"
+#include "glog/logging.h"
+
+#ifdef HAVE_SYMBOLIZE
+
+#if defined(__ELF__)  // defined by gcc
+#if defined(__OpenBSD__)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+
+#if !defined(ANDROID)
+#include <link.h>  // For ElfW() macro.
+#endif
+
+// For systems where SIZEOF_VOID_P is not defined, determine it
+// based on __LP64__ (defined by gcc on 64-bit systems)
+#if !defined(SIZEOF_VOID_P)
+# if defined(__LP64__)
+#  define SIZEOF_VOID_P 8
+# else
+#  define SIZEOF_VOID_P 4
+# endif
+#endif
+
+// If there is no ElfW macro, let's define it by ourself.
+#ifndef ElfW
+# if SIZEOF_VOID_P == 4
+#  define ElfW(type) Elf32_##type
+# elif SIZEOF_VOID_P == 8
+#  define ElfW(type) Elf64_##type
+# else
+#  error "Unknown sizeof(void *)"
+# endif
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  /* __ELF__ */
+
+_START_GOOGLE_NAMESPACE_
+
+// Restrictions on the callbacks that follow:
+//  - The callbacks must not use heaps but only use stacks.
+//  - The callbacks must be async-signal-safe.
+
+// Installs a callback function, which will be called right before a symbol name
+// is printed. The callback is intended to be used for showing a file name and a
+// line number preceding a symbol name.
+// "fd" is a file descriptor of the object file containing the program
+// counter "pc". The callback function should write output to "out"
+// and return the size of the output written. On error, the callback
+// function should return -1.
+typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
+                                 uint64 relocation);
+void InstallSymbolizeCallback(SymbolizeCallback callback);
+
+// Installs a callback function, which will be called instead of
+// OpenObjectFileContainingPcAndGetStartAddress.  The callback is expected
+// to searches for the object file (from /proc/self/maps) that contains
+// the specified pc.  If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file.  If the object
+// file is opened successfully, returns the file descriptor.  Otherwise,
+// returns -1.  |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
+typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc,
+                                               uint64_t &start_address,
+                                               uint64_t &base_address,
+                                               char *out_file_name,
+                                               int out_file_name_size);
+void InstallSymbolizeOpenObjectFileCallback(
+    SymbolizeOpenObjectFileCallback callback);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Symbolizes a program counter.  On success, returns true and write the
+// symbol name to "out".  The symbol name is demangled if possible
+// (supports symbols generated by GCC 3.x or newer).  Otherwise,
+// returns false.
+bool Symbolize(void *pc, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_SYMBOLIZE_H_
diff --git a/base/third_party/symbolize/utilities.h b/base/third_party/symbolize/utilities.h
new file mode 100644
index 0000000..0bed526
--- /dev/null
+++ b/base/third_party/symbolize/utilities.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+typedef uint64_t uint64;
+#define HAVE_SYMBOLIZE 1
+#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
diff --git a/base/third_party/valgrind/LICENSE b/base/third_party/valgrind/LICENSE
new file mode 100644
index 0000000..41f677b
--- /dev/null
+++ b/base/third_party/valgrind/LICENSE
@@ -0,0 +1,39 @@
+   Notice that the following BSD-style license applies to the Valgrind header
+   files used by Chromium (valgrind.h and memcheck.h). However, the rest of
+   Valgrind is licensed under the terms of the GNU General Public License,
+   version 2, unless otherwise indicated.
+
+   ----------------------------------------------------------------
+
+   Copyright (C) 2000-2008 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/valgrind/README.chromium b/base/third_party/valgrind/README.chromium
new file mode 100644
index 0000000..56a1cbb
--- /dev/null
+++ b/base/third_party/valgrind/README.chromium
@@ -0,0 +1,11 @@
+Name: valgrind
+URL: http://valgrind.org
+License: BSD
+
+Header files in this directory define runtime macros that determine whether the
+current process is running under Valgrind and tell Memcheck tool about custom
+memory allocators.
+
+These header files were taken from Valgrind source code
+(svn://svn.valgrind.org/valgrind/trunk@11504, dated 21 Jan 2011). The files are
+covered under BSD license as described within.
diff --git a/base/third_party/valgrind/memcheck.h b/base/third_party/valgrind/memcheck.h
new file mode 100644
index 0000000..f59c212
--- /dev/null
+++ b/base/third_party/valgrind/memcheck.h
@@ -0,0 +1,279 @@
+
+/*
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (memcheck.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of MemCheck, a heavyweight Valgrind tool for
+   detecting memory errors.
+
+   Copyright (C) 2000-2010 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (memcheck.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+#ifndef __MEMCHECK_H
+#define __MEMCHECK_H
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query memory permissions
+   inside your own programs.
+
+   See comment near the top of valgrind.h on how to use them.
+*/
+
+#include "valgrind.h"
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { 
+      VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'),
+      VG_USERREQ__MAKE_MEM_UNDEFINED,
+      VG_USERREQ__MAKE_MEM_DEFINED,
+      VG_USERREQ__DISCARD,
+      VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,
+      VG_USERREQ__CHECK_MEM_IS_DEFINED,
+      VG_USERREQ__DO_LEAK_CHECK,
+      VG_USERREQ__COUNT_LEAKS,
+
+      VG_USERREQ__GET_VBITS,
+      VG_USERREQ__SET_VBITS,
+
+      VG_USERREQ__CREATE_BLOCK,
+
+      VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE,
+
+      /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
+      VG_USERREQ__COUNT_LEAK_BLOCKS,
+
+      /* This is just for memcheck's internal use - don't use it */
+      _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR 
+         = VG_USERREQ_TOOL_BASE('M','C') + 256
+   } Vg_MemCheckClientRequest;
+
+
+
+/* Client-code macros to manipulate the state of memory. */
+
+/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len)           \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_NOACCESS,       \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+      
+/* Similarly, mark memory at _qzz_addr as addressable but undefined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len)          \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_UNDEFINED,      \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Similarly, mark memory at _qzz_addr as addressable and defined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len)            \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_DEFINED,        \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is
+   not altered: bytes which are addressable are marked as defined,
+   but those which are not addressable are left unchanged. */
+#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len)     \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,              \
+                            VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Create a block-description handle.  The description is an ascii
+   string which is included in any messages pertaining to addresses
+   within the specified memory range.  Has no other effect on the
+   properties of the memory range. */
+#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc)	   \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,        \
+                            VG_USERREQ__CREATE_BLOCK,              \
+                            (_qzz_addr), (_qzz_len), (_qzz_desc),  \
+                            0, 0)
+
+/* Discard a block-description-handle. Returns 1 for an
+   invalid handle, 0 for a valid handle. */
+#define VALGRIND_DISCARD(_qzz_blkindex)                          \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__DISCARD,                 \
+                            0, (_qzz_blkindex), 0, 0, 0)
+
+
+/* Client-code macros to check the state of memory. */
+
+/* Check that memory at _qzz_addr is addressable for _qzz_len bytes.
+   If suitable addressibility is not established, Valgrind prints an
+   error message and returns the address of the first offending byte.
+   Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len)      \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                             \
+                            VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,  \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Check that memory at _qzz_addr is addressable and defined for
+   _qzz_len bytes.  If suitable addressibility and definedness are not
+   established, Valgrind prints an error message and returns the
+   address of the first offending byte.  Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len)        \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                           \
+                            VG_USERREQ__CHECK_MEM_IS_DEFINED,    \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Use this macro to force the definedness and addressibility of an
+   lvalue to be checked.  If suitable addressibility and definedness
+   are not established, Valgrind prints an error message and returns
+   the address of the first offending byte.  Otherwise it returns
+   zero. */
+#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue)                \
+   VALGRIND_CHECK_MEM_IS_DEFINED(                                \
+      (volatile unsigned char *)&(__lvalue),                     \
+                      (unsigned long)(sizeof (__lvalue)))
+
+
+/* Do a full memory leak check (like --leak-check=full) mid-execution. */
+#define VALGRIND_DO_LEAK_CHECK                                   \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            0, 0, 0, 0, 0);                      \
+   }
+
+/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
+#define VALGRIND_DO_QUICK_LEAK_CHECK				 \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            1, 0, 0, 0, 0);                      \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed)     \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAKS,                  \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAK_BLOCKS,            \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+
+/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it
+   into the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zzsrc/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes)                \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                          \
+                                    VG_USERREQ__GET_VBITS,      \
+                                    (const char*)(zza),         \
+                                    (char*)(zzvbits),           \
+                                    (zznbytes), 0, 0)
+
+/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it
+   from the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zza/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes)                \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                          \
+                                    VG_USERREQ__SET_VBITS,      \
+                                    (const char*)(zza),         \
+                                    (const char*)(zzvbits),     \
+                                    (zznbytes), 0, 0 )
+
+#endif
+
diff --git a/base/third_party/valgrind/valgrind.h b/base/third_party/valgrind/valgrind.h
new file mode 100644
index 0000000..0bae0aa
--- /dev/null
+++ b/base/third_party/valgrind/valgrind.h
@@ -0,0 +1,4792 @@
+/* -*- c -*-
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (valgrind.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2010 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (valgrind.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query Valgrind's 
+   execution inside your own programs.
+
+   The resulting executables will still run without Valgrind, just a
+   little bit more slowly than they otherwise would, but otherwise
+   unchanged.  When not running on valgrind, each client request
+   consumes very few (eg. 7) instructions, so the resulting performance
+   loss is negligible unless you plan to execute client requests
+   millions of times per second.  Nevertheless, if that is still a
+   problem, you can compile with the NVALGRIND symbol defined (gcc
+   -DNVALGRIND) so that client requests are not even compiled in.  */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+
+/* ------------------------------------------------------------------ */
+/* VERSION NUMBER OF VALGRIND                                         */
+/* ------------------------------------------------------------------ */
+
+/* Specify Valgrind's version number, so that user code can
+   conditionally compile based on our version number.  Note that these
+   were introduced at version 3.6 and so do not exist in version 3.5
+   or earlier.  The recommended way to use them to check for "version
+   X.Y or later" is (eg)
+
+#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__)   \
+    && (__VALGRIND_MAJOR__ > 3                                   \
+        || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
+*/
+#define __VALGRIND_MAJOR__    3
+#define __VALGRIND_MINOR__    6
+
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi.  So
+   we can't use C++ style "//" comments nor the "asm" keyword (instead
+   use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is.  Note
+   that in this file we're using the compiler's CPP symbols for
+   identifying architectures, which are different to the ones we use
+   within the rest of Valgrind.  Note, __powerpc__ is active for both
+   32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+   latter (on Linux, that is).
+
+   Misc note: how to find out what's predefined in gcc by default:
+   gcc -Wp,-dM somefile.c
+*/
+#undef PLAT_ppc64_aix5
+#undef PLAT_ppc32_aix5
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_win32
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+
+#if defined(_AIX) && defined(__64BIT__)
+#  define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+#  define PLAT_ppc32_aix5 1
+#elif defined(__APPLE__) && defined(__i386__)
+#  define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+#  define PLAT_amd64_darwin 1
+#elif defined(__MINGW32__) || defined(__CYGWIN32__) || defined(_WIN32) && defined(_M_IX86)
+#  define PLAT_x86_win32 1
+#elif defined(__linux__) && defined(__i386__)
+#  define PLAT_x86_linux 1
+#elif defined(__linux__) && defined(__x86_64__)
+#  define PLAT_amd64_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
+#  define PLAT_ppc32_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
+#  define PLAT_ppc64_linux 1
+#elif defined(__linux__) && defined(__arm__)
+#  define PLAT_arm_linux 1
+#else
+/* If we're not compiling for our target platform, don't generate
+   any inline asms.  */
+#  if !defined(NVALGRIND)
+#    define NVALGRIND 1
+#  endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS.  There is nothing */
+/* in here of use to end-users -- skip to the next section.           */
+/* ------------------------------------------------------------------ */
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+   from the compiled code (analogous to NDEBUG's effects on
+   assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+   {                                                              \
+      (_zzq_rlval) = (_zzq_default);                              \
+   }
+
+#else  /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+   spots and handles magically.  Don't look too closely at them as
+   they will rot your brain.
+
+   The assembly code sequences for all architectures is in this one
+   file.  This is because this file must be stand-alone, and we don't
+   want to have multiple files.
+
+   For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+   value gets put in the return slot, so that everything works when
+   this is executed not under Valgrind.  Args are passed in a memory
+   block, and so there's no intrinsic limit to the number that could
+   be passed, but it's currently five.
+   
+   The macro args are: 
+      _zzq_rlval    result lvalue
+      _zzq_default  default value (result returned when running on real CPU)
+      _zzq_request  request code
+      _zzq_arg1..5  request params
+
+   The other two macros are used to support function wrapping, and are
+   a lot simpler.  VALGRIND_GET_NR_CONTEXT returns the value of the
+   guest's NRADDR pseudo-register and whatever other information is
+   needed to safely run the call original from the wrapper: on
+   ppc64-linux, the R2 value at the divert point is also needed.  This
+   information is abstracted into a user-visible type, OrigFn.
+
+   VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+   guest, but guarantees that the branch instruction will not be
+   redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+   branch-and-link-to-r11.  VALGRIND_CALL_NOREDIR is just text, not a
+   complete inline asm, since it needs to be combined with more magic
+   inline asm stuff to be useful.
+*/
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)  \
+    ||  (defined(PLAT_x86_win32) && defined(__GNUC__))
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "roll $3,  %%edi ; roll $13, %%edi\n\t"      \
+                     "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned int _zzq_args[6];                           \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EDX = client_request ( %EAX ) */         \
+                     "xchgl %%ebx,%%ebx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EAX = guest_NRADDR */                    \
+                     "xchgl %%ecx,%%ecx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%EAX */                     \
+                     "xchgl %%edx,%%edx\n\t"
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */
+
+/* ------------------------- x86-Win32 ------------------------- */
+
+#if defined(PLAT_x86_win32) && !defined(__GNUC__)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#if defined(_MSC_VER)
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     __asm rol edi, 3  __asm rol edi, 13          \
+                     __asm rol edi, 29 __asm rol edi, 19
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile uintptr_t _zzq_args[6];                              \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (uintptr_t)(_zzq_request);                     \
+    _zzq_args[1] = (uintptr_t)(_zzq_arg1);                        \
+    _zzq_args[2] = (uintptr_t)(_zzq_arg2);                        \
+    _zzq_args[3] = (uintptr_t)(_zzq_arg3);                        \
+    _zzq_args[4] = (uintptr_t)(_zzq_arg4);                        \
+    _zzq_args[5] = (uintptr_t)(_zzq_arg5);                        \
+    __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default  \
+            __SPECIAL_INSTRUCTION_PREAMBLE                        \
+            /* %EDX = client_request ( %EAX ) */                  \
+            __asm xchg ebx,ebx                                    \
+            __asm mov _zzq_result, edx                            \
+    }                                                             \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm { __SPECIAL_INSTRUCTION_PREAMBLE                        \
+            /* %EAX = guest_NRADDR */                             \
+            __asm xchg ecx,ecx                                    \
+            __asm mov __addr, eax                                 \
+    }                                                             \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX ERROR
+
+#else
+#error Unsupported compiler.
+#endif
+
+#endif /* PLAT_x86_win32 */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rolq $3,  %%rdi ; rolq $13, %%rdi\n\t"      \
+                     "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned long long int _zzq_args[6];                 \
+    volatile unsigned long long int _zzq_result;                  \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RDX = client_request ( %RAX ) */         \
+                     "xchgq %%rbx,%%rbx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RAX = guest_NRADDR */                    \
+                     "xchgq %%rcx,%%rcx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_RAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%RAX */                     \
+                     "xchgq %%rdx,%%rdx\n\t"
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[6];                          \
+             unsigned int  _zzq_result;                           \
+             unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 3,%1\n\t" /*default*/                    \
+                     "mr 4,%2\n\t" /*ptr*/                        \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"     /*result*/                     \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_default), "b" (_zzq_ptr)         \
+                     : "cc", "memory", "r3", "r4");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[6];                \
+    register unsigned long long int  _zzq_result __asm__("r3");   \
+    register unsigned long long int* _zzq_ptr __asm__("r4");      \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1"                                   \
+                     : "=r" (_zzq_result)                         \
+                     : "0" (_zzq_default), "r" (_zzq_ptr)         \
+                     : "cc", "memory");                           \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr __asm__("r3");         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+            "mov r12, r12, ror #3  ; mov r12, r12, ror #13 \n\t"  \
+            "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  { volatile unsigned int  _zzq_args[6];                          \
+    volatile unsigned int  _zzq_result;                           \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile("mov r3, %1\n\t" /*default*/                 \
+                     "mov r4, %2\n\t" /*ptr*/                     \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = client_request ( R4 ) */             \
+                     "orr r10, r10, r10\n\t"                      \
+                     "mov %0, r3"     /*result*/                  \
+                     : "=r" (_zzq_result)                         \
+                     : "r" (_zzq_default), "r" (&_zzq_args[0])    \
+                     : "cc","memory", "r3", "r4");                \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = guest_NRADDR */                      \
+                     "orr r11, r11, r11\n\t"                      \
+                     "mov %0, r3"                                 \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                    \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R4 */        \
+                     "orr r12, r12, r12\n\t"
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+      unsigned int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[7];                          \
+    register unsigned int  _zzq_result;                           \
+    register unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_args[6] = (unsigned int)(_zzq_default);                  \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "lwz 3, 24(4)\n\t"                           \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[7];                \
+    register unsigned long long int  _zzq_result;                 \
+    register unsigned long long int* _zzq_ptr;                    \
+    _zzq_args[0] = (unsigned int long long)(_zzq_request);        \
+    _zzq_args[1] = (unsigned int long long)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned int long long)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned int long long)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned int long long)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned int long long)(_zzq_arg5);           \
+    _zzq_args[6] = (unsigned int long long)(_zzq_default);        \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "ld 3, 48(4)\n\t"                            \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_aix5 */
+
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING.  This is all very        */
+/* ugly.  It's the least-worst tradeoff I can think of.               */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+   guaranteed-no-redirection macros, so as to get from function
+   wrappers to the functions they are wrapping.  The whole point is to
+   construct standard call sequences, but to do the call itself with a
+   special no-redirect call pseudo-instruction that the JIT
+   understands and handles specially.  This section is long and
+   repetitious, and I can't see a way to make it shorter.
+
+   The naming scheme is as follows:
+
+      CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+   'W' stands for "word" and 'v' for "void".  Hence there are
+   different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+   and for each, the possibility of returning a word-typed result, or
+   no result.
+*/
+
+/* Use these to write the name of your wrapper.  NOTE: duplicates
+   VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+   args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname)                    \
+   VG_CONCAT4(_vgwZU_,soname,_,fnname)
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname)                    \
+   VG_CONCAT4(_vgwZZ_,soname,_,fnname)
+
+/* Use this macro from within a wrapper function to collect the
+   context (address and possibly other info) of the original function.
+   Once you have that you can then use it in one of the CALL_FN_
+   macros.  The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval)  VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Derivatives of the main macros below, for calling functions
+   returning void. */
+
+#define CALL_FN_v_v(fnptr)                                        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1)                                  \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2)                            \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3)                      \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4)                \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
+
+#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5)             \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
+
+#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6)        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0)
+
+#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7)   \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
+
+/* These regs are trashed by the hidden call.  No need to mention eax
+   as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "pushl 48(%%eax)\n\t"                                    \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi",       \
+                            "rdi", "r8", "r9", "r10", "r11"
+
+/* This is all pretty complex.  It's so as to make stack unwinding
+   work reliably.  See bug 243270.  The basic problem is the sub and
+   add of 128 of %rsp in all of the following macros.  If gcc believes
+   the CFA is in %rsp, then unwinding may fail, because what's at the
+   CFA is not what gcc "expected" when it constructs the CFIs for the
+   places where the macros are instantiated.
+
+   But we can't just add a CFI annotation to increase the CFA offset
+   by 128, to match the sub of 128 from %rsp, because we don't know
+   whether gcc has chosen %rsp as the CFA at that point, or whether it
+   has chosen some other register (eg, %rbp).  In the latter case,
+   adding a CFI annotation to change the CFA offset is simply wrong.
+
+   So the solution is to get hold of the CFA using
+   __builtin_dwarf_cfa(), put it in a known register, and add a
+   CFI annotation to say what the register is.  We choose %rbp for
+   this (perhaps perversely), because:
+
+   (1) %rbp is already subject to unwinding.  If a new register was
+       chosen then the unwinder would have to unwind it in all stack
+       traces, which is expensive, and
+
+   (2) %rbp is already subject to precise exception updates in the
+       JIT.  If a new register was chosen, we'd have to have precise
+       exceptions for it too, which reduces performance of the
+       generated code.
+
+   However .. one extra complication.  We can't just whack the result
+   of __builtin_dwarf_cfa() into %rbp and then add %rbp to the
+   list of trashed registers at the end of the inline assembly
+   fragments; gcc won't allow %rbp to appear in that list.  Hence
+   instead we need to stash %rbp in %r15 for the duration of the asm,
+   and say that %r15 is trashed instead.  gcc seems happy to go with
+   that.
+
+   Oh .. and this all needs to be conditionalised so that it is
+   unchanged from before this commit, when compiled with older gccs
+   that don't support __builtin_dwarf_cfa.  Furthermore, since
+   this header file is freestanding, it has to be independent of
+   config.h, and so the following conditionalisation cannot depend on
+   configure time checks.
+
+   Although it's not clear from
+   'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)',
+   this expression excludes Darwin.
+   .cfi directives in Darwin assembly appear to be completely
+   different and I haven't investigated how they work.
+
+   For even more entertainment value, note we have to use the
+   completely undocumented __builtin_dwarf_cfa(), which appears to
+   really compute the CFA, whereas __builtin_frame_address(0) claims
+   to but actually doesn't.  See
+   https://bugs.kde.org/show_bug.cgi?id=243270#c47
+*/
+#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#  define __FRAME_POINTER                                         \
+      ,"r"(__builtin_dwarf_cfa())
+#  define VALGRIND_CFI_PROLOGUE                                   \
+      "movq %%rbp, %%r15\n\t"                                     \
+      "movq %2, %%rbp\n\t"                                        \
+      ".cfi_remember_state\n\t"                                   \
+      ".cfi_def_cfa rbp, 0\n\t"
+#  define VALGRIND_CFI_EPILOGUE                                   \
+      "movq %%r15, %%rbp\n\t"                                     \
+      ".cfi_restore_state\n\t"
+#else
+#  define __FRAME_POINTER
+#  define VALGRIND_CFI_PROLOGUE
+#  define VALGRIND_CFI_EPILOGUE
+#endif
+
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+   long) == 8. */
+
+/* NB 9 Sept 07.  There is a nasty kludge here in all these CALL_FN_
+   macros.  In order not to trash the stack redzone, we need to drop
+   %rsp by 128 before the hidden call, and restore afterwards.  The
+   nastyness is that it is only by luck that the stack still appears
+   to be unwindable during the hidden call - since then the behaviour
+   of any routine using this macro does not match what the CFI data
+   says.  Sigh.
+
+   Why is this important?  Imagine that a wrapper has a stack
+   allocated local, and passes to the hidden call, a pointer to it.
+   Because gcc does not know about the hidden call, it may allocate
+   that local in the redzone.  Unfortunately the hidden call may then
+   trash it before it comes to use it.  So we must step clear of the
+   redzone, for the duration of the hidden call, to make it safe.
+
+   Probably the same problem afflicts the other redzone-style ABIs too
+   (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is
+   self describing (none of this CFI nonsense) so at least messing
+   with the stack pointer doesn't give a danger of non-unwindable
+   stack. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $8, %%rsp\n"                                       \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $16, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $24, %%rsp\n"                                      \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $32, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $40, %%rsp\n"                                      \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 96(%%rax)\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $48, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+   extern int f9  ( int,int,int,int,int,int,int,int,int );
+   extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+   extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+   extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+   int g9 ( void ) {
+      return f9(11,22,33,44,55,66,77,88,99);
+   }
+   int g10 ( void ) {
+      return f10(11,22,33,44,55,66,77,88,99,110);
+   }
+   int g11 ( void ) {
+      return f11(11,22,33,44,55,66,77,88,99,110,121);
+   }
+   int g12 ( void ) {
+      return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+   }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc32-linux, 
+   sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      _argvec[12] = (unsigned long)arg12;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,20(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14"
+
+/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",  __CALLER_SAVED_REGS         \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #4 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #8 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #12 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "push {r0, r1, r2, r3} \n\t"                             \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #16 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #20 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #24 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #28 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS           \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "ldr r2, [%1, #48] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #32 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "lwz  3," #_n_fr "(1)\n\t"                               \
+         "stw  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t" /* arg2->r4 */                       \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,68(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "ld   3," #_n_fr "(1)\n\t"                               \
+         "std  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_aix5 */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS.               */
+/*                                                                    */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes.  There are many more of these, but most are not
+   exposed to end-user view.  These are the public ones, all of the
+   form 0x1000 + small_number.
+
+   Core ones are in the range 0x00000000--0x0000ffff.  The non-public
+   ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+   embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+   ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+   (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { VG_USERREQ__RUNNING_ON_VALGRIND  = 0x1001,
+          VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+          /* These allow any function to be called from the simulated
+             CPU but run on the real CPU.  Nb: the first arg passed to
+             the function is always the ThreadId of the running
+             thread!  So CLIENT_CALL0 actually requires a 1 arg
+             function, etc. */
+          VG_USERREQ__CLIENT_CALL0 = 0x1101,
+          VG_USERREQ__CLIENT_CALL1 = 0x1102,
+          VG_USERREQ__CLIENT_CALL2 = 0x1103,
+          VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+          /* Can be useful in regression testing suites -- eg. can
+             send Valgrind's output to /dev/null and still count
+             errors. */
+          VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+          /* These are useful and can be interpreted by any tool that
+             tracks malloc() et al, by using vg_replace_malloc.c. */
+          VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+          VG_USERREQ__FREELIKE_BLOCK   = 0x1302,
+          /* Memory pool support. */
+          VG_USERREQ__CREATE_MEMPOOL   = 0x1303,
+          VG_USERREQ__DESTROY_MEMPOOL  = 0x1304,
+          VG_USERREQ__MEMPOOL_ALLOC    = 0x1305,
+          VG_USERREQ__MEMPOOL_FREE     = 0x1306,
+          VG_USERREQ__MEMPOOL_TRIM     = 0x1307,
+          VG_USERREQ__MOVE_MEMPOOL     = 0x1308,
+          VG_USERREQ__MEMPOOL_CHANGE   = 0x1309,
+          VG_USERREQ__MEMPOOL_EXISTS   = 0x130a,
+
+          /* Allow printfs to valgrind log. */
+          /* The first two pass the va_list argument by value, which
+             assumes it is the same size as or smaller than a UWord,
+             which generally isn't the case.  Hence are deprecated.
+             The second two pass the vargs by reference and so are
+             immune to this problem. */
+          /* both :: char* fmt, va_list vargs (DEPRECATED) */
+          VG_USERREQ__PRINTF           = 0x1401,
+          VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+          /* both :: char* fmt, va_list* vargs */
+          VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
+          VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
+
+          /* Stack support. */
+          VG_USERREQ__STACK_REGISTER   = 0x1501,
+          VG_USERREQ__STACK_DEREGISTER = 0x1502,
+          VG_USERREQ__STACK_CHANGE     = 0x1503,
+
+          /* Wine support */
+          VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601,
+
+          /* Querying of debug info. */
+          VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701
+   } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+#  define __extension__ /* */
+#endif
+
+
+/*
+ * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind
+ * client request and whose value equals the client request result.
+ */
+
+#if defined(NVALGRIND)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                               \
+        _zzq_default, _zzq_request,                                    \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)         \
+   (_zzq_default)
+
+#else /*defined(NVALGRIND)*/
+
+#if defined(_MSC_VER)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                                \
+        _zzq_default, _zzq_request,                                     \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)          \
+   (vg_VALGRIND_DO_CLIENT_REQUEST_EXPR((uintptr_t)(_zzq_default),       \
+        (_zzq_request), (uintptr_t)(_zzq_arg1), (uintptr_t)(_zzq_arg2), \
+        (uintptr_t)(_zzq_arg3), (uintptr_t)(_zzq_arg4),                 \
+        (uintptr_t)(_zzq_arg5)))
+
+static __inline unsigned
+vg_VALGRIND_DO_CLIENT_REQUEST_EXPR(uintptr_t _zzq_default,
+                                   unsigned _zzq_request, uintptr_t _zzq_arg1,
+                                   uintptr_t _zzq_arg2, uintptr_t _zzq_arg3,
+                                   uintptr_t _zzq_arg4, uintptr_t _zzq_arg5)
+{
+    unsigned _zzq_rlval;
+    VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request,
+                      _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5);
+    return _zzq_rlval;
+}
+
+#else /*defined(_MSC_VER)*/
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                               \
+        _zzq_default, _zzq_request,                                    \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)         \
+   (__extension__({unsigned int _zzq_rlval;                            \
+    VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request, \
+                _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+    _zzq_rlval;                                                        \
+   }))
+
+#endif /*defined(_MSC_VER)*/
+
+#endif /*defined(NVALGRIND)*/
+
+
+/* Returns the number of Valgrinds this code is running under.  That
+   is, 0 if running natively, 1 if running under Valgrind, 2 if
+   running under Valgrind which is running under another Valgrind,
+   etc. */
+#define RUNNING_ON_VALGRIND                                           \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */,                   \
+                                    VG_USERREQ__RUNNING_ON_VALGRIND,  \
+                                    0, 0, 0, 0, 0)                    \
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+   _qzz_len - 1].  Useful if you are debugging a JITter or some such,
+   since it provides a way to make sure valgrind will retranslate the
+   invalidated area.  Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DISCARD_TRANSLATIONS,  \
+                               _qzz_addr, _qzz_len, 0, 0, 0);     \
+   }
+
+
+/* These requests are for getting Valgrind itself to print something.
+   Possibly with a backtrace.  This is a really ugly hack.  The return value
+   is the number of characters printed, excluding the "**<pid>** " part at the
+   start and the backtrace (if present). */
+
+#if defined(NVALGRIND)
+
+#  define VALGRIND_PRINTF(...)
+#  define VALGRIND_PRINTF_BACKTRACE(...)
+
+#else /* NVALGRIND */
+
+#if !defined(_MSC_VER)
+/* Modern GCC will optimize the static routine out if unused,
+   and unused attribute will shut down warnings about it.  */
+static int VALGRIND_PRINTF(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+#if defined(_MSC_VER)
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (uintptr_t)format,
+                              (uintptr_t)&vargs,
+                              0, 0, 0);
+#else
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+#endif
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#if !defined(_MSC_VER)
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+#if defined(_MSC_VER)
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (uintptr_t)format,
+                              (uintptr_t)&vargs,
+                              0, 0, 0);
+#else
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+#endif
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#endif /* NVALGRIND */
+
+
+/* These requests allow control to move from the simulated CPU to the
+   real CPU, calling an arbitary function.
+   
+   Note that the current ThreadId is inserted as the first argument.
+   So this call:
+
+     VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+   requires f to have this signature:
+
+     Word f(Word tid, Word arg1, Word arg2)
+
+   where "Word" is a word-sized type.
+
+   Note that these client requests are not entirely reliable.  For example,
+   if you call a function with them that subsequently calls printf(),
+   there's a high chance Valgrind will crash.  Generally, your prospects of
+   these working are made higher if the called function does not refer to
+   any global variables, and does not refer to any libc or other functions
+   (printf et al).  Any kind of entanglement with libc or dynamic linking is
+   likely to have a bad outcome, for tricky reasons which we've grappled
+   with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn)                          \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL0,          \
+                               _qyy_fn,                           \
+                               0, 0, 0, 0);                       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1)               \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL1,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, 0, 0, 0);               \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2)    \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL2,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2, 0, 0);       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL3,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2,              \
+                               _qyy_arg3, 0);                     \
+    _qyy_res;                                                     \
+   })
+
+
+/* Counts the number of errors that have been recorded by a tool.  Nb:
+   the tool must record the errors with VG_(maybe_record_error)() or
+   VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS                                     \
+   __extension__                                                  \
+   ({unsigned int _qyy_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__COUNT_ERRORS,          \
+                               0, 0, 0, 0, 0);                    \
+    _qyy_res;                                                     \
+   })
+
+/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
+   when heap blocks are allocated in order to give accurate results.  This
+   happens automatically for the standard allocator functions such as
+   malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
+   delete[], etc.
+
+   But if your program uses a custom allocator, this doesn't automatically
+   happen, and Valgrind will not do as well.  For example, if you allocate
+   superblocks with mmap() and then allocates chunks of the superblocks, all
+   Valgrind's observations will be at the mmap() level and it won't know that
+   the chunks should be considered separate entities.  In Memcheck's case,
+   that means you probably won't get heap block overrun detection (because
+   there won't be redzones marked as unaddressable) and you definitely won't
+   get any leak detection.
+
+   The following client requests allow a custom allocator to be annotated so
+   that it can be handled accurately by Valgrind.
+
+   VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated
+   by a malloc()-like function.  For Memcheck (an illustrative case), this
+   does two things:
+
+   - It records that the block has been allocated.  This means any addresses
+     within the block mentioned in error messages will be
+     identified as belonging to the block.  It also means that if the block
+     isn't freed it will be detected by the leak checker.
+
+   - It marks the block as being addressable and undefined (if 'is_zeroed' is
+     not set), or addressable and defined (if 'is_zeroed' is set).  This
+     controls how accesses to the block by the program are handled.
+   
+   'addr' is the start of the usable block (ie. after any
+   redzone), 'sizeB' is its size.  'rzB' is the redzone size if the allocator
+   can apply redzones -- these are blocks of padding at the start and end of
+   each block.  Adding redzones is recommended as it makes it much more likely
+   Valgrind will spot block overruns.  `is_zeroed' indicates if the memory is
+   zeroed (or filled with another predictable value), as is the case for
+   calloc().
+   
+   VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a
+   heap block -- that will be used by the client program -- is allocated.
+   It's best to put it at the outermost level of the allocator if possible;
+   for example, if you have a function my_alloc() which calls
+   internal_alloc(), and the client request is put inside internal_alloc(),
+   stack traces relating to the heap block will contain entries for both
+   my_alloc() and internal_alloc(), which is probably not what you want.
+
+   For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
+   custom blocks from within a heap block, B, that has been allocated with
+   malloc/calloc/new/etc, then block B will be *ignored* during leak-checking
+   -- the custom blocks will take precedence.
+
+   VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK.  For
+   Memcheck, it does two things:
+
+   - It records that the block has been deallocated.  This assumes that the
+     block was annotated as having been allocated via
+     VALGRIND_MALLOCLIKE_BLOCK.  Otherwise, an error will be issued.
+
+   - It marks the block as being unaddressable.
+
+   VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a
+   heap block is deallocated.
+
+   In many cases, these two client requests will not be enough to get your
+   allocator working well with Memcheck.  More specifically, if your allocator
+   writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call
+   will be necessary to mark the memory as addressable just before the zeroing
+   occurs, otherwise you'll get a lot of invalid write errors.  For example,
+   you'll need to do this if your allocator recycles freed blocks, but it
+   zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK).
+   Alternatively, if your allocator reuses freed blocks for allocator-internal
+   data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary.
+
+   Really, what's happening is a blurring of the lines between the client
+   program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the
+   memory should be considered unaddressable to the client program, but the
+   allocator knows more than the rest of the client program and so may be able
+   to safely access it.  Extra client requests are necessary for Valgrind to
+   understand the distinction between the allocator and the rest of the
+   program.
+
+   Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request;  it
+   has to be emulated with MALLOCLIKE/FREELIKE and memory copying.
+   
+   Ignored if addr == 0.
+*/
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)    \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MALLOCLIKE_BLOCK,      \
+                               addr, sizeB, rzB, is_zeroed, 0);   \
+   }
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+   Ignored if addr == 0.
+*/
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB)                        \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__FREELIKE_BLOCK,        \
+                               addr, rzB, 0, 0, 0);               \
+   }
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__CREATE_MEMPOOL,        \
+                               pool, rzB, is_zeroed, 0, 0);       \
+   }
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool)                            \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DESTROY_MEMPOOL,       \
+                               pool, 0, 0, 0, 0);                 \
+   }
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)                  \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_ALLOC,         \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr)                         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_FREE,          \
+                               pool, addr, 0, 0, 0);              \
+   }
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size)                   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_TRIM,          \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB)                       \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MOVE_MEMPOOL,          \
+                               poolA, poolB, 0, 0, 0);            \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_CHANGE,        \
+                               pool, addrA, addrB, size, 0);      \
+   }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool)                             \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_EXISTS,        \
+                               pool, 0, 0, 0, 0);                 \
+    _qzz_res;                                                     \
+   })
+
+/* Mark a piece of memory as being a stack. Returns a stack id. */
+#define VALGRIND_STACK_REGISTER(start, end)                       \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_REGISTER,        \
+                               start, end, 0, 0, 0);              \
+    _qzz_res;                                                     \
+   })
+
+/* Unmark the piece of memory associated with a stack id as being a
+   stack. */
+#define VALGRIND_STACK_DEREGISTER(id)                             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_DEREGISTER,      \
+                               id, 0, 0, 0, 0);                   \
+   }
+
+/* Change the start and end address of the stack id. */
+#define VALGRIND_STACK_CHANGE(id, start, end)                     \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_CHANGE,          \
+                               id, start, end, 0, 0);             \
+   }
+
+/* Load PDB debug info for Wine PE image_map. */
+#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta)   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__LOAD_PDB_DEBUGINFO,    \
+                               fd, ptr, total_size, delta, 0);    \
+   }
+
+/* Map a code address to a source file name and line number.  buf64
+   must point to a 64-byte buffer in the caller's address space.  The
+   result will be dumped in there and is guaranteed to be zero
+   terminated.  If no info is found, the first byte is set to zero. */
+#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64)                    \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MAP_IP_TO_SRCLOC,      \
+                               addr, buf64, 0, 0, 0);             \
+   }
+
+
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#endif   /* __VALGRIND_H */
diff --git a/base/third_party/xdg_mime/BUILD.gn b/base/third_party/xdg_mime/BUILD.gn
new file mode 100644
index 0000000..72a3038
--- /dev/null
+++ b/base/third_party/xdg_mime/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("xdg_mime") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "xdgmime.c",
+    "xdgmime.h",
+    "xdgmimealias.c",
+    "xdgmimealias.h",
+    "xdgmimecache.c",
+    "xdgmimecache.h",
+    "xdgmimeglob.c",
+    "xdgmimeglob.h",
+    "xdgmimeicon.c",
+    "xdgmimeicon.h",
+    "xdgmimeint.c",
+    "xdgmimeint.h",
+    "xdgmimemagic.c",
+    "xdgmimemagic.h",
+    "xdgmimeparent.c",
+    "xdgmimeparent.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/base/third_party/xdg_mime/LICENSE b/base/third_party/xdg_mime/LICENSE
new file mode 100644
index 0000000..55fedcf
--- /dev/null
+++ b/base/third_party/xdg_mime/LICENSE
@@ -0,0 +1,168 @@
+Licensed under the Academic Free License version 2.0 (below)
+Or under the following terms:
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+
+--------------------------------------------------------------------------------
+Academic Free License v. 2.0
+--------------------------------------------------------------------------------
+
+This Academic Free License (the "License") applies to any original work of
+authorship (the "Original Work") whose owner (the "Licensor") has placed the
+following notice immediately following the copyright notice for the Original
+Work:
+
+Licensed under the Academic Free License version 2.0
+1) Grant of Copyright License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license to do the
+following:
+
+a) to reproduce the Original Work in copies;
+b) to prepare derivative works ("Derivative Works") based upon the Original
+   Work;
+c) to distribute copies of the Original Work and Derivative Works to the
+   public;
+d) to perform the Original Work publicly; and
+e) to display the Original Work publicly.
+
+2) Grant of Patent License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
+claims owned or controlled by the Licensor that are embodied in the Original
+Work as furnished by the Licensor, to make, use, sell and offer for sale the
+Original Work and Derivative Works.
+
+3) Grant of Source Code License. The term "Source Code" means the preferred
+form of the Original Work for making modifications to it and all available
+documentation describing how to modify the Original Work. Licensor hereby
+agrees to provide a machine-readable copy of the Source Code of the Original
+Work along with each copy of the Original Work that Licensor distributes.
+Licensor reserves the right to satisfy this obligation by placing a
+machine-readable copy of the Source Code in an information repository
+reasonably calculated to permit inexpensive and convenient access by You for as
+long as Licensor continues to distribute the Original Work, and by publishing
+the address of that information repository in a notice immediately following
+the copyright notice that applies to the Original Work.
+
+4) Exclusions From License Grant. Neither the names of Licensor, nor the names
+of any contributors to the Original Work, nor any of their trademarks or
+service marks, may be used to endorse or promote products derived from this
+Original Work without express prior written permission of the Licensor. Nothing
+in this License shall be deemed to grant any rights to trademarks, copyrights,
+patents, trade secrets or any other intellectual property of Licensor except as
+expressly stated herein. No patent license is granted to make, use, sell or
+offer to sell embodiments of any patent claims other than the licensed claims
+defined in Section 2. No right is granted to the trademarks of Licensor even if
+such marks are included in the Original Work. Nothing in this License shall be
+interpreted to prohibit Licensor from licensing under different terms from this
+License any Original Work that Licensor otherwise would have a right to
+license.
+
+5) This section intentionally omitted.
+
+6) Attribution Rights. You must retain, in the Source Code of any Derivative
+Works that You create, all copyright, patent or trademark notices from the
+Source Code of the Original Work, as well as any notices of licensing and any
+descriptive text identified therein as an "Attribution Notice." You must cause
+the Source Code for any Derivative Works that You create to carry a prominent
+Attribution Notice reasonably calculated to inform recipients that You have
+modified the Original Work.
+
+7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
+the copyright in and to the Original Work and the patent rights granted herein
+by Licensor are owned by the Licensor or are sublicensed to You under the terms
+of this License with the permission of the contributor(s) of those copyrights
+and patent rights. Except as expressly stated in the immediately proceeding
+sentence, the Original Work is provided under this License on an "AS IS" BASIS
+and WITHOUT WARRANTY, either express or implied, including, without limitation,
+the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
+This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
+license to Original Work is granted hereunder except under this disclaimer.
+
+8) Limitation of Liability. Under no circumstances and under no legal theory,
+whether in tort (including negligence), contract, or otherwise, shall the
+Licensor be liable to any person for any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License
+or the use of the Original Work including, without limitation, damages for loss
+of goodwill, work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses. This limitation of liability shall not
+apply to liability for death or personal injury resulting from Licensor's
+negligence to the extent applicable law prohibits such limitation. Some
+jurisdictions do not allow the exclusion or limitation of incidental or
+consequential damages, so this exclusion and limitation may not apply to You.
+
+9) Acceptance and Termination. If You distribute copies of the Original Work or
+a Derivative Work, You must make a reasonable effort under the circumstances to
+obtain the express assent of recipients to the terms of this License. Nothing
+else but this License (or another written agreement between Licensor and You)
+grants You permission to create Derivative Works based upon the Original Work
+or to exercise any of the rights granted in Section 1 herein, and any attempt
+to do so except under the terms of this License (or another written agreement
+between Licensor and You) is expressly prohibited by U.S. copyright law, the
+equivalent laws of other countries, and by international treaty. Therefore, by
+exercising any of the rights granted to You in Section 1 herein, You indicate
+Your acceptance of this License and all of its terms and conditions.
+
+10) Termination for Patent Action. This License shall terminate automatically
+and You may no longer exercise any of the rights granted to You by this License
+as of the date You commence an action, including a cross-claim or counterclaim,
+for patent infringement (i) against Licensor with respect to a patent
+applicable to software or (ii) against any entity with respect to a patent
+applicable to the Original Work (but excluding combinations of the Original
+Work with other software or hardware).
+
+11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
+License may be brought only in the courts of a jurisdiction wherein the
+Licensor resides or in which Licensor conducts its primary business, and under
+the laws of that jurisdiction excluding its conflict-of-law provisions. The
+application of the United Nations Convention on Contracts for the International
+Sale of Goods is expressly excluded. Any use of the Original Work outside the
+scope of this License or after its termination shall be subject to the
+requirements and penalties of the U.S. Copyright Act, 17 U.S.C. 101 et seq.,
+the equivalent laws of other countries, and international treaty. This section
+shall survive the termination of this License.
+
+12) Attorneys Fees. In any action to enforce the terms of this License or
+seeking damages relating thereto, the prevailing party shall be entitled to
+recover its costs and expenses, including, without limitation, reasonable
+attorneys' fees and costs incurred in connection with such action, including
+any appeal of such action. This section shall survive the termination of this
+License.
+
+13) Miscellaneous. This License represents the complete agreement concerning
+the subject matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent necessary to
+make it enforceable.
+
+14) Definition of "You" in This License. "You" throughout this License, whether
+in upper or lower case, means an individual or a legal entity exercising rights
+under, and complying with all of the terms of, this License. For legal
+entities, "You" includes any entity that controls, is controlled by, or is
+under common control with you. For purposes of this definition, "control" means
+(i) the power, direct or indirect, to cause the direction or management of such
+entity, whether by contract or otherwise, or (ii) ownership of fifty percent
+(50%) or more of the outstanding shares, or (iii) beneficial ownership of such
+entity.
+
+15) Right to Use. You may use the Original Work in all ways not otherwise
+restricted or conditioned by this License or by law, and Licensor promises not
+to interfere with or be responsible for such uses by You.
+
+This license is Copyright (C) 2003 Lawrence E. Rosen. All rights reserved.
+Permission is hereby granted to copy and distribute this license without
+modification. This license may not be modified without the express written
+permission of its copyright owner.
diff --git a/base/third_party/xdg_mime/README b/base/third_party/xdg_mime/README
new file mode 100644
index 0000000..e7f3f68
--- /dev/null
+++ b/base/third_party/xdg_mime/README
@@ -0,0 +1,8 @@
+This module is a simple module that parses the proposed MIME spec listed
+at http://freedesktop.org/.  It is currently targetted at version 0.12.
+There are no formal releases planned for this module, and it is not
+intended to be installed at this time.  Rather, it is meant to be used
+by other libraries or applications to add support for the MIME system.
+
+It is dual-licensed under the terms of the GNU Lesser General Public
+License, and the Academic Free License, version 2.0.
diff --git a/base/third_party/xdg_mime/README.chromium b/base/third_party/xdg_mime/README.chromium
new file mode 100644
index 0000000..95f3a96
--- /dev/null
+++ b/base/third_party/xdg_mime/README.chromium
@@ -0,0 +1,13 @@
+Name: xdg-mime
+URL: http://freedesktop.org
+License: Academic Free License version 2.0 or LGPL v2
+
+The code in this directory is synced from:
+git://anongit.freedesktop.org/xdg/xdgmime
+@ 2cdd8d36d7930d5a594587286cb1949ff62f7027 on 2012/08/06.
+
+In addition, we have the following patch(es):
+  - compile.patch: small tweaks to make the code compile.
+  - free_pointer_later.patch: small patch that fixes potential crash in
+      xdg_mime_get_mime_type_for_file() - use of pointer after being freed.
+  - Added a LICENSE file.
diff --git a/base/third_party/xdg_mime/compile.patch b/base/third_party/xdg_mime/compile.patch
new file mode 100644
index 0000000..cd055ed
--- /dev/null
+++ b/base/third_party/xdg_mime/compile.patch
@@ -0,0 +1,17 @@
+--- a/xdgmimecache.c
++++ b/xdgmimecache.c
+@@ -40,6 +40,8 @@
+ 
+ #include <netinet/in.h> /* for ntohl/ntohs */
+ 
++#define HAVE_MMAP 1
++
+ #ifdef HAVE_MMAP
+ #include <sys/mman.h>
+ #else
+@@ -1000,5 +1002,3 @@
+ 	    dump_glob_node (cache, offset + 20 * j, 0);
+   }
+ }
+-
+-
diff --git a/base/third_party/xdg_mime/free_pointer_later.patch b/base/third_party/xdg_mime/free_pointer_later.patch
new file mode 100644
index 0000000..7668761
--- /dev/null
+++ b/base/third_party/xdg_mime/free_pointer_later.patch
@@ -0,0 +1,22 @@
+diff --git a/base/third_party/xdg_mime/xdgmime.c b/base/third_party/xdg_mime/xdgmime.c
+index c7b16bb..6dc58c2 100644
+--- a/base/third_party/xdg_mime/xdgmime.c
++++ b/base/third_party/xdg_mime/xdgmime.c
+@@ -558,13 +558,13 @@ xdg_mime_get_mime_type_for_file (const char  *file_name,
+   mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
+ 					   mime_types, n);
+ 
+-  free (data);
+   fclose (file);
+ 
+-  if (mime_type)
+-    return mime_type;
++  if (!mime_type)
++    mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+ 
+-  return _xdg_binary_or_text_fallback(data, bytes_read);
++  free (data);
++  return mime_type;
+ }
+ 
+ const char *
diff --git a/base/third_party/xdg_mime/xdgmime.c b/base/third_party/xdg_mime/xdgmime.c
new file mode 100644
index 0000000..6dc58c2
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmime.c
@@ -0,0 +1,934 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmime.c: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ * 
+ * Copyright (C) 2003,2004  Red Hat, Inc.
+ * Copyright (C) 2003,2004  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmime.h"
+#include "xdgmimeint.h"
+#include "xdgmimeglob.h"
+#include "xdgmimemagic.h"
+#include "xdgmimealias.h"
+#include "xdgmimeicon.h"
+#include "xdgmimeparent.h"
+#include "xdgmimecache.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <assert.h>
+
+typedef struct XdgDirTimeList XdgDirTimeList;
+typedef struct XdgCallbackList XdgCallbackList;
+
+static int need_reread = TRUE;
+static time_t last_stat_time = 0;
+
+static XdgGlobHash *global_hash = NULL;
+static XdgMimeMagic *global_magic = NULL;
+static XdgAliasList *alias_list = NULL;
+static XdgParentList *parent_list = NULL;
+static XdgDirTimeList *dir_time_list = NULL;
+static XdgCallbackList *callback_list = NULL;
+static XdgIconList *icon_list = NULL;
+static XdgIconList *generic_icon_list = NULL;
+
+XdgMimeCache **_caches = NULL;
+static int n_caches = 0;
+
+const char xdg_mime_type_unknown[] = "application/octet-stream";
+const char xdg_mime_type_empty[] = "application/x-zerosize";
+const char xdg_mime_type_textplain[] = "text/plain";
+
+
+enum
+{
+  XDG_CHECKED_UNCHECKED,
+  XDG_CHECKED_VALID,
+  XDG_CHECKED_INVALID
+};
+
+struct XdgDirTimeList
+{
+  time_t mtime;
+  char *directory_name;
+  int checked;
+  XdgDirTimeList *next;
+};
+
+struct XdgCallbackList
+{
+  XdgCallbackList *next;
+  XdgCallbackList *prev;
+  int              callback_id;
+  XdgMimeCallback  callback;
+  void            *data;
+  XdgMimeDestroy   destroy;
+};
+
+/* Function called by xdg_run_command_on_dirs.  If it returns TRUE, further
+ * directories aren't looked at */
+typedef int (*XdgDirectoryFunc) (const char *directory,
+				 void       *user_data);
+
+static void
+xdg_dir_time_list_add (char   *file_name, 
+		       time_t  mtime)
+{
+  XdgDirTimeList *list;
+
+  for (list = dir_time_list; list; list = list->next) 
+    {
+      if (strcmp (list->directory_name, file_name) == 0)
+        {
+          free (file_name);
+          return;
+        }
+    }
+  
+  list = calloc (1, sizeof (XdgDirTimeList));
+  list->checked = XDG_CHECKED_UNCHECKED;
+  list->directory_name = file_name;
+  list->mtime = mtime;
+  list->next = dir_time_list;
+  dir_time_list = list;
+}
+ 
+static void
+xdg_dir_time_list_free (XdgDirTimeList *list)
+{
+  XdgDirTimeList *next;
+
+  while (list)
+    {
+      next = list->next;
+      free (list->directory_name);
+      free (list);
+      list = next;
+    }
+}
+
+static int
+xdg_mime_init_from_directory (const char *directory)
+{
+  char *file_name;
+  struct stat st;
+
+  assert (directory != NULL);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
+  if (stat (file_name, &st) == 0)
+    {
+      XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
+
+      if (cache != NULL)
+	{
+	  xdg_dir_time_list_add (file_name, st.st_mtime);
+
+	  _caches = realloc (_caches, sizeof (XdgMimeCache *) * (n_caches + 2));
+	  _caches[n_caches] = cache;
+          _caches[n_caches + 1] = NULL;
+	  n_caches++;
+
+	  return FALSE;
+	}
+    }
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/globs2") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/globs2");
+  if (stat (file_name, &st) == 0)
+    {
+      _xdg_mime_glob_read_from_file (global_hash, file_name, TRUE);
+      xdg_dir_time_list_add (file_name, st.st_mtime);
+    }
+  else
+    {
+      free (file_name);
+      file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
+      strcpy (file_name, directory); strcat (file_name, "/mime/globs");
+      if (stat (file_name, &st) == 0)
+        {
+          _xdg_mime_glob_read_from_file (global_hash, file_name, FALSE);
+          xdg_dir_time_list_add (file_name, st.st_mtime);
+        }
+      else
+        {
+          free (file_name);
+        }
+    }
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/magic");
+  if (stat (file_name, &st) == 0)
+    {
+      _xdg_mime_magic_read_from_file (global_magic, file_name);
+      xdg_dir_time_list_add (file_name, st.st_mtime);
+    }
+  else
+    {
+      free (file_name);
+    }
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
+  _xdg_mime_alias_read_from_file (alias_list, file_name);
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
+  _xdg_mime_parent_read_from_file (parent_list, file_name);
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/icons") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/icons");
+  _xdg_mime_icon_read_from_file (icon_list, file_name);
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/generic-icons") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/generic-icons");
+  _xdg_mime_icon_read_from_file (generic_icon_list, file_name);
+  free (file_name);
+
+  return FALSE; /* Keep processing */
+}
+
+/* Runs a command on all the directories in the search path */
+static void
+xdg_run_command_on_dirs (XdgDirectoryFunc  func,
+			 void             *user_data)
+{
+  const char *xdg_data_home;
+  const char *xdg_data_dirs;
+  const char *ptr;
+
+  xdg_data_home = getenv ("XDG_DATA_HOME");
+  if (xdg_data_home)
+    {
+      if ((func) (xdg_data_home, user_data))
+	return;
+    }
+  else
+    {
+      const char *home;
+
+      home = getenv ("HOME");
+      if (home != NULL)
+	{
+	  char *guessed_xdg_home;
+	  int stop_processing;
+
+	  guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
+	  strcpy (guessed_xdg_home, home);
+	  strcat (guessed_xdg_home, "/.local/share/");
+	  stop_processing = (func) (guessed_xdg_home, user_data);
+	  free (guessed_xdg_home);
+
+	  if (stop_processing)
+	    return;
+	}
+    }
+
+  xdg_data_dirs = getenv ("XDG_DATA_DIRS");
+  if (xdg_data_dirs == NULL)
+    xdg_data_dirs = "/usr/local/share/:/usr/share/";
+
+  ptr = xdg_data_dirs;
+
+  while (*ptr != '\000')
+    {
+      const char *end_ptr;
+      char *dir;
+      int len;
+      int stop_processing;
+
+      end_ptr = ptr;
+      while (*end_ptr != ':' && *end_ptr != '\000')
+	end_ptr ++;
+
+      if (end_ptr == ptr)
+	{
+	  ptr++;
+	  continue;
+	}
+
+      if (*end_ptr == ':')
+	len = end_ptr - ptr;
+      else
+	len = end_ptr - ptr + 1;
+      dir = malloc (len + 1);
+      strncpy (dir, ptr, len);
+      dir[len] = '\0';
+      stop_processing = (func) (dir, user_data);
+      free (dir);
+
+      if (stop_processing)
+	return;
+
+      ptr = end_ptr;
+    }
+}
+
+/* Checks file_path to make sure it has the same mtime as last time it was
+ * checked.  If it has a different mtime, or if the file doesn't exist, it
+ * returns FALSE.
+ *
+ * FIXME: This doesn't protect against permission changes.
+ */
+static int
+xdg_check_file (const char *file_path,
+                int        *exists)
+{
+  struct stat st;
+
+  /* If the file exists */
+  if (stat (file_path, &st) == 0)
+    {
+      XdgDirTimeList *list;
+
+      if (exists)
+        *exists = TRUE;
+
+      for (list = dir_time_list; list; list = list->next)
+	{
+	  if (! strcmp (list->directory_name, file_path))
+	    {
+	      if (st.st_mtime == list->mtime)
+		list->checked = XDG_CHECKED_VALID;
+	      else 
+		list->checked = XDG_CHECKED_INVALID;
+
+	      return (list->checked != XDG_CHECKED_VALID);
+	    }
+	}
+      return TRUE;
+    }
+
+  if (exists)
+    *exists = FALSE;
+
+  return FALSE;
+}
+
+static int
+xdg_check_dir (const char *directory,
+	       int        *invalid_dir_list)
+{
+  int invalid, exists;
+  char *file_name;
+
+  assert (directory != NULL);
+
+  /* Check the mime.cache file */
+  file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
+  invalid = xdg_check_file (file_name, &exists);
+  free (file_name);
+  if (invalid)
+    {
+      *invalid_dir_list = TRUE;
+      return TRUE;
+    }
+  else if (exists)
+    {
+      return FALSE;
+    }
+
+  /* Check the globs file */
+  file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/globs");
+  invalid = xdg_check_file (file_name, NULL);
+  free (file_name);
+  if (invalid)
+    {
+      *invalid_dir_list = TRUE;
+      return TRUE;
+    }
+
+  /* Check the magic file */
+  file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/magic");
+  invalid = xdg_check_file (file_name, NULL);
+  free (file_name);
+  if (invalid)
+    {
+      *invalid_dir_list = TRUE;
+      return TRUE;
+    }
+
+  return FALSE; /* Keep processing */
+}
+
+/* Walks through all the mime files stat()ing them to see if they've changed.
+ * Returns TRUE if they have. */
+static int
+xdg_check_dirs (void)
+{
+  XdgDirTimeList *list;
+  int invalid_dir_list = FALSE;
+
+  for (list = dir_time_list; list; list = list->next)
+    list->checked = XDG_CHECKED_UNCHECKED;
+
+  xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir,
+			   &invalid_dir_list);
+
+  if (invalid_dir_list)
+    return TRUE;
+
+  for (list = dir_time_list; list; list = list->next)
+    {
+      if (list->checked != XDG_CHECKED_VALID)
+	return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* We want to avoid stat()ing on every single mime call, so we only look for
+ * newer files every 5 seconds.  This will return TRUE if we need to reread the
+ * mime data from disk.
+ */
+static int
+xdg_check_time_and_dirs (void)
+{
+  struct timeval tv;
+  time_t current_time;
+  int retval = FALSE;
+
+  gettimeofday (&tv, NULL);
+  current_time = tv.tv_sec;
+
+  if (current_time >= last_stat_time + 5)
+    {
+      retval = xdg_check_dirs ();
+      last_stat_time = current_time;
+    }
+
+  return retval;
+}
+
+/* Called in every public function.  It reloads the hash function if need be.
+ */
+static void
+xdg_mime_init (void)
+{
+  if (xdg_check_time_and_dirs ())
+    {
+      xdg_mime_shutdown ();
+    }
+
+  if (need_reread)
+    {
+      global_hash = _xdg_glob_hash_new ();
+      global_magic = _xdg_mime_magic_new ();
+      alias_list = _xdg_mime_alias_list_new ();
+      parent_list = _xdg_mime_parent_list_new ();
+      icon_list = _xdg_mime_icon_list_new ();
+      generic_icon_list = _xdg_mime_icon_list_new ();
+
+      xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_mime_init_from_directory,
+			       NULL);
+
+      need_reread = FALSE;
+    }
+}
+
+const char *
+xdg_mime_get_mime_type_for_data (const void *data,
+				 size_t      len,
+				 int        *result_prio)
+{
+  const char *mime_type;
+
+  if (len == 0)
+    {
+      *result_prio = 100;
+      return XDG_MIME_TYPE_EMPTY;
+    }
+
+  xdg_mime_init ();
+
+  if (_caches)
+    mime_type = _xdg_mime_cache_get_mime_type_for_data (data, len, result_prio);
+  else
+    mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, result_prio, NULL, 0);
+
+  if (mime_type)
+    return mime_type;
+
+  return _xdg_binary_or_text_fallback(data, len);
+}
+
+const char *
+xdg_mime_get_mime_type_for_file (const char  *file_name,
+                                 struct stat *statbuf)
+{
+  const char *mime_type;
+  /* currently, only a few globs occur twice, and none
+   * more often, so 5 seems plenty.
+   */
+  const char *mime_types[5];
+  FILE *file;
+  unsigned char *data;
+  int max_extent;
+  int bytes_read;
+  struct stat buf;
+  const char *base_name;
+  int n;
+
+  if (file_name == NULL)
+    return NULL;
+  if (! _xdg_utf8_validate (file_name))
+    return NULL;
+
+  xdg_mime_init ();
+
+  if (_caches)
+    return _xdg_mime_cache_get_mime_type_for_file (file_name, statbuf);
+
+  base_name = _xdg_get_base_name (file_name);
+  n = _xdg_glob_hash_lookup_file_name (global_hash, base_name, mime_types, 5);
+
+  if (n == 1)
+    return mime_types[0];
+
+  if (!statbuf)
+    {
+      if (stat (file_name, &buf) != 0)
+	return XDG_MIME_TYPE_UNKNOWN;
+
+      statbuf = &buf;
+    }
+
+  if (!S_ISREG (statbuf->st_mode))
+    return XDG_MIME_TYPE_UNKNOWN;
+
+  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
+   * be large and need getting from a stream instead of just reading it all
+   * in. */
+  max_extent = _xdg_mime_magic_get_buffer_extents (global_magic);
+  data = malloc (max_extent);
+  if (data == NULL)
+    return XDG_MIME_TYPE_UNKNOWN;
+        
+  file = fopen (file_name, "r");
+  if (file == NULL)
+    {
+      free (data);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  bytes_read = fread (data, 1, max_extent, file);
+  if (ferror (file))
+    {
+      free (data);
+      fclose (file);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
+					   mime_types, n);
+
+  fclose (file);
+
+  if (!mime_type)
+    mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+
+  free (data);
+  return mime_type;
+}
+
+const char *
+xdg_mime_get_mime_type_from_file_name (const char *file_name)
+{
+  const char *mime_type;
+
+  xdg_mime_init ();
+
+  if (_caches)
+    return _xdg_mime_cache_get_mime_type_from_file_name (file_name);
+
+  if (_xdg_glob_hash_lookup_file_name (global_hash, file_name, &mime_type, 1))
+    return mime_type;
+  else
+    return XDG_MIME_TYPE_UNKNOWN;
+}
+
+int
+xdg_mime_get_mime_types_from_file_name (const char *file_name,
+					const char  *mime_types[],
+					int          n_mime_types)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_mime_types_from_file_name (file_name, mime_types, n_mime_types);
+  
+  return _xdg_glob_hash_lookup_file_name (global_hash, file_name, mime_types, n_mime_types);
+}
+
+int
+xdg_mime_is_valid_mime_type (const char *mime_type)
+{
+  /* FIXME: We should make this a better test
+   */
+  return _xdg_utf8_validate (mime_type);
+}
+
+void
+xdg_mime_shutdown (void)
+{
+  XdgCallbackList *list;
+
+  /* FIXME: Need to make this (and the whole library) thread safe */
+  if (dir_time_list)
+    {
+      xdg_dir_time_list_free (dir_time_list);
+      dir_time_list = NULL;
+    }
+	
+  if (global_hash)
+    {
+      _xdg_glob_hash_free (global_hash);
+      global_hash = NULL;
+    }
+  if (global_magic)
+    {
+      _xdg_mime_magic_free (global_magic);
+      global_magic = NULL;
+    }
+
+  if (alias_list)
+    {
+      _xdg_mime_alias_list_free (alias_list);
+      alias_list = NULL;
+    }
+
+  if (parent_list)
+    {
+      _xdg_mime_parent_list_free (parent_list);
+      parent_list = NULL;
+    }
+
+  if (icon_list)
+    {
+      _xdg_mime_icon_list_free (icon_list);
+      icon_list = NULL;
+    }
+
+  if (generic_icon_list)
+    {
+      _xdg_mime_icon_list_free (generic_icon_list);
+      generic_icon_list = NULL;
+    }
+  
+  if (_caches)
+    {
+      int i;
+
+      for (i = 0; i < n_caches; i++)
+        _xdg_mime_cache_unref (_caches[i]);
+      free (_caches);
+      _caches = NULL;
+      n_caches = 0;
+    }
+
+  for (list = callback_list; list; list = list->next)
+    (list->callback) (list->data);
+
+  need_reread = TRUE;
+}
+
+int
+xdg_mime_get_max_buffer_extents (void)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_max_buffer_extents ();
+
+  return _xdg_mime_magic_get_buffer_extents (global_magic);
+}
+
+const char *
+_xdg_mime_unalias_mime_type (const char *mime_type)
+{
+  const char *lookup;
+
+  if (_caches)
+    return _xdg_mime_cache_unalias_mime_type (mime_type);
+
+  if ((lookup = _xdg_mime_alias_list_lookup (alias_list, mime_type)) != NULL)
+    return lookup;
+
+  return mime_type;
+}
+
+const char *
+xdg_mime_unalias_mime_type (const char *mime_type)
+{
+  xdg_mime_init ();
+
+  return _xdg_mime_unalias_mime_type (mime_type);
+}
+
+int
+_xdg_mime_mime_type_equal (const char *mime_a,
+			   const char *mime_b)
+{
+  const char *unalias_a, *unalias_b;
+
+  unalias_a = _xdg_mime_unalias_mime_type (mime_a);
+  unalias_b = _xdg_mime_unalias_mime_type (mime_b);
+
+  if (strcmp (unalias_a, unalias_b) == 0)
+    return 1;
+
+  return 0;
+}
+
+int
+xdg_mime_mime_type_equal (const char *mime_a,
+			  const char *mime_b)
+{
+  xdg_mime_init ();
+
+  return _xdg_mime_mime_type_equal (mime_a, mime_b);
+}
+
+int
+xdg_mime_media_type_equal (const char *mime_a,
+			   const char *mime_b)
+{
+  char *sep;
+
+  sep = strchr (mime_a, '/');
+  
+  if (sep && strncmp (mime_a, mime_b, sep - mime_a + 1) == 0)
+    return 1;
+
+  return 0;
+}
+
+#if 1
+static int
+xdg_mime_is_super_type (const char *mime)
+{
+  int length;
+  const char *type;
+
+  length = strlen (mime);
+  type = &(mime[length - 2]);
+
+  if (strcmp (type, "/*") == 0)
+    return 1;
+
+  return 0;
+}
+#endif
+
+int
+_xdg_mime_mime_type_subclass (const char *mime,
+			      const char *base)
+{
+  const char *umime, *ubase;
+  const char **parents;
+
+  if (_caches)
+    return _xdg_mime_cache_mime_type_subclass (mime, base);
+
+  umime = _xdg_mime_unalias_mime_type (mime);
+  ubase = _xdg_mime_unalias_mime_type (base);
+
+  if (strcmp (umime, ubase) == 0)
+    return 1;
+
+#if 1  
+  /* Handle supertypes */
+  if (xdg_mime_is_super_type (ubase) &&
+      xdg_mime_media_type_equal (umime, ubase))
+    return 1;
+#endif
+
+  /*  Handle special cases text/plain and application/octet-stream */
+  if (strcmp (ubase, "text/plain") == 0 && 
+      strncmp (umime, "text/", 5) == 0)
+    return 1;
+
+  if (strcmp (ubase, "application/octet-stream") == 0)
+    return 1;
+  
+  parents = _xdg_mime_parent_list_lookup (parent_list, umime);
+  for (; parents && *parents; parents++)
+    {
+      if (_xdg_mime_mime_type_subclass (*parents, ubase))
+	return 1;
+    }
+
+  return 0;
+}
+
+int
+xdg_mime_mime_type_subclass (const char *mime,
+			     const char *base)
+{
+  xdg_mime_init ();
+
+  return _xdg_mime_mime_type_subclass (mime, base);
+}
+
+char **
+xdg_mime_list_mime_parents (const char *mime)
+{
+  const char **parents;
+  char **result;
+  int i, n;
+
+  if (_caches)
+    return _xdg_mime_cache_list_mime_parents (mime);
+
+  parents = xdg_mime_get_mime_parents (mime);
+
+  if (!parents)
+    return NULL;
+
+  for (i = 0; parents[i]; i++) ;
+  
+  n = (i + 1) * sizeof (char *);
+  result = (char **) malloc (n);
+  memcpy (result, parents, n);
+
+  return result;
+}
+
+const char **
+xdg_mime_get_mime_parents (const char *mime)
+{
+  const char *umime;
+
+  xdg_mime_init ();
+
+  umime = _xdg_mime_unalias_mime_type (mime);
+
+  return _xdg_mime_parent_list_lookup (parent_list, umime);
+}
+
+void 
+xdg_mime_dump (void)
+{
+  xdg_mime_init();
+
+  printf ("*** ALIASES ***\n\n");
+  _xdg_mime_alias_list_dump (alias_list);
+  printf ("\n*** PARENTS ***\n\n");
+  _xdg_mime_parent_list_dump (parent_list);
+  printf ("\n*** CACHE ***\n\n");
+  _xdg_glob_hash_dump (global_hash);
+  printf ("\n*** GLOBS ***\n\n");
+  _xdg_glob_hash_dump (global_hash);
+  printf ("\n*** GLOBS REVERSE TREE ***\n\n");
+  _xdg_mime_cache_glob_dump ();
+}
+
+
+/* Registers a function to be called every time the mime database reloads its files
+ */
+int
+xdg_mime_register_reload_callback (XdgMimeCallback  callback,
+				   void            *data,
+				   XdgMimeDestroy   destroy)
+{
+  XdgCallbackList *list_el;
+  static int callback_id = 1;
+
+  /* Make a new list element */
+  list_el = calloc (1, sizeof (XdgCallbackList));
+  list_el->callback_id = callback_id;
+  list_el->callback = callback;
+  list_el->data = data;
+  list_el->destroy = destroy;
+  list_el->next = callback_list;
+  if (list_el->next)
+    list_el->next->prev = list_el;
+
+  callback_list = list_el;
+  callback_id ++;
+
+  return callback_id - 1;
+}
+
+void
+xdg_mime_remove_callback (int callback_id)
+{
+  XdgCallbackList *list;
+
+  for (list = callback_list; list; list = list->next)
+    {
+      if (list->callback_id == callback_id)
+	{
+	  if (list->next)
+	    list->next = list->prev;
+
+	  if (list->prev)
+	    list->prev->next = list->next;
+	  else
+	    callback_list = list->next;
+
+	  /* invoke the destroy handler */
+	  (list->destroy) (list->data);
+	  free (list);
+	  return;
+	}
+    }
+}
+
+const char *
+xdg_mime_get_icon (const char *mime)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_icon (mime);
+
+  return _xdg_mime_icon_list_lookup (icon_list, mime);
+}
+
+const char *
+xdg_mime_get_generic_icon (const char *mime)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_generic_icon (mime);
+
+  return _xdg_mime_icon_list_lookup (generic_icon_list, mime);
+}
diff --git a/base/third_party/xdg_mime/xdgmime.h b/base/third_party/xdg_mime/xdgmime.h
new file mode 100644
index 0000000..6a34edf
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmime.h
@@ -0,0 +1,133 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmime.h: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ * 
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __XDG_MIME_H__
+#define __XDG_MIME_H__
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef XDG_PREFIX
+#define XDG_ENTRY(func) _XDG_ENTRY2(XDG_PREFIX,func)
+#define _XDG_ENTRY2(prefix,func) _XDG_ENTRY3(prefix,func)
+#define _XDG_ENTRY3(prefix,func) prefix##_##func
+
+#define XDG_RESERVED_ENTRY(func) _XDG_RESERVED_ENTRY2(XDG_PREFIX,func)
+#define _XDG_RESERVED_ENTRY2(prefix,func) _XDG_RESERVED_ENTRY3(prefix,func)
+#define _XDG_RESERVED_ENTRY3(prefix,func) _##prefix##_##func
+#endif
+
+typedef void (*XdgMimeCallback) (void *user_data);
+typedef void (*XdgMimeDestroy)  (void *user_data);
+
+  
+#ifdef XDG_PREFIX
+#define xdg_mime_get_mime_type_for_data       XDG_ENTRY(get_mime_type_for_data)
+#define xdg_mime_get_mime_type_for_file       XDG_ENTRY(get_mime_type_for_file)
+#define xdg_mime_get_mime_type_from_file_name XDG_ENTRY(get_mime_type_from_file_name)
+#define xdg_mime_get_mime_types_from_file_name XDG_ENTRY(get_mime_types_from_file_name)
+#define xdg_mime_is_valid_mime_type           XDG_ENTRY(is_valid_mime_type)
+#define xdg_mime_mime_type_equal              XDG_ENTRY(mime_type_equal)
+#define xdg_mime_media_type_equal             XDG_ENTRY(media_type_equal)
+#define xdg_mime_mime_type_subclass           XDG_ENTRY(mime_type_subclass)
+#define xdg_mime_get_mime_parents             XDG_ENTRY(get_mime_parents)
+#define xdg_mime_list_mime_parents            XDG_ENTRY(list_mime_parents)
+#define xdg_mime_unalias_mime_type            XDG_ENTRY(unalias_mime_type)
+#define xdg_mime_get_max_buffer_extents       XDG_ENTRY(get_max_buffer_extents)
+#define xdg_mime_shutdown                     XDG_ENTRY(shutdown)
+#define xdg_mime_dump                         XDG_ENTRY(dump)
+#define xdg_mime_register_reload_callback     XDG_ENTRY(register_reload_callback)
+#define xdg_mime_remove_callback              XDG_ENTRY(remove_callback)
+#define xdg_mime_type_unknown                 XDG_ENTRY(type_unknown)
+#define xdg_mime_type_empty                   XDG_ENTRY(type_empty)
+#define xdg_mime_type_textplain               XDG_ENTRY(type_textplain)
+#define xdg_mime_get_icon                     XDG_ENTRY(get_icon)
+#define xdg_mime_get_generic_icon             XDG_ENTRY(get_generic_icon)
+
+#define _xdg_mime_mime_type_equal             XDG_RESERVED_ENTRY(mime_type_equal)
+#define _xdg_mime_mime_type_subclass          XDG_RESERVED_ENTRY(mime_type_subclass)
+#define _xdg_mime_unalias_mime_type           XDG_RESERVED_ENTRY(unalias_mime_type)  
+#endif
+
+extern const char xdg_mime_type_unknown[];
+extern const char xdg_mime_type_empty[];
+extern const char xdg_mime_type_textplain[];
+#define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown
+#define XDG_MIME_TYPE_EMPTY xdg_mime_type_empty
+#define XDG_MIME_TYPE_TEXTPLAIN xdg_mime_type_textplain
+
+const char  *xdg_mime_get_mime_type_for_data       (const void *data,
+						    size_t      len,
+						    int        *result_prio);
+const char  *xdg_mime_get_mime_type_for_file       (const char *file_name,
+                                                    struct stat *statbuf);
+const char  *xdg_mime_get_mime_type_from_file_name (const char *file_name);
+int          xdg_mime_get_mime_types_from_file_name(const char *file_name,
+						    const char *mime_types[],
+						    int         n_mime_types);
+int          xdg_mime_is_valid_mime_type           (const char *mime_type);
+int          xdg_mime_mime_type_equal              (const char *mime_a,
+						    const char *mime_b);
+int          xdg_mime_media_type_equal             (const char *mime_a,
+						    const char *mime_b);
+int          xdg_mime_mime_type_subclass           (const char *mime_a,
+						    const char *mime_b);
+  /* xdg_mime_get_mime_parents() is deprecated since it does
+   * not work correctly with caches. Use xdg_mime_list_parents() 
+   * instead, but notice that that function expects you to free
+   * the array it returns. 
+   */
+const char **xdg_mime_get_mime_parents		   (const char *mime);
+char **      xdg_mime_list_mime_parents		   (const char *mime);
+const char  *xdg_mime_unalias_mime_type		   (const char *mime);
+const char  *xdg_mime_get_icon                     (const char *mime);
+const char  *xdg_mime_get_generic_icon             (const char *mime);
+int          xdg_mime_get_max_buffer_extents       (void);
+void         xdg_mime_shutdown                     (void);
+void         xdg_mime_dump                         (void);
+int          xdg_mime_register_reload_callback     (XdgMimeCallback  callback,
+						    void            *data,
+						    XdgMimeDestroy   destroy);
+void         xdg_mime_remove_callback              (int              callback_id);
+
+   /* Private versions of functions that don't call xdg_mime_init () */
+int          _xdg_mime_mime_type_equal             (const char *mime_a,
+						    const char *mime_b);
+int          _xdg_mime_mime_type_subclass          (const char *mime,
+						    const char *base);
+const char  *_xdg_mime_unalias_mime_type           (const char *mime);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __XDG_MIME_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimealias.c b/base/third_party/xdg_mime/xdgmimealias.c
new file mode 100644
index 0000000..07d89eb
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimealias.c
@@ -0,0 +1,184 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.c: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 2004  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimealias.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgAlias XdgAlias;
+
+struct XdgAlias 
+{
+  char *alias;
+  char *mime_type;
+};
+
+struct XdgAliasList
+{
+  struct XdgAlias *aliases;
+  int n_aliases;
+};
+
+XdgAliasList *
+_xdg_mime_alias_list_new (void)
+{
+  XdgAliasList *list;
+
+  list = malloc (sizeof (XdgAliasList));
+
+  list->aliases = NULL;
+  list->n_aliases = 0;
+
+  return list;
+}
+
+void         
+_xdg_mime_alias_list_free (XdgAliasList *list)
+{
+  int i;
+
+  if (list->aliases)
+    {
+      for (i = 0; i < list->n_aliases; i++)
+	{
+	  free (list->aliases[i].alias);
+	  free (list->aliases[i].mime_type);
+	}
+      free (list->aliases);
+    }
+  free (list);
+}
+
+static int
+alias_entry_cmp (const void *v1, const void *v2)
+{
+  return strcmp (((XdgAlias *)v1)->alias, ((XdgAlias *)v2)->alias);
+}
+
+const char  *
+_xdg_mime_alias_list_lookup (XdgAliasList *list,
+			     const char   *alias)
+{
+  XdgAlias *entry;
+  XdgAlias key;
+
+  if (list->n_aliases > 0)
+    {
+      key.alias = (char *)alias;
+      key.mime_type = NULL;
+
+      entry = bsearch (&key, list->aliases, list->n_aliases,
+		       sizeof (XdgAlias), alias_entry_cmp);
+      if (entry)
+        return entry->mime_type;
+    }
+
+  return NULL;
+}
+
+void
+_xdg_mime_alias_read_from_file (XdgAliasList *list,
+				const char   *file_name)
+{
+  FILE *file;
+  char line[255];
+  int alloc;
+
+  file = fopen (file_name, "r");
+
+  if (file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  alloc = list->n_aliases + 16;
+  list->aliases = realloc (list->aliases, alloc * sizeof (XdgAlias));
+  while (fgets (line, 255, file) != NULL)
+    {
+      char *sep;
+      if (line[0] == '#')
+	continue;
+
+      sep = strchr (line, ' ');
+      if (sep == NULL)
+	continue;
+      *(sep++) = '\000';
+      sep[strlen (sep) -1] = '\000';
+      if (list->n_aliases == alloc)
+	{
+	  alloc <<= 1;
+	  list->aliases = realloc (list->aliases, 
+				   alloc * sizeof (XdgAlias));
+	}
+      list->aliases[list->n_aliases].alias = strdup (line);
+      list->aliases[list->n_aliases].mime_type = strdup (sep);
+      list->n_aliases++;
+    }
+  list->aliases = realloc (list->aliases, 
+			   list->n_aliases * sizeof (XdgAlias));
+
+  fclose (file);  
+  
+  if (list->n_aliases > 1)
+    qsort (list->aliases, list->n_aliases, 
+           sizeof (XdgAlias), alias_entry_cmp);
+}
+
+
+void
+_xdg_mime_alias_list_dump (XdgAliasList *list)
+{
+  int i;
+
+  if (list->aliases)
+    {
+      for (i = 0; i < list->n_aliases; i++)
+	{
+	  printf ("%s %s\n", 
+		  list->aliases[i].alias,
+		  list->aliases[i].mime_type);
+	}
+    }
+}
+
+
diff --git a/base/third_party/xdg_mime/xdgmimealias.h b/base/third_party/xdg_mime/xdgmimealias.h
new file mode 100644
index 0000000..3c28012
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimealias.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.h: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 200  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_ALIAS_H__
+#define __XDG_MIME_ALIAS_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgAliasList XdgAliasList;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_alias_read_from_file        XDG_RESERVED_ENTRY(alias_read_from_file)
+#define _xdg_mime_alias_list_new              XDG_RESERVED_ENTRY(alias_list_new)
+#define _xdg_mime_alias_list_free             XDG_RESERVED_ENTRY(alias_list_free)
+#define _xdg_mime_alias_list_lookup           XDG_RESERVED_ENTRY(alias_list_lookup)
+#define _xdg_mime_alias_list_dump             XDG_RESERVED_ENTRY(alias_list_dump)
+#endif
+
+void          _xdg_mime_alias_read_from_file (XdgAliasList *list,
+					      const char   *file_name);
+XdgAliasList *_xdg_mime_alias_list_new       (void);
+void          _xdg_mime_alias_list_free      (XdgAliasList *list);
+const char   *_xdg_mime_alias_list_lookup    (XdgAliasList *list,
+					      const char  *alias);
+void          _xdg_mime_alias_list_dump      (XdgAliasList *list);
+
+#endif /* __XDG_MIME_ALIAS_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimecache.c b/base/third_party/xdg_mime/xdgmimecache.c
new file mode 100644
index 0000000..ddb8754
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimecache.c
@@ -0,0 +1,1069 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.c: Private file.  mmappable caches for mime data
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <fnmatch.h>
+#include <assert.h>
+
+#include <netinet/in.h> /* for ntohl/ntohs */
+
+#define HAVE_MMAP 1
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#else
+#warning Building xdgmime without MMAP support. Binary "mime.cache" files will not be used.
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "xdgmimecache.h"
+#include "xdgmimeint.h"
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION_MIN 1
+#define MINOR_VERSION_MAX 2
+
+struct _XdgMimeCache
+{
+  int ref_count;
+  int minor;
+
+  size_t  size;
+  char   *buffer;
+};
+
+#define GET_UINT16(cache,offset) (ntohs(*(xdg_uint16_t*)((cache) + (offset))))
+#define GET_UINT32(cache,offset) (ntohl(*(xdg_uint32_t*)((cache) + (offset))))
+
+XdgMimeCache *
+_xdg_mime_cache_ref (XdgMimeCache *cache)
+{
+  cache->ref_count++;
+  return cache;
+}
+
+void
+_xdg_mime_cache_unref (XdgMimeCache *cache)
+{
+  cache->ref_count--;
+
+  if (cache->ref_count == 0)
+    {
+#ifdef HAVE_MMAP
+      munmap (cache->buffer, cache->size);
+#endif
+      free (cache);
+    }
+}
+
+XdgMimeCache *
+_xdg_mime_cache_new_from_file (const char *file_name)
+{
+  XdgMimeCache *cache = NULL;
+
+#ifdef HAVE_MMAP
+  int fd = -1;
+  struct stat st;
+  char *buffer = NULL;
+  int minor;
+
+  /* Open the file and map it into memory */
+  fd = open (file_name, O_RDONLY|_O_BINARY, 0);
+
+  if (fd < 0)
+    return NULL;
+  
+  if (fstat (fd, &st) < 0 || st.st_size < 4)
+    goto done;
+
+  buffer = (char *) mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+  if (buffer == MAP_FAILED)
+    goto done;
+
+  minor = GET_UINT16 (buffer, 2);
+  /* Verify version */
+  if (GET_UINT16 (buffer, 0) != MAJOR_VERSION ||
+      (minor < MINOR_VERSION_MIN ||
+       minor > MINOR_VERSION_MAX))
+    {
+      munmap (buffer, st.st_size);
+
+      goto done;
+    }
+  
+  cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache));
+  cache->minor = minor;
+  cache->ref_count = 1;
+  cache->buffer = buffer;
+  cache->size = st.st_size;
+
+ done:
+  if (fd != -1)
+    close (fd);
+
+#endif  /* HAVE_MMAP */
+
+  return cache;
+}
+
+static int
+cache_magic_matchlet_compare_to_data (XdgMimeCache *cache, 
+				      xdg_uint32_t  offset,
+				      const void   *data,
+				      size_t        len)
+{
+  xdg_uint32_t range_start = GET_UINT32 (cache->buffer, offset);
+  xdg_uint32_t range_length = GET_UINT32 (cache->buffer, offset + 4);
+  xdg_uint32_t data_length = GET_UINT32 (cache->buffer, offset + 12);
+  xdg_uint32_t data_offset = GET_UINT32 (cache->buffer, offset + 16);
+  xdg_uint32_t mask_offset = GET_UINT32 (cache->buffer, offset + 20);
+  
+  int i, j;
+
+  for (i = range_start; i < range_start + range_length; i++)
+    {
+      int valid_matchlet = TRUE;
+      
+      if (i + data_length > len)
+	return FALSE;
+
+      if (mask_offset)
+	{
+	  for (j = 0; j < data_length; j++)
+	    {
+	      if ((((unsigned char *)cache->buffer)[data_offset + j] & ((unsigned char *)cache->buffer)[mask_offset + j]) !=
+		  ((((unsigned char *) data)[j + i]) & ((unsigned char *)cache->buffer)[mask_offset + j]))
+		{
+		  valid_matchlet = FALSE;
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  valid_matchlet = memcmp(cache->buffer + data_offset, data + i, data_length) == 0;
+	}
+
+      if (valid_matchlet)
+	return TRUE;
+    }
+  
+  return FALSE;  
+}
+
+static int
+cache_magic_matchlet_compare (XdgMimeCache *cache, 
+			      xdg_uint32_t  offset,
+			      const void   *data,
+			      size_t        len)
+{
+  xdg_uint32_t n_children = GET_UINT32 (cache->buffer, offset + 24);
+  xdg_uint32_t child_offset = GET_UINT32 (cache->buffer, offset + 28);
+
+  int i;
+  
+  if (cache_magic_matchlet_compare_to_data (cache, offset, data, len))
+    {
+      if (n_children == 0)
+	return TRUE;
+      
+      for (i = 0; i < n_children; i++)
+	{
+	  if (cache_magic_matchlet_compare (cache, child_offset + 32 * i,
+					    data, len))
+	    return TRUE;
+	}
+    }
+  
+  return FALSE;  
+}
+
+static const char *
+cache_magic_compare_to_data (XdgMimeCache *cache, 
+			     xdg_uint32_t  offset,
+			     const void   *data, 
+			     size_t        len, 
+			     int          *prio)
+{
+  xdg_uint32_t priority = GET_UINT32 (cache->buffer, offset);
+  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, offset + 4);
+  xdg_uint32_t n_matchlets = GET_UINT32 (cache->buffer, offset + 8);
+  xdg_uint32_t matchlet_offset = GET_UINT32 (cache->buffer, offset + 12);
+
+  int i;
+
+  for (i = 0; i < n_matchlets; i++)
+    {
+      if (cache_magic_matchlet_compare (cache, matchlet_offset + i * 32, 
+					data, len))
+	{
+	  *prio = priority;
+	  
+	  return cache->buffer + mimetype_offset;
+	}
+    }
+
+  return NULL;
+}
+
+static const char *
+cache_magic_lookup_data (XdgMimeCache *cache, 
+			 const void   *data, 
+			 size_t        len, 
+			 int          *prio,
+			 const char   *mime_types[],
+			 int           n_mime_types)
+{
+  xdg_uint32_t list_offset;
+  xdg_uint32_t n_entries;
+  xdg_uint32_t offset;
+
+  int j, n;
+
+  *prio = 0;
+
+  list_offset = GET_UINT32 (cache->buffer, 24);
+  n_entries = GET_UINT32 (cache->buffer, list_offset);
+  offset = GET_UINT32 (cache->buffer, list_offset + 8);
+  
+  for (j = 0; j < n_entries; j++)
+    {
+      const char *match;
+
+      match = cache_magic_compare_to_data (cache, offset + 16 * j, 
+					   data, len, prio);
+      if (match)
+	return match;
+      else
+	{
+	  xdg_uint32_t mimetype_offset;
+	  const char *non_match;
+	  
+	  mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * j + 4);
+	  non_match = cache->buffer + mimetype_offset;
+
+	  for (n = 0; n < n_mime_types; n++)
+	    {
+	      if (mime_types[n] && 
+		  _xdg_mime_mime_type_equal (mime_types[n], non_match))
+		mime_types[n] = NULL;
+	    }
+	}
+    }
+
+  return NULL;
+}
+
+static const char *
+cache_alias_lookup (const char *alias)
+{
+  const char *ptr;
+  int i, min, max, mid, cmp;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 4);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min) 
+	{
+	  mid = (min + max) / 2;
+
+	  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
+	  ptr = cache->buffer + offset;
+	  cmp = strcmp (ptr, alias);
+	  
+	  if (cmp < 0)
+	    min = mid + 1;
+	  else if (cmp > 0)
+	    max = mid - 1;
+	  else
+	    {
+	      offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
+	      return cache->buffer + offset;
+	    }
+	}
+    }
+
+  return NULL;
+}
+
+typedef struct {
+  const char *mime;
+  int weight;
+} MimeWeight;
+
+static int
+cache_glob_lookup_literal (const char *file_name,
+			   const char *mime_types[],
+			   int         n_mime_types,
+			   int         case_sensitive_check)
+{
+  const char *ptr;
+  int i, min, max, mid, cmp;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 12);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min) 
+	{
+	  mid = (min + max) / 2;
+
+	  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid);
+	  ptr = cache->buffer + offset;
+	  cmp = strcmp (ptr, file_name);
+
+	  if (cmp < 0)
+	    min = mid + 1;
+	  else if (cmp > 0)
+	    max = mid - 1;
+	  else
+	    {
+	      int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 8);
+	      int case_sensitive = weight & 0x100;
+	      weight = weight & 0xff;
+
+	      if (case_sensitive_check || !case_sensitive)
+		{
+		  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4);
+		  mime_types[0] = (const char *)(cache->buffer + offset);
+
+		  return 1;
+		}
+	      return 0;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+static int
+cache_glob_lookup_fnmatch (const char *file_name,
+			   MimeWeight  mime_types[],
+			   int         n_mime_types,
+			   int         case_sensitive_check)
+{
+  const char *mime_type;
+  const char *ptr;
+
+  int i, j, n;
+
+  n = 0;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 20);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+
+      for (j = 0; j < n_entries && n < n_mime_types; j++)
+	{
+	  xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j);
+	  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 4);
+	  int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8);
+	  int case_sensitive = weight & 0x100;
+	  weight = weight & 0xff;
+	  ptr = cache->buffer + offset;
+	  mime_type = cache->buffer + mimetype_offset;
+	  if (case_sensitive_check || !case_sensitive)
+	    {
+	      /* FIXME: Not UTF-8 safe */
+	      if (fnmatch (ptr, file_name, 0) == 0)
+	        {
+	          mime_types[n].mime = mime_type;
+	          mime_types[n].weight = weight;
+	          n++;
+	        }
+	    }
+	}
+
+      if (n > 0)
+	return n;
+    }
+  
+  return 0;
+}
+
+static int
+cache_glob_node_lookup_suffix (XdgMimeCache  *cache,
+			       xdg_uint32_t   n_entries,
+			       xdg_uint32_t   offset,
+			       const char    *file_name,
+			       int            len,
+			       int            case_sensitive_check,
+			       MimeWeight     mime_types[],
+			       int            n_mime_types)
+{
+  xdg_unichar_t character;
+  xdg_unichar_t match_char;
+  xdg_uint32_t mimetype_offset;
+  xdg_uint32_t n_children;
+  xdg_uint32_t child_offset; 
+  int weight;
+  int case_sensitive;
+
+  int min, max, mid, n, i;
+
+  character = file_name[len - 1];
+
+  assert (character != 0);
+
+  min = 0;
+  max = n_entries - 1;
+  while (max >= min)
+    {
+      mid = (min + max) /  2;
+      match_char = GET_UINT32 (cache->buffer, offset + 12 * mid);
+      if (match_char < character)
+	min = mid + 1;
+      else if (match_char > character)
+	max = mid - 1;
+      else 
+	{
+          len--;
+          n = 0;
+          n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4);
+          child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8);
+      
+          if (len > 0)
+            {
+              n = cache_glob_node_lookup_suffix (cache, 
+                                                 n_children, child_offset,
+                                                 file_name, len, 
+                                                 case_sensitive_check,
+                                                 mime_types,
+                                                 n_mime_types);
+            }
+          if (n == 0)
+            {
+	      i = 0;
+	      while (n < n_mime_types && i < n_children)
+		{
+		  match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i);
+		  if (match_char != 0)
+		    break;
+
+		  mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12 * i + 4);
+		  weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8);
+		  case_sensitive = weight & 0x100;
+		  weight = weight & 0xff;
+
+		  if (case_sensitive_check || !case_sensitive)
+		    {
+		      mime_types[n].mime = cache->buffer + mimetype_offset;
+		      mime_types[n].weight = weight;
+		      n++;
+		    }
+		  i++;
+		}
+	    }
+	  return n;
+	}
+    }
+  return 0;
+}
+
+static int
+cache_glob_lookup_suffix (const char *file_name,
+			  int         len,
+			  int         ignore_case,
+			  MimeWeight  mime_types[],
+			  int         n_mime_types)
+{
+  int i, n;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
+
+      n = cache_glob_node_lookup_suffix (cache, 
+					 n_entries, offset, 
+					 file_name, len,
+					 ignore_case,
+					 mime_types,
+					 n_mime_types);
+      if (n > 0)
+	return n;
+    }
+
+  return 0;
+}
+
+static int compare_mime_weight (const void *a, const void *b)
+{
+  const MimeWeight *aa = (const MimeWeight *)a;
+  const MimeWeight *bb = (const MimeWeight *)b;
+
+  return bb->weight - aa->weight;
+}
+
+#define ISUPPER(c)		((c) >= 'A' && (c) <= 'Z')
+static char *
+ascii_tolower (const char *str)
+{
+  char *p, *lower;
+
+  lower = strdup (str);
+  p = lower;
+  while (*p != 0)
+    {
+      char c = *p;
+      *p++ = ISUPPER (c) ? c - 'A' + 'a' : c;
+    }
+  return lower;
+}
+
+static int
+cache_glob_lookup_file_name (const char *file_name, 
+			     const char *mime_types[],
+			     int         n_mime_types)
+{
+  int n;
+  MimeWeight mimes[10];
+  int n_mimes = 10;
+  int i;
+  int len;
+  char *lower_case;
+
+  assert (file_name != NULL && n_mime_types > 0);
+
+  /* First, check the literals */
+
+  lower_case = ascii_tolower (file_name);
+
+  n = cache_glob_lookup_literal (lower_case, mime_types, n_mime_types, FALSE);
+  if (n > 0)
+    {
+      free (lower_case);
+      return n;
+    }
+
+  n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types, TRUE);
+  if (n > 0)
+    {
+      free (lower_case);
+      return n;
+    }
+
+  len = strlen (file_name);
+  n = cache_glob_lookup_suffix (lower_case, len, FALSE, mimes, n_mimes);
+  if (n == 0)
+    n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes);
+
+  /* Last, try fnmatch */
+  if (n == 0)
+    n = cache_glob_lookup_fnmatch (lower_case, mimes, n_mimes, FALSE);
+  if (n == 0)
+    n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes, TRUE);
+
+  free (lower_case);
+
+  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
+
+  if (n_mime_types < n)
+    n = n_mime_types;
+
+  for (i = 0; i < n; i++)
+    mime_types[i] = mimes[i].mime;
+
+  return n;
+}
+
+int
+_xdg_mime_cache_get_max_buffer_extents (void)
+{
+  xdg_uint32_t offset;
+  xdg_uint32_t max_extent;
+  int i;
+
+  max_extent = 0;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      offset = GET_UINT32 (cache->buffer, 24);
+      max_extent = MAX (max_extent, GET_UINT32 (cache->buffer, offset + 4));
+    }
+
+  return max_extent;
+}
+
+static const char *
+cache_get_mime_type_for_data (const void *data,
+			      size_t      len,
+			      int        *result_prio,
+			      const char *mime_types[],
+			      int         n_mime_types)
+{
+  const char *mime_type;
+  int i, n, priority;
+
+  priority = 0;
+  mime_type = NULL;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      int prio;
+      const char *match;
+
+      match = cache_magic_lookup_data (cache, data, len, &prio, 
+				       mime_types, n_mime_types);
+      if (prio > priority)
+	{
+	  priority = prio;
+	  mime_type = match;
+	}
+    }
+
+  if (result_prio)
+    *result_prio = priority;
+
+  if (priority > 0)
+    {
+      /* Pick glob-result R where mime_type inherits from R */
+      for (n = 0; n < n_mime_types; n++)
+        {
+          if (mime_types[n] && _xdg_mime_cache_mime_type_subclass(mime_types[n], mime_type))
+              return mime_types[n];
+        }
+
+      /* Return magic match */
+      return mime_type;
+    }
+
+  /* Pick first glob result, as fallback */
+  for (n = 0; n < n_mime_types; n++)
+    {
+      if (mime_types[n])
+        return mime_types[n];
+    }
+
+  return NULL;
+}
+
+const char *
+_xdg_mime_cache_get_mime_type_for_data (const void *data,
+					size_t      len,
+					int        *result_prio)
+{
+  return cache_get_mime_type_for_data (data, len, result_prio, NULL, 0);
+}
+
+const char *
+_xdg_mime_cache_get_mime_type_for_file (const char  *file_name,
+					struct stat *statbuf)
+{
+  const char *mime_type;
+  const char *mime_types[10];
+  FILE *file;
+  unsigned char *data;
+  int max_extent;
+  int bytes_read;
+  struct stat buf;
+  const char *base_name;
+  int n;
+
+  if (file_name == NULL)
+    return NULL;
+
+  if (! _xdg_utf8_validate (file_name))
+    return NULL;
+
+  base_name = _xdg_get_base_name (file_name);
+  n = cache_glob_lookup_file_name (base_name, mime_types, 10);
+
+  if (n == 1)
+    return mime_types[0];
+
+  if (!statbuf)
+    {
+      if (stat (file_name, &buf) != 0)
+	return XDG_MIME_TYPE_UNKNOWN;
+
+      statbuf = &buf;
+    }
+
+  if (statbuf->st_size == 0)
+    return XDG_MIME_TYPE_EMPTY;
+
+  if (!S_ISREG (statbuf->st_mode))
+    return XDG_MIME_TYPE_UNKNOWN;
+
+  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
+   * be large and need getting from a stream instead of just reading it all
+   * in. */
+  max_extent = _xdg_mime_cache_get_max_buffer_extents ();
+  data = malloc (max_extent);
+  if (data == NULL)
+    return XDG_MIME_TYPE_UNKNOWN;
+        
+  file = fopen (file_name, "r");
+  if (file == NULL)
+    {
+      free (data);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  bytes_read = fread (data, 1, max_extent, file);
+  if (ferror (file))
+    {
+      free (data);
+      fclose (file);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL,
+					    mime_types, n);
+
+  if (!mime_type)
+    mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+
+  free (data);
+  fclose (file);
+
+  return mime_type;
+}
+
+const char *
+_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name)
+{
+  const char *mime_type;
+
+  if (cache_glob_lookup_file_name (file_name, &mime_type, 1))
+    return mime_type;
+  else
+    return XDG_MIME_TYPE_UNKNOWN;
+}
+
+int
+_xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
+					       const char  *mime_types[],
+					       int          n_mime_types)
+{
+  return cache_glob_lookup_file_name (file_name, mime_types, n_mime_types);
+}
+
+#if 1
+static int
+is_super_type (const char *mime)
+{
+  int length;
+  const char *type;
+
+  length = strlen (mime);
+  type = &(mime[length - 2]);
+
+  if (strcmp (type, "/*") == 0)
+    return 1;
+
+  return 0;
+}
+#endif
+
+int
+_xdg_mime_cache_mime_type_subclass (const char *mime,
+				    const char *base)
+{
+  const char *umime, *ubase;
+
+  int i, j, min, max, med, cmp;
+  
+  umime = _xdg_mime_cache_unalias_mime_type (mime);
+  ubase = _xdg_mime_cache_unalias_mime_type (base);
+
+  if (strcmp (umime, ubase) == 0)
+    return 1;
+
+  /* We really want to handle text/ * in GtkFileFilter, so we just
+   * turn on the supertype matching
+   */
+#if 1
+  /* Handle supertypes */
+  if (is_super_type (ubase) &&
+      xdg_mime_media_type_equal (umime, ubase))
+    return 1;
+#endif
+
+  /*  Handle special cases text/plain and application/octet-stream */
+  if (strcmp (ubase, "text/plain") == 0 && 
+      strncmp (umime, "text/", 5) == 0)
+    return 1;
+
+  if (strcmp (ubase, "application/octet-stream") == 0)
+    return 1;
+ 
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset, n_parents, parent_offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min)
+	{
+	  med = (min + max)/2;
+	  
+	  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med);
+	  cmp = strcmp (cache->buffer + offset, umime);
+	  if (cmp < 0)
+	    min = med + 1;
+	  else if (cmp > 0)
+	    max = med - 1;
+	  else
+	    {
+	      offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med + 4);
+	      n_parents = GET_UINT32 (cache->buffer, offset);
+	      
+	      for (j = 0; j < n_parents; j++)
+		{
+		  parent_offset = GET_UINT32 (cache->buffer, offset + 4 + 4 * j);
+		  if (_xdg_mime_cache_mime_type_subclass (cache->buffer + parent_offset, ubase))
+		    return 1;
+		}
+
+	      break;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+const char *
+_xdg_mime_cache_unalias_mime_type (const char *mime)
+{
+  const char *lookup;
+  
+  lookup = cache_alias_lookup (mime);
+  
+  if (lookup)
+    return lookup;
+  
+  return mime;  
+}
+
+char **
+_xdg_mime_cache_list_mime_parents (const char *mime)
+{
+  int i, j, k, l, p;
+  char *all_parents[128]; /* we'll stop at 128 */ 
+  char **result;
+
+  mime = xdg_mime_unalias_mime_type (mime);
+
+  p = 0;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+  
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+
+      for (j = 0; j < n_entries; j++)
+	{
+	  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
+	  xdg_uint32_t parents_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
+
+	  if (strcmp (cache->buffer + mimetype_offset, mime) == 0)
+	    {
+	      xdg_uint32_t parent_mime_offset;
+	      xdg_uint32_t n_parents = GET_UINT32 (cache->buffer, parents_offset);
+
+	      for (k = 0; k < n_parents && p < 127; k++)
+		{
+		  parent_mime_offset = GET_UINT32 (cache->buffer, parents_offset + 4 + 4 * k);
+
+		  /* Don't add same parent multiple times.
+		   * This can happen for instance if the same type is listed in multiple directories
+		   */
+		  for (l = 0; l < p; l++)
+		    {
+		      if (strcmp (all_parents[l], cache->buffer + parent_mime_offset) == 0)
+			break;
+		    }
+
+		  if (l == p)
+		    all_parents[p++] = cache->buffer + parent_mime_offset;
+		}
+
+	      break;
+	    }
+	}
+    }
+  all_parents[p++] = NULL;
+  
+  result = (char **) malloc (p * sizeof (char *));
+  memcpy (result, all_parents, p * sizeof (char *));
+
+  return result;
+}
+
+static const char *
+cache_lookup_icon (const char *mime, int header)
+{
+  const char *ptr;
+  int i, min, max, mid, cmp;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, header);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min) 
+        {
+          mid = (min + max) / 2;
+
+          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
+          ptr = cache->buffer + offset;
+          cmp = strcmp (ptr, mime);
+         
+          if (cmp < 0)
+            min = mid + 1;
+          else if (cmp > 0)
+            max = mid - 1;
+          else
+            {
+              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
+              return cache->buffer + offset;
+            }
+        }
+    }
+
+  return NULL;
+}
+
+const char *
+_xdg_mime_cache_get_generic_icon (const char *mime)
+{
+  return cache_lookup_icon (mime, 36);
+}
+
+const char *
+_xdg_mime_cache_get_icon (const char *mime)
+{
+  return cache_lookup_icon (mime, 32);
+}
+
+static void
+dump_glob_node (XdgMimeCache *cache,
+		xdg_uint32_t  offset,
+		int           depth)
+{
+  xdg_unichar_t character;
+  xdg_uint32_t mime_offset;
+  xdg_uint32_t n_children;
+  xdg_uint32_t child_offset;
+  int i;
+
+  character = GET_UINT32 (cache->buffer, offset);
+  mime_offset = GET_UINT32 (cache->buffer, offset + 4);
+  n_children = GET_UINT32 (cache->buffer, offset + 8);
+  child_offset = GET_UINT32 (cache->buffer, offset + 12);
+  for (i = 0; i < depth; i++)
+    printf (" ");
+  printf ("%c", character);
+  if (mime_offset)
+    printf (" - %s", cache->buffer + mime_offset);
+  printf ("\n");
+  if (child_offset)
+  {
+    for (i = 0; i < n_children; i++)
+      dump_glob_node (cache, child_offset + 20 * i, depth + 1);
+  }
+}
+
+void
+_xdg_mime_cache_glob_dump (void)
+{
+  int i, j;
+  for (i = 0; _caches[i]; i++)
+  {
+    XdgMimeCache *cache = _caches[i];
+    xdg_uint32_t list_offset;
+    xdg_uint32_t n_entries;
+    xdg_uint32_t offset;
+    list_offset = GET_UINT32 (cache->buffer, 16);
+    n_entries = GET_UINT32 (cache->buffer, list_offset);
+    offset = GET_UINT32 (cache->buffer, list_offset + 4);
+    for (j = 0; j < n_entries; j++)
+	    dump_glob_node (cache, offset + 20 * j, 0);
+  }
+}
diff --git a/base/third_party/xdg_mime/xdgmimecache.h b/base/third_party/xdg_mime/xdgmimecache.h
new file mode 100644
index 0000000..27f42d0
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimecache.h
@@ -0,0 +1,81 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimecache.h: Private file.  Datastructure for mmapped caches.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_CACHE_H__
+#define __XDG_MIME_CACHE_H__
+
+#include "xdgmime.h"
+
+typedef struct _XdgMimeCache XdgMimeCache;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_cache_new_from_file                 XDG_RESERVED_ENTRY(cache_new_from_file)
+#define _xdg_mime_cache_ref                           XDG_RESERVED_ENTRY(cache_ref)
+#define _xdg_mime_cache_unref                         XDG_RESERVED_ENTRY(cache_unref)
+#define _xdg_mime_cache_get_max_buffer_extents        XDG_RESERVED_ENTRY(cache_get_max_buffer_extents)
+#define _xdg_mime_cache_get_mime_type_for_data        XDG_RESERVED_ENTRY(cache_get_mime_type_for_data)
+#define _xdg_mime_cache_get_mime_type_for_file        XDG_RESERVED_ENTRY(cache_get_mime_type_for_file)
+#define _xdg_mime_cache_get_mime_type_from_file_name  XDG_RESERVED_ENTRY(cache_get_mime_type_from_file_name)
+#define _xdg_mime_cache_get_mime_types_from_file_name XDG_RESERVED_ENTRY(cache_get_mime_types_from_file_name)
+#define _xdg_mime_cache_list_mime_parents             XDG_RESERVED_ENTRY(cache_list_mime_parents)
+#define _xdg_mime_cache_mime_type_subclass            XDG_RESERVED_ENTRY(cache_mime_type_subclass)
+#define _xdg_mime_cache_unalias_mime_type             XDG_RESERVED_ENTRY(cache_unalias_mime_type)
+#define _xdg_mime_cache_get_icon                      XDG_RESERVED_ENTRY(cache_get_icon)
+#define _xdg_mime_cache_get_generic_icon              XDG_RESERVED_ENTRY(cache_get_generic_icon)
+#define _xdg_mime_cache_glob_dump                     XDG_RESERVED_ENTRY(cache_glob_dump)
+#endif
+
+extern XdgMimeCache **_caches;
+
+XdgMimeCache *_xdg_mime_cache_new_from_file (const char   *file_name);
+XdgMimeCache *_xdg_mime_cache_ref           (XdgMimeCache *cache);
+void          _xdg_mime_cache_unref         (XdgMimeCache *cache);
+
+
+const char  *_xdg_mime_cache_get_mime_type_for_data       (const void *data,
+		 				           size_t      len,
+							   int        *result_prio);
+const char  *_xdg_mime_cache_get_mime_type_for_file       (const char  *file_name,
+							   struct stat *statbuf);
+int          _xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
+							    const char  *mime_types[],
+							    int          n_mime_types);
+const char  *_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name);
+int          _xdg_mime_cache_is_valid_mime_type           (const char *mime_type);
+int          _xdg_mime_cache_mime_type_equal              (const char *mime_a,
+						           const char *mime_b);
+int          _xdg_mime_cache_media_type_equal             (const char *mime_a,
+							   const char *mime_b);
+int          _xdg_mime_cache_mime_type_subclass           (const char *mime_a,
+							   const char *mime_b);
+char       **_xdg_mime_cache_list_mime_parents		  (const char *mime);
+const char  *_xdg_mime_cache_unalias_mime_type            (const char *mime);
+int          _xdg_mime_cache_get_max_buffer_extents       (void);
+const char  *_xdg_mime_cache_get_icon                     (const char *mime);
+const char  *_xdg_mime_cache_get_generic_icon             (const char *mime);
+void         _xdg_mime_cache_glob_dump                    (void);
+
+#endif /* __XDG_MIME_CACHE_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeglob.c b/base/third_party/xdg_mime/xdgmimeglob.c
new file mode 100644
index 0000000..f8434bc
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeglob.c
@@ -0,0 +1,691 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeglob.c: Private file.  Datastructure for storing the globs.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeglob.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgGlobHashNode XdgGlobHashNode;
+typedef struct XdgGlobList XdgGlobList;
+
+struct XdgGlobHashNode
+{
+  xdg_unichar_t character;
+  const char *mime_type;
+  int weight;
+  int case_sensitive;
+  XdgGlobHashNode *next;
+  XdgGlobHashNode *child;
+};
+struct XdgGlobList
+{
+  const char *data;
+  const char *mime_type;
+  int weight;
+  int case_sensitive;
+  XdgGlobList *next;
+};
+
+struct XdgGlobHash
+{
+  XdgGlobList *literal_list;
+  XdgGlobHashNode *simple_node;
+  XdgGlobList *full_list;
+};
+
+
+/* XdgGlobList
+ */
+static XdgGlobList *
+_xdg_glob_list_new (void)
+{
+  XdgGlobList *new_element;
+
+  new_element = calloc (1, sizeof (XdgGlobList));
+
+  return new_element;
+}
+
+/* Frees glob_list and all of it's children */
+static void
+_xdg_glob_list_free (XdgGlobList *glob_list)
+{
+  XdgGlobList *ptr, *next;
+
+  ptr = glob_list;
+
+  while (ptr != NULL)
+    {
+      next = ptr->next;
+
+      if (ptr->data)
+	free ((void *) ptr->data);
+      if (ptr->mime_type)
+	free ((void *) ptr->mime_type);
+      free (ptr);
+
+      ptr = next;
+    }
+}
+
+static XdgGlobList *
+_xdg_glob_list_append (XdgGlobList *glob_list,
+		       void        *data,
+		       const char  *mime_type,
+		       int          weight,
+		       int          case_sensitive)
+{
+  XdgGlobList *new_element;
+  XdgGlobList *tmp_element;
+
+  tmp_element = glob_list;
+  while (tmp_element != NULL)
+    {
+      if (strcmp (tmp_element->data, data) == 0 &&
+	  strcmp (tmp_element->mime_type, mime_type) == 0)
+	return glob_list;
+
+      tmp_element = tmp_element->next;
+    }
+
+  new_element = _xdg_glob_list_new ();
+  new_element->data = data;
+  new_element->mime_type = mime_type;
+  new_element->weight = weight;
+  new_element->case_sensitive = case_sensitive;
+  if (glob_list == NULL)
+    return new_element;
+
+  tmp_element = glob_list;
+  while (tmp_element->next != NULL)
+    tmp_element = tmp_element->next;
+
+  tmp_element->next = new_element;
+
+  return glob_list;
+}
+
+/* XdgGlobHashNode
+ */
+
+static XdgGlobHashNode *
+_xdg_glob_hash_node_new (void)
+{
+  XdgGlobHashNode *glob_hash_node;
+
+  glob_hash_node = calloc (1, sizeof (XdgGlobHashNode));
+
+  return glob_hash_node;
+}
+
+static void
+_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
+			  int depth)
+{
+  int i;
+  for (i = 0; i < depth; i++)
+    printf (" ");
+
+  printf ("%c", (char)glob_hash_node->character);
+  if (glob_hash_node->mime_type)
+    printf (" - %s %d\n", glob_hash_node->mime_type, glob_hash_node->weight);
+  else
+    printf ("\n");
+  if (glob_hash_node->child)
+    _xdg_glob_hash_node_dump (glob_hash_node->child, depth + 1);
+  if (glob_hash_node->next)
+    _xdg_glob_hash_node_dump (glob_hash_node->next, depth);
+}
+
+static XdgGlobHashNode *
+_xdg_glob_hash_insert_ucs4 (XdgGlobHashNode *glob_hash_node,
+			    xdg_unichar_t   *text,
+			    const char      *mime_type,
+			    int              weight,
+			    int              case_sensitive)
+{
+  XdgGlobHashNode *node;
+  xdg_unichar_t character;
+
+  character = text[0];
+
+  if ((glob_hash_node == NULL) ||
+      (character < glob_hash_node->character))
+    {
+      node = _xdg_glob_hash_node_new ();
+      node->character = character;
+      node->next = glob_hash_node;
+      glob_hash_node = node;
+    }
+  else if (character == glob_hash_node->character)
+    {
+      node = glob_hash_node;
+    }
+  else
+    {
+      XdgGlobHashNode *prev_node;
+      int found_node = FALSE;
+
+      /* Look for the first character of text in glob_hash_node, and insert it if we
+       * have to.*/
+      prev_node = glob_hash_node;
+      node = prev_node->next;
+
+      while (node != NULL)
+	{
+	  if (character < node->character)
+	    {
+	      node = _xdg_glob_hash_node_new ();
+	      node->character = character;
+	      node->next = prev_node->next;
+	      prev_node->next = node;
+
+	      found_node = TRUE;
+	      break;
+	    }
+	  else if (character == node->character)
+	    {
+	      found_node = TRUE;
+	      break;
+	    }
+	  prev_node = node;
+	  node = node->next;
+	}
+
+      if (! found_node)
+	{
+	  node = _xdg_glob_hash_node_new ();
+	  node->character = character;
+	  node->next = prev_node->next;
+	  prev_node->next = node;
+	}
+    }
+
+  text++;
+  if (*text == 0)
+    {
+      if (node->mime_type)
+	{
+	  if (strcmp (node->mime_type, mime_type) != 0)
+	    {
+	      XdgGlobHashNode *child;
+	      int found_node = FALSE;
+
+	      child = node->child;
+	      while (child && child->character == 0)
+		{
+		  if (strcmp (child->mime_type, mime_type) == 0)
+		    {
+		      found_node = TRUE;
+		      break;
+		    }
+		  child = child->next;
+		}
+
+	      if (!found_node)
+		{
+		  child = _xdg_glob_hash_node_new ();
+		  child->character = 0;
+		  child->mime_type = strdup (mime_type);
+		  child->weight = weight;
+		  child->case_sensitive = case_sensitive;
+		  child->child = NULL;
+		  child->next = node->child;
+		  node->child = child;
+		}
+	    }
+	}
+      else
+	{
+	  node->mime_type = strdup (mime_type);
+	  node->weight = weight;
+	  node->case_sensitive = case_sensitive;
+	}
+    }
+  else
+    {
+      node->child = _xdg_glob_hash_insert_ucs4 (node->child, text, mime_type, weight, case_sensitive);
+    }
+  return glob_hash_node;
+}
+
+/* glob must be valid UTF-8 */
+static XdgGlobHashNode *
+_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
+			    const char      *text,
+			    const char      *mime_type,
+			    int              weight,
+			    int              case_sensitive)
+{
+  XdgGlobHashNode *node;
+  xdg_unichar_t *unitext;
+  int len;
+
+  unitext = _xdg_convert_to_ucs4 (text, &len);
+  _xdg_reverse_ucs4 (unitext, len);
+  node = _xdg_glob_hash_insert_ucs4 (glob_hash_node, unitext, mime_type, weight, case_sensitive);
+  free (unitext);
+  return node;
+}
+
+typedef struct {
+  const char *mime;
+  int weight;
+} MimeWeight;
+
+static int
+_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
+				      const char      *file_name,
+				      int              len,
+				      int              case_sensitive_check,
+				      MimeWeight       mime_types[],
+				      int              n_mime_types)
+{
+  int n;
+  XdgGlobHashNode *node;
+  xdg_unichar_t character;
+
+  if (glob_hash_node == NULL)
+    return 0;
+
+  character = file_name[len - 1];
+
+  for (node = glob_hash_node; node && character >= node->character; node = node->next)
+    {
+      if (character == node->character)
+        {
+          len--;
+          n = 0;
+          if (len > 0) 
+	    {
+	      n = _xdg_glob_hash_node_lookup_file_name (node->child,
+							file_name,
+							len,
+							case_sensitive_check,
+							mime_types,
+							n_mime_types);
+	    }
+	  if (n == 0)
+	    {
+              if (node->mime_type &&
+		  (case_sensitive_check ||
+		   !node->case_sensitive))
+                {
+	          mime_types[n].mime = node->mime_type;
+		  mime_types[n].weight = node->weight;
+		  n++; 
+                }
+	      node = node->child;
+	      while (n < n_mime_types && node && node->character == 0)
+		{
+                  if (node->mime_type &&
+		      (case_sensitive_check ||
+		       !node->case_sensitive))
+		    {
+		      mime_types[n].mime = node->mime_type;
+		      mime_types[n].weight = node->weight;
+		      n++;
+		    }
+		  node = node->next;
+		}
+	    }
+	  return n;
+	}
+    }
+
+  return 0;
+}
+
+static int compare_mime_weight (const void *a, const void *b)
+{
+  const MimeWeight *aa = (const MimeWeight *)a;
+  const MimeWeight *bb = (const MimeWeight *)b;
+
+  return bb->weight - aa->weight;
+}
+
+#define ISUPPER(c)		((c) >= 'A' && (c) <= 'Z')
+static char *
+ascii_tolower (const char *str)
+{
+  char *p, *lower;
+
+  lower = strdup (str);
+  p = lower;
+  while (*p != 0)
+    {
+      char c = *p;
+      *p++ = ISUPPER (c) ? c - 'A' + 'a' : c;
+    }
+  return lower;
+}
+
+int
+_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
+				 const char  *file_name,
+				 const char  *mime_types[],
+				 int          n_mime_types)
+{
+  XdgGlobList *list;
+  int i, n;
+  MimeWeight mimes[10];
+  int n_mimes = 10;
+  int len;
+  char *lower_case;
+
+  /* First, check the literals */
+
+  assert (file_name != NULL && n_mime_types > 0);
+
+  n = 0;
+
+  lower_case = ascii_tolower (file_name);
+
+  for (list = glob_hash->literal_list; list; list = list->next)
+    {
+      if (strcmp ((const char *)list->data, file_name) == 0)
+	{
+	  mime_types[0] = list->mime_type;
+	  free (lower_case);
+	  return 1;
+	}
+    }
+
+  for (list = glob_hash->literal_list; list; list = list->next)
+    {
+      if (!list->case_sensitive &&
+	  strcmp ((const char *)list->data, lower_case) == 0)
+	{
+	  mime_types[0] = list->mime_type;
+	  free (lower_case);
+	  return 1;
+	}
+    }
+
+
+  len = strlen (file_name);
+  n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, lower_case, len, FALSE,
+					    mimes, n_mimes);
+  if (n == 0)
+    n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, file_name, len, TRUE,
+					      mimes, n_mimes);
+
+  if (n == 0)
+    {
+      for (list = glob_hash->full_list; list && n < n_mime_types; list = list->next)
+        {
+          if (fnmatch ((const char *)list->data, file_name, 0) == 0)
+	    {
+	      mimes[n].mime = list->mime_type;
+	      mimes[n].weight = list->weight;
+	      n++;
+	    }
+        }
+    }
+  free (lower_case);
+
+  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
+
+  if (n_mime_types < n)
+    n = n_mime_types;
+
+  for (i = 0; i < n; i++)
+    mime_types[i] = mimes[i].mime;
+
+  return n;
+}
+
+
+
+/* XdgGlobHash
+ */
+
+XdgGlobHash *
+_xdg_glob_hash_new (void)
+{
+  XdgGlobHash *glob_hash;
+
+  glob_hash = calloc (1, sizeof (XdgGlobHash));
+
+  return glob_hash;
+}
+
+
+static void
+_xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
+{
+  if (node)
+    {
+      if (node->child)
+       _xdg_glob_hash_free_nodes (node->child);
+      if (node->next)
+       _xdg_glob_hash_free_nodes (node->next);
+      if (node->mime_type)
+	free ((void *) node->mime_type);
+      free (node);
+    }
+}
+
+void
+_xdg_glob_hash_free (XdgGlobHash *glob_hash)
+{
+  _xdg_glob_list_free (glob_hash->literal_list);
+  _xdg_glob_list_free (glob_hash->full_list);
+  _xdg_glob_hash_free_nodes (glob_hash->simple_node);
+  free (glob_hash);
+}
+
+XdgGlobType
+_xdg_glob_determine_type (const char *glob)
+{
+  const char *ptr;
+  int maybe_in_simple_glob = FALSE;
+  int first_char = TRUE;
+
+  ptr = glob;
+
+  while (*ptr != '\0')
+    {
+      if (*ptr == '*' && first_char)
+	maybe_in_simple_glob = TRUE;
+      else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
+	  return XDG_GLOB_FULL;
+
+      first_char = FALSE;
+      ptr = _xdg_utf8_next_char (ptr);
+    }
+  if (maybe_in_simple_glob)
+    return XDG_GLOB_SIMPLE;
+  else
+    return XDG_GLOB_LITERAL;
+}
+
+/* glob must be valid UTF-8 */
+void
+_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
+			    const char  *glob,
+			    const char  *mime_type,
+			    int          weight,
+			    int          case_sensitive)
+{
+  XdgGlobType type;
+
+  assert (glob_hash != NULL);
+  assert (glob != NULL);
+
+  type = _xdg_glob_determine_type (glob);
+
+  switch (type)
+    {
+    case XDG_GLOB_LITERAL:
+      glob_hash->literal_list = _xdg_glob_list_append (glob_hash->literal_list, strdup (glob), strdup (mime_type), weight, case_sensitive);
+      break;
+    case XDG_GLOB_SIMPLE:
+      glob_hash->simple_node = _xdg_glob_hash_insert_text (glob_hash->simple_node, glob + 1, mime_type, weight, case_sensitive);
+      break;
+    case XDG_GLOB_FULL:
+      glob_hash->full_list = _xdg_glob_list_append (glob_hash->full_list, strdup (glob), strdup (mime_type), weight, case_sensitive);
+      break;
+    }
+}
+
+void
+_xdg_glob_hash_dump (XdgGlobHash *glob_hash)
+{
+  XdgGlobList *list;
+  printf ("LITERAL STRINGS\n");
+  if (!glob_hash || glob_hash->literal_list == NULL)
+    {
+      printf ("    None\n");
+    }
+  else
+    {
+      for (list = glob_hash->literal_list; list; list = list->next)
+	printf ("    %s - %s %d\n", (char *)list->data, list->mime_type, list->weight);
+    }
+  printf ("\nSIMPLE GLOBS\n");
+  if (!glob_hash || glob_hash->simple_node == NULL)
+    {
+      printf ("    None\n");
+    }
+  else
+    {
+      _xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
+    }
+
+  printf ("\nFULL GLOBS\n");
+  if (!glob_hash || glob_hash->full_list == NULL)
+    {
+      printf ("    None\n");
+    }
+  else
+    {
+      for (list = glob_hash->full_list; list; list = list->next)
+	printf ("    %s - %s %d\n", (char *)list->data, list->mime_type, list->weight);
+    }
+}
+
+
+void
+_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
+			       const char  *file_name,
+			       int          version_two)
+{
+  FILE *glob_file;
+  char line[255];
+  char *p;
+
+  glob_file = fopen (file_name, "r");
+
+  if (glob_file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  while (fgets (line, 255, glob_file) != NULL)
+    {
+      char *colon;
+      char *mimetype, *glob, *end;
+      int weight;
+      int case_sensitive;
+
+      if (line[0] == '#' || line[0] == 0)
+	continue;
+
+      end = line + strlen(line) - 1;
+      if (*end == '\n')
+	*end = 0;
+
+      p = line;
+      if (version_two)
+	{
+	  colon = strchr (p, ':');
+	  if (colon == NULL)
+	    continue;
+	  *colon = 0;
+          weight = atoi (p);
+	  p = colon + 1;
+	}
+      else
+	weight = 50;
+
+      colon = strchr (p, ':');
+      if (colon == NULL)
+	continue;
+      *colon = 0;
+
+      mimetype = p;
+      p = colon + 1;
+      glob = p;
+      case_sensitive = FALSE;
+
+      colon = strchr (p, ':');
+      if (version_two && colon != NULL)
+	{
+	  char *flag;
+
+	  /* We got flags */
+	  *colon = 0;
+	  p = colon + 1;
+
+	  /* Flags end at next colon */
+	  colon = strchr (p, ':');
+	  if (colon != NULL)
+	    *colon = 0;
+
+	  flag = strstr (p, "cs");
+	  if (flag != NULL &&
+	      /* Start or after comma */
+	      (flag == p ||
+	       flag[-1] == ',') &&
+	      /* ends with comma or end of string */
+	      (flag[2] == 0 ||
+	       flag[2] == ','))
+	    case_sensitive = TRUE;
+	}
+
+      _xdg_glob_hash_append_glob (glob_hash, glob, mimetype, weight, case_sensitive);
+    }
+
+  fclose (glob_file);
+}
diff --git a/base/third_party/xdg_mime/xdgmimeglob.h b/base/third_party/xdg_mime/xdgmimeglob.h
new file mode 100644
index 0000000..0018292
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeglob.h
@@ -0,0 +1,70 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeglob.h: Private file.  Datastructure for storing the globs.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_GLOB_H__
+#define __XDG_MIME_GLOB_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgGlobHash XdgGlobHash;
+
+typedef enum
+{
+  XDG_GLOB_LITERAL, /* Makefile */
+  XDG_GLOB_SIMPLE,  /* *.gif */
+  XDG_GLOB_FULL     /* x*.[ch] */
+} XdgGlobType;
+
+  
+#ifdef XDG_PREFIX
+#define _xdg_mime_glob_read_from_file         XDG_RESERVED_ENTRY(glob_read_from_file)
+#define _xdg_glob_hash_new                    XDG_RESERVED_ENTRY(hash_new)
+#define _xdg_glob_hash_free                   XDG_RESERVED_ENTRY(hash_free)
+#define _xdg_glob_hash_lookup_file_name       XDG_RESERVED_ENTRY(hash_lookup_file_name)
+#define _xdg_glob_hash_append_glob            XDG_RESERVED_ENTRY(hash_append_glob)
+#define _xdg_glob_determine_type              XDG_RESERVED_ENTRY(determine_type)
+#define _xdg_glob_hash_dump                   XDG_RESERVED_ENTRY(hash_dump)
+#endif
+
+void         _xdg_mime_glob_read_from_file   (XdgGlobHash *glob_hash,
+					      const char  *file_name,
+					      int          version_two);
+XdgGlobHash *_xdg_glob_hash_new              (void);
+void         _xdg_glob_hash_free             (XdgGlobHash *glob_hash);
+int          _xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
+					      const char  *text,
+					      const char  *mime_types[],
+					      int          n_mime_types);
+void         _xdg_glob_hash_append_glob      (XdgGlobHash *glob_hash,
+					      const char  *glob,
+					      const char  *mime_type,
+					      int          weight,
+					      int          case_sensitive);
+XdgGlobType  _xdg_glob_determine_type        (const char  *glob);
+void         _xdg_glob_hash_dump             (XdgGlobHash *glob_hash);
+
+#endif /* __XDG_MIME_GLOB_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeicon.c b/base/third_party/xdg_mime/xdgmimeicon.c
new file mode 100644
index 0000000..05c9473
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeicon.c
@@ -0,0 +1,183 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeicon.c: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2008  Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeicon.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgIcon XdgIcon;
+
+struct XdgIcon 
+{
+  char *mime_type;
+  char *icon_name;
+};
+
+struct XdgIconList
+{
+  struct XdgIcon *icons;
+  int n_icons;
+};
+
+XdgIconList *
+_xdg_mime_icon_list_new (void)
+{
+  XdgIconList *list;
+
+  list = malloc (sizeof (XdgIconList));
+
+  list->icons = NULL;
+  list->n_icons = 0;
+
+  return list;
+}
+
+void         
+_xdg_mime_icon_list_free (XdgIconList *list)
+{
+  int i;
+
+  if (list->icons)
+    {
+      for (i = 0; i < list->n_icons; i++)
+	{
+	  free (list->icons[i].mime_type);
+	  free (list->icons[i].icon_name);
+	}
+      free (list->icons);
+    }
+  free (list);
+}
+
+static int
+icon_entry_cmp (const void *v1, const void *v2)
+{
+  return strcmp (((XdgIcon *)v1)->mime_type, ((XdgIcon *)v2)->mime_type);
+}
+
+const char  *
+_xdg_mime_icon_list_lookup (XdgIconList *list,
+			    const char  *mime_type)
+{
+  XdgIcon *entry;
+  XdgIcon key;
+
+  if (list->n_icons > 0)
+    {
+      key.mime_type = (char *)mime_type;
+      key.icon_name = NULL;
+
+      entry = bsearch (&key, list->icons, list->n_icons,
+		       sizeof (XdgIcon), icon_entry_cmp);
+      if (entry)
+        return entry->icon_name;
+    }
+
+  return NULL;
+}
+
+void
+_xdg_mime_icon_read_from_file (XdgIconList *list,
+			       const char   *file_name)
+{
+  FILE *file;
+  char line[255];
+  int alloc;
+
+  file = fopen (file_name, "r");
+
+  if (file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  alloc = list->n_icons + 16;
+  list->icons = realloc (list->icons, alloc * sizeof (XdgIcon));
+  while (fgets (line, 255, file) != NULL)
+    {
+      char *sep;
+      if (line[0] == '#')
+	continue;
+
+      sep = strchr (line, ':');
+      if (sep == NULL)
+	continue;
+      *(sep++) = '\000';
+      sep[strlen (sep) -1] = '\000';
+      if (list->n_icons == alloc)
+	{
+	  alloc <<= 1;
+	  list->icons = realloc (list->icons, 
+				   alloc * sizeof (XdgIcon));
+	}
+      list->icons[list->n_icons].mime_type = strdup (line);
+      list->icons[list->n_icons].icon_name = strdup (sep);
+      list->n_icons++;
+    }
+  list->icons = realloc (list->icons, 
+			   list->n_icons * sizeof (XdgIcon));
+
+  fclose (file);  
+  
+  if (list->n_icons > 1)
+    qsort (list->icons, list->n_icons, 
+           sizeof (XdgIcon), icon_entry_cmp);
+}
+
+
+void
+_xdg_mime_icon_list_dump (XdgIconList *list)
+{
+  int i;
+
+  if (list->icons)
+    {
+      for (i = 0; i < list->n_icons; i++)
+	{
+	  printf ("%s %s\n", 
+		  list->icons[i].mime_type,
+		  list->icons[i].icon_name);
+	}
+    }
+}
+
+
diff --git a/base/third_party/xdg_mime/xdgmimeicon.h b/base/third_party/xdg_mime/xdgmimeicon.h
new file mode 100644
index 0000000..b5f2583
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeicon.h
@@ -0,0 +1,50 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeicon.h: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2008  Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_ICON_H__
+#define __XDG_MIME_ICON_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgIconList XdgIconList;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_icon_read_from_file        XDG_ENTRY(icon_read_from_file)
+#define _xdg_mime_icon_list_new              XDG_ENTRY(icon_list_new)
+#define _xdg_mime_icon_list_free             XDG_ENTRY(icon_list_free)
+#define _xdg_mime_icon_list_lookup           XDG_ENTRY(icon_list_lookup)
+#define _xdg_mime_icon_list_dump             XDG_ENTRY(icon_list_dump)
+#endif
+
+void          _xdg_mime_icon_read_from_file (XdgIconList *list,
+					    const char   *file_name);
+XdgIconList  *_xdg_mime_icon_list_new       (void);
+void          _xdg_mime_icon_list_free      (XdgIconList *list);
+const char   *_xdg_mime_icon_list_lookup    (XdgIconList *list,
+					     const char  *mime);
+void          _xdg_mime_icon_list_dump      (XdgIconList *list);
+
+#endif /* __XDG_MIME_ICON_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeint.c b/base/third_party/xdg_mime/xdgmimeint.c
new file mode 100644
index 0000000..cf789d9
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeint.c
@@ -0,0 +1,206 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeint.c: Internal defines and functions.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeint.h"
+#include <ctype.h>
+#include <string.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+static const char _xdg_utf8_skip_data[256] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+
+const char * const _xdg_utf8_skip = _xdg_utf8_skip_data;
+
+
+
+/* Returns the number of unprocessed characters. */
+xdg_unichar_t
+_xdg_utf8_to_ucs4(const char *source)
+{
+  xdg_unichar_t ucs32;
+  if( ! ( *source & 0x80 ) )
+    {
+      ucs32 = *source;
+    }
+  else
+    {
+      int bytelength = 0;
+      xdg_unichar_t result;
+      if ( ! (*source & 0x40) )
+	{
+	  ucs32 = *source;
+	}
+      else
+	{
+	  if ( ! (*source & 0x20) )
+	    {
+	      result = *source++ & 0x1F;
+	      bytelength = 2;
+	    }
+	  else if ( ! (*source & 0x10) )
+	    {
+	      result = *source++ & 0x0F;
+	      bytelength = 3;
+	    }
+	  else if ( ! (*source & 0x08) )
+	    {
+	      result = *source++ & 0x07;
+	      bytelength = 4;
+	    }
+	  else if ( ! (*source & 0x04) )
+	    {
+	      result = *source++ & 0x03;
+	      bytelength = 5;
+	    }
+	  else if ( ! (*source & 0x02) )
+	    {
+	      result = *source++ & 0x01;
+	      bytelength = 6;
+	    }
+	  else
+	    {
+	      result = *source++;
+	      bytelength = 1;
+	    }
+
+	  for ( bytelength --; bytelength > 0; bytelength -- )
+	    {
+	      result <<= 6;
+	      result |= *source++ & 0x3F;
+	    }
+	  ucs32 = result;
+	}
+    }
+  return ucs32;
+}
+
+
+/* hullo.  this is great code.  don't rewrite it */
+
+xdg_unichar_t
+_xdg_ucs4_to_lower (xdg_unichar_t source)
+{
+  /* FIXME: Do a real to_upper sometime */
+  /* CaseFolding-3.2.0.txt has a table of rules. */
+  if ((source & 0xFF) == source)
+    return (xdg_unichar_t) tolower ((unsigned char) source);
+  return source;
+}
+
+int
+_xdg_utf8_validate (const char *source)
+{
+  /* FIXME: actually write */
+  return TRUE;
+}
+
+const char *
+_xdg_get_base_name (const char *file_name)
+{
+  const char *base_name;
+
+  if (file_name == NULL)
+    return NULL;
+
+  base_name = strrchr (file_name, '/');
+
+  if (base_name == NULL)
+    return file_name;
+  else
+    return base_name + 1;
+}
+
+xdg_unichar_t *
+_xdg_convert_to_ucs4 (const char *source, int *len)
+{
+  xdg_unichar_t *out;
+  int i;
+  const char *p;
+
+  out = malloc (sizeof (xdg_unichar_t) * (strlen (source) + 1));
+
+  p = source;
+  i = 0;
+  while (*p) 
+    {
+      out[i++] = _xdg_utf8_to_ucs4 (p);
+      p = _xdg_utf8_next_char (p); 
+    }
+  out[i] = 0;
+  *len = i;
+ 
+  return out;
+}
+
+void
+_xdg_reverse_ucs4 (xdg_unichar_t *source, int len)
+{
+  xdg_unichar_t c;
+  int i;
+
+  for (i = 0; i < len - i - 1; i++) 
+    {
+      c = source[i]; 
+      source[i] = source[len - i - 1];
+      source[len - i - 1] = c;
+    }
+}
+
+const char *
+_xdg_binary_or_text_fallback(const void *data, size_t len)
+{
+  unsigned char *chardata;
+  int i;
+
+  chardata = (unsigned char *) data;
+  for (i = 0; i < 32 && i < len; ++i)
+    {
+       if (chardata[i] < 32 && chardata[i] != 9 && chardata[i] != 10 && chardata[i] != 13)
+         return XDG_MIME_TYPE_UNKNOWN; /* binary data */
+    }
+
+  return XDG_MIME_TYPE_TEXTPLAIN;
+}
diff --git a/base/third_party/xdg_mime/xdgmimeint.h b/base/third_party/xdg_mime/xdgmimeint.h
new file mode 100644
index 0000000..9e8b2cb
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeint.h
@@ -0,0 +1,78 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeint.h: Internal defines and functions.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_INT_H__
+#define __XDG_MIME_INT_H__
+
+#include "xdgmime.h"
+
+
+#ifndef	FALSE
+#define	FALSE (0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE (!FALSE)
+#endif
+
+/* FIXME: Needs to be configure check */
+typedef unsigned int   xdg_unichar_t;
+typedef unsigned char  xdg_uchar8_t;
+typedef unsigned short xdg_uint16_t;
+typedef unsigned int   xdg_uint32_t;
+
+#ifdef XDG_PREFIX
+#define _xdg_utf8_skip       XDG_RESERVED_ENTRY(utf8_skip)
+#define _xdg_utf8_to_ucs4    XDG_RESERVED_ENTRY(utf8_to_ucs4)
+#define _xdg_ucs4_to_lower   XDG_RESERVED_ENTRY(ucs4_to_lower)
+#define _xdg_utf8_validate   XDG_RESERVED_ENTRY(utf8_validate)
+#define _xdg_get_base_name   XDG_RESERVED_ENTRY(get_base_name)
+#define _xdg_convert_to_ucs4 XDG_RESERVED_ENTRY(convert_to_ucs4)
+#define _xdg_reverse_ucs4    XDG_RESERVED_ENTRY(reverse_ucs4)
+#endif
+
+#define SWAP_BE16_TO_LE16(val) (xdg_uint16_t)(((xdg_uint16_t)(val) << 8)|((xdg_uint16_t)(val) >> 8))
+
+#define SWAP_BE32_TO_LE32(val) (xdg_uint32_t)((((xdg_uint32_t)(val) & 0xFF000000U) >> 24) |	\
+					      (((xdg_uint32_t)(val) & 0x00FF0000U) >> 8) |	\
+					      (((xdg_uint32_t)(val) & 0x0000FF00U) << 8) |	\
+					      (((xdg_uint32_t)(val) & 0x000000FFU) << 24))
+/* UTF-8 utils
+ */
+extern const char *const _xdg_utf8_skip;
+#define _xdg_utf8_next_char(p) (char *)((p) + _xdg_utf8_skip[*(unsigned char *)(p)])
+#define _xdg_utf8_char_size(p) (int) (_xdg_utf8_skip[*(unsigned char *)(p)])
+
+xdg_unichar_t  _xdg_utf8_to_ucs4  (const char    *source);
+xdg_unichar_t  _xdg_ucs4_to_lower (xdg_unichar_t  source);
+int            _xdg_utf8_validate (const char    *source);
+xdg_unichar_t *_xdg_convert_to_ucs4 (const char *source, int *len);
+void           _xdg_reverse_ucs4 (xdg_unichar_t *source, int len);
+const char    *_xdg_get_base_name (const char    *file_name);
+const char    *_xdg_binary_or_text_fallback(const void *data, size_t len);
+
+#endif /* __XDG_MIME_INT_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimemagic.c b/base/third_party/xdg_mime/xdgmimemagic.c
new file mode 100644
index 0000000..a2320f5
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimemagic.c
@@ -0,0 +1,813 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimemagic.: Private file.  Datastructure for storing magic files.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include "xdgmimemagic.h"
+#include "xdgmimeint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
+# define getc_unlocked(fp) getc (fp)
+#endif
+
+typedef struct XdgMimeMagicMatch XdgMimeMagicMatch;
+typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet;
+
+typedef enum
+{
+  XDG_MIME_MAGIC_SECTION,
+  XDG_MIME_MAGIC_MAGIC,
+  XDG_MIME_MAGIC_ERROR,
+  XDG_MIME_MAGIC_EOF
+} XdgMimeMagicState;
+
+struct XdgMimeMagicMatch
+{
+  const char *mime_type;
+  int priority;
+  XdgMimeMagicMatchlet *matchlet;
+  XdgMimeMagicMatch *next;
+};
+
+
+struct XdgMimeMagicMatchlet
+{
+  int indent;
+  int offset;
+  unsigned int value_length;
+  unsigned char *value;
+  unsigned char *mask;
+  unsigned int range_length;
+  unsigned int word_size;
+  XdgMimeMagicMatchlet *next;
+};
+
+
+struct XdgMimeMagic
+{
+  XdgMimeMagicMatch *match_list;
+  int max_extent;
+};
+
+static XdgMimeMagicMatch *
+_xdg_mime_magic_match_new (void)
+{
+  return calloc (1, sizeof (XdgMimeMagicMatch));
+}
+
+
+static XdgMimeMagicMatchlet *
+_xdg_mime_magic_matchlet_new (void)
+{
+  XdgMimeMagicMatchlet *matchlet;
+
+  matchlet = malloc (sizeof (XdgMimeMagicMatchlet));
+
+  matchlet->indent = 0;
+  matchlet->offset = 0;
+  matchlet->value_length = 0;
+  matchlet->value = NULL;
+  matchlet->mask = NULL;
+  matchlet->range_length = 1;
+  matchlet->word_size = 1;
+  matchlet->next = NULL;
+
+  return matchlet;
+}
+
+
+static void
+_xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
+{
+  if (mime_magic_matchlet)
+    {
+      if (mime_magic_matchlet->next)
+	_xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
+      if (mime_magic_matchlet->value)
+	free (mime_magic_matchlet->value);
+      if (mime_magic_matchlet->mask)
+	free (mime_magic_matchlet->mask);
+      free (mime_magic_matchlet);
+    }
+}
+
+
+/* Frees mime_magic_match and the remainder of its list
+ */
+static void
+_xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
+{
+  XdgMimeMagicMatch *ptr, *next;
+
+  ptr = mime_magic_match;
+  while (ptr)
+    {
+      next = ptr->next;
+
+      if (ptr->mime_type)
+	free ((void *) ptr->mime_type);
+      if (ptr->matchlet)
+	_xdg_mime_magic_matchlet_free (ptr->matchlet);
+      free (ptr);
+
+      ptr = next;
+    }
+}
+
+/* Reads in a hunk of data until a newline character or a '\000' is hit.  The
+ * returned string is null terminated, and doesn't include the newline.
+ */
+static unsigned char *
+_xdg_mime_magic_read_to_newline (FILE *magic_file,
+				 int  *end_of_file)
+{
+  unsigned char *retval;
+  int c;
+  int len, pos;
+
+  len = 128;
+  pos = 0;
+  retval = malloc (len);
+  *end_of_file = FALSE;
+
+  while (TRUE)
+    {
+      c = getc_unlocked (magic_file);
+      if (c == EOF)
+	{
+	  *end_of_file = TRUE;
+	  break;
+	}
+      if (c == '\n' || c == '\000')
+	break;
+      retval[pos++] = (unsigned char) c;
+      if (pos % 128 == 127)
+	{
+	  len = len + 128;
+	  retval = realloc (retval, len);
+	}
+    }
+
+  retval[pos] = '\000';
+  return retval;
+}
+
+/* Returns the number read from the file, or -1 if no number could be read.
+ */
+static int
+_xdg_mime_magic_read_a_number (FILE *magic_file,
+			       int  *end_of_file)
+{
+  /* LONG_MAX is about 20 characters on my system */
+#define MAX_NUMBER_SIZE 30
+  char number_string[MAX_NUMBER_SIZE + 1];
+  int pos = 0;
+  int c;
+  long retval = -1;
+
+  while (TRUE)
+    {
+      c = getc_unlocked (magic_file);
+
+      if (c == EOF)
+	{
+	  *end_of_file = TRUE;
+	  break;
+	}
+      if (! isdigit (c))
+	{
+	  ungetc (c, magic_file);
+	  break;
+	}
+      number_string[pos] = (char) c;
+      pos++;
+      if (pos == MAX_NUMBER_SIZE)
+	break;
+    }
+  if (pos > 0)
+    {
+      number_string[pos] = '\000';
+      errno = 0;
+      retval = strtol (number_string, NULL, 10);
+
+      if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
+	return -1;
+    }
+
+  return retval;
+}
+
+/* Headers are of the format:
+ * [<priority>:<mime-type>]
+ */
+static XdgMimeMagicState
+_xdg_mime_magic_parse_header (FILE *magic_file, XdgMimeMagicMatch *match)
+{
+  int c;
+  char *buffer;
+  char *end_ptr;
+  int end_of_file = 0;
+
+  assert (magic_file != NULL);
+  assert (match != NULL);
+
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+  if (c != '[')
+    return XDG_MIME_MAGIC_ERROR;
+
+  match->priority = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+  if (end_of_file)
+    return XDG_MIME_MAGIC_EOF;
+  if (match->priority == -1)
+    return XDG_MIME_MAGIC_ERROR;
+
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+  if (c != ':')
+    return XDG_MIME_MAGIC_ERROR;
+
+  buffer = (char *)_xdg_mime_magic_read_to_newline (magic_file, &end_of_file);
+  if (end_of_file)
+    return XDG_MIME_MAGIC_EOF;
+
+  end_ptr = buffer;
+  while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
+    end_ptr++;
+  if (*end_ptr != ']')
+    {
+      free (buffer);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+  *end_ptr = '\000';
+
+  match->mime_type = strdup (buffer);
+  free (buffer);
+
+  return XDG_MIME_MAGIC_MAGIC;
+}
+
+static XdgMimeMagicState
+_xdg_mime_magic_parse_error (FILE *magic_file)
+{
+  int c;
+
+  while (1)
+    {
+      c = getc_unlocked (magic_file);
+      if (c == EOF)
+	return XDG_MIME_MAGIC_EOF;
+      if (c == '\n')
+	return XDG_MIME_MAGIC_SECTION;
+    }
+}
+
+/* Headers are of the format:
+ * [ indent ] ">" start-offset "=" value
+ * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
+ */
+static XdgMimeMagicState
+_xdg_mime_magic_parse_magic_line (FILE              *magic_file,
+				  XdgMimeMagicMatch *match)
+{
+  XdgMimeMagicMatchlet *matchlet;
+  int c;
+  int end_of_file;
+  int indent = 0;
+  int bytes_read;
+
+  assert (magic_file != NULL);
+
+  /* Sniff the buffer to make sure it's a valid line */
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+  else if (c == '[')
+    {
+      ungetc (c, magic_file);
+      return XDG_MIME_MAGIC_SECTION;
+    }
+  else if (c == '\n')
+    return XDG_MIME_MAGIC_MAGIC;
+
+  /* At this point, it must be a digit or a '>' */
+  end_of_file = FALSE;
+  if (isdigit (c))
+    {
+      ungetc (c, magic_file);
+      indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+      if (end_of_file)
+	return XDG_MIME_MAGIC_EOF;
+      if (indent == -1)
+	return XDG_MIME_MAGIC_ERROR;
+      c = getc_unlocked (magic_file);
+      if (c == EOF)
+	return XDG_MIME_MAGIC_EOF;
+    }
+
+  if (c != '>')
+    return XDG_MIME_MAGIC_ERROR;
+
+  matchlet = _xdg_mime_magic_matchlet_new ();
+  matchlet->indent = indent;
+  matchlet->offset = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+  if (end_of_file)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  if (matchlet->offset == -1)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  else if (c != '=')
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+
+  /* Next two bytes determine how long the value is */
+  matchlet->value_length = 0;
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  matchlet->value_length = c & 0xFF;
+  matchlet->value_length = matchlet->value_length << 8;
+
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  matchlet->value_length = matchlet->value_length + (c & 0xFF);
+
+  matchlet->value = malloc (matchlet->value_length);
+
+  /* OOM */
+  if (matchlet->value == NULL)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+  bytes_read = fread (matchlet->value, 1, matchlet->value_length, magic_file);
+  if (bytes_read != matchlet->value_length)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      if (feof (magic_file))
+	return XDG_MIME_MAGIC_EOF;
+      else
+	return XDG_MIME_MAGIC_ERROR;
+    }
+
+  c = getc_unlocked (magic_file);
+  if (c == '&')
+    {
+      matchlet->mask = malloc (matchlet->value_length);
+      /* OOM */
+      if (matchlet->mask == NULL)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_ERROR;
+	}
+      bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
+      if (bytes_read != matchlet->value_length)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  if (feof (magic_file))
+	    return XDG_MIME_MAGIC_EOF;
+	  else
+	    return XDG_MIME_MAGIC_ERROR;
+	}
+      c = getc_unlocked (magic_file);
+    }
+
+  if (c == '~')
+    {
+      matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+      if (end_of_file)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_EOF;
+	}
+      if (matchlet->word_size != 0 &&
+	  matchlet->word_size != 1 &&
+	  matchlet->word_size != 2 &&
+	  matchlet->word_size != 4)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_ERROR;
+	}
+      c = getc_unlocked (magic_file);
+    }
+
+  if (c == '+')
+    {
+      matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+      if (end_of_file)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_EOF;
+	}
+      if (matchlet->range_length == -1)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_ERROR;
+	}
+      c = getc_unlocked (magic_file);
+    }
+
+
+  if (c == '\n')
+    {
+      /* We clean up the matchlet, byte swapping if needed */
+      if (matchlet->word_size > 1)
+	{
+	  int i;
+	  if (matchlet->value_length % matchlet->word_size != 0)
+	    {
+	      _xdg_mime_magic_matchlet_free (matchlet);
+	      return XDG_MIME_MAGIC_ERROR;
+	    }
+	  /* FIXME: need to get this defined in a <config.h> style file */
+#if LITTLE_ENDIAN
+	  for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
+	    {
+	      if (matchlet->word_size == 2)
+		*((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
+	      else if (matchlet->word_size == 4)
+		*((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
+	      if (matchlet->mask)
+		{
+		  if (matchlet->word_size == 2)
+		    *((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
+		  else if (matchlet->word_size == 4)
+		    *((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
+
+		}
+	    }
+#endif
+	}
+
+      matchlet->next = match->matchlet;
+      match->matchlet = matchlet;
+
+
+      return XDG_MIME_MAGIC_MAGIC;
+    }
+
+  _xdg_mime_magic_matchlet_free (matchlet);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+
+  return XDG_MIME_MAGIC_ERROR;
+}
+
+static int
+_xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
+					  const void           *data,
+					  size_t                len)
+{
+  int i, j;
+  for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++)
+    {
+      int valid_matchlet = TRUE;
+
+      if (i + matchlet->value_length > len)
+	return FALSE;
+
+      if (matchlet->mask)
+	{
+	  for (j = 0; j < matchlet->value_length; j++)
+	    {
+	      if ((matchlet->value[j] & matchlet->mask[j]) !=
+		  ((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
+		{
+		  valid_matchlet = FALSE;
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  for (j = 0; j <  matchlet->value_length; j++)
+	    {
+	      if (matchlet->value[j] != ((unsigned char *) data)[j + i])
+		{
+		  valid_matchlet = FALSE;
+		  break;
+		}
+	    }
+	}
+      if (valid_matchlet)
+	return TRUE;
+    }
+  return FALSE;
+}
+
+static int
+_xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
+					const void           *data,
+					size_t                len,
+					int                   indent)
+{
+  while ((matchlet != NULL) && (matchlet->indent == indent))
+    {
+      if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
+	{
+	  if ((matchlet->next == NULL) ||
+	      (matchlet->next->indent <= indent))
+	    return TRUE;
+
+	  if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
+						      data,
+						      len,
+						      indent + 1))
+	    return TRUE;
+	}
+
+      do
+	{
+	  matchlet = matchlet->next;
+	}
+      while (matchlet && matchlet->indent > indent);
+    }
+
+  return FALSE;
+}
+
+static int
+_xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
+				       const void        *data,
+				       size_t             len)
+{
+  return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
+}
+
+static void
+_xdg_mime_magic_insert_match (XdgMimeMagic      *mime_magic,
+			      XdgMimeMagicMatch *match)
+{
+  XdgMimeMagicMatch *list;
+
+  if (mime_magic->match_list == NULL)
+    {
+      mime_magic->match_list = match;
+      return;
+    }
+
+  if (match->priority > mime_magic->match_list->priority)
+    {
+      match->next = mime_magic->match_list;
+      mime_magic->match_list = match;
+      return;
+    }
+
+  list = mime_magic->match_list;
+  while (list->next != NULL)
+    {
+      if (list->next->priority < match->priority)
+	{
+	  match->next = list->next;
+	  list->next = match;
+	  return;
+	}
+      list = list->next;
+    }
+  list->next = match;
+  match->next = NULL;
+}
+
+XdgMimeMagic *
+_xdg_mime_magic_new (void)
+{
+  return calloc (1, sizeof (XdgMimeMagic));
+}
+
+void
+_xdg_mime_magic_free (XdgMimeMagic *mime_magic)
+{
+  if (mime_magic) {
+    _xdg_mime_magic_match_free (mime_magic->match_list);
+    free (mime_magic);
+  }
+}
+
+int
+_xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
+{
+  return mime_magic->max_extent;
+}
+
+const char *
+_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
+			     const void   *data,
+			     size_t        len,
+			     int           *result_prio,
+                             const char   *mime_types[],
+                             int           n_mime_types)
+{
+  XdgMimeMagicMatch *match;
+  const char *mime_type;
+  int n;
+  int prio;
+
+  prio = 0;
+  mime_type = NULL;
+  for (match = mime_magic->match_list; match; match = match->next)
+    {
+      if (_xdg_mime_magic_match_compare_to_data (match, data, len))
+	{
+	  prio = match->priority;
+	  mime_type = match->mime_type;
+	  break;
+	}
+      else 
+	{
+	  for (n = 0; n < n_mime_types; n++)
+	    {
+	      if (mime_types[n] && 
+		  _xdg_mime_mime_type_equal (mime_types[n], match->mime_type))
+		mime_types[n] = NULL;
+	    }
+	}
+    }
+
+  if (mime_type == NULL)
+    {
+      for (n = 0; n < n_mime_types; n++)
+	{
+	  if (mime_types[n])
+	    mime_type = mime_types[n];
+	}
+    }
+  
+  if (result_prio)
+    *result_prio = prio;
+
+  return mime_type;
+}
+
+static void
+_xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
+{
+  XdgMimeMagicMatch *match;
+  int max_extent = 0;
+
+  for (match = mime_magic->match_list; match; match = match->next)
+    {
+      XdgMimeMagicMatchlet *matchlet;
+
+      for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
+	{
+	  int extent;
+
+	  extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
+	  if (max_extent < extent)
+	    max_extent = extent;
+	}
+    }
+
+  mime_magic->max_extent = max_extent;
+}
+
+static XdgMimeMagicMatchlet *
+_xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
+{
+  XdgMimeMagicMatchlet *new_list;
+  XdgMimeMagicMatchlet *tmp;
+
+  if ((matchlets == NULL) || (matchlets->next == NULL))
+    return matchlets;
+
+  new_list = NULL;
+  tmp = matchlets;
+  while (tmp != NULL)
+    {
+      XdgMimeMagicMatchlet *matchlet;
+
+      matchlet = tmp;
+      tmp = tmp->next;
+      matchlet->next = new_list;
+      new_list = matchlet;
+    }
+
+  return new_list;
+
+}
+
+static void
+_xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
+				 FILE         *magic_file)
+{
+  XdgMimeMagicState state;
+  XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
+
+  state = XDG_MIME_MAGIC_SECTION;
+
+  while (state != XDG_MIME_MAGIC_EOF)
+    {
+      switch (state)
+	{
+	case XDG_MIME_MAGIC_SECTION:
+	  match = _xdg_mime_magic_match_new ();
+	  state = _xdg_mime_magic_parse_header (magic_file, match);
+	  if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
+	    _xdg_mime_magic_match_free (match);
+	  break;
+	case XDG_MIME_MAGIC_MAGIC:
+	  state = _xdg_mime_magic_parse_magic_line (magic_file, match);
+	  if (state == XDG_MIME_MAGIC_SECTION ||
+	      (state == XDG_MIME_MAGIC_EOF && match->mime_type))
+	    {
+	      match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
+	      _xdg_mime_magic_insert_match (mime_magic, match);
+	    }
+	  else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
+	    _xdg_mime_magic_match_free (match);
+	  break;
+	case XDG_MIME_MAGIC_ERROR:
+	  state = _xdg_mime_magic_parse_error (magic_file);
+	  break;
+	case XDG_MIME_MAGIC_EOF:
+	default:
+	  /* Make the compiler happy */
+	  assert (0);
+	}
+    }
+  _xdg_mime_update_mime_magic_extents (mime_magic);
+}
+
+void
+_xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
+				const char   *file_name)
+{
+  FILE *magic_file;
+  char header[12];
+
+  magic_file = fopen (file_name, "r");
+
+  if (magic_file == NULL)
+    return;
+
+  if (fread (header, 1, 12, magic_file) == 12)
+    {
+      if (memcmp ("MIME-Magic\0\n", header, 12) == 0)
+        _xdg_mime_magic_read_magic_file (mime_magic, magic_file);
+    }
+
+  fclose (magic_file);
+}
diff --git a/base/third_party/xdg_mime/xdgmimemagic.h b/base/third_party/xdg_mime/xdgmimemagic.h
new file mode 100644
index 0000000..35c8039
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimemagic.h
@@ -0,0 +1,57 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimemagic.h: Private file.  Datastructure for storing the magic files.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_MAGIC_H__
+#define __XDG_MIME_MAGIC_H__
+
+#include <unistd.h>
+#include "xdgmime.h"
+typedef struct XdgMimeMagic XdgMimeMagic;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_glob_read_from_file             XDG_RESERVED_ENTRY(glob_read_from_file)
+#define _xdg_mime_magic_new                       XDG_RESERVED_ENTRY(magic_new)
+#define _xdg_mime_magic_read_from_file            XDG_RESERVED_ENTRY(magic_read_from_file)
+#define _xdg_mime_magic_free                      XDG_RESERVED_ENTRY(magic_free)
+#define _xdg_mime_magic_get_buffer_extents        XDG_RESERVED_ENTRY(magic_get_buffer_extents)
+#define _xdg_mime_magic_lookup_data               XDG_RESERVED_ENTRY(magic_lookup_data)
+#endif
+
+
+XdgMimeMagic *_xdg_mime_magic_new                (void);
+void          _xdg_mime_magic_read_from_file     (XdgMimeMagic *mime_magic,
+						  const char   *file_name);
+void          _xdg_mime_magic_free               (XdgMimeMagic *mime_magic);
+int           _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic);
+const char   *_xdg_mime_magic_lookup_data        (XdgMimeMagic *mime_magic,
+						  const void   *data,
+						  size_t        len,
+						  int          *result_prio,
+						  const char   *mime_types[],
+						  int           n_mime_types);
+
+#endif /* __XDG_MIME_MAGIC_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeparent.c b/base/third_party/xdg_mime/xdgmimeparent.c
new file mode 100644
index 0000000..511bbac
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeparent.c
@@ -0,0 +1,219 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.c: Private file.  Datastructure for storing the hierarchy.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 2004  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeparent.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgMimeParents XdgMimeParents;
+
+struct XdgMimeParents
+{
+  char *mime;
+  char **parents;
+  int n_parents;
+};
+
+struct XdgParentList
+{
+  struct XdgMimeParents *parents;
+  int n_mimes;
+};
+
+XdgParentList *
+_xdg_mime_parent_list_new (void)
+{
+  XdgParentList *list;
+
+  list = malloc (sizeof (XdgParentList));
+
+  list->parents = NULL;
+  list->n_mimes = 0;
+
+  return list;
+}
+
+void         
+_xdg_mime_parent_list_free (XdgParentList *list)
+{
+  int i;
+  char **p;
+
+  if (list->parents)
+    {
+      for (i = 0; i < list->n_mimes; i++)
+	{
+	  for (p = list->parents[i].parents; *p; p++)
+	    free (*p);
+
+	  free (list->parents[i].parents);
+	  free (list->parents[i].mime);
+	}
+      free (list->parents);
+    }
+  free (list);
+}
+
+static int
+parent_entry_cmp (const void *v1, const void *v2)
+{
+  return strcmp (((XdgMimeParents *)v1)->mime, ((XdgMimeParents *)v2)->mime);
+}
+
+const char **
+_xdg_mime_parent_list_lookup (XdgParentList *list,
+			      const char    *mime)
+{
+  XdgMimeParents *entry;
+  XdgMimeParents key;
+
+  if (list->n_mimes > 0)
+    {
+      key.mime = (char *)mime;
+      key.parents = NULL;
+
+      entry = bsearch (&key, list->parents, list->n_mimes,
+		       sizeof (XdgMimeParents), &parent_entry_cmp);
+      if (entry)
+        return (const char **)entry->parents;
+    }
+
+  return NULL;
+}
+
+void
+_xdg_mime_parent_read_from_file (XdgParentList *list,
+				 const char    *file_name)
+{
+  FILE *file;
+  char line[255];
+  int i, alloc;
+  XdgMimeParents *entry;
+
+  file = fopen (file_name, "r");
+
+  if (file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  alloc = list->n_mimes + 16;
+  list->parents = realloc (list->parents, alloc * sizeof (XdgMimeParents));
+  while (fgets (line, 255, file) != NULL)
+    {
+      char *sep;
+      if (line[0] == '#')
+	continue;
+
+      sep = strchr (line, ' ');
+      if (sep == NULL)
+	continue;
+      *(sep++) = '\000';
+      sep[strlen (sep) -1] = '\000';
+      entry = NULL;
+      for (i = 0; i < list->n_mimes; i++)
+	{
+	  if (strcmp (list->parents[i].mime, line) == 0)
+	    {
+	      entry = &(list->parents[i]);
+	      break;
+	    }
+	}
+      
+      if (!entry)
+	{
+	  if (list->n_mimes == alloc)
+	    {
+	      alloc <<= 1;
+	      list->parents = realloc (list->parents, 
+				       alloc * sizeof (XdgMimeParents));
+	    }
+	  list->parents[list->n_mimes].mime = strdup (line);
+	  list->parents[list->n_mimes].parents = NULL;
+	  entry = &(list->parents[list->n_mimes]);
+	  list->n_mimes++;
+	}
+
+      if (!entry->parents)
+	{
+	  entry->n_parents = 1;
+	  entry->parents = malloc ((entry->n_parents + 1) * sizeof (char *));
+	}
+      else
+	{
+	  entry->n_parents += 1;
+	  entry->parents = realloc (entry->parents, 
+				    (entry->n_parents + 2) * sizeof (char *));
+	}
+      entry->parents[entry->n_parents - 1] = strdup (sep);
+      entry->parents[entry->n_parents] = NULL;
+    }
+
+  list->parents = realloc (list->parents, 
+			   list->n_mimes * sizeof (XdgMimeParents));
+
+  fclose (file);  
+  
+  if (list->n_mimes > 1)
+    qsort (list->parents, list->n_mimes, 
+           sizeof (XdgMimeParents), &parent_entry_cmp);
+}
+
+
+void         
+_xdg_mime_parent_list_dump (XdgParentList *list)
+{
+  int i;
+  char **p;
+
+  if (list->parents)
+    {
+      for (i = 0; i < list->n_mimes; i++)
+	{
+	  for (p = list->parents[i].parents; *p; p++)
+	    printf ("%s %s\n", list->parents[i].mime, *p);
+	}
+    }
+}
+
+
diff --git a/base/third_party/xdg_mime/xdgmimeparent.h b/base/third_party/xdg_mime/xdgmimeparent.h
new file mode 100644
index 0000000..b564f41
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeparent.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeparent.h: Private file.  Datastructure for storing the hierarchy.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 200  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_PARENT_H__
+#define __XDG_MIME_PARENT_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgParentList XdgParentList;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_parent_read_from_file        XDG_RESERVED_ENTRY(parent_read_from_file)
+#define _xdg_mime_parent_list_new              XDG_RESERVED_ENTRY(parent_list_new)
+#define _xdg_mime_parent_list_free             XDG_RESERVED_ENTRY(parent_list_free)
+#define _xdg_mime_parent_list_lookup           XDG_RESERVED_ENTRY(parent_list_lookup)
+#define _xdg_mime_parent_list_dump             XDG_RESERVED_ENTRY(parent_list_dump)
+#endif
+
+void          _xdg_mime_parent_read_from_file (XdgParentList *list,
+					       const char    *file_name);
+XdgParentList *_xdg_mime_parent_list_new       (void);
+void           _xdg_mime_parent_list_free      (XdgParentList *list);
+const char   **_xdg_mime_parent_list_lookup    (XdgParentList *list,
+						const char    *mime);
+void           _xdg_mime_parent_list_dump      (XdgParentList *list);
+
+#endif /* __XDG_MIME_PARENT_H__ */
diff --git a/base/third_party/xdg_user_dirs/BUILD.gn b/base/third_party/xdg_user_dirs/BUILD.gn
new file mode 100644
index 0000000..62e7cdf
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("xdg_user_dirs") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "xdg_user_dir_lookup.cc",
+    "xdg_user_dir_lookup.h",
+  ]
+}
diff --git a/base/third_party/xdg_user_dirs/LICENSE b/base/third_party/xdg_user_dirs/LICENSE
new file mode 100644
index 0000000..540e803
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/LICENSE
@@ -0,0 +1,21 @@
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
diff --git a/base/third_party/xdg_user_dirs/README.chromium b/base/third_party/xdg_user_dirs/README.chromium
new file mode 100644
index 0000000..b4cf6d7
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/README.chromium
@@ -0,0 +1,7 @@
+Name: xdg-user-dirs
+URL: http://www.freedesktop.org/wiki/Software/xdg-user-dirs
+License: MIT
+
+This directory include xdg-user-dir-lookup.c renamed as xdg_user_dir_lookup.cc
+from xdg-user-dirs 0.10. We made xdg_user_dir_lookup() non-static and added a
+xdg_user_dir_lookup.h.
diff --git a/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc
new file mode 100644
index 0000000..343f70c
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc
@@ -0,0 +1,232 @@
+/*
+  This file is not licenced under the GPL like the rest of the code.
+  Its is under the MIT license, to encourage reuse by cut-and-paste.
+
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * xdg_user_dir_lookup_with_fallback:
+ * @type: a string specifying the type of directory
+ * @fallback: value to use if the directory isn't specified by the user
+ * @returns: a newly allocated absolute pathname
+ *
+ * Looks up a XDG user directory of the specified type.
+ * Example of types are "DESKTOP" and "DOWNLOAD".
+ *
+ * In case the user hasn't specified any directory for the specified
+ * type the value returned is @fallback.
+ *
+ * The return value is newly allocated and must be freed with
+ * free(). The return value is never NULL if @fallback != NULL, unless
+ * out of memory.
+ **/
+static char *
+xdg_user_dir_lookup_with_fallback (const char *type, const char *fallback)
+{
+  FILE *file;
+  char *home_dir, *config_home, *config_file;
+  char buffer[512];
+  char *user_dir;
+  char *p, *d;
+  int len;
+  int relative;
+  
+  home_dir = getenv ("HOME");
+
+  if (home_dir == NULL)
+    goto error;
+
+  config_home = getenv ("XDG_CONFIG_HOME");
+  if (config_home == NULL || config_home[0] == 0)
+    {
+      config_file = (char*) malloc (strlen (home_dir) + strlen ("/.config/user-dirs.dirs") + 1);
+      if (config_file == NULL)
+        goto error;
+
+      strcpy (config_file, home_dir);
+      strcat (config_file, "/.config/user-dirs.dirs");
+    }
+  else
+    {
+      config_file = (char*) malloc (strlen (config_home) + strlen ("/user-dirs.dirs") + 1);
+      if (config_file == NULL)
+        goto error;
+
+      strcpy (config_file, config_home);
+      strcat (config_file, "/user-dirs.dirs");
+    }
+
+  file = fopen (config_file, "r");
+  free (config_file);
+  if (file == NULL)
+    goto error;
+
+  user_dir = NULL;
+  while (fgets (buffer, sizeof (buffer), file))
+    {
+      /* Remove newline at end */
+      len = strlen (buffer);
+      if (len > 0 && buffer[len-1] == '\n')
+	buffer[len-1] = 0;
+      
+      p = buffer;
+      while (*p == ' ' || *p == '\t')
+	p++;
+      
+      if (strncmp (p, "XDG_", 4) != 0)
+	continue;
+      p += 4;
+      if (strncmp (p, type, strlen (type)) != 0)
+	continue;
+      p += strlen (type);
+      if (strncmp (p, "_DIR", 4) != 0)
+	continue;
+      p += 4;
+
+      while (*p == ' ' || *p == '\t')
+	p++;
+
+      if (*p != '=')
+	continue;
+      p++;
+      
+      while (*p == ' ' || *p == '\t')
+	p++;
+
+      if (*p != '"')
+	continue;
+      p++;
+      
+      relative = 0;
+      if (strncmp (p, "$HOME/", 6) == 0)
+	{
+	  p += 6;
+	  relative = 1;
+	}
+      else if (*p != '/')
+	continue;
+      
+      if (relative)
+	{
+	  user_dir = (char*) malloc (strlen (home_dir) + 1 + strlen (p) + 1);
+          if (user_dir == NULL)
+            goto error2;
+
+	  strcpy (user_dir, home_dir);
+	  strcat (user_dir, "/");
+	}
+      else
+	{
+	  user_dir = (char*) malloc (strlen (p) + 1);
+          if (user_dir == NULL)
+            goto error2;
+
+	  *user_dir = 0;
+	}
+      
+      d = user_dir + strlen (user_dir);
+      while (*p && *p != '"')
+	{
+	  if ((*p == '\\') && (*(p+1) != 0))
+	    p++;
+	  *d++ = *p++;
+	}
+      *d = 0;
+    }
+error2:
+  fclose (file);
+
+  if (user_dir)
+    return user_dir;
+
+ error:
+  if (fallback)
+    return strdup (fallback);
+  return NULL;
+}
+
+/**
+ * xdg_user_dir_lookup:
+ * @type: a string specifying the type of directory
+ * @returns: a newly allocated absolute pathname
+ *
+ * Looks up a XDG user directory of the specified type.
+ * Example of types are "DESKTOP" and "DOWNLOAD".
+ *
+ * The return value is always != NULL (unless out of memory),
+ * and if a directory
+ * for the type is not specified by the user the default
+ * is the home directory. Except for DESKTOP which defaults
+ * to ~/Desktop.
+ *
+ * The return value is newly allocated and must be freed with
+ * free().
+ **/
+char *
+xdg_user_dir_lookup (const char *type)
+{
+  char *dir, *home_dir, *user_dir;
+	  
+  dir = xdg_user_dir_lookup_with_fallback (type, NULL);
+  if (dir != NULL)
+    return dir;
+  
+  home_dir = getenv ("HOME");
+  
+  if (home_dir == NULL)
+    return strdup ("/tmp");
+  
+  /* Special case desktop for historical compatibility */
+  if (strcmp (type, "DESKTOP") == 0)
+    {
+      user_dir = (char*) malloc (strlen (home_dir) + strlen ("/Desktop") + 1);
+      if (user_dir == NULL)
+        return NULL;
+
+      strcpy (user_dir, home_dir);
+      strcat (user_dir, "/Desktop");
+      return user_dir;
+    }
+  
+  return strdup (home_dir);
+}
+
+#ifdef STANDALONE_XDG_USER_DIR_LOOKUP
+int
+main (int argc, char *argv[])
+{
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage %s <dir-type>\n", argv[0]);
+      exit (1);
+    }
+  
+  printf ("%s\n", xdg_user_dir_lookup (argv[1]));
+  return 0;
+}
+#endif
diff --git a/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h
new file mode 100644
index 0000000..9e81e1b
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h
@@ -0,0 +1,33 @@
+/*
+  This file is not licenced under the GPL like the rest of the code.
+  Its is under the MIT license, to encourage reuse by cut-and-paste.
+
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
+#ifndef CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
+#define CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
+
+char* xdg_user_dir_lookup(const char *type);
+
+#endif  // CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
diff --git a/base/thread_task_runner_handle.cc b/base/thread_task_runner_handle.cc
new file mode 100644
index 0000000..860a0ec
--- /dev/null
+++ b/base/thread_task_runner_handle.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/thread_task_runner_handle.h"
+
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >
+    lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// static
+scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
+  ThreadTaskRunnerHandle* current = lazy_tls_ptr.Pointer()->Get();
+  DCHECK(current);
+  return current->task_runner_;
+}
+
+// static
+bool ThreadTaskRunnerHandle::IsSet() {
+  return lazy_tls_ptr.Pointer()->Get() != NULL;
+}
+
+ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner_(task_runner) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!lazy_tls_ptr.Pointer()->Get());
+  lazy_tls_ptr.Pointer()->Set(this);
+}
+
+ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK_EQ(lazy_tls_ptr.Pointer()->Get(), this);
+  lazy_tls_ptr.Pointer()->Set(NULL);
+}
+
+}  // namespace base
diff --git a/base/thread_task_runner_handle.h b/base/thread_task_runner_handle.h
new file mode 100644
index 0000000..238435f
--- /dev/null
+++ b/base/thread_task_runner_handle.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREAD_TASK_RUNNER_HANDLE_H_
+#define BASE_THREAD_TASK_RUNNER_HANDLE_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+// ThreadTaskRunnerHandle stores a reference to a thread's TaskRunner
+// in thread-local storage.  Callers can then retrieve the TaskRunner
+// for the current thread by calling ThreadTaskRunnerHandle::Get().
+// At most one TaskRunner may be bound to each thread at a time.
+class BASE_EXPORT ThreadTaskRunnerHandle {
+ public:
+  // Gets the SingleThreadTaskRunner for the current thread.
+  static scoped_refptr<SingleThreadTaskRunner> Get();
+
+  // Returns true if the SingleThreadTaskRunner is already created for
+  // the current thread.
+  static bool IsSet();
+
+  // Binds |task_runner| to the current thread. |task_runner| must belong
+  // to the current thread for this to succeed.
+  explicit ThreadTaskRunnerHandle(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+  ~ThreadTaskRunnerHandle();
+
+ private:
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREAD_TASK_RUNNER_HANDLE_H_
diff --git a/base/threading/OWNERS b/base/threading/OWNERS
new file mode 100644
index 0000000..4198e99
--- /dev/null
+++ b/base/threading/OWNERS
@@ -0,0 +1,2 @@
+# For thread_resrictions.*
+jam@chromium.org
diff --git a/base/threading/non_thread_safe.h b/base/threading/non_thread_safe.h
new file mode 100644
index 0000000..d41c086
--- /dev/null
+++ b/base/threading/non_thread_safe.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_NON_THREAD_SAFE_H_
+#define BASE_THREADING_NON_THREAD_SAFE_H_
+
+// Classes deriving from NonThreadSafe may need to suppress MSVC warning 4275:
+// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
+// There is a specific macro to do it: NON_EXPORTED_BASE(), defined in
+// compiler_specific.h
+#include "base/compiler_specific.h"
+
+// See comment at top of thread_checker.h
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_NON_THREAD_SAFE 1
+#else
+#define ENABLE_NON_THREAD_SAFE 0
+#endif
+
+#include "base/threading/non_thread_safe_impl.h"
+
+namespace base {
+
+// Do nothing implementation of NonThreadSafe, for release mode.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class NonThreadSafeDoNothing {
+ public:
+  bool CalledOnValidThread() const {
+    return true;
+  }
+
+ protected:
+  ~NonThreadSafeDoNothing() {}
+  void DetachFromThread() {}
+};
+
+// NonThreadSafe is a helper class used to help verify that methods of a
+// class are called from the same thread.  One can inherit from this class
+// and use CalledOnValidThread() to verify.
+//
+// This is intended to be used with classes that appear to be thread safe, but
+// aren't.  For example, a service or a singleton like the preferences system.
+//
+// Example:
+// class MyClass : public base::NonThreadSafe {
+//  public:
+//   void Foo() {
+//     DCHECK(CalledOnValidThread());
+//     ... (do stuff) ...
+//   }
+// }
+//
+// Note that base::ThreadChecker offers identical functionality to
+// NonThreadSafe, but does not require inheritance. In general, it is preferable
+// to have a base::ThreadChecker as a member, rather than inherit from
+// NonThreadSafe. For more details about when to choose one over the other, see
+// the documentation for base::ThreadChecker.
+#if ENABLE_NON_THREAD_SAFE
+typedef NonThreadSafeImpl NonThreadSafe;
+#else
+typedef NonThreadSafeDoNothing NonThreadSafe;
+#endif  // ENABLE_NON_THREAD_SAFE
+
+#undef ENABLE_NON_THREAD_SAFE
+
+}  // namespace base
+
+#endif  // BASE_THREADING_NON_THREAD_SAFE_H_
diff --git a/base/threading/non_thread_safe_impl.cc b/base/threading/non_thread_safe_impl.cc
new file mode 100644
index 0000000..7e729d9
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/non_thread_safe_impl.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+bool NonThreadSafeImpl::CalledOnValidThread() const {
+  return thread_checker_.CalledOnValidThread();
+}
+
+NonThreadSafeImpl::~NonThreadSafeImpl() {
+  DCHECK(CalledOnValidThread());
+}
+
+void NonThreadSafeImpl::DetachFromThread() {
+  thread_checker_.DetachFromThread();
+}
+
+}  // namespace base
diff --git a/base/threading/non_thread_safe_impl.h b/base/threading/non_thread_safe_impl.h
new file mode 100644
index 0000000..a3a356d
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
+#define BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// Full implementation of NonThreadSafe, for debug mode or for occasional
+// temporary use in release mode e.g. when you need to CHECK on a thread
+// bug that only occurs in the wild.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class BASE_EXPORT NonThreadSafeImpl {
+ public:
+  bool CalledOnValidThread() const;
+
+ protected:
+  ~NonThreadSafeImpl();
+
+  // Changes the thread that is checked for in CalledOnValidThread. The next
+  // call to CalledOnValidThread will attach this class to a new thread. It is
+  // up to the NonThreadSafe derived class to decide to expose this or not.
+  // This may be useful when an object may be created on one thread and then
+  // used exclusively on another thread.
+  void DetachFromThread();
+
+ private:
+  ThreadCheckerImpl thread_checker_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
diff --git a/base/threading/non_thread_safe_unittest.cc b/base/threading/non_thread_safe_unittest.cc
new file mode 100644
index 0000000..955c939
--- /dev/null
+++ b/base/threading/non_thread_safe_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/threading/non_thread_safe.h so that we can be
+// good citizens there and undef the macro.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_NON_THREAD_SAFE 1
+#else
+#define ENABLE_NON_THREAD_SAFE 0
+#endif
+
+namespace base {
+
+namespace {
+
+// Simple class to exersice the basics of NonThreadSafe.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class NonThreadSafeClass : public NonThreadSafe {
+ public:
+  NonThreadSafeClass() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  void DetachFromThread() {
+    NonThreadSafe::DetachFromThread();
+  }
+
+  static void MethodOnDifferentThreadImpl();
+  static void DestructorOnDifferentThreadImpl();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
+};
+
+// Calls NonThreadSafeClass::DoStuff on another thread.
+class CallDoStuffOnThread : public SimpleThread {
+ public:
+  explicit CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
+      : SimpleThread("call_do_stuff_on_thread"),
+        non_thread_safe_class_(non_thread_safe_class) {
+  }
+
+  void Run() override { non_thread_safe_class_->DoStuff(); }
+
+ private:
+  NonThreadSafeClass* non_thread_safe_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes NonThreadSafeClass on a different thread.
+class DeleteNonThreadSafeClassOnThread : public SimpleThread {
+ public:
+  explicit DeleteNonThreadSafeClassOnThread(
+      NonThreadSafeClass* non_thread_safe_class)
+      : SimpleThread("delete_non_thread_safe_class_on_thread"),
+        non_thread_safe_class_(non_thread_safe_class) {
+  }
+
+  void Run() override { non_thread_safe_class_.reset(); }
+
+ private:
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
+};
+
+}  // namespace
+
+TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that DoStuff doesn't assert.
+  non_thread_safe_class->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  non_thread_safe_class.reset();
+}
+
+TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that the destructor doesn't assert when called on a different thread
+  // after a detach.
+  non_thread_safe_class->DetachFromThread();
+  DeleteNonThreadSafeClassOnThread delete_on_thread(
+      non_thread_safe_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
+
+void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that DoStuff asserts in debug builds only when called
+  // on a different thread.
+  CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if ENABLE_NON_THREAD_SAFE
+TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      NonThreadSafeClass::MethodOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
+  NonThreadSafeClass::MethodOnDifferentThreadImpl();
+}
+#endif  // ENABLE_NON_THREAD_SAFE
+
+void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that the destructor asserts in debug builds only
+  // when called on a different thread.
+  DeleteNonThreadSafeClassOnThread delete_on_thread(
+      non_thread_safe_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+#if ENABLE_NON_THREAD_SAFE
+TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
+  NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+}
+#endif  // ENABLE_NON_THREAD_SAFE
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_NON_THREAD_SAFE
+
+}  // namespace base
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
new file mode 100644
index 0000000..d8f06e5
--- /dev/null
+++ b/base/threading/platform_thread.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: You should *NOT* be using this class directly.  PlatformThread is
+// the low-level platform-specific abstraction to the OS's threading interface.
+// You should instead be using a message-loop driven Thread, see thread.h.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_H_
+#define BASE_THREADING_PLATFORM_THREAD_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+// Used for logging. Always an integer value.
+#if defined(OS_WIN)
+typedef DWORD PlatformThreadId;
+#elif defined(OS_POSIX)
+typedef pid_t PlatformThreadId;
+#endif
+
+// Used for thread checking and debugging.
+// Meant to be as fast as possible.
+// These are produced by PlatformThread::CurrentRef(), and used to later
+// check if we are on the same thread or not by using ==. These are safe
+// to copy between threads, but can't be copied to another process as they
+// have no meaning there. Also, the internal identifier can be re-used
+// after a thread dies, so a PlatformThreadRef cannot be reliably used
+// to distinguish a new thread from an old, dead thread.
+class PlatformThreadRef {
+ public:
+#if defined(OS_WIN)
+  typedef DWORD RefType;
+#elif defined(OS_POSIX)
+  typedef pthread_t RefType;
+#endif
+  PlatformThreadRef()
+      : id_(0) {
+  }
+
+  explicit PlatformThreadRef(RefType id)
+      : id_(id) {
+  }
+
+  bool operator==(PlatformThreadRef other) const {
+    return id_ == other.id_;
+  }
+
+  bool is_null() const {
+    return id_ == 0;
+  }
+ private:
+  RefType id_;
+};
+
+// Used to operate on threads.
+class PlatformThreadHandle {
+ public:
+#if defined(OS_WIN)
+  typedef void* Handle;
+#elif defined(OS_POSIX)
+  typedef pthread_t Handle;
+#endif
+
+  PlatformThreadHandle()
+      : handle_(0),
+        id_(0) {
+  }
+
+  explicit PlatformThreadHandle(Handle handle)
+      : handle_(handle),
+        id_(0) {
+  }
+
+  PlatformThreadHandle(Handle handle,
+                       PlatformThreadId id)
+      : handle_(handle),
+        id_(id) {
+  }
+
+  bool is_equal(const PlatformThreadHandle& other) const {
+    return handle_ == other.handle_;
+  }
+
+  bool is_null() const {
+    return !handle_;
+  }
+
+  Handle platform_handle() const {
+    return handle_;
+  }
+
+ private:
+  friend class PlatformThread;
+
+  Handle handle_;
+  PlatformThreadId id_;
+};
+
+const PlatformThreadId kInvalidThreadId(0);
+
+// Valid values for SetThreadPriority(), listed in increasing order of
+// importance.
+enum class ThreadPriority {
+  // Suitable for threads that shouldn't disrupt high priority work.
+  BACKGROUND,
+  // Default priority level.
+  NORMAL,
+  // Suitable for threads which generate data for the display (at ~60Hz).
+  DISPLAY,
+  // Suitable for low-latency, glitch-resistant audio.
+  REALTIME_AUDIO,
+};
+
+// A namespace for low-level thread functions.
+class BASE_EXPORT PlatformThread {
+ public:
+  // Implement this interface to run code on a background thread.  Your
+  // ThreadMain method will be called on the newly created thread.
+  class BASE_EXPORT Delegate {
+   public:
+    virtual void ThreadMain() = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  // Gets the current thread id, which may be useful for logging purposes.
+  static PlatformThreadId CurrentId();
+
+  // Gets the current thread reference, which can be used to check if
+  // we're on the right thread quickly.
+  static PlatformThreadRef CurrentRef();
+
+  // Get the handle representing the current thread. On Windows, this is a
+  // pseudo handle constant which will always represent the thread using it and
+  // hence should not be shared with other threads nor be used to differentiate
+  // the current thread from another.
+  static PlatformThreadHandle CurrentHandle();
+
+  // Yield the current thread so another thread can be scheduled.
+  static void YieldCurrentThread();
+
+  // Sleeps for the specified duration.
+  static void Sleep(base::TimeDelta duration);
+
+  // Sets the thread name visible to debuggers/tools. This has no effect
+  // otherwise.
+  static void SetName(const std::string& name);
+
+  // Gets the thread name, if previously set by SetName.
+  static const char* GetName();
+
+  // Creates a new thread.  The |stack_size| parameter can be 0 to indicate
+  // that the default stack size should be used.  Upon success,
+  // |*thread_handle| will be assigned a handle to the newly created thread,
+  // and |delegate|'s ThreadMain method will be executed on the newly created
+  // thread.
+  // NOTE: When you are done with the thread handle, you must call Join to
+  // release system resources associated with the thread.  You must ensure that
+  // the Delegate object outlives the thread.
+  static bool Create(size_t stack_size, Delegate* delegate,
+                     PlatformThreadHandle* thread_handle);
+
+  // CreateWithPriority() does the same thing as Create() except the priority of
+  // the thread is set based on |priority|.  Can be used in place of Create()
+  // followed by SetThreadPriority().
+  static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                 PlatformThreadHandle* thread_handle,
+                                 ThreadPriority priority);
+
+  // CreateNonJoinable() does the same thing as Create() except the thread
+  // cannot be Join()'d.  Therefore, it also does not output a
+  // PlatformThreadHandle.
+  static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
+
+  // Joins with a thread created via the Create function.  This function blocks
+  // the caller until the designated thread exits.  This will invalidate
+  // |thread_handle|.
+  static void Join(PlatformThreadHandle thread_handle);
+
+  static void SetThreadPriority(PlatformThreadHandle handle,
+                                ThreadPriority priority);
+
+  static ThreadPriority GetThreadPriority(PlatformThreadHandle handle);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
new file mode 100644
index 0000000..11e5e2e
--- /dev/null
+++ b/base/threading/platform_thread_android.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/thread_utils.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+#include "jni/ThreadUtils_jni.h"
+
+namespace base {
+
+namespace internal {
+
+// These nice values are taken from Android, which uses nice values like linux,
+// but defines some preset nice values.
+//   Process.THREAD_PRIORITY_AUDIO = -16
+//   Process.THREAD_PRIORITY_BACKGROUND = 10
+//   Process.THREAD_PRIORITY_DEFAULT = 0;
+//   Process.THREAD_PRIORITY_DISPLAY = -4;
+//   Process.THREAD_PRIORITY_FOREGROUND = -2;
+//   Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
+//   Process.THREAD_PRIORITY_LOWEST = 19;
+//   Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
+//   Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
+//   Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
+// We use -6 for display, but we may want to split this into urgent (-8) and
+// non-urgent (-4).
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::NORMAL, 0},
+    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::REALTIME_AUDIO, -16},
+};
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority) {
+  // On Android, we set the Audio priority through JNI as Audio priority
+  // will also allow the process to run while it is backgrounded.
+  if (priority == ThreadPriority::REALTIME_AUDIO) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId());
+    return true;
+  }
+  return false;
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace internal
+
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // Like linux, on android we can get the thread names to show up in the
+  // debugger by setting the process name for the LWP.
+  // We don't want to do this for the main thread because that would rename
+  // the process, causing tools like killall to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+
+  // Set the name for the LWP (which gets truncated to 15 characters).
+  int err = prctl(PR_SET_NAME, name.c_str());
+  if (err < 0 && errno != EPERM)
+    DPLOG(ERROR) << "prctl(PR_SET_NAME)";
+}
+
+
+void InitThreading() {
+}
+
+void InitOnThread() {
+  // Threads on linux/android may inherit their priority from the thread
+  // where they were created. This sets all new threads to the default.
+  PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
+                                    ThreadPriority::NORMAL);
+}
+
+void TerminateOnThread() {
+  base::android::DetachFromVM();
+}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if !defined(ADDRESS_SANITIZER)
+  return 0;
+#else
+  // AddressSanitizer bloats the stack approximately 2x. Default stack size of
+  // 1Mb is not enough for some tests (see http://crbug.com/263749 for example).
+  return 2 * (1 << 20);  // 2Mb
+#endif
+}
+
+bool RegisterThreadUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
new file mode 100644
index 0000000..f4fded0
--- /dev/null
+++ b/base/threading/platform_thread_freebsd.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+
+#if !defined(OS_NACL)
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+namespace internal {
+
+namespace {
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+}  // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::NORMAL, 0},
+    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::REALTIME_AUDIO, -10},
+}
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority) {
+#if !defined(OS_NACL)
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  return priority == ThreadPriority::REALTIME_AUDIO &&
+         pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+  return false;
+#endif
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority) {
+#if !defined(OS_NACL)
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  int maybe_sched_rr = 0;
+  struct sched_param maybe_realtime_prio = {0};
+  if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
+                            &maybe_realtime_prio) == 0 &&
+      maybe_sched_rr == SCHED_RR &&
+      maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
+    *priority = ThreadPriority::REALTIME_AUDIO;
+    return true;
+  }
+#endif
+  return false;
+}
+
+}  // namespace internal
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+#if !defined(OS_NACL)
+  // On FreeBSD we can get the thread names to show up in the debugger by
+  // setting the process name for the LWP.  We don't want to do this for the
+  // main thread because that would rename the process, causing tools like
+  // killall to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+  setproctitle("%s", name.c_str());
+#endif  //  !defined(OS_NACL)
+}
+
+void InitThreading() {}
+
+void InitOnThread() {}
+
+void TerminateOnThread() {}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if !defined(THREAD_SANITIZER)
+  return 0;
+#else
+  // ThreadSanitizer bloats the stack heavily. Evidence has been that the
+  // default stack size isn't enough for some browser tests.
+  return 2 * (1 << 23);  // 2 times 8192K (the default stack size on Linux).
+#endif
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_internal_posix.cc b/base/threading/platform_thread_internal_posix.cc
new file mode 100644
index 0000000..9af0204
--- /dev/null
+++ b/base/threading/platform_thread_internal_posix.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread_internal_posix.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+int ThreadPriorityToNiceValue(ThreadPriority priority) {
+  for (const ThreadPriorityToNiceValuePair& pair :
+       kThreadPriorityToNiceValueMap) {
+    if (pair.priority == priority)
+      return pair.nice_value;
+  }
+  NOTREACHED() << "Unknown ThreadPriority";
+  return 0;
+}
+
+ThreadPriority NiceValueToThreadPriority(int nice_value) {
+  for (const ThreadPriorityToNiceValuePair& pair :
+       kThreadPriorityToNiceValueMap) {
+    if (pair.nice_value == nice_value)
+      return pair.priority;
+  }
+  NOTREACHED() << "Unknown nice value";
+  return ThreadPriority::NORMAL;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
new file mode 100644
index 0000000..62006ce
--- /dev/null
+++ b/base/threading/platform_thread_internal_posix.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace internal {
+
+struct ThreadPriorityToNiceValuePair {
+  ThreadPriority priority;
+  int nice_value;
+};
+extern const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4];
+
+// Returns the nice value matching |priority| based on the platform-specific
+// implementation of kThreadPriorityToNiceValueMap.
+int ThreadPriorityToNiceValue(ThreadPriority priority);
+
+// Returns the ThreadPrioirty matching |nice_value| based on the platform-
+// specific implementation of kThreadPriorityToNiceValueMap.
+ThreadPriority NiceValueToThreadPriority(int nice_value);
+
+// Allows platform specific tweaks to the generic POSIX solution for
+// SetThreadPriority. Returns true if the platform-specific implementation
+// handled this |priority| change, false if the generic implementation should
+// instead proceed.
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority);
+
+// Returns true if there is a platform-specific ThreadPriority set on |handle|
+// (and returns the actual ThreadPriority via |priority|). Returns false
+// otherwise, leaving |priority| untouched.
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority);
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
new file mode 100644
index 0000000..9f74374
--- /dev/null
+++ b/base/threading/platform_thread_linux.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+
+#if !defined(OS_NACL)
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+namespace internal {
+
+namespace {
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+}  // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::NORMAL, 0},
+    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::REALTIME_AUDIO, -10},
+};
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority) {
+#if !defined(OS_NACL)
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  return priority == ThreadPriority::REALTIME_AUDIO  &&
+         pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+  return false;
+#endif
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority) {
+#if !defined(OS_NACL)
+  int maybe_sched_rr = 0;
+  struct sched_param maybe_realtime_prio = {0};
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
+                            &maybe_realtime_prio) == 0 &&
+      maybe_sched_rr == SCHED_RR &&
+      maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
+    *priority = ThreadPriority::REALTIME_AUDIO;
+    return true;
+  }
+#endif
+  return false;
+}
+
+}  // namespace internal
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+#if !defined(OS_NACL)
+  // On linux we can get the thread names to show up in the debugger by setting
+  // the process name for the LWP.  We don't want to do this for the main
+  // thread because that would rename the process, causing tools like killall
+  // to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+
+  // http://0pointer.de/blog/projects/name-your-threads.html
+  // Set the name for the LWP (which gets truncated to 15 characters).
+  // Note that glibc also has a 'pthread_setname_np' api, but it may not be
+  // available everywhere and it's only benefit over using prctl directly is
+  // that it can set the name of threads other than the current thread.
+  int err = prctl(PR_SET_NAME, name.c_str());
+  // We expect EPERM failures in sandboxed processes, just ignore those.
+  if (err < 0 && errno != EPERM)
+    DPLOG(ERROR) << "prctl(PR_SET_NAME)";
+#endif  //  !defined(OS_NACL)
+}
+
+void InitThreading() {}
+
+void InitOnThread() {}
+
+void TerminateOnThread() {}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if !defined(THREAD_SANITIZER)
+  return 0;
+#else
+  // ThreadSanitizer bloats the stack heavily. Evidence has been that the
+  // default stack size isn't enough for some browser tests.
+  return 2 * (1 << 23);  // 2 times 8192K (the default stack size on Linux).
+#endif
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
new file mode 100644
index 0000000..a9c347a
--- /dev/null
+++ b/base/threading/platform_thread_mac.mm
@@ -0,0 +1,223 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/thread_policy.h>
+#include <sys/resource.h>
+
+#include <algorithm>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+// If Cocoa is to be used on more than one thread, it must know that the
+// application is multithreaded.  Since it's possible to enter Cocoa code
+// from threads created by pthread_thread_create, Cocoa won't necessarily
+// be aware that the application is multithreaded.  Spawning an NSThread is
+// enough to get Cocoa to set up for multithreaded operation, so this is done
+// if necessary before pthread_thread_create spawns any threads.
+//
+// http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html
+void InitThreading() {
+  static BOOL multithreaded = [NSThread isMultiThreaded];
+  if (!multithreaded) {
+    // +[NSObject class] is idempotent.
+    [NSThread detachNewThreadSelector:@selector(class)
+                             toTarget:[NSObject class]
+                           withObject:nil];
+    multithreaded = YES;
+
+    DCHECK([NSThread isMultiThreaded]);
+  }
+}
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // Mac OS X does not expose the length limit of the name, so
+  // hardcode it.
+  const int kMaxNameLength = 63;
+  std::string shortened_name = name.substr(0, kMaxNameLength);
+  // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
+  // See http://crbug.com/47058
+  pthread_setname_np(shortened_name.c_str());
+}
+
+namespace {
+
+void SetPriorityNormal(mach_port_t mach_thread_id) {
+  // Make thread standard policy.
+  // Please note that this call could fail in rare cases depending
+  // on runtime conditions.
+  thread_standard_policy policy;
+  kern_return_t result =
+      thread_policy_set(mach_thread_id,
+                        THREAD_STANDARD_POLICY,
+                        reinterpret_cast<thread_policy_t>(&policy),
+                        THREAD_STANDARD_POLICY_COUNT);
+
+  if (result != KERN_SUCCESS)
+    MACH_DVLOG(1, result) << "thread_policy_set";
+}
+
+// Enables time-contraint policy and priority suitable for low-latency,
+// glitch-resistant audio.
+void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
+  // Increase thread priority to real-time.
+
+  // Please note that the thread_policy_set() calls may fail in
+  // rare cases if the kernel decides the system is under heavy load
+  // and is unable to handle boosting the thread priority.
+  // In these cases we just return early and go on with life.
+
+  // Make thread fixed priority.
+  thread_extended_policy_data_t policy;
+  policy.timeshare = 0;  // Set to 1 for a non-fixed thread.
+  kern_return_t result =
+      thread_policy_set(mach_thread_id,
+                        THREAD_EXTENDED_POLICY,
+                        reinterpret_cast<thread_policy_t>(&policy),
+                        THREAD_EXTENDED_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_DVLOG(1, result) << "thread_policy_set";
+    return;
+  }
+
+  // Set to relatively high priority.
+  thread_precedence_policy_data_t precedence;
+  precedence.importance = 63;
+  result = thread_policy_set(mach_thread_id,
+                             THREAD_PRECEDENCE_POLICY,
+                             reinterpret_cast<thread_policy_t>(&precedence),
+                             THREAD_PRECEDENCE_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_DVLOG(1, result) << "thread_policy_set";
+    return;
+  }
+
+  // Most important, set real-time constraints.
+
+  // Define the guaranteed and max fraction of time for the audio thread.
+  // These "duty cycle" values can range from 0 to 1.  A value of 0.5
+  // means the scheduler would give half the time to the thread.
+  // These values have empirically been found to yield good behavior.
+  // Good means that audio performance is high and other threads won't starve.
+  const double kGuaranteedAudioDutyCycle = 0.75;
+  const double kMaxAudioDutyCycle = 0.85;
+
+  // Define constants determining how much time the audio thread can
+  // use in a given time quantum.  All times are in milliseconds.
+
+  // About 128 frames @44.1KHz
+  const double kTimeQuantum = 2.9;
+
+  // Time guaranteed each quantum.
+  const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
+
+  // Maximum time each quantum.
+  const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
+
+  // Get the conversion factor from milliseconds to absolute time
+  // which is what the time-constraints call needs.
+  mach_timebase_info_data_t tb_info;
+  mach_timebase_info(&tb_info);
+  double ms_to_abs_time =
+      (static_cast<double>(tb_info.denom) / tb_info.numer) * 1000000;
+
+  thread_time_constraint_policy_data_t time_constraints;
+  time_constraints.period = kTimeQuantum * ms_to_abs_time;
+  time_constraints.computation = kAudioTimeNeeded * ms_to_abs_time;
+  time_constraints.constraint = kMaxTimeAllowed * ms_to_abs_time;
+  time_constraints.preemptible = 0;
+
+  result =
+      thread_policy_set(mach_thread_id,
+                        THREAD_TIME_CONSTRAINT_POLICY,
+                        reinterpret_cast<thread_policy_t>(&time_constraints),
+                        THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+  MACH_DVLOG_IF(1, result != KERN_SUCCESS, result) << "thread_policy_set";
+
+  return;
+}
+
+}  // anonymous namespace
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+  // Convert from pthread_t to mach thread identifier.
+  mach_port_t mach_thread_id = pthread_mach_thread_np(handle.handle_);
+
+  switch (priority) {
+    case ThreadPriority::NORMAL:
+      SetPriorityNormal(mach_thread_id);
+      break;
+    case ThreadPriority::REALTIME_AUDIO:
+      SetPriorityRealtimeAudio(mach_thread_id);
+      break;
+    default:
+      NOTREACHED() << "Unknown priority.";
+      break;
+  }
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+  NOTIMPLEMENTED();
+  return ThreadPriority::NORMAL;
+}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if defined(OS_IOS)
+  return 0;
+#else
+  // The Mac OS X default for a pthread stack size is 512kB.
+  // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
+  // DEFAULT_STACK_SIZE for this purpose.
+  //
+  // 512kB isn't quite generous enough for some deeply recursive threads that
+  // otherwise request the default stack size by specifying 0. Here, adopt
+  // glibc's behavior as on Linux, which is to use the current stack size
+  // limit (ulimit -s) as the default stack size. See
+  // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
+  // avoid setting the limit below the Mac OS X default or the minimum usable
+  // stack size, these values are also considered. If any of these values
+  // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
+  // stack_size is left at 0 to get the system default.
+  //
+  // Mac OS X normally only applies ulimit -s to the main thread stack. On
+  // contemporary OS X and Linux systems alike, this value is generally 8MB
+  // or in that neighborhood.
+  size_t default_stack_size = 0;
+  struct rlimit stack_rlimit;
+  if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
+      getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
+      stack_rlimit.rlim_cur != RLIM_INFINITY) {
+    default_stack_size =
+        std::max(std::max(default_stack_size,
+                          static_cast<size_t>(PTHREAD_STACK_MIN)),
+                 static_cast<size_t>(stack_rlimit.rlim_cur));
+  }
+  return default_stack_size;
+#endif
+}
+
+void InitOnThread() {
+}
+
+void TerminateOnThread() {
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000..3dbdc98
--- /dev/null
+++ b/base/threading/platform_thread_posix.cc
@@ -0,0 +1,295 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/safe_strerror_posix.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_LINUX)
+#include <sys/syscall.h>
+#elif defined(OS_ANDROID)
+#include <sys/types.h>
+#endif
+
+namespace base {
+
+void InitThreading();
+void InitOnThread();
+void TerminateOnThread();
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
+
+namespace {
+
+struct ThreadParams {
+  ThreadParams()
+      : delegate(NULL),
+        joinable(false),
+        priority(ThreadPriority::NORMAL),
+        handle(NULL),
+        handle_set(false, false) {
+  }
+
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+  ThreadPriority priority;
+  PlatformThreadHandle* handle;
+  WaitableEvent handle_set;
+};
+
+void* ThreadFunc(void* params) {
+  base::InitOnThread();
+  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+
+  PlatformThread::Delegate* delegate = thread_params->delegate;
+  if (!thread_params->joinable)
+    base::ThreadRestrictions::SetSingletonAllowed(false);
+
+  if (thread_params->priority != ThreadPriority::NORMAL) {
+    PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
+                                      thread_params->priority);
+  }
+
+  // Stash the id in the handle so the calling thread has a complete
+  // handle, and unblock the parent thread.
+  *(thread_params->handle) = PlatformThreadHandle(pthread_self(),
+                                                  PlatformThread::CurrentId());
+  thread_params->handle_set.Signal();
+
+  ThreadIdNameManager::GetInstance()->RegisterThread(
+      PlatformThread::CurrentHandle().platform_handle(),
+      PlatformThread::CurrentId());
+
+  delegate->ThreadMain();
+
+  ThreadIdNameManager::GetInstance()->RemoveName(
+      PlatformThread::CurrentHandle().platform_handle(),
+      PlatformThread::CurrentId());
+
+  base::TerminateOnThread();
+  return NULL;
+}
+
+bool CreateThread(size_t stack_size, bool joinable,
+                  PlatformThread::Delegate* delegate,
+                  PlatformThreadHandle* thread_handle,
+                  ThreadPriority priority) {
+  base::InitThreading();
+
+  bool success = false;
+  pthread_attr_t attributes;
+  pthread_attr_init(&attributes);
+
+  // Pthreads are joinable by default, so only specify the detached
+  // attribute if the thread should be non-joinable.
+  if (!joinable) {
+    pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
+  }
+
+  // Get a better default if available.
+  if (stack_size == 0)
+    stack_size = base::GetDefaultThreadStackSize(attributes);
+
+  if (stack_size > 0)
+    pthread_attr_setstacksize(&attributes, stack_size);
+
+  ThreadParams params;
+  params.delegate = delegate;
+  params.joinable = joinable;
+  params.priority = priority;
+  params.handle = thread_handle;
+
+  pthread_t handle;
+  int err = pthread_create(&handle,
+                           &attributes,
+                           ThreadFunc,
+                           &params);
+  success = !err;
+  if (!success) {
+    // Value of |handle| is undefined if pthread_create fails.
+    handle = 0;
+    errno = err;
+    PLOG(ERROR) << "pthread_create";
+  }
+
+  pthread_attr_destroy(&attributes);
+
+  // Don't let this call complete until the thread id
+  // is set in the handle.
+  if (success)
+    params.handle_set.Wait();
+  CHECK_EQ(handle, thread_handle->platform_handle());
+
+  return success;
+}
+
+}  // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+  // Pthreads doesn't have the concept of a thread ID, so we have to reach down
+  // into the kernel.
+#if defined(OS_MACOSX)
+  return pthread_mach_thread_np(pthread_self());
+#elif defined(OS_LINUX)
+  return syscall(__NR_gettid);
+#elif defined(OS_ANDROID)
+  return gettid();
+#elif defined(OS_SOLARIS) || defined(OS_QNX)
+  return pthread_self();
+#elif defined(OS_NACL) && defined(__GLIBC__)
+  return pthread_self();
+#elif defined(OS_NACL) && !defined(__GLIBC__)
+  // Pointers are 32-bits in NaCl.
+  return reinterpret_cast<int32>(pthread_self());
+#elif defined(OS_POSIX)
+  return reinterpret_cast<int64>(pthread_self());
+#endif
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+  return PlatformThreadRef(pthread_self());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+  return PlatformThreadHandle(pthread_self(), CurrentId());
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+  sched_yield();
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+  struct timespec sleep_time, remaining;
+
+  // Break the duration into seconds and nanoseconds.
+  // NOTE: TimeDelta's microseconds are int64s while timespec's
+  // nanoseconds are longs, so this unpacking must prevent overflow.
+  sleep_time.tv_sec = duration.InSeconds();
+  duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
+  sleep_time.tv_nsec = duration.InMicroseconds() * 1000;  // nanoseconds
+
+  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
+    sleep_time = remaining;
+}
+
+// static
+const char* PlatformThread::GetName() {
+  return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  return CreateThread(stack_size, true /* joinable thread */,
+                      delegate, thread_handle, ThreadPriority::NORMAL);
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                        PlatformThreadHandle* thread_handle,
+                                        ThreadPriority priority) {
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  return CreateThread(stack_size, true,  // joinable thread
+                      delegate, thread_handle, priority);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+  PlatformThreadHandle unused;
+
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  bool result = CreateThread(stack_size, false /* non-joinable thread */,
+                             delegate, &unused, ThreadPriority::NORMAL);
+  return result;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  // Joining another thread may block the current thread for a long time, since
+  // the thread referred to by |thread_handle| may still be running long-lived /
+  // blocking tasks.
+  base::ThreadRestrictions::AssertIOAllowed();
+  CHECK_EQ(0, pthread_join(thread_handle.handle_, NULL));
+}
+
+// Mac has its own Set/GetThreadPriority() implementations.
+#if !defined(OS_MACOSX)
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();
+#else
+  if (internal::SetThreadPriorityForPlatform(handle, priority))
+    return;
+
+  // setpriority(2) should change the whole thread group's (i.e. process)
+  // priority. However, as stated in the bugs section of
+  // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
+  // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
+  // attribute". Also, 0 is prefered to the current thread id since it is
+  // equivalent but makes sandboxing easier (https://crbug.com/399473).
+  DCHECK_NE(handle.id_, kInvalidThreadId);
+  const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+  const PlatformThreadId current_id = PlatformThread::CurrentId();
+  if (setpriority(PRIO_PROCESS, handle.id_ == current_id ? 0 : handle.id_,
+                  nice_setting)) {
+    DVPLOG(1) << "Failed to set nice value of thread (" << handle.id_ << ") to "
+              << nice_setting;
+  }
+#endif  // defined(OS_NACL)
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();
+  return ThreadPriority::NORMAL;
+#else
+  // Mirrors SetThreadPriority()'s implementation.
+  ThreadPriority platform_specific_priority;
+  if (internal::GetThreadPriorityForPlatform(handle,
+                                             &platform_specific_priority)) {
+    return platform_specific_priority;
+  }
+
+  DCHECK_NE(handle.id_, kInvalidThreadId);
+  const PlatformThreadId current_id = PlatformThread::CurrentId();
+  // Need to clear errno before calling getpriority():
+  // http://man7.org/linux/man-pages/man2/getpriority.2.html
+  errno = 0;
+  int nice_value =
+      getpriority(PRIO_PROCESS, handle.id_ == current_id ? 0 : handle.id_);
+  if (errno != 0) {
+    DVPLOG(1) << "Failed to get nice value of thread (" << handle.id_ << ")";
+    return ThreadPriority::NORMAL;
+  }
+
+  return internal::NiceValueToThreadPriority(nice_value);
+#endif  // !defined(OS_NACL)
+}
+
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace base
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
new file mode 100644
index 0000000..c4b3d5d
--- /dev/null
+++ b/base/threading/platform_thread_unittest.cc
@@ -0,0 +1,275 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// Trivial tests that thread runs and doesn't crash on create and join ---------
+
+class TrivialThread : public PlatformThread::Delegate {
+ public:
+  TrivialThread() : did_run_(false) {}
+
+  void ThreadMain() override { did_run_ = true; }
+
+  bool did_run() const { return did_run_; }
+
+ private:
+  bool did_run_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrivialThread);
+};
+
+TEST(PlatformThreadTest, Trivial) {
+  TrivialThread thread;
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.did_run());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  PlatformThread::Join(handle);
+  ASSERT_TRUE(thread.did_run());
+}
+
+TEST(PlatformThreadTest, TrivialTimesTen) {
+  TrivialThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].did_run());
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+  for (size_t n = 0; n < arraysize(thread); n++)
+    PlatformThread::Join(handle[n]);
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(thread[n].did_run());
+}
+
+// Tests of basic thread functions ---------------------------------------------
+
+class FunctionTestThread : public PlatformThread::Delegate {
+ public:
+  FunctionTestThread()
+      : thread_id_(kInvalidThreadId),
+        thread_started_(true, false),
+        terminate_thread_(true, false),
+        done_(false) {}
+  ~FunctionTestThread() override {
+    EXPECT_TRUE(terminate_thread_.IsSignaled())
+        << "Need to mark thread for termination and join the underlying thread "
+        << "before destroying a FunctionTestThread as it owns the "
+        << "WaitableEvent blocking the underlying thread's main.";
+  }
+
+  // Grabs |thread_id_|, signals |thread_started_|, and then waits for
+  // |terminate_thread_| to be signaled before exiting.
+  void ThreadMain() override {
+    thread_id_ = PlatformThread::CurrentId();
+    EXPECT_NE(thread_id_, kInvalidThreadId);
+
+    // Make sure that the thread ID is the same across calls.
+    EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
+
+    thread_started_.Signal();
+
+    terminate_thread_.Wait();
+
+    done_ = true;
+  }
+
+  PlatformThreadId thread_id() const {
+    EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown";
+    return thread_id_;
+  }
+
+  bool IsRunning() const {
+    return thread_started_.IsSignaled() && !done_;
+  }
+
+  // Blocks until this thread is started.
+  void WaitForThreadStart() { thread_started_.Wait(); }
+
+  // Mark this thread for termination (callers must then join this thread to be
+  // guaranteed of termination).
+  void MarkForTermination() { terminate_thread_.Signal(); }
+
+ private:
+  PlatformThreadId thread_id_;
+
+  mutable WaitableEvent thread_started_;
+  WaitableEvent terminate_thread_;
+  bool done_;
+
+  DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
+};
+
+TEST(PlatformThreadTest, Function) {
+  PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+  FunctionTestThread thread;
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.IsRunning());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForThreadStart();
+  ASSERT_TRUE(thread.IsRunning());
+  EXPECT_NE(thread.thread_id(), main_thread_id);
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+  ASSERT_FALSE(thread.IsRunning());
+
+  // Make sure that the thread ID is the same across calls.
+  EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
+}
+
+TEST(PlatformThreadTest, FunctionTimesTen) {
+  PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+  FunctionTestThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].IsRunning());
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+  for (size_t n = 0; n < arraysize(thread); n++)
+    thread[n].WaitForThreadStart();
+
+  for (size_t n = 0; n < arraysize(thread); n++) {
+    ASSERT_TRUE(thread[n].IsRunning());
+    EXPECT_NE(thread[n].thread_id(), main_thread_id);
+
+    // Make sure no two threads get the same ID.
+    for (size_t i = 0; i < n; ++i) {
+      EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
+    }
+  }
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    thread[n].MarkForTermination();
+  for (size_t n = 0; n < arraysize(thread); n++)
+    PlatformThread::Join(handle[n]);
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].IsRunning());
+
+  // Make sure that the thread ID is the same across calls.
+  EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
+}
+
+namespace {
+
+const ThreadPriority kThreadPriorityTestValues[] = {
+// Disable non-normal priority toggling on POSIX as it appears to be broken
+// (http://crbug.com/468793). This is prefered to disabling the tests altogether
+// on POSIX as it at least provides coverage for running this code under
+// "normal" priority.
+#if !defined(OS_POSIX)
+    ThreadPriority::DISPLAY,
+    ThreadPriority::REALTIME_AUDIO,
+    // Keep BACKGROUND second to last to test backgrounding from other
+    // priorities.
+    ThreadPriority::BACKGROUND,
+#endif  // !defined(OS_POSIX)
+    // Keep NORMAL last to test unbackgrounding.
+    ThreadPriority::NORMAL
+};
+
+}  // namespace
+
+// Test changing another thread's priority.
+// NOTE: This test is partially disabled on POSIX, see note above and
+// http://crbug.com/468793.
+TEST(PlatformThreadTest, ThreadPriorityOtherThread) {
+  PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+
+  // Confirm that the current thread's priority is as expected.
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            PlatformThread::GetThreadPriority(current_handle));
+
+  // Create a test thread.
+  FunctionTestThread thread;
+  PlatformThreadHandle handle;
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForThreadStart();
+  EXPECT_NE(thread.thread_id(), kInvalidThreadId);
+  EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
+
+  // New threads should get normal priority by default.
+  EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
+
+  // Toggle each supported priority on the test thread and confirm it only
+  // affects it (and not the current thread).
+  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+    SCOPED_TRACE(i);
+
+    // Alter and verify the test thread's priority.
+    PlatformThread::SetThreadPriority(handle, kThreadPriorityTestValues[i]);
+    EXPECT_EQ(kThreadPriorityTestValues[i],
+              PlatformThread::GetThreadPriority(handle));
+
+    // Make sure the current thread was otherwise unaffected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetThreadPriority(current_handle));
+  }
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+}
+
+// Test changing the current thread's priority (which has different semantics on
+// some platforms).
+// NOTE: This test is partially disabled on POSIX, see note above and
+// http://crbug.com/468793.
+TEST(PlatformThreadTest, ThreadPriorityCurrentThread) {
+  PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+
+  // Confirm that the current thread's priority is as expected.
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            PlatformThread::GetThreadPriority(current_handle));
+
+  // Create a test thread for verification purposes only.
+  FunctionTestThread thread;
+  PlatformThreadHandle handle;
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForThreadStart();
+  EXPECT_NE(thread.thread_id(), kInvalidThreadId);
+  EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
+
+  // Confirm that the new thread's priority is as expected.
+  EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
+
+  // Toggle each supported priority on the current thread and confirm it only
+  // affects it (and not the test thread).
+  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+    SCOPED_TRACE(i);
+
+    // Alter and verify the current thread's priority.
+    PlatformThread::SetThreadPriority(current_handle,
+                                      kThreadPriorityTestValues[i]);
+    EXPECT_EQ(kThreadPriorityTestValues[i],
+              PlatformThread::GetThreadPriority(current_handle));
+
+    // Make sure the test thread was otherwise unaffected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetThreadPriority(handle));
+  }
+
+  // Restore current thread priority for follow-up tests.
+  PlatformThread::SetThreadPriority(current_handle, ThreadPriority::NORMAL);
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
new file mode 100644
index 0000000..4eb2cb2
--- /dev/null
+++ b/base/threading/platform_thread_win.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include "base/debug/alias.h"
+#include "base/debug/profiler.h"
+#include "base/logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+namespace {
+
+// The information on how to set the thread name comes from
+// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
+const DWORD kVCThreadNameException = 0x406D1388;
+
+typedef struct tagTHREADNAME_INFO {
+  DWORD dwType;  // Must be 0x1000.
+  LPCSTR szName;  // Pointer to name (in user addr space).
+  DWORD dwThreadID;  // Thread ID (-1=caller thread).
+  DWORD dwFlags;  // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+
+// This function has try handling, so it is separated out of its caller.
+void SetNameInternal(PlatformThreadId thread_id, const char* name) {
+  THREADNAME_INFO info;
+  info.dwType = 0x1000;
+  info.szName = name;
+  info.dwThreadID = thread_id;
+  info.dwFlags = 0;
+
+  __try {
+    RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
+                   reinterpret_cast<DWORD_PTR*>(&info));
+  } __except(EXCEPTION_CONTINUE_EXECUTION) {
+  }
+}
+
+struct ThreadParams {
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+};
+
+DWORD __stdcall ThreadFunc(void* params) {
+  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+  PlatformThread::Delegate* delegate = thread_params->delegate;
+  if (!thread_params->joinable)
+    base::ThreadRestrictions::SetSingletonAllowed(false);
+
+  // Retrieve a copy of the thread handle to use as the key in the
+  // thread name mapping.
+  PlatformThreadHandle::Handle platform_handle;
+  BOOL did_dup = DuplicateHandle(GetCurrentProcess(),
+                                GetCurrentThread(),
+                                GetCurrentProcess(),
+                                &platform_handle,
+                                0,
+                                FALSE,
+                                DUPLICATE_SAME_ACCESS);
+
+  win::ScopedHandle scoped_platform_handle;
+
+  if (did_dup) {
+    scoped_platform_handle.Set(platform_handle);
+    ThreadIdNameManager::GetInstance()->RegisterThread(
+        scoped_platform_handle.Get(),
+        PlatformThread::CurrentId());
+  }
+
+  delete thread_params;
+  delegate->ThreadMain();
+
+  if (did_dup) {
+    ThreadIdNameManager::GetInstance()->RemoveName(
+        scoped_platform_handle.Get(),
+        PlatformThread::CurrentId());
+  }
+
+  return NULL;
+}
+
+// CreateThreadInternal() matches PlatformThread::Create(), except that
+// |out_thread_handle| may be NULL, in which case a non-joinable thread is
+// created.
+bool CreateThreadInternal(size_t stack_size,
+                          PlatformThread::Delegate* delegate,
+                          PlatformThreadHandle* out_thread_handle) {
+  unsigned int flags = 0;
+  if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
+    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+  } else {
+    stack_size = 0;
+  }
+
+  ThreadParams* params = new ThreadParams;
+  params->delegate = delegate;
+  params->joinable = out_thread_handle != NULL;
+
+  // Using CreateThread here vs _beginthreadex makes thread creation a bit
+  // faster and doesn't require the loader lock to be available.  Our code will
+  // have to work running on CreateThread() threads anyway, since we run code
+  // on the Windows thread pool, etc.  For some background on the difference:
+  //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
+  void* thread_handle = CreateThread(
+      NULL, stack_size, ThreadFunc, params, flags, NULL);
+  if (!thread_handle) {
+    delete params;
+    return false;
+  }
+
+  if (out_thread_handle)
+    *out_thread_handle = PlatformThreadHandle(thread_handle);
+  else
+    CloseHandle(thread_handle);
+  return true;
+}
+
+}  // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+  return ::GetCurrentThreadId();
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+  return PlatformThreadRef(::GetCurrentThreadId());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+  return PlatformThreadHandle(::GetCurrentThread());
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+  ::Sleep(0);
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+  // When measured with a high resolution clock, Sleep() sometimes returns much
+  // too early. We may need to call it repeatedly to get the desired duration.
+  TimeTicks end = TimeTicks::Now() + duration;
+  for (TimeTicks now = TimeTicks::Now(); now < end; now = TimeTicks::Now())
+    ::Sleep(static_cast<DWORD>((end - now).InMillisecondsRoundedUp()));
+}
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+
+  // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
+  // thread, as it exists only in the chrome.exe image, and never spawns or runs
+  // tasks (items which could be profiled).  This test avoids the notification,
+  // which would also (as a side effect) initialize the profiler in this unused
+  // context, including setting up thread local storage, etc.  The performance
+  // impact is not terrible, but there is no reason to do initialize it.
+  if (name != "BrokerEvent")
+    tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // The debugger needs to be around to catch the name in the exception.  If
+  // there isn't a debugger, we are just needlessly throwing an exception.
+  // If this image file is instrumented, we raise the exception anyway
+  // to provide the profiler with human-readable thread names.
+  if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
+    return;
+
+  SetNameInternal(CurrentId(), name.c_str());
+}
+
+// static
+const char* PlatformThread::GetName() {
+  return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  DCHECK(thread_handle);
+  return CreateThreadInternal(stack_size, delegate, thread_handle);
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                        PlatformThreadHandle* thread_handle,
+                                        ThreadPriority priority) {
+  bool result = Create(stack_size, delegate, thread_handle);
+  if (result)
+    SetThreadPriority(*thread_handle, priority);
+  return result;
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+  return CreateThreadInternal(stack_size, delegate, NULL);
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  DCHECK(thread_handle.handle_);
+  // TODO(willchan): Enable this check once I can get it to work for Windows
+  // shutdown.
+  // Joining another thread may block the current thread for a long time, since
+  // the thread referred to by |thread_handle| may still be running long-lived /
+  // blocking tasks.
+#if 0
+  base::ThreadRestrictions::AssertIOAllowed();
+#endif
+
+  // Wait for the thread to exit.  It should already have terminated but make
+  // sure this assumption is valid.
+  DWORD result = WaitForSingleObject(thread_handle.handle_, INFINITE);
+  if (result != WAIT_OBJECT_0) {
+    // Debug info for bug 127931.
+    DWORD error = GetLastError();
+    debug::Alias(&error);
+    debug::Alias(&result);
+    debug::Alias(&thread_handle.handle_);
+    CHECK(false);
+  }
+
+  CloseHandle(thread_handle.handle_);
+}
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+  DCHECK(!handle.is_null());
+
+  int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
+  switch (priority) {
+    case ThreadPriority::BACKGROUND:
+      desired_priority = THREAD_PRIORITY_LOWEST;
+      break;
+    case ThreadPriority::NORMAL:
+      desired_priority = THREAD_PRIORITY_NORMAL;
+      break;
+    case ThreadPriority::DISPLAY:
+      desired_priority = THREAD_PRIORITY_ABOVE_NORMAL;
+      break;
+    case ThreadPriority::REALTIME_AUDIO:
+      desired_priority = THREAD_PRIORITY_TIME_CRITICAL;
+      break;
+    default:
+      NOTREACHED() << "Unknown priority.";
+      break;
+  }
+  DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN);
+
+#ifndef NDEBUG
+  const BOOL success =
+#endif
+      ::SetThreadPriority(handle.handle_, desired_priority);
+  DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
+                            << desired_priority;
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+  DCHECK(!handle.is_null());
+
+  int priority = ::GetThreadPriority(handle.handle_);
+  switch (priority) {
+    case THREAD_PRIORITY_LOWEST:
+      return ThreadPriority::BACKGROUND;
+    case THREAD_PRIORITY_NORMAL:
+      return ThreadPriority::NORMAL;
+    case THREAD_PRIORITY_ABOVE_NORMAL:
+      return ThreadPriority::DISPLAY;
+    case THREAD_PRIORITY_TIME_CRITICAL:
+      return ThreadPriority::REALTIME_AUDIO;
+    case THREAD_PRIORITY_ERROR_RETURN:
+      DPCHECK(false) << "GetThreadPriority error";  // Falls through.
+    default:
+      NOTREACHED() << "Unexpected priority: " << priority;
+      return ThreadPriority::NORMAL;
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
new file mode 100644
index 0000000..f3e88ab
--- /dev/null
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/post_task_and_reply_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+
+namespace base {
+
+namespace {
+
+// This relay class remembers the MessageLoop that it was created on, and
+// ensures that both the |task| and |reply| Closures are deleted on this same
+// thread. Also, |task| is guaranteed to be deleted before |reply| is run or
+// deleted.
+//
+// If this is not possible because the originating MessageLoop is no longer
+// available, the the |task| and |reply| Closures are leaked.  Leaking is
+// considered preferable to having a thread-safetey violations caused by
+// invoking the Closure destructor on the wrong thread.
+class PostTaskAndReplyRelay {
+ public:
+  PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply)
+      : from_here_(from_here),
+        origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
+    task_ = task;
+    reply_ = reply;
+  }
+
+  ~PostTaskAndReplyRelay() {
+    DCHECK(origin_task_runner_->BelongsToCurrentThread());
+    task_.Reset();
+    reply_.Reset();
+  }
+
+  void Run() {
+    task_.Run();
+    origin_task_runner_->PostTask(
+        from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
+                         base::Unretained(this)));
+  }
+
+ private:
+  void RunReplyAndSelfDestruct() {
+    DCHECK(origin_task_runner_->BelongsToCurrentThread());
+
+    // Force |task_| to be released before |reply_| is to ensure that no one
+    // accidentally depends on |task_| keeping one of its arguments alive while
+    // |reply_| is executing.
+    task_.Reset();
+
+    reply_.Run();
+
+    // Cue mission impossible theme.
+    delete this;
+  }
+
+  tracked_objects::Location from_here_;
+  scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
+  Closure reply_;
+  Closure task_;
+};
+
+}  // namespace
+
+namespace internal {
+
+bool PostTaskAndReplyImpl::PostTaskAndReply(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  PostTaskAndReplyRelay* relay =
+      new PostTaskAndReplyRelay(from_here, task, reply);
+  if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
+                                Unretained(relay)))) {
+    delete relay;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
new file mode 100644
index 0000000..a5b9580
--- /dev/null
+++ b/base/threading/post_task_and_reply_impl.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation shared by
+// TaskRunner::PostTaskAndReply and WorkerPool::PostTaskAndReply.
+
+#ifndef BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
+#define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
+
+#include "base/callback_forward.h"
+#include "base/location.h"
+
+namespace base {
+namespace internal {
+
+// Inherit from this in a class that implements PostTask appropriately
+// for sending to a destination thread.
+//
+// Note that 'reply' will always get posted back to your current
+// MessageLoop.
+//
+// If you're looking for a concrete implementation of
+// PostTaskAndReply, you probably want base::SingleThreadTaskRunner, or you
+// may want base::WorkerPool.
+class PostTaskAndReplyImpl {
+ public:
+  // Implementation for TaskRunner::PostTaskAndReply and
+  // WorkerPool::PostTaskAndReply.
+  bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply);
+
+ private:
+  virtual bool PostTask(const tracked_objects::Location& from_here,
+                        const Closure& task) = 0;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
new file mode 100644
index 0000000..7bbca92
--- /dev/null
+++ b/base/threading/sequenced_worker_pool.cc
@@ -0,0 +1,1307 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/sequenced_worker_pool.h"
+
+#include <list>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/atomic_sequence_num.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/critical_closure.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#elif defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
+#if !defined(OS_NACL)
+#include "base/metrics/histogram.h"
+#endif
+
+namespace base {
+
+namespace {
+
+struct SequencedTask : public TrackingInfo  {
+  SequencedTask()
+      : sequence_token_id(0),
+        trace_id(0),
+        sequence_task_number(0),
+        shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {}
+
+  explicit SequencedTask(const tracked_objects::Location& from_here)
+      : base::TrackingInfo(from_here, TimeTicks()),
+        sequence_token_id(0),
+        trace_id(0),
+        sequence_task_number(0),
+        shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {}
+
+  ~SequencedTask() {}
+
+  int sequence_token_id;
+  int trace_id;
+  int64 sequence_task_number;
+  SequencedWorkerPool::WorkerShutdown shutdown_behavior;
+  tracked_objects::Location posted_from;
+  Closure task;
+
+  // Non-delayed tasks and delayed tasks are managed together by time-to-run
+  // order. We calculate the time by adding the posted time and the given delay.
+  TimeTicks time_to_run;
+};
+
+struct SequencedTaskLessThan {
+ public:
+  bool operator()(const SequencedTask& lhs, const SequencedTask& rhs) const {
+    if (lhs.time_to_run < rhs.time_to_run)
+      return true;
+
+    if (lhs.time_to_run > rhs.time_to_run)
+      return false;
+
+    // If the time happen to match, then we use the sequence number to decide.
+    return lhs.sequence_task_number < rhs.sequence_task_number;
+  }
+};
+
+// SequencedWorkerPoolTaskRunner ---------------------------------------------
+// A TaskRunner which posts tasks to a SequencedWorkerPool with a
+// fixed ShutdownBehavior.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class SequencedWorkerPoolTaskRunner : public TaskRunner {
+ public:
+  SequencedWorkerPoolTaskRunner(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      SequencedWorkerPool::WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  ~SequencedWorkerPoolTaskRunner() override;
+
+  const scoped_refptr<SequencedWorkerPool> pool_;
+
+  const SequencedWorkerPool::WorkerShutdown shutdown_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolTaskRunner);
+};
+
+SequencedWorkerPoolTaskRunner::SequencedWorkerPoolTaskRunner(
+    const scoped_refptr<SequencedWorkerPool>& pool,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(pool),
+      shutdown_behavior_(shutdown_behavior) {
+}
+
+SequencedWorkerPoolTaskRunner::~SequencedWorkerPoolTaskRunner() {
+}
+
+bool SequencedWorkerPoolTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay == TimeDelta()) {
+    return pool_->PostWorkerTaskWithShutdownBehavior(
+        from_here, task, shutdown_behavior_);
+  }
+  return pool_->PostDelayedWorkerTask(from_here, task, delay);
+}
+
+bool SequencedWorkerPoolTaskRunner::RunsTasksOnCurrentThread() const {
+  return pool_->RunsTasksOnCurrentThread();
+}
+
+// SequencedWorkerPoolSequencedTaskRunner ------------------------------------
+// A SequencedTaskRunner which posts tasks to a SequencedWorkerPool with a
+// fixed sequence token.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class SequencedWorkerPoolSequencedTaskRunner : public SequencedTaskRunner {
+ public:
+  SequencedWorkerPoolSequencedTaskRunner(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      SequencedWorkerPool::SequenceToken token,
+      SequencedWorkerPool::WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // SequencedTaskRunner implementation
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+ private:
+  ~SequencedWorkerPoolSequencedTaskRunner() override;
+
+  const scoped_refptr<SequencedWorkerPool> pool_;
+
+  const SequencedWorkerPool::SequenceToken token_;
+
+  const SequencedWorkerPool::WorkerShutdown shutdown_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolSequencedTaskRunner);
+};
+
+SequencedWorkerPoolSequencedTaskRunner::SequencedWorkerPoolSequencedTaskRunner(
+    const scoped_refptr<SequencedWorkerPool>& pool,
+    SequencedWorkerPool::SequenceToken token,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(pool),
+      token_(token),
+      shutdown_behavior_(shutdown_behavior) {
+}
+
+SequencedWorkerPoolSequencedTaskRunner::
+~SequencedWorkerPoolSequencedTaskRunner() {
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay == TimeDelta()) {
+    return pool_->PostSequencedWorkerTaskWithShutdownBehavior(
+        token_, from_here, task, shutdown_behavior_);
+  }
+  return pool_->PostDelayedSequencedWorkerTask(token_, from_here, task, delay);
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::RunsTasksOnCurrentThread() const {
+  return pool_->IsRunningSequenceOnCurrentThread(token_);
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  // There's no way to run nested tasks, so simply forward to
+  // PostDelayedTask.
+  return PostDelayedTask(from_here, task, delay);
+}
+
+// Create a process-wide unique ID to represent this task in trace events. This
+// will be mangled with a Process ID hash to reduce the likelyhood of colliding
+// with MessageLoop pointers on other processes.
+uint64 GetTaskTraceID(const SequencedTask& task,
+                      void* pool) {
+  return (static_cast<uint64>(task.trace_id) << 32) |
+         static_cast<uint64>(reinterpret_cast<intptr_t>(pool));
+}
+
+base::LazyInstance<base::ThreadLocalPointer<
+    SequencedWorkerPool::SequenceToken> >::Leaky g_lazy_tls_ptr =
+        LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Worker ---------------------------------------------------------------------
+
+class SequencedWorkerPool::Worker : public SimpleThread {
+ public:
+  // Hold a (cyclic) ref to |worker_pool|, since we want to keep it
+  // around as long as we are running.
+  Worker(const scoped_refptr<SequencedWorkerPool>& worker_pool,
+         int thread_number,
+         const std::string& thread_name_prefix);
+  ~Worker() override;
+
+  // SimpleThread implementation. This actually runs the background thread.
+  void Run() override;
+
+  // Indicates that a task is about to be run. The parameters provide
+  // additional metainformation about the task being run.
+  void set_running_task_info(SequenceToken token,
+                             WorkerShutdown shutdown_behavior) {
+    is_processing_task_ = true;
+    task_sequence_token_ = token;
+    task_shutdown_behavior_ = shutdown_behavior;
+  }
+
+  // Indicates that the task has finished running.
+  void reset_running_task_info() { is_processing_task_ = false; }
+
+  // Whether the worker is processing a task.
+  bool is_processing_task() { return is_processing_task_; }
+
+  SequenceToken task_sequence_token() const {
+    DCHECK(is_processing_task_);
+    return task_sequence_token_;
+  }
+
+  WorkerShutdown task_shutdown_behavior() const {
+    DCHECK(is_processing_task_);
+    return task_shutdown_behavior_;
+  }
+
+ private:
+  scoped_refptr<SequencedWorkerPool> worker_pool_;
+  // The sequence token of the task being processed. Only valid when
+  // is_processing_task_ is true.
+  SequenceToken task_sequence_token_;
+  // The shutdown behavior of the task being processed. Only valid when
+  // is_processing_task_ is true.
+  WorkerShutdown task_shutdown_behavior_;
+  // Whether the Worker is processing a task.
+  bool is_processing_task_;
+
+  DISALLOW_COPY_AND_ASSIGN(Worker);
+};
+
+// Inner ----------------------------------------------------------------------
+
+class SequencedWorkerPool::Inner {
+ public:
+  // Take a raw pointer to |worker| to avoid cycles (since we're owned
+  // by it).
+  Inner(SequencedWorkerPool* worker_pool, size_t max_threads,
+        const std::string& thread_name_prefix,
+        TestingObserver* observer);
+
+  ~Inner();
+
+  SequenceToken GetSequenceToken();
+
+  SequenceToken GetNamedSequenceToken(const std::string& name);
+
+  // This function accepts a name and an ID. If the name is null, the
+  // token ID is used. This allows us to implement the optional name lookup
+  // from a single function without having to enter the lock a separate time.
+  bool PostTask(const std::string* optional_token_name,
+                SequenceToken sequence_token,
+                WorkerShutdown shutdown_behavior,
+                const tracked_objects::Location& from_here,
+                const Closure& task,
+                TimeDelta delay);
+
+  bool RunsTasksOnCurrentThread() const;
+
+  bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+
+  void CleanupForTesting();
+
+  void SignalHasWorkForTesting();
+
+  int GetWorkSignalCountForTesting() const;
+
+  void Shutdown(int max_blocking_tasks_after_shutdown);
+
+  bool IsShutdownInProgress();
+
+  // Runs the worker loop on the background thread.
+  void ThreadLoop(Worker* this_worker);
+
+ private:
+  enum GetWorkStatus {
+    GET_WORK_FOUND,
+    GET_WORK_NOT_FOUND,
+    GET_WORK_WAIT,
+  };
+
+  enum CleanupState {
+    CLEANUP_REQUESTED,
+    CLEANUP_STARTING,
+    CLEANUP_RUNNING,
+    CLEANUP_FINISHING,
+    CLEANUP_DONE,
+  };
+
+  // Called from within the lock, this converts the given token name into a
+  // token ID, creating a new one if necessary.
+  int LockedGetNamedTokenID(const std::string& name);
+
+  // Called from within the lock, this returns the next sequence task number.
+  int64 LockedGetNextSequenceTaskNumber();
+
+  // Gets new task. There are 3 cases depending on the return value:
+  //
+  // 1) If the return value is |GET_WORK_FOUND|, |task| is filled in and should
+  //    be run immediately.
+  // 2) If the return value is |GET_WORK_NOT_FOUND|, there are no tasks to run,
+  //    and |task| is not filled in. In this case, the caller should wait until
+  //    a task is posted.
+  // 3) If the return value is |GET_WORK_WAIT|, there are no tasks to run
+  //    immediately, and |task| is not filled in. Likewise, |wait_time| is
+  //    filled in the time to wait until the next task to run. In this case, the
+  //    caller should wait the time.
+  //
+  // In any case, the calling code should clear the given
+  // delete_these_outside_lock vector the next time the lock is released.
+  // See the implementation for a more detailed description.
+  GetWorkStatus GetWork(SequencedTask* task,
+                        TimeDelta* wait_time,
+                        std::vector<Closure>* delete_these_outside_lock);
+
+  void HandleCleanup();
+
+  // Peforms init and cleanup around running the given task. WillRun...
+  // returns the value from PrepareToStartAdditionalThreadIfNecessary.
+  // The calling code should call FinishStartingAdditionalThread once the
+  // lock is released if the return values is nonzero.
+  int WillRunWorkerTask(const SequencedTask& task);
+  void DidRunWorkerTask(const SequencedTask& task);
+
+  // Returns true if there are no threads currently running the given
+  // sequence token.
+  bool IsSequenceTokenRunnable(int sequence_token_id) const;
+
+  // Checks if all threads are busy and the addition of one more could run an
+  // additional task waiting in the queue. This must be called from within
+  // the lock.
+  //
+  // If another thread is helpful, this will mark the thread as being in the
+  // process of starting and returns the index of the new thread which will be
+  // 0 or more. The caller should then call FinishStartingAdditionalThread to
+  // complete initialization once the lock is released.
+  //
+  // If another thread is not necessary, returne 0;
+  //
+  // See the implementedion for more.
+  int PrepareToStartAdditionalThreadIfHelpful();
+
+  // The second part of thread creation after
+  // PrepareToStartAdditionalThreadIfHelpful with the thread number it
+  // generated. This actually creates the thread and should be called outside
+  // the lock to avoid blocking important work starting a thread in the lock.
+  void FinishStartingAdditionalThread(int thread_number);
+
+  // Signal |has_work_| and increment |has_work_signal_count_|.
+  void SignalHasWork();
+
+  // Checks whether there is work left that's blocking shutdown. Must be
+  // called inside the lock.
+  bool CanShutdown() const;
+
+  SequencedWorkerPool* const worker_pool_;
+
+  // The last sequence number used. Managed by GetSequenceToken, since this
+  // only does threadsafe increment operations, you do not need to hold the
+  // lock. This is class-static to make SequenceTokens issued by
+  // GetSequenceToken unique across SequencedWorkerPool instances.
+  static base::StaticAtomicSequenceNumber g_last_sequence_number_;
+
+  // This lock protects |everything in this class|. Do not read or modify
+  // anything without holding this lock. Do not block while holding this
+  // lock.
+  mutable Lock lock_;
+
+  // Condition variable that is waited on by worker threads until new
+  // tasks are posted or shutdown starts.
+  ConditionVariable has_work_cv_;
+
+  // Condition variable that is waited on by non-worker threads (in
+  // Shutdown()) until CanShutdown() goes to true.
+  ConditionVariable can_shutdown_cv_;
+
+  // The maximum number of worker threads we'll create.
+  const size_t max_threads_;
+
+  const std::string thread_name_prefix_;
+
+  // Associates all known sequence token names with their IDs.
+  std::map<std::string, int> named_sequence_tokens_;
+
+  // Owning pointers to all threads we've created so far, indexed by
+  // ID. Since we lazily create threads, this may be less than
+  // max_threads_ and will be initially empty.
+  typedef std::map<PlatformThreadId, linked_ptr<Worker> > ThreadMap;
+  ThreadMap threads_;
+
+  // Set to true when we're in the process of creating another thread.
+  // See PrepareToStartAdditionalThreadIfHelpful for more.
+  bool thread_being_created_;
+
+  // Number of threads currently waiting for work.
+  size_t waiting_thread_count_;
+
+  // Number of threads currently running tasks that have the BLOCK_SHUTDOWN
+  // or SKIP_ON_SHUTDOWN flag set.
+  size_t blocking_shutdown_thread_count_;
+
+  // A set of all pending tasks in time-to-run order. These are tasks that are
+  // either waiting for a thread to run on, waiting for their time to run,
+  // or blocked on a previous task in their sequence. We have to iterate over
+  // the tasks by time-to-run order, so we use the set instead of the
+  // traditional priority_queue.
+  typedef std::set<SequencedTask, SequencedTaskLessThan> PendingTaskSet;
+  PendingTaskSet pending_tasks_;
+
+  // The next sequence number for a new sequenced task.
+  int64 next_sequence_task_number_;
+
+  // Number of tasks in the pending_tasks_ list that are marked as blocking
+  // shutdown.
+  size_t blocking_shutdown_pending_task_count_;
+
+  // Lists all sequence tokens currently executing.
+  std::set<int> current_sequences_;
+
+  // An ID for each posted task to distinguish the task from others in traces.
+  int trace_id_;
+
+  // Set when Shutdown is called and no further tasks should be
+  // allowed, though we may still be running existing tasks.
+  bool shutdown_called_;
+
+  // The number of new BLOCK_SHUTDOWN tasks that may be posted after Shudown()
+  // has been called.
+  int max_blocking_tasks_after_shutdown_;
+
+  // State used to cleanup for testing, all guarded by lock_.
+  CleanupState cleanup_state_;
+  size_t cleanup_idlers_;
+  ConditionVariable cleanup_cv_;
+
+  TestingObserver* const testing_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(Inner);
+};
+
+// Worker definitions ---------------------------------------------------------
+
+SequencedWorkerPool::Worker::Worker(
+    const scoped_refptr<SequencedWorkerPool>& worker_pool,
+    int thread_number,
+    const std::string& prefix)
+    : SimpleThread(prefix + StringPrintf("Worker%d", thread_number)),
+      worker_pool_(worker_pool),
+      task_shutdown_behavior_(BLOCK_SHUTDOWN),
+      is_processing_task_(false) {
+  Start();
+}
+
+SequencedWorkerPool::Worker::~Worker() {
+}
+
+void SequencedWorkerPool::Worker::Run() {
+#if defined(OS_WIN)
+  win::ScopedCOMInitializer com_initializer;
+#endif
+
+  // Store a pointer to the running sequence in thread local storage for
+  // static function access.
+  g_lazy_tls_ptr.Get().Set(&task_sequence_token_);
+
+  // Just jump back to the Inner object to run the thread, since it has all the
+  // tracking information and queues. It might be more natural to implement
+  // using DelegateSimpleThread and have Inner implement the Delegate to avoid
+  // having these worker objects at all, but that method lacks the ability to
+  // send thread-specific information easily to the thread loop.
+  worker_pool_->inner_->ThreadLoop(this);
+  // Release our cyclic reference once we're done.
+  worker_pool_ = NULL;
+}
+
+// Inner definitions ---------------------------------------------------------
+
+SequencedWorkerPool::Inner::Inner(
+    SequencedWorkerPool* worker_pool,
+    size_t max_threads,
+    const std::string& thread_name_prefix,
+    TestingObserver* observer)
+    : worker_pool_(worker_pool),
+      lock_(),
+      has_work_cv_(&lock_),
+      can_shutdown_cv_(&lock_),
+      max_threads_(max_threads),
+      thread_name_prefix_(thread_name_prefix),
+      thread_being_created_(false),
+      waiting_thread_count_(0),
+      blocking_shutdown_thread_count_(0),
+      next_sequence_task_number_(0),
+      blocking_shutdown_pending_task_count_(0),
+      trace_id_(0),
+      shutdown_called_(false),
+      max_blocking_tasks_after_shutdown_(0),
+      cleanup_state_(CLEANUP_DONE),
+      cleanup_idlers_(0),
+      cleanup_cv_(&lock_),
+      testing_observer_(observer) {}
+
+SequencedWorkerPool::Inner::~Inner() {
+  // You must call Shutdown() before destroying the pool.
+  DCHECK(shutdown_called_);
+
+  // Need to explicitly join with the threads before they're destroyed or else
+  // they will be running when our object is half torn down.
+  for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it)
+    it->second->Join();
+  threads_.clear();
+
+  if (testing_observer_)
+    testing_observer_->OnDestruct();
+}
+
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::Inner::GetSequenceToken() {
+  // Need to add one because StaticAtomicSequenceNumber starts at zero, which
+  // is used as a sentinel value in SequenceTokens.
+  return SequenceToken(g_last_sequence_number_.GetNext() + 1);
+}
+
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::Inner::GetNamedSequenceToken(const std::string& name) {
+  AutoLock lock(lock_);
+  return SequenceToken(LockedGetNamedTokenID(name));
+}
+
+bool SequencedWorkerPool::Inner::PostTask(
+    const std::string* optional_token_name,
+    SequenceToken sequence_token,
+    WorkerShutdown shutdown_behavior,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(delay == TimeDelta() || shutdown_behavior == SKIP_ON_SHUTDOWN);
+  SequencedTask sequenced(from_here);
+  sequenced.sequence_token_id = sequence_token.id_;
+  sequenced.shutdown_behavior = shutdown_behavior;
+  sequenced.posted_from = from_here;
+  sequenced.task =
+      shutdown_behavior == BLOCK_SHUTDOWN ?
+      base::MakeCriticalClosure(task) : task;
+  sequenced.time_to_run = TimeTicks::Now() + delay;
+
+  int create_thread_id = 0;
+  {
+    AutoLock lock(lock_);
+    if (shutdown_called_) {
+      // Don't allow a new task to be posted if it doesn't block shutdown.
+      if (shutdown_behavior != BLOCK_SHUTDOWN)
+        return false;
+
+      // If the current thread is running a task, and that task doesn't block
+      // shutdown, then it shouldn't be allowed to post any more tasks.
+      ThreadMap::const_iterator found =
+          threads_.find(PlatformThread::CurrentId());
+      if (found != threads_.end() && found->second->is_processing_task() &&
+          found->second->task_shutdown_behavior() != BLOCK_SHUTDOWN) {
+        return false;
+      }
+
+      if (max_blocking_tasks_after_shutdown_ <= 0) {
+        DLOG(WARNING) << "BLOCK_SHUTDOWN task disallowed";
+        return false;
+      }
+      max_blocking_tasks_after_shutdown_ -= 1;
+    }
+
+    // The trace_id is used for identifying the task in about:tracing.
+    sequenced.trace_id = trace_id_++;
+
+    TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+        "SequencedWorkerPool::PostTask",
+        TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))));
+
+    sequenced.sequence_task_number = LockedGetNextSequenceTaskNumber();
+
+    // Now that we have the lock, apply the named token rules.
+    if (optional_token_name)
+      sequenced.sequence_token_id = LockedGetNamedTokenID(*optional_token_name);
+
+    pending_tasks_.insert(sequenced);
+    if (shutdown_behavior == BLOCK_SHUTDOWN)
+      blocking_shutdown_pending_task_count_++;
+
+    create_thread_id = PrepareToStartAdditionalThreadIfHelpful();
+  }
+
+  // Actually start the additional thread or signal an existing one now that
+  // we're outside the lock.
+  if (create_thread_id)
+    FinishStartingAdditionalThread(create_thread_id);
+  else
+    SignalHasWork();
+
+  return true;
+}
+
+bool SequencedWorkerPool::Inner::RunsTasksOnCurrentThread() const {
+  AutoLock lock(lock_);
+  return ContainsKey(threads_, PlatformThread::CurrentId());
+}
+
+bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
+    SequenceToken sequence_token) const {
+  AutoLock lock(lock_);
+  ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
+  if (found == threads_.end())
+    return false;
+  return found->second->is_processing_task() &&
+         sequence_token.Equals(found->second->task_sequence_token());
+}
+
+// See https://code.google.com/p/chromium/issues/detail?id=168415
+void SequencedWorkerPool::Inner::CleanupForTesting() {
+  DCHECK(!RunsTasksOnCurrentThread());
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  AutoLock lock(lock_);
+  CHECK_EQ(CLEANUP_DONE, cleanup_state_);
+  if (shutdown_called_)
+    return;
+  if (pending_tasks_.empty() && waiting_thread_count_ == threads_.size())
+    return;
+  cleanup_state_ = CLEANUP_REQUESTED;
+  cleanup_idlers_ = 0;
+  has_work_cv_.Signal();
+  while (cleanup_state_ != CLEANUP_DONE)
+    cleanup_cv_.Wait();
+}
+
+void SequencedWorkerPool::Inner::SignalHasWorkForTesting() {
+  SignalHasWork();
+}
+
+void SequencedWorkerPool::Inner::Shutdown(
+    int max_new_blocking_tasks_after_shutdown) {
+  DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0);
+  {
+    AutoLock lock(lock_);
+    // Cleanup and Shutdown should not be called concurrently.
+    CHECK_EQ(CLEANUP_DONE, cleanup_state_);
+    if (shutdown_called_)
+      return;
+    shutdown_called_ = true;
+    max_blocking_tasks_after_shutdown_ = max_new_blocking_tasks_after_shutdown;
+
+    // Tickle the threads. This will wake up a waiting one so it will know that
+    // it can exit, which in turn will wake up any other waiting ones.
+    SignalHasWork();
+
+    // There are no pending or running tasks blocking shutdown, we're done.
+    if (CanShutdown())
+      return;
+  }
+
+  // If we're here, then something is blocking shutdown.  So wait for
+  // CanShutdown() to go to true.
+
+  if (testing_observer_)
+    testing_observer_->WillWaitForShutdown();
+
+#if !defined(OS_NACL)
+  TimeTicks shutdown_wait_begin = TimeTicks::Now();
+#endif
+
+  {
+    base::ThreadRestrictions::ScopedAllowWait allow_wait;
+    AutoLock lock(lock_);
+    while (!CanShutdown())
+      can_shutdown_cv_.Wait();
+  }
+#if !defined(OS_NACL)
+  UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime",
+                      TimeTicks::Now() - shutdown_wait_begin);
+#endif
+}
+
+bool SequencedWorkerPool::Inner::IsShutdownInProgress() {
+    AutoLock lock(lock_);
+    return shutdown_called_;
+}
+
+void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
+  {
+    AutoLock lock(lock_);
+    DCHECK(thread_being_created_);
+    thread_being_created_ = false;
+    std::pair<ThreadMap::iterator, bool> result =
+        threads_.insert(
+            std::make_pair(this_worker->tid(), make_linked_ptr(this_worker)));
+    DCHECK(result.second);
+
+    while (true) {
+#if defined(OS_MACOSX)
+      base::mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+      HandleCleanup();
+
+      // See GetWork for what delete_these_outside_lock is doing.
+      SequencedTask task;
+      TimeDelta wait_time;
+      std::vector<Closure> delete_these_outside_lock;
+      GetWorkStatus status =
+          GetWork(&task, &wait_time, &delete_these_outside_lock);
+      if (status == GET_WORK_FOUND) {
+        TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+            "SequencedWorkerPool::PostTask",
+            TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))));
+        TRACE_EVENT2("toplevel", "SequencedWorkerPool::ThreadLoop",
+                     "src_file", task.posted_from.file_name(),
+                     "src_func", task.posted_from.function_name());
+        int new_thread_id = WillRunWorkerTask(task);
+        {
+          AutoUnlock unlock(lock_);
+          // There may be more work available, so wake up another
+          // worker thread. (Technically not required, since we
+          // already get a signal for each new task, but it doesn't
+          // hurt.)
+          SignalHasWork();
+          delete_these_outside_lock.clear();
+
+          // Complete thread creation outside the lock if necessary.
+          if (new_thread_id)
+            FinishStartingAdditionalThread(new_thread_id);
+
+          this_worker->set_running_task_info(
+              SequenceToken(task.sequence_token_id), task.shutdown_behavior);
+
+          tracked_objects::TaskStopwatch stopwatch;
+          stopwatch.Start();
+          task.task.Run();
+          stopwatch.Stop();
+
+          tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(
+              task, stopwatch);
+
+          // Make sure our task is erased outside the lock for the
+          // same reason we do this with delete_these_oustide_lock.
+          // Also, do it before calling reset_running_task_info() so
+          // that sequence-checking from within the task's destructor
+          // still works.
+          task.task = Closure();
+
+          this_worker->reset_running_task_info();
+        }
+        DidRunWorkerTask(task);  // Must be done inside the lock.
+      } else if (cleanup_state_ == CLEANUP_RUNNING) {
+        switch (status) {
+          case GET_WORK_WAIT: {
+              AutoUnlock unlock(lock_);
+              delete_these_outside_lock.clear();
+            }
+            break;
+          case GET_WORK_NOT_FOUND:
+            CHECK(delete_these_outside_lock.empty());
+            cleanup_state_ = CLEANUP_FINISHING;
+            cleanup_cv_.Broadcast();
+            break;
+          default:
+            NOTREACHED();
+        }
+      } else {
+        // When we're terminating and there's no more work, we can
+        // shut down, other workers can complete any pending or new tasks.
+        // We can get additional tasks posted after shutdown_called_ is set
+        // but only worker threads are allowed to post tasks at that time, and
+        // the workers responsible for posting those tasks will be available
+        // to run them. Also, there may be some tasks stuck behind running
+        // ones with the same sequence token, but additional threads won't
+        // help this case.
+        if (shutdown_called_ && blocking_shutdown_pending_task_count_ == 0) {
+          AutoUnlock unlock(lock_);
+          delete_these_outside_lock.clear();
+          break;
+        }
+
+        // No work was found, but there are tasks that need deletion. The
+        // deletion must happen outside of the lock.
+        if (delete_these_outside_lock.size()) {
+          AutoUnlock unlock(lock_);
+          delete_these_outside_lock.clear();
+
+          // Since the lock has been released, |status| may no longer be
+          // accurate. It might read GET_WORK_WAIT even if there are tasks
+          // ready to perform work. Jump to the top of the loop to recalculate
+          // |status|.
+          continue;
+        }
+
+        waiting_thread_count_++;
+
+        switch (status) {
+          case GET_WORK_NOT_FOUND:
+            has_work_cv_.Wait();
+            break;
+          case GET_WORK_WAIT:
+            has_work_cv_.TimedWait(wait_time);
+            break;
+          default:
+            NOTREACHED();
+        }
+        waiting_thread_count_--;
+      }
+    }
+  }  // Release lock_.
+
+  // We noticed we should exit. Wake up the next worker so it knows it should
+  // exit as well (because the Shutdown() code only signals once).
+  SignalHasWork();
+
+  // Possibly unblock shutdown.
+  can_shutdown_cv_.Signal();
+}
+
+void SequencedWorkerPool::Inner::HandleCleanup() {
+  lock_.AssertAcquired();
+  if (cleanup_state_ == CLEANUP_DONE)
+    return;
+  if (cleanup_state_ == CLEANUP_REQUESTED) {
+    // We win, we get to do the cleanup as soon as the others wise up and idle.
+    cleanup_state_ = CLEANUP_STARTING;
+    while (thread_being_created_ ||
+           cleanup_idlers_ != threads_.size() - 1) {
+      has_work_cv_.Signal();
+      cleanup_cv_.Wait();
+    }
+    cleanup_state_ = CLEANUP_RUNNING;
+    return;
+  }
+  if (cleanup_state_ == CLEANUP_STARTING) {
+    // Another worker thread is cleaning up, we idle here until thats done.
+    ++cleanup_idlers_;
+    cleanup_cv_.Broadcast();
+    while (cleanup_state_ != CLEANUP_FINISHING) {
+      cleanup_cv_.Wait();
+    }
+    --cleanup_idlers_;
+    cleanup_cv_.Broadcast();
+    return;
+  }
+  if (cleanup_state_ == CLEANUP_FINISHING) {
+    // We wait for all idlers to wake up prior to being DONE.
+    while (cleanup_idlers_ != 0) {
+      cleanup_cv_.Broadcast();
+      cleanup_cv_.Wait();
+    }
+    if (cleanup_state_ == CLEANUP_FINISHING) {
+      cleanup_state_ = CLEANUP_DONE;
+      cleanup_cv_.Signal();
+    }
+    return;
+  }
+}
+
+int SequencedWorkerPool::Inner::LockedGetNamedTokenID(
+    const std::string& name) {
+  lock_.AssertAcquired();
+  DCHECK(!name.empty());
+
+  std::map<std::string, int>::const_iterator found =
+      named_sequence_tokens_.find(name);
+  if (found != named_sequence_tokens_.end())
+    return found->second;  // Got an existing one.
+
+  // Create a new one for this name.
+  SequenceToken result = GetSequenceToken();
+  named_sequence_tokens_.insert(std::make_pair(name, result.id_));
+  return result.id_;
+}
+
+int64 SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
+  lock_.AssertAcquired();
+  // We assume that we never create enough tasks to wrap around.
+  return next_sequence_task_number_++;
+}
+
+SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork(
+    SequencedTask* task,
+    TimeDelta* wait_time,
+    std::vector<Closure>* delete_these_outside_lock) {
+  lock_.AssertAcquired();
+
+  // Find the next task with a sequence token that's not currently in use.
+  // If the token is in use, that means another thread is running something
+  // in that sequence, and we can't run it without going out-of-order.
+  //
+  // This algorithm is simple and fair, but inefficient in some cases. For
+  // example, say somebody schedules 1000 slow tasks with the same sequence
+  // number. We'll have to go through all those tasks each time we feel like
+  // there might be work to schedule. If this proves to be a problem, we
+  // should make this more efficient.
+  //
+  // One possible enhancement would be to keep a map from sequence ID to a
+  // list of pending but currently blocked SequencedTasks for that ID.
+  // When a worker finishes a task of one sequence token, it can pick up the
+  // next one from that token right away.
+  //
+  // This may lead to starvation if there are sufficient numbers of sequences
+  // in use. To alleviate this, we could add an incrementing priority counter
+  // to each SequencedTask. Then maintain a priority_queue of all runnable
+  // tasks, sorted by priority counter. When a sequenced task is completed
+  // we would pop the head element off of that tasks pending list and add it
+  // to the priority queue. Then we would run the first item in the priority
+  // queue.
+
+  GetWorkStatus status = GET_WORK_NOT_FOUND;
+  int unrunnable_tasks = 0;
+  PendingTaskSet::iterator i = pending_tasks_.begin();
+  // We assume that the loop below doesn't take too long and so we can just do
+  // a single call to TimeTicks::Now().
+  const TimeTicks current_time = TimeTicks::Now();
+  while (i != pending_tasks_.end()) {
+    if (!IsSequenceTokenRunnable(i->sequence_token_id)) {
+      unrunnable_tasks++;
+      ++i;
+      continue;
+    }
+
+    if (shutdown_called_ && i->shutdown_behavior != BLOCK_SHUTDOWN) {
+      // We're shutting down and the task we just found isn't blocking
+      // shutdown. Delete it and get more work.
+      //
+      // Note that we do not want to delete unrunnable tasks. Deleting a task
+      // can have side effects (like freeing some objects) and deleting a
+      // task that's supposed to run after one that's currently running could
+      // cause an obscure crash.
+      //
+      // We really want to delete these tasks outside the lock in case the
+      // closures are holding refs to objects that want to post work from
+      // their destructorss (which would deadlock). The closures are
+      // internally refcounted, so we just need to keep a copy of them alive
+      // until the lock is exited. The calling code can just clear() the
+      // vector they passed to us once the lock is exited to make this
+      // happen.
+      delete_these_outside_lock->push_back(i->task);
+      pending_tasks_.erase(i++);
+      continue;
+    }
+
+    if (i->time_to_run > current_time) {
+      // The time to run has not come yet.
+      *wait_time = i->time_to_run - current_time;
+      status = GET_WORK_WAIT;
+      if (cleanup_state_ == CLEANUP_RUNNING) {
+        // Deferred tasks are deleted when cleaning up, see Inner::ThreadLoop.
+        delete_these_outside_lock->push_back(i->task);
+        pending_tasks_.erase(i);
+      }
+      break;
+    }
+
+    // Found a runnable task.
+    *task = *i;
+    pending_tasks_.erase(i);
+    if (task->shutdown_behavior == BLOCK_SHUTDOWN) {
+      blocking_shutdown_pending_task_count_--;
+    }
+
+    status = GET_WORK_FOUND;
+    break;
+  }
+
+  return status;
+}
+
+int SequencedWorkerPool::Inner::WillRunWorkerTask(const SequencedTask& task) {
+  lock_.AssertAcquired();
+
+  // Mark the task's sequence number as in use.
+  if (task.sequence_token_id)
+    current_sequences_.insert(task.sequence_token_id);
+
+  // Ensure that threads running tasks posted with either SKIP_ON_SHUTDOWN
+  // or BLOCK_SHUTDOWN will prevent shutdown until that task or thread
+  // completes.
+  if (task.shutdown_behavior != CONTINUE_ON_SHUTDOWN)
+    blocking_shutdown_thread_count_++;
+
+  // We just picked up a task. Since StartAdditionalThreadIfHelpful only
+  // creates a new thread if there is no free one, there is a race when posting
+  // tasks that many tasks could have been posted before a thread started
+  // running them, so only one thread would have been created. So we also check
+  // whether we should create more threads after removing our task from the
+  // queue, which also has the nice side effect of creating the workers from
+  // background threads rather than the main thread of the app.
+  //
+  // If another thread wasn't created, we want to wake up an existing thread
+  // if there is one waiting to pick up the next task.
+  //
+  // Note that we really need to do this *before* running the task, not
+  // after. Otherwise, if more than one task is posted, the creation of the
+  // second thread (since we only create one at a time) will be blocked by
+  // the execution of the first task, which could be arbitrarily long.
+  return PrepareToStartAdditionalThreadIfHelpful();
+}
+
+void SequencedWorkerPool::Inner::DidRunWorkerTask(const SequencedTask& task) {
+  lock_.AssertAcquired();
+
+  if (task.shutdown_behavior != CONTINUE_ON_SHUTDOWN) {
+    DCHECK_GT(blocking_shutdown_thread_count_, 0u);
+    blocking_shutdown_thread_count_--;
+  }
+
+  if (task.sequence_token_id)
+    current_sequences_.erase(task.sequence_token_id);
+}
+
+bool SequencedWorkerPool::Inner::IsSequenceTokenRunnable(
+    int sequence_token_id) const {
+  lock_.AssertAcquired();
+  return !sequence_token_id ||
+      current_sequences_.find(sequence_token_id) ==
+          current_sequences_.end();
+}
+
+int SequencedWorkerPool::Inner::PrepareToStartAdditionalThreadIfHelpful() {
+  lock_.AssertAcquired();
+  // How thread creation works:
+  //
+  // We'de like to avoid creating threads with the lock held. However, we
+  // need to be sure that we have an accurate accounting of the threads for
+  // proper Joining and deltion on shutdown.
+  //
+  // We need to figure out if we need another thread with the lock held, which
+  // is what this function does. It then marks us as in the process of creating
+  // a thread. When we do shutdown, we wait until the thread_being_created_
+  // flag is cleared, which ensures that the new thread is properly added to
+  // all the data structures and we can't leak it. Once shutdown starts, we'll
+  // refuse to create more threads or they would be leaked.
+  //
+  // Note that this creates a mostly benign race condition on shutdown that
+  // will cause fewer workers to be created than one would expect. It isn't
+  // much of an issue in real life, but affects some tests. Since we only spawn
+  // one worker at a time, the following sequence of events can happen:
+  //
+  //  1. Main thread posts a bunch of unrelated tasks that would normally be
+  //     run on separate threads.
+  //  2. The first task post causes us to start a worker. Other tasks do not
+  //     cause a worker to start since one is pending.
+  //  3. Main thread initiates shutdown.
+  //  4. No more threads are created since the shutdown_called_ flag is set.
+  //
+  // The result is that one may expect that max_threads_ workers to be created
+  // given the workload, but in reality fewer may be created because the
+  // sequence of thread creation on the background threads is racing with the
+  // shutdown call.
+  if (!shutdown_called_ &&
+      !thread_being_created_ &&
+      cleanup_state_ == CLEANUP_DONE &&
+      threads_.size() < max_threads_ &&
+      waiting_thread_count_ == 0) {
+    // We could use an additional thread if there's work to be done.
+    for (PendingTaskSet::const_iterator i = pending_tasks_.begin();
+         i != pending_tasks_.end(); ++i) {
+      if (IsSequenceTokenRunnable(i->sequence_token_id)) {
+        // Found a runnable task, mark the thread as being started.
+        thread_being_created_ = true;
+        return static_cast<int>(threads_.size() + 1);
+      }
+    }
+  }
+  return 0;
+}
+
+void SequencedWorkerPool::Inner::FinishStartingAdditionalThread(
+    int thread_number) {
+  // Called outside of the lock.
+  DCHECK_GT(thread_number, 0);
+
+  // The worker is assigned to the list when the thread actually starts, which
+  // will manage the memory of the pointer.
+  new Worker(worker_pool_, thread_number, thread_name_prefix_);
+}
+
+void SequencedWorkerPool::Inner::SignalHasWork() {
+  has_work_cv_.Signal();
+  if (testing_observer_) {
+    testing_observer_->OnHasWork();
+  }
+}
+
+bool SequencedWorkerPool::Inner::CanShutdown() const {
+  lock_.AssertAcquired();
+  // See PrepareToStartAdditionalThreadIfHelpful for how thread creation works.
+  return !thread_being_created_ &&
+         blocking_shutdown_thread_count_ == 0 &&
+         blocking_shutdown_pending_task_count_ == 0;
+}
+
+base::StaticAtomicSequenceNumber
+SequencedWorkerPool::Inner::g_last_sequence_number_;
+
+// SequencedWorkerPool --------------------------------------------------------
+
+// static
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
+  // Don't construct lazy instance on check.
+  if (g_lazy_tls_ptr == NULL)
+    return SequenceToken();
+
+  SequencedWorkerPool::SequenceToken* token = g_lazy_tls_ptr.Get().Get();
+  if (!token)
+    return SequenceToken();
+  return *token;
+}
+
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+                                         const std::string& thread_name_prefix)
+    : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
+      inner_(new Inner(this, max_threads, thread_name_prefix, NULL)) {
+}
+
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+                                         const std::string& thread_name_prefix,
+                                         TestingObserver* observer)
+    : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
+      inner_(new Inner(this, max_threads, thread_name_prefix, observer)) {
+}
+
+SequencedWorkerPool::~SequencedWorkerPool() {}
+
+void SequencedWorkerPool::OnDestruct() const {
+  // Avoid deleting ourselves on a worker thread (which would
+  // deadlock).
+  if (RunsTasksOnCurrentThread()) {
+    constructor_task_runner_->DeleteSoon(FROM_HERE, this);
+  } else {
+    delete this;
+  }
+}
+
+SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() {
+  return inner_->GetSequenceToken();
+}
+
+SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken(
+    const std::string& name) {
+  return inner_->GetNamedSequenceToken(name);
+}
+
+scoped_refptr<SequencedTaskRunner> SequencedWorkerPool::GetSequencedTaskRunner(
+    SequenceToken token) {
+  return GetSequencedTaskRunnerWithShutdownBehavior(token, BLOCK_SHUTDOWN);
+}
+
+scoped_refptr<SequencedTaskRunner>
+SequencedWorkerPool::GetSequencedTaskRunnerWithShutdownBehavior(
+    SequenceToken token, WorkerShutdown shutdown_behavior) {
+  return new SequencedWorkerPoolSequencedTaskRunner(
+      this, token, shutdown_behavior);
+}
+
+scoped_refptr<TaskRunner>
+SequencedWorkerPool::GetTaskRunnerWithShutdownBehavior(
+    WorkerShutdown shutdown_behavior) {
+  return new SequencedWorkerPoolTaskRunner(this, shutdown_behavior);
+}
+
+bool SequencedWorkerPool::PostWorkerTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return inner_->PostTask(NULL, SequenceToken(), BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedWorkerTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  WorkerShutdown shutdown_behavior =
+      delay == TimeDelta() ? BLOCK_SHUTDOWN : SKIP_ON_SHUTDOWN;
+  return inner_->PostTask(NULL, SequenceToken(), shutdown_behavior,
+                          from_here, task, delay);
+}
+
+bool SequencedWorkerPool::PostWorkerTaskWithShutdownBehavior(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    WorkerShutdown shutdown_behavior) {
+  return inner_->PostTask(NULL, SequenceToken(), shutdown_behavior,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostSequencedWorkerTask(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return inner_->PostTask(NULL, sequence_token, BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedSequencedWorkerTask(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  WorkerShutdown shutdown_behavior =
+      delay == TimeDelta() ? BLOCK_SHUTDOWN : SKIP_ON_SHUTDOWN;
+  return inner_->PostTask(NULL, sequence_token, shutdown_behavior,
+                          from_here, task, delay);
+}
+
+bool SequencedWorkerPool::PostNamedSequencedWorkerTask(
+    const std::string& token_name,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  DCHECK(!token_name.empty());
+  return inner_->PostTask(&token_name, SequenceToken(), BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostSequencedWorkerTaskWithShutdownBehavior(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    WorkerShutdown shutdown_behavior) {
+  return inner_->PostTask(NULL, sequence_token, shutdown_behavior,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedWorkerTask(from_here, task, delay);
+}
+
+bool SequencedWorkerPool::RunsTasksOnCurrentThread() const {
+  return inner_->RunsTasksOnCurrentThread();
+}
+
+bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread(
+    SequenceToken sequence_token) const {
+  return inner_->IsRunningSequenceOnCurrentThread(sequence_token);
+}
+
+void SequencedWorkerPool::FlushForTesting() {
+  inner_->CleanupForTesting();
+}
+
+void SequencedWorkerPool::SignalHasWorkForTesting() {
+  inner_->SignalHasWorkForTesting();
+}
+
+void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) {
+  DCHECK(constructor_task_runner_->BelongsToCurrentThread());
+  inner_->Shutdown(max_new_blocking_tasks_after_shutdown);
+}
+
+bool SequencedWorkerPool::IsShutdownInProgress() {
+  return inner_->IsShutdownInProgress();
+}
+
+}  // namespace base
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
new file mode 100644
index 0000000..ee282bc
--- /dev/null
+++ b/base/threading/sequenced_worker_pool.h
@@ -0,0 +1,360 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+
+#include <cstddef>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner.h"
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+template <class T> class DeleteHelper;
+
+class SequencedTaskRunner;
+
+// A worker thread pool that enforces ordering between sets of tasks. It also
+// allows you to specify what should happen to your tasks on shutdown.
+//
+// To enforce ordering, get a unique sequence token from the pool and post all
+// tasks you want to order with the token. All tasks with the same token are
+// guaranteed to execute serially, though not necessarily on the same thread.
+// This means that:
+//
+//   - No two tasks with the same token will run at the same time.
+//
+//   - Given two tasks T1 and T2 with the same token such that T2 will
+//     run after T1, then T2 will start after T1 is destroyed.
+//
+//   - If T2 will run after T1, then all memory changes in T1 and T1's
+//     destruction will be visible to T2.
+//
+// Example:
+//   SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
+//   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
+//                                FROM_HERE, base::Bind(...));
+//   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
+//                                FROM_HERE, base::Bind(...));
+//
+// You can make named sequence tokens to make it easier to share a token
+// across different components.
+//
+// You can also post tasks to the pool without ordering using PostWorkerTask.
+// These will be executed in an unspecified order. The order of execution
+// between tasks with different sequence tokens is also unspecified.
+//
+// This class may be leaked on shutdown to facilitate fast shutdown. The
+// expected usage, however, is to call Shutdown(), which correctly accounts
+// for CONTINUE_ON_SHUTDOWN behavior and is required for BLOCK_SHUTDOWN
+// behavior.
+//
+// Implementation note: This does not use a base::WorkerPool since that does
+// not enforce shutdown semantics or allow us to specify how many worker
+// threads to run. For the typical use case of random background work, we don't
+// necessarily want to be super aggressive about creating threads.
+//
+// Note that SequencedWorkerPool is RefCountedThreadSafe (inherited
+// from TaskRunner).
+//
+// Test-only code should wrap this in a base::SequencedWorkerPoolOwner to avoid
+// memory leaks. See http://crbug.com/273800
+class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
+ public:
+  // Defines what should happen to a task posted to the worker pool on
+  // shutdown.
+  enum WorkerShutdown {
+    // Tasks posted with this mode which have not run at shutdown will be
+    // deleted rather than run, and any tasks with this mode running at
+    // shutdown will be ignored (the worker thread will not be joined).
+    //
+    // This option provides a nice way to post stuff you don't want blocking
+    // shutdown. For example, you might be doing a slow DNS lookup and if it's
+    // blocked on the OS, you may not want to stop shutdown, since the result
+    // doesn't really matter at that point.
+    //
+    // However, you need to be very careful what you do in your callback when
+    // you use this option. Since the thread will continue to run until the OS
+    // terminates the process, the app can be in the process of tearing down
+    // when you're running. This means any singletons or global objects you
+    // use may suddenly become invalid out from under you. For this reason,
+    // it's best to use this only for slow but simple operations like the DNS
+    // example.
+    CONTINUE_ON_SHUTDOWN,
+
+    // Tasks posted with this mode that have not started executing at
+    // shutdown will be deleted rather than executed. However, any tasks that
+    // have already begun executing when shutdown is called will be allowed
+    // to continue, and will block shutdown until completion.
+    //
+    // Note: Because Shutdown() may block while these tasks are executing,
+    // care must be taken to ensure that they do not block on the thread that
+    // called Shutdown(), as this may lead to deadlock.
+    SKIP_ON_SHUTDOWN,
+
+    // Tasks posted with this mode will block shutdown until they're
+    // executed. Since this can have significant performance implications,
+    // use sparingly.
+    //
+    // Generally, this should be used only for user data, for example, a task
+    // writing a preference file.
+    //
+    // If a task is posted during shutdown, it will not get run since the
+    // workers may already be stopped. In this case, the post operation will
+    // fail (return false) and the task will be deleted.
+    BLOCK_SHUTDOWN,
+  };
+
+  // Opaque identifier that defines sequencing of tasks posted to the worker
+  // pool.
+  class SequenceToken {
+   public:
+    SequenceToken() : id_(0) {}
+    ~SequenceToken() {}
+
+    bool Equals(const SequenceToken& other) const {
+      return id_ == other.id_;
+    }
+
+    // Returns false if current thread is executing an unsequenced task.
+    bool IsValid() const {
+      return id_ != 0;
+    }
+
+   private:
+    friend class SequencedWorkerPool;
+
+    explicit SequenceToken(int id) : id_(id) {}
+
+    int id_;
+  };
+
+  // Allows tests to perform certain actions.
+  class TestingObserver {
+   public:
+    virtual ~TestingObserver() {}
+    virtual void OnHasWork() = 0;
+    virtual void WillWaitForShutdown() = 0;
+    virtual void OnDestruct() = 0;
+  };
+
+  // Gets the SequencedToken of the current thread.
+  // If current thread is not a SequencedWorkerPool worker thread or is running
+  // an unsequenced task, returns an invalid SequenceToken.
+  static SequenceToken GetSequenceTokenForCurrentThread();
+
+  // When constructing a SequencedWorkerPool, there must be a
+  // MessageLoop on the current thread unless you plan to deliberately
+  // leak it.
+
+  // Pass the maximum number of threads (they will be lazily created as needed)
+  // and a prefix for the thread name to aid in debugging.
+  SequencedWorkerPool(size_t max_threads,
+                      const std::string& thread_name_prefix);
+
+  // Like above, but with |observer| for testing.  Does not take
+  // ownership of |observer|.
+  SequencedWorkerPool(size_t max_threads,
+                      const std::string& thread_name_prefix,
+                      TestingObserver* observer);
+
+  // Returns a unique token that can be used to sequence tasks posted to
+  // PostSequencedWorkerTask(). Valid tokens are always nonzero.
+  SequenceToken GetSequenceToken();
+
+  // Returns the sequence token associated with the given name. Calling this
+  // function multiple times with the same string will always produce the
+  // same sequence token. If the name has not been used before, a new token
+  // will be created.
+  SequenceToken GetNamedSequenceToken(const std::string& name);
+
+  // Returns a SequencedTaskRunner wrapper which posts to this
+  // SequencedWorkerPool using the given sequence token. Tasks with nonzero
+  // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
+  // are posted with BLOCK_SHUTDOWN behavior.
+  scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner(
+      SequenceToken token);
+
+  // Returns a SequencedTaskRunner wrapper which posts to this
+  // SequencedWorkerPool using the given sequence token. Tasks with nonzero
+  // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
+  // are posted with the given shutdown behavior.
+  scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior(
+      SequenceToken token,
+      WorkerShutdown shutdown_behavior);
+
+  // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using
+  // the given shutdown behavior. Tasks with nonzero delay are posted with
+  // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the
+  // given shutdown behavior.
+  scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior(
+      WorkerShutdown shutdown_behavior);
+
+  // Posts the given task for execution in the worker pool. Tasks posted with
+  // this function will execute in an unspecified order on a background thread.
+  // Returns true if the task was posted. If your tasks have ordering
+  // requirements, see PostSequencedWorkerTask().
+  //
+  // This class will attempt to delete tasks that aren't run
+  // (non-block-shutdown semantics) but can't guarantee that this happens. If
+  // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there
+  // will be no workers available to delete these tasks. And there may be
+  // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN
+  // tasks. Deleting those tasks before the previous one has completed could
+  // cause nondeterministic crashes because the task could be keeping some
+  // objects alive which do work in their destructor, which could voilate the
+  // assumptions of the running task.
+  //
+  // The task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  //
+  // Returns true if the task was posted successfully. This may fail during
+  // shutdown regardless of the specified ShutdownBehavior.
+  bool PostWorkerTask(const tracked_objects::Location& from_here,
+                      const Closure& task);
+
+  // Same as PostWorkerTask but allows a delay to be specified (although doing
+  // so changes the shutdown behavior). The task will be run after the given
+  // delay has elapsed.
+  //
+  // If the delay is nonzero, the task won't be guaranteed to run to completion
+  // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
+  // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the
+  // task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  bool PostDelayedWorkerTask(const tracked_objects::Location& from_here,
+                             const Closure& task,
+                             TimeDelta delay);
+
+  // Same as PostWorkerTask but allows specification of the shutdown behavior.
+  bool PostWorkerTaskWithShutdownBehavior(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      WorkerShutdown shutdown_behavior);
+
+  // Like PostWorkerTask above, but provides sequencing semantics. This means
+  // that tasks posted with the same sequence token (see GetSequenceToken())
+  // are guaranteed to execute in order. This is useful in cases where you're
+  // doing operations that may depend on previous ones, like appending to a
+  // file.
+  //
+  // The task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  //
+  // Returns true if the task was posted successfully. This may fail during
+  // shutdown regardless of the specified ShutdownBehavior.
+  bool PostSequencedWorkerTask(SequenceToken sequence_token,
+                               const tracked_objects::Location& from_here,
+                               const Closure& task);
+
+  // Like PostSequencedWorkerTask above, but allows you to specify a named
+  // token, which saves an extra call to GetNamedSequenceToken.
+  bool PostNamedSequencedWorkerTask(const std::string& token_name,
+                                    const tracked_objects::Location& from_here,
+                                    const Closure& task);
+
+  // Same as PostSequencedWorkerTask but allows a delay to be specified
+  // (although doing so changes the shutdown behavior). The task will be run
+  // after the given delay has elapsed.
+  //
+  // If the delay is nonzero, the task won't be guaranteed to run to completion
+  // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
+  // If the delay is zero, this behaves exactly like PostSequencedWorkerTask,
+  // i.e. the task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  bool PostDelayedSequencedWorkerTask(
+      SequenceToken sequence_token,
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      TimeDelta delay);
+
+  // Same as PostSequencedWorkerTask but allows specification of the shutdown
+  // behavior.
+  bool PostSequencedWorkerTaskWithShutdownBehavior(
+      SequenceToken sequence_token,
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation. Forwards to PostDelayedWorkerTask().
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // Returns true if the current thread is processing a task with the given
+  // sequence_token.
+  bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+
+  // Blocks until all pending tasks are complete. This should only be called in
+  // unit tests when you want to validate something that should have happened.
+  // This will not flush delayed tasks; delayed tasks get deleted.
+  //
+  // Note that calling this will not prevent other threads from posting work to
+  // the queue while the calling thread is waiting on Flush(). In this case,
+  // Flush will return only when there's no more work in the queue. Normally,
+  // this doesn't come up since in a test, all the work is being posted from
+  // the main thread.
+  void FlushForTesting();
+
+  // Spuriously signal that there is work to be done.
+  void SignalHasWorkForTesting();
+
+  // Implements the worker pool shutdown. This should be called during app
+  // shutdown, and will discard/join with appropriate tasks before returning.
+  // After this call, subsequent calls to post tasks will fail.
+  //
+  // Must be called from the same thread this object was constructed on.
+  void Shutdown() { Shutdown(0); }
+
+  // A variant that allows an arbitrary number of new blocking tasks to be
+  // posted during shutdown. The tasks cannot be posted within the execution
+  // context of tasks whose shutdown behavior is not BLOCKING_SHUTDOWN. Once
+  // the limit is reached, subsequent calls to post task fail in all cases.
+  // Must be called from the same thread this object was constructed on.
+  void Shutdown(int max_new_blocking_tasks_after_shutdown);
+
+  // Check if Shutdown was called for given threading pool. This method is used
+  // for aborting time consuming operation to avoid blocking shutdown.
+  //
+  // Can be called from any thread.
+  bool IsShutdownInProgress();
+
+ protected:
+  ~SequencedWorkerPool() override;
+
+  void OnDestruct() const override;
+
+ private:
+  friend class RefCountedThreadSafe<SequencedWorkerPool>;
+  friend class DeleteHelper<SequencedWorkerPool>;
+
+  class Inner;
+  class Worker;
+
+  const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_;
+
+  // Avoid pulling in too many headers by putting (almost) everything
+  // into |inner_|.
+  const scoped_ptr<Inner> inner_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_WORKER_POOL_H_
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
new file mode 100644
index 0000000..05989a5
--- /dev/null
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -0,0 +1,1032 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/sequenced_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/test/sequenced_task_runner_test_template.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/test/task_runner_test_template.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// IMPORTANT NOTE:
+//
+// Many of these tests have failure modes where they'll hang forever. These
+// tests should not be flaky, and hanging indicates a type of failure. Do not
+// mark as flaky if they're hanging, it's likely an actual bug.
+
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Allows a number of threads to all be blocked on the same event, and
+// provides a way to unblock a certain number of them.
+class ThreadBlocker {
+ public:
+  ThreadBlocker() : lock_(), cond_var_(&lock_), unblock_counter_(0) {}
+
+  void Block() {
+    {
+      base::AutoLock lock(lock_);
+      while (unblock_counter_ == 0)
+        cond_var_.Wait();
+      unblock_counter_--;
+    }
+    cond_var_.Signal();
+  }
+
+  void Unblock(size_t count) {
+    {
+      base::AutoLock lock(lock_);
+      DCHECK_EQ(unblock_counter_, 0u);
+      unblock_counter_ = count;
+    }
+    cond_var_.Signal();
+  }
+
+ private:
+  base::Lock lock_;
+  base::ConditionVariable cond_var_;
+
+  size_t unblock_counter_;
+};
+
+class DestructionDeadlockChecker
+    : public base::RefCountedThreadSafe<DestructionDeadlockChecker> {
+ public:
+  DestructionDeadlockChecker(const scoped_refptr<SequencedWorkerPool>& pool)
+      : pool_(pool) {}
+
+ protected:
+  virtual ~DestructionDeadlockChecker() {
+    // This method should not deadlock.
+    pool_->RunsTasksOnCurrentThread();
+  }
+
+ private:
+  scoped_refptr<SequencedWorkerPool> pool_;
+  friend class base::RefCountedThreadSafe<DestructionDeadlockChecker>;
+};
+
+class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
+ public:
+  TestTracker()
+      : lock_(),
+        cond_var_(&lock_),
+        started_events_(0) {
+  }
+
+  // Each of these tasks appends the argument to the complete sequence vector
+  // so calling code can see what order they finished in.
+  void FastTask(int id) {
+    SignalWorkerDone(id);
+  }
+
+  void SlowTask(int id) {
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+    SignalWorkerDone(id);
+  }
+
+  void BlockTask(int id, ThreadBlocker* blocker) {
+    // Note that this task has started and signal anybody waiting for that
+    // to happen.
+    {
+      base::AutoLock lock(lock_);
+      started_events_++;
+    }
+    cond_var_.Signal();
+
+    blocker->Block();
+    SignalWorkerDone(id);
+  }
+
+  void PostAdditionalTasks(
+        int id, SequencedWorkerPool* pool,
+        bool expected_return_value) {
+    Closure fast_task = base::Bind(&TestTracker::FastTask, this, 100);
+    EXPECT_EQ(expected_return_value,
+              pool->PostWorkerTaskWithShutdownBehavior(
+                  FROM_HERE, fast_task,
+                  SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+    EXPECT_EQ(expected_return_value,
+              pool->PostWorkerTaskWithShutdownBehavior(
+                  FROM_HERE, fast_task,
+                  SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+    pool->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE, fast_task,
+        SequencedWorkerPool::BLOCK_SHUTDOWN);
+    SignalWorkerDone(id);
+  }
+
+  // This task posts itself back onto the SequencedWorkerPool before it
+  // finishes running. Each instance of the task maintains a strong reference
+  // to a DestructionDeadlockChecker. The DestructionDeadlockChecker is only
+  // destroyed when the task is destroyed without being run, which only happens
+  // during destruction of the SequencedWorkerPool.
+  void PostRepostingTask(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      const scoped_refptr<DestructionDeadlockChecker>& checker) {
+    Closure reposting_task =
+        base::Bind(&TestTracker::PostRepostingTask, this, pool, checker);
+    pool->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE, reposting_task, SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  }
+
+  // This task reposts itself back onto the SequencedWorkerPool before it
+  // finishes running.
+  void PostRepostingBlockingTask(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      const SequencedWorkerPool::SequenceToken& token) {
+    Closure reposting_task =
+        base::Bind(&TestTracker::PostRepostingBlockingTask, this, pool, token);
+    pool->PostSequencedWorkerTaskWithShutdownBehavior(token,
+        FROM_HERE, reposting_task, SequencedWorkerPool::BLOCK_SHUTDOWN);
+  }
+
+  void PostBlockingTaskThenUnblockThreads(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      ThreadBlocker* blocker,
+      size_t threads_to_wake) {
+    Closure arbitrary_task = base::Bind(&TestTracker::FastTask, this, 0);
+    pool->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE, arbitrary_task, SequencedWorkerPool::BLOCK_SHUTDOWN);
+    blocker->Unblock(threads_to_wake);
+  }
+
+  // Waits until the given number of tasks have started executing.
+  void WaitUntilTasksBlocked(size_t count) {
+    {
+      base::AutoLock lock(lock_);
+      while (started_events_ < count)
+        cond_var_.Wait();
+    }
+    cond_var_.Signal();
+  }
+
+  // Blocks the current thread until at least the given number of tasks are in
+  // the completed vector, and then returns a copy.
+  std::vector<int> WaitUntilTasksComplete(size_t num_tasks) {
+    std::vector<int> ret;
+    {
+      base::AutoLock lock(lock_);
+      while (complete_sequence_.size() < num_tasks)
+        cond_var_.Wait();
+      ret = complete_sequence_;
+    }
+    cond_var_.Signal();
+    return ret;
+  }
+
+  size_t GetTasksCompletedCount() {
+    base::AutoLock lock(lock_);
+    return complete_sequence_.size();
+  }
+
+  void ClearCompleteSequence() {
+    base::AutoLock lock(lock_);
+    complete_sequence_.clear();
+    started_events_ = 0;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<TestTracker>;
+  ~TestTracker() {}
+
+  void SignalWorkerDone(int id) {
+    {
+      base::AutoLock lock(lock_);
+      complete_sequence_.push_back(id);
+    }
+    cond_var_.Signal();
+  }
+
+  // Protects the complete_sequence.
+  base::Lock lock_;
+
+  base::ConditionVariable cond_var_;
+
+  // Protected by lock_.
+  std::vector<int> complete_sequence_;
+
+  // Counter of the number of "block" workers that have started.
+  size_t started_events_;
+};
+
+class SequencedWorkerPoolTest : public testing::Test {
+ public:
+  SequencedWorkerPoolTest()
+      : tracker_(new TestTracker) {
+    ResetPool();
+  }
+
+  void TearDown() override { pool()->Shutdown(); }
+
+  const scoped_refptr<SequencedWorkerPool>& pool() {
+    return pool_owner_->pool();
+  }
+  TestTracker* tracker() { return tracker_.get(); }
+
+  // Destroys the SequencedWorkerPool instance, blocking until it is fully shut
+  // down, and creates a new instance.
+  void ResetPool() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test"));
+  }
+
+  void SetWillWaitForShutdownCallback(const Closure& callback) {
+    pool_owner_->SetWillWaitForShutdownCallback(callback);
+  }
+
+  // Ensures that the given number of worker threads is created by adding
+  // tasks and waiting until they complete. Worker thread creation is
+  // serialized, can happen on background threads asynchronously, and doesn't
+  // happen any more at shutdown. This means that if a test posts a bunch of
+  // tasks and calls shutdown, fewer workers will be created than the test may
+  // expect.
+  //
+  // This function ensures that this condition can't happen so tests can make
+  // assumptions about the number of workers active. See the comment in
+  // PrepareToStartAdditionalThreadIfNecessary in the .cc file for more
+  // details.
+  //
+  // It will post tasks to the queue with id -1. It also assumes this is the
+  // first thing called in a test since it will clear the complete_sequence_.
+  void EnsureAllWorkersCreated() {
+    // Create a bunch of threads, all waiting. This will cause that may
+    // workers to be created.
+    ThreadBlocker blocker;
+    for (size_t i = 0; i < kNumWorkerThreads; i++) {
+      pool()->PostWorkerTask(FROM_HERE,
+                             base::Bind(&TestTracker::BlockTask,
+                                        tracker(), -1, &blocker));
+    }
+    tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+    // Now wake them up and wait until they're done.
+    blocker.Unblock(kNumWorkerThreads);
+    tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+    // Clean up the task IDs we added.
+    tracker()->ClearCompleteSequence();
+  }
+
+  int has_work_call_count() const {
+    return pool_owner_->has_work_call_count();
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  const scoped_refptr<TestTracker> tracker_;
+};
+
+// Checks that the given number of entries are in the tasks to complete of
+// the given tracker, and then signals the given event the given number of
+// times. This is used to wake up blocked background threads before blocking
+// on shutdown.
+void EnsureTasksToCompleteCountAndUnblock(scoped_refptr<TestTracker> tracker,
+                                          size_t expected_tasks_to_complete,
+                                          ThreadBlocker* blocker,
+                                          size_t threads_to_awake) {
+  EXPECT_EQ(
+      expected_tasks_to_complete,
+      tracker->WaitUntilTasksComplete(expected_tasks_to_complete).size());
+
+  blocker->Unblock(threads_to_awake);
+}
+
+class DeletionHelper : public base::RefCountedThreadSafe<DeletionHelper> {
+ public:
+  explicit DeletionHelper(
+      const scoped_refptr<base::RefCountedData<bool> >& deleted_flag)
+      : deleted_flag_(deleted_flag) {
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<DeletionHelper>;
+  virtual ~DeletionHelper() { deleted_flag_->data = true; }
+
+  const scoped_refptr<base::RefCountedData<bool> > deleted_flag_;
+  DISALLOW_COPY_AND_ASSIGN(DeletionHelper);
+};
+
+void HoldPoolReference(const scoped_refptr<base::SequencedWorkerPool>& pool,
+                       const scoped_refptr<DeletionHelper>& helper) {
+  ADD_FAILURE() << "Should never run";
+}
+
+// Tests that delayed tasks are deleted upon shutdown of the pool.
+TEST_F(SequencedWorkerPoolTest, DelayedTaskDuringShutdown) {
+  // Post something to verify the pool is started up.
+  EXPECT_TRUE(pool()->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 1)));
+
+  scoped_refptr<base::RefCountedData<bool> > deleted_flag(
+      new base::RefCountedData<bool>(false));
+
+  base::Time posted_at(base::Time::Now());
+  // Post something that shouldn't run.
+  EXPECT_TRUE(pool()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&HoldPoolReference,
+                 pool(),
+                 make_scoped_refptr(new DeletionHelper(deleted_flag))),
+      TestTimeouts::action_timeout()));
+
+  std::vector<int> completion_sequence = tracker()->WaitUntilTasksComplete(1);
+  ASSERT_EQ(1u, completion_sequence.size());
+  ASSERT_EQ(1, completion_sequence[0]);
+
+  pool()->Shutdown();
+  // Shutdown is asynchronous, so use ResetPool() to block until the pool is
+  // fully destroyed (and thus shut down).
+  ResetPool();
+
+  // Verify that we didn't block until the task was due.
+  ASSERT_LT(base::Time::Now() - posted_at, TestTimeouts::action_timeout());
+
+  // Verify that the deferred task has not only not run, but has also been
+  // destroyed.
+  ASSERT_TRUE(deleted_flag->data);
+}
+
+// Tests that same-named tokens have the same ID.
+TEST_F(SequencedWorkerPoolTest, NamedTokens) {
+  const std::string name1("hello");
+  SequencedWorkerPool::SequenceToken token1 =
+      pool()->GetNamedSequenceToken(name1);
+
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+
+  const std::string name3("goodbye");
+  SequencedWorkerPool::SequenceToken token3 =
+      pool()->GetNamedSequenceToken(name3);
+
+  // All 3 tokens should be different.
+  EXPECT_FALSE(token1.Equals(token2));
+  EXPECT_FALSE(token1.Equals(token3));
+  EXPECT_FALSE(token2.Equals(token3));
+
+  // Requesting the same name again should give the same value.
+  SequencedWorkerPool::SequenceToken token1again =
+      pool()->GetNamedSequenceToken(name1);
+  EXPECT_TRUE(token1.Equals(token1again));
+
+  SequencedWorkerPool::SequenceToken token3again =
+      pool()->GetNamedSequenceToken(name3);
+  EXPECT_TRUE(token3.Equals(token3again));
+}
+
+// Tests that posting a bunch of tasks (many more than the number of worker
+// threads) runs them all.
+TEST_F(SequencedWorkerPoolTest, LotsOfTasks) {
+  pool()->PostWorkerTask(FROM_HERE,
+                         base::Bind(&TestTracker::SlowTask, tracker(), 0));
+
+  const size_t kNumTasks = 20;
+  for (size_t i = 1; i < kNumTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::FastTask, tracker(), i));
+  }
+
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(kNumTasks);
+  EXPECT_EQ(kNumTasks, result.size());
+}
+
+// Tests that posting a bunch of tasks (many more than the number of
+// worker threads) to two pools simultaneously runs them all twice.
+// This test is meant to shake out any concurrency issues between
+// pools (like histograms).
+TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) {
+  SequencedWorkerPoolOwner pool1(kNumWorkerThreads, "test1");
+  SequencedWorkerPoolOwner pool2(kNumWorkerThreads, "test2");
+
+  base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0);
+  pool1.pool()->PostWorkerTask(FROM_HERE, slow_task);
+  pool2.pool()->PostWorkerTask(FROM_HERE, slow_task);
+
+  const size_t kNumTasks = 20;
+  for (size_t i = 1; i < kNumTasks; i++) {
+    base::Closure fast_task =
+        base::Bind(&TestTracker::FastTask, tracker(), i);
+    pool1.pool()->PostWorkerTask(FROM_HERE, fast_task);
+    pool2.pool()->PostWorkerTask(FROM_HERE, fast_task);
+  }
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(2*kNumTasks);
+  EXPECT_EQ(2 * kNumTasks, result.size());
+
+  pool2.pool()->Shutdown();
+  pool1.pool()->Shutdown();
+}
+
+// Test that tasks with the same sequence token are executed in order but don't
+// affect other tasks.
+TEST_F(SequencedWorkerPoolTest, Sequence) {
+  // Fill all the worker threads except one.
+  const size_t kNumBackgroundTasks = kNumWorkerThreads - 1;
+  ThreadBlocker background_blocker;
+  for (size_t i = 0; i < kNumBackgroundTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &background_blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumBackgroundTasks);
+
+  // Create two tasks with the same sequence token, one that will block on the
+  // event, and one which will just complete quickly when it's run. Since there
+  // is one worker thread free, the first task will start and then block, and
+  // the second task should be waiting.
+  ThreadBlocker blocker;
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&TestTracker::BlockTask, tracker(), 100, &blocker));
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101));
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Create another two tasks as above with a different token. These will be
+  // blocked since there are no slots to run.
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 200));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 201));
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Let one background task complete. This should then let both tasks of
+  // token2 run to completion in order. The second task of token1 should still
+  // be blocked.
+  background_blocker.Unblock(1);
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(3);
+  ASSERT_EQ(3u, result.size());
+  EXPECT_EQ(200, result[1]);
+  EXPECT_EQ(201, result[2]);
+
+  // Finish the rest of the background tasks. This should leave some workers
+  // free with the second token1 task still blocked on the first.
+  background_blocker.Unblock(kNumBackgroundTasks - 1);
+  EXPECT_EQ(kNumBackgroundTasks + 2,
+            tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 2).size());
+
+  // Allow the first task of token1 to complete. This should run the second.
+  blocker.Unblock(1);
+  result = tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 4);
+  ASSERT_EQ(kNumBackgroundTasks + 4, result.size());
+  EXPECT_EQ(100, result[result.size() - 2]);
+  EXPECT_EQ(101, result[result.size() - 1]);
+}
+
+// Tests that any tasks posted after Shutdown are ignored.
+// Disabled for flakiness.  See http://crbug.com/166451.
+TEST_F(SequencedWorkerPoolTest, DISABLED_IgnoresAfterShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+
+  // Shutdown the worker pool. This should discard all non-blocking tasks.
+  const int kMaxNewBlockingTasksAfterShutdown = 100;
+  pool()->Shutdown(kMaxNewBlockingTasksAfterShutdown);
+
+  int old_has_work_call_count = has_work_call_count();
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+  // The kNumWorkerThread items should have completed, in no particular order.
+  ASSERT_EQ(kNumWorkerThreads, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+
+  // No further tasks, regardless of shutdown mode, should be allowed.
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 100),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 102),
+      SequencedWorkerPool::BLOCK_SHUTDOWN));
+
+  ASSERT_EQ(old_has_work_call_count, has_work_call_count());
+}
+
+TEST_F(SequencedWorkerPoolTest, AllowsAfterShutdown) {
+  // Test that <n> new blocking tasks are allowed provided they're posted
+  // by a running tasks.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Start tasks to take all the threads and block them.
+  const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads);
+  for (int i = 0; i < kNumBlockTasks; ++i) {
+    EXPECT_TRUE(pool()->PostWorkerTask(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker)));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Queue up shutdown blocking tasks behind those which will attempt to post
+  // additional tasks when run, PostAdditionalTasks attemtps to post 3
+  // new FastTasks, one for each shutdown_behavior.
+  const int kNumQueuedTasks = static_cast<int>(kNumWorkerThreads);
+  for (int i = 0; i < kNumQueuedTasks; ++i) {
+    EXPECT_TRUE(pool()->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE,
+        base::Bind(&TestTracker::PostAdditionalTasks, tracker(), i, pool(),
+                   false),
+        SequencedWorkerPool::BLOCK_SHUTDOWN));
+  }
+
+  // Setup to open the floodgates from within Shutdown().
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()),
+                 0, &blocker, kNumBlockTasks));
+
+  // Allow half of the additional blocking tasks thru.
+  const int kNumNewBlockingTasksToAllow = kNumWorkerThreads / 2;
+  pool()->Shutdown(kNumNewBlockingTasksToAllow);
+
+  // Ensure that the correct number of tasks actually got run.
+  tracker()->WaitUntilTasksComplete(static_cast<size_t>(
+      kNumBlockTasks + kNumQueuedTasks + kNumNewBlockingTasksToAllow));
+
+  // Clean up the task IDs we added and go home.
+  tracker()->ClearCompleteSequence();
+}
+
+// Tests that blocking tasks can still be posted during shutdown, as long as
+// the task is not being posted within the context of a running task.
+TEST_F(SequencedWorkerPoolTest,
+       AllowsBlockingTasksDuringShutdownOutsideOfRunningTask) {
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Start tasks to take all the threads and block them.
+  const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads);
+  for (int i = 0; i < kNumBlockTasks; ++i) {
+    EXPECT_TRUE(pool()->PostWorkerTask(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker)));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Setup to open the floodgates from within Shutdown().
+  SetWillWaitForShutdownCallback(
+      base::Bind(&TestTracker::PostBlockingTaskThenUnblockThreads,
+                 scoped_refptr<TestTracker>(tracker()), pool(), &blocker,
+                 kNumWorkerThreads));
+  pool()->Shutdown(kNumWorkerThreads + 1);
+
+  // Ensure that the correct number of tasks actually got run.
+  tracker()->WaitUntilTasksComplete(static_cast<size_t>(kNumWorkerThreads + 1));
+  tracker()->ClearCompleteSequence();
+}
+
+// Tests that unrun tasks are discarded properly according to their shutdown
+// mode.
+TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Create some tasks with different shutdown modes.
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 100),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 102),
+      SequencedWorkerPool::BLOCK_SHUTDOWN);
+
+  // Shutdown the worker pool. This should discard all non-blocking tasks.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+  pool()->Shutdown();
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads + 1);
+
+  // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN
+  // one, in no particular order.
+  ASSERT_EQ(kNumWorkerThreads + 1, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+  EXPECT_TRUE(std::find(result.begin(), result.end(), 102) != result.end());
+}
+
+// Tests that CONTINUE_ON_SHUTDOWN tasks don't block shutdown.
+TEST_F(SequencedWorkerPoolTest, ContinueOnShutdown) {
+  scoped_refptr<TaskRunner> runner(pool()->GetTaskRunnerWithShutdownBehavior(
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  scoped_refptr<SequencedTaskRunner> sequenced_runner(
+      pool()->GetSequencedTaskRunnerWithShutdownBehavior(
+          pool()->GetSequenceToken(),
+          SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 0, &blocker),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  runner->PostTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 1, &blocker));
+  sequenced_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 2, &blocker));
+
+  tracker()->WaitUntilTasksBlocked(3);
+
+  // This should not block. If this test hangs, it means it failed.
+  pool()->Shutdown();
+
+  // The task should not have completed yet.
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Posting more tasks should fail.
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EXPECT_FALSE(runner->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0)));
+  EXPECT_FALSE(sequenced_runner->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0)));
+
+  // Continue the background thread and make sure the tasks can complete.
+  blocker.Unblock(3);
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(3);
+  EXPECT_EQ(3u, result.size());
+}
+
+// Tests that SKIP_ON_SHUTDOWN tasks that have been started block Shutdown
+// until they stop, but tasks not yet started do not.
+TEST_F(SequencedWorkerPoolTest, SkipOnShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Now block all the threads with SKIP_ON_SHUTDOWN. Shutdown() should not
+  // return until these tasks have completed.
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker),
+        SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Now post an additional task as SKIP_ON_SHUTDOWN, which should not be
+  // executed once Shutdown() has been called.
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 0, &blocker),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
+  // This callback will only be invoked if SKIP_ON_SHUTDOWN tasks that have
+  // been started block shutdown.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+
+  // No tasks should have completed yet.
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // This should not block. If this test hangs, it means it failed.
+  pool()->Shutdown();
+
+  // Shutdown should not return until all of the tasks have completed.
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+  // Only tasks marked SKIP_ON_SHUTDOWN that were already started should be
+  // allowed to complete. No additional non-blocking tasks should have been
+  // started.
+  ASSERT_EQ(kNumWorkerThreads, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+}
+
+// Ensure all worker threads are created, and then trigger a spurious
+// work signal. This shouldn't cause any other work signals to be
+// triggered. This is a regression test for http://crbug.com/117469.
+TEST_F(SequencedWorkerPoolTest, SpuriousWorkSignal) {
+  EnsureAllWorkersCreated();
+  int old_has_work_call_count = has_work_call_count();
+  pool()->SignalHasWorkForTesting();
+  // This is inherently racy, but can only produce false positives.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_EQ(old_has_work_call_count + 1, has_work_call_count());
+}
+
+void IsRunningOnCurrentThreadTask(
+    SequencedWorkerPool::SequenceToken test_positive_token,
+    SequencedWorkerPool::SequenceToken test_negative_token,
+    SequencedWorkerPool* pool,
+    SequencedWorkerPool* unused_pool) {
+  EXPECT_TRUE(pool->RunsTasksOnCurrentThread());
+  EXPECT_TRUE(pool->IsRunningSequenceOnCurrentThread(test_positive_token));
+  EXPECT_FALSE(pool->IsRunningSequenceOnCurrentThread(test_negative_token));
+  EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(test_positive_token));
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(test_negative_token));
+}
+
+// Verify correctness of the IsRunningSequenceOnCurrentThread method.
+TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken unsequenced_token;
+
+  scoped_refptr<SequencedWorkerPool> unused_pool =
+      new SequencedWorkerPool(2, "unused_pool");
+
+  EXPECT_FALSE(pool()->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token1));
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token2));
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(unsequenced_token));
+  EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token1));
+  EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token2));
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(unsequenced_token));
+
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 token1, token2, pool(), unused_pool));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 token2, unsequenced_token, pool(), unused_pool));
+  pool()->PostWorkerTask(
+      FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 unsequenced_token, token1, pool(), unused_pool));
+  pool()->Shutdown();
+  unused_pool->Shutdown();
+}
+
+// Checks that tasks are destroyed in the right context during shutdown. If a
+// task is destroyed while SequencedWorkerPool's global lock is held,
+// SequencedWorkerPool might deadlock.
+TEST_F(SequencedWorkerPoolTest, AvoidsDeadlockOnShutdown) {
+  for (int i = 0; i < 4; ++i) {
+    scoped_refptr<DestructionDeadlockChecker> checker(
+        new DestructionDeadlockChecker(pool()));
+    tracker()->PostRepostingTask(pool(), checker);
+  }
+
+  // Shutting down the pool should destroy the DestructionDeadlockCheckers,
+  // which in turn should not deadlock in their destructors.
+  pool()->Shutdown();
+}
+
+// Similar to the test AvoidsDeadlockOnShutdown, but there are now also
+// sequenced, blocking tasks in the queue during shutdown.
+TEST_F(SequencedWorkerPoolTest,
+       AvoidsDeadlockOnShutdownWithSequencedBlockingTasks) {
+  const std::string sequence_token_name("name");
+  for (int i = 0; i < 4; ++i) {
+    scoped_refptr<DestructionDeadlockChecker> checker(
+        new DestructionDeadlockChecker(pool()));
+    tracker()->PostRepostingTask(pool(), checker);
+
+    SequencedWorkerPool::SequenceToken token1 =
+        pool()->GetNamedSequenceToken(sequence_token_name);
+    tracker()->PostRepostingBlockingTask(pool(), token1);
+  }
+
+  // Shutting down the pool should destroy the DestructionDeadlockCheckers,
+  // which in turn should not deadlock in their destructors.
+  pool()->Shutdown();
+}
+
+// Verify that FlushForTesting works as intended.
+TEST_F(SequencedWorkerPoolTest, FlushForTesting) {
+  // Should be fine to call on a new instance.
+  pool()->FlushForTesting();
+
+  // Queue up a bunch of work, including  a long delayed task and
+  // a task that produces additional tasks as an artifact.
+  pool()->PostDelayedWorkerTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 0),
+      TimeDelta::FromMinutes(5));
+  pool()->PostWorkerTask(FROM_HERE,
+                         base::Bind(&TestTracker::SlowTask, tracker(), 0));
+  const size_t kNumFastTasks = 20;
+  for (size_t i = 0; i < kNumFastTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::FastTask, tracker(), 0));
+  }
+  pool()->PostWorkerTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::PostAdditionalTasks, tracker(), 0, pool(),
+                 true));
+
+  // We expect all except the delayed task to have been run. We verify all
+  // closures have been deleted by looking at the refcount of the
+  // tracker.
+  EXPECT_FALSE(tracker()->HasOneRef());
+  pool()->FlushForTesting();
+  EXPECT_TRUE(tracker()->HasOneRef());
+  EXPECT_EQ(1 + kNumFastTasks + 1 + 3, tracker()->GetTasksCompletedCount());
+
+  // Should be fine to call on an idle instance with all threads created, and
+  // spamming the method shouldn't deadlock or confuse the class.
+  pool()->FlushForTesting();
+  pool()->FlushForTesting();
+
+  // Should be fine to call after shutdown too.
+  pool()->Shutdown();
+  pool()->FlushForTesting();
+}
+
+TEST(SequencedWorkerPoolRefPtrTest, ShutsDownCleanWithContinueOnShutdown) {
+  MessageLoop loop;
+  scoped_refptr<SequencedWorkerPool> pool(new SequencedWorkerPool(3, "Pool"));
+  scoped_refptr<SequencedTaskRunner> task_runner =
+      pool->GetSequencedTaskRunnerWithShutdownBehavior(
+          pool->GetSequenceToken(),
+          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+
+  // Upon test exit, should shut down without hanging.
+  pool->Shutdown();
+}
+
+class SequencedWorkerPoolTaskRunnerTestDelegate {
+ public:
+  SequencedWorkerPoolTaskRunnerTestDelegate() {}
+
+  ~SequencedWorkerPoolTaskRunnerTestDelegate() {}
+
+  void StartTaskRunner() {
+    pool_owner_.reset(
+        new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
+  }
+
+  scoped_refptr<SequencedWorkerPool> GetTaskRunner() {
+    return pool_owner_->pool();
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks are run before shutting down. Delayed tasks are
+    // not run, they're simply deleted.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPool, TaskRunnerTest,
+    SequencedWorkerPoolTaskRunnerTestDelegate);
+
+class SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate {
+ public:
+  SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate() {}
+
+  ~SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate() {
+  }
+
+  void StartTaskRunner() {
+    pool_owner_.reset(
+        new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
+    task_runner_ = pool_owner_->pool()->GetTaskRunnerWithShutdownBehavior(
+        SequencedWorkerPool::BLOCK_SHUTDOWN);
+  }
+
+  scoped_refptr<TaskRunner> GetTaskRunner() {
+    return task_runner_;
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks are run before shutting down. Delayed tasks are
+    // not run, they're simply deleted.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  scoped_refptr<TaskRunner> task_runner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolTaskRunner, TaskRunnerTest,
+    SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate);
+
+class SequencedWorkerPoolSequencedTaskRunnerTestDelegate {
+ public:
+  SequencedWorkerPoolSequencedTaskRunnerTestDelegate() {}
+
+  ~SequencedWorkerPoolSequencedTaskRunnerTestDelegate() {
+  }
+
+  void StartTaskRunner() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(
+        10, "SequencedWorkerPoolSequencedTaskRunnerTest"));
+    task_runner_ = pool_owner_->pool()->GetSequencedTaskRunner(
+        pool_owner_->pool()->GetSequenceToken());
+  }
+
+  scoped_refptr<SequencedTaskRunner> GetTaskRunner() {
+    return task_runner_;
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks are run before shutting down. Delayed tasks are
+    // not run, they're simply deleted.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  scoped_refptr<SequencedTaskRunner> task_runner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
new file mode 100644
index 0000000..1bc3113
--- /dev/null
+++ b/base/threading/simple_thread.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/simple_thread.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+SimpleThread::SimpleThread(const std::string& name_prefix)
+    : name_prefix_(name_prefix), name_(name_prefix),
+      thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::SimpleThread(const std::string& name_prefix,
+                           const Options& options)
+    : name_prefix_(name_prefix), name_(name_prefix), options_(options),
+      thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::~SimpleThread() {
+  DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
+  DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
+}
+
+void SimpleThread::Start() {
+  DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
+  bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  DCHECK(success);
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  event_.Wait();  // Wait for the thread to complete initialization.
+}
+
+void SimpleThread::Join() {
+  DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread.";
+  DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times.";
+  PlatformThread::Join(thread_);
+  joined_ = true;
+}
+
+bool SimpleThread::HasBeenStarted() {
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  return event_.IsSignaled();
+}
+
+void SimpleThread::ThreadMain() {
+  tid_ = PlatformThread::CurrentId();
+  // Construct our full name of the form "name_prefix_/TID".
+  name_.push_back('/');
+  name_.append(IntToString(tid_));
+  PlatformThread::SetName(name_);
+
+  // We've initialized our new thread, signal that we're done to Start().
+  event_.Signal();
+
+  Run();
+}
+
+DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
+                                           const std::string& name_prefix)
+    : SimpleThread(name_prefix),
+      delegate_(delegate) {
+}
+
+DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
+                                           const std::string& name_prefix,
+                                           const Options& options)
+    : SimpleThread(name_prefix, options),
+      delegate_(delegate) {
+}
+
+DelegateSimpleThread::~DelegateSimpleThread() {
+}
+
+void DelegateSimpleThread::Run() {
+  DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
+  delegate_->Run();
+  delegate_ = NULL;
+}
+
+DelegateSimpleThreadPool::DelegateSimpleThreadPool(
+    const std::string& name_prefix,
+    int num_threads)
+    : name_prefix_(name_prefix),
+      num_threads_(num_threads),
+      dry_(true, false) {
+}
+
+DelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
+  DCHECK(threads_.empty());
+  DCHECK(delegates_.empty());
+  DCHECK(!dry_.IsSignaled());
+}
+
+void DelegateSimpleThreadPool::Start() {
+  DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
+  for (int i = 0; i < num_threads_; ++i) {
+    DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
+    thread->Start();
+    threads_.push_back(thread);
+  }
+}
+
+void DelegateSimpleThreadPool::JoinAll() {
+  DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads.";
+
+  // Tell all our threads to quit their worker loop.
+  AddWork(NULL, num_threads_);
+
+  // Join and destroy all the worker threads.
+  for (int i = 0; i < num_threads_; ++i) {
+    threads_[i]->Join();
+    delete threads_[i];
+  }
+  threads_.clear();
+  DCHECK(delegates_.empty());
+}
+
+void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
+  AutoLock locked(lock_);
+  for (int i = 0; i < repeat_count; ++i)
+    delegates_.push(delegate);
+  // If we were empty, signal that we have work now.
+  if (!dry_.IsSignaled())
+    dry_.Signal();
+}
+
+void DelegateSimpleThreadPool::Run() {
+  Delegate* work = NULL;
+
+  while (true) {
+    dry_.Wait();
+    {
+      AutoLock locked(lock_);
+      if (!dry_.IsSignaled())
+        continue;
+
+      DCHECK(!delegates_.empty());
+      work = delegates_.front();
+      delegates_.pop();
+
+      // Signal to any other threads that we're currently out of work.
+      if (delegates_.empty())
+        dry_.Reset();
+    }
+
+    // A NULL delegate pointer signals us to quit.
+    if (!work)
+      break;
+
+    work->Run();
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
new file mode 100644
index 0000000..ecd3604
--- /dev/null
+++ b/base/threading/simple_thread.h
@@ -0,0 +1,191 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: You should probably be using Thread (thread.h) instead.  Thread is
+//          Chrome's message-loop based Thread abstraction, and if you are a
+//          thread running in the browser, there will likely be assumptions
+//          that your thread will have an associated message loop.
+//
+// This is a simple thread interface that backs to a native operating system
+// thread.  You should use this only when you want a thread that does not have
+// an associated MessageLoop.  Unittesting is the best example of this.
+//
+// The simplest interface to use is DelegateSimpleThread, which will create
+// a new thread, and execute the Delegate's virtual Run() in this new thread
+// until it has completed, exiting the thread.
+//
+// NOTE: You *MUST* call Join on the thread to clean up the underlying thread
+// resources.  You are also responsible for destructing the SimpleThread object.
+// It is invalid to destroy a SimpleThread while it is running, or without
+// Start() having been called (and a thread never created).  The Delegate
+// object should live as long as a DelegateSimpleThread.
+//
+// Thread Safety: A SimpleThread is not completely thread safe.  It is safe to
+// access it from the creating thread or from the newly created thread.  This
+// implies that the creator thread should be the thread that calls Join.
+//
+// Example:
+//   class MyThreadRunner : public DelegateSimpleThread::Delegate { ... };
+//   MyThreadRunner runner;
+//   DelegateSimpleThread thread(&runner, "good_name_here");
+//   thread.Start();
+//   // Start will return after the Thread has been successfully started and
+//   // initialized.  The newly created thread will invoke runner->Run(), and
+//   // run until it returns.
+//   thread.Join();  // Wait until the thread has exited.  You *MUST* Join!
+//   // The SimpleThread object is still valid, however you may not call Join
+//   // or Start again.
+
+#ifndef BASE_THREADING_SIMPLE_THREAD_H_
+#define BASE_THREADING_SIMPLE_THREAD_H_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// This is the base SimpleThread.  You can derive from it and implement the
+// virtual Run method, or you can use the DelegateSimpleThread interface.
+class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
+ public:
+  class BASE_EXPORT Options {
+   public:
+    Options() : stack_size_(0) { }
+    ~Options() { }
+
+    // We use the standard compiler-supplied copy constructor.
+
+    // A custom stack size, or 0 for the system default.
+    void set_stack_size(size_t size) { stack_size_ = size; }
+    size_t stack_size() const { return stack_size_; }
+   private:
+    size_t stack_size_;
+  };
+
+  // Create a SimpleThread.  |options| should be used to manage any specific
+  // configuration involving the thread creation and management.
+  // Every thread has a name, in the form of |name_prefix|/TID, for example
+  // "my_thread/321".  The thread will not be created until Start() is called.
+  explicit SimpleThread(const std::string& name_prefix);
+  SimpleThread(const std::string& name_prefix, const Options& options);
+
+  ~SimpleThread() override;
+
+  virtual void Start();
+  virtual void Join();
+
+  // Subclasses should override the Run method.
+  virtual void Run() = 0;
+
+  // Return the thread name prefix, or "unnamed" if none was supplied.
+  std::string name_prefix() { return name_prefix_; }
+
+  // Return the completed name including TID, only valid after Start().
+  std::string name() { return name_; }
+
+  // Return the thread id, only valid after Start().
+  PlatformThreadId tid() { return tid_; }
+
+  // Return True if Start() has ever been called.
+  bool HasBeenStarted();
+
+  // Return True if Join() has evern been called.
+  bool HasBeenJoined() { return joined_; }
+
+  // Overridden from PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  // Only set priorities with a careful understanding of the consequences.
+  // This is meant for very limited use cases.
+  void SetThreadPriority(ThreadPriority priority) {
+    PlatformThread::SetThreadPriority(thread_, priority);
+  }
+
+ private:
+  const std::string name_prefix_;
+  std::string name_;
+  const Options options_;
+  PlatformThreadHandle thread_;  // PlatformThread handle, invalid after Join!
+  WaitableEvent event_;          // Signaled if Start() was ever called.
+  PlatformThreadId tid_;         // The backing thread's id.
+  bool joined_;                  // True if Join has been called.
+};
+
+class BASE_EXPORT DelegateSimpleThread : public SimpleThread {
+ public:
+  class BASE_EXPORT Delegate {
+   public:
+    Delegate() { }
+    virtual ~Delegate() { }
+    virtual void Run() = 0;
+  };
+
+  DelegateSimpleThread(Delegate* delegate,
+                       const std::string& name_prefix);
+  DelegateSimpleThread(Delegate* delegate,
+                       const std::string& name_prefix,
+                       const Options& options);
+
+  ~DelegateSimpleThread() override;
+  void Run() override;
+
+ private:
+  Delegate* delegate_;
+};
+
+// DelegateSimpleThreadPool allows you to start up a fixed number of threads,
+// and then add jobs which will be dispatched to the threads.  This is
+// convenient when you have a lot of small work that you want done
+// multi-threaded, but don't want to spawn a thread for each small bit of work.
+//
+// You just call AddWork() to add a delegate to the list of work to be done.
+// JoinAll() will make sure that all outstanding work is processed, and wait
+// for everything to finish.  You can reuse a pool, so you can call Start()
+// again after you've called JoinAll().
+class BASE_EXPORT DelegateSimpleThreadPool
+    : public DelegateSimpleThread::Delegate {
+ public:
+  typedef DelegateSimpleThread::Delegate Delegate;
+
+  DelegateSimpleThreadPool(const std::string& name_prefix, int num_threads);
+  ~DelegateSimpleThreadPool() override;
+
+  // Start up all of the underlying threads, and start processing work if we
+  // have any.
+  void Start();
+
+  // Make sure all outstanding work is finished, and wait for and destroy all
+  // of the underlying threads in the pool.
+  void JoinAll();
+
+  // It is safe to AddWork() any time, before or after Start().
+  // Delegate* should always be a valid pointer, NULL is reserved internally.
+  void AddWork(Delegate* work, int repeat_count);
+  void AddWork(Delegate* work) {
+    AddWork(work, 1);
+  }
+
+  // We implement the Delegate interface, for running our internal threads.
+  void Run() override;
+
+ private:
+  const std::string name_prefix_;
+  int num_threads_;
+  std::vector<DelegateSimpleThread*> threads_;
+  std::queue<Delegate*> delegates_;
+  base::Lock lock_;            // Locks delegates_
+  WaitableEvent dry_;    // Not signaled when there is no work to do.
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SIMPLE_THREAD_H_
diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc
new file mode 100644
index 0000000..7229d36
--- /dev/null
+++ b/base/threading/simple_thread_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/atomic_sequence_num.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class SetIntRunner : public DelegateSimpleThread::Delegate {
+ public:
+  SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
+  ~SetIntRunner() override {}
+
+  void Run() override { *ptr_ = val_; }
+
+ private:
+  int* ptr_;
+  int val_;
+};
+
+class WaitEventRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
+  ~WaitEventRunner() override {}
+
+  void Run() override {
+    EXPECT_FALSE(event_->IsSignaled());
+    event_->Signal();
+    EXPECT_TRUE(event_->IsSignaled());
+  }
+ private:
+  WaitableEvent* event_;
+};
+
+class SeqRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
+  void Run() override { seq_->GetNext(); }
+
+ private:
+  AtomicSequenceNumber* seq_;
+};
+
+// We count up on a sequence number, firing on the event when we've hit our
+// expected amount, otherwise we wait on the event.  This will ensure that we
+// have all threads outstanding until we hit our expected thread pool size.
+class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
+ public:
+  VerifyPoolRunner(AtomicSequenceNumber* seq,
+                   int total, WaitableEvent* event)
+      : seq_(seq), total_(total), event_(event) { }
+
+  void Run() override {
+    if (seq_->GetNext() == total_) {
+      event_->Signal();
+    } else {
+      event_->Wait();
+    }
+  }
+
+ private:
+  AtomicSequenceNumber* seq_;
+  int total_;
+  WaitableEvent* event_;
+};
+
+}  // namespace
+
+TEST(SimpleThreadTest, CreateAndJoin) {
+  int stack_int = 0;
+
+  SetIntRunner runner(&stack_int, 7);
+  EXPECT_EQ(0, stack_int);
+
+  DelegateSimpleThread thread(&runner, "int_setter");
+  EXPECT_FALSE(thread.HasBeenStarted());
+  EXPECT_FALSE(thread.HasBeenJoined());
+  EXPECT_EQ(0, stack_int);
+
+  thread.Start();
+  EXPECT_TRUE(thread.HasBeenStarted());
+  EXPECT_FALSE(thread.HasBeenJoined());
+
+  thread.Join();
+  EXPECT_TRUE(thread.HasBeenStarted());
+  EXPECT_TRUE(thread.HasBeenJoined());
+  EXPECT_EQ(7, stack_int);
+}
+
+TEST(SimpleThreadTest, WaitForEvent) {
+  // Create a thread, and wait for it to signal us.
+  WaitableEvent event(true, false);
+
+  WaitEventRunner runner(&event);
+  DelegateSimpleThread thread(&runner, "event_waiter");
+
+  EXPECT_FALSE(event.IsSignaled());
+  thread.Start();
+  event.Wait();
+  EXPECT_TRUE(event.IsSignaled());
+  thread.Join();
+}
+
+TEST(SimpleThreadTest, NamedWithOptions) {
+  WaitableEvent event(true, false);
+
+  WaitEventRunner runner(&event);
+  SimpleThread::Options options;
+  DelegateSimpleThread thread(&runner, "event_waiter", options);
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_FALSE(event.IsSignaled());
+
+  thread.Start();
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_EQ(thread.name(),
+            std::string("event_waiter/") + IntToString(thread.tid()));
+  event.Wait();
+
+  EXPECT_TRUE(event.IsSignaled());
+  thread.Join();
+
+  // We keep the name and tid, even after the thread is gone.
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_EQ(thread.name(),
+            std::string("event_waiter/") + IntToString(thread.tid()));
+}
+
+TEST(SimpleThreadTest, ThreadPool) {
+  AtomicSequenceNumber seq;
+  SeqRunner runner(&seq);
+  DelegateSimpleThreadPool pool("seq_runner", 10);
+
+  // Add work before we're running.
+  pool.AddWork(&runner, 300);
+
+  EXPECT_EQ(seq.GetNext(), 0);
+  pool.Start();
+
+  // Add work while we're running.
+  pool.AddWork(&runner, 300);
+
+  pool.JoinAll();
+
+  EXPECT_EQ(seq.GetNext(), 601);
+
+  // We can reuse our pool.  Verify that all 10 threads can actually run in
+  // parallel, so this test will only pass if there are actually 10 threads.
+  AtomicSequenceNumber seq2;
+  WaitableEvent event(true, false);
+  // Changing 9 to 10, for example, would cause us JoinAll() to never return.
+  VerifyPoolRunner verifier(&seq2, 9, &event);
+  pool.Start();
+
+  pool.AddWork(&verifier, 10);
+
+  pool.JoinAll();
+  EXPECT_EQ(seq2.GetNext(), 10);
+}
+
+}  // namespace base
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
new file mode 100644
index 0000000..0e4aab2
--- /dev/null
+++ b/base/threading/thread.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// We use this thread-local variable to record whether or not a thread exited
+// because its Stop method was called.  This allows us to catch cases where
+// MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
+// using a Thread to setup and run a MessageLoop.
+base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// This is used to trigger the message loop to exit.
+void ThreadQuitHelper() {
+  MessageLoop::current()->QuitWhenIdle();
+  Thread::SetThreadWasQuitProperly(true);
+}
+
+// Used to pass data to ThreadMain.  This structure is allocated on the stack
+// from within StartWithOptions.
+struct Thread::StartupData {
+  // We get away with a const reference here because of how we are allocated.
+  const Thread::Options& options;
+
+  // Used to synchronize thread startup.
+  WaitableEvent event;
+
+  explicit StartupData(const Options& opt)
+      : options(opt),
+        event(false, false) {}
+};
+
+Thread::Options::Options()
+    : message_loop_type(MessageLoop::TYPE_DEFAULT),
+      timer_slack(TIMER_SLACK_NONE),
+      stack_size(0) {
+}
+
+Thread::Options::Options(MessageLoop::Type type,
+                         size_t size)
+    : message_loop_type(type),
+      timer_slack(TIMER_SLACK_NONE),
+      stack_size(size) {
+}
+
+Thread::Options::~Options() {
+}
+
+Thread::Thread(const std::string& name)
+    :
+#if defined(OS_WIN)
+      com_status_(NONE),
+#endif
+      started_(false),
+      stopping_(false),
+      running_(false),
+      startup_data_(NULL),
+      thread_(0),
+      message_loop_(NULL),
+      thread_id_(kInvalidThreadId),
+      name_(name) {
+}
+
+Thread::~Thread() {
+  Stop();
+}
+
+bool Thread::Start() {
+  Options options;
+#if defined(OS_WIN)
+  if (com_status_ == STA)
+    options.message_loop_type = MessageLoop::TYPE_UI;
+#endif
+  return StartWithOptions(options);
+}
+
+bool Thread::StartWithOptions(const Options& options) {
+  DCHECK(!message_loop_);
+#if defined(OS_WIN)
+  DCHECK((com_status_ != STA) ||
+      (options.message_loop_type == MessageLoop::TYPE_UI));
+#endif
+
+  SetThreadWasQuitProperly(false);
+
+  StartupData startup_data(options);
+  startup_data_ = &startup_data;
+
+  if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
+    DLOG(ERROR) << "failed to create thread";
+    startup_data_ = NULL;
+    return false;
+  }
+
+  // TODO(kinuko): Remove once crbug.com/465458 is solved.
+  tracked_objects::ScopedTracker tracking_profile_wait(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "465458 base::Thread::StartWithOptions (Wait)"));
+
+  // Wait for the thread to start and initialize message_loop_
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  startup_data.event.Wait();
+
+  // set it to NULL so we don't keep a pointer to some object on the stack.
+  startup_data_ = NULL;
+  started_ = true;
+
+  DCHECK(message_loop_);
+  return true;
+}
+
+void Thread::Stop() {
+  if (!started_)
+    return;
+
+  StopSoon();
+
+  // Wait for the thread to exit.
+  //
+  // TODO(darin): Unfortunately, we need to keep message_loop_ around until
+  // the thread exits.  Some consumers are abusing the API.  Make them stop.
+  //
+  PlatformThread::Join(thread_);
+
+  // The thread should NULL message_loop_ on exit.
+  DCHECK(!message_loop_);
+
+  // The thread no longer needs to be joined.
+  started_ = false;
+
+  stopping_ = false;
+}
+
+void Thread::StopSoon() {
+  // We should only be called on the same thread that started us.
+
+  // Reading thread_id_ without a lock can lead to a benign data race
+  // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
+  DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
+
+  if (stopping_ || !message_loop_)
+    return;
+
+  stopping_ = true;
+  task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+}
+
+bool Thread::IsRunning() const {
+  return running_;
+}
+
+void Thread::SetPriority(ThreadPriority priority) {
+  // The thread must be started (and id known) for this to be
+  // compatible with all platforms.
+  DCHECK_NE(thread_id_, kInvalidThreadId);
+  PlatformThread::SetThreadPriority(thread_, priority);
+}
+
+void Thread::Run(MessageLoop* message_loop) {
+  message_loop->Run();
+}
+
+void Thread::SetThreadWasQuitProperly(bool flag) {
+  lazy_tls_bool.Pointer()->Set(flag);
+}
+
+bool Thread::GetThreadWasQuitProperly() {
+  bool quit_properly = true;
+#ifndef NDEBUG
+  quit_properly = lazy_tls_bool.Pointer()->Get();
+#endif
+  return quit_properly;
+}
+
+void Thread::ThreadMain() {
+  {
+    // The message loop for this thread.
+    // Allocated on the heap to centralize any leak reports at this line.
+    scoped_ptr<MessageLoop> message_loop;
+    if (!startup_data_->options.message_pump_factory.is_null()) {
+      message_loop.reset(
+          new MessageLoop(startup_data_->options.message_pump_factory.Run()));
+    } else {
+      message_loop.reset(
+          new MessageLoop(startup_data_->options.message_loop_type));
+    }
+
+    // Complete the initialization of our Thread object.
+    thread_id_ = PlatformThread::CurrentId();
+    PlatformThread::SetName(name_);
+    ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
+    message_loop->set_thread_name(name_);
+    message_loop->SetTimerSlack(startup_data_->options.timer_slack);
+    message_loop_ = message_loop.get();
+
+#if defined(OS_WIN)
+    scoped_ptr<win::ScopedCOMInitializer> com_initializer;
+    if (com_status_ != NONE) {
+      com_initializer.reset((com_status_ == STA) ?
+          new win::ScopedCOMInitializer() :
+          new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
+    }
+#endif
+
+    // Let the thread do extra initialization.
+    // Let's do this before signaling we are started.
+    Init();
+
+    running_ = true;
+    startup_data_->event.Signal();
+    // startup_data_ can't be touched anymore since the starting thread is now
+    // unlocked.
+
+    Run(message_loop_);
+    running_ = false;
+
+    // Let the thread do extra cleanup.
+    CleanUp();
+
+#if defined(OS_WIN)
+    com_initializer.reset();
+#endif
+
+    // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
+    DCHECK(GetThreadWasQuitProperly());
+
+    // We can't receive messages anymore.
+    message_loop_ = NULL;
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
new file mode 100644
index 0000000..4915606
--- /dev/null
+++ b/base/threading/thread.h
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_H_
+#define BASE_THREADING_THREAD_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+class MessagePump;
+
+// A simple thread abstraction that establishes a MessageLoop on a new thread.
+// The consumer uses the MessageLoop of the thread to cause code to execute on
+// the thread.  When this object is destroyed the thread is terminated.  All
+// pending tasks queued on the thread's message loop will run to completion
+// before the thread is terminated.
+//
+// WARNING! SUBCLASSES MUST CALL Stop() IN THEIR DESTRUCTORS!  See ~Thread().
+//
+// After the thread is stopped, the destruction sequence is:
+//
+//  (1) Thread::CleanUp()
+//  (2) MessageLoop::~MessageLoop
+//  (3.b)    MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop
+class BASE_EXPORT Thread : PlatformThread::Delegate {
+ public:
+  struct BASE_EXPORT Options {
+    typedef Callback<scoped_ptr<MessagePump>()> MessagePumpFactory;
+
+    Options();
+    Options(MessageLoop::Type type, size_t size);
+    ~Options();
+
+    // Specifies the type of message loop that will be allocated on the thread.
+    // This is ignored if message_pump_factory.is_null() is false.
+    MessageLoop::Type message_loop_type;
+
+    // Specify timer slack for thread message loop.
+    TimerSlack timer_slack;
+
+    // Used to create the MessagePump for the MessageLoop. The callback is Run()
+    // on the thread. If message_pump_factory.is_null(), then a MessagePump
+    // appropriate for |message_loop_type| is created. Setting this forces the
+    // MessageLoop::Type to TYPE_CUSTOM.
+    MessagePumpFactory message_pump_factory;
+
+    // Specifies the maximum stack size that the thread is allowed to use.
+    // This does not necessarily correspond to the thread's initial stack size.
+    // A value of 0 indicates that the default maximum should be used.
+    size_t stack_size;
+  };
+
+  // Constructor.
+  // name is a display string to identify the thread.
+  explicit Thread(const std::string& name);
+
+  // Destroys the thread, stopping it if necessary.
+  //
+  // NOTE: ALL SUBCLASSES OF Thread MUST CALL Stop() IN THEIR DESTRUCTORS (or
+  // guarantee Stop() is explicitly called before the subclass is destroyed).
+  // This is required to avoid a data race between the destructor modifying the
+  // vtable, and the thread's ThreadMain calling the virtual method Run().  It
+  // also ensures that the CleanUp() virtual method is called on the subclass
+  // before it is destructed.
+  ~Thread() override;
+
+#if defined(OS_WIN)
+  // Causes the thread to initialize COM.  This must be called before calling
+  // Start() or StartWithOptions().  If |use_mta| is false, the thread is also
+  // started with a TYPE_UI message loop.  It is an error to call
+  // init_com_with_mta(false) and then StartWithOptions() with any message loop
+  // type other than TYPE_UI.
+  void init_com_with_mta(bool use_mta) {
+    DCHECK(!started_);
+    com_status_ = use_mta ? MTA : STA;
+  }
+#endif
+
+  // Starts the thread.  Returns true if the thread was successfully started;
+  // otherwise, returns false.  Upon successful return, the message_loop()
+  // getter will return non-null.
+  //
+  // Note: This function can't be called on Windows with the loader lock held;
+  // i.e. during a DllMain, global object construction or destruction, atexit()
+  // callback.
+  bool Start();
+
+  // Starts the thread. Behaves exactly like Start in addition to allow to
+  // override the default options.
+  //
+  // Note: This function can't be called on Windows with the loader lock held;
+  // i.e. during a DllMain, global object construction or destruction, atexit()
+  // callback.
+  bool StartWithOptions(const Options& options);
+
+  // Signals the thread to exit and returns once the thread has exited.  After
+  // this method returns, the Thread object is completely reset and may be used
+  // as if it were newly constructed (i.e., Start may be called again).
+  //
+  // Stop may be called multiple times and is simply ignored if the thread is
+  // already stopped.
+  //
+  // NOTE: If you are a consumer of Thread, it is not necessary to call this
+  // before deleting your Thread objects, as the destructor will do it.
+  // IF YOU ARE A SUBCLASS OF Thread, YOU MUST CALL THIS IN YOUR DESTRUCTOR.
+  void Stop();
+
+  // Signals the thread to exit in the near future.
+  //
+  // WARNING: This function is not meant to be commonly used. Use at your own
+  // risk. Calling this function will cause message_loop() to become invalid in
+  // the near future. This function was created to workaround a specific
+  // deadlock on Windows with printer worker thread. In any other case, Stop()
+  // should be used.
+  //
+  // StopSoon should not be called multiple times as it is risky to do so. It
+  // could cause a timing issue in message_loop() access. Call Stop() to reset
+  // the thread object once it is known that the thread has quit.
+  void StopSoon();
+
+  // Returns the message loop for this thread.  Use the MessageLoop's
+  // PostTask methods to execute code on the thread.  This only returns
+  // non-null after a successful call to Start.  After Stop has been called,
+  // this will return NULL.
+  //
+  // NOTE: You must not call this MessageLoop's Quit method directly.  Use
+  // the Thread's Stop method instead.
+  //
+  MessageLoop* message_loop() const { return message_loop_; }
+
+  // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
+  // PostTask methods to execute code on the thread. Returns NULL if the thread
+  // is not running (e.g. before Start or after Stop have been called). Callers
+  // can hold on to this even after the thread is gone; in this situation,
+  // attempts to PostTask() will fail.
+  //
+  // Note: This method is deprecated. Callers should call task_runner() instead
+  // and use the TaskRunner interfaces for safely interfacing with the Thread.
+  scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
+    return message_loop_ ? message_loop_->message_loop_proxy() : NULL;
+  }
+
+  // Returns a TaskRunner for this thread. Use the TaskRunner's PostTask
+  // methods to execute code on the thread. Returns NULL if the thread is not
+  // running (e.g. before Start or after Stop have been called). Callers can
+  // hold on to this even after the thread is gone; in this situation, attempts
+  // to PostTask() will fail.
+  scoped_refptr<SingleThreadTaskRunner> task_runner() const {
+    return message_loop_->task_runner();
+  }
+
+  // Returns the name of this thread (for display in debugger too).
+  const std::string& thread_name() const { return name_; }
+
+  // The native thread handle.
+  PlatformThreadHandle thread_handle() { return thread_; }
+
+  // The thread ID.
+  PlatformThreadId thread_id() const { return thread_id_; }
+
+  // Returns true if the thread has been started, and not yet stopped.
+  bool IsRunning() const;
+
+  // Sets the thread priority. The thread must already be started.
+  void SetPriority(ThreadPriority priority);
+
+ protected:
+  // Called just prior to starting the message loop
+  virtual void Init() {}
+
+  // Called to start the message loop
+  virtual void Run(MessageLoop* message_loop);
+
+  // Called just after the message loop ends
+  virtual void CleanUp() {}
+
+  static void SetThreadWasQuitProperly(bool flag);
+  static bool GetThreadWasQuitProperly();
+
+  void set_message_loop(MessageLoop* message_loop) {
+    message_loop_ = message_loop;
+  }
+
+ private:
+#if defined(OS_WIN)
+  enum ComStatus {
+    NONE,
+    STA,
+    MTA,
+  };
+#endif
+
+  // PlatformThread::Delegate methods:
+  void ThreadMain() override;
+
+#if defined(OS_WIN)
+  // Whether this thread needs to initialize COM, and if so, in what mode.
+  ComStatus com_status_;
+#endif
+
+  // Whether we successfully started the thread.
+  bool started_;
+
+  // If true, we're in the middle of stopping, and shouldn't access
+  // |message_loop_|. It may non-NULL and invalid.
+  bool stopping_;
+
+  // True while inside of Run().
+  bool running_;
+
+  // Used to pass data to ThreadMain.
+  struct StartupData;
+  StartupData* startup_data_;
+
+  // The thread's handle.
+  PlatformThreadHandle thread_;
+
+  // The thread's message loop.  Valid only while the thread is alive.  Set
+  // by the created thread.
+  MessageLoop* message_loop_;
+
+  // Our thread's ID.
+  PlatformThreadId thread_id_;
+
+  // The name of the thread.  Used for debugging purposes.
+  std::string name_;
+
+  friend void ThreadQuitHelper();
+
+  DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_H_
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
new file mode 100644
index 0000000..449247a
--- /dev/null
+++ b/base/threading/thread_checker.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_CHECKER_H_
+#define BASE_THREADING_THREAD_CHECKER_H_
+
+// Apart from debug builds, we also enable the thread checker in
+// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
+// with this define will get the same level of thread checking as
+// debug bots.
+//
+// Note that this does not perfectly match situations where DCHECK is
+// enabled.  For example a non-official release build may have
+// DCHECK_ALWAYS_ON undefined (and therefore ThreadChecker would be
+// disabled) but have DCHECKs enabled at runtime.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class ThreadCheckerDoNothing {
+ public:
+  bool CalledOnValidThread() const WARN_UNUSED_RESULT {
+    return true;
+  }
+
+  void DetachFromThread() {}
+};
+
+// ThreadChecker is a helper class used to help verify that some methods of a
+// class are called from the same thread. It provides identical functionality to
+// base::NonThreadSafe, but it is meant to be held as a member variable, rather
+// than inherited from base::NonThreadSafe.
+//
+// While inheriting from base::NonThreadSafe may give a clear indication about
+// the thread-safety of a class, it may also lead to violations of the style
+// guide with regard to multiple inheritance. The choice between having a
+// ThreadChecker member and inheriting from base::NonThreadSafe should be based
+// on whether:
+//  - Derived classes need to know the thread they belong to, as opposed to
+//    having that functionality fully encapsulated in the base class.
+//  - Derived classes should be able to reassign the base class to another
+//    thread, via DetachFromThread.
+//
+// If neither of these are true, then having a ThreadChecker member and calling
+// CalledOnValidThread is the preferable solution.
+//
+// Example:
+// class MyClass {
+//  public:
+//   void Foo() {
+//     DCHECK(thread_checker_.CalledOnValidThread());
+//     ... (do stuff) ...
+//   }
+//
+//  private:
+//   ThreadChecker thread_checker_;
+// }
+//
+// In Release mode, CalledOnValidThread will always return true.
+#if ENABLE_THREAD_CHECKER
+class ThreadChecker : public ThreadCheckerImpl {
+};
+#else
+class ThreadChecker : public ThreadCheckerDoNothing {
+};
+#endif  // ENABLE_THREAD_CHECKER
+
+#undef ENABLE_THREAD_CHECKER
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_CHECKER_H_
diff --git a/base/threading/thread_checker_impl.cc b/base/threading/thread_checker_impl.cc
new file mode 100644
index 0000000..eb87bae
--- /dev/null
+++ b/base/threading/thread_checker_impl.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+ThreadCheckerImpl::ThreadCheckerImpl()
+    : valid_thread_id_() {
+  EnsureThreadIdAssigned();
+}
+
+ThreadCheckerImpl::~ThreadCheckerImpl() {}
+
+bool ThreadCheckerImpl::CalledOnValidThread() const {
+  EnsureThreadIdAssigned();
+  AutoLock auto_lock(lock_);
+  return valid_thread_id_ == PlatformThread::CurrentRef();
+}
+
+void ThreadCheckerImpl::DetachFromThread() {
+  AutoLock auto_lock(lock_);
+  valid_thread_id_ = PlatformThreadRef();
+}
+
+void ThreadCheckerImpl::EnsureThreadIdAssigned() const {
+  AutoLock auto_lock(lock_);
+  if (valid_thread_id_.is_null()) {
+    valid_thread_id_ = PlatformThread::CurrentRef();
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h
new file mode 100644
index 0000000..c92e143
--- /dev/null
+++ b/base/threading/thread_checker_impl.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_CHECKER_IMPL_H_
+#define BASE_THREADING_THREAD_CHECKER_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// Real implementation of ThreadChecker, for use in debug mode, or
+// for temporary use in release mode (e.g. to CHECK on a threading issue
+// seen only in the wild).
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class BASE_EXPORT ThreadCheckerImpl {
+ public:
+  ThreadCheckerImpl();
+  ~ThreadCheckerImpl();
+
+  bool CalledOnValidThread() const WARN_UNUSED_RESULT;
+
+  // Changes the thread that is checked for in CalledOnValidThread.  This may
+  // be useful when an object may be created on one thread and then used
+  // exclusively on another thread.
+  void DetachFromThread();
+
+ private:
+  void EnsureThreadIdAssigned() const;
+
+  mutable base::Lock lock_;
+  // This is mutable so that CalledOnValidThread can set it.
+  // It's guarded by |lock_|.
+  mutable PlatformThreadRef valid_thread_id_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_CHECKER_IMPL_H_
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
new file mode 100644
index 0000000..d42cbc2
--- /dev/null
+++ b/base/threading/thread_checker_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/threading/thread_checker.h so that we can be
+// good citizens there and undef the macro.
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+namespace base {
+
+namespace {
+
+// Simple class to exercise the basics of ThreadChecker.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class ThreadCheckerClass : public ThreadChecker {
+ public:
+  ThreadCheckerClass() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  void DetachFromThread() {
+    ThreadChecker::DetachFromThread();
+  }
+
+  static void MethodOnDifferentThreadImpl();
+  static void DetachThenCallFromDifferentThreadImpl();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
+};
+
+// Calls ThreadCheckerClass::DoStuff on another thread.
+class CallDoStuffOnThread : public base::SimpleThread {
+ public:
+  explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
+      : SimpleThread("call_do_stuff_on_thread"),
+        thread_checker_class_(thread_checker_class) {
+  }
+
+  void Run() override { thread_checker_class_->DoStuff(); }
+
+ private:
+  ThreadCheckerClass* thread_checker_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes ThreadCheckerClass on a different thread.
+class DeleteThreadCheckerClassOnThread : public base::SimpleThread {
+ public:
+  explicit DeleteThreadCheckerClassOnThread(
+      ThreadCheckerClass* thread_checker_class)
+      : SimpleThread("delete_thread_checker_class_on_thread"),
+        thread_checker_class_(thread_checker_class) {
+  }
+
+  void Run() override { thread_checker_class_.reset(); }
+
+ private:
+  scoped_ptr<ThreadCheckerClass> thread_checker_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
+};
+
+}  // namespace
+
+TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that DoStuff doesn't assert.
+  thread_checker_class->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  thread_checker_class.reset();
+}
+
+TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that the destructor doesn't assert
+  // when called on a different thread.
+  DeleteThreadCheckerClassOnThread delete_on_thread(
+      thread_checker_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+TEST(ThreadCheckerTest, DetachFromThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that DoStuff doesn't assert when called on a different thread after
+  // a call to DetachFromThread.
+  thread_checker_class->DetachFromThread();
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
+
+void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // DoStuff should assert in debug builds only when called on a
+  // different thread.
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if ENABLE_THREAD_CHECKER
+TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      ThreadCheckerClass::MethodOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
+  ThreadCheckerClass::MethodOnDifferentThreadImpl();
+}
+#endif  // ENABLE_THREAD_CHECKER
+
+void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // DoStuff doesn't assert when called on a different thread
+  // after a call to DetachFromThread.
+  thread_checker_class->DetachFromThread();
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+
+  // DoStuff should assert in debug builds only after moving to
+  // another thread.
+  thread_checker_class->DoStuff();
+}
+
+#if ENABLE_THREAD_CHECKER
+TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
+  ASSERT_DEATH({
+    ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
+  ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+}
+#endif  // ENABLE_THREAD_CHECKER
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_THREAD_CHECKER
+
+}  // namespace base
diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc
new file mode 100644
index 0000000..547e11c
--- /dev/null
+++ b/base/threading/thread_collision_warner.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_collision_warner.h"
+
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+void DCheckAsserter::warn() {
+  NOTREACHED() << "Thread Collision";
+}
+
+static subtle::Atomic32 CurrentThread() {
+  const PlatformThreadId current_thread_id = PlatformThread::CurrentId();
+  // We need to get the thread id into an atomic data type. This might be a
+  // truncating conversion, but any loss-of-information just increases the
+  // chance of a fault negative, not a false positive.
+  const subtle::Atomic32 atomic_thread_id =
+      static_cast<subtle::Atomic32>(current_thread_id);
+
+  return atomic_thread_id;
+}
+
+void ThreadCollisionWarner::EnterSelf() {
+  // If the active thread is 0 then I'll write the current thread ID
+  // if two or more threads arrive here only one will succeed to
+  // write on valid_thread_id_ the current thread ID.
+  subtle::Atomic32 current_thread_id = CurrentThread();
+
+  int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+                                                        0,
+                                                        current_thread_id);
+  if (previous_value != 0 && previous_value != current_thread_id) {
+    // gotcha! a thread is trying to use the same class and that is
+    // not current thread.
+    asserter_->warn();
+  }
+
+  subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Enter() {
+  subtle::Atomic32 current_thread_id = CurrentThread();
+
+  if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+                                       0,
+                                       current_thread_id) != 0) {
+    // gotcha! another thread is trying to use the same class.
+    asserter_->warn();
+  }
+
+  subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Leave() {
+  if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) {
+    subtle::NoBarrier_Store(&valid_thread_id_, 0);
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
new file mode 100644
index 0000000..de4e9c3
--- /dev/null
+++ b/base/threading/thread_collision_warner.h
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_
+#define BASE_THREADING_THREAD_COLLISION_WARNER_H_
+
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// A helper class alongside macros to be used to verify assumptions about thread
+// safety of a class.
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+//          are synchronized somehow.
+//
+//          In this case the macro DFAKE_SCOPED_LOCK has to be
+//          used, it checks that if a thread is inside the push/pop then
+//          noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+//  public:
+//   ...
+//   void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
+//   int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+//          are synchronized somehow, it calls a method to "protect" from
+//          a "protected" method
+//
+//          In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
+//          has to be used, it checks that if a thread is inside the push/pop
+//          then noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+//  public:
+//   void push(int) {
+//     DFAKE_SCOPED_LOCK(push_pop_);
+//     ...
+//   }
+//   int pop() {
+//     DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+//     bar();
+//     ...
+//   }
+//   void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation not usable even if clients are synchronized,
+//          so only one thread in the class life cycle can use the two members
+//          push/pop.
+//
+//          In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
+//          specified
+//          critical section the first time a thread enters push or pop, from
+//          that time on only that thread is allowed to execute push or pop.
+//
+// class NonThreadSafeQueue {
+//  public:
+//   ...
+//   void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+//   int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Class that has to be contructed/destroyed on same thread, it has
+//          a "shareable" method (with external synchronization) and a not
+//          shareable method (even with external synchronization).
+//
+//          In this case 3 Critical sections have to be defined
+//
+// class ExoticClass {
+//  public:
+//   ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//   ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//
+//   void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
+//   void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(ctor_dtor_);
+//   DFAKE_MUTEX(shareable_section_);
+// };
+
+
+#if !defined(NDEBUG)
+
+// Defines a class member that acts like a mutex. It is used only as a
+// verification tool.
+#define DFAKE_MUTEX(obj) \
+     mutable base::ThreadCollisionWarner obj
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope.
+#define DFAKE_SCOPED_LOCK(obj) \
+     base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
+     base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
+// Asserts the code is always executed in the same thread.
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
+     base::ThreadCollisionWarner::Check check_##obj(&obj)
+
+#else
+
+#define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj
+#define DFAKE_SCOPED_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
+
+#endif
+
+namespace base {
+
+// The class ThreadCollisionWarner uses an Asserter to notify the collision
+// AsserterBase is the interfaces and DCheckAsserter is the default asserter
+// used. During the unit tests is used another class that doesn't "DCHECK"
+// in case of collision (check thread_collision_warner_unittests.cc)
+struct BASE_EXPORT AsserterBase {
+  virtual ~AsserterBase() {}
+  virtual void warn() = 0;
+};
+
+struct BASE_EXPORT DCheckAsserter : public AsserterBase {
+  ~DCheckAsserter() override {}
+  void warn() override;
+};
+
+class BASE_EXPORT ThreadCollisionWarner {
+ public:
+  // The parameter asserter is there only for test purpose
+  explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
+      : valid_thread_id_(0),
+        counter_(0),
+        asserter_(asserter) {}
+
+  ~ThreadCollisionWarner() {
+    delete asserter_;
+  }
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_LOCK_THREAD_LOCKED
+  // it doesn't leave the critical section, as opposed to ScopedCheck,
+  // because the critical section being pinned is allowed to be used only
+  // from one thread
+  class BASE_EXPORT Check {
+   public:
+    explicit Check(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->EnterSelf();
+    }
+
+    ~Check() {}
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(Check);
+  };
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_LOCK
+  class BASE_EXPORT ScopedCheck {
+   public:
+    explicit ScopedCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->Enter();
+    }
+
+    ~ScopedCheck() {
+      warner_->Leave();
+    }
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+  };
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_RECURSIVE_LOCK
+  class BASE_EXPORT ScopedRecursiveCheck {
+   public:
+    explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->EnterSelf();
+    }
+
+    ~ScopedRecursiveCheck() {
+      warner_->Leave();
+    }
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+  };
+
+ private:
+  // This method stores the current thread identifier and does a DCHECK
+  // if a another thread has already done it, it is safe if same thread
+  // calls this multiple time (recursion allowed).
+  void EnterSelf();
+
+  // Same as EnterSelf but recursion is not allowed.
+  void Enter();
+
+  // Removes the thread_id stored in order to allow other threads to
+  // call EnterSelf or Enter.
+  void Leave();
+
+  // This stores the thread id that is inside the critical section, if the
+  // value is 0 then no thread is inside.
+  volatile subtle::Atomic32 valid_thread_id_;
+
+  // Counter to trace how many time a critical section was "pinned"
+  // (when allowed) in order to unpin it when counter_ reaches 0.
+  volatile subtle::Atomic32 counter_;
+
+  // Here only for class unit tests purpose, during the test I need to not
+  // DCHECK but notify the collision with something else.
+  AsserterBase* asserter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_COLLISION_WARNER_H_
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc
new file mode 100644
index 0000000..d7ce79e
--- /dev/null
+++ b/base/threading/thread_collision_warner_unittest.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_collision_warner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// '' : local class member function does not have a body
+MSVC_PUSH_DISABLE_WARNING(4822)
+
+
+#if defined(NDEBUG)
+
+// Would cause a memory leak otherwise.
+#undef DFAKE_MUTEX
+#define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj
+
+// In Release, we expect the AsserterBase::warn() to not happen.
+#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
+
+#else
+
+// In Debug, we expect the AsserterBase::warn() to happen.
+#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
+
+#endif
+
+
+namespace {
+
+// This is the asserter used with ThreadCollisionWarner instead of the default
+// DCheckAsserter. The method fail_state is used to know if a collision took
+// place.
+class AssertReporter : public base::AsserterBase {
+ public:
+  AssertReporter()
+      : failed_(false) {}
+
+  void warn() override { failed_ = true; }
+
+  ~AssertReporter() override {}
+
+  bool fail_state() const { return failed_; }
+  void reset() { failed_ = false; }
+
+ private:
+  bool failed_;
+};
+
+}  // namespace
+
+TEST(ThreadCollisionTest, BookCriticalSection) {
+  AssertReporter* local_reporter = new AssertReporter();
+
+  base::ThreadCollisionWarner warner(local_reporter);
+  EXPECT_FALSE(local_reporter->fail_state());
+
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+    {  // Pin section.
+      DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
+      EXPECT_FALSE(local_reporter->fail_state());
+    }
+  }
+}
+
+TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) {
+  AssertReporter* local_reporter = new AssertReporter();
+
+  base::ThreadCollisionWarner warner(local_reporter);
+  EXPECT_FALSE(local_reporter->fail_state());
+
+  {  // Pin section.
+    DFAKE_SCOPED_RECURSIVE_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+    {  // Pin section again (allowed by DFAKE_SCOPED_RECURSIVE_LOCK)
+      DFAKE_SCOPED_RECURSIVE_LOCK(warner);
+      EXPECT_FALSE(local_reporter->fail_state());
+    }  // Unpin section.
+  }  // Unpin section.
+
+  // Check that section is not pinned
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+  }  // Unpin section.
+}
+
+TEST(ThreadCollisionTest, ScopedBookCriticalSection) {
+  AssertReporter* local_reporter = new AssertReporter();
+
+  base::ThreadCollisionWarner warner(local_reporter);
+  EXPECT_FALSE(local_reporter->fail_state());
+
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+  }  // Unpin section.
+
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+    {
+      // Pin section again (not allowed by DFAKE_SCOPED_LOCK)
+      DFAKE_SCOPED_LOCK(warner);
+      EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
+      // Reset the status of warner for further tests.
+      local_reporter->reset();
+    }  // Unpin section.
+  }  // Unpin section.
+
+  {
+    // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+  }  // Unpin section.
+}
+
+TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int value) {
+      DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
+    }
+
+    int pop() {
+      DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
+      return 0;
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
+
+    void Run() override {
+      queue_->push(0);
+      queue_->pop();
+    }
+
+   private:
+    NonThreadSafeQueue* queue_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  QueueUser queue_user_a(&queue);
+  QueueUser queue_user_b(&queue);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
+}
+
+TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
+  // Queue with a 5 seconds push execution time, hopefuly the two used threads
+  // in the test will enter the push at same time.
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int value) {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
+    }
+
+    int pop() {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      return 0;
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
+
+    void Run() override {
+      queue_->push(0);
+      queue_->pop();
+    }
+
+   private:
+    NonThreadSafeQueue* queue_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  QueueUser queue_user_a(&queue);
+  QueueUser queue_user_b(&queue);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
+}
+
+TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
+  // Queue with a 2 seconds push execution time, hopefuly the two used threads
+  // in the test will enter the push at same time.
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int value) {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
+    }
+
+    int pop() {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      return 0;
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  // This time the QueueUser class protects the non thread safe queue with
+  // a lock.
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
+        : queue_(queue), lock_(lock) {}
+
+    void Run() override {
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->push(0);
+      }
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->pop();
+      }
+    }
+   private:
+    NonThreadSafeQueue* queue_;
+    base::Lock* lock_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  base::Lock lock;
+
+  QueueUser queue_user_a(&queue, &lock);
+  QueueUser queue_user_b(&queue, &lock);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_FALSE(local_reporter->fail_state());
+}
+
+TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
+  // Queue with a 2 seconds push execution time, hopefuly the two used threads
+  // in the test will enter the push at same time.
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int) {
+      DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+      bar();
+      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
+    }
+
+    int pop() {
+      DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+      return 0;
+    }
+
+    void bar() {
+      DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  // This time the QueueUser class protects the non thread safe queue with
+  // a lock.
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
+        : queue_(queue), lock_(lock) {}
+
+    void Run() override {
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->push(0);
+      }
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->bar();
+      }
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->pop();
+      }
+    }
+   private:
+    NonThreadSafeQueue* queue_;
+    base::Lock* lock_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  base::Lock lock;
+
+  QueueUser queue_user_a(&queue, &lock);
+  QueueUser queue_user_b(&queue, &lock);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_FALSE(local_reporter->fail_state());
+}
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
new file mode 100644
index 0000000..56cfa27
--- /dev/null
+++ b/base/threading/thread_id_name_manager.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_id_name_manager.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace {
+
+static const char kDefaultName[] = "";
+static std::string* g_default_name;
+
+}
+
+ThreadIdNameManager::ThreadIdNameManager()
+    : main_process_name_(NULL),
+      main_process_id_(kInvalidThreadId) {
+  g_default_name = new std::string(kDefaultName);
+
+  AutoLock locked(lock_);
+  name_to_interned_name_[kDefaultName] = g_default_name;
+}
+
+ThreadIdNameManager::~ThreadIdNameManager() {
+}
+
+ThreadIdNameManager* ThreadIdNameManager::GetInstance() {
+  return Singleton<ThreadIdNameManager,
+      LeakySingletonTraits<ThreadIdNameManager> >::get();
+}
+
+const char* ThreadIdNameManager::GetDefaultInternedString() {
+  return g_default_name->c_str();
+}
+
+void ThreadIdNameManager::RegisterThread(PlatformThreadHandle::Handle handle,
+                                         PlatformThreadId id) {
+  AutoLock locked(lock_);
+  thread_id_to_handle_[id] = handle;
+  thread_handle_to_interned_name_[handle] =
+      name_to_interned_name_[kDefaultName];
+}
+
+void ThreadIdNameManager::SetName(PlatformThreadId id,
+                                  const std::string& name) {
+  AutoLock locked(lock_);
+  NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name);
+  std::string* leaked_str = NULL;
+  if (iter != name_to_interned_name_.end()) {
+    leaked_str = iter->second;
+  } else {
+    leaked_str = new std::string(name);
+    name_to_interned_name_[name] = leaked_str;
+  }
+
+  ThreadIdToHandleMap::iterator id_to_handle_iter =
+      thread_id_to_handle_.find(id);
+
+  // The main thread of a process will not be created as a Thread object which
+  // means there is no PlatformThreadHandler registered.
+  if (id_to_handle_iter == thread_id_to_handle_.end()) {
+    main_process_name_ = leaked_str;
+    main_process_id_ = id;
+    return;
+  }
+  thread_handle_to_interned_name_[id_to_handle_iter->second] = leaked_str;
+}
+
+const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
+  AutoLock locked(lock_);
+
+  if (id == main_process_id_)
+    return main_process_name_->c_str();
+
+  ThreadIdToHandleMap::iterator id_to_handle_iter =
+      thread_id_to_handle_.find(id);
+  if (id_to_handle_iter == thread_id_to_handle_.end())
+    return name_to_interned_name_[kDefaultName]->c_str();
+
+  ThreadHandleToInternedNameMap::iterator handle_to_name_iter =
+      thread_handle_to_interned_name_.find(id_to_handle_iter->second);
+  return handle_to_name_iter->second->c_str();
+}
+
+void ThreadIdNameManager::RemoveName(PlatformThreadHandle::Handle handle,
+                                     PlatformThreadId id) {
+  AutoLock locked(lock_);
+  ThreadHandleToInternedNameMap::iterator handle_to_name_iter =
+      thread_handle_to_interned_name_.find(handle);
+
+  DCHECK(handle_to_name_iter != thread_handle_to_interned_name_.end());
+  thread_handle_to_interned_name_.erase(handle_to_name_iter);
+
+  ThreadIdToHandleMap::iterator id_to_handle_iter =
+      thread_id_to_handle_.find(id);
+  DCHECK((id_to_handle_iter!= thread_id_to_handle_.end()));
+  // The given |id| may have been re-used by the system. Make sure the
+  // mapping points to the provided |handle| before removal.
+  if (id_to_handle_iter->second != handle)
+    return;
+
+  thread_id_to_handle_.erase(id_to_handle_iter);
+}
+
+}  // namespace base
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
new file mode 100644
index 0000000..927d25f
--- /dev/null
+++ b/base/threading/thread_id_name_manager.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
+#define BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace base {
+
+class BASE_EXPORT ThreadIdNameManager {
+ public:
+  static ThreadIdNameManager* GetInstance();
+
+  static const char* GetDefaultInternedString();
+
+  // Register the mapping between a thread |id| and |handle|.
+  void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
+
+  // Set the name for the given id.
+  void SetName(PlatformThreadId id, const std::string& name);
+
+  // Get the name for the given id.
+  const char* GetName(PlatformThreadId id);
+
+  // Remove the name for the given id.
+  void RemoveName(PlatformThreadHandle::Handle handle, PlatformThreadId id);
+
+ private:
+  friend struct DefaultSingletonTraits<ThreadIdNameManager>;
+
+  typedef std::map<PlatformThreadId, PlatformThreadHandle::Handle>
+      ThreadIdToHandleMap;
+  typedef std::map<PlatformThreadHandle::Handle, std::string*>
+      ThreadHandleToInternedNameMap;
+  typedef std::map<std::string, std::string*> NameToInternedNameMap;
+
+  ThreadIdNameManager();
+  ~ThreadIdNameManager();
+
+  // lock_ protects the name_to_interned_name_, thread_id_to_handle_ and
+  // thread_handle_to_interned_name_ maps.
+  Lock lock_;
+
+  NameToInternedNameMap name_to_interned_name_;
+  ThreadIdToHandleMap thread_id_to_handle_;
+  ThreadHandleToInternedNameMap thread_handle_to_interned_name_;
+
+  // Treat the main process specially as there is no PlatformThreadHandle.
+  std::string* main_process_name_;
+  PlatformThreadId main_process_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadIdNameManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
new file mode 100644
index 0000000..b5953d5
--- /dev/null
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_id_name_manager.h"
+
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest ThreadIdNameManagerTest;
+
+namespace {
+
+const char kAThread[] = "a thread";
+const char kBThread[] = "b thread";
+
+TEST_F(ThreadIdNameManagerTest, AddThreads) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+  base::Thread thread_b(kBThread);
+
+  thread_a.Start();
+  thread_b.Start();
+
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+  EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id()));
+
+  thread_b.Stop();
+  thread_a.Stop();
+}
+
+TEST_F(ThreadIdNameManagerTest, RemoveThreads) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+
+  thread_a.Start();
+  {
+    base::Thread thread_b(kBThread);
+    thread_b.Start();
+    thread_b.Stop();
+  }
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+
+  thread_a.Stop();
+  EXPECT_STREQ("", manager->GetName(thread_a.thread_id()));
+}
+
+TEST_F(ThreadIdNameManagerTest, RestartThread) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+
+  thread_a.Start();
+  base::PlatformThreadId a_id = thread_a.thread_id();
+  EXPECT_STREQ(kAThread, manager->GetName(a_id));
+  thread_a.Stop();
+
+  thread_a.Start();
+  EXPECT_STREQ("", manager->GetName(a_id));
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+  thread_a.Stop();
+}
+
+TEST_F(ThreadIdNameManagerTest, ThreadNameInterning) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+
+  base::PlatformThreadId a_id = base::PlatformThread::CurrentId();
+  base::PlatformThread::SetName("First Name");
+  std::string version = manager->GetName(a_id);
+
+  base::PlatformThread::SetName("New name");
+  EXPECT_NE(version, manager->GetName(a_id));
+  base::PlatformThread::SetName("");
+}
+
+TEST_F(ThreadIdNameManagerTest, ResettingNameKeepsCorrectInternedValue) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+
+  base::PlatformThreadId a_id = base::PlatformThread::CurrentId();
+  base::PlatformThread::SetName("Test Name");
+  std::string version = manager->GetName(a_id);
+
+  base::PlatformThread::SetName("New name");
+  EXPECT_NE(version, manager->GetName(a_id));
+
+  base::PlatformThread::SetName("Test Name");
+  EXPECT_EQ(version, manager->GetName(a_id));
+
+  base::PlatformThread::SetName("");
+}
+
+}  // namespace
diff --git a/base/threading/thread_local.h b/base/threading/thread_local.h
new file mode 100644
index 0000000..df9c4b7
--- /dev/null
+++ b/base/threading/thread_local.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: Thread local storage is a bit tricky to get right.  Please make
+// sure that this is really the proper solution for what you're trying to
+// achieve.  Don't prematurely optimize, most likely you can just use a Lock.
+//
+// These classes implement a wrapper around the platform's TLS storage
+// mechanism.  On construction, they will allocate a TLS slot, and free the
+// TLS slot on destruction.  No memory management (creation or destruction) is
+// handled.  This means for uses of ThreadLocalPointer, you must correctly
+// manage the memory yourself, these classes will not destroy the pointer for
+// you.  There are no at-thread-exit actions taken by these classes.
+//
+// ThreadLocalPointer<Type> wraps a Type*.  It performs no creation or
+// destruction, so memory management must be handled elsewhere.  The first call
+// to Get() on a thread will return NULL.  You can update the pointer with a
+// call to Set().
+//
+// ThreadLocalBoolean wraps a bool.  It will default to false if it has never
+// been set otherwise with Set().
+//
+// Thread Safety:  An instance of ThreadLocalStorage is completely thread safe
+// once it has been created.  If you want to dynamically create an instance,
+// you must of course properly deal with safety and race conditions.  This
+// means a function-level static initializer is generally inappropiate.
+//
+// In Android, the system TLS is limited, the implementation is backed with
+// ThreadLocalStorage.
+//
+// Example usage:
+//   // My class is logically attached to a single thread.  We cache a pointer
+//   // on the thread it was created on, so we can implement current().
+//   MyClass::MyClass() {
+//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL);
+//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this);
+//   }
+//
+//   MyClass::~MyClass() {
+//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL);
+//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL);
+//   }
+//
+//   // Return the current MyClass associated with the calling thread, can be
+//   // NULL if there isn't a MyClass associated.
+//   MyClass* MyClass::current() {
+//     return Singleton<ThreadLocalPointer<MyClass> >::get()->Get();
+//   }
+
+#ifndef BASE_THREADING_THREAD_LOCAL_H_
+#define BASE_THREADING_THREAD_LOCAL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/threading/thread_local_storage.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+namespace internal {
+
+// Helper functions that abstract the cross-platform APIs.  Do not use directly.
+struct BASE_EXPORT ThreadLocalPlatform {
+#if defined(OS_WIN)
+  typedef unsigned long SlotType;
+#elif defined(OS_ANDROID)
+  typedef ThreadLocalStorage::StaticSlot SlotType;
+#elif defined(OS_POSIX)
+  typedef pthread_key_t SlotType;
+#endif
+
+  static void AllocateSlot(SlotType* slot);
+  static void FreeSlot(SlotType slot);
+  static void* GetValueFromSlot(SlotType slot);
+  static void SetValueInSlot(SlotType slot, void* value);
+};
+
+}  // namespace internal
+
+template <typename Type>
+class ThreadLocalPointer {
+ public:
+  ThreadLocalPointer() : slot_() {
+    internal::ThreadLocalPlatform::AllocateSlot(&slot_);
+  }
+
+  ~ThreadLocalPointer() {
+    internal::ThreadLocalPlatform::FreeSlot(slot_);
+  }
+
+  Type* Get() {
+    return static_cast<Type*>(
+        internal::ThreadLocalPlatform::GetValueFromSlot(slot_));
+  }
+
+  void Set(Type* ptr) {
+    internal::ThreadLocalPlatform::SetValueInSlot(
+        slot_, const_cast<void*>(static_cast<const void*>(ptr)));
+  }
+
+ private:
+  typedef internal::ThreadLocalPlatform::SlotType SlotType;
+
+  SlotType slot_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
+};
+
+class ThreadLocalBoolean {
+ public:
+  ThreadLocalBoolean() {}
+  ~ThreadLocalBoolean() {}
+
+  bool Get() {
+    return tlp_.Get() != NULL;
+  }
+
+  void Set(bool val) {
+    tlp_.Set(val ? this : NULL);
+  }
+
+ private:
+  ThreadLocalPointer<void> tlp_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_LOCAL_H_
diff --git a/base/threading/thread_local_android.cc b/base/threading/thread_local_android.cc
new file mode 100644
index 0000000..813dd78
--- /dev/null
+++ b/base/threading/thread_local_android.cc
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local.h"
+
+namespace base {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  slot->Initialize(nullptr);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  slot.Free();
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return slot.Get();
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  slot.Set(value);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/threading/thread_local_posix.cc b/base/threading/thread_local_posix.cc
new file mode 100644
index 0000000..75ea479
--- /dev/null
+++ b/base/threading/thread_local_posix.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local.h"
+
+#include <pthread.h>
+
+#include "base/logging.h"
+
+#if !defined(OS_ANDROID)
+
+namespace base {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  int error = pthread_key_create(slot, NULL);
+  CHECK_EQ(error, 0);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  int error = pthread_key_delete(slot);
+  DCHECK_EQ(0, error);
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return pthread_getspecific(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  int error = pthread_setspecific(slot, value);
+  DCHECK_EQ(error, 0);
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !defined(OS_ANDROID)
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
new file mode 100644
index 0000000..0bb396c
--- /dev/null
+++ b/base/threading/thread_local_storage.cc
@@ -0,0 +1,249 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+
+using base::internal::PlatformThreadLocalStorage;
+
+namespace {
+// In order to make TLS destructors work, we need to keep around a function
+// pointer to the destructor for each slot. We keep this array of pointers in a
+// global (static) array.
+// We use the single OS-level TLS slot (giving us one pointer per thread) to
+// hold a pointer to a per-thread array (table) of slots that we allocate to
+// Chromium consumers.
+
+// g_native_tls_key is the one native TLS that we use.  It stores our table.
+base::subtle::Atomic32 g_native_tls_key =
+    PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES;
+
+// g_last_used_tls_key is the high-water-mark of allocated thread local storage.
+// Each allocation is an index into our g_tls_destructors[].  Each such index is
+// assigned to the instance variable slot_ in a ThreadLocalStorage::Slot
+// instance.  We reserve the value slot_ == 0 to indicate that the corresponding
+// instance of ThreadLocalStorage::Slot has been freed (i.e., destructor called,
+// etc.).  This reserved use of 0 is then stated as the initial value of
+// g_last_used_tls_key, so that the first issued index will be 1.
+base::subtle::Atomic32 g_last_used_tls_key = 0;
+
+// The maximum number of 'slots' in our thread local storage stack.
+const int kThreadLocalStorageSize = 256;
+
+// The maximum number of times to try to clear slots by calling destructors.
+// Use pthread naming convention for clarity.
+const int kMaxDestructorIterations = kThreadLocalStorageSize;
+
+// An array of destructor function pointers for the slots.  If a slot has a
+// destructor, it will be stored in its corresponding entry in this array.
+// The elements are volatile to ensure that when the compiler reads the value
+// to potentially call the destructor, it does so once, and that value is tested
+// for null-ness and then used. Yes, that would be a weird de-optimization,
+// but I can imagine some register machines where it was just as easy to
+// re-fetch an array element, and I want to be sure a call to free the key
+// (i.e., null out the destructor entry) that happens on a separate thread can't
+// hurt the racy calls to the destructors on another thread.
+volatile base::ThreadLocalStorage::TLSDestructorFunc
+    g_tls_destructors[kThreadLocalStorageSize];
+
+// This function is called to initialize our entire Chromium TLS system.
+// It may be called very early, and we need to complete most all of the setup
+// (initialization) before calling *any* memory allocator functions, which may
+// recursively depend on this initialization.
+// As a result, we use Atomics, and avoid anything (like a singleton) that might
+// require memory allocations.
+void** ConstructTlsVector() {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
+    CHECK(PlatformThreadLocalStorage::AllocTLS(&key));
+
+    // The TLS_KEY_OUT_OF_INDEXES is used to find out whether the key is set or
+    // not in NoBarrier_CompareAndSwap, but Posix doesn't have invalid key, we
+    // define an almost impossible value be it.
+    // If we really get TLS_KEY_OUT_OF_INDEXES as value of key, just alloc
+    // another TLS slot.
+    if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
+      PlatformThreadLocalStorage::TLSKey tmp = key;
+      CHECK(PlatformThreadLocalStorage::AllocTLS(&key) &&
+            key != PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES);
+      PlatformThreadLocalStorage::FreeTLS(tmp);
+    }
+    // Atomically test-and-set the tls_key.  If the key is
+    // TLS_KEY_OUT_OF_INDEXES, go ahead and set it.  Otherwise, do nothing, as
+    // another thread already did our dirty work.
+    if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
+        base::subtle::NoBarrier_CompareAndSwap(&g_native_tls_key,
+            PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key)) {
+      // We've been shortcut. Another thread replaced g_native_tls_key first so
+      // we need to destroy our index and use the one the other thread got
+      // first.
+      PlatformThreadLocalStorage::FreeTLS(key);
+      key = base::subtle::NoBarrier_Load(&g_native_tls_key);
+    }
+  }
+  CHECK(!PlatformThreadLocalStorage::GetTLSValue(key));
+
+  // Some allocators, such as TCMalloc, make use of thread local storage.
+  // As a result, any attempt to call new (or malloc) will lazily cause such a
+  // system to initialize, which will include registering for a TLS key.  If we
+  // are not careful here, then that request to create a key will call new back,
+  // and we'll have an infinite loop.  We avoid that as follows:
+  // Use a stack allocated vector, so that we don't have dependence on our
+  // allocator until our service is in place.  (i.e., don't even call new until
+  // after we're setup)
+  void* stack_allocated_tls_data[kThreadLocalStorageSize];
+  memset(stack_allocated_tls_data, 0, sizeof(stack_allocated_tls_data));
+  // Ensure that any rentrant calls change the temp version.
+  PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data);
+
+  // Allocate an array to store our data.
+  void** tls_data = new void*[kThreadLocalStorageSize];
+  memcpy(tls_data, stack_allocated_tls_data, sizeof(stack_allocated_tls_data));
+  PlatformThreadLocalStorage::SetTLSValue(key, tls_data);
+  return tls_data;
+}
+
+void OnThreadExitInternal(void* value) {
+  DCHECK(value);
+  void** tls_data = static_cast<void**>(value);
+  // Some allocators, such as TCMalloc, use TLS.  As a result, when a thread
+  // terminates, one of the destructor calls we make may be to shut down an
+  // allocator.  We have to be careful that after we've shutdown all of the
+  // known destructors (perchance including an allocator), that we don't call
+  // the allocator and cause it to resurrect itself (with no possibly destructor
+  // call to follow).  We handle this problem as follows:
+  // Switch to using a stack allocated vector, so that we don't have dependence
+  // on our allocator after we have called all g_tls_destructors.  (i.e., don't
+  // even call delete[] after we're done with destructors.)
+  void* stack_allocated_tls_data[kThreadLocalStorageSize];
+  memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data));
+  // Ensure that any re-entrant calls change the temp version.
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data);
+  delete[] tls_data;  // Our last dependence on an allocator.
+
+  int remaining_attempts = kMaxDestructorIterations;
+  bool need_to_scan_destructors = true;
+  while (need_to_scan_destructors) {
+    need_to_scan_destructors = false;
+    // Try to destroy the first-created-slot (which is slot 1) in our last
+    // destructor call.  That user was able to function, and define a slot with
+    // no other services running, so perhaps it is a basic service (like an
+    // allocator) and should also be destroyed last.  If we get the order wrong,
+    // then we'll itterate several more times, so it is really not that
+    // critical (but it might help).
+    base::subtle::Atomic32 last_used_tls_key =
+        base::subtle::NoBarrier_Load(&g_last_used_tls_key);
+    for (int slot = last_used_tls_key; slot > 0; --slot) {
+      void* tls_value = stack_allocated_tls_data[slot];
+      if (tls_value == NULL)
+        continue;
+
+      base::ThreadLocalStorage::TLSDestructorFunc destructor =
+          g_tls_destructors[slot];
+      if (destructor == NULL)
+        continue;
+      stack_allocated_tls_data[slot] = NULL;  // pre-clear the slot.
+      destructor(tls_value);
+      // Any destructor might have called a different service, which then set
+      // a different slot to a non-NULL value.  Hence we need to check
+      // the whole vector again.  This is a pthread standard.
+      need_to_scan_destructors = true;
+    }
+    if (--remaining_attempts <= 0) {
+      NOTREACHED();  // Destructors might not have been called.
+      break;
+    }
+  }
+
+  // Remove our stack allocated vector.
+  PlatformThreadLocalStorage::SetTLSValue(key, NULL);
+}
+
+}  // namespace
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_WIN)
+void PlatformThreadLocalStorage::OnThreadExit() {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
+    return;
+  void *tls_data = GetTLSValue(key);
+  // Maybe we have never initialized TLS for this thread.
+  if (!tls_data)
+    return;
+  OnThreadExitInternal(tls_data);
+}
+#elif defined(OS_POSIX)
+void PlatformThreadLocalStorage::OnThreadExit(void* value) {
+  OnThreadExitInternal(value);
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace internal
+
+ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
+  initialized_ = false;
+  slot_ = 0;
+  Initialize(destructor);
+}
+
+void ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES ||
+      !PlatformThreadLocalStorage::GetTLSValue(key))
+    ConstructTlsVector();
+
+  // Grab a new slot.
+  slot_ = base::subtle::NoBarrier_AtomicIncrement(&g_last_used_tls_key, 1);
+  DCHECK_GT(slot_, 0);
+  CHECK_LT(slot_, kThreadLocalStorageSize);
+
+  // Setup our destructor.
+  g_tls_destructors[slot_] = destructor;
+  initialized_ = true;
+}
+
+void ThreadLocalStorage::StaticSlot::Free() {
+  // At this time, we don't reclaim old indices for TLS slots.
+  // So all we need to do is wipe the destructor.
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  g_tls_destructors[slot_] = NULL;
+  slot_ = 0;
+  initialized_ = false;
+}
+
+void* ThreadLocalStorage::StaticSlot::Get() const {
+  void** tls_data = static_cast<void**>(
+      PlatformThreadLocalStorage::GetTLSValue(
+          base::subtle::NoBarrier_Load(&g_native_tls_key)));
+  if (!tls_data)
+    tls_data = ConstructTlsVector();
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  return tls_data[slot_];
+}
+
+void ThreadLocalStorage::StaticSlot::Set(void* value) {
+  void** tls_data = static_cast<void**>(
+      PlatformThreadLocalStorage::GetTLSValue(
+          base::subtle::NoBarrier_Load(&g_native_tls_key)));
+  if (!tls_data)
+    tls_data = ConstructTlsVector();
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  tls_data[slot_] = value;
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
new file mode 100644
index 0000000..50f8868
--- /dev/null
+++ b/base/threading/thread_local_storage.h
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+
+namespace internal {
+
+// WARNING: You should *NOT* be using this class directly.
+// PlatformThreadLocalStorage is low-level abstraction to the OS's TLS
+// interface, you should instead be using ThreadLocalStorage::StaticSlot/Slot.
+class BASE_EXPORT PlatformThreadLocalStorage {
+ public:
+
+#if defined(OS_WIN)
+  typedef unsigned long TLSKey;
+  enum { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
+#elif defined(OS_POSIX)
+  typedef pthread_key_t TLSKey;
+  // The following is a "reserved key" which is used in our generic Chromium
+  // ThreadLocalStorage implementation.  We expect that an OS will not return
+  // such a key, but if it is returned (i.e., the OS tries to allocate it) we
+  // will just request another key.
+  enum { TLS_KEY_OUT_OF_INDEXES = 0x7FFFFFFF };
+#endif
+
+  // The following methods need to be supported on each OS platform, so that
+  // the Chromium ThreadLocalStore functionality can be constructed.
+  // Chromium will use these methods to acquire a single OS slot, and then use
+  // that to support a much larger number of Chromium slots (independent of the
+  // OS restrictions).
+  // The following returns true if it successfully is able to return an OS
+  // key in |key|.
+  static bool AllocTLS(TLSKey* key);
+  // Note: FreeTLS() doesn't have to be called, it is fine with this leak, OS
+  // might not reuse released slot, you might just reset the TLS value with
+  // SetTLSValue().
+  static void FreeTLS(TLSKey key);
+  static void SetTLSValue(TLSKey key, void* value);
+  static void* GetTLSValue(TLSKey key);
+
+  // Each platform (OS implementation) is required to call this method on each
+  // terminating thread when the thread is about to terminate.  This method
+  // will then call all registered destructors for slots in Chromium
+  // ThreadLocalStorage, until there are no slot values remaining as having
+  // been set on this thread.
+  // Destructors may end up being called multiple times on a terminating
+  // thread, as other destructors may re-set slots that were previously
+  // destroyed.
+#if defined(OS_WIN)
+  // Since Windows which doesn't support TLS destructor, the implementation
+  // should use GetTLSValue() to retrieve the value of TLS slot.
+  static void OnThreadExit();
+#elif defined(OS_POSIX)
+  // |Value| is the data stored in TLS slot, The implementation can't use
+  // GetTLSValue() to retrieve the value of slot as it has already been reset
+  // in Posix.
+  static void OnThreadExit(void* value);
+#endif
+};
+
+}  // namespace internal
+
+// Wrapper for thread local storage.  This class doesn't do much except provide
+// an API for portability.
+class BASE_EXPORT ThreadLocalStorage {
+ public:
+
+  // Prototype for the TLS destructor function, which can be optionally used to
+  // cleanup thread local storage on thread exit.  'value' is the data that is
+  // stored in thread local storage.
+  typedef void (*TLSDestructorFunc)(void* value);
+
+  // StaticSlot uses its own struct initializer-list style static
+  // initialization, as base's LINKER_INITIALIZED requires a constructor and on
+  // some compilers (notably gcc 4.4) this still ends up needing runtime
+  // initialization.
+  #define TLS_INITIALIZER {0}
+
+  // A key representing one value stored in TLS.
+  // Initialize like
+  //   ThreadLocalStorage::StaticSlot my_slot = TLS_INITIALIZER;
+  // If you're not using a static variable, use the convenience class
+  // ThreadLocalStorage::Slot (below) instead.
+  struct BASE_EXPORT StaticSlot {
+    // Set up the TLS slot.  Called by the constructor.
+    // 'destructor' is a pointer to a function to perform per-thread cleanup of
+    // this object.  If set to NULL, no cleanup is done for this TLS slot.
+    void Initialize(TLSDestructorFunc destructor);
+
+    // Free a previously allocated TLS 'slot'.
+    // If a destructor was set for this slot, removes
+    // the destructor so that remaining threads exiting
+    // will not free data.
+    void Free();
+
+    // Get the thread-local value stored in slot 'slot'.
+    // Values are guaranteed to initially be zero.
+    void* Get() const;
+
+    // Set the thread-local value stored in slot 'slot' to
+    // value 'value'.
+    void Set(void* value);
+
+    bool initialized() const { return initialized_; }
+
+    // The internals of this struct should be considered private.
+    bool initialized_;
+    int slot_;
+  };
+
+  // A convenience wrapper around StaticSlot with a constructor. Can be used
+  // as a member variable.
+  class BASE_EXPORT Slot : public StaticSlot {
+   public:
+    // Calls StaticSlot::Initialize().
+    explicit Slot(TLSDestructorFunc destructor = NULL);
+
+   private:
+    using StaticSlot::initialized_;
+    using StaticSlot::slot_;
+
+    DISALLOW_COPY_AND_ASSIGN(Slot);
+  };
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_LOCAL_STORAGE_H_
diff --git a/base/threading/thread_local_storage_posix.cc b/base/threading/thread_local_storage_posix.cc
new file mode 100644
index 0000000..ebaf400
--- /dev/null
+++ b/base/threading/thread_local_storage_posix.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
+  return !pthread_key_create(key,
+      base::internal::PlatformThreadLocalStorage::OnThreadExit);
+}
+
+void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
+  int ret = pthread_key_delete(key);
+  DCHECK_EQ(ret, 0);
+}
+
+void* PlatformThreadLocalStorage::GetTLSValue(TLSKey key) {
+  return pthread_getspecific(key);
+}
+
+void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
+  int ret = pthread_setspecific(key, value);
+  DCHECK_EQ(ret, 0);
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc
new file mode 100644
index 0000000..bcc1d1b
--- /dev/null
+++ b/base/threading/thread_local_storage_unittest.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <process.h>
+#endif
+
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+// Ignore warnings about ptr->int conversions that we use when
+// storing ints into ThreadLocalStorage.
+#pragma warning(disable : 4311 4312)
+#endif
+
+namespace base {
+
+namespace {
+
+const int kInitialTlsValue = 0x5555;
+const int kFinalTlsValue = 0x7777;
+// How many times must a destructor be called before we really are done.
+const int kNumberDestructorCallRepetitions = 3;
+
+static ThreadLocalStorage::StaticSlot tls_slot = TLS_INITIALIZER;
+
+class ThreadLocalStorageRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit ThreadLocalStorageRunner(int* tls_value_ptr)
+      : tls_value_ptr_(tls_value_ptr) {}
+
+  ~ThreadLocalStorageRunner() override {}
+
+  void Run() override {
+    *tls_value_ptr_ = kInitialTlsValue;
+    tls_slot.Set(tls_value_ptr_);
+
+    int *ptr = static_cast<int*>(tls_slot.Get());
+    EXPECT_EQ(ptr, tls_value_ptr_);
+    EXPECT_EQ(*ptr, kInitialTlsValue);
+    *tls_value_ptr_ = 0;
+
+    ptr = static_cast<int*>(tls_slot.Get());
+    EXPECT_EQ(ptr, tls_value_ptr_);
+    EXPECT_EQ(*ptr, 0);
+
+    *ptr = kFinalTlsValue + kNumberDestructorCallRepetitions;
+  }
+
+ private:
+  int* tls_value_ptr_;
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorageRunner);
+};
+
+
+void ThreadLocalStorageCleanup(void *value) {
+  int *ptr = reinterpret_cast<int*>(value);
+  // Destructors should never be called with a NULL.
+  ASSERT_NE(reinterpret_cast<int*>(NULL), ptr);
+  if (*ptr == kFinalTlsValue)
+    return;  // We've been called enough times.
+  ASSERT_LT(kFinalTlsValue, *ptr);
+  ASSERT_GE(kFinalTlsValue + kNumberDestructorCallRepetitions, *ptr);
+  --*ptr;  // Move closer to our target.
+  // Tell tls that we're not done with this thread, and still need destruction.
+  tls_slot.Set(value);
+}
+
+}  // namespace
+
+TEST(ThreadLocalStorageTest, Basics) {
+  ThreadLocalStorage::Slot slot;
+  slot.Set(reinterpret_cast<void*>(123));
+  int value = reinterpret_cast<intptr_t>(slot.Get());
+  EXPECT_EQ(value, 123);
+}
+
+#if defined(THREAD_SANITIZER) || \
+    (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG))
+// Do not run the test under ThreadSanitizer. Because this test iterates its
+// own TSD destructor for the maximum possible number of times, TSan can't jump
+// in after the last destructor invocation, therefore the destructor remains
+// unsynchronized with the following users of the same TSD slot. This results
+// in race reports between the destructor and functions in other tests.
+//
+// It is disabled on Win x64 with incremental linking (i.e. "Debug") pending
+// resolution of http://crbug.com/251251.
+#define MAYBE_TLSDestructors DISABLED_TLSDestructors
+#else
+#define MAYBE_TLSDestructors TLSDestructors
+#endif
+TEST(ThreadLocalStorageTest, MAYBE_TLSDestructors) {
+  // Create a TLS index with a destructor.  Create a set of
+  // threads that set the TLS, while the destructor cleans it up.
+  // After the threads finish, verify that the value is cleaned up.
+  const int kNumThreads = 5;
+  int values[kNumThreads];
+  ThreadLocalStorageRunner* thread_delegates[kNumThreads];
+  DelegateSimpleThread* threads[kNumThreads];
+
+  tls_slot.Initialize(ThreadLocalStorageCleanup);
+
+  // Spawn the threads.
+  for (int index = 0; index < kNumThreads; index++) {
+    values[index] = kInitialTlsValue;
+    thread_delegates[index] = new ThreadLocalStorageRunner(&values[index]);
+    threads[index] = new DelegateSimpleThread(thread_delegates[index],
+                                              "tls thread");
+    threads[index]->Start();
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kNumThreads; index++) {
+    threads[index]->Join();
+    delete threads[index];
+    delete thread_delegates[index];
+
+    // Verify that the destructor was called and that we reset.
+    EXPECT_EQ(values[index], kFinalTlsValue);
+  }
+  tls_slot.Free();  // Stop doing callbacks to cleanup threads.
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage_win.cc b/base/threading/thread_local_storage_win.cc
new file mode 100644
index 0000000..42a7d01
--- /dev/null
+++ b/base/threading/thread_local_storage_win.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
+  TLSKey value = TlsAlloc();
+  if (value != TLS_OUT_OF_INDEXES) {
+    *key = value;
+    return true;
+  }
+  return false;
+}
+
+void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
+  BOOL ret = TlsFree(key);
+  DCHECK(ret);
+}
+
+void* PlatformThreadLocalStorage::GetTLSValue(TLSKey key) {
+  return TlsGetValue(key);
+}
+
+void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
+  BOOL ret = TlsSetValue(key, value);
+  DCHECK(ret);
+}
+
+}  // namespace internal
+
+}  // namespace base
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives.  So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from http://www.codeproject.com/threads/tls.asp
+// and it works for VC++ 7.0 and later.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there.  (e.g. if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_base to prevent whole program
+// optimization from discarding the variable.
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_base")
+
+#else  // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")
+
+#endif  // _WIN64
+
+// Static callback function to call with each thread termination.
+void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+  // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
+  // and on W2K and W2K3. So don't assume it is sent.
+  if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
+    base::internal::PlatformThreadLocalStorage::OnThreadExit();
+}
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// By implicitly loaded, I mean that it is directly referenced by the main EXE
+// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
+// implicitly loaded.
+//
+// See VC\crt\src\tlssup.c for reference.
+
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard p_thread_callback_base.  (We force a reference
+// to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If
+// this variable is discarded, the OnThreadExit function will never be called.
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_base;
+const PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else  // _WIN64
+
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma data_seg()
+
+#endif  // _WIN64
+}  // extern "C"
diff --git a/base/threading/thread_local_unittest.cc b/base/threading/thread_local_unittest.cc
new file mode 100644
index 0000000..e94c1db
--- /dev/null
+++ b/base/threading/thread_local_unittest.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
+ public:
+  typedef base::ThreadLocalPointer<char> TLPType;
+
+  ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
+      : tlp_(tlp),
+        done_(done) {
+  }
+  ~ThreadLocalTesterBase() override {}
+
+ protected:
+  TLPType* tlp_;
+  base::WaitableEvent* done_;
+};
+
+class SetThreadLocal : public ThreadLocalTesterBase {
+ public:
+  SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
+      : ThreadLocalTesterBase(tlp, done),
+        val_(NULL) {
+  }
+  ~SetThreadLocal() override {}
+
+  void set_value(char* val) { val_ = val; }
+
+  void Run() override {
+    DCHECK(!done_->IsSignaled());
+    tlp_->Set(val_);
+    done_->Signal();
+  }
+
+ private:
+  char* val_;
+};
+
+class GetThreadLocal : public ThreadLocalTesterBase {
+ public:
+  GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
+      : ThreadLocalTesterBase(tlp, done),
+        ptr_(NULL) {
+  }
+  ~GetThreadLocal() override {}
+
+  void set_ptr(char** ptr) { ptr_ = ptr; }
+
+  void Run() override {
+    DCHECK(!done_->IsSignaled());
+    *ptr_ = tlp_->Get();
+    done_->Signal();
+  }
+
+ private:
+  char** ptr_;
+};
+
+}  // namespace
+
+// In this test, we start 2 threads which will access a ThreadLocalPointer.  We
+// make sure the default is NULL, and the pointers are unique to the threads.
+TEST(ThreadLocalTest, Pointer) {
+  base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
+  base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
+  tp1.Start();
+  tp2.Start();
+
+  base::ThreadLocalPointer<char> tlp;
+
+  static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
+
+  char* tls_val;
+  base::WaitableEvent done(true, false);
+
+  GetThreadLocal getter(&tlp, &done);
+  getter.set_ptr(&tls_val);
+
+  // Check that both threads defaulted to NULL.
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<char*>(NULL), tls_val);
+
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<char*>(NULL), tls_val);
+
+
+  SetThreadLocal setter(&tlp, &done);
+  setter.set_value(kBogusPointer);
+
+  // Have thread 1 set their pointer value to kBogusPointer.
+  done.Reset();
+  tp1.AddWork(&setter);
+  done.Wait();
+
+  tls_val = NULL;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer, tls_val);
+
+  // Make sure thread 2 is still NULL
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<char*>(NULL), tls_val);
+
+  // Set thread 2 to kBogusPointer + 1.
+  setter.set_value(kBogusPointer + 1);
+
+  done.Reset();
+  tp2.AddWork(&setter);
+  done.Wait();
+
+  tls_val = NULL;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer + 1, tls_val);
+
+  // Make sure thread 1 is still kBogusPointer.
+  tls_val = NULL;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer, tls_val);
+
+  tp1.JoinAll();
+  tp2.JoinAll();
+}
+
+TEST(ThreadLocalTest, Boolean) {
+  {
+    base::ThreadLocalBoolean tlb;
+    EXPECT_FALSE(tlb.Get());
+
+    tlb.Set(false);
+    EXPECT_FALSE(tlb.Get());
+
+    tlb.Set(true);
+    EXPECT_TRUE(tlb.Get());
+  }
+
+  // Our slot should have been freed, we're all reset.
+  {
+    base::ThreadLocalBoolean tlb;
+    EXPECT_FALSE(tlb.Get());
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_win.cc b/base/threading/thread_local_win.cc
new file mode 100644
index 0000000..1c74e42
--- /dev/null
+++ b/base/threading/thread_local_win.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  *slot = TlsAlloc();
+  CHECK_NE(*slot, TLS_OUT_OF_INDEXES);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  if (!TlsFree(slot)) {
+    NOTREACHED() << "Failed to deallocate tls slot with TlsFree().";
+  }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return TlsGetValue(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  if (!TlsSetValue(slot, value)) {
+    LOG(FATAL) << "Failed to TlsSetValue().";
+  }
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
new file mode 100644
index 0000000..3bc9fb4
--- /dev/null
+++ b/base/threading/thread_perftest.cc
@@ -0,0 +1,308 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+
+namespace {
+
+const int kNumRuns = 100000;
+
+// Base class for a threading perf-test. This sets up some threads for the
+// test and measures the clock-time in addition to time spent on each thread.
+class ThreadPerfTest : public testing::Test {
+ public:
+  ThreadPerfTest()
+      : done_(false, false) {
+    // Disable the task profiler as it adds significant cost!
+    CommandLine::Init(0, NULL);
+    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kProfilerTiming,
+        switches::kProfilerTimingDisabledValue);
+  }
+
+  // To be implemented by each test. Subclass must uses threads_ such that
+  // their cpu-time can be measured. Test must return from PingPong() _and_
+  // call FinishMeasurement from any thread to complete the test.
+  virtual void Init() {}
+  virtual void PingPong(int hops) = 0;
+  virtual void Reset() {}
+
+  void TimeOnThread(base::TimeTicks* ticks, base::WaitableEvent* done) {
+    *ticks = base::TimeTicks::ThreadNow();
+    done->Signal();
+  }
+
+  base::TimeTicks ThreadNow(base::Thread* thread) {
+    base::WaitableEvent done(false, false);
+    base::TimeTicks ticks;
+    thread->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadPerfTest::TimeOnThread,
+                              base::Unretained(this), &ticks, &done));
+    done.Wait();
+    return ticks;
+  }
+
+  void RunPingPongTest(const std::string& name, unsigned num_threads) {
+    // Create threads and collect starting cpu-time for each thread.
+    std::vector<base::TimeTicks> thread_starts;
+    while (threads_.size() < num_threads) {
+      threads_.push_back(new base::Thread("PingPonger"));
+      threads_.back()->Start();
+      if (base::TimeTicks::IsThreadNowSupported())
+        thread_starts.push_back(ThreadNow(threads_.back()));
+    }
+
+    Init();
+
+    base::TimeTicks start = base::TimeTicks::Now();
+    PingPong(kNumRuns);
+    done_.Wait();
+    base::TimeTicks end = base::TimeTicks::Now();
+
+    // Gather the cpu-time spent on each thread. This does one extra tasks,
+    // but that should be in the noise given enough runs.
+    base::TimeDelta thread_time;
+    while (threads_.size()) {
+      if (base::TimeTicks::IsThreadNowSupported()) {
+        thread_time += ThreadNow(threads_.back()) - thread_starts.back();
+        thread_starts.pop_back();
+      }
+      threads_.pop_back();
+    }
+
+    Reset();
+
+    double num_runs = static_cast<double>(kNumRuns);
+    double us_per_task_clock = (end - start).InMicroseconds() / num_runs;
+    double us_per_task_cpu = thread_time.InMicroseconds() / num_runs;
+
+    // Clock time per task.
+    perf_test::PrintResult(
+        "task", "", name + "_time ", us_per_task_clock, "us/hop", true);
+
+    // Total utilization across threads if available (likely higher).
+    if (base::TimeTicks::IsThreadNowSupported()) {
+      perf_test::PrintResult(
+          "task", "", name + "_cpu ", us_per_task_cpu, "us/hop", true);
+    }
+  }
+
+ protected:
+  void FinishMeasurement() { done_.Signal(); }
+  ScopedVector<base::Thread> threads_;
+
+ private:
+  base::WaitableEvent done_;
+};
+
+// Class to test task performance by posting empty tasks back and forth.
+class TaskPerfTest : public ThreadPerfTest {
+  base::Thread* NextThread(int count) {
+    return threads_[count % threads_.size()];
+  }
+
+  void PingPong(int hops) override {
+    if (!hops) {
+      FinishMeasurement();
+      return;
+    }
+    NextThread(hops)->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadPerfTest::PingPong, base::Unretained(this),
+                              hops - 1));
+  }
+};
+
+// This tries to test the 'best-case' as well as the 'worst-case' task posting
+// performance. The best-case keeps one thread alive such that it never yeilds,
+// while the worse-case forces a context switch for every task. Four threads are
+// used to ensure the threads do yeild (with just two it might be possible for
+// both threads to stay awake if they can signal each other fast enough).
+TEST_F(TaskPerfTest, TaskPingPong) {
+  RunPingPongTest("1_Task_Threads", 1);
+  RunPingPongTest("4_Task_Threads", 4);
+}
+
+
+// Same as above, but add observers to test their perf impact.
+class MessageLoopObserver : public base::MessageLoop::TaskObserver {
+ public:
+  void WillProcessTask(const base::PendingTask& pending_task) override {}
+  void DidProcessTask(const base::PendingTask& pending_task) override {}
+};
+MessageLoopObserver message_loop_observer;
+
+class TaskObserverPerfTest : public TaskPerfTest {
+ public:
+  void Init() override {
+    TaskPerfTest::Init();
+    for (size_t i = 0; i < threads_.size(); i++) {
+      threads_[i]->message_loop()->AddTaskObserver(&message_loop_observer);
+    }
+  }
+};
+
+TEST_F(TaskObserverPerfTest, TaskPingPong) {
+  RunPingPongTest("1_Task_Threads_With_Observer", 1);
+  RunPingPongTest("4_Task_Threads_With_Observer", 4);
+}
+
+// Class to test our WaitableEvent performance by signaling back and fort.
+// WaitableEvent is templated so we can also compare with other versions.
+template <typename WaitableEventType>
+class EventPerfTest : public ThreadPerfTest {
+ public:
+  void Init() override {
+    for (size_t i = 0; i < threads_.size(); i++)
+      events_.push_back(new WaitableEventType(false, false));
+  }
+
+  void Reset() override { events_.clear(); }
+
+  void WaitAndSignalOnThread(size_t event) {
+    size_t next_event = (event + 1) % events_.size();
+    int my_hops = 0;
+    do {
+      events_[event]->Wait();
+      my_hops = --remaining_hops_;  // We own 'hops' between Wait and Signal.
+      events_[next_event]->Signal();
+    } while (my_hops > 0);
+    // Once we are done, all threads will signal as hops passes zero.
+    // We only signal completion once, on the thread that reaches zero.
+    if (!my_hops)
+      FinishMeasurement();
+  }
+
+  void PingPong(int hops) override {
+    remaining_hops_ = hops;
+    for (size_t i = 0; i < threads_.size(); i++) {
+      threads_[i]->task_runner()->PostTask(
+          FROM_HERE, base::Bind(&EventPerfTest::WaitAndSignalOnThread,
+                                base::Unretained(this), i));
+    }
+
+    // Kick off the Signal ping-ponging.
+    events_.front()->Signal();
+  }
+
+  int remaining_hops_;
+  ScopedVector<WaitableEventType> events_;
+};
+
+// Similar to the task posting test, this just tests similar functionality
+// using WaitableEvents. We only test four threads (worst-case), but we
+// might want to craft a way to test the best-case (where the thread doesn't
+// end up blocking because the event is already signalled).
+typedef EventPerfTest<base::WaitableEvent> WaitableEventPerfTest;
+TEST_F(WaitableEventPerfTest, EventPingPong) {
+  RunPingPongTest("4_WaitableEvent_Threads", 4);
+}
+
+// Build a minimal event using ConditionVariable.
+class ConditionVariableEvent {
+ public:
+  ConditionVariableEvent(bool manual_reset, bool initially_signaled)
+      : cond_(&lock_), signaled_(false) {
+    DCHECK(!manual_reset);
+    DCHECK(!initially_signaled);
+  }
+
+  void Signal() {
+    {
+      base::AutoLock scoped_lock(lock_);
+      signaled_ = true;
+    }
+    cond_.Signal();
+  }
+
+  void Wait() {
+    base::AutoLock scoped_lock(lock_);
+    while (!signaled_)
+      cond_.Wait();
+    signaled_ = false;
+  }
+
+ private:
+  base::Lock lock_;
+  base::ConditionVariable cond_;
+  bool signaled_;
+};
+
+// This is meant to test the absolute minimal context switching time
+// using our own base synchronization code.
+typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest;
+TEST_F(ConditionVariablePerfTest, EventPingPong) {
+  RunPingPongTest("4_ConditionVariable_Threads", 4);
+}
+#if defined(OS_POSIX)
+
+// Absolutely 100% minimal posix waitable event. If there is a better/faster
+// way to force a context switch, we should use that instead.
+class PthreadEvent {
+ public:
+  PthreadEvent(bool manual_reset, bool initially_signaled) {
+    DCHECK(!manual_reset);
+    DCHECK(!initially_signaled);
+    pthread_mutex_init(&mutex_, 0);
+    pthread_cond_init(&cond_, 0);
+    signaled_ = false;
+  }
+
+  ~PthreadEvent() {
+    pthread_cond_destroy(&cond_);
+    pthread_mutex_destroy(&mutex_);
+  }
+
+  void Signal() {
+    pthread_mutex_lock(&mutex_);
+    signaled_ = true;
+    pthread_mutex_unlock(&mutex_);
+    pthread_cond_signal(&cond_);
+  }
+
+  void Wait() {
+    pthread_mutex_lock(&mutex_);
+    while (!signaled_)
+      pthread_cond_wait(&cond_, &mutex_);
+    signaled_ = false;
+    pthread_mutex_unlock(&mutex_);
+  }
+
+ private:
+  bool signaled_;
+  pthread_mutex_t mutex_;
+  pthread_cond_t cond_;
+};
+
+// This is meant to test the absolute minimal context switching time.
+// If there is any faster way to do this we should substitute it in.
+typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest;
+TEST_F(PthreadEventPerfTest, EventPingPong) {
+  RunPingPongTest("4_PthreadCondVar_Threads", 4);
+}
+
+#endif
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
new file mode 100644
index 0000000..871f2dc
--- /dev/null
+++ b/base/threading/thread_restrictions.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_restrictions.h"
+
+#if ENABLE_THREAD_RESTRICTIONS
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_io_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_wait_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+}  // anonymous namespace
+
+// static
+bool ThreadRestrictions::SetIOAllowed(bool allowed) {
+  bool previous_disallowed = g_io_disallowed.Get().Get();
+  g_io_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertIOAllowed() {
+  if (g_io_disallowed.Get().Get()) {
+    LOG(FATAL) <<
+        "Function marked as IO-only was called from a thread that "
+        "disallows IO!  If this thread really should be allowed to "
+        "make IO calls, adjust the call to "
+        "base::ThreadRestrictions::SetIOAllowed() in this thread's "
+        "startup.";
+  }
+}
+
+// static
+bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
+  bool previous_disallowed = g_singleton_disallowed.Get().Get();
+  g_singleton_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertSingletonAllowed() {
+  if (g_singleton_disallowed.Get().Get()) {
+    LOG(FATAL) << "LazyInstance/Singleton is not allowed to be used on this "
+               << "thread.  Most likely it's because this thread is not "
+               << "joinable, so AtExitManager may have deleted the object "
+               << "on shutdown, leading to a potential shutdown crash.";
+  }
+}
+
+// static
+void ThreadRestrictions::DisallowWaiting() {
+  g_wait_disallowed.Get().Set(true);
+}
+
+// static
+void ThreadRestrictions::AssertWaitAllowed() {
+  if (g_wait_disallowed.Get().Get()) {
+    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent"
+               << "jank and deadlock.";
+  }
+}
+
+bool ThreadRestrictions::SetWaitAllowed(bool allowed) {
+  bool previous_disallowed = g_wait_disallowed.Get().Get();
+  g_wait_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+}  // namespace base
+
+#endif  // ENABLE_THREAD_RESTRICTIONS
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
new file mode 100644
index 0000000..54f50eb
--- /dev/null
+++ b/base/threading/thread_restrictions.h
@@ -0,0 +1,240 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
+#define BASE_THREADING_THREAD_RESTRICTIONS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// See comment at top of thread_checker.h
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_THREAD_RESTRICTIONS 1
+#else
+#define ENABLE_THREAD_RESTRICTIONS 0
+#endif
+
+class BrowserProcessImpl;
+class HistogramSynchronizer;
+class NativeBackendKWallet;
+class ScopedAllowWaitForLegacyWebViewApi;
+
+namespace cc {
+class CompletionEvent;
+class TaskGraphRunner;
+}
+namespace chromeos {
+class BlockingMethodCaller;
+namespace system {
+class StatisticsProviderImpl;
+}
+}
+namespace chrome_browser_net {
+class Predictor;
+}
+namespace content {
+class BrowserGpuChannelHostFactory;
+class BrowserGpuMemoryBufferManager;
+class BrowserShutdownProfileDumper;
+class BrowserTestBase;
+class GpuChannelHost;
+class NestedMessagePumpAndroid;
+class RenderWidgetResizeHelper;
+class ScopedAllowWaitForAndroidLayoutTests;
+class ScopedAllowWaitForDebugURL;
+class TextInputClientMac;
+}  // namespace content
+namespace dbus {
+class Bus;
+}
+namespace disk_cache {
+class BackendImpl;
+class InFlightIO;
+}
+namespace mojo {
+namespace common {
+class WatcherThreadManager;
+}
+}
+namespace net {
+namespace internal {
+class AddressTrackerLinux;
+}
+}
+
+namespace remoting {
+class AutoThread;
+}
+
+namespace base {
+
+namespace android {
+class JavaHandlerThread;
+}
+
+class SequencedWorkerPool;
+class SimpleThread;
+class Thread;
+class ThreadTestHelper;
+
+// Certain behavior is disallowed on certain threads.  ThreadRestrictions helps
+// enforce these rules.  Examples of such rules:
+//
+// * Do not do blocking IO (makes the thread janky)
+// * Do not access Singleton/LazyInstance (may lead to shutdown crashes)
+//
+// Here's more about how the protection works:
+//
+// 1) If a thread should not be allowed to make IO calls, mark it:
+//      base::ThreadRestrictions::SetIOAllowed(false);
+//    By default, threads *are* allowed to make IO calls.
+//    In Chrome browser code, IO calls should be proxied to the File thread.
+//
+// 2) If a function makes a call that will go out to disk, check whether the
+//    current thread is allowed:
+//      base::ThreadRestrictions::AssertIOAllowed();
+//
+//
+// Style tip: where should you put AssertIOAllowed checks?  It's best
+// if you put them as close to the disk access as possible, at the
+// lowest level.  This rule is simple to follow and helps catch all
+// callers.  For example, if your function GoDoSomeBlockingDiskCall()
+// only calls other functions in Chrome and not fopen(), you should go
+// add the AssertIOAllowed checks in the helper functions.
+
+class BASE_EXPORT ThreadRestrictions {
+ public:
+  // Constructing a ScopedAllowIO temporarily allows IO for the current
+  // thread.  Doing this is almost certainly always incorrect.
+  class BASE_EXPORT ScopedAllowIO {
+   public:
+    ScopedAllowIO() { previous_value_ = SetIOAllowed(true); }
+    ~ScopedAllowIO() { SetIOAllowed(previous_value_); }
+   private:
+    // Whether IO is allowed when the ScopedAllowIO was constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
+  };
+
+  // Constructing a ScopedAllowSingleton temporarily allows accessing for the
+  // current thread.  Doing this is almost always incorrect.
+  class BASE_EXPORT ScopedAllowSingleton {
+   public:
+    ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); }
+    ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); }
+   private:
+    // Whether singleton use is allowed when the ScopedAllowSingleton was
+    // constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton);
+  };
+
+#if ENABLE_THREAD_RESTRICTIONS
+  // Set whether the current thread to make IO calls.
+  // Threads start out in the *allowed* state.
+  // Returns the previous value.
+  static bool SetIOAllowed(bool allowed);
+
+  // Check whether the current thread is allowed to make IO calls,
+  // and DCHECK if not.  See the block comment above the class for
+  // a discussion of where to add these checks.
+  static void AssertIOAllowed();
+
+  // Set whether the current thread can use singletons.  Returns the previous
+  // value.
+  static bool SetSingletonAllowed(bool allowed);
+
+  // Check whether the current thread is allowed to use singletons (Singleton /
+  // LazyInstance).  DCHECKs if not.
+  static void AssertSingletonAllowed();
+
+  // Disable waiting on the current thread. Threads start out in the *allowed*
+  // state. Returns the previous value.
+  static void DisallowWaiting();
+
+  // Check whether the current thread is allowed to wait, and DCHECK if not.
+  static void AssertWaitAllowed();
+#else
+  // Inline the empty definitions of these functions so that they can be
+  // compiled out.
+  static bool SetIOAllowed(bool allowed) { return true; }
+  static void AssertIOAllowed() {}
+  static bool SetSingletonAllowed(bool allowed) { return true; }
+  static void AssertSingletonAllowed() {}
+  static void DisallowWaiting() {}
+  static void AssertWaitAllowed() {}
+#endif
+
+ private:
+  // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first.
+  // BEGIN ALLOWED USAGE.
+  friend class content::BrowserShutdownProfileDumper;
+  friend class content::BrowserTestBase;
+  friend class content::NestedMessagePumpAndroid;
+  friend class content::RenderWidgetResizeHelper;
+  friend class content::ScopedAllowWaitForAndroidLayoutTests;
+  friend class content::ScopedAllowWaitForDebugURL;
+  friend class ::HistogramSynchronizer;
+  friend class ::ScopedAllowWaitForLegacyWebViewApi;
+  friend class cc::CompletionEvent;
+  friend class cc::TaskGraphRunner;
+  friend class mojo::common::WatcherThreadManager;
+  friend class remoting::AutoThread;
+  friend class MessagePumpDefault;
+  friend class SequencedWorkerPool;
+  friend class SimpleThread;
+  friend class Thread;
+  friend class ThreadTestHelper;
+  friend class PlatformThread;
+  friend class android::JavaHandlerThread;
+
+  // END ALLOWED USAGE.
+  // BEGIN USAGE THAT NEEDS TO BE FIXED.
+  friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
+  friend class ::chromeos::system::StatisticsProviderImpl;  // http://crbug.com/125385
+  friend class chrome_browser_net::Predictor;     // http://crbug.com/78451
+  friend class
+      content::BrowserGpuChannelHostFactory;      // http://crbug.com/125248
+  friend class
+      content::BrowserGpuMemoryBufferManager;     // http://crbug.com/420368
+  friend class content::GpuChannelHost;           // http://crbug.com/125264
+  friend class content::TextInputClientMac;       // http://crbug.com/121917
+  friend class dbus::Bus;                         // http://crbug.com/125222
+  friend class disk_cache::BackendImpl;           // http://crbug.com/74623
+  friend class disk_cache::InFlightIO;            // http://crbug.com/74623
+  friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
+  friend class ::BrowserProcessImpl;              // http://crbug.com/125207
+  friend class ::NativeBackendKWallet;            // http://crbug.com/125331
+  // END USAGE THAT NEEDS TO BE FIXED.
+
+#if ENABLE_THREAD_RESTRICTIONS
+  static bool SetWaitAllowed(bool allowed);
+#else
+  static bool SetWaitAllowed(bool allowed) { return true; }
+#endif
+
+  // Constructing a ScopedAllowWait temporarily allows waiting on the current
+  // thread.  Doing this is almost always incorrect, which is why we limit who
+  // can use this through friend. If you find yourself needing to use this, find
+  // another way. Talk to jam or brettw.
+  class BASE_EXPORT ScopedAllowWait {
+   public:
+    ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); }
+    ~ScopedAllowWait() { SetWaitAllowed(previous_value_); }
+   private:
+    // Whether singleton use is allowed when the ScopedAllowWait was
+    // constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait);
+  };
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
new file mode 100644
index 0000000..a89768e
--- /dev/null
+++ b/base/threading/thread_unittest.cc
@@ -0,0 +1,235 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using base::Thread;
+
+typedef PlatformTest ThreadTest;
+
+namespace {
+
+void ToggleValue(bool* value) {
+  ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean "
+                       "in base/thread_unittest");
+  *value = !*value;
+}
+
+class SleepInsideInitThread : public Thread {
+ public:
+  SleepInsideInitThread() : Thread("none") {
+    init_called_ = false;
+    ANNOTATE_BENIGN_RACE(
+        this, "Benign test-only data race on vptr - http://crbug.com/98219");
+  }
+  ~SleepInsideInitThread() override { Stop(); }
+
+  void Init() override {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
+    init_called_ = true;
+  }
+  bool InitCalled() { return init_called_; }
+ private:
+  bool init_called_;
+};
+
+enum ThreadEvent {
+  // Thread::Init() was called.
+  THREAD_EVENT_INIT = 0,
+
+  // The MessageLoop for the thread was deleted.
+  THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
+
+  // Thread::CleanUp() was called.
+  THREAD_EVENT_CLEANUP,
+
+  // Keep at end of list.
+  THREAD_NUM_EVENTS
+};
+
+typedef std::vector<ThreadEvent> EventList;
+
+class CaptureToEventList : public Thread {
+ public:
+  // This Thread pushes events into the vector |event_list| to show
+  // the order they occured in. |event_list| must remain valid for the
+  // lifetime of this thread.
+  explicit CaptureToEventList(EventList* event_list)
+      : Thread("none"),
+        event_list_(event_list) {
+  }
+
+  ~CaptureToEventList() override { Stop(); }
+
+  void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
+
+  void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); }
+
+ private:
+  EventList* event_list_;
+};
+
+// Observer that writes a value into |event_list| when a message loop has been
+// destroyed.
+class CapturingDestructionObserver
+    : public base::MessageLoop::DestructionObserver {
+ public:
+  // |event_list| must remain valid throughout the observer's lifetime.
+  explicit CapturingDestructionObserver(EventList* event_list)
+      : event_list_(event_list) {
+  }
+
+  // DestructionObserver implementation:
+  void WillDestroyCurrentMessageLoop() override {
+    event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
+    event_list_ = NULL;
+  }
+
+ private:
+  EventList* event_list_;
+};
+
+// Task that adds a destruction observer to the current message loop.
+void RegisterDestructionObserver(
+    base::MessageLoop::DestructionObserver* observer) {
+  base::MessageLoop::current()->AddDestructionObserver(observer);
+}
+
+}  // namespace
+
+TEST_F(ThreadTest, Restart) {
+  Thread a("Restart");
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+}
+
+TEST_F(ThreadTest, StartWithOptions_StackSize) {
+  Thread a("StartWithStackSize");
+  // Ensure that the thread can work with only 12 kb and still process a
+  // message.
+  Thread::Options options;
+#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
+  // ASan bloats the stack variables and overflows the 12 kb stack on OSX.
+  options.stack_size = 24*1024;
+#else
+  options.stack_size = 12*1024;
+#endif
+  EXPECT_TRUE(a.StartWithOptions(options));
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+
+  bool was_invoked = false;
+  a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
+
+  // wait for the task to run (we could use a kernel event here
+  // instead to avoid busy waiting, but this is sufficient for
+  // testing purposes).
+  for (int i = 100; i >= 0 && !was_invoked; --i) {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+  }
+  EXPECT_TRUE(was_invoked);
+}
+
+TEST_F(ThreadTest, TwoTasks) {
+  bool was_invoked = false;
+  {
+    Thread a("TwoTasks");
+    EXPECT_TRUE(a.Start());
+    EXPECT_TRUE(a.message_loop());
+
+    // Test that all events are dispatched before the Thread object is
+    // destroyed.  We do this by dispatching a sleep event before the
+    // event that will toggle our sentinel value.
+    a.task_runner()->PostTask(
+        FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
+                                  &base::PlatformThread::Sleep),
+                              base::TimeDelta::FromMilliseconds(20)));
+    a.task_runner()->PostTask(FROM_HERE,
+                              base::Bind(&ToggleValue, &was_invoked));
+  }
+  EXPECT_TRUE(was_invoked);
+}
+
+TEST_F(ThreadTest, StopSoon) {
+  Thread a("StopSoon");
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.StopSoon();
+  a.StopSoon();
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+}
+
+TEST_F(ThreadTest, ThreadName) {
+  Thread a("ThreadName");
+  EXPECT_TRUE(a.Start());
+  EXPECT_EQ("ThreadName", a.thread_name());
+}
+
+// Make sure we can't use a thread between Start() and Init().
+TEST_F(ThreadTest, SleepInsideInit) {
+  SleepInsideInitThread t;
+  EXPECT_FALSE(t.InitCalled());
+  t.Start();
+  EXPECT_TRUE(t.InitCalled());
+}
+
+// Make sure that the destruction sequence is:
+//
+//  (1) Thread::CleanUp()
+//  (2) MessageLoop::~MessageLoop()
+//      MessageLoop::DestructionObservers called.
+TEST_F(ThreadTest, CleanUp) {
+  EventList captured_events;
+  CapturingDestructionObserver loop_destruction_observer(&captured_events);
+
+  {
+    // Start a thread which writes its event into |captured_events|.
+    CaptureToEventList t(&captured_events);
+    EXPECT_TRUE(t.Start());
+    EXPECT_TRUE(t.message_loop());
+    EXPECT_TRUE(t.IsRunning());
+
+    // Register an observer that writes into |captured_events| once the
+    // thread's message loop is destroyed.
+    t.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&RegisterDestructionObserver,
+                              base::Unretained(&loop_destruction_observer)));
+
+    // Upon leaving this scope, the thread is deleted.
+  }
+
+  // Check the order of events during shutdown.
+  ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
+  EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
+  EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
+  EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
+}
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
new file mode 100644
index 0000000..c063799
--- /dev/null
+++ b/base/threading/watchdog.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/watchdog.h"
+
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+// When the debugger breaks (when we alarm), all the other alarms that are
+// armed will expire (also alarm).  To diminish this effect, we track any
+// delay due to debugger breaks, and we *try* to adjust the effective start
+// time of other alarms to step past the debugging break.
+// Without this safety net, any alarm will typically trigger a host of follow
+// on alarms from callers that specify old times.
+
+struct StaticData {
+  // Lock for access of static data...
+  Lock lock;
+
+  // When did we last alarm and get stuck (for a while) in a debugger?
+  TimeTicks last_debugged_alarm_time;
+
+  // How long did we sit on a break in the debugger?
+  TimeDelta last_debugged_alarm_delay;
+};
+
+LazyInstance<StaticData>::Leaky g_static_data = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Start thread running in a Disarmed state.
+Watchdog::Watchdog(const TimeDelta& duration,
+                   const std::string& thread_watched_name,
+                   bool enabled)
+  : enabled_(enabled),
+    lock_(),
+    condition_variable_(&lock_),
+    state_(DISARMED),
+    duration_(duration),
+    thread_watched_name_(thread_watched_name),
+    delegate_(this) {
+  if (!enabled_)
+    return;  // Don't start thread, or doing anything really.
+  enabled_ = PlatformThread::Create(0,  // Default stack size.
+                                    &delegate_,
+                                    &handle_);
+  DCHECK(enabled_);
+}
+
+// Notify watchdog thread, and wait for it to finish up.
+Watchdog::~Watchdog() {
+  if (!enabled_)
+    return;
+  if (!IsJoinable())
+    Cleanup();
+  condition_variable_.Signal();
+  PlatformThread::Join(handle_);
+}
+
+void Watchdog::Cleanup() {
+  if (!enabled_)
+    return;
+  {
+    AutoLock lock(lock_);
+    state_ = SHUTDOWN;
+  }
+  condition_variable_.Signal();
+}
+
+bool Watchdog::IsJoinable() {
+  if (!enabled_)
+    return true;
+  AutoLock lock(lock_);
+  return (state_ == JOINABLE);
+}
+
+void Watchdog::Arm() {
+  ArmAtStartTime(TimeTicks::Now());
+}
+
+void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
+  ArmAtStartTime(TimeTicks::Now() - time_delta);
+}
+
+// Start clock for watchdog.
+void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
+  {
+    AutoLock lock(lock_);
+    start_time_ = start_time;
+    state_ = ARMED;
+  }
+  // Force watchdog to wake up, and go to sleep with the timer ticking with the
+  // proper duration.
+  condition_variable_.Signal();
+}
+
+// Disable watchdog so that it won't do anything when time expires.
+void Watchdog::Disarm() {
+  AutoLock lock(lock_);
+  state_ = DISARMED;
+  // We don't need to signal, as the watchdog will eventually wake up, and it
+  // will check its state and time, and act accordingly.
+}
+
+void Watchdog::Alarm() {
+  DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
+}
+
+//------------------------------------------------------------------------------
+// Internal private methods that the watchdog thread uses.
+
+void Watchdog::ThreadDelegate::ThreadMain() {
+  SetThreadName();
+  TimeDelta remaining_duration;
+  StaticData* static_data = g_static_data.Pointer();
+  while (1) {
+    AutoLock lock(watchdog_->lock_);
+    while (DISARMED == watchdog_->state_)
+      watchdog_->condition_variable_.Wait();
+    if (SHUTDOWN == watchdog_->state_) {
+      watchdog_->state_ = JOINABLE;
+      return;
+    }
+    DCHECK(ARMED == watchdog_->state_);
+    remaining_duration = watchdog_->duration_ -
+        (TimeTicks::Now() - watchdog_->start_time_);
+    if (remaining_duration.InMilliseconds() > 0) {
+      // Spurios wake?  Timer drifts?  Go back to sleep for remaining time.
+      watchdog_->condition_variable_.TimedWait(remaining_duration);
+      continue;
+    }
+    // We overslept, so this seems like a real alarm.
+    // Watch out for a user that stopped the debugger on a different alarm!
+    {
+      AutoLock static_lock(static_data->lock);
+      if (static_data->last_debugged_alarm_time > watchdog_->start_time_) {
+        // False alarm: we started our clock before the debugger break (last
+        // alarm time).
+        watchdog_->start_time_ += static_data->last_debugged_alarm_delay;
+        if (static_data->last_debugged_alarm_time > watchdog_->start_time_)
+          // Too many alarms must have taken place.
+          watchdog_->state_ = DISARMED;
+        continue;
+      }
+    }
+    watchdog_->state_ = DISARMED;  // Only alarm at most once.
+    TimeTicks last_alarm_time = TimeTicks::Now();
+    {
+      AutoUnlock unlock(watchdog_->lock_);
+      watchdog_->Alarm();  // Set a break point here to debug on alarms.
+    }
+    TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
+    if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
+      continue;
+    // Ignore race of two alarms/breaks going off at roughly the same time.
+    AutoLock static_lock(static_data->lock);
+    // This was a real debugger break.
+    static_data->last_debugged_alarm_time = last_alarm_time;
+    static_data->last_debugged_alarm_delay = last_alarm_delay;
+  }
+}
+
+void Watchdog::ThreadDelegate::SetThreadName() const {
+  std::string name = watchdog_->thread_watched_name_ + " Watchdog";
+  PlatformThread::SetName(name);
+  DVLOG(1) << "Watchdog active: " << name;
+}
+
+// static
+void Watchdog::ResetStaticData() {
+  StaticData* static_data = g_static_data.Pointer();
+  AutoLock lock(static_data->lock);
+  static_data->last_debugged_alarm_time = TimeTicks();
+  static_data->last_debugged_alarm_delay = TimeDelta();
+}
+
+}  // namespace base
diff --git a/base/threading/watchdog.h b/base/threading/watchdog.h
new file mode 100644
index 0000000..ea3be36
--- /dev/null
+++ b/base/threading/watchdog.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The Watchdog class creates a second thread that can Alarm if a specific
+// duration of time passes without proper attention.  The duration of time is
+// specified at construction time.  The Watchdog may be used many times by
+// simply calling Arm() (to start timing) and Disarm() (to reset the timer).
+// The Watchdog is typically used under a debugger, where the stack traces on
+// other threads can be examined if/when the Watchdog alarms.
+
+// Some watchdogs will be enabled or disabled via command line switches. To
+// facilitate such code, an "enabled" argument for the constuctor can be used
+// to permanently disable the watchdog.  Disabled watchdogs don't even spawn
+// a second thread, and their methods call (Arm() and Disarm()) return very
+// quickly.
+
+#ifndef BASE_THREADING_WATCHDOG_H_
+#define BASE_THREADING_WATCHDOG_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BASE_EXPORT Watchdog {
+ public:
+  // Constructor specifies how long the Watchdog will wait before alarming.
+  Watchdog(const TimeDelta& duration,
+           const std::string& thread_watched_name,
+           bool enabled);
+  virtual ~Watchdog();
+
+  // Notify watchdog thread to finish up. Sets the state_ to SHUTDOWN.
+  void Cleanup();
+
+  // Returns true if we state_ is JOINABLE (which indicates that Watchdog has
+  // exited).
+  bool IsJoinable();
+
+  // Start timing, and alarm when time expires (unless we're disarm()ed.)
+  void Arm();  // Arm  starting now.
+  void ArmSomeTimeDeltaAgo(const TimeDelta& time_delta);
+  void ArmAtStartTime(const TimeTicks start_time);
+
+  // Reset time, and do not set off the alarm.
+  void Disarm();
+
+  // Alarm is called if the time expires after an Arm() without someone calling
+  // Disarm().  This method can be overridden to create testable classes.
+  virtual void Alarm();
+
+  // Reset static data to initial state. Useful for tests, to ensure
+  // they are independent.
+  static void ResetStaticData();
+
+ private:
+  class ThreadDelegate : public PlatformThread::Delegate {
+   public:
+    explicit ThreadDelegate(Watchdog* watchdog) : watchdog_(watchdog) {
+    }
+    void ThreadMain() override;
+
+   private:
+    void SetThreadName() const;
+
+    Watchdog* watchdog_;
+  };
+
+  enum State {ARMED, DISARMED, SHUTDOWN, JOINABLE };
+
+  bool enabled_;
+
+  Lock lock_;  // Mutex for state_.
+  ConditionVariable condition_variable_;
+  State state_;
+  const TimeDelta duration_;  // How long after start_time_ do we alarm?
+  const std::string thread_watched_name_;
+  PlatformThreadHandle handle_;
+  ThreadDelegate delegate_;  // Store it, because it must outlive the thread.
+
+  TimeTicks start_time_;  // Start of epoch, and alarm after duration_.
+
+  DISALLOW_COPY_AND_ASSIGN(Watchdog);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WATCHDOG_H_
diff --git a/base/threading/watchdog_unittest.cc b/base/threading/watchdog_unittest.cc
new file mode 100644
index 0000000..627f46d
--- /dev/null
+++ b/base/threading/watchdog_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/watchdog.h"
+
+#include "base/logging.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Provide a derived class to facilitate testing.
+
+class WatchdogCounter : public Watchdog {
+ public:
+  WatchdogCounter(const TimeDelta& duration,
+                  const std::string& thread_watched_name,
+                  bool enabled)
+      : Watchdog(duration, thread_watched_name, enabled),
+        alarm_counter_(0) {
+  }
+
+  ~WatchdogCounter() override {}
+
+  void Alarm() override {
+    alarm_counter_++;
+    Watchdog::Alarm();
+  }
+
+  int alarm_counter() { return alarm_counter_; }
+
+ private:
+  int alarm_counter_;
+
+  DISALLOW_COPY_AND_ASSIGN(WatchdogCounter);
+};
+
+class WatchdogTest : public testing::Test {
+ public:
+  void SetUp() override { Watchdog::ResetStaticData(); }
+};
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// Actual tests
+
+// Minimal constructor/destructor test.
+TEST_F(WatchdogTest, StartupShutdownTest) {
+  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+}
+
+// Test ability to call Arm and Disarm repeatedly.
+TEST_F(WatchdogTest, ArmDisarmTest) {
+  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  watchdog1.Arm();
+  watchdog1.Disarm();
+  watchdog1.Arm();
+  watchdog1.Disarm();
+
+  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+  watchdog2.Arm();
+  watchdog2.Disarm();
+  watchdog2.Arm();
+  watchdog2.Disarm();
+}
+
+// Make sure a basic alarm fires when the time has expired.
+TEST_F(WatchdogTest, AlarmTest) {
+  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true);
+  watchdog.Arm();
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+// Make sure a basic alarm fires when the time has expired.
+TEST_F(WatchdogTest, AlarmPriorTimeTest) {
+  WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
+  // Set a time in the past.
+  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
+  // It should instantly go off, but certainly in less than 5 minutes.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+// Make sure a disable alarm does nothing, even if we arm it.
+TEST_F(WatchdogTest, ConstructorDisabledTest) {
+  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false);
+  watchdog.Arm();
+  // Alarm should not fire, as it was disabled.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+  EXPECT_EQ(0, watchdog.alarm_counter());
+}
+
+// Make sure Disarming will prevent firing, even after Arming.
+TEST_F(WatchdogTest, DisarmTest) {
+  WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);
+
+  TimeTicks start = TimeTicks::Now();
+  watchdog.Arm();
+  // Sleep a bit, but not past the alarm point.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  watchdog.Disarm();
+  TimeTicks end = TimeTicks::Now();
+
+  if (end - start > TimeDelta::FromMilliseconds(500)) {
+    LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
+                 << "timing-sensitive test suspicious.  Aborting now.";
+    return;
+  }
+
+  // Alarm should not have fired before it was disarmed.
+  EXPECT_EQ(0, watchdog.alarm_counter());
+
+  // Sleep past the point where it would have fired if it wasn't disarmed,
+  // and verify that it didn't fire.
+  PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+  EXPECT_EQ(0, watchdog.alarm_counter());
+
+  // ...but even after disarming, we can still use the alarm...
+  // Set a time greater than the timeout into the past.
+  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10));
+  // It should almost instantly go off, but certainly in less than 5 minutes.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
new file mode 100644
index 0000000..bc016ce
--- /dev/null
+++ b/base/threading/worker_pool.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance.h"
+#include "base/task_runner.h"
+#include "base/threading/post_task_and_reply_impl.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+class PostTaskAndReplyWorkerPool : public internal::PostTaskAndReplyImpl {
+ public:
+  explicit PostTaskAndReplyWorkerPool(bool task_is_slow)
+      : task_is_slow_(task_is_slow) {
+  }
+
+ private:
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task) override {
+    return WorkerPool::PostTask(from_here, task, task_is_slow_);
+  }
+
+  bool task_is_slow_;
+};
+
+// WorkerPoolTaskRunner ---------------------------------------------
+// A TaskRunner which posts tasks to a WorkerPool with a
+// fixed ShutdownBehavior.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class WorkerPoolTaskRunner : public TaskRunner {
+ public:
+  explicit WorkerPoolTaskRunner(bool tasks_are_slow);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  ~WorkerPoolTaskRunner() override;
+
+  // Helper function for posting a delayed task. Asserts that the delay is
+  // zero because non-zero delays are not supported.
+  bool PostDelayedTaskAssertZeroDelay(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      base::TimeDelta delay);
+
+  const bool tasks_are_slow_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerPoolTaskRunner);
+};
+
+WorkerPoolTaskRunner::WorkerPoolTaskRunner(bool tasks_are_slow)
+    : tasks_are_slow_(tasks_are_slow) {
+}
+
+WorkerPoolTaskRunner::~WorkerPoolTaskRunner() {
+}
+
+bool WorkerPoolTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedTaskAssertZeroDelay(from_here, task, delay);
+}
+
+bool WorkerPoolTaskRunner::RunsTasksOnCurrentThread() const {
+  return WorkerPool::RunsTasksOnCurrentThread();
+}
+
+bool WorkerPoolTaskRunner::PostDelayedTaskAssertZeroDelay(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  DCHECK_EQ(delay.InMillisecondsRoundedUp(), 0)
+      << "WorkerPoolTaskRunner does not support non-zero delays";
+  return WorkerPool::PostTask(from_here, task, tasks_are_slow_);
+}
+
+struct TaskRunnerHolder {
+  TaskRunnerHolder() {
+    taskrunners_[0] = new WorkerPoolTaskRunner(false);
+    taskrunners_[1] = new WorkerPoolTaskRunner(true);
+  }
+  scoped_refptr<TaskRunner> taskrunners_[2];
+};
+
+base::LazyInstance<TaskRunnerHolder>::Leaky
+    g_taskrunners = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+bool WorkerPool::PostTaskAndReply(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  const Closure& reply,
+                                  bool task_is_slow) {
+  // Do not report PostTaskAndReplyRelay leaks in tests. There's nothing we can
+  // do about them because WorkerPool doesn't have a flushing API.
+  // http://crbug.com/248513
+  // http://crbug.com/290897
+  // Note: this annotation does not cover tasks posted through a TaskRunner.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  return PostTaskAndReplyWorkerPool(task_is_slow).PostTaskAndReply(
+      from_here, task, reply);
+}
+
+// static
+const scoped_refptr<TaskRunner>&
+WorkerPool::GetTaskRunner(bool tasks_are_slow) {
+  return g_taskrunners.Get().taskrunners_[tasks_are_slow];
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool.h b/base/threading/worker_pool.h
new file mode 100644
index 0000000..a52a414
--- /dev/null
+++ b/base/threading/worker_pool.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_WORKER_POOL_H_
+#define BASE_THREADING_WORKER_POOL_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+
+class Task;
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class TaskRunner;
+
+// This is a facility that runs tasks that don't require a specific thread or
+// a message loop.
+//
+// WARNING: This shouldn't be used unless absolutely necessary. We don't wait
+// for the worker pool threads to finish on shutdown, so the tasks running
+// inside the pool must be extremely careful about other objects they access
+// (MessageLoops, Singletons, etc). During shutdown these object may no longer
+// exist.
+class BASE_EXPORT WorkerPool {
+ public:
+  // This function posts |task| to run on a worker thread.  |task_is_slow|
+  // should be used for tasks that will take a long time to execute.  Returns
+  // false if |task| could not be posted to a worker thread.  Regardless of
+  // return value, ownership of |task| is transferred to the worker pool.
+  static bool PostTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task, bool task_is_slow);
+
+  // Just like TaskRunner::PostTaskAndReply, except the destination
+  // for |task| is a worker thread and you can specify |task_is_slow| just
+  // like you can for PostTask above.
+  static bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               const Closure& reply,
+                               bool task_is_slow);
+
+  // Return true if the current thread is one that this WorkerPool runs tasks
+  // on.  (Note that if the Windows worker pool is used without going through
+  // this WorkerPool interface, RunsTasksOnCurrentThread would return false on
+  // those threads.)
+  static bool RunsTasksOnCurrentThread();
+
+  // Get a TaskRunner wrapper which posts to the WorkerPool using the given
+  // |task_is_slow| behavior.
+  static const scoped_refptr<TaskRunner>& GetTaskRunner(bool task_is_slow);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_H_
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
new file mode 100644
index 0000000..349b5d7
--- /dev/null
+++ b/base/threading/worker_pool_posix.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool_posix.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/worker_pool.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+using tracked_objects::TrackedTime;
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+    g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
+
+const int kIdleSecondsBeforeExit = 10 * 60;
+
+class WorkerPoolImpl {
+ public:
+  WorkerPoolImpl();
+  ~WorkerPoolImpl();
+
+  void PostTask(const tracked_objects::Location& from_here,
+                const base::Closure& task, bool task_is_slow);
+
+ private:
+  scoped_refptr<base::PosixDynamicThreadPool> pool_;
+};
+
+WorkerPoolImpl::WorkerPoolImpl()
+    : pool_(new base::PosixDynamicThreadPool("WorkerPool",
+                                             kIdleSecondsBeforeExit)) {
+}
+
+WorkerPoolImpl::~WorkerPoolImpl() {
+  pool_->Terminate();
+}
+
+void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
+                              const base::Closure& task, bool task_is_slow) {
+  pool_->PostTask(from_here, task);
+}
+
+base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool =
+    LAZY_INSTANCE_INITIALIZER;
+
+class WorkerThread : public PlatformThread::Delegate {
+ public:
+  WorkerThread(const std::string& name_prefix,
+               base::PosixDynamicThreadPool* pool)
+      : name_prefix_(name_prefix),
+        pool_(pool) {}
+
+  void ThreadMain() override;
+
+ private:
+  const std::string name_prefix_;
+  scoped_refptr<base::PosixDynamicThreadPool> pool_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerThread);
+};
+
+void WorkerThread::ThreadMain() {
+  g_worker_pool_running_on_this_thread.Get().Set(true);
+  const std::string name = base::StringPrintf(
+      "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
+  // Note |name.c_str()| must remain valid for for the whole life of the thread.
+  PlatformThread::SetName(name);
+
+  for (;;) {
+    PendingTask pending_task = pool_->WaitForTask();
+    if (pending_task.task.is_null())
+      break;
+    TRACE_EVENT2("toplevel", "WorkerThread::ThreadMain::Run",
+        "src_file", pending_task.posted_from.file_name(),
+        "src_func", pending_task.posted_from.function_name());
+
+    tracked_objects::TaskStopwatch stopwatch;
+    stopwatch.Start();
+    pending_task.task.Run();
+    stopwatch.Stop();
+
+    tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
+        pending_task.birth_tally, pending_task.time_posted, stopwatch);
+  }
+
+  // The WorkerThread is non-joinable, so it deletes itself.
+  delete this;
+}
+
+}  // namespace
+
+// static
+bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
+                          const base::Closure& task, bool task_is_slow) {
+  g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
+  return true;
+}
+
+// static
+bool WorkerPool::RunsTasksOnCurrentThread() {
+  return g_worker_pool_running_on_this_thread.Get().Get();
+}
+
+PosixDynamicThreadPool::PosixDynamicThreadPool(const std::string& name_prefix,
+                                               int idle_seconds_before_exit)
+    : name_prefix_(name_prefix),
+      idle_seconds_before_exit_(idle_seconds_before_exit),
+      pending_tasks_available_cv_(&lock_),
+      num_idle_threads_(0),
+      terminated_(false) {}
+
+PosixDynamicThreadPool::~PosixDynamicThreadPool() {
+  while (!pending_tasks_.empty())
+    pending_tasks_.pop();
+}
+
+void PosixDynamicThreadPool::Terminate() {
+  {
+    AutoLock locked(lock_);
+    DCHECK(!terminated_) << "Thread pool is already terminated.";
+    terminated_ = true;
+  }
+  pending_tasks_available_cv_.Broadcast();
+}
+
+void PosixDynamicThreadPool::PostTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task) {
+  PendingTask pending_task(from_here, task);
+  AddTask(&pending_task);
+}
+
+void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
+  AutoLock locked(lock_);
+  DCHECK(!terminated_) <<
+      "This thread pool is already terminated.  Do not post new tasks.";
+
+  pending_tasks_.push(*pending_task);
+  pending_task->task.Reset();
+
+  // We have enough worker threads.
+  if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
+    pending_tasks_available_cv_.Signal();
+  } else {
+    // The new PlatformThread will take ownership of the WorkerThread object,
+    // which will delete itself on exit.
+    WorkerThread* worker =
+        new WorkerThread(name_prefix_, this);
+    PlatformThread::CreateNonJoinable(0, worker);
+  }
+}
+
+PendingTask PosixDynamicThreadPool::WaitForTask() {
+  AutoLock locked(lock_);
+
+  if (terminated_)
+    return PendingTask(FROM_HERE, base::Closure());
+
+  if (pending_tasks_.empty()) {  // No work available, wait for work.
+    num_idle_threads_++;
+    if (num_idle_threads_cv_.get())
+      num_idle_threads_cv_->Signal();
+    pending_tasks_available_cv_.TimedWait(
+        TimeDelta::FromSeconds(idle_seconds_before_exit_));
+    num_idle_threads_--;
+    if (num_idle_threads_cv_.get())
+      num_idle_threads_cv_->Signal();
+    if (pending_tasks_.empty()) {
+      // We waited for work, but there's still no work.  Return NULL to signal
+      // the thread to terminate.
+      return PendingTask(FROM_HERE, base::Closure());
+    }
+  }
+
+  PendingTask pending_task = pending_tasks_.front();
+  pending_tasks_.pop();
+  return pending_task;
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_posix.h b/base/threading/worker_pool_posix.h
new file mode 100644
index 0000000..dd0ffb6
--- /dev/null
+++ b/base/threading/worker_pool_posix.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// The thread pool used in the POSIX implementation of WorkerPool dynamically
+// adds threads as necessary to handle all tasks.  It keeps old threads around
+// for a period of time to allow them to be reused.  After this waiting period,
+// the threads exit.  This thread pool uses non-joinable threads, therefore
+// worker threads are not joined during process shutdown.  This means that
+// potentially long running tasks (such as DNS lookup) do not block process
+// shutdown, but also means that process shutdown may "leak" objects.  Note that
+// although PosixDynamicThreadPool spawns the worker threads and manages the
+// task queue, it does not own the worker threads.  The worker threads ask the
+// PosixDynamicThreadPool for work and eventually clean themselves up.  The
+// worker threads all maintain scoped_refptrs to the PosixDynamicThreadPool
+// instance, which prevents PosixDynamicThreadPool from disappearing before all
+// worker threads exit.  The owner of PosixDynamicThreadPool should likewise
+// maintain a scoped_refptr to the PosixDynamicThreadPool instance.
+//
+// NOTE: The classes defined in this file are only meant for use by the POSIX
+// implementation of WorkerPool.  No one else should be using these classes.
+// These symbols are exported in a header purely for testing purposes.
+
+#ifndef BASE_THREADING_WORKER_POOL_POSIX_H_
+#define BASE_THREADING_WORKER_POOL_POSIX_H_
+
+#include <queue>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pending_task.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/tracked_objects.h"
+
+class Task;
+
+namespace base {
+
+class BASE_EXPORT PosixDynamicThreadPool
+    : public RefCountedThreadSafe<PosixDynamicThreadPool> {
+ public:
+  class PosixDynamicThreadPoolPeer;
+
+  // All worker threads will share the same |name_prefix|.  They will exit after
+  // |idle_seconds_before_exit|.
+  PosixDynamicThreadPool(const std::string& name_prefix,
+                         int idle_seconds_before_exit);
+
+  // Indicates that the thread pool is going away.  Stops handing out tasks to
+  // worker threads.  Wakes up all the idle threads to let them exit.
+  void Terminate();
+
+  // Adds |task| to the thread pool.
+  void PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  // Worker thread method to wait for up to |idle_seconds_before_exit| for more
+  // work from the thread pool.  Returns NULL if no work is available.
+  PendingTask WaitForTask();
+
+ private:
+  friend class RefCountedThreadSafe<PosixDynamicThreadPool>;
+  friend class PosixDynamicThreadPoolPeer;
+
+  ~PosixDynamicThreadPool();
+
+  // Adds pending_task to the thread pool.  This function will clear
+  // |pending_task->task|.
+  void AddTask(PendingTask* pending_task);
+
+  const std::string name_prefix_;
+  const int idle_seconds_before_exit_;
+
+  Lock lock_;  // Protects all the variables below.
+
+  // Signal()s worker threads to let them know more tasks are available.
+  // Also used for Broadcast()'ing to worker threads to let them know the pool
+  // is being deleted and they can exit.
+  ConditionVariable pending_tasks_available_cv_;
+  int num_idle_threads_;
+  TaskQueue pending_tasks_;
+  bool terminated_;
+  // Only used for tests to ensure correct thread ordering.  It will always be
+  // NULL in non-test code.
+  scoped_ptr<ConditionVariable> num_idle_threads_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_POSIX_H_
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
new file mode 100644
index 0000000..354a99c
--- /dev/null
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool_posix.h"
+
+#include <set>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Peer class to provide passthrough access to PosixDynamicThreadPool internals.
+class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
+ public:
+  explicit PosixDynamicThreadPoolPeer(PosixDynamicThreadPool* pool)
+      : pool_(pool) {}
+
+  Lock* lock() { return &pool_->lock_; }
+  ConditionVariable* pending_tasks_available_cv() {
+    return &pool_->pending_tasks_available_cv_;
+  }
+  const std::queue<PendingTask>& pending_tasks() const {
+    return pool_->pending_tasks_;
+  }
+  int num_idle_threads() const { return pool_->num_idle_threads_; }
+  ConditionVariable* num_idle_threads_cv() {
+    return pool_->num_idle_threads_cv_.get();
+  }
+  void set_num_idle_threads_cv(ConditionVariable* cv) {
+    pool_->num_idle_threads_cv_.reset(cv);
+  }
+
+ private:
+  PosixDynamicThreadPool* pool_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPoolPeer);
+};
+
+namespace {
+
+// IncrementingTask's main purpose is to increment a counter.  It also updates a
+// set of unique thread ids, and signals a ConditionVariable on completion.
+// Note that since it does not block, there is no way to control the number of
+// threads used if more than one IncrementingTask is consecutively posted to the
+// thread pool, since the first one might finish executing before the subsequent
+// PostTask() calls get invoked.
+void IncrementingTask(Lock* counter_lock,
+                      int* counter,
+                      Lock* unique_threads_lock,
+                      std::set<PlatformThreadId>* unique_threads) {
+  {
+    base::AutoLock locked(*unique_threads_lock);
+    unique_threads->insert(PlatformThread::CurrentId());
+  }
+  base::AutoLock locked(*counter_lock);
+  (*counter)++;
+}
+
+// BlockingIncrementingTask is a simple wrapper around IncrementingTask that
+// allows for waiting at the start of Run() for a WaitableEvent to be signalled.
+struct BlockingIncrementingTaskArgs {
+  Lock* counter_lock;
+  int* counter;
+  Lock* unique_threads_lock;
+  std::set<PlatformThreadId>* unique_threads;
+  Lock* num_waiting_to_start_lock;
+  int* num_waiting_to_start;
+  ConditionVariable* num_waiting_to_start_cv;
+  base::WaitableEvent* start;
+};
+
+void BlockingIncrementingTask(const BlockingIncrementingTaskArgs& args) {
+  {
+    base::AutoLock num_waiting_to_start_locked(*args.num_waiting_to_start_lock);
+    (*args.num_waiting_to_start)++;
+  }
+  args.num_waiting_to_start_cv->Signal();
+  args.start->Wait();
+  IncrementingTask(args.counter_lock, args.counter, args.unique_threads_lock,
+                   args.unique_threads);
+}
+
+class PosixDynamicThreadPoolTest : public testing::Test {
+ protected:
+  PosixDynamicThreadPoolTest()
+      : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
+        peer_(pool_.get()),
+        counter_(0),
+        num_waiting_to_start_(0),
+        num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
+        start_(true, false) {}
+
+  void SetUp() override {
+    peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
+  }
+
+  void TearDown() override {
+    // Wake up the idle threads so they can terminate.
+    if (pool_.get()) pool_->Terminate();
+  }
+
+  void WaitForTasksToStart(int num_tasks) {
+    base::AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
+    while (num_waiting_to_start_ < num_tasks) {
+      num_waiting_to_start_cv_.Wait();
+    }
+  }
+
+  void WaitForIdleThreads(int num_idle_threads) {
+    base::AutoLock pool_locked(*peer_.lock());
+    while (peer_.num_idle_threads() < num_idle_threads) {
+      peer_.num_idle_threads_cv()->Wait();
+    }
+  }
+
+  base::Closure CreateNewIncrementingTaskCallback() {
+    return base::Bind(&IncrementingTask, &counter_lock_, &counter_,
+                      &unique_threads_lock_, &unique_threads_);
+  }
+
+  base::Closure CreateNewBlockingIncrementingTaskCallback() {
+    BlockingIncrementingTaskArgs args = {
+        &counter_lock_, &counter_, &unique_threads_lock_, &unique_threads_,
+        &num_waiting_to_start_lock_, &num_waiting_to_start_,
+        &num_waiting_to_start_cv_, &start_
+    };
+    return base::Bind(&BlockingIncrementingTask, args);
+  }
+
+  scoped_refptr<base::PosixDynamicThreadPool> pool_;
+  base::PosixDynamicThreadPool::PosixDynamicThreadPoolPeer peer_;
+  Lock counter_lock_;
+  int counter_;
+  Lock unique_threads_lock_;
+  std::set<PlatformThreadId> unique_threads_;
+  Lock num_waiting_to_start_lock_;
+  int num_waiting_to_start_;
+  ConditionVariable num_waiting_to_start_cv_;
+  base::WaitableEvent start_;
+};
+
+}  // namespace
+
+TEST_F(PosixDynamicThreadPoolTest, Basic) {
+  EXPECT_EQ(0, peer_.num_idle_threads());
+  EXPECT_EQ(0U, unique_threads_.size());
+  EXPECT_EQ(0U, peer_.pending_tasks().size());
+
+  // Add one task and wait for it to be completed.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  EXPECT_EQ(1U, unique_threads_.size()) <<
+      "There should be only one thread allocated for one task.";
+  EXPECT_EQ(1, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
+  // Add one task and wait for it to be completed.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  // Add another 2 tasks.  One should reuse the existing worker thread.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(2U, unique_threads_.size());
+  EXPECT_EQ(2, peer_.num_idle_threads());
+  EXPECT_EQ(3, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
+  // Add two blocking tasks.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  EXPECT_EQ(0, counter_) << "Blocking tasks should not have started yet.";
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(2U, unique_threads_.size());
+  EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
+  EXPECT_EQ(2, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, Complex) {
+  // Add two non blocking tasks and wait for them to finish.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  // Add two blocking tasks, start them simultaneously, and wait for them to
+  // finish.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(3, counter_);
+  EXPECT_EQ(2, peer_.num_idle_threads());
+  EXPECT_EQ(2U, unique_threads_.size());
+
+  // Wake up all idle threads so they can exit.
+  {
+    base::AutoLock locked(*peer_.lock());
+    while (peer_.num_idle_threads() > 0) {
+      peer_.pending_tasks_available_cv()->Signal();
+      peer_.num_idle_threads_cv()->Wait();
+    }
+  }
+
+  // Add another non blocking task.  There are no threads to reuse.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+  WaitForIdleThreads(1);
+
+  // The POSIX implementation of PlatformThread::CurrentId() uses pthread_self()
+  // which is not guaranteed to be unique after a thread joins. The OS X
+  // implemntation of pthread_self() returns the address of the pthread_t, which
+  // is merely a malloc()ed pointer stored in the first TLS slot. When a thread
+  // joins and that structure is freed, the block of memory can be put on the
+  // OS free list, meaning the same address could be reused in a subsequent
+  // allocation. This in fact happens when allocating in a loop as this test
+  // does.
+  //
+  // Because there are two concurrent threads, there's at least the guarantee
+  // of having two unique thread IDs in the set. But after those two threads are
+  // joined, the next-created thread can get a re-used ID if the allocation of
+  // the pthread_t structure is taken from the free list. Therefore, there can
+  // be either 2 or 3 unique thread IDs in the set at this stage in the test.
+  EXPECT_TRUE(unique_threads_.size() >= 2 && unique_threads_.size() <= 3)
+      << "unique_threads_.size() = " << unique_threads_.size();
+  EXPECT_EQ(1, peer_.num_idle_threads());
+  EXPECT_EQ(4, counter_);
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_unittest.cc b/base/threading/worker_pool_unittest.cc
new file mode 100644
index 0000000..9a9ab95
--- /dev/null
+++ b/base/threading/worker_pool_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread_checker_impl.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest WorkerPoolTest;
+
+namespace base {
+
+namespace {
+
+class PostTaskAndReplyTester
+    : public base::RefCountedThreadSafe<PostTaskAndReplyTester> {
+ public:
+  PostTaskAndReplyTester() : finished_(false), test_event_(false, false) {}
+
+  void RunTest() {
+    ASSERT_TRUE(thread_checker_.CalledOnValidThread());
+    WorkerPool::PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&PostTaskAndReplyTester::OnWorkerThread, this),
+      base::Bind(&PostTaskAndReplyTester::OnOriginalThread, this),
+      false);
+
+    test_event_.Wait();
+  }
+
+  void OnWorkerThread() {
+    // We're not on the original thread.
+    EXPECT_FALSE(thread_checker_.CalledOnValidThread());
+
+    test_event_.Signal();
+  }
+
+  void OnOriginalThread() {
+    EXPECT_TRUE(thread_checker_.CalledOnValidThread());
+    finished_ = true;
+  }
+
+  bool finished() const {
+    return finished_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<PostTaskAndReplyTester>;
+  ~PostTaskAndReplyTester() {}
+
+  bool finished_;
+  WaitableEvent test_event_;
+
+  // The Impl version performs its checks even in release builds.
+  ThreadCheckerImpl thread_checker_;
+};
+
+}  // namespace
+
+TEST_F(WorkerPoolTest, PostTask) {
+  WaitableEvent test_event(false, false);
+  WaitableEvent long_test_event(false, false);
+
+  WorkerPool::PostTask(FROM_HERE,
+                       base::Bind(&WaitableEvent::Signal,
+                                  base::Unretained(&test_event)),
+                       false);
+  WorkerPool::PostTask(FROM_HERE,
+                       base::Bind(&WaitableEvent::Signal,
+                                  base::Unretained(&long_test_event)),
+                       true);
+
+  test_event.Wait();
+  long_test_event.Wait();
+}
+
+#if defined(OS_WIN) || defined(OS_LINUX)
+// Flaky on Windows and Linux (http://crbug.com/130337)
+#define MAYBE_PostTaskAndReply DISABLED_PostTaskAndReply
+#else
+#define MAYBE_PostTaskAndReply PostTaskAndReply
+#endif
+
+TEST_F(WorkerPoolTest, MAYBE_PostTaskAndReply) {
+  MessageLoop message_loop;
+  scoped_refptr<PostTaskAndReplyTester> tester(new PostTaskAndReplyTester());
+  tester->RunTest();
+
+  const TimeDelta kMaxDuration = TestTimeouts::tiny_timeout();
+  TimeTicks start = TimeTicks::Now();
+  while (!tester->finished() && TimeTicks::Now() - start < kMaxDuration) {
+#if defined(OS_IOS)
+    // Ensure that the other thread has a chance to run even on a single-core
+    // device.
+    pthread_yield_np();
+#endif
+    RunLoop().RunUntilIdle();
+  }
+  EXPECT_TRUE(tester->finished());
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_win.cc b/base/threading/worker_pool_win.cc
new file mode 100644
index 0000000..1b0ade5
--- /dev/null
+++ b/base/threading/worker_pool_win.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/pending_task.h"
+#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+    g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
+
+DWORD CALLBACK WorkItemCallback(void* param) {
+  PendingTask* pending_task = static_cast<PendingTask*>(param);
+  TRACE_EVENT2("toplevel", "WorkItemCallback::Run",
+               "src_file", pending_task->posted_from.file_name(),
+               "src_func", pending_task->posted_from.function_name());
+
+  g_worker_pool_running_on_this_thread.Get().Set(true);
+
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  pending_task->task.Run();
+  stopwatch.Stop();
+
+  g_worker_pool_running_on_this_thread.Get().Set(false);
+
+  tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
+      pending_task->birth_tally, pending_task->time_posted, stopwatch);
+
+  delete pending_task;
+  return 0;
+}
+
+// Takes ownership of |pending_task|
+bool PostTaskInternal(PendingTask* pending_task, bool task_is_slow) {
+  ULONG flags = 0;
+  if (task_is_slow)
+    flags |= WT_EXECUTELONGFUNCTION;
+
+  if (!QueueUserWorkItem(WorkItemCallback, pending_task, flags)) {
+    DPLOG(ERROR) << "QueueUserWorkItem failed";
+    delete pending_task;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// static
+bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
+                          const base::Closure& task, bool task_is_slow) {
+  PendingTask* pending_task = new PendingTask(from_here, task);
+  return PostTaskInternal(pending_task, task_is_slow);
+}
+
+// static
+bool WorkerPool::RunsTasksOnCurrentThread() {
+  return g_worker_pool_running_on_this_thread.Get().Get();
+}
+
+}  // namespace base
diff --git a/base/time/clock.cc b/base/time/clock.cc
new file mode 100644
index 0000000..34dc37e
--- /dev/null
+++ b/base/time/clock.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/clock.h"
+
+namespace base {
+
+Clock::~Clock() {}
+
+}  // namespace base
diff --git a/base/time/clock.h b/base/time/clock.h
new file mode 100644
index 0000000..507a850
--- /dev/null
+++ b/base/time/clock.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIME_CLOCK_H_
+#define BASE_TIME_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// A Clock is an interface for objects that vend Times.  It is
+// intended to be able to test the behavior of classes with respect to
+// time.
+//
+// See DefaultClock (base/time/default_clock.h) for the default
+// implementation that simply uses Time::Now().
+//
+// (An implementation that uses Time::SystemTime() should be added as
+// needed.)
+//
+// See SimpleTestClock (base/test/simple_test_clock.h) for a simple
+// test implementation.
+//
+// See TickClock (base/time/tick_clock.h) for the equivalent interface for
+// TimeTicks.
+class BASE_EXPORT Clock {
+ public:
+  virtual ~Clock();
+
+  // Now() must be safe to call from any thread.  The caller cannot
+  // make any ordering assumptions about the returned Time.  For
+  // example, the system clock may change to an earlier time.
+  virtual Time Now() = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_CLOCK_H_
diff --git a/base/time/default_clock.cc b/base/time/default_clock.cc
new file mode 100644
index 0000000..5f70114
--- /dev/null
+++ b/base/time/default_clock.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/default_clock.h"
+
+namespace base {
+
+DefaultClock::~DefaultClock() {}
+
+Time DefaultClock::Now() {
+  return Time::Now();
+}
+
+}  // namespace base
diff --git a/base/time/default_clock.h b/base/time/default_clock.h
new file mode 100644
index 0000000..0b8250e
--- /dev/null
+++ b/base/time/default_clock.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIME_DEFAULT_CLOCK_H_
+#define BASE_TIME_DEFAULT_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/time/clock.h"
+
+namespace base {
+
+// DefaultClock is a Clock implementation that uses Time::Now().
+class BASE_EXPORT DefaultClock : public Clock {
+ public:
+  ~DefaultClock() override;
+
+  // Simply returns Time::Now().
+  Time Now() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_DEFAULT_CLOCK_H_
diff --git a/base/time/default_tick_clock.cc b/base/time/default_tick_clock.cc
new file mode 100644
index 0000000..ce62fcc
--- /dev/null
+++ b/base/time/default_tick_clock.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/default_tick_clock.h"
+
+namespace base {
+
+DefaultTickClock::~DefaultTickClock() {}
+
+TimeTicks DefaultTickClock::NowTicks() {
+  return TimeTicks::Now();
+}
+
+}  // namespace base
diff --git a/base/time/default_tick_clock.h b/base/time/default_tick_clock.h
new file mode 100644
index 0000000..cb041e6
--- /dev/null
+++ b/base/time/default_tick_clock.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIME_DEFAULT_TICK_CLOCK_H_
+#define BASE_TIME_DEFAULT_TICK_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/time/tick_clock.h"
+
+namespace base {
+
+// DefaultClock is a Clock implementation that uses TimeTicks::Now().
+class BASE_EXPORT DefaultTickClock : public TickClock {
+ public:
+  ~DefaultTickClock() override;
+
+  // Simply returns TimeTicks::Now().
+  TimeTicks NowTicks() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_DEFAULT_TICK_CLOCK_H_
diff --git a/base/time/pr_time_unittest.cc b/base/time/pr_time_unittest.cc
new file mode 100644
index 0000000..06043a5
--- /dev/null
+++ b/base/time/pr_time_unittest.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+#include <time.h>
+
+#include "base/compiler_specific.h"
+#include "base/third_party/nspr/prtime.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+
+namespace {
+
+// time_t representation of 15th Oct 2007 12:45:00 PDT
+PRTime comparison_time_pdt = 1192477500 * Time::kMicrosecondsPerSecond;
+
+// Time with positive tz offset and fractional seconds:
+// 2013-07-08T11:28:12.441381+02:00
+PRTime comparison_time_2 = INT64_C(1373275692441381);   // represented as GMT
+
+// Specialized test fixture allowing time strings without timezones to be
+// tested by comparing them to a known time in the local zone.
+class PRTimeTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Use mktime to get a time_t, and turn it into a PRTime by converting
+    // seconds to microseconds.  Use 15th Oct 2007 12:45:00 local.  This
+    // must be a time guaranteed to be outside of a DST fallback hour in
+    // any timezone.
+    struct tm local_comparison_tm = {
+      0,            // second
+      45,           // minute
+      12,           // hour
+      15,           // day of month
+      10 - 1,       // month
+      2007 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+    comparison_time_local_ =
+        mktime(&local_comparison_tm) * Time::kMicrosecondsPerSecond;
+    ASSERT_GT(comparison_time_local_, 0);
+
+    const int microseconds = 441381;
+    struct tm local_comparison_tm_2 = {
+      12,           // second
+      28,           // minute
+      11,           // hour
+      8,            // day of month
+      7 - 1,        // month
+      2013 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+    comparison_time_local_2_ =
+        mktime(&local_comparison_tm_2) * Time::kMicrosecondsPerSecond;
+    ASSERT_GT(comparison_time_local_2_, 0);
+    comparison_time_local_2_ += microseconds;
+  }
+
+  PRTime comparison_time_local_;
+  PRTime comparison_time_local_2_;
+};
+
+// Tests the PR_ParseTimeString nspr helper function for
+// a variety of time strings.
+TEST_F(PRTimeTest, ParseTimeTest1) {
+  time_t current_time = 0;
+  time(&current_time);
+
+  const int BUFFER_SIZE = 64;
+  struct tm local_time = {0};
+  char time_buf[BUFFER_SIZE] = {0};
+#if defined(OS_WIN)
+  localtime_s(&local_time, &current_time);
+  asctime_s(time_buf, arraysize(time_buf), &local_time);
+#elif defined(OS_POSIX)
+  localtime_r(&current_time, &local_time);
+  asctime_r(&local_time, time_buf);
+#endif
+
+  PRTime current_time64 = static_cast<PRTime>(current_time) * PR_USEC_PER_SEC;
+
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString(time_buf, PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(current_time64, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon, 15 Oct 2007 19:45:00 GMT",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest3) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15 Oct 07 12:45:00", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest4) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15 Oct 07 19:45 GMT", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest5) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:45 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest6) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Monday, Oct 15, 2007 12:45 PM",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest7) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00 PM", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest8) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00. PM", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest9) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00.0 PM", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest10) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15-OCT-2007 12:45pm", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest11) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("16 Oct 2007 4:45-JST (Tuesday)",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+// hh:mm timezone offset.
+TEST_F(PRTimeTest, ParseTimeTest12) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+02:00",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// hhmm timezone offset.
+TEST_F(PRTimeTest, ParseTimeTest13) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+0200",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// hh timezone offset.
+TEST_F(PRTimeTest, ParseTimeTest14) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.4413819+02",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// 5 digits fractional second.
+TEST_F(PRTimeTest, ParseTimeTest15) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.44138Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2-1, parsed_time);
+}
+
+// Fractional seconds, local timezone.
+TEST_F(PRTimeTest, ParseTimeTest16) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_2_, parsed_time);
+}
+
+// "Z" (=GMT) timezone.
+TEST_F(PRTimeTest, ParseTimeTest17) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// "T" delimiter replaced by space.
+TEST_F(PRTimeTest, ParseTimeTest18) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08 09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestInvalid1) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("201-07-08T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_FAILURE, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestInvalid2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-007-08T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_FAILURE, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestInvalid3) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-008T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_FAILURE, result);
+}
+
+// This test should not crash when compiled with Visual C++ 2005 (see
+// http://crbug.com/4387).
+TEST_F(PRTimeTest, ParseTimeTestOutOfRange) {
+  PRTime parsed_time = 0;
+  // Note the lack of timezone in the time string.  The year has to be 3001.
+  // The date has to be after 23:59:59, December 31, 3000, US Pacific Time, so
+  // we use January 2, 3001 to make sure it's after the magic maximum in any
+  // timezone.
+  PRStatus result = PR_ParseTimeString("Sun Jan  2 00:00:00 3001",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestNotNormalized1) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:44:60 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestNotNormalized2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Sun Oct 14 36:45 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+}  // namespace
diff --git a/base/time/tick_clock.cc b/base/time/tick_clock.cc
new file mode 100644
index 0000000..495805c
--- /dev/null
+++ b/base/time/tick_clock.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/tick_clock.h"
+
+namespace base {
+
+TickClock::~TickClock() {}
+
+}  // namespace base
diff --git a/base/time/tick_clock.h b/base/time/tick_clock.h
new file mode 100644
index 0000000..f7aba53
--- /dev/null
+++ b/base/time/tick_clock.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIME_TICK_CLOCK_H_
+#define BASE_TIME_TICK_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// A TickClock is an interface for objects that vend TimeTicks.  It is
+// intended to be able to test the behavior of classes with respect to
+// non-decreasing time.
+//
+// See DefaultTickClock (base/time/default_tick_clock.h) for the default
+// implementation that simply uses TimeTicks::Now().
+//
+// (Other implementations that use TimeTicks::NowFromSystemTime() should
+// be added as needed.)
+//
+// See SimpleTestTickClock (base/test/simple_test_tick_clock.h) for a
+// simple test implementation.
+//
+// See Clock (base/time/clock.h) for the equivalent interface for Times.
+class BASE_EXPORT TickClock {
+ public:
+  virtual ~TickClock();
+
+  // NowTicks() must be safe to call from any thread.  The caller may
+  // assume that NowTicks() is monotonic (but not strictly monotonic).
+  // In other words, the returned TimeTicks will never decrease with
+  // time, although they might "stand still".
+  virtual TimeTicks NowTicks() = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_TICK_CLOCK_H_
diff --git a/base/time/time.cc b/base/time/time.cc
new file mode 100644
index 0000000..bf6c998
--- /dev/null
+++ b/base/time/time.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+
+#include <cmath>
+#include <ios>
+#include <limits>
+#include <ostream>
+#include <sstream>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/nspr/prtime.h"
+
+namespace base {
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::Max() {
+  return TimeDelta(std::numeric_limits<int64>::max());
+}
+
+int TimeDelta::InDays() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int>::max();
+  }
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
+}
+
+int TimeDelta::InHours() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int>::max();
+  }
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
+}
+
+int TimeDelta::InMinutes() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int>::max();
+  }
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
+}
+
+double TimeDelta::InSecondsF() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
+}
+
+int64 TimeDelta::InSeconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return delta_ / Time::kMicrosecondsPerSecond;
+}
+
+double TimeDelta::InMillisecondsF() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMilliseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return delta_ / Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMillisecondsRoundedUp() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
+      Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMicroseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return delta_;
+}
+
+int64 TimeDelta::SaturatedAdd(int64 value) const {
+  CheckedNumeric<int64> rv(delta_);
+  rv += value;
+  return FromCheckedNumeric(rv);
+}
+
+int64 TimeDelta::SaturatedSub(int64 value) const {
+  CheckedNumeric<int64> rv(delta_);
+  rv -= value;
+  return FromCheckedNumeric(rv);
+}
+
+// static
+int64 TimeDelta::FromCheckedNumeric(const CheckedNumeric<int64> value) {
+  if (value.IsValid())
+    return value.ValueUnsafe();
+
+  // We could return max/min but we don't really expose what the maximum delta
+  // is. Instead, return max/(-max), which is something that clients can reason
+  // about.
+  // TODO(rvargas) crbug.com/332611: don't use internal values.
+  int64 limit = std::numeric_limits<int64>::max();
+  if (value.validity() == internal::RANGE_UNDERFLOW)
+    limit = -limit;
+  return value.ValueOrDefault(limit);
+}
+
+std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
+  return os << time_delta.InSecondsF() << "s";
+}
+
+// Time -----------------------------------------------------------------------
+
+// static
+Time Time::Max() {
+  return Time(std::numeric_limits<int64>::max());
+}
+
+// static
+Time Time::FromTimeT(time_t tt) {
+  if (tt == 0)
+    return Time();  // Preserve 0 so we can tell it doesn't exist.
+  if (tt == std::numeric_limits<time_t>::max())
+    return Max();
+  return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
+}
+
+time_t Time::ToTimeT() const {
+  if (is_null())
+    return 0;  // Preserve 0 so we can tell it doesn't exist.
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<time_t>::max();
+  }
+  if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) {
+    DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
+                     "value " << us_ << " to time_t.";
+    return std::numeric_limits<time_t>::max();
+  }
+  return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
+}
+
+// static
+Time Time::FromDoubleT(double dt) {
+  if (dt == 0 || std::isnan(dt))
+    return Time();  // Preserve 0 so we can tell it doesn't exist.
+  if (dt == std::numeric_limits<double>::infinity())
+    return Max();
+  return Time(static_cast<int64>((dt *
+                                  static_cast<double>(kMicrosecondsPerSecond)) +
+                                 kTimeTToMicrosecondsOffset));
+}
+
+double Time::ToDoubleT() const {
+  if (is_null())
+    return 0;  // Preserve 0 so we can tell it doesn't exist.
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+          static_cast<double>(kMicrosecondsPerSecond));
+}
+
+#if defined(OS_POSIX)
+// static
+Time Time::FromTimeSpec(const timespec& ts) {
+  return FromDoubleT(ts.tv_sec +
+                     static_cast<double>(ts.tv_nsec) /
+                         base::Time::kNanosecondsPerSecond);
+}
+#endif
+
+// static
+Time Time::FromJsTime(double ms_since_epoch) {
+  // The epoch is a valid time, so this constructor doesn't interpret
+  // 0 as the null time.
+  if (ms_since_epoch == std::numeric_limits<double>::infinity())
+    return Max();
+  return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) +
+              kTimeTToMicrosecondsOffset);
+}
+
+double Time::ToJsTime() const {
+  if (is_null()) {
+    // Preserve 0 so the invalid result doesn't depend on the platform.
+    return 0;
+  }
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+          kMicrosecondsPerMillisecond);
+}
+
+int64 Time::ToJavaTime() const {
+  if (is_null()) {
+    // Preserve 0 so the invalid result doesn't depend on the platform.
+    return 0;
+  }
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return ((us_ - kTimeTToMicrosecondsOffset) /
+          kMicrosecondsPerMillisecond);
+}
+
+// static
+Time Time::UnixEpoch() {
+  Time time;
+  time.us_ = kTimeTToMicrosecondsOffset;
+  return time;
+}
+
+Time Time::LocalMidnight() const {
+  Exploded exploded;
+  LocalExplode(&exploded);
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+  return FromLocalExploded(exploded);
+}
+
+// static
+bool Time::FromStringInternal(const char* time_string,
+                              bool is_local,
+                              Time* parsed_time) {
+  DCHECK((time_string != NULL) && (parsed_time != NULL));
+
+  if (time_string[0] == '\0')
+    return false;
+
+  PRTime result_time = 0;
+  PRStatus result = PR_ParseTimeString(time_string,
+                                       is_local ? PR_FALSE : PR_TRUE,
+                                       &result_time);
+  if (PR_SUCCESS != result)
+    return false;
+
+  result_time += kTimeTToMicrosecondsOffset;
+  *parsed_time = Time(result_time);
+  return true;
+}
+
+std::ostream& operator<<(std::ostream& os, Time time) {
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  // Use StringPrintf because iostreams formatting is painful.
+  return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC",
+                            exploded.year,
+                            exploded.month,
+                            exploded.day_of_month,
+                            exploded.hour,
+                            exploded.minute,
+                            exploded.second,
+                            exploded.millisecond);
+}
+
+// Local helper class to hold the conversion from Time to TickTime at the
+// time of the Unix epoch.
+class UnixEpochSingleton {
+ public:
+  UnixEpochSingleton()
+      : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {}
+
+  TimeTicks unix_epoch() const { return unix_epoch_; }
+
+ private:
+  const TimeTicks unix_epoch_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton);
+};
+
+static LazyInstance<UnixEpochSingleton>::Leaky
+    leaky_unix_epoch_singleton_instance = LAZY_INSTANCE_INITIALIZER;
+
+// Static
+TimeTicks TimeTicks::UnixEpoch() {
+  return leaky_unix_epoch_singleton_instance.Get().unix_epoch();
+}
+
+TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
+                                       TimeDelta tick_interval) const {
+  // |interval_offset| is the offset from |this| to the next multiple of
+  // |tick_interval| after |tick_phase|, possibly negative if in the past.
+  TimeDelta interval_offset = TimeDelta::FromInternalValue(
+      (tick_phase - *this).ToInternalValue() % tick_interval.ToInternalValue());
+  // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
+  // Otherwise, if |tick_phase| was in the past, adjust forward to the next
+  // tick after |this|.
+  if (interval_offset.ToInternalValue() != 0 && tick_phase < *this) {
+    interval_offset += tick_interval;
+  }
+
+  return *this + interval_offset;
+}
+
+std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
+  // This function formats a TimeTicks object as "bogo-microseconds".
+  // The origin and granularity of the count are platform-specific, and may very
+  // from run to run. Although bogo-microseconds usually roughly correspond to
+  // real microseconds, the only real guarantee is that the number never goes
+  // down during a single run.
+  const TimeDelta as_time_delta = time_ticks - TimeTicks();
+  return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
+}
+
+// Time::Exploded -------------------------------------------------------------
+
+inline bool is_in_range(int value, int lo, int hi) {
+  return lo <= value && value <= hi;
+}
+
+bool Time::Exploded::HasValidValues() const {
+  return is_in_range(month, 1, 12) &&
+         is_in_range(day_of_week, 0, 6) &&
+         is_in_range(day_of_month, 1, 31) &&
+         is_in_range(hour, 0, 23) &&
+         is_in_range(minute, 0, 59) &&
+         is_in_range(second, 0, 60) &&
+         is_in_range(millisecond, 0, 999);
+}
+
+}  // namespace base
diff --git a/base/time/time.h b/base/time/time.h
new file mode 100644
index 0000000..5c8b89c
--- /dev/null
+++ b/base/time/time.h
@@ -0,0 +1,791 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Time represents an absolute point in coordinated universal time (UTC),
+// internally represented as microseconds (s/1,000,000) since the Windows epoch
+// (1601-01-01 00:00:00 UTC) (See http://crbug.com/14734).  System-dependent
+// clock interface routines are defined in time_PLATFORM.cc.
+//
+// TimeDelta represents a duration of time, internally represented in
+// microseconds.
+//
+// TimeTicks represents an abstract time that is most of the time incrementing
+// for use in measuring time durations. It is internally represented in
+// microseconds.  It can not be converted to a human-readable time, but is
+// guaranteed not to decrease (if the user changes the computer clock,
+// Time::Now() may actually decrease or jump).  But note that TimeTicks may
+// "stand still", for example if the computer suspended.
+//
+// These classes are represented as only a 64-bit value, so they can be
+// efficiently passed by value.
+//
+// Definitions of operator<< are provided to make these types work with
+// DCHECK_EQ() and other log macros. For human-readable formatting, see
+// "base/i18n/time_formatting.h".
+
+#ifndef BASE_TIME_TIME_H_
+#define BASE_TIME_TIME_H_
+
+#include <time.h>
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/numerics/safe_math.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+// Avoid Mac system header macro leak.
+#undef TYPE_BOOL
+#endif
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#if defined(OS_WIN)
+// For FILETIME in FromFileTime, until it moves to a new converter class.
+// See TODO(iyengar) below.
+#include <windows.h>
+#endif
+
+#include <limits>
+
+namespace base {
+
+class Time;
+class TimeTicks;
+
+// TimeDelta ------------------------------------------------------------------
+
+class BASE_EXPORT TimeDelta {
+ public:
+  TimeDelta() : delta_(0) {
+  }
+
+  // Converts units of time to TimeDeltas.
+  static TimeDelta FromDays(int days);
+  static TimeDelta FromHours(int hours);
+  static TimeDelta FromMinutes(int minutes);
+  static TimeDelta FromSeconds(int64 secs);
+  static TimeDelta FromMilliseconds(int64 ms);
+  static TimeDelta FromSecondsD(double secs);
+  static TimeDelta FromMillisecondsD(double ms);
+  static TimeDelta FromMicroseconds(int64 us);
+#if defined(OS_WIN)
+  static TimeDelta FromQPCValue(LONGLONG qpc_value);
+#endif
+
+  // Converts an integer value representing TimeDelta to a class. This is used
+  // when deserializing a |TimeDelta| structure, using a value known to be
+  // compatible. It is not provided as a constructor because the integer type
+  // may be unclear from the perspective of a caller.
+  static TimeDelta FromInternalValue(int64 delta) {
+    return TimeDelta(delta);
+  }
+
+  // Returns the maximum time delta, which should be greater than any reasonable
+  // time delta we might compare it to. Adding or subtracting the maximum time
+  // delta to a time or another time delta has an undefined result.
+  static TimeDelta Max();
+
+  // Returns the internal numeric value of the TimeDelta object. Please don't
+  // use this and do arithmetic on it, as it is more error prone than using the
+  // provided operators.
+  // For serializing, use FromInternalValue to reconstitute.
+  int64 ToInternalValue() const {
+    return delta_;
+  }
+
+  // Returns the magnitude (absolute value) of this TimeDelta.
+  TimeDelta magnitude() const {
+    // Some toolchains provide an incomplete C++11 implementation and lack an
+    // int64 overload for std::abs().  The following is a simple branchless
+    // implementation:
+    const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1);
+    return TimeDelta((delta_ + mask) ^ mask);
+  }
+
+  // Returns true if the time delta is the maximum time delta.
+  bool is_max() const {
+    return delta_ == std::numeric_limits<int64>::max();
+  }
+
+#if defined(OS_POSIX)
+  struct timespec ToTimeSpec() const;
+#endif
+
+  // Returns the time delta in some unit. The F versions return a floating
+  // point value, the "regular" versions return a rounded-down value.
+  //
+  // InMillisecondsRoundedUp() instead returns an integer that is rounded up
+  // to the next full millisecond.
+  int InDays() const;
+  int InHours() const;
+  int InMinutes() const;
+  double InSecondsF() const;
+  int64 InSeconds() const;
+  double InMillisecondsF() const;
+  int64 InMilliseconds() const;
+  int64 InMillisecondsRoundedUp() const;
+  int64 InMicroseconds() const;
+
+  TimeDelta& operator=(TimeDelta other) {
+    delta_ = other.delta_;
+    return *this;
+  }
+
+  // Computations with other deltas.
+  TimeDelta operator+(TimeDelta other) const {
+    return TimeDelta(SaturatedAdd(other.delta_));
+  }
+  TimeDelta operator-(TimeDelta other) const {
+    return TimeDelta(SaturatedSub(other.delta_));
+  }
+
+  TimeDelta& operator+=(TimeDelta other) {
+    delta_ = SaturatedAdd(other.delta_);
+    return *this;
+  }
+  TimeDelta& operator-=(TimeDelta other) {
+    delta_ = SaturatedSub(other.delta_);
+    return *this;
+  }
+  TimeDelta operator-() const {
+    return TimeDelta(-delta_);
+  }
+
+  // Computations with numeric types.
+  template<typename T>
+  TimeDelta operator*(T a) const {
+    CheckedNumeric<int64> rv(delta_);
+    rv *= a;
+    return TimeDelta(FromCheckedNumeric(rv));
+  }
+  template<typename T>
+  TimeDelta operator/(T a) const {
+    CheckedNumeric<int64> rv(delta_);
+    rv /= a;
+    return TimeDelta(FromCheckedNumeric(rv));
+  }
+  template<typename T>
+  TimeDelta& operator*=(T a) {
+    CheckedNumeric<int64> rv(delta_);
+    rv *= a;
+    delta_ = FromCheckedNumeric(rv);
+    return *this;
+  }
+  template<typename T>
+  TimeDelta& operator/=(T a) {
+    CheckedNumeric<int64> rv(delta_);
+    rv /= a;
+    delta_ = FromCheckedNumeric(rv);
+    return *this;
+  }
+
+  int64 operator/(TimeDelta a) const {
+    return delta_ / a.delta_;
+  }
+
+  // Defined below because it depends on the definition of the other classes.
+  Time operator+(Time t) const;
+  TimeTicks operator+(TimeTicks t) const;
+
+  // Comparison operators.
+  bool operator==(TimeDelta other) const {
+    return delta_ == other.delta_;
+  }
+  bool operator!=(TimeDelta other) const {
+    return delta_ != other.delta_;
+  }
+  bool operator<(TimeDelta other) const {
+    return delta_ < other.delta_;
+  }
+  bool operator<=(TimeDelta other) const {
+    return delta_ <= other.delta_;
+  }
+  bool operator>(TimeDelta other) const {
+    return delta_ > other.delta_;
+  }
+  bool operator>=(TimeDelta other) const {
+    return delta_ >= other.delta_;
+  }
+
+ private:
+  friend class Time;
+  friend class TimeTicks;
+
+  // Constructs a delta given the duration in microseconds. This is private
+  // to avoid confusion by callers with an integer constructor. Use
+  // FromSeconds, FromMilliseconds, etc. instead.
+  explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
+  }
+
+  // Add or subtract |value| from this delta.
+  int64 SaturatedAdd(int64 value) const;
+  int64 SaturatedSub(int64 value) const;
+
+  // Clamp |value| on overflow and underflow conditions.
+  static int64 FromCheckedNumeric(const CheckedNumeric<int64> value);
+
+  // Delta in microseconds.
+  int64 delta_;
+};
+
+template<typename T>
+inline TimeDelta operator*(T a, TimeDelta td) {
+  return td * a;
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeDelta time_delta);
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time in UTC.
+class BASE_EXPORT Time {
+ public:
+  static const int64 kHoursPerDay = 24;
+  static const int64 kMillisecondsPerSecond = 1000;
+  static const int64 kMillisecondsPerDay = kMillisecondsPerSecond * 60 * 60 *
+                                           kHoursPerDay;
+  static const int64 kMicrosecondsPerMillisecond = 1000;
+  static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
+                                              kMillisecondsPerSecond;
+  static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+  static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+  static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * kHoursPerDay;
+  static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+  static const int64 kNanosecondsPerMicrosecond = 1000;
+  static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
+                                             kMicrosecondsPerSecond;
+
+  // The representation of Jan 1, 1970 UTC in microseconds since the
+  // platform-dependent epoch.
+  static const int64 kTimeTToMicrosecondsOffset;
+
+#if !defined(OS_WIN)
+  // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
+  // the Posix delta of 1970. This is used for migrating between the old
+  // 1970-based epochs to the new 1601-based ones. It should be removed from
+  // this global header and put in the platform-specific ones when we remove the
+  // migration code.
+  static const int64 kWindowsEpochDeltaMicroseconds;
+#else
+  // To avoid overflow in QPC to Microseconds calculations, since we multiply
+  // by kMicrosecondsPerSecond, then the QPC value should not exceed
+  // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
+  static const int64 kQPCOverflowThreshold = 0x8637BD05AF7;
+#endif
+
+  // Represents an exploded time that can be formatted nicely. This is kind of
+  // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few
+  // additions and changes to prevent errors.
+  struct BASE_EXPORT Exploded {
+    int year;          // Four digit year "2007"
+    int month;         // 1-based month (values 1 = January, etc.)
+    int day_of_week;   // 0-based day of week (0 = Sunday, etc.)
+    int day_of_month;  // 1-based day of month (1-31)
+    int hour;          // Hour within the current day (0-23)
+    int minute;        // Minute within the current hour (0-59)
+    int second;        // Second within the current minute (0-59 plus leap
+                       //   seconds which may take it up to 60).
+    int millisecond;   // Milliseconds within the current second (0-999)
+
+    // A cursory test for whether the data members are within their
+    // respective ranges. A 'true' return value does not guarantee the
+    // Exploded value can be successfully converted to a Time value.
+    bool HasValidValues() const;
+  };
+
+  // Contains the NULL time. Use Time::Now() to get the current time.
+  Time() : us_(0) {
+  }
+
+  // Returns true if the time object has not been initialized.
+  bool is_null() const {
+    return us_ == 0;
+  }
+
+  // Returns true if the time object is the maximum time.
+  bool is_max() const {
+    return us_ == std::numeric_limits<int64>::max();
+  }
+
+  // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+  static Time UnixEpoch();
+
+  // Returns the current time. Watch out, the system might adjust its clock
+  // in which case time will actually go backwards. We don't guarantee that
+  // times are increasing, or that two calls to Now() won't be the same.
+  static Time Now();
+
+  // Returns the maximum time, which should be greater than any reasonable time
+  // with which we might compare it.
+  static Time Max();
+
+  // Returns the current time. Same as Now() except that this function always
+  // uses system time so that there are no discrepancies between the returned
+  // time and system time even on virtual environments including our test bot.
+  // For timing sensitive unittests, this function should be used.
+  static Time NowFromSystemTime();
+
+  // Converts to/from time_t in UTC and a Time class.
+  // TODO(brettw) this should be removed once everybody starts using the |Time|
+  // class.
+  static Time FromTimeT(time_t tt);
+  time_t ToTimeT() const;
+
+  // Converts time to/from a double which is the number of seconds since epoch
+  // (Jan 1, 1970).  Webkit uses this format to represent time.
+  // Because WebKit initializes double time value to 0 to indicate "not
+  // initialized", we map it to empty Time object that also means "not
+  // initialized".
+  static Time FromDoubleT(double dt);
+  double ToDoubleT() const;
+
+#if defined(OS_POSIX)
+  // Converts the timespec structure to time. MacOS X 10.8.3 (and tentatively,
+  // earlier versions) will have the |ts|'s tv_nsec component zeroed out,
+  // having a 1 second resolution, which agrees with
+  // https://developer.apple.com/legacy/library/#technotes/tn/tn1150.html#HFSPlusDates.
+  static Time FromTimeSpec(const timespec& ts);
+#endif
+
+  // Converts to/from the Javascript convention for times, a number of
+  // milliseconds since the epoch:
+  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTime.
+  static Time FromJsTime(double ms_since_epoch);
+  double ToJsTime() const;
+
+  // Converts to Java convention for times, a number of
+  // milliseconds since the epoch.
+  int64 ToJavaTime() const;
+
+#if defined(OS_POSIX)
+  static Time FromTimeVal(struct timeval t);
+  struct timeval ToTimeVal() const;
+#endif
+
+#if defined(OS_MACOSX)
+  static Time FromCFAbsoluteTime(CFAbsoluteTime t);
+  CFAbsoluteTime ToCFAbsoluteTime() const;
+#endif
+
+#if defined(OS_WIN)
+  static Time FromFileTime(FILETIME ft);
+  FILETIME ToFileTime() const;
+
+  // The minimum time of a low resolution timer.  This is basically a windows
+  // constant of ~15.6ms.  While it does vary on some older OS versions, we'll
+  // treat it as static across all windows versions.
+  static const int kMinLowResolutionThresholdMs = 16;
+
+  // Enable or disable Windows high resolution timer.
+  static void EnableHighResolutionTimer(bool enable);
+
+  // Activates or deactivates the high resolution timer based on the |activate|
+  // flag.  If the HighResolutionTimer is not Enabled (see
+  // EnableHighResolutionTimer), this function will return false.  Otherwise
+  // returns true.  Each successful activate call must be paired with a
+  // subsequent deactivate call.
+  // All callers to activate the high resolution timer must eventually call
+  // this function to deactivate the high resolution timer.
+  static bool ActivateHighResolutionTimer(bool activate);
+
+  // Returns true if the high resolution timer is both enabled and activated.
+  // This is provided for testing only, and is not tracked in a thread-safe
+  // way.
+  static bool IsHighResolutionTimerInUse();
+#endif
+
+  // Converts an exploded structure representing either the local time or UTC
+  // into a Time class.
+  static Time FromUTCExploded(const Exploded& exploded) {
+    return FromExploded(false, exploded);
+  }
+  static Time FromLocalExploded(const Exploded& exploded) {
+    return FromExploded(true, exploded);
+  }
+
+  // Converts an integer value representing Time to a class. This is used
+  // when deserializing a |Time| structure, using a value known to be
+  // compatible. It is not provided as a constructor because the integer type
+  // may be unclear from the perspective of a caller.
+  static Time FromInternalValue(int64 us) {
+    return Time(us);
+  }
+
+  // Converts a string representation of time to a Time object.
+  // An example of a time string which is converted is as below:-
+  // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+  // in the input string, FromString assumes local time and FromUTCString
+  // assumes UTC. A timezone that cannot be parsed (e.g. "UTC" which is not
+  // specified in RFC822) is treated as if the timezone is not specified.
+  // TODO(iyengar) Move the FromString/FromTimeT/ToTimeT/FromFileTime to
+  // a new time converter class.
+  static bool FromString(const char* time_string, Time* parsed_time) {
+    return FromStringInternal(time_string, true, parsed_time);
+  }
+  static bool FromUTCString(const char* time_string, Time* parsed_time) {
+    return FromStringInternal(time_string, false, parsed_time);
+  }
+
+  // For serializing, use FromInternalValue to reconstitute. Please don't use
+  // this and do arithmetic on it, as it is more error prone than using the
+  // provided operators.
+  int64 ToInternalValue() const {
+    return us_;
+  }
+
+  // Fills the given exploded structure with either the local time or UTC from
+  // this time structure (containing UTC).
+  void UTCExplode(Exploded* exploded) const {
+    return Explode(false, exploded);
+  }
+  void LocalExplode(Exploded* exploded) const {
+    return Explode(true, exploded);
+  }
+
+  // Rounds this time down to the nearest day in local time. It will represent
+  // midnight on that day.
+  Time LocalMidnight() const;
+
+  Time& operator=(Time other) {
+    us_ = other.us_;
+    return *this;
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(Time other) const {
+    return TimeDelta(us_ - other.us_);
+  }
+
+  // Modify by some time delta.
+  Time& operator+=(TimeDelta delta) {
+    us_ = delta.SaturatedAdd(us_);
+    return *this;
+  }
+  Time& operator-=(TimeDelta delta) {
+    us_ = -delta.SaturatedSub(us_);
+    return *this;
+  }
+
+  // Return a new time modified by some delta.
+  Time operator+(TimeDelta delta) const {
+    return Time(delta.SaturatedAdd(us_));
+  }
+  Time operator-(TimeDelta delta) const {
+    return Time(-delta.SaturatedSub(us_));
+  }
+
+  // Comparison operators
+  bool operator==(Time other) const {
+    return us_ == other.us_;
+  }
+  bool operator!=(Time other) const {
+    return us_ != other.us_;
+  }
+  bool operator<(Time other) const {
+    return us_ < other.us_;
+  }
+  bool operator<=(Time other) const {
+    return us_ <= other.us_;
+  }
+  bool operator>(Time other) const {
+    return us_ > other.us_;
+  }
+  bool operator>=(Time other) const {
+    return us_ >= other.us_;
+  }
+
+ private:
+  friend class TimeDelta;
+
+  explicit Time(int64 us) : us_(us) {
+  }
+
+  // Explodes the given time to either local time |is_local = true| or UTC
+  // |is_local = false|.
+  void Explode(bool is_local, Exploded* exploded) const;
+
+  // Unexplodes a given time assuming the source is either local time
+  // |is_local = true| or UTC |is_local = false|.
+  static Time FromExploded(bool is_local, const Exploded& exploded);
+
+  // Converts a string representation of time to a Time object.
+  // An example of a time string which is converted is as below:-
+  // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+  // in the input string, local time |is_local = true| or
+  // UTC |is_local = false| is assumed. A timezone that cannot be parsed
+  // (e.g. "UTC" which is not specified in RFC822) is treated as if the
+  // timezone is not specified.
+  static bool FromStringInternal(const char* time_string,
+                                 bool is_local,
+                                 Time* parsed_time);
+
+  // Time in microseconds in UTC.
+  int64 us_;
+};
+
+// Inline the TimeDelta factory methods, for fast TimeDelta construction.
+
+// static
+inline TimeDelta TimeDelta::FromDays(int days) {
+  // Preserve max to prevent overflow.
+  if (days == std::numeric_limits<int>::max())
+    return Max();
+  return TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+inline TimeDelta TimeDelta::FromHours(int hours) {
+  // Preserve max to prevent overflow.
+  if (hours == std::numeric_limits<int>::max())
+    return Max();
+  return TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMinutes(int minutes) {
+  // Preserve max to prevent overflow.
+  if (minutes == std::numeric_limits<int>::max())
+    return Max();
+  return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
+  // Preserve max to prevent overflow.
+  if (secs == std::numeric_limits<int64>::max())
+    return Max();
+  return TimeDelta(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
+  // Preserve max to prevent overflow.
+  if (ms == std::numeric_limits<int64>::max())
+    return Max();
+  return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSecondsD(double secs) {
+  // Preserve max to prevent overflow.
+  if (secs == std::numeric_limits<double>::infinity())
+    return Max();
+  return TimeDelta(static_cast<int64>(secs * Time::kMicrosecondsPerSecond));
+}
+
+// static
+inline TimeDelta TimeDelta::FromMillisecondsD(double ms) {
+  // Preserve max to prevent overflow.
+  if (ms == std::numeric_limits<double>::infinity())
+    return Max();
+  return TimeDelta(static_cast<int64>(ms * Time::kMicrosecondsPerMillisecond));
+}
+
+// static
+inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
+  // Preserve max to prevent overflow.
+  if (us == std::numeric_limits<int64>::max())
+    return Max();
+  return TimeDelta(us);
+}
+
+inline Time TimeDelta::operator+(Time t) const {
+  return Time(SaturatedAdd(t.us_));
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time);
+
+// TimeTicks ------------------------------------------------------------------
+
+class BASE_EXPORT TimeTicks {
+ public:
+  // We define this even without OS_CHROMEOS for seccomp sandbox testing.
+#if defined(OS_LINUX)
+  // Force definition of the system trace clock; it is a chromeos-only api
+  // at the moment and surfacing it in the right place requires mucking
+  // with glibc et al.
+  static const clockid_t kClockSystemTrace = 11;
+#endif
+
+  TimeTicks() : ticks_(0) {
+  }
+
+  // Platform-dependent tick count representing "right now." When
+  // IsHighResolution() returns false, the resolution of the clock could be
+  // as coarse as ~15.6ms. Otherwise, the resolution should be no worse than one
+  // microsecond.
+  static TimeTicks Now();
+
+  // Returns true if the high resolution clock is working on this system and
+  // Now() will return high resolution values. Note that, on systems where the
+  // high resolution clock works but is deemed inefficient, the low resolution
+  // clock will be used instead.
+  static bool IsHighResolution();
+
+  // Returns true if ThreadNow() is supported on this system.
+  static bool IsThreadNowSupported() {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
+    return true;
+#else
+    return false;
+#endif
+  }
+
+  // Returns thread-specific CPU-time on systems that support this feature.
+  // Needs to be guarded with a call to IsThreadNowSupported(). Use this timer
+  // to (approximately) measure how much time the calling thread spent doing
+  // actual work vs. being de-scheduled. May return bogus results if the thread
+  // migrates to another CPU between two calls.
+  //
+  // WARNING: The returned value might NOT have the same origin as Now(). Do not
+  // perform math between TimeTicks values returned by Now() and ThreadNow() and
+  // expect meaningful results.
+  // TODO(miu): Since the timeline of these values is different, the values
+  // should be of a different type.
+  static TimeTicks ThreadNow();
+
+  // Returns the current system trace time or, if not available on this
+  // platform, a high-resolution time value; or a low-resolution time value if
+  // neither are avalable. On systems where a global trace clock is defined,
+  // timestamping TraceEvents's with this value guarantees synchronization
+  // between events collected inside chrome and events collected outside
+  // (e.g. kernel, X server).
+  //
+  // WARNING: The returned value might NOT have the same origin as Now(). Do not
+  // perform math between TimeTicks values returned by Now() and
+  // NowFromSystemTraceTime() and expect meaningful results.
+  // TODO(miu): Since the timeline of these values is different, the values
+  // should be of a different type.
+  static TimeTicks NowFromSystemTraceTime();
+
+#if defined(OS_WIN)
+  // Translates an absolute QPC timestamp into a TimeTicks value. The returned
+  // value has the same origin as Now(). Do NOT attempt to use this if
+  // IsHighResolution() returns false.
+  static TimeTicks FromQPCValue(LONGLONG qpc_value);
+#endif
+
+  // Returns true if this object has not been initialized.
+  bool is_null() const {
+    return ticks_ == 0;
+  }
+
+  // Returns true if the time delta is the maximum delta.
+  bool is_max() const {
+    return ticks_ == std::numeric_limits<int64>::max();
+  }
+
+  // Converts an integer value representing TimeTicks to a class. This is used
+  // when deserializing a |TimeTicks| structure, using a value known to be
+  // compatible. It is not provided as a constructor because the integer type
+  // may be unclear from the perspective of a caller.
+  static TimeTicks FromInternalValue(int64 ticks) {
+    return TimeTicks(ticks);
+  }
+
+  // Get the TimeTick value at the time of the UnixEpoch. This is useful when
+  // you need to relate the value of TimeTicks to a real time and date.
+  // Note: Upon first invocation, this function takes a snapshot of the realtime
+  // clock to establish a reference point.  This function will return the same
+  // value for the duration of the application, but will be different in future
+  // application runs.
+  static TimeTicks UnixEpoch();
+
+  // Returns the internal numeric value of the TimeTicks object.
+  // For serializing, use FromInternalValue to reconstitute.
+  int64 ToInternalValue() const {
+    return ticks_;
+  }
+
+  // Returns |this| snapped to the next tick, given a |tick_phase| and
+  // repeating |tick_interval| in both directions. |this| may be before,
+  // after, or equal to the |tick_phase|.
+  TimeTicks SnappedToNextTick(TimeTicks tick_phase,
+                              TimeDelta tick_interval) const;
+
+  TimeTicks& operator=(TimeTicks other) {
+    ticks_ = other.ticks_;
+    return *this;
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(TimeTicks other) const {
+    return TimeDelta(ticks_ - other.ticks_);
+  }
+
+  // Modify by some time delta.
+  TimeTicks& operator+=(TimeDelta delta) {
+    ticks_ = delta.SaturatedAdd(ticks_);
+    return *this;
+  }
+  TimeTicks& operator-=(TimeDelta delta) {
+    ticks_ = -delta.SaturatedSub(ticks_);
+    return *this;
+  }
+
+  // Return a new TimeTicks modified by some delta.
+  TimeTicks operator+(TimeDelta delta) const {
+    return TimeTicks(delta.SaturatedAdd(ticks_));
+  }
+  TimeTicks operator-(TimeDelta delta) const {
+    return TimeTicks(-delta.SaturatedSub(ticks_));
+  }
+
+  // Comparison operators
+  bool operator==(TimeTicks other) const {
+    return ticks_ == other.ticks_;
+  }
+  bool operator!=(TimeTicks other) const {
+    return ticks_ != other.ticks_;
+  }
+  bool operator<(TimeTicks other) const {
+    return ticks_ < other.ticks_;
+  }
+  bool operator<=(TimeTicks other) const {
+    return ticks_ <= other.ticks_;
+  }
+  bool operator>(TimeTicks other) const {
+    return ticks_ > other.ticks_;
+  }
+  bool operator>=(TimeTicks other) const {
+    return ticks_ >= other.ticks_;
+  }
+
+ protected:
+  friend class TimeDelta;
+
+  // Please use Now() to create a new object. This is for internal use
+  // and testing. Ticks is in microseconds.
+  explicit TimeTicks(int64 ticks) : ticks_(ticks) {
+  }
+
+  // Tick count in microseconds.
+  int64 ticks_;
+
+#if defined(OS_WIN)
+  typedef DWORD (*TickFunctionType)(void);
+  static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
+#endif
+};
+
+inline TimeTicks TimeDelta::operator+(TimeTicks t) const {
+  return TimeTicks(SaturatedAdd(t.ticks_));
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks);
+
+}  // namespace base
+
+#endif  // BASE_TIME_TIME_H_
diff --git a/base/time/time_mac.cc b/base/time/time_mac.cc
new file mode 100644
index 0000000..e263d07
--- /dev/null
+++ b/base/time/time_mac.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/time/time.h"
+
+#include <CoreFoundation/CFDate.h>
+#include <CoreFoundation/CFTimeZone.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_mach_port.h"
+
+namespace {
+
+uint64_t ComputeCurrentTicks() {
+#if defined(OS_IOS)
+  // On iOS mach_absolute_time stops while the device is sleeping. Instead use
+  // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
+  // changes. KERN_BOOTTIME will be updated by the system whenever the system
+  // clock change.
+  struct timeval boottime;
+  int mib[2] = {CTL_KERN, KERN_BOOTTIME};
+  size_t size = sizeof(boottime);
+  int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
+  DCHECK_EQ(KERN_SUCCESS, kr);
+  base::TimeDelta time_difference = base::Time::Now() -
+      (base::Time::FromTimeT(boottime.tv_sec) +
+       base::TimeDelta::FromMicroseconds(boottime.tv_usec));
+  return time_difference.InMicroseconds();
+#else
+  uint64_t absolute_micro;
+
+  static mach_timebase_info_data_t timebase_info;
+  if (timebase_info.denom == 0) {
+    // Zero-initialization of statics guarantees that denom will be 0 before
+    // calling mach_timebase_info.  mach_timebase_info will never set denom to
+    // 0 as that would be invalid, so the zero-check can be used to determine
+    // whether mach_timebase_info has already been called.  This is
+    // recommended by Apple's QA1398.
+    kern_return_t kr = mach_timebase_info(&timebase_info);
+    MACH_DCHECK(kr == KERN_SUCCESS, kr) << "mach_timebase_info";
+  }
+
+  // mach_absolute_time is it when it comes to ticks on the Mac.  Other calls
+  // with less precision (such as TickCount) just call through to
+  // mach_absolute_time.
+
+  // timebase_info converts absolute time tick units into nanoseconds.  Convert
+  // to microseconds up front to stave off overflows.
+  absolute_micro =
+      mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond *
+      timebase_info.numer / timebase_info.denom;
+
+  // Don't bother with the rollover handling that the Windows version does.
+  // With numer and denom = 1 (the expected case), the 64-bit absolute time
+  // reported in nanoseconds is enough to last nearly 585 years.
+  return absolute_micro;
+#endif  // defined(OS_IOS)
+}
+
+uint64_t ComputeThreadTicks() {
+#if defined(OS_IOS)
+  NOTREACHED();
+  return 0;
+#else
+  base::mac::ScopedMachSendRight thread(mach_thread_self());
+  mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
+  thread_basic_info_data_t thread_info_data;
+
+  if (thread.get() == MACH_PORT_NULL) {
+    DLOG(ERROR) << "Failed to get mach_thread_self()";
+    return 0;
+  }
+
+  kern_return_t kr = thread_info(
+      thread,
+      THREAD_BASIC_INFO,
+      reinterpret_cast<thread_info_t>(&thread_info_data),
+      &thread_info_count);
+  MACH_DCHECK(kr == KERN_SUCCESS, kr) << "thread_info";
+
+  return (thread_info_data.user_time.seconds *
+              base::Time::kMicrosecondsPerSecond) +
+         thread_info_data.user_time.microseconds;
+#endif  // defined(OS_IOS)
+}
+
+}  // namespace
+
+namespace base {
+
+// The Time routines in this file use Mach and CoreFoundation APIs, since the
+// POSIX definition of time_t in Mac OS X wraps around after 2038--and
+// there are already cookie expiration dates, etc., past that time out in
+// the field.  Using CFDate prevents that problem, and using mach_absolute_time
+// for TimeTicks gives us nice high-resolution interval timing.
+
+// Time -----------------------------------------------------------------------
+
+// Core Foundation uses a double second count since 2001-01-01 00:00:00 UTC.
+// The UNIX epoch is 1970-01-01 00:00:00 UTC.
+// Windows uses a Gregorian epoch of 1601.  We need to match this internally
+// so that our time representations match across all platforms.  See bug 14734.
+//   irb(main):010:0> Time.at(0).getutc()
+//   => Thu Jan 01 00:00:00 UTC 1970
+//   irb(main):011:0> Time.at(-11644473600).getutc()
+//   => Mon Jan 01 00:00:00 UTC 1601
+static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
+
+// static
+const int64 Time::kWindowsEpochDeltaMicroseconds =
+    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
+
+// Some functions in time.cc use time_t directly, so we provide an offset
+// to convert from time_t (Unix epoch) and internal (Windows epoch).
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  return FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent());
+}
+
+// static
+Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
+  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
+  if (t == 0)
+    return Time();  // Consider 0 as a null Time.
+  if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
+    return Max();
+  return Time(static_cast<int64>(
+      (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+CFAbsoluteTime Time::ToCFAbsoluteTime() const {
+  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
+  if (is_null())
+    return 0;  // Consider 0 as a null Time.
+  if (is_max())
+    return std::numeric_limits<CFAbsoluteTime>::infinity();
+  return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
+      kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Just use Now() because Now() returns the system time.
+  return Now();
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  CFGregorianDate date;
+  date.second = exploded.second +
+      exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
+  date.minute = exploded.minute;
+  date.hour = exploded.hour;
+  date.day = exploded.day_of_month;
+  date.month = exploded.month;
+  date.year = exploded.year;
+
+  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
+      is_local ? CFTimeZoneCopySystem() : NULL);
+  CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
+      kCFAbsoluteTimeIntervalSince1970;
+  return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  // Avoid rounding issues, by only putting the integral number of seconds
+  // (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
+  int64 microsecond = us_ % kMicrosecondsPerSecond;
+  if (microsecond < 0)
+    microsecond += kMicrosecondsPerSecond;
+  CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
+                           kWindowsEpochDeltaSeconds -
+                           kCFAbsoluteTimeIntervalSince1970;
+
+  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
+      is_local ? CFTimeZoneCopySystem() : NULL);
+  CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
+  // 1 = Monday, ..., 7 = Sunday.
+  int cf_day_of_week = CFAbsoluteTimeGetDayOfWeek(seconds, time_zone);
+
+  exploded->year = date.year;
+  exploded->month = date.month;
+  exploded->day_of_week = cf_day_of_week % 7;
+  exploded->day_of_month = date.day;
+  exploded->hour = date.hour;
+  exploded->minute = date.minute;
+  // Make sure seconds are rounded down towards -infinity.
+  exploded->second = floor(date.second);
+  // Calculate milliseconds ourselves, since we rounded the |seconds|, making
+  // sure to round towards -infinity.
+  exploded->millisecond =
+      (microsecond >= 0) ? microsecond / kMicrosecondsPerMillisecond :
+                           (microsecond - kMicrosecondsPerMillisecond + 1) /
+                               kMicrosecondsPerMillisecond;
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+// static
+TimeTicks TimeTicks::Now() {
+  return TimeTicks(ComputeCurrentTicks());
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+  return true;
+}
+
+// static
+TimeTicks TimeTicks::ThreadNow() {
+  return TimeTicks(ComputeThreadTicks());
+}
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  return Now();
+}
+
+}  // namespace base
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
new file mode 100644
index 0000000..8b207eb
--- /dev/null
+++ b/base/time/time_posix.cc
@@ -0,0 +1,395 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <time.h>
+#if defined(OS_ANDROID) && !defined(__LP64__)
+#include <time64.h>
+#endif
+#include <unistd.h>
+
+#include <limits>
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/port.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"
+#endif
+
+#if !defined(OS_MACOSX)
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace {
+
+#if !defined(OS_MACOSX)
+// This prevents a crash on traversing the environment global and looking up
+// the 'TZ' variable in libc. See: crbug.com/390567.
+base::LazyInstance<base::Lock>::Leaky
+    g_sys_time_to_time_struct_lock = LAZY_INSTANCE_INITIALIZER;
+
+// Define a system-specific SysTime that wraps either to a time_t or
+// a time64_t depending on the host system, and associated convertion.
+// See crbug.com/162007
+#if defined(OS_ANDROID) && !defined(__LP64__)
+typedef time64_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    return mktime64(timestruct);
+  else
+    return timegm64(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    localtime64_r(&t, timestruct);
+  else
+    gmtime64_r(&t, timestruct);
+}
+
+#else  // OS_ANDROID && !__LP64__
+typedef time_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    return mktime(timestruct);
+  else
+    return timegm(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    localtime_r(&t, timestruct);
+  else
+    gmtime_r(&t, timestruct);
+}
+#endif  // OS_ANDROID
+
+// Helper function to get results from clock_gettime() as TimeTicks object.
+// Minimum requirement is MONOTONIC_CLOCK to be supported on the system.
+// FreeBSD 6 has CLOCK_MONOTONIC but defines _POSIX_MONOTONIC_CLOCK to -1.
+#if (defined(OS_POSIX) &&                                               \
+     defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
+    defined(OS_BSD) || defined(OS_ANDROID)
+base::TimeTicks ClockNow(clockid_t clk_id) {
+  uint64_t absolute_micro;
+
+  struct timespec ts;
+  if (clock_gettime(clk_id, &ts) != 0) {
+    NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
+    return base::TimeTicks();
+  }
+
+  absolute_micro =
+      (static_cast<int64>(ts.tv_sec) * base::Time::kMicrosecondsPerSecond) +
+      (static_cast<int64>(ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond));
+
+  return base::TimeTicks::FromInternalValue(absolute_micro);
+}
+#else  // _POSIX_MONOTONIC_CLOCK
+#error No usable tick clock function on this platform.
+#endif  // _POSIX_MONOTONIC_CLOCK
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace
+
+namespace base {
+
+struct timespec TimeDelta::ToTimeSpec() const {
+  int64 microseconds = InMicroseconds();
+  time_t seconds = 0;
+  if (microseconds >= Time::kMicrosecondsPerSecond) {
+    seconds = InSeconds();
+    microseconds -= seconds * Time::kMicrosecondsPerSecond;
+  }
+  struct timespec result =
+      {seconds,
+       static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)};
+  return result;
+}
+
+#if !defined(OS_MACOSX)
+// The Time routines in this file use standard POSIX routines, or almost-
+// standard routines in the case of timegm.  We need to use a Mach-specific
+// function for TimeTicks::Now() on Mac OS X.
+
+// Time -----------------------------------------------------------------------
+
+// Windows uses a Gregorian epoch of 1601.  We need to match this internally
+// so that our time representations match across all platforms.  See bug 14734.
+//   irb(main):010:0> Time.at(0).getutc()
+//   => Thu Jan 01 00:00:00 UTC 1970
+//   irb(main):011:0> Time.at(-11644473600).getutc()
+//   => Mon Jan 01 00:00:00 UTC 1601
+static const int64 kWindowsEpochDeltaSeconds = GG_INT64_C(11644473600);
+
+// static
+const int64 Time::kWindowsEpochDeltaMicroseconds =
+    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
+
+// Some functions in time.cc use time_t directly, so we provide an offset
+// to convert from time_t (Unix epoch) and internal (Windows epoch).
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  struct timeval tv;
+  struct timezone tz = { 0, 0 };  // UTC
+  if (gettimeofday(&tv, &tz) != 0) {
+    DCHECK(0) << "Could not determine time of day";
+    PLOG(ERROR) << "Call to gettimeofday failed.";
+    // Return null instead of uninitialized |tv| value, which contains random
+    // garbage data. This may result in the crash seen in crbug.com/147570.
+    return Time();
+  }
+  // Combine seconds and microseconds in a 64-bit field containing microseconds
+  // since the epoch.  That's enough for nearly 600 centuries.  Adjust from
+  // Unix (1970) to Windows (1601) epoch.
+  return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Just use Now() because Now() returns the system time.
+  return Now();
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  // Time stores times with microsecond resolution, but Exploded only carries
+  // millisecond resolution, so begin by being lossy.  Adjust from Windows
+  // epoch (1601) to Unix epoch (1970);
+  int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds;
+  // The following values are all rounded towards -infinity.
+  int64 milliseconds;  // Milliseconds since epoch.
+  SysTime seconds;  // Seconds since epoch.
+  int millisecond;  // Exploded millisecond value (0-999).
+  if (microseconds >= 0) {
+    // Rounding towards -infinity <=> rounding towards 0, in this case.
+    milliseconds = microseconds / kMicrosecondsPerMillisecond;
+    seconds = milliseconds / kMillisecondsPerSecond;
+    millisecond = milliseconds % kMillisecondsPerSecond;
+  } else {
+    // Round these *down* (towards -infinity).
+    milliseconds = (microseconds - kMicrosecondsPerMillisecond + 1) /
+                   kMicrosecondsPerMillisecond;
+    seconds = (milliseconds - kMillisecondsPerSecond + 1) /
+              kMillisecondsPerSecond;
+    // Make this nonnegative (and between 0 and 999 inclusive).
+    millisecond = milliseconds % kMillisecondsPerSecond;
+    if (millisecond < 0)
+      millisecond += kMillisecondsPerSecond;
+  }
+
+  struct tm timestruct;
+  SysTimeToTimeStruct(seconds, &timestruct, is_local);
+
+  exploded->year         = timestruct.tm_year + 1900;
+  exploded->month        = timestruct.tm_mon + 1;
+  exploded->day_of_week  = timestruct.tm_wday;
+  exploded->day_of_month = timestruct.tm_mday;
+  exploded->hour         = timestruct.tm_hour;
+  exploded->minute       = timestruct.tm_min;
+  exploded->second       = timestruct.tm_sec;
+  exploded->millisecond  = millisecond;
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  struct tm timestruct;
+  timestruct.tm_sec    = exploded.second;
+  timestruct.tm_min    = exploded.minute;
+  timestruct.tm_hour   = exploded.hour;
+  timestruct.tm_mday   = exploded.day_of_month;
+  timestruct.tm_mon    = exploded.month - 1;
+  timestruct.tm_year   = exploded.year - 1900;
+  timestruct.tm_wday   = exploded.day_of_week;  // mktime/timegm ignore this
+  timestruct.tm_yday   = 0;     // mktime/timegm ignore this
+  timestruct.tm_isdst  = -1;    // attempt to figure it out
+#if !defined(OS_NACL) && !defined(OS_SOLARIS)
+  timestruct.tm_gmtoff = 0;     // not a POSIX field, so mktime/timegm ignore
+  timestruct.tm_zone   = NULL;  // not a POSIX field, so mktime/timegm ignore
+#endif
+
+
+  int64 milliseconds;
+  SysTime seconds;
+
+  // Certain exploded dates do not really exist due to daylight saving times,
+  // and this causes mktime() to return implementation-defined values when
+  // tm_isdst is set to -1. On Android, the function will return -1, while the
+  // C libraries of other platforms typically return a liberally-chosen value.
+  // Handling this requires the special code below.
+
+  // SysTimeFromTimeStruct() modifies the input structure, save current value.
+  struct tm timestruct0 = timestruct;
+
+  seconds = SysTimeFromTimeStruct(&timestruct, is_local);
+  if (seconds == -1) {
+    // Get the time values with tm_isdst == 0 and 1, then select the closest one
+    // to UTC 00:00:00 that isn't -1.
+    timestruct = timestruct0;
+    timestruct.tm_isdst = 0;
+    int64 seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+    timestruct = timestruct0;
+    timestruct.tm_isdst = 1;
+    int64 seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+    // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
+    // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
+    if (seconds_isdst0 < 0)
+      seconds = seconds_isdst1;
+    else if (seconds_isdst1 < 0)
+      seconds = seconds_isdst0;
+    else
+      seconds = std::min(seconds_isdst0, seconds_isdst1);
+  }
+
+  // Handle overflow.  Clamping the range to what mktime and timegm might
+  // return is the best that can be done here.  It's not ideal, but it's better
+  // than failing here or ignoring the overflow case and treating each time
+  // overflow as one second prior to the epoch.
+  if (seconds == -1 &&
+      (exploded.year < 1969 || exploded.year > 1970)) {
+    // If exploded.year is 1969 or 1970, take -1 as correct, with the
+    // time indicating 1 second prior to the epoch.  (1970 is allowed to handle
+    // time zone and DST offsets.)  Otherwise, return the most future or past
+    // time representable.  Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
+    //
+    // The minimum and maximum representible times that mktime and timegm could
+    // return are used here instead of values outside that range to allow for
+    // proper round-tripping between exploded and counter-type time
+    // representations in the presence of possible truncation to time_t by
+    // division and use with other functions that accept time_t.
+    //
+    // When representing the most distant time in the future, add in an extra
+    // 999ms to avoid the time being less than any other possible value that
+    // this function can return.
+
+    // On Android, SysTime is int64, special care must be taken to avoid
+    // overflows.
+    const int64 min_seconds = (sizeof(SysTime) < sizeof(int64))
+                                  ? std::numeric_limits<SysTime>::min()
+                                  : std::numeric_limits<int32_t>::min();
+    const int64 max_seconds = (sizeof(SysTime) < sizeof(int64))
+                                  ? std::numeric_limits<SysTime>::max()
+                                  : std::numeric_limits<int32_t>::max();
+    if (exploded.year < 1969) {
+      milliseconds = min_seconds * kMillisecondsPerSecond;
+    } else {
+      milliseconds = max_seconds * kMillisecondsPerSecond;
+      milliseconds += (kMillisecondsPerSecond - 1);
+    }
+  } else {
+    milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
+  }
+
+  // Adjust from Unix (1970) to Windows (1601) epoch.
+  return Time((milliseconds * kMicrosecondsPerMillisecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+// TimeTicks ------------------------------------------------------------------
+// static
+TimeTicks TimeTicks::Now() {
+  return ClockNow(CLOCK_MONOTONIC);
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+  return true;
+}
+
+// static
+TimeTicks TimeTicks::ThreadNow() {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+    defined(OS_ANDROID)
+  return ClockNow(CLOCK_THREAD_CPUTIME_ID);
+#else
+  NOTREACHED();
+  return TimeTicks();
+#endif
+}
+
+// Use the Chrome OS specific system-wide clock.
+#if defined(OS_CHROMEOS)
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  uint64_t absolute_micro;
+
+  struct timespec ts;
+  if (clock_gettime(kClockSystemTrace, &ts) != 0) {
+    // NB: fall-back for a chrome os build running on linux
+    return Now();
+  }
+
+  absolute_micro =
+      (static_cast<int64>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
+      (static_cast<int64>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
+
+  return TimeTicks(absolute_micro);
+}
+
+#else  // !defined(OS_CHROMEOS)
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  return Now();
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+#endif  // !OS_MACOSX
+
+// static
+Time Time::FromTimeVal(struct timeval t) {
+  DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
+  DCHECK_GE(t.tv_usec, 0);
+  if (t.tv_usec == 0 && t.tv_sec == 0)
+    return Time();
+  if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
+      t.tv_sec == std::numeric_limits<time_t>::max())
+    return Max();
+  return Time(
+      (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
+      t.tv_usec +
+      kTimeTToMicrosecondsOffset);
+}
+
+struct timeval Time::ToTimeVal() const {
+  struct timeval result;
+  if (is_null()) {
+    result.tv_sec = 0;
+    result.tv_usec = 0;
+    return result;
+  }
+  if (is_max()) {
+    result.tv_sec = std::numeric_limits<time_t>::max();
+    result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+    return result;
+  }
+  int64 us = us_ - kTimeTToMicrosecondsOffset;
+  result.tv_sec = us / Time::kMicrosecondsPerSecond;
+  result.tv_usec = us % Time::kMicrosecondsPerSecond;
+  return result;
+}
+
+}  // namespace base
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
new file mode 100644
index 0000000..6c12423
--- /dev/null
+++ b/base/time/time_unittest.cc
@@ -0,0 +1,1102 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+
+#include <time.h>
+
+#include <limits>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Specialized test fixture allowing time strings without timezones to be
+// tested by comparing them to a known time in the local zone.
+// See also pr_time_unittests.cc
+class TimeTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Use mktime to get a time_t, and turn it into a PRTime by converting
+    // seconds to microseconds.  Use 15th Oct 2007 12:45:00 local.  This
+    // must be a time guaranteed to be outside of a DST fallback hour in
+    // any timezone.
+    struct tm local_comparison_tm = {
+      0,            // second
+      45,           // minute
+      12,           // hour
+      15,           // day of month
+      10 - 1,       // month
+      2007 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+
+    time_t converted_time = mktime(&local_comparison_tm);
+    ASSERT_GT(converted_time, 0);
+    comparison_time_local_ = Time::FromTimeT(converted_time);
+
+    // time_t representation of 15th Oct 2007 12:45:00 PDT
+    comparison_time_pdt_ = Time::FromTimeT(1192477500);
+  }
+
+  Time comparison_time_local_;
+  Time comparison_time_pdt_;
+};
+
+// Test conversions to/from time_t and exploding/unexploding.
+TEST_F(TimeTest, TimeT) {
+  // C library time and exploded time.
+  time_t now_t_1 = time(NULL);
+  struct tm tms;
+#if defined(OS_WIN)
+  localtime_s(&tms, &now_t_1);
+#elif defined(OS_POSIX)
+  localtime_r(&now_t_1, &tms);
+#endif
+
+  // Convert to ours.
+  Time our_time_1 = Time::FromTimeT(now_t_1);
+  Time::Exploded exploded;
+  our_time_1.LocalExplode(&exploded);
+
+  // This will test both our exploding and our time_t -> Time conversion.
+  EXPECT_EQ(tms.tm_year + 1900, exploded.year);
+  EXPECT_EQ(tms.tm_mon + 1, exploded.month);
+  EXPECT_EQ(tms.tm_mday, exploded.day_of_month);
+  EXPECT_EQ(tms.tm_hour, exploded.hour);
+  EXPECT_EQ(tms.tm_min, exploded.minute);
+  EXPECT_EQ(tms.tm_sec, exploded.second);
+
+  // Convert exploded back to the time struct.
+  Time our_time_2 = Time::FromLocalExploded(exploded);
+  EXPECT_TRUE(our_time_1 == our_time_2);
+
+  time_t now_t_2 = our_time_2.ToTimeT();
+  EXPECT_EQ(now_t_1, now_t_2);
+
+  EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT());
+  EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT());
+
+  // Conversions of 0 should stay 0.
+  EXPECT_EQ(0, Time().ToTimeT());
+  EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue());
+}
+
+// Test conversions to/from javascript time.
+TEST_F(TimeTest, JsTime) {
+  Time epoch = Time::FromJsTime(0.0);
+  EXPECT_EQ(epoch, Time::UnixEpoch());
+  Time t = Time::FromJsTime(700000.3);
+  EXPECT_EQ(700.0003, t.ToDoubleT());
+  t = Time::FromDoubleT(800.73);
+  EXPECT_EQ(800730.0, t.ToJsTime());
+}
+
+#if defined(OS_POSIX)
+TEST_F(TimeTest, FromTimeVal) {
+  Time now = Time::Now();
+  Time also_now = Time::FromTimeVal(now.ToTimeVal());
+  EXPECT_EQ(now, also_now);
+}
+#endif  // OS_POSIX
+
+TEST_F(TimeTest, FromExplodedWithMilliseconds) {
+  // Some platform implementations of FromExploded are liable to drop
+  // milliseconds if we aren't careful.
+  Time now = Time::NowFromSystemTime();
+  Time::Exploded exploded1 = {0};
+  now.UTCExplode(&exploded1);
+  exploded1.millisecond = 500;
+  Time time = Time::FromUTCExploded(exploded1);
+  Time::Exploded exploded2 = {0};
+  time.UTCExplode(&exploded2);
+  EXPECT_EQ(exploded1.millisecond, exploded2.millisecond);
+}
+
+TEST_F(TimeTest, ZeroIsSymmetric) {
+  Time zero_time(Time::FromTimeT(0));
+  EXPECT_EQ(0, zero_time.ToTimeT());
+
+  EXPECT_EQ(0.0, zero_time.ToDoubleT());
+}
+
+TEST_F(TimeTest, LocalExplode) {
+  Time a = Time::Now();
+  Time::Exploded exploded;
+  a.LocalExplode(&exploded);
+
+  Time b = Time::FromLocalExploded(exploded);
+
+  // The exploded structure doesn't have microseconds, and on Mac & Linux, the
+  // internal OS conversion uses seconds, which will cause truncation. So we
+  // can only make sure that the delta is within one second.
+  EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TimeTest, UTCExplode) {
+  Time a = Time::Now();
+  Time::Exploded exploded;
+  a.UTCExplode(&exploded);
+
+  Time b = Time::FromUTCExploded(exploded);
+  EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TimeTest, LocalMidnight) {
+  Time::Exploded exploded;
+  Time::Now().LocalMidnight().LocalExplode(&exploded);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+}
+
+TEST_F(TimeTest, ParseTimeTest1) {
+  time_t current_time = 0;
+  time(&current_time);
+
+  const int BUFFER_SIZE = 64;
+  struct tm local_time = {0};
+  char time_buf[BUFFER_SIZE] = {0};
+#if defined(OS_WIN)
+  localtime_s(&local_time, &current_time);
+  asctime_s(time_buf, arraysize(time_buf), &local_time);
+#elif defined(OS_POSIX)
+  localtime_r(&current_time, &local_time);
+  asctime_r(&local_time, time_buf);
+#endif
+
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString(time_buf, &parsed_time));
+  EXPECT_EQ(current_time, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, DayOfWeekSunday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Sun, 06 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(0, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, DayOfWeekWednesday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Wed, 09 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(3, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, DayOfWeekSaturday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Sat, 12 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(6, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, ParseTimeTest2) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Mon, 15 Oct 2007 19:45:00 GMT", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest3) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15 Oct 07 12:45:00", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest4) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15 Oct 07 19:45 GMT", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest5) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Mon Oct 15 12:45 PDT 2007", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest6) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Monday, Oct 15, 2007 12:45 PM", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest7) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("10/15/07 12:45:00 PM", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest8) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15-OCT-2007 12:45pm", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest9) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("16 Oct 2007 4:45-JST (Tuesday)", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest10) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15/10/07 12:45", &parsed_time));
+  EXPECT_EQ(parsed_time, comparison_time_local_);
+}
+
+// Test some of edge cases around epoch, etc.
+TEST_F(TimeTest, ParseTimeTestEpoch0) {
+  Time parsed_time;
+
+  // time_t == epoch == 0
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:00 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(0, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:00 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(0, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch1) {
+  Time parsed_time;
+
+  // time_t == 1 second after epoch == 1
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:01 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(1, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:01 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(1, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch2) {
+  Time parsed_time;
+
+  // time_t == 2 seconds after epoch == 2
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:02 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(2, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:02 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(2, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpochNeg1) {
+  Time parsed_time;
+
+  // time_t == 1 second before epoch == -1
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:59 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(-1, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 1969",
+                               &parsed_time));
+  EXPECT_EQ(-1, parsed_time.ToTimeT());
+}
+
+// If time_t is 32 bits, a date after year 2038 will overflow time_t and
+// cause timegm() to return -1.  The parsed time should not be 1 second
+// before epoch.
+TEST_F(TimeTest, ParseTimeTestEpochNotNeg1) {
+  Time parsed_time;
+
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 2100",
+                               &parsed_time));
+  EXPECT_NE(-1, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpochNeg2) {
+  Time parsed_time;
+
+  // time_t == 2 seconds before epoch == -2
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:58 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(-2, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:58 GMT 1969",
+                               &parsed_time));
+  EXPECT_EQ(-2, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch1960) {
+  Time parsed_time;
+
+  // time_t before Epoch, in 1960
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 19:40:01 +0100 1960",
+                               &parsed_time));
+  EXPECT_EQ(-299999999, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 18:40:01 GMT 1960",
+                               &parsed_time));
+  EXPECT_EQ(-299999999, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 17:40:01 GMT 1960",
+                               &parsed_time));
+  EXPECT_EQ(-300003599, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEmpty) {
+  Time parsed_time;
+  EXPECT_FALSE(Time::FromString("", &parsed_time));
+}
+
+TEST_F(TimeTest, ParseTimeTestInvalidString) {
+  Time parsed_time;
+  EXPECT_FALSE(Time::FromString("Monday morning 2000", &parsed_time));
+}
+
+TEST_F(TimeTest, ExplodeBeforeUnixEpoch) {
+  static const int kUnixEpochYear = 1970;  // In case this changes (ha!).
+  Time t;
+  Time::Exploded exploded;
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 999 milliseconds (and 999 microseconds).
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 999 milliseconds.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 998 milliseconds (and 999 microseconds).
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(998, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:58 999 milliseconds.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(58, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  // Make sure we still handle at/after Unix epoch correctly.
+  t = Time::UnixEpoch();
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-12-31 00:00:00 0 milliseconds.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:00 0 milliseconds (and 1 microsecond).
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:00 1 millisecond.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(1, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:01.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(1, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:01 1 millisecond.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(1, exploded.second);
+  EXPECT_EQ(1, exploded.millisecond);
+}
+
+TEST_F(TimeTest, TimeDeltaMax) {
+  TimeDelta max = TimeDelta::Max();
+  EXPECT_TRUE(max.is_max());
+  EXPECT_EQ(max, TimeDelta::Max());
+  EXPECT_GT(max, TimeDelta::FromDays(100 * 365));
+  EXPECT_GT(max, TimeDelta());
+}
+
+TEST_F(TimeTest, TimeDeltaMaxConversions) {
+  TimeDelta t = TimeDelta::Max();
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+
+  EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays());
+  EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours());
+  EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF());
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.InSeconds());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF());
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMilliseconds());
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMillisecondsRoundedUp());
+
+  t = TimeDelta::FromDays(std::numeric_limits<int>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromHours(std::numeric_limits<int>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMinutes(std::numeric_limits<int>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSeconds(std::numeric_limits<int64>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMilliseconds(std::numeric_limits<int64>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMicroseconds(std::numeric_limits<int64>::max());
+  EXPECT_TRUE(t.is_max());
+}
+
+TEST_F(TimeTest, Max) {
+  Time max = Time::Max();
+  EXPECT_TRUE(max.is_max());
+  EXPECT_EQ(max, Time::Max());
+  EXPECT_GT(max, Time::Now());
+  EXPECT_GT(max, Time());
+}
+
+TEST_F(TimeTest, MaxConversions) {
+  Time t = Time::Max();
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+
+  t = Time::FromDoubleT(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToDoubleT());
+
+  t = Time::FromJsTime(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToJsTime());
+
+  t = Time::FromTimeT(std::numeric_limits<time_t>::max());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+
+#if defined(OS_POSIX)
+  struct timeval tval;
+  tval.tv_sec = std::numeric_limits<time_t>::max();
+  tval.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+  t = Time::FromTimeVal(tval);
+  EXPECT_TRUE(t.is_max());
+  tval = t.ToTimeVal();
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), tval.tv_sec);
+  EXPECT_EQ(static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1,
+      tval.tv_usec);
+#endif
+
+#if defined(OS_MACOSX)
+  t = Time::FromCFAbsoluteTime(std::numeric_limits<CFAbsoluteTime>::infinity());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::infinity(),
+            t.ToCFAbsoluteTime());
+#endif
+
+#if defined(OS_WIN)
+  FILETIME ftime;
+  ftime.dwHighDateTime = std::numeric_limits<DWORD>::max();
+  ftime.dwLowDateTime = std::numeric_limits<DWORD>::max();
+  t = Time::FromFileTime(ftime);
+  EXPECT_TRUE(t.is_max());
+  ftime = t.ToFileTime();
+  EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime);
+  EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime);
+#endif
+}
+
+#if defined(OS_MACOSX)
+TEST_F(TimeTest, TimeTOverflow) {
+  Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1);
+  EXPECT_FALSE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+}
+#endif
+
+#if defined(OS_ANDROID)
+TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) {
+  // This crashed inside Time:: FromLocalExploded() on Android 4.1.2.
+  // See http://crbug.com/287821
+  Time::Exploded midnight = {2013,  // year
+                             10,    // month
+                             0,     // day_of_week
+                             13,    // day_of_month
+                             0,     // hour
+                             0,     // minute
+                             0,     // second
+  };
+  // The string passed to putenv() must be a char* and the documentation states
+  // that it 'becomes part of the environment', so use a static buffer.
+  static char buffer[] = "TZ=America/Santiago";
+  putenv(buffer);
+  tzset();
+  Time t = Time::FromLocalExploded(midnight);
+  EXPECT_EQ(1381633200, t.ToTimeT());
+}
+#endif  // OS_ANDROID
+
+TEST(TimeTicks, Deltas) {
+  for (int index = 0; index < 50; index++) {
+    TimeTicks ticks_start = TimeTicks::Now();
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    TimeTicks ticks_stop = TimeTicks::Now();
+    TimeDelta delta = ticks_stop - ticks_start;
+    // Note:  Although we asked for a 10ms sleep, if the
+    // time clock has a finer granularity than the Sleep()
+    // clock, it is quite possible to wakeup early.  Here
+    // is how that works:
+    //      Time(ms timer)      Time(us timer)
+    //          5                   5010
+    //          6                   6010
+    //          7                   7010
+    //          8                   8010
+    //          9                   9000
+    // Elapsed  4ms                 3990us
+    //
+    // Unfortunately, our InMilliseconds() function truncates
+    // rather than rounds.  We should consider fixing this
+    // so that our averages come out better.
+    EXPECT_GE(delta.InMilliseconds(), 9);
+    EXPECT_GE(delta.InMicroseconds(), 9000);
+    EXPECT_EQ(delta.InSeconds(), 0);
+  }
+}
+
+static void HighResClockTest(TimeTicks (*GetTicks)()) {
+  // IsHighResolution() is false on some systems.  Since the product still works
+  // even if it's false, it makes this entire test questionable.
+  if (!TimeTicks::IsHighResolution())
+    return;
+
+  // Why do we loop here?
+  // We're trying to measure that intervals increment in a VERY small amount
+  // of time --  less than 15ms.  Unfortunately, if we happen to have a
+  // context switch in the middle of our test, the context switch could easily
+  // exceed our limit.  So, we iterate on this several times.  As long as we're
+  // able to detect the fine-granularity timers at least once, then the test
+  // has succeeded.
+
+  const int kTargetGranularityUs = 15000;  // 15ms
+
+  bool success = false;
+  int retries = 100;  // Arbitrary.
+  TimeDelta delta;
+  while (!success && retries--) {
+    TimeTicks ticks_start = GetTicks();
+    // Loop until we can detect that the clock has changed.  Non-HighRes timers
+    // will increment in chunks, e.g. 15ms.  By spinning until we see a clock
+    // change, we detect the minimum time between measurements.
+    do {
+      delta = GetTicks() - ticks_start;
+    } while (delta.InMilliseconds() == 0);
+
+    if (delta.InMicroseconds() <= kTargetGranularityUs)
+      success = true;
+  }
+
+  // In high resolution mode, we expect to see the clock increment
+  // in intervals less than 15ms.
+  EXPECT_TRUE(success);
+}
+
+TEST(TimeTicks, HighRes) {
+  HighResClockTest(&TimeTicks::Now);
+}
+
+// Fails frequently on Android http://crbug.com/352633 with:
+// Expected: (delta_thread.InMicroseconds()) > (0), actual: 0 vs 0
+#if defined(OS_ANDROID)
+#define MAYBE_ThreadNow DISABLED_ThreadNow
+#else
+#define MAYBE_ThreadNow ThreadNow
+#endif
+TEST(TimeTicks, MAYBE_ThreadNow) {
+  if (TimeTicks::IsThreadNowSupported()) {
+    TimeTicks begin = TimeTicks::Now();
+    TimeTicks begin_thread = TimeTicks::ThreadNow();
+    // Make sure that ThreadNow value is non-zero.
+    EXPECT_GT(begin_thread, TimeTicks());
+    // Sleep for 10 milliseconds to get the thread de-scheduled.
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    TimeTicks end_thread = TimeTicks::ThreadNow();
+    TimeTicks end = TimeTicks::Now();
+    TimeDelta delta = end - begin;
+    TimeDelta delta_thread = end_thread - begin_thread;
+    // Make sure that some thread time have elapsed.
+    EXPECT_GT(delta_thread.InMicroseconds(), 0);
+    // But the thread time is at least 9ms less than clock time.
+    TimeDelta difference = delta - delta_thread;
+    EXPECT_GE(difference.InMicroseconds(), 9000);
+  }
+}
+
+TEST(TimeTicks, NowFromSystemTraceTime) {
+  // Re-use HighRes test for now since clock properties are identical.
+  HighResClockTest(&TimeTicks::NowFromSystemTraceTime);
+}
+
+TEST(TimeTicks, SnappedToNextTickBasic) {
+  base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000);
+  base::TimeDelta interval = base::TimeDelta::FromInternalValue(1000);
+  base::TimeTicks timestamp;
+
+  // Timestamp in previous interval.
+  timestamp = base::TimeTicks::FromInternalValue(3500);
+  EXPECT_EQ(4000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp in next interval.
+  timestamp = base::TimeTicks::FromInternalValue(4500);
+  EXPECT_EQ(5000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp multiple intervals before.
+  timestamp = base::TimeTicks::FromInternalValue(2500);
+  EXPECT_EQ(3000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp multiple intervals after.
+  timestamp = base::TimeTicks::FromInternalValue(6500);
+  EXPECT_EQ(7000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp on previous interval.
+  timestamp = base::TimeTicks::FromInternalValue(3000);
+  EXPECT_EQ(3000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp on next interval.
+  timestamp = base::TimeTicks::FromInternalValue(5000);
+  EXPECT_EQ(5000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp equal to phase.
+  timestamp = base::TimeTicks::FromInternalValue(4000);
+  EXPECT_EQ(4000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+}
+
+TEST(TimeTicks, SnappedToNextTickOverflow) {
+  // int(big_timestamp / interval) < 0, so this causes a crash if the number of
+  // intervals elapsed is attempted to be stored in an int.
+  base::TimeTicks phase = base::TimeTicks::FromInternalValue(0);
+  base::TimeDelta interval = base::TimeDelta::FromInternalValue(4000);
+  base::TimeTicks big_timestamp =
+      base::TimeTicks::FromInternalValue(8635916564000);
+
+  EXPECT_EQ(8635916564000,
+            big_timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+  EXPECT_EQ(8635916564000,
+            big_timestamp.SnappedToNextTick(big_timestamp, interval)
+                .ToInternalValue());
+}
+
+TEST(TimeDelta, FromAndIn) {
+  EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
+  EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
+  EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120));
+  EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
+  EXPECT_TRUE(TimeDelta::FromMilliseconds(2) ==
+              TimeDelta::FromMicroseconds(2000));
+  EXPECT_TRUE(TimeDelta::FromSecondsD(2.3) ==
+              TimeDelta::FromMilliseconds(2300));
+  EXPECT_TRUE(TimeDelta::FromMillisecondsD(2.5) ==
+              TimeDelta::FromMicroseconds(2500));
+  EXPECT_EQ(13, TimeDelta::FromDays(13).InDays());
+  EXPECT_EQ(13, TimeDelta::FromHours(13).InHours());
+  EXPECT_EQ(13, TimeDelta::FromMinutes(13).InMinutes());
+  EXPECT_EQ(13, TimeDelta::FromSeconds(13).InSeconds());
+  EXPECT_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF());
+  EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).InMilliseconds());
+  EXPECT_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF());
+  EXPECT_EQ(13, TimeDelta::FromSecondsD(13.1).InSeconds());
+  EXPECT_EQ(13.1, TimeDelta::FromSecondsD(13.1).InSecondsF());
+  EXPECT_EQ(13, TimeDelta::FromMillisecondsD(13.3).InMilliseconds());
+  EXPECT_EQ(13.3, TimeDelta::FromMillisecondsD(13.3).InMillisecondsF());
+  EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds());
+}
+
+#if defined(OS_POSIX)
+TEST(TimeDelta, TimeSpecConversion) {
+  struct timespec result = TimeDelta::FromSeconds(0).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 0);
+  EXPECT_EQ(result.tv_nsec, 0);
+
+  result = TimeDelta::FromSeconds(1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 1);
+  EXPECT_EQ(result.tv_nsec, 0);
+
+  result = TimeDelta::FromMicroseconds(1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 0);
+  EXPECT_EQ(result.tv_nsec, 1000);
+
+  result = TimeDelta::FromMicroseconds(
+      Time::kMicrosecondsPerSecond + 1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 1);
+  EXPECT_EQ(result.tv_nsec, 1000);
+}
+#endif  // OS_POSIX
+
+// Our internal time format is serialized in things like databases, so it's
+// important that it's consistent across all our platforms.  We use the 1601
+// Windows epoch as the internal format across all platforms.
+TEST(TimeDelta, WindowsEpoch) {
+  Time::Exploded exploded;
+  exploded.year = 1970;
+  exploded.month = 1;
+  exploded.day_of_week = 0;  // Should be unusued.
+  exploded.day_of_month = 1;
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+  Time t = Time::FromUTCExploded(exploded);
+  // Unix 1970 epoch.
+  EXPECT_EQ(GG_INT64_C(11644473600000000), t.ToInternalValue());
+
+  // We can't test 1601 epoch, since the system time functions on Linux
+  // only compute years starting from 1900.
+}
+
+// We could define this separately for Time, TimeTicks and TimeDelta but the
+// definitions would be identical anyway.
+template <class Any>
+std::string AnyToString(Any any) {
+  std::ostringstream oss;
+  oss << any;
+  return oss.str();
+}
+
+TEST(TimeDelta, Magnitude) {
+  const int64 zero = 0;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(zero),
+            TimeDelta::FromMicroseconds(zero).magnitude());
+
+  const int64 one = 1;
+  const int64 negative_one = -1;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+            TimeDelta::FromMicroseconds(one).magnitude());
+  EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+            TimeDelta::FromMicroseconds(negative_one).magnitude());
+
+  const int64 max_int64_minus_one = std::numeric_limits<int64>::max() - 1;
+  const int64 min_int64_plus_two = std::numeric_limits<int64>::min() + 2;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
+            TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude());
+  EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one),
+            TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
+}
+
+
+TEST(TimeDelta, NumericOperators) {
+  double d = 0.5;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            d * TimeDelta::FromMilliseconds(1000));
+
+  float f = 0.5;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            f * TimeDelta::FromMilliseconds(1000));
+
+
+  int i = 2;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            i * TimeDelta::FromMilliseconds(1000));
+
+  int64_t i64 = 2;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            i64 * TimeDelta::FromMilliseconds(1000));
+
+
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            0.5 * TimeDelta::FromMilliseconds(1000));
+
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            2 * TimeDelta::FromMilliseconds(1000));
+}
+
+bool IsMin(TimeDelta delta) {
+  return (-delta).is_max();
+}
+
+TEST(TimeDelta, Overflows) {
+  // Some sanity checks.
+  EXPECT_TRUE(TimeDelta::Max().is_max());
+  EXPECT_TRUE(IsMin(-TimeDelta::Max()));
+  EXPECT_GT(TimeDelta(), -TimeDelta::Max());
+
+  TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1);
+  TimeDelta large_negative = -large_delta;
+  EXPECT_GT(TimeDelta(), large_negative);
+  EXPECT_FALSE(large_delta.is_max());
+  EXPECT_FALSE(IsMin(-large_negative));
+  TimeDelta one_second = TimeDelta::FromSeconds(1);
+
+  // Test +, -, * and / operators.
+  EXPECT_TRUE((large_delta + one_second).is_max());
+  EXPECT_TRUE(IsMin(large_negative + (-one_second)));
+  EXPECT_TRUE(IsMin(large_negative - one_second));
+  EXPECT_TRUE((large_delta - (-one_second)).is_max());
+  EXPECT_TRUE((large_delta * 2).is_max());
+  EXPECT_TRUE(IsMin(large_delta * -2));
+  EXPECT_TRUE((large_delta / 0.5).is_max());
+  EXPECT_TRUE(IsMin(large_delta / -0.5));
+
+  // Test +=, -=, *= and /= operators.
+  TimeDelta delta = large_delta;
+  delta += one_second;
+  EXPECT_TRUE(delta.is_max());
+  delta = large_negative;
+  delta += -one_second;
+  EXPECT_TRUE(IsMin(delta));
+
+  delta = large_negative;
+  delta -= one_second;
+  EXPECT_TRUE(IsMin(delta));
+  delta = large_delta;
+  delta -= -one_second;
+  EXPECT_TRUE(delta.is_max());
+
+  delta = large_delta;
+  delta *= 2;
+  EXPECT_TRUE(delta.is_max());
+  delta = large_negative;
+  delta *= 1.5;
+  EXPECT_TRUE(IsMin(delta));
+
+  delta = large_delta;
+  delta /= 0.5;
+  EXPECT_TRUE(delta.is_max());
+  delta = large_negative;
+  delta /= 0.5;
+  EXPECT_TRUE(IsMin(delta));
+
+  // Test operations with Time and TimeTicks.
+  EXPECT_TRUE((large_delta + Time::Now()).is_max());
+  EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max());
+  EXPECT_TRUE((Time::Now() + large_delta).is_max());
+  EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max());
+
+  Time time_now = Time::Now();
+  EXPECT_EQ(one_second, (time_now + one_second) - time_now);
+  EXPECT_EQ(-one_second, (time_now - one_second) - time_now);
+
+  TimeTicks ticks_now = TimeTicks::Now();
+  EXPECT_EQ(-one_second, (ticks_now - one_second) - ticks_now);
+  EXPECT_EQ(one_second, (ticks_now + one_second) - ticks_now);
+}
+
+TEST(TimeDeltaLogging, DCheckEqCompiles) {
+  DCHECK_EQ(TimeDelta(), TimeDelta());
+}
+
+TEST(TimeDeltaLogging, EmptyIsZero) {
+  TimeDelta zero;
+  EXPECT_EQ("0s", AnyToString(zero));
+}
+
+TEST(TimeDeltaLogging, FiveHundredMs) {
+  TimeDelta five_hundred_ms = TimeDelta::FromMilliseconds(500);
+  EXPECT_EQ("0.5s", AnyToString(five_hundred_ms));
+}
+
+TEST(TimeDeltaLogging, MinusTenSeconds) {
+  TimeDelta minus_ten_seconds = TimeDelta::FromSeconds(-10);
+  EXPECT_EQ("-10s", AnyToString(minus_ten_seconds));
+}
+
+TEST(TimeDeltaLogging, DoesNotMessUpFormattingFlags) {
+  std::ostringstream oss;
+  std::ios_base::fmtflags flags_before = oss.flags();
+  oss << TimeDelta();
+  EXPECT_EQ(flags_before, oss.flags());
+}
+
+TEST(TimeDeltaLogging, DoesNotMakeStreamBad) {
+  std::ostringstream oss;
+  oss << TimeDelta();
+  EXPECT_TRUE(oss.good());
+}
+
+TEST(TimeLogging, DCheckEqCompiles) {
+  DCHECK_EQ(Time(), Time());
+}
+
+TEST(TimeLogging, ChromeBirthdate) {
+  Time birthdate;
+  ASSERT_TRUE(Time::FromString("Tue, 02 Sep 2008 09:42:18 GMT", &birthdate));
+  EXPECT_EQ("2008-09-02 09:42:18.000 UTC", AnyToString(birthdate));
+}
+
+TEST(TimeLogging, DoesNotMessUpFormattingFlags) {
+  std::ostringstream oss;
+  std::ios_base::fmtflags flags_before = oss.flags();
+  oss << Time();
+  EXPECT_EQ(flags_before, oss.flags());
+}
+
+TEST(TimeLogging, DoesNotMakeStreamBad) {
+  std::ostringstream oss;
+  oss << Time();
+  EXPECT_TRUE(oss.good());
+}
+
+TEST(TimeTicksLogging, DCheckEqCompiles) {
+  DCHECK_EQ(TimeTicks(), TimeTicks());
+}
+
+TEST(TimeTicksLogging, ZeroTime) {
+  TimeTicks zero;
+  EXPECT_EQ("0 bogo-microseconds", AnyToString(zero));
+}
+
+TEST(TimeTicksLogging, FortyYearsLater) {
+  TimeTicks forty_years_later =
+      TimeTicks() + TimeDelta::FromDays(365.25 * 40);
+  EXPECT_EQ("1262304000000000 bogo-microseconds",
+            AnyToString(forty_years_later));
+}
+
+TEST(TimeTicksLogging, DoesNotMessUpFormattingFlags) {
+  std::ostringstream oss;
+  std::ios_base::fmtflags flags_before = oss.flags();
+  oss << TimeTicks();
+  EXPECT_EQ(flags_before, oss.flags());
+}
+
+TEST(TimeTicksLogging, DoesNotMakeStreamBad) {
+  std::ostringstream oss;
+  oss << TimeTicks();
+  EXPECT_TRUE(oss.good());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
new file mode 100644
index 0000000..d2403f2
--- /dev/null
+++ b/base/time/time_win.cc
@@ -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.
+
+
+// Windows Timer Primer
+//
+// A good article:  http://www.ddj.com/windows/184416651
+// A good mozilla bug:  http://bugzilla.mozilla.org/show_bug.cgi?id=363258
+//
+// The default windows timer, GetSystemTimeAsFileTime is not very precise.
+// It is only good to ~15.5ms.
+//
+// QueryPerformanceCounter is the logical choice for a high-precision timer.
+// However, it is known to be buggy on some hardware.  Specifically, it can
+// sometimes "jump".  On laptops, QPC can also be very expensive to call.
+// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
+// on laptops.  A unittest exists which will show the relative cost of various
+// timers on any system.
+//
+// The next logical choice is timeGetTime().  timeGetTime has a precision of
+// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
+// applications on the system.  By default, precision is only 15.5ms.
+// Unfortunately, we don't want to call timeBeginPeriod because we don't
+// want to affect other applications.  Further, on mobile platforms, use of
+// faster multimedia timers can hurt battery life.  See the intel
+// article about this here:
+// http://softwarecommunity.intel.com/articles/eng/1086.htm
+//
+// To work around all this, we're going to generally use timeGetTime().  We
+// will only increase the system-wide timer if we're not running on battery
+// power.
+
+#include "base/time/time.h"
+
+#pragma comment(lib, "winmm.lib")
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "base/basictypes.h"
+#include "base/cpu.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace {
+
+// From MSDN, FILETIME "Contains a 64-bit value representing the number of
+// 100-nanosecond intervals since January 1, 1601 (UTC)."
+int64 FileTimeToMicroseconds(const FILETIME& ft) {
+  // Need to bit_cast to fix alignment, then divide by 10 to convert
+  // 100-nanoseconds to milliseconds. This only works on little-endian
+  // machines.
+  return bit_cast<int64, FILETIME>(ft) / 10;
+}
+
+void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
+  DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
+      "representable in FILETIME";
+
+  // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
+  // handle alignment problems. This only works on little-endian machines.
+  *ft = bit_cast<FILETIME, int64>(us * 10);
+}
+
+int64 CurrentWallclockMicroseconds() {
+  FILETIME ft;
+  ::GetSystemTimeAsFileTime(&ft);
+  return FileTimeToMicroseconds(ft);
+}
+
+// Time between resampling the un-granular clock for this API.  60 seconds.
+const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
+
+int64 initial_time = 0;
+TimeTicks initial_ticks;
+
+void InitializeClock() {
+  initial_ticks = TimeTicks::Now();
+  initial_time = CurrentWallclockMicroseconds();
+}
+
+// The two values that ActivateHighResolutionTimer uses to set the systemwide
+// timer interrupt frequency on Windows. It controls how precise timers are
+// but also has a big impact on battery life.
+const int kMinTimerIntervalHighResMs = 1;
+const int kMinTimerIntervalLowResMs = 4;
+// Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active.
+bool g_high_res_timer_enabled = false;
+// How many times the high resolution timer has been called.
+uint32_t g_high_res_timer_count = 0;
+// The lock to control access to the above two variables.
+base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Time -----------------------------------------------------------------------
+
+// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
+// 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
+// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
+// 1700, 1800, and 1900.
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
+
+// static
+Time Time::Now() {
+  if (initial_time == 0)
+    InitializeClock();
+
+  // We implement time using the high-resolution timers so that we can get
+  // timeouts which are smaller than 10-15ms.  If we just used
+  // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
+  //
+  // To make this work, we initialize the clock (initial_time) and the
+  // counter (initial_ctr).  To compute the initial time, we can check
+  // the number of ticks that have elapsed, and compute the delta.
+  //
+  // To avoid any drift, we periodically resync the counters to the system
+  // clock.
+  while (true) {
+    TimeTicks ticks = TimeTicks::Now();
+
+    // Calculate the time elapsed since we started our timer
+    TimeDelta elapsed = ticks - initial_ticks;
+
+    // Check if enough time has elapsed that we need to resync the clock.
+    if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
+      InitializeClock();
+      continue;
+    }
+
+    return Time(elapsed + Time(initial_time));
+  }
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Force resync.
+  InitializeClock();
+  return Time(initial_time);
+}
+
+// static
+Time Time::FromFileTime(FILETIME ft) {
+  if (bit_cast<int64, FILETIME>(ft) == 0)
+    return Time();
+  if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
+      ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
+    return Max();
+  return Time(FileTimeToMicroseconds(ft));
+}
+
+FILETIME Time::ToFileTime() const {
+  if (is_null())
+    return bit_cast<FILETIME, int64>(0);
+  if (is_max()) {
+    FILETIME result;
+    result.dwHighDateTime = std::numeric_limits<DWORD>::max();
+    result.dwLowDateTime = std::numeric_limits<DWORD>::max();
+    return result;
+  }
+  FILETIME utc_ft;
+  MicrosecondsToFileTime(us_, &utc_ft);
+  return utc_ft;
+}
+
+// static
+void Time::EnableHighResolutionTimer(bool enable) {
+  base::AutoLock lock(g_high_res_lock.Get());
+  if (g_high_res_timer_enabled == enable)
+    return;
+  g_high_res_timer_enabled = enable;
+  if (!g_high_res_timer_count)
+    return;
+  // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true)
+  // was called which called timeBeginPeriod with g_high_res_timer_enabled
+  // with a value which is the opposite of |enable|. With that information we
+  // call timeEndPeriod with the same value used in timeBeginPeriod and
+  // therefore undo the period effect.
+  if (enable) {
+    timeEndPeriod(kMinTimerIntervalLowResMs);
+    timeBeginPeriod(kMinTimerIntervalHighResMs);
+  } else {
+    timeEndPeriod(kMinTimerIntervalHighResMs);
+    timeBeginPeriod(kMinTimerIntervalLowResMs);
+  }
+}
+
+// static
+bool Time::ActivateHighResolutionTimer(bool activating) {
+  // We only do work on the transition from zero to one or one to zero so we
+  // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
+  // called.
+  const uint32_t max = std::numeric_limits<uint32_t>::max();
+
+  base::AutoLock lock(g_high_res_lock.Get());
+  UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
+                                         : kMinTimerIntervalLowResMs;
+  if (activating) {
+    DCHECK_NE(g_high_res_timer_count, max);
+    ++g_high_res_timer_count;
+    if (g_high_res_timer_count == 1)
+      timeBeginPeriod(period);
+  } else {
+    DCHECK_NE(g_high_res_timer_count, 0u);
+    --g_high_res_timer_count;
+    if (g_high_res_timer_count == 0)
+      timeEndPeriod(period);
+  }
+  return (period == kMinTimerIntervalHighResMs);
+}
+
+// static
+bool Time::IsHighResolutionTimerInUse() {
+  base::AutoLock lock(g_high_res_lock.Get());
+  return g_high_res_timer_enabled && g_high_res_timer_count > 0;
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  // Create the system struct representing our exploded time. It will either be
+  // in local time or UTC.
+  SYSTEMTIME st;
+  st.wYear = static_cast<WORD>(exploded.year);
+  st.wMonth = static_cast<WORD>(exploded.month);
+  st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week);
+  st.wDay = static_cast<WORD>(exploded.day_of_month);
+  st.wHour = static_cast<WORD>(exploded.hour);
+  st.wMinute = static_cast<WORD>(exploded.minute);
+  st.wSecond = static_cast<WORD>(exploded.second);
+  st.wMilliseconds = static_cast<WORD>(exploded.millisecond);
+
+  FILETIME ft;
+  bool success = true;
+  // Ensure that it's in UTC.
+  if (is_local) {
+    SYSTEMTIME utc_st;
+    success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) &&
+              SystemTimeToFileTime(&utc_st, &ft);
+  } else {
+    success = !!SystemTimeToFileTime(&st, &ft);
+  }
+
+  if (!success) {
+    NOTREACHED() << "Unable to convert time";
+    return Time(0);
+  }
+  return Time(FileTimeToMicroseconds(ft));
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  if (us_ < 0LL) {
+    // We are not able to convert it to FILETIME.
+    ZeroMemory(exploded, sizeof(*exploded));
+    return;
+  }
+
+  // FILETIME in UTC.
+  FILETIME utc_ft;
+  MicrosecondsToFileTime(us_, &utc_ft);
+
+  // FILETIME in local time if necessary.
+  bool success = true;
+  // FILETIME in SYSTEMTIME (exploded).
+  SYSTEMTIME st = {0};
+  if (is_local) {
+    SYSTEMTIME utc_st;
+    // We don't use FileTimeToLocalFileTime here, since it uses the current
+    // settings for the time zone and daylight saving time. Therefore, if it is
+    // daylight saving time, it will take daylight saving time into account,
+    // even if the time you are converting is in standard time.
+    success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
+              SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st);
+  } else {
+    success = !!FileTimeToSystemTime(&utc_ft, &st);
+  }
+
+  if (!success) {
+    NOTREACHED() << "Unable to convert time, don't know why";
+    ZeroMemory(exploded, sizeof(*exploded));
+    return;
+  }
+
+  exploded->year = st.wYear;
+  exploded->month = st.wMonth;
+  exploded->day_of_week = st.wDayOfWeek;
+  exploded->day_of_month = st.wDay;
+  exploded->hour = st.wHour;
+  exploded->minute = st.wMinute;
+  exploded->second = st.wSecond;
+  exploded->millisecond = st.wMilliseconds;
+}
+
+// TimeTicks ------------------------------------------------------------------
+namespace {
+
+// We define a wrapper to adapt between the __stdcall and __cdecl call of the
+// mock function, and to avoid a static constructor.  Assigning an import to a
+// function pointer directly would require setup code to fetch from the IAT.
+DWORD timeGetTimeWrapper() {
+  return timeGetTime();
+}
+
+DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
+
+// Accumulation of time lost due to rollover (in milliseconds).
+int64 g_rollover_ms = 0;
+
+// The last timeGetTime value we saw, to detect rollover.
+DWORD g_last_seen_now = 0;
+
+// Lock protecting rollover_ms and last_seen_now.
+// Note: this is a global object, and we usually avoid these. However, the time
+// code is low-level, and we don't want to use Singletons here (it would be too
+// easy to use a Singleton without even knowing it, and that may lead to many
+// gotchas). Its impact on startup time should be negligible due to low-level
+// nature of time code.
+base::Lock g_rollover_lock;
+
+// We use timeGetTime() to implement TimeTicks::Now().  This can be problematic
+// because it returns the number of milliseconds since Windows has started,
+// which will roll over the 32-bit value every ~49 days.  We try to track
+// rollover ourselves, which works if TimeTicks::Now() is called at least every
+// 49 days.
+TimeTicks RolloverProtectedNow() {
+  base::AutoLock locked(g_rollover_lock);
+  // We should hold the lock while calling tick_function to make sure that
+  // we keep last_seen_now stay correctly in sync.
+  DWORD now = g_tick_function();
+  if (now < g_last_seen_now)
+    g_rollover_ms += 0x100000000I64;  // ~49.7 days.
+  g_last_seen_now = now;
+  return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms);
+}
+
+// Discussion of tick counter options on Windows:
+//
+// (1) CPU cycle counter. (Retrieved via RDTSC)
+// The CPU counter provides the highest resolution time stamp and is the least
+// expensive to retrieve. However, on older CPUs, two issues can affect its
+// reliability: First it is maintained per processor and not synchronized
+// between processors. Also, the counters will change frequency due to thermal
+// and power changes, and stop in some states.
+//
+// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
+// resolution (<1 microsecond) time stamp. On most hardware running today, it
+// auto-detects and uses the constant-rate RDTSC counter to provide extremely
+// efficient and reliable time stamps.
+//
+// On older CPUs where RDTSC is unreliable, it falls back to using more
+// expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI
+// PM timer, and can involve system calls; and all this is up to the HAL (with
+// some help from ACPI). According to
+// http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the
+// worst case, it gets the counter from the rollover interrupt on the
+// programmable interrupt timer. In best cases, the HAL may conclude that the
+// RDTSC counter runs at a constant frequency, then it uses that instead. On
+// multiprocessor machines, it will try to verify the values returned from
+// RDTSC on each processor are consistent with each other, and apply a handful
+// of workarounds for known buggy hardware. In other words, QPC is supposed to
+// give consistent results on a multiprocessor computer, but for older CPUs it
+// can be unreliable due bugs in BIOS or HAL.
+//
+// (3) System time. The system time provides a low-resolution (from ~1 to ~15.6
+// milliseconds) time stamp but is comparatively less expensive to retrieve and
+// more reliable. Time::EnableHighResolutionTimer() and
+// Time::ActivateHighResolutionTimer() can be called to alter the resolution of
+// this timer; and also other Windows applications can alter it, affecting this
+// one.
+
+using NowFunction = TimeTicks (*)(void);
+
+TimeTicks InitialNowFunction();
+TimeTicks InitialSystemTraceNowFunction();
+
+// See "threading notes" in InitializeNowFunctionPointers() for details on how
+// concurrent reads/writes to these globals has been made safe.
+NowFunction g_now_function = &InitialNowFunction;
+NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction;
+int64 g_qpc_ticks_per_second = 0;
+
+// As of January 2015, use of <atomic> is forbidden in Chromium code. This is
+// what std::atomic_thread_fence does on Windows on all Intel architectures when
+// the memory_order argument is anything but std::memory_order_seq_cst:
+#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
+
+TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
+  // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
+  // InitializeNowFunctionPointers(), has happened by this point.
+  ATOMIC_THREAD_FENCE(memory_order_acquire);
+
+  DCHECK_GT(g_qpc_ticks_per_second, 0);
+
+  // If the QPC Value is below the overflow threshold, we proceed with
+  // simple multiply and divide.
+  if (qpc_value < Time::kQPCOverflowThreshold) {
+    return TimeDelta::FromMicroseconds(
+        qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
+  }
+  // Otherwise, calculate microseconds in a round about manner to avoid
+  // overflow and precision issues.
+  int64 whole_seconds = qpc_value / g_qpc_ticks_per_second;
+  int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
+  return TimeDelta::FromMicroseconds(
+      (whole_seconds * Time::kMicrosecondsPerSecond) +
+      ((leftover_ticks * Time::kMicrosecondsPerSecond) /
+       g_qpc_ticks_per_second));
+}
+
+TimeTicks QPCNow() {
+  LARGE_INTEGER now;
+  QueryPerformanceCounter(&now);
+  return TimeTicks() + QPCValueToTimeDelta(now.QuadPart);
+}
+
+bool IsBuggyAthlon(const base::CPU& cpu) {
+  // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
+  return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
+}
+
+void InitializeNowFunctionPointers() {
+  LARGE_INTEGER ticks_per_sec = {0};
+  if (!QueryPerformanceFrequency(&ticks_per_sec))
+    ticks_per_sec.QuadPart = 0;
+
+  // If Windows cannot provide a QPC implementation, both Now() and
+  // NowFromSystemTraceTime() must use the low-resolution clock.
+  //
+  // If the QPC implementation is expensive and/or unreliable, Now() will use
+  // the low-resolution clock, but NowFromSystemTraceTime() will use the QPC (in
+  // the hope that it is still useful for tracing purposes). A CPU lacking a
+  // non-stop time counter will cause Windows to provide an alternate QPC
+  // implementation that works, but is expensive to use. Certain Athlon CPUs are
+  // known to make the QPC implementation unreliable.
+  //
+  // Otherwise, both Now functions can use the high-resolution QPC clock. As of
+  // 4 January 2015, ~68% of users fall within this category.
+  NowFunction now_function;
+  NowFunction system_trace_now_function;
+  base::CPU cpu;
+  if (ticks_per_sec.QuadPart <= 0) {
+    now_function = system_trace_now_function = &RolloverProtectedNow;
+  } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
+    now_function = &RolloverProtectedNow;
+    system_trace_now_function = &QPCNow;
+  } else {
+    now_function = system_trace_now_function = &QPCNow;
+  }
+
+  // Threading note 1: In an unlikely race condition, it's possible for two or
+  // more threads to enter InitializeNowFunctionPointers() in parallel. This is
+  // not a problem since all threads should end up writing out the same values
+  // to the global variables.
+  //
+  // Threading note 2: A release fence is placed here to ensure, from the
+  // perspective of other threads using the function pointers, that the
+  // assignment to |g_qpc_ticks_per_second| happens before the function pointers
+  // are changed.
+  g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
+  ATOMIC_THREAD_FENCE(memory_order_release);
+  g_now_function = now_function;
+  g_system_trace_now_function = system_trace_now_function;
+}
+
+TimeTicks InitialNowFunction() {
+  InitializeNowFunctionPointers();
+  return g_now_function();
+}
+
+TimeTicks InitialSystemTraceNowFunction() {
+  InitializeNowFunctionPointers();
+  return g_system_trace_now_function();
+}
+
+}  // namespace
+
+// static
+TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
+    TickFunctionType ticker) {
+  base::AutoLock locked(g_rollover_lock);
+  TickFunctionType old = g_tick_function;
+  g_tick_function = ticker;
+  g_rollover_ms = 0;
+  g_last_seen_now = 0;
+  return old;
+}
+
+// static
+TimeTicks TimeTicks::Now() {
+  return g_now_function();
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+  if (g_now_function == &InitialNowFunction)
+    InitializeNowFunctionPointers();
+  return g_now_function == &QPCNow;
+}
+
+// static
+TimeTicks TimeTicks::ThreadNow() {
+  NOTREACHED();
+  return TimeTicks();
+}
+
+// static
+TimeTicks TimeTicks::NowFromSystemTraceTime() {
+  return g_system_trace_now_function();
+}
+
+// static
+TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
+  return TimeTicks() + QPCValueToTimeDelta(qpc_value);
+}
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
+  return QPCValueToTimeDelta(qpc_value);
+}
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc
new file mode 100644
index 0000000..82be8c5
--- /dev/null
+++ b/base/time/time_win_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <process.h>
+
+#include <cmath>
+#include <limits>
+#include <vector>
+
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace {
+
+class MockTimeTicks : public TimeTicks {
+ public:
+  static DWORD Ticker() {
+    return static_cast<int>(InterlockedIncrement(&ticker_));
+  }
+
+  static void InstallTicker() {
+    old_tick_function_ = SetMockTickFunction(&Ticker);
+    ticker_ = -5;
+  }
+
+  static void UninstallTicker() {
+    SetMockTickFunction(old_tick_function_);
+  }
+
+ private:
+  static volatile LONG ticker_;
+  static TickFunctionType old_tick_function_;
+};
+
+volatile LONG MockTimeTicks::ticker_;
+MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_;
+
+HANDLE g_rollover_test_start;
+
+unsigned __stdcall RolloverTestThreadMain(void* param) {
+  int64 counter = reinterpret_cast<int64>(param);
+  DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
+  EXPECT_EQ(rv, WAIT_OBJECT_0);
+
+  TimeTicks last = TimeTicks::Now();
+  for (int index = 0; index < counter; index++) {
+    TimeTicks now = TimeTicks::Now();
+    int64 milliseconds = (now - last).InMilliseconds();
+    // This is a tight loop; we could have looped faster than our
+    // measurements, so the time might be 0 millis.
+    EXPECT_GE(milliseconds, 0);
+    EXPECT_LT(milliseconds, 250);
+    last = now;
+  }
+  return 0;
+}
+
+}  // namespace
+
+TEST(TimeTicks, WinRollover) {
+  // The internal counter rolls over at ~49days.  We'll use a mock
+  // timer to test this case.
+  // Basic test algorithm:
+  //   1) Set clock to rollover - N
+  //   2) Create N threads
+  //   3) Start the threads
+  //   4) Each thread loops through TimeTicks() N times
+  //   5) Each thread verifies integrity of result.
+
+  const int kThreads = 8;
+  // Use int64 so we can cast into a void* without a compiler warning.
+  const int64 kChecks = 10;
+
+  // It takes a lot of iterations to reproduce the bug!
+  // (See bug 1081395)
+  for (int loop = 0; loop < 4096; loop++) {
+    // Setup
+    MockTimeTicks::InstallTicker();
+    g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0);
+    HANDLE threads[kThreads];
+
+    for (int index = 0; index < kThreads; index++) {
+      void* argument = reinterpret_cast<void*>(kChecks);
+      unsigned thread_id;
+      threads[index] = reinterpret_cast<HANDLE>(
+        _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0,
+          &thread_id));
+      EXPECT_NE((HANDLE)NULL, threads[index]);
+    }
+
+    // Start!
+    SetEvent(g_rollover_test_start);
+
+    // Wait for threads to finish
+    for (int index = 0; index < kThreads; index++) {
+      DWORD rv = WaitForSingleObject(threads[index], INFINITE);
+      EXPECT_EQ(rv, WAIT_OBJECT_0);
+      // Since using _beginthreadex() (as opposed to _beginthread),
+      // an explicit CloseHandle() is supposed to be called.
+      CloseHandle(threads[index]);
+    }
+
+    CloseHandle(g_rollover_test_start);
+
+    // Teardown
+    MockTimeTicks::UninstallTicker();
+  }
+}
+
+TEST(TimeTicks, SubMillisecondTimers) {
+  // IsHighResolution() is false on some systems.  Since the product still works
+  // even if it's false, it makes this entire test questionable.
+  if (!TimeTicks::IsHighResolution())
+    return;
+
+  const int kRetries = 1000;
+  bool saw_submillisecond_timer = false;
+
+  // Run kRetries attempts to see a sub-millisecond timer.
+  for (int index = 0; index < kRetries; index++) {
+    TimeTicks last_time = TimeTicks::Now();
+    TimeDelta delta;
+    // Spin until the clock has detected a change.
+    do {
+      delta = TimeTicks::Now() - last_time;
+    } while (delta.InMicroseconds() == 0);
+    if (delta.InMicroseconds() < 1000) {
+      saw_submillisecond_timer = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(saw_submillisecond_timer);
+}
+
+TEST(TimeTicks, TimeGetTimeCaps) {
+  // Test some basic assumptions that we expect about how timeGetDevCaps works.
+
+  TIMECAPS caps;
+  MMRESULT status = timeGetDevCaps(&caps, sizeof(caps));
+  EXPECT_EQ(TIMERR_NOERROR, status);
+  if (status != TIMERR_NOERROR) {
+    printf("Could not get timeGetDevCaps\n");
+    return;
+  }
+
+  EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
+  EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
+  EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
+  EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
+  printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin,
+    caps.wPeriodMax);
+}
+
+TEST(TimeTicks, QueryPerformanceFrequency) {
+  // Test some basic assumptions that we expect about QPC.
+
+  LARGE_INTEGER frequency;
+  BOOL rv = QueryPerformanceFrequency(&frequency);
+  EXPECT_EQ(TRUE, rv);
+  EXPECT_GT(frequency.QuadPart, 1000000);  // Expect at least 1MHz
+  printf("QueryPerformanceFrequency is %5.2fMHz\n",
+    frequency.QuadPart / 1000000.0);
+}
+
+TEST(TimeTicks, TimerPerformance) {
+  // Verify that various timer mechanisms can always complete quickly.
+  // Note:  This is a somewhat arbitrary test.
+  const int kLoops = 10000;
+
+  typedef TimeTicks (*TestFunc)();
+  struct TestCase {
+    TestFunc func;
+    const char *description;
+  };
+  // Cheating a bit here:  assumes sizeof(TimeTicks) == sizeof(Time)
+  // in order to create a single test case list.
+  COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time),
+                 test_only_works_with_same_sizes);
+  TestCase cases[] = {
+    { reinterpret_cast<TestFunc>(Time::Now), "Time::Now" },
+    { TimeTicks::Now, "TimeTicks::Now" },
+    { TimeTicks::NowFromSystemTraceTime, "TimeTicks::NowFromSystemTraceTime" },
+    { NULL, "" }
+  };
+
+  int test_case = 0;
+  while (cases[test_case].func) {
+    TimeTicks start = TimeTicks::Now();
+    for (int index = 0; index < kLoops; index++)
+      cases[test_case].func();
+    TimeTicks stop = TimeTicks::Now();
+    // Turning off the check for acceptible delays.  Without this check,
+    // the test really doesn't do much other than measure.  But the
+    // measurements are still useful for testing timers on various platforms.
+    // The reason to remove the check is because the tests run on many
+    // buildbots, some of which are VMs.  These machines can run horribly
+    // slow, and there is really no value for checking against a max timer.
+    //const int kMaxTime = 35;  // Maximum acceptible milliseconds for test.
+    //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime);
+    printf("%s: %1.2fus per call\n", cases[test_case].description,
+      (stop - start).InMillisecondsF() * 1000 / kLoops);
+    test_case++;
+  }
+}
+
+TEST(TimeTicks, FromQPCValue) {
+  if (!TimeTicks::IsHighResolution())
+    return;
+
+  LARGE_INTEGER frequency;
+  ASSERT_TRUE(QueryPerformanceFrequency(&frequency));
+  const int64 ticks_per_second = frequency.QuadPart;
+  ASSERT_GT(ticks_per_second, 0);
+
+  // Generate the tick values to convert, advancing the tick count by varying
+  // amounts.  These values will ensure that both the fast and overflow-safe
+  // conversion logic in FromQPCValue() is tested, and across the entire range
+  // of possible QPC tick values.
+  std::vector<int64> test_cases;
+  test_cases.push_back(0);
+  const int kNumAdvancements = 100;
+  int64 ticks = 0;
+  int64 ticks_increment = 10;
+  for (int i = 0; i < kNumAdvancements; ++i) {
+    test_cases.push_back(ticks);
+    ticks += ticks_increment;
+    ticks_increment = ticks_increment * 6 / 5;
+  }
+  test_cases.push_back(Time::kQPCOverflowThreshold - 1);
+  test_cases.push_back(Time::kQPCOverflowThreshold);
+  test_cases.push_back(Time::kQPCOverflowThreshold + 1);
+  ticks = Time::kQPCOverflowThreshold + 10;
+  ticks_increment = 10;
+  for (int i = 0; i < kNumAdvancements; ++i) {
+    test_cases.push_back(ticks);
+    ticks += ticks_increment;
+    ticks_increment = ticks_increment * 6 / 5;
+  }
+  test_cases.push_back(std::numeric_limits<int64>::max());
+
+  // Test that the conversions using FromQPCValue() match those computed here
+  // using simple floating-point arithmetic.  The floating-point math provides
+  // enough precision to confirm the implementation is correct to the
+  // microsecond for all |test_cases| (though it would be insufficient to
+  // confirm many "very large" tick values which are not being tested here).
+  for (int64 ticks : test_cases) {
+    const double expected_microseconds_since_origin =
+        (static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) /
+            ticks_per_second;
+    const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks);
+    const double converted_microseconds_since_origin =
+        static_cast<double>((converted_value - TimeTicks()).InMicroseconds());
+    EXPECT_NEAR(expected_microseconds_since_origin,
+                converted_microseconds_since_origin,
+                1.0)
+        << "ticks=" << ticks << ", to be converted via logic path: "
+        << (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE");
+  }
+}
diff --git a/base/timer/elapsed_timer.cc b/base/timer/elapsed_timer.cc
new file mode 100644
index 0000000..f2a2f71
--- /dev/null
+++ b/base/timer/elapsed_timer.cc
@@ -0,0 +1,17 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+ElapsedTimer::ElapsedTimer() {
+  begin_ = TimeTicks::Now();
+}
+
+TimeDelta ElapsedTimer::Elapsed() const {
+  return TimeTicks::Now() - begin_;
+}
+
+}  // namespace base
diff --git a/base/timer/elapsed_timer.h b/base/timer/elapsed_timer.h
new file mode 100644
index 0000000..592858a
--- /dev/null
+++ b/base/timer/elapsed_timer.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIMER_ELAPSED_TIMER_H_
+#define BASE_TIMER_ELAPSED_TIMER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// A simple wrapper around TimeTicks::Now().
+class BASE_EXPORT ElapsedTimer {
+ public:
+  ElapsedTimer();
+
+  // Returns the time elapsed since object construction.
+  TimeDelta Elapsed() const;
+
+ private:
+  TimeTicks begin_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElapsedTimer);
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_ELAPSED_TIMER_H_
diff --git a/base/timer/hi_res_timer_manager.h b/base/timer/hi_res_timer_manager.h
new file mode 100644
index 0000000..ed0e1e0
--- /dev/null
+++ b/base/timer/hi_res_timer_manager.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIMER_HI_RES_TIMER_MANAGER_H_
+#define BASE_TIMER_HI_RES_TIMER_MANAGER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/power_monitor/power_observer.h"
+
+namespace base {
+
+// Ensures that the Windows high resolution timer is only used
+// when not running on battery power.
+class BASE_EXPORT HighResolutionTimerManager : public base::PowerObserver {
+ public:
+  HighResolutionTimerManager();
+  ~HighResolutionTimerManager() override;
+
+  // base::PowerObserver method.
+  void OnPowerStateChange(bool on_battery_power) override;
+
+  // Returns true if the hi resolution clock could be used right now.
+  bool hi_res_clock_available() const { return hi_res_clock_available_; }
+
+ private:
+  // Enable or disable the faster multimedia timer.
+  void UseHiResClock(bool use);
+
+  bool hi_res_clock_available_;
+
+  DISALLOW_COPY_AND_ASSIGN(HighResolutionTimerManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_HI_RES_TIMER_MANAGER_H_
diff --git a/base/timer/hi_res_timer_manager_posix.cc b/base/timer/hi_res_timer_manager_posix.cc
new file mode 100644
index 0000000..d2f152c
--- /dev/null
+++ b/base/timer/hi_res_timer_manager_posix.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/hi_res_timer_manager.h"
+
+// On POSIX we don't need to do anything special with the system timer.
+
+namespace base {
+
+HighResolutionTimerManager::HighResolutionTimerManager()
+    : hi_res_clock_available_(false) {
+}
+
+HighResolutionTimerManager::~HighResolutionTimerManager() {
+}
+
+void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) {
+}
+
+void HighResolutionTimerManager::UseHiResClock(bool use) {
+}
+
+}  // namespace base
diff --git a/base/timer/hi_res_timer_manager_unittest.cc b/base/timer/hi_res_timer_manager_unittest.cc
new file mode 100644
index 0000000..5475a91
--- /dev/null
+++ b/base/timer/hi_res_timer_manager_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/hi_res_timer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+#if defined(OS_WIN)
+TEST(HiResTimerManagerTest, ToggleOnOff) {
+  // The power monitor creates Window to receive power notifications from
+  // Windows, which makes this test flaky if you run while the machine
+  // goes in or out of AC power.
+  base::MessageLoop loop(base::MessageLoop::TYPE_UI);
+  scoped_ptr<base::PowerMonitorSource> power_monitor_source(
+      new base::PowerMonitorDeviceSource());
+  scoped_ptr<base::PowerMonitor> power_monitor(
+      new base::PowerMonitor(power_monitor_source.Pass()));
+
+  HighResolutionTimerManager manager;
+  // Simulate a on-AC power event to get to a known initial state.
+  manager.OnPowerStateChange(false);
+
+  // Loop a few times to test power toggling.
+  for (int times = 0; times != 3; ++times) {
+    // The manager has the high resolution clock enabled now.
+    EXPECT_TRUE(manager.hi_res_clock_available());
+    // But the Time class has it off, because it hasn't been activated.
+    EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse());
+
+    // Activate the high resolution timer.
+    base::Time::ActivateHighResolutionTimer(true);
+    EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse());
+
+    // Simulate a on-battery power event.
+    manager.OnPowerStateChange(true);
+    EXPECT_FALSE(manager.hi_res_clock_available());
+    EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse());
+
+    // Back to on-AC power.
+    manager.OnPowerStateChange(false);
+    EXPECT_TRUE(manager.hi_res_clock_available());
+    EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse());
+
+    // De-activate the high resolution timer.
+    base::Time::ActivateHighResolutionTimer(false);
+  }
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace base
diff --git a/base/timer/hi_res_timer_manager_win.cc b/base/timer/hi_res_timer_manager_win.cc
new file mode 100644
index 0000000..692f72b
--- /dev/null
+++ b/base/timer/hi_res_timer_manager_win.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/hi_res_timer_manager.h"
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/time/time.h"
+
+namespace base {
+
+HighResolutionTimerManager::HighResolutionTimerManager()
+    : hi_res_clock_available_(false) {
+  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
+  DCHECK(power_monitor != NULL);
+  power_monitor->AddObserver(this);
+  UseHiResClock(!power_monitor->IsOnBatteryPower());
+}
+
+HighResolutionTimerManager::~HighResolutionTimerManager() {
+  base::PowerMonitor::Get()->RemoveObserver(this);
+  UseHiResClock(false);
+}
+
+void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) {
+  UseHiResClock(!on_battery_power);
+}
+
+void HighResolutionTimerManager::UseHiResClock(bool use) {
+  if (use == hi_res_clock_available_)
+    return;
+  hi_res_clock_available_ = use;
+  base::Time::EnableHighResolutionTimer(use);
+}
+
+}  // namespace base
diff --git a/base/timer/mock_timer.cc b/base/timer/mock_timer.cc
new file mode 100644
index 0000000..296071e
--- /dev/null
+++ b/base/timer/mock_timer.cc
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/mock_timer.h"
+
+namespace base {
+
+MockTimer::MockTimer(bool retain_user_task, bool is_repeating)
+    : Timer(retain_user_task, is_repeating),
+      is_running_(false) {
+}
+
+MockTimer::MockTimer(const tracked_objects::Location& posted_from,
+                     TimeDelta delay,
+                     const base::Closure& user_task,
+                     bool is_repeating)
+    : Timer(true, is_repeating),
+      delay_(delay),
+      is_running_(false) {
+}
+
+MockTimer::~MockTimer() {
+}
+
+bool MockTimer::IsRunning() const {
+  return is_running_;
+}
+
+base::TimeDelta MockTimer::GetCurrentDelay() const {
+  return delay_;
+}
+
+void MockTimer::Start(const tracked_objects::Location& posted_from,
+                      TimeDelta delay,
+                      const base::Closure& user_task) {
+  delay_ = delay;
+  user_task_ = user_task;
+  Reset();
+}
+
+void MockTimer::Stop() {
+  is_running_ = false;
+  if (!retain_user_task())
+    user_task_.Reset();
+}
+
+void MockTimer::Reset() {
+  DCHECK(!user_task_.is_null());
+  is_running_ = true;
+}
+
+void MockTimer::Fire() {
+  DCHECK(is_running_);
+  base::Closure old_task = user_task_;
+  if (is_repeating())
+    Reset();
+  else
+    Stop();
+  old_task.Run();
+}
+
+}  // namespace base
diff --git a/base/timer/mock_timer.h b/base/timer/mock_timer.h
new file mode 100644
index 0000000..e18a5c0
--- /dev/null
+++ b/base/timer/mock_timer.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIMER_MOCK_TIMER_H_
+#define BASE_TIMER_MOCK_TIMER_H_
+
+#include "base/timer/timer.h"
+
+namespace base {
+
+class BASE_EXPORT MockTimer : public Timer {
+ public:
+  MockTimer(bool retain_user_task, bool is_repeating);
+  MockTimer(const tracked_objects::Location& posted_from,
+            TimeDelta delay,
+            const base::Closure& user_task,
+            bool is_repeating);
+  ~MockTimer() override;
+
+  // base::Timer implementation.
+  bool IsRunning() const override;
+  base::TimeDelta GetCurrentDelay() const override;
+  void Start(const tracked_objects::Location& posted_from,
+             base::TimeDelta delay,
+             const base::Closure& user_task) override;
+  void Stop() override;
+  void Reset() override;
+
+  // Testing methods.
+  void Fire();
+
+ private:
+  base::Closure user_task_;
+  TimeDelta delay_;
+  bool is_running_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_MOCK_TIMER_H_
diff --git a/base/timer/mock_timer_unittest.cc b/base/timer/mock_timer_unittest.cc
new file mode 100644
index 0000000..f6b6953
--- /dev/null
+++ b/base/timer/mock_timer_unittest.cc
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/mock_timer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void CallMeMaybe(int *number) {
+  (*number)++;
+}
+
+TEST(MockTimerTest, FiresOnce) {
+  int calls = 0;
+  base::MockTimer timer(false, false);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&CallMeMaybe,
+                         base::Unretained(&calls)));
+  EXPECT_EQ(delay, timer.GetCurrentDelay());
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Fire();
+  EXPECT_FALSE(timer.IsRunning());
+  EXPECT_EQ(1, calls);
+}
+
+TEST(MockTimerTest, FiresRepeatedly) {
+  int calls = 0;
+  base::MockTimer timer(true, true);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&CallMeMaybe,
+                         base::Unretained(&calls)));
+  timer.Fire();
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Fire();
+  timer.Fire();
+  EXPECT_TRUE(timer.IsRunning());
+  EXPECT_EQ(3, calls);
+}
+
+TEST(MockTimerTest, Stops) {
+  int calls = 0;
+  base::MockTimer timer(true, true);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&CallMeMaybe,
+                         base::Unretained(&calls)));
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Stop();
+  EXPECT_FALSE(timer.IsRunning());
+}
+
+class HasWeakPtr : public base::SupportsWeakPtr<HasWeakPtr> {
+ public:
+  HasWeakPtr() {}
+  virtual ~HasWeakPtr() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HasWeakPtr);
+};
+
+void DoNothingWithWeakPtr(HasWeakPtr* has_weak_ptr) {
+}
+
+TEST(MockTimerTest, DoesNotRetainClosure) {
+  HasWeakPtr *has_weak_ptr = new HasWeakPtr();
+  base::WeakPtr<HasWeakPtr> weak_ptr(has_weak_ptr->AsWeakPtr());
+  base::MockTimer timer(false, false);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  ASSERT_TRUE(weak_ptr.get());
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&DoNothingWithWeakPtr,
+                         base::Owned(has_weak_ptr)));
+  ASSERT_TRUE(weak_ptr.get());
+  timer.Fire();
+  ASSERT_FALSE(weak_ptr.get());
+}
+
+}  // namespace
diff --git a/base/timer/timer.cc b/base/timer/timer.cc
new file mode 100644
index 0000000..fa6b8cd
--- /dev/null
+++ b/base/timer/timer.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/timer.h"
+
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// BaseTimerTaskInternal is a simple delegate for scheduling a callback to
+// Timer in the thread's default task runner. It also handles the following
+// edge cases:
+// - deleted by the task runner.
+// - abandoned (orphaned) by Timer.
+class BaseTimerTaskInternal {
+ public:
+  explicit BaseTimerTaskInternal(Timer* timer)
+      : timer_(timer) {
+  }
+
+  ~BaseTimerTaskInternal() {
+    // This task may be getting cleared because the task runner has been
+    // destructed.  If so, don't leave Timer with a dangling pointer
+    // to this.
+    if (timer_)
+      timer_->StopAndAbandon();
+  }
+
+  void Run() {
+    // timer_ is NULL if we were abandoned.
+    if (!timer_)
+      return;
+
+    // *this will be deleted by the task runner, so Timer needs to
+    // forget us:
+    timer_->scheduled_task_ = NULL;
+
+    // Although Timer should not call back into *this, let's clear
+    // the timer_ member first to be pedantic.
+    Timer* timer = timer_;
+    timer_ = NULL;
+    timer->RunScheduledTask();
+  }
+
+  // The task remains in the MessageLoop queue, but nothing will happen when it
+  // runs.
+  void Abandon() {
+    timer_ = NULL;
+  }
+
+ private:
+  Timer* timer_;
+};
+
+Timer::Timer(bool retain_user_task, bool is_repeating)
+    : scheduled_task_(NULL),
+      thread_id_(0),
+      is_repeating_(is_repeating),
+      retain_user_task_(retain_user_task),
+      is_running_(false) {
+}
+
+Timer::Timer(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             const base::Closure& user_task,
+             bool is_repeating)
+    : scheduled_task_(NULL),
+      posted_from_(posted_from),
+      delay_(delay),
+      user_task_(user_task),
+      thread_id_(0),
+      is_repeating_(is_repeating),
+      retain_user_task_(true),
+      is_running_(false) {
+}
+
+Timer::~Timer() {
+  StopAndAbandon();
+}
+
+bool Timer::IsRunning() const {
+  return is_running_;
+}
+
+TimeDelta Timer::GetCurrentDelay() const {
+  return delay_;
+}
+
+void Timer::SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  // Do not allow changing the task runner once something has been scheduled.
+  DCHECK_EQ(thread_id_, 0);
+  task_runner_.swap(task_runner);
+}
+
+void Timer::Start(const tracked_objects::Location& posted_from,
+                  TimeDelta delay,
+                  const base::Closure& user_task) {
+  SetTaskInfo(posted_from, delay, user_task);
+  Reset();
+}
+
+void Timer::Stop() {
+  is_running_ = false;
+  if (!retain_user_task_)
+    user_task_.Reset();
+}
+
+void Timer::Reset() {
+  DCHECK(!user_task_.is_null());
+
+  // If there's no pending task, start one up and return.
+  if (!scheduled_task_) {
+    PostNewScheduledTask(delay_);
+    return;
+  }
+
+  // Set the new desired_run_time_.
+  if (delay_ > TimeDelta::FromMicroseconds(0))
+    desired_run_time_ = TimeTicks::Now() + delay_;
+  else
+    desired_run_time_ = TimeTicks();
+
+  // We can use the existing scheduled task if it arrives before the new
+  // desired_run_time_.
+  if (desired_run_time_ >= scheduled_run_time_) {
+    is_running_ = true;
+    return;
+  }
+
+  // We can't reuse the scheduled_task_, so abandon it and post a new one.
+  AbandonScheduledTask();
+  PostNewScheduledTask(delay_);
+}
+
+void Timer::SetTaskInfo(const tracked_objects::Location& posted_from,
+                        TimeDelta delay,
+                        const base::Closure& user_task) {
+  posted_from_ = posted_from;
+  delay_ = delay;
+  user_task_ = user_task;
+}
+
+void Timer::PostNewScheduledTask(TimeDelta delay) {
+  DCHECK(scheduled_task_ == NULL);
+  is_running_ = true;
+  scheduled_task_ = new BaseTimerTaskInternal(this);
+  if (delay > TimeDelta::FromMicroseconds(0)) {
+    GetTaskRunner()->PostDelayedTask(posted_from_,
+        base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)),
+        delay);
+    scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay;
+  } else {
+    GetTaskRunner()->PostTask(posted_from_,
+        base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)));
+    scheduled_run_time_ = desired_run_time_ = TimeTicks();
+  }
+  // Remember the thread ID that posts the first task -- this will be verified
+  // later when the task is abandoned to detect misuse from multiple threads.
+  if (!thread_id_) {
+    DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+    thread_id_ = static_cast<int>(PlatformThread::CurrentId());
+  }
+}
+
+scoped_refptr<SingleThreadTaskRunner> Timer::GetTaskRunner() {
+  return task_runner_.get() ? task_runner_ : ThreadTaskRunnerHandle::Get();
+}
+
+void Timer::AbandonScheduledTask() {
+  DCHECK(thread_id_ == 0 ||
+         thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
+  if (scheduled_task_) {
+    scheduled_task_->Abandon();
+    scheduled_task_ = NULL;
+  }
+}
+
+void Timer::RunScheduledTask() {
+  // Task may have been disabled.
+  if (!is_running_)
+    return;
+
+  // First check if we need to delay the task because of a new target time.
+  if (desired_run_time_ > scheduled_run_time_) {
+    // TimeTicks::Now() can be expensive, so only call it if we know the user
+    // has changed the desired_run_time_.
+    TimeTicks now = TimeTicks::Now();
+    // Task runner may have called us late anyway, so only post a continuation
+    // task if the desired_run_time_ is in the future.
+    if (desired_run_time_ > now) {
+      // Post a new task to span the remaining time.
+      PostNewScheduledTask(desired_run_time_ - now);
+      return;
+    }
+  }
+
+  // Make a local copy of the task to run. The Stop method will reset the
+  // user_task_ member if retain_user_task_ is false.
+  base::Closure task = user_task_;
+
+  if (is_repeating_)
+    PostNewScheduledTask(delay_);
+  else
+    Stop();
+
+  task.Run();
+
+  // No more member accesses here: *this could be deleted at this point.
+}
+
+}  // namespace base
diff --git a/base/timer/timer.h b/base/timer/timer.h
new file mode 100644
index 0000000..1ef58a3
--- /dev/null
+++ b/base/timer/timer.h
@@ -0,0 +1,268 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// OneShotTimer and RepeatingTimer provide a simple timer API.  As the names
+// suggest, OneShotTimer calls you back once after a time delay expires.
+// RepeatingTimer on the other hand calls you back periodically with the
+// prescribed time interval.
+//
+// OneShotTimer and RepeatingTimer both cancel the timer when they go out of
+// scope, which makes it easy to ensure that you do not get called when your
+// object has gone out of scope.  Just instantiate a OneShotTimer or
+// RepeatingTimer as a member variable of the class for which you wish to
+// receive timer events.
+//
+// Sample RepeatingTimer usage:
+//
+//   class MyClass {
+//    public:
+//     void StartDoingStuff() {
+//       timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1),
+//                    this, &MyClass::DoStuff);
+//     }
+//     void StopDoingStuff() {
+//       timer_.Stop();
+//     }
+//    private:
+//     void DoStuff() {
+//       // This method is called every second to do stuff.
+//       ...
+//     }
+//     base::RepeatingTimer<MyClass> timer_;
+//   };
+//
+// Both OneShotTimer and RepeatingTimer also support a Reset method, which
+// allows you to easily defer the timer event until the timer delay passes once
+// again.  So, in the above example, if 0.5 seconds have already passed,
+// calling Reset on timer_ would postpone DoStuff by another 1 second.  In
+// other words, Reset is shorthand for calling Stop and then Start again with
+// the same arguments.
+//
+// NOTE: These APIs are not thread safe. Always call from the same thread.
+
+#ifndef BASE_TIMER_TIMER_H_
+#define BASE_TIMER_TIMER_H_
+
+// IMPORTANT: If you change timer code, make sure that all tests (including
+// disabled ones) from timer_unittests.cc pass locally. Some are disabled
+// because they're flaky on the buildbot, but when you run them locally you
+// should be able to tell the difference.
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BaseTimerTaskInternal;
+class SingleThreadTaskRunner;
+
+//-----------------------------------------------------------------------------
+// This class wraps MessageLoop::PostDelayedTask to manage delayed and repeating
+// tasks. It must be destructed on the same thread that starts tasks. There are
+// DCHECKs in place to verify this.
+//
+class BASE_EXPORT Timer {
+ public:
+  // Construct a timer in repeating or one-shot mode. Start or SetTaskInfo must
+  // be called later to set task info. |retain_user_task| determines whether the
+  // user_task is retained or reset when it runs or stops.
+  Timer(bool retain_user_task, bool is_repeating);
+
+  // Construct a timer with retained task info.
+  Timer(const tracked_objects::Location& posted_from,
+        TimeDelta delay,
+        const base::Closure& user_task,
+        bool is_repeating);
+
+  virtual ~Timer();
+
+  // Returns true if the timer is running (i.e., not stopped).
+  virtual bool IsRunning() const;
+
+  // Returns the current delay for this timer.
+  virtual TimeDelta GetCurrentDelay() const;
+
+  // Set the task runner on which the task should be scheduled. This method can
+  // only be called before any tasks have been scheduled. The task runner must
+  // run tasks on the same thread the timer is used on.
+  virtual void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
+
+  // Start the timer to run at the given |delay| from now. If the timer is
+  // already running, it will be replaced to call the given |user_task|.
+  virtual void Start(const tracked_objects::Location& posted_from,
+                     TimeDelta delay,
+                     const base::Closure& user_task);
+
+  // Call this method to stop and cancel the timer.  It is a no-op if the timer
+  // is not running.
+  virtual void Stop();
+
+  // Call this method to reset the timer delay. The user_task_ must be set. If
+  // the timer is not running, this will start it by posting a task.
+  virtual void Reset();
+
+  const base::Closure& user_task() const { return user_task_; }
+  const TimeTicks& desired_run_time() const { return desired_run_time_; }
+
+ protected:
+  // Used to initiate a new delayed task.  This has the side-effect of disabling
+  // scheduled_task_ if it is non-null.
+  void SetTaskInfo(const tracked_objects::Location& posted_from,
+                   TimeDelta delay,
+                   const base::Closure& user_task);
+
+  void set_user_task(const Closure& task) { user_task_ = task; }
+  void set_desired_run_time(TimeTicks desired) { desired_run_time_ = desired; }
+  void set_is_running(bool running) { is_running_ = running; }
+
+  const tracked_objects::Location& posted_from() const { return posted_from_; }
+  bool retain_user_task() const { return retain_user_task_; }
+  bool is_repeating() const { return is_repeating_; }
+  bool is_running() const { return is_running_; }
+
+ private:
+  friend class BaseTimerTaskInternal;
+
+  // Allocates a new scheduled_task_ and posts it on the current MessageLoop
+  // with the given |delay|. scheduled_task_ must be NULL. scheduled_run_time_
+  // and desired_run_time_ are reset to Now() + delay.
+  void PostNewScheduledTask(TimeDelta delay);
+
+  // Returns the task runner on which the task should be scheduled. If the
+  // corresponding task_runner_ field is null, the task runner for the current
+  // thread is returned.
+  scoped_refptr<SingleThreadTaskRunner> GetTaskRunner();
+
+  // Disable scheduled_task_ and abandon it so that it no longer refers back to
+  // this object.
+  void AbandonScheduledTask();
+
+  // Called by BaseTimerTaskInternal when the MessageLoop runs it.
+  void RunScheduledTask();
+
+  // Stop running task (if any) and abandon scheduled task (if any).
+  void StopAndAbandon() {
+    Stop();
+    AbandonScheduledTask();
+  }
+
+  // When non-NULL, the scheduled_task_ is waiting in the MessageLoop to call
+  // RunScheduledTask() at scheduled_run_time_.
+  BaseTimerTaskInternal* scheduled_task_;
+
+  // The task runner on which the task should be scheduled. If it is null, the
+  // task runner for the current thread should be used.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  // Location in user code.
+  tracked_objects::Location posted_from_;
+  // Delay requested by user.
+  TimeDelta delay_;
+  // user_task_ is what the user wants to be run at desired_run_time_.
+  base::Closure user_task_;
+
+  // The estimated time that the MessageLoop will run the scheduled_task_ that
+  // will call RunScheduledTask(). This time can be a "zero" TimeTicks if the
+  // task must be run immediately.
+  TimeTicks scheduled_run_time_;
+
+  // The desired run time of user_task_. The user may update this at any time,
+  // even if their previous request has not run yet. If desired_run_time_ is
+  // greater than scheduled_run_time_, a continuation task will be posted to
+  // wait for the remaining time. This allows us to reuse the pending task so as
+  // not to flood the MessageLoop with orphaned tasks when the user code
+  // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks
+  // if the task must be run immediately.
+  TimeTicks desired_run_time_;
+
+  // Thread ID of current MessageLoop for verifying single-threaded usage.
+  int thread_id_;
+
+  // Repeating timers automatically post the task again before calling the task
+  // callback.
+  const bool is_repeating_;
+
+  // If true, hold on to the user_task_ closure object for reuse.
+  const bool retain_user_task_;
+
+  // If true, user_task_ is scheduled to run sometime in the future.
+  bool is_running_;
+
+  DISALLOW_COPY_AND_ASSIGN(Timer);
+};
+
+//-----------------------------------------------------------------------------
+// This class is an implementation detail of OneShotTimer and RepeatingTimer.
+// Please do not use this class directly.
+template <class Receiver, bool kIsRepeating>
+class BaseTimerMethodPointer : public Timer {
+ public:
+  typedef void (Receiver::*ReceiverMethod)();
+
+  // This is here to work around the fact that Timer::Start is "hidden" by the
+  // Start definition below, rather than being overloaded.
+  // TODO(tim): We should remove uses of BaseTimerMethodPointer::Start below
+  // and convert callers to use the base::Closure version in Timer::Start,
+  // see bug 148832.
+  using Timer::Start;
+
+  BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
+
+  // Start the timer to run at the given |delay| from now. If the timer is
+  // already running, it will be replaced to call a task formed from
+  // |reviewer->*method|.
+  virtual void Start(const tracked_objects::Location& posted_from,
+                     TimeDelta delay,
+                     Receiver* receiver,
+                     ReceiverMethod method) {
+    Timer::Start(posted_from, delay,
+                 base::Bind(method, base::Unretained(receiver)));
+  }
+};
+
+//-----------------------------------------------------------------------------
+// A simple, one-shot timer.  See usage notes at the top of the file.
+template <class Receiver>
+class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
+
+//-----------------------------------------------------------------------------
+// A simple, repeating timer.  See usage notes at the top of the file.
+template <class Receiver>
+class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
+
+//-----------------------------------------------------------------------------
+// A Delay timer is like The Button from Lost. Once started, you have to keep
+// calling Reset otherwise it will call the given method in the MessageLoop
+// thread.
+//
+// Once created, it is inactive until Reset is called. Once |delay| seconds have
+// passed since the last call to Reset, the callback is made. Once the callback
+// has been made, it's inactive until Reset is called again.
+//
+// If destroyed, the timeout is canceled and will not occur even if already
+// inflight.
+template <class Receiver>
+class DelayTimer : protected Timer {
+ public:
+  typedef void (Receiver::*ReceiverMethod)();
+
+  DelayTimer(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             ReceiverMethod method)
+      : Timer(posted_from, delay,
+              base::Bind(method, base::Unretained(receiver)),
+              false) {}
+
+  void Reset() override { Timer::Reset(); }
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_TIMER_H_
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
new file mode 100644
index 0000000..7213b80
--- /dev/null
+++ b/base/timer/timer_unittest.cc
@@ -0,0 +1,537 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/timer/timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::TimeDelta;
+using base::SingleThreadTaskRunner;
+
+namespace {
+
+// The message loops on which each timer should be tested.
+const base::MessageLoop::Type testing_message_loops[] = {
+  base::MessageLoop::TYPE_DEFAULT,
+  base::MessageLoop::TYPE_IO,
+#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
+  base::MessageLoop::TYPE_UI,
+#endif
+};
+
+const int kNumTestingMessageLoops = arraysize(testing_message_loops);
+
+class OneShotTimerTester {
+ public:
+  explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10)
+      : did_run_(did_run),
+        delay_ms_(milliseconds),
+        quit_message_loop_(true) {
+  }
+
+  void Start() {
+    timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this,
+                 &OneShotTimerTester::Run);
+  }
+
+  void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
+    quit_message_loop_ = false;
+    timer_.SetTaskRunner(task_runner);
+  }
+
+ private:
+  void Run() {
+    *did_run_ = true;
+    if (quit_message_loop_) {
+      base::MessageLoop::current()->QuitWhenIdle();
+    }
+  }
+
+  bool* did_run_;
+  base::OneShotTimer<OneShotTimerTester> timer_;
+  const unsigned delay_ms_;
+  bool quit_message_loop_;
+};
+
+class OneShotSelfDeletingTimerTester {
+ public:
+  explicit OneShotSelfDeletingTimerTester(bool* did_run) :
+      did_run_(did_run),
+      timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
+  }
+
+  void Start() {
+    timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
+                  &OneShotSelfDeletingTimerTester::Run);
+  }
+
+ private:
+  void Run() {
+    *did_run_ = true;
+    timer_.reset();
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  bool* did_run_;
+  scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
+};
+
+class RepeatingTimerTester {
+ public:
+  explicit RepeatingTimerTester(bool* did_run, const TimeDelta& delay)
+      : did_run_(did_run), counter_(10), delay_(delay) {
+  }
+
+  void Start() {
+    timer_.Start(FROM_HERE, delay_, this, &RepeatingTimerTester::Run);
+  }
+
+ private:
+  void Run() {
+    if (--counter_ == 0) {
+      *did_run_ = true;
+      timer_.Stop();
+      base::MessageLoop::current()->QuitWhenIdle();
+    }
+  }
+
+  bool* did_run_;
+  int counter_;
+  TimeDelta delay_;
+  base::RepeatingTimer<RepeatingTimerTester> timer_;
+};
+
+void RunTest_OneShotTimer(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  OneShotTimerTester f(&did_run);
+  f.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_OneShotTimer_Cancel(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run_a = false;
+  OneShotTimerTester* a = new OneShotTimerTester(&did_run_a);
+
+  // This should run before the timer expires.
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  OneShotTimerTester b(&did_run_b);
+  b.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_FALSE(did_run_a);
+  EXPECT_TRUE(did_run_b);
+}
+
+void RunTest_OneShotSelfDeletingTimer(
+    base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  OneShotSelfDeletingTimerTester f(&did_run);
+  f.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_RepeatingTimer(base::MessageLoop::Type message_loop_type,
+                            const TimeDelta& delay) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  RepeatingTimerTester f(&did_run, delay);
+  f.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_RepeatingTimer_Cancel(base::MessageLoop::Type message_loop_type,
+                                   const TimeDelta& delay) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run_a = false;
+  RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a, delay);
+
+  // This should run before the timer expires.
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  RepeatingTimerTester b(&did_run_b, delay);
+  b.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_FALSE(did_run_a);
+  EXPECT_TRUE(did_run_b);
+}
+
+class DelayTimerTarget {
+ public:
+  bool signaled() const { return signaled_; }
+
+  void Signal() {
+    ASSERT_FALSE(signaled_);
+    signaled_ = true;
+  }
+
+ private:
+  bool signaled_ = false;
+};
+
+void RunTest_DelayTimer_NoCall(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  // If Delay is never called, the timer shouldn't go off.
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run);
+  tester.Start();
+  base::MessageLoop::current()->Run();
+
+  ASSERT_FALSE(target.signaled());
+}
+
+void RunTest_DelayTimer_OneCall(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
+  tester.Start();
+  base::MessageLoop::current()->Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+struct ResetHelper {
+  ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
+              DelayTimerTarget* target)
+      : timer_(timer),
+        target_(target) {
+  }
+
+  void Reset() {
+    ASSERT_FALSE(target_->signaled());
+    timer_->Reset();
+  }
+
+ private:
+  base::DelayTimer<DelayTimerTarget> *const timer_;
+  DelayTimerTarget *const target_;
+};
+
+void RunTest_DelayTimer_Reset(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  // If Delay is never called, the timer shouldn't go off.
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(50), &target, &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  ResetHelper reset_helper(&timer, &target);
+
+  base::OneShotTimer<ResetHelper> timers[20];
+  for (size_t i = 0; i < arraysize(timers); ++i) {
+    timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10),
+                    &reset_helper, &ResetHelper::Reset);
+  }
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 300);
+  tester.Start();
+  base::MessageLoop::current()->Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+class DelayTimerFatalTarget {
+ public:
+  void Signal() {
+    ASSERT_TRUE(false);
+  }
+};
+
+
+void RunTest_DelayTimer_Deleted(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  DelayTimerFatalTarget target;
+
+  {
+    base::DelayTimer<DelayTimerFatalTarget> timer(
+        FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+        &DelayTimerFatalTarget::Signal);
+    timer.Reset();
+  }
+
+  // When the timer is deleted, the DelayTimerFatalTarget should never be
+  // called.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop.  That way we are sure
+// that timers work properly in all configurations.
+
+TEST(TimerTest, OneShotTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, OneShotTimer_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotTimer_Cancel(testing_message_loops[i]);
+  }
+}
+
+// If underline timer does not handle properly, we will crash or fail
+// in full page heap environment.
+TEST(TimerTest, OneShotSelfDeletingTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotSelfDeletingTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, OneShotTimer_CustomTaskRunner) {
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner =
+      new base::TestSimpleTaskRunner();
+
+  bool did_run = false;
+  OneShotTimerTester f(&did_run);
+  f.SetTaskRunner(task_runner);
+  f.Start();
+
+  EXPECT_FALSE(did_run);
+  task_runner->RunUntilIdle();
+  EXPECT_TRUE(did_run);
+}
+
+TEST(TimerTest, RepeatingTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer(testing_message_loops[i],
+                           TimeDelta::FromMilliseconds(10));
+  }
+}
+
+TEST(TimerTest, RepeatingTimer_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer_Cancel(testing_message_loops[i],
+                                  TimeDelta::FromMilliseconds(10));
+  }
+}
+
+TEST(TimerTest, RepeatingTimerZeroDelay) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer(testing_message_loops[i],
+                           TimeDelta::FromMilliseconds(0));
+  }
+}
+
+TEST(TimerTest, RepeatingTimerZeroDelay_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer_Cancel(testing_message_loops[i],
+                                  TimeDelta::FromMilliseconds(0));
+  }
+}
+
+TEST(TimerTest, DelayTimer_NoCall) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_NoCall(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, DelayTimer_OneCall) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_OneCall(testing_message_loops[i]);
+  }
+}
+
+// It's flaky on the buildbot, http://crbug.com/25038.
+TEST(TimerTest, DISABLED_DelayTimer_Reset) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_Reset(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, DelayTimer_Deleted) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_Deleted(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, MessageLoopShutdown) {
+  // This test is designed to verify that shutdown of the
+  // message loop does not cause crashes if there were pending
+  // timers not yet fired.  It may only trigger exceptions
+  // if debug heap checking is enabled.
+  bool did_run = false;
+  {
+    OneShotTimerTester a(&did_run);
+    OneShotTimerTester b(&did_run);
+    OneShotTimerTester c(&did_run);
+    OneShotTimerTester d(&did_run);
+    {
+      base::MessageLoop loop;
+      a.Start();
+      b.Start();
+    }  // MessageLoop destructs by falling out of scope.
+  }  // OneShotTimers destruct.  SHOULD NOT CRASH, of course.
+
+  EXPECT_FALSE(did_run);
+}
+
+void TimerTestCallback() {
+}
+
+TEST(TimerTest, NonRepeatIsRunning) {
+  {
+    base::MessageLoop loop;
+    base::Timer timer(false, false);
+    EXPECT_FALSE(timer.IsRunning());
+    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+                base::Bind(&TimerTestCallback));
+    EXPECT_TRUE(timer.IsRunning());
+    timer.Stop();
+    EXPECT_FALSE(timer.IsRunning());
+    EXPECT_TRUE(timer.user_task().is_null());
+  }
+
+  {
+    base::Timer timer(true, false);
+    base::MessageLoop loop;
+    EXPECT_FALSE(timer.IsRunning());
+    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+                base::Bind(&TimerTestCallback));
+    EXPECT_TRUE(timer.IsRunning());
+    timer.Stop();
+    EXPECT_FALSE(timer.IsRunning());
+    ASSERT_FALSE(timer.user_task().is_null());
+    timer.Reset();
+    EXPECT_TRUE(timer.IsRunning());
+  }
+}
+
+TEST(TimerTest, NonRepeatMessageLoopDeath) {
+  base::Timer timer(false, false);
+  {
+    base::MessageLoop loop;
+    EXPECT_FALSE(timer.IsRunning());
+    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+                base::Bind(&TimerTestCallback));
+    EXPECT_TRUE(timer.IsRunning());
+  }
+  EXPECT_FALSE(timer.IsRunning());
+  EXPECT_TRUE(timer.user_task().is_null());
+}
+
+TEST(TimerTest, RetainRepeatIsRunning) {
+  base::MessageLoop loop;
+  base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
+                    base::Bind(&TimerTestCallback), true);
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Stop();
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+}
+
+TEST(TimerTest, RetainNonRepeatIsRunning) {
+  base::MessageLoop loop;
+  base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
+                    base::Bind(&TimerTestCallback), false);
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Stop();
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+}
+
+namespace {
+
+bool g_callback_happened1 = false;
+bool g_callback_happened2 = false;
+
+void ClearAllCallbackHappened() {
+  g_callback_happened1 = false;
+  g_callback_happened2 = false;
+}
+
+void SetCallbackHappened1() {
+  g_callback_happened1 = true;
+  base::MessageLoop::current()->QuitWhenIdle();
+}
+
+void SetCallbackHappened2() {
+  g_callback_happened2 = true;
+  base::MessageLoop::current()->QuitWhenIdle();
+}
+
+TEST(TimerTest, ContinuationStopStart) {
+  {
+    ClearAllCallbackHappened();
+    base::MessageLoop loop;
+    base::Timer timer(false, false);
+    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
+                base::Bind(&SetCallbackHappened1));
+    timer.Stop();
+    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(40),
+                base::Bind(&SetCallbackHappened2));
+    base::MessageLoop::current()->Run();
+    EXPECT_FALSE(g_callback_happened1);
+    EXPECT_TRUE(g_callback_happened2);
+  }
+}
+
+TEST(TimerTest, ContinuationReset) {
+  {
+    ClearAllCallbackHappened();
+    base::MessageLoop loop;
+    base::Timer timer(false, false);
+    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
+                base::Bind(&SetCallbackHappened1));
+    timer.Reset();
+    // Since Reset happened before task ran, the user_task must not be cleared:
+    ASSERT_FALSE(timer.user_task().is_null());
+    base::MessageLoop::current()->Run();
+    EXPECT_TRUE(g_callback_happened1);
+  }
+}
+
+}  // namespace
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
new file mode 100644
index 0000000..2ddaf89
--- /dev/null
+++ b/base/tools_sanity_unittest.cc
@@ -0,0 +1,330 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file contains intentional memory errors, some of which may lead to
+// crashes if the test is ran without special memory testing tools. We use these
+// errors to verify the sanity of the tools.
+
+#include "base/atomicops.h"
+#include "base/debug/asan_invalid_access.h"
+#include "base/debug/profiler.h"
+#include "base/message_loop/message_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const base::subtle::Atomic32 kMagicValue = 42;
+
+// Helper for memory accesses that can potentially corrupt memory or cause a
+// crash during a native run.
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+#if defined(OS_IOS)
+// EXPECT_DEATH is not supported on IOS.
+#define HARMFUL_ACCESS(action,error_regexp) do { action; } while (0)
+#elif defined(SYZYASAN)
+// We won't get a meaningful error message because we're not running under the
+// SyzyASan logger, but we can at least make sure that the error has been
+// generated in the SyzyASan runtime.
+#define HARMFUL_ACCESS(action,unused) \
+if (debug::IsBinaryInstrumented()) { EXPECT_DEATH(action, \
+                                                  "AsanRuntime::OnError"); }
+#else
+#define HARMFUL_ACCESS(action,error_regexp) EXPECT_DEATH(action,error_regexp)
+#endif  // !OS_IOS && !SYZYASAN
+#else
+#define HARMFUL_ACCESS(action,error_regexp) \
+do { if (RunningOnValgrind()) { action; } } while (0)
+#endif
+
+void DoReadUninitializedValue(char *ptr) {
+  // Comparison with 64 is to prevent clang from optimizing away the
+  // jump -- valgrind only catches jumps and conditional moves, but clang uses
+  // the borrow flag if the condition is just `*ptr == '\0'`.
+  if (*ptr == 64) {
+    VLOG(1) << "Uninit condition is true";
+  } else {
+    VLOG(1) << "Uninit condition is false";
+  }
+}
+
+void ReadUninitializedValue(char *ptr) {
+#if defined(MEMORY_SANITIZER)
+  EXPECT_DEATH(DoReadUninitializedValue(ptr),
+               "use-of-uninitialized-value");
+#else
+  DoReadUninitializedValue(ptr);
+#endif
+}
+
+void ReadValueOutOfArrayBoundsLeft(char *ptr) {
+  char c = ptr[-2];
+  VLOG(1) << "Reading a byte out of bounds: " << c;
+}
+
+void ReadValueOutOfArrayBoundsRight(char *ptr, size_t size) {
+  char c = ptr[size + 1];
+  VLOG(1) << "Reading a byte out of bounds: " << c;
+}
+
+// This is harmless if you run it under Valgrind thanks to redzones.
+void WriteValueOutOfArrayBoundsLeft(char *ptr) {
+  ptr[-1] = kMagicValue;
+}
+
+// This is harmless if you run it under Valgrind thanks to redzones.
+void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) {
+  ptr[size] = kMagicValue;
+}
+
+void MakeSomeErrors(char *ptr, size_t size) {
+  ReadUninitializedValue(ptr);
+
+  HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(ptr),
+                 "2 bytes to the left");
+  HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(ptr, size),
+                 "1 bytes to the right");
+  HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(ptr),
+                 "1 bytes to the left");
+  HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(ptr, size),
+                 "0 bytes to the right");
+}
+
+}  // namespace
+
+// A memory leak detector should report an error in this test.
+TEST(ToolsSanityTest, MemoryLeak) {
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile leak = new int[256];  // Leak some memory intentionally.
+  leak[4] = 1;  // Make sure the allocated memory is used.
+}
+
+#if (defined(ADDRESS_SANITIZER) && defined(OS_IOS)) || defined(SYZYASAN)
+// Because iOS doesn't support death tests, each of the following tests will
+// crash the whole program under Asan. On Windows Asan is based on SyzyAsan; the
+// error report mechanism is different than with Asan so these tests will fail.
+#define MAYBE_AccessesToNewMemory DISABLED_AccessesToNewMemory
+#define MAYBE_AccessesToMallocMemory DISABLED_AccessesToMallocMemory
+#else
+#define MAYBE_AccessesToNewMemory AccessesToNewMemory
+#define MAYBE_AccessesToMallocMemory AccessesToMallocMemory
+#endif // (defined(ADDRESS_SANITIZER) && defined(OS_IOS)) || defined(SYZYASAN)
+
+// The following tests pass with Clang r170392, but not r172454, which
+// makes AddressSanitizer detect errors in them. We disable these tests under
+// AddressSanitizer until we fully switch to Clang r172454. After that the
+// tests should be put back under the (defined(OS_IOS) || defined(OS_WIN))
+// clause above.
+// See also http://crbug.com/172614.
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+#define MAYBE_SingleElementDeletedWithBraces \
+    DISABLED_SingleElementDeletedWithBraces
+#define MAYBE_ArrayDeletedWithoutBraces DISABLED_ArrayDeletedWithoutBraces
+#else
+#define MAYBE_ArrayDeletedWithoutBraces ArrayDeletedWithoutBraces
+#define MAYBE_SingleElementDeletedWithBraces SingleElementDeletedWithBraces
+#endif  // defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+TEST(ToolsSanityTest, MAYBE_AccessesToNewMemory) {
+  char *foo = new char[10];
+  MakeSomeErrors(foo, 10);
+  delete [] foo;
+  // Use after delete.
+  HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
+}
+
+TEST(ToolsSanityTest, MAYBE_AccessesToMallocMemory) {
+  char *foo = reinterpret_cast<char*>(malloc(10));
+  MakeSomeErrors(foo, 10);
+  free(foo);
+  // Use after free.
+  HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
+}
+
+TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) {
+#if !defined(ADDRESS_SANITIZER) && !defined(SYZYASAN)
+  // This test may corrupt memory if not run under Valgrind or compiled with
+  // AddressSanitizer.
+  if (!RunningOnValgrind())
+    return;
+#endif
+
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile foo = new int[10];
+  delete foo;
+}
+
+TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) {
+#if !defined(ADDRESS_SANITIZER)
+  // This test may corrupt memory if not run under Valgrind or compiled with
+  // AddressSanitizer.
+  if (!RunningOnValgrind())
+    return;
+#endif
+
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile foo = new int;
+  (void) foo;
+  delete [] foo;
+}
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is running.
+  // This test should not be ran on bots.
+  int* volatile zero = NULL;
+  *zero = 0;
+}
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerLocalOOBCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is instrumenting
+  // the local variables.
+  // This test should not be ran on bots.
+  int array[5];
+  // Work around the OOB warning reported by Clang.
+  int* volatile access = &array[5];
+  *access = 43;
+}
+
+namespace {
+int g_asan_test_global_array[10];
+}  // namespace
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerGlobalOOBCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is instrumenting
+  // the global variables.
+  // This test should not be ran on bots.
+
+  // Work around the OOB warning reported by Clang.
+  int* volatile access = g_asan_test_global_array - 1;
+  *access = 43;
+}
+
+TEST(ToolsSanityTest, AsanHeapOverflow) {
+  HARMFUL_ACCESS(debug::AsanHeapOverflow() ,"to the right");
+}
+
+TEST(ToolsSanityTest, AsanHeapUnderflow) {
+  HARMFUL_ACCESS(debug::AsanHeapUnderflow(), "to the left");
+}
+
+TEST(ToolsSanityTest, AsanHeapUseAfterFree) {
+  HARMFUL_ACCESS(debug::AsanHeapUseAfterFree(), "heap-use-after-free");
+}
+
+#if defined(SYZYASAN)
+TEST(ToolsSanityTest, AsanCorruptHeapBlock) {
+  HARMFUL_ACCESS(debug::AsanCorruptHeapBlock(), "");
+}
+
+TEST(ToolsSanityTest, AsanCorruptHeap) {
+  // This test will kill the process by raising an exception, there's no
+  // particular string to look for in the stack trace.
+  EXPECT_DEATH(debug::AsanCorruptHeap(), "");
+}
+#endif  // SYZYASAN
+
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+
+namespace {
+
+// We use caps here just to ensure that the method name doesn't interfere with
+// the wildcarded suppressions.
+class TOOLS_SANITY_TEST_CONCURRENT_THREAD : public PlatformThread::Delegate {
+ public:
+  explicit TOOLS_SANITY_TEST_CONCURRENT_THREAD(bool *value) : value_(value) {}
+  ~TOOLS_SANITY_TEST_CONCURRENT_THREAD() override {}
+  void ThreadMain() override {
+    *value_ = true;
+
+    // Sleep for a few milliseconds so the two threads are more likely to live
+    // simultaneously. Otherwise we may miss the report due to mutex
+    // lock/unlock's inside thread creation code in pure-happens-before mode...
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+ private:
+  bool *value_;
+};
+
+class ReleaseStoreThread : public PlatformThread::Delegate {
+ public:
+  explicit ReleaseStoreThread(base::subtle::Atomic32 *value) : value_(value) {}
+  ~ReleaseStoreThread() override {}
+  void ThreadMain() override {
+    base::subtle::Release_Store(value_, kMagicValue);
+
+    // Sleep for a few milliseconds so the two threads are more likely to live
+    // simultaneously. Otherwise we may miss the report due to mutex
+    // lock/unlock's inside thread creation code in pure-happens-before mode...
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+ private:
+  base::subtle::Atomic32 *value_;
+};
+
+class AcquireLoadThread : public PlatformThread::Delegate {
+ public:
+  explicit AcquireLoadThread(base::subtle::Atomic32 *value) : value_(value) {}
+  ~AcquireLoadThread() override {}
+  void ThreadMain() override {
+    // Wait for the other thread to make Release_Store
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+    base::subtle::Acquire_Load(value_);
+  }
+ private:
+  base::subtle::Atomic32 *value_;
+};
+
+void RunInParallel(PlatformThread::Delegate *d1, PlatformThread::Delegate *d2) {
+  PlatformThreadHandle a;
+  PlatformThreadHandle b;
+  PlatformThread::Create(0, d1, &a);
+  PlatformThread::Create(0, d2, &b);
+  PlatformThread::Join(a);
+  PlatformThread::Join(b);
+}
+
+#if defined(THREAD_SANITIZER)
+void DataRace() {
+  bool *shared = new bool(false);
+  TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(shared), thread2(shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_TRUE(*shared);
+  delete shared;
+  // We're in a death test - crash.
+  CHECK(0);
+}
+#endif
+
+}  // namespace
+
+#if defined(THREAD_SANITIZER)
+// A data race detector should report an error in this test.
+TEST(ToolsSanityTest, DataRace) {
+  // The suppression regexp must match that in base/debug/tsan_suppressions.cc.
+  EXPECT_DEATH(DataRace(), "1 race:base/tools_sanity_unittest.cc");
+}
+#endif
+
+TEST(ToolsSanityTest, AnnotateBenignRace) {
+  bool shared = false;
+  ANNOTATE_BENIGN_RACE(&shared, "Intentional race - make sure doesn't show up");
+  TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_TRUE(shared);
+}
+
+TEST(ToolsSanityTest, AtomicsAreIgnored) {
+  base::subtle::Atomic32 shared = 0;
+  ReleaseStoreThread thread1(&shared);
+  AcquireLoadThread thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_EQ(kMagicValue, shared);
+}
+
+}  // namespace base
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
new file mode 100644
index 0000000..633ab90
--- /dev/null
+++ b/base/trace_event/BUILD.gn
@@ -0,0 +1,107 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("trace_event") {
+  sources = [
+    "java_heap_dump_provider_android.cc",
+    "java_heap_dump_provider_android.h",
+    "memory_allocator_dump.cc",
+    "memory_allocator_dump.h",
+    "memory_dump_manager.cc",
+    "memory_dump_manager.h",
+    "memory_dump_provider.h",
+    "memory_dump_request_args.h",
+    "memory_dump_session_state.cc",
+    "memory_dump_session_state.h",
+    "process_memory_dump.cc",
+    "process_memory_dump.h",
+    "process_memory_maps.cc",
+    "process_memory_maps.h",
+    "process_memory_maps_dump_provider.cc",
+    "process_memory_maps_dump_provider.h",
+    "process_memory_totals.cc",
+    "process_memory_totals.h",
+    "process_memory_totals_dump_provider.cc",
+    "process_memory_totals_dump_provider.h",
+    "trace_event.h",
+    "trace_event_android.cc",
+    "trace_event_argument.cc",
+    "trace_event_argument.h",
+    "trace_event_etw_export_win.cc",
+    "trace_event_etw_export_win.h",
+    "trace_event_impl.cc",
+    "trace_event_impl.h",
+    "trace_event_impl_constants.cc",
+    "trace_event_memory.cc",
+    "trace_event_memory.h",
+    "trace_event_synthetic_delay.cc",
+    "trace_event_synthetic_delay.h",
+    "trace_event_system_stats_monitor.cc",
+    "trace_event_system_stats_monitor.h",
+    "trace_event_win.cc",
+    "trace_event_win.h",
+    "winheap_dump_provider_win.cc",
+    "winheap_dump_provider_win.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [
+      "process_memory_totals_dump_provider.cc",
+      "trace_event_system_stats_monitor.cc",
+    ]
+  }
+
+  if (is_linux || is_android) {
+    sources += [
+      "malloc_dump_provider.cc",
+      "malloc_dump_provider.h",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/debug",
+    "//base/json",
+    "//base/memory",
+    "//base/process",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  if (is_win) {
+    deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
+  }
+
+  allow_circular_includes_from = [
+    "//base/debug",
+    "//base/memory",
+    "//base/process",
+  ]
+
+  visibility = [ "//base/*" ]
+}
+
+source_set("trace_event_unittests") {
+  testonly = true
+  sources = [
+    "java_heap_dump_provider_android_unittest.cc",
+    "memory_allocator_dump_unittest.cc",
+    "memory_dump_manager_unittest.cc",
+    "process_memory_maps_dump_provider_unittest.cc",
+    "process_memory_totals_dump_provider_unittest.cc",
+    "trace_event_argument_unittest.cc",
+    "trace_event_memory_unittest.cc",
+    "trace_event_synthetic_delay_unittest.cc",
+    "trace_event_system_stats_monitor_unittest.cc",
+    "trace_event_unittest.cc",
+    "trace_event_win_unittest.cc",
+    "winheap_dump_provider_win_unittest.cc",
+  ]
+
+  deps = [
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/base/trace_event/OWNERS b/base/trace_event/OWNERS
new file mode 100644
index 0000000..aa1d675
--- /dev/null
+++ b/base/trace_event/OWNERS
@@ -0,0 +1,4 @@
+nduca@chromium.org
+dsinclair@chromium.org
+primiano@chromium.org
+per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
new file mode 100644
index 0000000..f62e356
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win, "This only runs on Windows.")
+
+# Makes the .h/.rc files from the .man file.
+action("chrome_events_win_generate") {
+  visibility = [ ":*" ]
+  script = "build/message_compiler.py"
+
+  sources = [
+    "chrome_events_win.man",
+  ]
+
+  outputs = [
+    "$target_gen_dir/chrome_events_win.h",
+    "$target_gen_dir/chrome_events_win.rc",
+  ]
+
+  args = [
+    # Where to put the header.
+    "-h",
+    rebase_path("$target_gen_dir", root_build_dir),
+
+    # Where to put the .rc file.
+    "-r",
+    rebase_path("$target_gen_dir", root_build_dir),
+
+    # Generate the user-mode code.
+    "-um",
+    rebase_path("chrome_events_win.man", root_build_dir),
+  ]
+}
+
+# Compile the generated files.
+source_set("chrome_events_win") {
+  visibility = [
+    "//base/trace_event/*",
+    "//chrome:main_dll",
+  ]
+
+  sources = get_target_outputs(":chrome_events_win_generate")
+
+  deps = [
+    ":chrome_events_win_generate",
+  ]
+}
diff --git a/base/trace_event/etw_manifest/BUILD/message_compiler.py b/base/trace_event/etw_manifest/BUILD/message_compiler.py
new file mode 100644
index 0000000..be5927d
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD/message_compiler.py
@@ -0,0 +1,16 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
+# GN build, which can only run Python and not native binaries.
+
+import subprocess
+import sys
+
+# mc writes to stderr, so this explicily redirects to stdout and eats it.
+try:
+  subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT)
+except subprocess.CalledProcessError as e:
+  print e.output
+  sys.exit(e.returncode)
diff --git a/base/trace_event/etw_manifest/chrome_events_win.man b/base/trace_event/etw_manifest/chrome_events_win.man
new file mode 100644
index 0000000..10a8ddf
--- /dev/null
+++ b/base/trace_event/etw_manifest/chrome_events_win.man
@@ -0,0 +1,84 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<instrumentationManifest
+    xmlns="http://schemas.microsoft.com/win/2004/08/events"
+    xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
+    >
+  <instrumentation>
+    <events>
+      <provider
+          guid="{D2D578D9-2936-45B6-A09f-30E32715F42D}"
+          messageFileName="chrome.dll"
+          name="Chrome"
+          resourceFileName="chrome.dll"
+          symbol="CHROME"
+          >
+        <channels>
+          <importChannel
+              chid="SYSTEM"
+              name="System"
+              />
+        </channels>
+        <templates>
+          <template tid="tid_chrome_event">
+            <data
+                inType="win:AnsiString"
+                name="Name"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Phase"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 1"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 1"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 2"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 2"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 3"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 3"
+                />
+          </template>
+        </templates>
+        <events>
+          <event
+              channel="SYSTEM"
+              level="win:Informational"
+              message="$(string.ChromeEvent.EventMessage)"
+              opcode="win:Info"
+              symbol="ChromeEvent"
+              template="tid_chrome_event"
+              value="1"
+              />
+        </events>
+      </provider>
+    </events>
+  </instrumentation>
+  <localization xmlns="http://schemas.microsoft.com/win/2004/08/events">
+    <resources culture="en-US">
+      <stringTable>
+        <string
+            id="ChromeEvent.EventMessage"
+            value="Chrome Event: %1 (%2)"
+            />
+      </stringTable>
+    </resources>
+  </localization>
+</instrumentationManifest>
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 0000000..b2f0eb8
--- /dev/null
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -0,0 +1,41 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      # GN version: //base/trace_event/etw_manifest/BUILD.gn
+      'target_name': 'etw_manifest',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'hard_dependency': 1,
+      'conditions': [
+        ['OS=="win"', {
+          'sources': [
+            'chrome_events_win.man',
+          ],
+          'variables': {
+            'man_output_dir': '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest',
+          },
+          'rules': [{
+            # Rule to run the message compiler.
+            'rule_name': 'message_compiler',
+            'extension': 'man',
+            'outputs': [
+              '<(man_output_dir)/chrome_events_win.h',
+              '<(man_output_dir)/chrome_events_win.rc',
+            ],
+            'action': [
+              'mc.exe',
+              '-h', '<(man_output_dir)',
+              '-r', '<(man_output_dir)/.',
+              '-um',
+              '<(RULE_INPUT_PATH)',
+            ],
+            'message': 'Running message compiler on <(RULE_INPUT_PATH)',
+          }],
+        }],
+      ],
+    }
+  ]
+}
diff --git a/base/trace_event/java_heap_dump_provider_android.cc b/base/trace_event/java_heap_dump_provider_android.cc
new file mode 100644
index 0000000..2a84b81
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/android/java_runtime.h"
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+JavaHeapDumpProvider* JavaHeapDumpProvider::GetInstance() {
+  return Singleton<JavaHeapDumpProvider,
+                   LeakySingletonTraits<JavaHeapDumpProvider>>::get();
+}
+
+JavaHeapDumpProvider::JavaHeapDumpProvider() {
+}
+
+JavaHeapDumpProvider::~JavaHeapDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot with the memory counters
+// for the current process.
+bool JavaHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("java_heap");
+
+  // These numbers come from java.lang.Runtime stats.
+  long total_heap_size = 0;
+  long free_heap_size = 0;
+  android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                  MemoryAllocatorDump::kUnitsBytes, total_heap_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                  MemoryAllocatorDump::kUnitsBytes,
+                  total_heap_size - free_heap_size);
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android.h b/base/trace_event/java_heap_dump_provider_android.h
new file mode 100644
index 0000000..2f31047
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+#define BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT JavaHeapDumpProvider : public MemoryDumpProvider {
+ public:
+  static JavaHeapDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
+
+  JavaHeapDumpProvider();
+  ~JavaHeapDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(JavaHeapDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
diff --git a/base/trace_event/java_heap_dump_provider_android_unittest.cc b/base/trace_event/java_heap_dump_provider_android_unittest.cc
new file mode 100644
index 0000000..bbefba5
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
+  auto jhdp = JavaHeapDumpProvider::GetInstance();
+  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+
+  jhdp->OnMemoryDump(pmd.get());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
new file mode 100644
index 0000000..c04b858
--- /dev/null
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/malloc_dump_provider.h"
+
+#include <malloc.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+MallocDumpProvider* MallocDumpProvider::GetInstance() {
+  return Singleton<MallocDumpProvider,
+                   LeakySingletonTraits<MallocDumpProvider>>::get();
+}
+
+MallocDumpProvider::MallocDumpProvider() {
+}
+
+MallocDumpProvider::~MallocDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool MallocDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  struct mallinfo info = mallinfo();
+  DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
+
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump("malloc");
+  if (!dump)
+    return false;
+
+  // When the system allocator is implemented by tcmalloc, the total physical
+  // size is given by |arena| and |hblkhd| is 0. In case of Android's jemalloc
+  // |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
+  // dlmalloc the total is given by |arena| + |hblkhd|.
+  // For more details see link: http://goo.gl/fMR8lF.
+  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                  MemoryAllocatorDump::kUnitsBytes, info.arena + info.hblkhd);
+
+  // Total allocated space is given by |uordblks|.
+  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                  MemoryAllocatorDump::kUnitsBytes, info.uordblks);
+
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
new file mode 100644
index 0000000..ec8683a
--- /dev/null
+++ b/base/trace_event/malloc_dump_provider.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
+ public:
+  static MallocDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<MallocDumpProvider>;
+
+  MallocDumpProvider();
+  ~MallocDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(MallocDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
new file mode 100644
index 0000000..edec31b
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -0,0 +1,119 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+// Returns the c-string pointer from a dictionary value without performing extra
+// std::string copies. The ptr will be valid as long as the value exists.
+bool GetDictionaryValueAsCStr(const DictionaryValue* dict_value,
+                              const std::string& key,
+                              const char** out_cstr) {
+  const Value* value = nullptr;
+  const StringValue* str_value = nullptr;
+  if (!dict_value->GetWithoutPathExpansion(key, &value))
+    return false;
+  if (!value->GetAsString(&str_value))
+    return false;
+  *out_cstr = str_value->GetString().c_str();
+  return true;
+}
+}  // namespace
+
+const char MemoryAllocatorDump::kNameOuterSize[] = "outer_size";
+const char MemoryAllocatorDump::kNameInnerSize[] = "inner_size";
+const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
+const char MemoryAllocatorDump::kTypeString[] = "string";
+const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
+const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
+                                         ProcessMemoryDump* process_memory_dump)
+    : absolute_name_(absolute_name), process_memory_dump_(process_memory_dump) {
+  // The |absolute_name| cannot be empty.
+  DCHECK(!absolute_name.empty());
+
+  // The |absolute_name| can contain slash separator, but not leading or
+  // trailing ones.
+  DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
+
+  // Dots are not allowed anywhere as the underlying base::DictionaryValue
+  // would treat them magically and split in sub-nodes, which is not intended.
+  DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
+}
+
+MemoryAllocatorDump::~MemoryAllocatorDump() {
+}
+
+void MemoryAllocatorDump::Add(const std::string& name,
+                              const char* type,
+                              const char* units,
+                              scoped_ptr<Value> value) {
+  scoped_ptr<DictionaryValue> attribute(new DictionaryValue());
+  DCHECK(!attributes_.HasKey(name));
+  attribute->SetStringWithoutPathExpansion("type", type);
+  attribute->SetStringWithoutPathExpansion("units", units);
+  attribute->SetWithoutPathExpansion("value", value.Pass());
+  attributes_.SetWithoutPathExpansion(name, attribute.Pass());
+}
+
+bool MemoryAllocatorDump::Get(const std::string& name,
+                              const char** out_type,
+                              const char** out_units,
+                              const Value** out_value) const {
+  const DictionaryValue* attribute = nullptr;
+  if (!attributes_.GetDictionaryWithoutPathExpansion(name, &attribute))
+    return false;
+
+  if (!GetDictionaryValueAsCStr(attribute, "type", out_type))
+    return false;
+
+  if (!GetDictionaryValueAsCStr(attribute, "units", out_units))
+    return false;
+
+  if (!attribute->GetWithoutPathExpansion("value", out_value))
+    return false;
+
+  return true;
+}
+
+void MemoryAllocatorDump::AddScalar(const std::string& name,
+                                    const char* units,
+                                    uint64 value) {
+  scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
+  Add(name, kTypeScalar, units, hex_value.Pass());
+}
+
+void MemoryAllocatorDump::AddString(const std::string& name,
+                                    const char* units,
+                                    const std::string& value) {
+  scoped_ptr<Value> str_value(new StringValue(value));
+  Add(name, kTypeString, units, str_value.Pass());
+}
+
+void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
+  value->BeginDictionary(absolute_name_.c_str());
+  value->BeginDictionary("attrs");
+
+  for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
+    value->SetValue(it.key().c_str(), it.value().CreateDeepCopy());
+
+  value->EndDictionary();  // "attrs": { ... }
+  value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
new file mode 100644
index 0000000..1bb27f9
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump.h
@@ -0,0 +1,82 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpManager;
+class ProcessMemoryDump;
+class TracedValue;
+
+// Data model for user-land memory allocator dumps.
+class BASE_EXPORT MemoryAllocatorDump {
+ public:
+  // MemoryAllocatorDump is owned by ProcessMemoryDump.
+  MemoryAllocatorDump(const std::string& absolute_name,
+                      ProcessMemoryDump* process_memory_dump);
+  ~MemoryAllocatorDump();
+
+  // Standard attribute name to model total space requested by the allocator
+  // (e.g., amount of pages requested to the system).
+  static const char kNameOuterSize[];
+
+  // Standard attribute name to model space for allocated objects, without
+  // taking into account allocator metadata or fragmentation.
+  static const char kNameInnerSize[];
+
+  // Standard attribute name to model the number of objects allocated.
+  static const char kNameObjectsCount[];
+
+  static const char kTypeScalar[];    // Type name for scalar attributes.
+  static const char kTypeString[];    // Type name for string attributes.
+  static const char kUnitsBytes[];    // Unit name to represent bytes.
+  static const char kUnitsObjects[];  // Unit name to represent #objects.
+
+  // Absolute name, unique within the scope of an entire ProcessMemoryDump.
+  const std::string& absolute_name() const { return absolute_name_; }
+
+  // Generic attribute setter / getter.
+  void Add(const std::string& name,
+           const char* type,
+           const char* units,
+           scoped_ptr<Value> value);
+  bool Get(const std::string& name,
+           const char** out_type,
+           const char** out_units,
+           const Value** out_value) const;
+
+  // Helper setter for scalar attributes.
+  void AddScalar(const std::string& name, const char* units, uint64 value);
+  void AddString(const std::string& name,
+                 const char* units,
+                 const std::string& value);
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  // Get the ProcessMemoryDump instance that owns this.
+  ProcessMemoryDump* process_memory_dump() const {
+    return process_memory_dump_;
+  }
+
+ private:
+  const std::string absolute_name_;
+  ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
+  DictionaryValue attributes_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
new file mode 100644
index 0000000..0b2cbdf
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
+ public:
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+    MemoryAllocatorDump* root_heap =
+        pmd->CreateAllocatorDump("foobar_allocator");
+
+    root_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                         MemoryAllocatorDump::kUnitsBytes, 4096);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                         MemoryAllocatorDump::kUnitsBytes, 1000);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                         MemoryAllocatorDump::kUnitsObjects, 42);
+    root_heap->AddScalar("attr1", "units1", 1234);
+    root_heap->AddString("attr2", "units2", "string_value");
+
+    MemoryAllocatorDump* sub_heap =
+        pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                        MemoryAllocatorDump::kUnitsBytes, 1);
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                        MemoryAllocatorDump::kUnitsBytes, 2);
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                        MemoryAllocatorDump::kUnitsObjects, 3);
+
+    pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
+    // Leave the rest of sub heap deliberately uninitialized, to check that
+    // CreateAllocatorDump returns a properly zero-initialized object.
+
+    return true;
+  }
+};
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+                    const std::string& name,
+                    const char* expected_type,
+                    const char* expected_units,
+                    const std::string& expected_value) {
+  const char* attr_type;
+  const char* attr_units;
+  const Value* attr_value;
+  std::string attr_str_value;
+  bool res = dump->Get(name, &attr_type, &attr_units, &attr_value);
+  EXPECT_TRUE(res);
+  if (!res)
+    return;
+  EXPECT_EQ(expected_type, std::string(attr_type));
+  EXPECT_EQ(expected_units, std::string(attr_units));
+  EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
+  EXPECT_EQ(expected_value, attr_str_value);
+}
+
+void CheckAttribute(const MemoryAllocatorDump* dump,
+                    const std::string& name,
+                    const char* expected_type,
+                    const char* expected_units,
+                    uint64 expected_value) {
+  CheckAttribute(dump, name, expected_type, expected_units,
+                 StringPrintf("%" PRIx64, expected_value));
+}
+}  // namespace
+
+TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
+  FakeMemoryAllocatorDumpProvider fmadp;
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+  fmadp.OnMemoryDump(&pmd);
+
+  ASSERT_EQ(3u, pmd.allocator_dumps().size());
+
+  const MemoryAllocatorDump* root_heap =
+      pmd.GetAllocatorDump("foobar_allocator");
+  ASSERT_NE(nullptr, root_heap);
+  EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
+  CheckAttribute(root_heap, MemoryAllocatorDump::kNameOuterSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 4096);
+  CheckAttribute(root_heap, MemoryAllocatorDump::kNameInnerSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 1000);
+  CheckAttribute(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsObjects, 42);
+  CheckAttribute(root_heap, "attr1", MemoryAllocatorDump::kTypeScalar, "units1",
+                 1234);
+  CheckAttribute(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
+                 "string_value");
+
+  const MemoryAllocatorDump* sub_heap =
+      pmd.GetAllocatorDump("foobar_allocator/sub_heap");
+  ASSERT_NE(nullptr, sub_heap);
+  EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
+  CheckAttribute(sub_heap, MemoryAllocatorDump::kNameOuterSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 1);
+  CheckAttribute(sub_heap, MemoryAllocatorDump::kNameInnerSize,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsBytes, 2);
+  CheckAttribute(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+                 MemoryAllocatorDump::kTypeScalar,
+                 MemoryAllocatorDump::kUnitsObjects, 3);
+
+  const MemoryAllocatorDump* empty_sub_heap =
+      pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
+  ASSERT_NE(nullptr, empty_sub_heap);
+  EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
+  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameOuterSize, nullptr,
+                                   nullptr, nullptr));
+  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameInnerSize, nullptr,
+                                   nullptr, nullptr));
+  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameObjectsCount,
+                                   nullptr, nullptr, nullptr));
+
+  // Check that the AsValueInfo doesn't hit any DCHECK.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd.AsValueInto(traced_value.get());
+}
+
+// DEATH tests are not supported in Android / iOS.
+#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
+TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
+  FakeMemoryAllocatorDumpProvider fmadp;
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  pmd.CreateAllocatorDump("foo_allocator");
+  pmd.CreateAllocatorDump("bar_allocator/heap");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
+}
+#endif
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
new file mode 100644
index 0000000..1e4d822
--- /dev/null
+++ b/base/trace_event/memory_dump_manager.cc
@@ -0,0 +1,405 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+
+#include <algorithm>
+
+#include "base/atomic_sequence_num.h"
+#include "base/compiler_specific.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if !defined(OS_NACL)
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include "base/trace_event/malloc_dump_provider.h"
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/trace_event/java_heap_dump_provider_android.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/trace_event/winheap_dump_provider_win.h"
+#endif
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// TODO(primiano): this should be smarter and should do something similar to
+// trace event synthetic delays.
+const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
+MemoryDumpManager* g_instance_for_testing = nullptr;
+const int kDumpIntervalSeconds = 2;
+const int kTraceEventNumArgs = 1;
+const char* kTraceEventArgNames[] = {"dumps"};
+const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+StaticAtomicSequenceNumber g_next_guid;
+
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+  switch (dump_type) {
+    case MemoryDumpType::TASK_BEGIN:
+      return "TASK_BEGIN";
+    case MemoryDumpType::TASK_END:
+      return "TASK_END";
+    case MemoryDumpType::PERIODIC_INTERVAL:
+      return "PERIODIC_INTERVAL";
+    case MemoryDumpType::EXPLICITLY_TRIGGERED:
+      return "EXPLICITLY_TRIGGERED";
+  }
+  NOTREACHED();
+  return "UNKNOWN";
+}
+
+// Internal class used to hold details about ProcessMemoryDump requests for the
+// current process.
+// TODO(primiano): In the upcoming CLs, ProcessMemoryDump will become async.
+// and this class will be used to convey more details across PostTask()s.
+class ProcessMemoryDumpHolder
+    : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
+ public:
+  ProcessMemoryDumpHolder(
+      MemoryDumpRequestArgs req_args,
+      const scoped_refptr<MemoryDumpSessionState>& session_state,
+      MemoryDumpCallback callback)
+      : process_memory_dump(session_state),
+        req_args(req_args),
+        callback(callback),
+        task_runner(MessageLoop::current()->task_runner()),
+        num_pending_async_requests(0) {}
+
+  ProcessMemoryDump process_memory_dump;
+  const MemoryDumpRequestArgs req_args;
+
+  // Callback passed to the initial call to CreateProcessDump().
+  MemoryDumpCallback callback;
+
+  // Thread on which FinalizeDumpAndAddToTrace() should be called, which is the
+  // same that invoked the initial CreateProcessDump().
+  const scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+  // Number of pending ContinueAsyncProcessDump() calls.
+  int num_pending_async_requests;
+
+ private:
+  friend class RefCountedThreadSafe<ProcessMemoryDumpHolder>;
+  virtual ~ProcessMemoryDumpHolder() {}
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpHolder);
+};
+
+void FinalizeDumpAndAddToTrace(
+    const scoped_refptr<ProcessMemoryDumpHolder>& pmd_holder) {
+  DCHECK_EQ(0, pmd_holder->num_pending_async_requests);
+
+  if (!pmd_holder->task_runner->BelongsToCurrentThread()) {
+    pmd_holder->task_runner->PostTask(
+        FROM_HERE, Bind(&FinalizeDumpAndAddToTrace, pmd_holder));
+    return;
+  }
+
+  scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
+  pmd_holder->process_memory_dump.AsValueInto(
+      static_cast<TracedValue*>(event_value.get()));
+  const char* const event_name =
+      MemoryDumpTypeToString(pmd_holder->req_args.dump_type);
+
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      TRACE_EVENT_PHASE_MEMORY_DUMP,
+      TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+      pmd_holder->req_args.dump_guid, kTraceEventNumArgs, kTraceEventArgNames,
+      kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+      TRACE_EVENT_FLAG_HAS_ID);
+
+  if (!pmd_holder->callback.is_null()) {
+    pmd_holder->callback.Run(pmd_holder->req_args.dump_guid, true);
+    pmd_holder->callback.Reset();
+  }
+}
+
+void RequestPeriodicGlobalDump() {
+  MemoryDumpManager::GetInstance()->RequestGlobalDump(
+      MemoryDumpType::PERIODIC_INTERVAL);
+}
+
+}  // namespace
+
+// static
+const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
+
+// static
+MemoryDumpManager* MemoryDumpManager::GetInstance() {
+  if (g_instance_for_testing)
+    return g_instance_for_testing;
+
+  return Singleton<MemoryDumpManager,
+                   LeakySingletonTraits<MemoryDumpManager>>::get();
+}
+
+// static
+void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
+  if (instance)
+    instance->skip_core_dumpers_auto_registration_for_testing_ = true;
+  g_instance_for_testing = instance;
+}
+
+MemoryDumpManager::MemoryDumpManager()
+    : delegate_(nullptr),
+      memory_tracing_enabled_(0),
+      skip_core_dumpers_auto_registration_for_testing_(false) {
+  g_next_guid.GetNext();  // Make sure that first guid is not zero.
+}
+
+MemoryDumpManager::~MemoryDumpManager() {
+  base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void MemoryDumpManager::Initialize() {
+  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
+  trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+
+  if (skip_core_dumpers_auto_registration_for_testing_)
+    return;
+
+  // Enable the core dump providers.
+#if !defined(OS_NACL)
+  RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
+  RegisterDumpProvider(MallocDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_ANDROID)
+  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_WIN)
+  RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+#endif
+}
+
+void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
+  AutoLock lock(lock_);
+  DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
+  delegate_ = delegate;
+}
+
+void MemoryDumpManager::RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+  MemoryDumpProviderInfo mdp_info(task_runner);
+  AutoLock lock(lock_);
+  dump_providers_.insert(std::make_pair(mdp, mdp_info));
+}
+
+void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+  RegisterDumpProvider(mdp, nullptr);
+}
+
+void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+  AutoLock lock(lock_);
+
+  auto it = dump_providers_.find(mdp);
+  if (it == dump_providers_.end())
+    return;
+
+  const MemoryDumpProviderInfo& mdp_info = it->second;
+  // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
+  // only if the MDP has specified a thread affinity (via task_runner()) AND
+  // the unregistration happens on the same thread (so the MDP cannot unregister
+  // and OnMemoryDump() at the same time).
+  // Otherwise, it is not possible to guarantee that its unregistration is
+  // race-free. If you hit this DCHECK, your MDP has a bug.
+  DCHECK_IMPLIES(
+      subtle::NoBarrier_Load(&memory_tracing_enabled_),
+      mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
+      << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
+      << " Please file a crbug.";
+
+  // Remove from the enabled providers list. This is to deal with the case that
+  // UnregisterDumpProvider is called while the trace is enabled.
+  dump_providers_.erase(it);
+}
+
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    const MemoryDumpCallback& callback) {
+  // Bail out immediately if tracing is not enabled at all.
+  if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
+    return;
+
+  const uint64 guid =
+      TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
+
+  // The delegate_ is supposed to be thread safe, immutable and long lived.
+  // No need to keep the lock after we ensure that a delegate has been set.
+  MemoryDumpManagerDelegate* delegate;
+  {
+    AutoLock lock(lock_);
+    delegate = delegate_;
+  }
+
+  if (delegate) {
+    // The delegate is in charge to coordinate the request among all the
+    // processes and call the CreateLocalDumpPoint on the local process.
+    MemoryDumpRequestArgs args = {guid, dump_type};
+    delegate->RequestGlobalMemoryDump(args, callback);
+  } else if (!callback.is_null()) {
+    callback.Run(guid, false /* success */);
+  }
+}
+
+void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
+  RequestGlobalDump(dump_type, MemoryDumpCallback());
+}
+
+// Creates a memory dump for the current process and appends it to the trace.
+void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
+                                          const MemoryDumpCallback& callback) {
+  scoped_refptr<ProcessMemoryDumpHolder> pmd_holder(
+      new ProcessMemoryDumpHolder(args, session_state_, callback));
+  ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+  bool did_any_provider_dump = false;
+
+  // Iterate over the active dump providers and invoke OnMemoryDump(pmd).
+  // The MDM guarantees linearity (at most one MDP is active within one
+  // process) and thread-safety (MDM enforces the right locking when entering /
+  // leaving the MDP.OnMemoryDump() call). This is to simplify the clients'
+  // design
+  // and not let the MDPs worry about locking.
+  // As regards thread affinity, depending on the MDP configuration (see
+  // memory_dump_provider.h), the OnMemoryDump() invocation can happen:
+  //  - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
+  //  - Posted on MDP.task_runner(), when MDP.task_runner() is set.
+  {
+    AutoLock lock(lock_);
+    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+      MemoryDumpProvider* mdp = it->first;
+      MemoryDumpProviderInfo* mdp_info = &it->second;
+      if (mdp_info->disabled)
+        continue;
+      if (mdp_info->task_runner) {
+        // The OnMemoryDump() call must be posted.
+        bool did_post_async_task = mdp_info->task_runner->PostTask(
+            FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+                            Unretained(this), Unretained(mdp), pmd_holder));
+        // The thread underlying the TaskRunner might have gone away.
+        if (did_post_async_task)
+          ++pmd_holder->num_pending_async_requests;
+      } else {
+        // Invoke the dump provider synchronously.
+        did_any_provider_dump |= InvokeDumpProviderLocked(mdp, pmd);
+      }
+    }
+  }  // AutoLock
+
+  // If at least one synchronous provider did dump and there are no pending
+  // asynchronous requests, add the dump to the trace and invoke the callback
+  // straight away (FinalizeDumpAndAddToTrace() takes care of the callback).
+  if (did_any_provider_dump && pmd_holder->num_pending_async_requests == 0)
+    FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+// Invokes the MemoryDumpProvider.OnMemoryDump(), taking care of the fail-safe
+// logic which disables the dumper when failing (crbug.com/461788).
+bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+                                                 ProcessMemoryDump* pmd) {
+  lock_.AssertAcquired();
+  bool dump_successful = mdp->OnMemoryDump(pmd);
+  if (!dump_successful) {
+    LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
+                  "(crbug.com/461788), disabling it for current process. Try "
+                  "restarting chrome with the --no-sandbox switch.";
+    dump_providers_.find(mdp)->second.disabled = true;
+  }
+  return dump_successful;
+}
+
+// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
+// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
+// happen on a different thread.
+void MemoryDumpManager::ContinueAsyncProcessDump(
+    MemoryDumpProvider* mdp,
+    scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
+  bool should_finalize_dump = false;
+  {
+    // The lock here is to guarantee that different asynchronous dumps on
+    // different threads are still serialized, so that the MemoryDumpProvider
+    // has a consistent view of the |pmd| argument passed.
+    AutoLock lock(lock_);
+    ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+
+    // Check if the MemoryDumpProvider is still there. It might have been
+    // destroyed and unregistered while hopping threads.
+    if (dump_providers_.count(mdp))
+      InvokeDumpProviderLocked(mdp, pmd);
+
+    // Finalize the dump appending it to the trace if this was the last
+    // asynchronous request pending.
+    --pmd_holder->num_pending_async_requests;
+    if (pmd_holder->num_pending_async_requests == 0)
+      should_finalize_dump = true;
+  }  // AutoLock(lock_)
+
+  if (should_finalize_dump)
+    FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+void MemoryDumpManager::OnTraceLogEnabled() {
+  // TODO(primiano): at this point we query  TraceLog::GetCurrentCategoryFilter
+  // to figure out (and cache) which dumpers should be enabled or not.
+  // For the moment piggy back everything on the generic "memory" category.
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+
+  AutoLock lock(lock_);
+
+  // There is no point starting the tracing without a delegate.
+  if (!enabled || !delegate_) {
+    // Disable all the providers.
+    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+      it->second.disabled = true;
+    return;
+  }
+
+  session_state_ = new MemoryDumpSessionState();
+  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+    it->second.disabled = false;
+
+  subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
+
+  if (delegate_->IsCoordinatorProcess()) {
+    periodic_dump_timer_.Start(FROM_HERE,
+                               TimeDelta::FromSeconds(kDumpIntervalSeconds),
+                               base::Bind(&RequestPeriodicGlobalDump));
+  }
+}
+
+void MemoryDumpManager::OnTraceLogDisabled() {
+  AutoLock lock(lock_);
+  periodic_dump_timer_.Stop();
+  subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
+  session_state_ = nullptr;
+}
+
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner(task_runner), disabled(false) {
+}
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
new file mode 100644
index 0000000..3645ac1
--- /dev/null
+++ b/base/trace_event/memory_dump_manager.h
@@ -0,0 +1,170 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+namespace {
+class ProcessMemoryDumpHolder;
+}
+
+class MemoryDumpManagerDelegate;
+class MemoryDumpProvider;
+class ProcessMemoryDump;
+class MemoryDumpSessionState;
+
+// This is the interface exposed to the rest of the codebase to deal with
+// memory tracing. The main entry point for clients is represented by
+// RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
+class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
+ public:
+  static const char* const kTraceCategoryForTesting;
+
+  static MemoryDumpManager* GetInstance();
+
+  // Invoked once per process to register the TraceLog observer.
+  void Initialize();
+
+  // See the lifetime and thread-safety requirements on the delegate below in
+  // the |MemoryDumpManagerDelegate| docstring.
+  void SetDelegate(MemoryDumpManagerDelegate* delegate);
+
+  // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
+  // expected to either be a singleton or unregister itself.
+  // If the optional |task_runner| argument is non-null, all the calls to the
+  // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
+  // able to handle calls on arbitrary threads.
+  void RegisterDumpProvider(
+      MemoryDumpProvider* mdp,
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+  void RegisterDumpProvider(MemoryDumpProvider* mdp);
+  void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+
+  // Requests a memory dump. The dump might happen or not depending on the
+  // filters and categories specified when enabling tracing.
+  // The optional |callback| is executed asynchronously, on an arbitrary thread,
+  // to notify about the completion of the global dump (i.e. after all the
+  // processes have dumped) and its success (true iff all the dumps were
+  // successful).
+  void RequestGlobalDump(MemoryDumpType dump_type,
+                         const MemoryDumpCallback& callback);
+
+  // Same as above (still asynchronous), but without callback.
+  void RequestGlobalDump(MemoryDumpType dump_type);
+
+  // TraceLog::EnabledStateObserver implementation.
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Returns the MemoryDumpSessionState object, which is shared by all the
+  // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
+  // session lifetime.
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
+ private:
+  // Descriptor struct used to hold information about registered MDPs. It is
+  // deliberately copyable, in order to allow to be used as hash_map value.
+  struct MemoryDumpProviderInfo {
+    MemoryDumpProviderInfo(
+        const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+    ~MemoryDumpProviderInfo();
+
+    scoped_refptr<SingleThreadTaskRunner> task_runner;  // Optional.
+    bool disabled;  // For fail-safe logic (auto-disable failing MDPs).
+  };
+
+  friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
+  friend struct DefaultSingletonTraits<MemoryDumpManager>;
+  friend class MemoryDumpManagerDelegate;
+  friend class MemoryDumpManagerTest;
+
+  static void SetInstanceForTesting(MemoryDumpManager* instance);
+
+  MemoryDumpManager();
+  virtual ~MemoryDumpManager();
+
+  // Internal, used only by MemoryDumpManagerDelegate.
+  // Creates a memory dump for the current process and appends it to the trace.
+  // |callback| will be invoked asynchronously upon completion on the same
+  // thread on which CreateProcessDump() was called.
+  void CreateProcessDump(const MemoryDumpRequestArgs& args,
+                         const MemoryDumpCallback& callback);
+
+  bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+                                ProcessMemoryDump* pmd);
+  void ContinueAsyncProcessDump(
+      MemoryDumpProvider* mdp,
+      scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
+
+  hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
+
+  // Shared among all the PMDs to keep state scoped to the tracing session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
+  MemoryDumpManagerDelegate* delegate_;  // Not owned.
+
+  // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
+  // to guard against disabling logging while dumping on another thread.
+  Lock lock_;
+
+  // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
+  // dump_providers_enabled_ list) when tracing is not enabled.
+  subtle::AtomicWord memory_tracing_enabled_;
+
+  // For time-triggered periodic dumps.
+  RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
+
+  // Skips the auto-registration of the core dumpers during Initialize().
+  bool skip_core_dumpers_auto_registration_for_testing_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
+};
+
+// The delegate is supposed to be long lived (read: a Singleton) and thread
+// safe (i.e. should expect calls from any thread and handle thread hopping).
+class BASE_EXPORT MemoryDumpManagerDelegate {
+ public:
+  virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
+                                       const MemoryDumpCallback& callback) = 0;
+
+  // Determines whether the MemoryDumpManager instance should be the master
+  // (the ones which initiates and coordinates the multiprocess dumps) or not.
+  virtual bool IsCoordinatorProcess() const = 0;
+
+ protected:
+  MemoryDumpManagerDelegate() {}
+  virtual ~MemoryDumpManagerDelegate() {}
+
+  void CreateProcessDump(const MemoryDumpRequestArgs& args,
+                         const MemoryDumpCallback& callback) {
+    MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
new file mode 100644
index 0000000..1da9429
--- /dev/null
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -0,0 +1,276 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
+namespace base {
+namespace trace_event {
+
+// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
+// instead of performing IPC dances.
+class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
+ public:
+  void RequestGlobalMemoryDump(
+      const base::trace_event::MemoryDumpRequestArgs& args,
+      const MemoryDumpCallback& callback) override {
+    CreateProcessDump(args, callback);
+  }
+
+  bool IsCoordinatorProcess() const override { return false; }
+};
+
+class MemoryDumpManagerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    message_loop_.reset(new MessageLoop());
+    mdm_.reset(new MemoryDumpManager());
+    MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+    ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
+    MemoryDumpManager::GetInstance()->Initialize();
+    MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
+  }
+
+  void TearDown() override {
+    MemoryDumpManager::SetInstanceForTesting(nullptr);
+    mdm_.reset();
+    message_loop_.reset();
+    TraceLog::DeleteForTesting();
+  }
+
+  void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                           Closure closure,
+                           uint64 dump_guid,
+                           bool success) {
+    task_runner->PostTask(FROM_HERE, closure);
+  }
+
+ protected:
+  const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
+
+  void EnableTracing(const char* category) {
+    TraceLog::GetInstance()->SetEnabled(
+        CategoryFilter(category), TraceLog::RECORDING_MODE, TraceOptions());
+  }
+
+  void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+
+  scoped_ptr<MemoryDumpManager> mdm_;
+
+ private:
+  scoped_ptr<MessageLoop> message_loop_;
+  MemoryDumpManagerDelegateForTesting delegate_;
+
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+};
+
+class MockDumpProvider : public MemoryDumpProvider {
+ public:
+  MockDumpProvider() : last_session_state_(nullptr) {}
+
+  // Ctor used by the RespectTaskRunnerAffinity test.
+  explicit MockDumpProvider(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+      : last_session_state_(nullptr), task_runner_(task_runner) {}
+
+  virtual ~MockDumpProvider() {}
+
+  MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));
+
+  // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
+  bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
+    EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
+    return true;
+  }
+
+  // OnMemoryDump() override for the SharedSessionState test.
+  bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
+    MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
+    if (last_session_state_)
+      EXPECT_EQ(last_session_state_, cur_session_state);
+    last_session_state_ = cur_session_state;
+    return true;
+  }
+
+ private:
+  MemoryDumpSessionState* last_session_state_;
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+};
+
+TEST_F(MemoryDumpManagerTest, SingleDumper) {
+  MockDumpProvider mdp;
+  mdm_->RegisterDumpProvider(&mdp);
+
+  // Check that the dumper is not called if the memory category is not enabled.
+  EnableTracing("foo-and-bar-but-not-memory");
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  // Now repeat enabling the memory category and check that the dumper is
+  // invoked this time.
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
+  for (int i = 0; i < 3; ++i)
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  // Finally check the unregister logic (no calls to the mdp after unregister).
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(MemoryDumpManagerTest, SharedSessionState) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+  mdm_->RegisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
+
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_))
+      .Times(2)
+      .WillRepeatedly(
+          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .Times(2)
+      .WillRepeatedly(
+          Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+
+  for (int i = 0; i < 2; ++i)
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+  DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+
+  // Enable only mdp1.
+  mdm_->RegisterDumpProvider(&mdp1);
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  // Invert: enable mdp1 and disable mdp2.
+  mdm_->UnregisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  // Enable both mdp1 and mdp2.
+  mdm_->RegisterDumpProvider(&mdp1);
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+}
+
+// Checks that the MemoryDumpManager respects the thread affinity when a
+// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
+// threads and registering a MemoryDumpProvider on each of them. At each
+// iteration, one thread is removed, to check the live unregistration logic.
+TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
+  const uint32 kNumInitialThreads = 8;
+
+  ScopedVector<Thread> threads;
+  ScopedVector<MockDumpProvider> mdps;
+
+  // Create the threads and setup the expectations. Given that at each iteration
+  // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
+  // invoked a number of times equal to its index.
+  for (uint32 i = kNumInitialThreads; i > 0; --i) {
+    threads.push_back(new Thread("test thread"));
+    threads.back()->Start();
+    mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
+    MockDumpProvider* mdp = mdps.back();
+    mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
+    EXPECT_CALL(*mdp, OnMemoryDump(_))
+        .Times(i)
+        .WillRepeatedly(
+            Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
+  }
+
+  EnableTracing(kTraceCategory);
+
+  while (!threads.empty()) {
+    {
+      RunLoop run_loop;
+      MemoryDumpCallback callback =
+          Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+               MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+      mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
+      // This nested message loop (|run_loop|) will be quit if and only if
+      // the RequestGlobalDump callback is invoked.
+      run_loop.Run();
+    }
+
+    // Unregister a MDP and destroy one thread at each iteration to check the
+    // live unregistration logic. The unregistration needs to happen on the same
+    // thread the MDP belongs to.
+    {
+      RunLoop run_loop;
+      Closure unregistration =
+          Bind(&MemoryDumpManager::UnregisterDumpProvider,
+               Unretained(mdm_.get()), Unretained(mdps.back()));
+      threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
+                                                      run_loop.QuitClosure());
+      run_loop.Run();
+    }
+    mdps.pop_back();
+    threads.back()->Stop();
+    threads.pop_back();
+  }
+
+  DisableTracing();
+}
+
+// Enable both dump providers, make mdp1 fail and assert that only mdp2 is
+// invoked the 2nd time.
+// FIXME(primiano): remove once crbug.com/461788 gets fixed.
+TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+
+  mdm_->RegisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
+  EnableTracing(kTraceCategory);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+  DisableTracing();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
new file mode 100644
index 0000000..6e6551c
--- /dev/null
+++ b/base/trace_event/memory_dump_provider.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// The contract interface that memory dump providers must implement.
+class BASE_EXPORT MemoryDumpProvider {
+ public:
+  // Called by the MemoryDumpManager when generating memory dumps.
+  // The embedder should return true if the |pmd| was successfully populated,
+  // false if something went wrong and the dump should be considered invalid.
+  // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
+  // MemoryDumpProvider for the entire trace session if it fails consistently).
+  virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
+
+ protected:
+  MemoryDumpProvider() {}
+  virtual ~MemoryDumpProvider() {}
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
new file mode 100644
index 0000000..4fb0335
--- /dev/null
+++ b/base/trace_event/memory_dump_request_args.h
@@ -0,0 +1,41 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_H_
+
+// This file defines the types and structs used to issue memory dump requests.
+// These are also used in the IPCs for coordinating inter-process memory dumps.
+
+#include "base/base_export.h"
+#include "base/callback.h"
+
+namespace base {
+namespace trace_event {
+
+// Captures the reason why a memory dump is being requested. This is to allow
+// selective enabling of dumps, filtering and post-processing.
+enum class MemoryDumpType {
+  TASK_BEGIN,         // Dumping memory at the beginning of a message-loop task.
+  TASK_END,           // Dumping memory at the ending of a message-loop task.
+  PERIODIC_INTERVAL,  // Dumping memory at periodic intervals.
+  EXPLICITLY_TRIGGERED,  // Non maskable dump request.
+  LAST = EXPLICITLY_TRIGGERED // For IPC macros.
+};
+
+using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+
+struct BASE_EXPORT MemoryDumpRequestArgs {
+  // Globally unique identifier. In multi-process dumps, all processes issue a
+  // local dump with the same guid. This allows the trace importers to
+  // reconstruct the global dump.
+  uint64 dump_guid;
+
+  MemoryDumpType dump_type;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_H_
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
new file mode 100644
index 0000000..433ac14
--- /dev/null
+++ b/base/trace_event/memory_dump_session_state.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_session_state.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryDumpSessionState::MemoryDumpSessionState() {
+}
+
+MemoryDumpSessionState::~MemoryDumpSessionState() {
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
new file mode 100644
index 0000000..cf29b85
--- /dev/null
+++ b/base/trace_event/memory_dump_session_state.h
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+namespace trace_event {
+
+// Container for state variables that should be shared across all the memory
+// dumps in a tracing session.
+class BASE_EXPORT MemoryDumpSessionState
+    : public RefCountedThreadSafe<MemoryDumpSessionState> {
+ public:
+  MemoryDumpSessionState();
+
+ private:
+  friend class RefCountedThreadSafe<MemoryDumpSessionState>;
+  ~MemoryDumpSessionState();
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
new file mode 100644
index 0000000..54fcad6
--- /dev/null
+++ b/base/trace_event/process_memory_dump.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_dump.h"
+
+#include "base/trace_event/process_memory_totals.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+ProcessMemoryDump::ProcessMemoryDump(
+    const scoped_refptr<MemoryDumpSessionState>& session_state)
+    : has_process_totals_(false),
+      has_process_mmaps_(false),
+      session_state_(session_state) {
+}
+
+ProcessMemoryDump::~ProcessMemoryDump() {
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+    const std::string& absolute_name) {
+  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this);
+  DCHECK_EQ(0ul, allocator_dumps_.count(absolute_name));
+  allocator_dumps_storage_.push_back(mad);
+  allocator_dumps_[absolute_name] = mad;
+  return mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
+    const std::string& absolute_name) const {
+  auto it = allocator_dumps_.find(absolute_name);
+  return it == allocator_dumps_.end() ? nullptr : it->second;
+}
+
+void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
+  // Build up the [dumper name] -> [value] dictionary.
+  if (has_process_totals_) {
+    value->BeginDictionary("process_totals");
+    process_totals_.AsValueInto(value);
+    value->EndDictionary();
+  }
+  if (has_process_mmaps_) {
+    value->BeginDictionary("process_mmaps");
+    process_mmaps_.AsValueInto(value);
+    value->EndDictionary();
+  }
+  if (allocator_dumps_storage_.size() > 0) {
+    value->BeginDictionary("allocators");
+    for (const MemoryAllocatorDump* allocator_dump : allocator_dumps_storage_)
+      allocator_dump->AsValueInto(value);
+    value->EndDictionary();
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
new file mode 100644
index 0000000..889356d
--- /dev/null
+++ b/base/trace_event/process_memory_dump.h
@@ -0,0 +1,94 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+class ConvertableToTraceFormat;
+class MemoryDumpManager;
+class MemoryDumpSessionState;
+
+// ProcessMemoryDump is as a strongly typed container which enforces the data
+// model for each memory dump and holds the dumps produced by the
+// MemoryDumpProvider(s) for a specific process.
+// At trace generation time (i.e. when AsValue() is called), ProcessMemoryDump
+// will compose a key-value dictionary of the various dumps obtained at trace
+// dump point time.
+class BASE_EXPORT ProcessMemoryDump {
+ public:
+  // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
+  // MemoryAllocatorDump instances.
+  using AllocatorDumpsMap =
+      SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
+
+  ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
+  ~ProcessMemoryDump();
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  ProcessMemoryTotals* process_totals() { return &process_totals_; }
+  bool has_process_totals() const { return has_process_totals_; }
+  void set_has_process_totals() { has_process_totals_ = true; }
+
+  ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+  bool has_process_mmaps() const { return has_process_mmaps_; }
+  void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
+  // Creates a new MemoryAllocatorDump with the given name and returns the
+  // empty object back to the caller.
+  // Arguments:
+  //   absolute_name: a name that uniquely identifies allocator dumps produced
+  //       by this provider. It is possible to specify nesting by using a
+  //       path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
+  //       Leading or trailing slashes are not allowed.
+  // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
+
+  // Looks up a MemoryAllocatorDump given its allocator and heap names, or
+  // nullptr if not found.
+  MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
+
+  // Returns the map of the MemoryAllocatorDumps added to this dump.
+  const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
+ private:
+  ProcessMemoryTotals process_totals_;
+  bool has_process_totals_;
+
+  ProcessMemoryMaps process_mmaps_;
+  bool has_process_mmaps_;
+
+  AllocatorDumpsMap allocator_dumps_;
+
+  // ProcessMemoryDump handles the memory ownership of all its belongings.
+  ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
+
+  // State shared among all PMDs instances created in a given trace session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
new file mode 100644
index 0000000..d553ee8
--- /dev/null
+++ b/base/trace_event/process_memory_maps.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+
+ProcessMemoryMaps::ProcessMemoryMaps() {
+}
+
+ProcessMemoryMaps::~ProcessMemoryMaps() {
+}
+
+void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
+  static const char kHexFmt[] = "%" PRIx64;
+
+  // Refer to the design doc goo.gl/sxfFY8 for the semantic of these fields.
+  value->BeginArray("vm_regions");
+  for (const auto& region : vm_regions_) {
+    value->BeginDictionary();
+
+    value->SetString("sa", StringPrintf(kHexFmt, region.start_address));
+    value->SetString("sz", StringPrintf(kHexFmt, region.size_in_bytes));
+    value->SetInteger("pf", region.protection_flags);
+    value->SetString("mf", region.mapped_file);
+
+    value->BeginDictionary("bs");  // byte stats
+    value->SetString(
+        "pss", StringPrintf(kHexFmt, region.byte_stats_proportional_resident));
+    value->SetString("prv",
+                     StringPrintf(kHexFmt, region.byte_stats_private_resident));
+    value->SetString("shr",
+                     StringPrintf(kHexFmt, region.byte_stats_shared_resident));
+    value->EndDictionary();
+
+    value->EndDictionary();
+  }
+  value->EndArray();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
new file mode 100644
index 0000000..dc1892f
--- /dev/null
+++ b/base/trace_event/process_memory_maps.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMaps {
+ public:
+  struct VMRegion {
+    static const uint32 kProtectionFlagsRead;
+    static const uint32 kProtectionFlagsWrite;
+    static const uint32 kProtectionFlagsExec;
+
+    uint64 start_address;
+    uint64 size_in_bytes;
+    uint32 protection_flags;
+    std::string mapped_file;
+
+    // private_resident + shared_resident = resident set size.
+    uint64 byte_stats_private_resident;
+    uint64 byte_stats_shared_resident;
+
+    // For multiprocess accounting.
+    uint64 byte_stats_proportional_resident;
+  };
+
+  ProcessMemoryMaps();
+  ~ProcessMemoryMaps();
+
+  void AddVMRegion(const VMRegion& region) { vm_regions_.push_back(region); }
+  const std::vector<VMRegion>& vm_regions() const { return vm_regions_; }
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+ private:
+  std::vector<VMRegion> vm_regions_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMaps);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
new file mode 100644
index 0000000..680fa29
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -0,0 +1,189 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <cctype>
+#include <fstream>
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// static
+std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
+
+namespace {
+
+const uint32 kMaxLineSize = 4096;
+
+bool ParseSmapsHeader(std::istream* smaps,
+                      ProcessMemoryMaps::VMRegion* region) {
+  // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234  /foo.so\n"
+  bool res = true;  // Whether this region should be appended or skipped.
+  uint64 end_addr;
+  std::string protection_flags;
+  std::string ignored;
+  *smaps >> std::hex >> region->start_address;
+  smaps->ignore(1);
+  *smaps >> std::hex >> end_addr;
+  if (end_addr > region->start_address) {
+    region->size_in_bytes = end_addr - region->start_address;
+  } else {
+    // This is not just paranoia, it can actually happen (See crbug.com/461237).
+    region->size_in_bytes = 0;
+    res = false;
+  }
+
+  region->protection_flags = 0;
+  *smaps >> protection_flags;
+  CHECK_EQ(4UL, protection_flags.size());
+  if (protection_flags[0] == 'r') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  }
+  if (protection_flags[1] == 'w') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  }
+  if (protection_flags[2] == 'x') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+  }
+  *smaps >> ignored;  // Ignore mapped file offset.
+  *smaps >> ignored;  // Ignore device maj-min (fc:01 in the example above).
+  *smaps >> ignored;  // Ignore inode number (1234 in the example above).
+
+  while (smaps->peek() == ' ')
+    smaps->ignore(1);
+  char mapped_file[kMaxLineSize];
+  smaps->getline(mapped_file, sizeof(mapped_file));
+  region->mapped_file = mapped_file;
+
+  return res;
+}
+
+uint64 ReadCounterBytes(std::istream* smaps) {
+  uint64 counter_value = 0;
+  *smaps >> std::dec >> counter_value;
+  return counter_value * 1024;
+}
+
+uint32 ParseSmapsCounter(std::istream* smaps,
+                         ProcessMemoryMaps::VMRegion* region) {
+  // A smaps counter lines looks as follows: "RSS:  0 Kb\n"
+  uint32 res = 0;
+  std::string counter_name;
+  *smaps >> counter_name;
+
+  // TODO(primiano): "Swap" should also be accounted as resident. Check
+  // whether Rss isn't already counting swapped and fix below if that is
+  // the case.
+  if (counter_name == "Pss:") {
+    region->byte_stats_proportional_resident = ReadCounterBytes(smaps);
+    res = 1;
+  } else if (counter_name == "Private_Dirty:" ||
+             counter_name == "Private_Clean:") {
+    // For Private and Shared counters keep the sum of the dirty + clean stats.
+    region->byte_stats_private_resident += ReadCounterBytes(smaps);
+    res = 1;
+  } else if (counter_name == "Shared_Dirty:" ||
+             counter_name == "Shared_Clean:") {
+    region->byte_stats_shared_resident += ReadCounterBytes(smaps);
+    res = 1;
+  }
+
+#ifndef NDEBUG
+  // Paranoid check against changes of the Kernel /proc interface.
+  if (res) {
+    std::string unit;
+    *smaps >> unit;
+    DCHECK_EQ("kB", unit);
+  }
+#endif
+
+  smaps->ignore(kMaxLineSize, '\n');
+
+  return res;
+}
+
+uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
+  if (!smaps->good())
+    return 0;
+
+  const uint32 kNumExpectedCountersPerRegion = 5;
+  uint32 counters_parsed_for_current_region = 0;
+  uint32 num_valid_regions = 0;
+  ProcessMemoryMaps::VMRegion region;
+  bool should_add_current_region = false;
+  for (;;) {
+    int next = smaps->peek();
+    if (next == std::ifstream::traits_type::eof() || next == '\n')
+      break;
+    if (isxdigit(next) && !isupper(next)) {
+      region = {0};
+      counters_parsed_for_current_region = 0;
+      should_add_current_region = ParseSmapsHeader(smaps, &region);
+    } else {
+      counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+      DCHECK_LE(counters_parsed_for_current_region,
+                kNumExpectedCountersPerRegion);
+      if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
+        if (should_add_current_region) {
+          pmm->AddVMRegion(region);
+          ++num_valid_regions;
+          should_add_current_region = false;
+        }
+      }
+    }
+  }
+  return num_valid_regions;
+}
+
+}  // namespace
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// static
+ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
+  return Singleton<ProcessMemoryMapsDumpProvider,
+                   LeakySingletonTraits<ProcessMemoryMapsDumpProvider>>::get();
+}
+
+ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() {
+}
+
+ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory maps for the
+// current process.
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  uint32 res = 0;
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (UNLIKELY(proc_smaps_for_testing)) {
+    res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
+  } else {
+    std::ifstream proc_self_smaps("/proc/self/smaps");
+    res = ReadLinuxProcSmapsFile(&proc_self_smaps, pmd->process_mmaps());
+  }
+#else
+  LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
+#endif
+
+  if (res > 0) {
+    pmd->set_has_process_mmaps();
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
new file mode 100644
index 0000000..c73c4d2
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
+ public:
+  static ProcessMemoryMapsDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
+  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  static std::istream* proc_smaps_for_testing;
+#endif
+
+  ProcessMemoryMapsDumpProvider();
+  ~ProcessMemoryMapsDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMapsDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
new file mode 100644
index 0000000..e45d30a
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+namespace {
+const char kTestSmaps1[] =
+    "00400000-004be000 r-xp 00000000 fc:01 1234              /file/1\n"
+    "Size:                760 kB\n"
+    "Rss:                 296 kB\n"
+    "Pss:                 162 kB\n"
+    "Shared_Clean:        228 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:        68 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:            68 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    "ff000000-ff800000 -w-p 00001080 fc:01 0            /file/name with space\n"
+    "Size:                  0 kB\n"
+    "Rss:                 192 kB\n"
+    "Pss:                 128 kB\n"
+    "Shared_Clean:        120 kB\n"
+    "Shared_Dirty:          4 kB\n"
+    "Private_Clean:        60 kB\n"
+    "Private_Dirty:         8 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd";
+
+const char kTestSmaps2[] =
+    // An invalid region, with zero size and overlapping with the last one
+    // (See crbug.com/461237).
+    "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A invalid region with its range going backwards.
+    "00400000-00200000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A good anonymous region at the end.
+    "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
+    "Size:                 48 kB\n"
+    "Rss:                  40 kB\n"
+    "Pss:                  32 kB\n"
+    "Shared_Clean:         16 kB\n"
+    "Shared_Dirty:         12 kB\n"
+    "Private_Clean:         8 kB\n"
+    "Private_Dirty:         4 kB\n"
+    "Referenced:           40 kB\n"
+    "Anonymous:            16 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd wr mr mw me ac sd\n";
+}  // namespace
+
+TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
+  const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+
+  auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
+
+  // Emulate a non-existent /proc/self/smaps.
+  ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
+  std::ifstream non_existent_file("/tmp/does-not-exist");
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
+  CHECK_EQ(false, non_existent_file.good());
+  pmmdp->OnMemoryDump(&pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Emulate an empty /proc/self/smaps.
+  std::ifstream empty_file("/dev/null");
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
+  CHECK_EQ(true, empty_file.good());
+  pmmdp->OnMemoryDump(&pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Parse the 1st smaps file.
+  ProcessMemoryDump pmd_1(nullptr /* session_state */);
+  std::istringstream test_smaps_1(kTestSmaps1);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
+  pmmdp->OnMemoryDump(&pmd_1);
+  ASSERT_TRUE(pmd_1.has_process_mmaps());
+  const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
+  ASSERT_EQ(2UL, regions_1.size());
+
+  EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
+  EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
+  EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
+  EXPECT_EQ("/file/1", regions_1[0].mapped_file);
+  EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
+  EXPECT_EQ((228 + 0) * 1024UL, regions_1[0].byte_stats_shared_resident);
+  EXPECT_EQ((0 + 68) * 1024UL, regions_1[0].byte_stats_private_resident);
+
+  EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
+  EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
+  EXPECT_EQ(kProtW, regions_1[1].protection_flags);
+  EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
+  EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
+  EXPECT_EQ((120 + 4) * 1024UL, regions_1[1].byte_stats_shared_resident);
+  EXPECT_EQ((60 + 8) * 1024UL, regions_1[1].byte_stats_private_resident);
+
+  // Parse the 2nd smaps file.
+  ProcessMemoryDump pmd_2(nullptr /* session_state */);
+  std::istringstream test_smaps_2(kTestSmaps2);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
+  pmmdp->OnMemoryDump(&pmd_2);
+  ASSERT_TRUE(pmd_2.has_process_mmaps());
+  const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
+  ASSERT_EQ(1UL, regions_2.size());
+  EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
+  EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
+  EXPECT_EQ(0U, regions_2[0].protection_flags);
+  EXPECT_EQ("", regions_2[0].mapped_file);
+  EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
+  EXPECT_EQ((16 + 12) * 1024UL, regions_2[0].byte_stats_shared_resident);
+  EXPECT_EQ((8 + 4) * 1024UL, regions_2[0].byte_stats_private_resident);
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
new file mode 100644
index 0000000..9b0c377
--- /dev/null
+++ b/base/trace_event/process_memory_totals.cc
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
+  value->SetString("resident_set_bytes",
+                   StringPrintf("%" PRIx64, resident_set_bytes_));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
new file mode 100644
index 0000000..29c94c9
--- /dev/null
+++ b/base/trace_event/process_memory_totals.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotals {
+ public:
+  ProcessMemoryTotals() : resident_set_bytes_(0) {}
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  uint64 resident_set_bytes() const { return resident_set_bytes_; }
+  void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+
+ private:
+  uint64 resident_set_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
new file mode 100644
index 0000000..06b537c
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+uint64 ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+namespace {
+
+ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
+#else
+  return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle(), NULL);
+#endif
+}
+}  // namespace
+
+// static
+ProcessMemoryTotalsDumpProvider*
+ProcessMemoryTotalsDumpProvider::GetInstance() {
+  return Singleton<
+      ProcessMemoryTotalsDumpProvider,
+      LeakySingletonTraits<ProcessMemoryTotalsDumpProvider>>::get();
+}
+
+ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
+    : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
+}
+
+ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  const uint64 rss_bytes = rss_bytes_for_testing
+                               ? rss_bytes_for_testing
+                               : process_metrics_->GetWorkingSetSize();
+
+  if (rss_bytes > 0) {
+    pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+    pmd->set_has_process_totals();
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
new file mode 100644
index 0000000..6c86eb6
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+
+class ProcessMetrics;
+
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider {
+ public:
+  static ProcessMemoryTotalsDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
+  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS);
+
+  static uint64 rss_bytes_for_testing;
+
+  ProcessMemoryTotalsDumpProvider();
+  ~ProcessMemoryTotalsDumpProvider() override;
+
+  scoped_ptr<ProcessMetrics> process_metrics_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotalsDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
new file mode 100644
index 0000000..f9bb6c0
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
+  auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
+  scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr));
+  scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
+
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
+  pmtdp->OnMemoryDump(pmd_before.get());
+
+  // Pretend that the RSS of the process increased of +1M.
+  const size_t kAllocSize = 1048576;
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
+
+  pmtdp->OnMemoryDump(pmd_after.get());
+
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+  ASSERT_TRUE(pmd_before->has_process_totals());
+  ASSERT_TRUE(pmd_after->has_process_totals());
+
+  const uint64 rss_before = pmd_before->process_totals()->resident_set_bytes();
+  const uint64 rss_after = pmd_after->process_totals()->resident_set_bytes();
+
+  EXPECT_NE(0U, rss_before);
+  EXPECT_NE(0U, rss_after);
+
+  EXPECT_EQ(rss_after - rss_before, kAllocSize);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
new file mode 100644
index 0000000..9a072e4
--- /dev/null
+++ b/base/trace_event/trace_event.gypi
@@ -0,0 +1,70 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'variables': {
+    'trace_event_sources' : [
+      'trace_event/java_heap_dump_provider_android.cc',
+      'trace_event/java_heap_dump_provider_android.h',
+      'trace_event/memory_allocator_dump.cc',
+      'trace_event/memory_allocator_dump.h',
+      'trace_event/memory_dump_manager.cc',
+      'trace_event/memory_dump_manager.h',
+      'trace_event/memory_dump_provider.h',
+      'trace_event/memory_dump_request_args.h',
+      'trace_event/memory_dump_session_state.cc',
+      'trace_event/memory_dump_session_state.h',
+      'trace_event/process_memory_dump.cc',
+      'trace_event/process_memory_dump.h',
+      'trace_event/process_memory_maps.cc',
+      'trace_event/process_memory_maps.h',
+      'trace_event/process_memory_maps_dump_provider.cc',
+      'trace_event/process_memory_maps_dump_provider.h',
+      'trace_event/process_memory_totals.cc',
+      'trace_event/process_memory_totals.h',
+      'trace_event/process_memory_totals_dump_provider.cc',
+      'trace_event/process_memory_totals_dump_provider.h',
+      'trace_event/trace_event.h',
+      'trace_event/trace_event_android.cc',
+      'trace_event/trace_event_argument.cc',
+      'trace_event/trace_event_argument.h',
+      'trace_event/trace_event_etw_export_win.cc',
+      'trace_event/trace_event_etw_export_win.h',
+      'trace_event/trace_event_impl.cc',
+      'trace_event/trace_event_impl.h',
+      'trace_event/trace_event_impl_constants.cc',
+      'trace_event/trace_event_memory.cc',
+      'trace_event/trace_event_memory.h',
+      'trace_event/trace_event_synthetic_delay.cc',
+      'trace_event/trace_event_synthetic_delay.h',
+      'trace_event/trace_event_system_stats_monitor.cc',
+      'trace_event/trace_event_system_stats_monitor.h',
+      'trace_event/trace_event_win.cc',
+      'trace_event/trace_event_win.h',
+      'trace_event/winheap_dump_provider_win.cc',
+      'trace_event/winheap_dump_provider_win.h',
+    ],
+    'conditions': [
+      ['OS == "linux" or OS == "android"', {
+          'trace_event_sources': [
+            'trace_event/malloc_dump_provider.cc',
+            'trace_event/malloc_dump_provider.h',
+          ],
+      }],
+    ],
+    'trace_event_test_sources' : [
+      'trace_event/java_heap_dump_provider_android_unittest.cc',
+      'trace_event/memory_allocator_dump_unittest.cc',
+      'trace_event/memory_dump_manager_unittest.cc',
+      'trace_event/process_memory_maps_dump_provider_unittest.cc',
+      'trace_event/process_memory_totals_dump_provider_unittest.cc',
+      'trace_event/trace_event_argument_unittest.cc',
+      'trace_event/trace_event_memory_unittest.cc',
+      'trace_event/trace_event_synthetic_delay_unittest.cc',
+      'trace_event/trace_event_system_stats_monitor_unittest.cc',
+      'trace_event/trace_event_unittest.cc',
+      'trace_event/trace_event_win_unittest.cc',
+      'trace_event/winheap_dump_provider_win_unittest.cc',
+    ],
+  },
+}
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
new file mode 100644
index 0000000..d4e8070
--- /dev/null
+++ b/base/trace_event/trace_event.h
@@ -0,0 +1,1671 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header file defines the set of trace_event macros without specifying
+// how the events actually get collected and stored. If you need to expose trace
+// events to some other universe, you can copy-and-paste this file as well as
+// trace_event.h, modifying the macros contained there as necessary for the
+// target platform. The end result is that multiple libraries can funnel events
+// through to a shared trace event collector.
+
+// Trace events are for tracking application performance and resource usage.
+// Macros are provided to track:
+//    Begin and end of function calls
+//    Counters
+//
+// Events are issued against categories. Whereas LOG's
+// categories are statically defined, TRACE categories are created
+// implicitly with a string. For example:
+//   TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent",
+//                        TRACE_EVENT_SCOPE_THREAD)
+//
+// It is often the case that one trace may belong in multiple categories at the
+// same time. The first argument to the trace can be a comma-separated list of
+// categories, forming a category group, like:
+//
+// TRACE_EVENT_INSTANT0("input,views", "OnMouseOver", TRACE_EVENT_SCOPE_THREAD)
+//
+// We can enable/disable tracing of OnMouseOver by enabling/disabling either
+// category.
+//
+// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
+//   TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
+//   doSomethingCostly()
+//   TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
+// Note: our tools can't always determine the correct BEGIN/END pairs unless
+// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
+// need them to be in separate scopes.
+//
+// A common use case is to trace entire function scopes. This
+// issues a trace BEGIN and END automatically:
+//   void doSomethingCostly() {
+//     TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
+//     ...
+//   }
+//
+// Additional parameters can be associated with an event:
+//   void doSomethingCostly2(int howMuch) {
+//     TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
+//         "howMuch", howMuch);
+//     ...
+//   }
+//
+// The trace system will automatically add to this information the
+// current process id, thread id, and a timestamp in microseconds.
+//
+// To trace an asynchronous procedure such as an IPC send/receive, use
+// ASYNC_BEGIN and ASYNC_END:
+//   [single threaded sender code]
+//     static int send_count = 0;
+//     ++send_count;
+//     TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
+//     Send(new MyMessage(send_count));
+//   [receive code]
+//     void OnMyMessage(send_count) {
+//       TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
+//     }
+// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
+// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
+// Pointers can be used for the ID parameter, and they will be mangled
+// internally so that the same pointer on two different processes will not
+// match. For example:
+//   class MyTracedClass {
+//    public:
+//     MyTracedClass() {
+//       TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
+//     }
+//     ~MyTracedClass() {
+//       TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
+//     }
+//   }
+//
+// Trace event also supports counters, which is a way to track a quantity
+// as it varies over time. Counters are created with the following macro:
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
+//
+// Counters are process-specific. The macro itself can be issued from any
+// thread, however.
+//
+// Sometimes, you want to track two counters at once. You can do this with two
+// counter macros:
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
+// Or you can do it with a combined macro:
+//   TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
+//       "bytesPinned", g_myCounterValue[0],
+//       "bytesAllocated", g_myCounterValue[1]);
+// This indicates to the tracing UI that these counters should be displayed
+// in a single graph, as a summed area chart.
+//
+// Since counters are in a global namespace, you may want to disambiguate with a
+// unique ID, by using the TRACE_COUNTER_ID* variations.
+//
+// By default, trace collection is compiled in, but turned off at runtime.
+// Collecting trace data is the responsibility of the embedding
+// application. In Chrome's case, navigating to about:tracing will turn on
+// tracing and display data collected across all active processes.
+//
+//
+// Memory scoping note:
+// Tracing copies the pointers, not the string content, of the strings passed
+// in for category_group, name, and arg_names.  Thus, the following code will
+// cause problems:
+//     char* str = strdup("importantName");
+//     TRACE_EVENT_INSTANT0("SUBSYSTEM", str);  // BAD!
+//     free(str);                   // Trace system now has dangling pointer
+//
+// To avoid this issue with the |name| and |arg_name| parameters, use the
+// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead.
+// Notes: The category must always be in a long-lived char* (i.e. static const).
+//        The |arg_values|, when used, are always deep copied with the _COPY
+//        macros.
+//
+// When are string argument values copied:
+// const char* arg_values are only referenced by default:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", "literal string is only referenced");
+// Use TRACE_STR_COPY to force copying of a const char*:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", TRACE_STR_COPY("string will be copied"));
+// std::string arg_values are always copied:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", std::string("string will be copied"));
+//
+//
+// Convertable notes:
+// Converting a large data type to a string can be costly. To help with this,
+// the trace framework provides an interface ConvertableToTraceFormat. If you
+// inherit from it and implement the AppendAsTraceFormat method the trace
+// framework will call back to your object to convert a trace output time. This
+// means, if the category for the event is disabled, the conversion will not
+// happen.
+//
+//   class MyData : public base::trace_event::ConvertableToTraceFormat {
+//    public:
+//     MyData() {}
+//     void AppendAsTraceFormat(std::string* out) const override {
+//       out->append("{\"foo\":1}");
+//     }
+//    private:
+//     ~MyData() override {}
+//     DISALLOW_COPY_AND_ASSIGN(MyData);
+//   };
+//
+//   TRACE_EVENT1("foo", "bar", "data",
+//                scoped_refptr<ConvertableToTraceFormat>(new MyData()));
+//
+// The trace framework will take ownership if the passed pointer and it will
+// be free'd when the trace buffer is flushed.
+//
+// Note, we only do the conversion when the buffer is flushed, so the provided
+// data object should not be modified after it's passed to the trace framework.
+//
+//
+// Thread Safety:
+// A thread safe singleton and mutex are used for thread safety. Category
+// enabled flags are used to limit the performance impact when the system
+// is not enabled.
+//
+// TRACE_EVENT macros first cache a pointer to a category. The categories are
+// statically allocated and safe at all times, even after exit. Fetching a
+// category is protected by the TraceLog::lock_. Multiple threads initializing
+// the static variable is safe, as they will be serialized by the lock and
+// multiple calls will return the same pointer to the category.
+//
+// Then the category_group_enabled flag is checked. This is a unsigned char, and
+// not intended to be multithread safe. It optimizes access to AddTraceEvent
+// which is threadsafe internally via TraceLog::lock_. The enabled flag may
+// cause some threads to incorrectly call or skip calling AddTraceEvent near
+// the time of the system being enabled or disabled. This is acceptable as
+// we tolerate some data loss while the system is being enabled/disabled and
+// because AddTraceEvent is threadsafe internally and checks the enabled state
+// again under lock.
+//
+// Without the use of these static category pointers and enabled flags all
+// trace points would carry a significant performance cost of acquiring a lock
+// and resolving the category.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_H_
+
+#include <string>
+
+#include "base/atomicops.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_event_memory.h"
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+#include "build/build_config.h"
+
+// By default, const char* argument values are assumed to have long-lived scope
+// and will not be copied. Use this macro to force a const char* to be copied.
+#define TRACE_STR_COPY(str) \
+    trace_event_internal::TraceStringWithCopy(str)
+
+// This will mark the trace event as disabled by default. The user will need
+// to explicitly enable the event.
+#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
+
+// By default, uint64 ID argument values are not mangled with the Process ID in
+// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
+#define TRACE_ID_MANGLE(id) \
+    trace_event_internal::TraceID::ForceMangle(id)
+
+// By default, pointers are mangled with the Process ID in TRACE_EVENT_ASYNC
+// macros. Use this macro to prevent Process ID mangling.
+#define TRACE_ID_DONT_MANGLE(id) \
+    trace_event_internal::TraceID::DontMangle(id)
+
+// Records a pair of begin and end events called "name" for the current
+// scope, with 0, 1 or 2 associated arguments. If the category is not
+// enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT0(category_group, name) \
+    INTERNAL_TRACE_MEMORY(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name)
+#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_MEMORY(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
+#define TRACE_EVENT2( \
+    category_group, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+  INTERNAL_TRACE_MEMORY(category_group, name) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED( \
+      category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records events like TRACE_EVENT2 but uses |memory_tag| for memory tracing.
+// Use this where |name| is too generic to accurately aggregate allocations.
+#define TRACE_EVENT_WITH_MEMORY_TAG2( \
+    category, name, memory_tag, arg1_name, arg1_val, arg2_name, arg2_val) \
+  INTERNAL_TRACE_MEMORY(category, memory_tag) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED( \
+      category, name, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not
+// included in official builds.
+
+#if OFFICIAL_BUILD
+#undef TRACING_IS_OFFICIAL_BUILD
+#define TRACING_IS_OFFICIAL_BUILD 1
+#elif !defined(TRACING_IS_OFFICIAL_BUILD)
+#define TRACING_IS_OFFICIAL_BUILD 0
+#endif
+
+#if TRACING_IS_OFFICIAL_BUILD
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) (void)0
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+    (void)0
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, \
+                                       arg1_name, arg1_val) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, \
+                                       arg1_name, arg1_val, \
+                                       arg2_name, arg2_val) (void)0
+#else
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) \
+    TRACE_EVENT0(category_group, name)
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+    TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val) \
+    TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) \
+    TRACE_EVENT_INSTANT0(category_group, name, scope)
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, \
+                                       arg1_name, arg1_val) \
+    TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, \
+                                       arg1_name, arg1_val, \
+                                       arg2_name, arg2_val) \
+    TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+                         arg2_name, arg2_val)
+#endif
+
+// Records a single event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_INSTANT0(category_group, name, scope) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_NONE | scope)
+#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_NONE | scope, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+                             arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_NONE | scope, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_INSTANT0(category_group, name, scope) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_COPY | scope)
+#define TRACE_EVENT_COPY_INSTANT1(category_group, name, scope, \
+                                  arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_COPY | scope, arg1_name, \
+        arg1_val)
+#define TRACE_EVENT_COPY_INSTANT2(category_group, name, scope, \
+                                  arg1_name, arg1_val, \
+                                  arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_COPY | scope, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Sets the current sample state to the given category and name (both must be
+// constant strings). These states are intended for a sampling profiler.
+// Implementation note: we store category and name together because we don't
+// want the inconsistency/expense of storing two pointers.
+// |thread_bucket| is [0..2] and is used to statically isolate samples in one
+// thread from others.
+#define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET( \
+    bucket_number, category, name)                 \
+        trace_event_internal::                     \
+        TraceEventSamplingStateScope<bucket_number>::Set(category "\0" name)
+
+// Returns a current sampling state of the given bucket.
+#define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \
+    trace_event_internal::TraceEventSamplingStateScope<bucket_number>::Current()
+
+// Creates a scope of a sampling state of the given bucket.
+//
+// {  // The sampling state is set within this scope.
+//    TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name");
+//    ...;
+// }
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(                   \
+    bucket_number, category, name)                                      \
+    trace_event_internal::TraceEventSamplingStateScope<bucket_number>   \
+        traceEventSamplingScope(category "\0" name);
+
+// Syntactic sugars for the sampling tracing in the main thread.
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \
+    TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+#define TRACE_EVENT_GET_SAMPLING_STATE() \
+    TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0)
+#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \
+    TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+
+
+// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_BEGIN0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_BEGIN0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_BEGINx but with a custom |at| timestamp provided.
+// - |id| is used to match the _BEGIN event with the _END event.
+//   Events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, \
+        name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( \
+        category_group, name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
+        arg2_val)
+
+// Records a single END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_END0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_END0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
+// - |id| is used to match the _BEGIN event with the _END event.
+//   Events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, \
+        name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( \
+        category_group, name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
+        arg2_val)
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_COUNTER1(category_group, name, value) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, \
+        "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER1(category_group, name, value) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, \
+        "value", static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_COUNTER2(category_group, name, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID1(category_group, name, id, value) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        "value", static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name, \
+        value1_val, value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+
+// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name,       \
+                                                   thread_id, timestamp)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(                            \
+    category_group, name, thread_id, timestamp, arg1_name, arg1_val)           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name,       \
+                                                   thread_id, timestamp,       \
+                                                   arg1_name, arg1_val,        \
+                                                   arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// ASYNC_STEP_* APIs should be only used by legacy code. New code should
+// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
+// event.
+// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC
+//   events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+//
+// An asynchronous operation can consist of multiple phases. The first phase is
+// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
+// ASYNC_STEP_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
+// annotate the block following the call. The ASYNC_STEP_PAST macro will
+// annotate the block prior to the call. Note that any particular event must use
+// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
+// operation completes, call ASYNC_END.
+//
+// An ASYNC trace typically occurs on a single thread (if not, they will only be
+// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
+// operation must use the same |name| and |id|. Each step can have its own
+// args.
+#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_PAST events.
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
+                                     arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+
+// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, \
+        id, step, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_NONE, "step", step)
+
+// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_INTO events.
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
+                                     arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+
+// Records a single ASYNC_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_ASYNC_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+
+// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
+// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
+// events.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
+//   considered as a match if their category_group, name and id all match.
+// - |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+// - |id| is used to match a child NESTABLE_ASYNC event with its parent
+//   NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
+//   be logged using the same id and category_group.
+//
+// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
+// at the first NESTABLE_ASYNC event of that id, and unmatched
+// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
+// NESTABLE_ASYNC event of that id. Corresponding warning messages for
+// unmatched events will be shown in the analysis view.
+
+// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with 2
+// associated arguments. If the category is not enabled, then this does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
+        id, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, \
+        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 2
+// associated arguments. If the category is not enabled, then this does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
+        id, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+        category_group, name, id, \
+        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(category_group, name, id, \
+        arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW
+//   events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+// FLOW events are different from ASYNC events in how they are drawn by the
+// tracing UI. A FLOW defines asynchronous data flow, such as posting a task
+// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be
+// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar
+// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined
+// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP
+// macros. When the operation completes, call FLOW_END. An async operation can
+// span threads and processes, but all events in that operation must use the
+// same |name| and |id|. Each event can have its own args.
+#define TRACE_EVENT_FLOW_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_BEGIN1(category_group, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_BEGIN2(category_group, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single FLOW_STEP event for |step| immediately. If the category
+// is not enabled, then this does nothing. The |name| and |id| must match the
+// FLOW_BEGIN event above. The |step| param identifies this step within the
+// async event. This should be called at the beginning of the next phase of an
+// asynchronous operation.
+#define TRACE_EVENT_FLOW_STEP0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_FLOW_STEP1(category_group, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_STEP0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_FLOW_STEP1(category_group, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
+        arg1_name, arg1_val)
+
+// Records a single FLOW_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_FLOW_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_END2(category_group, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_END1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_END2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Macros to track the life time and value of arbitrary client objects.
+// See also TraceTrackableObject.
+#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_CREATE_OBJECT, \
+        category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, snapshot) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, \
+        category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE,\
+        "snapshot", snapshot)
+
+#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_DELETE_OBJECT, \
+        category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
+
+#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
+  UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) &           \
+           (base::trace_event::TraceLog::ENABLED_FOR_RECORDING |         \
+            base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK |    \
+            base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
+
+// Macro to efficiently determine if a given category group is enabled.
+#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        *ret = true; \
+      } else { \
+        *ret = false; \
+      } \
+    } while (0)
+
+// Macro to efficiently determine, through polling, if a new trace has begun.
+#define TRACE_EVENT_IS_NEW_TRACE(ret) \
+    do { \
+      static int INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = 0; \
+      int num_traces_recorded = TRACE_EVENT_API_GET_NUM_TRACES_RECORDED(); \
+      if (num_traces_recorded != -1 && \
+          num_traces_recorded != \
+          INTERNAL_TRACE_EVENT_UID(lastRecordingNumber)) { \
+        INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = \
+            num_traces_recorded; \
+        *ret = true; \
+      } else { \
+        *ret = false; \
+      } \
+    } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation specific tracing API definitions.
+
+// Get a pointer to the enabled state of the given trace category. Only
+// long-lived literal strings should be given as the category group. The
+// returned pointer can be held permanently in a local static for example. If
+// the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
+// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
+// between the load of the tracing state and the call to
+// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
+// for best performance when tracing is disabled.
+// const unsigned char*
+//     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
+#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
+    base::trace_event::TraceLog::GetCategoryGroupEnabled
+
+// Get the number of times traces have been recorded. This is used to implement
+// the TRACE_EVENT_IS_NEW_TRACE facility.
+// unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED()
+#define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED \
+    base::trace_event::TraceLog::GetInstance()->GetNumTracesRecorded
+
+// Add a trace event to the platform tracing system.
+// base::trace_event::TraceEventHandle TRACE_EVENT_API_ADD_TRACE_EVENT(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT \
+    base::trace_event::TraceLog::GetInstance()->AddTraceEvent
+
+// Add a trace event to the platform tracing system.
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    int thread_id,
+//                    const TimeTicks& timestamp,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \
+    base::trace_event::TraceLog::GetInstance() \
+      ->AddTraceEventWithThreadIdAndTimestamp
+
+// Set the duration field of a COMPLETE trace event.
+// void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
+//     const unsigned char* category_group_enabled,
+//     const char* name,
+//     base::trace_event::TraceEventHandle id)
+#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
+    base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDuration
+
+// Defines atomic operations used internally by the tracing system.
+#define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord
+#define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::NoBarrier_Load(&(var))
+#define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
+    base::subtle::NoBarrier_Store(&(var), (value))
+
+// Defines visibility for classes in trace_event.h
+#define TRACE_EVENT_API_CLASS_EXPORT BASE_EXPORT
+
+// The thread buckets for the sampling profiler.
+TRACE_EVENT_API_CLASS_EXPORT extern \
+    TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+#define TRACE_EVENT_API_THREAD_BUCKET(thread_bucket)                           \
+    g_trace_state[thread_bucket]
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Implementation detail: trace event macros create temporary variables
+// to keep instrumentation overhead low. These macros give each temporary
+// variable a unique name based on the line number to prevent name collisions.
+#define INTERNAL_TRACE_EVENT_UID3(a,b) \
+    trace_event_unique_##a##b
+#define INTERNAL_TRACE_EVENT_UID2(a,b) \
+    INTERNAL_TRACE_EVENT_UID3(a,b)
+#define INTERNAL_TRACE_EVENT_UID(name_prefix) \
+    INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
+
+// Implementation detail: internal macro to create static category.
+// No barriers are needed, because this code is designed to operate safely
+// even when the unsigned char* points to garbage data (which may be the case
+// on processors without cache coherency).
+#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \
+    category_group, atomic, category_group_enabled) \
+    category_group_enabled = \
+        reinterpret_cast<const unsigned char*>(TRACE_EVENT_API_ATOMIC_LOAD( \
+            atomic)); \
+    if (UNLIKELY(!category_group_enabled)) { \
+      category_group_enabled = \
+          TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \
+      TRACE_EVENT_API_ATOMIC_STORE(atomic, \
+          reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>( \
+              category_group_enabled)); \
+    }
+
+#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \
+    static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
+    const unsigned char* INTERNAL_TRACE_EVENT_UID(category_group_enabled); \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(category_group, \
+        INTERNAL_TRACE_EVENT_UID(atomic), \
+        INTERNAL_TRACE_EVENT_UID(category_group_enabled));
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        trace_event_internal::AddTraceEvent( \
+            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+            trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Implementation detail: internal macro to create static category and add begin
+// event if the category is enabled. Also adds the end event when the scope
+// ends.
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+    trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+      base::trace_event::TraceEventHandle h = \
+          trace_event_internal::AddTraceEvent( \
+              TRACE_EVENT_PHASE_COMPLETE, \
+              INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+              trace_event_internal::kNoEventId, TRACE_EVENT_FLAG_NONE, \
+              ##__VA_ARGS__); \
+      INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
+          INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
+    }
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \
+                                         flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+        trace_event_internal::TraceID trace_event_trace_id( \
+            id, &trace_event_flags); \
+        trace_event_internal::AddTraceEvent( \
+            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
+            name, trace_event_trace_id.data(), trace_event_flags, \
+            ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(phase, \
+        category_group, name, id, thread_id, timestamp, flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+        trace_event_internal::TraceID trace_event_trace_id( \
+            id, &trace_event_flags); \
+        trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
+            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
+            name, trace_event_trace_id.data(), \
+            thread_id, base::TimeTicks::FromInternalValue(timestamp), \
+            trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+            ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Notes regarding the following definitions:
+// New values can be added and propagated to third party libraries, but existing
+// definitions must never be changed, because third party libraries may use old
+// definitions.
+
+// Phase indicates the nature of an event entry. E.g. part of a begin/end pair.
+#define TRACE_EVENT_PHASE_BEGIN    ('B')
+#define TRACE_EVENT_PHASE_END      ('E')
+#define TRACE_EVENT_PHASE_COMPLETE ('X')
+#define TRACE_EVENT_PHASE_INSTANT  ('I')
+#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO  ('T')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST  ('p')
+#define TRACE_EVENT_PHASE_ASYNC_END   ('F')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ('b')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_END ('e')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT ('n')
+#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s')
+#define TRACE_EVENT_PHASE_FLOW_STEP  ('t')
+#define TRACE_EVENT_PHASE_FLOW_END   ('f')
+#define TRACE_EVENT_PHASE_METADATA ('M')
+#define TRACE_EVENT_PHASE_COUNTER  ('C')
+#define TRACE_EVENT_PHASE_SAMPLE  ('P')
+#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N')
+#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O')
+#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D')
+#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE         (static_cast<unsigned char>(0))
+#define TRACE_EVENT_FLAG_COPY         (static_cast<unsigned char>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID       (static_cast<unsigned char>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID    (static_cast<unsigned char>(1 << 2))
+#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA  (static_cast<unsigned char>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS    (static_cast<unsigned char>(1 << 6))
+
+#define TRACE_EVENT_FLAG_SCOPE_MASK   (static_cast<unsigned char>( \
+    TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
+
+// Type values for identifying types in the TraceValue union.
+#define TRACE_VALUE_TYPE_BOOL         (static_cast<unsigned char>(1))
+#define TRACE_VALUE_TYPE_UINT         (static_cast<unsigned char>(2))
+#define TRACE_VALUE_TYPE_INT          (static_cast<unsigned char>(3))
+#define TRACE_VALUE_TYPE_DOUBLE       (static_cast<unsigned char>(4))
+#define TRACE_VALUE_TYPE_POINTER      (static_cast<unsigned char>(5))
+#define TRACE_VALUE_TYPE_STRING       (static_cast<unsigned char>(6))
+#define TRACE_VALUE_TYPE_COPY_STRING  (static_cast<unsigned char>(7))
+#define TRACE_VALUE_TYPE_CONVERTABLE  (static_cast<unsigned char>(8))
+
+// Enum reflecting the scope of an INSTANT event. Must fit within
+// TRACE_EVENT_FLAG_SCOPE_MASK.
+#define TRACE_EVENT_SCOPE_GLOBAL  (static_cast<unsigned char>(0 << 3))
+#define TRACE_EVENT_SCOPE_PROCESS (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_SCOPE_THREAD  (static_cast<unsigned char>(2 << 3))
+
+#define TRACE_EVENT_SCOPE_NAME_GLOBAL  ('g')
+#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p')
+#define TRACE_EVENT_SCOPE_NAME_THREAD  ('t')
+
+namespace trace_event_internal {
+
+// Specify these values when the corresponding argument of AddTraceEvent is not
+// used.
+const int kZeroNumArgs = 0;
+const unsigned long long kNoEventId = 0;
+
+// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
+// are by default mangled with the Process ID so that they are unlikely to
+// collide when the same pointer is used on different processes.
+class TraceID {
+ public:
+  class DontMangle {
+   public:
+    explicit DontMangle(const void* id)
+        : data_(static_cast<unsigned long long>(
+              reinterpret_cast<uintptr_t>(id))) {}
+    explicit DontMangle(unsigned long long id) : data_(id) {}
+    explicit DontMangle(unsigned long id) : data_(id) {}
+    explicit DontMangle(unsigned int id) : data_(id) {}
+    explicit DontMangle(unsigned short id) : data_(id) {}
+    explicit DontMangle(unsigned char id) : data_(id) {}
+    explicit DontMangle(long long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(int id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(short id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(signed char id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    unsigned long long data() const { return data_; }
+   private:
+    unsigned long long data_;
+  };
+
+  class ForceMangle {
+   public:
+    explicit ForceMangle(unsigned long long id) : data_(id) {}
+    explicit ForceMangle(unsigned long id) : data_(id) {}
+    explicit ForceMangle(unsigned int id) : data_(id) {}
+    explicit ForceMangle(unsigned short id) : data_(id) {}
+    explicit ForceMangle(unsigned char id) : data_(id) {}
+    explicit ForceMangle(long long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(int id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(short id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(signed char id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    unsigned long long data() const { return data_; }
+   private:
+    unsigned long long data_;
+  };
+  TraceID(const void* id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(
+              reinterpret_cast<uintptr_t>(id))) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  TraceID(DontMangle id, unsigned char* flags) : data_(id.data()) {
+  }
+  TraceID(unsigned long long id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned long id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned int id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned short id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned char id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(long long id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(long id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(int id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(short id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(signed char id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+
+  unsigned long long data() const { return data_; }
+
+ private:
+  unsigned long long data_;
+};
+
+// Simple union to store various types as unsigned long long.
+union TraceValueUnion {
+  bool as_bool;
+  unsigned long long as_uint;
+  long long as_int;
+  double as_double;
+  const void* as_pointer;
+  const char* as_string;
+};
+
+// Simple container for const char* that should be copied instead of retained.
+class TraceStringWithCopy {
+ public:
+  explicit TraceStringWithCopy(const char* str) : str_(str) {}
+  const char* str() const { return str_; }
+ private:
+  const char* str_;
+};
+
+// Define SetTraceValue for each allowed type. It stores the type and
+// value in the return arguments. This allows this API to avoid declaring any
+// structures so that it is portable to third_party libraries.
+#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
+                                         arg_expression, \
+                                         union_member, \
+                                         value_type_id) \
+    static inline void SetTraceValue( \
+        actual_type arg, \
+        unsigned char* type, \
+        unsigned long long* value) { \
+      TraceValueUnion type_value; \
+      type_value.union_member = arg_expression; \
+      *type = value_type_id; \
+      *value = type_value.as_uint; \
+    }
+// Simpler form for int types that can be safely casted.
+#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
+                                             value_type_id) \
+    static inline void SetTraceValue( \
+        actual_type arg, \
+        unsigned char* type, \
+        unsigned long long* value) { \
+      *type = value_type_id; \
+      *value = static_cast<unsigned long long>(arg); \
+    }
+
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE(bool, arg, as_bool, TRACE_VALUE_TYPE_BOOL)
+INTERNAL_DECLARE_SET_TRACE_VALUE(double, arg, as_double,
+                                 TRACE_VALUE_TYPE_DOUBLE)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, arg, as_pointer,
+                                 TRACE_VALUE_TYPE_POINTER)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, arg, as_string,
+                                 TRACE_VALUE_TYPE_STRING)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, arg.str(),
+                                 as_string, TRACE_VALUE_TYPE_COPY_STRING)
+
+#undef INTERNAL_DECLARE_SET_TRACE_VALUE
+#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
+
+// std::string version of SetTraceValue so that trace arguments can be strings.
+static inline void SetTraceValue(const std::string& arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  TraceValueUnion type_value;
+  type_value.as_string = arg.c_str();
+  *type = TRACE_VALUE_TYPE_COPY_STRING;
+  *value = type_value.as_uint;
+}
+
+// base::Time and base::TimeTicks version of SetTraceValue to make it easier to
+// trace these types.
+static inline void SetTraceValue(const base::Time arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
+static inline void SetTraceValue(const base::TimeTicks arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
+// These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template
+// functions are defined here instead of in the macro, because the arg_values
+// could be temporary objects, such as std::string. In order to store
+// pointers to the internal c_str and pass through to the tracing API,
+// the arg_values must live throughout these procedures.
+
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+        arg1_val) {
+  const int num_args = 1;
+  unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+        arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+
+  unsigned char arg_types[2];
+  unsigned long long arg_values[2];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  arg_types[1] = TRACE_VALUE_TYPE_CONVERTABLE;
+
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2];
+  convertable_values[1] = arg2_val;
+
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+}
+
+template<class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+
+  unsigned char arg_types[2];
+  unsigned long long arg_values[2];
+  arg_types[0] = TRACE_VALUE_TYPE_CONVERTABLE;
+  arg_values[0] = 0;
+  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2];
+  convertable_values[0] = arg1_val;
+
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+}
+
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
+    const char* arg2_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+        arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+  unsigned char arg_types[2] =
+      { TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE };
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2] = {arg1_val, arg2_val};
+
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, NULL, convertable_values, flags);
+}
+
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags) {
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
+}
+
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned char flags) {
+  const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  const base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now, flags);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val) {
+  const int num_args = 1;
+  unsigned char arg_types[1];
+  unsigned long long arg_values[1];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, &arg1_name, arg_types, arg_values, NULL, flags);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now, flags,
+                                               arg1_name, arg1_val);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+  unsigned char arg_types[2];
+  unsigned long long arg_values[2];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, arg_values, NULL, flags);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now, flags,
+                                               arg1_name, arg1_val,
+                                               arg2_name, arg2_val);
+}
+
+// Used by TRACE_EVENTx macros. Do not use directly.
+class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
+ public:
+  // Note: members of data_ intentionally left uninitialized. See Initialize.
+  ScopedTracer() : p_data_(NULL) {}
+
+  ~ScopedTracer() {
+    if (p_data_ && *data_.category_group_enabled)
+      TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
+          data_.category_group_enabled, data_.name, data_.event_handle);
+  }
+
+  void Initialize(const unsigned char* category_group_enabled,
+                  const char* name,
+                  base::trace_event::TraceEventHandle event_handle) {
+    data_.category_group_enabled = category_group_enabled;
+    data_.name = name;
+    data_.event_handle = event_handle;
+    p_data_ = &data_;
+  }
+
+ private:
+  // This Data struct workaround is to avoid initializing all the members
+  // in Data during construction of this object, since this object is always
+  // constructed, even when tracing is disabled. If the members of Data were
+  // members of this class instead, compiler warnings occur about potential
+  // uninitialized accesses.
+  struct Data {
+    const unsigned char* category_group_enabled;
+    const char* name;
+    base::trace_event::TraceEventHandle event_handle;
+  };
+  Data* p_data_;
+  Data data_;
+};
+
+// Used by TRACE_EVENT_BINARY_EFFICIENTx macro. Do not use directly.
+class TRACE_EVENT_API_CLASS_EXPORT ScopedTraceBinaryEfficient {
+ public:
+  ScopedTraceBinaryEfficient(const char* category_group, const char* name);
+  ~ScopedTraceBinaryEfficient();
+
+ private:
+  const unsigned char* category_group_enabled_;
+  const char* name_;
+  base::trace_event::TraceEventHandle event_handle_;
+};
+
+// This macro generates less code then TRACE_EVENT0 but is also
+// slower to execute when tracing is off. It should generally only be
+// used with code that is seldom executed or conditionally executed
+// when debugging.
+// For now the category_group must be "gpu".
+#define TRACE_EVENT_BINARY_EFFICIENT0(category_group, name) \
+    trace_event_internal::ScopedTraceBinaryEfficient \
+        INTERNAL_TRACE_EVENT_UID(scoped_trace)(category_group, name);
+
+// TraceEventSamplingStateScope records the current sampling state
+// and sets a new sampling state. When the scope exists, it restores
+// the sampling state having recorded.
+template<size_t BucketNumber>
+class TraceEventSamplingStateScope {
+ public:
+  TraceEventSamplingStateScope(const char* category_and_name) {
+    previous_state_ = TraceEventSamplingStateScope<BucketNumber>::Current();
+    TraceEventSamplingStateScope<BucketNumber>::Set(category_and_name);
+  }
+
+  ~TraceEventSamplingStateScope() {
+    TraceEventSamplingStateScope<BucketNumber>::Set(previous_state_);
+  }
+
+  static inline const char* Current() {
+    return reinterpret_cast<const char*>(TRACE_EVENT_API_ATOMIC_LOAD(
+      g_trace_state[BucketNumber]));
+  }
+
+  static inline void Set(const char* category_and_name) {
+    TRACE_EVENT_API_ATOMIC_STORE(
+      g_trace_state[BucketNumber],
+      reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(
+        const_cast<char*>(category_and_name)));
+  }
+
+ private:
+  const char* previous_state_;
+};
+
+}  // namespace trace_event_internal
+
+namespace base {
+namespace trace_event {
+
+template<typename IDType> class TraceScopedTrackableObject {
+ public:
+  TraceScopedTrackableObject(const char* category_group, const char* name,
+      IDType id)
+    : category_group_(category_group),
+      name_(name),
+      id_(id) {
+    TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group_, name_, id_);
+  }
+
+  template <typename ArgType> void snapshot(ArgType snapshot) {
+    TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group_, name_, id_, snapshot);
+  }
+
+  ~TraceScopedTrackableObject() {
+    TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group_, name_, id_);
+  }
+
+ private:
+  const char* category_group_;
+  const char* name_;
+  IDType id_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceScopedTrackableObject);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_H_
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
new file mode 100644
index 0000000..26bd0c7
--- /dev/null
+++ b/base/trace_event/trace_event_android.cc
@@ -0,0 +1,200 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_impl.h"
+
+#include <fcntl.h>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
+
+namespace {
+
+int g_atrace_fd = -1;
+const char kATraceMarkerFile[] = "/sys/kernel/debug/tracing/trace_marker";
+
+void WriteEvent(
+    char phase,
+    const char* category_group,
+    const char* name,
+    unsigned long long id,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const base::trace_event::TraceEvent::TraceValue* arg_values,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>*
+        convertable_values,
+    unsigned char flags) {
+  std::string out = base::StringPrintf("%c|%d|%s", phase, getpid(), name);
+  if (flags & TRACE_EVENT_FLAG_HAS_ID)
+    base::StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
+  out += '|';
+
+  for (int i = 0; i < base::trace_event::kTraceMaxNumArgs && arg_names[i];
+       ++i) {
+    if (i)
+      out += ';';
+    out += arg_names[i];
+    out += '=';
+    std::string::size_type value_start = out.length();
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+      convertable_values[i]->AppendAsTraceFormat(&out);
+    } else {
+      base::trace_event::TraceEvent::AppendValueAsJSON(arg_types[i],
+                                                       arg_values[i], &out);
+    }
+    // Remove the quotes which may confuse the atrace script.
+    ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
+    ReplaceSubstringsAfterOffset(&out, value_start, "\"", "");
+    // Replace chars used for separators with similar chars in the value.
+    std::replace(out.begin() + value_start, out.end(), ';', ',');
+    std::replace(out.begin() + value_start, out.end(), '|', '!');
+  }
+
+  out += '|';
+  out += category_group;
+  write(g_atrace_fd, out.c_str(), out.size());
+}
+
+void NoOpOutputCallback(base::WaitableEvent* complete_event,
+                        const scoped_refptr<base::RefCountedString>&,
+                        bool has_more_events) {
+  if (!has_more_events)
+    complete_event->Signal();
+}
+
+void EndChromeTracing(base::trace_event::TraceLog* trace_log,
+                      base::WaitableEvent* complete_event) {
+  trace_log->SetDisabled();
+  // Delete the buffered trace events as they have been sent to atrace.
+  trace_log->Flush(base::Bind(&NoOpOutputCallback, complete_event));
+}
+
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+// These functions support Android systrace.py when 'webview' category is
+// traced. With the new adb_profile_chrome, we may have two phases:
+// - before WebView is ready for combined tracing, we can use adb_profile_chrome
+//   to trace android categories other than 'webview' and chromium categories.
+//   In this way we can avoid the conflict between StartATrace/StopATrace and
+//   the intents.
+// - TODO(wangxianzhu): after WebView is ready for combined tracing, remove
+//   StartATrace, StopATrace and SendToATrace, and perhaps send Java traces
+//   directly to atrace in trace_event_binding.cc.
+
+void TraceLog::StartATrace() {
+  if (g_atrace_fd != -1)
+    return;
+
+  g_atrace_fd = open(kATraceMarkerFile, O_WRONLY);
+  if (g_atrace_fd == -1) {
+    PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
+    return;
+  }
+  SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
+             TraceLog::RECORDING_MODE,
+             TraceOptions(RECORD_CONTINUOUSLY));
+}
+
+void TraceLog::StopATrace() {
+  if (g_atrace_fd == -1)
+    return;
+
+  close(g_atrace_fd);
+  g_atrace_fd = -1;
+
+  // TraceLog::Flush() requires the current thread to have a message loop, but
+  // this thread called from Java may not have one, so flush in another thread.
+  Thread end_chrome_tracing_thread("end_chrome_tracing");
+  WaitableEvent complete_event(false, false);
+  end_chrome_tracing_thread.Start();
+  end_chrome_tracing_thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this),
+                            Unretained(&complete_event)));
+  complete_event.Wait();
+}
+
+void TraceEvent::SendToATrace() {
+  if (g_atrace_fd == -1)
+    return;
+
+  const char* category_group =
+      TraceLog::GetCategoryGroupName(category_group_enabled_);
+
+  switch (phase_) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      WriteEvent('B', category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      break;
+
+    case TRACE_EVENT_PHASE_COMPLETE:
+      WriteEvent(duration_.ToInternalValue() == -1 ? 'B' : 'E',
+                 category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      break;
+
+    case TRACE_EVENT_PHASE_END:
+      // Though a single 'E' is enough, here append pid, name and
+      // category_group etc. So that unpaired events can be found easily.
+      WriteEvent('E', category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      break;
+
+    case TRACE_EVENT_PHASE_INSTANT:
+      // Simulate an instance event with a pair of begin/end events.
+      WriteEvent('B', category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      write(g_atrace_fd, "E", 1);
+      break;
+
+    case TRACE_EVENT_PHASE_COUNTER:
+      for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+        DCHECK(arg_types_[i] == TRACE_VALUE_TYPE_INT);
+        std::string out = base::StringPrintf(
+            "C|%d|%s-%s", getpid(), name_, arg_names_[i]);
+        if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
+          StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id_));
+        StringAppendF(&out, "|%d|%s",
+                      static_cast<int>(arg_values_[i].as_int), category_group);
+        write(g_atrace_fd, out.c_str(), out.size());
+      }
+      break;
+
+    default:
+      // Do nothing.
+      break;
+  }
+}
+
+void TraceLog::AddClockSyncMetadataEvent() {
+  int atrace_fd = open(kATraceMarkerFile, O_WRONLY | O_APPEND);
+  if (atrace_fd == -1) {
+    PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
+    return;
+  }
+
+  // Android's kernel trace system has a trace_marker feature: this is a file on
+  // debugfs that takes the written data and pushes it onto the trace
+  // buffer. So, to establish clock sync, we write our monotonic clock into that
+  // trace buffer.
+  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()) == -1)
+    PLOG(WARNING) << "Couldn't write to " << kATraceMarkerFile;
+  close(atrace_fd);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
new file mode 100644
index 0000000..88b1879
--- /dev/null
+++ b/base/trace_event/trace_event_argument.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_argument.h"
+
+#include "base/json/json_writer.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+TracedValue::TracedValue() : root_(new DictionaryValue()) {
+  stack_.push_back(root_.get());
+}
+
+TracedValue::~TracedValue() {
+  DCHECK_EQ(1u, stack_.size());
+}
+
+void TracedValue::SetInteger(const char* name, int value) {
+  GetCurrentDictionary()->SetInteger(name, value);
+}
+
+void TracedValue::SetDouble(const char* name, double value) {
+  GetCurrentDictionary()->SetDouble(name, value);
+}
+
+void TracedValue::SetBoolean(const char* name, bool value) {
+  GetCurrentDictionary()->SetBoolean(name, value);
+}
+
+void TracedValue::SetString(const char* name, const std::string& value) {
+  GetCurrentDictionary()->SetString(name, value);
+}
+
+void TracedValue::SetValue(const char* name, scoped_ptr<Value> value) {
+  GetCurrentDictionary()->Set(name, value.Pass());
+}
+
+void TracedValue::BeginDictionary(const char* name) {
+  DictionaryValue* dictionary = new DictionaryValue();
+  GetCurrentDictionary()->Set(name, make_scoped_ptr(dictionary));
+  stack_.push_back(dictionary);
+}
+
+void TracedValue::BeginArray(const char* name) {
+  ListValue* array = new ListValue();
+  GetCurrentDictionary()->Set(name, make_scoped_ptr(array));
+  stack_.push_back(array);
+}
+
+void TracedValue::EndDictionary() {
+  DCHECK_GT(stack_.size(), 1u);
+  DCHECK(GetCurrentDictionary());
+  stack_.pop_back();
+}
+
+void TracedValue::AppendInteger(int value) {
+  GetCurrentArray()->AppendInteger(value);
+}
+
+void TracedValue::AppendDouble(double value) {
+  GetCurrentArray()->AppendDouble(value);
+}
+
+void TracedValue::AppendBoolean(bool value) {
+  GetCurrentArray()->AppendBoolean(value);
+}
+
+void TracedValue::AppendString(const std::string& value) {
+  GetCurrentArray()->AppendString(value);
+}
+
+void TracedValue::BeginArray() {
+  ListValue* array = new ListValue();
+  GetCurrentArray()->Append(array);
+  stack_.push_back(array);
+}
+
+void TracedValue::BeginDictionary() {
+  DictionaryValue* dictionary = new DictionaryValue();
+  GetCurrentArray()->Append(dictionary);
+  stack_.push_back(dictionary);
+}
+
+void TracedValue::EndArray() {
+  DCHECK_GT(stack_.size(), 1u);
+  DCHECK(GetCurrentArray());
+  stack_.pop_back();
+}
+
+DictionaryValue* TracedValue::GetCurrentDictionary() {
+  DCHECK(!stack_.empty());
+  DictionaryValue* dictionary = NULL;
+  stack_.back()->GetAsDictionary(&dictionary);
+  DCHECK(dictionary);
+  return dictionary;
+}
+
+ListValue* TracedValue::GetCurrentArray() {
+  DCHECK(!stack_.empty());
+  ListValue* list = NULL;
+  stack_.back()->GetAsList(&list);
+  DCHECK(list);
+  return list;
+}
+
+void TracedValue::AppendAsTraceFormat(std::string* out) const {
+  std::string tmp;
+  JSONWriter::Write(stack_.front(), &tmp);
+  *out += tmp;
+  DCHECK_EQ(1u, stack_.size()) << tmp;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
new file mode 100644
index 0000000..d86cfd1
--- /dev/null
+++ b/base/trace_event/trace_event_argument.h
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class Value;
+
+namespace trace_event {
+
+class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
+ public:
+  TracedValue();
+
+  void EndDictionary();
+  void EndArray();
+
+  void SetInteger(const char* name, int value);
+  void SetDouble(const char* name, double);
+  void SetBoolean(const char* name, bool value);
+  void SetString(const char* name, const std::string& value);
+  void SetValue(const char* name, scoped_ptr<Value> value);
+  void BeginDictionary(const char* name);
+  void BeginArray(const char* name);
+
+  void AppendInteger(int);
+  void AppendDouble(double);
+  void AppendBoolean(bool);
+  void AppendString(const std::string&);
+  void BeginArray();
+  void BeginDictionary();
+
+  void AppendAsTraceFormat(std::string* out) const override;
+
+ private:
+  ~TracedValue() override;
+
+  DictionaryValue* GetCurrentDictionary();
+  ListValue* GetCurrentArray();
+
+  scoped_ptr<base::Value> root_;
+  std::vector<Value*> stack_;  // Weak references.
+  DISALLOW_COPY_AND_ASSIGN(TracedValue);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
new file mode 100644
index 0000000..c59910e
--- /dev/null
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(TraceEventArgumentTest, FlatDictionary) {
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetInteger("int", 2014);
+  value->SetDouble("double", 0.0);
+  value->SetBoolean("bool", true);
+  value->SetString("string", "string");
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
+            json);
+}
+
+TEST(TraceEventArgumentTest, Hierarchy) {
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetInteger("i0", 2014);
+  value->BeginDictionary("dict1");
+  value->SetInteger("i1", 2014);
+  value->BeginDictionary("dict2");
+  value->SetBoolean("b2", false);
+  value->EndDictionary();
+  value->SetString("s1", "foo");
+  value->EndDictionary();
+  value->SetDouble("d0", 0.0);
+  value->SetBoolean("b0", true);
+  value->BeginArray("a1");
+  value->AppendInteger(1);
+  value->AppendBoolean(true);
+  value->BeginDictionary();
+  value->SetInteger("i2", 3);
+  value->EndDictionary();
+  value->EndArray();
+  value->SetString("s0", "foo");
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"a1\":[1,true,{\"i2\":3}],\"b0\":true,\"d0\":0.0,\"dict1\":{\"dict2\":"
+      "{\"b2\":false},\"i1\":2014,\"s1\":\"foo\"},\"i0\":2014,\"s0\":"
+      "\"foo\"}",
+      json);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
new file mode 100644
index 0000000..1cb3b8c
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -0,0 +1,243 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_etw_export_win.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// The GetProcAddress technique is borrowed from
+// https://github.com/randomascii/main/tree/master/xperf/ETWProviders
+//
+// EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
+// We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
+// implement these functions locally instead of using the import library, and
+// can therefore still run on Windows XP.
+#define EVNTAPI __stdcall
+// Include the event register/write/unregister macros compiled from the manifest
+// file. Note that this includes evntprov.h which requires a Vista+ Windows SDK.
+//
+// In SHARED_INTERMEDIATE_DIR.
+#include "base/trace_event/etw_manifest/chrome_events_win.h"  // NOLINT
+
+namespace {
+// Typedefs for use with GetProcAddress
+typedef ULONG(__stdcall* tEventRegister)(LPCGUID ProviderId,
+                                         PENABLECALLBACK EnableCallback,
+                                         PVOID CallbackContext,
+                                         PREGHANDLE RegHandle);
+typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle,
+                                      PCEVENT_DESCRIPTOR EventDescriptor,
+                                      ULONG UserDataCount,
+                                      PEVENT_DATA_DESCRIPTOR UserData);
+typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
+
+tEventRegister EventRegisterProc = nullptr;
+tEventWrite EventWriteProc = nullptr;
+tEventUnregister EventUnregisterProc = nullptr;
+}  // namespace
+
+// Redirector function for EventRegister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventRegister(LPCGUID ProviderId,
+                            PENABLECALLBACK EnableCallback,
+                            PVOID CallbackContext,
+                            PREGHANDLE RegHandle) {
+  if (EventRegisterProc)
+    return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
+                             RegHandle);
+  return 0;
+}
+
+// Redirector function for EventWrite. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventWrite(REGHANDLE RegHandle,
+                         PCEVENT_DESCRIPTOR EventDescriptor,
+                         ULONG UserDataCount,
+                         PEVENT_DATA_DESCRIPTOR UserData) {
+  if (EventWriteProc)
+    return EventWriteProc(RegHandle, EventDescriptor, UserDataCount, UserData);
+  return 0;
+}
+
+// Redirector function for EventUnregister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
+  if (EventUnregisterProc)
+    return EventUnregisterProc(RegHandle);
+  return 0;
+}
+
+namespace base {
+namespace trace_event {
+
+TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
+  // Find Advapi32.dll. This should always succeed.
+  HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
+  if (AdvapiDLL) {
+    // Try to find the ETW functions. This will fail on XP.
+    EventRegisterProc = reinterpret_cast<tEventRegister>(
+        ::GetProcAddress(AdvapiDLL, "EventRegister"));
+    EventWriteProc = reinterpret_cast<tEventWrite>(
+        ::GetProcAddress(AdvapiDLL, "EventWrite"));
+    EventUnregisterProc = reinterpret_cast<tEventUnregister>(
+        ::GetProcAddress(AdvapiDLL, "EventUnregister"));
+
+    // Register the ETW provider. If registration fails then the event logging
+    // calls will fail (on XP this call will do nothing).
+    EventRegisterChrome();
+  }
+}
+
+TraceEventETWExport::~TraceEventETWExport() {
+  EventUnregisterChrome();
+}
+
+// static
+TraceEventETWExport* TraceEventETWExport::GetInstance() {
+  return Singleton<TraceEventETWExport,
+                   StaticMemorySingletonTraits<TraceEventETWExport>>::get();
+}
+
+// static
+void TraceEventETWExport::EnableETWExport() {
+  if (GetInstance())
+    GetInstance()->ETWExportEnabled_ = true;
+}
+
+// static
+void TraceEventETWExport::DisableETWExport() {
+  if (GetInstance())
+    GetInstance()->ETWExportEnabled_ = false;
+}
+
+// static
+void TraceEventETWExport::AddEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
+  // We bail early in case exporting is disabled or no consumer is listening.
+  if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+      !EventEnabledChromeEvent())
+    return;
+
+  std::string phase_string;
+  switch (phase) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      phase_string = "Begin";
+      break;
+    case TRACE_EVENT_PHASE_END:
+      phase_string = "End";
+      break;
+    case TRACE_EVENT_PHASE_COMPLETE:
+      phase_string = "Complete";
+      break;
+    case TRACE_EVENT_PHASE_INSTANT:
+      phase_string = "Instant";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_BEGIN:
+      phase_string = "Async Begin";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_STEP_INTO:
+      phase_string = "Async Step Into";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_STEP_PAST:
+      phase_string = "Async Step Past";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_END:
+      phase_string = "Async End";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN:
+      phase_string = "Nestable Async Begin";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_END:
+      phase_string = "Nestable Async End";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT:
+      phase_string = "Nestable Async Instant";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_BEGIN:
+      phase_string = "Phase Flow Begin";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_STEP:
+      phase_string = "Phase Flow Step";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_END:
+      phase_string = "Phase Flow End";
+      break;
+    case TRACE_EVENT_PHASE_METADATA:
+      phase_string = "Phase Metadata";
+      break;
+    case TRACE_EVENT_PHASE_COUNTER:
+      phase_string = "Phase Counter";
+      break;
+    case TRACE_EVENT_PHASE_SAMPLE:
+      phase_string = "Phase Sample";
+      break;
+    case TRACE_EVENT_PHASE_CREATE_OBJECT:
+      phase_string = "Phase Create Object";
+      break;
+    case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT:
+      phase_string = "Phase Snapshot Object";
+      break;
+    case TRACE_EVENT_PHASE_DELETE_OBJECT:
+      phase_string = "Phase Delete Object";
+      break;
+    default:
+      phase_string.push_back(phase);
+      break;
+  }
+
+  std::string arg_values_string[3];
+  for (int i = 0; i < num_args; i++) {
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+      convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
+    } else {
+      TraceEvent::TraceValue trace_event;
+      trace_event.as_uint = arg_values[i];
+      TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
+                                    arg_values_string + i);
+    }
+  }
+
+  EventWriteChromeEvent(
+      name, phase_string.c_str(), num_args > 0 ? arg_names[0] : "",
+      arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
+      arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
+      arg_values_string[2].c_str());
+}
+
+// static
+void TraceEventETWExport::AddCustomEvent(const char* name,
+                                         char const* phase,
+                                         const char* arg_name_1,
+                                         const char* arg_value_1,
+                                         const char* arg_name_2,
+                                         const char* arg_value_2,
+                                         const char* arg_name_3,
+                                         const char* arg_value_3) {
+  if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+      !EventEnabledChromeEvent())
+    return;
+
+  EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
+                        arg_value_2, arg_name_3, arg_value_3);
+}
+
+void TraceEventETWExport::Resurrect() {
+  StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h
new file mode 100644
index 0000000..3d26b33
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -0,0 +1,75 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the Windows-specific exporting to ETW.
+#ifndef BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
+#define BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT TraceEventETWExport {
+ public:
+  ~TraceEventETWExport();
+
+  // Retrieves the singleton.
+  // Note that this may return NULL post-AtExit processing.
+  static TraceEventETWExport* GetInstance();
+
+  // Enables/disables exporting of events to ETW. If disabled,
+  // AddEvent and AddCustomEvent will simply return when called.
+  static void EnableETWExport();
+  static void DisableETWExport();
+
+  static bool isETWExportEnabled() {
+    return (GetInstance() && GetInstance()->ETWExportEnabled_);
+  }
+
+  // Exports an event to ETW. This is mainly used in
+  // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
+  static void AddEvent(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values);
+
+  // Exports an event to ETW. This should be used when exporting an event only
+  // to ETW. Supports three arguments to be passed to ETW.
+  // TODO(georgesak): Allow different providers.
+  static void AddCustomEvent(const char* name,
+                             char const* phase,
+                             const char* arg_name_1,
+                             const char* arg_value_1,
+                             const char* arg_name_2,
+                             const char* arg_value_2,
+                             const char* arg_name_3,
+                             const char* arg_value_3);
+
+  void Resurrect();
+
+ private:
+  bool ETWExportEnabled_;
+  // Ensure only the provider can construct us.
+  friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
+  TraceEventETWExport();
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
new file mode 100644
index 0000000..5ae7fb2
--- /dev/null
+++ b/base/trace_event/trace_event_impl.cc
@@ -0,0 +1,2650 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_impl.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
+#include "base/format_macros.h"
+#include "base/json/string_escape.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_metrics.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/sys_info.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+
+#if defined(OS_WIN)
+#include "base/trace_event/trace_event_etw_export_win.h"
+#include "base/trace_event/trace_event_win.h"
+#endif
+
+class DeleteTraceLogForTesting {
+ public:
+  static void Delete() {
+    Singleton<base::trace_event::TraceLog,
+              LeakySingletonTraits<base::trace_event::TraceLog>>::OnExit(0);
+  }
+};
+
+// The thread buckets for the sampling profiler.
+BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// The overhead of TraceEvent above this threshold will be reported in the
+// trace.
+const int kOverheadReportThresholdInMicroseconds = 50;
+
+// String options that can be used to initialize TraceOptions.
+const char kRecordUntilFull[] = "record-until-full";
+const char kRecordContinuously[] = "record-continuously";
+const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
+const char kTraceToConsole[] = "trace-to-console";
+const char kEnableSampling[] = "enable-sampling";
+const char kEnableSystrace[] = "enable-systrace";
+
+// Controls the number of trace events we will buffer in-memory
+// before throwing them away.
+const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize;
+const size_t kTraceEventVectorBigBufferChunks =
+    512000000 / kTraceBufferChunkSize;
+const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
+const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
+const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
+// Can store results for 30 seconds with 1 ms sampling interval.
+const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
+// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
+const size_t kEchoToConsoleTraceEventBufferChunks = 256;
+
+const int kThreadFlushTimeoutMs = 3000;
+
+#if !defined(OS_NACL)
+// These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575.
+const char kEchoToConsoleCategoryFilter[] = "-ipc,-task";
+#endif
+
+const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
+
+#define MAX_CATEGORY_GROUPS 100
+
+// Parallel arrays g_category_groups and g_category_group_enabled are separate
+// so that a pointer to a member of g_category_group_enabled can be easily
+// converted to an index into g_category_groups. This allows macros to deal
+// only with char enabled pointers from g_category_group_enabled, and we can
+// convert internally to determine the category name from the char enabled
+// pointer.
+const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
+  "toplevel",
+  "tracing already shutdown",
+  "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
+  "__metadata",
+  // For reporting trace_event overhead. For thread local event buffers only.
+  "trace_event_overhead"};
+
+// The enabled flag is char instead of bool so that the API can be used from C.
+unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = { 0 };
+// Indexes here have to match the g_category_groups array indexes above.
+const int g_category_already_shutdown = 1;
+const int g_category_categories_exhausted = 2;
+const int g_category_metadata = 3;
+const int g_category_trace_event_overhead = 4;
+const int g_num_builtin_categories = 5;
+// Skip default categories.
+base::subtle::AtomicWord g_category_index = g_num_builtin_categories;
+
+// The name of the current thread. This is used to decide if the current
+// thread name has changed. We combine all the seen thread names into the
+// output name for the thread.
+LazyInstance<ThreadLocalPointer<const char> >::Leaky
+    g_current_thread_name = LAZY_INSTANCE_INITIALIZER;
+
+TimeTicks ThreadNow() {
+  return TimeTicks::IsThreadNowSupported() ?
+      TimeTicks::ThreadNow() : TimeTicks();
+}
+
+class TraceBufferRingBuffer : public TraceBuffer {
+ public:
+  TraceBufferRingBuffer(size_t max_chunks)
+      : max_chunks_(max_chunks),
+        recyclable_chunks_queue_(new size_t[queue_capacity()]),
+        queue_head_(0),
+        queue_tail_(max_chunks),
+        current_iteration_index_(0),
+        current_chunk_seq_(1) {
+    chunks_.reserve(max_chunks);
+    for (size_t i = 0; i < max_chunks; ++i)
+      recyclable_chunks_queue_[i] = i;
+  }
+
+  scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+    // Because the number of threads is much less than the number of chunks,
+    // the queue should never be empty.
+    DCHECK(!QueueIsEmpty());
+
+    *index = recyclable_chunks_queue_[queue_head_];
+    queue_head_ = NextQueueIndex(queue_head_);
+    current_iteration_index_ = queue_head_;
+
+    if (*index >= chunks_.size())
+      chunks_.resize(*index + 1);
+
+    TraceBufferChunk* chunk = chunks_[*index];
+    chunks_[*index] = NULL;  // Put NULL in the slot of a in-flight chunk.
+    if (chunk)
+      chunk->Reset(current_chunk_seq_++);
+    else
+      chunk = new TraceBufferChunk(current_chunk_seq_++);
+
+    return scoped_ptr<TraceBufferChunk>(chunk);
+  }
+
+  void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
+    // When this method is called, the queue should not be full because it
+    // can contain all chunks including the one to be returned.
+    DCHECK(!QueueIsFull());
+    DCHECK(chunk);
+    DCHECK_LT(index, chunks_.size());
+    DCHECK(!chunks_[index]);
+    chunks_[index] = chunk.release();
+    recyclable_chunks_queue_[queue_tail_] = index;
+    queue_tail_ = NextQueueIndex(queue_tail_);
+  }
+
+  bool IsFull() const override { return false; }
+
+  size_t Size() const override {
+    // This is approximate because not all of the chunks are full.
+    return chunks_.size() * kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+    if (!chunk || chunk->seq() != handle.chunk_seq)
+      return NULL;
+    return chunk->GetEventAt(handle.event_index);
+  }
+
+  const TraceBufferChunk* NextChunk() override {
+    if (chunks_.empty())
+      return NULL;
+
+    while (current_iteration_index_ != queue_tail_) {
+      size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
+      current_iteration_index_ = NextQueueIndex(current_iteration_index_);
+      if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+        continue;
+      DCHECK(chunks_[chunk_index]);
+      return chunks_[chunk_index];
+    }
+    return NULL;
+  }
+
+  scoped_ptr<TraceBuffer> CloneForIteration() const override {
+    scoped_ptr<ClonedTraceBuffer> cloned_buffer(new ClonedTraceBuffer());
+    for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+        queue_index = NextQueueIndex(queue_index)) {
+      size_t chunk_index = recyclable_chunks_queue_[queue_index];
+      if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+        continue;
+      TraceBufferChunk* chunk = chunks_[chunk_index];
+      cloned_buffer->chunks_.push_back(chunk ? chunk->Clone().release() : NULL);
+    }
+    return cloned_buffer.Pass();
+  }
+
+ private:
+  class ClonedTraceBuffer : public TraceBuffer {
+   public:
+    ClonedTraceBuffer() : current_iteration_index_(0) {}
+
+    // The only implemented method.
+    const TraceBufferChunk* NextChunk() override {
+      return current_iteration_index_ < chunks_.size() ?
+          chunks_[current_iteration_index_++] : NULL;
+    }
+
+    scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBufferChunk>();
+    }
+    void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk>) override {
+      NOTIMPLEMENTED();
+    }
+    bool IsFull() const override { return false; }
+    size_t Size() const override { return 0; }
+    size_t Capacity() const override { return 0; }
+    TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+      return NULL;
+    }
+    scoped_ptr<TraceBuffer> CloneForIteration() const override {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBuffer>();
+    }
+
+    size_t current_iteration_index_;
+    ScopedVector<TraceBufferChunk> chunks_;
+  };
+
+  bool QueueIsEmpty() const {
+    return queue_head_ == queue_tail_;
+  }
+
+  size_t QueueSize() const {
+    return queue_tail_ > queue_head_ ? queue_tail_ - queue_head_ :
+        queue_tail_ + queue_capacity() - queue_head_;
+  }
+
+  bool QueueIsFull() const {
+    return QueueSize() == queue_capacity() - 1;
+  }
+
+  size_t queue_capacity() const {
+    // One extra space to help distinguish full state and empty state.
+    return max_chunks_ + 1;
+  }
+
+  size_t NextQueueIndex(size_t index) const {
+    index++;
+    if (index >= queue_capacity())
+      index = 0;
+    return index;
+  }
+
+  size_t max_chunks_;
+  ScopedVector<TraceBufferChunk> chunks_;
+
+  scoped_ptr<size_t[]> recyclable_chunks_queue_;
+  size_t queue_head_;
+  size_t queue_tail_;
+
+  size_t current_iteration_index_;
+  uint32 current_chunk_seq_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer);
+};
+
+class TraceBufferVector : public TraceBuffer {
+ public:
+  TraceBufferVector(size_t max_chunks)
+      : in_flight_chunk_count_(0),
+        current_iteration_index_(0),
+        max_chunks_(max_chunks) {
+    chunks_.reserve(max_chunks_);
+  }
+
+  scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+    // This function may be called when adding normal events or indirectly from
+    // AddMetadataEventsWhileLocked(). We can not DECHECK(!IsFull()) because we
+    // have to add the metadata events and flush thread-local buffers even if
+    // the buffer is full.
+    *index = chunks_.size();
+    chunks_.push_back(NULL);  // Put NULL in the slot of a in-flight chunk.
+    ++in_flight_chunk_count_;
+    // + 1 because zero chunk_seq is not allowed.
+    return scoped_ptr<TraceBufferChunk>(
+        new TraceBufferChunk(static_cast<uint32>(*index) + 1));
+  }
+
+  void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
+    DCHECK_GT(in_flight_chunk_count_, 0u);
+    DCHECK_LT(index, chunks_.size());
+    DCHECK(!chunks_[index]);
+    --in_flight_chunk_count_;
+    chunks_[index] = chunk.release();
+  }
+
+  bool IsFull() const override { return chunks_.size() >= max_chunks_; }
+
+  size_t Size() const override {
+    // This is approximate because not all of the chunks are full.
+    return chunks_.size() * kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+    if (!chunk || chunk->seq() != handle.chunk_seq)
+      return NULL;
+    return chunk->GetEventAt(handle.event_index);
+  }
+
+  const TraceBufferChunk* NextChunk() override {
+    while (current_iteration_index_ < chunks_.size()) {
+      // Skip in-flight chunks.
+      const TraceBufferChunk* chunk = chunks_[current_iteration_index_++];
+      if (chunk)
+        return chunk;
+    }
+    return NULL;
+  }
+
+  scoped_ptr<TraceBuffer> CloneForIteration() const override {
+    NOTIMPLEMENTED();
+    return scoped_ptr<TraceBuffer>();
+  }
+
+ private:
+  size_t in_flight_chunk_count_;
+  size_t current_iteration_index_;
+  size_t max_chunks_;
+  ScopedVector<TraceBufferChunk> chunks_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
+};
+
+template <typename T>
+void InitializeMetadataEvent(TraceEvent* trace_event,
+                             int thread_id,
+                             const char* metadata_name, const char* arg_name,
+                             const T& value) {
+  if (!trace_event)
+    return;
+
+  int num_args = 1;
+  unsigned char arg_type;
+  unsigned long long arg_value;
+  ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
+  trace_event->Initialize(thread_id,
+                          TimeTicks(), TimeTicks(), TRACE_EVENT_PHASE_METADATA,
+                          &g_category_group_enabled[g_category_metadata],
+                          metadata_name, ::trace_event_internal::kNoEventId,
+                          num_args, &arg_name, &arg_type, &arg_value, NULL,
+                          TRACE_EVENT_FLAG_NONE);
+}
+
+class AutoThreadLocalBoolean {
+ public:
+  explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean)
+      : thread_local_boolean_(thread_local_boolean) {
+    DCHECK(!thread_local_boolean_->Get());
+    thread_local_boolean_->Set(true);
+  }
+  ~AutoThreadLocalBoolean() {
+    thread_local_boolean_->Set(false);
+  }
+
+ private:
+  ThreadLocalBoolean* thread_local_boolean_;
+  DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
+};
+
+}  // namespace
+
+void TraceBufferChunk::Reset(uint32 new_seq) {
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].Reset();
+  next_free_ = 0;
+  seq_ = new_seq;
+}
+
+TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
+  DCHECK(!IsFull());
+  *event_index = next_free_++;
+  return &chunk_[*event_index];
+}
+
+scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
+  scoped_ptr<TraceBufferChunk> cloned_chunk(new TraceBufferChunk(seq_));
+  cloned_chunk->next_free_ = next_free_;
+  for (size_t i = 0; i < next_free_; ++i)
+    cloned_chunk->chunk_[i].CopyFrom(chunk_[i]);
+  return cloned_chunk.Pass();
+}
+
+// A helper class that allows the lock to be acquired in the middle of the scope
+// and unlocks at the end of scope if locked.
+class TraceLog::OptionalAutoLock {
+ public:
+  explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
+
+  ~OptionalAutoLock() {
+    if (locked_)
+      lock_->Release();
+  }
+
+  void EnsureAcquired() {
+    if (!locked_) {
+      lock_->Acquire();
+      locked_ = true;
+    }
+  }
+
+ private:
+  Lock* lock_;
+  bool locked_;
+  DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
+};
+
+// Use this function instead of TraceEventHandle constructor to keep the
+// overhead of ScopedTracer (trace_event.h) constructor minimum.
+void MakeHandle(uint32 chunk_seq, size_t chunk_index, size_t event_index,
+                TraceEventHandle* handle) {
+  DCHECK(chunk_seq);
+  DCHECK(chunk_index < (1u << 16));
+  DCHECK(event_index < (1u << 16));
+  handle->chunk_seq = chunk_seq;
+  handle->chunk_index = static_cast<uint16>(chunk_index);
+  handle->event_index = static_cast<uint16>(event_index);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceEvent
+//
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; }
+
+// Copies |*member| into |*buffer|, sets |*member| to point to this new
+// location, and then advances |*buffer| by the amount written.
+void CopyTraceEventParameter(char** buffer,
+                             const char** member,
+                             const char* end) {
+  if (*member) {
+    size_t written = strlcpy(*buffer, *member, end - *buffer) + 1;
+    DCHECK_LE(static_cast<int>(written), end - *buffer);
+    *member = *buffer;
+    *buffer += written;
+  }
+}
+
+}  // namespace
+
+TraceEvent::TraceEvent()
+    : duration_(TimeDelta::FromInternalValue(-1)),
+      id_(0u),
+      category_group_enabled_(NULL),
+      name_(NULL),
+      thread_id_(0),
+      phase_(TRACE_EVENT_PHASE_BEGIN),
+      flags_(0) {
+  for (int i = 0; i < kTraceMaxNumArgs; ++i)
+    arg_names_[i] = NULL;
+  memset(arg_values_, 0, sizeof(arg_values_));
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+void TraceEvent::CopyFrom(const TraceEvent& other) {
+  timestamp_ = other.timestamp_;
+  thread_timestamp_ = other.thread_timestamp_;
+  duration_ = other.duration_;
+  id_ = other.id_;
+  category_group_enabled_ = other.category_group_enabled_;
+  name_ = other.name_;
+  thread_id_ = other.thread_id_;
+  phase_ = other.phase_;
+  flags_ = other.flags_;
+  parameter_copy_storage_ = other.parameter_copy_storage_;
+
+  for (int i = 0; i < kTraceMaxNumArgs; ++i) {
+    arg_names_[i] = other.arg_names_[i];
+    arg_types_[i] = other.arg_types_[i];
+    arg_values_[i] = other.arg_values_[i];
+    convertable_values_[i] = other.convertable_values_[i];
+  }
+}
+
+void TraceEvent::Initialize(
+    int thread_id,
+    TimeTicks timestamp,
+    TimeTicks thread_timestamp,
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned char flags) {
+  timestamp_ = timestamp;
+  thread_timestamp_ = thread_timestamp;
+  duration_ = TimeDelta::FromInternalValue(-1);
+  id_ = id;
+  category_group_enabled_ = category_group_enabled;
+  name_ = name;
+  thread_id_ = thread_id;
+  phase_ = phase;
+  flags_ = flags;
+
+  // Clamp num_args since it may have been set by a third_party library.
+  num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
+  int i = 0;
+  for (; i < num_args; ++i) {
+    arg_names_[i] = arg_names[i];
+    arg_types_[i] = arg_types[i];
+
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      convertable_values_[i] = convertable_values[i];
+    else
+      arg_values_[i].as_uint = arg_values[i];
+  }
+  for (; i < kTraceMaxNumArgs; ++i) {
+    arg_names_[i] = NULL;
+    arg_values_[i].as_uint = 0u;
+    convertable_values_[i] = NULL;
+    arg_types_[i] = TRACE_VALUE_TYPE_UINT;
+  }
+
+  bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
+  size_t alloc_size = 0;
+  if (copy) {
+    alloc_size += GetAllocLength(name);
+    for (i = 0; i < num_args; ++i) {
+      alloc_size += GetAllocLength(arg_names_[i]);
+      if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
+        arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
+    }
+  }
+
+  bool arg_is_copy[kTraceMaxNumArgs];
+  for (i = 0; i < num_args; ++i) {
+    // No copying of convertable types, we retain ownership.
+    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      continue;
+
+    // We only take a copy of arg_vals if they are of type COPY_STRING.
+    arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
+    if (arg_is_copy[i])
+      alloc_size += GetAllocLength(arg_values_[i].as_string);
+  }
+
+  if (alloc_size) {
+    parameter_copy_storage_ = new RefCountedString;
+    parameter_copy_storage_->data().resize(alloc_size);
+    char* ptr = string_as_array(&parameter_copy_storage_->data());
+    const char* end = ptr + alloc_size;
+    if (copy) {
+      CopyTraceEventParameter(&ptr, &name_, end);
+      for (i = 0; i < num_args; ++i) {
+        CopyTraceEventParameter(&ptr, &arg_names_[i], end);
+      }
+    }
+    for (i = 0; i < num_args; ++i) {
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        continue;
+      if (arg_is_copy[i])
+        CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end);
+    }
+    DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end;
+  }
+}
+
+void TraceEvent::Reset() {
+  // Only reset fields that won't be initialized in Initialize(), or that may
+  // hold references to other objects.
+  duration_ = TimeDelta::FromInternalValue(-1);
+  parameter_copy_storage_ = NULL;
+  for (int i = 0; i < kTraceMaxNumArgs; ++i)
+    convertable_values_[i] = NULL;
+}
+
+void TraceEvent::UpdateDuration(const TimeTicks& now,
+                                const TimeTicks& thread_now) {
+  DCHECK_EQ(duration_.ToInternalValue(), -1);
+  duration_ = now - timestamp_;
+  thread_duration_ = thread_now - thread_timestamp_;
+}
+
+// static
+void TraceEvent::AppendValueAsJSON(unsigned char type,
+                                   TraceEvent::TraceValue value,
+                                   std::string* out) {
+  switch (type) {
+    case TRACE_VALUE_TYPE_BOOL:
+      *out += value.as_bool ? "true" : "false";
+      break;
+    case TRACE_VALUE_TYPE_UINT:
+      StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint));
+      break;
+    case TRACE_VALUE_TYPE_INT:
+      StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int));
+      break;
+    case TRACE_VALUE_TYPE_DOUBLE: {
+      // FIXME: base/json/json_writer.cc is using the same code,
+      //        should be made into a common method.
+      std::string real;
+      double val = value.as_double;
+      if (std::isfinite(val)) {
+        real = DoubleToString(val);
+        // Ensure that the number has a .0 if there's no decimal or 'e'.  This
+        // makes sure that when we read the JSON back, it's interpreted as a
+        // real rather than an int.
+        if (real.find('.') == std::string::npos &&
+            real.find('e') == std::string::npos &&
+            real.find('E') == std::string::npos) {
+          real.append(".0");
+        }
+        // The JSON spec requires that non-integer values in the range (-1,1)
+        // have a zero before the decimal point - ".52" is not valid, "0.52" is.
+        if (real[0] == '.') {
+          real.insert(0, "0");
+        } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+          // "-.1" bad "-0.1" good
+          real.insert(1, "0");
+        }
+      } else if (std::isnan(val)){
+        // The JSON spec doesn't allow NaN and Infinity (since these are
+        // objects in EcmaScript).  Use strings instead.
+        real = "\"NaN\"";
+      } else if (val < 0) {
+        real = "\"-Infinity\"";
+      } else {
+        real = "\"Infinity\"";
+      }
+      StringAppendF(out, "%s", real.c_str());
+      break;
+    }
+    case TRACE_VALUE_TYPE_POINTER:
+      // JSON only supports double and int numbers.
+      // So as not to lose bits from a 64-bit pointer, output as a hex string.
+      StringAppendF(out, "\"0x%" PRIx64 "\"", static_cast<uint64>(
+                                     reinterpret_cast<intptr_t>(
+                                     value.as_pointer)));
+      break;
+    case TRACE_VALUE_TYPE_STRING:
+    case TRACE_VALUE_TYPE_COPY_STRING:
+      EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out);
+      break;
+    default:
+      NOTREACHED() << "Don't know how to print this value";
+      break;
+  }
+}
+
+void TraceEvent::AppendAsJSON(std::string* out) const {
+  int64 time_int64 = timestamp_.ToInternalValue();
+  int process_id = TraceLog::GetInstance()->process_id();
+  // Category group checked at category creation time.
+  DCHECK(!strchr(name_, '"'));
+  StringAppendF(out,
+      "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ","
+      "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{",
+      process_id,
+      thread_id_,
+      time_int64,
+      phase_,
+      TraceLog::GetCategoryGroupName(category_group_enabled_),
+      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 += "\":";
+
+    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      convertable_values_[i]->AppendAsTraceFormat(out);
+    else
+      AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+  }
+  *out += "}";
+
+  if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
+    int64 duration = duration_.ToInternalValue();
+    if (duration != -1)
+      StringAppendF(out, ",\"dur\":%" PRId64, duration);
+    if (!thread_timestamp_.is_null()) {
+      int64 thread_duration = thread_duration_.ToInternalValue();
+      if (thread_duration != -1)
+        StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration);
+    }
+  }
+
+  // Output tts if thread_timestamp is valid.
+  if (!thread_timestamp_.is_null()) {
+    int64 thread_time_int64 = thread_timestamp_.ToInternalValue();
+    StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
+  }
+
+  // Output async tts marker field if flag is set.
+  if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
+    StringAppendF(out, ", \"use_async_tts\":1");
+  }
+
+  // If id_ is set, print it out as a hex string so we don't loose any
+  // bits (it might be a 64-bit pointer).
+  if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
+    StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64>(id_));
+
+  // Instant events also output their scope.
+  if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
+    char scope = '?';
+    switch (flags_ & TRACE_EVENT_FLAG_SCOPE_MASK) {
+      case TRACE_EVENT_SCOPE_GLOBAL:
+        scope = TRACE_EVENT_SCOPE_NAME_GLOBAL;
+        break;
+
+      case TRACE_EVENT_SCOPE_PROCESS:
+        scope = TRACE_EVENT_SCOPE_NAME_PROCESS;
+        break;
+
+      case TRACE_EVENT_SCOPE_THREAD:
+        scope = TRACE_EVENT_SCOPE_NAME_THREAD;
+        break;
+    }
+    StringAppendF(out, ",\"s\":\"%c\"", scope);
+  }
+
+  *out += "}";
+}
+
+void TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const {
+  *out << name_ << "[";
+  *out << TraceLog::GetCategoryGroupName(category_group_enabled_);
+  *out << "]";
+  if (arg_names_[0]) {
+    *out << ", {";
+    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+      if (i > 0)
+        *out << ", ";
+      *out << arg_names_[i] << ":";
+      std::string value_as_text;
+
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        convertable_values_[i]->AppendAsTraceFormat(&value_as_text);
+      else
+        AppendValueAsJSON(arg_types_[i], arg_values_[i], &value_as_text);
+
+      *out << value_as_text;
+    }
+    *out << "}";
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceResultBuffer
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TraceResultBuffer::OutputCallback
+    TraceResultBuffer::SimpleOutput::GetCallback() {
+  return Bind(&SimpleOutput::Append, Unretained(this));
+}
+
+void TraceResultBuffer::SimpleOutput::Append(
+    const std::string& json_trace_output) {
+  json_output += json_trace_output;
+}
+
+TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {
+}
+
+TraceResultBuffer::~TraceResultBuffer() {
+}
+
+void TraceResultBuffer::SetOutputCallback(
+    const OutputCallback& json_chunk_callback) {
+  output_callback_ = json_chunk_callback;
+}
+
+void TraceResultBuffer::Start() {
+  append_comma_ = false;
+  output_callback_.Run("[");
+}
+
+void TraceResultBuffer::AddFragment(const std::string& trace_fragment) {
+  if (append_comma_)
+    output_callback_.Run(",");
+  append_comma_ = true;
+  output_callback_.Run(trace_fragment);
+}
+
+void TraceResultBuffer::Finish() {
+  output_callback_.Run("]");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceSamplingThread
+//
+////////////////////////////////////////////////////////////////////////////////
+class TraceBucketData;
+typedef base::Callback<void(TraceBucketData*)> TraceSampleCallback;
+
+class TraceBucketData {
+ public:
+  TraceBucketData(base::subtle::AtomicWord* bucket,
+                  const char* name,
+                  TraceSampleCallback callback);
+  ~TraceBucketData();
+
+  TRACE_EVENT_API_ATOMIC_WORD* bucket;
+  const char* bucket_name;
+  TraceSampleCallback callback;
+};
+
+// This object must be created on the IO thread.
+class TraceSamplingThread : public PlatformThread::Delegate {
+ public:
+  TraceSamplingThread();
+  ~TraceSamplingThread() override;
+
+  // Implementation of PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  static void DefaultSamplingCallback(TraceBucketData* bucekt_data);
+
+  void Stop();
+  void WaitSamplingEventForTesting();
+
+ private:
+  friend class TraceLog;
+
+  void GetSamples();
+  // Not thread-safe. Once the ThreadMain has been called, this can no longer
+  // be called.
+  void RegisterSampleBucket(TRACE_EVENT_API_ATOMIC_WORD* bucket,
+                            const char* const name,
+                            TraceSampleCallback callback);
+  // Splits a combined "category\0name" into the two component parts.
+  static void ExtractCategoryAndName(const char* combined,
+                                     const char** category,
+                                     const char** name);
+  std::vector<TraceBucketData> sample_buckets_;
+  bool thread_running_;
+  CancellationFlag cancellation_flag_;
+  WaitableEvent waitable_event_for_testing_;
+};
+
+
+TraceSamplingThread::TraceSamplingThread()
+    : thread_running_(false),
+      waitable_event_for_testing_(false, false) {
+}
+
+TraceSamplingThread::~TraceSamplingThread() {
+}
+
+void TraceSamplingThread::ThreadMain() {
+  PlatformThread::SetName("Sampling Thread");
+  thread_running_ = true;
+  const int kSamplingFrequencyMicroseconds = 1000;
+  while (!cancellation_flag_.IsSet()) {
+    PlatformThread::Sleep(
+        TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
+    GetSamples();
+    waitable_event_for_testing_.Signal();
+  }
+}
+
+// static
+void TraceSamplingThread::DefaultSamplingCallback(
+    TraceBucketData* bucket_data) {
+  TRACE_EVENT_API_ATOMIC_WORD category_and_name =
+      TRACE_EVENT_API_ATOMIC_LOAD(*bucket_data->bucket);
+  if (!category_and_name)
+    return;
+  const char* const combined =
+      reinterpret_cast<const char* const>(category_and_name);
+  const char* category_group;
+  const char* name;
+  ExtractCategoryAndName(combined, &category_group, &name);
+  TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_SAMPLE,
+      TraceLog::GetCategoryGroupEnabled(category_group),
+      name, 0, 0, NULL, NULL, NULL, NULL, 0);
+}
+
+void TraceSamplingThread::GetSamples() {
+  for (size_t i = 0; i < sample_buckets_.size(); ++i) {
+    TraceBucketData* bucket_data = &sample_buckets_[i];
+    bucket_data->callback.Run(bucket_data);
+  }
+}
+
+void TraceSamplingThread::RegisterSampleBucket(
+    TRACE_EVENT_API_ATOMIC_WORD* bucket,
+    const char* const name,
+    TraceSampleCallback callback) {
+  // Access to sample_buckets_ doesn't cause races with the sampling thread
+  // that uses the sample_buckets_, because it is guaranteed that
+  // RegisterSampleBucket is called before the sampling thread is created.
+  DCHECK(!thread_running_);
+  sample_buckets_.push_back(TraceBucketData(bucket, name, callback));
+}
+
+// static
+void TraceSamplingThread::ExtractCategoryAndName(const char* combined,
+                                                 const char** category,
+                                                 const char** name) {
+  *category = combined;
+  *name = &combined[strlen(combined) + 1];
+}
+
+void TraceSamplingThread::Stop() {
+  cancellation_flag_.Set();
+}
+
+void TraceSamplingThread::WaitSamplingEventForTesting() {
+  waitable_event_for_testing_.Wait();
+}
+
+TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket,
+                                 const char* name,
+                                 TraceSampleCallback callback)
+    : bucket(bucket),
+      bucket_name(name),
+      callback(callback) {
+}
+
+TraceBucketData::~TraceBucketData() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceOptions
+//
+////////////////////////////////////////////////////////////////////////////////
+
+bool TraceOptions::SetFromString(const std::string& options_string) {
+  record_mode = RECORD_UNTIL_FULL;
+  enable_sampling = false;
+  enable_systrace = false;
+
+  std::vector<std::string> split;
+  std::vector<std::string>::iterator iter;
+  base::SplitString(options_string, ',', &split);
+  for (iter = split.begin(); iter != split.end(); ++iter) {
+    if (*iter == kRecordUntilFull) {
+      record_mode = RECORD_UNTIL_FULL;
+    } else if (*iter == kRecordContinuously) {
+      record_mode = RECORD_CONTINUOUSLY;
+    } else if (*iter == kTraceToConsole) {
+      record_mode = ECHO_TO_CONSOLE;
+    } else if (*iter == kRecordAsMuchAsPossible) {
+      record_mode = RECORD_AS_MUCH_AS_POSSIBLE;
+    } else if (*iter == kEnableSampling) {
+      enable_sampling = true;
+    } else if (*iter == kEnableSystrace) {
+      enable_systrace = true;
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+std::string TraceOptions::ToString() const {
+  std::string ret;
+  switch (record_mode) {
+    case RECORD_UNTIL_FULL:
+      ret = kRecordUntilFull;
+      break;
+    case RECORD_CONTINUOUSLY:
+      ret = kRecordContinuously;
+      break;
+    case ECHO_TO_CONSOLE:
+      ret = kTraceToConsole;
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      ret = kRecordAsMuchAsPossible;
+      break;
+    default:
+      NOTREACHED();
+  }
+  if (enable_sampling)
+    ret = ret + "," + kEnableSampling;
+  if (enable_systrace)
+    ret = ret + "," + kEnableSystrace;
+  return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceLog
+//
+////////////////////////////////////////////////////////////////////////////////
+
+class TraceLog::ThreadLocalEventBuffer
+    : public MessageLoop::DestructionObserver {
+ public:
+  ThreadLocalEventBuffer(TraceLog* trace_log);
+  ~ThreadLocalEventBuffer() override;
+
+  TraceEvent* AddTraceEvent(TraceEventHandle* handle);
+
+  void ReportOverhead(const TimeTicks& event_timestamp,
+                      const TimeTicks& event_thread_timestamp);
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) {
+    if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
+        handle.chunk_index != chunk_index_)
+      return NULL;
+
+    return chunk_->GetEventAt(handle.event_index);
+  }
+
+  int generation() const { return generation_; }
+
+ private:
+  // MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
+  void FlushWhileLocked();
+
+  void CheckThisIsCurrentBuffer() const {
+    DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
+  }
+
+  // Since TraceLog is a leaky singleton, trace_log_ will always be valid
+  // as long as the thread exists.
+  TraceLog* trace_log_;
+  scoped_ptr<TraceBufferChunk> chunk_;
+  size_t chunk_index_;
+  int event_count_;
+  TimeDelta overhead_;
+  int generation_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
+};
+
+TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
+    : trace_log_(trace_log),
+      chunk_index_(0),
+      event_count_(0),
+      generation_(trace_log->generation()) {
+  // ThreadLocalEventBuffer is created only if the thread has a message loop, so
+  // the following message_loop won't be NULL.
+  MessageLoop* message_loop = MessageLoop::current();
+  message_loop->AddDestructionObserver(this);
+
+  AutoLock lock(trace_log->lock_);
+  trace_log->thread_message_loops_.insert(message_loop);
+}
+
+TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
+  CheckThisIsCurrentBuffer();
+  MessageLoop::current()->RemoveDestructionObserver(this);
+
+  // Zero event_count_ happens in either of the following cases:
+  // - no event generated for the thread;
+  // - the thread has no message loop;
+  // - trace_event_overhead is disabled.
+  if (event_count_) {
+    InitializeMetadataEvent(AddTraceEvent(NULL),
+                            static_cast<int>(base::PlatformThread::CurrentId()),
+                            "overhead", "average_overhead",
+                            overhead_.InMillisecondsF() / event_count_);
+  }
+
+  {
+    AutoLock lock(trace_log_->lock_);
+    FlushWhileLocked();
+    trace_log_->thread_message_loops_.erase(MessageLoop::current());
+  }
+  trace_log_->thread_local_event_buffer_.Set(NULL);
+}
+
+TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
+    TraceEventHandle* handle) {
+  CheckThisIsCurrentBuffer();
+
+  if (chunk_ && chunk_->IsFull()) {
+    AutoLock lock(trace_log_->lock_);
+    FlushWhileLocked();
+    chunk_.reset();
+  }
+  if (!chunk_) {
+    AutoLock lock(trace_log_->lock_);
+    chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
+    trace_log_->CheckIfBufferIsFullWhileLocked();
+  }
+  if (!chunk_)
+    return NULL;
+
+  size_t event_index;
+  TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
+  if (trace_event && handle)
+    MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
+
+  return trace_event;
+}
+
+void TraceLog::ThreadLocalEventBuffer::ReportOverhead(
+    const TimeTicks& event_timestamp,
+    const TimeTicks& event_thread_timestamp) {
+  if (!g_category_group_enabled[g_category_trace_event_overhead])
+    return;
+
+  CheckThisIsCurrentBuffer();
+
+  event_count_++;
+  TimeTicks thread_now = ThreadNow();
+  TimeTicks now = trace_log_->OffsetNow();
+  TimeDelta overhead = now - event_timestamp;
+  if (overhead.InMicroseconds() >= kOverheadReportThresholdInMicroseconds) {
+    TraceEvent* trace_event = AddTraceEvent(NULL);
+    if (trace_event) {
+      trace_event->Initialize(
+          static_cast<int>(PlatformThread::CurrentId()),
+          event_timestamp, event_thread_timestamp,
+          TRACE_EVENT_PHASE_COMPLETE,
+          &g_category_group_enabled[g_category_trace_event_overhead],
+          "overhead", 0, 0, NULL, NULL, NULL, NULL, 0);
+      trace_event->UpdateDuration(now, thread_now);
+    }
+  }
+  overhead_ += overhead;
+}
+
+void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() {
+  delete this;
+}
+
+void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
+  if (!chunk_)
+    return;
+
+  trace_log_->lock_.AssertAcquired();
+  if (trace_log_->CheckGeneration(generation_)) {
+    // Return the chunk to the buffer only if the generation matches.
+    trace_log_->logged_events_->ReturnChunk(chunk_index_, chunk_.Pass());
+  }
+  // Otherwise this method may be called from the destructor, or TraceLog will
+  // find the generation mismatch and delete this buffer soon.
+}
+
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {
+}
+
+TraceLogStatus::~TraceLogStatus() {
+}
+
+// static
+TraceLog* TraceLog::GetInstance() {
+  return Singleton<TraceLog, LeakySingletonTraits<TraceLog> >::get();
+}
+
+TraceLog::TraceLog()
+    : mode_(DISABLED),
+      num_traces_recorded_(0),
+      event_callback_(0),
+      dispatching_to_observer_list_(false),
+      process_sort_index_(0),
+      process_id_hash_(0),
+      process_id_(0),
+      watch_category_(0),
+      trace_options_(kInternalRecordUntilFull),
+      sampling_thread_handle_(0),
+      category_filter_(CategoryFilter::kDefaultCategoryFilterString),
+      event_callback_category_filter_(
+          CategoryFilter::kDefaultCategoryFilterString),
+      thread_shared_chunk_index_(0),
+      generation_(0),
+      use_worker_thread_(false) {
+  // Trace is enabled or disabled on one thread while other threads are
+  // accessing the enabled flag. We don't care whether edge-case events are
+  // traced or not, so we allow races on the enabled flag to keep the trace
+  // macros fast.
+  // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots:
+  // ANNOTATE_BENIGN_RACE_SIZED(g_category_group_enabled,
+  //                            sizeof(g_category_group_enabled),
+  //                           "trace_event category enabled");
+  for (int i = 0; i < MAX_CATEGORY_GROUPS; ++i) {
+    ANNOTATE_BENIGN_RACE(&g_category_group_enabled[i],
+                         "trace_event category enabled");
+  }
+#if defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  SetProcessID(0);
+#else
+  SetProcessID(static_cast<int>(GetCurrentProcId()));
+
+  // NaCl also shouldn't access the command line.
+  if (CommandLine::InitializedForCurrentProcess() &&
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToConsole)) {
+    std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+        switches::kTraceToConsole);
+    if (filter.empty()) {
+      filter = kEchoToConsoleCategoryFilter;
+    } else {
+      filter.append(",");
+      filter.append(kEchoToConsoleCategoryFilter);
+    }
+
+    LOG(ERROR) << "Start " << switches::kTraceToConsole
+               << " with CategoryFilter '" << filter << "'.";
+    SetEnabled(CategoryFilter(filter),
+               RECORDING_MODE,
+               TraceOptions(ECHO_TO_CONSOLE));
+  }
+#endif
+
+  logged_events_.reset(CreateTraceBuffer());
+}
+
+TraceLog::~TraceLog() {
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabled(
+    const char* category_group) {
+  TraceLog* tracelog = GetInstance();
+  if (!tracelog) {
+    DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
+    return &g_category_group_enabled[g_category_already_shutdown];
+  }
+  return tracelog->GetCategoryGroupEnabledInternal(category_group);
+}
+
+const char* TraceLog::GetCategoryGroupName(
+    const unsigned char* category_group_enabled) {
+  // Calculate the index of the category group by finding
+  // category_group_enabled in g_category_group_enabled array.
+  uintptr_t category_begin =
+      reinterpret_cast<uintptr_t>(g_category_group_enabled);
+  uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
+  DCHECK(category_ptr >= category_begin &&
+         category_ptr < reinterpret_cast<uintptr_t>(
+             g_category_group_enabled + MAX_CATEGORY_GROUPS)) <<
+      "out of bounds category pointer";
+  uintptr_t category_index =
+      (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
+  return g_category_groups[category_index];
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
+  unsigned char enabled_flag = 0;
+  const char* category_group = g_category_groups[category_index];
+  if (mode_ == RECORDING_MODE &&
+      category_filter_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_RECORDING;
+  else if (mode_ == MONITORING_MODE &&
+      category_filter_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_MONITORING;
+  if (event_callback_ &&
+      event_callback_category_filter_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
+#if defined(OS_WIN)
+  if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
+    enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+#endif
+
+  g_category_group_enabled[category_index] = enabled_flag;
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlags() {
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  for (size_t i = 0; i < category_index; i++)
+    UpdateCategoryGroupEnabledFlag(i);
+}
+
+void TraceLog::UpdateSyntheticDelaysFromCategoryFilter() {
+  ResetTraceEventSyntheticDelays();
+  const CategoryFilter::StringList& delays =
+      category_filter_.GetSyntheticDelayValues();
+  CategoryFilter::StringList::const_iterator ci;
+  for (ci = delays.begin(); ci != delays.end(); ++ci) {
+    StringTokenizer tokens(*ci, ";");
+    if (!tokens.GetNext())
+      continue;
+    TraceEventSyntheticDelay* delay =
+        TraceEventSyntheticDelay::Lookup(tokens.token());
+    while (tokens.GetNext()) {
+      std::string token = tokens.token();
+      char* duration_end;
+      double target_duration = strtod(token.c_str(), &duration_end);
+      if (duration_end != token.c_str()) {
+        delay->SetTargetDuration(TimeDelta::FromMicroseconds(
+            static_cast<int64>(target_duration * 1e6)));
+      } else if (token == "static") {
+        delay->SetMode(TraceEventSyntheticDelay::STATIC);
+      } else if (token == "oneshot") {
+        delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
+      } else if (token == "alternating") {
+        delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
+      }
+    }
+  }
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
+    const char* category_group) {
+  DCHECK(!strchr(category_group, '"')) <<
+      "Category groups may not contain double quote";
+  // The g_category_groups is append only, avoid using a lock for the fast path.
+  size_t current_category_index = base::subtle::Acquire_Load(&g_category_index);
+
+  // Search for pre-existing category group.
+  for (size_t i = 0; i < current_category_index; ++i) {
+    if (strcmp(g_category_groups[i], category_group) == 0) {
+      return &g_category_group_enabled[i];
+    }
+  }
+
+  unsigned char* category_group_enabled = NULL;
+  // This is the slow path: the lock is not held in the case above, so more
+  // than one thread could have reached here trying to add the same category.
+  // Only hold to lock when actually appending a new category, and
+  // check the categories groups again.
+  AutoLock lock(lock_);
+  size_t category_index = base::subtle::Acquire_Load(&g_category_index);
+  for (size_t i = 0; i < category_index; ++i) {
+    if (strcmp(g_category_groups[i], category_group) == 0) {
+      return &g_category_group_enabled[i];
+    }
+  }
+
+  // Create a new category group.
+  DCHECK(category_index < MAX_CATEGORY_GROUPS) <<
+      "must increase MAX_CATEGORY_GROUPS";
+  if (category_index < MAX_CATEGORY_GROUPS) {
+    // Don't hold on to the category_group pointer, so that we can create
+    // category groups with strings not known at compile time (this is
+    // required by SetWatchEvent).
+    const char* new_group = strdup(category_group);
+    ANNOTATE_LEAKING_OBJECT_PTR(new_group);
+    g_category_groups[category_index] = new_group;
+    DCHECK(!g_category_group_enabled[category_index]);
+    // Note that if both included and excluded patterns in the
+    // CategoryFilter are empty, we exclude nothing,
+    // thereby enabling this category group.
+    UpdateCategoryGroupEnabledFlag(category_index);
+    category_group_enabled = &g_category_group_enabled[category_index];
+    // Update the max index now.
+    base::subtle::Release_Store(&g_category_index, category_index + 1);
+  } else {
+    category_group_enabled =
+        &g_category_group_enabled[g_category_categories_exhausted];
+  }
+  return category_group_enabled;
+}
+
+void TraceLog::GetKnownCategoryGroups(
+    std::vector<std::string>* category_groups) {
+  AutoLock lock(lock_);
+  category_groups->push_back(
+      g_category_groups[g_category_trace_event_overhead]);
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  for (size_t i = g_num_builtin_categories; i < category_index; i++)
+    category_groups->push_back(g_category_groups[i]);
+}
+
+void TraceLog::SetEnabled(const CategoryFilter& category_filter,
+                          Mode mode,
+                          const TraceOptions& options) {
+  std::vector<EnabledStateObserver*> observer_list;
+  {
+    AutoLock lock(lock_);
+
+    // Can't enable tracing when Flush() is in progress.
+    DCHECK(!flush_task_runner_);
+
+    InternalTraceOptions new_options =
+        GetInternalOptionsFromTraceOptions(options);
+
+   InternalTraceOptions old_options = trace_options();
+
+    if (IsEnabled()) {
+      if (new_options != old_options) {
+        DLOG(ERROR) << "Attempting to re-enable tracing with a different "
+                    << "set of options.";
+      }
+
+      if (mode != mode_) {
+        DLOG(ERROR) << "Attempting to re-enable tracing with a different mode.";
+      }
+
+      category_filter_.Merge(category_filter);
+      UpdateCategoryGroupEnabledFlags();
+      return;
+    }
+
+    if (dispatching_to_observer_list_) {
+      DLOG(ERROR) <<
+          "Cannot manipulate TraceLog::Enabled state from an observer.";
+      return;
+    }
+
+    mode_ = mode;
+
+    if (new_options != old_options) {
+      subtle::NoBarrier_Store(&trace_options_, new_options);
+      UseNextTraceBuffer();
+    }
+
+    num_traces_recorded_++;
+
+    category_filter_ = CategoryFilter(category_filter);
+    UpdateCategoryGroupEnabledFlags();
+    UpdateSyntheticDelaysFromCategoryFilter();
+
+    if (new_options & kInternalEnableSampling) {
+      sampling_thread_.reset(new TraceSamplingThread);
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[0],
+          "bucket0",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[1],
+          "bucket1",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[2],
+          "bucket2",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      if (!PlatformThread::Create(
+            0, sampling_thread_.get(), &sampling_thread_handle_)) {
+        DCHECK(false) << "failed to create thread";
+      }
+    }
+
+    dispatching_to_observer_list_ = true;
+    observer_list = enabled_state_observer_list_;
+  }
+  // Notify observers outside the lock in case they trigger trace events.
+  for (size_t i = 0; i < observer_list.size(); ++i)
+    observer_list[i]->OnTraceLogEnabled();
+
+  {
+    AutoLock lock(lock_);
+    dispatching_to_observer_list_ = false;
+  }
+}
+
+TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceOptions(
+    const TraceOptions& options) {
+  InternalTraceOptions ret =
+      options.enable_sampling ? kInternalEnableSampling : kInternalNone;
+  switch (options.record_mode) {
+    case RECORD_UNTIL_FULL:
+      return ret | kInternalRecordUntilFull;
+    case RECORD_CONTINUOUSLY:
+      return ret | kInternalRecordContinuously;
+    case ECHO_TO_CONSOLE:
+      return ret | kInternalEchoToConsole;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      return ret | kInternalRecordAsMuchAsPossible;
+  }
+  NOTREACHED();
+  return kInternalNone;
+}
+
+CategoryFilter TraceLog::GetCurrentCategoryFilter() {
+  AutoLock lock(lock_);
+  return category_filter_;
+}
+
+TraceOptions TraceLog::GetCurrentTraceOptions() const {
+  TraceOptions ret;
+  InternalTraceOptions option = trace_options();
+  ret.enable_sampling = (option & kInternalEnableSampling) != 0;
+  if (option & kInternalRecordUntilFull)
+    ret.record_mode = RECORD_UNTIL_FULL;
+  else if (option & kInternalRecordContinuously)
+    ret.record_mode = RECORD_CONTINUOUSLY;
+  else if (option & kInternalEchoToConsole)
+    ret.record_mode = ECHO_TO_CONSOLE;
+  else if (option & kInternalRecordAsMuchAsPossible)
+    ret.record_mode = RECORD_AS_MUCH_AS_POSSIBLE;
+  else
+    NOTREACHED();
+  return ret;
+}
+
+void TraceLog::SetDisabled() {
+  AutoLock lock(lock_);
+  SetDisabledWhileLocked();
+}
+
+void TraceLog::SetDisabledWhileLocked() {
+  lock_.AssertAcquired();
+
+  if (!IsEnabled())
+    return;
+
+  if (dispatching_to_observer_list_) {
+    DLOG(ERROR)
+        << "Cannot manipulate TraceLog::Enabled state from an observer.";
+    return;
+  }
+
+  mode_ = DISABLED;
+
+  if (sampling_thread_.get()) {
+    // Stop the sampling thread.
+    sampling_thread_->Stop();
+    lock_.Release();
+    PlatformThread::Join(sampling_thread_handle_);
+    lock_.Acquire();
+    sampling_thread_handle_ = PlatformThreadHandle();
+    sampling_thread_.reset();
+  }
+
+  category_filter_.Clear();
+  subtle::NoBarrier_Store(&watch_category_, 0);
+  watch_event_name_ = "";
+  UpdateCategoryGroupEnabledFlags();
+  AddMetadataEventsWhileLocked();
+
+  dispatching_to_observer_list_ = true;
+  std::vector<EnabledStateObserver*> observer_list =
+      enabled_state_observer_list_;
+
+  {
+    // Dispatch to observers outside the lock in case the observer triggers a
+    // trace event.
+    AutoUnlock unlock(lock_);
+    for (size_t i = 0; i < observer_list.size(); ++i)
+      observer_list[i]->OnTraceLogDisabled();
+  }
+  dispatching_to_observer_list_ = false;
+}
+
+int TraceLog::GetNumTracesRecorded() {
+  AutoLock lock(lock_);
+  if (!IsEnabled())
+    return -1;
+  return num_traces_recorded_;
+}
+
+void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
+  enabled_state_observer_list_.push_back(listener);
+}
+
+void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
+  std::vector<EnabledStateObserver*>::iterator it =
+      std::find(enabled_state_observer_list_.begin(),
+                enabled_state_observer_list_.end(),
+                listener);
+  if (it != enabled_state_observer_list_.end())
+    enabled_state_observer_list_.erase(it);
+}
+
+bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
+  std::vector<EnabledStateObserver*>::const_iterator it =
+      std::find(enabled_state_observer_list_.begin(),
+                enabled_state_observer_list_.end(),
+                listener);
+  return it != enabled_state_observer_list_.end();
+}
+
+TraceLogStatus TraceLog::GetStatus() const {
+  AutoLock lock(lock_);
+  TraceLogStatus result;
+  result.event_capacity = logged_events_->Capacity();
+  result.event_count = logged_events_->Size();
+  return result;
+}
+
+bool TraceLog::BufferIsFull() const {
+  AutoLock lock(lock_);
+  return logged_events_->IsFull();
+}
+
+TraceBuffer* TraceLog::CreateTraceBuffer() {
+  InternalTraceOptions options = trace_options();
+  if (options & kInternalRecordContinuously)
+    return new TraceBufferRingBuffer(kTraceEventRingBufferChunks);
+  else if ((options & kInternalEnableSampling) && mode_ == MONITORING_MODE)
+    return new TraceBufferRingBuffer(kMonitorTraceEventBufferChunks);
+  else if (options & kInternalEchoToConsole)
+    return new TraceBufferRingBuffer(kEchoToConsoleTraceEventBufferChunks);
+  else if (options & kInternalRecordAsMuchAsPossible)
+    return CreateTraceBufferVectorOfSize(kTraceEventVectorBigBufferChunks);
+  return CreateTraceBufferVectorOfSize(kTraceEventVectorBufferChunks);
+}
+
+TraceBuffer* TraceLog::CreateTraceBufferVectorOfSize(size_t max_chunks) {
+  return new TraceBufferVector(max_chunks);
+}
+
+TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
+    TraceEventHandle* handle, bool check_buffer_is_full) {
+  lock_.AssertAcquired();
+
+  if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
+    logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                thread_shared_chunk_.Pass());
+  }
+
+  if (!thread_shared_chunk_) {
+    thread_shared_chunk_ = logged_events_->GetChunk(
+        &thread_shared_chunk_index_);
+    if (check_buffer_is_full)
+      CheckIfBufferIsFullWhileLocked();
+  }
+  if (!thread_shared_chunk_)
+    return NULL;
+
+  size_t event_index;
+  TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
+  if (trace_event && handle) {
+    MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
+               event_index, handle);
+  }
+  return trace_event;
+}
+
+void TraceLog::CheckIfBufferIsFullWhileLocked() {
+  lock_.AssertAcquired();
+  if (logged_events_->IsFull()) {
+    if (buffer_limit_reached_timestamp_.is_null()) {
+      buffer_limit_reached_timestamp_ = OffsetNow();
+    }
+    SetDisabledWhileLocked();
+  }
+}
+
+void TraceLog::SetEventCallbackEnabled(const CategoryFilter& category_filter,
+                                       EventCallback cb) {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&event_callback_,
+                          reinterpret_cast<subtle::AtomicWord>(cb));
+  event_callback_category_filter_ = category_filter;
+  UpdateCategoryGroupEnabledFlags();
+};
+
+void TraceLog::SetEventCallbackDisabled() {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&event_callback_, 0);
+  UpdateCategoryGroupEnabledFlags();
+}
+
+// Flush() works as the following:
+// 1. Flush() is called in thread A whose task runner is saved in
+//    flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
+//    loop to flush the thread local buffers; otherwise finish the flush;
+// 3. FlushCurrentThread() deletes the thread local event buffer:
+//    - The last batch of events of the thread are flushed into the main buffer;
+//    - The message loop will be removed from thread_message_loops_;
+//    If this is the last message loop, finish the flush;
+// 4. If any thread hasn't finish its flush in time, finish the flush.
+void TraceLog::Flush(const TraceLog::OutputCallback& cb,
+                     bool use_worker_thread) {
+  use_worker_thread_ = use_worker_thread;
+  if (IsEnabled()) {
+    // Can't flush when tracing is enabled because otherwise PostTask would
+    // - generate more trace events;
+    // - deschedule the calling thread on some platforms causing inaccurate
+    //   timing of the trace events.
+    scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+    if (!cb.is_null())
+      cb.Run(empty_result, false);
+    LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled";
+    return;
+  }
+
+  int generation = this->generation();
+  // Copy of thread_message_loops_ to be used without locking.
+  std::vector<scoped_refptr<SingleThreadTaskRunner> >
+      thread_message_loop_task_runners;
+  {
+    AutoLock lock(lock_);
+    DCHECK(!flush_task_runner_);
+    flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+                             ? ThreadTaskRunnerHandle::Get()
+                             : nullptr;
+    DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
+    flush_output_callback_ = cb;
+
+    if (thread_shared_chunk_) {
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  thread_shared_chunk_.Pass());
+    }
+
+    if (thread_message_loops_.size()) {
+      for (hash_set<MessageLoop*>::const_iterator it =
+           thread_message_loops_.begin();
+           it != thread_message_loops_.end(); ++it) {
+        thread_message_loop_task_runners.push_back((*it)->task_runner());
+      }
+    }
+  }
+
+  if (thread_message_loop_task_runners.size()) {
+    for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
+      thread_message_loop_task_runners[i]->PostTask(
+          FROM_HERE,
+          Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
+    }
+    flush_task_runner_->PostDelayedTask(
+        FROM_HERE,
+        Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
+        TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
+    return;
+  }
+
+  FinishFlush(generation);
+}
+
+// Usually it runs on a different thread.
+void TraceLog::ConvertTraceEventsToTraceFormat(
+    scoped_ptr<TraceBuffer> logged_events,
+    const TraceLog::OutputCallback& flush_output_callback) {
+
+  if (flush_output_callback.is_null())
+    return;
+
+  // The callback need to be called at least once even if there is no events
+  // to let the caller know the completion of flush.
+  bool has_more_events = true;
+  do {
+    scoped_refptr<RefCountedString> json_events_str_ptr =
+        new RefCountedString();
+
+    while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) {
+      const TraceBufferChunk* chunk = logged_events->NextChunk();
+      has_more_events = chunk != NULL;
+      if (!chunk)
+        break;
+      for (size_t j = 0; j < chunk->size(); ++j) {
+        if (json_events_str_ptr->size())
+          json_events_str_ptr->data().append(",\n");
+        chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()));
+      }
+    }
+    flush_output_callback.Run(json_events_str_ptr, has_more_events);
+  } while (has_more_events);
+}
+
+void TraceLog::FinishFlush(int generation) {
+  scoped_ptr<TraceBuffer> previous_logged_events;
+  OutputCallback flush_output_callback;
+
+  if (!CheckGeneration(generation))
+    return;
+
+  {
+    AutoLock lock(lock_);
+
+    previous_logged_events.swap(logged_events_);
+    UseNextTraceBuffer();
+    thread_message_loops_.clear();
+
+    flush_task_runner_ = NULL;
+    flush_output_callback = flush_output_callback_;
+    flush_output_callback_.Reset();
+  }
+
+  if (use_worker_thread_ &&
+      WorkerPool::PostTask(
+          FROM_HERE,
+          Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+               Passed(&previous_logged_events),
+               flush_output_callback),
+          true)) {
+    return;
+  }
+
+  ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
+                                  flush_output_callback);
+}
+
+// Run in each thread holding a local event buffer.
+void TraceLog::FlushCurrentThread(int generation) {
+  {
+    AutoLock lock(lock_);
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
+      // This is late. The corresponding flush has finished.
+      return;
+    }
+  }
+
+  // This will flush the thread local buffer.
+  delete thread_local_event_buffer_.Get();
+
+  AutoLock lock(lock_);
+  if (!CheckGeneration(generation) || !flush_task_runner_ ||
+      thread_message_loops_.size())
+    return;
+
+  flush_task_runner_->PostTask(
+      FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
+}
+
+void TraceLog::OnFlushTimeout(int generation) {
+  {
+    AutoLock lock(lock_);
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
+      // Flush has finished before timeout.
+      return;
+    }
+
+    LOG(WARNING) <<
+        "The following threads haven't finished flush in time. "
+        "If this happens stably for some thread, please call "
+        "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from "
+        "the thread to avoid its trace events from being lost.";
+    for (hash_set<MessageLoop*>::const_iterator it =
+         thread_message_loops_.begin();
+         it != thread_message_loops_.end(); ++it) {
+      LOG(WARNING) << "Thread: " << (*it)->thread_name();
+    }
+  }
+  FinishFlush(generation);
+}
+
+void TraceLog::FlushButLeaveBufferIntact(
+    const TraceLog::OutputCallback& flush_output_callback) {
+  scoped_ptr<TraceBuffer> previous_logged_events;
+  {
+    AutoLock lock(lock_);
+    AddMetadataEventsWhileLocked();
+    if (thread_shared_chunk_) {
+      // Return the chunk to the main buffer to flush the sampling data.
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  thread_shared_chunk_.Pass());
+    }
+    previous_logged_events = logged_events_->CloneForIteration().Pass();
+  }  // release lock
+
+  ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
+                                  flush_output_callback);
+}
+
+void TraceLog::UseNextTraceBuffer() {
+  logged_events_.reset(CreateTraceBuffer());
+  subtle::NoBarrier_AtomicIncrement(&generation_, 1);
+  thread_shared_chunk_.reset();
+  thread_shared_chunk_index_ = 0;
+}
+
+TraceEventHandle TraceLog::AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned char flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now,
+                                               num_args, arg_names,
+                                               arg_types, arg_values,
+                                               convertable_values, flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const TimeTicks& timestamp,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned char flags) {
+  TraceEventHandle handle = { 0, 0, 0 };
+  if (!*category_group_enabled)
+    return handle;
+
+  // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+  // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+  // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+  if (thread_is_in_trace_event_.Get())
+    return handle;
+
+  AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+  DCHECK(name);
+  DCHECK(!timestamp.is_null());
+
+  if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
+    id = MangleEventId(id);
+
+  TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+  TimeTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
+      OffsetNow() : offset_event_timestamp;
+  TimeTicks thread_now = ThreadNow();
+
+  ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
+  // A ThreadLocalEventBuffer needs the message loop
+  // - to know when the thread exits;
+  // - to handle the final flush.
+  // For a thread without a message loop or the message loop may be blocked, the
+  // trace events will be added into the main buffer directly.
+  if (!thread_blocks_message_loop_.Get() && MessageLoop::current()) {
+    thread_local_event_buffer = thread_local_event_buffer_.Get();
+    if (thread_local_event_buffer &&
+        !CheckGeneration(thread_local_event_buffer->generation())) {
+      delete thread_local_event_buffer;
+      thread_local_event_buffer = NULL;
+    }
+    if (!thread_local_event_buffer) {
+      thread_local_event_buffer = new ThreadLocalEventBuffer(this);
+      thread_local_event_buffer_.Set(thread_local_event_buffer);
+    }
+  }
+
+  // Check and update the current thread name only if the event is for the
+  // current thread to avoid locks in most cases.
+  if (thread_id == static_cast<int>(PlatformThread::CurrentId())) {
+    const char* new_name = ThreadIdNameManager::GetInstance()->
+        GetName(thread_id);
+    // Check if the thread name has been set or changed since the previous
+    // call (if any), but don't bother if the new name is empty. Note this will
+    // not detect a thread name change within the same char* buffer address: we
+    // favor common case performance over corner case correctness.
+    if (new_name != g_current_thread_name.Get().Get() &&
+        new_name && *new_name) {
+      g_current_thread_name.Get().Set(new_name);
+
+      AutoLock thread_info_lock(thread_info_lock_);
+
+      hash_map<int, std::string>::iterator existing_name =
+          thread_names_.find(thread_id);
+      if (existing_name == thread_names_.end()) {
+        // This is a new thread id, and a new name.
+        thread_names_[thread_id] = new_name;
+      } else {
+        // This is a thread id that we've seen before, but potentially with a
+        // new name.
+        std::vector<StringPiece> existing_names;
+        Tokenize(existing_name->second, ",", &existing_names);
+        bool found = std::find(existing_names.begin(),
+                               existing_names.end(),
+                               new_name) != existing_names.end();
+        if (!found) {
+          if (existing_names.size())
+            existing_name->second.push_back(',');
+          existing_name->second.append(new_name);
+        }
+      }
+    }
+  }
+
+#if defined(OS_WIN)
+  // This is done sooner rather than later, to avoid creating the event and
+  // acquiring the lock, which is not needed for ETW as it's already threadsafe.
+  if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
+    TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
+                                  num_args, arg_names, arg_types, arg_values,
+                                  convertable_values);
+#endif  // OS_WIN
+
+  std::string console_message;
+  if (*category_group_enabled &
+      (ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
+    OptionalAutoLock lock(&lock_);
+
+    TraceEvent* trace_event = NULL;
+    if (thread_local_event_buffer) {
+      trace_event = thread_local_event_buffer->AddTraceEvent(&handle);
+    } else {
+      lock.EnsureAcquired();
+      trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true);
+    }
+
+    if (trace_event) {
+      trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
+                              phase, category_group_enabled, name, id,
+                              num_args, arg_names, arg_types, arg_values,
+                              convertable_values, flags);
+
+#if defined(OS_ANDROID)
+      trace_event->SendToATrace();
+#endif
+    }
+
+    if (trace_options() & kInternalEchoToConsole) {
+      console_message = EventToConsoleMessage(
+          phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+          timestamp, trace_event);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (reinterpret_cast<const unsigned char*>(subtle::NoBarrier_Load(
+      &watch_category_)) == category_group_enabled) {
+    bool event_name_matches;
+    WatchEventCallback watch_event_callback_copy;
+    {
+      AutoLock lock(lock_);
+      event_name_matches = watch_event_name_ == name;
+      watch_event_callback_copy = watch_event_callback_;
+    }
+    if (event_name_matches) {
+      if (!watch_event_callback_copy.is_null())
+        watch_event_callback_copy.Run();
+    }
+  }
+
+  if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+    EventCallback event_callback = reinterpret_cast<EventCallback>(
+        subtle::NoBarrier_Load(&event_callback_));
+    if (event_callback) {
+      event_callback(offset_event_timestamp,
+                     phase == TRACE_EVENT_PHASE_COMPLETE ?
+                         TRACE_EVENT_PHASE_BEGIN : phase,
+                     category_group_enabled, name, id,
+                     num_args, arg_names, arg_types, arg_values,
+                     flags);
+    }
+  }
+
+  if (thread_local_event_buffer)
+    thread_local_event_buffer->ReportOverhead(now, thread_now);
+
+  return handle;
+}
+
+// May be called when a COMPELETE event ends and the unfinished event has been
+// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
+std::string TraceLog::EventToConsoleMessage(unsigned char phase,
+                                            const TimeTicks& timestamp,
+                                            TraceEvent* trace_event) {
+  AutoLock thread_info_lock(thread_info_lock_);
+
+  // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
+  // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
+  DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
+
+  TimeDelta duration;
+  int thread_id = trace_event ?
+      trace_event->thread_id() : PlatformThread::CurrentId();
+  if (phase == TRACE_EVENT_PHASE_END) {
+    duration = timestamp - thread_event_start_times_[thread_id].top();
+    thread_event_start_times_[thread_id].pop();
+  }
+
+  std::string thread_name = thread_names_[thread_id];
+  if (thread_colors_.find(thread_name) == thread_colors_.end())
+    thread_colors_[thread_name] = (thread_colors_.size() % 6) + 1;
+
+  std::ostringstream log;
+  log << base::StringPrintf("%s: \x1b[0;3%dm",
+                            thread_name.c_str(),
+                            thread_colors_[thread_name]);
+
+  size_t depth = 0;
+  if (thread_event_start_times_.find(thread_id) !=
+      thread_event_start_times_.end())
+    depth = thread_event_start_times_[thread_id].size();
+
+  for (size_t i = 0; i < depth; ++i)
+    log << "| ";
+
+  if (trace_event)
+    trace_event->AppendPrettyPrinted(&log);
+  if (phase == TRACE_EVENT_PHASE_END)
+    log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
+
+  log << "\x1b[0;m";
+
+  if (phase == TRACE_EVENT_PHASE_BEGIN)
+    thread_event_start_times_[thread_id].push(timestamp);
+
+  return log.str();
+}
+
+void TraceLog::AddTraceEventEtw(char phase,
+                                const char* name,
+                                const void* id,
+                                const char* extra) {
+#if defined(OS_WIN)
+  TraceEventETWProvider::Trace(name, phase, id, extra);
+#endif
+  INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
+                           TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
+}
+
+void TraceLog::AddTraceEventEtw(char phase,
+                                const char* name,
+                                const void* id,
+                                const std::string& extra) {
+#if defined(OS_WIN)
+  TraceEventETWProvider::Trace(name, phase, id, extra);
+#endif
+  INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
+                           TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
+}
+
+void TraceLog::UpdateTraceEventDuration(
+    const unsigned char* category_group_enabled,
+    const char* name,
+    TraceEventHandle handle) {
+  // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+  // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+  // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+  if (thread_is_in_trace_event_.Get())
+    return;
+
+  AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+  TimeTicks thread_now = ThreadNow();
+  TimeTicks now = OffsetNow();
+
+  std::string console_message;
+  if (*category_group_enabled & ENABLED_FOR_RECORDING) {
+    OptionalAutoLock lock(&lock_);
+
+    TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
+    if (trace_event) {
+      DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
+      trace_event->UpdateDuration(now, thread_now);
+#if defined(OS_ANDROID)
+      trace_event->SendToATrace();
+#endif
+    }
+
+    if (trace_options() & kInternalEchoToConsole) {
+      console_message = EventToConsoleMessage(TRACE_EVENT_PHASE_END,
+                                              now, trace_event);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+    EventCallback event_callback = reinterpret_cast<EventCallback>(
+        subtle::NoBarrier_Load(&event_callback_));
+    if (event_callback) {
+      event_callback(now, TRACE_EVENT_PHASE_END, category_group_enabled, name,
+                     trace_event_internal::kNoEventId, 0, NULL, NULL, NULL,
+                     TRACE_EVENT_FLAG_NONE);
+    }
+  }
+}
+
+void TraceLog::SetWatchEvent(const std::string& category_name,
+                             const std::string& event_name,
+                             const WatchEventCallback& callback) {
+  const unsigned char* category = GetCategoryGroupEnabled(
+      category_name.c_str());
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&watch_category_,
+                          reinterpret_cast<subtle::AtomicWord>(category));
+  watch_event_name_ = event_name;
+  watch_event_callback_ = callback;
+}
+
+void TraceLog::CancelWatchEvent() {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&watch_category_, 0);
+  watch_event_name_ = "";
+  watch_event_callback_.Reset();
+}
+
+uint64 TraceLog::MangleEventId(uint64 id) {
+  return id ^ process_id_hash_;
+}
+
+void TraceLog::AddMetadataEventsWhileLocked() {
+  lock_.AssertAcquired();
+
+#if !defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                          0,
+                          "num_cpus", "number",
+                          base::SysInfo::NumberOfProcessors());
+#endif
+
+
+  int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  if (process_sort_index_ != 0) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "process_sort_index", "sort_index",
+                            process_sort_index_);
+  }
+
+  if (process_name_.size()) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "process_name", "name",
+                            process_name_);
+  }
+
+  if (process_labels_.size() > 0) {
+    std::vector<std::string> labels;
+    for(base::hash_map<int, std::string>::iterator it = process_labels_.begin();
+        it != process_labels_.end();
+        it++) {
+      labels.push_back(it->second);
+    }
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "process_labels", "labels",
+                            JoinString(labels, ','));
+  }
+
+  // Thread sort indices.
+  for(hash_map<int, int>::iterator it = thread_sort_indices_.begin();
+      it != thread_sort_indices_.end();
+      it++) {
+    if (it->second == 0)
+      continue;
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            it->first,
+                            "thread_sort_index", "sort_index",
+                            it->second);
+  }
+
+  // Thread names.
+  AutoLock thread_info_lock(thread_info_lock_);
+  for(hash_map<int, std::string>::iterator it = thread_names_.begin();
+      it != thread_names_.end();
+      it++) {
+    if (it->second.empty())
+      continue;
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            it->first,
+                            "thread_name", "name",
+                            it->second);
+  }
+
+  // If buffer is full, add a metadata record to report this.
+  if (!buffer_limit_reached_timestamp_.is_null()) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "trace_buffer_overflowed",
+                            "overflowed_at_ts",
+                            buffer_limit_reached_timestamp_);
+  }
+}
+
+void TraceLog::WaitSamplingEventForTesting() {
+  if (!sampling_thread_)
+    return;
+  sampling_thread_->WaitSamplingEventForTesting();
+}
+
+void TraceLog::DeleteForTesting() {
+  DeleteTraceLogForTesting::Delete();
+}
+
+TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
+  return GetEventByHandleInternal(handle, NULL);
+}
+
+TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
+                                               OptionalAutoLock* lock) {
+  if (!handle.chunk_seq)
+    return NULL;
+
+  if (thread_local_event_buffer_.Get()) {
+    TraceEvent* trace_event =
+        thread_local_event_buffer_.Get()->GetEventByHandle(handle);
+    if (trace_event)
+      return trace_event;
+  }
+
+  // The event has been out-of-control of the thread local buffer.
+  // Try to get the event from the main buffer with a lock.
+  if (lock)
+    lock->EnsureAcquired();
+
+  if (thread_shared_chunk_ &&
+      handle.chunk_index == thread_shared_chunk_index_) {
+    return handle.chunk_seq == thread_shared_chunk_->seq() ?
+        thread_shared_chunk_->GetEventAt(handle.event_index) : NULL;
+  }
+
+  return logged_events_->GetEventByHandle(handle);
+}
+
+void TraceLog::SetProcessID(int process_id) {
+  process_id_ = process_id;
+  // Create a FNV hash from the process ID for XORing.
+  // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
+  unsigned long long offset_basis = 14695981039346656037ull;
+  unsigned long long fnv_prime = 1099511628211ull;
+  unsigned long long pid = static_cast<unsigned long long>(process_id_);
+  process_id_hash_ = (offset_basis ^ pid) * fnv_prime;
+}
+
+void TraceLog::SetProcessSortIndex(int sort_index) {
+  AutoLock lock(lock_);
+  process_sort_index_ = sort_index;
+}
+
+void TraceLog::SetProcessName(const std::string& process_name) {
+  AutoLock lock(lock_);
+  process_name_ = process_name;
+}
+
+void TraceLog::UpdateProcessLabel(
+    int label_id, const std::string& current_label) {
+  if(!current_label.length())
+    return RemoveProcessLabel(label_id);
+
+  AutoLock lock(lock_);
+  process_labels_[label_id] = current_label;
+}
+
+void TraceLog::RemoveProcessLabel(int label_id) {
+  AutoLock lock(lock_);
+  base::hash_map<int, std::string>::iterator it = process_labels_.find(
+      label_id);
+  if (it == process_labels_.end())
+    return;
+
+  process_labels_.erase(it);
+}
+
+void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) {
+  AutoLock lock(lock_);
+  thread_sort_indices_[static_cast<int>(thread_id)] = sort_index;
+}
+
+void TraceLog::SetTimeOffset(TimeDelta offset) {
+  time_offset_ = offset;
+}
+
+size_t TraceLog::GetObserverCountForTest() const {
+  return enabled_state_observer_list_.size();
+}
+
+void TraceLog::SetCurrentThreadBlocksMessageLoop() {
+  thread_blocks_message_loop_.Set(true);
+  if (thread_local_event_buffer_.Get()) {
+    // This will flush the thread local buffer.
+    delete thread_local_event_buffer_.Get();
+  }
+}
+
+bool CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+    const std::string& str) {
+  return  str.empty() ||
+          str.at(0) == ' ' ||
+          str.at(str.length() - 1) == ' ';
+}
+
+CategoryFilter::CategoryFilter(const std::string& filter_string) {
+  if (!filter_string.empty())
+    Initialize(filter_string);
+  else
+    Initialize(CategoryFilter::kDefaultCategoryFilterString);
+}
+
+CategoryFilter::CategoryFilter() {
+    Initialize(CategoryFilter::kDefaultCategoryFilterString);
+}
+
+CategoryFilter::CategoryFilter(const CategoryFilter& cf)
+    : included_(cf.included_),
+      disabled_(cf.disabled_),
+      excluded_(cf.excluded_),
+      delays_(cf.delays_) {
+}
+
+CategoryFilter::~CategoryFilter() {
+}
+
+CategoryFilter& CategoryFilter::operator=(const CategoryFilter& rhs) {
+  if (this == &rhs)
+    return *this;
+
+  included_ = rhs.included_;
+  disabled_ = rhs.disabled_;
+  excluded_ = rhs.excluded_;
+  delays_ = rhs.delays_;
+  return *this;
+}
+
+void CategoryFilter::Initialize(const std::string& filter_string) {
+  // Tokenize list of categories, delimited by ','.
+  StringTokenizer tokens(filter_string, ",");
+  // Add each token to the appropriate list (included_,excluded_).
+  while (tokens.GetNext()) {
+    std::string category = tokens.token();
+    // Ignore empty categories.
+    if (category.empty())
+      continue;
+    // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
+    if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 &&
+        category.at(category.size() - 1) == ')') {
+      category = category.substr(
+          strlen(kSyntheticDelayCategoryFilterPrefix),
+          category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
+      size_t name_length = category.find(';');
+      if (name_length != std::string::npos && name_length > 0 &&
+          name_length != category.size() - 1) {
+        delays_.push_back(category);
+      }
+    } else if (category.at(0) == '-') {
+      // Excluded categories start with '-'.
+      // Remove '-' from category string.
+      category = category.substr(1);
+      excluded_.push_back(category);
+    } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
+                                TRACE_DISABLED_BY_DEFAULT("")) == 0) {
+      disabled_.push_back(category);
+    } else {
+      included_.push_back(category);
+    }
+  }
+}
+
+void CategoryFilter::WriteString(const StringList& values,
+                                 std::string* out,
+                                 bool included) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (StringList::const_iterator ci = values.begin();
+       ci != values.end(); ++ci) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str());
+    ++token_cnt;
+  }
+}
+
+void CategoryFilter::WriteString(const StringList& delays,
+                                 std::string* out) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (StringList::const_iterator ci = delays.begin();
+       ci != delays.end(); ++ci) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
+                  ci->c_str());
+    ++token_cnt;
+  }
+}
+
+std::string CategoryFilter::ToString() const {
+  std::string filter_string;
+  WriteString(included_, &filter_string, true);
+  WriteString(disabled_, &filter_string, true);
+  WriteString(excluded_, &filter_string, false);
+  WriteString(delays_, &filter_string);
+  return filter_string;
+}
+
+bool CategoryFilter::IsCategoryGroupEnabled(
+    const char* category_group_name) const {
+  // TraceLog should call this method only as  part of enabling/disabling
+  // categories.
+
+  bool had_enabled_by_default = false;
+  DCHECK(category_group_name);
+  CStringTokenizer category_group_tokens(
+      category_group_name, category_group_name + strlen(category_group_name),
+      ",");
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    // Don't allow empty tokens, nor tokens with leading or trailing space.
+    DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+               category_group_token))
+        << "Disallowed category string";
+    if (IsCategoryEnabled(category_group_token.c_str())) {
+      return true;
+    }
+    if (!MatchPattern(category_group_token.c_str(),
+                      TRACE_DISABLED_BY_DEFAULT("*")))
+      had_enabled_by_default = true;
+  }
+  // Do a second pass to check for explicitly disabled categories
+  // (those explicitly enabled have priority due to first pass).
+  category_group_tokens.Reset();
+  bool category_group_disabled = false;
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    for (StringList::const_iterator ci = excluded_.begin();
+         ci != excluded_.end(); ++ci) {
+      if (MatchPattern(category_group_token.c_str(), ci->c_str())) {
+        // Current token of category_group_name is present in excluded_list.
+        // Flag the exclusion and proceed further to check if any of the
+        // remaining categories of category_group_name is not present in the
+        // excluded_ list.
+        category_group_disabled = true;
+        break;
+      }
+      // One of the category of category_group_name is not present in
+      // excluded_ list. So, it has to be included_ list. Enable the
+      // category_group_name for recording.
+      category_group_disabled = false;
+    }
+    // One of the categories present in category_group_name is not present in
+    // excluded_ list. Implies this category_group_name group can be enabled
+    // for recording, since one of its groups is enabled for recording.
+    if (!category_group_disabled)
+      break;
+  }
+  // If the category group is not excluded, and there are no included patterns
+  // we consider this category group enabled, as long as it had categories
+  // other than disabled-by-default.
+  return !category_group_disabled &&
+         included_.empty() && had_enabled_by_default;
+}
+
+bool CategoryFilter::IsCategoryEnabled(const char* category_name) const {
+  StringList::const_iterator ci;
+
+  // Check the disabled- filters and the disabled-* wildcard first so that a
+  // "*" filter does not include the disabled.
+  for (ci = disabled_.begin(); ci != disabled_.end(); ++ci) {
+    if (MatchPattern(category_name, ci->c_str()))
+      return true;
+  }
+
+  if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
+    return false;
+
+  for (ci = included_.begin(); ci != included_.end(); ++ci) {
+    if (MatchPattern(category_name, ci->c_str()))
+      return true;
+  }
+
+  return false;
+}
+
+bool CategoryFilter::HasIncludedPatterns() const {
+  return !included_.empty();
+}
+
+void CategoryFilter::Merge(const CategoryFilter& nested_filter) {
+  // Keep included patterns only if both filters have an included entry.
+  // Otherwise, one of the filter was specifying "*" and we want to honour the
+  // broadest filter.
+  if (HasIncludedPatterns() && nested_filter.HasIncludedPatterns()) {
+    included_.insert(included_.end(),
+                     nested_filter.included_.begin(),
+                     nested_filter.included_.end());
+  } else {
+    included_.clear();
+  }
+
+  disabled_.insert(disabled_.end(),
+                   nested_filter.disabled_.begin(),
+                   nested_filter.disabled_.end());
+  excluded_.insert(excluded_.end(),
+                   nested_filter.excluded_.begin(),
+                   nested_filter.excluded_.end());
+  delays_.insert(delays_.end(),
+                 nested_filter.delays_.begin(),
+                 nested_filter.delays_.end());
+}
+
+void CategoryFilter::Clear() {
+  included_.clear();
+  disabled_.clear();
+  excluded_.clear();
+}
+
+const CategoryFilter::StringList&
+    CategoryFilter::GetSyntheticDelayValues() const {
+  return delays_;
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace trace_event_internal {
+
+ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
+    const char* category_group, const char* name) {
+  // The single atom works because for now the category_group can only be "gpu".
+  DCHECK_EQ(strcmp(category_group, "gpu"), 0);
+  static TRACE_EVENT_API_ATOMIC_WORD atomic = 0;
+  INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(
+      category_group, atomic, category_group_enabled_);
+  name_ = name;
+  if (*category_group_enabled_) {
+    event_handle_ =
+        TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+            TRACE_EVENT_PHASE_COMPLETE, category_group_enabled_, name,
+            trace_event_internal::kNoEventId,
+            static_cast<int>(base::PlatformThread::CurrentId()),
+            base::TimeTicks::NowFromSystemTraceTime(),
+            0, NULL, NULL, NULL, NULL, TRACE_EVENT_FLAG_NONE);
+  }
+}
+
+ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() {
+  if (*category_group_enabled_) {
+    TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_,
+                                                name_, event_handle_);
+  }
+}
+
+}  // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
new file mode 100644
index 0000000..50d33ca
--- /dev/null
+++ b/base/trace_event/trace_event_impl.h
@@ -0,0 +1,823 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
+
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_local.h"
+
+// Older style trace macros with explicit id and extra data
+// Only these macros result in publishing data to ETW as currently implemented.
+// TODO(georgesak): Update/replace these with new ETW macros.
+#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
+    base::trace_event::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_BEGIN, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+#define TRACE_EVENT_END_ETW(name, id, extra) \
+    base::trace_event::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_END, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+#define TRACE_EVENT_INSTANT_ETW(name, id, extra) \
+    base::trace_event::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_INSTANT, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+template <typename Type>
+struct DefaultSingletonTraits;
+
+namespace base {
+
+class WaitableEvent;
+class MessageLoop;
+
+namespace trace_event {
+
+// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
+// class must implement this interface.
+class BASE_EXPORT ConvertableToTraceFormat
+    : public RefCounted<ConvertableToTraceFormat> {
+ public:
+  // Append the class info to the provided |out| string. The appended
+  // data must be a valid JSON object. Strings must be properly quoted, and
+  // escaped. There is no processing applied to the content after it is
+  // appended.
+  virtual void AppendAsTraceFormat(std::string* out) const = 0;
+
+  std::string ToString() const {
+    std::string result;
+    AppendAsTraceFormat(&result);
+    return result;
+  }
+
+ protected:
+  virtual ~ConvertableToTraceFormat() {}
+
+ private:
+  friend class RefCounted<ConvertableToTraceFormat>;
+};
+
+struct TraceEventHandle {
+  uint32 chunk_seq;
+  uint16 chunk_index;
+  uint16 event_index;
+};
+
+const int kTraceMaxNumArgs = 2;
+
+class BASE_EXPORT TraceEvent {
+ public:
+  union TraceValue {
+    bool as_bool;
+    unsigned long long as_uint;
+    long long as_int;
+    double as_double;
+    const void* as_pointer;
+    const char* as_string;
+  };
+
+  TraceEvent();
+  ~TraceEvent();
+
+  // We don't need to copy TraceEvent except when TraceEventBuffer is cloned.
+  // Use explicit copy method to avoid accidentally misuse of copy.
+  void CopyFrom(const TraceEvent& other);
+
+  void Initialize(
+      int thread_id,
+      TimeTicks timestamp,
+      TimeTicks thread_timestamp,
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned char flags);
+
+  void Reset();
+
+  void UpdateDuration(const TimeTicks& now, const TimeTicks& thread_now);
+
+  // Serialize event data to JSON
+  void AppendAsJSON(std::string* out) const;
+  void AppendPrettyPrinted(std::ostringstream* out) const;
+
+  static void AppendValueAsJSON(unsigned char type,
+                                TraceValue value,
+                                std::string* out);
+
+  TimeTicks timestamp() const { return timestamp_; }
+  TimeTicks thread_timestamp() const { return thread_timestamp_; }
+  char phase() const { return phase_; }
+  int thread_id() const { return thread_id_; }
+  TimeDelta duration() const { return duration_; }
+  TimeDelta thread_duration() const { return thread_duration_; }
+  unsigned long long id() const { return id_; }
+  unsigned char flags() const { return flags_; }
+
+  // Exposed for unittesting:
+
+  const base::RefCountedString* parameter_copy_storage() const {
+    return parameter_copy_storage_.get();
+  }
+
+  const unsigned char* category_group_enabled() const {
+    return category_group_enabled_;
+  }
+
+  const char* name() const { return name_; }
+
+#if defined(OS_ANDROID)
+  void SendToATrace();
+#endif
+
+ private:
+  // Note: these are ordered by size (largest first) for optimal packing.
+  TimeTicks timestamp_;
+  TimeTicks thread_timestamp_;
+  TimeDelta duration_;
+  TimeDelta thread_duration_;
+  // id_ can be used to store phase-specific data.
+  unsigned long long id_;
+  TraceValue arg_values_[kTraceMaxNumArgs];
+  const char* arg_names_[kTraceMaxNumArgs];
+  scoped_refptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
+  const unsigned char* category_group_enabled_;
+  const char* name_;
+  scoped_refptr<base::RefCountedString> parameter_copy_storage_;
+  int thread_id_;
+  char phase_;
+  unsigned char flags_;
+  unsigned char arg_types_[kTraceMaxNumArgs];
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEvent);
+};
+
+// TraceBufferChunk is the basic unit of TraceBuffer.
+class BASE_EXPORT TraceBufferChunk {
+ public:
+  explicit TraceBufferChunk(uint32 seq)
+      : next_free_(0),
+        seq_(seq) {
+  }
+
+  void Reset(uint32 new_seq);
+  TraceEvent* AddTraceEvent(size_t* event_index);
+  bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
+
+  uint32 seq() const { return seq_; }
+  size_t capacity() const { return kTraceBufferChunkSize; }
+  size_t size() const { return next_free_; }
+
+  TraceEvent* GetEventAt(size_t index) {
+    DCHECK(index < size());
+    return &chunk_[index];
+  }
+  const TraceEvent* GetEventAt(size_t index) const {
+    DCHECK(index < size());
+    return &chunk_[index];
+  }
+
+  scoped_ptr<TraceBufferChunk> Clone() const;
+
+  static const size_t kTraceBufferChunkSize = 64;
+
+ private:
+  size_t next_free_;
+  TraceEvent chunk_[kTraceBufferChunkSize];
+  uint32 seq_;
+};
+
+// TraceBuffer holds the events as they are collected.
+class BASE_EXPORT TraceBuffer {
+ public:
+  virtual ~TraceBuffer() {}
+
+  virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t *index) = 0;
+  virtual void ReturnChunk(size_t index,
+                           scoped_ptr<TraceBufferChunk> chunk) = 0;
+
+  virtual bool IsFull() const = 0;
+  virtual size_t Size() const = 0;
+  virtual size_t Capacity() const = 0;
+  virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) = 0;
+
+  // For iteration. Each TraceBuffer can only be iterated once.
+  virtual const TraceBufferChunk* NextChunk() = 0;
+
+  virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
+};
+
+// 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 CategoryFilter {
+ public:
+  typedef std::vector<std::string> StringList;
+
+  // The default category filter, used when none is provided.
+  // Allows all categories through, except if they end in the suffix 'Debug' or
+  // 'Test'.
+  static const char kDefaultCategoryFilterString[];
+
+  // |filter_string| is a comma-delimited list of category wildcards.
+  // A category can have an optional '-' prefix to make it an excluded category.
+  // All the same rules apply above, so for example, having both included and
+  // excluded categories in the same list would not be supported.
+  //
+  // Example: CategoryFilter"test_MyTest*");
+  // Example: CategoryFilter("test_MyTest*,test_OtherStuff");
+  // Example: CategoryFilter("-excluded_category1,-excluded_category2");
+  // Example: CategoryFilter("-*,webkit"); would disable everything but webkit.
+  // Example: CategoryFilter("-webkit"); would enable everything but webkit.
+  //
+  // Category filters can also be used to configure synthetic delays.
+  //
+  // Example: CategoryFilter("DELAY(gpu.PresentingFrame;16)"); would make swap
+  //          buffers always take at least 16 ms.
+  // Example: CategoryFilter("DELAY(gpu.PresentingFrame;16;oneshot)"); would
+  //          make swap buffers take at least 16 ms the first time it is
+  //          called.
+  // Example: CategoryFilter("DELAY(gpu.PresentingFrame;16;alternating)");
+  //          would make swap buffers take at least 16 ms every other time it
+  //          is called.
+  explicit CategoryFilter(const std::string& filter_string);
+
+  CategoryFilter();
+
+  CategoryFilter(const CategoryFilter& cf);
+
+  ~CategoryFilter();
+
+  CategoryFilter& operator=(const CategoryFilter& rhs);
+
+  // Writes the string representation of the CategoryFilter. This is a comma
+  // separated string, similar in nature to the one used to determine
+  // enabled/disabled category patterns, except here there is an arbitrary
+  // order, included categories go first, then excluded categories. Excluded
+  // categories are distinguished from included categories by the prefix '-'.
+  std::string ToString() const;
+
+  // Returns true if at least one category in the list is enabled by this
+  // category filter.
+  bool IsCategoryGroupEnabled(const char* category_group) const;
+
+  // Return a list of the synthetic delays specified in this category filter.
+  const StringList& GetSyntheticDelayValues() const;
+
+  // Merges nested_filter with the current CategoryFilter
+  void Merge(const CategoryFilter& nested_filter);
+
+  // Clears both included/excluded pattern lists. This would be equivalent to
+  // creating a CategoryFilter with an empty string, through the constructor.
+  // i.e: CategoryFilter().
+  //
+  // When using an empty filter, all categories are considered included as we
+  // are not excluding anything.
+  void Clear();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, CategoryFilter);
+
+  // Returns true if category is enable according to this filter.
+  bool IsCategoryEnabled(const char* category_name) const;
+
+  static bool IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      const std::string& str);
+
+  void Initialize(const std::string& filter_string);
+  void WriteString(const StringList& values,
+                   std::string* out,
+                   bool included) const;
+  void WriteString(const StringList& delays, std::string* out) const;
+  bool HasIncludedPatterns() const;
+
+  StringList included_;
+  StringList disabled_;
+  StringList excluded_;
+  StringList delays_;
+};
+
+class TraceSamplingThread;
+
+// Options determines how the trace buffer stores data.
+enum TraceRecordMode {
+  // Record until the trace buffer is full.
+  RECORD_UNTIL_FULL,
+
+  // Record until the user ends the trace. The trace buffer is a fixed size
+  // and we use it as a ring buffer during recording.
+  RECORD_CONTINUOUSLY,
+
+  // Echo to console. Events are discarded.
+  ECHO_TO_CONSOLE,
+
+  // Record until the trace buffer is full, but with a huge buffer size.
+  RECORD_AS_MUCH_AS_POSSIBLE
+};
+
+struct BASE_EXPORT TraceOptions {
+  TraceOptions()
+      : record_mode(RECORD_UNTIL_FULL),
+        enable_sampling(false),
+        enable_systrace(false) {}
+
+  explicit TraceOptions(TraceRecordMode record_mode)
+      : record_mode(record_mode),
+        enable_sampling(false),
+        enable_systrace(false) {}
+
+  // |options_string| is a comma-delimited list of trace options.
+  // Possible options are: "record-until-full", "record-continuously",
+  // "trace-to-console", "enable-sampling" and "enable-systrace".
+  // The first 3 options are trace recoding modes and hence
+  // mutually exclusive. If more than one trace recording modes appear in the
+  // options_string, the last one takes precedence. If none of the trace
+  // recording mode is specified, recording mode is RECORD_UNTIL_FULL.
+  //
+  // The trace option will first be reset to the default option
+  // (record_mode set to RECORD_UNTIL_FULL, enable_sampling and enable_systrace
+  // set to false) before options parsed from |options_string| are applied on
+  // it.
+  // If |options_string| is invalid, the final state of trace_options is
+  // undefined.
+  //
+  // Example: trace_options.SetFromString("record-until-full")
+  // Example: trace_options.SetFromString(
+  //              "record-continuously, enable-sampling")
+  // Example: trace_options.SetFromString("record-until-full, trace-to-console")
+  // will set ECHO_TO_CONSOLE as the recording mode.
+  //
+  // Returns true on success.
+  bool SetFromString(const std::string& options_string);
+
+  std::string ToString() const;
+
+  TraceRecordMode record_mode;
+  bool enable_sampling;
+  bool enable_systrace;
+};
+
+struct BASE_EXPORT TraceLogStatus {
+  TraceLogStatus();
+  ~TraceLogStatus();
+  size_t event_capacity;
+  size_t event_count;
+};
+
+class BASE_EXPORT TraceLog {
+ public:
+  enum Mode {
+    DISABLED = 0,
+    RECORDING_MODE,
+    MONITORING_MODE,
+  };
+
+  // The pointer returned from GetCategoryGroupEnabledInternal() points to a
+  // value with zero or more of the following bits. Used in this class only.
+  // The TRACE_EVENT macros should only use the value as a bool.
+  // These values must be in sync with macro values in TraceEvent.h in Blink.
+  enum CategoryGroupEnabledFlags {
+    // Category group enabled for the recording mode.
+    ENABLED_FOR_RECORDING = 1 << 0,
+    // Category group enabled for the monitoring mode.
+    ENABLED_FOR_MONITORING = 1 << 1,
+    // Category group enabled by SetEventCallbackEnabled().
+    ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+    // Category group enabled to export events to ETW.
+    ENABLED_FOR_ETW_EXPORT = 1 << 3
+  };
+
+  static TraceLog* GetInstance();
+
+  // Get set of known category groups. This can change as new code paths are
+  // reached. The known category groups are inserted into |category_groups|.
+  void GetKnownCategoryGroups(std::vector<std::string>* category_groups);
+
+  // Retrieves a copy (for thread-safety) of the current CategoryFilter.
+  CategoryFilter GetCurrentCategoryFilter();
+
+  // Retrieves a copy (for thread-safety) of the current TraceOptions.
+  TraceOptions GetCurrentTraceOptions() const;
+
+  // Enables normal tracing (recording trace events in the trace buffer).
+  // See CategoryFilter comments for details on how to control what categories
+  // will be traced. If tracing has already been enabled, |category_filter| will
+  // be merged into the current category filter.
+  void SetEnabled(const CategoryFilter& category_filter,
+                  Mode mode, const TraceOptions& options);
+
+  // Disables normal tracing for all categories.
+  void SetDisabled();
+
+  bool IsEnabled() { return mode_ != DISABLED; }
+
+  // The number of times we have begun recording traces. If tracing is off,
+  // returns -1. If tracing is on, then it returns the number of times we have
+  // recorded a trace. By watching for this number to increment, you can
+  // passively discover when a new trace has begun. This is then used to
+  // implement the TRACE_EVENT_IS_NEW_TRACE() primitive.
+  int GetNumTracesRecorded();
+
+#if defined(OS_ANDROID)
+  void StartATrace();
+  void StopATrace();
+  void AddClockSyncMetadataEvent();
+#endif
+
+  // Enabled state listeners give a callback when tracing is enabled or
+  // disabled. This can be used to tie into other library's tracing systems
+  // on-demand.
+  class BASE_EXPORT EnabledStateObserver {
+   public:
+    // Called just after the tracing system becomes enabled, outside of the
+    // |lock_|. TraceLog::IsEnabled() is true at this point.
+    virtual void OnTraceLogEnabled() = 0;
+
+    // Called just after the tracing system disables, outside of the |lock_|.
+    // TraceLog::IsEnabled() is false at this point.
+    virtual void OnTraceLogDisabled() = 0;
+  };
+  void AddEnabledStateObserver(EnabledStateObserver* listener);
+  void RemoveEnabledStateObserver(EnabledStateObserver* listener);
+  bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
+
+  TraceLogStatus GetStatus() const;
+  bool BufferIsFull() const;
+
+  // Not using base::Callback because of its limited by 7 parameters.
+  // Also, using primitive type allows directly passing callback from WebCore.
+  // WARNING: It is possible for the previously set callback to be called
+  // after a call to SetEventCallbackEnabled() that replaces or a call to
+  // SetEventCallbackDisabled() that disables the callback.
+  // This callback may be invoked on any thread.
+  // For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
+  // of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
+  // interface simple.
+  typedef void (*EventCallback)(TimeTicks timestamp,
+                                char phase,
+                                const unsigned char* category_group_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                int num_args,
+                                const char* const arg_names[],
+                                const unsigned char arg_types[],
+                                const unsigned long long arg_values[],
+                                unsigned char flags);
+
+  // Enable tracing for EventCallback.
+  void SetEventCallbackEnabled(const CategoryFilter& category_filter,
+                               EventCallback cb);
+  void SetEventCallbackDisabled();
+
+  // Flush all collected events to the given output callback. The callback will
+  // be called one or more times either synchronously or asynchronously from
+  // the current thread with IPC-bite-size chunks. The string format is
+  // undefined. Use TraceResultBuffer to convert one or more trace strings to
+  // JSON. The callback can be null if the caller doesn't want any data.
+  // Due to the implementation of thread-local buffers, flush can't be
+  // done when tracing is enabled. If called when tracing is enabled, the
+  // callback will be called directly with (empty_string, false) to indicate
+  // the end of this unsuccessful flush. Flush does the serialization
+  // on the same thread if the caller doesn't set use_worker_thread explicitly.
+  typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
+                              bool has_more_events)> OutputCallback;
+  void Flush(const OutputCallback& cb, bool use_worker_thread = false);
+  void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // The name parameter is a category group for example:
+  // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent")
+  static const unsigned char* GetCategoryGroupEnabled(const char* name);
+  static const char* GetCategoryGroupName(
+      const unsigned char* category_group_enabled);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied
+  // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above.
+  TraceEventHandle AddTraceEvent(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned char flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int thread_id,
+      const TimeTicks& timestamp,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned char flags);
+  static void AddTraceEventEtw(char phase,
+                               const char* category_group,
+                               const void* id,
+                               const char* extra);
+  static void AddTraceEventEtw(char phase,
+                               const char* category_group,
+                               const void* id,
+                               const std::string& extra);
+
+  void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
+                                const char* name,
+                                TraceEventHandle handle);
+
+  // For every matching event, the callback will be called.
+  typedef base::Callback<void()> WatchEventCallback;
+  void SetWatchEvent(const std::string& category_name,
+                     const std::string& event_name,
+                     const WatchEventCallback& callback);
+  // Cancel the watch event. If tracing is enabled, this may race with the
+  // watch event notification firing.
+  void CancelWatchEvent();
+
+  int process_id() const { return process_id_; }
+
+  uint64 MangleEventId(uint64 id);
+
+  // Exposed for unittesting:
+
+  void WaitSamplingEventForTesting();
+
+  // Allows deleting our singleton instance.
+  static void DeleteForTesting();
+
+  // Allow tests to inspect TraceEvents.
+  TraceEvent* GetEventByHandle(TraceEventHandle handle);
+
+  void SetProcessID(int process_id);
+
+  // Process sort indices, if set, override the order of a process will appear
+  // relative to other processes in the trace viewer. Processes are sorted first
+  // on their sort index, ascending, then by their name, and then tid.
+  void SetProcessSortIndex(int sort_index);
+
+  // Sets the name of the process.
+  void SetProcessName(const std::string& process_name);
+
+  // Processes can have labels in addition to their names. Use labels, for
+  // instance, to list out the web page titles that a process is handling.
+  void UpdateProcessLabel(int label_id, const std::string& current_label);
+  void RemoveProcessLabel(int label_id);
+
+  // Thread sort indices, if set, override the order of a thread will appear
+  // within its process in the trace viewer. Threads are sorted first on their
+  // sort index, ascending, then by their name, and then tid.
+  void SetThreadSortIndex(PlatformThreadId , int sort_index);
+
+  // Allow setting an offset between the current TimeTicks time and the time
+  // that should be reported.
+  void SetTimeOffset(TimeDelta offset);
+
+  size_t GetObserverCountForTest() const;
+
+  // Call this method if the current thread may block the message loop to
+  // prevent the thread from using the thread-local buffer because the thread
+  // may not handle the flush request in time causing lost of unflushed events.
+  void SetCurrentThreadBlocksMessageLoop();
+
+ private:
+  typedef unsigned int InternalTraceOptions;
+
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferGetReturnChunk);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferHalfIteration);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferFullIteration);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferVectorReportFull);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           ConvertTraceOptionsToInternalOptions);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceRecordAsMuchAsPossibleMode);
+
+  // This allows constructor and destructor to be private and usable only
+  // by the Singleton class.
+  friend struct DefaultSingletonTraits<TraceLog>;
+
+  // Enable/disable each category group based on the current mode_,
+  // category_filter_, event_callback_ and event_callback_category_filter_.
+  // Enable the category group in the enabled mode if category_filter_ matches
+  // the category group, or event_callback_ is not null and
+  // event_callback_category_filter_ matches the category group.
+  void UpdateCategoryGroupEnabledFlags();
+  void UpdateCategoryGroupEnabledFlag(size_t category_index);
+
+  // Configure synthetic delays based on the values set in the current
+  // category filter.
+  void UpdateSyntheticDelaysFromCategoryFilter();
+
+  InternalTraceOptions GetInternalOptionsFromTraceOptions(
+      const TraceOptions& options);
+
+  class ThreadLocalEventBuffer;
+  class OptionalAutoLock;
+
+  TraceLog();
+  ~TraceLog();
+  const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
+  void AddMetadataEventsWhileLocked();
+
+  InternalTraceOptions trace_options() const {
+    return static_cast<InternalTraceOptions>(
+        subtle::NoBarrier_Load(&trace_options_));
+  }
+
+  TraceBuffer* trace_buffer() const { return logged_events_.get(); }
+  TraceBuffer* CreateTraceBuffer();
+  TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
+
+  std::string EventToConsoleMessage(unsigned char phase,
+                                    const TimeTicks& timestamp,
+                                    TraceEvent* trace_event);
+
+  TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
+                                                     bool check_buffer_is_full);
+  void CheckIfBufferIsFullWhileLocked();
+  void SetDisabledWhileLocked();
+
+  TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
+                                       OptionalAutoLock* lock);
+
+  // |generation| is used in the following callbacks to check if the callback
+  // is called for the flush of the current |logged_events_|.
+  void FlushCurrentThread(int generation);
+  // Usually it runs on a different thread.
+  static void ConvertTraceEventsToTraceFormat(
+      scoped_ptr<TraceBuffer> logged_events,
+      const TraceLog::OutputCallback& flush_output_callback);
+  void FinishFlush(int generation);
+  void OnFlushTimeout(int generation);
+
+  int generation() const {
+    return static_cast<int>(subtle::NoBarrier_Load(&generation_));
+  }
+  bool CheckGeneration(int generation) const {
+    return generation == this->generation();
+  }
+  void UseNextTraceBuffer();
+
+  TimeTicks OffsetNow() const {
+    return OffsetTimestamp(TimeTicks::NowFromSystemTraceTime());
+  }
+  TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
+    return timestamp - time_offset_;
+  }
+
+  // Internal representation of trace options since we store the currently used
+  // trace option as an AtomicWord.
+  static const InternalTraceOptions kInternalNone;
+  static const InternalTraceOptions kInternalRecordUntilFull;
+  static const InternalTraceOptions kInternalRecordContinuously;
+  static const InternalTraceOptions kInternalEchoToConsole;
+  static const InternalTraceOptions kInternalEnableSampling;
+  static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
+
+  // This lock protects TraceLog member accesses (except for members protected
+  // by thread_info_lock_) from arbitrary threads.
+  mutable Lock lock_;
+  // This lock protects accesses to thread_names_, thread_event_start_times_
+  // and thread_colors_.
+  Lock thread_info_lock_;
+  Mode mode_;
+  int num_traces_recorded_;
+  scoped_ptr<TraceBuffer> logged_events_;
+  subtle::AtomicWord /* EventCallback */ event_callback_;
+  bool dispatching_to_observer_list_;
+  std::vector<EnabledStateObserver*> enabled_state_observer_list_;
+
+  std::string process_name_;
+  base::hash_map<int, std::string> process_labels_;
+  int process_sort_index_;
+  base::hash_map<int, int> thread_sort_indices_;
+  base::hash_map<int, std::string> thread_names_;
+
+  // The following two maps are used only when ECHO_TO_CONSOLE.
+  base::hash_map<int, std::stack<TimeTicks> > thread_event_start_times_;
+  base::hash_map<std::string, int> thread_colors_;
+
+  TimeTicks buffer_limit_reached_timestamp_;
+
+  // XORed with TraceID to make it unlikely to collide with other processes.
+  unsigned long long process_id_hash_;
+
+  int process_id_;
+
+  TimeDelta time_offset_;
+
+  // Allow tests to wake up when certain events occur.
+  WatchEventCallback watch_event_callback_;
+  subtle::AtomicWord /* const unsigned char* */ watch_category_;
+  std::string watch_event_name_;
+
+  subtle::AtomicWord /* Options */ trace_options_;
+
+  // Sampling thread handles.
+  scoped_ptr<TraceSamplingThread> sampling_thread_;
+  PlatformThreadHandle sampling_thread_handle_;
+
+  CategoryFilter category_filter_;
+  CategoryFilter event_callback_category_filter_;
+
+  ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
+  ThreadLocalBoolean thread_blocks_message_loop_;
+  ThreadLocalBoolean thread_is_in_trace_event_;
+
+  // Contains the message loops of threads that have had at least one event
+  // added into the local event buffer. Not using SingleThreadTaskRunner
+  // because we need to know the life time of the message loops.
+  hash_set<MessageLoop*> thread_message_loops_;
+
+  // For events which can't be added into the thread local buffer, e.g. events
+  // from threads without a message loop.
+  scoped_ptr<TraceBufferChunk> thread_shared_chunk_;
+  size_t thread_shared_chunk_index_;
+
+  // Set when asynchronous Flush is in progress.
+  OutputCallback flush_output_callback_;
+  scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
+  subtle::AtomicWord generation_;
+  bool use_worker_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceLog);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
diff --git a/base/trace_event/trace_event_impl_constants.cc b/base/trace_event/trace_event_impl_constants.cc
new file mode 100644
index 0000000..ffeacff
--- /dev/null
+++ b/base/trace_event/trace_event_impl_constants.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+// Enable everything but debug and test categories by default.
+const char CategoryFilter::kDefaultCategoryFilterString[] = "-*Debug,-*Test";
+
+// Constant used by TraceLog's internal implementation of trace_option.
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalNone = 0;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalRecordUntilFull = 1 << 0;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalRecordContinuously = 1 << 1;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalEnableSampling = 1 << 2;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalEchoToConsole = 1 << 3;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalRecordAsMuchAsPossible = 1 << 4;
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
new file mode 100644
index 0000000..8959589
--- /dev/null
+++ b/base/trace_event/trace_event_memory.cc
@@ -0,0 +1,437 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_memory.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Maximum number of nested TRACE_EVENT scopes to record. Must be less than
+// or equal to HeapProfileTable::kMaxStackDepth / 2 because we record two
+// entries on the pseudo-stack per scope.
+const size_t kMaxScopeDepth = 16;
+
+/////////////////////////////////////////////////////////////////////////////
+// Holds a memory dump until the tracing system needs to serialize it.
+class MemoryDumpHolder : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  // Takes ownership of dump, which must be a JSON string, allocated with
+  // malloc() and NULL terminated.
+  explicit MemoryDumpHolder(char* dump) : dump_(dump) {}
+
+  // base::trace_event::ConvertableToTraceFormat overrides:
+  void AppendAsTraceFormat(std::string* out) const override {
+    AppendHeapProfileAsTraceFormat(dump_, out);
+  }
+
+ private:
+  ~MemoryDumpHolder() override { free(dump_); }
+
+  char* dump_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Records a stack of TRACE_MEMORY events. One per thread is required.
+struct TraceMemoryStack {
+  TraceMemoryStack() : scope_depth(0) {
+    memset(scope_data, 0, kMaxScopeDepth * sizeof(scope_data[0]));
+  }
+
+  // Depth of the currently nested TRACE_EVENT scopes. Allowed to be greater
+  // than kMaxScopeDepth so we can match scope pushes and pops even if we don't
+  // have enough space to store the EventData.
+  size_t scope_depth;
+
+  // Stack of categories and names.
+  ScopedTraceMemory::ScopeData scope_data[kMaxScopeDepth];
+};
+
+// Pointer to a TraceMemoryStack per thread.
+base::ThreadLocalStorage::StaticSlot tls_trace_memory_stack = TLS_INITIALIZER;
+
+// Clean up memory pointed to by our thread-local storage.
+void DeleteStackOnThreadCleanup(void* value) {
+  TraceMemoryStack* stack = static_cast<TraceMemoryStack*>(value);
+  delete stack;
+}
+
+// Initializes the thread-local TraceMemoryStack pointer.
+void InitThreadLocalStorage() {
+  if (tls_trace_memory_stack.initialized())
+    return;
+  // Initialize the thread-local storage key.
+  tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup);
+}
+
+// Clean up thread-local-storage in the main thread.
+void CleanupThreadLocalStorage() {
+  if (!tls_trace_memory_stack.initialized())
+    return;
+  TraceMemoryStack* stack =
+      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
+  delete stack;
+  tls_trace_memory_stack.Set(NULL);
+  // Intentionally do not release the thread-local-storage key here, that is,
+  // do not call tls_trace_memory_stack.Free(). Other threads have lazily
+  // created pointers in thread-local-storage via GetTraceMemoryStack() below.
+  // Those threads need to run the DeleteStack() destructor function when they
+  // exit. If we release the key the destructor will not be called and those
+  // threads will not clean up their memory.
+}
+
+// Returns the thread-local trace memory stack for the current thread, creating
+// one if needed. Returns NULL if the thread-local storage key isn't
+// initialized, which indicates that heap profiling isn't running.
+TraceMemoryStack* GetTraceMemoryStack() {
+  TraceMemoryStack* stack =
+      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
+  // Lazily initialize TraceMemoryStack objects for new threads.
+  if (!stack) {
+    stack = new TraceMemoryStack;
+    tls_trace_memory_stack.Set(stack);
+  }
+  return stack;
+}
+
+// Returns a "pseudo-stack" of pointers to trace event categories and names.
+// Because tcmalloc stores one pointer per stack frame this converts N nested
+// trace events into N * 2 pseudo-stack entries. Thus this macro invocation:
+//    TRACE_EVENT0("category1", "name1");
+//    TRACE_EVENT0("category2", "name2");
+// becomes this pseudo-stack:
+//    stack_out[0] = "category1"
+//    stack_out[1] = "name1"
+//    stack_out[2] = "category2"
+//    stack_out[3] = "name2"
+// Returns int instead of size_t to match the signature required by tcmalloc.
+int GetPseudoStack(int skip_count_ignored, void** stack_out) {
+  // If the tracing system isn't fully initialized, just skip this allocation.
+  // Attempting to initialize will allocate memory, causing this function to
+  // be called recursively from inside the allocator.
+  if (!tls_trace_memory_stack.initialized() || !tls_trace_memory_stack.Get())
+    return 0;
+  TraceMemoryStack* stack =
+      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
+  // Copy at most kMaxScopeDepth scope entries.
+  const size_t count = std::min(stack->scope_depth, kMaxScopeDepth);
+  // Notes that memcpy() works for zero bytes.
+  memcpy(stack_out,
+         stack->scope_data,
+         count * sizeof(stack->scope_data[0]));
+  // Each item in the trace event stack contains both name and category so tell
+  // tcmalloc that we have returned |count| * 2 stack frames.
+  return static_cast<int>(count * 2);
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+TraceMemoryController::TraceMemoryController(
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
+    HeapProfilerStartFunction heap_profiler_start_function,
+    HeapProfilerStopFunction heap_profiler_stop_function,
+    GetHeapProfileFunction get_heap_profile_function)
+    : task_runner_(task_runner.Pass()),
+      heap_profiler_start_function_(heap_profiler_start_function),
+      heap_profiler_stop_function_(heap_profiler_stop_function),
+      get_heap_profile_function_(get_heap_profile_function),
+      weak_factory_(this) {
+  // Force the "memory" category to show up in the trace viewer.
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory"), "init");
+  // Watch for the tracing system being enabled.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
+
+TraceMemoryController::~TraceMemoryController() {
+  if (dump_timer_.IsRunning())
+    StopProfiling();
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+// base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
+void TraceMemoryController::OnTraceLogEnabled() {
+  // Check to see if tracing is enabled for the memory category.
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"),
+                                     &enabled);
+  if (!enabled)
+    return;
+  DVLOG(1) << "OnTraceLogEnabled";
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&TraceMemoryController::StartProfiling,
+                                    weak_factory_.GetWeakPtr()));
+}
+
+void TraceMemoryController::OnTraceLogDisabled() {
+  // The memory category is always disabled before OnTraceLogDisabled() is
+  // called, so we cannot tell if it was enabled before. Always try to turn
+  // off profiling.
+  DVLOG(1) << "OnTraceLogDisabled";
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&TraceMemoryController::StopProfiling,
+                                    weak_factory_.GetWeakPtr()));
+}
+
+void TraceMemoryController::StartProfiling() {
+  // Watch for the tracing framework sending enabling more than once.
+  if (dump_timer_.IsRunning())
+    return;
+  DVLOG(1) << "Starting trace memory";
+  InitThreadLocalStorage();
+  ScopedTraceMemory::set_enabled(true);
+  // Call ::HeapProfilerWithPseudoStackStart().
+  heap_profiler_start_function_(&GetPseudoStack);
+  const int kDumpIntervalSeconds = 5;
+  dump_timer_.Start(FROM_HERE,
+                    TimeDelta::FromSeconds(kDumpIntervalSeconds),
+                    base::Bind(&TraceMemoryController::DumpMemoryProfile,
+                               weak_factory_.GetWeakPtr()));
+}
+
+void TraceMemoryController::DumpMemoryProfile() {
+  // Don't trace allocations here in the memory tracing system.
+  INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"),
+                        TRACE_MEMORY_IGNORE);
+
+  DVLOG(1) << "DumpMemoryProfile";
+  // MemoryDumpHolder takes ownership of this string. See GetHeapProfile() in
+  // tcmalloc for details.
+  char* dump = get_heap_profile_function_();
+  const int kSnapshotId = 1;
+  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+      TRACE_DISABLED_BY_DEFAULT("memory"),
+      "memory::Heap",
+      kSnapshotId,
+      scoped_refptr<ConvertableToTraceFormat>(new MemoryDumpHolder(dump)));
+}
+
+void TraceMemoryController::StopProfiling() {
+  // Watch for the tracing framework sending disabled more than once.
+  if (!dump_timer_.IsRunning())
+    return;
+  DVLOG(1) << "Stopping trace memory";
+  dump_timer_.Stop();
+  ScopedTraceMemory::set_enabled(false);
+  CleanupThreadLocalStorage();
+  // Call ::HeapProfilerStop().
+  heap_profiler_stop_function_();
+}
+
+bool TraceMemoryController::IsTimerRunningForTest() const {
+  return dump_timer_.IsRunning();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+// static
+bool ScopedTraceMemory::enabled_ = false;
+
+void ScopedTraceMemory::Initialize(const char* category, const char* name) {
+  DCHECK(enabled_);
+  // Get our thread's copy of the stack.
+  TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
+  const size_t index = trace_memory_stack->scope_depth;
+  // Don't record data for deeply nested scopes, but continue to increment
+  // |stack_depth| so we can match pushes and pops.
+  if (index < kMaxScopeDepth) {
+    ScopeData& event = trace_memory_stack->scope_data[index];
+    event.category = category;
+    event.name = name;
+  }
+  trace_memory_stack->scope_depth++;
+}
+
+void ScopedTraceMemory::Destroy() {
+  DCHECK(enabled_);
+  // Get our thread's copy of the stack.
+  TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
+  // The tracing system can be turned on with ScopedTraceMemory objects
+  // allocated on the stack, so avoid potential underflow as they are destroyed.
+  if (trace_memory_stack->scope_depth > 0)
+    trace_memory_stack->scope_depth--;
+}
+
+// static
+void ScopedTraceMemory::InitForTest() {
+  InitThreadLocalStorage();
+  enabled_ = true;
+}
+
+// static
+void ScopedTraceMemory::CleanupForTest() {
+  enabled_ = false;
+  CleanupThreadLocalStorage();
+}
+
+// static
+int ScopedTraceMemory::GetStackDepthForTest() {
+  TraceMemoryStack* stack = GetTraceMemoryStack();
+  return static_cast<int>(stack->scope_depth);
+}
+
+// static
+ScopedTraceMemory::ScopeData ScopedTraceMemory::GetScopeDataForTest(
+    int stack_index) {
+  TraceMemoryStack* stack = GetTraceMemoryStack();
+  return stack->scope_data[stack_index];
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void AppendHeapProfileAsTraceFormat(const char* input, std::string* output) {
+  // Heap profile output has a header total line, then a list of stacks with
+  // memory totals, like this:
+  //
+  // heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile
+  //    95:    40940 [   649:   114260] @ 0x7fa7f4b3be13
+  //    77:    32546 [   742:   106234] @
+  //    68:     4195 [  1087:    98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
+  //
+  // MAPPED_LIBRARIES:
+  // 1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0
+  // 1be4139e4000-1be4139e5000 ---p 00000000 00:00 0
+  // ...
+  //
+  // Skip input after MAPPED_LIBRARIES.
+  std::string input_string;
+  const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES");
+  if (mapped_libraries) {
+    input_string.assign(input, mapped_libraries - input);
+  } else {
+    input_string.assign(input);
+  }
+
+  std::vector<std::string> lines;
+  size_t line_count = Tokenize(input_string, "\n", &lines);
+  if (line_count == 0) {
+    DLOG(WARNING) << "No lines found";
+    return;
+  }
+
+  // Handle the initial summary line.
+  output->append("[");
+  AppendHeapProfileTotalsAsTraceFormat(lines[0], output);
+
+  // Handle the following stack trace lines.
+  for (size_t i = 1; i < line_count; ++i) {
+    const std::string& line = lines[i];
+    AppendHeapProfileLineAsTraceFormat(line, output);
+  }
+  output->append("]\n");
+}
+
+void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
+                                          std::string* output) {
+  // This is what a line looks like:
+  // heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile
+  //
+  // The numbers represent total allocations since profiling was enabled.
+  // From the example above:
+  //     357 = Outstanding allocations (mallocs - frees)
+  //   55227 = Outstanding bytes (malloc bytes - free bytes)
+  //   14653 = Total allocations (mallocs)
+  // 2624014 = Total bytes (malloc bytes)
+  std::vector<std::string> tokens;
+  Tokenize(line, " :[]@", &tokens);
+  if (tokens.size() < 4) {
+    DLOG(WARNING) << "Invalid totals line " << line;
+    return;
+  }
+  DCHECK_EQ(tokens[0], "heap");
+  DCHECK_EQ(tokens[1], "profile");
+  output->append("{\"current_allocs\": ");
+  output->append(tokens[2]);
+  output->append(", \"current_bytes\": ");
+  output->append(tokens[3]);
+  output->append(", \"trace\": \"\"}");
+}
+
+bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
+                                        std::string* output) {
+  // This is what a line looks like:
+  //    68:     4195 [  1087:    98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
+  //
+  // The numbers represent allocations for a particular stack trace since
+  // profiling was enabled. From the example above:
+  //    68 = Outstanding allocations (mallocs - frees)
+  //  4195 = Outstanding bytes (malloc bytes - free bytes)
+  //  1087 = Total allocations (mallocs)
+  // 98009 = Total bytes (malloc bytes)
+  //
+  // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to
+  //                                 static strings from trace event categories
+  //                                 and names.
+  std::vector<std::string> tokens;
+  Tokenize(line, " :[]@", &tokens);
+  // It's valid to have no stack addresses, so only require 4 tokens.
+  if (tokens.size() < 4) {
+    DLOG(WARNING) << "Invalid line " << line;
+    return false;
+  }
+  // Don't bother with stacks that have no current allocations.
+  if (tokens[0] == "0")
+    return false;
+  output->append(",\n");
+  output->append("{\"current_allocs\": ");
+  output->append(tokens[0]);
+  output->append(", \"current_bytes\": ");
+  output->append(tokens[1]);
+  output->append(", \"trace\": \"");
+
+  // Convert pairs of "stack addresses" into category and name strings.
+  const std::string kSingleQuote = "'";
+  for (size_t t = 4; t < tokens.size(); t += 2) {
+    // Casting strings into pointers is ugly but otherwise tcmalloc would need
+    // to gain a special output serializer just for pseudo-stacks.
+    const char* trace_category = StringFromHexAddress(tokens[t]);
+    DCHECK_LT(t + 1, tokens.size());
+    const char* trace_name = StringFromHexAddress(tokens[t + 1]);
+
+    // TODO(jamescook): Report the trace category and name separately to the
+    // trace viewer and allow it to decide what decorations to apply. For now
+    // just hard-code a decoration for posted tasks (toplevel).
+    std::string trace_string(trace_name);
+    if (!strcmp(trace_category, "toplevel"))
+      trace_string.append("->PostTask");
+
+    // Some trace name strings have double quotes, convert them to single.
+    ReplaceChars(trace_string, "\"", kSingleQuote, &trace_string);
+
+    output->append(trace_string);
+
+    // Trace viewer expects a trailing space.
+    output->append(" ");
+  }
+  output->append("\"}");
+  return true;
+}
+
+const char* StringFromHexAddress(const std::string& hex_address) {
+  uint64 address = 0;
+  if (!base::HexStringToUInt64(hex_address, &address))
+    return "error";
+  if (!address)
+    return "null";
+  // Note that this cast handles 64-bit to 32-bit conversion if necessary.
+  return reinterpret_cast<const char*>(address);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h
new file mode 100644
index 0000000..e2b3ae9
--- /dev/null
+++ b/base/trace_event/trace_event_memory.h
@@ -0,0 +1,171 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// TODO(jamescook): Windows support for memory tracing.
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \
+    (defined(OS_LINUX) || defined(OS_ANDROID))
+#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1
+#endif
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+// Watches for chrome://tracing to be enabled or disabled. When tracing is
+// enabled, also enables tcmalloc heap profiling. This class is the preferred
+// way to turn trace-base heap memory profiling on and off.
+class BASE_EXPORT TraceMemoryController
+    : public TraceLog::EnabledStateObserver {
+ public:
+  typedef int (*StackGeneratorFunction)(int skip_count, void** stack);
+  typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback);
+  typedef void (*HeapProfilerStopFunction)();
+  typedef char* (*GetHeapProfileFunction)();
+
+  // |task_runner| must be a task runner for the primary thread for the client
+  // process, e.g. the UI thread in a browser. The function pointers must be
+  // pointers to tcmalloc heap profiling functions; by avoiding direct calls to
+  // these functions we avoid a dependency on third_party/tcmalloc from base.
+  TraceMemoryController(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                        HeapProfilerStartFunction heap_profiler_start_function,
+                        HeapProfilerStopFunction heap_profiler_stop_function,
+                        GetHeapProfileFunction get_heap_profile_function);
+  virtual ~TraceMemoryController();
+
+  // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Starts heap memory profiling.
+  void StartProfiling();
+
+  // Captures a heap profile.
+  void DumpMemoryProfile();
+
+  // If memory tracing is enabled, dumps a memory profile to the tracing system.
+  void StopProfiling();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController);
+
+  bool IsTimerRunningForTest() const;
+
+  // Ensures the observer starts and stops tracing on the primary thread.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  // Pointers to tcmalloc heap profiling functions. Allows this class to use
+  // tcmalloc functions without introducing a dependency from base to tcmalloc.
+  HeapProfilerStartFunction heap_profiler_start_function_;
+  HeapProfilerStopFunction heap_profiler_stop_function_;
+  GetHeapProfileFunction get_heap_profile_function_;
+
+  // Timer to schedule memory profile dumps.
+  RepeatingTimer<TraceMemoryController> dump_timer_;
+
+  WeakPtrFactory<TraceMemoryController> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceMemoryController);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+// A scoped context for memory tracing. Pushes the name onto a stack for
+// recording by tcmalloc heap profiling.
+class BASE_EXPORT ScopedTraceMemory {
+ public:
+  struct ScopeData {
+    const char* category;
+    const char* name;
+  };
+
+  // Memory for |category| and |name| must be static, for example, literal
+  // strings in a TRACE_EVENT macro.
+  ScopedTraceMemory(const char* category, const char* name) {
+    if (!enabled_)
+      return;
+    Initialize(category, name);
+  }
+  ~ScopedTraceMemory() {
+    if (!enabled_)
+      return;
+    Destroy();
+  }
+
+  // Enables the storing of trace names on a per-thread stack.
+  static void set_enabled(bool enabled) { enabled_ = enabled; }
+
+  // Testing interface:
+  static void InitForTest();
+  static void CleanupForTest();
+  static int GetStackDepthForTest();
+  static ScopeData GetScopeDataForTest(int stack_index);
+
+ private:
+  void Initialize(const char* category, const char* name);
+  void Destroy();
+
+  static bool enabled_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to
+// trace event compatible JSON and appends to |output|. Visible for testing.
+BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input,
+                                                std::string* output);
+
+// Converts the first |line| of heap profiler data, which contains totals for
+// all allocations in a special format, into trace event compatible JSON and
+// appends to |output|. Visible for testing.
+BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
+                                                      std::string* output);
+
+// Converts a single |line| of heap profiler data into trace event compatible
+// JSON and appends to |output|. Returns true if the line was valid and has a
+// non-zero number of current allocations. Visible for testing.
+BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
+                                                    std::string* output);
+
+// Returns a pointer to a string given its hexadecimal address in |hex_address|.
+// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers
+// and "error" if |address| could not be parsed. Visible for testing.
+BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
+
+}  // namespace trace_event
+}  // namespace base
+
+// Make local variables with unique names based on the line number. Note that
+// the extra level of redirection is needed.
+#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line
+#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line)
+#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__)
+
+// This is the core macro that adds a scope to each TRACE_EVENT location.
+// It generates a unique local variable name using the macros above.
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+#define INTERNAL_TRACE_MEMORY(category, name) \
+  base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
+#else
+#define INTERNAL_TRACE_MEMORY(category, name)
+#endif  // defined(TRACE_MEMORY_SUPPORTED)
+
+// A special trace name that allows us to ignore memory allocations inside
+// the memory dump system itself. The allocations are recorded, but the
+// visualizer skips them. Must match the value in heap.js.
+#define TRACE_MEMORY_IGNORE "trace-memory-ignore"
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc
new file mode 100644
index 0000000..781a054
--- /dev/null
+++ b/base/trace_event/trace_event_memory_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_memory.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/trace_event/trace_event_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#endif
+
+namespace base {
+namespace trace_event {
+
+// Tests for the trace event memory tracking system. Exists as a class so it
+// can be a friend of TraceMemoryController.
+class TraceMemoryTest : public testing::Test {
+ public:
+  TraceMemoryTest() {}
+  ~TraceMemoryTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+
+TEST_F(TraceMemoryTest, TraceMemoryController) {
+  MessageLoop message_loop;
+
+  // Start with no observers of the TraceLog.
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  // Creating a controller adds it to the TraceLog observer list.
+  scoped_ptr<TraceMemoryController> controller(new TraceMemoryController(
+      message_loop.task_runner(), ::HeapProfilerWithPseudoStackStart,
+      ::HeapProfilerStop, ::GetHeapProfile));
+  EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+  EXPECT_TRUE(
+      TraceLog::GetInstance()->HasEnabledStateObserver(controller.get()));
+
+  // By default the observer isn't dumping memory profiles.
+  EXPECT_FALSE(controller->IsTimerRunningForTest());
+
+  // Simulate enabling tracing.
+  controller->StartProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(controller->IsTimerRunningForTest());
+
+  // Simulate disabling tracing.
+  controller->StopProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(controller->IsTimerRunningForTest());
+
+  // Deleting the observer removes it from the TraceLog observer list.
+  controller.reset();
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+
+TEST_F(TraceMemoryTest, ScopedTraceMemory) {
+  ScopedTraceMemory::InitForTest();
+
+  // Start with an empty stack.
+  EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
+
+  {
+    // Push an item.
+    ScopedTraceMemory scope1("cat1", "name1");
+    EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
+    EXPECT_EQ("cat1", ScopedTraceMemory::GetScopeDataForTest(0).category);
+    EXPECT_EQ("name1", ScopedTraceMemory::GetScopeDataForTest(0).name);
+
+    {
+      // One more item.
+      ScopedTraceMemory scope2("cat2", "name2");
+      EXPECT_EQ(2, ScopedTraceMemory::GetStackDepthForTest());
+      EXPECT_EQ("cat2", ScopedTraceMemory::GetScopeDataForTest(1).category);
+      EXPECT_EQ("name2", ScopedTraceMemory::GetScopeDataForTest(1).name);
+    }
+
+    // Ended scope 2.
+    EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
+  }
+
+  // Ended scope 1.
+  EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
+
+  ScopedTraceMemory::CleanupForTest();
+}
+
+void TestDeepScopeNesting(int current, int depth) {
+  EXPECT_EQ(current, ScopedTraceMemory::GetStackDepthForTest());
+  ScopedTraceMemory scope("category", "name");
+  if (current < depth)
+    TestDeepScopeNesting(current + 1, depth);
+  EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackDepthForTest());
+}
+
+TEST_F(TraceMemoryTest, DeepScopeNesting) {
+  ScopedTraceMemory::InitForTest();
+
+  // Ensure really deep scopes don't crash.
+  TestDeepScopeNesting(0, 100);
+
+  ScopedTraceMemory::CleanupForTest();
+}
+
+#endif  // defined(TRACE_MEMORY_SUPPORTED)
+
+/////////////////////////////////////////////////////////////////////////////
+
+TEST_F(TraceMemoryTest, AppendHeapProfileTotalsAsTraceFormat) {
+  // Empty input gives empty output.
+  std::string empty_output;
+  AppendHeapProfileTotalsAsTraceFormat("", &empty_output);
+  EXPECT_EQ("", empty_output);
+
+  // Typical case.
+  const char input[] =
+      "heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile";
+  const std::string kExpectedOutput =
+      "{\"current_allocs\": 357, \"current_bytes\": 55227, \"trace\": \"\"}";
+  std::string output;
+  AppendHeapProfileTotalsAsTraceFormat(input, &output);
+  EXPECT_EQ(kExpectedOutput, output);
+}
+
+TEST_F(TraceMemoryTest, AppendHeapProfileLineAsTraceFormat) {
+  // Empty input gives empty output.
+  std::string empty_output;
+  EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("", &empty_output));
+  EXPECT_EQ("", empty_output);
+
+  // Invalid input returns false.
+  std::string junk_output;
+  EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("junk", &junk_output));
+
+  // Input with normal category and name entries.
+  const char kCategory[] = "category";
+  const char kName[] = "name";
+  std::ostringstream input;
+  input << "   68:     4195 [  1087:    98009] @ " << &kCategory << " "
+        << &kName;
+  const std::string kExpectedOutput =
+      ",\n"
+      "{"
+      "\"current_allocs\": 68, "
+      "\"current_bytes\": 4195, "
+      "\"trace\": \"name \""
+      "}";
+  std::string output;
+  EXPECT_TRUE(
+      AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output));
+  EXPECT_EQ(kExpectedOutput, output);
+
+  // Input with with the category "toplevel".
+  // TODO(jamescook): Eliminate this special case and move the logic to the
+  // trace viewer code.
+  const char kTaskCategory[] = "toplevel";
+  const char kTaskName[] = "TaskName";
+  std::ostringstream input2;
+  input2 << "   68:     4195 [  1087:    98009] @ " << &kTaskCategory << " "
+        << &kTaskName;
+  const std::string kExpectedOutput2 =
+      ",\n"
+      "{"
+      "\"current_allocs\": 68, "
+      "\"current_bytes\": 4195, "
+      "\"trace\": \"TaskName->PostTask \""
+      "}";
+  std::string output2;
+  EXPECT_TRUE(
+      AppendHeapProfileLineAsTraceFormat(input2.str().c_str(), &output2));
+  EXPECT_EQ(kExpectedOutput2, output2);
+
+  // Zero current allocations is skipped.
+  std::ostringstream zero_input;
+  zero_input << "   0:     0 [  1087:    98009] @ " << &kCategory << " "
+             << &kName;
+  std::string zero_output;
+  EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat(zero_input.str().c_str(),
+                                                  &zero_output));
+  EXPECT_EQ("", zero_output);
+}
+
+TEST_F(TraceMemoryTest, AppendHeapProfileAsTraceFormat) {
+  // Empty input gives empty output.
+  std::string empty_output;
+  AppendHeapProfileAsTraceFormat("", &empty_output);
+  EXPECT_EQ("", empty_output);
+
+  // Typical case.
+  const char input[] =
+      "heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile\n"
+      "   95:    40940 [   649:   114260] @\n"
+      "   77:    32546 [   742:   106234] @ 0x0 0x0\n"
+      "    0:        0 [   132:     4236] @ 0x0\n"
+      "\n"
+      "MAPPED_LIBRARIES:\n"
+      "1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0\n"
+      "1be4139e4000-1be4139e5000 ---p 00000000 00:00 0\n";
+  const std::string kExpectedOutput =
+      "[{"
+      "\"current_allocs\": 357, "
+      "\"current_bytes\": 55227, "
+      "\"trace\": \"\"},\n"
+      "{\"current_allocs\": 95, "
+      "\"current_bytes\": 40940, "
+      "\"trace\": \"\"},\n"
+      "{\"current_allocs\": 77, "
+      "\"current_bytes\": 32546, "
+      "\"trace\": \"null \""
+      "}]\n";
+  std::string output;
+  AppendHeapProfileAsTraceFormat(input, &output);
+  EXPECT_EQ(kExpectedOutput, output);
+}
+
+TEST_F(TraceMemoryTest, StringFromHexAddress) {
+  EXPECT_STREQ("null", StringFromHexAddress("0x0"));
+  EXPECT_STREQ("error", StringFromHexAddress("not an address"));
+  const char kHello[] = "hello";
+  std::ostringstream hex_address;
+  hex_address << &kHello;
+  EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str()));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_synthetic_delay.cc b/base/trace_event/trace_event_synthetic_delay.cc
new file mode 100644
index 0000000..bad79cc
--- /dev/null
+++ b/base/trace_event/trace_event_synthetic_delay.cc
@@ -0,0 +1,235 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/singleton.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+
+namespace {
+const int kMaxSyntheticDelays = 32;
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
+TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
+
+class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
+ public:
+  static TraceEventSyntheticDelayRegistry* GetInstance();
+
+  TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
+  void ResetAllDelays();
+
+  // TraceEventSyntheticDelayClock implementation.
+  base::TimeTicks Now() override;
+
+ private:
+  TraceEventSyntheticDelayRegistry();
+
+  friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
+
+  Lock lock_;
+  TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
+  TraceEventSyntheticDelay dummy_delay_;
+  base::subtle::Atomic32 delay_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
+};
+
+TraceEventSyntheticDelay::TraceEventSyntheticDelay()
+    : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
+
+TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
+
+TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
+    const std::string& name) {
+  return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
+      name.c_str());
+}
+
+void TraceEventSyntheticDelay::Initialize(
+    const std::string& name,
+    TraceEventSyntheticDelayClock* clock) {
+  name_ = name;
+  clock_ = clock;
+}
+
+void TraceEventSyntheticDelay::SetTargetDuration(
+    base::TimeDelta target_duration) {
+  AutoLock lock(lock_);
+  target_duration_ = target_duration;
+  trigger_count_ = 0;
+  begin_count_ = 0;
+}
+
+void TraceEventSyntheticDelay::SetMode(Mode mode) {
+  AutoLock lock(lock_);
+  mode_ = mode;
+}
+
+void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
+  AutoLock lock(lock_);
+  clock_ = clock;
+}
+
+void TraceEventSyntheticDelay::Begin() {
+  // Note that we check for a non-zero target duration without locking to keep
+  // things quick for the common case when delays are disabled. Since the delay
+  // calculation is done with a lock held, it will always be correct. The only
+  // downside of this is that we may fail to apply some delays when the target
+  // duration changes.
+  ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
+  if (!target_duration_.ToInternalValue())
+    return;
+
+  base::TimeTicks start_time = clock_->Now();
+  {
+    AutoLock lock(lock_);
+    if (++begin_count_ != 1)
+      return;
+    end_time_ = CalculateEndTimeLocked(start_time);
+  }
+}
+
+void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
+  // See note in Begin().
+  ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
+  if (!target_duration_.ToInternalValue()) {
+    *out_end_time = base::TimeTicks();
+    return;
+  }
+
+  base::TimeTicks start_time = clock_->Now();
+  {
+    AutoLock lock(lock_);
+    *out_end_time = CalculateEndTimeLocked(start_time);
+  }
+}
+
+void TraceEventSyntheticDelay::End() {
+  // See note in Begin().
+  ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
+  if (!target_duration_.ToInternalValue())
+    return;
+
+  base::TimeTicks end_time;
+  {
+    AutoLock lock(lock_);
+    if (!begin_count_ || --begin_count_ != 0)
+      return;
+    end_time = end_time_;
+  }
+  if (!end_time.is_null())
+    ApplyDelay(end_time);
+}
+
+void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
+  if (!end_time.is_null())
+    ApplyDelay(end_time);
+}
+
+base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
+    base::TimeTicks start_time) {
+  if (mode_ == ONE_SHOT && trigger_count_++)
+    return base::TimeTicks();
+  else if (mode_ == ALTERNATING && trigger_count_++ % 2)
+    return base::TimeTicks();
+  return start_time + target_duration_;
+}
+
+void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
+  TRACE_EVENT0("synthetic_delay", name_.c_str());
+  while (clock_->Now() < end_time) {
+    // Busy loop.
+  }
+}
+
+TraceEventSyntheticDelayRegistry*
+TraceEventSyntheticDelayRegistry::GetInstance() {
+  return Singleton<
+      TraceEventSyntheticDelayRegistry,
+      LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
+}
+
+TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
+    : delay_count_(0) {}
+
+TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
+    const char* name) {
+  // Try to find an existing delay first without locking to make the common case
+  // fast.
+  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    if (!strcmp(name, delays_[i].name_.c_str()))
+      return &delays_[i];
+  }
+
+  AutoLock lock(lock_);
+  delay_count = base::subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    if (!strcmp(name, delays_[i].name_.c_str()))
+      return &delays_[i];
+  }
+
+  DCHECK(delay_count < kMaxSyntheticDelays)
+      << "must increase kMaxSyntheticDelays";
+  if (delay_count >= kMaxSyntheticDelays)
+    return &dummy_delay_;
+
+  delays_[delay_count].Initialize(std::string(name), this);
+  base::subtle::Release_Store(&delay_count_, delay_count + 1);
+  return &delays_[delay_count];
+}
+
+base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
+  return base::TimeTicks::Now();
+}
+
+void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
+  AutoLock lock(lock_);
+  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    delays_[i].SetTargetDuration(base::TimeDelta());
+    delays_[i].SetClock(this);
+  }
+}
+
+void ResetTraceEventSyntheticDelays() {
+  TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace trace_event_internal {
+
+ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
+                                           base::subtle::AtomicWord* impl_ptr)
+    : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
+  delay_impl_->BeginParallel(&end_time_);
+}
+
+ScopedSyntheticDelay::~ScopedSyntheticDelay() {
+  delay_impl_->EndParallel(end_time_);
+}
+
+base::trace_event::TraceEventSyntheticDelay* GetOrCreateDelay(
+    const char* name,
+    base::subtle::AtomicWord* impl_ptr) {
+  base::trace_event::TraceEventSyntheticDelay* delay_impl =
+      reinterpret_cast<base::trace_event::TraceEventSyntheticDelay*>(
+          base::subtle::Acquire_Load(impl_ptr));
+  if (!delay_impl) {
+    delay_impl =
+        base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
+            ->GetOrCreateDelay(name);
+    base::subtle::Release_Store(
+        impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
+  }
+  return delay_impl;
+}
+
+}  // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_synthetic_delay.h b/base/trace_event/trace_event_synthetic_delay.h
new file mode 100644
index 0000000..0df794b
--- /dev/null
+++ b/base/trace_event/trace_event_synthetic_delay.h
@@ -0,0 +1,166 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The synthetic delay framework makes it possible to dynamically inject
+// arbitrary delays into into different parts of the codebase. This can be used,
+// for instance, for testing various task scheduling algorithms.
+//
+// The delays are specified in terms of a target duration for a given block of
+// code. If the code executes faster than the duration, the thread is made to
+// sleep until the deadline is met.
+//
+// Code can be instrumented for delays with two sets of macros. First, for
+// delays that should apply within a scope, use the following macro:
+//
+//   TRACE_EVENT_SYNTHETIC_DELAY("cc.LayerTreeHost.DrawAndSwap");
+//
+// For delaying operations that span multiple scopes, use:
+//
+//   TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.Scheduler.BeginMainFrame");
+//   ...
+//   TRACE_EVENT_SYNTHETIC_DELAY_END("cc.Scheduler.BeginMainFrame");
+//
+// Here BEGIN establishes the start time for the delay and END executes the
+// delay based on the remaining time. If BEGIN is called multiple times in a
+// row, END should be called a corresponding number of times. Only the last
+// call to END will have an effect.
+//
+// Note that a single delay may begin on one thread and end on another. This
+// implies that a single delay cannot not be applied in several threads at once.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
+
+#include "base/atomicops.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+
+// Apply a named delay in the current scope.
+#define TRACE_EVENT_SYNTHETIC_DELAY(name)                                     \
+  static base::subtle::AtomicWord INTERNAL_TRACE_EVENT_UID(impl_ptr) = 0;     \
+  trace_event_internal::ScopedSyntheticDelay INTERNAL_TRACE_EVENT_UID(delay)( \
+      name, &INTERNAL_TRACE_EVENT_UID(impl_ptr));
+
+// Begin a named delay, establishing its timing start point. May be called
+// multiple times as long as the calls to TRACE_EVENT_SYNTHETIC_DELAY_END are
+// balanced. Only the first call records the timing start point.
+#define TRACE_EVENT_SYNTHETIC_DELAY_BEGIN(name)                          \
+  do {                                                                   \
+    static base::subtle::AtomicWord impl_ptr = 0;                        \
+    trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->Begin();    \
+  } while (false)
+
+// End a named delay. The delay is applied only if this call matches the
+// first corresponding call to TRACE_EVENT_SYNTHETIC_DELAY_BEGIN with the
+// same delay.
+#define TRACE_EVENT_SYNTHETIC_DELAY_END(name)                         \
+  do {                                                                \
+    static base::subtle::AtomicWord impl_ptr = 0;                     \
+    trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->End();   \
+  } while (false)
+
+template <typename Type>
+struct DefaultSingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+// Time source for computing delay durations. Used for testing.
+class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelayClock {
+ public:
+  TraceEventSyntheticDelayClock();
+  virtual ~TraceEventSyntheticDelayClock();
+  virtual base::TimeTicks Now() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayClock);
+};
+
+// Single delay point instance.
+class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelay {
+ public:
+  enum Mode {
+    STATIC,      // Apply the configured delay every time.
+    ONE_SHOT,    // Apply the configured delay just once.
+    ALTERNATING  // Apply the configured delay every other time.
+  };
+
+  // Returns an existing named delay instance or creates a new one with |name|.
+  static TraceEventSyntheticDelay* Lookup(const std::string& name);
+
+  void SetTargetDuration(TimeDelta target_duration);
+  void SetMode(Mode mode);
+  void SetClock(TraceEventSyntheticDelayClock* clock);
+
+  // Begin the delay, establishing its timing start point. May be called
+  // multiple times as long as the calls to End() are balanced. Only the first
+  // call records the timing start point.
+  void Begin();
+
+  // End the delay. The delay is applied only if this call matches the first
+  // corresponding call to Begin() with the same delay.
+  void End();
+
+  // Begin a parallel instance of the delay. Several parallel instances may be
+  // active simultaneously and will complete independently. The computed end
+  // time for the delay is stored in |out_end_time|, which should later be
+  // passed to EndParallel().
+  void BeginParallel(base::TimeTicks* out_end_time);
+
+  // End a previously started parallel delay. |end_time| is the delay end point
+  // computed by BeginParallel().
+  void EndParallel(base::TimeTicks end_time);
+
+ private:
+  TraceEventSyntheticDelay();
+  ~TraceEventSyntheticDelay();
+  friend class TraceEventSyntheticDelayRegistry;
+
+  void Initialize(const std::string& name,
+                  TraceEventSyntheticDelayClock* clock);
+  base::TimeTicks CalculateEndTimeLocked(base::TimeTicks start_time);
+  void ApplyDelay(base::TimeTicks end_time);
+
+  Lock lock_;
+  Mode mode_;
+  std::string name_;
+  int begin_count_;
+  int trigger_count_;
+  base::TimeTicks end_time_;
+  base::TimeDelta target_duration_;
+  TraceEventSyntheticDelayClock* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelay);
+};
+
+// Set the target durations of all registered synthetic delay points to zero.
+TRACE_EVENT_API_CLASS_EXPORT void ResetTraceEventSyntheticDelays();
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace trace_event_internal {
+
+// Helper class for scoped delays. Do not use directly.
+class TRACE_EVENT_API_CLASS_EXPORT ScopedSyntheticDelay {
+ public:
+  explicit ScopedSyntheticDelay(const char* name,
+                                base::subtle::AtomicWord* impl_ptr);
+  ~ScopedSyntheticDelay();
+
+ private:
+  base::trace_event::TraceEventSyntheticDelay* delay_impl_;
+  base::TimeTicks end_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSyntheticDelay);
+};
+
+// Helper for registering delays. Do not use directly.
+TRACE_EVENT_API_CLASS_EXPORT base::trace_event::TraceEventSyntheticDelay*
+    GetOrCreateDelay(const char* name, base::subtle::AtomicWord* impl_ptr);
+
+}  // namespace trace_event_internal
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
diff --git a/base/trace_event/trace_event_synthetic_delay_unittest.cc b/base/trace_event/trace_event_synthetic_delay_unittest.cc
new file mode 100644
index 0000000..1dc0fc2
--- /dev/null
+++ b/base/trace_event/trace_event_synthetic_delay_unittest.cc
@@ -0,0 +1,154 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_synthetic_delay.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+namespace {
+
+const int kTargetDurationMs = 100;
+// Allow some leeway in timings to make it possible to run these tests with a
+// wall clock time source too.
+const int kShortDurationMs = 10;
+
+}  // namespace
+
+class TraceEventSyntheticDelayTest : public testing::Test,
+                                     public TraceEventSyntheticDelayClock {
+ public:
+  TraceEventSyntheticDelayTest() {}
+  ~TraceEventSyntheticDelayTest() override { ResetTraceEventSyntheticDelays(); }
+
+  // TraceEventSyntheticDelayClock implementation.
+  base::TimeTicks Now() override {
+    AdvanceTime(base::TimeDelta::FromMilliseconds(kShortDurationMs / 10));
+    return now_;
+  }
+
+  TraceEventSyntheticDelay* ConfigureDelay(const char* name) {
+    TraceEventSyntheticDelay* delay = TraceEventSyntheticDelay::Lookup(name);
+    delay->SetClock(this);
+    delay->SetTargetDuration(
+        base::TimeDelta::FromMilliseconds(kTargetDurationMs));
+    return delay;
+  }
+
+  void AdvanceTime(base::TimeDelta delta) { now_ += delta; }
+
+  int64 TestFunction() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+  int64 AsyncTestFunctionBegin() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+  int64 AsyncTestFunctionEnd() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY_END("test.AsyncDelay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+ private:
+  base::TimeTicks now_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayTest);
+};
+
+TEST_F(TraceEventSyntheticDelayTest, StaticDelay) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
+  delay->SetMode(TraceEventSyntheticDelay::STATIC);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, OneShotDelay) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
+  delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+
+  delay->SetTargetDuration(
+      base::TimeDelta::FromMilliseconds(kTargetDurationMs));
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AlternatingDelay) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
+  delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelay) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayExceeded) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  AdvanceTime(base::TimeDelta::FromMilliseconds(kTargetDurationMs));
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNoActivation) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNested) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayUnbalanced) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, ResetDelays) {
+  ConfigureDelay("test.Delay");
+  ResetTraceEventSyntheticDelays();
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, BeginParallel) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.AsyncDelay");
+  base::TimeTicks end_times[2];
+  base::TimeTicks start_time = Now();
+
+  delay->BeginParallel(&end_times[0]);
+  EXPECT_FALSE(end_times[0].is_null());
+
+  delay->BeginParallel(&end_times[1]);
+  EXPECT_FALSE(end_times[1].is_null());
+
+  delay->EndParallel(end_times[0]);
+  EXPECT_GE((Now() - start_time).InMilliseconds(), kTargetDurationMs);
+
+  start_time = Now();
+  delay->EndParallel(end_times[1]);
+  EXPECT_LT((Now() - start_time).InMilliseconds(), kShortDurationMs);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_system_stats_monitor.cc b/base/trace_event/trace_event_system_stats_monitor.cc
new file mode 100644
index 0000000..98f361a
--- /dev/null
+++ b/base/trace_event/trace_event_system_stats_monitor.cc
@@ -0,0 +1,133 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/json/json_writer.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+/////////////////////////////////////////////////////////////////////////////
+// Holds profiled system stats until the tracing system needs to serialize it.
+class SystemStatsHolder : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  SystemStatsHolder() { }
+
+  // Fills system_metrics_ with profiled system memory and disk stats.
+  // Uses the previous stats to compute rates if this is not the first profile.
+  void GetSystemProfilingStats();
+
+  // base::trace_event::ConvertableToTraceFormat overrides:
+  void AppendAsTraceFormat(std::string* out) const override {
+    AppendSystemProfileAsTraceFormat(system_stats_, out);
+  }
+
+ private:
+  ~SystemStatsHolder() override {}
+
+  SystemMetrics system_stats_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemStatsHolder);
+};
+
+void SystemStatsHolder::GetSystemProfilingStats() {
+  system_stats_ = SystemMetrics::Sample();
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+TraceEventSystemStatsMonitor::TraceEventSystemStatsMonitor(
+    scoped_refptr<SingleThreadTaskRunner> task_runner)
+    : task_runner_(task_runner),
+      weak_factory_(this) {
+  // Force the "system_stats" category to show up in the trace viewer.
+  TraceLog::GetCategoryGroupEnabled(TRACE_DISABLED_BY_DEFAULT("system_stats"));
+
+  // Allow this to be instantiated on unsupported platforms, but don't run.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
+
+TraceEventSystemStatsMonitor::~TraceEventSystemStatsMonitor() {
+  if (dump_timer_.IsRunning())
+    StopProfiling();
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void TraceEventSystemStatsMonitor::OnTraceLogEnabled() {
+  // Check to see if system tracing is enabled.
+  bool enabled;
+
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT(
+                                     "system_stats"), &enabled);
+  if (!enabled)
+    return;
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&TraceEventSystemStatsMonitor::StartProfiling,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void TraceEventSystemStatsMonitor::OnTraceLogDisabled() {
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&TraceEventSystemStatsMonitor::StopProfiling,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void TraceEventSystemStatsMonitor::StartProfiling() {
+  // Watch for the tracing framework sending enabling more than once.
+  if (dump_timer_.IsRunning())
+    return;
+
+  dump_timer_.Start(FROM_HERE,
+                    TimeDelta::FromMilliseconds(TraceEventSystemStatsMonitor::
+                                                kSamplingIntervalMilliseconds),
+                    base::Bind(&TraceEventSystemStatsMonitor::
+                               DumpSystemStats,
+                               weak_factory_.GetWeakPtr()));
+}
+
+// If system tracing is enabled, dumps a profile to the tracing system.
+void TraceEventSystemStatsMonitor::DumpSystemStats() {
+  scoped_refptr<SystemStatsHolder> dump_holder = new SystemStatsHolder();
+  dump_holder->GetSystemProfilingStats();
+
+  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+      TRACE_DISABLED_BY_DEFAULT("system_stats"),
+      "base::TraceEventSystemStatsMonitor::SystemStats",
+      this,
+      scoped_refptr<ConvertableToTraceFormat>(dump_holder));
+}
+
+void TraceEventSystemStatsMonitor::StopProfiling() {
+  dump_timer_.Stop();
+}
+
+bool TraceEventSystemStatsMonitor::IsTimerRunningForTest() const {
+  return dump_timer_.IsRunning();
+}
+
+void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics,
+                                      std::string* output) {
+  std::string tmp;
+  base::JSONWriter::Write(system_metrics.ToValue().get(), &tmp);
+  *output += tmp;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_system_stats_monitor.h b/base/trace_event/trace_event_system_stats_monitor.h
new file mode 100644
index 0000000..051669a
--- /dev/null
+++ b/base/trace_event/trace_event_system_stats_monitor.h
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process_metrics.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+// Watches for chrome://tracing to be enabled or disabled. When tracing is
+// enabled, also enables system events profiling. This class is the preferred
+// way to turn system tracing on and off.
+class BASE_EXPORT TraceEventSystemStatsMonitor
+    : public TraceLog::EnabledStateObserver {
+ public:
+  // Length of time interval between stat profiles.
+  static const int kSamplingIntervalMilliseconds = 2000;
+
+  // |task_runner| must be the primary thread for the client
+  // process, e.g. the UI thread in a browser.
+  explicit TraceEventSystemStatsMonitor(
+      scoped_refptr<SingleThreadTaskRunner> task_runner);
+
+  virtual ~TraceEventSystemStatsMonitor();
+
+  // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Retrieves system profiling at the current time.
+  void DumpSystemStats();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceSystemStatsMonitorTest,
+                           TraceEventSystemStatsMonitor);
+
+  bool IsTimerRunningForTest() const;
+
+  void StartProfiling();
+
+  void StopProfiling();
+
+  // Ensures the observer starts and stops tracing on the primary thread.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  // Timer to schedule system profile dumps.
+  RepeatingTimer<TraceEventSystemStatsMonitor> dump_timer_;
+
+  WeakPtrFactory<TraceEventSystemStatsMonitor> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSystemStatsMonitor);
+};
+
+// Converts system memory profiling stats in |input| to
+// trace event compatible JSON and appends to |output|. Visible for testing.
+BASE_EXPORT void AppendSystemProfileAsTraceFormat(const SystemMetrics&
+                                                  system_stats,
+                                                  std::string* output);
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
diff --git a/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
new file mode 100644
index 0000000..03dff59
--- /dev/null
+++ b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/trace_event/trace_event_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if !defined(OS_IOS)
+// Tests for the system stats monitor.
+// Exists as a class so it can be a friend of TraceEventSystemStatsMonitor.
+class TraceSystemStatsMonitorTest : public testing::Test {
+ public:
+  TraceSystemStatsMonitorTest() {}
+  ~TraceSystemStatsMonitorTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceSystemStatsMonitorTest);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) {
+  MessageLoop message_loop;
+
+  // Start with no observers of the TraceLog.
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  // Creating a system stats monitor adds it to the TraceLog observer list.
+  scoped_ptr<TraceEventSystemStatsMonitor> system_stats_monitor(
+      new TraceEventSystemStatsMonitor(message_loop.task_runner()));
+  EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+  EXPECT_TRUE(
+      TraceLog::GetInstance()->HasEnabledStateObserver(
+          system_stats_monitor.get()));
+
+  // By default the observer isn't dumping memory profiles.
+  EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest());
+
+  // Simulate enabling tracing.
+  system_stats_monitor->StartProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(system_stats_monitor->IsTimerRunningForTest());
+
+  // Simulate disabling tracing.
+  system_stats_monitor->StopProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest());
+
+  // Deleting the observer removes it from the TraceLog observer list.
+  system_stats_monitor.reset();
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+#endif  // !defined(OS_IOS)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
new file mode 100644
index 0000000..17953e7
--- /dev/null
+++ b/base/trace_event/trace_event_unittest.cc
@@ -0,0 +1,3084 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <math.h>
+#include <cstdlib>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/location.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+enum CompareOp {
+  IS_EQUAL,
+  IS_NOT_EQUAL,
+};
+
+struct JsonKeyValue {
+  const char* key;
+  const char* value;
+  CompareOp op;
+};
+
+const int kThreadId = 42;
+const int kAsyncId = 5;
+const char kAsyncIdStr[] = "0x5";
+const int kAsyncId2 = 6;
+const char kAsyncId2Str[] = "0x6";
+
+class TraceEventTestFixture : public testing::Test {
+ public:
+  void OnTraceDataCollected(
+      WaitableEvent* flush_complete_event,
+      const scoped_refptr<base::RefCountedString>& events_str,
+      bool has_more_events);
+  void OnWatchEventMatched() {
+    ++event_watch_notification_;
+  }
+  DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values);
+  DictionaryValue* FindNamePhase(const char* name, const char* phase);
+  DictionaryValue* FindNamePhaseKeyValue(const char* name,
+                                         const char* phase,
+                                         const char* key,
+                                         const char* value);
+  void DropTracedMetadataRecords();
+  bool FindMatchingValue(const char* key,
+                         const char* value);
+  bool FindNonMatchingValue(const char* key,
+                            const char* value);
+  void Clear() {
+    trace_parsed_.Clear();
+    json_output_.json_output.clear();
+  }
+
+  void BeginTrace() {
+    BeginSpecificTrace("*");
+  }
+
+  void BeginSpecificTrace(const std::string& filter) {
+    event_watch_notification_ = 0;
+    TraceLog::GetInstance()->SetEnabled(
+        CategoryFilter(filter),
+        TraceLog::RECORDING_MODE,
+        TraceOptions());
+  }
+
+  void EndTraceAndFlush() {
+    WaitableEvent flush_complete_event(false, false);
+    EndTraceAndFlushAsync(&flush_complete_event);
+    flush_complete_event.Wait();
+  }
+
+  // Used when testing thread-local buffers which requires the thread initiating
+  // flush to have a message loop.
+  void EndTraceAndFlushInThreadWithMessageLoop() {
+    WaitableEvent flush_complete_event(false, false);
+    Thread flush_thread("flush");
+    flush_thread.Start();
+    flush_thread.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
+                              base::Unretained(this), &flush_complete_event));
+    flush_complete_event.Wait();
+  }
+
+  void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->SetDisabled();
+    TraceLog::GetInstance()->Flush(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
+  void FlushMonitoring() {
+    WaitableEvent flush_complete_event(false, false);
+    FlushMonitoring(&flush_complete_event);
+    flush_complete_event.Wait();
+  }
+
+  void FlushMonitoring(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->FlushButLeaveBufferIntact(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
+  void SetUp() override {
+    const char* name = PlatformThread::GetName();
+    old_thread_name_ = name ? strdup(name) : NULL;
+
+    TraceLog::DeleteForTesting();
+    TraceLog* tracelog = TraceLog::GetInstance();
+    ASSERT_TRUE(tracelog);
+    ASSERT_FALSE(tracelog->IsEnabled());
+    trace_buffer_.SetOutputCallback(json_output_.GetCallback());
+    event_watch_notification_ = 0;
+  }
+  void TearDown() override {
+    if (TraceLog::GetInstance())
+      EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+    PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : "");
+    free(old_thread_name_);
+    old_thread_name_ = NULL;
+    // We want our singleton torn down after each test.
+    TraceLog::DeleteForTesting();
+  }
+
+  char* old_thread_name_;
+  ListValue trace_parsed_;
+  TraceResultBuffer trace_buffer_;
+  TraceResultBuffer::SimpleOutput json_output_;
+  int event_watch_notification_;
+
+ private:
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+  Lock lock_;
+};
+
+void TraceEventTestFixture::OnTraceDataCollected(
+    WaitableEvent* flush_complete_event,
+    const scoped_refptr<base::RefCountedString>& events_str,
+    bool has_more_events) {
+  AutoLock lock(lock_);
+  json_output_.json_output.clear();
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment(events_str->data());
+  trace_buffer_.Finish();
+
+  scoped_ptr<Value> root;
+  root.reset(base::JSONReader::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()) {
+    scoped_ptr<Value> item;
+    root_list->Remove(0, &item);
+    trace_parsed_.Append(item.release());
+  }
+
+  if (!has_more_events)
+    flush_complete_event->Signal();
+}
+
+static bool CompareJsonValues(const std::string& lhs,
+                              const std::string& rhs,
+                              CompareOp op) {
+  switch (op) {
+    case IS_EQUAL:
+      return lhs == rhs;
+    case IS_NOT_EQUAL:
+      return lhs != rhs;
+    default:
+      CHECK(0);
+  }
+  return false;
+}
+
+static bool IsKeyValueInDict(const JsonKeyValue* key_value,
+                             DictionaryValue* dict) {
+  Value* value = NULL;
+  std::string value_str;
+  if (dict->Get(key_value->key, &value) &&
+      value->GetAsString(&value_str) &&
+      CompareJsonValues(value_str, key_value->value, key_value->op))
+    return true;
+
+  // Recurse to test arguments
+  DictionaryValue* args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  if (args_dict)
+    return IsKeyValueInDict(key_value, args_dict);
+
+  return false;
+}
+
+static bool IsAllKeyValueInDict(const JsonKeyValue* key_values,
+                                DictionaryValue* dict) {
+  // Scan all key_values, they must all be present and equal.
+  while (key_values && key_values->key) {
+    if (!IsKeyValueInDict(key_values, dict))
+      return false;
+    ++key_values;
+  }
+  return true;
+}
+
+DictionaryValue* TraceEventTestFixture::FindMatchingTraceEntry(
+    const JsonKeyValue* key_values) {
+  // Scan all items
+  size_t trace_parsed_count = trace_parsed_.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    Value* value = NULL;
+    trace_parsed_.Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+
+    if (IsAllKeyValueInDict(key_values, dict))
+      return dict;
+  }
+  return NULL;
+}
+
+void TraceEventTestFixture::DropTracedMetadataRecords() {
+  scoped_ptr<ListValue> old_trace_parsed(trace_parsed_.DeepCopy());
+  size_t old_trace_parsed_size = old_trace_parsed->GetSize();
+  trace_parsed_.Clear();
+
+  for (size_t i = 0; i < old_trace_parsed_size; i++) {
+    Value* value = NULL;
+    old_trace_parsed->Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY) {
+      trace_parsed_.Append(value->DeepCopy());
+      continue;
+    }
+    DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+    std::string tmp;
+    if (dict->GetString("ph", &tmp) && tmp == "M")
+      continue;
+
+    trace_parsed_.Append(value->DeepCopy());
+  }
+}
+
+DictionaryValue* TraceEventTestFixture::FindNamePhase(const char* name,
+                                                      const char* phase) {
+  JsonKeyValue key_values[] = {
+    {"name", name, IS_EQUAL},
+    {"ph", phase, IS_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+DictionaryValue* TraceEventTestFixture::FindNamePhaseKeyValue(
+    const char* name,
+    const char* phase,
+    const char* key,
+    const char* value) {
+  JsonKeyValue key_values[] = {
+    {"name", name, IS_EQUAL},
+    {"ph", phase, IS_EQUAL},
+    {key, value, IS_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+bool TraceEventTestFixture::FindMatchingValue(const char* key,
+                                              const char* value) {
+  JsonKeyValue key_values[] = {
+    {key, value, IS_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+bool TraceEventTestFixture::FindNonMatchingValue(const char* key,
+                                                 const char* value) {
+  JsonKeyValue key_values[] = {
+    {key, value, IS_NOT_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+bool IsStringInDict(const char* string_to_match, const DictionaryValue* dict) {
+  for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
+    if (it.key().find(string_to_match) != std::string::npos)
+      return true;
+
+    std::string value_str;
+    it.value().GetAsString(&value_str);
+    if (value_str.find(string_to_match) != std::string::npos)
+      return true;
+  }
+
+  // Recurse to test arguments
+  const DictionaryValue* args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  if (args_dict)
+    return IsStringInDict(string_to_match, args_dict);
+
+  return false;
+}
+
+const DictionaryValue* FindTraceEntry(
+    const ListValue& trace_parsed,
+    const char* string_to_match,
+    const DictionaryValue* match_after_this_item = NULL) {
+  // Scan all items
+  size_t trace_parsed_count = trace_parsed.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    const Value* value = NULL;
+    trace_parsed.Get(i, &value);
+    if (match_after_this_item) {
+      if (value == match_after_this_item)
+         match_after_this_item = NULL;
+      continue;
+    }
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+
+    if (IsStringInDict(string_to_match, dict))
+      return dict;
+  }
+  return NULL;
+}
+
+std::vector<const DictionaryValue*> FindTraceEntries(
+    const ListValue& trace_parsed,
+    const char* string_to_match) {
+  std::vector<const DictionaryValue*> hits;
+  size_t trace_parsed_count = trace_parsed.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    const Value* value = NULL;
+    trace_parsed.Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+
+    if (IsStringInDict(string_to_match, dict))
+      hits.push_back(dict);
+  }
+  return hits;
+}
+
+const char kControlCharacters[] = "\001\002\003\n\r";
+
+void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
+  {
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 0x1122, "extrastring1");
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 0x3344, "extrastring2");
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
+                            0x5566, "extrastring3");
+
+    TRACE_EVENT0("all", "TRACE_EVENT0 call");
+    TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
+    TRACE_EVENT2("all", "TRACE_EVENT2 call",
+                 "name1", "\"value1\"",
+                 "name2", "value\\2");
+
+    TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call",
+                         TRACE_EVENT_SCOPE_GLOBAL);
+    TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call",
+                         TRACE_EVENT_SCOPE_PROCESS, "name1", "value1");
+    TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
+                         TRACE_EVENT_SCOPE_THREAD,
+                         "name1", "value1",
+                         "name2", "value2");
+
+    TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
+    TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
+    TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
+                       "name1", "value1",
+                       "name2", "value2");
+
+    TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
+    TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
+    TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
+                     "name1", "value1",
+                     "name2", "value2");
+
+    TRACE_EVENT_ASYNC_BEGIN0("all", "TRACE_EVENT_ASYNC_BEGIN0 call", kAsyncId);
+    TRACE_EVENT_ASYNC_BEGIN1("all", "TRACE_EVENT_ASYNC_BEGIN1 call", kAsyncId,
+                             "name1", "value1");
+    TRACE_EVENT_ASYNC_BEGIN2("all", "TRACE_EVENT_ASYNC_BEGIN2 call", kAsyncId,
+                             "name1", "value1",
+                             "name2", "value2");
+
+    TRACE_EVENT_ASYNC_STEP_INTO0("all", "TRACE_EVENT_ASYNC_STEP_INTO0 call",
+                                 kAsyncId, "step_begin1");
+    TRACE_EVENT_ASYNC_STEP_INTO1("all", "TRACE_EVENT_ASYNC_STEP_INTO1 call",
+                                 kAsyncId, "step_begin2", "name1", "value1");
+
+    TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", kAsyncId);
+    TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", kAsyncId,
+                           "name1", "value1");
+    TRACE_EVENT_ASYNC_END2("all", "TRACE_EVENT_ASYNC_END2 call", kAsyncId,
+                           "name1", "value1",
+                           "name2", "value2");
+
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", kAsyncId, NULL);
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", kAsyncId, "value");
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", kAsyncId, NULL);
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW1 call", kAsyncId, "value");
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW0 call", kAsyncId, NULL);
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW1 call", kAsyncId, "value");
+
+    TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
+    TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
+                   "a", 30000,
+                   "b", 1415);
+
+    TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
+    TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
+                      "a", 30000, "b", 1415);
+
+    TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId, kThreadId, 12345);
+    TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId, kThreadId, 23456);
+
+    TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId2, kThreadId, 34567);
+    TRACE_EVENT_ASYNC_STEP_PAST0("all", "TRACE_EVENT_ASYNC_STEP_PAST0 call",
+                                 kAsyncId2, "step_end1");
+    TRACE_EVENT_ASYNC_STEP_PAST1("all", "TRACE_EVENT_ASYNC_STEP_PAST1 call",
+                                 kAsyncId2, "step_end2", "name1", "value1");
+
+    TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId2, kThreadId, 45678);
+
+    TRACE_EVENT_OBJECT_CREATED_WITH_ID("all", "tracked object 1", 0x42);
+    TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+        "all", "tracked object 1", 0x42, "hello");
+    TRACE_EVENT_OBJECT_DELETED_WITH_ID("all", "tracked object 1", 0x42);
+
+    TraceScopedTrackableObject<int> trackable("all", "tracked object 2",
+                                              0x2128506);
+    trackable.snapshot("world");
+
+    TRACE_EVENT1(kControlCharacters, kControlCharacters,
+                 kControlCharacters, kControlCharacters);
+  }  // Scope close causes TRACE_EVENT0 etc to send their END events.
+
+  if (task_complete_event)
+    task_complete_event->Signal();
+}
+
+void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
+  const DictionaryValue* item = NULL;
+
+#define EXPECT_FIND_(string) \
+    item = FindTraceEntry(trace_parsed, string); \
+    EXPECT_TRUE(item);
+#define EXPECT_NOT_FIND_(string) \
+    item = FindTraceEntry(trace_parsed, string); \
+    EXPECT_FALSE(item);
+#define EXPECT_SUB_FIND_(string) \
+    if (item) \
+      EXPECT_TRUE(IsStringInDict(string, item));
+
+  EXPECT_FIND_("ETW Trace Event");
+  EXPECT_FIND_("all");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
+  {
+    std::string str_val;
+    EXPECT_TRUE(item && item->GetString("args.id", &str_val));
+    EXPECT_STREQ("0x1122", str_val.c_str());
+  }
+  EXPECT_SUB_FIND_("extrastring1");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW call");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
+  EXPECT_FIND_("TRACE_EVENT0 call");
+  {
+    std::string ph;
+    std::string ph_end;
+    EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("X", ph);
+    item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call", item);
+    EXPECT_FALSE(item);
+  }
+  EXPECT_FIND_("TRACE_EVENT1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT2 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("\"value1\"");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value\\2");
+
+  EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
+  {
+    std::string scope;
+    EXPECT_TRUE((item && item->GetString("s", &scope)));
+    EXPECT_EQ("g", scope);
+  }
+  EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
+  {
+    std::string scope;
+    EXPECT_TRUE((item && item->GetString("s", &scope)));
+    EXPECT_EQ("p", scope);
+  }
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
+  {
+    std::string scope;
+    EXPECT_TRUE((item && item->GetString("s", &scope)));
+    EXPECT_EQ("t", scope);
+  }
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_END0 call");
+  EXPECT_FIND_("TRACE_EVENT_END1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_END2 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN2 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("step_begin1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("step_begin2");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END2 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+
+  EXPECT_FIND_("TRACE_COUNTER1 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+    EXPECT_EQ(31415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER2 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+    EXPECT_EQ(30000, value);
+
+    EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+    EXPECT_EQ(1415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_ID1 call");
+  {
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x319009", id);
+
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+    EXPECT_EQ(31415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_ID2 call");
+  {
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x319009", id);
+
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+    EXPECT_EQ(30000, value);
+
+    EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+    EXPECT_EQ(1415, value);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(12345, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncIdStr, id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(23456, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncIdStr, id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(34567, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncId2Str, id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST0 call");
+  {
+    EXPECT_SUB_FIND_("id");
+    EXPECT_SUB_FIND_(kAsyncId2Str);
+    EXPECT_SUB_FIND_("step_end1");
+    EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST1 call");
+    EXPECT_SUB_FIND_("id");
+    EXPECT_SUB_FIND_(kAsyncId2Str);
+    EXPECT_SUB_FIND_("step_end2");
+    EXPECT_SUB_FIND_("name1");
+    EXPECT_SUB_FIND_("value1");
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(45678, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncId2Str, id);
+  }
+
+  EXPECT_FIND_("tracked object 1");
+  {
+    std::string phase;
+    std::string id;
+    std::string snapshot;
+
+    EXPECT_TRUE((item && item->GetString("ph", &phase)));
+    EXPECT_EQ("N", phase);
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x42", id);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 1", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("O", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x42", id);
+    EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
+    EXPECT_EQ("hello", snapshot);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 1", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("D", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x42", id);
+  }
+
+  EXPECT_FIND_("tracked object 2");
+  {
+    std::string phase;
+    std::string id;
+    std::string snapshot;
+
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("N", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x2128506", id);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 2", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("O", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x2128506", id);
+    EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
+    EXPECT_EQ("world", snapshot);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 2", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("D", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x2128506", id);
+  }
+
+  EXPECT_FIND_(kControlCharacters);
+  EXPECT_SUB_FIND_(kControlCharacters);
+}
+
+void TraceManyInstantEvents(int thread_id, int num_events,
+                            WaitableEvent* task_complete_event) {
+  for (int i = 0; i < num_events; i++) {
+    TRACE_EVENT_INSTANT2("all", "multi thread event",
+                         TRACE_EVENT_SCOPE_THREAD,
+                         "thread", thread_id,
+                         "event", i);
+  }
+
+  if (task_complete_event)
+    task_complete_event->Signal();
+}
+
+void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
+                                              int num_threads,
+                                              int num_events) {
+  std::map<int, std::map<int, bool> > results;
+
+  size_t trace_parsed_count = trace_parsed.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    const Value* value = NULL;
+    trace_parsed.Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+    std::string name;
+    dict->GetString("name", &name);
+    if (name != "multi thread event")
+      continue;
+
+    int thread = 0;
+    int event = 0;
+    EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
+    EXPECT_TRUE(dict->GetInteger("args.event", &event));
+    results[thread][event] = true;
+  }
+
+  EXPECT_FALSE(results[-1][-1]);
+  for (int thread = 0; thread < num_threads; thread++) {
+    for (int event = 0; event < num_events; event++) {
+      EXPECT_TRUE(results[thread][event]);
+    }
+  }
+}
+
+}  // namespace
+
+// Simple Test for emitting data and validating it was received.
+TEST_F(TraceEventTestFixture, DataCaptured) {
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+
+  TraceWithAllMacroVariants(NULL);
+
+  EndTraceAndFlush();
+
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+class MockEnabledStateChangedObserver :
+      public TraceLog::EnabledStateObserver {
+ public:
+  MOCK_METHOD0(OnTraceLogEnabled, void());
+  MOCK_METHOD0(OnTraceLogDisabled, void());
+};
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) {
+  MockEnabledStateChangedObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogEnabled())
+      .Times(1);
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  testing::Mock::VerifyAndClear(&observer);
+  EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) {
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+
+  testing::StrictMock<MockEnabledStateChangedObserver> observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogEnabled())
+      .Times(0);
+  EXPECT_CALL(observer, OnTraceLogDisabled())
+      .Times(0);
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  testing::Mock::VerifyAndClear(&observer);
+  EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetDisabled();
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnFirstDisable) {
+  CategoryFilter cf_inc_all("*");
+  TraceLog::GetInstance()->SetEnabled(
+      cf_inc_all,
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TraceLog::GetInstance()->SetEnabled(
+      cf_inc_all,
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+
+  testing::StrictMock<MockEnabledStateChangedObserver> observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogEnabled())
+      .Times(0);
+  EXPECT_CALL(observer, OnTraceLogDisabled())
+      .Times(1);
+  TraceLog::GetInstance()->SetDisabled();
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+
+  MockEnabledStateChangedObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogDisabled())
+      .Times(1);
+  TraceLog::GetInstance()->SetDisabled();
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+// Tests the IsEnabled() state of TraceLog changes before callbacks.
+class AfterStateChangeEnabledStateObserver
+    : public TraceLog::EnabledStateObserver {
+ public:
+  AfterStateChangeEnabledStateObserver() {}
+  virtual ~AfterStateChangeEnabledStateObserver() {}
+
+  // TraceLog::EnabledStateObserver overrides:
+  void OnTraceLogEnabled() override {
+    EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+  }
+
+  void OnTraceLogDisabled() override {
+    EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+  }
+};
+
+TEST_F(TraceEventTestFixture, ObserversFireAfterStateChange) {
+  AfterStateChangeEnabledStateObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+  TraceLog::GetInstance()->SetDisabled();
+  EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+// Tests that a state observer can remove itself during a callback.
+class SelfRemovingEnabledStateObserver
+    : public TraceLog::EnabledStateObserver {
+ public:
+  SelfRemovingEnabledStateObserver() {}
+  virtual ~SelfRemovingEnabledStateObserver() {}
+
+  // TraceLog::EnabledStateObserver overrides:
+  void OnTraceLogEnabled() override {}
+
+  void OnTraceLogDisabled() override {
+    TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+  }
+};
+
+TEST_F(TraceEventTestFixture, SelfRemovingObserver) {
+  ASSERT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  SelfRemovingEnabledStateObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+  EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TraceLog::GetInstance()->SetDisabled();
+  // The observer removed itself on disable.
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+
+bool IsNewTrace() {
+  bool is_new_trace;
+  TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
+  return is_new_trace;
+}
+
+TEST_F(TraceEventTestFixture, NewTraceRecording) {
+  ASSERT_FALSE(IsNewTrace());
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  // First call to IsNewTrace() should succeed. But, the second shouldn't.
+  ASSERT_TRUE(IsNewTrace());
+  ASSERT_FALSE(IsNewTrace());
+  EndTraceAndFlush();
+
+  // IsNewTrace() should definitely be false now.
+  ASSERT_FALSE(IsNewTrace());
+
+  // Start another trace. IsNewTrace() should become true again, briefly, as
+  // before.
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  ASSERT_TRUE(IsNewTrace());
+  ASSERT_FALSE(IsNewTrace());
+
+  // Cleanup.
+  EndTraceAndFlush();
+}
+
+
+// Test that categories work.
+TEST_F(TraceEventTestFixture, Categories) {
+  // Test that categories that are used can be retrieved whether trace was
+  // enabled or disabled when the trace event was encountered.
+  TRACE_EVENT_INSTANT0("c1", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("c2", "name", TRACE_EVENT_SCOPE_THREAD);
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("c3", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("c4", "name", TRACE_EVENT_SCOPE_THREAD);
+  // Category groups containing more than one category.
+  TRACE_EVENT_INSTANT0("c5,c6", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("c7,c8", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("c9"), "name",
+                       TRACE_EVENT_SCOPE_THREAD);
+
+  EndTraceAndFlush();
+  std::vector<std::string> cat_groups;
+  TraceLog::GetInstance()->GetKnownCategoryGroups(&cat_groups);
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c1") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c2") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c3") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c4") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c5,c6") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c7,c8") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(),
+                        "disabled-by-default-c9") != cat_groups.end());
+  // Make sure metadata isn't returned.
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "__metadata") == cat_groups.end());
+
+  const std::vector<std::string> empty_categories;
+  std::vector<std::string> included_categories;
+  std::vector<std::string> excluded_categories;
+
+  // Test that category filtering works.
+
+  // Include nonexistent category -> no events
+  Clear();
+  included_categories.clear();
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("not_found823564786"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+  EXPECT_TRUE(trace_parsed_.empty());
+
+  // Include existent category -> only events of that category
+  Clear();
+  included_categories.clear();
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("inc"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc"));
+  EXPECT_FALSE(FindNonMatchingValue("cat", "inc"));
+
+  // Include existent wildcard -> all categories matching wildcard
+  Clear();
+  included_categories.clear();
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("inc_wildcard_*,inc_wildchar_?_end"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildcard_", "included", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat1", "not_inc", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "not_inc", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildcard_category,other_category", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0(
+      "non_included_category,inc_wildcard_category", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end"));
+  EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_category,other_category"));
+  EXPECT_TRUE(FindMatchingValue("cat",
+                                "non_included_category,inc_wildcard_category"));
+
+  included_categories.clear();
+
+  // Exclude nonexistent category -> all events
+  Clear();
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("-not_found823564786"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("category1,category2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+  EXPECT_TRUE(FindMatchingValue("cat", "category1,category2"));
+
+  // Exclude existent category -> only events of other categories
+  Clear();
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("-inc"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc2,inc", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc,inc2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
+  EXPECT_FALSE(FindMatchingValue("cat", "inc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc2,inc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc,inc2"));
+
+  // Exclude existent wildcard -> all categories not matching wildcard
+  Clear();
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("-inc_wildcard_*,-inc_wildchar_?_end"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat1", "included", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "included", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+  EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
+}
+
+
+// Test EVENT_WATCH_NOTIFICATION
+TEST_F(TraceEventTestFixture, EventWatchNotification) {
+  // Basic one occurrence.
+  BeginTrace();
+  TraceLog::WatchEventCallback callback =
+      base::Bind(&TraceEventTestFixture::OnWatchEventMatched,
+                 base::Unretained(this));
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 1);
+
+  // Auto-reset after end trace.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  EndTraceAndFlush();
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Multiple occurrence.
+  BeginTrace();
+  int num_occurrences = 5;
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  for (int i = 0; i < num_occurrences; ++i)
+    TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, num_occurrences);
+
+  // Wrong category.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TRACE_EVENT_INSTANT0("wrong_cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Wrong name.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TRACE_EVENT_INSTANT0("cat", "wrong_event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Canceled.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TraceLog::GetInstance()->CancelWatchEvent();
+  TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+}
+
+// Test ASYNC_BEGIN/END events
+TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) {
+  BeginTrace();
+
+  unsigned long long id = 0xfeedbeeffeedbeefull;
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", id);
+  TRACE_EVENT_ASYNC_STEP_INTO0("cat", "name1", id, "step1");
+  TRACE_EVENT_ASYNC_END0("cat", "name1", id);
+  TRACE_EVENT_BEGIN0("cat", "name2");
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name3", 0);
+  TRACE_EVENT_ASYNC_STEP_PAST0("cat", "name3", 0, "step2");
+
+  EndTraceAndFlush();
+
+  EXPECT_TRUE(FindNamePhase("name1", "S"));
+  EXPECT_TRUE(FindNamePhase("name1", "T"));
+  EXPECT_TRUE(FindNamePhase("name1", "F"));
+
+  std::string id_str;
+  StringAppendF(&id_str, "0x%llx", id);
+
+  EXPECT_TRUE(FindNamePhaseKeyValue("name1", "S", "id", id_str.c_str()));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name1", "T", "id", id_str.c_str()));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name1", "F", "id", id_str.c_str()));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name3", "S", "id", "0x0"));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name3", "p", "id", "0x0"));
+
+  // BEGIN events should not have id
+  EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0"));
+}
+
+// Test ASYNC_BEGIN/END events
+TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) {
+  void* ptr = this;
+
+  TraceLog::GetInstance()->SetProcessID(100);
+  BeginTrace();
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", ptr);
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name2", ptr);
+  EndTraceAndFlush();
+
+  TraceLog::GetInstance()->SetProcessID(200);
+  BeginTrace();
+  TRACE_EVENT_ASYNC_END0("cat", "name1", ptr);
+  EndTraceAndFlush();
+
+  DictionaryValue* async_begin = FindNamePhase("name1", "S");
+  DictionaryValue* async_begin2 = FindNamePhase("name2", "S");
+  DictionaryValue* async_end = FindNamePhase("name1", "F");
+  EXPECT_TRUE(async_begin);
+  EXPECT_TRUE(async_begin2);
+  EXPECT_TRUE(async_end);
+
+  Value* value = NULL;
+  std::string async_begin_id_str;
+  std::string async_begin2_id_str;
+  std::string async_end_id_str;
+  ASSERT_TRUE(async_begin->Get("id", &value));
+  ASSERT_TRUE(value->GetAsString(&async_begin_id_str));
+  ASSERT_TRUE(async_begin2->Get("id", &value));
+  ASSERT_TRUE(value->GetAsString(&async_begin2_id_str));
+  ASSERT_TRUE(async_end->Get("id", &value));
+  ASSERT_TRUE(value->GetAsString(&async_end_id_str));
+
+  EXPECT_STREQ(async_begin_id_str.c_str(), async_begin2_id_str.c_str());
+  EXPECT_STRNE(async_begin_id_str.c_str(), async_end_id_str.c_str());
+}
+
+// Test that static strings are not copied.
+TEST_F(TraceEventTestFixture, StaticStringVsString) {
+  TraceLog* tracer = TraceLog::GetInstance();
+  // Make sure old events are flushed:
+  EXPECT_EQ(0u, tracer->GetStatus().event_count);
+  const unsigned char* category_group_enabled =
+      TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat");
+
+  {
+    BeginTrace();
+    // Test that string arguments are copied.
+    TraceEventHandle handle1 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+            "arg1", std::string("argval"), "arg2", std::string("argval"));
+    // Test that static TRACE_STR_COPY string arguments are copied.
+    TraceEventHandle handle2 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+            "arg1", TRACE_STR_COPY("argval"),
+            "arg2", TRACE_STR_COPY("argval"));
+    EXPECT_GT(tracer->GetStatus().event_count, 1u);
+    const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
+    const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
+    ASSERT_TRUE(event1);
+    ASSERT_TRUE(event2);
+    EXPECT_STREQ("name1", event1->name());
+    EXPECT_STREQ("name2", event2->name());
+    EXPECT_TRUE(event1->parameter_copy_storage() != NULL);
+    EXPECT_TRUE(event2->parameter_copy_storage() != NULL);
+    EXPECT_GT(event1->parameter_copy_storage()->size(), 0u);
+    EXPECT_GT(event2->parameter_copy_storage()->size(), 0u);
+    EndTraceAndFlush();
+  }
+
+  {
+    BeginTrace();
+    // Test that static literal string arguments are not copied.
+    TraceEventHandle handle1 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+            "arg1", "argval", "arg2", "argval");
+    // Test that static TRACE_STR_COPY NULL string arguments are not copied.
+    const char* str1 = NULL;
+    const char* str2 = NULL;
+    TraceEventHandle handle2 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+            "arg1", TRACE_STR_COPY(str1),
+            "arg2", TRACE_STR_COPY(str2));
+    EXPECT_GT(tracer->GetStatus().event_count, 1u);
+    const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
+    const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
+    ASSERT_TRUE(event1);
+    ASSERT_TRUE(event2);
+    EXPECT_STREQ("name1", event1->name());
+    EXPECT_STREQ("name2", event2->name());
+    EXPECT_TRUE(event1->parameter_copy_storage() == NULL);
+    EXPECT_TRUE(event2->parameter_copy_storage() == NULL);
+    EndTraceAndFlush();
+  }
+}
+
+// Test that data sent from other threads is gathered
+TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  thread.Stop();
+
+  EndTraceAndFlush();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+// Test that data sent from multiple threads is gathered
+TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
+  BeginTrace();
+
+  const int num_threads = 4;
+  const int num_events = 4000;
+  Thread* threads[num_threads];
+  WaitableEvent* task_complete_events[num_threads];
+  for (int i = 0; i < num_threads; i++) {
+    threads[i] = new Thread(StringPrintf("Thread %d", i));
+    task_complete_events[i] = new WaitableEvent(false, false);
+    threads[i]->Start();
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents, i, num_events,
+                              task_complete_events[i]));
+  }
+
+  for (int i = 0; i < num_threads; i++) {
+    task_complete_events[i]->Wait();
+  }
+
+  // Let half of the threads end before flush.
+  for (int i = 0; i < num_threads / 2; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+
+  EndTraceAndFlushInThreadWithMessageLoop();
+  ValidateInstantEventPresentOnEveryThread(trace_parsed_,
+                                           num_threads, num_events);
+
+  // Let the other half of the threads end after flush.
+  for (int i = num_threads / 2; i < num_threads; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+}
+
+// Test that thread and process names show up in the trace
+TEST_F(TraceEventTestFixture, ThreadNames) {
+  // Create threads before we enable tracing to make sure
+  // that tracelog still captures them.
+  const int kNumThreads = 4;
+  const int kNumEvents = 10;
+  Thread* threads[kNumThreads];
+  PlatformThreadId thread_ids[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++)
+    threads[i] = new Thread(StringPrintf("Thread %d", i));
+
+  // Enable tracing.
+  BeginTrace();
+
+  // Now run some trace code on these threads.
+  WaitableEvent* task_complete_events[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    task_complete_events[i] = new WaitableEvent(false, false);
+    threads[i]->Start();
+    thread_ids[i] = threads[i]->thread_id();
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
+                              task_complete_events[i]));
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    task_complete_events[i]->Wait();
+  }
+
+  // Shut things down.
+  for (int i = 0; i < kNumThreads; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+
+  EndTraceAndFlush();
+
+  std::string tmp;
+  int tmp_int;
+  const DictionaryValue* item;
+
+  // Make sure we get thread name metadata.
+  // Note, the test suite may have created a ton of threads.
+  // So, we'll have thread names for threads we didn't create.
+  std::vector<const DictionaryValue*> items =
+      FindTraceEntries(trace_parsed_, "thread_name");
+  for (int i = 0; i < static_cast<int>(items.size()); i++) {
+    item = items[i];
+    ASSERT_TRUE(item);
+    EXPECT_TRUE(item->GetInteger("tid", &tmp_int));
+
+    // See if this thread name is one of the threads we just created
+    for (int j = 0; j < kNumThreads; j++) {
+      if(static_cast<int>(thread_ids[j]) != tmp_int)
+        continue;
+
+      std::string expected_name = StringPrintf("Thread %d", j);
+      EXPECT_TRUE(item->GetString("ph", &tmp) && tmp == "M");
+      EXPECT_TRUE(item->GetInteger("pid", &tmp_int) &&
+                  tmp_int == static_cast<int>(base::GetCurrentProcId()));
+      // If the thread name changes or the tid gets reused, the name will be
+      // a comma-separated list of thread names, so look for a substring.
+      EXPECT_TRUE(item->GetString("args.name", &tmp) &&
+                  tmp.find(expected_name) != std::string::npos);
+    }
+  }
+}
+
+TEST_F(TraceEventTestFixture, ThreadNameChanges) {
+  BeginTrace();
+
+  PlatformThread::SetName("");
+  TRACE_EVENT_INSTANT0("drink", "water", TRACE_EVENT_SCOPE_THREAD);
+
+  PlatformThread::SetName("cafe");
+  TRACE_EVENT_INSTANT0("drink", "coffee", TRACE_EVENT_SCOPE_THREAD);
+
+  PlatformThread::SetName("shop");
+  // No event here, so won't appear in combined name.
+
+  PlatformThread::SetName("pub");
+  TRACE_EVENT_INSTANT0("drink", "beer", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("drink", "wine", TRACE_EVENT_SCOPE_THREAD);
+
+  PlatformThread::SetName(" bar");
+  TRACE_EVENT_INSTANT0("drink", "whisky", TRACE_EVENT_SCOPE_THREAD);
+
+  EndTraceAndFlush();
+
+  std::vector<const DictionaryValue*> items =
+      FindTraceEntries(trace_parsed_, "thread_name");
+  EXPECT_EQ(1u, items.size());
+  ASSERT_GT(items.size(), 0u);
+  const DictionaryValue* item = items[0];
+  ASSERT_TRUE(item);
+  int tid;
+  EXPECT_TRUE(item->GetInteger("tid", &tid));
+  EXPECT_EQ(PlatformThread::CurrentId(), static_cast<PlatformThreadId>(tid));
+
+  std::string expected_name = "cafe,pub, bar";
+  std::string tmp;
+  EXPECT_TRUE(item->GetString("args.name", &tmp));
+  EXPECT_EQ(expected_name, tmp);
+}
+
+// Test that the disabled trace categories are included/excluded from the
+// trace output correctly.
+TEST_F(TraceEventTestFixture, DisabledCategories) {
+  BeginTrace();
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "first",
+                       TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("included", "first", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_NOT_FIND_("disabled-by-default-cc");
+    EXPECT_FIND_("included");
+  }
+  Clear();
+
+  BeginSpecificTrace("disabled-by-default-cc");
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "second",
+                       TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("other_included", "second", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_FIND_("disabled-by-default-cc");
+    EXPECT_FIND_("other_included");
+  }
+
+  Clear();
+
+  BeginSpecificTrace("other_included");
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc") ",other_included",
+                       "first", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("other_included," TRACE_DISABLED_BY_DEFAULT("cc"),
+                       "second", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_FIND_("disabled-by-default-cc,other_included");
+    EXPECT_FIND_("other_included,disabled-by-default-cc");
+  }
+}
+
+TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
+  // Test that the TRACE_EVENT macros do not deep-copy their string. If they
+  // do so it may indicate a performance regression, but more-over it would
+  // make the DEEP_COPY overloads redundant.
+  std::string name_string("event name");
+
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("category", name_string.c_str(),
+                       TRACE_EVENT_SCOPE_THREAD);
+
+  // Modify the string in place (a wholesale reassignment may leave the old
+  // string intact on the heap).
+  name_string[0] = '@';
+
+  EndTraceAndFlush();
+
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name"));
+  EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str()));
+}
+
+TEST_F(TraceEventTestFixture, DeepCopy) {
+  static const char kOriginalName1[] = "name1";
+  static const char kOriginalName2[] = "name2";
+  static const char kOriginalName3[] = "name3";
+  std::string name1(kOriginalName1);
+  std::string name2(kOriginalName2);
+  std::string name3(kOriginalName3);
+  std::string arg1("arg1");
+  std::string arg2("arg2");
+  std::string val1("val1");
+  std::string val2("val2");
+
+  BeginTrace();
+  TRACE_EVENT_COPY_INSTANT0("category", name1.c_str(),
+                            TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(),
+                          arg1.c_str(), 5);
+  TRACE_EVENT_COPY_END2("category", name3.c_str(),
+                        arg1.c_str(), val1,
+                        arg2.c_str(), val2);
+
+  // As per NormallyNoDeepCopy, modify the strings in place.
+  name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@';
+
+  EndTraceAndFlush();
+
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str()));
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str()));
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str()));
+
+  const DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1);
+  const DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2);
+  const DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3);
+  ASSERT_TRUE(entry1);
+  ASSERT_TRUE(entry2);
+  ASSERT_TRUE(entry3);
+
+  int i;
+  EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i));
+  EXPECT_TRUE(entry2->GetInteger("args.arg1", &i));
+  EXPECT_EQ(5, i);
+
+  std::string s;
+  EXPECT_TRUE(entry3->GetString("args.arg1", &s));
+  EXPECT_EQ("val1", s);
+  EXPECT_TRUE(entry3->GetString("args.arg2", &s));
+  EXPECT_EQ("val2", s);
+}
+
+// Test that TraceResultBuffer outputs the correct result whether it is added
+// in chunks or added all at once.
+TEST_F(TraceEventTestFixture, TraceResultBuffer) {
+  Clear();
+
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment("bla1");
+  trace_buffer_.AddFragment("bla2");
+  trace_buffer_.AddFragment("bla3,bla4");
+  trace_buffer_.Finish();
+  EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
+
+  Clear();
+
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment("bla1,bla2,bla3,bla4");
+  trace_buffer_.Finish();
+  EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
+}
+
+// Test that trace_event parameters are not evaluated if the tracing
+// system is disabled.
+TEST_F(TraceEventTestFixture, TracingIsLazy) {
+  BeginTrace();
+
+  int a = 0;
+  TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++);
+  EXPECT_EQ(1, a);
+
+  TraceLog::GetInstance()->SetDisabled();
+
+  TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++);
+  EXPECT_EQ(1, a);
+
+  EndTraceAndFlush();
+}
+
+TEST_F(TraceEventTestFixture, TraceEnableDisable) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  CategoryFilter cf_inc_all("*");
+  trace_log->SetEnabled(cf_inc_all,
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(trace_log->IsEnabled());
+  trace_log->SetDisabled();
+  EXPECT_FALSE(trace_log->IsEnabled());
+
+  trace_log->SetEnabled(cf_inc_all,
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(trace_log->IsEnabled());
+  const std::vector<std::string> empty;
+  trace_log->SetEnabled(CategoryFilter(),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(trace_log->IsEnabled());
+  trace_log->SetDisabled();
+  EXPECT_FALSE(trace_log->IsEnabled());
+  trace_log->SetDisabled();
+  EXPECT_FALSE(trace_log->IsEnabled());
+}
+
+TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  trace_log->SetEnabled(CategoryFilter("foo,bar"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
+  trace_log->SetEnabled(CategoryFilter("foo2"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo2"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
+  // The "" becomes the default catergory set when applied.
+  trace_log->SetEnabled(CategoryFilter(),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
+  EXPECT_STREQ("-*Debug,-*Test",
+               trace_log->GetCurrentCategoryFilter().ToString().c_str());
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
+
+  trace_log->SetEnabled(CategoryFilter("-foo,-bar"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
+  trace_log->SetEnabled(CategoryFilter("moo"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("moo"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_STREQ("-foo,-bar",
+               trace_log->GetCurrentCategoryFilter().ToString().c_str());
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+
+  // Make sure disabled categories aren't cleared if we set in the second.
+  trace_log->SetEnabled(CategoryFilter("disabled-by-default-cc,foo"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar"));
+  trace_log->SetEnabled(CategoryFilter("disabled-by-default-gpu"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-gpu"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
+  EXPECT_STREQ("disabled-by-default-cc,disabled-by-default-gpu",
+               trace_log->GetCurrentCategoryFilter().ToString().c_str());
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceSampling) {
+  TraceOptions trace_options(RECORD_UNTIL_FULL);
+  trace_options.enable_sampling = true;
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::RECORDING_MODE,
+                                      trace_options);
+
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Stuff");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Things");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  EndTraceAndFlush();
+
+  // Make sure we hit at least once.
+  EXPECT_TRUE(FindNamePhase("Stuff", "P"));
+  EXPECT_TRUE(FindNamePhase("Things", "P"));
+}
+
+TEST_F(TraceEventTestFixture, TraceSamplingScope) {
+  TraceOptions trace_options(RECORD_UNTIL_FULL);
+  trace_options.enable_sampling = true;
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::RECORDING_MODE,
+                                      trace_options);
+
+  TRACE_EVENT_SCOPED_SAMPLING_STATE("AAA", "name");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  {
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+    TRACE_EVENT_SCOPED_SAMPLING_STATE("BBB", "name");
+    TraceLog::GetInstance()->WaitSamplingEventForTesting();
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "BBB");
+  }
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  {
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+    TRACE_EVENT_SCOPED_SAMPLING_STATE("CCC", "name");
+    TraceLog::GetInstance()->WaitSamplingEventForTesting();
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "CCC");
+  }
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  {
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+    TRACE_EVENT_SET_SAMPLING_STATE("DDD", "name");
+    TraceLog::GetInstance()->WaitSamplingEventForTesting();
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD");
+  }
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD");
+
+  EndTraceAndFlush();
+}
+
+TEST_F(TraceEventTestFixture, TraceContinuousSampling) {
+  TraceOptions trace_options(RECORD_UNTIL_FULL);
+  trace_options.enable_sampling = true;
+
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::MONITORING_MODE,
+                                      trace_options);
+
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "AAA");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "BBB");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  FlushMonitoring();
+
+  // Make sure we can get the profiled data.
+  EXPECT_TRUE(FindNamePhase("AAA", "P"));
+  EXPECT_TRUE(FindNamePhase("BBB", "P"));
+
+  Clear();
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "CCC");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "DDD");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  FlushMonitoring();
+
+  // Make sure the profiled data is accumulated.
+  EXPECT_TRUE(FindNamePhase("AAA", "P"));
+  EXPECT_TRUE(FindNamePhase("BBB", "P"));
+  EXPECT_TRUE(FindNamePhase("CCC", "P"));
+  EXPECT_TRUE(FindNamePhase("DDD", "P"));
+
+  Clear();
+
+  TraceLog::GetInstance()->SetDisabled();
+
+  // Make sure disabling the continuous sampling thread clears
+  // the profiled data.
+  EXPECT_FALSE(FindNamePhase("AAA", "P"));
+  EXPECT_FALSE(FindNamePhase("BBB", "P"));
+  EXPECT_FALSE(FindNamePhase("CCC", "P"));
+  EXPECT_FALSE(FindNamePhase("DDD", "P"));
+
+  Clear();
+}
+
+class MyData : public ConvertableToTraceFormat {
+ public:
+  MyData() {}
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append("{\"foo\":1}");
+  }
+
+ private:
+  ~MyData() override {}
+  DISALLOW_COPY_AND_ASSIGN(MyData);
+};
+
+TEST_F(TraceEventTestFixture, ConvertableTypes) {
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+
+  scoped_refptr<ConvertableToTraceFormat> data(new MyData());
+  scoped_refptr<ConvertableToTraceFormat> data1(new MyData());
+  scoped_refptr<ConvertableToTraceFormat> data2(new MyData());
+  TRACE_EVENT1("foo", "bar", "data", data);
+  TRACE_EVENT2("foo", "baz",
+               "data1", data1,
+               "data2", data2);
+
+
+  scoped_refptr<ConvertableToTraceFormat> convertData1(new MyData());
+  scoped_refptr<ConvertableToTraceFormat> convertData2(new MyData());
+  TRACE_EVENT2(
+      "foo",
+      "string_first",
+      "str",
+      "string value 1",
+      "convert",
+      convertData1);
+  TRACE_EVENT2(
+      "foo",
+      "string_second",
+      "convert",
+      convertData2,
+      "str",
+      "string value 2");
+  EndTraceAndFlush();
+
+  // One arg version.
+  DictionaryValue* dict = FindNamePhase("bar", "X");
+  ASSERT_TRUE(dict);
+
+  const DictionaryValue* args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  const Value* value = NULL;
+  const DictionaryValue* convertable_dict = NULL;
+  EXPECT_TRUE(args_dict->Get("data", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+  int foo_val;
+  EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+  EXPECT_EQ(1, foo_val);
+
+  // Two arg version.
+  dict = FindNamePhase("baz", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  value = NULL;
+  convertable_dict = NULL;
+  EXPECT_TRUE(args_dict->Get("data1", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+  value = NULL;
+  convertable_dict = NULL;
+  EXPECT_TRUE(args_dict->Get("data2", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+  // Convertable with other types.
+  dict = FindNamePhase("string_first", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  std::string str_value;
+  EXPECT_TRUE(args_dict->GetString("str", &str_value));
+  EXPECT_STREQ("string value 1", str_value.c_str());
+
+  value = NULL;
+  convertable_dict = NULL;
+  foo_val = 0;
+  EXPECT_TRUE(args_dict->Get("convert", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+  EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+  EXPECT_EQ(1, foo_val);
+
+  dict = FindNamePhase("string_second", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  EXPECT_TRUE(args_dict->GetString("str", &str_value));
+  EXPECT_STREQ("string value 2", str_value.c_str());
+
+  value = NULL;
+  convertable_dict = NULL;
+  foo_val = 0;
+  EXPECT_TRUE(args_dict->Get("convert", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+  EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+  EXPECT_EQ(1, foo_val);
+}
+
+TEST_F(TraceEventTestFixture, PrimitiveArgs) {
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+
+  TRACE_EVENT1("foo", "event1", "int_one", 1);
+  TRACE_EVENT1("foo", "event2", "int_neg_ten", -10);
+  TRACE_EVENT1("foo", "event3", "float_one", 1.0f);
+  TRACE_EVENT1("foo", "event4", "float_half", .5f);
+  TRACE_EVENT1("foo", "event5", "float_neghalf", -.5f);
+  TRACE_EVENT1("foo", "event6", "float_infinity",
+      std::numeric_limits<float>::infinity());
+  TRACE_EVENT1("foo", "event6b", "float_neg_infinity",
+      -std::numeric_limits<float>::infinity());
+  TRACE_EVENT1("foo", "event7", "double_nan",
+      std::numeric_limits<double>::quiet_NaN());
+  void* p = 0;
+  TRACE_EVENT1("foo", "event8", "pointer_null", p);
+  p = reinterpret_cast<void*>(0xbadf00d);
+  TRACE_EVENT1("foo", "event9", "pointer_badf00d", p);
+  TRACE_EVENT1("foo", "event10", "bool_true", true);
+  TRACE_EVENT1("foo", "event11", "bool_false", false);
+  TRACE_EVENT1("foo", "event12", "time_null",
+      base::Time());
+  TRACE_EVENT1("foo", "event13", "time_one",
+      base::Time::FromInternalValue(1));
+  TRACE_EVENT1("foo", "event14", "timeticks_null",
+      base::TimeTicks());
+  TRACE_EVENT1("foo", "event15", "timeticks_one",
+      base::TimeTicks::FromInternalValue(1));
+  EndTraceAndFlush();
+
+  const DictionaryValue* args_dict = NULL;
+  DictionaryValue* dict = NULL;
+  const Value* value = NULL;
+  std::string str_value;
+  int int_value;
+  double double_value;
+  bool bool_value;
+
+  dict = FindNamePhase("event1", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value));
+  EXPECT_EQ(1, int_value);
+
+  dict = FindNamePhase("event2", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("int_neg_ten", &int_value));
+  EXPECT_EQ(-10, int_value);
+
+  // 1f must be serlized to JSON as "1.0" in order to be a double, not an int.
+  dict = FindNamePhase("event3", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->Get("float_one", &value));
+  EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
+  EXPECT_TRUE(value->GetAsDouble(&double_value));
+  EXPECT_EQ(1, double_value);
+
+  // .5f must be serlized to JSON as "0.5".
+  dict = FindNamePhase("event4", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->Get("float_half", &value));
+  EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
+  EXPECT_TRUE(value->GetAsDouble(&double_value));
+  EXPECT_EQ(0.5, double_value);
+
+  // -.5f must be serlized to JSON as "-0.5".
+  dict = FindNamePhase("event5", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->Get("float_neghalf", &value));
+  EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
+  EXPECT_TRUE(value->GetAsDouble(&double_value));
+  EXPECT_EQ(-0.5, double_value);
+
+  // Infinity is serialized to JSON as a string.
+  dict = FindNamePhase("event6", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("float_infinity", &str_value));
+  EXPECT_STREQ("Infinity", str_value.c_str());
+  dict = FindNamePhase("event6b", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("float_neg_infinity", &str_value));
+  EXPECT_STREQ("-Infinity", str_value.c_str());
+
+  // NaN is serialized to JSON as a string.
+  dict = FindNamePhase("event7", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("double_nan", &str_value));
+  EXPECT_STREQ("NaN", str_value.c_str());
+
+  // NULL pointers should be serialized as "0x0".
+  dict = FindNamePhase("event8", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("pointer_null", &str_value));
+  EXPECT_STREQ("0x0", str_value.c_str());
+
+  // Other pointers should be serlized as a hex string.
+  dict = FindNamePhase("event9", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("pointer_badf00d", &str_value));
+  EXPECT_STREQ("0xbadf00d", str_value.c_str());
+
+  dict = FindNamePhase("event10", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetBoolean("bool_true", &bool_value));
+  EXPECT_TRUE(bool_value);
+
+  dict = FindNamePhase("event11", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetBoolean("bool_false", &bool_value));
+  EXPECT_FALSE(bool_value);
+
+  dict = FindNamePhase("event12", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("time_null", &int_value));
+  EXPECT_EQ(0, int_value);
+
+  dict = FindNamePhase("event13", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("time_one", &int_value));
+  EXPECT_EQ(1, int_value);
+
+  dict = FindNamePhase("event14", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("timeticks_null", &int_value));
+  EXPECT_EQ(0, int_value);
+
+  dict = FindNamePhase("event15", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("timeticks_one", &int_value));
+  EXPECT_EQ(1, int_value);
+}
+
+class TraceEventCallbackTest : public TraceEventTestFixture {
+ public:
+  void SetUp() override {
+    TraceEventTestFixture::SetUp();
+    ASSERT_EQ(NULL, s_instance);
+    s_instance = this;
+  }
+  void TearDown() override {
+    TraceLog::GetInstance()->SetDisabled();
+    ASSERT_TRUE(!!s_instance);
+    s_instance = NULL;
+    TraceEventTestFixture::TearDown();
+  }
+
+ protected:
+  // For TraceEventCallbackAndRecordingX tests.
+  void VerifyCallbackAndRecordedEvents(size_t expected_callback_count,
+                                       size_t expected_recorded_count) {
+    // Callback events.
+    EXPECT_EQ(expected_callback_count, collected_events_names_.size());
+    for (size_t i = 0; i < collected_events_names_.size(); ++i) {
+      EXPECT_EQ("callback", collected_events_categories_[i]);
+      EXPECT_EQ("yes", collected_events_names_[i]);
+    }
+
+    // Recorded events.
+    EXPECT_EQ(expected_recorded_count, trace_parsed_.GetSize());
+    EXPECT_TRUE(FindTraceEntry(trace_parsed_, "recording"));
+    EXPECT_FALSE(FindTraceEntry(trace_parsed_, "callback"));
+    EXPECT_TRUE(FindTraceEntry(trace_parsed_, "yes"));
+    EXPECT_FALSE(FindTraceEntry(trace_parsed_, "no"));
+  }
+
+  void VerifyCollectedEvent(size_t i,
+                            unsigned phase,
+                            const std::string& category,
+                            const std::string& name) {
+    EXPECT_EQ(phase, collected_events_phases_[i]);
+    EXPECT_EQ(category, collected_events_categories_[i]);
+    EXPECT_EQ(name, collected_events_names_[i]);
+  }
+
+  std::vector<std::string> collected_events_categories_;
+  std::vector<std::string> collected_events_names_;
+  std::vector<unsigned char> collected_events_phases_;
+  std::vector<TimeTicks> collected_events_timestamps_;
+
+  static TraceEventCallbackTest* s_instance;
+  static void Callback(TimeTicks timestamp,
+                       char phase,
+                       const unsigned char* category_group_enabled,
+                       const char* name,
+                       unsigned long long id,
+                       int num_args,
+                       const char* const arg_names[],
+                       const unsigned char arg_types[],
+                       const unsigned long long arg_values[],
+                       unsigned char flags) {
+    s_instance->collected_events_phases_.push_back(phase);
+    s_instance->collected_events_categories_.push_back(
+        TraceLog::GetCategoryGroupName(category_group_enabled));
+    s_instance->collected_events_names_.push_back(name);
+    s_instance->collected_events_timestamps_.push_back(timestamp);
+  }
+};
+
+TraceEventCallbackTest* TraceEventCallbackTest::s_instance;
+
+TEST_F(TraceEventCallbackTest, TraceEventCallback) {
+  TRACE_EVENT_INSTANT0("all", "before enable", TRACE_EVENT_SCOPE_THREAD);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(
+      CategoryFilter("*"), Callback);
+  TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL);
+  {
+    TRACE_EVENT0("all", "duration");
+    TRACE_EVENT_INSTANT0("all", "event3", TRACE_EVENT_SCOPE_GLOBAL);
+  }
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("all", "after callback removed",
+                       TRACE_EVENT_SCOPE_GLOBAL);
+  ASSERT_EQ(5u, collected_events_names_.size());
+  EXPECT_EQ("event1", collected_events_names_[0]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[0]);
+  EXPECT_EQ("event2", collected_events_names_[1]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[1]);
+  EXPECT_EQ("duration", collected_events_names_[2]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_BEGIN, collected_events_phases_[2]);
+  EXPECT_EQ("event3", collected_events_names_[3]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[3]);
+  EXPECT_EQ("duration", collected_events_names_[4]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_END, collected_events_phases_[4]);
+  for (size_t i = 1; i < collected_events_timestamps_.size(); i++) {
+    EXPECT_LE(collected_events_timestamps_[i - 1],
+              collected_events_timestamps_[i]);
+  }
+}
+
+TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  do {
+    TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL);
+  } while (!TraceLog::GetInstance()->BufferIsFull());
+  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  ASSERT_EQ(1u, collected_events_names_.size());
+  EXPECT_EQ("a snake", collected_events_names_[0]);
+}
+
+// 1: Enable callback, enable recording, disable callback, disable recording.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording1) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("recording"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(2, 2);
+}
+
+// 2: Enable callback, enable recording, disable recording, disable callback.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording2) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("recording"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(3, 1);
+}
+
+// 3: Enable recording, enable callback, disable callback, disable recording.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording3) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("recording"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(1, 3);
+}
+
+// 4: Enable recording, enable callback, disable recording, disable callback.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording4) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("recording"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions());
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(2, 2);
+}
+
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecordingDuration) {
+  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
+                                                   Callback);
+  {
+    TRACE_EVENT0("callback", "duration1");
+    TraceLog::GetInstance()->SetEnabled(
+        CategoryFilter("*"),
+        TraceLog::RECORDING_MODE,
+        TraceOptions());
+    TRACE_EVENT0("callback", "duration2");
+    EndTraceAndFlush();
+    TRACE_EVENT0("callback", "duration3");
+  }
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+
+  ASSERT_EQ(6u, collected_events_names_.size());
+  VerifyCollectedEvent(0, TRACE_EVENT_PHASE_BEGIN, "callback", "duration1");
+  VerifyCollectedEvent(1, TRACE_EVENT_PHASE_BEGIN, "callback", "duration2");
+  VerifyCollectedEvent(2, TRACE_EVENT_PHASE_BEGIN, "callback", "duration3");
+  VerifyCollectedEvent(3, TRACE_EVENT_PHASE_END, "callback", "duration3");
+  VerifyCollectedEvent(4, TRACE_EVENT_PHASE_END, "callback", "duration2");
+  VerifyCollectedEvent(5, TRACE_EVENT_PHASE_END, "callback", "duration1");
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  trace_log->SetEnabled(CategoryFilter("*"),
+                        TraceLog::RECORDING_MODE,
+                        TraceOptions());
+  trace_log->logged_events_.reset(
+      trace_log->CreateTraceBufferVectorOfSize(100));
+  do {
+    TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
+        "all", "with_timestamp", 0, 0,
+        TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+    TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
+        "all", "with_timestamp", 0, 0,
+        TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+  } while (!trace_log->BufferIsFull());
+
+  EndTraceAndFlush();
+
+  const DictionaryValue* trace_full_metadata = NULL;
+
+  trace_full_metadata = FindTraceEntry(trace_parsed_,
+                                       "overflowed_at_ts");
+  std::string phase;
+  double buffer_limit_reached_timestamp = 0;
+
+  EXPECT_TRUE(trace_full_metadata);
+  EXPECT_TRUE(trace_full_metadata->GetString("ph", &phase));
+  EXPECT_EQ("M", phase);
+  EXPECT_TRUE(trace_full_metadata->GetDouble(
+      "args.overflowed_at_ts", &buffer_limit_reached_timestamp));
+  EXPECT_DOUBLE_EQ(
+      static_cast<double>(
+          trace_log->buffer_limit_reached_timestamp_.ToInternalValue()),
+      buffer_limit_reached_timestamp);
+
+  // Test that buffer_limit_reached_timestamp's value is between the timestamp
+  // of the last trace event and current time.
+  DropTracedMetadataRecords();
+  const DictionaryValue* last_trace_event = NULL;
+  double last_trace_event_timestamp = 0;
+  EXPECT_TRUE(trace_parsed_.GetDictionary(trace_parsed_.GetSize() - 1,
+                                          &last_trace_event));
+  EXPECT_TRUE(last_trace_event->GetDouble("ts", &last_trace_event_timestamp));
+  EXPECT_LE(last_trace_event_timestamp, buffer_limit_reached_timestamp);
+  EXPECT_LE(buffer_limit_reached_timestamp,
+            trace_log->OffsetNow().ToInternalValue());
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) {
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::RECORDING_MODE,
+                                      TraceOptions(RECORD_CONTINUOUSLY));
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  size_t capacity = buffer->Capacity();
+  size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
+  uint32 last_seq = 0;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+
+  scoped_ptr<TraceBufferChunk*[]> chunks(new TraceBufferChunk*[num_chunks]);
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+    EXPECT_GT(chunks[i]->seq(), last_seq);
+    EXPECT_EQ((i + 1) * TraceBufferChunk::kTraceBufferChunkSize,
+              buffer->Size());
+    last_seq = chunks[i]->seq();
+  }
+
+  // Ring buffer is never full.
+  EXPECT_FALSE(buffer->IsFull());
+
+  // Return all chunks in original order.
+  for (size_t i = 0; i < num_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  // Should recycle the chunks in the returned order.
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+    EXPECT_GT(chunks[i]->seq(), last_seq);
+    last_seq = chunks[i]->seq();
+  }
+
+  // Return all chunks in reverse order.
+  for (size_t i = 0; i < num_chunks; ++i) {
+    buffer->ReturnChunk(
+        num_chunks - i - 1,
+        scoped_ptr<TraceBufferChunk>(chunks[num_chunks - i - 1]));
+  }
+
+  // Should recycle the chunks in the returned order.
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(num_chunks - i - 1, chunk_index);
+    EXPECT_GT(chunks[i]->seq(), last_seq);
+    last_seq = chunks[i]->seq();
+  }
+
+  for (size_t i = 0; i < num_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferRingBufferHalfIteration) {
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::RECORDING_MODE,
+                                      TraceOptions(RECORD_CONTINUOUSLY));
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  size_t capacity = buffer->Capacity();
+  size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+  EXPECT_FALSE(buffer->NextChunk());
+
+  size_t half_chunks = num_chunks / 2;
+  scoped_ptr<TraceBufferChunk*[]> chunks(new TraceBufferChunk*[half_chunks]);
+
+  for (size_t i = 0; i < half_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+  }
+  for (size_t i = 0; i < half_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  for (size_t i = 0; i < half_chunks; ++i)
+    EXPECT_EQ(chunks[i], buffer->NextChunk());
+  EXPECT_FALSE(buffer->NextChunk());
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferRingBufferFullIteration) {
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::RECORDING_MODE,
+                                      TraceOptions(RECORD_CONTINUOUSLY));
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  size_t capacity = buffer->Capacity();
+  size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+  EXPECT_FALSE(buffer->NextChunk());
+
+  scoped_ptr<TraceBufferChunk*[]> chunks(new TraceBufferChunk*[num_chunks]);
+
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+  }
+  for (size_t i = 0; i < num_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  for (size_t i = 0; i < num_chunks; ++i)
+    EXPECT_TRUE(chunks[i] == buffer->NextChunk());
+  EXPECT_FALSE(buffer->NextChunk());
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceRecordAsMuchAsPossibleMode) {
+  TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+                                      TraceLog::RECORDING_MODE,
+                                      TraceOptions(RECORD_AS_MUCH_AS_POSSIBLE));
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  EXPECT_EQ(512000000UL, buffer->Capacity());
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+// Test the category filter.
+TEST_F(TraceEventTestFixture, CategoryFilter) {
+  // Using the default filter.
+  CategoryFilter default_cf = CategoryFilter(
+      CategoryFilter::kDefaultCategoryFilterString);
+  std::string category_filter_str = default_cf.ToString();
+  EXPECT_STREQ("-*Debug,-*Test", category_filter_str.c_str());
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("not-excluded-category"));
+  EXPECT_FALSE(
+      default_cf.IsCategoryGroupEnabled("disabled-by-default-category"));
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
+
+  // Make sure that upon an empty string, we fall back to the default filter.
+  default_cf = CategoryFilter();
+  category_filter_str = default_cf.ToString();
+  EXPECT_STREQ("-*Debug,-*Test", category_filter_str.c_str());
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("not-excluded-category"));
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+  EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
+
+  // Using an arbitrary non-empty filter.
+  CategoryFilter cf("included,-excluded,inc_pattern*,-exc_pattern*");
+  category_filter_str = cf.ToString();
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               category_filter_str.c_str());
+  EXPECT_TRUE(cf.IsCategoryGroupEnabled("included"));
+  EXPECT_TRUE(cf.IsCategoryGroupEnabled("inc_pattern_category"));
+  EXPECT_FALSE(cf.IsCategoryGroupEnabled("exc_pattern_category"));
+  EXPECT_FALSE(cf.IsCategoryGroupEnabled("excluded"));
+  EXPECT_FALSE(cf.IsCategoryGroupEnabled("not-excluded-nor-included"));
+  EXPECT_FALSE(cf.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+  EXPECT_FALSE(cf.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+  EXPECT_FALSE(cf.IsCategoryGroupEnabled("CategoryTest,Category2"));
+
+  cf.Merge(default_cf);
+  category_filter_str = cf.ToString();
+  EXPECT_STREQ("-excluded,-exc_pattern*,-*Debug,-*Test",
+                category_filter_str.c_str());
+  cf.Clear();
+
+  CategoryFilter reconstructed_cf(category_filter_str);
+  category_filter_str = reconstructed_cf.ToString();
+  EXPECT_STREQ("-excluded,-exc_pattern*,-*Debug,-*Test",
+               category_filter_str.c_str());
+
+  // One included category.
+  CategoryFilter one_inc_cf("only_inc_cat");
+  category_filter_str = one_inc_cf.ToString();
+  EXPECT_STREQ("only_inc_cat", category_filter_str.c_str());
+
+  // One excluded category.
+  CategoryFilter one_exc_cf("-only_exc_cat");
+  category_filter_str = one_exc_cf.ToString();
+  EXPECT_STREQ("-only_exc_cat", category_filter_str.c_str());
+
+  // Enabling a disabled- category does not require all categories to be traced
+  // to be included.
+  CategoryFilter disabled_cat("disabled-by-default-cc,-excluded");
+  EXPECT_STREQ("disabled-by-default-cc,-excluded",
+               disabled_cat.ToString().c_str());
+  EXPECT_TRUE(disabled_cat.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(disabled_cat.IsCategoryGroupEnabled("some_other_group"));
+  EXPECT_FALSE(disabled_cat.IsCategoryGroupEnabled("excluded"));
+
+  // Enabled a disabled- category and also including makes all categories to
+  // be traced require including.
+  CategoryFilter disabled_inc_cat("disabled-by-default-cc,included");
+  EXPECT_STREQ("included,disabled-by-default-cc",
+               disabled_inc_cat.ToString().c_str());
+  EXPECT_TRUE(
+      disabled_inc_cat.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(disabled_inc_cat.IsCategoryGroupEnabled("included"));
+  EXPECT_FALSE(disabled_inc_cat.IsCategoryGroupEnabled("other_included"));
+
+  // Test that IsEmptyOrContainsLeadingOrTrailingWhitespace actually catches
+  // categories that are explicitly forbiden.
+  // This method is called in a DCHECK to assert that we don't have these types
+  // of strings as categories.
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      " bad_category "));
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      " bad_category"));
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "bad_category "));
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "   bad_category"));
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "bad_category   "));
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "   bad_category   "));
+  EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      ""));
+  EXPECT_FALSE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "good_category"));
+}
+
+void BlockUntilStopped(WaitableEvent* task_start_event,
+                       WaitableEvent* task_stop_event) {
+  task_start_event->Signal();
+  task_stop_event->Wait();
+}
+
+TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopBeforeTracing) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceLog::SetCurrentThreadBlocksMessageLoop,
+                      Unretained(TraceLog::GetInstance())));
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+
+  EndTraceAndFlush();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+
+  task_stop_event.Signal();
+  thread.Stop();
+}
+
+TEST_F(TraceEventTestFixture, ConvertTraceOptionsToInternalOptions) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  TraceOptions options(RECORD_UNTIL_FULL);
+  EXPECT_EQ(TraceLog::kInternalRecordUntilFull,
+            trace_log->GetInternalOptionsFromTraceOptions(options));
+
+  options.record_mode = RECORD_CONTINUOUSLY;
+  EXPECT_EQ(TraceLog::kInternalRecordContinuously,
+            trace_log->GetInternalOptionsFromTraceOptions(options));
+
+  options.record_mode = ECHO_TO_CONSOLE;
+  EXPECT_EQ(TraceLog::kInternalEchoToConsole,
+            trace_log->GetInternalOptionsFromTraceOptions(options));
+
+  options.enable_sampling = true;
+
+  options.record_mode = RECORD_UNTIL_FULL;
+  EXPECT_EQ(
+      TraceLog::kInternalRecordUntilFull | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceOptions(options));
+
+  options.record_mode = RECORD_CONTINUOUSLY;
+  EXPECT_EQ(
+      TraceLog::kInternalRecordContinuously | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceOptions(options));
+
+  options.record_mode = ECHO_TO_CONSOLE;
+  EXPECT_EQ(
+      TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceOptions(options));
+
+  options.enable_systrace = true;
+  EXPECT_EQ(
+      TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceOptions(options));
+}
+
+void SetBlockingFlagAndBlockUntilStopped(WaitableEvent* task_start_event,
+                                         WaitableEvent* task_stop_event) {
+  TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
+  BlockUntilStopped(task_start_event, task_stop_event);
+}
+
+TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopAfterTracing) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped, &task_start_event,
+                      &task_stop_event));
+  task_start_event.Wait();
+
+  EndTraceAndFlush();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+
+  task_stop_event.Signal();
+  thread.Stop();
+}
+
+TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  task_complete_event.Reset();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+
+  // The thread will timeout in this flush.
+  EndTraceAndFlushInThreadWithMessageLoop();
+  Clear();
+
+  // Let the thread's message loop continue to spin.
+  task_stop_event.Signal();
+
+  // The following sequence ensures that the FlushCurrentThread task has been
+  // executed in the thread before continuing.
+  task_start_event.Reset();
+  task_stop_event.Reset();
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+  task_stop_event.Signal();
+  Clear();
+
+  // TraceLog should discover the generation mismatch and recover the thread
+  // local buffer for the thread without any error.
+  BeginTrace();
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  task_complete_event.Reset();
+  EndTraceAndFlushInThreadWithMessageLoop();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+std::string* g_log_buffer = NULL;
+bool MockLogMessageHandler(int, const char*, int, size_t,
+                           const std::string& str) {
+  if (!g_log_buffer)
+    g_log_buffer = new std::string();
+  g_log_buffer->append(str);
+  return false;
+}
+
+TEST_F(TraceEventTestFixture, EchoToConsole) {
+  logging::LogMessageHandlerFunction old_log_message_handler =
+      logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(MockLogMessageHandler);
+
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions(ECHO_TO_CONSOLE));
+  TRACE_EVENT_BEGIN0("a", "begin_end");
+  {
+    TRACE_EVENT0("b", "duration");
+    TRACE_EVENT0("b1", "duration1");
+  }
+  TRACE_EVENT_INSTANT0("c", "instant", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_END0("a", "begin_end");
+
+  EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1] ("));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b] ("));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| instant[c]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a] ("));
+
+  EndTraceAndFlush();
+  delete g_log_buffer;
+  logging::SetLogMessageHandler(old_log_message_handler);
+  g_log_buffer = NULL;
+}
+
+bool LogMessageHandlerWithTraceEvent(int, const char*, int, size_t,
+                                     const std::string&) {
+  TRACE_EVENT0("log", "trace_event");
+  return false;
+}
+
+TEST_F(TraceEventTestFixture, EchoToConsoleTraceEventRecursion) {
+  logging::LogMessageHandlerFunction old_log_message_handler =
+      logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(LogMessageHandlerWithTraceEvent);
+
+  TraceLog::GetInstance()->SetEnabled(
+      CategoryFilter("*"),
+      TraceLog::RECORDING_MODE,
+      TraceOptions(ECHO_TO_CONSOLE));
+  {
+    // This should not cause deadlock or infinite recursion.
+    TRACE_EVENT0("b", "duration");
+  }
+
+  EndTraceAndFlush();
+  logging::SetLogMessageHandler(old_log_message_handler);
+}
+
+TEST_F(TraceEventTestFixture, TimeOffset) {
+  BeginTrace();
+  // Let TraceLog timer start from 0.
+  TimeDelta time_offset = TimeTicks::NowFromSystemTraceTime() - TimeTicks();
+  TraceLog::GetInstance()->SetTimeOffset(time_offset);
+
+  {
+    TRACE_EVENT0("all", "duration1");
+    TRACE_EVENT0("all", "duration2");
+  }
+  TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
+      "all", "with_timestamp", 0, 0,
+      TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+  TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
+      "all", "with_timestamp", 0, 0,
+      TimeTicks::NowFromSystemTraceTime().ToInternalValue());
+
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+
+  double end_time = static_cast<double>(
+      (TimeTicks::NowFromSystemTraceTime() - time_offset).ToInternalValue());
+  double last_timestamp = 0;
+  for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) {
+    const DictionaryValue* item;
+    EXPECT_TRUE(trace_parsed_.GetDictionary(i, &item));
+    double timestamp;
+    EXPECT_TRUE(item->GetDouble("ts", &timestamp));
+    EXPECT_GE(timestamp, last_timestamp);
+    EXPECT_LE(timestamp, end_time);
+    last_timestamp = timestamp;
+  }
+}
+
+TEST_F(TraceEventTestFixture, ConfigureSyntheticDelays) {
+  BeginSpecificTrace("DELAY(test.Delay;0.05)");
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  {
+    TRACE_EVENT_SYNTHETIC_DELAY("test.Delay");
+  }
+  base::TimeDelta duration = base::TimeTicks::Now() - start;
+  EXPECT_GE(duration.InMilliseconds(), 50);
+
+  EndTraceAndFlush();
+}
+
+TEST_F(TraceEventTestFixture, BadSyntheticDelayConfigurations) {
+  const char* const configs[] = {
+    "",
+    "DELAY(",
+    "DELAY(;",
+    "DELAY(;)",
+    "DELAY(test.Delay)",
+    "DELAY(test.Delay;)"
+  };
+  for (size_t i = 0; i < arraysize(configs); i++) {
+    BeginSpecificTrace(configs[i]);
+    EndTraceAndFlush();
+    CategoryFilter filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
+    EXPECT_EQ(0u, filter.GetSyntheticDelayValues().size());
+  }
+}
+
+TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationMerging) {
+  CategoryFilter filter1("DELAY(test.Delay1;16)");
+  CategoryFilter filter2("DELAY(test.Delay2;32)");
+  filter1.Merge(filter2);
+  EXPECT_EQ(2u, filter1.GetSyntheticDelayValues().size());
+}
+
+TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationToString) {
+  const char config[] = "DELAY(test.Delay;16;oneshot)";
+  CategoryFilter filter(config);
+  EXPECT_EQ(config, filter.ToString());
+}
+
+TEST(TraceOptionsTest, TraceOptionsFromString) {
+  TraceOptions options;
+  EXPECT_TRUE(options.SetFromString("record-until-full"));
+  EXPECT_EQ(RECORD_UNTIL_FULL, options.record_mode);
+  EXPECT_FALSE(options.enable_sampling);
+  EXPECT_FALSE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString("record-continuously"));
+  EXPECT_EQ(RECORD_CONTINUOUSLY, options.record_mode);
+  EXPECT_FALSE(options.enable_sampling);
+  EXPECT_FALSE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString("trace-to-console"));
+  EXPECT_EQ(ECHO_TO_CONSOLE, options.record_mode);
+  EXPECT_FALSE(options.enable_sampling);
+  EXPECT_FALSE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString("record-as-much-as-possible"));
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, options.record_mode);
+  EXPECT_FALSE(options.enable_sampling);
+  EXPECT_FALSE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString("record-until-full, enable-sampling"));
+  EXPECT_EQ(RECORD_UNTIL_FULL, options.record_mode);
+  EXPECT_TRUE(options.enable_sampling);
+  EXPECT_FALSE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString("enable-systrace,record-continuously"));
+  EXPECT_EQ(RECORD_CONTINUOUSLY, options.record_mode);
+  EXPECT_FALSE(options.enable_sampling);
+  EXPECT_TRUE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString(
+      "enable-systrace, trace-to-console,enable-sampling"));
+  EXPECT_EQ(ECHO_TO_CONSOLE, options.record_mode);
+  EXPECT_TRUE(options.enable_sampling);
+  EXPECT_TRUE(options.enable_systrace);
+
+  EXPECT_TRUE(options.SetFromString(
+      "record-continuously,record-until-full,trace-to-console"));
+  EXPECT_EQ(ECHO_TO_CONSOLE, options.record_mode);
+  EXPECT_FALSE(options.enable_systrace);
+  EXPECT_FALSE(options.enable_sampling);
+
+  EXPECT_TRUE(options.SetFromString(""));
+  EXPECT_EQ(RECORD_UNTIL_FULL, options.record_mode);
+  EXPECT_FALSE(options.enable_systrace);
+  EXPECT_FALSE(options.enable_sampling);
+
+  EXPECT_FALSE(options.SetFromString("foo-bar-baz"));
+}
+
+TEST(TraceOptionsTest, TraceOptionsToString) {
+  // Test that we can intialize TraceOptions from a string got from
+  // TraceOptions.ToString() method to get a same TraceOptions.
+  TraceRecordMode modes[] = {RECORD_UNTIL_FULL,
+                             RECORD_CONTINUOUSLY,
+                             ECHO_TO_CONSOLE,
+                             RECORD_AS_MUCH_AS_POSSIBLE};
+  bool enable_sampling_options[] = {true, false};
+  bool enable_systrace_options[] = {true, false};
+
+  for (int i = 0; i < 4; ++i) {
+    for (int j = 0; j < 2; ++j) {
+      for (int k = 0; k < 2; ++k) {
+        TraceOptions original_option = TraceOptions(modes[i]);
+        original_option.enable_sampling = enable_sampling_options[j];
+        original_option.enable_systrace = enable_systrace_options[k];
+        TraceOptions new_options;
+        EXPECT_TRUE(new_options.SetFromString(original_option.ToString()));
+        EXPECT_EQ(original_option.record_mode, new_options.record_mode);
+        EXPECT_EQ(original_option.enable_sampling, new_options.enable_sampling);
+        EXPECT_EQ(original_option.enable_systrace, new_options.enable_systrace);
+      }
+    }
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_win.cc b/base/trace_event/trace_event_win.cc
new file mode 100644
index 0000000..ebb55c8
--- /dev/null
+++ b/base/trace_event/trace_event_win.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_win.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include <initguid.h>  // NOLINT
+
+namespace base {
+namespace trace_event {
+
+using base::win::EtwEventType;
+using base::win::EtwMofEvent;
+
+// {3DADA31D-19EF-4dc1-B345-037927193422}
+const GUID kChromeTraceProviderName = {
+    0x3dada31d, 0x19ef, 0x4dc1, 0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22 };
+
+// {B967AE67-BB22-49d7-9406-55D91EE1D560}
+const GUID kTraceEventClass32 = {
+    0xb967ae67, 0xbb22, 0x49d7, 0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60 };
+
+// {97BE602D-2930-4ac3-8046-B6763B631DFE}
+const GUID kTraceEventClass64 = {
+    0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe};
+
+
+TraceEventETWProvider::TraceEventETWProvider() :
+    EtwTraceProvider(kChromeTraceProviderName) {
+  Register();
+}
+
+TraceEventETWProvider* TraceEventETWProvider::GetInstance() {
+  return Singleton<TraceEventETWProvider,
+      StaticMemorySingletonTraits<TraceEventETWProvider> >::get();
+}
+
+bool TraceEventETWProvider::StartTracing() {
+  return true;
+}
+
+void TraceEventETWProvider::TraceEvent(const char* name,
+                                       size_t name_len,
+                                       char type,
+                                       const void* id,
+                                       const char* extra,
+                                       size_t extra_len) {
+  // Make sure we don't touch NULL.
+  if (name == NULL)
+    name = "";
+  if (extra == NULL)
+    extra = "";
+
+  EtwEventType etw_type = 0;
+  switch (type) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      etw_type = kTraceEventTypeBegin;
+      break;
+    case TRACE_EVENT_PHASE_END:
+      etw_type = kTraceEventTypeEnd;
+      break;
+
+    case TRACE_EVENT_PHASE_INSTANT:
+      etw_type = kTraceEventTypeInstant;
+      break;
+
+    default:
+      NOTREACHED() << "Unknown event type";
+      etw_type = kTraceEventTypeInstant;
+      break;
+  }
+
+  EtwMofEvent<5> event(kTraceEventClass32,
+                       etw_type,
+                       TRACE_LEVEL_INFORMATION);
+  event.SetField(0, name_len + 1, name);
+  event.SetField(1, sizeof(id), &id);
+  event.SetField(2, extra_len + 1, extra);
+
+  // These variables are declared here so that they are not out of scope when
+  // the event is logged.
+  DWORD depth;
+  void* backtrace[32];
+
+  // See whether we're to capture a backtrace.
+  if (enable_flags() & CAPTURE_STACK_TRACE) {
+    depth = CaptureStackBackTrace(0,
+                                  arraysize(backtrace),
+                                  backtrace,
+                                  NULL);
+    event.SetField(3, sizeof(depth), &depth);
+    event.SetField(4, sizeof(backtrace[0]) * depth, backtrace);
+  }
+
+  // Trace the event.
+  Log(event.get());
+}
+
+void TraceEventETWProvider::Trace(const char* name,
+                                  size_t name_len,
+                                  char type,
+                                  const void* id,
+                                  const char* extra,
+                                  size_t extra_len) {
+  TraceEventETWProvider* provider = TraceEventETWProvider::GetInstance();
+  if (provider && provider->IsTracing()) {
+    // Compute the name & extra lengths if not supplied already.
+    if (name_len == kUseStrlen)
+      name_len = (name == NULL) ? 0 : strlen(name);
+    if (extra_len == kUseStrlen)
+      extra_len = (extra == NULL) ? 0 : strlen(extra);
+
+    provider->TraceEvent(name, name_len, type, id, extra, extra_len);
+  }
+}
+
+void TraceEventETWProvider::Resurrect() {
+  StaticMemorySingletonTraits<TraceEventETWProvider>::Resurrect();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_win.h b/base/trace_event/trace_event_win.h
new file mode 100644
index 0000000..4161361
--- /dev/null
+++ b/base/trace_event/trace_event_win.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the Windows-specific declarations for trace_event.h.
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "base/win/event_trace_provider.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+// This EtwTraceProvider subclass implements ETW logging
+// for the macros above on Windows.
+class BASE_EXPORT TraceEventETWProvider : public base::win::EtwTraceProvider {
+ public:
+   static const size_t kUseStrlen = static_cast<size_t>(-1);
+
+  // Start logging trace events.
+  // This is a noop in this implementation.
+  static bool StartTracing();
+
+  // Trace begin/end/instant events, this is the bottleneck implementation
+  // all the others defer to.
+  // Allowing the use of std::string for name or extra is a convenience,
+  // whereas passing name or extra as a const char* avoids the construction
+  // of temporary std::string instances.
+  // If kUseStrlen is passed for name_len or extra_len, the strlen of the string
+  // will be used for length.
+  static void Trace(const char* name,
+                    size_t name_len,
+                    char type,
+                    const void* id,
+                    const char* extra,
+                    size_t extra_len);
+
+  // Allows passing extra as a std::string for convenience.
+  static void Trace(const char* name,
+                    char type,
+                    const void* id,
+                    const std::string& extra) {
+    return Trace(name, kUseStrlen, type, id, extra.c_str(), extra.length());
+  }
+
+  // Allows passing extra as a const char* to avoid constructing temporary
+  // std::string instances where not needed.
+  static void Trace(const char* name,
+                    char type,
+                    const void* id,
+                    const char* extra) {
+    return Trace(name, kUseStrlen, type, id, extra, kUseStrlen);
+  }
+
+  // Retrieves the singleton.
+  // Note that this may return NULL post-AtExit processing.
+  static TraceEventETWProvider* GetInstance();
+
+  // Returns true iff tracing is turned on.
+  bool IsTracing() {
+    return enable_level() >= TRACE_LEVEL_INFORMATION;
+  }
+
+  // Emit a trace of type |type| containing |name|, |id|, and |extra|.
+  // Note: |name| and |extra| must be NULL, or a zero-terminated string of
+  //    length |name_len| or |extra_len| respectively.
+  // Note: if name_len or extra_len are kUseStrlen, the length of the
+  //    corresponding string will be used.
+  void TraceEvent(const char* name,
+                  size_t name_len,
+                  char type,
+                  const void* id,
+                  const char* extra,
+                  size_t extra_len);
+
+  // Exposed for unittesting only, allows resurrecting our
+  // singleton instance post-AtExit processing.
+  static void Resurrect();
+
+ private:
+  // Ensure only the provider can construct us.
+  friend struct StaticMemorySingletonTraits<TraceEventETWProvider>;
+  TraceEventETWProvider();
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventETWProvider);
+};
+
+// The ETW trace provider GUID.
+BASE_EXPORT extern const GUID kChromeTraceProviderName;
+
+// The ETW event class GUID for 32 bit events.
+BASE_EXPORT extern const GUID kTraceEventClass32;
+
+// The ETW event class GUID for 64 bit events.
+BASE_EXPORT extern const GUID kTraceEventClass64;
+
+// The ETW event types, IDs 0x00-0x09 are reserved, so start at 0x10.
+const base::win::EtwEventType kTraceEventTypeBegin = 0x10;
+const base::win::EtwEventType kTraceEventTypeEnd = 0x11;
+const base::win::EtwEventType kTraceEventTypeInstant = 0x12;
+
+// If this flag is set in enable flags
+enum TraceEventETWFlags {
+  CAPTURE_STACK_TRACE = 0x0001,
+};
+
+// The event format consists of:
+// The "name" string as a zero-terminated ASCII string.
+// The id pointer in the machine bitness.
+// The "extra" string as a zero-terminated ASCII string.
+// Optionally the stack trace, consisting of a DWORD "depth", followed
+//    by an array of void* (machine bitness) of length "depth".
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
diff --git a/base/trace_event/trace_event_win_unittest.cc b/base/trace_event/trace_event_win_unittest.cc
new file mode 100644
index 0000000..d4dc854
--- /dev/null
+++ b/base/trace_event/trace_event_win_unittest.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event.h"
+
+#include <strstream>
+
+#include "base/at_exit.h"
+#include "base/basictypes.h"
+#include "base/files/file_util.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_win.h"
+#include "base/win/event_trace_consumer.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/windows_version.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include <initguid.h>  // NOLINT - must be last include.
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+using testing::_;
+using testing::AnyNumber;
+using testing::InSequence;
+using testing::Ge;
+using testing::Le;
+using testing::NotNull;
+
+using base::win::EtwEventType;
+using base::win::EtwTraceConsumerBase;
+using base::win::EtwTraceController;
+using base::win::EtwTraceProperties;
+
+// Data for unittests traces.
+const char kEmpty[] = "";
+const char kName[] = "unittest.trace_name";
+const char kExtra[] = "UnittestDummyExtraString";
+const void* kId = kName;
+
+const wchar_t kTestSessionName[] = L"TraceEvent unittest session";
+
+MATCHER_P(BufferStartsWith, str, "Buffer starts with") {
+  return memcmp(arg, str.c_str(), str.length()) == 0;
+}
+
+// Duplicated from <evntrace.h> to fix link problems.
+DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */
+    kEventTraceGuid,
+    0x68fdd900,
+    0x4a3e,
+    0x11d1,
+    0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3);
+
+class TestEventConsumer: public EtwTraceConsumerBase<TestEventConsumer> {
+ public:
+  TestEventConsumer() {
+    EXPECT_TRUE(current_ == NULL);
+    current_ = this;
+  }
+
+  ~TestEventConsumer() {
+    EXPECT_TRUE(current_ == this);
+    current_ = NULL;
+  }
+
+  MOCK_METHOD4(Event, void(REFGUID event_class,
+                      EtwEventType event_type,
+                      size_t buf_len,
+                      const void* buf));
+
+  static void ProcessEvent(EVENT_TRACE* event) {
+    ASSERT_TRUE(current_ != NULL);
+    current_->Event(event->Header.Guid,
+                    event->Header.Class.Type,
+                    event->MofLength,
+                    event->MofData);
+  }
+
+ private:
+  static TestEventConsumer* current_;
+};
+
+TestEventConsumer* TestEventConsumer::current_ = NULL;
+
+class TraceEventWinTest: public testing::Test {
+ public:
+  TraceEventWinTest() {
+  }
+
+  void SetUp() override {
+    bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
+
+    if (is_xp) {
+      // Tear down any dangling session from an earlier failing test.
+      EtwTraceProperties ignore;
+      EtwTraceController::Stop(kTestSessionName, &ignore);
+    }
+
+    // Resurrect and initialize the TraceLog singleton instance.
+    // On Vista and better, we need the provider registered before we
+    // start the private, in-proc session, but on XP we need the global
+    // session created and the provider enabled before we register our
+    // provider.
+    TraceEventETWProvider* tracelog = NULL;
+    if (!is_xp) {
+      TraceEventETWProvider::Resurrect();
+      tracelog = TraceEventETWProvider::GetInstance();
+      ASSERT_TRUE(tracelog != NULL);
+      ASSERT_FALSE(tracelog->IsTracing());
+    }
+
+    // Create the log file.
+    ASSERT_TRUE(base::CreateTemporaryFile(&log_file_));
+
+    // Create a private log session on the file.
+    EtwTraceProperties prop;
+    ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(log_file_.value().c_str()));
+    EVENT_TRACE_PROPERTIES& p = *prop.get();
+    p.Wnode.ClientContext = 1;  // QPC timer accuracy.
+    p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;   // Sequential log.
+
+    // On Vista and later, we create a private in-process log session, because
+    // otherwise we'd need administrator privileges. Unfortunately we can't
+    // do the same on XP and better, because the semantics of a private
+    // logger session are different, and the IN_PROC flag is not supported.
+    if (!is_xp) {
+      p.LogFileMode |= EVENT_TRACE_PRIVATE_IN_PROC |  // In-proc for non-admin.
+          EVENT_TRACE_PRIVATE_LOGGER_MODE;  // Process-private log.
+    }
+
+    p.MaximumFileSize = 100;  // 100M file size.
+    p.FlushTimer = 1;  // 1 second flush lag.
+    ASSERT_HRESULT_SUCCEEDED(controller_.Start(kTestSessionName, &prop));
+
+    // Enable the TraceLog provider GUID.
+    ASSERT_HRESULT_SUCCEEDED(
+        controller_.EnableProvider(kChromeTraceProviderName,
+                                   TRACE_LEVEL_INFORMATION,
+                                   0));
+
+    if (is_xp) {
+      TraceEventETWProvider::Resurrect();
+      tracelog = TraceEventETWProvider::GetInstance();
+    }
+    ASSERT_TRUE(tracelog != NULL);
+    EXPECT_TRUE(tracelog->IsTracing());
+  }
+
+  void TearDown() override {
+    EtwTraceProperties prop;
+    if (controller_.session() != 0)
+      EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
+
+    if (!log_file_.value().empty())
+      base::DeleteFile(log_file_, false);
+
+    // We want our singleton torn down after each test.
+    TraceLog::DeleteForTesting();
+  }
+
+  void ExpectEvent(REFGUID guid,
+                   EtwEventType type,
+                   const char* name,
+                   size_t name_len,
+                   const void* id,
+                   const char* extra,
+                   size_t extra_len) {
+    // Build the trace event buffer we expect will result from this.
+    std::stringbuf str;
+    str.sputn(name, name_len + 1);
+    str.sputn(reinterpret_cast<const char*>(&id), sizeof(id));
+    str.sputn(extra, extra_len + 1);
+
+    // And set up the expectation for the event callback.
+    EXPECT_CALL(consumer_, Event(guid,
+                                 type,
+                                 testing::Ge(str.str().length()),
+                                 BufferStartsWith(str.str())));
+  }
+
+  void ExpectPlayLog() {
+    // Ignore EventTraceGuid events.
+    EXPECT_CALL(consumer_, Event(kEventTraceGuid, _, _, _))
+        .Times(AnyNumber());
+  }
+
+  void PlayLog() {
+    EtwTraceProperties prop;
+    EXPECT_HRESULT_SUCCEEDED(controller_.Flush(&prop));
+    EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
+    ASSERT_HRESULT_SUCCEEDED(
+        consumer_.OpenFileSession(log_file_.value().c_str()));
+
+    ASSERT_HRESULT_SUCCEEDED(consumer_.Consume());
+  }
+
+ private:
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+  EtwTraceController controller_;
+  FilePath log_file_;
+  TestEventConsumer consumer_;
+};
+
+}  // namespace
+
+
+TEST_F(TraceEventWinTest, TraceLog) {
+  ExpectPlayLog();
+
+  // The events should arrive in the same sequence as the expects.
+  InSequence in_sequence;
+
+  // Full argument version, passing lengths explicitly.
+  TraceEventETWProvider::Trace(kName,
+                        strlen(kName),
+                        TRACE_EVENT_PHASE_BEGIN,
+                        kId,
+                        kExtra,
+                        strlen(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  // Const char* version.
+  TraceEventETWProvider::Trace(static_cast<const char*>(kName),
+                        TRACE_EVENT_PHASE_END,
+                        kId,
+                        static_cast<const char*>(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  // std::string extra version.
+  TraceEventETWProvider::Trace(static_cast<const char*>(kName),
+                        TRACE_EVENT_PHASE_INSTANT,
+                        kId,
+                        std::string(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeInstant,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+
+  // Test for sanity on NULL inputs.
+  TraceEventETWProvider::Trace(NULL,
+                        0,
+                        TRACE_EVENT_PHASE_BEGIN,
+                        kId,
+                        NULL,
+                        0);
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kEmpty, 0,
+              kId,
+              kEmpty, 0);
+
+  TraceEventETWProvider::Trace(NULL,
+                        TraceEventETWProvider::kUseStrlen,
+                        TRACE_EVENT_PHASE_END,
+                        kId,
+                        NULL,
+                        TraceEventETWProvider::kUseStrlen);
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kEmpty, 0,
+              kId,
+              kEmpty, 0);
+
+  PlayLog();
+}
+
+TEST_F(TraceEventWinTest, Macros) {
+  ExpectPlayLog();
+
+  // The events should arrive in the same sequence as the expects.
+  InSequence in_sequence;
+
+  TRACE_EVENT_BEGIN_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  TRACE_EVENT_END_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  TRACE_EVENT_INSTANT_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeInstant,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  PlayLog();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
new file mode 100644
index 0000000..e1e9bcf
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Report a heap dump to a process memory dump. The |heap_info| structure
+// contains the information about this heap, and |dump_absolute_name| will be
+// used to represent it in the report.
+bool ReportHeapDump(ProcessMemoryDump* pmd,
+                    const WinHeapInfo& heap_info,
+                    const std::string& dump_absolute_name) {
+  MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(dump_absolute_name);
+  if (!dump)
+    return false;
+  dump->AddScalar(MemoryAllocatorDump::kNameOuterSize,
+                  MemoryAllocatorDump::kUnitsBytes, heap_info.committed_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameInnerSize,
+                  MemoryAllocatorDump::kUnitsBytes, heap_info.allocated_size);
+  dump->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                  MemoryAllocatorDump::kUnitsObjects, heap_info.block_count);
+  return true;
+}
+
+}  // namespace
+
+WinHeapDumpProvider* WinHeapDumpProvider::GetInstance() {
+  return Singleton<WinHeapDumpProvider,
+                   LeakySingletonTraits<WinHeapDumpProvider>>::get();
+}
+
+bool WinHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  // Retrieves the number of heaps in the current process.
+  DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
+  WinHeapInfo all_heap_info = {0};
+
+  // Try to retrieve a handle to all the heaps owned by this process. Returns
+  // false if the number of heaps has changed.
+  //
+  // This is inherently racy as is, but it's not something that we observe a lot
+  // in Chrome, the heaps tend to be created at startup only.
+  scoped_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]);
+  if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps)
+    return false;
+
+  // Skip the pointer to the heap array to avoid accounting the memory used by
+  // this dump provider.
+  std::set<void*> block_to_skip;
+  block_to_skip.insert(all_heaps.get());
+
+  // Retrieves some metrics about each heap.
+  for (size_t i = 0; i < number_of_heaps; ++i) {
+    WinHeapInfo heap_info = {0};
+    heap_info.heap_id = all_heaps[i];
+    GetHeapInformation(&heap_info, block_to_skip);
+
+    all_heap_info.allocated_size += heap_info.allocated_size;
+    all_heap_info.committed_size += heap_info.committed_size;
+    all_heap_info.block_count += heap_info.block_count;
+  }
+  // Report the heap dump.
+  if (!ReportHeapDump(pmd, all_heap_info, "winheap"))
+    return false;
+
+  return true;
+}
+
+bool WinHeapDumpProvider::GetHeapInformation(
+    WinHeapInfo* heap_info,
+    const std::set<void*>& block_to_skip) {
+  CHECK(::HeapLock(heap_info->heap_id) == TRUE);
+  PROCESS_HEAP_ENTRY heap_entry;
+  heap_entry.lpData = nullptr;
+  // Walk over all the entries in this heap.
+  while (::HeapWalk(heap_info->heap_id, &heap_entry) != FALSE) {
+    if (block_to_skip.count(heap_entry.lpData) == 1)
+      continue;
+    if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
+      heap_info->allocated_size += heap_entry.cbData;
+      heap_info->block_count++;
+    } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) {
+      heap_info->committed_size += heap_entry.Region.dwCommittedSize;
+    }
+  }
+  CHECK(::HeapUnlock(heap_info->heap_id) == TRUE);
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/winheap_dump_provider_win.h b/base/trace_event/winheap_dump_provider_win.h
new file mode 100644
index 0000000..99239a0
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win.h
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+#define BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+
+#include <set>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// A structure containing some information about a given heap.
+struct WinHeapInfo {
+  HANDLE heap_id;
+  size_t committed_size;
+  size_t allocated_size;
+  size_t block_count;
+};
+
+// Dump provider which collects process-wide heap memory stats. This provider
+// iterates over all the heaps of the current process to gather some metrics
+// about them.
+class BASE_EXPORT WinHeapDumpProvider : public MemoryDumpProvider {
+ public:
+  static WinHeapDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
+
+  // Retrieves the information about given heap. The |heap_info| should contain
+  // a valid handle to an existing heap. The blocks contained in the
+  // |block_to_skip| set will be ignored.
+  bool GetHeapInformation(WinHeapInfo* heap_info,
+                          const std::set<void*>& block_to_skip);
+
+  WinHeapDumpProvider() {}
+  ~WinHeapDumpProvider() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(WinHeapDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
diff --git a/base/trace_event/winheap_dump_provider_win_unittest.cc b/base/trace_event/winheap_dump_provider_win_unittest.cc
new file mode 100644
index 0000000..2309802
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(WinHeapDumpProviderTest, OnMemoryDump) {
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+  WinHeapDumpProvider* winheap_dump_provider =
+      WinHeapDumpProvider::GetInstance();
+  ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
+
+  ASSERT_TRUE(winheap_dump_provider->OnMemoryDump(&pmd));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
new file mode 100644
index 0000000..9db05c0
--- /dev/null
+++ b/base/tracked_objects.cc
@@ -0,0 +1,1007 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/tracked_objects.h"
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include "base/atomicops.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/leak_annotations.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/valgrind/memcheck.h"
+#include "base/tracking_info.h"
+
+using base::TimeDelta;
+
+namespace base {
+class TimeDelta;
+}
+
+namespace tracked_objects {
+
+namespace {
+// When ThreadData is first initialized, should we start in an ACTIVE state to
+// record all of the startup-time tasks, or should we start up DEACTIVATED, so
+// that we only record after parsing the command line flag --enable-tracking.
+// Note that the flag may force either state, so this really controls only the
+// period of time up until that flag is parsed.  If there is no flag seen, then
+// this state may prevail for much or all of the process lifetime.
+const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE;
+
+// Control whether an alternate time source (Now() function) is supported by
+// the ThreadData class.  This compile time flag should be set to true if we
+// want other modules (such as a memory allocator, or a thread-specific CPU time
+// clock) to be able to provide a thread-specific Now() function.  Without this
+// compile-time flag, the code will only support the wall-clock time.  This flag
+// can be flipped to efficiently disable this path (if there is a performance
+// problem with its presence).
+static const bool kAllowAlternateTimeSourceHandling = true;
+
+// Possible states of the profiler timing enabledness.
+enum {
+  UNDEFINED_TIMING,
+  ENABLED_TIMING,
+  DISABLED_TIMING,
+};
+
+// State of the profiler timing enabledness.
+base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING;
+
+// Returns whether profiler timing is enabled.  The default is true, but this
+// may be overridden by a command-line flag.  Some platforms may
+// programmatically set this command-line flag to the "off" value if it's not
+// specified.
+// This in turn can be overridden by explicitly calling
+// ThreadData::EnableProfilerTiming, say, based on a field trial.
+inline bool IsProfilerTimingEnabled() {
+  // Reading |g_profiler_timing_enabled| is done without barrier because
+  // multiple initialization is not an issue while the barrier can be relatively
+  // costly given that this method is sometimes called in a tight loop.
+  base::subtle::Atomic32 current_timing_enabled =
+      base::subtle::NoBarrier_Load(&g_profiler_timing_enabled);
+  if (current_timing_enabled == UNDEFINED_TIMING) {
+    if (!base::CommandLine::InitializedForCurrentProcess())
+      return true;
+    current_timing_enabled =
+        (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+             switches::kProfilerTiming) ==
+         switches::kProfilerTimingDisabledValue)
+            ? DISABLED_TIMING
+            : ENABLED_TIMING;
+    base::subtle::NoBarrier_Store(&g_profiler_timing_enabled,
+                                  current_timing_enabled);
+  }
+  return current_timing_enabled == ENABLED_TIMING;
+}
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// DeathData tallies durations when a death takes place.
+
+DeathData::DeathData()
+    : count_(0),
+      sample_probability_count_(0),
+      run_duration_sum_(0),
+      queue_duration_sum_(0),
+      run_duration_max_(0),
+      queue_duration_max_(0),
+      run_duration_sample_(0),
+      queue_duration_sample_(0),
+      last_phase_snapshot_(nullptr) {
+}
+
+DeathData::DeathData(const DeathData& other)
+    : count_(other.count_),
+      sample_probability_count_(other.sample_probability_count_),
+      run_duration_sum_(other.run_duration_sum_),
+      queue_duration_sum_(other.queue_duration_sum_),
+      run_duration_max_(other.run_duration_max_),
+      queue_duration_max_(other.queue_duration_max_),
+      run_duration_sample_(other.run_duration_sample_),
+      queue_duration_sample_(other.queue_duration_sample_),
+      last_phase_snapshot_(nullptr) {
+  // This constructor will be used by std::map when adding new DeathData values
+  // to the map.  At that point, last_phase_snapshot_ is still NULL, so we don't
+  // need to worry about ownership transfer.
+  DCHECK(other.last_phase_snapshot_ == nullptr);
+}
+
+DeathData::~DeathData() {
+  while (last_phase_snapshot_) {
+    const DeathDataPhaseSnapshot* snapshot = last_phase_snapshot_;
+    last_phase_snapshot_ = snapshot->prev;
+    delete snapshot;
+  }
+}
+
+// TODO(jar): I need to see if this macro to optimize branching is worth using.
+//
+// This macro has no branching, so it is surely fast, and is equivalent to:
+//             if (assign_it)
+//               target = source;
+// We use a macro rather than a template to force this to inline.
+// Related code for calculating max is discussed on the web.
+#define CONDITIONAL_ASSIGN(assign_it, target, source) \
+    ((target) ^= ((target) ^ (source)) & -static_cast<int32>(assign_it))
+
+void DeathData::RecordDeath(const int32 queue_duration,
+                            const int32 run_duration,
+                            const uint32 random_number) {
+  // We'll just clamp at INT_MAX, but we should note this in the UI as such.
+  if (count_ < INT_MAX)
+    ++count_;
+
+  int sample_probability_count = sample_probability_count_;
+  if (sample_probability_count < INT_MAX)
+    ++sample_probability_count;
+  sample_probability_count_ = sample_probability_count;
+
+  queue_duration_sum_ += queue_duration;
+  run_duration_sum_ += run_duration;
+
+  if (queue_duration_max_ < queue_duration)
+    queue_duration_max_ = queue_duration;
+  if (run_duration_max_ < run_duration)
+    run_duration_max_ = run_duration;
+
+  // Take a uniformly distributed sample over all durations ever supplied during
+  // the current profiling phase.
+  // The probability that we (instead) use this new sample is
+  // 1/sample_probability_count_. This results in a completely uniform selection
+  // of the sample (at least when we don't clamp sample_probability_count_...
+  // but that should be inconsequentially likely).  We ignore the fact that we
+  // correlated our selection of a sample to the run and queue times (i.e., we
+  // used them to generate random_number).
+  CHECK_GT(sample_probability_count, 0);
+  if (0 == (random_number % sample_probability_count)) {
+    queue_duration_sample_ = queue_duration;
+    run_duration_sample_ = run_duration;
+  }
+}
+
+void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
+  // Snapshotting and storing current state.
+  last_phase_snapshot_ = new DeathDataPhaseSnapshot(
+      profiling_phase, count_, run_duration_sum_, run_duration_max_,
+      run_duration_sample_, queue_duration_sum_, queue_duration_max_,
+      queue_duration_sample_, last_phase_snapshot_);
+
+  // Not touching fields for which a delta can be computed by comparing with a
+  // snapshot from the previous phase. Resetting other fields.  Sample values
+  // will be reset upon next death recording because sample_probability_count_
+  // is set to 0.
+  // We avoid resetting to 0 in favor of deltas whenever possible.  The reason
+  // is that for incrementable fields, resetting to 0 from the snapshot thread
+  // potentially in parallel with incrementing in the death thread may result in
+  // significant data corruption that has a potential to grow with time.  Not
+  // resetting incrementable fields and using deltas will cause any
+  // off-by-little corruptions to be likely fixed at the next snapshot.
+  // The max values are not incrementable, and cannot be deduced using deltas
+  // for a given phase. Hence, we have to reset them to 0.  But the potential
+  // damage is limited to getting the previous phase's max to apply for the next
+  // phase, and the error doesn't have a potential to keep growing with new
+  // resets.
+  // sample_probability_count_ is incrementable, but must be reset to 0 at the
+  // phase end, so that we start a new uniformly randomized sample selection
+  // after the reset.  Corruptions due to race conditions are possible, but the
+  // damage is limited to selecting a wrong sample, which is not something that
+  // can cause accumulating or cascading effects.
+  // If there were no corruptions caused by race conditions, we never send a
+  // sample for the previous phase in the next phase's snapshot because
+  // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count.
+  sample_probability_count_ = 0;
+  run_duration_max_ = 0;
+  queue_duration_max_ = 0;
+}
+
+//------------------------------------------------------------------------------
+DeathDataSnapshot::DeathDataSnapshot()
+    : count(-1),
+      run_duration_sum(-1),
+      run_duration_max(-1),
+      run_duration_sample(-1),
+      queue_duration_sum(-1),
+      queue_duration_max(-1),
+      queue_duration_sample(-1) {
+}
+
+DeathDataSnapshot::DeathDataSnapshot(int count,
+                                     int32 run_duration_sum,
+                                     int32 run_duration_max,
+                                     int32 run_duration_sample,
+                                     int32 queue_duration_sum,
+                                     int32 queue_duration_max,
+                                     int32 queue_duration_sample)
+    : count(count),
+      run_duration_sum(run_duration_sum),
+      run_duration_max(run_duration_max),
+      run_duration_sample(run_duration_sample),
+      queue_duration_sum(queue_duration_sum),
+      queue_duration_max(queue_duration_max),
+      queue_duration_sample(queue_duration_sample) {
+}
+
+DeathDataSnapshot::~DeathDataSnapshot() {
+}
+
+DeathDataSnapshot DeathDataSnapshot::Delta(
+    const DeathDataSnapshot& older) const {
+  return DeathDataSnapshot(count - older.count,
+                           run_duration_sum - older.run_duration_sum,
+                           run_duration_max, run_duration_sample,
+                           queue_duration_sum - older.queue_duration_sum,
+                           queue_duration_max, queue_duration_sample);
+}
+
+//------------------------------------------------------------------------------
+BirthOnThread::BirthOnThread(const Location& location,
+                             const ThreadData& current)
+    : location_(location),
+      birth_thread_(&current) {
+}
+
+//------------------------------------------------------------------------------
+BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
+}
+
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth)
+    : location(birth.location()),
+      thread_name(birth.birth_thread()->thread_name()) {
+}
+
+BirthOnThreadSnapshot::~BirthOnThreadSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+Births::Births(const Location& location, const ThreadData& current)
+    : BirthOnThread(location, current),
+      birth_count_(1) { }
+
+int Births::birth_count() const { return birth_count_; }
+
+void Births::RecordBirth() { ++birth_count_; }
+
+//------------------------------------------------------------------------------
+// ThreadData maintains the central data for all births and deaths on a single
+// thread.
+
+// TODO(jar): We should pull all these static vars together, into a struct, and
+// optimize layout so that we benefit from locality of reference during accesses
+// to them.
+
+// static
+NowFunction* ThreadData::now_function_ = NULL;
+
+// static
+bool ThreadData::now_function_is_time_ = false;
+
+// A TLS slot which points to the ThreadData instance for the current thread.
+// We do a fake initialization here (zeroing out data), and then the real
+// in-place construction happens when we call tls_index_.Initialize().
+// static
+base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
+
+// static
+int ThreadData::worker_thread_data_creation_count_ = 0;
+
+// static
+int ThreadData::cleanup_count_ = 0;
+
+// static
+int ThreadData::incarnation_counter_ = 0;
+
+// static
+ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
+
+// static
+ThreadData* ThreadData::first_retired_worker_ = NULL;
+
+// static
+base::LazyInstance<base::Lock>::Leaky
+    ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
+
+ThreadData::ThreadData(const std::string& suggested_name)
+    : next_(NULL),
+      next_retired_worker_(NULL),
+      worker_thread_number_(0),
+      incarnation_count_for_pool_(-1),
+      current_stopwatch_(NULL) {
+  DCHECK_GE(suggested_name.size(), 0u);
+  thread_name_ = suggested_name;
+  PushToHeadOfList();  // Which sets real incarnation_count_for_pool_.
+}
+
+ThreadData::ThreadData(int thread_number)
+    : next_(NULL),
+      next_retired_worker_(NULL),
+      worker_thread_number_(thread_number),
+      incarnation_count_for_pool_(-1),
+      current_stopwatch_(NULL) {
+  CHECK_GT(thread_number, 0);
+  base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
+  PushToHeadOfList();  // Which sets real incarnation_count_for_pool_.
+}
+
+ThreadData::~ThreadData() {
+}
+
+void ThreadData::PushToHeadOfList() {
+  // Toss in a hint of randomness (atop the uniniitalized value).
+  (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
+                                                 sizeof(random_number_));
+  MSAN_UNPOISON(&random_number_, sizeof(random_number_));
+  random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
+  random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
+
+  DCHECK(!next_);
+  base::AutoLock lock(*list_lock_.Pointer());
+  incarnation_count_for_pool_ = incarnation_counter_;
+  next_ = all_thread_data_list_head_;
+  all_thread_data_list_head_ = this;
+}
+
+// static
+ThreadData* ThreadData::first() {
+  base::AutoLock lock(*list_lock_.Pointer());
+  return all_thread_data_list_head_;
+}
+
+ThreadData* ThreadData::next() const { return next_; }
+
+// static
+void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
+  Initialize();
+  ThreadData* current_thread_data =
+      reinterpret_cast<ThreadData*>(tls_index_.Get());
+  if (current_thread_data)
+    return;  // Browser tests instigate this.
+  current_thread_data = new ThreadData(suggested_name);
+  tls_index_.Set(current_thread_data);
+}
+
+// static
+ThreadData* ThreadData::Get() {
+  if (!tls_index_.initialized())
+    return NULL;  // For unittests only.
+  ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get());
+  if (registered)
+    return registered;
+
+  // We must be a worker thread, since we didn't pre-register.
+  ThreadData* worker_thread_data = NULL;
+  int worker_thread_number = 0;
+  {
+    base::AutoLock lock(*list_lock_.Pointer());
+    if (first_retired_worker_) {
+      worker_thread_data = first_retired_worker_;
+      first_retired_worker_ = first_retired_worker_->next_retired_worker_;
+      worker_thread_data->next_retired_worker_ = NULL;
+    } else {
+      worker_thread_number = ++worker_thread_data_creation_count_;
+    }
+  }
+
+  // If we can't find a previously used instance, then we have to create one.
+  if (!worker_thread_data) {
+    DCHECK_GT(worker_thread_number, 0);
+    worker_thread_data = new ThreadData(worker_thread_number);
+  }
+  DCHECK_GT(worker_thread_data->worker_thread_number_, 0);
+
+  tls_index_.Set(worker_thread_data);
+  return worker_thread_data;
+}
+
+// static
+void ThreadData::OnThreadTermination(void* thread_data) {
+  DCHECK(thread_data);  // TLS should *never* call us with a NULL.
+  // We must NOT do any allocations during this callback.  There is a chance
+  // that the allocator is no longer active on this thread.
+  reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
+}
+
+void ThreadData::OnThreadTerminationCleanup() {
+  // The list_lock_ was created when we registered the callback, so it won't be
+  // allocated here despite the lazy reference.
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (incarnation_counter_ != incarnation_count_for_pool_)
+    return;  // ThreadData was constructed in an earlier unit test.
+  ++cleanup_count_;
+  // Only worker threads need to be retired and reused.
+  if (!worker_thread_number_) {
+    return;
+  }
+  // We must NOT do any allocations during this callback.
+  // Using the simple linked lists avoids all allocations.
+  DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL));
+  this->next_retired_worker_ = first_retired_worker_;
+  first_retired_worker_ = this;
+}
+
+// static
+void ThreadData::Snapshot(int current_profiling_phase,
+                          ProcessDataSnapshot* process_data_snapshot) {
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Gather data serially.
+  // This hackish approach *can* get some slightly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  If a user
+  // sees any strangeness, they can always just run their stats gathering a
+  // second time.
+  BirthCountMap birth_counts;
+  for (ThreadData* thread_data = my_list; thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->SnapshotExecutedTasks(current_profiling_phase,
+                                       &process_data_snapshot->phased_snapshots,
+                                       &birth_counts);
+  }
+
+  // Add births that are still active -- i.e. objects that have tallied a birth,
+  // but have not yet tallied a matching death, and hence must be either
+  // running, queued up, or being held in limbo for future posting.
+  auto* current_phase_tasks =
+      &process_data_snapshot->phased_snapshots[current_profiling_phase].tasks;
+  for (const auto& birth_count : birth_counts) {
+    if (birth_count.second > 0) {
+      current_phase_tasks->push_back(
+          TaskSnapshot(BirthOnThreadSnapshot(*birth_count.first),
+                       DeathDataSnapshot(birth_count.second, 0, 0, 0, 0, 0, 0),
+                       "Still_Alive"));
+    }
+  }
+}
+
+// static
+void ThreadData::OnProfilingPhaseCompleted(int profiling_phase) {
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Add snapshots for all instances of death data in all threads serially.
+  // This hackish approach *can* get some slightly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  Any corruption
+  // shouldn't cause "cascading damage" to anything else (in later phases).
+  for (ThreadData* thread_data = my_list; thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->OnProfilingPhaseCompletedOnThread(profiling_phase);
+  }
+}
+
+Births* ThreadData::TallyABirth(const Location& location) {
+  BirthMap::iterator it = birth_map_.find(location);
+  Births* child;
+  if (it != birth_map_.end()) {
+    child =  it->second;
+    child->RecordBirth();
+  } else {
+    child = new Births(location, *this);  // Leak this.
+    // Lock since the map may get relocated now, and other threads sometimes
+    // snapshot it (but they lock before copying it).
+    base::AutoLock lock(map_lock_);
+    birth_map_[location] = child;
+  }
+
+  return child;
+}
+
+void ThreadData::TallyADeath(const Births& births,
+                             int32 queue_duration,
+                             const TaskStopwatch& stopwatch) {
+  int32 run_duration = stopwatch.RunDurationMs();
+
+  // Stir in some randomness, plus add constant in case durations are zero.
+  const uint32 kSomePrimeNumber = 2147483647;
+  random_number_ += queue_duration + run_duration + kSomePrimeNumber;
+  // An address is going to have some randomness to it as well ;-).
+  random_number_ ^= static_cast<uint32>(&births - reinterpret_cast<Births*>(0));
+
+  // We don't have queue durations without OS timer.  OS timer is automatically
+  // used for task-post-timing, so the use of an alternate timer implies all
+  // queue times are invalid, unless it was explicitly said that we can trust
+  // the alternate timer.
+  if (kAllowAlternateTimeSourceHandling &&
+      now_function_ &&
+      !now_function_is_time_) {
+    queue_duration = 0;
+  }
+
+  DeathMap::iterator it = death_map_.find(&births);
+  DeathData* death_data;
+  if (it != death_map_.end()) {
+    death_data = &it->second;
+  } else {
+    base::AutoLock lock(map_lock_);  // Lock as the map may get relocated now.
+    death_data = &death_map_[&births];
+  }  // Release lock ASAP.
+  death_data->RecordDeath(queue_duration, run_duration, random_number_);
+}
+
+// static
+Births* ThreadData::TallyABirthIfActive(const Location& location) {
+  if (!TrackingStatus())
+    return NULL;
+  ThreadData* current_thread_data = Get();
+  if (!current_thread_data)
+    return NULL;
+  return current_thread_data->TallyABirth(location);
+}
+
+// static
+void ThreadData::TallyRunOnNamedThreadIfTracking(
+    const base::TrackingInfo& completed_task,
+    const TaskStopwatch& stopwatch) {
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  const Births* births = completed_task.birth_tally;
+  if (!births)
+    return;
+  ThreadData* current_thread_data = stopwatch.GetThreadData();
+  if (!current_thread_data)
+    return;
+
+  // Watch out for a race where status_ is changing, and hence one or both
+  // of start_of_run or end_of_run is zero.  In that case, we didn't bother to
+  // get a time value since we "weren't tracking" and we were trying to be
+  // efficient by not calling for a genuine time value.  For simplicity, we'll
+  // use a default zero duration when we can't calculate a true value.
+  TrackedTime start_of_run = stopwatch.StartTime();
+  int32 queue_duration = 0;
+  if (!start_of_run.is_null()) {
+    queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
+        .InMilliseconds();
+  }
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
+}
+
+// static
+void ThreadData::TallyRunOnWorkerThreadIfTracking(
+    const Births* births,
+    const TrackedTime& time_posted,
+    const TaskStopwatch& stopwatch) {
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  if (!births)
+    return;
+
+  // TODO(jar): Support the option to coalesce all worker-thread activity under
+  // one ThreadData instance that uses locks to protect *all* access.  This will
+  // reduce memory (making it provably bounded), but run incrementally slower
+  // (since we'll use locks on TallyABirth and TallyADeath).  The good news is
+  // that the locks on TallyADeath will be *after* the worker thread has run,
+  // and hence nothing will be waiting for the completion (...  besides some
+  // other thread that might like to run).  Also, the worker threads tasks are
+  // generally longer, and hence the cost of the lock may perchance be amortized
+  // over the long task's lifetime.
+  ThreadData* current_thread_data = stopwatch.GetThreadData();
+  if (!current_thread_data)
+    return;
+
+  TrackedTime start_of_run = stopwatch.StartTime();
+  int32 queue_duration = 0;
+  if (!start_of_run.is_null()) {
+    queue_duration = (start_of_run - time_posted).InMilliseconds();
+  }
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
+}
+
+// static
+void ThreadData::TallyRunInAScopedRegionIfTracking(
+    const Births* births,
+    const TaskStopwatch& stopwatch) {
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  if (!births)
+    return;
+
+  ThreadData* current_thread_data = stopwatch.GetThreadData();
+  if (!current_thread_data)
+    return;
+
+  int32 queue_duration = 0;
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
+}
+
+void ThreadData::SnapshotExecutedTasks(
+    int current_profiling_phase,
+    PhasedProcessDataSnapshotMap* phased_snapshots,
+    BirthCountMap* birth_counts) {
+  // Get copy of data, so that the data will not change during the iterations
+  // and processing.
+  BirthMap birth_map;
+  DeathsSnapshot deaths;
+  SnapshotMaps(current_profiling_phase, &birth_map, &deaths);
+
+  for (const auto& birth : birth_map) {
+    (*birth_counts)[birth.second] += birth.second->birth_count();
+  }
+
+  for (const auto& death : deaths) {
+    (*birth_counts)[death.first] -= death.first->birth_count();
+
+    // For the current death data, walk through all its snapshots, starting from
+    // the current one, then from the previous profiling phase etc., and for
+    // each snapshot calculate the delta between the snapshot and the previous
+    // phase, if any.  Store the deltas in the result.
+    for (const DeathDataPhaseSnapshot* phase = &death.second; phase;
+         phase = phase->prev) {
+      const DeathDataSnapshot& death_data =
+          phase->prev ? phase->death_data.Delta(phase->prev->death_data)
+                      : phase->death_data;
+
+      if (death_data.count > 0) {
+        (*phased_snapshots)[phase->profiling_phase].tasks.push_back(
+            TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data,
+                         thread_name()));
+      }
+    }
+  }
+}
+
+// This may be called from another thread.
+void ThreadData::SnapshotMaps(int profiling_phase,
+                              BirthMap* birth_map,
+                              DeathsSnapshot* deaths) {
+  base::AutoLock lock(map_lock_);
+
+  for (const auto& birth : birth_map_)
+    (*birth_map)[birth.first] = birth.second;
+
+  for (const auto& death : death_map_) {
+    deaths->push_back(std::make_pair(
+        death.first,
+        DeathDataPhaseSnapshot(profiling_phase, death.second.count(),
+                               death.second.run_duration_sum(),
+                               death.second.run_duration_max(),
+                               death.second.run_duration_sample(),
+                               death.second.queue_duration_sum(),
+                               death.second.queue_duration_max(),
+                               death.second.queue_duration_sample(),
+                               death.second.last_phase_snapshot())));
+  }
+}
+
+void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) {
+  base::AutoLock lock(map_lock_);
+
+  for (auto& death : death_map_) {
+    death.second.OnProfilingPhaseCompleted(profiling_phase);
+  }
+}
+
+static void OptionallyInitializeAlternateTimer() {
+  NowFunction* alternate_time_source = GetAlternateTimeSource();
+  if (alternate_time_source)
+    ThreadData::SetAlternateTimeSource(alternate_time_source);
+}
+
+void ThreadData::Initialize() {
+  if (status_ >= DEACTIVATED)
+    return;  // Someone else did the initialization.
+  // Due to racy lazy initialization in tests, we'll need to recheck status_
+  // after we acquire the lock.
+
+  // Ensure that we don't double initialize tls.  We are called when single
+  // threaded in the product, but some tests may be racy and lazy about our
+  // initialization.
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (status_ >= DEACTIVATED)
+    return;  // Someone raced in here and beat us.
+
+  // Put an alternate timer in place if the environment calls for it, such as
+  // for tracking TCMalloc allocations.  This insertion is idempotent, so we
+  // don't mind if there is a race, and we'd prefer not to be in a lock while
+  // doing this work.
+  if (kAllowAlternateTimeSourceHandling)
+    OptionallyInitializeAlternateTimer();
+
+  // Perform the "real" TLS initialization now, and leave it intact through
+  // process termination.
+  if (!tls_index_.initialized()) {  // Testing may have initialized this.
+    DCHECK_EQ(status_, UNINITIALIZED);
+    tls_index_.Initialize(&ThreadData::OnThreadTermination);
+    DCHECK(tls_index_.initialized());
+  } else {
+    // TLS was initialzed for us earlier.
+    DCHECK_EQ(status_, DORMANT_DURING_TESTS);
+  }
+
+  // Incarnation counter is only significant to testing, as it otherwise will
+  // never again change in this process.
+  ++incarnation_counter_;
+
+  // The lock is not critical for setting status_, but it doesn't hurt.  It also
+  // ensures that if we have a racy initialization, that we'll bail as soon as
+  // we get the lock earlier in this method.
+  status_ = kInitialStartupState;
+  DCHECK(status_ != UNINITIALIZED);
+}
+
+// static
+void ThreadData::InitializeAndSetTrackingStatus(Status status) {
+  DCHECK_GE(status, DEACTIVATED);
+  DCHECK_LE(status, PROFILING_ACTIVE);
+
+  Initialize();  // No-op if already initialized.
+
+  if (status > DEACTIVATED)
+    status = PROFILING_ACTIVE;
+  status_ = status;
+}
+
+// static
+ThreadData::Status ThreadData::status() {
+  return status_;
+}
+
+// static
+bool ThreadData::TrackingStatus() {
+  return status_ > DEACTIVATED;
+}
+
+// static
+void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
+  DCHECK(now_function);
+  if (kAllowAlternateTimeSourceHandling)
+    now_function_ = now_function;
+}
+
+// static
+void ThreadData::EnableProfilerTiming() {
+  base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING);
+}
+
+// static
+TrackedTime ThreadData::Now() {
+  if (kAllowAlternateTimeSourceHandling && now_function_)
+    return TrackedTime::FromMilliseconds((*now_function_)());
+  if (IsProfilerTimingEnabled() && TrackingStatus())
+    return TrackedTime::Now();
+  return TrackedTime();  // Super fast when disabled, or not compiled.
+}
+
+// static
+void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) {
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (worker_thread_data_creation_count_ == 0)
+    return;  // We haven't really run much, and couldn't have leaked.
+
+  // TODO(jar): until this is working on XP, don't run the real test.
+#if 0
+  // Verify that we've at least shutdown/cleanup the major namesd threads.  The
+  // caller should tell us how many thread shutdowns should have taken place by
+  // now.
+  CHECK_GT(cleanup_count_, major_threads_shutdown_count);
+#endif
+}
+
+// static
+void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
+  // This is only called from test code, where we need to cleanup so that
+  // additional tests can be run.
+  // We must be single threaded... but be careful anyway.
+  InitializeAndSetTrackingStatus(DEACTIVATED);
+
+  ThreadData* thread_data_list;
+  {
+    base::AutoLock lock(*list_lock_.Pointer());
+    thread_data_list = all_thread_data_list_head_;
+    all_thread_data_list_head_ = NULL;
+    ++incarnation_counter_;
+    // To be clean, break apart the retired worker list (though we leak them).
+    while (first_retired_worker_) {
+      ThreadData* worker = first_retired_worker_;
+      CHECK_GT(worker->worker_thread_number_, 0);
+      first_retired_worker_ = worker->next_retired_worker_;
+      worker->next_retired_worker_ = NULL;
+    }
+  }
+
+  // Put most global static back in pristine shape.
+  worker_thread_data_creation_count_ = 0;
+  cleanup_count_ = 0;
+  tls_index_.Set(NULL);
+  status_ = DORMANT_DURING_TESTS;  // Almost UNINITIALIZED.
+
+  // To avoid any chance of racing in unit tests, which is the only place we
+  // call this function, we may sometimes leak all the data structures we
+  // recovered, as they may still be in use on threads from prior tests!
+  if (leak) {
+    ThreadData* thread_data = thread_data_list;
+    while (thread_data) {
+      ANNOTATE_LEAKING_OBJECT_PTR(thread_data);
+      thread_data = thread_data->next();
+    }
+    return;
+  }
+
+  // When we want to cleanup (on a single thread), here is what we do.
+
+  // Do actual recursive delete in all ThreadData instances.
+  while (thread_data_list) {
+    ThreadData* next_thread_data = thread_data_list;
+    thread_data_list = thread_data_list->next();
+
+    for (BirthMap::iterator it = next_thread_data->birth_map_.begin();
+         next_thread_data->birth_map_.end() != it; ++it)
+      delete it->second;  // Delete the Birth Records.
+    delete next_thread_data;  // Includes all Death Records.
+  }
+}
+
+//------------------------------------------------------------------------------
+TaskStopwatch::TaskStopwatch()
+    : wallclock_duration_ms_(0),
+      current_thread_data_(NULL),
+      excluded_duration_ms_(0),
+      parent_(NULL) {
+#if DCHECK_IS_ON()
+  state_ = CREATED;
+  child_ = NULL;
+#endif
+}
+
+TaskStopwatch::~TaskStopwatch() {
+#if DCHECK_IS_ON()
+  DCHECK(state_ != RUNNING);
+  DCHECK(child_ == NULL);
+#endif
+}
+
+void TaskStopwatch::Start() {
+#if DCHECK_IS_ON()
+  DCHECK(state_ == CREATED);
+  state_ = RUNNING;
+#endif
+
+  start_time_ = ThreadData::Now();
+
+  current_thread_data_ = ThreadData::Get();
+  if (!current_thread_data_)
+    return;
+
+  parent_ = current_thread_data_->current_stopwatch_;
+#if DCHECK_IS_ON()
+  if (parent_) {
+    DCHECK(parent_->state_ == RUNNING);
+    DCHECK(parent_->child_ == NULL);
+    parent_->child_ = this;
+  }
+#endif
+  current_thread_data_->current_stopwatch_ = this;
+}
+
+void TaskStopwatch::Stop() {
+  const TrackedTime end_time = ThreadData::Now();
+#if DCHECK_IS_ON()
+  DCHECK(state_ == RUNNING);
+  state_ = STOPPED;
+  DCHECK(child_ == NULL);
+#endif
+
+  if (!start_time_.is_null() && !end_time.is_null()) {
+    wallclock_duration_ms_ = (end_time - start_time_).InMilliseconds();
+  }
+
+  if (!current_thread_data_)
+    return;
+
+  DCHECK(current_thread_data_->current_stopwatch_ == this);
+  current_thread_data_->current_stopwatch_ = parent_;
+  if (!parent_)
+    return;
+
+#if DCHECK_IS_ON()
+  DCHECK(parent_->state_ == RUNNING);
+  DCHECK(parent_->child_ == this);
+  parent_->child_ = NULL;
+#endif
+  parent_->excluded_duration_ms_ += wallclock_duration_ms_;
+  parent_ = NULL;
+}
+
+TrackedTime TaskStopwatch::StartTime() const {
+#if DCHECK_IS_ON()
+  DCHECK(state_ != CREATED);
+#endif
+
+  return start_time_;
+}
+
+int32 TaskStopwatch::RunDurationMs() const {
+#if DCHECK_IS_ON()
+  DCHECK(state_ == STOPPED);
+#endif
+
+  return wallclock_duration_ms_ - excluded_duration_ms_;
+}
+
+ThreadData* TaskStopwatch::GetThreadData() const {
+#if DCHECK_IS_ON()
+  DCHECK(state_ != CREATED);
+#endif
+
+  return current_thread_data_;
+}
+
+//------------------------------------------------------------------------------
+// DeathDataPhaseSnapshot
+
+DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
+    int profiling_phase,
+    int count,
+    int32 run_duration_sum,
+    int32 run_duration_max,
+    int32 run_duration_sample,
+    int32 queue_duration_sum,
+    int32 queue_duration_max,
+    int32 queue_duration_sample,
+    const DeathDataPhaseSnapshot* prev)
+    : profiling_phase(profiling_phase),
+      death_data(count,
+                 run_duration_sum,
+                 run_duration_max,
+                 run_duration_sample,
+                 queue_duration_sum,
+                 queue_duration_max,
+                 queue_duration_sample),
+      prev(prev) {
+}
+
+//------------------------------------------------------------------------------
+// TaskSnapshot
+
+TaskSnapshot::TaskSnapshot() {
+}
+
+TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth,
+                           const DeathDataSnapshot& death_data,
+                           const std::string& death_thread_name)
+    : birth(birth),
+      death_data(death_data),
+      death_thread_name(death_thread_name) {
+}
+
+TaskSnapshot::~TaskSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataPhaseSnapshot
+
+ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
+}
+
+ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataPhaseSnapshot
+
+ProcessDataSnapshot::ProcessDataSnapshot()
+#if !defined(OS_NACL)
+    : process_id(base::GetCurrentProcId()) {
+#else
+    : process_id(base::kNullProcessId) {
+#endif
+}
+
+ProcessDataSnapshot::~ProcessDataSnapshot() {
+}
+
+}  // namespace tracked_objects
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
new file mode 100644
index 0000000..8f83794
--- /dev/null
+++ b/base/tracked_objects.h
@@ -0,0 +1,812 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACKED_OBJECTS_H_
+#define BASE_TRACKED_OBJECTS_H_
+
+#include <map>
+#include <set>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/process/process_handle.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/profiler/tracked_time.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+struct TrackingInfo;
+}
+
+// TrackedObjects provides a database of stats about objects (generally Tasks)
+// that are tracked.  Tracking means their birth, death, duration, birth thread,
+// death thread, and birth place are recorded.  This data is carefully spread
+// across a series of objects so that the counts and times can be rapidly
+// updated without (usually) having to lock the data, and hence there is usually
+// very little contention caused by the tracking.  The data can be viewed via
+// the about:profiler URL, with a variety of sorting and filtering choices.
+//
+// These classes serve as the basis of a profiler of sorts for the Tasks system.
+// As a result, design decisions were made to maximize speed, by minimizing
+// recurring allocation/deallocation, lock contention and data copying.  In the
+// "stable" state, which is reached relatively quickly, there is no separate
+// marginal allocation cost associated with construction or destruction of
+// tracked objects, no locks are generally employed, and probably the largest
+// computational cost is associated with obtaining start and stop times for
+// instances as they are created and destroyed.
+//
+// The following describes the life cycle of tracking an instance.
+//
+// First off, when the instance is created, the FROM_HERE macro is expanded
+// to specify the birth place (file, line, function) where the instance was
+// created.  That data is used to create a transient Location instance
+// encapsulating the above triple of information.  The strings (like __FILE__)
+// are passed around by reference, with the assumption that they are static, and
+// will never go away.  This ensures that the strings can be dealt with as atoms
+// with great efficiency (i.e., copying of strings is never needed, and
+// comparisons for equality can be based on pointer comparisons).
+//
+// Next, a Births instance is created for use ONLY on the thread where this
+// instance was created.  That Births instance records (in a base class
+// BirthOnThread) references to the static data provided in a Location instance,
+// as well as a pointer specifying the thread on which the birth takes place.
+// Hence there is at most one Births instance for each Location on each thread.
+// The derived Births class contains slots for recording statistics about all
+// instances born at the same location.  Statistics currently include only the
+// count of instances constructed.
+//
+// Since the base class BirthOnThread contains only constant data, it can be
+// freely accessed by any thread at any time (i.e., only the statistic needs to
+// be handled carefully, and stats are updated exclusively on the birth thread).
+//
+// For Tasks, having now either constructed or found the Births instance
+// described above, a pointer to the Births instance is then recorded into the
+// PendingTask structure in MessageLoop.  This fact alone is very useful in
+// debugging, when there is a question of where an instance came from.  In
+// addition, the birth time is also recorded and used to later evaluate the
+// lifetime duration of the whole Task.  As a result of the above embedding, we
+// can find out a Task's location of birth, and thread of birth, without using
+// any locks, as all that data is constant across the life of the process.
+//
+// The above work *could* also be done for any other object as well by calling
+// TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate.
+//
+// The amount of memory used in the above data structures depends on how many
+// threads there are, and how many Locations of construction there are.
+// Fortunately, we don't use memory that is the product of those two counts, but
+// rather we only need one Births instance for each thread that constructs an
+// instance at a Location.  In many cases, instances are only created on one
+// thread, so the memory utilization is actually fairly restrained.
+//
+// Lastly, when an instance is deleted, the final tallies of statistics are
+// carefully accumulated.  That tallying writes into slots (members) in a
+// collection of DeathData instances.  For each birth place Location that is
+// destroyed on a thread, there is a DeathData instance to record the additional
+// death count, as well as accumulate the run-time and queue-time durations for
+// the instance as it is destroyed (dies).  By maintaining a single place to
+// aggregate this running sum *only* for the given thread, we avoid the need to
+// lock such DeathData instances. (i.e., these accumulated stats in a DeathData
+// instance are exclusively updated by the singular owning thread).
+//
+// With the above life cycle description complete, the major remaining detail
+// is explaining how each thread maintains a list of DeathData instances, and
+// of Births instances, and is able to avoid additional (redundant/unnecessary)
+// allocations.
+//
+// Each thread maintains a list of data items specific to that thread in a
+// ThreadData instance (for that specific thread only).  The two critical items
+// are lists of DeathData and Births instances.  These lists are maintained in
+// STL maps, which are indexed by Location.  As noted earlier, we can compare
+// locations very efficiently as we consider the underlying data (file,
+// function, line) to be atoms, and hence pointer comparison is used rather than
+// (slow) string comparisons.
+//
+// To provide a mechanism for iterating over all "known threads," which means
+// threads that have recorded a birth or a death, we create a singly linked list
+// of ThreadData instances.  Each such instance maintains a pointer to the next
+// one.  A static member of ThreadData provides a pointer to the first item on
+// this global list, and access via that all_thread_data_list_head_ item
+// requires the use of the list_lock_.
+// When new ThreadData instances is added to the global list, it is pre-pended,
+// which ensures that any prior acquisition of the list is valid (i.e., the
+// holder can iterate over it without fear of it changing, or the necessity of
+// using an additional lock.  Iterations are actually pretty rare (used
+// primarily for cleanup, or snapshotting data for display), so this lock has
+// very little global performance impact.
+//
+// The above description tries to define the high performance (run time)
+// portions of these classes.  After gathering statistics, calls instigated
+// by visiting about:profiler will assemble and aggregate data for display.  The
+// following data structures are used for producing such displays.  They are
+// not performance critical, and their only major constraint is that they should
+// be able to run concurrently with ongoing augmentation of the birth and death
+// data.
+//
+// This header also exports collection of classes that provide "snapshotted"
+// representations of the core tracked_objects:: classes.  These snapshotted
+// representations are designed for safe transmission of the tracked_objects::
+// data across process boundaries.  Each consists of:
+// (1) a default constructor, to support the IPC serialization macros,
+// (2) a constructor that extracts data from the type being snapshotted, and
+// (3) the snapshotted data.
+//
+// For a given birth location, information about births is spread across data
+// structures that are asynchronously changing on various threads.  For
+// serialization and display purposes, we need to construct TaskSnapshot
+// instances for each combination of birth thread, death thread, and location,
+// along with the count of such lifetimes.  We gather such data into a
+// TaskSnapshot instances, so that such instances can be sorted and
+// aggregated (and remain frozen during our processing).
+//
+// Profiling consists of phases.  The concrete phase in the sequence of phases
+// is identified by its 0-based index.
+//
+// The ProcessDataPhaseSnapshot struct is a serialized representation of the
+// list of ThreadData objects for a process for a concrete profiling phase.  It
+// holds a set of TaskSnapshots.  The statistics in a snapshot are gathered
+// asynhcronously relative to their ongoing updates.
+// It is possible, though highly unlikely, that stats could be incorrectly
+// recorded by this process (all data is held in 32 bit ints, but we are not
+// atomically collecting all data, so we could have count that does not, for
+// example, match with the number of durations we accumulated).  The advantage
+// to having fast (non-atomic) updates of the data outweighs the minimal risk of
+// a singular corrupt statistic snapshot (only the snapshot could be corrupt,
+// not the underlying and ongoing statistic).  In contrast, pointer data that
+// is accessed during snapshotting is completely invariant, and hence is
+// perfectly acquired (i.e., no potential corruption, and no risk of a bad
+// memory reference).
+//
+// TODO(jar): We can implement a Snapshot system that *tries* to grab the
+// snapshots on the source threads *when* they have MessageLoops available
+// (worker threads don't have message loops generally, and hence gathering from
+// them will continue to be asynchronous).  We had an implementation of this in
+// the past, but the difficulty is dealing with message loops being terminated.
+// We can *try* to spam the available threads via some message loop proxy to
+// achieve this feat, and it *might* be valuable when we are collecting data
+// for upload via UMA (where correctness of data may be more significant than
+// for a single screen of about:profiler).
+//
+// TODO(jar): We need to store DataCollections, and provide facilities for
+// taking the difference between two gathered DataCollections.  For now, we're
+// just adding a hack that Reset()s to zero all counts and stats.  This is also
+// done in a slightly thread-unsafe fashion, as the resetting is done
+// asynchronously relative to ongoing updates (but all data is 32 bit in size).
+// For basic profiling, this will work "most of the time," and should be
+// sufficient... but storing away DataCollections is the "right way" to do this.
+// We'll accomplish this via JavaScript storage of snapshots, and then we'll
+// remove the Reset() methods.  We may also need a short-term-max value in
+// DeathData that is reset (as synchronously as possible) during each snapshot.
+// This will facilitate displaying a max value for each snapshot period.
+
+namespace tracked_objects {
+
+//------------------------------------------------------------------------------
+// For a specific thread, and a specific birth place, the collection of all
+// death info (with tallies for each death thread, to prevent access conflicts).
+class ThreadData;
+class BASE_EXPORT BirthOnThread {
+ public:
+  BirthOnThread(const Location& location, const ThreadData& current);
+
+  const Location location() const { return location_; }
+  const ThreadData* birth_thread() const { return birth_thread_; }
+
+ private:
+  // File/lineno of birth.  This defines the essence of the task, as the context
+  // of the birth (construction) often tell what the item is for.  This field
+  // is const, and hence safe to access from any thread.
+  const Location location_;
+
+  // The thread that records births into this object.  Only this thread is
+  // allowed to update birth_count_ (which changes over time).
+  const ThreadData* const birth_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the BirthOnThread class.
+
+struct BASE_EXPORT BirthOnThreadSnapshot {
+  BirthOnThreadSnapshot();
+  explicit BirthOnThreadSnapshot(const BirthOnThread& birth);
+  ~BirthOnThreadSnapshot();
+
+  LocationSnapshot location;
+  std::string thread_name;
+};
+
+//------------------------------------------------------------------------------
+// A class for accumulating counts of births (without bothering with a map<>).
+
+class BASE_EXPORT Births: public BirthOnThread {
+ public:
+  Births(const Location& location, const ThreadData& current);
+
+  int birth_count() const;
+
+  // When we have a birth we update the count for this birthplace.
+  void RecordBirth();
+
+ private:
+  // The number of births on this thread for our location_.
+  int birth_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(Births);
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData class.
+
+struct BASE_EXPORT DeathDataSnapshot {
+  DeathDataSnapshot();
+
+  // Constructs the snapshot from individual values.
+  // The alternative would be taking a DeathData parameter, but this would
+  // create a loop since DeathData indirectly refers DeathDataSnapshot.  Passing
+  // a wrapper structure as a param or using an empty constructor for
+  // snapshotting DeathData would be less efficient.
+  DeathDataSnapshot(int count,
+                    int32 run_duration_sum,
+                    int32 run_duration_max,
+                    int32 run_duration_sample,
+                    int32 queue_duration_sum,
+                    int32 queue_duration_max,
+                    int32 queue_duration_sample);
+  ~DeathDataSnapshot();
+
+  // Calculates and returns the delta between this snapshot and an earlier
+  // snapshot of the same task |older|.
+  DeathDataSnapshot Delta(const DeathDataSnapshot& older) const;
+
+  int count;
+  int32 run_duration_sum;
+  int32 run_duration_max;
+  int32 run_duration_sample;
+  int32 queue_duration_sum;
+  int32 queue_duration_max;
+  int32 queue_duration_sample;
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData for a particular profiling
+// phase.  Used as an element of the list of phase snapshots owned by DeathData.
+
+struct DeathDataPhaseSnapshot {
+  DeathDataPhaseSnapshot(int profiling_phase,
+                         int count,
+                         int32 run_duration_sum,
+                         int32 run_duration_max,
+                         int32 run_duration_sample,
+                         int32 queue_duration_sum,
+                         int32 queue_duration_max,
+                         int32 queue_duration_sample,
+                         const DeathDataPhaseSnapshot* prev);
+
+  // Profiling phase at which completion this snapshot was taken.
+  int profiling_phase;
+
+  // Death data snapshot.
+  DeathDataSnapshot death_data;
+
+  // Pointer to a snapshot from the previous phase.
+  const DeathDataPhaseSnapshot* prev;
+};
+
+//------------------------------------------------------------------------------
+// Information about deaths of a task on a given thread, called "death thread".
+// Access to members of this class is never protected by a lock.  The fields
+// are accessed in such a way that corruptions resulting from race conditions
+// are not significant, and don't accumulate as a result of multiple accesses.
+// All invocations of DeathData::OnProfilingPhaseCompleted and
+// ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process
+// must be called from the same thread. It doesn't matter what thread it is, but
+// it's important the same thread is used as a snapshot thread during the whole
+// process lifetime.  All fields except sample_probability_count_ can be
+// snapshotted.
+
+class BASE_EXPORT DeathData {
+ public:
+  DeathData();
+  DeathData(const DeathData& other);
+  ~DeathData();
+
+  // Update stats for a task destruction (death) that had a Run() time of
+  // |duration|, and has had a queueing delay of |queue_duration|.
+  void RecordDeath(const int32 queue_duration,
+                   const int32 run_duration,
+                   const uint32 random_number);
+
+  // Metrics and past snapshots accessors, used only for serialization and in
+  // tests.
+  int count() const { return count_; }
+  int32 run_duration_sum() const { return run_duration_sum_; }
+  int32 run_duration_max() const { return run_duration_max_; }
+  int32 run_duration_sample() const { return run_duration_sample_; }
+  int32 queue_duration_sum() const { return queue_duration_sum_; }
+  int32 queue_duration_max() const { return queue_duration_max_; }
+  int32 queue_duration_sample() const { return queue_duration_sample_; }
+  const DeathDataPhaseSnapshot* last_phase_snapshot() const {
+    return last_phase_snapshot_;
+  }
+
+  // Called when the current profiling phase, identified by |profiling_phase|,
+  // ends.
+  // Must be called only on the snapshot thread.
+  void OnProfilingPhaseCompleted(int profiling_phase);
+
+ private:
+  // Members are ordered from most regularly read and updated, to least
+  // frequently used.  This might help a bit with cache lines.
+  // Number of runs seen (divisor for calculating averages).
+  // Can be incremented only on the death thread.
+  int count_;
+
+  // Count used in determining probability of selecting exec/queue times from a
+  // recorded death as samples.
+  // Gets incremented only on the death thread, but can be set to 0 by
+  // OnProfilingPhaseCompleted() on the snapshot thread.
+  int sample_probability_count_;
+
+  // Basic tallies, used to compute averages.  Can be incremented only on the
+  // death thread.
+  int32 run_duration_sum_;
+  int32 queue_duration_sum_;
+  // Max values, used by local visualization routines.  These are often read,
+  // but rarely updated.  The max values get assigned only on the death thread,
+  // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the
+  // snapshot thread.
+  int32 run_duration_max_;
+  int32 queue_duration_max_;
+  // Samples, used by crowd sourcing gatherers.  These are almost never read,
+  // and rarely updated.  They can be modified only on the death thread.
+  int32 run_duration_sample_;
+  int32 queue_duration_sample_;
+
+  // Snapshot of this death data made at the last profiling phase completion, if
+  // any.  DeathData owns the whole list starting with this pointer.
+  // Can be accessed only on the snapshot thread.
+  const DeathDataPhaseSnapshot* last_phase_snapshot_;
+
+  DISALLOW_ASSIGN(DeathData);
+};
+
+//------------------------------------------------------------------------------
+// A temporary collection of data that can be sorted and summarized.  It is
+// gathered (carefully) from many threads.  Instances are held in arrays and
+// processed, filtered, and rendered.
+// The source of this data was collected on many threads, and is asynchronously
+// changing.  The data in this instance is not asynchronously changing.
+
+struct BASE_EXPORT TaskSnapshot {
+  TaskSnapshot();
+  TaskSnapshot(const BirthOnThreadSnapshot& birth,
+               const DeathDataSnapshot& death_data,
+               const std::string& death_thread_name);
+  ~TaskSnapshot();
+
+  BirthOnThreadSnapshot birth;
+  // Delta between death data for a thread for a certain profiling phase and the
+  // snapshot for the pervious phase, if any.  Otherwise, just a snapshot.
+  DeathDataSnapshot death_data;
+  std::string death_thread_name;
+};
+
+//------------------------------------------------------------------------------
+// For each thread, we have a ThreadData that stores all tracking info generated
+// on this thread.  This prevents the need for locking as data accumulates.
+// We use ThreadLocalStorage to quickly identfy the current ThreadData context.
+// We also have a linked list of ThreadData instances, and that list is used to
+// harvest data from all existing instances.
+
+struct ProcessDataPhaseSnapshot;
+struct ProcessDataSnapshot;
+class BASE_EXPORT TaskStopwatch;
+
+// Map from profiling phase number to the process-wide snapshotted
+// representation of the list of ThreadData objects that died during the given
+// phase.
+typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap;
+
+class BASE_EXPORT ThreadData {
+ public:
+  // Current allowable states of the tracking system.  The states can vary
+  // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
+  enum Status {
+    UNINITIALIZED,         // Pristine, link-time state before running.
+    DORMANT_DURING_TESTS,  // Only used during testing.
+    DEACTIVATED,           // No longer recording profiling.
+    PROFILING_ACTIVE,      // Recording profiles.
+    STATUS_LAST = PROFILING_ACTIVE
+  };
+
+  typedef base::hash_map<Location, Births*, Location::Hash> BirthMap;
+  typedef std::map<const Births*, DeathData> DeathMap;
+
+  // Initialize the current thread context with a new instance of ThreadData.
+  // This is used by all threads that have names, and should be explicitly
+  // set *before* any births on the threads have taken place.  It is generally
+  // only used by the message loop, which has a well defined thread name.
+  static void InitializeThreadContext(const std::string& suggested_name);
+
+  // Using Thread Local Store, find the current instance for collecting data.
+  // If an instance does not exist, construct one (and remember it for use on
+  // this thread.
+  // This may return NULL if the system is disabled for any reason.
+  static ThreadData* Get();
+
+  // Fills |process_data_snapshot| with phased snapshots of all profiling
+  // phases, including the current one, identified by |current_profiling_phase|.
+  // |current_profiling_phase| is necessary because a child process can start
+  // after several phase-changing events, so it needs to receive the current
+  // phase number from the browser process to fill the correct entry for the
+  // current phase in the |process_data_snapshot| map.
+  static void Snapshot(int current_profiling_phase,
+                       ProcessDataSnapshot* process_data_snapshot);
+
+  // Called when the current profiling phase, identified by |profiling_phase|,
+  // ends.
+  // |profiling_phase| is necessary because a child process can start after
+  // several phase-changing events, so it needs to receive the phase number from
+  // the browser process to fill the correct entry in the
+  // completed_phases_snapshots_ map.
+  static void OnProfilingPhaseCompleted(int profiling_phase);
+
+  // Finds (or creates) a place to count births from the given location in this
+  // thread, and increment that tally.
+  // TallyABirthIfActive will returns NULL if the birth cannot be tallied.
+  static Births* TallyABirthIfActive(const Location& location);
+
+  // Records the end of a timed run of an object.  The |completed_task| contains
+  // a pointer to a Births, the time_posted, and a delayed_start_time if any.
+  // The |start_of_run| indicates when we started to perform the run of the
+  // task.  The delayed_start_time is non-null for tasks that were posted as
+  // delayed tasks, and it indicates when the task should have run (i.e., when
+  // it should have posted out of the timer queue, and into the work queue.
+  // The |end_of_run| was just obtained by a call to Now() (just after the task
+  // finished).  It is provided as an argument to help with testing.
+  static void TallyRunOnNamedThreadIfTracking(
+      const base::TrackingInfo& completed_task,
+      const TaskStopwatch& stopwatch);
+
+  // Record the end of a timed run of an object.  The |birth| is the record for
+  // the instance, the |time_posted| records that instant, which is presumed to
+  // be when the task was posted into a queue to run on a worker thread.
+  // The |start_of_run| is when the worker thread started to perform the run of
+  // the task.
+  // The |end_of_run| was just obtained by a call to Now() (just after the task
+  // finished).
+  static void TallyRunOnWorkerThreadIfTracking(const Births* births,
+                                               const TrackedTime& time_posted,
+                                               const TaskStopwatch& stopwatch);
+
+  // Record the end of execution in region, generally corresponding to a scope
+  // being exited.
+  static void TallyRunInAScopedRegionIfTracking(const Births* births,
+                                                const TaskStopwatch& stopwatch);
+
+  const std::string& thread_name() const { return thread_name_; }
+
+  // Initializes all statics if needed (this initialization call should be made
+  // while we are single threaded).
+  static void Initialize();
+
+  // Sets internal status_.
+  // If |status| is false, then status_ is set to DEACTIVATED.
+  // If |status| is true, then status_ is set to PROFILING_ACTIVE.
+  static void InitializeAndSetTrackingStatus(Status status);
+
+  static Status status();
+
+  // Indicate if any sort of profiling is being done (i.e., we are more than
+  // DEACTIVATED).
+  static bool TrackingStatus();
+
+  // Enables profiler timing.
+  static void EnableProfilerTiming();
+
+  // Provide a time function that does nothing (runs fast) when we don't have
+  // the profiler enabled.  It will generally be optimized away when it is
+  // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of
+  // the code).
+  static TrackedTime Now();
+
+  // Use the function |now| to provide current times, instead of calling the
+  // TrackedTime::Now() function.  Since this alternate function is being used,
+  // the other time arguments (used for calculating queueing delay) will be
+  // ignored.
+  static void SetAlternateTimeSource(NowFunction* now);
+
+  // This function can be called at process termination to validate that thread
+  // cleanup routines have been called for at least some number of named
+  // threads.
+  static void EnsureCleanupWasCalled(int major_threads_shutdown_count);
+
+ private:
+  friend class TaskStopwatch;
+  // Allow only tests to call ShutdownSingleThreadedCleanup.  We NEVER call it
+  // in production code.
+  // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a
+  // better change of optimizing (inlining? etc.) private methods (knowing that
+  // there will be no need for an external entry point).
+  friend class TrackedObjectsTest;
+  FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown);
+  FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown);
+
+  typedef std::map<const BirthOnThread*, int> BirthCountMap;
+
+  typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>>
+      DeathsSnapshot;
+
+  // Worker thread construction creates a name since there is none.
+  explicit ThreadData(int thread_number);
+
+  // Message loop based construction should provide a name.
+  explicit ThreadData(const std::string& suggested_name);
+
+  ~ThreadData();
+
+  // Push this instance to the head of all_thread_data_list_head_, linking it to
+  // the previous head.  This is performed after each construction, and leaves
+  // the instance permanently on that list.
+  void PushToHeadOfList();
+
+  // (Thread safe) Get start of list of all ThreadData instances using the lock.
+  static ThreadData* first();
+
+  // Iterate through the null terminated list of ThreadData instances.
+  ThreadData* next() const;
+
+
+  // In this thread's data, record a new birth.
+  Births* TallyABirth(const Location& location);
+
+  // Find a place to record a death on this thread.
+  void TallyADeath(const Births& births,
+                   int32 queue_duration,
+                   const TaskStopwatch& stopwatch);
+
+  // Snapshots (under a lock) the profiled data for the tasks for this thread
+  // and writes all of the executed tasks' data -- i.e. the data for all
+  // profiling phases (including the current one: |current_profiling_phase|) for
+  // the tasks with with entries in the death_map_ -- into |phased_snapshots|.
+  // Also updates the |birth_counts| tally for each task to keep track of the
+  // number of living instances of the task -- that is, each task maps to the
+  // number of births for the task that have not yet been balanced by a death.
+  void SnapshotExecutedTasks(int current_profiling_phase,
+                             PhasedProcessDataSnapshotMap* phased_snapshots,
+                             BirthCountMap* birth_counts);
+
+  // Using our lock, make a copy of the specified maps.  This call may be made
+  // on  non-local threads, which necessitate the use of the lock to prevent
+  // the map(s) from being reallocated while they are copied.
+  void SnapshotMaps(int profiling_phase,
+                    BirthMap* birth_map,
+                    DeathsSnapshot* deaths);
+
+  // Called for this thread when the current profiling phase, identified by
+  // |profiling_phase|, ends.
+  void OnProfilingPhaseCompletedOnThread(int profiling_phase);
+
+  // This method is called by the TLS system when a thread terminates.
+  // The argument may be NULL if this thread has never tracked a birth or death.
+  static void OnThreadTermination(void* thread_data);
+
+  // This method should be called when a worker thread terminates, so that we
+  // can save all the thread data into a cache of reusable ThreadData instances.
+  void OnThreadTerminationCleanup();
+
+  // Cleans up data structures, and returns statics to near pristine (mostly
+  // uninitialized) state.  If there is any chance that other threads are still
+  // using the data structures, then the |leak| argument should be passed in as
+  // true, and the data structures (birth maps, death maps, ThreadData
+  // insntances, etc.) will be leaked and not deleted.  If you have joined all
+  // threads since the time that InitializeAndSetTrackingStatus() was called,
+  // then you can pass in a |leak| value of false, and this function will
+  // delete recursively all data structures, starting with the list of
+  // ThreadData instances.
+  static void ShutdownSingleThreadedCleanup(bool leak);
+
+  // When non-null, this specifies an external function that supplies monotone
+  // increasing time functcion.
+  static NowFunction* now_function_;
+
+  // If true, now_function_ returns values that can be used to calculate queue
+  // time.
+  static bool now_function_is_time_;
+
+  // We use thread local store to identify which ThreadData to interact with.
+  static base::ThreadLocalStorage::StaticSlot tls_index_;
+
+  // List of ThreadData instances for use with worker threads.  When a worker
+  // thread is done (terminated), we push it onto this list.  When a new worker
+  // thread is created, we first try to re-use a ThreadData instance from the
+  // list, and if none are available, construct a new one.
+  // This is only accessed while list_lock_ is held.
+  static ThreadData* first_retired_worker_;
+
+  // Link to the most recently created instance (starts a null terminated list).
+  // The list is traversed by about:profiler when it needs to snapshot data.
+  // This is only accessed while list_lock_ is held.
+  static ThreadData* all_thread_data_list_head_;
+
+  // The next available worker thread number.  This should only be accessed when
+  // the list_lock_ is held.
+  static int worker_thread_data_creation_count_;
+
+  // The number of times TLS has called us back to cleanup a ThreadData
+  // instance.  This is only accessed while list_lock_ is held.
+  static int cleanup_count_;
+
+  // Incarnation sequence number, indicating how many times (during unittests)
+  // we've either transitioned out of UNINITIALIZED, or into that state.  This
+  // value is only accessed while the list_lock_ is held.
+  static int incarnation_counter_;
+
+  // Protection for access to all_thread_data_list_head_, and to
+  // unregistered_thread_data_pool_.  This lock is leaked at shutdown.
+  // The lock is very infrequently used, so we can afford to just make a lazy
+  // instance and be safe.
+  static base::LazyInstance<base::Lock>::Leaky list_lock_;
+
+  // We set status_ to SHUTDOWN when we shut down the tracking service.
+  static Status status_;
+
+  // Link to next instance (null terminated list).  Used to globally track all
+  // registered instances (corresponds to all registered threads where we keep
+  // data).
+  ThreadData* next_;
+
+  // Pointer to another ThreadData instance for a Worker-Thread that has been
+  // retired (its thread was terminated).  This value is non-NULL only for a
+  // retired ThreadData associated with a Worker-Thread.
+  ThreadData* next_retired_worker_;
+
+  // The name of the thread that is being recorded.  If this thread has no
+  // message_loop, then this is a worker thread, with a sequence number postfix.
+  std::string thread_name_;
+
+  // Indicate if this is a worker thread, and the ThreadData contexts should be
+  // stored in the unregistered_thread_data_pool_ when not in use.
+  // Value is zero when it is not a worker thread.  Value is a positive integer
+  // corresponding to the created thread name if it is a worker thread.
+  int worker_thread_number_;
+
+  // A map used on each thread to keep track of Births on this thread.
+  // This map should only be accessed on the thread it was constructed on.
+  // When a snapshot is needed, this structure can be locked in place for the
+  // duration of the snapshotting activity.
+  BirthMap birth_map_;
+
+  // Similar to birth_map_, this records informations about death of tracked
+  // instances (i.e., when a tracked instance was destroyed on this thread).
+  // It is locked before changing, and hence other threads may access it by
+  // locking before reading it.
+  DeathMap death_map_;
+
+  // Lock to protect *some* access to BirthMap and DeathMap.  The maps are
+  // regularly read and written on this thread, but may only be read from other
+  // threads.  To support this, we acquire this lock if we are writing from this
+  // thread, or reading from another thread.  For reading from this thread we
+  // don't need a lock, as there is no potential for a conflict since the
+  // writing is only done from this thread.
+  mutable base::Lock map_lock_;
+
+  // A random number that we used to select decide which sample to keep as a
+  // representative sample in each DeathData instance.  We can't start off with
+  // much randomness (because we can't call RandInt() on all our threads), so
+  // we stir in more and more as we go.
+  uint32 random_number_;
+
+  // Record of what the incarnation_counter_ was when this instance was created.
+  // If the incarnation_counter_ has changed, then we avoid pushing into the
+  // pool (this is only critical in tests which go through multiple
+  // incarnations).
+  int incarnation_count_for_pool_;
+
+  // Most recently started (i.e. most nested) stopwatch on the current thread,
+  // if it exists; NULL otherwise.
+  TaskStopwatch* current_stopwatch_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadData);
+};
+
+//------------------------------------------------------------------------------
+// Stopwatch to measure task run time or simply create a time interval that will
+// be subtracted from the current most nested task's run time.  Stopwatches
+// coordinate with the stopwatches in which they are nested to avoid
+// double-counting nested tasks run times.
+
+class BASE_EXPORT TaskStopwatch {
+ public:
+  // Starts the stopwatch.
+  TaskStopwatch();
+  ~TaskStopwatch();
+
+  // Starts stopwatch.
+  void Start();
+
+  // Stops stopwatch.
+  void Stop();
+
+  // Returns the start time.
+  TrackedTime StartTime() const;
+
+  // Task's duration is calculated as the wallclock duration between starting
+  // and stopping this stopwatch, minus the wallclock durations of any other
+  // instances that are immediately nested in this one, started and stopped on
+  // this thread during that period.
+  int32 RunDurationMs() const;
+
+  // Returns tracking info for the current thread.
+  ThreadData* GetThreadData() const;
+
+ private:
+  // Time when the stopwatch was started.
+  TrackedTime start_time_;
+
+  // Wallclock duration of the task.
+  int32 wallclock_duration_ms_;
+
+  // Tracking info for the current thread.
+  ThreadData* current_thread_data_;
+
+  // Sum of wallclock durations of all stopwatches that were directly nested in
+  // this one.
+  int32 excluded_duration_ms_;
+
+  // Stopwatch which was running on our thread when this stopwatch was started.
+  // That preexisting stopwatch must be adjusted to the exclude the wallclock
+  // duration of this stopwatch.
+  TaskStopwatch* parent_;
+
+#if DCHECK_IS_ON()
+  // State of the stopwatch.  Stopwatch is first constructed in a created state
+  // state, then is optionally started/stopped, then destructed.
+  enum { CREATED, RUNNING, STOPPED } state_;
+
+  // Currently running stopwatch that is directly nested in this one, if such
+  // stopwatch exists.  NULL otherwise.
+  TaskStopwatch* child_;
+#endif
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for a single profiling phase.
+
+struct BASE_EXPORT ProcessDataPhaseSnapshot {
+ public:
+  ProcessDataPhaseSnapshot();
+  ~ProcessDataPhaseSnapshot();
+
+  std::vector<TaskSnapshot> tasks;
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for all profiling phases, including the current one.
+
+struct BASE_EXPORT ProcessDataSnapshot {
+ public:
+  ProcessDataSnapshot();
+  ~ProcessDataSnapshot();
+
+  PhasedProcessDataSnapshotMap phased_snapshots;
+  base::ProcessId process_id;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_TRACKED_OBJECTS_H_
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
new file mode 100644
index 0000000..cdbf9ac
--- /dev/null
+++ b/base/tracked_objects_unittest.cc
@@ -0,0 +1,1186 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test of classes in the tracked_objects.h classes.
+
+#include "base/tracked_objects.h"
+
+#include <stddef.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "base/tracking_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const int kLineNumber = 1776;
+const char kFile[] = "FixedUnitTestFileName";
+const char kWorkerThreadName[] = "WorkerThread-1";
+const char kMainThreadName[] = "SomeMainThreadName";
+const char kStillAlive[] = "Still_Alive";
+
+namespace tracked_objects {
+
+class TrackedObjectsTest : public testing::Test {
+ protected:
+  TrackedObjectsTest() {
+    // On entry, leak any database structures in case they are still in use by
+    // prior threads.
+    ThreadData::ShutdownSingleThreadedCleanup(true);
+
+    test_time_ = 0;
+    ThreadData::SetAlternateTimeSource(&TrackedObjectsTest::GetTestTime);
+    ThreadData::now_function_is_time_ = true;
+  }
+
+  ~TrackedObjectsTest() override {
+    // We should not need to leak any structures we create, since we are
+    // single threaded, and carefully accounting for items.
+    ThreadData::ShutdownSingleThreadedCleanup(false);
+  }
+
+  // Reset the profiler state.
+  void Reset() {
+    ThreadData::ShutdownSingleThreadedCleanup(false);
+    test_time_ = 0;
+  }
+
+  // Simulate a birth on the thread named |thread_name|, at the given
+  // |location|.
+  void TallyABirth(const Location& location, const std::string& thread_name) {
+    // If the |thread_name| is empty, we don't initialize system with a thread
+    // name, so we're viewed as a worker thread.
+    if (!thread_name.empty())
+      ThreadData::InitializeThreadContext(kMainThreadName);
+
+    // Do not delete |birth|.  We don't own it.
+    Births* birth = ThreadData::TallyABirthIfActive(location);
+
+    if (ThreadData::status() == ThreadData::DEACTIVATED)
+      EXPECT_EQ(reinterpret_cast<Births*>(NULL), birth);
+    else
+      EXPECT_NE(reinterpret_cast<Births*>(NULL), birth);
+  }
+
+  // Helper function to verify the most common test expectations.
+  void ExpectSimpleProcessData(const ProcessDataSnapshot& process_data,
+                               const std::string& function_name,
+                               const std::string& birth_thread,
+                               const std::string& death_thread,
+                               int count,
+                               int run_ms,
+                               int queue_ms) {
+    ASSERT_EQ(1u, process_data.phased_snapshots.size());
+    auto it = process_data.phased_snapshots.find(0);
+    ASSERT_TRUE(it != process_data.phased_snapshots.end());
+    const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+    ASSERT_EQ(1u, process_data_phase.tasks.size());
+
+    EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+    EXPECT_EQ(function_name,
+              process_data_phase.tasks[0].birth.location.function_name);
+    EXPECT_EQ(kLineNumber,
+              process_data_phase.tasks[0].birth.location.line_number);
+
+    EXPECT_EQ(birth_thread, process_data_phase.tasks[0].birth.thread_name);
+
+    EXPECT_EQ(count, process_data_phase.tasks[0].death_data.count);
+    EXPECT_EQ(count * run_ms,
+              process_data_phase.tasks[0].death_data.run_duration_sum);
+    EXPECT_EQ(run_ms, process_data_phase.tasks[0].death_data.run_duration_max);
+    EXPECT_EQ(run_ms,
+              process_data_phase.tasks[0].death_data.run_duration_sample);
+    EXPECT_EQ(count * queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_sum);
+    EXPECT_EQ(queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_max);
+    EXPECT_EQ(queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_sample);
+
+    EXPECT_EQ(death_thread, process_data_phase.tasks[0].death_thread_name);
+
+    EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+  }
+
+  // Sets time that will be returned by ThreadData::Now().
+  static void SetTestTime(unsigned int test_time) { test_time_ = test_time; }
+
+ private:
+  // Returns test time in milliseconds.
+  static unsigned int GetTestTime() { return test_time_; }
+
+  // Test time in milliseconds.
+  static unsigned int test_time_;
+};
+
+// static
+unsigned int TrackedObjectsTest::test_time_;
+
+TEST_F(TrackedObjectsTest, TaskStopwatchNoStartStop) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  // Check that creating and destroying a stopwatch without starting it doesn't
+  // crash.
+  TaskStopwatch stopwatch;
+}
+
+TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
+  // Minimal test doesn't even create any tasks.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  EXPECT_FALSE(ThreadData::first());  // No activity even on this thread.
+  ThreadData* data = ThreadData::Get();
+  EXPECT_TRUE(ThreadData::first());  // Now class was constructed.
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  ThreadData::BirthMap birth_map;
+  ThreadData::DeathsSnapshot deaths;
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(0u, birth_map.size());
+  EXPECT_EQ(0u, deaths.size());
+
+  // Clean up with no leaking.
+  Reset();
+
+  // Do it again, just to be sure we reset state completely.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+  EXPECT_FALSE(ThreadData::first());  // No activity even on this thread.
+  data = ThreadData::Get();
+  EXPECT_TRUE(ThreadData::first());  // Now class was constructed.
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  birth_map.clear();
+  deaths.clear();
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(0u, birth_map.size());
+  EXPECT_EQ(0u, deaths.size());
+}
+
+TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  // Instigate tracking on a single tracked object, on our thread.
+  const char kFunction[] = "TinyStartupShutdown";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::TallyABirthIfActive(location);
+
+  ThreadData* data = ThreadData::first();
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  ThreadData::BirthMap birth_map;
+  ThreadData::DeathsSnapshot deaths;
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
+  EXPECT_EQ(1, birth_map.begin()->second->birth_count());  // 1 birth.
+  EXPECT_EQ(0u, deaths.size());                            // No deaths.
+
+
+  // Now instigate another birth, while we are timing the run of the first
+  // execution.
+  // Create a child (using the same birth location).
+  // TrackingInfo will call TallyABirth() during construction.
+  const int32 start_time = 1;
+  base::TimeTicks kBogusBirthTime = base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(start_time);
+  base::TrackingInfo pending_task(location, kBogusBirthTime);
+  SetTestTime(1);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  // Finally conclude the outer run.
+  const int32 time_elapsed = 1000;
+  SetTestTime(start_time + time_elapsed);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  birth_map.clear();
+  deaths.clear();
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
+  EXPECT_EQ(2, birth_map.begin()->second->birth_count());  // 2 births.
+  EXPECT_EQ(1u, deaths.size());                            // 1 location.
+  EXPECT_EQ(1, deaths.begin()->second.death_data.count);   // 1 death.
+
+  // The births were at the same location as the one known death.
+  EXPECT_EQ(birth_map.begin()->second, deaths.begin()->first);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+  ASSERT_EQ(1u, process_data_phase.tasks.size());
+  EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].death_thread_name);
+}
+
+TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  scoped_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+  EXPECT_EQ(data->run_duration_sum(), 0);
+  EXPECT_EQ(data->run_duration_max(), 0);
+  EXPECT_EQ(data->run_duration_sample(), 0);
+  EXPECT_EQ(data->queue_duration_sum(), 0);
+  EXPECT_EQ(data->queue_duration_max(), 0);
+  EXPECT_EQ(data->queue_duration_sample(), 0);
+  EXPECT_EQ(data->count(), 0);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+
+  int32 run_ms = 42;
+  int32 queue_ms = 8;
+
+  const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms);
+  EXPECT_EQ(data->run_duration_max(), run_ms);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 1);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+  EXPECT_EQ(data->run_duration_max(), run_ms);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 2);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+}
+
+TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  scoped_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+
+  int32 run_ms = 42;
+  int32 queue_ms = 8;
+
+  const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+
+  data->OnProfilingPhaseCompleted(123);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+  EXPECT_EQ(data->run_duration_max(), 0);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), 0);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 2);
+  ASSERT_NE(nullptr, data->last_phase_snapshot());
+  EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+  EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+  EXPECT_EQ(2 * run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sum);
+  EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+  EXPECT_EQ(run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sum);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_max);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sample);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+
+  int32 run_ms1 = 21;
+  int32 queue_ms1 = 4;
+
+  data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
+  EXPECT_EQ(data->run_duration_max(), run_ms1);
+  EXPECT_EQ(data->run_duration_sample(), run_ms1);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms + queue_ms1);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms1);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms1);
+  EXPECT_EQ(data->count(), 3);
+  ASSERT_NE(nullptr, data->last_phase_snapshot());
+  EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+  EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+  EXPECT_EQ(2 * run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sum);
+  EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+  EXPECT_EQ(run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sum);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_max);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sample);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+}
+
+TEST_F(TrackedObjectsTest, Delta) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  DeathDataSnapshot snapshot;
+  snapshot.count = 10;
+  snapshot.run_duration_sum = 100;
+  snapshot.run_duration_max = 50;
+  snapshot.run_duration_sample = 25;
+  snapshot.queue_duration_sum = 200;
+  snapshot.queue_duration_max = 101;
+  snapshot.queue_duration_sample = 26;
+
+  DeathDataSnapshot older_snapshot;
+  older_snapshot.count = 2;
+  older_snapshot.run_duration_sum = 95;
+  older_snapshot.run_duration_max = 48;
+  older_snapshot.run_duration_sample = 22;
+  older_snapshot.queue_duration_sum = 190;
+  older_snapshot.queue_duration_max = 99;
+  older_snapshot.queue_duration_sample = 21;
+
+  const DeathDataSnapshot& delta = snapshot.Delta(older_snapshot);
+  EXPECT_EQ(8, delta.count);
+  EXPECT_EQ(5, delta.run_duration_sum);
+  EXPECT_EQ(50, delta.run_duration_max);
+  EXPECT_EQ(25, delta.run_duration_sample);
+  EXPECT_EQ(10, delta.queue_duration_sum);
+  EXPECT_EQ(101, delta.queue_duration_max);
+  EXPECT_EQ(26, delta.queue_duration_sample);
+}
+
+TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotWorkerThread) {
+  // Start in the deactivated state.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const char kFunction[] = "DeactivatedBirthOnlyToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, std::string());
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotMainThread) {
+  // Start in the deactivated state.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const char kFunction[] = "DeactivatedBirthOnlyToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotWorkerThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "BirthOnlyToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, std::string());
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
+                          kStillAlive, 1, 0, 0);
+}
+
+TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotMainThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "BirthOnlyToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName, kStillAlive,
+                          1, 0, 0);
+}
+
+TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "LifeCycleToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 2, 4);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhases) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TwoPhases";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted1 = TrackedTime::FromMilliseconds(9);
+  const base::TimeTicks kDelayedStartTime1 = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task1(location, kDelayedStartTime1);
+  pending_task1.time_posted = kTimePosted1;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun1 = 11;
+  const unsigned int kEndOfRun1 = 21;
+  SetTestTime(kStartOfRun1);
+  TaskStopwatch stopwatch1;
+  stopwatch1.Start();
+  SetTestTime(kEndOfRun1);
+  stopwatch1.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task1, stopwatch1);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, ThreePhases) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "ThreePhases";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  // Phase 0
+  {
+    TallyABirth(location, kMainThreadName);
+
+    // TrackingInfo will call TallyABirth() during construction.
+    SetTestTime(10);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(17);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(23);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  // Phase 1
+  {
+    TallyABirth(location, kMainThreadName);
+
+    SetTestTime(30);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(35);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(39);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(1);
+
+  // Phase 2
+  {
+    TallyABirth(location, kMainThreadName);
+
+    // TrackingInfo will call TallyABirth() during construction.
+    SetTestTime(40);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(43);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(45);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  // Snapshot and check results.
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(2, &process_data);
+
+  ASSERT_EQ(3u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  auto it2 = process_data.phased_snapshots.find(2);
+  ASSERT_TRUE(it2 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase2 = it2->second;
+
+  ASSERT_EQ(1u, process_data_phase2.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase2.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase2.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase2.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase2.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesSecondEmpty) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TwoPhasesSecondEmpty";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::InitializeThreadContext(kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(0u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesFirstEmpty) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  const char kFunction[] = "TwoPhasesSecondEmpty";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::InitializeThreadContext(kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+// We will deactivate tracking after the birth, and before the death, and
+// demonstrate that the lifecycle is completely tallied. This ensures that
+// our tallied births are matched by tallied deaths (except for when the
+// task is still running, or is queued).
+TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "LifeCycleMidDeactivatedToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  // Turn off tracking now that we have births.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 2, 4);
+}
+
+// We will deactivate tracking before starting a life cycle, and neither
+// the birth nor the death will be recorded.
+TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
+  // Start in the deactivated state.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const char kFunction[] = "LifeCyclePreDeactivatedToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoLives) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TwoLives";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task2(location, kDelayedStartTime);
+  pending_task2.time_posted = kTimePosted;  // Overwrite implied Now().
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch2;
+  stopwatch2.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch2.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task2, stopwatch2);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 2, 2, 4);
+}
+
+TEST_F(TrackedObjectsTest, DifferentLives) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  // Use a well named thread.
+  ThreadData::InitializeThreadContext(kMainThreadName);
+  const char kFunction[] = "DifferentLives";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  const int kSecondFakeLineNumber = 999;
+  Location second_location(kFunction, kFile, kSecondFakeLineNumber, NULL);
+
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task2(second_location, kDelayedStartTime);
+  pending_task2.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(2u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].death_thread_name);
+  EXPECT_EQ(kFile, process_data_phase.tasks[1].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[1].birth.location.function_name);
+  EXPECT_EQ(kSecondFakeLineNumber,
+            process_data_phase.tasks[1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[1].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[1].death_data.count);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sample);
+  EXPECT_EQ(kStillAlive, process_data_phase.tasks[1].death_thread_name);
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TaskWithNestedExclusion) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TaskWithNestedExclusion";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  SetTestTime(5);
+  TaskStopwatch task_stopwatch;
+  task_stopwatch.Start();
+  {
+    SetTestTime(8);
+    TaskStopwatch exclusion_stopwatch;
+    exclusion_stopwatch.Start();
+    SetTestTime(12);
+    exclusion_stopwatch.Stop();
+  }
+  SetTestTime(15);
+  task_stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 6, 4);
+}
+
+TEST_F(TrackedObjectsTest, TaskWith2NestedExclusions) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TaskWith2NestedExclusions";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  SetTestTime(5);
+  TaskStopwatch task_stopwatch;
+  task_stopwatch.Start();
+  {
+    SetTestTime(8);
+    TaskStopwatch exclusion_stopwatch;
+    exclusion_stopwatch.Start();
+    SetTestTime(12);
+    exclusion_stopwatch.Stop();
+
+    SetTestTime(15);
+    TaskStopwatch exclusion_stopwatch2;
+    exclusion_stopwatch2.Start();
+    SetTestTime(18);
+    exclusion_stopwatch2.Stop();
+  }
+  SetTestTime(25);
+  task_stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 13, 4);
+}
+
+TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TaskWithNestedExclusionWithNestedTask";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  const int kSecondFakeLineNumber = 999;
+
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  SetTestTime(5);
+  TaskStopwatch task_stopwatch;
+  task_stopwatch.Start();
+  {
+    SetTestTime(8);
+    TaskStopwatch exclusion_stopwatch;
+    exclusion_stopwatch.Start();
+    {
+      Location second_location(kFunction, kFile, kSecondFakeLineNumber, NULL);
+      base::TrackingInfo nested_task(second_location, kDelayedStartTime);
+       // Overwrite implied Now().
+      nested_task.time_posted = TrackedTime::FromMilliseconds(8);
+      SetTestTime(9);
+      TaskStopwatch nested_task_stopwatch;
+      nested_task_stopwatch.Start();
+      SetTestTime(11);
+      nested_task_stopwatch.Stop();
+      ThreadData::TallyRunOnNamedThreadIfTracking(
+          nested_task, nested_task_stopwatch);
+    }
+    SetTestTime(12);
+    exclusion_stopwatch.Stop();
+  }
+  SetTestTime(15);
+  task_stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  // The order in which the two task follow is platform-dependent.
+  int t0 =
+      (process_data_phase.tasks[0].birth.location.line_number == kLineNumber)
+          ? 0
+          : 1;
+  int t1 = 1 - t0;
+
+  ASSERT_EQ(2u, process_data_phase.tasks.size());
+  EXPECT_EQ(kFile, process_data_phase.tasks[t0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[t0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[t0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[t0].death_data.count);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sum);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_max);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].death_thread_name);
+  EXPECT_EQ(kFile, process_data_phase.tasks[t1].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[t1].birth.location.function_name);
+  EXPECT_EQ(kSecondFakeLineNumber,
+            process_data_phase.tasks[t1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.count);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sample);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sum);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_max);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].death_thread_name);
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+}  // namespace tracked_objects
diff --git a/base/tracking_info.cc b/base/tracking_info.cc
new file mode 100644
index 0000000..c02b2f4
--- /dev/null
+++ b/base/tracking_info.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/tracking_info.h"
+
+#include <stddef.h>
+#include "base/tracked_objects.h"
+
+namespace base {
+
+TrackingInfo::TrackingInfo()
+    : birth_tally(NULL) {
+}
+
+TrackingInfo::TrackingInfo(
+    const tracked_objects::Location& posted_from,
+    base::TimeTicks delayed_run_time)
+    : birth_tally(
+          tracked_objects::ThreadData::TallyABirthIfActive(posted_from)),
+      time_posted(tracked_objects::ThreadData::Now()),
+      delayed_run_time(delayed_run_time) {
+}
+
+TrackingInfo::~TrackingInfo() {}
+
+}  // namespace base
+
diff --git a/base/tracking_info.h b/base/tracking_info.h
new file mode 100644
index 0000000..6c3bcd1
--- /dev/null
+++ b/base/tracking_info.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a simple struct with tracking information that is stored
+// with a PendingTask (when message_loop is handling the task).
+// Only the information that is shared with the profiler in tracked_objects
+// are included in this structure.
+
+
+#ifndef BASE_TRACKING_INFO_H_
+#define BASE_TRACKING_INFO_H_
+
+#include "base/base_export.h"
+#include "base/profiler/tracked_time.h"
+#include "base/time/time.h"
+
+namespace tracked_objects {
+class Location;
+class Births;
+}
+
+namespace base {
+
+// This structure is copied around by value.
+struct BASE_EXPORT TrackingInfo {
+  TrackingInfo();
+  TrackingInfo(const tracked_objects::Location& posted_from,
+               base::TimeTicks delayed_run_time);
+  ~TrackingInfo();
+
+  // To avoid conflating our stats with the delay duration in a PostDelayedTask,
+  // we identify such tasks, and replace their post_time with the time they
+  // were scheduled (requested?) to emerge from the delayed task queue. This
+  // means that queuing delay for such tasks will show how long they went
+  // unserviced, after they *could* be serviced.  This is the same stat as we
+  // have for non-delayed tasks, and we consistently call it queuing delay.
+  tracked_objects::TrackedTime EffectiveTimePosted() const {
+    return delayed_run_time.is_null()
+               ? time_posted
+               : tracked_objects::TrackedTime(delayed_run_time);
+  }
+
+  // Record of location and thread that the task came from.
+  tracked_objects::Births* birth_tally;
+
+  // Time when the related task was posted. Note that this value may be empty
+  // if task profiling is disabled, and should only be used in conjunction with
+  // profiling-related reporting.
+  tracked_objects::TrackedTime time_posted;
+
+  // The time when the task should be run.
+  base::TimeTicks delayed_run_time;
+};
+
+}  // namespace base
+
+#endif  // BASE_TRACKING_INFO_H_
diff --git a/base/tuple.h b/base/tuple.h
new file mode 100644
index 0000000..88c3075
--- /dev/null
+++ b/base/tuple.h
@@ -0,0 +1,332 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A Tuple is a generic templatized container, similar in concept to std::pair
+// and std::tuple.  The convenient MakeTuple() function takes any number of
+// arguments and will construct and return the appropriate Tuple object.  The
+// functions DispatchToMethod and DispatchToFunction take a function pointer or
+// instance and method pointer, and unpack a tuple into arguments to the call.
+//
+// Tuple elements are copied by value, and stored in the tuple.  See the unit
+// tests for more details of how/when the values are copied.
+//
+// Example usage:
+//   // These two methods of creating a Tuple are identical.
+//   Tuple<int, const char*> tuple_a(1, "wee");
+//   Tuple<int, const char*> tuple_b = MakeTuple(1, "wee");
+//
+//   void SomeFunc(int a, const char* b) { }
+//   DispatchToFunction(&SomeFunc, tuple_a);  // SomeFunc(1, "wee")
+//   DispatchToFunction(
+//       &SomeFunc, MakeTuple(10, "foo"));    // SomeFunc(10, "foo")
+//
+//   struct { void SomeMeth(int a, int b, int c) { } } foo;
+//   DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
+//   // foo->SomeMeth(1, 2, 3);
+
+#ifndef BASE_TUPLE_H__
+#define BASE_TUPLE_H__
+
+#include "base/bind_helpers.h"
+
+// Index sequences
+//
+// Minimal clone of the similarly-named C++14 functionality.
+
+template <size_t...>
+struct IndexSequence {};
+
+template <size_t... Ns>
+struct MakeIndexSequenceImpl;
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+
+// Work around VC++ 2013 /analyze internal compiler error:
+// https://connect.microsoft.com/VisualStudio/feedback/details/1053626
+
+template <> struct MakeIndexSequenceImpl<0> {
+  using Type = IndexSequence<>;
+};
+template <> struct MakeIndexSequenceImpl<1> {
+  using Type = IndexSequence<0>;
+};
+template <> struct MakeIndexSequenceImpl<2> {
+  using Type = IndexSequence<0,1>;
+};
+template <> struct MakeIndexSequenceImpl<3> {
+  using Type = IndexSequence<0,1,2>;
+};
+template <> struct MakeIndexSequenceImpl<4> {
+  using Type = IndexSequence<0,1,2,3>;
+};
+template <> struct MakeIndexSequenceImpl<5> {
+  using Type = IndexSequence<0,1,2,3,4>;
+};
+template <> struct MakeIndexSequenceImpl<6> {
+  using Type = IndexSequence<0,1,2,3,4,5>;
+};
+template <> struct MakeIndexSequenceImpl<7> {
+  using Type = IndexSequence<0,1,2,3,4,5,6>;
+};
+template <> struct MakeIndexSequenceImpl<8> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7>;
+};
+template <> struct MakeIndexSequenceImpl<9> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8>;
+};
+template <> struct MakeIndexSequenceImpl<10> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9>;
+};
+template <> struct MakeIndexSequenceImpl<11> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10>;
+};
+template <> struct MakeIndexSequenceImpl<12> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11>;
+};
+template <> struct MakeIndexSequenceImpl<13> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11,12>;
+};
+
+#else  // defined(WIN) && defined(_PREFAST_)
+
+template <size_t... Ns>
+struct MakeIndexSequenceImpl<0, Ns...> {
+  using Type = IndexSequence<Ns...>;
+};
+
+template <size_t N, size_t... Ns>
+struct MakeIndexSequenceImpl<N, Ns...>
+    : MakeIndexSequenceImpl<N - 1, N - 1, Ns...> {};
+
+#endif  // defined(WIN) && defined(_PREFAST_)
+
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
+
+// Traits ----------------------------------------------------------------------
+//
+// A simple traits class for tuple arguments.
+//
+// ValueType: the bare, nonref version of a type (same as the type for nonrefs).
+// RefType: the ref version of a type (same as the type for refs).
+// ParamType: what type to pass to functions (refs should not be constified).
+
+template <class P>
+struct TupleTraits {
+  typedef P ValueType;
+  typedef P& RefType;
+  typedef const P& ParamType;
+};
+
+template <class P>
+struct TupleTraits<P&> {
+  typedef P ValueType;
+  typedef P& RefType;
+  typedef P& ParamType;
+};
+
+// Tuple -----------------------------------------------------------------------
+//
+// This set of classes is useful for bundling 0 or more heterogeneous data types
+// into a single variable.  The advantage of this is that it greatly simplifies
+// function objects that need to take an arbitrary number of parameters; see
+// RunnableMethod and IPC::MessageWithTuple.
+//
+// Tuple<> is supplied to act as a 'void' type.  It can be used, for example,
+// when dispatching to a function that accepts no arguments (see the
+// Dispatchers below).
+// Tuple<A> is rarely useful.  One such use is when A is non-const ref that you
+// want filled by the dispatchee, and the tuple is merely a container for that
+// output (a "tier").  See MakeRefTuple and its usages.
+
+template <typename IxSeq, typename... Ts>
+struct TupleBaseImpl;
+template <typename... Ts>
+using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>;
+template <size_t N, typename T>
+struct TupleLeaf;
+
+template <typename... Ts>
+struct Tuple : TupleBase<Ts...> {
+  Tuple() : TupleBase<Ts...>() {}
+  explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
+      : TupleBase<Ts...>(args...) {}
+};
+
+// Avoids ambiguity between Tuple's two constructors.
+template <>
+struct Tuple<> {};
+
+template <size_t... Ns, typename... Ts>
+struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
+  TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {}
+  explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args)
+      : TupleLeaf<Ns, Ts>(args)... {}
+};
+
+template <size_t N, typename T>
+struct TupleLeaf {
+  TupleLeaf() {}
+  explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {}
+
+  T& get() { return x; }
+  const T& get() const { return x; }
+
+  T x;
+};
+
+// Tuple getters --------------------------------------------------------------
+//
+// Allows accessing an arbitrary tuple element by index.
+//
+// Example usage:
+//   Tuple<int, double> t2;
+//   get<0>(t2) = 42;
+//   get<1>(t2) = 3.14;
+
+template <size_t I, typename T>
+T& get(TupleLeaf<I, T>& leaf) {
+  return leaf.get();
+}
+
+template <size_t I, typename T>
+const T& get(const TupleLeaf<I, T>& leaf) {
+  return leaf.get();
+}
+
+// Tuple types ----------------------------------------------------------------
+//
+// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
+// definitions of class types the tuple takes as parameters.
+
+template <typename T>
+struct TupleTypes;
+
+template <typename... Ts>
+struct TupleTypes<Tuple<Ts...>> {
+  using ValueTuple = Tuple<typename TupleTraits<Ts>::ValueType...>;
+  using RefTuple = Tuple<typename TupleTraits<Ts>::RefType...>;
+  using ParamTuple = Tuple<typename TupleTraits<Ts>::ParamType...>;
+};
+
+// Tuple creators -------------------------------------------------------------
+//
+// Helper functions for constructing tuples while inferring the template
+// argument types.
+
+template <typename... Ts>
+inline Tuple<Ts...> MakeTuple(const Ts&... arg) {
+  return Tuple<Ts...>(arg...);
+}
+
+// The following set of helpers make what Boost refers to as "Tiers" - a tuple
+// of references.
+
+template <typename... Ts>
+inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) {
+  return Tuple<Ts&...>(arg...);
+}
+
+// Dispatchers ----------------------------------------------------------------
+//
+// Helper functions that call the given method on an object, with the unpacked
+// tuple arguments.  Notice that they all have the same number of arguments,
+// so you need only write:
+//   DispatchToMethod(object, &Object::method, args);
+// This is very useful for templated dispatchers, since they don't need to know
+// what type |args| is.
+
+// Non-Static Dispatchers with no out params.
+
+template <typename ObjT, typename Method, typename A>
+inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
+  (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg));
+}
+
+template <typename ObjT, typename Method, typename... Ts, size_t... Ns>
+inline void DispatchToMethodImpl(ObjT* obj,
+                                 Method method,
+                                 const Tuple<Ts...>& arg,
+                                 IndexSequence<Ns...>) {
+  (obj->*method)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
+}
+
+template <typename ObjT, typename Method, typename... Ts>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple<Ts...>& arg) {
+  DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>());
+}
+
+// Static Dispatchers with no out params.
+
+template <typename Function, typename A>
+inline void DispatchToMethod(Function function, const A& arg) {
+  (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg));
+}
+
+template <typename Function, typename... Ts, size_t... Ns>
+inline void DispatchToFunctionImpl(Function function,
+                                   const Tuple<Ts...>& arg,
+                                   IndexSequence<Ns...>) {
+  (*function)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
+}
+
+template <typename Function, typename... Ts>
+inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) {
+  DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>());
+}
+
+// Dispatchers with out parameters.
+
+template <typename ObjT,
+          typename Method,
+          typename In,
+          typename... OutTs,
+          size_t... OutNs>
+inline void DispatchToMethodImpl(ObjT* obj,
+                                 Method method,
+                                 const In& in,
+                                 Tuple<OutTs...>* out,
+                                 IndexSequence<OutNs...>) {
+  (obj->*method)(base::internal::UnwrapTraits<In>::Unwrap(in),
+                 &get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename In, typename... OutTs>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const In& in,
+                             Tuple<OutTs...>* out) {
+  DispatchToMethodImpl(obj, method, in, out,
+                       MakeIndexSequence<sizeof...(OutTs)>());
+}
+
+template <typename ObjT,
+          typename Method,
+          typename... InTs,
+          typename... OutTs,
+          size_t... InNs,
+          size_t... OutNs>
+inline void DispatchToMethodImpl(ObjT* obj,
+                                 Method method,
+                                 const Tuple<InTs...>& in,
+                                 Tuple<OutTs...>* out,
+                                 IndexSequence<InNs...>,
+                                 IndexSequence<OutNs...>) {
+  (obj->*method)(base::internal::UnwrapTraits<InTs>::Unwrap(get<InNs>(in))...,
+                 &get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename... InTs, typename... OutTs>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple<InTs...>& in,
+                             Tuple<OutTs...>* out) {
+  DispatchToMethodImpl(obj, method, in, out,
+                       MakeIndexSequence<sizeof...(InTs)>(),
+                       MakeIndexSequence<sizeof...(OutTs)>());
+}
+
+#endif  // BASE_TUPLE_H__
diff --git a/base/tuple_unittest.cc b/base/tuple_unittest.cc
new file mode 100644
index 0000000..5b43aff
--- /dev/null
+++ b/base/tuple_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/tuple.h"
+
+#include "base/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void DoAdd(int a, int b, int c, int* res) {
+  *res = a + b + c;
+}
+
+struct Addy {
+  Addy() { }
+  void DoAdd(int a, int b, int c, int d, int* res) {
+    *res = a + b + c + d;
+  }
+};
+
+struct Addz {
+  Addz() { }
+  void DoAdd(int a, int b, int c, int d, int e, int* res) {
+    *res = a + b + c + d + e;
+  }
+};
+
+}  // namespace
+
+TEST(TupleTest, Basic) {
+  Tuple<> t0 = MakeTuple();
+  ALLOW_UNUSED_LOCAL(t0);
+  Tuple<int> t1(1);
+  Tuple<int, const char*> t2 = MakeTuple(1, static_cast<const char*>("wee"));
+  Tuple<int, int, int> t3(1, 2, 3);
+  Tuple<int, int, int, int*> t4(1, 2, 3, &get<0>(t1));
+  Tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &get<0>(t4));
+  Tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &get<0>(t4));
+
+  EXPECT_EQ(1, get<0>(t1));
+  EXPECT_EQ(1, get<0>(t2));
+  EXPECT_EQ(1, get<0>(t3));
+  EXPECT_EQ(2, get<1>(t3));
+  EXPECT_EQ(3, get<2>(t3));
+  EXPECT_EQ(1, get<0>(t4));
+  EXPECT_EQ(2, get<1>(t4));
+  EXPECT_EQ(3, get<2>(t4));
+  EXPECT_EQ(1, get<0>(t5));
+  EXPECT_EQ(2, get<1>(t5));
+  EXPECT_EQ(3, get<2>(t5));
+  EXPECT_EQ(4, get<3>(t5));
+  EXPECT_EQ(1, get<0>(t6));
+  EXPECT_EQ(2, get<1>(t6));
+  EXPECT_EQ(3, get<2>(t6));
+  EXPECT_EQ(4, get<3>(t6));
+  EXPECT_EQ(5, get<4>(t6));
+
+  EXPECT_EQ(1, get<0>(t1));
+  DispatchToFunction(&DoAdd, t4);
+  EXPECT_EQ(6, get<0>(t1));
+
+  int res = 0;
+  DispatchToFunction(&DoAdd, MakeTuple(9, 8, 7, &res));
+  EXPECT_EQ(24, res);
+
+  Addy addy;
+  EXPECT_EQ(1, get<0>(t4));
+  DispatchToMethod(&addy, &Addy::DoAdd, t5);
+  EXPECT_EQ(10, get<0>(t4));
+
+  Addz addz;
+  EXPECT_EQ(10, get<0>(t4));
+  DispatchToMethod(&addz, &Addz::DoAdd, t6);
+  EXPECT_EQ(15, get<0>(t4));
+}
+
+namespace {
+
+struct CopyLogger {
+  CopyLogger() { ++TimesConstructed; }
+  CopyLogger(const CopyLogger& tocopy) { ++TimesConstructed; ++TimesCopied; }
+  ~CopyLogger() { }
+
+  static int TimesCopied;
+  static int TimesConstructed;
+};
+
+void SomeLoggerMethRef(const CopyLogger& logy, const CopyLogger* ptr, bool* b) {
+  *b = &logy == ptr;
+}
+
+void SomeLoggerMethCopy(CopyLogger logy, const CopyLogger* ptr, bool* b) {
+  *b = &logy == ptr;
+}
+
+int CopyLogger::TimesCopied = 0;
+int CopyLogger::TimesConstructed = 0;
+
+}  // namespace
+
+TEST(TupleTest, Copying) {
+  CopyLogger logger;
+  EXPECT_EQ(0, CopyLogger::TimesCopied);
+  EXPECT_EQ(1, CopyLogger::TimesConstructed);
+
+  bool res = false;
+
+  // Creating the tuple should copy the class to store internally in the tuple.
+  Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
+  get<1>(tuple) = &get<0>(tuple);
+  EXPECT_EQ(2, CopyLogger::TimesConstructed);
+  EXPECT_EQ(1, CopyLogger::TimesCopied);
+
+  // Our internal Logger and the one passed to the function should be the same.
+  res = false;
+  DispatchToFunction(&SomeLoggerMethRef, tuple);
+  EXPECT_TRUE(res);
+  EXPECT_EQ(2, CopyLogger::TimesConstructed);
+  EXPECT_EQ(1, CopyLogger::TimesCopied);
+
+  // Now they should be different, since the function call will make a copy.
+  res = false;
+  DispatchToFunction(&SomeLoggerMethCopy, tuple);
+  EXPECT_FALSE(res);
+  EXPECT_EQ(3, CopyLogger::TimesConstructed);
+  EXPECT_EQ(2, CopyLogger::TimesCopied);
+}
diff --git a/base/value_conversions.cc b/base/value_conversions.cc
new file mode 100644
index 0000000..45cd619
--- /dev/null
+++ b/base/value_conversions.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/value_conversions.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/values.h"
+
+namespace base {
+
+// |Value| internally stores strings in UTF-8, so we have to convert from the
+// system native code to UTF-8 and back.
+StringValue* CreateFilePathValue(const FilePath& in_value) {
+  return new StringValue(in_value.AsUTF8Unsafe());
+}
+
+bool GetValueAsFilePath(const Value& value, FilePath* file_path) {
+  std::string str;
+  if (!value.GetAsString(&str))
+    return false;
+  if (file_path)
+    *file_path = FilePath::FromUTF8Unsafe(str);
+  return true;
+}
+
+// |Value| does not support 64-bit integers, and doubles do not have enough
+// precision, so we store the 64-bit time value as a string instead.
+StringValue* CreateTimeDeltaValue(const TimeDelta& time) {
+  std::string string_value = base::Int64ToString(time.ToInternalValue());
+  return new StringValue(string_value);
+}
+
+bool GetValueAsTimeDelta(const Value& value, TimeDelta* time) {
+  std::string str;
+  int64 int_value;
+  if (!value.GetAsString(&str) || !base::StringToInt64(str, &int_value))
+    return false;
+  if (time)
+    *time = TimeDelta::FromInternalValue(int_value);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/value_conversions.h b/base/value_conversions.h
new file mode 100644
index 0000000..452c587
--- /dev/null
+++ b/base/value_conversions.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_VALUE_CONVERSIONS_H_
+#define BASE_VALUE_CONVERSIONS_H_
+
+// This file contains methods to convert things to a |Value| and back.
+
+#include "base/base_export.h"
+
+
+namespace base {
+
+class FilePath;
+class TimeDelta;
+class StringValue;
+class Value;
+
+// The caller takes ownership of the returned value.
+BASE_EXPORT StringValue* CreateFilePathValue(const FilePath& in_value);
+BASE_EXPORT bool GetValueAsFilePath(const Value& value, FilePath* file_path);
+
+BASE_EXPORT StringValue* CreateTimeDeltaValue(const TimeDelta& time);
+BASE_EXPORT bool GetValueAsTimeDelta(const Value& value, TimeDelta* time);
+
+}  // namespace base
+
+#endif  // BASE_VALUE_CONVERSIONS_H_
diff --git a/base/values.cc b/base/values.cc
new file mode 100644
index 0000000..f448f51
--- /dev/null
+++ b/base/values.cc
@@ -0,0 +1,1173 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/values.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cmath>
+#include <ostream>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/move.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Make a deep copy of |node|, but don't include empty lists or dictionaries
+// in the copy. It's possible for this function to return NULL and it
+// expects |node| to always be non-NULL.
+Value* CopyWithoutEmptyChildren(const Value* node) {
+  DCHECK(node);
+  switch (node->GetType()) {
+    case Value::TYPE_LIST: {
+      const ListValue* list = static_cast<const ListValue*>(node);
+      ListValue* copy = new ListValue;
+      for (ListValue::const_iterator it = list->begin(); it != list->end();
+           ++it) {
+        Value* child_copy = CopyWithoutEmptyChildren(*it);
+        if (child_copy)
+          copy->Append(child_copy);
+      }
+      if (!copy->empty())
+        return copy;
+
+      delete copy;
+      return NULL;
+    }
+
+    case Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict = static_cast<const DictionaryValue*>(node);
+      DictionaryValue* copy = new DictionaryValue;
+      for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
+        Value* child_copy = CopyWithoutEmptyChildren(&it.value());
+        if (child_copy)
+          copy->SetWithoutPathExpansion(it.key(), child_copy);
+      }
+      if (!copy->empty())
+        return copy;
+
+      delete copy;
+      return NULL;
+    }
+
+    default:
+      // For everything else, just make a copy.
+      return node->DeepCopy();
+  }
+}
+
+// A small functor for comparing Values for std::find_if and similar.
+class ValueEquals {
+ public:
+  // Pass the value against which all consecutive calls of the () operator will
+  // compare their argument to. This Value object must not be destroyed while
+  // the ValueEquals is  in use.
+  explicit ValueEquals(const Value* first) : first_(first) { }
+
+  bool operator ()(const Value* second) const {
+    return first_->Equals(second);
+  }
+
+ private:
+  const Value* first_;
+};
+
+}  // namespace
+
+Value::~Value() {
+}
+
+// static
+Value* Value::CreateNullValue() {
+  return new Value(TYPE_NULL);
+}
+
+bool Value::GetAsBinary(const BinaryValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsBoolean(bool* out_value) const {
+  return false;
+}
+
+bool Value::GetAsInteger(int* out_value) const {
+  return false;
+}
+
+bool Value::GetAsDouble(double* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(std::string* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(string16* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(const StringValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsList(ListValue** out_value) {
+  return false;
+}
+
+bool Value::GetAsList(const ListValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsDictionary(DictionaryValue** out_value) {
+  return false;
+}
+
+bool Value::GetAsDictionary(const DictionaryValue** out_value) const {
+  return false;
+}
+
+Value* Value::DeepCopy() const {
+  // This method should only be getting called for null Values--all subclasses
+  // need to provide their own implementation;.
+  DCHECK(IsType(TYPE_NULL));
+  return CreateNullValue();
+}
+
+scoped_ptr<Value> Value::CreateDeepCopy() const {
+  return make_scoped_ptr(DeepCopy());
+}
+
+bool Value::Equals(const Value* other) const {
+  // This method should only be getting called for null Values--all subclasses
+  // need to provide their own implementation;.
+  DCHECK(IsType(TYPE_NULL));
+  return other->IsType(TYPE_NULL);
+}
+
+// static
+bool Value::Equals(const Value* a, const Value* b) {
+  if ((a == NULL) && (b == NULL)) return true;
+  if ((a == NULL) ^  (b == NULL)) return false;
+  return a->Equals(b);
+}
+
+Value::Value(Type type) : type_(type) {}
+
+Value::Value(const Value& that) : type_(that.type_) {}
+
+Value& Value::operator=(const Value& that) {
+  type_ = that.type_;
+  return *this;
+}
+
+///////////////////// FundamentalValue ////////////////////
+
+FundamentalValue::FundamentalValue(bool in_value)
+    : Value(TYPE_BOOLEAN), boolean_value_(in_value) {
+}
+
+FundamentalValue::FundamentalValue(int in_value)
+    : Value(TYPE_INTEGER), integer_value_(in_value) {
+}
+
+FundamentalValue::FundamentalValue(double in_value)
+    : Value(TYPE_DOUBLE), double_value_(in_value) {
+  if (!std::isfinite(double_value_)) {
+    NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
+                 << "values cannot be represented in JSON";
+    double_value_ = 0.0;
+  }
+}
+
+FundamentalValue::~FundamentalValue() {
+}
+
+bool FundamentalValue::GetAsBoolean(bool* out_value) const {
+  if (out_value && IsType(TYPE_BOOLEAN))
+    *out_value = boolean_value_;
+  return (IsType(TYPE_BOOLEAN));
+}
+
+bool FundamentalValue::GetAsInteger(int* out_value) const {
+  if (out_value && IsType(TYPE_INTEGER))
+    *out_value = integer_value_;
+  return (IsType(TYPE_INTEGER));
+}
+
+bool FundamentalValue::GetAsDouble(double* out_value) const {
+  if (out_value && IsType(TYPE_DOUBLE))
+    *out_value = double_value_;
+  else if (out_value && IsType(TYPE_INTEGER))
+    *out_value = integer_value_;
+  return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER));
+}
+
+FundamentalValue* FundamentalValue::DeepCopy() const {
+  switch (GetType()) {
+    case TYPE_BOOLEAN:
+      return new FundamentalValue(boolean_value_);
+
+    case TYPE_INTEGER:
+      return new FundamentalValue(integer_value_);
+
+    case TYPE_DOUBLE:
+      return new FundamentalValue(double_value_);
+
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+}
+
+bool FundamentalValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  switch (GetType()) {
+    case TYPE_BOOLEAN: {
+      bool lhs, rhs;
+      return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs;
+    }
+    case TYPE_INTEGER: {
+      int lhs, rhs;
+      return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
+    }
+    case TYPE_DOUBLE: {
+      double lhs, rhs;
+      return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs;
+    }
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+///////////////////// StringValue ////////////////////
+
+StringValue::StringValue(const std::string& in_value)
+    : Value(TYPE_STRING),
+      value_(in_value) {
+  DCHECK(IsStringUTF8(in_value));
+}
+
+StringValue::StringValue(const string16& in_value)
+    : Value(TYPE_STRING),
+      value_(UTF16ToUTF8(in_value)) {
+}
+
+StringValue::~StringValue() {
+}
+
+std::string* StringValue::GetString() {
+  return &value_;
+}
+
+const std::string& StringValue::GetString() const {
+  return value_;
+}
+
+bool StringValue::GetAsString(std::string* out_value) const {
+  if (out_value)
+    *out_value = value_;
+  return true;
+}
+
+bool StringValue::GetAsString(string16* out_value) const {
+  if (out_value)
+    *out_value = UTF8ToUTF16(value_);
+  return true;
+}
+
+bool StringValue::GetAsString(const StringValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+StringValue* StringValue::DeepCopy() const {
+  return new StringValue(value_);
+}
+
+bool StringValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+  std::string lhs, rhs;
+  return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs;
+}
+
+///////////////////// BinaryValue ////////////////////
+
+BinaryValue::BinaryValue()
+    : Value(TYPE_BINARY),
+      size_(0) {
+}
+
+BinaryValue::BinaryValue(scoped_ptr<char[]> buffer, size_t size)
+    : Value(TYPE_BINARY),
+      buffer_(buffer.Pass()),
+      size_(size) {
+}
+
+BinaryValue::~BinaryValue() {
+}
+
+// static
+BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
+                                                 size_t size) {
+  char* buffer_copy = new char[size];
+  memcpy(buffer_copy, buffer, size);
+  scoped_ptr<char[]> scoped_buffer_copy(buffer_copy);
+  return new BinaryValue(scoped_buffer_copy.Pass(), size);
+}
+
+bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+BinaryValue* BinaryValue::DeepCopy() const {
+  return CreateWithCopiedBuffer(buffer_.get(), size_);
+}
+
+bool BinaryValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+  const BinaryValue* other_binary = static_cast<const BinaryValue*>(other);
+  if (other_binary->size_ != size_)
+    return false;
+  return !memcmp(GetBuffer(), other_binary->GetBuffer(), size_);
+}
+
+///////////////////// DictionaryValue ////////////////////
+
+DictionaryValue::DictionaryValue()
+    : Value(TYPE_DICTIONARY) {
+}
+
+DictionaryValue::~DictionaryValue() {
+  Clear();
+}
+
+bool DictionaryValue::GetAsDictionary(DictionaryValue** out_value) {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool DictionaryValue::HasKey(const std::string& key) const {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::const_iterator current_entry = dictionary_.find(key);
+  DCHECK((current_entry == dictionary_.end()) || current_entry->second);
+  return current_entry != dictionary_.end();
+}
+
+void DictionaryValue::Clear() {
+  ValueMap::iterator dict_iterator = dictionary_.begin();
+  while (dict_iterator != dictionary_.end()) {
+    delete dict_iterator->second;
+    ++dict_iterator;
+  }
+
+  dictionary_.clear();
+}
+
+void DictionaryValue::Set(const std::string& path, scoped_ptr<Value> in_value) {
+  DCHECK(IsStringUTF8(path));
+  DCHECK(in_value);
+
+  std::string current_path(path);
+  DictionaryValue* current_dictionary = this;
+  for (size_t delimiter_position = current_path.find('.');
+       delimiter_position != std::string::npos;
+       delimiter_position = current_path.find('.')) {
+    // Assume that we're indexing into a dictionary.
+    std::string key(current_path, 0, delimiter_position);
+    DictionaryValue* child_dictionary = NULL;
+    if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
+      child_dictionary = new DictionaryValue;
+      current_dictionary->SetWithoutPathExpansion(key, child_dictionary);
+    }
+
+    current_dictionary = child_dictionary;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass());
+}
+
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+  Set(path, make_scoped_ptr(in_value));
+}
+
+void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
+  Set(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetInteger(const std::string& path, int in_value) {
+  Set(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetDouble(const std::string& path, double in_value) {
+  Set(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+                                const std::string& in_value) {
+  Set(path, new StringValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+                                const string16& in_value) {
+  Set(path, new StringValue(in_value));
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+                                              scoped_ptr<Value> in_value) {
+  Value* bare_ptr = in_value.release();
+  // If there's an existing value here, we need to delete it, because
+  // we own all our children.
+  std::pair<ValueMap::iterator, bool> ins_res =
+      dictionary_.insert(std::make_pair(key, bare_ptr));
+  if (!ins_res.second) {
+    DCHECK_NE(ins_res.first->second, bare_ptr);  // This would be bogus
+    delete ins_res.first->second;
+    ins_res.first->second = bare_ptr;
+  }
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+                                              Value* in_value) {
+  SetWithoutPathExpansion(key, make_scoped_ptr(in_value));
+}
+
+void DictionaryValue::SetBooleanWithoutPathExpansion(
+    const std::string& path, bool in_value) {
+  SetWithoutPathExpansion(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetIntegerWithoutPathExpansion(
+    const std::string& path, int in_value) {
+  SetWithoutPathExpansion(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetDoubleWithoutPathExpansion(
+    const std::string& path, double in_value) {
+  SetWithoutPathExpansion(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetStringWithoutPathExpansion(
+    const std::string& path, const std::string& in_value) {
+  SetWithoutPathExpansion(path, new StringValue(in_value));
+}
+
+void DictionaryValue::SetStringWithoutPathExpansion(
+    const std::string& path, const string16& in_value) {
+  SetWithoutPathExpansion(path, new StringValue(in_value));
+}
+
+bool DictionaryValue::Get(const std::string& path,
+                          const Value** out_value) const {
+  DCHECK(IsStringUTF8(path));
+  std::string current_path(path);
+  const DictionaryValue* current_dictionary = this;
+  for (size_t delimiter_position = current_path.find('.');
+       delimiter_position != std::string::npos;
+       delimiter_position = current_path.find('.')) {
+    const DictionaryValue* child_dictionary = NULL;
+    if (!current_dictionary->GetDictionary(
+            current_path.substr(0, delimiter_position), &child_dictionary))
+      return false;
+
+    current_dictionary = child_dictionary;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+}
+
+bool DictionaryValue::Get(const std::string& path, Value** out_value)  {
+  return static_cast<const DictionaryValue&>(*this).Get(
+      path,
+      const_cast<const Value**>(out_value));
+}
+
+bool DictionaryValue::GetBoolean(const std::string& path,
+                                 bool* bool_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsBoolean(bool_value);
+}
+
+bool DictionaryValue::GetInteger(const std::string& path,
+                                 int* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDouble(const std::string& path,
+                                double* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+                                std::string* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+                                string16* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringASCII(const std::string& path,
+                                     std::string* out_value) const {
+  std::string out;
+  if (!GetString(path, &out))
+    return false;
+
+  if (!IsStringASCII(out)) {
+    NOTREACHED();
+    return false;
+  }
+
+  out_value->assign(out);
+  return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+                                const BinaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_BINARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const BinaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+                                BinaryValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetBinary(
+      path,
+      const_cast<const BinaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+                                    const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+                                    DictionaryValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetDictionary(
+      path,
+      const_cast<const DictionaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetList(const std::string& path,
+                              const ListValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetList(const std::string& path, ListValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetList(
+      path,
+      const_cast<const ListValue**>(out_value));
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+                                              const Value** out_value) const {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::const_iterator entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  const Value* entry = entry_iterator->second;
+  if (out_value)
+    *out_value = entry;
+  return true;
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+                                              Value** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion(
+      key,
+      const_cast<const Value**>(out_value));
+}
+
+bool DictionaryValue::GetBooleanWithoutPathExpansion(const std::string& key,
+                                                     bool* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsBoolean(out_value);
+}
+
+bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
+                                                     int* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key,
+                                                    double* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(
+    const std::string& key,
+    std::string* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(const std::string& key,
+                                                    string16* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+    const std::string& key,
+    const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = GetWithoutPathExpansion(key, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+    const std::string& key,
+    DictionaryValue** out_value) {
+  const DictionaryValue& const_this =
+      static_cast<const DictionaryValue&>(*this);
+  return const_this.GetDictionaryWithoutPathExpansion(
+          key,
+          const_cast<const DictionaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(
+    const std::string& key,
+    const ListValue** out_value) const {
+  const Value* value;
+  bool result = GetWithoutPathExpansion(key, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key,
+                                                  ListValue** out_value) {
+  return
+      static_cast<const DictionaryValue&>(*this).GetListWithoutPathExpansion(
+          key,
+          const_cast<const ListValue**>(out_value));
+}
+
+bool DictionaryValue::Remove(const std::string& path,
+                             scoped_ptr<Value>* out_value) {
+  DCHECK(IsStringUTF8(path));
+  std::string current_path(path);
+  DictionaryValue* current_dictionary = this;
+  size_t delimiter_position = current_path.rfind('.');
+  if (delimiter_position != std::string::npos) {
+    if (!GetDictionary(current_path.substr(0, delimiter_position),
+                       &current_dictionary))
+      return false;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  return current_dictionary->RemoveWithoutPathExpansion(current_path,
+                                                        out_value);
+}
+
+bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key,
+                                                 scoped_ptr<Value>* out_value) {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::iterator entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  Value* entry = entry_iterator->second;
+  if (out_value)
+    out_value->reset(entry);
+  else
+    delete entry;
+  dictionary_.erase(entry_iterator);
+  return true;
+}
+
+bool DictionaryValue::RemovePath(const std::string& path,
+                                 scoped_ptr<Value>* out_value) {
+  bool result = false;
+  size_t delimiter_position = path.find('.');
+
+  if (delimiter_position == std::string::npos)
+    return RemoveWithoutPathExpansion(path, out_value);
+
+  const std::string subdict_path = path.substr(0, delimiter_position);
+  DictionaryValue* subdict = NULL;
+  if (!GetDictionary(subdict_path, &subdict))
+    return false;
+  result = subdict->RemovePath(path.substr(delimiter_position + 1),
+                               out_value);
+  if (result && subdict->empty())
+    RemoveWithoutPathExpansion(subdict_path, NULL);
+
+  return result;
+}
+
+DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() const {
+  Value* copy = CopyWithoutEmptyChildren(this);
+  return copy ? static_cast<DictionaryValue*>(copy) : new DictionaryValue;
+}
+
+void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
+  for (DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd(); it.Advance()) {
+    const Value* merge_value = &it.value();
+    // Check whether we have to merge dictionaries.
+    if (merge_value->IsType(Value::TYPE_DICTIONARY)) {
+      DictionaryValue* sub_dict;
+      if (GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) {
+        sub_dict->MergeDictionary(
+            static_cast<const DictionaryValue*>(merge_value));
+        continue;
+      }
+    }
+    // All other cases: Make a copy and hook it up.
+    SetWithoutPathExpansion(it.key(), merge_value->DeepCopy());
+  }
+}
+
+void DictionaryValue::Swap(DictionaryValue* other) {
+  dictionary_.swap(other->dictionary_);
+}
+
+DictionaryValue::Iterator::Iterator(const DictionaryValue& target)
+    : target_(target),
+      it_(target.dictionary_.begin()) {}
+
+DictionaryValue::Iterator::~Iterator() {}
+
+DictionaryValue* DictionaryValue::DeepCopy() const {
+  DictionaryValue* result = new DictionaryValue;
+
+  for (ValueMap::const_iterator current_entry(dictionary_.begin());
+       current_entry != dictionary_.end(); ++current_entry) {
+    result->SetWithoutPathExpansion(current_entry->first,
+                                    current_entry->second->DeepCopy());
+  }
+
+  return result;
+}
+
+scoped_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
+  return make_scoped_ptr(DeepCopy());
+}
+
+bool DictionaryValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const DictionaryValue* other_dict =
+      static_cast<const DictionaryValue*>(other);
+  Iterator lhs_it(*this);
+  Iterator rhs_it(*other_dict);
+  while (!lhs_it.IsAtEnd() && !rhs_it.IsAtEnd()) {
+    if (lhs_it.key() != rhs_it.key() ||
+        !lhs_it.value().Equals(&rhs_it.value())) {
+      return false;
+    }
+    lhs_it.Advance();
+    rhs_it.Advance();
+  }
+  if (!lhs_it.IsAtEnd() || !rhs_it.IsAtEnd())
+    return false;
+
+  return true;
+}
+
+///////////////////// ListValue ////////////////////
+
+ListValue::ListValue() : Value(TYPE_LIST) {
+}
+
+ListValue::~ListValue() {
+  Clear();
+}
+
+void ListValue::Clear() {
+  for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i)
+    delete *i;
+  list_.clear();
+}
+
+bool ListValue::Set(size_t index, Value* in_value) {
+  if (!in_value)
+    return false;
+
+  if (index >= list_.size()) {
+    // Pad out any intermediate indexes with null settings
+    while (index > list_.size())
+      Append(CreateNullValue());
+    Append(in_value);
+  } else {
+    DCHECK(list_[index] != in_value);
+    delete list_[index];
+    list_[index] = in_value;
+  }
+  return true;
+}
+
+bool ListValue::Set(size_t index, scoped_ptr<Value> in_value) {
+  return Set(index, in_value.release());
+}
+
+bool ListValue::Get(size_t index, const Value** out_value) const {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    *out_value = list_[index];
+
+  return true;
+}
+
+bool ListValue::Get(size_t index, Value** out_value) {
+  return static_cast<const ListValue&>(*this).Get(
+      index,
+      const_cast<const Value**>(out_value));
+}
+
+bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsBoolean(bool_value);
+}
+
+bool ListValue::GetInteger(size_t index, int* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool ListValue::GetDouble(size_t index, double* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool ListValue::GetString(size_t index, std::string* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool ListValue::GetString(size_t index, string16* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool ListValue::GetBinary(size_t index, const BinaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_BINARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const BinaryValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetBinary(size_t index, BinaryValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetBinary(
+      index,
+      const_cast<const BinaryValue**>(out_value));
+}
+
+bool ListValue::GetDictionary(size_t index,
+                              const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetDictionary(
+      index,
+      const_cast<const DictionaryValue**>(out_value));
+}
+
+bool ListValue::GetList(size_t index, const ListValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetList(size_t index, ListValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetList(
+      index,
+      const_cast<const ListValue**>(out_value));
+}
+
+bool ListValue::Remove(size_t index, scoped_ptr<Value>* out_value) {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    out_value->reset(list_[index]);
+  else
+    delete list_[index];
+
+  list_.erase(list_.begin() + index);
+  return true;
+}
+
+bool ListValue::Remove(const Value& value, size_t* index) {
+  for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) {
+    if ((*i)->Equals(&value)) {
+      size_t previous_index = i - list_.begin();
+      delete *i;
+      list_.erase(i);
+
+      if (index)
+        *index = previous_index;
+      return true;
+    }
+  }
+  return false;
+}
+
+ListValue::iterator ListValue::Erase(iterator iter,
+                                     scoped_ptr<Value>* out_value) {
+  if (out_value)
+    out_value->reset(*iter);
+  else
+    delete *iter;
+
+  return list_.erase(iter);
+}
+
+void ListValue::Append(scoped_ptr<Value> in_value) {
+  Append(in_value.release());
+}
+
+void ListValue::Append(Value* in_value) {
+  DCHECK(in_value);
+  list_.push_back(in_value);
+}
+
+void ListValue::AppendBoolean(bool in_value) {
+  Append(new FundamentalValue(in_value));
+}
+
+void ListValue::AppendInteger(int in_value) {
+  Append(new FundamentalValue(in_value));
+}
+
+void ListValue::AppendDouble(double in_value) {
+  Append(new FundamentalValue(in_value));
+}
+
+void ListValue::AppendString(const std::string& in_value) {
+  Append(new StringValue(in_value));
+}
+
+void ListValue::AppendString(const string16& in_value) {
+  Append(new StringValue(in_value));
+}
+
+void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
+  for (std::vector<std::string>::const_iterator it = in_values.begin();
+       it != in_values.end(); ++it) {
+    AppendString(*it);
+  }
+}
+
+void ListValue::AppendStrings(const std::vector<string16>& in_values) {
+  for (std::vector<string16>::const_iterator it = in_values.begin();
+       it != in_values.end(); ++it) {
+    AppendString(*it);
+  }
+}
+
+bool ListValue::AppendIfNotPresent(Value* in_value) {
+  DCHECK(in_value);
+  for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) {
+    if ((*i)->Equals(in_value)) {
+      delete in_value;
+      return false;
+    }
+  }
+  list_.push_back(in_value);
+  return true;
+}
+
+bool ListValue::Insert(size_t index, Value* in_value) {
+  DCHECK(in_value);
+  if (index > list_.size())
+    return false;
+
+  list_.insert(list_.begin() + index, in_value);
+  return true;
+}
+
+ListValue::const_iterator ListValue::Find(const Value& value) const {
+  return std::find_if(list_.begin(), list_.end(), ValueEquals(&value));
+}
+
+void ListValue::Swap(ListValue* other) {
+  list_.swap(other->list_);
+}
+
+bool ListValue::GetAsList(ListValue** out_value) {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool ListValue::GetAsList(const ListValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+ListValue* ListValue::DeepCopy() const {
+  ListValue* result = new ListValue;
+
+  for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
+    result->Append((*i)->DeepCopy());
+
+  return result;
+}
+
+bool ListValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const ListValue* other_list =
+      static_cast<const ListValue*>(other);
+  const_iterator lhs_it, rhs_it;
+  for (lhs_it = begin(), rhs_it = other_list->begin();
+       lhs_it != end() && rhs_it != other_list->end();
+       ++lhs_it, ++rhs_it) {
+    if (!(*lhs_it)->Equals(*rhs_it))
+      return false;
+  }
+  if (lhs_it != end() || rhs_it != other_list->end())
+    return false;
+
+  return true;
+}
+
+ValueSerializer::~ValueSerializer() {
+}
+
+ValueDeserializer::~ValueDeserializer() {
+}
+
+std::ostream& operator<<(std::ostream& out, const Value& value) {
+  std::string json;
+  JSONWriter::WriteWithOptions(&value,
+                               JSONWriter::OPTIONS_PRETTY_PRINT,
+                               &json);
+  return out << json;
+}
+
+}  // namespace base
diff --git a/base/values.h b/base/values.h
new file mode 100644
index 0000000..ca046f1
--- /dev/null
+++ b/base/values.h
@@ -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.
+
+// This file specifies a recursive data storage class called Value intended for
+// storing settings and other persistable data.
+//
+// A Value represents something that can be stored in JSON or passed to/from
+// JavaScript. As such, it is NOT a generalized variant type, since only the
+// types supported by JavaScript/JSON are supported.
+//
+// IN PARTICULAR this means that there is no support for int64 or unsigned
+// numbers. Writing JSON with such types would violate the spec. If you need
+// something like this, either use a double or make a string value containing
+// the number you want.
+
+#ifndef BASE_VALUES_H_
+#define BASE_VALUES_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+class BinaryValue;
+class DictionaryValue;
+class FundamentalValue;
+class ListValue;
+class StringValue;
+class Value;
+
+typedef std::vector<Value*> ValueVector;
+typedef std::map<std::string, Value*> ValueMap;
+
+// The Value class is the base class for Values. A Value can be instantiated
+// via the Create*Value() factory methods, or by directly creating instances of
+// the subclasses.
+//
+// See the file-level comment above for more information.
+class BASE_EXPORT Value {
+ public:
+  enum Type {
+    TYPE_NULL = 0,
+    TYPE_BOOLEAN,
+    TYPE_INTEGER,
+    TYPE_DOUBLE,
+    TYPE_STRING,
+    TYPE_BINARY,
+    TYPE_DICTIONARY,
+    TYPE_LIST
+    // Note: Do not add more types. See the file-level comment above for why.
+  };
+
+  virtual ~Value();
+
+  static Value* CreateNullValue();
+
+  // Returns the type of the value stored by the current Value object.
+  // Each type will be implemented by only one subclass of Value, so it's
+  // safe to use the Type to determine whether you can cast from
+  // Value* to (Implementing Class)*.  Also, a Value object never changes
+  // its type after construction.
+  Type GetType() const { return type_; }
+
+  // Returns true if the current object represents a given type.
+  bool IsType(Type type) const { return type == type_; }
+
+  // These methods allow the convenient retrieval of the contents of the Value.
+  // If the current object can be converted into the given type, the value is
+  // returned through the |out_value| parameter and true is returned;
+  // otherwise, false is returned and |out_value| is unchanged.
+  virtual bool GetAsBoolean(bool* out_value) const;
+  virtual bool GetAsInteger(int* out_value) const;
+  virtual bool GetAsDouble(double* out_value) const;
+  virtual bool GetAsString(std::string* out_value) const;
+  virtual bool GetAsString(string16* out_value) const;
+  virtual bool GetAsString(const StringValue** out_value) const;
+  virtual bool GetAsBinary(const BinaryValue** out_value) const;
+  virtual bool GetAsList(ListValue** out_value);
+  virtual bool GetAsList(const ListValue** out_value) const;
+  virtual bool GetAsDictionary(DictionaryValue** out_value);
+  virtual bool GetAsDictionary(const DictionaryValue** out_value) const;
+  // Note: Do not add more types. See the file-level comment above for why.
+
+  // This creates a deep copy of the entire Value tree, and returns a pointer
+  // to the copy.  The caller gets ownership of the copy, of course.
+  //
+  // Subclasses return their own type directly in their overrides;
+  // this works because C++ supports covariant return types.
+  virtual Value* DeepCopy() const;
+  // Preferred version of DeepCopy. TODO(estade): remove the above.
+  scoped_ptr<Value> CreateDeepCopy() const;
+
+  // Compares if two Value objects have equal contents.
+  virtual bool Equals(const Value* other) const;
+
+  // Compares if two Value objects have equal contents. Can handle NULLs.
+  // NULLs are considered equal but different from Value::CreateNullValue().
+  static bool Equals(const Value* a, const Value* b);
+
+ protected:
+  // These aren't safe for end-users, but they are useful for subclasses.
+  explicit Value(Type type);
+  Value(const Value& that);
+  Value& operator=(const Value& that);
+
+ private:
+  Type type_;
+};
+
+// FundamentalValue represents the simple fundamental types of values.
+class BASE_EXPORT FundamentalValue : public Value {
+ public:
+  explicit FundamentalValue(bool in_value);
+  explicit FundamentalValue(int in_value);
+  explicit FundamentalValue(double in_value);
+  ~FundamentalValue() override;
+
+  // Overridden from Value:
+  bool GetAsBoolean(bool* out_value) const override;
+  bool GetAsInteger(int* out_value) const override;
+  // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
+  // doubles.
+  bool GetAsDouble(double* out_value) const override;
+  FundamentalValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+ private:
+  union {
+    bool boolean_value_;
+    int integer_value_;
+    double double_value_;
+  };
+};
+
+class BASE_EXPORT StringValue : public Value {
+ public:
+  // Initializes a StringValue with a UTF-8 narrow character string.
+  explicit StringValue(const std::string& in_value);
+
+  // Initializes a StringValue with a string16.
+  explicit StringValue(const string16& in_value);
+
+  ~StringValue() override;
+
+  // Returns |value_| as a pointer or reference.
+  std::string* GetString();
+  const std::string& GetString() const;
+
+  // Overridden from Value:
+  bool GetAsString(std::string* out_value) const override;
+  bool GetAsString(string16* out_value) const override;
+  bool GetAsString(const StringValue** out_value) const override;
+  StringValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+ private:
+  std::string value_;
+};
+
+class BASE_EXPORT BinaryValue: public Value {
+ public:
+  // Creates a BinaryValue with a null buffer and size of 0.
+  BinaryValue();
+
+  // Creates a BinaryValue, taking ownership of the bytes pointed to by
+  // |buffer|.
+  BinaryValue(scoped_ptr<char[]> buffer, size_t size);
+
+  ~BinaryValue() override;
+
+  // For situations where you want to keep ownership of your buffer, this
+  // factory method creates a new BinaryValue by copying the contents of the
+  // buffer that's passed in.
+  static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size);
+
+  size_t GetSize() const { return size_; }
+
+  // May return NULL.
+  char* GetBuffer() { return buffer_.get(); }
+  const char* GetBuffer() const { return buffer_.get(); }
+
+  // Overridden from Value:
+  bool GetAsBinary(const BinaryValue** out_value) const override;
+  BinaryValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+ private:
+  scoped_ptr<char[]> buffer_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(BinaryValue);
+};
+
+// DictionaryValue provides a key-value dictionary with (optional) "path"
+// parsing for recursive access; see the comment at the top of the file. Keys
+// are |std::string|s and should be UTF-8 encoded.
+class BASE_EXPORT DictionaryValue : public Value {
+ public:
+  DictionaryValue();
+  ~DictionaryValue() override;
+
+  // Overridden from Value:
+  bool GetAsDictionary(DictionaryValue** out_value) override;
+  bool GetAsDictionary(const DictionaryValue** out_value) const override;
+
+  // Returns true if the current dictionary has a value for the given key.
+  bool HasKey(const std::string& key) const;
+
+  // Returns the number of Values in this dictionary.
+  size_t size() const { return dictionary_.size(); }
+
+  // Returns whether the dictionary is empty.
+  bool empty() const { return dictionary_.empty(); }
+
+  // Clears any current contents of this dictionary.
+  void Clear();
+
+  // Sets the Value associated with the given path starting from this object.
+  // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
+  // into the next DictionaryValue down.  Obviously, "." can't be used
+  // within a key, but there are no other restrictions on keys.
+  // If the key at any step of the way doesn't exist, or exists but isn't
+  // a DictionaryValue, a new DictionaryValue will be created and attached
+  // to the path in that location. |in_value| must be non-null.
+  void Set(const std::string& path, scoped_ptr<Value> in_value);
+  // Deprecated version of the above. TODO(estade): remove.
+  void Set(const std::string& path, Value* in_value);
+
+  // Convenience forms of Set().  These methods will replace any existing
+  // value at that path, even if it has a different type.
+  void SetBoolean(const std::string& path, bool in_value);
+  void SetInteger(const std::string& path, int in_value);
+  void SetDouble(const std::string& path, double in_value);
+  void SetString(const std::string& path, const std::string& in_value);
+  void SetString(const std::string& path, const string16& in_value);
+
+  // Like Set(), but without special treatment of '.'.  This allows e.g. URLs to
+  // be used as paths.
+  void SetWithoutPathExpansion(const std::string& key,
+                               scoped_ptr<Value> in_value);
+  // Deprecated version of the above. TODO(estade): remove.
+  void SetWithoutPathExpansion(const std::string& key, Value* in_value);
+
+  // Convenience forms of SetWithoutPathExpansion().
+  void SetBooleanWithoutPathExpansion(const std::string& path, bool in_value);
+  void SetIntegerWithoutPathExpansion(const std::string& path, int in_value);
+  void SetDoubleWithoutPathExpansion(const std::string& path, double in_value);
+  void SetStringWithoutPathExpansion(const std::string& path,
+                                     const std::string& in_value);
+  void SetStringWithoutPathExpansion(const std::string& path,
+                                     const string16& in_value);
+
+  // Gets the Value associated with the given path starting from this object.
+  // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
+  // into the next DictionaryValue down.  If the path can be resolved
+  // successfully, the value for the last key in the path will be returned
+  // through the |out_value| parameter, and the function will return true.
+  // Otherwise, it will return false and |out_value| will be untouched.
+  // Note that the dictionary always owns the value that's returned.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool Get(const std::string& path, const Value** out_value) const;
+  bool Get(const std::string& path, Value** out_value);
+
+  // These are convenience forms of Get().  The value will be retrieved
+  // and the return value will be true if the path is valid and the value at
+  // the end of the path can be returned in the form specified.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool GetBoolean(const std::string& path, bool* out_value) const;
+  bool GetInteger(const std::string& path, int* out_value) const;
+  // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
+  // doubles.
+  bool GetDouble(const std::string& path, double* out_value) const;
+  bool GetString(const std::string& path, std::string* out_value) const;
+  bool GetString(const std::string& path, string16* out_value) const;
+  bool GetStringASCII(const std::string& path, std::string* out_value) const;
+  bool GetBinary(const std::string& path, const BinaryValue** out_value) const;
+  bool GetBinary(const std::string& path, BinaryValue** out_value);
+  bool GetDictionary(const std::string& path,
+                     const DictionaryValue** out_value) const;
+  bool GetDictionary(const std::string& path, DictionaryValue** out_value);
+  bool GetList(const std::string& path, const ListValue** out_value) const;
+  bool GetList(const std::string& path, ListValue** out_value);
+
+  // Like Get(), but without special treatment of '.'.  This allows e.g. URLs to
+  // be used as paths.
+  bool GetWithoutPathExpansion(const std::string& key,
+                               const Value** out_value) const;
+  bool GetWithoutPathExpansion(const std::string& key, Value** out_value);
+  bool GetBooleanWithoutPathExpansion(const std::string& key,
+                                      bool* out_value) const;
+  bool GetIntegerWithoutPathExpansion(const std::string& key,
+                                      int* out_value) const;
+  bool GetDoubleWithoutPathExpansion(const std::string& key,
+                                     double* out_value) const;
+  bool GetStringWithoutPathExpansion(const std::string& key,
+                                     std::string* out_value) const;
+  bool GetStringWithoutPathExpansion(const std::string& key,
+                                     string16* out_value) const;
+  bool GetDictionaryWithoutPathExpansion(
+      const std::string& key,
+      const DictionaryValue** out_value) const;
+  bool GetDictionaryWithoutPathExpansion(const std::string& key,
+                                         DictionaryValue** out_value);
+  bool GetListWithoutPathExpansion(const std::string& key,
+                                   const ListValue** out_value) const;
+  bool GetListWithoutPathExpansion(const std::string& key,
+                                   ListValue** out_value);
+
+  // Removes the Value with the specified path from this dictionary (or one
+  // of its child dictionaries, if the path is more than just a local key).
+  // If |out_value| is non-NULL, the removed Value will be passed out via
+  // |out_value|.  If |out_value| is NULL, the removed value will be deleted.
+  // This method returns true if |path| is a valid path; otherwise it will
+  // return false and the DictionaryValue object will be unchanged.
+  virtual bool Remove(const std::string& path, scoped_ptr<Value>* out_value);
+
+  // Like Remove(), but without special treatment of '.'.  This allows e.g. URLs
+  // to be used as paths.
+  virtual bool RemoveWithoutPathExpansion(const std::string& key,
+                                          scoped_ptr<Value>* out_value);
+
+  // Removes a path, clearing out all dictionaries on |path| that remain empty
+  // after removing the value at |path|.
+  virtual bool RemovePath(const std::string& path,
+                          scoped_ptr<Value>* out_value);
+
+  // Makes a copy of |this| but doesn't include empty dictionaries and lists in
+  // the copy.  This never returns NULL, even if |this| itself is empty.
+  DictionaryValue* DeepCopyWithoutEmptyChildren() const;
+
+  // Merge |dictionary| into this dictionary. This is done recursively, i.e. any
+  // sub-dictionaries will be merged as well. In case of key collisions, the
+  // passed in dictionary takes precedence and data already present will be
+  // replaced. Values within |dictionary| are deep-copied, so |dictionary| may
+  // be freed any time after this call.
+  void MergeDictionary(const DictionaryValue* dictionary);
+
+  // Swaps contents with the |other| dictionary.
+  virtual void Swap(DictionaryValue* other);
+
+  // This class provides an iterator over both keys and values in the
+  // dictionary.  It can't be used to modify the dictionary.
+  class BASE_EXPORT Iterator {
+   public:
+    explicit Iterator(const DictionaryValue& target);
+    ~Iterator();
+
+    bool IsAtEnd() const { return it_ == target_.dictionary_.end(); }
+    void Advance() { ++it_; }
+
+    const std::string& key() const { return it_->first; }
+    const Value& value() const { return *it_->second; }
+
+   private:
+    const DictionaryValue& target_;
+    ValueMap::const_iterator it_;
+  };
+
+  // Overridden from Value:
+  DictionaryValue* DeepCopy() const override;
+  // Preferred version of DeepCopy. TODO(estade): remove the above.
+  scoped_ptr<DictionaryValue> CreateDeepCopy() const;
+  bool Equals(const Value* other) const override;
+
+ private:
+  ValueMap dictionary_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryValue);
+};
+
+// This type of Value represents a list of other Value values.
+class BASE_EXPORT ListValue : public Value {
+ public:
+  typedef ValueVector::iterator iterator;
+  typedef ValueVector::const_iterator const_iterator;
+
+  ListValue();
+  ~ListValue() override;
+
+  // Clears the contents of this ListValue
+  void Clear();
+
+  // Returns the number of Values in this list.
+  size_t GetSize() const { return list_.size(); }
+
+  // Returns whether the list is empty.
+  bool empty() const { return list_.empty(); }
+
+  // Sets the list item at the given index to be the Value specified by
+  // the value given.  If the index beyond the current end of the list, null
+  // Values will be used to pad out the list.
+  // Returns true if successful, or false if the index was negative or
+  // the value is a null pointer.
+  bool Set(size_t index, Value* in_value);
+  // Preferred version of the above. TODO(estade): remove the above.
+  bool Set(size_t index, scoped_ptr<Value> in_value);
+
+  // Gets the Value at the given index.  Modifies |out_value| (and returns true)
+  // only if the index falls within the current list range.
+  // Note that the list always owns the Value passed out via |out_value|.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool Get(size_t index, const Value** out_value) const;
+  bool Get(size_t index, Value** out_value);
+
+  // Convenience forms of Get().  Modifies |out_value| (and returns true)
+  // only if the index is valid and the Value at that index can be returned
+  // in the specified form.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool GetBoolean(size_t index, bool* out_value) const;
+  bool GetInteger(size_t index, int* out_value) const;
+  // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
+  // doubles.
+  bool GetDouble(size_t index, double* out_value) const;
+  bool GetString(size_t index, std::string* out_value) const;
+  bool GetString(size_t index, string16* out_value) const;
+  bool GetBinary(size_t index, const BinaryValue** out_value) const;
+  bool GetBinary(size_t index, BinaryValue** out_value);
+  bool GetDictionary(size_t index, const DictionaryValue** out_value) const;
+  bool GetDictionary(size_t index, DictionaryValue** out_value);
+  bool GetList(size_t index, const ListValue** out_value) const;
+  bool GetList(size_t index, ListValue** out_value);
+
+  // Removes the Value with the specified index from this list.
+  // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be
+  // passed out via |out_value|.  If |out_value| is NULL, the removed value will
+  // be deleted.  This method returns true if |index| is valid; otherwise
+  // it will return false and the ListValue object will be unchanged.
+  virtual bool Remove(size_t index, scoped_ptr<Value>* out_value);
+
+  // Removes the first instance of |value| found in the list, if any, and
+  // deletes it. |index| is the location where |value| was found. Returns false
+  // if not found.
+  bool Remove(const Value& value, size_t* index);
+
+  // Removes the element at |iter|. If |out_value| is NULL, the value will be
+  // deleted, otherwise ownership of the value is passed back to the caller.
+  // Returns an iterator pointing to the location of the element that
+  // followed the erased element.
+  iterator Erase(iterator iter, scoped_ptr<Value>* out_value);
+
+  // Appends a Value to the end of the list.
+  void Append(scoped_ptr<Value> in_value);
+  // Deprecated version of the above. TODO(estade): remove.
+  void Append(Value* in_value);
+
+  // Convenience forms of Append.
+  void AppendBoolean(bool in_value);
+  void AppendInteger(int in_value);
+  void AppendDouble(double in_value);
+  void AppendString(const std::string& in_value);
+  void AppendString(const string16& in_value);
+  void AppendStrings(const std::vector<std::string>& in_values);
+  void AppendStrings(const std::vector<string16>& in_values);
+
+  // Appends a Value if it's not already present. Takes ownership of the
+  // |in_value|. Returns true if successful, or false if the value was already
+  // present. If the value was already present the |in_value| is deleted.
+  bool AppendIfNotPresent(Value* in_value);
+
+  // Insert a Value at index.
+  // Returns true if successful, or false if the index was out of range.
+  bool Insert(size_t index, Value* in_value);
+
+  // Searches for the first instance of |value| in the list using the Equals
+  // method of the Value type.
+  // Returns a const_iterator to the found item or to end() if none exists.
+  const_iterator Find(const Value& value) const;
+
+  // Swaps contents with the |other| list.
+  virtual void Swap(ListValue* other);
+
+  // Iteration.
+  iterator begin() { return list_.begin(); }
+  iterator end() { return list_.end(); }
+
+  const_iterator begin() const { return list_.begin(); }
+  const_iterator end() const { return list_.end(); }
+
+  // Overridden from Value:
+  bool GetAsList(ListValue** out_value) override;
+  bool GetAsList(const ListValue** out_value) const override;
+  ListValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+ private:
+  ValueVector list_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListValue);
+};
+
+// This interface is implemented by classes that know how to serialize
+// Value objects.
+class BASE_EXPORT ValueSerializer {
+ public:
+  virtual ~ValueSerializer();
+
+  virtual bool Serialize(const Value& root) = 0;
+};
+
+// This interface is implemented by classes that know how to deserialize Value
+// objects.
+class BASE_EXPORT ValueDeserializer {
+ public:
+  virtual ~ValueDeserializer();
+
+  // This method deserializes the subclass-specific format into a Value object.
+  // If the return value is non-NULL, the caller takes ownership of returned
+  // Value. If the return value is NULL, and if error_code is non-NULL,
+  // error_code will be set with the underlying error.
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  virtual Value* Deserialize(int* error_code, std::string* error_str) = 0;
+};
+
+// Stream operator so Values can be used in assertion statements.  In order that
+// gtest uses this operator to print readable output on test failures, we must
+// override each specific type. Otherwise, the default template implementation
+// is preferred over an upcast.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value);
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const FundamentalValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const StringValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const DictionaryValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const ListValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+}  // namespace base
+
+#endif  // BASE_VALUES_H_
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
new file mode 100644
index 0000000..0d39d8b
--- /dev/null
+++ b/base/values_unittest.cc
@@ -0,0 +1,1129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ValuesTest, Basic) {
+  // Test basic dictionary getting/setting
+  DictionaryValue settings;
+  std::string homepage = "http://google.com";
+  ASSERT_FALSE(settings.GetString("global.homepage", &homepage));
+  ASSERT_EQ(std::string("http://google.com"), homepage);
+
+  ASSERT_FALSE(settings.Get("global", NULL));
+  settings.SetBoolean("global", true);
+  ASSERT_TRUE(settings.Get("global", NULL));
+  settings.SetString("global.homepage", "http://scurvy.com");
+  ASSERT_TRUE(settings.Get("global", NULL));
+  homepage = "http://google.com";
+  ASSERT_TRUE(settings.GetString("global.homepage", &homepage));
+  ASSERT_EQ(std::string("http://scurvy.com"), homepage);
+
+  // Test storing a dictionary in a list.
+  ListValue* toolbar_bookmarks;
+  ASSERT_FALSE(
+    settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
+
+  toolbar_bookmarks = new ListValue;
+  settings.Set("global.toolbar.bookmarks", make_scoped_ptr(toolbar_bookmarks));
+  ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
+
+  DictionaryValue* new_bookmark = new DictionaryValue;
+  new_bookmark->SetString("name", "Froogle");
+  new_bookmark->SetString("url", "http://froogle.com");
+  toolbar_bookmarks->Append(new_bookmark);
+
+  ListValue* bookmark_list;
+  ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
+  DictionaryValue* bookmark;
+  ASSERT_EQ(1U, bookmark_list->GetSize());
+  ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark));
+  std::string bookmark_name = "Unnamed";
+  ASSERT_TRUE(bookmark->GetString("name", &bookmark_name));
+  ASSERT_EQ(std::string("Froogle"), bookmark_name);
+  std::string bookmark_url;
+  ASSERT_TRUE(bookmark->GetString("url", &bookmark_url));
+  ASSERT_EQ(std::string("http://froogle.com"), bookmark_url);
+}
+
+TEST(ValuesTest, List) {
+  scoped_ptr<ListValue> mixed_list(new ListValue());
+  mixed_list->Set(0, make_scoped_ptr(new FundamentalValue(true)));
+  mixed_list->Set(1, make_scoped_ptr(new FundamentalValue(42)));
+  mixed_list->Set(2, make_scoped_ptr(new FundamentalValue(88.8)));
+  mixed_list->Set(3, make_scoped_ptr(new StringValue("foo")));
+  ASSERT_EQ(4u, mixed_list->GetSize());
+
+  Value *value = NULL;
+  bool bool_value = false;
+  int int_value = 0;
+  double double_value = 0.0;
+  std::string string_value;
+
+  ASSERT_FALSE(mixed_list->Get(4, &value));
+
+  ASSERT_FALSE(mixed_list->GetInteger(0, &int_value));
+  ASSERT_EQ(0, int_value);
+  ASSERT_FALSE(mixed_list->GetBoolean(1, &bool_value));
+  ASSERT_FALSE(bool_value);
+  ASSERT_FALSE(mixed_list->GetString(2, &string_value));
+  ASSERT_EQ("", string_value);
+  ASSERT_FALSE(mixed_list->GetInteger(2, &int_value));
+  ASSERT_EQ(0, int_value);
+  ASSERT_FALSE(mixed_list->GetBoolean(3, &bool_value));
+  ASSERT_FALSE(bool_value);
+
+  ASSERT_TRUE(mixed_list->GetBoolean(0, &bool_value));
+  ASSERT_TRUE(bool_value);
+  ASSERT_TRUE(mixed_list->GetInteger(1, &int_value));
+  ASSERT_EQ(42, int_value);
+  // implicit conversion from Integer to Double should be possible.
+  ASSERT_TRUE(mixed_list->GetDouble(1, &double_value));
+  ASSERT_EQ(42, double_value);
+  ASSERT_TRUE(mixed_list->GetDouble(2, &double_value));
+  ASSERT_EQ(88.8, double_value);
+  ASSERT_TRUE(mixed_list->GetString(3, &string_value));
+  ASSERT_EQ("foo", string_value);
+
+  // Try searching in the mixed list.
+  base::FundamentalValue sought_value(42);
+  base::FundamentalValue not_found_value(false);
+
+  ASSERT_NE(mixed_list->end(), mixed_list->Find(sought_value));
+  ASSERT_TRUE((*mixed_list->Find(sought_value))->GetAsInteger(&int_value));
+  ASSERT_EQ(42, int_value);
+  ASSERT_EQ(mixed_list->end(), mixed_list->Find(not_found_value));
+}
+
+TEST(ValuesTest, BinaryValue) {
+  // Default constructor creates a BinaryValue with a null buffer and size 0.
+  scoped_ptr<BinaryValue> binary(new BinaryValue());
+  ASSERT_TRUE(binary.get());
+  ASSERT_EQ(NULL, binary->GetBuffer());
+  ASSERT_EQ(0U, binary->GetSize());
+
+  // Test the common case of a non-empty buffer
+  char* buffer = new char[15];
+  binary.reset(new BinaryValue(scoped_ptr<char[]>(buffer), 15));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  ASSERT_EQ(buffer, binary->GetBuffer());
+  ASSERT_EQ(15U, binary->GetSize());
+
+  char stack_buffer[42];
+  memset(stack_buffer, '!', 42);
+  binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  ASSERT_NE(stack_buffer, binary->GetBuffer());
+  ASSERT_EQ(42U, binary->GetSize());
+  ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize()));
+
+  // Test overloaded GetAsBinary.
+  Value* narrow_value = binary.get();
+  const BinaryValue* narrow_binary = NULL;
+  ASSERT_TRUE(narrow_value->GetAsBinary(&narrow_binary));
+  EXPECT_EQ(binary.get(), narrow_binary);
+}
+
+TEST(ValuesTest, StringValue) {
+  // Test overloaded StringValue constructor.
+  scoped_ptr<Value> narrow_value(new StringValue("narrow"));
+  ASSERT_TRUE(narrow_value.get());
+  ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING));
+  scoped_ptr<Value> utf16_value(new StringValue(ASCIIToUTF16("utf16")));
+  ASSERT_TRUE(utf16_value.get());
+  ASSERT_TRUE(utf16_value->IsType(Value::TYPE_STRING));
+
+  // Test overloaded GetAsString.
+  std::string narrow = "http://google.com";
+  string16 utf16 = ASCIIToUTF16("http://google.com");
+  const StringValue* string_value = NULL;
+  ASSERT_TRUE(narrow_value->GetAsString(&narrow));
+  ASSERT_TRUE(narrow_value->GetAsString(&utf16));
+  ASSERT_TRUE(narrow_value->GetAsString(&string_value));
+  ASSERT_EQ(std::string("narrow"), narrow);
+  ASSERT_EQ(ASCIIToUTF16("narrow"), utf16);
+  ASSERT_EQ(string_value->GetString(), narrow);
+
+  ASSERT_TRUE(utf16_value->GetAsString(&narrow));
+  ASSERT_TRUE(utf16_value->GetAsString(&utf16));
+  ASSERT_TRUE(utf16_value->GetAsString(&string_value));
+  ASSERT_EQ(std::string("utf16"), narrow);
+  ASSERT_EQ(ASCIIToUTF16("utf16"), utf16);
+  ASSERT_EQ(string_value->GetString(), narrow);
+
+  // Don't choke on NULL values.
+  ASSERT_TRUE(narrow_value->GetAsString(static_cast<string16*>(NULL)));
+  ASSERT_TRUE(narrow_value->GetAsString(static_cast<std::string*>(NULL)));
+  ASSERT_TRUE(narrow_value->GetAsString(
+                  static_cast<const StringValue**>(NULL)));
+}
+
+// This is a Value object that allows us to tell if it's been
+// properly deleted by modifying the value of external flag on destruction.
+class DeletionTestValue : public Value {
+ public:
+  explicit DeletionTestValue(bool* deletion_flag) : Value(TYPE_NULL) {
+    Init(deletion_flag);  // Separate function so that we can use ASSERT_*
+  }
+
+  void Init(bool* deletion_flag) {
+    ASSERT_TRUE(deletion_flag);
+    deletion_flag_ = deletion_flag;
+    *deletion_flag_ = false;
+  }
+
+  ~DeletionTestValue() override { *deletion_flag_ = true; }
+
+ private:
+  bool* deletion_flag_;
+};
+
+TEST(ValuesTest, ListDeletion) {
+  bool deletion_flag = true;
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+    list.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(list.Set(0, Value::CreateNullValue()));
+    EXPECT_TRUE(deletion_flag);
+  }
+}
+
+TEST(ValuesTest, ListRemoval) {
+  bool deletion_flag = true;
+  scoped_ptr<Value> removed_item;
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_EQ(1U, list.GetSize());
+    EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(),
+                             &removed_item));
+    EXPECT_FALSE(list.Remove(1, &removed_item));
+    EXPECT_TRUE(list.Remove(0, &removed_item));
+    ASSERT_TRUE(removed_item);
+    EXPECT_EQ(0U, list.GetSize());
+  }
+  EXPECT_FALSE(deletion_flag);
+  removed_item.reset();
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(new DeletionTestValue(&deletion_flag));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(list.Remove(0, NULL));
+    EXPECT_TRUE(deletion_flag);
+    EXPECT_EQ(0U, list.GetSize());
+  }
+
+  {
+    ListValue list;
+    DeletionTestValue* value = new DeletionTestValue(&deletion_flag);
+    list.Append(value);
+    EXPECT_FALSE(deletion_flag);
+    size_t index = 0;
+    list.Remove(*value, &index);
+    EXPECT_EQ(0U, index);
+    EXPECT_TRUE(deletion_flag);
+    EXPECT_EQ(0U, list.GetSize());
+  }
+}
+
+TEST(ValuesTest, DictionaryDeletion) {
+  std::string key = "test";
+  bool deletion_flag = true;
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    dict.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    dict.Set(key, Value::CreateNullValue());
+    EXPECT_TRUE(deletion_flag);
+  }
+}
+
+TEST(ValuesTest, DictionaryRemoval) {
+  std::string key = "test";
+  bool deletion_flag = true;
+  scoped_ptr<Value> removed_item;
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(dict.HasKey(key));
+    EXPECT_FALSE(dict.Remove("absent key", &removed_item));
+    EXPECT_TRUE(dict.Remove(key, &removed_item));
+    EXPECT_FALSE(dict.HasKey(key));
+    ASSERT_TRUE(removed_item);
+  }
+  EXPECT_FALSE(deletion_flag);
+  removed_item.reset();
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(dict.HasKey(key));
+    EXPECT_TRUE(dict.Remove(key, NULL));
+    EXPECT_TRUE(deletion_flag);
+    EXPECT_FALSE(dict.HasKey(key));
+  }
+}
+
+TEST(ValuesTest, DictionaryWithoutPathExpansion) {
+  DictionaryValue dict;
+  dict.Set("this.is.expanded", make_scoped_ptr(Value::CreateNullValue()));
+  dict.SetWithoutPathExpansion("this.isnt.expanded",
+                               make_scoped_ptr(Value::CreateNullValue()));
+
+  EXPECT_FALSE(dict.HasKey("this.is.expanded"));
+  EXPECT_TRUE(dict.HasKey("this"));
+  Value* value1;
+  EXPECT_TRUE(dict.Get("this", &value1));
+  DictionaryValue* value2;
+  ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2));
+  EXPECT_EQ(value1, value2);
+  EXPECT_EQ(1U, value2->size());
+
+  EXPECT_TRUE(dict.HasKey("this.isnt.expanded"));
+  Value* value3;
+  EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3));
+  Value* value4;
+  ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4));
+  EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
+}
+
+// Tests the deprecated version of SetWithoutPathExpansion.
+// TODO(estade): remove.
+TEST(ValuesTest, DictionaryWithoutPathExpansionDeprecated) {
+  DictionaryValue dict;
+  dict.Set("this.is.expanded", Value::CreateNullValue());
+  dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue());
+
+  EXPECT_FALSE(dict.HasKey("this.is.expanded"));
+  EXPECT_TRUE(dict.HasKey("this"));
+  Value* value1;
+  EXPECT_TRUE(dict.Get("this", &value1));
+  DictionaryValue* value2;
+  ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2));
+  EXPECT_EQ(value1, value2);
+  EXPECT_EQ(1U, value2->size());
+
+  EXPECT_TRUE(dict.HasKey("this.isnt.expanded"));
+  Value* value3;
+  EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3));
+  Value* value4;
+  ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4));
+  EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
+}
+
+TEST(ValuesTest, DictionaryRemovePath) {
+  DictionaryValue dict;
+  dict.SetInteger("a.long.way.down", 1);
+  dict.SetBoolean("a.long.key.path", true);
+
+  scoped_ptr<Value> removed_item;
+  EXPECT_TRUE(dict.RemovePath("a.long.way.down", &removed_item));
+  ASSERT_TRUE(removed_item);
+  EXPECT_TRUE(removed_item->IsType(base::Value::TYPE_INTEGER));
+  EXPECT_FALSE(dict.HasKey("a.long.way.down"));
+  EXPECT_FALSE(dict.HasKey("a.long.way"));
+  EXPECT_TRUE(dict.Get("a.long.key.path", NULL));
+
+  removed_item.reset();
+  EXPECT_FALSE(dict.RemovePath("a.long.way.down", &removed_item));
+  EXPECT_FALSE(removed_item);
+  EXPECT_TRUE(dict.Get("a.long.key.path", NULL));
+
+  removed_item.reset();
+  EXPECT_TRUE(dict.RemovePath("a.long.key.path", &removed_item));
+  ASSERT_TRUE(removed_item);
+  EXPECT_TRUE(removed_item->IsType(base::Value::TYPE_BOOLEAN));
+  EXPECT_TRUE(dict.empty());
+}
+
+TEST(ValuesTest, DeepCopy) {
+  DictionaryValue original_dict;
+  Value* original_null = Value::CreateNullValue();
+  original_dict.Set("null", make_scoped_ptr(original_null));
+  FundamentalValue* original_bool = new FundamentalValue(true);
+  original_dict.Set("bool", make_scoped_ptr(original_bool));
+  FundamentalValue* original_int = new FundamentalValue(42);
+  original_dict.Set("int", make_scoped_ptr(original_int));
+  FundamentalValue* original_double = new FundamentalValue(3.14);
+  original_dict.Set("double", make_scoped_ptr(original_double));
+  StringValue* original_string = new StringValue("hello");
+  original_dict.Set("string", make_scoped_ptr(original_string));
+  StringValue* original_string16 = new StringValue(ASCIIToUTF16("hello16"));
+  original_dict.Set("string16", make_scoped_ptr(original_string16));
+
+  scoped_ptr<char[]> original_buffer(new char[42]);
+  memset(original_buffer.get(), '!', 42);
+  BinaryValue* original_binary = new BinaryValue(original_buffer.Pass(), 42);
+  original_dict.Set("binary", original_binary);
+
+  ListValue* original_list = new ListValue();
+  FundamentalValue* original_list_element_0 = new FundamentalValue(0);
+  original_list->Append(original_list_element_0);
+  FundamentalValue* original_list_element_1 = new FundamentalValue(1);
+  original_list->Append(original_list_element_1);
+  original_dict.Set("list", make_scoped_ptr(original_list));
+
+  DictionaryValue* original_nested_dictionary = new DictionaryValue();
+  original_nested_dictionary->SetString("key", "value");
+  original_dict.Set("dictionary", make_scoped_ptr(original_nested_dictionary));
+
+  scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy();
+  ASSERT_TRUE(copy_dict.get());
+  ASSERT_NE(copy_dict.get(), &original_dict);
+
+  Value* copy_null = NULL;
+  ASSERT_TRUE(copy_dict->Get("null", &copy_null));
+  ASSERT_TRUE(copy_null);
+  ASSERT_NE(copy_null, original_null);
+  ASSERT_TRUE(copy_null->IsType(Value::TYPE_NULL));
+
+  Value* copy_bool = NULL;
+  ASSERT_TRUE(copy_dict->Get("bool", &copy_bool));
+  ASSERT_TRUE(copy_bool);
+  ASSERT_NE(copy_bool, original_bool);
+  ASSERT_TRUE(copy_bool->IsType(Value::TYPE_BOOLEAN));
+  bool copy_bool_value = false;
+  ASSERT_TRUE(copy_bool->GetAsBoolean(&copy_bool_value));
+  ASSERT_TRUE(copy_bool_value);
+
+  Value* copy_int = NULL;
+  ASSERT_TRUE(copy_dict->Get("int", &copy_int));
+  ASSERT_TRUE(copy_int);
+  ASSERT_NE(copy_int, original_int);
+  ASSERT_TRUE(copy_int->IsType(Value::TYPE_INTEGER));
+  int copy_int_value = 0;
+  ASSERT_TRUE(copy_int->GetAsInteger(&copy_int_value));
+  ASSERT_EQ(42, copy_int_value);
+
+  Value* copy_double = NULL;
+  ASSERT_TRUE(copy_dict->Get("double", &copy_double));
+  ASSERT_TRUE(copy_double);
+  ASSERT_NE(copy_double, original_double);
+  ASSERT_TRUE(copy_double->IsType(Value::TYPE_DOUBLE));
+  double copy_double_value = 0;
+  ASSERT_TRUE(copy_double->GetAsDouble(&copy_double_value));
+  ASSERT_EQ(3.14, copy_double_value);
+
+  Value* copy_string = NULL;
+  ASSERT_TRUE(copy_dict->Get("string", &copy_string));
+  ASSERT_TRUE(copy_string);
+  ASSERT_NE(copy_string, original_string);
+  ASSERT_TRUE(copy_string->IsType(Value::TYPE_STRING));
+  std::string copy_string_value;
+  string16 copy_string16_value;
+  ASSERT_TRUE(copy_string->GetAsString(&copy_string_value));
+  ASSERT_TRUE(copy_string->GetAsString(&copy_string16_value));
+  ASSERT_EQ(std::string("hello"), copy_string_value);
+  ASSERT_EQ(ASCIIToUTF16("hello"), copy_string16_value);
+
+  Value* copy_string16 = NULL;
+  ASSERT_TRUE(copy_dict->Get("string16", &copy_string16));
+  ASSERT_TRUE(copy_string16);
+  ASSERT_NE(copy_string16, original_string16);
+  ASSERT_TRUE(copy_string16->IsType(Value::TYPE_STRING));
+  ASSERT_TRUE(copy_string16->GetAsString(&copy_string_value));
+  ASSERT_TRUE(copy_string16->GetAsString(&copy_string16_value));
+  ASSERT_EQ(std::string("hello16"), copy_string_value);
+  ASSERT_EQ(ASCIIToUTF16("hello16"), copy_string16_value);
+
+  Value* copy_binary = NULL;
+  ASSERT_TRUE(copy_dict->Get("binary", &copy_binary));
+  ASSERT_TRUE(copy_binary);
+  ASSERT_NE(copy_binary, original_binary);
+  ASSERT_TRUE(copy_binary->IsType(Value::TYPE_BINARY));
+  ASSERT_NE(original_binary->GetBuffer(),
+    static_cast<BinaryValue*>(copy_binary)->GetBuffer());
+  ASSERT_EQ(original_binary->GetSize(),
+    static_cast<BinaryValue*>(copy_binary)->GetSize());
+  ASSERT_EQ(0, memcmp(original_binary->GetBuffer(),
+               static_cast<BinaryValue*>(copy_binary)->GetBuffer(),
+               original_binary->GetSize()));
+
+  Value* copy_value = NULL;
+  ASSERT_TRUE(copy_dict->Get("list", &copy_value));
+  ASSERT_TRUE(copy_value);
+  ASSERT_NE(copy_value, original_list);
+  ASSERT_TRUE(copy_value->IsType(Value::TYPE_LIST));
+  ListValue* copy_list = NULL;
+  ASSERT_TRUE(copy_value->GetAsList(&copy_list));
+  ASSERT_TRUE(copy_list);
+  ASSERT_EQ(2U, copy_list->GetSize());
+
+  Value* copy_list_element_0;
+  ASSERT_TRUE(copy_list->Get(0, &copy_list_element_0));
+  ASSERT_TRUE(copy_list_element_0);
+  ASSERT_NE(copy_list_element_0, original_list_element_0);
+  int copy_list_element_0_value;
+  ASSERT_TRUE(copy_list_element_0->GetAsInteger(&copy_list_element_0_value));
+  ASSERT_EQ(0, copy_list_element_0_value);
+
+  Value* copy_list_element_1;
+  ASSERT_TRUE(copy_list->Get(1, &copy_list_element_1));
+  ASSERT_TRUE(copy_list_element_1);
+  ASSERT_NE(copy_list_element_1, original_list_element_1);
+  int copy_list_element_1_value;
+  ASSERT_TRUE(copy_list_element_1->GetAsInteger(&copy_list_element_1_value));
+  ASSERT_EQ(1, copy_list_element_1_value);
+
+  copy_value = NULL;
+  ASSERT_TRUE(copy_dict->Get("dictionary", &copy_value));
+  ASSERT_TRUE(copy_value);
+  ASSERT_NE(copy_value, original_nested_dictionary);
+  ASSERT_TRUE(copy_value->IsType(Value::TYPE_DICTIONARY));
+  DictionaryValue* copy_nested_dictionary = NULL;
+  ASSERT_TRUE(copy_value->GetAsDictionary(&copy_nested_dictionary));
+  ASSERT_TRUE(copy_nested_dictionary);
+  EXPECT_TRUE(copy_nested_dictionary->HasKey("key"));
+}
+
+TEST(ValuesTest, Equals) {
+  Value* null1 = Value::CreateNullValue();
+  Value* null2 = Value::CreateNullValue();
+  EXPECT_NE(null1, null2);
+  EXPECT_TRUE(null1->Equals(null2));
+
+  Value* boolean = new FundamentalValue(false);
+  EXPECT_FALSE(null1->Equals(boolean));
+  delete null1;
+  delete null2;
+  delete boolean;
+
+  DictionaryValue dv;
+  dv.SetBoolean("a", false);
+  dv.SetInteger("b", 2);
+  dv.SetDouble("c", 2.5);
+  dv.SetString("d1", "string");
+  dv.SetString("d2", ASCIIToUTF16("http://google.com"));
+  dv.Set("e", make_scoped_ptr(Value::CreateNullValue()));
+
+  scoped_ptr<DictionaryValue> copy = dv.CreateDeepCopy();
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  ListValue* list = new ListValue;
+  list->Append(Value::CreateNullValue());
+  list->Append(new DictionaryValue);
+  dv.Set("f", make_scoped_ptr(list));
+
+  EXPECT_FALSE(dv.Equals(copy.get()));
+  copy->Set("f", list->CreateDeepCopy());
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  list->Append(new FundamentalValue(true));
+  EXPECT_FALSE(dv.Equals(copy.get()));
+
+  // Check if Equals detects differences in only the keys.
+  copy = dv.CreateDeepCopy();
+  EXPECT_TRUE(dv.Equals(copy.get()));
+  copy->Remove("a", NULL);
+  copy->SetBoolean("aa", false);
+  EXPECT_FALSE(dv.Equals(copy.get()));
+}
+
+TEST(ValuesTest, StaticEquals) {
+  scoped_ptr<Value> null1(Value::CreateNullValue());
+  scoped_ptr<Value> null2(Value::CreateNullValue());
+  EXPECT_TRUE(Value::Equals(null1.get(), null2.get()));
+  EXPECT_TRUE(Value::Equals(NULL, NULL));
+
+  scoped_ptr<Value> i42(new FundamentalValue(42));
+  scoped_ptr<Value> j42(new FundamentalValue(42));
+  scoped_ptr<Value> i17(new FundamentalValue(17));
+  EXPECT_TRUE(Value::Equals(i42.get(), i42.get()));
+  EXPECT_TRUE(Value::Equals(j42.get(), i42.get()));
+  EXPECT_TRUE(Value::Equals(i42.get(), j42.get()));
+  EXPECT_FALSE(Value::Equals(i42.get(), i17.get()));
+  EXPECT_FALSE(Value::Equals(i42.get(), NULL));
+  EXPECT_FALSE(Value::Equals(NULL, i42.get()));
+
+  // NULL and Value::CreateNullValue() are intentionally different: We need
+  // support for NULL as a return value for "undefined" without caring for
+  // ownership of the pointer.
+  EXPECT_FALSE(Value::Equals(null1.get(), NULL));
+  EXPECT_FALSE(Value::Equals(NULL, null1.get()));
+}
+
+TEST(ValuesTest, DeepCopyCovariantReturnTypes) {
+  DictionaryValue original_dict;
+  Value* original_null = Value::CreateNullValue();
+  original_dict.Set("null", make_scoped_ptr(original_null));
+  FundamentalValue* original_bool = new FundamentalValue(true);
+  original_dict.Set("bool", make_scoped_ptr(original_bool));
+  FundamentalValue* original_int = new FundamentalValue(42);
+  original_dict.Set("int", make_scoped_ptr(original_int));
+  FundamentalValue* original_double = new FundamentalValue(3.14);
+  original_dict.Set("double", make_scoped_ptr(original_double));
+  StringValue* original_string = new StringValue("hello");
+  original_dict.Set("string", make_scoped_ptr(original_string));
+  StringValue* original_string16 = new StringValue(ASCIIToUTF16("hello16"));
+  original_dict.Set("string16", make_scoped_ptr(original_string16));
+
+  scoped_ptr<char[]> original_buffer(new char[42]);
+  memset(original_buffer.get(), '!', 42);
+  BinaryValue* original_binary = new BinaryValue(original_buffer.Pass(), 42);
+  original_dict.Set("binary", make_scoped_ptr(original_binary));
+
+  ListValue* original_list = new ListValue();
+  FundamentalValue* original_list_element_0 = new FundamentalValue(0);
+  original_list->Append(original_list_element_0);
+  FundamentalValue* original_list_element_1 = new FundamentalValue(1);
+  original_list->Append(original_list_element_1);
+  original_dict.Set("list", make_scoped_ptr(original_list));
+
+  Value* original_dict_value = &original_dict;
+  Value* original_bool_value = original_bool;
+  Value* original_int_value = original_int;
+  Value* original_double_value = original_double;
+  Value* original_string_value = original_string;
+  Value* original_string16_value = original_string16;
+  Value* original_binary_value = original_binary;
+  Value* original_list_value = original_list;
+
+  scoped_ptr<Value> copy_dict_value = original_dict_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_bool_value = original_bool_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_int_value = original_int_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_double_value = original_double_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_string_value = original_string_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_string16_value =
+      original_string16_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_binary_value = original_binary_value->CreateDeepCopy();
+  scoped_ptr<Value> copy_list_value = original_list_value->CreateDeepCopy();
+
+  EXPECT_TRUE(original_dict_value->Equals(copy_dict_value.get()));
+  EXPECT_TRUE(original_bool_value->Equals(copy_bool_value.get()));
+  EXPECT_TRUE(original_int_value->Equals(copy_int_value.get()));
+  EXPECT_TRUE(original_double_value->Equals(copy_double_value.get()));
+  EXPECT_TRUE(original_string_value->Equals(copy_string_value.get()));
+  EXPECT_TRUE(original_string16_value->Equals(copy_string16_value.get()));
+  EXPECT_TRUE(original_binary_value->Equals(copy_binary_value.get()));
+  EXPECT_TRUE(original_list_value->Equals(copy_list_value.get()));
+}
+
+TEST(ValuesTest, RemoveEmptyChildren) {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  // Remove empty lists and dictionaries.
+  root->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+  root->Set("empty_list", make_scoped_ptr(new ListValue));
+  root->SetWithoutPathExpansion("a.b.c.d.e",
+                                make_scoped_ptr(new DictionaryValue));
+  root.reset(root->DeepCopyWithoutEmptyChildren());
+  EXPECT_TRUE(root->empty());
+
+  // Make sure we don't prune too much.
+  root->SetBoolean("bool", true);
+  root->Set("empty_dict", new DictionaryValue);
+  root->SetString("empty_string", std::string());
+  root.reset(root->DeepCopyWithoutEmptyChildren());
+  EXPECT_EQ(2U, root->size());
+
+  // Should do nothing.
+  root.reset(root->DeepCopyWithoutEmptyChildren());
+  EXPECT_EQ(2U, root->size());
+
+  // Nested test cases.  These should all reduce back to the bool and string
+  // set above.
+  {
+    root->Set("a.b.c.d.e", new DictionaryValue);
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    scoped_ptr<DictionaryValue> inner(new DictionaryValue);
+    inner->Set("empty_dict", new DictionaryValue);
+    inner->Set("empty_list", new ListValue);
+    root->Set("dict_with_empty_children", inner.Pass());
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    scoped_ptr<ListValue> inner(new ListValue);
+    inner->Append(make_scoped_ptr(new DictionaryValue));
+    inner->Append(make_scoped_ptr(new ListValue));
+    root->Set("list_with_empty_children", inner.Pass());
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Nested with siblings.
+  {
+    scoped_ptr<ListValue> inner(new ListValue());
+    inner->Append(make_scoped_ptr(new DictionaryValue));
+    inner->Append(make_scoped_ptr(new ListValue));
+    root->Set("list_with_empty_children", inner.Pass());
+    scoped_ptr<DictionaryValue> inner2(new DictionaryValue);
+    inner2->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+    inner2->Set("empty_list", make_scoped_ptr(new ListValue));
+    root->Set("dict_with_empty_children", inner2.Pass());
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Make sure nested values don't get pruned.
+  {
+    scoped_ptr<ListValue> inner(new ListValue);
+    scoped_ptr<ListValue> inner2(new ListValue);
+    inner2->Append(new StringValue("hello"));
+    inner->Append(make_scoped_ptr(new DictionaryValue));
+    inner->Append(inner2.Pass());
+    root->Set("list_with_empty_children", inner.Pass());
+    root.reset(root->DeepCopyWithoutEmptyChildren());
+    EXPECT_EQ(3U, root->size());
+
+    ListValue* inner_value, *inner_value2;
+    EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value));
+    EXPECT_EQ(1U, inner_value->GetSize());  // Dictionary was pruned.
+    EXPECT_TRUE(inner_value->GetList(0, &inner_value2));
+    EXPECT_EQ(1U, inner_value2->GetSize());
+  }
+}
+
+TEST(ValuesTest, MergeDictionary) {
+  scoped_ptr<DictionaryValue> base(new DictionaryValue);
+  base->SetString("base_key", "base_key_value_base");
+  base->SetString("collide_key", "collide_key_value_base");
+  DictionaryValue* base_sub_dict = new DictionaryValue;
+  base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
+  base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
+  base->Set("sub_dict_key", base_sub_dict);
+
+  scoped_ptr<DictionaryValue> merge(new DictionaryValue);
+  merge->SetString("merge_key", "merge_key_value_merge");
+  merge->SetString("collide_key", "collide_key_value_merge");
+  DictionaryValue* merge_sub_dict = new DictionaryValue;
+  merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
+  merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
+  merge->Set("sub_dict_key", merge_sub_dict);
+
+  base->MergeDictionary(merge.get());
+
+  EXPECT_EQ(4U, base->size());
+  std::string base_key_value;
+  EXPECT_TRUE(base->GetString("base_key", &base_key_value));
+  EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved.
+  std::string collide_key_value;
+  EXPECT_TRUE(base->GetString("collide_key", &collide_key_value));
+  EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced.
+  std::string merge_key_value;
+  EXPECT_TRUE(base->GetString("merge_key", &merge_key_value));
+  EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in.
+
+  DictionaryValue* res_sub_dict;
+  EXPECT_TRUE(base->GetDictionary("sub_dict_key", &res_sub_dict));
+  EXPECT_EQ(3U, res_sub_dict->size());
+  std::string sub_base_key_value;
+  EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value));
+  EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved.
+  std::string sub_collide_key_value;
+  EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key",
+                                      &sub_collide_key_value));
+  EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced.
+  std::string sub_merge_key_value;
+  EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value));
+  EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in.
+}
+
+TEST(ValuesTest, MergeDictionaryDeepCopy) {
+  DictionaryValue* child = new DictionaryValue;
+  child->SetString("test", "value");
+  EXPECT_EQ(1U, child->size());
+
+  std::string value;
+  EXPECT_TRUE(child->GetString("test", &value));
+  EXPECT_EQ("value", value);
+
+  scoped_ptr<DictionaryValue> base(new DictionaryValue);
+  base->Set("dict", child);
+  EXPECT_EQ(1U, base->size());
+
+  DictionaryValue* ptr;
+  EXPECT_TRUE(base->GetDictionary("dict", &ptr));
+  EXPECT_EQ(child, ptr);
+
+  scoped_ptr<DictionaryValue> merged(new DictionaryValue);
+  merged->MergeDictionary(base.get());
+  EXPECT_EQ(1U, merged->size());
+  EXPECT_TRUE(merged->GetDictionary("dict", &ptr));
+  EXPECT_NE(child, ptr);
+  EXPECT_TRUE(ptr->GetString("test", &value));
+  EXPECT_EQ("value", value);
+
+  child->SetString("test", "overwrite");
+  base.reset();
+  EXPECT_TRUE(ptr->GetString("test", &value));
+  EXPECT_EQ("value", value);
+}
+
+TEST(ValuesTest, DictionaryIterator) {
+  DictionaryValue dict;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    ADD_FAILURE();
+  }
+
+  StringValue value1("value1");
+  dict.Set("key1", value1.CreateDeepCopy());
+  bool seen1 = false;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    EXPECT_FALSE(seen1);
+    EXPECT_EQ("key1", it.key());
+    EXPECT_TRUE(value1.Equals(&it.value()));
+    seen1 = true;
+  }
+  EXPECT_TRUE(seen1);
+
+  StringValue value2("value2");
+  dict.Set("key2", value2.CreateDeepCopy());
+  bool seen2 = seen1 = false;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    if (it.key() == "key1") {
+      EXPECT_FALSE(seen1);
+      EXPECT_TRUE(value1.Equals(&it.value()));
+      seen1 = true;
+    } else if (it.key() == "key2") {
+      EXPECT_FALSE(seen2);
+      EXPECT_TRUE(value2.Equals(&it.value()));
+      seen2 = true;
+    } else {
+      ADD_FAILURE();
+    }
+  }
+  EXPECT_TRUE(seen1);
+  EXPECT_TRUE(seen2);
+}
+
+// DictionaryValue/ListValue's Get*() methods should accept NULL as an out-value
+// and still return true/false based on success.
+TEST(ValuesTest, GetWithNullOutValue) {
+  DictionaryValue main_dict;
+  ListValue main_list;
+
+  FundamentalValue bool_value(false);
+  FundamentalValue int_value(1234);
+  FundamentalValue double_value(12.34567);
+  StringValue string_value("foo");
+  BinaryValue binary_value;
+  DictionaryValue dict_value;
+  ListValue list_value;
+
+  main_dict.Set("bool", bool_value.CreateDeepCopy());
+  main_dict.Set("int", int_value.CreateDeepCopy());
+  main_dict.Set("double", double_value.CreateDeepCopy());
+  main_dict.Set("string", string_value.CreateDeepCopy());
+  main_dict.Set("binary", binary_value.CreateDeepCopy());
+  main_dict.Set("dict", dict_value.CreateDeepCopy());
+  main_dict.Set("list", list_value.CreateDeepCopy());
+
+  main_list.Append(bool_value.CreateDeepCopy());
+  main_list.Append(int_value.CreateDeepCopy());
+  main_list.Append(double_value.CreateDeepCopy());
+  main_list.Append(string_value.CreateDeepCopy());
+  main_list.Append(binary_value.CreateDeepCopy());
+  main_list.Append(dict_value.CreateDeepCopy());
+  main_list.Append(list_value.CreateDeepCopy());
+
+  EXPECT_TRUE(main_dict.Get("bool", NULL));
+  EXPECT_TRUE(main_dict.Get("int", NULL));
+  EXPECT_TRUE(main_dict.Get("double", NULL));
+  EXPECT_TRUE(main_dict.Get("string", NULL));
+  EXPECT_TRUE(main_dict.Get("binary", NULL));
+  EXPECT_TRUE(main_dict.Get("dict", NULL));
+  EXPECT_TRUE(main_dict.Get("list", NULL));
+  EXPECT_FALSE(main_dict.Get("DNE", NULL));
+
+  EXPECT_TRUE(main_dict.GetBoolean("bool", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("int", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("double", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("string", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("binary", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("dict", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("list", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetInteger("bool", NULL));
+  EXPECT_TRUE(main_dict.GetInteger("int", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("double", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("string", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("binary", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("dict", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("list", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("DNE", NULL));
+
+  // Both int and double values can be obtained from GetDouble.
+  EXPECT_FALSE(main_dict.GetDouble("bool", NULL));
+  EXPECT_TRUE(main_dict.GetDouble("int", NULL));
+  EXPECT_TRUE(main_dict.GetDouble("double", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("string", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("binary", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("list", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetString("bool", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("int", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("double", static_cast<std::string*>(NULL)));
+  EXPECT_TRUE(main_dict.GetString("string", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("binary", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("dict", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("list", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("DNE", static_cast<std::string*>(NULL)));
+
+  EXPECT_FALSE(main_dict.GetString("bool", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("int", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("double", static_cast<string16*>(NULL)));
+  EXPECT_TRUE(main_dict.GetString("string", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("binary", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("dict", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("list", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("DNE", static_cast<string16*>(NULL)));
+
+  EXPECT_FALSE(main_dict.GetBinary("bool", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("int", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("double", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("string", NULL));
+  EXPECT_TRUE(main_dict.GetBinary("binary", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("dict", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("list", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetDictionary("bool", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("int", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("double", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("string", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("binary", NULL));
+  EXPECT_TRUE(main_dict.GetDictionary("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("list", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetList("bool", NULL));
+  EXPECT_FALSE(main_dict.GetList("int", NULL));
+  EXPECT_FALSE(main_dict.GetList("double", NULL));
+  EXPECT_FALSE(main_dict.GetList("string", NULL));
+  EXPECT_FALSE(main_dict.GetList("binary", NULL));
+  EXPECT_FALSE(main_dict.GetList("dict", NULL));
+  EXPECT_TRUE(main_dict.GetList("list", NULL));
+  EXPECT_FALSE(main_dict.GetList("DNE", NULL));
+
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("bool", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("int", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("double", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("string", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("binary", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("dict", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_TRUE(main_dict.GetBooleanWithoutPathExpansion("bool", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("bool", NULL));
+  EXPECT_TRUE(main_dict.GetIntegerWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("bool", NULL));
+  EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("int", NULL));
+  EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "bool", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "int", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "double", static_cast<std::string*>(NULL)));
+  EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion(
+      "string", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "binary", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "dict", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "list", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "DNE", static_cast<std::string*>(NULL)));
+
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "bool", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "int", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "double", static_cast<string16*>(NULL)));
+  EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion(
+      "string", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "binary", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "dict", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "list", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "DNE", static_cast<string16*>(NULL)));
+
+  // There is no GetBinaryWithoutPathExpansion for some reason, but if there
+  // were it should be tested here...
+
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("bool", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("binary", NULL));
+  EXPECT_TRUE(main_dict.GetDictionaryWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("bool", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("dict", NULL));
+  EXPECT_TRUE(main_dict.GetListWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_TRUE(main_list.Get(0, NULL));
+  EXPECT_TRUE(main_list.Get(1, NULL));
+  EXPECT_TRUE(main_list.Get(2, NULL));
+  EXPECT_TRUE(main_list.Get(3, NULL));
+  EXPECT_TRUE(main_list.Get(4, NULL));
+  EXPECT_TRUE(main_list.Get(5, NULL));
+  EXPECT_TRUE(main_list.Get(6, NULL));
+  EXPECT_FALSE(main_list.Get(7, NULL));
+
+  EXPECT_TRUE(main_list.GetBoolean(0, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(1, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(2, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(3, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(4, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(5, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(6, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(7, NULL));
+
+  EXPECT_FALSE(main_list.GetInteger(0, NULL));
+  EXPECT_TRUE(main_list.GetInteger(1, NULL));
+  EXPECT_FALSE(main_list.GetInteger(2, NULL));
+  EXPECT_FALSE(main_list.GetInteger(3, NULL));
+  EXPECT_FALSE(main_list.GetInteger(4, NULL));
+  EXPECT_FALSE(main_list.GetInteger(5, NULL));
+  EXPECT_FALSE(main_list.GetInteger(6, NULL));
+  EXPECT_FALSE(main_list.GetInteger(7, NULL));
+
+  EXPECT_FALSE(main_list.GetDouble(0, NULL));
+  EXPECT_TRUE(main_list.GetDouble(1, NULL));
+  EXPECT_TRUE(main_list.GetDouble(2, NULL));
+  EXPECT_FALSE(main_list.GetDouble(3, NULL));
+  EXPECT_FALSE(main_list.GetDouble(4, NULL));
+  EXPECT_FALSE(main_list.GetDouble(5, NULL));
+  EXPECT_FALSE(main_list.GetDouble(6, NULL));
+  EXPECT_FALSE(main_list.GetDouble(7, NULL));
+
+  EXPECT_FALSE(main_list.GetString(0, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(1, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(2, static_cast<std::string*>(NULL)));
+  EXPECT_TRUE(main_list.GetString(3, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(4, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(5, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(6, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(7, static_cast<std::string*>(NULL)));
+
+  EXPECT_FALSE(main_list.GetString(0, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(1, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(2, static_cast<string16*>(NULL)));
+  EXPECT_TRUE(main_list.GetString(3, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(4, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(5, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(6, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(7, static_cast<string16*>(NULL)));
+
+  EXPECT_FALSE(main_list.GetBinary(0, NULL));
+  EXPECT_FALSE(main_list.GetBinary(1, NULL));
+  EXPECT_FALSE(main_list.GetBinary(2, NULL));
+  EXPECT_FALSE(main_list.GetBinary(3, NULL));
+  EXPECT_TRUE(main_list.GetBinary(4, NULL));
+  EXPECT_FALSE(main_list.GetBinary(5, NULL));
+  EXPECT_FALSE(main_list.GetBinary(6, NULL));
+  EXPECT_FALSE(main_list.GetBinary(7, NULL));
+
+  EXPECT_FALSE(main_list.GetDictionary(0, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(1, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(2, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(3, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(4, NULL));
+  EXPECT_TRUE(main_list.GetDictionary(5, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(6, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(7, NULL));
+
+  EXPECT_FALSE(main_list.GetList(0, NULL));
+  EXPECT_FALSE(main_list.GetList(1, NULL));
+  EXPECT_FALSE(main_list.GetList(2, NULL));
+  EXPECT_FALSE(main_list.GetList(3, NULL));
+  EXPECT_FALSE(main_list.GetList(4, NULL));
+  EXPECT_FALSE(main_list.GetList(5, NULL));
+  EXPECT_TRUE(main_list.GetList(6, NULL));
+  EXPECT_FALSE(main_list.GetList(7, NULL));
+}
+
+}  // namespace base
diff --git a/base/version.cc b/base/version.cc
new file mode 100644
index 0000000..ede8a45
--- /dev/null
+++ b/base/version.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/version.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+namespace {
+
+// Parses the |numbers| vector representing the different numbers
+// inside the version string and constructs a vector of valid integers. It stops
+// when it reaches an invalid item (including the wildcard character). |parsed|
+// is the resulting integer vector. Function returns true if all numbers were
+// parsed successfully, false otherwise.
+bool ParseVersionNumbers(const std::string& version_str,
+                         std::vector<uint32_t>* parsed) {
+  std::vector<std::string> numbers;
+  SplitString(version_str, '.', &numbers);
+  if (numbers.empty())
+    return false;
+
+  for (std::vector<std::string>::const_iterator it = numbers.begin();
+       it != numbers.end(); ++it) {
+    if (StartsWithASCII(*it, "+", false))
+      return false;
+    unsigned int num;
+    if (!StringToUint(*it, &num))
+      return false;
+
+    // This throws out leading zeros for the first item only.
+    if (it == numbers.begin() && UintToString(num) != *it)
+      return false;
+
+    // StringToUint returns unsigned int but Version fields are uint32_t.
+    static_assert(sizeof (uint32_t) == sizeof (unsigned int),
+        "uint32_t must be same as unsigned int");
+    parsed->push_back(num);
+  }
+  return true;
+}
+
+// Compares version components in |components1| with components in
+// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to,
+// or greater than |components2|, respectively.
+int CompareVersionComponents(const std::vector<uint32_t>& components1,
+                             const std::vector<uint32_t>& components2) {
+  const size_t count = std::min(components1.size(), components2.size());
+  for (size_t i = 0; i < count; ++i) {
+    if (components1[i] > components2[i])
+      return 1;
+    if (components1[i] < components2[i])
+      return -1;
+  }
+  if (components1.size() > components2.size()) {
+    for (size_t i = count; i < components1.size(); ++i) {
+      if (components1[i] > 0)
+        return 1;
+    }
+  } else if (components1.size() < components2.size()) {
+    for (size_t i = count; i < components2.size(); ++i) {
+      if (components2[i] > 0)
+        return -1;
+    }
+  }
+  return 0;
+}
+
+}  // namespace
+
+Version::Version() {
+}
+
+Version::~Version() {
+}
+
+Version::Version(const std::string& version_str) {
+  std::vector<uint32_t> parsed;
+  if (!ParseVersionNumbers(version_str, &parsed))
+    return;
+
+  components_.swap(parsed);
+}
+
+bool Version::IsValid() const {
+  return (!components_.empty());
+}
+
+// static
+bool Version::IsValidWildcardString(const std::string& wildcard_string) {
+  std::string version_string = wildcard_string;
+  if (EndsWith(wildcard_string.c_str(), ".*", false))
+    version_string = wildcard_string.substr(0, wildcard_string.size() - 2);
+
+  Version version(version_string);
+  return version.IsValid();
+}
+
+bool Version::IsOlderThan(const std::string& version_str) const {
+  Version proposed_ver(version_str);
+  if (!proposed_ver.IsValid())
+    return false;
+  return (CompareTo(proposed_ver) < 0);
+}
+
+int Version::CompareToWildcardString(const std::string& wildcard_string) const {
+  DCHECK(IsValid());
+  DCHECK(Version::IsValidWildcardString(wildcard_string));
+
+  // Default behavior if the string doesn't end with a wildcard.
+  if (!EndsWith(wildcard_string.c_str(), ".*", false)) {
+    Version version(wildcard_string);
+    DCHECK(version.IsValid());
+    return CompareTo(version);
+  }
+
+  std::vector<uint32_t> parsed;
+  const bool success = ParseVersionNumbers(
+      wildcard_string.substr(0, wildcard_string.length() - 2), &parsed);
+  DCHECK(success);
+  const int comparison = CompareVersionComponents(components_, parsed);
+  // If the version is smaller than the wildcard version's |parsed| vector,
+  // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the
+  // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to
+  // 1.2.2.* is 0 regardless of the wildcard). Under this logic,
+  // 1.2.0.0.0.0 compared to 1.2.* is 0.
+  if (comparison == -1 || comparison == 0)
+    return comparison;
+
+  // Catch the case where the digits of |parsed| are found in |components_|,
+  // which means that the two are equal since |parsed| has a trailing "*".
+  // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since
+  // components is greater (e.g. 3.2.3 vs 1.*).
+  DCHECK_GT(parsed.size(), 0UL);
+  const size_t min_num_comp = std::min(components_.size(), parsed.size());
+  for (size_t i = 0; i < min_num_comp; ++i) {
+    if (components_[i] != parsed[i])
+      return 1;
+  }
+  return 0;
+}
+
+bool Version::Equals(const Version& that) const {
+  DCHECK(IsValid());
+  DCHECK(that.IsValid());
+  return (CompareTo(that) == 0);
+}
+
+int Version::CompareTo(const Version& other) const {
+  DCHECK(IsValid());
+  DCHECK(other.IsValid());
+  return CompareVersionComponents(components_, other.components_);
+}
+
+const std::string Version::GetString() const {
+  DCHECK(IsValid());
+  std::string version_str;
+  size_t count = components_.size();
+  for (size_t i = 0; i < count - 1; ++i) {
+    version_str.append(IntToString(components_[i]));
+    version_str.append(".");
+  }
+  version_str.append(IntToString(components_[count - 1]));
+  return version_str;
+}
+
+}  // namespace base
diff --git a/base/version.h b/base/version.h
new file mode 100644
index 0000000..814acaa
--- /dev/null
+++ b/base/version.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_VERSION_H_
+#define BASE_VERSION_H_
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+// Version represents a dotted version number, like "1.2.3.4", supporting
+// parsing and comparison.
+class BASE_EXPORT Version {
+ public:
+  // The only thing you can legally do to a default constructed
+  // Version object is assign to it.
+  Version();
+
+  ~Version();
+
+  // Initializes from a decimal dotted version number, like "0.1.1".
+  // Each component is limited to a uint16. Call IsValid() to learn
+  // the outcome.
+  explicit Version(const std::string& version_str);
+
+  // Returns true if the object contains a valid version number.
+  bool IsValid() const;
+
+  // Returns true if the version wildcard string is valid. The version wildcard
+  // string may end with ".*" (e.g. 1.2.*, 1.*). Any other arrangement with "*"
+  // is invalid (e.g. 1.*.3 or 1.2.3*). This functions defaults to standard
+  // Version behavior (IsValid) if no wildcard is present.
+  static bool IsValidWildcardString(const std::string& wildcard_string);
+
+  // Commonly used pattern. Given a valid version object, compare if a
+  // |version_str| results in a newer version. Returns true if the
+  // string represents valid version and if the version is greater than
+  // than the version of this object.
+  bool IsOlderThan(const std::string& version_str) const;
+
+  bool Equals(const Version& other) const;
+
+  // Returns -1, 0, 1 for <, ==, >.
+  int CompareTo(const Version& other) const;
+
+  // Given a valid version object, compare if a |wildcard_string| results in a
+  // newer version. This function will default to CompareTo if the string does
+  // not end in wildcard sequence ".*". IsValidWildcard(wildcard_string) must be
+  // true before using this function.
+  int CompareToWildcardString(const std::string& wildcard_string) const;
+
+  // Return the string representation of this version.
+  const std::string GetString() const;
+
+  const std::vector<uint32_t>& components() const { return components_; }
+
+ private:
+  std::vector<uint32_t> components_;
+};
+
+}  // namespace base
+
+// TODO(xhwang) remove this when all users are updated to explicitly use the
+// namespace
+using base::Version;
+
+#endif  // BASE_VERSION_H_
diff --git a/base/version_unittest.cc b/base/version_unittest.cc
new file mode 100644
index 0000000..f40ed27
--- /dev/null
+++ b/base/version_unittest.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/version.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(VersionTest, DefaultConstructor) {
+  Version v;
+  EXPECT_FALSE(v.IsValid());
+}
+
+TEST(VersionTest, ValueSemantics) {
+  Version v1("1.2.3.4");
+  EXPECT_TRUE(v1.IsValid());
+  Version v3;
+  EXPECT_FALSE(v3.IsValid());
+  {
+    Version v2(v1);
+    v3 = v2;
+    EXPECT_TRUE(v2.IsValid());
+    EXPECT_TRUE(v1.Equals(v2));
+  }
+  EXPECT_TRUE(v3.Equals(v1));
+}
+
+TEST(VersionTest, GetVersionFromString) {
+  static const struct version_string {
+    const char* input;
+    size_t parts;
+    uint32_t firstpart;
+    bool success;
+  } cases[] = {
+    {"", 0, 0, false},
+    {" ", 0, 0, false},
+    {"\t", 0, 0, false},
+    {"\n", 0, 0, false},
+    {"  ", 0, 0, false},
+    {".", 0, 0, false},
+    {" . ", 0, 0, false},
+    {"0", 1, 0, true},
+    {"0.", 0, 0, false},
+    {"0.0", 2, 0, true},
+    {"4294967295.0", 2, 4294967295, true},
+    {"4294967296.0", 0, 0, false},
+    {"-1.0", 0, 0, false},
+    {"1.-1.0", 0, 0, false},
+    {"1,--1.0", 0, 0, false},
+    {"+1.0", 0, 0, false},
+    {"1.+1.0", 0, 0, false},
+    {"1+1.0", 0, 0, false},
+    {"++1.0", 0, 0, false},
+    {"1.0a", 0, 0, false},
+    {"1.2.3.4.5.6.7.8.9.0", 10, 1, true},
+    {"02.1", 0, 0, false},
+    {"0.01", 2, 0, true},
+    {"f.1", 0, 0, false},
+    {"15.007.20011", 3, 15, true},
+    {"15.5.28.130162", 4, 15, true},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    Version version(cases[i].input);
+    EXPECT_EQ(cases[i].success, version.IsValid());
+    if (cases[i].success) {
+      EXPECT_EQ(cases[i].parts, version.components().size());
+      EXPECT_EQ(cases[i].firstpart, version.components()[0]);
+    }
+  }
+}
+
+TEST(VersionTest, Compare) {
+  static const struct version_compare {
+    const char* lhs;
+    const char* rhs;
+    int expected;
+  } cases[] = {
+    {"1.0", "1.0", 0},
+    {"1.0", "0.0", 1},
+    {"1.0", "2.0", -1},
+    {"1.0", "1.1", -1},
+    {"1.1", "1.0", 1},
+    {"1.0", "1.0.1", -1},
+    {"1.1", "1.0.1", 1},
+    {"1.1", "1.0.1", 1},
+    {"1.0.0", "1.0", 0},
+    {"1.0.3", "1.0.20", -1},
+    {"11.0.10", "15.007.20011", -1},
+    {"11.0.10", "15.5.28.130162", -1},
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    Version lhs(cases[i].lhs);
+    Version rhs(cases[i].rhs);
+    EXPECT_EQ(lhs.CompareTo(rhs), cases[i].expected) <<
+        cases[i].lhs << " ? " << cases[i].rhs;
+
+    EXPECT_EQ(lhs.IsOlderThan(cases[i].rhs), (cases[i].expected == -1));
+  }
+}
+
+TEST(VersionTest, CompareToWildcardString) {
+  static const struct version_compare {
+    const char* lhs;
+    const char* rhs;
+    int expected;
+  } cases[] = {
+    {"1.0", "1.*", 0},
+    {"1.0", "0.*", 1},
+    {"1.0", "2.*", -1},
+    {"1.2.3", "1.2.3.*", 0},
+    {"10.0", "1.0.*", 1},
+    {"1.0", "3.0.*", -1},
+    {"1.4", "1.3.0.*", 1},
+    {"1.3.9", "1.3.*", 0},
+    {"1.4.1", "1.3.*", 1},
+    {"1.3", "1.4.5.*", -1},
+    {"1.5", "1.4.5.*", 1},
+    {"1.3.9", "1.3.*", 0},
+    {"1.2.0.0.0.0", "1.2.*", 0},
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    const Version version(cases[i].lhs);
+    const int result = version.CompareToWildcardString(cases[i].rhs);
+    EXPECT_EQ(result, cases[i].expected) << cases[i].lhs << "?" << cases[i].rhs;
+  }
+}
+
+TEST(VersionTest, IsValidWildcardString) {
+  static const struct version_compare {
+    const char* version;
+    bool expected;
+  } cases[] = {
+    {"1.0", true},
+    {"", false},
+    {"1.2.3.4.5.6", true},
+    {"1.2.3.*", true},
+    {"1.2.3.5*", false},
+    {"1.2.3.56*", false},
+    {"1.*.3", false},
+    {"20.*", true},
+    {"+2.*", false},
+    {"*", false},
+    {"*.2", false},
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    EXPECT_EQ(Version::IsValidWildcardString(cases[i].version),
+        cases[i].expected) << cases[i].version << "?" << cases[i].expected;
+  }
+}
+
+}  // namespace
diff --git a/base/vlog.cc b/base/vlog.cc
new file mode 100644
index 0000000..519ceff
--- /dev/null
+++ b/base/vlog.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/vlog.h"
+
+#include <cstddef>
+#include <ostream>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+
+namespace logging {
+
+const int VlogInfo::kDefaultVlogLevel = 0;
+
+struct VlogInfo::VmodulePattern {
+  enum MatchTarget { MATCH_MODULE, MATCH_FILE };
+
+  explicit VmodulePattern(const std::string& pattern);
+
+  VmodulePattern();
+
+  std::string pattern;
+  int vlog_level;
+  MatchTarget match_target;
+};
+
+VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern)
+    : pattern(pattern),
+      vlog_level(VlogInfo::kDefaultVlogLevel),
+      match_target(MATCH_MODULE) {
+  // If the pattern contains a {forward,back} slash, we assume that
+  // it's meant to be tested against the entire __FILE__ string.
+  std::string::size_type first_slash = pattern.find_first_of("\\/");
+  if (first_slash != std::string::npos)
+    match_target = MATCH_FILE;
+}
+
+VlogInfo::VmodulePattern::VmodulePattern()
+    : vlog_level(VlogInfo::kDefaultVlogLevel),
+      match_target(MATCH_MODULE) {}
+
+VlogInfo::VlogInfo(const std::string& v_switch,
+                   const std::string& vmodule_switch,
+                   int* min_log_level)
+    : min_log_level_(min_log_level) {
+  DCHECK(min_log_level != NULL);
+
+  int vlog_level = 0;
+  if (!v_switch.empty()) {
+    if (base::StringToInt(v_switch, &vlog_level)) {
+      SetMaxVlogLevel(vlog_level);
+    } else {
+      DLOG(WARNING) << "Could not parse v switch \"" << v_switch << "\"";
+    }
+  }
+
+  base::StringPairs kv_pairs;
+  if (!base::SplitStringIntoKeyValuePairs(
+          vmodule_switch, '=', ',', &kv_pairs)) {
+    DLOG(WARNING) << "Could not fully parse vmodule switch \""
+                  << vmodule_switch << "\"";
+  }
+  for (base::StringPairs::const_iterator it = kv_pairs.begin();
+       it != kv_pairs.end(); ++it) {
+    VmodulePattern pattern(it->first);
+    if (!base::StringToInt(it->second, &pattern.vlog_level)) {
+      DLOG(WARNING) << "Parsed vlog level for \""
+                    << it->first << "=" << it->second
+                    << "\" as " << pattern.vlog_level;
+    }
+    vmodule_levels_.push_back(pattern);
+  }
+}
+
+VlogInfo::~VlogInfo() {}
+
+namespace {
+
+// Given a path, returns the basename with the extension chopped off
+// (and any -inl suffix).  We avoid using FilePath to minimize the
+// number of dependencies the logging system has.
+base::StringPiece GetModule(const base::StringPiece& file) {
+  base::StringPiece module(file);
+  base::StringPiece::size_type last_slash_pos =
+      module.find_last_of("\\/");
+  if (last_slash_pos != base::StringPiece::npos)
+    module.remove_prefix(last_slash_pos + 1);
+  base::StringPiece::size_type extension_start = module.rfind('.');
+  module = module.substr(0, extension_start);
+  static const char kInlSuffix[] = "-inl";
+  static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
+  if (module.ends_with(kInlSuffix))
+    module.remove_suffix(kInlSuffixLen);
+  return module;
+}
+
+}  // namespace
+
+int VlogInfo::GetVlogLevel(const base::StringPiece& file) const {
+  if (!vmodule_levels_.empty()) {
+    base::StringPiece module(GetModule(file));
+    for (std::vector<VmodulePattern>::const_iterator it =
+             vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) {
+      base::StringPiece target(
+          (it->match_target == VmodulePattern::MATCH_FILE) ? file : module);
+      if (MatchVlogPattern(target, it->pattern))
+        return it->vlog_level;
+    }
+  }
+  return GetMaxVlogLevel();
+}
+
+void VlogInfo::SetMaxVlogLevel(int level) {
+  // Log severity is the negative verbosity.
+  *min_log_level_ = -level;
+}
+
+int VlogInfo::GetMaxVlogLevel() const {
+  return -*min_log_level_;
+}
+
+bool MatchVlogPattern(const base::StringPiece& string,
+                      const base::StringPiece& vlog_pattern) {
+  base::StringPiece p(vlog_pattern);
+  base::StringPiece s(string);
+  // Consume characters until the next star.
+  while (!p.empty() && !s.empty() && (p[0] != '*')) {
+    switch (p[0]) {
+      // A slash (forward or back) must match a slash (forward or back).
+      case '/':
+      case '\\':
+        if ((s[0] != '/') && (s[0] != '\\'))
+          return false;
+        break;
+
+      // A '?' matches anything.
+      case '?':
+        break;
+
+      // Anything else must match literally.
+      default:
+        if (p[0] != s[0])
+          return false;
+        break;
+    }
+    p.remove_prefix(1), s.remove_prefix(1);
+  }
+
+  // An empty pattern here matches only an empty string.
+  if (p.empty())
+    return s.empty();
+
+  // Coalesce runs of consecutive stars.  There should be at least
+  // one.
+  while (!p.empty() && (p[0] == '*'))
+    p.remove_prefix(1);
+
+  // Since we moved past the stars, an empty pattern here matches
+  // anything.
+  if (p.empty())
+    return true;
+
+  // Since we moved past the stars and p is non-empty, if some
+  // non-empty substring of s matches p, then we ourselves match.
+  while (!s.empty()) {
+    if (MatchVlogPattern(s, p))
+      return true;
+    s.remove_prefix(1);
+  }
+
+  // Otherwise, we couldn't find a match.
+  return false;
+}
+
+}  // namespace logging
diff --git a/base/vlog.h b/base/vlog.h
new file mode 100644
index 0000000..a32ed14
--- /dev/null
+++ b/base/vlog.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_VLOG_H_
+#define BASE_VLOG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace logging {
+
+// A helper class containing all the settings for vlogging.
+class BASE_EXPORT VlogInfo {
+ public:
+  static const int kDefaultVlogLevel;
+
+  // |v_switch| gives the default maximal active V-logging level; 0 is
+  // the default.  Normally positive values are used for V-logging
+  // levels.
+  //
+  // |vmodule_switch| gives the per-module maximal V-logging levels to
+  // override the value given by |v_switch|.
+  // E.g. "my_module=2,foo*=3" would change the logging level for all
+  // code in source files "my_module.*" and "foo*.*" ("-inl" suffixes
+  // are also disregarded for this matching).
+  //
+  // |log_severity| points to an int that stores the log level. If a valid
+  // |v_switch| is provided, it will set the log level, and the default
+  // vlog severity will be read from there..
+  //
+  // Any pattern containing a forward or backward slash will be tested
+  // against the whole pathname and not just the module.  E.g.,
+  // "*/foo/bar/*=2" would change the logging level for all code in
+  // source files under a "foo/bar" directory.
+  VlogInfo(const std::string& v_switch,
+           const std::string& vmodule_switch,
+           int* min_log_level);
+  ~VlogInfo();
+
+  // Returns the vlog level for a given file (usually taken from
+  // __FILE__).
+  int GetVlogLevel(const base::StringPiece& file) const;
+
+ private:
+  void SetMaxVlogLevel(int level);
+  int GetMaxVlogLevel() const;
+
+  // VmodulePattern holds all the information for each pattern parsed
+  // from |vmodule_switch|.
+  struct VmodulePattern;
+  std::vector<VmodulePattern> vmodule_levels_;
+  int* min_log_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(VlogInfo);
+};
+
+// Returns true if the string passed in matches the vlog pattern.  The
+// vlog pattern string can contain wildcards like * and ?.  ? matches
+// exactly one character while * matches 0 or more characters.  Also,
+// as a special case, a / or \ character matches either / or \.
+//
+// Examples:
+//   "kh?n" matches "khan" but not "khn" or "khaan"
+//   "kh*n" matches "khn", "khan", or even "khaaaaan"
+//   "/foo\bar" matches "/foo/bar", "\foo\bar", or "/foo\bar"
+//     (disregarding C escaping rules)
+BASE_EXPORT bool MatchVlogPattern(const base::StringPiece& string,
+                                  const base::StringPiece& vlog_pattern);
+
+}  // namespace logging
+
+#endif  // BASE_VLOG_H_
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc
new file mode 100644
index 0000000..b505d4c
--- /dev/null
+++ b/base/vlog_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/vlog.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+TEST(VlogTest, NoVmodule) {
+  int min_log_level = 0;
+  EXPECT_EQ(0,
+            VlogInfo(std::string(), std::string(), &min_log_level)
+                .GetVlogLevel("test1"));
+  EXPECT_EQ(0,
+            VlogInfo("0", std::string(), &min_log_level).GetVlogLevel("test2"));
+  EXPECT_EQ(
+      0, VlogInfo("blah", std::string(), &min_log_level).GetVlogLevel("test3"));
+  EXPECT_EQ(
+      0,
+      VlogInfo("0blah1", std::string(), &min_log_level).GetVlogLevel("test4"));
+  EXPECT_EQ(1,
+            VlogInfo("1", std::string(), &min_log_level).GetVlogLevel("test5"));
+  EXPECT_EQ(5,
+            VlogInfo("5", std::string(), &min_log_level).GetVlogLevel("test6"));
+}
+
+TEST(VlogTest, MatchVlogPattern) {
+  // Degenerate cases.
+  EXPECT_TRUE(MatchVlogPattern("", ""));
+  EXPECT_TRUE(MatchVlogPattern("", "****"));
+  EXPECT_FALSE(MatchVlogPattern("", "x"));
+  EXPECT_FALSE(MatchVlogPattern("x", ""));
+
+  // Basic.
+  EXPECT_TRUE(MatchVlogPattern("blah", "blah"));
+
+  // ? should match exactly one character.
+  EXPECT_TRUE(MatchVlogPattern("blah", "bl?h"));
+  EXPECT_FALSE(MatchVlogPattern("blh", "bl?h"));
+  EXPECT_FALSE(MatchVlogPattern("blaah", "bl?h"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "?lah"));
+  EXPECT_FALSE(MatchVlogPattern("lah", "?lah"));
+  EXPECT_FALSE(MatchVlogPattern("bblah", "?lah"));
+
+  // * can match any number (even 0) of characters.
+  EXPECT_TRUE(MatchVlogPattern("blah", "bl*h"));
+  EXPECT_TRUE(MatchVlogPattern("blabcdefh", "bl*h"));
+  EXPECT_TRUE(MatchVlogPattern("blh", "bl*h"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "*blah"));
+  EXPECT_TRUE(MatchVlogPattern("ohblah", "*blah"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "*blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blahhhh", "*blah*"));
+  EXPECT_TRUE(MatchVlogPattern("bbbblahhhh", "*blah*"));
+
+  // Multiple *s should work fine.
+  EXPECT_TRUE(MatchVlogPattern("ballaah", "b*la*h"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "b*la*h"));
+  EXPECT_TRUE(MatchVlogPattern("bbbblah", "b*la*h"));
+  EXPECT_TRUE(MatchVlogPattern("blaaah", "b*la*h"));
+
+  // There should be no escaping going on.
+  EXPECT_TRUE(MatchVlogPattern("bl\\ah", "bl\\?h"));
+  EXPECT_FALSE(MatchVlogPattern("bl?h", "bl\\?h"));
+  EXPECT_TRUE(MatchVlogPattern("bl\\aaaah", "bl\\*h"));
+  EXPECT_FALSE(MatchVlogPattern("bl*h", "bl\\*h"));
+
+  // Any slash matches any slash.
+  EXPECT_TRUE(MatchVlogPattern("/b\\lah", "/b\\lah"));
+  EXPECT_TRUE(MatchVlogPattern("\\b/lah", "/b\\lah"));
+}
+
+TEST(VlogTest, VmoduleBasic) {
+  const char kVSwitch[] = "-1";
+  const char kVModuleSwitch[] =
+      "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge.ext=5";
+  int min_log_level = 0;
+  VlogInfo vlog_info(kVSwitch, kVModuleSwitch, &min_log_level);
+  EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm"));
+  EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h"));
+  EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux"));
+  EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.ext.h"));
+}
+
+TEST(VlogTest, VmoduleDirs) {
+  const char kVModuleSwitch[] =
+      "foo/bar.cc=1,baz\\*\\qux.cc=2,*quux/*=3,*/*-inl.h=4";
+  int min_log_level = 0;
+  VlogInfo vlog_info(std::string(), kVModuleSwitch, &min_log_level);
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("bar.cc"));
+  EXPECT_EQ(1, vlog_info.GetVlogLevel("foo/bar.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz/grault/qux.h"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/baz/grault/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/blah/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault\\qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault//blah\\qux.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar/baz/quux.cc"));
+  EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo/bar/baz/quux/grault.cc"));
+  EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo\\bar/baz\\quux/grault.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("foo/bar/test-inl.cc"));
+  EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/test-inl.h"));
+  EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/baz/blah-inl.h"));
+}
+
+}  // namespace
+
+}  // namespace logging
diff --git a/base/win/OWNERS b/base/win/OWNERS
new file mode 100644
index 0000000..8624efe
--- /dev/null
+++ b/base/win/OWNERS
@@ -0,0 +1,3 @@
+cpu@chromium.org
+grt@chromium.org
+rvargas@chromium.org
diff --git a/base/win/dllmain.cc b/base/win/dllmain.cc
new file mode 100644
index 0000000..907c7f4
--- /dev/null
+++ b/base/win/dllmain.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Windows doesn't support pthread_key_create's destr_function, and in fact
+// it's a bit tricky to get code to run when a thread exits.  This is
+// cargo-cult magic from http://www.codeproject.com/threads/tls.asp.
+// We are trying to be compatible with both a LoadLibrary style invocation, as
+// well as static linking. This code only needs to be included if we use
+// LoadLibrary, but it hooks into the "standard" set of TLS callbacks that are
+// provided for static linking.
+
+// This code is deliberately written to match the style of calls seen in
+// base/threading/thread_local_storage_win.cc.  Please keep the two in sync if
+// coding conventions are changed.
+
+// WARNING: Do *NOT* try to include this in the construction of the base
+// library, even though it potentially drives code in
+// base/threading/thread_local_storage_win.cc.  If you do, some users will end
+// up getting duplicate definition of DllMain() in some of their later links.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there (that is, even if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_dllmain_typical_entry to prevent whole
+// program optimization from discarding the variables.
+
+#include <windows.h>
+
+#include "base/compiler_specific.h"
+#include "base/win/win_util.h"
+
+// Indicate if another service is scanning the callbacks.  When this becomes
+// set to true, then DllMain() will stop supporting the callback service. This
+// value is set to true the first time any of our callbacks are called, as that
+// shows that some other service is handling callbacks.
+static bool linker_notifications_are_active = false;
+
+// This will be our mostly no-op callback that we'll list.  We won't
+// deliberately call it, and if it is called, that means we don't need to do any
+// of the callbacks anymore.  We expect such a call to arrive via a
+// THREAD_ATTACH message, long before we'd have to perform our THREAD_DETACH
+// callbacks.
+static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved);
+
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_dllmain_typical_entry")
+
+#else  // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_dllmain_typical_entry")
+
+#endif  // _WIN64
+
+// Explicitly depend on VC\crt\src\tlssup.c variables
+// to bracket the list of TLS callbacks.
+extern "C" PIMAGE_TLS_CALLBACK __xl_a, __xl_z;
+
+// extern "C" suppresses C++ name mangling so we know the symbol names for the
+// linker /INCLUDE:symbol pragmas above.
+extern "C" {
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma data_seg(push, old_seg)
+// Use a typical possible name in the .CRT$XL? list of segments.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry;
+const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback;
+#pragma data_seg(pop, old_seg)
+
+#else  // _WIN64
+
+#pragma data_seg(push, old_seg)
+// Use a typical possible name in the .CRT$XL? list of segments.
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback;
+#pragma data_seg(pop, old_seg)
+
+#endif  // _WIN64
+}  // extern "C"
+
+// Custom crash code to get a unique entry in crash reports.
+NOINLINE static void CrashOnProcessDetach() {
+  *static_cast<volatile int*>(0) = 0x356;
+}
+
+// Make DllMain call the listed callbacks.  This way any third parties that are
+// linked in will also be called.
+BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) {
+  if (DLL_PROCESS_DETACH == reason && base::win::ShouldCrashOnProcessDetach())
+    CrashOnProcessDetach();
+
+  if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason)
+    return true;  // We won't service THREAD_ATTACH calls.
+
+  if (linker_notifications_are_active)
+    return true;  // Some other service is doing this work.
+
+  for (PIMAGE_TLS_CALLBACK* it = &__xl_a; it < &__xl_z; ++it) {
+    if (*it == NULL || *it == on_callback)
+      continue;  // Don't bother to call our own callback.
+    (*it)(h, reason, reserved);
+  }
+  return true;
+}
+
+static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved) {
+  // Do nothing.  We were just a place holder in the list used to test that we
+  // call all items.
+  // If we are called, it means that some other system is scanning the callbacks
+  // and we don't need to do so in DllMain().
+  linker_notifications_are_active = true;
+  // Note: If some other routine some how plays this same game... we could both
+  // decide not to do the scanning <sigh>, but this trick should suppress
+  // duplicate calls on Vista, where the runtime takes care of the callbacks,
+  // and allow us to do the callbacks on XP, where we are currently devoid of
+  // callbacks (due to an explicit LoadLibrary call).
+}
diff --git a/base/win/enum_variant.cc b/base/win/enum_variant.cc
new file mode 100644
index 0000000..2975560
--- /dev/null
+++ b/base/win/enum_variant.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/enum_variant.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+EnumVariant::EnumVariant(unsigned long count)
+    : items_(new VARIANT[count]),
+      count_(count),
+      current_index_(0) {
+}
+
+EnumVariant::~EnumVariant() {
+}
+
+VARIANT* EnumVariant::ItemAt(unsigned long index) {
+  DCHECK(index < count_);
+  return &items_[index];
+}
+
+ULONG STDMETHODCALLTYPE EnumVariant::AddRef() {
+  return IUnknownImpl::AddRef();
+}
+
+ULONG STDMETHODCALLTYPE EnumVariant::Release() {
+  return IUnknownImpl::Release();
+}
+
+STDMETHODIMP EnumVariant::QueryInterface(REFIID riid, void** ppv) {
+  if (riid == IID_IEnumVARIANT) {
+    *ppv = static_cast<IEnumVARIANT*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  return IUnknownImpl::QueryInterface(riid, ppv);
+}
+
+STDMETHODIMP EnumVariant::Next(ULONG requested_count,
+                               VARIANT* out_elements,
+                               ULONG* out_elements_received) {
+  unsigned long count = std::min(requested_count, count_ - current_index_);
+  for (unsigned long i = 0; i < count; ++i)
+    out_elements[i] = items_[current_index_ + i];
+  current_index_ += count;
+  *out_elements_received = count;
+
+  return (count == requested_count ? S_OK : S_FALSE);
+}
+
+STDMETHODIMP EnumVariant::Skip(ULONG skip_count) {
+  unsigned long count = skip_count;
+  if (current_index_ + count > count_)
+    count = count_ - current_index_;
+
+  current_index_ += count;
+  return (count == skip_count ? S_OK : S_FALSE);
+}
+
+STDMETHODIMP EnumVariant::Reset() {
+  current_index_ = 0;
+  return S_OK;
+}
+
+STDMETHODIMP EnumVariant::Clone(IEnumVARIANT** out_cloned_object) {
+  EnumVariant* other = new EnumVariant(count_);
+  if (count_ > 0)
+    memcpy(other->ItemAt(0), &items_[0], count_ * sizeof(VARIANT));
+  other->Skip(current_index_);
+  other->AddRef();
+  *out_cloned_object = other;
+  return S_OK;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/enum_variant.h b/base/win/enum_variant.h
new file mode 100644
index 0000000..2caaccd
--- /dev/null
+++ b/base/win/enum_variant.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_ENUM_VARIANT_H_
+#define BASE_WIN_ENUM_VARIANT_H_
+
+#include <unknwn.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/iunknown_impl.h"
+
+namespace base {
+namespace win {
+
+// A simple implementation of IEnumVARIANT.
+class BASE_EXPORT EnumVariant
+  : public IEnumVARIANT,
+    public IUnknownImpl {
+ public:
+  // The constructor allocates an array of size |count|. Then use
+  // ItemAt to set the value of each item in the array to initialize it.
+  explicit EnumVariant(unsigned long count);
+
+  // Returns a mutable pointer to the item at position |index|.
+  VARIANT* ItemAt(unsigned long index);
+
+  // IUnknown.
+  ULONG STDMETHODCALLTYPE AddRef() override;
+  ULONG STDMETHODCALLTYPE Release() override;
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+
+  // IEnumVARIANT.
+  STDMETHODIMP Next(ULONG requested_count,
+                    VARIANT* out_elements,
+                    ULONG* out_elements_received) override;
+  STDMETHODIMP Skip(ULONG skip_count) override;
+  STDMETHODIMP Reset() override;
+  STDMETHODIMP Clone(IEnumVARIANT** out_cloned_object) override;
+
+ private:
+  ~EnumVariant() override;
+
+  scoped_ptr<VARIANT[]> items_;
+  unsigned long count_;
+  unsigned long current_index_;
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_ENUM_VARIANT_H_
diff --git a/base/win/enum_variant_unittest.cc b/base/win/enum_variant_unittest.cc
new file mode 100644
index 0000000..99645a2
--- /dev/null
+++ b/base/win/enum_variant_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/enum_variant.h"
+
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+TEST(EnumVariantTest, EmptyEnumVariant) {
+  ScopedCOMInitializer com_initializer;
+
+  EnumVariant* ev = new EnumVariant(0);
+  ev->AddRef();
+
+  IUnknown* iunknown;
+  EXPECT_TRUE(SUCCEEDED(
+      ev->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&iunknown))));
+  iunknown->Release();
+
+  IEnumVARIANT* ienumvariant;
+  EXPECT_TRUE(SUCCEEDED(
+      ev->QueryInterface(IID_IEnumVARIANT,
+                         reinterpret_cast<void**>(&ienumvariant))));
+  EXPECT_EQ(ev, ienumvariant);
+  ienumvariant->Release();
+
+  VARIANT out_element;
+  ULONG out_received = 0;
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(0, out_received);
+
+  EXPECT_EQ(S_FALSE, ev->Skip(1));
+
+  EXPECT_EQ(S_OK, ev->Reset());
+
+  IEnumVARIANT* ev2 = NULL;
+  EXPECT_EQ(S_OK, ev->Clone(&ev2));
+
+  EXPECT_NE(static_cast<IEnumVARIANT*>(NULL), ev2);
+  EXPECT_NE(ev, ev2);
+  EXPECT_EQ(S_FALSE, ev2->Skip(1));
+  EXPECT_EQ(S_OK, ev2->Reset());
+
+  ULONG ev2_finalrefcount = ev2->Release();
+  EXPECT_EQ(0, ev2_finalrefcount);
+
+  ULONG ev_finalrefcount = ev->Release();
+  EXPECT_EQ(0, ev_finalrefcount);
+}
+
+TEST(EnumVariantTest, SimpleEnumVariant) {
+  ScopedCOMInitializer com_initializer;
+
+  EnumVariant* ev = new EnumVariant(3);
+  ev->AddRef();
+  ev->ItemAt(0)->vt = VT_I4;
+  ev->ItemAt(0)->lVal = 10;
+  ev->ItemAt(1)->vt = VT_I4;
+  ev->ItemAt(1)->lVal = 20;
+  ev->ItemAt(2)->vt = VT_I4;
+  ev->ItemAt(2)->lVal = 30;
+
+  // Get elements one at a time.
+  VARIANT out_element;
+  ULONG out_received = 0;
+  EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(VT_I4, out_element.vt);
+  EXPECT_EQ(10, out_element.lVal);
+  EXPECT_EQ(S_OK, ev->Skip(1));
+  EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(VT_I4, out_element.vt);
+  EXPECT_EQ(30, out_element.lVal);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+
+  // Reset and get all elements at once.
+  VARIANT out_elements[3];
+  EXPECT_EQ(S_OK, ev->Reset());
+  EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received));
+  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(VT_I4, out_elements[0].vt);
+  EXPECT_EQ(10, out_elements[0].lVal);
+  EXPECT_EQ(VT_I4, out_elements[1].vt);
+  EXPECT_EQ(20, out_elements[1].lVal);
+  EXPECT_EQ(VT_I4, out_elements[2].vt);
+  EXPECT_EQ(30, out_elements[2].lVal);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+
+  // Clone it.
+  IEnumVARIANT* ev2 = NULL;
+  EXPECT_EQ(S_OK, ev->Clone(&ev2));
+  EXPECT_TRUE(ev2 != NULL);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(S_OK, ev2->Reset());
+  EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received));
+  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(VT_I4, out_elements[0].vt);
+  EXPECT_EQ(10, out_elements[0].lVal);
+  EXPECT_EQ(VT_I4, out_elements[1].vt);
+  EXPECT_EQ(20, out_elements[1].lVal);
+  EXPECT_EQ(VT_I4, out_elements[2].vt);
+  EXPECT_EQ(30, out_elements[2].lVal);
+  EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received));
+
+  ULONG ev2_finalrefcount = ev2->Release();
+  EXPECT_EQ(0, ev2_finalrefcount);
+
+  ULONG ev_finalrefcount = ev->Release();
+  EXPECT_EQ(0, ev_finalrefcount);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_consumer.h b/base/win/event_trace_consumer.h
new file mode 100644
index 0000000..fd44894
--- /dev/null
+++ b/base/win/event_trace_consumer.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declaration of a Windows event trace consumer base class.
+#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
+#define BASE_WIN_EVENT_TRACE_CONSUMER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// This class is a base class that makes it easier to consume events
+// from realtime or file sessions. Concrete consumers need to subclass
+// a specialization of this class and override the ProcessEvent and/or
+// the ProcessBuffer methods to implement the event consumption logic.
+// Usage might look like:
+// class MyConsumer: public EtwTraceConsumerBase<MyConsumer, 1> {
+//  protected:
+//    static VOID WINAPI ProcessEvent(PEVENT_TRACE event);
+// };
+//
+// MyConsumer consumer;
+// consumer.OpenFileSession(file_path);
+// consumer.Consume();
+template <class ImplClass>
+class EtwTraceConsumerBase {
+ public:
+  // Constructs a closed consumer.
+  EtwTraceConsumerBase() {
+  }
+
+  ~EtwTraceConsumerBase() {
+    Close();
+  }
+
+  // Opens the named realtime session, which must be existent.
+  // Note: You can use OpenRealtimeSession or OpenFileSession
+  //    to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at
+  //    any one time, though only one of them may be a realtime
+  //    session.
+  HRESULT OpenRealtimeSession(const wchar_t* session_name);
+
+  // Opens the event trace log in "file_name", which must be a full or
+  // relative path to an existing event trace log file.
+  // Note: You can use OpenRealtimeSession or OpenFileSession
+  //    to open as many as kNumSessions at any one time.
+  HRESULT OpenFileSession(const wchar_t* file_name);
+
+  // Consume all open sessions from beginning to end.
+  HRESULT Consume();
+
+  // Close all open sessions.
+  HRESULT Close();
+
+ protected:
+  // Override in subclasses to handle events.
+  static void ProcessEvent(EVENT_TRACE* event) {
+  }
+  // Override in subclasses to handle buffers.
+  static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
+    return true;  // keep going
+  }
+
+ protected:
+  // Currently open sessions.
+  std::vector<TRACEHANDLE> trace_handles_;
+
+ private:
+  // These delegate to ImplClass callbacks with saner signatures.
+  static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
+    ImplClass::ProcessEvent(event);
+  }
+  static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
+    return ImplClass::ProcessBuffer(buffer);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase);
+};
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession(
+    const wchar_t* session_name) {
+  EVENT_TRACE_LOGFILE logfile = {};
+  logfile.LoggerName = const_cast<wchar_t*>(session_name);
+  logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
+  logfile.BufferCallback = &ProcessBufferCallback;
+  logfile.EventCallback = &ProcessEventCallback;
+  logfile.Context = this;
+  TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
+  if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
+    return HRESULT_FROM_WIN32(::GetLastError());
+
+  trace_handles_.push_back(trace_handle);
+  return S_OK;
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
+    const wchar_t* file_name) {
+  EVENT_TRACE_LOGFILE logfile = {};
+  logfile.LogFileName = const_cast<wchar_t*>(file_name);
+  logfile.BufferCallback = &ProcessBufferCallback;
+  logfile.EventCallback = &ProcessEventCallback;
+  logfile.Context = this;
+  TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
+  if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
+    return HRESULT_FROM_WIN32(::GetLastError());
+
+  trace_handles_.push_back(trace_handle);
+  return S_OK;
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
+  ULONG err = ::ProcessTrace(&trace_handles_[0],
+                             static_cast<ULONG>(trace_handles_.size()),
+                             NULL,
+                             NULL);
+  return HRESULT_FROM_WIN32(err);
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
+  HRESULT hr = S_OK;
+  for (size_t i = 0; i < trace_handles_.size(); ++i) {
+    if (NULL != trace_handles_[i]) {
+      ULONG ret = ::CloseTrace(trace_handles_[i]);
+      trace_handles_[i] = NULL;
+
+      if (FAILED(HRESULT_FROM_WIN32(ret)))
+        hr = HRESULT_FROM_WIN32(ret);
+    }
+  }
+  trace_handles_.clear();
+
+  return hr;
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_CONSUMER_H_
diff --git a/base/win/event_trace_consumer_unittest.cc b/base/win/event_trace_consumer_unittest.cc
new file mode 100644
index 0000000..ecbf238
--- /dev/null
+++ b/base/win/event_trace_consumer_unittest.cc
@@ -0,0 +1,366 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace consumer base class.
+#include "base/win/event_trace_consumer.h"
+
+#include <list>
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <initguid.h>  // NOLINT - has to be last
+
+namespace base {
+namespace win {
+
+namespace {
+
+typedef std::list<EVENT_TRACE> EventQueue;
+
+class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
+ public:
+  TestConsumer() {
+    sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+    ClearQueue();
+  }
+
+  ~TestConsumer() {
+    ClearQueue();
+    sank_event_.Close();
+  }
+
+  void ClearQueue() {
+    for (EventQueue::const_iterator it(events_.begin()), end(events_.end());
+         it != end; ++it) {
+      delete[] reinterpret_cast<char*>(it->MofData);
+    }
+
+    events_.clear();
+  }
+
+  static void EnqueueEvent(EVENT_TRACE* event) {
+    events_.push_back(*event);
+    EVENT_TRACE& back = events_.back();
+
+    if (event->MofData != NULL && event->MofLength != 0) {
+      back.MofData = new char[event->MofLength];
+      memcpy(back.MofData, event->MofData, event->MofLength);
+    }
+  }
+
+  static void ProcessEvent(EVENT_TRACE* event) {
+    EnqueueEvent(event);
+    ::SetEvent(sank_event_.Get());
+  }
+
+  static ScopedHandle sank_event_;
+  static EventQueue events_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestConsumer);
+};
+
+ScopedHandle TestConsumer::sank_event_;
+EventQueue TestConsumer::events_;
+
+class EtwTraceConsumerBaseTest: public testing::Test {
+ public:
+  EtwTraceConsumerBaseTest()
+      : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
+  }
+
+  void SetUp() override {
+    // Cleanup any potentially dangling sessions.
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+
+    // Allocate a new GUID for each provider test.
+    ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
+  }
+
+  void TearDown() override {
+    // Cleanup any potentially dangling sessions.
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+  }
+
+ protected:
+  GUID test_provider_;
+  std::wstring session_name_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerBaseTest, Initialize) {
+  TestConsumer consumer_;
+}
+
+TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
+  TestConsumer consumer_;
+  ASSERT_HRESULT_SUCCEEDED(
+      consumer_.OpenRealtimeSession(session_name_.c_str()));
+}
+
+TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) {
+  TestConsumer consumer_;
+  ASSERT_HRESULT_SUCCEEDED(
+      consumer_.OpenRealtimeSession(session_name_.c_str()));
+  ASSERT_HRESULT_FAILED(consumer_.Consume());
+}
+
+namespace {
+
+class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
+ public:
+  void SetUp() override {
+    EtwTraceConsumerBaseTest::SetUp();
+    ASSERT_HRESULT_SUCCEEDED(
+        consumer_.OpenRealtimeSession(session_name_.c_str()));
+  }
+
+  void TearDown() override {
+    consumer_.Close();
+    EtwTraceConsumerBaseTest::TearDown();
+  }
+
+  DWORD ConsumerThread() {
+    ::SetEvent(consumer_ready_.Get());
+    return consumer_.Consume();
+  }
+
+  static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
+    return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)->
+        ConsumerThread();
+  }
+
+  HRESULT StartConsumerThread() {
+    consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+    EXPECT_TRUE(consumer_ready_.IsValid());
+    consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, this,
+                                        0, NULL));
+    if (consumer_thread_.Get() == NULL)
+      return HRESULT_FROM_WIN32(::GetLastError());
+
+    HANDLE events[] = { consumer_ready_.Get(), consumer_thread_.Get() };
+    DWORD result = ::WaitForMultipleObjects(arraysize(events), events,
+                                            FALSE, INFINITE);
+    switch (result) {
+      case WAIT_OBJECT_0:
+        // The event was set, the consumer_ is ready.
+        return S_OK;
+      case WAIT_OBJECT_0 + 1: {
+          // The thread finished. This may race with the event, so check
+          // explicitly for the event here, before concluding there's trouble.
+          if (::WaitForSingleObject(consumer_ready_.Get(), 0) == WAIT_OBJECT_0)
+            return S_OK;
+          DWORD exit_code = 0;
+          if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code))
+            return exit_code;
+          return HRESULT_FROM_WIN32(::GetLastError());
+        }
+      default:
+        return E_UNEXPECTED;
+    }
+  }
+
+  // Waits for consumer_ thread to exit, and returns its exit code.
+  HRESULT JoinConsumerThread() {
+    if (::WaitForSingleObject(consumer_thread_.Get(), INFINITE) !=
+        WAIT_OBJECT_0) {
+      return HRESULT_FROM_WIN32(::GetLastError());
+    }
+
+    DWORD exit_code = 0;
+    if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code))
+      return exit_code;
+
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  TestConsumer consumer_;
+  ScopedHandle consumer_ready_;
+  ScopedHandle consumer_thread_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
+  EtwTraceController controller;
+  if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
+      E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  // Start the consumer_.
+  ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
+
+  // Wait around for the consumer_ thread a bit.
+  ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_.Get(), 50));
+  ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  // The consumer_ returns success on session stop.
+  ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
+}
+
+namespace {
+
+// {57E47923-A549-476f-86CA-503D57F59E62}
+DEFINE_GUID(
+    kTestEventType,
+    0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
+  EtwTraceController controller;
+  if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
+      E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(
+      test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+
+  EtwTraceProvider provider(test_provider_);
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+
+  // Start the consumer_.
+  ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
+  ASSERT_EQ(0, TestConsumer::events_.size());
+
+  EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
+  EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(TestConsumer::sank_event_.Get(), INFINITE));
+  ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
+  ASSERT_NE(0u, TestConsumer::events_.size());
+}
+
+namespace {
+
+// We run events through a file session to assert that
+// the content comes through.
+class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
+ public:
+  EtwTraceConsumerDataTest() {
+  }
+
+  void SetUp() override {
+    EtwTraceConsumerBaseTest::SetUp();
+
+    EtwTraceProperties prop;
+    EtwTraceController::Stop(session_name_.c_str(), &prop);
+
+    // Create a temp dir for this test.
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    // Construct a temp file name in our dir.
+    temp_file_ = temp_dir_.path().Append(L"test.etl");
+  }
+
+  void TearDown() override {
+    EXPECT_TRUE(base::DeleteFile(temp_file_, false));
+
+    EtwTraceConsumerBaseTest::TearDown();
+  }
+
+  HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) {
+    EtwTraceController controller;
+
+    // Set up a file session.
+    HRESULT hr = controller.StartFileSession(session_name_.c_str(),
+                                             temp_file_.value().c_str());
+    if (FAILED(hr))
+      return hr;
+
+    // Enable our provider.
+    EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(
+        test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+
+    EtwTraceProvider provider(test_provider_);
+    // Then register our provider, means we get a session handle immediately.
+    EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+    // Trace the event, it goes to the temp file.
+    EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
+    EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
+    EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
+    EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
+    EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+    return S_OK;
+  }
+
+  HRESULT ConsumeEventFromTempSession() {
+    // Now consume the event(s).
+    TestConsumer consumer_;
+    HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str());
+    if (SUCCEEDED(hr))
+      hr = consumer_.Consume();
+    consumer_.Close();
+    // And nab the result.
+    events_.swap(TestConsumer::events_);
+    return hr;
+  }
+
+  HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) {
+    base::DeleteFile(temp_file_, false);
+
+    HRESULT hr = LogEventToTempSession(header);
+    if (SUCCEEDED(hr))
+      hr = ConsumeEventFromTempSession();
+
+    if (FAILED(hr))
+      return hr;
+
+    // We should now have the event in the queue.
+    if (events_.empty())
+      return E_FAIL;
+
+    *trace = &events_.back();
+    return S_OK;
+  }
+
+  EventQueue events_;
+  ScopedTempDir temp_dir_;
+  FilePath temp_file_;
+};
+
+}  // namespace
+
+
+TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
+  EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
+
+  static const char kData[] = "This is but test data";
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData);
+  event.fields[0].Length = sizeof(kData);
+
+  PEVENT_TRACE trace = NULL;
+  HRESULT hr = RoundTripEvent(&event.header, &trace);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+  ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed";
+  ASSERT_TRUE(trace != NULL);
+  ASSERT_EQ(sizeof(kData), trace->MofLength);
+  ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData));
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_controller.cc b/base/win/event_trace_controller.cc
new file mode 100644
index 0000000..9a35a6b
--- /dev/null
+++ b/base/win/event_trace_controller.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of a Windows event trace controller class.
+#include "base/win/event_trace_controller.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+EtwTraceProperties::EtwTraceProperties() {
+  memset(buffer_, 0, sizeof(buffer_));
+  EVENT_TRACE_PROPERTIES* prop = get();
+
+  prop->Wnode.BufferSize = sizeof(buffer_);
+  prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
+  prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+  prop->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) +
+                            sizeof(wchar_t) * kMaxStringLen;
+}
+
+HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) {
+  size_t len = wcslen(logger_name) + 1;
+  if (kMaxStringLen < len)
+    return E_INVALIDARG;
+
+  memcpy(buffer_ + get()->LoggerNameOffset,
+         logger_name,
+         sizeof(wchar_t) * len);
+  return S_OK;
+}
+
+HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) {
+  size_t len = wcslen(logger_file_name) + 1;
+  if (kMaxStringLen < len)
+    return E_INVALIDARG;
+
+  memcpy(buffer_ + get()->LogFileNameOffset,
+         logger_file_name,
+         sizeof(wchar_t) * len);
+  return S_OK;
+}
+
+EtwTraceController::EtwTraceController() : session_(NULL) {
+}
+
+EtwTraceController::~EtwTraceController() {
+  Stop(NULL);
+}
+
+HRESULT EtwTraceController::Start(const wchar_t* session_name,
+    EtwTraceProperties* prop) {
+  DCHECK(NULL == session_ && session_name_.empty());
+  EtwTraceProperties ignore;
+  if (prop == NULL)
+    prop = &ignore;
+
+  HRESULT hr = Start(session_name, prop, &session_);
+  if (SUCCEEDED(hr))
+    session_name_ = session_name;
+
+  return hr;
+}
+
+HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name,
+    const wchar_t* logfile_path, bool realtime) {
+  DCHECK(NULL == session_ && session_name_.empty());
+
+  EtwTraceProperties prop;
+  prop.SetLoggerFileName(logfile_path);
+  EVENT_TRACE_PROPERTIES& p = *prop.get();
+  p.Wnode.ClientContext = 1;  // QPC timer accuracy.
+  p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;  // Sequential log.
+  if (realtime)
+    p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
+
+  p.MaximumFileSize = 100;  // 100M file size.
+  p.FlushTimer = 30;  // 30 seconds flush lag.
+  return Start(session_name, &prop);
+}
+
+HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name,
+    size_t buffer_size) {
+  DCHECK(NULL == session_ && session_name_.empty());
+  EtwTraceProperties prop;
+  EVENT_TRACE_PROPERTIES& p = *prop.get();
+  p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY;
+  p.FlushTimer = 1;  // flush every second.
+  p.BufferSize = 16;  // 16 K buffers.
+  p.LogFileNameOffset = 0;
+  return Start(session_name, &prop);
+}
+
+HRESULT EtwTraceController::EnableProvider(REFGUID provider, UCHAR level,
+    ULONG flags) {
+  ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_);
+  return HRESULT_FROM_WIN32(error);
+}
+
+HRESULT EtwTraceController::DisableProvider(REFGUID provider) {
+  ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_);
+  return HRESULT_FROM_WIN32(error);
+}
+
+HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) {
+  EtwTraceProperties ignore;
+  if (properties == NULL)
+    properties = &ignore;
+
+  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
+    EVENT_TRACE_CONTROL_STOP);
+  if (ERROR_SUCCESS != error)
+    return HRESULT_FROM_WIN32(error);
+
+  session_ = NULL;
+  session_name_.clear();
+  return S_OK;
+}
+
+HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) {
+  EtwTraceProperties ignore;
+  if (properties == NULL)
+    properties = &ignore;
+
+  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
+                               EVENT_TRACE_CONTROL_FLUSH);
+  if (ERROR_SUCCESS != error)
+    return HRESULT_FROM_WIN32(error);
+
+  return S_OK;
+}
+
+HRESULT EtwTraceController::Start(const wchar_t* session_name,
+    EtwTraceProperties* properties, TRACEHANDLE* session_handle) {
+  DCHECK(properties != NULL);
+  ULONG err = ::StartTrace(session_handle, session_name, properties->get());
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Query(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_QUERY);
+  return HRESULT_FROM_WIN32(err);
+};
+
+HRESULT EtwTraceController::Update(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_UPDATE);
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Stop(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_STOP);
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Flush(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_FLUSH);
+  return HRESULT_FROM_WIN32(err);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_controller.h b/base/win/event_trace_controller.h
new file mode 100644
index 0000000..69e755b
--- /dev/null
+++ b/base/win/event_trace_controller.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declaration of a Windows event trace controller class.
+// The controller takes care of creating and manipulating event trace
+// sessions.
+//
+// Event tracing for Windows is a system-provided service that provides
+// logging control and high-performance transport for generic, binary trace
+// events. Event trace providers register with the system by their name,
+// which is a GUID, and can from that point forward receive callbacks that
+// start or end tracing and that change their trace level and enable mask.
+//
+// A trace controller can create an event tracing session, which either
+// sends events to a binary file, or to a realtime consumer, or both.
+//
+// A trace consumer consumes events from zero or one realtime session,
+// as well as potentially from multiple binary trace files.
+#ifndef BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+#define BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Utility class to make it easier to work with EVENT_TRACE_PROPERTIES.
+// The EVENT_TRACE_PROPERTIES structure contains information about an
+// event tracing session.
+class BASE_EXPORT EtwTraceProperties {
+ public:
+  EtwTraceProperties();
+
+  EVENT_TRACE_PROPERTIES* get() {
+    return &properties_;
+  }
+
+  const EVENT_TRACE_PROPERTIES* get() const {
+    return reinterpret_cast<const EVENT_TRACE_PROPERTIES*>(&properties_);
+  }
+
+  const wchar_t* GetLoggerName() const {
+    return reinterpret_cast<const wchar_t *>(buffer_ + get()->LoggerNameOffset);
+  }
+
+  // Copies logger_name to the properties structure.
+  HRESULT SetLoggerName(const wchar_t* logger_name);
+  const wchar_t* GetLoggerFileName() const {
+    return reinterpret_cast<const wchar_t*>(buffer_ + get()->LogFileNameOffset);
+  }
+
+  // Copies logger_file_name to the properties structure.
+  HRESULT SetLoggerFileName(const wchar_t* logger_file_name);
+
+  // Max string len for name and session name is 1024 per documentation.
+  static const size_t kMaxStringLen = 1024;
+  // Properties buffer allocates space for header and for
+  // max length for name and session name.
+  static const size_t kBufSize = sizeof(EVENT_TRACE_PROPERTIES)
+      + 2 * sizeof(wchar_t) * (kMaxStringLen);
+
+ private:
+  // The EVENT_TRACE_PROPERTIES structure needs to be overlaid on a
+  // larger buffer to allow storing the logger name and logger file
+  // name contiguously with the structure.
+  union {
+   public:
+    // Our properties header.
+    EVENT_TRACE_PROPERTIES properties_;
+    // The actual size of the buffer is forced by this member.
+    char buffer_[kBufSize];
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceProperties);
+};
+
+// This class implements an ETW controller, which knows how to start and
+// stop event tracing sessions, as well as controlling ETW provider
+// log levels and enable bit masks under the session.
+class BASE_EXPORT EtwTraceController {
+ public:
+  EtwTraceController();
+  ~EtwTraceController();
+
+  // Start a session with given name and properties.
+  HRESULT Start(const wchar_t* session_name, EtwTraceProperties* prop);
+
+  // Starts a session tracing to a file with some default properties.
+  HRESULT StartFileSession(const wchar_t* session_name,
+                           const wchar_t* logfile_path,
+                           bool realtime = false);
+
+  // Starts a realtime session with some default properties.
+  HRESULT StartRealtimeSession(const wchar_t* session_name,
+                               size_t buffer_size);
+
+  // Enables "provider" at "level" for this session.
+  // This will cause all providers registered with the GUID
+  // "provider" to start tracing at the new level, systemwide.
+  HRESULT EnableProvider(const GUID& provider, UCHAR level,
+                         ULONG flags = 0xFFFFFFFF);
+  // Disables "provider".
+  HRESULT DisableProvider(const GUID& provider);
+
+  // Stops our session and retrieve the new properties of the session,
+  // properties may be NULL.
+  HRESULT Stop(EtwTraceProperties* properties);
+
+  // Flushes our session and retrieve the current properties,
+  // properties may be NULL.
+  HRESULT Flush(EtwTraceProperties* properties);
+
+  // Static utility functions for controlling
+  // sessions we don't necessarily own.
+  static HRESULT Start(const wchar_t* session_name,
+                       EtwTraceProperties* properties,
+                       TRACEHANDLE* session_handle);
+
+  static HRESULT Query(const wchar_t* session_name,
+                       EtwTraceProperties* properties);
+
+  static HRESULT Update(const wchar_t* session_name,
+                        EtwTraceProperties* properties);
+
+  static HRESULT Stop(const wchar_t* session_name,
+                      EtwTraceProperties* properties);
+  static HRESULT Flush(const wchar_t* session_name,
+                       EtwTraceProperties* properties);
+
+  // Accessors.
+  TRACEHANDLE session() const { return session_; }
+  const wchar_t* session_name() const { return session_name_.c_str(); }
+
+ private:
+  std::wstring session_name_;
+  TRACEHANDLE session_;
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceController);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_CONTROLLER_H_
diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc
new file mode 100644
index 0000000..a2cd81c
--- /dev/null
+++ b/base/win/event_trace_controller_unittest.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace controller.
+
+#include <objbase.h>
+#include <initguid.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+DEFINE_GUID(kGuidNull,
+    0x0000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0);
+
+const ULONG kTestProviderFlags = 0xCAFEBABE;
+
+class TestingProvider: public EtwTraceProvider {
+ public:
+  explicit TestingProvider(const GUID& provider_name)
+      : EtwTraceProvider(provider_name) {
+    callback_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+  }
+
+  void WaitForCallback() {
+    ::WaitForSingleObject(callback_event_.Get(), INFINITE);
+    ::ResetEvent(callback_event_.Get());
+  }
+
+ private:
+  void OnEventsEnabled() override { ::SetEvent(callback_event_.Get()); }
+  void PostEventsDisabled() override { ::SetEvent(callback_event_.Get()); }
+
+  ScopedHandle callback_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingProvider);
+};
+
+}  // namespace
+
+TEST(EtwTracePropertiesTest, Initialization) {
+  EtwTraceProperties prop;
+
+  EVENT_TRACE_PROPERTIES* p = prop.get();
+  EXPECT_NE(0u, p->Wnode.BufferSize);
+  EXPECT_EQ(0u, p->Wnode.ProviderId);
+  EXPECT_EQ(0u, p->Wnode.HistoricalContext);
+
+  EXPECT_TRUE(kGuidNull == p->Wnode.Guid);
+  EXPECT_EQ(0, p->Wnode.ClientContext);
+  EXPECT_EQ(WNODE_FLAG_TRACED_GUID, p->Wnode.Flags);
+
+  EXPECT_EQ(0, p->BufferSize);
+  EXPECT_EQ(0, p->MinimumBuffers);
+  EXPECT_EQ(0, p->MaximumBuffers);
+  EXPECT_EQ(0, p->MaximumFileSize);
+  EXPECT_EQ(0, p->LogFileMode);
+  EXPECT_EQ(0, p->FlushTimer);
+  EXPECT_EQ(0, p->EnableFlags);
+  EXPECT_EQ(0, p->AgeLimit);
+
+  EXPECT_EQ(0, p->NumberOfBuffers);
+  EXPECT_EQ(0, p->FreeBuffers);
+  EXPECT_EQ(0, p->EventsLost);
+  EXPECT_EQ(0, p->BuffersWritten);
+  EXPECT_EQ(0, p->LogBuffersLost);
+  EXPECT_EQ(0, p->RealTimeBuffersLost);
+  EXPECT_EQ(0, p->LoggerThreadId);
+  EXPECT_NE(0u, p->LogFileNameOffset);
+  EXPECT_NE(0u, p->LoggerNameOffset);
+}
+
+TEST(EtwTracePropertiesTest, Strings) {
+  EtwTraceProperties prop;
+
+  ASSERT_STREQ(L"", prop.GetLoggerFileName());
+  ASSERT_STREQ(L"", prop.GetLoggerName());
+
+  std::wstring name(1023, L'A');
+  ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(name.c_str()));
+  ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerName(name.c_str()));
+  ASSERT_STREQ(name.c_str(), prop.GetLoggerFileName());
+  ASSERT_STREQ(name.c_str(), prop.GetLoggerName());
+
+  std::wstring name2(1024, L'A');
+  ASSERT_HRESULT_FAILED(prop.SetLoggerFileName(name2.c_str()));
+  ASSERT_HRESULT_FAILED(prop.SetLoggerName(name2.c_str()));
+}
+
+namespace {
+
+class EtwTraceControllerTest : public testing::Test {
+ public:
+  EtwTraceControllerTest()
+      : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
+  }
+
+  void SetUp() override {
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+
+    // Allocate a new provider name GUID for each test.
+    ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
+  }
+
+  void TearDown() override {
+    EtwTraceProperties prop;
+    EtwTraceController::Stop(session_name_.c_str(), &prop);
+  }
+
+ protected:
+  GUID test_provider_;
+  std::wstring session_name_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceControllerTest, Initialize) {
+  EtwTraceController controller;
+
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+}
+
+
+TEST_F(EtwTraceControllerTest, StartRealTimeSession) {
+  EtwTraceController controller;
+
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_STREQ(session_name_.c_str(), controller.session_name());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+}
+
+TEST_F(EtwTraceControllerTest, StartFileSession) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath temp;
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp));
+
+  EtwTraceController controller;
+  HRESULT hr = controller.StartFileSession(session_name_.c_str(),
+                                           temp.value().c_str());
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    base::DeleteFile(temp, false);
+    return;
+  }
+
+  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_STREQ(session_name_.c_str(), controller.session_name());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+  base::DeleteFile(temp, false);
+}
+
+TEST_F(EtwTraceControllerTest, EnableDisable) {
+  TestingProvider provider(test_provider_);
+
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_EQ(NULL, provider.session_handle());
+
+  EtwTraceController controller;
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+                           TRACE_LEVEL_VERBOSE, kTestProviderFlags));
+
+  provider.WaitForCallback();
+
+  EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
+  EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
+
+  provider.WaitForCallback();
+
+  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0, provider.enable_flags());
+
+  EXPECT_EQ(ERROR_SUCCESS, provider.Unregister());
+
+  // Enable the provider again, before registering.
+  EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+                           TRACE_LEVEL_VERBOSE, kTestProviderFlags));
+
+  // Register the provider again, the settings above
+  // should take immediate effect.
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+
+  EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
+  EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  provider.WaitForCallback();
+
+  // Session should have wound down.
+  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0, provider.enable_flags());
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_provider.cc b/base/win/event_trace_provider.cc
new file mode 100644
index 0000000..8fcf67d
--- /dev/null
+++ b/base/win/event_trace_provider.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#include "base/win/event_trace_provider.h"
+#include <windows.h>
+#include <cguid.h>
+
+namespace base {
+namespace win {
+
+TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = {
+  &GUID_NULL,
+  NULL
+};
+
+EtwTraceProvider::EtwTraceProvider(const GUID& provider_name)
+    : provider_name_(provider_name), registration_handle_(NULL),
+      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
+}
+
+EtwTraceProvider::EtwTraceProvider()
+    : provider_name_(GUID_NULL), registration_handle_(NULL),
+      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
+}
+
+EtwTraceProvider::~EtwTraceProvider() {
+  Unregister();
+}
+
+ULONG EtwTraceProvider::EnableEvents(void* buffer) {
+  session_handle_ = ::GetTraceLoggerHandle(buffer);
+  if (NULL == session_handle_) {
+    return ::GetLastError();
+  }
+
+  enable_flags_ = ::GetTraceEnableFlags(session_handle_);
+  enable_level_ = ::GetTraceEnableLevel(session_handle_);
+
+  // Give subclasses a chance to digest the state change.
+  OnEventsEnabled();
+
+  return ERROR_SUCCESS;
+}
+
+ULONG EtwTraceProvider::DisableEvents() {
+  // Give subclasses a chance to digest the state change.
+  OnEventsDisabled();
+
+  enable_level_ = 0;
+  enable_flags_ = 0;
+  session_handle_ = NULL;
+
+  PostEventsDisabled();
+
+  return ERROR_SUCCESS;
+}
+
+ULONG EtwTraceProvider::Callback(WMIDPREQUESTCODE request, void* buffer) {
+  switch (request) {
+    case WMI_ENABLE_EVENTS:
+      return EnableEvents(buffer);
+    case WMI_DISABLE_EVENTS:
+      return DisableEvents();
+    default:
+      return ERROR_INVALID_PARAMETER;
+  }
+  // Not reached.
+}
+
+ULONG WINAPI EtwTraceProvider::ControlCallback(WMIDPREQUESTCODE request,
+    void* context, ULONG *reserved, void* buffer) {
+  EtwTraceProvider *provider = reinterpret_cast<EtwTraceProvider*>(context);
+
+  return provider->Callback(request, buffer);
+}
+
+ULONG EtwTraceProvider::Register() {
+  if (provider_name_ == GUID_NULL)
+    return ERROR_INVALID_NAME;
+
+  return ::RegisterTraceGuids(ControlCallback, this, &provider_name_,
+      1, &obligatory_guid_registration_, NULL, NULL, &registration_handle_);
+}
+
+ULONG EtwTraceProvider::Unregister() {
+  // If a session is active, notify subclasses that it's going away.
+  if (session_handle_ != NULL)
+    DisableEvents();
+
+  ULONG ret = ::UnregisterTraceGuids(registration_handle_);
+
+  registration_handle_ = NULL;
+
+  return ret;
+}
+
+ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
+    EtwEventType type, EtwEventLevel level, const char *message) {
+  if (NULL == session_handle_ || enable_level_ < level)
+    return ERROR_SUCCESS;  // No one listening.
+
+  EtwMofEvent<1> event(event_class, type, level);
+
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
+  event.fields[0].Length = message ?
+      static_cast<ULONG>(sizeof(message[0]) * (1 + strlen(message))) : 0;
+
+  return ::TraceEvent(session_handle_, &event.header);
+}
+
+ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
+    EtwEventType type, EtwEventLevel level, const wchar_t *message) {
+  if (NULL == session_handle_ || enable_level_ < level)
+    return ERROR_SUCCESS;  // No one listening.
+
+  EtwMofEvent<1> event(event_class, type, level);
+
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
+  event.fields[0].Length = message ?
+      static_cast<ULONG>(sizeof(message[0]) * (1 + wcslen(message))) : 0;
+
+  return ::TraceEvent(session_handle_, &event.header);
+}
+
+ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) {
+  if (enable_level_ < event->Class.Level)
+    return ERROR_SUCCESS;
+
+  return ::TraceEvent(session_handle_, event);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_provider.h b/base/win/event_trace_provider.h
new file mode 100644
index 0000000..7907347
--- /dev/null
+++ b/base/win/event_trace_provider.h
@@ -0,0 +1,180 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Declaration of a Windows event trace provider class, to allow using
+// Windows Event Tracing for logging transport and control.
+#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
+#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+typedef GUID EtwEventClass;
+typedef UCHAR EtwEventType;
+typedef UCHAR EtwEventLevel;
+typedef USHORT EtwEventVersion;
+typedef ULONG EtwEventFlags;
+
+// Base class is a POD for correctness.
+template <size_t N> struct EtwMofEventBase {
+  EVENT_TRACE_HEADER header;
+  MOF_FIELD fields[N];
+};
+
+// Utility class to auto-initialize event trace header structures.
+template <size_t N> class EtwMofEvent: public EtwMofEventBase<N> {
+ public:
+  typedef EtwMofEventBase<N> Super;
+
+  // Clang and the C++ standard don't allow unqualified lookup into dependent
+  // bases, hence these using decls to explicitly pull the names out.
+  using EtwMofEventBase<N>::header;
+  using EtwMofEventBase<N>::fields;
+
+  EtwMofEvent() {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+  }
+
+  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
+              EtwEventLevel level) {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+    header.Size = sizeof(Super);
+    header.Guid = event_class;
+    header.Class.Type = type;
+    header.Class.Level = level;
+    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
+  }
+
+  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
+              EtwEventVersion version, EtwEventLevel level) {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+    header.Size = sizeof(Super);
+    header.Guid = event_class;
+    header.Class.Type = type;
+    header.Class.Version = version;
+    header.Class.Level = level;
+    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
+  }
+
+  void SetField(int field, size_t size, const void *data) {
+    // DCHECK(field < N);
+    if ((field < N) && (size <= kuint32max)) {
+      fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
+      fields[field].Length = static_cast<ULONG>(size);
+    }
+  }
+
+  EVENT_TRACE_HEADER* get() { return& header; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EtwMofEvent);
+};
+
+// Trace provider with Event Tracing for Windows. The trace provider
+// registers with ETW by its name which is a GUID. ETW calls back to
+// the object whenever the trace level or enable flags for this provider
+// name changes.
+// Users of this class can test whether logging is currently enabled at
+// a particular trace level, and whether particular enable flags are set,
+// before other resources are consumed to generate and issue the log
+// messages themselves.
+class BASE_EXPORT EtwTraceProvider {
+ public:
+  // Creates an event trace provider identified by provider_name, which
+  // will be the name registered with Event Tracing for Windows (ETW).
+  explicit EtwTraceProvider(const GUID& provider_name);
+
+  // Creates an unnamed event trace provider, the provider must be given
+  // a name before registration.
+  EtwTraceProvider();
+  virtual ~EtwTraceProvider();
+
+  // Registers the trace provider with Event Tracing for Windows.
+  // Note: from this point forward ETW may call the provider's control
+  //    callback. If the provider's name is enabled in some trace session
+  //    already, the callback may occur recursively from this call, so
+  //    call this only when you're ready to handle callbacks.
+  ULONG Register();
+  // Unregisters the trace provider with ETW.
+  ULONG Unregister();
+
+  // Accessors.
+  void set_provider_name(const GUID& provider_name) {
+    provider_name_ = provider_name;
+  }
+  const GUID& provider_name() const { return provider_name_; }
+  TRACEHANDLE registration_handle() const { return registration_handle_; }
+  TRACEHANDLE session_handle() const { return session_handle_; }
+  EtwEventFlags enable_flags() const { return enable_flags_; }
+  EtwEventLevel enable_level() const { return enable_level_; }
+
+  // Returns true iff logging should be performed for "level" and "flags".
+  // Note: flags is treated as a bitmask, and should normally have a single
+  //      bit set, to test whether to log for a particular sub "facility".
+  bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
+    return NULL != session_handle_ && level >= enable_level_ &&
+        (0 != (flags & enable_flags_));
+  }
+
+  // Simple wrappers to log Unicode and ANSI strings.
+  // Do nothing if !ShouldLog(level, 0xFFFFFFFF).
+  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
+            EtwEventLevel level, const char *message);
+  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
+            EtwEventLevel level, const wchar_t *message);
+
+  // Log the provided event.
+  ULONG Log(EVENT_TRACE_HEADER* event);
+
+ protected:
+  // Called after events have been enabled, override in subclasses
+  // to set up state or log at the start of a session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void OnEventsEnabled() {}
+
+  // Called just before events are disabled, override in subclasses
+  // to tear down state or log at the end of a session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void OnEventsDisabled() {}
+
+  // Called just after events have been disabled, override in subclasses
+  // to tear down state at the end of a session. At this point it's
+  // to late to log anything to the session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void PostEventsDisabled() {}
+
+ private:
+  ULONG EnableEvents(PVOID buffer);
+  ULONG DisableEvents();
+  ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
+  static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request, PVOID context,
+                                      ULONG *reserved, PVOID buffer);
+
+  GUID provider_name_;
+  TRACEHANDLE registration_handle_;
+  TRACEHANDLE session_handle_;
+  EtwEventFlags enable_flags_;
+  EtwEventLevel enable_level_;
+
+  // We don't use this, but on XP we're obliged to pass one in to
+  // RegisterTraceGuids. Non-const, because that's how the API needs it.
+  static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_PROVIDER_H_
diff --git a/base/win/event_trace_provider_unittest.cc b/base/win/event_trace_provider_unittest.cc
new file mode 100644
index 0000000..55b5ae6
--- /dev/null
+++ b/base/win/event_trace_provider_unittest.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace provider.
+#include "base/win/event_trace_provider.h"
+#include <new>
+#include "testing/gtest/include/gtest/gtest.h"
+#include <initguid.h>  // NOLINT - has to be last
+
+namespace {
+
+using base::win::EtwTraceProvider;
+using base::win::EtwMofEvent;
+
+// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
+DEFINE_GUID(kTestProvider,
+  0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
+
+// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
+DEFINE_GUID(kTestEventClass,
+  0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
+
+}  // namespace
+
+TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) {
+  // Because the trace provider is used in logging, it's important that
+  // it be possible to use static provider instances without regard to
+  // whether they've been constructed or destructed.
+  // The interface of the class is designed to tolerate this usage.
+  char buf[sizeof(EtwTraceProvider)] = {0};
+  EtwTraceProvider& provider = reinterpret_cast<EtwTraceProvider&>(buf);
+
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
+
+  // We expect these not to crash.
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo");
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo");
+
+  EtwMofEvent<1> dummy(kTestEventClass, 0, TRACE_LEVEL_FATAL);
+  DWORD data = 0;
+  dummy.SetField(0, sizeof(data), &data);
+  provider.Log(dummy.get());
+
+  // Placement-new the provider into our buffer.
+  new (buf) EtwTraceProvider(kTestProvider);
+
+  // Registration is now safe.
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+
+  // Destruct the instance, this should unregister it.
+  provider.EtwTraceProvider::~EtwTraceProvider();
+
+  // And post-destruction, all of the above should still be safe.
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
+
+  // We expect these not to crash.
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo");
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo");
+  provider.Log(dummy.get());
+}
+
+TEST(EtwTraceProviderTest, Initialize) {
+  EtwTraceProvider provider(kTestProvider);
+
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+}
+
+TEST(EtwTraceProviderTest, Register) {
+  EtwTraceProvider provider(kTestProvider);
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_NE(NULL, provider.registration_handle());
+  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(NULL, provider.registration_handle());
+}
+
+TEST(EtwTraceProviderTest, RegisterWithNoNameFails) {
+  EtwTraceProvider provider;
+
+  EXPECT_TRUE(provider.Register() != ERROR_SUCCESS);
+}
+
+TEST(EtwTraceProviderTest, Enable) {
+  EtwTraceProvider provider(kTestProvider);
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_NE(NULL, provider.registration_handle());
+
+  // No session so far.
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(NULL, provider.registration_handle());
+}
diff --git a/base/win/i18n.cc b/base/win/i18n.cc
new file mode 100644
index 0000000..9e523a1
--- /dev/null
+++ b/base/win/i18n.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/i18n.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace {
+
+// Keep this enum in sync with kLanguageFunctionNames.
+enum LanguageFunction {
+  SYSTEM_LANGUAGES,
+  USER_LANGUAGES,
+  PROCESS_LANGUAGES,
+  THREAD_LANGUAGES,
+  NUM_FUNCTIONS
+};
+
+const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages";
+const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages";
+const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages";
+const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages";
+
+// Keep this array in sync with enum LanguageFunction.
+const char *const kLanguageFunctionNames[] = {
+  &kSystemLanguagesFunctionName[0],
+  &kUserLanguagesFunctionName[0],
+  &kProcessLanguagesFunctionName[0],
+  &kThreadLanguagesFunctionName[0]
+};
+
+COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
+               language_function_enum_and_names_out_of_sync);
+
+// Calls one of the MUI Get*PreferredUILanguages functions, placing the result
+// in |languages|.  |function| identifies the function to call and |flags| is
+// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or
+// MUI_LANGUAGE_NAME).  Returns true if at least one language is placed in
+// |languages|.
+bool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags,
+                                   std::vector<wchar_t>* languages) {
+  DCHECK(0 <= function && NUM_FUNCTIONS > function);
+  DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME)));
+  DCHECK(languages);
+
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  if (NULL != kernel32) {
+    typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)(
+        DWORD, PULONG, PZZWSTR, PULONG);
+    GetPreferredUILanguages_Fn get_preferred_ui_languages =
+        reinterpret_cast<GetPreferredUILanguages_Fn>(
+            GetProcAddress(kernel32, kLanguageFunctionNames[function]));
+    if (NULL != get_preferred_ui_languages) {
+      const ULONG call_flags = flags | MUI_LANGUAGE_NAME;
+      ULONG language_count = 0;
+      ULONG buffer_length = 0;
+      if (get_preferred_ui_languages(call_flags, &language_count, NULL,
+                                     &buffer_length) &&
+          0 != buffer_length) {
+        languages->resize(buffer_length);
+        if (get_preferred_ui_languages(call_flags, &language_count,
+                                       &(*languages)[0], &buffer_length) &&
+            0 != language_count) {
+          DCHECK(languages->size() == buffer_length);
+          return true;
+        } else {
+          DPCHECK(0 == language_count)
+              << "Failed getting preferred UI languages.";
+        }
+      } else {
+        DPCHECK(0 == buffer_length)
+            << "Failed getting size of preferred UI languages.";
+      }
+    } else {
+      DVLOG(2) << "MUI not available.";
+    }
+  } else {
+    NOTREACHED() << "kernel32.dll not found.";
+  }
+
+  return false;
+}
+
+bool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) {
+  DCHECK(language);
+
+  LANGID lang_id = ::GetUserDefaultUILanguage();
+  if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) {
+    const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT);
+    // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9
+    wchar_t result_buffer[9];
+    int result_length =
+        GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &result_buffer[0],
+                      arraysize(result_buffer));
+    DPCHECK(0 != result_length) << "Failed getting language id";
+    if (1 < result_length) {
+      language->assign(&result_buffer[0], result_length - 1);
+      region->clear();
+      if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) {
+        result_length =
+            GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &result_buffer[0],
+                          arraysize(result_buffer));
+        DPCHECK(0 != result_length) << "Failed getting region id";
+        if (1 < result_length)
+          region->assign(&result_buffer[0], result_length - 1);
+      }
+      return true;
+    }
+  } else {
+    // This is entirely unexpected on pre-Vista, which is the only time we
+    // should try GetUserDefaultUILanguage anyway.
+    NOTREACHED() << "Cannot determine language for a supplemental locale.";
+  }
+  return false;
+}
+
+bool GetPreferredUILanguageList(LanguageFunction function, ULONG flags,
+                                std::vector<std::wstring>* languages) {
+  std::vector<wchar_t> buffer;
+  std::wstring language;
+  std::wstring region;
+
+  if (GetMUIPreferredUILanguageList(function, flags, &buffer)) {
+    std::vector<wchar_t>::const_iterator scan = buffer.begin();
+    language.assign(&*scan);
+    while (!language.empty()) {
+      languages->push_back(language);
+      scan += language.size() + 1;
+      language.assign(&*scan);
+    }
+  } else if (GetUserDefaultUILanguage(&language, &region)) {
+    // Mimic the MUI behavior of putting the neutral version of the lang after
+    // the regional one (e.g., "fr-CA, fr").
+    if (!region.empty())
+      languages->push_back(std::wstring(language)
+                               .append(1, L'-')
+                               .append(region));
+    languages->push_back(language);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+namespace win {
+namespace i18n {
+
+bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
+  DCHECK(languages);
+  return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages);
+}
+
+bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) {
+  DCHECK(languages);
+  return GetPreferredUILanguageList(
+      THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK,
+      languages);
+}
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
diff --git a/base/win/i18n.h b/base/win/i18n.h
new file mode 100644
index 0000000..c0379c1
--- /dev/null
+++ b/base/win/i18n.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_I18N_H_
+#define BASE_WIN_I18N_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Adds to |languages| the list of user preferred UI languages from MUI, if
+// available, falling-back on the user default UI language otherwise.  Returns
+// true if at least one language is added.
+BASE_EXPORT bool GetUserPreferredUILanguageList(
+    std::vector<std::wstring>* languages);
+
+// Adds to |languages| the list of thread, process, user, and system preferred
+// UI languages from MUI, if available, falling-back on the user default UI
+// language otherwise.  Returns true if at least one language is added.
+BASE_EXPORT bool GetThreadPreferredUILanguageList(
+    std::vector<std::wstring>* languages);
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_I18N_H_
diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc
new file mode 100644
index 0000000..781fc39
--- /dev/null
+++ b/base/win/i18n_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for Windows internationalization funcs.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/win/i18n.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Tests that at least one user preferred UI language can be obtained.
+TEST(I18NTest, GetUserPreferredUILanguageList) {
+  std::vector<std::wstring> languages;
+  EXPECT_TRUE(GetUserPreferredUILanguageList(&languages));
+  EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+            languages.size());
+  for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+          end = languages.end(); scan != end; ++scan) {
+    EXPECT_FALSE((*scan).empty());
+  }
+}
+
+// Tests that at least one thread preferred UI language can be obtained.
+TEST(I18NTest, GetThreadPreferredUILanguageList) {
+  std::vector<std::wstring> languages;
+  EXPECT_TRUE(GetThreadPreferredUILanguageList(&languages));
+  EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+            languages.size());
+  for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+          end = languages.end(); scan != end; ++scan) {
+    EXPECT_FALSE((*scan).empty());
+  }
+}
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc
new file mode 100644
index 0000000..13acd65
--- /dev/null
+++ b/base/win/iat_patch_function.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/iat_patch_function.h"
+
+#include "base/logging.h"
+#include "base/win/pe_image.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct InterceptFunctionInformation {
+  bool finished_operation;
+  const char* imported_from_module;
+  const char* function_name;
+  void* new_function;
+  void** old_function;
+  IMAGE_THUNK_DATA** iat_thunk;
+  DWORD return_code;
+};
+
+void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) {
+  if (NULL == iat_thunk) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  // Works around the 64 bit portability warning:
+  // The Function member inside IMAGE_THUNK_DATA is really a pointer
+  // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
+  // or IMAGE_THUNK_DATA64 for correct pointer size.
+  union FunctionThunk {
+    IMAGE_THUNK_DATA thunk;
+    void* pointer;
+  } iat_function;
+
+  iat_function.thunk = *iat_thunk;
+  return iat_function.pointer;
+}
+
+bool InterceptEnumCallback(const base::win::PEImage& image, const char* module,
+                           DWORD ordinal, const char* name, DWORD hint,
+                           IMAGE_THUNK_DATA* iat, void* cookie) {
+  InterceptFunctionInformation* intercept_information =
+    reinterpret_cast<InterceptFunctionInformation*>(cookie);
+
+  if (NULL == intercept_information) {
+    NOTREACHED();
+    return false;
+  }
+
+  DCHECK(module);
+
+  if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) &&
+     (NULL != name) &&
+     (0 == lstrcmpiA(name, intercept_information->function_name))) {
+    // Save the old pointer.
+    if (NULL != intercept_information->old_function) {
+      *(intercept_information->old_function) = GetIATFunction(iat);
+    }
+
+    if (NULL != intercept_information->iat_thunk) {
+      *(intercept_information->iat_thunk) = iat;
+    }
+
+    // portability check
+    COMPILE_ASSERT(sizeof(iat->u1.Function) ==
+      sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
+
+    // Patch the function.
+    intercept_information->return_code =
+      ModifyCode(&(iat->u1.Function),
+                 &(intercept_information->new_function),
+                 sizeof(intercept_information->new_function));
+
+    // Terminate further enumeration.
+    intercept_information->finished_operation = true;
+    return false;
+  }
+
+  return true;
+}
+
+// Helper to intercept a function in an import table of a specific
+// module.
+//
+// Arguments:
+// module_handle          Module to be intercepted
+// imported_from_module   Module that exports the symbol
+// function_name          Name of the API to be intercepted
+// new_function           Interceptor function
+// old_function           Receives the original function pointer
+// iat_thunk              Receives pointer to IAT_THUNK_DATA
+//                        for the API from the import table.
+//
+// Returns: Returns NO_ERROR on success or Windows error code
+//          as defined in winerror.h
+DWORD InterceptImportedFunction(HMODULE module_handle,
+                                const char* imported_from_module,
+                                const char* function_name, void* new_function,
+                                void** old_function,
+                                IMAGE_THUNK_DATA** iat_thunk) {
+  if ((NULL == module_handle) || (NULL == imported_from_module) ||
+     (NULL == function_name) || (NULL == new_function)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  base::win::PEImage target_image(module_handle);
+  if (!target_image.VerifyMagic()) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  InterceptFunctionInformation intercept_information = {
+    false,
+    imported_from_module,
+    function_name,
+    new_function,
+    old_function,
+    iat_thunk,
+    ERROR_GEN_FAILURE};
+
+  // First go through the IAT. If we don't find the import we are looking
+  // for in IAT, search delay import table.
+  target_image.EnumAllImports(InterceptEnumCallback, &intercept_information);
+  if (!intercept_information.finished_operation) {
+    target_image.EnumAllDelayImports(InterceptEnumCallback,
+                                     &intercept_information);
+  }
+
+  return intercept_information.return_code;
+}
+
+// Restore intercepted IAT entry with the original function.
+//
+// Arguments:
+// intercept_function     Interceptor function
+// original_function      Receives the original function pointer
+//
+// Returns: Returns NO_ERROR on success or Windows error code
+//          as defined in winerror.h
+DWORD RestoreImportedFunction(void* intercept_function,
+                              void* original_function,
+                              IMAGE_THUNK_DATA* iat_thunk) {
+  if ((NULL == intercept_function) || (NULL == original_function) ||
+      (NULL == iat_thunk)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  if (GetIATFunction(iat_thunk) != intercept_function) {
+    // Check if someone else has intercepted on top of us.
+    // We cannot unpatch in this case, just raise a red flag.
+    NOTREACHED();
+    return ERROR_INVALID_FUNCTION;
+  }
+
+  return ModifyCode(&(iat_thunk->u1.Function),
+                    &original_function,
+                    sizeof(original_function));
+}
+
+}  // namespace
+
+// Change the page protection (of code pages) to writable and copy
+// the data at the specified location
+//
+// Arguments:
+// old_code               Target location to copy
+// new_code               Source
+// length                 Number of bytes to copy
+//
+// Returns: Windows error code (winerror.h). NO_ERROR if successful
+DWORD ModifyCode(void* old_code, void* new_code, int length) {
+  if ((NULL == old_code) || (NULL == new_code) || (0 == length)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  // Change the page protection so that we can write.
+  MEMORY_BASIC_INFORMATION memory_info;
+  DWORD error = NO_ERROR;
+  DWORD old_page_protection = 0;
+
+  if (!VirtualQuery(old_code, &memory_info, sizeof(memory_info))) {
+    error = GetLastError();
+    return error;
+  }
+
+  DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+                        PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
+                        memory_info.Protect;
+
+  if (VirtualProtect(old_code,
+                     length,
+                     is_executable ? PAGE_EXECUTE_READWRITE :
+                                     PAGE_READWRITE,
+                     &old_page_protection)) {
+
+    // Write the data.
+    CopyMemory(old_code, new_code, length);
+
+    // Restore the old page protection.
+    error = ERROR_SUCCESS;
+    VirtualProtect(old_code,
+                  length,
+                  old_page_protection,
+                  &old_page_protection);
+  } else {
+    error = GetLastError();
+  }
+
+  return error;
+}
+
+IATPatchFunction::IATPatchFunction()
+    : module_handle_(NULL),
+      original_function_(NULL),
+      iat_thunk_(NULL),
+      intercept_function_(NULL) {
+}
+
+IATPatchFunction::~IATPatchFunction() {
+  if (NULL != intercept_function_) {
+    DWORD error = Unpatch();
+    DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
+  }
+}
+
+DWORD IATPatchFunction::Patch(const wchar_t* module,
+                              const char* imported_from_module,
+                              const char* function_name,
+                              void* new_function) {
+  HMODULE module_handle = LoadLibraryW(module);
+  if (module_handle == NULL) {
+    NOTREACHED();
+    return GetLastError();
+  }
+
+  DWORD error = PatchFromModule(module_handle, imported_from_module,
+                                function_name, new_function);
+  if (NO_ERROR == error) {
+    module_handle_ = module_handle;
+  } else {
+    FreeLibrary(module_handle);
+  }
+
+  return error;
+}
+
+DWORD IATPatchFunction::PatchFromModule(HMODULE module,
+                                        const char* imported_from_module,
+                                        const char* function_name,
+                                        void* new_function) {
+  DCHECK_EQ(static_cast<void*>(NULL), original_function_);
+  DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_);
+  DCHECK_EQ(static_cast<void*>(NULL), intercept_function_);
+  DCHECK(module);
+
+  DWORD error = InterceptImportedFunction(module,
+                                          imported_from_module,
+                                          function_name,
+                                          new_function,
+                                          &original_function_,
+                                          &iat_thunk_);
+
+  if (NO_ERROR == error) {
+    DCHECK_NE(original_function_, intercept_function_);
+    intercept_function_ = new_function;
+  }
+
+  return error;
+}
+
+DWORD IATPatchFunction::Unpatch() {
+  DWORD error = RestoreImportedFunction(intercept_function_,
+                                        original_function_,
+                                        iat_thunk_);
+  DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
+
+  // Hands off the intercept if we fail to unpatch.
+  // If IATPatchFunction::Unpatch fails during RestoreImportedFunction
+  // it means that we cannot safely unpatch the import address table
+  // patch. In this case its better to be hands off the intercept as
+  // trying to unpatch again in the destructor of IATPatchFunction is
+  // not going to be any safer
+  if (module_handle_)
+    FreeLibrary(module_handle_);
+  module_handle_ = NULL;
+  intercept_function_ = NULL;
+  original_function_ = NULL;
+  iat_thunk_ = NULL;
+
+  return error;
+}
+
+void* IATPatchFunction::original_function() const {
+  DCHECK(is_patched());
+  return original_function_;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iat_patch_function.h b/base/win/iat_patch_function.h
new file mode 100644
index 0000000..8be97f8
--- /dev/null
+++ b/base/win/iat_patch_function.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_IAT_PATCH_FUNCTION_H_
+#define BASE_WIN_IAT_PATCH_FUNCTION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// A class that encapsulates Import Address Table patching helpers and restores
+// the original function in the destructor.
+//
+// It will intercept functions for a specific DLL imported from another DLL.
+// This is the case when, for example, we want to intercept
+// CertDuplicateCertificateContext function (exported from crypt32.dll) called
+// by wininet.dll.
+class BASE_EXPORT IATPatchFunction {
+ public:
+  IATPatchFunction();
+  ~IATPatchFunction();
+
+  // Intercept a function in an import table of a specific
+  // module. Save the original function and the import
+  // table address. These values will be used later
+  // during Unpatch
+  //
+  // Arguments:
+  // module                 Module to be intercepted
+  // imported_from_module   Module that exports the 'function_name'
+  // function_name          Name of the API to be intercepted
+  //
+  // Returns: Windows error code (winerror.h). NO_ERROR if successful
+  //
+  // Note: Patching a function will make the IAT patch take some "ownership" on
+  // |module|.  It will LoadLibrary(module) to keep the DLL alive until a call
+  // to Unpatch(), which will call FreeLibrary() and allow the module to be
+  // unloaded.  The idea is to help prevent the DLL from going away while a
+  // patch is still active.
+  DWORD Patch(const wchar_t* module,
+              const char* imported_from_module,
+              const char* function_name,
+              void* new_function);
+
+  // Same as Patch(), but uses a handle to a |module| instead of the DLL name.
+  DWORD PatchFromModule(HMODULE module,
+                        const char* imported_from_module,
+                        const char* function_name,
+                        void* new_function);
+
+  // Unpatch the IAT entry using internally saved original
+  // function.
+  //
+  // Returns: Windows error code (winerror.h). NO_ERROR if successful
+  DWORD Unpatch();
+
+  bool is_patched() const {
+    return (NULL != intercept_function_);
+  }
+
+  void* original_function() const;
+
+
+ private:
+  HMODULE module_handle_;
+  void* intercept_function_;
+  void* original_function_;
+  IMAGE_THUNK_DATA* iat_thunk_;
+
+  DISALLOW_COPY_AND_ASSIGN(IATPatchFunction);
+};
+
+BASE_EXPORT DWORD ModifyCode(void* old_code, void* new_code, int length);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_IAT_PATCH_FUNCTION_H_
diff --git a/base/win/iunknown_impl.cc b/base/win/iunknown_impl.cc
new file mode 100644
index 0000000..9baa0f3
--- /dev/null
+++ b/base/win/iunknown_impl.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/iunknown_impl.h"
+
+namespace base {
+namespace win {
+
+IUnknownImpl::IUnknownImpl()
+    : ref_count_(0) {
+}
+
+IUnknownImpl::~IUnknownImpl() {
+}
+
+ULONG STDMETHODCALLTYPE IUnknownImpl::AddRef() {
+  base::AtomicRefCountInc(&ref_count_);
+  return 1;
+}
+
+ULONG STDMETHODCALLTYPE IUnknownImpl::Release() {
+  if (!base::AtomicRefCountDec(&ref_count_)) {
+    delete this;
+    return 0;
+  }
+  return 1;
+}
+
+STDMETHODIMP IUnknownImpl::QueryInterface(REFIID riid, void** ppv) {
+  if (riid == IID_IUnknown) {
+    *ppv = static_cast<IUnknown*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  *ppv = NULL;
+  return E_NOINTERFACE;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iunknown_impl.h b/base/win/iunknown_impl.h
new file mode 100644
index 0000000..b7de205
--- /dev/null
+++ b/base/win/iunknown_impl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_IUNKNOWN_IMPL_H_
+#define BASE_WIN_IUNKNOWN_IMPL_H_
+
+#include <unknwn.h>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace win {
+
+// IUnknown implementation for other classes to derive from.
+class BASE_EXPORT IUnknownImpl : public IUnknown {
+ public:
+  IUnknownImpl();
+
+  ULONG STDMETHODCALLTYPE AddRef() override;
+  ULONG STDMETHODCALLTYPE Release() override;
+
+  // Subclasses should extend this to return any interfaces they provide.
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+
+ protected:
+  virtual ~IUnknownImpl();
+
+ private:
+  AtomicRefCount ref_count_;
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_IUNKNOWN_IMPL_H_
diff --git a/base/win/iunknown_impl_unittest.cc b/base/win/iunknown_impl_unittest.cc
new file mode 100644
index 0000000..874a43a
--- /dev/null
+++ b/base/win/iunknown_impl_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/iunknown_impl.h"
+
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+class TestIUnknownImplSubclass : public IUnknownImpl {
+ public:
+  TestIUnknownImplSubclass() {
+    ++instance_count;
+  }
+  ~TestIUnknownImplSubclass() override { --instance_count; }
+  static int instance_count;
+};
+
+// static
+int TestIUnknownImplSubclass::instance_count = 0;
+
+TEST(IUnknownImplTest, IUnknownImpl) {
+  ScopedCOMInitializer com_initializer;
+
+  EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
+  IUnknown* u = new TestIUnknownImplSubclass();
+
+  EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count);
+
+  EXPECT_EQ(1, u->AddRef());
+  EXPECT_EQ(1, u->AddRef());
+
+  IUnknown* other = NULL;
+  EXPECT_EQ(E_NOINTERFACE, u->QueryInterface(
+      IID_IDispatch, reinterpret_cast<void**>(&other)));
+  EXPECT_EQ(S_OK, u->QueryInterface(
+      IID_IUnknown, reinterpret_cast<void**>(&other)));
+  other->Release();
+
+  EXPECT_EQ(1, u->Release());
+  EXPECT_EQ(0, u->Release());
+  EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/memory_pressure_monitor.cc b/base/win/memory_pressure_monitor.cc
new file mode 100644
index 0000000..ed49a40
--- /dev/null
+++ b/base/win/memory_pressure_monitor.cc
@@ -0,0 +1,254 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/memory_pressure_monitor.h"
+
+#include <windows.h>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const DWORDLONG kMBBytes = 1024 * 1024;
+
+// Enumeration of UMA memory pressure levels. This needs to be kept in sync with
+// histograms.xml and the memory pressure levels defined in
+// MemoryPressureListener.
+enum MemoryPressureLevelUMA {
+  UMA_MEMORY_PRESSURE_LEVEL_NONE = 0,
+  UMA_MEMORY_PRESSURE_LEVEL_MODERATE = 1,
+  UMA_MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
+  // This must be the last value in the enum.
+  UMA_MEMORY_PRESSURE_LEVEL_COUNT,
+};
+
+// Converts a memory pressure level to an UMA enumeration value.
+MemoryPressureLevelUMA MemoryPressureLevelToUmaEnumValue(
+    MemoryPressureListener::MemoryPressureLevel level) {
+  switch (level) {
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      return UMA_MEMORY_PRESSURE_LEVEL_NONE;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      return UMA_MEMORY_PRESSURE_LEVEL_MODERATE;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      return UMA_MEMORY_PRESSURE_LEVEL_CRITICAL;
+  }
+  NOTREACHED();
+  return UMA_MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+}  // namespace
+
+// The following constants have been lifted from similar values in the ChromeOS
+// memory pressure monitor. The values were determined experimentally to ensure
+// sufficient responsiveness of the memory pressure subsystem, and minimal
+// overhead.
+const int MemoryPressureMonitor::kPollingIntervalMs = 5000;
+const int MemoryPressureMonitor::kModeratePressureCooldownMs = 10000;
+const int MemoryPressureMonitor::kModeratePressureCooldownCycles =
+    kModeratePressureCooldownMs / kPollingIntervalMs;
+
+// TODO(chrisha): Explore the following constants further with an experiment.
+
+// A system is considered 'high memory' if it has more than 1.5GB of system
+// memory available for use by the memory manager (not reserved for hardware
+// and drivers). This is a fuzzy version of the ~2GB discussed below.
+const int MemoryPressureMonitor::kLargeMemoryThresholdMb = 1536;
+
+// These are the default thresholds used for systems with < ~2GB of physical
+// memory. Such systems have been observed to always maintain ~100MB of
+// available memory, paging until that is the case. To try to avoid paging a
+// threshold slightly above this is chosen. The moderate threshold is slightly
+// less grounded in reality and chosen as 2.5x critical.
+const int MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb = 500;
+const int MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb = 200;
+
+// These are the default thresholds used for systems with >= ~2GB of physical
+// memory. Such systems have been observed to always maintain ~300MB of
+// available memory, paging until that is the case.
+const int MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb = 1000;
+const int MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb = 400;
+
+MemoryPressureMonitor::MemoryPressureMonitor()
+    : moderate_threshold_mb_(0),
+      critical_threshold_mb_(0),
+      current_memory_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      moderate_pressure_repeat_count_(0),
+      weak_ptr_factory_(this) {
+  InferThresholds();
+  StartObserving();
+}
+
+MemoryPressureMonitor::MemoryPressureMonitor(int moderate_threshold_mb,
+                                             int critical_threshold_mb)
+    : moderate_threshold_mb_(moderate_threshold_mb),
+      critical_threshold_mb_(critical_threshold_mb),
+      current_memory_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      moderate_pressure_repeat_count_(0),
+      weak_ptr_factory_(this) {
+  DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
+  DCHECK_LE(0, critical_threshold_mb_);
+  StartObserving();
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+  StopObserving();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureSoon() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
+                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+  return current_memory_pressure_level_;
+}
+
+void MemoryPressureMonitor::InferThresholds() {
+  // Default to a 'high' memory situation, which uses more conservative
+  // thresholds.
+  bool high_memory = true;
+  MEMORYSTATUSEX mem_status = {};
+  if (GetSystemMemoryStatus(&mem_status)) {
+    static const DWORDLONG kLargeMemoryThresholdBytes =
+        static_cast<DWORDLONG>(kLargeMemoryThresholdMb) * kMBBytes;
+    high_memory = mem_status.ullTotalPhys >= kLargeMemoryThresholdBytes;
+  }
+
+  if (high_memory) {
+    moderate_threshold_mb_ = kLargeMemoryDefaultModerateThresholdMb;
+    critical_threshold_mb_ = kLargeMemoryDefaultCriticalThresholdMb;
+  } else {
+    moderate_threshold_mb_ = kSmallMemoryDefaultModerateThresholdMb;
+    critical_threshold_mb_ = kSmallMemoryDefaultCriticalThresholdMb;
+  }
+}
+
+void MemoryPressureMonitor::StartObserving() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  timer_.Start(FROM_HERE,
+               TimeDelta::FromMilliseconds(kPollingIntervalMs),
+               Bind(&MemoryPressureMonitor::
+                        CheckMemoryPressureAndRecordStatistics,
+                    weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MemoryPressureMonitor::StopObserving() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // If StartObserving failed, StopObserving will still get called.
+  timer_.Stop();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressure() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Get the previous pressure level and update the current one.
+  MemoryPressureLevel old_pressure = current_memory_pressure_level_;
+  current_memory_pressure_level_ = CalculateCurrentPressureLevel();
+
+  // |notify| will be set to true if MemoryPressureListeners need to be
+  // notified of a memory pressure level state change.
+  bool notify = false;
+  switch (current_memory_pressure_level_) {
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      break;
+
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      if (old_pressure != current_memory_pressure_level_) {
+        // This is a new transition to moderate pressure so notify.
+        moderate_pressure_repeat_count_ = 0;
+        notify = true;
+      } else {
+        // Already in moderate pressure, only notify if sustained over the
+        // cooldown period.
+        if (++moderate_pressure_repeat_count_ ==
+                kModeratePressureCooldownCycles) {
+          moderate_pressure_repeat_count_ = 0;
+          notify = true;
+        }
+      }
+      break;
+
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      // Always notify of critical pressure levels.
+      notify = true;
+      break;
+  }
+
+  if (!notify)
+    return;
+
+  // Emit a notification of the current memory pressure level. This can only
+  // happen for moderate and critical pressure levels.
+  DCHECK_NE(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            current_memory_pressure_level_);
+  MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  CheckMemoryPressure();
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "Memory.PressureLevel",
+      MemoryPressureLevelToUmaEnumValue(current_memory_pressure_level_),
+      UMA_MEMORY_PRESSURE_LEVEL_COUNT);
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::CalculateCurrentPressureLevel() {
+  MEMORYSTATUSEX mem_status = {};
+  if (!GetSystemMemoryStatus(&mem_status))
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+  // How much system memory is actively available for use right now, in MBs.
+  int phys_free = static_cast<int>(mem_status.ullAvailPhys / kMBBytes);
+
+  // TODO(chrisha): This should eventually care about address space pressure,
+  // but the browser process (where this is running) effectively never runs out
+  // of address space. Renderers occasionally do, but it does them no good to
+  // have the browser process monitor address space pressure. Long term,
+  // renderers should run their own address space pressure monitors and act
+  // accordingly, with the browser making cross-process decisions based on
+  // system memory pressure.
+
+  // Determine if the physical memory is under critical memory pressure.
+  if (phys_free <= critical_threshold_mb_)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+
+  // Determine if the physical memory is under moderate memory pressure.
+  if (phys_free <= moderate_threshold_mb_)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+
+  // No memory pressure was detected.
+  return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+bool MemoryPressureMonitor::GetSystemMemoryStatus(
+    MEMORYSTATUSEX* mem_status) {
+  DCHECK(mem_status != nullptr);
+  mem_status->dwLength = sizeof(*mem_status);
+  if (!::GlobalMemoryStatusEx(mem_status))
+    return false;
+  return true;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/memory_pressure_monitor.h b/base/win/memory_pressure_monitor.h
new file mode 100644
index 0000000..6da176e
--- /dev/null
+++ b/base/win/memory_pressure_monitor.h
@@ -0,0 +1,144 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_WIN_MEMORY_PRESSURE_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+
+// To not pull in windows.h.
+typedef struct _MEMORYSTATUSEX MEMORYSTATUSEX;
+
+namespace base {
+namespace win {
+
+// Windows memory pressure monitor. Because there is no OS provided signal this
+// polls at a low frequency (once per second), and applies internal hysteresis.
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+  // Constants governing the polling and hysteresis behaviour of the observer.
+
+  // The polling interval, in milliseconds. While under critical pressure, this
+  // is also the timer to repeat cleanup attempts.
+  static const int kPollingIntervalMs;
+  // The time which should pass between 2 successive moderate memory pressure
+  // signals, in milliseconds.
+  static const int kModeratePressureCooldownMs;
+  // The number of cycles that should pass between 2 successive moderate memory
+  // pressure signals.
+  static const int kModeratePressureCooldownCycles;
+
+  // Constants governing the memory pressure level detection.
+
+  // The amount of total system memory beyond which a system is considered to be
+  // a large-memory system.
+  static const int kLargeMemoryThresholdMb;
+  // Default minimum free memory thresholds for small-memory systems, in MB.
+  static const int kSmallMemoryDefaultModerateThresholdMb;
+  static const int kSmallMemoryDefaultCriticalThresholdMb;
+  // Default minimum free memory thresholds for large-memory systems, in MB.
+  static const int kLargeMemoryDefaultModerateThresholdMb;
+  static const int kLargeMemoryDefaultCriticalThresholdMb;
+
+  // Default constructor. Will choose thresholds automatically basd on the
+  // actual amount of system memory.
+  MemoryPressureMonitor();
+
+  // Constructor with explicit memory thresholds. These represent the amount of
+  // free memory below which the applicable memory pressure state engages.
+  MemoryPressureMonitor(int moderate_threshold_mb, int critical_threshold_mb);
+
+  ~MemoryPressureMonitor() override;
+
+  // Schedules a memory pressure check to run soon. This must be called on the
+  // same thread where the monitor was instantiated.
+  void CheckMemoryPressureSoon();
+
+  // Get the current memory pressure level. This can be called from any thread.
+  MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+  // Returns the moderate pressure level free memory threshold, in MB.
+  int moderate_threshold_mb() const { return moderate_threshold_mb_; }
+
+  // Returns the critical pressure level free memory threshold, in MB.
+  int critical_threshold_mb() const { return critical_threshold_mb_; }
+
+ protected:
+  // Internals are exposed for unittests.
+
+  // Automatically infers threshold values based on system memory. This invokes
+  // GetMemoryStatus so it can be mocked in unittests.
+  void InferThresholds();
+
+  // Starts observing the memory fill level. Calls to StartObserving should
+  // always be matched with calls to StopObserving.
+  void StartObserving();
+
+  // Stop observing the memory fill level. May be safely called if
+  // StartObserving has not been called. Must be called from the same thread on
+  // which the monitor was instantiated.
+  void StopObserving();
+
+  // Checks memory pressure, storing the current level, applying any hysteresis
+  // and emitting memory pressure level change signals as necessary. This
+  // function is called periodically while the monitor is observing memory
+  // pressure. This is split out from CheckMemoryPressureAndRecordStatistics so
+  // that it may be called by CheckMemoryPressureSoon and not invoke UMA
+  // logging. Must be called from the same thread on which the monitor was
+  // instantiated.
+  void CheckMemoryPressure();
+
+  // Wrapper to CheckMemoryPressure that also records the observed memory
+  // pressure level via an UMA enumeration. This is the function that is called
+  // periodically by the timer. Must be called from the same thread on which the
+  // monitor was instantiated.
+  void CheckMemoryPressureAndRecordStatistics();
+
+  // Calculates the current instantaneous memory pressure level. This does not
+  // use any hysteresis and simply returns the result at the current moment. Can
+  // be called on any thread.
+  MemoryPressureLevel CalculateCurrentPressureLevel();
+
+  // Gets system memory status. This is virtual as a unittesting hook. Returns
+  // true if the system call succeeds, false otherwise. Can be called on any
+  // thread.
+  virtual bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status);
+
+ private:
+  // Threshold amounts of available memory that trigger pressure levels. See
+  // memory_pressure_monitor.cc for a discussion of reasonable values for these.
+  int moderate_threshold_mb_;
+  int critical_threshold_mb_;
+
+  // A periodic timer to check for memory pressure changes.
+  base::RepeatingTimer<MemoryPressureMonitor> timer_;
+
+  // The current memory pressure.
+  MemoryPressureLevel current_memory_pressure_level_;
+
+  // To slow down the amount of moderate pressure event calls, this gets used to
+  // count the number of events since the last event occured. This is used by
+  // |CheckMemoryPressure| to apply hysteresis on the raw results of
+  // |CalculateCurrentPressureLevel|.
+  int moderate_pressure_repeat_count_;
+
+  // Weak pointer factory to ourself used for scheduling calls to
+  // CheckMemoryPressure/CheckMemoryPressureAndRecordStatistics via |timer_|.
+  base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
+
+  // Ensures that this object is used from a single thread.
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_MEMORY_PRESSURE_MONITOR_H_
diff --git a/base/win/memory_pressure_monitor_unittest.cc b/base/win/memory_pressure_monitor_unittest.cc
new file mode 100644
index 0000000..40a25a7
--- /dev/null
+++ b/base/win/memory_pressure_monitor_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/memory_pressure_monitor.h"
+
+#include "base/basictypes.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct PressureSettings {
+  int phys_left_mb;
+  MemoryPressureListener::MemoryPressureLevel level;
+};
+
+}  // namespace
+
+// This is outside of the anonymous namespace so that it can be seen as a friend
+// to the monitor class.
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+  using MemoryPressureMonitor::CalculateCurrentPressureLevel;
+  using MemoryPressureMonitor::CheckMemoryPressure;
+
+  static const DWORDLONG kMBBytes = 1024 * 1024;
+
+  explicit TestMemoryPressureMonitor(bool large_memory)
+      : mem_status_() {
+    // Generate a plausible amount of memory.
+    mem_status_.ullTotalPhys =
+        static_cast<DWORDLONG>(GenerateTotalMemoryMb(large_memory)) * kMBBytes;
+
+    // Rerun InferThresholds using the test fixture's GetSystemMemoryStatus.
+    InferThresholds();
+    // Stop the timer.
+    StopObserving();
+  }
+
+  TestMemoryPressureMonitor(int system_memory_mb,
+                            int moderate_threshold_mb,
+                            int critical_threshold_mb)
+      : MemoryPressureMonitor(moderate_threshold_mb, critical_threshold_mb),
+        mem_status_() {
+    // Set the amount of system memory.
+    mem_status_.ullTotalPhys = static_cast<DWORDLONG>(
+        system_memory_mb * kMBBytes);
+
+    // Stop the timer.
+    StopObserving();
+  }
+
+  virtual ~TestMemoryPressureMonitor() {}
+
+  MOCK_METHOD1(OnMemoryPressure,
+               void(MemoryPressureListener::MemoryPressureLevel level));
+
+  // Generates an amount of total memory that is consistent with the requested
+  // memory model.
+  int GenerateTotalMemoryMb(bool large_memory) {
+    int total_mb = 64;
+    while (total_mb < MemoryPressureMonitor::kLargeMemoryThresholdMb)
+      total_mb *= 2;
+    if (large_memory)
+      return total_mb * 2;
+    return total_mb / 2;
+  }
+
+  // Sets up the memory status to reflect the provided absolute memory left.
+  void SetMemoryFree(int phys_left_mb) {
+    // ullTotalPhys is set in the constructor and not modified.
+
+    // Set the amount of available memory.
+    mem_status_.ullAvailPhys =
+        static_cast<DWORDLONG>(phys_left_mb) * kMBBytes;
+    DCHECK_LT(mem_status_.ullAvailPhys, mem_status_.ullTotalPhys);
+
+    // These fields are unused.
+    mem_status_.dwMemoryLoad = 0;
+    mem_status_.ullTotalPageFile = 0;
+    mem_status_.ullAvailPageFile = 0;
+    mem_status_.ullTotalVirtual = 0;
+    mem_status_.ullAvailVirtual = 0;
+  }
+
+  void SetNone() {
+    SetMemoryFree(moderate_threshold_mb() + 1);
+  }
+
+  void SetModerate() {
+    SetMemoryFree(moderate_threshold_mb() - 1);
+  }
+
+  void SetCritical() {
+    SetMemoryFree(critical_threshold_mb() - 1);
+  }
+
+ private:
+  bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status) override {
+    // Simply copy the memory status set by the test fixture.
+    *mem_status = mem_status_;
+    return true;
+  }
+
+  MEMORYSTATUSEX mem_status_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+class WinMemoryPressureMonitorTest : public testing::Test {
+ protected:
+  void CalculateCurrentMemoryPressureLevelTest(
+      TestMemoryPressureMonitor* monitor) {
+
+    int mod = monitor->moderate_threshold_mb();
+    monitor->SetMemoryFree(mod + 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(mod);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(mod - 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->CalculateCurrentPressureLevel());
+
+    int crit = monitor->critical_threshold_mb();
+    monitor->SetMemoryFree(crit + 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(crit);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(crit - 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              monitor->CalculateCurrentPressureLevel());
+  }
+
+  base::MessageLoopForUI message_loop_;
+};
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// small-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelSmall) {
+  static const int kModerateMb =
+      MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb;
+  static const int kCriticalMb =
+      MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb;
+
+  TestMemoryPressureMonitor monitor(false);  // Small-memory model.
+
+  EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// large-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLarge) {
+  static const int kModerateMb =
+      MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb;
+  static const int kCriticalMb =
+      MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb;
+
+  TestMemoryPressureMonitor monitor(true);  // Large-memory model.
+
+  EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with manually
+// specified threshold levels.
+TEST_F(WinMemoryPressureMonitorTest,
+       CalculateCurrentMemoryPressureLevelCustom) {
+  static const int kSystemMb = 512;
+  static const int kModerateMb = 256;
+  static const int kCriticalMb = 128;
+
+  TestMemoryPressureMonitor monitor(kSystemMb, kModerateMb, kCriticalMb);
+
+  EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST_F(WinMemoryPressureMonitorTest, CheckMemoryPressure) {
+  // Large-memory.
+  testing::StrictMock<TestMemoryPressureMonitor> monitor(true);
+  MemoryPressureListener listener(
+      base::Bind(&TestMemoryPressureMonitor::OnMemoryPressure,
+                 base::Unretained(&monitor)));
+
+  // Checking the memory pressure at 0% load should not produce any
+  // events.
+  monitor.SetNone();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            monitor.GetCurrentPressureLevel());
+
+  // Setting the memory level to 80% should produce a moderate pressure level.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_MODERATE));
+  monitor.SetModerate();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // Check that the event gets reposted after a while.
+  for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+    if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+      EXPECT_CALL(monitor,
+                  OnMemoryPressure(MemoryPressureListener::
+                                       MEMORY_PRESSURE_LEVEL_MODERATE));
+    }
+    monitor.CheckMemoryPressure();
+    message_loop_.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor.GetCurrentPressureLevel());
+    testing::Mock::VerifyAndClearExpectations(&monitor);
+  }
+
+  // Setting the memory usage to 99% should produce critical levels.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_CRITICAL));
+  monitor.SetCritical();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // Calling it again should immediately produce a second call.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_CRITICAL));
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // When lowering the pressure again there should be a notification and the
+  // pressure should go back to moderate.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_MODERATE));
+  monitor.SetModerate();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // Check that the event gets reposted after a while.
+  for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+    if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+      EXPECT_CALL(monitor,
+                  OnMemoryPressure(MemoryPressureListener::
+                                       MEMORY_PRESSURE_LEVEL_MODERATE));
+    }
+    monitor.CheckMemoryPressure();
+    message_loop_.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor.GetCurrentPressureLevel());
+    testing::Mock::VerifyAndClearExpectations(&monitor);
+  }
+
+  // Going down to no pressure should not produce an notification.
+  monitor.SetNone();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/message_window.cc b/base/win/message_window.cc
new file mode 100644
index 0000000..0b4b29f
--- /dev/null
+++ b/base/win/message_window.cc
@@ -0,0 +1,170 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/message_window.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/win/wrapped_window_proc.h"
+
+const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow";
+
+namespace base {
+namespace win {
+
+// Used along with LazyInstance to register a window class for message-only
+// windows created by MessageWindow.
+class MessageWindow::WindowClass {
+ public:
+  WindowClass();
+  ~WindowClass();
+
+  ATOM atom() { return atom_; }
+  HINSTANCE instance() { return instance_; }
+
+ private:
+  ATOM atom_;
+  HINSTANCE instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowClass);
+};
+
+static LazyInstance<MessageWindow::WindowClass> g_window_class =
+    LAZY_INSTANCE_INITIALIZER;
+
+MessageWindow::WindowClass::WindowClass()
+    : atom_(0),
+      instance_(base::GetModuleFromAddress(&MessageWindow::WindowProc)) {
+  WNDCLASSEX window_class;
+  window_class.cbSize = sizeof(window_class);
+  window_class.style = 0;
+  window_class.lpfnWndProc = &base::win::WrappedWindowProc<WindowProc>;
+  window_class.cbClsExtra = 0;
+  window_class.cbWndExtra = 0;
+  window_class.hInstance = instance_;
+  window_class.hIcon = NULL;
+  window_class.hCursor = NULL;
+  window_class.hbrBackground = NULL;
+  window_class.lpszMenuName = NULL;
+  window_class.lpszClassName = kMessageWindowClassName;
+  window_class.hIconSm = NULL;
+  atom_ = RegisterClassEx(&window_class);
+  if (atom_ == 0) {
+    PLOG(ERROR)
+        << "Failed to register the window class for a message-only window";
+  }
+}
+
+MessageWindow::WindowClass::~WindowClass() {
+  if (atom_ != 0) {
+    BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_);
+    // Hitting this DCHECK usually means that some MessageWindow objects were
+    // leaked. For example not calling
+    // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked
+    // MessageWindow.
+    DCHECK(result);
+  }
+}
+
+MessageWindow::MessageWindow()
+    : window_(NULL) {
+}
+
+MessageWindow::~MessageWindow() {
+  DCHECK(CalledOnValidThread());
+
+  if (window_ != NULL) {
+    BOOL result = DestroyWindow(window_);
+    DCHECK(result);
+  }
+}
+
+bool MessageWindow::Create(const MessageCallback& message_callback) {
+  return DoCreate(message_callback, NULL);
+}
+
+bool MessageWindow::CreateNamed(const MessageCallback& message_callback,
+                                const string16& window_name) {
+  return DoCreate(message_callback, window_name.c_str());
+}
+
+// static
+HWND MessageWindow::FindWindow(const string16& window_name) {
+  return FindWindowEx(HWND_MESSAGE, NULL, kMessageWindowClassName,
+                      window_name.c_str());
+}
+
+bool MessageWindow::DoCreate(const MessageCallback& message_callback,
+                             const wchar_t* window_name) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(message_callback_.is_null());
+  DCHECK(!window_);
+
+  message_callback_ = message_callback;
+
+  WindowClass& window_class = g_window_class.Get();
+  window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0,
+                         0, 0, HWND_MESSAGE, 0, window_class.instance(), this);
+  if (!window_) {
+    PLOG(ERROR) << "Failed to create a message-only window";
+    return false;
+  }
+
+  return true;
+}
+
+// static
+LRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd,
+                                           UINT message,
+                                           WPARAM wparam,
+                                           LPARAM lparam) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 MessageWindow::WindowProc"));
+
+  MessageWindow* self = reinterpret_cast<MessageWindow*>(
+      GetWindowLongPtr(hwnd, GWLP_USERDATA));
+
+  switch (message) {
+    // Set up the self before handling WM_CREATE.
+    case WM_CREATE: {
+      CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
+      self = reinterpret_cast<MessageWindow*>(cs->lpCreateParams);
+
+      // Make |hwnd| available to the message handler. At this point the control
+      // hasn't returned from CreateWindow() yet.
+      self->window_ = hwnd;
+
+      // Store pointer to the self to the window's user data.
+      SetLastError(ERROR_SUCCESS);
+      LONG_PTR result = SetWindowLongPtr(
+          hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
+      CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
+      break;
+    }
+
+    // Clear the pointer to stop calling the self once WM_DESTROY is
+    // received.
+    case WM_DESTROY: {
+      SetLastError(ERROR_SUCCESS);
+      LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
+      CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
+      break;
+    }
+  }
+
+  // Handle the message.
+  if (self) {
+    LRESULT message_result;
+    if (self->message_callback_.Run(message, wparam, lparam, &message_result))
+      return message_result;
+  }
+
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/message_window.h b/base/win/message_window.h
new file mode 100644
index 0000000..ae0c6f0
--- /dev/null
+++ b/base/win/message_window.h
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_MESSAGE_WINDOW_H_
+#define BASE_WIN_MESSAGE_WINDOW_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace base {
+namespace win {
+
+// Implements a message-only window.
+class BASE_EXPORT MessageWindow : public base::NonThreadSafe {
+ public:
+  // Used to register a process-wide message window class.
+  class WindowClass;
+
+  // Implement this callback to handle messages received by the message window.
+  // If the callback returns |false|, the first four parameters are passed to
+  // DefWindowProc(). Otherwise, |*result| is returned by the window procedure.
+  typedef base::Callback<bool(UINT message,
+                              WPARAM wparam,
+                              LPARAM lparam,
+                              LRESULT* result)> MessageCallback;
+
+  MessageWindow();
+  ~MessageWindow();
+
+  // Creates a message-only window. The incoming messages will be passed by
+  // |message_callback|. |message_callback| must outlive |this|.
+  bool Create(const MessageCallback& message_callback);
+
+  // Same as Create() but assigns the name to the created window.
+  bool CreateNamed(const MessageCallback& message_callback,
+                   const string16& window_name);
+
+  HWND hwnd() const { return window_; }
+
+  // Retrieves a handle of the first message-only window with matching
+  // |window_name|.
+  static HWND FindWindow(const string16& window_name);
+
+ private:
+  // Give |WindowClass| access to WindowProc().
+  friend class WindowClass;
+
+  // Contains the actual window creation code.
+  bool DoCreate(const MessageCallback& message_callback,
+                const wchar_t* window_name);
+
+  // Invoked by the OS to process incoming window messages.
+  static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam,
+                                     LPARAM lparam);
+
+  // Invoked to handle messages received by the window.
+  MessageCallback message_callback_;
+
+  // Handle of the input window.
+  HWND window_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageWindow);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_MESSAGE_WINDOW_H_
diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc
new file mode 100644
index 0000000..00248bf
--- /dev/null
+++ b/base/win/message_window_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/message_window.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+bool HandleMessage(
+    UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
+  // Return |wparam| as the result of WM_USER message.
+  if (message == WM_USER) {
+    *result = wparam;
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+// Checks that a window can be created.
+TEST(MessageWindowTest, Create) {
+  win::MessageWindow window;
+  EXPECT_TRUE(window.Create(base::Bind(&HandleMessage)));
+}
+
+// Checks that a named window can be created.
+TEST(MessageWindowTest, CreateNamed) {
+  win::MessageWindow window;
+  EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage),
+              UTF8ToUTF16("test_message_window")));
+}
+
+// Verifies that the created window can receive messages.
+TEST(MessageWindowTest, SendMessage) {
+  win::MessageWindow window;
+  EXPECT_TRUE(window.Create(base::Bind(&HandleMessage)));
+
+  EXPECT_EQ(SendMessage(window.hwnd(), WM_USER, 100, 0), 100);
+}
+
+// Verifies that a named window can be found by name.
+TEST(MessageWindowTest, FindWindow) {
+  string16 name = UTF8ToUTF16(base::GenerateGUID());
+  win::MessageWindow window;
+  EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), name));
+
+  HWND hwnd = win::MessageWindow::FindWindow(name);
+  EXPECT_TRUE(hwnd != NULL);
+  EXPECT_EQ(SendMessage(hwnd, WM_USER, 200, 0), 200);
+}
+
+}  // namespace base
diff --git a/base/win/metro.cc b/base/win/metro.cc
new file mode 100644
index 0000000..7946698
--- /dev/null
+++ b/base/win/metro.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/metro.h"
+
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace win {
+
+HMODULE GetMetroModule() {
+  const HMODULE kUninitialized = reinterpret_cast<HMODULE>(1);
+  static HMODULE metro_module = kUninitialized;
+
+  if (metro_module == kUninitialized) {
+    // Initialize the cache, note that the initialization is idempotent
+    // under the assumption that metro_driver is never unloaded, so the
+    // race to this assignment is safe.
+    metro_module = GetModuleHandleA("metro_driver.dll");
+    if (metro_module != NULL) {
+      // This must be a metro process if the metro_driver is loaded.
+      DCHECK(IsMetroProcess());
+    }
+  }
+
+  DCHECK(metro_module != kUninitialized);
+  return metro_module;
+}
+
+bool IsMetroProcess() {
+  enum ImmersiveState {
+    kImmersiveUnknown,
+    kImmersiveTrue,
+    kImmersiveFalse
+  };
+  // The immersive state of a process can never change.
+  // Look it up once and cache it here.
+  static ImmersiveState state = kImmersiveUnknown;
+
+  if (state == kImmersiveUnknown) {
+    if (IsProcessImmersive(::GetCurrentProcess())) {
+      state = kImmersiveTrue;
+    } else {
+      state = kImmersiveFalse;
+    }
+  }
+  DCHECK_NE(kImmersiveUnknown, state);
+  return state == kImmersiveTrue;
+}
+
+bool IsProcessImmersive(HANDLE process) {
+  typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process);
+  HMODULE user32 = ::GetModuleHandleA("user32.dll");
+  DCHECK(user32 != NULL);
+
+  IsImmersiveProcessFunc is_immersive_process =
+      reinterpret_cast<IsImmersiveProcessFunc>(
+          ::GetProcAddress(user32, "IsImmersiveProcess"));
+
+  if (is_immersive_process)
+    return is_immersive_process(process) ? true: false;
+  return false;
+}
+
+wchar_t* LocalAllocAndCopyString(const string16& src) {
+  size_t dest_size = (src.length() + 1) * sizeof(wchar_t);
+  wchar_t* dest = reinterpret_cast<wchar_t*>(LocalAlloc(LPTR, dest_size));
+  base::wcslcpy(dest, src.c_str(), dest_size);
+  return dest;
+}
+
+// Metro driver exports for getting the launch type, initial url, initial
+// search term, etc.
+extern "C" {
+typedef const wchar_t* (*GetInitialUrl)();
+typedef const wchar_t* (*GetInitialSearchString)();
+typedef base::win::MetroLaunchType (*GetLaunchType)(
+    base::win::MetroPreviousExecutionState* previous_state);
+}
+
+MetroLaunchType GetMetroLaunchParams(string16* params) {
+  HMODULE metro = base::win::GetMetroModule();
+  if (!metro)
+    return base::win::METRO_LAUNCH_ERROR;
+
+  GetLaunchType get_launch_type = reinterpret_cast<GetLaunchType>(
+      ::GetProcAddress(metro, "GetLaunchType"));
+  DCHECK(get_launch_type);
+
+  base::win::MetroLaunchType launch_type = get_launch_type(NULL);
+
+  if ((launch_type == base::win::METRO_PROTOCOL) ||
+      (launch_type == base::win::METRO_LAUNCH)) {
+    GetInitialUrl initial_metro_url = reinterpret_cast<GetInitialUrl>(
+        ::GetProcAddress(metro, "GetInitialUrl"));
+    DCHECK(initial_metro_url);
+    *params = initial_metro_url();
+  } else if (launch_type == base::win::METRO_SEARCH) {
+    GetInitialSearchString initial_search_string =
+        reinterpret_cast<GetInitialSearchString>(
+            ::GetProcAddress(metro, "GetInitialSearchString"));
+    DCHECK(initial_search_string);
+    *params = initial_search_string();
+  }
+  return launch_type;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/metro.h b/base/win/metro.h
new file mode 100644
index 0000000..0696006
--- /dev/null
+++ b/base/win/metro.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_METRO_H_
+#define BASE_WIN_METRO_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+// Identifies the type of the metro launch.
+enum MetroLaunchType {
+  METRO_LAUNCH,
+  METRO_SEARCH,
+  METRO_SHARE,
+  METRO_FILE,
+  METRO_PROTOCOL,
+  METRO_LAUNCH_ERROR,
+  METRO_LASTLAUNCHTYPE,
+};
+
+// In metro mode, this enum identifies the last execution state, i.e. whether
+// we crashed, terminated, etc.
+enum MetroPreviousExecutionState {
+  NOTRUNNING,
+  RUNNING,
+  SUSPENDED,
+  TERMINATED,
+  CLOSEDBYUSER,
+  LASTEXECUTIONSTATE,
+};
+
+// Enum values for UMA histogram reporting of site-specific tile pinning.
+// TODO(tapted): Move this to win8/util when ready (http://crbug.com/160288).
+enum MetroSecondaryTilePinUmaResult {
+  METRO_PIN_STATE_NONE,
+  METRO_PIN_INITIATED,
+  METRO_PIN_LOGO_READY,
+  METRO_PIN_REQUEST_SHOW_ERROR,
+  METRO_PIN_RESULT_CANCEL,
+  METRO_PIN_RESULT_OK,
+  METRO_PIN_RESULT_OTHER,
+  METRO_PIN_RESULT_ERROR,
+  METRO_UNPIN_INITIATED,
+  METRO_UNPIN_REQUEST_SHOW_ERROR,
+  METRO_UNPIN_RESULT_CANCEL,
+  METRO_UNPIN_RESULT_OK,
+  METRO_UNPIN_RESULT_OTHER,
+  METRO_UNPIN_RESULT_ERROR,
+  METRO_PIN_STATE_LIMIT
+};
+
+// Contains information about the currently displayed tab in metro mode.
+struct CurrentTabInfo {
+  wchar_t* title;
+  wchar_t* url;
+};
+
+// Returns the handle to the metro dll loaded in the process. A NULL return
+// indicates that the metro dll was not loaded in the process.
+BASE_EXPORT HMODULE GetMetroModule();
+
+// Returns true if this process is running as an immersive program
+// in Windows Metro mode.
+BASE_EXPORT bool IsMetroProcess();
+
+// Returns true if the process identified by the handle passed in is an
+// immersive (Metro) process.
+BASE_EXPORT bool IsProcessImmersive(HANDLE process);
+
+// Allocates and returns the destination string via the LocalAlloc API after
+// copying the src to it.
+BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src);
+
+// Returns the type of launch and the activation params. For example if the
+// the launch is for METRO_PROTOCOL then the params is a url.
+BASE_EXPORT MetroLaunchType GetMetroLaunchParams(string16* params);
+
+// Handler function for the buttons on a metro dialog box
+typedef void (*MetroDialogButtonPressedHandler)();
+
+// Handler function invoked when a metro style notification is clicked.
+typedef void (*MetroNotificationClickedHandler)(const wchar_t* context);
+
+// Function to display metro style notifications.
+typedef void (*MetroNotification)(const char* origin_url,
+                                  const char* icon_url,
+                                  const wchar_t* title,
+                                  const wchar_t* body,
+                                  const wchar_t* display_source,
+                                  const char* notification_id,
+                                  MetroNotificationClickedHandler handler,
+                                  const wchar_t* handler_context);
+
+// Function to cancel displayed notification.
+typedef bool (*MetroCancelNotification)(const char* notification_id);
+
+// Callback for UMA invoked by Metro Pin and UnPin functions after user gesture.
+typedef base::Callback<void(MetroSecondaryTilePinUmaResult)>
+    MetroPinUmaResultCallback;
+
+// Function to pin a site-specific tile (bookmark) to the start screen.
+typedef void (*MetroPinToStartScreen)(
+    const string16& tile_id,
+    const string16& title,
+    const string16& url,
+    const FilePath& logo_path,
+    const MetroPinUmaResultCallback& callback);
+
+// Function to un-pin a site-specific tile (bookmark) from the start screen.
+typedef void (*MetroUnPinFromStartScreen)(
+    const string16& title_id,
+    const MetroPinUmaResultCallback& callback);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_METRO_H_
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
new file mode 100644
index 0000000..5ebe185
--- /dev/null
+++ b/base/win/object_watcher.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/object_watcher.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+//-----------------------------------------------------------------------------
+
+ObjectWatcher::ObjectWatcher()
+    : object_(NULL),
+      wait_object_(NULL),
+      origin_loop_(NULL),
+      weak_factory_(this) {
+}
+
+ObjectWatcher::~ObjectWatcher() {
+  StopWatching();
+}
+
+bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
+  CHECK(delegate);
+  if (wait_object_) {
+    NOTREACHED() << "Already watching an object";
+    return false;
+  }
+
+  // Since our job is to just notice when an object is signaled and report the
+  // result back to this thread, we can just run on a Windows wait thread.
+  DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;
+
+  // DoneWaiting can be synchronously called from RegisterWaitForSingleObject,
+  // so set up all state now.
+  callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(),
+                         delegate);
+  object_ = object;
+  origin_loop_ = MessageLoop::current();
+
+  if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting,
+                                   this, INFINITE, wait_flags)) {
+    DPLOG(FATAL) << "RegisterWaitForSingleObject failed";
+    object_ = NULL;
+    wait_object_ = NULL;
+    return false;
+  }
+
+  // We need to know if the current message loop is going away so we can
+  // prevent the wait thread from trying to access a dead message loop.
+  MessageLoop::current()->AddDestructionObserver(this);
+  return true;
+}
+
+bool ObjectWatcher::StopWatching() {
+  if (!wait_object_)
+    return false;
+
+  // Make sure ObjectWatcher is used in a single-threaded fashion.
+  DCHECK_EQ(origin_loop_, MessageLoop::current());
+
+  // Blocking call to cancel the wait. Any callbacks already in progress will
+  // finish before we return from this call.
+  if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) {
+    DPLOG(FATAL) << "UnregisterWaitEx failed";
+    return false;
+  }
+
+  weak_factory_.InvalidateWeakPtrs();
+  object_ = NULL;
+  wait_object_ = NULL;
+
+  MessageLoop::current()->RemoveDestructionObserver(this);
+  return true;
+}
+
+bool ObjectWatcher::IsWatching() const {
+  return object_ != NULL;
+}
+
+HANDLE ObjectWatcher::GetWatchedObject() const {
+  return object_;
+}
+
+// static
+void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
+  DCHECK(!timed_out);
+
+  // The destructor blocks on any callbacks that are in flight, so we know that
+  // that is always a pointer to a valid ObjectWater.
+  ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
+  that->origin_loop_->task_runner()->PostTask(FROM_HERE, that->callback_);
+  that->callback_.Reset();
+}
+
+void ObjectWatcher::Signal(Delegate* delegate) {
+  // Signaling the delegate may result in our destruction or a nested call to
+  // StartWatching(). As a result, we save any state we need and clear previous
+  // watcher state before signaling the delegate.
+  HANDLE object = object_;
+  StopWatching();
+  delegate->OnObjectSignaled(object);
+}
+
+void ObjectWatcher::WillDestroyCurrentMessageLoop() {
+  // Need to shutdown the watch so that we don't try to access the MessageLoop
+  // after this point.
+  StopWatching();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/object_watcher.h b/base/win/object_watcher.h
new file mode 100644
index 0000000..d68d935
--- /dev/null
+++ b/base/win/object_watcher.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_OBJECT_WATCHER_H_
+#define BASE_WIN_OBJECT_WATCHER_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+
+namespace base {
+namespace win {
+
+// A class that provides a means to asynchronously wait for a Windows object to
+// become signaled.  It is an abstraction around RegisterWaitForSingleObject
+// that provides a notification callback, OnObjectSignaled, that runs back on
+// the origin thread (i.e., the thread that called StartWatching).
+//
+// This class acts like a smart pointer such that when it goes out-of-scope,
+// UnregisterWaitEx is automatically called, and any in-flight notification is
+// suppressed.
+//
+// Typical usage:
+//
+//   class MyClass : public base::ObjectWatcher::Delegate {
+//    public:
+//     void DoStuffWhenSignaled(HANDLE object) {
+//       watcher_.StartWatching(object, this);
+//     }
+//     virtual void OnObjectSignaled(HANDLE object) {
+//       // OK, time to do stuff!
+//     }
+//    private:
+//     base::ObjectWatcher watcher_;
+//   };
+//
+// In the above example, MyClass wants to "do stuff" when object becomes
+// signaled.  ObjectWatcher makes this task easy.  When MyClass goes out of
+// scope, the watcher_ will be destroyed, and there is no need to worry about
+// OnObjectSignaled being called on a deleted MyClass pointer.  Easy!
+// If the object is already signaled before being watched, OnObjectSignaled is
+// still called after (but not necessarily immediately after) watch is started.
+//
+class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
+ public:
+  class BASE_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+    // Called from the MessageLoop when a signaled object is detected.  To
+    // continue watching the object, StartWatching must be called again.
+    virtual void OnObjectSignaled(HANDLE object) = 0;
+  };
+
+  ObjectWatcher();
+  ~ObjectWatcher() override;
+
+  // When the object is signaled, the given delegate is notified on the thread
+  // where StartWatching is called.  The ObjectWatcher is not responsible for
+  // deleting the delegate.
+  //
+  // Returns true if the watch was started.  Otherwise, false is returned.
+  //
+  bool StartWatching(HANDLE object, Delegate* delegate);
+
+  // Stops watching.  Does nothing if the watch has already completed.  If the
+  // watch is still active, then it is canceled, and the associated delegate is
+  // not notified.
+  //
+  // Returns true if the watch was canceled.  Otherwise, false is returned.
+  //
+  bool StopWatching();
+
+  // Returns true if currently watching an object.
+  bool IsWatching() const;
+
+  // Returns the handle of the object being watched.
+  HANDLE GetWatchedObject() const;
+
+ private:
+  // Called on a background thread when done waiting.
+  static void CALLBACK DoneWaiting(void* param, BOOLEAN timed_out);
+
+  void Signal(Delegate* delegate);
+
+  // MessageLoop::DestructionObserver implementation:
+  void WillDestroyCurrentMessageLoop() override;
+
+  // Internal state.
+  Closure callback_;
+  HANDLE object_;             // The object being watched
+  HANDLE wait_object_;        // Returned by RegisterWaitForSingleObject
+  MessageLoop* origin_loop_;  // Used to get back to the origin thread
+
+  WeakPtrFactory<ObjectWatcher> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectWatcher);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_OBJECT_WATCHER_H_
diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc
new file mode 100644
index 0000000..b30ca41
--- /dev/null
+++ b/base/win/object_watcher_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/object_watcher.h"
+
+#include <process.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+class QuitDelegate : public ObjectWatcher::Delegate {
+ public:
+  void OnObjectSignaled(HANDLE object) override {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+};
+
+class DecrementCountDelegate : public ObjectWatcher::Delegate {
+ public:
+  explicit DecrementCountDelegate(int* counter) : counter_(counter) {
+  }
+  void OnObjectSignaled(HANDLE object) override { --(*counter_); }
+
+ private:
+  int* counter_;
+};
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+  EXPECT_FALSE(watcher.IsWatching());
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+  EXPECT_TRUE(watcher.IsWatching());
+  EXPECT_EQ(event, watcher.GetWatchedObject());
+
+  SetEvent(event);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_FALSE(watcher.IsWatching());
+  CloseHandle(event);
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  watcher.StopWatching();
+
+  CloseHandle(event);
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  int counter = 1;
+  DecrementCountDelegate delegate(&counter);
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  SetEvent(event);
+
+  // Let the background thread do its business
+  Sleep(30);
+
+  watcher.StopWatching();
+
+  RunLoop().RunUntilIdle();
+
+  // Our delegate should not have fired.
+  EXPECT_EQ(1, counter);
+
+  CloseHandle(event);
+}
+
+void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  // A manual-reset event that is signaled before we begin watching.
+  HANDLE event = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_FALSE(watcher.IsWatching());
+  CloseHandle(event);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+  // Simulate a MessageLoop that dies before an ObjectWatcher.  This ordinarily
+  // doesn't happen when people use the Thread class, but it can happen when
+  // people use the Singleton pattern or atexit.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);  // not signaled
+  {
+    ObjectWatcher watcher;
+    {
+      MessageLoop message_loop(message_loop_type);
+
+      QuitDelegate delegate;
+      watcher.StartWatching(event, &delegate);
+    }
+  }
+  CloseHandle(event);
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(ObjectWatcherTest, BasicSignal) {
+  RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT);
+  RunTest_BasicSignal(MessageLoop::TYPE_IO);
+  RunTest_BasicSignal(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, BasicCancel) {
+  RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT);
+  RunTest_BasicCancel(MessageLoop::TYPE_IO);
+  RunTest_BasicCancel(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, CancelAfterSet) {
+  RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT);
+  RunTest_CancelAfterSet(MessageLoop::TYPE_IO);
+  RunTest_CancelAfterSet(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, SignalBeforeWatch) {
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_DEFAULT);
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_IO);
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, OutlivesMessageLoop) {
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT);
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO);
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
new file mode 100644
index 0000000..692b7b6
--- /dev/null
+++ b/base/win/pe_image.cc
@@ -0,0 +1,602 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements PEImage, a generic class to manipulate PE files.
+// This file was adapted from GreenBorder's Code.
+
+#include "base/win/pe_image.h"
+
+namespace base {
+namespace win {
+
+// TODO(jschuh): crbug.com/167707 Make sure this code works on 64-bit.
+
+// Structure to perform imports enumerations.
+struct EnumAllImportsStorage {
+  PEImage::EnumImportsFunction callback;
+  PVOID cookie;
+};
+
+namespace {
+
+  // PdbInfo Signature
+  const DWORD kPdbInfoSignature = 'SDSR';
+
+  // Compare two strings byte by byte on an unsigned basis.
+  //   if s1 == s2, return 0
+  //   if s1 < s2, return negative
+  //   if s1 > s2, return positive
+  // Exception if inputs are invalid.
+  int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
+    while (*s1 != '\0' && *s1 == *s2) {
+      ++s1;
+      ++s2;
+    }
+
+    return (*reinterpret_cast<const unsigned char*>(s1) -
+            *reinterpret_cast<const unsigned char*>(s2));
+  }
+
+  struct PdbInfo {
+    DWORD Signature;
+    GUID Guid;
+    DWORD Age;
+    char PdbFileName[1];
+  };
+}  // namespace
+
+// Callback used to enumerate imports. See EnumImportChunksFunction.
+bool ProcessImportChunk(const PEImage &image, LPCSTR module,
+                        PIMAGE_THUNK_DATA name_table,
+                        PIMAGE_THUNK_DATA iat, PVOID cookie) {
+  EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
+                                       cookie);
+
+  return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
+                                  storage.cookie);
+}
+
+// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
+bool ProcessDelayImportChunk(const PEImage &image,
+                             PImgDelayDescr delay_descriptor,
+                             LPCSTR module, PIMAGE_THUNK_DATA name_table,
+                             PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat,
+                             PIMAGE_THUNK_DATA unload_iat, PVOID cookie) {
+  EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
+                                       cookie);
+
+  return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
+                                       module, name_table, iat, bound_iat,
+                                       unload_iat, storage.cookie);
+}
+
+void PEImage::set_module(HMODULE module) {
+  module_ = module;
+}
+
+PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
+  return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
+}
+
+PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const {
+  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+  return reinterpret_cast<PIMAGE_NT_HEADERS>(
+      reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+  PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers);
+
+  if (section < nt_headers->FileHeader.NumberOfSections)
+    return first_section + section;
+  else
+    return NULL;
+}
+
+WORD PEImage::GetNumSections() const {
+  return GetNTHeaders()->FileHeader.NumberOfSections;
+}
+
+DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  return nt_headers->OptionalHeader.DataDirectory[directory].Size;
+}
+
+PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  return RVAToAddr(
+      nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
+  PBYTE target = reinterpret_cast<PBYTE>(address);
+  PIMAGE_SECTION_HEADER section;
+
+  for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) {
+    // Don't use the virtual RVAToAddr.
+    PBYTE start = reinterpret_cast<PBYTE>(
+                      PEImage::RVAToAddr(section->VirtualAddress));
+
+    DWORD size = section->Misc.VirtualSize;
+
+    if ((start <= target) && (start + size > target))
+      return section;
+  }
+
+  return NULL;
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
+    LPCSTR section_name) const {
+  if (NULL == section_name)
+    return NULL;
+
+  PIMAGE_SECTION_HEADER ret = NULL;
+  int num_sections = GetNumSections();
+
+  for (int i = 0; i < num_sections; i++) {
+    PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
+    if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
+                       sizeof(section->Name))) {
+      ret = section;
+      break;
+    }
+  }
+
+  return ret;
+}
+
+bool PEImage::GetDebugId(LPGUID guid, LPDWORD age) const {
+  if (NULL == guid || NULL == age) {
+    return false;
+  }
+
+  DWORD debug_directory_size =
+      GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
+  PIMAGE_DEBUG_DIRECTORY debug_directory =
+      reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
+      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
+
+  size_t directory_count =
+      debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
+
+  for (size_t index = 0; index < directory_count; ++index) {
+    if (debug_directory[index].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
+      PdbInfo* pdb_info = reinterpret_cast<PdbInfo*>(
+          RVAToAddr(debug_directory[index].AddressOfRawData));
+      if (pdb_info->Signature != kPdbInfoSignature) {
+        // Unsupported PdbInfo signature
+        return false;
+      }
+      *guid = pdb_info->Guid;
+      *age = pdb_info->Age;
+      return true;
+    }
+  }
+  return false;
+}
+
+PDWORD PEImage::GetExportEntry(LPCSTR name) const {
+  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+  if (NULL == exports)
+    return NULL;
+
+  WORD ordinal = 0;
+  if (!GetProcOrdinal(name, &ordinal))
+    return NULL;
+
+  PDWORD functions = reinterpret_cast<PDWORD>(
+                         RVAToAddr(exports->AddressOfFunctions));
+
+  return functions + ordinal - exports->Base;
+}
+
+FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
+  PDWORD export_entry = GetExportEntry(function_name);
+  if (NULL == export_entry)
+    return NULL;
+
+  PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
+
+  PBYTE exports = reinterpret_cast<PBYTE>(
+      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+  // Check for forwarded exports as a special case.
+  if (exports <= function && exports + size > function)
+#pragma warning(push)
+#pragma warning(disable: 4312)
+    // This cast generates a warning because it is 32 bit specific.
+    return reinterpret_cast<FARPROC>(0xFFFFFFFF);
+#pragma warning(pop)
+
+  return reinterpret_cast<FARPROC>(function);
+}
+
+bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const {
+  if (NULL == ordinal)
+    return false;
+
+  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+  if (NULL == exports)
+    return false;
+
+  if (IsOrdinal(function_name)) {
+    *ordinal = ToOrdinal(function_name);
+  } else {
+    PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+    PDWORD lower = names;
+    PDWORD upper = names + exports->NumberOfNames;
+    int cmp = -1;
+
+    // Binary Search for the name.
+    while (lower != upper) {
+      PDWORD middle = lower + (upper - lower) / 2;
+      LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
+
+      // This may be called by sandbox before MSVCRT dll loads, so can't use
+      // CRT function here.
+      cmp = StrCmpByByte(function_name, name);
+
+      if (cmp == 0) {
+        lower = middle;
+        break;
+      }
+
+      if (cmp > 0)
+        lower = middle + 1;
+      else
+        upper = middle;
+    }
+
+    if (cmp != 0)
+      return false;
+
+
+    PWORD ordinals = reinterpret_cast<PWORD>(
+                         RVAToAddr(exports->AddressOfNameOrdinals));
+
+    *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
+  }
+
+  return true;
+}
+
+bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+  UINT num_sections = nt_headers->FileHeader.NumberOfSections;
+  PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
+
+  for (UINT i = 0; i < num_sections; i++, section++) {
+    PVOID section_start = RVAToAddr(section->VirtualAddress);
+    DWORD size = section->Misc.VirtualSize;
+
+    if (!callback(*this, section, section_start, size, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+  // Check if there are any exports at all.
+  if (NULL == directory || 0 == size)
+    return true;
+
+  PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+                                        directory);
+  UINT ordinal_base = exports->Base;
+  UINT num_funcs = exports->NumberOfFunctions;
+  UINT num_names = exports->NumberOfNames;
+  PDWORD functions  = reinterpret_cast<PDWORD>(RVAToAddr(
+                          exports->AddressOfFunctions));
+  PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+  PWORD ordinals = reinterpret_cast<PWORD>(RVAToAddr(
+                       exports->AddressOfNameOrdinals));
+
+  for (UINT count = 0; count < num_funcs; count++) {
+    PVOID func = RVAToAddr(functions[count]);
+    if (NULL == func)
+      continue;
+
+    // Check for a name.
+    LPCSTR name = NULL;
+    UINT hint;
+    for (hint = 0; hint < num_names; hint++) {
+      if (ordinals[hint] == count) {
+        name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
+        break;
+      }
+    }
+
+    if (name == NULL)
+      hint = 0;
+
+    // Check for forwarded exports.
+    LPCSTR forward = NULL;
+    if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
+        reinterpret_cast<char*>(func) <= reinterpret_cast<char*>(directory) +
+            size) {
+      forward = reinterpret_cast<LPCSTR>(func);
+      func = 0;
+    }
+
+    if (!callback(*this, ordinal_base + count, hint, name, func, forward,
+                  cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+  PIMAGE_BASE_RELOCATION base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+      directory);
+
+  if (!directory)
+    return true;
+
+  while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock &&
+         size >= base->SizeOfBlock) {
+    PWORD reloc = reinterpret_cast<PWORD>(base + 1);
+    UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
+        sizeof(WORD);
+
+    for (UINT i = 0; i < num_relocs; i++, reloc++) {
+      WORD type = *reloc >> 12;
+      PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
+
+      if (!callback(*this, type, address, cookie))
+        return false;
+    }
+
+    size -= base->SizeOfBlock;
+    base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+               reinterpret_cast<char*>(base) + base->SizeOfBlock);
+  }
+
+  return true;
+}
+
+bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
+                               PVOID cookie) const {
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
+  PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
+
+  if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
+    return true;
+
+  for (; import->FirstThunk; import++) {
+    LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
+    PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                                       RVAToAddr(import->OriginalFirstThunk));
+    PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                                RVAToAddr(import->FirstThunk));
+
+    if (!callback(*this, module_name, name_table, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
+                                 LPCSTR module_name,
+                                 PIMAGE_THUNK_DATA name_table,
+                                 PIMAGE_THUNK_DATA iat, PVOID cookie) const {
+  if (NULL == name_table)
+    return false;
+
+  for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
+    LPCSTR name = NULL;
+    WORD ordinal = 0;
+    WORD hint = 0;
+
+    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+    } else {
+      PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+          RVAToAddr(name_table->u1.ForwarderString));
+
+      hint = import->Hint;
+      name = reinterpret_cast<LPCSTR>(&import->Name);
+    }
+
+    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const {
+  EnumAllImportsStorage temp = { callback, cookie };
+  return EnumImportChunks(ProcessImportChunk, &temp);
+}
+
+bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+                                    PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(
+                        IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+  PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
+
+  if (directory == NULL || size == 0)
+    return true;
+
+  for (; delay_descriptor->rvaHmod; delay_descriptor++) {
+    PIMAGE_THUNK_DATA name_table;
+    PIMAGE_THUNK_DATA iat;
+    PIMAGE_THUNK_DATA bound_iat;    // address of the optional bound IAT
+    PIMAGE_THUNK_DATA unload_iat;   // address of optional copy of original IAT
+    LPCSTR module_name;
+
+    // check if VC7-style imports, using RVAs instead of
+    // VC6-style addresses.
+    bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+    if (rvas) {
+      module_name = reinterpret_cast<LPCSTR>(
+                        RVAToAddr(delay_descriptor->rvaDLLName));
+      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       RVAToAddr(delay_descriptor->rvaINT));
+      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                RVAToAddr(delay_descriptor->rvaIAT));
+      bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                      RVAToAddr(delay_descriptor->rvaBoundIAT));
+      unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       RVAToAddr(delay_descriptor->rvaUnloadIAT));
+    } else {
+#pragma warning(push)
+#pragma warning(disable: 4312)
+      // These casts generate warnings because they are 32 bit specific.
+      module_name = reinterpret_cast<LPCSTR>(delay_descriptor->rvaDLLName);
+      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       delay_descriptor->rvaINT);
+      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(delay_descriptor->rvaIAT);
+      bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                      delay_descriptor->rvaBoundIAT);
+      unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       delay_descriptor->rvaUnloadIAT);
+#pragma warning(pop)
+    }
+
+    if (!callback(*this, delay_descriptor, module_name, name_table, iat,
+                  bound_iat, unload_iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
+                                      PImgDelayDescr delay_descriptor,
+                                      LPCSTR module_name,
+                                      PIMAGE_THUNK_DATA name_table,
+                                      PIMAGE_THUNK_DATA iat,
+                                      PIMAGE_THUNK_DATA bound_iat,
+                                      PIMAGE_THUNK_DATA unload_iat,
+                                      PVOID cookie) const {
+  UNREFERENCED_PARAMETER(bound_iat);
+  UNREFERENCED_PARAMETER(unload_iat);
+
+  for (; name_table->u1.Ordinal; name_table++, iat++) {
+    LPCSTR name = NULL;
+    WORD ordinal = 0;
+    WORD hint = 0;
+
+    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+    } else {
+      PIMAGE_IMPORT_BY_NAME import;
+      bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+      if (rvas) {
+        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+                     RVAToAddr(name_table->u1.ForwarderString));
+      } else {
+#pragma warning(push)
+#pragma warning(disable: 4312)
+        // This cast generates a warning because it is 32 bit specific.
+        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+                     name_table->u1.ForwarderString);
+#pragma warning(pop)
+      }
+
+      hint = import->Hint;
+      name = reinterpret_cast<LPCSTR>(&import->Name);
+    }
+
+    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
+                                  PVOID cookie) const {
+  EnumAllImportsStorage temp = { callback, cookie };
+  return EnumDelayImportChunks(ProcessDelayImportChunk, &temp);
+}
+
+bool PEImage::VerifyMagic() const {
+  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+    return false;
+
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
+    return false;
+
+  if (nt_headers->FileHeader.SizeOfOptionalHeader !=
+      sizeof(IMAGE_OPTIONAL_HEADER))
+    return false;
+
+  if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+    return false;
+
+  return true;
+}
+
+bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const {
+  LPVOID address = RVAToAddr(rva);
+  return ImageAddrToOnDiskOffset(address, on_disk_offset);
+}
+
+bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
+                                      DWORD *on_disk_offset) const {
+  if (NULL == address)
+    return false;
+
+  // Get the section that this address belongs to.
+  PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
+  if (NULL == section_header)
+    return false;
+
+  // Don't follow the virtual RVAToAddr, use the one on the base.
+  DWORD offset_within_section =
+      static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
+      static_cast<DWORD>(reinterpret_cast<uintptr_t>(
+          PEImage::RVAToAddr(section_header->VirtualAddress)));
+
+  *on_disk_offset = section_header->PointerToRawData + offset_within_section;
+  return true;
+}
+
+PVOID PEImage::RVAToAddr(DWORD rva) const {
+  if (rva == 0)
+    return NULL;
+
+  return reinterpret_cast<char*>(module_) + rva;
+}
+
+PVOID PEImageAsData::RVAToAddr(DWORD rva) const {
+  if (rva == 0)
+    return NULL;
+
+  PVOID in_memory = PEImage::RVAToAddr(rva);
+  DWORD disk_offset;
+
+  if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
+    return NULL;
+
+  return PEImage::RVAToAddr(disk_offset);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image.h b/base/win/pe_image.h
new file mode 100644
index 0000000..343d286
--- /dev/null
+++ b/base/win/pe_image.h
@@ -0,0 +1,269 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was adapted from GreenBorder's Code.
+// To understand what this class is about (for other than well known functions
+// as GetProcAddress), a good starting point is "An In-Depth Look into the
+// Win32 Portable Executable File Format" by Matt Pietrek:
+// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
+
+#ifndef BASE_WIN_PE_IMAGE_H_
+#define BASE_WIN_PE_IMAGE_H_
+
+#include <windows.h>
+
+#if defined(_WIN32_WINNT_WIN8)
+// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
+#undef FACILITY_VISUALCPP
+#endif
+#include <DelayIMP.h>
+
+namespace base {
+namespace win {
+
+// This class is a wrapper for the Portable Executable File Format (PE).
+// Its main purpose is to provide an easy way to work with imports and exports
+// from a file, mapped in memory as image.
+class PEImage {
+ public:
+  // Callback to enumerate sections.
+  // cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumSectionsFunction)(const PEImage &image,
+                                       PIMAGE_SECTION_HEADER header,
+                                       PVOID section_start, DWORD section_size,
+                                       PVOID cookie);
+
+  // Callback to enumerate exports.
+  // function is the actual address of the symbol. If forward is not null, it
+  // contains the dll and symbol to forward this export to. cookie is the value
+  // passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumExportsFunction)(const PEImage &image, DWORD ordinal,
+                                      DWORD hint, LPCSTR name, PVOID function,
+                                      LPCSTR forward, PVOID cookie);
+
+  // Callback to enumerate import blocks.
+  // name_table and iat point to the imports name table and address table for
+  // this block. cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumImportChunksFunction)(const PEImage &image, LPCSTR module,
+                                           PIMAGE_THUNK_DATA name_table,
+                                           PIMAGE_THUNK_DATA iat, PVOID cookie);
+
+  // Callback to enumerate imports.
+  // module is the dll that exports this symbol. cookie is the value passed to
+  // the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumImportsFunction)(const PEImage &image, LPCSTR module,
+                                      DWORD ordinal, LPCSTR name, DWORD hint,
+                                      PIMAGE_THUNK_DATA iat, PVOID cookie);
+
+  // Callback to enumerate dalayed import blocks.
+  // module is the dll that exports this block of symbols. cookie is the value
+  // passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumDelayImportChunksFunction)(const PEImage &image,
+                                                PImgDelayDescr delay_descriptor,
+                                                LPCSTR module,
+                                                PIMAGE_THUNK_DATA name_table,
+                                                PIMAGE_THUNK_DATA iat,
+                                                PIMAGE_THUNK_DATA bound_iat,
+                                                PIMAGE_THUNK_DATA unload_iat,
+                                                PVOID cookie);
+
+  // Callback to enumerate relocations.
+  // cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumRelocsFunction)(const PEImage &image, WORD type,
+                                     PVOID address, PVOID cookie);
+
+  explicit PEImage(HMODULE module) : module_(module) {}
+  explicit PEImage(const void* module) {
+    module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
+  }
+
+  virtual ~PEImage() {}
+
+  // Gets the HMODULE for this object.
+  HMODULE module() const;
+
+  // Sets this object's HMODULE.
+  void set_module(HMODULE module);
+
+  // Checks if this symbol is actually an ordinal.
+  static bool IsOrdinal(LPCSTR name);
+
+  // Converts a named symbol to the corresponding ordinal.
+  static WORD ToOrdinal(LPCSTR name);
+
+  // Returns the DOS_HEADER for this PE.
+  PIMAGE_DOS_HEADER GetDosHeader() const;
+
+  // Returns the NT_HEADER for this PE.
+  PIMAGE_NT_HEADERS GetNTHeaders() const;
+
+  // Returns number of sections of this PE.
+  WORD GetNumSections() const;
+
+  // Returns the header for a given section.
+  // returns NULL if there is no such section.
+  PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
+
+  // Returns the size of a given directory entry.
+  DWORD GetImageDirectoryEntrySize(UINT directory) const;
+
+  // Returns the address of a given directory entry.
+  PVOID GetImageDirectoryEntryAddr(UINT directory) const;
+
+  // Returns the section header for a given address.
+  // Use: s = image.GetImageSectionFromAddr(a);
+  // Post: 's' is the section header of the section that contains 'a'
+  //       or NULL if there is no such section.
+  PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
+
+  // Returns the section header for a given section.
+  PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
+
+  // Returns the first block of imports.
+  PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
+
+  // Returns the exports directory.
+  PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
+
+  // Returns the debug id (guid+age).
+  bool GetDebugId(LPGUID guid, LPDWORD age) const;
+
+  // Returns a given export entry.
+  // Use: e = image.GetExportEntry(f);
+  // Pre: 'f' is either a zero terminated string or ordinal
+  // Post: 'e' is a pointer to the export directory entry
+  //       that contains 'f's export RVA, or NULL if 'f'
+  //       is not exported from this image
+  PDWORD GetExportEntry(LPCSTR name) const;
+
+  // Returns the address for a given exported symbol.
+  // Use: p = image.GetProcAddress(f);
+  // Pre: 'f' is either a zero terminated string or ordinal.
+  // Post: if 'f' is a non-forwarded export from image, 'p' is
+  //       the exported function. If 'f' is a forwarded export
+  //       then p is the special value 0xFFFFFFFF. In this case
+  //       RVAToAddr(*GetExportEntry) can be used to resolve
+  //       the string that describes the forward.
+  FARPROC GetProcAddress(LPCSTR function_name) const;
+
+  // Retrieves the ordinal for a given exported symbol.
+  // Returns true if the symbol was found.
+  bool GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const;
+
+  // Enumerates PE sections.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE exports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE imports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE import blocks.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const;
+
+  // Enumerates the imports from a single PE import block.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumOneImportChunk(EnumImportsFunction callback, LPCSTR module_name,
+                          PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat,
+                          PVOID cookie) const;
+
+
+  // Enumerates PE delay imports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE delay import blocks.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+                             PVOID cookie) const;
+
+  // Enumerates imports from a single PE delay import block.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumOneDelayImportChunk(EnumImportsFunction callback,
+                               PImgDelayDescr delay_descriptor,
+                               LPCSTR module_name,
+                               PIMAGE_THUNK_DATA name_table,
+                               PIMAGE_THUNK_DATA iat,
+                               PIMAGE_THUNK_DATA bound_iat,
+                               PIMAGE_THUNK_DATA unload_iat,
+                               PVOID cookie) const;
+
+  // Enumerates PE relocation entries.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
+
+  // Verifies the magic values on the PE file.
+  // Returns true if all values are correct.
+  bool VerifyMagic() const;
+
+  // Converts an rva value to the appropriate address.
+  virtual PVOID RVAToAddr(DWORD rva) const;
+
+  // Converts an rva value to an offset on disk.
+  // Returns true on success.
+  bool ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const;
+
+  // Converts an address to an offset on disk.
+  // Returns true on success.
+  bool ImageAddrToOnDiskOffset(LPVOID address, DWORD *on_disk_offset) const;
+
+ private:
+  HMODULE module_;
+};
+
+// This class is an extension to the PEImage class that allows working with PE
+// files mapped as data instead of as image file.
+class PEImageAsData : public PEImage {
+ public:
+  explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
+
+  PVOID RVAToAddr(DWORD rva) const override;
+};
+
+inline bool PEImage::IsOrdinal(LPCSTR name) {
+  return reinterpret_cast<uintptr_t>(name) <= 0xFFFF;
+}
+
+inline WORD PEImage::ToOrdinal(LPCSTR name) {
+  return static_cast<WORD>(reinterpret_cast<intptr_t>(name));
+}
+
+inline HMODULE PEImage::module() const {
+  return module_;
+}
+
+inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
+  return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
+             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
+}
+
+inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
+  return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_PE_IMAGE_H_
diff --git a/base/win/pe_image_test.cc b/base/win/pe_image_test.cc
new file mode 100644
index 0000000..e374598
--- /dev/null
+++ b/base/win/pe_image_test.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include <cfgmgr32.h>
+#include <shellapi.h>
+
+extern "C" {
+
+__declspec(dllexport) void ExportFunc1() {
+  // Call into user32.dll.
+  HWND dummy = GetDesktopWindow();
+  SetWindowTextA(dummy, "dummy");
+}
+
+__declspec(dllexport) void ExportFunc2() {
+  // Call into cfgmgr32.dll.
+  CM_MapCrToWin32Err(CR_SUCCESS, ERROR_SUCCESS);
+
+  // Call into shell32.dll.
+  SHFILEOPSTRUCT file_operation = {0};
+  SHFileOperation(&file_operation);
+
+  // Call into kernel32.dll.
+  HANDLE h = CreateEvent(NULL, FALSE, FALSE, NULL);
+  CloseHandle(h);
+}
+
+}  // extern "C"
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc
new file mode 100644
index 0000000..28b65a4
--- /dev/null
+++ b/base/win/pe_image_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for PEImage.
+#include <algorithm>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/win/pe_image.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Just counts the number of invocations.
+bool ImportsCallback(const PEImage& image,
+                     LPCSTR module,
+                     DWORD ordinal,
+                     LPCSTR name,
+                     DWORD hint,
+                     PIMAGE_THUNK_DATA iat,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool SectionsCallback(const PEImage& image,
+                      PIMAGE_SECTION_HEADER header,
+                      PVOID section_start,
+                      DWORD section_size,
+                      PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool RelocsCallback(const PEImage& image,
+                    WORD type,
+                    PVOID address,
+                    PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool ImportChunksCallback(const PEImage& image,
+                          LPCSTR module,
+                          PIMAGE_THUNK_DATA name_table,
+                          PIMAGE_THUNK_DATA iat,
+                          PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool DelayImportChunksCallback(const PEImage& image,
+                               PImgDelayDescr delay_descriptor,
+                               LPCSTR module,
+                               PIMAGE_THUNK_DATA name_table,
+                               PIMAGE_THUNK_DATA iat,
+                               PIMAGE_THUNK_DATA bound_iat,
+                               PIMAGE_THUNK_DATA unload_iat,
+                               PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool ExportsCallback(const PEImage& image,
+                     DWORD ordinal,
+                     DWORD hint,
+                     LPCSTR name,
+                     PVOID function,
+                     LPCSTR forward,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+}  // namespace
+
+// Tests that we are able to enumerate stuff from a PE file, and that
+// the actual number of items found matches an expected value.
+TEST(PEImageTest, EnumeratesPE) {
+  base::FilePath pe_image_test_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &pe_image_test_path));
+  pe_image_test_path = pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image"));
+
+#if defined(ARCH_CPU_64_BITS)
+  pe_image_test_path =
+      pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_64.dll"));
+  const int sections = 6;
+  const int imports_dlls = 2;
+  const int delay_dlls = 2;
+  const int exports = 2;
+  const int imports = 69;
+  const int delay_imports = 2;
+  const int relocs = 632;
+#else
+  pe_image_test_path =
+      pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll"));
+  const int sections = 5;
+  const int imports_dlls = 2;
+  const int delay_dlls = 2;
+  const int exports = 2;
+  const int imports = 66;
+  const int delay_imports = 2;
+  const int relocs = 1586;
+#endif
+
+  HMODULE module = LoadLibrary(pe_image_test_path.value().c_str());
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  int count = 0;
+  EXPECT_TRUE(pe.VerifyMagic());
+
+  pe.EnumSections(SectionsCallback, &count);
+  EXPECT_EQ(sections, count);
+
+  count = 0;
+  pe.EnumImportChunks(ImportChunksCallback, &count);
+  EXPECT_EQ(imports_dlls, count);
+
+  count = 0;
+  pe.EnumDelayImportChunks(DelayImportChunksCallback, &count);
+  EXPECT_EQ(delay_dlls, count);
+
+  count = 0;
+  pe.EnumExports(ExportsCallback, &count);
+  EXPECT_EQ(exports, count);
+
+  count = 0;
+  pe.EnumAllImports(ImportsCallback, &count);
+  EXPECT_EQ(imports, count);
+
+  count = 0;
+  pe.EnumAllDelayImports(ImportsCallback, &count);
+  EXPECT_EQ(delay_imports, count);
+
+  count = 0;
+  pe.EnumRelocs(RelocsCallback, &count);
+  EXPECT_EQ(relocs, count);
+
+  FreeLibrary(module);
+}
+
+// Tests that we can locate an specific exported symbol, by name and by ordinal.
+TEST(PEImageTest, RetrievesExports) {
+  HMODULE module = LoadLibrary(L"advapi32.dll");
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  WORD ordinal;
+
+  EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal));
+
+  FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW");
+  FARPROC address2 = pe.GetProcAddress(reinterpret_cast<char*>(ordinal));
+  EXPECT_TRUE(address1 != NULL);
+  EXPECT_TRUE(address2 != NULL);
+  EXPECT_TRUE(address1 == address2);
+
+  FreeLibrary(module);
+}
+
+// Test that we can get debug id out of a module.
+TEST(PEImageTest, GetDebugId) {
+  HMODULE module = LoadLibrary(L"advapi32.dll");
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  GUID guid = {0};
+  DWORD age = 0;
+  EXPECT_TRUE(pe.GetDebugId(&guid, &age));
+
+  GUID empty_guid = {0};
+  EXPECT_TRUE(!IsEqualGUID(empty_guid, guid));
+  EXPECT_NE(0U, age);
+  FreeLibrary(module);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/registry.cc b/base/win/registry.cc
new file mode 100644
index 0000000..47afcbf
--- /dev/null
+++ b/base/win/registry.cc
@@ -0,0 +1,680 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/registry.h"
+
+#include <shlwapi.h>
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// RegEnumValue() reports the number of characters from the name that were
+// written to the buffer, not how many there are. This constant is the maximum
+// name size, such that a buffer with this size should read any name.
+const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
+
+// Registry values are read as BYTE* but can have wchar_t* data whose last
+// wchar_t is truncated. This function converts the reported |byte_size| to
+// a size in wchar_t that can store a truncated wchar_t if necessary.
+inline DWORD to_wchar_size(DWORD byte_size) {
+  return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
+}
+
+// Mask to pull WOW64 access flags out of REGSAM access.
+const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
+
+}  // namespace
+
+// Watches for modifications to a key.
+class RegKey::Watcher : public ObjectWatcher::Delegate {
+ public:
+  explicit Watcher(RegKey* owner) : owner_(owner) {}
+  ~Watcher() override {}
+
+  bool StartWatching(HKEY key, const ChangeCallback& callback);
+
+  // Implementation of ObjectWatcher::Delegate.
+  void OnObjectSignaled(HANDLE object) override {
+    DCHECK(watch_event_.IsValid() && watch_event_.Get() == object);
+    ChangeCallback callback = callback_;
+    callback_.Reset();
+    callback.Run();
+  }
+
+ private:
+  RegKey* owner_;
+  ScopedHandle watch_event_;
+  ObjectWatcher object_watcher_;
+  ChangeCallback callback_;
+  DISALLOW_COPY_AND_ASSIGN(Watcher);
+};
+
+bool RegKey::Watcher::StartWatching(HKEY key, const ChangeCallback& callback) {
+  DCHECK(key);
+  DCHECK(callback_.is_null());
+
+  if (!watch_event_.IsValid())
+    watch_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
+
+  if (!watch_event_.IsValid())
+    return false;
+
+  DWORD filter = REG_NOTIFY_CHANGE_NAME |
+                 REG_NOTIFY_CHANGE_ATTRIBUTES |
+                 REG_NOTIFY_CHANGE_LAST_SET |
+                 REG_NOTIFY_CHANGE_SECURITY;
+
+  // Watch the registry key for a change of value.
+  LONG result = RegNotifyChangeKeyValue(key, TRUE, filter, watch_event_.Get(),
+                                        TRUE);
+  if (result != ERROR_SUCCESS) {
+    watch_event_.Close();
+    return false;
+  }
+
+  callback_ = callback;
+  return object_watcher_.StartWatching(watch_event_.Get(), this);
+}
+
+// RegKey ----------------------------------------------------------------------
+
+RegKey::RegKey() : key_(NULL), wow64access_(0) {
+}
+
+RegKey::RegKey(HKEY key) : key_(key), wow64access_(0) {
+}
+
+RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
+    : key_(NULL),
+      wow64access_(0) {
+  if (rootkey) {
+    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
+      Create(rootkey, subkey, access);
+    else
+      Open(rootkey, subkey, access);
+  } else {
+    DCHECK(!subkey);
+    wow64access_ = access & kWow64AccessMask;
+  }
+}
+
+RegKey::~RegKey() {
+  Close();
+}
+
+LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+  DWORD disposition_value;
+  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
+}
+
+LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+                                   DWORD* disposition, REGSAM access) {
+  DCHECK(rootkey && subkey && access && disposition);
+  HKEY subhkey = NULL;
+  LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
+                               REG_OPTION_NON_VOLATILE, access, NULL, &subhkey,
+                               disposition);
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subhkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+
+  return result;
+}
+
+LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
+  DCHECK(name && access);
+  // After the application has accessed an alternate registry view using one of
+  // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+  // (create, delete, or open) on child registry keys must explicitly use the
+  // same flag. Otherwise, there can be unexpected behavior.
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  if ((access & kWow64AccessMask) != wow64access_) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+  HKEY subkey = NULL;
+  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
+                               access, NULL, &subkey, NULL);
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+
+  return result;
+}
+
+LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+  DCHECK(rootkey && subkey && access);
+  HKEY subhkey = NULL;
+
+  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subhkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+
+  return result;
+}
+
+LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
+  DCHECK(relative_key_name && access);
+  // After the application has accessed an alternate registry view using one of
+  // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+  // (create, delete, or open) on child registry keys must explicitly use the
+  // same flag. Otherwise, there can be unexpected behavior.
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  if ((access & kWow64AccessMask) != wow64access_) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+  HKEY subkey = NULL;
+  LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
+
+  // We have to close the current opened key before replacing it with the new
+  // one.
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+  return result;
+}
+
+void RegKey::Close() {
+  if (key_) {
+    ::RegCloseKey(key_);
+    key_ = NULL;
+    wow64access_ = 0;
+  }
+}
+
+// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
+void RegKey::Set(HKEY key) {
+  if (key_ != key) {
+    Close();
+    key_ = key;
+  }
+}
+
+HKEY RegKey::Take() {
+  DCHECK_EQ(wow64access_, 0u);
+  HKEY key = key_;
+  key_ = NULL;
+  return key;
+}
+
+bool RegKey::HasValue(const wchar_t* name) const {
+  return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
+}
+
+DWORD RegKey::GetValueCount() const {
+  DWORD count = 0;
+  LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                                NULL, NULL, NULL, NULL);
+  return (result == ERROR_SUCCESS) ? count : 0;
+}
+
+LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
+  wchar_t buf[256];
+  DWORD bufsize = arraysize(buf);
+  LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
+  if (r == ERROR_SUCCESS)
+    *name = buf;
+
+  return r;
+}
+
+LONG RegKey::DeleteKey(const wchar_t* name) {
+  DCHECK(key_);
+  DCHECK(name);
+  HKEY subkey = NULL;
+
+  // Verify the key exists before attempting delete to replicate previous
+  // behavior.
+  LONG result =
+      RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
+  if (result != ERROR_SUCCESS)
+    return result;
+  RegCloseKey(subkey);
+
+  return RegDelRecurse(key_, std::wstring(name), wow64access_);
+}
+
+LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
+  DCHECK(key_);
+  DCHECK(name);
+
+  HKEY target_key = NULL;
+  LONG result = RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_,
+                             &target_key);
+
+  if (result != ERROR_SUCCESS)
+    return result;
+
+  DWORD count = 0;
+  result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                           NULL, NULL, NULL, NULL);
+
+  RegCloseKey(target_key);
+
+  if (result != ERROR_SUCCESS)
+    return result;
+
+  if (count == 0)
+    return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
+
+  return ERROR_DIR_NOT_EMPTY;
+}
+
+LONG RegKey::DeleteValue(const wchar_t* value_name) {
+  DCHECK(key_);
+  LONG result = RegDeleteValue(key_, value_name);
+  return result;
+}
+
+LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
+  DCHECK(out_value);
+  DWORD type = REG_DWORD;
+  DWORD size = sizeof(DWORD);
+  DWORD local_value = 0;
+  LONG result = ReadValue(name, &local_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
+      *out_value = local_value;
+    else
+      result = ERROR_CANTREAD;
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
+  DCHECK(out_value);
+  DWORD type = REG_QWORD;
+  int64 local_value = 0;
+  DWORD size = sizeof(local_value);
+  LONG result = ReadValue(name, &local_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if ((type == REG_QWORD || type == REG_BINARY) &&
+        size == sizeof(local_value))
+      *out_value = local_value;
+    else
+      result = ERROR_CANTREAD;
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
+  DCHECK(out_value);
+  const size_t kMaxStringLength = 1024;  // This is after expansion.
+  // Use the one of the other forms of ReadValue if 1024 is too small for you.
+  wchar_t raw_value[kMaxStringLength];
+  DWORD type = REG_SZ, size = sizeof(raw_value);
+  LONG result = ReadValue(name, raw_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if (type == REG_SZ) {
+      *out_value = raw_value;
+    } else if (type == REG_EXPAND_SZ) {
+      wchar_t expanded[kMaxStringLength];
+      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
+      // Success: returns the number of wchar_t's copied
+      // Fail: buffer too small, returns the size required
+      // Fail: other, returns 0
+      if (size == 0 || size > kMaxStringLength) {
+        result = ERROR_MORE_DATA;
+      } else {
+        *out_value = expanded;
+      }
+    } else {
+      // Not a string. Oops.
+      result = ERROR_CANTREAD;
+    }
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadValue(const wchar_t* name,
+                       void* data,
+                       DWORD* dsize,
+                       DWORD* dtype) const {
+  LONG result = RegQueryValueEx(key_, name, 0, dtype,
+                                reinterpret_cast<LPBYTE>(data), dsize);
+  return result;
+}
+
+LONG RegKey::ReadValues(const wchar_t* name,
+                        std::vector<std::wstring>* values) {
+  values->clear();
+
+  DWORD type = REG_MULTI_SZ;
+  DWORD size = 0;
+  LONG result = ReadValue(name, NULL, &size, &type);
+  if (FAILED(result) || size == 0)
+    return result;
+
+  if (type != REG_MULTI_SZ)
+    return ERROR_CANTREAD;
+
+  std::vector<wchar_t> buffer(size / sizeof(wchar_t));
+  result = ReadValue(name, &buffer[0], &size, NULL);
+  if (FAILED(result) || size == 0)
+    return result;
+
+  // Parse the double-null-terminated list of strings.
+  // Note: This code is paranoid to not read outside of |buf|, in the case where
+  // it may not be properly terminated.
+  const wchar_t* entry = &buffer[0];
+  const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
+  while (entry < buffer_end && entry[0] != '\0') {
+    const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
+    values->push_back(std::wstring(entry, entry_end));
+    entry = entry_end + 1;
+  }
+  return 0;
+}
+
+LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
+  return WriteValue(
+      name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
+}
+
+LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
+  return WriteValue(name, in_value,
+      static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
+}
+
+LONG RegKey::WriteValue(const wchar_t* name,
+                        const void* data,
+                        DWORD dsize,
+                        DWORD dtype) {
+  DCHECK(data || !dsize);
+
+  LONG result = RegSetValueEx(key_, name, 0, dtype,
+      reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
+  return result;
+}
+
+bool RegKey::StartWatching(const ChangeCallback& callback) {
+  if (!key_watcher_)
+    key_watcher_.reset(new Watcher(this));
+
+  if (!key_watcher_.get()->StartWatching(key_, callback))
+    return false;
+
+  return true;
+}
+
+// static
+LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
+                                   const wchar_t* lpSubKey,
+                                   REGSAM samDesired,
+                                   DWORD Reserved) {
+  typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
+
+  RegDeleteKeyExPtr reg_delete_key_ex_func =
+      reinterpret_cast<RegDeleteKeyExPtr>(
+          GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
+
+  if (reg_delete_key_ex_func)
+    return reg_delete_key_ex_func(hKey, lpSubKey, samDesired, Reserved);
+
+  // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
+  return RegDeleteKey(hKey, lpSubKey);
+}
+
+// static
+LONG RegKey::RegDelRecurse(HKEY root_key,
+                           const std::wstring& name,
+                           REGSAM access) {
+  // First, see if the key can be deleted without having to recurse.
+  LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+  if (result == ERROR_SUCCESS)
+    return result;
+
+  HKEY target_key = NULL;
+  result = RegOpenKeyEx(
+      root_key, name.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key);
+
+  if (result == ERROR_FILE_NOT_FOUND)
+    return ERROR_SUCCESS;
+  if (result != ERROR_SUCCESS)
+    return result;
+
+  std::wstring subkey_name(name);
+
+  // Check for an ending slash and add one if it is missing.
+  if (!name.empty() && subkey_name[name.length() - 1] != L'\\')
+    subkey_name += L"\\";
+
+  // Enumerate the keys
+  result = ERROR_SUCCESS;
+  const DWORD kMaxKeyNameLength = MAX_PATH;
+  const size_t base_key_length = subkey_name.length();
+  std::wstring key_name;
+  while (result == ERROR_SUCCESS) {
+    DWORD key_size = kMaxKeyNameLength;
+    result = RegEnumKeyEx(target_key,
+                          0,
+                          WriteInto(&key_name, kMaxKeyNameLength),
+                          &key_size,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL);
+
+    if (result != ERROR_SUCCESS)
+      break;
+
+    key_name.resize(key_size);
+    subkey_name.resize(base_key_length);
+    subkey_name += key_name;
+
+    if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
+      break;
+  }
+
+  RegCloseKey(target_key);
+
+  // Try again to delete the key.
+  result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+
+  return result;
+}
+
+// RegistryValueIterator ------------------------------------------------------
+
+RegistryValueIterator::RegistryValueIterator(HKEY root_key,
+                                             const wchar_t* folder_key,
+                                             REGSAM wow64access)
+    : name_(MAX_PATH, L'\0'),
+      value_(MAX_PATH, L'\0') {
+  Initialize(root_key, folder_key, wow64access);
+}
+
+RegistryValueIterator::RegistryValueIterator(HKEY root_key,
+                                             const wchar_t* folder_key)
+    : name_(MAX_PATH, L'\0'),
+      value_(MAX_PATH, L'\0') {
+  Initialize(root_key, folder_key, 0);
+}
+
+void RegistryValueIterator::Initialize(HKEY root_key,
+                                       const wchar_t* folder_key,
+                                       REGSAM wow64access) {
+  DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
+  LONG result =
+      RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
+  if (result != ERROR_SUCCESS) {
+    key_ = NULL;
+  } else {
+    DWORD count = 0;
+    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                               NULL, NULL, NULL, NULL);
+
+    if (result != ERROR_SUCCESS) {
+      ::RegCloseKey(key_);
+      key_ = NULL;
+    } else {
+      index_ = count - 1;
+    }
+  }
+
+  Read();
+}
+
+RegistryValueIterator::~RegistryValueIterator() {
+  if (key_)
+    ::RegCloseKey(key_);
+}
+
+DWORD RegistryValueIterator::ValueCount() const {
+  DWORD count = 0;
+  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
+                                  &count, NULL, NULL, NULL, NULL);
+  if (result != ERROR_SUCCESS)
+    return 0;
+
+  return count;
+}
+
+bool RegistryValueIterator::Valid() const {
+  return key_ != NULL && index_ >= 0;
+}
+
+void RegistryValueIterator::operator++() {
+  --index_;
+  Read();
+}
+
+bool RegistryValueIterator::Read() {
+  if (Valid()) {
+    DWORD capacity = static_cast<DWORD>(name_.capacity());
+    DWORD name_size = capacity;
+    // |value_size_| is in bytes. Reserve the last character for a NUL.
+    value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
+    LONG result = ::RegEnumValue(
+        key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
+        reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+
+    if (result == ERROR_MORE_DATA) {
+      // Registry key names are limited to 255 characters and fit within
+      // MAX_PATH (which is 260) but registry value names can use up to 16,383
+      // characters and the value itself is not limited
+      // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
+      // ms724872(v=vs.85).aspx).
+      // Resize the buffers and retry if their size caused the failure.
+      DWORD value_size_in_wchars = to_wchar_size(value_size_);
+      if (value_size_in_wchars + 1 > value_.size())
+        value_.resize(value_size_in_wchars + 1, L'\0');
+      value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
+      name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
+      result = ::RegEnumValue(
+          key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
+          reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+    }
+
+    if (result == ERROR_SUCCESS) {
+      DCHECK_LT(to_wchar_size(value_size_), value_.size());
+      value_[to_wchar_size(value_size_)] = L'\0';
+      return true;
+    }
+  }
+
+  name_[0] = L'\0';
+  value_[0] = L'\0';
+  value_size_ = 0;
+  return false;
+}
+
+// RegistryKeyIterator --------------------------------------------------------
+
+RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
+                                         const wchar_t* folder_key) {
+  Initialize(root_key, folder_key, 0);
+}
+
+RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
+                                         const wchar_t* folder_key,
+                                         REGSAM wow64access) {
+  Initialize(root_key, folder_key, wow64access);
+}
+
+RegistryKeyIterator::~RegistryKeyIterator() {
+  if (key_)
+    ::RegCloseKey(key_);
+}
+
+DWORD RegistryKeyIterator::SubkeyCount() const {
+  DWORD count = 0;
+  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
+                                  NULL, NULL, NULL, NULL, NULL);
+  if (result != ERROR_SUCCESS)
+    return 0;
+
+  return count;
+}
+
+bool RegistryKeyIterator::Valid() const {
+  return key_ != NULL && index_ >= 0;
+}
+
+void RegistryKeyIterator::operator++() {
+  --index_;
+  Read();
+}
+
+bool RegistryKeyIterator::Read() {
+  if (Valid()) {
+    DWORD ncount = arraysize(name_);
+    FILETIME written;
+    LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
+                            NULL, &written);
+    if (ERROR_SUCCESS == r)
+      return true;
+  }
+
+  name_[0] = '\0';
+  return false;
+}
+
+void RegistryKeyIterator::Initialize(HKEY root_key,
+                                     const wchar_t* folder_key,
+                                     REGSAM wow64access) {
+  DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
+  LONG result =
+      RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
+  if (result != ERROR_SUCCESS) {
+    key_ = NULL;
+  } else {
+    DWORD count = 0;
+    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL);
+
+    if (result != ERROR_SUCCESS) {
+      ::RegCloseKey(key_);
+      key_ = NULL;
+    } else {
+      index_ = count - 1;
+    }
+  }
+
+  Read();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/registry.h b/base/win/registry.h
new file mode 100644
index 0000000..c3e015b
--- /dev/null
+++ b/base/win/registry.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_REGISTRY_H_
+#define BASE_WIN_REGISTRY_H_
+
+#include <windows.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/stl_util.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Utility class to read, write and manipulate the Windows Registry.
+// Registry vocabulary primer: a "key" is like a folder, in which there
+// are "values", which are <name, data> pairs, with an associated data type.
+//
+// Note:
+// ReadValue family of functions guarantee that the return arguments
+// are not touched in case of failure.
+class BASE_EXPORT RegKey {
+ public:
+  // Called from the MessageLoop when the key changes.
+  typedef base::Callback<void()> ChangeCallback;
+
+  RegKey();
+  explicit RegKey(HKEY key);
+  RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+  ~RegKey();
+
+  LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+
+  LONG CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+                             DWORD* disposition, REGSAM access);
+
+  // Creates a subkey or open it if it already exists.
+  LONG CreateKey(const wchar_t* name, REGSAM access);
+
+  // Opens an existing reg key.
+  LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+
+  // Opens an existing reg key, given the relative key name.
+  LONG OpenKey(const wchar_t* relative_key_name, REGSAM access);
+
+  // Closes this reg key.
+  void Close();
+
+  // Replaces the handle of the registry key and takes ownership of the handle.
+  void Set(HKEY key);
+
+  // Transfers ownership away from this object.
+  HKEY Take();
+
+  // Returns false if this key does not have the specified value, or if an error
+  // occurrs while attempting to access it.
+  bool HasValue(const wchar_t* value_name) const;
+
+  // Returns the number of values for this key, or 0 if the number cannot be
+  // determined.
+  DWORD GetValueCount() const;
+
+  // Determine the nth value's name.
+  LONG GetValueNameAt(int index, std::wstring* name) const;
+
+  // True while the key is valid.
+  bool Valid() const { return key_ != NULL; }
+
+  // Kill a key and everything that live below it; please be careful when using
+  // it.
+  LONG DeleteKey(const wchar_t* name);
+
+  // Deletes an empty subkey.  If the subkey has subkeys or values then this
+  // will fail.
+  LONG DeleteEmptyKey(const wchar_t* name);
+
+  // Deletes a single value within the key.
+  LONG DeleteValue(const wchar_t* name);
+
+  // Getters:
+
+  // Returns an int32 value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const;
+
+  // Returns an int64 value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadInt64(const wchar_t* name, int64* out_value) const;
+
+  // Returns a string value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValue(const wchar_t* name, std::wstring* out_value) const;
+
+  // Reads a REG_MULTI_SZ registry field into a vector of strings. Clears
+  // |values| initially and adds further strings to the list. Returns
+  // ERROR_CANTREAD if type is not REG_MULTI_SZ.
+  LONG ReadValues(const wchar_t* name, std::vector<std::wstring>* values);
+
+  // Returns raw data. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValue(const wchar_t* name,
+                 void* data,
+                 DWORD* dsize,
+                 DWORD* dtype) const;
+
+  // Setters:
+
+  // Sets an int32 value.
+  LONG WriteValue(const wchar_t* name, DWORD in_value);
+
+  // Sets a string value.
+  LONG WriteValue(const wchar_t* name, const wchar_t* in_value);
+
+  // Sets raw data, including type.
+  LONG WriteValue(const wchar_t* name,
+                  const void* data,
+                  DWORD dsize,
+                  DWORD dtype);
+
+  // Starts watching the key to see if any of its values have changed.
+  // The key must have been opened with the KEY_NOTIFY access privilege.
+  // Returns true on success.
+  // To stop watching, delete this RegKey object. To continue watching the
+  // object after the callback is invoked, call StartWatching again.
+  bool StartWatching(const ChangeCallback& callback);
+
+  HKEY Handle() const { return key_; }
+
+ private:
+  class Watcher;
+
+  // Calls RegDeleteKeyEx on supported platforms, alternatively falls back to
+  // RegDeleteKey.
+  static LONG RegDeleteKeyExWrapper(HKEY hKey,
+                                    const wchar_t* lpSubKey,
+                                    REGSAM samDesired,
+                                    DWORD Reserved);
+
+  // Recursively deletes a key and all of its subkeys.
+  static LONG RegDelRecurse(HKEY root_key,
+                            const std::wstring& name,
+                            REGSAM access);
+
+  HKEY key_;  // The registry key being iterated.
+  REGSAM wow64access_;
+  scoped_ptr<Watcher> key_watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegKey);
+};
+
+// Iterates the entries found in a particular folder on the registry.
+class BASE_EXPORT RegistryValueIterator {
+ public:
+  // Construct a Registry Value Iterator with default WOW64 access.
+  RegistryValueIterator(HKEY root_key, const wchar_t* folder_key);
+
+  // Construct a Registry Key Iterator with specific WOW64 access, one of
+  // KEY_WOW64_32KEY or KEY_WOW64_64KEY, or 0.
+  // Note: |wow64access| should be the same access used to open |root_key|
+  // previously, or a predefined key (e.g. HKEY_LOCAL_MACHINE).
+  // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  RegistryValueIterator(HKEY root_key,
+                        const wchar_t* folder_key,
+                        REGSAM wow64access);
+
+  ~RegistryValueIterator();
+
+  DWORD ValueCount() const;
+
+  // True while the iterator is valid.
+  bool Valid() const;
+
+  // Advances to the next registry entry.
+  void operator++();
+
+  const wchar_t* Name() const { return name_.c_str(); }
+  const wchar_t* Value() const { return vector_as_array(&value_); }
+  // ValueSize() is in bytes.
+  DWORD ValueSize() const { return value_size_; }
+  DWORD Type() const { return type_; }
+
+  int Index() const { return index_; }
+
+ private:
+  // Read in the current values.
+  bool Read();
+
+  void Initialize(HKEY root_key, const wchar_t* folder_key, REGSAM wow64access);
+
+  // The registry key being iterated.
+  HKEY key_;
+
+  // Current index of the iteration.
+  int index_;
+
+  // Current values.
+  std::wstring name_;
+  std::vector<wchar_t> value_;
+  DWORD value_size_;
+  DWORD type_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryValueIterator);
+};
+
+class BASE_EXPORT RegistryKeyIterator {
+ public:
+  // Construct a Registry Key Iterator with default WOW64 access.
+  RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key);
+
+  // Construct a Registry Value Iterator with specific WOW64 access, one of
+  // KEY_WOW64_32KEY or KEY_WOW64_64KEY, or 0.
+  // Note: |wow64access| should be the same access used to open |root_key|
+  // previously, or a predefined key (e.g. HKEY_LOCAL_MACHINE).
+  // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  RegistryKeyIterator(HKEY root_key,
+                      const wchar_t* folder_key,
+                      REGSAM wow64access);
+
+  ~RegistryKeyIterator();
+
+  DWORD SubkeyCount() const;
+
+  // True while the iterator is valid.
+  bool Valid() const;
+
+  // Advances to the next entry in the folder.
+  void operator++();
+
+  const wchar_t* Name() const { return name_; }
+
+  int Index() const { return index_; }
+
+ private:
+  // Read in the current values.
+  bool Read();
+
+  void Initialize(HKEY root_key, const wchar_t* folder_key, REGSAM wow64access);
+
+  // The registry key being iterated.
+  HKEY key_;
+
+  // Current index of the iteration.
+  int index_;
+
+  wchar_t name_[MAX_PATH];
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryKeyIterator);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_REGISTRY_H_
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
new file mode 100644
index 0000000..2257663
--- /dev/null
+++ b/base/win/registry_unittest.cc
@@ -0,0 +1,420 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/registry.h"
+
+#include <cstring>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+class RegistryTest : public testing::Test {
+ protected:
+#if defined(_WIN64)
+  static const REGSAM kNativeViewMask = KEY_WOW64_64KEY;
+  static const REGSAM kRedirectedViewMask = KEY_WOW64_32KEY;
+#else
+  static const REGSAM kNativeViewMask = KEY_WOW64_32KEY;
+  static const REGSAM kRedirectedViewMask = KEY_WOW64_64KEY;
+#endif  //  _WIN64
+
+  RegistryTest() {}
+  void SetUp() override {
+    // Create a temporary key.
+    RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+    key.DeleteKey(kRootKey);
+    ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+    ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+    foo_software_key_ = L"Software\\";
+    foo_software_key_ += kRootKey;
+    foo_software_key_ += L"\\Foo";
+  }
+
+  void TearDown() override {
+    // Clean up the temporary key.
+    RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+    ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+  }
+
+  static bool IsRedirectorPresent() {
+#if defined(_WIN64)
+    return true;
+#else
+    return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED;
+#endif
+  }
+
+  const wchar_t* const kRootKey = L"Base_Registry_Unittest";
+  std::wstring foo_software_key_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegistryTest);
+};
+
+// static
+const REGSAM RegistryTest::kNativeViewMask;
+const REGSAM RegistryTest::kRedirectedViewMask;
+
+TEST_F(RegistryTest, ValueTest) {
+  RegKey key;
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+
+  {
+    ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ | KEY_SET_VALUE));
+    ASSERT_TRUE(key.Valid());
+
+    const wchar_t kStringValueName[] = L"StringValue";
+    const wchar_t kDWORDValueName[] = L"DWORDValue";
+    const wchar_t kInt64ValueName[] = L"Int64Value";
+    const wchar_t kStringData[] = L"string data";
+    const DWORD kDWORDData = 0xdeadbabe;
+    const int64 kInt64Data = 0xdeadbabedeadbabeLL;
+
+    // Test value creation
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData));
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data,
+                                            sizeof(kInt64Data), REG_QWORD));
+    EXPECT_EQ(3U, key.GetValueCount());
+    EXPECT_TRUE(key.HasValue(kStringValueName));
+    EXPECT_TRUE(key.HasValue(kDWORDValueName));
+    EXPECT_TRUE(key.HasValue(kInt64ValueName));
+
+    // Test Read
+    std::wstring string_value;
+    DWORD dword_value = 0;
+    int64 int64_value = 0;
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
+    EXPECT_STREQ(kStringData, string_value.c_str());
+    EXPECT_EQ(kDWORDData, dword_value);
+    EXPECT_EQ(kInt64Data, int64_value);
+
+    // Make sure out args are not touched if ReadValue fails
+    const wchar_t* kNonExistent = L"NonExistent";
+    ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value));
+    ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value));
+    ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value));
+    EXPECT_STREQ(kStringData, string_value.c_str());
+    EXPECT_EQ(kDWORDData, dword_value);
+    EXPECT_EQ(kInt64Data, int64_value);
+
+    // Test delete
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName));
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName));
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName));
+    EXPECT_EQ(0U, key.GetValueCount());
+    EXPECT_FALSE(key.HasValue(kStringValueName));
+    EXPECT_FALSE(key.HasValue(kDWORDValueName));
+    EXPECT_FALSE(key.HasValue(kInt64ValueName));
+  }
+}
+
+TEST_F(RegistryTest, BigValueIteratorTest) {
+  RegKey key;
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                    KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key.Valid());
+
+  // Create a test value that is larger than MAX_PATH.
+  std::wstring data(MAX_PATH * 2, L'a');
+
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str()));
+
+  RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
+  ASSERT_TRUE(iterator.Valid());
+  EXPECT_STREQ(data.c_str(), iterator.Name());
+  EXPECT_STREQ(data.c_str(), iterator.Value());
+  // ValueSize() is in bytes, including NUL.
+  EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize());
+  ++iterator;
+  EXPECT_FALSE(iterator.Valid());
+}
+
+TEST_F(RegistryTest, TruncatedCharTest) {
+  RegKey key;
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                    KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key.Valid());
+
+  const wchar_t kName[] = L"name";
+  // kData size is not a multiple of sizeof(wchar_t).
+  const uint8 kData[] = { 1, 2, 3, 4, 5 };
+  EXPECT_EQ(5, arraysize(kData));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData,
+                                          arraysize(kData), REG_BINARY));
+
+  RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
+  ASSERT_TRUE(iterator.Valid());
+  EXPECT_STREQ(kName, iterator.Name());
+  // ValueSize() is in bytes.
+  ASSERT_EQ(arraysize(kData), iterator.ValueSize());
+  // Value() is NUL terminated.
+  int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t);
+  EXPECT_NE(L'\0', iterator.Value()[end-1]);
+  EXPECT_EQ(L'\0', iterator.Value()[end]);
+  EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData)));
+  ++iterator;
+  EXPECT_FALSE(iterator.Valid());
+}
+
+TEST_F(RegistryTest, RecursiveDelete) {
+  RegKey key;
+  // Create kRootKey->Foo
+  //                  \->Bar (TestValue)
+  //                     \->Foo (TestValue)
+  //                        \->Bar
+  //                           \->Foo
+  //                  \->Moo
+  //                  \->Foo
+  // and delete kRootKey->Foo
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+  foo_key += L"\\Bar";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar\\Foo"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar"));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Foo"));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L""));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+}
+
+// This test requires running as an Administrator as it tests redirected
+// registry writes to HKLM\Software
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
+// TODO(wfh): flaky test on Vista.  See http://crbug.com/377917
+TEST_F(RegistryTest, DISABLED_Wow64RedirectedFromNative) {
+  if (!IsRedirectorPresent())
+    return;
+
+  RegKey key;
+
+  // Test redirected key access from non-redirected.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_LOCAL_MACHINE,
+                       foo_software_key_.c_str(),
+                       KEY_WRITE | kRedirectedViewMask));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     foo_software_key_.c_str(),
+                     KEY_READ | kNativeViewMask));
+
+  // Open the non-redirected view of the parent and try to delete the test key.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kNativeViewMask));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+
+  // Open the redirected view and delete the key created above.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kRedirectedViewMask));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+}
+
+// Test for the issue found in http://crbug.com/384587 where OpenKey would call
+// Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
+// subsequent OpenKey call.
+TEST_F(RegistryTest, SameWowFlags) {
+  RegKey key;
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_READ | KEY_WOW64_64KEY));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.OpenKey(L"Microsoft",
+                        KEY_READ | KEY_WOW64_64KEY));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.OpenKey(L"Windows",
+                        KEY_READ | KEY_WOW64_64KEY));
+}
+
+// TODO(wfh): flaky test on Vista.  See http://crbug.com/377917
+TEST_F(RegistryTest, DISABLED_Wow64NativeFromRedirected) {
+  if (!IsRedirectorPresent())
+    return;
+  RegKey key;
+
+  // Test non-redirected key access from redirected.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_LOCAL_MACHINE,
+                       foo_software_key_.c_str(),
+                       KEY_WRITE | kNativeViewMask));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     foo_software_key_.c_str(),
+                     KEY_READ | kRedirectedViewMask));
+
+  // Open the redirected view of the parent and try to delete the test key
+  // from the non-redirected view.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kRedirectedViewMask));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kNativeViewMask));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+}
+
+TEST_F(RegistryTest, OpenSubKey) {
+  RegKey key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER,
+                     kRootKey,
+                     KEY_READ | KEY_CREATE_SUB_KEY));
+
+  ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo"));
+}
+
+class TestChangeDelegate {
+ public:
+   TestChangeDelegate() : called_(false) {}
+   ~TestChangeDelegate() {}
+
+   void OnKeyChanged() {
+     MessageLoop::current()->QuitWhenIdle();
+     called_ = true;
+   }
+
+   bool WasCalled() {
+     bool was_called = called_;
+     called_ = false;
+     return was_called;
+   }
+
+ private:
+  bool called_;
+};
+
+TEST_F(RegistryTest, ChangeCallback) {
+  RegKey key;
+  TestChangeDelegate delegate;
+  MessageLoop message_loop;
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+
+  ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged,
+                                     Unretained(&delegate))));
+  EXPECT_FALSE(delegate.WasCalled());
+
+  // Make some change.
+  RegKey key2;
+  ASSERT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key2.Valid());
+  EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name", L"data"));
+
+  // Allow delivery of the notification.
+  EXPECT_FALSE(delegate.WasCalled());
+  base::RunLoop().Run();
+
+  ASSERT_TRUE(delegate.WasCalled());
+  EXPECT_FALSE(delegate.WasCalled());
+
+  ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged,
+                                     Unretained(&delegate))));
+
+  // Change something else.
+  EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name2", L"data2"));
+  base::RunLoop().Run();
+  ASSERT_TRUE(delegate.WasCalled());
+
+  ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged,
+                                     Unretained(&delegate))));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(delegate.WasCalled());
+}
+
+}  // namespace
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/resource_util.cc b/base/win/resource_util.cc
new file mode 100644
index 0000000..0c10078
--- /dev/null
+++ b/base/win/resource_util.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/win/resource_util.h"
+
+namespace base {
+namespace win {
+
+bool GetResourceFromModule(HMODULE module,
+                           int resource_id,
+                           LPCTSTR resource_type,
+                           void** data,
+                           size_t* length) {
+  if (!module)
+    return false;
+
+  if (!IS_INTRESOURCE(resource_id)) {
+    NOTREACHED();
+    return false;
+  }
+
+  HRSRC hres_info = FindResource(module, MAKEINTRESOURCE(resource_id),
+                                 resource_type);
+  if (NULL == hres_info)
+    return false;
+
+  DWORD data_size = SizeofResource(module, hres_info);
+  HGLOBAL hres = LoadResource(module, hres_info);
+  if (!hres)
+    return false;
+
+  void* resource = LockResource(hres);
+  if (!resource)
+    return false;
+
+  *data = resource;
+  *length = static_cast<size_t>(data_size);
+  return true;
+}
+
+bool GetDataResourceFromModule(HMODULE module,
+                               int resource_id,
+                               void** data,
+                               size_t* length) {
+  return GetResourceFromModule(module, resource_id, L"BINDATA", data, length);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/resource_util.h b/base/win/resource_util.h
new file mode 100644
index 0000000..f3444ae
--- /dev/null
+++ b/base/win/resource_util.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains utility functions for accessing resources in external
+// files (DLLs) or embedded in the executable itself.
+
+#ifndef BASE_WIN_RESOURCE_UTIL_H__
+#define BASE_WIN_RESOURCE_UTIL_H__
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Function for getting a data resource of the specified |resource_type| from
+// a dll.  Some resources are optional, especially in unit tests, so this
+// returns false but doesn't raise an error if the resource can't be loaded.
+bool BASE_EXPORT GetResourceFromModule(HMODULE module,
+                                       int resource_id,
+                                       LPCTSTR resource_type,
+                                       void** data,
+                                       size_t* length);
+
+// Function for getting a data resource (BINDATA) from a dll.  Some
+// resources are optional, especially in unit tests, so this returns false
+// but doesn't raise an error if the resource can't be loaded.
+bool BASE_EXPORT GetDataResourceFromModule(HMODULE module,
+                                           int resource_id,
+                                           void** data,
+                                           size_t* length);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_RESOURCE_UTIL_H__
diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc
new file mode 100644
index 0000000..63ade0c
--- /dev/null
+++ b/base/win/scoped_bstr.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_bstr.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+ScopedBstr::ScopedBstr(const char16* non_bstr)
+    : bstr_(SysAllocString(non_bstr)) {
+}
+
+ScopedBstr::~ScopedBstr() {
+  COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
+  SysFreeString(bstr_);
+}
+
+void ScopedBstr::Reset(BSTR bstr) {
+  if (bstr != bstr_) {
+    // if |bstr_| is NULL, SysFreeString does nothing.
+    SysFreeString(bstr_);
+    bstr_ = bstr;
+  }
+}
+
+BSTR ScopedBstr::Release() {
+  BSTR bstr = bstr_;
+  bstr_ = NULL;
+  return bstr;
+}
+
+void ScopedBstr::Swap(ScopedBstr& bstr2) {
+  BSTR tmp = bstr_;
+  bstr_ = bstr2.bstr_;
+  bstr2.bstr_ = tmp;
+}
+
+BSTR* ScopedBstr::Receive() {
+  DCHECK(!bstr_) << "BSTR leak.";
+  return &bstr_;
+}
+
+BSTR ScopedBstr::Allocate(const char16* str) {
+  Reset(SysAllocString(str));
+  return bstr_;
+}
+
+BSTR ScopedBstr::AllocateBytes(size_t bytes) {
+  Reset(SysAllocStringByteLen(NULL, static_cast<UINT>(bytes)));
+  return bstr_;
+}
+
+void ScopedBstr::SetByteLen(size_t bytes) {
+  DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
+  uint32* data = reinterpret_cast<uint32*>(bstr_);
+  data[-1] = static_cast<uint32>(bytes);
+}
+
+size_t ScopedBstr::Length() const {
+  return SysStringLen(bstr_);
+}
+
+size_t ScopedBstr::ByteLength() const {
+  return SysStringByteLen(bstr_);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_bstr.h b/base/win/scoped_bstr.h
new file mode 100644
index 0000000..7c9f5df
--- /dev/null
+++ b/base/win/scoped_bstr.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_BSTR_H_
+#define BASE_WIN_SCOPED_BSTR_H_
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+// Manages a BSTR string pointer.
+// The class interface is based on scoped_ptr.
+class BASE_EXPORT ScopedBstr {
+ public:
+  ScopedBstr() : bstr_(NULL) {
+  }
+
+  // Constructor to create a new BSTR.
+  //
+  // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+  // be transferred - even though it compiles! ;-)
+  explicit ScopedBstr(const char16* non_bstr);
+  ~ScopedBstr();
+
+  // Give ScopedBstr ownership over an already allocated BSTR or NULL.
+  // If you need to allocate a new BSTR instance, use |allocate| instead.
+  void Reset(BSTR bstr = NULL);
+
+  // Releases ownership of the BSTR to the caller.
+  BSTR Release();
+
+  // Creates a new BSTR from a 16-bit C-style string.
+  //
+  // If you already have a BSTR and want to transfer ownership to the
+  // ScopedBstr instance, call |reset| instead.
+  //
+  // Returns a pointer to the new BSTR, or NULL if allocation failed.
+  BSTR Allocate(const char16* str);
+
+  // Allocates a new BSTR with the specified number of bytes.
+  // Returns a pointer to the new BSTR, or NULL if allocation failed.
+  BSTR AllocateBytes(size_t bytes);
+
+  // Sets the allocated length field of the already-allocated BSTR to be
+  // |bytes|.  This is useful when the BSTR was preallocated with e.g.
+  // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and then
+  // not all the bytes are being used.
+  //
+  // Note that if you want to set the length to a specific number of
+  // characters, you need to multiply by sizeof(wchar_t).  Oddly, there's no
+  // public API to set the length, so we do this ourselves by hand.
+  //
+  // NOTE: The actual allocated size of the BSTR MUST be >= bytes.  That
+  // responsibility is with the caller.
+  void SetByteLen(size_t bytes);
+
+  // Swap values of two ScopedBstr's.
+  void Swap(ScopedBstr& bstr2);
+
+  // Retrieves the pointer address.
+  // Used to receive BSTRs as out arguments (and take ownership).
+  // The function DCHECKs on the current value being NULL.
+  // Usage: GetBstr(bstr.Receive());
+  BSTR* Receive();
+
+  // Returns number of chars in the BSTR.
+  size_t Length() const;
+
+  // Returns the number of bytes allocated for the BSTR.
+  size_t ByteLength() const;
+
+  operator BSTR() const {
+    return bstr_;
+  }
+
+ protected:
+  BSTR bstr_;
+
+ private:
+  // Forbid comparison of ScopedBstr types.  You should never have the same
+  // BSTR owned by two different scoped_ptrs.
+  bool operator==(const ScopedBstr& bstr2) const;
+  bool operator!=(const ScopedBstr& bstr2) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedBstr);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_BSTR_H_
diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc
new file mode 100644
index 0000000..5f6f7df
--- /dev/null
+++ b/base/win/scoped_bstr_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_bstr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"123";
+static const wchar_t kTestString2[] = L"456789";
+size_t test1_len = arraysize(kTestString1) - 1;
+size_t test2_len = arraysize(kTestString2) - 1;
+
+void DumbBstrTests() {
+  ScopedBstr b;
+  EXPECT_TRUE(b == NULL);
+  EXPECT_EQ(0, b.Length());
+  EXPECT_EQ(0, b.ByteLength());
+  b.Reset(NULL);
+  EXPECT_TRUE(b == NULL);
+  EXPECT_TRUE(b.Release() == NULL);
+  ScopedBstr b2;
+  b.Swap(b2);
+  EXPECT_TRUE(b2 == NULL);
+}
+
+void GiveMeABstr(BSTR* ret) {
+  *ret = SysAllocString(kTestString1);
+}
+
+void BasicBstrTests() {
+  ScopedBstr b1(kTestString1);
+  EXPECT_EQ(test1_len, b1.Length());
+  EXPECT_EQ(test1_len * sizeof(kTestString1[0]), b1.ByteLength());
+
+  ScopedBstr b2;
+  b1.Swap(b2);
+  EXPECT_EQ(test1_len, b2.Length());
+  EXPECT_EQ(0, b1.Length());
+  EXPECT_EQ(0, lstrcmp(b2, kTestString1));
+  BSTR tmp = b2.Release();
+  EXPECT_TRUE(tmp != NULL);
+  EXPECT_EQ(0, lstrcmp(tmp, kTestString1));
+  EXPECT_TRUE(b2 == NULL);
+  SysFreeString(tmp);
+
+  GiveMeABstr(b2.Receive());
+  EXPECT_TRUE(b2 != NULL);
+  b2.Reset();
+  EXPECT_TRUE(b2.AllocateBytes(100) != NULL);
+  EXPECT_EQ(100, b2.ByteLength());
+  EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+  lstrcpy(static_cast<BSTR>(b2), kTestString1);
+  EXPECT_EQ(test1_len, lstrlen(b2));
+  EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+  b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0]));
+  EXPECT_EQ(b2.Length(), lstrlen(b2));
+
+  EXPECT_TRUE(b1.Allocate(kTestString2) != NULL);
+  EXPECT_EQ(test2_len, b1.Length());
+  b1.SetByteLen((test2_len - 1) * sizeof(kTestString2[0]));
+  EXPECT_EQ(test2_len - 1, b1.Length());
+}
+
+}  // namespace
+
+TEST(ScopedBstrTest, ScopedBstr) {
+  DumbBstrTests();
+  BasicBstrTests();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_co_mem.h b/base/win/scoped_co_mem.h
new file mode 100644
index 0000000..fc85114
--- /dev/null
+++ b/base/win/scoped_co_mem.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_CO_MEM_H_
+#define BASE_WIN_SCOPED_CO_MEM_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Simple scoped memory releaser class for COM allocated memory.
+// Example:
+//   base::win::ScopedCoMem<ITEMIDLIST> file_item;
+//   SHGetSomeInfo(&file_item, ...);
+//   ...
+//   return;  <-- memory released
+template<typename T>
+class ScopedCoMem {
+ public:
+  ScopedCoMem() : mem_ptr_(NULL) {}
+  ~ScopedCoMem() {
+    Reset(NULL);
+  }
+
+  T** operator&() {  // NOLINT
+    DCHECK(mem_ptr_ == NULL);  // To catch memory leaks.
+    return &mem_ptr_;
+  }
+
+  operator T*() {
+    return mem_ptr_;
+  }
+
+  T* operator->() {
+    DCHECK(mem_ptr_ != NULL);
+    return mem_ptr_;
+  }
+
+  const T* operator->() const {
+    DCHECK(mem_ptr_ != NULL);
+    return mem_ptr_;
+  }
+
+  void Reset(T* ptr) {
+    if (mem_ptr_)
+      CoTaskMemFree(mem_ptr_);
+    mem_ptr_ = ptr;
+  }
+
+  T* get() const {
+    return mem_ptr_;
+  }
+
+ private:
+  T* mem_ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCoMem);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_CO_MEM_H_
diff --git a/base/win/scoped_com_initializer.h b/base/win/scoped_com_initializer.h
new file mode 100644
index 0000000..92228ba
--- /dev/null
+++ b/base/win/scoped_com_initializer.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_COM_INITIALIZER_H_
+#define BASE_WIN_SCOPED_COM_INITIALIZER_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace win {
+
+// Initializes COM in the constructor (STA or MTA), and uninitializes COM in the
+// destructor.
+//
+// WARNING: This should only be used once per thread, ideally scoped to a
+// similar lifetime as the thread itself.  You should not be using this in
+// random utility functions that make COM calls -- instead ensure these
+// functions are running on a COM-supporting thread!
+class ScopedCOMInitializer {
+ public:
+  // Enum value provided to initialize the thread as an MTA instead of STA.
+  enum SelectMTA { kMTA };
+
+  // Constructor for STA initialization.
+  ScopedCOMInitializer() {
+    Initialize(COINIT_APARTMENTTHREADED);
+  }
+
+  // Constructor for MTA initialization.
+  explicit ScopedCOMInitializer(SelectMTA mta) {
+    Initialize(COINIT_MULTITHREADED);
+  }
+
+  ~ScopedCOMInitializer() {
+#ifndef NDEBUG
+    // Using the windows API directly to avoid dependency on platform_thread.
+    DCHECK_EQ(GetCurrentThreadId(), thread_id_);
+#endif
+    if (succeeded())
+      CoUninitialize();
+  }
+
+  bool succeeded() const { return SUCCEEDED(hr_); }
+
+ private:
+  void Initialize(COINIT init) {
+#ifndef NDEBUG
+    thread_id_ = GetCurrentThreadId();
+#endif
+    hr_ = CoInitializeEx(NULL, init);
+#ifndef NDEBUG
+    if (hr_ == S_FALSE)
+      LOG(ERROR) << "Multiple CoInitialize() calls for thread " << thread_id_;
+    else
+      DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change";
+#endif
+  }
+
+  HRESULT hr_;
+#ifndef NDEBUG
+  // In debug builds we use this variable to catch a potential bug where a
+  // ScopedCOMInitializer instance is deleted on a different thread than it
+  // was initially created on.  If that ever happens it can have bad
+  // consequences and the cause can be tricky to track down.
+  DWORD thread_id_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_COM_INITIALIZER_H_
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
new file mode 100644
index 0000000..373c0c3
--- /dev/null
+++ b/base/win/scoped_comptr.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_COMPTR_H_
+#define BASE_WIN_SCOPED_COMPTR_H_
+
+#include <unknwn.h>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+namespace win {
+
+// A fairly minimalistic smart class for COM interface pointers.
+// Uses scoped_refptr for the basic smart pointer functionality
+// and adds a few IUnknown specific services.
+template <class Interface, const IID* interface_id = &__uuidof(Interface)>
+class ScopedComPtr : public scoped_refptr<Interface> {
+ public:
+  // Utility template to prevent users of ScopedComPtr from calling AddRef
+  // and/or Release() without going through the ScopedComPtr class.
+  class BlockIUnknownMethods : public Interface {
+   private:
+    STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
+    STDMETHOD_(ULONG, AddRef)() = 0;
+    STDMETHOD_(ULONG, Release)() = 0;
+  };
+
+  typedef scoped_refptr<Interface> ParentClass;
+
+  ScopedComPtr() {
+  }
+
+  explicit ScopedComPtr(Interface* p) : ParentClass(p) {
+  }
+
+  ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
+      : ParentClass(p) {
+  }
+
+  ~ScopedComPtr() {
+    // We don't want the smart pointer class to be bigger than the pointer
+    // it wraps.
+    COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
+                   sizeof(Interface*), ScopedComPtrSize);
+  }
+
+  // Explicit Release() of the held object.  Useful for reuse of the
+  // ScopedComPtr instance.
+  // Note that this function equates to IUnknown::Release and should not
+  // be confused with e.g. scoped_ptr::release().
+  void Release() {
+    if (ptr_ != NULL) {
+      ptr_->Release();
+      ptr_ = NULL;
+    }
+  }
+
+  // Sets the internal pointer to NULL and returns the held object without
+  // releasing the reference.
+  Interface* Detach() {
+    Interface* p = ptr_;
+    ptr_ = NULL;
+    return p;
+  }
+
+  // Accepts an interface pointer that has already been addref-ed.
+  void Attach(Interface* p) {
+    DCHECK(!ptr_);
+    ptr_ = p;
+  }
+
+  // Retrieves the pointer address.
+  // Used to receive object pointers as out arguments (and take ownership).
+  // The function DCHECKs on the current value being NULL.
+  // Usage: Foo(p.Receive());
+  Interface** Receive() {
+    DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
+    return &ptr_;
+  }
+
+  // A convenience for whenever a void pointer is needed as an out argument.
+  void** ReceiveVoid() {
+    return reinterpret_cast<void**>(Receive());
+  }
+
+  template <class Query>
+  HRESULT QueryInterface(Query** p) {
+    DCHECK(p != NULL);
+    DCHECK(ptr_ != NULL);
+    // IUnknown already has a template version of QueryInterface
+    // so the iid parameter is implicit here. The only thing this
+    // function adds are the DCHECKs.
+    return ptr_->QueryInterface(p);
+  }
+
+  // QI for times when the IID is not associated with the type.
+  HRESULT QueryInterface(const IID& iid, void** obj) {
+    DCHECK(obj != NULL);
+    DCHECK(ptr_ != NULL);
+    return ptr_->QueryInterface(iid, obj);
+  }
+
+  // Queries |other| for the interface this object wraps and returns the
+  // error code from the other->QueryInterface operation.
+  HRESULT QueryFrom(IUnknown* object) {
+    DCHECK(object != NULL);
+    return object->QueryInterface(Receive());
+  }
+
+  // Convenience wrapper around CoCreateInstance
+  HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
+                         DWORD context = CLSCTX_ALL) {
+    DCHECK(!ptr_);
+    HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
+                                    reinterpret_cast<void**>(&ptr_));
+    return hr;
+  }
+
+  // Checks if the identity of |other| and this object is the same.
+  bool IsSameObject(IUnknown* other) {
+    if (!other && !ptr_)
+      return true;
+
+    if (!other || !ptr_)
+      return false;
+
+    ScopedComPtr<IUnknown> my_identity;
+    QueryInterface(my_identity.Receive());
+
+    ScopedComPtr<IUnknown> other_identity;
+    other->QueryInterface(other_identity.Receive());
+
+    return my_identity == other_identity;
+  }
+
+  // Provides direct access to the interface.
+  // Here we use a well known trick to make sure we block access to
+  // IUnknown methods so that something bad like this doesn't happen:
+  //    ScopedComPtr<IUnknown> p(Foo());
+  //    p->Release();
+  //    ... later the destructor runs, which will Release() again.
+  // and to get the benefit of the DCHECKs we add to QueryInterface.
+  // There's still a way to call these methods if you absolutely must
+  // by statically casting the ScopedComPtr instance to the wrapped interface
+  // and then making the call... but generally that shouldn't be necessary.
+  BlockIUnknownMethods* operator->() const {
+    DCHECK(ptr_ != NULL);
+    return reinterpret_cast<BlockIUnknownMethods*>(ptr_);
+  }
+
+  // Pull in operator=() from the parent class.
+  using scoped_refptr<Interface>::operator=;
+
+  // static methods
+
+  static const IID& iid() {
+    return *interface_id;
+  }
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_COMPTR_H_
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
new file mode 100644
index 0000000..d38752d
--- /dev/null
+++ b/base/win/scoped_comptr_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_comptr.h"
+
+#include <shlobj.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct Dummy {
+  Dummy() : adds(0), releases(0) { }
+  void AddRef() { ++adds; }
+  void Release() { ++releases; }
+
+  int adds;
+  int releases;
+};
+
+extern const IID dummy_iid;
+const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
+                        01, 23, 45 };
+
+}  // namespace
+
+TEST(ScopedComPtrTest, ScopedComPtr) {
+  EXPECT_EQ(memcmp(&ScopedComPtr<IUnknown>::iid(), &IID_IUnknown, sizeof(IID)),
+            0);
+
+  base::win::ScopedCOMInitializer com_initializer;
+  EXPECT_TRUE(com_initializer.succeeded());
+
+  ScopedComPtr<IUnknown> unk;
+  EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
+  ScopedComPtr<IUnknown> unk2;
+  unk2.Attach(unk.Detach());
+  EXPECT_TRUE(unk.get() == NULL);
+  EXPECT_TRUE(unk2.get() != NULL);
+
+  ScopedComPtr<IMalloc> mem_alloc;
+  EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
+
+  ScopedComPtr<IUnknown> qi_test;
+  EXPECT_HRESULT_SUCCEEDED(mem_alloc.QueryInterface(IID_IUnknown,
+      reinterpret_cast<void**>(qi_test.Receive())));
+  EXPECT_TRUE(qi_test.get() != NULL);
+  qi_test.Release();
+
+  // test ScopedComPtr& constructor
+  ScopedComPtr<IMalloc> copy1(mem_alloc);
+  EXPECT_TRUE(copy1.IsSameObject(mem_alloc.get()));
+  EXPECT_FALSE(copy1.IsSameObject(unk2.get()));  // unk2 is valid but different
+  EXPECT_FALSE(copy1.IsSameObject(unk.get()));  // unk is NULL
+
+  IMalloc* naked_copy = copy1.Detach();
+  copy1 = naked_copy;  // Test the =(T*) operator.
+  naked_copy->Release();
+
+  copy1.Release();
+  EXPECT_FALSE(copy1.IsSameObject(unk2.get()));  // unk2 is valid, copy1 is not
+
+  // test Interface* constructor
+  ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc.get()));
+  EXPECT_TRUE(copy2.IsSameObject(mem_alloc.get()));
+
+  EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc.get())));
+  EXPECT_TRUE(unk.get() != NULL);
+  unk.Release();
+  EXPECT_TRUE(unk.get() == NULL);
+  EXPECT_TRUE(unk.IsSameObject(copy1.get()));  // both are NULL
+}
+
+TEST(ScopedComPtrTest, ScopedComPtrVector) {
+  // Verify we don't get error C2558.
+  typedef ScopedComPtr<Dummy, &dummy_iid> Ptr;
+  std::vector<Ptr> bleh;
+
+  scoped_ptr<Dummy> p(new Dummy);
+  {
+    Ptr p2(p.get());
+    EXPECT_EQ(p->adds, 1);
+    EXPECT_EQ(p->releases, 0);
+    Ptr p3 = p2;
+    EXPECT_EQ(p->adds, 2);
+    EXPECT_EQ(p->releases, 0);
+    p3 = p2;
+    EXPECT_EQ(p->adds, 3);
+    EXPECT_EQ(p->releases, 1);
+    // To avoid hitting a reallocation.
+    bleh.reserve(1);
+    bleh.push_back(p2);
+    EXPECT_EQ(p->adds, 4);
+    EXPECT_EQ(p->releases, 1);
+    EXPECT_EQ(bleh[0].get(), p.get());
+    bleh.pop_back();
+    EXPECT_EQ(p->adds, 4);
+    EXPECT_EQ(p->releases, 2);
+  }
+  EXPECT_EQ(p->adds, 4);
+  EXPECT_EQ(p->releases, 4);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_gdi_object.h b/base/win/scoped_gdi_object.h
new file mode 100644
index 0000000..57b013e
--- /dev/null
+++ b/base/win/scoped_gdi_object.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_GDI_OBJECT_H_
+#define BASE_WIN_SCOPED_GDI_OBJECT_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for GDI objects.
+template<class T>
+class ScopedGDIObject {
+ public:
+  ScopedGDIObject() : object_(NULL) {}
+  explicit ScopedGDIObject(T object) : object_(object) {}
+
+  ~ScopedGDIObject() {
+    Close();
+  }
+
+  T Get() {
+    return object_;
+  }
+
+  void Set(T object) {
+    if (object_ && object != object_)
+      Close();
+    object_ = object;
+  }
+
+  ScopedGDIObject& operator=(T object) {
+    Set(object);
+    return *this;
+  }
+
+  T release() {
+    T object = object_;
+    object_ = NULL;
+    return object;
+  }
+
+  operator T() { return object_; }
+
+ private:
+  void Close() {
+    if (object_)
+      DeleteObject(object_);
+  }
+
+  T object_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+};
+
+// An explicit specialization for HICON because we have to call DestroyIcon()
+// instead of DeleteObject() for HICON.
+template<>
+void inline ScopedGDIObject<HICON>::Close() {
+  if (object_)
+    DestroyIcon(object_);
+}
+
+// Typedefs for some common use cases.
+typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
+typedef ScopedGDIObject<HRGN> ScopedRegion;
+typedef ScopedGDIObject<HFONT> ScopedHFONT;
+typedef ScopedGDIObject<HICON> ScopedHICON;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_GDI_OBJECT_H_
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc
new file mode 100644
index 0000000..2ebef32
--- /dev/null
+++ b/base/win/scoped_handle.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_handle.h"
+
+#include <unordered_map>
+
+#include "base/debug/alias.h"
+#include "base/hash.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock_impl.h"
+
+extern "C" {
+__declspec(dllexport) void* GetHandleVerifier();
+typedef void* (*GetHandleVerifierFn)();
+}
+
+namespace {
+
+struct HandleHash {
+  size_t operator()(const HANDLE& handle) const {
+    char buffer[sizeof(handle)];
+    memcpy(buffer, &handle, sizeof(handle));
+    return base::Hash(buffer, sizeof(buffer));
+  }
+};
+
+struct Info {
+  const void* owner;
+  const void* pc1;
+  const void* pc2;
+  DWORD thread_id;
+};
+typedef std::unordered_map<HANDLE, Info, HandleHash> HandleMap;
+
+// g_lock protects the handle map and setting g_active_verifier.
+typedef base::internal::LockImpl NativeLock;
+base::LazyInstance<NativeLock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+
+bool CloseHandleWrapper(HANDLE handle) {
+  if (!::CloseHandle(handle))
+    CHECK(false);
+  return true;
+}
+
+// Simple automatic locking using a native critical section so it supports
+// recursive locking.
+class AutoNativeLock {
+ public:
+  explicit AutoNativeLock(NativeLock& lock) : lock_(lock) {
+    lock_.Lock();
+  }
+
+  ~AutoNativeLock() {
+    lock_.Unlock();
+  }
+
+ private:
+  NativeLock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoNativeLock);
+};
+
+// Implements the actual object that is verifying handles for this process.
+// The active instance is shared across the module boundary but there is no
+// way to delete this object from the wrong side of it (or any side, actually).
+class ActiveVerifier {
+ public:
+  explicit ActiveVerifier(bool enabled)
+      : enabled_(enabled), closing_(false), lock_(g_lock.Pointer()) {
+  }
+
+  // Retrieves the current verifier.
+  static ActiveVerifier* Get();
+
+  // The methods required by HandleTraits. They are virtual because we need to
+  // forward the call execution to another module, instead of letting the
+  // compiler call the version that is linked in the current module.
+  virtual bool CloseHandle(HANDLE handle);
+  virtual void StartTracking(HANDLE handle, const void* owner,
+                             const void* pc1, const void* pc2);
+  virtual void StopTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2);
+  virtual void Disable();
+  virtual void OnHandleBeingClosed(HANDLE handle);
+
+ private:
+  ~ActiveVerifier();  // Not implemented.
+
+  static void InstallVerifier();
+
+  bool enabled_;
+  bool closing_;
+  NativeLock* lock_;
+  HandleMap map_;
+  DISALLOW_COPY_AND_ASSIGN(ActiveVerifier);
+};
+ActiveVerifier* g_active_verifier = NULL;
+
+// static
+ActiveVerifier* ActiveVerifier::Get() {
+  if (!g_active_verifier)
+    ActiveVerifier::InstallVerifier();
+
+  return g_active_verifier;
+}
+
+// static
+void ActiveVerifier::InstallVerifier() {
+#if defined(COMPONENT_BUILD)
+  AutoNativeLock lock(g_lock.Get());
+  g_active_verifier = new ActiveVerifier(true);
+#else
+  // If you are reading this, wondering why your process seems deadlocked, take
+  // a look at your DllMain code and remove things that should not be done
+  // there, like doing whatever gave you that nice windows handle you are trying
+  // to store in a ScopedHandle.
+  HMODULE main_module = ::GetModuleHandle(NULL);
+  GetHandleVerifierFn get_handle_verifier =
+      reinterpret_cast<GetHandleVerifierFn>(::GetProcAddress(
+          main_module, "GetHandleVerifier"));
+
+  if (!get_handle_verifier) {
+    g_active_verifier = new ActiveVerifier(false);
+    return;
+  }
+
+  ActiveVerifier* verifier =
+      reinterpret_cast<ActiveVerifier*>(get_handle_verifier());
+
+  // This lock only protects against races in this module, which is fine.
+  AutoNativeLock lock(g_lock.Get());
+  g_active_verifier = verifier ? verifier : new ActiveVerifier(true);
+#endif
+}
+
+bool ActiveVerifier::CloseHandle(HANDLE handle) {
+  if (!enabled_)
+    return CloseHandleWrapper(handle);
+
+  AutoNativeLock lock(*lock_);
+  closing_ = true;
+  CloseHandleWrapper(handle);
+  closing_ = false;
+
+  return true;
+}
+
+void ActiveVerifier::StartTracking(HANDLE handle, const void* owner,
+                                   const void* pc1, const void* pc2) {
+  if (!enabled_)
+    return;
+
+  // Grab the thread id before the lock.
+  DWORD thread_id = GetCurrentThreadId();
+
+  AutoNativeLock lock(*lock_);
+
+  Info handle_info = { owner, pc1, pc2, thread_id };
+  std::pair<HANDLE, Info> item(handle, handle_info);
+  std::pair<HandleMap::iterator, bool> result = map_.insert(item);
+  if (!result.second) {
+    Info other = result.first->second;
+    base::debug::Alias(&other);
+    CHECK(false);
+  }
+}
+
+void ActiveVerifier::StopTracking(HANDLE handle, const void* owner,
+                                  const void* pc1, const void* pc2) {
+  if (!enabled_)
+    return;
+
+  AutoNativeLock lock(*lock_);
+  HandleMap::iterator i = map_.find(handle);
+  if (i == map_.end())
+    CHECK(false);
+
+  Info other = i->second;
+  if (other.owner != owner) {
+    base::debug::Alias(&other);
+    CHECK(false);
+  }
+
+  map_.erase(i);
+}
+
+void ActiveVerifier::Disable() {
+  enabled_ = false;
+}
+
+void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) {
+  AutoNativeLock lock(*lock_);
+  if (closing_)
+    return;
+
+  HandleMap::iterator i = map_.find(handle);
+  if (i == map_.end())
+    return;
+
+  Info other = i->second;
+  base::debug::Alias(&other);
+  CHECK(false);
+}
+
+}  // namespace
+
+void* GetHandleVerifier() {
+  return g_active_verifier;
+}
+
+namespace base {
+namespace win {
+
+// Static.
+bool HandleTraits::CloseHandle(HANDLE handle) {
+  return ActiveVerifier::Get()->CloseHandle(handle);
+}
+
+// Static.
+void VerifierTraits::StartTracking(HANDLE handle, const void* owner,
+                                   const void* pc1, const void* pc2) {
+  return ActiveVerifier::Get()->StartTracking(handle, owner, pc1, pc2);
+}
+
+// Static.
+void VerifierTraits::StopTracking(HANDLE handle, const void* owner,
+                                  const void* pc1, const void* pc2) {
+  return ActiveVerifier::Get()->StopTracking(handle, owner, pc1, pc2);
+}
+
+void DisableHandleVerifier() {
+  return ActiveVerifier::Get()->Disable();
+}
+
+void OnHandleBeingClosed(HANDLE handle) {
+  return ActiveVerifier::Get()->OnHandleBeingClosed(handle);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
new file mode 100644
index 0000000..97fd7a5
--- /dev/null
+++ b/base/win/scoped_handle.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HANDLE_H_
+#define BASE_WIN_SCOPED_HANDLE_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/move.h"
+
+// TODO(rvargas): remove this with the rest of the verifier.
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#define BASE_WIN_GET_CALLER _ReturnAddress()
+#elif defined(COMPILER_GCC)
+#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\
+    __builtin_return_address(0))
+#endif
+
+namespace base {
+namespace win {
+
+// Generic wrapper for raw handles that takes care of closing handles
+// automatically. The class interface follows the style of
+// the ScopedFILE class with one addition:
+//   - IsValid() method can tolerate multiple invalid handle values such as NULL
+//     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
+template <class Traits, class Verifier>
+class GenericScopedHandle {
+  MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
+
+ public:
+  typedef typename Traits::Handle Handle;
+
+  GenericScopedHandle() : handle_(Traits::NullHandle()) {}
+
+  explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
+    Set(handle);
+  }
+
+  // Move constructor for C++03 move emulation of this type.
+  GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) {
+    Set(other.object->Take());
+  }
+
+  ~GenericScopedHandle() {
+    Close();
+  }
+
+  bool IsValid() const {
+    return Traits::IsHandleValid(handle_);
+  }
+
+  // Move operator= for C++03 move emulation of this type.
+  GenericScopedHandle& operator=(RValue other) {
+    if (this != other.object) {
+      Set(other.object->Take());
+    }
+    return *this;
+  }
+
+  void Set(Handle handle) {
+    if (handle_ != handle) {
+      Close();
+
+      if (Traits::IsHandleValid(handle)) {
+        handle_ = handle;
+        Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
+                                tracked_objects::GetProgramCounter());
+      }
+    }
+  }
+
+  Handle Get() const {
+    return handle_;
+  }
+
+  // Transfers ownership away from this object.
+  Handle Take() {
+    Handle temp = handle_;
+    handle_ = Traits::NullHandle();
+    if (Traits::IsHandleValid(temp)) {
+      Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
+                             tracked_objects::GetProgramCounter());
+    }
+    return temp;
+  }
+
+  // Explicitly closes the owned handle.
+  void Close() {
+    if (Traits::IsHandleValid(handle_)) {
+      Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
+                             tracked_objects::GetProgramCounter());
+
+      Traits::CloseHandle(handle_);
+      handle_ = Traits::NullHandle();
+    }
+  }
+
+ private:
+  Handle handle_;
+};
+
+#undef BASE_WIN_GET_CALLER
+
+// The traits class for Win32 handles that can be closed via CloseHandle() API.
+class HandleTraits {
+ public:
+  typedef HANDLE Handle;
+
+  // Closes the handle.
+  static bool BASE_EXPORT CloseHandle(HANDLE handle);
+
+  // Returns true if the handle value is valid.
+  static bool IsHandleValid(HANDLE handle) {
+    return handle != NULL && handle != INVALID_HANDLE_VALUE;
+  }
+
+  // Returns NULL handle value.
+  static HANDLE NullHandle() {
+    return NULL;
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
+};
+
+// Do-nothing verifier.
+class DummyVerifierTraits {
+ public:
+  typedef HANDLE Handle;
+
+  static void StartTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2) {}
+  static void StopTracking(HANDLE handle, const void* owner,
+                           const void* pc1, const void* pc2) {}
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
+};
+
+// Performs actual run-time tracking.
+class BASE_EXPORT VerifierTraits {
+ public:
+  typedef HANDLE Handle;
+
+  static void StartTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2);
+  static void StopTracking(HANDLE handle, const void* owner,
+                           const void* pc1, const void* pc2);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
+};
+
+typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle;
+
+// This function may be called by the embedder to disable the use of
+// VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
+// for ScopedHandle.
+void BASE_EXPORT DisableHandleVerifier();
+
+// This should be called whenever the OS is closing a handle, if extended
+// verification of improper handle closing is desired. If |handle| is being
+// tracked by the handle verifier and ScopedHandle is not the one closing it,
+// a CHECK is generated.
+void BASE_EXPORT OnHandleBeingClosed(HANDLE handle);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HANDLE_H_
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
new file mode 100644
index 0000000..2452067
--- /dev/null
+++ b/base/win/scoped_hdc.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HDC_H_
+#define BASE_WIN_SCOPED_HDC_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
+// GetDC.
+class ScopedGetDC {
+ public:
+  explicit ScopedGetDC(HWND hwnd)
+      : hwnd_(hwnd),
+        hdc_(GetDC(hwnd)) {
+    if (hwnd_) {
+      DCHECK(IsWindow(hwnd_));
+      DCHECK(hdc_);
+    } else {
+      // If GetDC(NULL) returns NULL, something really bad has happened, like
+      // GDI handle exhaustion.  In this case Chrome is going to behave badly no
+      // matter what, so we may as well just force a crash now.
+      CHECK(hdc_);
+    }
+  }
+
+  ~ScopedGetDC() {
+    if (hdc_)
+      ReleaseDC(hwnd_, hdc_);
+  }
+
+  operator HDC() { return hdc_; }
+
+ private:
+  HWND hwnd_;
+  HDC hdc_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedGetDC);
+};
+
+// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
+// CreateCompatibleDC, CreateDC and CreateIC.
+class CreateDCTraits {
+ public:
+  typedef HDC Handle;
+
+  static bool CloseHandle(HDC handle) {
+    return ::DeleteDC(handle) != FALSE;
+  }
+
+  static bool IsHandleValid(HDC handle) {
+    return handle != NULL;
+  }
+
+  static HDC NullHandle() {
+    return NULL;
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits);
+};
+
+typedef GenericScopedHandle<CreateDCTraits, DummyVerifierTraits> ScopedCreateDC;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HDC_H_
diff --git a/base/win/scoped_hglobal.h b/base/win/scoped_hglobal.h
new file mode 100644
index 0000000..185ccbd
--- /dev/null
+++ b/base/win/scoped_hglobal.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HGLOBAL_H_
+#define BASE_WIN_SCOPED_HGLOBAL_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle except for HGLOBAL.
+template<class T>
+class ScopedHGlobal {
+ public:
+  explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) {
+    data_ = static_cast<T>(GlobalLock(glob_));
+  }
+  ~ScopedHGlobal() {
+    GlobalUnlock(glob_);
+  }
+
+  T get() { return data_; }
+
+  size_t Size() const { return GlobalSize(glob_); }
+
+  T operator->() const {
+    assert(data_ != 0);
+    return data_;
+  }
+
+  T release() {
+    T data = data_;
+    data_ = NULL;
+    return data;
+  }
+
+ private:
+  HGLOBAL glob_;
+
+  T data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedHGlobal);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HGLOBAL_H_
diff --git a/base/win/scoped_process_information.cc b/base/win/scoped_process_information.cc
new file mode 100644
index 0000000..634a538
--- /dev/null
+++ b/base/win/scoped_process_information.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_process_information.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Duplicates source into target, returning true upon success. |target| is
+// guaranteed to be untouched in case of failure. Succeeds with no side-effects
+// if source is NULL.
+bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) {
+  if (!source)
+    return true;
+
+  HANDLE temp = NULL;
+
+  // TODO(shrikant): Remove following code as soon as we gather some
+  // information regarding AppContainer related DuplicateHandle failures that
+  // only seem to happen on certain machine and only random launches (normally
+  // renderer launches seem to succeed even on those machines.)
+  if (base::win::GetVersion() == base::win::VERSION_WIN8 ||
+      base::win::GetVersion() == base::win::VERSION_WIN8_1) {
+    typedef LONG (WINAPI *NtDuplicateObject)(
+        IN HANDLE SourceProcess,
+        IN HANDLE SourceHandle,
+        IN HANDLE TargetProcess,
+        OUT PHANDLE TargetHandle,
+        IN ACCESS_MASK DesiredAccess,
+        IN ULONG Attributes,
+        IN ULONG Options);
+
+    typedef ULONG (WINAPI *RtlNtStatusToDosError)(IN LONG Status);
+
+    NtDuplicateObject nt_duplicate_object =
+        reinterpret_cast<NtDuplicateObject>(::GetProcAddress(
+            GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"));
+    if (nt_duplicate_object != NULL) {
+      LONG status = nt_duplicate_object(::GetCurrentProcess(), source,
+                                        ::GetCurrentProcess(), &temp,
+                                        0, FALSE, DUPLICATE_SAME_ACCESS);
+      if (status < 0) {
+        DPLOG(ERROR) << "Failed to duplicate a handle.";
+        RtlNtStatusToDosError ntstatus_to_doserror =
+            reinterpret_cast<RtlNtStatusToDosError>(::GetProcAddress(
+                GetModuleHandle(L"ntdll.dll"), "RtlNtStatusToDosError"));
+        if (ntstatus_to_doserror != NULL) {
+          ::SetLastError(ntstatus_to_doserror(status));
+        }
+        return false;
+      }
+    }
+  } else {
+    if (!::DuplicateHandle(::GetCurrentProcess(), source,
+                           ::GetCurrentProcess(), &temp, 0, FALSE,
+                           DUPLICATE_SAME_ACCESS)) {
+      DPLOG(ERROR) << "Failed to duplicate a handle.";
+      return false;
+    }
+  }
+  target->Set(temp);
+  return true;
+}
+
+}  // namespace
+
+ScopedProcessInformation::ScopedProcessInformation()
+    : process_id_(0), thread_id_(0) {
+}
+
+ScopedProcessInformation::ScopedProcessInformation(
+    const PROCESS_INFORMATION& process_info) : process_id_(0), thread_id_(0) {
+  Set(process_info);
+}
+
+ScopedProcessInformation::~ScopedProcessInformation() {
+  Close();
+}
+
+bool ScopedProcessInformation::IsValid() const {
+  return process_id_ || process_handle_.Get() ||
+         thread_id_ || thread_handle_.Get();
+}
+
+void ScopedProcessInformation::Close() {
+  process_handle_.Close();
+  thread_handle_.Close();
+  process_id_ = 0;
+  thread_id_ = 0;
+}
+
+void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) {
+  if (IsValid())
+    Close();
+
+  process_handle_.Set(process_info.hProcess);
+  thread_handle_.Set(process_info.hThread);
+  process_id_ = process_info.dwProcessId;
+  thread_id_ = process_info.dwThreadId;
+}
+
+bool ScopedProcessInformation::DuplicateFrom(
+    const ScopedProcessInformation& other) {
+  DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
+  DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid";
+
+  if (CheckAndDuplicateHandle(other.process_handle(), &process_handle_) &&
+      CheckAndDuplicateHandle(other.thread_handle(), &thread_handle_)) {
+    process_id_ = other.process_id();
+    thread_id_ = other.thread_id();
+    return true;
+  }
+
+  return false;
+}
+
+PROCESS_INFORMATION ScopedProcessInformation::Take() {
+  PROCESS_INFORMATION process_information = {};
+  process_information.hProcess = process_handle_.Take();
+  process_information.hThread = thread_handle_.Take();
+  process_information.dwProcessId = process_id();
+  process_information.dwThreadId = thread_id();
+  process_id_ = 0;
+  thread_id_ = 0;
+
+  return process_information;
+}
+
+HANDLE ScopedProcessInformation::TakeProcessHandle() {
+  process_id_ = 0;
+  return process_handle_.Take();
+}
+
+HANDLE ScopedProcessInformation::TakeThreadHandle() {
+  thread_id_ = 0;
+  return thread_handle_.Take();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_process_information.h b/base/win/scoped_process_information.h
new file mode 100644
index 0000000..2e24054
--- /dev/null
+++ b/base/win/scoped_process_information.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+#define BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Manages the closing of process and thread handles from PROCESS_INFORMATION
+// structures. Allows clients to take ownership of either handle independently.
+class BASE_EXPORT ScopedProcessInformation {
+ public:
+  ScopedProcessInformation();
+  explicit ScopedProcessInformation(const PROCESS_INFORMATION& process_info);
+  ~ScopedProcessInformation();
+
+  // Returns true iff this instance is holding a thread and/or process handle.
+  bool IsValid() const;
+
+  // Closes the held thread and process handles, if any.
+  void Close();
+
+  // Populates this instance with the provided |process_info|.
+  void Set(const PROCESS_INFORMATION& process_info);
+
+  // Populates this instance with duplicate handles and the thread/process IDs
+  // from |other|. Returns false in case of failure, in which case this instance
+  // will be completely unpopulated.
+  bool DuplicateFrom(const ScopedProcessInformation& other);
+
+  // Transfers ownership of the held PROCESS_INFORMATION, if any, away from this
+  // instance.
+  PROCESS_INFORMATION Take();
+
+  // Transfers ownership of the held process handle, if any, away from this
+  // instance. Note that the related process_id will also be cleared.
+  HANDLE TakeProcessHandle();
+
+  // Transfers ownership of the held thread handle, if any, away from this
+  // instance. Note that the related thread_id will also be cleared.
+  HANDLE TakeThreadHandle();
+
+  // Returns the held process handle, if any, while retaining ownership.
+  HANDLE process_handle() const {
+    return process_handle_.Get();
+  }
+
+  // Returns the held thread handle, if any, while retaining ownership.
+  HANDLE thread_handle() const {
+    return thread_handle_.Get();
+  }
+
+  // Returns the held process id, if any.
+  DWORD process_id() const {
+    return process_id_;
+  }
+
+  // Returns the held thread id, if any.
+  DWORD thread_id() const {
+    return thread_id_;
+  }
+
+ private:
+  ScopedHandle process_handle_;
+  ScopedHandle thread_handle_;
+  DWORD process_id_;
+  DWORD thread_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedProcessInformation);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc
new file mode 100644
index 0000000..614504d
--- /dev/null
+++ b/base/win/scoped_process_information_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/process/kill.h"
+#include "base/process/process.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_process_information.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace {
+
+const DWORD kProcessId = 4321;
+const DWORD kThreadId = 1234;
+const HANDLE kProcessHandle = reinterpret_cast<HANDLE>(7651);
+const HANDLE kThreadHandle = reinterpret_cast<HANDLE>(1567);
+
+void MockCreateProcess(base::win::ScopedProcessInformation* process_info) {
+  PROCESS_INFORMATION process_information = {};
+  process_information.dwProcessId = kProcessId;
+  process_information.dwThreadId = kThreadId;
+  process_information.hProcess = kProcessHandle;
+  process_information.hThread = kThreadHandle;
+  process_info->Set(process_information);
+}
+
+}  // namespace
+
+class ScopedProcessInformationTest : public base::MultiProcessTest {
+ protected:
+  void DoCreateProcess(const std::string& main_id,
+                       PROCESS_INFORMATION* process_handle);
+};
+
+MULTIPROCESS_TEST_MAIN(ReturnSeven) {
+  return 7;
+}
+
+MULTIPROCESS_TEST_MAIN(ReturnNine) {
+  return 9;
+}
+
+void ScopedProcessInformationTest::DoCreateProcess(
+    const std::string& main_id, PROCESS_INFORMATION* process_handle) {
+  std::wstring cmd_line = MakeCmdLine(main_id).GetCommandLineString();
+  STARTUPINFO startup_info = {};
+  startup_info.cb = sizeof(startup_info);
+
+  EXPECT_TRUE(::CreateProcess(NULL, &cmd_line[0],
+                              NULL, NULL, false, 0, NULL, NULL,
+                              &startup_info, process_handle));
+}
+
+TEST_F(ScopedProcessInformationTest, InitiallyInvalid) {
+  base::win::ScopedProcessInformation process_info;
+  ASSERT_FALSE(process_info.IsValid());
+}
+
+TEST_F(ScopedProcessInformationTest, Receive) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  EXPECT_TRUE(process_info.IsValid());
+  EXPECT_EQ(kProcessId, process_info.process_id());
+  EXPECT_EQ(kThreadId, process_info.thread_id());
+  EXPECT_EQ(kProcessHandle, process_info.process_handle());
+  EXPECT_EQ(kThreadHandle, process_info.thread_handle());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeProcess) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  HANDLE process = process_info.TakeProcessHandle();
+  EXPECT_EQ(kProcessHandle, process);
+  EXPECT_EQ(NULL, process_info.process_handle());
+  EXPECT_EQ(0, process_info.process_id());
+  EXPECT_TRUE(process_info.IsValid());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeThread) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  HANDLE thread = process_info.TakeThreadHandle();
+  EXPECT_EQ(kThreadHandle, thread);
+  EXPECT_EQ(NULL, process_info.thread_handle());
+  EXPECT_EQ(0, process_info.thread_id());
+  EXPECT_TRUE(process_info.IsValid());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeBoth) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  process_info.TakeProcessHandle();
+  process_info.TakeThreadHandle();
+  EXPECT_FALSE(process_info.IsValid());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeWholeStruct) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  PROCESS_INFORMATION to_discard = process_info.Take();
+  EXPECT_EQ(kProcessId, to_discard.dwProcessId);
+  EXPECT_EQ(kThreadId, to_discard.dwThreadId);
+  EXPECT_EQ(kProcessHandle, to_discard.hProcess);
+  EXPECT_EQ(kThreadHandle, to_discard.hThread);
+  EXPECT_FALSE(process_info.IsValid());
+}
+
+TEST_F(ScopedProcessInformationTest, Duplicate) {
+  PROCESS_INFORMATION temp_process_information;
+  DoCreateProcess("ReturnSeven", &temp_process_information);
+  base::win::ScopedProcessInformation process_info;
+  process_info.Set(temp_process_information);
+
+  base::win::ScopedProcessInformation duplicate;
+  duplicate.DuplicateFrom(process_info);
+
+  ASSERT_TRUE(process_info.IsValid());
+  ASSERT_NE(0u, process_info.process_id());
+  ASSERT_EQ(duplicate.process_id(), process_info.process_id());
+  ASSERT_NE(0u, process_info.thread_id());
+  ASSERT_EQ(duplicate.thread_id(), process_info.thread_id());
+
+  // Validate that we have separate handles that are good.
+  int exit_code = 0;
+  base::Process process(process_info.TakeProcessHandle());
+  ASSERT_TRUE(process.WaitForExit(&exit_code));
+  ASSERT_EQ(7, exit_code);
+
+  exit_code = 0;
+  base::Process dup_process(duplicate.TakeProcessHandle());
+  ASSERT_TRUE(dup_process.WaitForExit(&exit_code));
+  ASSERT_EQ(7, exit_code);
+
+  ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
+  ASSERT_TRUE(::CloseHandle(duplicate.TakeThreadHandle()));
+}
+
+TEST_F(ScopedProcessInformationTest, Set) {
+  base::win::ScopedProcessInformation base_process_info;
+  MockCreateProcess(&base_process_info);
+
+  PROCESS_INFORMATION base_struct = base_process_info.Take();
+
+  base::win::ScopedProcessInformation process_info;
+  process_info.Set(base_struct);
+
+  EXPECT_EQ(kProcessId, process_info.process_id());
+  EXPECT_EQ(kThreadId, process_info.thread_id());
+  EXPECT_EQ(kProcessHandle, process_info.process_handle());
+  EXPECT_EQ(kThreadHandle, process_info.thread_handle());
+  base_struct = process_info.Take();
+}
diff --git a/base/win/scoped_propvariant.h b/base/win/scoped_propvariant.h
new file mode 100644
index 0000000..62cc6a6
--- /dev/null
+++ b/base/win/scoped_propvariant.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_PROPVARIANT_H_
+#define BASE_WIN_SCOPED_PROPVARIANT_H_
+
+#include <propidl.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// A PROPVARIANT that is automatically initialized and cleared upon respective
+// construction and destruction of this class.
+class ScopedPropVariant {
+ public:
+  ScopedPropVariant() {
+    PropVariantInit(&pv_);
+  }
+
+  ~ScopedPropVariant() {
+    Reset();
+  }
+
+  // Returns a pointer to the underlying PROPVARIANT for use as an out param in
+  // a function call.
+  PROPVARIANT* Receive() {
+    DCHECK_EQ(pv_.vt, VT_EMPTY);
+    return &pv_;
+  }
+
+  // Clears the instance to prepare it for re-use (e.g., via Receive).
+  void Reset() {
+    if (pv_.vt != VT_EMPTY) {
+      HRESULT result = PropVariantClear(&pv_);
+      DCHECK_EQ(result, S_OK);
+    }
+  }
+
+  const PROPVARIANT& get() const { return pv_; }
+  const PROPVARIANT* ptr() const { return &pv_; }
+
+ private:
+  PROPVARIANT pv_;
+
+  // Comparison operators for ScopedPropVariant are not supported at this point.
+  bool operator==(const ScopedPropVariant&) const;
+  bool operator!=(const ScopedPropVariant&) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedPropVariant);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_PROPVARIANT_H_
diff --git a/base/win/scoped_select_object.h b/base/win/scoped_select_object.h
new file mode 100644
index 0000000..347de79
--- /dev/null
+++ b/base/win/scoped_select_object.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_SELECT_OBJECT_H_
+#define BASE_WIN_SCOPED_SELECT_OBJECT_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Helper class for deselecting object from DC.
+class ScopedSelectObject {
+ public:
+  ScopedSelectObject(HDC hdc, HGDIOBJ object)
+      : hdc_(hdc),
+        oldobj_(SelectObject(hdc, object)) {
+    DCHECK(hdc_);
+    DCHECK(object);
+    DCHECK(oldobj_ != NULL && oldobj_ != HGDI_ERROR);
+  }
+
+  ~ScopedSelectObject() {
+    HGDIOBJ object = SelectObject(hdc_, oldobj_);
+    DCHECK((GetObjectType(oldobj_) != OBJ_REGION && object != NULL) ||
+           (GetObjectType(oldobj_) == OBJ_REGION && object != HGDI_ERROR));
+  }
+
+ private:
+  HDC hdc_;
+  HGDIOBJ oldobj_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSelectObject);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_SELECT_OBJECT_H_
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
new file mode 100644
index 0000000..f57ab93
--- /dev/null
+++ b/base/win/scoped_variant.cc
@@ -0,0 +1,276 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_variant.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Global, const instance of an empty variant.
+const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
+
+ScopedVariant::~ScopedVariant() {
+  COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
+  ::VariantClear(&var_);
+}
+
+ScopedVariant::ScopedVariant(const wchar_t* str) {
+  var_.vt = VT_EMPTY;
+  Set(str);
+}
+
+ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
+  var_.vt = VT_BSTR;
+  var_.bstrVal = ::SysAllocStringLen(str, length);
+}
+
+ScopedVariant::ScopedVariant(int value, VARTYPE vt) {
+  var_.vt = vt;
+  var_.lVal = value;
+}
+
+ScopedVariant::ScopedVariant(double value, VARTYPE vt) {
+  DCHECK(vt == VT_R8 || vt == VT_DATE);
+  var_.vt = vt;
+  var_.dblVal = value;
+}
+
+ScopedVariant::ScopedVariant(IDispatch* dispatch) {
+  var_.vt = VT_EMPTY;
+  Set(dispatch);
+}
+
+ScopedVariant::ScopedVariant(IUnknown* unknown) {
+  var_.vt = VT_EMPTY;
+  Set(unknown);
+}
+
+ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
+  var_.vt = VT_EMPTY;
+  Set(safearray);
+}
+
+ScopedVariant::ScopedVariant(const VARIANT& var) {
+  var_.vt = VT_EMPTY;
+  Set(var);
+}
+
+void ScopedVariant::Reset(const VARIANT& var) {
+  if (&var != &var_) {
+    ::VariantClear(&var_);
+    var_ = var;
+  }
+}
+
+VARIANT ScopedVariant::Release() {
+  VARIANT var = var_;
+  var_.vt = VT_EMPTY;
+  return var;
+}
+
+void ScopedVariant::Swap(ScopedVariant& var) {
+  VARIANT tmp = var_;
+  var_ = var.var_;
+  var.var_ = tmp;
+}
+
+VARIANT* ScopedVariant::Receive() {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
+  return &var_;
+}
+
+VARIANT ScopedVariant::Copy() const {
+  VARIANT ret = { VT_EMPTY };
+  ::VariantCopy(&ret, &var_);
+  return ret;
+}
+
+int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
+  ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
+  HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
+                        LOCALE_USER_DEFAULT, flags);
+  int ret = 0;
+
+  switch (hr) {
+    case VARCMP_LT:
+      ret = -1;
+      break;
+
+    case VARCMP_GT:
+    case VARCMP_NULL:
+      ret = 1;
+      break;
+
+    default:
+      // Equal.
+      break;
+  }
+
+  return ret;
+}
+
+void ScopedVariant::Set(const wchar_t* str) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_BSTR;
+  var_.bstrVal = ::SysAllocString(str);
+}
+
+void ScopedVariant::Set(int8 i8) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I1;
+  var_.cVal = i8;
+}
+
+void ScopedVariant::Set(uint8 ui8) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI1;
+  var_.bVal = ui8;
+}
+
+void ScopedVariant::Set(int16 i16) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I2;
+  var_.iVal = i16;
+}
+
+void ScopedVariant::Set(uint16 ui16) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI2;
+  var_.uiVal = ui16;
+}
+
+void ScopedVariant::Set(int32 i32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I4;
+  var_.lVal = i32;
+}
+
+void ScopedVariant::Set(uint32 ui32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI4;
+  var_.ulVal = ui32;
+}
+
+void ScopedVariant::Set(int64 i64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I8;
+  var_.llVal = i64;
+}
+
+void ScopedVariant::Set(uint64 ui64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI8;
+  var_.ullVal = ui64;
+}
+
+void ScopedVariant::Set(float r32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_R4;
+  var_.fltVal = r32;
+}
+
+void ScopedVariant::Set(double r64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_R8;
+  var_.dblVal = r64;
+}
+
+void ScopedVariant::SetDate(DATE date) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_DATE;
+  var_.date = date;
+}
+
+void ScopedVariant::Set(IDispatch* disp) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_DISPATCH;
+  var_.pdispVal = disp;
+  if (disp)
+    disp->AddRef();
+}
+
+void ScopedVariant::Set(bool b) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_BOOL;
+  var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
+}
+
+void ScopedVariant::Set(IUnknown* unk) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UNKNOWN;
+  var_.punkVal = unk;
+  if (unk)
+    unk->AddRef();
+}
+
+void ScopedVariant::Set(SAFEARRAY* array) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
+    var_.vt |= VT_ARRAY;
+    var_.parray = array;
+  } else {
+    DCHECK(!array) << "Unable to determine safearray vartype";
+    var_.vt = VT_EMPTY;
+  }
+}
+
+void ScopedVariant::Set(const VARIANT& var) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  if (FAILED(::VariantCopy(&var_, &var))) {
+    DLOG(ERROR) << "VariantCopy failed";
+    var_.vt = VT_EMPTY;
+  }
+}
+
+ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
+  if (&var != &var_) {
+    VariantClear(&var_);
+    Set(var);
+  }
+  return *this;
+}
+
+bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
+  bool leakable = false;
+  switch (vt & VT_TYPEMASK) {
+    case VT_BSTR:
+    case VT_DISPATCH:
+    // we treat VT_VARIANT as leakable to err on the safe side.
+    case VT_VARIANT:
+    case VT_UNKNOWN:
+    case VT_SAFEARRAY:
+
+    // very rarely used stuff (if ever):
+    case VT_VOID:
+    case VT_PTR:
+    case VT_CARRAY:
+    case VT_USERDEFINED:
+    case VT_LPSTR:
+    case VT_LPWSTR:
+    case VT_RECORD:
+    case VT_INT_PTR:
+    case VT_UINT_PTR:
+    case VT_FILETIME:
+    case VT_BLOB:
+    case VT_STREAM:
+    case VT_STORAGE:
+    case VT_STREAMED_OBJECT:
+    case VT_STORED_OBJECT:
+    case VT_BLOB_OBJECT:
+    case VT_VERSIONED_STREAM:
+    case VT_BSTR_BLOB:
+      leakable = true;
+      break;
+  }
+
+  if (!leakable && (vt & VT_ARRAY) != 0) {
+    leakable = true;
+  }
+
+  return leakable;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_variant.h b/base/win/scoped_variant.h
new file mode 100644
index 0000000..322fcf7
--- /dev/null
+++ b/base/win/scoped_variant.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_VARIANT_H_
+#define BASE_WIN_SCOPED_VARIANT_H_
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Scoped VARIANT class for automatically freeing a COM VARIANT at the
+// end of a scope.  Additionally provides a few functions to make the
+// encapsulated VARIANT easier to use.
+// Instead of inheriting from VARIANT, we take the containment approach
+// in order to have more control over the usage of the variant and guard
+// against memory leaks.
+class BASE_EXPORT ScopedVariant {
+ public:
+  // Declaration of a global variant variable that's always VT_EMPTY
+  static const VARIANT kEmptyVariant;
+
+  // Default constructor.
+  ScopedVariant() {
+    // This is equivalent to what VariantInit does, but less code.
+    var_.vt = VT_EMPTY;
+  }
+
+  // Constructor to create a new VT_BSTR VARIANT.
+  // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+  // be transferred
+  explicit ScopedVariant(const wchar_t* str);
+
+  // Creates a new VT_BSTR variant of a specified length.
+  ScopedVariant(const wchar_t* str, UINT length);
+
+  // Creates a new integral type variant and assigns the value to
+  // VARIANT.lVal (32 bit sized field).
+  explicit ScopedVariant(int value, VARTYPE vt = VT_I4);
+
+  // Creates a new double-precision type variant.  |vt| must be either VT_R8
+  // or VT_DATE.
+  explicit ScopedVariant(double value, VARTYPE vt = VT_R8);
+
+  // VT_DISPATCH
+  explicit ScopedVariant(IDispatch* dispatch);
+
+  // VT_UNKNOWN
+  explicit ScopedVariant(IUnknown* unknown);
+
+  // SAFEARRAY
+  explicit ScopedVariant(SAFEARRAY* safearray);
+
+  // Copies the variant.
+  explicit ScopedVariant(const VARIANT& var);
+
+  ~ScopedVariant();
+
+  inline VARTYPE type() const {
+    return var_.vt;
+  }
+
+  // Give ScopedVariant ownership over an already allocated VARIANT.
+  void Reset(const VARIANT& var = kEmptyVariant);
+
+  // Releases ownership of the VARIANT to the caller.
+  VARIANT Release();
+
+  // Swap two ScopedVariant's.
+  void Swap(ScopedVariant& var);
+
+  // Returns a copy of the variant.
+  VARIANT Copy() const;
+
+  // The return value is 0 if the variants are equal, 1 if this object is
+  // greater than |var|, -1 if it is smaller.
+  int Compare(const VARIANT& var, bool ignore_case = false) const;
+
+  // Retrieves the pointer address.
+  // Used to receive a VARIANT as an out argument (and take ownership).
+  // The function DCHECKs on the current value being empty/null.
+  // Usage: GetVariant(var.receive());
+  VARIANT* Receive();
+
+  void Set(const wchar_t* str);
+
+  // Setters for simple types.
+  void Set(int8 i8);
+  void Set(uint8 ui8);
+  void Set(int16 i16);
+  void Set(uint16 ui16);
+  void Set(int32 i32);
+  void Set(uint32 ui32);
+  void Set(int64 i64);
+  void Set(uint64 ui64);
+  void Set(float r32);
+  void Set(double r64);
+  void Set(bool b);
+
+  // Creates a copy of |var| and assigns as this instance's value.
+  // Note that this is different from the Reset() method that's used to
+  // free the current value and assume ownership.
+  void Set(const VARIANT& var);
+
+  // COM object setters
+  void Set(IDispatch* disp);
+  void Set(IUnknown* unk);
+
+  // SAFEARRAY support
+  void Set(SAFEARRAY* array);
+
+  // Special setter for DATE since DATE is a double and we already have
+  // a setter for double.
+  void SetDate(DATE date);
+
+  // Allows const access to the contained variant without DCHECKs etc.
+  // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to
+  // work properly but still doesn't allow modifications since we want control
+  // over that.
+  const VARIANT* ptr() const { return &var_; }
+
+  // Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr)
+  // we support the assignment operator for the type we wrap.
+  ScopedVariant& operator=(const VARIANT& var);
+
+  // A hack to pass a pointer to the variant where the accepting
+  // function treats the variant as an input-only, read-only value
+  // but the function prototype requires a non const variant pointer.
+  // There's no DCHECK or anything here.  Callers must know what they're doing.
+  VARIANT* AsInput() const {
+    // The nature of this function is const, so we declare
+    // it as such and cast away the constness here.
+    return const_cast<VARIANT*>(&var_);
+  }
+
+  // Allows the ScopedVariant instance to be passed to functions either by value
+  // or by const reference.
+  operator const VARIANT&() const {
+    return var_;
+  }
+
+  // Used as a debug check to see if we're leaking anything.
+  static bool IsLeakableVarType(VARTYPE vt);
+
+ protected:
+  VARIANT var_;
+
+ private:
+  // Comparison operators for ScopedVariant are not supported at this point.
+  // Use the Compare method instead.
+  bool operator==(const ScopedVariant& var) const;
+  bool operator!=(const ScopedVariant& var) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedVariant);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_VARIANT_H_
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
new file mode 100644
index 0000000..d530d5b
--- /dev/null
+++ b/base/win/scoped_variant_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_variant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"Used to create BSTRs";
+static const wchar_t kTestString2[] = L"Also used to create BSTRs";
+
+void GiveMeAVariant(VARIANT* ret) {
+  EXPECT_TRUE(ret != NULL);
+  ret->vt = VT_BSTR;
+  V_BSTR(ret) = ::SysAllocString(kTestString1);
+}
+
+// A dummy IDispatch implementation (if you can call it that).
+// The class does nothing intelligent really.  Only increments a counter
+// when AddRef is called and decrements it when Release is called.
+class FakeComObject : public IDispatch {
+ public:
+  FakeComObject() : ref_(0) {
+  }
+
+  STDMETHOD_(DWORD, AddRef)() override {
+    ref_++;
+    return ref_;
+  }
+
+  STDMETHOD_(DWORD, Release)() override {
+    ref_--;
+    return ref_;
+  }
+
+  STDMETHOD(QueryInterface)(REFIID, void**) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetTypeInfoCount)(UINT*) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) override {
+    return E_NOTIMPL;
+  }
+
+  STDMETHOD(Invoke)(DISPID,
+                    REFIID,
+                    LCID,
+                    WORD,
+                    DISPPARAMS*,
+                    VARIANT*,
+                    EXCEPINFO*,
+                    UINT*) override {
+    return E_NOTIMPL;
+  }
+
+  // A way to check the internal reference count of the class.
+  int ref_count() const {
+    return ref_;
+  }
+
+ protected:
+  int ref_;
+};
+
+}  // namespace
+
+TEST(ScopedVariantTest, ScopedVariant) {
+  ScopedVariant var;
+  EXPECT_TRUE(var.type() == VT_EMPTY);
+  // V_BSTR(var.ptr()) = NULL;  <- NOTE: Assignment like that is not supported.
+
+  ScopedVariant var_bstr(L"VT_BSTR");
+  EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+  EXPECT_TRUE(V_BSTR(var_bstr.ptr()) != NULL);  // can't use EXPECT_NE for BSTR
+  var_bstr.Reset();
+  EXPECT_NE(VT_BSTR, V_VT(var_bstr.ptr()));
+  var_bstr.Set(kTestString2);
+  EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+
+  VARIANT tmp = var_bstr.Release();
+  EXPECT_EQ(VT_EMPTY, V_VT(var_bstr.ptr()));
+  EXPECT_EQ(VT_BSTR, V_VT(&tmp));
+  EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2));
+
+  var.Reset(tmp);
+  EXPECT_EQ(VT_BSTR, V_VT(var.ptr()));
+  EXPECT_EQ(0, lstrcmpW(V_BSTR(var.ptr()), kTestString2));
+
+  var_bstr.Swap(var);
+  EXPECT_EQ(VT_EMPTY, V_VT(var.ptr()));
+  EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+  EXPECT_EQ(0, lstrcmpW(V_BSTR(var_bstr.ptr()), kTestString2));
+  var_bstr.Reset();
+
+  // Test the Compare and Copy routines.
+  GiveMeAVariant(var_bstr.Receive());
+  ScopedVariant var_bstr2(V_BSTR(var_bstr.ptr()));
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  EXPECT_NE(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset(var_bstr.Copy());
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  var_bstr2.Set(V_BSTR(var_bstr.ptr()));
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  var_bstr.Reset();
+
+  // Test for the SetDate setter.
+  SYSTEMTIME sys_time;
+  ::GetSystemTime(&sys_time);
+  DATE date;
+  ::SystemTimeToVariantTime(&sys_time, &date);
+  var.Reset();
+  var.SetDate(date);
+  EXPECT_EQ(VT_DATE, var.type());
+  EXPECT_EQ(date, V_DATE(var.ptr()));
+
+  // Simple setter tests.  These do not require resetting the variant
+  // after each test since the variant type is not "leakable" (i.e. doesn't
+  // need to be freed explicitly).
+
+  // We need static cast here since char defaults to int (!?).
+  var.Set(static_cast<int8>('v'));
+  EXPECT_EQ(VT_I1, var.type());
+  EXPECT_EQ('v', V_I1(var.ptr()));
+
+  var.Set(static_cast<short>(123));
+  EXPECT_EQ(VT_I2, var.type());
+  EXPECT_EQ(123, V_I2(var.ptr()));
+
+  var.Set(static_cast<int32>(123));
+  EXPECT_EQ(VT_I4, var.type());
+  EXPECT_EQ(123, V_I4(var.ptr()));
+
+  var.Set(static_cast<int64>(123));
+  EXPECT_EQ(VT_I8, var.type());
+  EXPECT_EQ(123, V_I8(var.ptr()));
+
+  var.Set(static_cast<uint8>(123));
+  EXPECT_EQ(VT_UI1, var.type());
+  EXPECT_EQ(123, V_UI1(var.ptr()));
+
+  var.Set(static_cast<unsigned short>(123));
+  EXPECT_EQ(VT_UI2, var.type());
+  EXPECT_EQ(123, V_UI2(var.ptr()));
+
+  var.Set(static_cast<uint32>(123));
+  EXPECT_EQ(VT_UI4, var.type());
+  EXPECT_EQ(123, V_UI4(var.ptr()));
+
+  var.Set(static_cast<uint64>(123));
+  EXPECT_EQ(VT_UI8, var.type());
+  EXPECT_EQ(123, V_UI8(var.ptr()));
+
+  var.Set(123.123f);
+  EXPECT_EQ(VT_R4, var.type());
+  EXPECT_EQ(123.123f, V_R4(var.ptr()));
+
+  var.Set(static_cast<double>(123.123));
+  EXPECT_EQ(VT_R8, var.type());
+  EXPECT_EQ(123.123, V_R8(var.ptr()));
+
+  var.Set(true);
+  EXPECT_EQ(VT_BOOL, var.type());
+  EXPECT_EQ(VARIANT_TRUE, V_BOOL(var.ptr()));
+  var.Set(false);
+  EXPECT_EQ(VT_BOOL, var.type());
+  EXPECT_EQ(VARIANT_FALSE, V_BOOL(var.ptr()));
+
+  // Com interface tests
+
+  var.Set(static_cast<IDispatch*>(NULL));
+  EXPECT_EQ(VT_DISPATCH, var.type());
+  EXPECT_EQ(NULL, V_DISPATCH(var.ptr()));
+  var.Reset();
+
+  var.Set(static_cast<IUnknown*>(NULL));
+  EXPECT_EQ(VT_UNKNOWN, var.type());
+  EXPECT_EQ(NULL, V_UNKNOWN(var.ptr()));
+  var.Reset();
+
+  FakeComObject faker;
+  EXPECT_EQ(0, faker.ref_count());
+  var.Set(static_cast<IDispatch*>(&faker));
+  EXPECT_EQ(VT_DISPATCH, var.type());
+  EXPECT_EQ(&faker, V_DISPATCH(var.ptr()));
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  var.Set(static_cast<IUnknown*>(&faker));
+  EXPECT_EQ(VT_UNKNOWN, var.type());
+  EXPECT_EQ(&faker, V_UNKNOWN(var.ptr()));
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant disp_var(&faker);
+    EXPECT_EQ(VT_DISPATCH, disp_var.type());
+    EXPECT_EQ(&faker, V_DISPATCH(disp_var.ptr()));
+    EXPECT_EQ(1, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant ref1(&faker);
+    EXPECT_EQ(1, faker.ref_count());
+    ScopedVariant ref2(static_cast<const VARIANT&>(ref1));
+    EXPECT_EQ(2, faker.ref_count());
+    ScopedVariant ref3;
+    ref3 = static_cast<const VARIANT&>(ref2);
+    EXPECT_EQ(3, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant unk_var(static_cast<IUnknown*>(&faker));
+    EXPECT_EQ(VT_UNKNOWN, unk_var.type());
+    EXPECT_EQ(&faker, V_UNKNOWN(unk_var.ptr()));
+    EXPECT_EQ(1, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  VARIANT raw;
+  raw.vt = VT_UNKNOWN;
+  raw.punkVal = &faker;
+  EXPECT_EQ(0, faker.ref_count());
+  var.Set(raw);
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant number(123);
+    EXPECT_EQ(VT_I4, number.type());
+    EXPECT_EQ(123, V_I4(number.ptr()));
+  }
+
+  // SAFEARRAY tests
+  var.Set(static_cast<SAFEARRAY*>(NULL));
+  EXPECT_EQ(VT_EMPTY, var.type());
+
+  SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100);
+  ASSERT_TRUE(sa != NULL);
+
+  var.Set(sa);
+  EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type()));
+  EXPECT_EQ(VT_ARRAY | VT_UI1, var.type());
+  EXPECT_EQ(sa, V_ARRAY(var.ptr()));
+  // The array is destroyed in the destructor of var.
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
new file mode 100644
index 0000000..f8b2182
--- /dev/null
+++ b/base/win/shortcut.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/shortcut.h"
+
+#include <shellapi.h>
+#include <shlobj.h>
+#include <propkey.h>
+
+#include "base/files/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_propvariant.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
+// are already initialized).
+// If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
+// If any of the above steps fail, both |i_shell_link| and |i_persist_file| will
+// be released.
+void InitializeShortcutInterfaces(
+    const wchar_t* shortcut,
+    ScopedComPtr<IShellLink>* i_shell_link,
+    ScopedComPtr<IPersistFile>* i_persist_file) {
+  i_shell_link->Release();
+  i_persist_file->Release();
+  if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL,
+                                          CLSCTX_INPROC_SERVER)) ||
+      FAILED(i_persist_file->QueryFrom(i_shell_link->get())) ||
+      (shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) {
+    i_shell_link->Release();
+    i_persist_file->Release();
+  }
+}
+
+}  // namespace
+
+ShortcutProperties::ShortcutProperties()
+    : icon_index(-1), dual_mode(false), options(0U) {
+}
+
+ShortcutProperties::~ShortcutProperties() {
+}
+
+bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
+                                const ShortcutProperties& properties,
+                                ShortcutOperation operation) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // A target is required unless |operation| is SHORTCUT_UPDATE_EXISTING.
+  if (operation != SHORTCUT_UPDATE_EXISTING &&
+      !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) {
+    NOTREACHED();
+    return false;
+  }
+
+  bool shortcut_existed = PathExists(shortcut_path);
+
+  // Interfaces to the old shortcut when replacing an existing shortcut.
+  ScopedComPtr<IShellLink> old_i_shell_link;
+  ScopedComPtr<IPersistFile> old_i_persist_file;
+
+  // Interfaces to the shortcut being created/updated.
+  ScopedComPtr<IShellLink> i_shell_link;
+  ScopedComPtr<IPersistFile> i_persist_file;
+  switch (operation) {
+    case SHORTCUT_CREATE_ALWAYS:
+      InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file);
+      break;
+    case SHORTCUT_UPDATE_EXISTING:
+      InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link,
+                                   &i_persist_file);
+      break;
+    case SHORTCUT_REPLACE_EXISTING:
+      InitializeShortcutInterfaces(shortcut_path.value().c_str(),
+                                   &old_i_shell_link, &old_i_persist_file);
+      // Confirm |shortcut_path| exists and is a shortcut by verifying
+      // |old_i_persist_file| was successfully initialized in the call above. If
+      // so, initialize the interfaces to begin writing a new shortcut (to
+      // overwrite the current one if successful).
+      if (old_i_persist_file.get())
+        InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  // Return false immediately upon failure to initialize shortcut interfaces.
+  if (!i_persist_file.get())
+    return false;
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) &&
+      FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) &&
+      FAILED(i_shell_link->SetWorkingDirectory(
+          properties.working_dir.value().c_str()))) {
+    return false;
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    if (FAILED(i_shell_link->SetArguments(properties.arguments.c_str())))
+      return false;
+  } else if (old_i_persist_file.get()) {
+    wchar_t current_arguments[MAX_PATH] = {0};
+    if (SUCCEEDED(old_i_shell_link->GetArguments(current_arguments,
+                                                 MAX_PATH))) {
+      i_shell_link->SetArguments(current_arguments);
+    }
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
+      FAILED(i_shell_link->SetDescription(properties.description.c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_ICON) &&
+      FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(),
+                                           properties.icon_index))) {
+    return false;
+  }
+
+  bool has_app_id =
+      (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0;
+  bool has_dual_mode =
+      (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
+  if ((has_app_id || has_dual_mode) &&
+      GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    if (FAILED(property_store.QueryFrom(i_shell_link.get())) ||
+        !property_store.get())
+      return false;
+
+    if (has_app_id &&
+        !SetAppIdForPropertyStore(property_store.get(),
+                                  properties.app_id.c_str())) {
+      return false;
+    }
+    if (has_dual_mode &&
+        !SetBooleanValueForPropertyStore(property_store.get(),
+                                         PKEY_AppUserModel_IsDualMode,
+                                         properties.dual_mode)) {
+      return false;
+    }
+  }
+
+  // Release the interfaces to the old shortcut to make sure it doesn't prevent
+  // overwriting it if needed.
+  old_i_persist_file.Release();
+  old_i_shell_link.Release();
+
+  HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE);
+
+  // Release the interfaces in case the SHChangeNotify call below depends on
+  // the operations above being fully completed.
+  i_persist_file.Release();
+  i_shell_link.Release();
+
+  // If we successfully created/updated the icon, notify the shell that we have
+  // done so.
+  const bool succeeded = SUCCEEDED(result);
+  if (succeeded) {
+    if (shortcut_existed) {
+      // TODO(gab): SHCNE_UPDATEITEM might be sufficient here; further testing
+      // required.
+      SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+    } else {
+      SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, shortcut_path.value().c_str(),
+                     NULL);
+    }
+  }
+
+  return succeeded;
+}
+
+bool ResolveShortcutProperties(const FilePath& shortcut_path,
+                               uint32 options,
+                               ShortcutProperties* properties) {
+  DCHECK(options && properties);
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (options & ~ShortcutProperties::PROPERTIES_ALL)
+    NOTREACHED() << "Unhandled property is used.";
+
+  ScopedComPtr<IShellLink> i_shell_link;
+
+  // Get pointer to the IShellLink interface.
+  if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+                                         CLSCTX_INPROC_SERVER))) {
+    return false;
+  }
+
+  ScopedComPtr<IPersistFile> persist;
+  // Query IShellLink for the IPersistFile interface.
+  if (FAILED(persist.QueryFrom(i_shell_link.get())))
+    return false;
+
+  // Load the shell link.
+  if (FAILED(persist->Load(shortcut_path.value().c_str(), STGM_READ)))
+    return false;
+
+  // Reset |properties|.
+  properties->options = 0;
+
+  wchar_t temp[MAX_PATH];
+  if (options & ShortcutProperties::PROPERTIES_TARGET) {
+    if (FAILED(i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY)))
+      return false;
+    properties->set_target(FilePath(temp));
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+    if (FAILED(i_shell_link->GetWorkingDirectory(temp, MAX_PATH)))
+      return false;
+    properties->set_working_dir(FilePath(temp));
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    if (FAILED(i_shell_link->GetArguments(temp, MAX_PATH)))
+      return false;
+    properties->set_arguments(temp);
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+    // Note: description length constrained by MAX_PATH.
+    if (FAILED(i_shell_link->GetDescription(temp, MAX_PATH)))
+      return false;
+    properties->set_description(temp);
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_ICON) {
+    int temp_index;
+    if (FAILED(i_shell_link->GetIconLocation(temp, MAX_PATH, &temp_index)))
+      return false;
+    properties->set_icon(FilePath(temp), temp_index);
+  }
+
+  // Windows 7+ options, avoiding unnecessary work.
+  if ((options & ShortcutProperties::PROPERTIES_WIN7) &&
+      GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    if (FAILED(property_store.QueryFrom(i_shell_link.get())))
+      return false;
+
+    if (options & ShortcutProperties::PROPERTIES_APP_ID) {
+      ScopedPropVariant pv_app_id;
+      if (property_store->GetValue(PKEY_AppUserModel_ID,
+                                   pv_app_id.Receive()) != S_OK) {
+        return false;
+      }
+      switch (pv_app_id.get().vt) {
+        case VT_EMPTY:
+          properties->set_app_id(L"");
+          break;
+        case VT_LPWSTR:
+          properties->set_app_id(pv_app_id.get().pwszVal);
+          break;
+        default:
+          NOTREACHED() << "Unexpected variant type: " << pv_app_id.get().vt;
+          return false;
+      }
+    }
+
+    if (options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+      ScopedPropVariant pv_dual_mode;
+      if (property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+                                   pv_dual_mode.Receive()) != S_OK) {
+        return false;
+      }
+      switch (pv_dual_mode.get().vt) {
+        case VT_EMPTY:
+          properties->set_dual_mode(false);
+          break;
+        case VT_BOOL:
+          properties->set_dual_mode(pv_dual_mode.get().boolVal == VARIANT_TRUE);
+          break;
+        default:
+          NOTREACHED() << "Unexpected variant type: " << pv_dual_mode.get().vt;
+          return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool ResolveShortcut(const FilePath& shortcut_path,
+                     FilePath* target_path,
+                     string16* args) {
+  uint32 options = 0;
+  if (target_path)
+    options |= ShortcutProperties::PROPERTIES_TARGET;
+  if (args)
+    options |= ShortcutProperties::PROPERTIES_ARGUMENTS;
+  DCHECK(options);
+
+  ShortcutProperties properties;
+  if (!ResolveShortcutProperties(shortcut_path, options, &properties))
+    return false;
+
+  if (target_path)
+    *target_path = properties.target;
+  if (args)
+    *args = properties.arguments;
+  return true;
+}
+
+bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // "Pin to taskbar" is only supported after Win7.
+  if (GetVersion() < VERSION_WIN7)
+    return false;
+
+  intptr_t result = reinterpret_cast<intptr_t>(
+      ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
+  return result > 32;
+}
+
+bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // "Unpin from taskbar" is only supported after Win7.
+  if (GetVersion() < VERSION_WIN7)
+    return false;
+
+  intptr_t result = reinterpret_cast<intptr_t>(
+      ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
+  return result > 32;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
new file mode 100644
index 0000000..6f7d10c
--- /dev/null
+++ b/base/win/shortcut.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SHORTCUT_H_
+#define BASE_WIN_SHORTCUT_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+enum ShortcutOperation {
+  // Create a new shortcut (overwriting if necessary).
+  SHORTCUT_CREATE_ALWAYS = 0,
+  // Overwrite an existing shortcut (fails if the shortcut doesn't exist).
+  // If the arguments are not specified on the new shortcut, keep the old
+  // shortcut's arguments.
+  SHORTCUT_REPLACE_EXISTING,
+  // Update specified properties only on an existing shortcut.
+  SHORTCUT_UPDATE_EXISTING,
+};
+
+// Properties for shortcuts. Properties set will be applied to the shortcut on
+// creation/update, others will be ignored.
+// Callers are encouraged to use the setters provided which take care of
+// setting |options| as desired.
+struct BASE_EXPORT ShortcutProperties {
+  enum IndividualProperties {
+    PROPERTIES_TARGET = 1U << 0,
+    PROPERTIES_WORKING_DIR = 1U << 1,
+    PROPERTIES_ARGUMENTS = 1U << 2,
+    PROPERTIES_DESCRIPTION = 1U << 3,
+    PROPERTIES_ICON = 1U << 4,
+    PROPERTIES_APP_ID = 1U << 5,
+    PROPERTIES_DUAL_MODE = 1U << 6,
+    // Be sure to update the values below when adding a new property.
+    PROPERTIES_BASIC = PROPERTIES_TARGET |
+        PROPERTIES_WORKING_DIR |
+        PROPERTIES_ARGUMENTS |
+        PROPERTIES_DESCRIPTION |
+        PROPERTIES_ICON,
+    PROPERTIES_WIN7 = PROPERTIES_APP_ID | PROPERTIES_DUAL_MODE,
+    PROPERTIES_ALL = PROPERTIES_BASIC | PROPERTIES_WIN7
+  };
+
+  ShortcutProperties();
+  ~ShortcutProperties();
+
+  void set_target(const FilePath& target_in) {
+    target = target_in;
+    options |= PROPERTIES_TARGET;
+  }
+
+  void set_working_dir(const FilePath& working_dir_in) {
+    working_dir = working_dir_in;
+    options |= PROPERTIES_WORKING_DIR;
+  }
+
+  void set_arguments(const string16& arguments_in) {
+    // Size restriction as per MSDN at http://goo.gl/TJ7q5.
+    DCHECK(arguments_in.size() < MAX_PATH);
+    arguments = arguments_in;
+    options |= PROPERTIES_ARGUMENTS;
+  }
+
+  void set_description(const string16& description_in) {
+    // Size restriction as per MSDN at http://goo.gl/OdNQq.
+    DCHECK(description_in.size() < MAX_PATH);
+    description = description_in;
+    options |= PROPERTIES_DESCRIPTION;
+  }
+
+  void set_icon(const FilePath& icon_in, int icon_index_in) {
+    icon = icon_in;
+    icon_index = icon_index_in;
+    options |= PROPERTIES_ICON;
+  }
+
+  void set_app_id(const string16& app_id_in) {
+    app_id = app_id_in;
+    options |= PROPERTIES_APP_ID;
+  }
+
+  void set_dual_mode(bool dual_mode_in) {
+    dual_mode = dual_mode_in;
+    options |= PROPERTIES_DUAL_MODE;
+  }
+
+  // The target to launch from this shortcut. This is mandatory when creating
+  // a shortcut.
+  FilePath target;
+  // The name of the working directory when launching the shortcut.
+  FilePath working_dir;
+  // The arguments to be applied to |target| when launching from this shortcut.
+  // The length of this string must be less than MAX_PATH.
+  string16 arguments;
+  // The localized description of the shortcut.
+  // The length of this string must be less than MAX_PATH.
+  string16 description;
+  // The path to the icon (can be a dll or exe, in which case |icon_index| is
+  // the resource id).
+  FilePath icon;
+  int icon_index;
+  // The app model id for the shortcut (Win7+).
+  string16 app_id;
+  // Whether this is a dual mode shortcut (Win8+).
+  bool dual_mode;
+  // Bitfield made of IndividualProperties. Properties set in |options| will be
+  // set on the shortcut, others will be ignored.
+  uint32 options;
+};
+
+// This method creates (or updates) a shortcut link at |shortcut_path| using the
+// information given through |properties|.
+// Ensure you have initialized COM before calling into this function.
+// |operation|: a choice from the ShortcutOperation enum.
+// If |operation| is SHORTCUT_REPLACE_EXISTING or SHORTCUT_UPDATE_EXISTING and
+// |shortcut_path| does not exist, this method is a no-op and returns false.
+BASE_EXPORT bool CreateOrUpdateShortcutLink(
+    const FilePath& shortcut_path,
+    const ShortcutProperties& properties,
+    ShortcutOperation operation);
+
+// Resolves Windows shortcut (.LNK file).
+// This methods tries to resolve selected properties of a shortcut .LNK file.
+// The path of the shortcut to resolve is in |shortcut_path|. |options| is a bit
+// field composed of ShortcutProperties::IndividualProperties, to specify which
+// properties to read. It should be non-0. The resulting data are read into
+// |properties|, which must not be NULL. Note: PROPERTIES_TARGET will retrieve
+// the target path as stored in the shortcut but won't attempt to resolve that
+// path so it may not be valid. The function returns true if all requested
+// properties are successfully read. Otherwise some reads have failed and
+// intermediate values written to |properties| should be ignored.
+BASE_EXPORT bool ResolveShortcutProperties(const FilePath& shortcut_path,
+                                           uint32 options,
+                                           ShortcutProperties* properties);
+
+// Resolves Windows shortcut (.LNK file).
+// This is a wrapper to ResolveShortcutProperties() to handle the common use
+// case of resolving target and arguments. |target_path| and |args| are
+// optional output variables that are ignored if NULL (but at least one must be
+// non-NULL). The function returns true if all requested fields are found
+// successfully. Callers can safely use the same variable for both
+// |shortcut_path| and |target_path|.
+BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
+                                 FilePath* target_path,
+                                 string16* args);
+
+// Pins a shortcut to the Windows 7 taskbar. The shortcut file must already
+// exist and be a shortcut that points to an executable. The app id of the
+// shortcut is used to group windows and must be set correctly.
+BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut);
+
+// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
+// already be pinned to the taskbar. The app id of the shortcut is used as the
+// identifier for the taskbar item to remove and must be set correctly.
+BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SHORTCUT_H_
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
new file mode 100644
index 0000000..794be23
--- /dev/null
+++ b/base/win/shortcut_unittest.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/shortcut.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_shortcut_win.h"
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const char kFileContents[] = "This is a target.";
+static const char kFileContents2[] = "This is another target.";
+
+class ShortcutTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
+
+    link_file_ = temp_dir_.path().Append(L"My Link.lnk");
+
+    // Shortcut 1's properties
+    {
+      const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
+      WriteFile(target_file, kFileContents, arraysize(kFileContents));
+
+      link_properties_.set_target(target_file);
+      link_properties_.set_working_dir(temp_dir_.path());
+      link_properties_.set_arguments(L"--magic --awesome");
+      link_properties_.set_description(L"Chrome is awesome.");
+      link_properties_.set_icon(link_properties_.target, 4);
+      link_properties_.set_app_id(L"Chrome");
+      link_properties_.set_dual_mode(false);
+    }
+
+    // Shortcut 2's properties (all different from properties of shortcut 1).
+    {
+      const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt"));
+      WriteFile(target_file_2, kFileContents2, arraysize(kFileContents2));
+
+      FilePath icon_path_2;
+      CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
+
+      link_properties_2_.set_target(target_file_2);
+      link_properties_2_.set_working_dir(temp_dir_2_.path());
+      link_properties_2_.set_arguments(L"--super --crazy");
+      link_properties_2_.set_description(L"The best in the west.");
+      link_properties_2_.set_icon(icon_path_2, 0);
+      link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix");
+      link_properties_2_.set_dual_mode(true);
+    }
+  }
+
+  ScopedCOMInitializer com_initializer_;
+  ScopedTempDir temp_dir_;
+  ScopedTempDir temp_dir_2_;
+
+  // The link file to be created/updated in the shortcut tests below.
+  FilePath link_file_;
+
+  // Properties for the created shortcut.
+  ShortcutProperties link_properties_;
+
+  // Properties for the updated shortcut.
+  ShortcutProperties link_properties_2_;
+};
+
+}  // namespace
+
+TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
+  uint32 valid_properties = ShortcutProperties::PROPERTIES_BASIC;
+  if (GetVersion() >= VERSION_WIN7)
+    valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
+
+  // Test all properties.
+  FilePath file_1(temp_dir_.path().Append(L"Link1.lnk"));
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      file_1, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties properties_read_1;
+  ASSERT_TRUE(ResolveShortcutProperties(
+      file_1, ShortcutProperties::PROPERTIES_ALL, &properties_read_1));
+  EXPECT_EQ(valid_properties, properties_read_1.options);
+  ValidatePathsAreEqual(link_properties_.target, properties_read_1.target);
+  ValidatePathsAreEqual(link_properties_.working_dir,
+                        properties_read_1.working_dir);
+  EXPECT_EQ(link_properties_.arguments, properties_read_1.arguments);
+  EXPECT_EQ(link_properties_.description, properties_read_1.description);
+  ValidatePathsAreEqual(link_properties_.icon, properties_read_1.icon);
+  EXPECT_EQ(link_properties_.icon_index, properties_read_1.icon_index);
+  if (GetVersion() >= VERSION_WIN7) {
+    EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id);
+    EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode);
+  }
+
+  // Test simple shortcut with no special properties set.
+  FilePath file_2(temp_dir_.path().Append(L"Link2.lnk"));
+  ShortcutProperties only_target_properties;
+  only_target_properties.set_target(link_properties_.target);
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      file_2, only_target_properties, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties properties_read_2;
+  ASSERT_TRUE(ResolveShortcutProperties(
+      file_2, ShortcutProperties::PROPERTIES_ALL, &properties_read_2));
+  EXPECT_EQ(valid_properties, properties_read_2.options);
+  ValidatePathsAreEqual(only_target_properties.target,
+                        properties_read_2.target);
+  ValidatePathsAreEqual(FilePath(), properties_read_2.working_dir);
+  EXPECT_EQ(L"", properties_read_2.arguments);
+  EXPECT_EQ(L"", properties_read_2.description);
+  ValidatePathsAreEqual(FilePath(), properties_read_2.icon);
+  EXPECT_EQ(0, properties_read_2.icon_index);
+  if (GetVersion() >= VERSION_WIN7) {
+    EXPECT_EQ(L"", properties_read_2.app_id);
+    EXPECT_FALSE(properties_read_2.dual_mode);
+  }
+}
+
+TEST_F(ShortcutTest, CreateAndResolveShortcut) {
+  ShortcutProperties only_target_properties;
+  only_target_properties.set_target(link_properties_.target);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, only_target_properties, SHORTCUT_CREATE_ALWAYS));
+
+  FilePath resolved_name;
+  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
+
+  char read_contents[arraysize(kFileContents)];
+  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents, read_contents);
+}
+
+TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  FilePath resolved_name;
+  string16 args;
+  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, &args));
+
+  char read_contents[arraysize(kFileContents)];
+  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents, read_contents);
+  EXPECT_EQ(link_properties_.arguments, args);
+}
+
+TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
+  ShortcutProperties target_and_args_properties;
+  target_and_args_properties.set_target(link_properties_.target);
+  target_and_args_properties.set_arguments(link_properties_.arguments);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, target_and_args_properties,
+      SHORTCUT_CREATE_ALWAYS));
+
+  ValidateShortcut(link_file_, target_and_args_properties);
+}
+
+TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ValidateShortcut(link_file_, link_properties_);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_UPDATE_EXISTING));
+
+  ValidateShortcut(link_file_, link_properties_2_);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties update_only_target_properties;
+  update_only_target_properties.set_target(link_properties_2_.target);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, update_only_target_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_target(link_properties_2_.target);
+  ValidateShortcut(link_file_, expected_properties);
+
+  FilePath resolved_name;
+  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
+
+  char read_contents[arraysize(kFileContents2)];
+  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents2, read_contents);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties make_dual_mode_properties;
+  make_dual_mode_properties.set_dual_mode(true);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, make_dual_mode_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_dual_mode(true);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties remove_dual_mode_properties;
+  remove_dual_mode_properties.set_dual_mode(false);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, remove_dual_mode_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_2_;
+  expected_properties.set_dual_mode(false);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties clear_arguments_properties;
+  clear_arguments_properties.set_arguments(string16());
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, clear_arguments_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_arguments(string16());
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) {
+  ASSERT_FALSE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_UPDATE_EXISTING));
+  ASSERT_FALSE(PathExists(link_file_));
+}
+
+TEST_F(ShortcutTest, ReplaceShortcutAllProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
+
+  ValidateShortcut(link_file_, link_properties_2_);
+}
+
+TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties new_properties;
+  new_properties.set_target(link_properties_2_.target);
+  new_properties.set_arguments(link_properties_2_.arguments);
+  new_properties.set_description(link_properties_2_.description);
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, new_properties, SHORTCUT_REPLACE_EXISTING));
+
+  // Expect only properties in |new_properties| to be set, all other properties
+  // should have been overwritten.
+  ShortcutProperties expected_properties(new_properties);
+  expected_properties.set_working_dir(FilePath());
+  expected_properties.set_icon(FilePath(), 0);
+  expected_properties.set_app_id(string16());
+  expected_properties.set_dual_mode(false);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, FailReplaceShortcutThatDoesNotExist) {
+  ASSERT_FALSE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_REPLACE_EXISTING));
+  ASSERT_FALSE(PathExists(link_file_));
+}
+
+// Test that the old arguments remain on the replaced shortcut when not
+// otherwise specified.
+TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  // Do not explicitly set the arguments.
+  link_properties_2_.options &=
+      ~ShortcutProperties::PROPERTIES_ARGUMENTS;
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
+
+  ShortcutProperties expected_properties(link_properties_2_);
+  expected_properties.set_arguments(link_properties_.arguments);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/startup_information.cc b/base/win/startup_information.cc
new file mode 100644
index 0000000..aff52eb
--- /dev/null
+++ b/base/win/startup_information.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/startup_information.h"
+
+#include "base/logging.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+typedef BOOL (WINAPI *InitializeProcThreadAttributeListFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST attribute_list,
+    DWORD attribute_count,
+    DWORD flags,
+    PSIZE_T size);
+static InitializeProcThreadAttributeListFunction
+    initialize_proc_thread_attribute_list;
+
+typedef BOOL (WINAPI *UpdateProcThreadAttributeFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST attribute_list,
+    DWORD flags,
+    DWORD_PTR attribute,
+    PVOID value,
+    SIZE_T size,
+    PVOID previous_value,
+    PSIZE_T return_size);
+static UpdateProcThreadAttributeFunction update_proc_thread_attribute_list;
+
+typedef VOID (WINAPI *DeleteProcThreadAttributeListFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList);
+static DeleteProcThreadAttributeListFunction delete_proc_thread_attribute_list;
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+StartupInformation::StartupInformation() {
+  memset(&startup_info_, 0, sizeof(startup_info_));
+
+  // Pre Windows Vista doesn't support STARTUPINFOEX.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    startup_info_.StartupInfo.cb = sizeof(STARTUPINFO);
+    return;
+  }
+
+  startup_info_.StartupInfo.cb = sizeof(startup_info_);
+
+  // Load the attribute API functions.
+  if (!initialize_proc_thread_attribute_list ||
+      !update_proc_thread_attribute_list ||
+      !delete_proc_thread_attribute_list) {
+    HMODULE module = ::GetModuleHandleW(L"kernel32.dll");
+    initialize_proc_thread_attribute_list =
+        reinterpret_cast<InitializeProcThreadAttributeListFunction>(
+            ::GetProcAddress(module, "InitializeProcThreadAttributeList"));
+    update_proc_thread_attribute_list =
+        reinterpret_cast<UpdateProcThreadAttributeFunction>(
+            ::GetProcAddress(module, "UpdateProcThreadAttribute"));
+    delete_proc_thread_attribute_list =
+        reinterpret_cast<DeleteProcThreadAttributeListFunction>(
+            ::GetProcAddress(module, "DeleteProcThreadAttributeList"));
+  }
+}
+
+StartupInformation::~StartupInformation() {
+  if (startup_info_.lpAttributeList) {
+    delete_proc_thread_attribute_list(startup_info_.lpAttributeList);
+    delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList);
+  }
+}
+
+bool StartupInformation::InitializeProcThreadAttributeList(
+    DWORD attribute_count) {
+  if (startup_info_.StartupInfo.cb != sizeof(startup_info_) ||
+      startup_info_.lpAttributeList)
+    return false;
+
+  SIZE_T size = 0;
+  initialize_proc_thread_attribute_list(NULL, attribute_count, 0, &size);
+  if (size == 0)
+    return false;
+
+  startup_info_.lpAttributeList =
+      reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new BYTE[size]);
+  if (!initialize_proc_thread_attribute_list(startup_info_.lpAttributeList,
+                                           attribute_count, 0, &size)) {
+    delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList);
+    startup_info_.lpAttributeList = NULL;
+    return false;
+  }
+
+  return true;
+}
+
+bool StartupInformation::UpdateProcThreadAttribute(
+    DWORD_PTR attribute,
+    void* value,
+    size_t size) {
+  if (!startup_info_.lpAttributeList)
+    return false;
+  return !!update_proc_thread_attribute_list(startup_info_.lpAttributeList, 0,
+                                       attribute, value, size, NULL, NULL);
+}
+
+}  // namespace win
+}  // namespace base
+
diff --git a/base/win/startup_information.h b/base/win/startup_information.h
new file mode 100644
index 0000000..73d9f3e
--- /dev/null
+++ b/base/win/startup_information.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_STARTUP_INFORMATION_H_
+#define BASE_WIN_STARTUP_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Manages the lifetime of additional attributes in STARTUPINFOEX.
+class BASE_EXPORT StartupInformation {
+ public:
+  StartupInformation();
+
+  ~StartupInformation();
+
+  // Initialize the attribute list for the specified number of entries.
+  bool InitializeProcThreadAttributeList(DWORD attribute_count);
+
+  // Sets one entry in the initialized attribute list.
+  // |value| needs to live at least as long as the StartupInformation object
+  // this is called on.
+  bool UpdateProcThreadAttribute(DWORD_PTR attribute,
+                                 void* value,
+                                 size_t size);
+
+  LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; }
+  const LPSTARTUPINFOW startup_info() const {
+    return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo);
+  }
+
+  bool has_extended_startup_info() const {
+    return !!startup_info_.lpAttributeList;
+  }
+
+ private:
+  STARTUPINFOEXW startup_info_;
+  DISALLOW_COPY_AND_ASSIGN(StartupInformation);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_STARTUP_INFORMATION_H__
diff --git a/base/win/startup_information_unittest.cc b/base/win/startup_information_unittest.cc
new file mode 100644
index 0000000..36c6e84
--- /dev/null
+++ b/base/win/startup_information_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "testing/multiprocess_func_list.h"
+
+const wchar_t kSectionName[] = L"EventTestSection";
+const size_t kSectionSize = 4096;
+
+MULTIPROCESS_TEST_MAIN(FireInheritedEvents) {
+  HANDLE section = ::OpenFileMappingW(PAGE_READWRITE, false, kSectionName);
+  HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section,
+      PAGE_READWRITE, 0, 0, kSectionSize));
+  // This event should not be valid because it wasn't explicitly inherited.
+  if (::SetEvent(events[1]))
+    return -1;
+  // This event should be valid because it was explicitly inherited.
+  if (!::SetEvent(events[0]))
+    return -1;
+
+  return 0;
+}
+
+class StartupInformationTest : public base::MultiProcessTest {};
+
+// Verify that only the explicitly specified event is inherited.
+TEST_F(StartupInformationTest, InheritStdOut) {
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return;
+
+  base::win::StartupInformation startup_info;
+
+  HANDLE section = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+                                        PAGE_READWRITE, 0, kSectionSize,
+                                        kSectionName);
+  ASSERT_TRUE(section);
+
+  HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section,
+      FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kSectionSize));
+
+  // Make two inheritable events.
+  SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes),
+                                              NULL, true };
+  events[0] = ::CreateEvent(&security_attributes, false, false, NULL);
+  ASSERT_TRUE(events[0]);
+  events[1] = ::CreateEvent(&security_attributes, false, false, NULL);
+  ASSERT_TRUE(events[1]);
+
+  ASSERT_TRUE(startup_info.InitializeProcThreadAttributeList(1));
+  ASSERT_TRUE(startup_info.UpdateProcThreadAttribute(
+      PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &events[0],
+      sizeof(events[0])));
+
+  std::wstring cmd_line =
+      MakeCmdLine("FireInheritedEvents").GetCommandLineString();
+
+  PROCESS_INFORMATION temp_process_info = {};
+  ASSERT_TRUE(::CreateProcess(NULL, &cmd_line[0],
+                              NULL, NULL, true, EXTENDED_STARTUPINFO_PRESENT,
+                              NULL, NULL, startup_info.startup_info(),
+                              &temp_process_info)) << ::GetLastError();
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  // Only the first event should be signalled
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(2, events, false,
+                                                    4000));
+}
+
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
new file mode 100644
index 0000000..c5b06c4
--- /dev/null
+++ b/base/win/win_util.cc
@@ -0,0 +1,496 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/win_util.h"
+
+#include <aclapi.h>
+#include <cfgmgr32.h>
+#include <lm.h>
+#include <powrprof.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <shobjidl.h>  // Must be before propkey.
+#include <initguid.h>
+#include <propkey.h>
+#include <propvarutil.h>
+#include <sddl.h>
+#include <setupapi.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/metro.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_propvariant.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+// Sets the value of |property_key| to |property_value| in |property_store|.
+bool SetPropVariantValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    const base::win::ScopedPropVariant& property_value) {
+  DCHECK(property_store);
+
+  HRESULT result = property_store->SetValue(property_key, property_value.get());
+  if (result == S_OK)
+    result = property_store->Commit();
+  return SUCCEEDED(result);
+}
+
+void __cdecl ForceCrashOnSigAbort(int) {
+  *((int*)0) = 0x1337;
+}
+
+const wchar_t kWindows8OSKRegPath[] =
+    L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
+    L"\\LocalServer32";
+
+// Returns true if a physical keyboard is detected on Windows 8 and up.
+// Uses the Setup APIs to enumerate the attached keyboards and returns true
+// if the keyboard count is 1 or more.. While this will work in most cases
+// it won't work if there are devices which expose keyboard interfaces which
+// are attached to the machine.
+bool IsKeyboardPresentOnSlate() {
+  // This function is only supported for Windows 8 and up.
+  DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN8);
+
+  // This function should be only invoked for machines with touch screens.
+  if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
+        != NID_INTEGRATED_TOUCH) {
+    return true;
+  }
+
+  // If the device is docked, the user is treating the device as a PC.
+  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
+    return true;
+
+  // To determine whether a keyboard is present on the device, we do the
+  // following:-
+  // 1. Check whether the device supports auto rotation. If it does then
+  //    it possibly supports flipping from laptop to slate mode. If it
+  //    does not support auto rotation, then we assume it is a desktop
+  //    or a normal laptop and assume that there is a keyboard.
+
+  // 2. If the device supports auto rotation, then we get its platform role
+  //    and check the system metric SM_CONVERTIBLESLATEMODE to see if it is
+  //    being used in slate mode. If yes then we return false here to ensure
+  //    that the OSK is displayed.
+
+  // 3. If step 1 and 2 fail then we check attached keyboards and return true
+  //    if we find ACPI\* or HID\VID* keyboards.
+
+  typedef BOOL (WINAPI* GetAutoRotationState)(PAR_STATE state);
+
+  GetAutoRotationState get_rotation_state =
+      reinterpret_cast<GetAutoRotationState>(::GetProcAddress(
+          GetModuleHandle(L"user32.dll"), "GetAutoRotationState"));
+
+  if (get_rotation_state) {
+    AR_STATE auto_rotation_state = AR_ENABLED;
+    get_rotation_state(&auto_rotation_state);
+    if ((auto_rotation_state & AR_NOSENSOR) ||
+        (auto_rotation_state & AR_NOT_SUPPORTED)) {
+      // If there is no auto rotation sensor or rotation is not supported in
+      // the current configuration, then we can assume that this is a desktop
+      // or a traditional laptop.
+      return true;
+    }
+  }
+
+  // Check if the device is being used as a laptop or a tablet. This can be
+  // checked by first checking the role of the device and then the
+  // corresponding system metric (SM_CONVERTIBLESLATEMODE). If it is being used
+  // as a tablet then we want the OSK to show up.
+  POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+
+  if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
+       (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0))
+    return false;
+
+  const GUID KEYBOARD_CLASS_GUID =
+      { 0x4D36E96B, 0xE325,  0x11CE,
+          { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+
+  // Query for all the keyboard devices.
+  HDEVINFO device_info =
+      SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, NULL, NULL, DIGCF_PRESENT);
+  if (device_info == INVALID_HANDLE_VALUE)
+    return false;
+
+  // Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If
+  // the count is more than 1 we assume that a keyboard is present. This is
+  // under the assumption that there will always be one keyboard device.
+  int keyboard_count = 0;
+  for (DWORD i = 0;; ++i) {
+    SP_DEVINFO_DATA device_info_data = { 0 };
+    device_info_data.cbSize = sizeof(device_info_data);
+    if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data))
+      break;
+
+    // Get the device ID.
+    wchar_t device_id[MAX_DEVICE_ID_LEN];
+    CONFIGRET status = CM_Get_Device_ID(device_info_data.DevInst,
+                                        device_id,
+                                        MAX_DEVICE_ID_LEN,
+                                        0);
+    if (status == CR_SUCCESS) {
+      // To reduce the scope of the hack we only look for ACPI and HID\\VID
+      // prefixes in the keyboard device ids.
+      if (StartsWith(device_id, L"ACPI", false) ||
+          StartsWith(device_id, L"HID\\VID", false)) {
+        keyboard_count++;
+      }
+    }
+  }
+  // The heuristic we are using is to check the count of keyboards and return
+  // true if the API's report one or more keyboards. Please note that this
+  // will break for non keyboard devices which expose a keyboard PDO.
+  return keyboard_count >= 1;
+}
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+static bool g_crash_on_process_detach = false;
+
+void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) {
+  DCHECK(metrics);
+  metrics->cbSize = sizeof(*metrics);
+  const bool success = !!SystemParametersInfo(
+      SPI_GETNONCLIENTMETRICS,
+      metrics->cbSize,
+      reinterpret_cast<NONCLIENTMETRICS*>(metrics),
+      0);
+  DCHECK(success);
+}
+
+bool GetUserSidString(std::wstring* user_sid) {
+  // Get the current token.
+  HANDLE token = NULL;
+  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+    return false;
+  base::win::ScopedHandle token_scoped(token);
+
+  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+  scoped_ptr<BYTE[]> user_bytes(new BYTE[size]);
+  TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get());
+
+  if (!::GetTokenInformation(token, TokenUser, user, size, &size))
+    return false;
+
+  if (!user->User.Sid)
+    return false;
+
+  // Convert the data to a string.
+  wchar_t* sid_string;
+  if (!::ConvertSidToStringSid(user->User.Sid, &sid_string))
+    return false;
+
+  *user_sid = sid_string;
+
+  ::LocalFree(sid_string);
+
+  return true;
+}
+
+bool IsShiftPressed() {
+  return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
+}
+
+bool IsCtrlPressed() {
+  return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
+}
+
+bool IsAltPressed() {
+  return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000;
+}
+
+bool IsAltGrPressed() {
+  return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000 &&
+      (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
+}
+
+bool UserAccountControlIsEnabled() {
+  // This can be slow if Windows ends up going to disk.  Should watch this key
+  // for changes and only read it once, preferably on the file thread.
+  //   http://code.google.com/p/chromium/issues/detail?id=61644
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  base::win::RegKey key(HKEY_LOCAL_MACHINE,
+      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
+      KEY_READ);
+  DWORD uac_enabled;
+  if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
+    return true;
+  // Users can set the EnableLUA value to something arbitrary, like 2, which
+  // Vista will treat as UAC enabled, so we make sure it is not set to 0.
+  return (uac_enabled != 0);
+}
+
+bool SetBooleanValueForPropertyStore(IPropertyStore* property_store,
+                                     const PROPERTYKEY& property_key,
+                                     bool property_bool_value) {
+  ScopedPropVariant property_value;
+  if (FAILED(InitPropVariantFromBoolean(property_bool_value,
+                                        property_value.Receive()))) {
+    return false;
+  }
+
+  return SetPropVariantValueForPropertyStore(property_store,
+                                             property_key,
+                                             property_value);
+}
+
+bool SetStringValueForPropertyStore(IPropertyStore* property_store,
+                                    const PROPERTYKEY& property_key,
+                                    const wchar_t* property_string_value) {
+  ScopedPropVariant property_value;
+  if (FAILED(InitPropVariantFromString(property_string_value,
+                                       property_value.Receive()))) {
+    return false;
+  }
+
+  return SetPropVariantValueForPropertyStore(property_store,
+                                             property_key,
+                                             property_value);
+}
+
+bool SetAppIdForPropertyStore(IPropertyStore* property_store,
+                              const wchar_t* app_id) {
+  // App id should be less than 64 chars and contain no space. And recommended
+  // format is CompanyName.ProductName[.SubProduct.ProductNumber].
+  // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx
+  DCHECK(lstrlen(app_id) < 64 && wcschr(app_id, L' ') == NULL);
+
+  return SetStringValueForPropertyStore(property_store,
+                                        PKEY_AppUserModel_ID,
+                                        app_id);
+}
+
+static const char16 kAutoRunKeyPath[] =
+    L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+
+bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+                         const string16& command) {
+  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
+      ERROR_SUCCESS);
+}
+
+bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
+  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
+}
+
+bool ReadCommandFromAutoRun(HKEY root_key,
+                            const string16& name,
+                            string16* command) {
+  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
+  return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
+}
+
+void SetShouldCrashOnProcessDetach(bool crash) {
+  g_crash_on_process_detach = crash;
+}
+
+bool ShouldCrashOnProcessDetach() {
+  return g_crash_on_process_detach;
+}
+
+void SetAbortBehaviorForCrashReporting() {
+  // Prevent CRT's abort code from prompting a dialog or trying to "report" it.
+  // Disabling the _CALL_REPORTFAULT behavior is important since otherwise it
+  // has the sideffect of clearing our exception filter, which means we
+  // don't get any crash.
+  _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+
+  // Set a SIGABRT handler for good measure. We will crash even if the default
+  // is left in place, however this allows us to crash earlier. And it also
+  // lets us crash in response to code which might directly call raise(SIGABRT)
+  signal(SIGABRT, ForceCrashOnSigAbort);
+}
+
+bool IsTabletDevice() {
+  if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
+    return false;
+
+  base::win::Version version = base::win::GetVersion();
+  if (version == base::win::VERSION_XP)
+    return (GetSystemMetrics(SM_TABLETPC) != 0);
+
+  // If the device is docked, the user is treating the device as a PC.
+  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
+    return false;
+
+  // PlatformRoleSlate was only added in Windows 8, but prior to Win8 it is
+  // still possible to check for a mobile power profile.
+  POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+  bool mobile_power_profile = (role == PlatformRoleMobile);
+  bool slate_power_profile = false;
+  if (version >= base::win::VERSION_WIN8)
+    slate_power_profile = (role == PlatformRoleSlate);
+
+  if (mobile_power_profile || slate_power_profile)
+    return (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
+
+  return false;
+}
+
+bool DisplayVirtualKeyboard() {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return false;
+
+  if (IsKeyboardPresentOnSlate())
+    return false;
+
+  static base::LazyInstance<string16>::Leaky osk_path =
+      LAZY_INSTANCE_INITIALIZER;
+
+  if (osk_path.Get().empty()) {
+    // We need to launch TabTip.exe from the location specified under the
+    // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}}
+    // CLSID.
+    // TabTip.exe is typically found at
+    // c:\program files\common files\microsoft shared\ink on English Windows.
+    // We don't want to launch TabTip.exe from
+    // c:\program files (x86)\common files\microsoft shared\ink. This path is
+    // normally found on 64 bit Windows.
+    base::win::RegKey key(HKEY_LOCAL_MACHINE,
+                          kWindows8OSKRegPath,
+                          KEY_READ | KEY_WOW64_64KEY);
+    DWORD osk_path_length = 1024;
+    if (key.ReadValue(NULL,
+                      WriteInto(&osk_path.Get(), osk_path_length),
+                      &osk_path_length,
+                      NULL) != ERROR_SUCCESS) {
+      DLOG(WARNING) << "Failed to read on screen keyboard path from registry";
+      return false;
+    }
+    size_t common_program_files_offset =
+        osk_path.Get().find(L"%CommonProgramFiles%");
+    // Typically the path to TabTip.exe read from the registry will start with
+    // %CommonProgramFiles% which needs to be replaced with the corrsponding
+    // expanded string.
+    // If the path does not begin with %CommonProgramFiles% we use it as is.
+    if (common_program_files_offset != string16::npos) {
+      // Preserve the beginning quote in the path.
+      osk_path.Get().erase(common_program_files_offset,
+                           wcslen(L"%CommonProgramFiles%"));
+      // The path read from the registry contains the %CommonProgramFiles%
+      // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath
+      // function returns the common program files path with the X86 suffix for
+      // the FOLDERID_ProgramFilesCommon value.
+      // To get the correct path to TabTip.exe we first read the environment
+      // variable CommonProgramW6432 which points to the desired common
+      // files path. Failing that we fallback to the SHGetKnownFolderPath API.
+
+      // We then replace the %CommonProgramFiles% value with the actual common
+      // files path found in the process.
+      string16 common_program_files_path;
+      scoped_ptr<wchar_t[]> common_program_files_wow6432;
+      DWORD buffer_size =
+          GetEnvironmentVariable(L"CommonProgramW6432", NULL, 0);
+      if (buffer_size) {
+        common_program_files_wow6432.reset(new wchar_t[buffer_size]);
+        GetEnvironmentVariable(L"CommonProgramW6432",
+                               common_program_files_wow6432.get(),
+                               buffer_size);
+        common_program_files_path = common_program_files_wow6432.get();
+        DCHECK(!common_program_files_path.empty());
+      } else {
+        base::win::ScopedCoMem<wchar_t> common_program_files;
+        if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
+                                        &common_program_files))) {
+          return false;
+        }
+        common_program_files_path = common_program_files;
+      }
+
+      osk_path.Get().insert(1, common_program_files_path);
+    }
+  }
+
+  HINSTANCE ret = ::ShellExecuteW(NULL,
+                                  L"",
+                                  osk_path.Get().c_str(),
+                                  NULL,
+                                  NULL,
+                                  SW_SHOW);
+  return reinterpret_cast<intptr_t>(ret) > 32;
+}
+
+bool DismissVirtualKeyboard() {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return false;
+
+  // We dismiss the virtual keyboard by generating the ESC keystroke
+  // programmatically.
+  const wchar_t kOSKClassName[] = L"IPTip_Main_Window";
+  HWND osk = ::FindWindow(kOSKClassName, NULL);
+  if (::IsWindow(osk) && ::IsWindowEnabled(osk)) {
+    PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0);
+    return true;
+  }
+  return false;
+}
+
+typedef HWND (*MetroRootWindow) ();
+
+enum DomainEnrollementState {UNKNOWN = -1, NOT_ENROLLED, ENROLLED};
+static volatile long int g_domain_state = UNKNOWN;
+
+bool IsEnrolledToDomain() {
+  // Doesn't make any sense to retry inside a user session because joining a
+  // domain will only kick in on a restart.
+  if (g_domain_state == UNKNOWN) {
+    LPWSTR domain;
+    NETSETUP_JOIN_STATUS join_status;
+    if(::NetGetJoinInformation(NULL, &domain, &join_status) != NERR_Success)
+      return false;
+    ::NetApiBufferFree(domain);
+    ::InterlockedCompareExchange(&g_domain_state,
+                                 join_status == ::NetSetupDomainName ?
+                                     ENROLLED : NOT_ENROLLED,
+                                 UNKNOWN);
+  }
+
+  return g_domain_state == ENROLLED;
+}
+
+void SetDomainStateForTesting(bool state) {
+  g_domain_state = state ? ENROLLED : NOT_ENROLLED;
+}
+
+bool MaybeHasSHA256Support() {
+  const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+
+  if (os_info->version() == base::win::VERSION_PRE_XP)
+    return false;  // Too old to have it and this OS is not supported anyway.
+
+  if (os_info->version() == base::win::VERSION_XP)
+    return os_info->service_pack().major >= 3;  // Windows XP SP3 has it.
+
+  // Assume it is missing in this case, although it may not be. This category
+  // includes Windows XP x64, and Windows Server, where a hotfix could be
+  // deployed.
+  if (os_info->version() == base::win::VERSION_SERVER_2003)
+    return false;
+
+  DCHECK(os_info->version() >= base::win::VERSION_VISTA);
+  return true;  // New enough to have SHA-256 support.
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/win_util.h b/base/win/win_util.h
new file mode 100644
index 0000000..8513f62
--- /dev/null
+++ b/base/win/win_util.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// =============================================================================
+// PLEASE READ
+//
+// In general, you should not be adding stuff to this file.
+//
+// - If your thing is only used in one place, just put it in a reasonable
+//   location in or near that one place. It's nice you want people to be able
+//   to re-use your function, but realistically, if it hasn't been necessary
+//   before after so many years of development, it's probably not going to be
+//   used in other places in the future unless you know of them now.
+//
+// - If your thing is used by multiple callers and is UI-related, it should
+//   probably be in app/win/ instead. Try to put it in the most specific file
+//   possible (avoiding the *_util files when practical).
+//
+// =============================================================================
+
+#ifndef BASE_WIN_WIN_UTIL_H_
+#define BASE_WIN_WIN_UTIL_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+struct IPropertyStore;
+struct _tagpropertykey;
+typedef _tagpropertykey PROPERTYKEY;
+
+// This is the same as NONCLIENTMETRICS except that the
+// unused member |iPaddedBorderWidth| has been removed.
+struct NONCLIENTMETRICS_XP {
+    UINT    cbSize;
+    int     iBorderWidth;
+    int     iScrollWidth;
+    int     iScrollHeight;
+    int     iCaptionWidth;
+    int     iCaptionHeight;
+    LOGFONTW lfCaptionFont;
+    int     iSmCaptionWidth;
+    int     iSmCaptionHeight;
+    LOGFONTW lfSmCaptionFont;
+    int     iMenuWidth;
+    int     iMenuHeight;
+    LOGFONTW lfMenuFont;
+    LOGFONTW lfStatusFont;
+    LOGFONTW lfMessageFont;
+};
+
+namespace base {
+namespace win {
+
+BASE_EXPORT void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics);
+
+// Returns the string representing the current user sid.
+BASE_EXPORT bool GetUserSidString(std::wstring* user_sid);
+
+// Returns true if the shift key is currently pressed.
+BASE_EXPORT bool IsShiftPressed();
+
+// Returns true if the ctrl key is currently pressed.
+BASE_EXPORT bool IsCtrlPressed();
+
+// Returns true if the alt key is currently pressed.
+BASE_EXPORT bool IsAltPressed();
+
+// Returns true if the altgr key is currently pressed.
+// Windows does not have specific key code and modifier bit and Alt+Ctrl key is
+// used as AltGr key in Windows.
+BASE_EXPORT bool IsAltGrPressed();
+
+// Returns false if user account control (UAC) has been disabled with the
+// EnableLUA registry flag. Returns true if user account control is enabled.
+// NOTE: The EnableLUA registry flag, which is ignored on Windows XP
+// machines, might still exist and be set to 0 (UAC disabled), in which case
+// this function will return false. You should therefore check this flag only
+// if the OS is Vista or later.
+BASE_EXPORT bool UserAccountControlIsEnabled();
+
+// Sets the boolean value for a given key in given IPropertyStore.
+BASE_EXPORT bool SetBooleanValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    bool property_bool_value);
+
+// Sets the string value for a given key in given IPropertyStore.
+BASE_EXPORT bool SetStringValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    const wchar_t* property_string_value);
+
+// Sets the application id in given IPropertyStore. The function is intended
+// for tagging application/chromium shortcut, browser window and jump list for
+// Win7.
+BASE_EXPORT bool SetAppIdForPropertyStore(IPropertyStore* property_store,
+                                          const wchar_t* app_id);
+
+// Adds the specified |command| using the specified |name| to the AutoRun key.
+// |root_key| could be HKCU or HKLM or the root of any user hive.
+BASE_EXPORT bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+                                     const string16& command);
+// Removes the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive.
+BASE_EXPORT bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name);
+
+// Reads the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive. Used for unit-tests.
+BASE_EXPORT bool ReadCommandFromAutoRun(HKEY root_key,
+                                        const string16& name,
+                                        string16* command);
+
+// Sets whether to crash the process during exit. This is inspected by DLLMain
+// and used to intercept unexpected terminations of the process (via calls to
+// exit(), abort(), _exit(), ExitProcess()) and convert them into crashes.
+// Note that not all mechanisms for terminating the process are covered by
+// this. In particular, TerminateProcess() is not caught.
+BASE_EXPORT void SetShouldCrashOnProcessDetach(bool crash);
+BASE_EXPORT bool ShouldCrashOnProcessDetach();
+
+// Adjusts the abort behavior so that crash reports can be generated when the
+// process is aborted.
+BASE_EXPORT void SetAbortBehaviorForCrashReporting();
+
+// A tablet is a device that is touch enabled and also is being used
+// "like a tablet".  This is used primarily for metrics in order to gain some
+// insight into how users use Chrome.
+BASE_EXPORT bool IsTabletDevice();
+
+// Get the size of a struct up to and including the specified member.
+// This is necessary to set compatible struct sizes for different versions
+// of certain Windows APIs (e.g. SystemParametersInfo).
+#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \
+    offsetof(struct_name, member) + \
+    (sizeof static_cast<struct_name*>(NULL)->member)
+
+// Displays the on screen keyboard on Windows 8 and above. Returns true on
+// success.
+BASE_EXPORT bool DisplayVirtualKeyboard();
+
+// Dismisses the on screen keyboard if it is being displayed on Windows 8 and.
+// above. Returns true on success.
+BASE_EXPORT bool DismissVirtualKeyboard();
+
+// Returns true if the machine is enrolled to a domain.
+BASE_EXPORT bool IsEnrolledToDomain();
+
+// Used by tests to mock any wanted state. Call with |state| set to true to
+// simulate being in a domain and false otherwise.
+BASE_EXPORT void SetDomainStateForTesting(bool state);
+
+// Returns true if the current operating system has support for SHA-256
+// certificates. As its name indicates, this function provides a best-effort
+// answer, which is solely based on comparing version numbers. The function
+// may be re-implemented in the future to return a reliable value, based on
+// run-time detection of this capability.
+BASE_EXPORT bool MaybeHasSHA256Support();
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WIN_UTIL_H_
diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc
new file mode 100644
index 0000000..24141cd
--- /dev/null
+++ b/base/win/win_util_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/strings/string_util.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Saves the current thread's locale ID when initialized, and restores it when
+// the instance is going out of scope.
+class ThreadLocaleSaver {
+ public:
+  ThreadLocaleSaver() : original_locale_id_(GetThreadLocale()) {}
+  ~ThreadLocaleSaver() { SetThreadLocale(original_locale_id_); }
+
+ private:
+  LCID original_locale_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocaleSaver);
+};
+
+}  // namespace
+
+// The test is somewhat silly, because the Vista bots some have UAC enabled
+// and some have it disabled. At least we check that it does not crash.
+TEST(BaseWinUtilTest, TestIsUACEnabled) {
+  if (GetVersion() >= base::win::VERSION_VISTA) {
+    UserAccountControlIsEnabled();
+  } else {
+    EXPECT_TRUE(UserAccountControlIsEnabled());
+  }
+}
+
+TEST(BaseWinUtilTest, TestGetUserSidString) {
+  std::wstring user_sid;
+  EXPECT_TRUE(GetUserSidString(&user_sid));
+  EXPECT_TRUE(!user_sid.empty());
+}
+
+TEST(BaseWinUtilTest, TestGetNonClientMetrics) {
+  NONCLIENTMETRICS_XP metrics = {0};
+  GetNonClientMetrics(&metrics);
+  EXPECT_GT(metrics.cbSize, 0u);
+  EXPECT_GT(metrics.iScrollWidth, 0);
+  EXPECT_GT(metrics.iScrollHeight, 0);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
new file mode 100644
index 0000000..fc2def3
--- /dev/null
+++ b/base/win/windows_version.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/windows_version.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+
+namespace {
+typedef BOOL (WINAPI *GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD);
+}
+
+namespace base {
+namespace win {
+
+// static
+OSInfo* OSInfo::GetInstance() {
+  // Note: we don't use the Singleton class because it depends on AtExitManager,
+  // and it's convenient for other modules to use this classs without it. This
+  // pattern is copied from gurl.cc.
+  static OSInfo* info;
+  if (!info) {
+    OSInfo* new_info = new OSInfo();
+    if (InterlockedCompareExchangePointer(
+        reinterpret_cast<PVOID*>(&info), new_info, NULL)) {
+      delete new_info;
+    }
+  }
+  return info;
+}
+
+OSInfo::OSInfo()
+    : version_(VERSION_PRE_XP),
+      architecture_(OTHER_ARCHITECTURE),
+      wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
+  OSVERSIONINFOEX version_info = { sizeof version_info };
+  ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
+  version_number_.major = version_info.dwMajorVersion;
+  version_number_.minor = version_info.dwMinorVersion;
+  version_number_.build = version_info.dwBuildNumber;
+  if ((version_number_.major == 5) && (version_number_.minor > 0)) {
+    // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
+    version_ = (version_number_.minor == 1) ? VERSION_XP : VERSION_SERVER_2003;
+  } else if (version_number_.major == 6) {
+    switch (version_number_.minor) {
+      case 0:
+        // Treat Windows Server 2008 the same as Windows Vista.
+        version_ = VERSION_VISTA;
+        break;
+      case 1:
+        // Treat Windows Server 2008 R2 the same as Windows 7.
+        version_ = VERSION_WIN7;
+        break;
+      case 2:
+        // Treat Windows Server 2012 the same as Windows 8.
+        version_ = VERSION_WIN8;
+        break;
+      default:
+        DCHECK_EQ(version_number_.minor, 3);
+        version_ = VERSION_WIN8_1;
+        break;
+    }
+  } else if (version_number_.major == 10) {
+    version_ = VERSION_WIN10;
+  } else if (version_number_.major > 6) {
+    NOTREACHED();
+    version_ = VERSION_WIN_LAST;
+  }
+  service_pack_.major = version_info.wServicePackMajor;
+  service_pack_.minor = version_info.wServicePackMinor;
+
+  SYSTEM_INFO system_info = { 0 };
+  ::GetNativeSystemInfo(&system_info);
+  switch (system_info.wProcessorArchitecture) {
+    case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break;
+    case PROCESSOR_ARCHITECTURE_AMD64: architecture_ = X64_ARCHITECTURE; break;
+    case PROCESSOR_ARCHITECTURE_IA64:  architecture_ = IA64_ARCHITECTURE; break;
+  }
+  processors_ = system_info.dwNumberOfProcessors;
+  allocation_granularity_ = system_info.dwAllocationGranularity;
+
+  GetProductInfoPtr get_product_info;
+  DWORD os_type;
+
+  if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
+    // Only present on Vista+.
+    get_product_info = reinterpret_cast<GetProductInfoPtr>(
+        ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetProductInfo"));
+
+    get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion,
+                     0, 0, &os_type);
+    switch (os_type) {
+      case PRODUCT_CLUSTER_SERVER:
+      case PRODUCT_DATACENTER_SERVER:
+      case PRODUCT_DATACENTER_SERVER_CORE:
+      case PRODUCT_ENTERPRISE_SERVER:
+      case PRODUCT_ENTERPRISE_SERVER_CORE:
+      case PRODUCT_ENTERPRISE_SERVER_IA64:
+      case PRODUCT_SMALLBUSINESS_SERVER:
+      case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
+      case PRODUCT_STANDARD_SERVER:
+      case PRODUCT_STANDARD_SERVER_CORE:
+      case PRODUCT_WEB_SERVER:
+        version_type_ = SUITE_SERVER;
+        break;
+      case PRODUCT_PROFESSIONAL:
+      case PRODUCT_ULTIMATE:
+      case PRODUCT_ENTERPRISE:
+      case PRODUCT_BUSINESS:
+        version_type_ = SUITE_PROFESSIONAL;
+        break;
+      case PRODUCT_HOME_BASIC:
+      case PRODUCT_HOME_PREMIUM:
+      case PRODUCT_STARTER:
+      default:
+        version_type_ = SUITE_HOME;
+        break;
+    }
+  } else if (version_info.dwMajorVersion == 5 &&
+             version_info.dwMinorVersion == 2) {
+    if (version_info.wProductType == VER_NT_WORKSTATION &&
+        system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+      version_type_ = SUITE_PROFESSIONAL;
+    } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER ) {
+      version_type_ = SUITE_HOME;
+    } else {
+      version_type_ = SUITE_SERVER;
+    }
+  } else if (version_info.dwMajorVersion == 5 &&
+             version_info.dwMinorVersion == 1) {
+    if(version_info.wSuiteMask & VER_SUITE_PERSONAL)
+      version_type_ = SUITE_HOME;
+    else
+      version_type_ = SUITE_PROFESSIONAL;
+  } else {
+    // Windows is pre XP so we don't care but pick a safe default.
+    version_type_ = SUITE_HOME;
+  }
+}
+
+OSInfo::~OSInfo() {
+}
+
+std::string OSInfo::processor_model_name() {
+  if (processor_model_name_.empty()) {
+    const wchar_t kProcessorNameString[] =
+        L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
+    base::win::RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
+    string16 value;
+    key.ReadValue(L"ProcessorNameString", &value);
+    processor_model_name_ = UTF16ToUTF8(value);
+  }
+  return processor_model_name_;
+}
+
+// static
+OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
+  typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL);
+  IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
+  if (!is_wow64_process)
+    return WOW64_DISABLED;
+  BOOL is_wow64 = FALSE;
+  if (!(*is_wow64_process)(process_handle, &is_wow64))
+    return WOW64_UNKNOWN;
+  return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
+Version GetVersion() {
+  return OSInfo::GetInstance()->version();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
new file mode 100644
index 0000000..a52e64e
--- /dev/null
+++ b/base/win/windows_version.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_WINDOWS_VERSION_H_
+#define BASE_WIN_WINDOWS_VERSION_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+typedef void* HANDLE;
+
+namespace base {
+namespace win {
+
+// The running version of Windows.  This is declared outside OSInfo for
+// syntactic sugar reasons; see the declaration of GetVersion() below.
+// NOTE: Keep these in order so callers can do things like
+// "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...".
+enum Version {
+  VERSION_PRE_XP = 0,  // Not supported.
+  VERSION_XP,
+  VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2.
+  VERSION_VISTA,       // Also includes Windows Server 2008.
+  VERSION_WIN7,        // Also includes Windows Server 2008 R2.
+  VERSION_WIN8,        // Also includes Windows Server 2012.
+  VERSION_WIN8_1,      // Also includes Windows Server 2012 R2.
+  VERSION_WIN10,       // Also includes Windows 10 Server.
+  VERSION_WIN_LAST,    // Indicates error condition.
+};
+
+// A rough bucketing of the available types of versions of Windows. This is used
+// to distinguish enterprise enabled versions from home versions and potentially
+// server versions.
+enum VersionType {
+  SUITE_HOME,
+  SUITE_PROFESSIONAL,
+  SUITE_SERVER,
+  SUITE_LAST,
+};
+
+// A singleton that can be used to query various pieces of information about the
+// OS and process state. Note that this doesn't use the base Singleton class, so
+// it can be used without an AtExitManager.
+class BASE_EXPORT OSInfo {
+ public:
+  struct VersionNumber {
+    int major;
+    int minor;
+    int build;
+  };
+
+  struct ServicePack {
+    int major;
+    int minor;
+  };
+
+  // The processor architecture this copy of Windows natively uses.  For
+  // example, given an x64-capable processor, we have three possibilities:
+  //   32-bit Chrome running on 32-bit Windows:           X86_ARCHITECTURE
+  //   32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE
+  //   64-bit Chrome running on 64-bit Windows:           X64_ARCHITECTURE
+  enum WindowsArchitecture {
+    X86_ARCHITECTURE,
+    X64_ARCHITECTURE,
+    IA64_ARCHITECTURE,
+    OTHER_ARCHITECTURE,
+  };
+
+  // Whether a process is running under WOW64 (the wrapper that allows 32-bit
+  // processes to run on 64-bit versions of Windows).  This will return
+  // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
+  // Chrome on 64-bit Windows".  WOW64_UNKNOWN means "an error occurred", e.g.
+  // the process does not have sufficient access rights to determine this.
+  enum WOW64Status {
+    WOW64_DISABLED,
+    WOW64_ENABLED,
+    WOW64_UNKNOWN,
+  };
+
+  static OSInfo* GetInstance();
+
+  Version version() const { return version_; }
+  // The next two functions return arrays of values, [major, minor(, build)].
+  VersionNumber version_number() const { return version_number_; }
+  VersionType version_type() const { return version_type_; }
+  ServicePack service_pack() const { return service_pack_; }
+  WindowsArchitecture architecture() const { return architecture_; }
+  int processors() const { return processors_; }
+  size_t allocation_granularity() const { return allocation_granularity_; }
+  WOW64Status wow64_status() const { return wow64_status_; }
+  std::string processor_model_name();
+
+  // Like wow64_status(), but for the supplied handle instead of the current
+  // process.  This doesn't touch member state, so you can bypass the singleton.
+  static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
+
+ private:
+  OSInfo();
+  ~OSInfo();
+
+  Version version_;
+  VersionNumber version_number_;
+  VersionType version_type_;
+  ServicePack service_pack_;
+  WindowsArchitecture architecture_;
+  int processors_;
+  size_t allocation_granularity_;
+  WOW64Status wow64_status_;
+  std::string processor_model_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(OSInfo);
+};
+
+// Because this is by far the most commonly-requested value from the above
+// singleton, we add a global-scope accessor here as syntactic sugar.
+BASE_EXPORT Version GetVersion();
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WINDOWS_VERSION_H_
diff --git a/base/win/wrapped_window_proc.cc b/base/win/wrapped_window_proc.cc
new file mode 100644
index 0000000..61b79ed
--- /dev/null
+++ b/base/win/wrapped_window_proc.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/wrapped_window_proc.h"
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/process/memory.h"
+
+namespace {
+
+base::win::WinProcExceptionFilter s_exception_filter = NULL;
+
+}  // namespace.
+
+namespace base {
+namespace win {
+
+WinProcExceptionFilter SetWinProcExceptionFilter(
+    WinProcExceptionFilter filter) {
+  subtle::AtomicWord rv = subtle::NoBarrier_AtomicExchange(
+      reinterpret_cast<subtle::AtomicWord*>(&s_exception_filter),
+      reinterpret_cast<subtle::AtomicWord>(filter));
+  return reinterpret_cast<WinProcExceptionFilter>(rv);
+}
+
+int CallExceptionFilter(EXCEPTION_POINTERS* info) {
+  return s_exception_filter ? s_exception_filter(info) :
+                              EXCEPTION_CONTINUE_SEARCH;
+}
+
+BASE_EXPORT void InitializeWindowClass(
+    const char16* class_name,
+    WNDPROC window_proc,
+    UINT style,
+    int class_extra,
+    int window_extra,
+    HCURSOR cursor,
+    HBRUSH background,
+    const char16* menu_name,
+    HICON large_icon,
+    HICON small_icon,
+    WNDCLASSEX* class_out) {
+  class_out->cbSize = sizeof(WNDCLASSEX);
+  class_out->style = style;
+  class_out->lpfnWndProc = window_proc;
+  class_out->cbClsExtra = class_extra;
+  class_out->cbWndExtra = window_extra;
+  class_out->hInstance = base::GetModuleFromAddress(window_proc);
+  class_out->hIcon = large_icon;
+  class_out->hCursor = cursor;
+  class_out->hbrBackground = background;
+  class_out->lpszMenuName = menu_name;
+  class_out->lpszClassName = class_name;
+  class_out->hIconSm = small_icon;
+
+  // Check if |window_proc| is valid.
+  DCHECK(class_out->hInstance != NULL);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/wrapped_window_proc.h b/base/win/wrapped_window_proc.h
new file mode 100644
index 0000000..d464a9c
--- /dev/null
+++ b/base/win/wrapped_window_proc.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Provides a way to handle exceptions that happen while a WindowProc is
+// running. The behavior of exceptions generated inside a WindowProc is OS
+// dependent, but it is possible that the OS just ignores the exception and
+// continues execution, which leads to unpredictable behavior for Chrome.
+
+#ifndef BASE_WIN_WRAPPED_WINDOW_PROC_H_
+#define BASE_WIN_WRAPPED_WINDOW_PROC_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+// An exception filter for a WindowProc. The return value determines how the
+// exception should be handled, following standard SEH rules. However, the
+// expected behavior for this function is to not return, instead of returning
+// EXCEPTION_EXECUTE_HANDLER or similar, given that in general we are not
+// prepared to handle exceptions.
+typedef int (__cdecl *WinProcExceptionFilter)(EXCEPTION_POINTERS* info);
+
+// Sets the filter to deal with exceptions inside a WindowProc. Returns the old
+// exception filter, if any.
+// This function should be called before any window is created.
+BASE_EXPORT WinProcExceptionFilter SetWinProcExceptionFilter(
+    WinProcExceptionFilter filter);
+
+// Calls the registered exception filter.
+BASE_EXPORT int CallExceptionFilter(EXCEPTION_POINTERS* info);
+
+// Initializes the WNDCLASSEX structure |*class_out| to be passed to
+// RegisterClassEx() making sure that it is associated with the module
+// containing the window procedure.
+BASE_EXPORT void InitializeWindowClass(
+    const char16* class_name,
+    WNDPROC window_proc,
+    UINT style,
+    int class_extra,
+    int window_extra,
+    HCURSOR cursor,
+    HBRUSH background,
+    const char16* menu_name,
+    HICON large_icon,
+    HICON small_icon,
+    WNDCLASSEX* class_out);
+
+// Wrapper that supplies a standard exception frame for the provided WindowProc.
+// The normal usage is something like this:
+//
+// LRESULT CALLBACK MyWinProc(HWND hwnd, UINT message,
+//                            WPARAM wparam, LPARAM lparam) {
+//   // Do Something.
+// }
+//
+// ...
+//
+//   WNDCLASSEX wc = {0};
+//   wc.lpfnWndProc = WrappedWindowProc<MyWinProc>;
+//   wc.lpszClassName = class_name;
+//   ...
+//   RegisterClassEx(&wc);
+//
+//   CreateWindowW(class_name, window_name, ...
+//
+template <WNDPROC proc>
+LRESULT CALLBACK WrappedWindowProc(HWND hwnd, UINT message,
+                                   WPARAM wparam, LPARAM lparam) {
+  LRESULT rv = 0;
+  __try {
+    rv = proc(hwnd, message, wparam, lparam);
+  } __except(CallExceptionFilter(GetExceptionInformation())) {
+  }
+  return rv;
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WRAPPED_WINDOW_PROC_H_
diff --git a/base/win/wrapped_window_proc_unittest.cc b/base/win/wrapped_window_proc_unittest.cc
new file mode 100644
index 0000000..161c913
--- /dev/null
+++ b/base/win/wrapped_window_proc_unittest.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop.h"
+#include "base/win/wrapped_window_proc.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+DWORD kExceptionCode = 12345;
+WPARAM kCrashMsg = 98765;
+
+// A trivial WindowProc that generates an exception.
+LRESULT CALLBACK TestWindowProc(HWND hwnd, UINT message,
+                                WPARAM wparam, LPARAM lparam) {
+  if (message == kCrashMsg)
+    RaiseException(kExceptionCode, 0, 0, NULL);
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+// This class implements an exception filter that can be queried about a past
+// exception.
+class TestWrappedExceptionFiter {
+ public:
+  TestWrappedExceptionFiter() : called_(false) {
+    EXPECT_FALSE(s_filter_);
+    s_filter_ = this;
+  }
+
+  ~TestWrappedExceptionFiter() {
+    EXPECT_EQ(s_filter_, this);
+    s_filter_ = NULL;
+  }
+
+  bool called() {
+    return called_;
+  }
+
+  // The actual exception filter just records the exception.
+  static int Filter(EXCEPTION_POINTERS* info) {
+    EXPECT_FALSE(s_filter_->called_);
+    if (info->ExceptionRecord->ExceptionCode == kExceptionCode)
+      s_filter_->called_ = true;
+    return EXCEPTION_EXECUTE_HANDLER;
+  }
+
+ private:
+  bool called_;
+  static TestWrappedExceptionFiter* s_filter_;
+};
+TestWrappedExceptionFiter* TestWrappedExceptionFiter::s_filter_ = NULL;
+
+}  // namespace.
+
+TEST(WrappedWindowProc, CatchesExceptions) {
+  HINSTANCE hinst = GetModuleHandle(NULL);
+  std::wstring class_name(L"TestClass");
+
+  WNDCLASS wc = {0};
+  wc.lpfnWndProc = base::win::WrappedWindowProc<TestWindowProc>;
+  wc.hInstance = hinst;
+  wc.lpszClassName = class_name.c_str();
+  RegisterClass(&wc);
+
+  HWND window = CreateWindow(class_name.c_str(), 0, 0, 0, 0, 0, 0, HWND_MESSAGE,
+                             0, hinst, 0);
+  ASSERT_TRUE(window);
+
+  // Before generating the exception we make sure that the filter will see it.
+  TestWrappedExceptionFiter wrapper;
+  base::win::WinProcExceptionFilter old_filter =
+      base::win::SetWinProcExceptionFilter(TestWrappedExceptionFiter::Filter);
+
+  SendMessage(window, kCrashMsg, 0, 0);
+  EXPECT_TRUE(wrapper.called());
+
+  base::win::SetWinProcExceptionFilter(old_filter);
+}
diff --git a/build/OWNERS b/build/OWNERS
new file mode 100644
index 0000000..17d067c
--- /dev/null
+++ b/build/OWNERS
@@ -0,0 +1,5 @@
+cjhopman@chromium.org
+dpranke@chromium.org
+jochen@chromium.org
+scottmg@chromium.org
+thakis@chromium.org
diff --git a/build/PRESUBMIT.py b/build/PRESUBMIT.py
new file mode 100644
index 0000000..fca962f
--- /dev/null
+++ b/build/PRESUBMIT.py
@@ -0,0 +1,16 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+def _RunTests(input_api, output_api):
+  return (input_api.canned_checks.RunUnitTestsInDirectory(
+          input_api, output_api, '.', whitelist=[r'.+_test.py$']))
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _RunTests(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _RunTests(input_api, output_api)
diff --git a/build/README.chromium b/build/README.chromium
new file mode 100644
index 0000000..012df35
--- /dev/null
+++ b/build/README.chromium
@@ -0,0 +1,15 @@
+List of property sheets to be included by projects:
+  common.vsprops
+    Not used anymore. No-op. Kept for compatibility with current projects.
+
+  debug.vsprops
+    Enables debug settings. Must be included directly in Debug configuration. Includes internal\essential.vsprops.
+
+  external_code.vsprops
+    Contains settings made to simplify usage of external (non-Google) code. It relaxes the warning levels. Should be included after debug.vsprops or release.vsprops to override their settings.
+
+  output_dll_copy.rules
+    Run to enable automatic copy of DLL when they are as an input file in a vcproj project.
+
+  release.vsprops
+    Enables release settings. Must be included directly in Release configuration. Includes internal\essential.vsprops. Also includes "internal\release_impl$(CHROME_BUILD_TYPE).vsprops". So the behavior is dependant on the CHROME_BUILD_TYPE environment variable.
diff --git a/build/all.gyp b/build/all.gyp
new file mode 100644
index 0000000..1866c2e
--- /dev/null
+++ b/build/all.gyp
@@ -0,0 +1,1409 @@
+# Copyright (c) 2012 The Chromium 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': {
+    # A hook that can be overridden in other repositories to add additional
+    # compilation targets to 'All'.
+    'app_targets%': [],
+    # For Android-specific targets.
+    'android_app_targets%': [],
+  },
+  'targets': [
+    {
+      'target_name': 'All',
+      'type': 'none',
+      'xcode_create_dependents_test_runner': 1,
+      'dependencies': [
+        '<@(app_targets)',
+        'some.gyp:*',
+        '../base/base.gyp:*',
+        '../components/components.gyp:*',
+        '../components/components_tests.gyp:*',
+        '../content/content.gyp:*',
+        '../crypto/crypto.gyp:*',
+        '../net/net.gyp:*',
+        '../sdch/sdch.gyp:*',
+        '../sql/sql.gyp:*',
+        '../testing/gmock.gyp:*',
+        '../testing/gtest.gyp:*',
+        '../third_party/icu/icu.gyp:*',
+        '../third_party/libxml/libxml.gyp:*',
+        '../third_party/sqlite/sqlite.gyp:*',
+        '../third_party/zlib/zlib.gyp:*',
+        '../ui/accessibility/accessibility.gyp:*',
+        '../ui/base/ui_base.gyp:*',
+        '../ui/display/display.gyp:display_unittests',
+        '../ui/snapshot/snapshot.gyp:*',
+        '../url/url.gyp:*',
+      ],
+      'conditions': [
+        ['OS!="ios" and OS!="mac"', {
+          'dependencies': [
+            '../ui/touch_selection/ui_touch_selection.gyp:*',
+          ],
+        }],
+        ['OS=="ios"', {
+          'dependencies': [
+            '../chrome/chrome.gyp:browser',
+            '../chrome/chrome.gyp:browser_ui',
+            '../ios/ios.gyp:*',
+            # NOTE: This list of targets is present because
+            # mojo_base.gyp:mojo_base cannot be built on iOS, as
+            # javascript-related targets cause v8 to be built.
+            '../mojo/mojo_base.gyp:mojo_common_lib',
+            '../mojo/mojo_base.gyp:mojo_common_unittests',
+            '../google_apis/google_apis.gyp:google_apis_unittests',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests',
+            '../third_party/mojo/mojo_edk_tests.gyp:mojo_system_unittests',
+            '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+            '../third_party/mojo/mojo_public.gyp:mojo_public_test_utils',
+            '../third_party/mojo/mojo_public.gyp:mojo_system',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+          ],
+        }],
+        ['OS=="android"', {
+          'dependencies': [
+            '../content/content_shell_and_tests.gyp:content_shell_apk',
+            '<@(android_app_targets)',
+            'android_builder_tests',
+            '../tools/telemetry/telemetry.gyp:*#host',
+            # TODO(nyquist) This should instead by a target for sync when all of
+            # the sync-related code for Android has been upstreamed.
+            # See http://crbug.com/159203
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib',
+          ],
+          'conditions': [
+            ['chromecast==0', {
+              'dependencies': [
+                '../android_webview/android_webview.gyp:android_webview_apk',
+                '../android_webview/android_webview.gyp:system_webview_apk',
+                '../android_webview/android_webview_shell.gyp:android_webview_shell_apk',
+                '../android_webview/android_webview_telemetry_shell.gyp:android_webview_telemetry_shell_apk',
+                '../chrome/chrome.gyp:chrome_shell_apk',
+                '../chrome/chrome.gyp:chrome_sync_shell_apk',
+                '../remoting/remoting.gyp:remoting_apk',
+              ],
+            }],
+            ['target_arch == "arm" or target_arch == "arm64"', {
+              'dependencies': [
+                # The relocation packer only works on ARM or ARM64.
+                '../tools/relocation_packer/relocation_packer.gyp:relocation_packer_unittests#host',
+              ],
+            }],
+          ],
+        }, {
+          'dependencies': [
+            '../content/content_shell_and_tests.gyp:*',
+            # TODO: This should build on Android and the target should move to the list above.
+            '../sync/sync.gyp:*',
+          ],
+        }],
+        ['OS!="ios" and OS!="android" and chromecast==0', {
+          'dependencies': [
+            '../third_party/re2/re2.gyp:re2',
+            '../chrome/chrome.gyp:*',
+            '../chrome/tools/profile_reset/jtl_compiler.gyp:*',
+            '../cc/blink/cc_blink_tests.gyp:*',
+            '../cc/cc_tests.gyp:*',
+            '../device/usb/usb.gyp:*',
+            '../extensions/extensions.gyp:*',
+            '../extensions/extensions_tests.gyp:*',
+            '../gin/gin.gyp:*',
+            '../gpu/gpu.gyp:*',
+            '../gpu/tools/tools.gyp:*',
+            '../ipc/ipc.gyp:*',
+            '../ipc/mojo/ipc_mojo.gyp:*',
+            '../jingle/jingle.gyp:*',
+            '../media/cast/cast.gyp:*',
+            '../media/media.gyp:*',
+            '../media/midi/midi.gyp:*',
+            '../mojo/mojo.gyp:*',
+            '../mojo/mojo_base.gyp:*',
+            '../ppapi/ppapi.gyp:*',
+            '../ppapi/ppapi_internal.gyp:*',
+            '../ppapi/tools/ppapi_tools.gyp:*',
+            '../printing/printing.gyp:*',
+            '../skia/skia.gyp:*',
+            '../sync/tools/sync_tools.gyp:*',
+            '../third_party/WebKit/public/all.gyp:*',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:*',
+            '../third_party/codesighs/codesighs.gyp:*',
+            '../third_party/ffmpeg/ffmpeg.gyp:*',
+            '../third_party/iccjpeg/iccjpeg.gyp:*',
+            '../third_party/libpng/libpng.gyp:*',
+            '../third_party/libusb/libusb.gyp:*',
+            '../third_party/libwebp/libwebp.gyp:*',
+            '../third_party/libxslt/libxslt.gyp:*',
+            '../third_party/lzma_sdk/lzma_sdk.gyp:*',
+            '../third_party/mesa/mesa.gyp:*',
+            '../third_party/modp_b64/modp_b64.gyp:*',
+            '../third_party/npapi/npapi.gyp:*',
+            '../third_party/ots/ots.gyp:*',
+            '../third_party/pdfium/samples/samples.gyp:*',
+            '../third_party/qcms/qcms.gyp:*',
+            '../tools/gn/gn.gyp:*',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
+            '../tools/telemetry/telemetry.gyp:*',
+            '../v8/tools/gyp/v8.gyp:*',
+            '<(libjpeg_gyp_path):*',
+          ],
+        }],
+        ['OS!="ios"', {
+          'dependencies': [
+            '../device/bluetooth/bluetooth.gyp:*',
+            '../device/device_tests.gyp:*',
+          ],
+        }],
+        ['use_openssl==0 and (OS=="mac" or OS=="ios" or OS=="win")', {
+          'dependencies': [
+            '../third_party/nss/nss.gyp:*',
+           ],
+        }],
+        ['OS=="win" or OS=="ios" or OS=="linux"', {
+          'dependencies': [
+            '../breakpad/breakpad.gyp:*',
+           ],
+        }],
+        ['OS=="mac"', {
+          'dependencies': [
+            '../sandbox/sandbox.gyp:*',
+            '../third_party/crashpad/crashpad/crashpad.gyp:*',
+            '../third_party/ocmock/ocmock.gyp:*',
+          ],
+        }],
+        ['OS=="linux"', {
+          'dependencies': [
+            '../courgette/courgette.gyp:*',
+            '../sandbox/sandbox.gyp:*',
+          ],
+          'conditions': [
+            ['branding=="Chrome"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:linux_packages_<(channel)',
+              ],
+            }],
+            ['enable_ipc_fuzzer==1', {
+              'dependencies': [
+                '../tools/ipc_fuzzer/ipc_fuzzer.gyp:*',
+              ],
+            }],
+            ['use_dbus==1', {
+              'dependencies': [
+                '../dbus/dbus.gyp:*',
+              ],
+            }],
+          ],
+        }],
+        ['chromecast==1', {
+          'dependencies': [
+            '../chromecast/chromecast.gyp:*',
+          ],
+        }],
+        ['use_x11==1', {
+          'dependencies': [
+            '../tools/xdisplaycheck/xdisplaycheck.gyp:*',
+          ],
+        }],
+        ['OS=="win"', {
+          'conditions': [
+            ['win_use_allocator_shim==1', {
+              'dependencies': [
+                '../base/allocator/allocator.gyp:*',
+              ],
+            }],
+          ],
+          'dependencies': [
+            '../chrome/tools/crash_service/caps/caps.gyp:*',
+            '../chrome_elf/chrome_elf.gyp:*',
+            '../cloud_print/cloud_print.gyp:*',
+            '../courgette/courgette.gyp:*',
+            '../rlz/rlz.gyp:*',
+            '../sandbox/sandbox.gyp:*',
+            '<(angle_path)/src/angle.gyp:*',
+            '../third_party/bspatch/bspatch.gyp:*',
+            '../tools/win/static_initializers/static_initializers.gyp:*',
+          ],
+        }, {
+          'dependencies': [
+            '../third_party/libevent/libevent.gyp:*',
+          ],
+        }],
+        ['toolkit_views==1', {
+          'dependencies': [
+            '../ui/views/controls/webview/webview.gyp:*',
+            '../ui/views/views.gyp:*',
+          ],
+        }],
+        ['use_aura==1', {
+          'dependencies': [
+            '../ui/aura/aura.gyp:*',
+            '../ui/aura_extra/aura_extra.gyp:*',
+          ],
+        }],
+        ['use_ash==1', {
+          'dependencies': [
+            '../ash/ash.gyp:*',
+          ],
+        }],
+        ['remoting==1', {
+          'dependencies': [
+            '../remoting/remoting_all.gyp:remoting_all',
+          ],
+        }],
+        ['use_openssl==0', {
+          'dependencies': [
+            '../net/third_party/nss/ssl.gyp:*',
+          ],
+        }],
+        ['use_openssl==1', {
+          'dependencies': [
+            '../third_party/boringssl/boringssl.gyp:*',
+            '../third_party/boringssl/boringssl_tests.gyp:*',
+          ],
+        }],
+        ['enable_app_list==1', {
+          'dependencies': [
+            '../ui/app_list/app_list.gyp:*',
+          ],
+        }],
+        ['OS!="android" and OS!="ios"', {
+          'dependencies': [
+            '../google_apis/gcm/gcm.gyp:*',
+          ],
+        }],
+        ['(chromeos==1 or OS=="linux" or OS=="win" or OS=="mac") and chromecast==0', {
+          'dependencies': [
+            '../extensions/shell/app_shell.gyp:*',
+          ],
+        }],
+        ['envoy==1', {
+          'dependencies': [
+            '../envoy/envoy.gyp:*',
+          ],
+        }],
+      ],
+    }, # target_name: All
+    {
+      'target_name': 'All_syzygy',
+      'type': 'none',
+      'conditions': [
+        ['OS=="win" and fastbuild==0 and target_arch=="ia32" and '
+            '(syzyasan==1 or syzygy_optimize==1)', {
+          'dependencies': [
+            '../chrome/installer/mini_installer_syzygy.gyp:*',
+          ],
+        }],
+      ],
+    }, # target_name: All_syzygy
+    {
+      # Note: Android uses android_builder_tests below.
+      # TODO: Consider merging that with this target.
+      'target_name': 'chromium_builder_tests',
+      'type': 'none',
+      'dependencies': [
+        '../base/base.gyp:base_unittests',
+        '../components/components_tests.gyp:components_unittests',
+        '../crypto/crypto.gyp:crypto_unittests',
+        '../net/net.gyp:net_unittests',
+        '../skia/skia_tests.gyp:skia_unittests',
+        '../sql/sql.gyp:sql_unittests',
+        '../sync/sync.gyp:sync_unit_tests',
+        '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+        '../ui/display/display.gyp:display_unittests',
+        '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+        '../ui/gl/gl_tests.gyp:gl_unittests',
+        '../url/url.gyp:url_unittests',
+      ],
+      'conditions': [
+        ['OS!="ios" and OS!="mac"', {
+          'dependencies': [
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+          ],
+        }],
+        ['OS!="ios" and OS!="android"', {
+          'dependencies': [
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_shell',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../gin/gin.gyp:gin_unittests',
+            '../google_apis/google_apis.gyp:google_apis_unittests',
+            '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/cast/cast.gyp:cast_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../mojo/mojo.gyp:mojo',
+            '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../third_party/WebKit/public/all.gyp:all_blink',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../tools/telemetry/telemetry.gyp:*',
+          ],
+        }],
+        ['OS!="ios" and OS!="android" and chromecast==0', {
+          'dependencies': [
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:chromedriver_tests',
+            '../chrome/chrome.gyp:chromedriver_unittests',
+            '../chrome/chrome.gyp:interactive_ui_tests',
+            '../chrome/chrome.gyp:sync_integration_tests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../extensions/extensions_tests.gyp:extensions_browsertests',
+            '../extensions/extensions_tests.gyp:extensions_unittests',
+          ],
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            '../chrome/chrome.gyp:app_installer',
+            '../chrome/chrome.gyp:app_installer_unittests',
+            '../chrome/chrome.gyp:crash_service',
+            '../chrome/chrome.gyp:installer_util_unittests',
+            # ../chrome/test/mini_installer requires mini_installer.
+            '../chrome/installer/mini_installer.gyp:mini_installer',
+            '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
+            '../content/content_shell_and_tests.gyp:copy_test_netscape_plugin',
+            '../courgette/courgette.gyp:courgette_unittests',
+            '../sandbox/sandbox.gyp:sbox_integration_tests',
+            '../sandbox/sandbox.gyp:sbox_unittests',
+            '../sandbox/sandbox.gyp:sbox_validation_tests',
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+          ],
+          'conditions': [
+            # remoting_host_installation uses lots of non-trivial GYP that tend
+            # to break because of differences between ninja and msbuild. Make
+            # sure this target is built by the builders on the main waterfall.
+            # See http://crbug.com/180600.
+            ['wix_exists == "True" and sas_dll_exists == "True"', {
+              'dependencies': [
+                '../remoting/remoting.gyp:remoting_host_installation',
+              ],
+            }],
+            ['syzyasan==1', {
+              'variables': {
+                # Disable incremental linking for all modules.
+                # 0: inherit, 1: disabled, 2: enabled.
+                'msvs_debug_link_incremental': '1',
+                'msvs_large_module_debug_link_mode': '1',
+                # Disable RTC. Syzygy explicitly doesn't support RTC
+                # instrumented binaries for now.
+                'win_debug_RuntimeChecks': '0',
+              },
+              'defines': [
+                # Disable iterator debugging (huge speed boost).
+                '_HAS_ITERATOR_DEBUGGING=0',
+              ],
+              'msvs_settings': {
+                'VCLinkerTool': {
+                  # Enable profile information (necessary for SyzyAsan
+                  # instrumentation). This is incompatible with incremental
+                  # linking.
+                  'Profile': 'true',
+                },
+              }
+            }],
+          ],
+        }],
+        ['chromeos==1', {
+          'dependencies': [
+            '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_unittests',
+          ],
+        }],
+        ['OS=="linux"', {
+          'dependencies': [
+            '../sandbox/sandbox.gyp:sandbox_linux_unittests',
+          ],
+        }],
+        ['OS=="linux" and use_dbus==1', {
+          'dependencies': [
+            '../dbus/dbus.gyp:dbus_unittests',
+          ],
+        }],
+        ['OS=="mac"', {
+          'dependencies': [
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+            '../ui/message_center/message_center.gyp:*',
+          ],
+        }],
+        ['test_isolation_mode != "noop"', {
+          'dependencies': [
+            'chromium_swarm_tests',
+          ],
+        }],
+        ['OS!="android"', {
+          'dependencies': [
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+          ],
+        }],
+        ['enable_basic_printing==1 or enable_print_preview==1', {
+          'dependencies': [
+            '../printing/printing.gyp:printing_unittests',
+          ],
+        }],
+        ['use_aura==1', {
+          'dependencies': [
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+            '../ui/aura/aura.gyp:aura_unittests',
+            '../ui/compositor/compositor.gyp:compositor_unittests',
+          ],
+        }],
+        ['use_aura==1 and chromecast==0', {
+          'dependencies': [
+            '../ui/keyboard/keyboard.gyp:keyboard_unittests',
+            '../ui/views/views.gyp:views_unittests',
+          ],
+        }],
+        ['use_aura==1 or toolkit_views==1', {
+          'dependencies': [
+            '../ui/events/events.gyp:events_unittests',
+          ],
+        }],
+        ['use_ash==1', {
+          'dependencies': [
+            '../ash/ash.gyp:ash_unittests',
+          ],
+        }],
+        ['disable_nacl==0', {
+          'dependencies': [
+            '../components/nacl.gyp:nacl_loader_unittests',
+          ],
+        }],
+        ['disable_nacl==0 and disable_nacl_untrusted==0', {
+          'dependencies': [
+            '../mojo/mojo_nacl_untrusted.gyp:libmojo',
+            '../mojo/mojo_nacl.gyp:monacl_codegen',
+            '../mojo/mojo_nacl.gyp:monacl_sel',
+            '../mojo/mojo_nacl.gyp:monacl_shell',
+          ],
+        }],
+      ],
+    }, # target_name: chromium_builder_tests
+  ],
+  'conditions': [
+    # TODO(GYP): make gn_migration.gypi work unconditionally.
+    ['OS=="mac" or OS=="win" or (OS=="linux" and target_arch=="x64" and chromecast==0)', {
+      'includes': [
+        'gn_migration.gypi',
+      ],
+    }],
+    ['OS!="ios"', {
+      'targets': [
+        {
+          'target_name': 'blink_tests',
+          'type': 'none',
+          'dependencies': [
+            '../third_party/WebKit/public/all.gyp:all_blink',
+          ],
+          'conditions': [
+            ['OS=="android"', {
+              'dependencies': [
+                '../content/content_shell_and_tests.gyp:content_shell_apk',
+                '../breakpad/breakpad.gyp:dump_syms#host',
+                '../breakpad/breakpad.gyp:minidump_stackwalk#host',
+              ],
+            }, {  # OS!="android"
+              'dependencies': [
+                '../content/content_shell_and_tests.gyp:content_shell',
+              ],
+            }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../content/content_shell_and_tests.gyp:content_shell_crash_service',
+                '../content/content_shell_and_tests.gyp:layout_test_helper',
+              ],
+            }],
+            ['OS!="win" and OS!="android"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:minidump_stackwalk',
+              ],
+            }],
+            ['OS=="mac"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:dump_syms#host',
+                '../content/content_shell_and_tests.gyp:layout_test_helper',
+              ],
+            }],
+            ['OS=="linux"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:dump_syms#host',
+              ],
+            }],
+          ],
+        }, # target_name: blink_tests
+      ],
+    }], # OS!=ios
+    ['OS!="ios" and OS!="android" and chromecast==0', {
+      'targets': [
+        {
+          'target_name': 'chromium_builder_nacl_win_integration',
+          'type': 'none',
+          'dependencies': [
+            'chromium_builder_tests',
+          ],
+        }, # target_name: chromium_builder_nacl_win_integration
+        {
+          'target_name': 'chromium_builder_perf',
+          'type': 'none',
+          'dependencies': [
+            '../cc/cc_tests.gyp:cc_perftests',
+            '../chrome/chrome.gyp:chrome',
+            '../chrome/chrome.gyp:load_library_perf_tests',
+            '../chrome/chrome.gyp:performance_browser_tests',
+            '../chrome/chrome.gyp:sync_performance_tests',
+            '../content/content_shell_and_tests.gyp:content_shell',
+            '../gpu/gpu.gyp:gpu_perftests',
+            '../media/media.gyp:media_perftests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
+            '../tools/telemetry/telemetry.gyp:*',
+          ],
+          'conditions': [
+            ['OS!="ios" and OS!="win"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:minidump_stackwalk',
+              ],
+            }],
+            ['OS=="linux"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:linux_symbols'
+              ],
+            }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service',
+                '../gpu/gpu.gyp:angle_perftests',
+              ],
+            }],
+            ['OS=="win" and target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
+          ],
+        }, # target_name: chromium_builder_perf
+        {
+          'target_name': 'chromium_gpu_builder',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/chrome.gyp:chrome',
+            '../chrome/chrome.gyp:performance_browser_tests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_gl_tests',
+            '../gpu/gles2_conform_support/gles2_conform_test.gyp:gles2_conform_test',
+            '../gpu/khronos_glcts_support/khronos_glcts_test.gyp:khronos_glcts_test',
+            '../gpu/gpu.gyp:gl_tests',
+            '../gpu/gpu.gyp:angle_unittests',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../tools/telemetry/telemetry.gyp:*',
+          ],
+          'conditions': [
+            ['OS!="ios" and OS!="win"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:minidump_stackwalk',
+              ],
+            }],
+            ['OS=="linux"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:linux_symbols'
+              ],
+            }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service',
+              ],
+            }],
+            ['OS=="win" and target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
+          ],
+        }, # target_name: chromium_gpu_builder
+        {
+          'target_name': 'chromium_gpu_debug_builder',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/chrome.gyp:chrome',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_gl_tests',
+            '../gpu/gles2_conform_support/gles2_conform_test.gyp:gles2_conform_test',
+            '../gpu/khronos_glcts_support/khronos_glcts_test.gyp:khronos_glcts_test',
+            '../gpu/gpu.gyp:gl_tests',
+            '../gpu/gpu.gyp:angle_unittests',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../tools/telemetry/telemetry.gyp:*',
+          ],
+          'conditions': [
+            ['OS!="ios" and OS!="win"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:minidump_stackwalk',
+              ],
+            }],
+            ['OS=="linux"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:linux_symbols'
+              ],
+            }],
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service',
+              ],
+            }],
+            ['OS=="win" and target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
+          ],
+        }, # target_name: chromium_gpu_debug_builder
+        {
+          # This target contains everything we need to run tests on the special
+          # device-equipped WebRTC bots. We have device-requiring tests in
+          # browser_tests and content_browsertests.
+          'target_name': 'chromium_builder_webrtc',
+          'type': 'none',
+          'dependencies': [
+            'chromium_builder_perf',
+            '../chrome/chrome.gyp:browser_tests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../third_party/webrtc/tools/tools.gyp:frame_analyzer',
+            '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter',
+          ],
+          'conditions': [
+            ['remoting==1', {
+              'dependencies': [
+                '../remoting/remoting.gyp:*',
+              ],
+            }],
+          ],
+        },  # target_name: chromium_builder_webrtc
+        {
+          'target_name': 'chromium_builder_chromedriver',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/chrome.gyp:chromedriver',
+            '../chrome/chrome.gyp:chromedriver_tests',
+            '../chrome/chrome.gyp:chromedriver_unittests',
+          ],
+        },  # target_name: chromium_builder_chromedriver
+        {
+          'target_name': 'chromium_builder_asan',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/chrome.gyp:chrome',
+
+            # We refer to content_shell directly rather than blink_tests
+            # because we don't want the _unittests binaries.
+            '../content/content_shell_and_tests.gyp:content_shell',
+          ],
+          'conditions': [
+            ['OS!="win"', {
+              'dependencies': [
+                '../net/net.gyp:hpack_fuzz_wrapper',
+                '../net/net.gyp:dns_fuzz_stub',
+                '../skia/skia.gyp:filter_fuzz_stub',
+              ],
+            }],
+            ['enable_ipc_fuzzer==1 and component!="shared_library" and '
+                 '(OS=="linux" or OS=="win")', {
+              'dependencies': [
+                '../tools/ipc_fuzzer/ipc_fuzzer.gyp:*',
+              ],
+            }],
+            ['chromeos==0', {
+              'dependencies': [
+                '../v8/src/d8.gyp:d8#host',
+                '../third_party/pdfium/samples/samples.gyp:pdfium_test',
+              ],
+            }],
+            ['internal_filter_fuzzer==1', {
+              'dependencies': [
+                '../skia/tools/clusterfuzz-data/fuzzers/filter_fuzzer/filter_fuzzer.gyp:filter_fuzzer',
+              ],
+            }], # internal_filter_fuzzer
+            ['clang==1', {
+              'dependencies': [
+                'sanitizers/sanitizers.gyp:llvm-symbolizer',
+              ],
+            }],
+            ['OS=="win" and fastbuild==0 and target_arch=="ia32" and syzyasan==1', {
+              'dependencies': [
+                '../chrome/chrome_syzygy.gyp:chrome_dll_syzygy',
+                '../content/content_shell_and_tests.gyp:content_shell_syzyasan',
+              ],
+              'conditions': [
+                ['chrome_multiple_dll==1', {
+                  'dependencies': [
+                    '../chrome/chrome_syzygy.gyp:chrome_child_dll_syzygy',
+                  ],
+                }],
+              ],
+            }],
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_nacl_sdk',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/chrome.gyp:chrome',
+          ],
+          'conditions': [
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:chrome_nacl_win64',
+              ]
+            }],
+          ],
+        },  #target_name: chromium_builder_nacl_sdk
+      ],  # targets
+    }], #OS!=ios and OS!=android
+    ['OS=="android"', {
+      'targets': [
+        {
+          # The current list of tests for android.  This is temporary
+          # until the full set supported.  If adding a new test here,
+          # please also add it to build/android/pylib/gtest/gtest_config.py,
+          # else the test is not run.
+          #
+          # WARNING:
+          # Do not add targets here without communicating the implications
+          # on tryserver triggers and load.  Discuss with
+          # chrome-infrastructure-team please.
+          'target_name': 'android_builder_tests',
+          'type': 'none',
+          'dependencies': [
+            '../base/android/jni_generator/jni_generator.gyp:jni_generator_tests',
+            '../base/base.gyp:base_unittests',
+            '../breakpad/breakpad.gyp:breakpad_unittests_deps',
+            # Also compile the tools needed to deal with minidumps, they are
+            # needed to run minidump tests upstream.
+            '../breakpad/breakpad.gyp:dump_syms#host',
+            '../breakpad/breakpad.gyp:symupload#host',
+            '../breakpad/breakpad.gyp:minidump_dump#host',
+            '../breakpad/breakpad.gyp:minidump_stackwalk#host',
+            '../build/android/tests/multiple_proguards/multiple_proguards.gyp:multiple_proguards_test_apk',
+            '../build/android/pylib/device/commands/commands.gyp:chromium_commands',
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_perftests_apk',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_gl_tests',
+            '../content/content_shell_and_tests.gyp:content_junit_tests',
+            '../content/content_shell_and_tests.gyp:chromium_linker_test_apk',
+            '../content/content_shell_and_tests.gyp:content_shell_test_apk',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../gpu/gpu.gyp:gl_tests',
+            '../gpu/gpu.gyp:gpu_perftests_apk',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../media/media.gyp:media_perftests_apk',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests_apk',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../net/net.gyp:net_unittests',
+            '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../sync/sync.gyp:sync_unit_tests',
+            '../testing/android/junit/junit_test.gyp:junit_unit_tests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/WebKit/public/all.gyp:*',
+            '../tools/android/android_tools.gyp:android_tools',
+            '../tools/android/android_tools.gyp:memconsumer',
+            '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test',
+            '../ui/android/ui_android.gyp:ui_android_unittests',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/events/events.gyp:events_unittests',
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+            # Unit test bundles packaged as an apk.
+            '../base/base.gyp:base_unittests_apk',
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests_apk',
+            '../cc/cc_tests.gyp:cc_unittests_apk',
+            '../components/components_tests.gyp:components_browsertests_apk',
+            '../components/components_tests.gyp:components_unittests_apk',
+            '../content/content_shell_and_tests.gyp:content_browsertests_apk',
+            '../content/content_shell_and_tests.gyp:content_gl_tests_apk',
+            '../content/content_shell_and_tests.gyp:content_unittests_apk',
+            '../content/content_shell_and_tests.gyp:video_decode_accelerator_unittest_apk',
+            '../gpu/gpu.gyp:gl_tests_apk',
+            '../gpu/gpu.gyp:gpu_unittests_apk',
+            '../ipc/ipc.gyp:ipc_tests_apk',
+            '../media/media.gyp:media_unittests_apk',
+            '../media/midi/midi.gyp:midi_unittests_apk',
+            '../net/net.gyp:net_unittests_apk',
+            '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests_apk',
+            '../skia/skia_tests.gyp:skia_unittests_apk',
+            '../sql/sql.gyp:sql_unittests_apk',
+            '../sync/sync.gyp:sync_unit_tests_apk',
+            '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
+            '../ui/android/ui_android.gyp:ui_android_unittests_apk',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
+            '../ui/events/events.gyp:events_unittests_apk',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
+            '../ui/gl/gl_tests.gyp:gl_unittests_apk',
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_apk',
+          ],
+          'conditions': [
+            ['chromecast==0', {
+              'dependencies': [
+                '../android_webview/android_webview.gyp:android_webview_unittests',
+                '../chrome/chrome.gyp:unit_tests',
+                # Unit test bundles packaged as an apk.
+                '../android_webview/android_webview.gyp:android_webview_test_apk',
+                '../android_webview/android_webview.gyp:android_webview_unittests_apk',
+                '../chrome/chrome.gyp:chrome_junit_tests',
+                '../chrome/chrome.gyp:chrome_shell_test_apk',
+                '../chrome/chrome.gyp:chrome_sync_shell_test_apk',
+                '../chrome/chrome.gyp:chrome_shell_uiautomator_tests',
+                '../chrome/chrome.gyp:chromedriver_webview_shell_apk',
+                '../chrome/chrome.gyp:unit_tests_apk',
+              ],
+            }],
+            ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', {
+              'dependencies': [
+                '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
+              ],
+            }],
+          ],
+        },
+        {
+          # WebRTC Chromium tests to run on Android.
+          'target_name': 'android_builder_chromium_webrtc',
+          'type': 'none',
+          'dependencies': [
+            '../build/android/pylib/device/commands/commands.gyp:chromium_commands',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../tools/android/android_tools.gyp:android_tools',
+            '../tools/android/android_tools.gyp:memconsumer',
+            # Unit test bundles packaged as an apk.
+            '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
+            '../content/content_shell_and_tests.gyp:content_browsertests_apk',
+          ],
+        },  # target_name: android_builder_chromium_webrtc
+      ], # targets
+    }], # OS="android"
+    ['OS=="mac"', {
+      'targets': [
+        {
+          # Target to build everything plus the dmg.  We don't put the dmg
+          # in the All target because developers really don't need it.
+          'target_name': 'all_and_dmg',
+          'type': 'none',
+          'dependencies': [
+            'All',
+            '../chrome/chrome.gyp:build_app_dmg',
+          ],
+        },
+        # These targets are here so the build bots can use them to build
+        # subsets of a full tree for faster cycle times.
+        {
+          'target_name': 'chromium_builder_dbg',
+          'type': 'none',
+          'dependencies': [
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:interactive_ui_tests',
+            '../chrome/chrome.gyp:sync_integration_tests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../rlz/rlz.gyp:*',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../sync/sync.gyp:sync_unit_tests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
+            '../tools/telemetry/telemetry.gyp:*',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_rel',
+          'type': 'none',
+          'dependencies': [
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:performance_browser_tests',
+            '../chrome/chrome.gyp:sync_integration_tests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../sync/sync.gyp:sync_unit_tests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
+            '../tools/telemetry/telemetry.gyp:*',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_dbg_tsan_mac',
+          'type': 'none',
+          'dependencies': [
+            '../base/base.gyp:base_unittests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../crypto/crypto.gyp:crypto_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../net/net.gyp:net_unittests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_dbg_valgrind_mac',
+          'type': 'none',
+          'dependencies': [
+            '../base/base.gyp:base_unittests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../crypto/crypto.gyp:crypto_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../net/net.gyp:net_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../sync/sync.gyp:sync_unit_tests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        },
+      ],  # targets
+    }], # OS="mac"
+    ['OS=="win"', {
+      'targets': [
+        # These targets are here so the build bots can use them to build
+        # subsets of a full tree for faster cycle times.
+        {
+          'target_name': 'chromium_builder',
+          'type': 'none',
+          'dependencies': [
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:crash_service',
+            '../chrome/chrome.gyp:gcapi_test',
+            '../chrome/chrome.gyp:installer_util_unittests',
+            '../chrome/chrome.gyp:interactive_ui_tests',
+            '../chrome/chrome.gyp:performance_browser_tests',
+            '../chrome/chrome.gyp:sync_integration_tests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../content/content_shell_and_tests.gyp:copy_test_netscape_plugin',
+            # ../chrome/test/mini_installer requires mini_installer.
+            '../chrome/installer/mini_installer.gyp:mini_installer',
+            '../courgette/courgette.gyp:courgette_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../sync/sync.gyp:sync_unit_tests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
+            '../tools/telemetry/telemetry.gyp:*',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/events/events.gyp:events_unittests',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+            '../ui/views/views.gyp:views_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+          'conditions': [
+            ['target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_dbg_tsan_win',
+          'type': 'none',
+          'dependencies': [
+            '../base/base.gyp:base_unittests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../crypto/crypto.gyp:crypto_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../net/net.gyp:net_unittests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_lkgr_drmemory_win',
+          'type': 'none',
+          'dependencies': [
+            '../content/content_shell_and_tests.gyp:content_shell',
+            '../content/content_shell_and_tests.gyp:content_shell_crash_service',
+            '../content/content_shell_and_tests.gyp:layout_test_helper',
+          ],
+        },
+        {
+          'target_name': 'chromium_builder_dbg_drmemory_win',
+          'type': 'none',
+          'dependencies': [
+            '../ash/ash.gyp:ash_shell_unittests',
+            '../ash/ash.gyp:ash_unittests',
+            '../base/base.gyp:base_unittests',
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:chrome_app_unittests',
+            '../chrome/chrome.gyp:chromedriver_unittests',
+            '../chrome/chrome.gyp:installer_util_unittests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
+            '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_shell',
+            '../content/content_shell_and_tests.gyp:content_shell_crash_service',
+            '../content/content_shell_and_tests.gyp:layout_test_helper',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../courgette/courgette.gyp:courgette_unittests',
+            '../crypto/crypto.gyp:crypto_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../extensions/extensions_tests.gyp:extensions_browsertests',
+            '../extensions/extensions_tests.gyp:extensions_unittests',
+            '../gin/gin.gyp:gin_shell',
+            '../gin/gin.gyp:gin_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../google_apis/google_apis.gyp:google_apis_unittests',
+            '../gpu/gpu.gyp:angle_unittests',
+            '../gpu/gpu.gyp:gpu_unittests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../media/cast/cast.gyp:cast_unittests',
+            '../media/media.gyp:media_unittests',
+            '../media/midi/midi.gyp:midi_unittests',
+            '../mojo/mojo.gyp:mojo',
+            '../net/net.gyp:net_unittests',
+            '../printing/printing.gyp:printing_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../sql/sql.gyp:sql_unittests',
+            '../sync/sync.gyp:sync_unit_tests',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+            '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+            '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+            '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests',
+            '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests',
+            '../ui/accessibility/accessibility.gyp:accessibility_unittests',
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+            '../ui/aura/aura.gyp:aura_unittests',
+            '../ui/compositor/compositor.gyp:compositor_unittests',
+            '../ui/display/display.gyp:display_unittests',
+            '../ui/events/events.gyp:events_unittests',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../ui/keyboard/keyboard.gyp:keyboard_unittests',
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        },
+      ],  # targets
+      'conditions': [
+        ['branding=="Chrome"', {
+          'targets': [
+            {
+              'target_name': 'chrome_official_builder_no_unittests',
+              'type': 'none',
+              'dependencies': [
+                '../chrome/chrome.gyp:app_installer',
+                '../chrome/chrome.gyp:crash_service',
+                '../chrome/chrome.gyp:gcapi_dll',
+                '../chrome/chrome.gyp:pack_policy_templates',
+                '../chrome/installer/mini_installer.gyp:mini_installer',
+                '../cloud_print/cloud_print.gyp:cloud_print',
+                '../courgette/courgette.gyp:courgette',
+                '../courgette/courgette.gyp:courgette64',
+                '../remoting/remoting.gyp:remoting_webapp',
+                '../third_party/widevine/cdm/widevine_cdm.gyp:widevinecdmadapter',
+              ],
+              'conditions': [
+                ['target_arch=="ia32"', {
+                  'dependencies': [
+                    '../chrome/chrome.gyp:crash_service_win64',
+                  ],
+                }],
+                ['component != "shared_library" and wix_exists == "True" and \
+                    sas_dll_exists == "True"', {
+                  'dependencies': [
+                    '../remoting/remoting.gyp:remoting_host_installation',
+                  ],
+                }], # component != "shared_library"
+              ]
+            }, {
+              'target_name': 'chrome_official_builder',
+              'type': 'none',
+              'dependencies': [
+	        'chrome_official_builder_no_unittests',
+                '../base/base.gyp:base_unittests',
+		'../chrome/chrome.gyp:app_installer_unittests',
+                '../chrome/chrome.gyp:browser_tests',
+                '../chrome/chrome.gyp:sync_integration_tests',
+                '../ipc/ipc.gyp:ipc_tests',
+                '../media/media.gyp:media_unittests',
+                '../media/midi/midi.gyp:midi_unittests',
+                '../net/net.gyp:net_unittests_run',
+                '../printing/printing.gyp:printing_unittests',
+                '../sql/sql.gyp:sql_unittests',
+                '../sync/sync.gyp:sync_unit_tests',
+                '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+                '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+                '../ui/gl/gl_tests.gyp:gl_unittests',
+                '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+                '../ui/views/views.gyp:views_unittests',
+                '../url/url.gyp:url_unittests',
+              ],
+            },
+          ], # targets
+        }], # branding=="Chrome"
+       ], # conditions
+    }], # OS="win"
+    ['use_aura==1', {
+      'targets': [
+        {
+          'target_name': 'aura_builder',
+          'type': 'none',
+          'dependencies': [
+            '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+            '../cc/cc_tests.gyp:cc_unittests',
+            '../components/components_tests.gyp:components_unittests',
+            '../content/content_shell_and_tests.gyp:content_browsertests',
+            '../content/content_shell_and_tests.gyp:content_unittests',
+            '../device/device_tests.gyp:device_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+            '../remoting/remoting.gyp:remoting_unittests',
+            '../skia/skia_tests.gyp:skia_unittests',
+            '../ui/app_list/app_list.gyp:*',
+            '../ui/aura/aura.gyp:*',
+            '../ui/aura_extra/aura_extra.gyp:*',
+            '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+            '../ui/compositor/compositor.gyp:*',
+            '../ui/display/display.gyp:display_unittests',
+            '../ui/events/events.gyp:*',
+            '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+            '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../ui/keyboard/keyboard.gyp:*',
+            '../ui/snapshot/snapshot.gyp:snapshot_unittests',
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+            '../ui/wm/wm.gyp:*',
+            'blink_tests',
+          ],
+          'conditions': [
+            ['OS=="win"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service',
+              ],
+            }],
+            ['OS=="win" and target_arch=="ia32"', {
+              'dependencies': [
+                '../chrome/chrome.gyp:crash_service_win64',
+              ],
+            }],
+            ['use_ash==1', {
+              'dependencies': [
+                '../ash/ash.gyp:ash_shell',
+                '../ash/ash.gyp:ash_unittests',
+              ],
+            }],
+            ['OS=="linux"', {
+              # Tests that currently only work on Linux.
+              'dependencies': [
+                '../base/base.gyp:base_unittests',
+                '../ipc/ipc.gyp:ipc_tests',
+                '../sql/sql.gyp:sql_unittests',
+                '../sync/sync.gyp:sync_unit_tests',
+              ],
+            }],
+            ['chromeos==1', {
+              'dependencies': [
+                '../chromeos/chromeos.gyp:chromeos_unittests',
+                '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_unittests',
+              ],
+            }],
+            ['use_ozone==1', {
+              'dependencies': [
+                '../ui/ozone/ozone.gyp:*',
+                '../ui/ozone/demo/ozone_demos.gyp:*',
+              ],
+            }],
+            ['chromecast==0', {
+              'dependencies': [
+                '../chrome/chrome.gyp:browser_tests',
+                '../chrome/chrome.gyp:chrome',
+                '../chrome/chrome.gyp:interactive_ui_tests',
+                '../chrome/chrome.gyp:unit_tests',
+                '../ui/message_center/message_center.gyp:*',
+                '../ui/views/examples/examples.gyp:views_examples_with_content_exe',
+                '../ui/views/views.gyp:views',
+                '../ui/views/views.gyp:views_unittests',
+              ],
+            }],
+          ],
+        },
+      ],  # targets
+    }], # "use_aura==1"
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'chromium_swarm_tests',
+          'type': 'none',
+          'dependencies': [
+            '../base/base.gyp:base_unittests_run',
+            '../content/content_shell_and_tests.gyp:content_browsertests_run',
+            '../content/content_shell_and_tests.gyp:content_unittests_run',
+            '../net/net.gyp:net_unittests_run',
+          ],
+          'conditions': [
+            ['chromecast==0', {
+              'dependencies': [
+                '../chrome/chrome.gyp:browser_tests_run',
+                '../chrome/chrome.gyp:interactive_ui_tests_run',
+                '../chrome/chrome.gyp:sync_integration_tests_run',
+                '../chrome/chrome.gyp:unit_tests_run',
+              ],
+            }],
+          ],
+        }, # target_name: chromium_swarm_tests
+      ],
+    }],
+    ['archive_chromoting_tests==1', {
+      'targets': [
+        {
+          'target_name': 'chromoting_swarm_tests',
+          'type': 'none',
+          'dependencies': [
+            '../testing/chromoting/integration_tests.gyp:chromoting_integration_tests_run',
+          ],
+        }, # target_name: chromoting_swarm_tests
+      ]
+    }],
+    ['OS=="mac" and toolkit_views==1', {
+      'targets': [
+        {
+          'target_name': 'macviews_builder',
+          'type': 'none',
+          'dependencies': [
+            '../ui/views/examples/examples.gyp:views_examples_with_content_exe',
+            '../ui/views/views.gyp:views',
+            '../ui/views/views.gyp:views_unittests',
+          ],
+        },  # target_name: macviews_builder
+      ],  # targets
+    }],  # os=='mac' and toolkit_views==1
+  ],  # conditions
+}
diff --git a/build/android/AndroidManifest.xml b/build/android/AndroidManifest.xml
new file mode 100644
index 0000000..f27872e
--- /dev/null
+++ b/build/android/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (c) 2012 The Chromium 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 dummy manifest which is required by:
+  1. aapt when generating R.java in java.gypi:
+     Nothing in the manifest is used, but it is still required by aapt.
+  2. lint: [min|target]SdkVersion are required by lint and should
+     be kept up-to-date.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="dummy.package">
+
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" />
+
+</manifest>
diff --git a/build/android/CheckInstallApk-debug.apk b/build/android/CheckInstallApk-debug.apk
new file mode 100644
index 0000000..3dc3191
--- /dev/null
+++ b/build/android/CheckInstallApk-debug.apk
Binary files differ
diff --git a/build/android/OWNERS b/build/android/OWNERS
new file mode 100644
index 0000000..9a5d270
--- /dev/null
+++ b/build/android/OWNERS
@@ -0,0 +1,3 @@
+jbudorick@chromium.org
+klundberg@chromium.org
+pasko@chromium.org
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
new file mode 100644
index 0000000..6e0a3de
--- /dev/null
+++ b/build/android/PRESUBMIT.py
@@ -0,0 +1,64 @@
+# 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.
+
+"""Presubmit script for android buildbot.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
+details on the presubmit API built into depot_tools.
+"""
+
+
+def CommonChecks(input_api, output_api):
+  output = []
+
+  def J(*dirs):
+    """Returns a path relative to presubmit directory."""
+    return input_api.os_path.join(input_api.PresubmitLocalPath(), *dirs)
+
+  output.extend(input_api.canned_checks.RunPylint(
+      input_api,
+      output_api,
+      black_list=[r'pylib/symbols/.*\.py$', r'gyp/.*\.py$', r'gn/.*\.py'],
+      extra_paths_list=[
+          J(), J('..', '..', 'third_party', 'android_testrunner'),
+          J('buildbot')]))
+  output.extend(input_api.canned_checks.RunPylint(
+      input_api,
+      output_api,
+      white_list=[r'gyp/.*\.py$', r'gn/.*\.py'],
+      extra_paths_list=[J('gyp'), J('gn')]))
+
+  # Disabled due to http://crbug.com/410936
+  #output.extend(input_api.canned_checks.RunUnitTestsInDirectory(
+  #input_api, output_api, J('buildbot', 'tests')))
+
+  pylib_test_env = dict(input_api.environ)
+  pylib_test_env.update({
+      'PYTHONPATH': input_api.PresubmitLocalPath(),
+      'PYTHONDONTWRITEBYTECODE': '1',
+  })
+  output.extend(input_api.canned_checks.RunUnitTests(
+      input_api,
+      output_api,
+      unit_tests=[
+          J('pylib', 'base', 'test_dispatcher_unittest.py'),
+          J('pylib', 'device', 'battery_utils_test.py'),
+          J('pylib', 'device', 'device_utils_test.py'),
+          J('pylib', 'device', 'logcat_monitor_test.py'),
+          J('pylib', 'gtest', 'gtest_test_instance_test.py'),
+          J('pylib', 'instrumentation',
+            'instrumentation_test_instance_test.py'),
+          J('pylib', 'results', 'json_results_test.py'),
+          J('pylib', 'utils', 'md5sum_test.py'),
+      ],
+      env=pylib_test_env))
+  return output
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return CommonChecks(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return CommonChecks(input_api, output_api)
diff --git a/build/android/adb_android_webview_command_line b/build/android/adb_android_webview_command_line
new file mode 100755
index 0000000..947cfb1
--- /dev/null
+++ b/build/android/adb_android_webview_command_line
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# If no flags are given, prints the current content shell flags.
+#
+# Otherwise, the given flags are used to REPLACE (not modify) the content shell
+# flags. For example:
+#   adb_android_webview_command_line --enable-webgl
+#
+# To remove all content shell flags, pass an empty string for the flags:
+#   adb_android_webview_command_line ""
+
+CMD_LINE_FILE=/data/local/tmp/android-webview-command-line
+
+if [ $# -eq 0 ] ; then
+  # If nothing specified, print the command line (stripping off "content_shell")
+  tempfile=$(tempfile)
+  adb pull $CMD_LINE_FILE $tempfile 2>/dev/null
+  if [ $? -eq 0 ] ; then
+    rm $tempfile
+    adb shell cat $CMD_LINE_FILE | cut -d " " -f "2-" 2>/dev/null
+  fi
+elif [ $# -eq 1 ] && [ "$1" = '' ] ; then
+  # If given an empty string, delete the command line.
+  set -x
+  adb shell rm $CMD_LINE_FILE >/dev/null
+else
+  # Else set it.
+  set -x
+  adb shell "echo 'android_webview $*' > $CMD_LINE_FILE"
+  # Prevent other apps from modifying flags -- this can create security issues.
+  adb shell chmod 0664 $CMD_LINE_FILE
+fi
+
diff --git a/build/android/adb_chrome_shell_command_line b/build/android/adb_chrome_shell_command_line
new file mode 100755
index 0000000..1e2bd38
--- /dev/null
+++ b/build/android/adb_chrome_shell_command_line
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright 2014 The Chromium 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 no flags are given, prints the current chrome shell flags.
+#
+# Otherwise, the given flags are used to REPLACE (not modify) the chrome shell
+# flags. For example:
+#   adb_chrome_shell_command_line --enable-webgl
+#
+# To remove all chrome shell flags, pass an empty string for the flags:
+#   adb_chrome_shell_command_line ""
+
+CMD_LINE_FILE=/data/local/tmp/chrome-shell-command-line
+
+if [ $# -eq 0 ] ; then
+  # If nothing specified, print the command line (stripping off "chrome_shell")
+  tempfile=$(tempfile)
+  adb pull $CMD_LINE_FILE $tempfile 2>/dev/null
+  if [ $? -eq 0 ] ; then
+    rm $tempfile
+    adb shell cat $CMD_LINE_FILE | cut -d " " -f "2-" 2>/dev/null
+  fi
+elif [ $# -eq 1 ] && [ "$1" = '' ] ; then
+  # If given an empty string, delete the command line.
+  set -x
+  adb shell rm $CMD_LINE_FILE >/dev/null
+else
+  # Else set it.
+  set -x
+  adb shell "echo 'chrome_shell $*' > $CMD_LINE_FILE"
+  # Prevent other apps from modifying flags -- this can create security issues.
+  adb shell chmod 0664 $CMD_LINE_FILE
+fi
+
diff --git a/build/android/adb_content_shell_command_line b/build/android/adb_content_shell_command_line
new file mode 100755
index 0000000..f3c1d4f
--- /dev/null
+++ b/build/android/adb_content_shell_command_line
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium 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 no flags are given, prints the current content shell flags.
+#
+# Otherwise, the given flags are used to REPLACE (not modify) the content shell
+# flags. For example:
+#   adb_content_shell_command_line --enable-webgl
+#
+# To remove all content shell flags, pass an empty string for the flags:
+#   adb_content_shell_command_line ""
+
+CMD_LINE_FILE=/data/local/tmp/content-shell-command-line
+
+if [ $# -eq 0 ] ; then
+  # If nothing specified, print the command line (stripping off "content_shell")
+  tempfile=$(tempfile)
+  adb pull $CMD_LINE_FILE $tempfile 2>/dev/null
+  if [ $? -eq 0 ] ; then
+    rm $tempfile
+    adb shell cat $CMD_LINE_FILE | cut -d " " -f "2-" 2>/dev/null
+  fi
+elif [ $# -eq 1 ] && [ "$1" = '' ] ; then
+  # If given an empty string, delete the command line.
+  set -x
+  adb shell rm $CMD_LINE_FILE >/dev/null
+else
+  # Else set it.
+  set -x
+  adb shell "echo 'content_shell $*' > $CMD_LINE_FILE"
+  # Prevent other apps from modifying flags -- this can create security issues.
+  adb shell chmod 0664 $CMD_LINE_FILE
+fi
+
diff --git a/build/android/adb_device_functions.sh b/build/android/adb_device_functions.sh
new file mode 100755
index 0000000..66cc32f
--- /dev/null
+++ b/build/android/adb_device_functions.sh
@@ -0,0 +1,139 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium 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 collection of functions useful for maintaining android devices
+
+
+# Run an adb command on all connected device in parallel.
+# Usage: adb_all command line to eval.  Quoting is optional.
+#
+# Examples:
+#  adb_all install Chrome.apk
+#  adb_all 'shell cat /path/to/file'
+#
+adb_all() {
+  if [[ $# == 0 ]]; then
+    echo "Usage: adb_all <adb command>.  Quoting is optional."
+    echo "Example: adb_all install Chrome.apk"
+    return 1
+  fi
+  local DEVICES=$(adb_get_devices -b)
+  local NUM_DEVICES=$(echo $DEVICES | wc -w)
+  if (( $NUM_DEVICES > 1 )); then
+    echo "Looping over $NUM_DEVICES devices"
+  fi
+  _adb_multi "$DEVICES" "$*"
+}
+
+
+# Run a command on each connected device.  Quoting the command is suggested but
+# not required.  The script setups up variable DEVICE to correspond to the
+# current serial number.  Intended for complex one_liners that don't work in
+# adb_all
+# Usage: adb_device_loop 'command line to eval'
+adb_device_loop() {
+  if [[ $# == 0 ]]; then
+    echo "Intended for more complex one-liners that cannot be done with" \
+        "adb_all."
+    echo 'Usage: adb_device_loop "echo $DEVICE: $(adb root &&' \
+        'adb shell cat /data/local.prop)"'
+    return 1
+  fi
+  local DEVICES=$(adb_get_devices)
+  if [[ -z $DEVICES ]]; then
+    return
+  fi
+  # Do not change DEVICE variable name - part of api
+  for DEVICE in $DEVICES; do
+    DEV_TYPE=$(adb -s $DEVICE shell getprop ro.product.device | sed 's/\r//')
+    echo "Running on $DEVICE ($DEV_TYPE)"
+    ANDROID_SERIAL=$DEVICE eval "$*"
+  done
+}
+
+# Erases data from any devices visible on adb.  To preserve a device,
+# disconnect it or:
+#  1) Reboot it into fastboot with 'adb reboot bootloader'
+#  2) Run wipe_all_devices to wipe remaining devices
+#  3) Restore device it with 'fastboot reboot'
+#
+#  Usage: wipe_all_devices [-f]
+#
+wipe_all_devices() {
+  if [[ -z $(which adb) || -z $(which fastboot) ]]; then
+    echo "aborting: adb and fastboot not in path"
+    return 1
+  elif ! $(groups | grep -q 'plugdev'); then
+    echo "If fastboot fails, run: 'sudo adduser $(whoami) plugdev'"
+  fi
+
+  local DEVICES=$(adb_get_devices -b)
+
+  if [[ $1 != '-f' ]]; then
+    echo "This will ERASE ALL DATA from $(echo $DEVICES | wc -w) device."
+    read -p "Hit enter to continue"
+  fi
+
+  _adb_multi "$DEVICES" "reboot bootloader"
+  # Subshell to isolate job list
+  (
+  for DEVICE in $DEVICES; do
+    fastboot_erase $DEVICE &
+  done
+  wait
+  )
+
+  # Reboot devices together
+  for DEVICE in $DEVICES; do
+    fastboot -s $DEVICE reboot
+  done
+}
+
+# Wipe a device in fastboot.
+# Usage fastboot_erase [serial]
+fastboot_erase() {
+  if [[ -n $1 ]]; then
+    echo "Wiping $1"
+    local SERIAL="-s $1"
+  else
+    if [ -z $(fastboot devices) ]; then
+      echo "No devices in fastboot, aborting."
+      echo "Check out wipe_all_devices to see if sufficient"
+      echo "You can put a device in fastboot using adb reboot bootloader"
+      return 1
+    fi
+    local SERIAL=""
+  fi
+  fastboot $SERIAL erase cache
+  fastboot $SERIAL erase userdata
+}
+
+# Get list of devices connected via adb
+# Args: -b block until adb detects a device
+adb_get_devices() {
+  local DEVICES="$(adb devices | grep 'device$')"
+  if [[ -z $DEVICES && $1 == '-b' ]]; then
+    echo '- waiting for device -' >&2
+    local DEVICES="$(adb wait-for-device devices | grep 'device$')"
+  fi
+  echo "$DEVICES" | awk -vORS=' ' '{print $1}' | sed 's/ $/\n/'
+}
+
+###################################################
+## HELPER FUNCTIONS
+###################################################
+
+# Run an adb command in parallel over a device list
+_adb_multi() {
+  local DEVICES=$1
+  local ADB_ARGS=$2
+  (
+    for DEVICE in $DEVICES; do
+      adb -s $DEVICE $ADB_ARGS &
+    done
+    wait
+  )
+}
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
new file mode 100755
index 0000000..65ec7b2
--- /dev/null
+++ b/build/android/adb_gdb
@@ -0,0 +1,1047 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium 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 generic script used to attach to a running Chromium process and
+# debug it. Most users should not use this directly, but one of the
+# wrapper scripts like adb_gdb_content_shell
+#
+# Use --help to print full usage instructions.
+#
+
+PROGNAME=$(basename "$0")
+PROGDIR=$(dirname "$0")
+
+# Location of Chromium-top-level sources.
+CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null)
+
+# Location of Chromium out/ directory.
+if [ -z "$CHROMIUM_OUT_DIR" ]; then
+  CHROMIUM_OUT_DIR=out
+fi
+
+TMPDIR=
+GDBSERVER_PIDFILE=
+TARGET_GDBSERVER=
+COMMAND_PREFIX=
+
+clean_exit () {
+  if [ "$TMPDIR" ]; then
+    GDBSERVER_PID=$(cat $GDBSERVER_PIDFILE 2>/dev/null)
+    if [ "$GDBSERVER_PID" ]; then
+      log "Killing background gdbserver process: $GDBSERVER_PID"
+      kill -9 $GDBSERVER_PID >/dev/null 2>&1
+    fi
+    if [ "$TARGET_GDBSERVER" ]; then
+      log "Removing target gdbserver binary: $TARGET_GDBSERVER."
+      "$ADB" shell "$COMMAND_PREFIX" rm "$TARGET_GDBSERVER" >/dev/null 2>&1
+    fi
+    log "Cleaning up: $TMPDIR"
+    rm -rf "$TMPDIR"
+  fi
+  trap "" EXIT
+  exit $1
+}
+
+# Ensure clean exit on Ctrl-C or normal exit.
+trap "clean_exit 1" INT HUP QUIT TERM
+trap "clean_exit \$?" EXIT
+
+panic () {
+  echo "ERROR: $@" >&2
+  exit 1
+}
+
+fail_panic () {
+  if [ $? != 0 ]; then panic "$@"; fi
+}
+
+log () {
+  if [ "$VERBOSE" -gt 0 ]; then
+    echo "$@"
+  fi
+}
+
+DEFAULT_PULL_LIBS_DIR=/tmp/$USER-adb-gdb-libs
+
+# NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX
+# environment variables. This is only for cosmetic reasons, i.e. to
+# display proper
+
+# Allow wrapper scripts to set the default activity through
+# the ADB_GDB_ACTIVITY variable. Users are still able to change the
+# final activity name through --activity=<name> option.
+#
+# This is only for cosmetic reasons, i.e. to display the proper default
+# in the --help output.
+#
+DEFAULT_ACTIVITY=${ADB_GDB_ACTIVITY:-".Main"}
+
+# Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME
+PROGNAME=${ADB_GDB_PROGNAME:-$(basename "$0")}
+
+ACTIVITY=$DEFAULT_ACTIVITY
+ADB=
+ANNOTATE=
+# Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it.
+BUILDTYPE=
+FORCE=
+GDBEXEPOSTFIX=gdb
+GDBINIT=
+GDBSERVER=
+HELP=
+NDK_DIR=
+NO_PULL_LIBS=
+PACKAGE_NAME=
+PID=
+PORT=
+PRIVILEGED=
+PRIVILEGED_INDEX=
+PROGRAM_NAME="activity"
+PULL_LIBS=
+PULL_LIBS_DIR=
+SANDBOXED=
+SANDBOXED_INDEX=
+START=
+SU_PREFIX=
+SYMBOL_DIR=
+TARGET_ARCH=
+TOOLCHAIN=
+VERBOSE=0
+
+for opt; do
+  optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
+  case $opt in
+    --adb=*)
+      ADB=$optarg
+      ;;
+    --activity=*)
+      ACTIVITY=$optarg
+      ;;
+    --annotate=3)
+      ANNOTATE=$optarg
+      ;;
+    --force)
+      FORCE=true
+      ;;
+    --gdbserver=*)
+      GDBSERVER=$optarg
+      ;;
+    --gdb=*)
+      GDB=$optarg
+      ;;
+    --help|-h|-?)
+      HELP=true
+      ;;
+    --ndk-dir=*)
+      NDK_DIR=$optarg
+      ;;
+    --no-pull-libs)
+      NO_PULL_LIBS=true
+      ;;
+    --package-name=*)
+      PACKAGE_NAME=$optarg
+      ;;
+    --pid=*)
+      PID=$optarg
+      ;;
+    --port=*)
+      PORT=$optarg
+      ;;
+    --privileged)
+      PRIVILEGED=true
+      ;;
+    --privileged=*)
+      PRIVILEGED=true
+      PRIVILEGED_INDEX=$optarg
+      ;;
+    --program-name=*)
+      PROGRAM_NAME=$optarg
+      ;;
+    --pull-libs)
+      PULL_LIBS=true
+      ;;
+    --pull-libs-dir=*)
+      PULL_LIBS_DIR=$optarg
+      ;;
+    --sandboxed)
+      SANDBOXED=true
+      ;;
+    --sandboxed=*)
+      SANDBOXED=true
+      SANDBOXED_INDEX=$optarg
+      ;;
+    --script=*)
+      GDBINIT=$optarg
+      ;;
+    --start)
+      START=true
+      ;;
+    --su-prefix=*)
+      SU_PREFIX=$optarg
+      ;;
+    --symbol-dir=*)
+      SYMBOL_DIR=$optarg
+      ;;
+    --out-dir=*)
+      CHROMIUM_OUT_DIR=$optarg
+      ;;
+    --target-arch=*)
+      TARGET_ARCH=$optarg
+      ;;
+    --toolchain=*)
+      TOOLCHAIN=$optarg
+      ;;
+    --ui)
+      GDBEXEPOSTFIX=gdbtui
+      ;;
+    --verbose)
+      VERBOSE=$(( $VERBOSE + 1 ))
+      ;;
+    --debug)
+      BUILDTYPE=Debug
+      ;;
+    --release)
+      BUILDTYPE=Release
+      ;;
+    -*)
+      panic "Unknown option $OPT, see --help." >&2
+      ;;
+    *)
+      if [ "$PACKAGE_NAME" ]; then
+        panic "You can only provide a single package name as argument!\
+ See --help."
+      fi
+      PACKAGE_NAME=$opt
+      ;;
+  esac
+done
+
+print_help_options () {
+  cat <<EOF
+EOF
+}
+
+if [ "$HELP" ]; then
+  if [ "$ADB_GDB_PROGNAME" ]; then
+    # Assume wrapper scripts all provide a default package name.
+    cat <<EOF
+Usage: $PROGNAME [options]
+
+Attach gdb to a running Android $PROGRAM_NAME process.
+EOF
+  else
+    # Assume this is a direct call to adb_gdb
+  cat <<EOF
+Usage: $PROGNAME [options] [<package-name>]
+
+Attach gdb to a running Android $PROGRAM_NAME process.
+
+If provided, <package-name> must be the name of the Android application's
+package name to be debugged. You can also use --package-name=<name> to
+specify it.
+EOF
+  fi
+
+  cat <<EOF
+
+This script is used to debug a running $PROGRAM_NAME process.
+This can be a regular Android application process, sandboxed (if you use the
+--sandboxed or --sandboxed=<num> option) or a privileged (--privileged or
+--privileged=<num>) service.
+
+This script needs several things to work properly. It will try to pick
+them up automatically for you though:
+
+   - target gdbserver binary
+   - host gdb client (e.g. arm-linux-androideabi-gdb)
+   - directory with symbolic version of $PROGRAM_NAME's shared libraries.
+
+You can also use --ndk-dir=<path> to specify an alternative NDK installation
+directory.
+
+The script tries to find the most recent version of the debug version of
+shared libraries under one of the following directories:
+
+  \$CHROMIUM_SRC/<out>/Release/lib/           (used by Ninja builds)
+  \$CHROMIUM_SRC/<out>/Debug/lib/             (used by Ninja builds)
+  \$CHROMIUM_SRC/<out>/Release/lib.target/    (used by Make builds)
+  \$CHROMIUM_SRC/<out>/Debug/lib.target/      (used by Make builds)
+
+Where <out> is 'out' by default, unless the --out=<name> option is used or
+the CHROMIUM_OUT_DIR environment variable is defined.
+
+You can restrict this search by using --release or --debug to specify the
+build type, or simply use --symbol-dir=<path> to specify the file manually.
+
+The script tries to extract the target architecture from your target device,
+but if this fails, will default to 'arm'. Use --target-arch=<name> to force
+its value.
+
+Otherwise, the script will complain, but you can use the --gdbserver,
+--gdb and --symbol-lib options to specify everything manually.
+
+An alternative to --gdb=<file> is to use --toollchain=<path> to specify
+the path to the host target-specific cross-toolchain.
+
+You will also need the 'adb' tool in your path. Otherwise, use the --adb
+option. The script will complain if there is more than one device connected
+and ANDROID_SERIAL is not defined.
+
+The first time you use it on a device, the script will pull many system
+libraries required by the process into a temporary directory. This
+is done to strongly improve the debugging experience, like allowing
+readable thread stacks and more. The libraries are copied to the following
+directory by default:
+
+  $DEFAULT_PULL_LIBS_DIR/
+
+But you can use the --pull-libs-dir=<path> option to specify an
+alternative. The script can detect when you change the connected device,
+and will re-pull the libraries only in this case. You can however force it
+with the --pull-libs option.
+
+Any local .gdbinit script will be ignored, but it is possible to pass a
+gdb command script with the --script=<file> option. Note that its commands
+will be passed to gdb after the remote connection and library symbol
+loading have completed.
+
+Valid options:
+  --help|-h|-?          Print this message.
+  --verbose             Increase verbosity.
+
+  --sandboxed           Debug first sandboxed process we find.
+  --sandboxed=<num>     Debug specific sandboxed process.
+  --symbol-dir=<path>   Specify directory with symbol shared libraries.
+  --out-dir=<path>      Specify the out directory.
+  --package-name=<name> Specify package name (alternative to 1st argument).
+  --privileged          Debug first privileged process we find.
+  --privileged=<num>    Debug specific privileged process.
+  --program-name=<name> Specify program name (cosmetic only).
+  --pid=<pid>           Specify application process pid.
+  --force               Kill any previous debugging session, if any.
+  --start               Start package's activity on device.
+  --ui                  Use gdbtui instead of gdb
+  --activity=<name>     Activity name for --start [$DEFAULT_ACTIVITY].
+  --annotate=<num>      Enable gdb annotation.
+  --script=<file>       Specify extra GDB init script.
+
+  --gdbserver=<file>    Specify target gdbserver binary.
+  --gdb=<file>          Specify host gdb client binary.
+  --target-arch=<name>  Specify NDK target arch.
+  --adb=<file>          Specify host ADB binary.
+  --port=<port>         Specify the tcp port to use.
+
+  --su-prefix=<prefix>  Prepend <prefix> to 'adb shell' commands that are
+                        run by this script. This can be useful to use
+                        the 'su' program on rooted production devices.
+                        e.g. --su-prefix="su -c"
+
+  --pull-libs           Force system libraries extraction.
+  --no-pull-libs        Do not extract any system library.
+  --libs-dir=<path>     Specify system libraries extraction directory.
+
+  --debug               Use libraries under out/Debug.
+  --release             Use libraries under out/Release.
+
+EOF
+  exit 0
+fi
+
+if [ -z "$PACKAGE_NAME" ]; then
+  panic "Please specify a package name on the command line. See --help."
+fi
+
+if [ -z "$NDK_DIR" ]; then
+  ANDROID_NDK_ROOT=$(PYTHONPATH=$CHROMIUM_SRC/build/android python -c \
+'from pylib.constants import ANDROID_NDK_ROOT; print ANDROID_NDK_ROOT,')
+else
+  if [ ! -d "$NDK_DIR" ]; then
+    panic "Invalid directory: $NDK_DIR"
+  fi
+  if [ ! -f "$NDK_DIR/ndk-build" ]; then
+    panic "Not a valid NDK directory: $NDK_DIR"
+  fi
+  ANDROID_NDK_ROOT=$NDK_DIR
+fi
+
+if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then
+  panic "Unknown --script file: $GDBINIT"
+fi
+
+# Check that ADB is in our path
+if [ -z "$ADB" ]; then
+  ADB=$(which adb 2>/dev/null)
+  if [ -z "$ADB" ]; then
+    panic "Can't find 'adb' tool in your path. Install it or use \
+--adb=<file>"
+  fi
+  log "Auto-config: --adb=$ADB"
+fi
+
+# Check that it works minimally
+ADB_VERSION=$($ADB version 2>/dev/null)
+echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge"
+if [ $? != 0 ]; then
+  panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
+different one: $ADB"
+fi
+
+# If there are more than one device connected, and ANDROID_SERIAL is not
+# defined, print an error message.
+NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l)
+if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then
+  echo "ERROR: There is more than one Android device connected to ADB."
+  echo "Please define ANDROID_SERIAL to specify which one to use."
+  exit 1
+fi
+
+# Run a command through adb shell, strip the extra \r from the output
+# and return the correct status code to detect failures. This assumes
+# that the adb shell command prints a final \n to stdout.
+# $1+: command to run
+# Out: command's stdout
+# Return: command's status
+# Note: the command's stderr is lost
+adb_shell () {
+  local TMPOUT="$(mktemp)"
+  local LASTLINE RET
+  local ADB=${ADB:-adb}
+
+  # The weird sed rule is to strip the final \r on each output line
+  # Since 'adb shell' never returns the command's proper exit/status code,
+  # we force it to print it as '%%<status>' in the temporary output file,
+  # which we will later strip from it.
+  $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \
+      sed -e 's![[:cntrl:]]!!g' > $TMPOUT
+  # Get last line in log, which contains the exit code from the command
+  LASTLINE=$(sed -e '$!d' $TMPOUT)
+  # Extract the status code from the end of the line, which must
+  # be '%%<code>'.
+  RET=$(echo "$LASTLINE" | \
+    awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }')
+  # Remove the status code from the last line. Note that this may result
+  # in an empty line.
+  LASTLINE=$(echo "$LASTLINE" | \
+    awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }')
+  # The output itself: all lines except the status code.
+  sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE"
+  # Remove temp file.
+  rm -f $TMPOUT
+  # Exit with the appropriate status.
+  return $RET
+}
+
+# Find the target architecture from the target device.
+# This returns an NDK-compatible architecture name.
+# out: NDK Architecture name, or empty string.
+get_gyp_target_arch () {
+  local ARCH=$(adb_shell getprop ro.product.cpu.abi)
+  case $ARCH in
+    mips|x86|x86_64) echo "$ARCH";;
+    arm64*) echo "arm64";;
+    arm*) echo "arm";;
+    *) echo "";
+  esac
+}
+
+if [ -z "$TARGET_ARCH" ]; then
+  TARGET_ARCH=$(get_gyp_target_arch)
+  if [ -z "$TARGET_ARCH" ]; then
+    TARGET_ARCH=arm
+  fi
+else
+  # Nit: accept Chromium's 'ia32' as a valid target architecture. This
+  # script prefers the NDK 'x86' name instead because it uses it to find
+  # NDK-specific files (host gdb) with it.
+  if [ "$TARGET_ARCH" = "ia32" ]; then
+    TARGET_ARCH=x86
+    log "Auto-config: --arch=$TARGET_ARCH  (equivalent to ia32)"
+  fi
+fi
+
+# Detect the NDK system name, i.e. the name used to identify the host.
+# out: NDK system name (e.g. 'linux' or 'darwin')
+get_ndk_host_system () {
+  local HOST_OS
+  if [ -z "$NDK_HOST_SYSTEM" ]; then
+    HOST_OS=$(uname -s)
+    case $HOST_OS in
+      Linux) NDK_HOST_SYSTEM=linux;;
+      Darwin) NDK_HOST_SYSTEM=darwin;;
+      *) panic "You can't run this script on this system: $HOST_OS";;
+    esac
+  fi
+  echo "$NDK_HOST_SYSTEM"
+}
+
+# Detect the NDK host architecture name.
+# out: NDK arch name (e.g. 'x86' or 'x86_64')
+get_ndk_host_arch () {
+  local HOST_ARCH HOST_OS
+  if [ -z "$NDK_HOST_ARCH" ]; then
+    HOST_OS=$(get_ndk_host_system)
+    HOST_ARCH=$(uname -p)
+    case $HOST_ARCH in
+      i?86) NDK_HOST_ARCH=x86;;
+      x86_64|amd64) NDK_HOST_ARCH=x86_64;;
+      *) panic "You can't run this script on this host architecture: $HOST_ARCH";;
+    esac
+    # Darwin trick: "uname -p" always returns i386 on 64-bit installations.
+    if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then
+      # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts
+      # implementations of the tool. See http://b.android.com/53769
+      HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64")
+      if [ "$HOST_64BITS" ]; then
+        NDK_HOST_ARCH=x86_64
+      fi
+    fi
+  fi
+  echo "$NDK_HOST_ARCH"
+}
+
+# Convert an NDK architecture name into a GNU configure triplet.
+# $1: NDK architecture name (e.g. 'arm')
+# Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi')
+get_arch_gnu_config () {
+  case $1 in
+    arm)
+      echo "arm-linux-androideabi"
+      ;;
+    arm64)
+      echo "aarch64-linux-android"
+      ;;
+    x86)
+      echo "i686-linux-android"
+      ;;
+    x86_64)
+      echo "x86_64-linux-android"
+      ;;
+    mips)
+      echo "mipsel-linux-android"
+      ;;
+    *)
+      echo "$ARCH-linux-android"
+      ;;
+  esac
+}
+
+# Convert an NDK architecture name into a toolchain name prefix
+# $1: NDK architecture name (e.g. 'arm')
+# Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi')
+get_arch_toolchain_prefix () {
+  # Return the configure triplet, except for x86!
+  if [ "$1" = "x86" ]; then
+    echo "$1"
+  else
+    get_arch_gnu_config $1
+  fi
+}
+
+# Find a NDK toolchain prebuilt file or sub-directory.
+# This will probe the various arch-specific toolchain directories
+# in the NDK for the needed file.
+# $1: NDK install path
+# $2: NDK architecture name
+# $3: prebuilt sub-path to look for.
+# Out: file path, or empty if none is found.
+get_ndk_toolchain_prebuilt () {
+  local NDK_DIR="${1%/}"
+  local ARCH="$2"
+  local SUBPATH="$3"
+  local NAME="$(get_arch_toolchain_prefix $ARCH)"
+  local FILE TARGET
+  FILE=$NDK_DIR/toolchains/$NAME-4.9/prebuilt/$SUBPATH
+  if [ ! -f "$FILE" ]; then
+    FILE=$NDK_DIR/toolchains/$NAME-4.8/prebuilt/$SUBPATH
+    if [ ! -f "$FILE" ]; then
+      FILE=
+    fi
+  fi
+  echo "$FILE"
+}
+
+# Find the path to an NDK's toolchain full prefix for a given architecture
+# $1: NDK install path
+# $2: NDK target architecture name
+# Out: install path + binary prefix (e.g.
+#      ".../path/to/bin/arm-linux-androideabi-")
+get_ndk_toolchain_fullprefix () {
+  local NDK_DIR="$1"
+  local ARCH="$2"
+  local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG
+
+  # NOTE: This will need to be updated if the NDK changes the names or moves
+  #        the location of its prebuilt toolchains.
+  #
+  GCC=
+  HOST_OS=$(get_ndk_host_system)
+  HOST_ARCH=$(get_ndk_host_arch)
+  CONFIG=$(get_arch_gnu_config $ARCH)
+  GCC=$(get_ndk_toolchain_prebuilt \
+        "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc")
+  if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then
+    GCC=$(get_ndk_toolchain_prebuilt \
+          "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc")
+  fi
+  if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then
+    # Special case, the x86 toolchain used to be incorrectly
+    # named i686-android-linux-gcc!
+    GCC=$(get_ndk_toolchain_prebuilt \
+          "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc")
+  fi
+  if [ -z "$GCC" ]; then
+    panic "Cannot find Android NDK toolchain for '$ARCH' architecture. \
+Please verify your NDK installation!"
+  fi
+  echo "${GCC%%gcc}"
+}
+
+# $1: NDK install path
+# $2: target architecture.
+get_ndk_gdbserver () {
+  local NDK_DIR="$1"
+  local ARCH=$2
+  local BINARY
+
+  # The location has moved after NDK r8
+  BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver
+  if [ ! -f "$BINARY" ]; then
+    BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver)
+  fi
+  echo "$BINARY"
+}
+
+# Check/probe the path to the Android toolchain installation. Always
+# use the NDK versions of gdb and gdbserver. They must match to avoid
+# issues when both binaries do not speak the same wire protocol.
+#
+if [ -z "$TOOLCHAIN" ]; then
+  ANDROID_TOOLCHAIN=$(get_ndk_toolchain_fullprefix \
+                      "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
+  ANDROID_TOOLCHAIN=$(dirname "$ANDROID_TOOLCHAIN")
+  log "Auto-config: --toolchain=$ANDROID_TOOLCHAIN"
+else
+  # Be flexible, allow one to specify either the install path or the bin
+  # sub-directory in --toolchain:
+  #
+  if [ -d "$TOOLCHAIN/bin" ]; then
+    TOOLCHAIN=$TOOLCHAIN/bin
+  fi
+  ANDROID_TOOLCHAIN=$TOOLCHAIN
+fi
+
+# Cosmetic: Remove trailing directory separator.
+ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN%/}
+
+# Find host GDB client binary
+if [ -z "$GDB" ]; then
+  GDB=$(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev/null | head -1)
+  if [ -z "$GDB" ]; then
+    panic "Can't find Android gdb client in your path, check your \
+--toolchain or --gdb path."
+  fi
+  log "Host gdb client: $GDB"
+fi
+
+# Find gdbserver binary, we will later push it to /data/local/tmp
+# This ensures that both gdbserver and $GDB talk the same binary protocol,
+# otherwise weird problems will appear.
+#
+if [ -z "$GDBSERVER" ]; then
+  GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
+  if [ -z "$GDBSERVER" ]; then
+    panic "Can't find NDK gdbserver binary. use --gdbserver to specify \
+valid one!"
+  fi
+  log "Auto-config: --gdbserver=$GDBSERVER"
+fi
+
+# A unique ID for this script's session. This needs to be the same in all
+# sub-shell commands we're going to launch, so take the PID of the launcher
+# process.
+TMP_ID=$$
+
+# Temporary directory, will get cleaned up on exit.
+TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID
+mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/*
+
+GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid
+
+# If --force is specified, try to kill any gdbserver process started by the
+# same user on the device. Normally, these are killed automatically by the
+# script on exit, but there are a few corner cases where this would still
+# be needed.
+if [ "$FORCE" ]; then
+  GDBSERVER_PIDS=$(adb_shell ps | awk '$9 ~ /gdbserver/ { print $2; }')
+  for GDB_PID in $GDBSERVER_PIDS; do
+    log "Killing previous gdbserver (PID=$GDB_PID)"
+    adb_shell kill -9 $GDB_PID
+  done
+fi
+
+if [ "$START" ]; then
+  log "Starting $PROGRAM_NAME on device."
+  adb_shell am start -n $PACKAGE_NAME/$ACTIVITY 2>/dev/null
+  adb_shell ps | grep -q $PACKAGE_NAME
+  fail_panic "Could not start $PROGRAM_NAME on device. Are you sure the \
+package is installed?"
+fi
+
+# Return the timestamp of a given time, as number of seconds since epoch.
+# $1: file path
+# Out: file timestamp
+get_file_timestamp () {
+  stat -c %Y "$1" 2>/dev/null
+}
+
+# Detect the build type and symbol directory. This is done by finding
+# the most recent sub-directory containing debug shared libraries under
+# $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/
+#
+# $1: $BUILDTYPE value, can be empty
+# Out: nothing, but this sets SYMBOL_DIR
+#
+detect_symbol_dir () {
+  local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP
+  # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while
+  # Make places then under out/$BUILDTYPE/lib.target.
+  if [ "$1" ]; then
+    SUBDIRS="$1/lib $1/lib.target"
+  else
+    SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target"
+  fi
+  LIST=$TMPDIR/scan-subdirs-$$.txt
+  printf "" > "$LIST"
+  for SUBDIR in $SUBDIRS; do
+    DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
+    if [ -d "$DIR" ]; then
+      # Ignore build directories that don't contain symbol versions
+      # of the shared libraries.
+      DIR_LIBS=$(ls "$DIR"/lib*.so 2>/dev/null)
+      if [ -z "$DIR_LIBS" ]; then
+        echo "No shared libs: $DIR"
+        continue
+      fi
+      TSTAMP=$(get_file_timestamp "$DIR")
+      printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
+    fi
+  done
+  SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2)
+  rm -f "$LIST"
+
+  if [ -z "$SUBDIR" ]; then
+    if [ -z "$1" ]; then
+      panic "Could not find any build directory under \
+$CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!"
+    else
+      panic "Could not find any $1 directory under \
+$CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!"
+    fi
+  fi
+
+  SYMBOL_DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR
+  log "Auto-config: --symbol-dir=$SYMBOL_DIR"
+}
+
+if [ -z "$SYMBOL_DIR" ]; then
+  detect_symbol_dir "$BUILDTYPE"
+fi
+
+# Allow several concurrent debugging sessions
+TARGET_GDBSERVER=/data/data/$PACKAGE_NAME/gdbserver-adb-gdb-$TMP_ID
+TMP_TARGET_GDBSERVER=/data/local/tmp/gdbserver-adb-gdb-$TMP_ID
+
+# Return the build fingerprint contained in a build.prop file.
+# $1: path to build.prop file
+get_build_fingerprint_from () {
+  cat "$1" | grep -e '^ro.build.fingerprint=' | cut -d= -f2
+}
+
+
+ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR
+PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
+
+HOST_FINGERPRINT=
+DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
+log "Device build fingerprint: $DEVICE_FINGERPRINT"
+
+# If --pull-libs-dir is not specified, and this is a platform build, look
+# if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/
+# directly, if the build fingerprint matches the device.
+if [ -z "$ORG_PULL_LIBS_DIR" -a \
+     "$ANDROID_PRODUCT_OUT" -a \
+     -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then
+  ANDROID_FINGERPRINT=$(get_build_fingerprint_from \
+                        "$ANDROID_PRODUCT_OUT"/system/build.prop)
+  log "Android build fingerprint:  $ANDROID_FINGERPRINT"
+  if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then
+    log "Perfect match!"
+    PULL_LIBS_DIR=$ANDROID_PRODUCT_OUT/symbols
+    HOST_FINGERPRINT=$ANDROID_FINGERPRINT
+    if [ "$PULL_LIBS" ]; then
+      log "Ignoring --pull-libs since the device and platform build \
+fingerprints match."
+      NO_PULL_LIBS=true
+    fi
+  fi
+fi
+
+# If neither --pull-libs an --no-pull-libs were specified, check the build
+# fingerprints of the device, and the cached system libraries on the host.
+#
+if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then
+  if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then
+    log "Auto-config: --pull-libs  (no cached libraries)"
+    PULL_LIBS=true
+  else
+    HOST_FINGERPRINT=$(get_build_fingerprint_from "$PULL_LIBS_DIR/build.prop")
+    log "Host build fingerprint:   $HOST_FINGERPRINT"
+    if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
+      log "Auto-config: --no-pull-libs (fingerprint match)"
+      NO_PULL_LIBS=true
+    else
+      log "Auto-config: --pull-libs  (fingerprint mismatch)"
+      PULL_LIBS=true
+    fi
+  fi
+fi
+
+# Extract the system libraries from the device if necessary.
+if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
+  echo "Extracting system libraries into: $PULL_LIBS_DIR"
+fi
+
+mkdir -p "$PULL_LIBS_DIR"
+fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR"
+
+# If requested, work for M-x gdb.  The gdb indirections make it
+# difficult to pass --annotate=3 to the gdb binary itself.
+GDB_ARGS=
+if [ "$ANNOTATE" ]; then
+  GDB_ARGS=$GDB_ARGS" --annotate=$ANNOTATE"
+fi
+
+# Get the PID from the first argument or else find the PID of the
+# browser process.
+if [ -z "$PID" ]; then
+  PROCESSNAME=$PACKAGE_NAME
+  if [ "$SANDBOXED_INDEX" ]; then
+    PROCESSNAME=$PROCESSNAME:sandboxed_process$SANDBOXED_INDEX
+  elif [ "$SANDBOXED" ]; then
+    PROCESSNAME=$PROCESSNAME:sandboxed_process
+    PID=$(adb_shell ps | \
+          awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
+  elif [ "$PRIVILEGED_INDEX" ]; then
+    PROCESSNAME=$PROCESSNAME:privileged_process$PRIVILEGED_INDEX
+  elif [ "$PRIVILEGED" ]; then
+    PROCESSNAME=$PROCESSNAME:privileged_process
+    PID=$(adb_shell ps | \
+          awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
+  fi
+  if [ -z "$PID" ]; then
+    PID=$(adb_shell ps | \
+          awk '$9 == "'$PROCESSNAME'" { print $2; }' | head -1)
+  fi
+  if [ -z "$PID" ]; then
+    if [ "$START" ]; then
+      panic "Can't find application process PID, did it crash?"
+    else
+      panic "Can't find application process PID, are you sure it is \
+running? Try using --start."
+    fi
+  fi
+  log "Found process PID: $PID"
+elif [ "$SANDBOXED" ]; then
+  echo "WARNING: --sandboxed option ignored due to use of --pid."
+elif [ "$PRIVILEGED" ]; then
+  echo "WARNING: --privileged option ignored due to use of --pid."
+fi
+
+# Determine if 'adb shell' runs as root or not.
+# If so, we can launch gdbserver directly, otherwise, we have to
+# use run-as $PACKAGE_NAME ..., which requires the package to be debuggable.
+#
+if [ "$SU_PREFIX" ]; then
+  # Need to check that this works properly.
+  SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log
+  adb_shell $SU_PREFIX \"echo "foo"\" > $SU_PREFIX_TEST_LOG 2>&1
+  if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then
+    echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:"
+    echo "$ adb shell $SU_PREFIX \"echo foo\""
+    cat $SU_PREFIX_TEST_LOG
+    exit 1
+  fi
+  COMMAND_PREFIX="$SU_PREFIX \""
+  COMMAND_SUFFIX="\""
+else
+  SHELL_UID=$(adb shell cat /proc/self/status | \
+              awk '$1 == "Uid:" { print $2; }')
+  log "Shell UID: $SHELL_UID"
+  if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
+    COMMAND_PREFIX="run-as $PACKAGE_NAME"
+    COMMAND_SUFFIX=
+  else
+    COMMAND_PREFIX=
+    COMMAND_SUFFIX=
+  fi
+fi
+log "Command prefix: '$COMMAND_PREFIX'"
+log "Command suffix: '$COMMAND_SUFFIX'"
+
+# Pull device's system libraries that are mapped by our process.
+# Pulling all system libraries is too long, so determine which ones
+# we need by looking at /proc/$PID/maps instead
+if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
+  echo "Extracting system libraries into: $PULL_LIBS_DIR"
+  rm -f $PULL_LIBS_DIR/build.prop
+  MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps $COMMAND_SUFFIX)
+  if [ $? != 0 ]; then
+    echo "ERROR: Could not list process's memory mappings."
+    if [ "$SU_PREFIX" ]; then
+      panic "Are you sure your --su-prefix is correct?"
+    else
+      panic "Use --su-prefix if the application is not debuggable."
+    fi
+  fi
+  SYSTEM_LIBS=$(echo "$MAPPINGS" | \
+      awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u)
+  for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do
+    echo "Pulling from device: $SYSLIB"
+    DST_FILE=$PULL_LIBS_DIR$SYSLIB
+    DST_DIR=$(dirname "$DST_FILE")
+    mkdir -p "$DST_DIR" && adb pull $SYSLIB "$DST_FILE" 2>/dev/null
+    fail_panic "Could not pull $SYSLIB from device !?"
+  done
+  echo "Pulling device build.prop"
+  adb pull /system/build.prop $PULL_LIBS_DIR/build.prop
+  fail_panic "Could not pull device build.prop !?"
+fi
+
+# Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
+# so we can add them to solib-search-path later.
+SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
+             grep -v "^$" | tr '\n' ':')
+
+# This is a re-implementation of gdbclient, where we use compatible
+# versions of gdbserver and $GDBNAME to ensure that everything works
+# properly.
+#
+
+# Push gdbserver to the device
+log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER"
+adb push $GDBSERVER $TMP_TARGET_GDBSERVER &>/dev/null
+adb shell $COMMAND_PREFIX cp $TMP_TARGET_GDBSERVER $TARGET_GDBSERVER
+adb shell rm $TMP_TARGET_GDBSERVER
+fail_panic "Could not copy gdbserver to the device!"
+
+if [ -z "$PORT" ]; then
+    PORT=5039
+fi
+HOST_PORT=$PORT
+TARGET_PORT=$PORT
+
+# Select correct app_process for architecture.
+case $TARGET_ARCH in
+      arm|x86|mips) GDBEXEC=app_process;;
+      arm64|x86_64) GDBEXEC=app_process64;;
+      *) fail_panic "Unknown app_process for architecture!";;
+esac
+
+# Detect AddressSanitizer setup on the device. In that case app_process is a
+# script, and the real executable is app_process.real.
+GDBEXEC_ASAN=app_process.real
+adb_shell ls /system/bin/$GDBEXEC_ASAN
+if [ $? == 0 ]; then
+    GDBEXEC=$GDBEXEC_ASAN
+fi
+
+# Pull the app_process binary from the device.
+log "Pulling $GDBEXEC from device"
+adb pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null
+fail_panic "Could not retrieve $GDBEXEC from the device!"
+
+# Setup network redirection
+log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)"
+adb forward tcp:$HOST_PORT tcp:$TARGET_PORT
+fail_panic "Could not setup network redirection from \
+host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!"
+
+# Start gdbserver in the background
+# Note that using run-as requires the package to be debuggable.
+#
+# If not, this will fail horribly. The alternative is to run the
+# program as root, which requires of course root privileges.
+# Maybe we should add a --root option to enable this?
+#
+log "Starting gdbserver in the background:"
+GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log
+log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
+--attach $PID $COMMAND_SUFFIX"
+("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
+ --attach $PID $COMMAND_SUFFIX > $GDBSERVER_LOG 2>&1) &
+GDBSERVER_PID=$!
+echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE
+log "background job pid: $GDBSERVER_PID"
+
+# Check that it is still running after a few seconds. If not, this means we
+# could not properly attach to it
+sleep 2
+log "Job control: $(jobs -l)"
+STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }')
+if [ "$STATE" != "Running" ]; then
+  echo "ERROR: GDBServer could not attach to PID $PID!"
+  if [ $(adb_shell su -c getenforce) != "Permissive" ];  then
+    echo "Device mode is Enforcing. Changing Device mode to Permissive "
+    $(adb_shell su -c setenforce 0)
+    if [ $(adb_shell su -c getenforce) != "Permissive" ]; then
+      echo "ERROR: Failed to Change Device mode to Permissive"
+      echo "Failure log (use --verbose for more information):"
+      cat $GDBSERVER_LOG
+      exit 1
+    fi
+  else
+    echo "Failure log (use --verbose for more information):"
+    cat $GDBSERVER_LOG
+    exit 1
+  fi
+fi
+
+# Generate a file containing useful GDB initialization commands
+readonly COMMANDS=$TMPDIR/gdb.init
+log "Generating GDB initialization commands file: $COMMANDS"
+echo -n "" > $COMMANDS
+echo "set print pretty 1" >> $COMMANDS
+echo "python" >> $COMMANDS
+echo "import sys" >> $COMMANDS
+echo "sys.path.insert(0, '$CHROMIUM_SRC/tools/gdb/')" >> $COMMANDS
+echo "try:" >> $COMMANDS
+echo "  import gdb_chrome" >> $COMMANDS
+echo "finally:" >> $COMMANDS
+echo "  sys.path.pop(0)" >> $COMMANDS
+echo "end" >> $COMMANDS
+echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS
+echo "directory $CHROMIUM_SRC" >> $COMMANDS
+echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS
+echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \
+    >> $COMMANDS
+echo "echo Attaching and reading symbols, this may take a while.." \
+    >> $COMMANDS
+echo "target remote :$HOST_PORT" >> $COMMANDS
+
+if [ "$GDBINIT" ]; then
+  cat "$GDBINIT" >> $COMMANDS
+fi
+
+if [ "$VERBOSE" -gt 0 ]; then
+  echo "### START $COMMANDS"
+  cat $COMMANDS
+  echo "### END $COMMANDS"
+fi
+
+log "Launching gdb client: $GDB $GDB_ARGS -x $COMMANDS"
+$GDB $GDB_ARGS -x $COMMANDS &&
+rm -f "$GDBSERVER_PIDFILE"
diff --git a/build/android/adb_gdb_android_webview_shell b/build/android/adb_gdb_android_webview_shell
new file mode 100755
index 0000000..f685fda
--- /dev/null
+++ b/build/android/adb_gdb_android_webview_shell
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# 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.
+#
+# Attach to or start a ContentShell process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=.AwShellActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=AwShellApplication \
+    --package-name=org.chromium.android_webview.shell \
+    "$@"
diff --git a/build/android/adb_gdb_chrome_shell b/build/android/adb_gdb_chrome_shell
new file mode 100755
index 0000000..e5c8a30
--- /dev/null
+++ b/build/android/adb_gdb_chrome_shell
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Attach to or start a ChromeShell process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=.ChromeShellActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=ChromeShell \
+    --package-name=org.chromium.chrome.shell \
+    "$@"
diff --git a/build/android/adb_gdb_content_shell b/build/android/adb_gdb_content_shell
new file mode 100755
index 0000000..18e1a61
--- /dev/null
+++ b/build/android/adb_gdb_content_shell
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Attach to or start a ContentShell process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=.ContentShellActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=ContentShell \
+    --package-name=org.chromium.content_shell_apk \
+    "$@"
diff --git a/build/android/adb_gdb_cronet_sample b/build/android/adb_gdb_cronet_sample
new file mode 100755
index 0000000..8d0c864
--- /dev/null
+++ b/build/android/adb_gdb_cronet_sample
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Attach to or start a ContentShell process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=.CronetSampleActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=CronetSample \
+    --package-name=org.chromium.cronet_sample_apk \
+    "$@"
diff --git a/build/android/adb_gdb_mojo_shell b/build/android/adb_gdb_mojo_shell
new file mode 100755
index 0000000..ba91149
--- /dev/null
+++ b/build/android/adb_gdb_mojo_shell
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Attach to or start a ContentShell process and debug it.
+# See --help for details.
+#
+PROGDIR=$(dirname "$0")
+export ADB_GDB_PROGNAME=$(basename "$0")
+export ADB_GDB_ACTIVITY=.MojoShellActivity
+"$PROGDIR"/adb_gdb \
+    --program-name=MojoShell \
+    --package-name=org.chromium.mojo_shell_apk \
+    "$@"
diff --git a/build/android/adb_install_apk.py b/build/android/adb_install_apk.py
new file mode 100755
index 0000000..7bc634c
--- /dev/null
+++ b/build/android/adb_install_apk.py
@@ -0,0 +1,91 @@
+#!/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.
+
+"""Utility script to install APKs from the command line quickly."""
+
+import optparse
+import os
+import sys
+
+from pylib import constants
+from pylib.device import device_utils
+
+
+def AddInstallAPKOption(option_parser):
+  """Adds apk option used to install the APK to the OptionParser."""
+  option_parser.add_option('--apk',
+                           help=('DEPRECATED The name of the apk containing the'
+                                 ' application (with the .apk extension).'))
+  option_parser.add_option('--apk_package',
+                           help=('DEPRECATED The package name used by the apk '
+                                 'containing the application.'))
+  option_parser.add_option('--keep_data',
+                           action='store_true',
+                           default=False,
+                           help=('Keep the package data when installing '
+                                 'the application.'))
+  option_parser.add_option('--debug', action='store_const', const='Debug',
+                           dest='build_type',
+                           default=os.environ.get('BUILDTYPE', 'Debug'),
+                           help='If set, run test suites under out/Debug. '
+                           'Default is env var BUILDTYPE or Debug')
+  option_parser.add_option('--release', action='store_const', const='Release',
+                           dest='build_type',
+                           help='If set, run test suites under out/Release. '
+                           'Default is env var BUILDTYPE or Debug.')
+  option_parser.add_option('-d', '--device', dest='device',
+                           help='Target device for apk to install on.')
+
+
+def ValidateInstallAPKOption(option_parser, options, args):
+  """Validates the apk option and potentially qualifies the path."""
+  if not options.apk:
+    if len(args) > 1:
+      options.apk = args[1]
+    else:
+      option_parser.error('apk target not specified.')
+
+  if not options.apk.endswith('.apk'):
+    options.apk += '.apk'
+
+  if not os.path.exists(options.apk):
+    options.apk = os.path.join(constants.GetOutDirectory(), 'apks',
+                               options.apk)
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.set_usage("usage: %prog [options] target")
+  AddInstallAPKOption(parser)
+  options, args = parser.parse_args(argv)
+
+  if len(args) > 1 and options.apk:
+    parser.error("Appending the apk as argument can't be used with --apk.")
+  elif len(args) > 2:
+    parser.error("Too many arguments.")
+
+  constants.SetBuildType(options.build_type)
+  ValidateInstallAPKOption(parser, options, args)
+
+  devices = device_utils.DeviceUtils.HealthyDevices()
+
+  if options.device:
+    device_serials = [d.adb.GetDeviceSerial() for d in devices]
+    if options.device not in device_serials:
+      raise Exception('Error: %s not in attached devices %s' % (options.device,
+                      ','.join(device_serials)))
+    devices = [options.device]
+
+  if not devices:
+    raise Exception('Error: no connected devices')
+
+  device_utils.DeviceUtils.parallel(devices).Install(
+      options.apk, reinstall=options.keep_data)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
+
diff --git a/build/android/adb_kill_android_webview_shell b/build/android/adb_kill_android_webview_shell
new file mode 100755
index 0000000..5f287f0
--- /dev/null
+++ b/build/android/adb_kill_android_webview_shell
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Kill a running android webview shell.
+#
+# Assumes you have sourced the build/android/envsetup.sh script.
+
+SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.android_webview.shell')
+VAL=$(echo "$SHELL_PID_LINES" | wc -l)
+if [ $VAL -lt 1 ] ; then
+   echo "Not running android webview shell."
+else
+   SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}')
+   if [ "$SHELL_PID" != "" ] ; then
+      set -x
+      adb shell kill $SHELL_PID
+      set -
+   else
+     echo "Android webview shell does not appear to be running."
+   fi
+fi
diff --git a/build/android/adb_kill_chrome_shell b/build/android/adb_kill_chrome_shell
new file mode 100755
index 0000000..2b63c9a
--- /dev/null
+++ b/build/android/adb_kill_chrome_shell
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Kill a running chrome shell.
+#
+# Assumes you have sourced the build/android/envsetup.sh script.
+
+SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.chrome.shell')
+VAL=$(echo "$SHELL_PID_LINES" | wc -l)
+if [ $VAL -lt 1 ] ; then
+   echo "Not running Chrome shell."
+else
+   SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}')
+   if [ "$SHELL_PID" != "" ] ; then
+      set -x
+      adb shell kill $SHELL_PID
+      set -
+   else
+     echo "Chrome shell does not appear to be running."
+   fi
+fi
diff --git a/build/android/adb_kill_content_shell b/build/android/adb_kill_content_shell
new file mode 100755
index 0000000..e379dd4
--- /dev/null
+++ b/build/android/adb_kill_content_shell
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Kill a running content shell.
+#
+# Assumes you have sourced the build/android/envsetup.sh script.
+
+SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.content_shell_apk')
+VAL=$(echo "$SHELL_PID_LINES" | wc -l)
+if [ $VAL -lt 1 ] ; then
+   echo "Not running Content shell."
+else
+   SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}')
+   if [ "$SHELL_PID" != "" ] ; then
+      set -x
+      adb shell kill $SHELL_PID
+      set -
+   else
+     echo "Content shell does not appear to be running."
+   fi
+fi
diff --git a/build/android/adb_logcat_monitor.py b/build/android/adb_logcat_monitor.py
new file mode 100755
index 0000000..d3cc67d
--- /dev/null
+++ b/build/android/adb_logcat_monitor.py
@@ -0,0 +1,156 @@
+#!/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.
+
+"""Saves logcats from all connected devices.
+
+Usage: adb_logcat_monitor.py <base_dir> [<adb_binary_path>]
+
+This script will repeatedly poll adb for new devices and save logcats
+inside the <base_dir> directory, which it attempts to create.  The
+script will run until killed by an external signal.  To test, run the
+script in a shell and <Ctrl>-C it after a while.  It should be
+resilient across phone disconnects and reconnects and start the logcat
+early enough to not miss anything.
+"""
+
+import logging
+import os
+import re
+import shutil
+import signal
+import subprocess
+import sys
+import time
+
+# Map from device_id -> (process, logcat_num)
+devices = {}
+
+
+class TimeoutException(Exception):
+  """Exception used to signal a timeout."""
+  pass
+
+
+class SigtermError(Exception):
+  """Exception used to catch a sigterm."""
+  pass
+
+
+def StartLogcatIfNecessary(device_id, adb_cmd, base_dir):
+  """Spawns a adb logcat process if one is not currently running."""
+  process, logcat_num = devices[device_id]
+  if process:
+    if process.poll() is None:
+      # Logcat process is still happily running
+      return
+    else:
+      logging.info('Logcat for device %s has died', device_id)
+      error_filter = re.compile('- waiting for device -')
+      for line in process.stderr:
+        if not error_filter.match(line):
+          logging.error(device_id + ':   ' + line)
+
+  logging.info('Starting logcat %d for device %s', logcat_num,
+               device_id)
+  logcat_filename = 'logcat_%s_%03d' % (device_id, logcat_num)
+  logcat_file = open(os.path.join(base_dir, logcat_filename), 'w')
+  process = subprocess.Popen([adb_cmd, '-s', device_id,
+                              'logcat', '-v', 'threadtime'],
+                             stdout=logcat_file,
+                             stderr=subprocess.PIPE)
+  devices[device_id] = (process, logcat_num + 1)
+
+
+def GetAttachedDevices(adb_cmd):
+  """Gets the device list from adb.
+
+  We use an alarm in this function to avoid deadlocking from an external
+  dependency.
+
+  Args:
+    adb_cmd: binary to run adb
+
+  Returns:
+    list of devices or an empty list on timeout
+  """
+  signal.alarm(2)
+  try:
+    out, err = subprocess.Popen([adb_cmd, 'devices'],
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE).communicate()
+    if err:
+      logging.warning('adb device error %s', err.strip())
+    return re.findall('^(\\S+)\tdevice$', out, re.MULTILINE)
+  except TimeoutException:
+    logging.warning('"adb devices" command timed out')
+    return []
+  except (IOError, OSError):
+    logging.exception('Exception from "adb devices"')
+    return []
+  finally:
+    signal.alarm(0)
+
+
+def main(base_dir, adb_cmd='adb'):
+  """Monitor adb forever.  Expects a SIGINT (Ctrl-C) to kill."""
+  # We create the directory to ensure 'run once' semantics
+  if os.path.exists(base_dir):
+    print 'adb_logcat_monitor: %s already exists? Cleaning' % base_dir
+    shutil.rmtree(base_dir, ignore_errors=True)
+
+  os.makedirs(base_dir)
+  logging.basicConfig(filename=os.path.join(base_dir, 'eventlog'),
+                      level=logging.INFO,
+                      format='%(asctime)-2s %(levelname)-8s %(message)s')
+
+  # Set up the alarm for calling 'adb devices'. This is to ensure
+  # our script doesn't get stuck waiting for a process response
+  def TimeoutHandler(_signum, _unused_frame):
+    raise TimeoutException()
+  signal.signal(signal.SIGALRM, TimeoutHandler)
+
+  # Handle SIGTERMs to ensure clean shutdown
+  def SigtermHandler(_signum, _unused_frame):
+    raise SigtermError()
+  signal.signal(signal.SIGTERM, SigtermHandler)
+
+  logging.info('Started with pid %d', os.getpid())
+  pid_file_path = os.path.join(base_dir, 'LOGCAT_MONITOR_PID')
+
+  try:
+    with open(pid_file_path, 'w') as f:
+      f.write(str(os.getpid()))
+    while True:
+      for device_id in GetAttachedDevices(adb_cmd):
+        if not device_id in devices:
+          subprocess.call([adb_cmd, '-s', device_id, 'logcat', '-c'])
+          devices[device_id] = (None, 0)
+
+      for device in devices:
+        # This will spawn logcat watchers for any device ever detected
+        StartLogcatIfNecessary(device, adb_cmd, base_dir)
+
+      time.sleep(5)
+  except SigtermError:
+    logging.info('Received SIGTERM, shutting down')
+  except: # pylint: disable=bare-except
+    logging.exception('Unexpected exception in main.')
+  finally:
+    for process, _ in devices.itervalues():
+      if process:
+        try:
+          process.terminate()
+        except OSError:
+          pass
+    os.remove(pid_file_path)
+
+
+if __name__ == '__main__':
+  if 2 <= len(sys.argv) <= 3:
+    print 'adb_logcat_monitor: Initializing'
+    sys.exit(main(*sys.argv[1:3]))
+
+  print 'Usage: %s <base_dir> [<adb_binary_path>]' % sys.argv[0]
diff --git a/build/android/adb_logcat_printer.py b/build/android/adb_logcat_printer.py
new file mode 100755
index 0000000..55176ab
--- /dev/null
+++ b/build/android/adb_logcat_printer.py
@@ -0,0 +1,213 @@
+#!/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.
+
+"""Shutdown adb_logcat_monitor and print accumulated logs.
+
+To test, call './adb_logcat_printer.py <base_dir>' where
+<base_dir> contains 'adb logcat -v threadtime' files named as
+logcat_<deviceID>_<sequenceNum>
+
+The script will print the files to out, and will combine multiple
+logcats from a single device if there is overlap.
+
+Additionally, if a <base_dir>/LOGCAT_MONITOR_PID exists, the script
+will attempt to terminate the contained PID by sending a SIGINT and
+monitoring for the deletion of the aforementioned file.
+"""
+# pylint: disable=W0702
+
+import cStringIO
+import logging
+import optparse
+import os
+import re
+import signal
+import sys
+import time
+
+
+# Set this to debug for more verbose output
+LOG_LEVEL = logging.INFO
+
+
+def CombineLogFiles(list_of_lists, logger):
+  """Splices together multiple logcats from the same device.
+
+  Args:
+    list_of_lists: list of pairs (filename, list of timestamped lines)
+    logger: handler to log events
+
+  Returns:
+    list of lines with duplicates removed
+  """
+  cur_device_log = ['']
+  for cur_file, cur_file_lines in list_of_lists:
+    # Ignore files with just the logcat header
+    if len(cur_file_lines) < 2:
+      continue
+    common_index = 0
+    # Skip this step if list just has empty string
+    if len(cur_device_log) > 1:
+      try:
+        line = cur_device_log[-1]
+        # Used to make sure we only splice on a timestamped line
+        if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} ', line):
+          common_index = cur_file_lines.index(line)
+        else:
+          logger.warning('splice error - no timestamp in "%s"?', line.strip())
+      except ValueError:
+        # The last line was valid but wasn't found in the next file
+        cur_device_log += ['***** POSSIBLE INCOMPLETE LOGCAT *****']
+        logger.info('Unable to splice %s. Incomplete logcat?', cur_file)
+
+    cur_device_log += ['*'*30 + '  %s' % cur_file]
+    cur_device_log.extend(cur_file_lines[common_index:])
+
+  return cur_device_log
+
+
+def FindLogFiles(base_dir):
+  """Search a directory for logcat files.
+
+  Args:
+    base_dir: directory to search
+
+  Returns:
+    Mapping of device_id to a sorted list of file paths for a given device
+  """
+  logcat_filter = re.compile(r'^logcat_(\S+)_(\d+)$')
+  # list of tuples (<device_id>, <seq num>, <full file path>)
+  filtered_list = []
+  for cur_file in os.listdir(base_dir):
+    matcher = logcat_filter.match(cur_file)
+    if matcher:
+      filtered_list += [(matcher.group(1), int(matcher.group(2)),
+                         os.path.join(base_dir, cur_file))]
+  filtered_list.sort()
+  file_map = {}
+  for device_id, _, cur_file in filtered_list:
+    if device_id not in file_map:
+      file_map[device_id] = []
+
+    file_map[device_id] += [cur_file]
+  return file_map
+
+
+def GetDeviceLogs(log_filenames, logger):
+  """Read log files, combine and format.
+
+  Args:
+    log_filenames: mapping of device_id to sorted list of file paths
+    logger: logger handle for logging events
+
+  Returns:
+    list of formatted device logs, one for each device.
+  """
+  device_logs = []
+
+  for device, device_files in log_filenames.iteritems():
+    logger.debug('%s: %s', device, str(device_files))
+    device_file_lines = []
+    for cur_file in device_files:
+      with open(cur_file) as f:
+        device_file_lines += [(cur_file, f.read().splitlines())]
+    combined_lines = CombineLogFiles(device_file_lines, logger)
+    # Prepend each line with a short unique ID so it's easy to see
+    # when the device changes.  We don't use the start of the device
+    # ID because it can be the same among devices.  Example lines:
+    # AB324:  foo
+    # AB324:  blah
+    device_logs += [('\n' + device[-5:] + ':  ').join(combined_lines)]
+  return device_logs
+
+
+def ShutdownLogcatMonitor(base_dir, logger):
+  """Attempts to shutdown adb_logcat_monitor and blocks while waiting."""
+  try:
+    monitor_pid_path = os.path.join(base_dir, 'LOGCAT_MONITOR_PID')
+    with open(monitor_pid_path) as f:
+      monitor_pid = int(f.readline())
+
+    logger.info('Sending SIGTERM to %d', monitor_pid)
+    os.kill(monitor_pid, signal.SIGTERM)
+    i = 0
+    while True:
+      time.sleep(.2)
+      if not os.path.exists(monitor_pid_path):
+        return
+      if not os.path.exists('/proc/%d' % monitor_pid):
+        logger.warning('Monitor (pid %d) terminated uncleanly?', monitor_pid)
+        return
+      logger.info('Waiting for logcat process to terminate.')
+      i += 1
+      if i >= 10:
+        logger.warning('Monitor pid did not terminate. Continuing anyway.')
+        return
+
+  except (ValueError, IOError, OSError):
+    logger.exception('Error signaling logcat monitor - continuing')
+
+
+def main(argv):
+  parser = optparse.OptionParser(usage='Usage: %prog [options] <log dir>')
+  parser.add_option('--output-path',
+                    help='Output file path (if unspecified, prints to stdout)')
+  options, args = parser.parse_args(argv)
+  if len(args) != 1:
+    parser.error('Wrong number of unparsed args')
+  base_dir = args[0]
+  if options.output_path:
+    output_file = open(options.output_path, 'w')
+  else:
+    output_file = sys.stdout
+
+  log_stringio = cStringIO.StringIO()
+  logger = logging.getLogger('LogcatPrinter')
+  logger.setLevel(LOG_LEVEL)
+  sh = logging.StreamHandler(log_stringio)
+  sh.setFormatter(logging.Formatter('%(asctime)-2s %(levelname)-8s'
+                                    ' %(message)s'))
+  logger.addHandler(sh)
+
+  try:
+    # Wait at least 5 seconds after base_dir is created before printing.
+    #
+    # The idea is that 'adb logcat > file' output consists of 2 phases:
+    #  1 Dump all the saved logs to the file
+    #  2 Stream log messages as they are generated
+    #
+    # We want to give enough time for phase 1 to complete.  There's no
+    # good method to tell how long to wait, but it usually only takes a
+    # second.  On most bots, this code path won't occur at all, since
+    # adb_logcat_monitor.py command will have spawned more than 5 seconds
+    # prior to called this shell script.
+    try:
+      sleep_time = 5 - (time.time() - os.path.getctime(base_dir))
+    except OSError:
+      sleep_time = 5
+    if sleep_time > 0:
+      logger.warning('Monitor just started? Sleeping %.1fs', sleep_time)
+      time.sleep(sleep_time)
+
+    assert os.path.exists(base_dir), '%s does not exist' % base_dir
+    ShutdownLogcatMonitor(base_dir, logger)
+    separator = '\n' + '*' * 80 + '\n\n'
+    for log in GetDeviceLogs(FindLogFiles(base_dir), logger):
+      output_file.write(log)
+      output_file.write(separator)
+    with open(os.path.join(base_dir, 'eventlog')) as f:
+      output_file.write('\nLogcat Monitor Event Log\n')
+      output_file.write(f.read())
+  except:
+    logger.exception('Unexpected exception')
+
+  logger.info('Done.')
+  sh.flush()
+  output_file.write('\nLogcat Printer Event Log\n')
+  output_file.write(log_stringio.getvalue())
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/adb_profile_chrome b/build/android/adb_profile_chrome
new file mode 100755
index 0000000..21f6faf
--- /dev/null
+++ b/build/android/adb_profile_chrome
@@ -0,0 +1,8 @@
+#!/bin/bash
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Start / stop profiling in chrome.
+exec $(dirname $0)/../../tools/profile_chrome.py $@
diff --git a/build/android/adb_reverse_forwarder.py b/build/android/adb_reverse_forwarder.py
new file mode 100755
index 0000000..6cae0cf
--- /dev/null
+++ b/build/android/adb_reverse_forwarder.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Command line tool for forwarding ports from a device to the host.
+
+Allows an Android device to connect to services running on the host machine,
+i.e., "adb forward" in reverse. Requires |host_forwarder| and |device_forwarder|
+to be built.
+"""
+
+import logging
+import optparse
+import sys
+import time
+
+from pylib import constants
+from pylib import forwarder
+from pylib.device import adb_wrapper
+from pylib.device import device_utils
+from pylib.utils import run_tests_helper
+
+
+def main(argv):
+  parser = optparse.OptionParser(usage='Usage: %prog [options] device_port '
+                                 'host_port [device_port_2 host_port_2] ...',
+                                 description=__doc__)
+  parser.add_option('-v',
+                    '--verbose',
+                    dest='verbose_count',
+                    default=0,
+                    action='count',
+                    help='Verbose level (multiple times for more)')
+  parser.add_option('--device',
+                    help='Serial number of device we should use.')
+  parser.add_option('--debug', action='store_const', const='Debug',
+                    dest='build_type', default='Release',
+                    help='Use Debug build of host tools instead of Release.')
+
+  options, args = parser.parse_args(argv)
+  run_tests_helper.SetLogLevel(options.verbose_count)
+
+  if len(args) < 2 or not len(args) % 2:
+    parser.error('Need even number of port pairs')
+    sys.exit(1)
+
+  try:
+    port_pairs = map(int, args[1:])
+    port_pairs = zip(port_pairs[::2], port_pairs[1::2])
+  except ValueError:
+    parser.error('Bad port number')
+    sys.exit(1)
+
+  devices = device_utils.DeviceUtils.HealthyDevices()
+
+  if options.device:
+    if options.device not in [str(d) for d in devices]:
+      raise Exception('Error: %s not in attached devices %s' % (options.device,
+                      ','.join(devices)))
+    devices = [options.device]
+  else:
+    if not devices:
+      raise Exception('Error: no connected devices')
+    logging.info('No device specified. Defaulting to %s', devices[0])
+
+  device = devices[0]
+  constants.SetBuildType(options.build_type)
+  try:
+    forwarder.Forwarder.Map(port_pairs, device)
+    while True:
+      time.sleep(60)
+  except KeyboardInterrupt:
+    sys.exit(0)
+  finally:
+    forwarder.Forwarder.UnmapAllDevicePorts(device)
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/build/android/adb_run_android_webview_shell b/build/android/adb_run_android_webview_shell
new file mode 100755
index 0000000..1014a73
--- /dev/null
+++ b/build/android/adb_run_android_webview_shell
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# 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.
+
+optional_url=$1
+
+adb shell am start \
+  -a android.intent.action.VIEW \
+  -n org.chromium.android_webview.shell/.AwShellActivity \
+  ${optional_url:+-d "$optional_url"}
diff --git a/build/android/adb_run_chrome_shell b/build/android/adb_run_chrome_shell
new file mode 100755
index 0000000..79c4c32
--- /dev/null
+++ b/build/android/adb_run_chrome_shell
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+optional_url=$1
+
+adb shell am start \
+  -a android.intent.action.VIEW \
+  -n org.chromium.chrome.shell/.ChromeShellActivity \
+  ${optional_url:+-d "$optional_url"}
diff --git a/build/android/adb_run_content_shell b/build/android/adb_run_content_shell
new file mode 100755
index 0000000..3f01f3b
--- /dev/null
+++ b/build/android/adb_run_content_shell
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+optional_url=$1
+
+adb shell am start \
+  -a android.intent.action.VIEW \
+  -n org.chromium.content_shell_apk/.ContentShellActivity \
+  ${optional_url:+-d "$optional_url"}
diff --git a/build/android/adb_run_mojo_shell b/build/android/adb_run_mojo_shell
new file mode 100755
index 0000000..b585e4a
--- /dev/null
+++ b/build/android/adb_run_mojo_shell
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+optional_url=$1
+parameters=$2
+
+adb logcat -c
+adb shell am start -S \
+  -a android.intent.action.VIEW \
+  -n org.chromium.mojo_shell_apk/.MojoShellActivity \
+  ${parameters:+--esa parameters "$parameters"} \
+  ${optional_url:+-d "$optional_url"}
+adb logcat -s MojoShellApplication MojoShellActivity chromium
diff --git a/build/android/android_no_jni_exports.lst b/build/android/android_no_jni_exports.lst
new file mode 100644
index 0000000..ffc6cf7
--- /dev/null
+++ b/build/android/android_no_jni_exports.lst
@@ -0,0 +1,17 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script makes all JNI exported symbols local, to prevent the JVM from
+# being able to find them, enforcing use of manual JNI function registration.
+# This is used for all Android binaries by default, unless they explicitly state
+# that they want JNI exported symbols to remain visible, as we need to ensure
+# the manual registration path is correct to maintain compatibility with the
+# crazy linker.
+# Check ld version script manual:
+# https://sourceware.org/binutils/docs-2.24/ld/VERSION.html#VERSION
+
+{
+  local:
+    Java_*;
+};
diff --git a/build/android/ant/apk-package.xml b/build/android/ant/apk-package.xml
new file mode 100644
index 0000000..99279a4
--- /dev/null
+++ b/build/android/ant/apk-package.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (C) 2005-2008 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<project default="-package">
+  <property name="verbose" value="false" />
+  <property name="out.dir" location="${OUT_DIR}" />
+  <property name="out.absolute.dir" location="${out.dir}" />
+
+  <property name="sdk.dir" location="${ANDROID_SDK_ROOT}"/>
+  <property name="emma.device.jar" location="${EMMA_DEVICE_JAR}" />
+
+  <condition property="emma.enabled" value="true" else="false">
+    <equals arg1="${EMMA_INSTRUMENT}" arg2="1"/>
+  </condition>
+
+  <!-- jar file from where the tasks are loaded -->
+  <path id="android.antlibs">
+    <pathelement path="${sdk.dir}/tools/lib/ant-tasks.jar" />
+  </path>
+
+  <!-- Custom tasks -->
+  <taskdef resource="anttasks.properties" classpathref="android.antlibs" />
+
+  <condition property="build.target" value="release" else="debug">
+    <equals arg1="${CONFIGURATION_NAME}" arg2="Release" />
+  </condition>
+  <condition property="build.is.packaging.debug" value="true" else="false">
+    <equals arg1="${build.target}" arg2="debug" />
+  </condition>
+
+  <!-- Disables automatic signing. -->
+  <property name="build.is.signing.debug" value="false"/>
+
+  <!-- SDK tools assume that out.packaged.file is signed and name it "...-unaligned" -->
+  <property name="out.packaged.file" value="${UNSIGNED_APK_PATH}" />
+
+  <property name="native.libs.absolute.dir" location="${NATIVE_LIBS_DIR}" />
+
+  <!-- Intermediate files -->
+  <property name="resource.package.file.name" value="${RESOURCE_PACKAGED_APK_NAME}" />
+
+  <property name="intermediate.dex.file" location="${DEX_FILE_PATH}" />
+
+  <!-- Macro that enables passing a variable list of external jar files
+       to ApkBuilder. -->
+  <macrodef name="package-helper">
+    <element name="extra-jars" optional="yes" />
+    <sequential>
+      <apkbuilder
+          outfolder="${out.absolute.dir}"
+          resourcefile="${resource.package.file.name}"
+          apkfilepath="${out.packaged.file}"
+          debugpackaging="${build.is.packaging.debug}"
+          debugsigning="${build.is.signing.debug}"
+          verbose="${verbose}"
+          hascode="true"
+          previousBuildType="/"
+          buildType="${build.is.packaging.debug}/${build.is.signing.debug}">
+        <dex path="${intermediate.dex.file}"/>
+        <nativefolder path="${native.libs.absolute.dir}" />
+        <extra-jars/>
+      </apkbuilder>
+    </sequential>
+  </macrodef>
+
+
+  <!-- Packages the application. -->
+  <target name="-package">
+    <if condition="${emma.enabled}">
+      <then>
+        <package-helper>
+          <extra-jars>
+            <jarfile path="${emma.device.jar}" />
+          </extra-jars>
+        </package-helper>
+      </then>
+      <else>
+        <package-helper />
+      </else>
+    </if>
+  </target>
+</project>
diff --git a/build/android/ant/chromium-debug.keystore b/build/android/ant/chromium-debug.keystore
new file mode 100644
index 0000000..67eb0aa
--- /dev/null
+++ b/build/android/ant/chromium-debug.keystore
Binary files differ
diff --git a/build/android/ant/empty/res/.keep b/build/android/ant/empty/res/.keep
new file mode 100644
index 0000000..1fd038b
--- /dev/null
+++ b/build/android/ant/empty/res/.keep
@@ -0,0 +1,2 @@
+# This empty res folder can be passed to aapt while building Java libraries or
+# APKs that don't have any resources.
diff --git a/build/android/asan_symbolize.py b/build/android/asan_symbolize.py
new file mode 100755
index 0000000..10087a6
--- /dev/null
+++ b/build/android/asan_symbolize.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import collections
+import optparse
+import os
+import re
+import sys
+
+from pylib import constants
+
+# Uses symbol.py from third_party/android_platform, not python's.
+sys.path.insert(0,
+                os.path.join(constants.DIR_SOURCE_ROOT,
+                            'third_party/android_platform/development/scripts'))
+import symbol
+
+
+_RE_ASAN = re.compile(r'(.*?)(#\S*?) (\S*?) \((.*?)\+(.*?)\)')
+
+def _ParseAsanLogLine(line):
+  m = re.match(_RE_ASAN, line)
+  if not m:
+    return None
+  return {
+      'prefix': m.group(1),
+      'library': m.group(4),
+      'pos': m.group(2),
+      'rel_address': '%08x' % int(m.group(5), 16),
+  }
+
+
+def _FindASanLibraries():
+  asan_lib_dir = os.path.join(constants.DIR_SOURCE_ROOT,
+                              'third_party', 'llvm-build',
+                              'Release+Asserts', 'lib')
+  asan_libs = []
+  for src_dir, _, files in os.walk(asan_lib_dir):
+    asan_libs += [os.path.relpath(os.path.join(src_dir, f))
+                  for f in files
+                  if f.endswith('.so')]
+  return asan_libs
+
+
+def _TranslateLibPath(library, asan_libs):
+  for asan_lib in asan_libs:
+    if os.path.basename(library) == os.path.basename(asan_lib):
+      return '/' + asan_lib
+  return symbol.TranslateLibPath(library)
+
+
+def _Symbolize(asan_input):
+  asan_libs = _FindASanLibraries()
+  libraries = collections.defaultdict(list)
+  asan_lines = []
+  for asan_log_line in [a.rstrip() for a in asan_input]:
+    m = _ParseAsanLogLine(asan_log_line)
+    if m:
+      libraries[m['library']].append(m)
+    asan_lines.append({'raw_log': asan_log_line, 'parsed': m})
+
+  all_symbols = collections.defaultdict(dict)
+  for library, items in libraries.iteritems():
+    libname = _TranslateLibPath(library, asan_libs)
+    lib_relative_addrs = set([i['rel_address'] for i in items])
+    info_dict = symbol.SymbolInformationForSet(libname,
+                                               lib_relative_addrs,
+                                               True)
+    if info_dict:
+      all_symbols[library]['symbols'] = info_dict
+
+  for asan_log_line in asan_lines:
+    m = asan_log_line['parsed']
+    if not m:
+      print asan_log_line['raw_log']
+      continue
+    if (m['library'] in all_symbols and
+        m['rel_address'] in all_symbols[m['library']]['symbols']):
+      s = all_symbols[m['library']]['symbols'][m['rel_address']][0]
+      print '%s%s %s %s' % (m['prefix'], m['pos'], s[0], s[1])
+    else:
+      print asan_log_line['raw_log']
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('-l', '--logcat',
+                    help='File containing adb logcat output with ASan stacks. '
+                         'Use stdin if not specified.')
+  options, _ = parser.parse_args()
+  if options.logcat:
+    asan_input = file(options.logcat, 'r')
+  else:
+    asan_input = sys.stdin
+  _Symbolize(asan_input.readlines())
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/build/android/avd.py b/build/android/avd.py
new file mode 100755
index 0000000..c45544f
--- /dev/null
+++ b/build/android/avd.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+# 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.
+
+"""Launches Android Virtual Devices with a set configuration for testing Chrome.
+
+The script will launch a specified number of Android Virtual Devices (AVD's).
+"""
+
+
+import install_emulator_deps
+import logging
+import optparse
+import os
+import re
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.utils import emulator
+
+
+def main(argv):
+  # ANDROID_SDK_ROOT needs to be set to the location of the SDK used to launch
+  # the emulator to find the system images upon launch.
+  emulator_sdk = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk')
+  os.environ['ANDROID_SDK_ROOT'] = emulator_sdk
+
+  opt_parser = optparse.OptionParser(description='AVD script.')
+  opt_parser.add_option('--name', help='Optinaly, name of existing AVD to '
+                        'launch. If not specified, new AVD\'s will be created')
+  opt_parser.add_option('-n', '--num', dest='emulator_count',
+                        help='Number of emulators to launch (default is 1).',
+                        type='int', default='1')
+  opt_parser.add_option('--abi', default='x86',
+                        help='Platform of emulators to launch (x86 default).')
+  opt_parser.add_option('--api-level', dest='api_level',
+                        help='API level for the image, e.g. 19 for Android 4.4',
+                        type='int', default=constants.ANDROID_SDK_VERSION)
+
+  options, _ = opt_parser.parse_args(argv[1:])
+
+  logging.basicConfig(level=logging.INFO,
+                      format='# %(asctime)-15s: %(message)s')
+  logging.root.setLevel(logging.INFO)
+
+  # Check if KVM is enabled for x86 AVD's and check for x86 system images.
+  # TODO(andrewhayden) Since we can fix all of these with install_emulator_deps
+  # why don't we just run it?
+  if options.abi == 'x86':
+    if not install_emulator_deps.CheckKVM():
+      logging.critical('ERROR: KVM must be enabled in BIOS, and installed. '
+                       'Enable KVM in BIOS and run install_emulator_deps.py')
+      return 1
+    elif not install_emulator_deps.CheckX86Image(options.api_level):
+      logging.critical('ERROR: System image for x86 AVD not installed. Run '
+                       'install_emulator_deps.py')
+      return 1
+
+  if not install_emulator_deps.CheckSDK():
+    logging.critical('ERROR: Emulator SDK not installed. Run '
+                     'install_emulator_deps.py.')
+    return 1
+
+  # If AVD is specified, check that the SDK has the required target. If not,
+  # check that the SDK has the desired target for the temporary AVD's.
+  api_level = options.api_level
+  if options.name:
+    android = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk', 'tools',
+                           'android')
+    avds_output = cmd_helper.GetCmdOutput([android, 'list', 'avd'])
+    names = re.findall(r'Name: (\w+)', avds_output)
+    api_levels = re.findall(r'API level (\d+)', avds_output)
+    try:
+      avd_index = names.index(options.name)
+    except ValueError:
+      logging.critical('ERROR: Specified AVD %s does not exist.' % options.name)
+      return 1
+    api_level = int(api_levels[avd_index])
+
+  if not install_emulator_deps.CheckSDKPlatform(api_level):
+    logging.critical('ERROR: Emulator SDK missing required target for API %d. '
+                     'Run install_emulator_deps.py.')
+    return 1
+
+  if options.name:
+    emulator.LaunchEmulator(options.name, options.abi)
+  else:
+    emulator.LaunchTempEmulators(options.emulator_count, options.abi,
+                                 options.api_level, True)
+
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/bb_run_sharded_steps.py b/build/android/bb_run_sharded_steps.py
new file mode 100755
index 0000000..6aeba5b
--- /dev/null
+++ b/build/android/bb_run_sharded_steps.py
@@ -0,0 +1,41 @@
+#!/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.
+
+"""DEPRECATED!
+TODO(bulach): remove me once all other repositories reference
+'test_runner.py perf' directly.
+"""
+
+import optparse
+import sys
+
+from pylib import cmd_helper
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('-s', '--steps',
+                    help='A JSON file containing all the steps to be '
+                         'sharded.')
+  parser.add_option('--flaky_steps',
+                    help='A JSON file containing steps that are flaky and '
+                         'will have its exit code ignored.')
+  parser.add_option('-p', '--print_results',
+                    help='Only prints the results for the previously '
+                         'executed step, do not run it again.')
+  options, _ = parser.parse_args(argv)
+  if options.print_results:
+    return cmd_helper.RunCmd(['build/android/test_runner.py', 'perf',
+                              '--print-step', options.print_results])
+  flaky_options = []
+  if options.flaky_steps:
+    flaky_options = ['--flaky-steps', options.flaky_steps]
+  return cmd_helper.RunCmd(['build/android/test_runner.py', 'perf', '-v',
+                            '--steps', options.steps] + flaky_options)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/buildbot/OWNERS b/build/android/buildbot/OWNERS
new file mode 100644
index 0000000..f289720
--- /dev/null
+++ b/build/android/buildbot/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+cmp@chromium.org
+jbudorick@chromium.org
+navabi@chromium.org
+
diff --git a/build/android/buildbot/bb_annotations.py b/build/android/buildbot/bb_annotations.py
new file mode 100644
index 0000000..059d673
--- /dev/null
+++ b/build/android/buildbot/bb_annotations.py
@@ -0,0 +1,46 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper functions to print buildbot messages."""
+
+def PrintLink(label, url):
+  """Adds a link with name |label| linking to |url| to current buildbot step.
+
+  Args:
+    label: A string with the name of the label.
+    url: A string of the URL.
+  """
+  print '@@@STEP_LINK@%s@%s@@@' % (label, url)
+
+
+def PrintMsg(msg):
+  """Appends |msg| to the current buildbot step text.
+
+  Args:
+    msg: String to be appended.
+  """
+  print '@@@STEP_TEXT@%s@@@' % msg
+
+
+def PrintSummaryText(msg):
+  """Appends |msg| to main build summary. Visible from waterfall.
+
+  Args:
+    msg: String to be appended.
+  """
+  print '@@@STEP_SUMMARY_TEXT@%s@@@' % msg
+
+
+def PrintError():
+  """Marks the current step as failed."""
+  print '@@@STEP_FAILURE@@@'
+
+
+def PrintWarning():
+  """Marks the current step with a warning."""
+  print '@@@STEP_WARNINGS@@@'
+
+
+def PrintNamedStep(step):
+  print '@@@BUILD_STEP %s@@@' % step
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
new file mode 100755
index 0000000..8690a60
--- /dev/null
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -0,0 +1,412 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A class to keep track of devices across builds and report state."""
+import json
+import logging
+import optparse
+import os
+import psutil
+import re
+import signal
+import smtplib
+import subprocess
+import sys
+import time
+import urllib
+
+import bb_annotations
+import bb_utils
+
+sys.path.append(os.path.join(os.path.dirname(__file__),
+                             os.pardir, os.pardir, 'util', 'lib',
+                             'common'))
+import perf_tests_results_helper  # pylint: disable=F0401
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+from pylib import android_commands
+from pylib import constants
+from pylib.cmd_helper import GetCmdOutput
+from pylib.device import battery_utils
+from pylib.device import device_blacklist
+from pylib.device import device_errors
+from pylib.device import device_list
+from pylib.device import device_utils
+from pylib.utils import run_tests_helper
+
+_RE_DEVICE_ID = re.compile('Device ID = (\d+)')
+
+def DeviceInfo(serial, options):
+  """Gathers info on a device via various adb calls.
+
+  Args:
+    serial: The serial of the attached device to construct info about.
+
+  Returns:
+    Tuple of device type, build id, report as a string, error messages, and
+    boolean indicating whether or not device can be used for testing.
+  """
+  device = device_utils.DeviceUtils(serial)
+  battery = battery_utils.BatteryUtils(device)
+
+  battery_info = {}
+  battery_level = 100
+  errors = []
+  dev_good = True
+  json_data = {
+    'serial': serial,
+    'type': device.build_product,
+    'build': device.build_id,
+    'build_detail': device.GetProp('ro.build.fingerprint'),
+    'battery': {},
+    'imei_slice': 'Unknown',
+    'wifi_ip': device.GetProp('dhcp.wlan0.ipaddress'),
+  }
+
+  try:
+    try:
+      battery_info = battery.GetBatteryInfo(timeout=5)
+      battery_level = int(battery_info.get('level', battery_level))
+      json_data['battery'] = battery_info
+    except device_errors.CommandFailedError:
+      logging.exception('Failed to get battery information for %s', serial)
+
+    try:
+      for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'],
+                                      check_return=True, timeout=5):
+        m = _RE_DEVICE_ID.match(l)
+        if m:
+          json_data['imei_slice'] = m.group(1)[-6:]
+    except device_errors.CommandFailedError:
+      logging.exception('Failed to get IMEI slice for %s', serial)
+
+    if battery_level < 15:
+      errors += ['Device critically low in battery.']
+      dev_good = False
+      if not battery.GetCharging():
+        battery.SetCharging(True)
+    if not options.no_provisioning_check:
+      setup_wizard_disabled = (
+          device.GetProp('ro.setupwizard.mode') == 'DISABLED')
+      if not setup_wizard_disabled and device.build_type != 'user':
+        errors += ['Setup wizard not disabled. Was it provisioned correctly?']
+    if (device.product_name == 'mantaray' and
+        battery_info.get('AC powered', None) != 'true'):
+      errors += ['Mantaray device not connected to AC power.']
+  except device_errors.CommandFailedError:
+    logging.exception('Failure while getting device status.')
+    dev_good = False
+  except device_errors.CommandTimeoutError:
+    logging.exception('Timeout while getting device status.')
+    dev_good = False
+
+  return (device.build_product, device.build_id, battery_level, errors,
+          dev_good, json_data)
+
+
+def CheckForMissingDevices(options, adb_online_devs):
+  """Uses file of previous online devices to detect broken phones.
+
+  Args:
+    options: out_dir parameter of options argument is used as the base
+             directory to load and update the cache file.
+    adb_online_devs: A list of serial numbers of the currently visible
+                     and online attached devices.
+  """
+  out_dir = os.path.abspath(options.out_dir)
+
+  # last_devices denotes all known devices prior to this run
+  last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME)
+  last_missing_devices_path = os.path.join(out_dir,
+      device_list.LAST_MISSING_DEVICES_FILENAME)
+  try:
+    last_devices = device_list.GetPersistentDeviceList(last_devices_path)
+  except IOError:
+    # Ignore error, file might not exist
+    last_devices = []
+
+  try:
+    last_missing_devices = device_list.GetPersistentDeviceList(
+        last_missing_devices_path)
+  except IOError:
+    last_missing_devices = []
+
+  missing_devs = list(set(last_devices) - set(adb_online_devs))
+  new_missing_devs = list(set(missing_devs) - set(last_missing_devices))
+
+  if new_missing_devs and os.environ.get('BUILDBOT_SLAVENAME'):
+    logging.info('new_missing_devs %s' % new_missing_devs)
+    devices_missing_msg = '%d devices not detected.' % len(missing_devs)
+    bb_annotations.PrintSummaryText(devices_missing_msg)
+
+    from_address = 'chrome-bot@chromium.org'
+    to_addresses = ['chrome-labs-tech-ticket@google.com',
+                    'chrome-android-device-alert@google.com']
+    cc_addresses = ['chrome-android-device-alert@google.com']
+    subject = 'Devices offline on %s, %s, %s' % (
+      os.environ.get('BUILDBOT_SLAVENAME'),
+      os.environ.get('BUILDBOT_BUILDERNAME'),
+      os.environ.get('BUILDBOT_BUILDNUMBER'))
+    msg = ('Please reboot the following devices:\n%s' %
+           '\n'.join(map(str, new_missing_devs)))
+    SendEmail(from_address, to_addresses, cc_addresses, subject, msg)
+
+  all_known_devices = list(set(adb_online_devs) | set(last_devices))
+  device_list.WritePersistentDeviceList(last_devices_path, all_known_devices)
+  device_list.WritePersistentDeviceList(last_missing_devices_path, missing_devs)
+
+  if not all_known_devices:
+    # This can happen if for some reason the .last_devices file is not
+    # present or if it was empty.
+    return ['No online devices. Have any devices been plugged in?']
+  if missing_devs:
+    devices_missing_msg = '%d devices not detected.' % len(missing_devs)
+    bb_annotations.PrintSummaryText(devices_missing_msg)
+
+    # TODO(navabi): Debug by printing both output from GetCmdOutput and
+    # GetAttachedDevices to compare results.
+    crbug_link = ('https://code.google.com/p/chromium/issues/entry?summary='
+                  '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' %
+                  (urllib.quote('Device Offline'),
+                   urllib.quote('Buildbot: %s %s\n'
+                                'Build: %s\n'
+                                '(please don\'t change any labels)' %
+                                (os.environ.get('BUILDBOT_BUILDERNAME'),
+                                 os.environ.get('BUILDBOT_SLAVENAME'),
+                                 os.environ.get('BUILDBOT_BUILDNUMBER')))))
+    return ['Current online devices: %s' % adb_online_devs,
+            '%s are no longer visible. Were they removed?' % missing_devs,
+            'SHERIFF:',
+            '@@@STEP_LINK@Click here to file a bug@%s@@@' % crbug_link,
+            'Cache file: %s' % last_devices_path,
+            'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
+            'adb devices(GetAttachedDevices): %s' % adb_online_devs]
+  else:
+    new_devs = set(adb_online_devs) - set(last_devices)
+    if new_devs and os.path.exists(last_devices_path):
+      bb_annotations.PrintWarning()
+      bb_annotations.PrintSummaryText(
+          '%d new devices detected' % len(new_devs))
+      logging.info('New devices detected:')
+      for d in new_devs:
+        logging.info('  %s', d)
+
+
+def SendEmail(from_address, to_addresses, cc_addresses, subject, msg):
+  msg_body = '\r\n'.join(['From: %s' % from_address,
+                          'To: %s' % ', '.join(to_addresses),
+                          'CC: %s' % ', '.join(cc_addresses),
+                          'Subject: %s' % subject, '', msg])
+  try:
+    server = smtplib.SMTP('localhost')
+    server.sendmail(from_address, to_addresses, msg_body)
+    server.quit()
+  except Exception:
+    logging.exception('Failed to send alert email.')
+
+
+def RestartUsb():
+  if not os.path.isfile('/usr/bin/restart_usb'):
+    logging.error('Could not restart usb. ''/usr/bin/restart_usb not '
+                  'installed on host (see BUG=305769).')
+    return False
+
+  lsusb_proc = bb_utils.SpawnCmd(['lsusb'], stdout=subprocess.PIPE)
+  lsusb_output, _ = lsusb_proc.communicate()
+  if lsusb_proc.returncode:
+    logging.error('Could not get list of USB ports (i.e. lsusb).')
+    return lsusb_proc.returncode
+
+  usb_devices = [re.findall(r'Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0]
+                 for lsusb_line in lsusb_output.strip().split('\n')]
+
+  all_restarted = True
+  # Walk USB devices from leaves up (i.e reverse sorted) restarting the
+  # connection. If a parent node (e.g. usb hub) is restarted before the
+  # devices connected to it, the (bus, dev) for the hub can change, making the
+  # output we have wrong. This way we restart the devices before the hub.
+  for (bus, dev) in reversed(sorted(usb_devices)):
+    # Can not restart root usb connections
+    if dev != '001':
+      return_code = bb_utils.RunCmd(['/usr/bin/restart_usb', bus, dev])
+      if return_code:
+        logging.error('Error restarting USB device /dev/bus/usb/%s/%s',
+                      bus, dev)
+        all_restarted = False
+      else:
+        logging.info('Restarted USB device /dev/bus/usb/%s/%s', bus, dev)
+
+  return all_restarted
+
+
+def KillAllAdb():
+  def GetAllAdb():
+    for p in psutil.process_iter():
+      try:
+        if 'adb' in p.name:
+          yield p
+      except (psutil.NoSuchProcess, psutil.AccessDenied):
+        pass
+
+  for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]:
+    for p in GetAllAdb():
+      try:
+        logging.info('kill %d %d (%s [%s])', sig, p.pid, p.name,
+                     ' '.join(p.cmdline))
+        p.send_signal(sig)
+      except (psutil.NoSuchProcess, psutil.AccessDenied):
+        pass
+  for p in GetAllAdb():
+    try:
+      logging.error('Unable to kill %d (%s [%s])', p.pid, p.name,
+                    ' '.join(p.cmdline))
+    except (psutil.NoSuchProcess, psutil.AccessDenied):
+      pass
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('', '--out-dir',
+                    help='Directory where the device path is stored',
+                    default=os.path.join(constants.DIR_SOURCE_ROOT, 'out'))
+  parser.add_option('--no-provisioning-check', action='store_true',
+                    help='Will not check if devices are provisioned properly.')
+  parser.add_option('--device-status-dashboard', action='store_true',
+                    help='Output device status data for dashboard.')
+  parser.add_option('--restart-usb', action='store_true',
+                    help='Restart USB ports before running device check.')
+  parser.add_option('--json-output',
+                    help='Output JSON information into a specified file.')
+  parser.add_option('-v', '--verbose', action='count', default=1,
+                    help='Log more information.')
+
+  options, args = parser.parse_args()
+  if args:
+    parser.error('Unknown options %s' % args)
+
+  run_tests_helper.SetLogLevel(options.verbose)
+
+  # Remove the last build's "bad devices" before checking device statuses.
+  device_blacklist.ResetBlacklist()
+
+  try:
+    expected_devices = device_list.GetPersistentDeviceList(
+        os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME))
+  except IOError:
+    expected_devices = []
+  devices = android_commands.GetAttachedDevices()
+  # Only restart usb if devices are missing.
+  if set(expected_devices) != set(devices):
+    logging.warning('expected_devices: %s', expected_devices)
+    logging.warning('devices: %s', devices)
+    KillAllAdb()
+    retries = 5
+    usb_restarted = True
+    if options.restart_usb:
+      if not RestartUsb():
+        usb_restarted = False
+        bb_annotations.PrintWarning()
+        logging.error('USB reset stage failed, '
+                      'wait for any device to come back.')
+    while retries:
+      logging.info('retry adb devices...')
+      time.sleep(1)
+      devices = android_commands.GetAttachedDevices()
+      if set(expected_devices) == set(devices):
+        # All devices are online, keep going.
+        break
+      if not usb_restarted and devices:
+        # The USB wasn't restarted, but there's at least one device online.
+        # No point in trying to wait for all devices.
+        break
+      retries -= 1
+
+  # TODO(navabi): Test to make sure this fails and then fix call
+  offline_devices = android_commands.GetAttachedDevices(
+      hardware=False, emulator=False, offline=True)
+
+  types, builds, batteries, errors, devices_ok, json_data = (
+      [], [], [], [], [], [])
+  if devices:
+    types, builds, batteries, errors, devices_ok, json_data = (
+        zip(*[DeviceInfo(dev, options) for dev in devices]))
+
+  # Write device info to file for buildbot info display.
+  if os.path.exists('/home/chrome-bot'):
+    with open('/home/chrome-bot/.adb_device_info', 'w') as f:
+      for device in json_data:
+        try:
+          f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'],
+              device['build'], float(device['battery']['temperature']) / 10,
+              device['battery']['level']))
+        except Exception:
+          pass
+
+  err_msg = CheckForMissingDevices(options, devices) or []
+
+  unique_types = list(set(types))
+  unique_builds = list(set(builds))
+
+  bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s'
+                           % (len(devices), unique_types, unique_builds))
+
+  for j in json_data:
+    logging.info('Device %s (%s)', j.get('serial'), j.get('type'))
+    logging.info('  Build: %s (%s)', j.get('build'), j.get('build_detail'))
+    logging.info('  Current Battery Service state:')
+    for k, v in j.get('battery', {}).iteritems():
+      logging.info('    %s: %s', k, v)
+    logging.info('  IMEI slice: %s', j.get('imei_slice'))
+    logging.info('  WiFi IP: %s', j.get('wifi_ip'))
+
+
+  for serial, dev_errors in zip(devices, errors):
+    if dev_errors:
+      err_msg += ['%s errors:' % serial]
+      err_msg += ['    %s' % error for error in dev_errors]
+
+  if err_msg:
+    bb_annotations.PrintWarning()
+    for e in err_msg:
+      logging.error(e)
+    from_address = 'buildbot@chromium.org'
+    to_addresses = ['chromium-android-device-alerts@google.com']
+    bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
+    slave_name = os.environ.get('BUILDBOT_SLAVENAME')
+    subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name)
+    SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg))
+
+  if options.device_status_dashboard:
+    perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices',
+                                              [len(devices)], 'devices')
+    perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices',
+                                              [len(offline_devices)], 'devices',
+                                              'unimportant')
+    for serial, battery in zip(devices, batteries):
+      perf_tests_results_helper.PrintPerfResult('DeviceBattery', serial,
+                                                [battery], '%',
+                                                'unimportant')
+
+  if options.json_output:
+    with open(options.json_output, 'wb') as f:
+      f.write(json.dumps(json_data, indent=4))
+
+  num_failed_devs = 0
+  for device_ok, device in zip(devices_ok, devices):
+    if not device_ok:
+      logging.warning('Blacklisting %s', str(device))
+      device_blacklist.ExtendBlacklist([str(device)])
+      num_failed_devs += 1
+
+  if num_failed_devs == len(devices):
+    return 2
+
+  if not devices:
+    return 1
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
new file mode 100755
index 0000000..d7975a3
--- /dev/null
+++ b/build/android/buildbot/bb_device_steps.py
@@ -0,0 +1,774 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import glob
+import hashlib
+import json
+import os
+import random
+import re
+import shutil
+import sys
+
+import bb_utils
+import bb_annotations
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import provision_devices
+from pylib import android_commands
+from pylib import constants
+from pylib.device import device_utils
+from pylib.gtest import gtest_config
+
+CHROME_SRC_DIR = bb_utils.CHROME_SRC
+DIR_BUILD_ROOT = os.path.dirname(CHROME_SRC_DIR)
+CHROME_OUT_DIR = bb_utils.CHROME_OUT_DIR
+BLINK_SCRIPTS_DIR = 'third_party/WebKit/Tools/Scripts'
+
+SLAVE_SCRIPTS_DIR = os.path.join(bb_utils.BB_BUILD_DIR, 'scripts', 'slave')
+LOGCAT_DIR = os.path.join(bb_utils.CHROME_OUT_DIR, 'logcat')
+GS_URL = 'https://storage.googleapis.com'
+GS_AUTH_URL = 'https://storage.cloud.google.com'
+
+# Describes an instrumation test suite:
+#   test: Name of test we're running.
+#   apk: apk to be installed.
+#   apk_package: package for the apk to be installed.
+#   test_apk: apk to run tests on.
+#   test_data: data folder in format destination:source.
+#   host_driven_root: The host-driven test root directory.
+#   annotation: Annotation of the tests to include.
+#   exclude_annotation: The annotation of the tests to exclude.
+I_TEST = collections.namedtuple('InstrumentationTest', [
+    'name', 'apk', 'apk_package', 'test_apk', 'test_data', 'isolate_file_path',
+    'host_driven_root', 'annotation', 'exclude_annotation', 'extra_flags'])
+
+
+def SrcPath(*path):
+  return os.path.join(CHROME_SRC_DIR, *path)
+
+
+def I(name, apk, apk_package, test_apk, test_data, isolate_file_path=None,
+      host_driven_root=None, annotation=None, exclude_annotation=None,
+      extra_flags=None):
+  return I_TEST(name, apk, apk_package, test_apk, test_data, isolate_file_path,
+                host_driven_root, annotation, exclude_annotation, extra_flags)
+
+INSTRUMENTATION_TESTS = dict((suite.name, suite) for suite in [
+    I('ContentShell',
+      'ContentShell.apk',
+      'org.chromium.content_shell_apk',
+      'ContentShellTest',
+      'content:content/test/data/android/device_files',
+      isolate_file_path='content/content_shell_test_apk.isolate'),
+    I('ChromeShell',
+      'ChromeShell.apk',
+      'org.chromium.chrome.shell',
+      'ChromeShellTest',
+      'chrome:chrome/test/data/android/device_files',
+      isolate_file_path='chrome/chrome_shell_test_apk.isolate',
+      host_driven_root=constants.CHROME_SHELL_HOST_DRIVEN_DIR),
+    I('AndroidWebView',
+      'AndroidWebView.apk',
+      'org.chromium.android_webview.shell',
+      'AndroidWebViewTest',
+      'webview:android_webview/test/data/device_files',
+      isolate_file_path='android_webview/android_webview_test_apk.isolate'),
+    I('ChromeSyncShell',
+      'ChromeSyncShell.apk',
+      'org.chromium.chrome.browser.sync',
+      'ChromeSyncShellTest',
+      None),
+    ])
+
+InstallablePackage = collections.namedtuple('InstallablePackage', [
+    'name', 'apk', 'apk_package'])
+
+INSTALLABLE_PACKAGES = dict((package.name, package) for package in (
+    [InstallablePackage(i.name, i.apk, i.apk_package)
+     for i in INSTRUMENTATION_TESTS.itervalues()] +
+    [InstallablePackage('ChromeDriverWebViewShell',
+                        'ChromeDriverWebViewShell.apk',
+                        'org.chromium.chromedriver_webview_shell')]))
+
+VALID_TESTS = set(['chromedriver', 'chrome_proxy', 'components_browsertests',
+                   'gpu', 'python_unittests', 'telemetry_unittests',
+                   'telemetry_perf_unittests', 'ui', 'unit', 'webkit',
+                   'webkit_layout'])
+
+RunCmd = bb_utils.RunCmd
+
+
+def _GetRevision(options):
+  """Get the SVN revision number.
+
+  Args:
+    options: options object.
+
+  Returns:
+    The revision number.
+  """
+  revision = options.build_properties.get('got_revision')
+  if not revision:
+    revision = options.build_properties.get('revision', 'testing')
+  return revision
+
+
+def _RunTest(options, cmd, suite):
+  """Run test command with runtest.py.
+
+  Args:
+    options: options object.
+    cmd: the command to run.
+    suite: test name.
+  """
+  property_args = bb_utils.EncodeProperties(options)
+  args = [os.path.join(SLAVE_SCRIPTS_DIR, 'runtest.py')] + property_args
+  args += ['--test-platform', 'android']
+  if options.factory_properties.get('generate_gtest_json'):
+    args.append('--generate-json-file')
+    args += ['-o', 'gtest-results/%s' % suite,
+             '--annotate', 'gtest',
+             '--build-number', str(options.build_properties.get('buildnumber',
+                                                                '')),
+             '--builder-name', options.build_properties.get('buildername', '')]
+  if options.target == 'Release':
+    args += ['--target', 'Release']
+  else:
+    args += ['--target', 'Debug']
+  if options.flakiness_server:
+    args += ['--flakiness-dashboard-server=%s' %
+                options.flakiness_server]
+  args += cmd
+  RunCmd(args, cwd=DIR_BUILD_ROOT)
+
+
+def RunTestSuites(options, suites, suites_options=None):
+  """Manages an invocation of test_runner.py for gtests.
+
+  Args:
+    options: options object.
+    suites: List of suite names to run.
+    suites_options: Command line options dictionary for particular suites.
+                    For example,
+                    {'content_browsertests', ['--num_retries=1', '--release']}
+                    will add the options only to content_browsertests.
+  """
+
+  if not suites_options:
+    suites_options = {}
+
+  args = ['--verbose']
+  if options.target == 'Release':
+    args.append('--release')
+  if options.asan:
+    args.append('--tool=asan')
+  if options.gtest_filter:
+    args.append('--gtest-filter=%s' % options.gtest_filter)
+
+  for suite in suites:
+    bb_annotations.PrintNamedStep(suite)
+    cmd = [suite] + args
+    cmd += suites_options.get(suite, [])
+    if suite == 'content_browsertests' or suite == 'components_browsertests':
+      cmd.append('--num_retries=1')
+    _RunTest(options, cmd, suite)
+
+
+def RunChromeDriverTests(options):
+  """Run all the steps for running chromedriver tests."""
+  bb_annotations.PrintNamedStep('chromedriver_annotation')
+  RunCmd(['chrome/test/chromedriver/run_buildbot_steps.py',
+          '--android-packages=%s,%s,%s,%s' %
+          ('chrome_shell',
+           'chrome_stable',
+           'chrome_beta',
+           'chromedriver_webview_shell'),
+          '--revision=%s' % _GetRevision(options),
+          '--update-log'])
+
+def RunChromeProxyTests(options):
+  """Run the chrome_proxy tests.
+
+  Args:
+    options: options object.
+  """
+  InstallApk(options, INSTRUMENTATION_TESTS['ChromeShell'], False)
+  args = ['--browser', 'android-chrome-shell']
+  devices = android_commands.GetAttachedDevices()
+  if devices:
+    args = args + ['--device', devices[0]]
+  bb_annotations.PrintNamedStep('chrome_proxy')
+  RunCmd(['tools/chrome_proxy/run_tests'] + args)
+
+
+def RunTelemetryTests(options, step_name, run_tests_path):
+  """Runs either telemetry_perf_unittests or telemetry_unittests.
+
+  Args:
+    options: options object.
+    step_name: either 'telemetry_unittests' or 'telemetry_perf_unittests'
+    run_tests_path: path to run_tests script (tools/perf/run_tests for
+                    perf_unittests and tools/telemetry/run_tests for
+                    telemetry_unittests)
+  """
+  InstallApk(options, INSTRUMENTATION_TESTS['ChromeShell'], False)
+  args = ['--browser', 'android-chrome-shell']
+  devices = android_commands.GetAttachedDevices()
+  if devices:
+    args = args + ['--device', 'android']
+  bb_annotations.PrintNamedStep(step_name)
+  RunCmd([run_tests_path] + args)
+
+
+def InstallApk(options, test, print_step=False):
+  """Install an apk to all phones.
+
+  Args:
+    options: options object
+    test: An I_TEST namedtuple
+    print_step: Print a buildbot step
+  """
+  if print_step:
+    bb_annotations.PrintNamedStep('install_%s' % test.name.lower())
+
+  args = ['--apk_package', test.apk_package]
+  if options.target == 'Release':
+    args.append('--release')
+  args.append(test.apk)
+
+  RunCmd(['build/android/adb_install_apk.py'] + args, halt_on_failure=True)
+
+
+def RunInstrumentationSuite(options, test, flunk_on_failure=True,
+                            python_only=False, official_build=False):
+  """Manages an invocation of test_runner.py for instrumentation tests.
+
+  Args:
+    options: options object
+    test: An I_TEST namedtuple
+    flunk_on_failure: Flunk the step if tests fail.
+    Python: Run only host driven Python tests.
+    official_build: Run official-build tests.
+  """
+  bb_annotations.PrintNamedStep('%s_instrumentation_tests' % test.name.lower())
+
+  if test.apk:
+    InstallApk(options, test)
+  args = ['--test-apk', test.test_apk, '--verbose']
+  if test.test_data:
+    args.extend(['--test_data', test.test_data])
+  if options.target == 'Release':
+    args.append('--release')
+  if options.asan:
+    args.append('--tool=asan')
+  if options.flakiness_server:
+    args.append('--flakiness-dashboard-server=%s' %
+                options.flakiness_server)
+  if options.coverage_bucket:
+    args.append('--coverage-dir=%s' % options.coverage_dir)
+  if test.isolate_file_path:
+    args.append('--isolate-file-path=%s' % test.isolate_file_path)
+  if test.host_driven_root:
+    args.append('--host-driven-root=%s' % test.host_driven_root)
+  if test.annotation:
+    args.extend(['-A', test.annotation])
+  if test.exclude_annotation:
+    args.extend(['-E', test.exclude_annotation])
+  if test.extra_flags:
+    args.extend(test.extra_flags)
+  if python_only:
+    args.append('-p')
+  if official_build:
+    # The option needs to be assigned 'True' as it does not have an action
+    # associated with it.
+    args.append('--official-build')
+
+  RunCmd(['build/android/test_runner.py', 'instrumentation'] + args,
+         flunk_on_failure=flunk_on_failure)
+
+
+def RunWebkitLint():
+  """Lint WebKit's TestExpectation files."""
+  bb_annotations.PrintNamedStep('webkit_lint')
+  RunCmd([SrcPath(os.path.join(BLINK_SCRIPTS_DIR, 'lint-test-expectations'))])
+
+
+def RunWebkitLayoutTests(options):
+  """Run layout tests on an actual device."""
+  bb_annotations.PrintNamedStep('webkit_tests')
+  cmd_args = [
+      '--no-show-results',
+      '--no-new-test-results',
+      '--full-results-html',
+      '--clobber-old-results',
+      '--exit-after-n-failures', '5000',
+      '--exit-after-n-crashes-or-timeouts', '100',
+      '--debug-rwt-logging',
+      '--results-directory', '../layout-test-results',
+      '--target', options.target,
+      '--builder-name', options.build_properties.get('buildername', ''),
+      '--build-number', str(options.build_properties.get('buildnumber', '')),
+      '--master-name', 'ChromiumWebkit',  # TODO: Get this from the cfg.
+      '--build-name', options.build_properties.get('buildername', ''),
+      '--platform=android']
+
+  for flag in 'test_results_server', 'driver_name', 'additional_driver_flag':
+    if flag in options.factory_properties:
+      cmd_args.extend(['--%s' % flag.replace('_', '-'),
+                       options.factory_properties.get(flag)])
+
+  for f in options.factory_properties.get('additional_expectations', []):
+    cmd_args.extend(
+        ['--additional-expectations=%s' % os.path.join(CHROME_SRC_DIR, *f)])
+
+  # TODO(dpranke): Remove this block after
+  # https://codereview.chromium.org/12927002/ lands.
+  for f in options.factory_properties.get('additional_expectations_files', []):
+    cmd_args.extend(
+        ['--additional-expectations=%s' % os.path.join(CHROME_SRC_DIR, *f)])
+
+  exit_code = RunCmd(
+      [SrcPath(os.path.join(BLINK_SCRIPTS_DIR, 'run-webkit-tests'))] + cmd_args)
+  if exit_code == 255: # test_run_results.UNEXPECTED_ERROR_EXIT_STATUS
+    bb_annotations.PrintMsg('?? (crashed or hung)')
+  elif exit_code == 254: # test_run_results.NO_DEVICES_EXIT_STATUS
+    bb_annotations.PrintMsg('?? (no devices found)')
+  elif exit_code == 253: # test_run_results.NO_TESTS_EXIT_STATUS
+    bb_annotations.PrintMsg('?? (no tests found)')
+  else:
+    full_results_path = os.path.join('..', 'layout-test-results',
+                                     'full_results.json')
+    if os.path.exists(full_results_path):
+      full_results = json.load(open(full_results_path))
+      unexpected_passes, unexpected_failures, unexpected_flakes = (
+          _ParseLayoutTestResults(full_results))
+      if unexpected_failures:
+        _PrintDashboardLink('failed', unexpected_failures.keys(),
+                            max_tests=25)
+      elif unexpected_passes:
+        _PrintDashboardLink('unexpected passes', unexpected_passes.keys(),
+                            max_tests=10)
+      if unexpected_flakes:
+        _PrintDashboardLink('unexpected flakes', unexpected_flakes.keys(),
+                            max_tests=10)
+
+      if exit_code == 0 and (unexpected_passes or unexpected_flakes):
+        # If exit_code != 0, RunCmd() will have already printed an error.
+        bb_annotations.PrintWarning()
+    else:
+      bb_annotations.PrintError()
+      bb_annotations.PrintMsg('?? (results missing)')
+
+  if options.factory_properties.get('archive_webkit_results', False):
+    bb_annotations.PrintNamedStep('archive_webkit_results')
+    base = 'https://storage.googleapis.com/chromium-layout-test-archives'
+    builder_name = options.build_properties.get('buildername', '')
+    build_number = str(options.build_properties.get('buildnumber', ''))
+    results_link = '%s/%s/%s/layout-test-results/results.html' % (
+        base, EscapeBuilderName(builder_name), build_number)
+    bb_annotations.PrintLink('results', results_link)
+    bb_annotations.PrintLink('(zip)', '%s/%s/%s/layout-test-results.zip' % (
+        base, EscapeBuilderName(builder_name), build_number))
+    gs_bucket = 'gs://chromium-layout-test-archives'
+    RunCmd([os.path.join(SLAVE_SCRIPTS_DIR, 'chromium',
+                         'archive_layout_test_results.py'),
+            '--results-dir', '../../layout-test-results',
+            '--build-number', build_number,
+            '--builder-name', builder_name,
+            '--gs-bucket', gs_bucket],
+            cwd=DIR_BUILD_ROOT)
+
+
+def _ParseLayoutTestResults(results):
+  """Extract the failures from the test run."""
+  # Cloned from third_party/WebKit/Tools/Scripts/print-json-test-results
+  tests = _ConvertTrieToFlatPaths(results['tests'])
+  failures = {}
+  flakes = {}
+  passes = {}
+  for (test, result) in tests.iteritems():
+    if result.get('is_unexpected'):
+      actual_results = result['actual'].split()
+      expected_results = result['expected'].split()
+      if len(actual_results) > 1:
+        # We report the first failure type back, even if the second
+        # was more severe.
+        if actual_results[1] in expected_results:
+          flakes[test] = actual_results[0]
+        else:
+          failures[test] = actual_results[0]
+      elif actual_results[0] == 'PASS':
+        passes[test] = result
+      else:
+        failures[test] = actual_results[0]
+
+  return (passes, failures, flakes)
+
+
+def _ConvertTrieToFlatPaths(trie, prefix=None):
+  """Flatten the trie of failures into a list."""
+  # Cloned from third_party/WebKit/Tools/Scripts/print-json-test-results
+  result = {}
+  for name, data in trie.iteritems():
+    if prefix:
+      name = prefix + '/' + name
+
+    if len(data) and 'actual' not in data and 'expected' not in data:
+      result.update(_ConvertTrieToFlatPaths(data, name))
+    else:
+      result[name] = data
+
+  return result
+
+
+def _PrintDashboardLink(link_text, tests, max_tests):
+  """Add a link to the flakiness dashboard in the step annotations."""
+  if len(tests) > max_tests:
+    test_list_text = ' '.join(tests[:max_tests]) + ' and more'
+  else:
+    test_list_text = ' '.join(tests)
+
+  dashboard_base = ('http://test-results.appspot.com'
+                    '/dashboards/flakiness_dashboard.html#'
+                    'master=ChromiumWebkit&tests=')
+
+  bb_annotations.PrintLink('%d %s: %s' %
+                           (len(tests), link_text, test_list_text),
+                           dashboard_base + ','.join(tests))
+
+
+def EscapeBuilderName(builder_name):
+  return re.sub('[ ()]', '_', builder_name)
+
+
+def SpawnLogcatMonitor():
+  shutil.rmtree(LOGCAT_DIR, ignore_errors=True)
+  bb_utils.SpawnCmd([
+      os.path.join(CHROME_SRC_DIR, 'build', 'android', 'adb_logcat_monitor.py'),
+      LOGCAT_DIR])
+
+  # Wait for logcat_monitor to pull existing logcat
+  RunCmd(['sleep', '5'])
+
+
+def ProvisionDevices(options):
+  bb_annotations.PrintNamedStep('provision_devices')
+
+  if not bb_utils.TESTING:
+    # Restart adb to work around bugs, sleep to wait for usb discovery.
+    device_utils.RestartServer()
+    RunCmd(['sleep', '1'])
+  provision_cmd = ['build/android/provision_devices.py', '-t', options.target]
+  if options.auto_reconnect:
+    provision_cmd.append('--auto-reconnect')
+  if options.skip_wipe:
+    provision_cmd.append('--skip-wipe')
+  if options.disable_location:
+    provision_cmd.append('--disable-location')
+  RunCmd(provision_cmd, halt_on_failure=True)
+
+
+def DeviceStatusCheck(options):
+  bb_annotations.PrintNamedStep('device_status_check')
+  cmd = ['build/android/buildbot/bb_device_status_check.py']
+  if options.restart_usb:
+    cmd.append('--restart-usb')
+  RunCmd(cmd, halt_on_failure=True)
+
+
+def GetDeviceSetupStepCmds():
+  return [
+      ('device_status_check', DeviceStatusCheck),
+      ('provision_devices', ProvisionDevices),
+  ]
+
+
+def RunUnitTests(options):
+  suites = gtest_config.STABLE_TEST_SUITES
+  if options.asan:
+    suites = [s for s in suites
+              if s not in gtest_config.ASAN_EXCLUDED_TEST_SUITES]
+  RunTestSuites(options, suites)
+
+
+def RunTelemetryUnitTests(options):
+  RunTelemetryTests(options, 'telemetry_unittests', 'tools/telemetry/run_tests')
+
+
+def RunTelemetryPerfUnitTests(options):
+  RunTelemetryTests(options, 'telemetry_perf_unittests', 'tools/perf/run_tests')
+
+
+def RunInstrumentationTests(options):
+  for test in INSTRUMENTATION_TESTS.itervalues():
+    RunInstrumentationSuite(options, test)
+
+
+def RunWebkitTests(options):
+  RunTestSuites(options, ['webkit_unit_tests', 'blink_heap_unittests'])
+  RunWebkitLint()
+
+
+def RunGPUTests(options):
+  revision = _GetRevision(options)
+  builder_name = options.build_properties.get('buildername', 'noname')
+
+  bb_annotations.PrintNamedStep('pixel_tests')
+  RunCmd(['content/test/gpu/run_gpu_test.py',
+          'pixel',
+          '--browser',
+          'android-content-shell',
+          '--build-revision',
+          str(revision),
+          '--upload-refimg-to-cloud-storage',
+          '--refimg-cloud-storage-bucket',
+          'chromium-gpu-archive/reference-images',
+          '--os-type',
+          'android',
+          '--test-machine-name',
+          EscapeBuilderName(builder_name)])
+
+  bb_annotations.PrintNamedStep('webgl_conformance_tests')
+  RunCmd(['content/test/gpu/run_gpu_test.py',
+          '--browser=android-content-shell', 'webgl_conformance',
+          '--webgl-conformance-version=1.0.1'])
+
+  bb_annotations.PrintNamedStep('android_webview_webgl_conformance_tests')
+  RunCmd(['content/test/gpu/run_gpu_test.py',
+          '--browser=android-webview-shell', 'webgl_conformance',
+          '--webgl-conformance-version=1.0.1'])
+
+  bb_annotations.PrintNamedStep('gpu_rasterization_tests')
+  RunCmd(['content/test/gpu/run_gpu_test.py',
+          'gpu_rasterization',
+          '--browser',
+          'android-content-shell',
+          '--build-revision',
+          str(revision),
+          '--test-machine-name',
+          EscapeBuilderName(builder_name)])
+
+
+def RunPythonUnitTests(_options):
+  for suite in constants.PYTHON_UNIT_TEST_SUITES:
+    bb_annotations.PrintNamedStep(suite)
+    RunCmd(['build/android/test_runner.py', 'python', '-s', suite])
+
+
+def GetTestStepCmds():
+  return [
+      ('chromedriver', RunChromeDriverTests),
+      ('chrome_proxy', RunChromeProxyTests),
+      ('components_browsertests',
+          lambda options: RunTestSuites(options, ['components_browsertests'])),
+      ('gpu', RunGPUTests),
+      ('python_unittests', RunPythonUnitTests),
+      ('telemetry_unittests', RunTelemetryUnitTests),
+      ('telemetry_perf_unittests', RunTelemetryPerfUnitTests),
+      ('ui', RunInstrumentationTests),
+      ('unit', RunUnitTests),
+      ('webkit', RunWebkitTests),
+      ('webkit_layout', RunWebkitLayoutTests),
+  ]
+
+
+def MakeGSPath(options, gs_base_dir):
+  revision = _GetRevision(options)
+  bot_id = options.build_properties.get('buildername', 'testing')
+  randhash = hashlib.sha1(str(random.random())).hexdigest()
+  gs_path = '%s/%s/%s/%s' % (gs_base_dir, bot_id, revision, randhash)
+  # remove double slashes, happens with blank revisions and confuses gsutil
+  gs_path = re.sub('/+', '/', gs_path)
+  return gs_path
+
+def UploadHTML(options, gs_base_dir, dir_to_upload, link_text,
+               link_rel_path='index.html', gs_url=GS_URL):
+  """Uploads directory at |dir_to_upload| to Google Storage and output a link.
+
+  Args:
+    options: Command line options.
+    gs_base_dir: The Google Storage base directory (e.g.
+      'chromium-code-coverage/java')
+    dir_to_upload: Absolute path to the directory to be uploaded.
+    link_text: Link text to be displayed on the step.
+    link_rel_path: Link path relative to |dir_to_upload|.
+    gs_url: Google storage URL.
+  """
+  gs_path = MakeGSPath(options, gs_base_dir)
+  RunCmd([bb_utils.GSUTIL_PATH, 'cp', '-R', dir_to_upload, 'gs://%s' % gs_path])
+  bb_annotations.PrintLink(link_text,
+                           '%s/%s/%s' % (gs_url, gs_path, link_rel_path))
+
+
+def GenerateJavaCoverageReport(options):
+  """Generates an HTML coverage report using EMMA and uploads it."""
+  bb_annotations.PrintNamedStep('java_coverage_report')
+
+  coverage_html = os.path.join(options.coverage_dir, 'coverage_html')
+  RunCmd(['build/android/generate_emma_html.py',
+          '--coverage-dir', options.coverage_dir,
+          '--metadata-dir', os.path.join(CHROME_OUT_DIR, options.target),
+          '--cleanup',
+          '--output', os.path.join(coverage_html, 'index.html')])
+  return coverage_html
+
+
+def LogcatDump(options):
+  # Print logcat, kill logcat monitor
+  bb_annotations.PrintNamedStep('logcat_dump')
+  logcat_file = os.path.join(CHROME_OUT_DIR, options.target, 'full_log.txt')
+  RunCmd([SrcPath('build', 'android', 'adb_logcat_printer.py'),
+          '--output-path', logcat_file, LOGCAT_DIR])
+  gs_path = MakeGSPath(options, 'chromium-android/logcat_dumps')
+  RunCmd([bb_utils.GSUTIL_PATH, 'cp', '-z', 'txt', logcat_file,
+          'gs://%s' % gs_path])
+  bb_annotations.PrintLink('logcat dump', '%s/%s' % (GS_AUTH_URL, gs_path))
+
+
+def RunStackToolSteps(options):
+  """Run stack tool steps.
+
+  Stack tool is run for logcat dump, optionally for ASAN.
+  """
+  bb_annotations.PrintNamedStep('Run stack tool with logcat dump')
+  logcat_file = os.path.join(CHROME_OUT_DIR, options.target, 'full_log.txt')
+  RunCmd([os.path.join(CHROME_SRC_DIR, 'third_party', 'android_platform',
+          'development', 'scripts', 'stack'),
+          '--more-info', logcat_file])
+  if options.asan_symbolize:
+    bb_annotations.PrintNamedStep('Run stack tool for ASAN')
+    RunCmd([
+        os.path.join(CHROME_SRC_DIR, 'build', 'android', 'asan_symbolize.py'),
+        '-l', logcat_file])
+
+
+def GenerateTestReport(options):
+  bb_annotations.PrintNamedStep('test_report')
+  for report in glob.glob(
+      os.path.join(CHROME_OUT_DIR, options.target, 'test_logs', '*.log')):
+    RunCmd(['cat', report])
+    os.remove(report)
+
+
+def MainTestWrapper(options):
+  try:
+    # Spawn logcat monitor
+    SpawnLogcatMonitor()
+
+    # Run all device setup steps
+    for _, cmd in GetDeviceSetupStepCmds():
+      cmd(options)
+
+    if options.install:
+      for i in options.install:
+        install_obj = INSTALLABLE_PACKAGES[i]
+        InstallApk(options, install_obj, print_step=True)
+
+    if options.test_filter:
+      bb_utils.RunSteps(options.test_filter, GetTestStepCmds(), options)
+
+    if options.coverage_bucket:
+      coverage_html = GenerateJavaCoverageReport(options)
+      UploadHTML(options, '%s/java' % options.coverage_bucket, coverage_html,
+                 'Coverage Report')
+      shutil.rmtree(coverage_html, ignore_errors=True)
+
+    if options.experimental:
+      RunTestSuites(options, gtest_config.EXPERIMENTAL_TEST_SUITES)
+
+  finally:
+    # Run all post test steps
+    LogcatDump(options)
+    if not options.disable_stack_tool:
+      RunStackToolSteps(options)
+    GenerateTestReport(options)
+    # KillHostHeartbeat() has logic to check if heartbeat process is running,
+    # and kills only if it finds the process is running on the host.
+    provision_devices.KillHostHeartbeat()
+    if options.cleanup:
+      shutil.rmtree(os.path.join(CHROME_OUT_DIR, options.target),
+          ignore_errors=True)
+
+
+def GetDeviceStepsOptParser():
+  parser = bb_utils.GetParser()
+  parser.add_option('--experimental', action='store_true',
+                    help='Run experiemental tests')
+  parser.add_option('-f', '--test-filter', metavar='<filter>', default=[],
+                    action='append',
+                    help=('Run a test suite. Test suites: "%s"' %
+                          '", "'.join(VALID_TESTS)))
+  parser.add_option('--gtest-filter',
+                    help='Filter for running a subset of tests of a gtest test')
+  parser.add_option('--asan', action='store_true', help='Run tests with asan.')
+  parser.add_option('--install', metavar='<apk name>', action="append",
+                    help='Install an apk by name')
+  parser.add_option('--no-reboot', action='store_true',
+                    help='Do not reboot devices during provisioning.')
+  parser.add_option('--coverage-bucket',
+                    help=('Bucket name to store coverage results. Coverage is '
+                          'only run if this is set.'))
+  parser.add_option('--restart-usb', action='store_true',
+                    help='Restart usb ports before device status check.')
+  parser.add_option(
+      '--flakiness-server',
+      help=('The flakiness dashboard server to which the results should be '
+            'uploaded.'))
+  parser.add_option(
+      '--auto-reconnect', action='store_true',
+      help='Push script to device which restarts adbd on disconnections.')
+  parser.add_option('--skip-wipe', action='store_true',
+                    help='Do not wipe devices during provisioning.')
+  parser.add_option('--disable-location', action='store_true',
+                    help='Disable location settings.')
+  parser.add_option(
+      '--logcat-dump-output',
+      help='The logcat dump output will be "tee"-ed into this file')
+  # During processing perf bisects, a seperate working directory created under
+  # which builds are produced. Therefore we should look for relevent output
+  # file under this directory.(/b/build/slave/<slave_name>/build/bisect/src/out)
+  parser.add_option(
+      '--chrome-output-dir',
+      help='Chrome output directory to be used while bisecting.')
+
+  parser.add_option('--disable-stack-tool', action='store_true',
+      help='Do not run stack tool.')
+  parser.add_option('--asan-symbolize', action='store_true',
+      help='Run stack tool for ASAN')
+  parser.add_option('--cleanup', action='store_true',
+      help='Delete out/<target> directory at the end of the run.')
+  return parser
+
+
+def main(argv):
+  parser = GetDeviceStepsOptParser()
+  options, args = parser.parse_args(argv[1:])
+
+  if args:
+    return sys.exit('Unused args %s' % args)
+
+  unknown_tests = set(options.test_filter) - VALID_TESTS
+  if unknown_tests:
+    return sys.exit('Unknown tests %s' % list(unknown_tests))
+
+  setattr(options, 'target', options.factory_properties.get('target', 'Debug'))
+
+  if options.chrome_output_dir:
+    global CHROME_OUT_DIR
+    global LOGCAT_DIR
+    CHROME_OUT_DIR = options.chrome_output_dir
+    LOGCAT_DIR = os.path.join(CHROME_OUT_DIR, 'logcat')
+
+  if options.coverage_bucket:
+    setattr(options, 'coverage_dir',
+            os.path.join(CHROME_OUT_DIR, options.target, 'coverage'))
+
+  MainTestWrapper(options)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/buildbot/bb_host_steps.py b/build/android/buildbot/bb_host_steps.py
new file mode 100755
index 0000000..1e927fb
--- /dev/null
+++ b/build/android/buildbot/bb_host_steps.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import json
+import sys
+
+import bb_utils
+import bb_annotations
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+from pylib import constants
+
+
+SLAVE_SCRIPTS_DIR = os.path.join(bb_utils.BB_BUILD_DIR, 'scripts', 'slave')
+VALID_HOST_TESTS = set(['check_webview_licenses'])
+
+DIR_BUILD_ROOT = os.path.dirname(constants.DIR_SOURCE_ROOT)
+
+# Short hand for RunCmd which is used extensively in this file.
+RunCmd = bb_utils.RunCmd
+
+
+def SrcPath(*path):
+  return os.path.join(constants.DIR_SOURCE_ROOT, *path)
+
+
+def CheckWebViewLicenses(_):
+  bb_annotations.PrintNamedStep('check_licenses')
+  RunCmd([SrcPath('android_webview', 'tools', 'webview_licenses.py'), 'scan'],
+         warning_code=1)
+
+
+def RunHooks(build_type):
+  RunCmd([SrcPath('build', 'landmines.py')])
+  build_path = SrcPath('out', build_type)
+  landmine_path = os.path.join(build_path, '.landmines_triggered')
+  clobber_env = os.environ.get('BUILDBOT_CLOBBER')
+  if clobber_env or os.path.isfile(landmine_path):
+    bb_annotations.PrintNamedStep('Clobber')
+    if not clobber_env:
+      print 'Clobbering due to triggered landmines:'
+      with open(landmine_path) as f:
+        print f.read()
+    RunCmd(['rm', '-rf', build_path])
+
+  bb_annotations.PrintNamedStep('runhooks')
+  RunCmd(['gclient', 'runhooks'], halt_on_failure=True)
+
+
+def Compile(options):
+  RunHooks(options.target)
+  cmd = [os.path.join(SLAVE_SCRIPTS_DIR, 'compile.py'),
+         '--build-tool=ninja',
+         '--compiler=goma',
+         '--target=%s' % options.target,
+         '--goma-dir=%s' % bb_utils.GOMA_DIR]
+  bb_annotations.PrintNamedStep('compile')
+  if options.build_targets:
+    build_targets = options.build_targets.split(',')
+    cmd += ['--build-args', ' '.join(build_targets)]
+  RunCmd(cmd, halt_on_failure=True, cwd=DIR_BUILD_ROOT)
+
+
+def ZipBuild(options):
+  bb_annotations.PrintNamedStep('zip_build')
+  RunCmd([
+      os.path.join(SLAVE_SCRIPTS_DIR, 'zip_build.py'),
+      '--src-dir', constants.DIR_SOURCE_ROOT,
+      '--exclude-files', 'lib.target,gen,android_webview,jingle_unittests']
+      + bb_utils.EncodeProperties(options), cwd=DIR_BUILD_ROOT)
+
+
+def ExtractBuild(options):
+  bb_annotations.PrintNamedStep('extract_build')
+  RunCmd([os.path.join(SLAVE_SCRIPTS_DIR, 'extract_build.py')]
+         + bb_utils.EncodeProperties(options), cwd=DIR_BUILD_ROOT)
+
+
+def BisectPerfRegression(options):
+  args = []
+  if options.extra_src:
+    args = ['--extra_src', options.extra_src]
+  RunCmd([SrcPath('tools', 'prepare-bisect-perf-regression.py'),
+          '-w', os.path.join(constants.DIR_SOURCE_ROOT, os.pardir)])
+  RunCmd([SrcPath('tools', 'run-bisect-perf-regression.py'),
+          '-w', os.path.join(constants.DIR_SOURCE_ROOT, os.pardir),
+          '--build-properties=%s' % json.dumps(options.build_properties)] +
+          args)
+
+
+def GetHostStepCmds():
+  return [
+      ('compile', Compile),
+      ('extract_build', ExtractBuild),
+      ('check_webview_licenses', CheckWebViewLicenses),
+      ('bisect_perf_regression', BisectPerfRegression),
+      ('zip_build', ZipBuild)
+  ]
+
+
+def GetHostStepsOptParser():
+  parser = bb_utils.GetParser()
+  parser.add_option('--steps', help='Comma separated list of host tests.')
+  parser.add_option('--build-targets', default='',
+                    help='Comma separated list of build targets.')
+  parser.add_option('--experimental', action='store_true',
+                    help='Indicate whether to compile experimental targets.')
+  parser.add_option('--extra_src', default='',
+                    help='Path to extra source file. If this is supplied, '
+                    'bisect script will use it to override default behavior.')
+
+  return parser
+
+
+def main(argv):
+  parser = GetHostStepsOptParser()
+  options, args = parser.parse_args(argv[1:])
+  if args:
+    return sys.exit('Unused args %s' % args)
+
+  setattr(options, 'target', options.factory_properties.get('target', 'Debug'))
+  setattr(options, 'extra_src',
+          options.factory_properties.get('extra_src', ''))
+
+  if options.steps:
+    bb_utils.RunSteps(options.steps.split(','), GetHostStepCmds(), options)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py
new file mode 100755
index 0000000..a6afb86
--- /dev/null
+++ b/build/android/buildbot/bb_run_bot.py
@@ -0,0 +1,314 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import copy
+import json
+import os
+import pipes
+import re
+import subprocess
+import sys
+
+import bb_utils
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+from pylib import constants
+
+
+CHROMIUM_COVERAGE_BUCKET = 'chromium-code-coverage'
+
+_BotConfig = collections.namedtuple(
+    'BotConfig', ['bot_id', 'host_obj', 'test_obj'])
+
+HostConfig = collections.namedtuple(
+    'HostConfig',
+    ['script', 'host_steps', 'extra_args', 'extra_gyp_defines', 'target_arch'])
+
+TestConfig = collections.namedtuple('Tests', ['script', 'tests', 'extra_args'])
+
+
+def BotConfig(bot_id, host_object, test_object=None):
+  return _BotConfig(bot_id, host_object, test_object)
+
+
+def DictDiff(d1, d2):
+  diff = []
+  for key in sorted(set(d1.keys() + d2.keys())):
+    if key in d1 and d1[key] != d2.get(key):
+      diff.append('- %s=%s' % (key, pipes.quote(d1[key])))
+    if key in d2 and d2[key] != d1.get(key):
+      diff.append('+ %s=%s' % (key, pipes.quote(d2[key])))
+  return '\n'.join(diff)
+
+
+def GetEnvironment(host_obj, testing, extra_env_vars=None):
+  init_env = dict(os.environ)
+  init_env['GYP_GENERATORS'] = 'ninja'
+  if extra_env_vars:
+    init_env.update(extra_env_vars)
+  envsetup_cmd = '. build/android/envsetup.sh'
+  if testing:
+    # Skip envsetup to avoid presubmit dependence on android deps.
+    print 'Testing mode - skipping "%s"' % envsetup_cmd
+    envsetup_cmd = ':'
+  else:
+    print 'Running %s' % envsetup_cmd
+  proc = subprocess.Popen(['bash', '-exc',
+    envsetup_cmd + ' >&2; python build/android/buildbot/env_to_json.py'],
+    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+    cwd=bb_utils.CHROME_SRC, env=init_env)
+  json_env, envsetup_output = proc.communicate()
+  if proc.returncode != 0:
+    print >> sys.stderr, 'FATAL Failure in envsetup.'
+    print >> sys.stderr, envsetup_output
+    sys.exit(1)
+  env = json.loads(json_env)
+  env['GYP_DEFINES'] = env.get('GYP_DEFINES', '') + \
+      ' OS=android fastbuild=1 use_goma=1 gomadir=%s' % bb_utils.GOMA_DIR
+  if host_obj.target_arch:
+    env['GYP_DEFINES'] += ' target_arch=%s' % host_obj.target_arch
+  extra_gyp = host_obj.extra_gyp_defines
+  if extra_gyp:
+    env['GYP_DEFINES'] += ' %s' % extra_gyp
+    if re.search('(asan|clang)=1', extra_gyp):
+      env.pop('CXX_target', None)
+
+  # Bots checkout chrome in /b/build/slave/<name>/build/src
+  build_internal_android = os.path.abspath(os.path.join(
+      bb_utils.CHROME_SRC, '..', '..', '..', '..', '..', 'build_internal',
+      'scripts', 'slave', 'android'))
+  if os.path.exists(build_internal_android):
+    env['PATH'] = os.pathsep.join([build_internal_android, env['PATH']])
+  return env
+
+
+def GetCommands(options, bot_config):
+  """Get a formatted list of commands.
+
+  Args:
+    options: Options object.
+    bot_config: A BotConfig named tuple.
+    host_step_script: Host step script.
+    device_step_script: Device step script.
+  Returns:
+    list of Command objects.
+  """
+  property_args = bb_utils.EncodeProperties(options)
+  commands = [[bot_config.host_obj.script,
+               '--steps=%s' % ','.join(bot_config.host_obj.host_steps)] +
+              property_args + (bot_config.host_obj.extra_args or [])]
+
+  test_obj = bot_config.test_obj
+  if test_obj:
+    run_test_cmd = [test_obj.script] + property_args
+    for test in test_obj.tests:
+      run_test_cmd.extend(['-f', test])
+    if test_obj.extra_args:
+      run_test_cmd.extend(test_obj.extra_args)
+    commands.append(run_test_cmd)
+  return commands
+
+
+def GetBotStepMap():
+  compile_step = ['compile']
+  chrome_proxy_tests = ['chrome_proxy']
+  python_unittests = ['python_unittests']
+  std_host_tests = ['check_webview_licenses']
+  std_build_steps = ['compile', 'zip_build']
+  std_test_steps = ['extract_build']
+  std_tests = ['ui', 'unit']
+  telemetry_tests = ['telemetry_perf_unittests']
+  telemetry_tests_user_build = ['telemetry_unittests',
+                                'telemetry_perf_unittests']
+  flakiness_server = (
+      '--flakiness-server=%s' % constants.UPSTREAM_FLAKINESS_SERVER)
+  experimental = ['--experimental']
+  bisect_chrome_output_dir = os.path.abspath(
+      os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+                   os.pardir, 'bisect', 'src', 'out'))
+  B = BotConfig
+  H = (lambda steps, extra_args=None, extra_gyp=None, target_arch=None:
+       HostConfig('build/android/buildbot/bb_host_steps.py', steps, extra_args,
+                  extra_gyp, target_arch))
+  T = (lambda tests, extra_args=None:
+       TestConfig('build/android/buildbot/bb_device_steps.py', tests,
+                  extra_args))
+
+  bot_configs = [
+      # Main builders
+      B('main-builder-dbg', H(std_build_steps + std_host_tests)),
+      B('main-builder-rel', H(std_build_steps)),
+      B('main-clang-builder',
+        H(compile_step, extra_gyp='clang=1 component=shared_library')),
+      B('main-clobber', H(compile_step)),
+      B('main-tests-rel', H(std_test_steps),
+        T(std_tests + telemetry_tests + chrome_proxy_tests,
+          ['--cleanup', flakiness_server])),
+      B('main-tests', H(std_test_steps),
+        T(std_tests, ['--cleanup', flakiness_server])),
+
+      # Other waterfalls
+      B('asan-builder-tests', H(compile_step,
+                                extra_gyp='asan=1 component=shared_library'),
+        T(std_tests, ['--asan', '--asan-symbolize'])),
+      B('blink-try-builder', H(compile_step)),
+      B('chromedriver-fyi-tests-dbg', H(std_test_steps),
+        T(['chromedriver'],
+          ['--install=ChromeShell', '--install=ChromeDriverWebViewShell',
+           '--skip-wipe', '--disable-location', '--cleanup'])),
+      B('fyi-x86-builder-dbg',
+        H(compile_step + std_host_tests, experimental, target_arch='ia32')),
+      B('fyi-builder-dbg',
+        H(std_build_steps + std_host_tests, experimental,
+          extra_gyp='emma_coverage=1')),
+      B('x86-builder-dbg',
+        H(compile_step + std_host_tests, target_arch='ia32')),
+      B('fyi-builder-rel', H(std_build_steps, experimental)),
+      B('fyi-tests', H(std_test_steps),
+        T(std_tests + python_unittests,
+                      ['--experimental', flakiness_server,
+                      '--coverage-bucket', CHROMIUM_COVERAGE_BUCKET,
+                      '--cleanup'])),
+      B('user-build-fyi-tests-dbg', H(std_test_steps),
+        T(telemetry_tests_user_build + ['components_browsertests'])),
+      B('fyi-component-builder-tests-dbg',
+        H(compile_step, extra_gyp='component=shared_library'),
+        T(std_tests, ['--experimental', flakiness_server])),
+      B('gpu-builder-tests-dbg',
+        H(compile_step),
+        T(['gpu'], ['--install=ContentShell'])),
+      # Pass empty T([]) so that logcat monitor and device status check are run.
+      B('perf-bisect-builder-tests-dbg',
+        H(['bisect_perf_regression']),
+        T([], ['--chrome-output-dir', bisect_chrome_output_dir])),
+      B('perf-tests-rel', H(std_test_steps),
+        T([], ['--install=ChromeShell', '--cleanup'])),
+      B('webkit-latest-webkit-tests', H(std_test_steps),
+        T(['webkit_layout', 'webkit'], ['--cleanup', '--auto-reconnect'])),
+      B('webkit-latest-contentshell', H(compile_step),
+        T(['webkit_layout'], ['--auto-reconnect'])),
+      B('builder-unit-tests', H(compile_step), T(['unit'])),
+
+      # Generic builder config (for substring match).
+      B('builder', H(std_build_steps)),
+  ]
+
+  bot_map = dict((config.bot_id, config) for config in bot_configs)
+
+  # These bots have identical configuration to ones defined earlier.
+  copy_map = [
+      ('lkgr-clobber', 'main-clobber'),
+      ('try-builder-dbg', 'main-builder-dbg'),
+      ('try-builder-rel', 'main-builder-rel'),
+      ('try-clang-builder', 'main-clang-builder'),
+      ('try-fyi-builder-dbg', 'fyi-builder-dbg'),
+      ('try-x86-builder-dbg', 'x86-builder-dbg'),
+      ('try-tests-rel', 'main-tests-rel'),
+      ('try-tests', 'main-tests'),
+      ('try-fyi-tests', 'fyi-tests'),
+      ('webkit-latest-tests', 'main-tests'),
+  ]
+  for to_id, from_id in copy_map:
+    assert to_id not in bot_map
+    # pylint: disable=W0212
+    bot_map[to_id] = copy.deepcopy(bot_map[from_id])._replace(bot_id=to_id)
+
+    # Trybots do not upload to flakiness dashboard. They should be otherwise
+    # identical in configuration to their trunk building counterparts.
+    test_obj = bot_map[to_id].test_obj
+    if to_id.startswith('try') and test_obj:
+      extra_args = test_obj.extra_args
+      if extra_args and flakiness_server in extra_args:
+        extra_args.remove(flakiness_server)
+  return bot_map
+
+
+# Return an object from the map, looking first for an exact id match.
+# If this fails, look for an id which is a substring of the specified id.
+# Choose the longest of all substring matches.
+# pylint: disable=W0622
+def GetBestMatch(id_map, id):
+  config = id_map.get(id)
+  if not config:
+    substring_matches = [x for x in id_map.iterkeys() if x in id]
+    if substring_matches:
+      max_id = max(substring_matches, key=len)
+      print 'Using config from id="%s" (substring match).' % max_id
+      config = id_map[max_id]
+  return config
+
+
+def GetRunBotOptParser():
+  parser = bb_utils.GetParser()
+  parser.add_option('--bot-id', help='Specify bot id directly.')
+  parser.add_option('--testing', action='store_true',
+                    help='For testing: print, but do not run commands')
+
+  return parser
+
+
+def GetBotConfig(options, bot_step_map):
+  bot_id = options.bot_id or options.factory_properties.get('android_bot_id')
+  if not bot_id:
+    print (sys.stderr,
+           'A bot id must be specified through option or factory_props.')
+    return
+
+  bot_config = GetBestMatch(bot_step_map, bot_id)
+  if not bot_config:
+    print 'Error: config for id="%s" cannot be inferred.' % bot_id
+  return bot_config
+
+
+def RunBotCommands(options, commands, env):
+  print 'Environment changes:'
+  print DictDiff(dict(os.environ), env)
+
+  for command in commands:
+    print bb_utils.CommandToString(command)
+    sys.stdout.flush()
+    if options.testing:
+      env['BUILDBOT_TESTING'] = '1'
+    return_code = subprocess.call(command, cwd=bb_utils.CHROME_SRC, env=env)
+    if return_code != 0:
+      return return_code
+
+
+def main(argv):
+  proc = subprocess.Popen(
+      ['/bin/hostname', '-f'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  hostname_stdout, hostname_stderr = proc.communicate()
+  if proc.returncode == 0:
+    print 'Running on: ' + hostname_stdout
+  else:
+    print >> sys.stderr, 'WARNING: failed to run hostname'
+    print >> sys.stderr, hostname_stdout
+    print >> sys.stderr, hostname_stderr
+    sys.exit(1)
+
+  parser = GetRunBotOptParser()
+  options, args = parser.parse_args(argv[1:])
+  if args:
+    parser.error('Unused args: %s' % args)
+
+  bot_config = GetBotConfig(options, GetBotStepMap())
+  if not bot_config:
+    sys.exit(1)
+
+  print 'Using config:', bot_config
+
+  commands = GetCommands(options, bot_config)
+  for command in commands:
+    print 'Will run: ', bb_utils.CommandToString(command)
+  print
+
+  env = GetEnvironment(bot_config.host_obj, options.testing)
+  return RunBotCommands(options, commands, env)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/buildbot/bb_utils.py b/build/android/buildbot/bb_utils.py
new file mode 100644
index 0000000..3c16cc2
--- /dev/null
+++ b/build/android/buildbot/bb_utils.py
@@ -0,0 +1,100 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import optparse
+import os
+import pipes
+import subprocess
+import sys
+
+import bb_annotations
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+from pylib import constants
+
+
+TESTING = 'BUILDBOT_TESTING' in os.environ
+
+BB_BUILD_DIR = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+    os.pardir, os.pardir, os.pardir, os.pardir))
+
+CHROME_SRC = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), '..', '..', '..'))
+
+# TODO: Figure out how to merge this with pylib.cmd_helper.OutDirectory().
+CHROME_OUT_DIR = os.path.join(CHROME_SRC, 'out')
+
+GOMA_DIR = os.environ.get('GOMA_DIR', os.path.join(BB_BUILD_DIR, 'goma'))
+
+GSUTIL_PATH = os.path.join(BB_BUILD_DIR, 'third_party', 'gsutil', 'gsutil')
+
+def CommandToString(command):
+  """Returns quoted command that can be run in bash shell."""
+  return ' '.join(map(pipes.quote, command))
+
+
+def SpawnCmd(command, stdout=None, cwd=CHROME_SRC):
+  """Spawn a process without waiting for termination."""
+  print '>', CommandToString(command)
+  sys.stdout.flush()
+  if TESTING:
+    class MockPopen(object):
+      @staticmethod
+      def wait():
+        return 0
+      @staticmethod
+      def communicate():
+        return '', ''
+    return MockPopen()
+  return subprocess.Popen(command, cwd=cwd, stdout=stdout)
+
+
+def RunCmd(command, flunk_on_failure=True, halt_on_failure=False,
+           warning_code=constants.WARNING_EXIT_CODE, stdout=None,
+           cwd=CHROME_SRC):
+  """Run a command relative to the chrome source root."""
+  code = SpawnCmd(command, stdout, cwd).wait()
+  print '<', CommandToString(command)
+  if code != 0:
+    print 'ERROR: process exited with code %d' % code
+    if code != warning_code and flunk_on_failure:
+      bb_annotations.PrintError()
+    else:
+      bb_annotations.PrintWarning()
+    # Allow steps to have both halting (i.e. 1) and non-halting exit codes.
+    if code != warning_code and halt_on_failure:
+      print 'FATAL %d != %d' % (code, warning_code)
+      sys.exit(1)
+  return code
+
+
+def GetParser():
+  def ConvertJson(option, _, value, parser):
+    setattr(parser.values, option.dest, json.loads(value))
+  parser = optparse.OptionParser()
+  parser.add_option('--build-properties', action='callback',
+                    callback=ConvertJson, type='string', default={},
+                    help='build properties in JSON format')
+  parser.add_option('--factory-properties', action='callback',
+                    callback=ConvertJson, type='string', default={},
+                    help='factory properties in JSON format')
+  return parser
+
+
+def EncodeProperties(options):
+  return ['--factory-properties=%s' % json.dumps(options.factory_properties),
+          '--build-properties=%s' % json.dumps(options.build_properties)]
+
+
+def RunSteps(steps, step_cmds, options):
+  unknown_steps = set(steps) - set(step for step, _ in step_cmds)
+  if unknown_steps:
+    print >> sys.stderr, 'FATAL: Unknown steps %s' % list(unknown_steps)
+    sys.exit(1)
+
+  for step, cmd in step_cmds:
+    if step in steps:
+      cmd(options)
diff --git a/build/android/buildbot/env_to_json.py b/build/android/buildbot/env_to_json.py
new file mode 100755
index 0000000..f9a7a44
--- /dev/null
+++ b/build/android/buildbot/env_to_json.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Encode current environment into json.
+
+import json
+import os
+
+print json.dumps(dict(os.environ))
diff --git a/build/android/buildbot/tests/bb_run_bot_test.py b/build/android/buildbot/tests/bb_run_bot_test.py
new file mode 100755
index 0000000..810c60d
--- /dev/null
+++ b/build/android/buildbot/tests/bb_run_bot_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import subprocess
+import sys
+
+BUILDBOT_DIR = os.path.join(os.path.dirname(__file__), '..')
+sys.path.append(BUILDBOT_DIR)
+import bb_run_bot
+
+def RunBotProcesses(bot_process_map):
+  code = 0
+  for bot, proc in bot_process_map:
+    _, err = proc.communicate()
+    code |= proc.returncode
+    if proc.returncode != 0:
+      print 'Error running the bot script with id="%s"' % bot, err
+
+  return code
+
+
+def main():
+  procs = [
+      (bot, subprocess.Popen(
+          [os.path.join(BUILDBOT_DIR, 'bb_run_bot.py'), '--bot-id', bot,
+          '--testing'], stdout=subprocess.PIPE, stderr=subprocess.PIPE))
+      for bot in bb_run_bot.GetBotStepMap()]
+  return RunBotProcesses(procs)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/chrome_with_libs.gyp b/build/android/chrome_with_libs.gyp
new file mode 100644
index 0000000..690be88
--- /dev/null
+++ b/build/android/chrome_with_libs.gyp
@@ -0,0 +1,82 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to add more loadable libs into Chrome_apk.
+#
+# This is useful when building Chrome_apk with some loadable modules which are
+# not included in Chrome_apk.
+# As an example, when building Chrome_apk with
+# libpeer_target_type=loadable_module,
+# the libpeerconnection.so is not included in Chrome_apk. To add the missing
+# lib, follow the steps below:
+# - Run gyp:
+#     GYP_DEFINES="$GYP_DEFINES libpeer_target_type=loadable_module" CHROMIUM_GYP_FILE="build/android/chrome_with_libs.gyp" build/gyp_chromium
+# - Build chrome_with_libs:
+#     ninja (or make) chrome_with_libs
+#
+# This tool also allows replacing the loadable module with a new one via the
+# following steps:
+# - Build Chrome_apk with the gyp define:
+#     GYP_DEFINES="$GYP_DEFINES libpeer_target_type=loadable_module" build/gyp_chromium
+#     ninja (or make) Chrome_apk
+# - Replace libpeerconnection.so with a new one:
+#     cp the_new_one path/to/libpeerconnection.so
+# - Run gyp:
+#     GYP_DEFINES="$GYP_DEFINES libpeer_target_type=loadable_module" CHROMIUM_GYP_FILE="build/android/chrome_with_libs.gyp" build/gyp_chromium
+# - Build chrome_with_libs:
+#     ninja (or make) chrome_with_libs
+{
+  'targets': [
+    {
+      # An "All" target is required for a top-level gyp-file.
+      'target_name': 'All',
+      'type': 'none',
+      'dependencies': [
+        'chrome_with_libs',
+      ],
+    },
+    {
+      'target_name': 'chrome_with_libs',
+      'type': 'none',
+      'variables': {
+        'intermediate_dir': '<(PRODUCT_DIR)/prebuilt_libs/',
+        'chrome_unsigned_path': '<(PRODUCT_DIR)/chrome_apk/Chrome-unsigned.apk',
+        'chrome_with_libs_unsigned': '<(intermediate_dir)/Chrome-with-libs-unsigned.apk',
+        'chrome_with_libs_final': '<(PRODUCT_DIR)/apks/Chrome-with-libs.apk',
+      },
+      'dependencies': [
+        '<(DEPTH)/clank/native/framework/clank.gyp:chrome_apk'
+      ],
+      'copies': [
+        {
+          'destination': '<(intermediate_dir)/lib/<(android_app_abi)',
+          'files': [
+            '<(PRODUCT_DIR)/libpeerconnection.so',
+          ],
+        },
+      ],
+      'actions': [
+        {
+          'action_name': 'put_libs_in_chrome',
+          'variables': {
+            'inputs': [
+              '<(intermediate_dir)/lib/<(android_app_abi)/libpeerconnection.so',
+            ],
+            'input_apk_path': '<(chrome_unsigned_path)',
+            'output_apk_path': '<(chrome_with_libs_unsigned)',
+            'libraries_top_dir%': '<(intermediate_dir)',
+          },
+          'includes': [ 'create_standalone_apk_action.gypi' ],
+        },
+        {
+          'action_name': 'finalize_chrome_with_libs',
+          'variables': {
+            'input_apk_path': '<(chrome_with_libs_unsigned)',
+            'output_apk_path': '<(chrome_with_libs_final)',
+          },
+          'includes': [ 'finalize_apk_action.gypi'],
+        },
+      ],
+    }],
+}
diff --git a/build/android/cpufeatures.gypi b/build/android/cpufeatures.gypi
new file mode 100644
index 0000000..672ff1f
--- /dev/null
+++ b/build/android/cpufeatures.gypi
@@ -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.
+
+# Depend on the Android NDK's cpu feature detection. This additional level of
+# abstraction is no longer necessary and targets can depend directly on
+# build/android/ndk.gyp:cpu_features instead.
+# TODO(torne): delete this once all DEPS have been rolled to not use it.
+# http://crbug.com/440793
+{
+  'dependencies': [
+    '<(DEPTH)/build/android/ndk.gyp:cpu_features',
+  ],
+}
diff --git a/build/android/create_standalone_apk_action.gypi b/build/android/create_standalone_apk_action.gypi
new file mode 100644
index 0000000..d17af7c
--- /dev/null
+++ b/build/android/create_standalone_apk_action.gypi
@@ -0,0 +1,41 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide an action that
+# combines a directory of shared libraries and an incomplete APK into a
+# standalone APK.
+#
+# To use this, create a gyp action with the following form:
+#  {
+#    'action_name': 'some descriptive action name',
+#    'variables': {
+#      'inputs': [ 'input_path1', 'input_path2' ],
+#      'input_apk_path': '<(unsigned_apk_path)',
+#      'output_apk_path': '<(unsigned_standalone_apk_path)',
+#      'libraries_top_dir': '<(libraries_top_dir)',
+#    },
+#    'includes': [ 'relative/path/to/create_standalone_apk_action.gypi' ],
+#  },
+
+{
+  'message': 'Creating standalone APK: <(output_apk_path)',
+  'variables': {
+    'inputs': [],
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/create_standalone_apk.py',
+    '<(input_apk_path)',
+    '>@(inputs)',
+  ],
+  'outputs': [
+    '<(output_apk_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/create_standalone_apk.py',
+    '--libraries-top-dir=<(libraries_top_dir)',
+    '--input-apk-path=<(input_apk_path)',
+    '--output-apk-path=<(output_apk_path)',
+  ],
+}
diff --git a/build/android/developer_recommended_flags.gypi b/build/android/developer_recommended_flags.gypi
new file mode 100644
index 0000000..79c201d
--- /dev/null
+++ b/build/android/developer_recommended_flags.gypi
@@ -0,0 +1,61 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is the set of recommended gyp variable settings for Chrome for Android development.
+#
+# These can be used by copying this file to $CHROME_SRC/chrome/supplement.gypi.
+#
+# Even better, create chrome/supplement.gypi containing the following:
+#   {
+#     'includes': [ '../build/android/developer_recommended_flags.gypi' ]
+#   }
+# and you'll get new settings automatically.
+# When using this method, you can override individual settings by setting them unconditionally (with
+# no %) in chrome/supplement.gypi.
+# I.e. to disable gyp_managed_install but use everything else:
+#   {
+#     'variables': {
+#       'gyp_managed_install': 0,
+#     },
+#     'includes': [ '../build/android/developer_recommended_flags.gypi' ]
+#   }
+
+{
+  'variables': {
+    'variables': {
+      # Set component to 'shared_library' to enable the component build. This builds native code as
+      # many small shared libraries instead of one monolithic library. This slightly reduces the time
+      # required for incremental builds.
+      'component%': 'shared_library',
+    },
+    'component%': '<(component)',
+
+    # When gyp_managed_install is set to 1, building an APK will install that APK on the connected
+    # device(/emulator). To install on multiple devices (or onto a new device), build the APK once
+    # with each device attached. This greatly reduces the time required for incremental builds.
+    #
+    # This comes with some caveats:
+    #   Only works with a single device connected (it will print a warning if
+    #     zero or multiple devices are attached).
+    #   Device must be flashed with a user-debug unsigned Android build.
+    #   Some actions are always run (i.e. ninja will never say "no work to do").
+    'gyp_managed_install%': 1,
+
+    # With gyp_managed_install, we do not necessarily need a standalone APK.
+    # When create_standalone_apk is set to 1, we will build a standalone APK
+    # anyway. For even faster builds, you can set create_standalone_apk to 0.
+    'create_standalone_apk%': 1,
+
+    # Set clang to 1 to use the clang compiler. Clang has much (much, much) better warning/error
+    # messages than gcc.
+    # TODO(cjhopman): Enable this when http://crbug.com/156420 is addressed. Until then, users can
+    # set clang to 1, but Android stack traces will sometimes be incomplete.
+    #'clang%': 1,
+
+    # Set fastbuild to 1 to build with less debugging information. This can greatly decrease linking
+    # time. The downside is that stack traces will be missing useful information (like line
+    # numbers).
+    #'fastbuild%': 1,
+  },
+}
diff --git a/build/android/dex_action.gypi b/build/android/dex_action.gypi
new file mode 100644
index 0000000..9ea3e71
--- /dev/null
+++ b/build/android/dex_action.gypi
@@ -0,0 +1,59 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule that dexes
+# compiled java files. If proguard_enabled == "true" and CONFIGURATION_NAME ==
+# "Release", then it will dex the proguard_enabled_input_path instead of the
+# normal dex_input_paths/dex_generated_input_paths.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'action_name': 'some name for the action'
+#    'actions': [
+#      'variables': {
+#        'dex_input_paths': [ 'files to dex (when proguard is not used) and add to input paths' ],
+#        'dex_generated_input_dirs': [ 'dirs that contain generated files to dex' ],
+#
+#        # For targets that use proguard:
+#        'proguard_enabled': 'true',
+#        'proguard_enabled_input_path': 'path to dex when using proguard',
+#      },
+#      'includes': [ 'relative/path/to/dex_action.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'message': 'Creating dex file: <(output_path)',
+  'variables': {
+    'dex_input_paths': [],
+    'dex_generated_input_dirs': [],
+    'proguard_enabled%': 'false',
+    'proguard_enabled_input_path%': '',
+    'dex_no_locals%': 0,
+    'dex_additional_options': [],
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/util/md5_check.py',
+    '<(DEPTH)/build/android/gyp/dex.py',
+    '>@(dex_input_paths)',
+  ],
+  'outputs': [
+    '<(output_path)',
+    '<(output_path).inputs',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/dex.py',
+    '--dex-path=<(output_path)',
+    '--android-sdk-tools=<(android_sdk_tools)',
+    '--configuration-name=<(CONFIGURATION_NAME)',
+    '--proguard-enabled=>(proguard_enabled)',
+    '--proguard-enabled-input-path=<(proguard_enabled_input_path)',
+    '--no-locals=>(dex_no_locals)',
+    '>@(dex_additional_options)',
+    '>@(dex_input_paths)',
+    '>@(dex_generated_input_dirs)',
+  ]
+}
diff --git a/build/android/disable_lto.gypi b/build/android/disable_lto.gypi
new file mode 100644
index 0000000..e379cfd
--- /dev/null
+++ b/build/android/disable_lto.gypi
@@ -0,0 +1,20 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included to disable LTO on a target.
+
+{
+  'target_conditions': [
+    ['_toolset=="target"', {
+      'conditions': [
+        ['OS=="android" and (use_lto==1 or use_lto_o2==1)', {
+          'cflags!': [
+            '-flto',
+            '-ffat-lto-objects',
+          ],
+        }],
+      ],
+    }],
+  ],
+}
diff --git a/build/android/empty/src/.keep b/build/android/empty/src/.keep
new file mode 100644
index 0000000..0f710b6
--- /dev/null
+++ b/build/android/empty/src/.keep
@@ -0,0 +1,6 @@
+This is a file that needs to live here until http://crbug.com/158155 has
+been fixed.
+
+The ant build system requires that a src folder is always present, and for
+some of our targets that is not the case. Giving it an empty src-folder works
+nicely though.
diff --git a/build/android/empty_proguard.flags b/build/android/empty_proguard.flags
new file mode 100644
index 0000000..53484fe
--- /dev/null
+++ b/build/android/empty_proguard.flags
@@ -0,0 +1 @@
+# Used for apk targets that do not need proguard. See build/java_apk.gypi.
diff --git a/build/android/enable_asserts.py b/build/android/enable_asserts.py
new file mode 100755
index 0000000..8fb7dca
--- /dev/null
+++ b/build/android/enable_asserts.py
@@ -0,0 +1,42 @@
+#!/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.
+
+"""Enables dalvik vm asserts in the android device."""
+
+import argparse
+import sys
+
+from pylib.device import device_utils
+
+
+def main():
+  parser = argparse.ArgumentParser()
+
+  set_asserts_group = parser.add_mutually_exclusive_group(required=True)
+  set_asserts_group.add_argument(
+      '--enable_asserts', dest='set_asserts', action='store_true',
+      help='Sets the dalvik.vm.enableassertions property to "all"')
+  set_asserts_group.add_argument(
+      '--disable_asserts', dest='set_asserts', action='store_false',
+      help='Removes the dalvik.vm.enableassertions property')
+
+  args = parser.parse_args()
+
+  # TODO(jbudorick): Accept optional serial number and run only for the
+  # specified device when present.
+  devices = device_utils.DeviceUtils.parallel()
+
+  def set_java_asserts_and_restart(device):
+    if device.SetJavaAsserts(args.set_asserts):
+      device.RunShellCommand('stop')
+      device.RunShellCommand('start')
+
+  devices.pMap(set_java_asserts_and_restart)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh
new file mode 100755
index 0000000..0545330
--- /dev/null
+++ b/build/android/envsetup.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Sets up environment for building Chromium on Android.
+
+# Make sure we're being sourced (possibly by another script). Check for bash
+# since zsh sets $0 when sourcing.
+if [[ -n "$BASH_VERSION" && "${BASH_SOURCE:-$0}" == "$0" ]]; then
+  echo "ERROR: envsetup must be sourced."
+  exit 1
+fi
+
+# This only exists to set local variables. Don't call this manually.
+android_envsetup_main() {
+  local SCRIPT_PATH="$1"
+  local SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
+
+  local CURRENT_DIR="$(readlink -f "${SCRIPT_DIR}/../../")"
+  if [[ -z "${CHROME_SRC}" ]]; then
+    # If $CHROME_SRC was not set, assume current directory is CHROME_SRC.
+    local CHROME_SRC="${CURRENT_DIR}"
+  fi
+
+  if [[ "${CURRENT_DIR/"${CHROME_SRC}"/}" == "${CURRENT_DIR}" ]]; then
+    # If current directory is not in $CHROME_SRC, it might be set for other
+    # source tree. If $CHROME_SRC was set correctly and we are in the correct
+    # directory, "${CURRENT_DIR/"${CHROME_SRC}"/}" will be "".
+    # Otherwise, it will equal to "${CURRENT_DIR}"
+    echo "Warning: Current directory is out of CHROME_SRC, it may not be \
+  the one you want."
+    echo "${CHROME_SRC}"
+  fi
+
+  # Allow the caller to override a few environment variables. If any of them is
+  # unset, we default to a sane value that's known to work. This allows for
+  # experimentation with a custom SDK.
+  if [[ -z "${ANDROID_SDK_ROOT}" || ! -d "${ANDROID_SDK_ROOT}" ]]; then
+    local ANDROID_SDK_ROOT="${CHROME_SRC}/third_party/android_tools/sdk/"
+  fi
+
+  # Add Android SDK tools to system path.
+  export PATH=$PATH:${ANDROID_SDK_ROOT}/platform-tools
+
+  # Add Android utility tools to the system path.
+  export PATH=$PATH:${ANDROID_SDK_ROOT}/tools/
+
+  # Add Chromium Android development scripts to system path.
+  # Must be after CHROME_SRC is set.
+  export PATH=$PATH:${CHROME_SRC}/build/android
+
+  export ENVSETUP_GYP_CHROME_SRC=${CHROME_SRC}  # TODO(thakis): Remove.
+}
+# In zsh, $0 is the name of the file being sourced.
+android_envsetup_main "${BASH_SOURCE:-$0}"
+unset -f android_envsetup_main
+
+android_gyp() {
+  echo "Please call build/gyp_chromium instead. android_gyp is going away."
+  "${ENVSETUP_GYP_CHROME_SRC}/build/gyp_chromium" --depth="${ENVSETUP_GYP_CHROME_SRC}" --check "$@"
+}
diff --git a/build/android/finalize_apk_action.gypi b/build/android/finalize_apk_action.gypi
new file mode 100644
index 0000000..bdf9966
--- /dev/null
+++ b/build/android/finalize_apk_action.gypi
@@ -0,0 +1,48 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide an action that
+# signs and zipaligns an APK.
+#
+# To use this, create a gyp action with the following form:
+#  {
+#    'action_name': 'some descriptive action name',
+#    'variables': {
+#      'input_apk_path': 'relative/path/to/input.apk',
+#      'output_apk_path': 'relative/path/to/output.apk',
+#    },
+#    'includes': [ '../../build/android/finalize_apk_action.gypi' ],
+#  },
+#
+
+{
+  'message': 'Signing/aligning <(_target_name) APK: <(input_apk_path)',
+  'variables': {
+    'keystore_path%': '<(DEPTH)/build/android/ant/chromium-debug.keystore',
+    'keystore_name%': 'chromiumdebugkey',
+    'keystore_password%': 'chromium',
+    'zipalign_path%': '<(android_sdk_tools)/zipalign',
+    'rezip_apk_jar_path%': '<(PRODUCT_DIR)/lib.java/rezip_apk.jar',
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/finalize_apk.py',
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(keystore_path)',
+    '<(input_apk_path)',
+  ],
+  'outputs': [
+    '<(output_apk_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/finalize_apk.py',
+    '--zipalign-path=<(zipalign_path)',
+    '--unsigned-apk-path=<(input_apk_path)',
+    '--final-apk-path=<(output_apk_path)',
+    '--key-path=<(keystore_path)',
+    '--key-name=<(keystore_name)',
+    '--key-passwd=<(keystore_password)',
+    '--load-library-from-zip-file=<(load_library_from_zip_file)',
+    '--rezip-apk-jar-path=<(rezip_apk_jar_path)',
+  ],
+}
diff --git a/build/android/findbugs_action.gypi b/build/android/findbugs_action.gypi
new file mode 100644
index 0000000..e3b3d36
--- /dev/null
+++ b/build/android/findbugs_action.gypi
@@ -0,0 +1,22 @@
+
+{
+  'action_name': 'findbugs_<(_target_name)',
+  'message': 'Running findbugs on <(_target_name)',
+  'variables': {
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/findbugs_diff.py',
+    '<(DEPTH)/build/android/findbugs_filter/findbugs_exclude.xml',
+    '<(DEPTH)/build/android/pylib/utils/findbugs.py',
+    '<(findbugs_target_jar_path)',
+  ],
+  'outputs': [
+    '<(stamp_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/findbugs_diff.py',
+    '--auxclasspath-gyp', '>(auxclasspath)',
+    '--stamp', '<(stamp_path)',
+    '<(findbugs_target_jar_path)',
+  ],
+}
diff --git a/build/android/findbugs_diff.py b/build/android/findbugs_diff.py
new file mode 100755
index 0000000..f55e462
--- /dev/null
+++ b/build/android/findbugs_diff.py
@@ -0,0 +1,110 @@
+#!/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.
+
+"""Runs findbugs, and returns an error code if there are new warnings.
+
+Other options
+  --only-analyze used to only analyze the class you are interested.
+  --relase-build analyze the classes in out/Release directory.
+  --findbugs-args used to passin other findbugs's options.
+
+Run
+  $CHROMIUM_SRC/third_party/findbugs/bin/findbugs -textui for details.
+
+"""
+
+import argparse
+import os
+import sys
+
+from pylib import constants
+from pylib.utils import findbugs
+
+_DEFAULT_BASE_DIR = os.path.join(
+    constants.DIR_SOURCE_ROOT, 'build', 'android', 'findbugs_filter')
+
+sys.path.append(
+    os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android', 'gyp'))
+from util import build_utils
+
+
+def main():
+  parser = argparse.ArgumentParser()
+
+  parser.add_argument(
+      '-a', '--auxclasspath', default=None, dest='auxclasspath',
+      help='Set aux classpath for analysis.')
+  parser.add_argument(
+      '--auxclasspath-gyp', dest='auxclasspath_gyp',
+      help='A gyp list containing the aux classpath for analysis')
+  parser.add_argument(
+      '-o', '--only-analyze', default=None,
+      dest='only_analyze', help='Only analyze the given classes and packages.')
+  parser.add_argument(
+      '-e', '--exclude', default=None, dest='exclude',
+      help='Exclude bugs matching given filter.')
+  parser.add_argument(
+      '-l', '--release-build', action='store_true', dest='release_build',
+      help='Analyze release build instead of debug.')
+  parser.add_argument(
+      '-f', '--findbug-args', default=None, dest='findbug_args',
+      help='Additional findbug arguments.')
+  parser.add_argument(
+      '-b', '--base-dir', default=_DEFAULT_BASE_DIR,
+      dest='base_dir', help='Base directory for configuration file.')
+  parser.add_argument(
+      '--output-file', dest='output_file',
+      help='Path to save the output to.')
+  parser.add_argument(
+      '--stamp', help='Path to touch on success.')
+  parser.add_argument(
+      '--depfile', help='Path to the depfile. This must be specified as the '
+                        "action's first output.")
+
+  parser.add_argument(
+      'jar_paths', metavar='JAR_PATH', nargs='+',
+      help='JAR file to analyze')
+
+  args = parser.parse_args(build_utils.ExpandFileArgs(sys.argv[1:]))
+  if args.auxclasspath:
+    args.auxclasspath = args.auxclasspath.split(':')
+  elif args.auxclasspath_gyp:
+    args.auxclasspath = build_utils.ParseGypList(args.auxclasspath_gyp)
+
+  if args.base_dir:
+    if not args.exclude:
+      args.exclude = os.path.join(args.base_dir, 'findbugs_exclude.xml')
+
+  findbugs_command, findbugs_warnings = findbugs.Run(
+      args.exclude, args.only_analyze, args.auxclasspath,
+      args.output_file, args.findbug_args, args.jar_paths)
+
+  if findbugs_warnings:
+    print
+    print '*' * 80
+    print 'FindBugs run via:'
+    print findbugs_command
+    print
+    print 'FindBugs reported the following issues:'
+    for warning in sorted(findbugs_warnings):
+      print str(warning)
+    print '*' * 80
+    print
+  else:
+    if args.depfile:
+      build_utils.WriteDepfile(
+          args.depfile,
+          build_utils.GetPythonDependencies() + args.auxclasspath
+              + args.jar_paths)
+    if args.stamp:
+      build_utils.Touch(args.stamp)
+
+  return len(findbugs_warnings)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/findbugs_filter/findbugs_exclude.xml b/build/android/findbugs_filter/findbugs_exclude.xml
new file mode 100644
index 0000000..dbff9d9
--- /dev/null
+++ b/build/android/findbugs_filter/findbugs_exclude.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright (c) 2012 The Chromium Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file.
+-->
+
+<!--
+Documentation: http://findbugs.sourceforge.net/manual/filter.html
+In particular, ~ at the start of a string means it's a regex.
+-->
+<FindBugsFilter>
+  <!-- Skip the generated resource classes (including nested classes). -->
+  <Match>
+    <Class name="~.*\.R(\$\w+)?" />
+  </Match>
+  <Match>
+    <Class name="~org\.chromium\..*\.Manifest(\$\w+)?" />
+  </Match>
+  <Bug pattern="DM_STRING_CTOR" />
+  <!-- Ignore "reliance on default String encoding" warnings, as we're not multi-platform -->
+  <Bug pattern="DM_DEFAULT_ENCODING" />
+</FindBugsFilter>
diff --git a/build/android/generate_emma_html.py b/build/android/generate_emma_html.py
new file mode 100755
index 0000000..93b0b0e
--- /dev/null
+++ b/build/android/generate_emma_html.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Aggregates EMMA coverage files to produce html output."""
+
+import fnmatch
+import json
+import optparse
+import os
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+
+
+def _GetFilesWithExt(root_dir, ext):
+  """Gets all files with a given extension.
+
+  Args:
+    root_dir: Directory in which to search for files.
+    ext: Extension to look for (including dot)
+
+  Returns:
+    A list of absolute paths to files that match.
+  """
+  files = []
+  for root, _, filenames in os.walk(root_dir):
+    basenames = fnmatch.filter(filenames, '*.' + ext)
+    files.extend([os.path.join(root, basename)
+                  for basename in basenames])
+
+  return files
+
+
+def main():
+  option_parser = optparse.OptionParser()
+  option_parser.add_option('--output', help='HTML output filename.')
+  option_parser.add_option('--coverage-dir', default=None,
+                           help=('Root of the directory in which to search for '
+                                 'coverage data (.ec) files.'))
+  option_parser.add_option('--metadata-dir', default=None,
+                           help=('Root of the directory in which to search for '
+                                 'coverage metadata (.em) files.'))
+  option_parser.add_option('--cleanup', action='store_true',
+                           help=('If set, removes coverage files generated at '
+                                 'runtime.'))
+  options, _ = option_parser.parse_args()
+
+  if not (options.coverage_dir and options.metadata_dir and options.output):
+    option_parser.error('One or more mandatory options are missing.')
+
+  coverage_files = _GetFilesWithExt(options.coverage_dir, 'ec')
+  metadata_files = _GetFilesWithExt(options.metadata_dir, 'em')
+  print 'Found coverage files: %s' % str(coverage_files)
+  print 'Found metadata files: %s' % str(metadata_files)
+
+  sources = []
+  for f in metadata_files:
+    sources_file = os.path.splitext(f)[0] + '_sources.txt'
+    with open(sources_file, 'r') as sf:
+      sources.extend(json.load(sf))
+  sources = [os.path.join(constants.DIR_SOURCE_ROOT, s) for s in sources]
+  print 'Sources: %s' % sources
+
+  input_args = []
+  for f in coverage_files + metadata_files:
+    input_args.append('-in')
+    input_args.append(f)
+
+  output_args = ['-Dreport.html.out.file', options.output]
+  source_args = ['-sp', ','.join(sources)]
+
+  exit_code = cmd_helper.RunCmd(
+      ['java', '-cp',
+       os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'lib', 'emma.jar'),
+       'emma', 'report', '-r', 'html']
+      + input_args + output_args + source_args)
+
+  if options.cleanup:
+    for f in coverage_files:
+      os.remove(f)
+
+  return exit_code
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gn/zip.py b/build/android/gn/zip.py
new file mode 100755
index 0000000..5050ea0
--- /dev/null
+++ b/build/android/gn/zip.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Archives a set of files.
+"""
+
+import ast
+import optparse
+import os
+import sys
+import zipfile
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'gyp'))
+from util import build_utils
+
+def DoZip(inputs, output, base_dir):
+  with zipfile.ZipFile(output, 'w') as outfile:
+    for f in inputs:
+      outfile.write(f, os.path.relpath(f, base_dir))
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--inputs', help='List of files to archive.')
+  parser.add_option('--output', help='Path to output archive.')
+  parser.add_option('--base-dir',
+                    help='If provided, the paths in the archive will be '
+                    'relative to this directory', default='.')
+
+  options, _ = parser.parse_args()
+
+  inputs = ast.literal_eval(options.inputs)
+  output = options.output
+  base_dir = options.base_dir
+
+  DoZip(inputs, output, base_dir)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/aidl.py b/build/android/gyp/aidl.py
new file mode 100755
index 0000000..d5aa546
--- /dev/null
+++ b/build/android/gyp/aidl.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Invokes Android's aidl
+"""
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+
+def main(argv):
+  option_parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(option_parser)
+  option_parser.add_option('--aidl-path', help='Path to the aidl binary.')
+  option_parser.add_option('--imports', help='Files to import.')
+  option_parser.add_option('--includes',
+                           help='Directories to add as import search paths.')
+  option_parser.add_option('--srcjar', help='Path for srcjar output.')
+  options, args = option_parser.parse_args(argv[1:])
+
+  with build_utils.TempDir() as temp_dir:
+    for f in args:
+      classname = os.path.splitext(os.path.basename(f))[0]
+      output = os.path.join(temp_dir, classname + '.java')
+      aidl_cmd = [options.aidl_path]
+      aidl_cmd += [
+        '-p' + s for s in build_utils.ParseGypList(options.imports)
+      ]
+      if options.includes is not None:
+        aidl_cmd += [
+          '-I' + s for s in build_utils.ParseGypList(options.includes)
+        ]
+      aidl_cmd += [
+        f,
+        output
+      ]
+      build_utils.CheckOutput(aidl_cmd)
+
+    build_utils.ZipDir(options.srcjar, temp_dir)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/gyp/ant.py b/build/android/gyp/ant.py
new file mode 100755
index 0000000..5394b9e
--- /dev/null
+++ b/build/android/gyp/ant.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""An Ant wrapper that suppresses useless Ant output.
+
+Ant build scripts output "BUILD SUCCESSFUL" and build timing at the end of
+every build. In the Android build, this just adds a lot of useless noise to the
+build output. This script forwards its arguments to ant, and prints Ant's
+output up until the BUILD SUCCESSFUL line.
+
+Also, when a command fails, this script will re-run that ant command with the
+'-verbose' argument so that the failure is easier to debug.
+"""
+
+import optparse
+import sys
+import traceback
+
+from util import build_utils
+
+
+def main(argv):
+  option_parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(option_parser)
+  options, args = option_parser.parse_args(argv[1:])
+
+  try:
+    stdout = build_utils.CheckOutput(['ant'] + args)
+  except build_utils.CalledProcessError:
+    # It is very difficult to diagnose ant failures without the '-verbose'
+    # argument. So, when an ant command fails, re-run it with '-verbose' so that
+    # the cause of the failure is easier to identify.
+    verbose_args = ['-verbose'] + [a for a in args if a != '-quiet']
+    try:
+      stdout = build_utils.CheckOutput(['ant'] + verbose_args)
+    except build_utils.CalledProcessError:
+      traceback.print_exc()
+      sys.exit(1)
+
+    # If this did sys.exit(1), building again would succeed (which would be
+    # awkward). Instead, just print a big warning.
+    build_utils.PrintBigWarning(
+        'This is unexpected. `ant ' + ' '.join(args) + '` failed.' +
+        'But, running `ant ' + ' '.join(verbose_args) + '` passed.')
+
+  stdout = stdout.strip().split('\n')
+  for line in stdout:
+    if line.strip() == 'BUILD SUCCESSFUL':
+      break
+    print line
+
+  if options.depfile:
+    assert '-buildfile' in args
+    ant_buildfile = args[args.index('-buildfile') + 1]
+
+    build_utils.WriteDepfile(
+        options.depfile,
+        [ant_buildfile] + build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/gyp/apk_install.py b/build/android/gyp/apk_install.py
new file mode 100755
index 0000000..19a217c
--- /dev/null
+++ b/build/android/gyp/apk_install.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Installs an APK.
+
+"""
+
+import optparse
+import os
+import re
+import sys
+
+from util import build_device
+from util import build_utils
+from util import md5_check
+
+BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
+sys.path.append(BUILD_ANDROID_DIR)
+
+from pylib import constants
+from pylib.utils import apk_helper
+
+def GetNewMetadata(device, apk_package):
+  """Gets the metadata on the device for the apk_package apk."""
+  output = device.RunShellCommand('ls -l /data/app/')
+  # Matches lines like:
+  # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
+  # org.chromium.chrome.shell.apk
+  # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
+  # org.chromium.chrome.shell-1.apk
+  apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?(.apk)?$' % apk_package, s)
+  matches = filter(apk_matcher, output)
+  return matches[0] if matches else None
+
+def HasInstallMetadataChanged(device, apk_package, metadata_path):
+  """Checks if the metadata on the device for apk_package has changed."""
+  if not os.path.exists(metadata_path):
+    return True
+
+  with open(metadata_path, 'r') as expected_file:
+    return expected_file.read() != device.GetInstallMetadata(apk_package)
+
+
+def RecordInstallMetadata(device, apk_package, metadata_path):
+  """Records the metadata from the device for apk_package."""
+  metadata = GetNewMetadata(device, apk_package)
+  if not metadata:
+    raise Exception('APK install failed unexpectedly.')
+
+  with open(metadata_path, 'w') as outfile:
+    outfile.write(metadata)
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--apk-path',
+      help='Path to .apk to install.')
+  parser.add_option('--install-record',
+      help='Path to install record (touched only when APK is installed).')
+  parser.add_option('--build-device-configuration',
+      help='Path to build device configuration.')
+  parser.add_option('--stamp',
+      help='Path to touch on success.')
+  parser.add_option('--configuration-name',
+      help='The build CONFIGURATION_NAME')
+  options, _ = parser.parse_args()
+
+  device = build_device.GetBuildDeviceFromPath(
+      options.build_device_configuration)
+  if not device:
+    return
+
+  constants.SetBuildType(options.configuration_name)
+
+  serial_number = device.GetSerialNumber()
+  apk_package = apk_helper.GetPackageName(options.apk_path)
+
+  metadata_path = '%s.%s.device.time.stamp' % (options.apk_path, serial_number)
+
+  # If the APK on the device does not match the one that was last installed by
+  # the build, then the APK has to be installed (regardless of the md5 record).
+  force_install = HasInstallMetadataChanged(device, apk_package, metadata_path)
+
+  def Install():
+    device.Install(options.apk_path, reinstall=True)
+    RecordInstallMetadata(device, apk_package, metadata_path)
+    build_utils.Touch(options.install_record)
+
+
+  record_path = '%s.%s.md5.stamp' % (options.apk_path, serial_number)
+  md5_check.CallAndRecordIfStale(
+      Install,
+      record_path=record_path,
+      input_paths=[options.apk_path],
+      force=force_install)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/apk_obfuscate.py b/build/android/gyp/apk_obfuscate.py
new file mode 100755
index 0000000..b075758
--- /dev/null
+++ b/build/android/gyp/apk_obfuscate.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates the obfuscated jar and test jar for an apk.
+
+If proguard is not enabled or 'Release' is not in the configuration name,
+obfuscation will be a no-op.
+"""
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+from util import proguard_util
+
+
+def ParseArgs(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('--android-sdk', help='path to the Android SDK folder')
+  parser.add_option('--android-sdk-tools',
+                    help='path to the Android SDK build tools folder')
+  parser.add_option('--android-sdk-jar',
+                    help='path to Android SDK\'s android.jar')
+  parser.add_option('--proguard-jar-path',
+                    help='Path to proguard.jar in the sdk')
+  parser.add_option('--input-jars-paths',
+                    help='Path to jars to include in obfuscated jar')
+
+  parser.add_option('--proguard-configs',
+                    help='Paths to proguard config files')
+
+  parser.add_option('--configuration-name',
+                    help='Gyp configuration name (i.e. Debug, Release)')
+  parser.add_option('--proguard-enabled', action='store_true',
+                    help='Set if proguard is enabled for this target.')
+
+  parser.add_option('--obfuscated-jar-path',
+                    help='Output path for obfuscated jar.')
+
+  parser.add_option('--testapp', action='store_true',
+                    help='Set this if building an instrumentation test apk')
+  parser.add_option('--tested-apk-obfuscated-jar-path',
+                    help='Path to obfusctated jar of the tested apk')
+  parser.add_option('--test-jar-path',
+                    help='Output path for jar containing all the test apk\'s '
+                    'code.')
+
+  parser.add_option('--stamp', help='File to touch on success')
+
+  (options, args) = parser.parse_args(argv)
+
+  if args:
+    parser.error('No positional arguments should be given. ' + str(args))
+
+  # Check that required options have been provided.
+  required_options = (
+      'android_sdk',
+      'android_sdk_tools',
+      'android_sdk_jar',
+      'proguard_jar_path',
+      'input_jars_paths',
+      'configuration_name',
+      'obfuscated_jar_path',
+      )
+
+  if options.testapp:
+    required_options += (
+        'test_jar_path',
+        )
+
+  build_utils.CheckOptions(options, parser, required=required_options)
+  return options, args
+
+
+def DoProguard(options):
+  proguard = proguard_util.ProguardCmdBuilder(options.proguard_jar_path)
+  proguard.outjar(options.obfuscated_jar_path)
+
+  library_classpath = [options.android_sdk_jar]
+  input_jars = build_utils.ParseGypList(options.input_jars_paths)
+
+  exclude_paths = []
+  configs = build_utils.ParseGypList(options.proguard_configs)
+  if options.tested_apk_obfuscated_jar_path:
+    # configs should only contain the process_resources.py generated config.
+    assert len(configs) == 1, (
+        'test apks should not have custom proguard configs: ' + str(configs))
+    tested_jar_info = build_utils.ReadJson(
+        options.tested_apk_obfuscated_jar_path + '.info')
+    exclude_paths = tested_jar_info['inputs']
+    configs = tested_jar_info['configs']
+
+    proguard.is_test(True)
+    proguard.mapping(options.tested_apk_obfuscated_jar_path + '.mapping')
+    library_classpath.append(options.tested_apk_obfuscated_jar_path)
+
+  proguard.libraryjars(library_classpath)
+  proguard_injars = [p for p in input_jars if p not in exclude_paths]
+  proguard.injars(proguard_injars)
+  proguard.configs(configs)
+
+  proguard.CheckOutput()
+
+  this_info = {
+    'inputs': proguard_injars,
+    'configs': configs
+  }
+
+  build_utils.WriteJson(
+      this_info, options.obfuscated_jar_path + '.info')
+
+
+def main(argv):
+  options, _ = ParseArgs(argv)
+
+  input_jars = build_utils.ParseGypList(options.input_jars_paths)
+
+  if options.testapp:
+    dependency_class_filters = [
+        '*R.class', '*R$*.class', '*Manifest.class', '*BuildConfig.class']
+    build_utils.MergeZips(
+        options.test_jar_path, input_jars, dependency_class_filters)
+
+  if options.configuration_name == 'Release' and options.proguard_enabled:
+    DoProguard(options)
+  else:
+    output_files = [
+        options.obfuscated_jar_path,
+        options.obfuscated_jar_path + '.info',
+        options.obfuscated_jar_path + '.dump',
+        options.obfuscated_jar_path + '.seeds',
+        options.obfuscated_jar_path + '.usage',
+        options.obfuscated_jar_path + '.mapping']
+    for f in output_files:
+      if os.path.exists(f):
+        os.remove(f)
+      build_utils.Touch(f)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/copy_ex.py b/build/android/gyp/copy_ex.py
new file mode 100755
index 0000000..eee3d19
--- /dev/null
+++ b/build/android/gyp/copy_ex.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Copies files to a directory."""
+
+import optparse
+import shutil
+import sys
+
+from util import build_utils
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--dest', help='Directory to copy files to.')
+  parser.add_option('--files', action='append',
+                    help='List of files to copy.')
+  parser.add_option('--clear', action='store_true',
+                    help='If set, the destination directory will be deleted '
+                    'before copying files to it. This is highly recommended to '
+                    'ensure that no stale files are left in the directory.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  options, _ = parser.parse_args(args)
+
+  if options.clear:
+    build_utils.DeleteDirectory(options.dest)
+    build_utils.MakeDirectory(options.dest)
+
+  files = []
+  for file_arg in options.files:
+    files += build_utils.ParseGypList(file_arg)
+
+  for f in files:
+    shutil.copy(f, options.dest)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        files + build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
+
diff --git a/build/android/gyp/create_device_library_links.py b/build/android/gyp/create_device_library_links.py
new file mode 100755
index 0000000..3e630b6
--- /dev/null
+++ b/build/android/gyp/create_device_library_links.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Creates symlinks to native libraries for an APK.
+
+The native libraries should have previously been pushed to the device (in
+options.target_dir). This script then creates links in an apk's lib/ folder to
+those native libraries.
+"""
+
+import optparse
+import os
+import sys
+
+from util import build_device
+from util import build_utils
+
+BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
+sys.path.append(BUILD_ANDROID_DIR)
+
+from pylib import constants
+from pylib.utils import apk_helper
+
+def RunShellCommand(device, cmd):
+  output = device.RunShellCommand(cmd)
+
+  if output:
+    raise Exception(
+        'Unexpected output running command: ' + cmd + '\n' +
+        '\n'.join(output))
+
+
+def CreateSymlinkScript(options):
+  libraries = build_utils.ParseGypList(options.libraries)
+
+  link_cmd = (
+      'rm $APK_LIBRARIES_DIR/%(lib_basename)s > /dev/null 2>&1 \n'
+      'ln -s $STRIPPED_LIBRARIES_DIR/%(lib_basename)s '
+        '$APK_LIBRARIES_DIR/%(lib_basename)s \n'
+      )
+
+  script = '#!/bin/sh \n'
+
+  for lib in libraries:
+    script += link_cmd % { 'lib_basename': lib }
+
+  with open(options.script_host_path, 'w') as scriptfile:
+    scriptfile.write(script)
+
+
+def TriggerSymlinkScript(options):
+  device = build_device.GetBuildDeviceFromPath(
+      options.build_device_configuration)
+  if not device:
+    return
+
+  apk_package = apk_helper.GetPackageName(options.apk)
+  apk_libraries_dir = '/data/data/%s/lib' % apk_package
+
+  device_dir = os.path.dirname(options.script_device_path)
+  mkdir_cmd = ('if [ ! -e %(dir)s ]; then mkdir -p %(dir)s; fi ' %
+      { 'dir': device_dir })
+  RunShellCommand(device, mkdir_cmd)
+  device.PushChangedFiles([(options.script_host_path,
+                            options.script_device_path)])
+
+  trigger_cmd = (
+      'APK_LIBRARIES_DIR=%(apk_libraries_dir)s; '
+      'STRIPPED_LIBRARIES_DIR=%(target_dir)s; '
+      '. %(script_device_path)s'
+      ) % {
+          'apk_libraries_dir': apk_libraries_dir,
+          'target_dir': options.target_dir,
+          'script_device_path': options.script_device_path
+          }
+  RunShellCommand(device, trigger_cmd)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = optparse.OptionParser()
+  parser.add_option('--apk', help='Path to the apk.')
+  parser.add_option('--script-host-path',
+      help='Path on the host for the symlink script.')
+  parser.add_option('--script-device-path',
+      help='Path on the device to push the created symlink script.')
+  parser.add_option('--libraries',
+      help='List of native libraries.')
+  parser.add_option('--target-dir',
+      help='Device directory that contains the target libraries for symlinks.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+  parser.add_option('--build-device-configuration',
+      help='Path to build device configuration.')
+  parser.add_option('--configuration-name',
+      help='The build CONFIGURATION_NAME')
+  options, _ = parser.parse_args(args)
+
+  required_options = ['apk', 'libraries', 'script_host_path',
+      'script_device_path', 'target_dir', 'configuration_name']
+  build_utils.CheckOptions(options, parser, required=required_options)
+  constants.SetBuildType(options.configuration_name)
+
+  CreateSymlinkScript(options)
+  TriggerSymlinkScript(options)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/create_dist_jar.py b/build/android/gyp/create_dist_jar.py
new file mode 100755
index 0000000..0d31c5d
--- /dev/null
+++ b/build/android/gyp/create_dist_jar.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Merges a list of jars into a single jar."""
+
+import optparse
+import sys
+
+from util import build_utils
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--output', help='Path to output jar.')
+  parser.add_option('--inputs', action='append', help='List of jar inputs.')
+  options, _ = parser.parse_args(args)
+  build_utils.CheckOptions(options, parser, ['output', 'inputs'])
+
+  input_jars = []
+  for inputs_arg in options.inputs:
+    input_jars.extend(build_utils.ParseGypList(inputs_arg))
+
+  build_utils.MergeZips(options.output, input_jars)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        input_jars + build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py
new file mode 100755
index 0000000..d632728
--- /dev/null
+++ b/build/android/gyp/create_java_binary_script.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Creates a simple script to run a java "binary".
+
+This creates a script that sets up the java command line for running a java
+jar. This includes correctly setting the classpath and the main class.
+"""
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+# The java command must be executed in the current directory because there may
+# be user-supplied paths in the args. The script receives the classpath relative
+# to the directory that the script is written in and then, when run, must
+# recalculate the paths relative to the current directory.
+script_template = """\
+#!/usr/bin/env python
+#
+# This file was generated by build/android/gyp/create_java_binary_script.py
+
+import os
+import sys
+
+self_dir = os.path.dirname(__file__)
+classpath = [{classpath}]
+if os.getcwd() != self_dir:
+  offset = os.path.relpath(self_dir, os.getcwd())
+  classpath = [os.path.join(offset, p) for p in classpath]
+java_args = [
+  "java",
+  "-classpath", ":".join(classpath),
+  \"{main_class}\"] + sys.argv[1:]
+os.execvp("java", java_args)
+"""
+
+def main(argv):
+  argv = build_utils.ExpandFileArgs(argv)
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--output', help='Output path for executable script.')
+  parser.add_option('--jar-path', help='Path to the main jar.')
+  parser.add_option('--main-class',
+      help='Name of the java class with the "main" entry point.')
+  parser.add_option('--classpath', action='append',
+      help='Classpath for running the jar.')
+  options, _ = parser.parse_args(argv)
+
+  classpath = [options.jar_path]
+  for cp_arg in options.classpath:
+    classpath += build_utils.ParseGypList(cp_arg)
+
+  run_dir = os.path.dirname(options.output)
+  classpath = [os.path.relpath(p, run_dir) for p in classpath]
+
+  with open(options.output, 'w') as script:
+    script.write(script_template.format(
+      classpath=('"%s"' % '", "'.join(classpath)),
+      main_class=options.main_class))
+
+  os.chmod(options.output, 0750)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/create_placeholder_files.py b/build/android/gyp/create_placeholder_files.py
new file mode 100755
index 0000000..103e1df
--- /dev/null
+++ b/build/android/gyp/create_placeholder_files.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Create placeholder files.
+"""
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option(
+      '--dest-lib-dir',
+      help='Destination directory to have placeholder files.')
+  parser.add_option(
+      '--stamp',
+      help='Path to touch on success')
+
+  options, args = parser.parse_args()
+
+  for name in args:
+    target_path = os.path.join(options.dest_lib_dir, name)
+    build_utils.Touch(target_path)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/gyp/create_standalone_apk.py b/build/android/gyp/create_standalone_apk.py
new file mode 100755
index 0000000..c560599
--- /dev/null
+++ b/build/android/gyp/create_standalone_apk.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Combines stripped libraries and incomplete APK into single standalone APK.
+
+"""
+
+import optparse
+import os
+import shutil
+import sys
+import tempfile
+
+from util import build_utils
+from util import md5_check
+
+def CreateStandaloneApk(options):
+  def DoZip():
+    with tempfile.NamedTemporaryFile(suffix='.zip') as intermediate_file:
+      intermediate_path = intermediate_file.name
+      shutil.copy(options.input_apk_path, intermediate_path)
+      apk_path_abs = os.path.abspath(intermediate_path)
+      build_utils.CheckOutput(
+          ['zip', '-r', '-1', apk_path_abs, 'lib'],
+          cwd=options.libraries_top_dir)
+      shutil.copy(intermediate_path, options.output_apk_path)
+
+  input_paths = [options.input_apk_path, options.libraries_top_dir]
+  record_path = '%s.standalone.stamp' % options.input_apk_path
+  md5_check.CallAndRecordIfStale(
+      DoZip,
+      record_path=record_path,
+      input_paths=input_paths)
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--libraries-top-dir',
+      help='Top directory that contains libraries '
+      '(i.e. library paths are like '
+      'libraries_top_dir/lib/android_app_abi/foo.so).')
+  parser.add_option('--input-apk-path', help='Path to incomplete APK.')
+  parser.add_option('--output-apk-path', help='Path for standalone APK.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+  options, _ = parser.parse_args()
+
+  required_options = ['libraries_top_dir', 'input_apk_path', 'output_apk_path']
+  build_utils.CheckOptions(options, parser, required=required_options)
+
+  CreateStandaloneApk(options)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
new file mode 100755
index 0000000..4e62332
--- /dev/null
+++ b/build/android/gyp/dex.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+from util import md5_check
+
+
+def DoDex(options, paths):
+  dx_binary = os.path.join(options.android_sdk_tools, 'dx')
+  # See http://crbug.com/272064 for context on --force-jumbo.
+  dex_cmd = [dx_binary, '--dex', '--force-jumbo', '--output', options.dex_path]
+  if options.no_locals != '0':
+    dex_cmd.append('--no-locals')
+
+  dex_cmd += paths
+
+  record_path = '%s.md5.stamp' % options.dex_path
+  md5_check.CallAndRecordIfStale(
+      lambda: build_utils.CheckOutput(dex_cmd, print_stderr=False),
+      record_path=record_path,
+      input_paths=paths,
+      input_strings=dex_cmd,
+      force=not os.path.exists(options.dex_path))
+  build_utils.WriteJson(paths, options.dex_path + '.inputs')
+
+
+def main():
+  args = build_utils.ExpandFileArgs(sys.argv[1:])
+
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--android-sdk-tools',
+                    help='Android sdk build tools directory.')
+  parser.add_option('--dex-path', help='Dex output path.')
+  parser.add_option('--configuration-name',
+                    help='The build CONFIGURATION_NAME.')
+  parser.add_option('--proguard-enabled',
+                    help='"true" if proguard is enabled.')
+  parser.add_option('--proguard-enabled-input-path',
+                    help=('Path to dex in Release mode when proguard '
+                          'is enabled.'))
+  parser.add_option('--no-locals',
+                    help='Exclude locals list from the dex file.')
+  parser.add_option('--inputs', help='A list of additional input paths.')
+  parser.add_option('--excluded-paths',
+                    help='A list of paths to exclude from the dex file.')
+
+  options, paths = parser.parse_args(args)
+
+  required_options = ('android_sdk_tools',)
+  build_utils.CheckOptions(options, parser, required=required_options)
+
+  if (options.proguard_enabled == 'true'
+      and options.configuration_name == 'Release'):
+    paths = [options.proguard_enabled_input_path]
+
+  if options.inputs:
+    paths += build_utils.ParseGypList(options.inputs)
+
+  if options.excluded_paths:
+    exclude_paths = build_utils.ParseGypList(options.excluded_paths)
+    paths = [p for p in paths if not p in exclude_paths]
+
+  DoDex(options, paths)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        paths + build_utils.GetPythonDependencies())
+
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/emma_instr.py b/build/android/gyp/emma_instr.py
new file mode 100755
index 0000000..6f3555a
--- /dev/null
+++ b/build/android/gyp/emma_instr.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Instruments classes and jar files.
+
+This script corresponds to the 'emma_instr' action in the java build process.
+Depending on whether emma_instrument is set, the 'emma_instr' action will either
+call one of the instrument commands, or the copy command.
+
+Possible commands are:
+- instrument_jar: Accepts a jar and instruments it using emma.jar.
+- instrument_classes: Accepts a directory containing java classes and
+      instruments it using emma.jar.
+- copy: Called when EMMA coverage is not enabled. This allows us to make
+      this a required step without necessarily instrumenting on every build.
+      Also removes any stale coverage files.
+"""
+
+import collections
+import json
+import os
+import shutil
+import sys
+import tempfile
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from pylib.utils import command_option_parser
+
+from util import build_utils
+
+
+def _AddCommonOptions(option_parser):
+  """Adds common options to |option_parser|."""
+  option_parser.add_option('--input-path',
+                           help=('Path to input file(s). Either the classes '
+                                 'directory, or the path to a jar.'))
+  option_parser.add_option('--output-path',
+                           help=('Path to output final file(s) to. Either the '
+                                 'final classes directory, or the directory in '
+                                 'which to place the instrumented/copied jar.'))
+  option_parser.add_option('--stamp', help='Path to touch when done.')
+  option_parser.add_option('--coverage-file',
+                           help='File to create with coverage metadata.')
+  option_parser.add_option('--sources-file',
+                           help='File to create with the list of sources.')
+
+
+def _AddInstrumentOptions(option_parser):
+  """Adds options related to instrumentation to |option_parser|."""
+  _AddCommonOptions(option_parser)
+  option_parser.add_option('--sources',
+                           help='Space separated list of sources.')
+  option_parser.add_option('--src-root',
+                           help='Root of the src repository.')
+  option_parser.add_option('--emma-jar',
+                           help='Path to emma.jar.')
+  option_parser.add_option(
+      '--filter-string', default='',
+      help=('Filter string consisting of a list of inclusion/exclusion '
+            'patterns separated with whitespace and/or comma.'))
+
+
+def _RunCopyCommand(_command, options, _, option_parser):
+  """Copies the jar from input to output locations.
+
+  Also removes any old coverage/sources file.
+
+  Args:
+    command: String indicating the command that was received to trigger
+        this function.
+    options: optparse options dictionary.
+    args: List of extra args from optparse.
+    option_parser: optparse.OptionParser object.
+
+  Returns:
+    An exit code.
+  """
+  if not (options.input_path and options.output_path and
+          options.coverage_file and options.sources_file):
+    option_parser.error('All arguments are required.')
+
+  coverage_file = os.path.join(os.path.dirname(options.output_path),
+                               options.coverage_file)
+  sources_file = os.path.join(os.path.dirname(options.output_path),
+                              options.sources_file)
+  if os.path.exists(coverage_file):
+    os.remove(coverage_file)
+  if os.path.exists(sources_file):
+    os.remove(sources_file)
+
+  if os.path.isdir(options.input_path):
+    shutil.rmtree(options.output_path, ignore_errors=True)
+    shutil.copytree(options.input_path, options.output_path)
+  else:
+    shutil.copy(options.input_path, options.output_path)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+def _CreateSourcesFile(sources_string, sources_file, src_root):
+  """Adds all normalized source directories to |sources_file|.
+
+  Args:
+    sources_string: String generated from gyp containing the list of sources.
+    sources_file: File into which to write the JSON list of sources.
+    src_root: Root which sources added to the file should be relative to.
+
+  Returns:
+    An exit code.
+  """
+  src_root = os.path.abspath(src_root)
+  sources = build_utils.ParseGypList(sources_string)
+  relative_sources = []
+  for s in sources:
+    abs_source = os.path.abspath(s)
+    if abs_source[:len(src_root)] != src_root:
+      print ('Error: found source directory not under repository root: %s %s'
+             % (abs_source, src_root))
+      return 1
+    rel_source = os.path.relpath(abs_source, src_root)
+
+    relative_sources.append(rel_source)
+
+  with open(sources_file, 'w') as f:
+    json.dump(relative_sources, f)
+
+
+def _RunInstrumentCommand(command, options, _, option_parser):
+  """Instruments the classes/jar files using EMMA.
+
+  Args:
+    command: 'instrument_jar' or 'instrument_classes'. This distinguishes
+        whether we copy the output from the created lib/ directory, or classes/
+        directory.
+    options: optparse options dictionary.
+    args: List of extra args from optparse.
+    option_parser: optparse.OptionParser object.
+
+  Returns:
+    An exit code.
+  """
+  if not (options.input_path and options.output_path and
+          options.coverage_file and options.sources_file and options.sources and
+          options.src_root and options.emma_jar):
+    option_parser.error('All arguments are required.')
+
+  coverage_file = os.path.join(os.path.dirname(options.output_path),
+                               options.coverage_file)
+  sources_file = os.path.join(os.path.dirname(options.output_path),
+                              options.sources_file)
+  if os.path.exists(coverage_file):
+    os.remove(coverage_file)
+  temp_dir = tempfile.mkdtemp()
+  try:
+    cmd = ['java', '-cp', options.emma_jar,
+           'emma', 'instr',
+           '-ip', options.input_path,
+           '-ix', options.filter_string,
+           '-d', temp_dir,
+           '-out', coverage_file,
+           '-m', 'fullcopy']
+    build_utils.CheckOutput(cmd)
+
+    if command == 'instrument_jar':
+      for jar in os.listdir(os.path.join(temp_dir, 'lib')):
+        shutil.copy(os.path.join(temp_dir, 'lib', jar),
+                    options.output_path)
+    else:  # 'instrument_classes'
+      if os.path.isdir(options.output_path):
+        shutil.rmtree(options.output_path, ignore_errors=True)
+      shutil.copytree(os.path.join(temp_dir, 'classes'),
+                      options.output_path)
+  finally:
+    shutil.rmtree(temp_dir)
+
+  _CreateSourcesFile(options.sources, sources_file, options.src_root)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+  return 0
+
+
+CommandFunctionTuple = collections.namedtuple(
+    'CommandFunctionTuple', ['add_options_func', 'run_command_func'])
+VALID_COMMANDS = {
+    'copy': CommandFunctionTuple(_AddCommonOptions,
+                                 _RunCopyCommand),
+    'instrument_jar': CommandFunctionTuple(_AddInstrumentOptions,
+                                           _RunInstrumentCommand),
+    'instrument_classes': CommandFunctionTuple(_AddInstrumentOptions,
+                                               _RunInstrumentCommand),
+}
+
+
+def main():
+  option_parser = command_option_parser.CommandOptionParser(
+      commands_dict=VALID_COMMANDS)
+  command_option_parser.ParseAndExecute(option_parser)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/finalize_apk.py b/build/android/gyp/finalize_apk.py
new file mode 100755
index 0000000..5416008
--- /dev/null
+++ b/build/android/gyp/finalize_apk.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Signs and zipaligns APK.
+
+"""
+
+import optparse
+import shutil
+import sys
+import tempfile
+
+from util import build_utils
+
+def RenameInflateAndAddPageAlignment(
+    rezip_apk_jar_path, in_zip_file, out_zip_file):
+  rezip_apk_cmd = [
+      'java',
+      '-classpath',
+      rezip_apk_jar_path,
+      'RezipApk',
+      'renamealign',
+      in_zip_file,
+      out_zip_file,
+    ]
+  build_utils.CheckOutput(rezip_apk_cmd)
+
+
+def ReorderAndAlignApk(rezip_apk_jar_path, in_zip_file, out_zip_file):
+  rezip_apk_cmd = [
+      'java',
+      '-classpath',
+      rezip_apk_jar_path,
+      'RezipApk',
+      'reorder',
+      in_zip_file,
+      out_zip_file,
+    ]
+  build_utils.CheckOutput(rezip_apk_cmd)
+
+
+def JarSigner(key_path, key_name, key_passwd, unsigned_path, signed_path):
+  shutil.copy(unsigned_path, signed_path)
+  sign_cmd = [
+      'jarsigner',
+      '-sigalg', 'MD5withRSA',
+      '-digestalg', 'SHA1',
+      '-keystore', key_path,
+      '-storepass', key_passwd,
+      signed_path,
+      key_name,
+    ]
+  build_utils.CheckOutput(sign_cmd)
+
+
+def AlignApk(zipalign_path, unaligned_path, final_path):
+  align_cmd = [
+      zipalign_path,
+      '-f', '4',  # 4 bytes
+      unaligned_path,
+      final_path,
+      ]
+  build_utils.CheckOutput(align_cmd)
+
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--rezip-apk-jar-path',
+                    help='Path to the RezipApk jar file.')
+  parser.add_option('--zipalign-path', help='Path to the zipalign tool.')
+  parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.')
+  parser.add_option('--final-apk-path',
+      help='Path to output signed and aligned APK.')
+  parser.add_option('--key-path', help='Path to keystore for signing.')
+  parser.add_option('--key-passwd', help='Keystore password')
+  parser.add_option('--key-name', help='Keystore name')
+  parser.add_option('--stamp', help='Path to touch on success.')
+  parser.add_option('--load-library-from-zip-file', type='int',
+      help='If non-zero, build the APK such that the library can be loaded ' +
+           'directly from the zip file using the crazy linker. The library ' +
+           'will be renamed, uncompressed and page aligned.')
+
+  options, _ = parser.parse_args()
+
+  with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \
+      tempfile.NamedTemporaryFile() as apk_to_sign_tmp:
+
+    if options.load_library_from_zip_file:
+      # We alter the name of the library so that the Android Package Manager
+      # does not extract it into a separate file. This must be done before
+      # signing, as the filename is part of the signed manifest. At the same
+      # time we uncompress the library, which is necessary so that it can be
+      # loaded directly from the APK.
+      # Move the library to a page boundary by adding a page alignment file.
+      apk_to_sign = apk_to_sign_tmp.name
+      RenameInflateAndAddPageAlignment(
+          options.rezip_apk_jar_path, options.unsigned_apk_path, apk_to_sign)
+    else:
+      apk_to_sign = options.unsigned_apk_path
+
+    signed_apk_path = signed_apk_path_tmp.name
+    JarSigner(options.key_path, options.key_name, options.key_passwd,
+              apk_to_sign, signed_apk_path)
+
+    if options.load_library_from_zip_file:
+      # Reorder the contents of the APK. This re-establishes the canonical
+      # order which means the library will be back at its page aligned location.
+      # This step also aligns uncompressed items to 4 bytes.
+      ReorderAndAlignApk(
+          options.rezip_apk_jar_path, signed_apk_path, options.final_apk_path)
+    else:
+      # Align uncompressed items to 4 bytes
+      AlignApk(options.zipalign_path, signed_apk_path, options.final_apk_path)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile, build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/find.py b/build/android/gyp/find.py
new file mode 100755
index 0000000..a9f1d49
--- /dev/null
+++ b/build/android/gyp/find.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Finds files in directories.
+"""
+
+import fnmatch
+import optparse
+import os
+import sys
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('--pattern', default='*', help='File pattern to match.')
+  options, directories = parser.parse_args(argv)
+
+  for d in directories:
+    if not os.path.exists(d):
+      print >> sys.stderr, '%s does not exist' % d
+      return 1
+    for root, _, filenames in os.walk(d):
+      for f in fnmatch.filter(filenames, options.pattern):
+        print os.path.join(root, f)
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/gcc_preprocess.py b/build/android/gyp/gcc_preprocess.py
new file mode 100755
index 0000000..03becf9
--- /dev/null
+++ b/build/android/gyp/gcc_preprocess.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+def DoGcc(options):
+  build_utils.MakeDirectory(os.path.dirname(options.output))
+
+  gcc_cmd = [ 'gcc' ]  # invoke host gcc.
+  if options.defines:
+    gcc_cmd.extend(sum(map(lambda w: ['-D', w], options.defines), []))
+  gcc_cmd.extend([
+      '-E',                  # stop after preprocessing.
+      '-D', 'ANDROID',       # Specify ANDROID define for pre-processor.
+      '-x', 'c-header',      # treat sources as C header files
+      '-P',                  # disable line markers, i.e. '#line 309'
+      '-I', options.include_path,
+      '-o', options.output,
+      options.template
+      ])
+
+  build_utils.CheckOutput(gcc_cmd)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--include-path', help='Include path for gcc.')
+  parser.add_option('--template', help='Path to template.')
+  parser.add_option('--output', help='Path for generated file.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+  parser.add_option('--defines', help='Pre-defines macros', action='append')
+
+  options, _ = parser.parse_args(args)
+
+  DoGcc(options)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/generate_v14_compatible_resources.py b/build/android/gyp/generate_v14_compatible_resources.py
new file mode 100755
index 0000000..7818170
--- /dev/null
+++ b/build/android/gyp/generate_v14_compatible_resources.py
@@ -0,0 +1,359 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Convert Android xml resources to API 14 compatible.
+
+There are two reasons that we cannot just use API 17 attributes,
+so we are generating another set of resources by this script.
+
+1. paddingStart attribute can cause a crash on Galaxy Tab 2.
+2. There is a bug that paddingStart does not override paddingLeft on
+   JB-MR1. This is fixed on JB-MR2. b/8654490
+
+Therefore, this resource generation script can be removed when
+we drop the support for JB-MR1.
+
+Please refer to http://crbug.com/235118 for the details.
+"""
+
+import optparse
+import os
+import re
+import shutil
+import sys
+import xml.dom.minidom as minidom
+
+from util import build_utils
+
+# Note that we are assuming 'android:' is an alias of
+# the namespace 'http://schemas.android.com/apk/res/android'.
+
+GRAVITY_ATTRIBUTES = ('android:gravity', 'android:layout_gravity')
+
+# Almost all the attributes that has "Start" or "End" in
+# its name should be mapped.
+ATTRIBUTES_TO_MAP = {'paddingStart' : 'paddingLeft',
+                     'drawableStart' : 'drawableLeft',
+                     'layout_alignStart' : 'layout_alignLeft',
+                     'layout_marginStart' : 'layout_marginLeft',
+                     'layout_alignParentStart' : 'layout_alignParentLeft',
+                     'layout_toStartOf' : 'layout_toLeftOf',
+                     'paddingEnd' : 'paddingRight',
+                     'drawableEnd' : 'drawableRight',
+                     'layout_alignEnd' : 'layout_alignRight',
+                     'layout_marginEnd' : 'layout_marginRight',
+                     'layout_alignParentEnd' : 'layout_alignParentRight',
+                     'layout_toEndOf' : 'layout_toRightOf'}
+
+ATTRIBUTES_TO_MAP = dict(['android:' + k, 'android:' + v] for k, v
+                         in ATTRIBUTES_TO_MAP.iteritems())
+
+ATTRIBUTES_TO_MAP_REVERSED = dict([v, k] for k, v
+                                  in ATTRIBUTES_TO_MAP.iteritems())
+
+
+def IterateXmlElements(node):
+  """minidom helper function that iterates all the element nodes.
+  Iteration order is pre-order depth-first."""
+  if node.nodeType == node.ELEMENT_NODE:
+    yield node
+  for child_node in node.childNodes:
+    for child_node_element in IterateXmlElements(child_node):
+      yield child_node_element
+
+
+def ParseAndReportErrors(filename):
+  try:
+    return minidom.parse(filename)
+  except Exception:
+    import traceback
+    traceback.print_exc()
+    sys.stderr.write('Failed to parse XML file: %s\n' % filename)
+    sys.exit(1)
+
+
+def AssertNotDeprecatedAttribute(name, value, filename):
+  """Raises an exception if the given attribute is deprecated."""
+  msg = None
+  if name in ATTRIBUTES_TO_MAP_REVERSED:
+    msg = '{0} should use {1} instead of {2}'.format(filename,
+        ATTRIBUTES_TO_MAP_REVERSED[name], name)
+  elif name in GRAVITY_ATTRIBUTES and ('left' in value or 'right' in value):
+    msg = '{0} should use start/end instead of left/right for {1}'.format(
+        filename, name)
+
+  if msg:
+    msg += ('\nFor background, see: http://android-developers.blogspot.com/'
+            '2013/03/native-rtl-support-in-android-42.html\n'
+            'If you have a legitimate need for this attribute, discuss with '
+            'kkimlabs@chromium.org or newt@chromium.org')
+    raise Exception(msg)
+
+
+def WriteDomToFile(dom, filename):
+  """Write the given dom to filename."""
+  build_utils.MakeDirectory(os.path.dirname(filename))
+  with open(filename, 'w') as f:
+    dom.writexml(f, '', '  ', '\n', encoding='utf-8')
+
+
+def HasStyleResource(dom):
+  """Return True if the dom is a style resource, False otherwise."""
+  root_node = IterateXmlElements(dom).next()
+  return bool(root_node.nodeName == 'resources' and
+              list(root_node.getElementsByTagName('style')))
+
+
+def ErrorIfStyleResourceExistsInDir(input_dir):
+  """If a style resource is in input_dir, raises an exception."""
+  for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'):
+    dom = ParseAndReportErrors(input_filename)
+    if HasStyleResource(dom):
+      raise Exception('error: style file ' + input_filename +
+                      ' should be under ' + input_dir +
+                      '-v17 directory. Please refer to '
+                      'http://crbug.com/243952 for the details.')
+
+
+def GenerateV14LayoutResourceDom(dom, filename, assert_not_deprecated=True):
+  """Convert layout resource to API 14 compatible layout resource.
+
+  Args:
+    dom: Parsed minidom object to be modified.
+    filename: Filename that the DOM was parsed from.
+    assert_not_deprecated: Whether deprecated attributes (e.g. paddingLeft) will
+                           cause an exception to be thrown.
+
+  Returns:
+    True if dom is modified, False otherwise.
+  """
+  is_modified = False
+
+  # Iterate all the elements' attributes to find attributes to convert.
+  for element in IterateXmlElements(dom):
+    for name, value in list(element.attributes.items()):
+      # Convert any API 17 Start/End attributes to Left/Right attributes.
+      # For example, from paddingStart="10dp" to paddingLeft="10dp"
+      # Note: gravity attributes are not necessary to convert because
+      # start/end values are backward-compatible. Explained at
+      # https://plus.sandbox.google.com/+RomanNurik/posts/huuJd8iVVXY?e=Showroom
+      if name in ATTRIBUTES_TO_MAP:
+        element.setAttribute(ATTRIBUTES_TO_MAP[name], value)
+        del element.attributes[name]
+        is_modified = True
+      elif assert_not_deprecated:
+        AssertNotDeprecatedAttribute(name, value, filename)
+
+  return is_modified
+
+
+def GenerateV14StyleResourceDom(dom, filename, assert_not_deprecated=True):
+  """Convert style resource to API 14 compatible style resource.
+
+  Args:
+    dom: Parsed minidom object to be modified.
+    filename: Filename that the DOM was parsed from.
+    assert_not_deprecated: Whether deprecated attributes (e.g. paddingLeft) will
+                           cause an exception to be thrown.
+
+  Returns:
+    True if dom is modified, False otherwise.
+  """
+  is_modified = False
+
+  for style_element in dom.getElementsByTagName('style'):
+    for item_element in style_element.getElementsByTagName('item'):
+      name = item_element.attributes['name'].value
+      value = item_element.childNodes[0].nodeValue
+      if name in ATTRIBUTES_TO_MAP:
+        item_element.attributes['name'].value = ATTRIBUTES_TO_MAP[name]
+        is_modified = True
+      elif assert_not_deprecated:
+        AssertNotDeprecatedAttribute(name, value, filename)
+
+  return is_modified
+
+
+def GenerateV14LayoutResource(input_filename, output_v14_filename,
+                              output_v17_filename):
+  """Convert API 17 layout resource to API 14 compatible layout resource.
+
+  It's mostly a simple replacement, s/Start/Left s/End/Right,
+  on the attribute names.
+  If the generated resource is identical to the original resource,
+  don't do anything. If not, write the generated resource to
+  output_v14_filename, and copy the original resource to output_v17_filename.
+  """
+  dom = ParseAndReportErrors(input_filename)
+  is_modified = GenerateV14LayoutResourceDom(dom, input_filename)
+
+  if is_modified:
+    # Write the generated resource.
+    WriteDomToFile(dom, output_v14_filename)
+
+    # Copy the original resource.
+    build_utils.MakeDirectory(os.path.dirname(output_v17_filename))
+    shutil.copy2(input_filename, output_v17_filename)
+
+
+def GenerateV14StyleResource(input_filename, output_v14_filename):
+  """Convert API 17 style resources to API 14 compatible style resource.
+
+  Write the generated style resource to output_v14_filename.
+  It's mostly a simple replacement, s/Start/Left s/End/Right,
+  on the attribute names.
+  """
+  dom = ParseAndReportErrors(input_filename)
+  GenerateV14StyleResourceDom(dom, input_filename)
+
+  # Write the generated resource.
+  WriteDomToFile(dom, output_v14_filename)
+
+
+def GenerateV14LayoutResourcesInDir(input_dir, output_v14_dir, output_v17_dir):
+  """Convert layout resources to API 14 compatible resources in input_dir."""
+  for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'):
+    rel_filename = os.path.relpath(input_filename, input_dir)
+    output_v14_filename = os.path.join(output_v14_dir, rel_filename)
+    output_v17_filename = os.path.join(output_v17_dir, rel_filename)
+    GenerateV14LayoutResource(input_filename, output_v14_filename,
+                              output_v17_filename)
+
+
+def GenerateV14StyleResourcesInDir(input_dir, output_v14_dir):
+  """Convert style resources to API 14 compatible resources in input_dir."""
+  for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'):
+    rel_filename = os.path.relpath(input_filename, input_dir)
+    output_v14_filename = os.path.join(output_v14_dir, rel_filename)
+    GenerateV14StyleResource(input_filename, output_v14_filename)
+
+
+def VerifyV14ResourcesInDir(input_dir, resource_type):
+  """Verify that the resources in input_dir is compatible with v14, i.e., they
+  don't use attributes that cause crashes on certain devices. Print an error if
+  they have."""
+  for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'):
+    exception_message = ('error : ' + input_filename + ' has an RTL attribute, '
+                        'i.e., attribute that has "start" or "end" in its name.'
+                        ' Pre-v17 resources should not include it because it '
+                        'can cause crashes on certain devices. Please refer to '
+                        'http://crbug.com/243952 for the details.')
+    dom = ParseAndReportErrors(input_filename)
+    if resource_type in ('layout', 'xml'):
+      if GenerateV14LayoutResourceDom(dom, input_filename, False):
+        raise Exception(exception_message)
+    elif resource_type == 'values':
+      if GenerateV14StyleResourceDom(dom, input_filename, False):
+        raise Exception(exception_message)
+
+
+def AssertNoDeprecatedAttributesInDir(input_dir, resource_type):
+  """Raises an exception if resources in input_dir have deprecated attributes,
+  e.g., paddingLeft, paddingRight"""
+  for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'):
+    dom = ParseAndReportErrors(input_filename)
+    if resource_type in ('layout', 'xml'):
+      GenerateV14LayoutResourceDom(dom, input_filename)
+    elif resource_type == 'values':
+      GenerateV14StyleResourceDom(dom, input_filename)
+
+
+def ParseArgs():
+  """Parses command line options.
+
+  Returns:
+    An options object as from optparse.OptionsParser.parse_args()
+  """
+  parser = optparse.OptionParser()
+  parser.add_option('--res-dir',
+                    help='directory containing resources '
+                         'used to generate v14 compatible resources')
+  parser.add_option('--res-v14-compatibility-dir',
+                    help='output directory into which '
+                         'v14 compatible resources will be generated')
+  parser.add_option('--stamp', help='File to touch on success')
+  parser.add_option('--verify-only', action="store_true", help='Do not generate'
+      ' v14 resources. Instead, just verify that the resources are already '
+      "compatible with v14, i.e. they don't use attributes that cause crashes "
+      'on certain devices.')
+
+  options, args = parser.parse_args()
+
+  if args:
+    parser.error('No positional arguments should be given.')
+
+  # Check that required options have been provided.
+  required_options = ('res_dir', 'res_v14_compatibility_dir')
+  build_utils.CheckOptions(options, parser, required=required_options)
+  return options
+
+def GenerateV14Resources(res_dir, res_v14_dir, verify_only):
+  for name in os.listdir(res_dir):
+    if not os.path.isdir(os.path.join(res_dir, name)):
+      continue
+
+    dir_pieces = name.split('-')
+    resource_type = dir_pieces[0]
+    qualifiers = dir_pieces[1:]
+
+    api_level_qualifier_index = -1
+    api_level_qualifier = ''
+    for index, qualifier in enumerate(qualifiers):
+      if re.match('v[0-9]+$', qualifier):
+        api_level_qualifier_index = index
+        api_level_qualifier = qualifier
+        break
+
+    # Android pre-v17 API doesn't support RTL. Skip.
+    if 'ldrtl' in qualifiers:
+      continue
+
+    input_dir = os.path.abspath(os.path.join(res_dir, name))
+
+    if verify_only:
+      if not api_level_qualifier or int(api_level_qualifier[1:]) < 17:
+        VerifyV14ResourcesInDir(input_dir, resource_type)
+      else:
+        AssertNoDeprecatedAttributesInDir(input_dir, resource_type)
+    else:
+      # We also need to copy the original v17 resource to *-v17 directory
+      # because the generated v14 resource will hide the original resource.
+      output_v14_dir = os.path.join(res_v14_dir, name)
+      output_v17_dir = os.path.join(res_v14_dir, name + '-v17')
+
+      # We only convert layout resources under layout*/, xml*/,
+      # and style resources under values*/.
+      if resource_type in ('layout', 'xml'):
+        if not api_level_qualifier:
+          GenerateV14LayoutResourcesInDir(input_dir, output_v14_dir,
+                                          output_v17_dir)
+      elif resource_type == 'values':
+        if api_level_qualifier == 'v17':
+          output_qualifiers = qualifiers[:]
+          del output_qualifiers[api_level_qualifier_index]
+          output_v14_dir = os.path.join(res_v14_dir,
+                                        '-'.join([resource_type] +
+                                                 output_qualifiers))
+          GenerateV14StyleResourcesInDir(input_dir, output_v14_dir)
+        elif not api_level_qualifier:
+          ErrorIfStyleResourceExistsInDir(input_dir)
+
+def main():
+  options = ParseArgs()
+
+  res_v14_dir = options.res_v14_compatibility_dir
+
+  build_utils.DeleteDirectory(res_v14_dir)
+  build_utils.MakeDirectory(res_v14_dir)
+
+  GenerateV14Resources(options.res_dir, res_v14_dir, options.verify_only)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/gyp/get_device_configuration.py b/build/android/gyp/get_device_configuration.py
new file mode 100755
index 0000000..390eb2f
--- /dev/null
+++ b/build/android/gyp/get_device_configuration.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Gets and writes the configurations of the attached devices.
+
+This configuration is used by later build steps to determine which devices to
+install to and what needs to be installed to those devices.
+"""
+
+import optparse
+import sys
+
+from util import build_utils
+from util import build_device
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('--stamp', action='store')
+  parser.add_option('--output', action='store')
+  options, _ = parser.parse_args(argv)
+
+  devices = build_device.GetAttachedDevices()
+
+  device_configurations = []
+  for d in devices:
+    configuration, is_online, has_root = (
+        build_device.GetConfigurationForDevice(d))
+
+    if not is_online:
+      build_utils.PrintBigWarning(
+          '%s is not online. Skipping managed install for this device. '
+          'Try rebooting the device to fix this warning.' % d)
+      continue
+
+    if not has_root:
+      build_utils.PrintBigWarning(
+          '"adb root" failed on device: %s\n'
+          'Skipping managed install for this device.'
+          % configuration['description'])
+      continue
+
+    device_configurations.append(configuration)
+
+  if len(device_configurations) == 0:
+    build_utils.PrintBigWarning(
+        'No valid devices attached. Skipping managed install steps.')
+  elif len(devices) > 1:
+    # Note that this checks len(devices) and not len(device_configurations).
+    # This way, any time there are multiple devices attached it is
+    # explicitly stated which device we will install things to even if all but
+    # one device were rejected for other reasons (e.g. two devices attached,
+    # one w/o root).
+    build_utils.PrintBigWarning(
+        'Multiple devices attached. '
+        'Installing to the preferred device: '
+        '%(id)s (%(description)s)' % (device_configurations[0]))
+
+
+  build_device.WriteConfigurations(device_configurations, options.output)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/gyp/insert_chromium_version.py b/build/android/gyp/insert_chromium_version.py
new file mode 100755
index 0000000..171f9d4
--- /dev/null
+++ b/build/android/gyp/insert_chromium_version.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Insert a version string into a library as a section '.chromium.version'.
+"""
+
+import optparse
+import os
+import sys
+import tempfile
+
+from util import build_utils
+
+def InsertChromiumVersion(android_objcopy,
+                          library_path,
+                          version_string):
+  # Remove existing .chromium.version section from .so
+  objcopy_command = [android_objcopy,
+                     '--remove-section=.chromium.version',
+                     library_path]
+  build_utils.CheckOutput(objcopy_command)
+
+  # Add a .chromium.version section.
+  with tempfile.NamedTemporaryFile() as stream:
+    stream.write(version_string)
+    stream.flush()
+    objcopy_command = [android_objcopy,
+                       '--add-section', '.chromium.version=%s' % stream.name,
+                       library_path]
+    build_utils.CheckOutput(objcopy_command)
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = optparse.OptionParser()
+
+  parser.add_option('--android-objcopy',
+      help='Path to the toolchain\'s objcopy binary')
+  parser.add_option('--stripped-libraries-dir',
+      help='Directory of native libraries')
+  parser.add_option('--libraries',
+      help='List of libraries')
+  parser.add_option('--version-string',
+      help='Version string to be inserted')
+  parser.add_option('--stamp', help='Path to touch on success')
+
+  options, _ = parser.parse_args(args)
+  libraries = build_utils.ParseGypList(options.libraries)
+
+  for library in libraries:
+    library_path = os.path.join(options.stripped_libraries_dir, library)
+
+    InsertChromiumVersion(options.android_objcopy,
+                          library_path,
+                          options.version_string)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/jar.py b/build/android/gyp/jar.py
new file mode 100755
index 0000000..17f968c
--- /dev/null
+++ b/build/android/gyp/jar.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import fnmatch
+import optparse
+import os
+import sys
+
+from util import build_utils
+from util import md5_check
+
+
+def Jar(class_files, classes_dir, jar_path, manifest_file=None):
+  jar_path = os.path.abspath(jar_path)
+
+  # The paths of the files in the jar will be the same as they are passed in to
+  # the command. Because of this, the command should be run in
+  # options.classes_dir so the .class file paths in the jar are correct.
+  jar_cwd = classes_dir
+  class_files_rel = [os.path.relpath(f, jar_cwd) for f in class_files]
+  jar_cmd = ['jar', 'cf0', jar_path]
+  if manifest_file:
+    jar_cmd[1] += 'm'
+    jar_cmd.append(os.path.abspath(manifest_file))
+  jar_cmd.extend(class_files_rel)
+
+  record_path = '%s.md5.stamp' % jar_path
+  md5_check.CallAndRecordIfStale(
+      lambda: build_utils.CheckOutput(jar_cmd, cwd=jar_cwd),
+      record_path=record_path,
+      input_paths=class_files,
+      input_strings=jar_cmd,
+      force=not os.path.exists(jar_path),
+      )
+
+  build_utils.Touch(jar_path, fail_if_missing=True)
+
+
+def JarDirectory(classes_dir, excluded_classes, jar_path, manifest_file=None):
+  class_files = build_utils.FindInDirectory(classes_dir, '*.class')
+  for exclude in excluded_classes:
+    class_files = filter(
+        lambda f: not fnmatch.fnmatch(f, exclude), class_files)
+
+  Jar(class_files, classes_dir, jar_path, manifest_file=manifest_file)
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--classes-dir', help='Directory containing .class files.')
+  parser.add_option('--jar-path', help='Jar output path.')
+  parser.add_option('--excluded-classes',
+      help='List of .class file patterns to exclude from the jar.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  options, _ = parser.parse_args()
+
+  if options.excluded_classes:
+    excluded_classes = build_utils.ParseGypList(options.excluded_classes)
+  else:
+    excluded_classes = []
+  JarDirectory(options.classes_dir,
+               excluded_classes,
+               options.jar_path)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/build/android/gyp/jar_toc.py b/build/android/gyp/jar_toc.py
new file mode 100755
index 0000000..3cafd6e
--- /dev/null
+++ b/build/android/gyp/jar_toc.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Creates a TOC file from a Java jar.
+
+The TOC file contains the non-package API of the jar. This includes all
+public/protected/package classes/functions/members and the values of static
+final variables (members with package access are kept because in some cases we
+have multiple libraries with the same package, particularly test+non-test). Some
+other information (major/minor javac version) is also included.
+
+This TOC file then can be used to determine if a dependent library should be
+rebuilt when this jar changes. I.e. any change to the jar that would require a
+rebuild, will have a corresponding change in the TOC file.
+"""
+
+import optparse
+import os
+import re
+import sys
+import zipfile
+
+from util import build_utils
+from util import md5_check
+
+
+def GetClassesInZipFile(zip_file):
+  classes = []
+  files = zip_file.namelist()
+  for f in files:
+    if f.endswith('.class'):
+      # f is of the form org/chromium/base/Class$Inner.class
+      classes.append(f.replace('/', '.')[:-6])
+  return classes
+
+
+def CallJavap(classpath, classes):
+  javap_cmd = [
+      'javap',
+      '-package',  # Show public/protected/package.
+      # -verbose is required to get constant values (which can be inlined in
+      # dependents).
+      '-verbose',
+      '-classpath', classpath
+      ] + classes
+  return build_utils.CheckOutput(javap_cmd)
+
+
+def ExtractToc(disassembled_classes):
+  # javap output is structured by indent (2-space) levels.
+  good_patterns = [
+      '^[^ ]', # This includes all class/function/member signatures.
+      '^  SourceFile:',
+      '^  minor version:',
+      '^  major version:',
+      '^  Constant value:',
+      ]
+  bad_patterns = [
+      '^const #', # Matches the constant pool (i.e. literals used in the class).
+    ]
+
+  def JavapFilter(line):
+    return (re.match('|'.join(good_patterns), line) and
+        not re.match('|'.join(bad_patterns), line))
+  toc = filter(JavapFilter, disassembled_classes.split('\n'))
+
+  return '\n'.join(toc)
+
+
+def UpdateToc(jar_path, toc_path):
+  classes = GetClassesInZipFile(zipfile.ZipFile(jar_path))
+  javap_output = CallJavap(classpath=jar_path, classes=classes)
+  toc = ExtractToc(javap_output)
+
+  with open(toc_path, 'w') as tocfile:
+    tocfile.write(toc)
+
+
+def DoJarToc(options):
+  jar_path = options.jar_path
+  toc_path = options.toc_path
+  record_path = '%s.md5.stamp' % toc_path
+  md5_check.CallAndRecordIfStale(
+      lambda: UpdateToc(jar_path, toc_path),
+      record_path=record_path,
+      input_paths=[jar_path],
+      force=not os.path.exists(toc_path),
+      )
+  build_utils.Touch(toc_path, fail_if_missing=True)
+
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--jar-path', help='Input .jar path.')
+  parser.add_option('--toc-path', help='Output .jar.TOC path.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  options, _ = parser.parse_args()
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+  DoJarToc(options)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py
new file mode 100755
index 0000000..1603959
--- /dev/null
+++ b/build/android/gyp/java_cpp_enum.py
@@ -0,0 +1,336 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium 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 collections
+import re
+import optparse
+import os
+from string import Template
+import sys
+
+from util import build_utils
+
+# List of C++ types that are compatible with the Java code generated by this
+# script.
+ENUM_FIXED_TYPE_WHITELIST = ['char', 'unsigned char',
+  'short', 'unsigned short',
+  'int', 'int8_t', 'int16_t', 'int32_t', 'uint8_t', 'uint16_t']
+
+class EnumDefinition(object):
+  def __init__(self, original_enum_name=None, class_name_override=None,
+               enum_package=None, entries=None, fixed_type=None):
+    self.original_enum_name = original_enum_name
+    self.class_name_override = class_name_override
+    self.enum_package = enum_package
+    self.entries = collections.OrderedDict(entries or [])
+    self.prefix_to_strip = None
+    self.fixed_type = fixed_type
+
+  def AppendEntry(self, key, value):
+    if key in self.entries:
+      raise Exception('Multiple definitions of key %s found.' % key)
+    self.entries[key] = value
+
+  @property
+  def class_name(self):
+    return self.class_name_override or self.original_enum_name
+
+  def Finalize(self):
+    self._Validate()
+    self._AssignEntryIndices()
+    self._StripPrefix()
+
+  def _Validate(self):
+    assert self.class_name
+    assert self.enum_package
+    assert self.entries
+    if self.fixed_type and self.fixed_type not in ENUM_FIXED_TYPE_WHITELIST:
+      raise Exception('Fixed type %s for enum %s not whitelisted.' %
+          (self.fixed_type, self.class_name))
+
+  def _AssignEntryIndices(self):
+    # Enums, if given no value, are given the value of the previous enum + 1.
+    if not all(self.entries.values()):
+      prev_enum_value = -1
+      for key, value in self.entries.iteritems():
+        if not value:
+          self.entries[key] = prev_enum_value + 1
+        elif value in self.entries:
+          self.entries[key] = self.entries[value]
+        else:
+          try:
+            self.entries[key] = int(value)
+          except ValueError:
+            raise Exception('Could not interpret integer from enum value "%s" '
+                            'for key %s.' % (value, key))
+        prev_enum_value = self.entries[key]
+
+
+  def _StripPrefix(self):
+    prefix_to_strip = self.prefix_to_strip
+    if not prefix_to_strip:
+      prefix_to_strip = self.original_enum_name
+      prefix_to_strip = re.sub('(?!^)([A-Z]+)', r'_\1', prefix_to_strip).upper()
+      prefix_to_strip += '_'
+      if not all([w.startswith(prefix_to_strip) for w in self.entries.keys()]):
+        prefix_to_strip = ''
+
+    entries = collections.OrderedDict()
+    for (k, v) in self.entries.iteritems():
+      stripped_key = k.replace(prefix_to_strip, '', 1)
+      if isinstance(v, basestring):
+        stripped_value = v.replace(prefix_to_strip, '', 1)
+      else:
+        stripped_value = v
+      entries[stripped_key] = stripped_value
+
+    self.entries = entries
+
+class DirectiveSet(object):
+  class_name_override_key = 'CLASS_NAME_OVERRIDE'
+  enum_package_key = 'ENUM_PACKAGE'
+  prefix_to_strip_key = 'PREFIX_TO_STRIP'
+
+  known_keys = [class_name_override_key, enum_package_key, prefix_to_strip_key]
+
+  def __init__(self):
+    self._directives = {}
+
+  def Update(self, key, value):
+    if key not in DirectiveSet.known_keys:
+      raise Exception("Unknown directive: " + key)
+    self._directives[key] = value
+
+  @property
+  def empty(self):
+    return len(self._directives) == 0
+
+  def UpdateDefinition(self, definition):
+    definition.class_name_override = self._directives.get(
+        DirectiveSet.class_name_override_key, '')
+    definition.enum_package = self._directives.get(
+        DirectiveSet.enum_package_key)
+    definition.prefix_to_strip = self._directives.get(
+        DirectiveSet.prefix_to_strip_key)
+
+
+class HeaderParser(object):
+  single_line_comment_re = re.compile(r'\s*//')
+  multi_line_comment_start_re = re.compile(r'\s*/\*')
+  enum_line_re = re.compile(r'^\s*(\w+)(\s*\=\s*([^,\n]+))?,?')
+  enum_end_re = re.compile(r'^\s*}\s*;\.*$')
+  generator_directive_re = re.compile(
+      r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*([\.\w]+)$')
+  multi_line_generator_directive_start_re = re.compile(
+      r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*\(([\.\w]*)$')
+  multi_line_directive_continuation_re = re.compile(
+      r'^\s*//\s+([\.\w]+)$')
+  multi_line_directive_end_re = re.compile(
+      r'^\s*//\s+([\.\w]*)\)$')
+
+  optional_class_or_struct_re = r'(class|struct)?'
+  enum_name_re = r'(\w+)'
+  optional_fixed_type_re = r'(\:\s*(\w+\s*\w+?))?'
+  enum_start_re = re.compile(r'^\s*enum\s+' + optional_class_or_struct_re +
+      '\s*' + enum_name_re + '\s*' + optional_fixed_type_re + '\s*{\s*$')
+
+  def __init__(self, lines, path=None):
+    self._lines = lines
+    self._path = path
+    self._enum_definitions = []
+    self._in_enum = False
+    self._current_definition = None
+    self._generator_directives = DirectiveSet()
+    self._multi_line_generator_directive = None
+
+  def _ApplyGeneratorDirectives(self):
+    self._generator_directives.UpdateDefinition(self._current_definition)
+    self._generator_directives = DirectiveSet()
+
+  def ParseDefinitions(self):
+    for line in self._lines:
+      self._ParseLine(line)
+    return self._enum_definitions
+
+  def _ParseLine(self, line):
+    if self._multi_line_generator_directive:
+      self._ParseMultiLineDirectiveLine(line)
+    elif not self._in_enum:
+      self._ParseRegularLine(line)
+    else:
+      self._ParseEnumLine(line)
+
+  def _ParseEnumLine(self, line):
+    if HeaderParser.single_line_comment_re.match(line):
+      return
+    if HeaderParser.multi_line_comment_start_re.match(line):
+      raise Exception('Multi-line comments in enums are not supported in ' +
+                      self._path)
+    enum_end = HeaderParser.enum_end_re.match(line)
+    enum_entry = HeaderParser.enum_line_re.match(line)
+    if enum_end:
+      self._ApplyGeneratorDirectives()
+      self._current_definition.Finalize()
+      self._enum_definitions.append(self._current_definition)
+      self._in_enum = False
+    elif enum_entry:
+      enum_key = enum_entry.groups()[0]
+      enum_value = enum_entry.groups()[2]
+      self._current_definition.AppendEntry(enum_key, enum_value)
+
+  def _ParseMultiLineDirectiveLine(self, line):
+    multi_line_directive_continuation = (
+        HeaderParser.multi_line_directive_continuation_re.match(line))
+    multi_line_directive_end = (
+        HeaderParser.multi_line_directive_end_re.match(line))
+
+    if multi_line_directive_continuation:
+      value_cont = multi_line_directive_continuation.groups()[0]
+      self._multi_line_generator_directive[1].append(value_cont)
+    elif multi_line_directive_end:
+      directive_name = self._multi_line_generator_directive[0]
+      directive_value = "".join(self._multi_line_generator_directive[1])
+      directive_value += multi_line_directive_end.groups()[0]
+      self._multi_line_generator_directive = None
+      self._generator_directives.Update(directive_name, directive_value)
+    else:
+      raise Exception('Malformed multi-line directive declaration in ' +
+                      self._path)
+
+  def _ParseRegularLine(self, line):
+    enum_start = HeaderParser.enum_start_re.match(line)
+    generator_directive = HeaderParser.generator_directive_re.match(line)
+    multi_line_generator_directive_start = (
+        HeaderParser.multi_line_generator_directive_start_re.match(line))
+
+    if generator_directive:
+      directive_name = generator_directive.groups()[0]
+      directive_value = generator_directive.groups()[1]
+      self._generator_directives.Update(directive_name, directive_value)
+    elif multi_line_generator_directive_start:
+      directive_name = multi_line_generator_directive_start.groups()[0]
+      directive_value = multi_line_generator_directive_start.groups()[1]
+      self._multi_line_generator_directive = (directive_name, [directive_value])
+    elif enum_start:
+      if self._generator_directives.empty:
+        return
+      self._current_definition = EnumDefinition(
+          original_enum_name=enum_start.groups()[1],
+          fixed_type=enum_start.groups()[3])
+      self._in_enum = True
+
+def GetScriptName():
+  script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
+  build_index = script_components.index('build')
+  return os.sep.join(script_components[build_index:])
+
+
+def DoGenerate(output_dir, source_paths, print_output_only=False):
+  output_paths = []
+  for source_path in source_paths:
+    enum_definitions = DoParseHeaderFile(source_path)
+    if not enum_definitions:
+      raise Exception('No enums found in %s\n'
+                      'Did you forget prefixing enums with '
+                      '"// GENERATED_JAVA_ENUM_PACKAGE: foo"?' %
+                      source_path)
+    for enum_definition in enum_definitions:
+      package_path = enum_definition.enum_package.replace('.', os.path.sep)
+      file_name = enum_definition.class_name + '.java'
+      output_path = os.path.join(output_dir, package_path, file_name)
+      output_paths.append(output_path)
+      if not print_output_only:
+        build_utils.MakeDirectory(os.path.dirname(output_path))
+        DoWriteOutput(source_path, output_path, enum_definition)
+  return output_paths
+
+
+def DoParseHeaderFile(path):
+  with open(path) as f:
+    return HeaderParser(f.readlines(), path).ParseDefinitions()
+
+
+def GenerateOutput(source_path, enum_definition):
+  template = Template("""
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     ${SCRIPT_NAME}
+// From
+//     ${SOURCE_PATH}
+
+package ${PACKAGE};
+
+public class ${CLASS_NAME} {
+${ENUM_ENTRIES}
+}
+""")
+
+  enum_template = Template('  public static final int ${NAME} = ${VALUE};')
+  enum_entries_string = []
+  for enum_name, enum_value in enum_definition.entries.iteritems():
+    values = {
+        'NAME': enum_name,
+        'VALUE': enum_value,
+    }
+    enum_entries_string.append(enum_template.substitute(values))
+  enum_entries_string = '\n'.join(enum_entries_string)
+
+  values = {
+      'CLASS_NAME': enum_definition.class_name,
+      'ENUM_ENTRIES': enum_entries_string,
+      'PACKAGE': enum_definition.enum_package,
+      'SCRIPT_NAME': GetScriptName(),
+      'SOURCE_PATH': source_path,
+  }
+  return template.substitute(values)
+
+
+def DoWriteOutput(source_path, output_path, enum_definition):
+  with open(output_path, 'w') as out_file:
+    out_file.write(GenerateOutput(source_path, enum_definition))
+
+def AssertFilesList(output_paths, assert_files_list):
+  actual = set(output_paths)
+  expected = set(assert_files_list)
+  if not actual == expected:
+    need_to_add = list(actual - expected)
+    need_to_remove = list(expected - actual)
+    raise Exception('Output files list does not match expectations. Please '
+                    'add %s and remove %s.' % (need_to_add, need_to_remove))
+
+def DoMain(argv):
+  usage = 'usage: %prog [options] output_dir input_file(s)...'
+  parser = optparse.OptionParser(usage=usage)
+
+  parser.add_option('--assert_file', action="append", default=[],
+                    dest="assert_files_list", help='Assert that the given '
+                    'file is an output. There can be multiple occurrences of '
+                    'this flag.')
+  parser.add_option('--print_output_only', help='Only print output paths.',
+                    action='store_true')
+  parser.add_option('--verbose', help='Print more information.',
+                    action='store_true')
+
+  options, args = parser.parse_args(argv)
+  if len(args) < 2:
+    parser.error('Need to specify output directory and at least one input file')
+  output_paths = DoGenerate(args[0], args[1:],
+                            print_output_only=options.print_output_only)
+
+  if options.assert_files_list:
+    AssertFilesList(output_paths, options.assert_files_list)
+
+  if options.verbose:
+    print 'Output paths:'
+    print '\n'.join(output_paths)
+
+  return ' '.join(output_paths)
+
+if __name__ == '__main__':
+  DoMain(sys.argv[1:])
diff --git a/build/android/gyp/java_cpp_enum_tests.py b/build/android/gyp/java_cpp_enum_tests.py
new file mode 100755
index 0000000..44f9766
--- /dev/null
+++ b/build/android/gyp/java_cpp_enum_tests.py
@@ -0,0 +1,436 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 enum_preprocess.py.
+
+This test suite containss various tests for the C++ -> Java enum generator.
+"""
+
+import collections
+import optparse
+import os
+import sys
+import unittest
+
+import java_cpp_enum
+from java_cpp_enum import EnumDefinition, GenerateOutput, GetScriptName
+from java_cpp_enum import HeaderParser
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "gyp"))
+from util import build_utils
+
+class TestPreprocess(unittest.TestCase):
+  def testOutput(self):
+    definition = EnumDefinition(original_enum_name='ClassName',
+                                enum_package='some.package',
+                                entries=[('E1', 1), ('E2', '2 << 2')])
+    output = GenerateOutput('path/to/file', definition)
+    expected = """
+// Copyright 2014 The Chromium 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
+//     %s
+// From
+//     path/to/file
+
+package some.package;
+
+public class ClassName {
+  public static final int E1 = 1;
+  public static final int E2 = 2 << 2;
+}
+"""
+    self.assertEqual(expected % GetScriptName(), output)
+
+  def testParseSimpleEnum(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum EnumName {
+        VALUE_ZERO,
+        VALUE_ONE,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('EnumName', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('VALUE_ZERO', 0),
+                                              ('VALUE_ONE', 1)]),
+                     definition.entries)
+
+  def testParseBitShifts(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum EnumName {
+        VALUE_ZERO = 1 << 0,
+        VALUE_ONE = 1 << 1,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('EnumName', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('VALUE_ZERO', '1 << 0'),
+                                              ('VALUE_ONE', '1 << 1')]),
+                     definition.entries)
+
+  def testParseClassNameOverride(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName
+      enum EnumName {
+        FOO
+      };
+
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OtherOverride
+      enum PrefixTest {
+        PREFIX_TEST_A,
+        PREFIX_TEST_B,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(2, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('OverrideName', definition.class_name)
+
+    definition = definitions[1]
+    self.assertEqual('OtherOverride', definition.class_name)
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 1)]),
+                     definition.entries)
+
+  def testParseTwoEnums(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum EnumOne {
+        ENUM_ONE_A = 1,
+        // Comment there
+        ENUM_ONE_B = A,
+      };
+
+      enum EnumIgnore {
+        C, D, E
+      };
+
+      // GENERATED_JAVA_ENUM_PACKAGE: other.package
+      // GENERATED_JAVA_PREFIX_TO_STRIP: P_
+      enum EnumTwo {
+        P_A,
+        P_B
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(2, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('EnumOne', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('A', '1'),
+                                              ('B', 'A')]),
+                     definition.entries)
+
+    definition = definitions[1]
+    self.assertEqual('EnumTwo', definition.class_name)
+    self.assertEqual('other.package', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 1)]),
+                     definition.entries)
+
+  def testParseThrowsOnUnknownDirective(self):
+    test_data = """
+      // GENERATED_JAVA_UNKNOWN: Value
+      enum EnumName {
+        VALUE_ONE,
+      };
+    """.split('\n')
+    with self.assertRaises(Exception):
+      HeaderParser(test_data).ParseDefinitions()
+
+  def testParseReturnsEmptyListWithoutDirectives(self):
+    test_data = """
+      enum EnumName {
+        VALUE_ONE,
+      };
+    """.split('\n')
+    self.assertEqual([], HeaderParser(test_data).ParseDefinitions())
+
+  def testParseEnumClass(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum class Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseEnumStruct(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum struct Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseFixedTypeEnum(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum Foo : int {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual('int', definition.fixed_type)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseFixedTypeEnumClass(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum class Foo: unsigned short {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual('unsigned short', definition.fixed_type)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseUnknownFixedTypeRaises(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum class Foo: foo_type {
+        FOO_A,
+      };
+    """.split('\n')
+    with self.assertRaises(Exception):
+      HeaderParser(test_data).ParseDefinitions()
+
+  def testParseSimpleMultiLineDirective(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: (
+      //   test.namespace)
+      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar
+      enum Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual('test.namespace', definitions[0].enum_package)
+    self.assertEqual('Bar', definitions[0].class_name)
+
+  def testParseMultiLineDirective(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: (te
+      //   st.name
+      //   space)
+      enum Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual('test.namespace', definitions[0].enum_package)
+
+  def testParseMultiLineDirectiveWithOtherDirective(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: (
+      //   test.namespace)
+      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: (
+      //   Ba
+      //   r
+      //   )
+      enum Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual('test.namespace', definitions[0].enum_package)
+    self.assertEqual('Bar', definitions[0].class_name)
+
+  def testParseMalformedMultiLineDirectiveWithOtherDirective(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: (
+      //   test.name
+      //   space
+      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar
+      enum Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    with self.assertRaises(Exception):
+      HeaderParser(test_data).ParseDefinitions()
+
+  def testParseMalformedMultiLineDirective(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: (
+      //   test.name
+      //   space
+      enum Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    with self.assertRaises(Exception):
+      HeaderParser(test_data).ParseDefinitions()
+
+  def testParseMalformedMultiLineDirectiveShort(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: (
+      enum Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    with self.assertRaises(Exception):
+      HeaderParser(test_data).ParseDefinitions()
+
+  def testEnumValueAssignmentNoneDefined(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('A', None)
+    definition.AppendEntry('B', None)
+    definition.AppendEntry('C', None)
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 1),
+                                              ('C', 2)]),
+                     definition.entries)
+
+  def testEnumValueAssignmentAllDefined(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('A', '1')
+    definition.AppendEntry('B', '2')
+    definition.AppendEntry('C', '3')
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', '1'),
+                                              ('B', '2'),
+                                              ('C', '3')]),
+                     definition.entries)
+
+  def testEnumValueAssignmentReferences(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('A', None)
+    definition.AppendEntry('B', 'A')
+    definition.AppendEntry('C', None)
+    definition.AppendEntry('D', 'C')
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 0),
+                                              ('C', 1),
+                                              ('D', 1)]),
+                     definition.entries)
+
+  def testEnumValueAssignmentSet(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('A', None)
+    definition.AppendEntry('B', '2')
+    definition.AppendEntry('C', None)
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 2),
+                                              ('C', 3)]),
+                     definition.entries)
+
+  def testEnumValueAssignmentSetReferences(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('A', None)
+    definition.AppendEntry('B', 'A')
+    definition.AppendEntry('C', 'B')
+    definition.AppendEntry('D', None)
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 0),
+                                              ('C', 0),
+                                              ('D', 1)]),
+                     definition.entries)
+
+  def testEnumValueAssignmentRaises(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('A', None)
+    definition.AppendEntry('B', 'foo')
+    definition.AppendEntry('C', None)
+    with self.assertRaises(Exception):
+      definition.Finalize()
+
+  def testExplicitPrefixStripping(self):
+    definition = EnumDefinition(original_enum_name='c', enum_package='p')
+    definition.AppendEntry('P_A', None)
+    definition.AppendEntry('B', None)
+    definition.AppendEntry('P_C', None)
+    definition.AppendEntry('P_LAST', 'P_C')
+    definition.prefix_to_strip = 'P_'
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 1),
+                                              ('C', 2),
+                                              ('LAST', 2)]),
+                     definition.entries)
+
+  def testImplicitPrefixStripping(self):
+    definition = EnumDefinition(original_enum_name='ClassName',
+                                enum_package='p')
+    definition.AppendEntry('CLASS_NAME_A', None)
+    definition.AppendEntry('CLASS_NAME_B', None)
+    definition.AppendEntry('CLASS_NAME_C', None)
+    definition.AppendEntry('CLASS_NAME_LAST', 'CLASS_NAME_C')
+    definition.Finalize()
+    self.assertEqual(collections.OrderedDict([('A', 0),
+                                              ('B', 1),
+                                              ('C', 2),
+                                              ('LAST', 2)]),
+                     definition.entries)
+
+  def testImplicitPrefixStrippingRequiresAllConstantsToBePrefixed(self):
+    definition = EnumDefinition(original_enum_name='Name',
+                                enum_package='p')
+    definition.AppendEntry('A', None)
+    definition.AppendEntry('B', None)
+    definition.AppendEntry('NAME_LAST', None)
+    definition.Finalize()
+    self.assertEqual(['A', 'B', 'NAME_LAST'], definition.entries.keys())
+
+  def testGenerateThrowsOnEmptyInput(self):
+    with self.assertRaises(Exception):
+      original_do_parse = java_cpp_enum.DoParseHeaderFile
+      try:
+        java_cpp_enum.DoParseHeaderFile = lambda _: []
+        java_cpp_enum.DoGenerate('dir', ['file'])
+      finally:
+        java_cpp_enum.DoParseHeaderFile = original_do_parse
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option("--stamp", help="File to touch on success.")
+  options, _ = parser.parse_args(argv)
+
+  suite = unittest.TestLoader().loadTestsFromTestCase(TestPreprocess)
+  unittest.TextTestRunner(verbosity=0).run(suite)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
new file mode 100755
index 0000000..a0fcda8
--- /dev/null
+++ b/build/android/gyp/javac.py
@@ -0,0 +1,281 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import fnmatch
+import optparse
+import os
+import shutil
+import re
+import sys
+import textwrap
+
+from util import build_utils
+from util import md5_check
+
+import jar
+
+sys.path.append(build_utils.COLORAMA_ROOT)
+import colorama
+
+
+def ColorJavacOutput(output):
+  fileline_prefix = r'(?P<fileline>(?P<file>[-.\w/\\]+.java):(?P<line>[0-9]+):)'
+  warning_re = re.compile(
+      fileline_prefix + r'(?P<full_message> warning: (?P<message>.*))$')
+  error_re = re.compile(
+      fileline_prefix + r'(?P<full_message> (?P<message>.*))$')
+  marker_re = re.compile(r'\s*(?P<marker>\^)\s*$')
+
+  warning_color = ['full_message', colorama.Fore.YELLOW + colorama.Style.DIM]
+  error_color = ['full_message', colorama.Fore.MAGENTA + colorama.Style.BRIGHT]
+  marker_color = ['marker',  colorama.Fore.BLUE + colorama.Style.BRIGHT]
+
+  def Colorize(line, regex, color):
+    match = regex.match(line)
+    start = match.start(color[0])
+    end = match.end(color[0])
+    return (line[:start]
+            + color[1] + line[start:end]
+            + colorama.Fore.RESET + colorama.Style.RESET_ALL
+            + line[end:])
+
+  def ApplyColor(line):
+    if warning_re.match(line):
+      line = Colorize(line, warning_re, warning_color)
+    elif error_re.match(line):
+      line = Colorize(line, error_re, error_color)
+    elif marker_re.match(line):
+      line = Colorize(line, marker_re, marker_color)
+    return line
+
+  return '\n'.join(map(ApplyColor, output.split('\n')))
+
+
+def DoJavac(
+    classpath, classes_dir, chromium_code, java_files):
+  """Runs javac.
+
+  Builds |java_files| with the provided |classpath| and puts the generated
+  .class files into |classes_dir|. If |chromium_code| is true, extra lint
+  checking will be enabled.
+  """
+
+  jar_inputs = []
+  for path in classpath:
+    if os.path.exists(path + '.TOC'):
+      jar_inputs.append(path + '.TOC')
+    else:
+      jar_inputs.append(path)
+
+  javac_args = [
+      '-g',
+      # Chromium only allows UTF8 source files.  Being explicit avoids
+      # javac pulling a default encoding from the user's environment.
+      '-encoding', 'UTF-8',
+      '-source', '1.7',
+      '-target', '1.7',
+      '-classpath', ':'.join(classpath),
+      '-d', classes_dir]
+  if chromium_code:
+    # TODO(aurimas): re-enable '-Xlint:deprecation' checks once they are fixed.
+    javac_args.extend(['-Xlint:unchecked'])
+  else:
+    # XDignore.symbol.file makes javac compile against rt.jar instead of
+    # ct.sym. This means that using a java internal package/class will not
+    # trigger a compile warning or error.
+    javac_args.extend(['-XDignore.symbol.file'])
+
+  javac_cmd = ['javac'] + javac_args + java_files
+
+  def Compile():
+    build_utils.CheckOutput(
+        javac_cmd,
+        print_stdout=chromium_code,
+        stderr_filter=ColorJavacOutput)
+
+  record_path = os.path.join(classes_dir, 'javac.md5.stamp')
+  md5_check.CallAndRecordIfStale(
+      Compile,
+      record_path=record_path,
+      input_paths=java_files + jar_inputs,
+      input_strings=javac_cmd)
+
+
+_MAX_MANIFEST_LINE_LEN = 72
+
+
+def CreateManifest(manifest_path, classpath, main_class=None,
+                   manifest_entries=None):
+  """Creates a manifest file with the given parameters.
+
+  This generates a manifest file that compiles with the spec found at
+  http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#JAR_Manifest
+
+  Args:
+    manifest_path: The path to the manifest file that should be created.
+    classpath: The JAR files that should be listed on the manifest file's
+      classpath.
+    main_class: If present, the class containing the main() function.
+    manifest_entries: If present, a list of (key, value) pairs to add to
+      the manifest.
+
+  """
+  output = ['Manifest-Version: 1.0']
+  if main_class:
+    output.append('Main-Class: %s' % main_class)
+  if manifest_entries:
+    for k, v in manifest_entries:
+      output.append('%s: %s' % (k, v))
+  if classpath:
+    sanitized_paths = []
+    for path in classpath:
+      sanitized_paths.append(os.path.basename(path.strip('"')))
+    output.append('Class-Path: %s' % ' '.join(sanitized_paths))
+  output.append('Created-By: ')
+  output.append('')
+
+  wrapper = textwrap.TextWrapper(break_long_words=True,
+                                 drop_whitespace=False,
+                                 subsequent_indent=' ',
+                                 width=_MAX_MANIFEST_LINE_LEN - 2)
+  output = '\r\n'.join(w for l in output for w in wrapper.wrap(l))
+
+  with open(manifest_path, 'w') as f:
+    f.write(output)
+
+
+def main(argv):
+  colorama.init()
+
+  argv = build_utils.ExpandFileArgs(argv)
+
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option(
+      '--src-gendirs',
+      help='Directories containing generated java files.')
+  parser.add_option(
+      '--java-srcjars',
+      action='append',
+      default=[],
+      help='List of srcjars to include in compilation.')
+  parser.add_option(
+      '--classpath',
+      action='append',
+      help='Classpath for javac. If this is specified multiple times, they '
+      'will all be appended to construct the classpath.')
+  parser.add_option(
+      '--javac-includes',
+      help='A list of file patterns. If provided, only java files that match'
+      'one of the patterns will be compiled.')
+  parser.add_option(
+      '--jar-excluded-classes',
+      default='',
+      help='List of .class file patterns to exclude from the jar.')
+
+  parser.add_option(
+      '--chromium-code',
+      type='int',
+      help='Whether code being compiled should be built with stricter '
+      'warnings for chromium code.')
+
+  parser.add_option(
+      '--classes-dir',
+      help='Directory for compiled .class files.')
+  parser.add_option('--jar-path', help='Jar output path.')
+  parser.add_option(
+      '--main-class',
+      help='The class containing the main method.')
+  parser.add_option(
+      '--manifest-entry',
+      action='append',
+      help='Key:value pairs to add to the .jar manifest.')
+
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  options, args = parser.parse_args(argv)
+
+  if options.main_class and not options.jar_path:
+    parser.error('--main-class requires --jar-path')
+
+  classpath = []
+  for arg in options.classpath:
+    classpath += build_utils.ParseGypList(arg)
+
+  java_srcjars = []
+  for arg in options.java_srcjars:
+    java_srcjars += build_utils.ParseGypList(arg)
+
+  java_files = args
+  if options.src_gendirs:
+    src_gendirs = build_utils.ParseGypList(options.src_gendirs)
+    java_files += build_utils.FindInDirectories(src_gendirs, '*.java')
+
+  input_files = classpath + java_srcjars + java_files
+  with build_utils.TempDir() as temp_dir:
+    classes_dir = os.path.join(temp_dir, 'classes')
+    os.makedirs(classes_dir)
+    if java_srcjars:
+      java_dir = os.path.join(temp_dir, 'java')
+      os.makedirs(java_dir)
+      for srcjar in java_srcjars:
+        build_utils.ExtractAll(srcjar, path=java_dir, pattern='*.java')
+      java_files += build_utils.FindInDirectory(java_dir, '*.java')
+
+    if options.javac_includes:
+      javac_includes = build_utils.ParseGypList(options.javac_includes)
+      filtered_java_files = []
+      for f in java_files:
+        for include in javac_includes:
+          if fnmatch.fnmatch(f, include):
+            filtered_java_files.append(f)
+            break
+      java_files = filtered_java_files
+
+    DoJavac(
+        classpath,
+        classes_dir,
+        options.chromium_code,
+        java_files)
+
+    if options.jar_path:
+      if options.main_class or options.manifest_entry:
+        if options.manifest_entry:
+          entries = map(lambda e: e.split(":"), options.manifest_entry)
+        else:
+          entries = []
+        manifest_file = os.path.join(temp_dir, 'manifest')
+        CreateManifest(manifest_file, classpath, options.main_class, entries)
+      else:
+        manifest_file = None
+      jar.JarDirectory(classes_dir,
+                       build_utils.ParseGypList(options.jar_excluded_classes),
+                       options.jar_path,
+                       manifest_file=manifest_file)
+
+    if options.classes_dir:
+      # Delete the old classes directory. This ensures that all .class files in
+      # the output are actually from the input .java files. For example, if a
+      # .java file is deleted or an inner class is removed, the classes
+      # directory should not contain the corresponding old .class file after
+      # running this action.
+      build_utils.DeleteDirectory(options.classes_dir)
+      shutil.copytree(classes_dir, options.classes_dir)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        input_files + build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
+
+
diff --git a/build/android/gyp/jinja_template.py b/build/android/gyp/jinja_template.py
new file mode 100755
index 0000000..e7c9a34
--- /dev/null
+++ b/build/android/gyp/jinja_template.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Renders one or more template files using the Jinja template engine."""
+
+import codecs
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+# Import jinja2 from third_party/jinja2
+sys.path.append(os.path.join(os.path.dirname(__file__), '../../../third_party'))
+import jinja2  # pylint: disable=F0401
+
+
+class RecordingFileSystemLoader(jinja2.FileSystemLoader):
+  '''A FileSystemLoader that stores a list of loaded templates.'''
+  def __init__(self, searchpath):
+    jinja2.FileSystemLoader.__init__(self, searchpath)
+    self.loaded_templates = set()
+
+  def get_source(self, environment, template):
+    contents, filename, uptodate = jinja2.FileSystemLoader.get_source(
+        self, environment, template)
+    self.loaded_templates.add(os.path.relpath(filename))
+    return contents, filename, uptodate
+
+  def get_loaded_templates(self):
+    return list(self.loaded_templates)
+
+
+def ProcessFile(env, input_filename, loader_base_dir, output_filename,
+                variables):
+  input_rel_path = os.path.relpath(input_filename, loader_base_dir)
+  template = env.get_template(input_rel_path)
+  output = template.render(variables)
+  with codecs.open(output_filename, 'w', 'utf-8') as output_file:
+    output_file.write(output)
+
+
+def ProcessFiles(env, input_filenames, loader_base_dir, inputs_base_dir,
+                 outputs_zip, variables):
+  with build_utils.TempDir() as temp_dir:
+    for input_filename in input_filenames:
+      relpath = os.path.relpath(os.path.abspath(input_filename),
+                                os.path.abspath(inputs_base_dir))
+      if relpath.startswith(os.pardir):
+        raise Exception('input file %s is not contained in inputs base dir %s'
+                        % (input_filename, inputs_base_dir))
+
+      output_filename = os.path.join(temp_dir, relpath)
+      parent_dir = os.path.dirname(output_filename)
+      build_utils.MakeDirectory(parent_dir)
+      ProcessFile(env, input_filename, loader_base_dir, output_filename,
+                  variables)
+
+    build_utils.ZipDir(outputs_zip, temp_dir)
+
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--inputs', help='The template files to process.')
+  parser.add_option('--output', help='The output file to generate. Valid '
+                    'only if there is a single input.')
+  parser.add_option('--outputs-zip', help='A zip file containing the processed '
+                    'templates. Required if there are multiple inputs.')
+  parser.add_option('--inputs-base-dir', help='A common ancestor directory of '
+                    'the inputs. Each output\'s path in the output zip will '
+                    'match the relative path from INPUTS_BASE_DIR to the '
+                    'input. Required if --output-zip is given.')
+  parser.add_option('--loader-base-dir', help='Base path used by the template '
+                    'loader. Must be a common ancestor directory of '
+                    'the inputs. Defaults to CHROMIUM_SRC.',
+                    default=build_utils.CHROMIUM_SRC)
+  parser.add_option('--variables', help='Variables to be made available in the '
+                    'template processing environment, as a GYP list (e.g. '
+                    '--variables "channel=beta mstone=39")', default='')
+  options, args = parser.parse_args()
+
+  build_utils.CheckOptions(options, parser, required=['inputs'])
+  inputs = build_utils.ParseGypList(options.inputs)
+
+  if (options.output is None) == (options.outputs_zip is None):
+    parser.error('Exactly one of --output and --output-zip must be given')
+  if options.output and len(inputs) != 1:
+    parser.error('--output cannot be used with multiple inputs')
+  if options.outputs_zip and not options.inputs_base_dir:
+    parser.error('--inputs-base-dir must be given when --output-zip is used')
+  if args:
+    parser.error('No positional arguments should be given.')
+
+  variables = {}
+  for v in build_utils.ParseGypList(options.variables):
+    if '=' not in v:
+      parser.error('--variables argument must contain "=": ' + v)
+    name, _, value = v.partition('=')
+    variables[name] = value
+
+  loader = RecordingFileSystemLoader(options.loader_base_dir)
+  env = jinja2.Environment(loader=loader, undefined=jinja2.StrictUndefined,
+                           line_comment_prefix='##')
+  if options.output:
+    ProcessFile(env, inputs[0], options.loader_base_dir, options.output,
+                variables)
+  else:
+    ProcessFiles(env, inputs, options.loader_base_dir, options.inputs_base_dir,
+                 options.outputs_zip, variables)
+
+  if options.depfile:
+    deps = loader.get_loaded_templates() + build_utils.GetPythonDependencies()
+    build_utils.WriteDepfile(options.depfile, deps)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/gyp/lint.py b/build/android/gyp/lint.py
new file mode 100755
index 0000000..9402780
--- /dev/null
+++ b/build/android/gyp/lint.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Runs Android's lint tool."""
+
+
+import optparse
+import os
+import sys
+from xml.dom import minidom
+
+from util import build_utils
+
+
+_SRC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                         '..', '..', '..'))
+
+
+def _RunLint(lint_path, config_path, processed_config_path, manifest_path,
+             result_path, product_dir, sources, jar_path, resource_dir=None,
+             can_fail_build=False):
+
+  def _RelativizePath(path):
+    """Returns relative path to top-level src dir.
+
+    Args:
+      path: A path relative to cwd.
+    """
+    return os.path.relpath(os.path.abspath(path), _SRC_ROOT)
+
+  def _ProcessConfigFile():
+    if not build_utils.IsTimeStale(processed_config_path, [config_path]):
+      return
+
+    with open(config_path, 'rb') as f:
+      content = f.read().replace(
+          'PRODUCT_DIR', _RelativizePath(product_dir))
+
+    with open(processed_config_path, 'wb') as f:
+      f.write(content)
+
+  def _ProcessResultFile():
+    with open(result_path, 'rb') as f:
+      content = f.read().replace(
+          _RelativizePath(product_dir), 'PRODUCT_DIR')
+
+    with open(result_path, 'wb') as f:
+      f.write(content)
+
+  def _ParseAndShowResultFile():
+    dom = minidom.parse(result_path)
+    issues = dom.getElementsByTagName('issue')
+    print >> sys.stderr
+    for issue in issues:
+      issue_id = issue.attributes['id'].value
+      message = issue.attributes['message'].value
+      location_elem = issue.getElementsByTagName('location')[0]
+      path = location_elem.attributes['file'].value
+      line = location_elem.getAttribute('line')
+      if line:
+        error = '%s:%s %s: %s [warning]' % (path, line, message, issue_id)
+      else:
+        # Issues in class files don't have a line number.
+        error = '%s %s: %s [warning]' % (path, message, issue_id)
+      print >> sys.stderr, error
+      for attr in ['errorLine1', 'errorLine2']:
+        error_line = issue.getAttribute(attr)
+        if error_line:
+          print >> sys.stderr, error_line
+    return len(issues)
+
+  with build_utils.TempDir() as temp_dir:
+    _ProcessConfigFile()
+
+    cmd = [
+        _RelativizePath(lint_path), '-Werror', '--exitcode', '--showall',
+        '--config', _RelativizePath(processed_config_path),
+        '--classpath', _RelativizePath(jar_path),
+        '--xml', _RelativizePath(result_path),
+    ]
+    if resource_dir:
+      cmd.extend(['--resources', _RelativizePath(resource_dir)])
+
+    # There may be multiple source files with the same basename (but in
+    # different directories). It is difficult to determine what part of the path
+    # corresponds to the java package, and so instead just link the source files
+    # into temporary directories (creating a new one whenever there is a name
+    # conflict).
+    src_dirs = []
+    def NewSourceDir():
+      new_dir = os.path.join(temp_dir, str(len(src_dirs)))
+      os.mkdir(new_dir)
+      src_dirs.append(new_dir)
+      cmd.extend(['--sources', _RelativizePath(new_dir)])
+      return new_dir
+
+    def PathInDir(d, src):
+      return os.path.join(d, os.path.basename(src))
+
+    for src in sources:
+      src_dir = None
+      for d in src_dirs:
+        if not os.path.exists(PathInDir(d, src)):
+          src_dir = d
+          break
+      if not src_dir:
+        src_dir = NewSourceDir()
+      os.symlink(os.path.abspath(src), PathInDir(src_dir, src))
+
+    cmd.append(_RelativizePath(os.path.join(manifest_path, os.pardir)))
+
+    if os.path.exists(result_path):
+      os.remove(result_path)
+
+    try:
+      build_utils.CheckOutput(cmd, cwd=_SRC_ROOT)
+    except build_utils.CalledProcessError as e:
+      # There is a problem with lint usage
+      if not os.path.exists(result_path):
+        print 'Something is wrong:'
+        print e
+        return 0
+
+      # There are actual lint issues
+      else:
+        try:
+          num_issues = _ParseAndShowResultFile()
+        except Exception:
+          print 'Lint created unparseable xml file...'
+          print 'File contents:'
+          with open(result_path) as f:
+            print f.read()
+          return 0
+
+        _ProcessResultFile()
+        msg = ('\nLint found %d new issues.\n'
+               ' - For full explanation refer to %s\n'
+               ' - Wanna suppress these issues?\n'
+               '    1. Read comment in %s\n'
+               '    2. Run "python %s %s"\n' %
+               (num_issues,
+                _RelativizePath(result_path),
+                _RelativizePath(config_path),
+                _RelativizePath(os.path.join(_SRC_ROOT, 'build', 'android',
+                                             'lint', 'suppress.py')),
+                _RelativizePath(result_path)))
+        print >> sys.stderr, msg
+        return 1 if can_fail_build else 0
+
+  return 0
+
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--lint-path', help='Path to lint executable.')
+  parser.add_option('--config-path', help='Path to lint suppressions file.')
+  parser.add_option('--processed-config-path',
+                    help='Path to processed lint suppressions file.')
+  parser.add_option('--manifest-path', help='Path to AndroidManifest.xml')
+  parser.add_option('--result-path', help='Path to XML lint result file.')
+  parser.add_option('--product-dir', help='Path to product dir.')
+  parser.add_option('--src-dirs', help='Directories containing java files.')
+  parser.add_option('--java-files', help='Paths to java files.')
+  parser.add_option('--jar-path', help='Jar file containing class files.')
+  parser.add_option('--resource-dir', help='Path to resource dir.')
+  parser.add_option('--can-fail-build', action='store_true',
+                    help='If set, script will exit with nonzero exit status'
+                    ' if lint errors are present')
+  parser.add_option('--stamp', help='Path to touch on success.')
+  parser.add_option('--enable', action='store_true',
+                    help='Run lint instead of just touching stamp.')
+
+  options, _ = parser.parse_args()
+
+  build_utils.CheckOptions(
+      options, parser, required=['lint_path', 'config_path',
+                                 'processed_config_path', 'manifest_path',
+                                 'result_path', 'product_dir',
+                                 'jar_path'])
+
+  rc = 0
+
+  if options.enable:
+    sources = []
+    if options.src_dirs:
+      src_dirs = build_utils.ParseGypList(options.src_dirs)
+      sources = build_utils.FindInDirectories(src_dirs, '*.java')
+    elif options.java_files:
+      sources = build_utils.ParseGypList(options.java_files)
+    else:
+      print 'One of --src-dirs or --java-files must be specified.'
+      return 1
+    rc = _RunLint(options.lint_path, options.config_path,
+                  options.processed_config_path,
+                  options.manifest_path, options.result_path,
+                  options.product_dir, sources, options.jar_path,
+                  options.resource_dir, options.can_fail_build)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+  if options.stamp and not rc:
+    build_utils.Touch(options.stamp)
+
+  return rc
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/gyp/pack_arm_relocations.py b/build/android/gyp/pack_arm_relocations.py
new file mode 100755
index 0000000..517a22e
--- /dev/null
+++ b/build/android/gyp/pack_arm_relocations.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Pack ARM relative relocations in a library (or copy unchanged).
+
+If --enable-packing and --configuration-name=='Release', invoke the
+relocation_packer tool to pack the .rel.dyn or .rela.dyn section in the given
+library files.  This step is inserted after the libraries are stripped.
+Packing adds a new .android.rel.dyn or .android.rela.dyn section to the file
+and reduces the size of .rel.dyn or .rela.dyn accordingly.
+
+Currently packing only understands ARM32 shared libraries.  For all other
+architectures --enable-packing should be set to zero.  In this case the
+script copies files verbatim, with no attempt to pack relative relocations.
+
+Any library listed in --exclude-packing-list is also copied verbatim,
+irrespective of any --enable-packing setting.  Typically this would be
+'libchromium_android_linker.so'.
+"""
+
+import optparse
+import os
+import shlex
+import shutil
+import sys
+import tempfile
+
+from util import build_utils
+
+def PackArmLibraryRelocations(android_pack_relocations,
+                              android_objcopy,
+                              has_relocations_with_addends,
+                              library_path,
+                              output_path):
+  # Select an appropriate name for the section we add.
+  if has_relocations_with_addends:
+    new_section = '.android.rela.dyn'
+  else:
+    new_section = '.android.rel.dyn'
+
+  # Copy and add a 'NULL' packed relocations section for the packing tool.
+  with tempfile.NamedTemporaryFile() as stream:
+    stream.write('NULL')
+    stream.flush()
+    objcopy_command = [android_objcopy,
+                       '--add-section', '%s=%s' % (new_section, stream.name),
+                       library_path, output_path]
+    build_utils.CheckOutput(objcopy_command)
+
+  # Pack R_ARM_RELATIVE relocations.
+  pack_command = [android_pack_relocations, output_path]
+  build_utils.CheckOutput(pack_command)
+
+
+def CopyArmLibraryUnchanged(library_path, output_path):
+  shutil.copy(library_path, output_path)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--clear-dir', action='store_true',
+                    help='If set, the destination directory will be deleted '
+                    'before copying files to it. This is highly recommended to '
+                    'ensure that no stale files are left in the directory.')
+
+  parser.add_option('--configuration-name',
+      default='Release',
+      help='Gyp configuration name (i.e. Debug, Release)')
+  parser.add_option('--enable-packing',
+      choices=['0', '1'],
+      help=('Pack relocations if 1 and configuration name is \'Release\','
+            ' otherwise plain file copy'))
+  parser.add_option('--has-relocations-with-addends',
+      choices=['0', '1'],
+      help=('Pack into \'.android.rela.dyn\' if 1, else \'.android.rel.dyn\''))
+  parser.add_option('--exclude-packing-list',
+      default='',
+      help='Names of any libraries explicitly not packed')
+  parser.add_option('--android-pack-relocations',
+      help='Path to the ARM relocations packer binary')
+  parser.add_option('--android-objcopy',
+      help='Path to the toolchain\'s objcopy binary')
+  parser.add_option('--stripped-libraries-dir',
+      help='Directory for stripped libraries')
+  parser.add_option('--packed-libraries-dir',
+      help='Directory for packed libraries')
+  parser.add_option('--libraries', action='append',
+      help='List of libraries')
+  parser.add_option('--stamp', help='Path to touch on success')
+
+  options, _ = parser.parse_args(args)
+  enable_packing = (options.enable_packing == '1' and
+                    options.configuration_name == 'Release')
+  has_relocations_with_addends = (options.has_relocations_with_addends == '1')
+  exclude_packing_set = set(shlex.split(options.exclude_packing_list))
+
+  libraries = []
+  for libs_arg in options.libraries:
+    libraries += build_utils.ParseGypList(libs_arg)
+
+  if options.clear_dir:
+    build_utils.DeleteDirectory(options.packed_libraries_dir)
+
+  build_utils.MakeDirectory(options.packed_libraries_dir)
+
+  for library in libraries:
+    library_path = os.path.join(options.stripped_libraries_dir, library)
+    output_path = os.path.join(
+        options.packed_libraries_dir, os.path.basename(library))
+
+    if enable_packing and library not in exclude_packing_set:
+      PackArmLibraryRelocations(options.android_pack_relocations,
+                                options.android_objcopy,
+                                has_relocations_with_addends,
+                                library_path,
+                                output_path)
+    else:
+      CopyArmLibraryUnchanged(library_path, output_path)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        libraries + build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/package_resources.py b/build/android/gyp/package_resources.py
new file mode 100755
index 0000000..2251de0
--- /dev/null
+++ b/build/android/gyp/package_resources.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=C0301
+"""Package resources into an apk.
+
+See https://android.googlesource.com/platform/tools/base/+/master/legacy/ant-tasks/src/main/java/com/android/ant/AaptExecTask.java
+and
+https://android.googlesource.com/platform/sdk/+/master/files/ant/build.xml
+"""
+# pylint: enable=C0301
+
+import optparse
+import os
+import shutil
+
+from util import build_utils
+
+def ParseArgs():
+  """Parses command line options.
+
+  Returns:
+    An options object as from optparse.OptionsParser.parse_args()
+  """
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--android-sdk', help='path to the Android SDK folder')
+  parser.add_option('--android-sdk-tools',
+                    help='path to the Android SDK build tools folder')
+
+  parser.add_option('--configuration-name',
+                    help='Gyp\'s configuration name (Debug or Release).')
+
+  parser.add_option('--android-manifest', help='AndroidManifest.xml path')
+  parser.add_option('--version-code', help='Version code for apk.')
+  parser.add_option('--version-name', help='Version name for apk.')
+  parser.add_option(
+      '--shared-resources',
+      action='store_true',
+      help='Make a resource package that can be loaded by a different'
+      'application at runtime to access the package\'s resources.')
+  parser.add_option('--resource-zips',
+                    help='zip files containing resources to be packaged')
+  parser.add_option('--asset-dir',
+                    help='directories containing assets to be packaged')
+  parser.add_option('--no-compress', help='disables compression for the '
+                    'given comma separated list of extensions')
+
+  parser.add_option('--apk-path',
+                    help='Path to output (partial) apk.')
+
+  (options, args) = parser.parse_args()
+
+  if args:
+    parser.error('No positional arguments should be given.')
+
+  # Check that required options have been provided.
+  required_options = ('android_sdk', 'android_sdk_tools', 'configuration_name',
+                      'android_manifest', 'version_code', 'version_name',
+                      'resource_zips', 'asset_dir', 'apk_path')
+
+  build_utils.CheckOptions(options, parser, required=required_options)
+
+  return options
+
+
+def MoveImagesToNonMdpiFolders(res_root):
+  """Move images from drawable-*-mdpi-* folders to drawable-* folders.
+
+  Why? http://crbug.com/289843
+  """
+  for src_dir_name in os.listdir(res_root):
+    src_components = src_dir_name.split('-')
+    if src_components[0] != 'drawable' or 'mdpi' not in src_components:
+      continue
+    src_dir = os.path.join(res_root, src_dir_name)
+    if not os.path.isdir(src_dir):
+      continue
+    dst_components = [c for c in src_components if c != 'mdpi']
+    assert dst_components != src_components
+    dst_dir_name = '-'.join(dst_components)
+    dst_dir = os.path.join(res_root, dst_dir_name)
+    build_utils.MakeDirectory(dst_dir)
+    for src_file_name in os.listdir(src_dir):
+      if not src_file_name.endswith('.png'):
+        continue
+      src_file = os.path.join(src_dir, src_file_name)
+      dst_file = os.path.join(dst_dir, src_file_name)
+      assert not os.path.lexists(dst_file)
+      shutil.move(src_file, dst_file)
+
+
+def PackageArgsForExtractedZip(d):
+  """Returns the aapt args for an extracted resources zip.
+
+  A resources zip either contains the resources for a single target or for
+  multiple targets. If it is multiple targets merged into one, the actual
+  resource directories will be contained in the subdirectories 0, 1, 2, ...
+  """
+  subdirs = [os.path.join(d, s) for s in os.listdir(d)]
+  subdirs = [s for s in subdirs if os.path.isdir(s)]
+  is_multi = '0' in [os.path.basename(s) for s in subdirs]
+  if is_multi:
+    res_dirs = sorted(subdirs, key=lambda p : int(os.path.basename(p)))
+  else:
+    res_dirs = [d]
+  package_command = []
+  for d in res_dirs:
+    MoveImagesToNonMdpiFolders(d)
+    package_command += ['-S', d]
+  return package_command
+
+
+def main():
+  options = ParseArgs()
+  android_jar = os.path.join(options.android_sdk, 'android.jar')
+  aapt = os.path.join(options.android_sdk_tools, 'aapt')
+
+  with build_utils.TempDir() as temp_dir:
+    package_command = [aapt,
+                       'package',
+                       '--version-code', options.version_code,
+                       '--version-name', options.version_name,
+                       '-M', options.android_manifest,
+                       '--no-crunch',
+                       '-f',
+                       '--auto-add-overlay',
+
+                       '-I', android_jar,
+                       '-F', options.apk_path,
+                       '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN,
+                       ]
+
+    if options.no_compress:
+      for ext in options.no_compress.split(','):
+        package_command += ['-0', ext]
+    if options.shared_resources:
+      package_command.append('--shared-lib')
+
+    if os.path.exists(options.asset_dir):
+      package_command += ['-A', options.asset_dir]
+
+    dep_zips = build_utils.ParseGypList(options.resource_zips)
+    for z in dep_zips:
+      subdir = os.path.join(temp_dir, os.path.basename(z))
+      if os.path.exists(subdir):
+        raise Exception('Resource zip name conflict: ' + os.path.basename(z))
+      build_utils.ExtractAll(z, path=subdir)
+      package_command += PackageArgsForExtractedZip(subdir)
+
+    if 'Debug' in options.configuration_name:
+      package_command += ['--debug-mode']
+
+    build_utils.CheckOutput(
+        package_command, print_stdout=False, print_stderr=False)
+
+    if options.depfile:
+      build_utils.WriteDepfile(
+          options.depfile,
+          build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py
new file mode 100755
index 0000000..4e6c27d
--- /dev/null
+++ b/build/android/gyp/process_resources.py
@@ -0,0 +1,322 @@
+#!/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.
+
+"""Process Android resources to generate R.java, and prepare for packaging.
+
+This will crunch images and generate v14 compatible resources
+(see generate_v14_compatible_resources.py).
+"""
+
+import codecs
+import optparse
+import os
+import re
+import shutil
+import sys
+import zipfile
+
+import generate_v14_compatible_resources
+
+from util import build_utils
+
+
+def ParseArgs(args):
+  """Parses command line options.
+
+  Returns:
+    An options object as from optparse.OptionsParser.parse_args()
+  """
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--android-sdk', help='path to the Android SDK folder')
+  parser.add_option('--android-sdk-tools',
+                    help='path to the Android SDK build tools folder')
+  parser.add_option('--non-constant-id', action='store_true')
+
+  parser.add_option('--android-manifest', help='AndroidManifest.xml path')
+  parser.add_option('--custom-package', help='Java package for R.java')
+  parser.add_option(
+      '--shared-resources',
+      action='store_true',
+      help='Make a resource package that can be loaded by a different'
+      'application at runtime to access the package\'s resources.')
+
+  parser.add_option('--resource-dirs',
+                    help='Directories containing resources of this target.')
+  parser.add_option('--dependencies-res-zips',
+                    help='Resources from dependents.')
+
+  parser.add_option('--resource-zip-out',
+                    help='Path for output zipped resources.')
+
+  parser.add_option('--R-dir',
+                    help='directory to hold generated R.java.')
+  parser.add_option('--srcjar-out',
+                    help='Path to srcjar to contain generated R.java.')
+
+  parser.add_option('--proguard-file',
+                    help='Path to proguard.txt generated file')
+
+  parser.add_option(
+      '--v14-verify-only',
+      action='store_true',
+      help='Do not generate v14 resources. Instead, just verify that the '
+      'resources are already compatible with v14, i.e. they don\'t use '
+      'attributes that cause crashes on certain devices.')
+
+  parser.add_option(
+      '--extra-res-packages',
+      help='Additional package names to generate R.java files for')
+  # TODO(cjhopman): Actually use --extra-r-text-files. We currently include all
+  # the resources in all R.java files for a particular apk.
+  parser.add_option(
+      '--extra-r-text-files',
+      help='For each additional package, the R.txt file should contain a '
+      'list of resources to be included in the R.java file in the format '
+      'generated by aapt')
+
+  parser.add_option(
+      '--all-resources-zip-out',
+      help='Path for output of all resources. This includes resources in '
+      'dependencies.')
+
+  parser.add_option('--stamp', help='File to touch on success')
+
+  (options, args) = parser.parse_args(args)
+
+  if args:
+    parser.error('No positional arguments should be given.')
+
+  # Check that required options have been provided.
+  required_options = (
+      'android_sdk',
+      'android_sdk_tools',
+      'android_manifest',
+      'dependencies_res_zips',
+      'resource_dirs',
+      'resource_zip_out',
+      )
+  build_utils.CheckOptions(options, parser, required=required_options)
+
+  if (options.R_dir is None) == (options.srcjar_out is None):
+    raise Exception('Exactly one of --R-dir or --srcjar-out must be specified.')
+
+  return options
+
+
+def CreateExtraRJavaFiles(r_dir, extra_packages):
+  java_files = build_utils.FindInDirectory(r_dir, "R.java")
+  if len(java_files) != 1:
+    return
+  r_java_file = java_files[0]
+  r_java_contents = codecs.open(r_java_file, encoding='utf-8').read()
+
+  for package in extra_packages:
+    package_r_java_dir = os.path.join(r_dir, *package.split('.'))
+    build_utils.MakeDirectory(package_r_java_dir)
+    package_r_java_path = os.path.join(package_r_java_dir, 'R.java')
+    new_r_java = re.sub(r'package [.\w]*;', u'package %s;' % package,
+                        r_java_contents)
+    codecs.open(package_r_java_path, 'w', encoding='utf-8').write(new_r_java)
+    # TODO(cjhopman): These extra package's R.java files should be filtered to
+    # only contain the resources listed in their R.txt files. At this point, we
+    # have already compiled those other libraries, so doing this would only
+    # affect how the code in this .apk target could refer to the resources.
+
+
+def CrunchDirectory(aapt, input_dir, output_dir):
+  """Crunches the images in input_dir and its subdirectories into output_dir.
+
+  If an image is already optimized, crunching often increases image size. In
+  this case, the crunched image is overwritten with the original image.
+  """
+  aapt_cmd = [aapt,
+              'crunch',
+              '-C', output_dir,
+              '-S', input_dir,
+              '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN]
+  build_utils.CheckOutput(aapt_cmd, stderr_filter=FilterCrunchStderr,
+                          fail_func=DidCrunchFail)
+
+  # Check for images whose size increased during crunching and replace them
+  # with their originals (except for 9-patches, which must be crunched).
+  for dir_, _, files in os.walk(output_dir):
+    for crunched in files:
+      if crunched.endswith('.9.png'):
+        continue
+      if not crunched.endswith('.png'):
+        raise Exception('Unexpected file in crunched dir: ' + crunched)
+      crunched = os.path.join(dir_, crunched)
+      original = os.path.join(input_dir, os.path.relpath(crunched, output_dir))
+      original_size = os.path.getsize(original)
+      crunched_size = os.path.getsize(crunched)
+      if original_size < crunched_size:
+        shutil.copyfile(original, crunched)
+
+
+def FilterCrunchStderr(stderr):
+  """Filters out lines from aapt crunch's stderr that can safely be ignored."""
+  filtered_lines = []
+  for line in stderr.splitlines(True):
+    # Ignore this libpng warning, which is a known non-error condition.
+    # http://crbug.com/364355
+    if ('libpng warning: iCCP: Not recognizing known sRGB profile that has '
+        + 'been edited' in line):
+      continue
+    filtered_lines.append(line)
+  return ''.join(filtered_lines)
+
+
+def DidCrunchFail(returncode, stderr):
+  """Determines whether aapt crunch failed from its return code and output.
+
+  Because aapt's return code cannot be trusted, any output to stderr is
+  an indication that aapt has failed (http://crbug.com/314885).
+  """
+  return returncode != 0 or stderr
+
+
+def ZipResources(resource_dirs, zip_path):
+  # Python zipfile does not provide a way to replace a file (it just writes
+  # another file with the same name). So, first collect all the files to put
+  # in the zip (with proper overriding), and then zip them.
+  files_to_zip = dict()
+  for d in resource_dirs:
+    for root, _, files in os.walk(d):
+      for f in files:
+        archive_path = os.path.join(os.path.relpath(root, d), f)
+        path = os.path.join(root, f)
+        files_to_zip[archive_path] = path
+  with zipfile.ZipFile(zip_path, 'w') as outzip:
+    for archive_path, path in files_to_zip.iteritems():
+      outzip.write(path, archive_path)
+
+
+def CombineZips(zip_files, output_path):
+  # When packaging resources, if the top-level directories in the zip file are
+  # of the form 0, 1, ..., then each subdirectory will be passed to aapt as a
+  # resources directory. While some resources just clobber others (image files,
+  # etc), other resources (particularly .xml files) need to be more
+  # intelligently merged. That merging is left up to aapt.
+  with zipfile.ZipFile(output_path, 'w') as outzip:
+    for i, z in enumerate(zip_files):
+      with zipfile.ZipFile(z, 'r') as inzip:
+        for name in inzip.namelist():
+          new_name = '%d/%s' % (i, name)
+          outzip.writestr(new_name, inzip.read(name))
+
+
+def main():
+  args = build_utils.ExpandFileArgs(sys.argv[1:])
+
+  options = ParseArgs(args)
+  android_jar = os.path.join(options.android_sdk, 'android.jar')
+  aapt = os.path.join(options.android_sdk_tools, 'aapt')
+
+  input_files = []
+
+  with build_utils.TempDir() as temp_dir:
+    deps_dir = os.path.join(temp_dir, 'deps')
+    build_utils.MakeDirectory(deps_dir)
+    v14_dir = os.path.join(temp_dir, 'v14')
+    build_utils.MakeDirectory(v14_dir)
+
+    gen_dir = os.path.join(temp_dir, 'gen')
+    build_utils.MakeDirectory(gen_dir)
+
+    input_resource_dirs = build_utils.ParseGypList(options.resource_dirs)
+
+    for resource_dir in input_resource_dirs:
+      generate_v14_compatible_resources.GenerateV14Resources(
+          resource_dir,
+          v14_dir,
+          options.v14_verify_only)
+
+    dep_zips = build_utils.ParseGypList(options.dependencies_res_zips)
+    input_files += dep_zips
+    dep_subdirs = []
+    for z in dep_zips:
+      subdir = os.path.join(deps_dir, os.path.basename(z))
+      if os.path.exists(subdir):
+        raise Exception('Resource zip name conflict: ' + os.path.basename(z))
+      build_utils.ExtractAll(z, path=subdir)
+      dep_subdirs.append(subdir)
+
+    # Generate R.java. This R.java contains non-final constants and is used only
+    # while compiling the library jar (e.g. chromium_content.jar). When building
+    # an apk, a new R.java file with the correct resource -> ID mappings will be
+    # generated by merging the resources from all libraries and the main apk
+    # project.
+    package_command = [aapt,
+                       'package',
+                       '-m',
+                       '-M', options.android_manifest,
+                       '--auto-add-overlay',
+                       '-I', android_jar,
+                       '--output-text-symbols', gen_dir,
+                       '-J', gen_dir,
+                       '--ignore-assets', build_utils.AAPT_IGNORE_PATTERN]
+
+    for d in input_resource_dirs:
+      package_command += ['-S', d]
+
+    for d in dep_subdirs:
+      package_command += ['-S', d]
+
+    if options.non_constant_id:
+      package_command.append('--non-constant-id')
+    if options.custom_package:
+      package_command += ['--custom-package', options.custom_package]
+    if options.proguard_file:
+      package_command += ['-G', options.proguard_file]
+    if options.shared_resources:
+      package_command.append('--shared-lib')
+    build_utils.CheckOutput(package_command, print_stderr=False)
+
+    if options.extra_res_packages:
+      CreateExtraRJavaFiles(
+          gen_dir,
+          build_utils.ParseGypList(options.extra_res_packages))
+
+    # This is the list of directories with resources to put in the final .zip
+    # file. The order of these is important so that crunched/v14 resources
+    # override the normal ones.
+    zip_resource_dirs = input_resource_dirs + [v14_dir]
+
+    base_crunch_dir = os.path.join(temp_dir, 'crunch')
+
+    # Crunch image resources. This shrinks png files and is necessary for
+    # 9-patch images to display correctly. 'aapt crunch' accepts only a single
+    # directory at a time and deletes everything in the output directory.
+    for idx, input_dir in enumerate(input_resource_dirs):
+      crunch_dir = os.path.join(base_crunch_dir, str(idx))
+      build_utils.MakeDirectory(crunch_dir)
+      zip_resource_dirs.append(crunch_dir)
+      CrunchDirectory(aapt, input_dir, crunch_dir)
+
+    ZipResources(zip_resource_dirs, options.resource_zip_out)
+
+    if options.all_resources_zip_out:
+      CombineZips([options.resource_zip_out] + dep_zips,
+                  options.all_resources_zip_out)
+
+    if options.R_dir:
+      build_utils.DeleteDirectory(options.R_dir)
+      shutil.copytree(gen_dir, options.R_dir)
+    else:
+      build_utils.ZipDir(options.srcjar_out, gen_dir)
+
+  if options.depfile:
+    input_files += build_utils.GetPythonDependencies()
+    build_utils.WriteDepfile(options.depfile, input_files)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
new file mode 100755
index 0000000..5127100
--- /dev/null
+++ b/build/android/gyp/proguard.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import optparse
+import sys
+
+from util import build_utils
+from util import proguard_util
+
+def DoProguard(options):
+  proguard = proguard_util.ProguardCmdBuilder(options.proguard_path)
+  proguard.injars(build_utils.ParseGypList(options.input_paths))
+  proguard.configs(build_utils.ParseGypList(options.proguard_configs))
+  proguard.outjar(options.output_path)
+
+  if options.mapping:
+    proguard.mapping(options.mapping)
+
+  if options.is_test:
+    proguard.is_test(True)
+
+  classpath = []
+  for arg in options.classpath:
+    classpath += build_utils.ParseGypList(arg)
+  classpath = list(set(classpath))
+  proguard.libraryjars(classpath)
+
+  proguard.CheckOutput()
+
+  return proguard.GetInputs()
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--proguard-path',
+                    help='Path to the proguard executable.')
+  parser.add_option('--input-paths',
+                    help='Paths to the .jar files proguard should run on.')
+  parser.add_option('--output-path', help='Path to the generated .jar file.')
+  parser.add_option('--proguard-configs',
+                    help='Paths to proguard configuration files.')
+  parser.add_option('--mapping', help='Path to proguard mapping to apply.')
+  parser.add_option('--is-test', action='store_true',
+      help='If true, extra proguard options for instrumentation tests will be '
+      'added.')
+  parser.add_option('--classpath', action='append',
+                    help='Classpath for proguard.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  options, _ = parser.parse_args(args)
+
+  inputs = DoProguard(options)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        inputs + build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/push_libraries.py b/build/android/gyp/push_libraries.py
new file mode 100755
index 0000000..6b31a2e
--- /dev/null
+++ b/build/android/gyp/push_libraries.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Pushes native libraries to a device.
+
+"""
+
+import optparse
+import os
+import sys
+
+BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), os.pardir)
+sys.path.append(BUILD_ANDROID_DIR)
+
+from pylib import constants
+
+from util import build_device
+from util import build_utils
+from util import md5_check
+
+def DoPush(options):
+  libraries = build_utils.ParseGypList(options.libraries)
+
+  device = build_device.GetBuildDeviceFromPath(
+      options.build_device_configuration)
+  if not device:
+    return
+
+  serial_number = device.GetSerialNumber()
+  # A list so that it is modifiable in Push below.
+  needs_directory = [True]
+  for lib in libraries:
+    device_path = os.path.join(options.device_dir, lib)
+    host_path = os.path.join(options.libraries_dir, lib)
+
+    def Push():
+      if needs_directory:
+        device.RunShellCommand('mkdir -p ' + options.device_dir)
+        needs_directory[:] = [] # = False
+      device.PushChangedFiles([(host_path, device_path)])
+
+    record_path = '%s.%s.push.md5.stamp' % (host_path, serial_number)
+    md5_check.CallAndRecordIfStale(
+        Push,
+        record_path=record_path,
+        input_paths=[host_path],
+        input_strings=[device_path])
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = optparse.OptionParser()
+  parser.add_option('--libraries-dir',
+      help='Directory that contains stripped libraries.')
+  parser.add_option('--device-dir',
+      help='Device directory to push the libraries to.')
+  parser.add_option('--libraries',
+      help='List of native libraries.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+  parser.add_option('--build-device-configuration',
+      help='Path to build device configuration.')
+  parser.add_option('--configuration-name',
+      help='The build CONFIGURATION_NAME')
+  options, _ = parser.parse_args(args)
+
+  required_options = ['libraries', 'device_dir', 'libraries']
+  build_utils.CheckOptions(options, parser, required=required_options)
+  constants.SetBuildType(options.configuration_name)
+
+  DoPush(options)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/strip_library_for_device.py b/build/android/gyp/strip_library_for_device.py
new file mode 100755
index 0000000..9e2daae
--- /dev/null
+++ b/build/android/gyp/strip_library_for_device.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+
+def StripLibrary(android_strip, android_strip_args, library_path, output_path):
+  if build_utils.IsTimeStale(output_path, [library_path]):
+    strip_cmd = ([android_strip] +
+                 android_strip_args +
+                 ['-o', output_path, library_path])
+    build_utils.CheckOutput(strip_cmd)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--android-strip',
+      help='Path to the toolchain\'s strip binary')
+  parser.add_option('--android-strip-arg', action='append',
+      help='Argument to be passed to strip')
+  parser.add_option('--libraries-dir',
+      help='Directory for un-stripped libraries')
+  parser.add_option('--stripped-libraries-dir',
+      help='Directory for stripped libraries')
+  parser.add_option('--libraries',
+      help='List of libraries to strip')
+  parser.add_option('--stamp', help='Path to touch on success')
+
+  options, _ = parser.parse_args(args)
+
+  libraries = build_utils.ParseGypList(options.libraries)
+
+  build_utils.MakeDirectory(options.stripped_libraries_dir)
+
+  for library in libraries:
+    for base_path in options.libraries_dir.split(','):
+      library_path = os.path.join(base_path, library)
+      if (os.path.exists(library_path)):
+        break
+    stripped_library_path = os.path.join(
+        options.stripped_libraries_dir, library)
+    StripLibrary(options.android_strip, options.android_strip_arg, library_path,
+        stripped_library_path)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/test/BUILD.gn b/build/android/gyp/test/BUILD.gn
new file mode 100644
index 0000000..2deac1d
--- /dev/null
+++ b/build/android/gyp/test/BUILD.gn
@@ -0,0 +1,13 @@
+import("//build/config/android/rules.gni")
+
+java_library("hello_world_java") {
+  java_files = [ "java/org/chromium/helloworld/HelloWorldPrinter.java" ]
+}
+
+java_binary("hello_world") {
+  deps = [
+    ":hello_world_java",
+  ]
+  java_files = [ "java/org/chromium/helloworld/HelloWorldMain.java" ]
+  main_class = "org.chromium.helloworld.HelloWorldMain"
+}
diff --git a/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldMain.java b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldMain.java
new file mode 100644
index 0000000..10860d8
--- /dev/null
+++ b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldMain.java
@@ -0,0 +1,15 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.helloworld;
+
+public class HelloWorldMain {
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            System.exit(Integer.parseInt(args[0]));
+        }
+        HelloWorldPrinter.print();
+    }
+}
+
diff --git a/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldPrinter.java b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldPrinter.java
new file mode 100644
index 0000000..b09673e
--- /dev/null
+++ b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldPrinter.java
@@ -0,0 +1,12 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.helloworld;
+
+public class HelloWorldPrinter {
+    public static void print() {
+        System.out.println("Hello, world!");
+    }
+}
+
diff --git a/build/android/gyp/touch.py b/build/android/gyp/touch.py
new file mode 100755
index 0000000..7b4375e
--- /dev/null
+++ b/build/android/gyp/touch.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium 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 sys
+
+from util import build_utils
+
+def main(argv):
+  for f in argv[1:]:
+    build_utils.Touch(f)
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/gyp/util/__init__.py b/build/android/gyp/util/__init__.py
new file mode 100644
index 0000000..727e987
--- /dev/null
+++ b/build/android/gyp/util/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/gyp/util/build_device.py b/build/android/gyp/util/build_device.py
new file mode 100644
index 0000000..7e0d57b
--- /dev/null
+++ b/build/android/gyp/util/build_device.py
@@ -0,0 +1,105 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" A simple device interface for build steps.
+
+"""
+
+import logging
+import os
+import re
+import sys
+
+from util import build_utils
+
+BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..', '..')
+sys.path.append(BUILD_ANDROID_DIR)
+
+from pylib import android_commands
+from pylib.device import device_errors
+from pylib.device import device_utils
+
+GetAttachedDevices = android_commands.GetAttachedDevices
+
+
+class BuildDevice(object):
+  def __init__(self, configuration):
+    self.id = configuration['id']
+    self.description = configuration['description']
+    self.install_metadata = configuration['install_metadata']
+    self.device = device_utils.DeviceUtils(self.id)
+
+  def RunShellCommand(self, *args, **kwargs):
+    return self.device.RunShellCommand(*args, **kwargs)
+
+  def PushChangedFiles(self, *args, **kwargs):
+    return self.device.PushChangedFiles(*args, **kwargs)
+
+  def GetSerialNumber(self):
+    return self.id
+
+  def Install(self, *args, **kwargs):
+    return self.device.Install(*args, **kwargs)
+
+  def GetInstallMetadata(self, apk_package):
+    """Gets the metadata on the device for the apk_package apk."""
+    # Matches lines like:
+    # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
+    #   org.chromium.chrome.shell.apk
+    # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
+    #   org.chromium.chrome.shell-1.apk
+    apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?.apk$' % apk_package, s)
+    matches = filter(apk_matcher, self.install_metadata)
+    return matches[0] if matches else None
+
+
+def GetConfigurationForDevice(device_id):
+  device = device_utils.DeviceUtils(device_id)
+  configuration = None
+  has_root = False
+  is_online = device.IsOnline()
+  if is_online:
+    cmd = 'ls -l /data/app; getprop ro.build.description'
+    cmd_output = device.RunShellCommand(cmd)
+    has_root = not 'Permission denied' in cmd_output[0]
+    if not has_root:
+      # Disable warning log messages from EnableRoot()
+      logging.getLogger().disabled = True
+      try:
+        device.EnableRoot()
+        has_root = True
+      except device_errors.CommandFailedError:
+        has_root = False
+      finally:
+        logging.getLogger().disabled = False
+      cmd_output = device.RunShellCommand(cmd)
+
+    configuration = {
+        'id': device_id,
+        'description': cmd_output[-1],
+        'install_metadata': cmd_output[:-1],
+      }
+  return configuration, is_online, has_root
+
+
+def WriteConfigurations(configurations, path):
+  # Currently we only support installing to the first device.
+  build_utils.WriteJson(configurations[:1], path, only_if_changed=True)
+
+
+def ReadConfigurations(path):
+  return build_utils.ReadJson(path)
+
+
+def GetBuildDevice(configurations):
+  assert len(configurations) == 1
+  return BuildDevice(configurations[0])
+
+
+def GetBuildDeviceFromPath(path):
+  configurations = ReadConfigurations(path)
+  if len(configurations) > 0:
+    return GetBuildDevice(ReadConfigurations(path))
+  return None
+
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
new file mode 100644
index 0000000..65b1a64
--- /dev/null
+++ b/build/android/gyp/util/build_utils.py
@@ -0,0 +1,376 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import ast
+import contextlib
+import fnmatch
+import json
+import os
+import pipes
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+
+CHROMIUM_SRC = os.path.normpath(
+    os.path.join(os.path.dirname(__file__),
+                 os.pardir, os.pardir, os.pardir, os.pardir))
+COLORAMA_ROOT = os.path.join(CHROMIUM_SRC,
+                             'third_party', 'colorama', 'src')
+# aapt should ignore OWNERS files in addition the default ignore pattern.
+AAPT_IGNORE_PATTERN = ('!OWNERS:!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:' +
+                       '!CVS:!thumbs.db:!picasa.ini:!*~:!*.d.stamp')
+
+
+@contextlib.contextmanager
+def TempDir():
+  dirname = tempfile.mkdtemp()
+  try:
+    yield dirname
+  finally:
+    shutil.rmtree(dirname)
+
+
+def MakeDirectory(dir_path):
+  try:
+    os.makedirs(dir_path)
+  except OSError:
+    pass
+
+
+def DeleteDirectory(dir_path):
+  if os.path.exists(dir_path):
+    shutil.rmtree(dir_path)
+
+
+def Touch(path, fail_if_missing=False):
+  if fail_if_missing and not os.path.exists(path):
+    raise Exception(path + ' doesn\'t exist.')
+
+  MakeDirectory(os.path.dirname(path))
+  with open(path, 'a'):
+    os.utime(path, None)
+
+
+def FindInDirectory(directory, filename_filter):
+  files = []
+  for root, _dirnames, filenames in os.walk(directory):
+    matched_files = fnmatch.filter(filenames, filename_filter)
+    files.extend((os.path.join(root, f) for f in matched_files))
+  return files
+
+
+def FindInDirectories(directories, filename_filter):
+  all_files = []
+  for directory in directories:
+    all_files.extend(FindInDirectory(directory, filename_filter))
+  return all_files
+
+
+def ParseGnList(gn_string):
+  return ast.literal_eval(gn_string)
+
+
+def ParseGypList(gyp_string):
+  # The ninja generator doesn't support $ in strings, so use ## to
+  # represent $.
+  # TODO(cjhopman): Remove when
+  # https://code.google.com/p/gyp/issues/detail?id=327
+  # is addressed.
+  gyp_string = gyp_string.replace('##', '$')
+
+  if gyp_string.startswith('['):
+    return ParseGnList(gyp_string)
+  return shlex.split(gyp_string)
+
+
+def CheckOptions(options, parser, required=None):
+  if not required:
+    return
+  for option_name in required:
+    if getattr(options, option_name) is None:
+      parser.error('--%s is required' % option_name.replace('_', '-'))
+
+
+def WriteJson(obj, path, only_if_changed=False):
+  old_dump = None
+  if os.path.exists(path):
+    with open(path, 'r') as oldfile:
+      old_dump = oldfile.read()
+
+  new_dump = json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': '))
+
+  if not only_if_changed or old_dump != new_dump:
+    with open(path, 'w') as outfile:
+      outfile.write(new_dump)
+
+
+def ReadJson(path):
+  with open(path, 'r') as jsonfile:
+    return json.load(jsonfile)
+
+
+class CalledProcessError(Exception):
+  """This exception is raised when the process run by CheckOutput
+  exits with a non-zero exit code."""
+
+  def __init__(self, cwd, args, output):
+    super(CalledProcessError, self).__init__()
+    self.cwd = cwd
+    self.args = args
+    self.output = output
+
+  def __str__(self):
+    # A user should be able to simply copy and paste the command that failed
+    # into their shell.
+    copyable_command = '( cd {}; {} )'.format(os.path.abspath(self.cwd),
+        ' '.join(map(pipes.quote, self.args)))
+    return 'Command failed: {}\n{}'.format(copyable_command, self.output)
+
+
+# This can be used in most cases like subprocess.check_output(). The output,
+# particularly when the command fails, better highlights the command's failure.
+# If the command fails, raises a build_utils.CalledProcessError.
+def CheckOutput(args, cwd=None,
+                print_stdout=False, print_stderr=True,
+                stdout_filter=None,
+                stderr_filter=None,
+                fail_func=lambda returncode, stderr: returncode != 0):
+  if not cwd:
+    cwd = os.getcwd()
+
+  child = subprocess.Popen(args,
+      stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
+  stdout, stderr = child.communicate()
+
+  if stdout_filter is not None:
+    stdout = stdout_filter(stdout)
+
+  if stderr_filter is not None:
+    stderr = stderr_filter(stderr)
+
+  if fail_func(child.returncode, stderr):
+    raise CalledProcessError(cwd, args, stdout + stderr)
+
+  if print_stdout:
+    sys.stdout.write(stdout)
+  if print_stderr:
+    sys.stderr.write(stderr)
+
+  return stdout
+
+
+def GetModifiedTime(path):
+  # For a symlink, the modified time should be the greater of the link's
+  # modified time and the modified time of the target.
+  return max(os.lstat(path).st_mtime, os.stat(path).st_mtime)
+
+
+def IsTimeStale(output, inputs):
+  if not os.path.exists(output):
+    return True
+
+  output_time = GetModifiedTime(output)
+  for i in inputs:
+    if GetModifiedTime(i) > output_time:
+      return True
+  return False
+
+
+def IsDeviceReady():
+  device_state = CheckOutput(['adb', 'get-state'])
+  return device_state.strip() == 'device'
+
+
+def CheckZipPath(name):
+  if os.path.normpath(name) != name:
+    raise Exception('Non-canonical zip path: %s' % name)
+  if os.path.isabs(name):
+    raise Exception('Absolute zip path: %s' % name)
+
+
+def ExtractAll(zip_path, path=None, no_clobber=True, pattern=None):
+  if path is None:
+    path = os.getcwd()
+  elif not os.path.exists(path):
+    MakeDirectory(path)
+
+  with zipfile.ZipFile(zip_path) as z:
+    for name in z.namelist():
+      if name.endswith('/'):
+        continue
+      if pattern is not None:
+        if not fnmatch.fnmatch(name, pattern):
+          continue
+      CheckZipPath(name)
+      if no_clobber:
+        output_path = os.path.join(path, name)
+        if os.path.exists(output_path):
+          raise Exception(
+              'Path already exists from zip: %s %s %s'
+              % (zip_path, name, output_path))
+
+    z.extractall(path=path)
+
+
+def DoZip(inputs, output, base_dir):
+  with zipfile.ZipFile(output, 'w') as outfile:
+    for f in inputs:
+      CheckZipPath(os.path.relpath(f, base_dir))
+      outfile.write(f, os.path.relpath(f, base_dir))
+
+
+def ZipDir(output, base_dir):
+  with zipfile.ZipFile(output, 'w') as outfile:
+    for root, _, files in os.walk(base_dir):
+      for f in files:
+        path = os.path.join(root, f)
+        archive_path = os.path.relpath(path, base_dir)
+        CheckZipPath(archive_path)
+        outfile.write(path, archive_path)
+
+
+def MergeZips(output, inputs, exclude_patterns=None):
+  added_names = set()
+  def Allow(name):
+    if exclude_patterns is not None:
+      for p in exclude_patterns:
+        if fnmatch.fnmatch(name, p):
+          return False
+    return True
+
+  with zipfile.ZipFile(output, 'w') as out_zip:
+    for in_file in inputs:
+      with zipfile.ZipFile(in_file, 'r') as in_zip:
+        for name in in_zip.namelist():
+          if name not in added_names and Allow(name):
+            out_zip.writestr(name, in_zip.read(name))
+            added_names.add(name)
+
+
+def PrintWarning(message):
+  print 'WARNING: ' + message
+
+
+def PrintBigWarning(message):
+  print '*****     ' * 8
+  PrintWarning(message)
+  print '*****     ' * 8
+
+
+def GetSortedTransitiveDependencies(top, deps_func):
+  """Gets the list of all transitive dependencies in sorted order.
+
+  There should be no cycles in the dependency graph.
+
+  Args:
+    top: a list of the top level nodes
+    deps_func: A function that takes a node and returns its direct dependencies.
+  Returns:
+    A list of all transitive dependencies of nodes in top, in order (a node will
+    appear in the list at a higher index than all of its dependencies).
+  """
+  def Node(dep):
+    return (dep, deps_func(dep))
+
+  # First: find all deps
+  unchecked_deps = list(top)
+  all_deps = set(top)
+  while unchecked_deps:
+    dep = unchecked_deps.pop()
+    new_deps = deps_func(dep).difference(all_deps)
+    unchecked_deps.extend(new_deps)
+    all_deps = all_deps.union(new_deps)
+
+  # Then: simple, slow topological sort.
+  sorted_deps = []
+  unsorted_deps = dict(map(Node, all_deps))
+  while unsorted_deps:
+    for library, dependencies in unsorted_deps.items():
+      if not dependencies.intersection(unsorted_deps.keys()):
+        sorted_deps.append(library)
+        del unsorted_deps[library]
+
+  return sorted_deps
+
+
+def GetPythonDependencies():
+  """Gets the paths of imported non-system python modules.
+
+  A path is assumed to be a "system" import if it is outside of chromium's
+  src/. The paths will be relative to the current directory.
+  """
+  module_paths = (m.__file__ for m in sys.modules.itervalues()
+                  if m is not None and hasattr(m, '__file__'))
+
+  abs_module_paths = map(os.path.abspath, module_paths)
+
+  non_system_module_paths = [
+      p for p in abs_module_paths if p.startswith(CHROMIUM_SRC)]
+  def ConvertPycToPy(s):
+    if s.endswith('.pyc'):
+      return s[:-1]
+    return s
+
+  non_system_module_paths = map(ConvertPycToPy, non_system_module_paths)
+  non_system_module_paths = map(os.path.relpath, non_system_module_paths)
+  return sorted(set(non_system_module_paths))
+
+
+def AddDepfileOption(parser):
+  parser.add_option('--depfile',
+                    help='Path to depfile. This must be specified as the '
+                    'action\'s first output.')
+
+
+def WriteDepfile(path, dependencies):
+  with open(path, 'w') as depfile:
+    depfile.write(path)
+    depfile.write(': ')
+    depfile.write(' '.join(dependencies))
+    depfile.write('\n')
+
+
+def ExpandFileArgs(args):
+  """Replaces file-arg placeholders in args.
+
+  These placeholders have the form:
+    @FileArg(filename:key1:key2:...:keyn)
+
+  The value of such a placeholder is calculated by reading 'filename' as json.
+  And then extracting the value at [key1][key2]...[keyn].
+
+  Note: This intentionally does not return the list of files that appear in such
+  placeholders. An action that uses file-args *must* know the paths of those
+  files prior to the parsing of the arguments (typically by explicitly listing
+  them in the action's inputs in build files).
+  """
+  new_args = list(args)
+  file_jsons = dict()
+  r = re.compile('@FileArg\((.*?)\)')
+  for i, arg in enumerate(args):
+    match = r.search(arg)
+    if not match:
+      continue
+
+    if match.end() != len(arg):
+      raise Exception('Unexpected characters after FileArg: ' + arg)
+
+    lookup_path = match.group(1).split(':')
+    file_path = lookup_path[0]
+    if not file_path in file_jsons:
+      file_jsons[file_path] = ReadJson(file_path)
+
+    expansion = file_jsons[file_path]
+    for k in lookup_path[1:]:
+      expansion = expansion[k]
+
+    new_args[i] = arg[:match.start()] + str(expansion)
+
+  return new_args
+
diff --git a/build/android/gyp/util/md5_check.py b/build/android/gyp/util/md5_check.py
new file mode 100644
index 0000000..9f365aa
--- /dev/null
+++ b/build/android/gyp/util/md5_check.py
@@ -0,0 +1,86 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import hashlib
+import os
+
+
+def CallAndRecordIfStale(
+    function, record_path=None, input_paths=None, input_strings=None,
+    force=False):
+  """Calls function if the md5sum of the input paths/strings has changed.
+
+  The md5sum of the inputs is compared with the one stored in record_path. If
+  this has changed (or the record doesn't exist), function will be called and
+  the new md5sum will be recorded.
+
+  If force is True, the function will be called regardless of whether the
+  md5sum is out of date.
+  """
+  if not input_paths:
+    input_paths = []
+  if not input_strings:
+    input_strings = []
+  md5_checker = _Md5Checker(
+      record_path=record_path,
+      input_paths=input_paths,
+      input_strings=input_strings)
+  if force or md5_checker.IsStale():
+    function()
+    md5_checker.Write()
+
+
+def _UpdateMd5ForFile(md5, path, block_size=2**16):
+  with open(path, 'rb') as infile:
+    while True:
+      data = infile.read(block_size)
+      if not data:
+        break
+      md5.update(data)
+
+
+def _UpdateMd5ForDirectory(md5, dir_path):
+  for root, _, files in os.walk(dir_path):
+    for f in files:
+      _UpdateMd5ForFile(md5, os.path.join(root, f))
+
+
+def _UpdateMd5ForPath(md5, path):
+  if os.path.isdir(path):
+    _UpdateMd5ForDirectory(md5, path)
+  else:
+    _UpdateMd5ForFile(md5, path)
+
+
+class _Md5Checker(object):
+  def __init__(self, record_path=None, input_paths=None, input_strings=None):
+    if not input_paths:
+      input_paths = []
+    if not input_strings:
+      input_strings = []
+
+    assert record_path.endswith('.stamp'), (
+        'record paths must end in \'.stamp\' so that they are easy to find '
+        'and delete')
+
+    self.record_path = record_path
+
+    md5 = hashlib.md5()
+    for i in sorted(input_paths):
+      _UpdateMd5ForPath(md5, i)
+    for s in input_strings:
+      md5.update(s)
+    self.new_digest = md5.hexdigest()
+
+    self.old_digest = ''
+    if os.path.exists(self.record_path):
+      with open(self.record_path, 'r') as old_record:
+        self.old_digest = old_record.read()
+
+  def IsStale(self):
+    return self.old_digest != self.new_digest
+
+  def Write(self):
+    with open(self.record_path, 'w') as new_record:
+      new_record.write(self.new_digest)
diff --git a/build/android/gyp/util/md5_check_test.py b/build/android/gyp/util/md5_check_test.py
new file mode 100644
index 0000000..4f89fc2
--- /dev/null
+++ b/build/android/gyp/util/md5_check_test.py
@@ -0,0 +1,72 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import tempfile
+import unittest
+
+import md5_check # pylint: disable=W0403
+
+
+class TestMd5Check(unittest.TestCase):
+  def setUp(self):
+    self.called = False
+
+  def testCallAndRecordIfStale(self):
+    input_strings = ['string1', 'string2']
+    input_file1 = tempfile.NamedTemporaryFile()
+    input_file2 = tempfile.NamedTemporaryFile()
+    file1_contents = 'input file 1'
+    file2_contents = 'input file 2'
+    input_file1.write(file1_contents)
+    input_file1.flush()
+    input_file2.write(file2_contents)
+    input_file2.flush()
+    input_files = [input_file1.name, input_file2.name]
+
+    record_path = tempfile.NamedTemporaryFile(suffix='.stamp')
+
+    def CheckCallAndRecord(should_call, message, force=False):
+      self.called = False
+      def MarkCalled():
+        self.called = True
+      md5_check.CallAndRecordIfStale(
+          MarkCalled,
+          record_path=record_path.name,
+          input_paths=input_files,
+          input_strings=input_strings,
+          force=force)
+      self.failUnlessEqual(should_call, self.called, message)
+
+    CheckCallAndRecord(True, 'should call when record doesn\'t exist')
+    CheckCallAndRecord(False, 'should not call when nothing changed')
+    CheckCallAndRecord(True, force=True, message='should call when forced')
+
+    input_file1.write('some more input')
+    input_file1.flush()
+    CheckCallAndRecord(True, 'changed input file should trigger call')
+
+    input_files = input_files[::-1]
+    CheckCallAndRecord(False, 'reordering of inputs shouldn\'t trigger call')
+
+    input_files = input_files[:1]
+    CheckCallAndRecord(True, 'removing file should trigger call')
+
+    input_files.append(input_file2.name)
+    CheckCallAndRecord(True, 'added input file should trigger call')
+
+    input_strings[0] = input_strings[0] + ' a bit longer'
+    CheckCallAndRecord(True, 'changed input string should trigger call')
+
+    input_strings = input_strings[::-1]
+    CheckCallAndRecord(True, 'reordering of string inputs should trigger call')
+
+    input_strings = input_strings[:1]
+    CheckCallAndRecord(True, 'removing a string should trigger call')
+
+    input_strings.append('a brand new string')
+    CheckCallAndRecord(True, 'added input string should trigger call')
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py
new file mode 100644
index 0000000..901cd9f
--- /dev/null
+++ b/build/android/gyp/util/proguard_util.py
@@ -0,0 +1,128 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+from util import build_utils
+
+def FilterProguardOutput(output):
+  '''ProGuard outputs boring stuff to stdout (proguard version, jar path, etc)
+  as well as interesting stuff (notes, warnings, etc). If stdout is entirely
+  boring, this method suppresses the output.
+  '''
+  ignore_patterns = [
+    'ProGuard, version ',
+    'Reading program jar [',
+    'Reading library jar [',
+    'Preparing output jar [',
+    '  Copying resources from program jar [',
+  ]
+  for line in output.splitlines():
+    for pattern in ignore_patterns:
+      if line.startswith(pattern):
+        break
+    else:
+      # line doesn't match any of the patterns; it's probably something worth
+      # printing out.
+      return output
+  return ''
+
+
+class ProguardCmdBuilder(object):
+  def __init__(self, proguard_jar):
+    assert os.path.exists(proguard_jar)
+    self._proguard_jar_path = proguard_jar
+    self._test = None
+    self._mapping = None
+    self._libraries = None
+    self._injars = None
+    self._configs = None
+    self._outjar = None
+
+  def outjar(self, path):
+    assert self._outjar is None
+    self._outjar = path
+
+  def is_test(self, enable):
+    assert self._test is None
+    self._test = enable
+
+  def mapping(self, path):
+    assert self._mapping is None
+    assert os.path.exists(path), path
+    self._mapping = path
+
+  def libraryjars(self, paths):
+    assert self._libraries is None
+    for p in paths:
+      assert os.path.exists(p), p
+    self._libraries = paths
+
+  def injars(self, paths):
+    assert self._injars is None
+    for p in paths:
+      assert os.path.exists(p), p
+    self._injars = paths
+
+  def configs(self, paths):
+    assert self._configs is None
+    for p in paths:
+      assert os.path.exists(p), p
+    self._configs = paths
+
+  def build(self):
+    assert self._injars is not None
+    assert self._outjar is not None
+    assert self._configs is not None
+    cmd = [
+      'java', '-jar', self._proguard_jar_path,
+      '-forceprocessing',
+    ]
+    if self._test:
+      cmd += [
+        '-dontobfuscate',
+        '-dontoptimize',
+        '-dontshrink',
+        '-dontskipnonpubliclibraryclassmembers',
+      ]
+
+    if self._mapping:
+      cmd += [
+        '-applymapping', self._mapping,
+      ]
+
+    if self._libraries:
+      cmd += [
+        '-libraryjars', ':'.join(self._libraries),
+      ]
+
+    cmd += [
+      '-injars', ':'.join(self._injars)
+    ]
+
+    for config_file in self._configs:
+      cmd += ['-include', config_file]
+
+    # The output jar must be specified after inputs.
+    cmd += [
+      '-outjars', self._outjar,
+      '-dump', self._outjar + '.dump',
+      '-printseeds', self._outjar + '.seeds',
+      '-printusage', self._outjar + '.usage',
+      '-printmapping', self._outjar + '.mapping',
+    ]
+    return cmd
+
+  def GetInputs(self):
+    inputs = [self._proguard_jar_path] + self._configs + self._injars
+    if self._mapping:
+      inputs.append(self._mapping)
+    if self._libraries:
+      inputs += self._libraries
+    return inputs
+
+
+  def CheckOutput(self):
+    build_utils.CheckOutput(self.build(), print_stdout=True,
+                            stdout_filter=FilterProguardOutput)
+
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
new file mode 100755
index 0000000..1b4379d
--- /dev/null
+++ b/build/android/gyp/write_build_config.py
@@ -0,0 +1,323 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Writes a build_config file.
+
+The build_config file for a target is a json file containing information about
+how to build that target based on the target's dependencies. This includes
+things like: the javac classpath, the list of android resources dependencies,
+etc. It also includes the information needed to create the build_config for
+other targets that depend on that one.
+
+Android build scripts should not refer to the build_config directly, and the
+build specification should instead pass information in using the special
+file-arg syntax (see build_utils.py:ExpandFileArgs). That syntax allows passing
+of values in a json dict in a file and looks like this:
+  --python-arg=@FileArg(build_config_path:javac:classpath)
+
+Note: If paths to input files are passed in this way, it is important that:
+  1. inputs/deps of the action ensure that the files are available the first
+  time the action runs.
+  2. Either (a) or (b)
+    a. inputs/deps ensure that the action runs whenever one of the files changes
+    b. the files are added to the action's depfile
+"""
+
+import optparse
+import os
+import sys
+import xml.dom.minidom
+
+from util import build_utils
+
+import write_ordered_libraries
+
+class AndroidManifest(object):
+  def __init__(self, path):
+    self.path = path
+    dom = xml.dom.minidom.parse(path)
+    manifests = dom.getElementsByTagName('manifest')
+    assert len(manifests) == 1
+    self.manifest = manifests[0]
+
+  def GetInstrumentation(self):
+    instrumentation_els = self.manifest.getElementsByTagName('instrumentation')
+    if len(instrumentation_els) == 0:
+      return None
+    if len(instrumentation_els) != 1:
+      raise Exception(
+          'More than one <instrumentation> element found in %s' % self.path)
+    return instrumentation_els[0]
+
+  def CheckInstrumentation(self, expected_package):
+    instr = self.GetInstrumentation()
+    if not instr:
+      raise Exception('No <instrumentation> elements found in %s' % self.path)
+    instrumented_package = instr.getAttributeNS(
+        'http://schemas.android.com/apk/res/android', 'targetPackage')
+    if instrumented_package != expected_package:
+      raise Exception(
+          'Wrong instrumented package. Expected %s, got %s'
+          % (expected_package, instrumented_package))
+
+  def GetPackageName(self):
+    return self.manifest.getAttribute('package')
+
+
+dep_config_cache = {}
+def GetDepConfig(path):
+  if not path in dep_config_cache:
+    dep_config_cache[path] = build_utils.ReadJson(path)['deps_info']
+  return dep_config_cache[path]
+
+
+def DepsOfType(wanted_type, configs):
+  return [c for c in configs if c['type'] == wanted_type]
+
+
+def GetAllDepsConfigsInOrder(deps_config_paths):
+  def Deps(path):
+    return set(GetDepConfig(path)['deps_configs'])
+  return build_utils.GetSortedTransitiveDependencies(deps_config_paths, Deps)
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option('--build-config', help='Path to build_config output.')
+  parser.add_option(
+      '--type',
+      help='Type of this target (e.g. android_library).')
+  parser.add_option(
+      '--possible-deps-configs',
+      help='List of paths for dependency\'s build_config files. Some '
+      'dependencies may not write build_config files. Missing build_config '
+      'files are handled differently based on the type of this target.')
+
+  # android_resources options
+  parser.add_option('--srcjar', help='Path to target\'s resources srcjar.')
+  parser.add_option('--resources-zip', help='Path to target\'s resources zip.')
+  parser.add_option('--package-name',
+      help='Java package name for these resources.')
+  parser.add_option('--android-manifest', help='Path to android manifest.')
+
+  # java library options
+  parser.add_option('--jar-path', help='Path to target\'s jar output.')
+  parser.add_option('--supports-android', action='store_true',
+      help='Whether this library supports running on the Android platform.')
+  parser.add_option('--requires-android', action='store_true',
+      help='Whether this library requires running on the Android platform.')
+  parser.add_option('--bypass-platform-checks', action='store_true',
+      help='Bypass checks for support/require Android platform.')
+
+  # android library options
+  parser.add_option('--dex-path', help='Path to target\'s dex output.')
+
+  # native library options
+  parser.add_option('--native-libs', help='List of top-level native libs.')
+  parser.add_option('--readelf-path', help='Path to toolchain\'s readelf.')
+
+  parser.add_option('--tested-apk-config',
+      help='Path to the build config of the tested apk (for an instrumentation '
+      'test apk).')
+
+  options, args = parser.parse_args(argv)
+
+  if args:
+    parser.error('No positional arguments should be given.')
+
+
+  if not options.type in [
+      'java_library', 'android_resources', 'android_apk', 'deps_dex']:
+    raise Exception('Unknown type: <%s>' % options.type)
+
+  required_options = ['build_config'] + {
+      'java_library': ['jar_path'],
+      'android_resources': ['resources_zip'],
+      'android_apk': ['jar_path', 'dex_path', 'resources_zip'],
+      'deps_dex': ['dex_path']
+    }[options.type]
+
+  if options.native_libs:
+    required_options.append('readelf_path')
+
+  build_utils.CheckOptions(options, parser, required_options)
+
+  if options.type == 'java_library':
+    if options.supports_android and not options.dex_path:
+      raise Exception('java_library that supports Android requires a dex path.')
+
+    if options.requires_android and not options.supports_android:
+      raise Exception(
+          '--supports-android is required when using --requires-android')
+
+  possible_deps_config_paths = build_utils.ParseGypList(
+      options.possible_deps_configs)
+
+  allow_unknown_deps = options.type == 'android_apk'
+  unknown_deps = [
+      c for c in possible_deps_config_paths if not os.path.exists(c)]
+  if unknown_deps and not allow_unknown_deps:
+    raise Exception('Unknown deps: ' + str(unknown_deps))
+
+  direct_deps_config_paths = [
+      c for c in possible_deps_config_paths if not c in unknown_deps]
+  all_deps_config_paths = GetAllDepsConfigsInOrder(direct_deps_config_paths)
+
+  direct_deps_configs = [GetDepConfig(p) for p in direct_deps_config_paths]
+  all_deps_configs = [GetDepConfig(p) for p in all_deps_config_paths]
+
+  direct_library_deps = DepsOfType('java_library', direct_deps_configs)
+  all_library_deps = DepsOfType('java_library', all_deps_configs)
+
+  direct_resources_deps = DepsOfType('android_resources', direct_deps_configs)
+  all_resources_deps = DepsOfType('android_resources', all_deps_configs)
+  # Resources should be ordered with the highest-level dependency first so that
+  # overrides are done correctly.
+  all_resources_deps.reverse()
+
+  # Initialize some common config.
+  config = {
+    'deps_info': {
+      'name': os.path.basename(options.build_config),
+      'path': options.build_config,
+      'type': options.type,
+      'deps_configs': direct_deps_config_paths,
+    }
+  }
+  deps_info = config['deps_info']
+
+  if options.type == 'java_library' and not options.bypass_platform_checks:
+    deps_info['requires_android'] = options.requires_android
+    deps_info['supports_android'] = options.supports_android
+
+    deps_require_android = (all_resources_deps +
+        [d['name'] for d in all_library_deps if d['requires_android']])
+    deps_not_support_android = (
+        [d['name'] for d in all_library_deps if not d['supports_android']])
+
+    if deps_require_android and not options.requires_android:
+      raise Exception('Some deps require building for the Android platform: ' +
+          str(deps_require_android))
+
+    if deps_not_support_android and options.supports_android:
+      raise Exception('Not all deps support the Android platform: ' +
+          str(deps_not_support_android))
+
+  if options.type in ['java_library', 'android_apk']:
+    javac_classpath = [c['jar_path'] for c in direct_library_deps]
+    java_full_classpath = [c['jar_path'] for c in all_library_deps]
+    deps_info['resources_deps'] = [c['path'] for c in all_resources_deps]
+    deps_info['jar_path'] = options.jar_path
+    if options.type == 'android_apk' or options.supports_android:
+      deps_info['dex_path'] = options.dex_path
+    config['javac'] = {
+      'classpath': javac_classpath,
+    }
+    config['java'] = {
+      'full_classpath': java_full_classpath
+    }
+
+  if options.type == 'java_library':
+    # Only resources might have srcjars (normal srcjar targets are listed in
+    # srcjar_deps). A resource's srcjar contains the R.java file for those
+    # resources, and (like Android's default build system) we allow a library to
+    # refer to the resources in any of its dependents.
+    config['javac']['srcjars'] = [
+        c['srcjar'] for c in direct_resources_deps if 'srcjar' in c]
+
+  if options.type == 'android_apk':
+    # Apks will get their resources srcjar explicitly passed to the java step.
+    config['javac']['srcjars'] = []
+
+  if options.type == 'android_resources':
+    deps_info['resources_zip'] = options.resources_zip
+    if options.srcjar:
+      deps_info['srcjar'] = options.srcjar
+    if options.package_name:
+      deps_info['package_name'] = options.package_name
+
+  if options.type == 'android_resources' or options.type == 'android_apk':
+    config['resources'] = {}
+    config['resources']['dependency_zips'] = [
+        c['resources_zip'] for c in all_resources_deps]
+    config['resources']['extra_package_names'] = []
+
+  if options.type == 'android_apk':
+    config['resources']['extra_package_names'] = [
+        c['package_name'] for c in all_resources_deps if 'package_name' in c]
+
+  if options.type in ['android_apk', 'deps_dex']:
+    deps_dex_files = [c['dex_path'] for c in all_library_deps]
+
+  # An instrumentation test apk should exclude the dex files that are in the apk
+  # under test.
+  if options.type == 'android_apk' and options.tested_apk_config:
+    tested_apk_config_paths = GetAllDepsConfigsInOrder(
+        [options.tested_apk_config])
+    tested_apk_configs = [GetDepConfig(p) for p in tested_apk_config_paths]
+    tested_apk_library_deps = DepsOfType('java_library', tested_apk_configs)
+    tested_apk_deps_dex_files = [c['dex_path'] for c in tested_apk_library_deps]
+    deps_dex_files = [
+        p for p in deps_dex_files if not p in tested_apk_deps_dex_files]
+
+    tested_apk_config = GetDepConfig(options.tested_apk_config)
+    expected_tested_package = tested_apk_config['package_name']
+    AndroidManifest(options.android_manifest).CheckInstrumentation(
+        expected_tested_package)
+
+  # Dependencies for the final dex file of an apk or a 'deps_dex'.
+  if options.type in ['android_apk', 'deps_dex']:
+    config['final_dex'] = {}
+    dex_config = config['final_dex']
+    # TODO(cjhopman): proguard version
+    dex_config['dependency_dex_files'] = deps_dex_files
+
+  if options.type == 'android_apk':
+    config['dist_jar'] = {
+      'dependency_jars': [
+        c['jar_path'] for c in all_library_deps
+      ]
+    }
+    manifest = AndroidManifest(options.android_manifest)
+    deps_info['package_name'] = manifest.GetPackageName()
+    if not options.tested_apk_config and manifest.GetInstrumentation():
+      # This must then have instrumentation only for itself.
+      manifest.CheckInstrumentation(manifest.GetPackageName())
+
+    library_paths = []
+    java_libraries_list = []
+    if options.native_libs:
+      libraries = build_utils.ParseGypList(options.native_libs)
+      if libraries:
+        libraries_dir = os.path.dirname(libraries[0])
+        write_ordered_libraries.SetReadelfPath(options.readelf_path)
+        write_ordered_libraries.SetLibraryDirs([libraries_dir])
+        all_native_library_deps = (
+            write_ordered_libraries.GetSortedTransitiveDependenciesForBinaries(
+                libraries))
+        # Create a java literal array with the "base" library names:
+        # e.g. libfoo.so -> foo
+        java_libraries_list = '{%s}' % ','.join(
+            ['"%s"' % s[3:-3] for s in all_native_library_deps])
+        library_paths = map(
+            write_ordered_libraries.FullLibraryPath, all_native_library_deps)
+
+      config['native'] = {
+        'libraries': library_paths,
+        'java_libraries_list': java_libraries_list
+      }
+
+  build_utils.WriteJson(config, options.build_config, only_if_changed=True)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        all_deps_config_paths + build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/write_ordered_libraries.py b/build/android/gyp/write_ordered_libraries.py
new file mode 100755
index 0000000..67e7805
--- /dev/null
+++ b/build/android/gyp/write_ordered_libraries.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Writes dependency ordered list of native libraries.
+
+The list excludes any Android system libraries, as those are not bundled with
+the APK.
+
+This list of libraries is used for several steps of building an APK.
+In the component build, the --input-libraries only needs to be the top-level
+library (i.e. libcontent_shell_content_view). This will then use readelf to
+inspect the shared libraries and determine the full list of (non-system)
+libraries that should be included in the APK.
+"""
+
+# TODO(cjhopman): See if we can expose the list of library dependencies from
+# gyp, rather than calculating it ourselves.
+# http://crbug.com/225558
+
+import optparse
+import os
+import re
+import sys
+
+from util import build_utils
+
+_readelf = None
+_library_dirs = None
+
+_library_re = re.compile(
+    '.*NEEDED.*Shared library: \[(?P<library_name>.+)\]')
+
+
+def SetReadelfPath(path):
+  global _readelf
+  _readelf = path
+
+
+def SetLibraryDirs(dirs):
+  global _library_dirs
+  _library_dirs = dirs
+
+
+def FullLibraryPath(library_name):
+  assert _library_dirs is not None
+  for directory in _library_dirs:
+    path = '%s/%s' % (directory, library_name)
+    if os.path.exists(path):
+      return path
+  return library_name
+
+
+def IsSystemLibrary(library_name):
+  # If the library doesn't exist in the libraries directory, assume that it is
+  # an Android system library.
+  return not os.path.exists(FullLibraryPath(library_name))
+
+
+def CallReadElf(library_or_executable):
+  assert _readelf is not None
+  readelf_cmd = [_readelf,
+                 '-d',
+                 FullLibraryPath(library_or_executable)]
+  return build_utils.CheckOutput(readelf_cmd)
+
+
+def GetDependencies(library_or_executable):
+  elf = CallReadElf(library_or_executable)
+  return set(_library_re.findall(elf))
+
+
+def GetNonSystemDependencies(library_name):
+  all_deps = GetDependencies(FullLibraryPath(library_name))
+  return set((lib for lib in all_deps if not IsSystemLibrary(lib)))
+
+
+def GetSortedTransitiveDependencies(libraries):
+  """Returns all transitive library dependencies in dependency order."""
+  return build_utils.GetSortedTransitiveDependencies(
+      libraries, GetNonSystemDependencies)
+
+
+def GetSortedTransitiveDependenciesForBinaries(binaries):
+  if binaries[0].endswith('.so'):
+    libraries = [os.path.basename(lib) for lib in binaries]
+  else:
+    assert len(binaries) == 1
+    all_deps = GetDependencies(binaries[0])
+    libraries = [lib for lib in all_deps if not IsSystemLibrary(lib)]
+
+  return GetSortedTransitiveDependencies(libraries)
+
+
+def main():
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--input-libraries',
+      help='A list of top-level input libraries.')
+  parser.add_option('--libraries-dir',
+      help='The directory which contains shared libraries.')
+  parser.add_option('--readelf', help='Path to the readelf binary.')
+  parser.add_option('--output', help='Path to the generated .json file.')
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  options, _ = parser.parse_args()
+
+  SetReadelfPath(options.readelf)
+  SetLibraryDirs(options.libraries_dir.split(','))
+
+  libraries = build_utils.ParseGypList(options.input_libraries)
+  if len(libraries):
+    libraries = GetSortedTransitiveDependenciesForBinaries(libraries)
+
+  # Convert to "base" library names: e.g. libfoo.so -> foo
+  java_libraries_list = (
+      '{%s}' % ','.join(['"%s"' % s[3:-3] for s in libraries]))
+
+  build_utils.WriteJson(
+      {'libraries': libraries, 'java_libraries_list': java_libraries_list},
+      options.output,
+      only_if_changed=True)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        libraries + build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main())
+
+
diff --git a/build/android/gyp/zip.py b/build/android/gyp/zip.py
new file mode 100755
index 0000000..51322df
--- /dev/null
+++ b/build/android/gyp/zip.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Archives a set of files.
+"""
+
+import optparse
+import sys
+
+from util import build_utils
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--input-dir', help='Directory of files to archive.')
+  parser.add_option('--output', help='Path to output archive.')
+  options, _ = parser.parse_args()
+
+  inputs = build_utils.FindInDirectory(options.input_dir, '*')
+  build_utils.DoZip(inputs, options.output, options.input_dir)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/host_heartbeat.py b/build/android/host_heartbeat.py
new file mode 100755
index 0000000..6a7cdd1
--- /dev/null
+++ b/build/android/host_heartbeat.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Sends a heart beat pulse to the currently online Android devices.
+This heart beat lets the devices know that they are connected to a host.
+"""
+# pylint: disable=W0702
+
+import sys
+import time
+
+from pylib.device import device_utils
+
+PULSE_PERIOD = 20
+
+def main():
+  while True:
+    try:
+      devices = device_utils.DeviceUtils.HealthyDevices()
+      for d in devices:
+        d.RunShellCommand(['touch', '/sdcard/host_heartbeat'],
+                          check_return=True)
+    except:
+      # Keep the heatbeat running bypassing all errors.
+      pass
+    time.sleep(PULSE_PERIOD)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/increase_size_for_speed.gypi b/build/android/increase_size_for_speed.gypi
new file mode 100644
index 0000000..48d17f5
--- /dev/null
+++ b/build/android/increase_size_for_speed.gypi
@@ -0,0 +1,42 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included to optimize a target for speed
+# rather than for size on Android.
+# This is used in some carefully tailored targets and is not meant
+# to be included everywhere. Before adding the template to another target,
+# please ask in chromium-dev@. See crbug.com/411909
+
+{
+  'configurations': {
+    'Release': {
+      'target_conditions': [
+        ['_toolset=="target"', {
+          'conditions': [
+            ['OS=="android"', {
+              'cflags!': ['-Os'],
+              'cflags': ['-O2'],
+            }],
+            # Do not merge -Os and -O2 in LTO.
+            # LTO merges all optimization options at link-time. -O2 takes
+            # precedence over -Os. Avoid using LTO simultaneously
+            # on -Os and -O2 parts for that reason.
+            ['OS=="android" and use_lto==1', {
+              'cflags!': [
+                '-flto',
+                '-ffat-lto-objects',
+              ],
+            }],
+            ['OS=="android" and use_lto_o2==1', {
+              'cflags': [
+                '-flto',
+                '-ffat-lto-objects',
+              ],
+            }],
+          ],
+        }],
+      ],
+    },
+  },
+}
diff --git a/build/android/insert_chromium_version.gypi b/build/android/insert_chromium_version.gypi
new file mode 100644
index 0000000..a6ff908
--- /dev/null
+++ b/build/android/insert_chromium_version.gypi
@@ -0,0 +1,53 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule that
+# inserts a chromium version string into native libraries.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'action_name': 'insert_chromium_version',
+#    'actions': [
+#      'variables': {
+#        'ordered_libraries_file': 'file generated by write_ordered_libraries'
+#        'stripped_libraries_dir': 'the directory contains native libraries'
+#        'input_paths': 'files to be added to the list of inputs'
+#        'stamp': 'file to touch when the action is complete'
+#        'version_string': 'chromium version string to be inserted'
+#      'includes': [ '../../build/android/insert_chromium_version.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'message': 'Inserting chromium version string into native libraries',
+  'variables': {
+    'input_paths': [],
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/insert_chromium_version.py',
+    '<(ordered_libraries_file)',
+    '>@(input_paths)',
+  ],
+  'outputs': [
+    '<(stamp)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/insert_chromium_version.py',
+    '--android-objcopy=<(android_objcopy)',
+    '--stripped-libraries-dir=<(stripped_libraries_dir)',
+    '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
+    '--version-string=<(version_string)',
+    '--stamp=<(stamp)',
+  ],
+  'conditions': [
+    ['component == "shared_library"', {
+      # Add a fake output to force the build to always re-run this step. This
+      # is required because the real inputs are not known at gyp-time and
+      # changing base.so may not trigger changes to dependent libraries.
+      'outputs': [ '<(stamp).fake' ]
+    }],
+  ],
+}
diff --git a/build/android/install_emulator_deps.py b/build/android/install_emulator_deps.py
new file mode 100755
index 0000000..82d1c75
--- /dev/null
+++ b/build/android/install_emulator_deps.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python
+# 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.
+
+"""Installs deps for using SDK emulator for testing.
+
+The script will download the SDK and system images, if they are not present, and
+install and enable KVM, if virtualization has been enabled in the BIOS.
+"""
+
+
+import logging
+import optparse
+import os
+import re
+import shutil
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib import pexpect
+from pylib.utils import run_tests_helper
+
+# Android API level
+DEFAULT_ANDROID_API_LEVEL = constants.ANDROID_SDK_VERSION
+
+# From the Android Developer's website.
+# Keep this up to date; the user can install older API levels as necessary.
+SDK_BASE_URL = 'http://dl.google.com/android/adt'
+SDK_ZIP = 'adt-bundle-linux-x86_64-20131030.zip'
+
+# pylint: disable=line-too-long
+# Android x86 system image from the Intel website:
+# http://software.intel.com/en-us/articles/intel-eula-x86-android-4-2-jelly-bean-bin
+# These don't exist prior to Android-15.
+# As of 08 Nov 2013, Android-19 is not yet available either.
+X86_IMG_URLS = {
+  15: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-15_r01.zip',
+  16: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-16_r01.zip',
+  17: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-17_r01.zip',
+  18: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-18_r01.zip',
+  19: 'https://software.intel.com/sites/landingpage/android/sysimg_x86-19_r01.zip'}
+#pylint: enable=line-too-long
+
+def CheckSDK():
+  """Check if SDK is already installed.
+
+  Returns:
+    True if the emulator SDK directory (src/android_emulator_sdk/) exists.
+  """
+  return os.path.exists(constants.EMULATOR_SDK_ROOT)
+
+
+def CheckSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL):
+  """Check if the "SDK Platform" for the specified API level is installed.
+     This is necessary in order for the emulator to run when the target
+     is specified.
+
+  Args:
+    api_level: the Android API level to check; defaults to the latest API.
+
+  Returns:
+    True if the platform is already installed.
+  """
+  android_binary = os.path.join(constants.EMULATOR_SDK_ROOT,
+                                'sdk', 'tools', 'android')
+  pattern = re.compile('id: [0-9]+ or "android-%d"' % api_level)
+  try:
+    exit_code, stdout = cmd_helper.GetCmdStatusAndOutput(
+        [android_binary, 'list'])
+    if exit_code != 0:
+      raise Exception('\'android list\' command failed')
+    for line in stdout.split('\n'):
+      if pattern.match(line):
+        return True
+    return False
+  except OSError:
+    logging.exception('Unable to execute \'android list\'')
+    return False
+
+
+def CheckX86Image(api_level=DEFAULT_ANDROID_API_LEVEL):
+  """Check if Android system images have been installed.
+
+  Args:
+    api_level: the Android API level to check for; defaults to the latest API.
+
+  Returns:
+    True if sdk/system-images/android-<api_level>/x86 exists inside
+    EMULATOR_SDK_ROOT.
+  """
+  api_target = 'android-%d' % api_level
+  return os.path.exists(os.path.join(constants.EMULATOR_SDK_ROOT,
+                                     'sdk', 'system-images',
+                                     api_target, 'x86'))
+
+
+def CheckKVM():
+  """Quickly check whether KVM is enabled.
+
+  Returns:
+    True iff /dev/kvm exists (Linux only).
+  """
+  return os.path.exists('/dev/kvm')
+
+
+def RunKvmOk():
+  """Run kvm-ok as root to check that KVM is properly enabled after installation
+     of the required packages.
+
+  Returns:
+    True iff KVM is enabled (/dev/kvm exists). On failure, returns False
+    but also print detailed information explaining why KVM isn't enabled
+    (e.g. CPU doesn't support it, or BIOS disabled it).
+  """
+  try:
+    # Note: kvm-ok is in /usr/sbin, so always use 'sudo' to run it.
+    return not cmd_helper.RunCmd(['sudo', 'kvm-ok'])
+  except OSError:
+    logging.info('kvm-ok not installed')
+    return False
+
+
+def GetSDK():
+  """Download the SDK and unzip it into EMULATOR_SDK_ROOT."""
+  logging.info('Download Android SDK.')
+  sdk_url = '%s/%s' % (SDK_BASE_URL, SDK_ZIP)
+  try:
+    cmd_helper.RunCmd(['curl', '-o', '/tmp/sdk.zip', sdk_url])
+    print 'curled unzipping...'
+    rc = cmd_helper.RunCmd(['unzip', '-o', '/tmp/sdk.zip', '-d', '/tmp/'])
+    if rc:
+      raise Exception('ERROR: could not download/unzip Android SDK.')
+    # Get the name of the sub-directory that everything will be extracted to.
+    dirname, _ = os.path.splitext(SDK_ZIP)
+    zip_dir = '/tmp/%s' % dirname
+    # Move the extracted directory to EMULATOR_SDK_ROOT
+    shutil.move(zip_dir, constants.EMULATOR_SDK_ROOT)
+  finally:
+    os.unlink('/tmp/sdk.zip')
+
+
+def InstallKVM():
+  """Installs KVM packages."""
+  rc = cmd_helper.RunCmd(['sudo', 'apt-get', 'install', 'kvm'])
+  if rc:
+    logging.critical('ERROR: Did not install KVM. Make sure hardware '
+                     'virtualization is enabled in BIOS (i.e. Intel VT-x or '
+                     'AMD SVM).')
+  # TODO(navabi): Use modprobe kvm-amd on AMD processors.
+  rc = cmd_helper.RunCmd(['sudo', 'modprobe', 'kvm-intel'])
+  if rc:
+    logging.critical('ERROR: Did not add KVM module to Linux Kernel. Make sure '
+                     'hardware virtualization is enabled in BIOS.')
+  # Now check to ensure KVM acceleration can be used.
+  if not RunKvmOk():
+    logging.critical('ERROR: Can not use KVM acceleration. Make sure hardware '
+                     'virtualization is enabled in BIOS (i.e. Intel VT-x or '
+                     'AMD SVM).')
+
+
+def GetX86Image(api_level=DEFAULT_ANDROID_API_LEVEL):
+  """Download x86 system image from Intel's website.
+
+  Args:
+    api_level: the Android API level to download for.
+  """
+  logging.info('Download x86 system image directory into sdk directory.')
+  # TODO(andrewhayden): Use python tempfile lib instead
+  temp_file = '/tmp/x86_img_android-%d.zip' % api_level
+  if api_level not in X86_IMG_URLS:
+    raise Exception('ERROR: no URL known for x86 image for android-%s' %
+                    api_level)
+  try:
+    cmd_helper.RunCmd(['curl', '-o', temp_file, X86_IMG_URLS[api_level]])
+    rc = cmd_helper.RunCmd(['unzip', '-o', temp_file, '-d', '/tmp/'])
+    if rc:
+      raise Exception('ERROR: Could not download/unzip image zip.')
+    api_target = 'android-%d' % api_level
+    sys_imgs = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk',
+                            'system-images', api_target, 'x86')
+    logging.info('Deploying system image to %s' % sys_imgs)
+    shutil.move('/tmp/x86', sys_imgs)
+  finally:
+    os.unlink(temp_file)
+
+
+def GetSDKPlatform(api_level=DEFAULT_ANDROID_API_LEVEL):
+  """Update the SDK to include the platform specified.
+
+  Args:
+    api_level: the Android API level to download
+  """
+  android_binary = os.path.join(constants.EMULATOR_SDK_ROOT,
+                                'sdk', 'tools', 'android')
+  pattern = re.compile(
+      r'\s*([0-9]+)- SDK Platform Android [\.,0-9]+, API %d.*' % api_level)
+  # Example:
+  #   2- SDK Platform Android 4.3, API 18, revision 2
+  exit_code, stdout = cmd_helper.GetCmdStatusAndOutput(
+      [android_binary, 'list', 'sdk'])
+  if exit_code != 0:
+    raise Exception('\'android list sdk\' command return %d' % exit_code)
+  for line in stdout.split('\n'):
+    match = pattern.match(line)
+    if match:
+      index = match.group(1)
+      print 'package %s corresponds to platform level %d' % (index, api_level)
+      # update sdk --no-ui --filter $INDEX
+      update_command = [android_binary,
+                        'update', 'sdk', '--no-ui', '--filter', index]
+      update_command_str = ' '.join(update_command)
+      logging.info('running update command: %s' % update_command_str)
+      update_process = pexpect.spawn(update_command_str)
+      # TODO(andrewhayden): Do we need to bug the user about this?
+      if update_process.expect('Do you accept the license') != 0:
+        raise Exception('License agreement check failed')
+      update_process.sendline('y')
+      if update_process.expect('Done. 1 package installed.') == 0:
+        print 'Successfully installed platform for API level %d' % api_level
+        return
+      else:
+        raise Exception('Failed to install platform update')
+  raise Exception('Could not find android-%d update for the SDK!' % api_level)
+
+
+def main(argv):
+  opt_parser = optparse.OptionParser(
+      description='Install dependencies for running the Android emulator')
+  opt_parser.add_option('--api-level', dest='api_level',
+      help='The API level (e.g., 19 for Android 4.4) to ensure is available',
+      type='int', default=DEFAULT_ANDROID_API_LEVEL)
+  opt_parser.add_option('-v', dest='verbose', action='store_true',
+      help='enable verbose logging')
+  options, _ = opt_parser.parse_args(argv[1:])
+
+  # run_tests_helper will set logging to INFO or DEBUG
+  # We achieve verbose output by configuring it with 2 (==DEBUG)
+  verbosity = 1
+  if options.verbose:
+    verbosity = 2
+  logging.basicConfig(level=logging.INFO,
+                      format='# %(asctime)-15s: %(message)s')
+  run_tests_helper.SetLogLevel(verbose_count=verbosity)
+
+  # Calls below will download emulator SDK and/or system images only if needed.
+  if CheckSDK():
+    logging.info('android_emulator_sdk/ already exists, skipping download.')
+  else:
+    GetSDK()
+
+  # Check target. The target has to be installed in order to run the emulator.
+  if CheckSDKPlatform(options.api_level):
+    logging.info('SDK platform android-%d already present, skipping.' %
+                 options.api_level)
+  else:
+    logging.info('SDK platform android-%d not present, installing.' %
+                 options.api_level)
+    GetSDKPlatform(options.api_level)
+
+  # Download the x86 system image only if needed.
+  if CheckX86Image(options.api_level):
+    logging.info('x86 image for android-%d already present, skipping.' %
+                 options.api_level)
+  else:
+    GetX86Image(options.api_level)
+
+  # Make sure KVM packages are installed and enabled.
+  if CheckKVM():
+    logging.info('KVM already installed and enabled.')
+  else:
+    InstallKVM()
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/instr_action.gypi b/build/android/instr_action.gypi
new file mode 100644
index 0000000..fa6d062
--- /dev/null
+++ b/build/android/instr_action.gypi
@@ -0,0 +1,53 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule that
+# instruments either java class files, or jars.
+
+{
+  'variables': {
+    'instr_type%': 'jar',
+    'input_path%': '',
+    'output_path%': '',
+    'stamp_path%': '',
+    'extra_instr_args': [
+      '--coverage-file=<(_target_name).em',
+      '--sources-file=<(_target_name)_sources.txt',
+    ],
+    'emma_jar': '<(android_sdk_root)/tools/lib/emma.jar',
+    'conditions': [
+      ['emma_instrument != 0', {
+        'extra_instr_args': [
+          '--sources=<(java_in_dir)/src >(additional_src_dirs) >(generated_src_dirs)',
+          '--src-root=<(DEPTH)',
+          '--emma-jar=<(emma_jar)',
+          '--filter-string=<(emma_filter)',
+        ],
+        'conditions': [
+          ['instr_type == "jar"', {
+            'instr_action': 'instrument_jar',
+          }, {
+            'instr_action': 'instrument_classes',
+          }]
+        ],
+      }, {
+        'instr_action': 'copy',
+        'extra_instr_args': [],
+      }]
+    ]
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/emma_instr.py',
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/pylib/utils/command_option_parser.py',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/emma_instr.py',
+    '<(instr_action)',
+    '--input-path=<(input_path)',
+    '--output-path=<(output_path)',
+    '--stamp=<(stamp_path)',
+    '<@(extra_instr_args)',
+  ]
+}
diff --git a/build/android/java_cpp_enum.gypi b/build/android/java_cpp_enum.gypi
new file mode 100644
index 0000000..d4abafa
--- /dev/null
+++ b/build/android/java_cpp_enum.gypi
@@ -0,0 +1,64 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide an action
+# to generate Java source files from a C++ header file containing annotated
+# enum definitions using a Python script.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'target_name': 'bitmap_format_java',
+#    'type': 'none',
+#    'variables': {
+#      'source_file': 'ui/android/bitmap_format.h',
+#    },
+#    'includes': [ '../build/android/java_cpp_enum.gypi' ],
+#  },
+#
+# Then have the gyp target which compiles the java code depend on the newly
+# created target.
+
+{
+  'variables': {
+    # Location where all generated Java sources will be placed.
+    'output_dir': '<(SHARED_INTERMEDIATE_DIR)/enums/<(_target_name)',
+    'generator_path': '<(DEPTH)/build/android/gyp/java_cpp_enum.py',
+    'generator_args': '<(output_dir) <(source_file)',
+  },
+  'direct_dependent_settings': {
+    'variables': {
+      # Ensure that the output directory is used in the class path
+      # when building targets that depend on this one.
+      'generated_src_dirs': [
+        '<(output_dir)/',
+      ],
+      # Ensure that the targets depending on this one are rebuilt if the sources
+      # of this one are modified.
+      'additional_input_paths': [
+        '<(source_file)',
+      ],
+    },
+  },
+  'actions': [
+    {
+      'action_name': 'generate_java_constants',
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(generator_path)',
+        '<(source_file)',
+      ],
+      'outputs': [
+        # This is the main reason this is an action and not a rule. Gyp doesn't
+        # properly expand RULE_INPUT_PATH here and so it's impossible to
+        # calculate the list of outputs.
+        '<!@pymod_do_main(java_cpp_enum --print_output_only '
+            '<@(generator_args))',
+      ],
+      'action': [
+        'python', '<(generator_path)', '<@(generator_args)'
+      ],
+      'message': 'Generating Java from cpp header <(source_file)',
+    },
+  ],
+}
diff --git a/build/android/java_cpp_template.gypi b/build/android/java_cpp_template.gypi
new file mode 100644
index 0000000..3296659
--- /dev/null
+++ b/build/android/java_cpp_template.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to generate Java source files from templates that are processed
+# through the host C pre-processor.
+#
+# NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum
+#       rule instead.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'target_name': 'android_net_java_constants',
+#    'type': 'none',
+#    'sources': [
+#      'net/android/NetError.template',
+#    ],
+#    'variables': {
+#      'package_name': 'org/chromium/net',
+#      'template_deps': ['base/net_error_list.h'],
+#    },
+#    'includes': [ '../build/android/java_cpp_template.gypi' ],
+#  },
+#
+# The 'sources' entry should only list template file. The template file
+# itself should use the 'ClassName.template' format, and will generate
+# 'gen/templates/<target-name>/<package-name>/ClassName.java. The files which
+# template dependents on and typically included by the template should be listed
+# in template_deps variables. Any change to them will force a rebuild of
+# the template, and hence of any source that depends on it.
+#
+
+{
+  # Location where all generated Java sources will be placed.
+  'variables': {
+    'include_path%': '<(DEPTH)',
+    'output_dir': '<(SHARED_INTERMEDIATE_DIR)/templates/<(_target_name)/<(package_name)',
+  },
+  'direct_dependent_settings': {
+    'variables': {
+      # Ensure that the output directory is used in the class path
+      # when building targets that depend on this one.
+      'generated_src_dirs': [
+        '<(output_dir)/',
+      ],
+      # Ensure dependents are rebuilt when sources for this rule change.
+      'additional_input_paths': [
+        '<@(_sources)',
+        '<@(template_deps)',
+      ],
+    },
+  },
+  # Define a single rule that will be apply to each .template file
+  # listed in 'sources'.
+  'rules': [
+    {
+      'rule_name': 'generate_java_constants',
+      'extension': 'template',
+      # Set template_deps as additional dependencies.
+      'variables': {
+        'output_path': '<(output_dir)/<(RULE_INPUT_ROOT).java',
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/gcc_preprocess.py',
+        '<@(template_deps)'
+      ],
+      'outputs': [
+        '<(output_path)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/gcc_preprocess.py',
+        '--include-path=<(include_path)',
+        '--output=<(output_path)',
+        '--template=<(RULE_INPUT_PATH)',
+      ],
+      'message': 'Generating Java from cpp template <(RULE_INPUT_PATH)',
+    }
+  ],
+}
diff --git a/build/android/jinja_template.gypi b/build/android/jinja_template.gypi
new file mode 100644
index 0000000..9c49360
--- /dev/null
+++ b/build/android/jinja_template.gypi
@@ -0,0 +1,85 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to process one or more
+# Jinja templates.
+#
+# To process a single template file, create a gyp target with the following
+# form:
+#  {
+#    'target_name': 'chrome_shell_manifest',
+#    'type': 'none',
+#    'variables': {
+#      'jinja_inputs': ['android/shell/java/AndroidManifest.xml'],
+#      'jinja_output': '<(SHARED_INTERMEDIATE_DIR)/chrome_shell_manifest/AndroidManifest.xml',
+#      'jinja_variables': ['app_name=ChromeShell'],
+#    },
+#    'includes': [ '../build/android/jinja_template.gypi' ],
+#  },
+#
+# To process multiple template files and package the results into a zip file,
+# create a gyp target with the following form:
+#  {
+#    'target_name': 'chrome_template_resources',
+#    'type': 'none',
+#    'variables': {
+#       'jinja_inputs_base_dir': 'android/shell/java/res_template',
+#       'jinja_inputs': [
+#         '<(jinja_inputs_base_dir)/xml/searchable.xml',
+#         '<(jinja_inputs_base_dir)/xml/syncadapter.xml',
+#       ],
+#       'jinja_outputs_zip': '<(PRODUCT_DIR)/res.java/<(_target_name).zip',
+#       'jinja_variables': ['app_name=ChromeShell'],
+#     },
+#     'includes': [ '../build/android/jinja_template.gypi' ],
+#   },
+#
+
+{
+  'actions': [
+    {
+      'action_name': '<(_target_name)_jinja_template',
+      'message': 'processing jinja template',
+      'variables': {
+        'jinja_output%': '',
+        'jinja_outputs_zip%': '',
+        'jinja_inputs_base_dir%': '',
+        'jinja_includes%': [],
+        'jinja_variables%': [],
+        'jinja_args': [],
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/jinja_template.py',
+        '<@(jinja_inputs)',
+        '<@(jinja_includes)',
+      ],
+      'conditions': [
+        ['jinja_output != ""', {
+          'outputs': [ '<(jinja_output)' ],
+          'variables': {
+            'jinja_args': ['--output', '<(jinja_output)'],
+          },
+        }],
+        ['jinja_outputs_zip != ""', {
+          'outputs': [ '<(jinja_outputs_zip)' ],
+          'variables': {
+            'jinja_args': ['--outputs-zip', '<(jinja_outputs_zip)'],
+          },
+        }],
+        ['jinja_inputs_base_dir != ""', {
+          'variables': {
+            'jinja_args': ['--inputs-base-dir', '<(jinja_inputs_base_dir)'],
+          },
+        }],
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/jinja_template.py',
+        '--inputs', '<(jinja_inputs)',
+        '--variables', '<(jinja_variables)',
+        '<@(jinja_args)',
+      ],
+    },
+  ],
+}
diff --git a/build/android/lighttpd_server.py b/build/android/lighttpd_server.py
new file mode 100755
index 0000000..a5195ac
--- /dev/null
+++ b/build/android/lighttpd_server.py
@@ -0,0 +1,256 @@
+#!/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.
+
+"""Provides a convenient wrapper for spawning a test lighttpd instance.
+
+Usage:
+  lighttpd_server PATH_TO_DOC_ROOT
+"""
+
+import codecs
+import contextlib
+import httplib
+import os
+import random
+import shutil
+import socket
+import subprocess
+import sys
+import tempfile
+import time
+
+from pylib import constants
+from pylib import pexpect
+
+class LighttpdServer(object):
+  """Wraps lighttpd server, providing robust startup.
+
+  Args:
+    document_root: Path to root of this server's hosted files.
+    port: TCP port on the _host_ machine that the server will listen on. If
+        ommitted it will attempt to use 9000, or if unavailable it will find
+        a free port from 8001 - 8999.
+    lighttpd_path, lighttpd_module_path: Optional paths to lighttpd binaries.
+    base_config_path: If supplied this file will replace the built-in default
+        lighttpd config file.
+    extra_config_contents: If specified, this string will be appended to the
+        base config (default built-in, or from base_config_path).
+    config_path, error_log, access_log: Optional paths where the class should
+        place temprary files for this session.
+  """
+
+  def __init__(self, document_root, port=None,
+               lighttpd_path=None, lighttpd_module_path=None,
+               base_config_path=None, extra_config_contents=None,
+               config_path=None, error_log=None, access_log=None):
+    self.temp_dir = tempfile.mkdtemp(prefix='lighttpd_for_chrome_android')
+    self.document_root = os.path.abspath(document_root)
+    self.fixed_port = port
+    self.port = port or constants.LIGHTTPD_DEFAULT_PORT
+    self.server_tag = 'LightTPD ' + str(random.randint(111111, 999999))
+    self.lighttpd_path = lighttpd_path or '/usr/sbin/lighttpd'
+    self.lighttpd_module_path = lighttpd_module_path or '/usr/lib/lighttpd'
+    self.base_config_path = base_config_path
+    self.extra_config_contents = extra_config_contents
+    self.config_path = config_path or self._Mktmp('config')
+    self.error_log = error_log or self._Mktmp('error_log')
+    self.access_log = access_log or self._Mktmp('access_log')
+    self.pid_file = self._Mktmp('pid_file')
+    self.process = None
+
+  def _Mktmp(self, name):
+    return os.path.join(self.temp_dir, name)
+
+  @staticmethod
+  def _GetRandomPort():
+    # The ports of test server is arranged in constants.py.
+    return random.randint(constants.LIGHTTPD_RANDOM_PORT_FIRST,
+                          constants.LIGHTTPD_RANDOM_PORT_LAST)
+
+  def StartupHttpServer(self):
+    """Starts up a http server with specified document root and port."""
+    # If we want a specific port, make sure no one else is listening on it.
+    if self.fixed_port:
+      self._KillProcessListeningOnPort(self.fixed_port)
+    while True:
+      if self.base_config_path:
+        # Read the config
+        with codecs.open(self.base_config_path, 'r', 'utf-8') as f:
+          config_contents = f.read()
+      else:
+        config_contents = self._GetDefaultBaseConfig()
+      if self.extra_config_contents:
+        config_contents += self.extra_config_contents
+      # Write out the config, filling in placeholders from the members of |self|
+      with codecs.open(self.config_path, 'w', 'utf-8') as f:
+        f.write(config_contents % self.__dict__)
+      if (not os.path.exists(self.lighttpd_path) or
+          not os.access(self.lighttpd_path, os.X_OK)):
+        raise EnvironmentError(
+            'Could not find lighttpd at %s.\n'
+            'It may need to be installed (e.g. sudo apt-get install lighttpd)'
+            % self.lighttpd_path)
+      self.process = pexpect.spawn(self.lighttpd_path,
+                                   ['-D', '-f', self.config_path,
+                                    '-m', self.lighttpd_module_path],
+                                   cwd=self.temp_dir)
+      client_error, server_error = self._TestServerConnection()
+      if not client_error:
+        assert int(open(self.pid_file, 'r').read()) == self.process.pid
+        break
+      self.process.close()
+
+      if self.fixed_port or not 'in use' in server_error:
+        print 'Client error:', client_error
+        print 'Server error:', server_error
+        return False
+      self.port = self._GetRandomPort()
+    return True
+
+  def ShutdownHttpServer(self):
+    """Shuts down our lighttpd processes."""
+    if self.process:
+      self.process.terminate()
+    shutil.rmtree(self.temp_dir, ignore_errors=True)
+
+  def _TestServerConnection(self):
+    # Wait for server to start
+    server_msg = ''
+    for timeout in xrange(1, 5):
+      client_error = None
+      try:
+        with contextlib.closing(httplib.HTTPConnection(
+            '127.0.0.1', self.port, timeout=timeout)) as http:
+          http.set_debuglevel(timeout > 3)
+          http.request('HEAD', '/')
+          r = http.getresponse()
+          r.read()
+          if (r.status == 200 and r.reason == 'OK' and
+              r.getheader('Server') == self.server_tag):
+            return (None, server_msg)
+          client_error = ('Bad response: %s %s version %s\n  ' %
+                          (r.status, r.reason, r.version) +
+                          '\n  '.join([': '.join(h) for h in r.getheaders()]))
+      except (httplib.HTTPException, socket.error) as client_error:
+        pass  # Probably too quick connecting: try again
+      # Check for server startup error messages
+      ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'],
+                               timeout=timeout)
+      if ix == 2:  # stdout spew from the server
+        server_msg += self.process.match.group(0)
+      elif ix == 1:  # EOF -- server has quit so giveup.
+        client_error = client_error or 'Server exited'
+        break
+    return (client_error or 'Timeout', server_msg)
+
+  @staticmethod
+  def _KillProcessListeningOnPort(port):
+    """Checks if there is a process listening on port number |port| and
+    terminates it if found.
+
+    Args:
+      port: Port number to check.
+    """
+    if subprocess.call(['fuser', '-kv', '%d/tcp' % port]) == 0:
+      # Give the process some time to terminate and check that it is gone.
+      time.sleep(2)
+      assert subprocess.call(['fuser', '-v', '%d/tcp' % port]) != 0, \
+          'Unable to kill process listening on port %d.' % port
+
+  @staticmethod
+  def _GetDefaultBaseConfig():
+    return """server.tag                  = "%(server_tag)s"
+server.modules              = ( "mod_access",
+                                "mod_accesslog",
+                                "mod_alias",
+                                "mod_cgi",
+                                "mod_rewrite" )
+
+# default document root required
+#server.document-root = "."
+
+# files to check for if .../ is requested
+index-file.names            = ( "index.php", "index.pl", "index.cgi",
+                                "index.html", "index.htm", "default.htm" )
+# mimetype mapping
+mimetype.assign             = (
+  ".gif"          =>      "image/gif",
+  ".jpg"          =>      "image/jpeg",
+  ".jpeg"         =>      "image/jpeg",
+  ".png"          =>      "image/png",
+  ".svg"          =>      "image/svg+xml",
+  ".css"          =>      "text/css",
+  ".html"         =>      "text/html",
+  ".htm"          =>      "text/html",
+  ".xhtml"        =>      "application/xhtml+xml",
+  ".xhtmlmp"      =>      "application/vnd.wap.xhtml+xml",
+  ".js"           =>      "application/x-javascript",
+  ".log"          =>      "text/plain",
+  ".conf"         =>      "text/plain",
+  ".text"         =>      "text/plain",
+  ".txt"          =>      "text/plain",
+  ".dtd"          =>      "text/xml",
+  ".xml"          =>      "text/xml",
+  ".manifest"     =>      "text/cache-manifest",
+ )
+
+# Use the "Content-Type" extended attribute to obtain mime type if possible
+mimetype.use-xattr          = "enable"
+
+##
+# which extensions should not be handle via static-file transfer
+#
+# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
+static-file.exclude-extensions = ( ".php", ".pl", ".cgi" )
+
+server.bind = "127.0.0.1"
+server.port = %(port)s
+
+## virtual directory listings
+dir-listing.activate        = "enable"
+#dir-listing.encoding       = "iso-8859-2"
+#dir-listing.external-css   = "style/oldstyle.css"
+
+## enable debugging
+#debug.log-request-header   = "enable"
+#debug.log-response-header  = "enable"
+#debug.log-request-handling = "enable"
+#debug.log-file-not-found   = "enable"
+
+#### SSL engine
+#ssl.engine                 = "enable"
+#ssl.pemfile                = "server.pem"
+
+# Autogenerated test-specific config follows.
+
+cgi.assign = ( ".cgi"  => "/usr/bin/env",
+               ".pl"   => "/usr/bin/env",
+               ".asis" => "/bin/cat",
+               ".php"  => "/usr/bin/php-cgi" )
+
+server.errorlog = "%(error_log)s"
+accesslog.filename = "%(access_log)s"
+server.upload-dirs = ( "/tmp" )
+server.pid-file = "%(pid_file)s"
+server.document-root = "%(document_root)s"
+
+"""
+
+
+def main(argv):
+  server = LighttpdServer(*argv[1:])
+  try:
+    if server.StartupHttpServer():
+      raw_input('Server running at http://127.0.0.1:%s -'
+                ' press Enter to exit it.' % server.port)
+    else:
+      print 'Server exit code:', server.process.exitstatus
+  finally:
+    server.ShutdownHttpServer()
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/lint/OWNERS b/build/android/lint/OWNERS
new file mode 100644
index 0000000..cd396e7
--- /dev/null
+++ b/build/android/lint/OWNERS
@@ -0,0 +1,2 @@
+newt@chromium.org
+aurimas@chromium.org
diff --git a/build/android/lint/suppress.py b/build/android/lint/suppress.py
new file mode 100755
index 0000000..52d7579
--- /dev/null
+++ b/build/android/lint/suppress.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Add all generated lint_result.xml files to suppressions.xml"""
+
+
+import collections
+import optparse
+import os
+import sys
+from xml.dom import minidom
+
+_BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
+sys.path.append(_BUILD_ANDROID_DIR)
+
+from pylib import constants
+
+
+_THIS_FILE = os.path.abspath(__file__)
+_CONFIG_PATH = os.path.join(os.path.dirname(_THIS_FILE), 'suppressions.xml')
+_DOC = (
+    '\nSTOP! It looks like you want to suppress some lint errors:\n'
+    '- Have you tried identifing the offending patch?\n'
+    '  Ask the author for a fix and/or revert the patch.\n'
+    '- It is preferred to add suppressions in the code instead of\n'
+    '  sweeping it under the rug here. See:\n\n'
+    '    http://developer.android.com/tools/debugging/improving-w-lint.html\n'
+    '\n'
+    'Still reading?\n'
+    '- You can edit this file manually to suppress an issue\n'
+    '  globally if it is not applicable to the project.\n'
+    '- You can also automatically add issues found so for in the\n'
+    '  build process by running:\n\n'
+    '    ' + os.path.relpath(_THIS_FILE, constants.DIR_SOURCE_ROOT) + '\n\n'
+    '  which will generate this file (Comments are not preserved).\n'
+    '  Note: PRODUCT_DIR will be substituted at run-time with actual\n'
+    '  directory path (e.g. out/Debug)\n'
+)
+
+
+_Issue = collections.namedtuple('Issue', ['severity', 'paths'])
+
+
+def _ParseConfigFile(config_path):
+  print 'Parsing %s' % config_path
+  issues_dict = {}
+  dom = minidom.parse(config_path)
+  for issue in dom.getElementsByTagName('issue'):
+    issue_id = issue.attributes['id'].value
+    severity = issue.getAttribute('severity')
+    paths = set(
+        [p.attributes['path'].value for p in
+         issue.getElementsByTagName('ignore')])
+    issues_dict[issue_id] = _Issue(severity, paths)
+  return issues_dict
+
+
+def _ParseAndMergeResultFile(result_path, issues_dict):
+  print 'Parsing and merging %s' % result_path
+  dom = minidom.parse(result_path)
+  for issue in dom.getElementsByTagName('issue'):
+    issue_id = issue.attributes['id'].value
+    severity = issue.attributes['severity'].value
+    path = issue.getElementsByTagName('location')[0].attributes['file'].value
+    if issue_id not in issues_dict:
+      issues_dict[issue_id] = _Issue(severity, set())
+    issues_dict[issue_id].paths.add(path)
+
+
+def _WriteConfigFile(config_path, issues_dict):
+  new_dom = minidom.getDOMImplementation().createDocument(None, 'lint', None)
+  top_element = new_dom.documentElement
+  top_element.appendChild(new_dom.createComment(_DOC))
+  for issue_id in sorted(issues_dict.keys()):
+    severity = issues_dict[issue_id].severity
+    paths = issues_dict[issue_id].paths
+    issue = new_dom.createElement('issue')
+    issue.attributes['id'] = issue_id
+    if severity:
+      issue.attributes['severity'] = severity
+    if severity == 'ignore':
+      print 'Warning: [%s] is suppressed globally.' % issue_id
+    else:
+      for path in sorted(paths):
+        ignore = new_dom.createElement('ignore')
+        ignore.attributes['path'] = path
+        issue.appendChild(ignore)
+    top_element.appendChild(issue)
+
+  with open(config_path, 'w') as f:
+    f.write(new_dom.toprettyxml(indent='  ', encoding='utf-8'))
+  print 'Updated %s' % config_path
+
+
+def _Suppress(config_path, result_path):
+  issues_dict = _ParseConfigFile(config_path)
+  _ParseAndMergeResultFile(result_path, issues_dict)
+  _WriteConfigFile(config_path, issues_dict)
+
+
+def main():
+  parser = optparse.OptionParser(usage='%prog RESULT-FILE')
+  _, args = parser.parse_args()
+
+  if len(args) != 1 or not os.path.exists(args[0]):
+    parser.error('Must provide RESULT-FILE')
+
+  _Suppress(_CONFIG_PATH, args[0])
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
new file mode 100644
index 0000000..b16de84
--- /dev/null
+++ b/build/android/lint/suppressions.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<lint>
+  <!--
+STOP! It looks like you want to suppress some lint errors:
+- Have you tried identifing the offending patch?
+  Ask the author for a fix and/or revert the patch.
+- It is preferred to add suppressions in the code instead of
+  sweeping it under the rug here. See:
+
+    http://developer.android.com/tools/debugging/improving-w-lint.html
+
+Still reading?
+- You can edit this file manually to suppress an issue
+  globally if it is not applicable to the project.
+- You can also automatically add issues found so for in the
+  build process by running:
+
+    build/android/lint/suppress.py
+
+  which will generate this file (Comments are not preserved).
+  Note: PRODUCT_DIR will be substituted at run-time with actual
+  directory path (e.g. out/Debug)
+-->
+  <issue id="AllowBackup">
+    <ignore path="AndroidManifest.xml"/>
+  </issue>
+  <issue id="Assert" severity="ignore"/>
+  <issue id="CommitPrefEdits">
+    <ignore path="third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelPreferences.java"/>
+  </issue>
+  <issue id="DefaultLocale">
+    <ignore path="third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerState.java"/>
+  </issue>
+  <issue id="DrawAllocation">
+    <ignore path="content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java"/>
+    <ignore path="content/public/android/java/src/org/chromium/content/browser/PopupZoomer.java"/>
+  </issue>
+  <issue id="ExportedContentProvider">
+    <ignore path="AndroidManifest.xml"/>
+  </issue>
+  <issue id="HandlerLeak">
+    <ignore path="remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java"/>
+  </issue>
+  <issue id="IconDensities">
+    <!-- crbug.com/457918 is tracking missing assets -->
+    <ignore path="components/web_contents_delegate_android/android/java/res/drawable-xxhdpi"/>
+    <ignore path="components/web_contents_delegate_android/android/java/res/drawable-xxxhdpi"/>
+    <ignore path="content/public/android/java/res/drawable-xxhdpi"/>
+    <ignore path="content/public/android/java/res/drawable-xxxhdpi"/>
+    <ignore path="chrome/android/java/res/drawable-xxhdpi"/>
+    <ignore path="chrome/android/java/res/drawable-xxxhdpi"/>
+    <ignore path="ui/android/java/res/drawable-xxhdpi"/>
+    <ignore path="ui/android/java/res/drawable-xxxhdpi"/>
+  </issue>
+  <!-- It is OK for content_shell_apk and chrome_shell_apk to have missing assets. -->
+  <issue id="IconLocation">
+    <ignore path="content/shell/android/java/res/"/>
+    <ignore path="chrome/android/shell/res/"/>
+  </issue>
+  <issue id="InconsistentLayout" severity="ignore"/>
+  <issue id="InflateParams" severity="ignore"/>
+  <issue id="MissingApplicationIcon" severity="ignore"/>
+  <issue id="MissingRegistered" severity="ignore"/>
+  <issue id="MissingVersion">
+    <ignore path="AndroidManifest.xml"/>
+  </issue>
+  <issue id="InlinedApi" severity="ignore"/>
+  <issue id="NewApi">
+    <ignore regexp="Attribute `paddingStart` referenced here can result in a crash on some specific devices older than API 17"/>
+    <ignore path="org/chromium/base/AnimationFrameTimeHistogram$Recorder.class"/>
+    <ignore path="org/chromium/base/JavaHandlerThread.class"/>
+    <ignore path="org/chromium/base/SysUtils.class"/>
+    <ignore path="org/chromium/chrome/browser/TtsPlatformImpl.class"/>
+    <ignore path="org/chromium/chrome/browser/TtsPlatformImpl$*.class"/>
+  </issue>
+  <issue id="OldTargetApi">
+    <ignore path="AndroidManifest.xml"/>
+  </issue>
+  <issue id="Overdraw" severity="ignore"/>
+  <issue id="Recycle" severity="ignore"/>
+  <issue id="Registered" severity="ignore"/>
+  <issue id="RtlCompat" severity="ignore"/>
+  <issue id="RtlEnabled" severity="ignore"/>
+  <issue id="RtlSymmetry" severity="ignore"/>
+  <issue id="SdCardPath">
+    <ignore path="content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java"/>
+  </issue>
+  <issue id="SetJavaScriptEnabled" severity="ignore"/>
+  <issue id="UnusedResources">
+    <!-- These files are used by chrome_shell_apk and chrome_apk targets. -->
+    <ignore path="chrome/android/java/res/layout/accessibility_tab_switcher.xml" />
+    <ignore path="chrome/android/java/res/drawable/btn_back.xml" />
+    <ignore path="chrome/android/java/res/drawable/btn_forward.xml" />
+  </issue>
+  <issue id="SignatureOrSystemPermissions" severity="ignore"/>
+  <issue id="UnusedAttribute" severity="ignore"/>
+  <issue id="ViewConstructor" severity="ignore"/>
+  <issue id="WrongCall" severity="ignore"/>
+</lint>
diff --git a/build/android/lint_action.gypi b/build/android/lint_action.gypi
new file mode 100644
index 0000000..e042130
--- /dev/null
+++ b/build/android/lint_action.gypi
@@ -0,0 +1,42 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule to
+# run lint on java/class files.
+
+{
+  'action_name': 'lint_<(_target_name)',
+  'message': 'Linting <(_target_name)',
+  'variables': {
+    'conditions': [
+      ['chromium_code != 0 and android_lint != 0 and never_lint == 0', {
+        'is_enabled': '--enable',
+      }, {
+        'is_enabled': '',
+      }]
+    ],
+    'android_manifest_path%': '<(DEPTH)/build/android/AndroidManifest.xml',
+    'resource_dir%': '<(DEPTH)/build/android/ant/empty/res',
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/lint.py',
+    '<(DEPTH)/build/android/lint/suppressions.xml',
+    '<(lint_jar_path)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/lint.py',
+    '--lint-path=<(android_sdk_root)/tools/lint',
+    '--config-path=<(DEPTH)/build/android/lint/suppressions.xml',
+    '--processed-config-path=<(config_path)',
+    '--manifest-path=<(android_manifest_path)',
+    '--result-path=<(result_path)',
+    '--resource-dir=<(resource_dir)',
+    '--product-dir=<(PRODUCT_DIR)',
+    '--src-dirs=>(src_dirs)',
+    '--jar-path=<(lint_jar_path)',
+    '--stamp=<(stamp_path)',
+    '<(is_enabled)',
+  ],
+}
diff --git a/build/android/native_app_dependencies.gypi b/build/android/native_app_dependencies.gypi
new file mode 100644
index 0000000..6032274
--- /dev/null
+++ b/build/android/native_app_dependencies.gypi
@@ -0,0 +1,67 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to strip and place dependent shared libraries required by a native binary in a
+# single folder that can later be pushed to the device.
+#
+# NOTE: consider packaging your binary as an apk instead of running a native
+# library.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'target_name': 'target_that_depends_on_my_binary',
+#    'type': 'none',
+#    'dependencies': [
+#      'my_binary',
+#    ],
+#    'variables': {
+#      'native_binary': '<(PRODUCT_DIR)/my_binary',
+#      'output_dir': 'location to place binary and dependent libraries'
+#    },
+#    'includes': [ '../../build/android/native_app_dependencies.gypi' ],
+#  },
+#
+
+{
+  'variables': {
+    'include_main_binary%': 1,
+  },
+  'conditions': [
+      ['component == "shared_library"', {
+        'dependencies': [
+          '<(DEPTH)/build/android/setup.gyp:copy_system_libraries',
+        ],
+        'variables': {
+          'intermediate_dir': '<(PRODUCT_DIR)/<(_target_name)',
+          'ordered_libraries_file': '<(intermediate_dir)/native_libraries.json',
+        },
+        'actions': [
+          {
+            'variables': {
+              'input_libraries': ['<(native_binary)'],
+            },
+            'includes': ['../../build/android/write_ordered_libraries.gypi'],
+          },
+          {
+            'action_name': 'stripping native libraries',
+            'variables': {
+              'stripped_libraries_dir%': '<(output_dir)',
+              'input_paths': ['<(native_binary)'],
+              'stamp': '<(intermediate_dir)/strip.stamp',
+            },
+            'includes': ['../../build/android/strip_native_libraries.gypi'],
+          },
+        ],
+      }],
+      ['include_main_binary==1', {
+        'copies': [
+          {
+            'destination': '<(output_dir)',
+            'files': [ '<(native_binary)' ],
+          }
+        ],
+      }],
+  ],
+}
diff --git a/build/android/ndk.gyp b/build/android/ndk.gyp
new file mode 100644
index 0000000..2838a98
--- /dev/null
+++ b/build/android/ndk.gyp
@@ -0,0 +1,20 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'cpu_features',
+      'type': 'static_library',
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(android_ndk_root)/sources/android/cpufeatures',
+        ],
+      },
+      'sources': [
+        '<(android_ndk_root)/sources/android/cpufeatures/cpu-features.c',
+      ],
+    },
+  ],
+}
diff --git a/build/android/pack_arm_relocations.gypi b/build/android/pack_arm_relocations.gypi
new file mode 100644
index 0000000..5df1d7e
--- /dev/null
+++ b/build/android/pack_arm_relocations.gypi
@@ -0,0 +1,86 @@
+# Copyright 2014 The Chromium 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 to be included into an action to provide a rule that
+# packs ARM relative relocations in Release builds of native libraries.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'action_name': 'pack_arm_relocations',
+#    'actions': [
+#      'variables': {
+#        'enable_packing': 'pack relocations if 1, plain file copy if 0'
+#        'exclude_packing_list': 'names of libraries explicitly not packed',
+#        'ordered_libraries_file': 'file generated by write_ordered_libraries'
+#        'input_paths': 'files to be added to the list of inputs'
+#        'stamp': 'file to touch when the action is complete'
+#        'stripped_libraries_dir': 'directory holding stripped libraries',
+#        'packed_libraries_dir': 'directory holding packed libraries',
+#      'includes': [ '../../build/android/pack_arm_relocations.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'variables': {
+    'input_paths': [],
+    'conditions': [
+      ['target_arch == "arm64"', {
+        'has_relocations_with_addends': 1,
+      }, {
+        'has_relocations_with_addends': 0,
+      }],
+    ],
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/pack_arm_relocations.py',
+    '<(ordered_libraries_file)',
+    '>@(input_paths)',
+  ],
+  'outputs': [
+    '<(stamp)',
+  ],
+  'conditions': [
+    ['enable_packing == 1', {
+      'message': 'Packing ARM relative relocations for <(_target_name)',
+      'dependencies': [
+        '<(DEPTH)/tools/relocation_packer/relocation_packer.gyp:relocation_packer#host',
+      ],
+      'inputs': [
+        '<(PRODUCT_DIR)/relocation_packer',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/pack_arm_relocations.py',
+        '--configuration-name=<(CONFIGURATION_NAME)',
+        '--enable-packing=1',
+        '--has-relocations-with-addends=<(has_relocations_with_addends)',
+        '--exclude-packing-list=<@(exclude_packing_list)',
+        '--android-pack-relocations=<(PRODUCT_DIR)/relocation_packer',
+        '--android-objcopy=<(android_objcopy)',
+        '--stripped-libraries-dir=<(stripped_libraries_dir)',
+        '--packed-libraries-dir=<(packed_libraries_dir)',
+        '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
+        '--stamp=<(stamp)',
+      ],
+    }, {
+      'message': 'Copying libraries (no relocation packing) for <(_target_name)',
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/pack_arm_relocations.py',
+        '--configuration-name=<(CONFIGURATION_NAME)',
+        '--enable-packing=0',
+        '--stripped-libraries-dir=<(stripped_libraries_dir)',
+        '--packed-libraries-dir=<(packed_libraries_dir)',
+        '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
+        '--stamp=<(stamp)',
+      ],
+    }],
+    ['component == "shared_library"', {
+      # Add a fake output to force the build to always re-run this step. This
+      # is required because the real inputs are not known at gyp-time and
+      # changing base.so may not trigger changes to dependent libraries.
+      'outputs': [ '<(stamp).fake' ]
+    }],
+  ],
+}
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py
new file mode 100755
index 0000000..dbb3297
--- /dev/null
+++ b/build/android/provision_devices.py
@@ -0,0 +1,328 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Provisions Android devices with settings required for bots.
+
+Usage:
+  ./provision_devices.py [-d <device serial number>]
+"""
+
+import argparse
+import logging
+import os
+import posixpath
+import re
+import subprocess
+import sys
+import time
+
+from pylib import constants
+from pylib import device_settings
+from pylib.device import battery_utils
+from pylib.device import device_blacklist
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.utils import run_tests_helper
+from pylib.utils import timeout_retry
+
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT,
+                             'third_party', 'android_testrunner'))
+import errors
+
+
+class _DEFAULT_TIMEOUTS(object):
+  # L can take a while to reboot after a wipe.
+  LOLLIPOP = 600
+  PRE_LOLLIPOP = 180
+
+  HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP)
+
+
+class _PHASES(object):
+  WIPE = 'wipe'
+  PROPERTIES = 'properties'
+  FINISH = 'finish'
+
+  ALL = [WIPE, PROPERTIES, FINISH]
+
+
+def ProvisionDevices(options):
+  if options.device is not None:
+    devices = [options.device]
+  else:
+    devices = device_utils.DeviceUtils.HealthyDevices()
+
+  parallel_devices = device_utils.DeviceUtils.parallel(devices)
+  parallel_devices.pMap(ProvisionDevice, options)
+  if options.auto_reconnect:
+    _LaunchHostHeartbeat()
+  blacklist = device_blacklist.ReadBlacklist()
+  if all(d in blacklist for d in devices):
+    raise device_errors.NoDevicesError
+  return 0
+
+
+def ProvisionDevice(device, options):
+  if options.reboot_timeout:
+    reboot_timeout = options.reboot_timeout
+  elif (device.build_version_sdk >=
+        constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
+    reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP
+  else:
+    reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP
+
+  def should_run_phase(phase_name):
+    return not options.phases or phase_name in options.phases
+
+  def run_phase(phase_func, reboot=True):
+    device.WaitUntilFullyBooted(timeout=reboot_timeout)
+    phase_func(device, options)
+    if reboot:
+      device.Reboot(False, retries=0)
+      device.adb.WaitForDevice()
+
+  try:
+    if should_run_phase(_PHASES.WIPE):
+      run_phase(WipeDevice)
+
+    if should_run_phase(_PHASES.PROPERTIES):
+      run_phase(SetProperties)
+
+    if should_run_phase(_PHASES.FINISH):
+      run_phase(FinishProvisioning, reboot=False)
+
+  except (errors.WaitForResponseTimedOutError,
+          device_errors.CommandTimeoutError):
+    logging.exception('Timed out waiting for device %s. Adding to blacklist.',
+                      str(device))
+    device_blacklist.ExtendBlacklist([str(device)])
+
+  except device_errors.CommandFailedError:
+    logging.exception('Failed to provision device %s. Adding to blacklist.',
+                      str(device))
+    device_blacklist.ExtendBlacklist([str(device)])
+
+
+def WipeDevice(device, options):
+  """Wipes data from device, keeping only the adb_keys for authorization.
+
+  After wiping data on a device that has been authorized, adb can still
+  communicate with the device, but after reboot the device will need to be
+  re-authorized because the adb keys file is stored in /data/misc/adb/.
+  Thus, adb_keys file is rewritten so the device does not need to be
+  re-authorized.
+
+  Arguments:
+    device: the device to wipe
+  """
+  if options.skip_wipe:
+    return
+
+  try:
+    device.EnableRoot()
+    device_authorized = device.FileExists(constants.ADB_KEYS_FILE)
+    if device_authorized:
+      adb_keys = device.ReadFile(constants.ADB_KEYS_FILE,
+                                 as_root=True).splitlines()
+    device.RunShellCommand(['wipe', 'data'],
+                           as_root=True, check_return=True)
+    device.adb.WaitForDevice()
+
+    if device_authorized:
+      adb_keys_set = set(adb_keys)
+      for adb_key_file in options.adb_key_files or []:
+        try:
+          with open(adb_key_file, 'r') as f:
+            adb_public_keys = f.readlines()
+          adb_keys_set.update(adb_public_keys)
+        except IOError:
+          logging.warning('Unable to find adb keys file %s.' % adb_key_file)
+      _WriteAdbKeysFile(device, '\n'.join(adb_keys_set))
+  except device_errors.CommandFailedError:
+    logging.exception('Possible failure while wiping the device. '
+                      'Attempting to continue.')
+
+
+def _WriteAdbKeysFile(device, adb_keys_string):
+  dir_path = posixpath.dirname(constants.ADB_KEYS_FILE)
+  device.RunShellCommand(['mkdir', '-p', dir_path],
+                         as_root=True, check_return=True)
+  device.RunShellCommand(['restorecon', dir_path],
+                         as_root=True, check_return=True)
+  device.WriteFile(constants.ADB_KEYS_FILE, adb_keys_string, as_root=True)
+  device.RunShellCommand(['restorecon', constants.ADB_KEYS_FILE],
+                         as_root=True, check_return=True)
+
+
+def SetProperties(device, options):
+  try:
+    device.EnableRoot()
+  except device_errors.CommandFailedError as e:
+    logging.warning(str(e))
+
+  _ConfigureLocalProperties(device, options.enable_java_debug)
+  device_settings.ConfigureContentSettings(
+      device, device_settings.DETERMINISTIC_DEVICE_SETTINGS)
+  if options.disable_location:
+    device_settings.ConfigureContentSettings(
+        device, device_settings.DISABLE_LOCATION_SETTINGS)
+  else:
+    device_settings.ConfigureContentSettings(
+        device, device_settings.ENABLE_LOCATION_SETTINGS)
+  device_settings.SetLockScreenSettings(device)
+  if options.disable_network:
+    device_settings.ConfigureContentSettings(
+        device, device_settings.NETWORK_DISABLED_SETTINGS)
+
+  if options.min_battery_level is not None:
+    try:
+      battery = battery_utils.BatteryUtils(device)
+      battery.ChargeDeviceToLevel(options.min_battery_level)
+    except device_errors.CommandFailedError as e:
+      logging.exception('Unable to charge device to specified level.')
+
+  if options.max_battery_temp is not None:
+    try:
+      battery = battery_utils.BatteryUtils(device)
+      battery.LetBatteryCoolToTemperature(options.max_battery_temp)
+    except device_errors.CommandFailedError as e:
+      logging.exception('Unable to let battery cool to specified temperature.')
+
+def _ConfigureLocalProperties(device, java_debug=True):
+  """Set standard readonly testing device properties prior to reboot."""
+  local_props = [
+      'persist.sys.usb.config=adb',
+      'ro.monkey=1',
+      'ro.test_harness=1',
+      'ro.audio.silent=1',
+      'ro.setupwizard.mode=DISABLED',
+      ]
+  if java_debug:
+    local_props.append(
+        '%s=all' % device_utils.DeviceUtils.JAVA_ASSERT_PROPERTY)
+    local_props.append('debug.checkjni=1')
+  try:
+    device.WriteFile(
+        constants.DEVICE_LOCAL_PROPERTIES_PATH,
+        '\n'.join(local_props), as_root=True)
+    # Android will not respect the local props file if it is world writable.
+    device.RunShellCommand(
+        ['chmod', '644', constants.DEVICE_LOCAL_PROPERTIES_PATH],
+        as_root=True, check_return=True)
+  except device_errors.CommandFailedError:
+    logging.exception('Failed to configure local properties.')
+
+
+def FinishProvisioning(device, options):
+  device.RunShellCommand(
+      ['date', '-s', time.strftime('%Y%m%d.%H%M%S', time.gmtime())],
+      as_root=True, check_return=True)
+  props = device.RunShellCommand('getprop', check_return=True)
+  for prop in props:
+    logging.info('  %s' % prop)
+  if options.auto_reconnect:
+    _PushAndLaunchAdbReboot(device, options.target)
+
+
+def _PushAndLaunchAdbReboot(device, target):
+  """Pushes and launches the adb_reboot binary on the device.
+
+  Arguments:
+    device: The DeviceUtils instance for the device to which the adb_reboot
+            binary should be pushed.
+    target: The build target (example, Debug or Release) which helps in
+            locating the adb_reboot binary.
+  """
+  logging.info('Will push and launch adb_reboot on %s' % str(device))
+  # Kill if adb_reboot is already running.
+  device.KillAll('adb_reboot', blocking=True, timeout=2, quiet=True)
+  # Push adb_reboot
+  logging.info('  Pushing adb_reboot ...')
+  adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT,
+                            'out/%s/adb_reboot' % target)
+  device.PushChangedFiles([(adb_reboot, '/data/local/tmp/')])
+  # Launch adb_reboot
+  logging.info('  Launching adb_reboot ...')
+  device.RunShellCommand(
+      [device.GetDevicePieWrapper(), '/data/local/tmp/adb_reboot'],
+      check_return=True)
+
+
+def _LaunchHostHeartbeat():
+  # Kill if existing host_heartbeat
+  KillHostHeartbeat()
+  # Launch a new host_heartbeat
+  logging.info('Spawning host heartbeat...')
+  subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT,
+                                 'build/android/host_heartbeat.py')])
+
+
+def KillHostHeartbeat():
+  ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
+  stdout, _ = ps.communicate()
+  matches = re.findall('\\n.*host_heartbeat.*', stdout)
+  for match in matches:
+    logging.info('An instance of host heart beart running... will kill')
+    pid = re.findall(r'(\S+)', match)[1]
+    subprocess.call(['kill', str(pid)])
+
+
+def main():
+  # Recommended options on perf bots:
+  # --disable-network
+  #     TODO(tonyg): We eventually want network on. However, currently radios
+  #     can cause perfbots to drain faster than they charge.
+  # --min-battery-level 95
+  #     Some perf bots run benchmarks with USB charging disabled which leads
+  #     to gradual draining of the battery. We must wait for a full charge
+  #     before starting a run in order to keep the devices online.
+
+  parser = argparse.ArgumentParser(
+      description='Provision Android devices with settings required for bots.')
+  parser.add_argument('-d', '--device', metavar='SERIAL',
+                      help='the serial number of the device to be provisioned'
+                      ' (the default is to provision all devices attached)')
+  parser.add_argument('--phase', action='append', choices=_PHASES.ALL,
+                      dest='phases',
+                      help='Phases of provisioning to run. '
+                           '(If omitted, all phases will be run.)')
+  parser.add_argument('--skip-wipe', action='store_true', default=False,
+                      help="don't wipe device data during provisioning")
+  parser.add_argument('--reboot-timeout', metavar='SECS', type=int,
+                      help='when wiping the device, max number of seconds to'
+                      ' wait after each reboot '
+                      '(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT)
+  parser.add_argument('--min-battery-level', type=int, metavar='NUM',
+                      help='wait for the device to reach this minimum battery'
+                      ' level before trying to continue')
+  parser.add_argument('--disable-location', action='store_true',
+                      help='disable Google location services on devices')
+  parser.add_argument('--disable-network', action='store_true',
+                      help='disable network access on devices')
+  parser.add_argument('--disable-java-debug', action='store_false',
+                      dest='enable_java_debug', default=True,
+                      help='disable Java property asserts and JNI checking')
+  parser.add_argument('-t', '--target', default='Debug',
+                      help='the build target (default: %(default)s)')
+  parser.add_argument('-r', '--auto-reconnect', action='store_true',
+                      help='push binary which will reboot the device on adb'
+                      ' disconnections')
+  parser.add_argument('--adb-key-files', type=str, nargs='+',
+                      help='list of adb keys to push to device')
+  parser.add_argument('-v', '--verbose', action='count', default=1,
+                      help='Log more information.')
+  parser.add_argument('--max-battery-temp', type=int, metavar='NUM',
+                      help='Wait for the battery to have this temp or lower.')
+  args = parser.parse_args()
+  constants.SetBuildType(args.target)
+
+  run_tests_helper.SetLogLevel(args.verbose)
+
+  return ProvisionDevices(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/push_libraries.gypi b/build/android/push_libraries.gypi
new file mode 100644
index 0000000..c96e5a5
--- /dev/null
+++ b/build/android/push_libraries.gypi
@@ -0,0 +1,49 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule that
+# pushes stripped shared libraries to the attached Android device. This should
+# only be used with the gyp_managed_install flag set.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'actions': [
+#      'variables': {
+#        'ordered_libraries_file': 'file generated by write_ordered_libraries'
+#        'strip_stamp': 'stamp from strip action to block on'
+#        'libraries_source_dir': 'location where stripped libraries are stored'
+#        'device_library_dir': 'location on the device where to put pushed libraries',
+#        'push_stamp': 'file to touch when the action is complete'
+#        'configuration_name': 'The build CONFIGURATION_NAME'
+#      },
+#      'includes': [ '../../build/android/push_libraries.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'action_name': 'push_libraries_<(_target_name)',
+  'message': 'Pushing libraries to device for <(_target_name)',
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/util/md5_check.py',
+    '<(DEPTH)/build/android/gyp/push_libraries.py',
+    '<(strip_stamp)',
+    '<(strip_additional_stamp)',
+    '<(build_device_config_path)',
+    '<(pack_arm_relocations_stamp)',
+  ],
+  'outputs': [
+    '<(push_stamp)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/push_libraries.py',
+    '--build-device-configuration=<(build_device_config_path)',
+    '--libraries-dir=<(libraries_source_dir)',
+    '--device-dir=<(device_library_dir)',
+    '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
+    '--stamp=<(push_stamp)',
+    '--configuration-name=<(configuration_name)',
+  ],
+}
diff --git a/build/android/pylib/OWNERS b/build/android/pylib/OWNERS
new file mode 100644
index 0000000..dbbbba7
--- /dev/null
+++ b/build/android/pylib/OWNERS
@@ -0,0 +1,4 @@
+jbudorick@chromium.org
+klundberg@chromium.org
+navabi@chromium.org
+skyostil@chromium.org
diff --git a/build/android/pylib/__init__.py b/build/android/pylib/__init__.py
new file mode 100644
index 0000000..96196cf
--- /dev/null
+++ b/build/android/pylib/__init__.py
@@ -0,0 +1,3 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
new file mode 100644
index 0000000..1ed1877
--- /dev/null
+++ b/build/android/pylib/android_commands.py
@@ -0,0 +1,1972 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Provides an interface to communicate with the device via the adb command.
+
+Assumes adb binary is currently on system path.
+"""
+# pylint: skip-file
+
+import collections
+import datetime
+import inspect
+import logging
+import os
+import random
+import re
+import shlex
+import signal
+import subprocess
+import sys
+import tempfile
+import time
+
+import cmd_helper
+import constants
+import system_properties
+from utils import host_utils
+
+try:
+  from pylib import pexpect
+except ImportError:
+  pexpect = None
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner'))
+import adb_interface
+import am_instrument_parser
+import errors
+
+from pylib.device import device_blacklist
+from pylib.device import device_errors
+
+# Pattern to search for the next whole line of pexpect output and capture it
+# into a match group. We can't use ^ and $ for line start end with pexpect,
+# see http://www.noah.org/python/pexpect/#doc for explanation why.
+PEXPECT_LINE_RE = re.compile('\n([^\r]*)\r')
+
+# Set the adb shell prompt to be a unique marker that will [hopefully] not
+# appear at the start of any line of a command's output.
+SHELL_PROMPT = '~+~PQ\x17RS~+~'
+
+# Java properties file
+LOCAL_PROPERTIES_PATH = constants.DEVICE_LOCAL_PROPERTIES_PATH
+
+# Property in /data/local.prop that controls Java assertions.
+JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions'
+
+# Keycode "enum" suitable for passing to AndroidCommands.SendKey().
+KEYCODE_HOME = 3
+KEYCODE_BACK = 4
+KEYCODE_DPAD_UP = 19
+KEYCODE_DPAD_DOWN = 20
+KEYCODE_DPAD_RIGHT = 22
+KEYCODE_ENTER = 66
+KEYCODE_MENU = 82
+
+MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/'
+MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin'
+
+PIE_WRAPPER_PATH = constants.TEST_EXECUTABLE_DIR + '/run_pie'
+
+CONTROL_USB_CHARGING_COMMANDS = [
+  {
+    # Nexus 4
+    'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
+    'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled',
+    'disable_command':
+        'echo 1 > /sys/module/pm8921_charger/parameters/disabled',
+  },
+  {
+    # Nexus 5
+    # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
+    # energy coming from USB. Setting the power_supply offline just updates the
+    # Android system to reflect that.
+    'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
+    'enable_command': (
+        'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
+        'echo 1 > /sys/class/power_supply/usb/online'),
+    'disable_command': (
+        'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
+        'chmod 644 /sys/class/power_supply/usb/online && '
+        'echo 0 > /sys/class/power_supply/usb/online'),
+  },
+]
+
+class DeviceTempFile(object):
+  def __init__(self, android_commands, prefix='temp_file', suffix=''):
+    """Find an unused temporary file path in the devices external directory.
+
+    When this object is closed, the file will be deleted on the device.
+    """
+    self.android_commands = android_commands
+    while True:
+      # TODO(cjhopman): This could actually return the same file in multiple
+      # calls if the caller doesn't write to the files immediately. This is
+      # expected to never happen.
+      i = random.randint(0, 1000000)
+      self.name = '%s/%s-%d-%010d%s' % (
+          android_commands.GetExternalStorage(),
+          prefix, int(time.time()), i, suffix)
+      if not android_commands.FileExistsOnDevice(self.name):
+        break
+
+  def __enter__(self):
+    return self
+
+  def __exit__(self, type, value, traceback):
+    self.close()
+
+  def close(self):
+    self.android_commands.RunShellCommand('rm ' + self.name)
+
+
+def GetAVDs():
+  """Returns a list of AVDs."""
+  re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE)
+  avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd']))
+  return avds
+
+def ResetBadDevices():
+  """Removes the blacklist that keeps track of bad devices for a current
+     build.
+  """
+  device_blacklist.ResetBlacklist()
+
+def ExtendBadDevices(devices):
+  """Adds devices to the blacklist that keeps track of bad devices for a
+     current build.
+
+  The devices listed in the bad devices file will not be returned by
+  GetAttachedDevices.
+
+  Args:
+    devices: list of bad devices to be added to the bad devices file.
+  """
+  device_blacklist.ExtendBlacklist(devices)
+
+
+def GetAttachedDevices(hardware=True, emulator=True, offline=False):
+  """Returns a list of attached, android devices and emulators.
+
+  If a preferred device has been set with ANDROID_SERIAL, it will be first in
+  the returned list. The arguments specify what devices to include in the list.
+
+  Example output:
+
+    * daemon not running. starting it now on port 5037 *
+    * daemon started successfully *
+    List of devices attached
+    027c10494100b4d7        device
+    emulator-5554   offline
+
+  Args:
+    hardware: Include attached actual devices that are online.
+    emulator: Include emulators (i.e. AVD's) currently on host.
+    offline: Include devices and emulators that are offline.
+
+  Returns: List of devices.
+  """
+  adb_devices_output = cmd_helper.GetCmdOutput([constants.GetAdbPath(),
+                                                'devices'])
+
+  re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE)
+  online_devices = re_device.findall(adb_devices_output)
+
+  re_device = re.compile('^(emulator-[0-9]+)\tdevice', re.MULTILINE)
+  emulator_devices = re_device.findall(adb_devices_output)
+
+  re_device = re.compile('^([a-zA-Z0-9_:.-]+)\t(?:offline|unauthorized)$',
+                         re.MULTILINE)
+  offline_devices = re_device.findall(adb_devices_output)
+
+  devices = []
+  # First determine list of online devices (e.g. hardware and/or emulator).
+  if hardware and emulator:
+    devices = online_devices
+  elif hardware:
+    devices = [device for device in online_devices
+               if device not in emulator_devices]
+  elif emulator:
+    devices = emulator_devices
+
+  # Now add offline devices if offline is true
+  if offline:
+    devices = devices + offline_devices
+
+  # Remove any devices in the blacklist.
+  blacklist = device_blacklist.ReadBlacklist()
+  if len(blacklist):
+    logging.info('Avoiding bad devices %s', ' '.join(blacklist))
+    devices = [device for device in devices if device not in blacklist]
+
+  preferred_device = os.environ.get('ANDROID_SERIAL')
+  if preferred_device in devices:
+    devices.remove(preferred_device)
+    devices.insert(0, preferred_device)
+  return devices
+
+
+def IsDeviceAttached(device):
+  """Return true if the device is attached and online."""
+  return device in GetAttachedDevices()
+
+
+def _GetFilesFromRecursiveLsOutput(path, ls_output, re_file, utc_offset=None):
+  """Gets a list of files from `ls` command output.
+
+  Python's os.walk isn't used because it doesn't work over adb shell.
+
+  Args:
+    path: The path to list.
+    ls_output: A list of lines returned by an `ls -lR` command.
+    re_file: A compiled regular expression which parses a line into named groups
+        consisting of at minimum "filename", "date", "time", "size" and
+        optionally "timezone".
+    utc_offset: A 5-character string of the form +HHMM or -HHMM, where HH is a
+        2-digit string giving the number of UTC offset hours, and MM is a
+        2-digit string giving the number of UTC offset minutes. If the input
+        utc_offset is None, will try to look for the value of "timezone" if it
+        is specified in re_file.
+
+  Returns:
+    A dict of {"name": (size, lastmod), ...} where:
+      name: The file name relative to |path|'s directory.
+      size: The file size in bytes (0 for directories).
+      lastmod: The file last modification date in UTC.
+  """
+  re_directory = re.compile('^%s/(?P<dir>[^:]+):$' % re.escape(path))
+  path_dir = os.path.dirname(path)
+
+  current_dir = ''
+  files = {}
+  for line in ls_output:
+    directory_match = re_directory.match(line)
+    if directory_match:
+      current_dir = directory_match.group('dir')
+      continue
+    file_match = re_file.match(line)
+    if file_match:
+      filename = os.path.join(current_dir, file_match.group('filename'))
+      if filename.startswith(path_dir):
+        filename = filename[len(path_dir) + 1:]
+      lastmod = datetime.datetime.strptime(
+          file_match.group('date') + ' ' + file_match.group('time')[:5],
+          '%Y-%m-%d %H:%M')
+      if not utc_offset and 'timezone' in re_file.groupindex:
+        utc_offset = file_match.group('timezone')
+      if isinstance(utc_offset, str) and len(utc_offset) == 5:
+        utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]),
+                                       minutes=int(utc_offset[3:5]))
+        if utc_offset[0:1] == '-':
+          utc_delta = -utc_delta
+        lastmod -= utc_delta
+      files[filename] = (int(file_match.group('size')), lastmod)
+  return files
+
+
+def _ParseMd5SumOutput(md5sum_output):
+  """Returns a list of tuples from the provided md5sum output.
+
+  Args:
+    md5sum_output: output directly from md5sum binary.
+
+  Returns:
+    List of namedtuples with attributes |hash| and |path|, where |path| is the
+    absolute path to the file with an Md5Sum of |hash|.
+  """
+  HashAndPath = collections.namedtuple('HashAndPath', ['hash', 'path'])
+  split_lines = [line.split('  ') for line in md5sum_output]
+  return [HashAndPath._make(s) for s in split_lines if len(s) == 2]
+
+
+def _HasAdbPushSucceeded(command_output):
+  """Returns whether adb push has succeeded from the provided output."""
+  # TODO(frankf): We should look at the return code instead of the command
+  # output for many of the commands in this file.
+  if not command_output:
+    return True
+  # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)"
+  # Errors look like this: "failed to copy  ... "
+  if not re.search('^[0-9]', command_output.splitlines()[-1]):
+    logging.critical('PUSH FAILED: ' + command_output)
+    return False
+  return True
+
+
+def GetLogTimestamp(log_line, year):
+  """Returns the timestamp of the given |log_line| in the given year."""
+  try:
+    return datetime.datetime.strptime('%s-%s' % (year, log_line[:18]),
+                                      '%Y-%m-%d %H:%M:%S.%f')
+  except (ValueError, IndexError):
+    logging.critical('Error reading timestamp from ' + log_line)
+    return None
+
+
+class AndroidCommands(object):
+  """Helper class for communicating with Android device via adb."""
+
+  def __init__(self, device=None):
+    """Constructor.
+
+    Args:
+      device: If given, adb commands are only send to the device of this ID.
+          Otherwise commands are sent to all attached devices.
+    """
+    self._adb = adb_interface.AdbInterface(constants.GetAdbPath())
+    if device:
+      self._adb.SetTargetSerial(device)
+    self._device = device
+    self._logcat = None
+    self.logcat_process = None
+    self._logcat_tmpoutfile = None
+    self._pushed_files = []
+    self._device_utc_offset = None
+    self._potential_push_size = 0
+    self._actual_push_size = 0
+    self._external_storage = ''
+    self._util_wrapper = ''
+    self._system_properties = system_properties.SystemProperties(self.Adb())
+    self._push_if_needed_cache = {}
+    self._control_usb_charging_command = {
+        'command': None,
+        'cached': False,
+    }
+    self._protected_file_access_method_initialized = None
+    self._privileged_command_runner = None
+    self._pie_wrapper = None
+
+  @property
+  def system_properties(self):
+    return self._system_properties
+
+  def _LogShell(self, cmd):
+    """Logs the adb shell command."""
+    if self._device:
+      device_repr = self._device[-4:]
+    else:
+      device_repr = '????'
+    logging.info('[%s]> %s', device_repr, cmd)
+
+  def Adb(self):
+    """Returns our AdbInterface to avoid us wrapping all its methods."""
+    # TODO(tonyg): Goal should be to git rid of this method by making this API
+    # complete and alleviating the need.
+    return self._adb
+
+  def GetDevice(self):
+    """Returns the device serial."""
+    return self._device
+
+  def IsOnline(self):
+    """Checks whether the device is online.
+
+    Returns:
+      True if device is in 'device' mode, False otherwise.
+    """
+    # TODO(aurimas): revert to using adb get-state when android L adb is fixed.
+    #out = self._adb.SendCommand('get-state')
+    #return out.strip() == 'device'
+
+    out = self._adb.SendCommand('devices')
+    for line in out.split('\n'):
+      if self._device in line and 'device' in line:
+        return True
+    return False
+
+  def IsRootEnabled(self):
+    """Checks if root is enabled on the device."""
+    root_test_output = self.RunShellCommand('ls /root') or ['']
+    return not 'Permission denied' in root_test_output[0]
+
+  def EnableAdbRoot(self):
+    """Enables adb root on the device.
+
+    Returns:
+      True: if output from executing adb root was as expected.
+      False: otherwise.
+    """
+    if self.GetBuildType() == 'user':
+      logging.warning("Can't enable root in production builds with type user")
+      return False
+    else:
+      return_value = self._adb.EnableAdbRoot()
+      # EnableAdbRoot inserts a call for wait-for-device only when adb logcat
+      # output matches what is expected. Just to be safe add a call to
+      # wait-for-device.
+      self._adb.SendCommand('wait-for-device')
+      return return_value
+
+  def GetDeviceYear(self):
+    """Returns the year information of the date on device."""
+    return self.RunShellCommand('date +%Y')[0]
+
+  def GetExternalStorage(self):
+    if not self._external_storage:
+      self._external_storage = self.RunShellCommand('echo $EXTERNAL_STORAGE')[0]
+      if not self._external_storage:
+        raise device_errors.CommandFailedError(
+            ['shell', "'echo $EXTERNAL_STORAGE'"],
+            'Unable to find $EXTERNAL_STORAGE')
+    return self._external_storage
+
+  def WaitForDevicePm(self, timeout=120):
+    """Blocks until the device's package manager is available.
+
+    To workaround http://b/5201039, we restart the shell and retry if the
+    package manager isn't back after 120 seconds.
+
+    Raises:
+      errors.WaitForResponseTimedOutError after max retries reached.
+    """
+    last_err = None
+    retries = 3
+    while retries:
+      try:
+        self._adb.WaitForDevicePm(wait_time=timeout)
+        return  # Success
+      except errors.WaitForResponseTimedOutError as e:
+        last_err = e
+        logging.warning('Restarting and retrying after timeout: %s', e)
+        retries -= 1
+        self.RestartShell()
+    raise last_err # Only reached after max retries, re-raise the last error.
+
+  def RestartShell(self):
+    """Restarts the shell on the device. Does not block for it to return."""
+    self.RunShellCommand('stop')
+    self.RunShellCommand('start')
+
+  def Reboot(self, full_reboot=True):
+    """Reboots the device and waits for the package manager to return.
+
+    Args:
+      full_reboot: Whether to fully reboot the device or just restart the shell.
+    """
+    # TODO(torne): hive can't reboot the device either way without breaking the
+    # connection; work out if we can handle this better
+    if os.environ.get('USING_HIVE'):
+      logging.warning('Ignoring reboot request as we are on hive')
+      return
+    if full_reboot or not self.IsRootEnabled():
+      self._adb.SendCommand('reboot')
+      self._system_properties = system_properties.SystemProperties(self.Adb())
+      timeout = 300
+      retries = 1
+      # Wait for the device to disappear.
+      while retries < 10 and self.IsOnline():
+        time.sleep(1)
+        retries += 1
+    else:
+      self.RestartShell()
+      timeout = 120
+    # To run tests we need at least the package manager and the sd card (or
+    # other external storage) to be ready.
+    self.WaitForDevicePm(timeout)
+    self.WaitForSdCardReady(timeout)
+
+  def Shutdown(self):
+    """Shuts down the device."""
+    self._adb.SendCommand('reboot -p')
+    self._system_properties = system_properties.SystemProperties(self.Adb())
+
+  def Uninstall(self, package):
+    """Uninstalls the specified package from the device.
+
+    Args:
+      package: Name of the package to remove.
+
+    Returns:
+      A status string returned by adb uninstall
+    """
+    uninstall_command = 'uninstall %s' % package
+
+    self._LogShell(uninstall_command)
+    return self._adb.SendCommand(uninstall_command, timeout_time=60)
+
+  def Install(self, package_file_path, reinstall=False):
+    """Installs the specified package to the device.
+
+    Args:
+      package_file_path: Path to .apk file to install.
+      reinstall: Reinstall an existing apk, keeping the data.
+
+    Returns:
+      A status string returned by adb install
+    """
+    assert os.path.isfile(package_file_path), ('<%s> is not file' %
+                                               package_file_path)
+
+    install_cmd = ['install']
+
+    if reinstall:
+      install_cmd.append('-r')
+
+    install_cmd.append(package_file_path)
+    install_cmd = ' '.join(install_cmd)
+
+    self._LogShell(install_cmd)
+    return self._adb.SendCommand(install_cmd,
+                                 timeout_time=2 * 60,
+                                 retry_count=0)
+
+  def ManagedInstall(self, apk_path, keep_data=False, package_name=None,
+                     reboots_on_timeout=2):
+    """Installs specified package and reboots device on timeouts.
+
+    If package_name is supplied, checks if the package is already installed and
+    doesn't reinstall if the apk md5sums match.
+
+    Args:
+      apk_path: Path to .apk file to install.
+      keep_data: Reinstalls instead of uninstalling first, preserving the
+        application data.
+      package_name: Package name (only needed if keep_data=False).
+      reboots_on_timeout: number of time to reboot if package manager is frozen.
+    """
+    # Check if package is already installed and up to date.
+    if package_name:
+      installed_apk_path = self.GetApplicationPath(package_name)
+      if (installed_apk_path and
+          not self.GetFilesChanged(apk_path, installed_apk_path,
+                                   ignore_filenames=True)):
+        logging.info('Skipped install: identical %s APK already installed' %
+            package_name)
+        return
+    # Install.
+    reboots_left = reboots_on_timeout
+    while True:
+      try:
+        if not keep_data:
+          assert package_name
+          self.Uninstall(package_name)
+        install_status = self.Install(apk_path, reinstall=keep_data)
+        if 'Success' in install_status:
+          return
+        else:
+          raise Exception('Install failure: %s' % install_status)
+      except errors.WaitForResponseTimedOutError:
+        print '@@@STEP_WARNINGS@@@'
+        logging.info('Timeout on installing %s on device %s', apk_path,
+                     self._device)
+
+        if reboots_left <= 0:
+          raise Exception('Install timed out')
+
+        # Force a hard reboot on last attempt
+        self.Reboot(full_reboot=(reboots_left == 1))
+        reboots_left -= 1
+
+  def MakeSystemFolderWritable(self):
+    """Remounts the /system folder rw."""
+    out = self._adb.SendCommand('remount')
+    if out.strip() != 'remount succeeded':
+      raise errors.MsgException('Remount failed: %s' % out)
+
+  def RestartAdbdOnDevice(self):
+    logging.info('Restarting adbd on the device...')
+    with DeviceTempFile(self, suffix=".sh") as temp_script_file:
+      host_script_path = os.path.join(constants.DIR_SOURCE_ROOT,
+                                      'build',
+                                      'android',
+                                      'pylib',
+                                      'restart_adbd.sh')
+      self._adb.Push(host_script_path, temp_script_file.name)
+      self.RunShellCommand('. %s' % temp_script_file.name)
+      self._adb.SendCommand('wait-for-device')
+
+  def RestartAdbServer(self):
+    """Restart the adb server."""
+    ret = self.KillAdbServer()
+    if ret != 0:
+      raise errors.MsgException('KillAdbServer: %d' % ret)
+
+    ret = self.StartAdbServer()
+    if ret != 0:
+      raise errors.MsgException('StartAdbServer: %d' % ret)
+
+  @staticmethod
+  def KillAdbServer():
+    """Kill adb server."""
+    adb_cmd = [constants.GetAdbPath(), 'kill-server']
+    ret = cmd_helper.RunCmd(adb_cmd)
+    retry = 0
+    while retry < 3:
+      ret, _ = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
+      if ret != 0:
+        # pgrep didn't find adb, kill-server succeeded.
+        return 0
+      retry += 1
+      time.sleep(retry)
+    return ret
+
+  def StartAdbServer(self):
+    """Start adb server."""
+    adb_cmd = ['taskset', '-c', '0', constants.GetAdbPath(), 'start-server']
+    ret, _ = cmd_helper.GetCmdStatusAndOutput(adb_cmd)
+    retry = 0
+    while retry < 3:
+      ret, _ = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
+      if ret == 0:
+        # pgrep found adb, start-server succeeded.
+        # Waiting for device to reconnect before returning success.
+        self._adb.SendCommand('wait-for-device')
+        return 0
+      retry += 1
+      time.sleep(retry)
+    return ret
+
+  def WaitForSystemBootCompleted(self, wait_time):
+    """Waits for targeted system's boot_completed flag to be set.
+
+    Args:
+      wait_time: time in seconds to wait
+
+    Raises:
+      WaitForResponseTimedOutError if wait_time elapses and flag still not
+      set.
+    """
+    logging.info('Waiting for system boot completed...')
+    self._adb.SendCommand('wait-for-device')
+    # Now the device is there, but system not boot completed.
+    # Query the sys.boot_completed flag with a basic command
+    boot_completed = False
+    attempts = 0
+    wait_period = 5
+    while not boot_completed and (attempts * wait_period) < wait_time:
+      output = self.system_properties['sys.boot_completed']
+      output = output.strip()
+      if output == '1':
+        boot_completed = True
+      else:
+        # If 'error: xxx' returned when querying the flag, it means
+        # adb server lost the connection to the emulator, so restart the adb
+        # server.
+        if 'error:' in output:
+          self.RestartAdbServer()
+        time.sleep(wait_period)
+        attempts += 1
+    if not boot_completed:
+      raise errors.WaitForResponseTimedOutError(
+          'sys.boot_completed flag was not set after %s seconds' % wait_time)
+
+  def WaitForSdCardReady(self, timeout_time):
+    """Wait for the SD card ready before pushing data into it."""
+    logging.info('Waiting for SD card ready...')
+    sdcard_ready = False
+    attempts = 0
+    wait_period = 5
+    external_storage = self.GetExternalStorage()
+    while not sdcard_ready and attempts * wait_period < timeout_time:
+      output = self.RunShellCommand('ls ' + external_storage)
+      if output:
+        sdcard_ready = True
+      else:
+        time.sleep(wait_period)
+        attempts += 1
+    if not sdcard_ready:
+      raise errors.WaitForResponseTimedOutError(
+          'SD card not ready after %s seconds' % timeout_time)
+
+  def GetAndroidToolStatusAndOutput(self, command, lib_path=None, *args, **kw):
+    """Runs a native Android binary, wrapping the command as necessary.
+
+    This is a specialization of GetShellCommandStatusAndOutput, which is meant
+    for running tools/android/ binaries and handle properly: (1) setting the
+    lib path (for component=shared_library), (2) using the PIE wrapper on ICS.
+    See crbug.com/373219 for more context.
+
+    Args:
+      command: String containing the command to send.
+      lib_path: (optional) path to the folder containing the dependent libs.
+      Same other arguments of GetCmdStatusAndOutput.
+    """
+    # The first time this command is run the device is inspected to check
+    # whether a wrapper for running PIE executable is needed (only Android ICS)
+    # or not. The results is cached, so the wrapper is pushed only once.
+    if self._pie_wrapper is None:
+      # None: did not check; '': did check and not needed; '/path': use /path.
+      self._pie_wrapper = ''
+      if self.GetBuildId().startswith('I'):  # Ixxxx = Android ICS.
+        run_pie_dist_path = os.path.join(constants.GetOutDirectory(), 'run_pie')
+        assert os.path.exists(run_pie_dist_path), 'Please build run_pie'
+        # The PIE loader must be pushed manually (i.e. no PushIfNeeded) because
+        # PushIfNeeded requires md5sum and md5sum requires the wrapper as well.
+        adb_command = 'push %s %s' % (run_pie_dist_path, PIE_WRAPPER_PATH)
+        assert _HasAdbPushSucceeded(self._adb.SendCommand(adb_command))
+        self._pie_wrapper = PIE_WRAPPER_PATH
+
+    if self._pie_wrapper:
+      command = '%s %s' % (self._pie_wrapper, command)
+    if lib_path:
+      command = 'LD_LIBRARY_PATH=%s %s' % (lib_path, command)
+    return self.GetShellCommandStatusAndOutput(command, *args, **kw)
+
+  # It is tempting to turn this function into a generator, however this is not
+  # possible without using a private (local) adb_shell instance (to ensure no
+  # other command interleaves usage of it), which would defeat the main aim of
+  # being able to reuse the adb shell instance across commands.
+  def RunShellCommand(self, command, timeout_time=20, log_result=False):
+    """Send a command to the adb shell and return the result.
+
+    Args:
+      command: String containing the shell command to send.
+      timeout_time: Number of seconds to wait for command to respond before
+        retrying, used by AdbInterface.SendShellCommand.
+      log_result: Boolean to indicate whether we should log the result of the
+                  shell command.
+
+    Returns:
+      list containing the lines of output received from running the command
+    """
+    self._LogShell(command)
+    if "'" in command:
+      command = command.replace('\'', '\'\\\'\'')
+    result = self._adb.SendShellCommand(
+        "'%s'" % command, timeout_time).splitlines()
+    # TODO(b.kelemen): we should really be able to drop the stderr of the
+    # command or raise an exception based on what the caller wants.
+    result = [ l for l in result if not l.startswith('WARNING') ]
+    if ['error: device not found'] == result:
+      raise errors.DeviceUnresponsiveError('device not found')
+    if log_result:
+      self._LogShell('\n'.join(result))
+    return result
+
+  def GetShellCommandStatusAndOutput(self, command, timeout_time=20,
+                                     log_result=False):
+    """See RunShellCommand() above.
+
+    Returns:
+      The tuple (exit code, list of output lines).
+    """
+    lines = self.RunShellCommand(
+        command + '; echo %$?', timeout_time, log_result)
+    last_line = lines[-1]
+    status_pos = last_line.rfind('%')
+    assert status_pos >= 0
+    status = int(last_line[status_pos + 1:])
+    if status_pos == 0:
+      lines = lines[:-1]
+    else:
+      lines = lines[:-1] + [last_line[:status_pos]]
+    return (status, lines)
+
+  def KillAll(self, process, signum=9, with_su=False):
+    """Android version of killall, connected via adb.
+
+    Args:
+      process: name of the process to kill off.
+      signum: signal to use, 9 (SIGKILL) by default.
+      with_su: wether or not to use su to kill the processes.
+
+    Returns:
+      the number of processes killed
+    """
+    pids = self.ExtractPid(process)
+    if pids:
+      cmd = 'kill -%d %s' % (signum, ' '.join(pids))
+      if with_su:
+        self.RunShellCommandWithSU(cmd)
+      else:
+        self.RunShellCommand(cmd)
+    return len(pids)
+
+  def KillAllBlocking(self, process, timeout_sec, signum=9, with_su=False):
+    """Blocking version of killall, connected via adb.
+
+    This waits until no process matching the corresponding name appears in ps'
+    output anymore.
+
+    Args:
+      process: name of the process to kill off
+      timeout_sec: the timeout in seconds
+      signum: same as |KillAll|
+      with_su: same as |KillAll|
+    Returns:
+      the number of processes killed
+    """
+    processes_killed = self.KillAll(process, signum=signum, with_su=with_su)
+    if processes_killed:
+      elapsed = 0
+      wait_period = 0.1
+      # Note that this doesn't take into account the time spent in ExtractPid().
+      while self.ExtractPid(process) and elapsed < timeout_sec:
+        time.sleep(wait_period)
+        elapsed += wait_period
+      if elapsed >= timeout_sec:
+        return processes_killed - self.ExtractPid(process)
+    return processes_killed
+
+  @staticmethod
+  def _GetActivityCommand(package, activity, wait_for_completion, action,
+                          category, data, extras, trace_file_name, force_stop,
+                          flags):
+    """Creates command to start |package|'s activity on the device.
+
+    Args - as for StartActivity
+
+    Returns:
+      the command to run on the target to start the activity
+    """
+    cmd = 'am start -a %s' % action
+    if force_stop:
+      cmd += ' -S'
+    if wait_for_completion:
+      cmd += ' -W'
+    if category:
+      cmd += ' -c %s' % category
+    if package and activity:
+      cmd += ' -n %s/%s' % (package, activity)
+    if data:
+      cmd += ' -d "%s"' % data
+    if extras:
+      for key in extras:
+        value = extras[key]
+        if isinstance(value, str):
+          cmd += ' --es'
+        elif isinstance(value, bool):
+          cmd += ' --ez'
+        elif isinstance(value, int):
+          cmd += ' --ei'
+        else:
+          raise NotImplementedError(
+              'Need to teach StartActivity how to pass %s extras' % type(value))
+        cmd += ' %s %s' % (key, value)
+    if trace_file_name:
+      cmd += ' --start-profiler ' + trace_file_name
+    if flags:
+      cmd += ' -f %s' % flags
+    return cmd
+
+  def StartActivity(self, package, activity, wait_for_completion=False,
+                    action='android.intent.action.VIEW',
+                    category=None, data=None,
+                    extras=None, trace_file_name=None,
+                    force_stop=False, flags=None):
+    """Starts |package|'s activity on the device.
+
+    Args:
+      package: Name of package to start (e.g. 'com.google.android.apps.chrome').
+      activity: Name of activity (e.g. '.Main' or
+        'com.google.android.apps.chrome.Main').
+      wait_for_completion: wait for the activity to finish launching (-W flag).
+      action: string (e.g. "android.intent.action.MAIN"). Default is VIEW.
+      category: string (e.g. "android.intent.category.HOME")
+      data: Data string to pass to activity (e.g. 'http://www.example.com/').
+      extras: Dict of extras to pass to activity. Values are significant.
+      trace_file_name: If used, turns on and saves the trace to this file name.
+      force_stop: force stop the target app before starting the activity (-S
+        flag).
+    Returns:
+      The output of the underlying command as a list of lines.
+    """
+    cmd = self._GetActivityCommand(package, activity, wait_for_completion,
+                                   action, category, data, extras,
+                                   trace_file_name, force_stop, flags)
+    return self.RunShellCommand(cmd)
+
+  def StartActivityTimed(self, package, activity, wait_for_completion=False,
+                         action='android.intent.action.VIEW',
+                         category=None, data=None,
+                         extras=None, trace_file_name=None,
+                         force_stop=False, flags=None):
+    """Starts |package|'s activity on the device, returning the start time
+
+    Args - as for StartActivity
+
+    Returns:
+      A tuple containing:
+        - the output of the underlying command as a list of lines, and
+        - a timestamp string for the time at which the activity started
+    """
+    cmd = self._GetActivityCommand(package, activity, wait_for_completion,
+                                   action, category, data, extras,
+                                   trace_file_name, force_stop, flags)
+    self.StartMonitoringLogcat()
+    out = self.RunShellCommand('log starting activity; ' + cmd)
+    activity_started_re = re.compile('.*starting activity.*')
+    m = self.WaitForLogMatch(activity_started_re, None)
+    assert m
+    start_line = m.group(0)
+    return (out, GetLogTimestamp(start_line, self.GetDeviceYear()))
+
+  def StartCrashUploadService(self, package):
+    # TODO(frankf): We really need a python wrapper around Intent
+    # to be shared with StartActivity/BroadcastIntent.
+    cmd = (
+      'am startservice -a %s.crash.ACTION_FIND_ALL -n '
+      '%s/%s.crash.MinidumpUploadService' %
+      (constants.PACKAGE_INFO['chrome'].package,
+       package,
+       constants.PACKAGE_INFO['chrome'].package))
+    am_output = self.RunShellCommandWithSU(cmd)
+    assert am_output and 'Starting' in am_output[-1], (
+        'Service failed to start: %s' % am_output)
+    time.sleep(15)
+
+  def BroadcastIntent(self, package, intent, *args):
+    """Send a broadcast intent.
+
+    Args:
+      package: Name of package containing the intent.
+      intent: Name of the intent.
+      args: Optional extra arguments for the intent.
+    """
+    cmd = 'am broadcast -a %s.%s %s' % (package, intent, ' '.join(args))
+    self.RunShellCommand(cmd)
+
+  def GoHome(self):
+    """Tell the device to return to the home screen. Blocks until completion."""
+    self.RunShellCommand('am start -W '
+        '-a android.intent.action.MAIN -c android.intent.category.HOME')
+
+  def CloseApplication(self, package):
+    """Attempt to close down the application, using increasing violence.
+
+    Args:
+      package: Name of the process to kill off, e.g.
+      com.google.android.apps.chrome
+    """
+    self.RunShellCommand('am force-stop ' + package)
+
+  def GetApplicationPath(self, package):
+    """Get the installed apk path on the device for the given package.
+
+    Args:
+      package: Name of the package.
+
+    Returns:
+      Path to the apk on the device if it exists, None otherwise.
+    """
+    pm_path_output  = self.RunShellCommand('pm path ' + package)
+    # The path output contains anything if and only if the package
+    # exists.
+    if pm_path_output:
+      # pm_path_output is of the form: "package:/path/to/foo.apk"
+      return pm_path_output[0].split(':')[1]
+    else:
+      return None
+
+  def ClearApplicationState(self, package):
+    """Closes and clears all state for the given |package|."""
+    # Check that the package exists before clearing it. Necessary because
+    # calling pm clear on a package that doesn't exist may never return.
+    pm_path_output  = self.RunShellCommand('pm path ' + package)
+    # The path output only contains anything if and only if the package exists.
+    if pm_path_output:
+      self.RunShellCommand('pm clear ' + package)
+
+  def SendKeyEvent(self, keycode):
+    """Sends keycode to the device.
+
+    Args:
+      keycode: Numeric keycode to send (see "enum" at top of file).
+    """
+    self.RunShellCommand('input keyevent %d' % keycode)
+
+  def _RunMd5Sum(self, host_path, device_path):
+    """Gets the md5sum of a host path and device path.
+
+    Args:
+      host_path: Path (file or directory) on the host.
+      device_path: Path on the device.
+
+    Returns:
+      A tuple containing lists of the host and device md5sum results as
+      created by _ParseMd5SumOutput().
+    """
+    md5sum_dist_path = os.path.join(constants.GetOutDirectory(),
+                                    'md5sum_dist')
+    assert os.path.exists(md5sum_dist_path), 'Please build md5sum.'
+    md5sum_dist_mtime = os.stat(md5sum_dist_path).st_mtime
+    if (md5sum_dist_path not in self._push_if_needed_cache or
+        self._push_if_needed_cache[md5sum_dist_path] != md5sum_dist_mtime):
+      command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER)
+      assert _HasAdbPushSucceeded(self._adb.SendCommand(command))
+      self._push_if_needed_cache[md5sum_dist_path] = md5sum_dist_mtime
+
+    (_, md5_device_output) = self.GetAndroidToolStatusAndOutput(
+        self._util_wrapper + ' ' + MD5SUM_DEVICE_PATH + ' ' + device_path,
+        lib_path=MD5SUM_DEVICE_FOLDER,
+        timeout_time=2 * 60)
+    device_hash_tuples = _ParseMd5SumOutput(md5_device_output)
+    assert os.path.exists(host_path), 'Local path not found %s' % host_path
+    md5sum_output = cmd_helper.GetCmdOutput(
+        [os.path.join(constants.GetOutDirectory(), 'md5sum_bin_host'),
+         host_path])
+    host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines())
+    return (host_hash_tuples, device_hash_tuples)
+
+  def GetFilesChanged(self, host_path, device_path, ignore_filenames=False):
+    """Compares the md5sum of a host path against a device path.
+
+    Note: Ignores extra files on the device.
+
+    Args:
+      host_path: Path (file or directory) on the host.
+      device_path: Path on the device.
+      ignore_filenames: If True only the file contents are considered when
+          checking whether a file has changed, otherwise the relative path
+          must also match.
+
+    Returns:
+      A list of tuples of the form (host_path, device_path) for files whose
+      md5sums do not match.
+    """
+
+    # Md5Sum resolves symbolic links in path names so the calculation of
+    # relative path names from its output will need the real path names of the
+    # base directories. Having calculated these they are used throughout the
+    # function since this makes us less subject to any future changes to Md5Sum.
+    real_host_path = os.path.realpath(host_path)
+    real_device_path = self.RunShellCommand('realpath "%s"' % device_path)[0]
+
+    host_hash_tuples, device_hash_tuples = self._RunMd5Sum(
+        real_host_path, real_device_path)
+
+    if len(host_hash_tuples) > len(device_hash_tuples):
+      logging.info('%s files do not exist on the device' %
+                   (len(host_hash_tuples) - len(device_hash_tuples)))
+
+    host_rel = [(os.path.relpath(os.path.normpath(t.path), real_host_path),
+                 t.hash)
+                for t in host_hash_tuples]
+
+    if os.path.isdir(real_host_path):
+      def RelToRealPaths(rel_path):
+        return (os.path.join(real_host_path, rel_path),
+                os.path.join(real_device_path, rel_path))
+    else:
+      assert len(host_rel) == 1
+      def RelToRealPaths(_):
+        return (real_host_path, real_device_path)
+
+    if ignore_filenames:
+      # If we are ignoring file names, then we want to push any file for which
+      # a file with an equivalent MD5 sum does not exist on the device.
+      device_hashes = set([h.hash for h in device_hash_tuples])
+      ShouldPush = lambda p, h: h not in device_hashes
+    else:
+      # Otherwise, we want to push any file on the host for which a file with
+      # an equivalent MD5 sum does not exist at the same relative path on the
+      # device.
+      device_rel = dict([(os.path.relpath(os.path.normpath(t.path),
+                                          real_device_path),
+                          t.hash)
+                         for t in device_hash_tuples])
+      ShouldPush = lambda p, h: p not in device_rel or h != device_rel[p]
+
+    return [RelToRealPaths(path) for path, host_hash in host_rel
+            if ShouldPush(path, host_hash)]
+
+  def PushIfNeeded(self, host_path, device_path):
+    """Pushes |host_path| to |device_path|.
+
+    Works for files and directories. This method skips copying any paths in
+    |test_data_paths| that already exist on the device with the same hash.
+
+    All pushed files can be removed by calling RemovePushedFiles().
+    """
+    MAX_INDIVIDUAL_PUSHES = 50
+    if not os.path.exists(host_path):
+      raise device_errors.CommandFailedError(
+          'Local path not found %s' % host_path, device=str(self))
+
+    # See if the file on the host changed since the last push (if any) and
+    # return early if it didn't. Note that this shortcut assumes that the tests
+    # on the device don't modify the files.
+    if not os.path.isdir(host_path):
+      if host_path in self._push_if_needed_cache:
+        host_path_mtime = self._push_if_needed_cache[host_path]
+        if host_path_mtime == os.stat(host_path).st_mtime:
+          return
+
+    size = host_utils.GetRecursiveDiskUsage(host_path)
+    self._pushed_files.append(device_path)
+    self._potential_push_size += size
+
+    if os.path.isdir(host_path):
+      self.RunShellCommand('mkdir -p "%s"' % device_path)
+
+    changed_files = self.GetFilesChanged(host_path, device_path)
+    logging.info('Found %d files that need to be pushed to %s',
+        len(changed_files), device_path)
+    if not changed_files:
+      return
+
+    def Push(host, device):
+      # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout
+      # of 60 seconds which isn't sufficient for a lot of users of this method.
+      push_command = 'push %s %s' % (host, device)
+      self._LogShell(push_command)
+
+      # Retry push with increasing backoff if the device is busy.
+      retry = 0
+      while True:
+        output = self._adb.SendCommand(push_command, timeout_time=30 * 60)
+        if _HasAdbPushSucceeded(output):
+          if not os.path.isdir(host_path):
+            self._push_if_needed_cache[host] = os.stat(host).st_mtime
+          return
+        if retry < 3:
+          retry += 1
+          wait_time = 5 * retry
+          logging.error('Push failed, retrying in %d seconds: %s' %
+                        (wait_time, output))
+          time.sleep(wait_time)
+        else:
+          raise Exception('Push failed: %s' % output)
+
+    diff_size = 0
+    if len(changed_files) <= MAX_INDIVIDUAL_PUSHES:
+      diff_size = sum(host_utils.GetRecursiveDiskUsage(f[0])
+                      for f in changed_files)
+
+    # TODO(craigdh): Replace this educated guess with a heuristic that
+    # approximates the push time for each method.
+    if len(changed_files) > MAX_INDIVIDUAL_PUSHES or diff_size > 0.5 * size:
+      self._actual_push_size += size
+      Push(host_path, device_path)
+    else:
+      for f in changed_files:
+        Push(f[0], f[1])
+      self._actual_push_size += diff_size
+
+  def GetPushSizeInfo(self):
+    """Get total size of pushes to the device done via PushIfNeeded()
+
+    Returns:
+      A tuple:
+        1. Total size of push requests to PushIfNeeded (MB)
+        2. Total size that was actually pushed (MB)
+    """
+    return (self._potential_push_size, self._actual_push_size)
+
+  def GetFileContents(self, filename, log_result=False):
+    """Gets contents from the file specified by |filename|."""
+    return self.RunShellCommand('cat "%s" 2>/dev/null' % filename,
+                                log_result=log_result)
+
+  def SetFileContents(self, filename, contents):
+    """Writes |contents| to the file specified by |filename|."""
+    with tempfile.NamedTemporaryFile() as f:
+      f.write(contents)
+      f.flush()
+      self._adb.Push(f.name, filename)
+
+  def RunShellCommandWithSU(self, command, timeout_time=20, log_result=False):
+    return self.RunShellCommand('su -c %s' % command, timeout_time, log_result)
+
+  def CanAccessProtectedFileContents(self):
+    """Returns True if Get/SetProtectedFileContents would work via "su" or adb
+    shell running as root.
+
+    Devices running user builds don't have adb root, but may provide "su" which
+    can be used for accessing protected files.
+    """
+    return (self._GetProtectedFileCommandRunner() != None)
+
+  def _GetProtectedFileCommandRunner(self):
+    """Finds the best method to access protected files on the device.
+
+    Returns:
+      1. None when privileged files cannot be accessed on the device.
+      2. Otherwise: A function taking a single parameter: a string with command
+         line arguments. Running that function executes the command with
+         the appropriate method.
+    """
+    if self._protected_file_access_method_initialized:
+      return self._privileged_command_runner
+
+    self._privileged_command_runner = None
+    self._protected_file_access_method_initialized = True
+
+    for cmd in [self.RunShellCommand, self.RunShellCommandWithSU]:
+      # Get contents of the auxv vector for the init(8) process from a small
+      # binary file that always exists on linux and is always read-protected.
+      contents = cmd('cat /proc/1/auxv')
+      # The leading 4 or 8-bytes of auxv vector is a_type. There are not many
+      # reserved a_type values, hence byte 2 must always be '\0' for a realistic
+      # auxv. See /usr/include/elf.h.
+      if len(contents) > 0 and (contents[0][2] == '\0'):
+        self._privileged_command_runner = cmd
+        break
+    return self._privileged_command_runner
+
+  def GetProtectedFileContents(self, filename):
+    """Gets contents from the protected file specified by |filename|.
+
+    This is potentially less efficient than GetFileContents.
+    """
+    command = 'cat "%s" 2> /dev/null' % filename
+    command_runner = self._GetProtectedFileCommandRunner()
+    if command_runner:
+      return command_runner(command)
+    else:
+      logging.warning('Could not access protected file: %s' % filename)
+      return []
+
+  def SetProtectedFileContents(self, filename, contents):
+    """Writes |contents| to the protected file specified by |filename|.
+
+    This is less efficient than SetFileContents.
+    """
+    with DeviceTempFile(self) as temp_file:
+      with DeviceTempFile(self, suffix=".sh") as temp_script:
+        # Put the contents in a temporary file
+        self.SetFileContents(temp_file.name, contents)
+        # Create a script to copy the file contents to its final destination
+        self.SetFileContents(temp_script.name,
+                             'cat %s > %s' % (temp_file.name, filename))
+
+        command = 'sh %s' % temp_script.name
+        command_runner = self._GetProtectedFileCommandRunner()
+        if command_runner:
+          return command_runner(command)
+        else:
+          logging.warning(
+              'Could not set contents of protected file: %s' % filename)
+
+
+  def RemovePushedFiles(self):
+    """Removes all files pushed with PushIfNeeded() from the device."""
+    for p in self._pushed_files:
+      self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60)
+
+  def ListPathContents(self, path):
+    """Lists files in all subdirectories of |path|.
+
+    Args:
+      path: The path to list.
+
+    Returns:
+      A dict of {"name": (size, lastmod), ...}.
+    """
+    # Example output:
+    # /foo/bar:
+    # -rw-r----- user group   102 2011-05-12 12:29:54.131623387 +0100 baz.txt
+    re_file = re.compile('^-(?P<perms>[^\s]+)\s+'
+                         '(?P<user>[^\s]+)\s+'
+                         '(?P<group>[^\s]+)\s+'
+                         '(?P<size>[^\s]+)\s+'
+                         '(?P<date>[^\s]+)\s+'
+                         '(?P<time>[^\s]+)\s+'
+                         '(?P<filename>[^\s]+)$')
+    return _GetFilesFromRecursiveLsOutput(
+        path, self.RunShellCommand('ls -lR %s' % path), re_file,
+        self.GetUtcOffset())
+
+  def GetUtcOffset(self):
+    if not self._device_utc_offset:
+      self._device_utc_offset = self.RunShellCommand('date +%z')[0]
+    return self._device_utc_offset
+
+  def SetJavaAssertsEnabled(self, enable):
+    """Sets or removes the device java assertions property.
+
+    Args:
+      enable: If True the property will be set.
+
+    Returns:
+      True if the file was modified (reboot is required for it to take effect).
+    """
+    # First ensure the desired property is persisted.
+    temp_props_file = tempfile.NamedTemporaryFile()
+    properties = ''
+    if self._adb.Pull(LOCAL_PROPERTIES_PATH, temp_props_file.name):
+      with open(temp_props_file.name) as f:
+        properties = f.read()
+    re_search = re.compile(r'^\s*' + re.escape(JAVA_ASSERT_PROPERTY) +
+                           r'\s*=\s*all\s*$', re.MULTILINE)
+    if enable != bool(re.search(re_search, properties)):
+      re_replace = re.compile(r'^\s*' + re.escape(JAVA_ASSERT_PROPERTY) +
+                              r'\s*=\s*\w+\s*$', re.MULTILINE)
+      properties = re.sub(re_replace, '', properties)
+      if enable:
+        properties += '\n%s=all\n' % JAVA_ASSERT_PROPERTY
+
+      file(temp_props_file.name, 'w').write(properties)
+      self._adb.Push(temp_props_file.name, LOCAL_PROPERTIES_PATH)
+
+    # Next, check the current runtime value is what we need, and
+    # if not, set it and report that a reboot is required.
+    was_set = 'all' in self.system_properties[JAVA_ASSERT_PROPERTY]
+    if was_set == enable:
+      return False
+    self.system_properties[JAVA_ASSERT_PROPERTY] = enable and 'all' or ''
+    return True
+
+  def GetBuildId(self):
+    """Returns the build ID of the system (e.g. JRM79C)."""
+    build_id = self.system_properties['ro.build.id']
+    assert build_id
+    return build_id
+
+  def GetBuildType(self):
+    """Returns the build type of the system (e.g. eng)."""
+    build_type = self.system_properties['ro.build.type']
+    assert build_type
+    return build_type
+
+  def GetBuildProduct(self):
+    """Returns the build product of the device (e.g. maguro)."""
+    build_product = self.system_properties['ro.build.product']
+    assert build_product
+    return build_product
+
+  def GetProductName(self):
+    """Returns the product name of the device (e.g. takju)."""
+    name = self.system_properties['ro.product.name']
+    assert name
+    return name
+
+  def GetBuildFingerprint(self):
+    """Returns the build fingerprint of the device."""
+    build_fingerprint = self.system_properties['ro.build.fingerprint']
+    assert build_fingerprint
+    return build_fingerprint
+
+  def GetDescription(self):
+    """Returns the description of the system.
+
+    For example, "yakju-userdebug 4.1 JRN54F 364167 dev-keys".
+    """
+    description = self.system_properties['ro.build.description']
+    assert description
+    return description
+
+  def GetProductModel(self):
+    """Returns the name of the product model (e.g. "Galaxy Nexus") """
+    model = self.system_properties['ro.product.model']
+    assert model
+    return model
+
+  def GetWifiIP(self):
+    """Returns the wifi IP on the device."""
+    wifi_ip = self.system_properties['dhcp.wlan0.ipaddress']
+    # Do not assert here. Devices (e.g. emulators) may not have a WifiIP.
+    return wifi_ip
+
+  def GetSubscriberInfo(self):
+    """Returns the device subscriber info (e.g. GSM and device ID) as string."""
+    iphone_sub = self.RunShellCommand('dumpsys iphonesubinfo')
+    # Do not assert here. Devices (e.g. Nakasi on K) may not have iphonesubinfo.
+    return '\n'.join(iphone_sub)
+
+  def GetBatteryInfo(self):
+    """Returns a {str: str} dict of battery info (e.g. status, level, etc)."""
+    battery = self.RunShellCommand('dumpsys battery')
+    assert battery
+    battery_info = {}
+    for line in battery[1:]:
+      k, _, v = line.partition(': ')
+      battery_info[k.strip()] = v.strip()
+    return battery_info
+
+  def GetSetupWizardStatus(self):
+    """Returns the status of the device setup wizard (e.g. DISABLED)."""
+    status = self.system_properties['ro.setupwizard.mode']
+    # On some devices, the status is empty if not otherwise set. In such cases
+    # the caller should expect an empty string to be returned.
+    return status
+
+  def StartMonitoringLogcat(self, clear=True, logfile=None, filters=None):
+    """Starts monitoring the output of logcat, for use with WaitForLogMatch.
+
+    Args:
+      clear: If True the existing logcat output will be cleared, to avoiding
+             matching historical output lurking in the log.
+      filters: A list of logcat filters to be used.
+    """
+    if clear:
+      self.RunShellCommand('logcat -c')
+    args = []
+    if self._adb._target_arg:
+      args += shlex.split(self._adb._target_arg)
+    args += ['logcat', '-v', 'threadtime']
+    if filters:
+      args.extend(filters)
+    else:
+      args.append('*:v')
+
+    if logfile:
+      logfile = NewLineNormalizer(logfile)
+
+    # Spawn logcat and synchronize with it.
+    for _ in range(4):
+      self._logcat = pexpect.spawn(constants.GetAdbPath(), args, timeout=10,
+                                   logfile=logfile)
+      if not clear or self.SyncLogCat():
+        break
+      self._logcat.close(force=True)
+    else:
+      logging.critical('Error reading from logcat: ' + str(self._logcat.match))
+      sys.exit(1)
+
+  def SyncLogCat(self):
+    """Synchronize with logcat.
+
+    Synchronize with the monitored logcat so that WaitForLogMatch will only
+    consider new message that are received after this point in time.
+
+    Returns:
+      True if the synchronization succeeded.
+    """
+    assert self._logcat
+    tag = 'logcat_sync_%s' % time.time()
+    self.RunShellCommand('log ' + tag)
+    return self._logcat.expect([tag, pexpect.EOF, pexpect.TIMEOUT]) == 0
+
+  def GetMonitoredLogCat(self):
+    """Returns an "adb logcat" command as created by pexpected.spawn."""
+    if not self._logcat:
+      self.StartMonitoringLogcat(clear=False)
+    return self._logcat
+
+  def WaitForLogMatch(self, success_re, error_re, clear=False, timeout=10):
+    """Blocks until a matching line is logged or a timeout occurs.
+
+    Args:
+      success_re: A compiled re to search each line for.
+      error_re: A compiled re which, if found, terminates the search for
+          |success_re|. If None is given, no error condition will be detected.
+      clear: If True the existing logcat output will be cleared, defaults to
+          false.
+      timeout: Timeout in seconds to wait for a log match.
+
+    Raises:
+      pexpect.TIMEOUT after |timeout| seconds without a match for |success_re|
+      or |error_re|.
+
+    Returns:
+      The re match object if |success_re| is matched first or None if |error_re|
+      is matched first.
+    """
+    logging.info('<<< Waiting for logcat:' + str(success_re.pattern))
+    t0 = time.time()
+    while True:
+      if not self._logcat:
+        self.StartMonitoringLogcat(clear)
+      try:
+        while True:
+          # Note this will block for upto the timeout _per log line_, so we need
+          # to calculate the overall timeout remaining since t0.
+          time_remaining = t0 + timeout - time.time()
+          if time_remaining < 0:
+            raise pexpect.TIMEOUT(self._logcat)
+          self._logcat.expect(PEXPECT_LINE_RE, timeout=time_remaining)
+          line = self._logcat.match.group(1)
+          if error_re:
+            error_match = error_re.search(line)
+            if error_match:
+              return None
+          success_match = success_re.search(line)
+          if success_match:
+            return success_match
+          logging.info('<<< Skipped Logcat Line:' + str(line))
+      except pexpect.TIMEOUT:
+        raise pexpect.TIMEOUT(
+            'Timeout (%ds) exceeded waiting for pattern "%s" (tip: use -vv '
+            'to debug)' %
+            (timeout, success_re.pattern))
+      except pexpect.EOF:
+        # It seems that sometimes logcat can end unexpectedly. This seems
+        # to happen during Chrome startup after a reboot followed by a cache
+        # clean. I don't understand why this happens, but this code deals with
+        # getting EOF in logcat.
+        logging.critical('Found EOF in adb logcat. Restarting...')
+        # Rerun spawn with original arguments. Note that self._logcat.args[0] is
+        # the path of adb, so we don't want it in the arguments.
+        self._logcat = pexpect.spawn(constants.GetAdbPath(),
+                                     self._logcat.args[1:],
+                                     timeout=self._logcat.timeout,
+                                     logfile=self._logcat.logfile)
+
+  def StartRecordingLogcat(self, clear=True, filters=None):
+    """Starts recording logcat output to eventually be saved as a string.
+
+    This call should come before some series of tests are run, with either
+    StopRecordingLogcat or SearchLogcatRecord following the tests.
+
+    Args:
+      clear: True if existing log output should be cleared.
+      filters: A list of logcat filters to be used.
+    """
+    if not filters:
+      filters = ['*:v']
+    if clear:
+      self._adb.SendCommand('logcat -c')
+    logcat_command = 'adb %s logcat -v threadtime %s' % (self._adb._target_arg,
+                                                         ' '.join(filters))
+    self._logcat_tmpoutfile = tempfile.NamedTemporaryFile(bufsize=0)
+    self.logcat_process = subprocess.Popen(logcat_command, shell=True,
+                                           stdout=self._logcat_tmpoutfile)
+
+  def GetCurrentRecordedLogcat(self):
+    """Return the current content of the logcat being recorded.
+       Call this after StartRecordingLogcat() and before StopRecordingLogcat().
+       This can be useful to perform timed polling/parsing.
+    Returns:
+       Current logcat output as a single string, or None if
+       StopRecordingLogcat() was already called.
+    """
+    if not self._logcat_tmpoutfile:
+      return None
+
+    with open(self._logcat_tmpoutfile.name) as f:
+      return f.read()
+
+  def StopRecordingLogcat(self):
+    """Stops an existing logcat recording subprocess and returns output.
+
+    Returns:
+      The logcat output as a string or an empty string if logcat was not
+      being recorded at the time.
+    """
+    if not self.logcat_process:
+      return ''
+    # Cannot evaluate directly as 0 is a possible value.
+    # Better to read the self.logcat_process.stdout before killing it,
+    # Otherwise the communicate may return incomplete output due to pipe break.
+    if self.logcat_process.poll() is None:
+      self.logcat_process.kill()
+    self.logcat_process.wait()
+    self.logcat_process = None
+    self._logcat_tmpoutfile.seek(0)
+    output = self._logcat_tmpoutfile.read()
+    self._logcat_tmpoutfile.close()
+    self._logcat_tmpoutfile = None
+    return output
+
+  @staticmethod
+  def SearchLogcatRecord(record, message, thread_id=None, proc_id=None,
+                         log_level=None, component=None):
+    """Searches the specified logcat output and returns results.
+
+    This method searches through the logcat output specified by record for a
+    certain message, narrowing results by matching them against any other
+    specified criteria.  It returns all matching lines as described below.
+
+    Args:
+      record: A string generated by Start/StopRecordingLogcat to search.
+      message: An output string to search for.
+      thread_id: The thread id that is the origin of the message.
+      proc_id: The process that is the origin of the message.
+      log_level: The log level of the message.
+      component: The name of the component that would create the message.
+
+    Returns:
+      A list of dictionaries represeting matching entries, each containing keys
+      thread_id, proc_id, log_level, component, and message.
+    """
+    if thread_id:
+      thread_id = str(thread_id)
+    if proc_id:
+      proc_id = str(proc_id)
+    results = []
+    reg = re.compile('(\d+)\s+(\d+)\s+([A-Z])\s+([A-Za-z]+)\s*:(.*)$',
+                     re.MULTILINE)
+    log_list = reg.findall(record)
+    for (tid, pid, log_lev, comp, msg) in log_list:
+      if ((not thread_id or thread_id == tid) and
+          (not proc_id or proc_id == pid) and
+          (not log_level or log_level == log_lev) and
+          (not component or component == comp) and msg.find(message) > -1):
+        match = dict({'thread_id': tid, 'proc_id': pid,
+                      'log_level': log_lev, 'component': comp,
+                      'message': msg})
+        results.append(match)
+    return results
+
+  def ExtractPid(self, process_name):
+    """Extracts Process Ids for a given process name from Android Shell.
+
+    Args:
+      process_name: name of the process on the device.
+
+    Returns:
+      List of all the process ids (as strings) that match the given name.
+      If the name of a process exactly matches the given name, the pid of
+      that process will be inserted to the front of the pid list.
+    """
+    pids = []
+    for line in self.RunShellCommand('ps', log_result=False):
+      data = line.split()
+      try:
+        if process_name in data[-1]:  # name is in the last column
+          if process_name == data[-1]:
+            pids.insert(0, data[1])  # PID is in the second column
+          else:
+            pids.append(data[1])
+      except IndexError:
+        pass
+    return pids
+
+  def GetIoStats(self):
+    """Gets cumulative disk IO stats since boot (for all processes).
+
+    Returns:
+      Dict of {num_reads, num_writes, read_ms, write_ms} or None if there
+      was an error.
+    """
+    IoStats = collections.namedtuple(
+        'IoStats',
+        ['device',
+         'num_reads_issued',
+         'num_reads_merged',
+         'num_sectors_read',
+         'ms_spent_reading',
+         'num_writes_completed',
+         'num_writes_merged',
+         'num_sectors_written',
+         'ms_spent_writing',
+         'num_ios_in_progress',
+         'ms_spent_doing_io',
+         'ms_spent_doing_io_weighted',
+        ])
+
+    for line in self.GetFileContents('/proc/diskstats', log_result=False):
+      fields = line.split()
+      stats = IoStats._make([fields[2]] + [int(f) for f in fields[3:]])
+      if stats.device == 'mmcblk0':
+        return {
+            'num_reads': stats.num_reads_issued,
+            'num_writes': stats.num_writes_completed,
+            'read_ms': stats.ms_spent_reading,
+            'write_ms': stats.ms_spent_writing,
+        }
+    logging.warning('Could not find disk IO stats.')
+    return None
+
+  def GetMemoryUsageForPid(self, pid):
+    """Returns the memory usage for given pid.
+
+    Args:
+      pid: The pid number of the specific process running on device.
+
+    Returns:
+      Dict of {metric:usage_kb}, for the process which has specified pid.
+      The metric keys which may be included are: Size, Rss, Pss, Shared_Clean,
+      Shared_Dirty, Private_Clean, Private_Dirty, VmHWM.
+    """
+    showmap = self.RunShellCommand('showmap %d' % pid)
+    if not showmap or not showmap[-1].endswith('TOTAL'):
+      logging.warning('Invalid output for showmap %s', str(showmap))
+      return {}
+    items = showmap[-1].split()
+    if len(items) != 9:
+      logging.warning('Invalid TOTAL for showmap %s', str(items))
+      return {}
+    usage_dict = collections.defaultdict(int)
+    usage_dict.update({
+        'Size': int(items[0].strip()),
+        'Rss': int(items[1].strip()),
+        'Pss': int(items[2].strip()),
+        'Shared_Clean': int(items[3].strip()),
+        'Shared_Dirty': int(items[4].strip()),
+        'Private_Clean': int(items[5].strip()),
+        'Private_Dirty': int(items[6].strip()),
+    })
+    peak_value_kb = 0
+    for line in self.GetProtectedFileContents('/proc/%s/status' % pid):
+      if not line.startswith('VmHWM:'):  # Format: 'VmHWM: +[0-9]+ kB'
+        continue
+      peak_value_kb = int(line.split(':')[1].strip().split(' ')[0])
+      break
+    usage_dict['VmHWM'] = peak_value_kb
+    if not peak_value_kb:
+      logging.warning('Could not find memory peak value for pid ' + str(pid))
+
+    return usage_dict
+
+  def ProcessesUsingDevicePort(self, device_port):
+    """Lists processes using the specified device port on loopback interface.
+
+    Args:
+      device_port: Port on device we want to check.
+
+    Returns:
+      A list of (pid, process_name) tuples using the specified port.
+    """
+    tcp_results = self.RunShellCommand('cat /proc/net/tcp', log_result=False)
+    tcp_address = '0100007F:%04X' % device_port
+    pids = []
+    for single_connect in tcp_results:
+      connect_results = single_connect.split()
+      # Column 1 is the TCP port, and Column 9 is the inode of the socket
+      if connect_results[1] == tcp_address:
+        socket_inode = connect_results[9]
+        socket_name = 'socket:[%s]' % socket_inode
+        lsof_results = self.RunShellCommand('lsof', log_result=False)
+        for single_process in lsof_results:
+          process_results = single_process.split()
+          # Ignore the line if it has less than nine columns in it, which may
+          # be the case when a process stops while lsof is executing.
+          if len(process_results) <= 8:
+            continue
+          # Column 0 is the executable name
+          # Column 1 is the pid
+          # Column 8 is the Inode in use
+          if process_results[8] == socket_name:
+            pids.append((int(process_results[1]), process_results[0]))
+        break
+    logging.info('PidsUsingDevicePort: %s', pids)
+    return pids
+
+  def FileExistsOnDevice(self, file_name):
+    """Checks whether the given file exists on the device.
+
+    Args:
+      file_name: Full path of file to check.
+
+    Returns:
+      True if the file exists, False otherwise.
+    """
+    assert '"' not in file_name, 'file_name cannot contain double quotes'
+    try:
+      status = self._adb.SendShellCommand(
+          '\'test -e "%s"; echo $?\'' % (file_name))
+      if 'test: not found' not in status:
+        return int(status) == 0
+
+      status = self._adb.SendShellCommand(
+          '\'ls "%s" >/dev/null 2>&1; echo $?\'' % (file_name))
+      return int(status) == 0
+    except ValueError:
+      if IsDeviceAttached(self._device):
+        raise errors.DeviceUnresponsiveError('Device may be offline.')
+
+      return False
+
+  def IsFileWritableOnDevice(self, file_name):
+    """Checks whether the given file (or directory) is writable on the device.
+
+    Args:
+      file_name: Full path of file/directory to check.
+
+    Returns:
+      True if writable, False otherwise.
+    """
+    assert '"' not in file_name, 'file_name cannot contain double quotes'
+    try:
+      status = self._adb.SendShellCommand(
+          '\'test -w "%s"; echo $?\'' % (file_name))
+      if 'test: not found' not in status:
+        return int(status) == 0
+      raise errors.AbortError('"test" binary not found. OS too old.')
+
+    except ValueError:
+      if IsDeviceAttached(self._device):
+        raise errors.DeviceUnresponsiveError('Device may be offline.')
+
+      return False
+
+  @staticmethod
+  def GetTimestamp():
+    return time.strftime('%Y-%m-%d-%H%M%S', time.localtime())
+
+  @staticmethod
+  def EnsureHostDirectory(host_file):
+    host_dir = os.path.dirname(os.path.abspath(host_file))
+    if not os.path.exists(host_dir):
+      os.makedirs(host_dir)
+
+  def TakeScreenshot(self, host_file=None):
+    """Saves a screenshot image to |host_file| on the host.
+
+    Args:
+      host_file: Absolute path to the image file to store on the host or None to
+                 use an autogenerated file name.
+
+    Returns:
+      Resulting host file name of the screenshot.
+    """
+    host_file = os.path.abspath(host_file or
+                                'screenshot-%s.png' % self.GetTimestamp())
+    self.EnsureHostDirectory(host_file)
+    device_file = '%s/screenshot.png' % self.GetExternalStorage()
+    self.RunShellCommand(
+        '/system/bin/screencap -p %s' % device_file)
+    self.PullFileFromDevice(device_file, host_file)
+    self.RunShellCommand('rm -f "%s"' % device_file)
+    return host_file
+
+  def PullFileFromDevice(self, device_file, host_file):
+    """Download |device_file| on the device from to |host_file| on the host.
+
+    Args:
+      device_file: Absolute path to the file to retrieve from the device.
+      host_file: Absolute path to the file to store on the host.
+    """
+    if not self._adb.Pull(device_file, host_file):
+      raise device_errors.AdbCommandFailedError(
+          ['pull', device_file, host_file], 'Failed to pull file from device.')
+    assert os.path.exists(host_file)
+
+  def SetUtilWrapper(self, util_wrapper):
+    """Sets a wrapper prefix to be used when running a locally-built
+    binary on the device (ex.: md5sum_bin).
+    """
+    self._util_wrapper = util_wrapper
+
+  def RunUIAutomatorTest(self, test, test_package, timeout):
+    """Runs a single uiautomator test.
+
+    Args:
+      test: Test class/method.
+      test_package: Name of the test jar.
+      timeout: Timeout time in seconds.
+
+    Returns:
+      An instance of am_instrument_parser.TestResult object.
+    """
+    cmd = 'uiautomator runtest %s -e class %s' % (test_package, test)
+    self._LogShell(cmd)
+    output = self._adb.SendShellCommand(cmd, timeout_time=timeout)
+    # uiautomator doesn't fully conform to the instrumenation test runner
+    # convention and doesn't terminate with INSTRUMENTATION_CODE.
+    # Just assume the first result is valid.
+    (test_results, _) = am_instrument_parser.ParseAmInstrumentOutput(output)
+    if not test_results:
+      raise errors.InstrumentationError(
+          'no test results... device setup correctly?')
+    return test_results[0]
+
+  def DismissCrashDialogIfNeeded(self):
+    """Dismiss the error/ANR dialog if present.
+
+    Returns: Name of the crashed package if a dialog is focused,
+             None otherwise.
+    """
+    re_focus = re.compile(
+        r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}')
+
+    def _FindFocusedWindow():
+      match = None
+      for line in self.RunShellCommand('dumpsys window windows'):
+        match = re.match(re_focus, line)
+        if match:
+          break
+      return match
+
+    match = _FindFocusedWindow()
+    if not match:
+      return
+    package = match.group(2)
+    logging.warning('Trying to dismiss %s dialog for %s' % match.groups())
+    self.SendKeyEvent(KEYCODE_DPAD_RIGHT)
+    self.SendKeyEvent(KEYCODE_DPAD_RIGHT)
+    self.SendKeyEvent(KEYCODE_ENTER)
+    match = _FindFocusedWindow()
+    if match:
+      logging.error('Still showing a %s dialog for %s' % match.groups())
+    return package
+
+  def EfficientDeviceDirectoryCopy(self, source, dest):
+    """ Copy a directory efficiently on the device
+
+    Uses a shell script running on the target to copy new and changed files the
+    source directory to the destination directory and remove added files. This
+    is in some cases much faster than cp -r.
+
+    Args:
+      source: absolute path of source directory
+      dest: absolute path of destination directory
+    """
+    logging.info('In EfficientDeviceDirectoryCopy %s %s', source, dest)
+    with DeviceTempFile(self, suffix=".sh") as temp_script_file:
+      host_script_path = os.path.join(constants.DIR_SOURCE_ROOT,
+                                      'build',
+                                      'android',
+                                      'pylib',
+                                      'efficient_android_directory_copy.sh')
+      self._adb.Push(host_script_path, temp_script_file.name)
+      out = self.RunShellCommand(
+          'sh %s %s %s' % (temp_script_file.name, source, dest),
+          timeout_time=120)
+      if self._device:
+        device_repr = self._device[-4:]
+      else:
+        device_repr = '????'
+      for line in out:
+        logging.info('[%s]> %s', device_repr, line)
+
+  def _GetControlUsbChargingCommand(self):
+    if self._control_usb_charging_command['cached']:
+      return self._control_usb_charging_command['command']
+    self._control_usb_charging_command['cached'] = True
+    if not self.IsRootEnabled():
+      return None
+    for command in CONTROL_USB_CHARGING_COMMANDS:
+      # Assert command is valid.
+      assert 'disable_command' in command
+      assert 'enable_command' in command
+      assert 'witness_file' in command
+      witness_file = command['witness_file']
+      if self.FileExistsOnDevice(witness_file):
+        self._control_usb_charging_command['command'] = command
+        return command
+    return None
+
+  def CanControlUsbCharging(self):
+    return self._GetControlUsbChargingCommand() is not None
+
+  def DisableUsbCharging(self, timeout=10):
+    command = self._GetControlUsbChargingCommand()
+    if not command:
+      raise Exception('Unable to act on usb charging.')
+    disable_command = command['disable_command']
+    t0 = time.time()
+    # Do not loop directly on self.IsDeviceCharging to cut the number of calls
+    # to the device.
+    while True:
+      if t0 + timeout - time.time() < 0:
+        raise pexpect.TIMEOUT('Unable to disable USB charging in time: %s' % (
+            self.GetBatteryInfo()))
+      self.RunShellCommand(disable_command)
+      if not self.IsDeviceCharging():
+        break
+
+  def EnableUsbCharging(self, timeout=10):
+    command = self._GetControlUsbChargingCommand()
+    if not command:
+      raise Exception('Unable to act on usb charging.')
+    disable_command = command['enable_command']
+    t0 = time.time()
+    # Do not loop directly on self.IsDeviceCharging to cut the number of calls
+    # to the device.
+    while True:
+      if t0 + timeout - time.time() < 0:
+        raise pexpect.TIMEOUT('Unable to enable USB charging in time.')
+      self.RunShellCommand(disable_command)
+      if self.IsDeviceCharging():
+        break
+
+  def IsDeviceCharging(self):
+    for line in self.RunShellCommand('dumpsys battery'):
+      if 'powered: ' in line:
+        if line.split('powered: ')[1] == 'true':
+          return True
+
+
+class NewLineNormalizer(object):
+  """A file-like object to normalize EOLs to '\n'.
+
+  Pexpect runs adb within a pseudo-tty device (see
+  http://www.noah.org/wiki/pexpect), so any '\n' printed by adb is written
+  as '\r\n' to the logfile. Since adb already uses '\r\n' to terminate
+  lines, the log ends up having '\r\r\n' at the end of each line. This
+  filter replaces the above with a single '\n' in the data stream.
+  """
+  def __init__(self, output):
+    self._output = output
+
+  def write(self, data):
+    data = data.replace('\r\r\n', '\n')
+    self._output.write(data)
+
+  def flush(self):
+    self._output.flush()
diff --git a/build/android/pylib/android_commands_unittest.py b/build/android/pylib/android_commands_unittest.py
new file mode 100644
index 0000000..21c34f9
--- /dev/null
+++ b/build/android/pylib/android_commands_unittest.py
@@ -0,0 +1,191 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import sys
+import unittest
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+
+from pylib import android_commands
+
+# pylint: disable=W0212,W0702
+
+class TestDeviceTempFile(unittest.TestCase):
+  def setUp(self):
+    if not os.getenv('BUILDTYPE'):
+      os.environ['BUILDTYPE'] = 'Debug'
+
+    devices = android_commands.GetAttachedDevices()
+    self.assertGreater(len(devices), 0, 'No device attached!')
+    self.ac = android_commands.AndroidCommands(device=devices[0])
+
+  def testTempFileDeleted(self):
+    """Tests that DeviceTempFile deletes files when closed."""
+    temp_file = android_commands.DeviceTempFile(self.ac)
+    self.assertFalse(self.ac.FileExistsOnDevice(temp_file.name))
+    self.ac.SetFileContents(temp_file.name, "contents")
+    self.assertTrue(self.ac.FileExistsOnDevice(temp_file.name))
+    temp_file.close()
+    self.assertFalse(self.ac.FileExistsOnDevice(temp_file.name))
+
+    with android_commands.DeviceTempFile(self.ac) as with_temp_file:
+      self.assertFalse(self.ac.FileExistsOnDevice(with_temp_file.name))
+      self.ac.SetFileContents(with_temp_file.name, "contents")
+      self.assertTrue(self.ac.FileExistsOnDevice(with_temp_file.name))
+
+    self.assertFalse(self.ac.FileExistsOnDevice(with_temp_file.name))
+
+  def testTempFileNotWritten(self):
+    """Tests that device temp files work successfully even if not written to."""
+    temp_file = android_commands.DeviceTempFile(self.ac)
+    temp_file.close()
+    self.assertFalse(self.ac.FileExistsOnDevice(temp_file.name))
+
+    with android_commands.DeviceTempFile(self.ac) as with_temp_file:
+      pass
+    self.assertFalse(self.ac.FileExistsOnDevice(with_temp_file.name))
+
+  def testNaming(self):
+    """Tests that returned filenames are as requested."""
+    temp_file = android_commands.DeviceTempFile(self.ac, prefix="cat")
+    self.assertTrue(os.path.basename(temp_file.name).startswith("cat"))
+
+    temp_file = android_commands.DeviceTempFile(self.ac, suffix="dog")
+    self.assertTrue(temp_file.name.endswith("dog"))
+
+    temp_file = android_commands.DeviceTempFile(
+        self.ac, prefix="cat", suffix="dog")
+    self.assertTrue(os.path.basename(temp_file.name).startswith("cat"))
+    self.assertTrue(temp_file.name.endswith("dog"))
+
+
+class TestGetFilesChanged(unittest.TestCase):
+
+  def setUp(self):
+    if not os.getenv('BUILDTYPE'):
+      os.environ['BUILDTYPE'] = 'Debug'
+
+    devices = android_commands.GetAttachedDevices()
+    self.assertGreater(len(devices), 0, 'No device attached!')
+    self.ac = android_commands.AndroidCommands(device=devices[0])
+    self.host_data_dir = os.path.realpath('test_push_data')
+    self.device_data_dir = '%s/test_push_data' % (
+        self.ac.RunShellCommand('realpath %s' %
+            self.ac.GetExternalStorage())[0])
+
+    os.mkdir(self.host_data_dir)
+    for i in xrange(1, 10):
+      with open('%s/%d.txt' % (self.host_data_dir, i), 'w') as f:
+        f.write('file #%d' % i)
+
+    self.ac.RunShellCommand('mkdir %s' % self.device_data_dir)
+
+  def testGetFilesChangedAllNeeded(self):
+    """ Tests GetFilesChanged when none of the files are on the device.
+    """
+    expected = [('%s/%d.txt' % (self.host_data_dir, i),
+                 '%s/%d.txt' % (self.device_data_dir, i))
+                for i in xrange(1, 10)]
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def testGetFilesChangedSomeIdentical(self):
+    """ Tests GetFilesChanged when some of the files are on the device.
+    """
+    for i in xrange(1, 5):
+      self.ac._adb.Push('%s/%d.txt' % (self.host_data_dir, i),
+                        self.device_data_dir)
+    expected = [('%s/%d.txt' % (self.host_data_dir, i),
+                 '%s/%d.txt' % (self.device_data_dir, i))
+                for i in xrange(5, 10)]
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def testGetFilesChangedAllIdentical(self):
+    """ Tests GetFilesChanged when all of the files are on the device.
+    """
+    for i in xrange(1, 10):
+      self.ac._adb.Push('%s/%d.txt' % (self.host_data_dir, i),
+                        self.device_data_dir)
+    expected = []
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def testGetFilesChangedRename(self):
+    """ Tests GetFilesChanged when one of the files has been renamed.
+
+        This tests both with and without the ignore_filenames flag set.
+    """
+    for i in xrange(5, 10):
+      self.ac._adb.Push('%s/%d.txt' % (self.host_data_dir, i),
+                        self.device_data_dir)
+    os.rename('%s/5.txt' % (self.host_data_dir),
+              '%s/99.txt' % (self.host_data_dir))
+
+    expected = [('%s/%d.txt' % (self.host_data_dir, i),
+                 '%s/%d.txt' % (self.device_data_dir, i))
+                for i in xrange(1, 5)]
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir,
+                                     ignore_filenames=True)
+    self.assertSequenceEqual(expected, actual)
+
+    expected.append(('%s/99.txt' % self.host_data_dir,
+                     '%s/99.txt' % self.device_data_dir))
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def testGetFilesChangedCopy(self):
+    """ Tests GetFilesChanged when one of the files has been copied.
+
+        This tests both with and without the ignore_filenames flag set.
+    """
+    for i in xrange(5, 10):
+      self.ac._adb.Push('%s/%d.txt' % (self.host_data_dir, i),
+                        self.device_data_dir)
+    shutil.copy('%s/5.txt' % self.host_data_dir,
+                '%s/99.txt' % self.host_data_dir)
+
+    expected = [('%s/%d.txt' % (self.host_data_dir, i),
+                 '%s/%d.txt' % (self.device_data_dir, i))
+                for i in xrange(1, 5)]
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir,
+                                     ignore_filenames=True)
+    self.assertSequenceEqual(expected, actual)
+
+    expected.append(('%s/99.txt' % self.host_data_dir,
+                     '%s/99.txt' % self.device_data_dir))
+    actual = self.ac.GetFilesChanged(self.host_data_dir, self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def testGetFilesChangedIndividual(self):
+    """ Tests GetFilesChanged when provided one file.
+    """
+    expected = [('%s/1.txt' % self.host_data_dir,
+                 '%s/1.txt' % self.device_data_dir)]
+    actual = self.ac.GetFilesChanged('%s/1.txt' % self.host_data_dir,
+                                     '%s/1.txt' % self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def testGetFilesChangedFileToDirectory(self):
+    """ Tests GetFilesChanged when provided a file from the host and a
+        directory on the device.
+    """
+    expected = [('%s/1.txt' % self.host_data_dir,
+                 '%s' % self.device_data_dir)]
+    actual = self.ac.GetFilesChanged('%s/1.txt' % self.host_data_dir,
+                                     '%s' % self.device_data_dir)
+    self.assertSequenceEqual(expected, actual)
+
+  def tearDown(self):
+    try:
+      shutil.rmtree(self.host_data_dir)
+      self.ac.RunShellCommand('rm -rf %s' % self.device_data_dir)
+    except:
+      pass
+
+if __name__ == '__main__':
+  unittest.main()
+
diff --git a/build/android/pylib/base/__init__.py b/build/android/pylib/base/__init__.py
new file mode 100644
index 0000000..727e987
--- /dev/null
+++ b/build/android/pylib/base/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/base/base_setup.py b/build/android/pylib/base/base_setup.py
new file mode 100644
index 0000000..c276822
--- /dev/null
+++ b/build/android/pylib/base/base_setup.py
@@ -0,0 +1,62 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Base script for doing test setup."""
+
+import logging
+import os
+
+from pylib import constants
+from pylib import valgrind_tools
+from pylib.utils import isolator
+
+def GenerateDepsDirUsingIsolate(suite_name, isolate_file_path,
+                                isolate_file_paths, deps_exclusion_list):
+  """Generate the dependency dir for the test suite using isolate.
+
+  Args:
+    suite_name: Name of the test suite (e.g. base_unittests).
+    isolate_file_path: .isolate file path to use. If there is a default .isolate
+                       file path for the suite_name, this will override it.
+    isolate_file_paths: Dictionary with the default .isolate file paths for
+                        the test suites.
+    deps_exclusion_list: A list of files that are listed as dependencies in the
+                         .isolate files but should not be pushed to the device.
+  """
+  if isolate_file_path:
+    if os.path.isabs(isolate_file_path):
+      isolate_abs_path = isolate_file_path
+    else:
+      isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT,
+                                      isolate_file_path)
+  else:
+    isolate_rel_path = isolate_file_paths.get(suite_name)
+    if not isolate_rel_path:
+      logging.info('Did not find an isolate file for the test suite.')
+      return
+    isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path)
+
+  isolated_abs_path = os.path.join(
+      constants.GetOutDirectory(), '%s.isolated' % suite_name)
+  assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path
+
+  i = isolator.Isolator(constants.ISOLATE_DEPS_DIR)
+  i.Clear()
+  i.Remap(isolate_abs_path, isolated_abs_path)
+  # We're relying on the fact that timestamps are preserved
+  # by the remap command (hardlinked). Otherwise, all the data
+  # will be pushed to the device once we move to using time diff
+  # instead of md5sum. Perform a sanity check here.
+  i.VerifyHardlinks()
+  i.PurgeExcluded(deps_exclusion_list)
+  i.MoveOutputDeps()
+
+
+def PushDataDeps(device, device_dir, test_options):
+  valgrind_tools.PushFilesForTool(test_options.tool, device)
+  if os.path.exists(constants.ISOLATE_DEPS_DIR):
+    device.PushChangedFiles([
+        (os.path.join(constants.ISOLATE_DEPS_DIR, p),
+         '%s/%s' % (device_dir, p))
+        for p in os.listdir(constants.ISOLATE_DEPS_DIR)])
diff --git a/build/android/pylib/base/base_test_result.py b/build/android/pylib/base/base_test_result.py
new file mode 100644
index 0000000..58200f6
--- /dev/null
+++ b/build/android/pylib/base/base_test_result.py
@@ -0,0 +1,216 @@
+# 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.
+
+"""Module containing base test results classes."""
+
+class ResultType(object):
+  """Class enumerating test types."""
+  PASS = 'PASS'
+  SKIP = 'SKIP'
+  FAIL = 'FAIL'
+  CRASH = 'CRASH'
+  TIMEOUT = 'TIMEOUT'
+  UNKNOWN = 'UNKNOWN'
+
+  @staticmethod
+  def GetTypes():
+    """Get a list of all test types."""
+    return [ResultType.PASS, ResultType.SKIP, ResultType.FAIL,
+            ResultType.CRASH, ResultType.TIMEOUT, ResultType.UNKNOWN]
+
+
+class BaseTestResult(object):
+  """Base class for a single test result."""
+
+  def __init__(self, name, test_type, duration=0, log=''):
+    """Construct a BaseTestResult.
+
+    Args:
+      name: Name of the test which defines uniqueness.
+      test_type: Type of the test result as defined in ResultType.
+      duration: Time it took for the test to run in milliseconds.
+      log: An optional string listing any errors.
+    """
+    assert name
+    assert test_type in ResultType.GetTypes()
+    self._name = name
+    self._test_type = test_type
+    self._duration = duration
+    self._log = log
+
+  def __str__(self):
+    return self._name
+
+  def __repr__(self):
+    return self._name
+
+  def __cmp__(self, other):
+    # pylint: disable=W0212
+    return cmp(self._name, other._name)
+
+  def __hash__(self):
+    return hash(self._name)
+
+  def SetName(self, name):
+    """Set the test name.
+
+    Because we're putting this into a set, this should only be used if moving
+    this test result into another set.
+    """
+    self._name = name
+
+  def GetName(self):
+    """Get the test name."""
+    return self._name
+
+  def SetType(self, test_type):
+    """Set the test result type."""
+    assert test_type in ResultType.GetTypes()
+    self._test_type = test_type
+
+  def GetType(self):
+    """Get the test result type."""
+    return self._test_type
+
+  def GetDuration(self):
+    """Get the test duration."""
+    return self._duration
+
+  def SetLog(self, log):
+    """Set the test log."""
+    self._log = log
+
+  def GetLog(self):
+    """Get the test log."""
+    return self._log
+
+
+class TestRunResults(object):
+  """Set of results for a test run."""
+
+  def __init__(self):
+    self._results = set()
+
+  def GetLogs(self):
+    """Get the string representation of all test logs."""
+    s = []
+    for test_type in ResultType.GetTypes():
+      if test_type != ResultType.PASS:
+        for t in sorted(self._GetType(test_type)):
+          log = t.GetLog()
+          if log:
+            s.append('[%s] %s:' % (test_type, t))
+            s.append(log)
+    return '\n'.join(s)
+
+  def GetGtestForm(self):
+    """Get the gtest string representation of this object."""
+    s = []
+    plural = lambda n, s, p: '%d %s' % (n, p if n != 1 else s)
+    tests = lambda n: plural(n, 'test', 'tests')
+
+    s.append('[==========] %s ran.' % (tests(len(self.GetAll()))))
+    s.append('[  PASSED  ] %s.' % (tests(len(self.GetPass()))))
+
+    skipped = self.GetSkip()
+    if skipped:
+      s.append('[  SKIPPED ] Skipped %s, listed below:' % tests(len(skipped)))
+      for t in sorted(skipped):
+        s.append('[  SKIPPED ] %s' % str(t))
+
+    all_failures = self.GetFail().union(self.GetCrash(), self.GetTimeout(),
+        self.GetUnknown())
+    if all_failures:
+      s.append('[  FAILED  ] %s, listed below:' % tests(len(all_failures)))
+      for t in sorted(self.GetFail()):
+        s.append('[  FAILED  ] %s' % str(t))
+      for t in sorted(self.GetCrash()):
+        s.append('[  FAILED  ] %s (CRASHED)' % str(t))
+      for t in sorted(self.GetTimeout()):
+        s.append('[  FAILED  ] %s (TIMEOUT)' % str(t))
+      for t in sorted(self.GetUnknown()):
+        s.append('[  FAILED  ] %s (UNKNOWN)' % str(t))
+      s.append('')
+      s.append(plural(len(all_failures), 'FAILED TEST', 'FAILED TESTS'))
+    return '\n'.join(s)
+
+  def GetShortForm(self):
+    """Get the short string representation of this object."""
+    s = []
+    s.append('ALL: %d' % len(self._results))
+    for test_type in ResultType.GetTypes():
+      s.append('%s: %d' % (test_type, len(self._GetType(test_type))))
+    return ''.join([x.ljust(15) for x in s])
+
+  def __str__(self):
+    return self.GetLongForm()
+
+  def AddResult(self, result):
+    """Add |result| to the set.
+
+    Args:
+      result: An instance of BaseTestResult.
+    """
+    assert isinstance(result, BaseTestResult)
+    self._results.add(result)
+
+  def AddResults(self, results):
+    """Add |results| to the set.
+
+    Args:
+      results: An iterable of BaseTestResult objects.
+    """
+    for t in results:
+      self.AddResult(t)
+
+  def AddTestRunResults(self, results):
+    """Add the set of test results from |results|.
+
+    Args:
+      results: An instance of TestRunResults.
+    """
+    assert isinstance(results, TestRunResults)
+    # pylint: disable=W0212
+    self._results.update(results._results)
+
+  def GetAll(self):
+    """Get the set of all test results."""
+    return self._results.copy()
+
+  def _GetType(self, test_type):
+    """Get the set of test results with the given test type."""
+    return set(t for t in self._results if t.GetType() == test_type)
+
+  def GetPass(self):
+    """Get the set of all passed test results."""
+    return self._GetType(ResultType.PASS)
+
+  def GetSkip(self):
+    """Get the set of all skipped test results."""
+    return self._GetType(ResultType.SKIP)
+
+  def GetFail(self):
+    """Get the set of all failed test results."""
+    return self._GetType(ResultType.FAIL)
+
+  def GetCrash(self):
+    """Get the set of all crashed test results."""
+    return self._GetType(ResultType.CRASH)
+
+  def GetTimeout(self):
+    """Get the set of all timed out test results."""
+    return self._GetType(ResultType.TIMEOUT)
+
+  def GetUnknown(self):
+    """Get the set of all unknown test results."""
+    return self._GetType(ResultType.UNKNOWN)
+
+  def GetNotPass(self):
+    """Get the set of all non-passed test results."""
+    return self.GetAll() - self.GetPass()
+
+  def DidRunPass(self):
+    """Return whether the test run was successful."""
+    return not self.GetNotPass() - self.GetSkip()
+
diff --git a/build/android/pylib/base/base_test_result_unittest.py b/build/android/pylib/base/base_test_result_unittest.py
new file mode 100644
index 0000000..6f0cba7
--- /dev/null
+++ b/build/android/pylib/base/base_test_result_unittest.py
@@ -0,0 +1,82 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for TestRunResults."""
+
+import unittest
+
+from pylib.base.base_test_result import BaseTestResult
+from pylib.base.base_test_result import TestRunResults
+from pylib.base.base_test_result import ResultType
+
+
+class TestTestRunResults(unittest.TestCase):
+  def setUp(self):
+    self.p1 = BaseTestResult('p1', ResultType.PASS, log='pass1')
+    other_p1 = BaseTestResult('p1', ResultType.PASS)
+    self.p2 = BaseTestResult('p2', ResultType.PASS)
+    self.f1 = BaseTestResult('f1', ResultType.FAIL, log='failure1')
+    self.c1 = BaseTestResult('c1', ResultType.CRASH, log='crash1')
+    self.u1 = BaseTestResult('u1', ResultType.UNKNOWN)
+    self.tr = TestRunResults()
+    self.tr.AddResult(self.p1)
+    self.tr.AddResult(other_p1)
+    self.tr.AddResult(self.p2)
+    self.tr.AddResults(set([self.f1, self.c1, self.u1]))
+
+  def testGetAll(self):
+    self.assertFalse(
+        self.tr.GetAll().symmetric_difference(
+            [self.p1, self.p2, self.f1, self.c1, self.u1]))
+
+  def testGetPass(self):
+    self.assertFalse(self.tr.GetPass().symmetric_difference(
+        [self.p1, self.p2]))
+
+  def testGetNotPass(self):
+    self.assertFalse(self.tr.GetNotPass().symmetric_difference(
+        [self.f1, self.c1, self.u1]))
+
+  def testGetAddTestRunResults(self):
+    tr2 = TestRunResults()
+    other_p1 = BaseTestResult('p1', ResultType.PASS)
+    f2 = BaseTestResult('f2', ResultType.FAIL)
+    tr2.AddResult(other_p1)
+    tr2.AddResult(f2)
+    tr2.AddTestRunResults(self.tr)
+    self.assertFalse(
+        tr2.GetAll().symmetric_difference(
+            [self.p1, self.p2, self.f1, self.c1, self.u1, f2]))
+
+  def testGetLogs(self):
+    log_print = ('[FAIL] f1:\n'
+                 'failure1\n'
+                 '[CRASH] c1:\n'
+                 'crash1')
+    self.assertEqual(self.tr.GetLogs(), log_print)
+
+  def testGetShortForm(self):
+    short_print = ('ALL: 5         PASS: 2        FAIL: 1        '
+                   'CRASH: 1       TIMEOUT: 0     UNKNOWN: 1     ')
+    self.assertEqual(self.tr.GetShortForm(), short_print)
+
+  def testGetGtestForm(self):
+    gtest_print = ('[==========] 5 tests ran.\n'
+                   '[  PASSED  ] 2 tests.\n'
+                   '[  FAILED  ] 3 tests, listed below:\n'
+                   '[  FAILED  ] f1\n'
+                   '[  FAILED  ] c1 (CRASHED)\n'
+                   '[  FAILED  ] u1 (UNKNOWN)\n'
+                   '\n'
+                   '3 FAILED TESTS')
+    self.assertEqual(gtest_print, self.tr.GetGtestForm())
+
+  def testRunPassed(self):
+    self.assertFalse(self.tr.DidRunPass())
+    tr2 = TestRunResults()
+    self.assertTrue(tr2.DidRunPass())
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
new file mode 100644
index 0000000..2a7fdd3
--- /dev/null
+++ b/build/android/pylib/base/base_test_runner.py
@@ -0,0 +1,138 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Base class for running tests on a single device."""
+
+# TODO(jbudorick) Deprecate and remove this class and all subclasses after
+# any relevant parts have been ported to the new environment + test instance
+# model.
+
+import logging
+
+from pylib import ports
+from pylib.device import device_utils
+from pylib.forwarder import Forwarder
+from pylib.valgrind_tools import CreateTool
+# TODO(frankf): Move this to pylib/utils
+import lighttpd_server
+
+
+# A file on device to store ports of net test server. The format of the file is
+# test-spawner-server-port:test-server-port
+NET_TEST_SERVER_PORT_INFO_FILE = 'net-test-server-ports'
+
+
+class BaseTestRunner(object):
+  """Base class for running tests on a single device."""
+
+  def __init__(self, device, tool):
+    """
+      Args:
+        device: An instance of DeviceUtils that the tests will run on.
+        tool: Name of the Valgrind tool.
+    """
+    assert isinstance(device, device_utils.DeviceUtils)
+    self.device = device
+    self.device_serial = self.device.adb.GetDeviceSerial()
+    self.tool = CreateTool(tool, self.device)
+    self._http_server = None
+    self._forwarder_device_port = 8000
+    self.forwarder_base_url = ('http://localhost:%d' %
+        self._forwarder_device_port)
+    # We will allocate port for test server spawner when calling method
+    # LaunchChromeTestServerSpawner and allocate port for test server when
+    # starting it in TestServerThread.
+    self.test_server_spawner_port = 0
+    self.test_server_port = 0
+
+  def _PushTestServerPortInfoToDevice(self):
+    """Pushes the latest port information to device."""
+    self.device.WriteFile(
+        self.device.GetExternalStoragePath() + '/' +
+            NET_TEST_SERVER_PORT_INFO_FILE,
+        '%d:%d' % (self.test_server_spawner_port, self.test_server_port))
+
+  def RunTest(self, test):
+    """Runs a test. Needs to be overridden.
+
+    Args:
+      test: A test to run.
+
+    Returns:
+      Tuple containing:
+        (base_test_result.TestRunResults, tests to rerun or None)
+    """
+    raise NotImplementedError
+
+  def InstallTestPackage(self):
+    """Installs the test package once before all tests are run."""
+    pass
+
+  def SetUp(self):
+    """Run once before all tests are run."""
+    self.InstallTestPackage()
+
+  def TearDown(self):
+    """Run once after all tests are run."""
+    self.ShutdownHelperToolsForTestSuite()
+
+  def LaunchTestHttpServer(self, document_root, port=None,
+                           extra_config_contents=None):
+    """Launches an HTTP server to serve HTTP tests.
+
+    Args:
+      document_root: Document root of the HTTP server.
+      port: port on which we want to the http server bind.
+      extra_config_contents: Extra config contents for the HTTP server.
+    """
+    self._http_server = lighttpd_server.LighttpdServer(
+        document_root, port=port, extra_config_contents=extra_config_contents)
+    if self._http_server.StartupHttpServer():
+      logging.info('http server started: http://localhost:%s',
+                   self._http_server.port)
+    else:
+      logging.critical('Failed to start http server')
+    self._ForwardPortsForHttpServer()
+    return (self._forwarder_device_port, self._http_server.port)
+
+  def _ForwardPorts(self, port_pairs):
+    """Forwards a port."""
+    Forwarder.Map(port_pairs, self.device, self.tool)
+
+  def _UnmapPorts(self, port_pairs):
+    """Unmap previously forwarded ports."""
+    for (device_port, _) in port_pairs:
+      Forwarder.UnmapDevicePort(device_port, self.device)
+
+  # Deprecated: Use ForwardPorts instead.
+  def StartForwarder(self, port_pairs):
+    """Starts TCP traffic forwarding for the given |port_pairs|.
+
+    Args:
+      host_port_pairs: A list of (device_port, local_port) tuples to forward.
+    """
+    self._ForwardPorts(port_pairs)
+
+  def _ForwardPortsForHttpServer(self):
+    """Starts a forwarder for the HTTP server.
+
+    The forwarder forwards HTTP requests and responses between host and device.
+    """
+    self._ForwardPorts([(self._forwarder_device_port, self._http_server.port)])
+
+  def _RestartHttpServerForwarderIfNecessary(self):
+    """Restarts the forwarder if it's not open."""
+    # Checks to see if the http server port is being used.  If not forwards the
+    # request.
+    # TODO(dtrainor): This is not always reliable because sometimes the port
+    # will be left open even after the forwarder has been killed.
+    if not ports.IsDevicePortUsed(self.device, self._forwarder_device_port):
+      self._ForwardPortsForHttpServer()
+
+  def ShutdownHelperToolsForTestSuite(self):
+    """Shuts down the server and the forwarder."""
+    if self._http_server:
+      self._UnmapPorts([(self._forwarder_device_port, self._http_server.port)])
+      self._http_server.ShutdownHttpServer()
+
diff --git a/build/android/pylib/base/environment.py b/build/android/pylib/base/environment.py
new file mode 100644
index 0000000..3f49f41
--- /dev/null
+++ b/build/android/pylib/base/environment.py
@@ -0,0 +1,34 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class Environment(object):
+  """An environment in which tests can be run.
+
+  This is expected to handle all logic that is applicable to an entire specific
+  environment but is independent of the test type.
+
+  Examples include:
+    - The local device environment, for running tests on devices attached to
+      the local machine.
+    - The local machine environment, for running tests directly on the local
+      machine.
+  """
+
+  def __init__(self):
+    pass
+
+  def SetUp(self):
+    raise NotImplementedError
+
+  def TearDown(self):
+    raise NotImplementedError
+
+  def __enter__(self):
+    self.SetUp()
+    return self
+
+  def __exit__(self, _exc_type, _exc_val, _exc_tb):
+    self.TearDown()
+
diff --git a/build/android/pylib/base/environment_factory.py b/build/android/pylib/base/environment_factory.py
new file mode 100644
index 0000000..31b4952
--- /dev/null
+++ b/build/android/pylib/base/environment_factory.py
@@ -0,0 +1,18 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import constants
+from pylib.local.device import local_device_environment
+from pylib.remote.device import remote_device_environment
+
+def CreateEnvironment(args, error_func):
+
+  if args.environment == 'local':
+    if args.command not in constants.LOCAL_MACHINE_TESTS:
+      return local_device_environment.LocalDeviceEnvironment(args, error_func)
+    # TODO(jbudorick) Add local machine environment.
+  if args.environment == 'remote_device':
+    return remote_device_environment.RemoteDeviceEnvironment(args,
+                                                             error_func)
+  error_func('Unable to create %s environment.' % args.environment)
diff --git a/build/android/pylib/base/test_collection.py b/build/android/pylib/base/test_collection.py
new file mode 100644
index 0000000..de51027
--- /dev/null
+++ b/build/android/pylib/base/test_collection.py
@@ -0,0 +1,80 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import threading
+
+class TestCollection(object):
+  """A threadsafe collection of tests.
+
+  Args:
+    tests: List of tests to put in the collection.
+  """
+
+  def __init__(self, tests=None):
+    if not tests:
+      tests = []
+    self._lock = threading.Lock()
+    self._tests = []
+    self._tests_in_progress = 0
+    # Used to signal that an item is available or all items have been handled.
+    self._item_available_or_all_done = threading.Event()
+    for t in tests:
+      self.add(t)
+
+  def _pop(self):
+    """Pop a test from the collection.
+
+    Waits until a test is available or all tests have been handled.
+
+    Returns:
+      A test or None if all tests have been handled.
+    """
+    while True:
+      # Wait for a test to be available or all tests to have been handled.
+      self._item_available_or_all_done.wait()
+      with self._lock:
+        # Check which of the two conditions triggered the signal.
+        if self._tests_in_progress == 0:
+          return None
+        try:
+          return self._tests.pop(0)
+        except IndexError:
+          # Another thread beat us to the available test, wait again.
+          self._item_available_or_all_done.clear()
+
+  def add(self, test):
+    """Add a test to the collection.
+
+    Args:
+      test: A test to add.
+    """
+    with self._lock:
+      self._tests.append(test)
+      self._item_available_or_all_done.set()
+      self._tests_in_progress += 1
+
+  def test_completed(self):
+    """Indicate that a test has been fully handled."""
+    with self._lock:
+      self._tests_in_progress -= 1
+      if self._tests_in_progress == 0:
+        # All tests have been handled, signal all waiting threads.
+        self._item_available_or_all_done.set()
+
+  def __iter__(self):
+    """Iterate through tests in the collection until all have been handled."""
+    while True:
+      r = self._pop()
+      if r is None:
+        break
+      yield r
+
+  def __len__(self):
+    """Return the number of tests currently in the collection."""
+    return len(self._tests)
+
+  def test_names(self):
+    """Return a list of the names of the tests currently in the collection."""
+    with self._lock:
+      return list(t.test for t in self._tests)
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
new file mode 100644
index 0000000..f919965
--- /dev/null
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -0,0 +1,332 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Dispatches tests, either sharding or replicating them.
+
+Performs the following steps:
+* Create a test collection factory, using the given tests
+  - If sharding: test collection factory returns the same shared test collection
+    to all test runners
+  - If replciating: test collection factory returns a unique test collection to
+    each test runner, with the same set of tests in each.
+* Create a test runner for each device.
+* Run each test runner in its own thread, grabbing tests from the test
+  collection until there are no tests left.
+"""
+
+# TODO(jbudorick) Deprecate and remove this class after any relevant parts have
+# been ported to the new environment / test instance model.
+
+import logging
+import threading
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.base import test_collection
+from pylib.device import device_errors
+from pylib.utils import reraiser_thread
+from pylib.utils import watchdog_timer
+
+
+DEFAULT_TIMEOUT = 7 * 60  # seven minutes
+
+
+class _ThreadSafeCounter(object):
+  """A threadsafe counter."""
+
+  def __init__(self):
+    self._lock = threading.Lock()
+    self._value = 0
+
+  def GetAndIncrement(self):
+    """Get the current value and increment it atomically.
+
+    Returns:
+      The value before incrementing.
+    """
+    with self._lock:
+      pre_increment = self._value
+      self._value += 1
+      return pre_increment
+
+
+class _Test(object):
+  """Holds a test with additional metadata."""
+
+  def __init__(self, test, tries=0):
+    """Initializes the _Test object.
+
+    Args:
+      test: The test.
+      tries: Number of tries so far.
+    """
+    self.test = test
+    self.tries = tries
+
+
+def _RunTestsFromQueue(runner, collection, out_results, watcher,
+                       num_retries, tag_results_with_device=False):
+  """Runs tests from the collection until empty using the given runner.
+
+  Adds TestRunResults objects to the out_results list and may add tests to the
+  out_retry list.
+
+  Args:
+    runner: A TestRunner object used to run the tests.
+    collection: A TestCollection from which to get _Test objects to run.
+    out_results: A list to add TestRunResults to.
+    watcher: A watchdog_timer.WatchdogTimer object, used as a shared timeout.
+    num_retries: Number of retries for a test.
+    tag_results_with_device: If True, appends the name of the device on which
+        the test was run to the test name. Used when replicating to identify
+        which device ran each copy of the test, and to ensure each copy of the
+        test is recorded separately.
+  """
+
+  def TagTestRunResults(test_run_results):
+    """Tags all results with the last 4 digits of the device id.
+
+    Used when replicating tests to distinguish the same tests run on different
+    devices. We use a set to store test results, so the hash (generated from
+    name and tag) must be unique to be considered different results.
+    """
+    new_test_run_results = base_test_result.TestRunResults()
+    for test_result in test_run_results.GetAll():
+      test_result.SetName('%s_%s' % (runner.device_serial[-4:],
+                                     test_result.GetName()))
+      new_test_run_results.AddResult(test_result)
+    return new_test_run_results
+
+  for test in collection:
+    watcher.Reset()
+    try:
+      if not runner.device.IsOnline():
+        # Device is unresponsive, stop handling tests on this device.
+        msg = 'Device %s is unresponsive.' % runner.device_serial
+        logging.warning(msg)
+        raise device_errors.DeviceUnreachableError(msg)
+      result, retry = runner.RunTest(test.test)
+      if tag_results_with_device:
+        result = TagTestRunResults(result)
+      test.tries += 1
+      if retry and test.tries <= num_retries:
+        # Retry non-passing results, only record passing results.
+        pass_results = base_test_result.TestRunResults()
+        pass_results.AddResults(result.GetPass())
+        out_results.append(pass_results)
+        logging.warning('Will retry test %s, try #%s.', retry, test.tries)
+        collection.add(_Test(test=retry, tries=test.tries))
+      else:
+        # All tests passed or retry limit reached. Either way, record results.
+        out_results.append(result)
+    except:
+      # An unhandleable exception, ensure tests get run by another device and
+      # reraise this exception on the main thread.
+      collection.add(test)
+      raise
+    finally:
+      # Retries count as separate tasks so always mark the popped test as done.
+      collection.test_completed()
+
+
+def _SetUp(runner_factory, device, out_runners, threadsafe_counter):
+  """Creates a test runner for each device and calls SetUp() in parallel.
+
+  Note: if a device is unresponsive the corresponding TestRunner will not be
+    added to out_runners.
+
+  Args:
+    runner_factory: Callable that takes a device and index and returns a
+      TestRunner object.
+    device: The device serial number to set up.
+    out_runners: List to add the successfully set up TestRunner object.
+    threadsafe_counter: A _ThreadSafeCounter object used to get shard indices.
+  """
+  try:
+    index = threadsafe_counter.GetAndIncrement()
+    logging.warning('Creating shard %s for device %s.', index, device)
+    runner = runner_factory(device, index)
+    runner.SetUp()
+    out_runners.append(runner)
+  except device_errors.DeviceUnreachableError as e:
+    logging.warning('Failed to create shard for %s: [%s]', device, e)
+
+
+def _RunAllTests(runners, test_collection_factory, num_retries, timeout=None,
+                 tag_results_with_device=False):
+  """Run all tests using the given TestRunners.
+
+  Args:
+    runners: A list of TestRunner objects.
+    test_collection_factory: A callable to generate a TestCollection object for
+        each test runner.
+    num_retries: Number of retries for a test.
+    timeout: Watchdog timeout in seconds.
+    tag_results_with_device: If True, appends the name of the device on which
+        the test was run to the test name. Used when replicating to identify
+        which device ran each copy of the test, and to ensure each copy of the
+        test is recorded separately.
+
+  Returns:
+    A tuple of (TestRunResults object, exit code)
+  """
+  logging.warning('Running tests with %s test runners.' % (len(runners)))
+  results = []
+  exit_code = 0
+  run_results = base_test_result.TestRunResults()
+  watcher = watchdog_timer.WatchdogTimer(timeout)
+  test_collections = [test_collection_factory() for _ in runners]
+
+  threads = [
+      reraiser_thread.ReraiserThread(
+          _RunTestsFromQueue,
+          [r, tc, results, watcher, num_retries, tag_results_with_device],
+          name=r.device_serial[-4:])
+      for r, tc in zip(runners, test_collections)]
+
+  workers = reraiser_thread.ReraiserThreadGroup(threads)
+  workers.StartAll()
+
+  # Catch DeviceUnreachableErrors and set a warning exit code
+  try:
+    workers.JoinAll(watcher)
+  except device_errors.DeviceUnreachableError as e:
+    logging.error(e)
+
+  if not all((len(tc) == 0 for tc in test_collections)):
+    logging.error('Only ran %d tests (all devices are likely offline).' %
+                  len(results))
+    for tc in test_collections:
+      run_results.AddResults(base_test_result.BaseTestResult(
+          t, base_test_result.ResultType.UNKNOWN) for t in tc.test_names())
+
+  for r in results:
+    run_results.AddTestRunResults(r)
+  if not run_results.DidRunPass():
+    exit_code = constants.ERROR_EXIT_CODE
+  return (run_results, exit_code)
+
+
+def _CreateRunners(runner_factory, devices, timeout=None):
+  """Creates a test runner for each device and calls SetUp() in parallel.
+
+  Note: if a device is unresponsive the corresponding TestRunner will not be
+    included in the returned list.
+
+  Args:
+    runner_factory: Callable that takes a device and index and returns a
+      TestRunner object.
+    devices: List of device serial numbers as strings.
+    timeout: Watchdog timeout in seconds, defaults to the default timeout.
+
+  Returns:
+    A list of TestRunner objects.
+  """
+  logging.warning('Creating %s test runners.' % len(devices))
+  runners = []
+  counter = _ThreadSafeCounter()
+  threads = reraiser_thread.ReraiserThreadGroup(
+      [reraiser_thread.ReraiserThread(_SetUp,
+                                      [runner_factory, d, runners, counter],
+                                      name=str(d)[-4:])
+       for d in devices])
+  threads.StartAll()
+  threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
+  return runners
+
+
+def _TearDownRunners(runners, timeout=None):
+  """Calls TearDown() for each test runner in parallel.
+
+  Args:
+    runners: A list of TestRunner objects.
+    timeout: Watchdog timeout in seconds, defaults to the default timeout.
+  """
+  threads = reraiser_thread.ReraiserThreadGroup(
+      [reraiser_thread.ReraiserThread(r.TearDown, name=r.device_serial[-4:])
+       for r in runners])
+  threads.StartAll()
+  threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
+
+
+def ApplyMaxPerRun(tests, max_per_run):
+  """Rearrange the tests so that no group contains more than max_per_run tests.
+
+  Args:
+    tests:
+    max_per_run:
+
+  Returns:
+    A list of tests with no more than max_per_run per run.
+  """
+  tests_expanded = []
+  for test_group in tests:
+    if type(test_group) != str:
+      # Do not split test objects which are not strings.
+      tests_expanded.append(test_group)
+    else:
+      test_split = test_group.split(':')
+      for i in range(0, len(test_split), max_per_run):
+        tests_expanded.append(':'.join(test_split[i:i+max_per_run]))
+  return tests_expanded
+
+
+def RunTests(tests, runner_factory, devices, shard=True,
+             test_timeout=DEFAULT_TIMEOUT, setup_timeout=DEFAULT_TIMEOUT,
+             num_retries=2, max_per_run=256):
+  """Run all tests on attached devices, retrying tests that don't pass.
+
+  Args:
+    tests: List of tests to run.
+    runner_factory: Callable that takes a device and index and returns a
+        TestRunner object.
+    devices: List of attached devices.
+    shard: True if we should shard, False if we should replicate tests.
+      - Sharding tests will distribute tests across all test runners through a
+        shared test collection.
+      - Replicating tests will copy all tests to each test runner through a
+        unique test collection for each test runner.
+    test_timeout: Watchdog timeout in seconds for running tests.
+    setup_timeout: Watchdog timeout in seconds for creating and cleaning up
+        test runners.
+    num_retries: Number of retries for a test.
+    max_per_run: Maximum number of tests to run in any group.
+
+  Returns:
+    A tuple of (base_test_result.TestRunResults object, exit code).
+  """
+  if not tests:
+    logging.critical('No tests to run.')
+    return (base_test_result.TestRunResults(), constants.ERROR_EXIT_CODE)
+
+  tests_expanded = ApplyMaxPerRun(tests, max_per_run)
+  if shard:
+    # Generate a shared TestCollection object for all test runners, so they
+    # draw from a common pool of tests.
+    shared_test_collection = test_collection.TestCollection(
+        [_Test(t) for t in tests_expanded])
+    test_collection_factory = lambda: shared_test_collection
+    tag_results_with_device = False
+    log_string = 'sharded across devices'
+  else:
+    # Generate a unique TestCollection object for each test runner, but use
+    # the same set of tests.
+    test_collection_factory = lambda: test_collection.TestCollection(
+        [_Test(t) for t in tests_expanded])
+    tag_results_with_device = True
+    log_string = 'replicated on each device'
+
+  logging.info('Will run %d tests (%s): %s',
+               len(tests_expanded), log_string, str(tests_expanded))
+  runners = _CreateRunners(runner_factory, devices, setup_timeout)
+  try:
+    return _RunAllTests(runners, test_collection_factory,
+                        num_retries, test_timeout, tag_results_with_device)
+  finally:
+    try:
+      _TearDownRunners(runners, setup_timeout)
+    except device_errors.DeviceUnreachableError as e:
+      logging.warning('Device unresponsive during TearDown: [%s]', e)
+    except Exception as e:
+      logging.error('Unexpected exception caught during TearDown: %s' % str(e))
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
new file mode 100755
index 0000000..cace9a6
--- /dev/null
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for test_dispatcher.py."""
+# pylint: disable=R0201
+# pylint: disable=W0212
+
+import os
+import sys
+import unittest
+
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.base import test_collection
+from pylib.base import test_dispatcher
+from pylib.device import adb_wrapper
+from pylib.device import device_utils
+from pylib.utils import watchdog_timer
+
+sys.path.append(
+    os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
+
+class TestException(Exception):
+  pass
+
+
+def _MockDevice(serial):
+  d = mock.MagicMock(spec=device_utils.DeviceUtils)
+  d.__str__.return_value = serial
+  d.adb = mock.MagicMock(spec=adb_wrapper.AdbWrapper)
+  d.adb.GetDeviceSerial = mock.MagicMock(return_value=serial)
+  d.IsOnline = mock.MagicMock(return_value=True)
+  return d
+
+
+class MockRunner(object):
+  """A mock TestRunner."""
+  def __init__(self, device=None, shard_index=0):
+    self.device = device or _MockDevice('0')
+    self.device_serial = self.device.adb.GetDeviceSerial()
+    self.shard_index = shard_index
+    self.setups = 0
+    self.teardowns = 0
+
+  def RunTest(self, test):
+    results = base_test_result.TestRunResults()
+    results.AddResult(
+        base_test_result.BaseTestResult(test, base_test_result.ResultType.PASS))
+    return (results, None)
+
+  def SetUp(self):
+    self.setups += 1
+
+  def TearDown(self):
+    self.teardowns += 1
+
+
+class MockRunnerFail(MockRunner):
+  def RunTest(self, test):
+    results = base_test_result.TestRunResults()
+    results.AddResult(
+        base_test_result.BaseTestResult(test, base_test_result.ResultType.FAIL))
+    return (results, test)
+
+
+class MockRunnerFailTwice(MockRunner):
+  def __init__(self, device=None, shard_index=0):
+    super(MockRunnerFailTwice, self).__init__(device, shard_index)
+    self._fails = 0
+
+  def RunTest(self, test):
+    self._fails += 1
+    results = base_test_result.TestRunResults()
+    if self._fails <= 2:
+      results.AddResult(base_test_result.BaseTestResult(
+          test, base_test_result.ResultType.FAIL))
+      return (results, test)
+    else:
+      results.AddResult(base_test_result.BaseTestResult(
+          test, base_test_result.ResultType.PASS))
+      return (results, None)
+
+
+class MockRunnerException(MockRunner):
+  def RunTest(self, test):
+    raise TestException
+
+
+class TestFunctions(unittest.TestCase):
+  """Tests test_dispatcher._RunTestsFromQueue."""
+  @staticmethod
+  def _RunTests(mock_runner, tests):
+    results = []
+    tests = test_collection.TestCollection(
+        [test_dispatcher._Test(t) for t in tests])
+    test_dispatcher._RunTestsFromQueue(mock_runner, tests, results,
+                                       watchdog_timer.WatchdogTimer(None), 2)
+    run_results = base_test_result.TestRunResults()
+    for r in results:
+      run_results.AddTestRunResults(r)
+    return run_results
+
+  def testRunTestsFromQueue(self):
+    results = TestFunctions._RunTests(MockRunner(), ['a', 'b'])
+    self.assertEqual(len(results.GetPass()), 2)
+    self.assertEqual(len(results.GetNotPass()), 0)
+
+  def testRunTestsFromQueueRetry(self):
+    results = TestFunctions._RunTests(MockRunnerFail(), ['a', 'b'])
+    self.assertEqual(len(results.GetPass()), 0)
+    self.assertEqual(len(results.GetFail()), 2)
+
+  def testRunTestsFromQueueFailTwice(self):
+    results = TestFunctions._RunTests(MockRunnerFailTwice(), ['a', 'b'])
+    self.assertEqual(len(results.GetPass()), 2)
+    self.assertEqual(len(results.GetNotPass()), 0)
+
+  def testSetUp(self):
+    runners = []
+    counter = test_dispatcher._ThreadSafeCounter()
+    test_dispatcher._SetUp(MockRunner, _MockDevice('0'), runners, counter)
+    self.assertEqual(len(runners), 1)
+    self.assertEqual(runners[0].setups, 1)
+
+  def testThreadSafeCounter(self):
+    counter = test_dispatcher._ThreadSafeCounter()
+    for i in xrange(5):
+      self.assertEqual(counter.GetAndIncrement(), i)
+
+  def testApplyMaxPerRun(self):
+    self.assertEqual(
+        ['A:B', 'C:D', 'E', 'F:G', 'H:I'],
+        test_dispatcher.ApplyMaxPerRun(['A:B', 'C:D:E', 'F:G:H:I'], 2))
+
+
+class TestThreadGroupFunctions(unittest.TestCase):
+  """Tests test_dispatcher._RunAllTests and test_dispatcher._CreateRunners."""
+  def setUp(self):
+    self.tests = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
+    shared_test_collection = test_collection.TestCollection(
+        [test_dispatcher._Test(t) for t in self.tests])
+    self.test_collection_factory = lambda: shared_test_collection
+
+  def testCreate(self):
+    runners = test_dispatcher._CreateRunners(
+        MockRunner, [_MockDevice('0'), _MockDevice('1')])
+    for runner in runners:
+      self.assertEqual(runner.setups, 1)
+    self.assertEqual(set([r.device_serial for r in runners]),
+                     set(['0', '1']))
+    self.assertEqual(set([r.shard_index for r in runners]),
+                     set([0, 1]))
+
+  def testRun(self):
+    runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
+    results, exit_code = test_dispatcher._RunAllTests(
+        runners, self.test_collection_factory, 0)
+    self.assertEqual(len(results.GetPass()), len(self.tests))
+    self.assertEqual(exit_code, 0)
+
+  def testTearDown(self):
+    runners = [MockRunner(_MockDevice('0')), MockRunner(_MockDevice('1'))]
+    test_dispatcher._TearDownRunners(runners)
+    for runner in runners:
+      self.assertEqual(runner.teardowns, 1)
+
+  def testRetry(self):
+    runners = test_dispatcher._CreateRunners(
+        MockRunnerFail, [_MockDevice('0'), _MockDevice('1')])
+    results, exit_code = test_dispatcher._RunAllTests(
+        runners, self.test_collection_factory, 0)
+    self.assertEqual(len(results.GetFail()), len(self.tests))
+    self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
+
+  def testReraise(self):
+    runners = test_dispatcher._CreateRunners(
+        MockRunnerException, [_MockDevice('0'), _MockDevice('1')])
+    with self.assertRaises(TestException):
+      test_dispatcher._RunAllTests(runners, self.test_collection_factory, 0)
+
+
+class TestShard(unittest.TestCase):
+  """Tests test_dispatcher.RunTests with sharding."""
+  @staticmethod
+  def _RunShard(runner_factory):
+    return test_dispatcher.RunTests(
+        ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
+        shard=True)
+
+  def testShard(self):
+    results, exit_code = TestShard._RunShard(MockRunner)
+    self.assertEqual(len(results.GetPass()), 3)
+    self.assertEqual(exit_code, 0)
+
+  def testFailing(self):
+    results, exit_code = TestShard._RunShard(MockRunnerFail)
+    self.assertEqual(len(results.GetPass()), 0)
+    self.assertEqual(len(results.GetFail()), 3)
+    self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
+
+  def testNoTests(self):
+    results, exit_code = test_dispatcher.RunTests(
+        [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=True)
+    self.assertEqual(len(results.GetAll()), 0)
+    self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
+
+
+class TestReplicate(unittest.TestCase):
+  """Tests test_dispatcher.RunTests with replication."""
+  @staticmethod
+  def _RunReplicate(runner_factory):
+    return test_dispatcher.RunTests(
+        ['a', 'b', 'c'], runner_factory, [_MockDevice('0'), _MockDevice('1')],
+        shard=False)
+
+  def testReplicate(self):
+    results, exit_code = TestReplicate._RunReplicate(MockRunner)
+    # We expect 6 results since each test should have been run on every device
+    self.assertEqual(len(results.GetPass()), 6)
+    self.assertEqual(exit_code, 0)
+
+  def testFailing(self):
+    results, exit_code = TestReplicate._RunReplicate(MockRunnerFail)
+    self.assertEqual(len(results.GetPass()), 0)
+    self.assertEqual(len(results.GetFail()), 6)
+    self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
+
+  def testNoTests(self):
+    results, exit_code = test_dispatcher.RunTests(
+        [], MockRunner, [_MockDevice('0'), _MockDevice('1')], shard=False)
+    self.assertEqual(len(results.GetAll()), 0)
+    self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/base/test_instance.py b/build/android/pylib/base/test_instance.py
new file mode 100644
index 0000000..cdf678f
--- /dev/null
+++ b/build/android/pylib/base/test_instance.py
@@ -0,0 +1,35 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class TestInstance(object):
+  """A type of test.
+
+  This is expected to handle all logic that is test-type specific but
+  independent of the environment or device.
+
+  Examples include:
+    - gtests
+    - instrumentation tests
+  """
+
+  def __init__(self):
+    pass
+
+  def TestType(self):
+    raise NotImplementedError
+
+  def SetUp(self):
+    raise NotImplementedError
+
+  def TearDown(self):
+    raise NotImplementedError
+
+  def __enter__(self):
+    self.SetUp()
+    return self
+
+  def __exit__(self, _exc_type, _exc_val, _exc_tb):
+    self.TearDown()
+
diff --git a/build/android/pylib/base/test_instance_factory.py b/build/android/pylib/base/test_instance_factory.py
new file mode 100644
index 0000000..7e7cb0c
--- /dev/null
+++ b/build/android/pylib/base/test_instance_factory.py
@@ -0,0 +1,24 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import constants
+from pylib.gtest import gtest_test_instance
+from pylib.instrumentation import instrumentation_test_instance
+from pylib.utils import isolator
+from pylib.uirobot import uirobot_test_instance
+
+
+
+def CreateTestInstance(args, error_func):
+
+  if args.command == 'gtest':
+    return gtest_test_instance.GtestTestInstance(
+        args, isolator.Isolator(constants.ISOLATE_DEPS_DIR), error_func)
+  elif args.command == 'instrumentation':
+    return instrumentation_test_instance.InstrumentationTestInstance(
+        args, isolator.Isolator(constants.ISOLATE_DEPS_DIR), error_func)
+  elif args.command == 'uirobot':
+    return uirobot_test_instance.UirobotTestInstance(args, error_func)
+
+  error_func('Unable to create %s test instance.' % args.command)
diff --git a/build/android/pylib/base/test_run.py b/build/android/pylib/base/test_run.py
new file mode 100644
index 0000000..7380e78
--- /dev/null
+++ b/build/android/pylib/base/test_run.py
@@ -0,0 +1,39 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class TestRun(object):
+  """An execution of a particular test on a particular device.
+
+  This is expected to handle all logic that is specific to the combination of
+  environment and test type.
+
+  Examples include:
+    - local gtests
+    - local instrumentation tests
+  """
+
+  def __init__(self, env, test_instance):
+    self._env = env
+    self._test_instance = test_instance
+
+  def TestPackage(self):
+    raise NotImplementedError
+
+  def SetUp(self):
+    raise NotImplementedError
+
+  def RunTests(self):
+    raise NotImplementedError
+
+  def TearDown(self):
+    raise NotImplementedError
+
+  def __enter__(self):
+    self.SetUp()
+    return self
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    self.TearDown()
+
diff --git a/build/android/pylib/base/test_run_factory.py b/build/android/pylib/base/test_run_factory.py
new file mode 100644
index 0000000..8c71ebb
--- /dev/null
+++ b/build/android/pylib/base/test_run_factory.py
@@ -0,0 +1,41 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib.gtest import gtest_test_instance
+from pylib.gtest import local_device_gtest_run
+from pylib.instrumentation import instrumentation_test_instance
+from pylib.local.device import local_device_environment
+from pylib.local.device import local_device_instrumentation_test_run
+from pylib.remote.device import remote_device_environment
+from pylib.remote.device import remote_device_gtest_run
+from pylib.remote.device import remote_device_instrumentation_test_run
+from pylib.remote.device import remote_device_uirobot_test_run
+from pylib.uirobot import uirobot_test_instance
+
+
+def CreateTestRun(_args, env, test_instance, error_func):
+  if isinstance(env, local_device_environment.LocalDeviceEnvironment):
+    if isinstance(test_instance, gtest_test_instance.GtestTestInstance):
+      return local_device_gtest_run.LocalDeviceGtestRun(env, test_instance)
+    if isinstance(test_instance,
+                  instrumentation_test_instance.InstrumentationTestInstance):
+      return (local_device_instrumentation_test_run
+              .LocalDeviceInstrumentationTestRun(env, test_instance))
+
+  if isinstance(env, remote_device_environment.RemoteDeviceEnvironment):
+    if isinstance(test_instance, gtest_test_instance.GtestTestInstance):
+      return remote_device_gtest_run.RemoteDeviceGtestTestRun(
+          env, test_instance)
+    if isinstance(test_instance,
+                  instrumentation_test_instance.InstrumentationTestInstance):
+      return (remote_device_instrumentation_test_run
+              .RemoteDeviceInstrumentationTestRun(env, test_instance))
+    if isinstance(test_instance, uirobot_test_instance.UirobotTestInstance):
+      return remote_device_uirobot_test_run.RemoteDeviceUirobotTestRun(
+          env, test_instance)
+
+
+  error_func('Unable to create test run for %s tests in %s environment'
+             % (str(test_instance), str(env)))
+
diff --git a/build/android/pylib/base/test_server.py b/build/android/pylib/base/test_server.py
new file mode 100644
index 0000000..085a51e
--- /dev/null
+++ b/build/android/pylib/base/test_server.py
@@ -0,0 +1,19 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+class TestServer(object):
+  """Base class for any server that needs to be set up for the tests."""
+
+  def __init__(self, *args, **kwargs):
+    pass
+
+  def SetUp(self):
+    raise NotImplementedError
+
+  def Reset(self):
+    raise NotImplementedError
+
+  def TearDown(self):
+    raise NotImplementedError
+
diff --git a/build/android/pylib/chrome_test_server_spawner.py b/build/android/pylib/chrome_test_server_spawner.py
new file mode 100644
index 0000000..052c2fd
--- /dev/null
+++ b/build/android/pylib/chrome_test_server_spawner.py
@@ -0,0 +1,422 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A "Test Server Spawner" that handles killing/stopping per-test test servers.
+
+It's used to accept requests from the device to spawn and kill instances of the
+chrome test server on the host.
+"""
+# pylint: disable=W0702
+
+import BaseHTTPServer
+import json
+import logging
+import os
+import select
+import struct
+import subprocess
+import sys
+import threading
+import time
+import urlparse
+
+from pylib import constants
+from pylib import ports
+
+from pylib.forwarder import Forwarder
+
+
+# Path that are needed to import necessary modules when launching a testserver.
+os.environ['PYTHONPATH'] = os.environ.get('PYTHONPATH', '') + (':%s:%s:%s:%s:%s'
+    % (os.path.join(constants.DIR_SOURCE_ROOT, 'third_party'),
+       os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'tlslite'),
+       os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pyftpdlib',
+                    'src'),
+       os.path.join(constants.DIR_SOURCE_ROOT, 'net', 'tools', 'testserver'),
+       os.path.join(constants.DIR_SOURCE_ROOT, 'sync', 'tools', 'testserver')))
+
+
+SERVER_TYPES = {
+    'http': '',
+    'ftp': '-f',
+    'sync': '',  # Sync uses its own script, and doesn't take a server type arg.
+    'tcpecho': '--tcp-echo',
+    'udpecho': '--udp-echo',
+}
+
+
+# The timeout (in seconds) of starting up the Python test server.
+TEST_SERVER_STARTUP_TIMEOUT = 10
+
+def _WaitUntil(predicate, max_attempts=5):
+  """Blocks until the provided predicate (function) is true.
+
+  Returns:
+    Whether the provided predicate was satisfied once (before the timeout).
+  """
+  sleep_time_sec = 0.025
+  for _ in xrange(1, max_attempts):
+    if predicate():
+      return True
+    time.sleep(sleep_time_sec)
+    sleep_time_sec = min(1, sleep_time_sec * 2)  # Don't wait more than 1 sec.
+  return False
+
+
+def _CheckPortAvailable(port):
+  """Returns True if |port| is available."""
+  return _WaitUntil(lambda: ports.IsHostPortAvailable(port))
+
+
+def _CheckPortNotAvailable(port):
+  """Returns True if |port| is not available."""
+  return _WaitUntil(lambda: not ports.IsHostPortAvailable(port))
+
+
+def _CheckDevicePortStatus(device, port):
+  """Returns whether the provided port is used."""
+  return _WaitUntil(lambda: ports.IsDevicePortUsed(device, port))
+
+
+def _GetServerTypeCommandLine(server_type):
+  """Returns the command-line by the given server type.
+
+  Args:
+    server_type: the server type to be used (e.g. 'http').
+
+  Returns:
+    A string containing the command-line argument.
+  """
+  if server_type not in SERVER_TYPES:
+    raise NotImplementedError('Unknown server type: %s' % server_type)
+  if server_type == 'udpecho':
+    raise Exception('Please do not run UDP echo tests because we do not have '
+                    'a UDP forwarder tool.')
+  return SERVER_TYPES[server_type]
+
+
+class TestServerThread(threading.Thread):
+  """A thread to run the test server in a separate process."""
+
+  def __init__(self, ready_event, arguments, device, tool):
+    """Initialize TestServerThread with the following argument.
+
+    Args:
+      ready_event: event which will be set when the test server is ready.
+      arguments: dictionary of arguments to run the test server.
+      device: An instance of DeviceUtils.
+      tool: instance of runtime error detection tool.
+    """
+    threading.Thread.__init__(self)
+    self.wait_event = threading.Event()
+    self.stop_flag = False
+    self.ready_event = ready_event
+    self.ready_event.clear()
+    self.arguments = arguments
+    self.device = device
+    self.tool = tool
+    self.test_server_process = None
+    self.is_ready = False
+    self.host_port = self.arguments['port']
+    assert isinstance(self.host_port, int)
+    # The forwarder device port now is dynamically allocated.
+    self.forwarder_device_port = 0
+    # Anonymous pipe in order to get port info from test server.
+    self.pipe_in = None
+    self.pipe_out = None
+    self.process = None
+    self.command_line = []
+
+  def _WaitToStartAndGetPortFromTestServer(self):
+    """Waits for the Python test server to start and gets the port it is using.
+
+    The port information is passed by the Python test server with a pipe given
+    by self.pipe_out. It is written as a result to |self.host_port|.
+
+    Returns:
+      Whether the port used by the test server was successfully fetched.
+    """
+    assert self.host_port == 0 and self.pipe_out and self.pipe_in
+    (in_fds, _, _) = select.select([self.pipe_in, ], [], [],
+                                   TEST_SERVER_STARTUP_TIMEOUT)
+    if len(in_fds) == 0:
+      logging.error('Failed to wait to the Python test server to be started.')
+      return False
+    # First read the data length as an unsigned 4-byte value.  This
+    # is _not_ using network byte ordering since the Python test server packs
+    # size as native byte order and all Chromium platforms so far are
+    # configured to use little-endian.
+    # TODO(jnd): Change the Python test server and local_test_server_*.cc to
+    # use a unified byte order (either big-endian or little-endian).
+    data_length = os.read(self.pipe_in, struct.calcsize('=L'))
+    if data_length:
+      (data_length,) = struct.unpack('=L', data_length)
+      assert data_length
+    if not data_length:
+      logging.error('Failed to get length of server data.')
+      return False
+    port_json = os.read(self.pipe_in, data_length)
+    if not port_json:
+      logging.error('Failed to get server data.')
+      return False
+    logging.info('Got port json data: %s', port_json)
+    port_json = json.loads(port_json)
+    if port_json.has_key('port') and isinstance(port_json['port'], int):
+      self.host_port = port_json['port']
+      return _CheckPortNotAvailable(self.host_port)
+    logging.error('Failed to get port information from the server data.')
+    return False
+
+  def _GenerateCommandLineArguments(self):
+    """Generates the command line to run the test server.
+
+    Note that all options are processed by following the definitions in
+    testserver.py.
+    """
+    if self.command_line:
+      return
+
+    args_copy = dict(self.arguments)
+
+    # Translate the server type.
+    type_cmd = _GetServerTypeCommandLine(args_copy.pop('server-type'))
+    if type_cmd:
+      self.command_line.append(type_cmd)
+
+    # Use a pipe to get the port given by the instance of Python test server
+    # if the test does not specify the port.
+    assert self.host_port == args_copy['port']
+    if self.host_port == 0:
+      (self.pipe_in, self.pipe_out) = os.pipe()
+      self.command_line.append('--startup-pipe=%d' % self.pipe_out)
+
+    # Pass the remaining arguments as-is.
+    for key, values in args_copy.iteritems():
+      if not isinstance(values, list):
+        values = [values]
+      for value in values:
+        if value is None:
+          self.command_line.append('--%s' % key)
+        else:
+          self.command_line.append('--%s=%s' % (key, value))
+
+  def _CloseUnnecessaryFDsForTestServerProcess(self):
+    # This is required to avoid subtle deadlocks that could be caused by the
+    # test server child process inheriting undesirable file descriptors such as
+    # file lock file descriptors.
+    for fd in xrange(0, 1024):
+      if fd != self.pipe_out:
+        try:
+          os.close(fd)
+        except:
+          pass
+
+  def run(self):
+    logging.info('Start running the thread!')
+    self.wait_event.clear()
+    self._GenerateCommandLineArguments()
+    command = constants.DIR_SOURCE_ROOT
+    if self.arguments['server-type'] == 'sync':
+      command = [os.path.join(command, 'sync', 'tools', 'testserver',
+                              'sync_testserver.py')] + self.command_line
+    else:
+      command = [os.path.join(command, 'net', 'tools', 'testserver',
+                              'testserver.py')] + self.command_line
+    logging.info('Running: %s', command)
+    # Pass DIR_SOURCE_ROOT as the child's working directory so that relative
+    # paths in the arguments are resolved correctly.
+    self.process = subprocess.Popen(
+        command, preexec_fn=self._CloseUnnecessaryFDsForTestServerProcess,
+        cwd=constants.DIR_SOURCE_ROOT)
+    if self.process:
+      if self.pipe_out:
+        self.is_ready = self._WaitToStartAndGetPortFromTestServer()
+      else:
+        self.is_ready = _CheckPortNotAvailable(self.host_port)
+    if self.is_ready:
+      Forwarder.Map([(0, self.host_port)], self.device, self.tool)
+      # Check whether the forwarder is ready on the device.
+      self.is_ready = False
+      device_port = Forwarder.DevicePortForHostPort(self.host_port)
+      if device_port and _CheckDevicePortStatus(self.device, device_port):
+        self.is_ready = True
+        self.forwarder_device_port = device_port
+    # Wake up the request handler thread.
+    self.ready_event.set()
+    # Keep thread running until Stop() gets called.
+    _WaitUntil(lambda: self.stop_flag, max_attempts=sys.maxint)
+    if self.process.poll() is None:
+      self.process.kill()
+    Forwarder.UnmapDevicePort(self.forwarder_device_port, self.device)
+    self.process = None
+    self.is_ready = False
+    if self.pipe_out:
+      os.close(self.pipe_in)
+      os.close(self.pipe_out)
+      self.pipe_in = None
+      self.pipe_out = None
+    logging.info('Test-server has died.')
+    self.wait_event.set()
+
+  def Stop(self):
+    """Blocks until the loop has finished.
+
+    Note that this must be called in another thread.
+    """
+    if not self.process:
+      return
+    self.stop_flag = True
+    self.wait_event.wait()
+
+
+class SpawningServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+  """A handler used to process http GET/POST request."""
+
+  def _SendResponse(self, response_code, response_reason, additional_headers,
+                    contents):
+    """Generates a response sent to the client from the provided parameters.
+
+    Args:
+      response_code: number of the response status.
+      response_reason: string of reason description of the response.
+      additional_headers: dict of additional headers. Each key is the name of
+                          the header, each value is the content of the header.
+      contents: string of the contents we want to send to client.
+    """
+    self.send_response(response_code, response_reason)
+    self.send_header('Content-Type', 'text/html')
+    # Specify the content-length as without it the http(s) response will not
+    # be completed properly (and the browser keeps expecting data).
+    self.send_header('Content-Length', len(contents))
+    for header_name in additional_headers:
+      self.send_header(header_name, additional_headers[header_name])
+    self.end_headers()
+    self.wfile.write(contents)
+    self.wfile.flush()
+
+  def _StartTestServer(self):
+    """Starts the test server thread."""
+    logging.info('Handling request to spawn a test server.')
+    content_type = self.headers.getheader('content-type')
+    if content_type != 'application/json':
+      raise Exception('Bad content-type for start request.')
+    content_length = self.headers.getheader('content-length')
+    if not content_length:
+      content_length = 0
+    try:
+      content_length = int(content_length)
+    except:
+      raise Exception('Bad content-length for start request.')
+    logging.info(content_length)
+    test_server_argument_json = self.rfile.read(content_length)
+    logging.info(test_server_argument_json)
+    assert not self.server.test_server_instance
+    ready_event = threading.Event()
+    self.server.test_server_instance = TestServerThread(
+        ready_event,
+        json.loads(test_server_argument_json),
+        self.server.device,
+        self.server.tool)
+    self.server.test_server_instance.setDaemon(True)
+    self.server.test_server_instance.start()
+    ready_event.wait()
+    if self.server.test_server_instance.is_ready:
+      self._SendResponse(200, 'OK', {}, json.dumps(
+          {'port': self.server.test_server_instance.forwarder_device_port,
+           'message': 'started'}))
+      logging.info('Test server is running on port: %d.',
+                   self.server.test_server_instance.host_port)
+    else:
+      self.server.test_server_instance.Stop()
+      self.server.test_server_instance = None
+      self._SendResponse(500, 'Test Server Error.', {}, '')
+      logging.info('Encounter problem during starting a test server.')
+
+  def _KillTestServer(self):
+    """Stops the test server instance."""
+    # There should only ever be one test server at a time. This may do the
+    # wrong thing if we try and start multiple test servers.
+    if not self.server.test_server_instance:
+      return
+    port = self.server.test_server_instance.host_port
+    logging.info('Handling request to kill a test server on port: %d.', port)
+    self.server.test_server_instance.Stop()
+    # Make sure the status of test server is correct before sending response.
+    if _CheckPortAvailable(port):
+      self._SendResponse(200, 'OK', {}, 'killed')
+      logging.info('Test server on port %d is killed', port)
+    else:
+      self._SendResponse(500, 'Test Server Error.', {}, '')
+      logging.info('Encounter problem during killing a test server.')
+    self.server.test_server_instance = None
+
+  def do_POST(self):
+    parsed_path = urlparse.urlparse(self.path)
+    action = parsed_path.path
+    logging.info('Action for POST method is: %s.', action)
+    if action == '/start':
+      self._StartTestServer()
+    else:
+      self._SendResponse(400, 'Unknown request.', {}, '')
+      logging.info('Encounter unknown request: %s.', action)
+
+  def do_GET(self):
+    parsed_path = urlparse.urlparse(self.path)
+    action = parsed_path.path
+    params = urlparse.parse_qs(parsed_path.query, keep_blank_values=1)
+    logging.info('Action for GET method is: %s.', action)
+    for param in params:
+      logging.info('%s=%s', param, params[param][0])
+    if action == '/kill':
+      self._KillTestServer()
+    elif action == '/ping':
+      # The ping handler is used to check whether the spawner server is ready
+      # to serve the requests. We don't need to test the status of the test
+      # server when handling ping request.
+      self._SendResponse(200, 'OK', {}, 'ready')
+      logging.info('Handled ping request and sent response.')
+    else:
+      self._SendResponse(400, 'Unknown request', {}, '')
+      logging.info('Encounter unknown request: %s.', action)
+
+
+class SpawningServer(object):
+  """The class used to start/stop a http server."""
+
+  def __init__(self, test_server_spawner_port, device, tool):
+    logging.info('Creating new spawner on port: %d.', test_server_spawner_port)
+    self.server = BaseHTTPServer.HTTPServer(('', test_server_spawner_port),
+                                            SpawningServerRequestHandler)
+    self.server.device = device
+    self.server.tool = tool
+    self.server.test_server_instance = None
+    self.server.build_type = constants.GetBuildType()
+
+  def _Listen(self):
+    logging.info('Starting test server spawner')
+    self.server.serve_forever()
+
+  def Start(self):
+    """Starts the test server spawner."""
+    listener_thread = threading.Thread(target=self._Listen)
+    listener_thread.setDaemon(True)
+    listener_thread.start()
+
+  def Stop(self):
+    """Stops the test server spawner.
+
+    Also cleans the server state.
+    """
+    self.CleanupState()
+    self.server.shutdown()
+
+  def CleanupState(self):
+    """Cleans up the spawning server state.
+
+    This should be called if the test server spawner is reused,
+    to avoid sharing the test server instance.
+    """
+    if self.server.test_server_instance:
+      self.server.test_server_instance.Stop()
+      self.server.test_server_instance = None
diff --git a/build/android/pylib/cmd_helper.py b/build/android/pylib/cmd_helper.py
new file mode 100644
index 0000000..f881553
--- /dev/null
+++ b/build/android/pylib/cmd_helper.py
@@ -0,0 +1,261 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A wrapper for subprocess to make calling shell commands easier."""
+
+import logging
+import os
+import pipes
+import select
+import signal
+import string
+import StringIO
+import subprocess
+import time
+
+# fcntl is not available on Windows.
+try:
+  import fcntl
+except ImportError:
+  fcntl = None
+
+_SafeShellChars = frozenset(string.ascii_letters + string.digits + '@%_-+=:,./')
+
+def SingleQuote(s):
+  """Return an shell-escaped version of the string using single quotes.
+
+  Reliably quote a string which may contain unsafe characters (e.g. space,
+  quote, or other special characters such as '$').
+
+  The returned value can be used in a shell command line as one token that gets
+  to be interpreted literally.
+
+  Args:
+    s: The string to quote.
+
+  Return:
+    The string quoted using single quotes.
+  """
+  return pipes.quote(s)
+
+def DoubleQuote(s):
+  """Return an shell-escaped version of the string using double quotes.
+
+  Reliably quote a string which may contain unsafe characters (e.g. space
+  or quote characters), while retaining some shell features such as variable
+  interpolation.
+
+  The returned value can be used in a shell command line as one token that gets
+  to be further interpreted by the shell.
+
+  The set of characters that retain their special meaning may depend on the
+  shell implementation. This set usually includes: '$', '`', '\', '!', '*',
+  and '@'.
+
+  Args:
+    s: The string to quote.
+
+  Return:
+    The string quoted using double quotes.
+  """
+  if not s:
+    return '""'
+  elif all(c in _SafeShellChars for c in s):
+    return s
+  else:
+    return '"' + s.replace('"', '\\"') + '"'
+
+
+def Popen(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
+  return subprocess.Popen(
+      args=args, cwd=cwd, stdout=stdout, stderr=stderr,
+      shell=shell, close_fds=True, env=env,
+      preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
+
+
+def Call(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
+  pipe = Popen(args, stdout=stdout, stderr=stderr, shell=shell, cwd=cwd,
+               env=env)
+  pipe.communicate()
+  return pipe.wait()
+
+
+def RunCmd(args, cwd=None):
+  """Opens a subprocess to execute a program and returns its return value.
+
+  Args:
+    args: A string or a sequence of program arguments. The program to execute is
+      the string or the first item in the args sequence.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+
+  Returns:
+    Return code from the command execution.
+  """
+  logging.info(str(args) + ' ' + (cwd or ''))
+  return Call(args, cwd=cwd)
+
+
+def GetCmdOutput(args, cwd=None, shell=False):
+  """Open a subprocess to execute a program and returns its output.
+
+  Args:
+    args: A string or a sequence of program arguments. The program to execute is
+      the string or the first item in the args sequence.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+    shell: Whether to execute args as a shell command.
+
+  Returns:
+    Captures and returns the command's stdout.
+    Prints the command's stderr to logger (which defaults to stdout).
+  """
+  (_, output) = GetCmdStatusAndOutput(args, cwd, shell)
+  return output
+
+
+def _ValidateAndLogCommand(args, cwd, shell):
+  if isinstance(args, basestring):
+    if not shell:
+      raise Exception('string args must be run with shell=True')
+  else:
+    if shell:
+      raise Exception('array args must be run with shell=False')
+    args = ' '.join(SingleQuote(c) for c in args)
+  if cwd is None:
+    cwd = ''
+  else:
+    cwd = ':' + cwd
+  logging.info('[host]%s> %s', cwd, args)
+  return args
+
+
+def GetCmdStatusAndOutput(args, cwd=None, shell=False):
+  """Executes a subprocess and returns its exit code and output.
+
+  Args:
+    args: A string or a sequence of program arguments. The program to execute is
+      the string or the first item in the args sequence.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+    shell: Whether to execute args as a shell command. Must be True if args
+      is a string and False if args is a sequence.
+
+  Returns:
+    The 2-tuple (exit code, output).
+  """
+  _ValidateAndLogCommand(args, cwd, shell)
+  pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+               shell=shell, cwd=cwd)
+  stdout, stderr = pipe.communicate()
+
+  if stderr:
+    logging.critical(stderr)
+  if len(stdout) > 4096:
+    logging.debug('Truncated output:')
+  logging.debug(stdout[:4096])
+  return (pipe.returncode, stdout)
+
+
+class TimeoutError(Exception):
+  """Module-specific timeout exception."""
+  pass
+
+
+def _IterProcessStdout(process, timeout=None, buffer_size=4096,
+                       poll_interval=1):
+  assert fcntl, 'fcntl module is required'
+  try:
+    # Enable non-blocking reads from the child's stdout.
+    child_fd = process.stdout.fileno()
+    fl = fcntl.fcntl(child_fd, fcntl.F_GETFL)
+    fcntl.fcntl(child_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
+    end_time = (time.time() + timeout) if timeout else None
+    while True:
+      if end_time and time.time() > end_time:
+        raise TimeoutError
+      read_fds, _, _ = select.select([child_fd], [], [], poll_interval)
+      if child_fd in read_fds:
+        data = os.read(child_fd, buffer_size)
+        if not data:
+          break
+        yield data
+      if process.poll() is not None:
+        break
+  finally:
+    try:
+      # Make sure the process doesn't stick around if we fail with an
+      # exception.
+      process.kill()
+    except OSError:
+      pass
+    process.wait()
+
+
+def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
+                                     logfile=None):
+  """Executes a subprocess with a timeout.
+
+  Args:
+    args: List of arguments to the program, the program to execute is the first
+      element.
+    timeout: the timeout in seconds or None to wait forever.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+    shell: Whether to execute args as a shell command. Must be True if args
+      is a string and False if args is a sequence.
+    logfile: Optional file-like object that will receive output from the
+      command as it is running.
+
+  Returns:
+    The 2-tuple (exit code, output).
+  """
+  _ValidateAndLogCommand(args, cwd, shell)
+  output = StringIO.StringIO()
+  process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
+                  stderr=subprocess.STDOUT)
+  for data in _IterProcessStdout(process, timeout=timeout):
+    if logfile:
+      logfile.write(data)
+    output.write(data)
+  return process.returncode, output.getvalue()
+
+
+def IterCmdOutputLines(args, timeout=None, cwd=None, shell=False,
+                       check_status=True):
+  """Executes a subprocess and continuously yields lines from its output.
+
+  Args:
+    args: List of arguments to the program, the program to execute is the first
+      element.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+    shell: Whether to execute args as a shell command. Must be True if args
+      is a string and False if args is a sequence.
+    check_status: A boolean indicating whether to check the exit status of the
+      process after all output has been read.
+
+  Yields:
+    The output of the subprocess, line by line.
+
+  Raises:
+    CalledProcessError if check_status is True and the process exited with a
+      non-zero exit status.
+  """
+  cmd = _ValidateAndLogCommand(args, cwd, shell)
+  process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
+                  stderr=subprocess.STDOUT)
+  buffer_output = ''
+  for data in _IterProcessStdout(process, timeout=timeout):
+    buffer_output += data
+    has_incomplete_line = buffer_output[-1] not in '\r\n'
+    lines = buffer_output.splitlines()
+    buffer_output = lines.pop() if has_incomplete_line else ''
+    for line in lines:
+      yield line
+  if buffer_output:
+    yield buffer_output
+  if check_status and process.returncode:
+    raise subprocess.CalledProcessError(process.returncode, cmd)
diff --git a/build/android/pylib/cmd_helper_test.py b/build/android/pylib/cmd_helper_test.py
new file mode 100644
index 0000000..5155cea
--- /dev/null
+++ b/build/android/pylib/cmd_helper_test.py
@@ -0,0 +1,83 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for the cmd_helper module."""
+
+import unittest
+import subprocess
+
+from pylib import cmd_helper
+
+
+class CmdHelperSingleQuoteTest(unittest.TestCase):
+
+  def testSingleQuote_basic(self):
+    self.assertEquals('hello',
+                      cmd_helper.SingleQuote('hello'))
+
+  def testSingleQuote_withSpaces(self):
+    self.assertEquals("'hello world'",
+                      cmd_helper.SingleQuote('hello world'))
+
+  def testSingleQuote_withUnsafeChars(self):
+    self.assertEquals("""'hello'"'"'; rm -rf /'""",
+                      cmd_helper.SingleQuote("hello'; rm -rf /"))
+
+  def testSingleQuote_dontExpand(self):
+    test_string = 'hello $TEST_VAR'
+    cmd = 'TEST_VAR=world; echo %s' % cmd_helper.SingleQuote(test_string)
+    self.assertEquals(test_string,
+                      cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
+
+
+class CmdHelperDoubleQuoteTest(unittest.TestCase):
+
+  def testDoubleQuote_basic(self):
+    self.assertEquals('hello',
+                      cmd_helper.DoubleQuote('hello'))
+
+  def testDoubleQuote_withSpaces(self):
+    self.assertEquals('"hello world"',
+                      cmd_helper.DoubleQuote('hello world'))
+
+  def testDoubleQuote_withUnsafeChars(self):
+    self.assertEquals('''"hello\\"; rm -rf /"''',
+                      cmd_helper.DoubleQuote('hello"; rm -rf /'))
+
+  def testSingleQuote_doExpand(self):
+    test_string = 'hello $TEST_VAR'
+    cmd = 'TEST_VAR=world; echo %s' % cmd_helper.DoubleQuote(test_string)
+    self.assertEquals('hello world',
+                      cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
+
+
+class CmdHelperIterCmdOutputLinesTest(unittest.TestCase):
+  """Test IterCmdOutputLines with some calls to the unix 'seq' command."""
+
+  def testIterCmdOutputLines_success(self):
+    for num, line in enumerate(
+        cmd_helper.IterCmdOutputLines(['seq', '10']), 1):
+      self.assertEquals(num, int(line))
+
+  def testIterCmdOutputLines_exitStatusFail(self):
+    with self.assertRaises(subprocess.CalledProcessError):
+      for num, line in enumerate(
+          cmd_helper.IterCmdOutputLines('seq 10 && false', shell=True), 1):
+        self.assertEquals(num, int(line))
+      # after reading all the output we get an exit status of 1
+
+  def testIterCmdOutputLines_exitStatusIgnored(self):
+    for num, line in enumerate(
+        cmd_helper.IterCmdOutputLines('seq 10 && false', shell=True,
+                                      check_status=False), 1):
+      self.assertEquals(num, int(line))
+
+  def testIterCmdOutputLines_exitStatusSkipped(self):
+    for num, line in enumerate(
+        cmd_helper.IterCmdOutputLines('seq 10 && false', shell=True), 1):
+      self.assertEquals(num, int(line))
+      # no exception will be raised because we don't attempt to read past
+      # the end of the output and, thus, the status never gets checked
+      if num == 10:
+        break
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
new file mode 100644
index 0000000..025860c
--- /dev/null
+++ b/build/android/pylib/constants/__init__.py
@@ -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.
+
+"""Defines a set of constants shared by test runners and other scripts."""
+
+# TODO(jbudorick): Split these constants into coherent modules.
+
+# pylint: disable=W0212
+
+import collections
+import logging
+import os
+import subprocess
+
+
+DIR_SOURCE_ROOT = os.environ.get('CHECKOUT_SOURCE_ROOT',
+    os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                 os.pardir, os.pardir, os.pardir, os.pardir)))
+ISOLATE_DEPS_DIR = os.path.join(DIR_SOURCE_ROOT, 'isolate_deps_dir')
+
+CHROME_SHELL_HOST_DRIVEN_DIR = os.path.join(
+    DIR_SOURCE_ROOT, 'chrome', 'android')
+
+
+PackageInfo = collections.namedtuple('PackageInfo',
+    ['package', 'activity', 'cmdline_file', 'devtools_socket',
+     'test_package'])
+
+PACKAGE_INFO = {
+    'chrome_document': PackageInfo(
+        'com.google.android.apps.chrome.document',
+        'com.google.android.apps.chrome.document.ChromeLauncherActivity',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        None),
+    'chrome': PackageInfo(
+        'com.google.android.apps.chrome',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        'com.google.android.apps.chrome.tests'),
+    'chrome_beta': PackageInfo(
+        'com.chrome.beta',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        None),
+    'chrome_stable': PackageInfo(
+        'com.android.chrome',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        None),
+    'chrome_dev': PackageInfo(
+        'com.chrome.dev',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        None),
+    'chrome_canary': PackageInfo(
+        'com.chrome.canary',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        None),
+    'chrome_work': PackageInfo(
+        'com.chrome.work',
+        'com.google.android.apps.chrome.Main',
+        '/data/local/chrome-command-line',
+        'chrome_devtools_remote',
+        None),
+    'legacy_browser': PackageInfo(
+        'com.google.android.browser',
+        'com.android.browser.BrowserActivity',
+        None,
+        None,
+        None),
+    'chromecast_shell': PackageInfo(
+        'com.google.android.apps.mediashell',
+        'com.google.android.apps.mediashell.MediaShellActivity',
+        '/data/local/tmp/castshell-command-line',
+        None,
+        None),
+    'content_shell': PackageInfo(
+        'org.chromium.content_shell_apk',
+        'org.chromium.content_shell_apk.ContentShellActivity',
+        '/data/local/tmp/content-shell-command-line',
+        None,
+        'org.chromium.content_shell_apk.tests'),
+    'chrome_shell': PackageInfo(
+        'org.chromium.chrome.shell',
+        'org.chromium.chrome.shell.ChromeShellActivity',
+        '/data/local/tmp/chrome-shell-command-line',
+        'chrome_shell_devtools_remote',
+        'org.chromium.chrome.shell.tests'),
+    'android_webview_shell': PackageInfo(
+        'org.chromium.android_webview.shell',
+        'org.chromium.android_webview.shell.AwShellActivity',
+        '/data/local/tmp/android-webview-command-line',
+        None,
+        'org.chromium.android_webview.test'),
+    'gtest': PackageInfo(
+        'org.chromium.native_test',
+        'org.chromium.native_test.NativeTestActivity',
+        '/data/local/tmp/chrome-native-tests-command-line',
+        None,
+        None),
+    'components_browsertests': PackageInfo(
+        'org.chromium.components_browsertests_apk',
+        ('org.chromium.components_browsertests_apk' +
+         '.ComponentsBrowserTestsActivity'),
+        '/data/local/tmp/components-browser-tests-command-line',
+        None,
+        None),
+    'content_browsertests': PackageInfo(
+        'org.chromium.content_browsertests_apk',
+        'org.chromium.content_browsertests_apk.ContentBrowserTestsActivity',
+        '/data/local/tmp/content-browser-tests-command-line',
+        None,
+        None),
+    'chromedriver_webview_shell': PackageInfo(
+        'org.chromium.chromedriver_webview_shell',
+        'org.chromium.chromedriver_webview_shell.Main',
+        None,
+        None,
+        None),
+}
+
+
+# Ports arrangement for various test servers used in Chrome for Android.
+# Lighttpd server will attempt to use 9000 as default port, if unavailable it
+# will find a free port from 8001 - 8999.
+LIGHTTPD_DEFAULT_PORT = 9000
+LIGHTTPD_RANDOM_PORT_FIRST = 8001
+LIGHTTPD_RANDOM_PORT_LAST = 8999
+TEST_SYNC_SERVER_PORT = 9031
+TEST_SEARCH_BY_IMAGE_SERVER_PORT = 9041
+TEST_POLICY_SERVER_PORT = 9051
+
+# The net test server is started from port 10201.
+# TODO(pliard): http://crbug.com/239014. Remove this dirty workaround once
+# http://crbug.com/239014 is fixed properly.
+TEST_SERVER_PORT_FIRST = 10201
+TEST_SERVER_PORT_LAST = 30000
+# A file to record next valid port of test server.
+TEST_SERVER_PORT_FILE = '/tmp/test_server_port'
+TEST_SERVER_PORT_LOCKFILE = '/tmp/test_server_port.lock'
+
+TEST_EXECUTABLE_DIR = '/data/local/tmp'
+# Directories for common java libraries for SDK build.
+# These constants are defined in build/android/ant/common.xml
+SDK_BUILD_JAVALIB_DIR = 'lib.java'
+SDK_BUILD_TEST_JAVALIB_DIR = 'test.lib.java'
+SDK_BUILD_APKS_DIR = 'apks'
+
+ADB_KEYS_FILE = '/data/misc/adb/adb_keys'
+
+PERF_OUTPUT_DIR = os.path.join(DIR_SOURCE_ROOT, 'out', 'step_results')
+# The directory on the device where perf test output gets saved to.
+DEVICE_PERF_OUTPUT_DIR = (
+    '/data/data/' + PACKAGE_INFO['chrome'].package + '/files')
+
+SCREENSHOTS_DIR = os.path.join(DIR_SOURCE_ROOT, 'out_screenshots')
+
+class ANDROID_SDK_VERSION_CODES(object):
+  """Android SDK version codes.
+
+  http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
+  """
+
+  ICE_CREAM_SANDWICH = 14
+  ICE_CREAM_SANDWICH_MR1 = 15
+  JELLY_BEAN = 16
+  JELLY_BEAN_MR1 = 17
+  JELLY_BEAN_MR2 = 18
+  KITKAT = 19
+  KITKAT_WATCH = 20
+  LOLLIPOP = 21
+  LOLLIPOP_MR1 = 22
+
+ANDROID_SDK_VERSION = ANDROID_SDK_VERSION_CODES.LOLLIPOP_MR1
+ANDROID_SDK_BUILD_TOOLS_VERSION = '22.0.0'
+ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
+                                'third_party/android_tools/sdk')
+ANDROID_SDK_TOOLS = os.path.join(ANDROID_SDK_ROOT,
+                                 'build-tools', ANDROID_SDK_BUILD_TOOLS_VERSION)
+ANDROID_NDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
+                                'third_party/android_tools/ndk')
+
+EMULATOR_SDK_ROOT = os.environ.get('ANDROID_EMULATOR_SDK_ROOT',
+                                   os.path.join(DIR_SOURCE_ROOT,
+                                                'android_emulator_sdk'))
+
+BAD_DEVICES_JSON = os.path.join(DIR_SOURCE_ROOT,
+                                os.environ.get('CHROMIUM_OUT_DIR', 'out'),
+                                'bad_devices.json')
+
+UPSTREAM_FLAKINESS_SERVER = 'test-results.appspot.com'
+
+DEVICE_LOCAL_PROPERTIES_PATH = '/data/local.prop'
+
+PYTHON_UNIT_TEST_SUITES = {
+  'pylib_py_unittests': {
+    'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android'),
+    'test_modules': [
+      'pylib.cmd_helper_test',
+      'pylib.device.device_utils_test',
+      'pylib.results.json_results_test',
+      'pylib.utils.md5sum_test',
+    ]
+  },
+  'gyp_py_unittests': {
+    'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android', 'gyp'),
+    'test_modules': [
+      'java_cpp_enum_tests',
+    ]
+  },
+}
+
+LOCAL_MACHINE_TESTS = ['junit', 'python']
+VALID_ENVIRONMENTS = ['local', 'remote_device']
+VALID_TEST_TYPES = ['gtest', 'instrumentation', 'junit', 'linker', 'monkey',
+                    'perf', 'python', 'uiautomator', 'uirobot']
+VALID_DEVICE_TYPES = ['Android', 'iOS']
+
+
+def GetBuildType():
+  try:
+    return os.environ['BUILDTYPE']
+  except KeyError:
+    raise EnvironmentError(
+        'The BUILDTYPE environment variable has not been set')
+
+
+def SetBuildType(build_type):
+  os.environ['BUILDTYPE'] = build_type
+
+
+def SetBuildDirectory(build_directory):
+  os.environ['CHROMIUM_OUT_DIR'] = build_directory
+
+
+def SetOutputDirectory(output_directory):
+  os.environ['CHROMIUM_OUTPUT_DIR'] = output_directory
+
+
+def GetOutDirectory(build_type=None):
+  """Returns the out directory where the output binaries are built.
+
+  Args:
+    build_type: Build type, generally 'Debug' or 'Release'. Defaults to the
+      globally set build type environment variable BUILDTYPE.
+  """
+  if 'CHROMIUM_OUTPUT_DIR' in os.environ:
+    return os.path.abspath(os.path.join(
+        DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUTPUT_DIR')))
+
+  return os.path.abspath(os.path.join(
+      DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUT_DIR', 'out'),
+      GetBuildType() if build_type is None else build_type))
+
+
+def _Memoize(func):
+  def Wrapper():
+    try:
+      return func._result
+    except AttributeError:
+      func._result = func()
+      return func._result
+  return Wrapper
+
+
+def SetAdbPath(adb_path):
+  os.environ['ADB_PATH'] = adb_path
+
+
+def GetAdbPath():
+  # Check if a custom adb path as been set. If not, try to find adb
+  # on the system.
+  if os.environ.get('ADB_PATH'):
+    return os.environ.get('ADB_PATH')
+  else:
+    return _FindAdbPath()
+
+
+@_Memoize
+def _FindAdbPath():
+  if os.environ.get('ANDROID_SDK_ROOT'):
+    return 'adb'
+  # If envsetup.sh hasn't been sourced and there's no adb in the path,
+  # set it here.
+  try:
+    with file(os.devnull, 'w') as devnull:
+      subprocess.call(['adb', 'version'], stdout=devnull, stderr=devnull)
+    return 'adb'
+  except OSError:
+    logging.debug('No adb found in $PATH, fallback to checked in binary.')
+    return os.path.join(ANDROID_SDK_ROOT, 'platform-tools', 'adb')
+
+# Exit codes
+ERROR_EXIT_CODE = 1
+INFRA_EXIT_CODE = 87
+WARNING_EXIT_CODE = 88
diff --git a/build/android/pylib/constants/keyevent.py b/build/android/pylib/constants/keyevent.py
new file mode 100644
index 0000000..06736b3
--- /dev/null
+++ b/build/android/pylib/constants/keyevent.py
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Android KeyEvent constants.
+
+http://developer.android.com/reference/android/view/KeyEvent.html
+"""
+
+KEYCODE_BACK = 4
+KEYCODE_DPAD_RIGHT = 22
+KEYCODE_ENTER = 66
+KEYCODE_MENU = 82
+
diff --git a/build/android/pylib/content_settings.py b/build/android/pylib/content_settings.py
new file mode 100644
index 0000000..f039c96
--- /dev/null
+++ b/build/android/pylib/content_settings.py
@@ -0,0 +1,85 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import constants
+
+
+class ContentSettings(dict):
+
+  """A dict interface to interact with device content settings.
+
+  System properties are key/value pairs as exposed by adb shell content.
+  """
+
+  def __init__(self, table, device):
+    super(ContentSettings, self).__init__()
+    assert (device.build_version_sdk
+            >= constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN), (
+        'ContentSettings supported only on SDK 16 and later')
+    self._table = table
+    self._device = device
+
+  @staticmethod
+  def _GetTypeBinding(value):
+    if isinstance(value, bool):
+      return 'b'
+    if isinstance(value, float):
+      return 'f'
+    if isinstance(value, int):
+      return 'i'
+    if isinstance(value, long):
+      return 'l'
+    if isinstance(value, str):
+      return 's'
+    raise ValueError('Unsupported type %s' % type(value))
+
+  def iteritems(self):
+    # Example row:
+    # 'Row: 0 _id=13, name=logging_id2, value=-1fccbaa546705b05'
+    for row in self._device.RunShellCommand(
+        'content query --uri content://%s' % self._table, as_root=True):
+      fields = row.split(', ')
+      key = None
+      value = None
+      for field in fields:
+        k, _, v = field.partition('=')
+        if k == 'name':
+          key = v
+        elif k == 'value':
+          value = v
+      if not key:
+        continue
+      if not value:
+        value = ''
+      yield key, value
+
+  def __getitem__(self, key):
+    return self._device.RunShellCommand(
+        'content query --uri content://%s --where "name=\'%s\'" '
+        '--projection value' % (self._table, key), as_root=True).strip()
+
+  def __setitem__(self, key, value):
+    if key in self:
+      self._device.RunShellCommand(
+          'content update --uri content://%s '
+          '--bind value:%s:%s --where "name=\'%s\'"' % (
+              self._table,
+              self._GetTypeBinding(value), value, key),
+          as_root=True)
+    else:
+      self._device.RunShellCommand(
+          'content insert --uri content://%s '
+          '--bind name:%s:%s --bind value:%s:%s' % (
+              self._table,
+              self._GetTypeBinding(key), key,
+              self._GetTypeBinding(value), value),
+          as_root=True)
+
+  def __delitem__(self, key):
+    self._device.RunShellCommand(
+        'content delete --uri content://%s '
+        '--bind name:%s:%s' % (
+            self._table,
+            self._GetTypeBinding(key), key),
+        as_root=True)
diff --git a/build/android/pylib/device/OWNERS b/build/android/pylib/device/OWNERS
new file mode 100644
index 0000000..c35d7ac
--- /dev/null
+++ b/build/android/pylib/device/OWNERS
@@ -0,0 +1,2 @@
+jbudorick@chromium.org
+perezju@chromium.org
diff --git a/build/android/pylib/device/__init__.py b/build/android/pylib/device/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/android/pylib/device/__init__.py
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
new file mode 100644
index 0000000..8e8abf8
--- /dev/null
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -0,0 +1,573 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""This module wraps Android's adb tool.
+
+This is a thin wrapper around the adb interface. Any additional complexity
+should be delegated to a higher level (ex. DeviceUtils).
+"""
+
+import collections
+import errno
+import logging
+import os
+import re
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.device import decorators
+from pylib.device import device_errors
+from pylib.utils import timeout_retry
+
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 2
+
+_EMULATOR_RE = re.compile(r'^emulator-[0-9]+$')
+
+_READY_STATE = 'device'
+
+
+def _VerifyLocalFileExists(path):
+  """Verifies a local file exists.
+
+  Args:
+    path: Path to the local file.
+
+  Raises:
+    IOError: If the file doesn't exist.
+  """
+  if not os.path.exists(path):
+    raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path)
+
+
+DeviceStat = collections.namedtuple('DeviceStat',
+                                    ['st_mode', 'st_size', 'st_time'])
+
+
+class AdbWrapper(object):
+  """A wrapper around a local Android Debug Bridge executable."""
+
+  def __init__(self, device_serial):
+    """Initializes the AdbWrapper.
+
+    Args:
+      device_serial: The device serial number as a string.
+    """
+    if not device_serial:
+      raise ValueError('A device serial must be specified')
+    self._device_serial = str(device_serial)
+
+  # pylint: disable=unused-argument
+  @classmethod
+  def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
+    if cpu_affinity is not None:
+      cmd = ['taskset', '-c', str(cpu_affinity)]
+    else:
+      cmd = []
+    cmd.append(constants.GetAdbPath())
+    if device_serial is not None:
+      cmd.extend(['-s', device_serial])
+    cmd.extend(args)
+    return cmd
+  # pylint: enable=unused-argument
+
+  # pylint: disable=unused-argument
+  @classmethod
+  @decorators.WithTimeoutAndRetries
+  def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
+                 check_error=True, cpu_affinity=None):
+    status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
+        cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
+        timeout_retry.CurrentTimeoutThread().GetRemainingTime())
+    if status != 0:
+      raise device_errors.AdbCommandFailedError(
+          args, output, status, device_serial)
+    # This catches some errors, including when the device drops offline;
+    # unfortunately adb is very inconsistent with error reporting so many
+    # command failures present differently.
+    if check_error and output.startswith('error:'):
+      raise device_errors.AdbCommandFailedError(args, output)
+    return output
+  # pylint: enable=unused-argument
+
+  def _RunDeviceAdbCmd(self, args, timeout, retries, check_error=True):
+    """Runs an adb command on the device associated with this object.
+
+    Args:
+      args: A list of arguments to adb.
+      timeout: Timeout in seconds.
+      retries: Number of retries.
+      check_error: Check that the command doesn't return an error message. This
+        does NOT check the exit status of shell commands.
+
+    Returns:
+      The output of the command.
+    """
+    return self._RunAdbCmd(args, timeout=timeout, retries=retries,
+                           device_serial=self._device_serial,
+                           check_error=check_error)
+
+  def _IterRunDeviceAdbCmd(self, args, timeout):
+    """Runs an adb command and returns an iterator over its output lines.
+
+    Args:
+      args: A list of arguments to adb.
+      timeout: Timeout in seconds.
+
+    Yields:
+      The output of the command line by line.
+    """
+    return cmd_helper.IterCmdOutputLines(
+      self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
+
+  def __eq__(self, other):
+    """Consider instances equal if they refer to the same device.
+
+    Args:
+      other: The instance to compare equality with.
+
+    Returns:
+      True if the instances are considered equal, false otherwise.
+    """
+    return self._device_serial == str(other)
+
+  def __str__(self):
+    """The string representation of an instance.
+
+    Returns:
+      The device serial number as a string.
+    """
+    return self._device_serial
+
+  def __repr__(self):
+    return '%s(\'%s\')' % (self.__class__.__name__, self)
+
+  # pylint: disable=unused-argument
+  @classmethod
+  def IsServerOnline(cls):
+    status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
+    output = [int(x) for x in output.split()]
+    logging.info('PIDs for adb found: %r', output)
+    return status == 0
+  # pylint: enable=unused-argument
+
+  @classmethod
+  def KillServer(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries)
+
+  @classmethod
+  def StartServer(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    # CPU affinity is used to reduce adb instability http://crbug.com/268450
+    cls._RunAdbCmd(['start-server'], timeout=timeout, retries=retries,
+                   cpu_affinity=0)
+
+  @classmethod
+  def GetDevices(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """DEPRECATED. Refer to Devices(...) below."""
+    # TODO(jbudorick): Remove this function once no more clients are using it.
+    return cls.Devices(timeout=timeout, retries=retries)
+
+  @classmethod
+  def Devices(cls, is_ready=True, timeout=_DEFAULT_TIMEOUT,
+              retries=_DEFAULT_RETRIES):
+    """Get the list of active attached devices.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Yields:
+      AdbWrapper instances.
+    """
+    output = cls._RunAdbCmd(['devices'], timeout=timeout, retries=retries)
+    lines = (line.split() for line in output.splitlines())
+    return [AdbWrapper(line[0]) for line in lines
+            if len(line) == 2 and (not is_ready or line[1] == _READY_STATE)]
+
+  def GetDeviceSerial(self):
+    """Gets the device serial number associated with this object.
+
+    Returns:
+      Device serial number as a string.
+    """
+    return self._device_serial
+
+  def Push(self, local, remote, timeout=60*5, retries=_DEFAULT_RETRIES):
+    """Pushes a file from the host to the device.
+
+    Args:
+      local: Path on the host filesystem.
+      remote: Path on the device filesystem.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    _VerifyLocalFileExists(local)
+    self._RunDeviceAdbCmd(['push', local, remote], timeout, retries)
+
+  def Pull(self, remote, local, timeout=60*5, retries=_DEFAULT_RETRIES):
+    """Pulls a file from the device to the host.
+
+    Args:
+      remote: Path on the device filesystem.
+      local: Path on the host filesystem.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    cmd = ['pull', remote, local]
+    self._RunDeviceAdbCmd(cmd, timeout, retries)
+    try:
+      _VerifyLocalFileExists(local)
+    except IOError:
+      raise device_errors.AdbCommandFailedError(
+          cmd, 'File not found on host: %s' % local, device_serial=str(self))
+
+  def Shell(self, command, expect_status=0, timeout=_DEFAULT_TIMEOUT,
+            retries=_DEFAULT_RETRIES):
+    """Runs a shell command on the device.
+
+    Args:
+      command: A string with the shell command to run.
+      expect_status: (optional) Check that the command's exit status matches
+        this value. Default is 0. If set to None the test is skipped.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      The output of the shell command as a string.
+
+    Raises:
+      device_errors.AdbCommandFailedError: If the exit status doesn't match
+        |expect_status|.
+    """
+    if expect_status is None:
+      args = ['shell', command]
+    else:
+      args = ['shell', '%s; echo %%$?;' % command.rstrip()]
+    output = self._RunDeviceAdbCmd(args, timeout, retries, check_error=False)
+    if expect_status is not None:
+      output_end = output.rfind('%')
+      if output_end < 0:
+        # causes the status string to become empty and raise a ValueError
+        output_end = len(output)
+
+      try:
+        status = int(output[output_end+1:])
+      except ValueError:
+        logging.warning('exit status of shell command %r missing.', command)
+        raise device_errors.AdbShellCommandFailedError(
+            command, output, status=None, device_serial=self._device_serial)
+      output = output[:output_end]
+      if status != expect_status:
+        raise device_errors.AdbShellCommandFailedError(
+            command, output, status=status, device_serial=self._device_serial)
+    return output
+
+  def IterShell(self, command, timeout):
+    """Runs a shell command and returns an iterator over its output lines.
+
+    Args:
+      command: A string with the shell command to run.
+      timeout: Timeout in seconds.
+
+    Yields:
+      The output of the command line by line.
+    """
+    args = ['shell', command]
+    return cmd_helper.IterCmdOutputLines(
+      self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
+
+  def Ls(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """List the contents of a directory on the device.
+
+    Args:
+      path: Path on the device filesystem.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      A list of pairs (filename, stat) for each file found in the directory,
+      where the stat object has the properties: st_mode, st_size, and st_time.
+
+    Raises:
+      AdbCommandFailedError if |path| does not specify a valid and accessible
+          directory in the device.
+    """
+    def ParseLine(line):
+      cols = line.split(None, 3)
+      filename = cols.pop()
+      stat = DeviceStat(*[int(num, base=16) for num in cols])
+      return (filename, stat)
+
+    cmd = ['ls', path]
+    lines = self._RunDeviceAdbCmd(
+        cmd, timeout=timeout, retries=retries).splitlines()
+    if lines:
+      return [ParseLine(line) for line in lines]
+    else:
+      raise device_errors.AdbCommandFailedError(
+          cmd, 'path does not specify an accessible directory in the device',
+          device_serial=self._device_serial)
+
+  def Logcat(self, clear=False, dump=False, filter_specs=None,
+             logcat_format=None, ring_buffer=None, timeout=None,
+             retries=_DEFAULT_RETRIES):
+    """Get an iterable over the logcat output.
+
+    Args:
+      clear: If true, clear the logcat.
+      dump: If true, dump the current logcat contents.
+      filter_specs: If set, a list of specs to filter the logcat.
+      logcat_format: If set, the format in which the logcat should be output.
+        Options include "brief", "process", "tag", "thread", "raw", "time",
+        "threadtime", and "long"
+      ring_buffer: If set, a list of alternate ring buffers to request.
+        Options include "main", "system", "radio", "events", "crash" or "all".
+        The default is equivalent to ["main", "system", "crash"].
+      timeout: (optional) If set, timeout per try in seconds. If clear or dump
+        is set, defaults to _DEFAULT_TIMEOUT.
+      retries: (optional) If clear or dump is set, the number of retries to
+        attempt. Otherwise, does nothing.
+
+    Yields:
+      logcat output line by line.
+    """
+    cmd = ['logcat']
+    use_iter = True
+    if clear:
+      cmd.append('-c')
+      use_iter = False
+    if dump:
+      cmd.append('-d')
+      use_iter = False
+    if logcat_format:
+      cmd.extend(['-v', logcat_format])
+    if ring_buffer:
+      for buffer_name in ring_buffer:
+        cmd.extend(['-b', buffer_name])
+    if filter_specs:
+      cmd.extend(filter_specs)
+
+    if use_iter:
+      return self._IterRunDeviceAdbCmd(cmd, timeout)
+    else:
+      timeout = timeout if timeout is not None else _DEFAULT_TIMEOUT
+      return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()
+
+  def Forward(self, local, remote, timeout=_DEFAULT_TIMEOUT,
+              retries=_DEFAULT_RETRIES):
+    """Forward socket connections from the local socket to the remote socket.
+
+    Sockets are specified by one of:
+      tcp:<port>
+      localabstract:<unix domain socket name>
+      localreserved:<unix domain socket name>
+      localfilesystem:<unix domain socket name>
+      dev:<character device name>
+      jdwp:<process pid> (remote only)
+
+    Args:
+      local: The host socket.
+      remote: The device socket.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    self._RunDeviceAdbCmd(['forward', str(local), str(remote)], timeout,
+                          retries)
+
+  def JDWP(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """List of PIDs of processes hosting a JDWP transport.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      A list of PIDs as strings.
+    """
+    return [a.strip() for a in
+            self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
+
+  def Install(self, apk_path, forward_lock=False, reinstall=False,
+              sd_card=False, timeout=60*2, retries=_DEFAULT_RETRIES):
+    """Install an apk on the device.
+
+    Args:
+      apk_path: Host path to the APK file.
+      forward_lock: (optional) If set forward-locks the app.
+      reinstall: (optional) If set reinstalls the app, keeping its data.
+      sd_card: (optional) If set installs on the SD card.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    _VerifyLocalFileExists(apk_path)
+    cmd = ['install']
+    if forward_lock:
+      cmd.append('-l')
+    if reinstall:
+      cmd.append('-r')
+    if sd_card:
+      cmd.append('-s')
+    cmd.append(apk_path)
+    output = self._RunDeviceAdbCmd(cmd, timeout, retries)
+    if 'Success' not in output:
+      raise device_errors.AdbCommandFailedError(
+          cmd, output, device_serial=self._device_serial)
+
+  def Uninstall(self, package, keep_data=False, timeout=_DEFAULT_TIMEOUT,
+                retries=_DEFAULT_RETRIES):
+    """Remove the app |package| from the device.
+
+    Args:
+      package: The package to uninstall.
+      keep_data: (optional) If set keep the data and cache directories.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    cmd = ['uninstall']
+    if keep_data:
+      cmd.append('-k')
+    cmd.append(package)
+    output = self._RunDeviceAdbCmd(cmd, timeout, retries)
+    if 'Failure' in output:
+      raise device_errors.AdbCommandFailedError(
+          cmd, output, device_serial=self._device_serial)
+
+  def Backup(self, path, packages=None, apk=False, shared=False,
+             nosystem=True, include_all=False, timeout=_DEFAULT_TIMEOUT,
+             retries=_DEFAULT_RETRIES):
+    """Write an archive of the device's data to |path|.
+
+    Args:
+      path: Local path to store the backup file.
+      packages: List of to packages to be backed up.
+      apk: (optional) If set include the .apk files in the archive.
+      shared: (optional) If set buckup the device's SD card.
+      nosystem: (optional) If set exclude system applications.
+      include_all: (optional) If set back up all installed applications and
+        |packages| is optional.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    cmd = ['backup', '-f', path]
+    if apk:
+      cmd.append('-apk')
+    if shared:
+      cmd.append('-shared')
+    if nosystem:
+      cmd.append('-nosystem')
+    if include_all:
+      cmd.append('-all')
+    if packages:
+      cmd.extend(packages)
+    assert bool(packages) ^ bool(include_all), (
+        'Provide \'packages\' or set \'include_all\' but not both.')
+    ret = self._RunDeviceAdbCmd(cmd, timeout, retries)
+    _VerifyLocalFileExists(path)
+    return ret
+
+  def Restore(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """Restore device contents from the backup archive.
+
+    Args:
+      path: Host path to the backup archive.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    _VerifyLocalFileExists(path)
+    self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries)
+
+  def WaitForDevice(self, timeout=60*5, retries=_DEFAULT_RETRIES):
+    """Block until the device is online.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries)
+
+  def GetState(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """Get device state.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      One of 'offline', 'bootloader', or 'device'.
+    """
+    return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()
+
+  def GetDevPath(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """Gets the device path.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      The device path (e.g. usb:3-4)
+    """
+    return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries)
+
+  def Remount(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """Remounts the /system partition on the device read-write."""
+    self._RunDeviceAdbCmd(['remount'], timeout, retries)
+
+  def Reboot(self, to_bootloader=False, timeout=60*5,
+             retries=_DEFAULT_RETRIES):
+    """Reboots the device.
+
+    Args:
+      to_bootloader: (optional) If set reboots to the bootloader.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    if to_bootloader:
+      cmd = ['reboot-bootloader']
+    else:
+      cmd = ['reboot']
+    self._RunDeviceAdbCmd(cmd, timeout, retries)
+
+  def Root(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
+    """Restarts the adbd daemon with root permissions, if possible.
+
+    Args:
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+    """
+    output = self._RunDeviceAdbCmd(['root'], timeout, retries)
+    if 'cannot' in output:
+      raise device_errors.AdbCommandFailedError(
+          ['root'], output, device_serial=self._device_serial)
+
+  def Emu(self, cmd, timeout=_DEFAULT_TIMEOUT,
+               retries=_DEFAULT_RETRIES):
+    """Runs an emulator console command.
+
+    See http://developer.android.com/tools/devices/emulator.html#console
+
+    Args:
+      cmd: The command to run on the emulator console.
+      timeout: (optional) Timeout per try in seconds.
+      retries: (optional) Number of retries to attempt.
+
+    Returns:
+      The output of the emulator console command.
+    """
+    if isinstance(cmd, basestring):
+      cmd = [cmd]
+    return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)
+
+  @property
+  def is_emulator(self):
+    return _EMULATOR_RE.match(self._device_serial)
+
+  @property
+  def is_ready(self):
+    try:
+      return self.GetState() == _READY_STATE
+    except device_errors.CommandFailedError:
+      return False
+
diff --git a/build/android/pylib/device/adb_wrapper_test.py b/build/android/pylib/device/adb_wrapper_test.py
new file mode 100644
index 0000000..5fc9eb6
--- /dev/null
+++ b/build/android/pylib/device/adb_wrapper_test.py
@@ -0,0 +1,96 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for the AdbWrapper class."""
+
+import os
+import tempfile
+import time
+import unittest
+
+from pylib.device import adb_wrapper
+from pylib.device import device_errors
+
+
+class TestAdbWrapper(unittest.TestCase):
+
+  def setUp(self):
+    devices = adb_wrapper.AdbWrapper.Devices()
+    assert devices, 'A device must be attached'
+    self._adb = devices[0]
+    self._adb.WaitForDevice()
+
+  @staticmethod
+  def _MakeTempFile(contents):
+    """Make a temporary file with the given contents.
+
+    Args:
+      contents: string to write to the temporary file.
+
+    Returns:
+      The absolute path to the file.
+    """
+    fi, path = tempfile.mkstemp()
+    with os.fdopen(fi, 'wb') as f:
+      f.write(contents)
+    return path
+
+  def testShell(self):
+    output = self._adb.Shell('echo test', expect_status=0)
+    self.assertEqual(output.strip(), 'test')
+    output = self._adb.Shell('echo test')
+    self.assertEqual(output.strip(), 'test')
+    with self.assertRaises(device_errors.AdbCommandFailedError):
+        self._adb.Shell('echo test', expect_status=1)
+
+  def testPushLsPull(self):
+    path = self._MakeTempFile('foo')
+    device_path = '/data/local/tmp/testfile.txt'
+    local_tmpdir = os.path.dirname(path)
+    self._adb.Push(path, device_path)
+    files = dict(self._adb.Ls('/data/local/tmp'))
+    self.assertTrue('testfile.txt' in files)
+    self.assertEquals(3, files['testfile.txt'].st_size)
+    self.assertEqual(self._adb.Shell('cat %s' % device_path), 'foo')
+    self._adb.Pull(device_path, local_tmpdir)
+    with open(os.path.join(local_tmpdir, 'testfile.txt'), 'r') as f:
+      self.assertEqual(f.read(), 'foo')
+
+  def testInstall(self):
+    path = self._MakeTempFile('foo')
+    with self.assertRaises(device_errors.AdbCommandFailedError):
+      self._adb.Install(path)
+
+  def testForward(self):
+    with self.assertRaises(device_errors.AdbCommandFailedError):
+      self._adb.Forward(0, 0)
+
+  def testUninstall(self):
+    with self.assertRaises(device_errors.AdbCommandFailedError):
+      self._adb.Uninstall('some.nonexistant.package')
+
+  def testRebootWaitForDevice(self):
+    self._adb.Reboot()
+    print 'waiting for device to reboot...'
+    while self._adb.GetState() == 'device':
+      time.sleep(1)
+    self._adb.WaitForDevice()
+    self.assertEqual(self._adb.GetState(), 'device')
+    print 'waiting for package manager...'
+    while 'package:' not in self._adb.Shell('pm path android'):
+      time.sleep(1)
+
+  def testRootRemount(self):
+    self._adb.Root()
+    while True:
+      try:
+        self._adb.Shell('start')
+        break
+      except device_errors.AdbCommandFailedError:
+        time.sleep(1)
+    self._adb.Remount()
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/device/battery_utils.py b/build/android/pylib/device/battery_utils.py
new file mode 100644
index 0000000..ed66591
--- /dev/null
+++ b/build/android/pylib/device/battery_utils.py
@@ -0,0 +1,405 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Provides a variety of device interactions with power.
+"""
+# pylint: disable=unused-argument
+
+import collections
+import contextlib
+import csv
+import logging
+
+from pylib import constants
+from pylib.device import decorators
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.utils import timeout_retry
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+
+_CONTROL_CHARGING_COMMANDS = [
+  {
+    # Nexus 4
+    'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
+    'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled',
+    'disable_command':
+        'echo 1 > /sys/module/pm8921_charger/parameters/disabled',
+  },
+  {
+    # Nexus 5
+    # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
+    # energy coming from USB. Setting the power_supply offline just updates the
+    # Android system to reflect that.
+    'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
+    'enable_command': (
+        'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
+        'echo 1 > /sys/class/power_supply/usb/online'),
+    'disable_command': (
+        'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
+        'chmod 644 /sys/class/power_supply/usb/online && '
+        'echo 0 > /sys/class/power_supply/usb/online'),
+  },
+]
+
+# The list of useful dumpsys columns.
+# Index of the column containing the format version.
+_DUMP_VERSION_INDEX = 0
+# Index of the column containing the type of the row.
+_ROW_TYPE_INDEX = 3
+# Index of the column containing the uid.
+_PACKAGE_UID_INDEX = 4
+# Index of the column containing the application package.
+_PACKAGE_NAME_INDEX = 5
+# The column containing the uid of the power data.
+_PWI_UID_INDEX = 1
+# The column containing the type of consumption. Only consumtion since last
+# charge are of interest here.
+_PWI_AGGREGATION_INDEX = 2
+# The column containing the amount of power used, in mah.
+_PWI_POWER_CONSUMPTION_INDEX = 5
+
+
+class BatteryUtils(object):
+
+  def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
+               default_retries=_DEFAULT_RETRIES):
+    """BatteryUtils constructor.
+
+      Args:
+        device: A DeviceUtils instance.
+        default_timeout: An integer containing the default number of seconds to
+                         wait for an operation to complete if no explicit value
+                         is provided.
+        default_retries: An integer containing the default number or times an
+                         operation should be retried on failure if no explicit
+                         value is provided.
+
+      Raises:
+        TypeError: If it is not passed a DeviceUtils instance.
+    """
+    if not isinstance(device, device_utils.DeviceUtils):
+      raise TypeError('Must be initialized with DeviceUtils object.')
+    self._device = device
+    self._cache = device.GetClientCache(self.__class__.__name__)
+    self._default_timeout = default_timeout
+    self._default_retries = default_retries
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetNetworkData(self, package, timeout=None, retries=None):
+    """ Get network data for specific package.
+
+    Args:
+      package: package name you want network data for.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      Tuple of (sent_data, recieved_data)
+      None if no network data found
+    """
+    # If device_utils clears cache, cache['uids'] doesn't exist
+    if 'uids' not in self._cache:
+      self._cache['uids'] = {}
+    if package not in self._cache['uids']:
+      self.GetPowerData()
+      if package not in self._cache['uids']:
+        logging.warning('No UID found for %s. Can\'t get network data.',
+                        package)
+        return None
+
+    network_data_path = '/proc/uid_stat/%s/' % self._cache['uids'][package]
+    try:
+      send_data = int(self._device.ReadFile(network_data_path + 'tcp_snd'))
+    # If ReadFile throws exception, it means no network data usage file for
+    # package has been recorded. Return 0 sent and 0 received.
+    except device_errors.AdbShellCommandFailedError:
+      logging.warning('No sent data found for package %s', package)
+      send_data = 0
+    try:
+      recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv'))
+    except device_errors.AdbShellCommandFailedError:
+      logging.warning('No received data found for package %s', package)
+      recv_data = 0
+    return (send_data, recv_data)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetPowerData(self, timeout=None, retries=None):
+    """ Get power data for device.
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      Dict of power data, keyed on package names.
+      {
+        package_name: {
+          'uid': uid,
+          'data': [1,2,3]
+        },
+      }
+    """
+    if 'uids' not in self._cache:
+      self._cache['uids'] = {}
+    dumpsys_output = self._device.RunShellCommand(
+        ['dumpsys', 'batterystats', '-c'], check_return=True)
+    csvreader = csv.reader(dumpsys_output)
+    pwi_entries = collections.defaultdict(list)
+    for entry in csvreader:
+      if entry[_DUMP_VERSION_INDEX] not in ['8', '9']:
+        # Wrong dumpsys version.
+        raise device_errors.DeviceVersionError(
+            'Dumpsys version must be 8 or 9. %s found.'
+            % entry[_DUMP_VERSION_INDEX])
+      if _ROW_TYPE_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'uid':
+        current_package = entry[_PACKAGE_NAME_INDEX]
+        if (self._cache['uids'].get(current_package)
+            and self._cache['uids'].get(current_package)
+            != entry[_PACKAGE_UID_INDEX]):
+          raise device_errors.CommandFailedError(
+              'Package %s found multiple times with differnt UIDs %s and %s'
+               % (current_package, self._cache['uids'][current_package],
+               entry[_PACKAGE_UID_INDEX]))
+        self._cache['uids'][current_package] = entry[_PACKAGE_UID_INDEX]
+      elif (_PWI_POWER_CONSUMPTION_INDEX < len(entry)
+          and entry[_ROW_TYPE_INDEX] == 'pwi'
+          and entry[_PWI_AGGREGATION_INDEX] == 'l'):
+        pwi_entries[entry[_PWI_UID_INDEX]].append(
+            float(entry[_PWI_POWER_CONSUMPTION_INDEX]))
+
+    return {p: {'uid': uid, 'data': pwi_entries[uid]}
+            for p, uid in self._cache['uids'].iteritems()}
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetPackagePowerData(self, package, timeout=None, retries=None):
+    """ Get power data for particular package.
+
+    Args:
+      package: Package to get power data on.
+
+    returns:
+      Dict of UID and power data.
+      {
+        'uid': uid,
+        'data': [1,2,3]
+      }
+      None if the package is not found in the power data.
+    """
+    return self.GetPowerData().get(package)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetBatteryInfo(self, timeout=None, retries=None):
+    """Gets battery info for the device.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+    Returns:
+      A dict containing various battery information as reported by dumpsys
+      battery.
+    """
+    result = {}
+    # Skip the first line, which is just a header.
+    for line in self._device.RunShellCommand(
+        ['dumpsys', 'battery'], check_return=True)[1:]:
+      # If usb charging has been disabled, an extra line of header exists.
+      if 'UPDATES STOPPED' in line:
+        logging.warning('Dumpsys battery not receiving updates. '
+                        'Run dumpsys battery reset if this is in error.')
+      elif ':' not in line:
+        logging.warning('Unknown line found in dumpsys battery: "%s"', line)
+      else:
+        k, v = line.split(':', 1)
+        result[k.strip()] = v.strip()
+    return result
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetCharging(self, timeout=None, retries=None):
+    """Gets the charging state of the device.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+    Returns:
+      True if the device is charging, false otherwise.
+    """
+    battery_info = self.GetBatteryInfo()
+    for k in ('AC powered', 'USB powered', 'Wireless powered'):
+      if (k in battery_info and
+          battery_info[k].lower() in ('true', '1', 'yes')):
+        return True
+    return False
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SetCharging(self, enabled, timeout=None, retries=None):
+    """Enables or disables charging on the device.
+
+    Args:
+      enabled: A boolean indicating whether charging should be enabled or
+        disabled.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      device_errors.CommandFailedError: If method of disabling charging cannot
+        be determined.
+    """
+    if 'charging_config' not in self._cache:
+      for c in _CONTROL_CHARGING_COMMANDS:
+        if self._device.FileExists(c['witness_file']):
+          self._cache['charging_config'] = c
+          break
+      else:
+        raise device_errors.CommandFailedError(
+            'Unable to find charging commands.')
+
+    if enabled:
+      command = self._cache['charging_config']['enable_command']
+    else:
+      command = self._cache['charging_config']['disable_command']
+
+    def set_and_verify_charging():
+      self._device.RunShellCommand(command, check_return=True)
+      return self.GetCharging() == enabled
+
+    timeout_retry.WaitFor(set_and_verify_charging, wait_period=1)
+
+  # TODO(rnephew): Make private when all use cases can use the context manager.
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def DisableBatteryUpdates(self, timeout=None, retries=None):
+    """ Resets battery data and makes device appear like it is not
+    charging so that it will collect power data since last charge.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      device_errors.CommandFailedError: When resetting batterystats fails to
+        reset power values.
+      device_errors.DeviceVersionError: If device is not L or higher.
+    """
+    def battery_updates_disabled():
+      return self.GetCharging() is False
+
+    if (self._device.build_version_sdk <
+        constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
+      raise device_errors.DeviceVersionError('Device must be L or higher.')
+
+    self._device.RunShellCommand(
+        ['dumpsys', 'battery', 'reset'], check_return=True)
+    self._device.RunShellCommand(
+        ['dumpsys', 'batterystats', '--reset'], check_return=True)
+    battery_data = self._device.RunShellCommand(
+        ['dumpsys', 'batterystats', '--charged', '--checkin'],
+        check_return=True)
+    ROW_TYPE_INDEX = 3
+    PWI_POWER_INDEX = 5
+    for line in battery_data:
+      l = line.split(',')
+      if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi'
+          and l[PWI_POWER_INDEX] != 0):
+        raise device_errors.CommandFailedError(
+            'Non-zero pmi value found after reset.')
+    self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'],
+                                 check_return=True)
+    self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'],
+                                 check_return=True)
+    timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
+
+  # TODO(rnephew): Make private when all use cases can use the context manager.
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def EnableBatteryUpdates(self, timeout=None, retries=None):
+    """ Restarts device charging so that dumpsys no longer collects power data.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      device_errors.DeviceVersionError: If device is not L or higher.
+    """
+    def battery_updates_enabled():
+      return self.GetCharging() is True
+
+    if (self._device.build_version_sdk <
+        constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
+      raise device_errors.DeviceVersionError('Device must be L or higher.')
+
+    self._device.RunShellCommand(['dumpsys', 'battery', 'reset'],
+                                 check_return=True)
+    timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
+
+  @contextlib.contextmanager
+  def BatteryMeasurement(self, timeout=None, retries=None):
+    """Context manager that enables battery data collection. It makes
+    the device appear to stop charging so that dumpsys will start collecting
+    power data since last charge. Once the with block is exited, charging is
+    resumed and power data since last charge is no longer collected.
+
+    Only for devices L and higher.
+
+    Example usage:
+      with BatteryMeasurement():
+        browser_actions()
+        get_power_data() # report usage within this block
+      after_measurements() # Anything that runs after power
+                           # measurements are collected
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      device_errors.DeviceVersionError: If device is not L or higher.
+    """
+    if (self._device.build_version_sdk <
+        constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
+      raise device_errors.DeviceVersionError('Device must be L or higher.')
+    try:
+      self.DisableBatteryUpdates(timeout=timeout, retries=retries)
+      yield
+    finally:
+      self.EnableBatteryUpdates(timeout=timeout, retries=retries)
+
+  def ChargeDeviceToLevel(self, level, wait_period=60):
+    """Enables charging and waits for device to be charged to given level.
+
+    Args:
+      level: level of charge to wait for.
+      wait_period: time in seconds to wait between checking.
+    """
+    self.SetCharging(True)
+
+    def device_charged():
+      battery_level = self.GetBatteryInfo().get('level')
+      if battery_level is None:
+        logging.warning('Unable to find current battery level.')
+        battery_level = 100
+      else:
+        logging.info('current battery level: %s', battery_level)
+        battery_level = int(battery_level)
+      return battery_level >= level
+
+    timeout_retry.WaitFor(device_charged, wait_period=wait_period)
+
+  def LetBatteryCoolToTemperature(self, target_temp, wait_period=60):
+    """Lets device sit to give battery time to cool down
+    Args:
+      temp: maximum temperature to allow in tenths of degrees c.
+      wait_period: time in seconds to wait between checking.
+    """
+    def cool_device():
+      temp = self.GetBatteryInfo().get('temperature')
+      if temp is None:
+        logging.warning('Unable to find current battery temperature.')
+        temp = 0
+      else:
+        logging.info('Current battery temperature: %s', temp)
+      return int(temp) <= target_temp
+
+    logging.info('Waiting for the device to cool down to %s degrees.',
+                 target_temp)
+    timeout_retry.WaitFor(cool_device, wait_period=wait_period)
diff --git a/build/android/pylib/device/battery_utils_test.py b/build/android/pylib/device/battery_utils_test.py
new file mode 100755
index 0000000..72799b8
--- /dev/null
+++ b/build/android/pylib/device/battery_utils_test.py
@@ -0,0 +1,328 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for the contents of battery_utils.py
+"""
+
+# pylint: disable=W0613
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import battery_utils
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.device import device_utils_test
+from pylib.utils import mock_calls
+
+# RunCommand from third_party/android_testrunner/run_command.py is mocked
+# below, so its path needs to be in sys.path.
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner'))
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+_DUMPSYS_OUTPUT = [
+    '9,0,i,uid,1000,test_package1',
+    '9,0,i,uid,1001,test_package2',
+    '9,1000,l,pwi,uid,1',
+    '9,1001,l,pwi,uid,2'
+]
+
+
+class BatteryUtilsTest(mock_calls.TestCase):
+
+  def ShellError(self, output=None, status=1):
+    def action(cmd, *args, **kwargs):
+      raise device_errors.AdbShellCommandFailedError(
+          cmd, output, status, str(self.device))
+    if output is None:
+      output = 'Permission denied\n'
+    return action
+
+  def setUp(self):
+    self.adb = device_utils_test._AdbWrapperMock('0123456789abcdef')
+    self.device = device_utils.DeviceUtils(
+        self.adb, default_timeout=10, default_retries=0)
+    self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
+    self.battery = battery_utils.BatteryUtils(
+        self.device, default_timeout=10, default_retries=0)
+
+
+class BatteryUtilsInitTest(unittest.TestCase):
+
+  def testInitWithDeviceUtil(self):
+    serial = '0fedcba987654321'
+    d = device_utils.DeviceUtils(serial)
+    b = battery_utils.BatteryUtils(d)
+    self.assertEqual(d, b._device)
+
+  def testInitWithMissing_fails(self):
+    with self.assertRaises(TypeError):
+      battery_utils.BatteryUtils(None)
+    with self.assertRaises(TypeError):
+      battery_utils.BatteryUtils('')
+
+
+class BatteryUtilsSetChargingTest(BatteryUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetCharging_enabled(self):
+    with self.assertCalls(
+        (self.call.device.FileExists(mock.ANY), True),
+        (self.call.device.RunShellCommand(mock.ANY, check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(mock.ANY, check_return=True), []),
+        (self.call.battery.GetCharging(), True)):
+      self.battery.SetCharging(True)
+
+  def testSetCharging_alreadyEnabled(self):
+    with self.assertCalls(
+        (self.call.device.FileExists(mock.ANY), True),
+        (self.call.device.RunShellCommand(mock.ANY, check_return=True), []),
+        (self.call.battery.GetCharging(), True)):
+      self.battery.SetCharging(True)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testSetCharging_disabled(self):
+    with self.assertCalls(
+        (self.call.device.FileExists(mock.ANY), True),
+        (self.call.device.RunShellCommand(mock.ANY, check_return=True), []),
+        (self.call.battery.GetCharging(), True),
+        (self.call.device.RunShellCommand(mock.ANY, check_return=True), []),
+        (self.call.battery.GetCharging(), False)):
+      self.battery.SetCharging(False)
+
+
+class BatteryUtilsSetBatteryMeasurementTest(BatteryUtilsTest):
+
+  def testBatteryMeasurement(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            mock.ANY, retries=0, single_line=True,
+            timeout=10, check_return=True), '22'),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'reset'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '--charged', '--checkin'],
+            check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'reset'], check_return=True), []),
+        (self.call.battery.GetCharging(), True)):
+      with self.battery.BatteryMeasurement():
+        pass
+
+
+class BatteryUtilsGetPowerData(BatteryUtilsTest):
+
+  def testGetPowerData(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT)):
+      data = self.battery.GetPowerData()
+      check = {
+          'test_package1': {'uid': '1000', 'data': [1.0]},
+          'test_package2': {'uid': '1001', 'data': [2.0]}
+      }
+      self.assertEqual(data, check)
+
+  def testGetPowerData_packageCollisionSame(self):
+      self.battery._cache['uids'] = {'test_package1': '1000'}
+      with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT):
+        data = self.battery.GetPowerData()
+        check = {
+            'test_package1': {'uid': '1000', 'data': [1.0]},
+            'test_package2': {'uid': '1001', 'data': [2.0]}
+        }
+        self.assertEqual(data, check)
+
+  def testGetPowerData_packageCollisionDifferent(self):
+      self.battery._cache['uids'] = {'test_package1': '1'}
+      with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT):
+        with self.assertRaises(device_errors.CommandFailedError):
+          self.battery.GetPowerData()
+
+  def testGetPowerData_cacheCleared(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT)):
+      self.battery._cache.clear()
+      data = self.battery.GetPowerData()
+      check = {
+          'test_package1': {'uid': '1000', 'data': [1.0]},
+          'test_package2': {'uid': '1001', 'data': [2.0]}
+      }
+      self.assertEqual(data, check)
+
+  def testGetPackagePowerData(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT)):
+      data = self.battery.GetPackagePowerData('test_package2')
+      self.assertEqual(data, {'uid': '1001', 'data': [2.0]})
+
+  def testGetPackagePowerData_badPackage(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT)):
+      data = self.battery.GetPackagePowerData('not_a_package')
+      self.assertEqual(data, None)
+
+
+class BatteryUtilsChargeDevice(BatteryUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testChargeDeviceToLevel(self):
+    with self.assertCalls(
+        (self.call.battery.SetCharging(True)),
+        (self.call.battery.GetBatteryInfo(), {'level': '50'}),
+        (self.call.battery.GetBatteryInfo(), {'level': '100'})):
+      self.battery.ChargeDeviceToLevel(95)
+
+
+class BatteryUtilsGetBatteryInfoTest(BatteryUtilsTest):
+
+  def testGetBatteryInfo_normal(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True),
+        [
+          'Current Battery Service state:',
+          '  AC powered: false',
+          '  USB powered: true',
+          '  level: 100',
+          '  temperature: 321',
+        ]):
+      self.assertEquals(
+          {
+            'AC powered': 'false',
+            'USB powered': 'true',
+            'level': '100',
+            'temperature': '321',
+          },
+          self.battery.GetBatteryInfo())
+
+  def testGetBatteryInfo_nothing(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True), []):
+      self.assertEquals({}, self.battery.GetBatteryInfo())
+
+
+class BatteryUtilsGetChargingTest(BatteryUtilsTest):
+
+  def testGetCharging_usb(self):
+    with self.assertCall(
+        self.call.battery.GetBatteryInfo(), {'USB powered': 'true'}):
+      self.assertTrue(self.battery.GetCharging())
+
+  def testGetCharging_usbFalse(self):
+    with self.assertCall(
+        self.call.battery.GetBatteryInfo(), {'USB powered': 'false'}):
+      self.assertFalse(self.battery.GetCharging())
+
+  def testGetCharging_ac(self):
+    with self.assertCall(
+        self.call.battery.GetBatteryInfo(), {'AC powered': 'true'}):
+      self.assertTrue(self.battery.GetCharging())
+
+  def testGetCharging_wireless(self):
+    with self.assertCall(
+        self.call.battery.GetBatteryInfo(), {'Wireless powered': 'true'}):
+      self.assertTrue(self.battery.GetCharging())
+
+  def testGetCharging_unknown(self):
+    with self.assertCall(
+        self.call.battery.GetBatteryInfo(), {'level': '42'}):
+      self.assertFalse(self.battery.GetCharging())
+
+
+class BatteryUtilsGetNetworkDataTest(BatteryUtilsTest):
+
+  def testGetNetworkData_noDataUsage(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'),
+            self.ShellError()),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'),
+            self.ShellError())):
+      self.assertEquals(self.battery.GetNetworkData('test_package1'), (0, 0))
+
+  def testGetNetworkData_badPackage(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT):
+      self.assertEqual(self.battery.GetNetworkData('asdf'), None)
+
+  def testGetNetworkData_packageNotCached(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)):
+      self.assertEqual(self.battery.GetNetworkData('test_package1'), (1,2))
+
+  def testGetNetworkData_packageCached(self):
+    self.battery._cache['uids'] = {'test_package1': '1000'}
+    with self.assertCalls(
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)):
+      self.assertEqual(self.battery.GetNetworkData('test_package1'), (1,2))
+
+  def testGetNetworkData_clearedCache(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '-c'], check_return=True),
+            _DUMPSYS_OUTPUT),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1),
+        (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)):
+      self.battery._cache.clear()
+      self.assertEqual(self.battery.GetNetworkData('test_package1'), (1,2))
+
+class BatteryUtilsLetBatteryCoolToTemperatureTest(BatteryUtilsTest):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testLetBatteryCoolToTemperature_startUnder(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'temperature': '500'})):
+      self.battery.LetBatteryCoolToTemperature(600)
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testLetBatteryCoolToTemperature_startOver(self):
+    with self.assertCalls(
+        (self.call.battery.GetBatteryInfo(), {'temperature': '500'}),
+        (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
+      self.battery.LetBatteryCoolToTemperature(400)
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/pylib/device/commands/BUILD.gn b/build/android/pylib/device/commands/BUILD.gn
new file mode 100644
index 0000000..66e1010
--- /dev/null
+++ b/build/android/pylib/device/commands/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+group("commands") {
+  datadeps = [
+    ":chromium_commands",
+  ]
+}
+
+# GYP: //build/android/pylib/device/commands/commands.gyp:chromium_commands
+android_library("chromium_commands") {
+  java_files = [ "java/src/org/chromium/android/commands/unzip/Unzip.java" ]
+  dex_path = "$root_build_dir/lib.java/chromium_commands.dex.jar"
+}
diff --git a/build/android/pylib/device/commands/__init__.py b/build/android/pylib/device/commands/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/device/commands/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/device/commands/commands.gyp b/build/android/pylib/device/commands/commands.gyp
new file mode 100644
index 0000000..b5b5bc8
--- /dev/null
+++ b/build/android/pylib/device/commands/commands.gyp
@@ -0,0 +1,20 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      # GN version: //build/android/pylib/devices/commands:chromium_commands
+      'target_name': 'chromium_commands',
+      'type': 'none',
+      'variables': {
+        'add_to_dependents_classpaths': 0,
+        'java_in_dir': ['java'],
+      },
+      'includes': [
+        '../../../../../build/java.gypi',
+      ],
+    }
+  ],
+}
diff --git a/build/android/pylib/device/commands/install_commands.py b/build/android/pylib/device/commands/install_commands.py
new file mode 100644
index 0000000..58c56cc
--- /dev/null
+++ b/build/android/pylib/device/commands/install_commands.py
@@ -0,0 +1,51 @@
+# Copyright 2014 The Chromium 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 os
+
+from pylib import constants
+
+BIN_DIR = '%s/bin' % constants.TEST_EXECUTABLE_DIR
+_FRAMEWORK_DIR = '%s/framework' % constants.TEST_EXECUTABLE_DIR
+
+_COMMANDS = {
+  'unzip': 'org.chromium.android.commands.unzip.Unzip',
+}
+
+_SHELL_COMMAND_FORMAT = (
+"""#!/system/bin/sh
+base=%s
+export CLASSPATH=$base/framework/chromium_commands.jar
+exec app_process $base/bin %s $@
+""")
+
+
+def Installed(device):
+  return (all(device.FileExists('%s/%s' % (BIN_DIR, c)) for c in _COMMANDS)
+          and device.FileExists('%s/chromium_commands.jar' % _FRAMEWORK_DIR))
+
+def InstallCommands(device):
+  if device.IsUserBuild():
+    raise Exception('chromium_commands currently requires a userdebug build.')
+
+  chromium_commands_jar_path = os.path.join(
+      constants.GetOutDirectory(), constants.SDK_BUILD_JAVALIB_DIR,
+      'chromium_commands.dex.jar')
+  if not os.path.exists(chromium_commands_jar_path):
+    raise Exception('%s not found. Please build chromium_commands.'
+                    % chromium_commands_jar_path)
+
+  device.RunShellCommand(['mkdir', BIN_DIR, _FRAMEWORK_DIR])
+  for command, main_class in _COMMANDS.iteritems():
+    shell_command = _SHELL_COMMAND_FORMAT % (
+        constants.TEST_EXECUTABLE_DIR, main_class)
+    shell_file = '%s/%s' % (BIN_DIR, command)
+    device.WriteFile(shell_file, shell_command)
+    device.RunShellCommand(
+        ['chmod', '755', shell_file], check_return=True)
+
+  device.adb.Push(
+      chromium_commands_jar_path,
+      '%s/chromium_commands.jar' % _FRAMEWORK_DIR)
+
diff --git a/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java b/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java
new file mode 100644
index 0000000..4d2a045
--- /dev/null
+++ b/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.android.commands.unzip;
+
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ *  Minimal implementation of the command-line unzip utility for Android.
+ */
+public class Unzip {
+
+    private static final String TAG = "Unzip";
+
+    public static void main(String[] args) {
+        try {
+            (new Unzip()).run(args);
+        } catch (RuntimeException e) {
+            Log.e(TAG, e.toString());
+            System.exit(1);
+        }
+    }
+
+    private void showUsage(PrintStream s) {
+        s.println("Usage:");
+        s.println("unzip [zipfile]");
+    }
+
+    private void unzip(String[] args) {
+        ZipInputStream zis = null;
+        try {
+            String zipfile = args[0];
+            zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipfile)));
+            ZipEntry ze = null;
+
+            byte[] bytes = new byte[1024];
+            while ((ze = zis.getNextEntry()) != null) {
+                File outputFile = new File(ze.getName());
+                if (ze.isDirectory()) {
+                    if (!outputFile.exists() && !outputFile.mkdirs()) {
+                        throw new RuntimeException(
+                                "Failed to create directory: " + outputFile.toString());
+                    }
+                } else {
+                    File parentDir = outputFile.getParentFile();
+                    if (!parentDir.exists() && !parentDir.mkdirs()) {
+                        throw new RuntimeException(
+                                "Failed to create directory: " + parentDir.toString());
+                    }
+                    OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFile));
+                    int actual_bytes = 0;
+                    int total_bytes = 0;
+                    while ((actual_bytes = zis.read(bytes)) != -1) {
+                        out.write(bytes, 0, actual_bytes);
+                        total_bytes += actual_bytes;
+                    }
+                    out.close();
+                }
+                zis.closeEntry();
+            }
+
+        } catch (IOException e) {
+            throw new RuntimeException("Error while unzipping: " + e.toString());
+        } finally {
+            try {
+                if (zis != null) zis.close();
+            } catch (IOException e) {
+                throw new RuntimeException("Error while closing zip: " + e.toString());
+            }
+        }
+    }
+
+    public void run(String[] args) {
+        if (args.length != 1) {
+            showUsage(System.err);
+            throw new RuntimeException("Incorrect usage.");
+        }
+
+        unzip(args);
+    }
+}
+
diff --git a/build/android/pylib/device/decorators.py b/build/android/pylib/device/decorators.py
new file mode 100644
index 0000000..73c13da
--- /dev/null
+++ b/build/android/pylib/device/decorators.py
@@ -0,0 +1,157 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Function/method decorators that provide timeout and retry logic.
+"""
+
+import functools
+import os
+import sys
+import threading
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.device import device_errors
+from pylib.utils import reraiser_thread
+from pylib.utils import timeout_retry
+
+# TODO(jbudorick) Remove once the DeviceUtils implementations are no longer
+#                 backed by AndroidCommands / android_testrunner.
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'third_party',
+                             'android_testrunner'))
+import errors as old_errors
+
+DEFAULT_TIMEOUT_ATTR = '_default_timeout'
+DEFAULT_RETRIES_ATTR = '_default_retries'
+
+
+def _TimeoutRetryWrapper(f, timeout_func, retries_func, pass_values=False):
+  """ Wraps a funcion with timeout and retry handling logic.
+
+  Args:
+    f: The function to wrap.
+    timeout_func: A callable that returns the timeout value.
+    retries_func: A callable that returns the retries value.
+    pass_values: If True, passes the values returned by |timeout_func| and
+                 |retries_func| to the wrapped function as 'timeout' and
+                 'retries' kwargs, respectively.
+  Returns:
+    The wrapped function.
+  """
+  @functools.wraps(f)
+  def TimeoutRetryWrapper(*args, **kwargs):
+    timeout = timeout_func(*args, **kwargs)
+    retries = retries_func(*args, **kwargs)
+    if pass_values:
+      kwargs['timeout'] = timeout
+      kwargs['retries'] = retries
+    def impl():
+      return f(*args, **kwargs)
+    try:
+      if isinstance(threading.current_thread(),
+                    timeout_retry.TimeoutRetryThread):
+        return impl()
+      else:
+        return timeout_retry.Run(impl, timeout, retries)
+    except old_errors.WaitForResponseTimedOutError as e:
+      raise device_errors.CommandTimeoutError(str(e)), None, (
+          sys.exc_info()[2])
+    except old_errors.DeviceUnresponsiveError as e:
+      raise device_errors.DeviceUnreachableError(str(e)), None, (
+          sys.exc_info()[2])
+    except reraiser_thread.TimeoutError as e:
+      raise device_errors.CommandTimeoutError(str(e)), None, (
+          sys.exc_info()[2])
+    except cmd_helper.TimeoutError as e:
+      raise device_errors.CommandTimeoutError(str(e)), None, (
+          sys.exc_info()[2])
+  return TimeoutRetryWrapper
+
+
+def WithTimeoutAndRetries(f):
+  """A decorator that handles timeouts and retries.
+
+  'timeout' and 'retries' kwargs must be passed to the function.
+
+  Args:
+    f: The function to decorate.
+  Returns:
+    The decorated function.
+  """
+  get_timeout = lambda *a, **kw: kw['timeout']
+  get_retries = lambda *a, **kw: kw['retries']
+  return _TimeoutRetryWrapper(f, get_timeout, get_retries)
+
+
+def WithExplicitTimeoutAndRetries(timeout, retries):
+  """Returns a decorator that handles timeouts and retries.
+
+  The provided |timeout| and |retries| values are always used.
+
+  Args:
+    timeout: The number of seconds to wait for the decorated function to
+             return. Always used.
+    retries: The number of times the decorated function should be retried on
+             failure. Always used.
+  Returns:
+    The actual decorator.
+  """
+  def decorator(f):
+    get_timeout = lambda *a, **kw: timeout
+    get_retries = lambda *a, **kw: retries
+    return _TimeoutRetryWrapper(f, get_timeout, get_retries)
+  return decorator
+
+
+def WithTimeoutAndRetriesDefaults(default_timeout, default_retries):
+  """Returns a decorator that handles timeouts and retries.
+
+  The provided |default_timeout| and |default_retries| values are used only
+  if timeout and retries values are not provided.
+
+  Args:
+    default_timeout: The number of seconds to wait for the decorated function
+                     to return. Only used if a 'timeout' kwarg is not passed
+                     to the decorated function.
+    default_retries: The number of times the decorated function should be
+                     retried on failure. Only used if a 'retries' kwarg is not
+                     passed to the decorated function.
+  Returns:
+    The actual decorator.
+  """
+  def decorator(f):
+    get_timeout = lambda *a, **kw: kw.get('timeout', default_timeout)
+    get_retries = lambda *a, **kw: kw.get('retries', default_retries)
+    return _TimeoutRetryWrapper(f, get_timeout, get_retries, pass_values=True)
+  return decorator
+
+
+def WithTimeoutAndRetriesFromInstance(
+    default_timeout_name=DEFAULT_TIMEOUT_ATTR,
+    default_retries_name=DEFAULT_RETRIES_ATTR):
+  """Returns a decorator that handles timeouts and retries.
+
+  The provided |default_timeout_name| and |default_retries_name| are used to
+  get the default timeout value and the default retries value from the object
+  instance if timeout and retries values are not provided.
+
+  Note that this should only be used to decorate methods, not functions.
+
+  Args:
+    default_timeout_name: The name of the default timeout attribute of the
+                          instance.
+    default_retries_name: The name of the default retries attribute of the
+                          instance.
+  Returns:
+    The actual decorator.
+  """
+  def decorator(f):
+    def get_timeout(inst, *_args, **kwargs):
+      return kwargs.get('timeout', getattr(inst, default_timeout_name))
+    def get_retries(inst, *_args, **kwargs):
+      return kwargs.get('retries', getattr(inst, default_retries_name))
+    return _TimeoutRetryWrapper(f, get_timeout, get_retries, pass_values=True)
+  return decorator
+
diff --git a/build/android/pylib/device/decorators_test.py b/build/android/pylib/device/decorators_test.py
new file mode 100644
index 0000000..b75618b
--- /dev/null
+++ b/build/android/pylib/device/decorators_test.py
@@ -0,0 +1,365 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for decorators.py.
+"""
+
+# pylint: disable=W0613
+
+import os
+import sys
+import time
+import traceback
+import unittest
+
+from pylib import constants
+from pylib.device import decorators
+from pylib.device import device_errors
+from pylib.utils import reraiser_thread
+
+# TODO(jbudorick) Remove once the DeviceUtils implementations are no longer
+#                 backed by AndroidCommands / android_testrunner.
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'third_party',
+                             'android_testrunner'))
+import errors as old_errors
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+
+class DecoratorsTest(unittest.TestCase):
+  _decorated_function_called_count = 0
+
+  def testFunctionDecoratorDoesTimeouts(self):
+    """Tests that the base decorator handles the timeout logic."""
+    DecoratorsTest._decorated_function_called_count = 0
+    @decorators.WithTimeoutAndRetries
+    def alwaysTimesOut(timeout=None, retries=None):
+      DecoratorsTest._decorated_function_called_count += 1
+      time.sleep(100)
+
+    start_time = time.time()
+    with self.assertRaises(device_errors.CommandTimeoutError):
+      alwaysTimesOut(timeout=1, retries=0)
+    elapsed_time = time.time() - start_time
+    self.assertTrue(elapsed_time >= 1)
+    self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
+
+  def testFunctionDecoratorDoesRetries(self):
+    """Tests that the base decorator handles the retries logic."""
+    DecoratorsTest._decorated_function_called_count = 0
+    @decorators.WithTimeoutAndRetries
+    def alwaysRaisesCommandFailedError(timeout=None, retries=None):
+      DecoratorsTest._decorated_function_called_count += 1
+      raise device_errors.CommandFailedError('testCommand failed')
+
+    with self.assertRaises(device_errors.CommandFailedError):
+      alwaysRaisesCommandFailedError(timeout=30, retries=10)
+    self.assertEquals(11, DecoratorsTest._decorated_function_called_count)
+
+  def testFunctionDecoratorRequiresParams(self):
+    """Tests that the base decorator requires timeout and retries params."""
+    @decorators.WithTimeoutAndRetries
+    def requiresExplicitTimeoutAndRetries(timeout=None, retries=None):
+      return (timeout, retries)
+
+    with self.assertRaises(KeyError):
+      requiresExplicitTimeoutAndRetries()
+    with self.assertRaises(KeyError):
+      requiresExplicitTimeoutAndRetries(timeout=10)
+    with self.assertRaises(KeyError):
+      requiresExplicitTimeoutAndRetries(retries=0)
+    expected_timeout = 10
+    expected_retries = 1
+    (actual_timeout, actual_retries) = (
+        requiresExplicitTimeoutAndRetries(timeout=expected_timeout,
+                                          retries=expected_retries))
+    self.assertEquals(expected_timeout, actual_timeout)
+    self.assertEquals(expected_retries, actual_retries)
+
+  def testFunctionDecoratorTranslatesOldExceptions(self):
+    """Tests that the explicit decorator translates old exceptions."""
+    @decorators.WithTimeoutAndRetries
+    def alwaysRaisesProvidedException(exception, timeout=None, retries=None):
+      raise exception
+
+    exception_desc = 'Old response timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      alwaysRaisesProvidedException(
+          old_errors.WaitForResponseTimedOutError(exception_desc),
+          timeout=10, retries=1)
+    self.assertEquals(exception_desc, str(e.exception))
+
+    exception_desc = 'Old device error'
+    with self.assertRaises(device_errors.DeviceUnreachableError) as e:
+      alwaysRaisesProvidedException(
+          old_errors.DeviceUnresponsiveError(exception_desc),
+          timeout=10, retries=1)
+    self.assertEquals(exception_desc, str(e.exception))
+
+  def testFunctionDecoratorTranslatesReraiserExceptions(self):
+    """Tests that the explicit decorator translates reraiser exceptions."""
+    @decorators.WithTimeoutAndRetries
+    def alwaysRaisesProvidedException(exception, timeout=None, retries=None):
+      raise exception
+
+    exception_desc = 'Reraiser thread timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      alwaysRaisesProvidedException(
+          reraiser_thread.TimeoutError(exception_desc),
+          timeout=10, retries=1)
+    self.assertEquals(exception_desc, str(e.exception))
+
+  def testDefaultsFunctionDecoratorDoesTimeouts(self):
+    """Tests that the defaults decorator handles timeout logic."""
+    DecoratorsTest._decorated_function_called_count = 0
+    @decorators.WithTimeoutAndRetriesDefaults(1, 0)
+    def alwaysTimesOut(timeout=None, retries=None):
+      DecoratorsTest._decorated_function_called_count += 1
+      time.sleep(100)
+
+    start_time = time.time()
+    with self.assertRaises(device_errors.CommandTimeoutError):
+      alwaysTimesOut()
+    elapsed_time = time.time() - start_time
+    self.assertTrue(elapsed_time >= 1)
+    self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
+
+    DecoratorsTest._decorated_function_called_count = 0
+    with self.assertRaises(device_errors.CommandTimeoutError):
+      alwaysTimesOut(timeout=2)
+    elapsed_time = time.time() - start_time
+    self.assertTrue(elapsed_time >= 2)
+    self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
+
+  def testDefaultsFunctionDecoratorDoesRetries(self):
+    """Tests that the defaults decorator handles retries logic."""
+    DecoratorsTest._decorated_function_called_count = 0
+    @decorators.WithTimeoutAndRetriesDefaults(30, 10)
+    def alwaysRaisesCommandFailedError(timeout=None, retries=None):
+      DecoratorsTest._decorated_function_called_count += 1
+      raise device_errors.CommandFailedError('testCommand failed')
+
+    with self.assertRaises(device_errors.CommandFailedError):
+      alwaysRaisesCommandFailedError()
+    self.assertEquals(11, DecoratorsTest._decorated_function_called_count)
+
+    DecoratorsTest._decorated_function_called_count = 0
+    with self.assertRaises(device_errors.CommandFailedError):
+      alwaysRaisesCommandFailedError(retries=5)
+    self.assertEquals(6, DecoratorsTest._decorated_function_called_count)
+
+  def testDefaultsFunctionDecoratorPassesValues(self):
+    """Tests that the defaults decorator passes timeout and retries kwargs."""
+    @decorators.WithTimeoutAndRetriesDefaults(30, 10)
+    def alwaysReturnsTimeouts(timeout=None, retries=None):
+      return timeout
+
+    self.assertEquals(30, alwaysReturnsTimeouts())
+    self.assertEquals(120, alwaysReturnsTimeouts(timeout=120))
+
+    @decorators.WithTimeoutAndRetriesDefaults(30, 10)
+    def alwaysReturnsRetries(timeout=None, retries=None):
+      return retries
+
+    self.assertEquals(10, alwaysReturnsRetries())
+    self.assertEquals(1, alwaysReturnsRetries(retries=1))
+
+  def testDefaultsFunctionDecoratorTranslatesOldExceptions(self):
+    """Tests that the explicit decorator translates old exceptions."""
+    @decorators.WithTimeoutAndRetriesDefaults(30, 10)
+    def alwaysRaisesProvidedException(exception, timeout=None, retries=None):
+      raise exception
+
+    exception_desc = 'Old response timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      alwaysRaisesProvidedException(
+          old_errors.WaitForResponseTimedOutError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+    exception_desc = 'Old device error'
+    with self.assertRaises(device_errors.DeviceUnreachableError) as e:
+      alwaysRaisesProvidedException(
+          old_errors.DeviceUnresponsiveError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+  def testDefaultsFunctionDecoratorTranslatesReraiserExceptions(self):
+    """Tests that the explicit decorator translates reraiser exceptions."""
+    @decorators.WithTimeoutAndRetriesDefaults(30, 10)
+    def alwaysRaisesProvidedException(exception, timeout=None, retries=None):
+      raise exception
+
+    exception_desc = 'Reraiser thread timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      alwaysRaisesProvidedException(
+          reraiser_thread.TimeoutError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+  def testExplicitFunctionDecoratorDoesTimeouts(self):
+    """Tests that the explicit decorator handles timeout logic."""
+    DecoratorsTest._decorated_function_called_count = 0
+    @decorators.WithExplicitTimeoutAndRetries(1, 0)
+    def alwaysTimesOut():
+      DecoratorsTest._decorated_function_called_count += 1
+      time.sleep(100)
+
+    start_time = time.time()
+    with self.assertRaises(device_errors.CommandTimeoutError):
+      alwaysTimesOut()
+    elapsed_time = time.time() - start_time
+    self.assertTrue(elapsed_time >= 1)
+    self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
+
+  def testExplicitFunctionDecoratorDoesRetries(self):
+    """Tests that the explicit decorator handles retries logic."""
+    DecoratorsTest._decorated_function_called_count = 0
+    @decorators.WithExplicitTimeoutAndRetries(30, 10)
+    def alwaysRaisesCommandFailedError():
+      DecoratorsTest._decorated_function_called_count += 1
+      raise device_errors.CommandFailedError('testCommand failed')
+
+    with self.assertRaises(device_errors.CommandFailedError):
+      alwaysRaisesCommandFailedError()
+    self.assertEquals(11, DecoratorsTest._decorated_function_called_count)
+
+  def testExplicitDecoratorTranslatesOldExceptions(self):
+    """Tests that the explicit decorator translates old exceptions."""
+    @decorators.WithExplicitTimeoutAndRetries(30, 10)
+    def alwaysRaisesProvidedException(exception):
+      raise exception
+
+    exception_desc = 'Old response timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      alwaysRaisesProvidedException(
+          old_errors.WaitForResponseTimedOutError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+    exception_desc = 'Old device error'
+    with self.assertRaises(device_errors.DeviceUnreachableError) as e:
+      alwaysRaisesProvidedException(
+          old_errors.DeviceUnresponsiveError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+  def testExplicitDecoratorTranslatesReraiserExceptions(self):
+    """Tests that the explicit decorator translates reraiser exceptions."""
+    @decorators.WithExplicitTimeoutAndRetries(30, 10)
+    def alwaysRaisesProvidedException(exception):
+      raise exception
+
+    exception_desc = 'Reraiser thread timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      alwaysRaisesProvidedException(
+          reraiser_thread.TimeoutError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+  class _MethodDecoratorTestObject(object):
+    """An object suitable for testing the method decorator."""
+
+    def __init__(self, test_case, default_timeout=_DEFAULT_TIMEOUT,
+                 default_retries=_DEFAULT_RETRIES):
+      self._test_case = test_case
+      self.default_timeout = default_timeout
+      self.default_retries = default_retries
+      self.function_call_counters = {
+          'alwaysRaisesCommandFailedError': 0,
+          'alwaysTimesOut': 0,
+          'requiresExplicitTimeoutAndRetries': 0,
+      }
+
+    @decorators.WithTimeoutAndRetriesFromInstance(
+        'default_timeout', 'default_retries')
+    def alwaysTimesOut(self, timeout=None, retries=None):
+      self.function_call_counters['alwaysTimesOut'] += 1
+      time.sleep(100)
+      self._test_case.assertFalse(True, msg='Failed to time out?')
+
+    @decorators.WithTimeoutAndRetriesFromInstance(
+        'default_timeout', 'default_retries')
+    def alwaysRaisesCommandFailedError(self, timeout=None, retries=None):
+      self.function_call_counters['alwaysRaisesCommandFailedError'] += 1
+      raise device_errors.CommandFailedError('testCommand failed')
+
+    # pylint: disable=no-self-use
+
+    @decorators.WithTimeoutAndRetriesFromInstance(
+        'default_timeout', 'default_retries')
+    def alwaysReturnsTimeout(self, timeout=None, retries=None):
+      return timeout
+
+    @decorators.WithTimeoutAndRetriesFromInstance(
+        'default_timeout', 'default_retries')
+    def alwaysReturnsRetries(self, timeout=None, retries=None):
+      return retries
+
+    @decorators.WithTimeoutAndRetriesFromInstance(
+        'default_timeout', 'default_retries')
+    def alwaysRaisesProvidedException(self, exception, timeout=None,
+                                      retries=None):
+      raise exception
+
+    # pylint: enable=no-self-use
+
+
+  def testMethodDecoratorDoesTimeout(self):
+    """Tests that the method decorator handles timeout logic."""
+    test_obj = self._MethodDecoratorTestObject(self)
+    start_time = time.time()
+    with self.assertRaises(device_errors.CommandTimeoutError):
+      try:
+        test_obj.alwaysTimesOut(timeout=1, retries=0)
+      except:
+        traceback.print_exc()
+        raise
+    elapsed_time = time.time() - start_time
+    self.assertTrue(elapsed_time >= 1)
+    self.assertEquals(1, test_obj.function_call_counters['alwaysTimesOut'])
+
+  def testMethodDecoratorDoesRetries(self):
+    """Tests that the method decorator handles retries logic."""
+    test_obj = self._MethodDecoratorTestObject(self)
+    with self.assertRaises(device_errors.CommandFailedError):
+      try:
+        test_obj.alwaysRaisesCommandFailedError(retries=10)
+      except:
+        traceback.print_exc()
+        raise
+    self.assertEquals(
+        11, test_obj.function_call_counters['alwaysRaisesCommandFailedError'])
+
+  def testMethodDecoratorPassesValues(self):
+    """Tests that the method decorator passes timeout and retries kwargs."""
+    test_obj = self._MethodDecoratorTestObject(
+        self, default_timeout=42, default_retries=31)
+    self.assertEquals(42, test_obj.alwaysReturnsTimeout())
+    self.assertEquals(41, test_obj.alwaysReturnsTimeout(timeout=41))
+    self.assertEquals(31, test_obj.alwaysReturnsRetries())
+    self.assertEquals(32, test_obj.alwaysReturnsRetries(retries=32))
+
+  def testMethodDecoratorTranslatesOldExceptions(self):
+    test_obj = self._MethodDecoratorTestObject(self)
+
+    exception_desc = 'Old response timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      test_obj.alwaysRaisesProvidedException(
+          old_errors.WaitForResponseTimedOutError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+    exception_desc = 'Old device error'
+    with self.assertRaises(device_errors.DeviceUnreachableError) as e:
+      test_obj.alwaysRaisesProvidedException(
+          old_errors.DeviceUnresponsiveError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+  def testMethodDecoratorTranslatesReraiserExceptions(self):
+    test_obj = self._MethodDecoratorTestObject(self)
+
+    exception_desc = 'Reraiser thread timeout error'
+    with self.assertRaises(device_errors.CommandTimeoutError) as e:
+      test_obj.alwaysRaisesProvidedException(
+          reraiser_thread.TimeoutError(exception_desc))
+    self.assertEquals(exception_desc, str(e.exception))
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/device/device_blacklist.py b/build/android/pylib/device/device_blacklist.py
new file mode 100644
index 0000000..a141d62
--- /dev/null
+++ b/build/android/pylib/device/device_blacklist.py
@@ -0,0 +1,61 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+import threading
+
+from pylib import constants
+_BLACKLIST_JSON = os.path.join(
+    constants.DIR_SOURCE_ROOT,
+    os.environ.get('CHROMIUM_OUT_DIR', 'out'),
+    'bad_devices.json')
+
+# Note that this only protects against concurrent accesses to the blacklist
+# within a process.
+_blacklist_lock = threading.RLock()
+
+def ReadBlacklist():
+  """Reads the blacklist from the _BLACKLIST_JSON file.
+
+  Returns:
+    A list containing bad devices.
+  """
+  with _blacklist_lock:
+    if not os.path.exists(_BLACKLIST_JSON):
+      return []
+
+    with open(_BLACKLIST_JSON, 'r') as f:
+      return json.load(f)
+
+
+def WriteBlacklist(blacklist):
+  """Writes the provided blacklist to the _BLACKLIST_JSON file.
+
+  Args:
+    blacklist: list of bad devices to write to the _BLACKLIST_JSON file.
+  """
+  with _blacklist_lock:
+    with open(_BLACKLIST_JSON, 'w') as f:
+      json.dump(list(set(blacklist)), f)
+
+
+def ExtendBlacklist(devices):
+  """Adds devices to _BLACKLIST_JSON file.
+
+  Args:
+    devices: list of bad devices to be added to the _BLACKLIST_JSON file.
+  """
+  with _blacklist_lock:
+    blacklist = ReadBlacklist()
+    blacklist.extend(devices)
+    WriteBlacklist(blacklist)
+
+
+def ResetBlacklist():
+  """Erases the _BLACKLIST_JSON file if it exists."""
+  with _blacklist_lock:
+    if os.path.exists(_BLACKLIST_JSON):
+      os.remove(_BLACKLIST_JSON)
+
diff --git a/build/android/pylib/device/device_errors.py b/build/android/pylib/device/device_errors.py
new file mode 100644
index 0000000..2492015
--- /dev/null
+++ b/build/android/pylib/device/device_errors.py
@@ -0,0 +1,89 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Exception classes raised by AdbWrapper and DeviceUtils.
+"""
+
+from pylib import cmd_helper
+from pylib.utils import base_error
+
+
+class CommandFailedError(base_error.BaseError):
+  """Exception for command failures."""
+
+  def __init__(self, message, device_serial=None):
+    if device_serial is not None:
+      message = '(device: %s) %s' % (device_serial, message)
+    self.device_serial = device_serial
+    super(CommandFailedError, self).__init__(message)
+
+
+class AdbCommandFailedError(CommandFailedError):
+  """Exception for adb command failures."""
+
+  def __init__(self, args, output, status=None, device_serial=None,
+               message=None):
+    self.args = args
+    self.output = output
+    self.status = status
+    if not message:
+      adb_cmd = ' '.join(cmd_helper.SingleQuote(arg) for arg in self.args)
+      message = ['adb %s: failed ' % adb_cmd]
+      if status:
+        message.append('with exit status %s ' % self.status)
+      if output:
+        message.append('and output:\n')
+        message.extend('- %s\n' % line for line in output.splitlines())
+      else:
+        message.append('and no output.')
+      message = ''.join(message)
+    super(AdbCommandFailedError, self).__init__(message, device_serial)
+
+
+class DeviceVersionError(CommandFailedError):
+  """Exception for device version failures."""
+
+  def __init__(self, message, device_serial=None):
+    super(DeviceVersionError, self).__init__(message, device_serial)
+
+
+class AdbShellCommandFailedError(AdbCommandFailedError):
+  """Exception for shell command failures run via adb."""
+
+  def __init__(self, command, output, status, device_serial=None):
+    self.command = command
+    message = ['shell command run via adb failed on the device:\n',
+               '  command: %s\n' % command]
+    message.append('  exit status: %s\n' % status)
+    if output:
+      message.append('  output:\n')
+      if isinstance(output, basestring):
+        output_lines = output.splitlines()
+      else:
+        output_lines = output
+      message.extend('  - %s\n' % line for line in output_lines)
+    else:
+      message.append("  output: ''\n")
+    message = ''.join(message)
+    super(AdbShellCommandFailedError, self).__init__(
+      ['shell', command], output, status, device_serial, message)
+
+
+class CommandTimeoutError(base_error.BaseError):
+  """Exception for command timeouts."""
+  pass
+
+
+class DeviceUnreachableError(base_error.BaseError):
+  """Exception for device unreachable failures."""
+  pass
+
+
+class NoDevicesError(base_error.BaseError):
+  """Exception for having no devices attached."""
+
+  def __init__(self):
+    super(NoDevicesError, self).__init__(
+        'No devices attached.', is_infra_error=True)
diff --git a/build/android/pylib/device/device_list.py b/build/android/pylib/device/device_list.py
new file mode 100644
index 0000000..0eb6acb
--- /dev/null
+++ b/build/android/pylib/device/device_list.py
@@ -0,0 +1,30 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A module to keep track of devices across builds."""
+
+import os
+
+LAST_DEVICES_FILENAME = '.last_devices'
+LAST_MISSING_DEVICES_FILENAME = '.last_missing'
+
+
+def GetPersistentDeviceList(file_name):
+  """Returns a list of devices.
+
+  Args:
+    file_name: the file name containing a list of devices.
+
+  Returns: List of device serial numbers that were on the bot.
+  """
+  with open(file_name) as f:
+    return f.read().splitlines()
+
+
+def WritePersistentDeviceList(file_name, device_list):
+  path = os.path.dirname(file_name)
+  if not os.path.exists(path):
+    os.makedirs(path)
+  with open(file_name, 'w') as f:
+    f.write('\n'.join(set(device_list)))
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
new file mode 100644
index 0000000..091bb8e
--- /dev/null
+++ b/build/android/pylib/device/device_utils.py
@@ -0,0 +1,1623 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Provides a variety of device interactions based on adb.
+
+Eventually, this will be based on adb_wrapper.
+"""
+# pylint: disable=unused-argument
+
+import collections
+import contextlib
+import itertools
+import logging
+import multiprocessing
+import os
+import posixpath
+import re
+import shutil
+import sys
+import tempfile
+import time
+import zipfile
+
+import pylib.android_commands
+from pylib import cmd_helper
+from pylib import constants
+from pylib import device_signal
+from pylib.device import adb_wrapper
+from pylib.device import decorators
+from pylib.device import device_blacklist
+from pylib.device import device_errors
+from pylib.device import intent
+from pylib.device import logcat_monitor
+from pylib.device.commands import install_commands
+from pylib.utils import apk_helper
+from pylib.utils import base_error
+from pylib.utils import device_temp_file
+from pylib.utils import host_utils
+from pylib.utils import md5sum
+from pylib.utils import parallelizer
+from pylib.utils import timeout_retry
+from pylib.utils import zip_utils
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+
+# A sentinel object for default values
+# TODO(jbudorick,perezju): revisit how default values are handled by
+# the timeout_retry decorators.
+DEFAULT = object()
+
+_CONTROL_CHARGING_COMMANDS = [
+  {
+    # Nexus 4
+    'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
+    'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled',
+    'disable_command':
+        'echo 1 > /sys/module/pm8921_charger/parameters/disabled',
+  },
+  {
+    # Nexus 5
+    # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
+    # energy coming from USB. Setting the power_supply offline just updates the
+    # Android system to reflect that.
+    'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
+    'enable_command': (
+        'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
+        'echo 1 > /sys/class/power_supply/usb/online'),
+    'disable_command': (
+        'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
+        'chmod 644 /sys/class/power_supply/usb/online && '
+        'echo 0 > /sys/class/power_supply/usb/online'),
+  },
+]
+
+
+@decorators.WithExplicitTimeoutAndRetries(
+    _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
+def GetAVDs():
+  """Returns a list of Android Virtual Devices.
+
+  Returns:
+    A list containing the configured AVDs.
+  """
+  lines = cmd_helper.GetCmdOutput([
+      os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android'),
+      'list', 'avd']).splitlines()
+  avds = []
+  for line in lines:
+    if 'Name:' not in line:
+      continue
+    key, value = (s.strip() for s in line.split(':', 1))
+    if key == 'Name':
+      avds.append(value)
+  return avds
+
+
+@decorators.WithExplicitTimeoutAndRetries(
+    _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
+def RestartServer():
+  """Restarts the adb server.
+
+  Raises:
+    CommandFailedError if we fail to kill or restart the server.
+  """
+  def adb_killed():
+    return not adb_wrapper.AdbWrapper.IsServerOnline()
+
+  def adb_started():
+    return adb_wrapper.AdbWrapper.IsServerOnline()
+
+  adb_wrapper.AdbWrapper.KillServer()
+  if not timeout_retry.WaitFor(adb_killed, wait_period=1, max_tries=5):
+    # TODO(perezju): raise an exception after fixng http://crbug.com/442319
+    logging.warning('Failed to kill adb server')
+  adb_wrapper.AdbWrapper.StartServer()
+  if not timeout_retry.WaitFor(adb_started, wait_period=1, max_tries=5):
+    raise device_errors.CommandFailedError('Failed to start adb server')
+
+
+def _GetTimeStamp():
+  """Return a basic ISO 8601 time stamp with the current local time."""
+  return time.strftime('%Y%m%dT%H%M%S', time.localtime())
+
+
+def _JoinLines(lines):
+  # makes sure that the last line is also terminated, and is more memory
+  # efficient than first appending an end-line to each line and then joining
+  # all of them together.
+  return ''.join(s for line in lines for s in (line, '\n'))
+
+
+class DeviceUtils(object):
+
+  _MAX_ADB_COMMAND_LENGTH = 512
+  _MAX_ADB_OUTPUT_LENGTH = 32768
+  _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
+
+  # Property in /data/local.prop that controls Java assertions.
+  JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions'
+
+  def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
+               default_retries=_DEFAULT_RETRIES):
+    """DeviceUtils constructor.
+
+    Args:
+      device: Either a device serial, an existing AdbWrapper instance, or an
+              an existing AndroidCommands instance.
+      default_timeout: An integer containing the default number of seconds to
+                       wait for an operation to complete if no explicit value
+                       is provided.
+      default_retries: An integer containing the default number or times an
+                       operation should be retried on failure if no explicit
+                       value is provided.
+    """
+    self.adb = None
+    self.old_interface = None
+    if isinstance(device, basestring):
+      self.adb = adb_wrapper.AdbWrapper(device)
+      self.old_interface = pylib.android_commands.AndroidCommands(device)
+    elif isinstance(device, adb_wrapper.AdbWrapper):
+      self.adb = device
+      self.old_interface = pylib.android_commands.AndroidCommands(str(device))
+    elif isinstance(device, pylib.android_commands.AndroidCommands):
+      self.adb = adb_wrapper.AdbWrapper(device.GetDevice())
+      self.old_interface = device
+    else:
+      raise ValueError('Unsupported device value: %r' % device)
+    self._commands_installed = None
+    self._default_timeout = default_timeout
+    self._default_retries = default_retries
+    self._cache = {}
+    self._client_caches = {}
+    assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
+    assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
+
+  def __eq__(self, other):
+    """Checks whether |other| refers to the same device as |self|.
+
+    Args:
+      other: The object to compare to. This can be a basestring, an instance
+        of adb_wrapper.AdbWrapper, or an instance of DeviceUtils.
+    Returns:
+      Whether |other| refers to the same device as |self|.
+    """
+    return self.adb.GetDeviceSerial() == str(other)
+
+  def __lt__(self, other):
+    """Compares two instances of DeviceUtils.
+
+    This merely compares their serial numbers.
+
+    Args:
+      other: The instance of DeviceUtils to compare to.
+    Returns:
+      Whether |self| is less than |other|.
+    """
+    return self.adb.GetDeviceSerial() < other.adb.GetDeviceSerial()
+
+  def __str__(self):
+    """Returns the device serial."""
+    return self.adb.GetDeviceSerial()
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def IsOnline(self, timeout=None, retries=None):
+    """Checks whether the device is online.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if the device is online, False otherwise.
+
+    Raises:
+      CommandTimeoutError on timeout.
+    """
+    try:
+      return self.adb.GetState() == 'device'
+    except base_error.BaseError as exc:
+      logging.info('Failed to get state: %s', exc)
+      return False
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def HasRoot(self, timeout=None, retries=None):
+    """Checks whether or not adbd has root privileges.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if adbd has root privileges, False otherwise.
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    try:
+      self.RunShellCommand('ls /root', check_return=True)
+      return True
+    except device_errors.AdbCommandFailedError:
+      return False
+
+  def NeedsSU(self, timeout=DEFAULT, retries=DEFAULT):
+    """Checks whether 'su' is needed to access protected resources.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if 'su' is available on the device and is needed to to access
+        protected resources; False otherwise if either 'su' is not available
+        (e.g. because the device has a user build), or not needed (because adbd
+        already has root privileges).
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    if 'needs_su' not in self._cache:
+      try:
+        self.RunShellCommand(
+            'su -c ls /root && ! ls /root', check_return=True,
+            timeout=self._default_timeout if timeout is DEFAULT else timeout,
+            retries=self._default_retries if retries is DEFAULT else retries)
+        self._cache['needs_su'] = True
+      except device_errors.AdbCommandFailedError:
+        self._cache['needs_su'] = False
+    return self._cache['needs_su']
+
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def EnableRoot(self, timeout=None, retries=None):
+    """Restarts adbd with root privileges.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError if root could not be enabled.
+      CommandTimeoutError on timeout.
+    """
+    if self.IsUserBuild():
+      raise device_errors.CommandFailedError(
+          'Cannot enable root in user builds.', str(self))
+    if 'needs_su' in self._cache:
+      del self._cache['needs_su']
+    self.adb.Root()
+    self.adb.WaitForDevice()
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def IsUserBuild(self, timeout=None, retries=None):
+    """Checks whether or not the device is running a user build.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if the device is running a user build, False otherwise (i.e. if
+        it's running a userdebug build).
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    return self.build_type == 'user'
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetExternalStoragePath(self, timeout=None, retries=None):
+    """Get the device's path to its SD card.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The device's path to its SD card.
+
+    Raises:
+      CommandFailedError if the external storage path could not be determined.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    if 'external_storage' in self._cache:
+      return self._cache['external_storage']
+
+    value = self.RunShellCommand('echo $EXTERNAL_STORAGE',
+                                 single_line=True,
+                                 check_return=True)
+    if not value:
+      raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set',
+                                             str(self))
+    self._cache['external_storage'] = value
+    return value
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetApplicationPath(self, package, timeout=None, retries=None):
+    """Get the path of the installed apk on the device for the given package.
+
+    Args:
+      package: Name of the package.
+
+    Returns:
+      Path to the apk on the device if it exists, None otherwise.
+    """
+    # 'pm path' is liable to incorrectly exit with a nonzero number starting
+    # in Lollipop.
+    # TODO(jbudorick): Check if this is fixed as new Android versions are
+    # released to put an upper bound on this.
+    should_check_return = (self.build_version_sdk <
+                           constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP)
+    output = self.RunShellCommand(['pm', 'path', package], single_line=True,
+                                  check_return=should_check_return)
+    if not output:
+      return None
+    if not output.startswith('package:'):
+      raise device_errors.CommandFailedError('pm path returned: %r' % output,
+                                             str(self))
+    return output[len('package:'):]
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
+    """Wait for the device to fully boot.
+
+    This means waiting for the device to boot, the package manager to be
+    available, and the SD card to be ready. It can optionally mean waiting
+    for wifi to come up, too.
+
+    Args:
+      wifi: A boolean indicating if we should wait for wifi to come up or not.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError on failure.
+      CommandTimeoutError if one of the component waits times out.
+      DeviceUnreachableError if the device becomes unresponsive.
+    """
+    def sd_card_ready():
+      try:
+        self.RunShellCommand(['test', '-d', self.GetExternalStoragePath()],
+                             check_return=True)
+        return True
+      except device_errors.AdbCommandFailedError:
+        return False
+
+    def pm_ready():
+      try:
+        return self.GetApplicationPath('android')
+      except device_errors.CommandFailedError:
+        return False
+
+    def boot_completed():
+      return self.GetProp('sys.boot_completed') == '1'
+
+    def wifi_enabled():
+      return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'],
+                                                        check_return=False)
+
+    self.adb.WaitForDevice()
+    timeout_retry.WaitFor(sd_card_ready)
+    timeout_retry.WaitFor(pm_ready)
+    timeout_retry.WaitFor(boot_completed)
+    if wifi:
+      timeout_retry.WaitFor(wifi_enabled)
+
+  REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
+  REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES
+
+  @decorators.WithTimeoutAndRetriesDefaults(
+      REBOOT_DEFAULT_TIMEOUT,
+      REBOOT_DEFAULT_RETRIES)
+  def Reboot(self, block=True, wifi=False, timeout=None, retries=None):
+    """Reboot the device.
+
+    Args:
+      block: A boolean indicating if we should wait for the reboot to complete.
+      wifi: A boolean indicating if we should wait for wifi to be enabled after
+        the reboot. The option has no effect unless |block| is also True.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    def device_offline():
+      return not self.IsOnline()
+
+    self.adb.Reboot()
+    self._ClearCache()
+    timeout_retry.WaitFor(device_offline, wait_period=1)
+    if block:
+      self.WaitUntilFullyBooted(wifi=wifi)
+
+  INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT
+  INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES
+
+  @decorators.WithTimeoutAndRetriesDefaults(
+      INSTALL_DEFAULT_TIMEOUT,
+      INSTALL_DEFAULT_RETRIES)
+  def Install(self, apk_path, reinstall=False, timeout=None, retries=None):
+    """Install an APK.
+
+    Noop if an identical APK is already installed.
+
+    Args:
+      apk_path: A string containing the path to the APK to install.
+      reinstall: A boolean indicating if we should keep any existing app data.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError if the installation fails.
+      CommandTimeoutError if the installation times out.
+      DeviceUnreachableError on missing device.
+    """
+    package_name = apk_helper.GetPackageName(apk_path)
+    device_path = self.GetApplicationPath(package_name)
+    if device_path is not None:
+      should_install = bool(self._GetChangedFilesImpl(apk_path, device_path))
+      if should_install and not reinstall:
+        self.adb.Uninstall(package_name)
+    else:
+      should_install = True
+    if should_install:
+      self.adb.Install(apk_path, reinstall=reinstall)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def RunShellCommand(self, cmd, check_return=False, cwd=None, env=None,
+                      as_root=False, single_line=False, large_output=False,
+                      timeout=None, retries=None):
+    """Run an ADB shell command.
+
+    The command to run |cmd| should be a sequence of program arguments or else
+    a single string.
+
+    When |cmd| is a sequence, it is assumed to contain the name of the command
+    to run followed by its arguments. In this case, arguments are passed to the
+    command exactly as given, without any further processing by the shell. This
+    allows to easily pass arguments containing spaces or special characters
+    without having to worry about getting quoting right. Whenever possible, it
+    is recomended to pass |cmd| as a sequence.
+
+    When |cmd| is given as a string, it will be interpreted and run by the
+    shell on the device.
+
+    This behaviour is consistent with that of command runners in cmd_helper as
+    well as Python's own subprocess.Popen.
+
+    TODO(perezju) Change the default of |check_return| to True when callers
+      have switched to the new behaviour.
+
+    Args:
+      cmd: A string with the full command to run on the device, or a sequence
+        containing the command and its arguments.
+      check_return: A boolean indicating whether or not the return code should
+        be checked.
+      cwd: The device directory in which the command should be run.
+      env: The environment variables with which the command should be run.
+      as_root: A boolean indicating whether the shell command should be run
+        with root privileges.
+      single_line: A boolean indicating if only a single line of output is
+        expected.
+      large_output: Uses a work-around for large shell command output. Without
+        this large output will be truncated.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      If single_line is False, the output of the command as a list of lines,
+      otherwise, a string with the unique line of output emmited by the command
+      (with the optional newline at the end stripped).
+
+    Raises:
+      AdbCommandFailedError if check_return is True and the exit code of
+        the command run on the device is non-zero.
+      CommandFailedError if single_line is True but the output contains two or
+        more lines.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    def env_quote(key, value):
+      if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
+        raise KeyError('Invalid shell variable name %r' % key)
+      # using double quotes here to allow interpolation of shell variables
+      return '%s=%s' % (key, cmd_helper.DoubleQuote(value))
+
+    def run(cmd):
+      return self.adb.Shell(cmd)
+
+    def handle_check_return(cmd):
+      try:
+        return run(cmd)
+      except device_errors.AdbCommandFailedError as exc:
+        if check_return:
+          raise
+        else:
+          return exc.output
+
+    def handle_large_command(cmd):
+      if len(cmd) < self._MAX_ADB_COMMAND_LENGTH:
+        return handle_check_return(cmd)
+      else:
+        with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
+          self._WriteFileWithPush(script.name, cmd)
+          logging.info('Large shell command will be run from file: %s ...',
+                       cmd[:100])
+          return handle_check_return('sh %s' % script.name_quoted)
+
+    def handle_large_output(cmd, large_output_mode):
+      if large_output_mode:
+        with device_temp_file.DeviceTempFile(self.adb) as large_output_file:
+          cmd = '%s > %s' % (cmd, large_output_file.name)
+          logging.info('Large output mode enabled. Will write output to device '
+                       'and read results from file.')
+          handle_large_command(cmd)
+          return self.ReadFile(large_output_file.name, force_pull=True)
+      else:
+        try:
+          return handle_large_command(cmd)
+        except device_errors.AdbCommandFailedError as exc:
+          if exc.status is None:
+            logging.exception('No output found for %s', cmd)
+            logging.warning('Attempting to run in large_output mode.')
+            logging.warning('Use RunShellCommand(..., large_output=True) for '
+                            'shell commands that expect a lot of output.')
+            return handle_large_output(cmd, True)
+          else:
+            raise
+
+    if not isinstance(cmd, basestring):
+      cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
+    if env:
+      env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
+      cmd = '%s %s' % (env, cmd)
+    if cwd:
+      cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
+    if as_root and self.NeedsSU():
+      # "su -c sh -c" allows using shell features in |cmd|
+      cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd)
+
+    output = handle_large_output(cmd, large_output).splitlines()
+
+    if single_line:
+      if not output:
+        return ''
+      elif len(output) == 1:
+        return output[0]
+      else:
+        msg = 'one line of output was expected, but got: %s'
+        raise device_errors.CommandFailedError(msg % output, str(self))
+    else:
+      return output
+
+  def _RunPipedShellCommand(self, script, **kwargs):
+    PIPESTATUS_LEADER = 'PIPESTATUS: '
+
+    script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER
+    kwargs['check_return'] = True
+    output = self.RunShellCommand(script, **kwargs)
+    pipestatus_line = output[-1]
+
+    if not pipestatus_line.startswith(PIPESTATUS_LEADER):
+      logging.error('Pipe exit statuses of shell script missing.')
+      raise device_errors.AdbShellCommandFailedError(
+          script, output, status=None,
+          device_serial=self.adb.GetDeviceSerial())
+
+    output = output[:-1]
+    statuses = [
+        int(s) for s in pipestatus_line[len(PIPESTATUS_LEADER):].split()]
+    if any(statuses):
+      raise device_errors.AdbShellCommandFailedError(
+          script, output, status=statuses,
+          device_serial=self.adb.GetDeviceSerial())
+    return output
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def KillAll(self, process_name, signum=device_signal.SIGKILL, as_root=False,
+              blocking=False, quiet=False, timeout=None, retries=None):
+    """Kill all processes with the given name on the device.
+
+    Args:
+      process_name: A string containing the name of the process to kill.
+      signum: An integer containing the signal number to send to kill. Defaults
+              to SIGKILL (9).
+      as_root: A boolean indicating whether the kill should be executed with
+               root privileges.
+      blocking: A boolean indicating whether we should wait until all processes
+                with the given |process_name| are dead.
+      quiet: A boolean indicating whether to ignore the fact that no processes
+             to kill were found.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The number of processes attempted to kill.
+
+    Raises:
+      CommandFailedError if no process was killed and |quiet| is False.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    pids = self.GetPids(process_name)
+    if not pids:
+      if quiet:
+        return 0
+      else:
+        raise device_errors.CommandFailedError(
+            'No process "%s"' % process_name, str(self))
+
+    cmd = ['kill', '-%d' % signum] + pids.values()
+    self.RunShellCommand(cmd, as_root=as_root, check_return=True)
+
+    if blocking:
+      # TODO(perezu): use timeout_retry.WaitFor
+      wait_period = 0.1
+      while self.GetPids(process_name):
+        time.sleep(wait_period)
+
+    return len(pids)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def StartActivity(self, intent_obj, blocking=False, trace_file_name=None,
+                    force_stop=False, timeout=None, retries=None):
+    """Start package's activity on the device.
+
+    Args:
+      intent_obj: An Intent object to send.
+      blocking: A boolean indicating whether we should wait for the activity to
+                finish launching.
+      trace_file_name: If present, a string that both indicates that we want to
+                       profile the activity and contains the path to which the
+                       trace should be saved.
+      force_stop: A boolean indicating whether we should stop the activity
+                  before starting it.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError if the activity could not be started.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    cmd = ['am', 'start']
+    if blocking:
+      cmd.append('-W')
+    if trace_file_name:
+      cmd.extend(['--start-profiler', trace_file_name])
+    if force_stop:
+      cmd.append('-S')
+    cmd.extend(intent_obj.am_args)
+    for line in self.RunShellCommand(cmd, check_return=True):
+      if line.startswith('Error:'):
+        raise device_errors.CommandFailedError(line, str(self))
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def StartInstrumentation(self, component, finish=True, raw=False,
+                           extras=None, timeout=None, retries=None):
+    if extras is None:
+      extras = {}
+
+    cmd = ['am', 'instrument']
+    if finish:
+      cmd.append('-w')
+    if raw:
+      cmd.append('-r')
+    for k, v in extras.iteritems():
+      cmd.extend(['-e', str(k), str(v)])
+    cmd.append(component)
+    return self.RunShellCommand(cmd, check_return=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def BroadcastIntent(self, intent_obj, timeout=None, retries=None):
+    """Send a broadcast intent.
+
+    Args:
+      intent: An Intent to broadcast.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    cmd = ['am', 'broadcast'] + intent_obj.am_args
+    self.RunShellCommand(cmd, check_return=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GoHome(self, timeout=None, retries=None):
+    """Return to the home screen.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    self.StartActivity(
+        intent.Intent(action='android.intent.action.MAIN',
+                      category='android.intent.category.HOME'),
+        blocking=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def ForceStop(self, package, timeout=None, retries=None):
+    """Close the application.
+
+    Args:
+      package: A string containing the name of the package to stop.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    self.RunShellCommand(['am', 'force-stop', package], check_return=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def ClearApplicationState(self, package, timeout=None, retries=None):
+    """Clear all state for the given package.
+
+    Args:
+      package: A string containing the name of the package to stop.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    # Check that the package exists before clearing it for android builds below
+    # JB MR2. Necessary because calling pm clear on a package that doesn't exist
+    # may never return.
+    if ((self.build_version_sdk >=
+         constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN_MR2)
+        or self.GetApplicationPath(package)):
+      self.RunShellCommand(['pm', 'clear', package], check_return=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SendKeyEvent(self, keycode, timeout=None, retries=None):
+    """Sends a keycode to the device.
+
+    See: http://developer.android.com/reference/android/view/KeyEvent.html
+
+    Args:
+      keycode: A integer keycode to send to the device.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    self.RunShellCommand(['input', 'keyevent', format(keycode, 'd')],
+                         check_return=True)
+
+  PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
+  PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES
+
+  @decorators.WithTimeoutAndRetriesDefaults(
+      PUSH_CHANGED_FILES_DEFAULT_TIMEOUT,
+      PUSH_CHANGED_FILES_DEFAULT_RETRIES)
+  def PushChangedFiles(self, host_device_tuples, timeout=None,
+                       retries=None):
+    """Push files to the device, skipping files that don't need updating.
+
+    Args:
+      host_device_tuples: A list of (host_path, device_path) tuples, where
+        |host_path| is an absolute path of a file or directory on the host
+        that should be minimially pushed to the device, and |device_path| is
+        an absolute path of the destination on the device.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError on failure.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+
+    files = []
+    for h, d in host_device_tuples:
+      if os.path.isdir(h):
+        self.RunShellCommand(['mkdir', '-p', d], check_return=True)
+      files += self._GetChangedFilesImpl(h, d)
+
+    if not files:
+      return
+
+    size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
+    file_count = len(files)
+    dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
+                   for h, _ in host_device_tuples)
+    dir_file_count = 0
+    for h, _ in host_device_tuples:
+      if os.path.isdir(h):
+        dir_file_count += sum(len(f) for _r, _d, f in os.walk(h))
+      else:
+        dir_file_count += 1
+
+    push_duration = self._ApproximateDuration(
+        file_count, file_count, size, False)
+    dir_push_duration = self._ApproximateDuration(
+        len(host_device_tuples), dir_file_count, dir_size, False)
+    zip_duration = self._ApproximateDuration(1, 1, size, True)
+
+    self._InstallCommands()
+
+    if dir_push_duration < push_duration and (
+        dir_push_duration < zip_duration or not self._commands_installed):
+      self._PushChangedFilesIndividually(host_device_tuples)
+    elif push_duration < zip_duration or not self._commands_installed:
+      self._PushChangedFilesIndividually(files)
+    else:
+      self._PushChangedFilesZipped(files)
+      self.RunShellCommand(
+          ['chmod', '-R', '777'] + [d for _, d in host_device_tuples],
+          as_root=True, check_return=True)
+
+  def _GetChangedFilesImpl(self, host_path, device_path):
+    real_host_path = os.path.realpath(host_path)
+    try:
+      real_device_path = self.RunShellCommand(
+          ['realpath', device_path], single_line=True, check_return=True)
+    except device_errors.CommandFailedError:
+      real_device_path = None
+    if not real_device_path:
+      return [(host_path, device_path)]
+
+    try:
+      host_checksums = md5sum.CalculateHostMd5Sums([real_host_path])
+      device_paths_to_md5 = (
+          real_device_path if os.path.isfile(real_host_path)
+          else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
+                for p in host_checksums.iterkeys()))
+      device_checksums = md5sum.CalculateDeviceMd5Sums(
+          device_paths_to_md5, self)
+    except EnvironmentError as e:
+      logging.warning('Error calculating md5: %s', e)
+      return [(host_path, device_path)]
+
+    if os.path.isfile(host_path):
+      host_checksum = host_checksums.get(real_host_path)
+      device_checksum = device_checksums.get(real_device_path)
+      if host_checksum != device_checksum:
+        return [(host_path, device_path)]
+      else:
+        return []
+    else:
+      to_push = []
+      for host_abs_path, host_checksum in host_checksums.iteritems():
+        device_abs_path = '%s/%s' % (
+            real_device_path, os.path.relpath(host_abs_path, real_host_path))
+        if (device_checksums.get(device_abs_path) != host_checksum):
+          to_push.append((host_abs_path, device_abs_path))
+      return to_push
+
+  def _InstallCommands(self):
+    if self._commands_installed is None:
+      try:
+        if not install_commands.Installed(self):
+          install_commands.InstallCommands(self)
+        self._commands_installed = True
+      except Exception as e:
+        logging.warning('unzip not available: %s' % str(e))
+        self._commands_installed = False
+
+  @staticmethod
+  def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
+    # We approximate the time to push a set of files to a device as:
+    #   t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
+    #     t: total time (sec)
+    #     c1: adb call time delay (sec)
+    #     a: number of times adb is called (unitless)
+    #     c2: push time delay (sec)
+    #     f: number of files pushed via adb (unitless)
+    #     c3: zip time delay (sec)
+    #     c4: zip rate (bytes/sec)
+    #     b: total number of bytes (bytes)
+    #     c5: transfer rate (bytes/sec)
+    #     c6: compression ratio (unitless)
+
+    # All of these are approximations.
+    ADB_CALL_PENALTY = 0.1 # seconds
+    ADB_PUSH_PENALTY = 0.01 # seconds
+    ZIP_PENALTY = 2.0 # seconds
+    ZIP_RATE = 10000000.0 # bytes / second
+    TRANSFER_RATE = 2000000.0 # bytes / second
+    COMPRESSION_RATIO = 2.0 # unitless
+
+    adb_call_time = ADB_CALL_PENALTY * adb_calls
+    adb_push_setup_time = ADB_PUSH_PENALTY * file_count
+    if is_zipping:
+      zip_time = ZIP_PENALTY + byte_count / ZIP_RATE
+      transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
+    else:
+      zip_time = 0
+      transfer_time = byte_count / TRANSFER_RATE
+    return adb_call_time + adb_push_setup_time + zip_time + transfer_time
+
+  def _PushChangedFilesIndividually(self, files):
+    for h, d in files:
+      self.adb.Push(h, d)
+
+  def _PushChangedFilesZipped(self, files):
+    if not files:
+      return
+
+    with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
+      zip_proc = multiprocessing.Process(
+          target=DeviceUtils._CreateDeviceZip,
+          args=(zip_file.name, files))
+      zip_proc.start()
+      zip_proc.join()
+
+      zip_on_device = '%s/tmp.zip' % self.GetExternalStoragePath()
+      try:
+        self.adb.Push(zip_file.name, zip_on_device)
+        self.RunShellCommand(
+            ['unzip', zip_on_device],
+            as_root=True,
+            env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
+            check_return=True)
+      finally:
+        if zip_proc.is_alive():
+          zip_proc.terminate()
+        if self.IsOnline():
+          self.RunShellCommand(['rm', zip_on_device], check_return=True)
+
+  @staticmethod
+  def _CreateDeviceZip(zip_path, host_device_tuples):
+    with zipfile.ZipFile(zip_path, 'w') as zip_file:
+      for host_path, device_path in host_device_tuples:
+        zip_utils.WriteToZipFile(zip_file, host_path, device_path)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def FileExists(self, device_path, timeout=None, retries=None):
+    """Checks whether the given file exists on the device.
+
+    Args:
+      device_path: A string containing the absolute path to the file on the
+                   device.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if the file exists on the device, False otherwise.
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    try:
+      self.RunShellCommand(['test', '-e', device_path], check_return=True)
+      return True
+    except device_errors.AdbCommandFailedError:
+      return False
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def PullFile(self, device_path, host_path, timeout=None, retries=None):
+    """Pull a file from the device.
+
+    Args:
+      device_path: A string containing the absolute path of the file to pull
+                   from the device.
+      host_path: A string containing the absolute path of the destination on
+                 the host.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError on failure.
+      CommandTimeoutError on timeout.
+    """
+    # Create the base dir if it doesn't exist already
+    dirname = os.path.dirname(host_path)
+    if dirname and not os.path.exists(dirname):
+      os.makedirs(dirname)
+    self.adb.Pull(device_path, host_path)
+
+  def _ReadFileWithPull(self, device_path):
+    try:
+      d = tempfile.mkdtemp()
+      host_temp_path = os.path.join(d, 'tmp_ReadFileWithPull')
+      self.adb.Pull(device_path, host_temp_path)
+      with open(host_temp_path, 'r') as host_temp:
+        return host_temp.read()
+    finally:
+      if os.path.exists(d):
+        shutil.rmtree(d)
+
+  _LS_RE = re.compile(
+      r'(?P<perms>\S+) +(?P<owner>\S+) +(?P<group>\S+) +(?:(?P<size>\d+) +)?'
+      + r'(?P<date>\S+) +(?P<time>\S+) +(?P<name>.+)$')
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def ReadFile(self, device_path, as_root=False, force_pull=False,
+               timeout=None, retries=None):
+    """Reads the contents of a file from the device.
+
+    Args:
+      device_path: A string containing the absolute path of the file to read
+                   from the device.
+      as_root: A boolean indicating whether the read should be executed with
+               root privileges.
+      force_pull: A boolean indicating whether to force the operation to be
+          performed by pulling a file from the device. The default is, when the
+          contents are short, to retrieve the contents using cat instead.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The contents of |device_path| as a string. Contents are intepreted using
+      universal newlines, so the caller will see them encoded as '\n'. Also,
+      all lines will be terminated.
+
+    Raises:
+      AdbCommandFailedError if the file can't be read.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    def get_size(path):
+      # TODO(jbudorick): Implement a generic version of Stat() that handles
+      # as_root=True, then switch this implementation to use that.
+      ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root,
+                                    check_return=True)
+      for line in ls_out:
+        m = self._LS_RE.match(line)
+        if m and m.group('name') == posixpath.basename(device_path):
+          return int(m.group('size'))
+      logging.warning('Could not determine size of %s.', device_path)
+      return None
+
+    if (not force_pull
+        and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH):
+      return _JoinLines(self.RunShellCommand(
+          ['cat', device_path], as_root=as_root, check_return=True))
+    elif as_root and self.NeedsSU():
+      with device_temp_file.DeviceTempFile(self.adb) as device_temp:
+        self.RunShellCommand(['cp', device_path, device_temp.name],
+                             as_root=True, check_return=True)
+        return self._ReadFileWithPull(device_temp.name)
+    else:
+      return self._ReadFileWithPull(device_path)
+
+  def _WriteFileWithPush(self, device_path, contents):
+    with tempfile.NamedTemporaryFile() as host_temp:
+      host_temp.write(contents)
+      host_temp.flush()
+      self.adb.Push(host_temp.name, device_path)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def WriteFile(self, device_path, contents, as_root=False, force_push=False,
+                timeout=None, retries=None):
+    """Writes |contents| to a file on the device.
+
+    Args:
+      device_path: A string containing the absolute path to the file to write
+          on the device.
+      contents: A string containing the data to write to the device.
+      as_root: A boolean indicating whether the write should be executed with
+          root privileges (if available).
+      force_push: A boolean indicating whether to force the operation to be
+          performed by pushing a file to the device. The default is, when the
+          contents are short, to pass the contents using a shell script instead.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError if the file could not be written on the device.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH:
+      # If the contents are small, for efficieny we write the contents with
+      # a shell command rather than pushing a file.
+      cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents),
+                                 cmd_helper.SingleQuote(device_path))
+      self.RunShellCommand(cmd, as_root=as_root, check_return=True)
+    elif as_root and self.NeedsSU():
+      # Adb does not allow to "push with su", so we first push to a temp file
+      # on a safe location, and then copy it to the desired location with su.
+      with device_temp_file.DeviceTempFile(self.adb) as device_temp:
+        self._WriteFileWithPush(device_temp.name, contents)
+        # Here we need 'cp' rather than 'mv' because the temp and
+        # destination files might be on different file systems (e.g.
+        # on internal storage and an external sd card).
+        self.RunShellCommand(['cp', device_temp.name, device_path],
+                             as_root=True, check_return=True)
+    else:
+      # If root is not needed, we can push directly to the desired location.
+      self._WriteFileWithPush(device_path, contents)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def Ls(self, device_path, timeout=None, retries=None):
+    """Lists the contents of a directory on the device.
+
+    Args:
+      device_path: A string containing the path of the directory on the device
+                   to list.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      A list of pairs (filename, stat) for each file found in the directory,
+      where the stat object has the properties: st_mode, st_size, and st_time.
+
+    Raises:
+      AdbCommandFailedError if |device_path| does not specify a valid and
+          accessible directory in the device.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    return self.adb.Ls(device_path)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def Stat(self, device_path, timeout=None, retries=None):
+    """Get the stat attributes of a file or directory on the device.
+
+    Args:
+      device_path: A string containing the path of from which to get attributes
+                   on the device.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      A stat object with the properties: st_mode, st_size, and st_time
+
+    Raises:
+      CommandFailedError if device_path cannot be found on the device.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    dirname, target = device_path.rsplit('/', 1)
+    for filename, stat in self.adb.Ls(dirname):
+      if filename == target:
+        return stat
+    raise device_errors.CommandFailedError(
+        'Cannot find file or directory: %r' % device_path, str(self))
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SetJavaAsserts(self, enabled, timeout=None, retries=None):
+    """Enables or disables Java asserts.
+
+    Args:
+      enabled: A boolean indicating whether Java asserts should be enabled
+               or disabled.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      True if the device-side property changed and a restart is required as a
+      result, False otherwise.
+
+    Raises:
+      CommandTimeoutError on timeout.
+    """
+    def find_property(lines, property_name):
+      for index, line in enumerate(lines):
+        if line.strip() == '':
+          continue
+        key, value = (s.strip() for s in line.split('=', 1))
+        if key == property_name:
+          return index, value
+      return None, ''
+
+    new_value = 'all' if enabled else ''
+
+    # First ensure the desired property is persisted.
+    try:
+      properties = self.ReadFile(
+          constants.DEVICE_LOCAL_PROPERTIES_PATH).splitlines()
+    except device_errors.CommandFailedError:
+      properties = []
+    index, value = find_property(properties, self.JAVA_ASSERT_PROPERTY)
+    if new_value != value:
+      if new_value:
+        new_line = '%s=%s' % (self.JAVA_ASSERT_PROPERTY, new_value)
+        if index is None:
+          properties.append(new_line)
+        else:
+          properties[index] = new_line
+      else:
+        assert index is not None # since new_value == '' and new_value != value
+        properties.pop(index)
+      self.WriteFile(constants.DEVICE_LOCAL_PROPERTIES_PATH,
+                     _JoinLines(properties))
+
+    # Next, check the current runtime value is what we need, and
+    # if not, set it and report that a reboot is required.
+    value = self.GetProp(self.JAVA_ASSERT_PROPERTY)
+    if new_value != value:
+      self.SetProp(self.JAVA_ASSERT_PROPERTY, new_value)
+      return True
+    else:
+      return False
+
+
+  @property
+  def build_description(self):
+    """Returns the build description of the system.
+
+    For example:
+      nakasi-user 4.4.4 KTU84P 1227136 release-keys
+    """
+    return self.GetProp('ro.build.description', cache=True)
+
+  @property
+  def build_fingerprint(self):
+    """Returns the build fingerprint of the system.
+
+    For example:
+      google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys
+    """
+    return self.GetProp('ro.build.fingerprint', cache=True)
+
+  @property
+  def build_id(self):
+    """Returns the build ID of the system (e.g. 'KTU84P')."""
+    return self.GetProp('ro.build.id', cache=True)
+
+  @property
+  def build_product(self):
+    """Returns the build product of the system (e.g. 'grouper')."""
+    return self.GetProp('ro.build.product', cache=True)
+
+  @property
+  def build_type(self):
+    """Returns the build type of the system (e.g. 'user')."""
+    return self.GetProp('ro.build.type', cache=True)
+
+  @property
+  def build_version_sdk(self):
+    """Returns the build version sdk of the system as a number (e.g. 19).
+
+    For version code numbers see:
+    http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
+
+    For named constants see:
+    pylib.constants.ANDROID_SDK_VERSION_CODES
+
+    Raises:
+      CommandFailedError if the build version sdk is not a number.
+    """
+    value = self.GetProp('ro.build.version.sdk', cache=True)
+    try:
+      return int(value)
+    except ValueError:
+      raise device_errors.CommandFailedError(
+          'Invalid build version sdk: %r' % value)
+
+  @property
+  def product_cpu_abi(self):
+    """Returns the product cpu abi of the device (e.g. 'armeabi-v7a')."""
+    return self.GetProp('ro.product.cpu.abi', cache=True)
+
+  @property
+  def product_model(self):
+    """Returns the name of the product model (e.g. 'Nexus 7')."""
+    return self.GetProp('ro.product.model', cache=True)
+
+  @property
+  def product_name(self):
+    """Returns the product name of the device (e.g. 'nakasi')."""
+    return self.GetProp('ro.product.name', cache=True)
+
+  def GetProp(self, property_name, cache=False, timeout=DEFAULT,
+              retries=DEFAULT):
+    """Gets a property from the device.
+
+    Args:
+      property_name: A string containing the name of the property to get from
+                     the device.
+      cache: A boolean indicating whether to cache the value of this property.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The value of the device's |property_name| property.
+
+    Raises:
+      CommandTimeoutError on timeout.
+    """
+    assert isinstance(property_name, basestring), (
+        "property_name is not a string: %r" % property_name)
+
+    cache_key = '_prop:' + property_name
+    if cache and cache_key in self._cache:
+      return self._cache[cache_key]
+    else:
+      # timeout and retries are handled down at run shell, because we don't
+      # want to apply them in the other branch when reading from the cache
+      value = self.RunShellCommand(
+          ['getprop', property_name], single_line=True, check_return=True,
+          timeout=self._default_timeout if timeout is DEFAULT else timeout,
+          retries=self._default_retries if retries is DEFAULT else retries)
+      if cache or cache_key in self._cache:
+        self._cache[cache_key] = value
+      return value
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def SetProp(self, property_name, value, check=False, timeout=None,
+              retries=None):
+    """Sets a property on the device.
+
+    Args:
+      property_name: A string containing the name of the property to set on
+                     the device.
+      value: A string containing the value to set to the property on the
+             device.
+      check: A boolean indicating whether to check that the property was
+             successfully set on the device.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Raises:
+      CommandFailedError if check is true and the property was not correctly
+        set on the device (e.g. because it is not rooted).
+      CommandTimeoutError on timeout.
+    """
+    assert isinstance(property_name, basestring), (
+        "property_name is not a string: %r" % property_name)
+    assert isinstance(value, basestring), "value is not a string: %r" % value
+
+    self.RunShellCommand(['setprop', property_name, value], check_return=True)
+    if property_name in self._cache:
+      del self._cache[property_name]
+    # TODO(perezju) remove the option and make the check mandatory, but using a
+    # single shell script to both set- and getprop.
+    if check and value != self.GetProp(property_name):
+      raise device_errors.CommandFailedError(
+          'Unable to set property %r on the device to %r'
+          % (property_name, value), str(self))
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetABI(self, timeout=None, retries=None):
+    """Gets the device main ABI.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The device's main ABI name.
+
+    Raises:
+      CommandTimeoutError on timeout.
+    """
+    return self.GetProp('ro.product.cpu.abi')
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetPids(self, process_name, timeout=None, retries=None):
+    """Returns the PIDs of processes with the given name.
+
+    Note that the |process_name| is often the package name.
+
+    Args:
+      process_name: A string containing the process name to get the PIDs for.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      A dict mapping process name to PID for each process that contained the
+      provided |process_name|.
+
+    Raises:
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    procs_pids = {}
+    try:
+      ps_output = self._RunPipedShellCommand(
+          'ps | grep -F %s' % cmd_helper.SingleQuote(process_name))
+    except device_errors.AdbShellCommandFailedError as e:
+      if e.status and isinstance(e.status, list) and not e.status[0]:
+        # If ps succeeded but grep failed, there were no processes with the
+        # given name.
+        return procs_pids
+      else:
+        raise
+
+    for line in ps_output:
+      try:
+        ps_data = line.split()
+        if process_name in ps_data[-1]:
+          procs_pids[ps_data[-1]] = ps_data[1]
+      except IndexError:
+        pass
+    return procs_pids
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
+    """Takes a screenshot of the device.
+
+    Args:
+      host_path: A string containing the path on the host to save the
+                 screenshot to. If None, a file name in the current
+                 directory will be generated.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The name of the file on the host to which the screenshot was saved.
+
+    Raises:
+      CommandFailedError on failure.
+      CommandTimeoutError on timeout.
+      DeviceUnreachableError on missing device.
+    """
+    if not host_path:
+      host_path = os.path.abspath('screenshot-%s.png' % _GetTimeStamp())
+    with device_temp_file.DeviceTempFile(self.adb, suffix='.png') as device_tmp:
+      self.RunShellCommand(['/system/bin/screencap', '-p', device_tmp.name],
+                           check_return=True)
+      self.PullFile(device_tmp.name, host_path)
+    return host_path
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetMemoryUsageForPid(self, pid, timeout=None, retries=None):
+    """Gets the memory usage for the given PID.
+
+    Args:
+      pid: PID of the process.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      A dict containing memory usage statistics for the PID. May include:
+        Size, Rss, Pss, Shared_Clean, Shared_Dirty, Private_Clean,
+        Private_Dirty, VmHWM
+
+    Raises:
+      CommandTimeoutError on timeout.
+    """
+    result = collections.defaultdict(int)
+
+    try:
+      result.update(self._GetMemoryUsageForPidFromSmaps(pid))
+    except device_errors.CommandFailedError:
+      logging.exception('Error getting memory usage from smaps')
+
+    try:
+      result.update(self._GetMemoryUsageForPidFromStatus(pid))
+    except device_errors.CommandFailedError:
+      logging.exception('Error getting memory usage from status')
+
+    return result
+
+  def _GetMemoryUsageForPidFromSmaps(self, pid):
+    SMAPS_COLUMNS = (
+        'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean',
+        'Private_Dirty')
+
+    showmap_out = self._RunPipedShellCommand(
+        'showmap %d | grep TOTAL' % int(pid), as_root=True)
+
+    split_totals = showmap_out[-1].split()
+    if (not split_totals
+        or len(split_totals) != 9
+        or split_totals[-1] != 'TOTAL'):
+      raise device_errors.CommandFailedError(
+          'Invalid output from showmap: %s' % '\n'.join(showmap_out))
+
+    return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals)))
+
+  def _GetMemoryUsageForPidFromStatus(self, pid):
+    for line in self.ReadFile(
+        '/proc/%s/status' % str(pid), as_root=True).splitlines():
+      if line.startswith('VmHWM:'):
+        return {'VmHWM': int(line.split()[1])}
+    else:
+      raise device_errors.CommandFailedError(
+          'Could not find memory peak value for pid %s', str(pid))
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetLogcatMonitor(self, timeout=None, retries=None, *args, **kwargs):
+    """Returns a new LogcatMonitor associated with this device.
+
+    Parameters passed to this function are passed directly to
+    |logcat_monitor.LogcatMonitor| and are documented there.
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+    """
+    return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetDevicePieWrapper(self, timeout=None, retries=None):
+    """Gets the absolute path to the run_pie wrapper on the device.
+
+    We have to build our device executables to be PIE, but they need to be able
+    to run on versions of android that don't support PIE (i.e. ICS and below).
+    To do so, we push a wrapper to the device that lets older android versions
+    run PIE executables. This method pushes that wrapper to the device if
+    necessary and returns the path to it.
+
+    This is exposed publicly to allow clients to write scripts using run_pie
+    (e.g. md5sum.CalculateDeviceMd5Sum).
+
+    Args:
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      The path to the PIE wrapper on the device, or an empty string if the
+      device does not require the wrapper.
+    """
+    if 'run_pie' not in self._cache:
+      pie = ''
+      if (self.build_version_sdk <
+          constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN):
+        host_pie_path = os.path.join(constants.GetOutDirectory(), 'run_pie')
+        if not os.path.exists(host_pie_path):
+          raise device_errors.CommandFailedError('Please build run_pie')
+        pie = '%s/run_pie' % constants.TEST_EXECUTABLE_DIR
+        self.adb.Push(host_pie_path, pie)
+
+      self._cache['run_pie'] = pie
+
+    return self._cache['run_pie']
+
+  def GetClientCache(self, client_name):
+    """Returns client cache."""
+    if client_name not in self._client_caches:
+      self._client_caches[client_name] = {}
+    return self._client_caches[client_name]
+
+  def _ClearCache(self):
+    """Clears all caches."""
+    for client in self._client_caches:
+      self._client_caches[client].clear()
+    self._cache.clear()
+
+  @classmethod
+  def parallel(cls, devices=None, async=False):
+    """Creates a Parallelizer to operate over the provided list of devices.
+
+    If |devices| is either |None| or an empty list, the Parallelizer will
+    operate over all attached devices that have not been blacklisted.
+
+    Args:
+      devices: A list of either DeviceUtils instances or objects from
+               from which DeviceUtils instances can be constructed. If None,
+               all attached devices will be used.
+      async: If true, returns a Parallelizer that runs operations
+             asynchronously.
+
+    Returns:
+      A Parallelizer operating over |devices|.
+    """
+    if not devices:
+      devices = cls.HealthyDevices()
+      if not devices:
+        raise device_errors.NoDevicesError()
+
+    devices = [d if isinstance(d, cls) else cls(d) for d in devices]
+    if async:
+      return parallelizer.Parallelizer(devices)
+    else:
+      return parallelizer.SyncParallelizer(devices)
+
+  @classmethod
+  def HealthyDevices(cls):
+    blacklist = device_blacklist.ReadBlacklist()
+    def blacklisted(adb):
+      if adb.GetDeviceSerial() in blacklist:
+        logging.warning('Device %s is blacklisted.', adb.GetDeviceSerial())
+        return True
+      return False
+
+    return [cls(adb) for adb in adb_wrapper.AdbWrapper.Devices()
+            if not blacklisted(adb)]
+
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
new file mode 100755
index 0000000..e5e3936
--- /dev/null
+++ b/build/android/pylib/device/device_utils_test.py
@@ -0,0 +1,1700 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for the contents of device_utils.py (mostly DeviceUtils).
+"""
+
+# pylint: disable=C0321
+# pylint: disable=W0212
+# pylint: disable=W0613
+
+import collections
+import datetime
+import logging
+import os
+import re
+import sys
+import unittest
+
+from pylib import android_commands
+from pylib import cmd_helper
+from pylib import constants
+from pylib import device_signal
+from pylib.device import adb_wrapper
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.device import intent
+from pylib.utils import mock_calls
+
+# RunCommand from third_party/android_testrunner/run_command.py is mocked
+# below, so its path needs to be in sys.path.
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner'))
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class DeviceUtilsInitTest(unittest.TestCase):
+
+  def testInitWithStr(self):
+    serial_as_str = str('0123456789abcdef')
+    d = device_utils.DeviceUtils('0123456789abcdef')
+    self.assertEqual(serial_as_str, d.adb.GetDeviceSerial())
+
+  def testInitWithUnicode(self):
+    serial_as_unicode = unicode('fedcba9876543210')
+    d = device_utils.DeviceUtils(serial_as_unicode)
+    self.assertEqual(serial_as_unicode, d.adb.GetDeviceSerial())
+
+  def testInitWithAdbWrapper(self):
+    serial = '123456789abcdef0'
+    a = adb_wrapper.AdbWrapper(serial)
+    d = device_utils.DeviceUtils(a)
+    self.assertEqual(serial, d.adb.GetDeviceSerial())
+
+  def testInitWithAndroidCommands(self):
+    serial = '0fedcba987654321'
+    a = android_commands.AndroidCommands(device=serial)
+    d = device_utils.DeviceUtils(a)
+    self.assertEqual(serial, d.adb.GetDeviceSerial())
+
+  def testInitWithMissing_fails(self):
+    with self.assertRaises(ValueError):
+      device_utils.DeviceUtils(None)
+    with self.assertRaises(ValueError):
+      device_utils.DeviceUtils('')
+
+
+class DeviceUtilsGetAVDsTest(mock_calls.TestCase):
+
+  def testGetAVDs(self):
+    with self.assertCall(
+        mock.call.pylib.cmd_helper.GetCmdOutput([mock.ANY, 'list', 'avd']),
+        'Available Android Virtual Devices:\n'
+        '    Name: my_android5.0\n'
+        '    Path: /some/path/to/.android/avd/my_android5.0.avd\n'
+        '  Target: Android 5.0 (API level 21)\n'
+        ' Tag/ABI: default/x86\n'
+        '    Skin: WVGA800\n'):
+      self.assertEquals(['my_android5.0'],
+                        device_utils.GetAVDs())
+
+
+class DeviceUtilsRestartServerTest(mock_calls.TestCase):
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testRestartServer_succeeds(self):
+    with self.assertCalls(
+        mock.call.pylib.device.adb_wrapper.AdbWrapper.KillServer(),
+        (mock.call.pylib.cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb']),
+         (1, '')),
+        mock.call.pylib.device.adb_wrapper.AdbWrapper.StartServer(),
+        (mock.call.pylib.cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb']),
+         (1, '')),
+        (mock.call.pylib.cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb']),
+         (0, '123\n'))):
+      device_utils.RestartServer()
+
+
+class MockTempFile(object):
+
+  def __init__(self, name='/tmp/some/file'):
+    self.file = mock.MagicMock(spec=file)
+    self.file.name = name
+    self.file.name_quoted = cmd_helper.SingleQuote(name)
+
+  def __enter__(self):
+    return self.file
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    pass
+
+  @property
+  def name(self):
+    return self.file.name
+
+
+class _PatchedFunction(object):
+  def __init__(self, patched=None, mocked=None):
+    self.patched = patched
+    self.mocked = mocked
+
+
+def _AdbWrapperMock(test_serial):
+  adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
+  adb.__str__ = mock.Mock(return_value=test_serial)
+  adb.GetDeviceSerial.return_value = test_serial
+  return adb
+
+
+class DeviceUtilsTest(mock_calls.TestCase):
+
+  def setUp(self):
+    self.adb = _AdbWrapperMock('0123456789abcdef')
+    self.device = device_utils.DeviceUtils(
+        self.adb, default_timeout=10, default_retries=0)
+    self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
+
+  def ShellError(self, output=None, status=1):
+    def action(cmd, *args, **kwargs):
+      raise device_errors.AdbShellCommandFailedError(
+          cmd, output, status, str(self.device))
+    if output is None:
+      output = 'Permission denied\n'
+    return action
+
+  def TimeoutError(self, msg=None):
+    if msg is None:
+      msg = 'Operation timed out'
+    return mock.Mock(side_effect=device_errors.CommandTimeoutError(
+        msg, str(self.device)))
+
+  def CommandError(self, msg=None):
+    if msg is None:
+      msg = 'Command failed'
+    return mock.Mock(side_effect=device_errors.CommandFailedError(
+        msg, str(self.device)))
+
+
+class DeviceUtilsEqTest(DeviceUtilsTest):
+
+  def testEq_equal_deviceUtils(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
+    self.assertTrue(self.device == other)
+    self.assertTrue(other == self.device)
+
+  def testEq_equal_adbWrapper(self):
+    other = adb_wrapper.AdbWrapper('0123456789abcdef')
+    self.assertTrue(self.device == other)
+    self.assertTrue(other == self.device)
+
+  def testEq_equal_string(self):
+    other = '0123456789abcdef'
+    self.assertTrue(self.device == other)
+    self.assertTrue(other == self.device)
+
+  def testEq_devicesNotEqual(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee'))
+    self.assertFalse(self.device == other)
+    self.assertFalse(other == self.device)
+
+  def testEq_identity(self):
+    self.assertTrue(self.device == self.device)
+
+  def testEq_serialInList(self):
+    devices = [self.device]
+    self.assertTrue('0123456789abcdef' in devices)
+
+
+class DeviceUtilsLtTest(DeviceUtilsTest):
+
+  def testLt_lessThan(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff'))
+    self.assertTrue(self.device < other)
+    self.assertTrue(other > self.device)
+
+  def testLt_greaterThan_lhs(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000'))
+    self.assertFalse(self.device < other)
+    self.assertFalse(other > self.device)
+
+  def testLt_equal(self):
+    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
+    self.assertFalse(self.device < other)
+    self.assertFalse(other > self.device)
+
+  def testLt_sorted(self):
+    devices = [
+        device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')),
+        device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')),
+    ]
+    sorted_devices = sorted(devices)
+    self.assertEquals('0000000000000000',
+                      sorted_devices[0].adb.GetDeviceSerial())
+    self.assertEquals('ffffffffffffffff',
+                      sorted_devices[1].adb.GetDeviceSerial())
+
+
+class DeviceUtilsStrTest(DeviceUtilsTest):
+
+  def testStr_returnsSerial(self):
+    with self.assertCalls(
+        (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
+      self.assertEqual('0123456789abcdef', str(self.device))
+
+
+class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
+
+  def testIsOnline_true(self):
+    with self.assertCall(self.call.adb.GetState(), 'device'):
+      self.assertTrue(self.device.IsOnline())
+
+  def testIsOnline_false(self):
+    with self.assertCall(self.call.adb.GetState(), 'offline'):
+      self.assertFalse(self.device.IsOnline())
+
+  def testIsOnline_error(self):
+    with self.assertCall(self.call.adb.GetState(), self.CommandError()):
+      self.assertFalse(self.device.IsOnline())
+
+
+class DeviceUtilsHasRootTest(DeviceUtilsTest):
+
+  def testHasRoot_true(self):
+    with self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n'):
+      self.assertTrue(self.device.HasRoot())
+
+  def testHasRoot_false(self):
+    with self.assertCall(self.call.adb.Shell('ls /root'), self.ShellError()):
+      self.assertFalse(self.device.HasRoot())
+
+
+class DeviceUtilsEnableRootTest(DeviceUtilsTest):
+
+  def testEnableRoot_succeeds(self):
+    with self.assertCalls(
+        (self.call.device.IsUserBuild(), False),
+        self.call.adb.Root(),
+        self.call.adb.WaitForDevice()):
+      self.device.EnableRoot()
+
+  def testEnableRoot_userBuild(self):
+    with self.assertCalls(
+        (self.call.device.IsUserBuild(), True)):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.EnableRoot()
+
+  def testEnableRoot_rootFails(self):
+    with self.assertCalls(
+        (self.call.device.IsUserBuild(), False),
+        (self.call.adb.Root(), self.CommandError())):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.EnableRoot()
+
+
+class DeviceUtilsIsUserBuildTest(DeviceUtilsTest):
+
+  def testIsUserBuild_yes(self):
+    with self.assertCall(
+        self.call.device.GetProp('ro.build.type', cache=True), 'user'):
+      self.assertTrue(self.device.IsUserBuild())
+
+  def testIsUserBuild_no(self):
+    with self.assertCall(
+        self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'):
+      self.assertFalse(self.device.IsUserBuild())
+
+
+class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest):
+
+  def testGetExternalStoragePath_succeeds(self):
+    with self.assertCall(
+        self.call.adb.Shell('echo $EXTERNAL_STORAGE'), '/fake/storage/path\n'):
+      self.assertEquals('/fake/storage/path',
+                        self.device.GetExternalStoragePath())
+
+  def testGetExternalStoragePath_fails(self):
+    with self.assertCall(self.call.adb.Shell('echo $EXTERNAL_STORAGE'), '\n'):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.GetExternalStoragePath()
+
+
+class DeviceUtilsGetApplicationPathTest(DeviceUtilsTest):
+
+  def testGetApplicationPath_exists(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'),
+        (self.call.adb.Shell('pm path android'),
+         'package:/path/to/android.apk\n')):
+      self.assertEquals('/path/to/android.apk',
+                        self.device.GetApplicationPath('android'))
+
+  def testGetApplicationPath_notExists(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'),
+        (self.call.adb.Shell('pm path not.installed.app'), '')):
+      self.assertEquals(None,
+                        self.device.GetApplicationPath('not.installed.app'))
+
+  def testGetApplicationPath_fails(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'),
+        (self.call.adb.Shell('pm path android'),
+         self.CommandError('ERROR. Is package manager running?\n'))):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.GetApplicationPath('android')
+
+
+@mock.patch('time.sleep', mock.Mock())
+class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest):
+
+  def testWaitUntilFullyBooted_succeedsNoWifi(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '1')):
+      self.device.WaitUntilFullyBooted(wifi=False)
+
+  def testWaitUntilFullyBooted_succeedsWithWifi(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '1'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'),
+         'stuff\nWi-Fi is enabled\nmore stuff\n')):
+      self.device.WaitUntilFullyBooted(wifi=True)
+
+  def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.CommandError())):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.WaitUntilFullyBooted(wifi=False)
+
+  def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'),
+         self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=False)
+
+  def testWaitUntilFullyBooted_devicePmFails(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'), self.CommandError()),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'), self.CommandError()),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'), self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=False)
+
+  def testWaitUntilFullyBooted_bootFails(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '0'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '0'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=False)
+
+  def testWaitUntilFullyBooted_wifiFails(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '1'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=True)
+
+
+@mock.patch('time.sleep', mock.Mock())
+class DeviceUtilsRebootTest(DeviceUtilsTest):
+
+  def testReboot_nonBlocking(self):
+    with self.assertCalls(
+        self.call.adb.Reboot(),
+        (self.call.device.IsOnline(), True),
+        (self.call.device.IsOnline(), False)):
+      self.device.Reboot(block=False)
+
+  def testReboot_blocking(self):
+    with self.assertCalls(
+        self.call.adb.Reboot(),
+        (self.call.device.IsOnline(), True),
+        (self.call.device.IsOnline(), False),
+        self.call.device.WaitUntilFullyBooted(wifi=False)):
+      self.device.Reboot(block=True)
+
+  def testReboot_blockUntilWifi(self):
+    with self.assertCalls(
+        self.call.adb.Reboot(),
+        (self.call.device.IsOnline(), True),
+        (self.call.device.IsOnline(), False),
+        self.call.device.WaitUntilFullyBooted(wifi=True)):
+      self.device.Reboot(block=True, wifi=True)
+
+
+class DeviceUtilsInstallTest(DeviceUtilsTest):
+
+  def testInstall_noPriorInstall(self):
+    with self.assertCalls(
+        (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'),
+         'this.is.a.test.package'),
+        (self.call.device.GetApplicationPath('this.is.a.test.package'), None),
+        self.call.adb.Install('/fake/test/app.apk', reinstall=False)):
+      self.device.Install('/fake/test/app.apk', retries=0)
+
+  def testInstall_differentPriorInstall(self):
+    with self.assertCalls(
+        (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'),
+         'this.is.a.test.package'),
+        (self.call.device.GetApplicationPath('this.is.a.test.package'),
+         '/fake/data/app/this.is.a.test.package.apk'),
+        (self.call.device._GetChangedFilesImpl(
+            '/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk'),
+         [('/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk')]),
+        self.call.adb.Uninstall('this.is.a.test.package'),
+        self.call.adb.Install('/fake/test/app.apk', reinstall=False)):
+      self.device.Install('/fake/test/app.apk', retries=0)
+
+  def testInstall_differentPriorInstall_reinstall(self):
+    with self.assertCalls(
+        (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'),
+         'this.is.a.test.package'),
+        (self.call.device.GetApplicationPath('this.is.a.test.package'),
+         '/fake/data/app/this.is.a.test.package.apk'),
+        (self.call.device._GetChangedFilesImpl(
+            '/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk'),
+         [('/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk')]),
+        self.call.adb.Install('/fake/test/app.apk', reinstall=True)):
+      self.device.Install('/fake/test/app.apk', reinstall=True, retries=0)
+
+  def testInstall_identicalPriorInstall(self):
+    with self.assertCalls(
+        (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'),
+         'this.is.a.test.package'),
+        (self.call.device.GetApplicationPath('this.is.a.test.package'),
+         '/fake/data/app/this.is.a.test.package.apk'),
+        (self.call.device._GetChangedFilesImpl(
+            '/fake/test/app.apk', '/fake/data/app/this.is.a.test.package.apk'),
+         [])):
+      self.device.Install('/fake/test/app.apk', retries=0)
+
+  def testInstall_fails(self):
+    with self.assertCalls(
+        (mock.call.pylib.utils.apk_helper.GetPackageName('/fake/test/app.apk'),
+         'this.is.a.test.package'),
+        (self.call.device.GetApplicationPath('this.is.a.test.package'), None),
+        (self.call.adb.Install('/fake/test/app.apk', reinstall=False),
+         self.CommandError('Failure\r\n'))):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.Install('/fake/test/app.apk', retries=0)
+
+
+class DeviceUtilsRunShellCommandTest(DeviceUtilsTest):
+
+  def setUp(self):
+    super(DeviceUtilsRunShellCommandTest, self).setUp()
+    self.device.NeedsSU = mock.Mock(return_value=False)
+
+  def testRunShellCommand_commandAsList(self):
+    with self.assertCall(self.call.adb.Shell('pm list packages'), ''):
+      self.device.RunShellCommand(['pm', 'list', 'packages'])
+
+  def testRunShellCommand_commandAsListQuoted(self):
+    with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''):
+      self.device.RunShellCommand(['echo', 'hello world', '$10'])
+
+  def testRunShellCommand_commandAsString(self):
+    with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''):
+      self.device.RunShellCommand('echo "$VAR"')
+
+  def testNewRunShellImpl_withEnv(self):
+    with self.assertCall(
+        self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''):
+      self.device.RunShellCommand('echo "$VAR"', env={'VAR': 'some_string'})
+
+  def testNewRunShellImpl_withEnvQuoted(self):
+    with self.assertCall(
+        self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''):
+      self.device.RunShellCommand('run_this', env={'PATH': '$PATH:/other/path'})
+
+  def testNewRunShellImpl_withEnv_failure(self):
+    with self.assertRaises(KeyError):
+      self.device.RunShellCommand('some_cmd', env={'INVALID NAME': 'value'})
+
+  def testNewRunShellImpl_withCwd(self):
+    with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''):
+      self.device.RunShellCommand('ls', cwd='/some/test/path')
+
+  def testNewRunShellImpl_withCwdQuoted(self):
+    with self.assertCall(
+        self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''):
+      self.device.RunShellCommand('ls', cwd='/some test/path with/spaces')
+
+  def testRunShellCommand_withHugeCmd(self):
+    payload = 'hi! ' * 1024
+    expected_cmd = "echo '%s'" % payload
+    with self.assertCalls(
+      (mock.call.pylib.utils.device_temp_file.DeviceTempFile(
+          self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
+      self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd),
+      (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
+      self.assertEquals([payload],
+                        self.device.RunShellCommand(['echo', payload]))
+
+  def testRunShellCommand_withHugeCmdAmdSU(self):
+    payload = 'hi! ' * 1024
+    expected_cmd = """su -c sh -c 'echo '"'"'%s'"'"''""" % payload
+    with self.assertCalls(
+      (self.call.device.NeedsSU(), True),
+      (mock.call.pylib.utils.device_temp_file.DeviceTempFile(
+          self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
+      self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd),
+      (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
+      self.assertEquals(
+          [payload],
+          self.device.RunShellCommand(['echo', payload], as_root=True))
+
+  def testRunShellCommand_withSu(self):
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (self.call.adb.Shell("su -c sh -c 'setprop service.adb.root 0'"), '')):
+      self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
+
+  def testRunShellCommand_manyLines(self):
+    cmd = 'ls /some/path'
+    with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'):
+      self.assertEquals(['file1', 'file2', 'file3'],
+                        self.device.RunShellCommand(cmd))
+
+  def testRunShellCommand_singleLine_success(self):
+    cmd = 'echo $VALUE'
+    with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'):
+      self.assertEquals('some value',
+                        self.device.RunShellCommand(cmd, single_line=True))
+
+  def testRunShellCommand_singleLine_successEmptyLine(self):
+    cmd = 'echo $VALUE'
+    with self.assertCall(self.call.adb.Shell(cmd), '\n'):
+      self.assertEquals('',
+                        self.device.RunShellCommand(cmd, single_line=True))
+
+  def testRunShellCommand_singleLine_successWithoutEndLine(self):
+    cmd = 'echo -n $VALUE'
+    with self.assertCall(self.call.adb.Shell(cmd), 'some value'):
+      self.assertEquals('some value',
+                        self.device.RunShellCommand(cmd, single_line=True))
+
+  def testRunShellCommand_singleLine_successNoOutput(self):
+    cmd = 'echo -n $VALUE'
+    with self.assertCall(self.call.adb.Shell(cmd), ''):
+      self.assertEquals('',
+                        self.device.RunShellCommand(cmd, single_line=True))
+
+  def testRunShellCommand_singleLine_failTooManyLines(self):
+    cmd = 'echo $VALUE'
+    with self.assertCall(self.call.adb.Shell(cmd),
+                         'some value\nanother value\n'):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.RunShellCommand(cmd, single_line=True)
+
+  def testRunShellCommand_checkReturn_success(self):
+    cmd = 'echo $ANDROID_DATA'
+    output = '/data\n'
+    with self.assertCall(self.call.adb.Shell(cmd), output):
+      self.assertEquals([output.rstrip()],
+                        self.device.RunShellCommand(cmd, check_return=True))
+
+  def testRunShellCommand_checkReturn_failure(self):
+    cmd = 'ls /root'
+    output = 'opendir failed, Permission denied\n'
+    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
+      with self.assertRaises(device_errors.AdbCommandFailedError):
+        self.device.RunShellCommand(cmd, check_return=True)
+
+  def testRunShellCommand_checkReturn_disabled(self):
+    cmd = 'ls /root'
+    output = 'opendir failed, Permission denied\n'
+    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
+      self.assertEquals([output.rstrip()],
+                        self.device.RunShellCommand(cmd, check_return=False))
+
+  def testRunShellCommand_largeOutput_enabled(self):
+    cmd = 'echo $VALUE'
+    temp_file = MockTempFile('/sdcard/temp-123')
+    cmd_redirect = '%s > %s' % (cmd, temp_file.name)
+    with self.assertCalls(
+        (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
+            temp_file),
+        (self.call.adb.Shell(cmd_redirect)),
+        (self.call.device.ReadFile(temp_file.name, force_pull=True),
+         'something')):
+      self.assertEquals(
+          ['something'],
+          self.device.RunShellCommand(
+              cmd, large_output=True, check_return=True))
+
+  def testRunShellCommand_largeOutput_disabledNoTrigger(self):
+    cmd = 'something'
+    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError('')):
+      with self.assertRaises(device_errors.AdbCommandFailedError):
+        self.device.RunShellCommand(cmd, check_return=True)
+
+  def testRunShellCommand_largeOutput_disabledTrigger(self):
+    cmd = 'echo $VALUE'
+    temp_file = MockTempFile('/sdcard/temp-123')
+    cmd_redirect = '%s > %s' % (cmd, temp_file.name)
+    with self.assertCalls(
+        (self.call.adb.Shell(cmd), self.ShellError('', None)),
+        (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
+            temp_file),
+        (self.call.adb.Shell(cmd_redirect)),
+        (self.call.device.ReadFile(mock.ANY, force_pull=True),
+         'something')):
+      self.assertEquals(['something'],
+                        self.device.RunShellCommand(cmd, check_return=True))
+
+
+class DeviceUtilsRunPipedShellCommandTest(DeviceUtilsTest):
+
+  def testRunPipedShellCommand_success(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
+            check_return=True),
+        ['This line contains foo', 'PIPESTATUS: 0 0']):
+      self.assertEquals(['This line contains foo'],
+                        self.device._RunPipedShellCommand('ps | grep foo'))
+
+  def testRunPipedShellCommand_firstCommandFails(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
+            check_return=True),
+        ['PIPESTATUS: 1 0']):
+      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
+        self.device._RunPipedShellCommand('ps | grep foo')
+      self.assertEquals([1, 0], ec.exception.status)
+
+  def testRunPipedShellCommand_secondCommandFails(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
+            check_return=True),
+        ['PIPESTATUS: 0 1']):
+      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
+        self.device._RunPipedShellCommand('ps | grep foo')
+      self.assertEquals([0, 1], ec.exception.status)
+
+  def testRunPipedShellCommand_outputCutOff(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
+            check_return=True),
+        ['foo.bar'] * 256 + ['foo.ba']):
+      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
+        self.device._RunPipedShellCommand('ps | grep foo')
+      self.assertIs(None, ec.exception.status)
+
+
+class DeviceUtilsGetDevicePieWrapper(DeviceUtilsTest):
+
+  def testGetDevicePieWrapper_jb(self):
+    with self.assertCall(
+        self.call.device.build_version_sdk(),
+        constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN):
+      self.assertEqual('', self.device.GetDevicePieWrapper())
+
+  def testGetDevicePieWrapper_ics(self):
+    with self.assertCalls(
+        (self.call.device.build_version_sdk(),
+         constants.ANDROID_SDK_VERSION_CODES.ICE_CREAM_SANDWICH),
+        (mock.call.pylib.constants.GetOutDirectory(), '/foo/bar'),
+        (mock.call.os.path.exists(mock.ANY), True),
+        (self.call.adb.Push(mock.ANY, mock.ANY), '')):
+      self.assertNotEqual('', self.device.GetDevicePieWrapper())
+
+
+@mock.patch('time.sleep', mock.Mock())
+class DeviceUtilsKillAllTest(DeviceUtilsTest):
+
+  def testKillAll_noMatchingProcessesFailure(self):
+    with self.assertCall(self.call.device.GetPids('test_process'), {}):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.KillAll('test_process')
+
+  def testKillAll_noMatchingProcessesQuiet(self):
+    with self.assertCall(self.call.device.GetPids('test_process'), {}):
+      self.assertEqual(0, self.device.KillAll('test_process', quiet=True))
+
+  def testKillAll_nonblocking(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'), {'some.process': '1234'}),
+        (self.call.adb.Shell('kill -9 1234'), '')):
+      self.assertEquals(
+          1, self.device.KillAll('some.process', blocking=False))
+
+  def testKillAll_blocking(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'), {'some.process': '1234'}),
+        (self.call.adb.Shell('kill -9 1234'), ''),
+        (self.call.device.GetPids('some.process'), {'some.process': '1234'}),
+        (self.call.device.GetPids('some.process'), [])):
+      self.assertEquals(
+          1, self.device.KillAll('some.process', blocking=True))
+
+  def testKillAll_root(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'), {'some.process': '1234'}),
+        (self.call.device.NeedsSU(), True),
+        (self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')):
+      self.assertEquals(
+          1, self.device.KillAll('some.process', as_root=True))
+
+  def testKillAll_sigterm(self):
+    with self.assertCalls(
+        (self.call.device.GetPids('some.process'), {'some.process': '1234'}),
+        (self.call.adb.Shell('kill -15 1234'), '')):
+      self.assertEquals(
+          1, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
+
+
+class DeviceUtilsStartActivityTest(DeviceUtilsTest):
+
+  def testStartActivity_actionOnly(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_success(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_failure(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main'),
+        'Error: Failed to start test activity'):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.StartActivity(test_intent)
+
+  def testStartActivity_blocking(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-W '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent, blocking=True)
+
+  def testStartActivity_withCategory(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                category='android.intent.category.HOME')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-c android.intent.category.HOME '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_withMultipleCategories(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                category=['android.intent.category.HOME',
+                                          'android.intent.category.BROWSABLE'])
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-c android.intent.category.HOME '
+                            '-c android.intent.category.BROWSABLE '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_withData(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                data='http://www.google.com/')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-d http://www.google.com/ '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_withStringExtra(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                extras={'foo': 'test'})
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main '
+                            '--es foo test'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_withBoolExtra(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                extras={'foo': True})
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main '
+                            '--ez foo True'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_withIntExtra(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                extras={'foo': 123})
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main '
+                            '--ei foo 123'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+  def testStartActivity_withTraceFile(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '--start-profiler test_trace_file.out '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent,
+                                trace_file_name='test_trace_file.out')
+
+  def testStartActivity_withForceStop(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-S '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent, force_stop=True)
+
+  def testStartActivity_withFlags(self):
+    test_intent = intent.Intent(action='android.intent.action.VIEW',
+                                package='this.is.a.test.package',
+                                activity='.Main',
+                                flags='0x10000000')
+    with self.assertCall(
+        self.call.adb.Shell('am start '
+                            '-a android.intent.action.VIEW '
+                            '-n this.is.a.test.package/.Main '
+                            '-f 0x10000000'),
+        'Starting: Intent { act=android.intent.action.VIEW }'):
+      self.device.StartActivity(test_intent)
+
+
+class DeviceUtilsStartInstrumentationTest(DeviceUtilsTest):
+
+  def testStartInstrumentation_nothing(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            ['am', 'instrument', 'test.package/.TestInstrumentation'],
+            check_return=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=False, extras=None)
+
+  def testStartInstrumentation_finish(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['am', 'instrument', '-w', 'test.package/.TestInstrumentation'],
+            check_return=True),
+         ['OK (1 test)'])):
+      output = self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=True, raw=False, extras=None)
+      self.assertEquals(['OK (1 test)'], output)
+
+  def testStartInstrumentation_raw(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            ['am', 'instrument', '-r', 'test.package/.TestInstrumentation'],
+            check_return=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=True, extras=None)
+
+  def testStartInstrumentation_extras(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            ['am', 'instrument', '-e', 'foo', 'Foo', '-e', 'bar', 'Bar',
+             'test.package/.TestInstrumentation'],
+            check_return=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=False, extras={'foo': 'Foo', 'bar': 'Bar'})
+
+
+class DeviceUtilsBroadcastIntentTest(DeviceUtilsTest):
+
+  def testBroadcastIntent_noExtras(self):
+    test_intent = intent.Intent(action='test.package.with.an.INTENT')
+    with self.assertCall(
+        self.call.adb.Shell('am broadcast -a test.package.with.an.INTENT'),
+        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
+      self.device.BroadcastIntent(test_intent)
+
+  def testBroadcastIntent_withExtra(self):
+    test_intent = intent.Intent(action='test.package.with.an.INTENT',
+                                extras={'foo': 'bar value'})
+    with self.assertCall(
+        self.call.adb.Shell(
+            "am broadcast -a test.package.with.an.INTENT --es foo 'bar value'"),
+        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
+      self.device.BroadcastIntent(test_intent)
+
+  def testBroadcastIntent_withExtra_noValue(self):
+    test_intent = intent.Intent(action='test.package.with.an.INTENT',
+                                extras={'foo': None})
+    with self.assertCall(
+        self.call.adb.Shell(
+            'am broadcast -a test.package.with.an.INTENT --esn foo'),
+        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
+      self.device.BroadcastIntent(test_intent)
+
+
+class DeviceUtilsGoHomeTest(DeviceUtilsTest):
+
+  def testGoHome(self):
+    with self.assertCall(
+        self.call.adb.Shell('am start -W -a android.intent.action.MAIN '
+                            '-c android.intent.category.HOME'),
+        'Starting: Intent { act=android.intent.action.MAIN }\r\n'):
+      self.device.GoHome()
+
+
+class DeviceUtilsForceStopTest(DeviceUtilsTest):
+
+  def testForceStop(self):
+    with self.assertCall(
+        self.call.adb.Shell('am force-stop this.is.a.test.package'),
+        ''):
+      self.device.ForceStop('this.is.a.test.package')
+
+
+class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest):
+
+  def testClearApplicationState_packageDoesntExist(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '17\n'),
+        (self.call.device.GetApplicationPath('this.package.does.not.exist'),
+         None)):
+      self.device.ClearApplicationState('this.package.does.not.exist')
+
+  def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '18\n'),
+        (self.call.adb.Shell('pm clear this.package.does.not.exist'),
+         'Failed\r\n')):
+      self.device.ClearApplicationState('this.package.does.not.exist')
+
+  def testClearApplicationState_packageExists(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '17\n'),
+        (self.call.device.GetApplicationPath('this.package.exists'),
+         '/data/app/this.package.exists.apk'),
+        (self.call.adb.Shell('pm clear this.package.exists'),
+         'Success\r\n')):
+      self.device.ClearApplicationState('this.package.exists')
+
+  def testClearApplicationState_packageExistsOnAndroidJBMR2OrAbove(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '18\n'),
+        (self.call.adb.Shell('pm clear this.package.exists'),
+         'Success\r\n')):
+      self.device.ClearApplicationState('this.package.exists')
+
+
+class DeviceUtilsSendKeyEventTest(DeviceUtilsTest):
+
+  def testSendKeyEvent(self):
+    with self.assertCall(self.call.adb.Shell('input keyevent 66'), ''):
+      self.device.SendKeyEvent(66)
+
+
+class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsTest):
+
+  def testPushChangedFilesIndividually_empty(self):
+    test_files = []
+    with self.assertCalls():
+      self.device._PushChangedFilesIndividually(test_files)
+
+  def testPushChangedFilesIndividually_single(self):
+    test_files = [('/test/host/path', '/test/device/path')]
+    with self.assertCalls(self.call.adb.Push(*test_files[0])):
+      self.device._PushChangedFilesIndividually(test_files)
+
+  def testPushChangedFilesIndividually_multiple(self):
+    test_files = [
+        ('/test/host/path/file1', '/test/device/path/file1'),
+        ('/test/host/path/file2', '/test/device/path/file2')]
+    with self.assertCalls(
+        self.call.adb.Push(*test_files[0]),
+        self.call.adb.Push(*test_files[1])):
+      self.device._PushChangedFilesIndividually(test_files)
+
+
+class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest):
+
+  def testPushChangedFilesZipped_empty(self):
+    test_files = []
+    with self.assertCalls():
+      self.device._PushChangedFilesZipped(test_files)
+
+  def _testPushChangedFilesZipped_spec(self, test_files):
+    mock_zip_temp = mock.mock_open()
+    mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
+    with self.assertCalls(
+        (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp),
+        (mock.call.multiprocessing.Process(
+            target=device_utils.DeviceUtils._CreateDeviceZip,
+            args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()),
+        (self.call.device.GetExternalStoragePath(),
+         '/test/device/external_dir'),
+        self.call.adb.Push(
+            '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip'),
+        self.call.device.RunShellCommand(
+            ['unzip', '/test/device/external_dir/tmp.zip'],
+            as_root=True,
+            env={'PATH': '/data/local/tmp/bin:$PATH'},
+            check_return=True),
+        (self.call.device.IsOnline(), True),
+        self.call.device.RunShellCommand(
+            ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)):
+      self.device._PushChangedFilesZipped(test_files)
+
+  def testPushChangedFilesZipped_single(self):
+    self._testPushChangedFilesZipped_spec(
+        [('/test/host/path/file1', '/test/device/path/file1')])
+
+  def testPushChangedFilesZipped_multiple(self):
+    self._testPushChangedFilesZipped_spec(
+        [('/test/host/path/file1', '/test/device/path/file1'),
+         ('/test/host/path/file2', '/test/device/path/file2')])
+
+
+class DeviceUtilsFileExistsTest(DeviceUtilsTest):
+
+  def testFileExists_usingTest_fileExists(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['test', '-e', '/path/file.exists'], check_return=True), ''):
+      self.assertTrue(self.device.FileExists('/path/file.exists'))
+
+  def testFileExists_usingTest_fileDoesntExist(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['test', '-e', '/does/not/exist'], check_return=True),
+        self.ShellError('', 1)):
+      self.assertFalse(self.device.FileExists('/does/not/exist'))
+
+
+class DeviceUtilsPullFileTest(DeviceUtilsTest):
+
+  def testPullFile_existsOnDevice(self):
+    with mock.patch('os.path.exists', return_value=True):
+      with self.assertCall(
+          self.call.adb.Pull('/data/app/test.file.exists',
+                             '/test/file/host/path')):
+        self.device.PullFile('/data/app/test.file.exists',
+                             '/test/file/host/path')
+
+  def testPullFile_doesntExistOnDevice(self):
+    with mock.patch('os.path.exists', return_value=True):
+      with self.assertCall(
+          self.call.adb.Pull('/data/app/test.file.does.not.exist',
+                             '/test/file/host/path'),
+          self.CommandError('remote object does not exist')):
+        with self.assertRaises(device_errors.CommandFailedError):
+          self.device.PullFile('/data/app/test.file.does.not.exist',
+                               '/test/file/host/path')
+
+
+class DeviceUtilsReadFileTest(DeviceUtilsTest):
+
+  def testReadFileWithPull_success(self):
+    tmp_host_dir = '/tmp/dir/on.host/'
+    tmp_host = MockTempFile('/tmp/dir/on.host/tmp_ReadFileWithPull')
+    tmp_host.file.read.return_value = 'some interesting contents'
+    with self.assertCalls(
+        (mock.call.tempfile.mkdtemp(), tmp_host_dir),
+        (self.call.adb.Pull('/path/to/device/file', mock.ANY)),
+        (mock.call.__builtin__.open(mock.ANY, 'r'), tmp_host),
+        (mock.call.os.path.exists(tmp_host_dir), True),
+        (mock.call.shutil.rmtree(tmp_host_dir), None)):
+      self.assertEquals('some interesting contents',
+                        self.device._ReadFileWithPull('/path/to/device/file'))
+    tmp_host.file.read.assert_called_once_with()
+
+  def testReadFileWithPull_rejected(self):
+    tmp_host_dir = '/tmp/dir/on.host/'
+    with self.assertCalls(
+        (mock.call.tempfile.mkdtemp(), tmp_host_dir),
+        (self.call.adb.Pull('/path/to/device/file', mock.ANY),
+         self.CommandError()),
+        (mock.call.os.path.exists(tmp_host_dir), True),
+        (mock.call.shutil.rmtree(tmp_host_dir), None)):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device._ReadFileWithPull('/path/to/device/file')
+
+  def testReadFile_exists(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['ls', '-l', '/read/this/test/file'],
+            as_root=False, check_return=True),
+         ['-rw-rw---- root foo 256 1970-01-01 00:00 file']),
+        (self.call.device.RunShellCommand(
+            ['cat', '/read/this/test/file'],
+            as_root=False, check_return=True),
+         ['this is a test file'])):
+      self.assertEqual('this is a test file\n',
+                       self.device.ReadFile('/read/this/test/file'))
+
+  def testReadFile_doesNotExist(self):
+    with self.assertCall(
+        self.call.device.RunShellCommand(
+            ['ls', '-l', '/this/file/does.not.exist'],
+            as_root=False, check_return=True),
+        self.CommandError('File does not exist')):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.ReadFile('/this/file/does.not.exist')
+
+  def testReadFile_zeroSize(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['ls', '-l', '/this/file/has/zero/size'],
+            as_root=False, check_return=True),
+         ['-r--r--r-- root foo 0 1970-01-01 00:00 zero_size_file']),
+        (self.call.device._ReadFileWithPull('/this/file/has/zero/size'),
+         'but it has contents\n')):
+      self.assertEqual('but it has contents\n',
+                       self.device.ReadFile('/this/file/has/zero/size'))
+
+  def testReadFile_withSU(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['ls', '-l', '/this/file/can.be.read.with.su'],
+            as_root=True, check_return=True),
+         ['-rw------- root root 256 1970-01-01 00:00 can.be.read.with.su']),
+        (self.call.device.RunShellCommand(
+            ['cat', '/this/file/can.be.read.with.su'],
+            as_root=True, check_return=True),
+         ['this is a test file', 'read with su'])):
+      self.assertEqual(
+          'this is a test file\nread with su\n',
+          self.device.ReadFile('/this/file/can.be.read.with.su',
+                               as_root=True))
+
+  def testReadFile_withPull(self):
+    contents = 'a' * 123456
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['ls', '-l', '/read/this/big/test/file'],
+            as_root=False, check_return=True),
+         ['-rw-rw---- root foo 123456 1970-01-01 00:00 file']),
+        (self.call.device._ReadFileWithPull('/read/this/big/test/file'),
+         contents)):
+      self.assertEqual(
+          contents, self.device.ReadFile('/read/this/big/test/file'))
+
+  def testReadFile_withPullAndSU(self):
+    contents = 'b' * 123456
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['ls', '-l', '/this/big/file/can.be.read.with.su'],
+            as_root=True, check_return=True),
+         ['-rw------- root root 123456 1970-01-01 00:00 can.be.read.with.su']),
+        (self.call.device.NeedsSU(), True),
+        (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
+         MockTempFile('/sdcard/tmp/on.device')),
+        self.call.device.RunShellCommand(
+            ['cp', '/this/big/file/can.be.read.with.su',
+             '/sdcard/tmp/on.device'],
+            as_root=True, check_return=True),
+        (self.call.device._ReadFileWithPull('/sdcard/tmp/on.device'),
+         contents)):
+      self.assertEqual(
+          contents,
+          self.device.ReadFile('/this/big/file/can.be.read.with.su',
+                               as_root=True))
+
+  def testReadFile_forcePull(self):
+    contents = 'a' * 123456
+    with self.assertCall(
+        self.call.device._ReadFileWithPull('/read/this/big/test/file'),
+        contents):
+      self.assertEqual(
+          contents,
+          self.device.ReadFile('/read/this/big/test/file', force_pull=True))
+
+
+class DeviceUtilsWriteFileTest(DeviceUtilsTest):
+
+  def testWriteFileWithPush_success(self):
+    tmp_host = MockTempFile('/tmp/file/on.host')
+    contents = 'some interesting contents'
+    with self.assertCalls(
+        (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
+        self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file')):
+      self.device._WriteFileWithPush('/path/to/device/file', contents)
+    tmp_host.file.write.assert_called_once_with(contents)
+
+  def testWriteFileWithPush_rejected(self):
+    tmp_host = MockTempFile('/tmp/file/on.host')
+    contents = 'some interesting contents'
+    with self.assertCalls(
+        (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
+        (self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file'),
+         self.CommandError())):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device._WriteFileWithPush('/path/to/device/file', contents)
+
+  def testWriteFile_withPush(self):
+    contents = 'some large contents ' * 26 # 20 * 26 = 520 chars
+    with self.assertCalls(
+        self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
+      self.device.WriteFile('/path/to/device/file', contents)
+
+  def testWriteFile_withPushForced(self):
+    contents = 'tiny contents'
+    with self.assertCalls(
+        self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
+      self.device.WriteFile('/path/to/device/file', contents, force_push=True)
+
+  def testWriteFile_withPushAndSU(self):
+    contents = 'some large contents ' * 26 # 20 * 26 = 520 chars
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (mock.call.pylib.utils.device_temp_file.DeviceTempFile(self.adb),
+         MockTempFile('/sdcard/tmp/on.device')),
+        self.call.device._WriteFileWithPush('/sdcard/tmp/on.device', contents),
+        self.call.device.RunShellCommand(
+            ['cp', '/sdcard/tmp/on.device', '/path/to/device/file'],
+            as_root=True, check_return=True)):
+      self.device.WriteFile('/path/to/device/file', contents, as_root=True)
+
+  def testWriteFile_withEcho(self):
+    with self.assertCall(self.call.adb.Shell(
+        "echo -n the.contents > /test/file/to.write"), ''):
+      self.device.WriteFile('/test/file/to.write', 'the.contents')
+
+  def testWriteFile_withEchoAndQuotes(self):
+    with self.assertCall(self.call.adb.Shell(
+        "echo -n 'the contents' > '/test/file/to write'"), ''):
+      self.device.WriteFile('/test/file/to write', 'the contents')
+
+  def testWriteFile_withEchoAndSU(self):
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (self.call.adb.Shell("su -c sh -c 'echo -n contents > /test/file'"),
+         '')):
+      self.device.WriteFile('/test/file', 'contents', as_root=True)
+
+
+class DeviceUtilsLsTest(DeviceUtilsTest):
+
+  def testLs_directory(self):
+    result = [('.', adb_wrapper.DeviceStat(16889, 4096, 1417436123)),
+              ('..', adb_wrapper.DeviceStat(16873, 4096, 12382237)),
+              ('testfile.txt', adb_wrapper.DeviceStat(33206, 3, 1417436122))]
+    with self.assertCalls(
+        (self.call.adb.Ls('/data/local/tmp'), result)):
+      self.assertEquals(result,
+                        self.device.Ls('/data/local/tmp'))
+
+  def testLs_nothing(self):
+    with self.assertCalls(
+        (self.call.adb.Ls('/data/local/tmp/testfile.txt'), [])):
+      self.assertEquals([],
+                        self.device.Ls('/data/local/tmp/testfile.txt'))
+
+
+class DeviceUtilsStatTest(DeviceUtilsTest):
+
+  def testStat_file(self):
+    result = [('.', adb_wrapper.DeviceStat(16889, 4096, 1417436123)),
+              ('..', adb_wrapper.DeviceStat(16873, 4096, 12382237)),
+              ('testfile.txt', adb_wrapper.DeviceStat(33206, 3, 1417436122))]
+    with self.assertCalls(
+        (self.call.adb.Ls('/data/local/tmp'), result)):
+      self.assertEquals(adb_wrapper.DeviceStat(33206, 3, 1417436122),
+                        self.device.Stat('/data/local/tmp/testfile.txt'))
+
+  def testStat_directory(self):
+    result = [('.', adb_wrapper.DeviceStat(16873, 4096, 12382237)),
+              ('..', adb_wrapper.DeviceStat(16873, 4096, 12382237)),
+              ('tmp', adb_wrapper.DeviceStat(16889, 4096, 1417436123))]
+    with self.assertCalls(
+        (self.call.adb.Ls('/data/local'), result)):
+      self.assertEquals(adb_wrapper.DeviceStat(16889, 4096, 1417436123),
+                        self.device.Stat('/data/local/tmp'))
+
+  def testStat_doesNotExist(self):
+    result = [('.', adb_wrapper.DeviceStat(16889, 4096, 1417436123)),
+              ('..', adb_wrapper.DeviceStat(16873, 4096, 12382237)),
+              ('testfile.txt', adb_wrapper.DeviceStat(33206, 3, 1417436122))]
+    with self.assertCalls(
+        (self.call.adb.Ls('/data/local/tmp'), result)):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.Stat('/data/local/tmp/does.not.exist.txt')
+
+
+class DeviceUtilsSetJavaAssertsTest(DeviceUtilsTest):
+
+  def testSetJavaAsserts_enable(self):
+    with self.assertCalls(
+        (self.call.device.ReadFile(constants.DEVICE_LOCAL_PROPERTIES_PATH),
+         'some.example.prop=with an example value\n'
+         'some.other.prop=value_ok\n'),
+        self.call.device.WriteFile(
+            constants.DEVICE_LOCAL_PROPERTIES_PATH,
+            'some.example.prop=with an example value\n'
+            'some.other.prop=value_ok\n'
+            'dalvik.vm.enableassertions=all\n'),
+        (self.call.device.GetProp('dalvik.vm.enableassertions'), ''),
+        self.call.device.SetProp('dalvik.vm.enableassertions', 'all')):
+      self.assertTrue(self.device.SetJavaAsserts(True))
+
+  def testSetJavaAsserts_disable(self):
+    with self.assertCalls(
+        (self.call.device.ReadFile(constants.DEVICE_LOCAL_PROPERTIES_PATH),
+         'some.example.prop=with an example value\n'
+         'dalvik.vm.enableassertions=all\n'
+         'some.other.prop=value_ok\n'),
+        self.call.device.WriteFile(
+            constants.DEVICE_LOCAL_PROPERTIES_PATH,
+            'some.example.prop=with an example value\n'
+            'some.other.prop=value_ok\n'),
+        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all'),
+        self.call.device.SetProp('dalvik.vm.enableassertions', '')):
+      self.assertTrue(self.device.SetJavaAsserts(False))
+
+  def testSetJavaAsserts_alreadyEnabled(self):
+    with self.assertCalls(
+        (self.call.device.ReadFile(constants.DEVICE_LOCAL_PROPERTIES_PATH),
+         'some.example.prop=with an example value\n'
+         'dalvik.vm.enableassertions=all\n'
+         'some.other.prop=value_ok\n'),
+        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
+      self.assertFalse(self.device.SetJavaAsserts(True))
+
+
+class DeviceUtilsGetPropTest(DeviceUtilsTest):
+
+  def testGetProp_exists(self):
+    with self.assertCall(
+        self.call.adb.Shell('getprop test.property'), 'property_value\n'):
+      self.assertEqual('property_value',
+                       self.device.GetProp('test.property'))
+
+  def testGetProp_doesNotExist(self):
+    with self.assertCall(
+        self.call.adb.Shell('getprop property.does.not.exist'), '\n'):
+      self.assertEqual('', self.device.GetProp('property.does.not.exist'))
+
+  def testGetProp_cachedRoProp(self):
+    with self.assertCall(
+        self.call.adb.Shell('getprop ro.build.type'), 'userdebug\n'):
+      self.assertEqual('userdebug',
+                       self.device.GetProp('ro.build.type', cache=True))
+      self.assertEqual('userdebug',
+                       self.device.GetProp('ro.build.type', cache=True))
+
+  def testGetProp_retryAndCache(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.type'), self.ShellError()),
+        (self.call.adb.Shell('getprop ro.build.type'), self.ShellError()),
+        (self.call.adb.Shell('getprop ro.build.type'), 'userdebug\n')):
+      self.assertEqual('userdebug',
+                       self.device.GetProp('ro.build.type',
+                                           cache=True, retries=3))
+      self.assertEqual('userdebug',
+                       self.device.GetProp('ro.build.type',
+                                           cache=True, retries=3))
+
+
+class DeviceUtilsSetPropTest(DeviceUtilsTest):
+
+  def testSetProp(self):
+    with self.assertCall(
+        self.call.adb.Shell("setprop test.property 'test value'"), ''):
+      self.device.SetProp('test.property', 'test value')
+
+  def testSetProp_check_succeeds(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('setprop test.property new_value'), ''),
+        (self.call.adb.Shell('getprop test.property'), 'new_value')):
+      self.device.SetProp('test.property', 'new_value', check=True)
+
+  def testSetProp_check_fails(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('setprop test.property new_value'), ''),
+        (self.call.adb.Shell('getprop test.property'), 'old_value')):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.SetProp('test.property', 'new_value', check=True)
+
+
+class DeviceUtilsGetPidsTest(DeviceUtilsTest):
+
+  def testGetPids_noMatches(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand('ps | grep -F does.not.match'),
+        []):
+      self.assertEqual({}, self.device.GetPids('does.not.match'))
+
+  def testGetPids_oneMatch(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
+        ['user  1001    100   1024 1024   ffffffff 00000000 one.match']):
+      self.assertEqual({'one.match': '1001'}, self.device.GetPids('one.match'))
+
+  def testGetPids_mutlipleMatches(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand('ps | grep -F match'),
+        ['user  1001    100   1024 1024   ffffffff 00000000 one.match',
+         'user  1002    100   1024 1024   ffffffff 00000000 two.match',
+         'user  1003    100   1024 1024   ffffffff 00000000 three.match']):
+      self.assertEqual(
+          {'one.match': '1001', 'two.match': '1002', 'three.match': '1003'},
+          self.device.GetPids('match'))
+
+  def testGetPids_exactMatch(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand('ps | grep -F exact.match'),
+        ['user  1000    100   1024 1024   ffffffff 00000000 not.exact.match',
+         'user  1234    100   1024 1024   ffffffff 00000000 exact.match']):
+      self.assertEqual(
+          {'not.exact.match': '1000', 'exact.match': '1234'},
+          self.device.GetPids('exact.match'))
+
+  def testGetPids_quotable(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand("ps | grep -F 'my$process'"),
+        ['user  1234    100   1024 1024   ffffffff 00000000 my$process']):
+      self.assertEqual(
+          {'my$process': '1234'}, self.device.GetPids('my$process'))
+
+
+class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest):
+
+  def testTakeScreenshot_fileNameProvided(self):
+    with self.assertCalls(
+        (mock.call.pylib.utils.device_temp_file.DeviceTempFile(
+            self.adb, suffix='.png'),
+         MockTempFile('/tmp/path/temp-123.png')),
+        (self.call.adb.Shell('/system/bin/screencap -p /tmp/path/temp-123.png'),
+         ''),
+        self.call.device.PullFile('/tmp/path/temp-123.png',
+                                  '/test/host/screenshot.png')):
+      self.device.TakeScreenshot('/test/host/screenshot.png')
+
+
+class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsTest):
+
+  def setUp(self):
+    super(DeviceUtilsGetMemoryUsageForPidTest, self).setUp()
+
+  def testGetMemoryUsageForPid_validPid(self):
+    with self.assertCalls(
+        (self.call.device._RunPipedShellCommand(
+            'showmap 1234 | grep TOTAL', as_root=True),
+         ['100 101 102 103 104 105 106 107 TOTAL']),
+        (self.call.device.ReadFile('/proc/1234/status', as_root=True),
+         'VmHWM: 1024 kB\n')):
+      self.assertEqual(
+          {
+            'Size': 100,
+            'Rss': 101,
+            'Pss': 102,
+            'Shared_Clean': 103,
+            'Shared_Dirty': 104,
+            'Private_Clean': 105,
+            'Private_Dirty': 106,
+            'VmHWM': 1024
+          },
+          self.device.GetMemoryUsageForPid(1234))
+
+  def testGetMemoryUsageForPid_noSmaps(self):
+    with self.assertCalls(
+        (self.call.device._RunPipedShellCommand(
+            'showmap 4321 | grep TOTAL', as_root=True),
+         ['cannot open /proc/4321/smaps: No such file or directory']),
+        (self.call.device.ReadFile('/proc/4321/status', as_root=True),
+         'VmHWM: 1024 kb\n')):
+      self.assertEquals({'VmHWM': 1024}, self.device.GetMemoryUsageForPid(4321))
+
+  def testGetMemoryUsageForPid_noStatus(self):
+    with self.assertCalls(
+        (self.call.device._RunPipedShellCommand(
+            'showmap 4321 | grep TOTAL', as_root=True),
+         ['100 101 102 103 104 105 106 107 TOTAL']),
+        (self.call.device.ReadFile('/proc/4321/status', as_root=True),
+         self.CommandError())):
+      self.assertEquals(
+          {
+            'Size': 100,
+            'Rss': 101,
+            'Pss': 102,
+            'Shared_Clean': 103,
+            'Shared_Dirty': 104,
+            'Private_Clean': 105,
+            'Private_Dirty': 106,
+          },
+          self.device.GetMemoryUsageForPid(4321))
+
+
+class DeviceUtilsClientCache(DeviceUtilsTest):
+
+  def testClientCache_twoCaches(self):
+    self.device._cache['test'] = 0
+    client_cache_one = self.device.GetClientCache('ClientOne')
+    client_cache_one['test'] = 1
+    client_cache_two = self.device.GetClientCache('ClientTwo')
+    client_cache_two['test'] = 2
+    self.assertEqual(self.device._cache, {'test': 0})
+    self.assertEqual(client_cache_one, {'test': 1})
+    self.assertEqual(client_cache_two, {'test': 2})
+    self.device._ClearCache()
+    self.assertEqual(self.device._cache, {})
+    self.assertEqual(client_cache_one, {})
+    self.assertEqual(client_cache_two, {})
+
+  def testClientCache_multipleInstances(self):
+    client_cache_one = self.device.GetClientCache('ClientOne')
+    client_cache_one['test'] = 1
+    client_cache_two = self.device.GetClientCache('ClientOne')
+    self.assertEqual(client_cache_one, {'test': 1})
+    self.assertEqual(client_cache_two, {'test': 1})
+    self.device._ClearCache()
+    self.assertEqual(client_cache_one, {})
+    self.assertEqual(client_cache_two, {})
+
+
+class DeviceUtilsParallelTest(mock_calls.TestCase):
+
+  def testParallel_default(self):
+    test_serials = ['0123456789abcdef', 'fedcba9876543210']
+    with self.assertCall(
+        mock.call.pylib.device.device_utils.DeviceUtils.HealthyDevices(),
+        [device_utils.DeviceUtils(s) for s in test_serials]):
+      parallel_devices = device_utils.DeviceUtils.parallel()
+    for serial, device in zip(test_serials, parallel_devices.pGet(None)):
+      self.assertTrue(isinstance(device, device_utils.DeviceUtils))
+      self.assertEquals(serial, device.adb.GetDeviceSerial())
+
+  def testParallel_noDevices(self):
+    with self.assertCall(
+        mock.call.pylib.device.device_utils.DeviceUtils.HealthyDevices(), []):
+      with self.assertRaises(device_errors.NoDevicesError):
+        device_utils.DeviceUtils.parallel()
+
+
+class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase):
+
+  def _createAdbWrapperMock(self, serial, is_ready=True):
+    adb = _AdbWrapperMock(serial)
+    adb.is_ready = is_ready
+    return adb
+
+  def testHealthyDevices_default(self):
+    test_serials = ['0123456789abcdef', 'fedcba9876543210']
+    with self.assertCalls(
+        (mock.call.pylib.device.device_blacklist.ReadBlacklist(), []),
+        (mock.call.pylib.device.adb_wrapper.AdbWrapper.Devices(),
+         [self._createAdbWrapperMock(s) for s in test_serials])):
+      devices = device_utils.DeviceUtils.HealthyDevices()
+    for serial, device in zip(test_serials, devices):
+      self.assertTrue(isinstance(device, device_utils.DeviceUtils))
+      self.assertEquals(serial, device.adb.GetDeviceSerial())
+
+  def testHealthyDevices_blacklisted(self):
+    test_serials = ['0123456789abcdef', 'fedcba9876543210']
+    with self.assertCalls(
+        (mock.call.pylib.device.device_blacklist.ReadBlacklist(),
+         ['fedcba9876543210']),
+        (mock.call.pylib.device.adb_wrapper.AdbWrapper.Devices(),
+         [self._createAdbWrapperMock(s) for s in test_serials])):
+      devices = device_utils.DeviceUtils.HealthyDevices()
+    self.assertEquals(1, len(devices))
+    self.assertTrue(isinstance(devices[0], device_utils.DeviceUtils))
+    self.assertEquals('0123456789abcdef', devices[0].adb.GetDeviceSerial())
+
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/device/intent.py b/build/android/pylib/device/intent.py
new file mode 100644
index 0000000..333b9f1
--- /dev/null
+++ b/build/android/pylib/device/intent.py
@@ -0,0 +1,113 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Manages intents and associated information.
+
+This is generally intended to be used with functions that calls Android's
+Am command.
+"""
+
+class Intent(object):
+
+  def __init__(self, action='android.intent.action.VIEW', activity=None,
+               category=None, component=None, data=None, extras=None,
+               flags=None, package=None):
+    """Creates an Intent.
+
+    Args:
+      action: A string containing the action.
+      activity: A string that, with |package|, can be used to specify the
+                component.
+      category: A string or list containing any categories.
+      component: A string that specifies the component to send the intent to.
+      data: A string containing a data URI.
+      extras: A dict containing extra parameters to be passed along with the
+              intent.
+      flags: A string containing flags to pass.
+      package: A string that, with activity, can be used to specify the
+               component.
+    """
+    self._action = action
+    self._activity = activity
+    if isinstance(category, list) or category is None:
+      self._category = category
+    else:
+      self._category = [category]
+    self._component = component
+    self._data = data
+    self._extras = extras
+    self._flags = flags
+    self._package = package
+
+    if self._component and '/' in component:
+      self._package, self._activity = component.split('/', 1)
+    elif self._package and self._activity:
+      self._component = '%s/%s' % (package, activity)
+
+  @property
+  def action(self):
+    return self._action
+
+  @property
+  def activity(self):
+    return self._activity
+
+  @property
+  def category(self):
+    return self._category
+
+  @property
+  def component(self):
+    return self._component
+
+  @property
+  def data(self):
+    return self._data
+
+  @property
+  def extras(self):
+    return self._extras
+
+  @property
+  def flags(self):
+    return self._flags
+
+  @property
+  def package(self):
+    return self._package
+
+  @property
+  def am_args(self):
+    """Returns the intent as a list of arguments for the activity manager.
+
+    For details refer to the specification at:
+    - http://developer.android.com/tools/help/adb.html#IntentSpec
+    """
+    args = []
+    if self.action:
+      args.extend(['-a', self.action])
+    if self.data:
+      args.extend(['-d', self.data])
+    if self.category:
+      args.extend(arg for cat in self.category for arg in ('-c', cat))
+    if self.component:
+      args.extend(['-n', self.component])
+    if self.flags:
+      args.extend(['-f', self.flags])
+    if self.extras:
+      for key, value in self.extras.iteritems():
+        if value is None:
+          args.extend(['--esn', key])
+        elif isinstance(value, str):
+          args.extend(['--es', key, value])
+        elif isinstance(value, bool):
+          args.extend(['--ez', key, str(value)])
+        elif isinstance(value, int):
+          args.extend(['--ei', key, str(value)])
+        elif isinstance(value, float):
+          args.extend(['--ef', key, str(value)])
+        else:
+          raise NotImplementedError(
+              'Intent does not know how to pass %s extras' % type(value))
+    return args
diff --git a/build/android/pylib/device/logcat_monitor.py b/build/android/pylib/device/logcat_monitor.py
new file mode 100644
index 0000000..2eebc2d
--- /dev/null
+++ b/build/android/pylib/device/logcat_monitor.py
@@ -0,0 +1,139 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=unused-argument
+
+import collections
+import itertools
+import logging
+import subprocess
+import tempfile
+import time
+import re
+
+from pylib.device import adb_wrapper
+from pylib.device import decorators
+from pylib.device import device_errors
+
+
+class LogcatMonitor(object):
+
+  _THREADTIME_RE_FORMAT = (
+      r'(?P<date>\S*) +(?P<time>\S*) +(?P<proc_id>%s) +(?P<thread_id>%s) +'
+      r'(?P<log_level>%s) +(?P<component>%s) *: +(?P<message>%s)$')
+
+  def __init__(self, adb, clear=True, filter_specs=None):
+    """Create a LogcatMonitor instance.
+
+    Args:
+      adb: An instance of adb_wrapper.AdbWrapper.
+      clear: If True, clear the logcat when monitoring starts.
+      filter_specs: An optional list of '<tag>[:priority]' strings.
+    """
+    if isinstance(adb, adb_wrapper.AdbWrapper):
+      self._adb = adb
+    else:
+      raise ValueError('Unsupported type passed for argument "device"')
+    self._clear = clear
+    self._filter_specs = filter_specs
+    self._logcat_out = None
+    self._logcat_out_file = None
+    self._logcat_proc = None
+
+  @decorators.WithTimeoutAndRetriesDefaults(10, 0)
+  def WaitFor(self, success_regex, failure_regex=None, timeout=None,
+              retries=None):
+    """Wait for a matching logcat line or until a timeout occurs.
+
+    This will attempt to match lines in the logcat against both |success_regex|
+    and |failure_regex| (if provided). Note that this calls re.search on each
+    logcat line, not re.match, so the provided regular expressions don't have
+    to match an entire line.
+
+    Args:
+      success_regex: The regular expression to search for.
+      failure_regex: An optional regular expression that, if hit, causes this
+        to stop looking for a match. Can be None.
+      timeout: timeout in seconds
+      retries: number of retries
+
+    Returns:
+      A match object if |success_regex| matches a part of a logcat line, or
+      None if |failure_regex| matches a part of a logcat line.
+    Raises:
+      CommandFailedError on logcat failure (NOT on a |failure_regex| match).
+      CommandTimeoutError if no logcat line matching either |success_regex| or
+        |failure_regex| is found in |timeout| seconds.
+      DeviceUnreachableError if the device becomes unreachable.
+    """
+    if isinstance(success_regex, basestring):
+      success_regex = re.compile(success_regex)
+    if isinstance(failure_regex, basestring):
+      failure_regex = re.compile(failure_regex)
+
+    logging.debug('Waiting %d seconds for "%s"', timeout, success_regex.pattern)
+
+    # NOTE This will continue looping until:
+    #  - success_regex matches a line, in which case the match object is
+    #    returned.
+    #  - failure_regex matches a line, in which case None is returned
+    #  - the timeout is hit, in which case a CommandTimeoutError is raised.
+    for l in self._adb.Logcat(filter_specs=self._filter_specs):
+      m = success_regex.search(l)
+      if m:
+        return m
+      if failure_regex and failure_regex.search(l):
+        return None
+
+  def FindAll(self, message_regex, proc_id=None, thread_id=None, log_level=None,
+              component=None):
+    """Finds all lines in the logcat that match the provided constraints.
+
+    Args:
+      message_regex: The regular expression that the <message> section must
+        match.
+      proc_id: The process ID to match. If None, matches any process ID.
+      thread_id: The thread ID to match. If None, matches any thread ID.
+      log_level: The log level to match. If None, matches any log level.
+      component: The component to match. If None, matches any component.
+
+    Yields:
+      A match object for each matching line in the logcat. The match object
+      will always contain, in addition to groups defined in |message_regex|,
+      the following named groups: 'date', 'time', 'proc_id', 'thread_id',
+      'log_level', 'component', and 'message'.
+    """
+    if proc_id is None:
+      proc_id = r'\d+'
+    if thread_id is None:
+      thread_id = r'\d+'
+    if log_level is None:
+      log_level = r'[VDIWEF]'
+    if component is None:
+      component = r'[^\s:]+'
+    threadtime_re = re.compile(
+        type(self)._THREADTIME_RE_FORMAT % (
+            proc_id, thread_id, log_level, component, message_regex))
+
+    for line in self._adb.Logcat(dump=True, logcat_format='threadtime'):
+      m = re.match(threadtime_re, line)
+      if m:
+        yield m
+
+  def Start(self):
+    """Starts the logcat monitor.
+
+    Clears the logcat if |clear| was set in |__init__|.
+    """
+    if self._clear:
+      self._adb.Logcat(clear=True)
+
+  def __enter__(self):
+    """Starts the logcat monitor."""
+    self.Start()
+    return self
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """Stops the logcat monitor."""
+    pass
diff --git a/build/android/pylib/device/logcat_monitor_test.py b/build/android/pylib/device/logcat_monitor_test.py
new file mode 100755
index 0000000..db397e5
--- /dev/null
+++ b/build/android/pylib/device/logcat_monitor_test.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import itertools
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import adb_wrapper
+from pylib.device import decorators
+from pylib.device import logcat_monitor
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class LogcatMonitorTest(unittest.TestCase):
+
+  _TEST_THREADTIME_LOGCAT_DATA = [
+        '01-01 01:02:03.456  7890  0987 V LogcatMonitorTest: '
+            'verbose logcat monitor test message 1',
+        '01-01 01:02:03.457  8901  1098 D LogcatMonitorTest: '
+            'debug logcat monitor test message 2',
+        '01-01 01:02:03.458  9012  2109 I LogcatMonitorTest: '
+            'info logcat monitor test message 3',
+        '01-01 01:02:03.459  0123  3210 W LogcatMonitorTest: '
+            'warning logcat monitor test message 4',
+        '01-01 01:02:03.460  1234  4321 E LogcatMonitorTest: '
+            'error logcat monitor test message 5',
+        '01-01 01:02:03.461  2345  5432 F LogcatMonitorTest: '
+            'fatal logcat monitor test message 6',
+        '01-01 01:02:03.462  3456  6543 D LogcatMonitorTest: '
+            'ignore me',]
+
+  def _createTestLog(self, raw_logcat=None):
+    test_adb = adb_wrapper.AdbWrapper('0123456789abcdef')
+    test_adb.Logcat = mock.Mock(return_value=(l for l in raw_logcat))
+    test_log = logcat_monitor.LogcatMonitor(test_adb, clear=False)
+    return test_log
+
+  def assertIterEqual(self, expected_iter, actual_iter):
+    for expected, actual in itertools.izip_longest(expected_iter, actual_iter):
+      self.assertIsNotNone(
+          expected,
+          msg='actual has unexpected elements starting with %s' % str(actual))
+      self.assertIsNotNone(
+          actual,
+          msg='actual is missing elements starting with %s' % str(expected))
+      self.assertEqual(actual.group('proc_id'), expected[0])
+      self.assertEqual(actual.group('thread_id'), expected[1])
+      self.assertEqual(actual.group('log_level'), expected[2])
+      self.assertEqual(actual.group('component'), expected[3])
+      self.assertEqual(actual.group('message'), expected[4])
+
+    with self.assertRaises(StopIteration):
+      next(actual_iter)
+    with self.assertRaises(StopIteration):
+      next(expected_iter)
+
+  def testWaitFor_success(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_match = test_log.WaitFor(r'.*(fatal|error) logcat monitor.*', None)
+    self.assertTrue(actual_match)
+    self.assertEqual(
+        '01-01 01:02:03.460  1234  4321 E LogcatMonitorTest: '
+            'error logcat monitor test message 5',
+        actual_match.group(0))
+    self.assertEqual('error', actual_match.group(1))
+
+  def testWaitFor_failure(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_match = test_log.WaitFor(
+        r'.*My Success Regex.*', r'.*(fatal|error) logcat monitor.*')
+    self.assertIsNone(actual_match)
+
+  def testFindAll_defaults(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    expected_results = [
+        ('7890', '0987', 'V', 'LogcatMonitorTest',
+         'verbose logcat monitor test message 1'),
+        ('8901', '1098', 'D', 'LogcatMonitorTest',
+         'debug logcat monitor test message 2'),
+        ('9012', '2109', 'I', 'LogcatMonitorTest',
+         'info logcat monitor test message 3'),
+        ('0123', '3210', 'W', 'LogcatMonitorTest',
+         'warning logcat monitor test message 4'),
+        ('1234', '4321', 'E', 'LogcatMonitorTest',
+         'error logcat monitor test message 5'),
+        ('2345', '5432', 'F', 'LogcatMonitorTest',
+         'fatal logcat monitor test message 6')]
+    actual_results = test_log.FindAll(r'\S* logcat monitor test message \d')
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_defaults_miss(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    expected_results = []
+    actual_results = test_log.FindAll(r'\S* nothing should match this \d')
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterProcId(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(
+        r'\S* logcat monitor test message \d', proc_id=1234)
+    expected_results = [
+        ('1234', '4321', 'E', 'LogcatMonitorTest',
+         'error logcat monitor test message 5')]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterThreadId(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(
+        r'\S* logcat monitor test message \d', thread_id=2109)
+    expected_results = [
+        ('9012', '2109', 'I', 'LogcatMonitorTest',
+         'info logcat monitor test message 3')]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterLogLevel(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(
+        r'\S* logcat monitor test message \d', log_level=r'[DW]')
+    expected_results = [
+        ('8901', '1098', 'D', 'LogcatMonitorTest',
+         'debug logcat monitor test message 2'),
+        ('0123', '3210', 'W', 'LogcatMonitorTest',
+         'warning logcat monitor test message 4'),]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterComponent(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(r'.*', component='LogcatMonitorTest')
+    expected_results = [
+        ('7890', '0987', 'V', 'LogcatMonitorTest',
+         'verbose logcat monitor test message 1'),
+        ('8901', '1098', 'D', 'LogcatMonitorTest',
+         'debug logcat monitor test message 2'),
+        ('9012', '2109', 'I', 'LogcatMonitorTest',
+         'info logcat monitor test message 3'),
+        ('0123', '3210', 'W', 'LogcatMonitorTest',
+         'warning logcat monitor test message 4'),
+        ('1234', '4321', 'E', 'LogcatMonitorTest',
+         'error logcat monitor test message 5'),
+        ('2345', '5432', 'F', 'LogcatMonitorTest',
+         'fatal logcat monitor test message 6'),
+        ('3456', '6543', 'D', 'LogcatMonitorTest',
+         'ignore me'),]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/device/shared_prefs.py b/build/android/pylib/device/shared_prefs.py
new file mode 100644
index 0000000..32cef4b
--- /dev/null
+++ b/build/android/pylib/device/shared_prefs.py
@@ -0,0 +1,391 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper object to read and modify Shared Preferences from Android apps.
+
+See e.g.:
+  http://developer.android.com/reference/android/content/SharedPreferences.html
+"""
+
+import collections
+import logging
+import posixpath
+
+from xml.etree import ElementTree
+
+
+_XML_DECLARATION = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+
+
+class BasePref(object):
+  """Base class for getting/setting the value of a specific preference type.
+
+  Should not be instantiated directly. The SharedPrefs collection will
+  instantiate the appropriate subclasses, which directly manipulate the
+  underlying xml document, to parse and serialize values according to their
+  type.
+
+  Args:
+    elem: An xml ElementTree object holding the preference data.
+
+  Properties:
+    tag_name: A string with the tag that must be used for this preference type.
+  """
+  tag_name = None
+
+  def __init__(self, elem):
+    if elem.tag != type(self).tag_name:
+      raise TypeError('Property %r has type %r, but trying to access as %r' %
+                      (elem.get('name'), elem.tag, type(self).tag_name))
+    self._elem = elem
+
+  def __str__(self):
+    """Get the underlying xml element as a string."""
+    return ElementTree.tostring(self._elem)
+
+  def get(self):
+    """Get the value of this preference."""
+    return self._elem.get('value')
+
+  def set(self, value):
+    """Set from a value casted as a string."""
+    self._elem.set('value', str(value))
+
+  @property
+  def has_value(self):
+    """Check whether the element has a value."""
+    return self._elem.get('value') is not None
+
+
+class BooleanPref(BasePref):
+  """Class for getting/setting a preference with a boolean value.
+
+  The underlying xml element has the form, e.g.:
+      <boolean name="featureEnabled" value="false" />
+  """
+  tag_name = 'boolean'
+  VALUES = {'true': True, 'false': False}
+
+  def get(self):
+    """Get the value as a Python bool."""
+    return type(self).VALUES[super(BooleanPref, self).get()]
+
+  def set(self, value):
+    """Set from a value casted as a bool."""
+    super(BooleanPref, self).set('true' if value else 'false')
+
+
+class FloatPref(BasePref):
+  """Class for getting/setting a preference with a float value.
+
+  The underlying xml element has the form, e.g.:
+      <float name="someMetric" value="4.7" />
+  """
+  tag_name = 'float'
+
+  def get(self):
+    """Get the value as a Python float."""
+    return float(super(FloatPref, self).get())
+
+
+class IntPref(BasePref):
+  """Class for getting/setting a preference with an int value.
+
+  The underlying xml element has the form, e.g.:
+      <int name="aCounter" value="1234" />
+  """
+  tag_name = 'int'
+
+  def get(self):
+    """Get the value as a Python int."""
+    return int(super(IntPref, self).get())
+
+
+class LongPref(IntPref):
+  """Class for getting/setting a preference with a long value.
+
+  The underlying xml element has the form, e.g.:
+      <long name="aLongCounter" value="1234" />
+
+  We use the same implementation from IntPref.
+  """
+  tag_name = 'long'
+
+
+class StringPref(BasePref):
+  """Class for getting/setting a preference with a string value.
+
+  The underlying xml element has the form, e.g.:
+      <string name="someHashValue">249b3e5af13d4db2</string>
+  """
+  tag_name = 'string'
+
+  def get(self):
+    """Get the value as a Python string."""
+    return self._elem.text
+
+  def set(self, value):
+    """Set from a value casted as a string."""
+    self._elem.text = str(value)
+
+
+class StringSetPref(StringPref):
+  """Class for getting/setting a preference with a set of string values.
+
+  The underlying xml element has the form, e.g.:
+      <set name="managed_apps">
+          <string>com.mine.app1</string>
+          <string>com.mine.app2</string>
+          <string>com.mine.app3</string>
+      </set>
+  """
+  tag_name = 'set'
+
+  def get(self):
+    """Get a list with the string values contained."""
+    value = []
+    for child in self._elem:
+      assert child.tag == 'string'
+      value.append(child.text)
+    return value
+
+  def set(self, value):
+    """Set from a sequence of values, each casted as a string."""
+    for child in list(self._elem):
+      self._elem.remove(child)
+    for item in value:
+      ElementTree.SubElement(self._elem, 'string').text = str(item)
+
+
+_PREF_TYPES = {c.tag_name: c for c in [BooleanPref, FloatPref, IntPref,
+                                       LongPref, StringPref, StringSetPref]}
+
+
+class SharedPrefs(object):
+  def __init__(self, device, package, filename):
+    """Helper object to read and update "Shared Prefs" of Android apps.
+
+    Such files typically look like, e.g.:
+
+        <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+        <map>
+          <int name="databaseVersion" value="107" />
+          <boolean name="featureEnabled" value="false" />
+          <string name="someHashValue">249b3e5af13d4db2</string>
+        </map>
+
+    Example usage:
+
+        prefs = shared_prefs.SharedPrefs(device, 'com.my.app', 'my_prefs.xml')
+        prefs.Load()
+        prefs.GetString('someHashValue') # => '249b3e5af13d4db2'
+        prefs.SetInt('databaseVersion', 42)
+        prefs.Remove('featureEnabled')
+        prefs.Commit()
+
+    The object may also be used as a context manager to automatically load and
+    commit, respectively, upon entering and leaving the context.
+
+    Args:
+      device: A DeviceUtils object.
+      package: A string with the package name of the app that owns the shared
+        preferences file.
+      filename: A string with the name of the preferences file to read/write.
+    """
+    self._device = device
+    self._xml = None
+    self._package = package
+    self._filename = filename
+    self._path = '/data/data/%s/shared_prefs/%s' % (package, filename)
+    self._changed = False
+
+  def __repr__(self):
+    """Get a useful printable representation of the object."""
+    return '<{cls} file {filename} for {package} on {device}>'.format(
+      cls=type(self).__name__, filename=self.filename, package=self.package,
+      device=str(self._device))
+
+  def __str__(self):
+    """Get the underlying xml document as a string."""
+    return _XML_DECLARATION + ElementTree.tostring(self.xml)
+
+  @property
+  def package(self):
+    """Get the package name of the app that owns the shared preferences."""
+    return self._package
+
+  @property
+  def filename(self):
+    """Get the filename of the shared preferences file."""
+    return self._filename
+
+  @property
+  def path(self):
+    """Get the full path to the shared preferences file on the device."""
+    return self._path
+
+  @property
+  def changed(self):
+    """True if properties have changed and a commit would be needed."""
+    return self._changed
+
+  @property
+  def xml(self):
+    """Get the underlying xml document as an ElementTree object."""
+    if self._xml is None:
+      self._xml = ElementTree.Element('map')
+    return self._xml
+
+  def Load(self):
+    """Load the shared preferences file from the device.
+
+    A empty xml document, which may be modified and saved on |commit|, is
+    created if the file does not already exist.
+    """
+    if self._device.FileExists(self.path):
+      self._xml = ElementTree.fromstring(
+          self._device.ReadFile(self.path, as_root=True))
+      assert self._xml.tag == 'map'
+    else:
+      self._xml = None
+    self._changed = False
+
+  def Clear(self):
+    """Clear all of the preferences contained in this object."""
+    if self._xml is not None and len(self): # only clear if not already empty
+      self._xml = None
+      self._changed = True
+
+  def Commit(self):
+    """Save the current set of preferences to the device.
+
+    Only actually saves if some preferences have been modified.
+    """
+    if not self.changed:
+      return
+    self._device.RunShellCommand(
+        ['mkdir', '-p', posixpath.dirname(self.path)],
+        as_root=True, check_return=True)
+    self._device.WriteFile(self.path, str(self), as_root=True)
+    self._device.KillAll(self.package, as_root=True, quiet=True)
+    self._changed = False
+
+  def __len__(self):
+    """Get the number of preferences in this collection."""
+    return len(self.xml)
+
+  def PropertyType(self, key):
+    """Get the type (i.e. tag name) of a property in the collection."""
+    return self._GetChild(key).tag
+
+  def HasProperty(self, key):
+    try:
+      self._GetChild(key)
+      return True
+    except KeyError:
+      return False
+
+  def GetBoolean(self, key):
+    """Get a boolean property."""
+    return BooleanPref(self._GetChild(key)).get()
+
+  def SetBoolean(self, key, value):
+    """Set a boolean property."""
+    self._SetPrefValue(key, value, BooleanPref)
+
+  def GetFloat(self, key):
+    """Get a float property."""
+    return FloatPref(self._GetChild(key)).get()
+
+  def SetFloat(self, key, value):
+    """Set a float property."""
+    self._SetPrefValue(key, value, FloatPref)
+
+  def GetInt(self, key):
+    """Get an int property."""
+    return IntPref(self._GetChild(key)).get()
+
+  def SetInt(self, key, value):
+    """Set an int property."""
+    self._SetPrefValue(key, value, IntPref)
+
+  def GetLong(self, key):
+    """Get a long property."""
+    return LongPref(self._GetChild(key)).get()
+
+  def SetLong(self, key, value):
+    """Set a long property."""
+    self._SetPrefValue(key, value, LongPref)
+
+  def GetString(self, key):
+    """Get a string property."""
+    return StringPref(self._GetChild(key)).get()
+
+  def SetString(self, key, value):
+    """Set a string property."""
+    self._SetPrefValue(key, value, StringPref)
+
+  def GetStringSet(self, key):
+    """Get a string set property."""
+    return StringSetPref(self._GetChild(key)).get()
+
+  def SetStringSet(self, key, value):
+    """Set a string set property."""
+    self._SetPrefValue(key, value, StringSetPref)
+
+  def Remove(self, key):
+    """Remove a preference from the collection."""
+    self.xml.remove(self._GetChild(key))
+
+  def AsDict(self):
+    """Return the properties and their values as a dictionary."""
+    d = {}
+    for child in self.xml:
+      pref = _PREF_TYPES[child.tag](child)
+      d[child.get('name')] = pref.get()
+    return d
+
+  def __enter__(self):
+    """Load preferences file from the device when entering a context."""
+    self.Load()
+    return self
+
+  def __exit__(self, exc_type, _exc_value, _traceback):
+    """Save preferences file to the device when leaving a context."""
+    if not exc_type:
+      self.Commit()
+
+  def _GetChild(self, key):
+    """Get the underlying xml node that holds the property of a given key.
+
+    Raises:
+      KeyError when the key is not found in the collection.
+    """
+    for child in self.xml:
+      if child.get('name') == key:
+        return child
+    raise KeyError(key)
+
+  def _SetPrefValue(self, key, value, pref_cls):
+    """Set the value of a property.
+
+    Args:
+      key: The key of the property to set.
+      value: The new value of the property.
+      pref_cls: A subclass of BasePref used to access the property.
+
+    Raises:
+      TypeError when the key already exists but with a different type.
+    """
+    try:
+      pref = pref_cls(self._GetChild(key))
+      old_value = pref.get()
+    except KeyError:
+      pref = pref_cls(ElementTree.SubElement(
+          self.xml, pref_cls.tag_name, {'name': key}))
+      old_value = None
+    if old_value != value:
+      pref.set(value)
+      self._changed = True
+      logging.info('Setting property: %s', pref)
diff --git a/build/android/pylib/device/shared_prefs_test.py b/build/android/pylib/device/shared_prefs_test.py
new file mode 100755
index 0000000..c5f0ec3
--- /dev/null
+++ b/build/android/pylib/device/shared_prefs_test.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for the contents of shared_prefs.py (mostly SharedPrefs).
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import device_utils
+from pylib.device import shared_prefs
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
+
+def MockDeviceWithFiles(files=None):
+  if files is None:
+    files = {}
+
+  def file_exists(path):
+    return path in files
+
+  def write_file(path, contents, **_kwargs):
+    files[path] = contents
+
+  def read_file(path, **_kwargs):
+    return files[path]
+
+  device = mock.MagicMock(spec=device_utils.DeviceUtils)
+  device.FileExists = mock.Mock(side_effect=file_exists)
+  device.WriteFile = mock.Mock(side_effect=write_file)
+  device.ReadFile = mock.Mock(side_effect=read_file)
+  return device
+
+
+class SharedPrefsTest(unittest.TestCase):
+
+  def setUp(self):
+    self.device = MockDeviceWithFiles({
+      '/data/data/com.some.package/shared_prefs/prefs.xml':
+          "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+          '<map>\n'
+          '  <int name="databaseVersion" value="107" />\n'
+          '  <boolean name="featureEnabled" value="false" />\n'
+          '  <string name="someHashValue">249b3e5af13d4db2</string>\n'
+          '</map>'})
+    self.expected_data = {'databaseVersion': 107,
+                          'featureEnabled': False,
+                          'someHashValue': '249b3e5af13d4db2'}
+
+  def testPropertyLifetime(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    self.assertEquals(len(prefs), 0) # collection is empty before loading
+    prefs.SetInt('myValue', 444)
+    self.assertEquals(len(prefs), 1)
+    self.assertEquals(prefs.GetInt('myValue'), 444)
+    self.assertTrue(prefs.HasProperty('myValue'))
+    prefs.Remove('myValue')
+    self.assertEquals(len(prefs), 0)
+    self.assertFalse(prefs.HasProperty('myValue'))
+    with self.assertRaises(KeyError):
+      prefs.GetInt('myValue')
+
+  def testPropertyType(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    prefs.SetInt('myValue', 444)
+    self.assertEquals(prefs.PropertyType('myValue'), 'int')
+    with self.assertRaises(TypeError):
+      prefs.GetString('myValue')
+    with self.assertRaises(TypeError):
+      prefs.SetString('myValue', 'hello')
+
+  def testLoad(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    self.assertEquals(len(prefs), 0) # collection is empty before loading
+    prefs.Load()
+    self.assertEquals(len(prefs), len(self.expected_data))
+    self.assertEquals(prefs.AsDict(), self.expected_data)
+    self.assertFalse(prefs.changed)
+
+  def testClear(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml')
+    prefs.Load()
+    self.assertEquals(prefs.AsDict(), self.expected_data)
+    self.assertFalse(prefs.changed)
+    prefs.Clear()
+    self.assertEquals(len(prefs), 0) # collection is empty now
+    self.assertTrue(prefs.changed)
+
+  def testCommit(self):
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'other_prefs.xml')
+    self.assertFalse(self.device.FileExists(prefs.path)) # file does not exist
+    prefs.Load()
+    self.assertEquals(len(prefs), 0) # file did not exist, collection is empty
+    prefs.SetInt('magicNumber', 42)
+    prefs.SetFloat('myMetric', 3.14)
+    prefs.SetLong('bigNumner', 6000000000)
+    prefs.SetStringSet('apps', ['gmail', 'chrome', 'music'])
+    self.assertFalse(self.device.FileExists(prefs.path)) # still does not exist
+    self.assertTrue(prefs.changed)
+    prefs.Commit()
+    self.assertTrue(self.device.FileExists(prefs.path)) # should exist now
+    self.device.KillAll.assert_called_once_with(prefs.package, as_root=True,
+                                                quiet=True)
+    self.assertFalse(prefs.changed)
+
+    prefs = shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'other_prefs.xml')
+    self.assertEquals(len(prefs), 0) # collection is empty before loading
+    prefs.Load()
+    self.assertEquals(prefs.AsDict(), {
+        'magicNumber': 42,
+        'myMetric': 3.14,
+        'bigNumner': 6000000000,
+        'apps': ['gmail', 'chrome', 'music']}) # data survived roundtrip
+
+  def testAsContextManager_onlyReads(self):
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      self.assertEquals(prefs.AsDict(), self.expected_data) # loaded and ready
+    self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
+
+  def testAsContextManager_readAndWrite(self):
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      prefs.SetBoolean('featureEnabled', True)
+      prefs.Remove('someHashValue')
+      prefs.SetString('newString', 'hello')
+
+    self.assertTrue(self.device.WriteFile.called) # did write
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      # changes persisted
+      self.assertTrue(prefs.GetBoolean('featureEnabled'))
+      self.assertFalse(prefs.HasProperty('someHashValue'))
+      self.assertEquals(prefs.GetString('newString'), 'hello')
+      self.assertTrue(prefs.HasProperty('databaseVersion')) # still there
+
+  def testAsContextManager_commitAborted(self):
+    with self.assertRaises(TypeError):
+      with shared_prefs.SharedPrefs(
+          self.device, 'com.some.package', 'prefs.xml') as prefs:
+        prefs.SetBoolean('featureEnabled', True)
+        prefs.Remove('someHashValue')
+        prefs.SetString('newString', 'hello')
+        prefs.SetInt('newString', 123) # oops!
+
+    self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
+    with shared_prefs.SharedPrefs(
+        self.device, 'com.some.package', 'prefs.xml') as prefs:
+      # contents were not modified
+      self.assertEquals(prefs.AsDict(), self.expected_data)
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/pylib/device_settings.py b/build/android/pylib/device_settings.py
new file mode 100644
index 0000000..73ffa72
--- /dev/null
+++ b/build/android/pylib/device_settings.py
@@ -0,0 +1,196 @@
+# Copyright 2014 The Chromium 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 logging
+
+from pylib import constants
+from pylib import content_settings
+from pylib.device import device_errors
+
+_LOCK_SCREEN_SETTINGS_PATH = '/data/system/locksettings.db'
+_ALTERNATE_LOCK_SCREEN_SETTINGS_PATH = (
+    '/data/data/com.android.providers.settings/databases/settings.db')
+PASSWORD_QUALITY_UNSPECIFIED = '0'
+
+
+def ConfigureContentSettings(device, desired_settings):
+  """Configures device content setings from a list.
+
+  Many settings are documented at:
+    http://developer.android.com/reference/android/provider/Settings.Global.html
+    http://developer.android.com/reference/android/provider/Settings.Secure.html
+    http://developer.android.com/reference/android/provider/Settings.System.html
+
+  Many others are undocumented.
+
+  Args:
+    device: A DeviceUtils instance for the device to configure.
+    desired_settings: A list of (table, [(key: value), ...]) for all
+        settings to configure.
+  """
+  try:
+    sdk_version = device.build_version_sdk
+  except device_errors.CommandFailedError as exc:
+    logging.error('Skipping content settings configuration: %s', str(exc))
+    return
+
+  if sdk_version < constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN:
+    logging.error('Skipping content settings configuration due to outdated sdk')
+    return
+
+  if device.build_type == 'userdebug':
+    for table, key_value in desired_settings:
+      settings = content_settings.ContentSettings(table, device)
+      for key, value in key_value:
+        settings[key] = value
+      logging.info('\n%s %s', table, (80 - len(table)) * '-')
+      for key, value in sorted(settings.iteritems()):
+        logging.info('\t%s: %s', key, value)
+
+
+def SetLockScreenSettings(device):
+  """Sets lock screen settings on the device.
+
+  On certain device/Android configurations we need to disable the lock screen in
+  a different database. Additionally, the password type must be set to
+  DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED.
+  Lock screen settings are stored in sqlite on the device in:
+      /data/system/locksettings.db
+
+  IMPORTANT: The first column is used as a primary key so that all rows with the
+  same value for that column are removed from the table prior to inserting the
+  new values.
+
+  Args:
+    device: A DeviceUtils instance for the device to configure.
+
+  Raises:
+    Exception if the setting was not properly set.
+  """
+  if device.build_type != 'userdebug':
+    logging.warning('Unable to disable lockscreen on user builds.')
+    return
+
+  def get_lock_settings(table):
+    return [(table, 'lockscreen.disabled', '1'),
+            (table, 'lockscreen.password_type', PASSWORD_QUALITY_UNSPECIFIED),
+            (table, 'lockscreen.password_type_alternate',
+             PASSWORD_QUALITY_UNSPECIFIED)]
+
+  if device.FileExists(_LOCK_SCREEN_SETTINGS_PATH):
+    db = _LOCK_SCREEN_SETTINGS_PATH
+    locksettings = get_lock_settings('locksettings')
+    columns = ['name', 'user', 'value']
+    generate_values = lambda k, v: [k, '0', v]
+  elif device.FileExists(_ALTERNATE_LOCK_SCREEN_SETTINGS_PATH):
+    db = _ALTERNATE_LOCK_SCREEN_SETTINGS_PATH
+    locksettings = get_lock_settings('secure') + get_lock_settings('system')
+    columns = ['name', 'value']
+    generate_values = lambda k, v: [k, v]
+  else:
+    logging.warning('Unable to find database file to set lock screen settings.')
+    return
+
+  for table, key, value in locksettings:
+    # Set the lockscreen setting for default user '0'
+    values = generate_values(key, value)
+
+    cmd = """begin transaction;
+delete from '%(table)s' where %(primary_key)s='%(primary_value)s';
+insert into '%(table)s' (%(columns)s) values (%(values)s);
+commit transaction;""" % {
+      'table': table,
+      'primary_key': columns[0],
+      'primary_value': values[0],
+      'columns': ', '.join(columns),
+      'values': ', '.join(["'%s'" % value for value in values])
+    }
+    output_msg = device.RunShellCommand('sqlite3 %s "%s"' % (db, cmd),
+                                        as_root=True)
+    if output_msg:
+      logging.info(' '.join(output_msg))
+
+
+ENABLE_LOCATION_SETTINGS = [
+  # Note that setting these in this order is required in order for all of
+  # them to take and stick through a reboot.
+  ('com.google.settings/partner', [
+    ('use_location_for_services', 1),
+  ]),
+  ('settings/secure', [
+    # Ensure Geolocation is enabled and allowed for tests.
+    ('location_providers_allowed', 'gps,network'),
+  ]),
+  ('com.google.settings/partner', [
+    ('network_location_opt_in', 1),
+  ])
+]
+
+DISABLE_LOCATION_SETTINGS = [
+  ('com.google.settings/partner', [
+    ('use_location_for_services', 0),
+  ]),
+  ('settings/secure', [
+    # Ensure Geolocation is disabled.
+    ('location_providers_allowed', ''),
+  ]),
+]
+
+DETERMINISTIC_DEVICE_SETTINGS = [
+  ('settings/global', [
+    ('assisted_gps_enabled', 0),
+
+    # Disable "auto time" and "auto time zone" to avoid network-provided time
+    # to overwrite the device's datetime and timezone synchronized from host
+    # when running tests later. See b/6569849.
+    ('auto_time', 0),
+    ('auto_time_zone', 0),
+
+    ('development_settings_enabled', 1),
+
+    # Flag for allowing ActivityManagerService to send ACTION_APP_ERROR intents
+    # on application crashes and ANRs. If this is disabled, the crash/ANR dialog
+    # will never display the "Report" button.
+    # Type: int ( 0 = disallow, 1 = allow )
+    ('send_action_app_error', 0),
+
+    ('stay_on_while_plugged_in', 3),
+
+    ('verifier_verify_adb_installs', 0),
+  ]),
+  ('settings/secure', [
+    ('allowed_geolocation_origins',
+        'http://www.google.co.uk http://www.google.com'),
+
+    # Ensure that we never get random dialogs like "Unfortunately the process
+    # android.process.acore has stopped", which steal the focus, and make our
+    # automation fail (because the dialog steals the focus then mistakenly
+    # receives the injected user input events).
+    ('anr_show_background', 0),
+
+    ('lockscreen.disabled', 1),
+
+    ('screensaver_enabled', 0),
+  ]),
+  ('settings/system', [
+    # Don't want devices to accidentally rotate the screen as that could
+    # affect performance measurements.
+    ('accelerometer_rotation', 0),
+
+    ('lockscreen.disabled', 1),
+
+    # Turn down brightness and disable auto-adjust so that devices run cooler.
+    ('screen_brightness', 5),
+    ('screen_brightness_mode', 0),
+
+    ('user_rotation', 0),
+  ]),
+]
+
+NETWORK_DISABLED_SETTINGS = [
+  ('settings/global', [
+    ('airplane_mode_on', 1),
+    ('wifi_on', 0),
+  ]),
+]
diff --git a/build/android/pylib/device_signal.py b/build/android/pylib/device_signal.py
new file mode 100644
index 0000000..6a5b709
--- /dev/null
+++ b/build/android/pylib/device_signal.py
@@ -0,0 +1,41 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines constants for signals that should be supported on devices.
+
+Note: Obtained by running `kill -l` on a user device.
+"""
+
+
+SIGHUP = 1 # Hangup
+SIGINT = 2 # Interrupt
+SIGQUIT = 3 # Quit
+SIGILL = 4 # Illegal instruction
+SIGTRAP = 5 # Trap
+SIGABRT = 6 # Aborted
+SIGBUS = 7 # Bus error
+SIGFPE = 8 # Floating point exception
+SIGKILL = 9 # Killed
+SIGUSR1 = 10 # User signal 1
+SIGSEGV = 11 # Segmentation fault
+SIGUSR2 = 12 # User signal 2
+SIGPIPE = 13 # Broken pipe
+SIGALRM = 14 # Alarm clock
+SIGTERM = 15 # Terminated
+SIGSTKFLT = 16 # Stack fault
+SIGCHLD = 17 # Child exited
+SIGCONT = 18 # Continue
+SIGSTOP = 19 # Stopped (signal)
+SIGTSTP = 20 # Stopped
+SIGTTIN = 21 # Stopped (tty input)
+SIGTTOU = 22 # Stopped (tty output)
+SIGURG = 23 # Urgent I/O condition
+SIGXCPU = 24 # CPU time limit exceeded
+SIGXFSZ = 25 # File size limit exceeded
+SIGVTALRM = 26 # Virtual timer expired
+SIGPROF = 27 # Profiling timer expired
+SIGWINCH = 28 # Window size changed
+SIGIO = 29 # I/O possible
+SIGPWR = 30 # Power failure
+SIGSYS = 31 # Bad system call
diff --git a/build/android/pylib/efficient_android_directory_copy.sh b/build/android/pylib/efficient_android_directory_copy.sh
new file mode 100755
index 0000000..7021109
--- /dev/null
+++ b/build/android/pylib/efficient_android_directory_copy.sh
@@ -0,0 +1,78 @@
+#!/system/bin/sh
+
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Android shell script to make the destination directory identical with the
+# source directory, without doing unnecessary copies. This assumes that the
+# the destination directory was originally a copy of the source directory, and
+# has since been modified.
+
+source=$1
+dest=$2
+echo copying $source to $dest
+
+delete_extra() {
+  # Don't delete symbolic links, since doing so deletes the vital lib link.
+  if [ ! -L "$1" ]
+  then
+    if [ ! -e "$source/$1" ]
+    then
+      echo rm -rf "$dest/$1"
+      rm -rf "$dest/$1"
+    elif [ -d "$1" ]
+    then
+      for f in "$1"/*
+      do
+       delete_extra "$f"
+      done
+    fi
+  fi
+}
+
+copy_if_older() {
+  if [ -d "$1" ] && [ -e "$dest/$1" ]
+  then
+    if [ ! -e "$dest/$1" ]
+    then
+      echo cp -a "$1" "$dest/$1"
+      cp -a "$1" "$dest/$1"
+    else
+      for f in "$1"/*
+      do
+        copy_if_older "$f"
+      done
+    fi
+  elif [ ! -e "$dest/$1" ] || [ "$1" -ot "$dest/$1" ] || [ "$1" -nt "$dest/$1" ]
+  then
+    # dates are different, so either the destination of the source has changed.
+    echo cp -a "$1" "$dest/$1"
+    cp -a "$1" "$dest/$1"
+  fi
+}
+
+if [ -e "$dest" ]
+then
+  echo cd "$dest"
+  cd "$dest"
+  for f in ./*
+  do
+    if [ -e "$f" ]
+    then
+      delete_extra "$f"
+    fi
+  done
+else
+  echo mkdir "$dest"
+  mkdir "$dest"
+fi
+echo cd "$source"
+cd "$source"
+for f in ./*
+do
+  if [ -e "$f" ]
+  then
+    copy_if_older "$f"
+  fi
+done
diff --git a/build/android/pylib/flag_changer.py b/build/android/pylib/flag_changer.py
new file mode 100644
index 0000000..718bc39
--- /dev/null
+++ b/build/android/pylib/flag_changer.py
@@ -0,0 +1,166 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+
+import pylib.android_commands
+import pylib.device.device_utils
+
+from pylib.device import device_errors
+
+
+class FlagChanger(object):
+  """Changes the flags Chrome runs with.
+
+  There are two different use cases for this file:
+  * Flags are permanently set by calling Set().
+  * Flags can be temporarily set for a particular set of unit tests.  These
+    tests should call Restore() to revert the flags to their original state
+    once the tests have completed.
+  """
+
+  def __init__(self, device, cmdline_file):
+    """Initializes the FlagChanger and records the original arguments.
+
+    Args:
+      device: A DeviceUtils instance.
+      cmdline_file: Path to the command line file on the device.
+    """
+    # TODO(jbudorick) Remove once telemetry switches over.
+    if isinstance(device, pylib.android_commands.AndroidCommands):
+      device = pylib.device.device_utils.DeviceUtils(device)
+    self._device = device
+    self._cmdline_file = cmdline_file
+
+    # Save the original flags.
+    try:
+      self._orig_line = self._device.ReadFile(self._cmdline_file).strip()
+    except device_errors.CommandFailedError:
+      self._orig_line = ''
+
+    # Parse out the flags into a list to facilitate adding and removing flags.
+    self._current_flags = self._TokenizeFlags(self._orig_line)
+
+  def Get(self):
+    """Returns list of current flags."""
+    return self._current_flags
+
+  def Set(self, flags):
+    """Replaces all flags on the current command line with the flags given.
+
+    Args:
+      flags: A list of flags to set, eg. ['--single-process'].
+    """
+    if flags:
+      assert flags[0] != 'chrome'
+
+    self._current_flags = flags
+    self._UpdateCommandLineFile()
+
+  def AddFlags(self, flags):
+    """Appends flags to the command line if they aren't already there.
+
+    Args:
+      flags: A list of flags to add on, eg. ['--single-process'].
+    """
+    if flags:
+      assert flags[0] != 'chrome'
+
+    # Avoid appending flags that are already present.
+    for flag in flags:
+      if flag not in self._current_flags:
+        self._current_flags.append(flag)
+    self._UpdateCommandLineFile()
+
+  def RemoveFlags(self, flags):
+    """Removes flags from the command line, if they exist.
+
+    Args:
+      flags: A list of flags to remove, eg. ['--single-process'].  Note that we
+             expect a complete match when removing flags; if you want to remove
+             a switch with a value, you must use the exact string used to add
+             it in the first place.
+    """
+    if flags:
+      assert flags[0] != 'chrome'
+
+    for flag in flags:
+      if flag in self._current_flags:
+        self._current_flags.remove(flag)
+    self._UpdateCommandLineFile()
+
+  def Restore(self):
+    """Restores the flags to their original state."""
+    self._current_flags = self._TokenizeFlags(self._orig_line)
+    self._UpdateCommandLineFile()
+
+  def _UpdateCommandLineFile(self):
+    """Writes out the command line to the file, or removes it if empty."""
+    logging.info('Current flags: %s', self._current_flags)
+    # Root is not required to write to /data/local/tmp/.
+    use_root = '/data/local/tmp/' not in self._cmdline_file
+    if self._current_flags:
+      # The first command line argument doesn't matter as we are not actually
+      # launching the chrome executable using this command line.
+      cmd_line = ' '.join(['_'] + self._current_flags)
+      self._device.WriteFile(
+          self._cmdline_file, cmd_line, as_root=use_root)
+      file_contents = self._device.ReadFile(
+          self._cmdline_file, as_root=use_root).rstrip()
+      assert file_contents == cmd_line, (
+          'Failed to set the command line file at %s' % self._cmdline_file)
+    else:
+      self._device.RunShellCommand('rm ' + self._cmdline_file,
+                                   as_root=use_root)
+      assert not self._device.FileExists(self._cmdline_file), (
+          'Failed to remove the command line file at %s' % self._cmdline_file)
+
+  @staticmethod
+  def _TokenizeFlags(line):
+    """Changes the string containing the command line into a list of flags.
+
+    Follows similar logic to CommandLine.java::tokenizeQuotedArguments:
+    * Flags are split using whitespace, unless the whitespace is within a
+      pair of quotation marks.
+    * Unlike the Java version, we keep the quotation marks around switch
+      values since we need them to re-create the file when new flags are
+      appended.
+
+    Args:
+      line: A string containing the entire command line.  The first token is
+            assumed to be the program name.
+    """
+    if not line:
+      return []
+
+    tokenized_flags = []
+    current_flag = ""
+    within_quotations = False
+
+    # Move through the string character by character and build up each flag
+    # along the way.
+    for c in line.strip():
+      if c is '"':
+        if len(current_flag) > 0 and current_flag[-1] == '\\':
+          # Last char was a backslash; pop it, and treat this " as a literal.
+          current_flag = current_flag[0:-1] + '"'
+        else:
+          within_quotations = not within_quotations
+          current_flag += c
+      elif not within_quotations and (c is ' ' or c is '\t'):
+        if current_flag is not "":
+          tokenized_flags.append(current_flag)
+          current_flag = ""
+      else:
+        current_flag += c
+
+    # Tack on the last flag.
+    if not current_flag:
+      if within_quotations:
+        logging.warn('Unterminated quoted argument: ' + line)
+    else:
+      tokenized_flags.append(current_flag)
+
+    # Return everything but the program name.
+    return tokenized_flags[1:]
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
new file mode 100644
index 0000000..d16b9b1
--- /dev/null
+++ b/build/android/pylib/forwarder.py
@@ -0,0 +1,329 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=W0212
+
+import fcntl
+import logging
+import os
+import psutil
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib import valgrind_tools
+
+# TODO(jbudorick) Remove once telemetry gets switched over.
+import pylib.android_commands
+import pylib.device.device_utils
+
+
+def _GetProcessStartTime(pid):
+  return psutil.Process(pid).create_time
+
+
+class _FileLock(object):
+  """With statement-aware implementation of a file lock.
+
+  File locks are needed for cross-process synchronization when the
+  multiprocessing Python module is used.
+  """
+  def __init__(self, path):
+    self._fd = -1
+    self._path = path
+
+  def __enter__(self):
+    self._fd = os.open(self._path, os.O_RDONLY | os.O_CREAT)
+    if self._fd < 0:
+      raise Exception('Could not open file %s for reading' % self._path)
+    fcntl.flock(self._fd, fcntl.LOCK_EX)
+
+  def __exit__(self, _exception_type, _exception_value, traceback):
+    fcntl.flock(self._fd, fcntl.LOCK_UN)
+    os.close(self._fd)
+
+
+class Forwarder(object):
+  """Thread-safe class to manage port forwards from the device to the host."""
+
+  _DEVICE_FORWARDER_FOLDER = (constants.TEST_EXECUTABLE_DIR +
+                              '/forwarder/')
+  _DEVICE_FORWARDER_PATH = (constants.TEST_EXECUTABLE_DIR +
+                            '/forwarder/device_forwarder')
+  _LOCK_PATH = '/tmp/chrome.forwarder.lock'
+  # Defined in host_forwarder_main.cc
+  _HOST_FORWARDER_LOG = '/tmp/host_forwarder_log'
+
+  _instance = None
+
+  @staticmethod
+  def Map(port_pairs, device, tool=None):
+    """Runs the forwarder.
+
+    Args:
+      port_pairs: A list of tuples (device_port, host_port) to forward. Note
+                 that you can specify 0 as a device_port, in which case a
+                 port will by dynamically assigned on the device. You can
+                 get the number of the assigned port using the
+                 DevicePortForHostPort method.
+      device: A DeviceUtils instance.
+      tool: Tool class to use to get wrapper, if necessary, for executing the
+            forwarder (see valgrind_tools.py).
+
+    Raises:
+      Exception on failure to forward the port.
+    """
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, pylib.android_commands.AndroidCommands):
+      device = pylib.device.device_utils.DeviceUtils(device)
+    if not tool:
+      tool = valgrind_tools.CreateTool(None, device)
+    with _FileLock(Forwarder._LOCK_PATH):
+      instance = Forwarder._GetInstanceLocked(tool)
+      instance._InitDeviceLocked(device, tool)
+
+      device_serial = str(device)
+      redirection_commands = [
+          ['--adb=' + constants.GetAdbPath(),
+           '--serial-id=' + device_serial,
+           '--map', str(device_port), str(host_port)]
+          for device_port, host_port in port_pairs]
+      logging.info('Forwarding using commands: %s', redirection_commands)
+
+      for redirection_command in redirection_commands:
+        try:
+          (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
+              [instance._host_forwarder_path] + redirection_command)
+        except OSError as e:
+          if e.errno == 2:
+            raise Exception('Unable to start host forwarder. Make sure you have'
+                            ' built host_forwarder.')
+          else: raise
+        if exit_code != 0:
+          Forwarder._KillDeviceLocked(device, tool)
+          raise Exception('%s exited with %d:\n%s' % (
+              instance._host_forwarder_path, exit_code, '\n'.join(output)))
+        tokens = output.split(':')
+        if len(tokens) != 2:
+          raise Exception('Unexpected host forwarder output "%s", '
+                          'expected "device_port:host_port"' % output)
+        device_port = int(tokens[0])
+        host_port = int(tokens[1])
+        serial_with_port = (device_serial, device_port)
+        instance._device_to_host_port_map[serial_with_port] = host_port
+        instance._host_to_device_port_map[host_port] = serial_with_port
+        logging.info('Forwarding device port: %d to host port: %d.',
+                     device_port, host_port)
+
+  @staticmethod
+  def UnmapDevicePort(device_port, device):
+    """Unmaps a previously forwarded device port.
+
+    Args:
+      device: A DeviceUtils instance.
+      device_port: A previously forwarded port (through Map()).
+    """
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, pylib.android_commands.AndroidCommands):
+      device = pylib.device.device_utils.DeviceUtils(device)
+    with _FileLock(Forwarder._LOCK_PATH):
+      Forwarder._UnmapDevicePortLocked(device_port, device)
+
+  @staticmethod
+  def UnmapAllDevicePorts(device):
+    """Unmaps all the previously forwarded ports for the provided device.
+
+    Args:
+      device: A DeviceUtils instance.
+      port_pairs: A list of tuples (device_port, host_port) to unmap.
+    """
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, pylib.android_commands.AndroidCommands):
+      device = pylib.device.device_utils.DeviceUtils(device)
+    with _FileLock(Forwarder._LOCK_PATH):
+      if not Forwarder._instance:
+        return
+      adb_serial = str(device)
+      if adb_serial not in Forwarder._instance._initialized_devices:
+        return
+      port_map = Forwarder._GetInstanceLocked(
+          None)._device_to_host_port_map
+      for (device_serial, device_port) in port_map.keys():
+        if adb_serial == device_serial:
+          Forwarder._UnmapDevicePortLocked(device_port, device)
+      # There are no more ports mapped, kill the device_forwarder.
+      tool = valgrind_tools.CreateTool(None, device)
+      Forwarder._KillDeviceLocked(device, tool)
+
+  @staticmethod
+  def DevicePortForHostPort(host_port):
+    """Returns the device port that corresponds to a given host port."""
+    with _FileLock(Forwarder._LOCK_PATH):
+      (_device_serial, device_port) = Forwarder._GetInstanceLocked(
+          None)._host_to_device_port_map.get(host_port)
+      return device_port
+
+  @staticmethod
+  def RemoveHostLog():
+    if os.path.exists(Forwarder._HOST_FORWARDER_LOG):
+      os.unlink(Forwarder._HOST_FORWARDER_LOG)
+
+  @staticmethod
+  def GetHostLog():
+    if not os.path.exists(Forwarder._HOST_FORWARDER_LOG):
+      return ''
+    with file(Forwarder._HOST_FORWARDER_LOG, 'r') as f:
+      return f.read()
+
+  @staticmethod
+  def _GetInstanceLocked(tool):
+    """Returns the singleton instance.
+
+    Note that the global lock must be acquired before calling this method.
+
+    Args:
+      tool: Tool class to use to get wrapper, if necessary, for executing the
+            forwarder (see valgrind_tools.py).
+    """
+    if not Forwarder._instance:
+      Forwarder._instance = Forwarder(tool)
+    return Forwarder._instance
+
+  def __init__(self, tool):
+    """Constructs a new instance of Forwarder.
+
+    Note that Forwarder is a singleton therefore this constructor should be
+    called only once.
+
+    Args:
+      tool: Tool class to use to get wrapper, if necessary, for executing the
+            forwarder (see valgrind_tools.py).
+    """
+    assert not Forwarder._instance
+    self._tool = tool
+    self._initialized_devices = set()
+    self._device_to_host_port_map = dict()
+    self._host_to_device_port_map = dict()
+    self._host_forwarder_path = os.path.join(
+        constants.GetOutDirectory(), 'host_forwarder')
+    assert os.path.exists(self._host_forwarder_path), 'Please build forwarder2'
+    self._device_forwarder_path_on_host = os.path.join(
+        constants.GetOutDirectory(), 'forwarder_dist')
+    self._InitHostLocked()
+
+  @staticmethod
+  def _UnmapDevicePortLocked(device_port, device):
+    """Internal method used by UnmapDevicePort().
+
+    Note that the global lock must be acquired before calling this method.
+    """
+    instance = Forwarder._GetInstanceLocked(None)
+    serial = str(device)
+    serial_with_port = (serial, device_port)
+    if not serial_with_port in instance._device_to_host_port_map:
+      logging.error('Trying to unmap non-forwarded port %d' % device_port)
+      return
+    redirection_command = ['--adb=' + constants.GetAdbPath(),
+                           '--serial-id=' + serial,
+                           '--unmap', str(device_port)]
+    (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
+        [instance._host_forwarder_path] + redirection_command)
+    if exit_code != 0:
+      logging.error('%s exited with %d:\n%s' % (
+          instance._host_forwarder_path, exit_code, '\n'.join(output)))
+    host_port = instance._device_to_host_port_map[serial_with_port]
+    del instance._device_to_host_port_map[serial_with_port]
+    del instance._host_to_device_port_map[host_port]
+
+  @staticmethod
+  def _GetPidForLock():
+    """Returns the PID used for host_forwarder initialization.
+
+    The PID of the "sharder" is used to handle multiprocessing. The "sharder"
+    is the initial process that forks that is the parent process.
+    """
+    return os.getpgrp()
+
+  def _InitHostLocked(self):
+    """Initializes the host forwarder daemon.
+
+    Note that the global lock must be acquired before calling this method. This
+    method kills any existing host_forwarder process that could be stale.
+    """
+    # See if the host_forwarder daemon was already initialized by a concurrent
+    # process or thread (in case multi-process sharding is not used).
+    pid_for_lock = Forwarder._GetPidForLock()
+    fd = os.open(Forwarder._LOCK_PATH, os.O_RDWR | os.O_CREAT)
+    with os.fdopen(fd, 'r+') as pid_file:
+      pid_with_start_time = pid_file.readline()
+      if pid_with_start_time:
+        (pid, process_start_time) = pid_with_start_time.split(':')
+        if pid == str(pid_for_lock):
+          if process_start_time == str(_GetProcessStartTime(pid_for_lock)):
+            return
+      self._KillHostLocked()
+      pid_file.seek(0)
+      pid_file.write(
+          '%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock))))
+      pid_file.truncate()
+
+  def _InitDeviceLocked(self, device, tool):
+    """Initializes the device_forwarder daemon for a specific device (once).
+
+    Note that the global lock must be acquired before calling this method. This
+    method kills any existing device_forwarder daemon on the device that could
+    be stale, pushes the latest version of the daemon (to the device) and starts
+    it.
+
+    Args:
+      device: A DeviceUtils instance.
+      tool: Tool class to use to get wrapper, if necessary, for executing the
+            forwarder (see valgrind_tools.py).
+    """
+    device_serial = str(device)
+    if device_serial in self._initialized_devices:
+      return
+    Forwarder._KillDeviceLocked(device, tool)
+    device.PushChangedFiles([(
+        self._device_forwarder_path_on_host,
+        Forwarder._DEVICE_FORWARDER_FOLDER)])
+    cmd = '%s %s' % (tool.GetUtilWrapper(), Forwarder._DEVICE_FORWARDER_PATH)
+    device.RunShellCommand(
+        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER})
+    self._initialized_devices.add(device_serial)
+
+  def _KillHostLocked(self):
+    """Kills the forwarder process running on the host.
+
+    Note that the global lock must be acquired before calling this method.
+    """
+    logging.info('Killing host_forwarder.')
+    (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
+        [self._host_forwarder_path, '--kill-server'])
+    if exit_code != 0:
+      (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
+          ['pkill', '-9', 'host_forwarder'])
+      if exit_code != 0:
+        raise Exception('%s exited with %d:\n%s' % (
+              self._host_forwarder_path, exit_code, '\n'.join(output)))
+
+  @staticmethod
+  def _KillDeviceLocked(device, tool):
+    """Kills the forwarder process running on the device.
+
+    Note that the global lock must be acquired before calling this method.
+
+    Args:
+      device: Instance of DeviceUtils for talking to the device.
+      tool: Wrapper tool (e.g. valgrind) that can be used to execute the device
+            forwarder (see valgrind_tools.py).
+    """
+    logging.info('Killing device_forwarder.')
+    Forwarder._instance._initialized_devices.discard(str(device))
+    if not device.FileExists(Forwarder._DEVICE_FORWARDER_PATH):
+      return
+
+    cmd = '%s %s --kill-server' % (tool.GetUtilWrapper(),
+                                   Forwarder._DEVICE_FORWARDER_PATH)
+    device.RunShellCommand(
+        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER})
diff --git a/build/android/pylib/gtest/__init__.py b/build/android/pylib/gtest/__init__.py
new file mode 100644
index 0000000..727e987
--- /dev/null
+++ b/build/android/pylib/gtest/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/gtest/filter/OWNERS b/build/android/pylib/gtest/filter/OWNERS
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/build/android/pylib/gtest/filter/OWNERS
@@ -0,0 +1 @@
+*
diff --git a/build/android/pylib/gtest/filter/base_unittests_disabled b/build/android/pylib/gtest/filter/base_unittests_disabled
new file mode 100644
index 0000000..bf2311d
--- /dev/null
+++ b/build/android/pylib/gtest/filter/base_unittests_disabled
@@ -0,0 +1,28 @@
+# List of suppressions
+
+# Android will not support StackTrace.
+StackTrace.*
+#
+# Sometimes this is automatically generated by run_tests.py
+VerifyPathControlledByUserTest.Symlinks
+
+# http://crbug.com/138845
+MessagePumpLibeventTest.TestWatchingFromBadThread
+
+StringPrintfTest.StringPrintfMisc
+StringPrintfTest.StringAppendfString
+StringPrintfTest.StringAppendfInt
+StringPrintfTest.StringPrintfBounds
+ProcessUtilTest.GetAppOutputRestrictedSIGPIPE
+# TODO(jrg): Fails on bots.  Works locally.  Figure out why.  2/6/12
+FieldTrialTest.*
+# Flaky?
+ScopedJavaRefTest.RefCounts
+# Death tests are not supported with apks.
+*DeathTest*
+FileTest.MemoryCorruption
+MessagePumpLibeventTest.QuitOutsideOfRun
+ScopedFD.ScopedFDCrashesOnCloseFailure
+
+# http://crbug.com/245043
+StackContainer.BufferAlignment
diff --git a/build/android/pylib/gtest/filter/base_unittests_emulator_additional_disabled b/build/android/pylib/gtest/filter/base_unittests_emulator_additional_disabled
new file mode 100644
index 0000000..85e8fd6
--- /dev/null
+++ b/build/android/pylib/gtest/filter/base_unittests_emulator_additional_disabled
@@ -0,0 +1,10 @@
+# Addtional list of suppressions from emulator
+#
+# Automatically generated by run_tests.py
+PathServiceTest.Get
+SharedMemoryTest.OpenClose
+StringPrintfTest.StringAppendfInt
+StringPrintfTest.StringAppendfString
+StringPrintfTest.StringPrintfBounds
+StringPrintfTest.StringPrintfMisc
+VerifyPathControlledByUserTest.Symlinks
diff --git a/build/android/pylib/gtest/filter/blink_heap_unittests_disabled b/build/android/pylib/gtest/filter/blink_heap_unittests_disabled
new file mode 100644
index 0000000..7a43fb1
--- /dev/null
+++ b/build/android/pylib/gtest/filter/blink_heap_unittests_disabled
@@ -0,0 +1,2 @@
+# List of suppressions
+
diff --git a/build/android/pylib/gtest/filter/breakpad_unittests_disabled b/build/android/pylib/gtest/filter/breakpad_unittests_disabled
new file mode 100644
index 0000000..cefc64f
--- /dev/null
+++ b/build/android/pylib/gtest/filter/breakpad_unittests_disabled
@@ -0,0 +1,9 @@
+FileIDStripTest.StripSelf
+# crbug.com/303960
+ExceptionHandlerTest.InstructionPointerMemoryNullPointer
+# crbug.com/171419
+MinidumpWriterTest.MappingInfoContained
+# crbug.com/310088
+MinidumpWriterTest.MinidumpSizeLimit
+# crbug.com/375838
+ElfCoreDumpTest.ValidCoreFile
diff --git a/build/android/pylib/gtest/filter/cc_unittests_disabled b/build/android/pylib/gtest/filter/cc_unittests_disabled
new file mode 100644
index 0000000..feab5ac
--- /dev/null
+++ b/build/android/pylib/gtest/filter/cc_unittests_disabled
@@ -0,0 +1,5 @@
+# Death tests are not supported with apks.
+BeginFrameObserverMixInTest.OnBeginFrameImplementation
+BeginFrameSourceMixInTest.ObserverManipulation
+BeginFrameSourceMultiplexerTest.SourcesManipulation
+BeginFrameSourceMultiplexerTest.MinimumIntervalNegativeFails
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled
new file mode 100644
index 0000000..39eff4d
--- /dev/null
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -0,0 +1,65 @@
+# List of suppressions
+# Timeouts
+Http/MediaTest.*
+File/MediaTest.*
+MediaTest.*
+DatabaseTest.*
+
+# Crashes
+RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed
+
+# Plugins are not supported.
+BrowserPluginThreadedCompositorPixelTest.*
+BrowserPluginHostTest.*
+BrowserPluginTest.*
+PluginTest.*
+
+# http://crbug.com/463740
+CrossPlatformAccessibilityBrowserTest.SelectedEditableTextAccessibility
+
+# http://crbug.com/297230
+DumpAccessibilityTreeTest.AccessibilityAriaLevel
+DumpAccessibilityTreeTest.AccessibilityAriaProgressbar
+DumpAccessibilityTreeTest.AccessibilityListMarkers
+DumpAccessibilityTreeTest.AccessibilityUl
+DumpAccessibilityTreeTest.AccessibilityCanvas
+RendererAccessibilityTest.DetachAccessibilityObject
+DumpAccessibilityTreeTest.AccessibilityDialog
+DumpAccessibilityTreeTest.AccessibilityModalDialogClosed
+DumpAccessibilityTreeTest.AccessibilityModalDialogInIframeOpened
+RendererAccessibilityTest.EventOnObjectNotInTree
+
+# http://crbug.com/187500
+RenderViewImplTest.*
+RendererAccessibilityTest.SendFullAccessibilityTreeOnReload
+RendererAccessibilityTest.HideAccessibilityObject
+RendererAccessibilityTest.ShowAccessibilityObject
+
+# http://crbug.com/215894
+DownloadContentTest.CancelInterruptedDownload
+DownloadContentTest.CancelResumingDownload
+DownloadContentTest.RemoveDownload
+DownloadContentTest.RemoveResumingDownload
+DownloadContentTest.ResumeInterruptedDownload
+DownloadContentTest.ResumeInterruptedDownloadNoRange
+DownloadContentTest.ResumeInterruptedDownloadNoVerifiers
+DownloadContentTest.ResumeInterruptedDownloadBadPrecondition
+DownloadContentTest.ResumeWithDeletedFile
+
+# http://crbug.com/386227
+IndexedDBBrowserTest.VersionChangeCrashResilience
+
+# http://crbug.com/386222
+IndexedDBBrowserTest.DoesntHangTest
+
+# http://crbug.com/233118
+IndexedDBBrowserTest.NullKeyPathPersistence
+
+# http://crbug.com/342525
+IndexedDBBrowserTestSingleProcess.RenderThreadShutdownTest
+
+# http://crbug.com/338421
+GinBrowserTest.GinAndGarbageCollection
+
+# http://crbug.com/343604
+MSE_ClearKey/EncryptedMediaTest.ConfigChangeVideo/0
diff --git a/build/android/pylib/gtest/filter/content_unittests_disabled b/build/android/pylib/gtest/filter/content_unittests_disabled
new file mode 100644
index 0000000..925a7d1
--- /dev/null
+++ b/build/android/pylib/gtest/filter/content_unittests_disabled
@@ -0,0 +1,13 @@
+# List of suppressions
+
+# crbug.com/139095
+RenderWidgetTest.OnMsgPaintAtSize
+# crbug.com/147549
+GamepadProviderTest.PollingAccess
+PepperGamepadHostTest.WaitForReply
+# crbug.com/159234
+WebContentsVideoCaptureDeviceTest.*
+# crbug.com/167045
+ContentViewPopupZoomerTest.testPopupZoomerShowsUp
+# crbug.com/254034
+PageStateSerializationTest.BackwardsCompat_v11
diff --git a/build/android/pylib/gtest/filter/gfx_unittests_disabled b/build/android/pylib/gtest/filter/gfx_unittests_disabled
new file mode 100644
index 0000000..ade8b38
--- /dev/null
+++ b/build/android/pylib/gtest/filter/gfx_unittests_disabled
@@ -0,0 +1,27 @@
+CanvasTest.StringSizeEmptyString
+CanvasTest.StringWidth
+FontListTest.FontDescString_Derive
+FontListTest.FontDescString_FromFont
+FontListTest.FontDescString_FromFontNamesStyleAndSize
+FontListTest.FontDescString_FromFontVector
+FontListTest.FontDescString_FromFontWithNonNormalStyle
+FontListTest.Fonts_Derive
+FontListTest.Fonts_DeriveWithSizeDelta
+FontListTest.Fonts_DescStringWithStyleInFlexibleFormat_RoundTrip
+FontListTest.Fonts_FontVector_RoundTrip
+FontListTest.Fonts_FromDescString
+FontListTest.Fonts_FromDescStringInFlexibleFormat
+FontListTest.Fonts_FromDescStringWithStyleInFlexibleFormat
+FontListTest.Fonts_FromFont
+FontListTest.Fonts_FromFontVector
+FontListTest.Fonts_FromFontWithNonNormalStyle
+FontListTest.Fonts_GetHeight_GetBaseline
+FontListTest.Fonts_GetStyle
+FontTest.Ascent
+FontTest.AvgWidths
+FontTest.CapHeight
+FontTest.GetActualFontNameForTesting
+FontTest.Height
+FontTest.LoadArial
+FontTest.LoadArialBold
+TextUtilsTest.GetStringWidth
diff --git a/build/android/pylib/gtest/filter/ipc_tests_disabled b/build/android/pylib/gtest/filter/ipc_tests_disabled
new file mode 100644
index 0000000..e8d0691
--- /dev/null
+++ b/build/android/pylib/gtest/filter/ipc_tests_disabled
@@ -0,0 +1,18 @@
+# Times out
+IPCSyncChannelTest.ChattyServer
+
+# MultiProcessTest related failures. These tests fail if DCHECK is enabled.
+IPCChannelPosixTest.AdvancedConnected
+IPCChannelPosixTest.ResetState
+IPCChannelPosixTest.MultiConnection
+IPCFuzzingTest.SanityTest
+IPCFuzzingTest.MsgBadPayloadArgs
+IPCFuzzingTest.MsgBadPayloadShort
+IPCSendFdsTest.DescriptorTest
+IPCChannelProxyTest.MessageClassFilters
+IPCChannelProxyTest.GlobalAndMessageClassFilters
+IPCChannelProxyTest.FilterRemoval
+IPCChannelTest.ChannelTest
+IPCChannelTest.ChannelProxyTest
+IPCChannelTest.SendMessageInChannelConnected
+SyncSocketTest.SanityTest
diff --git a/build/android/pylib/gtest/filter/media_unittests_disabled b/build/android/pylib/gtest/filter/media_unittests_disabled
new file mode 100644
index 0000000..ed3b9aa
--- /dev/null
+++ b/build/android/pylib/gtest/filter/media_unittests_disabled
@@ -0,0 +1,8 @@
+# List of suppressions
+
+# Death tests are not supported on APK
+# http://crbug.com/138855
+CompositeFilterDeathTest.*
+
+# http://crbug.com/138833
+AesDecryptorTest.*
diff --git a/build/android/pylib/gtest/filter/net_unittests_disabled b/build/android/pylib/gtest/filter/net_unittests_disabled
new file mode 100644
index 0000000..75a1c86
--- /dev/null
+++ b/build/android/pylib/gtest/filter/net_unittests_disabled
@@ -0,0 +1,41 @@
+# List of suppressions.
+
+PythonUtils.PythonRunTime
+VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/0
+VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/1
+VerifyEndEntity/CertVerifyProcWeakDigestTest.Verify/2
+VerifyIncompleteEndEntity/CertVerifyProcWeakDigestTest.Verify/0
+VerifyIncompleteEndEntity/CertVerifyProcWeakDigestTest.Verify/1
+VerifyIncompleteEndEntity/CertVerifyProcWeakDigestTest.Verify/2
+VerifyIncompleteIntermediate/CertVerifyProcWeakDigestTest.Verify/0
+VerifyIncompleteIntermediate/CertVerifyProcWeakDigestTest.Verify/1
+VerifyIncompleteIntermediate/CertVerifyProcWeakDigestTest.Verify/2
+VerifyIntermediate/CertVerifyProcWeakDigestTest.Verify/0
+VerifyIntermediate/CertVerifyProcWeakDigestTest.Verify/1
+VerifyIntermediate/CertVerifyProcWeakDigestTest.Verify/2
+VerifyMixed/CertVerifyProcWeakDigestTest.Verify/0
+VerifyMixed/CertVerifyProcWeakDigestTest.Verify/1
+VerifyMixed/CertVerifyProcWeakDigestTest.Verify/2
+VerifyRoot/CertVerifyProcWeakDigestTest.Verify/0
+VerifyRoot/CertVerifyProcWeakDigestTest.Verify/1
+VerifyRoot/CertVerifyProcWeakDigestTest.Verify/2
+
+# Can't spin up more than one SpawnedTestServer on Android.
+URLRequestTestReferrerPolicy.HTTPToCrossOriginHTTP
+URLRequestTestReferrerPolicy.HTTPSToCrossOriginHTTPS
+URLRequestTestReferrerPolicy.HTTPToHTTPS
+URLRequestTestReferrerPolicy.HTTPSToHTTP
+
+# Fail only on bots.
+HttpCache.RangeGET_Cancel
+HttpCache.RangeGET_Cancel2
+HttpCache.RangeGET_OK
+HttpCache.RangeGET_Previous200
+HttpCache.RangeGET_Revalidate2
+HttpCache.RangeGET_SyncOK
+HttpCache.TypicalGET_ConditionalRequest
+# Death tests are not supported with apks.
+*DeathTest*
+# These are death tests and thus also disabled.
+PrioritizedDispatcherTest.CancelNull
+PrioritizedDispatcherTest.CancelMissing
diff --git a/build/android/pylib/gtest/filter/sync_unit_tests_disabled b/build/android/pylib/gtest/filter/sync_unit_tests_disabled
new file mode 100644
index 0000000..cc4b72d
--- /dev/null
+++ b/build/android/pylib/gtest/filter/sync_unit_tests_disabled
@@ -0,0 +1,4 @@
+SyncHttpBridgeTest.*
+
+# crbug.com/144422
+OnDiskSyncableDirectory.FailInitialWrite
diff --git a/build/android/pylib/gtest/filter/unit_tests_disabled b/build/android/pylib/gtest/filter/unit_tests_disabled
new file mode 100644
index 0000000..c7851fd
--- /dev/null
+++ b/build/android/pylib/gtest/filter/unit_tests_disabled
@@ -0,0 +1,119 @@
+# List of suppressions
+
+# The UDP related tests currently do not work on Android because
+# we lack a UDP forwarder tool.
+NetworkStatsTestUDP.*
+
+# Missing test resource of 16MB.
+HistoryProfileTest.TypicalProfileVersion
+
+# crbug.com/139408
+SQLitePersistentCookieStoreTest.TestDontLoadOldSessionCookies
+SQLitePersistentCookieStoreTest.PersistIsPersistent
+
+# crbug.com/139433
+AutofillTableTest.AutofillProfile*
+AutofillTableTest.UpdateAutofillProfile
+
+# crbug.com/139400
+AutofillProfileTest.*
+CreditCardTest.SetInfoExpirationMonth
+
+# crbug.com/139398
+DownloadItemModelTest.InterruptTooltip
+
+# Tests crashing in the APK
+# l10n_util.cc(655)] Check failed: std::string::npos != pos
+DownloadItemModelTest.InterruptStatus
+# l10n_util.cc(655)] Check failed: std::string::npos != pos
+WebsiteSettingsTest.OnSiteDataAccessed
+
+# crbug.com/139423
+ValueStoreFrontendTest.GetExistingData
+
+# crbug.com/139421
+ChromeSelectFilePolicyTest.ExpectAsynchronousListenerCall
+
+# http://crbug.com/139033
+ChromeDownloadManagerDelegateTest.StartDownload_PromptAlways
+
+# Extension support is limited on Android.
+# Some of these can be enabled if we register extension related prefs in
+# browser_prefs.cc
+ExtensionTest.*
+ExtensionAPI.*
+ExtensionFileUtilTest.*
+ExtensionPermissionsTest.*
+ExtensionUnpackerTest.*
+ActiveTabTest.*
+ExtensionAppsPromo.*
+ComponentLoaderTest.*
+ExtensionFromUserScript.*
+ExtensionFromWebApp.*
+ExtensionIconManagerTest.*
+ExtensionServiceTest.*
+ExtensionServiceTestSimple.*
+ExtensionSourcePriorityTest.*
+ExtensionSpecialStoragePolicyTest.*
+ExternalPolicyProviderTest.*
+ExternalProviderImplTest.*
+MenuManagerTest.*
+PageActionControllerTest.*
+PermissionsUpdaterTest.*
+ImageLoaderTest.*
+ImageLoadingTrackerTest.*
+ExtensionSettingsFrontendTest.*
+ExtensionSettingsSyncTest.*
+ExtensionUpdaterTest.*
+UserScriptListenerTest.*
+WebApplicationTest.GetShortcutInfoForTab
+ExtensionActionIconFactoryTest.*
+
+# crbug.com/139411
+AutocompleteProviderTest.*
+HistoryContentsProviderBodyOnlyTest.*
+HistoryContentsProviderTest.*
+HQPOrderingTest.*
+SearchProviderTest.*
+
+ProtocolHandlerRegistryTest.TestOSRegistrationFailure
+
+# crbug.com/139418
+SQLiteServerBoundCertStoreTest.TestUpgradeV1
+SQLiteServerBoundCertStoreTest.TestUpgradeV2
+
+ProfileSyncComponentsFactoryImplTest.*
+PermissionsTest.GetWarningMessages_Plugins
+ImageOperations.ResizeShouldAverageColors
+
+# crbug.com/138275
+PrerenderTest.*
+RenderWidgetTest.OnMsgPaintAtSize
+
+# crbug.com/139643
+VariationsUtilTest.DisableAfterInitialization
+VariationsUtilTest.AssociateGoogleVariationID
+VariationsUtilTest.NoAssociation
+
+# crbug.com/141473
+AutofillManagerTest.UpdatePasswordSyncState
+AutofillManagerTest.UpdatePasswordGenerationState
+
+# crbug.com/144227
+ExtensionIconImageTest.*
+
+# crbug.com/145843
+EntropyProviderTest.UseOneTimeRandomizationSHA1
+EntropyProviderTest.UseOneTimeRandomizationPermuted
+
+# crbug.com/147500
+ManifestTest.RestrictedKeys
+
+# crbug.com/152599
+SyncSearchEngineDataTypeControllerTest.*
+
+# crbug.com/256259
+DiagnosticsModelTest.RunAll
+
+# Death tests are not supported with apks.
+*DeathTest*
diff --git a/build/android/pylib/gtest/filter/webkit_unit_tests_disabled b/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
new file mode 100644
index 0000000..50292aa
--- /dev/null
+++ b/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
@@ -0,0 +1,28 @@
+# List of suppressions
+
+# crbug.com/159935
+WebCompositorInputHandlerImplTest.gestureFlingAnimates
+WebCompositorInputHandlerImplTest.gestureFlingTransferResets
+WebPageSerializerTest.HTMLNodes
+
+# crbug.com/241730
+ScrollAnimatorNoneTest.CurveMathQuartic
+ScrollAnimatorNoneTest.ScrollDownToBumper
+ScrollAnimatorNoneTest.ScrollQuadraticSmoothed
+ScrollAnimatorNoneTest.ScrollTwiceCubic
+ScrollAnimatorNoneTest.VaryingInputsEquivalencyCoastSteep
+WebViewTest.VisitedLinkCrash
+
+# Disabled until blink roll r151682
+DeferredImageDecoderTest.drawScaledIntoSkPicture
+
+# Disabled until blink roll r173540
+DeferredImageDecoderTest.decodeOnOtherThread
+DeferredImageDecoderTest.drawIntoSkPicture
+DeferredImageDecoderTest.drawIntoSkPictureProgressive
+
+# crbug.com/320005
+CoreAnimationCompositorAnimationsTest.ConvertTimingForCompositorIterationCount
+
+# crbug.com/412145
+TouchActionTest.Pan
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
new file mode 100644
index 0000000..6e332c7
--- /dev/null
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -0,0 +1,53 @@
+# 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.
+
+"""Configuration file for android gtest suites."""
+
+# Add new suites here before upgrading them to the stable list below.
+EXPERIMENTAL_TEST_SUITES = [
+    'components_browsertests',
+    'content_gl_tests',
+    'heap_profiler_unittests',
+    'devtools_bridge_tests',
+]
+
+TELEMETRY_EXPERIMENTAL_TEST_SUITES = [
+    'telemetry_unittests',
+]
+
+# Do not modify this list without approval of an android owner.
+# This list determines which suites are run by default, both for local
+# testing and on android trybots running on commit-queue.
+STABLE_TEST_SUITES = [
+    'android_webview_unittests',
+    'base_unittests',
+    'breakpad_unittests',
+    'cc_unittests',
+    'components_unittests',
+    'content_browsertests',
+    'content_unittests',
+    'events_unittests',
+    'gl_tests',
+    'gpu_unittests',
+    'ipc_tests',
+    'media_unittests',
+    'midi_unittests',
+    'net_unittests',
+    'sandbox_linux_unittests',
+    'skia_unittests',
+    'sql_unittests',
+    'sync_unit_tests',
+    'ui_android_unittests',
+    'ui_base_unittests',
+    'ui_touch_selection_unittests',
+    'unit_tests',
+    'webkit_unit_tests',
+]
+
+# Tests fail in component=shared_library build, which is required for ASan.
+# http://crbug.com/344868
+ASAN_EXCLUDED_TEST_SUITES = [
+    'breakpad_unittests',
+    'sandbox_linux_unittests'
+]
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
new file mode 100644
index 0000000..b6f83b3
--- /dev/null
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -0,0 +1,242 @@
+# Copyright 2014 The Chromium 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 logging
+import os
+import re
+import shutil
+import sys
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.base import test_instance
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', 'common'))
+import unittest_util
+
+
+# Used for filtering large data deps at a finer grain than what's allowed in
+# isolate files since pushing deps to devices is expensive.
+# Wildcards are allowed.
+_DEPS_EXCLUSION_LIST = [
+    'chrome/test/data/extensions/api_test',
+    'chrome/test/data/extensions/secure_shell',
+    'chrome/test/data/firefox*',
+    'chrome/test/data/gpu',
+    'chrome/test/data/image_decoding',
+    'chrome/test/data/import',
+    'chrome/test/data/page_cycler',
+    'chrome/test/data/perf',
+    'chrome/test/data/pyauto_private',
+    'chrome/test/data/safari_import',
+    'chrome/test/data/scroll',
+    'chrome/test/data/third_party',
+    'third_party/hunspell_dictionaries/*.dic',
+    # crbug.com/258690
+    'webkit/data/bmp_decoder',
+    'webkit/data/ico_decoder',
+]
+
+
+# TODO(jbudorick): Remove these once we're no longer parsing stdout to generate
+# results.
+_RE_TEST_STATUS = re.compile(
+    r'\[ +((?:RUN)|(?:FAILED)|(?:OK)) +\] ?([^ ]+)(?: \((\d+) ms\))?$')
+_RE_TEST_RUN_STATUS = re.compile(
+    r'\[ +(PASSED|RUNNER_FAILED|CRASHED) \] ?[^ ]+')
+
+
+# TODO(jbudorick): Make this a class method of GtestTestInstance once
+# test_package_apk and test_package_exe are gone.
+def ParseGTestListTests(raw_list):
+  """Parses a raw test list as provided by --gtest_list_tests.
+
+  Args:
+    raw_list: The raw test listing with the following format:
+
+    IPCChannelTest.
+      SendMessageInChannelConnected
+    IPCSyncChannelTest.
+      Simple
+      DISABLED_SendWithTimeoutMixedOKAndTimeout
+
+  Returns:
+    A list of all tests. For the above raw listing:
+
+    [IPCChannelTest.SendMessageInChannelConnected, IPCSyncChannelTest.Simple,
+     IPCSyncChannelTest.DISABLED_SendWithTimeoutMixedOKAndTimeout]
+  """
+  ret = []
+  current = ''
+  for test in raw_list:
+    if not test:
+      continue
+    if test[0] != ' ':
+      test_case = test.split()[0]
+      if test_case.endswith('.'):
+        current = test_case
+    elif not 'YOU HAVE' in test:
+      test_name = test.split()[0]
+      ret += [current + test_name]
+  return ret
+
+
+class GtestTestInstance(test_instance.TestInstance):
+
+  def __init__(self, args, isolate_delegate, error_func):
+    super(GtestTestInstance, self).__init__()
+    # TODO(jbudorick): Support multiple test suites.
+    if len(args.suite_name) > 1:
+      raise ValueError('Platform mode currently supports only 1 gtest suite')
+    self._suite = args.suite_name[0]
+
+    if (self._suite == 'content_browsertests' or
+        self._suite == 'components_browsertests'):
+      error_func('%s are not currently supported '
+                 'in platform mode.' % self._suite)
+      self._apk_path = os.path.join(
+          constants.GetOutDirectory(), 'apks', '%s.apk' % self._suite)
+    else:
+      self._apk_path = os.path.join(
+          constants.GetOutDirectory(), '%s_apk' % self._suite,
+          '%s-debug.apk' % self._suite)
+    self._exe_path = os.path.join(constants.GetOutDirectory(),
+                                  self._suite)
+    if not os.path.exists(self._apk_path):
+      self._apk_path = None
+    if not os.path.exists(self._exe_path):
+      self._exe_path = None
+    if not self._apk_path and not self._exe_path:
+      error_func('Could not find apk or executable for %s' % self._suite)
+
+    self._data_deps = []
+    if args.test_filter:
+      self._gtest_filter = args.test_filter
+    elif args.test_filter_file:
+      with open(args.test_filter_file, 'r') as f:
+        self._gtest_filter = ':'.join(l.strip() for l in f)
+    else:
+      self._gtest_filter = None
+    if args.isolate_file_path:
+      self._isolate_abs_path = os.path.abspath(args.isolate_file_path)
+      self._isolate_delegate = isolate_delegate
+      self._isolated_abs_path = os.path.join(
+          constants.GetOutDirectory(), '%s.isolated' % self._suite)
+    else:
+      logging.warning('No isolate file provided. No data deps will be pushed.');
+      self._isolate_delegate = None
+
+  #override
+  def TestType(self):
+    return 'gtest'
+
+  #override
+  def SetUp(self):
+    """Map data dependencies via isolate."""
+    if self._isolate_delegate:
+      self._isolate_delegate.Remap(
+          self._isolate_abs_path, self._isolated_abs_path)
+      self._isolate_delegate.PurgeExcluded(_DEPS_EXCLUSION_LIST)
+      self._isolate_delegate.MoveOutputDeps()
+      dest_dir = None
+      if self._suite == 'breakpad_unittests':
+        dest_dir = '/data/local/tmp/'
+      self._data_deps.extend([(constants.ISOLATE_DEPS_DIR, dest_dir)])
+
+
+  def GetDataDependencies(self):
+    """Returns the test suite's data dependencies.
+
+    Returns:
+      A list of (host_path, device_path) tuples to push. If device_path is
+      None, the client is responsible for determining where to push the file.
+    """
+    return self._data_deps
+
+  def FilterTests(self, test_list, disabled_prefixes=None):
+    """Filters |test_list| based on prefixes and, if present, a filter string.
+
+    Args:
+      test_list: The list of tests to filter.
+      disabled_prefixes: A list of test prefixes to filter. Defaults to
+        DISABLED_, FLAKY_, FAILS_, PRE_, and MANUAL_
+    Returns:
+      A filtered list of tests to run.
+    """
+    gtest_filter_strings = [
+        self._GenerateDisabledFilterString(disabled_prefixes)]
+    if self._gtest_filter:
+      gtest_filter_strings.append(self._gtest_filter)
+
+    filtered_test_list = test_list
+    for gtest_filter_string in gtest_filter_strings:
+      logging.debug('Filtering tests using: %s', gtest_filter_string)
+      filtered_test_list = unittest_util.FilterTestNames(
+          filtered_test_list, gtest_filter_string)
+    return filtered_test_list
+
+  def _GenerateDisabledFilterString(self, disabled_prefixes):
+    disabled_filter_items = []
+
+    if disabled_prefixes is None:
+      disabled_prefixes = ['DISABLED_', 'FLAKY_', 'FAILS_', 'PRE_', 'MANUAL_']
+    disabled_filter_items += ['%s*' % dp for dp in disabled_prefixes]
+    disabled_filter_items += ['*.%s*' % dp for dp in disabled_prefixes]
+
+    disabled_tests_file_path = os.path.join(
+        constants.DIR_SOURCE_ROOT, 'build', 'android', 'pylib', 'gtest',
+        'filter', '%s_disabled' % self._suite)
+    if disabled_tests_file_path and os.path.exists(disabled_tests_file_path):
+      with open(disabled_tests_file_path) as disabled_tests_file:
+        disabled_filter_items += [
+            '%s' % l for l in (line.strip() for line in disabled_tests_file)
+            if l and not l.startswith('#')]
+
+    return '*-%s' % ':'.join(disabled_filter_items)
+
+  def ParseGTestOutput(self, output):
+    """Parses raw gtest output and returns a list of results.
+
+    Args:
+      output: A list of output lines.
+    Returns:
+      A list of base_test_result.BaseTestResults.
+    """
+    results = []
+    for l in output:
+      matcher = _RE_TEST_STATUS.match(l)
+      if matcher:
+        result_type = None
+        if matcher.group(1) == 'OK':
+          result_type = base_test_result.ResultType.PASS
+        elif matcher.group(1) == 'FAILED':
+          result_type = base_test_result.ResultType.FAIL
+
+        if result_type:
+          test_name = matcher.group(2)
+          duration = matcher.group(3) if matcher.group(3) else 0
+          results.append(base_test_result.BaseTestResult(
+              test_name, result_type, duration))
+      logging.info(l)
+    return results
+
+  #override
+  def TearDown(self):
+    """Clear the mappings created by SetUp."""
+    if self._isolate_delegate:
+      self._isolate_delegate.Clear()
+
+  @property
+  def apk(self):
+    return self._apk_path
+
+  @property
+  def exe(self):
+    return self._exe_path
+
+  @property
+  def suite(self):
+    return self._suite
+
diff --git a/build/android/pylib/gtest/gtest_test_instance_test.py b/build/android/pylib/gtest/gtest_test_instance_test.py
new file mode 100755
index 0000000..c52b235
--- /dev/null
+++ b/build/android/pylib/gtest/gtest_test_instance_test.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 unittest
+
+from pylib.gtest import gtest_test_instance
+
+
+class GtestTestInstanceTests(unittest.TestCase):
+
+  def testParseGTestListTests_simple(self):
+    raw_output = [
+      'TestCaseOne.',
+      '  testOne',
+      '  testTwo',
+      'TestCaseTwo.',
+      '  testThree',
+      '  testFour',
+    ]
+    actual = gtest_test_instance.ParseGTestListTests(raw_output)
+    expected = [
+      'TestCaseOne.testOne',
+      'TestCaseOne.testTwo',
+      'TestCaseTwo.testThree',
+      'TestCaseTwo.testFour',
+    ]
+    self.assertEqual(expected, actual)
+
+  def testParseGTestListTests_typeParameterized_old(self):
+    raw_output = [
+      'TPTestCase/WithTypeParam/0.',
+      '  testOne',
+      '  testTwo',
+    ]
+    actual = gtest_test_instance.ParseGTestListTests(raw_output)
+    expected = [
+      'TPTestCase/WithTypeParam/0.testOne',
+      'TPTestCase/WithTypeParam/0.testTwo',
+    ]
+    self.assertEqual(expected, actual)
+
+  def testParseGTestListTests_typeParameterized_new(self):
+    raw_output = [
+      'TPTestCase/WithTypeParam/0.  # TypeParam = TypeParam0',
+      '  testOne',
+      '  testTwo',
+    ]
+    actual = gtest_test_instance.ParseGTestListTests(raw_output)
+    expected = [
+      'TPTestCase/WithTypeParam/0.testOne',
+      'TPTestCase/WithTypeParam/0.testTwo',
+    ]
+    self.assertEqual(expected, actual)
+
+  def testParseGTestListTests_valueParameterized_old(self):
+    raw_output = [
+      'VPTestCase.',
+      '  testWithValueParam/0',
+      '  testWithValueParam/1',
+    ]
+    actual = gtest_test_instance.ParseGTestListTests(raw_output)
+    expected = [
+      'VPTestCase.testWithValueParam/0',
+      'VPTestCase.testWithValueParam/1',
+    ]
+    self.assertEqual(expected, actual)
+
+  def testParseGTestListTests_valueParameterized_new(self):
+    raw_output = [
+      'VPTestCase.',
+      '  testWithValueParam/0  # GetParam() = 0',
+      '  testWithValueParam/1  # GetParam() = 1',
+    ]
+    actual = gtest_test_instance.ParseGTestListTests(raw_output)
+    expected = [
+      'VPTestCase.testWithValueParam/0',
+      'VPTestCase.testWithValueParam/1',
+    ]
+    self.assertEqual(expected, actual)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/gtest/local_device_gtest_run.py b/build/android/pylib/gtest/local_device_gtest_run.py
new file mode 100644
index 0000000..4241e85
--- /dev/null
+++ b/build/android/pylib/gtest/local_device_gtest_run.py
@@ -0,0 +1,206 @@
+# Copyright 2014 The Chromium 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 logging
+import os
+
+from pylib import constants
+from pylib import ports
+from pylib.base import test_run
+from pylib.device import device_errors
+from pylib.gtest import gtest_test_instance
+
+from pylib.local import local_test_server_spawner
+from pylib.local.device import local_device_environment
+from pylib.local.device import local_device_test_run
+from pylib.utils import apk_helper
+from pylib.utils import device_temp_file
+
+_COMMAND_LINE_FLAGS_SUPPORTED = True
+
+_EXTRA_COMMAND_LINE_FILE = (
+    'org.chromium.native_test.NativeTestActivity.CommandLineFile')
+_EXTRA_COMMAND_LINE_FLAGS = (
+    'org.chromium.native_test.NativeTestActivity.CommandLineFlags')
+
+_MAX_SHARD_SIZE = 256
+
+# TODO(jbudorick): Move this up to the test instance if the net test server is
+# handled outside of the APK for the remote_device environment.
+_SUITE_REQUIRES_TEST_SERVER_SPAWNER = [
+  'components_browsertests', 'content_unittests', 'content_browsertests',
+  'net_unittests', 'unit_tests'
+]
+
+class _ApkDelegate(object):
+  def __init__(self, apk):
+    self._apk = apk
+    self._package = apk_helper.GetPackageName(self._apk)
+    self._runner = apk_helper.GetInstrumentationName(self._apk)
+    self._component = '%s/%s' % (self._package, self._runner)
+    self._enable_test_server_spawner = False
+
+  def Install(self, device):
+    device.Install(self._apk)
+
+  def RunWithFlags(self, device, flags, **kwargs):
+    with device_temp_file.DeviceTempFile(device.adb) as command_line_file:
+      device.WriteFile(command_line_file.name, '_ %s' % flags)
+
+      extras = {
+        _EXTRA_COMMAND_LINE_FILE: command_line_file.name,
+      }
+
+      return device.StartInstrumentation(
+          self._component, extras=extras, raw=False, **kwargs)
+
+  def Clear(self, device):
+    device.ClearApplicationState(self._package)
+
+
+class _ExeDelegate(object):
+  def __init__(self, exe, tr):
+    self._exe_host_path = exe
+    self._exe_file_name = os.path.split(exe)[-1]
+    self._exe_device_path = '%s/%s' % (
+        constants.TEST_EXECUTABLE_DIR, self._exe_file_name)
+    deps_host_path = self._exe_host_path + '_deps'
+    if os.path.exists(deps_host_path):
+      self._deps_host_path = deps_host_path
+      self._deps_device_path = self._exe_device_path + '_deps'
+    else:
+      self._deps_host_path = None
+    self._test_run = tr
+
+  def Install(self, device):
+    # TODO(jbudorick): Look into merging this with normal data deps pushing if
+    # executables become supported on nonlocal environments.
+    host_device_tuples = [(self._exe_host_path, self._exe_device_path)]
+    if self._deps_host_path:
+      host_device_tuples.append((self._deps_host_path, self._deps_device_path))
+    device.PushChangedFiles(host_device_tuples)
+
+  def RunWithFlags(self, device, flags, **kwargs):
+    cmd = [
+        self._test_run.GetTool(device).GetTestWrapper(),
+        self._exe_device_path,
+        flags,
+    ]
+    cwd = constants.TEST_EXECUTABLE_DIR
+
+    env = {
+      'LD_LIBRARY_PATH':
+          '%s/%s_deps' % (constants.TEST_EXECUTABLE_DIR, self._exe_file_name),
+    }
+    try:
+      gcov_strip_depth = os.environ['NATIVE_COVERAGE_DEPTH_STRIP']
+      external = device.GetExternalStoragePath()
+      env['GCOV_PREFIX'] = '%s/gcov' % external
+      env['GCOV_PREFIX_STRIP'] = gcov_strip_depth
+    except (device_errors.CommandFailedError, KeyError):
+      pass
+
+    # TODO(jbudorick): Switch to just RunShellCommand once perezju@'s CL
+    # for long shell commands lands.
+    with device_temp_file.DeviceTempFile(device.adb) as script_file:
+      script_contents = ' '.join(cmd)
+      logging.info('script contents: %r' % script_contents)
+      device.WriteFile(script_file.name, script_contents)
+      output = device.RunShellCommand(['sh', script_file.name], cwd=cwd,
+                                      env=env, **kwargs)
+    return output
+
+  def Clear(self, device):
+    device.KillAll(self._exe_file_name, blocking=True, timeout=30, quiet=True)
+
+
+class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
+
+  def __init__(self, env, test_instance):
+    assert isinstance(env, local_device_environment.LocalDeviceEnvironment)
+    assert isinstance(test_instance, gtest_test_instance.GtestTestInstance)
+    super(LocalDeviceGtestRun, self).__init__(env, test_instance)
+
+    if self._test_instance.apk:
+      self._delegate = _ApkDelegate(self._test_instance.apk)
+    elif self._test_instance.exe:
+      self._delegate = _ExeDelegate(self, self._test_instance.exe)
+
+    self._servers = {}
+
+  #override
+  def TestPackage(self):
+    return self._test_instance._suite
+
+  #override
+  def SetUp(self):
+
+    def individual_device_set_up(dev, host_device_tuples):
+      # Install test APK.
+      self._delegate.Install(dev)
+
+      # Push data dependencies.
+      external_storage = dev.GetExternalStoragePath()
+      host_device_tuples = [
+          (h, d if d is not None else external_storage)
+          for h, d in host_device_tuples]
+      dev.PushChangedFiles(host_device_tuples)
+
+      self._servers[str(dev)] = []
+      if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
+        self._servers[str(dev)].append(
+            local_test_server_spawner.LocalTestServerSpawner(
+                ports.AllocateTestServerPort(), dev, self.GetTool(dev)))
+
+      for s in self._servers[str(dev)]:
+        s.SetUp()
+
+    self._env.parallel_devices.pMap(individual_device_set_up,
+                                    self._test_instance.GetDataDependencies())
+
+  #override
+  def _ShouldShard(self):
+    return True
+
+  #override
+  def _CreateShards(self, tests):
+    device_count = len(self._env.devices)
+    shards = []
+    for i in xrange(0, device_count):
+      unbounded_shard = tests[i::device_count]
+      shards += [unbounded_shard[j:j+_MAX_SHARD_SIZE]
+                 for j in xrange(0, len(unbounded_shard), _MAX_SHARD_SIZE)]
+    return [':'.join(s) for s in shards]
+
+  #override
+  def _GetTests(self):
+    tests = self._delegate.RunWithFlags(
+        self._env.devices[0], '--gtest_list_tests')
+    tests = gtest_test_instance.ParseGTestListTests(tests)
+    tests = self._test_instance.FilterTests(tests)
+    return tests
+
+  #override
+  def _RunTest(self, device, test):
+    # Run the test.
+    output = self._delegate.RunWithFlags(device, '--gtest_filter=%s' % test,
+                                         timeout=900, retries=0)
+    for s in self._servers[str(device)]:
+      s.Reset()
+    self._delegate.Clear(device)
+
+    # Parse the output.
+    # TODO(jbudorick): Transition test scripts away from parsing stdout.
+    results = self._test_instance.ParseGTestOutput(output)
+    return results
+
+  #override
+  def TearDown(self):
+    def individual_device_tear_down(dev):
+      for s in self._servers[str(dev)]:
+        s.TearDown()
+
+    self._env.parallel_devices.pMap(individual_device_tear_down)
+
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py
new file mode 100644
index 0000000..2676152
--- /dev/null
+++ b/build/android/pylib/gtest/setup.py
@@ -0,0 +1,247 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates test runner factory and tests for GTests."""
+# pylint: disable=W0212
+
+import logging
+import os
+import sys
+
+from pylib import constants
+
+from pylib.base import base_setup
+from pylib.base import base_test_result
+from pylib.base import test_dispatcher
+from pylib.device import device_utils
+from pylib.gtest import test_package_apk
+from pylib.gtest import test_package_exe
+from pylib.gtest import test_runner
+
+sys.path.insert(0,
+                os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib',
+                             'common'))
+import unittest_util # pylint: disable=F0401
+
+
+ISOLATE_FILE_PATHS = {
+    'base_unittests': 'base/base_unittests.isolate',
+    'blink_heap_unittests':
+      'third_party/WebKit/Source/platform/heap/BlinkHeapUnitTests.isolate',
+    'breakpad_unittests': 'breakpad/breakpad_unittests.isolate',
+    'cc_perftests': 'cc/cc_perftests.isolate',
+    'components_browsertests': 'components/components_browsertests.isolate',
+    'components_unittests': 'components/components_unittests.isolate',
+    'content_browsertests': 'content/content_browsertests.isolate',
+    'content_unittests': 'content/content_unittests.isolate',
+    'media_perftests': 'media/media_perftests.isolate',
+    'media_unittests': 'media/media_unittests.isolate',
+    'midi_unittests': 'media/midi/midi_unittests.isolate',
+    'net_unittests': 'net/net_unittests.isolate',
+    'sql_unittests': 'sql/sql_unittests.isolate',
+    'sync_unit_tests': 'sync/sync_unit_tests.isolate',
+    'ui_base_unittests': 'ui/base/ui_base_tests.isolate',
+    'unit_tests': 'chrome/unit_tests.isolate',
+    'webkit_unit_tests':
+      'third_party/WebKit/Source/web/WebKitUnitTests.isolate',
+}
+
+# Used for filtering large data deps at a finer grain than what's allowed in
+# isolate files since pushing deps to devices is expensive.
+# Wildcards are allowed.
+DEPS_EXCLUSION_LIST = [
+    'chrome/test/data/extensions/api_test',
+    'chrome/test/data/extensions/secure_shell',
+    'chrome/test/data/firefox*',
+    'chrome/test/data/gpu',
+    'chrome/test/data/image_decoding',
+    'chrome/test/data/import',
+    'chrome/test/data/page_cycler',
+    'chrome/test/data/perf',
+    'chrome/test/data/pyauto_private',
+    'chrome/test/data/safari_import',
+    'chrome/test/data/scroll',
+    'chrome/test/data/third_party',
+    'third_party/hunspell_dictionaries/*.dic',
+    # crbug.com/258690
+    'webkit/data/bmp_decoder',
+    'webkit/data/ico_decoder',
+]
+
+
+def _GetDisabledTestsFilterFromFile(suite_name):
+  """Returns a gtest filter based on the *_disabled file.
+
+  Args:
+    suite_name: Name of the test suite (e.g. base_unittests).
+
+  Returns:
+    A gtest filter which excludes disabled tests.
+    Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc'
+  """
+  filter_file_path = os.path.join(
+      os.path.abspath(os.path.dirname(__file__)),
+      'filter', '%s_disabled' % suite_name)
+
+  if not filter_file_path or not os.path.exists(filter_file_path):
+    logging.info('No filter file found at %s', filter_file_path)
+    return '*'
+
+  filters = [x for x in [x.strip() for x in file(filter_file_path).readlines()]
+             if x and x[0] != '#']
+  disabled_filter = '*-%s' % ':'.join(filters)
+  logging.info('Applying filter "%s" obtained from %s',
+               disabled_filter, filter_file_path)
+  return disabled_filter
+
+
+def _GetTests(test_options, test_package, devices):
+  """Get a list of tests.
+
+  Args:
+    test_options: A GTestOptions object.
+    test_package: A TestPackageApk object.
+    devices: A list of attached devices.
+
+  Returns:
+    A list of all the tests in the test suite.
+  """
+  class TestListResult(base_test_result.BaseTestResult):
+    def __init__(self):
+      super(TestListResult, self).__init__(
+          'gtest_list_tests', base_test_result.ResultType.PASS)
+      self.test_list = []
+
+  def TestListerRunnerFactory(device, _shard_index):
+    class TestListerRunner(test_runner.TestRunner):
+      def RunTest(self, _test):
+        result = TestListResult()
+        self.test_package.Install(self.device)
+        result.test_list = self.test_package.GetAllTests(self.device)
+        results = base_test_result.TestRunResults()
+        results.AddResult(result)
+        return results, None
+    return TestListerRunner(test_options, device, test_package)
+
+  results, _no_retry = test_dispatcher.RunTests(
+      ['gtest_list_tests'], TestListerRunnerFactory, devices)
+  tests = []
+  for r in results.GetAll():
+    tests.extend(r.test_list)
+  return tests
+
+
+def _FilterTestsUsingPrefixes(all_tests, pre=False, manual=False):
+  """Removes tests with disabled prefixes.
+
+  Args:
+    all_tests: List of tests to filter.
+    pre: If True, include tests with PRE_ prefix.
+    manual: If True, include tests with MANUAL_ prefix.
+
+  Returns:
+    List of tests remaining.
+  """
+  filtered_tests = []
+  filter_prefixes = ['DISABLED_', 'FLAKY_', 'FAILS_']
+
+  if not pre:
+    filter_prefixes.append('PRE_')
+
+  if not manual:
+    filter_prefixes.append('MANUAL_')
+
+  for t in all_tests:
+    test_case, test = t.split('.', 1)
+    if not any([test_case.startswith(prefix) or test.startswith(prefix) for
+                prefix in filter_prefixes]):
+      filtered_tests.append(t)
+  return filtered_tests
+
+
+def _FilterDisabledTests(tests, suite_name, has_gtest_filter):
+  """Removes disabled tests from |tests|.
+
+  Applies the following filters in order:
+    1. Remove tests with disabled prefixes.
+    2. Remove tests specified in the *_disabled files in the 'filter' dir
+
+  Args:
+    tests: List of tests.
+    suite_name: Name of the test suite (e.g. base_unittests).
+    has_gtest_filter: Whether a gtest_filter is provided.
+
+  Returns:
+    List of tests remaining.
+  """
+  tests = _FilterTestsUsingPrefixes(
+      tests, has_gtest_filter, has_gtest_filter)
+  tests = unittest_util.FilterTestNames(
+      tests, _GetDisabledTestsFilterFromFile(suite_name))
+
+  return tests
+
+
+def Setup(test_options, devices):
+  """Create the test runner factory and tests.
+
+  Args:
+    test_options: A GTestOptions object.
+    devices: A list of attached devices.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  test_package = test_package_apk.TestPackageApk(test_options.suite_name)
+  if not os.path.exists(test_package.suite_path):
+    exe_test_package = test_package_exe.TestPackageExecutable(
+        test_options.suite_name)
+    if not os.path.exists(exe_test_package.suite_path):
+      raise Exception(
+          'Did not find %s target. Ensure it has been built.\n'
+          '(not found at %s or %s)'
+          % (test_options.suite_name,
+             test_package.suite_path,
+             exe_test_package.suite_path))
+    test_package = exe_test_package
+  logging.warning('Found target %s', test_package.suite_path)
+
+  base_setup.GenerateDepsDirUsingIsolate(test_options.suite_name,
+                                         test_options.isolate_file_path,
+                                         ISOLATE_FILE_PATHS,
+                                         DEPS_EXCLUSION_LIST)
+  def push_data_deps_to_device_dir(device):
+    device_dir = (constants.TEST_EXECUTABLE_DIR
+        if test_package.suite_name == 'breakpad_unittests'
+        else device.GetExternalStoragePath())
+    base_setup.PushDataDeps(device, device_dir, test_options)
+  device_utils.DeviceUtils.parallel(devices).pMap(push_data_deps_to_device_dir)
+
+  tests = _GetTests(test_options, test_package, devices)
+
+  # Constructs a new TestRunner with the current options.
+  def TestRunnerFactory(device, _shard_index):
+    return test_runner.TestRunner(
+        test_options,
+        device,
+        test_package)
+
+  if test_options.run_disabled:
+    test_options = test_options._replace(
+        test_arguments=('%s --gtest_also_run_disabled_tests' %
+                        test_options.test_arguments))
+  else:
+    tests = _FilterDisabledTests(tests, test_options.suite_name,
+                                 bool(test_options.gtest_filter))
+  if test_options.gtest_filter:
+    tests = unittest_util.FilterTestNames(tests, test_options.gtest_filter)
+
+  # Coalesce unit tests into a single test per device
+  if (test_options.suite_name != 'content_browsertests' and
+      test_options.suite_name != 'components_browsertests'):
+    num_devices = len(devices)
+    tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)]
+    tests = [t for t in tests if t]
+
+  return (TestRunnerFactory, tests)
diff --git a/build/android/pylib/gtest/test_options.py b/build/android/pylib/gtest/test_options.py
new file mode 100644
index 0000000..58cd82b
--- /dev/null
+++ b/build/android/pylib/gtest/test_options.py
@@ -0,0 +1,16 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the GTestOptions named tuple."""
+
+import collections
+
+GTestOptions = collections.namedtuple('GTestOptions', [
+    'tool',
+    'gtest_filter',
+    'run_disabled',
+    'test_arguments',
+    'timeout',
+    'isolate_file_path',
+    'suite_name'])
diff --git a/build/android/pylib/gtest/test_package.py b/build/android/pylib/gtest/test_package.py
new file mode 100644
index 0000000..dbd47bf
--- /dev/null
+++ b/build/android/pylib/gtest/test_package.py
@@ -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.
+
+"""Base class representing GTest test packages."""
+# pylint: disable=R0201
+
+
+class TestPackage(object):
+
+  """A helper base class for both APK and stand-alone executables.
+
+  Args:
+    suite_name: Name of the test suite (e.g. base_unittests).
+  """
+  def __init__(self, suite_name):
+    self.suite_name = suite_name
+
+  def ClearApplicationState(self, device):
+    """Clears the application state.
+
+    Args:
+      device: Instance of DeviceUtils.
+    """
+    raise NotImplementedError('Method must be overriden.')
+
+  def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
+    """Creates a test runner script and pushes to the device.
+
+    Args:
+      device: Instance of DeviceUtils.
+      test_filter: A test_filter flag.
+      test_arguments: Additional arguments to pass to the test binary.
+    """
+    raise NotImplementedError('Method must be overriden.')
+
+  def GetAllTests(self, device):
+    """Returns a list of all tests available in the test suite.
+
+    Args:
+      device: Instance of DeviceUtils.
+    """
+    raise NotImplementedError('Method must be overriden.')
+
+  def GetGTestReturnCode(self, _device):
+    return None
+
+  def SpawnTestProcess(self, device):
+    """Spawn the test process.
+
+    Args:
+      device: Instance of DeviceUtils.
+
+    Returns:
+      An instance of pexpect spawn class.
+    """
+    raise NotImplementedError('Method must be overriden.')
+
+  def Install(self, device):
+    """Install the test package to the device.
+
+    Args:
+      device: Instance of DeviceUtils.
+    """
+    raise NotImplementedError('Method must be overriden.')
+
diff --git a/build/android/pylib/gtest/test_package_apk.py b/build/android/pylib/gtest/test_package_apk.py
new file mode 100644
index 0000000..9672f7a
--- /dev/null
+++ b/build/android/pylib/gtest/test_package_apk.py
@@ -0,0 +1,147 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines TestPackageApk to help run APK-based native tests."""
+# pylint: disable=W0212
+
+import logging
+import os
+import shlex
+import sys
+import tempfile
+import time
+
+from pylib import android_commands
+from pylib import constants
+from pylib import pexpect
+from pylib.device import device_errors
+from pylib.device import intent
+from pylib.gtest import gtest_test_instance
+from pylib.gtest.test_package import TestPackage
+
+
+class TestPackageApk(TestPackage):
+  """A helper class for running APK-based native tests."""
+
+  def __init__(self, suite_name):
+    """
+    Args:
+      suite_name: Name of the test suite (e.g. base_unittests).
+    """
+    TestPackage.__init__(self, suite_name)
+    if suite_name == 'content_browsertests':
+      self.suite_path = os.path.join(
+          constants.GetOutDirectory(), 'apks', '%s.apk' % suite_name)
+      self._package_info = constants.PACKAGE_INFO['content_browsertests']
+    elif suite_name == 'components_browsertests':
+      self.suite_path = os.path.join(
+          constants.GetOutDirectory(), 'apks', '%s.apk' % suite_name)
+      self._package_info = constants.PACKAGE_INFO['components_browsertests']
+    else:
+      self.suite_path = os.path.join(
+          constants.GetOutDirectory(), '%s_apk' % suite_name,
+          '%s-debug.apk' % suite_name)
+      self._package_info = constants.PACKAGE_INFO['gtest']
+
+  def _CreateCommandLineFileOnDevice(self, device, options):
+    device.WriteFile(self._package_info.cmdline_file,
+                     self.suite_name + ' ' + options)
+
+  def _GetFifo(self):
+    # The test.fifo path is determined by:
+    # testing/android/native_test/java/src/org/chromium/native_test/
+    #     NativeTestActivity.java and
+    # testing/android/native_test_launcher.cc
+    return '/data/data/' + self._package_info.package + '/files/test.fifo'
+
+  def _ClearFifo(self, device):
+    device.RunShellCommand('rm -f ' + self._GetFifo())
+
+  def _WatchFifo(self, device, timeout, logfile=None):
+    for i in range(100):
+      if device.FileExists(self._GetFifo()):
+        logging.info('Fifo created. Slept for %f secs' % (i * 0.5))
+        break
+      time.sleep(0.5)
+    else:
+      raise device_errors.DeviceUnreachableError(
+          'Unable to find fifo on device %s ' % self._GetFifo())
+    args = shlex.split(device.old_interface.Adb()._target_arg)
+    args += ['shell', 'cat', self._GetFifo()]
+    return pexpect.spawn('adb', args, timeout=timeout, logfile=logfile)
+
+  def _StartActivity(self, device, force_stop=True):
+    device.StartActivity(
+        intent.Intent(package=self._package_info.package,
+                      activity=self._package_info.activity,
+                      action='android.intent.action.MAIN'),
+        # No wait since the runner waits for FIFO creation anyway.
+        blocking=False,
+        force_stop=force_stop)
+
+  #override
+  def ClearApplicationState(self, device):
+    device.ClearApplicationState(self._package_info.package)
+    # Content shell creates a profile on the sdscard which accumulates cache
+    # files over time.
+    if self.suite_name == 'content_browsertests':
+      try:
+        device.RunShellCommand(
+            'rm -r %s/content_shell' % device.GetExternalStoragePath(),
+            timeout=60 * 2)
+      except device_errors.CommandFailedError:
+        # TODO(jbudorick) Handle this exception appropriately once the
+        #                 conversions are done.
+        pass
+    elif self.suite_name == 'components_browsertests':
+      try:
+        device.RunShellCommand(
+            'rm -r %s/components_shell' % device.GetExternalStoragePath(),
+            timeout=60 * 2)
+      except device_errors.CommandFailedError:
+        # TODO(jbudorick) Handle this exception appropriately once the
+        #                 conversions are done.
+        pass
+
+  #override
+  def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
+    self._CreateCommandLineFileOnDevice(
+        device, '--gtest_filter=%s %s' % (test_filter, test_arguments))
+
+  #override
+  def GetAllTests(self, device):
+    self._CreateCommandLineFileOnDevice(device, '--gtest_list_tests')
+    try:
+      self.tool.SetupEnvironment()
+      # Clear and start monitoring logcat.
+      self._ClearFifo(device)
+      self._StartActivity(device)
+      # Wait for native test to complete.
+      p = self._WatchFifo(device, timeout=30 * self.tool.GetTimeoutScale())
+      p.expect('<<ScopedMainEntryLogger')
+      p.close()
+    finally:
+      self.tool.CleanUpEnvironment()
+    # We need to strip the trailing newline.
+    content = [line.rstrip() for line in p.before.splitlines()]
+    return gtest_test_instance.ParseGTestListTests(content)
+
+  #override
+  def SpawnTestProcess(self, device):
+    try:
+      self.tool.SetupEnvironment()
+      self._ClearFifo(device)
+      # Doesn't need to stop an Activity because ClearApplicationState() is
+      # always called before this call and so it is already stopped at this
+      # point.
+      self._StartActivity(device, force_stop=False)
+    finally:
+      self.tool.CleanUpEnvironment()
+    logfile = android_commands.NewLineNormalizer(sys.stdout)
+    return self._WatchFifo(device, timeout=10, logfile=logfile)
+
+  #override
+  def Install(self, device):
+    self.tool.CopyFiles(device)
+    device.Install(self.suite_path)
diff --git a/build/android/pylib/gtest/test_package_exe.py b/build/android/pylib/gtest/test_package_exe.py
new file mode 100644
index 0000000..aa3374e
--- /dev/null
+++ b/build/android/pylib/gtest/test_package_exe.py
@@ -0,0 +1,160 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines TestPackageExecutable to help run stand-alone executables."""
+
+import logging
+import os
+import posixpath
+import sys
+import tempfile
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib import pexpect
+from pylib.device import device_errors
+from pylib.gtest import gtest_test_instance
+from pylib.gtest.test_package import TestPackage
+
+
+class TestPackageExecutable(TestPackage):
+  """A helper class for running stand-alone executables."""
+
+  _TEST_RUNNER_RET_VAL_FILE = 'gtest_retval'
+
+  def __init__(self, suite_name):
+    """
+    Args:
+      suite_name: Name of the test suite (e.g. base_unittests).
+    """
+    TestPackage.__init__(self, suite_name)
+    self.suite_path = os.path.join(constants.GetOutDirectory(), suite_name)
+    self._symbols_dir = os.path.join(constants.GetOutDirectory(),
+                                     'lib.target')
+
+  #override
+  def GetGTestReturnCode(self, device):
+    ret = None
+    ret_code = 1  # Assume failure if we can't find it
+    ret_code_file = tempfile.NamedTemporaryFile()
+    try:
+      if not device.PullFile(
+          constants.TEST_EXECUTABLE_DIR + '/' +
+          TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE,
+          ret_code_file.name):
+        logging.critical('Unable to pull gtest ret val file %s',
+                         ret_code_file.name)
+        raise ValueError
+      ret_code = file(ret_code_file.name).read()
+      ret = int(ret_code)
+    except ValueError:
+      logging.critical('Error reading gtest ret val file %s [%s]',
+                       ret_code_file.name, ret_code)
+      ret = 1
+    return ret
+
+  @staticmethod
+  def _AddNativeCoverageExports(device):
+    # export GCOV_PREFIX set the path for native coverage results
+    # export GCOV_PREFIX_STRIP indicates how many initial directory
+    #                          names to strip off the hardwired absolute paths.
+    #                          This value is calculated in buildbot.sh and
+    #                          depends on where the tree is built.
+    # Ex: /usr/local/google/code/chrome will become
+    #     /code/chrome if GCOV_PREFIX_STRIP=3
+    try:
+      depth = os.environ['NATIVE_COVERAGE_DEPTH_STRIP']
+      export_string = ('export GCOV_PREFIX="%s/gcov"\n' %
+                       device.GetExternalStoragePath())
+      export_string += 'export GCOV_PREFIX_STRIP=%s\n' % depth
+      return export_string
+    except KeyError:
+      logging.info('NATIVE_COVERAGE_DEPTH_STRIP is not defined: '
+                   'No native coverage.')
+      return ''
+    except device_errors.CommandFailedError:
+      logging.info('No external storage found: No native coverage.')
+      return ''
+
+  #override
+  def ClearApplicationState(self, device):
+    device.KillAll(self.suite_name, blocking=True, timeout=30, quiet=True)
+
+  #override
+  def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
+    tool_wrapper = self.tool.GetTestWrapper()
+    sh_script_file = tempfile.NamedTemporaryFile()
+    # We need to capture the exit status from the script since adb shell won't
+    # propagate to us.
+    sh_script_file.write(
+        'cd %s\n'
+        '%s'
+        '%s LD_LIBRARY_PATH=%s/%s_deps %s/%s --gtest_filter=%s %s\n'
+        'echo $? > %s' %
+        (constants.TEST_EXECUTABLE_DIR,
+         self._AddNativeCoverageExports(device),
+         tool_wrapper,
+         constants.TEST_EXECUTABLE_DIR,
+         self.suite_name,
+         constants.TEST_EXECUTABLE_DIR,
+         self.suite_name,
+         test_filter, test_arguments,
+         TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE))
+    sh_script_file.flush()
+    cmd_helper.RunCmd(['chmod', '+x', sh_script_file.name])
+    device.PushChangedFiles([(
+        sh_script_file.name,
+        constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh')])
+    logging.info('Conents of the test runner script: ')
+    for line in open(sh_script_file.name).readlines():
+      logging.info('  ' + line.rstrip())
+
+  #override
+  def GetAllTests(self, device):
+    lib_path = posixpath.join(
+        constants.TEST_EXECUTABLE_DIR, '%s_deps' % self.suite_name)
+
+    cmd = []
+    for wrapper in (device.GetDevicePieWrapper(), self.tool.GetTestWrapper()):
+      if wrapper:
+        cmd.append(wrapper)
+    cmd.extend([
+        posixpath.join(constants.TEST_EXECUTABLE_DIR, self.suite_name),
+        '--gtest_list_tests'])
+
+    output = device.RunShellCommand(
+        cmd, check_return=True, env={'LD_LIBRARY_PATH': lib_path})
+    return gtest_test_instance.ParseGTestListTests(output)
+
+  #override
+  def SpawnTestProcess(self, device):
+    args = ['adb', '-s', str(device), 'shell', 'sh',
+            constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh']
+    logging.info(args)
+    return pexpect.spawn(args[0], args[1:], logfile=sys.stdout)
+
+  #override
+  def Install(self, device):
+    if self.tool.NeedsDebugInfo():
+      target_name = self.suite_path
+    else:
+      target_name = self.suite_path + '_stripped'
+      if not os.path.isfile(target_name):
+        raise Exception('Did not find %s, build target %s' %
+                        (target_name, self.suite_name + '_stripped'))
+
+      target_mtime = os.stat(target_name).st_mtime
+      source_mtime = os.stat(self.suite_path).st_mtime
+      if target_mtime < source_mtime:
+        raise Exception(
+            'stripped binary (%s, timestamp %d) older than '
+            'source binary (%s, timestamp %d), build target %s' %
+            (target_name, target_mtime, self.suite_path, source_mtime,
+             self.suite_name + '_stripped'))
+
+    test_binary_path = constants.TEST_EXECUTABLE_DIR + '/' + self.suite_name
+    device.PushChangedFiles([(target_name, test_binary_path)])
+    deps_path = self.suite_path + '_deps'
+    if os.path.isdir(deps_path):
+      device.PushChangedFiles([(deps_path, test_binary_path + '_deps')])
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
new file mode 100644
index 0000000..4926388
--- /dev/null
+++ b/build/android/pylib/gtest/test_runner.py
@@ -0,0 +1,201 @@
+# Copyright (c) 2012 The Chromium 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 logging
+import os
+import re
+
+from pylib import pexpect
+from pylib import ports
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+from pylib.device import device_errors
+from pylib.local import local_test_server_spawner
+from pylib.perf import perf_control
+
+# Test case statuses.
+RE_RUN = re.compile('\\[ RUN      \\] ?(.*)\r\n')
+RE_FAIL = re.compile('\\[  FAILED  \\] ?(.*?)( \\((\\d+) ms\\))?\r\r\n')
+RE_OK = re.compile('\\[       OK \\] ?(.*?)( \\((\\d+) ms\\))?\r\r\n')
+
+# Test run statuses.
+RE_PASSED = re.compile('\\[  PASSED  \\] ?(.*)\r\n')
+RE_RUNNER_FAIL = re.compile('\\[ RUNNER_FAILED \\] ?(.*)\r\n')
+# Signal handlers are installed before starting tests
+# to output the CRASHED marker when a crash happens.
+RE_CRASH = re.compile('\\[ CRASHED      \\](.*)\r\n')
+
+# Bots that don't output anything for 20 minutes get timed out, so that's our
+# hard cap.
+_INFRA_STDOUT_TIMEOUT = 20 * 60
+
+
+def _TestSuiteRequiresMockTestServer(suite_name):
+  """Returns True if the test suite requires mock test server."""
+  tests_require_net_test_server = ['unit_tests', 'net_unittests',
+                                   'components_browsertests',
+                                   'content_unittests',
+                                   'content_browsertests']
+  return (suite_name in
+          tests_require_net_test_server)
+
+def _TestSuiteRequiresHighPerfMode(suite_name):
+  """Returns True if the test suite requires high performance mode."""
+  return 'perftests' in suite_name
+
+class TestRunner(base_test_runner.BaseTestRunner):
+  def __init__(self, test_options, device, test_package):
+    """Single test suite attached to a single device.
+
+    Args:
+      test_options: A GTestOptions object.
+      device: Device to run the tests.
+      test_package: An instance of TestPackage class.
+    """
+
+    super(TestRunner, self).__init__(device, test_options.tool)
+
+    self.test_package = test_package
+    self.test_package.tool = self.tool
+    self._test_arguments = test_options.test_arguments
+
+    timeout = test_options.timeout
+    if timeout == 0:
+      timeout = 60
+    # On a VM (e.g. chromium buildbots), this timeout is way too small.
+    if os.environ.get('BUILDBOT_SLAVENAME'):
+      timeout = timeout * 2
+
+    self._timeout = min(timeout * self.tool.GetTimeoutScale(),
+                        _INFRA_STDOUT_TIMEOUT)
+    if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
+      self._perf_controller = perf_control.PerfControl(self.device)
+
+    if _TestSuiteRequiresMockTestServer(self.test_package.suite_name):
+      self._servers = [
+          local_test_server_spawner.LocalTestServerSpawner(
+              ports.AllocateTestServerPort(), self.device, self.tool)]
+    else:
+      self._servers = []
+
+  #override
+  def InstallTestPackage(self):
+    self.test_package.Install(self.device)
+
+  def _ParseTestOutput(self, p):
+    """Process the test output.
+
+    Args:
+      p: An instance of pexpect spawn class.
+
+    Returns:
+      A TestRunResults object.
+    """
+    results = base_test_result.TestRunResults()
+
+    log = ''
+    try:
+      while True:
+        full_test_name = None
+
+        found = p.expect([RE_RUN, RE_PASSED, RE_RUNNER_FAIL],
+                         timeout=self._timeout)
+        if found == 1:  # RE_PASSED
+          break
+        elif found == 2:  # RE_RUNNER_FAIL
+          break
+        else:  # RE_RUN
+          full_test_name = p.match.group(1).replace('\r', '')
+          found = p.expect([RE_OK, RE_FAIL, RE_CRASH], timeout=self._timeout)
+          log = p.before.replace('\r', '')
+          if found == 0:  # RE_OK
+            if full_test_name == p.match.group(1).replace('\r', ''):
+              duration_ms = int(p.match.group(3)) if p.match.group(3) else 0
+              results.AddResult(base_test_result.BaseTestResult(
+                  full_test_name, base_test_result.ResultType.PASS,
+                  duration=duration_ms, log=log))
+          elif found == 2:  # RE_CRASH
+            results.AddResult(base_test_result.BaseTestResult(
+                full_test_name, base_test_result.ResultType.CRASH,
+                log=log))
+            break
+          else:  # RE_FAIL
+            duration_ms = int(p.match.group(3)) if p.match.group(3) else 0
+            results.AddResult(base_test_result.BaseTestResult(
+                full_test_name, base_test_result.ResultType.FAIL,
+                duration=duration_ms, log=log))
+    except pexpect.EOF:
+      logging.error('Test terminated - EOF')
+      # We're here because either the device went offline, or the test harness
+      # crashed without outputting the CRASHED marker (crbug.com/175538).
+      if not self.device.IsOnline():
+        raise device_errors.DeviceUnreachableError(
+            'Device %s went offline.' % str(self.device))
+      if full_test_name:
+        results.AddResult(base_test_result.BaseTestResult(
+            full_test_name, base_test_result.ResultType.CRASH,
+            log=p.before.replace('\r', '')))
+    except pexpect.TIMEOUT:
+      logging.error('Test terminated after %d second timeout.',
+                    self._timeout)
+      if full_test_name:
+        results.AddResult(base_test_result.BaseTestResult(
+            full_test_name, base_test_result.ResultType.TIMEOUT,
+            log=p.before.replace('\r', '')))
+    finally:
+      p.close()
+
+    ret_code = self.test_package.GetGTestReturnCode(self.device)
+    if ret_code:
+      logging.critical(
+          'gtest exit code: %d\npexpect.before: %s\npexpect.after: %s',
+          ret_code, p.before, p.after)
+
+    return results
+
+  #override
+  def RunTest(self, test):
+    test_results = base_test_result.TestRunResults()
+    if not test:
+      return test_results, None
+
+    try:
+      self.test_package.ClearApplicationState(self.device)
+      self.test_package.CreateCommandLineFileOnDevice(
+          self.device, test, self._test_arguments)
+      test_results = self._ParseTestOutput(
+          self.test_package.SpawnTestProcess(self.device))
+    finally:
+      for s in self._servers:
+        s.Reset()
+    # Calculate unknown test results.
+    all_tests = set(test.split(':'))
+    all_tests_ran = set([t.GetName() for t in test_results.GetAll()])
+    unknown_tests = all_tests - all_tests_ran
+    test_results.AddResults(
+        [base_test_result.BaseTestResult(t, base_test_result.ResultType.UNKNOWN)
+         for t in unknown_tests])
+    retry = ':'.join([t.GetName() for t in test_results.GetNotPass()])
+    return test_results, retry
+
+  #override
+  def SetUp(self):
+    """Sets up necessary test enviroment for the test suite."""
+    super(TestRunner, self).SetUp()
+    for s in self._servers:
+      s.SetUp()
+    if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
+      self._perf_controller.SetHighPerfMode()
+    self.tool.SetupEnvironment()
+
+  #override
+  def TearDown(self):
+    """Cleans up the test enviroment for the test suite."""
+    for s in self._servers:
+      s.TearDown()
+    if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
+      self._perf_controller.SetDefaultPerfMode()
+    self.test_package.ClearApplicationState(self.device)
+    self.tool.CleanUpEnvironment()
+    super(TestRunner, self).TearDown()
diff --git a/build/android/pylib/host_driven/__init__.py b/build/android/pylib/host_driven/__init__.py
new file mode 100644
index 0000000..727e987
--- /dev/null
+++ b/build/android/pylib/host_driven/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/host_driven/setup.py b/build/android/pylib/host_driven/setup.py
new file mode 100644
index 0000000..b2ed348
--- /dev/null
+++ b/build/android/pylib/host_driven/setup.py
@@ -0,0 +1,200 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Setup for instrumentation host-driven tests."""
+
+import logging
+import os
+import sys
+import types
+
+from pylib.host_driven import test_case
+from pylib.host_driven import test_info_collection
+from pylib.host_driven import test_runner
+
+
+def _GetPythonFiles(root, files):
+  """Returns all files from |files| that end in 'Test.py'.
+
+  Args:
+    root: A directory name with python files.
+    files: A list of file names.
+
+  Returns:
+    A list with all python files that match the testing naming scheme.
+  """
+  return [os.path.join(root, f) for f in files if f.endswith('Test.py')]
+
+
+def _InferImportNameFromFile(python_file):
+  """Given a file, infer the import name for that file.
+
+  Example: /usr/foo/bar/baz.py -> baz.
+
+  Args:
+    python_file: Path to the Python file, ostensibly to import later.
+
+  Returns:
+    The module name for the given file.
+  """
+  return os.path.splitext(os.path.basename(python_file))[0]
+
+
+def _GetTestModules(host_driven_test_root, is_official_build):
+  """Retrieve a list of python modules that match the testing naming scheme.
+
+  Walks the location of host-driven tests, imports them, and provides the list
+  of imported modules to the caller.
+
+  Args:
+    host_driven_test_root: The path to walk, looking for the
+        pythonDrivenTests or host_driven_tests directory
+    is_official_build: Whether to run only those tests marked 'official'
+
+  Returns:
+    A list of python modules under |host_driven_test_root| which match the
+    testing naming scheme. Each module should define one or more classes that
+    derive from HostDrivenTestCase.
+  """
+  # By default run all host-driven tests under pythonDrivenTests or
+  # host_driven_tests.
+  host_driven_test_file_list = []
+  for root, _, files in os.walk(host_driven_test_root):
+    if (root.endswith('host_driven_tests') or
+        root.endswith('pythonDrivenTests') or
+        (is_official_build and (root.endswith('pythonDrivenTests/official') or
+                                root.endswith('host_driven_tests/official')))):
+      host_driven_test_file_list += _GetPythonFiles(root, files)
+  host_driven_test_file_list.sort()
+
+  test_module_list = [_GetModuleFromFile(test_file)
+                      for test_file in host_driven_test_file_list]
+  return test_module_list
+
+
+def _GetModuleFromFile(python_file):
+  """Gets the python module associated with a file by importing it.
+
+  Args:
+    python_file: File to import.
+
+  Returns:
+    The module object.
+  """
+  sys.path.append(os.path.dirname(python_file))
+  import_name = _InferImportNameFromFile(python_file)
+  return __import__(import_name)
+
+
+def _GetTestsFromClass(test_case_class, **kwargs):
+  """Returns one test object for each test method in |test_case_class|.
+
+  Test methods are methods on the class which begin with 'test'.
+
+  Args:
+    test_case_class: Class derived from HostDrivenTestCase which contains zero
+        or more test methods.
+    kwargs: Keyword args to pass into the constructor of test cases.
+
+  Returns:
+    A list of test case objects, each initialized for a particular test method.
+  """
+  test_names = [m for m in dir(test_case_class)
+                if _IsTestMethod(m, test_case_class)]
+  return [test_case_class(name, **kwargs) for name in test_names]
+
+
+def _GetTestsFromModule(test_module, **kwargs):
+  """Gets a list of test objects from |test_module|.
+
+  Args:
+    test_module: Module from which to get the set of test methods.
+    kwargs: Keyword args to pass into the constructor of test cases.
+
+  Returns:
+    A list of test case objects each initialized for a particular test method
+    defined in |test_module|.
+  """
+
+  tests = []
+  for name in dir(test_module):
+    attr = getattr(test_module, name)
+    if _IsTestCaseClass(attr):
+      tests.extend(_GetTestsFromClass(attr, **kwargs))
+  return tests
+
+
+def _IsTestCaseClass(test_class):
+  return (type(test_class) is types.TypeType and
+          issubclass(test_class, test_case.HostDrivenTestCase) and
+          test_class is not test_case.HostDrivenTestCase)
+
+
+def _IsTestMethod(attrname, test_case_class):
+  """Checks whether this is a valid test method.
+
+  Args:
+    attrname: The method name.
+    test_case_class: The test case class.
+
+  Returns:
+    True if test_case_class.'attrname' is callable and it starts with 'test';
+    False otherwise.
+  """
+  attr = getattr(test_case_class, attrname)
+  return callable(attr) and attrname.startswith('test')
+
+
+def _GetAllTests(test_root, is_official_build, **kwargs):
+  """Retrieve a list of host-driven tests defined under |test_root|.
+
+  Args:
+    test_root: Path which contains host-driven test files.
+    is_official_build: Whether this is an official build.
+    kwargs: Keyword args to pass into the constructor of test cases.
+
+  Returns:
+    List of test case objects, one for each available test method.
+  """
+  if not test_root:
+    return []
+  all_tests = []
+  test_module_list = _GetTestModules(test_root, is_official_build)
+  for module in test_module_list:
+    all_tests.extend(_GetTestsFromModule(module, **kwargs))
+  return all_tests
+
+
+def InstrumentationSetup(host_driven_test_root, official_build,
+                         instrumentation_options):
+  """Creates a list of host-driven instrumentation tests and a runner factory.
+
+  Args:
+    host_driven_test_root: Directory where the host-driven tests are.
+    official_build: True if this is an official build.
+    instrumentation_options: An InstrumentationOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+
+  test_collection = test_info_collection.TestInfoCollection()
+  all_tests = _GetAllTests(
+      host_driven_test_root, official_build,
+      instrumentation_options=instrumentation_options)
+  test_collection.AddTests(all_tests)
+
+  available_tests = test_collection.GetAvailableTests(
+      instrumentation_options.annotations,
+      instrumentation_options.exclude_annotations,
+      instrumentation_options.test_filter)
+  logging.debug('All available tests: ' + str(
+      [t.tagged_name for t in available_tests]))
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.HostDrivenTestRunner(
+        device, shard_index,
+        instrumentation_options.tool)
+
+  return (TestRunnerFactory, available_tests)
diff --git a/build/android/pylib/host_driven/test_case.py b/build/android/pylib/host_driven/test_case.py
new file mode 100644
index 0000000..6ff4c5f
--- /dev/null
+++ b/build/android/pylib/host_driven/test_case.py
@@ -0,0 +1,189 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Base class for host-driven test cases.
+
+This test case is intended to serve as the base class for any host-driven
+test cases. It is similar to the Python unitttest module in that test cases
+inherit from this class and add methods which will be run as tests.
+
+When a HostDrivenTestCase object is instantiated, its purpose is to run only one
+test method in the derived class. The test runner gives it the name of the test
+method the instance will run. The test runner calls SetUp with the device ID
+which the test method will run against. The test runner runs the test method
+itself, collecting the result, and calls TearDown.
+
+Tests can perform arbitrary Python commands and asserts in test methods. Tests
+that run instrumentation tests can make use of the _RunJavaTestFilters helper
+function to trigger Java tests and convert results into a single host-driven
+test result.
+"""
+
+import logging
+import os
+import time
+
+from pylib import constants
+from pylib import forwarder
+from pylib import valgrind_tools
+from pylib.base import base_test_result
+from pylib.device import device_utils
+from pylib.instrumentation import test_package
+from pylib.instrumentation import test_result
+from pylib.instrumentation import test_runner
+
+# aka the parent of com.google.android
+BASE_ROOT = 'src' + os.sep
+
+
+class HostDrivenTestCase(object):
+  """Base class for host-driven test cases."""
+
+  _HOST_DRIVEN_TAG = 'HostDriven'
+
+  def __init__(self, test_name, instrumentation_options=None):
+    """Create a test case initialized to run |test_name|.
+
+    Args:
+      test_name: The name of the method to run as the test.
+      instrumentation_options: An InstrumentationOptions object.
+    """
+    class_name = self.__class__.__name__
+    self.device = None
+    self.device_id = ''
+    self.has_forwarded_ports = False
+    self.instrumentation_options = instrumentation_options
+    self.ports_to_forward = []
+    self.shard_index = 0
+
+    # Use tagged_name when creating results, so that we can identify host-driven
+    # tests in the overall results.
+    self.test_name = test_name
+    self.qualified_name = '%s.%s' % (class_name, self.test_name)
+    self.tagged_name = '%s_%s' % (self._HOST_DRIVEN_TAG, self.qualified_name)
+
+  # TODO(bulach): make ports_to_forward not optional and move the Forwarder
+  # mapping here.
+  def SetUp(self, device, shard_index, ports_to_forward=None):
+    if not ports_to_forward:
+      ports_to_forward = []
+    self.device = device
+    self.shard_index = shard_index
+    self.device_id = str(self.device)
+    if ports_to_forward:
+      self.ports_to_forward = ports_to_forward
+
+  def TearDown(self):
+    pass
+
+  # TODO(craigdh): Remove GetOutDir once references have been removed
+  # downstream.
+  @staticmethod
+  def GetOutDir():
+    return constants.GetOutDirectory()
+
+  def Run(self):
+    logging.info('Running host-driven test: %s', self.tagged_name)
+    # Get the test method on the derived class and execute it
+    return getattr(self, self.test_name)()
+
+  @staticmethod
+  def __GetHostForwarderLog():
+    return ('-- Begin Full HostForwarder log\n'
+            '%s\n'
+            '--End Full HostForwarder log\n' % forwarder.Forwarder.GetHostLog())
+
+  def __StartForwarder(self):
+    logging.warning('Forwarding %s %s', self.ports_to_forward,
+                    self.has_forwarded_ports)
+    if self.ports_to_forward and not self.has_forwarded_ports:
+      self.has_forwarded_ports = True
+      tool = valgrind_tools.CreateTool(None, self.device)
+      forwarder.Forwarder.Map([(port, port) for port in self.ports_to_forward],
+                              self.device, tool)
+
+  def __RunJavaTest(self, test, test_pkg, additional_flags=None):
+    """Runs a single Java test in a Java TestRunner.
+
+    Args:
+      test: Fully qualified test name (ex. foo.bar.TestClass#testMethod)
+      test_pkg: TestPackage object.
+      additional_flags: A list of additional flags to add to the command line.
+
+    Returns:
+      TestRunResults object with a single test result.
+    """
+    # TODO(bulach): move this to SetUp() stage.
+    self.__StartForwarder()
+
+    java_test_runner = test_runner.TestRunner(
+        self.instrumentation_options, self.device, self.shard_index,
+        test_pkg, additional_flags=additional_flags)
+    try:
+      java_test_runner.SetUp()
+      return java_test_runner.RunTest(test)[0]
+    finally:
+      java_test_runner.TearDown()
+
+  def _RunJavaTestFilters(self, test_filters, additional_flags=None):
+    """Calls a list of tests and stops at the first test failure.
+
+    This method iterates until either it encounters a non-passing test or it
+    exhausts the list of tests. Then it returns the appropriate overall result.
+
+    Test cases may make use of this method internally to assist in running
+    instrumentation tests. This function relies on instrumentation_options
+    being defined.
+
+    Args:
+      test_filters: A list of Java test filters.
+      additional_flags: A list of addition flags to add to the command line.
+
+    Returns:
+      A TestRunResults object containing an overall result for this set of Java
+      tests. If any Java tests do not pass, this is a fail overall.
+    """
+    test_type = base_test_result.ResultType.PASS
+    log = ''
+
+    test_pkg = test_package.TestPackage(
+        self.instrumentation_options.test_apk_path,
+        self.instrumentation_options.test_apk_jar_path,
+        self.instrumentation_options.test_support_apk_path)
+
+    start_ms = int(time.time()) * 1000
+    done = False
+    for test_filter in test_filters:
+      tests = test_pkg.GetAllMatchingTests(None, None, test_filter)
+      # Filters should always result in >= 1 test.
+      if len(tests) == 0:
+        raise Exception('Java test filter "%s" returned no tests.'
+                        % test_filter)
+      for test in tests:
+        # We're only running one test at a time, so this TestRunResults object
+        # will hold only one result.
+        java_result = self.__RunJavaTest(test, test_pkg, additional_flags)
+        assert len(java_result.GetAll()) == 1
+        if not java_result.DidRunPass():
+          result = java_result.GetNotPass().pop()
+          log = result.GetLog()
+          log += self.__GetHostForwarderLog()
+          test_type = result.GetType()
+          done = True
+          break
+      if done:
+        break
+    duration_ms = int(time.time()) * 1000 - start_ms
+
+    overall_result = base_test_result.TestRunResults()
+    overall_result.AddResult(
+        test_result.InstrumentationTestResult(
+            self.tagged_name, test_type, start_ms, duration_ms, log=log))
+    return overall_result
+
+  def __str__(self):
+    return self.tagged_name
+
+  def __repr__(self):
+    return self.tagged_name
diff --git a/build/android/pylib/host_driven/test_info_collection.py b/build/android/pylib/host_driven/test_info_collection.py
new file mode 100644
index 0000000..c65d417
--- /dev/null
+++ b/build/android/pylib/host_driven/test_info_collection.py
@@ -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.
+
+"""Module containing information about the host-driven tests."""
+
+import logging
+import os
+import sys
+
+from pylib.host_driven import tests_annotations
+
+from pylib import constants
+
+sys.path.insert(0,
+                os.path.join(constants.DIR_SOURCE_ROOT,
+                             'build', 'util', 'lib', 'common'))
+
+import unittest_util # pylint: disable=F0401
+
+class TestInfo(object):
+  """An object containing and representing a test function, plus metadata."""
+
+  def __init__(self, runnable, set_up=None, tear_down=None):
+    # The actual test function/method.
+    self.runnable = runnable
+    # Qualified name of test function/method (e.g. FooModule.testBar).
+    self.qualified_name = self._GetQualifiedName(runnable)
+    # setUp and teardown functions, if any.
+    self.set_up = set_up
+    self.tear_down = tear_down
+
+  @staticmethod
+  def _GetQualifiedName(runnable):
+    """Helper method to infer a runnable's name and module name.
+
+    Many filters and lists presuppose a format of module_name.testMethodName.
+    To make this easy on everyone, we use some reflection magic to infer this
+    name automatically.
+
+    Args:
+      runnable: the test method to get the qualified name for
+
+    Returns:
+      qualified name for this runnable, incl. module name and method name.
+    """
+    runnable_name = runnable.__name__
+    # See also tests_annotations.
+    module_name = os.path.splitext(
+        os.path.basename(runnable.__globals__['__file__']))[0]
+    return '.'.join([module_name, runnable_name])
+
+  def __str__(self):
+    return self.qualified_name
+
+
+class TestInfoCollection(object):
+  """A collection of TestInfo objects which facilitates filtering."""
+
+  def __init__(self):
+    """Initialize a new TestInfoCollection."""
+    # Master list of all valid tests.
+    self.all_tests = []
+
+  def AddTests(self, test_infos):
+    """Adds a set of tests to this collection.
+
+    The user may then retrieve them, optionally according to criteria, via
+    GetAvailableTests().
+
+    Args:
+      test_infos: a list of TestInfos representing test functions/methods.
+    """
+    self.all_tests = test_infos
+
+  def GetAvailableTests(self, annotations, exclude_annotations, name_filter):
+    """Get a collection of TestInfos which match the supplied criteria.
+
+    Args:
+      annotations: List of annotations. Each test in the returned list is
+        annotated with atleast one of these annotations.
+      exclude_annotations: List of annotations. The tests in the returned
+        list are not annotated with any of these annotations.
+      name_filter: name filter which tests must match, if any
+
+    Returns:
+      List of available tests.
+    """
+    available_tests = self.all_tests
+
+    # Filter out tests which match neither the requested annotation, nor the
+    # requested name filter, if any.
+    available_tests = [t for t in available_tests if
+                       self._AnnotationIncludesTest(t, annotations)]
+    if annotations and len(annotations) == 1 and annotations[0] == 'SmallTest':
+      tests_without_annotation = [
+          t for t in self.all_tests if
+          not tests_annotations.AnnotatedFunctions.GetTestAnnotations(
+              t.qualified_name)]
+      test_names = [t.qualified_name for t in tests_without_annotation]
+      logging.warning('The following tests do not contain any annotation. '
+                      'Assuming "SmallTest":\n%s',
+                      '\n'.join(test_names))
+      available_tests += tests_without_annotation
+    if exclude_annotations:
+      excluded_tests = [t for t in available_tests if
+                        self._AnnotationIncludesTest(t, exclude_annotations)]
+      available_tests = list(set(available_tests) - set(excluded_tests))
+
+    if name_filter:
+      available_test_names = unittest_util.FilterTestNames(
+          [t.qualified_name for t in available_tests], name_filter)
+      available_tests = [
+          t for t in available_tests if
+          t.qualified_name in available_test_names]
+    return available_tests
+
+  @staticmethod
+  def _AnnotationIncludesTest(test_info, annotation_filter_list):
+    """Checks whether a given test represented by test_info matches annotation.
+
+    Args:
+      test_info: TestInfo object representing the test
+      annotation_filter_list: list of annotation filters to match (e.g. Smoke)
+
+    Returns:
+      True if no annotation was supplied or the test matches; false otherwise.
+    """
+    if not annotation_filter_list:
+      return True
+    for annotation_filter in annotation_filter_list:
+      filters = annotation_filter.split('=')
+      if len(filters) == 2:
+        key = filters[0]
+        value_list = filters[1].split(',')
+        for value in value_list:
+          if tests_annotations.AnnotatedFunctions.IsAnnotated(
+              key + ':' + value, test_info.qualified_name):
+            return True
+      elif tests_annotations.AnnotatedFunctions.IsAnnotated(
+          annotation_filter, test_info.qualified_name):
+        return True
+    return False
+
diff --git a/build/android/pylib/host_driven/test_runner.py b/build/android/pylib/host_driven/test_runner.py
new file mode 100644
index 0000000..8620aa1
--- /dev/null
+++ b/build/android/pylib/host_driven/test_runner.py
@@ -0,0 +1,133 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs host-driven tests on a particular device."""
+
+import logging
+import sys
+import time
+import traceback
+
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+from pylib.host_driven import test_case
+from pylib.instrumentation import test_result
+
+
+class HostDrivenExceptionTestResult(test_result.InstrumentationTestResult):
+  """Test result corresponding to a python exception in a host-driven test."""
+
+  def __init__(self, test_name, start_date_ms, exc_info):
+    """Constructs a HostDrivenExceptionTestResult object.
+
+    Args:
+      test_name: name of the test which raised an exception.
+      start_date_ms: the starting time for the test.
+      exc_info: exception info, ostensibly from sys.exc_info().
+    """
+    exc_type, exc_value, exc_traceback = exc_info
+    trace_info = ''.join(traceback.format_exception(exc_type, exc_value,
+                                                    exc_traceback))
+    log_msg = 'Exception:\n' + trace_info
+    duration_ms = (int(time.time()) * 1000) - start_date_ms
+
+    super(HostDrivenExceptionTestResult, self).__init__(
+        test_name,
+        base_test_result.ResultType.FAIL,
+        start_date_ms,
+        duration_ms,
+        log=str(exc_type) + ' ' + log_msg)
+
+
+class HostDrivenTestRunner(base_test_runner.BaseTestRunner):
+  """Orchestrates running a set of host-driven tests.
+
+  Any Python exceptions in the tests are caught and translated into a failed
+  result, rather than being re-raised on the main thread.
+  """
+
+  # TODO(jbudorick): Remove cleanup_test_files once it's no longer used.
+  # pylint: disable=unused-argument
+  #override
+  def __init__(self, device, shard_index, tool, cleanup_test_files=None):
+    """Creates a new HostDrivenTestRunner.
+
+    Args:
+      device: Attached android device.
+      shard_index: Shard index.
+      tool: Name of the Valgrind tool.
+      cleanup_test_files: Deprecated.
+    """
+
+    super(HostDrivenTestRunner, self).__init__(device, tool)
+
+    # The shard index affords the ability to create unique port numbers (e.g.
+    # DEFAULT_PORT + shard_index) if the test so wishes.
+    self.shard_index = shard_index
+
+  # pylint: enable=unused-argument
+
+  #override
+  def RunTest(self, test):
+    """Sets up and runs a test case.
+
+    Args:
+      test: An object which is ostensibly a subclass of HostDrivenTestCase.
+
+    Returns:
+      A TestRunResults object which contains the result produced by the test
+      and, in the case of a failure, the test that should be retried.
+    """
+
+    assert isinstance(test, test_case.HostDrivenTestCase)
+
+    start_date_ms = int(time.time()) * 1000
+    exception_raised = False
+
+    try:
+      test.SetUp(self.device, self.shard_index)
+    except Exception:
+      logging.exception(
+          'Caught exception while trying to run SetUp() for test: ' +
+          test.tagged_name)
+      # Tests whose SetUp() method has failed are likely to fail, or at least
+      # yield invalid results.
+      exc_info = sys.exc_info()
+      results = base_test_result.TestRunResults()
+      results.AddResult(HostDrivenExceptionTestResult(
+          test.tagged_name, start_date_ms, exc_info))
+      return results, test
+
+    try:
+      results = test.Run()
+    except Exception:
+      # Setting this lets TearDown() avoid stomping on our stack trace from
+      # Run() should TearDown() also raise an exception.
+      exception_raised = True
+      logging.exception('Caught exception while trying to run test: ' +
+                        test.tagged_name)
+      exc_info = sys.exc_info()
+      results = base_test_result.TestRunResults()
+      results.AddResult(HostDrivenExceptionTestResult(
+          test.tagged_name, start_date_ms, exc_info))
+
+    try:
+      test.TearDown()
+    except Exception:
+      logging.exception(
+          'Caught exception while trying run TearDown() for test: ' +
+          test.tagged_name)
+      if not exception_raised:
+        # Don't stomp the error during the test if TearDown blows up. This is a
+        # trade-off: if the test fails, this will mask any problem with TearDown
+        # until the test is fixed.
+        exc_info = sys.exc_info()
+        results = base_test_result.TestRunResults()
+        results.AddResult(HostDrivenExceptionTestResult(
+            test.tagged_name, start_date_ms, exc_info))
+
+    if not results.DidRunPass():
+      return results, test
+    else:
+      return results, None
diff --git a/build/android/pylib/host_driven/test_server.py b/build/android/pylib/host_driven/test_server.py
new file mode 100644
index 0000000..0783500
--- /dev/null
+++ b/build/android/pylib/host_driven/test_server.py
@@ -0,0 +1,130 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Host driven test server controller.
+
+This class controls the startup and shutdown of a python driven test server that
+runs in a separate process.
+
+The server starts up automatically when the object is created.
+
+After it starts up, it is possible to retreive the hostname it started on
+through accessing the member field |host| and the port name through |port|.
+
+For shutting down the server, call TearDown().
+"""
+
+import logging
+import subprocess
+import os
+import os.path
+import time
+import urllib2
+
+from pylib import constants
+
+# NOTE: when adding or modifying these lines, omit any leading slashes!
+# Otherwise os.path.join() will (correctly) treat them as absolute paths
+# instead of relative paths, and will do nothing.
+_PYTHONPATH_DIRS = [
+    'net/tools/testserver/',
+    'third_party/',
+    'third_party/pyftpdlib/src/',
+    'third_party/pywebsocket/src',
+    'third_party/tlslite/',
+]
+
+# Python files in these directories are generated as part of the build.
+# These dirs are located in out/(Debug|Release) directory.
+# The correct path is determined based on the build type. E.g. out/Debug for
+# debug builds and out/Release for release builds.
+_GENERATED_PYTHONPATH_DIRS = [
+    'pyproto/policy/proto/',
+    'pyproto/sync/protocol/',
+    'pyproto/'
+]
+
+_TEST_SERVER_HOST = '127.0.0.1'
+# Paths for supported test server executables.
+TEST_NET_SERVER_PATH = 'net/tools/testserver/testserver.py'
+TEST_SYNC_SERVER_PATH = 'sync/tools/testserver/sync_testserver.py'
+TEST_POLICY_SERVER_PATH = 'chrome/browser/policy/test/policy_testserver.py'
+# Parameters to check that the server is up and running.
+TEST_SERVER_CHECK_PARAMS = {
+  TEST_NET_SERVER_PATH: {
+      'url_path': '/',
+      'response': 'Default response given for path'
+  },
+  TEST_SYNC_SERVER_PATH: {
+      'url_path': 'chromiumsync/time',
+      'response': '0123456789'
+  },
+  TEST_POLICY_SERVER_PATH: {
+      'url_path': 'test/ping',
+      'response': 'Policy server is up.'
+  },
+}
+
+class TestServer(object):
+  """Sets up a host driven test server on the host machine.
+
+  For shutting down the server, call TearDown().
+  """
+
+  def __init__(self, shard_index, test_server_port, test_server_path,
+               test_server_flags=None):
+    """Sets up a Python driven test server on the host machine.
+
+    Args:
+      shard_index: Index of the current shard.
+      test_server_port: Port to run the test server on. This is multiplexed with
+                        the shard index. To retrieve the real port access the
+                        member variable |port|.
+      test_server_path: The path (relative to the root src dir) of the server
+      test_server_flags: Optional list of additional flags to the test server
+    """
+    self.host = _TEST_SERVER_HOST
+    self.port = test_server_port + shard_index
+
+    src_dir = constants.DIR_SOURCE_ROOT
+    # Make dirs into a list of absolute paths.
+    abs_dirs = [os.path.join(src_dir, d) for d in _PYTHONPATH_DIRS]
+    # Add the generated python files to the path
+    abs_dirs.extend([os.path.join(src_dir, constants.GetOutDirectory(), d)
+                     for d in _GENERATED_PYTHONPATH_DIRS])
+    current_python_path = os.environ.get('PYTHONPATH')
+    extra_python_path = ':'.join(abs_dirs)
+    if current_python_path:
+      python_path = current_python_path + ':' + extra_python_path
+    else:
+      python_path = extra_python_path
+
+    # NOTE: A separate python process is used to simplify getting the right
+    # system path for finding includes.
+    test_server_flags = test_server_flags or []
+    cmd = ['python', os.path.join(src_dir, test_server_path),
+           '--log-to-console',
+           ('--host=%s' % self.host),
+           ('--port=%d' % self.port),
+           '--on-remote-server'] + test_server_flags
+    self._test_server_process = subprocess.Popen(
+          cmd, env={'PYTHONPATH': python_path})
+    test_url = 'http://%s:%d/%s' % (self.host, self.port,
+        TEST_SERVER_CHECK_PARAMS[test_server_path]['url_path'])
+    expected_response = TEST_SERVER_CHECK_PARAMS[test_server_path]['response']
+    retries = 0
+    while retries < 5:
+      try:
+        d = urllib2.urlopen(test_url).read()
+        logging.info('URL %s GOT: %s' % (test_url, d))
+        if d.startswith(expected_response):
+          break
+      except Exception as e:
+        logging.info('URL %s GOT: %s' % (test_url, e))
+      time.sleep(retries * 0.1)
+      retries += 1
+
+  def TearDown(self):
+    self._test_server_process.kill()
+    self._test_server_process.wait()
diff --git a/build/android/pylib/host_driven/tests_annotations.py b/build/android/pylib/host_driven/tests_annotations.py
new file mode 100644
index 0000000..5331140
--- /dev/null
+++ b/build/android/pylib/host_driven/tests_annotations.py
@@ -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.
+
+"""Annotations for host-driven tests."""
+# pylint: disable=W0212
+
+import os
+
+
+class AnnotatedFunctions(object):
+  """A container for annotated methods."""
+  _ANNOTATED = {}
+
+  @staticmethod
+  def _AddFunction(annotation, function):
+    """Adds an annotated function to our container.
+
+    Args:
+      annotation: the annotation string.
+      function: the function.
+    Returns:
+      The function passed in.
+    """
+    module_name = os.path.splitext(os.path.basename(
+        function.__globals__['__file__']))[0]
+    qualified_function_name = '.'.join([module_name, function.func_name])
+    function_list = AnnotatedFunctions._ANNOTATED.get(annotation, [])
+    function_list.append(qualified_function_name)
+    AnnotatedFunctions._ANNOTATED[annotation] = function_list
+    return function
+
+  @staticmethod
+  def IsAnnotated(annotation, qualified_function_name):
+    """True if function name (module.function) contains the annotation.
+
+    Args:
+      annotation: the annotation string.
+      qualified_function_name: the qualified function name.
+    Returns:
+      True if module.function contains the annotation.
+    """
+    return qualified_function_name in AnnotatedFunctions._ANNOTATED.get(
+        annotation, [])
+
+  @staticmethod
+  def GetTestAnnotations(qualified_function_name):
+    """Returns a list containing all annotations for the given function.
+
+    Args:
+      qualified_function_name: the qualified function name.
+    Returns:
+      List of all annotations for this function.
+    """
+    return [annotation
+            for annotation, tests in AnnotatedFunctions._ANNOTATED.iteritems()
+            if qualified_function_name in tests]
+
+
+# The following functions are annotations used for the host-driven tests.
+def Smoke(function):
+  return AnnotatedFunctions._AddFunction('Smoke', function)
+
+
+def SmallTest(function):
+  return AnnotatedFunctions._AddFunction('SmallTest', function)
+
+
+def MediumTest(function):
+  return AnnotatedFunctions._AddFunction('MediumTest', function)
+
+
+def LargeTest(function):
+  return AnnotatedFunctions._AddFunction('LargeTest', function)
+
+
+def EnormousTest(function):
+  return AnnotatedFunctions._AddFunction('EnormousTest', function)
+
+
+def FlakyTest(function):
+  return AnnotatedFunctions._AddFunction('FlakyTest', function)
+
+
+def DisabledTest(function):
+  return AnnotatedFunctions._AddFunction('DisabledTest', function)
+
+
+def Feature(feature_list):
+  def _AddFeatures(function):
+    for feature in feature_list:
+      AnnotatedFunctions._AddFunction('Feature:%s' % feature, function)
+    return AnnotatedFunctions._AddFunction('Feature', function)
+  return _AddFeatures
diff --git a/build/android/pylib/instrumentation/__init__.py b/build/android/pylib/instrumentation/__init__.py
new file mode 100644
index 0000000..727e987
--- /dev/null
+++ b/build/android/pylib/instrumentation/__init__.py
@@ -0,0 +1,4 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/instrumentation/instrumentation_parser.py b/build/android/pylib/instrumentation/instrumentation_parser.py
new file mode 100644
index 0000000..1859f14
--- /dev/null
+++ b/build/android/pylib/instrumentation/instrumentation_parser.py
@@ -0,0 +1,96 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import re
+
+# http://developer.android.com/reference/android/test/InstrumentationTestRunner.html
+STATUS_CODE_START = 1
+STATUS_CODE_OK = 0
+STATUS_CODE_ERROR = -1
+STATUS_CODE_FAILURE = -2
+
+# http://developer.android.com/reference/android/app/Activity.html
+RESULT_CODE_OK = -1
+RESULT_CODE_CANCELED = 0
+
+_INSTR_LINE_RE = re.compile('^\s*INSTRUMENTATION_([A-Z_]+): (.*)$')
+
+
+class InstrumentationParser(object):
+
+  def __init__(self, stream):
+    """An incremental parser for the output of Android instrumentation tests.
+
+    Example:
+
+      stream = adb.IterShell('am instrument -r ...')
+      parser = InstrumentationParser(stream)
+
+      for code, bundle in parser.IterStatus():
+        # do something with each instrumentation status
+        print 'status:', code, bundle
+
+      # do something with the final instrumentation result
+      code, bundle = parser.GetResult()
+      print 'result:', code, bundle
+
+    Args:
+      stream: a sequence of lines as produced by the raw output of an
+        instrumentation test (e.g. by |am instrument -r| or |uiautomator|).
+    """
+    self._stream = stream
+    self._code = None
+    self._bundle = None
+
+  def IterStatus(self):
+    """Iterate over statuses as they are produced by the instrumentation test.
+
+    Yields:
+      A tuple (code, bundle) for each instrumentation status found in the
+      output.
+    """
+    def join_bundle_values(bundle):
+      for key in bundle:
+        bundle[key] = '\n'.join(bundle[key])
+      return bundle
+
+    bundle = {'STATUS': {}, 'RESULT': {}}
+    header = None
+    key = None
+    for line in self._stream:
+      m = _INSTR_LINE_RE.match(line)
+      if m:
+        header, value = m.groups()
+        key = None
+        if header in ['STATUS', 'RESULT'] and '=' in value:
+          key, value = value.split('=', 1)
+          bundle[header][key] = [value]
+        elif header == 'STATUS_CODE':
+          yield int(value), join_bundle_values(bundle['STATUS'])
+          bundle['STATUS'] = {}
+        elif header == 'CODE':
+          self._code = int(value)
+        else:
+          logging.warning('Unknown INSTRUMENTATION_%s line: %s', header, value)
+      elif key is not None:
+        bundle[header][key].append(line)
+
+    self._bundle = join_bundle_values(bundle['RESULT'])
+
+  def GetResult(self):
+    """Return the final instrumentation result.
+
+    Returns:
+      A pair (code, bundle) with the final instrumentation result. The |code|
+      may be None if no instrumentation result was found in the output.
+
+    Raises:
+      AssertionError if attempting to get the instrumentation result before
+      exhausting |IterStatus| first.
+    """
+    assert self._bundle is not None, (
+        'The IterStatus generator must be exhausted before reading the final'
+        ' instrumentation result.')
+    return self._code, self._bundle
diff --git a/build/android/pylib/instrumentation/instrumentation_parser_test.py b/build/android/pylib/instrumentation/instrumentation_parser_test.py
new file mode 100755
index 0000000..092d10f
--- /dev/null
+++ b/build/android/pylib/instrumentation/instrumentation_parser_test.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Unit tests for instrumentation.InstrumentationParser."""
+
+import unittest
+
+from pylib.instrumentation import instrumentation_parser
+
+
+class InstrumentationParserTest(unittest.TestCase):
+
+  def testInstrumentationParser_nothing(self):
+    parser = instrumentation_parser.InstrumentationParser([''])
+    statuses = list(parser.IterStatus())
+    code, bundle = parser.GetResult()
+    self.assertEqual(None, code)
+    self.assertEqual({}, bundle)
+    self.assertEqual([], statuses)
+
+  def testInstrumentationParser_noMatchingStarts(self):
+    raw_output = [
+      '',
+      'this.is.a.test.package.TestClass:.',
+      'Test result for =.',
+      'Time: 1.234',
+      '',
+      'OK (1 test)',
+    ]
+
+    parser = instrumentation_parser.InstrumentationParser(raw_output)
+    statuses = list(parser.IterStatus())
+    code, bundle = parser.GetResult()
+    self.assertEqual(None, code)
+    self.assertEqual({}, bundle)
+    self.assertEqual([], statuses)
+
+  def testInstrumentationParser_resultAndCode(self):
+    raw_output = [
+      'INSTRUMENTATION_RESULT: shortMsg=foo bar',
+      'INSTRUMENTATION_RESULT: longMsg=a foo',
+      'walked into',
+      'a bar',
+      'INSTRUMENTATION_CODE: -1',
+    ]
+
+    parser = instrumentation_parser.InstrumentationParser(raw_output)
+    statuses = list(parser.IterStatus())
+    code, bundle = parser.GetResult()
+    self.assertEqual(-1, code)
+    self.assertEqual(
+        {'shortMsg': 'foo bar', 'longMsg': 'a foo\nwalked into\na bar'}, bundle)
+    self.assertEqual([], statuses)
+
+  def testInstrumentationParser_oneStatus(self):
+    raw_output = [
+      'INSTRUMENTATION_STATUS: foo=1',
+      'INSTRUMENTATION_STATUS: bar=hello',
+      'INSTRUMENTATION_STATUS: world=false',
+      'INSTRUMENTATION_STATUS: class=this.is.a.test.package.TestClass',
+      'INSTRUMENTATION_STATUS: test=testMethod',
+      'INSTRUMENTATION_STATUS_CODE: 0',
+    ]
+
+    parser = instrumentation_parser.InstrumentationParser(raw_output)
+    statuses = list(parser.IterStatus())
+
+    expected = [
+      (0, {
+        'foo': '1',
+        'bar': 'hello',
+        'world': 'false',
+        'class': 'this.is.a.test.package.TestClass',
+        'test': 'testMethod',
+      })
+    ]
+    self.assertEqual(expected, statuses)
+
+  def testInstrumentationParser_multiStatus(self):
+    raw_output = [
+      'INSTRUMENTATION_STATUS: class=foo',
+      'INSTRUMENTATION_STATUS: test=bar',
+      'INSTRUMENTATION_STATUS_CODE: 1',
+      'INSTRUMENTATION_STATUS: test_skipped=true',
+      'INSTRUMENTATION_STATUS_CODE: 0',
+      'INSTRUMENTATION_STATUS: class=hello',
+      'INSTRUMENTATION_STATUS: test=world',
+      'INSTRUMENTATION_STATUS: stack=',
+      'foo/bar.py (27)',
+      'hello/world.py (42)',
+      'test/file.py (1)',
+      'INSTRUMENTATION_STATUS_CODE: -1',
+    ]
+
+    parser = instrumentation_parser.InstrumentationParser(raw_output)
+    statuses = list(parser.IterStatus())
+
+    expected = [
+      (1, {'class': 'foo', 'test': 'bar',}),
+      (0, {'test_skipped': 'true'}),
+      (-1, {
+        'class': 'hello',
+        'test': 'world',
+        'stack': '\nfoo/bar.py (27)\nhello/world.py (42)\ntest/file.py (1)',
+      }),
+    ]
+    self.assertEqual(expected, statuses)
+
+  def testInstrumentationParser_statusResultAndCode(self):
+    raw_output = [
+      'INSTRUMENTATION_STATUS: class=foo',
+      'INSTRUMENTATION_STATUS: test=bar',
+      'INSTRUMENTATION_STATUS_CODE: 1',
+      'INSTRUMENTATION_RESULT: result=hello',
+      'world',
+      '',
+      '',
+      'INSTRUMENTATION_CODE: 0',
+    ]
+
+    parser = instrumentation_parser.InstrumentationParser(raw_output)
+    statuses = list(parser.IterStatus())
+    code, bundle = parser.GetResult()
+
+    self.assertEqual(0, code)
+    self.assertEqual({'result': 'hello\nworld\n\n'}, bundle)
+    self.assertEqual([(1, {'class': 'foo', 'test': 'bar'})], statuses)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
new file mode 100644
index 0000000..0633f14
--- /dev/null
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -0,0 +1,525 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import pickle
+import re
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib import flag_changer
+from pylib.base import base_test_result
+from pylib.base import test_instance
+from pylib.instrumentation import test_result
+from pylib.instrumentation import instrumentation_parser
+from pylib.utils import apk_helper
+from pylib.utils import md5sum
+from pylib.utils import proguard
+
+sys.path.append(
+    os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', 'common'))
+import unittest_util
+
+# Ref: http://developer.android.com/reference/android/app/Activity.html
+_ACTIVITY_RESULT_CANCELED = 0
+_ACTIVITY_RESULT_OK = -1
+
+_DEFAULT_ANNOTATIONS = [
+    'Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
+    'EnormousTest', 'IntegrationTest']
+_EXTRA_ENABLE_HTTP_SERVER = (
+    'org.chromium.chrome.test.ChromeInstrumentationTestRunner.'
+        + 'EnableTestHttpServer')
+_EXTRA_DRIVER_TEST_LIST = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList')
+_EXTRA_DRIVER_TEST_LIST_FILE = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile')
+_EXTRA_DRIVER_TARGET_PACKAGE = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage')
+_EXTRA_DRIVER_TARGET_CLASS = (
+    'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass')
+_NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE)
+_PICKLE_FORMAT_VERSION = 10
+
+
+# TODO(jbudorick): Make these private class methods of
+# InstrumentationTestInstance once the instrumentation test_runner is
+# deprecated.
+def ParseAmInstrumentRawOutput(raw_output):
+  """Parses the output of an |am instrument -r| call.
+
+  Args:
+    raw_output: the output of an |am instrument -r| call as a list of lines
+  Returns:
+    A 3-tuple containing:
+      - the instrumentation code as an integer
+      - the instrumentation result as a list of lines
+      - the instrumentation statuses received as a list of 2-tuples
+        containing:
+        - the status code as an integer
+        - the bundle dump as a dict mapping string keys to a list of
+          strings, one for each line.
+  """
+  parser = instrumentation_parser.InstrumentationParser(raw_output)
+  statuses = list(parser.IterStatus())
+  code, bundle = parser.GetResult()
+  return (code, bundle, statuses)
+
+
+def GenerateTestResults(
+    result_code, result_bundle, statuses, start_ms, duration_ms):
+  """Generate test results from |statuses|.
+
+  Args:
+    result_code: The overall status code as an integer.
+    result_bundle: The summary bundle dump as a dict.
+    statuses: A list of 2-tuples containing:
+      - the status code as an integer
+      - the bundle dump as a dict mapping string keys to string values
+      Note that this is the same as the third item in the 3-tuple returned by
+      |_ParseAmInstrumentRawOutput|.
+    start_ms: The start time of the test in milliseconds.
+    duration_ms: The duration of the test in milliseconds.
+
+  Returns:
+    A list containing an instance of InstrumentationTestResult for each test
+    parsed.
+  """
+
+  results = []
+
+  current_result = None
+
+  for status_code, bundle in statuses:
+    test_class = bundle.get('class', '')
+    test_method = bundle.get('test', '')
+    if test_class and test_method:
+      test_name = '%s#%s' % (test_class, test_method)
+    else:
+      continue
+
+    if status_code == instrumentation_parser.STATUS_CODE_START:
+      if current_result:
+        results.append(current_result)
+      current_result = test_result.InstrumentationTestResult(
+          test_name, base_test_result.ResultType.UNKNOWN, start_ms, duration_ms)
+    else:
+      if status_code == instrumentation_parser.STATUS_CODE_OK:
+        if bundle.get('test_skipped', '').lower() in ('true', '1', 'yes'):
+          current_result.SetType(base_test_result.ResultType.SKIP)
+        elif current_result.GetType() == base_test_result.ResultType.UNKNOWN:
+          current_result.SetType(base_test_result.ResultType.PASS)
+      else:
+        if status_code not in (instrumentation_parser.STATUS_CODE_ERROR,
+                               instrumentation_parser.STATUS_CODE_FAILURE):
+          logging.error('Unrecognized status code %d. Handling as an error.',
+                        status_code)
+        current_result.SetType(base_test_result.ResultType.FAIL)
+        if 'stack' in bundle:
+          current_result.SetLog(bundle['stack'])
+
+  if current_result:
+    if current_result.GetType() == base_test_result.ResultType.UNKNOWN:
+      crashed = (result_code == _ACTIVITY_RESULT_CANCELED
+                 and any(_NATIVE_CRASH_RE.search(l)
+                         for l in result_bundle.itervalues()))
+      if crashed:
+        current_result.SetType(base_test_result.ResultType.CRASH)
+
+    results.append(current_result)
+
+  return results
+
+
+class InstrumentationTestInstance(test_instance.TestInstance):
+
+  def __init__(self, args, isolate_delegate, error_func):
+    super(InstrumentationTestInstance, self).__init__()
+
+    self._apk_under_test = None
+    self._package_info = None
+    self._suite = None
+    self._test_apk = None
+    self._test_jar = None
+    self._test_package = None
+    self._test_runner = None
+    self._test_support_apk = None
+    self._initializeApkAttributes(args, error_func)
+
+    self._data_deps = None
+    self._isolate_abs_path = None
+    self._isolate_delegate = None
+    self._isolated_abs_path = None
+    self._test_data = None
+    self._initializeDataDependencyAttributes(args, isolate_delegate)
+
+    self._annotations = None
+    self._excluded_annotations = None
+    self._test_filter = None
+    self._initializeTestFilterAttributes(args)
+
+    self._flags = None
+    self._initializeFlagAttributes(args)
+
+    self._driver_apk = None
+    self._driver_package = None
+    self._driver_name = None
+    self._initializeDriverAttributes()
+
+  def _initializeApkAttributes(self, args, error_func):
+    if args.apk_under_test.endswith('.apk'):
+      self._apk_under_test = args.apk_under_test
+    else:
+      self._apk_under_test = os.path.join(
+          constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
+          '%s.apk' % args.apk_under_test)
+
+    if not os.path.exists(self._apk_under_test):
+      error_func('Unable to find APK under test: %s' % self._apk_under_test)
+
+    if args.test_apk.endswith('.apk'):
+      self._suite = os.path.splitext(os.path.basename(args.test_apk))[0]
+      self._test_apk = args.test_apk
+    else:
+      self._suite = args.test_apk
+      self._test_apk = os.path.join(
+          constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
+          '%s.apk' % args.test_apk)
+
+    self._test_jar = os.path.join(
+        constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR,
+        '%s.jar' % self._suite)
+    self._test_support_apk = os.path.join(
+        constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR,
+        '%sSupport.apk' % self._suite)
+
+    if not os.path.exists(self._test_apk):
+      error_func('Unable to find test APK: %s' % self._test_apk)
+    if not os.path.exists(self._test_jar):
+      error_func('Unable to find test JAR: %s' % self._test_jar)
+
+    self._test_package = apk_helper.GetPackageName(self.test_apk)
+    self._test_runner = apk_helper.GetInstrumentationName(self.test_apk)
+
+    self._package_info = None
+    for package_info in constants.PACKAGE_INFO.itervalues():
+      if self._test_package == package_info.test_package:
+        self._package_info = package_info
+    if not self._package_info:
+      logging.warning('Unable to find package info for %s', self._test_package)
+
+  def _initializeDataDependencyAttributes(self, args, isolate_delegate):
+    self._data_deps = []
+    if args.isolate_file_path:
+      self._isolate_abs_path = os.path.abspath(args.isolate_file_path)
+      self._isolate_delegate = isolate_delegate
+      self._isolated_abs_path = os.path.join(
+          constants.GetOutDirectory(), '%s.isolated' % self._test_package)
+    else:
+      self._isolate_delegate = None
+
+    # TODO(jbudorick): Deprecate and remove --test-data once data dependencies
+    # are fully converted to isolate.
+    if args.test_data:
+      logging.info('Data dependencies specified via --test-data')
+      self._test_data = args.test_data
+    else:
+      self._test_data = None
+
+    if not self._isolate_delegate and not self._test_data:
+      logging.warning('No data dependencies will be pushed.')
+
+  def _initializeTestFilterAttributes(self, args):
+    self._test_filter = args.test_filter
+
+    def annotation_dict_element(a):
+      a = a.split('=')
+      return (a[0], a[1] if len(a) == 2 else None)
+
+    if args.annotation_str:
+      self._annotations = dict(
+          annotation_dict_element(a)
+          for a in args.annotation_str.split(','))
+    elif not self._test_filter:
+      self._annotations = dict(
+          annotation_dict_element(a)
+          for a in _DEFAULT_ANNOTATIONS)
+    else:
+      self._annotations = {}
+
+    if args.exclude_annotation_str:
+      self._excluded_annotations = dict(
+          annotation_dict_element(a)
+          for a in args.exclude_annotation_str.split(','))
+    else:
+      self._excluded_annotations = {}
+
+  def _initializeFlagAttributes(self, args):
+    self._flags = ['--disable-fre', '--enable-test-intents']
+    # TODO(jbudorick): Transition "--device-flags" to "--device-flags-file"
+    if hasattr(args, 'device_flags') and args.device_flags:
+      with open(args.device_flags) as device_flags_file:
+        stripped_lines = (l.strip() for l in device_flags_file)
+        self._flags.extend([flag for flag in stripped_lines if flag])
+    if hasattr(args, 'device_flags_file') and args.device_flags_file:
+      with open(args.device_flags_file) as device_flags_file:
+        stripped_lines = (l.strip() for l in device_flags_file)
+        self._flags.extend([flag for flag in stripped_lines if flag])
+
+  def _initializeDriverAttributes(self):
+    self._driver_apk = os.path.join(
+        constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR,
+        'OnDeviceInstrumentationDriver.apk')
+    if os.path.exists(self._driver_apk):
+      self._driver_package = apk_helper.GetPackageName(
+          self._driver_apk)
+      self._driver_name = apk_helper.GetInstrumentationName(
+          self._driver_apk)
+    else:
+      self._driver_apk = None
+
+  @property
+  def apk_under_test(self):
+    return self._apk_under_test
+
+  @property
+  def flags(self):
+    return self._flags
+
+  @property
+  def driver_apk(self):
+    return self._driver_apk
+
+  @property
+  def driver_package(self):
+    return self._driver_package
+
+  @property
+  def driver_name(self):
+    return self._driver_name
+
+  @property
+  def package_info(self):
+    return self._package_info
+
+  @property
+  def suite(self):
+    return self._suite
+
+  @property
+  def test_apk(self):
+    return self._test_apk
+
+  @property
+  def test_jar(self):
+    return self._test_jar
+
+  @property
+  def test_support_apk(self):
+    return self._test_support_apk
+
+  @property
+  def test_package(self):
+    return self._test_package
+
+  @property
+  def test_runner(self):
+    return self._test_runner
+
+  #override
+  def TestType(self):
+    return 'instrumentation'
+
+  #override
+  def SetUp(self):
+    if self._isolate_delegate:
+      self._isolate_delegate.Remap(
+          self._isolate_abs_path, self._isolated_abs_path)
+      self._isolate_delegate.MoveOutputDeps()
+      self._data_deps.extend([(constants.ISOLATE_DEPS_DIR, None)])
+
+    # TODO(jbudorick): Convert existing tests that depend on the --test-data
+    # mechanism to isolate, then remove this.
+    if self._test_data:
+      for t in self._test_data:
+        device_rel_path, host_rel_path = t.split(':')
+        host_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, host_rel_path)
+        self._data_deps.extend(
+            [(host_abs_path,
+              [None, 'chrome', 'test', 'data', device_rel_path])])
+
+  def GetDataDependencies(self):
+    return self._data_deps
+
+  def GetTests(self):
+    pickle_path = '%s-proguard.pickle' % self.test_jar
+    try:
+      tests = self._GetTestsFromPickle(pickle_path, self.test_jar)
+    except self.ProguardPickleException as e:
+      logging.info('Getting tests from JAR via proguard. (%s)' % str(e))
+      tests = self._GetTestsFromProguard(self.test_jar)
+      self._SaveTestsToPickle(pickle_path, self.test_jar, tests)
+    return self._InflateTests(self._FilterTests(tests))
+
+  class ProguardPickleException(Exception):
+    pass
+
+  def _GetTestsFromPickle(self, pickle_path, jar_path):
+    if not os.path.exists(pickle_path):
+      raise self.ProguardPickleException('%s does not exist.' % pickle_path)
+    if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path):
+      raise self.ProguardPickleException(
+          '%s newer than %s.' % (jar_path, pickle_path))
+
+    with open(pickle_path, 'r') as pickle_file:
+      pickle_data = pickle.loads(pickle_file.read())
+    jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
+
+    try:
+      if pickle_data['VERSION'] != _PICKLE_FORMAT_VERSION:
+        raise self.ProguardPickleException('PICKLE_FORMAT_VERSION has changed.')
+      if pickle_data['JAR_MD5SUM'] != jar_md5:
+        raise self.ProguardPickleException('JAR file MD5 sum differs.')
+      return pickle_data['TEST_METHODS']
+    except TypeError as e:
+      logging.error(pickle_data)
+      raise self.ProguardPickleException(str(e))
+
+  def _GetTestsFromProguard(self, jar_path):
+    p = proguard.Dump(jar_path)
+
+    def is_test_class(c):
+      return c['class'].endswith('Test')
+
+    def is_test_method(m):
+      return m['method'].startswith('test')
+
+    class_lookup = dict((c['class'], c) for c in p['classes'])
+    def recursive_get_class_annotations(c):
+      s = c['superclass']
+      if s in class_lookup:
+        a = recursive_get_class_annotations(class_lookup[s])
+      else:
+        a = {}
+      a.update(c['annotations'])
+      return a
+
+    def stripped_test_class(c):
+      return {
+        'class': c['class'],
+        'annotations': recursive_get_class_annotations(c),
+        'methods': [m for m in c['methods'] if is_test_method(m)],
+      }
+
+    return [stripped_test_class(c) for c in p['classes']
+            if is_test_class(c)]
+
+  def _SaveTestsToPickle(self, pickle_path, jar_path, tests):
+    jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
+    pickle_data = {
+      'VERSION': _PICKLE_FORMAT_VERSION,
+      'JAR_MD5SUM': jar_md5,
+      'TEST_METHODS': tests,
+    }
+    with open(pickle_path, 'w') as pickle_file:
+      pickle.dump(pickle_data, pickle_file)
+
+  def _FilterTests(self, tests):
+
+    def gtest_filter(c, m):
+      t = ['%s.%s' % (c['class'].split('.')[-1], m['method'])]
+      return (not self._test_filter
+              or unittest_util.FilterTestNames(t, self._test_filter))
+
+    def annotation_filter(all_annotations):
+      if not self._annotations:
+        return True
+      return any_annotation_matches(self._annotations, all_annotations)
+
+    def excluded_annotation_filter(all_annotations):
+      if not self._excluded_annotations:
+        return True
+      return not any_annotation_matches(self._excluded_annotations,
+                                        all_annotations)
+
+    def any_annotation_matches(annotations, all_annotations):
+      return any(
+          ak in all_annotations and (av is None or av == all_annotations[ak])
+          for ak, av in annotations.iteritems())
+
+    filtered_classes = []
+    for c in tests:
+      filtered_methods = []
+      for m in c['methods']:
+        # Gtest filtering
+        if not gtest_filter(c, m):
+          continue
+
+        all_annotations = dict(c['annotations'])
+        all_annotations.update(m['annotations'])
+        if (not annotation_filter(all_annotations)
+            or not excluded_annotation_filter(all_annotations)):
+          continue
+
+        filtered_methods.append(m)
+
+      if filtered_methods:
+        filtered_class = dict(c)
+        filtered_class['methods'] = filtered_methods
+        filtered_classes.append(filtered_class)
+
+    return filtered_classes
+
+  def _InflateTests(self, tests):
+    inflated_tests = []
+    for c in tests:
+      for m in c['methods']:
+        a = dict(c['annotations'])
+        a.update(m['annotations'])
+        inflated_tests.append({
+            'class': c['class'],
+            'method': m['method'],
+            'annotations': a,
+        })
+    return inflated_tests
+
+  @staticmethod
+  def GetHttpServerEnvironmentVars():
+    return {
+      _EXTRA_ENABLE_HTTP_SERVER: None,
+    }
+
+  def GetDriverEnvironmentVars(
+      self, test_list=None, test_list_file_path=None):
+    env = {
+      _EXTRA_DRIVER_TARGET_PACKAGE: self.test_package,
+      _EXTRA_DRIVER_TARGET_CLASS: self.test_runner,
+    }
+
+    if test_list:
+      env[_EXTRA_DRIVER_TEST_LIST] = ','.join(test_list)
+
+    if test_list_file_path:
+      env[_EXTRA_DRIVER_TEST_LIST_FILE] = (
+          os.path.basename(test_list_file_path))
+
+    return env
+
+  @staticmethod
+  def ParseAmInstrumentRawOutput(raw_output):
+    return ParseAmInstrumentRawOutput(raw_output)
+
+  @staticmethod
+  def GenerateTestResults(
+      result_code, result_bundle, statuses, start_ms, duration_ms):
+    return GenerateTestResults(result_code, result_bundle, statuses,
+                               start_ms, duration_ms)
+
+  #override
+  def TearDown(self):
+    if self._isolate_delegate:
+      self._isolate_delegate.Clear()
+
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
new file mode 100755
index 0000000..752e4d3
--- /dev/null
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Unit tests for instrumentation.TestRunner."""
+
+# pylint: disable=W0212
+
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.instrumentation import instrumentation_test_instance
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock  # pylint: disable=F0401
+
+
+class InstrumentationTestInstanceTest(unittest.TestCase):
+
+  def setUp(self):
+    options = mock.Mock()
+    options.tool = ''
+
+  def testGenerateTestResults_noStatus(self):
+    results = instrumentation_test_instance.GenerateTestResults(
+        None, None, [], 0, 1000)
+    self.assertEqual([], results)
+
+  def testGenerateTestResults_testPassed(self):
+    statuses = [
+      (1, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+      (0, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+    ]
+    results = instrumentation_test_instance.GenerateTestResults(
+        None, None, statuses, 0, 1000)
+    self.assertEqual(1, len(results))
+    self.assertEqual(base_test_result.ResultType.PASS, results[0].GetType())
+
+  def testGenerateTestResults_testSkipped_true(self):
+    statuses = [
+      (1, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+      (0, {
+        'test_skipped': 'true',
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+      (0, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+    ]
+    results = instrumentation_test_instance.GenerateTestResults(
+        None, None, statuses, 0, 1000)
+    self.assertEqual(1, len(results))
+    self.assertEqual(base_test_result.ResultType.SKIP, results[0].GetType())
+
+  def testGenerateTestResults_testSkipped_false(self):
+    statuses = [
+      (1, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+      (0, {
+        'test_skipped': 'false',
+      }),
+      (0, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+    ]
+    results = instrumentation_test_instance.GenerateTestResults(
+        None, None, statuses, 0, 1000)
+    self.assertEqual(1, len(results))
+    self.assertEqual(base_test_result.ResultType.PASS, results[0].GetType())
+
+  def testGenerateTestResults_testFailed(self):
+    statuses = [
+      (1, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+      (-2, {
+        'class': 'test.package.TestClass',
+        'test': 'testMethod',
+      }),
+    ]
+    results = instrumentation_test_instance.GenerateTestResults(
+        None, None, statuses, 0, 1000)
+    self.assertEqual(1, len(results))
+    self.assertEqual(base_test_result.ResultType.FAIL, results[0].GetType())
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/build/android/pylib/instrumentation/json_perf_parser.py b/build/android/pylib/instrumentation/json_perf_parser.py
new file mode 100644
index 0000000..ffdfbe7
--- /dev/null
+++ b/build/android/pylib/instrumentation/json_perf_parser.py
@@ -0,0 +1,161 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""A helper module for parsing JSON objects from perf tests results."""
+
+import json
+
+
+def GetAverageRunInfo(json_data, name):
+  """Summarizes TraceEvent JSON data for performance metrics.
+
+  Example JSON Inputs (More tags can be added but these are required):
+  Measuring Duration:
+  [
+    { "cat": "Java",
+      "ts": 10000000000,
+      "ph": "S",
+      "name": "TestTrace"
+    },
+    { "cat": "Java",
+      "ts": 10000004000,
+      "ph": "F",
+      "name": "TestTrace"
+    },
+    ...
+  ]
+
+  Measuring Call Frequency (FPS):
+  [
+    { "cat": "Java",
+      "ts": 10000000000,
+      "ph": "I",
+      "name": "TestTraceFPS"
+    },
+    { "cat": "Java",
+      "ts": 10000004000,
+      "ph": "I",
+      "name": "TestTraceFPS"
+    },
+    ...
+  ]
+
+  Args:
+    json_data: A list of dictonaries each representing a JSON object.
+    name: The 'name' tag to filter on in the JSON file.
+
+  Returns:
+    A dictionary of result data with the following tags:
+      min: The minimum value tracked.
+      max: The maximum value tracked.
+      average: The average of all the values tracked.
+      count: The number of times the category/name pair was tracked.
+      type: The type of tracking ('Instant' for instant tags and 'Span' for
+            begin/end tags.
+      category: The passed in category filter.
+      name: The passed in name filter.
+      data_points: A list of all of the times used to generate this data.
+      units: The units for the values being reported.
+
+  Raises:
+    Exception: if entry contains invalid data.
+  """
+
+  def EntryFilter(entry):
+    return entry['cat'] == 'Java' and entry['name'] == name
+  filtered_entries = filter(EntryFilter, json_data)
+
+  result = {}
+
+  result['min'] = -1
+  result['max'] = -1
+  result['average'] = 0
+  result['count'] = 0
+  result['type'] = 'Unknown'
+  result['category'] = 'Java'
+  result['name'] = name
+  result['data_points'] = []
+  result['units'] = ''
+
+  total_sum = 0
+
+  last_val = 0
+  val_type = None
+  for entry in filtered_entries:
+    if not val_type:
+      if 'mem' in entry:
+        val_type = 'mem'
+
+        def GetVal(entry):
+          return entry['mem']
+
+        result['units'] = 'kb'
+      elif 'ts' in entry:
+        val_type = 'ts'
+
+        def GetVal(entry):
+          return float(entry['ts']) / 1000.0
+
+        result['units'] = 'ms'
+      else:
+        raise Exception('Entry did not contain valid value info: %s' % entry)
+
+    if not val_type in entry:
+      raise Exception('Entry did not contain expected value type "%s" '
+                      'information: %s' % (val_type, entry))
+    val = GetVal(entry)
+    if (entry['ph'] == 'S' and
+        (result['type'] == 'Unknown' or result['type'] == 'Span')):
+      result['type'] = 'Span'
+      last_val = val
+    elif ((entry['ph'] == 'F' and result['type'] == 'Span') or
+          (entry['ph'] == 'I' and (result['type'] == 'Unknown' or
+                                   result['type'] == 'Instant'))):
+      if last_val > 0:
+        delta = val - last_val
+        if result['min'] == -1 or result['min'] > delta:
+          result['min'] = delta
+        if result['max'] == -1 or result['max'] < delta:
+          result['max'] = delta
+        total_sum += delta
+        result['count'] += 1
+        result['data_points'].append(delta)
+      if entry['ph'] == 'I':
+        result['type'] = 'Instant'
+        last_val = val
+  if result['count'] > 0:
+    result['average'] = total_sum / result['count']
+
+  return result
+
+
+def GetAverageRunInfoFromJSONString(json_string, name):
+  """Returns the results from GetAverageRunInfo using a JSON string.
+
+  Args:
+    json_string: The string containing JSON.
+    name: The 'name' tag to filter on in the JSON file.
+
+  Returns:
+    See GetAverageRunInfo Returns section.
+  """
+  return GetAverageRunInfo(json.loads(json_string), name)
+
+
+def GetAverageRunInfoFromFile(json_file, name):
+  """Returns the results from GetAverageRunInfo using a JSON file.
+
+  Args:
+    json_file: The path to a JSON file.
+    name: The 'name' tag to filter on in the JSON file.
+
+  Returns:
+    See GetAverageRunInfo Returns section.
+  """
+  with open(json_file, 'r') as f:
+    data = f.read()
+    perf = json.loads(data)
+
+  return GetAverageRunInfo(perf, name)
diff --git a/build/android/pylib/instrumentation/setup.py b/build/android/pylib/instrumentation/setup.py
new file mode 100644
index 0000000..bdde80d
--- /dev/null
+++ b/build/android/pylib/instrumentation/setup.py
@@ -0,0 +1,111 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates test runner factory and tests for instrumentation tests."""
+
+import logging
+import os
+
+from pylib import constants
+from pylib import valgrind_tools
+
+from pylib.base import base_setup
+from pylib.device import device_utils
+from pylib.instrumentation import test_package
+from pylib.instrumentation import test_runner
+
+DEVICE_DATA_DIR = 'chrome/test/data'
+
+ISOLATE_FILE_PATHS = {
+    'AndroidWebViewTest': 'android_webview/android_webview_test_apk.isolate',
+    'ChromeShellTest': 'chrome/chrome_shell_test_apk.isolate',
+    'ContentShellTest': 'content/content_shell_test_apk.isolate',
+}
+
+DEPS_EXCLUSION_LIST = []
+
+# TODO(mikecase): Remove this function and the constant DEVICE_DATA_DIR
+# once all data deps are pushed to the same location on the device.
+def _PushExtraSuiteDataDeps(device, test_apk):
+  """Pushes some extra data files/dirs needed by some test suite.
+
+  Args:
+    test_apk: The test suite basename for which to return file paths.
+  """
+  if test_apk in ['ChromeTest', 'ContentShellTest']:
+    test_files = 'net/data/ssl/certificates'
+    host_device_file_tuple = [
+        (os.path.join(constants.DIR_SOURCE_ROOT, test_files),
+         os.path.join(device.GetExternalStoragePath(), test_files))]
+    device.PushChangedFiles(host_device_file_tuple)
+
+
+# TODO(mikecase): Remove this function once everything uses
+# base_setup.PushDataDeps to push data deps to the device.
+def _PushDataDeps(device, test_options):
+  valgrind_tools.PushFilesForTool(test_options.tool, device)
+
+  host_device_file_tuples = []
+  for dest_host_pair in test_options.test_data:
+    dst_src = dest_host_pair.split(':', 1)
+    dst_layer = dst_src[0]
+    host_src = dst_src[1]
+    host_test_files_path = os.path.join(constants.DIR_SOURCE_ROOT, host_src)
+    if os.path.exists(host_test_files_path):
+      host_device_file_tuples += [(
+          host_test_files_path,
+          '%s/%s/%s' % (
+              device.GetExternalStoragePath(),
+              DEVICE_DATA_DIR,
+              dst_layer))]
+  if host_device_file_tuples:
+    device.PushChangedFiles(host_device_file_tuples)
+
+
+def Setup(test_options, devices):
+  """Create and return the test runner factory and tests.
+
+  Args:
+    test_options: An InstrumentationOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  if (test_options.coverage_dir and not
+      os.path.exists(test_options.coverage_dir)):
+    os.makedirs(test_options.coverage_dir)
+
+  test_pkg = test_package.TestPackage(test_options.test_apk_path,
+                                      test_options.test_apk_jar_path,
+                                      test_options.test_support_apk_path)
+  tests = test_pkg.GetAllMatchingTests(
+      test_options.annotations,
+      test_options.exclude_annotations,
+      test_options.test_filter)
+  if not tests:
+    logging.error('No instrumentation tests to run with current args.')
+
+  if test_options.test_data:
+    device_utils.DeviceUtils.parallel(devices).pMap(
+        _PushDataDeps, test_options)
+
+  if test_options.isolate_file_path:
+    base_setup.GenerateDepsDirUsingIsolate(test_options.test_apk,
+                                           test_options.isolate_file_path,
+                                           ISOLATE_FILE_PATHS,
+                                           DEPS_EXCLUSION_LIST)
+    def push_data_deps_to_device_dir(device):
+      base_setup.PushDataDeps(device, device.GetExternalStoragePath(),
+                              test_options)
+    device_utils.DeviceUtils.parallel(devices).pMap(
+        push_data_deps_to_device_dir)
+
+  device_utils.DeviceUtils.parallel(devices).pMap(
+      _PushExtraSuiteDataDeps, test_options.test_apk)
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.TestRunner(test_options, device, shard_index,
+                                  test_pkg)
+
+  return (TestRunnerFactory, tests)
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
new file mode 100644
index 0000000..9c38510
--- /dev/null
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -0,0 +1,228 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper class for instrumenation test jar."""
+# pylint: disable=W0702
+
+import logging
+import os
+import pickle
+import re
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.device import device_utils
+from pylib.utils import md5sum
+from pylib.utils import proguard
+
+sys.path.insert(0,
+                os.path.join(constants.DIR_SOURCE_ROOT,
+                             'build', 'util', 'lib', 'common'))
+
+import unittest_util # pylint: disable=F0401
+
+# If you change the cached output of proguard, increment this number
+PICKLE_FORMAT_VERSION = 4
+
+
+class TestJar(object):
+  _ANNOTATIONS = frozenset(
+      ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest', 'EnormousTest',
+       'FlakyTest', 'DisabledTest', 'Manual', 'PerfTest', 'HostDrivenTest',
+       'IntegrationTest'])
+  _DEFAULT_ANNOTATION = 'SmallTest'
+  _PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$')
+  _PROGUARD_SUPERCLASS_RE = re.compile(r'\s*?  Superclass:\s*([\S]+)$')
+  _PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$')
+  _PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$')
+  _PROGUARD_ANNOTATION_CONST_RE = (
+      re.compile(r'\s*?- Constant element value.*$'))
+  _PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$')
+
+  def __init__(self, jar_path):
+    if not os.path.exists(jar_path):
+      raise Exception('%s not found, please build it' % jar_path)
+
+    self._PROGUARD_PATH = os.path.join(constants.ANDROID_SDK_ROOT,
+                                       'tools/proguard/lib/proguard.jar')
+    if not os.path.exists(self._PROGUARD_PATH):
+      self._PROGUARD_PATH = os.path.join(os.environ['ANDROID_BUILD_TOP'],
+                                         'external/proguard/lib/proguard.jar')
+    self._jar_path = jar_path
+    self._pickled_proguard_name = self._jar_path + '-proguard.pickle'
+    self._test_methods = {}
+    if not self._GetCachedProguardData():
+      self._GetProguardData()
+
+  def _GetCachedProguardData(self):
+    if (os.path.exists(self._pickled_proguard_name) and
+        (os.path.getmtime(self._pickled_proguard_name) >
+         os.path.getmtime(self._jar_path))):
+      logging.info('Loading cached proguard output from %s',
+                   self._pickled_proguard_name)
+      try:
+        with open(self._pickled_proguard_name, 'r') as r:
+          d = pickle.loads(r.read())
+        jar_md5 = md5sum.CalculateHostMd5Sums(self._jar_path)[self._jar_path]
+        if (d['JAR_MD5SUM'] == jar_md5 and
+            d['VERSION'] == PICKLE_FORMAT_VERSION):
+          self._test_methods = d['TEST_METHODS']
+          return True
+      except:
+        logging.warning('PICKLE_FORMAT_VERSION has changed, ignoring cache')
+    return False
+
+  def _GetProguardData(self):
+    logging.info('Retrieving test methods via proguard.')
+
+    p = proguard.Dump(self._jar_path)
+
+    class_lookup = dict((c['class'], c) for c in p['classes'])
+    def recursive_get_annotations(c):
+      s = c['superclass']
+      if s in class_lookup:
+        a = recursive_get_annotations(class_lookup[s])
+      else:
+        a = {}
+      a.update(c['annotations'])
+      return a
+
+    test_classes = (c for c in p['classes']
+                    if c['class'].endswith('Test'))
+    for c in test_classes:
+      class_annotations = recursive_get_annotations(c)
+      test_methods = (m for m in c['methods']
+                      if m['method'].startswith('test'))
+      for m in test_methods:
+        qualified_method = '%s#%s' % (c['class'], m['method'])
+        annotations = dict(class_annotations)
+        annotations.update(m['annotations'])
+        self._test_methods[qualified_method] = m
+        self._test_methods[qualified_method]['annotations'] = annotations
+
+    logging.info('Storing proguard output to %s', self._pickled_proguard_name)
+    d = {'VERSION': PICKLE_FORMAT_VERSION,
+         'TEST_METHODS': self._test_methods,
+         'JAR_MD5SUM':
+              md5sum.CalculateHostMd5Sums(self._jar_path)[self._jar_path]}
+    with open(self._pickled_proguard_name, 'w') as f:
+      f.write(pickle.dumps(d))
+
+  @staticmethod
+  def _IsTestMethod(test):
+    class_name, method = test.split('#')
+    return class_name.endswith('Test') and method.startswith('test')
+
+  def GetTestAnnotations(self, test):
+    """Returns a list of all annotations for the given |test|. May be empty."""
+    if not self._IsTestMethod(test) or not test in self._test_methods:
+      return []
+    return self._test_methods[test]['annotations']
+
+  @staticmethod
+  def _AnnotationsMatchFilters(annotation_filter_list, annotations):
+    """Checks if annotations match any of the filters."""
+    if not annotation_filter_list:
+      return True
+    for annotation_filter in annotation_filter_list:
+      filters = annotation_filter.split('=')
+      if len(filters) == 2:
+        key = filters[0]
+        value_list = filters[1].split(',')
+        for value in value_list:
+          if key in annotations and value == annotations[key]:
+            return True
+      elif annotation_filter in annotations:
+        return True
+    return False
+
+  def GetAnnotatedTests(self, annotation_filter_list):
+    """Returns a list of all tests that match the given annotation filters."""
+    return [test for test in self.GetTestMethods()
+            if self._IsTestMethod(test) and self._AnnotationsMatchFilters(
+                annotation_filter_list, self.GetTestAnnotations(test))]
+
+  def GetTestMethods(self):
+    """Returns a dict of all test methods and relevant attributes.
+
+    Test methods are retrieved as Class#testMethod.
+    """
+    return self._test_methods
+
+  def _GetTestsMissingAnnotation(self):
+    """Get a list of test methods with no known annotations."""
+    tests_missing_annotations = []
+    for test_method in self.GetTestMethods().iterkeys():
+      annotations_ = frozenset(self.GetTestAnnotations(test_method).iterkeys())
+      if (annotations_.isdisjoint(self._ANNOTATIONS) and
+          not self.IsHostDrivenTest(test_method)):
+        tests_missing_annotations.append(test_method)
+    return sorted(tests_missing_annotations)
+
+  def _IsTestValidForSdkRange(self, test_name, attached_min_sdk_level):
+    required_min_sdk_level = int(
+        self.GetTestAnnotations(test_name).get('MinAndroidSdkLevel', 0))
+    return (required_min_sdk_level is None or
+            attached_min_sdk_level >= required_min_sdk_level)
+
+  def GetAllMatchingTests(self, annotation_filter_list,
+                          exclude_annotation_list, test_filter):
+    """Get a list of tests matching any of the annotations and the filter.
+
+    Args:
+      annotation_filter_list: List of test annotations. A test must have at
+        least one of these annotations. A test without any annotations is
+        considered to be SmallTest.
+      exclude_annotation_list: List of test annotations. A test must not have
+        any of these annotations.
+      test_filter: Filter used for partial matching on the test method names.
+
+    Returns:
+      List of all matching tests.
+    """
+    if annotation_filter_list:
+      available_tests = self.GetAnnotatedTests(annotation_filter_list)
+      # Include un-annotated tests in SmallTest.
+      if annotation_filter_list.count(self._DEFAULT_ANNOTATION) > 0:
+        for test in self._GetTestsMissingAnnotation():
+          logging.warning(
+              '%s has no annotations. Assuming "%s".', test,
+              self._DEFAULT_ANNOTATION)
+          available_tests.append(test)
+    else:
+      available_tests = [m for m in self.GetTestMethods()
+                         if not self.IsHostDrivenTest(m)]
+
+    if exclude_annotation_list:
+      excluded_tests = self.GetAnnotatedTests(exclude_annotation_list)
+      available_tests = list(set(available_tests) - set(excluded_tests))
+
+    tests = []
+    if test_filter:
+      # |available_tests| are in adb instrument format: package.path.class#test.
+
+      # Maps a 'class.test' name to each 'package.path.class#test' name.
+      sanitized_test_names = dict([
+          (t.split('.')[-1].replace('#', '.'), t) for t in available_tests])
+      # Filters 'class.test' names and populates |tests| with the corresponding
+      # 'package.path.class#test' names.
+      tests = [
+          sanitized_test_names[t] for t in unittest_util.FilterTestNames(
+              sanitized_test_names.keys(), test_filter.replace('#', '.'))]
+    else:
+      tests = available_tests
+
+    # Filter out any tests with SDK level requirements that don't match the set
+    # of attached devices.
+    devices = device_utils.DeviceUtils.parallel()
+    min_sdk_version = min(devices.build_version_sdk.pGet(None))
+    tests = [t for t in tests
+             if self._IsTestValidForSdkRange(t, min_sdk_version)]
+
+    return tests
+
+  @staticmethod
+  def IsHostDrivenTest(test):
+    return 'pythonDrivenTests' in test
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py
new file mode 100644
index 0000000..792010b
--- /dev/null
+++ b/build/android/pylib/instrumentation/test_options.py
@@ -0,0 +1,26 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the InstrumentationOptions named tuple."""
+
+import collections
+
+InstrumentationOptions = collections.namedtuple('InstrumentationOptions', [
+    'tool',
+    'annotations',
+    'exclude_annotations',
+    'test_filter',
+    'test_data',
+    'save_perf_json',
+    'screenshot_failures',
+    'wait_for_debugger',
+    'coverage_dir',
+    'test_apk',
+    'test_apk_path',
+    'test_apk_jar_path',
+    'test_runner',
+    'test_support_apk_path',
+    'device_flags',
+    'isolate_file_path',
+    'set_asserts'])
diff --git a/build/android/pylib/instrumentation/test_package.py b/build/android/pylib/instrumentation/test_package.py
new file mode 100644
index 0000000..f32556f
--- /dev/null
+++ b/build/android/pylib/instrumentation/test_package.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Class representing instrumentation test apk and jar."""
+
+import os
+
+from pylib.instrumentation import test_jar
+from pylib.utils import apk_helper
+
+
+class TestPackage(test_jar.TestJar):
+  def __init__(self, apk_path, jar_path, test_support_apk_path):
+    test_jar.TestJar.__init__(self, jar_path)
+
+    if not os.path.exists(apk_path):
+      raise Exception('%s not found, please build it' % apk_path)
+    self._apk_path = apk_path
+    self._apk_name = os.path.splitext(os.path.basename(apk_path))[0]
+    self._package_name = apk_helper.GetPackageName(self._apk_path)
+    self._test_support_apk_path = test_support_apk_path
+
+  def GetApkPath(self):
+    """Returns the absolute path to the APK."""
+    return self._apk_path
+
+  def GetApkName(self):
+    """Returns the name of the apk without the suffix."""
+    return self._apk_name
+
+  def GetPackageName(self):
+    """Returns the package name of this APK."""
+    return self._package_name
+
+  # Override.
+  def Install(self, device):
+    device.Install(self.GetApkPath())
+    if (self._test_support_apk_path and
+        os.path.exists(self._test_support_apk_path)):
+      device.Install(self._test_support_apk_path)
+
diff --git a/build/android/pylib/instrumentation/test_result.py b/build/android/pylib/instrumentation/test_result.py
new file mode 100644
index 0000000..24e80a8
--- /dev/null
+++ b/build/android/pylib/instrumentation/test_result.py
@@ -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.
+
+from pylib.base import base_test_result
+
+
+class InstrumentationTestResult(base_test_result.BaseTestResult):
+  """Result information for a single instrumentation test."""
+
+  def __init__(self, full_name, test_type, start_date, dur, log=''):
+    """Construct an InstrumentationTestResult object.
+
+    Args:
+      full_name: Full name of the test.
+      test_type: Type of the test result as defined in ResultType.
+      start_date: Date in milliseconds when the test began running.
+      dur: Duration of the test run in milliseconds.
+      log: A string listing any errors.
+    """
+    super(InstrumentationTestResult, self).__init__(
+        full_name, test_type, dur, log)
+    name_pieces = full_name.rsplit('#')
+    if len(name_pieces) > 1:
+      self._test_name = name_pieces[1]
+      self._class_name = name_pieces[0]
+    else:
+      self._class_name = full_name
+      self._test_name = full_name
+    self._start_date = start_date
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
new file mode 100644
index 0000000..6e8be34
--- /dev/null
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -0,0 +1,371 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Class for running instrumentation tests on a single device."""
+
+import logging
+import os
+import re
+import sys
+import time
+
+from pylib import constants
+from pylib import flag_changer
+from pylib import valgrind_tools
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+from pylib.device import device_errors
+from pylib.instrumentation import instrumentation_test_instance
+from pylib.instrumentation import json_perf_parser
+from pylib.instrumentation import test_result
+from pylib.local.device import local_device_instrumentation_test_run
+
+sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib',
+                             'common'))
+import perf_tests_results_helper # pylint: disable=F0401
+
+
+_PERF_TEST_ANNOTATION = 'PerfTest'
+
+
+class TestRunner(base_test_runner.BaseTestRunner):
+  """Responsible for running a series of tests connected to a single device."""
+
+  _DEVICE_COVERAGE_DIR = 'chrome/test/coverage'
+  _HOSTMACHINE_PERF_OUTPUT_FILE = '/tmp/chrome-profile'
+  _DEVICE_PERF_OUTPUT_SEARCH_PREFIX = (constants.DEVICE_PERF_OUTPUT_DIR +
+                                       '/chrome-profile*')
+
+  def __init__(self, test_options, device, shard_index, test_pkg,
+               additional_flags=None):
+    """Create a new TestRunner.
+
+    Args:
+      test_options: An InstrumentationOptions object.
+      device: Attached android device.
+      shard_index: Shard index.
+      test_pkg: A TestPackage object.
+      additional_flags: A list of additional flags to add to the command line.
+    """
+    super(TestRunner, self).__init__(device, test_options.tool)
+    self._lighttp_port = constants.LIGHTTPD_RANDOM_PORT_FIRST + shard_index
+    self._logcat_monitor = None
+
+    self.coverage_device_file = None
+    self.coverage_dir = test_options.coverage_dir
+    self.coverage_host_file = None
+    self.options = test_options
+    self.test_pkg = test_pkg
+    # Use the correct command line file for the package under test.
+    cmdline_file = [a.cmdline_file for a in constants.PACKAGE_INFO.itervalues()
+                    if a.test_package == self.test_pkg.GetPackageName()]
+    assert len(cmdline_file) < 2, 'Multiple packages have the same test package'
+    if len(cmdline_file) and cmdline_file[0]:
+      self.flags = flag_changer.FlagChanger(self.device, cmdline_file[0])
+      if additional_flags:
+        self.flags.AddFlags(additional_flags)
+    else:
+      self.flags = None
+
+  #override
+  def InstallTestPackage(self):
+    self.test_pkg.Install(self.device)
+
+  def _GetInstrumentationArgs(self):
+    ret = {}
+    if self.options.wait_for_debugger:
+      ret['debug'] = 'true'
+    if self.coverage_dir:
+      ret['coverage'] = 'true'
+      ret['coverageFile'] = self.coverage_device_file
+
+    return ret
+
+  def _TakeScreenshot(self, test):
+    """Takes a screenshot from the device."""
+    screenshot_name = os.path.join(constants.SCREENSHOTS_DIR, '%s.png' % test)
+    logging.info('Taking screenshot named %s', screenshot_name)
+    self.device.TakeScreenshot(screenshot_name)
+
+  def SetUp(self):
+    """Sets up the test harness and device before all tests are run."""
+    super(TestRunner, self).SetUp()
+    if not self.device.HasRoot():
+      logging.warning('Unable to enable java asserts for %s, non rooted device',
+                      str(self.device))
+    else:
+      if self.device.SetJavaAsserts(self.options.set_asserts):
+        # TODO(jbudorick) How to best do shell restart after the
+        #                 android_commands refactor?
+        self.device.RunShellCommand('stop')
+        self.device.RunShellCommand('start')
+
+    # We give different default value to launch HTTP server based on shard index
+    # because it may have race condition when multiple processes are trying to
+    # launch lighttpd with same port at same time.
+    self.LaunchTestHttpServer(
+        os.path.join(constants.DIR_SOURCE_ROOT), self._lighttp_port)
+    if self.flags:
+      self.flags.AddFlags(['--disable-fre', '--enable-test-intents'])
+      if self.options.device_flags:
+        with open(self.options.device_flags) as device_flags_file:
+          stripped_flags = (l.strip() for l in device_flags_file)
+          self.flags.AddFlags([flag for flag in stripped_flags if flag])
+
+  def TearDown(self):
+    """Cleans up the test harness and saves outstanding data from test run."""
+    if self.flags:
+      self.flags.Restore()
+    super(TestRunner, self).TearDown()
+
+  def TestSetup(self, test):
+    """Sets up the test harness for running a particular test.
+
+    Args:
+      test: The name of the test that will be run.
+    """
+    self.SetupPerfMonitoringIfNeeded(test)
+    self._SetupIndividualTestTimeoutScale(test)
+    self.tool.SetupEnvironment()
+
+    if self.flags and self._IsFreTest(test):
+      self.flags.RemoveFlags(['--disable-fre'])
+
+    # Make sure the forwarder is still running.
+    self._RestartHttpServerForwarderIfNecessary()
+
+    if self.coverage_dir:
+      coverage_basename = '%s.ec' % test
+      self.coverage_device_file = '%s/%s/%s' % (
+          self.device.GetExternalStoragePath(),
+          TestRunner._DEVICE_COVERAGE_DIR, coverage_basename)
+      self.coverage_host_file = os.path.join(
+          self.coverage_dir, coverage_basename)
+
+  def _IsFreTest(self, test):
+    """Determines whether a test is a first run experience test.
+
+    Args:
+      test: The name of the test to be checked.
+
+    Returns:
+      Whether the feature being tested is FirstRunExperience.
+    """
+    annotations = self.test_pkg.GetTestAnnotations(test)
+    return 'FirstRunExperience' == annotations.get('Feature', None)
+
+  def _IsPerfTest(self, test):
+    """Determines whether a test is a performance test.
+
+    Args:
+      test: The name of the test to be checked.
+
+    Returns:
+      Whether the test is annotated as a performance test.
+    """
+    return _PERF_TEST_ANNOTATION in self.test_pkg.GetTestAnnotations(test)
+
+  def SetupPerfMonitoringIfNeeded(self, test):
+    """Sets up performance monitoring if the specified test requires it.
+
+    Args:
+      test: The name of the test to be run.
+    """
+    if not self._IsPerfTest(test):
+      return
+    self.device.RunShellCommand(
+        ['rm', TestRunner._DEVICE_PERF_OUTPUT_SEARCH_PREFIX])
+    self._logcat_monitor = self.device.GetLogcatMonitor()
+    self._logcat_monitor.Start()
+
+  def TestTeardown(self, test, result):
+    """Cleans up the test harness after running a particular test.
+
+    Depending on the options of this TestRunner this might handle performance
+    tracking.  This method will only be called if the test passed.
+
+    Args:
+      test: The name of the test that was just run.
+      result: result for this test.
+    """
+
+    self.tool.CleanUpEnvironment()
+
+    # The logic below relies on the test passing.
+    if not result or not result.DidRunPass():
+      return
+
+    self.TearDownPerfMonitoring(test)
+
+    if self.flags and self._IsFreTest(test):
+      self.flags.AddFlags(['--disable-fre'])
+
+    if self.coverage_dir:
+      self.device.PullFile(
+          self.coverage_device_file, self.coverage_host_file)
+      self.device.RunShellCommand(
+          'rm -f %s' % self.coverage_device_file)
+
+  def TearDownPerfMonitoring(self, test):
+    """Cleans up performance monitoring if the specified test required it.
+
+    Args:
+      test: The name of the test that was just run.
+    Raises:
+      Exception: if there's anything wrong with the perf data.
+    """
+    if not self._IsPerfTest(test):
+      return
+    raw_test_name = test.split('#')[1]
+
+    # Wait and grab annotation data so we can figure out which traces to parse
+    regex = self._logcat_monitor.WaitFor(
+        re.compile(r'\*\*PERFANNOTATION\(' + raw_test_name + r'\)\:(.*)'))
+
+    # If the test is set to run on a specific device type only (IE: only
+    # tablet or phone) and it is being run on the wrong device, the test
+    # just quits and does not do anything.  The java test harness will still
+    # print the appropriate annotation for us, but will add --NORUN-- for
+    # us so we know to ignore the results.
+    # The --NORUN-- tag is managed by ChromeTabbedActivityTestBase.java
+    if regex.group(1) != '--NORUN--':
+
+      # Obtain the relevant perf data.  The data is dumped to a
+      # JSON formatted file.
+      json_string = self.device.ReadFile(
+          '/data/data/com.google.android.apps.chrome/files/PerfTestData.txt',
+          as_root=True)
+
+      if not json_string:
+        raise Exception('Perf file is empty')
+
+      if self.options.save_perf_json:
+        json_local_file = '/tmp/chromium-android-perf-json-' + raw_test_name
+        with open(json_local_file, 'w') as f:
+          f.write(json_string)
+        logging.info('Saving Perf UI JSON from test ' +
+                     test + ' to ' + json_local_file)
+
+      raw_perf_data = regex.group(1).split(';')
+
+      for raw_perf_set in raw_perf_data:
+        if raw_perf_set:
+          perf_set = raw_perf_set.split(',')
+          if len(perf_set) != 3:
+            raise Exception('Unexpected number of tokens in perf annotation '
+                            'string: ' + raw_perf_set)
+
+          # Process the performance data
+          result = json_perf_parser.GetAverageRunInfoFromJSONString(json_string,
+                                                                    perf_set[0])
+          perf_tests_results_helper.PrintPerfResult(perf_set[1], perf_set[2],
+                                                    [result['average']],
+                                                    result['units'])
+
+  def _SetupIndividualTestTimeoutScale(self, test):
+    timeout_scale = self._GetIndividualTestTimeoutScale(test)
+    valgrind_tools.SetChromeTimeoutScale(self.device, timeout_scale)
+
+  def _GetIndividualTestTimeoutScale(self, test):
+    """Returns the timeout scale for the given |test|."""
+    annotations = self.test_pkg.GetTestAnnotations(test)
+    timeout_scale = 1
+    if 'TimeoutScale' in annotations:
+      try:
+        timeout_scale = int(annotations['TimeoutScale'])
+      except ValueError:
+        logging.warning('Non-integer value of TimeoutScale ignored. (%s)'
+                        % annotations['TimeoutScale'])
+    if self.options.wait_for_debugger:
+      timeout_scale *= 100
+    return timeout_scale
+
+  def _GetIndividualTestTimeoutSecs(self, test):
+    """Returns the timeout in seconds for the given |test|."""
+    annotations = self.test_pkg.GetTestAnnotations(test)
+    if 'Manual' in annotations:
+      return 10 * 60 * 60
+    if 'IntegrationTest' in annotations:
+      return 30 * 60
+    if 'External' in annotations:
+      return 10 * 60
+    if 'EnormousTest' in annotations:
+      return 10 * 60
+    if 'LargeTest' in annotations or _PERF_TEST_ANNOTATION in annotations:
+      return 5 * 60
+    if 'MediumTest' in annotations:
+      return 3 * 60
+    if 'SmallTest' in annotations:
+      return 1 * 60
+
+    logging.warn(("Test size not found in annotations for test '%s', using " +
+                  "1 minute for timeout.") % test)
+    return 1 * 60
+
+  def _RunTest(self, test, timeout):
+    """Runs a single instrumentation test.
+
+    Args:
+      test: Test class/method.
+      timeout: Timeout time in seconds.
+
+    Returns:
+      The raw output of am instrument as a list of lines.
+    """
+    extras = self._GetInstrumentationArgs()
+    extras['class'] = test
+    return self.device.StartInstrumentation(
+        '%s/%s' % (self.test_pkg.GetPackageName(), self.options.test_runner),
+        raw=True, extras=extras, timeout=timeout, retries=3)
+
+  def _GenerateTestResult(self, test, instr_result_code, instr_result_bundle,
+                          statuses, start_ms, duration_ms):
+    results = instrumentation_test_instance.GenerateTestResults(
+        instr_result_code, instr_result_bundle, statuses, start_ms, duration_ms)
+    for r in results:
+      if r.GetName() == test:
+        return r
+    logging.error('Could not find result for test: %s', test)
+    return test_result.InstrumentationTestResult(
+        test, base_test_result.ResultType.UNKNOWN, start_ms, duration_ms)
+
+  #override
+  def RunTest(self, test):
+    results = base_test_result.TestRunResults()
+    timeout = (self._GetIndividualTestTimeoutSecs(test) *
+               self._GetIndividualTestTimeoutScale(test) *
+               self.tool.GetTimeoutScale())
+    if (self.device.build_version_sdk
+        < constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN):
+      timeout *= 10
+
+    start_ms = 0
+    duration_ms = 0
+    try:
+      self.TestSetup(test)
+
+      time_ms = lambda: int(time.time() * 1000)
+      start_ms = time_ms()
+      raw_output = self._RunTest(test, timeout)
+      duration_ms = time_ms() - start_ms
+
+      # Parse the test output
+      result_code, result_bundle, statuses = (
+          instrumentation_test_instance.ParseAmInstrumentRawOutput(raw_output))
+      result = self._GenerateTestResult(
+          test, result_code, result_bundle, statuses, start_ms, duration_ms)
+      if local_device_instrumentation_test_run.DidPackageCrashOnDevice(
+          self.test_pkg.GetPackageName(), self.device):
+        result.SetType(base_test_result.ResultType.CRASH)
+      results.AddResult(result)
+    except device_errors.CommandTimeoutError as e:
+      results.AddResult(test_result.InstrumentationTestResult(
+          test, base_test_result.ResultType.TIMEOUT, start_ms, duration_ms,
+          log=str(e) or 'No information'))
+    except device_errors.DeviceUnreachableError as e:
+      results.AddResult(test_result.InstrumentationTestResult(
+          test, base_test_result.ResultType.CRASH, start_ms, duration_ms,
+          log=str(e) or 'No information'))
+    self.TestTeardown(test, results)
+    return (results, None if results.DidRunPass() else test)
diff --git a/build/android/pylib/junit/__init__.py b/build/android/pylib/junit/__init__.py
new file mode 100644
index 0000000..5cac026
--- /dev/null
+++ b/build/android/pylib/junit/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/junit/setup.py b/build/android/pylib/junit/setup.py
new file mode 100644
index 0000000..94d4277
--- /dev/null
+++ b/build/android/pylib/junit/setup.py
@@ -0,0 +1,20 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib.junit import test_runner
+
+def Setup(args):
+  """Creates a test runner factory for junit tests.
+
+  Args:
+    args: an argparse.Namespace object.
+  Return:
+    A (runner_factory, tests) tuple.
+  """
+
+  def TestRunnerFactory(_unused_device, _unused_shard_index):
+    return test_runner.JavaTestRunner(args)
+
+  return (TestRunnerFactory, ['JUnit tests'])
+
diff --git a/build/android/pylib/junit/test_dispatcher.py b/build/android/pylib/junit/test_dispatcher.py
new file mode 100644
index 0000000..6e0d865
--- /dev/null
+++ b/build/android/pylib/junit/test_dispatcher.py
@@ -0,0 +1,28 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import constants
+from pylib.base import base_test_result
+
+def RunTests(tests, runner_factory):
+  """Runs a set of java tests on the host.
+
+  Return:
+    A tuple containing the results & the exit code.
+  """
+  def run(t):
+    runner = runner_factory(None, None)
+    runner.SetUp()
+    results_list, return_code = runner.RunTest(t)
+    runner.TearDown()
+    return (results_list, return_code == 0)
+
+  test_run_results = base_test_result.TestRunResults()
+  exit_code = 0
+  for t in tests:
+    results_list, passed = run(t)
+    test_run_results.AddResults(results_list)
+    if not passed:
+      exit_code = constants.ERROR_EXIT_CODE
+  return (test_run_results, exit_code)
\ No newline at end of file
diff --git a/build/android/pylib/junit/test_runner.py b/build/android/pylib/junit/test_runner.py
new file mode 100644
index 0000000..a6d3bf9
--- /dev/null
+++ b/build/android/pylib/junit/test_runner.py
@@ -0,0 +1,50 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+import tempfile
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.results import json_results
+
+class JavaTestRunner(object):
+  """Runs java tests on the host."""
+
+  def __init__(self, args):
+    self._package_filter = args.package_filter
+    self._runner_filter = args.runner_filter
+    self._sdk_version = args.sdk_version
+    self._test_filter = args.test_filter
+    self._test_suite = args.test_suite
+
+  def SetUp(self):
+    pass
+
+  def RunTest(self, _test):
+    """Runs junit tests from |self._test_suite|."""
+    with tempfile.NamedTemporaryFile() as json_file:
+      java_script = os.path.join(
+          constants.GetOutDirectory(), 'bin', self._test_suite)
+      command = [java_script,
+                 '-test-jars', self._test_suite + '.jar',
+                 '-json-results-file', json_file.name]
+      if self._test_filter:
+        command.extend(['-gtest-filter', self._test_filter])
+      if self._package_filter:
+        command.extend(['-package-filter', self._package_filter])
+      if self._runner_filter:
+        command.extend(['-runner-filter', self._runner_filter])
+      if self._sdk_version:
+        command.extend(['-sdk-version', self._sdk_version])
+      return_code = cmd_helper.RunCmd(command)
+      results_list = json_results.ParseResultsFromJson(
+          json.loads(json_file.read()))
+      return (results_list, return_code)
+
+  def TearDown(self):
+    pass
+
diff --git a/build/android/pylib/linker/__init__.py b/build/android/pylib/linker/__init__.py
new file mode 100644
index 0000000..af99437
--- /dev/null
+++ b/build/android/pylib/linker/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/linker/setup.py b/build/android/pylib/linker/setup.py
new file mode 100644
index 0000000..5776f5a
--- /dev/null
+++ b/build/android/pylib/linker/setup.py
@@ -0,0 +1,45 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Setup for linker tests."""
+
+import os
+import sys
+
+from pylib import constants
+from pylib.linker import test_case
+from pylib.linker import test_runner
+
+sys.path.insert(0,
+                os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib',
+                             'common'))
+import unittest_util # pylint: disable=F0401
+
+def Setup(args, _devices):
+  """Creates a list of test cases and a runner factory.
+
+  Args:
+    args: an argparse.Namespace object.
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  test_cases = [
+      test_case.LinkerLibraryAddressTest,
+      test_case.LinkerSharedRelroTest,
+      test_case.LinkerRandomizationTest]
+
+  low_memory_modes = [False, True]
+  all_tests = [t(is_low_memory=m) for t in test_cases for m in low_memory_modes]
+
+  if args.test_filter:
+    all_test_names = [test.qualified_name for test in all_tests]
+    filtered_test_names = unittest_util.FilterTestNames(all_test_names,
+                                                        args.test_filter)
+    all_tests = [t for t in all_tests \
+                 if t.qualified_name in filtered_test_names]
+
+  def TestRunnerFactory(device, _shard_index):
+    return test_runner.LinkerTestRunner(device, args.tool)
+
+  return (TestRunnerFactory, all_tests)
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
new file mode 100644
index 0000000..c7b0f50
--- /dev/null
+++ b/build/android/pylib/linker/test_case.py
@@ -0,0 +1,496 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Base class for linker-specific test cases.
+
+   The custom dynamic linker can only be tested through a custom test case
+   for various technical reasons:
+
+     - It's an 'invisible feature', i.e. it doesn't expose a new API or
+       behaviour, all it does is save RAM when loading native libraries.
+
+     - Checking that it works correctly requires several things that do not
+       fit the existing GTest-based and instrumentation-based tests:
+
+         - Native test code needs to be run in both the browser and renderer
+           process at the same time just after loading native libraries, in
+           a completely asynchronous way.
+
+         - Each test case requires restarting a whole new application process
+           with a different command-line.
+
+         - Enabling test support in the Linker code requires building a special
+           APK with a flag to activate special test-only support code in the
+           Linker code itself.
+
+       Host-driven tests have also been tried, but since they're really
+       sub-classes of instrumentation tests, they didn't work well either.
+
+   To build and run the linker tests, do the following:
+
+     ninja -C out/Debug chromium_linker_test_apk
+     build/android/test_runner.py linker
+
+"""
+# pylint: disable=R0201
+
+import logging
+import os
+import re
+import time
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.device import device_errors
+from pylib.device import intent
+
+
+ResultType = base_test_result.ResultType
+
+_PACKAGE_NAME = 'org.chromium.chromium_linker_test_apk'
+_ACTIVITY_NAME = '.ChromiumLinkerTestActivity'
+_COMMAND_LINE_FILE = '/data/local/tmp/chromium-linker-test-command-line'
+
+# Path to the Linker.java source file.
+_LINKER_JAVA_SOURCE_PATH = (
+    'base/android/java/src/org/chromium/base/library_loader/Linker.java')
+
+# A regular expression used to extract the browser shared RELRO configuration
+# from the Java source file above.
+_RE_LINKER_BROWSER_CONFIG = re.compile(
+    r'.*BROWSER_SHARED_RELRO_CONFIG\s+=\s+' +
+        r'BROWSER_SHARED_RELRO_CONFIG_(\S+)\s*;.*',
+    re.MULTILINE | re.DOTALL)
+
+# Logcat filters used during each test. Only the 'chromium' one is really
+# needed, but the logs are added to the TestResult in case of error, and
+# it is handy to have the 'chromium_android_linker' ones as well when
+# troubleshooting.
+_LOGCAT_FILTERS = ['*:s', 'chromium:v', 'chromium_android_linker:v']
+#_LOGCAT_FILTERS = ['*:v']  ## DEBUG
+
+# Regular expression used to match status lines in logcat.
+_RE_BROWSER_STATUS_LINE = re.compile(r' BROWSER_LINKER_TEST: (FAIL|SUCCESS)$')
+_RE_RENDERER_STATUS_LINE = re.compile(r' RENDERER_LINKER_TEST: (FAIL|SUCCESS)$')
+
+# Regular expression used to mach library load addresses in logcat.
+_RE_LIBRARY_ADDRESS = re.compile(
+    r'(BROWSER|RENDERER)_LIBRARY_ADDRESS: (\S+) ([0-9A-Fa-f]+)')
+
+
+def _GetBrowserSharedRelroConfig():
+  """Returns a string corresponding to the Linker's configuration of shared
+     RELRO sections in the browser process. This parses the Java linker source
+     file to get the appropriate information.
+  Return:
+      None in case of error (e.g. could not locate the source file).
+     'NEVER' if the browser process shall never use shared RELROs.
+     'LOW_RAM_ONLY' if if uses it only on low-end devices.
+     'ALWAYS' if it always uses a shared RELRO.
+  """
+  source_path = \
+      os.path.join(constants.DIR_SOURCE_ROOT, _LINKER_JAVA_SOURCE_PATH)
+  if not os.path.exists(source_path):
+    logging.error('Could not find linker source file: ' + source_path)
+    return None
+
+  with open(source_path) as f:
+    configs = _RE_LINKER_BROWSER_CONFIG.findall(f.read())
+    if not configs:
+      logging.error(
+          'Can\'t find browser shared RELRO configuration value in ' + \
+          source_path)
+      return None
+
+    if configs[0] not in ['NEVER', 'LOW_RAM_ONLY', 'ALWAYS']:
+      logging.error('Unexpected browser config value: ' + configs[0])
+      return None
+
+    logging.info('Found linker browser shared RELRO config: ' + configs[0])
+    return configs[0]
+
+
+def _StartActivityAndWaitForLinkerTestStatus(device, timeout):
+  """Force-start an activity and wait up to |timeout| seconds until the full
+     linker test status lines appear in the logcat, recorded through |device|.
+  Args:
+    device: A DeviceUtils instance.
+    timeout: Timeout in seconds
+  Returns:
+    A (status, logs) tuple, where status is a ResultType constant, and logs
+    if the final logcat output as a string.
+  """
+
+  # 1. Start recording logcat with appropriate filters.
+  with device.GetLogcatMonitor(filter_specs=_LOGCAT_FILTERS) as logmon:
+
+    # 2. Force-start activity.
+    device.StartActivity(
+        intent.Intent(package=_PACKAGE_NAME, activity=_ACTIVITY_NAME),
+        force_stop=True)
+
+    # 3. Wait up to |timeout| seconds until the test status is in the logcat.
+    result = ResultType.PASS
+    try:
+      browser_match = logmon.WaitFor(_RE_BROWSER_STATUS_LINE, timeout=timeout)
+      logging.debug('Found browser match: %s', browser_match.group(0))
+      renderer_match = logmon.WaitFor(_RE_RENDERER_STATUS_LINE,
+                                      timeout=timeout)
+      logging.debug('Found renderer match: %s', renderer_match.group(0))
+      if (browser_match.group(1) != 'SUCCESS'
+          or renderer_match.group(1) != 'SUCCESS'):
+        result = ResultType.FAIL
+    except device_errors.CommandTimeoutError:
+      result = ResultType.TIMEOUT
+
+    return result, '\n'.join(device.adb.Logcat(dump=True))
+
+
+class LibraryLoadMap(dict):
+  """A helper class to pretty-print a map of library names to load addresses."""
+  def __str__(self):
+    items = ['\'%s\': 0x%x' % (name, address) for \
+        (name, address) in self.iteritems()]
+    return '{%s}' % (', '.join(items))
+
+  def __repr__(self):
+    return 'LibraryLoadMap(%s)' % self.__str__()
+
+
+class AddressList(list):
+  """A helper class to pretty-print a list of load addresses."""
+  def __str__(self):
+    items = ['0x%x' % address for address in self]
+    return '[%s]' % (', '.join(items))
+
+  def __repr__(self):
+    return 'AddressList(%s)' % self.__str__()
+
+
+def _ExtractLibraryLoadAddressesFromLogcat(logs):
+  """Extract the names and addresses of shared libraries loaded in the
+     browser and renderer processes.
+  Args:
+    logs: A string containing logcat output.
+  Returns:
+    A tuple (browser_libs, renderer_libs), where each item is a map of
+    library names (strings) to library load addresses (ints), for the
+    browser and renderer processes, respectively.
+  """
+  browser_libs = LibraryLoadMap()
+  renderer_libs = LibraryLoadMap()
+  for m in _RE_LIBRARY_ADDRESS.finditer(logs):
+    process_type, lib_name, lib_address = m.groups()
+    lib_address = int(lib_address, 16)
+    if process_type == 'BROWSER':
+      browser_libs[lib_name] = lib_address
+    elif process_type == 'RENDERER':
+      renderer_libs[lib_name] = lib_address
+    else:
+      assert False, 'Invalid process type'
+
+  return browser_libs, renderer_libs
+
+
+def _CheckLoadAddressRandomization(lib_map_list, process_type):
+  """Check that a map of library load addresses is random enough.
+  Args:
+    lib_map_list: a list of dictionaries that map library names (string)
+      to load addresses (int). Each item in the list corresponds to a
+      different run / process start.
+    process_type: a string describing the process type.
+  Returns:
+    (status, logs) tuple, where <status> is True iff the load addresses are
+    randomized, False otherwise, and <logs> is a string containing an error
+    message detailing the libraries that are not randomized properly.
+  """
+  # Collect, for each library, its list of load addresses.
+  lib_addr_map = {}
+  for lib_map in lib_map_list:
+    for lib_name, lib_address in lib_map.iteritems():
+      if lib_name not in lib_addr_map:
+        lib_addr_map[lib_name] = AddressList()
+      lib_addr_map[lib_name].append(lib_address)
+
+  logging.info('%s library load map: %s', process_type, lib_addr_map)
+
+  # For each library, check the randomness of its load addresses.
+  bad_libs = {}
+  for lib_name, lib_address_list in lib_addr_map.iteritems():
+    # If all addresses are different, skip to next item.
+    lib_address_set = set(lib_address_list)
+    # Consider that if there is more than one pair of identical addresses in
+    # the list, then randomization is broken.
+    if len(lib_address_set) < len(lib_address_list) - 1:
+      bad_libs[lib_name] = lib_address_list
+
+
+  if bad_libs:
+    return False, '%s libraries failed randomization: %s' % \
+        (process_type, bad_libs)
+
+  return True, '%s libraries properly randomized: %s' % \
+      (process_type, lib_addr_map)
+
+
+class LinkerTestCaseBase(object):
+  """Base class for linker test cases."""
+
+  def __init__(self, is_low_memory=False):
+    """Create a test case.
+    Args:
+      is_low_memory: True to simulate a low-memory device, False otherwise.
+    """
+    self.is_low_memory = is_low_memory
+    if is_low_memory:
+      test_suffix = 'ForLowMemoryDevice'
+    else:
+      test_suffix = 'ForRegularDevice'
+    class_name = self.__class__.__name__
+    self.qualified_name = '%s.%s' % (class_name, test_suffix)
+    self.tagged_name = self.qualified_name
+
+  def _RunTest(self, _device):
+    """Run the test, must be overriden.
+    Args:
+      _device: A DeviceUtils interface.
+    Returns:
+      A (status, log) tuple, where <status> is a ResultType constant, and <log>
+      is the logcat output captured during the test in case of error, or None
+      in case of success.
+    """
+    return ResultType.FAIL, 'Unimplemented _RunTest() method!'
+
+  def Run(self, device):
+    """Run the test on a given device.
+    Args:
+      device: Name of target device where to run the test.
+    Returns:
+      A base_test_result.TestRunResult() instance.
+    """
+    margin = 8
+    print '[ %-*s ] %s' % (margin, 'RUN', self.tagged_name)
+    logging.info('Running linker test: %s', self.tagged_name)
+
+    # Create command-line file on device.
+    command_line_flags = ''
+    if self.is_low_memory:
+      command_line_flags = '--low-memory-device'
+    device.WriteFile(_COMMAND_LINE_FILE, command_line_flags)
+
+    # Run the test.
+    status, logs = self._RunTest(device)
+
+    result_text = 'OK'
+    if status == ResultType.FAIL:
+      result_text = 'FAILED'
+    elif status == ResultType.TIMEOUT:
+      result_text = 'TIMEOUT'
+    print '[ %*s ] %s' % (margin, result_text, self.tagged_name)
+
+    results = base_test_result.TestRunResults()
+    results.AddResult(
+        base_test_result.BaseTestResult(
+            self.tagged_name,
+            status,
+            log=logs))
+
+    return results
+
+  def __str__(self):
+    return self.tagged_name
+
+  def __repr__(self):
+    return self.tagged_name
+
+
+class LinkerSharedRelroTest(LinkerTestCaseBase):
+  """A linker test case to check the status of shared RELRO sections.
+
+    The core of the checks performed here are pretty simple:
+
+      - Clear the logcat and start recording with an appropriate set of filters.
+      - Create the command-line appropriate for the test-case.
+      - Start the activity (always forcing a cold start).
+      - Every second, look at the current content of the filtered logcat lines
+        and look for instances of the following:
+
+            BROWSER_LINKER_TEST: <status>
+            RENDERER_LINKER_TEST: <status>
+
+        where <status> can be either FAIL or SUCCESS. These lines can appear
+        in any order in the logcat. Once both browser and renderer status are
+        found, stop the loop. Otherwise timeout after 30 seconds.
+
+        Note that there can be other lines beginning with BROWSER_LINKER_TEST:
+        and RENDERER_LINKER_TEST:, but are not followed by a <status> code.
+
+      - The test case passes if the <status> for both the browser and renderer
+        process are SUCCESS. Otherwise its a fail.
+  """
+  def _RunTest(self, device):
+    # Wait up to 30 seconds until the linker test status is in the logcat.
+    return _StartActivityAndWaitForLinkerTestStatus(device, timeout=30)
+
+
+class LinkerLibraryAddressTest(LinkerTestCaseBase):
+  """A test case that verifies library load addresses.
+
+     The point of this check is to ensure that the libraries are loaded
+     according to the following rules:
+
+     - For low-memory devices, they should always be loaded at the same address
+       in both browser and renderer processes, both below 0x4000_0000.
+
+     - For regular devices, the browser process should load libraries above
+       0x4000_0000, and renderer ones below it.
+  """
+  def _RunTest(self, device):
+    result, logs = _StartActivityAndWaitForLinkerTestStatus(device, timeout=30)
+
+    # Return immediately in case of timeout.
+    if result == ResultType.TIMEOUT:
+      return result, logs
+
+    # Collect the library load addresses in the browser and renderer processes.
+    browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs)
+
+    logging.info('Browser libraries: %s', browser_libs)
+    logging.info('Renderer libraries: %s', renderer_libs)
+
+    # Check that the same libraries are loaded into both processes:
+    browser_set = set(browser_libs.keys())
+    renderer_set = set(renderer_libs.keys())
+    if browser_set != renderer_set:
+      logging.error('Library set mistmach browser=%s renderer=%s',
+          browser_libs.keys(), renderer_libs.keys())
+      return ResultType.FAIL, logs
+
+    # And that there are not empty.
+    if not browser_set:
+      logging.error('No libraries loaded in any process!')
+      return ResultType.FAIL, logs
+
+    # Check that the renderer libraries are loaded at 'low-addresses'. i.e.
+    # below 0x4000_0000, for every kind of device.
+    memory_boundary = 0x40000000
+    bad_libs = []
+    for lib_name, lib_address in renderer_libs.iteritems():
+      if lib_address >= memory_boundary:
+        bad_libs.append((lib_name, lib_address))
+
+    if bad_libs:
+      logging.error('Renderer libraries loaded at high addresses: %s', bad_libs)
+      return ResultType.FAIL, logs
+
+    browser_config = _GetBrowserSharedRelroConfig()
+    if not browser_config:
+      return ResultType.FAIL, 'Bad linker source configuration'
+
+    if browser_config == 'ALWAYS' or \
+        (browser_config == 'LOW_RAM_ONLY' and self.is_low_memory):
+      # The libraries must all be loaded at the same addresses. This also
+      # implicitly checks that the browser libraries are at low addresses.
+      addr_mismatches = []
+      for lib_name, lib_address in browser_libs.iteritems():
+        lib_address2 = renderer_libs[lib_name]
+        if lib_address != lib_address2:
+          addr_mismatches.append((lib_name, lib_address, lib_address2))
+
+      if addr_mismatches:
+        logging.error('Library load address mismatches: %s',
+            addr_mismatches)
+        return ResultType.FAIL, logs
+
+    # Otherwise, check that libraries are loaded at 'high-addresses'.
+    # Note that for low-memory devices, the previous checks ensure that they
+    # were loaded at low-addresses.
+    else:
+      bad_libs = []
+      for lib_name, lib_address in browser_libs.iteritems():
+        if lib_address < memory_boundary:
+          bad_libs.append((lib_name, lib_address))
+
+      if bad_libs:
+        logging.error('Browser libraries loaded at low addresses: %s', bad_libs)
+        return ResultType.FAIL, logs
+
+    # Everything's ok.
+    return ResultType.PASS, logs
+
+
+class LinkerRandomizationTest(LinkerTestCaseBase):
+  """A linker test case to check that library load address randomization works
+     properly between successive starts of the test program/activity.
+
+     This starts the activity several time (each time forcing a new process
+     creation) and compares the load addresses of the libraries in them to
+     detect that they have changed.
+
+     In theory, two successive runs could (very rarely) use the same load
+     address, so loop 5 times and compare the values there. It is assumed
+     that if there are more than one pair of identical addresses, then the
+     load addresses are not random enough for this test.
+  """
+  def _RunTest(self, device):
+    max_loops = 5
+    browser_lib_map_list = []
+    renderer_lib_map_list = []
+    logs_list = []
+    for _ in range(max_loops):
+      # Start the activity.
+      result, logs = _StartActivityAndWaitForLinkerTestStatus(
+          device, timeout=30)
+      if result == ResultType.TIMEOUT:
+        # Something bad happened. Return immediately.
+        return result, logs
+
+      # Collect library addresses.
+      browser_libs, renderer_libs = _ExtractLibraryLoadAddressesFromLogcat(logs)
+      browser_lib_map_list.append(browser_libs)
+      renderer_lib_map_list.append(renderer_libs)
+      logs_list.append(logs)
+
+    # Check randomization in the browser libraries.
+    logs = '\n'.join(logs_list)
+
+    browser_status, browser_logs = _CheckLoadAddressRandomization(
+        browser_lib_map_list, 'Browser')
+
+    renderer_status, renderer_logs = _CheckLoadAddressRandomization(
+        renderer_lib_map_list, 'Renderer')
+
+    browser_config = _GetBrowserSharedRelroConfig()
+    if not browser_config:
+      return ResultType.FAIL, 'Bad linker source configuration'
+
+    if not browser_status:
+      if browser_config == 'ALWAYS' or \
+          (browser_config == 'LOW_RAM_ONLY' and self.is_low_memory):
+        return ResultType.FAIL, browser_logs
+
+      # IMPORTANT NOTE: The system's ASLR implementation seems to be very poor
+      # when starting an activity process in a loop with "adb shell am start".
+      #
+      # When simulating a regular device, loading libraries in the browser
+      # process uses a simple mmap(NULL, ...) to let the kernel device where to
+      # load the file (this is similar to what System.loadLibrary() does).
+      #
+      # Unfortunately, at least in the context of this test, doing so while
+      # restarting the activity with the activity manager very, very, often
+      # results in the system using the same load address for all 5 runs, or
+      # sometimes only 4 out of 5.
+      #
+      # This has been tested experimentally on both Android 4.1.2 and 4.3.
+      #
+      # Note that this behaviour doesn't seem to happen when starting an
+      # application 'normally', i.e. when using the application launcher to
+      # start the activity.
+      logging.info('Ignoring system\'s low randomization of browser libraries' +
+                   ' for regular devices')
+
+    if not renderer_status:
+      return ResultType.FAIL, renderer_logs
+
+    return ResultType.PASS, logs
diff --git a/build/android/pylib/linker/test_runner.py b/build/android/pylib/linker/test_runner.py
new file mode 100644
index 0000000..b6803e4
--- /dev/null
+++ b/build/android/pylib/linker/test_runner.py
@@ -0,0 +1,98 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs linker tests on a particular device."""
+
+import logging
+import os.path
+import sys
+import traceback
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+from pylib.linker import test_case
+from pylib.utils import apk_helper
+
+
+# Name of the Android package to install for this to work.
+_PACKAGE_NAME = 'ChromiumLinkerTest'
+
+
+class LinkerExceptionTestResult(base_test_result.BaseTestResult):
+  """Test result corresponding to a python exception in a host-custom test."""
+
+  def __init__(self, test_name, exc_info):
+    """Constructs a LinkerExceptionTestResult object.
+
+    Args:
+      test_name: name of the test which raised an exception.
+      exc_info: exception info, ostensibly from sys.exc_info().
+    """
+    exc_type, exc_value, exc_traceback = exc_info
+    trace_info = ''.join(traceback.format_exception(exc_type, exc_value,
+                                                    exc_traceback))
+    log_msg = 'Exception:\n' + trace_info
+
+    super(LinkerExceptionTestResult, self).__init__(
+        test_name,
+        base_test_result.ResultType.FAIL,
+        log="%s %s" % (exc_type, log_msg))
+
+
+class LinkerTestRunner(base_test_runner.BaseTestRunner):
+  """Orchestrates running a set of linker tests.
+
+  Any Python exceptions in the tests are caught and translated into a failed
+  result, rather than being re-raised on the main thread.
+  """
+
+  #override
+  def __init__(self, device, tool):
+    """Creates a new LinkerTestRunner.
+
+    Args:
+      device: Attached android device.
+      tool: Name of the Valgrind tool.
+    """
+    super(LinkerTestRunner, self).__init__(device, tool)
+
+  #override
+  def InstallTestPackage(self):
+    apk_path = os.path.join(
+        constants.GetOutDirectory(), 'apks', '%s.apk' % _PACKAGE_NAME)
+
+    if not os.path.exists(apk_path):
+      raise Exception('%s not found, please build it' % apk_path)
+
+    self.device.Install(apk_path)
+
+  #override
+  def RunTest(self, test):
+    """Sets up and runs a test case.
+
+    Args:
+      test: An object which is ostensibly a subclass of LinkerTestCaseBase.
+
+    Returns:
+      A TestRunResults object which contains the result produced by the test
+      and, in the case of a failure, the test that should be retried.
+    """
+
+    assert isinstance(test, test_case.LinkerTestCaseBase)
+
+    try:
+      results = test.Run(self.device)
+    except Exception:
+      logging.exception('Caught exception while trying to run test: ' +
+                        test.tagged_name)
+      exc_info = sys.exc_info()
+      results = base_test_result.TestRunResults()
+      results.AddResult(LinkerExceptionTestResult(
+          test.tagged_name, exc_info))
+
+    if not results.DidRunPass():
+      return results, test
+    else:
+      return results, None
diff --git a/build/android/pylib/local/__init__.py b/build/android/pylib/local/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/local/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/local/device/__init__.py b/build/android/pylib/local/device/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/local/device/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
new file mode 100644
index 0000000..0d02ca3
--- /dev/null
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -0,0 +1,54 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib.base import environment
+from pylib.device import adb_wrapper
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.utils import parallelizer
+
+
+class LocalDeviceEnvironment(environment.Environment):
+
+  def __init__(self, args, _error_func):
+    super(LocalDeviceEnvironment, self).__init__()
+    self._device_serial = args.test_device
+    self._devices = []
+    self._max_tries = 1 + args.num_retries
+    self._tool_name = args.tool
+
+  #override
+  def SetUp(self):
+    available_devices = device_utils.DeviceUtils.HealthyDevices()
+    if not available_devices:
+      raise device_errors.NoDevicesError
+    if self._device_serial:
+      self._devices = [d for d in available_devices
+                       if d.adb.GetDeviceSerial == self._device_serial]
+      if not self._devices:
+        raise device_errors.DeviceUnreachableError(
+            'Could not find device %r' % self._device_serial)
+    else:
+      self._devices = available_devices
+
+  @property
+  def devices(self):
+    return self._devices
+
+  @property
+  def parallel_devices(self):
+    return parallelizer.SyncParallelizer(self._devices)
+
+  @property
+  def max_tries(self):
+    return self._max_tries
+
+  @property
+  def tool(self):
+    return self._tool_name
+
+  #override
+  def TearDown(self):
+    pass
+
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
new file mode 100644
index 0000000..e388fce
--- /dev/null
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -0,0 +1,207 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import re
+import time
+
+from pylib import flag_changer
+from pylib.base import base_test_result
+from pylib.base import test_run
+from pylib.constants import keyevent
+from pylib.device import device_errors
+from pylib.local.device import local_device_test_run
+
+
+TIMEOUT_ANNOTATIONS = [
+  ('Manual', 10 * 60 * 60),
+  ('IntegrationTest', 30 * 60),
+  ('External', 10 * 60),
+  ('EnormousTest', 10 * 60),
+  ('LargeTest', 5 * 60),
+  ('MediumTest', 3 * 60),
+  ('SmallTest', 1 * 60),
+]
+
+
+# TODO(jbudorick): Make this private once the instrumentation test_runner is
+# deprecated.
+def DidPackageCrashOnDevice(package_name, device):
+  # Dismiss any error dialogs. Limit the number in case we have an error
+  # loop or we are failing to dismiss.
+  try:
+    for _ in xrange(10):
+      package = _DismissCrashDialog(device)
+      if not package:
+        return False
+      # Assume test package convention of ".test" suffix
+      if package in package_name:
+        return True
+  except device_errors.CommandFailedError:
+    logging.exception('Error while attempting to dismiss crash dialog.')
+  return False
+
+
+_CURRENT_FOCUS_CRASH_RE = re.compile(
+    r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}')
+
+
+def _DismissCrashDialog(device):
+  # TODO(jbudorick): Try to grep the output on the device instead of using
+  # large_output if/when DeviceUtils exposes a public interface for piped
+  # shell command handling.
+  for l in device.RunShellCommand(
+      ['dumpsys', 'window', 'windows'], check_return=True, large_output=True):
+    m = re.match(_CURRENT_FOCUS_CRASH_RE, l)
+    if m:
+      device.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
+      device.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
+      device.SendKeyEvent(keyevent.KEYCODE_ENTER)
+      return m.group(2)
+
+  return None
+
+
+class LocalDeviceInstrumentationTestRun(
+    local_device_test_run.LocalDeviceTestRun):
+  def __init__(self, env, test_instance):
+    super(LocalDeviceInstrumentationTestRun, self).__init__(env, test_instance)
+    self._flag_changers = {}
+
+  def TestPackage(self):
+    return None
+
+  def SetUp(self):
+    def substitute_external_storage(d, external_storage):
+      if not d:
+        return external_storage
+      elif isinstance(d, list):
+        return '/'.join(p if p else external_storage for p in d)
+      else:
+        return d
+
+    def individual_device_set_up(dev, host_device_tuples):
+      dev.Install(self._test_instance.apk_under_test)
+      dev.Install(self._test_instance.test_apk)
+
+      external_storage = dev.GetExternalStoragePath()
+      host_device_tuples = [
+          (h, substitute_external_storage(d, external_storage))
+          for h, d in host_device_tuples]
+      logging.info('instrumentation data deps:')
+      for h, d in host_device_tuples:
+        logging.info('%r -> %r', h, d)
+      dev.PushChangedFiles(host_device_tuples)
+      if self._test_instance.flags:
+        if not self._test_instance.package_info:
+          logging.error("Couldn't set flags: no package info")
+        elif not self._test_instance.package_info.cmdline_file:
+          logging.error("Couldn't set flags: no cmdline_file")
+        else:
+          self._flag_changers[str(dev)] = flag_changer.FlagChanger(
+              dev, self._test_instance.package_info.cmdline_file)
+          logging.debug('Attempting to set flags: %r',
+                        self._test_instance.flags)
+          self._flag_changers[str(dev)].AddFlags(self._test_instance.flags)
+
+    self._env.parallel_devices.pMap(
+        individual_device_set_up,
+        self._test_instance.GetDataDependencies())
+
+  def TearDown(self):
+    def individual_device_tear_down(dev):
+      if str(dev) in self._flag_changers:
+        self._flag_changers[str(dev)].Restore()
+
+    self._env.parallel_devices.pMap(individual_device_tear_down)
+
+  #override
+  def _CreateShards(self, tests):
+    return tests
+
+  #override
+  def _GetTests(self):
+    return self._test_instance.GetTests()
+
+  #override
+  def _GetTestName(self, test):
+    return '%s#%s' % (test['class'], test['method'])
+
+  #override
+  def _RunTest(self, device, test):
+    extras = self._test_instance.GetHttpServerEnvironmentVars()
+
+    if isinstance(test, list):
+      if not self._test_instance.driver_apk:
+        raise Exception('driver_apk does not exist. '
+                        'Please build it and try again.')
+
+      def name_and_timeout(t):
+        n = self._GetTestName(t)
+        i = self._GetTimeoutFromAnnotations(t['annotations'], n)
+        return (n, i)
+
+      test_names, timeouts = zip(*(name_and_timeout(t) for t in test))
+
+      test_name = ','.join(test_names)
+      target = '%s/%s' % (
+          self._test_instance.driver_package,
+          self._test_instance.driver_name)
+      extras.update(
+          self._test_instance.GetDriverEnvironmentVars(
+              test_list=test_names))
+      timeout = sum(timeouts)
+    else:
+      test_name = self._GetTestName(test)
+      target = '%s/%s' % (
+          self._test_instance.test_package, self._test_instance.test_runner)
+      extras['class'] = test_name
+      timeout = self._GetTimeoutFromAnnotations(test['annotations'], test_name)
+
+    logging.info('preparing to run %s: %s' % (test_name, test))
+
+    time_ms = lambda: int(time.time() * 1e3)
+    start_ms = time_ms()
+    output = device.StartInstrumentation(
+        target, raw=True, extras=extras, timeout=timeout, retries=0)
+    duration_ms = time_ms() - start_ms
+
+    # TODO(jbudorick): Make instrumentation tests output a JSON so this
+    # doesn't have to parse the output.
+    logging.debug('output from %s:', test_name)
+    for l in output:
+      logging.debug('  %s', l)
+
+    result_code, result_bundle, statuses = (
+        self._test_instance.ParseAmInstrumentRawOutput(output))
+    results = self._test_instance.GenerateTestResults(
+        result_code, result_bundle, statuses, start_ms, duration_ms)
+    if DidPackageCrashOnDevice(self._test_instance.test_package, device):
+      for r in results:
+        if r.GetType() == base_test_result.ResultType.UNKNOWN:
+          r.SetType(base_test_result.ResultType.CRASH)
+    return results
+
+  #override
+  def _ShouldShard(self):
+    return True
+
+  @staticmethod
+  def _GetTimeoutFromAnnotations(annotations, test_name):
+    for k, v in TIMEOUT_ANNOTATIONS:
+      if k in annotations:
+        timeout = v
+    else:
+      logging.warning('Using default 1 minute timeout for %s' % test_name)
+      timeout = 60
+
+    try:
+      scale = int(annotations.get('TimeoutScale', 1))
+    except ValueError as e:
+      logging.warning("Non-integer value of TimeoutScale ignored. (%s)", str(e))
+      scale = 1
+    timeout *= scale
+
+    return timeout
+
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
new file mode 100644
index 0000000..fa24eb1
--- /dev/null
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -0,0 +1,99 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+
+from pylib import valgrind_tools
+from pylib.base import base_test_result
+from pylib.base import test_run
+from pylib.base import test_collection
+
+
+class LocalDeviceTestRun(test_run.TestRun):
+
+  def __init__(self, env, test_instance):
+    super(LocalDeviceTestRun, self).__init__(env, test_instance)
+    self._tools = {}
+
+  #override
+  def RunTests(self):
+    tests = self._GetTests()
+
+    def run_tests_on_device(dev, tests):
+      r = base_test_result.TestRunResults()
+      for test in tests:
+        result = self._RunTest(dev, test)
+        if isinstance(result, base_test_result.BaseTestResult):
+          r.AddResult(result)
+        elif isinstance(result, list):
+          r.AddResults(result)
+        else:
+          raise Exception('Unexpected result type: %s' % type(result).__name__)
+        if isinstance(tests, test_collection.TestCollection):
+          tests.test_completed()
+      return r
+
+    tries = 0
+    results = base_test_result.TestRunResults()
+    all_fail_results = {}
+    while tries < self._env.max_tries and tests:
+      logging.debug('try %d, will run %d tests:', tries, len(tests))
+      for t in tests:
+        logging.debug('  %s', t)
+
+      if self._ShouldShard():
+        tc = test_collection.TestCollection(self._CreateShards(tests))
+        try_results = self._env.parallel_devices.pMap(
+            run_tests_on_device, tc).pGet(None)
+      else:
+        try_results = self._env.parallel_devices.pMap(
+            run_tests_on_device, tests).pGet(None)
+      for try_result in try_results:
+        for result in try_result.GetAll():
+          if result.GetType() in (base_test_result.ResultType.PASS,
+                                  base_test_result.ResultType.SKIP):
+            results.AddResult(result)
+          else:
+            all_fail_results[result.GetName()] = result
+
+      results_names = set(r.GetName() for r in results.GetAll())
+      tests = [t for t in tests if self._GetTestName(t) not in results_names]
+      tries += 1
+
+    all_unknown_test_names = set(self._GetTestName(t) for t in tests)
+    all_failed_test_names = set(all_fail_results.iterkeys())
+
+    unknown_tests = all_unknown_test_names.difference(all_failed_test_names)
+    failed_tests = all_failed_test_names.intersection(all_unknown_test_names)
+
+    if unknown_tests:
+      results.AddResults(
+          base_test_result.BaseTestResult(
+              u, base_test_result.ResultType.UNKNOWN)
+          for u in unknown_tests)
+    if failed_tests:
+      results.AddResults(all_fail_results[f] for f in failed_tests)
+
+    return results
+
+  def GetTool(self, device):
+    if not str(device) in self._tools:
+      self._tools[str(device)] = valgrind_tools.CreateTool(
+          self._env.tool, device)
+    return self._tools[str(device)]
+
+  def _CreateShards(self, tests):
+    raise NotImplementedError
+
+  def _GetTestName(self, test):
+    return test
+
+  def _GetTests(self):
+    raise NotImplementedError
+
+  def _RunTest(self, device, test):
+    raise NotImplementedError
+
+  def _ShouldShard(self):
+    raise NotImplementedError
diff --git a/build/android/pylib/local/local_test_server_spawner.py b/build/android/pylib/local/local_test_server_spawner.py
new file mode 100644
index 0000000..77f552e
--- /dev/null
+++ b/build/android/pylib/local/local_test_server_spawner.py
@@ -0,0 +1,45 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import chrome_test_server_spawner
+from pylib import forwarder
+from pylib.base import test_server
+
+
+class LocalTestServerSpawner(test_server.TestServer):
+
+  def __init__(self, port, device, tool):
+    super(LocalTestServerSpawner, self).__init__()
+    self._device = device
+    self._spawning_server = chrome_test_server_spawner.SpawningServer(
+        port, device, tool)
+    self._tool = tool
+
+  @property
+  def server_address(self):
+    return self._spawning_server.server.server_address
+
+  @property
+  def port(self):
+    return self.server_address[1]
+
+  #override
+  def SetUp(self):
+    self._device.WriteFile(
+        '%s/net-test-server-ports' % self._device.GetExternalStoragePath(),
+        '%s:0' % str(self.port))
+    forwarder.Forwarder.Map(
+        [(self.port, self.port)], self._device, self._tool)
+    self._spawning_server.Start()
+
+  #override
+  def Reset(self):
+    self._spawning_server.CleanupState()
+
+  #override
+  def TearDown(self):
+    self.Reset()
+    self._spawning_server.Stop()
+    forwarder.Forwarder.UnmapDevicePort(self.port, self._device)
+
diff --git a/build/android/pylib/monkey/__init__.py b/build/android/pylib/monkey/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/android/pylib/monkey/__init__.py
diff --git a/build/android/pylib/monkey/setup.py b/build/android/pylib/monkey/setup.py
new file mode 100644
index 0000000..fe690a5
--- /dev/null
+++ b/build/android/pylib/monkey/setup.py
@@ -0,0 +1,27 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates test runner factory and tests for monkey tests."""
+
+from pylib.monkey import test_runner
+
+
+def Setup(test_options):
+  """Create and return the test runner factory and tests.
+
+  Args:
+    test_options: A MonkeyOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  # Token to replicate across devices as the "test". The TestRunner does all of
+  # the work to run the test.
+  tests = ['MonkeyTest']
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.TestRunner(
+        test_options, device, shard_index)
+
+  return (TestRunnerFactory, tests)
diff --git a/build/android/pylib/monkey/test_options.py b/build/android/pylib/monkey/test_options.py
new file mode 100644
index 0000000..54d3d08
--- /dev/null
+++ b/build/android/pylib/monkey/test_options.py
@@ -0,0 +1,16 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the MonkeyOptions named tuple."""
+
+import collections
+
+MonkeyOptions = collections.namedtuple('MonkeyOptions', [
+    'verbose_count',
+    'package',
+    'event_count',
+    'category',
+    'throttle',
+    'seed',
+    'extra_args'])
diff --git a/build/android/pylib/monkey/test_runner.py b/build/android/pylib/monkey/test_runner.py
new file mode 100644
index 0000000..3fd1797
--- /dev/null
+++ b/build/android/pylib/monkey/test_runner.py
@@ -0,0 +1,106 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs a monkey test on a single device."""
+
+import logging
+import random
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+from pylib.device import device_errors
+from pylib.device import intent
+
+_CHROME_PACKAGE = constants.PACKAGE_INFO['chrome'].package
+
+class TestRunner(base_test_runner.BaseTestRunner):
+  """A TestRunner instance runs a monkey test on a single device."""
+
+  def __init__(self, test_options, device, _):
+    super(TestRunner, self).__init__(device, None)
+    self._options = test_options
+    self._package = constants.PACKAGE_INFO[self._options.package].package
+    self._activity = constants.PACKAGE_INFO[self._options.package].activity
+
+  def _LaunchMonkeyTest(self):
+    """Runs monkey test for a given package.
+
+    Returns:
+      Output from the monkey command on the device.
+    """
+
+    timeout_ms = self._options.event_count * self._options.throttle * 1.5
+
+    cmd = ['monkey',
+           '-p %s' % self._package,
+           ' '.join(['-c %s' % c for c in self._options.category]),
+           '--throttle %d' % self._options.throttle,
+           '-s %d' % (self._options.seed or random.randint(1, 100)),
+           '-v ' * self._options.verbose_count,
+           '--monitor-native-crashes',
+           '--kill-process-after-error',
+           self._options.extra_args,
+           '%d' % self._options.event_count]
+    return self.device.RunShellCommand(' '.join(cmd), timeout=timeout_ms)
+
+  def RunTest(self, test_name):
+    """Run a Monkey test on the device.
+
+    Args:
+      test_name: String to use for logging the test result.
+
+    Returns:
+      A tuple of (TestRunResults, retry).
+    """
+    self.device.StartActivity(
+        intent.Intent(package=self._package, activity=self._activity,
+                      action='android.intent.action.MAIN'),
+        blocking=True, force_stop=True)
+
+    # Chrome crashes are not always caught by Monkey test runner.
+    # Verify Chrome has the same PID before and after the test.
+    before_pids = self.device.GetPids(self._package)
+
+    # Run the test.
+    output = ''
+    if before_pids:
+      output = '\n'.join(self._LaunchMonkeyTest())
+      after_pids = self.device.GetPids(self._package)
+
+    crashed = True
+    if not self._package in before_pids:
+      logging.error('Failed to start the process.')
+    elif not self._package in after_pids:
+      logging.error('Process %s has died.', before_pids[self._package])
+    elif before_pids[self._package] != after_pids[self._package]:
+      logging.error('Detected process restart %s -> %s',
+                    before_pids[self._package], after_pids[self._package])
+    else:
+      crashed = False
+
+    results = base_test_result.TestRunResults()
+    success_pattern = 'Events injected: %d' % self._options.event_count
+    if success_pattern in output and not crashed:
+      result = base_test_result.BaseTestResult(
+          test_name, base_test_result.ResultType.PASS, log=output)
+    else:
+      result = base_test_result.BaseTestResult(
+          test_name, base_test_result.ResultType.FAIL, log=output)
+      if 'chrome' in self._options.package:
+        logging.warning('Starting MinidumpUploadService...')
+        # TODO(jbudorick): Update this after upstreaming.
+        minidump_intent = intent.Intent(
+            action='%s.crash.ACTION_FIND_ALL' % _CHROME_PACKAGE,
+            package=self._package,
+            activity='%s.crash.MinidumpUploadService' % _CHROME_PACKAGE)
+        try:
+          self.device.RunShellCommand(
+              ['am', 'startservice'] + minidump_intent.am_args,
+              as_root=True, check_return=True)
+        except device_errors.CommandFailedError:
+          logging.exception('Failed to start MinidumpUploadService')
+
+    results.AddResult(result)
+    return results, False
diff --git a/build/android/pylib/perf/__init__.py b/build/android/pylib/perf/__init__.py
new file mode 100644
index 0000000..9228df8
--- /dev/null
+++ b/build/android/pylib/perf/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/perf/cache_control.py b/build/android/pylib/perf/cache_control.py
new file mode 100644
index 0000000..8065cf9
--- /dev/null
+++ b/build/android/pylib/perf/cache_control.py
@@ -0,0 +1,21 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import android_commands
+from pylib.device import device_utils
+
+class CacheControl(object):
+  _DROP_CACHES = '/proc/sys/vm/drop_caches'
+
+  def __init__(self, device):
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, android_commands.AndroidCommands):
+      device = device_utils.DeviceUtils(device)
+    self._device = device
+
+  def DropRamCaches(self):
+    """Drops the filesystem ram caches for performance testing."""
+    self._device.RunShellCommand('sync', as_root=True)
+    self._device.WriteFile(CacheControl._DROP_CACHES, '3', as_root=True)
+
diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py
new file mode 100644
index 0000000..b6a0989
--- /dev/null
+++ b/build/android/pylib/perf/perf_control.py
@@ -0,0 +1,157 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import atexit
+import logging
+
+from pylib import android_commands
+from pylib.device import device_utils
+
+class PerfControl(object):
+  """Provides methods for setting the performance mode of a device."""
+  _CPU_PATH = '/sys/devices/system/cpu'
+  _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
+
+  def __init__(self, device):
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, android_commands.AndroidCommands):
+      device = device_utils.DeviceUtils(device)
+    self._device = device
+    # this will raise an AdbCommandFailedError if no CPU files are found
+    self._cpu_files = self._device.RunShellCommand(
+        'ls -d cpu[0-9]*', cwd=self._CPU_PATH, check_return=True, as_root=True)
+    assert self._cpu_files, 'Failed to detect CPUs.'
+    self._cpu_file_list = ' '.join(self._cpu_files)
+    logging.info('CPUs found: %s', self._cpu_file_list)
+    self._have_mpdecision = self._device.FileExists('/system/bin/mpdecision')
+
+  def SetHighPerfMode(self):
+    """Sets the highest stable performance mode for the device."""
+    if not self._device.HasRoot():
+      message = 'Need root for performance mode. Results may be NOISY!!'
+      logging.warning(message)
+      # Add an additional warning at exit, such that it's clear that any results
+      # may be different/noisy (due to the lack of intended performance mode).
+      atexit.register(logging.warning, message)
+      return
+
+    product_model = self._device.product_model
+    # TODO(epenner): Enable on all devices (http://crbug.com/383566)
+    if 'Nexus 4' == product_model:
+      self._ForceAllCpusOnline(True)
+      if not self._AllCpusAreOnline():
+        logging.warning('Failed to force CPUs online. Results may be NOISY!')
+      self._SetScalingGovernorInternal('performance')
+    elif 'Nexus 5' == product_model:
+      self._ForceAllCpusOnline(True)
+      if not self._AllCpusAreOnline():
+        logging.warning('Failed to force CPUs online. Results may be NOISY!')
+      self._SetScalingGovernorInternal('performance')
+      self._SetScalingMaxFreq(1190400)
+      self._SetMaxGpuClock(200000000)
+    else:
+      self._SetScalingGovernorInternal('performance')
+
+  def SetPerfProfilingMode(self):
+    """Enables all cores for reliable perf profiling."""
+    self._ForceAllCpusOnline(True)
+    self._SetScalingGovernorInternal('performance')
+    if not self._AllCpusAreOnline():
+      if not self._device.HasRoot():
+        raise RuntimeError('Need root to force CPUs online.')
+      raise RuntimeError('Failed to force CPUs online.')
+
+  def SetDefaultPerfMode(self):
+    """Sets the performance mode for the device to its default mode."""
+    if not self._device.HasRoot():
+      return
+    product_model = self._device.product_model
+    if 'Nexus 5' == product_model:
+      if self._AllCpusAreOnline():
+        self._SetScalingMaxFreq(2265600)
+        self._SetMaxGpuClock(450000000)
+
+    governor_mode = {
+        'GT-I9300': 'pegasusq',
+        'Galaxy Nexus': 'interactive',
+        'Nexus 4': 'ondemand',
+        'Nexus 5': 'ondemand',
+        'Nexus 7': 'interactive',
+        'Nexus 10': 'interactive'
+    }.get(product_model, 'ondemand')
+    self._SetScalingGovernorInternal(governor_mode)
+    self._ForceAllCpusOnline(False)
+
+  def GetCpuInfo(self):
+    online = (output.rstrip() == '1' and status == 0
+              for (_, output, status) in self._ForEachCpu('cat "$CPU/online"'))
+    governor = (output.rstrip() if status == 0 else None
+                for (_, output, status)
+                in self._ForEachCpu('cat "$CPU/cpufreq/scaling_governor"'))
+    return zip(self._cpu_files, online, governor)
+
+  def _ForEachCpu(self, cmd):
+    script = '; '.join([
+        'for CPU in %s' % self._cpu_file_list,
+        'do %s' % cmd,
+        'echo -n "%~%$?%~%"',
+        'done'
+    ])
+    output = self._device.RunShellCommand(
+        script, cwd=self._CPU_PATH, check_return=True, as_root=True)
+    output = '\n'.join(output).split('%~%')
+    return zip(self._cpu_files, output[0::2], (int(c) for c in output[1::2]))
+
+  def _WriteEachCpuFile(self, path, value):
+    results = self._ForEachCpu(
+        'test -e "$CPU/{path}" && echo {value} > "$CPU/{path}"'.format(
+            path=path, value=value))
+    cpus = ' '.join(cpu for (cpu, _, status) in results if status == 0)
+    if cpus:
+      logging.info('Successfully set %s to %r on: %s', path, value, cpus)
+    else:
+      logging.warning('Failed to set %s to %r on any cpus')
+
+  def _SetScalingGovernorInternal(self, value):
+    self._WriteEachCpuFile('cpufreq/scaling_governor', value)
+
+  def _SetScalingMaxFreq(self, value):
+    self._WriteEachCpuFile('cpufreq/scaling_max_freq', '%d' % value)
+
+  def _SetMaxGpuClock(self, value):
+    self._device.WriteFile('/sys/class/kgsl/kgsl-3d0/max_gpuclk',
+                           str(value),
+                           as_root=True)
+
+  def _AllCpusAreOnline(self):
+    results = self._ForEachCpu('cat "$CPU/online"')
+    # TODO(epenner): Investigate why file may be missing
+    # (http://crbug.com/397118)
+    return all(output.rstrip() == '1' and status == 0
+               for (cpu, output, status) in results
+               if cpu != 'cpu0')
+
+  def _ForceAllCpusOnline(self, force_online):
+    """Enable all CPUs on a device.
+
+    Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise
+    to measurements:
+    - In perf, samples are only taken for the CPUs that are online when the
+      measurement is started.
+    - The scaling governor can't be set for an offline CPU and frequency scaling
+      on newly enabled CPUs adds noise to both perf and tracing measurements.
+
+    It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm
+    this is done by "mpdecision".
+
+    """
+    if self._have_mpdecision:
+      script = 'stop mpdecision' if force_online else 'start mpdecision'
+      self._device.RunShellCommand(script, check_return=True, as_root=True)
+
+    if not self._have_mpdecision and not self._AllCpusAreOnline():
+      logging.warning('Unexpected cpu hot plugging detected.')
+
+    if force_online:
+      self._ForEachCpu('echo 1 > "$CPU/online"')
diff --git a/build/android/pylib/perf/perf_control_unittest.py b/build/android/pylib/perf/perf_control_unittest.py
new file mode 100644
index 0000000..69b8b46
--- /dev/null
+++ b/build/android/pylib/perf/perf_control_unittest.py
@@ -0,0 +1,37 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0212
+
+import os
+import sys
+import unittest
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+from pylib.device import device_utils
+from pylib.perf import perf_control
+
+class TestPerfControl(unittest.TestCase):
+  def setUp(self):
+    if not os.getenv('BUILDTYPE'):
+      os.environ['BUILDTYPE'] = 'Debug'
+
+    devices = device_utils.DeviceUtils.HealthyDevices()
+    self.assertGreater(len(devices), 0, 'No device attached!')
+    self._device = devices[0]
+
+  def testHighPerfMode(self):
+    perf = perf_control.PerfControl(self._device)
+    try:
+      perf.SetPerfProfilingMode()
+      cpu_info = perf.GetCpuInfo()
+      self.assertEquals(len(perf._cpu_files), len(cpu_info))
+      for _, online, governor in cpu_info:
+        self.assertTrue(online)
+        self.assertEquals('performance', governor)
+    finally:
+      perf.SetDefaultPerfMode()
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/perf/setup.py b/build/android/pylib/perf/setup.py
new file mode 100644
index 0000000..8e1fc28
--- /dev/null
+++ b/build/android/pylib/perf/setup.py
@@ -0,0 +1,97 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates test runner factory and tests for performance tests."""
+
+import json
+import fnmatch
+import logging
+import os
+import shutil
+
+from pylib import constants
+from pylib import forwarder
+from pylib.device import device_list
+from pylib.device import device_utils
+from pylib.perf import test_runner
+from pylib.utils import test_environment
+
+
+def _GetAllDevices():
+  devices_path = os.path.join(os.environ.get('CHROMIUM_OUT_DIR', 'out'),
+                              device_list.LAST_DEVICES_FILENAME)
+  try:
+    devices = [device_utils.DeviceUtils(s)
+               for s in device_list.GetPersistentDeviceList(devices_path)]
+  except IOError as e:
+    logging.error('Unable to find %s [%s]', devices_path, e)
+    devices = device_utils.DeviceUtils.HealthyDevices()
+  return sorted(devices)
+
+
+def _GetStepsDictFromSingleStep(test_options):
+  # Running a single command, build the tests structure.
+  steps_dict = {
+    'version': 1,
+    'steps': {
+        'single_step': {
+          'device_affinity': 0,
+          'cmd': test_options.single_step
+        },
+    }
+  }
+  return steps_dict
+
+
+def _GetStepsDict(test_options):
+  if test_options.single_step:
+    return _GetStepsDictFromSingleStep(test_options)
+  if test_options.steps:
+    with file(test_options.steps, 'r') as f:
+      steps = json.load(f)
+
+      # Already using the new format.
+      assert steps['version'] == 1
+      return steps
+
+
+def Setup(test_options):
+  """Create and return the test runner factory and tests.
+
+  Args:
+    test_options: A PerformanceOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests, devices).
+  """
+  # TODO(bulach): remove this once the bot side lands. BUG=318369
+  constants.SetBuildType('Release')
+  if os.path.exists(constants.PERF_OUTPUT_DIR):
+    shutil.rmtree(constants.PERF_OUTPUT_DIR)
+  os.makedirs(constants.PERF_OUTPUT_DIR)
+
+  # Before running the tests, kill any leftover server.
+  test_environment.CleanupLeftoverProcesses()
+
+  # We want to keep device affinity, so return all devices ever seen.
+  all_devices = _GetAllDevices()
+
+  steps_dict = _GetStepsDict(test_options)
+  sorted_step_names = sorted(steps_dict['steps'].keys())
+
+  if test_options.test_filter:
+    sorted_step_names = fnmatch.filter(sorted_step_names,
+                                       test_options.test_filter)
+
+  flaky_steps = []
+  if test_options.flaky_steps:
+    with file(test_options.flaky_steps, 'r') as f:
+      flaky_steps = json.load(f)
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.TestRunner(
+        test_options, device, shard_index, len(all_devices),
+        steps_dict, flaky_steps)
+
+  return (TestRunnerFactory, sorted_step_names, all_devices)
diff --git a/build/android/pylib/perf/surface_stats_collector.py b/build/android/pylib/perf/surface_stats_collector.py
new file mode 100644
index 0000000..c7e7527
--- /dev/null
+++ b/build/android/pylib/perf/surface_stats_collector.py
@@ -0,0 +1,191 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import Queue
+import datetime
+import logging
+import re
+import threading
+from pylib import android_commands
+from pylib.device import device_utils
+
+
+# Log marker containing SurfaceTexture timestamps.
+_SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps'
+_SURFACE_TEXTURE_TIMESTAMP_RE = r'\d+'
+
+
+class SurfaceStatsCollector(object):
+  """Collects surface stats for a SurfaceView from the output of SurfaceFlinger.
+
+  Args:
+    device: A DeviceUtils instance.
+  """
+
+  def __init__(self, device):
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, android_commands.AndroidCommands):
+      device = device_utils.DeviceUtils(device)
+    self._device = device
+    self._collector_thread = None
+    self._surface_before = None
+    self._get_data_event = None
+    self._data_queue = None
+    self._stop_event = None
+    self._warn_about_empty_data = True
+
+  def DisableWarningAboutEmptyData(self):
+    self._warn_about_empty_data = False
+
+  def Start(self):
+    assert not self._collector_thread
+
+    if self._ClearSurfaceFlingerLatencyData():
+      self._get_data_event = threading.Event()
+      self._stop_event = threading.Event()
+      self._data_queue = Queue.Queue()
+      self._collector_thread = threading.Thread(target=self._CollectorThread)
+      self._collector_thread.start()
+    else:
+      raise Exception('SurfaceFlinger not supported on this device.')
+
+  def Stop(self):
+    assert self._collector_thread
+    (refresh_period, timestamps) = self._GetDataFromThread()
+    if self._collector_thread:
+      self._stop_event.set()
+      self._collector_thread.join()
+      self._collector_thread = None
+    return (refresh_period, timestamps)
+
+  def _CollectorThread(self):
+    last_timestamp = 0
+    timestamps = []
+    retries = 0
+
+    while not self._stop_event.is_set():
+      self._get_data_event.wait(1)
+      try:
+        refresh_period, new_timestamps = self._GetSurfaceFlingerFrameData()
+        if refresh_period is None or timestamps is None:
+          retries += 1
+          if retries < 3:
+            continue
+          if last_timestamp:
+            # Some data has already been collected, but either the app
+            # was closed or there's no new data. Signal the main thread and
+            # wait.
+            self._data_queue.put((None, None))
+            self._stop_event.wait()
+            break
+          raise Exception('Unable to get surface flinger latency data')
+
+        timestamps += [timestamp for timestamp in new_timestamps
+                       if timestamp > last_timestamp]
+        if len(timestamps):
+          last_timestamp = timestamps[-1]
+
+        if self._get_data_event.is_set():
+          self._get_data_event.clear()
+          self._data_queue.put((refresh_period, timestamps))
+          timestamps = []
+      except Exception as e:
+        # On any error, before aborting, put the exception into _data_queue to
+        # prevent the main thread from waiting at _data_queue.get() infinitely.
+        self._data_queue.put(e)
+        raise
+
+  def _GetDataFromThread(self):
+    self._get_data_event.set()
+    ret = self._data_queue.get()
+    if isinstance(ret, Exception):
+      raise ret
+    return ret
+
+  def _ClearSurfaceFlingerLatencyData(self):
+    """Clears the SurfaceFlinger latency data.
+
+    Returns:
+      True if SurfaceFlinger latency is supported by the device, otherwise
+      False.
+    """
+    # The command returns nothing if it is supported, otherwise returns many
+    # lines of result just like 'dumpsys SurfaceFlinger'.
+    results = self._device.RunShellCommand(
+        'dumpsys SurfaceFlinger --latency-clear SurfaceView')
+    return not len(results)
+
+  def GetSurfaceFlingerPid(self):
+    results = self._device.RunShellCommand('ps | grep surfaceflinger')
+    if not results:
+      raise Exception('Unable to get surface flinger process id')
+    pid = results[0].split()[1]
+    return pid
+
+  def _GetSurfaceFlingerFrameData(self):
+    """Returns collected SurfaceFlinger frame timing data.
+
+    Returns:
+      A tuple containing:
+      - The display's nominal refresh period in milliseconds.
+      - A list of timestamps signifying frame presentation times in
+        milliseconds.
+      The return value may be (None, None) if there was no data collected (for
+      example, if the app was closed before the collector thread has finished).
+    """
+    # adb shell dumpsys SurfaceFlinger --latency <window name>
+    # prints some information about the last 128 frames displayed in
+    # that window.
+    # The data returned looks like this:
+    # 16954612
+    # 7657467895508   7657482691352   7657493499756
+    # 7657484466553   7657499645964   7657511077881
+    # 7657500793457   7657516600576   7657527404785
+    # (...)
+    #
+    # The first line is the refresh period (here 16.95 ms), it is followed
+    # by 128 lines w/ 3 timestamps in nanosecond each:
+    # A) when the app started to draw
+    # B) the vsync immediately preceding SF submitting the frame to the h/w
+    # C) timestamp immediately after SF submitted that frame to the h/w
+    #
+    # The difference between the 1st and 3rd timestamp is the frame-latency.
+    # An interesting data is when the frame latency crosses a refresh period
+    # boundary, this can be calculated this way:
+    #
+    # ceil((C - A) / refresh-period)
+    #
+    # (each time the number above changes, we have a "jank").
+    # If this happens a lot during an animation, the animation appears
+    # janky, even if it runs at 60 fps in average.
+    #
+    # We use the special "SurfaceView" window name because the statistics for
+    # the activity's main window are not updated when the main web content is
+    # composited into a SurfaceView.
+    results = self._device.RunShellCommand(
+        'dumpsys SurfaceFlinger --latency SurfaceView')
+    if not len(results):
+      return (None, None)
+
+    timestamps = []
+    nanoseconds_per_millisecond = 1e6
+    refresh_period = long(results[0]) / nanoseconds_per_millisecond
+
+    # If a fence associated with a frame is still pending when we query the
+    # latency data, SurfaceFlinger gives the frame a timestamp of INT64_MAX.
+    # Since we only care about completed frames, we will ignore any timestamps
+    # with this value.
+    pending_fence_timestamp = (1 << 63) - 1
+
+    for line in results[1:]:
+      fields = line.split()
+      if len(fields) != 3:
+        continue
+      timestamp = long(fields[1])
+      if timestamp == pending_fence_timestamp:
+        continue
+      timestamp /= nanoseconds_per_millisecond
+      timestamps.append(timestamp)
+
+    return (refresh_period, timestamps)
diff --git a/build/android/pylib/perf/surface_stats_collector_unittest.py b/build/android/pylib/perf/surface_stats_collector_unittest.py
new file mode 100644
index 0000000..e905d73
--- /dev/null
+++ b/build/android/pylib/perf/surface_stats_collector_unittest.py
@@ -0,0 +1,64 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for SurfaceStatsCollector."""
+# pylint: disable=W0212
+
+import unittest
+
+from pylib.perf.surface_stats_collector import SurfaceStatsCollector
+
+
+class TestSurfaceStatsCollector(unittest.TestCase):
+  @staticmethod
+  def _CreateUniformTimestamps(base, num, delta):
+    return [base + i * delta for i in range(1, num + 1)]
+
+  @staticmethod
+  def _CreateDictionaryFromResults(results):
+    dictionary = {}
+    for result in results:
+      dictionary[result.name] = result
+    return dictionary
+
+  def setUp(self):
+    self.refresh_period = 0.1
+
+  def testOneFrameDelta(self):
+    timestamps = self._CreateUniformTimestamps(0, 10, self.refresh_period)
+    results = self._CreateDictionaryFromResults(
+                  SurfaceStatsCollector._CalculateResults(
+                      self.refresh_period, timestamps, ''))
+
+    self.assertEquals(results['avg_surface_fps'].value,
+                      int(round(1 / self.refresh_period)))
+    self.assertEquals(results['jank_count'].value, 0)
+    self.assertEquals(results['max_frame_delay'].value, 1)
+    self.assertEquals(len(results['frame_lengths'].value), len(timestamps) - 1)
+
+  def testAllFramesTooShort(self):
+    timestamps = self._CreateUniformTimestamps(0, 10, self.refresh_period / 100)
+    self.assertRaises(Exception,
+                      SurfaceStatsCollector._CalculateResults,
+                      [self.refresh_period, timestamps, ''])
+
+  def testSomeFramesTooShort(self):
+    timestamps = self._CreateUniformTimestamps(0, 5, self.refresh_period)
+    # The following timestamps should be skipped.
+    timestamps += self._CreateUniformTimestamps(timestamps[4],
+                                                5,
+                                                self.refresh_period / 100)
+    timestamps += self._CreateUniformTimestamps(timestamps[4],
+                                                5,
+                                                self.refresh_period)
+
+    results = self._CreateDictionaryFromResults(
+                  SurfaceStatsCollector._CalculateResults(
+                      self.refresh_period, timestamps, ''))
+
+    self.assertEquals(len(results['frame_lengths'].value), 9)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/perf/test_options.py b/build/android/pylib/perf/test_options.py
new file mode 100644
index 0000000..0a0ace0
--- /dev/null
+++ b/build/android/pylib/perf/test_options.py
@@ -0,0 +1,20 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the PerfOptions named tuple."""
+
+import collections
+
+PerfOptions = collections.namedtuple('PerfOptions', [
+    'steps',
+    'flaky_steps',
+    'output_json_list',
+    'print_step',
+    'no_timeout',
+    'test_filter',
+    'dry_run',
+    'single_step',
+    'collect_chartjson_data',
+    'output_chartjson_data',
+])
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py
new file mode 100644
index 0000000..9d1f437
--- /dev/null
+++ b/build/android/pylib/perf/test_runner.py
@@ -0,0 +1,338 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs perf tests.
+
+Our buildbot infrastructure requires each slave to run steps serially.
+This is sub-optimal for android, where these steps can run independently on
+multiple connected devices.
+
+The buildbots will run this script multiple times per cycle:
+- First: all steps listed in --steps in will be executed in parallel using all
+connected devices. Step results will be pickled to disk. Each step has a unique
+name. The result code will be ignored if the step name is listed in
+--flaky-steps.
+The buildbot will treat this step as a regular step, and will not process any
+graph data.
+
+- Then, with -print-step STEP_NAME: at this stage, we'll simply print the file
+with the step results previously saved. The buildbot will then process the graph
+data accordingly.
+
+The JSON steps file contains a dictionary in the format:
+{ "version": int,
+  "steps": {
+    "foo": {
+      "device_affinity": int,
+      "cmd": "script_to_execute foo"
+    },
+    "bar": {
+      "device_affinity": int,
+      "cmd": "script_to_execute bar"
+    }
+  }
+}
+
+The JSON flaky steps file contains a list with step names which results should
+be ignored:
+[
+  "step_name_foo",
+  "step_name_bar"
+]
+
+Note that script_to_execute necessarily have to take at least the following
+option:
+  --device: the serial number to be passed to all adb commands.
+"""
+
+import collections
+import datetime
+import json
+import logging
+import os
+import pickle
+import shutil
+import sys
+import tempfile
+import threading
+import time
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib import forwarder
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+from pylib.device import device_errors
+
+
+def OutputJsonList(json_input, json_output):
+  with file(json_input, 'r') as i:
+    all_steps = json.load(i)
+  step_values = [{'test': k, 'device_affinity': v['device_affinity']}
+      for k, v in all_steps['steps'].iteritems()]
+  with file(json_output, 'w') as o:
+    o.write(json.dumps(step_values))
+  return 0
+
+
+def PrintTestOutput(test_name, json_file_name=None):
+  """Helper method to print the output of previously executed test_name.
+
+  Args:
+    test_name: name of the test that has been previously executed.
+    json_file_name: name of the file to output chartjson data to.
+
+  Returns:
+    exit code generated by the test step.
+  """
+  file_name = os.path.join(constants.PERF_OUTPUT_DIR, test_name)
+  if not os.path.exists(file_name):
+    logging.error('File not found %s', file_name)
+    return 1
+
+  with file(file_name, 'r') as f:
+    persisted_result = pickle.loads(f.read())
+  logging.info('*' * 80)
+  logging.info('Output from:')
+  logging.info(persisted_result['cmd'])
+  logging.info('*' * 80)
+  print persisted_result['output']
+
+  if json_file_name:
+    with file(json_file_name, 'w') as f:
+      f.write(persisted_result['chartjson'])
+
+  return persisted_result['exit_code']
+
+
+def PrintSummary(test_names):
+  logging.info('*' * 80)
+  logging.info('Sharding summary')
+  device_total_time = collections.defaultdict(int)
+  for test_name in test_names:
+    file_name = os.path.join(constants.PERF_OUTPUT_DIR, test_name)
+    if not os.path.exists(file_name):
+      logging.info('%s : No status file found', test_name)
+      continue
+    with file(file_name, 'r') as f:
+      result = pickle.loads(f.read())
+    logging.info('%s : exit_code=%d in %d secs at %s',
+                 result['name'], result['exit_code'], result['total_time'],
+                 result['device'])
+    device_total_time[result['device']] += result['total_time']
+  for device, device_time in device_total_time.iteritems():
+    logging.info('Total for device %s : %d secs', device, device_time)
+  logging.info('Total steps time: %d secs', sum(device_total_time.values()))
+
+
+class _HeartBeatLogger(object):
+  # How often to print the heartbeat on flush().
+  _PRINT_INTERVAL = 30.0
+
+  def __init__(self):
+    """A file-like class for keeping the buildbot alive."""
+    self._len = 0
+    self._tick = time.time()
+    self._stopped = threading.Event()
+    self._timer = threading.Thread(target=self._runner)
+    self._timer.start()
+
+  def _runner(self):
+    while not self._stopped.is_set():
+      self.flush()
+      self._stopped.wait(_HeartBeatLogger._PRINT_INTERVAL)
+
+  def write(self, data):
+    self._len += len(data)
+
+  def flush(self):
+    now = time.time()
+    if now - self._tick >= _HeartBeatLogger._PRINT_INTERVAL:
+      self._tick = now
+      print '--single-step output length %d' % self._len
+      sys.stdout.flush()
+
+  def stop(self):
+    self._stopped.set()
+
+
+class TestRunner(base_test_runner.BaseTestRunner):
+  def __init__(self, test_options, device, shard_index, max_shard, tests,
+      flaky_tests):
+    """A TestRunner instance runs a perf test on a single device.
+
+    Args:
+      test_options: A PerfOptions object.
+      device: Device to run the tests.
+      shard_index: the index of this device.
+      max_shards: the maximum shard index.
+      tests: a dict mapping test_name to command.
+      flaky_tests: a list of flaky test_name.
+    """
+    super(TestRunner, self).__init__(device, None)
+    self._options = test_options
+    self._shard_index = shard_index
+    self._max_shard = max_shard
+    self._tests = tests
+    self._flaky_tests = flaky_tests
+    self._output_dir = None
+
+  @staticmethod
+  def _IsBetter(result):
+    if result['actual_exit_code'] == 0:
+      return True
+    pickled = os.path.join(constants.PERF_OUTPUT_DIR,
+                           result['name'])
+    if not os.path.exists(pickled):
+      return True
+    with file(pickled, 'r') as f:
+      previous = pickle.loads(f.read())
+    return result['actual_exit_code'] < previous['actual_exit_code']
+
+  @staticmethod
+  def _SaveResult(result):
+    if TestRunner._IsBetter(result):
+      with file(os.path.join(constants.PERF_OUTPUT_DIR,
+                             result['name']), 'w') as f:
+        f.write(pickle.dumps(result))
+
+  def _CheckDeviceAffinity(self, test_name):
+    """Returns True if test_name has affinity for this shard."""
+    affinity = (self._tests['steps'][test_name]['device_affinity'] %
+                self._max_shard)
+    if self._shard_index == affinity:
+      return True
+    logging.info('Skipping %s on %s (affinity is %s, device is %s)',
+                 test_name, self.device_serial, affinity, self._shard_index)
+    return False
+
+  def _CleanupOutputDirectory(self):
+    if self._output_dir:
+      shutil.rmtree(self._output_dir, ignore_errors=True)
+      self._output_dir = None
+
+  def _ReadChartjsonOutput(self):
+    if not self._output_dir:
+      return ''
+
+    json_output_path = os.path.join(self._output_dir, 'results-chart.json')
+    with open(json_output_path) as f:
+      return f.read()
+
+  def _LaunchPerfTest(self, test_name):
+    """Runs a perf test.
+
+    Args:
+      test_name: the name of the test to be executed.
+
+    Returns:
+      A tuple containing (Output, base_test_result.ResultType)
+    """
+    if not self._CheckDeviceAffinity(test_name):
+      return '', base_test_result.ResultType.PASS
+
+    try:
+      logging.warning('Unmapping device ports')
+      forwarder.Forwarder.UnmapAllDevicePorts(self.device)
+      self.device.old_interface.RestartAdbdOnDevice()
+    except Exception as e:
+      logging.error('Exception when tearing down device %s', e)
+
+    cmd = ('%s --device %s' %
+           (self._tests['steps'][test_name]['cmd'],
+            self.device_serial))
+
+    if self._options.collect_chartjson_data:
+      self._output_dir = tempfile.mkdtemp()
+      cmd = cmd + ' --output-dir=%s' % self._output_dir
+
+    logging.info('%s : %s', test_name, cmd)
+    start_time = datetime.datetime.now()
+
+    timeout = self._tests['steps'][test_name].get('timeout', 5400)
+    if self._options.no_timeout:
+      timeout = None
+    logging.info('Timeout for %s test: %s', test_name, timeout)
+    full_cmd = cmd
+    if self._options.dry_run:
+      full_cmd = 'echo %s' % cmd
+
+    logfile = sys.stdout
+    if self._options.single_step:
+      # Just print a heart-beat so that the outer buildbot scripts won't timeout
+      # without response.
+      logfile = _HeartBeatLogger()
+    cwd = os.path.abspath(constants.DIR_SOURCE_ROOT)
+    if full_cmd.startswith('src/'):
+      cwd = os.path.abspath(os.path.join(constants.DIR_SOURCE_ROOT, os.pardir))
+    try:
+      exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
+          full_cmd, timeout, cwd=cwd, shell=True, logfile=logfile)
+      json_output = self._ReadChartjsonOutput()
+    except cmd_helper.TimeoutError as e:
+      exit_code = -1
+      output = str(e)
+      json_output = ''
+    finally:
+      self._CleanupOutputDirectory()
+      if self._options.single_step:
+        logfile.stop()
+    end_time = datetime.datetime.now()
+    if exit_code is None:
+      exit_code = -1
+    logging.info('%s : exit_code=%d in %d secs at %s',
+                 test_name, exit_code, (end_time - start_time).seconds,
+                 self.device_serial)
+
+    if exit_code == 0:
+      result_type = base_test_result.ResultType.PASS
+    else:
+      result_type = base_test_result.ResultType.FAIL
+      # Since perf tests use device affinity, give the device a chance to
+      # recover if it is offline after a failure. Otherwise, the master sharder
+      # will remove it from the pool and future tests on this device will fail.
+      try:
+        self.device.WaitUntilFullyBooted(timeout=120)
+      except device_errors.CommandTimeoutError as e:
+        logging.error('Device failed to return after %s: %s' % (test_name, e))
+
+    actual_exit_code = exit_code
+    if test_name in self._flaky_tests:
+      # The exit_code is used at the second stage when printing the
+      # test output. If the test is flaky, force to "0" to get that step green
+      # whilst still gathering data to the perf dashboards.
+      # The result_type is used by the test_dispatcher to retry the test.
+      exit_code = 0
+
+    persisted_result = {
+        'name': test_name,
+        'output': output,
+        'chartjson': json_output,
+        'exit_code': exit_code,
+        'actual_exit_code': actual_exit_code,
+        'result_type': result_type,
+        'total_time': (end_time - start_time).seconds,
+        'device': self.device_serial,
+        'cmd': cmd,
+    }
+    self._SaveResult(persisted_result)
+
+    return (output, result_type)
+
+  def RunTest(self, test_name):
+    """Run a perf test on the device.
+
+    Args:
+      test_name: String to use for logging the test result.
+
+    Returns:
+      A tuple of (TestRunResults, retry).
+    """
+    _, result_type = self._LaunchPerfTest(test_name)
+    results = base_test_result.TestRunResults()
+    results.AddResult(base_test_result.BaseTestResult(test_name, result_type))
+    retry = None
+    if not results.DidRunPass():
+      retry = test_name
+    return results, retry
diff --git a/build/android/pylib/perf/thermal_throttle.py b/build/android/pylib/perf/thermal_throttle.py
new file mode 100644
index 0000000..383b6d5
--- /dev/null
+++ b/build/android/pylib/perf/thermal_throttle.py
@@ -0,0 +1,137 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+from pylib import android_commands
+from pylib.device import device_utils
+
+
+class OmapThrottlingDetector(object):
+  """Class to detect and track thermal throttling on an OMAP 4."""
+  OMAP_TEMP_FILE = ('/sys/devices/platform/omap/omap_temp_sensor.0/'
+                    'temperature')
+
+  @staticmethod
+  def IsSupported(device):
+    return device.FileExists(OmapThrottlingDetector.OMAP_TEMP_FILE)
+
+  def __init__(self, device):
+    self._device = device
+
+  @staticmethod
+  def BecameThrottled(log_line):
+    return 'omap_thermal_throttle' in log_line
+
+  @staticmethod
+  def BecameUnthrottled(log_line):
+    return 'omap_thermal_unthrottle' in log_line
+
+  @staticmethod
+  def GetThrottlingTemperature(log_line):
+    if 'throttle_delayed_work_fn' in log_line:
+      return float([s for s in log_line.split() if s.isdigit()][0]) / 1000.0
+
+  def GetCurrentTemperature(self):
+    tempdata = self._device.ReadFile(OmapThrottlingDetector.OMAP_TEMP_FILE)
+    return float(tempdata) / 1000.0
+
+
+class ExynosThrottlingDetector(object):
+  """Class to detect and track thermal throttling on an Exynos 5."""
+  @staticmethod
+  def IsSupported(device):
+    return device.FileExists('/sys/bus/exynos5-core')
+
+  def __init__(self, device):
+    pass
+
+  @staticmethod
+  def BecameThrottled(log_line):
+    return 'exynos_tmu: Throttling interrupt' in log_line
+
+  @staticmethod
+  def BecameUnthrottled(log_line):
+    return 'exynos_thermal_unthrottle: not throttling' in log_line
+
+  @staticmethod
+  def GetThrottlingTemperature(_log_line):
+    return None
+
+  @staticmethod
+  def GetCurrentTemperature():
+    return None
+
+
+class ThermalThrottle(object):
+  """Class to detect and track thermal throttling.
+
+  Usage:
+    Wait for IsThrottled() to be False before running test
+    After running test call HasBeenThrottled() to find out if the
+    test run was affected by thermal throttling.
+  """
+
+  def __init__(self, device):
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, android_commands.AndroidCommands):
+      device = device_utils.DeviceUtils(device)
+    self._device = device
+    self._throttled = False
+    self._detector = None
+    if OmapThrottlingDetector.IsSupported(device):
+      self._detector = OmapThrottlingDetector(device)
+    elif ExynosThrottlingDetector.IsSupported(device):
+      self._detector = ExynosThrottlingDetector(device)
+
+  def HasBeenThrottled(self):
+    """True if there has been any throttling since the last call to
+       HasBeenThrottled or IsThrottled.
+    """
+    return self._ReadLog()
+
+  def IsThrottled(self):
+    """True if currently throttled."""
+    self._ReadLog()
+    return self._throttled
+
+  def _ReadLog(self):
+    if not self._detector:
+      return False
+    has_been_throttled = False
+    serial_number = str(self._device)
+    log = self._device.RunShellCommand('dmesg -c')
+    degree_symbol = unichr(0x00B0)
+    for line in log:
+      if self._detector.BecameThrottled(line):
+        if not self._throttled:
+          logging.warning('>>> Device %s thermally throttled', serial_number)
+        self._throttled = True
+        has_been_throttled = True
+      elif self._detector.BecameUnthrottled(line):
+        if self._throttled:
+          logging.warning('>>> Device %s thermally unthrottled', serial_number)
+        self._throttled = False
+        has_been_throttled = True
+      temperature = self._detector.GetThrottlingTemperature(line)
+      if temperature is not None:
+        logging.info(u'Device %s thermally throttled at %3.1f%sC',
+                     serial_number, temperature, degree_symbol)
+
+    if logging.getLogger().isEnabledFor(logging.DEBUG):
+      # Print current temperature of CPU SoC.
+      temperature = self._detector.GetCurrentTemperature()
+      if temperature is not None:
+        logging.debug(u'Current SoC temperature of %s = %3.1f%sC',
+                      serial_number, temperature, degree_symbol)
+
+      # Print temperature of battery, to give a system temperature
+      dumpsys_log = self._device.RunShellCommand('dumpsys battery')
+      for line in dumpsys_log:
+        if 'temperature' in line:
+          btemp = float([s for s in line.split() if s.isdigit()][0]) / 10.0
+          logging.debug(u'Current battery temperature of %s = %3.1f%sC',
+                        serial_number, btemp, degree_symbol)
+
+    return has_been_throttled
+
diff --git a/build/android/pylib/pexpect.py b/build/android/pylib/pexpect.py
new file mode 100644
index 0000000..cf59fb0
--- /dev/null
+++ b/build/android/pylib/pexpect.py
@@ -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.
+from __future__ import absolute_import
+
+import os
+import sys
+
+_CHROME_SRC = os.path.join(
+    os.path.abspath(os.path.dirname(__file__)), '..', '..', '..')
+
+_PEXPECT_PATH = os.path.join(_CHROME_SRC, 'third_party', 'pexpect')
+if _PEXPECT_PATH not in sys.path:
+  sys.path.append(_PEXPECT_PATH)
+
+# pexpect is not available on all platforms. We allow this file to be imported
+# on platforms without pexpect and only fail when pexpect is actually used.
+try:
+  from pexpect import * # pylint: disable=W0401,W0614
+except ImportError:
+  pass
diff --git a/build/android/pylib/ports.py b/build/android/pylib/ports.py
new file mode 100644
index 0000000..578152c
--- /dev/null
+++ b/build/android/pylib/ports.py
@@ -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.
+
+"""Functions that deal with local and device ports."""
+
+import contextlib
+import fcntl
+import httplib
+import logging
+import os
+import socket
+import traceback
+
+from pylib import constants
+
+
+# The following two methods are used to allocate the port source for various
+# types of test servers. Because some net-related tests can be run on shards at
+# same time, it's important to have a mechanism to allocate the port
+# process-safe. In here, we implement the safe port allocation by leveraging
+# flock.
+def ResetTestServerPortAllocation():
+  """Resets the port allocation to start from TEST_SERVER_PORT_FIRST.
+
+  Returns:
+    Returns True if reset successes. Otherwise returns False.
+  """
+  try:
+    with open(constants.TEST_SERVER_PORT_FILE, 'w') as fp:
+      fp.write('%d' % constants.TEST_SERVER_PORT_FIRST)
+    if os.path.exists(constants.TEST_SERVER_PORT_LOCKFILE):
+      os.unlink(constants.TEST_SERVER_PORT_LOCKFILE)
+    return True
+  except Exception as e:
+    logging.error(e)
+  return False
+
+
+def AllocateTestServerPort():
+  """Allocates a port incrementally.
+
+  Returns:
+    Returns a valid port which should be in between TEST_SERVER_PORT_FIRST and
+    TEST_SERVER_PORT_LAST. Returning 0 means no more valid port can be used.
+  """
+  port = 0
+  ports_tried = []
+  try:
+    fp_lock = open(constants.TEST_SERVER_PORT_LOCKFILE, 'w')
+    fcntl.flock(fp_lock, fcntl.LOCK_EX)
+    # Get current valid port and calculate next valid port.
+    if not os.path.exists(constants.TEST_SERVER_PORT_FILE):
+      ResetTestServerPortAllocation()
+    with open(constants.TEST_SERVER_PORT_FILE, 'r+') as fp:
+      port = int(fp.read())
+      ports_tried.append(port)
+      while not IsHostPortAvailable(port):
+        port += 1
+        ports_tried.append(port)
+      if (port > constants.TEST_SERVER_PORT_LAST or
+          port < constants.TEST_SERVER_PORT_FIRST):
+        port = 0
+      else:
+        fp.seek(0, os.SEEK_SET)
+        fp.write('%d' % (port + 1))
+  except Exception as e:
+    logging.error(e)
+  finally:
+    if fp_lock:
+      fcntl.flock(fp_lock, fcntl.LOCK_UN)
+      fp_lock.close()
+  if port:
+    logging.info('Allocate port %d for test server.', port)
+  else:
+    logging.error('Could not allocate port for test server. '
+                  'List of ports tried: %s', str(ports_tried))
+  return port
+
+
+def IsHostPortAvailable(host_port):
+  """Checks whether the specified host port is available.
+
+  Args:
+    host_port: Port on host to check.
+
+  Returns:
+    True if the port on host is available, otherwise returns False.
+  """
+  s = socket.socket()
+  try:
+    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    s.bind(('', host_port))
+    s.close()
+    return True
+  except socket.error:
+    return False
+
+
+def IsDevicePortUsed(device, device_port, state=''):
+  """Checks whether the specified device port is used or not.
+
+  Args:
+    device: A DeviceUtils instance.
+    device_port: Port on device we want to check.
+    state: String of the specified state. Default is empty string, which
+           means any state.
+
+  Returns:
+    True if the port on device is already used, otherwise returns False.
+  """
+  base_url = '127.0.0.1:%d' % device_port
+  netstat_results = device.RunShellCommand('netstat')
+  for single_connect in netstat_results:
+    # Column 3 is the local address which we want to check with.
+    connect_results = single_connect.split()
+    if connect_results[0] != 'tcp':
+      continue
+    if len(connect_results) < 6:
+      raise Exception('Unexpected format while parsing netstat line: ' +
+                      single_connect)
+    is_state_match = connect_results[5] == state if state else True
+    if connect_results[3] == base_url and is_state_match:
+      return True
+  return False
+
+
+def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/',
+                            expected_read='', timeout=2):
+  """Checks whether the specified http server is ready to serve request or not.
+
+  Args:
+    host: Host name of the HTTP server.
+    port: Port number of the HTTP server.
+    tries: How many times we want to test the connection. The default value is
+           3.
+    command: The http command we use to connect to HTTP server. The default
+             command is 'GET'.
+    path: The path we use when connecting to HTTP server. The default path is
+          '/'.
+    expected_read: The content we expect to read from the response. The default
+                   value is ''.
+    timeout: Timeout (in seconds) for each http connection. The default is 2s.
+
+  Returns:
+    Tuple of (connect status, client error). connect status is a boolean value
+    to indicate whether the server is connectable. client_error is the error
+    message the server returns when connect status is false.
+  """
+  assert tries >= 1
+  for i in xrange(0, tries):
+    client_error = None
+    try:
+      with contextlib.closing(httplib.HTTPConnection(
+          host, port, timeout=timeout)) as http:
+        # Output some debug information when we have tried more than 2 times.
+        http.set_debuglevel(i >= 2)
+        http.request(command, path)
+        r = http.getresponse()
+        content = r.read()
+        if r.status == 200 and r.reason == 'OK' and content == expected_read:
+          return (True, '')
+        client_error = ('Bad response: %s %s version %s\n  ' %
+                        (r.status, r.reason, r.version) +
+                        '\n  '.join([': '.join(h) for h in r.getheaders()]))
+    except (httplib.HTTPException, socket.error) as e:
+      # Probably too quick connecting: try again.
+      exception_error_msgs = traceback.format_exception_only(type(e), e)
+      if exception_error_msgs:
+        client_error = ''.join(exception_error_msgs)
+  # Only returns last client_error.
+  return (False, client_error or 'Timeout')
diff --git a/build/android/pylib/remote/__init__.py b/build/android/pylib/remote/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/remote/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/remote/device/__init__.py b/build/android/pylib/remote/device/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/remote/device/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/remote/device/appurify_constants.py b/build/android/pylib/remote/device/appurify_constants.py
new file mode 100644
index 0000000..9343178
--- /dev/null
+++ b/build/android/pylib/remote/device/appurify_constants.py
@@ -0,0 +1,57 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines a set of constants specific to appurify."""
+
+# Appurify network config constants.
+class NETWORK(object):
+  WIFI_1_BAR = 1
+  SPRINT_4G_LTE_4_BARS = 2
+  SPRINT_3G_5_BARS = 3
+  SPRINT_3G_4_BARS = 4
+  SPRINT_3G_3_BARS = 5
+  SPRINT_3G_2_BARS = 6
+  SPRINT_3G_1_BAR = 7
+  SPRING_4G_1_BAR = 8
+  VERIZON_3G_5_BARS = 9
+  VERIZON_3G_4_BARS = 10
+  VERIZON_3G_3_BARS = 11
+  VERIZON_3G_2_BARS = 12
+  VERIZON_3G_1_BAR = 13
+  VERIZON_4G_1_BAR = 14
+  ATANDT_3G_5_BARS = 15
+  ATANDT_3G_4_BARS = 16
+  ATANDT_3G_3_BARS = 17
+  ATANDT_3G_2_BARS = 18
+  ATANDT_3G_1_BAR = 19
+  GENERIC_2G_4_BARS = 20
+  GENERIC_2G_3_BARS = 21
+  GENERIC_EVOLVED_EDGE = 22
+  GENERIC_GPRS = 23
+  GENERIC_ENHANCED_GPRS = 24
+  GENERIC_LTE = 25
+  GENERIC_HIGH_LATENCY_DNS = 26
+  GENERIC_100_PERCENT_PACKET_LOSS = 27
+  ATANDT_HSPA_PLUS = 28
+  ATANDT_4G_LTE_4_BARS = 29
+  VERIZON_4G_LTE_4_BARS = 30
+  GENERIC_DIGITAL_SUBSCRIBE_LINE = 31
+  WIFI_STARBUCKS_3_BARS = 32
+  WIFI_STARBUCKS_4_BARS = 33
+  WIFI_STARBUCKS_HIGH_TRAFFIC = 34
+  WIFI_TARGET_1_BAR = 35
+  WIFI_TARGET_3_BARS = 36
+  WIFI_TARGET_4_BARS = 37
+  PUBLIC_WIFI_MCDONALDS_5_BARS = 38
+  PUBLIC_WIFI_MCDONALDS_4_BARS = 39
+  PUBLIC_WIFI_MCDONALDS_2_BARS = 40
+  PUBLIC_WIFI_MCDONALDS_1_BAR = 41
+  PUBLIC_WIFI_KOHLS_5_BARS = 42
+  PUBLIC_WIFI_KOHLS_4_BARS = 43
+  PUBLIC_WIFI_KOHLS_2_BARS = 44
+  PUBLIC_WIFI_ATANDT_5_BARS = 45
+  PUBLIC_WIFI_ATANDT_4_BARS = 46
+  PUBLIC_WIFI_ATANDT_2_BARS = 47
+  PUBLIC_WIFI_ATANDT_1_BAR = 48
+  BOINGO = 49
\ No newline at end of file
diff --git a/build/android/pylib/remote/device/appurify_sanitized.py b/build/android/pylib/remote/device/appurify_sanitized.py
new file mode 100644
index 0000000..9f6ab40
--- /dev/null
+++ b/build/android/pylib/remote/device/appurify_sanitized.py
@@ -0,0 +1,40 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import contextlib
+import logging
+import os
+import sys
+
+from pylib import constants
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'requests', 'src'))
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'appurify-python', 'src'))
+handlers_before = list(logging.getLogger().handlers)
+
+import appurify.api
+import appurify.utils
+
+handlers_after = list(logging.getLogger().handlers)
+new_handler = list(set(handlers_after) - set(handlers_before))
+while new_handler:
+  logging.info("Removing logging handler.")
+  logging.getLogger().removeHandler(new_handler.pop())
+
+api = appurify.api
+utils = appurify.utils
+
+# This is not thread safe. If multiple threads are ever supported with appurify
+# this may cause logging messages to go missing.
+@contextlib.contextmanager
+def SanitizeLogging(verbose_count, level):
+  if verbose_count < 2:
+    logging.disable(level)
+    yield True
+    logging.disable(logging.NOTSET)
+  else:
+    yield False
+
diff --git a/build/android/pylib/remote/device/dummy/BUILD.gn b/build/android/pylib/remote/device/dummy/BUILD.gn
new file mode 100644
index 0000000..54ca275
--- /dev/null
+++ b/build/android/pylib/remote/device/dummy/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+# GYP: //build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk
+android_apk("remote_device_dummy_apk") {
+  android_manifest = "//build/android/AndroidManifest.xml"
+  java_files = [ "src/org/chromium/dummy/Dummy.java" ]
+  apk_name = "remote_device_dummy"
+  testonly = true
+}
diff --git a/build/android/pylib/remote/device/dummy/dummy.gyp b/build/android/pylib/remote/device/dummy/dummy.gyp
new file mode 100644
index 0000000..b003edc
--- /dev/null
+++ b/build/android/pylib/remote/device/dummy/dummy.gyp
@@ -0,0 +1,25 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Running gtests on a remote device via am instrument requires both an "app"
+# APK and a "test" APK with different package names. Our gtests only use one
+# APK, so we build a dummy APK to upload as the app.
+
+{
+  'targets': [
+    {
+      # GN: //build/android/pylib/remote/device/dummy:remote_device_dummy_apk
+      'target_name': 'remote_device_dummy_apk',
+      'type': 'none',
+      'variables': {
+        'apk_name': 'remote_device_dummy',
+        'java_in_dir': '.',
+        'android_manifest_path': '../../../../../../build/android/AndroidManifest.xml',
+      },
+      'includes': [
+        '../../../../../../build/java_apk.gypi',
+      ]
+    },
+  ]
+}
diff --git a/build/android/pylib/remote/device/dummy/src/org/chromium/dummy/Dummy.java b/build/android/pylib/remote/device/dummy/src/org/chromium/dummy/Dummy.java
new file mode 100644
index 0000000..1281b39
--- /dev/null
+++ b/build/android/pylib/remote/device/dummy/src/org/chromium/dummy/Dummy.java
@@ -0,0 +1,9 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.dummy;
+
+/** Does nothing. */
+class Dummy {}
+
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
new file mode 100644
index 0000000..dc11845
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -0,0 +1,368 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Environment setup and teardown for remote devices."""
+
+import distutils.version
+import json
+import logging
+import os
+import random
+import sys
+
+from pylib import constants
+from pylib.base import environment
+from pylib.remote.device import appurify_sanitized
+from pylib.remote.device import remote_device_helper
+from pylib.utils import timeout_retry
+from pylib.utils import reraiser_thread
+
+class RemoteDeviceEnvironment(environment.Environment):
+  """An environment for running on remote devices."""
+
+  _ENV_KEY = 'env'
+  _DEVICE_KEY = 'device'
+  _DEFAULT_RETRIES = 0
+
+  def __init__(self, args, error_func):
+    """Constructor.
+
+    Args:
+      args: Command line arguments.
+      error_func: error to show when using bad command line arguments.
+    """
+    super(RemoteDeviceEnvironment, self).__init__()
+    self._access_token = None
+    self._device = None
+    self._device_type = args.device_type
+    self._verbose_count = args.verbose_count
+    self._timeouts = {
+        'queueing': 60 * 10,
+        'installing': 60 * 10,
+        'in-progress': 60 * 30,
+        'unknown': 60 * 5
+    }
+    # Example config file:
+    # {
+    #   "remote_device": ["Galaxy S4", "Galaxy S3"],
+    #   "remote_device_os": ["4.4.2", "4.4.4"],
+    #   "remote_device_minimum_os": "4.4.2",
+    #   "api_address": "www.example.com",
+    #   "api_port": "80",
+    #   "api_protocol": "http",
+    #   "api_secret": "apisecret",
+    #   "api_key": "apikey",
+    #   "timeouts": {
+    #     "queueing": 600,
+    #     "installing": 600,
+    #     "in-progress": 1800,
+    #     "unknown": 300
+    #   }
+    # }
+    if args.remote_device_file:
+      with open(args.remote_device_file) as device_file:
+        device_json = json.load(device_file)
+    else:
+      device_json = {}
+
+    self._api_address = device_json.get('api_address', None)
+    self._api_key = device_json.get('api_key', None)
+    self._api_port = device_json.get('api_port', None)
+    self._api_protocol = device_json.get('api_protocol', None)
+    self._api_secret = device_json.get('api_secret', None)
+    self._device_oem = device_json.get('device_oem', None)
+    self._device_type = device_json.get('device_type', 'Android')
+    self._network_config = device_json.get('network_config', None)
+    self._remote_device = device_json.get('remote_device', None)
+    self._remote_device_minimum_os = device_json.get(
+        'remote_device_minimum_os', None)
+    self._remote_device_os = device_json.get('remote_device_os', None)
+    self._remote_device_timeout = device_json.get(
+        'remote_device_timeout', None)
+    self._results_path = device_json.get('results_path', None)
+    self._runner_package = device_json.get('runner_package', None)
+    self._runner_type = device_json.get('runner_type', None)
+    self._timeouts.update(device_json.get('timeouts', {}))
+
+    def command_line_override(
+        file_value, cmd_line_value, desc, print_value=True):
+      if cmd_line_value:
+        if file_value and file_value != cmd_line_value:
+          if print_value:
+            logging.info('Overriding %s from %s to %s',
+                         desc, file_value, cmd_line_value)
+          else:
+            logging.info('overriding %s', desc)
+        return cmd_line_value
+      return file_value
+
+    self._api_address = command_line_override(
+        self._api_address, args.api_address, 'api_address')
+    self._api_port = command_line_override(
+        self._api_port, args.api_port, 'api_port')
+    self._api_protocol = command_line_override(
+        self._api_protocol, args.api_protocol, 'api_protocol')
+    self._device_oem = command_line_override(
+        self._device_oem, args.device_oem, 'device_oem')
+    self._device_type = command_line_override(
+        self._device_type, args.device_type, 'device_type')
+    self._network_config = command_line_override(
+        self._network_config, args.network_config, 'network_config')
+    self._remote_device = command_line_override(
+        self._remote_device, args.remote_device, 'remote_device')
+    self._remote_device_minimum_os = command_line_override(
+        self._remote_device_minimum_os, args.remote_device_minimum_os,
+        'remote_device_minimum_os')
+    self._remote_device_os = command_line_override(
+        self._remote_device_os, args.remote_device_os, 'remote_device_os')
+    self._remote_device_timeout = command_line_override(
+        self._remote_device_timeout, args.remote_device_timeout,
+        'remote_device_timeout')
+    self._results_path = command_line_override(
+        self._results_path, args.results_path, 'results_path')
+    self._runner_package = command_line_override(
+        self._runner_package, args.runner_package, 'runner_package')
+    self._runner_type = command_line_override(
+        self._runner_type, args.runner_type, 'runner_type')
+
+    if args.api_key_file:
+      with open(args.api_key_file) as api_key_file:
+        temp_key = api_key_file.read().strip()
+        self._api_key = command_line_override(
+            self._api_key, temp_key, 'api_key', print_value=False)
+    self._api_key = command_line_override(
+        self._api_key, args.api_key, 'api_key', print_value=False)
+
+    if args.api_secret_file:
+      with open(args.api_secret_file) as api_secret_file:
+        temp_secret = api_secret_file.read().strip()
+        self._api_secret = command_line_override(
+            self._api_secret, temp_secret, 'api_secret', print_value=False)
+    self._api_secret = command_line_override(
+        self._api_secret, args.api_secret, 'api_secret', print_value=False)
+
+    if not self._api_address:
+      error_func('Must set api address with --api-address'
+                 ' or in --remote-device-file.')
+    if not self._api_key:
+      error_func('Must set api key with --api-key, --api-key-file'
+                 ' or in --remote-device-file')
+    if not self._api_port:
+      error_func('Must set api port with --api-port'
+                 ' or in --remote-device-file')
+    if not self._api_protocol:
+      error_func('Must set api protocol with --api-protocol'
+                 ' or in --remote-device-file. Example: http')
+    if not self._api_secret:
+      error_func('Must set api secret with --api-secret, --api-secret-file'
+                 ' or in --remote-device-file')
+
+    logging.info('Api address: %s', self._api_address)
+    logging.info('Api port: %s', self._api_port)
+    logging.info('Api protocol: %s', self._api_protocol)
+    logging.info('Remote device: %s', self._remote_device)
+    logging.info('Remote device minimum OS: %s',
+                 self._remote_device_minimum_os)
+    logging.info('Remote device OS: %s', self._remote_device_os)
+    logging.info('Remote device OEM: %s', self._device_oem)
+    logging.info('Remote device type: %s', self._device_type)
+    logging.info('Remote device timout: %s', self._remote_device_timeout)
+    logging.info('Results Path: %s', self._results_path)
+    logging.info('Runner package: %s', self._runner_package)
+    logging.info('Runner type: %s', self._runner_type)
+    logging.info('Timeouts: %s', self._timeouts)
+
+    if not args.trigger and not args.collect:
+      self._trigger = True
+      self._collect = True
+    else:
+      self._trigger = args.trigger
+      self._collect = args.collect
+
+  def SetUp(self):
+    """Set up the test environment."""
+    os.environ['APPURIFY_API_PROTO'] = self._api_protocol
+    os.environ['APPURIFY_API_HOST'] = self._api_address
+    os.environ['APPURIFY_API_PORT'] = self._api_port
+    os.environ['APPURIFY_STATUS_BASE_URL'] = 'none'
+    self._GetAccessToken()
+    if self._trigger:
+      self._SelectDevice()
+
+  def TearDown(self):
+    """Teardown the test environment."""
+    self._RevokeAccessToken()
+
+  def __enter__(self):
+    """Set up the test run when used as a context manager."""
+    try:
+      self.SetUp()
+      return self
+    except:
+      self.__exit__(*sys.exc_info())
+      raise
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """Tears down the test run when used as a context manager."""
+    self.TearDown()
+
+  def DumpTo(self, persisted_data):
+    env_data = {
+      self._DEVICE_KEY: self._device,
+    }
+    persisted_data[self._ENV_KEY] = env_data
+
+  def LoadFrom(self, persisted_data):
+    env_data = persisted_data[self._ENV_KEY]
+    self._device = env_data[self._DEVICE_KEY]
+
+  def _GetAccessToken(self):
+    """Generates access token for remote device service."""
+    logging.info('Generating remote service access token')
+    with appurify_sanitized.SanitizeLogging(self._verbose_count,
+                                            logging.WARNING):
+      access_token_results = appurify_sanitized.api.access_token_generate(
+          self._api_key, self._api_secret)
+    remote_device_helper.TestHttpResponse(access_token_results,
+                                          'Unable to generate access token.')
+    self._access_token = access_token_results.json()['response']['access_token']
+
+  def _RevokeAccessToken(self):
+    """Destroys access token for remote device service."""
+    logging.info('Revoking remote service access token')
+    with appurify_sanitized.SanitizeLogging(self._verbose_count,
+                                            logging.WARNING):
+      revoke_token_results = appurify_sanitized.api.access_token_revoke(
+          self._access_token)
+    remote_device_helper.TestHttpResponse(revoke_token_results,
+                                          'Unable to revoke access token.')
+
+  def _SelectDevice(self):
+    if self._remote_device_timeout:
+      try:
+        timeout_retry.Run(self._FindDeviceWithTimeout,
+                          self._remote_device_timeout, self._DEFAULT_RETRIES)
+      except reraiser_thread.TimeoutError:
+        self._NoDeviceFound()
+    else:
+      if not self._FindDevice():
+        self._NoDeviceFound()
+
+  def _FindDevice(self):
+    """Find which device to use."""
+    logging.info('Finding device to run tests on.')
+    device_list = self._GetDeviceList()
+    random.shuffle(device_list)
+    for device in device_list:
+      if device['os_name'] != self._device_type:
+        continue
+      if self._remote_device and device['name'] not in self._remote_device:
+        continue
+      if (self._remote_device_os
+          and device['os_version'] not in self._remote_device_os):
+        continue
+      if self._device_oem and device['brand'] not in self._device_oem:
+        continue
+      if (self._remote_device_minimum_os
+          and distutils.version.LooseVersion(device['os_version'])
+          < distutils.version.LooseVersion(self._remote_device_minimum_os)):
+        continue
+      if device['has_available_device']:
+        logging.info('Found device: %s %s',
+                     device['name'], device['os_version'])
+        self._device = device
+        return True
+    return False
+
+  def _FindDeviceWithTimeout(self):
+    """Find which device to use with timeout."""
+    timeout_retry.WaitFor(self._FindDevice, wait_period=1)
+
+  def _PrintAvailableDevices(self, device_list):
+    def compare_devices(a,b):
+      for key in ('os_version', 'name'):
+        c = cmp(a[key], b[key])
+        if c:
+          return c
+      return 0
+
+    logging.critical('Available %s Devices:', self._device_type)
+    logging.critical(
+        '  %s %s %s %s %s',
+        'OS'.ljust(10),
+        'Device Name'.ljust(30),
+        'Available'.ljust(10),
+        'Busy'.ljust(10),
+        'All'.ljust(10))
+    devices = (d for d in device_list if d['os_name'] == self._device_type)
+    for d in sorted(devices, compare_devices):
+      logging.critical(
+          '  %s %s %s %s %s',
+          d['os_version'].ljust(10),
+          d['name'].ljust(30),
+          str(d['available_devices_count']).ljust(10),
+          str(d['busy_devices_count']).ljust(10),
+          str(d['all_devices_count']).ljust(10))
+
+  def _GetDeviceList(self):
+    with appurify_sanitized.SanitizeLogging(self._verbose_count,
+                                            logging.WARNING):
+      dev_list_res = appurify_sanitized.api.devices_list(self._access_token)
+    remote_device_helper.TestHttpResponse(dev_list_res,
+                                         'Unable to generate access token.')
+    return dev_list_res.json()['response']
+
+  def _NoDeviceFound(self):
+    self._PrintAvailableDevices(self._GetDeviceList())
+    raise remote_device_helper.RemoteDeviceError(
+        'No device found.', is_infra_error=True)
+
+  @property
+  def collect(self):
+    return self._collect
+
+  @property
+  def device_type_id(self):
+    return self._device['device_type_id']
+
+  @property
+  def network_config(self):
+    return self._network_config
+
+  @property
+  def only_output_failures(self):
+    # TODO(jbudorick): Remove this once b/18981674 is fixed.
+    return True
+
+  @property
+  def results_path(self):
+    return self._results_path
+
+  @property
+  def runner_package(self):
+    return self._runner_package
+
+  @property
+  def runner_type(self):
+    return self._runner_type
+
+  @property
+  def timeouts(self):
+    return self._timeouts
+
+  @property
+  def token(self):
+    return self._access_token
+
+  @property
+  def trigger(self):
+    return self._trigger
+
+  @property
+  def verbose_count(self):
+    return self._verbose_count
+
+  @property
+  def device_type(self):
+    return self._device_type
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py
new file mode 100644
index 0000000..4c645b0
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -0,0 +1,87 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Run specific test on specific environment."""
+
+import logging
+import os
+import sys
+import tempfile
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.remote.device import appurify_sanitized
+from pylib.remote.device import remote_device_test_run
+from pylib.remote.device import remote_device_helper
+
+
+_EXTRA_COMMAND_LINE_FILE = (
+    'org.chromium.native_test.NativeTestActivity.CommandLineFile')
+# TODO(jbudorick): Remove this extra when b/18981674 is fixed.
+_EXTRA_ONLY_OUTPUT_FAILURES = (
+    'org.chromium.native_test.NativeTestInstrumentationTestRunner.'
+        'OnlyOutputFailures')
+
+
+class RemoteDeviceGtestTestRun(remote_device_test_run.RemoteDeviceTestRun):
+  """Run gtests and uirobot tests on a remote device."""
+
+  DEFAULT_RUNNER_PACKAGE = (
+      'org.chromium.native_test.NativeTestInstrumentationTestRunner')
+
+  #override
+  def TestPackage(self):
+    return self._test_instance.suite
+
+  #override
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    logging.info('Triggering test run.')
+
+    if self._env.runner_type:
+      logging.warning('Ignoring configured runner_type "%s"',
+                      self._env.runner_type)
+
+    if not self._env.runner_package:
+      runner_package = self.DEFAULT_RUNNER_PACKAGE
+      logging.info('Using default runner package: %s',
+                   self.DEFAULT_RUNNER_PACKAGE)
+    else:
+      runner_package = self._env.runner_package
+
+    dummy_app_path = os.path.join(
+        constants.GetOutDirectory(), 'apks', 'remote_device_dummy.apk')
+    with tempfile.NamedTemporaryFile(suffix='.flags.txt') as flag_file:
+      env_vars = {}
+      filter_string = self._test_instance._GenerateDisabledFilterString(None)
+      if filter_string:
+        flag_file.write('_ --gtest_filter=%s' % filter_string)
+        flag_file.flush()
+        env_vars[_EXTRA_COMMAND_LINE_FILE] = os.path.basename(flag_file.name)
+        self._test_instance._data_deps.append(
+            (os.path.abspath(flag_file.name), None))
+      if self._env.only_output_failures:
+        env_vars[_EXTRA_ONLY_OUTPUT_FAILURES] = None
+      self._AmInstrumentTestSetup(
+          dummy_app_path, self._test_instance.apk, runner_package,
+          environment_variables=env_vars)
+
+  _INSTRUMENTATION_STREAM_LEADER = 'INSTRUMENTATION_STATUS: stream='
+
+  #override
+  def _ParseTestResults(self):
+    logging.info('Parsing results from stdout.')
+    results = base_test_result.TestRunResults()
+    output = self._results['results']['output'].splitlines()
+    output = (l[len(self._INSTRUMENTATION_STREAM_LEADER):] for l in output
+              if l.startswith(self._INSTRUMENTATION_STREAM_LEADER))
+    results_list = self._test_instance.ParseGTestOutput(output)
+    results.AddResults(results_list)
+    if self._env.only_output_failures:
+      logging.info('See logcat for more results information.')
+    if not self._results['results']['pass']:
+      results.AddResult(base_test_result.BaseTestResult(
+          'Remote Service detected error.',
+          base_test_result.ResultType.FAIL))
+    return results
diff --git a/build/android/pylib/remote/device/remote_device_helper.py b/build/android/pylib/remote/device/remote_device_helper.py
new file mode 100644
index 0000000..896ae99
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_helper.py
@@ -0,0 +1,24 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Common functions and Exceptions for remote_device_*"""
+
+from pylib.utils import base_error
+
+
+class RemoteDeviceError(base_error.BaseError):
+  """Exception to throw when problems occur with remote device service."""
+  pass
+
+
+def TestHttpResponse(response, error_msg):
+  """Checks the Http response from remote device service.
+
+  Args:
+      response: response dict from the remote device service.
+      error_msg: Error message to display if bad response is seen.
+  """
+  if response.status_code != 200:
+    raise RemoteDeviceError(
+        '%s (%d: %s)' % (error_msg, response.status_code, response.reason))
diff --git a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
new file mode 100644
index 0000000..bcdb90c
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
@@ -0,0 +1,74 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Run specific test on specific environment."""
+
+import logging
+import os
+import tempfile
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.remote.device import remote_device_test_run
+from pylib.utils import apk_helper
+
+
+class RemoteDeviceInstrumentationTestRun(
+    remote_device_test_run.RemoteDeviceTestRun):
+  """Run instrumentation tests on a remote device."""
+
+  #override
+  def TestPackage(self):
+    return self._test_instance.test_package
+
+  #override
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    logging.info('Triggering test run.')
+
+    with tempfile.NamedTemporaryFile(suffix='.txt') as test_list_file:
+      tests = self._test_instance.GetTests()
+      logging.debug('preparing to run %d instrumentation tests remotely:',
+                    len(tests))
+      for t in tests:
+        test_name = '%s#%s' % (t['class'], t['method'])
+        logging.debug('  %s', test_name)
+        test_list_file.write('%s\n' % test_name)
+      test_list_file.flush()
+      self._test_instance._data_deps.append(
+          (os.path.abspath(test_list_file.name), None))
+
+      env_vars = self._test_instance.GetDriverEnvironmentVars(
+          test_list_file_path=test_list_file.name)
+      env_vars.update(self._test_instance.GetHttpServerEnvironmentVars())
+
+      logging.debug('extras:')
+      for k, v in env_vars.iteritems():
+        logging.debug('  %s: %s', k, v)
+
+      self._AmInstrumentTestSetup(
+          self._test_instance.apk_under_test,
+          self._test_instance.driver_apk,
+          self._test_instance.driver_name,
+          environment_variables=env_vars,
+          extra_apks=[self._test_instance.test_apk])
+
+  #override
+  def _ParseTestResults(self):
+    logging.info('Parsing results from stdout.')
+    r = base_test_result.TestRunResults()
+    result_code, result_bundle, statuses = (
+        self._test_instance.ParseAmInstrumentRawOutput(
+            self._results['results']['output'].splitlines()))
+    result = self._test_instance.GenerateTestResults(
+        result_code, result_bundle, statuses, 0, 0)
+
+    if isinstance(result, base_test_result.BaseTestResult):
+      r.AddResult(result)
+    elif isinstance(result, list):
+      r.AddResults(result)
+    else:
+      raise Exception('Unexpected result type: %s' % type(result).__name__)
+
+    return r
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py
new file mode 100644
index 0000000..60cc735
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -0,0 +1,308 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Run specific test on specific environment."""
+
+import json
+import logging
+import os
+import sys
+import tempfile
+import time
+import zipfile
+
+from pylib import constants
+from pylib.base import test_run
+from pylib.remote.device import appurify_constants
+from pylib.remote.device import appurify_sanitized
+from pylib.remote.device import remote_device_helper
+from pylib.utils import zip_utils
+
+class RemoteDeviceTestRun(test_run.TestRun):
+  """Run tests on a remote device."""
+
+  _TEST_RUN_KEY = 'test_run'
+  _TEST_RUN_ID_KEY = 'test_run_id'
+
+  WAIT_TIME = 5
+  COMPLETE = 'complete'
+  HEARTBEAT_INTERVAL = 300
+
+  def __init__(self, env, test_instance):
+    """Constructor.
+
+    Args:
+      env: Environment the tests will run in.
+      test_instance: The test that will be run.
+    """
+    super(RemoteDeviceTestRun, self).__init__(env, test_instance)
+    self._env = env
+    self._test_instance = test_instance
+    self._app_id = ''
+    self._test_id = ''
+    self._results = ''
+    self._test_run_id = ''
+
+  #override
+  def SetUp(self):
+    """Set up a test run."""
+    if self._env.trigger:
+      self._TriggerSetUp()
+    elif self._env.collect:
+      assert isinstance(self._env.collect, basestring), (
+                        'File for storing test_run_id must be a string.')
+      with open(self._env.collect, 'r') as persisted_data_file:
+        persisted_data = json.loads(persisted_data_file.read())
+        self._env.LoadFrom(persisted_data)
+        self.LoadFrom(persisted_data)
+
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    raise NotImplementedError
+
+  #override
+  def RunTests(self):
+    """Run the test."""
+    if self._env.trigger:
+      with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                              logging.WARNING):
+        test_start_res = appurify_sanitized.api.tests_run(
+            self._env.token, self._env.device_type_id, self._app_id,
+            self._test_id)
+      remote_device_helper.TestHttpResponse(
+        test_start_res, 'Unable to run test.')
+      self._test_run_id = test_start_res.json()['response']['test_run_id']
+      logging.info('Test run id: %s' % self._test_run_id)
+
+    if self._env.collect:
+      current_status = ''
+      timeout_counter = 0
+      heartbeat_counter = 0
+      while self._GetTestStatus(self._test_run_id) != self.COMPLETE:
+        if self._results['detailed_status'] != current_status:
+          logging.info('Test status: %s', self._results['detailed_status'])
+          current_status = self._results['detailed_status']
+          timeout_counter = 0
+          heartbeat_counter = 0
+        if heartbeat_counter > self.HEARTBEAT_INTERVAL:
+          logging.info('Test status: %s', self._results['detailed_status'])
+          heartbeat_counter = 0
+
+        timeout = self._env.timeouts.get(
+            current_status, self._env.timeouts['unknown'])
+        if timeout_counter > timeout:
+          raise remote_device_helper.RemoteDeviceError(
+              'Timeout while in %s state for %s seconds'
+              % (current_status, timeout),
+              is_infra_error=True)
+        time.sleep(self.WAIT_TIME)
+        timeout_counter += self.WAIT_TIME
+        heartbeat_counter += self.WAIT_TIME
+      self._DownloadTestResults(self._env.results_path)
+
+      if self._results['results']['exception']:
+        raise remote_device_helper.RemoteDeviceError(
+            self._results['results']['exception'], is_infra_error=True)
+
+      return self._ParseTestResults()
+
+  #override
+  def TearDown(self):
+    """Tear down the test run."""
+    if self._env.collect:
+      self._CollectTearDown()
+    elif self._env.trigger:
+      assert isinstance(self._env.trigger, basestring), (
+                        'File for storing test_run_id must be a string.')
+      with open(self._env.trigger, 'w') as persisted_data_file:
+        persisted_data = {}
+        self.DumpTo(persisted_data)
+        self._env.DumpTo(persisted_data)
+        persisted_data_file.write(json.dumps(persisted_data))
+
+  def _CollectTearDown(self):
+    if self._GetTestStatus(self._test_run_id) != self.COMPLETE:
+      with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                              logging.WARNING):
+        test_abort_res = appurify_sanitized.api.tests_abort(
+            self._env.token, self._test_run_id, reason='Test runner exiting.')
+      remote_device_helper.TestHttpResponse(test_abort_res,
+                                            'Unable to abort test.')
+
+  def __enter__(self):
+    """Set up the test run when used as a context manager."""
+    self.SetUp()
+    return self
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """Tear down the test run when used as a context manager."""
+    self.TearDown()
+
+  def DumpTo(self, persisted_data):
+    test_run_data = {
+      self._TEST_RUN_ID_KEY: self._test_run_id,
+    }
+    persisted_data[self._TEST_RUN_KEY] = test_run_data
+
+  def LoadFrom(self, persisted_data):
+    test_run_data = persisted_data[self._TEST_RUN_KEY]
+    self._test_run_id = test_run_data[self._TEST_RUN_ID_KEY]
+
+  def _ParseTestResults(self):
+    raise NotImplementedError
+
+  def _GetTestByName(self, test_name):
+    """Gets test_id for specific test.
+
+    Args:
+      test_name: Test to find the ID of.
+    """
+    with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                            logging.WARNING):
+      test_list_res = appurify_sanitized.api.tests_list(self._env.token)
+    remote_device_helper.TestHttpResponse(test_list_res,
+                                          'Unable to get tests list.')
+    for test in test_list_res.json()['response']:
+      if test['test_type'] == test_name:
+        return test['test_id']
+    raise remote_device_helper.RemoteDeviceError(
+        'No test found with name %s' % (test_name))
+
+  def _DownloadTestResults(self, results_path):
+    """Download the test results from remote device service.
+
+    Args:
+      results_path: Path to download appurify results zipfile.
+    """
+    if results_path:
+      logging.info('Downloading results to %s.' % results_path)
+      if not os.path.exists(os.path.dirname(results_path)):
+        os.makedirs(os.path.dirname(results_path))
+      with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                              logging.WARNING):
+        appurify_sanitized.utils.wget(self._results['results']['url'],
+                                      results_path)
+
+  def _GetTestStatus(self, test_run_id):
+    """Checks the state of the test, and sets self._results
+
+    Args:
+      test_run_id: Id of test on on remote service.
+    """
+
+    with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                            logging.WARNING):
+      test_check_res = appurify_sanitized.api.tests_check_result(
+          self._env.token, test_run_id)
+    remote_device_helper.TestHttpResponse(test_check_res,
+                                          'Unable to get test status.')
+    self._results = test_check_res.json()['response']
+    return self._results['status']
+
+  def _AmInstrumentTestSetup(self, app_path, test_path, runner_package,
+                             environment_variables, extra_apks=None):
+    config = {'runner': runner_package}
+    if environment_variables:
+      config['environment_vars'] = ','.join(
+          '%s=%s' % (k, v) for k, v in environment_variables.iteritems())
+
+    self._app_id = self._UploadAppToDevice(app_path)
+
+    data_deps = self._test_instance.GetDataDependencies()
+    if data_deps:
+      with tempfile.NamedTemporaryFile(suffix='.zip') as test_with_deps:
+        sdcard_files = []
+        additional_apks = []
+        host_test = os.path.basename(test_path)
+        with zipfile.ZipFile(test_with_deps.name, 'w') as zip_file:
+          zip_file.write(test_path, host_test, zipfile.ZIP_DEFLATED)
+          for h, _ in data_deps:
+            if os.path.isdir(h):
+              zip_utils.WriteToZipFile(zip_file, h, '.')
+              sdcard_files.extend(os.listdir(h))
+            else:
+              zip_utils.WriteToZipFile(zip_file, h, os.path.basename(h))
+              sdcard_files.append(os.path.basename(h))
+          for a in extra_apks or ():
+            zip_utils.WriteToZipFile(zip_file, a, os.path.basename(a));
+            additional_apks.append(os.path.basename(a))
+
+        config['sdcard_files'] = ','.join(sdcard_files)
+        config['host_test'] = host_test
+        if additional_apks:
+          config['additional_apks'] = ','.join(additional_apks)
+        self._test_id = self._UploadTestToDevice(
+            'robotium', test_with_deps.name, app_id=self._app_id)
+    else:
+      self._test_id = self._UploadTestToDevice('robotium', test_path)
+
+    logging.info('Setting config: %s' % config)
+    appurify_configs = {}
+    if self._env.network_config:
+      appurify_configs['network'] = self._env.network_config
+    self._SetTestConfig('robotium', config, **appurify_configs)
+
+  def _UploadAppToDevice(self, app_path):
+    """Upload app to device."""
+    logging.info('Uploading %s to remote service as %s.', app_path,
+                 self._test_instance.suite)
+    with open(app_path, 'rb') as apk_src:
+      with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                              logging.WARNING):
+        upload_results = appurify_sanitized.api.apps_upload(
+            self._env.token, apk_src, 'raw', name=self._test_instance.suite)
+      remote_device_helper.TestHttpResponse(
+          upload_results, 'Unable to upload %s.' % app_path)
+      return upload_results.json()['response']['app_id']
+
+  def _UploadTestToDevice(self, test_type, test_path, app_id=None):
+    """Upload test to device
+    Args:
+      test_type: Type of test that is being uploaded. Ex. uirobot, gtest..
+    """
+    logging.info('Uploading %s to remote service.' % test_path)
+    with open(test_path, 'rb') as test_src:
+      with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                              logging.WARNING):
+        upload_results = appurify_sanitized.api.tests_upload(
+            self._env.token, test_src, 'raw', test_type, app_id=app_id)
+      remote_device_helper.TestHttpResponse(upload_results,
+          'Unable to upload %s.' % test_path)
+      return upload_results.json()['response']['test_id']
+
+  def _SetTestConfig(self, runner_type, runner_configs,
+                     network=appurify_constants.NETWORK.WIFI_1_BAR,
+                     pcap=0, profiler=0, videocapture=0):
+    """Generates and uploads config file for test.
+    Args:
+      runner_configs: Configs specific to the runner you are using.
+      network: Config to specify the network environment the devices running
+          the tests will be in.
+      pcap: Option to set the recording the of network traffic from the device.
+      profiler: Option to set the recording of CPU, memory, and network
+          transfer usage in the tests.
+      videocapture: Option to set video capture during the tests.
+
+    """
+    logging.info('Generating config file for test.')
+    with tempfile.TemporaryFile() as config:
+      config_data = [
+          '[appurify]',
+          'network=%s' % network,
+          'pcap=%s' % pcap,
+          'profiler=%s' % profiler,
+          'videocapture=%s' % videocapture,
+          '[%s]' % runner_type
+      ]
+      config_data.extend(
+          '%s=%s' % (k, v) for k, v in runner_configs.iteritems())
+      config.write(''.join('%s\n' % l for l in config_data))
+      config.flush()
+      config.seek(0)
+      with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                              logging.WARNING):
+        config_response = appurify_sanitized.api.config_upload(
+            self._env.token, config, self._test_id)
+      remote_device_helper.TestHttpResponse(
+          config_response, 'Unable to upload test config.')
diff --git a/build/android/pylib/remote/device/remote_device_uirobot_test_run.py b/build/android/pylib/remote/device/remote_device_uirobot_test_run.py
new file mode 100644
index 0000000..f818c98
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_uirobot_test_run.py
@@ -0,0 +1,88 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Run specific test on specific environment."""
+
+import logging
+import os
+import sys
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.remote.device import appurify_sanitized
+from pylib.remote.device import remote_device_test_run
+from pylib.remote.device import remote_device_helper
+
+
+class RemoteDeviceUirobotTestRun(remote_device_test_run.RemoteDeviceTestRun):
+  """Run uirobot tests on a remote device."""
+
+
+  def __init__(self, env, test_instance):
+    """Constructor.
+
+    Args:
+      env: Environment the tests will run in.
+      test_instance: The test that will be run.
+    """
+    super(RemoteDeviceUirobotTestRun, self).__init__(env, test_instance)
+
+  #override
+  def TestPackage(self):
+    return self._test_instance.package_name
+
+  #override
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    logging.info('Triggering test run.')
+
+    if self._env.device_type == 'Android':
+      default_runner_type = 'android_robot'
+    elif self._env.device_type == 'iOS':
+      default_runner_type = 'ios_robot'
+    else:
+      raise remote_device_helper.RemoteDeviceError(
+          'Unknown device type: %s' % self._env.device_type)
+
+    self._app_id = self._UploadAppToDevice(self._test_instance.app_under_test)
+    if not self._env.runner_type:
+      runner_type = default_runner_type
+      logging.info('Using default runner type: %s', default_runner_type)
+    else:
+      runner_type = self._env.runner_type
+
+    self._test_id = self._UploadTestToDevice(
+        'android_robot', None, app_id=self._app_id)
+    config_body = {'duration': self._test_instance.minutes}
+    self._SetTestConfig(runner_type, config_body)
+
+
+  # TODO(rnephew): Switch to base class implementation when supported.
+  #override
+  def _UploadTestToDevice(self, test_type, test_path, app_id=None):
+    if test_path:
+      logging.info("Ignoring test path.")
+    data = {
+        'access_token':self._env.token,
+        'test_type':test_type,
+        'app_id':app_id,
+    }
+    with appurify_sanitized.SanitizeLogging(self._env.verbose_count,
+                                            logging.WARNING):
+      test_upload_res = appurify_sanitized.utils.post('tests/upload',
+                                                      data, None)
+    remote_device_helper.TestHttpResponse(
+        test_upload_res, 'Unable to get UiRobot test id.')
+    return test_upload_res.json()['response']['test_id']
+
+  #override
+  def _ParseTestResults(self):
+    logging.info('Parsing results from remote service.')
+    results = base_test_result.TestRunResults()
+    if self._results['results']['pass']:
+      result_type = base_test_result.ResultType.PASS
+    else:
+      result_type = base_test_result.ResultType.FAIL
+    results.AddResult(base_test_result.BaseTestResult('uirobot', result_type))
+    return results
diff --git a/build/android/pylib/restart_adbd.sh b/build/android/pylib/restart_adbd.sh
new file mode 100755
index 0000000..393b2eb
--- /dev/null
+++ b/build/android/pylib/restart_adbd.sh
@@ -0,0 +1,20 @@
+#!/system/bin/sh
+
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Android shell script to restart adbd on the device. This has to be run
+# atomically as a shell script because stopping adbd prevents further commands
+# from running (even if called in the same adb shell).
+
+trap '' HUP
+trap '' TERM
+trap '' PIPE
+
+function restart() {
+  stop adbd
+  start adbd
+}
+
+restart &
diff --git a/build/android/pylib/results/__init__.py b/build/android/pylib/results/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/results/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/results/flakiness_dashboard/__init__.py b/build/android/pylib/results/flakiness_dashboard/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/results/flakiness_dashboard/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/pylib/results/flakiness_dashboard/json_results_generator.py b/build/android/pylib/results/flakiness_dashboard/json_results_generator.py
new file mode 100644
index 0000000..e5c433d
--- /dev/null
+++ b/build/android/pylib/results/flakiness_dashboard/json_results_generator.py
@@ -0,0 +1,697 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#
+# Most of this file was ported over from Blink's
+# Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
+# Tools/Scripts/webkitpy/common/net/file_uploader.py
+#
+
+import json
+import logging
+import mimetypes
+import os
+import time
+import urllib2
+
+_log = logging.getLogger(__name__)
+
+_JSON_PREFIX = 'ADD_RESULTS('
+_JSON_SUFFIX = ');'
+
+
+def HasJSONWrapper(string):
+  return string.startswith(_JSON_PREFIX) and string.endswith(_JSON_SUFFIX)
+
+
+def StripJSONWrapper(json_content):
+  # FIXME: Kill this code once the server returns json instead of jsonp.
+  if HasJSONWrapper(json_content):
+    return json_content[len(_JSON_PREFIX):len(json_content) - len(_JSON_SUFFIX)]
+  return json_content
+
+
+def WriteJSON(json_object, file_path, callback=None):
+  # Specify separators in order to get compact encoding.
+  json_string = json.dumps(json_object, separators=(',', ':'))
+  if callback:
+    json_string = callback + '(' + json_string + ');'
+  with open(file_path, 'w') as fp:
+    fp.write(json_string)
+
+
+def ConvertTrieToFlatPaths(trie, prefix=None):
+  """Flattens the trie of paths, prepending a prefix to each."""
+  result = {}
+  for name, data in trie.iteritems():
+    if prefix:
+      name = prefix + '/' + name
+
+    if len(data) and not 'results' in data:
+      result.update(ConvertTrieToFlatPaths(data, name))
+    else:
+      result[name] = data
+
+  return result
+
+
+def AddPathToTrie(path, value, trie):
+  """Inserts a single path and value into a directory trie structure."""
+  if not '/' in path:
+    trie[path] = value
+    return
+
+  directory, _slash, rest = path.partition('/')
+  if not directory in trie:
+    trie[directory] = {}
+  AddPathToTrie(rest, value, trie[directory])
+
+
+def TestTimingsTrie(individual_test_timings):
+  """Breaks a test name into dicts by directory
+
+  foo/bar/baz.html: 1ms
+  foo/bar/baz1.html: 3ms
+
+  becomes
+  foo: {
+      bar: {
+          baz.html: 1,
+          baz1.html: 3
+      }
+  }
+  """
+  trie = {}
+  for test_result in individual_test_timings:
+    test = test_result.test_name
+
+    AddPathToTrie(test, int(1000 * test_result.test_run_time), trie)
+
+  return trie
+
+
+class TestResult(object):
+  """A simple class that represents a single test result."""
+
+  # Test modifier constants.
+  (NONE, FAILS, FLAKY, DISABLED) = range(4)
+
+  def __init__(self, test, failed=False, elapsed_time=0):
+    self.test_name = test
+    self.failed = failed
+    self.test_run_time = elapsed_time
+
+    test_name = test
+    try:
+      test_name = test.split('.')[1]
+    except IndexError:
+      _log.warn('Invalid test name: %s.', test)
+
+    if test_name.startswith('FAILS_'):
+      self.modifier = self.FAILS
+    elif test_name.startswith('FLAKY_'):
+      self.modifier = self.FLAKY
+    elif test_name.startswith('DISABLED_'):
+      self.modifier = self.DISABLED
+    else:
+      self.modifier = self.NONE
+
+  def Fixable(self):
+    return self.failed or self.modifier == self.DISABLED
+
+
+class JSONResultsGeneratorBase(object):
+  """A JSON results generator for generic tests."""
+
+  MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG = 750
+  # Min time (seconds) that will be added to the JSON.
+  MIN_TIME = 1
+
+  # Note that in non-chromium tests those chars are used to indicate
+  # test modifiers (FAILS, FLAKY, etc) but not actual test results.
+  PASS_RESULT = 'P'
+  SKIP_RESULT = 'X'
+  FAIL_RESULT = 'F'
+  FLAKY_RESULT = 'L'
+  NO_DATA_RESULT = 'N'
+
+  MODIFIER_TO_CHAR = {TestResult.NONE: PASS_RESULT,
+                      TestResult.DISABLED: SKIP_RESULT,
+                      TestResult.FAILS: FAIL_RESULT,
+                      TestResult.FLAKY: FLAKY_RESULT}
+
+  VERSION = 4
+  VERSION_KEY = 'version'
+  RESULTS = 'results'
+  TIMES = 'times'
+  BUILD_NUMBERS = 'buildNumbers'
+  TIME = 'secondsSinceEpoch'
+  TESTS = 'tests'
+
+  FIXABLE_COUNT = 'fixableCount'
+  FIXABLE = 'fixableCounts'
+  ALL_FIXABLE_COUNT = 'allFixableCount'
+
+  RESULTS_FILENAME = 'results.json'
+  TIMES_MS_FILENAME = 'times_ms.json'
+  INCREMENTAL_RESULTS_FILENAME = 'incremental_results.json'
+
+  # line too long pylint: disable=line-too-long
+  URL_FOR_TEST_LIST_JSON = (
+      'http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s&master=%s')
+  # pylint: enable=line-too-long
+
+  def __init__(self, builder_name, build_name, build_number,
+               results_file_base_path, builder_base_url,
+               test_results_map, svn_repositories=None,
+               test_results_server=None,
+               test_type='',
+               master_name=''):
+    """Modifies the results.json file. Grabs it off the archive directory
+    if it is not found locally.
+
+    Args
+      builder_name: the builder name (e.g. Webkit).
+      build_name: the build name (e.g. webkit-rel).
+      build_number: the build number.
+      results_file_base_path: Absolute path to the directory containing the
+          results json file.
+      builder_base_url: the URL where we have the archived test results.
+          If this is None no archived results will be retrieved.
+      test_results_map: A dictionary that maps test_name to TestResult.
+      svn_repositories: A (json_field_name, svn_path) pair for SVN
+          repositories that tests rely on.  The SVN revision will be
+          included in the JSON with the given json_field_name.
+      test_results_server: server that hosts test results json.
+      test_type: test type string (e.g. 'layout-tests').
+      master_name: the name of the buildbot master.
+    """
+    self._builder_name = builder_name
+    self._build_name = build_name
+    self._build_number = build_number
+    self._builder_base_url = builder_base_url
+    self._results_directory = results_file_base_path
+
+    self._test_results_map = test_results_map
+    self._test_results = test_results_map.values()
+
+    self._svn_repositories = svn_repositories
+    if not self._svn_repositories:
+      self._svn_repositories = {}
+
+    self._test_results_server = test_results_server
+    self._test_type = test_type
+    self._master_name = master_name
+
+    self._archived_results = None
+
+  def GenerateJSONOutput(self):
+    json_object = self.GetJSON()
+    if json_object:
+      file_path = (
+          os.path.join(
+              self._results_directory,
+              self.INCREMENTAL_RESULTS_FILENAME))
+      WriteJSON(json_object, file_path)
+
+  def GenerateTimesMSFile(self):
+    times = TestTimingsTrie(self._test_results_map.values())
+    file_path = os.path.join(self._results_directory, self.TIMES_MS_FILENAME)
+    WriteJSON(times, file_path)
+
+  def GetJSON(self):
+    """Gets the results for the results.json file."""
+    results_json = {}
+
+    if not results_json:
+      results_json, error = self._GetArchivedJSONResults()
+      if error:
+        # If there was an error don't write a results.json
+        # file at all as it would lose all the information on the
+        # bot.
+        _log.error('Archive directory is inaccessible. Not '
+                   'modifying or clobbering the results.json '
+                   'file: ' + str(error))
+        return None
+
+    builder_name = self._builder_name
+    if results_json and builder_name not in results_json:
+      _log.debug('Builder name (%s) is not in the results.json file.'
+                 % builder_name)
+
+    self._ConvertJSONToCurrentVersion(results_json)
+
+    if builder_name not in results_json:
+      results_json[builder_name] = (
+          self._CreateResultsForBuilderJSON())
+
+    results_for_builder = results_json[builder_name]
+
+    if builder_name:
+      self._InsertGenericMetaData(results_for_builder)
+
+    self._InsertFailureSummaries(results_for_builder)
+
+    # Update the all failing tests with result type and time.
+    tests = results_for_builder[self.TESTS]
+    all_failing_tests = self._GetFailedTestNames()
+    all_failing_tests.update(ConvertTrieToFlatPaths(tests))
+
+    for test in all_failing_tests:
+      self._InsertTestTimeAndResult(test, tests)
+
+    return results_json
+
+  def SetArchivedResults(self, archived_results):
+    self._archived_results = archived_results
+
+  def UploadJSONFiles(self, json_files):
+    """Uploads the given json_files to the test_results_server (if the
+    test_results_server is given)."""
+    if not self._test_results_server:
+      return
+
+    if not self._master_name:
+      _log.error(
+          '--test-results-server was set, but --master-name was not.  Not '
+          'uploading JSON files.')
+      return
+
+    _log.info('Uploading JSON files for builder: %s', self._builder_name)
+    attrs = [('builder', self._builder_name),
+             ('testtype', self._test_type),
+             ('master', self._master_name)]
+
+    files = [(json_file, os.path.join(self._results_directory, json_file))
+             for json_file in json_files]
+
+    url = 'http://%s/testfile/upload' % self._test_results_server
+    # Set uploading timeout in case appengine server is having problems.
+    # 120 seconds are more than enough to upload test results.
+    uploader = _FileUploader(url, 120)
+    try:
+      response = uploader.UploadAsMultipartFormData(files, attrs)
+      if response:
+        if response.code == 200:
+          _log.info('JSON uploaded.')
+        else:
+          _log.debug(
+              "JSON upload failed, %d: '%s'" %
+              (response.code, response.read()))
+      else:
+        _log.error('JSON upload failed; no response returned')
+    except Exception, err:
+      _log.error('Upload failed: %s' % err)
+      return
+
+  def _GetTestTiming(self, test_name):
+    """Returns test timing data (elapsed time) in second
+    for the given test_name."""
+    if test_name in self._test_results_map:
+      # Floor for now to get time in seconds.
+      return int(self._test_results_map[test_name].test_run_time)
+    return 0
+
+  def _GetFailedTestNames(self):
+    """Returns a set of failed test names."""
+    return set([r.test_name for r in self._test_results if r.failed])
+
+  def _GetModifierChar(self, test_name):
+    """Returns a single char (e.g. SKIP_RESULT, FAIL_RESULT,
+    PASS_RESULT, NO_DATA_RESULT, etc) that indicates the test modifier
+    for the given test_name.
+    """
+    if test_name not in self._test_results_map:
+      return self.__class__.NO_DATA_RESULT
+
+    test_result = self._test_results_map[test_name]
+    if test_result.modifier in self.MODIFIER_TO_CHAR.keys():
+      return self.MODIFIER_TO_CHAR[test_result.modifier]
+
+    return self.__class__.PASS_RESULT
+
+  def _get_result_char(self, test_name):
+    """Returns a single char (e.g. SKIP_RESULT, FAIL_RESULT,
+    PASS_RESULT, NO_DATA_RESULT, etc) that indicates the test result
+    for the given test_name.
+    """
+    if test_name not in self._test_results_map:
+      return self.__class__.NO_DATA_RESULT
+
+    test_result = self._test_results_map[test_name]
+    if test_result.modifier == TestResult.DISABLED:
+      return self.__class__.SKIP_RESULT
+
+    if test_result.failed:
+      return self.__class__.FAIL_RESULT
+
+    return self.__class__.PASS_RESULT
+
+  def _GetSVNRevision(self, in_directory):
+    """Returns the svn revision for the given directory.
+
+    Args:
+      in_directory: The directory where svn is to be run.
+    """
+    # This is overridden in flakiness_dashboard_results_uploader.py.
+    raise NotImplementedError()
+
+  def _GetArchivedJSONResults(self):
+    """Download JSON file that only contains test
+    name list from test-results server. This is for generating incremental
+    JSON so the file generated has info for tests that failed before but
+    pass or are skipped from current run.
+
+    Returns (archived_results, error) tuple where error is None if results
+    were successfully read.
+    """
+    results_json = {}
+    old_results = None
+    error = None
+
+    if not self._test_results_server:
+      return {}, None
+
+    results_file_url = (self.URL_FOR_TEST_LIST_JSON %
+                        (urllib2.quote(self._test_results_server),
+                         urllib2.quote(self._builder_name),
+                         self.RESULTS_FILENAME,
+                         urllib2.quote(self._test_type),
+                         urllib2.quote(self._master_name)))
+
+    try:
+      # FIXME: We should talk to the network via a Host object.
+      results_file = urllib2.urlopen(results_file_url)
+      old_results = results_file.read()
+    except urllib2.HTTPError, http_error:
+      # A non-4xx status code means the bot is hosed for some reason
+      # and we can't grab the results.json file off of it.
+      if http_error.code < 400 and http_error.code >= 500:
+        error = http_error
+    except urllib2.URLError, url_error:
+      error = url_error
+
+    if old_results:
+      # Strip the prefix and suffix so we can get the actual JSON object.
+      old_results = StripJSONWrapper(old_results)
+
+      try:
+        results_json = json.loads(old_results)
+      except Exception:
+        _log.debug('results.json was not valid JSON. Clobbering.')
+        # The JSON file is not valid JSON. Just clobber the results.
+        results_json = {}
+    else:
+      _log.debug('Old JSON results do not exist. Starting fresh.')
+      results_json = {}
+
+    return results_json, error
+
+  def _InsertFailureSummaries(self, results_for_builder):
+    """Inserts aggregate pass/failure statistics into the JSON.
+    This method reads self._test_results and generates
+    FIXABLE, FIXABLE_COUNT and ALL_FIXABLE_COUNT entries.
+
+    Args:
+      results_for_builder: Dictionary containing the test results for a
+          single builder.
+    """
+    # Insert the number of tests that failed or skipped.
+    fixable_count = len([r for r in self._test_results if r.Fixable()])
+    self._InsertItemIntoRawList(results_for_builder,
+                                fixable_count, self.FIXABLE_COUNT)
+
+    # Create a test modifiers (FAILS, FLAKY etc) summary dictionary.
+    entry = {}
+    for test_name in self._test_results_map.iterkeys():
+      result_char = self._GetModifierChar(test_name)
+      entry[result_char] = entry.get(result_char, 0) + 1
+
+    # Insert the pass/skip/failure summary dictionary.
+    self._InsertItemIntoRawList(results_for_builder, entry,
+                                self.FIXABLE)
+
+    # Insert the number of all the tests that are supposed to pass.
+    all_test_count = len(self._test_results)
+    self._InsertItemIntoRawList(results_for_builder,
+                                all_test_count, self.ALL_FIXABLE_COUNT)
+
+  def _InsertItemIntoRawList(self, results_for_builder, item, key):
+    """Inserts the item into the list with the given key in the results for
+    this builder. Creates the list if no such list exists.
+
+    Args:
+      results_for_builder: Dictionary containing the test results for a
+          single builder.
+      item: Number or string to insert into the list.
+      key: Key in results_for_builder for the list to insert into.
+    """
+    if key in results_for_builder:
+      raw_list = results_for_builder[key]
+    else:
+      raw_list = []
+
+    raw_list.insert(0, item)
+    raw_list = raw_list[:self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG]
+    results_for_builder[key] = raw_list
+
+  def _InsertItemRunLengthEncoded(self, item, encoded_results):
+    """Inserts the item into the run-length encoded results.
+
+    Args:
+      item: String or number to insert.
+      encoded_results: run-length encoded results. An array of arrays, e.g.
+          [[3,'A'],[1,'Q']] encodes AAAQ.
+    """
+    if len(encoded_results) and item == encoded_results[0][1]:
+      num_results = encoded_results[0][0]
+      if num_results <= self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG:
+        encoded_results[0][0] = num_results + 1
+    else:
+      # Use a list instead of a class for the run-length encoding since
+      # we want the serialized form to be concise.
+      encoded_results.insert(0, [1, item])
+
+  def _InsertGenericMetaData(self, results_for_builder):
+    """ Inserts generic metadata (such as version number, current time etc)
+    into the JSON.
+
+    Args:
+      results_for_builder: Dictionary containing the test results for
+          a single builder.
+    """
+    self._InsertItemIntoRawList(results_for_builder,
+                                self._build_number, self.BUILD_NUMBERS)
+
+    # Include SVN revisions for the given repositories.
+    for (name, path) in self._svn_repositories:
+      # Note: for JSON file's backward-compatibility we use 'chrome' rather
+      # than 'chromium' here.
+      lowercase_name = name.lower()
+      if lowercase_name == 'chromium':
+        lowercase_name = 'chrome'
+      self._InsertItemIntoRawList(results_for_builder,
+                                  self._GetSVNRevision(path),
+                                  lowercase_name + 'Revision')
+
+    self._InsertItemIntoRawList(results_for_builder,
+                                int(time.time()),
+                                self.TIME)
+
+  def _InsertTestTimeAndResult(self, test_name, tests):
+    """ Insert a test item with its results to the given tests dictionary.
+
+    Args:
+      tests: Dictionary containing test result entries.
+    """
+
+    result = self._get_result_char(test_name)
+    test_time = self._GetTestTiming(test_name)
+
+    this_test = tests
+    for segment in test_name.split('/'):
+      if segment not in this_test:
+        this_test[segment] = {}
+      this_test = this_test[segment]
+
+    if not len(this_test):
+      self._PopulateResultsAndTimesJSON(this_test)
+
+    if self.RESULTS in this_test:
+      self._InsertItemRunLengthEncoded(result, this_test[self.RESULTS])
+    else:
+      this_test[self.RESULTS] = [[1, result]]
+
+    if self.TIMES in this_test:
+      self._InsertItemRunLengthEncoded(test_time, this_test[self.TIMES])
+    else:
+      this_test[self.TIMES] = [[1, test_time]]
+
+  def _ConvertJSONToCurrentVersion(self, results_json):
+    """If the JSON does not match the current version, converts it to the
+    current version and adds in the new version number.
+    """
+    if self.VERSION_KEY in results_json:
+      archive_version = results_json[self.VERSION_KEY]
+      if archive_version == self.VERSION:
+        return
+    else:
+      archive_version = 3
+
+    # version 3->4
+    if archive_version == 3:
+      for results in results_json.values():
+        self._ConvertTestsToTrie(results)
+
+    results_json[self.VERSION_KEY] = self.VERSION
+
+  def _ConvertTestsToTrie(self, results):
+    if not self.TESTS in results:
+      return
+
+    test_results = results[self.TESTS]
+    test_results_trie = {}
+    for test in test_results.iterkeys():
+      single_test_result = test_results[test]
+      AddPathToTrie(test, single_test_result, test_results_trie)
+
+    results[self.TESTS] = test_results_trie
+
+  def _PopulateResultsAndTimesJSON(self, results_and_times):
+    results_and_times[self.RESULTS] = []
+    results_and_times[self.TIMES] = []
+    return results_and_times
+
+  def _CreateResultsForBuilderJSON(self):
+    results_for_builder = {}
+    results_for_builder[self.TESTS] = {}
+    return results_for_builder
+
+  def _RemoveItemsOverMaxNumberOfBuilds(self, encoded_list):
+    """Removes items from the run-length encoded list after the final
+    item that exceeds the max number of builds to track.
+
+    Args:
+      encoded_results: run-length encoded results. An array of arrays, e.g.
+          [[3,'A'],[1,'Q']] encodes AAAQ.
+    """
+    num_builds = 0
+    index = 0
+    for result in encoded_list:
+      num_builds = num_builds + result[0]
+      index = index + 1
+      if num_builds > self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG:
+        return encoded_list[:index]
+    return encoded_list
+
+  def _NormalizeResultsJSON(self, test, test_name, tests):
+    """ Prune tests where all runs pass or tests that no longer exist and
+    truncate all results to maxNumberOfBuilds.
+
+    Args:
+      test: ResultsAndTimes object for this test.
+      test_name: Name of the test.
+      tests: The JSON object with all the test results for this builder.
+    """
+    test[self.RESULTS] = self._RemoveItemsOverMaxNumberOfBuilds(
+        test[self.RESULTS])
+    test[self.TIMES] = self._RemoveItemsOverMaxNumberOfBuilds(
+        test[self.TIMES])
+
+    is_all_pass = self._IsResultsAllOfType(test[self.RESULTS],
+                                           self.PASS_RESULT)
+    is_all_no_data = self._IsResultsAllOfType(test[self.RESULTS],
+                                              self.NO_DATA_RESULT)
+    max_time = max([test_time[1] for test_time in test[self.TIMES]])
+
+    # Remove all passes/no-data from the results to reduce noise and
+    # filesize. If a test passes every run, but takes > MIN_TIME to run,
+    # don't throw away the data.
+    if is_all_no_data or (is_all_pass and max_time <= self.MIN_TIME):
+      del tests[test_name]
+
+  # method could be a function pylint: disable=R0201
+  def _IsResultsAllOfType(self, results, result_type):
+    """Returns whether all the results are of the given type
+    (e.g. all passes)."""
+    return len(results) == 1 and results[0][1] == result_type
+
+
+class _FileUploader(object):
+
+  def __init__(self, url, timeout_seconds):
+    self._url = url
+    self._timeout_seconds = timeout_seconds
+
+  def UploadAsMultipartFormData(self, files, attrs):
+    file_objs = []
+    for filename, path in files:
+      with file(path, 'rb') as fp:
+        file_objs.append(('file', filename, fp.read()))
+
+    # FIXME: We should use the same variable names for the formal and actual
+    # parameters.
+    content_type, data = _EncodeMultipartFormData(attrs, file_objs)
+    return self._UploadData(content_type, data)
+
+  def _UploadData(self, content_type, data):
+    start = time.time()
+    end = start + self._timeout_seconds
+    while time.time() < end:
+      try:
+        request = urllib2.Request(self._url, data,
+                                  {'Content-Type': content_type})
+        return urllib2.urlopen(request)
+      except urllib2.HTTPError as e:
+        _log.warn("Received HTTP status %s loading \"%s\".  "
+                  'Retrying in 10 seconds...' % (e.code, e.filename))
+        time.sleep(10)
+
+
+def _GetMIMEType(filename):
+  return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+
+
+# FIXME: Rather than taking tuples, this function should take more
+# structured data.
+def _EncodeMultipartFormData(fields, files):
+  """Encode form fields for multipart/form-data.
+
+  Args:
+    fields: A sequence of (name, value) elements for regular form fields.
+    files: A sequence of (name, filename, value) elements for data to be
+           uploaded as files.
+  Returns:
+    (content_type, body) ready for httplib.HTTP instance.
+
+  Source:
+    http://code.google.com/p/rietveld/source/browse/trunk/upload.py
+  """
+  BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
+  CRLF = '\r\n'
+  lines = []
+
+  for key, value in fields:
+    lines.append('--' + BOUNDARY)
+    lines.append('Content-Disposition: form-data; name="%s"' % key)
+    lines.append('')
+    if isinstance(value, unicode):
+      value = value.encode('utf-8')
+    lines.append(value)
+
+  for key, filename, value in files:
+    lines.append('--' + BOUNDARY)
+    lines.append('Content-Disposition: form-data; name="%s"; '
+                 'filename="%s"' % (key, filename))
+    lines.append('Content-Type: %s' % _GetMIMEType(filename))
+    lines.append('')
+    if isinstance(value, unicode):
+      value = value.encode('utf-8')
+    lines.append(value)
+
+  lines.append('--' + BOUNDARY + '--')
+  lines.append('')
+  body = CRLF.join(lines)
+  content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+  return content_type, body
diff --git a/build/android/pylib/results/flakiness_dashboard/results_uploader.py b/build/android/pylib/results/flakiness_dashboard/results_uploader.py
new file mode 100644
index 0000000..856fa9c
--- /dev/null
+++ b/build/android/pylib/results/flakiness_dashboard/results_uploader.py
@@ -0,0 +1,178 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Uploads the results to the flakiness dashboard server."""
+# pylint: disable=E1002,R0201
+
+import logging
+import os
+import shutil
+import tempfile
+import xml
+
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.results.flakiness_dashboard import json_results_generator
+from pylib.utils import repo_utils
+
+
+
+class JSONResultsGenerator(json_results_generator.JSONResultsGeneratorBase):
+  """Writes test results to a JSON file and handles uploading that file to
+  the test results server.
+  """
+  def __init__(self, builder_name, build_name, build_number, tmp_folder,
+               test_results_map, test_results_server, test_type, master_name):
+    super(JSONResultsGenerator, self).__init__(
+        builder_name=builder_name,
+        build_name=build_name,
+        build_number=build_number,
+        results_file_base_path=tmp_folder,
+        builder_base_url=None,
+        test_results_map=test_results_map,
+        svn_repositories=(('webkit', 'third_party/WebKit'),
+                          ('chrome', '.')),
+        test_results_server=test_results_server,
+        test_type=test_type,
+        master_name=master_name)
+
+  #override
+  def _GetModifierChar(self, test_name):
+    if test_name not in self._test_results_map:
+      return self.__class__.NO_DATA_RESULT
+
+    return self._test_results_map[test_name].modifier
+
+  #override
+  def _GetSVNRevision(self, in_directory):
+    """Returns the git/svn revision for the given directory.
+
+    Args:
+      in_directory: The directory relative to src.
+    """
+    def _is_git_directory(in_directory):
+      """Returns true if the given directory is in a git repository.
+
+      Args:
+        in_directory: The directory path to be tested.
+      """
+      if os.path.exists(os.path.join(in_directory, '.git')):
+        return True
+      parent = os.path.dirname(in_directory)
+      if parent == constants.DIR_SOURCE_ROOT or parent == in_directory:
+        return False
+      return _is_git_directory(parent)
+
+    in_directory = os.path.join(constants.DIR_SOURCE_ROOT, in_directory)
+
+    if not os.path.exists(os.path.join(in_directory, '.svn')):
+      if _is_git_directory(in_directory):
+        return repo_utils.GetGitHeadSHA1(in_directory)
+      else:
+        return ''
+
+    output = cmd_helper.GetCmdOutput(['svn', 'info', '--xml'], cwd=in_directory)
+    try:
+      dom = xml.dom.minidom.parseString(output)
+      return dom.getElementsByTagName('entry')[0].getAttribute('revision')
+    except xml.parsers.expat.ExpatError:
+      return ''
+    return ''
+
+
+class ResultsUploader(object):
+  """Handles uploading buildbot tests results to the flakiness dashboard."""
+  def __init__(self, tests_type):
+    self._build_number = os.environ.get('BUILDBOT_BUILDNUMBER')
+    self._builder_name = os.environ.get('BUILDBOT_BUILDERNAME')
+    self._tests_type = tests_type
+
+    if not self._build_number or not self._builder_name:
+      raise Exception('You should not be uploading tests results to the server'
+                      'from your local machine.')
+
+    upstream = (tests_type != 'Chromium_Android_Instrumentation')
+    if upstream:
+      # TODO(frankf): Use factory properties (see buildbot/bb_device_steps.py)
+      # This requires passing the actual master name (e.g. 'ChromiumFYI' not
+      # 'chromium.fyi').
+      from slave import slave_utils # pylint: disable=F0401
+      self._build_name = slave_utils.SlaveBuildName(constants.DIR_SOURCE_ROOT)
+      self._master_name = slave_utils.GetActiveMaster()
+    else:
+      self._build_name = 'chromium-android'
+      buildbot_branch = os.environ.get('BUILDBOT_BRANCH')
+      if not buildbot_branch:
+        buildbot_branch = 'master'
+      self._master_name = '%s-%s' % (self._build_name, buildbot_branch)
+
+    self._test_results_map = {}
+
+  def AddResults(self, test_results):
+    # TODO(frankf): Differentiate between fail/crash/timeouts.
+    conversion_map = [
+        (test_results.GetPass(), False,
+            json_results_generator.JSONResultsGeneratorBase.PASS_RESULT),
+        (test_results.GetFail(), True,
+            json_results_generator.JSONResultsGeneratorBase.FAIL_RESULT),
+        (test_results.GetCrash(), True,
+            json_results_generator.JSONResultsGeneratorBase.FAIL_RESULT),
+        (test_results.GetTimeout(), True,
+            json_results_generator.JSONResultsGeneratorBase.FAIL_RESULT),
+        (test_results.GetUnknown(), True,
+            json_results_generator.JSONResultsGeneratorBase.NO_DATA_RESULT),
+        ]
+
+    for results_list, failed, modifier in conversion_map:
+      for single_test_result in results_list:
+        test_result = json_results_generator.TestResult(
+            test=single_test_result.GetName(),
+            failed=failed,
+            elapsed_time=single_test_result.GetDuration() / 1000)
+        # The WebKit TestResult object sets the modifier it based on test name.
+        # Since we don't use the same test naming convention as WebKit the
+        # modifier will be wrong, so we need to overwrite it.
+        test_result.modifier = modifier
+
+        self._test_results_map[single_test_result.GetName()] = test_result
+
+  def Upload(self, test_results_server):
+    if not self._test_results_map:
+      return
+
+    tmp_folder = tempfile.mkdtemp()
+
+    try:
+      results_generator = JSONResultsGenerator(
+          builder_name=self._builder_name,
+          build_name=self._build_name,
+          build_number=self._build_number,
+          tmp_folder=tmp_folder,
+          test_results_map=self._test_results_map,
+          test_results_server=test_results_server,
+          test_type=self._tests_type,
+          master_name=self._master_name)
+
+      json_files = ["incremental_results.json", "times_ms.json"]
+      results_generator.GenerateJSONOutput()
+      results_generator.GenerateTimesMSFile()
+      results_generator.UploadJSONFiles(json_files)
+    except Exception as e:
+      logging.error("Uploading results to test server failed: %s." % e)
+    finally:
+      shutil.rmtree(tmp_folder)
+
+
+def Upload(results, flakiness_dashboard_server, test_type):
+  """Reports test results to the flakiness dashboard for Chrome for Android.
+
+  Args:
+    results: test results.
+    flakiness_dashboard_server: the server to upload the results to.
+    test_type: the type of the tests (as displayed by the flakiness dashboard).
+  """
+  uploader = ResultsUploader(test_type)
+  uploader.AddResults(results)
+  uploader.Upload(flakiness_dashboard_server)
diff --git a/build/android/pylib/results/json_results.py b/build/android/pylib/results/json_results.py
new file mode 100644
index 0000000..65664e3
--- /dev/null
+++ b/build/android/pylib/results/json_results.py
@@ -0,0 +1,139 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import logging
+
+from pylib.base import base_test_result
+
+
+def GenerateResultsDict(test_run_result):
+  """Create a results dict from |test_run_result| suitable for writing to JSON.
+  Args:
+    test_run_result: a base_test_result.TestRunResults object.
+  Returns:
+    A results dict that mirrors the one generated by
+      base/test/launcher/test_results_tracker.cc:SaveSummaryAsJSON.
+  """
+  # Example json output.
+  # {
+  #   "global_tags": [],
+  #   "all_tests": [
+  #     "test1",
+  #     "test2",
+  #    ],
+  #   "disabled_tests": [],
+  #   "per_iteration_data": [
+  #     {
+  #       "test1": [
+  #         {
+  #           "status": "SUCCESS",
+  #           "elapsed_time_ms": 1,
+  #           "output_snippet": "",
+  #           "output_snippet_base64": "",
+  #           "losless_snippet": "",
+  #         },
+  #       ],
+  #       "test2": [
+  #         {
+  #           "status": "FAILURE",
+  #           "elapsed_time_ms": 12,
+  #           "output_snippet": "",
+  #           "output_snippet_base64": "",
+  #           "losless_snippet": "",
+  #         },
+  #       ],
+  #     },
+  #   ],
+  # }
+
+  assert isinstance(test_run_result, base_test_result.TestRunResults)
+
+  def status_as_string(s):
+    if s == base_test_result.ResultType.PASS:
+      return 'SUCCESS'
+    elif s == base_test_result.ResultType.SKIP:
+      return 'SKIPPED'
+    elif s == base_test_result.ResultType.FAIL:
+      return 'FAILURE'
+    elif s == base_test_result.ResultType.CRASH:
+      return 'CRASH'
+    elif s == base_test_result.ResultType.TIMEOUT:
+      return 'TIMEOUT'
+    elif s == base_test_result.ResultType.UNKNOWN:
+      return 'UNKNOWN'
+
+  def generate_iteration_data(t):
+    return {
+      t.GetName(): [
+        {
+          'status': status_as_string(t.GetType()),
+          'elapsed_time_ms': t.GetDuration(),
+          'output_snippet': '',
+          'losless_snippet': '',
+          'output_snippet_base64:': '',
+        }
+      ]
+    }
+
+  all_tests_tuple, per_iteration_data_tuple = zip(
+      *[(t.GetName(), generate_iteration_data(t))
+        for t in test_run_result.GetAll()])
+
+  return {
+    'global_tags': [],
+    'all_tests': list(all_tests_tuple),
+    # TODO(jbudorick): Add support for disabled tests within base_test_result.
+    'disabled_tests': [],
+    'per_iteration_data': list(per_iteration_data_tuple),
+  }
+
+
+def GenerateJsonResultsFile(test_run_result, file_path):
+  """Write |test_run_result| to JSON.
+
+  This emulates the format of the JSON emitted by
+  base/test/launcher/test_results_tracker.cc:SaveSummaryAsJSON.
+
+  Args:
+    test_run_result: a base_test_result.TestRunResults object.
+    file_path: The path to the JSON file to write.
+  """
+  with open(file_path, 'w') as json_result_file:
+    json_result_file.write(json.dumps(GenerateResultsDict(test_run_result)))
+
+
+def ParseResultsFromJson(json_results):
+  """Creates a list of BaseTestResult objects from JSON.
+
+  Args:
+    json_results: A JSON dict in the format created by
+                  GenerateJsonResultsFile.
+  """
+
+  def string_as_status(s):
+    if s == 'SUCCESS':
+      return base_test_result.ResultType.PASS
+    elif s == 'SKIPPED':
+      return base_test_result.ResultType.SKIP
+    elif s == 'FAILURE':
+      return base_test_result.ResultType.FAIL
+    elif s == 'CRASH':
+      return base_test_result.ResultType.CRASH
+    elif s == 'TIMEOUT':
+      return base_test_result.ResultType.TIMEOUT
+    else:
+      return base_test_result.ResultType.UNKNOWN
+
+  results_list = []
+  testsuite_runs = json_results['per_iteration_data']
+  for testsuite_run in testsuite_runs:
+    for test, test_runs in testsuite_run.iteritems():
+      results_list.extend(
+          [base_test_result.BaseTestResult(test,
+                                           string_as_status(tr['status']),
+                                           duration=tr['elapsed_time_ms'])
+          for tr in test_runs])
+  return results_list
+
diff --git a/build/android/pylib/results/json_results_test.py b/build/android/pylib/results/json_results_test.py
new file mode 100755
index 0000000..1bc730d
--- /dev/null
+++ b/build/android/pylib/results/json_results_test.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 unittest
+
+from pylib.base import base_test_result
+from pylib.results import json_results
+
+
+class JsonResultsTest(unittest.TestCase):
+
+  def testGenerateResultsDict_passedResult(self):
+    result = base_test_result.BaseTestResult(
+        'test.package.TestName', base_test_result.ResultType.PASS)
+
+    all_results = base_test_result.TestRunResults()
+    all_results.AddResult(result)
+
+    results_dict = json_results.GenerateResultsDict(all_results)
+    self.assertEquals(
+        ['test.package.TestName'],
+        results_dict['all_tests'])
+    self.assertEquals(1, len(results_dict['per_iteration_data']))
+
+    iteration_result = results_dict['per_iteration_data'][0]
+    self.assertTrue('test.package.TestName' in iteration_result)
+    self.assertEquals(1, len(iteration_result['test.package.TestName']))
+
+    test_iteration_result = iteration_result['test.package.TestName'][0]
+    self.assertTrue('status' in test_iteration_result)
+    self.assertEquals('SUCCESS', test_iteration_result['status'])
+
+  def testGenerateResultsDict_skippedResult(self):
+    result = base_test_result.BaseTestResult(
+        'test.package.TestName', base_test_result.ResultType.SKIP)
+
+    all_results = base_test_result.TestRunResults()
+    all_results.AddResult(result)
+
+    results_dict = json_results.GenerateResultsDict(all_results)
+    self.assertEquals(
+        ['test.package.TestName'],
+        results_dict['all_tests'])
+    self.assertEquals(1, len(results_dict['per_iteration_data']))
+
+    iteration_result = results_dict['per_iteration_data'][0]
+    self.assertTrue('test.package.TestName' in iteration_result)
+    self.assertEquals(1, len(iteration_result['test.package.TestName']))
+
+    test_iteration_result = iteration_result['test.package.TestName'][0]
+    self.assertTrue('status' in test_iteration_result)
+    self.assertEquals('SKIPPED', test_iteration_result['status'])
+
+  def testGenerateResultsDict_failedResult(self):
+    result = base_test_result.BaseTestResult(
+        'test.package.TestName', base_test_result.ResultType.FAIL)
+
+    all_results = base_test_result.TestRunResults()
+    all_results.AddResult(result)
+
+    results_dict = json_results.GenerateResultsDict(all_results)
+    self.assertEquals(
+        ['test.package.TestName'],
+        results_dict['all_tests'])
+    self.assertEquals(1, len(results_dict['per_iteration_data']))
+
+    iteration_result = results_dict['per_iteration_data'][0]
+    self.assertTrue('test.package.TestName' in iteration_result)
+    self.assertEquals(1, len(iteration_result['test.package.TestName']))
+
+    test_iteration_result = iteration_result['test.package.TestName'][0]
+    self.assertTrue('status' in test_iteration_result)
+    self.assertEquals('FAILURE', test_iteration_result['status'])
+
+  def testGenerateResultsDict_duration(self):
+    result = base_test_result.BaseTestResult(
+        'test.package.TestName', base_test_result.ResultType.PASS, duration=123)
+
+    all_results = base_test_result.TestRunResults()
+    all_results.AddResult(result)
+
+    results_dict = json_results.GenerateResultsDict(all_results)
+    self.assertEquals(
+        ['test.package.TestName'],
+        results_dict['all_tests'])
+    self.assertEquals(1, len(results_dict['per_iteration_data']))
+
+    iteration_result = results_dict['per_iteration_data'][0]
+    self.assertTrue('test.package.TestName' in iteration_result)
+    self.assertEquals(1, len(iteration_result['test.package.TestName']))
+
+    test_iteration_result = iteration_result['test.package.TestName'][0]
+    self.assertTrue('elapsed_time_ms' in test_iteration_result)
+    self.assertEquals(123, test_iteration_result['elapsed_time_ms'])
+
+  def testGenerateResultsDict_multipleResults(self):
+    result1 = base_test_result.BaseTestResult(
+        'test.package.TestName1', base_test_result.ResultType.PASS)
+    result2 = base_test_result.BaseTestResult(
+        'test.package.TestName2', base_test_result.ResultType.PASS)
+
+    all_results = base_test_result.TestRunResults()
+    all_results.AddResult(result1)
+    all_results.AddResult(result2)
+
+    results_dict = json_results.GenerateResultsDict(all_results)
+    self.assertEquals(
+        ['test.package.TestName1', 'test.package.TestName2'],
+        results_dict['all_tests'])
+    self.assertEquals(2, len(results_dict['per_iteration_data']))
+
+    expected_tests = set([
+        'test.package.TestName1',
+        'test.package.TestName2',
+    ])
+
+    for iteration_result in results_dict['per_iteration_data']:
+      self.assertEquals(1, len(iteration_result))
+      name = iteration_result.keys()[0]
+      self.assertTrue(name in expected_tests)
+      expected_tests.remove(name)
+      self.assertEquals(1, len(iteration_result[name]))
+
+      test_iteration_result = iteration_result[name][0]
+      self.assertTrue('status' in test_iteration_result)
+      self.assertEquals('SUCCESS', test_iteration_result['status'])
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/results/report_results.py b/build/android/pylib/results/report_results.py
new file mode 100644
index 0000000..4c9518e
--- /dev/null
+++ b/build/android/pylib/results/report_results.py
@@ -0,0 +1,112 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Module containing utility functions for reporting results."""
+
+import logging
+import os
+import re
+
+from pylib import constants
+from pylib.results.flakiness_dashboard import results_uploader
+
+
+def _LogToFile(results, test_type, suite_name):
+  """Log results to local files which can be used for aggregation later."""
+  log_file_path = os.path.join(constants.GetOutDirectory(), 'test_logs')
+  if not os.path.exists(log_file_path):
+    os.mkdir(log_file_path)
+  full_file_name = os.path.join(
+      log_file_path, re.sub(r'\W', '_', test_type).lower() + '.log')
+  if not os.path.exists(full_file_name):
+    with open(full_file_name, 'w') as log_file:
+      print >> log_file, '\n%s results for %s build %s:' % (
+          test_type, os.environ.get('BUILDBOT_BUILDERNAME'),
+          os.environ.get('BUILDBOT_BUILDNUMBER'))
+    logging.info('Writing results to %s.' % full_file_name)
+
+  logging.info('Writing results to %s.' % full_file_name)
+  with open(full_file_name, 'a') as log_file:
+    shortened_suite_name = suite_name[:25] + (suite_name[25:] and '...')
+    print >> log_file, '%s%s' % (shortened_suite_name.ljust(30),
+                                 results.GetShortForm())
+
+
+def _LogToFlakinessDashboard(results, test_type, test_package,
+                             flakiness_server):
+  """Upload results to the flakiness dashboard"""
+  logging.info('Upload results for test type "%s", test package "%s" to %s' %
+               (test_type, test_package, flakiness_server))
+
+  try:
+    if test_type == 'Instrumentation':
+      if flakiness_server == constants.UPSTREAM_FLAKINESS_SERVER:
+        assert test_package in ['ContentShellTest',
+                                'ChromeShellTest',
+                                'AndroidWebViewTest']
+        dashboard_test_type = ('%s_instrumentation_tests' %
+                               test_package.lower().rstrip('test'))
+      # Downstream server.
+      else:
+        dashboard_test_type = 'Chromium_Android_Instrumentation'
+
+    elif test_type == 'Unit test':
+      dashboard_test_type = test_package
+
+    else:
+      logging.warning('Invalid test type')
+      return
+
+    results_uploader.Upload(
+        results, flakiness_server, dashboard_test_type)
+
+  except Exception as e:
+    logging.error(e)
+
+
+def LogFull(results, test_type, test_package, annotation=None,
+            flakiness_server=None):
+  """Log the tests results for the test suite.
+
+  The results will be logged three different ways:
+    1. Log to stdout.
+    2. Log to local files for aggregating multiple test steps
+       (on buildbots only).
+    3. Log to flakiness dashboard (on buildbots only).
+
+  Args:
+    results: An instance of TestRunResults object.
+    test_type: Type of the test (e.g. 'Instrumentation', 'Unit test', etc.).
+    test_package: Test package name (e.g. 'ipc_tests' for gtests,
+                  'ContentShellTest' for instrumentation tests)
+    annotation: If instrumenation test type, this is a list of annotations
+                (e.g. ['Smoke', 'SmallTest']).
+    flakiness_server: If provider, upload the results to flakiness dashboard
+                      with this URL.
+    """
+  if not results.DidRunPass():
+    logging.critical('*' * 80)
+    logging.critical('Detailed Logs')
+    logging.critical('*' * 80)
+    for line in results.GetLogs().splitlines():
+      logging.critical(line)
+  logging.critical('*' * 80)
+  logging.critical('Summary')
+  logging.critical('*' * 80)
+  for line in results.GetGtestForm().splitlines():
+    logging.critical(line)
+  logging.critical('*' * 80)
+
+  if os.environ.get('BUILDBOT_BUILDERNAME'):
+    # It is possible to have multiple buildbot steps for the same
+    # instrumenation test package using different annotations.
+    if annotation and len(annotation) == 1:
+      suite_name = annotation[0]
+    else:
+      suite_name = test_package
+    _LogToFile(results, test_type, suite_name)
+
+    if flakiness_server:
+      _LogToFlakinessDashboard(results, test_type, test_package,
+                               flakiness_server)
diff --git a/build/android/pylib/screenshot.py b/build/android/pylib/screenshot.py
new file mode 100644
index 0000000..0fcc590
--- /dev/null
+++ b/build/android/pylib/screenshot.py
@@ -0,0 +1,99 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import tempfile
+import time
+
+from pylib import cmd_helper
+from pylib import device_signal
+from pylib.device import device_errors
+
+# TODO(jbudorick) Remove once telemetry gets switched over.
+import pylib.android_commands
+import pylib.device.device_utils
+
+
+class VideoRecorder(object):
+  """Records a screen capture video from an Android Device (KitKat or newer).
+
+  Args:
+    device: DeviceUtils instance.
+    host_file: Path to the video file to store on the host.
+    megabits_per_second: Video bitrate in megabits per second. Allowed range
+                         from 0.1 to 100 mbps.
+    size: Video frame size tuple (width, height) or None to use the device
+          default.
+    rotate: If True, the video will be rotated 90 degrees.
+  """
+  def __init__(self, device, megabits_per_second=4, size=None,
+               rotate=False):
+    # TODO(jbudorick) Remove once telemetry gets switched over.
+    if isinstance(device, pylib.android_commands.AndroidCommands):
+      device = pylib.device.device_utils.DeviceUtils(device)
+    self._device = device
+    self._device_file = (
+        '%s/screen-recording.mp4' % device.GetExternalStoragePath())
+    self._recorder = None
+    self._recorder_stdout = None
+    self._is_started = False
+
+    self._args = ['adb']
+    if str(self._device):
+      self._args += ['-s', str(self._device)]
+    self._args += ['shell', 'screenrecord', '--verbose']
+    self._args += ['--bit-rate', str(megabits_per_second * 1000 * 1000)]
+    if size:
+      self._args += ['--size', '%dx%d' % size]
+    if rotate:
+      self._args += ['--rotate']
+    self._args += [self._device_file]
+
+  def Start(self):
+    """Start recording video."""
+    self._recorder_stdout = tempfile.mkstemp()[1]
+    self._recorder = cmd_helper.Popen(
+        self._args, stdout=open(self._recorder_stdout, 'w'))
+    if not self._device.GetPids('screenrecord'):
+      raise RuntimeError('Recording failed. Is your device running Android '
+                         'KitKat or later?')
+
+  def IsStarted(self):
+    if not self._is_started:
+      for line in open(self._recorder_stdout):
+        self._is_started = line.startswith('Content area is ')
+        if self._is_started:
+          break
+    return self._is_started
+
+  def Stop(self):
+    """Stop recording video."""
+    os.remove(self._recorder_stdout)
+    self._is_started = False
+    if not self._recorder:
+      return
+    if not self._device.KillAll('screenrecord', signum=device_signal.SIGINT,
+                                quiet=True):
+      logging.warning('Nothing to kill: screenrecord was not running')
+    self._recorder.wait()
+
+  def Pull(self, host_file=None):
+    """Pull resulting video file from the device.
+
+    Args:
+      host_file: Path to the video file to store on the host.
+    Returns:
+      Output video file name on the host.
+    """
+    # TODO(jbudorick): Merge filename generation with the logic for doing so in
+    # DeviceUtils.
+    host_file_name = (
+        host_file
+        or 'screen-recording-%s.mp4' % time.strftime('%Y%m%dT%H%M%S',
+                                                     time.localtime()))
+    host_file_name = os.path.abspath(host_file_name)
+    self._device.PullFile(self._device_file, host_file_name)
+    self._device.RunShellCommand('rm -f "%s"' % self._device_file)
+    return host_file_name
diff --git a/build/android/pylib/symbols/PRESUBMIT.py b/build/android/pylib/symbols/PRESUBMIT.py
new file mode 100644
index 0000000..b4d94ae
--- /dev/null
+++ b/build/android/pylib/symbols/PRESUBMIT.py
@@ -0,0 +1,21 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+def CommonChecks(input_api, output_api):
+  output = []
+  output.extend(input_api.canned_checks.RunPylint(input_api, output_api))
+  output.extend(input_api.canned_checks.RunUnitTestsInDirectory(
+      input_api,
+      output_api,
+      input_api.PresubmitLocalPath(),
+      whitelist=[r'^.+_unittest\.py$']))
+  return output
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return CommonChecks(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return CommonChecks(input_api, output_api)
\ No newline at end of file
diff --git a/build/android/pylib/symbols/__init__.py b/build/android/pylib/symbols/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/android/pylib/symbols/__init__.py
diff --git a/build/android/pylib/symbols/elf_symbolizer.py b/build/android/pylib/symbols/elf_symbolizer.py
new file mode 100644
index 0000000..374063a
--- /dev/null
+++ b/build/android/pylib/symbols/elf_symbolizer.py
@@ -0,0 +1,467 @@
+# Copyright 2014 The Chromium 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 collections
+import datetime
+import logging
+import multiprocessing
+import os
+import posixpath
+import Queue
+import re
+import subprocess
+import sys
+import threading
+import time
+
+
+# addr2line builds a possibly infinite memory cache that can exhaust
+# the computer's memory if allowed to grow for too long. This constant
+# controls how many lookups we do before restarting the process. 4000
+# gives near peak performance without extreme memory usage.
+ADDR2LINE_RECYCLE_LIMIT = 4000
+
+
+class ELFSymbolizer(object):
+  """An uber-fast (multiprocessing, pipelined and asynchronous) ELF symbolizer.
+
+  This class is a frontend for addr2line (part of GNU binutils), designed to
+  symbolize batches of large numbers of symbols for a given ELF file. It
+  supports sharding symbolization against many addr2line instances and
+  pipelining of multiple requests per each instance (in order to hide addr2line
+  internals and OS pipe latencies).
+
+  The interface exhibited by this class is a very simple asynchronous interface,
+  which is based on the following three methods:
+  - SymbolizeAsync(): used to request (enqueue) resolution of a given address.
+  - The |callback| method: used to communicated back the symbol information.
+  - Join(): called to conclude the batch to gather the last outstanding results.
+  In essence, before the Join method returns, this class will have issued as
+  many callbacks as the number of SymbolizeAsync() calls. In this regard, note
+  that due to multiprocess sharding, callbacks can be delivered out of order.
+
+  Some background about addr2line:
+  - it is invoked passing the elf path in the cmdline, piping the addresses in
+    its stdin and getting results on its stdout.
+  - it has pretty large response times for the first requests, but it
+    works very well in streaming mode once it has been warmed up.
+  - it doesn't scale by itself (on more cores). However, spawning multiple
+    instances at the same time on the same file is pretty efficient as they
+    keep hitting the pagecache and become mostly CPU bound.
+  - it might hang or crash, mostly for OOM. This class deals with both of these
+    problems.
+
+  Despite the "scary" imports and the multi* words above, (almost) no multi-
+  threading/processing is involved from the python viewpoint. Concurrency
+  here is achieved by spawning several addr2line subprocesses and handling their
+  output pipes asynchronously. Therefore, all the code here (with the exception
+  of the Queue instance in Addr2Line) should be free from mind-blowing
+  thread-safety concerns.
+
+  The multiprocess sharding works as follows:
+  The symbolizer tries to use the lowest number of addr2line instances as
+  possible (with respect of |max_concurrent_jobs|) and enqueue all the requests
+  in a single addr2line instance. For few symbols (i.e. dozens) sharding isn't
+  worth the startup cost.
+  The multiprocess logic kicks in as soon as the queues for the existing
+  instances grow. Specifically, once all the existing instances reach the
+  |max_queue_size| bound, a new addr2line instance is kicked in.
+  In the case of a very eager producer (i.e. all |max_concurrent_jobs| instances
+  have a backlog of |max_queue_size|), back-pressure is applied on the caller by
+  blocking the SymbolizeAsync method.
+
+  This module has been deliberately designed to be dependency free (w.r.t. of
+  other modules in this project), to allow easy reuse in external projects.
+  """
+
+  def __init__(self, elf_file_path, addr2line_path, callback, inlines=False,
+      max_concurrent_jobs=None, addr2line_timeout=30, max_queue_size=50,
+      source_root_path=None, strip_base_path=None):
+    """Args:
+      elf_file_path: path of the elf file to be symbolized.
+      addr2line_path: path of the toolchain's addr2line binary.
+      callback: a callback which will be invoked for each resolved symbol with
+          the two args (sym_info, callback_arg). The former is an instance of
+          |ELFSymbolInfo| and contains the symbol information. The latter is an
+          embedder-provided argument which is passed to SymbolizeAsync().
+      inlines: when True, the ELFSymbolInfo will contain also the details about
+          the outer inlining functions. When False, only the innermost function
+          will be provided.
+      max_concurrent_jobs: Max number of addr2line instances spawned.
+          Parallelize responsibly, addr2line is a memory and I/O monster.
+      max_queue_size: Max number of outstanding requests per addr2line instance.
+      addr2line_timeout: Max time (in seconds) to wait for a addr2line response.
+          After the timeout, the instance will be considered hung and respawned.
+      source_root_path: In some toolchains only the name of the source file is
+          is output, without any path information; disambiguation searches
+          through the source directory specified by |source_root_path| argument
+          for files whose name matches, adding the full path information to the
+          output. For example, if the toolchain outputs "unicode.cc" and there
+          is a file called "unicode.cc" located under |source_root_path|/foo,
+          the tool will replace "unicode.cc" with
+          "|source_root_path|/foo/unicode.cc". If there are multiple files with
+          the same name, disambiguation will fail because the tool cannot
+          determine which of the files was the source of the symbol.
+      strip_base_path: Rebases the symbols source paths onto |source_root_path|
+          (i.e replace |strip_base_path| with |source_root_path).
+    """
+    assert(os.path.isfile(addr2line_path)), 'Cannot find ' + addr2line_path
+    self.elf_file_path = elf_file_path
+    self.addr2line_path = addr2line_path
+    self.callback = callback
+    self.inlines = inlines
+    self.max_concurrent_jobs = (max_concurrent_jobs or
+                                min(multiprocessing.cpu_count(), 4))
+    self.max_queue_size = max_queue_size
+    self.addr2line_timeout = addr2line_timeout
+    self.requests_counter = 0  # For generating monotonic request IDs.
+    self._a2l_instances = []  # Up to |max_concurrent_jobs| _Addr2Line inst.
+
+    # If necessary, create disambiguation lookup table
+    self.disambiguate = source_root_path is not None
+    self.disambiguation_table = {}
+    self.strip_base_path = strip_base_path
+    if(self.disambiguate):
+      self.source_root_path = os.path.abspath(source_root_path)
+      self._CreateDisambiguationTable()
+
+    # Create one addr2line instance. More instances will be created on demand
+    # (up to |max_concurrent_jobs|) depending on the rate of the requests.
+    self._CreateNewA2LInstance()
+
+  def SymbolizeAsync(self, addr, callback_arg=None):
+    """Requests symbolization of a given address.
+
+    This method is not guaranteed to return immediately. It generally does, but
+    in some scenarios (e.g. all addr2line instances have full queues) it can
+    block to create back-pressure.
+
+    Args:
+      addr: address to symbolize.
+      callback_arg: optional argument which will be passed to the |callback|."""
+    assert(isinstance(addr, int))
+
+    # Process all the symbols that have been resolved in the meanwhile.
+    # Essentially, this drains all the addr2line(s) out queues.
+    for a2l_to_purge in self._a2l_instances:
+      a2l_to_purge.ProcessAllResolvedSymbolsInQueue()
+      a2l_to_purge.RecycleIfNecessary()
+
+    # Find the best instance according to this logic:
+    # 1. Find an existing instance with the shortest queue.
+    # 2. If all of instances' queues are full, but there is room in the pool,
+    #    (i.e. < |max_concurrent_jobs|) create a new instance.
+    # 3. If there were already |max_concurrent_jobs| instances and all of them
+    #    had full queues, make back-pressure.
+
+    # 1.
+    def _SortByQueueSizeAndReqID(a2l):
+      return (a2l.queue_size, a2l.first_request_id)
+    a2l = min(self._a2l_instances, key=_SortByQueueSizeAndReqID)
+
+    # 2.
+    if (a2l.queue_size >= self.max_queue_size and
+        len(self._a2l_instances) < self.max_concurrent_jobs):
+      a2l = self._CreateNewA2LInstance()
+
+    # 3.
+    if a2l.queue_size >= self.max_queue_size:
+      a2l.WaitForNextSymbolInQueue()
+
+    a2l.EnqueueRequest(addr, callback_arg)
+
+  def Join(self):
+    """Waits for all the outstanding requests to complete and terminates."""
+    for a2l in self._a2l_instances:
+      a2l.WaitForIdle()
+      a2l.Terminate()
+
+  def _CreateNewA2LInstance(self):
+    assert(len(self._a2l_instances) < self.max_concurrent_jobs)
+    a2l = ELFSymbolizer.Addr2Line(self)
+    self._a2l_instances.append(a2l)
+    return a2l
+
+  def _CreateDisambiguationTable(self):
+    """ Non-unique file names will result in None entries"""
+    start_time = time.time()
+    logging.info('Collecting information about available source files...')
+    self.disambiguation_table = {}
+
+    for root, _, filenames in os.walk(self.source_root_path):
+      for f in filenames:
+        self.disambiguation_table[f] = os.path.join(root, f) if (f not in
+                                       self.disambiguation_table) else None
+    logging.info('Finished collecting information about '
+                 'possible files (took %.1f s).',
+                 (time.time() - start_time))
+
+
+  class Addr2Line(object):
+    """A python wrapper around an addr2line instance.
+
+    The communication with the addr2line process looks as follows:
+      [STDIN]         [STDOUT]  (from addr2line's viewpoint)
+    > f001111
+    > f002222
+                    < Symbol::Name(foo, bar) for f001111
+                    < /path/to/source/file.c:line_number
+    > f003333
+                    < Symbol::Name2() for f002222
+                    < /path/to/source/file.c:line_number
+                    < Symbol::Name3() for f003333
+                    < /path/to/source/file.c:line_number
+    """
+
+    SYM_ADDR_RE = re.compile(r'([^:]+):(\?|\d+).*')
+
+    def __init__(self, symbolizer):
+      self._symbolizer = symbolizer
+      self._lib_file_name = posixpath.basename(symbolizer.elf_file_path)
+
+      # The request queue (i.e. addresses pushed to addr2line's stdin and not
+      # yet retrieved on stdout)
+      self._request_queue = collections.deque()
+
+      # This is essentially len(self._request_queue). It has been optimized to a
+      # separate field because turned out to be a perf hot-spot.
+      self.queue_size = 0
+
+      # Keep track of the number of symbols a process has processed to
+      # avoid a single process growing too big and using all the memory.
+      self._processed_symbols_count = 0
+
+      # Objects required to handle the addr2line subprocess.
+      self._proc = None  # Subprocess.Popen(...) instance.
+      self._thread = None  # Threading.thread instance.
+      self._out_queue = None  # Queue.Queue instance (for buffering a2l stdout).
+      self._RestartAddr2LineProcess()
+
+    def EnqueueRequest(self, addr, callback_arg):
+      """Pushes an address to addr2line's stdin (and keeps track of it)."""
+      self._symbolizer.requests_counter += 1  # For global "age" of requests.
+      req_idx = self._symbolizer.requests_counter
+      self._request_queue.append((addr, callback_arg, req_idx))
+      self.queue_size += 1
+      self._WriteToA2lStdin(addr)
+
+    def WaitForIdle(self):
+      """Waits until all the pending requests have been symbolized."""
+      while self.queue_size > 0:
+        self.WaitForNextSymbolInQueue()
+
+    def WaitForNextSymbolInQueue(self):
+      """Waits for the next pending request to be symbolized."""
+      if not self.queue_size:
+        return
+
+      # This outer loop guards against a2l hanging (detecting stdout timeout).
+      while True:
+        start_time = datetime.datetime.now()
+        timeout = datetime.timedelta(seconds=self._symbolizer.addr2line_timeout)
+
+        # The inner loop guards against a2l crashing (checking if it exited).
+        while (datetime.datetime.now() - start_time < timeout):
+          # poll() returns !None if the process exited. a2l should never exit.
+          if self._proc.poll():
+            logging.warning('addr2line crashed, respawning (lib: %s).' %
+                            self._lib_file_name)
+            self._RestartAddr2LineProcess()
+            # TODO(primiano): the best thing to do in this case would be
+            # shrinking the pool size as, very likely, addr2line is crashed
+            # due to low memory (and the respawned one will die again soon).
+
+          try:
+            lines = self._out_queue.get(block=True, timeout=0.25)
+          except Queue.Empty:
+            # On timeout (1/4 s.) repeat the inner loop and check if either the
+            # addr2line process did crash or we waited its output for too long.
+            continue
+
+          # In nominal conditions, we get straight to this point.
+          self._ProcessSymbolOutput(lines)
+          return
+
+        # If this point is reached, we waited more than |addr2line_timeout|.
+        logging.warning('Hung addr2line process, respawning (lib: %s).' %
+                        self._lib_file_name)
+        self._RestartAddr2LineProcess()
+
+    def ProcessAllResolvedSymbolsInQueue(self):
+      """Consumes all the addr2line output lines produced (without blocking)."""
+      if not self.queue_size:
+        return
+      while True:
+        try:
+          lines = self._out_queue.get_nowait()
+        except Queue.Empty:
+          break
+        self._ProcessSymbolOutput(lines)
+
+    def RecycleIfNecessary(self):
+      """Restarts the process if it has been used for too long.
+
+      A long running addr2line process will consume excessive amounts
+      of memory without any gain in performance."""
+      if self._processed_symbols_count >= ADDR2LINE_RECYCLE_LIMIT:
+        self._RestartAddr2LineProcess()
+
+
+    def Terminate(self):
+      """Kills the underlying addr2line process.
+
+      The poller |_thread| will terminate as well due to the broken pipe."""
+      try:
+        self._proc.kill()
+        self._proc.communicate()  # Essentially wait() without risking deadlock.
+      except Exception:  # An exception while terminating? How interesting.
+        pass
+      self._proc = None
+
+    def _WriteToA2lStdin(self, addr):
+      self._proc.stdin.write('%s\n' % hex(addr))
+      if self._symbolizer.inlines:
+        # In the case of inlines we output an extra blank line, which causes
+        # addr2line to emit a (??,??:0) tuple that we use as a boundary marker.
+        self._proc.stdin.write('\n')
+      self._proc.stdin.flush()
+
+    def _ProcessSymbolOutput(self, lines):
+      """Parses an addr2line symbol output and triggers the client callback."""
+      (_, callback_arg, _) = self._request_queue.popleft()
+      self.queue_size -= 1
+
+      innermost_sym_info = None
+      sym_info = None
+      for (line1, line2) in lines:
+        prev_sym_info = sym_info
+        name = line1 if not line1.startswith('?') else None
+        source_path = None
+        source_line = None
+        m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2)
+        if m:
+          if not m.group(1).startswith('?'):
+            source_path = m.group(1)
+            if not m.group(2).startswith('?'):
+              source_line = int(m.group(2))
+        else:
+          logging.warning('Got invalid symbol path from addr2line: %s' % line2)
+
+        # In case disambiguation is on, and needed
+        was_ambiguous = False
+        disambiguated = False
+        if self._symbolizer.disambiguate:
+          if source_path and not posixpath.isabs(source_path):
+            path = self._symbolizer.disambiguation_table.get(source_path)
+            was_ambiguous = True
+            disambiguated = path is not None
+            source_path = path if disambiguated else source_path
+
+          # Use absolute paths (so that paths are consistent, as disambiguation
+          # uses absolute paths)
+          if source_path and not was_ambiguous:
+            source_path = os.path.abspath(source_path)
+
+        if source_path and self._symbolizer.strip_base_path:
+          # Strip the base path
+          source_path = re.sub('^' + self._symbolizer.strip_base_path,
+              self._symbolizer.source_root_path or '', source_path)
+
+        sym_info = ELFSymbolInfo(name, source_path, source_line, was_ambiguous,
+                                 disambiguated)
+        if prev_sym_info:
+          prev_sym_info.inlined_by = sym_info
+        if not innermost_sym_info:
+          innermost_sym_info = sym_info
+
+      self._processed_symbols_count += 1
+      self._symbolizer.callback(innermost_sym_info, callback_arg)
+
+    def _RestartAddr2LineProcess(self):
+      if self._proc:
+        self.Terminate()
+
+      # The only reason of existence of this Queue (and the corresponding
+      # Thread below) is the lack of a subprocess.stdout.poll_avail_lines().
+      # Essentially this is a pipe able to extract a couple of lines atomically.
+      self._out_queue = Queue.Queue()
+
+      # Start the underlying addr2line process in line buffered mode.
+
+      cmd = [self._symbolizer.addr2line_path, '--functions', '--demangle',
+          '--exe=' + self._symbolizer.elf_file_path]
+      if self._symbolizer.inlines:
+        cmd += ['--inlines']
+      self._proc = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE,
+          stdin=subprocess.PIPE, stderr=sys.stderr, close_fds=True)
+
+      # Start the poller thread, which simply moves atomically the lines read
+      # from the addr2line's stdout to the |_out_queue|.
+      self._thread = threading.Thread(
+          target=ELFSymbolizer.Addr2Line.StdoutReaderThread,
+          args=(self._proc.stdout, self._out_queue, self._symbolizer.inlines))
+      self._thread.daemon = True  # Don't prevent early process exit.
+      self._thread.start()
+
+      self._processed_symbols_count = 0
+
+      # Replay the pending requests on the new process (only for the case
+      # of a hung addr2line timing out during the game).
+      for (addr, _, _) in self._request_queue:
+        self._WriteToA2lStdin(addr)
+
+    @staticmethod
+    def StdoutReaderThread(process_pipe, queue, inlines):
+      """The poller thread fn, which moves the addr2line stdout to the |queue|.
+
+      This is the only piece of code not running on the main thread. It merely
+      writes to a Queue, which is thread-safe. In the case of inlines, it
+      detects the ??,??:0 marker and sends the lines atomically, such that the
+      main thread always receives all the lines corresponding to one symbol in
+      one shot."""
+      try:
+        lines_for_one_symbol = []
+        while True:
+          line1 = process_pipe.readline().rstrip('\r\n')
+          line2 = process_pipe.readline().rstrip('\r\n')
+          if not line1 or not line2:
+            break
+          inline_has_more_lines = inlines and (len(lines_for_one_symbol) == 0 or
+                                  (line1 != '??' and line2 != '??:0'))
+          if not inlines or inline_has_more_lines:
+            lines_for_one_symbol += [(line1, line2)]
+          if inline_has_more_lines:
+            continue
+          queue.put(lines_for_one_symbol)
+          lines_for_one_symbol = []
+        process_pipe.close()
+
+      # Every addr2line processes will die at some point, please die silently.
+      except (IOError, OSError):
+        pass
+
+    @property
+    def first_request_id(self):
+      """Returns the request_id of the oldest pending request in the queue."""
+      return self._request_queue[0][2] if self._request_queue else 0
+
+
+class ELFSymbolInfo(object):
+  """The result of the symbolization passed as first arg. of each callback."""
+
+  def __init__(self, name, source_path, source_line, was_ambiguous=False,
+               disambiguated=False):
+    """All the fields here can be None (if addr2line replies with '??')."""
+    self.name = name
+    self.source_path = source_path
+    self.source_line = source_line
+    # In the case of |inlines|=True, the |inlined_by| points to the outer
+    # function inlining the current one (and so on, to form a chain).
+    self.inlined_by = None
+    self.disambiguated = disambiguated
+    self.was_ambiguous = was_ambiguous
+
+  def __str__(self):
+    return '%s [%s:%d]' % (
+        self.name or '??', self.source_path or '??', self.source_line or 0)
diff --git a/build/android/pylib/symbols/elf_symbolizer_unittest.py b/build/android/pylib/symbols/elf_symbolizer_unittest.py
new file mode 100755
index 0000000..e963a34
--- /dev/null
+++ b/build/android/pylib/symbols/elf_symbolizer_unittest.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 functools
+import logging
+import os
+import sys
+import unittest
+
+sys.path.insert(0, os.path.dirname(__file__))
+import elf_symbolizer
+import mock_addr2line
+
+
+_MOCK_A2L_PATH = os.path.join(os.path.dirname(mock_addr2line.__file__),
+                              'mock_addr2line')
+_INCOMPLETE_MOCK_ADDR = 1024 * 1024
+_UNKNOWN_MOCK_ADDR = 2 * 1024 * 1024
+_INLINE_MOCK_ADDR = 3 * 1024 * 1024
+
+
+class ELFSymbolizerTest(unittest.TestCase):
+  def setUp(self):
+    self._callback = functools.partial(
+        ELFSymbolizerTest._SymbolizeCallback, self)
+    self._resolved_addresses = set()
+    # Mute warnings, we expect them due to the crash/hang tests.
+    logging.getLogger().setLevel(logging.ERROR)
+
+  def testParallelism1(self):
+    self._RunTest(max_concurrent_jobs=1, num_symbols=100)
+
+  def testParallelism4(self):
+    self._RunTest(max_concurrent_jobs=4, num_symbols=100)
+
+  def testParallelism8(self):
+    self._RunTest(max_concurrent_jobs=8, num_symbols=100)
+
+  def testCrash(self):
+    os.environ['MOCK_A2L_CRASH_EVERY'] = '99'
+    self._RunTest(max_concurrent_jobs=1, num_symbols=100)
+    os.environ['MOCK_A2L_CRASH_EVERY'] = '0'
+
+  def testHang(self):
+    os.environ['MOCK_A2L_HANG_EVERY'] = '99'
+    self._RunTest(max_concurrent_jobs=1, num_symbols=100)
+    os.environ['MOCK_A2L_HANG_EVERY'] = '0'
+
+  def testInlines(self):
+    """Stimulate the inline processing logic."""
+    symbolizer = elf_symbolizer.ELFSymbolizer(
+        elf_file_path='/path/doesnt/matter/mock_lib1.so',
+        addr2line_path=_MOCK_A2L_PATH,
+        callback=self._callback,
+        inlines=True,
+        max_concurrent_jobs=4)
+
+    for addr in xrange(1000):
+      exp_inline = False
+      exp_unknown = False
+
+      # First 100 addresses with inlines.
+      if addr < 100:
+        addr += _INLINE_MOCK_ADDR
+        exp_inline = True
+
+      # Followed by 100 without inlines.
+      elif addr < 200:
+        pass
+
+      # Followed by 100 interleaved inlines and not inlines.
+      elif addr < 300:
+        if addr & 1:
+          addr += _INLINE_MOCK_ADDR
+          exp_inline = True
+
+      # Followed by 100 interleaved inlines and unknonwn.
+      elif addr < 400:
+        if addr & 1:
+          addr += _INLINE_MOCK_ADDR
+          exp_inline = True
+        else:
+          addr += _UNKNOWN_MOCK_ADDR
+          exp_unknown = True
+
+      exp_name = 'mock_sym_for_addr_%d' % addr if not exp_unknown else None
+      exp_source_path = 'mock_src/mock_lib1.so.c' if not exp_unknown else None
+      exp_source_line = addr if not exp_unknown else None
+      cb_arg = (addr, exp_name, exp_source_path, exp_source_line, exp_inline)
+      symbolizer.SymbolizeAsync(addr, cb_arg)
+
+    symbolizer.Join()
+
+  def testIncompleteSyminfo(self):
+    """Stimulate the symbol-not-resolved logic."""
+    symbolizer = elf_symbolizer.ELFSymbolizer(
+        elf_file_path='/path/doesnt/matter/mock_lib1.so',
+        addr2line_path=_MOCK_A2L_PATH,
+        callback=self._callback,
+        max_concurrent_jobs=1)
+
+    # Test symbols with valid name but incomplete path.
+    addr = _INCOMPLETE_MOCK_ADDR
+    exp_name = 'mock_sym_for_addr_%d' % addr
+    exp_source_path = None
+    exp_source_line = None
+    cb_arg = (addr, exp_name, exp_source_path, exp_source_line, False)
+    symbolizer.SymbolizeAsync(addr, cb_arg)
+
+    # Test symbols with no name or sym info.
+    addr = _UNKNOWN_MOCK_ADDR
+    exp_name = None
+    exp_source_path = None
+    exp_source_line = None
+    cb_arg = (addr, exp_name, exp_source_path, exp_source_line, False)
+    symbolizer.SymbolizeAsync(addr, cb_arg)
+
+    symbolizer.Join()
+
+  def _RunTest(self, max_concurrent_jobs, num_symbols):
+    symbolizer = elf_symbolizer.ELFSymbolizer(
+        elf_file_path='/path/doesnt/matter/mock_lib1.so',
+        addr2line_path=_MOCK_A2L_PATH,
+        callback=self._callback,
+        max_concurrent_jobs=max_concurrent_jobs,
+        addr2line_timeout=0.5)
+
+    for addr in xrange(num_symbols):
+      exp_name = 'mock_sym_for_addr_%d' % addr
+      exp_source_path = 'mock_src/mock_lib1.so.c'
+      exp_source_line = addr
+      cb_arg = (addr, exp_name, exp_source_path, exp_source_line, False)
+      symbolizer.SymbolizeAsync(addr, cb_arg)
+
+    symbolizer.Join()
+
+    # Check that all the expected callbacks have been received.
+    for addr in xrange(num_symbols):
+      self.assertIn(addr, self._resolved_addresses)
+      self._resolved_addresses.remove(addr)
+
+    # Check for unexpected callbacks.
+    self.assertEqual(len(self._resolved_addresses), 0)
+
+  def _SymbolizeCallback(self, sym_info, cb_arg):
+    self.assertTrue(isinstance(sym_info, elf_symbolizer.ELFSymbolInfo))
+    self.assertTrue(isinstance(cb_arg, tuple))
+    self.assertEqual(len(cb_arg), 5)
+
+    # Unpack expectations from the callback extra argument.
+    (addr, exp_name, exp_source_path, exp_source_line, exp_inlines) = cb_arg
+    if exp_name is None:
+      self.assertIsNone(sym_info.name)
+    else:
+      self.assertTrue(sym_info.name.startswith(exp_name))
+    self.assertEqual(sym_info.source_path, exp_source_path)
+    self.assertEqual(sym_info.source_line, exp_source_line)
+
+    if exp_inlines:
+      self.assertEqual(sym_info.name, exp_name + '_inner')
+      self.assertEqual(sym_info.inlined_by.name, exp_name + '_middle')
+      self.assertEqual(sym_info.inlined_by.inlined_by.name,
+                       exp_name + '_outer')
+
+    # Check against duplicate callbacks.
+    self.assertNotIn(addr, self._resolved_addresses)
+    self._resolved_addresses.add(addr)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/symbols/mock_addr2line/__init__.py b/build/android/pylib/symbols/mock_addr2line/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/android/pylib/symbols/mock_addr2line/__init__.py
diff --git a/build/android/pylib/symbols/mock_addr2line/mock_addr2line b/build/android/pylib/symbols/mock_addr2line/mock_addr2line
new file mode 100755
index 0000000..cd58f56
--- /dev/null
+++ b/build/android/pylib/symbols/mock_addr2line/mock_addr2line
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Simple mock for addr2line.
+
+Outputs mock symbol information, with each symbol being a function of the
+original address (so it is easy to double-check consistency in unittests).
+"""
+
+import optparse
+import os
+import posixpath
+import sys
+import time
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('-e', '--exe', dest='exe')  # Path of the debug-library.so.
+  # Silently swallow the other unnecessary arguments.
+  parser.add_option('-C', '--demangle', action='store_true')
+  parser.add_option('-f', '--functions', action='store_true')
+  parser.add_option('-i', '--inlines', action='store_true')
+  options, _ = parser.parse_args(argv[1:])
+  lib_file_name = posixpath.basename(options.exe)
+  processed_sym_count = 0
+  crash_every = int(os.environ.get('MOCK_A2L_CRASH_EVERY', 0))
+  hang_every = int(os.environ.get('MOCK_A2L_HANG_EVERY', 0))
+
+  while(True):
+    line = sys.stdin.readline().rstrip('\r')
+    if not line:
+      break
+
+    # An empty line should generate '??,??:0' (is used as marker for inlines).
+    if line == '\n':
+      print '??'
+      print '??:0'
+      sys.stdout.flush()
+      continue
+
+    addr = int(line, 16)
+    processed_sym_count += 1
+    if crash_every and processed_sym_count % crash_every == 0:
+      sys.exit(1)
+    if hang_every and processed_sym_count % hang_every == 0:
+      time.sleep(1)
+
+    # Addresses < 1M will return good mock symbol information.
+    if addr < 1024 * 1024:
+      print 'mock_sym_for_addr_%d' % addr
+      print 'mock_src/%s.c:%d' % (lib_file_name, addr)
+
+    # Addresses 1M <= x < 2M will return symbols with a name but a missing path.
+    elif addr < 2 * 1024 * 1024:
+      print 'mock_sym_for_addr_%d' % addr
+      print '??:0'
+
+    # Addresses 2M <= x < 3M will return unknown symbol information.
+    elif addr < 3 * 1024 * 1024:
+      print '??'
+      print '??'
+
+    # Addresses 3M <= x < 4M will return inlines.
+    elif addr < 4 * 1024 * 1024:
+      print 'mock_sym_for_addr_%d_inner' % addr
+      print 'mock_src/%s.c:%d' % (lib_file_name, addr)
+      print 'mock_sym_for_addr_%d_middle' % addr
+      print 'mock_src/%s.c:%d' % (lib_file_name, addr)
+      print 'mock_sym_for_addr_%d_outer' % addr
+      print 'mock_src/%s.c:%d' % (lib_file_name, addr)
+
+    sys.stdout.flush()
+
+
+if __name__ == '__main__':
+  main(sys.argv)
\ No newline at end of file
diff --git a/build/android/pylib/system_properties.py b/build/android/pylib/system_properties.py
new file mode 100644
index 0000000..3f16f86
--- /dev/null
+++ b/build/android/pylib/system_properties.py
@@ -0,0 +1,40 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class SystemProperties(dict):
+
+  """A dict interface to interact with device system properties.
+
+  System properties are key/value pairs as exposed by adb shell getprop/setprop.
+
+  This implementation minimizes interaction with the physical device. It is
+  valid for the lifetime of a boot.
+  """
+
+  def __init__(self, android_commands):
+    super(SystemProperties, self).__init__()
+    self._adb = android_commands
+    self._cached_static_properties = {}
+
+  def __getitem__(self, key):
+    if self._IsStatic(key):
+      if key not in self._cached_static_properties:
+        self._cached_static_properties[key] = self._GetProperty(key)
+      return self._cached_static_properties[key]
+    return self._GetProperty(key)
+
+  def __setitem__(self, key, value):
+    # TODO(tonyg): This can fail with no root. Verify that it succeeds.
+    self._adb.SendShellCommand('setprop %s "%s"' % (key, value), retry_count=3)
+
+  @staticmethod
+  def _IsStatic(key):
+    # TODO(tonyg): This list is conservative and could be expanded as needed.
+    return (key.startswith('ro.boot.') or
+            key.startswith('ro.build.') or
+            key.startswith('ro.product.'))
+
+  def _GetProperty(self, key):
+    return self._adb.SendShellCommand('getprop %s' % key, retry_count=3).strip()
diff --git a/build/android/pylib/uiautomator/__init__.py b/build/android/pylib/uiautomator/__init__.py
new file mode 100644
index 0000000..cda7672
--- /dev/null
+++ b/build/android/pylib/uiautomator/__init__.py
@@ -0,0 +1,4 @@
+# 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.
+
diff --git a/build/android/pylib/uiautomator/setup.py b/build/android/pylib/uiautomator/setup.py
new file mode 100644
index 0000000..bd8ffc7
--- /dev/null
+++ b/build/android/pylib/uiautomator/setup.py
@@ -0,0 +1,35 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates test runner factory and tests for uiautomator tests."""
+
+import logging
+
+from pylib.uiautomator import test_package
+from pylib.uiautomator import test_runner
+
+
+def Setup(test_options):
+  """Runs uiautomator tests on connected device(s).
+
+  Args:
+    test_options: A UIAutomatorOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  test_pkg = test_package.TestPackage(test_options.uiautomator_jar,
+                                      test_options.uiautomator_info_jar)
+  tests = test_pkg.GetAllMatchingTests(test_options.annotations,
+                                       test_options.exclude_annotations,
+                                       test_options.test_filter)
+
+  if not tests:
+    logging.error('No uiautomator tests to run with current args.')
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.TestRunner(
+        test_options, device, shard_index, test_pkg)
+
+  return (TestRunnerFactory, tests)
diff --git a/build/android/pylib/uiautomator/test_options.py b/build/android/pylib/uiautomator/test_options.py
new file mode 100644
index 0000000..3f5f950
--- /dev/null
+++ b/build/android/pylib/uiautomator/test_options.py
@@ -0,0 +1,20 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the UIAutomatorOptions named tuple."""
+
+import collections
+
+UIAutomatorOptions = collections.namedtuple('UIAutomatorOptions', [
+    'tool',
+    'annotations',
+    'exclude_annotations',
+    'test_filter',
+    'test_data',
+    'save_perf_json',
+    'screenshot_failures',
+    'uiautomator_jar',
+    'uiautomator_info_jar',
+    'package',
+    'set_asserts'])
diff --git a/build/android/pylib/uiautomator/test_package.py b/build/android/pylib/uiautomator/test_package.py
new file mode 100644
index 0000000..cb51fdf
--- /dev/null
+++ b/build/android/pylib/uiautomator/test_package.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Class representing uiautomator test package."""
+
+import os
+
+from pylib import constants
+from pylib.instrumentation import test_jar
+
+
+class TestPackage(test_jar.TestJar):
+
+  UIAUTOMATOR_PATH = 'uiautomator/'
+  UIAUTOMATOR_DEVICE_DIR = os.path.join(constants.TEST_EXECUTABLE_DIR,
+                                        UIAUTOMATOR_PATH)
+
+  def __init__(self, jar_path, jar_info_path):
+    test_jar.TestJar.__init__(self, jar_info_path)
+
+    if not os.path.exists(jar_path):
+      raise Exception('%s not found, please build it' % jar_path)
+    self._jar_path = jar_path
+
+  def GetPackageName(self):
+    """Returns the JAR named that is installed on the device."""
+    return os.path.basename(self._jar_path)
+
+  # Override.
+  def Install(self, device):
+    device.PushChangedFiles([(self._jar_path, self.UIAUTOMATOR_DEVICE_DIR +
+                              self.GetPackageName())])
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
new file mode 100644
index 0000000..296bd47
--- /dev/null
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -0,0 +1,88 @@
+# 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.
+
+"""Class for running uiautomator tests on a single device."""
+
+from pylib import constants
+from pylib import flag_changer
+from pylib.device import intent
+from pylib.instrumentation import test_options as instr_test_options
+from pylib.instrumentation import test_runner as instr_test_runner
+
+
+class TestRunner(instr_test_runner.TestRunner):
+  """Responsible for running a series of tests connected to a single device."""
+
+  def __init__(self, test_options, device, shard_index, test_pkg):
+    """Create a new TestRunner.
+
+    Args:
+      test_options: A UIAutomatorOptions object.
+      device: Attached android device.
+      shard_index: Shard index.
+      test_pkg: A TestPackage object.
+    """
+    # Create an InstrumentationOptions object to pass to the super class
+    instrumentation_options = instr_test_options.InstrumentationOptions(
+        test_options.tool,
+        test_options.annotations,
+        test_options.exclude_annotations,
+        test_options.test_filter,
+        test_options.test_data,
+        test_options.save_perf_json,
+        test_options.screenshot_failures,
+        wait_for_debugger=False,
+        coverage_dir=None,
+        test_apk=None,
+        test_apk_path=None,
+        test_apk_jar_path=None,
+        test_runner=None,
+        test_support_apk_path=None,
+        device_flags=None,
+        isolate_file_path=None,
+        set_asserts=test_options.set_asserts)
+    super(TestRunner, self).__init__(instrumentation_options, device,
+                                     shard_index, test_pkg)
+
+    cmdline_file = constants.PACKAGE_INFO[test_options.package].cmdline_file
+    self.flags = None
+    if cmdline_file:
+      self.flags = flag_changer.FlagChanger(self.device, cmdline_file)
+    self._package = constants.PACKAGE_INFO[test_options.package].package
+    self._activity = constants.PACKAGE_INFO[test_options.package].activity
+
+  #override
+  def InstallTestPackage(self):
+    self.test_pkg.Install(self.device)
+
+  #override
+  def _RunTest(self, test, timeout):
+    self.device.ClearApplicationState(self._package)
+    if self.flags:
+      annotations = self.test_pkg.GetTestAnnotations(test)
+      if 'FirstRunExperience' == annotations.get('Feature', None):
+        self.flags.RemoveFlags(['--disable-fre'])
+      else:
+        self.flags.AddFlags(['--disable-fre'])
+    self.device.StartActivity(
+        intent.Intent(action='android.intent.action.MAIN',
+                      activity=self._activity,
+                      package=self._package),
+        blocking=True,
+        force_stop=True)
+    cmd = ['uiautomator', 'runtest',
+           self.test_pkg.UIAUTOMATOR_PATH + self.test_pkg.GetPackageName(),
+           '-e', 'class', test,
+           '-e', 'test_package', self._package]
+    return self.device.RunShellCommand(cmd, timeout=timeout, retries=0)
+
+  #override
+  def _GenerateTestResult(self, test, _result_code, _result_bundle, statuses,
+                          start_ms, duration_ms):
+    # uiautomator emits its summary status with INSTRUMENTATION_STATUS_CODE,
+    # not INSTRUMENTATION_CODE, so we have to drop if off the list of statuses.
+    summary_code, summary_bundle = statuses[-1]
+    return super(TestRunner, self)._GenerateTestResult(
+        test, summary_code, summary_bundle, statuses[:-1], start_ms,
+        duration_ms)
diff --git a/build/android/pylib/uirobot/__init__.py b/build/android/pylib/uirobot/__init__.py
new file mode 100644
index 0000000..5cac026
--- /dev/null
+++ b/build/android/pylib/uirobot/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
diff --git a/build/android/pylib/uirobot/uirobot_test_instance.py b/build/android/pylib/uirobot/uirobot_test_instance.py
new file mode 100644
index 0000000..e3f6eb7
--- /dev/null
+++ b/build/android/pylib/uirobot/uirobot_test_instance.py
@@ -0,0 +1,79 @@
+# Copyright 2014 The Chromium 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 os
+import json
+import logging
+
+from pylib import constants
+from pylib.base import test_instance
+from pylib.utils import apk_helper
+
+class UirobotTestInstance(test_instance.TestInstance):
+
+  def __init__(self, args, error_func):
+    """Constructor.
+
+    Args:
+      args: Command line arguments.
+    """
+    super(UirobotTestInstance, self).__init__()
+    if not args.app_under_test:
+      error_func('Must set --app-under-test.')
+    self._app_under_test = args.app_under_test
+    self._minutes = args.minutes
+
+    if args.remote_device_file:
+      with open(args.remote_device_file) as remote_device_file:
+        device_json = json.load(remote_device_file)
+    else:
+      device_json = {}
+    device_type = device_json.get('device_type', 'Android')
+    if args.device_type:
+      if device_type and device_type != args.device_type:
+        logging.info('Overriding device_type from %s to %s',
+                     device_type, args.device_type)
+      device_type = args.device_type
+
+    if device_type == 'Android':
+      self._suite = 'Android Uirobot'
+      self._package_name = apk_helper.GetPackageName(self._app_under_test)
+    elif device_type == 'iOS':
+      self._suite = 'iOS Uirobot'
+      self._package_name = self._app_under_test
+
+
+  #override
+  def TestType(self):
+    """Returns type of test."""
+    return 'uirobot'
+
+  #override
+  def SetUp(self):
+    """Setup for test."""
+    pass
+
+  #override
+  def TearDown(self):
+    """Teardown for test."""
+    pass
+
+  @property
+  def app_under_test(self):
+    """Returns the app to run the test on."""
+    return self._app_under_test
+
+  @property
+  def minutes(self):
+    """Returns the number of minutes to run the uirobot for."""
+    return self._minutes
+
+  @property
+  def package_name(self):
+    """Returns the name of the package in the APK."""
+    return self._package_name
+
+  @property
+  def suite(self):
+    return self._suite
diff --git a/build/android/pylib/utils/__init__.py b/build/android/pylib/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/android/pylib/utils/__init__.py
diff --git a/build/android/pylib/utils/apk_helper.py b/build/android/pylib/utils/apk_helper.py
new file mode 100644
index 0000000..f5e9cd3
--- /dev/null
+++ b/build/android/pylib/utils/apk_helper.py
@@ -0,0 +1,76 @@
+# 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.
+
+"""Module containing utilities for apk packages."""
+
+import os.path
+import re
+
+from pylib import cmd_helper
+from pylib import constants
+
+
+_AAPT_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'aapt')
+_MANIFEST_ATTRIBUTE_RE = re.compile(
+    r'\s*A: ([^\(\)= ]*)\([^\(\)= ]*\)="(.*)" \(Raw: .*\)$')
+_MANIFEST_ELEMENT_RE = re.compile(r'\s*(?:E|N): (\S*) .*$')
+
+
+def GetPackageName(apk_path):
+  """Returns the package name of the apk."""
+  aapt_cmd = [_AAPT_PATH, 'dump', 'badging', apk_path]
+  aapt_output = cmd_helper.GetCmdOutput(aapt_cmd).split('\n')
+  package_name_re = re.compile(r'package: .*name=\'(\S*)\'')
+  for line in aapt_output:
+    m = package_name_re.match(line)
+    if m:
+      return m.group(1)
+  raise Exception('Failed to determine package name of %s' % apk_path)
+
+
+def _ParseManifestFromApk(apk_path):
+  aapt_cmd = [_AAPT_PATH, 'dump', 'xmltree', apk_path, 'AndroidManifest.xml']
+  aapt_output = cmd_helper.GetCmdOutput(aapt_cmd).split('\n')
+
+  parsed_manifest = {}
+  node_stack = [parsed_manifest]
+  indent = '  '
+
+  for line in aapt_output[1:]:
+    if len(line) == 0:
+      continue
+
+    indent_depth = 0
+    while line[(len(indent) * indent_depth):].startswith(indent):
+      indent_depth += 1
+
+    node_stack = node_stack[:indent_depth]
+    node = node_stack[-1]
+
+    m = _MANIFEST_ELEMENT_RE.match(line[len(indent) * indent_depth:])
+    if m:
+      if not m.group(1) in node:
+        node[m.group(1)] = {}
+      node_stack += [node[m.group(1)]]
+      continue
+
+    m = _MANIFEST_ATTRIBUTE_RE.match(line[len(indent) * indent_depth:])
+    if m:
+      if not m.group(1) in node:
+        node[m.group(1)] = []
+      node[m.group(1)].append(m.group(2))
+      continue
+
+  return parsed_manifest
+
+
+def GetInstrumentationName(
+    apk_path, default='android.test.InstrumentationTestRunner'):
+  """Returns the name of the Instrumentation in the apk."""
+
+  try:
+    manifest_info = _ParseManifestFromApk(apk_path)
+    return manifest_info['manifest']['instrumentation']['android:name'][0]
+  except KeyError:
+    return default
diff --git a/build/android/pylib/utils/base_error.py b/build/android/pylib/utils/base_error.py
new file mode 100644
index 0000000..31eaa54
--- /dev/null
+++ b/build/android/pylib/utils/base_error.py
@@ -0,0 +1,16 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+class BaseError(Exception):
+  """Base error for all test runner errors."""
+
+  def __init__(self, message, is_infra_error=False):
+    super(BaseError, self).__init__(message)
+    self._is_infra_error = is_infra_error
+
+  @property
+  def is_infra_error(self):
+    """Property to indicate if error was caused by an infrastructure issue."""
+    return self._is_infra_error
\ No newline at end of file
diff --git a/build/android/pylib/utils/command_option_parser.py b/build/android/pylib/utils/command_option_parser.py
new file mode 100644
index 0000000..cf501d0
--- /dev/null
+++ b/build/android/pylib/utils/command_option_parser.py
@@ -0,0 +1,75 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""An option parser which handles the first arg as a command.
+
+Add other nice functionality such as printing a list of commands
+and an example in usage.
+"""
+
+import optparse
+import sys
+
+
+class CommandOptionParser(optparse.OptionParser):
+  """Wrapper class for OptionParser to help with listing commands."""
+
+  def __init__(self, *args, **kwargs):
+    """Creates a CommandOptionParser.
+
+    Args:
+      commands_dict: A dictionary mapping command strings to an object defining
+          - add_options_func: Adds options to the option parser
+          - run_command_func: Runs the command itself.
+      example: An example command.
+      everything else: Passed to optparse.OptionParser contructor.
+    """
+    self.commands_dict = kwargs.pop('commands_dict', {})
+    self.example = kwargs.pop('example', '')
+    if not 'usage' in kwargs:
+      kwargs['usage'] = 'Usage: %prog <command> [options]'
+    optparse.OptionParser.__init__(self, *args, **kwargs)
+
+  #override
+  def get_usage(self):
+    normal_usage = optparse.OptionParser.get_usage(self)
+    command_list = self.get_command_list()
+    example = self.get_example()
+    return self.expand_prog_name(normal_usage + example + command_list)
+
+  #override
+  def get_command_list(self):
+    if self.commands_dict.keys():
+      return '\nCommands:\n  %s\n' % '\n  '.join(
+          sorted(self.commands_dict.keys()))
+    return ''
+
+  def get_example(self):
+    if self.example:
+      return '\nExample:\n  %s\n' % self.example
+    return ''
+
+
+def ParseAndExecute(option_parser, argv=None):
+  """Parses options/args from argv and runs the specified command.
+
+  Args:
+    option_parser: A CommandOptionParser object.
+    argv: Command line arguments. If None, automatically draw from sys.argv.
+
+  Returns:
+    An exit code.
+  """
+  if not argv:
+    argv = sys.argv
+
+    if len(argv) < 2 or argv[1] not in option_parser.commands_dict:
+      # Parse args first, if this is '--help', optparse will print help and exit
+      option_parser.parse_args(argv)
+      option_parser.error('Invalid command.')
+
+    cmd = option_parser.commands_dict[argv[1]]
+    cmd.add_options_func(option_parser)
+    options, args = option_parser.parse_args(argv)
+    return cmd.run_command_func(argv[1], options, args, option_parser)
diff --git a/build/android/pylib/utils/device_temp_file.py b/build/android/pylib/utils/device_temp_file.py
new file mode 100644
index 0000000..7d3b95b
--- /dev/null
+++ b/build/android/pylib/utils/device_temp_file.py
@@ -0,0 +1,57 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A temp file that automatically gets pushed and deleted from a device."""
+
+# pylint: disable=W0622
+
+import random
+import time
+
+from pylib import cmd_helper
+from pylib.device import device_errors
+
+
+class DeviceTempFile(object):
+  def __init__(self, adb, suffix='', prefix='temp_file', dir='/data/local/tmp'):
+    """Find an unused temporary file path in the devices external directory.
+
+    When this object is closed, the file will be deleted on the device.
+
+    Args:
+      adb: An instance of AdbWrapper
+      suffix: The suffix of the name of the temp file.
+      prefix: The prefix of the name of the temp file.
+      dir: The directory on the device where to place the temp file.
+    """
+    self._adb = adb
+    # make sure that the temp dir is writable
+    self._adb.Shell('test -d %s' % cmd_helper.SingleQuote(dir))
+    while True:
+      self.name = '{dir}/{prefix}-{time:d}-{nonce:d}{suffix}'.format(
+        dir=dir, prefix=prefix, time=int(time.time()),
+        nonce=random.randint(0, 1000000), suffix=suffix)
+      self.name_quoted = cmd_helper.SingleQuote(self.name)
+      try:
+        self._adb.Shell('test -e %s' % self.name_quoted)
+      except device_errors.AdbCommandFailedError:
+        break # file does not exist
+
+    # Immediately touch the file, so other temp files can't get the same name.
+    self._adb.Shell('touch %s' % self.name_quoted)
+
+  def close(self):
+    """Deletes the temporary file from the device."""
+    # ignore exception if the file is already gone.
+    try:
+      self._adb.Shell('rm -f %s' % self.name_quoted)
+    except device_errors.AdbCommandFailedError:
+      # file does not exist on Android version without 'rm -f' support (ICS)
+      pass
+
+  def __enter__(self):
+    return self
+
+  def __exit__(self, type, value, traceback):
+    self.close()
diff --git a/build/android/pylib/utils/device_temp_file_test.py b/build/android/pylib/utils/device_temp_file_test.py
new file mode 100755
index 0000000..f839ce0
--- /dev/null
+++ b/build/android/pylib/utils/device_temp_file_test.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for the contents of device_temp_file.py.
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import adb_wrapper
+from pylib.device import device_errors
+from pylib.utils import device_temp_file
+from pylib.utils import mock_calls
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+class DeviceTempFileTest(mock_calls.TestCase):
+
+  def setUp(self):
+    test_serial = '0123456789abcdef'
+    self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
+    self.adb.__str__ = mock.Mock(return_value=test_serial)
+    self.watchMethodCalls(self.call.adb)
+
+  def mockShellCall(self, cmd_prefix, action=''):
+    """Expect an adb.Shell(cmd) call with cmd_prefix and do some action
+
+    Args:
+      cmd_prefix: A string, the cmd of the received call is expected to have
+          this as a prefix.
+      action: If callable, an action to perform when the expected call is
+          received, otherwise a return value.
+    Returns:
+      An (expected_call, action) pair suitable for use in assertCalls.
+    """
+    def check_and_return(cmd):
+      self.assertTrue(
+          cmd.startswith(cmd_prefix),
+          'command %r does not start with prefix %r' % (cmd, cmd_prefix))
+      if callable(action):
+        return action(cmd)
+      else:
+        return action
+    return (self.call.adb.Shell(mock.ANY), check_and_return)
+
+  def mockExistsTest(self, exists_result):
+    def action(cmd):
+      if exists_result:
+        return ''
+      else:
+        raise device_errors.AdbCommandFailedError(
+            cmd, 'File not found', 1, str(self.adb))
+    return self.mockShellCall('test -e ', action)
+
+  def testTempFileNameAlreadyExists(self):
+    with self.assertCalls(
+        self.mockShellCall('test -d /data/local/tmp'),
+        self.mockExistsTest(True),
+        self.mockExistsTest(True),
+        self.mockExistsTest(True),
+        self.mockExistsTest(False),
+        self.mockShellCall('touch '),
+        self.mockShellCall('rm -f ')):
+      with device_temp_file.DeviceTempFile(self.adb) as tmpfile:
+        logging.debug('Temp file name: %s' % tmpfile.name)
+
+  def testTempFileLifecycle(self):
+    with self.assertCalls(
+        self.mockShellCall('test -d /data/local/tmp'),
+        self.mockExistsTest(False),
+        self.mockShellCall('touch ')):
+      tempFileContextManager = device_temp_file.DeviceTempFile(self.adb)
+    with mock.patch.object(self.adb, 'Shell'):
+      with tempFileContextManager as tmpfile:
+        logging.debug('Temp file name: %s' % tmpfile.name)
+        self.assertEquals(0, self.adb.Shell.call_count)
+      self.assertEquals(1, self.adb.Shell.call_count)
+      args, _ = self.adb.Shell.call_args
+      self.assertTrue(args[0].startswith('rm -f '))
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
diff --git a/build/android/pylib/utils/emulator.py b/build/android/pylib/utils/emulator.py
new file mode 100644
index 0000000..635462f
--- /dev/null
+++ b/build/android/pylib/utils/emulator.py
@@ -0,0 +1,441 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Provides an interface to start and stop Android emulator.
+
+  Emulator: The class provides the methods to launch/shutdown the emulator with
+            the android virtual device named 'avd_armeabi' .
+"""
+
+import logging
+import os
+import signal
+import subprocess
+import time
+
+# TODO(craigdh): Move these pylib dependencies to pylib/utils/.
+from pylib import cmd_helper
+from pylib import constants
+from pylib import pexpect
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.utils import time_profile
+
+import errors
+import run_command
+
+# SD card size
+SDCARD_SIZE = '512M'
+
+# Template used to generate config.ini files for the emulator
+CONFIG_TEMPLATE = """avd.ini.encoding=ISO-8859-1
+hw.dPad=no
+hw.lcd.density=320
+sdcard.size=512M
+hw.cpu.arch={hw.cpu.arch}
+hw.device.hash=-708107041
+hw.camera.back=none
+disk.dataPartition.size=800M
+hw.gpu.enabled=yes
+skin.path=720x1280
+skin.dynamic=yes
+hw.keyboard=yes
+hw.ramSize=1024
+hw.device.manufacturer=Google
+hw.sdCard=yes
+hw.mainKeys=no
+hw.accelerometer=yes
+skin.name=720x1280
+abi.type={abi.type}
+hw.trackBall=no
+hw.device.name=Galaxy Nexus
+hw.battery=yes
+hw.sensors.proximity=yes
+image.sysdir.1=system-images/android-{api.level}/{abi.type}/
+hw.sensors.orientation=yes
+hw.audioInput=yes
+hw.camera.front=none
+hw.gps=yes
+vm.heapSize=128
+{extras}"""
+
+CONFIG_REPLACEMENTS = {
+  'x86': {
+    '{hw.cpu.arch}': 'x86',
+    '{abi.type}': 'x86',
+    '{extras}': ''
+  },
+  'arm': {
+    '{hw.cpu.arch}': 'arm',
+    '{abi.type}': 'armeabi-v7a',
+    '{extras}': 'hw.cpu.model=cortex-a8\n'
+  },
+  'mips': {
+    '{hw.cpu.arch}': 'mips',
+    '{abi.type}': 'mips',
+    '{extras}': ''
+  }
+}
+
+class EmulatorLaunchException(Exception):
+  """Emulator failed to launch."""
+  pass
+
+def _KillAllEmulators():
+  """Kill all running emulators that look like ones we started.
+
+  There are odd 'sticky' cases where there can be no emulator process
+  running but a device slot is taken.  A little bot trouble and and
+  we're out of room forever.
+  """
+  emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
+  if not emulators:
+    return
+  for e in emulators:
+    e.adb.Emu(['kill'])
+  logging.info('Emulator killing is async; give a few seconds for all to die.')
+  for _ in range(5):
+    if not any(d.adb.is_emulator for d in device_utils.HealthyDevices()):
+      return
+    time.sleep(1)
+
+
+def DeleteAllTempAVDs():
+  """Delete all temporary AVDs which are created for tests.
+
+  If the test exits abnormally and some temporary AVDs created when testing may
+  be left in the system. Clean these AVDs.
+  """
+  avds = device_utils.GetAVDs()
+  if not avds:
+    return
+  for avd_name in avds:
+    if 'run_tests_avd' in avd_name:
+      cmd = ['android', '-s', 'delete', 'avd', '--name', avd_name]
+      cmd_helper.RunCmd(cmd)
+      logging.info('Delete AVD %s' % avd_name)
+
+
+class PortPool(object):
+  """Pool for emulator port starting position that changes over time."""
+  _port_min = 5554
+  _port_max = 5585
+  _port_current_index = 0
+
+  @classmethod
+  def port_range(cls):
+    """Return a range of valid ports for emulator use.
+
+    The port must be an even number between 5554 and 5584.  Sometimes
+    a killed emulator "hangs on" to a port long enough to prevent
+    relaunch.  This is especially true on slow machines (like a bot).
+    Cycling through a port start position helps make us resilient."""
+    ports = range(cls._port_min, cls._port_max, 2)
+    n = cls._port_current_index
+    cls._port_current_index = (n + 1) % len(ports)
+    return ports[n:] + ports[:n]
+
+
+def _GetAvailablePort():
+  """Returns an available TCP port for the console."""
+  used_ports = []
+  emulators = [d for d in device_utils.HealthyDevices() if d.adb.is_emulator]
+  for emulator in emulators:
+    used_ports.append(emulator.adb.GetDeviceSerial().split('-')[1])
+  for port in PortPool.port_range():
+    if str(port) not in used_ports:
+      return port
+
+
+def LaunchTempEmulators(emulator_count, abi, api_level, wait_for_boot=True):
+  """Create and launch temporary emulators and wait for them to boot.
+
+  Args:
+    emulator_count: number of emulators to launch.
+    abi: the emulator target platform
+    api_level: the api level (e.g., 19 for Android v4.4 - KitKat release)
+    wait_for_boot: whether or not to wait for emulators to boot up
+
+  Returns:
+    List of emulators.
+  """
+  emulators = []
+  for n in xrange(emulator_count):
+    t = time_profile.TimeProfile('Emulator launch %d' % n)
+    # Creates a temporary AVD.
+    avd_name = 'run_tests_avd_%d' % n
+    logging.info('Emulator launch %d with avd_name=%s and api=%d',
+        n, avd_name, api_level)
+    emulator = Emulator(avd_name, abi)
+    emulator.CreateAVD(api_level)
+    emulator.Launch(kill_all_emulators=n == 0)
+    t.Stop()
+    emulators.append(emulator)
+  # Wait for all emulators to boot completed.
+  if wait_for_boot:
+    for emulator in emulators:
+      emulator.ConfirmLaunch(True)
+  return emulators
+
+
+def LaunchEmulator(avd_name, abi):
+  """Launch an existing emulator with name avd_name.
+
+  Args:
+    avd_name: name of existing emulator
+    abi: the emulator target platform
+
+  Returns:
+    emulator object.
+  """
+  logging.info('Specified emulator named avd_name=%s launched', avd_name)
+  emulator = Emulator(avd_name, abi)
+  emulator.Launch(kill_all_emulators=True)
+  emulator.ConfirmLaunch(True)
+  return emulator
+
+
+class Emulator(object):
+  """Provides the methods to launch/shutdown the emulator.
+
+  The emulator has the android virtual device named 'avd_armeabi'.
+
+  The emulator could use any even TCP port between 5554 and 5584 for the
+  console communication, and this port will be part of the device name like
+  'emulator-5554'. Assume it is always True, as the device name is the id of
+  emulator managed in this class.
+
+  Attributes:
+    emulator: Path of Android's emulator tool.
+    popen: Popen object of the running emulator process.
+    device: Device name of this emulator.
+  """
+
+  # Signals we listen for to kill the emulator on
+  _SIGNALS = (signal.SIGINT, signal.SIGHUP)
+
+  # Time to wait for an emulator launch, in seconds.  This includes
+  # the time to launch the emulator and a wait-for-device command.
+  _LAUNCH_TIMEOUT = 120
+
+  # Timeout interval of wait-for-device command before bouncing to a a
+  # process life check.
+  _WAITFORDEVICE_TIMEOUT = 5
+
+  # Time to wait for a "wait for boot complete" (property set on device).
+  _WAITFORBOOT_TIMEOUT = 300
+
+  def __init__(self, avd_name, abi):
+    """Init an Emulator.
+
+    Args:
+      avd_name: name of the AVD to create
+      abi: target platform for emulator being created, defaults to x86
+    """
+    android_sdk_root = os.path.join(constants.EMULATOR_SDK_ROOT, 'sdk')
+    self.emulator = os.path.join(android_sdk_root, 'tools', 'emulator')
+    self.android = os.path.join(android_sdk_root, 'tools', 'android')
+    self.popen = None
+    self.device_serial = None
+    self.abi = abi
+    self.avd_name = avd_name
+
+  @staticmethod
+  def _DeviceName():
+    """Return our device name."""
+    port = _GetAvailablePort()
+    return ('emulator-%d' % port, port)
+
+  def CreateAVD(self, api_level):
+    """Creates an AVD with the given name.
+
+    Args:
+      api_level: the api level of the image
+
+    Return avd_name.
+    """
+
+    if self.abi == 'arm':
+      abi_option = 'armeabi-v7a'
+    elif self.abi == 'mips':
+      abi_option = 'mips'
+    else:
+      abi_option = 'x86'
+
+    api_target = 'android-%s' % api_level
+
+    avd_command = [
+        self.android,
+        '--silent',
+        'create', 'avd',
+        '--name', self.avd_name,
+        '--abi', abi_option,
+        '--target', api_target,
+        '--sdcard', SDCARD_SIZE,
+        '--force',
+    ]
+    avd_cmd_str = ' '.join(avd_command)
+    logging.info('Create AVD command: %s', avd_cmd_str)
+    avd_process = pexpect.spawn(avd_cmd_str)
+
+    # Instead of creating a custom profile, we overwrite config files.
+    avd_process.expect('Do you wish to create a custom hardware profile')
+    avd_process.sendline('no\n')
+    avd_process.expect('Created AVD \'%s\'' % self.avd_name)
+
+    # Replace current configuration with default Galaxy Nexus config.
+    avds_dir = os.path.join(os.path.expanduser('~'), '.android', 'avd')
+    ini_file = os.path.join(avds_dir, '%s.ini' % self.avd_name)
+    new_config_ini = os.path.join(avds_dir, '%s.avd' % self.avd_name,
+                                  'config.ini')
+
+    # Remove config files with defaults to replace with Google's GN settings.
+    os.unlink(ini_file)
+    os.unlink(new_config_ini)
+
+    # Create new configuration files with Galaxy Nexus by Google settings.
+    with open(ini_file, 'w') as new_ini:
+      new_ini.write('avd.ini.encoding=ISO-8859-1\n')
+      new_ini.write('target=%s\n' % api_target)
+      new_ini.write('path=%s/%s.avd\n' % (avds_dir, self.avd_name))
+      new_ini.write('path.rel=avd/%s.avd\n' % self.avd_name)
+
+    custom_config = CONFIG_TEMPLATE
+    replacements = CONFIG_REPLACEMENTS[self.abi]
+    for key in replacements:
+      custom_config = custom_config.replace(key, replacements[key])
+    custom_config = custom_config.replace('{api.level}', str(api_level))
+
+    with open(new_config_ini, 'w') as new_config_ini:
+      new_config_ini.write(custom_config)
+
+    return self.avd_name
+
+
+  def _DeleteAVD(self):
+    """Delete the AVD of this emulator."""
+    avd_command = [
+        self.android,
+        '--silent',
+        'delete',
+        'avd',
+        '--name', self.avd_name,
+    ]
+    logging.info('Delete AVD command: %s', ' '.join(avd_command))
+    cmd_helper.RunCmd(avd_command)
+
+
+  def Launch(self, kill_all_emulators):
+    """Launches the emulator asynchronously. Call ConfirmLaunch() to ensure the
+    emulator is ready for use.
+
+    If fails, an exception will be raised.
+    """
+    if kill_all_emulators:
+      _KillAllEmulators()  # just to be sure
+    self._AggressiveImageCleanup()
+    (self.device_serial, port) = self._DeviceName()
+    emulator_command = [
+        self.emulator,
+        # Speed up emulator launch by 40%.  Really.
+        '-no-boot-anim',
+        # The default /data size is 64M.
+        # That's not enough for 8 unit test bundles and their data.
+        '-partition-size', '512',
+        # Use a familiar name and port.
+        '-avd', self.avd_name,
+        '-port', str(port),
+        # Wipe the data.  We've seen cases where an emulator gets 'stuck' if we
+        # don't do this (every thousand runs or so).
+        '-wipe-data',
+        # Enable GPU by default.
+        '-gpu', 'on',
+        '-qemu', '-m', '1024',
+        ]
+    if self.abi == 'x86':
+      emulator_command.extend([
+          # For x86 emulator --enable-kvm will fail early, avoiding accidental
+          # runs in a slow mode (i.e. without hardware virtualization support).
+          '--enable-kvm',
+          ])
+
+    logging.info('Emulator launch command: %s', ' '.join(emulator_command))
+    self.popen = subprocess.Popen(args=emulator_command,
+                                  stderr=subprocess.STDOUT)
+    self._InstallKillHandler()
+
+  @staticmethod
+  def _AggressiveImageCleanup():
+    """Aggressive cleanup of emulator images.
+
+    Experimentally it looks like our current emulator use on the bot
+    leaves image files around in /tmp/android-$USER.  If a "random"
+    name gets reused, we choke with a 'File exists' error.
+    TODO(jrg): is there a less hacky way to accomplish the same goal?
+    """
+    logging.info('Aggressive Image Cleanup')
+    emulator_imagedir = '/tmp/android-%s' % os.environ['USER']
+    if not os.path.exists(emulator_imagedir):
+      return
+    for image in os.listdir(emulator_imagedir):
+      full_name = os.path.join(emulator_imagedir, image)
+      if 'emulator' in full_name:
+        logging.info('Deleting emulator image %s', full_name)
+        os.unlink(full_name)
+
+  def ConfirmLaunch(self, wait_for_boot=False):
+    """Confirm the emulator launched properly.
+
+    Loop on a wait-for-device with a very small timeout.  On each
+    timeout, check the emulator process is still alive.
+    After confirming a wait-for-device can be successful, make sure
+    it returns the right answer.
+    """
+    seconds_waited = 0
+    number_of_waits = 2  # Make sure we can wfd twice
+
+    device = device_utils.DeviceUtils(self.device_serial)
+    while seconds_waited < self._LAUNCH_TIMEOUT:
+      try:
+        device.adb.WaitForDevice(
+            timeout=self._WAITFORDEVICE_TIMEOUT, retries=1)
+        number_of_waits -= 1
+        if not number_of_waits:
+          break
+      except device_errors.CommandTimeoutError:
+        seconds_waited += self._WAITFORDEVICE_TIMEOUT
+        device.adb.KillServer()
+      self.popen.poll()
+      if self.popen.returncode != None:
+        raise EmulatorLaunchException('EMULATOR DIED')
+
+    if seconds_waited >= self._LAUNCH_TIMEOUT:
+      raise EmulatorLaunchException('TIMEOUT with wait-for-device')
+
+    logging.info('Seconds waited on wait-for-device: %d', seconds_waited)
+    if wait_for_boot:
+      # Now that we checked for obvious problems, wait for a boot complete.
+      # Waiting for the package manager is sometimes problematic.
+      device.WaitUntilFullyBooted(timeout=self._WAITFORBOOT_TIMEOUT)
+
+  def Shutdown(self):
+    """Shuts down the process started by launch."""
+    self._DeleteAVD()
+    if self.popen:
+      self.popen.poll()
+      if self.popen.returncode == None:
+        self.popen.kill()
+      self.popen = None
+
+  def _ShutdownOnSignal(self, _signum, _frame):
+    logging.critical('emulator _ShutdownOnSignal')
+    for sig in self._SIGNALS:
+      signal.signal(sig, signal.SIG_DFL)
+    self.Shutdown()
+    raise KeyboardInterrupt  # print a stack
+
+  def _InstallKillHandler(self):
+    """Install a handler to kill the emulator when we exit unexpectedly."""
+    for sig in self._SIGNALS:
+      signal.signal(sig, self._ShutdownOnSignal)
diff --git a/build/android/pylib/utils/findbugs.py b/build/android/pylib/utils/findbugs.py
new file mode 100644
index 0000000..8deb0fe
--- /dev/null
+++ b/build/android/pylib/utils/findbugs.py
@@ -0,0 +1,154 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import logging
+import os
+import re
+import shlex
+import sys
+import xml.dom.minidom
+
+from pylib import cmd_helper
+from pylib import constants
+
+
+_FINDBUGS_HOME = os.path.join(constants.DIR_SOURCE_ROOT, 'third_party',
+                              'findbugs')
+_FINDBUGS_JAR = os.path.join(_FINDBUGS_HOME, 'lib', 'findbugs.jar')
+_FINDBUGS_MAX_HEAP = 768
+_FINDBUGS_PLUGIN_PATH = os.path.join(
+    constants.DIR_SOURCE_ROOT, 'tools', 'android', 'findbugs_plugin', 'lib',
+    'chromiumPlugin.jar')
+
+
+def _ParseXmlResults(results_doc):
+  warnings = set()
+  for en in (n for n in results_doc.documentElement.childNodes
+             if n.nodeType == xml.dom.Node.ELEMENT_NODE):
+    if en.tagName == 'BugInstance':
+      warnings.add(_ParseBugInstance(en))
+  return warnings
+
+
+def _GetMessage(node):
+  for c in (n for n in node.childNodes
+            if n.nodeType == xml.dom.Node.ELEMENT_NODE):
+    if c.tagName == 'Message':
+      if (len(c.childNodes) == 1
+          and c.childNodes[0].nodeType == xml.dom.Node.TEXT_NODE):
+        return c.childNodes[0].data
+  return None
+
+
+def _ParseBugInstance(node):
+  bug = FindBugsWarning(node.getAttribute('type'))
+  msg_parts = []
+  for c in (n for n in node.childNodes
+            if n.nodeType == xml.dom.Node.ELEMENT_NODE):
+    if c.tagName == 'Class':
+      msg_parts.append(_GetMessage(c))
+    elif c.tagName == 'Method':
+      msg_parts.append(_GetMessage(c))
+    elif c.tagName == 'Field':
+      msg_parts.append(_GetMessage(c))
+    elif c.tagName == 'SourceLine':
+      bug.file_name = c.getAttribute('sourcefile')
+      if c.hasAttribute('start'):
+        bug.start_line = int(c.getAttribute('start'))
+      if c.hasAttribute('end'):
+        bug.end_line = int(c.getAttribute('end'))
+      msg_parts.append(_GetMessage(c))
+    elif (c.tagName == 'ShortMessage' and len(c.childNodes) == 1
+          and c.childNodes[0].nodeType == xml.dom.Node.TEXT_NODE):
+      msg_parts.append(c.childNodes[0].data)
+  bug.message = tuple(m for m in msg_parts if m)
+  return bug
+
+
+class FindBugsWarning(object):
+
+  def __init__(self, bug_type='', end_line=0, file_name='', message=None,
+               start_line=0):
+    self.bug_type = bug_type
+    self.end_line = end_line
+    self.file_name = file_name
+    if message is None:
+      self.message = tuple()
+    else:
+      self.message = message
+    self.start_line = start_line
+
+  def __cmp__(self, other):
+    return (cmp(self.file_name, other.file_name)
+            or cmp(self.start_line, other.start_line)
+            or cmp(self.end_line, other.end_line)
+            or cmp(self.bug_type, other.bug_type)
+            or cmp(self.message, other.message))
+
+  def __eq__(self, other):
+    return self.__dict__ == other.__dict__
+
+  def __hash__(self):
+    return hash((self.bug_type, self.end_line, self.file_name, self.message,
+                 self.start_line))
+
+  def __ne__(self, other):
+    return not self == other
+
+  def __str__(self):
+    return '%s: %s' % (self.bug_type, '\n  '.join(self.message))
+
+
+def Run(exclude, classes_to_analyze, auxiliary_classes, output_file,
+        findbug_args, jars):
+  """Run FindBugs.
+
+  Args:
+    exclude: the exclude xml file, refer to FindBugs's -exclude command option.
+    classes_to_analyze: the list of classes need to analyze, refer to FindBug's
+                        -onlyAnalyze command line option.
+    auxiliary_classes: the classes help to analyze, refer to FindBug's
+                       -auxclasspath command line option.
+    output_file: An optional path to dump XML results to.
+    findbug_args: A list of addtional command line options to pass to Findbugs.
+  """
+  # TODO(jbudorick): Get this from the build system.
+  system_classes = [
+    os.path.join(constants.ANDROID_SDK_ROOT, 'platforms',
+                 'android-%s' % constants.ANDROID_SDK_VERSION, 'android.jar')
+  ]
+  system_classes.extend(os.path.abspath(classes)
+                        for classes in auxiliary_classes or [])
+
+  cmd = ['java',
+         '-classpath', '%s:' % _FINDBUGS_JAR,
+         '-Xmx%dm' % _FINDBUGS_MAX_HEAP,
+         '-Dfindbugs.home="%s"' % _FINDBUGS_HOME,
+         '-jar', _FINDBUGS_JAR,
+         '-textui', '-sortByClass',
+         '-pluginList', _FINDBUGS_PLUGIN_PATH, '-xml:withMessages']
+  if system_classes:
+    cmd.extend(['-auxclasspath', ':'.join(system_classes)])
+  if classes_to_analyze:
+    cmd.extend(['-onlyAnalyze', classes_to_analyze])
+  if exclude:
+    cmd.extend(['-exclude', os.path.abspath(exclude)])
+  if output_file:
+    cmd.extend(['-output', output_file])
+  if findbug_args:
+    cmd.extend(findbug_args)
+  cmd.extend(os.path.abspath(j) for j in jars or [])
+
+  if output_file:
+    cmd_helper.RunCmd(cmd)
+    results_doc = xml.dom.minidom.parse(output_file)
+  else:
+    raw_out = cmd_helper.GetCmdOutput(cmd)
+    results_doc = xml.dom.minidom.parseString(raw_out)
+
+  current_warnings_set = _ParseXmlResults(results_doc)
+
+  return (' '.join(cmd), current_warnings_set)
+
diff --git a/build/android/pylib/utils/host_path_finder.py b/build/android/pylib/utils/host_path_finder.py
new file mode 100644
index 0000000..389ac43
--- /dev/null
+++ b/build/android/pylib/utils/host_path_finder.py
@@ -0,0 +1,22 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+
+from pylib import constants
+
+
+def GetMostRecentHostPath(file_name):
+  """Returns the most recent existing full path for the given file name.
+
+  Returns: An empty string if no path could be found.
+  """
+  out_dir = os.path.join(
+      constants.DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUT_DIR', 'out'))
+  candidate_paths = [os.path.join(out_dir, build_type, file_name)
+                     for build_type in ['Debug', 'Release']]
+  candidate_paths = filter(os.path.exists, candidate_paths)
+  candidate_paths = sorted(candidate_paths, key=os.path.getmtime, reverse=True)
+  candidate_paths.append('')
+  return candidate_paths[0]
diff --git a/build/android/pylib/utils/host_utils.py b/build/android/pylib/utils/host_utils.py
new file mode 100644
index 0000000..580721f
--- /dev/null
+++ b/build/android/pylib/utils/host_utils.py
@@ -0,0 +1,16 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+
+
+def GetRecursiveDiskUsage(path):
+  """Returns the disk usage in bytes of |path|. Similar to `du -sb |path|`."""
+  running_size = os.path.getsize(path)
+  if os.path.isdir(path):
+    for root, dirs, files in os.walk(path):
+      running_size += sum([os.path.getsize(os.path.join(root, f))
+                           for f in files + dirs])
+  return running_size
+
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
new file mode 100644
index 0000000..cac39d8
--- /dev/null
+++ b/build/android/pylib/utils/isolator.py
@@ -0,0 +1,173 @@
+# Copyright 2014 The Chromium 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 fnmatch
+import glob
+import os
+import shutil
+import sys
+
+from pylib import cmd_helper
+from pylib import constants
+
+
+_ISOLATE_SCRIPT = os.path.join(
+    constants.DIR_SOURCE_ROOT, 'tools', 'swarming_client', 'isolate.py')
+
+
+def DefaultPathVariables():
+  return {
+    'DEPTH': constants.DIR_SOURCE_ROOT,
+    'PRODUCT_DIR': constants.GetOutDirectory(),
+  }
+
+
+def DefaultConfigVariables():
+  # Note: This list must match the --config-vars in build/isolate.gypi
+  return {
+    'CONFIGURATION_NAME': constants.GetBuildType(),
+    'OS': 'android',
+    'asan': '0',
+    'branding': 'Chromium',
+    'chromeos': '0',
+    'component': 'static_library',
+    'enable_pepper_cdms': '0',
+    'enable_plugins': '0',
+    'fastbuild': '0',
+    'icu_use_data_file_flag': '1',
+    'kasko': '0',
+    'lsan': '0',
+    'msan': '0',
+    # TODO(maruel): This may not always be true.
+    'target_arch': 'arm',
+    'tsan': '0',
+    'use_custom_libcxx': '0',
+    'use_instrumented_libraries': '0',
+    'use_prebuilt_instrumented_libraries': '0',
+    'use_openssl': '0',
+    'use_ozone': '0',
+    'use_x11': '0',
+    'v8_use_external_startup_data': '1',
+  }
+
+
+class Isolator(object):
+  """Manages calls to isolate.py for the android test runner scripts."""
+
+  def __init__(self, isolate_deps_dir):
+    """
+    Args:
+      isolate_deps_dir: The directory in which dependencies specified by
+        isolate are or should be stored.
+    """
+    self._isolate_deps_dir = isolate_deps_dir
+
+  def Clear(self):
+    """Deletes the isolate dependency directory."""
+    if os.path.exists(self._isolate_deps_dir):
+      shutil.rmtree(self._isolate_deps_dir)
+
+  def Remap(self, isolate_abs_path, isolated_abs_path,
+            path_variables=None, config_variables=None):
+    """Remaps data dependencies into |self._isolate_deps_dir|.
+
+    Args:
+      isolate_abs_path: The absolute path to the .isolate file, which specifies
+        data dependencies in the source tree.
+      isolated_abs_path: The absolute path to the .isolated file, which is
+        generated by isolate.py and specifies data dependencies in
+        |self._isolate_deps_dir| and their digests.
+      path_variables: A dict containing everything that should be passed
+        as a |--path-variable| to the isolate script. Defaults to the return
+        value of |DefaultPathVariables()|.
+      config_variables: A dict containing everything that should be passed
+        as a |--config-variable| to the isolate script. Defaults to the return
+        value of |DefaultConfigVariables()|.
+    Raises:
+      Exception if the isolate command fails for some reason.
+    """
+    if not path_variables:
+      path_variables = DefaultPathVariables()
+    if not config_variables:
+      config_variables = DefaultConfigVariables()
+
+    isolate_cmd = [
+      sys.executable, _ISOLATE_SCRIPT, 'remap',
+      '--isolate', isolate_abs_path,
+      '--isolated', isolated_abs_path,
+      '--outdir', self._isolate_deps_dir,
+    ]
+    for k, v in path_variables.iteritems():
+      isolate_cmd.extend(['--path-variable', k, v])
+    for k, v in config_variables.iteritems():
+      isolate_cmd.extend(['--config-variable', k, v])
+
+    if cmd_helper.RunCmd(isolate_cmd):
+      raise Exception('isolate command failed: %s' % ' '.join(isolate_cmd))
+
+  def VerifyHardlinks(self):
+    """Checks |isolate_deps_dir| for a hardlink.
+
+    Returns:
+      True if a hardlink is found.
+      False if nothing is found.
+    Raises:
+      Exception if a non-hardlink is found.
+    """
+    for root, _, filenames in os.walk(self._isolate_deps_dir):
+      if filenames:
+        linked_file = os.path.join(root, filenames[0])
+        orig_file = os.path.join(
+            self._isolate_deps_dir,
+            os.path.relpath(linked_file, self._isolate_deps_dir))
+        if os.stat(linked_file).st_ino == os.stat(orig_file).st_ino:
+          return True
+        else:
+          raise Exception('isolate remap command did not use hardlinks.')
+    return False
+
+  def PurgeExcluded(self, deps_exclusion_list):
+    """Deletes anything on |deps_exclusion_list| from |self._isolate_deps_dir|.
+
+    Args:
+      deps_exclusion_list: A list of globs to exclude from the isolate
+        dependency directory.
+    """
+    excluded_paths = (
+        x for y in deps_exclusion_list
+        for x in glob.glob(
+            os.path.abspath(os.path.join(self._isolate_deps_dir, y))))
+    for p in excluded_paths:
+      if os.path.isdir(p):
+        shutil.rmtree(p)
+      else:
+        os.remove(p)
+
+  def MoveOutputDeps(self):
+    """Moves files from the output directory to the top level of
+      |self._isolate_deps_dir|.
+
+    Moves pak files from the output directory to to <isolate_deps_dir>/paks
+    Moves files from the product directory to <isolate_deps_dir>
+    """
+    # On Android, all pak files need to be in the top-level 'paks' directory.
+    paks_dir = os.path.join(self._isolate_deps_dir, 'paks')
+    os.mkdir(paks_dir)
+
+    deps_out_dir = os.path.join(
+        self._isolate_deps_dir,
+        os.path.relpath(os.path.join(constants.GetOutDirectory(), os.pardir),
+                        constants.DIR_SOURCE_ROOT))
+    for root, _, filenames in os.walk(deps_out_dir):
+      for filename in fnmatch.filter(filenames, '*.pak'):
+        shutil.move(os.path.join(root, filename), paks_dir)
+
+    # Move everything in PRODUCT_DIR to top level.
+    deps_product_dir = os.path.join(deps_out_dir, constants.GetBuildType())
+    if os.path.isdir(deps_product_dir):
+      for p in os.listdir(deps_product_dir):
+        shutil.move(os.path.join(deps_product_dir, p), self._isolate_deps_dir)
+      os.rmdir(deps_product_dir)
+      os.rmdir(deps_out_dir)
+
diff --git a/build/android/pylib/utils/json_results_generator_unittest.py b/build/android/pylib/utils/json_results_generator_unittest.py
new file mode 100644
index 0000000..41ab77b
--- /dev/null
+++ b/build/android/pylib/utils/json_results_generator_unittest.py
@@ -0,0 +1,213 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#
+# Most of this file was ported over from Blink's
+# webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
+#
+
+import unittest
+import json
+
+from pylib.utils import json_results_generator
+
+
+class JSONGeneratorTest(unittest.TestCase):
+
+  def setUp(self):
+    self.builder_name = 'DUMMY_BUILDER_NAME'
+    self.build_name = 'DUMMY_BUILD_NAME'
+    self.build_number = 'DUMMY_BUILDER_NUMBER'
+
+    # For archived results.
+    self._json = None
+    self._num_runs = 0
+    self._tests_set = set([])
+    self._test_timings = {}
+    self._failed_count_map = {}
+
+    self._PASS_count = 0
+    self._DISABLED_count = 0
+    self._FLAKY_count = 0
+    self._FAILS_count = 0
+    self._fixable_count = 0
+
+    self._orig_write_json = json_results_generator.WriteJSON
+
+    # unused arguments ... pylint: disable=W0613
+    def _WriteJSONStub(json_object, file_path, callback=None):
+      pass
+
+    json_results_generator.WriteJSON = _WriteJSONStub
+
+  def tearDown(self):
+    json_results_generator.WriteJSON = self._orig_write_json
+
+  def _TestJSONGeneration(self, passed_tests_list, failed_tests_list):
+    tests_set = set(passed_tests_list) | set(failed_tests_list)
+
+    DISABLED_tests = set([t for t in tests_set
+                          if t.startswith('DISABLED_')])
+    FLAKY_tests = set([t for t in tests_set
+                       if t.startswith('FLAKY_')])
+    FAILS_tests = set([t for t in tests_set
+                       if t.startswith('FAILS_')])
+    PASS_tests = tests_set - (DISABLED_tests | FLAKY_tests | FAILS_tests)
+
+    failed_tests = set(failed_tests_list) - DISABLED_tests
+    failed_count_map = dict([(t, 1) for t in failed_tests])
+
+    test_timings = {}
+    i = 0
+    for test in tests_set:
+      test_timings[test] = float(self._num_runs * 100 + i)
+      i += 1
+
+    test_results_map = dict()
+    for test in tests_set:
+      test_results_map[test] = json_results_generator.TestResult(
+          test, failed=(test in failed_tests),
+          elapsed_time=test_timings[test])
+
+    generator = json_results_generator.JSONResultsGeneratorBase(
+        self.builder_name, self.build_name, self.build_number,
+        '',
+        None,   # don't fetch past json results archive
+        test_results_map)
+
+    failed_count_map = dict([(t, 1) for t in failed_tests])
+
+    # Test incremental json results
+    incremental_json = generator.GetJSON()
+    self._VerifyJSONResults(
+        tests_set,
+        test_timings,
+        failed_count_map,
+        len(PASS_tests),
+        len(DISABLED_tests),
+        len(FLAKY_tests),
+        len(DISABLED_tests | failed_tests),
+        incremental_json,
+        1)
+
+    # We don't verify the results here, but at least we make sure the code
+    # runs without errors.
+    generator.GenerateJSONOutput()
+    generator.GenerateTimesMSFile()
+
+  def _VerifyJSONResults(self, tests_set, test_timings, failed_count_map,
+                         PASS_count, DISABLED_count, FLAKY_count,
+                         fixable_count, json_obj, num_runs):
+    # Aliasing to a short name for better access to its constants.
+    JRG = json_results_generator.JSONResultsGeneratorBase
+
+    self.assertIn(JRG.VERSION_KEY, json_obj)
+    self.assertIn(self.builder_name, json_obj)
+
+    buildinfo = json_obj[self.builder_name]
+    self.assertIn(JRG.FIXABLE, buildinfo)
+    self.assertIn(JRG.TESTS, buildinfo)
+    self.assertEqual(len(buildinfo[JRG.BUILD_NUMBERS]), num_runs)
+    self.assertEqual(buildinfo[JRG.BUILD_NUMBERS][0], self.build_number)
+
+    if tests_set or DISABLED_count:
+      fixable = {}
+      for fixable_items in buildinfo[JRG.FIXABLE]:
+        for (result_type, count) in fixable_items.iteritems():
+          if result_type in fixable:
+            fixable[result_type] = fixable[result_type] + count
+          else:
+            fixable[result_type] = count
+
+      if PASS_count:
+        self.assertEqual(fixable[JRG.PASS_RESULT], PASS_count)
+      else:
+        self.assertTrue(JRG.PASS_RESULT not in fixable or
+                        fixable[JRG.PASS_RESULT] == 0)
+      if DISABLED_count:
+        self.assertEqual(fixable[JRG.SKIP_RESULT], DISABLED_count)
+      else:
+        self.assertTrue(JRG.SKIP_RESULT not in fixable or
+                        fixable[JRG.SKIP_RESULT] == 0)
+      if FLAKY_count:
+        self.assertEqual(fixable[JRG.FLAKY_RESULT], FLAKY_count)
+      else:
+        self.assertTrue(JRG.FLAKY_RESULT not in fixable or
+                        fixable[JRG.FLAKY_RESULT] == 0)
+
+    if failed_count_map:
+      tests = buildinfo[JRG.TESTS]
+      for test_name in failed_count_map.iterkeys():
+        test = self._FindTestInTrie(test_name, tests)
+
+        failed = 0
+        for result in test[JRG.RESULTS]:
+          if result[1] == JRG.FAIL_RESULT:
+            failed += result[0]
+        self.assertEqual(failed_count_map[test_name], failed)
+
+        timing_count = 0
+        for timings in test[JRG.TIMES]:
+          if timings[1] == test_timings[test_name]:
+            timing_count = timings[0]
+        self.assertEqual(1, timing_count)
+
+    if fixable_count:
+      self.assertEqual(sum(buildinfo[JRG.FIXABLE_COUNT]), fixable_count)
+
+  def _FindTestInTrie(self, path, trie):
+    nodes = path.split('/')
+    sub_trie = trie
+    for node in nodes:
+      self.assertIn(node, sub_trie)
+      sub_trie = sub_trie[node]
+    return sub_trie
+
+  def testJSONGeneration(self):
+    self._TestJSONGeneration([], [])
+    self._TestJSONGeneration(['A1', 'B1'], [])
+    self._TestJSONGeneration([], ['FAILS_A2', 'FAILS_B2'])
+    self._TestJSONGeneration(['DISABLED_A3', 'DISABLED_B3'], [])
+    self._TestJSONGeneration(['A4'], ['B4', 'FAILS_C4'])
+    self._TestJSONGeneration(['DISABLED_C5', 'DISABLED_D5'], ['A5', 'B5'])
+    self._TestJSONGeneration(
+        ['A6', 'B6', 'FAILS_C6', 'DISABLED_E6', 'DISABLED_F6'],
+        ['FAILS_D6'])
+
+    # Generate JSON with the same test sets. (Both incremental results and
+    # archived results must be updated appropriately.)
+    self._TestJSONGeneration(
+        ['A', 'FLAKY_B', 'DISABLED_C'],
+        ['FAILS_D', 'FLAKY_E'])
+    self._TestJSONGeneration(
+        ['A', 'DISABLED_C', 'FLAKY_E'],
+        ['FLAKY_B', 'FAILS_D'])
+    self._TestJSONGeneration(
+        ['FLAKY_B', 'DISABLED_C', 'FAILS_D'],
+        ['A', 'FLAKY_E'])
+
+  def testHierarchicalJSNGeneration(self):
+    # FIXME: Re-work tests to be more comprehensible and comprehensive.
+    self._TestJSONGeneration(['foo/A'], ['foo/B', 'bar/C'])
+
+  def testTestTimingsTrie(self):
+    individual_test_timings = []
+    individual_test_timings.append(
+        json_results_generator.TestResult(
+            'foo/bar/baz.html',
+            elapsed_time=1.2))
+    individual_test_timings.append(
+        json_results_generator.TestResult('bar.html', elapsed_time=0.0001))
+    trie = json_results_generator.TestTimingsTrie(individual_test_timings)
+
+    expected_trie = {
+        'bar.html': 0,
+        'foo': {
+            'bar': {
+                'baz.html': 1200,
+            }
+        }
+    }
+
+    self.assertEqual(json.dumps(trie), json.dumps(expected_trie))
diff --git a/build/android/pylib/utils/logging_utils.py b/build/android/pylib/utils/logging_utils.py
new file mode 100644
index 0000000..1e46fa8
--- /dev/null
+++ b/build/android/pylib/utils/logging_utils.py
@@ -0,0 +1,27 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import contextlib
+import logging
+
+@contextlib.contextmanager
+def SuppressLogging(level=logging.ERROR):
+  """Momentarilly suppress logging events from all loggers.
+
+  TODO(jbudorick): This is not thread safe. Log events from other threads might
+  also inadvertently dissapear.
+
+  Example:
+
+    with logging_utils.SuppressLogging():
+      # all but CRITICAL logging messages are suppressed
+      logging.info('just doing some thing') # not shown
+      logging.critical('something really bad happened') # still shown
+
+  Args:
+    level: logging events with this or lower levels are suppressed.
+  """
+  logging.disable(level)
+  yield
+  logging.disable(logging.NOTSET)
diff --git a/build/android/pylib/utils/md5sum.py b/build/android/pylib/utils/md5sum.py
new file mode 100644
index 0000000..d59245c
--- /dev/null
+++ b/build/android/pylib/utils/md5sum.py
@@ -0,0 +1,87 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import logging
+import os
+import re
+import tempfile
+import types
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.utils import device_temp_file
+
+MD5SUM_DEVICE_LIB_PATH = '/data/local/tmp/md5sum/'
+MD5SUM_DEVICE_BIN_PATH = MD5SUM_DEVICE_LIB_PATH + 'md5sum_bin'
+
+MD5SUM_DEVICE_SCRIPT_FORMAT = (
+    'test -f {path} -o -d {path} '
+    '&& LD_LIBRARY_PATH={md5sum_lib} {device_pie_wrapper} {md5sum_bin} {path}')
+
+_STARTS_WITH_CHECKSUM_RE = re.compile(r'^\s*[0-9a-fA-f]{32}\s+')
+
+
+def CalculateHostMd5Sums(paths):
+  """Calculates the MD5 sum value for all items in |paths|.
+
+  Args:
+    paths: A list of host paths to md5sum.
+  Returns:
+    A dict mapping paths to their respective md5sum checksums.
+  """
+  if isinstance(paths, basestring):
+    paths = [paths]
+
+  md5sum_bin_host_path = os.path.join(
+      constants.GetOutDirectory(), 'md5sum_bin_host')
+  if not os.path.exists(md5sum_bin_host_path):
+    raise IOError('File not built: %s' % md5sum_bin_host_path)
+  out = cmd_helper.GetCmdOutput([md5sum_bin_host_path] + [p for p in paths])
+
+  return _ParseMd5SumOutput(out.splitlines())
+
+
+def CalculateDeviceMd5Sums(paths, device):
+  """Calculates the MD5 sum value for all items in |paths|.
+
+  Args:
+    paths: A list of device paths to md5sum.
+  Returns:
+    A dict mapping paths to their respective md5sum checksums.
+  """
+  if isinstance(paths, basestring):
+    paths = [paths]
+
+  if not device.FileExists(MD5SUM_DEVICE_BIN_PATH):
+    md5sum_dist_path = os.path.join(constants.GetOutDirectory(), 'md5sum_dist')
+    if not os.path.exists(md5sum_dist_path):
+      raise IOError('File not built: %s' % md5sum_dist_path)
+    device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
+
+  out = []
+
+  with tempfile.NamedTemporaryFile() as md5sum_script_file:
+    with device_temp_file.DeviceTempFile(
+        device.adb) as md5sum_device_script_file:
+      device_pie_wrapper = device.GetDevicePieWrapper()
+      md5sum_script = (
+          MD5SUM_DEVICE_SCRIPT_FORMAT.format(
+              path=p, md5sum_lib=MD5SUM_DEVICE_LIB_PATH,
+              device_pie_wrapper=device_pie_wrapper,
+              md5sum_bin=MD5SUM_DEVICE_BIN_PATH)
+          for p in paths)
+      md5sum_script_file.write('; '.join(md5sum_script))
+      md5sum_script_file.flush()
+      device.adb.Push(md5sum_script_file.name, md5sum_device_script_file.name)
+      out = device.RunShellCommand(['sh', md5sum_device_script_file.name])
+
+  return _ParseMd5SumOutput(out)
+
+
+def _ParseMd5SumOutput(out):
+  hash_and_path = (l.split(None, 1) for l in out
+                   if l and _STARTS_WITH_CHECKSUM_RE.match(l))
+  return dict((p, h) for h, p in hash_and_path)
+
diff --git a/build/android/pylib/utils/md5sum_test.py b/build/android/pylib/utils/md5sum_test.py
new file mode 100755
index 0000000..5bdee32
--- /dev/null
+++ b/build/android/pylib/utils/md5sum_test.py
@@ -0,0 +1,230 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 os
+import sys
+import unittest
+
+from pylib import cmd_helper
+from pylib import constants
+from pylib.utils import md5sum
+
+sys.path.append(
+    os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock
+
+TEST_OUT_DIR = os.path.join('test', 'out', 'directory')
+HOST_MD5_EXECUTABLE = os.path.join(TEST_OUT_DIR, 'md5sum_bin_host')
+
+class Md5SumTest(unittest.TestCase):
+
+  def setUp(self):
+    self._patchers = [
+        mock.patch('pylib.constants.GetOutDirectory',
+                   new=mock.Mock(return_value=TEST_OUT_DIR)),
+        mock.patch('os.path.exists',
+                   new=mock.Mock(return_value=True)),
+    ]
+    for p in self._patchers:
+      p.start()
+
+  def tearDown(self):
+    for p in self._patchers:
+      p.stop()
+
+  def testCalculateHostMd5Sums_singlePath(self):
+    test_path = '/test/host/file.dat'
+    mock_get_cmd_output = mock.Mock(
+        return_value='0123456789abcdeffedcba9876543210 /test/host/file.dat')
+    with mock.patch('pylib.cmd_helper.GetCmdOutput', new=mock_get_cmd_output):
+      out = md5sum.CalculateHostMd5Sums(test_path)
+      self.assertEquals(1, len(out))
+      self.assertTrue('/test/host/file.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/test/host/file.dat'])
+      mock_get_cmd_output.assert_called_once_with(
+          [HOST_MD5_EXECUTABLE, '/test/host/file.dat'])
+
+  def testCalculateHostMd5Sums_list(self):
+    test_paths = ['/test/host/file0.dat', '/test/host/file1.dat']
+    mock_get_cmd_output = mock.Mock(
+        return_value='0123456789abcdeffedcba9876543210 /test/host/file0.dat\n'
+                     '123456789abcdef00fedcba987654321 /test/host/file1.dat\n')
+    with mock.patch('pylib.cmd_helper.GetCmdOutput', new=mock_get_cmd_output):
+      out = md5sum.CalculateHostMd5Sums(test_paths)
+      self.assertEquals(2, len(out))
+      self.assertTrue('/test/host/file0.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/test/host/file0.dat'])
+      self.assertTrue('/test/host/file1.dat' in out)
+      self.assertEquals('123456789abcdef00fedcba987654321',
+                        out['/test/host/file1.dat'])
+      mock_get_cmd_output.assert_called_once_with(
+          [HOST_MD5_EXECUTABLE, '/test/host/file0.dat',
+           '/test/host/file1.dat'])
+
+  def testCalculateHostMd5Sums_generator(self):
+    test_paths = ('/test/host/' + p for p in ['file0.dat', 'file1.dat'])
+    mock_get_cmd_output = mock.Mock(
+        return_value='0123456789abcdeffedcba9876543210 /test/host/file0.dat\n'
+                     '123456789abcdef00fedcba987654321 /test/host/file1.dat\n')
+    with mock.patch('pylib.cmd_helper.GetCmdOutput', new=mock_get_cmd_output):
+      out = md5sum.CalculateHostMd5Sums(test_paths)
+      self.assertEquals(2, len(out))
+      self.assertTrue('/test/host/file0.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/test/host/file0.dat'])
+      self.assertTrue('/test/host/file1.dat' in out)
+      self.assertEquals('123456789abcdef00fedcba987654321',
+                        out['/test/host/file1.dat'])
+      mock_get_cmd_output.assert_called_once_with(
+          [HOST_MD5_EXECUTABLE, '/test/host/file0.dat', '/test/host/file1.dat'])
+
+  def testCalculateDeviceMd5Sums_singlePath(self):
+    test_path = '/storage/emulated/legacy/test/file.dat'
+
+    device = mock.NonCallableMock()
+    device.adb = mock.NonCallableMock()
+    device.adb.Push = mock.Mock()
+    device_md5sum_output = [
+        '0123456789abcdeffedcba9876543210 '
+            '/storage/emulated/legacy/test/file.dat',
+    ]
+    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+
+    mock_temp_file = mock.mock_open()
+    mock_temp_file.return_value.name = '/tmp/test/script/file.sh'
+
+    mock_device_temp_file = mock.mock_open()
+    mock_device_temp_file.return_value.name = (
+        '/data/local/tmp/test/script/file.sh')
+
+    with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), (
+         mock.patch('pylib.utils.device_temp_file.DeviceTempFile',
+                    new=mock_device_temp_file)):
+      out = md5sum.CalculateDeviceMd5Sums(test_path, device)
+      self.assertEquals(1, len(out))
+      self.assertTrue('/storage/emulated/legacy/test/file.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/storage/emulated/legacy/test/file.dat'])
+      device.adb.Push.assert_called_once_with(
+          '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh')
+      device.RunShellCommand.assert_called_once_with(
+          ['sh', '/data/local/tmp/test/script/file.sh'])
+
+  def testCalculateDeviceMd5Sums_list(self):
+    test_path = ['/storage/emulated/legacy/test/file0.dat',
+                 '/storage/emulated/legacy/test/file1.dat']
+    device = mock.NonCallableMock()
+    device.adb = mock.NonCallableMock()
+    device.adb.Push = mock.Mock()
+    device_md5sum_output = [
+        '0123456789abcdeffedcba9876543210 '
+            '/storage/emulated/legacy/test/file0.dat',
+        '123456789abcdef00fedcba987654321 '
+            '/storage/emulated/legacy/test/file1.dat',
+    ]
+    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+
+    mock_temp_file = mock.mock_open()
+    mock_temp_file.return_value.name = '/tmp/test/script/file.sh'
+
+    mock_device_temp_file = mock.mock_open()
+    mock_device_temp_file.return_value.name = (
+        '/data/local/tmp/test/script/file.sh')
+
+    with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), (
+         mock.patch('pylib.utils.device_temp_file.DeviceTempFile',
+                    new=mock_device_temp_file)):
+      out = md5sum.CalculateDeviceMd5Sums(test_path, device)
+      self.assertEquals(2, len(out))
+      self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/storage/emulated/legacy/test/file0.dat'])
+      self.assertTrue('/storage/emulated/legacy/test/file1.dat' in out)
+      self.assertEquals('123456789abcdef00fedcba987654321',
+                        out['/storage/emulated/legacy/test/file1.dat'])
+      device.adb.Push.assert_called_once_with(
+          '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh')
+      device.RunShellCommand.assert_called_once_with(
+          ['sh', '/data/local/tmp/test/script/file.sh'])
+
+  def testCalculateDeviceMd5Sums_generator(self):
+    test_path = ('/storage/emulated/legacy/test/file%d.dat' % n
+                 for n in xrange(0, 2))
+
+    device = mock.NonCallableMock()
+    device.adb = mock.NonCallableMock()
+    device.adb.Push = mock.Mock()
+    device_md5sum_output = [
+        '0123456789abcdeffedcba9876543210 '
+            '/storage/emulated/legacy/test/file0.dat',
+        '123456789abcdef00fedcba987654321 '
+            '/storage/emulated/legacy/test/file1.dat',
+    ]
+    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+
+    mock_temp_file = mock.mock_open()
+    mock_temp_file.return_value.name = '/tmp/test/script/file.sh'
+
+    mock_device_temp_file = mock.mock_open()
+    mock_device_temp_file.return_value.name = (
+        '/data/local/tmp/test/script/file.sh')
+
+    with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), (
+         mock.patch('pylib.utils.device_temp_file.DeviceTempFile',
+                    new=mock_device_temp_file)):
+      out = md5sum.CalculateDeviceMd5Sums(test_path, device)
+      self.assertEquals(2, len(out))
+      self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/storage/emulated/legacy/test/file0.dat'])
+      self.assertTrue('/storage/emulated/legacy/test/file1.dat' in out)
+      self.assertEquals('123456789abcdef00fedcba987654321',
+                        out['/storage/emulated/legacy/test/file1.dat'])
+      device.adb.Push.assert_called_once_with(
+          '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh')
+      device.RunShellCommand.assert_called_once_with(
+          ['sh', '/data/local/tmp/test/script/file.sh'])
+
+  def testCalculateDeviceMd5Sums_singlePath_linkerWarning(self):
+    # See crbug/479966
+    test_path = '/storage/emulated/legacy/test/file.dat'
+
+    device = mock.NonCallableMock()
+    device.adb = mock.NonCallableMock()
+    device.adb.Push = mock.Mock()
+    device_md5sum_output = [
+        'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: '
+            'unused DT entry: type 0x1d arg 0x15db',
+        '0123456789abcdeffedcba9876543210 '
+            '/storage/emulated/legacy/test/file.dat',
+    ]
+    device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
+
+    mock_temp_file = mock.mock_open()
+    mock_temp_file.return_value.name = '/tmp/test/script/file.sh'
+
+    mock_device_temp_file = mock.mock_open()
+    mock_device_temp_file.return_value.name = (
+        '/data/local/tmp/test/script/file.sh')
+
+    with mock.patch('tempfile.NamedTemporaryFile', new=mock_temp_file), (
+         mock.patch('pylib.utils.device_temp_file.DeviceTempFile',
+                    new=mock_device_temp_file)):
+      out = md5sum.CalculateDeviceMd5Sums(test_path, device)
+      self.assertEquals(1, len(out))
+      self.assertTrue('/storage/emulated/legacy/test/file.dat' in out)
+      self.assertEquals('0123456789abcdeffedcba9876543210',
+                        out['/storage/emulated/legacy/test/file.dat'])
+      device.adb.Push.assert_called_once_with(
+          '/tmp/test/script/file.sh', '/data/local/tmp/test/script/file.sh')
+      device.RunShellCommand.assert_called_once_with(
+          ['sh', '/data/local/tmp/test/script/file.sh'])
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/utils/mock_calls.py b/build/android/pylib/utils/mock_calls.py
new file mode 100644
index 0000000..59167ba
--- /dev/null
+++ b/build/android/pylib/utils/mock_calls.py
@@ -0,0 +1,182 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+A test facility to assert call sequences while mocking their behavior.
+"""
+
+import os
+import sys
+import unittest
+
+from pylib import constants
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class TestCase(unittest.TestCase):
+  """Adds assertCalls to TestCase objects."""
+  class _AssertCalls(object):
+    def __init__(self, test_case, expected_calls, watched):
+      def call_action(pair):
+        if isinstance(pair, type(mock.call)):
+          return (pair, None)
+        else:
+          return pair
+
+      def do_check(call):
+        def side_effect(*args, **kwargs):
+          received_call = call(*args, **kwargs)
+          self._test_case.assertTrue(
+              self._expected_calls,
+              msg=('Unexpected call: %s' % str(received_call)))
+          expected_call, action = self._expected_calls.pop(0)
+          self._test_case.assertTrue(
+              received_call == expected_call,
+              msg=('Expected call mismatch:\n'
+                   '  expected: %s\n'
+                   '  received: %s\n'
+                   % (str(expected_call), str(received_call))))
+          if callable(action):
+            return action(*args, **kwargs)
+          else:
+            return action
+        return side_effect
+
+      self._test_case = test_case
+      self._expected_calls = [call_action(pair) for pair in expected_calls]
+      watched = watched.copy() # do not pollute the caller's dict
+      watched.update((call.parent.name, call.parent)
+                     for call, _ in self._expected_calls)
+      self._patched = [test_case.patch_call(call, side_effect=do_check(call))
+                       for call in watched.itervalues()]
+
+    def __enter__(self):
+      for patch in self._patched:
+        patch.__enter__()
+      return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+      for patch in self._patched:
+        patch.__exit__(exc_type, exc_val, exc_tb)
+      if exc_type is None:
+        missing = ''.join('  expected: %s\n' % str(call)
+                          for call, _ in self._expected_calls)
+        self._test_case.assertFalse(
+            missing,
+            msg='Expected calls not found:\n' + missing)
+
+  def __init__(self, *args, **kwargs):
+    super(TestCase, self).__init__(*args, **kwargs)
+    self.call = mock.call.self
+    self._watched = {}
+
+  def call_target(self, call):
+    """Resolve a self.call instance to the target it represents.
+
+    Args:
+      call: a self.call instance, e.g. self.call.adb.Shell
+
+    Returns:
+      The target object represented by the call, e.g. self.adb.Shell
+
+    Raises:
+      ValueError if the path of the call does not start with "self", i.e. the
+          target of the call is external to the self object.
+      AttributeError if the path of the call does not specify a valid
+          chain of attributes (without any calls) starting from "self".
+    """
+    path = call.name.split('.')
+    if path.pop(0) != 'self':
+      raise ValueError("Target %r outside of 'self' object" % call.name)
+    target = self
+    for attr in path:
+      target = getattr(target, attr)
+    return target
+
+  def patch_call(self, call, **kwargs):
+    """Patch the target of a mock.call instance.
+
+    Args:
+      call: a mock.call instance identifying a target to patch
+      Extra keyword arguments are processed by mock.patch
+
+    Returns:
+      A context manager to mock/unmock the target of the call
+    """
+    if call.name.startswith('self.'):
+      target = self.call_target(call.parent)
+      _, attribute = call.name.rsplit('.', 1)
+      if (hasattr(type(target), attribute)
+          and isinstance(getattr(type(target), attribute), property)):
+        return mock.patch.object(
+            type(target), attribute, new_callable=mock.PropertyMock, **kwargs)
+      else:
+        return mock.patch.object(target, attribute, **kwargs)
+    else:
+      return mock.patch(call.name, **kwargs)
+
+  def watchCalls(self, calls):
+    """Add calls to the set of watched calls.
+
+    Args:
+      calls: a sequence of mock.call instances identifying targets to watch
+    """
+    self._watched.update((call.name, call) for call in calls)
+
+  def watchMethodCalls(self, call, ignore=None):
+    """Watch all public methods of the target identified by a self.call.
+
+    Args:
+      call: a self.call instance indetifying an object
+      ignore: a list of public methods to ignore when watching for calls
+    """
+    target = self.call_target(call)
+    if ignore is None:
+      ignore = []
+    self.watchCalls(getattr(call, method)
+                    for method in dir(target.__class__)
+                    if not method.startswith('_') and not method in ignore)
+
+  def clearWatched(self):
+    """Clear the set of watched calls."""
+    self._watched = {}
+
+  def assertCalls(self, *calls):
+    """A context manager to assert that a sequence of calls is made.
+
+    During the assertion, a number of functions and methods will be "watched",
+    and any calls made to them is expected to appear---in the exact same order,
+    and with the exact same arguments---as specified by the argument |calls|.
+
+    By default, the targets of all expected calls are watched. Further targets
+    to watch may be added using watchCalls and watchMethodCalls.
+
+    Optionaly, each call may be accompanied by an action. If the action is a
+    (non-callable) value, this value will be used as the return value given to
+    the caller when the matching call is found. Alternatively, if the action is
+    a callable, the action will be then called with the same arguments as the
+    intercepted call, so that it can provide a return value or perform other
+    side effects. If the action is missing, a return value of None is assumed.
+
+    Note that mock.Mock objects are often convenient to use as a callable
+    action, e.g. to raise exceptions or return other objects which are
+    themselves callable.
+
+    Args:
+      calls: each argument is either a pair (expected_call, action) or just an
+          expected_call, where expected_call is a mock.call instance.
+
+    Raises:
+      AssertionError if the watched targets do not receive the exact sequence
+          of calls specified. Missing calls, extra calls, and calls with
+          mismatching arguments, all cause the assertion to fail.
+    """
+    return self._AssertCalls(self, calls, self._watched)
+
+  def assertCall(self, call, action=None):
+    return self.assertCalls((call, action))
+
diff --git a/build/android/pylib/utils/mock_calls_test.py b/build/android/pylib/utils/mock_calls_test.py
new file mode 100755
index 0000000..4dbafd4
--- /dev/null
+++ b/build/android/pylib/utils/mock_calls_test.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for the contents of mock_calls.py.
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.utils import mock_calls
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class _DummyAdb(object):
+  def __str__(self):
+    return '0123456789abcdef'
+
+  def Push(self, host_path, device_path):
+    logging.debug('(device %s) pushing %r to %r', self, host_path, device_path)
+
+  def IsOnline(self):
+    logging.debug('(device %s) checking device online', self)
+    return True
+
+  def Shell(self, cmd):
+    logging.debug('(device %s) running command %r', self, cmd)
+    return "nice output\n"
+
+  def Reboot(self):
+    logging.debug('(device %s) rebooted!', self)
+
+  @property
+  def build_version_sdk(self):
+    logging.debug('(device %s) getting build_version_sdk', self)
+    return constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP
+
+
+class TestCaseWithAssertCallsTest(mock_calls.TestCase):
+  def setUp(self):
+    self.adb = _DummyAdb()
+
+  def ShellError(self):
+    def action(cmd):
+      raise ValueError('(device %s) command %r is not nice' % (self.adb, cmd))
+    return action
+
+  def get_answer(self):
+    logging.debug("called 'get_answer' of %r object", self)
+    return 42
+
+  def echo(self, thing):
+    logging.debug("called 'echo' of %r object", self)
+    return thing
+
+  def testCallTarget_succeds(self):
+    self.assertEquals(self.adb.Shell,
+                      self.call_target(self.call.adb.Shell))
+
+  def testCallTarget_failsExternal(self):
+    with self.assertRaises(ValueError):
+      self.call_target(mock.call.sys.getcwd)
+
+  def testCallTarget_failsUnknownAttribute(self):
+    with self.assertRaises(AttributeError):
+      self.call_target(self.call.adb.Run)
+
+  def testCallTarget_failsIntermediateCalls(self):
+    with self.assertRaises(AttributeError):
+      self.call_target(self.call.adb.RunShell('cmd').append)
+
+  def testPatchCall_method(self):
+    self.assertEquals(42, self.get_answer())
+    with self.patch_call(self.call.get_answer, return_value=123):
+      self.assertEquals(123, self.get_answer())
+    self.assertEquals(42, self.get_answer())
+
+  def testPatchCall_attribute_method(self):
+    with self.patch_call(self.call.adb.Shell, return_value='hello'):
+      self.assertEquals('hello', self.adb.Shell('echo hello'))
+
+  def testPatchCall_global(self):
+    with self.patch_call(mock.call.os.getcwd, return_value='/some/path'):
+      self.assertEquals('/some/path', os.getcwd())
+
+  def testPatchCall_withSideEffect(self):
+    with self.patch_call(self.call.adb.Shell, side_effect=ValueError):
+      with self.assertRaises(ValueError):
+        self.adb.Shell('echo hello')
+
+  def testPatchCall_property(self):
+    self.assertEquals(constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP,
+                      self.adb.build_version_sdk)
+    with self.patch_call(
+        self.call.adb.build_version_sdk,
+        return_value=constants.ANDROID_SDK_VERSION_CODES.KITKAT):
+      self.assertEquals(constants.ANDROID_SDK_VERSION_CODES.KITKAT,
+                        self.adb.build_version_sdk)
+    self.assertEquals(constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP,
+                      self.adb.build_version_sdk)
+
+  def testAssertCalls_succeeds_simple(self):
+    self.assertEquals(42, self.get_answer())
+    with self.assertCall(self.call.get_answer(), 123):
+      self.assertEquals(123, self.get_answer())
+    self.assertEquals(42, self.get_answer())
+
+  def testAssertCalls_succeeds_multiple(self):
+    with self.assertCalls(
+        (mock.call.os.getcwd(), '/some/path'),
+        (self.call.echo('hello'), 'hello'),
+        (self.call.get_answer(), 11),
+        self.call.adb.Push('this_file', 'that_file'),
+        (self.call.get_answer(), 12)):
+      self.assertEquals(os.getcwd(), '/some/path')
+      self.assertEquals('hello', self.echo('hello'))
+      self.assertEquals(11, self.get_answer())
+      self.adb.Push('this_file', 'that_file')
+      self.assertEquals(12, self.get_answer())
+
+  def testAsserCalls_succeeds_withAction(self):
+    with self.assertCall(
+        self.call.adb.Shell('echo hello'), self.ShellError()):
+      with self.assertRaises(ValueError):
+        self.adb.Shell('echo hello')
+
+  def testAssertCalls_fails_tooManyCalls(self):
+    with self.assertRaises(AssertionError):
+      with self.assertCalls(self.call.adb.IsOnline()):
+        self.adb.IsOnline()
+        self.adb.IsOnline()
+
+  def testAssertCalls_fails_tooFewCalls(self):
+    with self.assertRaises(AssertionError):
+      with self.assertCalls(self.call.adb.IsOnline()):
+        pass
+
+  def testAssertCalls_succeeds_extraCalls(self):
+    # we are not watching Reboot, so the assertion succeeds
+    with self.assertCalls(self.call.adb.IsOnline()):
+      self.adb.IsOnline()
+      self.adb.Reboot()
+
+  def testAssertCalls_fails_extraCalls(self):
+    self.watchCalls([self.call.adb.Reboot])
+    # this time we are also watching Reboot, so the assertion fails
+    with self.assertRaises(AssertionError):
+      with self.assertCalls(self.call.adb.IsOnline()):
+        self.adb.IsOnline()
+        self.adb.Reboot()
+
+  def testAssertCalls_succeeds_NoCalls(self):
+    self.watchMethodCalls(self.call.adb) # we are watching all adb methods
+    with self.assertCalls():
+      pass
+
+  def testAssertCalls_fails_NoCalls(self):
+    self.watchMethodCalls(self.call.adb)
+    with self.assertRaises(AssertionError):
+      with self.assertCalls():
+        self.adb.IsOnline()
+
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/utils/parallelizer.py b/build/android/pylib/utils/parallelizer.py
new file mode 100644
index 0000000..9a85b54
--- /dev/null
+++ b/build/android/pylib/utils/parallelizer.py
@@ -0,0 +1,242 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Wrapper that allows method execution in parallel.
+
+This class wraps a list of objects of the same type, emulates their
+interface, and executes any functions called on the objects in parallel
+in ReraiserThreads.
+
+This means that, given a list of objects:
+
+  class Foo:
+    def __init__(self):
+      self.baz = Baz()
+
+    def bar(self, my_param):
+      // do something
+
+  list_of_foos = [Foo(1), Foo(2), Foo(3)]
+
+we can take a sequential operation on that list of objects:
+
+  for f in list_of_foos:
+    f.bar('Hello')
+
+and run it in parallel across all of the objects:
+
+  Parallelizer(list_of_foos).bar('Hello')
+
+It can also handle (non-method) attributes of objects, so that this:
+
+  for f in list_of_foos:
+    f.baz.myBazMethod()
+
+can be run in parallel with:
+
+  Parallelizer(list_of_foos).baz.myBazMethod()
+
+Because it emulates the interface of the wrapped objects, a Parallelizer
+can be passed to a method or function that takes objects of that type:
+
+  def DoesSomethingWithFoo(the_foo):
+    the_foo.bar('Hello')
+    the_foo.bar('world')
+    the_foo.baz.myBazMethod
+
+  DoesSomethingWithFoo(Parallelizer(list_of_foos))
+
+Note that this class spins up a thread for each object. Using this class
+to parallelize operations that are already fast will incur a net performance
+penalty.
+
+"""
+# pylint: disable=protected-access
+
+from pylib.utils import reraiser_thread
+from pylib.utils import watchdog_timer
+
+_DEFAULT_TIMEOUT = 30
+_DEFAULT_RETRIES = 3
+
+
+class Parallelizer(object):
+  """Allows parallel execution of method calls across a group of objects."""
+
+  def __init__(self, objs):
+    assert (objs is not None and len(objs) > 0), (
+        "Passed empty list to 'Parallelizer'")
+    self._orig_objs = objs
+    self._objs = objs
+
+  def __getattr__(self, name):
+    """Emulate getting the |name| attribute of |self|.
+
+    Args:
+      name: The name of the attribute to retrieve.
+    Returns:
+      A Parallelizer emulating the |name| attribute of |self|.
+    """
+    self.pGet(None)
+
+    r = type(self)(self._orig_objs)
+    r._objs = [getattr(o, name) for o in self._objs]
+    return r
+
+  def __getitem__(self, index):
+    """Emulate getting the value of |self| at |index|.
+
+    Returns:
+      A Parallelizer emulating the value of |self| at |index|.
+    """
+    self.pGet(None)
+
+    r = type(self)(self._orig_objs)
+    r._objs = [o[index] for o in self._objs]
+    return r
+
+  def __call__(self, *args, **kwargs):
+    """Emulate calling |self| with |args| and |kwargs|.
+
+    Note that this call is asynchronous. Call pFinish on the return value to
+    block until the call finishes.
+
+    Returns:
+      A Parallelizer wrapping the ReraiserThreadGroup running the call in
+      parallel.
+    Raises:
+      AttributeError if the wrapped objects aren't callable.
+    """
+    self.pGet(None)
+
+    if not self._objs:
+      raise AttributeError('Nothing to call.')
+    for o in self._objs:
+      if not callable(o):
+        raise AttributeError("'%s' is not callable" % o.__name__)
+
+    r = type(self)(self._orig_objs)
+    r._objs = reraiser_thread.ReraiserThreadGroup(
+        [reraiser_thread.ReraiserThread(
+            o, args=args, kwargs=kwargs,
+            name='%s.%s' % (str(d), o.__name__))
+         for d, o in zip(self._orig_objs, self._objs)])
+    r._objs.StartAll() # pylint: disable=W0212
+    return r
+
+  def pFinish(self, timeout):
+    """Finish any outstanding asynchronous operations.
+
+    Args:
+      timeout: The maximum number of seconds to wait for an individual
+               result to return, or None to wait forever.
+    Returns:
+      self, now emulating the return values.
+    """
+    self._assertNoShadow('pFinish')
+    if isinstance(self._objs, reraiser_thread.ReraiserThreadGroup):
+      self._objs.JoinAll()
+      self._objs = self._objs.GetAllReturnValues(
+          watchdog_timer.WatchdogTimer(timeout))
+    return self
+
+  def pGet(self, timeout):
+    """Get the current wrapped objects.
+
+    Args:
+      timeout: Same as |pFinish|.
+    Returns:
+      A list of the results, in order of the provided devices.
+    Raises:
+      Any exception raised by any of the called functions.
+    """
+    self._assertNoShadow('pGet')
+    self.pFinish(timeout)
+    return self._objs
+
+  def pMap(self, f, *args, **kwargs):
+    """Map a function across the current wrapped objects in parallel.
+
+    This calls f(o, *args, **kwargs) for each o in the set of wrapped objects.
+
+    Note that this call is asynchronous. Call pFinish on the return value to
+    block until the call finishes.
+
+    Args:
+      f: The function to call.
+      args: The positional args to pass to f.
+      kwargs: The keyword args to pass to f.
+    Returns:
+      A Parallelizer wrapping the ReraiserThreadGroup running the map in
+      parallel.
+    """
+    self._assertNoShadow('pMap')
+    r = type(self)(self._orig_objs)
+    r._objs = reraiser_thread.ReraiserThreadGroup(
+        [reraiser_thread.ReraiserThread(
+            f, args=tuple([o] + list(args)), kwargs=kwargs,
+            name='%s(%s)' % (f.__name__, d))
+         for d, o in zip(self._orig_objs, self._objs)])
+    r._objs.StartAll() # pylint: disable=W0212
+    return r
+
+  def _assertNoShadow(self, attr_name):
+    """Ensures that |attr_name| isn't shadowing part of the wrapped obejcts.
+
+    If the wrapped objects _do_ have an |attr_name| attribute, it will be
+    inaccessible to clients.
+
+    Args:
+      attr_name: The attribute to check.
+    Raises:
+      AssertionError if the wrapped objects have an attribute named 'attr_name'
+      or '_assertNoShadow'.
+    """
+    if isinstance(self._objs, reraiser_thread.ReraiserThreadGroup):
+      assert not hasattr(self._objs, '_assertNoShadow')
+      assert not hasattr(self._objs, attr_name)
+    else:
+      assert not any(hasattr(o, '_assertNoShadow') for o in self._objs)
+      assert not any(hasattr(o, attr_name) for o in self._objs)
+
+
+class SyncParallelizer(Parallelizer):
+  """A Parallelizer that blocks on function calls."""
+
+  #override
+  def __call__(self, *args, **kwargs):
+    """Emulate calling |self| with |args| and |kwargs|.
+
+    Note that this call is synchronous.
+
+    Returns:
+      A Parallelizer emulating the value returned from calling |self| with
+      |args| and |kwargs|.
+    Raises:
+      AttributeError if the wrapped objects aren't callable.
+    """
+    r = super(SyncParallelizer, self).__call__(*args, **kwargs)
+    r.pFinish(None)
+    return r
+
+  #override
+  def pMap(self, f, *args, **kwargs):
+    """Map a function across the current wrapped objects in parallel.
+
+    This calls f(o, *args, **kwargs) for each o in the set of wrapped objects.
+
+    Note that this call is synchronous.
+
+    Args:
+      f: The function to call.
+      args: The positional args to pass to f.
+      kwargs: The keyword args to pass to f.
+    Returns:
+      A Parallelizer wrapping the ReraiserThreadGroup running the map in
+      parallel.
+    """
+    r = super(SyncParallelizer, self).pMap(f, *args, **kwargs)
+    r.pFinish(None)
+    return r
+
diff --git a/build/android/pylib/utils/parallelizer_test.py b/build/android/pylib/utils/parallelizer_test.py
new file mode 100644
index 0000000..6e0c7e7
--- /dev/null
+++ b/build/android/pylib/utils/parallelizer_test.py
@@ -0,0 +1,166 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unit tests for the contents of parallelizer.py."""
+
+# pylint: disable=W0212
+# pylint: disable=W0613
+
+import os
+import tempfile
+import time
+import unittest
+
+from pylib.utils import parallelizer
+
+
+class ParallelizerTestObject(object):
+  """Class used to test parallelizer.Parallelizer."""
+
+  parallel = parallelizer.Parallelizer
+
+  def __init__(self, thing, completion_file_name=None):
+    self._thing = thing
+    self._completion_file_name = completion_file_name
+    self.helper = ParallelizerTestObjectHelper(thing)
+
+  @staticmethod
+  def doReturn(what):
+    return what
+
+  @classmethod
+  def doRaise(cls, what):
+    raise what
+
+  def doSetTheThing(self, new_thing):
+    self._thing = new_thing
+
+  def doReturnTheThing(self):
+    return self._thing
+
+  def doRaiseTheThing(self):
+    raise self._thing
+
+  def doRaiseIfExceptionElseSleepFor(self, sleep_duration):
+    if isinstance(self._thing, Exception):
+      raise self._thing
+    time.sleep(sleep_duration)
+    self._write_completion_file()
+    return self._thing
+
+  def _write_completion_file(self):
+    if self._completion_file_name and len(self._completion_file_name):
+      with open(self._completion_file_name, 'w+b') as completion_file:
+        completion_file.write('complete')
+
+  def __getitem__(self, index):
+    return self._thing[index]
+
+  def __str__(self):
+    return type(self).__name__
+
+
+class ParallelizerTestObjectHelper(object):
+
+  def __init__(self, thing):
+    self._thing = thing
+
+  def doReturnStringThing(self):
+    return str(self._thing)
+
+
+class ParallelizerTest(unittest.TestCase):
+
+  def testInitWithNone(self):
+    with self.assertRaises(AssertionError):
+      parallelizer.Parallelizer(None)
+
+  def testInitEmptyList(self):
+    with self.assertRaises(AssertionError):
+      parallelizer.Parallelizer([])
+
+  def testMethodCall(self):
+    test_data = ['abc_foo', 'def_foo', 'ghi_foo']
+    expected = ['abc_bar', 'def_bar', 'ghi_bar']
+    r = parallelizer.Parallelizer(test_data).replace('_foo', '_bar').pGet(0.1)
+    self.assertEquals(expected, r)
+
+  def testMutate(self):
+    devices = [ParallelizerTestObject(True) for _ in xrange(0, 10)]
+    self.assertTrue(all(d.doReturnTheThing() for d in devices))
+    ParallelizerTestObject.parallel(devices).doSetTheThing(False).pFinish(1)
+    self.assertTrue(not any(d.doReturnTheThing() for d in devices))
+
+  def testAllReturn(self):
+    devices = [ParallelizerTestObject(True) for _ in xrange(0, 10)]
+    results = ParallelizerTestObject.parallel(
+        devices).doReturnTheThing().pGet(1)
+    self.assertTrue(isinstance(results, list))
+    self.assertEquals(10, len(results))
+    self.assertTrue(all(results))
+
+  def testAllRaise(self):
+    devices = [ParallelizerTestObject(Exception('thing %d' % i))
+               for i in xrange(0, 10)]
+    p = ParallelizerTestObject.parallel(devices).doRaiseTheThing()
+    with self.assertRaises(Exception):
+      p.pGet(1)
+
+  def testOneFailOthersComplete(self):
+    parallel_device_count = 10
+    exception_index = 7
+    exception_msg = 'thing %d' % exception_index
+
+    try:
+      completion_files = [tempfile.NamedTemporaryFile(delete=False)
+                          for _ in xrange(0, parallel_device_count)]
+      devices = [
+          ParallelizerTestObject(
+              i if i != exception_index else Exception(exception_msg),
+              completion_files[i].name)
+          for i in xrange(0, parallel_device_count)]
+      for f in completion_files:
+        f.close()
+      p = ParallelizerTestObject.parallel(devices)
+      with self.assertRaises(Exception) as e:
+        p.doRaiseIfExceptionElseSleepFor(2).pGet(3)
+      self.assertTrue(exception_msg in str(e.exception))
+      for i in xrange(0, parallel_device_count):
+        with open(completion_files[i].name) as f:
+          if i == exception_index:
+            self.assertEquals('', f.read())
+          else:
+            self.assertEquals('complete', f.read())
+    finally:
+      for f in completion_files:
+        os.remove(f.name)
+
+  def testReusable(self):
+    devices = [ParallelizerTestObject(True) for _ in xrange(0, 10)]
+    p = ParallelizerTestObject.parallel(devices)
+    results = p.doReturn(True).pGet(1)
+    self.assertTrue(all(results))
+    results = p.doReturn(True).pGet(1)
+    self.assertTrue(all(results))
+    with self.assertRaises(Exception):
+      results = p.doRaise(Exception('reusableTest')).pGet(1)
+
+  def testContained(self):
+    devices = [ParallelizerTestObject(i) for i in xrange(0, 10)]
+    results = (ParallelizerTestObject.parallel(devices).helper
+        .doReturnStringThing().pGet(1))
+    self.assertTrue(isinstance(results, list))
+    self.assertEquals(10, len(results))
+    for i in xrange(0, 10):
+      self.assertEquals(str(i), results[i])
+
+  def testGetItem(self):
+    devices = [ParallelizerTestObject(range(i, i+10)) for i in xrange(0, 10)]
+    results = ParallelizerTestObject.parallel(devices)[9].pGet(1)
+    self.assertEquals(range(9, 19), results)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/utils/proguard.py b/build/android/pylib/utils/proguard.py
new file mode 100644
index 0000000..34ad5c3
--- /dev/null
+++ b/build/android/pylib/utils/proguard.py
@@ -0,0 +1,148 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+import tempfile
+
+from pylib import constants
+from pylib import cmd_helper
+
+
+_PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$')
+_PROGUARD_SUPERCLASS_RE = re.compile(r'\s*?  Superclass:\s*([\S]+)$')
+_PROGUARD_SECTION_RE = re.compile(
+    r'^(?:Interfaces|Constant Pool|Fields|Methods|Class file attributes) '
+    r'\(count = \d+\):$')
+_PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$')
+_PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$')
+_PROGUARD_ANNOTATION_CONST_RE = (
+    re.compile(r'\s*?- Constant element value.*$'))
+_PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$')
+
+_PROGUARD_PATH_SDK = os.path.join(
+    constants.ANDROID_SDK_ROOT, 'tools', 'proguard', 'lib', 'proguard.jar')
+_PROGUARD_PATH_BUILT = (
+    os.path.join(os.environ['ANDROID_BUILD_TOP'], 'external', 'proguard',
+                 'lib', 'proguard.jar')
+    if 'ANDROID_BUILD_TOP' in os.environ else None)
+_PROGUARD_PATH = (
+    _PROGUARD_PATH_SDK if os.path.exists(_PROGUARD_PATH_SDK)
+    else _PROGUARD_PATH_BUILT)
+
+
+def Dump(jar_path):
+  """Dumps class and method information from a JAR into a dict via proguard.
+
+  Args:
+    jar_path: An absolute path to the JAR file to dump.
+  Returns:
+    A dict in the following format:
+      {
+        'classes': [
+          {
+            'class': '',
+            'superclass': '',
+            'annotations': {},
+            'methods': [
+              {
+                'method': '',
+                'annotations': {},
+              },
+              ...
+            ],
+          },
+          ...
+        ],
+      }
+  """
+
+  with tempfile.NamedTemporaryFile() as proguard_output:
+    cmd_helper.RunCmd(['java', '-jar',
+                       _PROGUARD_PATH,
+                       '-injars', jar_path,
+                       '-dontshrink',
+                       '-dontoptimize',
+                       '-dontobfuscate',
+                       '-dontpreverify',
+                       '-dump', proguard_output.name])
+
+
+    results = {
+      'classes': [],
+    }
+
+    annotation = None
+    annotation_has_value = False
+    class_result = None
+    method_result = None
+
+    for line in proguard_output:
+      line = line.strip('\r\n')
+
+      m = _PROGUARD_CLASS_RE.match(line)
+      if m:
+        class_result = {
+          'class': m.group(1).replace('/', '.'),
+          'superclass': '',
+          'annotations': {},
+          'methods': [],
+        }
+        results['classes'].append(class_result)
+        annotation = None
+        annotation_has_value = False
+        method_result = None
+        continue
+
+      if not class_result:
+        continue
+
+      m = _PROGUARD_SUPERCLASS_RE.match(line)
+      if m:
+        class_result['superclass'] = m.group(1).replace('/', '.')
+        continue
+
+      m = _PROGUARD_SECTION_RE.match(line)
+      if m:
+        annotation = None
+        annotation_has_value = False
+        method_result = None
+        continue
+
+      m = _PROGUARD_METHOD_RE.match(line)
+      if m:
+        method_result = {
+          'method': m.group(1),
+          'annotations': {},
+        }
+        class_result['methods'].append(method_result)
+        annotation = None
+        annotation_has_value = False
+        continue
+
+      m = _PROGUARD_ANNOTATION_RE.match(line)
+      if m:
+        # Ignore the annotation package.
+        annotation = m.group(1).split('/')[-1]
+        if method_result:
+          method_result['annotations'][annotation] = None
+        else:
+          class_result['annotations'][annotation] = None
+        continue
+
+      if annotation:
+        if not annotation_has_value:
+          m = _PROGUARD_ANNOTATION_CONST_RE.match(line)
+          annotation_has_value = bool(m)
+        else:
+          m = _PROGUARD_ANNOTATION_VALUE_RE.match(line)
+          if m:
+            if method_result:
+              method_result['annotations'][annotation] = m.group(1)
+            else:
+              class_result['annotations'][annotation] = m.group(1)
+          annotation_has_value = None
+
+  return results
+
diff --git a/build/android/pylib/utils/repo_utils.py b/build/android/pylib/utils/repo_utils.py
new file mode 100644
index 0000000..e0c7d2c
--- /dev/null
+++ b/build/android/pylib/utils/repo_utils.py
@@ -0,0 +1,16 @@
+# 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.
+
+from pylib import cmd_helper
+
+
+def GetGitHeadSHA1(in_directory):
+  """Returns the git hash tag for the given directory.
+
+  Args:
+    in_directory: The directory where git is to be run.
+  """
+  command_line = ['git', 'log', '-1', '--pretty=format:%H']
+  output = cmd_helper.GetCmdOutput(command_line, cwd=in_directory)
+  return output[0:40]
diff --git a/build/android/pylib/utils/reraiser_thread.py b/build/android/pylib/utils/reraiser_thread.py
new file mode 100644
index 0000000..0ec16b1
--- /dev/null
+++ b/build/android/pylib/utils/reraiser_thread.py
@@ -0,0 +1,158 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Thread and ThreadGroup that reraise exceptions on the main thread."""
+# pylint: disable=W0212
+
+import logging
+import sys
+import threading
+import traceback
+
+from pylib.utils import watchdog_timer
+
+
+class TimeoutError(Exception):
+  """Module-specific timeout exception."""
+  pass
+
+
+def LogThreadStack(thread):
+  """Log the stack for the given thread.
+
+  Args:
+    thread: a threading.Thread instance.
+  """
+  stack = sys._current_frames()[thread.ident]
+  logging.critical('*' * 80)
+  logging.critical('Stack dump for thread %r', thread.name)
+  logging.critical('*' * 80)
+  for filename, lineno, name, line in traceback.extract_stack(stack):
+    logging.critical('File: "%s", line %d, in %s', filename, lineno, name)
+    if line:
+      logging.critical('  %s', line.strip())
+  logging.critical('*' * 80)
+
+
+class ReraiserThread(threading.Thread):
+  """Thread class that can reraise exceptions."""
+
+  def __init__(self, func, args=None, kwargs=None, name=None):
+    """Initialize thread.
+
+    Args:
+      func: callable to call on a new thread.
+      args: list of positional arguments for callable, defaults to empty.
+      kwargs: dictionary of keyword arguments for callable, defaults to empty.
+      name: thread name, defaults to Thread-N.
+    """
+    super(ReraiserThread, self).__init__(name=name)
+    if not args:
+      args = []
+    if not kwargs:
+      kwargs = {}
+    self.daemon = True
+    self._func = func
+    self._args = args
+    self._kwargs = kwargs
+    self._ret = None
+    self._exc_info = None
+
+  def ReraiseIfException(self):
+    """Reraise exception if an exception was raised in the thread."""
+    if self._exc_info:
+      raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
+
+  def GetReturnValue(self):
+    """Reraise exception if present, otherwise get the return value."""
+    self.ReraiseIfException()
+    return self._ret
+
+  #override
+  def run(self):
+    """Overrides Thread.run() to add support for reraising exceptions."""
+    try:
+      self._ret = self._func(*self._args, **self._kwargs)
+    except: # pylint: disable=W0702
+      self._exc_info = sys.exc_info()
+
+
+class ReraiserThreadGroup(object):
+  """A group of ReraiserThread objects."""
+
+  def __init__(self, threads=None):
+    """Initialize thread group.
+
+    Args:
+      threads: a list of ReraiserThread objects; defaults to empty.
+    """
+    if not threads:
+      threads = []
+    self._threads = threads
+
+  def Add(self, thread):
+    """Add a thread to the group.
+
+    Args:
+      thread: a ReraiserThread object.
+    """
+    self._threads.append(thread)
+
+  def StartAll(self):
+    """Start all threads."""
+    for thread in self._threads:
+      thread.start()
+
+  def _JoinAll(self, watcher=None):
+    """Join all threads without stack dumps.
+
+    Reraises exceptions raised by the child threads and supports breaking
+    immediately on exceptions raised on the main thread.
+
+    Args:
+      watcher: Watchdog object providing timeout, by default waits forever.
+    """
+    if watcher is None:
+      watcher = watchdog_timer.WatchdogTimer(None)
+    alive_threads = self._threads[:]
+    while alive_threads:
+      for thread in alive_threads[:]:
+        if watcher.IsTimedOut():
+          raise TimeoutError('Timed out waiting for %d of %d threads.' %
+                             (len(alive_threads), len(self._threads)))
+        # Allow the main thread to periodically check for interrupts.
+        thread.join(0.1)
+        if not thread.isAlive():
+          alive_threads.remove(thread)
+    # All threads are allowed to complete before reraising exceptions.
+    for thread in self._threads:
+      thread.ReraiseIfException()
+
+  def JoinAll(self, watcher=None):
+    """Join all threads.
+
+    Reraises exceptions raised by the child threads and supports breaking
+    immediately on exceptions raised on the main thread. Unfinished threads'
+    stacks will be logged on watchdog timeout.
+
+    Args:
+      watcher: Watchdog object providing timeout, by default waits forever.
+    """
+    try:
+      self._JoinAll(watcher)
+    except TimeoutError:
+      for thread in (t for t in self._threads if t.isAlive()):
+        LogThreadStack(thread)
+      raise
+
+  def GetAllReturnValues(self, watcher=None):
+    """Get all return values, joining all threads if necessary.
+
+    Args:
+      watcher: same as in |JoinAll|. Only used if threads are alive.
+    """
+    if any([t.isAlive() for t in self._threads]):
+      self.JoinAll(watcher)
+    return [t.GetReturnValue() for t in self._threads]
+
diff --git a/build/android/pylib/utils/reraiser_thread_unittest.py b/build/android/pylib/utils/reraiser_thread_unittest.py
new file mode 100644
index 0000000..2392d0e
--- /dev/null
+++ b/build/android/pylib/utils/reraiser_thread_unittest.py
@@ -0,0 +1,96 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for reraiser_thread.py."""
+
+import threading
+import unittest
+
+from pylib.utils import reraiser_thread
+from pylib.utils import watchdog_timer
+
+
+class TestException(Exception):
+  pass
+
+
+class TestReraiserThread(unittest.TestCase):
+  """Tests for reraiser_thread.ReraiserThread."""
+  def testNominal(self):
+    result = [None, None]
+
+    def f(a, b=None):
+      result[0] = a
+      result[1] = b
+
+    thread = reraiser_thread.ReraiserThread(f, [1], {'b': 2})
+    thread.start()
+    thread.join()
+    self.assertEqual(result[0], 1)
+    self.assertEqual(result[1], 2)
+
+  def testRaise(self):
+    def f():
+      raise TestException
+
+    thread = reraiser_thread.ReraiserThread(f)
+    thread.start()
+    thread.join()
+    with self.assertRaises(TestException):
+      thread.ReraiseIfException()
+
+
+class TestReraiserThreadGroup(unittest.TestCase):
+  """Tests for reraiser_thread.ReraiserThreadGroup."""
+  def testInit(self):
+    ran = [False] * 5
+    def f(i):
+      ran[i] = True
+
+    group = reraiser_thread.ReraiserThreadGroup(
+      [reraiser_thread.ReraiserThread(f, args=[i]) for i in range(5)])
+    group.StartAll()
+    group.JoinAll()
+    for v in ran:
+      self.assertTrue(v)
+
+  def testAdd(self):
+    ran = [False] * 5
+    def f(i):
+      ran[i] = True
+
+    group = reraiser_thread.ReraiserThreadGroup()
+    for i in xrange(5):
+      group.Add(reraiser_thread.ReraiserThread(f, args=[i]))
+    group.StartAll()
+    group.JoinAll()
+    for v in ran:
+      self.assertTrue(v)
+
+  def testJoinRaise(self):
+    def f():
+      raise TestException
+    group = reraiser_thread.ReraiserThreadGroup(
+      [reraiser_thread.ReraiserThread(f) for _ in xrange(5)])
+    group.StartAll()
+    with self.assertRaises(TestException):
+      group.JoinAll()
+
+  def testJoinTimeout(self):
+    def f():
+      pass
+    event = threading.Event()
+    def g():
+      event.wait()
+    group = reraiser_thread.ReraiserThreadGroup(
+        [reraiser_thread.ReraiserThread(g),
+         reraiser_thread.ReraiserThread(f)])
+    group.StartAll()
+    with self.assertRaises(reraiser_thread.TimeoutError):
+      group.JoinAll(watchdog_timer.WatchdogTimer(0.01))
+    event.set()
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/utils/run_tests_helper.py b/build/android/pylib/utils/run_tests_helper.py
new file mode 100644
index 0000000..43f654d
--- /dev/null
+++ b/build/android/pylib/utils/run_tests_helper.py
@@ -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.
+
+"""Helper functions common to native, java and host-driven test runners."""
+
+import logging
+import sys
+import time
+
+
+class CustomFormatter(logging.Formatter):
+  """Custom log formatter."""
+
+  #override
+  def __init__(self, fmt='%(threadName)-4s  %(message)s'):
+    # Can't use super() because in older Python versions logging.Formatter does
+    # not inherit from object.
+    logging.Formatter.__init__(self, fmt=fmt)
+    self._creation_time = time.time()
+
+  #override
+  def format(self, record):
+    # Can't use super() because in older Python versions logging.Formatter does
+    # not inherit from object.
+    msg = logging.Formatter.format(self, record)
+    if 'MainThread' in msg[:19]:
+      msg = msg.replace('MainThread', 'Main', 1)
+    timediff = time.time() - self._creation_time
+    return '%s %8.3fs %s' % (record.levelname[0], timediff, msg)
+
+
+def SetLogLevel(verbose_count):
+  """Sets log level as |verbose_count|."""
+  log_level = logging.WARNING  # Default.
+  if verbose_count == 1:
+    log_level = logging.INFO
+  elif verbose_count >= 2:
+    log_level = logging.DEBUG
+  logger = logging.getLogger()
+  logger.setLevel(log_level)
+  custom_handler = logging.StreamHandler(sys.stdout)
+  custom_handler.setFormatter(CustomFormatter())
+  logging.getLogger().addHandler(custom_handler)
diff --git a/build/android/pylib/utils/test_environment.py b/build/android/pylib/utils/test_environment.py
new file mode 100644
index 0000000..e78eb5c
--- /dev/null
+++ b/build/android/pylib/utils/test_environment.py
@@ -0,0 +1,47 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import psutil
+import signal
+
+from pylib.device import device_errors
+from pylib.device import device_utils
+
+
+def _KillWebServers():
+  for s in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT, signal.SIGKILL]:
+    signalled = []
+    for server in ['lighttpd', 'webpagereplay']:
+      for p in psutil.process_iter():
+        try:
+          if not server in ' '.join(p.cmdline):
+            continue
+          logging.info('Killing %s %s %s', s, server, p.pid)
+          p.send_signal(s)
+          signalled.append(p)
+        except Exception as e:
+          logging.warning('Failed killing %s %s %s', server, p.pid, e)
+    for p in signalled:
+      try:
+        p.wait(1)
+      except Exception as e:
+        logging.warning('Failed waiting for %s to die. %s', p.pid, e)
+
+
+def CleanupLeftoverProcesses():
+  """Clean up the test environment, restarting fresh adb and HTTP daemons."""
+  _KillWebServers()
+  device_utils.RestartServer()
+
+  def cleanup_device(d):
+    d.old_interface.RestartAdbdOnDevice()
+    try:
+      d.EnableRoot()
+    except device_errors.CommandFailedError as e:
+      logging.error(str(e))
+    d.WaitUntilFullyBooted()
+
+  device_utils.DeviceUtils.parallel().pMap(cleanup_device)
+
diff --git a/build/android/pylib/utils/time_profile.py b/build/android/pylib/utils/time_profile.py
new file mode 100644
index 0000000..45da7ff
--- /dev/null
+++ b/build/android/pylib/utils/time_profile.py
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import time
+
+
+class TimeProfile(object):
+  """Class for simple profiling of action, with logging of cost."""
+
+  def __init__(self, description):
+    self._starttime = None
+    self._description = description
+    self.Start()
+
+  def Start(self):
+    self._starttime = time.time()
+
+  def Stop(self):
+    """Stop profiling and dump a log."""
+    if self._starttime:
+      stoptime = time.time()
+      logging.info('%fsec to perform %s',
+                   stoptime - self._starttime, self._description)
+      self._starttime = None
diff --git a/build/android/pylib/utils/timeout_retry.py b/build/android/pylib/utils/timeout_retry.py
new file mode 100644
index 0000000..61f7c70
--- /dev/null
+++ b/build/android/pylib/utils/timeout_retry.py
@@ -0,0 +1,167 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A utility to run functions with timeouts and retries."""
+# pylint: disable=W0702
+
+import logging
+import threading
+import time
+import traceback
+
+from pylib.utils import reraiser_thread
+from pylib.utils import watchdog_timer
+
+
+class TimeoutRetryThread(reraiser_thread.ReraiserThread):
+  def __init__(self, func, timeout, name):
+    super(TimeoutRetryThread, self).__init__(func, name=name)
+    self._watcher = watchdog_timer.WatchdogTimer(timeout)
+    self._expired = False
+
+  def GetWatcher(self):
+    """Returns the watchdog keeping track of this thread's time."""
+    return self._watcher
+
+  def GetElapsedTime(self):
+    return self._watcher.GetElapsed()
+
+  def GetRemainingTime(self, required=0, msg=None):
+    """Get the remaining time before the thread times out.
+
+    Useful to send as the |timeout| parameter of async IO operations.
+
+    Args:
+      required: minimum amount of time that will be required to complete, e.g.,
+        some sleep or IO operation.
+      msg: error message to show if timing out.
+
+    Returns:
+      The number of seconds remaining before the thread times out, or None
+      if the thread never times out.
+
+    Raises:
+      reraiser_thread.TimeoutError if the remaining time is less than the
+        required time.
+    """
+    remaining = self._watcher.GetRemaining()
+    if remaining is not None and remaining < required:
+      if msg is None:
+        msg = 'Timeout expired'
+      if remaining > 0:
+        msg += (', wait of %.1f secs required but only %.1f secs left'
+                % (required, remaining))
+      self._expired = True
+      raise reraiser_thread.TimeoutError(msg)
+    return remaining
+
+  def LogTimeoutException(self):
+    """Log the exception that terminated this thread."""
+    if not self._expired:
+      return
+    logging.critical('*' * 80)
+    logging.critical('%s on thread %r', self._exc_info[0].__name__, self.name)
+    logging.critical('*' * 80)
+    fmt_exc = ''.join(traceback.format_exception(*self._exc_info))
+    for line in fmt_exc.splitlines():
+      logging.critical(line.rstrip())
+    logging.critical('*' * 80)
+
+
+def CurrentTimeoutThread():
+  """Get the current thread if it is a TimeoutRetryThread.
+
+  Returns:
+    The current thread if it is a TimeoutRetryThread, otherwise None.
+  """
+  current_thread = threading.current_thread()
+  if isinstance(current_thread, TimeoutRetryThread):
+    return current_thread
+  else:
+    return None
+
+
+def WaitFor(condition, wait_period=5, max_tries=None):
+  """Wait for a condition to become true.
+
+  Repeadly call the function condition(), with no arguments, until it returns
+  a true value.
+
+  If called within a TimeoutRetryThread, it cooperates nicely with it.
+
+  Args:
+    condition: function with the condition to check
+    wait_period: number of seconds to wait before retrying to check the
+      condition
+    max_tries: maximum number of checks to make, the default tries forever
+      or until the TimeoutRetryThread expires.
+
+  Returns:
+    The true value returned by the condition, or None if the condition was
+    not met after max_tries.
+
+  Raises:
+    reraiser_thread.TimeoutError if the current thread is a TimeoutRetryThread
+      and the timeout expires.
+  """
+  condition_name = condition.__name__
+  timeout_thread = CurrentTimeoutThread()
+  while max_tries is None or max_tries > 0:
+    result = condition()
+    if max_tries is not None:
+      max_tries -= 1
+    msg = ['condition', repr(condition_name), 'met' if result else 'not met']
+    if timeout_thread:
+      msg.append('(%.1fs)' % timeout_thread.GetElapsedTime())
+    logging.info(' '.join(msg))
+    if result:
+      return result
+    if timeout_thread:
+      timeout_thread.GetRemainingTime(wait_period,
+          msg='Timed out waiting for %r' % condition_name)
+    time.sleep(wait_period)
+  return None
+
+
+def Run(func, timeout, retries, args=None, kwargs=None):
+  """Runs the passed function in a separate thread with timeouts and retries.
+
+  Args:
+    func: the function to be wrapped.
+    timeout: the timeout in seconds for each try.
+    retries: the number of retries.
+    args: list of positional args to pass to |func|.
+    kwargs: dictionary of keyword args to pass to |func|.
+
+  Returns:
+    The return value of func(*args, **kwargs).
+  """
+  if not args:
+    args = []
+  if not kwargs:
+    kwargs = {}
+
+  # The return value uses a list because Python variables are references, not
+  # values. Closures make a copy of the reference, so updating the closure's
+  # reference wouldn't update where the original reference pointed.
+  ret = [None]
+  def RunOnTimeoutThread():
+    ret[0] = func(*args, **kwargs)
+
+  num_try = 1
+  while True:
+    child_thread = TimeoutRetryThread(
+      RunOnTimeoutThread, timeout,
+      name='TimeoutThread-%d-for-%s' % (num_try,
+                                        threading.current_thread().name))
+    try:
+      thread_group = reraiser_thread.ReraiserThreadGroup([child_thread])
+      thread_group.StartAll()
+      thread_group.JoinAll(child_thread.GetWatcher())
+      return ret[0]
+    except:
+      child_thread.LogTimeoutException()
+      if num_try > retries:
+        raise
+      num_try += 1
diff --git a/build/android/pylib/utils/timeout_retry_unittest.py b/build/android/pylib/utils/timeout_retry_unittest.py
new file mode 100644
index 0000000..dc36c42
--- /dev/null
+++ b/build/android/pylib/utils/timeout_retry_unittest.py
@@ -0,0 +1,52 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for timeout_and_retry.py."""
+
+import unittest
+
+from pylib.utils import reraiser_thread
+from pylib.utils import timeout_retry
+
+
+class TestException(Exception):
+  pass
+
+
+def _NeverEnding(tries):
+  tries[0] += 1
+  while True:
+    pass
+
+
+def _CountTries(tries):
+  tries[0] += 1
+  raise TestException
+
+
+class TestRun(unittest.TestCase):
+  """Tests for timeout_retry.Run."""
+
+  def testRun(self):
+    self.assertTrue(timeout_retry.Run(
+        lambda x: x, 30, 3, [True], {}))
+
+  def testTimeout(self):
+    tries = [0]
+    self.assertRaises(reraiser_thread.TimeoutError,
+        timeout_retry.Run, lambda: _NeverEnding(tries), 0, 3)
+    self.assertEqual(tries[0], 4)
+
+  def testRetries(self):
+    tries = [0]
+    self.assertRaises(TestException,
+        timeout_retry.Run, lambda: _CountTries(tries), 30, 3)
+    self.assertEqual(tries[0], 4)
+
+  def testReturnValue(self):
+    self.assertTrue(timeout_retry.Run(lambda: True, 30, 3))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/utils/watchdog_timer.py b/build/android/pylib/utils/watchdog_timer.py
new file mode 100644
index 0000000..2f4c464
--- /dev/null
+++ b/build/android/pylib/utils/watchdog_timer.py
@@ -0,0 +1,47 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""WatchdogTimer timeout objects."""
+
+import time
+
+
+class WatchdogTimer(object):
+  """A resetable timeout-based watchdog.
+
+  This object is threadsafe.
+  """
+
+  def __init__(self, timeout):
+    """Initializes the watchdog.
+
+    Args:
+      timeout: The timeout in seconds. If timeout is None it will never timeout.
+    """
+    self._start_time = time.time()
+    self._timeout = timeout
+
+  def Reset(self):
+    """Resets the timeout countdown."""
+    self._start_time = time.time()
+
+  def GetElapsed(self):
+    """Returns the elapsed time of the watchdog."""
+    return time.time() - self._start_time
+
+  def GetRemaining(self):
+    """Returns the remaining time of the watchdog."""
+    if self._timeout:
+      return self._timeout - self.GetElapsed()
+    else:
+      return None
+
+  def IsTimedOut(self):
+    """Whether the watchdog has timed out.
+
+    Returns:
+      True if the watchdog has timed out, False otherwise.
+    """
+    remaining = self.GetRemaining()
+    return remaining is not None and remaining < 0
diff --git a/build/android/pylib/utils/xvfb.py b/build/android/pylib/utils/xvfb.py
new file mode 100644
index 0000000..cb9d50e
--- /dev/null
+++ b/build/android/pylib/utils/xvfb.py
@@ -0,0 +1,58 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=W0702
+
+import os
+import signal
+import subprocess
+import sys
+import time
+
+
+def _IsLinux():
+  """Return True if on Linux; else False."""
+  return sys.platform.startswith('linux')
+
+
+class Xvfb(object):
+  """Class to start and stop Xvfb if relevant.  Nop if not Linux."""
+
+  def __init__(self):
+    self._pid = 0
+
+  def Start(self):
+    """Start Xvfb and set an appropriate DISPLAY environment.  Linux only.
+
+    Copied from tools/code_coverage/coverage_posix.py
+    """
+    if not _IsLinux():
+      return
+    proc = subprocess.Popen(['Xvfb', ':9', '-screen', '0', '1024x768x24',
+                             '-ac'],
+                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    self._pid = proc.pid
+    if not self._pid:
+      raise Exception('Could not start Xvfb')
+    os.environ['DISPLAY'] = ':9'
+
+    # Now confirm, giving a chance for it to start if needed.
+    for _ in range(10):
+      proc = subprocess.Popen('xdpyinfo >/dev/null', shell=True)
+      _, retcode = os.waitpid(proc.pid, 0)
+      if retcode == 0:
+        break
+      time.sleep(0.25)
+    if retcode != 0:
+      raise Exception('Could not confirm Xvfb happiness')
+
+  def Stop(self):
+    """Stop Xvfb if needed.  Linux only."""
+    if self._pid:
+      try:
+        os.kill(self._pid, signal.SIGKILL)
+      except:
+        pass
+      del os.environ['DISPLAY']
+      self._pid = 0
diff --git a/build/android/pylib/utils/zip_utils.py b/build/android/pylib/utils/zip_utils.py
new file mode 100644
index 0000000..d799463
--- /dev/null
+++ b/build/android/pylib/utils/zip_utils.py
@@ -0,0 +1,31 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import zipfile
+
+
+def WriteToZipFile(zip_file, path, arc_path):
+  """Recursively write |path| to |zip_file| as |arc_path|.
+
+  zip_file: An open instance of zipfile.ZipFile.
+  path: An absolute path to the file or directory to be zipped.
+  arc_path: A relative path within the zip file to which the file or directory
+    located at |path| should be written.
+  """
+  if os.path.isdir(path):
+    for dir_path, _, file_names in os.walk(path):
+      dir_arc_path = os.path.join(arc_path, os.path.relpath(dir_path, path))
+      logging.debug('dir:  %s -> %s', dir_path, dir_arc_path)
+      zip_file.write(dir_path, dir_arc_path, zipfile.ZIP_STORED)
+      for f in file_names:
+        file_path = os.path.join(dir_path, f)
+        file_arc_path = os.path.join(dir_arc_path, f)
+        logging.debug('file: %s -> %s', file_path, file_arc_path)
+        zip_file.write(file_path, file_arc_path, zipfile.ZIP_DEFLATED)
+  else:
+    logging.debug('file: %s -> %s', path, arc_path)
+    zip_file.write(path, arc_path, zipfile.ZIP_DEFLATED)
+
diff --git a/build/android/pylib/valgrind_tools.py b/build/android/pylib/valgrind_tools.py
new file mode 100644
index 0000000..99719d0
--- /dev/null
+++ b/build/android/pylib/valgrind_tools.py
@@ -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.
+
+"""
+Classes in this file define additional actions that need to be taken to run a
+test under some kind of runtime error detection tool.
+
+The interface is intended to be used as follows.
+
+1. For tests that simply run a native process (i.e. no activity is spawned):
+
+Call tool.CopyFiles(device).
+Prepend test command line with tool.GetTestWrapper().
+
+2. For tests that spawn an activity:
+
+Call tool.CopyFiles(device).
+Call tool.SetupEnvironment().
+Run the test as usual.
+Call tool.CleanUpEnvironment().
+"""
+# pylint: disable=R0201
+
+import glob
+import logging
+import os.path
+import subprocess
+import sys
+
+from pylib.constants import DIR_SOURCE_ROOT
+from pylib.device import device_errors
+
+
+def SetChromeTimeoutScale(device, scale):
+  """Sets the timeout scale in /data/local/tmp/chrome_timeout_scale to scale."""
+  path = '/data/local/tmp/chrome_timeout_scale'
+  if not scale or scale == 1.0:
+    # Delete if scale is None/0.0/1.0 since the default timeout scale is 1.0
+    device.RunShellCommand('rm %s' % path)
+  else:
+    device.WriteFile(path, '%f' % scale, as_root=True)
+
+
+class BaseTool(object):
+  """A tool that does nothing."""
+
+  def __init__(self):
+    """Does nothing."""
+    pass
+
+  def GetTestWrapper(self):
+    """Returns a string that is to be prepended to the test command line."""
+    return ''
+
+  def GetUtilWrapper(self):
+    """Returns the wrapper name for the utilities.
+
+    Returns:
+       A string that is to be prepended to the command line of utility
+    processes (forwarder, etc.).
+    """
+    return ''
+
+  @classmethod
+  def CopyFiles(cls, device):
+    """Copies tool-specific files to the device, create directories, etc."""
+    pass
+
+  def SetupEnvironment(self):
+    """Sets up the system environment for a test.
+
+    This is a good place to set system properties.
+    """
+    pass
+
+  def CleanUpEnvironment(self):
+    """Cleans up environment."""
+    pass
+
+  def GetTimeoutScale(self):
+    """Returns a multiplier that should be applied to timeout values."""
+    return 1.0
+
+  def NeedsDebugInfo(self):
+    """Whether this tool requires debug info.
+
+    Returns:
+      True if this tool can not work with stripped binaries.
+    """
+    return False
+
+
+class AddressSanitizerTool(BaseTool):
+  """AddressSanitizer tool."""
+
+  WRAPPER_NAME = '/system/bin/asanwrapper'
+  # Disable memcmp overlap check.There are blobs (gl drivers)
+  # on some android devices that use memcmp on overlapping regions,
+  # nothing we can do about that.
+  EXTRA_OPTIONS = 'strict_memcmp=0,use_sigaltstack=1'
+
+  def __init__(self, device):
+    super(AddressSanitizerTool, self).__init__()
+    self._device = device
+    # Configure AndroidCommands to run utils (such as md5sum_bin) under ASan.
+    # This is required because ASan is a compiler-based tool, and md5sum
+    # includes instrumented code from base.
+    device.old_interface.SetUtilWrapper(self.GetUtilWrapper())
+
+  @classmethod
+  def CopyFiles(cls, device):
+    """Copies ASan tools to the device."""
+    libs = glob.glob(os.path.join(DIR_SOURCE_ROOT,
+                                  'third_party/llvm-build/Release+Asserts/',
+                                  'lib/clang/*/lib/linux/',
+                                  'libclang_rt.asan-arm-android.so'))
+    assert len(libs) == 1
+    subprocess.call(
+        [os.path.join(
+             DIR_SOURCE_ROOT,
+             'tools/android/asan/third_party/asan_device_setup.sh'),
+         '--device', str(device),
+         '--lib', libs[0],
+         '--extra-options', AddressSanitizerTool.EXTRA_OPTIONS])
+    device.WaitUntilFullyBooted()
+
+  def GetTestWrapper(self):
+    return AddressSanitizerTool.WRAPPER_NAME
+
+  def GetUtilWrapper(self):
+    """Returns the wrapper for utilities, such as forwarder.
+
+    AddressSanitizer wrapper must be added to all instrumented binaries,
+    including forwarder and the like. This can be removed if such binaries
+    were built without instrumentation. """
+    return self.GetTestWrapper()
+
+  def SetupEnvironment(self):
+    try:
+      self._device.EnableRoot()
+    except device_errors.CommandFailedError as e:
+      # Try to set the timeout scale anyway.
+      # TODO(jbudorick) Handle this exception appropriately after interface
+      #                 conversions are finished.
+      logging.error(str(e))
+    SetChromeTimeoutScale(self._device, self.GetTimeoutScale())
+
+  def CleanUpEnvironment(self):
+    SetChromeTimeoutScale(self._device, None)
+
+  def GetTimeoutScale(self):
+    # Very slow startup.
+    return 20.0
+
+
+class ValgrindTool(BaseTool):
+  """Base abstract class for Valgrind tools."""
+
+  VG_DIR = '/data/local/tmp/valgrind'
+  VGLOGS_DIR = '/data/local/tmp/vglogs'
+
+  def __init__(self, device):
+    super(ValgrindTool, self).__init__()
+    self._device = device
+    # exactly 31 chars, SystemProperties::PROP_NAME_MAX
+    self._wrap_properties = ['wrap.com.google.android.apps.ch',
+                             'wrap.org.chromium.native_test']
+
+  @classmethod
+  def CopyFiles(cls, device):
+    """Copies Valgrind tools to the device."""
+    device.RunShellCommand(
+        'rm -r %s; mkdir %s' % (ValgrindTool.VG_DIR, ValgrindTool.VG_DIR))
+    device.RunShellCommand(
+        'rm -r %s; mkdir %s' % (ValgrindTool.VGLOGS_DIR,
+                                ValgrindTool.VGLOGS_DIR))
+    files = cls.GetFilesForTool()
+    device.PushChangedFiles(
+        [((os.path.join(DIR_SOURCE_ROOT, f),
+          os.path.join(ValgrindTool.VG_DIR, os.path.basename(f)))
+         for f in files)])
+
+  def SetupEnvironment(self):
+    """Sets up device environment."""
+    self._device.RunShellCommand('chmod 777 /data/local/tmp')
+    self._device.RunShellCommand('setenforce 0')
+    for prop in self._wrap_properties:
+      self._device.RunShellCommand(
+          'setprop %s "logwrapper %s"' % (prop, self.GetTestWrapper()))
+    SetChromeTimeoutScale(self._device, self.GetTimeoutScale())
+
+  def CleanUpEnvironment(self):
+    """Cleans up device environment."""
+    for prop in self._wrap_properties:
+      self._device.RunShellCommand('setprop %s ""' % (prop,))
+    SetChromeTimeoutScale(self._device, None)
+
+  @staticmethod
+  def GetFilesForTool():
+    """Returns a list of file names for the tool."""
+    raise NotImplementedError()
+
+  def NeedsDebugInfo(self):
+    """Whether this tool requires debug info.
+
+    Returns:
+      True if this tool can not work with stripped binaries.
+    """
+    return True
+
+
+class MemcheckTool(ValgrindTool):
+  """Memcheck tool."""
+
+  def __init__(self, device):
+    super(MemcheckTool, self).__init__(device)
+
+  @staticmethod
+  def GetFilesForTool():
+    """Returns a list of file names for the tool."""
+    return ['tools/valgrind/android/vg-chrome-wrapper.sh',
+            'tools/valgrind/memcheck/suppressions.txt',
+            'tools/valgrind/memcheck/suppressions_android.txt']
+
+  def GetTestWrapper(self):
+    """Returns a string that is to be prepended to the test command line."""
+    return ValgrindTool.VG_DIR + '/' + 'vg-chrome-wrapper.sh'
+
+  def GetTimeoutScale(self):
+    """Returns a multiplier that should be applied to timeout values."""
+    return 30
+
+
+class TSanTool(ValgrindTool):
+  """ThreadSanitizer tool. See http://code.google.com/p/data-race-test ."""
+
+  def __init__(self, device):
+    super(TSanTool, self).__init__(device)
+
+  @staticmethod
+  def GetFilesForTool():
+    """Returns a list of file names for the tool."""
+    return ['tools/valgrind/android/vg-chrome-wrapper-tsan.sh',
+            'tools/valgrind/tsan/suppressions.txt',
+            'tools/valgrind/tsan/suppressions_android.txt',
+            'tools/valgrind/tsan/ignores.txt']
+
+  def GetTestWrapper(self):
+    """Returns a string that is to be prepended to the test command line."""
+    return ValgrindTool.VG_DIR + '/' + 'vg-chrome-wrapper-tsan.sh'
+
+  def GetTimeoutScale(self):
+    """Returns a multiplier that should be applied to timeout values."""
+    return 30.0
+
+
+TOOL_REGISTRY = {
+    'memcheck': MemcheckTool,
+    'memcheck-renderer': MemcheckTool,
+    'tsan': TSanTool,
+    'tsan-renderer': TSanTool,
+    'asan': AddressSanitizerTool,
+}
+
+
+def CreateTool(tool_name, device):
+  """Creates a tool with the specified tool name.
+
+  Args:
+    tool_name: Name of the tool to create.
+    device: A DeviceUtils instance.
+  Returns:
+    A tool for the specified tool_name.
+  """
+  if not tool_name:
+    return BaseTool()
+
+  ctor = TOOL_REGISTRY.get(tool_name)
+  if ctor:
+    return ctor(device)
+  else:
+    print 'Unknown tool %s, available tools: %s' % (
+        tool_name, ', '.join(sorted(TOOL_REGISTRY.keys())))
+    sys.exit(1)
+
+def PushFilesForTool(tool_name, device):
+  """Pushes the files required for |tool_name| to |device|.
+
+  Args:
+    tool_name: Name of the tool to create.
+    device: A DeviceUtils instance.
+  """
+  if not tool_name:
+    return
+
+  clazz = TOOL_REGISTRY.get(tool_name)
+  if clazz:
+    clazz.CopyFiles(device)
+  else:
+    print 'Unknown tool %s, available tools: %s' % (
+        tool_name, ', '.join(sorted(TOOL_REGISTRY.keys())))
+    sys.exit(1)
+
diff --git a/build/android/rezip.gyp b/build/android/rezip.gyp
new file mode 100644
index 0000000..1115177
--- /dev/null
+++ b/build/android/rezip.gyp
@@ -0,0 +1,45 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Build the rezip build tool.
+{
+  'targets': [
+    {
+      # GN: //build/android/rezip:rezip
+      'target_name': 'rezip_apk_jar',
+      'type': 'none',
+      'variables': {
+        'java_in_dir': 'rezip',
+        'compile_stamp': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)/compile.stamp',
+        'javac_jar_path': '<(PRODUCT_DIR)/lib.java/rezip_apk.jar',
+      },
+      'actions': [
+        {
+          'action_name': 'javac_<(_target_name)',
+          'message': 'Compiling <(_target_name) java sources',
+          'variables': {
+            'java_sources': ['>!@(find >(java_in_dir) -name "*.java")'],
+          },
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/javac.py',
+            '>@(java_sources)',
+          ],
+          'outputs': [
+            '<(compile_stamp)',
+            '<(javac_jar_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/javac.py',
+            '--classpath=',
+            '--classes-dir=<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
+            '--jar-path=<(javac_jar_path)',
+            '--stamp=<(compile_stamp)',
+            '>@(java_sources)',
+          ]
+        },
+      ],
+    }
+  ],
+}
diff --git a/build/android/rezip/BUILD.gn b/build/android/rezip/BUILD.gn
new file mode 100644
index 0000000..8b8f78e
--- /dev/null
+++ b/build/android/rezip/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+# GYP: //build/android/rezip.gyp:rezip_apk_jar
+java_library("rezip") {
+  jar_path = "$root_build_dir/lib.java/rezip_apk.jar"
+  DEPRECATED_java_in_dir = "."
+}
diff --git a/build/android/rezip/RezipApk.java b/build/android/rezip/RezipApk.java
new file mode 100644
index 0000000..b4285cd
--- /dev/null
+++ b/build/android/rezip/RezipApk.java
@@ -0,0 +1,448 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.regex.Pattern;
+import java.util.zip.CRC32;
+
+/**
+ * Command line tool used to build APKs which support loading the native code library
+ * directly from the APK file. To construct the APK we rename the native library by
+ * adding the prefix "crazy." to the filename. This is done to prevent the Android
+ * Package Manager from extracting the library. The native code must be page aligned
+ * and uncompressed. The page alignment is implemented by adding a zero filled file
+ * in front of the the native code library. This tool is designed so that running
+ * SignApk and/or zipalign on the resulting APK does not break the page alignment.
+ * This is achieved by outputing the filenames in the same canonical order used
+ * by SignApk and adding the same alignment fields added by zipalign.
+ */
+class RezipApk {
+    // Alignment to use for non-compressed files (must match zipalign).
+    private static final int ALIGNMENT = 4;
+
+    // Alignment to use for non-compressed *.so files
+    private static final int LIBRARY_ALIGNMENT = 4096;
+
+    // Files matching this pattern are not copied to the output when adding alignment.
+    // When reordering and verifying the APK they are copied to the end of the file.
+    private static Pattern sMetaFilePattern =
+            Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA)|com/android/otacert))|("
+                    + Pattern.quote(JarFile.MANIFEST_NAME) + ")$");
+
+    // Pattern for matching a shared library in the APK
+    private static Pattern sLibraryPattern = Pattern.compile("^lib/[^/]*/lib.*[.]so$");
+    // Pattern for match the crazy linker in the APK
+    private static Pattern sCrazyLinkerPattern =
+            Pattern.compile("^lib/[^/]*/libchromium_android_linker.so$");
+    // Pattern for matching a crazy loaded shared library in the APK
+    private static Pattern sCrazyLibraryPattern = Pattern.compile("^lib/[^/]*/crazy.lib.*[.]so$");
+
+    private static boolean isLibraryFilename(String filename) {
+        return sLibraryPattern.matcher(filename).matches()
+                && !sCrazyLinkerPattern.matcher(filename).matches();
+    }
+
+    private static boolean isCrazyLibraryFilename(String filename) {
+        return sCrazyLibraryPattern.matcher(filename).matches();
+    }
+
+    private static String renameLibraryForCrazyLinker(String filename) {
+        int lastSlash = filename.lastIndexOf('/');
+        // We rename the library, so that the Android Package Manager
+        // no longer extracts the library.
+        return filename.substring(0, lastSlash + 1) + "crazy." + filename.substring(lastSlash + 1);
+    }
+
+    /**
+     * Wraps another output stream, counting the number of bytes written.
+     */
+    private static class CountingOutputStream extends OutputStream {
+        private long mCount = 0;
+        private OutputStream mOut;
+
+        public CountingOutputStream(OutputStream out) {
+            this.mOut = out;
+        }
+
+        /** Returns the number of bytes written. */
+        public long getCount() {
+            return mCount;
+        }
+
+        @Override public void write(byte[] b, int off, int len) throws IOException {
+            mOut.write(b, off, len);
+            mCount += len;
+        }
+
+        @Override public void write(int b) throws IOException {
+            mOut.write(b);
+            mCount++;
+        }
+
+        @Override public void close() throws IOException {
+            mOut.close();
+        }
+
+        @Override public void flush() throws IOException {
+            mOut.flush();
+        }
+    }
+
+    private static String outputName(JarEntry entry, boolean rename) {
+        String inName = entry.getName();
+        if (rename && entry.getSize() > 0 && isLibraryFilename(inName)) {
+            return renameLibraryForCrazyLinker(inName);
+        }
+        return inName;
+    }
+
+    /**
+     * Comparator used to sort jar entries from the input file.
+     * Sorting is done based on the output filename (which maybe renamed).
+     * Filenames are in natural string order, except that filenames matching
+     * the meta-file pattern are always after other files. This is so the manifest
+     * and signature are at the end of the file after any alignment file.
+     */
+    private static class EntryComparator implements Comparator<JarEntry> {
+        private boolean mRename;
+
+        public EntryComparator(boolean rename) {
+            mRename = rename;
+        }
+
+        @Override
+        public int compare(JarEntry j1, JarEntry j2) {
+            String o1 = outputName(j1, mRename);
+            String o2 = outputName(j2, mRename);
+            boolean o1Matches = sMetaFilePattern.matcher(o1).matches();
+            boolean o2Matches = sMetaFilePattern.matcher(o2).matches();
+            if (o1Matches != o2Matches) {
+                return o1Matches ? 1 : -1;
+            } else {
+                return o1.compareTo(o2);
+            }
+        }
+    }
+
+    // Build an ordered list of jar entries. The jar entries from the input are
+    // sorted based on the output filenames (which maybe renamed). If |omitMetaFiles|
+    // is true do not include the jar entries for the META-INF files.
+    // Entries are ordered in the deterministic order used by SignApk.
+    private static List<JarEntry> getOutputFileOrderEntries(
+            JarFile jar, boolean omitMetaFiles, boolean rename) {
+        List<JarEntry> entries = new ArrayList<JarEntry>();
+        for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
+            JarEntry entry = e.nextElement();
+            if (entry.isDirectory()) {
+                continue;
+            }
+            if (omitMetaFiles && sMetaFilePattern.matcher(entry.getName()).matches()) {
+                continue;
+            }
+            entries.add(entry);
+        }
+
+        // We sort the input entries by name. When present META-INF files
+        // are sorted to the end.
+        Collections.sort(entries, new EntryComparator(rename));
+        return entries;
+    }
+
+    /**
+     * Add a zero filled alignment file at this point in the zip file,
+     * The added file will be added before |name| and after |prevName|.
+     * The size of the alignment file is such that the location of the
+     * file |name| will be on a LIBRARY_ALIGNMENT boundary.
+     *
+     * Note this arrangement is devised so that running SignApk and/or zipalign on the resulting
+     * file will not alter the alignment.
+     *
+     * @param offset number of bytes into the output file at this point.
+     * @param timestamp time in millis since the epoch to include in the header.
+     * @param name the name of the library filename.
+     * @param prevName the name of the previous file in the archive (or null).
+     * @param out jar output stream to write the alignment file to.
+     *
+     * @throws IOException if the output file can not be written.
+     */
+    private static void addAlignmentFile(
+            long offset, long timestamp, String name, String prevName,
+            JarOutputStream out) throws IOException {
+
+        // Compute the start and alignment of the library, as if it was next.
+        int headerSize = JarFile.LOCHDR + name.length();
+        long libOffset = offset + headerSize;
+        int libNeeded = LIBRARY_ALIGNMENT - (int) (libOffset % LIBRARY_ALIGNMENT);
+        if (libNeeded == LIBRARY_ALIGNMENT) {
+            // Already aligned, no need to added alignment file.
+            return;
+        }
+
+        // Check that there is not another file between the library and the
+        // alignment file.
+        String alignName = name.substring(0, name.length() - 2) + "align";
+        if (prevName != null && prevName.compareTo(alignName) >= 0) {
+            throw new UnsupportedOperationException(
+                "Unable to insert alignment file, because there is "
+                + "another file in front of the file to be aligned. "
+                + "Other file: " + prevName + " Alignment file: " + alignName
+                + " file: " + name);
+        }
+
+        // Compute the size of the alignment file header.
+        headerSize = JarFile.LOCHDR + alignName.length();
+        // We are going to add an alignment file of type STORED. This file
+        // will itself induce a zipalign alignment adjustment.
+        int extraNeeded =
+                (ALIGNMENT - (int) ((offset + headerSize) % ALIGNMENT)) % ALIGNMENT;
+        headerSize += extraNeeded;
+
+        if (libNeeded < headerSize + 1) {
+            // The header was bigger than the alignment that we need, add another page.
+            libNeeded += LIBRARY_ALIGNMENT;
+        }
+        // Compute the size of the alignment file.
+        libNeeded -= headerSize;
+
+        // Build the header for the alignment file.
+        byte[] zeroBuffer = new byte[libNeeded];
+        JarEntry alignEntry = new JarEntry(alignName);
+        alignEntry.setMethod(JarEntry.STORED);
+        alignEntry.setSize(libNeeded);
+        alignEntry.setTime(timestamp);
+        CRC32 crc = new CRC32();
+        crc.update(zeroBuffer);
+        alignEntry.setCrc(crc.getValue());
+
+        if (extraNeeded != 0) {
+            alignEntry.setExtra(new byte[extraNeeded]);
+        }
+
+        // Output the alignment file.
+        out.putNextEntry(alignEntry);
+        out.write(zeroBuffer);
+        out.closeEntry();
+        out.flush();
+    }
+
+    // Make a JarEntry for the output file which corresponds to the input
+    // file. The output file will be called |name|. The output file will always
+    // be uncompressed (STORED). If the input is not STORED it is necessary to inflate
+    // it to compute the CRC and size of the output entry.
+    private static JarEntry makeStoredEntry(String name, JarEntry inEntry, JarFile in)
+            throws IOException {
+        JarEntry outEntry = new JarEntry(name);
+        outEntry.setMethod(JarEntry.STORED);
+
+        if (inEntry.getMethod() == JarEntry.STORED) {
+            outEntry.setCrc(inEntry.getCrc());
+            outEntry.setSize(inEntry.getSize());
+        } else {
+            // We are inflating the file. We need to compute the CRC and size.
+            byte[] buffer = new byte[4096];
+            CRC32 crc = new CRC32();
+            int size = 0;
+            int num;
+            InputStream data = in.getInputStream(inEntry);
+            while ((num = data.read(buffer)) > 0) {
+                crc.update(buffer, 0, num);
+                size += num;
+            }
+            data.close();
+            outEntry.setCrc(crc.getValue());
+            outEntry.setSize(size);
+        }
+        return outEntry;
+    }
+
+    /**
+     * Copy the contents of the input APK file to the output APK file. If |rename| is
+     * true then non-empty libraries (*.so) in the input will be renamed by prefixing
+     * "crazy.". This is done to prevent the Android Package Manager extracting the
+     * library. Note the crazy linker itself is not renamed, for bootstrapping reasons.
+     * Empty libraries are not renamed (they are in the APK to workaround a bug where
+     * the Android Package Manager fails to delete old versions when upgrading).
+     * There must be exactly one "crazy" library in the output stream. The "crazy"
+     * library will be uncompressed and page aligned in the output stream. Page
+     * alignment is implemented by adding a zero filled file, regular alignment is
+     * implemented by adding a zero filled extra field to the zip file header. If
+     * |addAlignment| is true a page alignment file is added, otherwise the "crazy"
+     * library must already be page aligned. Care is taken so that the output is generated
+     * in the same way as SignApk. This is important so that running SignApk and
+     * zipalign on the output does not break the page alignment. The archive may not
+     * contain a "*.apk" as SignApk has special nested signing logic that we do not
+     * support.
+     *
+     * @param in The input APK File.
+     * @param out The output APK stream.
+     * @param countOut Counting output stream (to measure the current offset).
+     * @param addAlignment Whether to add the alignment file or just check.
+     * @param rename Whether to rename libraries to be "crazy".
+     *
+     * @throws IOException if the output file can not be written.
+     */
+    private static void rezip(
+            JarFile in, JarOutputStream out, CountingOutputStream countOut,
+            boolean addAlignment, boolean rename) throws IOException {
+
+        List<JarEntry> entries = getOutputFileOrderEntries(in, addAlignment, rename);
+        long timestamp = System.currentTimeMillis();
+        byte[] buffer = new byte[4096];
+        boolean firstEntry = true;
+        String prevName = null;
+        int numCrazy = 0;
+        for (JarEntry inEntry : entries) {
+            // Rename files, if specied.
+            String name = outputName(inEntry, rename);
+            if (name.endsWith(".apk")) {
+                throw new UnsupportedOperationException(
+                        "Nested APKs are not supported: " + name);
+            }
+
+            // Build the header.
+            JarEntry outEntry = null;
+            boolean isCrazy = isCrazyLibraryFilename(name);
+            if (isCrazy) {
+                // "crazy" libraries are alway output uncompressed (STORED).
+                outEntry = makeStoredEntry(name, inEntry, in);
+                numCrazy++;
+                if (numCrazy > 1) {
+                    throw new UnsupportedOperationException(
+                            "Found more than one library\n"
+                            + "Multiple libraries are not supported for APKs that use "
+                            + "'load_library_from_zip_file'.\n"
+                            + "See crbug/388223.\n"
+                            + "Note, check that your build is clean.\n"
+                            + "An unclean build can incorrectly incorporate old "
+                            + "libraries in the APK.");
+                }
+            } else if (inEntry.getMethod() == JarEntry.STORED) {
+                // Preserve the STORED method of the input entry.
+                outEntry = new JarEntry(inEntry);
+                outEntry.setExtra(null);
+            } else {
+                // Create a new entry so that the compressed len is recomputed.
+                outEntry = new JarEntry(name);
+            }
+            outEntry.setTime(timestamp);
+
+            // Compute and add alignment
+            long offset = countOut.getCount();
+            if (firstEntry) {
+                // The first entry in a jar file has an extra field of
+                // four bytes that you can't get rid of; any extra
+                // data you specify in the JarEntry is appended to
+                // these forced four bytes.  This is JAR_MAGIC in
+                // JarOutputStream; the bytes are 0xfeca0000.
+                firstEntry = false;
+                offset += 4;
+            }
+            if (outEntry.getMethod() == JarEntry.STORED) {
+                if (isCrazy) {
+                    if (addAlignment) {
+                        addAlignmentFile(offset, timestamp, name, prevName, out);
+                    }
+                    // We check that we did indeed get to a page boundary.
+                    offset = countOut.getCount() + JarFile.LOCHDR + name.length();
+                    if ((offset % LIBRARY_ALIGNMENT) != 0) {
+                        throw new AssertionError(
+                                "Library was not page aligned when verifying page alignment. "
+                                + "Library name: " + name + " Expected alignment: "
+                                + LIBRARY_ALIGNMENT + "Offset: " + offset + " Error: "
+                                + (offset % LIBRARY_ALIGNMENT));
+                    }
+                } else {
+                    // This is equivalent to zipalign.
+                    offset += JarFile.LOCHDR + name.length();
+                    int needed = (ALIGNMENT - (int) (offset % ALIGNMENT)) % ALIGNMENT;
+                    if (needed != 0) {
+                        outEntry.setExtra(new byte[needed]);
+                    }
+                }
+            }
+            out.putNextEntry(outEntry);
+
+            // Copy the data from the input to the output
+            int num;
+            InputStream data = in.getInputStream(inEntry);
+            while ((num = data.read(buffer)) > 0) {
+                out.write(buffer, 0, num);
+            }
+            data.close();
+            out.closeEntry();
+            out.flush();
+            prevName = name;
+        }
+        if (numCrazy == 0) {
+            throw new AssertionError("There was no crazy library in the archive");
+        }
+    }
+
+    private static void usage() {
+        System.err.println("Usage: prealignapk (addalignment|reorder) input.apk output.apk");
+        System.err.println("\"crazy\" libraries are always inflated in the output");
+        System.err.println(
+                "  renamealign  - rename libraries with \"crazy.\" prefix and add alignment file");
+        System.err.println("  align        - add alignment file");
+        System.err.println("  reorder      - re-creates canonical ordering and checks alignment");
+        System.exit(2);
+    }
+
+    public static void main(String[] args) throws IOException {
+        if (args.length != 3) usage();
+
+        boolean addAlignment = false;
+        boolean rename = false;
+        if (args[0].equals("renamealign")) {
+            // Normal case. Before signing we rename the library and add an alignment file.
+            addAlignment = true;
+            rename = true;
+        } else if (args[0].equals("align")) {
+            // LGPL compliance case. Before signing, we add an alignment file to a
+            // reconstructed APK which already contains the "crazy" library.
+            addAlignment = true;
+            rename = false;
+        } else if (args[0].equals("reorder")) {
+            // Normal case. After jarsigning we write the file in the canonical order and check.
+            addAlignment = false;
+        } else {
+            usage();
+        }
+
+        String inputFilename = args[1];
+        String outputFilename = args[2];
+
+        JarFile inputJar = null;
+        FileOutputStream outputFile = null;
+
+        try {
+            inputJar = new JarFile(new File(inputFilename), true);
+            outputFile = new FileOutputStream(outputFilename);
+
+            CountingOutputStream outCount = new CountingOutputStream(outputFile);
+            JarOutputStream outputJar = new JarOutputStream(outCount);
+
+            // Match the compression level used by SignApk.
+            outputJar.setLevel(9);
+
+            rezip(inputJar, outputJar, outCount, addAlignment, rename);
+            outputJar.close();
+        } finally {
+            if (inputJar != null) inputJar.close();
+            if (outputFile != null) outputFile.close();
+        }
+    }
+}
diff --git a/build/android/screenshot.py b/build/android/screenshot.py
new file mode 100755
index 0000000..c48a255
--- /dev/null
+++ b/build/android/screenshot.py
@@ -0,0 +1,97 @@
+#!/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.
+
+"""Takes a screenshot or a screen video capture from an Android device."""
+
+import logging
+import optparse
+import os
+import sys
+
+from pylib import screenshot
+from pylib.device import device_errors
+from pylib.device import device_utils
+
+def _PrintMessage(heading, eol='\n'):
+  sys.stdout.write('%s%s' % (heading, eol))
+  sys.stdout.flush()
+
+
+def _CaptureScreenshot(device, host_file):
+  host_file = device.TakeScreenshot(host_file)
+  _PrintMessage('Screenshot written to %s' % os.path.abspath(host_file))
+
+
+def _CaptureVideo(device, host_file, options):
+  size = tuple(map(int, options.size.split('x'))) if options.size else None
+  recorder = screenshot.VideoRecorder(device,
+                                      megabits_per_second=options.bitrate,
+                                      size=size,
+                                      rotate=options.rotate)
+  try:
+    recorder.Start()
+    _PrintMessage('Recording. Press Enter to stop...', eol='')
+    raw_input()
+  finally:
+    recorder.Stop()
+  host_file = recorder.Pull(host_file)
+  _PrintMessage('Video written to %s' % os.path.abspath(host_file))
+
+
+def main():
+  # Parse options.
+  parser = optparse.OptionParser(description=__doc__,
+                                 usage='screenshot.py [options] [filename]')
+  parser.add_option('-d', '--device', metavar='ANDROID_DEVICE', help='Serial '
+                    'number of Android device to use.', default=None)
+  parser.add_option('-f', '--file', help='Save result to file instead of '
+                    'generating a timestamped file name.', metavar='FILE')
+  parser.add_option('-v', '--verbose', help='Verbose logging.',
+                    action='store_true')
+  video_options = optparse.OptionGroup(parser, 'Video capture')
+  video_options.add_option('--video', help='Enable video capturing. Requires '
+                           'Android KitKat or later', action='store_true')
+  video_options.add_option('-b', '--bitrate', help='Bitrate in megabits/s, '
+                           'from 0.1 to 100 mbps, %default mbps by default.',
+                           default=4, type='float')
+  video_options.add_option('-r', '--rotate', help='Rotate video by 90 degrees.',
+                           default=False, action='store_true')
+  video_options.add_option('-s', '--size', metavar='WIDTHxHEIGHT',
+                           help='Frame size to use instead of the device '
+                           'screen size.', default=None)
+  parser.add_option_group(video_options)
+
+  (options, args) = parser.parse_args()
+
+  if len(args) > 1:
+    parser.error('Too many positional arguments.')
+  host_file = args[0] if args else options.file
+
+  if options.verbose:
+    logging.getLogger().setLevel(logging.DEBUG)
+
+  devices = device_utils.DeviceUtils.HealthyDevices()
+
+  if not options.device:
+    if len(devices) > 1:
+      parser.error('Multiple devices are attached. '
+                   'Please specify device serial number with --device.')
+    elif len(devices) == 1:
+      device = devices[0]
+    else:
+      raise device_errors.NoDevicesError()
+  else:
+    device = device_utils.DeviceUtils(options.device)
+
+  if options.video:
+    _CaptureVideo(device, host_file, options)
+  else:
+    _CaptureScreenshot(device, host_file)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/setup.gyp b/build/android/setup.gyp
new file mode 100644
index 0000000..b3c3422
--- /dev/null
+++ b/build/android/setup.gyp
@@ -0,0 +1,82 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'conditions': [
+    ['component == "shared_library"', {
+      'targets': [
+        {
+          # These libraries from the Android ndk are required to be packaged with
+          # any APK that is built with them. build/java_apk.gypi expects any
+          # libraries that should be packaged with the apk to be in
+          # <(SHARED_LIB_DIR)
+          'target_name': 'copy_system_libraries',
+          'type': 'none',
+          'copies': [
+            {
+              'destination': '<(SHARED_LIB_DIR)/',
+              'files': [
+                '<(android_libcpp_libs_dir)/libc++_shared.so',
+              ],
+            },
+          ],
+        },
+      ],
+    }],
+  ],
+  'targets': [
+    {
+      'target_name': 'get_build_device_configurations',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'get configurations',
+          'inputs': [
+            'gyp/util/build_device.py',
+            'gyp/get_device_configuration.py',
+          ],
+          'outputs': [
+            '<(build_device_config_path)',
+            '<(build_device_config_path).fake',
+          ],
+          'action': [
+            'python', 'gyp/get_device_configuration.py',
+            '--output=<(build_device_config_path)',
+          ],
+        }
+      ],
+    },
+    {
+      # Target for creating common output build directories. Creating output
+      # dirs beforehand ensures that build scripts can assume these folders to
+      # exist and there are no race conditions resulting from build scripts
+      # trying to create these directories.
+      # The build/java.gypi target depends on this target.
+      'target_name': 'build_output_dirs',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'create_java_output_dirs',
+          'variables' : {
+            'output_dirs' : [
+              '<(PRODUCT_DIR)/apks',
+              '<(PRODUCT_DIR)/lib.java',
+              '<(PRODUCT_DIR)/test.lib.java',
+            ]
+          },
+          'inputs' : [],
+          # By not specifying any outputs, we ensure that this command isn't
+          # re-run when the output directories are touched (i.e. apks are
+          # written to them).
+          'outputs': [''],
+          'action': [
+            'mkdir',
+            '-p',
+            '<@(output_dirs)',
+          ],
+        },
+      ],
+    }, # build_output_dirs
+  ]
+}
+
diff --git a/build/android/strip_native_libraries.gypi b/build/android/strip_native_libraries.gypi
new file mode 100644
index 0000000..bdffcfd
--- /dev/null
+++ b/build/android/strip_native_libraries.gypi
@@ -0,0 +1,54 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule that strips
+# native libraries.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'action_name': 'strip_native_libraries',
+#    'actions': [
+#      'variables': {
+#        'ordered_libraries_file': 'file generated by write_ordered_libraries'
+#        'input_paths': 'files to be added to the list of inputs'
+#        'stamp': 'file to touch when the action is complete'
+#        'stripped_libraries_dir': 'directory to store stripped libraries',
+#      },
+#      'includes': [ '../../build/android/strip_native_libraries.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'message': 'Stripping libraries for <(_target_name)',
+  'variables': {
+    'input_paths': [],
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/strip_library_for_device.py',
+    '<(ordered_libraries_file)',
+    '>@(input_paths)',
+  ],
+  'outputs': [
+    '<(stamp)',
+  ],
+  'conditions': [
+    ['component == "shared_library"', {
+      # Add a fake output to force the build to always re-run this step. This
+      # is required because the real inputs are not known at gyp-time and
+      # changing base.so may not trigger changes to dependent libraries.
+      'outputs': [ '<(stamp).fake' ]
+    }],
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/strip_library_for_device.py',
+    '--android-strip=<(android_strip)',
+    '--android-strip-arg=--strip-unneeded',
+    '--stripped-libraries-dir=<(stripped_libraries_dir)',
+    '--libraries-dir=<(SHARED_LIB_DIR),<(PRODUCT_DIR)',
+    '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
+    '--stamp=<(stamp)',
+  ],
+}
diff --git a/build/android/symbolize.py b/build/android/symbolize.py
new file mode 100755
index 0000000..56d3b19
--- /dev/null
+++ b/build/android/symbolize.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Symbolizes stack traces generated by Chromium for Android.
+
+Sample usage:
+  adb logcat chromium:V | symbolize.py
+"""
+
+import os
+import re
+import sys
+
+from pylib import constants
+
+# Uses symbol.py from third_party/android_platform, not python's.
+sys.path.insert(0,
+                os.path.join(constants.DIR_SOURCE_ROOT,
+                            'third_party/android_platform/development/scripts'))
+import symbol
+
+# Sample output from base/debug/stack_trace_android.cc
+#00 0x693cd34f /path/to/some/libfoo.so+0x0007434f
+TRACE_LINE = re.compile(r'(?P<frame>\#[0-9]+ 0x[0-9a-f]{8,8}) '
+                        r'(?P<lib>[^+]+)\+0x(?P<addr>[0-9a-f]{8,8})')
+
+class Symbolizer(object):
+  def __init__(self, output):
+    self._output = output
+
+  def write(self, data):
+    while True:
+      match = re.search(TRACE_LINE, data)
+      if not match:
+        self._output.write(data)
+        break
+
+      frame = match.group('frame')
+      lib = match.group('lib')
+      addr = match.group('addr')
+
+      # TODO(scherkus): Doing a single lookup per line is pretty slow,
+      # especially with larger libraries. Consider caching strategies such as:
+      # 1) Have Python load the libraries and do symbol lookups instead of
+      #    calling out to addr2line each time.
+      # 2) Have Python keep multiple addr2line instances open as subprocesses,
+      #    piping addresses and reading back symbols as we find them
+      # 3) Read ahead the entire stack trace until we find no more, then batch
+      #    the symbol lookups.
+      #
+      # TODO(scherkus): These results are memoized, which could result in
+      # incorrect lookups when running this script on long-lived instances
+      # (e.g., adb logcat) when doing incremental development. Consider clearing
+      # the cache when modification timestamp of libraries change.
+      sym = symbol.SymbolInformation(lib, addr, False)[0][0]
+
+      if not sym:
+        post = match.end('addr')
+        self._output.write(data[:post])
+        data = data[post:]
+        continue
+
+      pre = match.start('frame')
+      post = match.end('addr')
+
+      self._output.write(data[:pre])
+      self._output.write(frame)
+      self._output.write(' ')
+      self._output.write(sym)
+
+      data = data[post:]
+
+  def flush(self):
+    self._output.flush()
+
+
+def main():
+  symbolizer = Symbolizer(sys.stdout)
+  for line in sys.stdin:
+    symbolizer.write(line)
+  symbolizer.flush()
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/android/symbolize_test.py b/build/android/symbolize_test.py
new file mode 100755
index 0000000..826d852
--- /dev/null
+++ b/build/android/symbolize_test.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittest for symbolize.py.
+
+This test uses test libraries generated by the Android g++ toolchain.
+
+Should things break you can recreate the libraries and get the updated
+addresses and demangled names by running the following:
+  cd test/symbolize/
+  make
+  nm -gC *.so
+"""
+
+import StringIO
+import unittest
+
+import symbolize
+
+LIB_A_PATH = '/build/android/tests/symbolize/liba.so'
+LIB_B_PATH = '/build/android/tests/symbolize/libb.so'
+
+def RunSymbolizer(text):
+  output = StringIO.StringIO()
+  s = symbolize.Symbolizer(output)
+  s.write(text)
+  return output.getvalue()
+
+
+class SymbolizerUnittest(unittest.TestCase):
+  def testSingleLineNoMatch(self):
+    # Leading '#' is required.
+    expected = '00 0x00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Whitespace should be exactly one space.
+    expected = '#00  0x00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000  ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Decimal stack frame numbers are required.
+    expected = '#0a 0x00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Hexadecimal addresses are required.
+    expected = '#00 0xghijklmn ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000 ' + LIB_A_PATH + '+0xghijklmn\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Addresses must be exactly 8 characters.
+    expected = '#00 0x0000000 ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x000000000 ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    expected = '#00 0x0000000 ' + LIB_A_PATH + '+0x0000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x000000000 ' + LIB_A_PATH + '+0x000000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Addresses must be prefixed with '0x'.
+    expected = '#00 00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000 ' + LIB_A_PATH + '+00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Library name is required.
+    expected = '#00 0x00000000\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000 +0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+    # Library name must be followed by offset with no spaces around '+'.
+    expected = '#00 0x00000000 ' + LIB_A_PATH + ' +0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000 ' + LIB_A_PATH + '+ 0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000 ' + LIB_A_PATH + ' 0x00000254\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+    expected = '#00 0x00000000 ' + LIB_A_PATH + '+\n'
+    self.assertEqual(expected, RunSymbolizer(expected))
+
+  def testSingleLine(self):
+    text = '#00 0x00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    expected = '#00 0x00000000 A::Bar(char const*)\n'
+    actual = RunSymbolizer(text)
+    self.assertEqual(expected, actual)
+
+  def testSingleLineWithSurroundingText(self):
+    text = 'LEFT #00 0x00000000 ' + LIB_A_PATH + '+0x00000254 RIGHT\n'
+    expected = 'LEFT #00 0x00000000 A::Bar(char const*) RIGHT\n'
+    actual = RunSymbolizer(text)
+    self.assertEqual(expected, actual)
+
+  def testMultipleLinesSameLibrary(self):
+    text = '#00 0x00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    text += '#01 0x00000000 ' + LIB_A_PATH + '+0x00000234\n'
+    expected = '#00 0x00000000 A::Bar(char const*)\n'
+    expected += '#01 0x00000000 A::Foo(int)\n'
+    actual = RunSymbolizer(text)
+    self.assertEqual(expected, actual)
+
+  def testMultipleLinesDifferentLibrary(self):
+    text = '#00 0x00000000 ' + LIB_A_PATH + '+0x00000254\n'
+    text += '#01 0x00000000 ' + LIB_B_PATH + '+0x00000234\n'
+    expected = '#00 0x00000000 A::Bar(char const*)\n'
+    expected += '#01 0x00000000 B::Baz(float)\n'
+    actual = RunSymbolizer(text)
+    self.assertEqual(expected, actual)
+
+  def testMultipleLinesWithSurroundingTextEverywhere(self):
+    text = 'TOP\n'
+    text += 'LEFT #00 0x00000000 ' + LIB_A_PATH + '+0x00000254 RIGHT\n'
+    text += 'LEFT #01 0x00000000 ' + LIB_B_PATH + '+0x00000234 RIGHT\n'
+    text += 'BOTTOM\n'
+    expected = 'TOP\n'
+    expected += 'LEFT #00 0x00000000 A::Bar(char const*) RIGHT\n'
+    expected += 'LEFT #01 0x00000000 B::Baz(float) RIGHT\n'
+    expected += 'BOTTOM\n'
+    actual = RunSymbolizer(text)
+    self.assertEqual(expected, actual)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
new file mode 100755
index 0000000..b9d2a3f
--- /dev/null
+++ b/build/android/test_runner.py
@@ -0,0 +1,1040 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs all types of tests from one unified interface."""
+
+import argparse
+import collections
+import logging
+import os
+import shutil
+import signal
+import sys
+import threading
+import unittest
+
+from pylib import constants
+from pylib import forwarder
+from pylib import ports
+from pylib.base import base_test_result
+from pylib.base import environment_factory
+from pylib.base import test_dispatcher
+from pylib.base import test_instance_factory
+from pylib.base import test_run_factory
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.gtest import gtest_config
+from pylib.gtest import setup as gtest_setup
+from pylib.gtest import test_options as gtest_test_options
+from pylib.linker import setup as linker_setup
+from pylib.host_driven import setup as host_driven_setup
+from pylib.instrumentation import setup as instrumentation_setup
+from pylib.instrumentation import test_options as instrumentation_test_options
+from pylib.junit import setup as junit_setup
+from pylib.junit import test_dispatcher as junit_dispatcher
+from pylib.monkey import setup as monkey_setup
+from pylib.monkey import test_options as monkey_test_options
+from pylib.perf import setup as perf_setup
+from pylib.perf import test_options as perf_test_options
+from pylib.perf import test_runner as perf_test_runner
+from pylib.results import json_results
+from pylib.results import report_results
+from pylib.uiautomator import setup as uiautomator_setup
+from pylib.uiautomator import test_options as uiautomator_test_options
+from pylib.utils import apk_helper
+from pylib.utils import base_error
+from pylib.utils import reraiser_thread
+from pylib.utils import run_tests_helper
+
+
+def AddCommonOptions(parser):
+  """Adds all common options to |parser|."""
+
+  group = parser.add_argument_group('Common Options')
+
+  default_build_type = os.environ.get('BUILDTYPE', 'Debug')
+
+  debug_or_release_group = group.add_mutually_exclusive_group()
+  debug_or_release_group.add_argument(
+      '--debug', action='store_const', const='Debug', dest='build_type',
+      default=default_build_type,
+      help=('If set, run test suites under out/Debug. '
+            'Default is env var BUILDTYPE or Debug.'))
+  debug_or_release_group.add_argument(
+      '--release', action='store_const', const='Release', dest='build_type',
+      help=('If set, run test suites under out/Release. '
+            'Default is env var BUILDTYPE or Debug.'))
+
+  group.add_argument('--build-directory', dest='build_directory',
+                     help=('Path to the directory in which build files are'
+                           ' located (should not include build type)'))
+  group.add_argument('--output-directory', dest='output_directory',
+                     help=('Path to the directory in which build files are'
+                           ' located (must include build type). This will take'
+                           ' precedence over --debug, --release and'
+                           ' --build-directory'))
+  group.add_argument('--num_retries', dest='num_retries', type=int, default=2,
+                     help=('Number of retries for a test before '
+                           'giving up (default: %(default)s).'))
+  group.add_argument('-v',
+                     '--verbose',
+                     dest='verbose_count',
+                     default=0,
+                     action='count',
+                     help='Verbose level (multiple times for more)')
+  group.add_argument('--flakiness-dashboard-server',
+                     dest='flakiness_dashboard_server',
+                     help=('Address of the server that is hosting the '
+                           'Chrome for Android flakiness dashboard.'))
+  group.add_argument('--enable-platform-mode', action='store_true',
+                     help=('Run the test scripts in platform mode, which '
+                           'conceptually separates the test runner from the '
+                           '"device" (local or remote, real or emulated) on '
+                           'which the tests are running. [experimental]'))
+  group.add_argument('-e', '--environment', default='local',
+                     choices=constants.VALID_ENVIRONMENTS,
+                     help='Test environment to run in (default: %(default)s).')
+  group.add_argument('--adb-path',
+                     help=('Specify the absolute path of the adb binary that '
+                           'should be used.'))
+  group.add_argument('--json-results-file', dest='json_results_file',
+                     help='If set, will dump results in JSON form '
+                          'to specified file.')
+
+def ProcessCommonOptions(args):
+  """Processes and handles all common options."""
+  run_tests_helper.SetLogLevel(args.verbose_count)
+  constants.SetBuildType(args.build_type)
+  if args.build_directory:
+    constants.SetBuildDirectory(args.build_directory)
+  if args.output_directory:
+    constants.SetOutputDirectory(args.output_directory)
+  if args.adb_path:
+    constants.SetAdbPath(args.adb_path)
+  # Some things such as Forwarder require ADB to be in the environment path.
+  adb_dir = os.path.dirname(constants.GetAdbPath())
+  if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep):
+    os.environ['PATH'] = adb_dir + os.pathsep + os.environ['PATH']
+
+
+def AddRemoteDeviceOptions(parser):
+  group = parser.add_argument_group('Remote Device Options')
+
+  group.add_argument('--trigger',
+                     help=('Only triggers the test if set. Stores test_run_id '
+                           'in given file path. '))
+  group.add_argument('--collect',
+                     help=('Only collects the test results if set. '
+                           'Gets test_run_id from given file path.'))
+  group.add_argument('--remote-device', action='append',
+                     help='Device type to run test on.')
+  group.add_argument('--results-path',
+                     help='File path to download results to.')
+  group.add_argument('--api-protocol',
+                     help='HTTP protocol to use. (http or https)')
+  group.add_argument('--api-address',
+                     help='Address to send HTTP requests.')
+  group.add_argument('--api-port',
+                     help='Port to send HTTP requests to.')
+  group.add_argument('--runner-type',
+                     help='Type of test to run as.')
+  group.add_argument('--runner-package',
+                     help='Package name of test.')
+  group.add_argument('--device-type',
+                     choices=constants.VALID_DEVICE_TYPES,
+                     help=('Type of device to run on. iOS or android'))
+  group.add_argument('--device-oem', action='append',
+                     help='Device OEM to run on.')
+  group.add_argument('--remote-device-file',
+                     help=('File with JSON to select remote device. '
+                           'Overrides all other flags.'))
+  group.add_argument('--remote-device-timeout', type=int,
+                     help='Times to retry finding remote device')
+  group.add_argument('--network-config', type=int,
+                     help='Integer that specifies the network environment '
+                          'that the tests will be run in.')
+
+  device_os_group = group.add_mutually_exclusive_group()
+  device_os_group.add_argument('--remote-device-minimum-os',
+                               help='Minimum OS on device.')
+  device_os_group.add_argument('--remote-device-os', action='append',
+                               help='OS to have on the device.')
+
+  api_secret_group = group.add_mutually_exclusive_group()
+  api_secret_group.add_argument('--api-secret', default='',
+                                help='API secret for remote devices.')
+  api_secret_group.add_argument('--api-secret-file', default='',
+                                help='Path to file that contains API secret.')
+
+  api_key_group = group.add_mutually_exclusive_group()
+  api_key_group.add_argument('--api-key', default='',
+                             help='API key for remote devices.')
+  api_key_group.add_argument('--api-key-file', default='',
+                             help='Path to file that contains API key.')
+
+
+def AddDeviceOptions(parser):
+  """Adds device options to |parser|."""
+  group = parser.add_argument_group(title='Device Options')
+  group.add_argument('--tool',
+                     dest='tool',
+                     help=('Run the test under a tool '
+                           '(use --tool help to list them)'))
+  group.add_argument('-d', '--device', dest='test_device',
+                     help=('Target device for the test suite '
+                           'to run on.'))
+
+
+def AddGTestOptions(parser):
+  """Adds gtest options to |parser|."""
+
+  gtest_suites = list(gtest_config.STABLE_TEST_SUITES
+                      + gtest_config.EXPERIMENTAL_TEST_SUITES)
+
+  group = parser.add_argument_group('GTest Options')
+  group.add_argument('-s', '--suite', dest='suite_name',
+                     nargs='+', metavar='SUITE_NAME', required=True,
+                     help=('Executable name of the test suite to run. '
+                           'Available suites include (but are not limited to): '
+                            '%s' % ', '.join('"%s"' % s for s in gtest_suites)))
+  group.add_argument('--gtest_also_run_disabled_tests',
+                     '--gtest-also-run-disabled-tests',
+                     dest='run_disabled', action='store_true',
+                     help='Also run disabled tests if applicable.')
+  group.add_argument('-a', '--test-arguments', dest='test_arguments',
+                     default='',
+                     help='Additional arguments to pass to the test.')
+  group.add_argument('-t', dest='timeout', type=int, default=60,
+                     help='Timeout to wait for each test '
+                          '(default: %(default)s).')
+  group.add_argument('--isolate_file_path',
+                     '--isolate-file-path',
+                     dest='isolate_file_path',
+                     help='.isolate file path to override the default '
+                          'path')
+
+  filter_group = group.add_mutually_exclusive_group()
+  filter_group.add_argument('-f', '--gtest_filter', '--gtest-filter',
+                            dest='test_filter',
+                            help='googletest-style filter string.')
+  filter_group.add_argument('--gtest-filter-file', dest='test_filter_file',
+                            help='Path to file that contains googletest-style '
+                                  'filter strings. (Lines will be joined with '
+                                  '":" to create a single filter string.)')
+
+  AddDeviceOptions(parser)
+  AddCommonOptions(parser)
+  AddRemoteDeviceOptions(parser)
+
+
+def AddLinkerTestOptions(parser):
+  group = parser.add_argument_group('Linker Test Options')
+  group.add_argument('-f', '--gtest-filter', dest='test_filter',
+                     help='googletest-style filter string.')
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+
+
+def AddJavaTestOptions(argument_group):
+  """Adds the Java test options to |option_parser|."""
+
+  argument_group.add_argument(
+      '-f', '--test-filter', dest='test_filter',
+      help=('Test filter (if not fully qualified, will run all matches).'))
+  argument_group.add_argument(
+      '-A', '--annotation', dest='annotation_str',
+      help=('Comma-separated list of annotations. Run only tests with any of '
+            'the given annotations. An annotation can be either a key or a '
+            'key-values pair. A test that has no annotation is considered '
+            '"SmallTest".'))
+  argument_group.add_argument(
+      '-E', '--exclude-annotation', dest='exclude_annotation_str',
+      help=('Comma-separated list of annotations. Exclude tests with these '
+            'annotations.'))
+  argument_group.add_argument(
+      '--screenshot', dest='screenshot_failures', action='store_true',
+      help='Capture screenshots of test failures')
+  argument_group.add_argument(
+      '--save-perf-json', action='store_true',
+      help='Saves the JSON file for each UI Perf test.')
+  argument_group.add_argument(
+      '--official-build', action='store_true', help='Run official build tests.')
+  argument_group.add_argument(
+      '--test_data', '--test-data', action='append', default=[],
+      help=('Each instance defines a directory of test data that should be '
+            'copied to the target(s) before running the tests. The argument '
+            'should be of the form <target>:<source>, <target> is relative to '
+            'the device data directory, and <source> is relative to the '
+            'chromium build directory.'))
+  argument_group.add_argument(
+      '--disable-dalvik-asserts', dest='set_asserts', action='store_false',
+      default=True, help='Removes the dalvik.vm.enableassertions property')
+
+
+
+def ProcessJavaTestOptions(args):
+  """Processes options/arguments and populates |options| with defaults."""
+
+  # TODO(jbudorick): Handle most of this function in argparse.
+  if args.annotation_str:
+    args.annotations = args.annotation_str.split(',')
+  elif args.test_filter:
+    args.annotations = []
+  else:
+    args.annotations = ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
+                        'EnormousTest', 'IntegrationTest']
+
+  if args.exclude_annotation_str:
+    args.exclude_annotations = args.exclude_annotation_str.split(',')
+  else:
+    args.exclude_annotations = []
+
+
+def AddInstrumentationTestOptions(parser):
+  """Adds Instrumentation test options to |parser|."""
+
+  parser.usage = '%(prog)s [options]'
+
+  group = parser.add_argument_group('Instrumentation Test Options')
+  AddJavaTestOptions(group)
+
+  java_or_python_group = group.add_mutually_exclusive_group()
+  java_or_python_group.add_argument(
+      '-j', '--java-only', action='store_false',
+      dest='run_python_tests', default=True, help='Run only the Java tests.')
+  java_or_python_group.add_argument(
+      '-p', '--python-only', action='store_false',
+      dest='run_java_tests', default=True,
+      help='Run only the host-driven tests.')
+
+  group.add_argument('--host-driven-root',
+                     help='Root of the host-driven tests.')
+  group.add_argument('-w', '--wait_debugger', dest='wait_for_debugger',
+                     action='store_true',
+                     help='Wait for debugger.')
+  group.add_argument('--apk-under-test', dest='apk_under_test',
+                     help=('the name of the apk under test.'))
+  group.add_argument('--test-apk', dest='test_apk', required=True,
+                     help=('The name of the apk containing the tests '
+                           '(without the .apk extension; '
+                           'e.g. "ContentShellTest").'))
+  group.add_argument('--coverage-dir',
+                     help=('Directory in which to place all generated '
+                           'EMMA coverage files.'))
+  group.add_argument('--device-flags', dest='device_flags', default='',
+                     help='The relative filepath to a file containing '
+                          'command-line flags to set on the device')
+  group.add_argument('--device-flags-file', default='',
+                     help='The relative filepath to a file containing '
+                          'command-line flags to set on the device')
+  group.add_argument('--isolate_file_path',
+                     '--isolate-file-path',
+                     dest='isolate_file_path',
+                     help='.isolate file path to override the default '
+                          'path')
+
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+  AddRemoteDeviceOptions(parser)
+
+
+def ProcessInstrumentationOptions(args):
+  """Processes options/arguments and populate |options| with defaults.
+
+  Args:
+    args: argparse.Namespace object.
+
+  Returns:
+    An InstrumentationOptions named tuple which contains all options relevant to
+    instrumentation tests.
+  """
+
+  ProcessJavaTestOptions(args)
+
+  if not args.host_driven_root:
+    args.run_python_tests = False
+
+  args.test_apk_path = os.path.join(
+      constants.GetOutDirectory(),
+      constants.SDK_BUILD_APKS_DIR,
+      '%s.apk' % args.test_apk)
+  args.test_apk_jar_path = os.path.join(
+      constants.GetOutDirectory(),
+      constants.SDK_BUILD_TEST_JAVALIB_DIR,
+      '%s.jar' %  args.test_apk)
+  args.test_support_apk_path = '%sSupport%s' % (
+      os.path.splitext(args.test_apk_path))
+
+  args.test_runner = apk_helper.GetInstrumentationName(args.test_apk_path)
+
+  # TODO(jbudorick): Get rid of InstrumentationOptions.
+  return instrumentation_test_options.InstrumentationOptions(
+      args.tool,
+      args.annotations,
+      args.exclude_annotations,
+      args.test_filter,
+      args.test_data,
+      args.save_perf_json,
+      args.screenshot_failures,
+      args.wait_for_debugger,
+      args.coverage_dir,
+      args.test_apk,
+      args.test_apk_path,
+      args.test_apk_jar_path,
+      args.test_runner,
+      args.test_support_apk_path,
+      args.device_flags,
+      args.isolate_file_path,
+      args.set_asserts
+      )
+
+
+def AddUIAutomatorTestOptions(parser):
+  """Adds UI Automator test options to |parser|."""
+
+  group = parser.add_argument_group('UIAutomator Test Options')
+  AddJavaTestOptions(group)
+  group.add_argument(
+      '--package', required=True, choices=constants.PACKAGE_INFO.keys(),
+      metavar='PACKAGE', help='Package under test.')
+  group.add_argument(
+      '--test-jar', dest='test_jar', required=True,
+      help=('The name of the dexed jar containing the tests (without the '
+            '.dex.jar extension). Alternatively, this can be a full path '
+            'to the jar.'))
+
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+
+
+def ProcessUIAutomatorOptions(args):
+  """Processes UIAutomator options/arguments.
+
+  Args:
+    args: argparse.Namespace object.
+
+  Returns:
+    A UIAutomatorOptions named tuple which contains all options relevant to
+    uiautomator tests.
+  """
+
+  ProcessJavaTestOptions(args)
+
+  if os.path.exists(args.test_jar):
+    # The dexed JAR is fully qualified, assume the info JAR lives along side.
+    args.uiautomator_jar = args.test_jar
+  else:
+    args.uiautomator_jar = os.path.join(
+        constants.GetOutDirectory(),
+        constants.SDK_BUILD_JAVALIB_DIR,
+        '%s.dex.jar' % args.test_jar)
+  args.uiautomator_info_jar = (
+      args.uiautomator_jar[:args.uiautomator_jar.find('.dex.jar')] +
+      '_java.jar')
+
+  return uiautomator_test_options.UIAutomatorOptions(
+      args.tool,
+      args.annotations,
+      args.exclude_annotations,
+      args.test_filter,
+      args.test_data,
+      args.save_perf_json,
+      args.screenshot_failures,
+      args.uiautomator_jar,
+      args.uiautomator_info_jar,
+      args.package,
+      args.set_asserts)
+
+
+def AddJUnitTestOptions(parser):
+  """Adds junit test options to |parser|."""
+
+  group = parser.add_argument_group('JUnit Test Options')
+  group.add_argument(
+      '-s', '--test-suite', dest='test_suite', required=True,
+      help=('JUnit test suite to run.'))
+  group.add_argument(
+      '-f', '--test-filter', dest='test_filter',
+      help='Filters tests googletest-style.')
+  group.add_argument(
+      '--package-filter', dest='package_filter',
+      help='Filters tests by package.')
+  group.add_argument(
+      '--runner-filter', dest='runner_filter',
+      help='Filters tests by runner class. Must be fully qualified.')
+  group.add_argument(
+      '--sdk-version', dest='sdk_version', type=int,
+      help='The Android SDK version.')
+  AddCommonOptions(parser)
+
+
+def AddMonkeyTestOptions(parser):
+  """Adds monkey test options to |parser|."""
+
+  group = parser.add_argument_group('Monkey Test Options')
+  group.add_argument(
+      '--package', required=True, choices=constants.PACKAGE_INFO.keys(),
+      metavar='PACKAGE', help='Package under test.')
+  group.add_argument(
+      '--event-count', default=10000, type=int,
+      help='Number of events to generate (default: %(default)s).')
+  group.add_argument(
+      '--category', default='',
+      help='A list of allowed categories.')
+  group.add_argument(
+      '--throttle', default=100, type=int,
+      help='Delay between events (ms) (default: %(default)s). ')
+  group.add_argument(
+      '--seed', type=int,
+      help=('Seed value for pseudo-random generator. Same seed value generates '
+            'the same sequence of events. Seed is randomized by default.'))
+  group.add_argument(
+      '--extra-args', default='',
+      help=('String of other args to pass to the command verbatim.'))
+
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+
+def ProcessMonkeyTestOptions(args):
+  """Processes all monkey test options.
+
+  Args:
+    args: argparse.Namespace object.
+
+  Returns:
+    A MonkeyOptions named tuple which contains all options relevant to
+    monkey tests.
+  """
+  # TODO(jbudorick): Handle this directly in argparse with nargs='+'
+  category = args.category
+  if category:
+    category = args.category.split(',')
+
+  # TODO(jbudorick): Get rid of MonkeyOptions.
+  return monkey_test_options.MonkeyOptions(
+      args.verbose_count,
+      args.package,
+      args.event_count,
+      category,
+      args.throttle,
+      args.seed,
+      args.extra_args)
+
+def AddUirobotTestOptions(parser):
+  """Adds uirobot test options to |option_parser|."""
+  group = parser.add_argument_group('Uirobot Test Options')
+
+  group.add_argument('--app-under-test', required=True,
+                     help='APK to run tests on.')
+  group.add_argument(
+      '--minutes', default=5, type=int,
+      help='Number of minutes to run uirobot test [default: %(default)s].')
+
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+  AddRemoteDeviceOptions(parser)
+
+def AddPerfTestOptions(parser):
+  """Adds perf test options to |parser|."""
+
+  group = parser.add_argument_group('Perf Test Options')
+
+  class SingleStepAction(argparse.Action):
+    def __call__(self, parser, namespace, values, option_string=None):
+      if values and not namespace.single_step:
+        parser.error('single step command provided, '
+                     'but --single-step not specified.')
+      elif namespace.single_step and not values:
+        parser.error('--single-step specified, '
+                     'but no single step command provided.')
+      setattr(namespace, self.dest, values)
+
+  step_group = group.add_mutually_exclusive_group(required=True)
+  # TODO(jbudorick): Revise --single-step to use argparse.REMAINDER.
+  # This requires removing "--" from client calls.
+  step_group.add_argument(
+      '--single-step', action='store_true',
+      help='Execute the given command with retries, but only print the result '
+           'for the "most successful" round.')
+  step_group.add_argument(
+      '--steps',
+      help='JSON file containing the list of commands to run.')
+  step_group.add_argument(
+      '--print-step',
+      help='The name of a previously executed perf step to print.')
+
+  group.add_argument(
+      '--output-json-list',
+      help='Write a simple list of names from --steps into the given file.')
+  group.add_argument(
+      '--collect-chartjson-data',
+      action='store_true',
+      help='Cache the chartjson output from each step for later use.')
+  group.add_argument(
+      '--output-chartjson-data',
+      default='',
+      help='Write out chartjson into the given file.')
+  group.add_argument(
+      '--flaky-steps',
+      help=('A JSON file containing steps that are flaky '
+            'and will have its exit code ignored.'))
+  group.add_argument(
+      '--no-timeout', action='store_true',
+      help=('Do not impose a timeout. Each perf step is responsible for '
+            'implementing the timeout logic.'))
+  group.add_argument(
+      '-f', '--test-filter',
+      help=('Test filter (will match against the names listed in --steps).'))
+  group.add_argument(
+      '--dry-run', action='store_true',
+      help='Just print the steps without executing.')
+  group.add_argument('single_step_command', nargs='*', action=SingleStepAction,
+                     help='If --single-step is specified, the command to run.')
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+
+
+def ProcessPerfTestOptions(args):
+  """Processes all perf test options.
+
+  Args:
+    args: argparse.Namespace object.
+
+  Returns:
+    A PerfOptions named tuple which contains all options relevant to
+    perf tests.
+  """
+  # TODO(jbudorick): Move single_step handling down into the perf tests.
+  if args.single_step:
+    args.single_step = ' '.join(args.single_step_command)
+  # TODO(jbudorick): Get rid of PerfOptions.
+  return perf_test_options.PerfOptions(
+      args.steps, args.flaky_steps, args.output_json_list,
+      args.print_step, args.no_timeout, args.test_filter,
+      args.dry_run, args.single_step, args.collect_chartjson_data,
+      args.output_chartjson_data)
+
+
+def AddPythonTestOptions(parser):
+  group = parser.add_argument_group('Python Test Options')
+  group.add_argument(
+      '-s', '--suite', dest='suite_name', metavar='SUITE_NAME',
+      choices=constants.PYTHON_UNIT_TEST_SUITES.keys(),
+      help='Name of the test suite to run.')
+  AddCommonOptions(parser)
+
+
+def _RunGTests(args, devices):
+  """Subcommand of RunTestsCommands which runs gtests."""
+  exit_code = 0
+  for suite_name in args.suite_name:
+    # TODO(jbudorick): Either deprecate multi-suite or move its handling down
+    # into the gtest code.
+    gtest_options = gtest_test_options.GTestOptions(
+        args.tool,
+        args.test_filter,
+        args.run_disabled,
+        args.test_arguments,
+        args.timeout,
+        args.isolate_file_path,
+        suite_name)
+    runner_factory, tests = gtest_setup.Setup(gtest_options, devices)
+
+    results, test_exit_code = test_dispatcher.RunTests(
+        tests, runner_factory, devices, shard=True, test_timeout=None,
+        num_retries=args.num_retries)
+
+    if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
+      exit_code = test_exit_code
+
+    report_results.LogFull(
+        results=results,
+        test_type='Unit test',
+        test_package=suite_name,
+        flakiness_server=args.flakiness_dashboard_server)
+
+    if args.json_results_file:
+      json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  if os.path.isdir(constants.ISOLATE_DEPS_DIR):
+    shutil.rmtree(constants.ISOLATE_DEPS_DIR)
+
+  return exit_code
+
+
+def _RunLinkerTests(args, devices):
+  """Subcommand of RunTestsCommands which runs linker tests."""
+  runner_factory, tests = linker_setup.Setup(args, devices)
+
+  results, exit_code = test_dispatcher.RunTests(
+      tests, runner_factory, devices, shard=True, test_timeout=60,
+      num_retries=args.num_retries)
+
+  report_results.LogFull(
+      results=results,
+      test_type='Linker test',
+      test_package='ChromiumLinkerTest')
+
+  if args.json_results_file:
+    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  return exit_code
+
+
+def _RunInstrumentationTests(args, devices):
+  """Subcommand of RunTestsCommands which runs instrumentation tests."""
+  logging.info('_RunInstrumentationTests(%s, %s)' % (str(args), str(devices)))
+
+  instrumentation_options = ProcessInstrumentationOptions(args)
+
+  if len(devices) > 1 and args.wait_for_debugger:
+    logging.warning('Debugger can not be sharded, using first available device')
+    devices = devices[:1]
+
+  results = base_test_result.TestRunResults()
+  exit_code = 0
+
+  if args.run_java_tests:
+    runner_factory, tests = instrumentation_setup.Setup(
+        instrumentation_options, devices)
+
+    test_results, exit_code = test_dispatcher.RunTests(
+        tests, runner_factory, devices, shard=True, test_timeout=None,
+        num_retries=args.num_retries)
+
+    results.AddTestRunResults(test_results)
+
+  if args.run_python_tests:
+    runner_factory, tests = host_driven_setup.InstrumentationSetup(
+        args.host_driven_root, args.official_build,
+        instrumentation_options)
+
+    if tests:
+      test_results, test_exit_code = test_dispatcher.RunTests(
+          tests, runner_factory, devices, shard=True, test_timeout=None,
+          num_retries=args.num_retries)
+
+      results.AddTestRunResults(test_results)
+
+      # Only allow exit code escalation
+      if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
+        exit_code = test_exit_code
+
+  if args.device_flags:
+    args.device_flags = os.path.join(constants.DIR_SOURCE_ROOT,
+                                     args.device_flags)
+
+  report_results.LogFull(
+      results=results,
+      test_type='Instrumentation',
+      test_package=os.path.basename(args.test_apk),
+      annotation=args.annotations,
+      flakiness_server=args.flakiness_dashboard_server)
+
+  if args.json_results_file:
+    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  return exit_code
+
+
+def _RunUIAutomatorTests(args, devices):
+  """Subcommand of RunTestsCommands which runs uiautomator tests."""
+  uiautomator_options = ProcessUIAutomatorOptions(args)
+
+  runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
+
+  results, exit_code = test_dispatcher.RunTests(
+      tests, runner_factory, devices, shard=True, test_timeout=None,
+      num_retries=args.num_retries)
+
+  report_results.LogFull(
+      results=results,
+      test_type='UIAutomator',
+      test_package=os.path.basename(args.test_jar),
+      annotation=args.annotations,
+      flakiness_server=args.flakiness_dashboard_server)
+
+  if args.json_results_file:
+    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  return exit_code
+
+
+def _RunJUnitTests(args):
+  """Subcommand of RunTestsCommand which runs junit tests."""
+  runner_factory, tests = junit_setup.Setup(args)
+  results, exit_code = junit_dispatcher.RunTests(tests, runner_factory)
+
+  report_results.LogFull(
+      results=results,
+      test_type='JUnit',
+      test_package=args.test_suite)
+
+  if args.json_results_file:
+    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  return exit_code
+
+
+def _RunMonkeyTests(args, devices):
+  """Subcommand of RunTestsCommands which runs monkey tests."""
+  monkey_options = ProcessMonkeyTestOptions(args)
+
+  runner_factory, tests = monkey_setup.Setup(monkey_options)
+
+  results, exit_code = test_dispatcher.RunTests(
+      tests, runner_factory, devices, shard=False, test_timeout=None,
+      num_retries=args.num_retries)
+
+  report_results.LogFull(
+      results=results,
+      test_type='Monkey',
+      test_package='Monkey')
+
+  if args.json_results_file:
+    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  return exit_code
+
+
+def _RunPerfTests(args):
+  """Subcommand of RunTestsCommands which runs perf tests."""
+  perf_options = ProcessPerfTestOptions(args)
+
+  # Just save a simple json with a list of test names.
+  if perf_options.output_json_list:
+    return perf_test_runner.OutputJsonList(
+        perf_options.steps, perf_options.output_json_list)
+
+  # Just print the results from a single previously executed step.
+  if perf_options.print_step:
+    return perf_test_runner.PrintTestOutput(
+        perf_options.print_step, perf_options.output_chartjson_data)
+
+  runner_factory, tests, devices = perf_setup.Setup(perf_options)
+
+  # shard=False means that each device will get the full list of tests
+  # and then each one will decide their own affinity.
+  # shard=True means each device will pop the next test available from a queue,
+  # which increases throughput but have no affinity.
+  results, _ = test_dispatcher.RunTests(
+      tests, runner_factory, devices, shard=False, test_timeout=None,
+      num_retries=args.num_retries)
+
+  report_results.LogFull(
+      results=results,
+      test_type='Perf',
+      test_package='Perf')
+
+  if args.json_results_file:
+    json_results.GenerateJsonResultsFile(results, args.json_results_file)
+
+  if perf_options.single_step:
+    return perf_test_runner.PrintTestOutput('single_step')
+
+  perf_test_runner.PrintSummary(tests)
+
+  # Always return 0 on the sharding stage. Individual tests exit_code
+  # will be returned on the print_step stage.
+  return 0
+
+
+def _RunPythonTests(args):
+  """Subcommand of RunTestsCommand which runs python unit tests."""
+  suite_vars = constants.PYTHON_UNIT_TEST_SUITES[args.suite_name]
+  suite_path = suite_vars['path']
+  suite_test_modules = suite_vars['test_modules']
+
+  sys.path = [suite_path] + sys.path
+  try:
+    suite = unittest.TestSuite()
+    suite.addTests(unittest.defaultTestLoader.loadTestsFromName(m)
+                   for m in suite_test_modules)
+    runner = unittest.TextTestRunner(verbosity=1+args.verbose_count)
+    return 0 if runner.run(suite).wasSuccessful() else 1
+  finally:
+    sys.path = sys.path[1:]
+
+
+def _GetAttachedDevices(test_device=None):
+  """Get all attached devices.
+
+  Args:
+    test_device: Name of a specific device to use.
+
+  Returns:
+    A list of attached devices.
+  """
+  attached_devices = device_utils.DeviceUtils.HealthyDevices()
+  if test_device:
+    test_device = [d for d in attached_devices if d == test_device]
+    if not test_device:
+      raise device_errors.DeviceUnreachableError(
+          'Did not find device %s among attached device. Attached devices: %s'
+          % (test_device, ', '.join(attached_devices)))
+    return test_device
+
+  else:
+    if not attached_devices:
+      raise device_errors.NoDevicesError()
+    return sorted(attached_devices)
+
+
+def RunTestsCommand(args, parser):
+  """Checks test type and dispatches to the appropriate function.
+
+  Args:
+    args: argparse.Namespace object.
+    parser: argparse.ArgumentParser object.
+
+  Returns:
+    Integer indicated exit code.
+
+  Raises:
+    Exception: Unknown command name passed in, or an exception from an
+        individual test runner.
+  """
+  command = args.command
+
+  ProcessCommonOptions(args)
+
+  if args.enable_platform_mode:
+    return RunTestsInPlatformMode(args, parser)
+
+  if command in constants.LOCAL_MACHINE_TESTS:
+    devices = []
+  else:
+    devices = _GetAttachedDevices(args.test_device)
+
+  forwarder.Forwarder.RemoveHostLog()
+  if not ports.ResetTestServerPortAllocation():
+    raise Exception('Failed to reset test server port.')
+
+  if command == 'gtest':
+    return _RunGTests(args, devices)
+  elif command == 'linker':
+    return _RunLinkerTests(args, devices)
+  elif command == 'instrumentation':
+    return _RunInstrumentationTests(args, devices)
+  elif command == 'uiautomator':
+    return _RunUIAutomatorTests(args, devices)
+  elif command == 'junit':
+    return _RunJUnitTests(args)
+  elif command == 'monkey':
+    return _RunMonkeyTests(args, devices)
+  elif command == 'perf':
+    return _RunPerfTests(args)
+  elif command == 'python':
+    return _RunPythonTests(args)
+  else:
+    raise Exception('Unknown test type.')
+
+
+_SUPPORTED_IN_PLATFORM_MODE = [
+  # TODO(jbudorick): Add support for more test types.
+  'gtest',
+  'instrumentation',
+  'uirobot',
+]
+
+
+def RunTestsInPlatformMode(args, parser):
+
+  if args.command not in _SUPPORTED_IN_PLATFORM_MODE:
+    parser.error('%s is not yet supported in platform mode' % args.command)
+
+  with environment_factory.CreateEnvironment(args, parser.error) as env:
+    with test_instance_factory.CreateTestInstance(args, parser.error) as test:
+      with test_run_factory.CreateTestRun(
+          args, env, test, parser.error) as test_run:
+        results = test_run.RunTests()
+
+        if args.environment == 'remote_device' and args.trigger:
+          return 0 # Not returning results, only triggering.
+
+        report_results.LogFull(
+            results=results,
+            test_type=test.TestType(),
+            test_package=test_run.TestPackage(),
+            annotation=getattr(args, 'annotations', None),
+            flakiness_server=getattr(args, 'flakiness_dashboard_server', None))
+
+        if args.json_results_file:
+          json_results.GenerateJsonResultsFile(
+              results, args.json_results_file)
+
+  return 0 if results.DidRunPass() else constants.ERROR_EXIT_CODE
+
+
+CommandConfigTuple = collections.namedtuple(
+    'CommandConfigTuple',
+    ['add_options_func', 'help_txt'])
+VALID_COMMANDS = {
+    'gtest': CommandConfigTuple(
+        AddGTestOptions,
+        'googletest-based C++ tests'),
+    'instrumentation': CommandConfigTuple(
+        AddInstrumentationTestOptions,
+        'InstrumentationTestCase-based Java tests'),
+    'uiautomator': CommandConfigTuple(
+        AddUIAutomatorTestOptions,
+        "Tests that run via Android's uiautomator command"),
+    'junit': CommandConfigTuple(
+        AddJUnitTestOptions,
+        'JUnit4-based Java tests'),
+    'monkey': CommandConfigTuple(
+        AddMonkeyTestOptions,
+        "Tests based on Android's monkey"),
+    'perf': CommandConfigTuple(
+        AddPerfTestOptions,
+        'Performance tests'),
+    'python': CommandConfigTuple(
+        AddPythonTestOptions,
+        'Python tests based on unittest.TestCase'),
+    'linker': CommandConfigTuple(
+        AddLinkerTestOptions,
+        'Linker tests'),
+    'uirobot': CommandConfigTuple(
+        AddUirobotTestOptions,
+        'Uirobot test'),
+}
+
+
+def DumpThreadStacks(_signal, _frame):
+  for thread in threading.enumerate():
+    reraiser_thread.LogThreadStack(thread)
+
+
+def main():
+  signal.signal(signal.SIGUSR1, DumpThreadStacks)
+
+  parser = argparse.ArgumentParser()
+  command_parsers = parser.add_subparsers(title='test types',
+                                          dest='command')
+
+  for test_type, config in sorted(VALID_COMMANDS.iteritems(),
+                                  key=lambda x: x[0]):
+    subparser = command_parsers.add_parser(
+        test_type, usage='%(prog)s [options]', help=config.help_txt)
+    config.add_options_func(subparser)
+
+  args = parser.parse_args()
+
+  try:
+    return RunTestsCommand(args, parser)
+  except base_error.BaseError as e:
+    logging.exception('Error occurred.')
+    if e.is_infra_error:
+      return constants.INFRA_EXIT_CODE
+    else:
+      return constants.ERROR_EXIT_CODE
+  except: # pylint: disable=W0702
+    logging.exception('Unrecognized error occurred.')
+    return constants.ERROR_EXIT_CODE
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/tests/multiple_proguards/AndroidManifest.xml b/build/android/tests/multiple_proguards/AndroidManifest.xml
new file mode 100644
index 0000000..1794712
--- /dev/null
+++ b/build/android/tests/multiple_proguards/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  - Copyright 2013 Google Inc.
+  -
+  - 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="dummy"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <application android:label="dummy">
+        <activity android:name="dummy.DummyActivity"
+                  android:label="dummy">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/build/android/tests/multiple_proguards/multiple_proguards.gyp b/build/android/tests/multiple_proguards/multiple_proguards.gyp
new file mode 100644
index 0000000..48a5d7b
--- /dev/null
+++ b/build/android/tests/multiple_proguards/multiple_proguards.gyp
@@ -0,0 +1,34 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'multiple_proguards_test_apk',
+      'type': 'none',
+      'variables': {
+        'app_manifest_version_name%': '<(android_app_version_name)',
+        'java_in_dir': '.',
+        'proguard_enabled': 'true',
+        'proguard_flags_paths': [
+          # Both these proguard?.flags files need to be part of the build to
+          # remove both warnings from the src/dummy/DummyActivity.java file, else the
+          # build will fail.
+          'proguard1.flags',
+          'proguard2.flags',
+        ],
+        'R_package': 'dummy',
+        'R_package_relpath': 'dummy',
+        'apk_name': 'MultipleProguards',
+        # This is a build-only test. There's nothing to install.
+        'gyp_managed_install': 0,
+        # The Java code produces warnings, so force the build to not show them.
+        'chromium_code': 0,
+      },
+      'includes': [ '../../../../build/java_apk.gypi' ],
+    },
+  ],
+}
diff --git a/build/android/tests/multiple_proguards/proguard1.flags b/build/android/tests/multiple_proguards/proguard1.flags
new file mode 100644
index 0000000..95a814c
--- /dev/null
+++ b/build/android/tests/multiple_proguards/proguard1.flags
@@ -0,0 +1 @@
+-dontwarn sun.misc.Unsafe
diff --git a/build/android/tests/multiple_proguards/proguard2.flags b/build/android/tests/multiple_proguards/proguard2.flags
new file mode 100644
index 0000000..ceac62b
--- /dev/null
+++ b/build/android/tests/multiple_proguards/proguard2.flags
@@ -0,0 +1 @@
+-dontwarn sun.reflect.Reflection
diff --git a/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java b/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java
new file mode 100644
index 0000000..e138acc
--- /dev/null
+++ b/build/android/tests/multiple_proguards/src/dummy/DummyActivity.java
@@ -0,0 +1,26 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package dummy;
+
+import android.app.Activity;
+
+/**
+ * Dummy activity to build apk.
+ *
+ * This class is created to ensure that proguard will produce two separate warnings.
+ */
+public class DummyActivity extends Activity {
+    private static void doBadThings1() {
+        try {
+            sun.misc.Unsafe.getUnsafe();
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
+    private static void doBadThings2() {
+        sun.reflect.Reflection.getCallerClass(2);
+    }
+}
diff --git a/build/android/tests/multiple_proguards/src/dummy/NativeLibraries.java b/build/android/tests/multiple_proguards/src/dummy/NativeLibraries.java
new file mode 100644
index 0000000..2f7db71
--- /dev/null
+++ b/build/android/tests/multiple_proguards/src/dummy/NativeLibraries.java
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.library_loader;
+
+/**
+ * This is a complete dummy, required because base now requires a version of
+ * NativeLibraries to build, but doesn't include it in its jar file.
+ */
+public class NativeLibraries {
+    public static boolean sUseLinker = false;
+    public static boolean sUseLibraryInZipFile = false;
+    public static boolean sEnableLinkerTests = false;
+    static final String[] LIBRARIES = {};
+    static String sVersionNumber = "";
+}
diff --git a/build/android/tests/symbolize/Makefile b/build/android/tests/symbolize/Makefile
new file mode 100644
index 0000000..5178a04
--- /dev/null
+++ b/build/android/tests/symbolize/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+TOOLCHAIN=../../../../third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
+CXX=$(TOOLCHAIN)g++
+
+lib%.so: %.cc
+	$(CXX) -nostdlib -g -fPIC -shared $< -o $@
+
+all: liba.so libb.so
diff --git a/build/android/tests/symbolize/a.cc b/build/android/tests/symbolize/a.cc
new file mode 100644
index 0000000..f0c7ca4
--- /dev/null
+++ b/build/android/tests/symbolize/a.cc
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class A {
+ public:
+  A();
+  void Foo(int i);
+  void Bar(const char* c);
+};
+
+A::A() {}
+void A::Foo(int i) {}
+void A::Bar(const char* c) {}
diff --git a/build/android/tests/symbolize/b.cc b/build/android/tests/symbolize/b.cc
new file mode 100644
index 0000000..db87520
--- /dev/null
+++ b/build/android/tests/symbolize/b.cc
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class B {
+ public:
+  B();
+  void Baz(float f);
+  void Qux(double d);
+};
+
+B::B() {}
+void B::Baz(float f) {}
+void B::Qux(double d) {}
diff --git a/build/android/tests/symbolize/liba.so b/build/android/tests/symbolize/liba.so
new file mode 100644
index 0000000..79cb739
--- /dev/null
+++ b/build/android/tests/symbolize/liba.so
Binary files differ
diff --git a/build/android/tests/symbolize/libb.so b/build/android/tests/symbolize/libb.so
new file mode 100644
index 0000000..7cf01d4
--- /dev/null
+++ b/build/android/tests/symbolize/libb.so
Binary files differ
diff --git a/build/android/tombstones.py b/build/android/tombstones.py
new file mode 100755
index 0000000..c83a584
--- /dev/null
+++ b/build/android/tombstones.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Find the most recent tombstone file(s) on all connected devices
+# and prints their stacks.
+#
+# Assumes tombstone file was created with current symbols.
+
+import datetime
+import itertools
+import logging
+import multiprocessing
+import os
+import re
+import subprocess
+import sys
+import optparse
+
+from pylib.device import adb_wrapper
+from pylib.device import device_errors
+from pylib.device import device_utils
+from pylib.utils import run_tests_helper
+
+
+_TZ_UTC = {'TZ': 'UTC'}
+
+def _ListTombstones(device):
+  """List the tombstone files on the device.
+
+  Args:
+    device: An instance of DeviceUtils.
+
+  Yields:
+    Tuples of (tombstone filename, date time of file on device).
+  """
+  try:
+    lines = device.RunShellCommand(
+        ['ls', '-a', '-l', '/data/tombstones'],
+        as_root=True, check_return=True, env=_TZ_UTC, timeout=60)
+    for line in lines:
+      if 'tombstone' in line and not 'No such file or directory' in line:
+        details = line.split()
+        t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
+                                       '%Y-%m-%d %H:%M')
+        yield details[-1], t
+  except device_errors.CommandFailedError:
+    logging.exception('Could not retrieve tombstones.')
+
+
+def _GetDeviceDateTime(device):
+  """Determine the date time on the device.
+
+  Args:
+    device: An instance of DeviceUtils.
+
+  Returns:
+    A datetime instance.
+  """
+  device_now_string = device.RunShellCommand(
+      ['date'], check_return=True, env=_TZ_UTC)
+  return datetime.datetime.strptime(
+      device_now_string[0], '%a %b %d %H:%M:%S %Z %Y')
+
+
+def _GetTombstoneData(device, tombstone_file):
+  """Retrieve the tombstone data from the device
+
+  Args:
+    device: An instance of DeviceUtils.
+    tombstone_file: the tombstone to retrieve
+
+  Returns:
+    A list of lines
+  """
+  return device.ReadFile(
+      '/data/tombstones/' + tombstone_file, as_root=True).splitlines()
+
+
+def _EraseTombstone(device, tombstone_file):
+  """Deletes a tombstone from the device.
+
+  Args:
+    device: An instance of DeviceUtils.
+    tombstone_file: the tombstone to delete.
+  """
+  return device.RunShellCommand(
+      ['rm', '/data/tombstones/' + tombstone_file],
+      as_root=True, check_return=True)
+
+
+def _DeviceAbiToArch(device_abi):
+  # The order of this list is significant to find the more specific match (e.g.,
+  # arm64) before the less specific (e.g., arm).
+  arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips']
+  for arch in arches:
+    if arch in device_abi:
+      return arch
+  raise RuntimeError('Unknown device ABI: %s' % device_abi)
+
+def _ResolveSymbols(tombstone_data, include_stack, device_abi):
+  """Run the stack tool for given tombstone input.
+
+  Args:
+    tombstone_data: a list of strings of tombstone data.
+    include_stack: boolean whether to include stack data in output.
+    device_abi: the default ABI of the device which generated the tombstone.
+
+  Yields:
+    A string for each line of resolved stack output.
+  """
+  # Check if the tombstone data has an ABI listed, if so use this in preference
+  # to the device's default ABI.
+  for line in tombstone_data:
+    found_abi = re.search('ABI: \'(.+?)\'', line)
+    if found_abi:
+      device_abi = found_abi.group(1)
+  arch = _DeviceAbiToArch(device_abi)
+  if not arch:
+    return
+
+  stack_tool = os.path.join(os.path.dirname(__file__), '..', '..',
+                            'third_party', 'android_platform', 'development',
+                            'scripts', 'stack')
+  proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE,
+                          stdout=subprocess.PIPE)
+  output = proc.communicate(input='\n'.join(tombstone_data))[0]
+  for line in output.split('\n'):
+    if not include_stack and 'Stack Data:' in line:
+      break
+    yield line
+
+
+def _ResolveTombstone(tombstone):
+  lines = []
+  lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) +
+            ', about this long ago: ' +
+            (str(tombstone['device_now'] - tombstone['time']) +
+            ' Device: ' + tombstone['serial'])]
+  logging.info('\n'.join(lines))
+  logging.info('Resolving...')
+  lines += _ResolveSymbols(tombstone['data'], tombstone['stack'],
+                           tombstone['device_abi'])
+  return lines
+
+
+def _ResolveTombstones(jobs, tombstones):
+  """Resolve a list of tombstones.
+
+  Args:
+    jobs: the number of jobs to use with multiprocess.
+    tombstones: a list of tombstones.
+  """
+  if not tombstones:
+    logging.warning('No tombstones to resolve.')
+    return
+  if len(tombstones) == 1:
+    data = _ResolveTombstone(tombstones[0])
+  else:
+    pool = multiprocessing.Pool(processes=jobs)
+    data = pool.map(_ResolveTombstone, tombstones)
+  for d in data:
+    logging.info(d)
+
+
+def _GetTombstonesForDevice(device, options):
+  """Returns a list of tombstones on a given device.
+
+  Args:
+    device: An instance of DeviceUtils.
+    options: command line arguments from OptParse
+  """
+  ret = []
+  all_tombstones = list(_ListTombstones(device))
+  if not all_tombstones:
+    logging.warning('No tombstones.')
+    return ret
+
+  # Sort the tombstones in date order, descending
+  all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1]))
+
+  # Only resolve the most recent unless --all-tombstones given.
+  tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]]
+
+  device_now = _GetDeviceDateTime(device)
+  try:
+    for tombstone_file, tombstone_time in tombstones:
+      ret += [{'serial': str(device),
+               'device_abi': device.product_cpu_abi,
+               'device_now': device_now,
+               'time': tombstone_time,
+               'file': tombstone_file,
+               'stack': options.stack,
+               'data': _GetTombstoneData(device, tombstone_file)}]
+  except device_errors.CommandFailedError:
+    for line in device.RunShellCommand(
+        ['ls', '-a', '-l', '/data/tombstones'],
+        as_root=True, check_return=True, env=_TZ_UTC, timeout=60):
+      logging.info('%s: %s', str(device), line)
+    raise
+
+  # Erase all the tombstones if desired.
+  if options.wipe_tombstones:
+    for tombstone_file, _ in all_tombstones:
+      _EraseTombstone(device, tombstone_file)
+
+  return ret
+
+
+def main():
+  custom_handler = logging.StreamHandler(sys.stdout)
+  custom_handler.setFormatter(run_tests_helper.CustomFormatter())
+  logging.getLogger().addHandler(custom_handler)
+  logging.getLogger().setLevel(logging.INFO)
+
+  parser = optparse.OptionParser()
+  parser.add_option('--device',
+                    help='The serial number of the device. If not specified '
+                         'will use all devices.')
+  parser.add_option('-a', '--all-tombstones', action='store_true',
+                    help="""Resolve symbols for all tombstones, rather than just
+                         the most recent""")
+  parser.add_option('-s', '--stack', action='store_true',
+                    help='Also include symbols for stack data')
+  parser.add_option('-w', '--wipe-tombstones', action='store_true',
+                    help='Erase all tombstones from device after processing')
+  parser.add_option('-j', '--jobs', type='int',
+                    default=4,
+                    help='Number of jobs to use when processing multiple '
+                         'crash stacks.')
+  options, _ = parser.parse_args()
+
+  if options.device:
+    devices = [device_utils.DeviceUtils(options.device)]
+  else:
+    devices = device_utils.DeviceUtils.HealthyDevices()
+
+  # This must be done serially because strptime can hit a race condition if
+  # used for the first time in a multithreaded environment.
+  # http://bugs.python.org/issue7980
+  tombstones = []
+  for device in devices:
+    tombstones += _GetTombstonesForDevice(device, options)
+
+  _ResolveTombstones(options.jobs, tombstones)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/update_verification.py b/build/android/update_verification.py
new file mode 100755
index 0000000..dada794
--- /dev/null
+++ b/build/android/update_verification.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Runs semi-automated update testing on a non-rooted device.
+
+This script will help verify that app data is preserved during an update.
+To use this script first run it with the create_app_data option.
+
+./update_verification.py create_app_data --old-apk <path> --app-data <path>
+
+The script will then install the old apk, prompt you to create some app data
+(bookmarks, etc.), and then save the app data in the path you gave it.
+
+Next, once you have some app data saved, run this script with the test_update
+option.
+
+./update_verification.py test_update --old-apk <path> --new-apk <path>
+--app-data <path>
+
+This will install the old apk, load the saved app data, install the new apk,
+and ask the user to verify that all of the app data was preserved.
+"""
+
+import argparse
+import logging
+import os
+import sys
+import time
+
+from pylib import constants
+from pylib.device import device_utils
+from pylib.utils import apk_helper
+from pylib.utils import run_tests_helper
+
+def CreateAppData(device, old_apk, app_data):
+  device.Install(old_apk)
+  raw_input('Set the application state. Once ready, press enter and '
+            'select "Backup my data" on the device.')
+  package_name = apk_helper.GetPackageName(old_apk)
+  device.adb.Backup(app_data, packages=[package_name])
+  logging.critical('Application data saved to %s' % app_data)
+
+def TestUpdate(device, old_apk, new_apk, app_data):
+  device.Install(old_apk)
+  device.adb.Restore(app_data)
+  # Restore command is not synchronous
+  raw_input('Select "Restore my data" on the device. Then press enter to '
+            'continue.')
+
+  package_name = apk_helper.GetPackageName(new_apk)
+  device_path = device.GetApplicationPath(package_name)
+  if not device_path:
+    raise Exception('Expected package %s to already be installed. '
+                    'Package name might have changed!' % package_name)
+
+  logging.info('Verifying that %s can be overinstalled.', new_apk)
+  device.adb.Install(new_apk, reinstall=True)
+  logging.critical('Successfully updated to the new apk. Please verify that '
+                   'the application data is preserved.')
+
+def main():
+  parser = argparse.ArgumentParser(
+      description="Script to do semi-automated upgrade testing.")
+  parser.add_argument('-v', '--verbose', action='count',
+                      help='Print verbose log information.')
+  command_parsers = parser.add_subparsers(dest='command')
+
+  subparser = command_parsers.add_parser('create_app_data')
+  subparser.add_argument('--old-apk', required=True,
+                      help='Path to apk to update from.')
+  subparser.add_argument('--app-data', required=True,
+                      help='Path to where the app data backup should be '
+                           'saved to.')
+
+  subparser = command_parsers.add_parser('test_update')
+  subparser.add_argument('--old-apk', required=True,
+                      help='Path to apk to update from.')
+  subparser.add_argument('--new-apk', required=True,
+                      help='Path to apk to update to.')
+  subparser.add_argument('--app-data', required=True,
+                      help='Path to where the app data backup is saved.')
+
+  args = parser.parse_args()
+  run_tests_helper.SetLogLevel(args.verbose)
+
+  devices = device_utils.DeviceUtils.HealthyDevices()
+  device = devices[0]
+  logging.info('Using device %s for testing.' % str(device))
+
+  if args.command == 'create_app_data':
+    CreateAppData(device, args.old_apk, args.app_data)
+  elif args.command == 'test_update':
+    TestUpdate(device,  args.old_apk, args.new_apk, args.app_data)
+  else:
+    raise Exception('Unknown test command: %s' % args.command)
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/android/write_ordered_libraries.gypi b/build/android/write_ordered_libraries.gypi
new file mode 100644
index 0000000..1b52e71
--- /dev/null
+++ b/build/android/write_ordered_libraries.gypi
@@ -0,0 +1,43 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to provide a rule that
+# generates a json file with the list of dependent libraries needed for a given
+# shared library or executable.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'actions': [
+#      'variables': {
+#        'input_libraries': 'shared library or executable to process',
+#        'ordered_libraries_file': 'file to generate'
+#      },
+#      'includes': [ '../../build/android/write_ordered_libraries.gypi' ],
+#    ],
+#  },
+#
+
+{
+  'action_name': 'ordered_libraries_<(_target_name)<(subtarget)',
+  'message': 'Writing dependency ordered libraries for <(_target_name)',
+  'variables': {
+    'input_libraries%': [],
+    'subtarget%': '',
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/gyp/write_ordered_libraries.py',
+    '<@(input_libraries)',
+  ],
+  'outputs': [
+    '<(ordered_libraries_file)',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/write_ordered_libraries.py',
+    '--input-libraries=<(input_libraries)',
+    '--libraries-dir=<(SHARED_LIB_DIR),<(PRODUCT_DIR)',
+    '--readelf=<(android_readelf)',
+    '--output=<(ordered_libraries_file)',
+  ],
+}
diff --git a/build/android_sdk_extras.json b/build/android_sdk_extras.json
new file mode 100644
index 0000000..4562726
--- /dev/null
+++ b/build/android_sdk_extras.json
@@ -0,0 +1,8 @@
+[
+  {
+    "dir_name": "google",
+    "version": "21.0.0",
+    "zip": "google_google_play_services_21.0.0.zip",
+    "package": "google_play_services"
+  }
+]
diff --git a/build/apk_fake_jar.gypi b/build/apk_fake_jar.gypi
new file mode 100644
index 0000000..128b84c
--- /dev/null
+++ b/build/apk_fake_jar.gypi
@@ -0,0 +1,15 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to build Java in a consistent manner.
+
+{
+  'all_dependent_settings': {
+    'variables': {
+      'input_jars_paths': ['>(apk_output_jar_path)'],
+      'library_dexed_jars_paths': ['>(apk_output_jar_path)'],
+    },
+  },
+}
diff --git a/build/apk_test.gypi b/build/apk_test.gypi
new file mode 100644
index 0000000..3a66e3b
--- /dev/null
+++ b/build/apk_test.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to build APK based test suites.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'test_suite_name_apk',
+#   'type': 'none',
+#   'variables': {
+#     'test_suite_name': 'test_suite_name',  # string
+#     'input_jars_paths': ['/path/to/test_suite.jar', ... ],  # list
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+
+{
+  'dependencies': [
+    '<(DEPTH)/base/base.gyp:base_java',
+    '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
+    '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk',
+    '<(DEPTH)/testing/android/appurify_support.gyp:appurify_support_java',
+    '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
+  ],
+  'conditions': [
+     ['OS == "android"', {
+       'variables': {
+         # These are used to configure java_apk.gypi included below.
+         'apk_name': '<(test_suite_name)',
+         'intermediate_dir': '<(PRODUCT_DIR)/<(test_suite_name)_apk',
+         'final_apk_path': '<(intermediate_dir)/<(test_suite_name)-debug.apk',
+         'java_in_dir': '<(DEPTH)/testing/android/native_test/java',
+         'native_lib_target': 'lib<(test_suite_name)',
+         # TODO(yfriedman, cjhopman): Support managed installs for gtests.
+         'gyp_managed_install': 0,
+       },
+       'includes': [ 'java_apk.gypi' ],
+     }],  # 'OS == "android"
+  ],  # conditions
+}
diff --git a/build/apply_locales.py b/build/apply_locales.py
new file mode 100755
index 0000000..6af7280
--- /dev/null
+++ b/build/apply_locales.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# 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.
+
+# TODO: remove this script when GYP has for loops
+
+import sys
+import optparse
+
+def main(argv):
+
+  parser = optparse.OptionParser()
+  usage = 'usage: %s [options ...] format_string locale_list'
+  parser.set_usage(usage.replace('%s', '%prog'))
+  parser.add_option('-d', dest='dash_to_underscore', action="store_true",
+                    default=False,
+                    help='map "en-US" to "en" and "-" to "_" in locales')
+
+  (options, arglist) = parser.parse_args(argv)
+
+  if len(arglist) < 3:
+    print 'ERROR: need string and list of locales'
+    return 1
+
+  str_template = arglist[1]
+  locales = arglist[2:]
+
+  results = []
+  for locale in locales:
+    # For Cocoa to find the locale at runtime, it needs to use '_' instead
+    # of '-' (http://crbug.com/20441).  Also, 'en-US' should be represented
+    # simply as 'en' (http://crbug.com/19165, http://crbug.com/25578).
+    if options.dash_to_underscore:
+      if locale == 'en-US':
+        locale = 'en'
+      locale = locale.replace('-', '_')
+    results.append(str_template.replace('ZZLOCALE', locale))
+
+  # Quote each element so filename spaces don't mess up GYP's attempt to parse
+  # it into a list.
+  print ' '.join(["'%s'" % x for x in results])
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/branding_value.sh b/build/branding_value.sh
new file mode 100755
index 0000000..9fcb550
--- /dev/null
+++ b/build/branding_value.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# Copyright (c) 2008 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a wrapper for fetching values from the BRANDING files.  Pass the
+# value of GYP's branding variable followed by the key you want and the right
+# file is checked.
+#
+#  branding_value.sh Chromium COPYRIGHT
+#  branding_value.sh Chromium PRODUCT_FULLNAME
+#
+
+set -e
+
+if [ $# -ne 2 ] ;  then
+  echo "error: expect two arguments, branding and key" >&2
+  exit 1
+fi
+
+BUILD_BRANDING=$1
+THE_KEY=$2
+
+pushd $(dirname "${0}") > /dev/null
+BUILD_DIR=$(pwd)
+popd > /dev/null
+
+TOP="${BUILD_DIR}/.."
+
+case ${BUILD_BRANDING} in
+  Chromium)
+    BRANDING_FILE="${TOP}/chrome/app/theme/chromium/BRANDING"
+    ;;
+  Chrome)
+    BRANDING_FILE="${TOP}/chrome/app/theme/google_chrome/BRANDING"
+    ;;
+  *)
+    echo "error: unknown branding: ${BUILD_BRANDING}" >&2
+    exit 1
+    ;;
+esac
+
+BRANDING_VALUE=$(sed -n -e "s/^${THE_KEY}=\(.*\)\$/\1/p" "${BRANDING_FILE}")
+
+if [ -z "${BRANDING_VALUE}" ] ; then
+  echo "error: failed to find key '${THE_KEY}'" >&2
+  exit 1
+fi
+
+echo "${BRANDING_VALUE}"
diff --git a/build/build-ctags.sh b/build/build-ctags.sh
new file mode 100755
index 0000000..61e017e
--- /dev/null
+++ b/build/build-ctags.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if [[ a"`ctags --version | head -1 | grep \"^Exuberant Ctags\"`" == "a" ]]; then
+  cat <<EOF
+  You must be using Exuberant Ctags, not just standard GNU ctags. If you are on
+  Debian or a related flavor of Linux, you may want to try running
+  apt-get install exuberant-ctags.
+EOF
+  exit
+fi
+
+CHROME_SRC_DIR="$PWD"
+
+fail() {
+  echo "Failed to create ctags for $1"
+  exit 1
+}
+
+ctags_cmd() {
+  echo "ctags --languages=C++ $1 --exclude=.git -R -f .tmp_tags"
+}
+
+build_dir() {
+  local extraexcludes=""
+  if [[ a"$1" == "a--extra-excludes" ]]; then
+    extraexcludes="--exclude=third_party --exclude=build --exclude=out"
+    shift
+  fi
+
+  cd "$CHROME_SRC_DIR/$1" || fail $1
+  # Redirect error messages so they aren't seen because they are almost always
+  # errors about components that you just happen to have not built (NaCl, for
+  # example).
+  $(ctags_cmd "$extraexcludes") 2> /dev/null || fail $1
+  mv -f .tmp_tags tags
+}
+
+# We always build the top level but leave all submodules as optional.
+build_dir --extra-excludes "" "top level"
+
+# Build any other directies that are listed on the command line.
+for dir in $@; do
+  build_dir "$1"
+  shift
+done
diff --git a/build/build_config.h b/build/build_config.h
new file mode 100644
index 0000000..d8c3db6
--- /dev/null
+++ b/build/build_config.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file adds defines about the platform we're currently building on.
+//  Operating System:
+//    OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) /
+//    OS_NACL (NACL_SFI or NACL_NONSFI) / OS_NACL_SFI / OS_NACL_NONSFI
+//  Compiler:
+//    COMPILER_MSVC / COMPILER_GCC
+//  Processor:
+//    ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64)
+//    ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
+
+#ifndef BUILD_BUILD_CONFIG_H_
+#define BUILD_BUILD_CONFIG_H_
+
+// A set of macros to use for platform detection.
+#if defined(__native_client__)
+// __native_client__ must be first, so that other OS_ defines are not set.
+#define OS_NACL 1
+// OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI.
+// PNaCl toolchain defines __native_client_nonsfi__ macro in Non-SFI build
+// mode, while it does not in SFI build mode.
+#if defined(__native_client_nonsfi__)
+#define OS_NACL_NONSFI
+#else
+#define OS_NACL_SFI
+#endif
+#elif defined(ANDROID)
+#define OS_ANDROID 1
+#elif defined(__APPLE__)
+// only include TargetConditions after testing ANDROID as some android builds
+// on mac don't have this header available and it's not needed unless the target
+// is really mac/ios.
+#include <TargetConditionals.h>
+#define OS_MACOSX 1
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#define OS_IOS 1
+#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#elif defined(__linux__)
+#define OS_LINUX 1
+// include a system header to pull in features.h for glibc/uclibc macros.
+#include <unistd.h>
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+// we really are using glibc, not uClibc pretending to be glibc
+#define LIBC_GLIBC 1
+#endif
+#elif defined(_WIN32)
+#define OS_WIN 1
+#define TOOLKIT_VIEWS 1
+#elif defined(__FreeBSD__)
+#define OS_FREEBSD 1
+#elif defined(__OpenBSD__)
+#define OS_OPENBSD 1
+#elif defined(__sun)
+#define OS_SOLARIS 1
+#elif defined(__QNXNTO__)
+#define OS_QNX 1
+#else
+#error Please add support for your platform in build/build_config.h
+#endif
+
+#if defined(USE_OPENSSL_CERTS) && defined(USE_NSS_CERTS)
+#error Cannot use both OpenSSL and NSS for certificates
+#endif
+
+// For access to standard BSD features, use OS_BSD instead of a
+// more specific macro.
+#if defined(OS_FREEBSD) || defined(OS_OPENBSD)
+#define OS_BSD 1
+#endif
+
+// For access to standard POSIXish features, use OS_POSIX instead of a
+// more specific macro.
+#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) ||     \
+    defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) ||  \
+    defined(OS_NACL) || defined(OS_QNX)
+#define OS_POSIX 1
+#endif
+
+// Use tcmalloc
+#if (defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)) && \
+    !defined(NO_TCMALLOC)
+#define USE_TCMALLOC 1
+#endif
+
+// Compiler detection.
+#if defined(__GNUC__)
+#define COMPILER_GCC 1
+#elif defined(_MSC_VER)
+#define COMPILER_MSVC 1
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+//   or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86_64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__ARMEL__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARMEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__aarch64__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARM64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__pnacl__)
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__MIPSEL__)
+#if defined(__LP64__)
+#define ARCH_CPU_MIPS64_FAMILY 1
+#define ARCH_CPU_MIPS64EL 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#else
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPSEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#endif
+#else
+#error Please add support for your architecture in build/build_config.h
+#endif
+
+// Type detection for wchar_t.
+#if defined(OS_WIN)
+#define WCHAR_T_IS_UTF16
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+    defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+    defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to
+// compile in this mode (in particular, Chrome doesn't). This is intended for
+// other projects using base who manage their own dependencies and make sure
+// short wchar works for them.
+#define WCHAR_T_IS_UTF16
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+#if defined(OS_ANDROID)
+// The compiler thinks std::string::const_iterator and "const char*" are
+// equivalent types.
+#define STD_STRING_ITERATOR_IS_CHAR_POINTER
+// The compiler thinks base::string16::const_iterator and "char16*" are
+// equivalent types.
+#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER
+#endif
+
+#endif  // BUILD_BUILD_CONFIG_H_
diff --git a/build/check_return_value.py b/build/check_return_value.py
new file mode 100755
index 0000000..c659d1e
--- /dev/null
+++ b/build/check_return_value.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 program wraps an arbitrary command and prints "1" if the command ran
+successfully."""
+
+import os
+import subprocess
+import sys
+
+devnull = open(os.devnull, 'wb')
+if not subprocess.call(sys.argv[1:], stdout=devnull, stderr=devnull):
+  print 1
+else:
+  print 0
diff --git a/build/chrome_settings.gypi b/build/chrome_settings.gypi
new file mode 100644
index 0000000..e9c7535
--- /dev/null
+++ b/build/chrome_settings.gypi
@@ -0,0 +1,30 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file contains settings for ../chrome/chrome.gyp that other gyp files
+# also use.
+{
+  'variables': {
+    # TODO: remove this helper when we have loops in GYP
+    'apply_locales_cmd': ['python', '<(DEPTH)/build/apply_locales.py'],
+
+    'conditions': [
+      ['OS=="mac"', {
+        'conditions': [
+          ['branding=="Chrome"', {
+            'mac_bundle_id': 'com.google.Chrome',
+            'mac_creator': 'rimZ',
+            # The policy .grd file also needs the bundle id.
+            'grit_defines': ['-D', 'mac_bundle_id=com.google.Chrome'],
+          }, {  # else: branding!="Chrome"
+            'mac_bundle_id': 'org.chromium.Chromium',
+            'mac_creator': 'Cr24',
+            # The policy .grd file also needs the bundle id.
+            'grit_defines': ['-D', 'mac_bundle_id=org.chromium.Chromium'],
+          }],  # branding
+        ],  # conditions
+      }],  # OS=="mac"
+    ],  # conditions
+  },  # variables
+}
diff --git a/build/common.croc b/build/common.croc
new file mode 100644
index 0000000..fde7a8b
--- /dev/null
+++ b/build/common.croc
@@ -0,0 +1,127 @@
+# -*- python -*-
+# Crocodile config file for Chromium - settings common to all platforms
+#
+# This should be speicified before the platform-specific config, for example:
+#       croc -c chrome_common.croc -c linux/chrome_linux.croc
+
+{
+  # List of root directories, applied in order
+  'roots' : [
+    # Sub-paths we specifically care about and want to call out
+    {
+      'root' : '_/src',
+      'altname' : 'CHROMIUM',
+    },
+  ],
+
+  # List of rules, applied in order
+  # Note that any 'include':0 rules here will be overridden by the 'include':1
+  # rules in the platform-specific configs.
+  'rules' : [
+    # Don't scan for executable lines in uninstrumented C++ header files
+    {
+      'regexp' : '.*\\.(h|hpp)$',
+      'add_if_missing' : 0,
+    },
+
+    # Groups
+    {
+      'regexp' : '',
+      'group' : 'source',
+    },
+    {
+      'regexp' : '.*_(test|unittest|uitest|browsertest)\\.',
+      'group' : 'test',
+    },
+
+    # Languages
+    {
+      'regexp' : '.*\\.(c|h)$',
+      'language' : 'C',
+    },
+    {
+      'regexp' : '.*\\.(cc|cpp|hpp)$',
+      'language' : 'C++',
+    },
+
+    # Files/paths to include.  Specify these before the excludes, since rules
+    # are in order.
+    {
+      'regexp' : '^CHROMIUM/(base|media|net|printing|remoting|chrome|content|webkit/glue|native_client)/',
+      'include' : 1,
+    },
+    # Don't include subversion or mercurial SCM dirs
+    {
+      'regexp' : '.*/(\\.svn|\\.hg)/',
+      'include' : 0,
+    },
+    # Don't include output dirs
+    {
+      'regexp' : '.*/(Debug|Release|out|xcodebuild)/',
+      'include' : 0,
+    },
+    # Don't include third-party source
+    {
+      'regexp' : '.*/third_party/',
+      'include' : 0,
+    },
+    # We don't run the V8 test suite, so we don't care about V8 coverage.
+    {
+      'regexp' : '.*/v8/',
+      'include' : 0,
+    },
+  ],
+
+  # Paths to add source from
+  'add_files' : [
+    'CHROMIUM'
+  ],
+
+  # Statistics to print
+  'print_stats' : [
+    {
+      'stat' : 'files_executable',
+      'format' : '*RESULT FilesKnown: files_executable= %d files',
+    },
+    {
+      'stat' : 'files_instrumented',
+      'format' : '*RESULT FilesInstrumented: files_instrumented= %d files',
+    },
+    {
+      'stat' : '100.0 * files_instrumented / files_executable',
+      'format' : '*RESULT FilesInstrumentedPercent: files_instrumented_percent= %g percent',
+    },
+    {
+      'stat' : 'lines_executable',
+      'format' : '*RESULT LinesKnown: lines_known= %d lines',
+    },
+    {
+      'stat' : 'lines_instrumented',
+      'format' : '*RESULT LinesInstrumented: lines_instrumented= %d lines',
+    },
+    {
+      'stat' : 'lines_covered',
+      'format' : '*RESULT LinesCoveredSource: lines_covered_source= %d lines',
+      'group' : 'source',
+    },
+    {
+      'stat' : 'lines_covered',
+      'format' : '*RESULT LinesCoveredTest: lines_covered_test= %d lines',
+      'group' : 'test',
+    },
+    {
+      'stat' : '100.0 * lines_covered / lines_executable',
+      'format' : '*RESULT PercentCovered: percent_covered= %g percent',
+    },
+    {
+      'stat' : '100.0 * lines_covered / lines_executable',
+      'format' : '*RESULT PercentCoveredSource: percent_covered_source= %g percent',
+      'group' : 'source',
+    },
+    {
+      'stat' : '100.0 * lines_covered / lines_executable',
+      'format' : '*RESULT PercentCoveredTest: percent_covered_test= %g percent',
+      'group' : 'test',
+    },
+  ],
+}
diff --git a/build/common.gypi b/build/common.gypi
new file mode 100644
index 0000000..bd38fc0
--- /dev/null
+++ b/build/common.gypi
@@ -0,0 +1,6196 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# IMPORTANT:
+# Please don't directly include this file if you are building via gyp_chromium,
+# since gyp_chromium is automatically forcing its inclusion.
+{
+  # Variables expected to be overriden on the GYP command line (-D) or by
+  # ~/.gyp/include.gypi.
+  'variables': {
+    # Putting a variables dict inside another variables dict looks kind of
+    # weird.  This is done so that 'host_arch', 'chromeos', etc are defined as
+    # variables within the outer variables dict here.  This is necessary
+    # to get these variables defined for the conditions within this variables
+    # dict that operate on these variables.
+    'variables': {
+      'variables': {
+        'variables': {
+          'variables': {
+            # Whether we're building a ChromeOS build.
+            'chromeos%': 0,
+
+            # Whether we're building the cast (chromecast) shell
+            'chromecast%': 0,
+
+            # Whether or not we are using the Aura windowing framework.
+            'use_aura%': 0,
+
+            # Whether or not we are building the Ash shell.
+            'use_ash%': 0,
+
+            # Whether or not we are using CRAS, the ChromeOS Audio Server.
+            'use_cras%': 0,
+
+            # Use a raw surface abstraction.
+            'use_ozone%': 0,
+
+            # Configure the build for small devices. See crbug.com/318413
+            'embedded%': 0,
+
+            'conditions': [
+              # Compute the architecture that we're building on.
+              ['OS=="win" or OS=="ios"', {
+                'host_arch%': 'ia32',
+              }, {
+                'host_arch%': '<!pymod_do_main(detect_host_arch)',
+              }],
+            ],
+          },
+          # Copy conditionally-set variables out one scope.
+          'chromeos%': '<(chromeos)',
+          'chromecast%': '<(chromecast)',
+          'use_aura%': '<(use_aura)',
+          'use_ash%': '<(use_ash)',
+          'use_cras%': '<(use_cras)',
+          'use_ozone%': '<(use_ozone)',
+          'embedded%': '<(embedded)',
+          'host_arch%': '<(host_arch)',
+
+          # Whether we are using Views Toolkit
+          'toolkit_views%': 0,
+
+          # Use the PCI lib to collect GPU information.
+          'use_libpci%': 1,
+
+          # Use OpenSSL instead of NSS as the underlying SSL and crypto
+          # implementation. Certificate verification will in most cases be
+          # handled by the OS. If OpenSSL's struct X509 is used to represent
+          # certificates, use_openssl_certs must be set.
+          'use_openssl%': 0,
+
+          # Use OpenSSL for representing certificates. When targeting Android,
+          # the platform certificate library is used for certificate
+          # verification. On other targets, this flag also enables OpenSSL for
+          # certificate verification, but this configuration is unsupported.
+          'use_openssl_certs%': 0,
+
+          # Disable viewport meta tag by default.
+          'enable_viewport%': 0,
+
+          # Enable HiDPI support.
+          'enable_hidpi%': 0,
+
+          # Override buildtype to select the desired build flavor.
+          # Dev - everyday build for development/testing
+          # Official - release build (generally implies additional processing)
+          # TODO(mmoss) Once 'buildtype' is fully supported (e.g. Windows gyp
+          # conversion is done), some of the things which are now controlled by
+          # 'branding', such as symbol generation, will need to be refactored
+          # based on 'buildtype' (i.e. we don't care about saving symbols for
+          # non-Official # builds).
+          'buildtype%': 'Dev',
+
+          # Override branding to select the desired branding flavor.
+          'branding%': 'Chromium',
+
+          'conditions': [
+            # ChromeOS and Windows use Aura and Ash.
+            ['chromeos==1 or OS=="win" or OS=="linux"', {
+              'use_ash%': 1,
+              'use_aura%': 1,
+            }],
+
+            ['chromecast==1 and OS!="android"', {
+              'embedded%': 1,
+              'use_ozone%': 1,
+            }],
+
+            # Ozone uses Aura.
+            ['use_ozone==1', {
+              'use_aura%': 1,
+            }],
+
+            # Whether we're a traditional desktop unix.
+            ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris") and chromeos==0', {
+              'desktop_linux%': 1,
+            }, {
+              'desktop_linux%': 0,
+            }],
+
+            # Embedded implies ozone.
+            ['embedded==1', {
+              'use_ozone%': 1,
+            }],
+
+            ['OS=="android"', {
+              'target_arch%': 'arm',
+            }, {
+              # Default architecture we're building for is the architecture we're
+              # building on, and possibly sub-architecture (for iOS builds).
+              'target_arch%': '<(host_arch)',
+            }],
+          ],
+        },
+        # Copy conditionally-set variables out one scope.
+        'chromeos%': '<(chromeos)',
+        'chromecast%': '<(chromecast)',
+        'desktop_linux%': '<(desktop_linux)',
+        'use_aura%': '<(use_aura)',
+        'use_ash%': '<(use_ash)',
+        'use_cras%': '<(use_cras)',
+        'use_ozone%': '<(use_ozone)',
+        'embedded%': '<(embedded)',
+        'use_libpci%': '<(use_libpci)',
+        'use_openssl%': '<(use_openssl)',
+        'use_openssl_certs%': '<(use_openssl_certs)',
+        'enable_viewport%': '<(enable_viewport)',
+        'enable_hidpi%': '<(enable_hidpi)',
+        'buildtype%': '<(buildtype)',
+        'branding%': '<(branding)',
+        'branding_path_component%': '<(branding)',
+        'host_arch%': '<(host_arch)',
+        'target_arch%': '<(target_arch)',
+
+        'target_subarch%': '',
+
+        # The channel to build on Android: stable, beta, dev, canary, or
+        # default. "default" should be used on non-official builds.
+        'android_channel%': 'default',
+
+        # Set ARM architecture version.
+        'arm_version%': 7,
+
+        # Use aurax11 for clipboard implementation. This is true on linux_aura.
+        'use_clipboard_aurax11%': 0,
+
+        # goma settings.
+        # 1 to use goma.
+        # If no gomadir is set, it uses the default gomadir.
+        'use_goma%': 0,
+        'gomadir%': '',
+
+        # The system root for cross-compiles. Default: none.
+        'sysroot%': '',
+        'use_sysroot%': 0,
+        'chroot_cmd%': '',
+
+        # The system libdir used for this ABI.
+        'system_libdir%': 'lib',
+
+        # Default MIPS arch variant. This is set in the conditions block
+        # below for MIPS targets.
+        'mips_arch_variant%': '',
+
+        # MIPS DSP ASE revision. Possible values are:
+        #   0: unavailable
+        #   1: revision 1
+        #   2: revision 2
+        'mips_dsp_rev%': 0,
+
+        'conditions': [
+          ['branding == "Chrome"', {
+            'branding_path_component%': 'google_chrome',
+          }],
+
+          ['branding == "Chromium"', {
+            'branding_path_component%': 'chromium',
+          }],
+
+          # Ash needs Aura.
+          ['use_aura==0', {
+            'use_ash%': 0,
+          }],
+
+          # Set default value of toolkit_views based on OS.
+          ['OS=="mac" or OS=="win" or chromeos==1 or use_aura==1', {
+            'toolkit_views%': 1,
+          }, {
+            'toolkit_views%': 0,
+          }],
+
+          # Embedded builds use aura without ash or views.
+          ['embedded==1', {
+            'use_aura%': 1,
+            'use_ash%': 0,
+            'toolkit_views%': 0,
+          }],
+
+          # Enable HiDPI on Mac OS, Chrome OS, Windows and Linux.
+          ['OS=="mac" or chromeos==1 or OS=="win" or OS=="linux"', {
+            'enable_hidpi%': 1,
+          }],
+
+          # Enable the OpenSSL backend on Mac OS and Windows.
+          ['OS=="mac" or OS=="win"', {
+            'use_openssl%': 1,
+          }],
+
+          # Enable App Launcher everywhere but mobile.
+          ['OS!="ios" and OS!="android"', {
+            'enable_app_list%': 1,
+          }, {
+            'enable_app_list%': 0,
+          }],
+
+          ['use_aura==1 or (OS!="win" and OS!="mac" and OS!="ios" and OS!="android")', {
+            'use_default_render_theme%': 1,
+          }, {
+            'use_default_render_theme%': 0,
+          }],
+
+          ['use_ozone==1', {
+            'use_ozone_evdev%': 1,
+          }, {
+            'use_ozone_evdev%': 0,
+          }],
+
+          # Set default gomadir.
+          ['OS=="win"', {
+            'gomadir': 'c:\\goma\\goma-win',
+          }, {
+            'gomadir': '<!(/bin/echo -n ${HOME}/goma)',
+          }],
+
+          # Set the default "target_subarch" on iOS. Valid values are "arm32",
+          # "arm64" and "both" (meaning a fat binary).
+          ['OS=="ios"', {
+            'target_subarch%': 'arm64',
+          }],
+
+          # Set arch variants for MIPS platforms.
+          ['target_arch=="mips64el"', {
+            'conditions': [
+              ['OS=="android"', {
+                'mips_arch_variant%': 'r6',
+              }, {
+                'mips_arch_variant%': 'r2',
+              }],
+            ],
+          }],
+
+          ['target_arch=="mipsel"', {
+            'mips_arch_variant%': 'r1',
+          }],
+        ],
+      },
+
+      # Copy conditionally-set variables out one scope.
+      'chromeos%': '<(chromeos)',
+      'chromecast%': '<(chromecast)',
+      'host_arch%': '<(host_arch)',
+      'target_arch%': '<(target_arch)',
+      'target_subarch%': '<(target_subarch)',
+      'mips_arch_variant%': '<(mips_arch_variant)',
+      'mips_dsp_rev%': '<(mips_dsp_rev)',
+      'toolkit_views%': '<(toolkit_views)',
+      'desktop_linux%': '<(desktop_linux)',
+      'use_aura%': '<(use_aura)',
+      'use_ash%': '<(use_ash)',
+      'use_cras%': '<(use_cras)',
+      'use_libpci%': '<(use_libpci)',
+      'use_ozone%': '<(use_ozone)',
+      'use_ozone_evdev%': '<(use_ozone_evdev)',
+      'use_clipboard_aurax11%': '<(use_clipboard_aurax11)',
+      'embedded%': '<(embedded)',
+      'use_openssl%': '<(use_openssl)',
+      'use_openssl_certs%': '<(use_openssl_certs)',
+      'enable_viewport%': '<(enable_viewport)',
+      'enable_hidpi%': '<(enable_hidpi)',
+      'android_channel%': '<(android_channel)',
+      'use_goma%': '<(use_goma)',
+      'gomadir%': '<(gomadir)',
+      'enable_app_list%': '<(enable_app_list)',
+      'use_default_render_theme%': '<(use_default_render_theme)',
+      'buildtype%': '<(buildtype)',
+      'branding%': '<(branding)',
+      'branding_path_component%': '<(branding_path_component)',
+      'arm_version%': '<(arm_version)',
+      'sysroot%': '<(sysroot)',
+      'chroot_cmd%': '<(chroot_cmd)',
+      'system_libdir%': '<(system_libdir)',
+
+      # Set to 1 to enable fast builds. Set to 2 for even faster builds
+      # (it disables debug info for fastest compilation - only for use
+      # on compile-only bots).
+      'fastbuild%': 0,
+
+      # Set to 1 to not store any build metadata, e.g. ifdef out all __DATE__
+      # and __TIME__. Set to 0 to reenable the use of these macros in the code
+      # base. See http://crbug.com/314403.
+      'dont_embed_build_metadata%': 1,
+
+      # Set to 1 to force Visual C++ to use legacy debug information format /Z7.
+      # This is useful for parallel compilation tools which can't support /Zi.
+      # Only used on Windows.
+      'win_z7%' : 0,
+
+      # Set to 1 to enable dcheck in Release build.
+      'dcheck_always_on%': 0,
+
+      # Set to 1 to make a build that disables unshipped tracing events.
+      # Note: this setting is ignored if buildtype=="Official".
+      'tracing_like_official_build%': 0,
+
+      # Disable image loader component extension by default.
+      'image_loader_extension%': 0,
+
+      # Set NEON compilation flags.
+      'arm_neon%': 1,
+
+      # Detect NEON support at run-time.
+      'arm_neon_optional%': 0,
+
+      # Use libjpeg-turbo as the JPEG codec used by Chromium.
+      'use_libjpeg_turbo%': 1,
+
+      # Use system libjpeg. Note that the system's libjepg will be used even if
+      # use_libjpeg_turbo is set.
+      'use_system_libjpeg%': 0,
+
+      # By default, component is set to static_library and it can be overriden
+      # by the GYP command line or by ~/.gyp/include.gypi.
+      'component%': 'static_library',
+
+      # /analyze is off by default on Windows because it is very slow and noisy.
+      # Enable with GYP_DEFINES=win_analyze=1
+      'win_analyze%': 0,
+
+      # Set to select the Title Case versions of strings in GRD files.
+      'use_titlecase_in_grd%': 0,
+
+      # Use translations provided by volunteers at launchpad.net.  This
+      # currently only works on Linux.
+      'use_third_party_translations%': 0,
+
+      # Remoting compilation is enabled by default. Set to 0 to disable.
+      'remoting%': 1,
+
+      # Configuration policy is enabled by default. Set to 0 to disable.
+      'configuration_policy%': 1,
+
+      # Variable safe_browsing is used to control the build time configuration
+      # for safe browsing feature. Safe browsing can be compiled in 3 different
+      # levels: 0 disables it, 1 enables it fully, and 2 enables only UI and
+      # reporting features without enabling phishing and malware detection. This
+      # is useful to integrate a third party phishing/malware detection to
+      # existing safe browsing logic.
+      'safe_browsing%': 1,
+
+      # Web speech is enabled by default. Set to 0 to disable.
+      'enable_web_speech%': 1,
+
+      # Notifications are compiled in by default. Set to 0 to disable.
+      'notifications%' : 1,
+
+      # Use dsymutil to generate real .dSYM files on Mac. The default is 0 for
+      # regular builds and 1 for ASan builds.
+      'mac_want_real_dsym%': 'default',
+
+      # If this is set, the clang plugins used on the buildbot will be used.
+      # Run tools/clang/scripts/update.sh to make sure they are compiled.
+      # This causes 'clang_chrome_plugins_flags' to be set.
+      # Has no effect if 'clang' is not set as well.
+      'clang_use_chrome_plugins%': 1,
+
+      # Enable building with ASAN (Clang's -fsanitize=address option).
+      # -fsanitize=address only works with clang, but asan=1 implies clang=1
+      # See https://sites.google.com/a/chromium.org/dev/developers/testing/addresssanitizer
+      'asan%': 0,
+      'asan_blacklist%': '<(PRODUCT_DIR)/../../tools/memory/asan/blacklist.txt',
+      # Enable coverage gathering instrumentation in sanitizer tools. This flag
+      # also controls coverage granularity (1 for function-level coverage, 2
+      # for block-level coverage).
+      'sanitizer_coverage%': 0,
+      # Deprecated, only works if |sanitizer_coverage| isn't set.
+      # TODO(glider): remove this flag.
+      'asan_coverage%': 0,
+      # Enable intra-object-overflow detection in ASan (experimental).
+      'asan_field_padding%': 0,
+
+      # Enable Chromium overrides of the default configurations for various
+      # dynamic tools (like ASan).
+      'use_sanitizer_options%': 0,
+
+      # Enable building with SyzyAsan.
+      # See https://code.google.com/p/sawbuck/wiki/SyzyASanHowTo
+      'syzyasan%': 0,
+
+      # Enable crash reporting via Kasko.
+      'kasko%': 0,
+
+      # Enable building with LSan (Clang's -fsanitize=leak option).
+      # -fsanitize=leak only works with clang, but lsan=1 implies clang=1
+      # See https://sites.google.com/a/chromium.org/dev/developers/testing/leaksanitizer
+      'lsan%': 0,
+
+      # Enable building with TSan (Clang's -fsanitize=thread option).
+      # -fsanitize=thread only works with clang, but tsan=1 implies clang=1
+      # See http://clang.llvm.org/docs/ThreadSanitizer.html
+      'tsan%': 0,
+      'tsan_blacklist%': '<(PRODUCT_DIR)/../../tools/memory/tsan_v2/ignores.txt',
+
+      # Enable building with MSan (Clang's -fsanitize=memory option).
+      # MemorySanitizer only works with clang, but msan=1 implies clang=1
+      # See http://clang.llvm.org/docs/MemorySanitizer.html
+      'msan%': 0,
+      'msan_blacklist%': '<(PRODUCT_DIR)/../../tools/msan/blacklist.txt',
+      # Track where uninitialized memory originates from. From fastest to
+      # slowest: 0 - no tracking, 1 - track only the initial allocation site, 2
+      # - track the chain of stores leading from allocation site to use site.
+      'msan_track_origins%': 2,
+
+      # Enable building with UBSan (Clang's -fsanitize=undefined option).
+      # -fsanitize=undefined only works with clang, but ubsan=1 implies clang=1
+      # See http://clang.llvm.org/docs/UsersManual.html
+      'ubsan%': 0,
+      'ubsan_blacklist%': '<(PRODUCT_DIR)/../../tools/ubsan/blacklist.txt',
+
+      # Enable building with UBsan's vptr (Clang's -fsanitize=vptr option).
+      # -fsanitize=vptr only works with clang, but ubsan_vptr=1 implies clang=1
+      'ubsan_vptr%': 0,
+
+      # Use dynamic libraries instrumented by one of the sanitizers
+      # instead of the standard system libraries. Set this flag to build the
+      # libraries from source.
+      'use_instrumented_libraries%': 0,
+
+      # Use dynamic libraries instrumented by one of the sanitizers
+      # instead of the standard system libraries. Set this flag to download
+      # prebuilt binaries from GCS.
+      'use_prebuilt_instrumented_libraries%': 0,
+
+      # Use libc++ (third_party/libc++ and third_party/libc++abi) instead of
+      # stdlibc++ as standard library. This is intended to use for instrumented
+      # builds.
+      'use_custom_libcxx%': 0,
+
+      # Use system libc++ instead of the default C++ library, usually libstdc++.
+      # This is intended for iOS builds only.
+      'use_system_libcxx%': 0,
+
+      # Use a modified version of Clang to intercept allocated types and sizes
+      # for allocated objects. clang_type_profiler=1 implies clang=1.
+      # See http://dev.chromium.org/developers/deep-memory-profiler/cpp-object-type-identifier
+      # TODO(dmikurube): Support mac.  See http://crbug.com/123758#c11
+      'clang_type_profiler%': 0,
+
+      # Set to true to instrument the code with function call logger.
+      # See src/third_party/cygprofile/cyg-profile.cc for details.
+      'order_profiling%': 0,
+
+      # Use the provided profiled order file to link Chrome image with it.
+      # This makes Chrome faster by better using CPU cache when executing code.
+      # This is known as PGO (profile guided optimization).
+      # See https://sites.google.com/a/google.com/chrome-msk/dev/boot-speed-up-effort
+      'order_text_section%' : "",
+
+      # Set to 1 compile with -fPIC cflag on linux. This is a must for shared
+      # libraries on linux x86-64 and arm, plus ASLR.
+      'linux_fpic%': 1,
+
+      # Whether one-click signin is enabled or not.
+      'enable_one_click_signin%': 0,
+
+      # Whether to back up data before sync.
+      'enable_pre_sync_backup%': 0,
+
+      # Enable Chrome browser extensions
+      'enable_extensions%': 1,
+
+      # Enable Google Now.
+      'enable_google_now%': 1,
+
+      # Enable basic printing support and UI.
+      'enable_basic_printing%': 1,
+
+      # Enable printing with print preview. It does not imply
+      # enable_basic_printing. It's possible to build Chrome with preview only.
+      'enable_print_preview%': 1,
+
+      # Set the version of CLD.
+      #   0: Don't specify the version. This option is for the Finch testing.
+      #   1: Use only CLD1.
+      #   2: Use only CLD2.
+      'cld_version%': 2,
+
+      # For CLD2, the size of the tables that should be included in the build
+      # Only evaluated if cld_version == 2 or if building the CLD2 dynamic data
+      # tool explicitly.
+      # See third_party/cld_2/cld_2.gyp for more information.
+      #   0: Small tables, lower accuracy
+      #   2: Large tables, high accuracy
+      'cld2_table_size%': 2,
+
+      # Enable spell checker.
+      'enable_spellcheck%': 1,
+
+      # Webrtc compilation is enabled by default. Set to 0 to disable.
+      'enable_webrtc%': 1,
+
+      # Media router support is enabled by default. Set to 0 to disable.
+      'enable_media_router%': 1,
+
+      # Enables use of the session service, which is enabled by default.
+      # Support for disabling depends on the platform.
+      'enable_session_service%': 1,
+
+      # Enables theme support, which is enabled by default.  Support for
+      # disabling depends on the platform.
+      'enable_themes%': 1,
+
+      # Enables autofill dialog and associated features; disabled by default.
+      'enable_autofill_dialog%' : 0,
+
+      # Defaults Wallet integration in Autofill dialog to use production
+      # servers. Unofficial builds won't have the proper API keys.
+      'enable_prod_wallet_service%': 0,
+
+      # Enables support for background apps.
+      'enable_background%': 1,
+
+      # Enable the task manager by default.
+      'enable_task_manager%': 1,
+
+      # Enables used resource whitelist generation; disabled by default.
+      'enable_resource_whitelist_generation%': 0,
+
+      # Enable FILE support by default.
+      'disable_file_support%': 0,
+
+      # Enable FTP support by default.
+      'disable_ftp_support%': 0,
+
+      # Use native android functions in place of ICU.  Not supported by most
+      # components.
+      'use_icu_alternatives_on_android%': 0,
+
+      # Use of precompiled headers on Windows.
+      #
+      # This variable may be explicitly set to 1 (enabled) or 0
+      # (disabled) in ~/.gyp/include.gypi or via the GYP command line.
+      # This setting will override the default.
+      #
+      # See
+      # http://code.google.com/p/chromium/wiki/WindowsPrecompiledHeaders
+      # for details.
+      'chromium_win_pch%': 0,
+
+      # Clang stuff.
+      'make_clang_dir%': 'third_party/llvm-build/Release+Asserts',
+      # Set this to true when building with Clang.
+      # See http://code.google.com/p/chromium/wiki/Clang for details.
+      # If this is set, clang is used as both host and target compiler in
+      # cross-compile builds.
+      'clang%': 0,
+
+      # Use experimental lld linker instead of the platform's default linker.
+      'use_lld%': 0,
+
+      # Enable plugin installation by default.
+      'enable_plugin_installation%': 1,
+
+      # Specifies whether to use canvas_skia.cc in place of platform
+      # specific implementations of gfx::Canvas. Affects text drawing in the
+      # Chrome UI.
+      # TODO(asvitkine): Enable this on all platforms and delete this flag.
+      #                  http://crbug.com/105550
+      'use_canvas_skia%': 0,
+
+      # Set to "tsan", "memcheck", or "drmemory" to configure the build to work
+      # with one of those tools.
+      'build_for_tool%': '',
+
+      # If no directory is specified then a temporary directory will be used.
+      'test_isolation_outdir%': '',
+
+      'wix_path%': '<(DEPTH)/third_party/wix',
+
+      # Supervised users are enabled by default.
+      'enable_supervised_users%': 1,
+
+      # Platform sends memory pressure signals natively.
+      'native_memory_pressure_signals%': 0,
+
+      'spdy_proxy_auth_property%' : '',
+      'spdy_proxy_auth_value%' : '',
+      'enable_mdns%' : 0,
+      'enable_service_discovery%': 0,
+      'enable_wifi_bootstrapping%': 0,
+      'enable_hangout_services_extension%': 0,
+
+       # Enable the Syzygy optimization step.
+      'syzygy_optimize%': 0,
+
+      # Enable hole punching for the protected video.
+      'video_hole%': 0,
+
+      # Automatically select platforms under ozone. Turn this off to
+      # build only explicitly selected platforms.
+      'ozone_auto_platforms%': 1,
+
+      # If this is set clang is used as host compiler, but not as target
+      # compiler. Always do this by default.
+      'host_clang%': 1,
+
+      # Variables to control Link-Time Optimization (LTO).
+      # On Android, the variable use_lto enables LTO on code compiled with -Os,
+      # and use_lto_o2 enables LTO on code compiled with -O2. On other
+      # platforms, use_lto enables LTO in all translation units, and use_lto_o2
+      # has no effect.
+      #
+      # On Linux and Android, when using LLVM LTO, the script
+      # build/download_gold_plugin.py must be run to download a linker plugin.
+      # On Mac, LLVM needs to be built from scratch using
+      # tools/clang/scripts/update.py and the absolute path to
+      # third_party/llvm-build/Release+Asserts/lib must be added to
+      # $DYLD_LIBRARY_PATH to pick up the right version of the linker plugin.
+      #
+      # On Android, the variables must *not* be enabled at the same time.
+      # In this case LTO would 'merge' the optimization flags at link-time
+      # which would lead to all code be optimized with -O2. See crbug.com/407544
+      'use_lto%': 0,
+      'use_lto_o2%': 0,
+
+      # Allowed level of identical code folding in the gold linker.
+      'gold_icf_level%': 'safe',
+
+      # Libxkbcommon usage.
+      'use_xkbcommon%': 0,
+
+      # Control Flow Integrity for virtual calls.
+      # See http://clang.llvm.org/docs/ControlFlowIntegrity.html
+      'cfi_vptr%': 0,
+
+      # Control Flow Integrity for casts.
+      # See http://clang.llvm.org/docs/ControlFlowIntegrity.html
+      'cfi_derived_cast%': 0,
+      'cfi_unrelated_cast%': 0,
+
+      'cfi_blacklist%': '<(PRODUCT_DIR)/../../tools/cfi/blacklist.txt',
+
+      # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
+      'mac_views_browser%': 0,
+
+      # By default, use ICU data file (icudtl.dat).
+      'icu_use_data_file_flag%': 1,
+
+      # Turn on JNI generation optimizations by default.
+      'optimize_jni_generation%': 1,
+
+      'conditions': [
+        # A flag for POSIX platforms
+        ['OS=="win"', {
+          'os_posix%': 0,
+        }, {
+          'os_posix%': 1,
+        }],
+
+        # A flag for BSD platforms
+        ['OS=="freebsd" or OS=="openbsd"', {
+          'os_bsd%': 1,
+        }, {
+          'os_bsd%': 0,
+        }],
+
+        # NSS usage.
+        ['(OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris")', {
+          'use_nss_certs%': 1,
+        }, {
+          'use_nss_certs%': 0,
+        }],
+
+        # libudev usage.  This currently only affects the content layer.
+        ['OS=="linux" and embedded==0', {
+          'use_udev%': 1,
+        }, {
+          'use_udev%': 0,
+        }],
+
+        # Flags to use X11 on non-Mac POSIX platforms.
+        ['OS=="win" or OS=="mac" or OS=="ios" or OS=="android" or use_ozone==1', {
+          'use_x11%': 0,
+        }, {
+          'use_x11%': 1,
+        }],
+
+        # Flags to use glib.
+        ['OS=="win" or OS=="mac" or OS=="ios" or OS=="android" or use_ozone==1', {
+          'use_glib%': 0,
+        }, {
+          'use_glib%': 1,
+        }],
+
+        # Flags to use pango and cairo.
+        ['OS=="win" or OS=="mac" or OS=="ios" or OS=="android" or embedded==1', {
+          'use_pango%': 0,
+          'use_cairo%': 0,
+        }, {
+          'use_pango%': 1,
+          'use_cairo%': 1,
+        }],
+
+        # DBus usage.
+        ['OS=="linux" and embedded==0', {
+          'use_dbus%': 1,
+        }, {
+          'use_dbus%': 0,
+        }],
+
+        # We always use skia text rendering in Aura on Windows, since GDI
+        # doesn't agree with our BackingStore.
+        # TODO(beng): remove once skia text rendering is on by default.
+        ['use_aura==1 and OS=="win"', {
+          'enable_skia_text%': 1,
+        }],
+
+        # A flag to enable or disable our compile-time dependency
+        # on gnome-keyring. If that dependency is disabled, no gnome-keyring
+        # support will be available. This option is useful
+        # for Linux distributions and for Aura.
+        ['OS!="linux" or chromeos==1', {
+          'use_gnome_keyring%': 0,
+        }, {
+          'use_gnome_keyring%': 1,
+        }],
+
+        ['OS=="mac" or OS=="ios"', {
+          # Mac and iOS want Title Case strings
+          'use_titlecase_in_grd%': 1,
+        }],
+
+        # Enable loader extensions on Chrome OS.
+        ['chromeos==1', {
+          'image_loader_extension%': 1,
+        }, {
+          'image_loader_extension%': 0,
+        }],
+
+        ['OS=="win" or OS=="mac" or (OS=="linux" and chromeos==0)', {
+          'enable_one_click_signin%': 1,
+          'enable_pre_sync_backup%': 1,
+        }],
+
+        ['OS=="android"', {
+          'enable_extensions%': 0,
+          'enable_google_now%': 0,
+          'cld_version%': 1,
+          'enable_spellcheck%': 0,
+          'enable_themes%': 0,
+          'remoting%': 0,
+          'arm_neon%': 0,
+          'arm_neon_optional%': 1,
+          'native_memory_pressure_signals%': 1,
+          'enable_basic_printing%': 1,
+          'enable_print_preview%': 0,
+          'enable_task_manager%':0,
+          'video_hole%': 1,
+        }],
+
+        # Android OS includes support for proprietary codecs regardless of
+        # building Chromium or Google Chrome. We also ship Google Chrome and
+        # Chromecast with proprietary codecs.
+        ['OS=="android" or branding=="Chrome" or chromecast==1', {
+          'proprietary_codecs%': 1,
+        }, {
+          'proprietary_codecs%': 0,
+        }],
+
+        ['OS=="mac" or OS=="ios"', {
+          'native_memory_pressure_signals%': 1,
+        }],
+
+        # Enable autofill dialog when not on iOS.
+        ['OS!="ios"', {
+          'enable_autofill_dialog%': 1,
+
+          'conditions': [
+            ['buildtype=="Official"', {
+              'enable_prod_wallet_service%': 1,
+            }],
+          ]
+        }],
+
+        ['OS=="android"', {
+          'enable_webrtc%': 1,
+        }],
+
+        ['OS=="ios"', {
+          'disable_ftp_support%': 1,
+          'enable_extensions%': 0,
+          'enable_google_now%': 0,
+          'cld_version%': 2,
+          'cld2_table_size%': 0,
+          'enable_basic_printing%': 0,
+          'enable_print_preview%': 0,
+          'enable_session_service%': 0,
+          'enable_spellcheck%': 0,
+          'enable_themes%': 0,
+          'enable_webrtc%': 0,
+          'notifications%': 0,
+          'remoting%': 0,
+          'safe_browsing%': 0,
+          'enable_supervised_users%': 0,
+          'enable_task_manager%': 0,
+          'use_system_libcxx%': 1,
+        }],
+
+        # Use GPU accelerated cross process image transport by default
+        # on linux builds with the Aura window manager
+        ['use_aura==1 and OS=="linux"', {
+          'ui_compositor_image_transport%': 1,
+        }, {
+          'ui_compositor_image_transport%': 0,
+        }],
+
+        # Turn precompiled headers on by default.
+        ['OS=="win" and buildtype!="Official"', {
+          'chromium_win_pch%': 1
+        }],
+
+        ['chromeos==1 or OS=="android" or OS=="ios" or desktop_linux==1', {
+          'enable_plugin_installation%': 0,
+        }, {
+          'enable_plugin_installation%': 1,
+        }],
+
+        # Whether PPAPI is enabled.
+        ['OS=="android" or OS=="ios" or embedded==1', {
+          'enable_plugins%': 0,
+        }, {
+          'enable_plugins%': 1,
+        }],
+
+        # linux_use_bundled_gold: whether to use the gold linker binary checked
+        # into third_party/binutils.  Force this off via GYP_DEFINES when you
+        # are using a custom toolchain and need to control -B in ldflags.
+        # Do not use 32-bit gold on 32-bit hosts as it runs out address space
+        # for component=static_library builds.
+        ['(OS=="linux" or OS=="android") and (target_arch=="x64" or target_arch=="arm")', {
+          'linux_use_bundled_gold%': 1,
+        }, {
+          'linux_use_bundled_gold%': 0,
+        }],
+
+        # linux_use_bundled_binutils: whether to use the binary binutils
+        # checked into third_party/binutils.  These are not multi-arch so cannot
+        # be used except on x86 and x86-64 (the only two architectures which
+        # are currently checke in).  Force this off via GYP_DEFINES when you
+        # are using a custom toolchain and need to control -B in cflags.
+        ['OS=="linux" and (target_arch=="x64")', {
+          'linux_use_bundled_binutils%': 1,
+        }, {
+          'linux_use_bundled_binutils%': 0,
+        }],
+
+        # linux_use_gold_flags: whether to use build flags that rely on gold.
+        # On by default for x64 Linux.
+        ['OS=="linux" and target_arch=="x64"', {
+          'linux_use_gold_flags%': 1,
+        }, {
+          'linux_use_gold_flags%': 0,
+        }],
+
+        # linux_use_debug_fission: whether to use split DWARF debug info
+        # files. This can reduce link time significantly, but is incompatible
+        # with some utilities such as icecc and ccache. Requires gold and
+        # gcc >= 4.8 or clang.
+        # http://gcc.gnu.org/wiki/DebugFission
+        ['OS=="linux" and target_arch=="x64"', {
+          'linux_use_debug_fission%': 1,
+        }, {
+          'linux_use_debug_fission%': 0,
+        }],
+
+        ['OS=="android" or OS=="ios"', {
+          'enable_captive_portal_detection%': 0,
+          'enable_media_router%': 0,
+        }, {
+          'enable_captive_portal_detection%': 1,
+          'enable_media_router%': 1,
+        }],
+
+        # Enable Skia UI text drawing incrementally on different platforms.
+        # http://crbug.com/105550
+        #
+        # On Aura, this allows per-tile painting to be used in the browser
+        # compositor.
+        ['OS!="android" and OS!="ios"', {
+          'use_canvas_skia%': 1,
+        }],
+
+        ['chromeos==1', {
+          'enable_basic_printing%': 0,
+          'enable_print_preview%': 1,
+        }],
+
+        # Do not enable the Settings App on ChromeOS.
+        ['enable_app_list==1 and chromeos==0', {
+          'enable_settings_app%': 1,
+        }, {
+          'enable_settings_app%': 0,
+        }],
+
+        ['OS=="linux" and target_arch=="arm" and chromeos==0', {
+          # Set some defaults for arm/linux chrome builds
+          'use_allocator%': 'none',
+          # sysroot needs to be an absolute path otherwise it generates
+          # incorrect results when passed to pkg-config
+          'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_arm-sysroot',
+        }], # OS=="linux" and target_arch=="arm" and chromeos==0
+
+        ['OS=="linux" and ((branding=="Chrome" and buildtype=="Official" and chromeos==0) or use_sysroot==1)' , {
+          'conditions': [
+            ['target_arch=="x64"', {
+              'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_amd64-sysroot',
+            }],
+            ['target_arch=="ia32"', {
+              'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_i386-sysroot',
+            }],
+        ],
+        }], # OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0
+
+        ['OS=="linux" and target_arch=="mipsel"', {
+          'sysroot%': '<!(cd <(DEPTH) && pwd -P)/mipsel-sysroot/sysroot',
+          'CXX%': '<!(cd <(DEPTH) && pwd -P)/mipsel-sysroot/bin/mipsel-linux-gnu-gcc',
+        }],
+
+        # Whether tests targets should be run, archived or just have the
+        # dependencies verified. All the tests targets have the '_run' suffix,
+        # e.g. base_unittests_run runs the target base_unittests. The test
+        # target always calls tools/swarming_client/isolate.py. See the script's
+        # --help for more information. Meant to be overriden with GYP_DEFINES.
+        # TODO(maruel): Remove the conditions as more configurations are
+        # supported.
+        ['OS!="ios" and OS!="android" and chromeos==0', {
+          'test_isolation_mode%': 'check',
+        }, {
+          'test_isolation_mode%': 'noop',
+        }],
+        # Whether Android build uses OpenMAX DL FFT.
+        ['OS=="android" and ((target_arch=="arm" and arm_version >= 7) or target_arch=="ia32" or target_arch=="x64" or target_arch=="arm64" or target_arch=="mipsel")', {
+          # Currently only supported on Android ARMv7+, ARM64, ia32, x64 and mipsel.
+          # When enabled, this will also enable WebAudio support on
+          # Android for these architectures.  Default is enabled.  Whether
+          # WebAudio is actually available depends on runtime settings
+          # and flags.
+          'use_openmax_dl_fft%': 1,
+        }, {
+          'use_openmax_dl_fft%': 0,
+        }],
+        ['OS=="win" or OS=="linux"', {
+            'enable_mdns%' : 1,
+        }],
+
+        # Turns on compiler optimizations in V8 in Debug build, except
+        # on android_clang, where we're hitting a weird linker error.
+        # TODO(dpranke): http://crbug.com/266155 .
+        ['OS=="android"', {
+          'v8_optimized_debug%': 1,
+        }, {
+          'v8_optimized_debug%': 2,
+        }],
+
+        # Disable various features by default on embedded.
+        ['embedded==1', {
+          'remoting%': 0,
+          'enable_basic_printing%': 0,
+          'enable_print_preview%': 0,
+        }],
+
+        ['OS=="win" or OS=="mac"', {
+          'enable_wifi_bootstrapping%' : 1,
+        }],
+
+        # Path to sas.dll, which provides the SendSAS function.
+        # http://msdn.microsoft.com/en-us/library/windows/desktop/dd979761(v=vs.85).aspx
+        ['target_arch=="x64"', {
+          'sas_dll_path%': '<(DEPTH)/third_party/platformsdk_win7/files/redist/amd64',
+        }, {
+          'sas_dll_path%': '<(DEPTH)/third_party/platformsdk_win7/files/redist/x86',
+        }],
+      ],
+
+      # Setting this to '0' will cause V8's startup snapshot to be
+      # embedded in the binary instead of being a external files.
+      'v8_use_external_startup_data%': 1,
+
+      # Set this to 1 to enable use of concatenated impulse responses
+      # for the HRTF panner in WebAudio.
+      'use_concatenated_impulse_responses': 1,
+
+      # You can set the variable 'use_official_google_api_keys' to 1
+      # to use the Google-internal file containing official API keys
+      # for Google Chrome even in a developer build.  Setting this
+      # variable explicitly to 1 will cause your build to fail if the
+      # internal file is missing.
+      #
+      # The variable is documented here, but not handled in this file;
+      # see //google_apis/determine_use_official_keys.gypi for the
+      # implementation.
+      #
+      # Set the variable to 0 to not use the internal file, even when
+      # it exists in your checkout.
+      #
+      # Leave it unset in your include.gypi to have the variable
+      # implicitly set to 1 if you have
+      # src/google_apis/internal/google_chrome_api_keys.h in your
+      # checkout, and implicitly set to 0 if not.
+      #
+      # Note that official builds always behave as if the variable
+      # was explicitly set to 1, i.e. they always use official keys,
+      # and will fail to build if the internal file is missing.
+      #
+      # NOTE: You MUST NOT explicitly set the variable to 2 in your
+      # include.gypi or by other means. Due to subtleties of GYP, this
+      # is not the same as leaving the variable unset, even though its
+      # default value in
+      # //google_apis/determine_use_official_keys.gypi is 2.
+
+      # Set these to bake the specified API keys and OAuth client
+      # IDs/secrets into your build.
+      #
+      # If you create a build without values baked in, you can instead
+      # set environment variables to provide the keys at runtime (see
+      # src/google_apis/google_api_keys.h for details).  Features that
+      # require server-side APIs may fail to work if no keys are
+      # provided.
+      #
+      # Note that if you are building an official build or if
+      # use_official_google_api_keys has been set to 1 (explicitly or
+      # implicitly), these values will be ignored and the official
+      # keys will be used instead.
+      'google_api_key%': '',
+      'google_default_client_id%': '',
+      'google_default_client_secret%': '',
+      # Native Client is enabled by default.
+      'disable_nacl%': '0',
+
+      # Sets the default version name and code for Android app, by default we
+      # do a developer build.
+      'android_app_version_name%': 'Developer Build',
+      'android_app_version_code%': 1,
+    },
+
+    # Copy conditionally-set variables out one scope.
+    'branding%': '<(branding)',
+    'branding_path_component%': '<(branding_path_component)',
+    'buildtype%': '<(buildtype)',
+    'target_arch%': '<(target_arch)',
+    'target_subarch%': '<(target_subarch)',
+    'mips_arch_variant%': '<(mips_arch_variant)',
+    'mips_dsp_rev%': '<(mips_dsp_rev)',
+    'host_arch%': '<(host_arch)',
+    'toolkit_views%': '<(toolkit_views)',
+    'ui_compositor_image_transport%': '<(ui_compositor_image_transport)',
+    'use_aura%': '<(use_aura)',
+    'use_ash%': '<(use_ash)',
+    'use_cras%': '<(use_cras)',
+    'use_libpci%': '<(use_libpci)',
+    'use_openssl%': '<(use_openssl)',
+    'use_openssl_certs%': '<(use_openssl_certs)',
+    'use_nss_certs%': '<(use_nss_certs)',
+    'use_udev%': '<(use_udev)',
+    'os_bsd%': '<(os_bsd)',
+    'os_posix%': '<(os_posix)',
+    'use_dbus%': '<(use_dbus)',
+    'use_glib%': '<(use_glib)',
+    'use_pango%': '<(use_pango)',
+    'use_cairo%': '<(use_cairo)',
+    'use_ozone%': '<(use_ozone)',
+    'use_ozone_evdev%': '<(use_ozone_evdev)',
+    'use_xkbcommon%': '<(use_xkbcommon)',
+    'use_clipboard_aurax11%': '<(use_clipboard_aurax11)',
+    'desktop_linux%': '<(desktop_linux)',
+    'use_x11%': '<(use_x11)',
+    'use_gnome_keyring%': '<(use_gnome_keyring)',
+    'linux_fpic%': '<(linux_fpic)',
+    'chromeos%': '<(chromeos)',
+    'chromecast%': '<(chromecast)',
+    'enable_viewport%': '<(enable_viewport)',
+    'enable_hidpi%': '<(enable_hidpi)',
+    'image_loader_extension%': '<(image_loader_extension)',
+    'fastbuild%': '<(fastbuild)',
+    'dont_embed_build_metadata%': '<(dont_embed_build_metadata)',
+    'win_z7%': '<(win_z7)',
+    'dcheck_always_on%': '<(dcheck_always_on)',
+    'tracing_like_official_build%': '<(tracing_like_official_build)',
+    'arm_version%': '<(arm_version)',
+    'arm_neon%': '<(arm_neon)',
+    'arm_neon_optional%': '<(arm_neon_optional)',
+    'sysroot%': '<(sysroot)',
+    'chroot_cmd%': '<(chroot_cmd)',
+    'system_libdir%': '<(system_libdir)',
+    'component%': '<(component)',
+    'win_analyze%': '<(win_analyze)',
+    'enable_resource_whitelist_generation%': '<(enable_resource_whitelist_generation)',
+    'use_titlecase_in_grd%': '<(use_titlecase_in_grd)',
+    'use_third_party_translations%': '<(use_third_party_translations)',
+    'remoting%': '<(remoting)',
+    'enable_one_click_signin%': '<(enable_one_click_signin)',
+    'enable_pre_sync_backup%': '<(enable_pre_sync_backup)',
+    'enable_media_router%': '<(enable_media_router)',
+    'enable_webrtc%': '<(enable_webrtc)',
+    'chromium_win_pch%': '<(chromium_win_pch)',
+    'configuration_policy%': '<(configuration_policy)',
+    'safe_browsing%': '<(safe_browsing)',
+    'enable_web_speech%': '<(enable_web_speech)',
+    'notifications%': '<(notifications)',
+    'clang_use_chrome_plugins%': '<(clang_use_chrome_plugins)',
+    'mac_want_real_dsym%': '<(mac_want_real_dsym)',
+    'asan%': '<(asan)',
+    'asan_blacklist%': '<(asan_blacklist)',
+    'asan_coverage%': '<(asan_coverage)',
+    'sanitizer_coverage%': '<(sanitizer_coverage)',
+    'asan_field_padding%': '<(asan_field_padding)',
+    'use_sanitizer_options%': '<(use_sanitizer_options)',
+    'syzyasan%': '<(syzyasan)',
+    'kasko%': '<(kasko)',
+    'syzygy_optimize%': '<(syzygy_optimize)',
+    'lsan%': '<(lsan)',
+    'msan%': '<(msan)',
+    'msan_blacklist%': '<(msan_blacklist)',
+    'msan_track_origins%': '<(msan_track_origins)',
+    'tsan%': '<(tsan)',
+    'tsan_blacklist%': '<(tsan_blacklist)',
+    'ubsan%': '<(ubsan)',
+    'ubsan_blacklist%': '<(ubsan_blacklist)',
+    'ubsan_vptr%': '<(ubsan_vptr)',
+    'use_instrumented_libraries%': '<(use_instrumented_libraries)',
+    'use_prebuilt_instrumented_libraries%': '<(use_prebuilt_instrumented_libraries)',
+    'use_custom_libcxx%': '<(use_custom_libcxx)',
+    'use_system_libcxx%': '<(use_system_libcxx)',
+    'clang_type_profiler%': '<(clang_type_profiler)',
+    'order_profiling%': '<(order_profiling)',
+    'order_text_section%': '<(order_text_section)',
+    'enable_extensions%': '<(enable_extensions)',
+    'enable_plugin_installation%': '<(enable_plugin_installation)',
+    'enable_plugins%': '<(enable_plugins)',
+    'enable_session_service%': '<(enable_session_service)',
+    'enable_themes%': '<(enable_themes)',
+    'enable_autofill_dialog%': '<(enable_autofill_dialog)',
+    'enable_prod_wallet_service%': '<(enable_prod_wallet_service)',
+    'enable_background%': '<(enable_background)',
+    'linux_use_bundled_gold%': '<(linux_use_bundled_gold)',
+    'linux_use_bundled_binutils%': '<(linux_use_bundled_binutils)',
+    'linux_use_gold_flags%': '<(linux_use_gold_flags)',
+    'linux_use_debug_fission%': '<(linux_use_debug_fission)',
+    'use_canvas_skia%': '<(use_canvas_skia)',
+    'test_isolation_mode%': '<(test_isolation_mode)',
+    'test_isolation_outdir%': '<(test_isolation_outdir)',
+    'enable_basic_printing%': '<(enable_basic_printing)',
+    'enable_print_preview%': '<(enable_print_preview)',
+    'enable_spellcheck%': '<(enable_spellcheck)',
+    'enable_google_now%': '<(enable_google_now)',
+    'cld_version%': '<(cld_version)',
+    'cld2_table_size%': '<(cld2_table_size)',
+    'enable_captive_portal_detection%': '<(enable_captive_portal_detection)',
+    'disable_file_support%': '<(disable_file_support)',
+    'disable_ftp_support%': '<(disable_ftp_support)',
+    'use_icu_alternatives_on_android%': '<(use_icu_alternatives_on_android)',
+    'enable_task_manager%': '<(enable_task_manager)',
+    'sas_dll_path%': '<(sas_dll_path)',
+    'wix_path%': '<(wix_path)',
+    'use_libjpeg_turbo%': '<(use_libjpeg_turbo)',
+    'use_system_libjpeg%': '<(use_system_libjpeg)',
+    'android_channel%': '<(android_channel)',
+    'icu_use_data_file_flag%': '<(icu_use_data_file_flag)',
+    'gyp_managed_install%': 0,
+    'create_standalone_apk%': 1,
+    'enable_app_list%': '<(enable_app_list)',
+    'use_default_render_theme%': '<(use_default_render_theme)',
+    'enable_settings_app%': '<(enable_settings_app)',
+    'google_api_key%': '<(google_api_key)',
+    'google_default_client_id%': '<(google_default_client_id)',
+    'google_default_client_secret%': '<(google_default_client_secret)',
+    'enable_supervised_users%': '<(enable_supervised_users)',
+    'native_memory_pressure_signals%': '<(native_memory_pressure_signals)',
+    'spdy_proxy_auth_property%': '<(spdy_proxy_auth_property)',
+    'spdy_proxy_auth_value%': '<(spdy_proxy_auth_value)',
+    'enable_mdns%' : '<(enable_mdns)',
+    'enable_service_discovery%' : '<(enable_service_discovery)',
+    'enable_wifi_bootstrapping%': '<(enable_wifi_bootstrapping)',
+    'enable_hangout_services_extension%' : '<(enable_hangout_services_extension)',
+    'v8_optimized_debug%': '<(v8_optimized_debug)',
+    'proprietary_codecs%': '<(proprietary_codecs)',
+    'use_goma%': '<(use_goma)',
+    'gomadir%': '<(gomadir)',
+    'use_lto%': '<(use_lto)',
+    'use_lto_o2%': '<(use_lto_o2)',
+    'gold_icf_level%': '<(gold_icf_level)',
+    'video_hole%': '<(video_hole)',
+    'v8_use_external_startup_data%': '<(v8_use_external_startup_data)',
+    'cfi_vptr%': '<(cfi_vptr)',
+    'cfi_derived_cast%': '<(cfi_derived_cast)',
+    'cfi_unrelated_cast%': '<(cfi_unrelated_cast)',
+    'cfi_blacklist%': '<(cfi_blacklist)',
+    'mac_views_browser%': '<(mac_views_browser)',
+    'android_app_version_name%': '<(android_app_version_name)',
+    'android_app_version_code%': '<(android_app_version_code)',
+
+    # Use system protobuf instead of bundled one.
+    'use_system_protobuf%': 0,
+
+    # Use system yasm instead of bundled one.
+    'use_system_yasm%': 0,
+
+    # Use system ICU instead of bundled one.
+    'use_system_icu%' : 0,
+
+    # Default to enabled PIE; this is important for ASLR but we may need to be
+    # able to turn it off for various reasons.
+    'linux_disable_pie%': 0,
+
+    # The release channel that this build targets. This is used to restrict
+    # channel-specific build options, like which installer packages to create.
+    # The default is 'all', which does no channel-specific filtering.
+    'channel%': 'all',
+
+    # Override chromium_mac_pch and set it to 0 to suppress the use of
+    # precompiled headers on the Mac.  Prefix header injection may still be
+    # used, but prefix headers will not be precompiled.  This is useful when
+    # using distcc to distribute a build to compile slaves that don't
+    # share the same compiler executable as the system driving the compilation,
+    # because precompiled headers rely on pointers into a specific compiler
+    # executable's image.  Setting this to 0 is needed to use an experimental
+    # Linux-Mac cross compiler distcc farm.
+    'chromium_mac_pch%': 1,
+
+    # The default value for mac_strip in target_defaults. This cannot be
+    # set there, per the comment about variable% in a target_defaults.
+    'mac_strip_release%': 0,
+
+    # Set to 1 to enable java code coverage. Instruments classes during build
+    # to produce .ec files during runtime.
+    'emma_coverage%': 0,
+
+    # EMMA filter string consisting of a list of inclusion/exclusion patterns
+    # separated with whitespace and/or comma. Only has effect if
+    # 'emma_coverage=1'.
+    'emma_filter%': '',
+
+    # Set to 1 to enable running Android lint on java/class files.
+    'android_lint%': 1,
+
+    # Although base/allocator lets you select a heap library via an
+    # environment variable, the libcmt shim it uses sometimes gets in
+    # the way.  To disable it entirely, and switch to normal msvcrt, do e.g.
+    #  'win_use_allocator_shim': 0,
+    #  'win_release_RuntimeLibrary': 2
+    # to ~/.gyp/include.gypi, gclient runhooks --force, and do a release build.
+    'win_use_allocator_shim%': 1, # 1 = shim allocator via libcmt; 0 = msvcrt
+
+    # TODO(bradnelson): eliminate this when possible.
+    # To allow local gyp files to prevent release.vsprops from being included.
+    # Yes(1) means include release.vsprops.
+    # Once all vsprops settings are migrated into gyp, this can go away.
+    'msvs_use_common_release%': 1,
+
+    # TODO(bradnelson): eliminate this when possible.
+    # To allow local gyp files to override additional linker options for msvs.
+    # Yes(1) means set use the common linker options.
+    'msvs_use_common_linker_extras%': 1,
+
+    # TODO(sgk): eliminate this if possible.
+    # It would be nicer to support this via a setting in 'target_defaults'
+    # in chrome/app/locales/locales.gypi overriding the setting in the
+    # 'Debug' configuration in the 'target_defaults' dict below,
+    # but that doesn't work as we'd like.
+    'msvs_debug_link_incremental%': '2',
+
+    # Needed for some of the largest modules.
+    'msvs_debug_link_nonincremental%': '1',
+
+    # Turns on Use Library Dependency Inputs for linking chrome.dll on Windows
+    # to get incremental linking to be faster in debug builds.
+    'incremental_chrome_dll%': '0',
+
+    # Experimental setting to break chrome.dll into multiple pieces based on
+    # process type.
+    'chrome_multiple_dll%': '0',
+
+    # Experimental setting to optimize Chrome's DLLs with PGO.
+    'chrome_pgo_phase%': '0',
+
+    # Whether the VS xtree header has been patched to disable warning 4702. If
+    # it has, then we don't need to disable 4702 (unreachable code warning).
+    # The patch is preapplied to the internal toolchain and hence all bots.
+    'msvs_xtree_patched%': '<!pymod_do_main(win_is_xtree_patched)',
+
+    # Clang stuff.
+    'clang%': '<(clang)',
+    'host_clang%': '<(host_clang)',
+    'make_clang_dir%': '<(make_clang_dir)',
+    'use_lld%': '<(use_lld)',
+
+    # Control which version of clang to use when building for iOS.  If set to
+    # '1', uses the version of clang that ships with Xcode.  If set to '0', uses
+    # the version of clang that ships with the Chromium source.  This variable
+    # is automatically set to '1' when using the Xcode generator.
+    'clang_xcode%': 0,
+
+    # These two variables can be set in GYP_DEFINES while running
+    # |gclient runhooks| to let clang run a plugin in every compilation.
+    # Only has an effect if 'clang=1' is in GYP_DEFINES as well.
+    # Example:
+    #     GYP_DEFINES='clang=1 clang_load=/abs/path/to/libPrintFunctionNames.dylib clang_add_plugin=print-fns' gclient runhooks
+
+    'clang_load%': '',
+    'clang_add_plugin%': '',
+
+    # Tell ld64 to write map files describing binary layout. Useful
+    # for looking at what contributes to binary size, e.g. with
+    # https://github.com/nico/bloat
+    'mac_write_linker_maps%': 0,
+
+    # The default type of gtest.
+    'gtest_target_type%': 'executable',
+
+    # Enable sampling based profiler.
+    # See http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html
+    'profiling%': '0',
+    # Profile without optimizing out stack frames when profiling==1.
+    'profiling_full_stack_frames%': '0',
+
+    # And if we want to dump symbols for Breakpad-enabled builds.
+    'linux_dump_symbols%': 0,
+    # And if we want to strip the binary after dumping symbols.
+    'linux_strip_binary%': 0,
+    # If we want stack unwind support for backtrace().
+    'debug_unwind_tables%': 1,
+    'release_unwind_tables%': 1,
+
+    # Override where to find binutils
+    'binutils_version%': 0,
+    'binutils_dir%': '',
+
+    # Enable TCMalloc.
+    # Default of 'use_allocator' is set to 'none' if OS=='android' later.
+    'use_allocator%': 'tcmalloc',
+
+    # Set to 1 to link against libgnome-keyring instead of using dlopen().
+    'linux_link_gnome_keyring%': 0,
+    # Set to 1 to link against gsettings APIs instead of using dlopen().
+    'linux_link_gsettings%': 0,
+
+    # Enable use of OpenMAX DL FFT routines.
+    'use_openmax_dl_fft%': '<(use_openmax_dl_fft)',
+
+    # Enable new NPDevice API.
+    'enable_new_npdevice_api%': 0,
+
+    # .gyp files or targets should set chromium_code to 1 if they build
+    # Chromium-specific code, as opposed to external code.  This variable is
+    # used to control such things as the set of warnings to enable, and
+    # whether warnings are treated as errors.
+    'chromium_code%': 0,
+
+    # Disable fatal linker warnings, similarly to how we make it possible
+    # to disable -Werror (e.g. for different toolchain versions).
+    'disable_fatal_linker_warnings%': 0,
+
+    'release_valgrind_build%': 0,
+
+    # TODO(thakis): Make this a blacklist instead, http://crbug.com/101600
+    'enable_wexit_time_destructors%': 0,
+
+    # Build libpeerconnection as a static library by default.
+    'libpeer_target_type%': 'static_library',
+
+    # Set to 1 to compile with the OpenGL ES 2.0 conformance tests.
+    'internal_gles2_conform_tests%': 0,
+
+    # Set to 1 to compile with the Khronos GL-CTS conformance tests.
+    'internal_khronos_glcts_tests%': 0,
+
+    # Set to 1 to compile the filter fuzzer.
+    'internal_filter_fuzzer%': 0,
+
+    # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_'
+    # so Cocoa is happy (http://crbug.com/20441).
+    'locales': [
+      'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB',
+      'en-US', 'es-419', 'es', 'et', 'fa', 'fi', 'fil', 'fr', 'gu', 'he',
+      'hi', 'hr', 'hu', 'id', 'it', 'ja', 'kn', 'ko', 'lt', 'lv',
+      'ml', 'mr', 'ms', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru',
+      'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk',
+      'vi', 'zh-CN', 'zh-TW',
+    ],
+
+    # Pseudo locales are special locales which are used for testing and
+    # debugging. They don't get copied to the final app. For more info,
+    # check out https://www.chromium.org/developers/testing/fake-bidi
+    'pseudo_locales': [
+      'fake-bidi',
+    ],
+
+    'grit_defines': [],
+
+    # If debug_devtools is set to 1, JavaScript files for DevTools are
+    # stored as is and loaded from disk. Otherwise, a concatenated file
+    # is stored in resources.pak. It is still possible to load JS files
+    # from disk by passing --debug-devtools cmdline switch.
+    'debug_devtools%': 0,
+
+    # The Java Bridge is not compiled in by default.
+    'java_bridge%': 0,
+
+    # Code signing for iOS binaries.  The bots need to be able to disable this.
+    'chromium_ios_signing%': 1,
+
+    # This flag is only used when disable_nacl==0 and disables all those
+    # subcomponents which would require the installation of a native_client
+    # untrusted toolchain.
+    'disable_nacl_untrusted%': 0,
+
+    # Disable Dart by default.
+    'enable_dart%': 0,
+
+    # Copy out the setting of disable_nacl.
+    'disable_nacl%': '<(disable_nacl)',
+
+    # Portable Native Client is enabled by default.
+    'disable_pnacl%': 0,
+
+    # Whether to build full debug version for Debug configuration on Android.
+    # Compared to full debug version, the default Debug configuration on Android
+    # has no full v8 debug, has size optimization and linker gc section, so that
+    # we can build a debug version with acceptable size and performance.
+    'android_full_debug%': 0,
+
+    # Contains data about the attached devices for gyp_managed_install.
+    'build_device_config_path': '<(PRODUCT_DIR)/build_devices.cfg',
+
+    'sas_dll_exists': '<!pymod_do_main(dir_exists "<(sas_dll_path)")',
+    'wix_exists': '<!pymod_do_main(dir_exists "<(wix_path)")',
+
+    'windows_sdk_default_path': '<(DEPTH)/third_party/platformsdk_win8/files',
+    'directx_sdk_default_path': '<(DEPTH)/third_party/directxsdk/files',
+
+    # Whether we are using the rlz library or not.  Platforms like Android send
+    # rlz codes for searches but do not use the library.
+    'enable_rlz%': 0,
+
+    # Turns on the i18n support in V8.
+    'v8_enable_i18n_support': 1,
+
+    # Compile d8 for the host toolset.
+    'v8_toolset_for_d8': 'host',
+
+    # Use brlapi from brltty for braille display support.
+    'use_brlapi%': 0,
+
+    # Relative path to icu.gyp from this file.
+    'icu_gyp_path': '../third_party/icu/icu.gyp',
+
+    # IPC fuzzer is disabled by default.
+    'enable_ipc_fuzzer%': 0,
+
+    # Force disable libstdc++ debug mode.
+    'disable_glibcxx_debug%': 0,
+
+    # Set to 1 to compile with MSE support for MPEG2 TS
+    'enable_mpeg2ts_stream_parser%': 0,
+
+    # Support ChromeOS touchpad gestures with ozone.
+    'use_evdev_gestures%': 0,
+
+    # Default ozone platform (if no --ozone-platform flag).
+    'ozone_platform%': "",
+
+    # Ozone platforms to include in the build.
+    'ozone_platform_caca%': 0,
+    'ozone_platform_cast%': 0,
+    'ozone_platform_dri%': 0,
+    'ozone_platform_drm%': 0,
+    'ozone_platform_egltest%': 0,
+    'ozone_platform_gbm%': 0,
+    'ozone_platform_ozonex%': 0,
+    'ozone_platform_test%': 0,
+
+    # Experiment: http://crbug.com/426914
+    'envoy%': 0,
+
+    # Used to set libjpeg_gyp_path. Chrome OS ui/gfx/gfx.gyp uses the IJG path
+    # for robust login screen decoding.
+    'libjpeg_ijg_gyp_path': '<(DEPTH)/third_party/libjpeg/libjpeg.gyp',
+    'libjpeg_turbo_gyp_path': '<(DEPTH)/third_party/libjpeg_turbo/libjpeg.gyp',
+
+    'conditions': [
+      ['buildtype=="Official"', {
+        # Continue to embed build meta data in Official builds, basically the
+        # time it was built.
+        # TODO(maruel): This decision should be revisited because having an
+        # official deterministic build has high value too but MSVC toolset can't
+        # generate anything deterministic with WPO enabled AFAIK.
+        'dont_embed_build_metadata%': 0,
+      }],
+      # Enable the Syzygy optimization step for the official builds.
+      ['OS=="win" and buildtype=="Official" and syzyasan!=1 and clang!=1', {
+        'syzygy_optimize%': 1,
+      }, {
+        'syzygy_optimize%': 0,
+      }],
+      # Get binutils version so we can enable debug fission if we can.
+      ['os_posix==1 and OS!="mac" and OS!="ios"', {
+        'conditions': [
+          # compiler_version doesn't work with clang
+          # TODO(mithro): Land https://codereview.chromium.org/199793014/ so
+          # compiler_version works with clang.
+          # TODO(glider): set clang to 1 earlier for ASan and TSan builds so
+          # that it takes effect here.
+          ['clang==0 and asan==0 and lsan==0 and tsan==0 and msan==0 and ubsan==0 and ubsan_vptr==0', {
+            'binutils_version%': '<!pymod_do_main(compiler_version target assembler)',
+          }],
+          # On Android we know the binutils version in the toolchain.
+          ['OS=="android"', {
+            'binutils_version%': 222,
+          }],
+          ['host_arch=="x64"', {
+            'binutils_dir%': 'third_party/binutils/Linux_x64/Release/bin',
+          }],
+          ['host_arch=="ia32"', {
+            'binutils_dir%': 'third_party/binutils/Linux_ia32/Release/bin',
+          }],
+          # Our version of binutils in third_party/binutils
+          ['linux_use_bundled_binutils==1', {
+            'binutils_version%': 224,
+          }],
+        ],
+      }, {
+        'binutils_version%': 0,
+      }],
+      # The version of GCC in use, set later in platforms that use GCC and have
+      # not explicitly chosen to build with clang. Currently, this means all
+      # platforms except Windows, Mac and iOS.
+      # TODO(glider): set clang to 1 earlier for ASan and TSan builds so that
+      # it takes effect here.
+      ['os_posix==1 and OS!="mac" and OS!="ios" and clang==0 and asan==0 and lsan==0 and tsan==0 and msan==0 and ubsan_vptr==0', {
+        'conditions': [
+          ['OS=="android"', {
+            'host_gcc_version%': '<!pymod_do_main(compiler_version host compiler)',
+            # We directly set the gcc version since we know what we use.
+            'gcc_version%': 49,
+          }, {
+            'host_gcc_version%': '<!pymod_do_main(compiler_version host compiler)',
+            'gcc_version%': '<!pymod_do_main(compiler_version target compiler)',
+          }],
+        ],
+      }, {
+        'host_gcc_version%': 0,
+        'gcc_version%': 0,
+      }],
+      ['OS=="win" and "<!pymod_do_main(dir_exists <(windows_sdk_default_path))"=="True"', {
+        'windows_sdk_path%': '<(windows_sdk_default_path)',
+      }, {
+        'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.1',
+      }],
+      ['OS=="win" and "<!pymod_do_main(dir_exists <(directx_sdk_default_path))"=="True"', {
+        'directx_sdk_path%': '<(directx_sdk_default_path)',
+      }, {
+        'directx_sdk_path%': '$(DXSDK_DIR)',
+      }],
+      ['OS=="win"', {
+        'windows_driver_kit_path%': '$(WDK_DIR)',
+      }],
+      ['os_posix==1 and OS!="mac" and OS!="ios"', {
+        'conditions': [
+          ['target_arch=="mipsel" or target_arch=="mips64el"', {
+            'werror%': '',
+            'disable_nacl%': 1,
+            'nacl_untrusted_build%': 0,
+            'use_allocator%': 'none',
+          }],
+          ['OS=="linux" and target_arch=="mipsel"', {
+            'sysroot%': '<(sysroot)',
+            'CXX%': '<(CXX)',
+          }],
+          # Use a 64-bit linker to avoid running out of address space. The
+          # buildbots should have a 64-bit kernel and a 64-bit libc installed.
+          ['host_arch=="ia32" and target_arch=="ia32"', {
+            # TODO(thestig) This is a horrible way to force the desired
+            # configuration. Our gyp variable scoping is likely wrong and
+            # needs to be cleaned up. The GN configuration should be changed
+            # to match.
+            'binutils_version%': 224,
+            'linux_use_bundled_binutils%': '1',
+            'linux_use_bundled_gold%': '1',
+            'binutils_dir%': 'third_party/binutils/Linux_x64/Release/bin',
+          }],
+          # All Chrome builds have breakpad symbols, but only process the
+          # symbols from official builds.
+          ['(branding=="Chrome" and buildtype=="Official")', {
+            'linux_dump_symbols%': 1,
+
+            # Omit unwind support in official release builds to save space. We
+            # can use breakpad for these builds.
+            'release_unwind_tables%': 0,
+          }],
+        ],
+      }],  # os_posix==1 and OS!="mac" and OS!="ios"
+      ['OS=="ios"', {
+        'disable_nacl%': 1,
+        'enable_background%': 0,
+        'icu_use_data_file_flag%': 1,
+        'enable_web_speech%': 0,
+        'use_system_libxml%': 1,
+        'use_system_sqlite%': 1,
+        'locales==': [
+          'ar', 'ca', 'cs', 'da', 'de', 'el', 'en-GB', 'en-US', 'es', 'es-MX',
+          'fi', 'fr', 'he', 'hi', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'ms',
+          'nb', 'nl', 'pl', 'pt', 'pt-PT', 'ro', 'ru', 'sk', 'sv', 'th', 'tr',
+          'uk', 'vi', 'zh-CN', 'zh-TW',
+        ],
+
+        # iOS SDK and deployment target support.  The |ios_sdk| value is left
+        # blank so that when it is set in the project files it will be the
+        # "current" iOS SDK.  Forcing a specific SDK even if it is "current"
+        # causes Xcode to spit out a warning for every single project file for
+        # not using the "current" SDK.
+        'ios_sdk%': '',
+        'ios_sdk_path%': '',
+        'ios_deployment_target%': '7.0',
+
+        'conditions': [
+          # ios_product_name is set to the name of the .app bundle as it should
+          # appear on disk.
+          ['branding=="Chrome"', {
+            'ios_product_name%': 'Chrome',
+          }, { # else: branding!="Chrome"
+            'ios_product_name%': 'Chromium',
+          }],
+          ['branding=="Chrome" and buildtype=="Official"', {
+            'ios_breakpad%': 1,
+          }, { # else: branding!="Chrome" or buildtype!="Official"
+            'ios_breakpad%': 0,
+          }],
+        ],
+      }],  # OS=="ios"
+      ['OS=="android"', {
+        # Location of Android NDK.
+        'variables': {
+          'variables': {
+            # Standard libraries can use the relative path to the NDK.
+            'android_ndk_root%': '../../third_party/android_tools/ndk/',
+            # Unfortunately, it is required to use the absolute path to the SDK
+            # because it us passed to ant which uses a different relative path
+            # from GYP.
+            'android_sdk_root%': '<!(cd <(DEPTH) && pwd -P)/third_party/android_tools/sdk/',
+            # Similarly, gdbserver and the Android toolchain need to use the
+            # absolute path to the NDK because they are used at different levels
+            # in the GYP files.
+            'android_ndk_absolute_root%': '<!(cd <(DEPTH) && pwd -P)/third_party/android_tools/ndk/',
+            'android_host_arch%': '<!(uname -m)',
+            # Android API-level of the SDK used for compilation.
+            'android_sdk_version%': '22',
+            'android_sdk_build_tools_version%': '22.0.0',
+            'host_os%': "<!(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')",
+          },
+          # Copy conditionally-set variables out one scope.
+          'android_ndk_root%': '<(android_ndk_root)',
+          'android_ndk_absolute_root%': '<(android_ndk_absolute_root)',
+          'android_sdk_root%': '<(android_sdk_root)',
+          'android_sdk_version%': '<(android_sdk_version)',
+          'android_libcpp_root': '<(android_ndk_root)/sources/cxx-stl/llvm-libc++',
+          'host_os%': '<(host_os)',
+
+          'android_sdk%': '<(android_sdk_root)/platforms/android-<(android_sdk_version)',
+          # Android SDK build tools (e.g. dx, aapt, aidl)
+          'android_sdk_tools%': '<(android_sdk_root)/build-tools/<(android_sdk_build_tools_version)',
+
+          # Android API level 14 is ICS (Android 4.0) which is the minimum
+          # platform requirement for Chrome on Android, we use it for native
+          # code compilation.
+          'conditions': [
+            ['target_arch == "ia32"', {
+              'android_app_abi%': 'x86',
+              'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-x86/gdbserver/gdbserver',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-x86',
+              'android_ndk_lib_dir%': 'usr/lib',
+              'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/x86-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin',
+            }],
+            ['target_arch == "x64"', {
+              'android_app_abi%': 'x86_64',
+              'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-x86_64/gdbserver/gdbserver',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-21/arch-x86_64',
+              'android_ndk_lib_dir%': 'usr/lib64',
+              'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/x86_64-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin',
+            }],
+            ['target_arch=="arm"', {
+              'conditions': [
+                ['arm_version<7', {
+                  'android_app_abi%': 'armeabi',
+                }, {
+                  'android_app_abi%': 'armeabi-v7a',
+                }],
+              ],
+              'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-arm/gdbserver/gdbserver',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-arm',
+              'android_ndk_lib_dir%': 'usr/lib',
+              'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/arm-linux-androideabi-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin',
+            }],
+            ['target_arch == "arm64"', {
+              'android_app_abi%': 'arm64-v8a',
+              'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-arm64/gdbserver/gdbserver',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-21/arch-arm64',
+              'android_ndk_lib_dir%': 'usr/lib',
+              'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/aarch64-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin',
+            }],
+            ['target_arch == "mipsel"', {
+              'android_app_abi%': 'mips',
+              'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-mips/gdbserver/gdbserver',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-14/arch-mips',
+              'android_ndk_lib_dir%': 'usr/lib',
+              'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/mipsel-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin',
+            }],
+            ['target_arch == "mips64el"', {
+              'android_app_abi%': 'mips64',
+              'android_gdbserver%': '<(android_ndk_absolute_root)/prebuilt/android-mips64/gdbserver/gdbserver',
+              'android_ndk_sysroot%': '<(android_ndk_root)/platforms/android-21/arch-mips64',
+              'android_ndk_lib_dir%': 'usr/lib64',
+              'android_toolchain%': '<(android_ndk_absolute_root)/toolchains/mips64el-linux-android-4.9/prebuilt/<(host_os)-<(android_host_arch)/bin',
+            }],
+          ],
+        },
+        # Copy conditionally-set variables out one scope.
+        'android_app_abi%': '<(android_app_abi)',
+        'android_gdbserver%': '<(android_gdbserver)',
+        'android_ndk_root%': '<(android_ndk_root)',
+        'android_ndk_sysroot%': '<(android_ndk_sysroot)',
+        'android_sdk_root%': '<(android_sdk_root)',
+        'android_sdk_version%': '<(android_sdk_version)',
+        'android_toolchain%': '<(android_toolchain)',
+
+        'android_ndk_include': '<(android_ndk_sysroot)/usr/include',
+        'android_ndk_lib': '<(android_ndk_sysroot)/<(android_ndk_lib_dir)',
+        'android_sdk_tools%': '<(android_sdk_tools)',
+        'android_sdk%': '<(android_sdk)',
+        'android_sdk_jar%': '<(android_sdk)/android.jar',
+
+        'android_libcpp_root': '<(android_libcpp_root)',
+        'android_libcpp_include': '<(android_libcpp_root)/libcxx/include',
+        'android_libcpp_libs_dir': '<(android_libcpp_root)/libs/<(android_app_abi)',
+        'host_os%': '<(host_os)',
+
+        # Location of the "objcopy" binary, used by both gyp and scripts.
+        'android_objcopy%' : '<!(/bin/echo -n <(android_toolchain)/*-objcopy)',
+
+        # Location of the "strip" binary, used by both gyp and scripts.
+        'android_strip%' : '<!(/bin/echo -n <(android_toolchain)/*-strip)',
+
+        # Location of the "readelf" binary.
+        'android_readelf%' : '<!(/bin/echo -n <(android_toolchain)/*-readelf)',
+
+        # Determines whether we should optimize JNI generation at the cost of
+        # breaking assumptions in the build system that when inputs have changed
+        # the outputs should always change as well.  This is meant purely for
+        # developer builds, to avoid spurious re-linking of native files.
+        'optimize_jni_generation%': '<(optimize_jni_generation)',
+
+        # Always uses openssl.
+        'use_openssl%': 1,
+        'use_openssl_certs%': 1,
+
+        'proprietary_codecs%': '<(proprietary_codecs)',
+        'safe_browsing%': 2,
+        'enable_web_speech%': 0,
+        'java_bridge%': 1,
+        'build_ffmpegsumo%': 0,
+        'use_allocator%': 'none',
+
+        # Disable Native Client.
+        'disable_nacl%': 1,
+
+        # Android does not support background apps.
+        'enable_background%': 0,
+
+        # Sessions are store separately in the Java side.
+        'enable_session_service%': 0,
+
+        'p2p_apis%' : 0,
+
+        'gtest_target_type%': 'shared_library',
+
+        # Uses system APIs for decoding audio and video.
+        'use_libffmpeg%': '0',
+      }],  # OS=="android"
+      ['embedded==1', {
+        'use_system_fontconfig%': 0,
+      }, {
+        'use_system_fontconfig%': 1,
+      }],
+      ['chromecast==1', {
+        'enable_mpeg2ts_stream_parser%': 1,
+        'ffmpeg_branding%': 'ChromeOS',
+        'ozone_platform_ozonex%': 1,
+        'use_playready%': 0,
+        'conditions': [
+          ['target_arch=="arm"', {
+            'arm_arch%': '',
+            'arm_tune%': 'cortex-a9',
+            'arm_thumb%': 1,
+            'video_hole%': 1,
+          }],
+        ],
+      }],
+      ['chromecast==1 and OS!="android"', {
+        'ozone_platform_cast%': 1
+      }],
+      ['OS=="linux" and target_arch!="mipsel"', {
+        'clang%': 1,
+      }],  # OS=="mac"
+      ['OS=="mac"', {
+        'conditions': [
+          # All Chrome builds have breakpad symbols, but only process the
+          # symbols from official builds.
+          ['(branding=="Chrome" and buildtype=="Official")', {
+            'mac_strip_release%': 1,
+          }],
+        ],
+      }],  # OS=="mac"
+      ['OS=="mac" or OS=="ios"', {
+        'clang%': 1,
+
+        'variables': {
+          # Mac OS X SDK and deployment target support.  The SDK identifies
+          # the version of the system headers that will be used, and
+          # corresponds to the MAC_OS_X_VERSION_MAX_ALLOWED compile-time
+          # macro.  "Maximum allowed" refers to the operating system version
+          # whose APIs are available in the headers.  The deployment target
+          # identifies the minimum system version that the built products are
+          # expected to function on.  It corresponds to the
+          # MAC_OS_X_VERSION_MIN_REQUIRED compile-time macro.  To ensure these
+          # macros are available, #include <AvailabilityMacros.h>.  Additional
+          # documentation on these macros is available at
+          # http://developer.apple.com/mac/library/technotes/tn2002/tn2064.html#SECTION3
+          # Chrome normally builds with the Mac OS X 10.6 SDK and sets the
+          # deployment target to 10.6.  Other projects, such as O3D, may
+          # override these defaults.
+
+          # Normally, mac_sdk_min is used to find an SDK that Xcode knows
+          # about that is at least the specified version. In official builds,
+          # the SDK must match mac_sdk_min exactly. If the SDK is installed
+          # someplace that Xcode doesn't know about, set mac_sdk_path to the
+          # path to the SDK; when set to a non-empty string, SDK detection
+          # based on mac_sdk_min will be bypassed entirely.
+          'conditions': [
+            ['OS=="ios"', {
+              'mac_sdk_min%': '10.8',
+            }, {  # else OS!="ios"
+              'mac_sdk_min%': '10.6',
+            }],
+          ],
+          'mac_sdk_path%': '',
+
+          'mac_deployment_target%': '10.6',
+        },
+
+        'mac_sdk_min': '<(mac_sdk_min)',
+        'mac_sdk_path': '<(mac_sdk_path)',
+        'mac_deployment_target': '<(mac_deployment_target)',
+
+        # Compile in Breakpad support by default so that it can be
+        # tested, even if it is not enabled by default at runtime.
+        'mac_breakpad_compiled_in%': 1,
+        'conditions': [
+          # mac_product_name is set to the name of the .app bundle as it should
+          # appear on disk.  This duplicates data from
+          # chrome/app/theme/chromium/BRANDING and
+          # chrome/app/theme/google_chrome/BRANDING, but is necessary to get
+          # these names into the build system.
+          ['branding=="Chrome"', {
+            'mac_product_name%': 'Google Chrome',
+          }, { # else: branding!="Chrome"
+            'mac_product_name%': 'Chromium',
+          }],
+          # Official mac builds require a specific OS X SDK, but iOS and
+          # non-official mac builds do not.
+          ['branding=="Chrome" and buildtype=="Official" and OS=="mac"', {
+            'mac_sdk%': '<!(python <(DEPTH)/build/mac/find_sdk.py --verify <(mac_sdk_min) --sdk_path=<(mac_sdk_path))',
+          }, {
+            'mac_sdk%': '<!(python <(DEPTH)/build/mac/find_sdk.py <(mac_sdk_min))',
+          }],
+          ['branding=="Chrome" and buildtype=="Official"', {
+            # Enable uploading crash dumps.
+            'mac_breakpad_uploads%': 1,
+            # Enable dumping symbols at build time for use by Mac Breakpad.
+            'mac_breakpad%': 1,
+            # Enable Keystone auto-update support.
+            'mac_keystone%': 1,
+          }, { # else: branding!="Chrome" or buildtype!="Official"
+            'mac_breakpad_uploads%': 0,
+            'mac_breakpad%': 0,
+            'mac_keystone%': 0,
+          }],
+        ],
+      }],  # OS=="mac" or OS=="ios"
+      ['OS=="win"', {
+        'conditions': [
+          # This is the architecture convention used in WinSDK paths.
+          ['target_arch=="ia32"', {
+            'winsdk_arch%': 'x86',
+          },{
+            'winsdk_arch%': '<(target_arch)',
+          }],
+          ['component=="shared_library" or MSVS_VERSION == "2015"', {
+            # TODO(scottmg): The allocator shimming doesn't work on the 2015 CRT
+            # and we are hoping to be able to remove it if an additional feature
+            # lands in the 2015 CRT API. For now, don't shim and revisit once
+            # VS2015 is RTM: http://crbug.com/481611.
+            'win_use_allocator_shim%': 0,
+          }],
+          ['component=="static_library"', {
+            # Turn on multiple dll by default on Windows when in static_library.
+            'chrome_multiple_dll%': 1,
+          }],
+          ['asan==1 or syzyasan==1', {
+            'win_use_allocator_shim%': 0,
+          }],
+          ['syzyasan==1', {
+            'kasko%': 1,
+          }],
+          ['component=="shared_library" and "<(GENERATOR)"=="ninja"', {
+            # Only enabled by default for ninja because it's buggy in VS.
+            # Not enabled for component=static_library because some targets
+            # are too large and the toolchain fails due to the size of the
+            # .obj files.
+            'incremental_chrome_dll%': 1,
+          }],
+          # Don't do incremental linking for large modules on 32-bit or when
+          # component=static_library as the toolchain fails due to the size of
+          # the .ilk files.
+          ['MSVS_OS_BITS==32 or component=="static_library"', {
+            'msvs_large_module_debug_link_mode%': '1',  # No
+          },{
+            'msvs_large_module_debug_link_mode%': '2',  # Yes
+          }],
+        ],
+        'nacl_win64_defines': [
+          # This flag is used to minimize dependencies when building
+          # Native Client loader for 64-bit Windows.
+          'NACL_WIN64',
+        ],
+        # Need to include allocator target, but exclude tcmalloc files.
+        'use_allocator%': 'winheap',
+      }],
+
+      ['os_posix==1 and chromeos==0 and OS!="android" and OS!="ios" and embedded==0', {
+        'use_cups%': 1,
+      }, {
+        'use_cups%': 0,
+      }],
+
+      ['enable_plugins==1 and (OS=="linux" or OS=="mac" or OS=="win")', {
+        'enable_pepper_cdms%': 1,
+      }, {
+        'enable_pepper_cdms%': 0,
+      }],
+
+      ['OS=="android" or chromecast==1', {
+        'enable_browser_cdms%': 1,
+      }, {
+        'enable_browser_cdms%': 0,
+      }],
+
+      # Native Client glibc toolchain is enabled
+      # by default except on arm, mips and mips64.
+      ['target_arch=="arm" or target_arch=="mipsel" or target_arch=="mips64el"', {
+        'disable_glibc%': 1,
+      }, {
+        'disable_glibc%': 0,
+      }],
+
+      # Set the relative path from this file to the GYP file of the JPEG
+      # library used by Chromium.
+      ['use_system_libjpeg==1 or use_libjpeg_turbo==0', {
+        # Configuration for using the system libjeg is here.
+        'libjpeg_gyp_path': '<(libjpeg_ijg_gyp_path)',
+      }, {
+        'libjpeg_gyp_path': '<(libjpeg_turbo_gyp_path)',
+      }],
+
+      # Options controlling the use of GConf (the classic GNOME configuration
+      # system) and GIO, which contains GSettings (the new GNOME config system).
+      ['chromeos==1 or embedded==1', {
+        'use_gconf%': 0,
+        'use_gio%': 0,
+      }, {
+        'use_gconf%': 1,
+        'use_gio%': 1,
+      }],
+
+      # Set up -D and -E flags passed into grit.
+      ['branding=="Chrome"', {
+        # TODO(mmoss) The .grd files look for _google_chrome, but for
+        # consistency they should look for google_chrome_build like C++.
+        'grit_defines': ['-D', '_google_chrome',
+                         '-E', 'CHROMIUM_BUILD=google_chrome'],
+      }, {
+        'grit_defines': ['-D', '_chromium',
+                         '-E', 'CHROMIUM_BUILD=chromium'],
+      }],
+      ['chromeos==1', {
+        'grit_defines': ['-D', 'chromeos', '-D', 'scale_factors=2x'],
+      }],
+      ['desktop_linux==1', {
+        'grit_defines': ['-D', 'desktop_linux'],
+      }],
+      ['toolkit_views==1', {
+        'grit_defines': ['-D', 'toolkit_views'],
+      }],
+      ['use_aura==1', {
+        'grit_defines': ['-D', 'use_aura'],
+      }],
+      ['use_ash==1', {
+        'grit_defines': ['-D', 'use_ash'],
+      }],
+      ['use_nss_certs==1', {
+        'grit_defines': ['-D', 'use_nss_certs'],
+      }],
+      ['use_ozone==1', {
+        'grit_defines': ['-D', 'use_ozone'],
+      }],
+      ['image_loader_extension==1', {
+        'grit_defines': ['-D', 'image_loader_extension'],
+      }],
+      ['remoting==1', {
+        'grit_defines': ['-D', 'remoting'],
+      }],
+      ['use_titlecase_in_grd==1', {
+        'grit_defines': ['-D', 'use_titlecase'],
+      }],
+      ['use_third_party_translations==1', {
+        'grit_defines': ['-D', 'use_third_party_translations'],
+        'locales': [
+          'ast', 'bs', 'ca@valencia', 'en-AU', 'eo', 'eu', 'gl', 'hy', 'ia',
+          'ka', 'ku', 'kw', 'ms', 'ug'
+        ],
+      }],
+      ['OS=="android"', {
+        'grit_defines': [
+          '-t', 'android',
+          '-E', 'ANDROID_JAVA_TAGGED_ONLY=true',
+          '--no-output-all-resource-defines',
+        ],
+      }],
+      ['OS=="mac" or OS=="ios"', {
+        'grit_defines': ['-D', 'scale_factors=2x'],
+      }],
+      ['OS == "ios"', {
+        'variables': {
+          'enable_coverage%': 0,
+        },
+        'grit_defines': [
+          '-t', 'ios',
+          '--no-output-all-resource-defines',
+        ],
+        # iOS uses a whitelist to filter resources.
+        'grit_whitelist%': '<(DEPTH)/build/ios/grit_whitelist.txt',
+
+        # Enable host builds when generating with ninja-ios.
+        'conditions': [
+          ['"<(GENERATOR)"=="ninja"', {
+            'host_os%': "mac",
+          }],
+
+          # Use the version of clang shipped with Xcode when building official
+          # version of Chrome for iOS.
+          #
+          # TODO(eugenebut): Remove enable_coverage check once
+          # libclang_rt.profile_ios.a is bundled with Chromium's clang.
+          # http://crbug.com/450379
+          ['buildtype=="Official" or enable_coverage', {
+            'clang_xcode%': 1,
+          }],
+        ],
+      }],
+      ['enable_extensions==1', {
+        'grit_defines': ['-D', 'enable_extensions'],
+      }],
+      ['enable_plugins!=0', {
+        'grit_defines': ['-D', 'enable_plugins'],
+      }],
+      ['enable_basic_printing==1 or enable_print_preview==1', {
+        'grit_defines': ['-D', 'enable_printing'],
+      }],
+      ['enable_print_preview==1', {
+        'grit_defines': ['-D', 'enable_print_preview'],
+      }],
+      ['enable_themes==1', {
+        'grit_defines': ['-D', 'enable_themes'],
+      }],
+      ['enable_app_list==1', {
+        'grit_defines': ['-D', 'enable_app_list'],
+      }],
+      ['enable_settings_app==1', {
+        'grit_defines': ['-D', 'enable_settings_app'],
+      }],
+      ['enable_google_now==1', {
+        'grit_defines': ['-D', 'enable_google_now'],
+      }],
+      ['use_concatenated_impulse_responses==1', {
+        'grit_defines': ['-D', 'use_concatenated_impulse_responses'],
+      }],
+      ['enable_media_router==1', {
+        'grit_defines': ['-D', 'enable_media_router'],
+      }],
+      ['enable_webrtc==1', {
+        'grit_defines': ['-D', 'enable_webrtc'],
+      }],
+      ['enable_hangout_services_extension==1', {
+        'grit_defines': ['-D', 'enable_hangout_services_extension'],
+      }],
+      ['enable_task_manager==1', {
+        'grit_defines': ['-D', 'enable_task_manager'],
+      }],
+      ['notifications==1', {
+        'grit_defines': ['-D', 'enable_notifications'],
+      }],
+      ['enable_wifi_bootstrapping==1', {
+        'grit_defines': ['-D', 'enable_wifi_bootstrapping'],
+      }],
+      ['mac_views_browser==1', {
+        'grit_defines': ['-D', 'mac_views_browser'],
+      }],
+      ['enable_resource_whitelist_generation==1 and OS!="win"', {
+        'grit_rc_header_format': ['-h', '#define {textual_id} _Pragma("whitelisted_resource_{numeric_id}") {numeric_id}'],
+      }],
+      ['enable_resource_whitelist_generation==1 and OS=="win"', {
+        'grit_rc_header_format': ['-h', '#define {textual_id} __pragma(message("whitelisted_resource_{numeric_id}")) {numeric_id}'],
+      }],
+      ['enable_mdns==1 or OS=="mac"', {
+        'grit_defines': ['-D', 'enable_service_discovery'],
+        'enable_service_discovery%': 1
+      }],
+      ['clang_use_chrome_plugins==1', {
+        'variables': {
+          'conditions': [
+            ['OS!="win"', {
+              'variables': {
+                'conditions': [
+                  ['OS=="mac" or OS=="ios"', {
+                    'clang_lib_path%': '<!(cd <(DEPTH) && pwd -P)/third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.dylib',
+                  }, { # OS != "mac" or OS != "ios"
+                    'clang_lib_path%': '<!(cd <(DEPTH) && pwd -P)/third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.so',
+                  }],
+                ],
+              },
+              'clang_dynlib_flags%': '-Xclang -load -Xclang <(clang_lib_path) ',
+              'clang_plugin_args%': '',
+            }, { # OS == "win"
+              # On Windows, the plugin is built directly into clang, so there's
+              # no need to load it dynamically.
+              'clang_dynlib_flags%': '',
+
+              # Don't error on plugin warnings on Windows until pre-existing warnings
+              # are cleaned up.  https://crbug.com/467287
+              'clang_plugin_args%': '-Xclang -plugin-arg-find-bad-constructs -Xclang warn-only',
+            }]
+          ],
+        },
+        # If you change these, also change build/config/clang/BUILD.gn.
+        'clang_chrome_plugins_flags%':
+          '<(clang_dynlib_flags)'
+          '-Xclang -add-plugin -Xclang find-bad-constructs '
+          '<(clang_plugin_args)',
+      }],
+      ['asan==1 or msan==1 or lsan==1 or tsan==1', {
+        'clang%': 1,
+        'use_allocator%': 'none',
+        'use_sanitizer_options%': 1,
+        # Disable ICF in the linker to avoid debug info loss.
+        'gold_icf_level%': 'none',
+      }],
+      ['asan==1 and OS=="linux" and chromeos==0', {
+        'use_custom_libcxx%': 1,
+      }],
+      ['ubsan==1', {
+        'clang%': 1,
+      }],
+      ['ubsan_vptr==1', {
+        'clang%': 1,
+      }],
+      ['asan==1 and OS=="mac"', {
+        'mac_strip_release': 1,
+      }],
+      ['tsan==1', {
+        'use_custom_libcxx%': 1,
+      }],
+      ['msan==1', {
+        # Use a just-built, MSan-instrumented libc++ instead of the system-wide
+        # libstdc++. This is required to avoid false positive reports whenever
+        # the C++ standard library is used.
+        'use_custom_libcxx%': 1,
+        # Running the V8-generated code on an ARM simulator is a powerful hack
+        # that allows the tool to see the memory accesses from JITted code.
+        # Without this flag, JS code causes false positive reports from MSan.
+        'v8_target_arch': 'arm64',
+      }],
+
+      ['OS=="linux" and clang_type_profiler==1', {
+        'clang%': 1,
+        'clang_use_chrome_plugins%': 0,
+        'conditions': [
+          ['host_arch=="x64"', {
+            'make_clang_dir%': 'third_party/llvm-allocated-type/Linux_x64',
+          }],
+          ['host_arch=="ia32"', {
+            # 32-bit Clang is unsupported.  It may not build.  Put your 32-bit
+            # Clang in this directory at your own risk if needed for some
+            # purpose (e.g. to compare 32-bit and 64-bit behavior like memory
+            # usage).  Any failure by this compiler should not close the tree.
+            'make_clang_dir%': 'third_party/llvm-allocated-type/Linux_ia32',
+          }],
+        ],
+      }],
+
+      ['OS=="win"', {
+        # The Blink GC plugin doesn't currently work on Windows.
+        # TODO(hans): One day, this will work. (crbug.com/82385)
+        'blink_gc_plugin%': 0,
+      }],
+
+      # On valgrind bots, override the optimizer settings so we don't inline too
+      # much and make the stacks harder to figure out.
+      #
+      # TODO(rnk): Kill off variables that no one else uses and just implement
+      # them under a build_for_tool== condition.
+      ['build_for_tool=="memcheck" or build_for_tool=="tsan"', {
+        # gcc flags
+        'mac_debug_optimization': '1',
+        'mac_release_optimization': '1',
+        'release_optimize': '1',
+        'no_gc_sections': 1,
+        'debug_extra_cflags': '-g -fno-inline -fno-omit-frame-pointer '
+                              '-fno-builtin -fno-optimize-sibling-calls',
+        'release_extra_cflags': '-g -fno-inline -fno-omit-frame-pointer '
+                                '-fno-builtin -fno-optimize-sibling-calls',
+
+        # MSVS flags for TSan on Pin and Windows.
+        'win_debug_RuntimeChecks': '0',
+        'win_debug_disable_iterator_debugging': '1',
+        'win_debug_Optimization': '1',
+        'win_debug_InlineFunctionExpansion': '0',
+        'win_release_InlineFunctionExpansion': '0',
+        'win_release_OmitFramePointers': '0',
+
+        'use_allocator': 'tcmalloc',
+        'release_valgrind_build': 1,
+        'werror': '',
+        'component': 'static_library',
+        'use_system_zlib': 0,
+      }],
+
+      # Build tweaks for DrMemory.
+      # TODO(rnk): Combine with tsan config to share the builder.
+      # http://crbug.com/108155
+      ['build_for_tool=="drmemory"', {
+        # These runtime checks force initialization of stack vars which blocks
+        # DrMemory's uninit detection.
+        'win_debug_RuntimeChecks': '0',
+        # Iterator debugging is slow.
+        'win_debug_disable_iterator_debugging': '1',
+        # Try to disable optimizations that mess up stacks in a release build.
+        # DrM-i#1054 (https://github.com/DynamoRIO/drmemory/issues/1054)
+        # /O2 and /Ob0 (disable inline) cannot be used together because of a
+        # compiler bug, so we use /Ob1 instead.
+        'win_release_InlineFunctionExpansion': '1',
+        'win_release_OmitFramePointers': '0',
+        # Ditto for debug, to support bumping win_debug_Optimization.
+        'win_debug_InlineFunctionExpansion': 0,
+        'win_debug_OmitFramePointers': 0,
+        # Keep the code under #ifndef NVALGRIND.
+        'release_valgrind_build': 1,
+      }],
+
+      # Enable RLZ on Win, Mac, iOS and ChromeOS.
+      ['branding=="Chrome" and (OS=="win" or OS=="mac" or OS=="ios" or chromeos==1)', {
+        'enable_rlz%': 1,
+      }],
+
+      # Set default compiler flags depending on ARM version.
+      ['arm_version==6', {
+        'arm_arch%': 'armv6',
+        'arm_tune%': '',
+        'arm_fpu%': 'vfp',
+        'arm_float_abi%': 'softfp',
+        'arm_thumb%': 0,
+      }],
+      ['arm_version==7', {
+        'arm_arch%': 'armv7-a',
+        'arm_tune%': 'generic-armv7-a',
+        'conditions': [
+          ['arm_neon==1', {
+            'arm_fpu%': 'neon',
+          }, {
+            'arm_fpu%': 'vfpv3-d16',
+          }],
+        ],
+        # Change the default to hard once the armhf transition is complete.
+        'arm_float_abi%': 'softfp',
+        'arm_thumb%': 1,
+      }],
+
+      # Set default compiler flags for MIPS floating-point support.
+      ['target_arch=="mipsel"', {
+        'mips_float_abi%': 'hard',
+      }],
+      ['target_arch=="mipsel" and mips_arch_variant=="r2"', {
+        'mips_fpu_mode%': 'fp32',
+      }],
+
+      # Enable brlapi by default for chromeos.
+      [ 'chromeos==1', {
+        'use_brlapi%': 1,
+      }],
+
+      ['use_ozone==1 and ozone_auto_platforms==1', {
+        # Use test as the default platform.
+        'ozone_platform%': 'test',
+
+        # Build all platforms whose deps are in install-build-deps.sh.
+        # Only these platforms will be compile tested by buildbots.
+        'ozone_platform_dri%': 1,
+        'ozone_platform_drm%': 1,
+        'ozone_platform_test%': 1,
+        'ozone_platform_egltest%': 1,
+      }],
+
+      ['desktop_linux==1 and use_aura==1 and use_x11==1', {
+        'use_clipboard_aurax11%': 1,
+      }],
+
+      ['OS=="win" and use_goma==1', {
+        # goma doesn't support pch yet.
+        'chromium_win_pch': 0,
+        # goma doesn't support PDB yet, so win_z7=1 or fastbuild=1.
+        'conditions': [
+          ['win_z7==0 and fastbuild==0', {
+            'fastbuild': 1,
+          }],
+        ],
+      }],
+
+      ['OS=="win" and (clang==1 or asan==1)', {
+        'chromium_win_pch': 0,
+      }],
+
+      ['host_clang==1', {
+        'host_cc': '<(make_clang_dir)/bin/clang',
+        'host_cxx': '<(make_clang_dir)/bin/clang++',
+      }, {
+        'host_cc': '<!(which gcc)',
+        'host_cxx': '<!(which g++)',
+      }],
+
+      # The seccomp-bpf sandbox is only supported on five architectures
+      # currently.
+      # Do not disable seccomp_bpf anywhere without talking to
+      # security@chromium.org!
+      ['((OS=="linux" or OS=="android") and '
+           '(target_arch=="ia32" or target_arch=="x64" or '
+             'target_arch=="arm" or target_arch=="mipsel" or '
+             'target_arch=="arm64"))', {
+         'use_seccomp_bpf%': 1,
+      }, {
+         'use_seccomp_bpf%': 0,
+      }],
+
+      ['cfi_vptr==1 or cfi_derived_cast==1 or cfi_unrelated_cast==1', {
+        'use_lto%': 1,
+      }],
+    ],
+
+    # The path to the ANGLE library.
+    'angle_path': '<(DEPTH)/third_party/angle',
+
+    # List of default apps to install in new profiles.  The first list contains
+    # the source files as found in svn.  The second list, used only for linux,
+    # contains the destination location for each of the files.  When a crx
+    # is added or removed from the list, the chrome/browser/resources/
+    # default_apps/external_extensions.json file must also be updated.
+    #
+    # README: GN version of these is in the target //chrome:default_apps
+    # (there's no global variable like in GYP). Be sure to update that target
+    # if you change these lists!
+    'default_apps_list': [
+      'browser/resources/default_apps/external_extensions.json',
+      'browser/resources/default_apps/gmail.crx',
+      'browser/resources/default_apps/search.crx',
+      'browser/resources/default_apps/youtube.crx',
+      'browser/resources/default_apps/drive.crx',
+      'browser/resources/default_apps/docs.crx',
+    ],
+    'default_apps_list_linux_dest': [
+      '<(PRODUCT_DIR)/default_apps/external_extensions.json',
+      '<(PRODUCT_DIR)/default_apps/gmail.crx',
+      '<(PRODUCT_DIR)/default_apps/search.crx',
+      '<(PRODUCT_DIR)/default_apps/youtube.crx',
+      '<(PRODUCT_DIR)/default_apps/drive.crx',
+      '<(PRODUCT_DIR)/default_apps/docs.crx',
+    ],
+
+    # Whether to allow building of the GPU-related isolates.
+    'archive_gpu_tests%': 0,
+
+     # Whether to allow building of chromoting related isolates.
+    'archive_chromoting_tests%': 0,
+  },
+  'target_defaults': {
+    'variables': {
+      # The condition that operates on chromium_code is in a target_conditions
+      # section, and will not have access to the default fallback value of
+      # chromium_code at the top of this file, or to the chromium_code
+      # variable placed at the root variables scope of .gyp files, because
+      # those variables are not set at target scope.  As a workaround,
+      # if chromium_code is not set at target scope, define it in target scope
+      # to contain whatever value it has during early variable expansion.
+      # That's enough to make it available during target conditional
+      # processing.
+      'chromium_code%': '<(chromium_code)',
+
+      'component%': '<(component)',
+
+      'chromecast%': '<(chromecast)',
+
+      # See http://msdn.microsoft.com/en-us/library/aa652360(VS.71).aspx
+      'win_release_Optimization%': '2', # 2 = /O2
+      'win_debug_Optimization%': '0',   # 0 = /Od
+
+      # See http://msdn.microsoft.com/en-us/library/2kxx5t2c(v=vs.80).aspx
+      # Tri-state: blank is default, 1 on, 0 off
+      'win_release_OmitFramePointers%': '0',
+      # Tri-state: blank is default, 1 on, 0 off
+      'win_debug_OmitFramePointers%': '',
+
+      # See http://msdn.microsoft.com/en-us/library/8wtf2dfz(VS.71).aspx
+      'win_debug_RuntimeChecks%': '3',    # 3 = all checks enabled, 0 = off
+
+      # See http://msdn.microsoft.com/en-us/library/47238hez(VS.71).aspx
+      'win_debug_InlineFunctionExpansion%': '',    # empty = default, 0 = off,
+      'win_release_InlineFunctionExpansion%': '2', # 1 = only __inline, 2 = max
+
+      # VS inserts quite a lot of extra checks to algorithms like
+      # std::partial_sort in Debug build which make them O(N^2)
+      # instead of O(N*logN). This is particularly slow under memory
+      # tools like ThreadSanitizer so we want it to be disablable.
+      # See http://msdn.microsoft.com/en-us/library/aa985982(v=VS.80).aspx
+      'win_debug_disable_iterator_debugging%': '0',
+
+      # An application manifest fragment to declare compatibility settings for
+      # 'executable' targets. Ignored in other target type.
+      'win_exe_compatibility_manifest%':
+          '<(DEPTH)\\build\\win\\compatibility.manifest',
+
+      'release_extra_cflags%': '',
+      'debug_extra_cflags%': '',
+
+      'release_valgrind_build%': '<(release_valgrind_build)',
+
+      # the non-qualified versions are widely assumed to be *nix-only
+      'win_release_extra_cflags%': '',
+      'win_debug_extra_cflags%': '',
+
+      # TODO(thakis): Make this a blacklist instead, http://crbug.com/101600
+      'enable_wexit_time_destructors%': '<(enable_wexit_time_destructors)',
+
+      # Only used by Windows build for now.  Can be used to build into a
+      # differet output directory, e.g., a build_dir_prefix of VS2010_ would
+      # output files in src/build/VS2010_{Debug,Release}.
+      'build_dir_prefix%': '',
+
+      # Targets are by default not nacl untrusted code.
+      'nacl_untrusted_build%': 0,
+
+      'pnacl_compile_flags': [
+        # pnacl uses the clang compiler so we need to suppress all the
+        # same warnings as we do for clang.
+        # TODO(sbc): Remove these if/when they are removed from the clang
+        # build.
+        '-Wno-unused-function',
+        '-Wno-char-subscripts',
+        '-Wno-c++11-extensions',
+        '-Wno-unnamed-type-template-args',
+      ],
+
+      # By default, Android targets have their exported JNI symbols stripped,
+      # so we test the manual JNI registration code paths that are required
+      # when using the crazy linker. To allow use of native JNI exports (lazily
+      # resolved by the JVM), targets can enable this variable, which will stop
+      # the stripping from happening. Only targets which do not need to be
+      # compatible with the crazy linker are permitted to set this.
+      'use_native_jni_exports%': 0,
+
+      'conditions': [
+        ['OS=="win" and component=="shared_library"', {
+          # See http://msdn.microsoft.com/en-us/library/aa652367.aspx
+          'win_release_RuntimeLibrary%': '2', # 2 = /MD (nondebug DLL)
+          'win_debug_RuntimeLibrary%': '3',   # 3 = /MDd (debug DLL)
+        }, {
+          # See http://msdn.microsoft.com/en-us/library/aa652367.aspx
+          'win_release_RuntimeLibrary%': '0', # 0 = /MT (nondebug static)
+          'win_debug_RuntimeLibrary%': '1',   # 1 = /MTd (debug static)
+        }],
+        ['OS=="ios"', {
+          # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html
+          'mac_release_optimization%': 's', # Use -Os unless overridden
+          'mac_debug_optimization%': '0',   # Use -O0 unless overridden
+        }, {
+          # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html
+          'mac_release_optimization%': '2', # Use -O2 unless overridden
+          'mac_debug_optimization%': '0',   # Use -O0 unless overridden
+        }],
+        ['OS=="android"', {
+          'host_os%': '<(host_os)',  # See comment above chromium_code.
+        }],
+      ],
+      'clang_warning_flags': [
+        '-Wheader-hygiene',
+
+        # Don't die on dtoa code that uses a char as an array index.
+        # This is required solely for base/third_party/dmg_fp/dtoa.cc.
+        '-Wno-char-subscripts',
+
+        # TODO(thakis): This used to be implied by -Wno-unused-function,
+        # which we no longer use. Check if it makes sense to remove
+        # this as well. http://crbug.com/316352
+        '-Wno-unneeded-internal-declaration',
+
+        # Warns on switches on enums that cover all enum values but
+        # also contain a default: branch. Chrome is full of that.
+        '-Wno-covered-switch-default',
+
+        # Warns when a const char[] is converted to bool.
+        '-Wstring-conversion',
+
+        # C++11-related flags:
+
+        # This warns on using ints as initializers for floats in
+        # initializer lists (e.g. |int a = f(); CGSize s = { a, a };|),
+        # which happens in several places in chrome code. Not sure if
+        # this is worth fixing.
+        '-Wno-c++11-narrowing',
+
+        # Clang considers the `register` keyword as deprecated, but e.g.
+        # code generated by flex (used in angle) contains that keyword.
+        # http://crbug.com/255186
+        '-Wno-deprecated-register',
+
+        # TODO(hans): Get this cleaned up.
+        '-Wno-inconsistent-missing-override',
+      ],
+    },
+    'includes': [ 'set_clang_warning_flags.gypi', ],
+    'defines': [
+      # Don't use deprecated V8 APIs anywhere.
+      'V8_DEPRECATION_WARNINGS',
+    ],
+    'include_dirs': [
+      '<(SHARED_INTERMEDIATE_DIR)',
+    ],
+    'conditions': [
+      ['(OS=="mac" or OS=="ios") and asan==1', {
+        'dependencies': [
+          '<(DEPTH)/build/mac/asan.gyp:asan_dynamic_runtime',
+        ],
+      }],
+      ['OS=="win" and asan==1 and component=="shared_library"', {
+        'dependencies': [
+          '<(DEPTH)/build/win/asan.gyp:asan_dynamic_runtime',
+        ],
+      }],
+      ['OS=="linux" and use_allocator!="none" and clang_type_profiler==1', {
+        'cflags_cc!': ['-fno-rtti'],
+        'cflags_cc+': [
+          '-frtti',
+          '-gline-tables-only',
+          '-fintercept-allocation-functions',
+        ],
+        'defines': ['TYPE_PROFILING'],
+        'dependencies': [
+          '<(DEPTH)/base/allocator/allocator.gyp:type_profiler',
+        ],
+      }],
+      ['branding=="Chrome"', {
+        'defines': ['GOOGLE_CHROME_BUILD'],
+      }, {  # else: branding!="Chrome"
+        'defines': ['CHROMIUM_BUILD'],
+      }],
+      ['OS=="mac" and component=="shared_library"', {
+        'xcode_settings': {
+          'DYLIB_INSTALL_NAME_BASE': '@rpath',
+          'LD_RUNPATH_SEARCH_PATHS': [
+            # For unbundled binaries.
+            '@loader_path/.',
+            # For bundled binaries, to get back from Binary.app/Contents/MacOS.
+            '@loader_path/../../..',
+          ],
+        },
+      }],
+      ['clang==1 or host_clang==1', {
+        # This is here so that all files get recompiled after a clang roll and
+        # when turning clang on or off.
+        # (defines are passed via the command line, and build systems rebuild
+        # things when their commandline changes). Nothing should ever read this
+        # define.
+        'defines': ['CR_CLANG_REVISION=<!(python <(DEPTH)/tools/clang/scripts/update.py --print-revision)'],
+      }],
+      ['enable_rlz==1', {
+        'defines': ['ENABLE_RLZ'],
+      }],
+      ['component=="shared_library"', {
+        'defines': ['COMPONENT_BUILD'],
+      }],
+      ['toolkit_views==1', {
+        'defines': ['TOOLKIT_VIEWS=1'],
+      }],
+      ['ui_compositor_image_transport==1', {
+        'defines': ['UI_COMPOSITOR_IMAGE_TRANSPORT'],
+      }],
+      ['use_aura==1', {
+        'defines': ['USE_AURA=1'],
+      }],
+      ['use_ash==1', {
+        'defines': ['USE_ASH=1'],
+      }],
+      ['use_pango==1', {
+        'defines': ['USE_PANGO=1'],
+      }],
+      ['use_cairo==1', {
+        'defines': ['USE_CAIRO=1'],
+      }],
+      ['use_cras==1', {
+        'defines': ['USE_CRAS=1'],
+      }],
+      ['use_ozone==1', {
+        'defines': ['USE_OZONE=1'],
+      }],
+      ['use_default_render_theme==1', {
+        'defines': ['USE_DEFAULT_RENDER_THEME=1'],
+      }],
+      ['use_libjpeg_turbo==1', {
+        'defines': ['USE_LIBJPEG_TURBO=1'],
+      }],
+      ['use_x11==1', {
+        'defines': ['USE_X11=1'],
+      }],
+      ['use_clipboard_aurax11==1', {
+        'defines': ['USE_CLIPBOARD_AURAX11=1'],
+      }],
+      ['enable_one_click_signin==1', {
+        'defines': ['ENABLE_ONE_CLICK_SIGNIN'],
+      }],
+      ['enable_pre_sync_backup==1', {
+        'defines': ['ENABLE_PRE_SYNC_BACKUP'],
+      }],
+      ['image_loader_extension==1', {
+        'defines': ['IMAGE_LOADER_EXTENSION=1'],
+      }],
+      ['profiling==1', {
+        'defines': ['ENABLE_PROFILING=1'],
+      }],
+      ['remoting==1', {
+        'defines': ['ENABLE_REMOTING=1'],
+      }],
+      ['enable_webrtc==1', {
+        'defines': ['ENABLE_WEBRTC=1'],
+      }],
+      ['enable_media_router==1', {
+        'defines': ['ENABLE_MEDIA_ROUTER=1'],
+      }],
+      ['proprietary_codecs==1', {
+        'defines': ['USE_PROPRIETARY_CODECS'],
+        'conditions': [
+          ['enable_mpeg2ts_stream_parser==1', {
+            'defines': ['ENABLE_MPEG2TS_STREAM_PARSER'],
+          }],
+        ],
+      }],
+      ['enable_viewport==1', {
+        'defines': ['ENABLE_VIEWPORT'],
+      }],
+      ['enable_pepper_cdms==1', {
+        'defines': ['ENABLE_PEPPER_CDMS'],
+      }],
+      ['enable_browser_cdms==1', {
+        'defines': ['ENABLE_BROWSER_CDMS'],
+      }],
+      ['configuration_policy==1', {
+        'defines': ['ENABLE_CONFIGURATION_POLICY'],
+      }],
+      ['notifications==1', {
+        'defines': ['ENABLE_NOTIFICATIONS'],
+      }],
+      ['enable_hidpi==1', {
+        'defines': ['ENABLE_HIDPI=1'],
+      }],
+      ['native_memory_pressure_signals==1', {
+        'defines': ['SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE'],
+      }],
+      ['use_udev==1', {
+        'defines': ['USE_UDEV'],
+      }],
+      ['fastbuild!=0', {
+        'xcode_settings': {
+          'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
+        },
+        'conditions': [
+          ['OS=="win" and fastbuild==2', {
+            # Completely disable debug information.
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'GenerateDebugInformation': 'false',
+              },
+              'VCCLCompilerTool': {
+                'DebugInformationFormat': '0',
+              },
+            },
+          }],
+          ['OS=="win" and fastbuild==1', {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                # This tells the linker to generate .pdbs, so that
+                # we can get meaningful stack traces.
+                'GenerateDebugInformation': 'true',
+              },
+              'VCCLCompilerTool': {
+                # No debug info to be generated by compiler.
+                'DebugInformationFormat': '0',
+              },
+            },
+          }],
+          ['(OS=="android" or OS=="linux") and fastbuild==2', {
+            'variables': { 'debug_extra_cflags': '-g0', },
+          }],
+          ['(OS=="android" or OS=="linux") and fastbuild==1', {
+            # TODO(thakis): Change this to -g1 once http://crbug.com/456947 is
+            # fixed.
+            'variables': { 'debug_extra_cflags': '-g0', },
+          }],
+          # Android builds symbols on release by default, disable them.
+          ['OS=="android" and fastbuild==2', {
+            'variables': { 'release_extra_cflags': '-g0', },
+          }],
+          ['OS=="android" and fastbuild==1', {
+            # TODO(thakis): Change this to -g1 once http://crbug.com/456947 is
+            # fixed.
+            'variables': { 'release_extra_cflags': '-g0', },
+          }],
+        ],
+      }],  # fastbuild!=0
+      ['dont_embed_build_metadata==1', {
+        'defines': [
+          'DONT_EMBED_BUILD_METADATA',
+        ],
+      }],  # dont_embed_build_metadata==1
+      ['dcheck_always_on!=0', {
+        'defines': ['DCHECK_ALWAYS_ON=1'],
+      }],  # dcheck_always_on!=0
+      ['tracing_like_official_build!=0', {
+        'defines': ['TRACING_IS_OFFICIAL_BUILD=1'],
+      }],  # tracing_like_official_build!=0
+      ['OS=="win"', {
+        'defines': ['NO_TCMALLOC'],
+        'conditions': [
+          ['win_use_allocator_shim==1', {
+            'defines': ['ALLOCATOR_SHIM'],
+          }],
+        ],
+      }],
+      ['asan==1', {
+        'defines': [
+          'ADDRESS_SANITIZER',
+          'MEMORY_TOOL_REPLACES_ALLOCATOR',
+          'MEMORY_SANITIZER_INITIAL_SIZE',
+        ],
+      }],
+      ['syzyasan==1', {
+        # SyzyAsan needs /PROFILE turned on to produce appropriate pdbs.
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'Profile': 'true',
+          },
+        },
+        'defines': [
+            'SYZYASAN',
+            'MEMORY_TOOL_REPLACES_ALLOCATOR',
+            'MEMORY_SANITIZER_INITIAL_SIZE',
+        ],
+      }],
+      ['kasko==1', {
+        'defines': [
+            'KASKO',
+        ],
+        'include_dirs': [
+          '<(DEPTH)/third_party/kasko/include',
+        ],
+      }],
+      ['OS=="win"', {
+        'defines': [
+          '__STD_C',
+          '_CRT_SECURE_NO_DEPRECATE',
+          '_SCL_SECURE_NO_DEPRECATE',
+          # This define is required to pull in the new Win8 interfaces from
+          # system headers like ShObjIdl.h.
+          'NTDDI_VERSION=0x06030000',
+          # This is required for ATL to use XP-safe versions of its functions.
+          '_USING_V110_SDK71_',
+        ],
+        'include_dirs': [
+          '<(DEPTH)/third_party/wtl/include',
+        ],
+        'conditions': [
+          ['win_z7!=0', {
+            'msvs_settings': {
+              # Generates debug info when win_z7=1
+              # even if fastbuild=1 (that makes GenerateDebugInformation false).
+              'VCLinkerTool': {
+                'GenerateDebugInformation': 'true',
+              },
+              'VCCLCompilerTool': {
+                'DebugInformationFormat': '1',
+              }
+            }
+          }],  # win_z7!=0
+          ['win_analyze', {
+            'defines!': [
+              # This is prohibited when running /analyze.
+              '_USING_V110_SDK71_',
+            ],
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                # Set WarnAsError to false to disable this setting for most
+                # projects so that compilation continues.
+                'WarnAsError': 'false',
+                # When win_analyze is specified add the /analyze switch.
+                # Also add /WX- to force-disable WarnAsError for projects that
+                # override WarnAsError.
+                # Also, disable various noisy warnings that have low value.
+                'AdditionalOptions': [
+                  '/analyze',
+                  '/WX-',
+                  '/wd6011',  # Dereferencing NULL pointer
+                  '/wd6312',  # Possible infinite loop: use of the constant
+                    # EXCEPTION_CONTINUE_EXECUTION in the exception-filter
+                  '/wd6326',  # Potential comparison of constant with constant
+                  '/wd28159', # Consider using 'GetTickCount64'
+                  '/wd28204', # Inconsistent SAL annotations
+                  '/wd28251', # Inconsistent SAL annotations
+                  '/wd28252', # Inconsistent SAL annotations
+                  '/wd28253', # Inconsistent SAL annotations
+                  '/wd28196', # The precondition is not satisfied
+                  '/wd28301', # Inconsistent SAL annotations
+                  '/wd6340',  # Sign mismatch in function parameter
+                  '/wd28182', # Dereferencing NULL pointer
+                  # C6285 is ~16% of raw warnings and has low value
+                  '/wd6285',  # non-zero constant || non-zero constant
+                  # C6334 is ~80% of raw warnings and has low value
+                  '/wd6334',  # sizeof applied to an expression with an operator
+                ],
+              },
+            },
+          }],  # win_analyze
+        ],
+      }],  # OS==win
+      ['chromecast==1', {
+        'defines': [
+          'LOG_DISABLED=0',
+        ],
+        'conditions': [
+          ['use_playready==1', {
+            'defines': [
+              'PLAYREADY_CDM_AVAILABLE',
+            ],
+          }],
+        ],
+      }],
+      ['enable_task_manager==1', {
+        'defines': [
+          'ENABLE_TASK_MANAGER=1',
+        ],
+      }],
+      ['enable_extensions==1', {
+        'defines': [
+          'ENABLE_EXTENSIONS=1',
+        ],
+      }],
+      ['OS=="win" and branding=="Chrome"', {
+        'defines': ['ENABLE_SWIFTSHADER'],
+      }],
+      ['enable_dart==1', {
+        'defines': ['WEBKIT_USING_DART=1'],
+      }],
+      ['enable_plugin_installation==1', {
+        'defines': ['ENABLE_PLUGIN_INSTALLATION=1'],
+      }],
+      ['enable_plugins==1', {
+        'defines': ['ENABLE_PLUGINS=1'],
+      }],
+      ['enable_session_service==1', {
+        'defines': ['ENABLE_SESSION_SERVICE=1'],
+      }],
+      ['enable_themes==1', {
+        'defines': ['ENABLE_THEMES=1'],
+      }],
+      ['enable_autofill_dialog==1', {
+        'defines': ['ENABLE_AUTOFILL_DIALOG=1'],
+      }],
+      ['enable_prod_wallet_service==1', {
+        'defines': ['ENABLE_PROD_WALLET_SERVICE=1'],
+      }],
+      ['enable_background==1', {
+        'defines': ['ENABLE_BACKGROUND=1'],
+      }],
+      ['enable_google_now==1', {
+        'defines': ['ENABLE_GOOGLE_NOW=1'],
+      }],
+      ['cld_version!=0', {
+        'defines': ['CLD_VERSION=<(cld_version)'],
+      }],
+      ['enable_basic_printing==1 or enable_print_preview==1', {
+        # Convenience define for ENABLE_BASIC_PRINTING || ENABLE_PRINT_PREVIEW.
+        'defines': ['ENABLE_PRINTING=1'],
+      }],
+      ['enable_basic_printing==1', {
+        # Enable basic printing support and UI.
+        'defines': ['ENABLE_BASIC_PRINTING=1'],
+      }],
+      ['enable_print_preview==1', {
+        # Enable printing with print preview.
+        # Can be defined without ENABLE_BASIC_PRINTING.
+        'defines': ['ENABLE_PRINT_PREVIEW=1'],
+      }],
+      ['enable_spellcheck==1', {
+        'defines': ['ENABLE_SPELLCHECK=1'],
+      }],
+      ['enable_captive_portal_detection==1', {
+        'defines': ['ENABLE_CAPTIVE_PORTAL_DETECTION=1'],
+      }],
+      ['enable_app_list==1', {
+        'defines': ['ENABLE_APP_LIST=1'],
+      }],
+      ['enable_settings_app==1', {
+        'defines': ['ENABLE_SETTINGS_APP=1'],
+      }],
+      ['disable_file_support==1', {
+        'defines': ['DISABLE_FILE_SUPPORT=1'],
+      }],
+      ['disable_ftp_support==1', {
+        'defines': ['DISABLE_FTP_SUPPORT=1'],
+      }],
+      ['enable_supervised_users==1', {
+        'defines': ['ENABLE_SUPERVISED_USERS=1'],
+      }],
+      ['spdy_proxy_auth_property != ""', {
+        'defines': ['SPDY_PROXY_AUTH_PROPERTY="<(spdy_proxy_auth_property)"'],
+      }],
+      ['spdy_proxy_auth_value != ""', {
+        'defines': ['SPDY_PROXY_AUTH_VALUE="<(spdy_proxy_auth_value)"'],
+      }],
+      ['enable_mdns==1', {
+        'defines': ['ENABLE_MDNS=1'],
+      }],
+      ['enable_service_discovery==1', {
+        'defines' : [ 'ENABLE_SERVICE_DISCOVERY=1' ],
+      }],
+      ['enable_wifi_bootstrapping==1', {
+        'defines' : [ 'ENABLE_WIFI_BOOTSTRAPPING=1' ],
+      }],
+      ['enable_hangout_services_extension==1', {
+        'defines': ['ENABLE_HANGOUT_SERVICES_EXTENSION=1'],
+      }],
+      ['enable_ipc_fuzzer==1', {
+        'defines': ['ENABLE_IPC_FUZZER=1'],
+      }],
+      ['video_hole==1', {
+        'defines': ['VIDEO_HOLE=1'],
+      }],
+      ['v8_use_external_startup_data==1', {
+       'defines': ['V8_USE_EXTERNAL_STARTUP_DATA'],
+      }],
+
+      # SAFE_BROWSING_SERVICE - browser manages a safe-browsing service.
+      # SAFE_BROWSING_DB_LOCAL - service manages a local database.
+      # SAFE_BROWSING_DB_REMOTE - service talks via API to a database
+      # SAFE_BROWSING_CSD - enable client-side phishing detection.
+      ['safe_browsing==1', {
+        # TODO(nparker): Remove existing uses of FULL_SAFE_BROWSING
+        'defines': [
+          'FULL_SAFE_BROWSING',
+          'SAFE_BROWSING_CSD',
+          'SAFE_BROWSING_DB_LOCAL',
+          'SAFE_BROWSING_SERVICE',
+        ],
+      }],
+      ['safe_browsing==2', {
+        'defines': [
+          # TODO(nparker): Remove existing uses of MOBILE_SAFE_BROWSING
+          'MOBILE_SAFE_BROWSING',
+          'SAFE_BROWSING_SERVICE',
+        ],
+      }],
+    ],  # conditions for 'target_defaults'
+    'target_conditions': [
+      ['<(use_libpci)==1', {
+        'defines': ['USE_LIBPCI=1'],
+      }],
+      ['<(use_openssl)==1', {
+        'defines': ['USE_OPENSSL=1'],
+      }],
+      ['<(use_openssl_certs)==1', {
+        'defines': ['USE_OPENSSL_CERTS=1'],
+      }],
+      ['>(nacl_untrusted_build)==1', {
+        'defines': [
+          'USE_OPENSSL=1',
+          'USE_OPENSSL_CERTS=1',
+        ],
+      }],
+      ['<(use_glib)==1 and >(nacl_untrusted_build)==0', {
+        'defines': ['USE_GLIB=1'],
+      }],
+      ['<(use_nss_certs)==1 and >(nacl_untrusted_build)==0', {
+        'defines': ['USE_NSS_CERTS=1'],
+      }],
+      ['<(chromeos)==1 and >(nacl_untrusted_build)==0', {
+        'defines': ['OS_CHROMEOS=1'],
+      }],
+      ['enable_wexit_time_destructors==1 and OS!="win"', {
+        # TODO: Enable on Windows too, http://crbug.com/404525
+        'variables': { 'clang_warning_flags': ['-Wexit-time-destructors']},
+      }],
+      ['chromium_code==0', {
+        'conditions': [
+          [ 'os_posix==1 and OS!="mac" and OS!="ios"', {
+            # We don't want to get warnings from third-party code,
+            # so remove any existing warning-enabling flags like -Wall.
+            'cflags!': [
+              '-Wall',
+              '-Wextra',
+            ],
+            'cflags_cc': [
+              # Don't warn about hash_map in third-party code.
+              '-Wno-deprecated',
+            ],
+            'cflags': [
+              # Don't warn about printf format problems.
+              # This is off by default in gcc but on in Ubuntu's gcc(!).
+              '-Wno-format',
+            ],
+            'cflags_cc!': [
+              # Necessary because llvm.org/PR10448 is WONTFIX (crbug.com/90453).
+              '-Wsign-compare',
+            ]
+          }],
+          # TODO: Fix all warnings on chromeos too.
+          [ 'os_posix==1 and OS!="mac" and OS!="ios" and (clang!=1 or chromeos==1)', {
+            'cflags!': [
+              '-Werror',
+            ],
+          }],
+          [ 'os_posix==1 and os_bsd!=1 and OS!="mac" and OS!="android"', {
+            'cflags': [
+              # Don't warn about ignoring the return value from e.g. close().
+              # This is off by default in some gccs but on by default in others.
+              # BSD systems do not support this option, since they are usually
+              # using gcc 4.2.1, which does not have this flag yet.
+              '-Wno-unused-result',
+            ],
+          }],
+          [ 'OS=="win"', {
+            'defines': [
+              '_CRT_SECURE_NO_DEPRECATE',
+              '_CRT_NONSTDC_NO_WARNINGS',
+              '_CRT_NONSTDC_NO_DEPRECATE',
+              '_SCL_SECURE_NO_DEPRECATE',
+            ],
+            'msvs_disabled_warnings': [
+              # These are variable shadowing warnings that are new in VS2015.
+              # We should probably work through these at some point for
+              # non-chromium code, but for now, focus on chromium_code==1 code.
+              4456, 4457, 4458, 4459,
+
+              4800,
+            ],
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'WarningLevel': '3',
+                'WarnAsError': 'true',
+                'Detect64BitPortabilityProblems': 'false',
+              },
+            },
+            'conditions': [
+              ['buildtype=="Official"', {
+                'msvs_settings': {
+                  'VCCLCompilerTool': { 'WarnAsError': 'false' },
+                }
+              }],
+              [ 'component=="shared_library"', {
+              # TODO(darin): Unfortunately, some third_party code depends on base.
+                'msvs_disabled_warnings': [
+                  4251,  # class 'std::xx' needs to have dll-interface.
+                 ],
+              }],
+            ],
+          }],
+
+          [ 'OS=="mac" or OS=="ios"', {
+            'xcode_settings': {
+              'WARNING_CFLAGS!': ['-Wall', '-Wextra'],
+            },
+            'conditions': [
+              ['buildtype=="Official"', {
+                'xcode_settings': {
+                  'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO',    # -Werror
+                },
+              }],
+            ],
+          }],
+          [ 'OS=="ios"', {
+            'xcode_settings': {
+              # TODO(ios): Fix remaining warnings in third-party code, then
+              # remove this; the Mac cleanup didn't get everything that's
+              # flagged in an iOS build.
+              'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO',
+              'RUN_CLANG_STATIC_ANALYZER': 'NO',
+              # Several internal ios directories generate numerous warnings for
+              # -Wobjc-missing-property-synthesis.
+              'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'NO',
+            },
+          }],
+        ],
+      }, {
+        'includes': [
+           # Rules for excluding e.g. foo_win.cc from the build on non-Windows.
+          'filename_rules.gypi',
+        ],
+        # In Chromium code, we define __STDC_foo_MACROS in order to get the
+        # C99 macros on Mac and Linux.
+        'defines': [
+          '__STDC_CONSTANT_MACROS',
+          '__STDC_FORMAT_MACROS',
+        ],
+        'conditions': [
+          ['OS=="win"', {
+            # turn on warnings for signed/unsigned mismatch on chromium code.
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': ['/we4389'],
+              },
+            },
+          }],
+          ['OS=="win" and component=="shared_library"', {
+            'msvs_disabled_warnings': [
+              4251,  # class 'std::xx' needs to have dll-interface.
+            ],
+          }],
+        ],
+      }],
+    ],  # target_conditions for 'target_defaults'
+    'default_configuration': 'Debug',
+    'configurations': {
+      # VCLinkerTool LinkIncremental values below:
+      #   0 == default
+      #   1 == /INCREMENTAL:NO
+      #   2 == /INCREMENTAL
+      # Debug links incremental, Release does not.
+      #
+      # Abstract base configurations to cover common attributes.
+      #
+      'Common_Base': {
+        'abstract': 1,
+        'msvs_configuration_attributes': {
+          'OutputDirectory': '<(DEPTH)\\build\\<(build_dir_prefix)$(ConfigurationName)',
+          'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
+          'CharacterSet': '1',
+        },
+        # Add the default import libs.
+        'msvs_settings':{
+          'VCLinkerTool': {
+            'AdditionalDependencies': [
+              'kernel32.lib',
+              'gdi32.lib',
+              'winspool.lib',
+              'comdlg32.lib',
+              'advapi32.lib',
+              'shell32.lib',
+              'ole32.lib',
+              'oleaut32.lib',
+              'user32.lib',
+              'uuid.lib',
+              'odbc32.lib',
+              'odbccp32.lib',
+              'delayimp.lib',
+              'credui.lib',
+              'netapi32.lib',
+            ],
+            'AdditionalOptions': [
+              # Suggested by Microsoft Devrel to avoid
+              #   LINK : fatal error LNK1248: image size (80000000) exceeds maximum allowable size (80000000)
+              # which started happening more regularly after VS2013 Update 4.
+              # Needs to be a bit lower for VS2015, or else errors out.
+              '/maxilksize:0x7ff00000',
+            ],
+          },
+        },
+      },
+      'x86_Base': {
+        'abstract': 1,
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'MinimumRequiredVersion': '5.01',  # XP.
+            'TargetMachine': '1',
+          },
+          'VCLibrarianTool': {
+            'TargetMachine': '1',
+          },
+        },
+        'msvs_configuration_platform': 'Win32',
+      },
+      'x64_Base': {
+        'abstract': 1,
+        'msvs_configuration_platform': 'x64',
+        'msvs_settings': {
+          'VCLinkerTool': {
+            # Make sure to understand http://crbug.com/361720 if you want to
+            # increase this.
+            'MinimumRequiredVersion': '5.02',  # Server 2003.
+            'TargetMachine': '17', # x86 - 64
+            'AdditionalLibraryDirectories!':
+              ['<(windows_sdk_path)/Lib/win8/um/x86'],
+            'AdditionalLibraryDirectories':
+              ['<(windows_sdk_path)/Lib/win8/um/x64'],
+            # Doesn't exist x64 SDK. Should use oleaut32 in any case.
+            'IgnoreDefaultLibraryNames': [ 'olepro32.lib' ],
+          },
+          'VCLibrarianTool': {
+            'AdditionalLibraryDirectories!':
+              ['<(windows_sdk_path)/Lib/win8/um/x86'],
+            'AdditionalLibraryDirectories':
+              ['<(windows_sdk_path)/Lib/win8/um/x64'],
+            'TargetMachine': '17', # x64
+          },
+        },
+      },
+      'Debug_Base': {
+        'abstract': 1,
+        'defines': [
+          'DYNAMIC_ANNOTATIONS_ENABLED=1',
+          'WTF_USE_DYNAMIC_ANNOTATIONS=1',
+        ],
+        'xcode_settings': {
+          'GCC_OPTIMIZATION_LEVEL': '<(mac_debug_optimization)',
+          'OTHER_CFLAGS': [
+            '<@(debug_extra_cflags)',
+          ],
+        },
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'Optimization': '<(win_debug_Optimization)',
+            'PreprocessorDefinitions': ['_DEBUG'],
+            'BasicRuntimeChecks': '<(win_debug_RuntimeChecks)',
+            'RuntimeLibrary': '<(win_debug_RuntimeLibrary)',
+            'conditions': [
+              # According to MSVS, InlineFunctionExpansion=0 means
+              # "default inlining", not "/Ob0".
+              # Thus, we have to handle InlineFunctionExpansion==0 separately.
+              ['win_debug_InlineFunctionExpansion==0', {
+                'AdditionalOptions': ['/Ob0'],
+              }],
+              ['win_debug_InlineFunctionExpansion!=""', {
+                'InlineFunctionExpansion':
+                  '<(win_debug_InlineFunctionExpansion)',
+              }],
+              ['win_debug_disable_iterator_debugging==1', {
+                'PreprocessorDefinitions': ['_HAS_ITERATOR_DEBUGGING=0'],
+              }],
+
+              # if win_debug_OmitFramePointers is blank, leave as default
+              ['win_debug_OmitFramePointers==1', {
+                'OmitFramePointers': 'true',
+              }],
+              ['win_debug_OmitFramePointers==0', {
+                'OmitFramePointers': 'false',
+                # The above is not sufficient (http://crbug.com/106711): it
+                # simply eliminates an explicit "/Oy", but both /O2 and /Ox
+                # perform FPO regardless, so we must explicitly disable.
+                # We still want the false setting above to avoid having
+                # "/Oy /Oy-" and warnings about overriding.
+                'AdditionalOptions': ['/Oy-'],
+              }],
+            ],
+            'AdditionalOptions': [ '<@(win_debug_extra_cflags)', ],
+          },
+          'VCLinkerTool': {
+            'LinkIncremental': '<(msvs_debug_link_incremental)',
+            # ASLR makes debugging with windbg difficult because Chrome.exe and
+            # Chrome.dll share the same base name. As result, windbg will
+            # name the Chrome.dll module like chrome_<base address>, where
+            # <base address> typically changes with each launch. This in turn
+            # means that breakpoints in Chrome.dll don't stick from one launch
+            # to the next. For this reason, we turn ASLR off in debug builds.
+            # Note that this is a three-way bool, where 0 means to pick up
+            # the default setting, 1 is off and 2 is on.
+            'RandomizedBaseAddress': 1,
+          },
+          'VCResourceCompilerTool': {
+            'PreprocessorDefinitions': ['_DEBUG'],
+          },
+        },
+        'conditions': [
+          ['OS=="linux" or OS=="android"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '<@(debug_extra_cflags)',
+                ],
+              }],
+            ],
+          }],
+          ['OS=="linux" and target_arch!="ia32" and disable_glibcxx_debug==0', {
+            # Enable libstdc++ debugging facilities to help catch problems
+            # early, see http://crbug.com/65151 .
+            # TODO(phajdan.jr): Should we enable this for all of POSIX?
+            'defines': ['_GLIBCXX_DEBUG=1',],
+          }],
+          ['release_valgrind_build==0', {
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fstack-protector-all',  # Implies -fstack-protector
+              ],
+            },
+          }],
+          ['clang==1', {
+            'cflags': [
+              # Allow comparing the address of references and 'this' against 0
+              # in debug builds. Technically, these can never be null in
+              # well-defined C/C++ and Clang can optimize such checks away in
+              # release builds, but they may be used in asserts in debug builds.
+              '-Wno-undefined-bool-conversion',
+              '-Wno-tautological-undefined-compare',
+            ],
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-Wno-undefined-bool-conversion',
+                '-Wno-tautological-undefined-compare',
+              ],
+            },
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-Wno-undefined-bool-conversion',
+                  '-Wno-tautological-undefined-compare',
+                ],
+              },
+            },
+          }],
+        ],
+      },
+      'Release_Base': {
+        'abstract': 1,
+        'defines': [
+          'NDEBUG',
+        ],
+        'xcode_settings': {
+          'DEAD_CODE_STRIPPING': 'YES',  # -Wl,-dead_strip
+          'GCC_OPTIMIZATION_LEVEL': '<(mac_release_optimization)',
+          'OTHER_CFLAGS': [ '<@(release_extra_cflags)', ],
+        },
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'RuntimeLibrary': '<(win_release_RuntimeLibrary)',
+            'conditions': [
+              # In official builds, each target will self-select
+              # an optimization level.
+              ['buildtype!="Official"', {
+                  'Optimization': '<(win_release_Optimization)',
+                },
+              ],
+              # According to MSVS, InlineFunctionExpansion=0 means
+              # "default inlining", not "/Ob0".
+              # Thus, we have to handle InlineFunctionExpansion==0 separately.
+              ['win_release_InlineFunctionExpansion==0', {
+                'AdditionalOptions': ['/Ob0'],
+              }],
+              ['win_release_InlineFunctionExpansion!=""', {
+                'InlineFunctionExpansion':
+                  '<(win_release_InlineFunctionExpansion)',
+              }],
+
+              # if win_release_OmitFramePointers is blank, leave as default
+              ['win_release_OmitFramePointers==1', {
+                'OmitFramePointers': 'true',
+              }],
+              ['win_release_OmitFramePointers==0', {
+                'OmitFramePointers': 'false',
+                # The above is not sufficient (http://crbug.com/106711): it
+                # simply eliminates an explicit "/Oy", but both /O2 and /Ox
+                # perform FPO regardless, so we must explicitly disable.
+                # We still want the false setting above to avoid having
+                # "/Oy /Oy-" and warnings about overriding.
+                'AdditionalOptions': ['/Oy-'],
+              }],
+              ['asan==0', {
+                # Put data in separate COMDATs. This allows the linker
+                # to put bit-identical constants at the same address even if
+                # they're unrelated constants, which saves binary size.
+                # This optimization can't be used when ASan is enabled because
+                # it is not compatible with the ASan ODR checker.
+                'AdditionalOptions': ['/Gw'],
+              }],
+            ],
+            'AdditionalOptions': [
+                '/d2Zi+',  # Improve debugging of Release builds.
+                '/Zc:inline',  # Remove unreferenced COMDAT (faster links).
+                '<@(win_release_extra_cflags)',
+            ],
+          },
+          'VCLinkerTool': {
+            # LinkIncremental is a tri-state boolean, where 0 means default
+            # (i.e., inherit from parent solution), 1 means false, and
+            # 2 means true.
+            'LinkIncremental': '1',
+            # This corresponds to the /PROFILE flag which ensures the PDB
+            # file contains FIXUP information (growing the PDB file by about
+            # 5%) but does not otherwise alter the output binary. This
+            # information is used by the Syzygy optimization tool when
+            # decomposing the release image.
+            'Profile': 'true',
+          },
+        },
+        'conditions': [
+          ['msvs_use_common_release', {
+            'includes': ['release.gypi'],
+          }],
+          ['release_valgrind_build==0 and tsan==0', {
+            'defines': [
+              'NVALGRIND',
+              'DYNAMIC_ANNOTATIONS_ENABLED=0',
+            ],
+          }, {
+            'defines': [
+              'MEMORY_TOOL_REPLACES_ALLOCATOR',
+              'MEMORY_SANITIZER_INITIAL_SIZE',
+              'DYNAMIC_ANNOTATIONS_ENABLED=1',
+              'WTF_USE_DYNAMIC_ANNOTATIONS=1',
+            ],
+          }],
+          ['OS=="win"', {
+            'defines': ['NO_TCMALLOC'],
+          }],
+          # _FORTIFY_SOURCE isn't really supported by Clang now, see
+          # http://llvm.org/bugs/show_bug.cgi?id=16821.
+          # It seems to work fine with Ubuntu 12 headers though, so use it
+          # in official builds.
+          ['os_posix==1 and (asan!=1 and msan!=1 and tsan!=1 and lsan!=1 and ubsan!=1) and (OS!="linux" or clang!=1 or buildtype=="Official")', {
+            'target_conditions': [
+              ['chromium_code==1', {
+                # Non-chromium code is not guaranteed to compile cleanly
+                # with _FORTIFY_SOURCE. Also, fortified build may fail
+                # when optimizations are disabled, so only do that for Release
+                # build.
+                'defines': [
+                  '_FORTIFY_SOURCE=2',
+                ],
+              }],
+            ],
+          }],
+          ['OS=="linux" or OS=="android"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '<@(release_extra_cflags)',
+                ],
+                'conditions': [
+                  ['enable_resource_whitelist_generation==1', {
+                    'cflags': [
+                      '-Wunknown-pragmas -Wno-error=unknown-pragmas',
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+          ['OS=="ios"', {
+            'defines': [
+              'NS_BLOCK_ASSERTIONS=1',
+            ],
+          }],
+        ],
+      },
+      #
+      # Concrete configurations
+      #
+      'Debug': {
+        'inherit_from': ['Common_Base', 'x86_Base', 'Debug_Base'],
+      },
+      'Release': {
+        'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'],
+      },
+      'conditions': [
+        [ 'OS=="ios"', {
+          'Profile': {
+            'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'],
+            'target_conditions': [
+              [ '_type=="executable"', {
+                # To get a real .dSYM bundle produced by dsymutil, set the
+                # debug information format to dwarf-with-dsym.  Since
+                # strip_from_xcode will not be used, set Xcode to do the
+                # stripping as well.
+                'xcode_settings': {
+                  'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+                  'DEPLOYMENT_POSTPROCESSING': 'YES',
+                  'STRIP_INSTALLED_PRODUCT': 'YES',
+                },
+              }],
+            ],
+          },
+        }],
+        [ 'OS=="win"', {
+          # TODO(bradnelson): add a gyp mechanism to make this more graceful.
+          'Debug_x64': {
+            'inherit_from': ['Common_Base', 'x64_Base', 'Debug_Base'],
+          },
+          'Release_x64': {
+            'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base'],
+          },
+        }],
+      ],
+    },
+  },
+  'conditions': [
+    ['os_posix==1', {
+      'target_defaults': {
+        'ldflags': [
+          '-Wl,-z,now',
+          '-Wl,-z,relro',
+        ],
+        # TODO(glider): enable the default options on other systems.
+        'conditions': [
+          ['use_sanitizer_options==1 and ((OS=="linux" and (chromeos==0 or target_arch!="ia32")) or OS=="mac")', {
+            'dependencies': [
+              '<(DEPTH)/build/sanitizers/sanitizers.gyp:sanitizer_options',
+            ],
+          }],
+        ],
+      },
+    }],
+    # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
+    ['os_posix==1 and disable_fatal_linker_warnings==0 and use_evdev_gestures==0 and (chromeos==0 or target_arch!="arm")', {
+      'target_defaults': {
+        'ldflags': [
+          '-Wl,--fatal-warnings',
+        ],
+      },
+    }],
+    # -Wl,-z,-defs doesn't work with the sanitiziers, http://crbug.com/452065
+    ['(OS=="linux" or OS=="android") and asan==0 and msan==0 and tsan==0 and ubsan==0 and ubsan_vptr==0', {
+      'target_defaults': {
+        'ldflags': [
+          '-Wl,-z,defs',
+        ],
+      },
+    }],
+    ['os_posix==1 and chromeos==0', {
+      # Chrome OS enables -fstack-protector-strong via its build wrapper,
+      # and we want to avoid overriding this, so stack-protector is only
+      # enabled when not building on Chrome OS.
+      # TODO(phajdan.jr): Use -fstack-protector-strong when our gcc
+      # supports it.
+      'target_defaults': {
+        'cflags': [
+          '-fstack-protector',
+          '--param=ssp-buffer-size=4',
+        ],
+      },
+    }],
+    ['os_posix==1 and OS!="mac" and OS!="ios"', {
+      'target_defaults': {
+        # Enable -Werror by default, but put it in a variable so it can
+        # be disabled in ~/.gyp/include.gypi on the valgrind builders.
+        'variables': {
+          'werror%': '-Werror',
+          'libraries_for_target%': '',
+        },
+        'defines': [
+          '_FILE_OFFSET_BITS=64',
+        ],
+        'cflags': [
+          '<(werror)',  # See note above about the werror variable.
+          '-pthread',
+          '-fno-strict-aliasing',  # See http://crbug.com/32204
+          '-Wall',
+          # Don't warn about unused function params.  We use those everywhere.
+          '-Wno-unused-parameter',
+          # Don't warn about the "struct foo f = {0};" initialization pattern.
+          '-Wno-missing-field-initializers',
+          # Don't export any symbols (for example, to plugins we dlopen()).
+          # Note: this is *required* to make some plugins work.
+          '-fvisibility=hidden',
+          '-pipe',
+        ],
+        'cflags_cc': [
+          '-fno-exceptions',
+          '-fno-rtti',
+          '-fno-threadsafe-statics',
+          # Make inline functions have hidden visiblity by default.
+          # Surprisingly, not covered by -fvisibility=hidden.
+          '-fvisibility-inlines-hidden',
+          # GCC turns on -Wsign-compare for C++ under -Wall, but clang doesn't,
+          # so we specify it explicitly.  (llvm.org/PR10448, crbug.com/90453)
+          '-Wsign-compare',
+        ],
+        'ldflags': [
+          '-pthread', '-Wl,-z,noexecstack',
+        ],
+        'libraries' : [
+          '<(libraries_for_target)',
+        ],
+        'configurations': {
+          'Debug_Base': {
+            'variables': {
+              'debug_optimize%': '0',
+            },
+            'defines': [
+              '_DEBUG',
+            ],
+            'cflags': [
+              '-O>(debug_optimize)',
+              '-g',
+              '-gdwarf-4',
+            ],
+            'conditions' : [
+              ['OS=="android" and target_arch!="mipsel" and target_arch!="mips64el"', {
+                # TODO(jdduke) Re-enable on mips after resolving linking
+                # issues with libc++ (crbug.com/456380).
+                'ldflags': [
+                  # Warn in case of text relocations.
+                  '-Wl,--warn-shared-textrel',
+                ],
+              }],
+              ['OS=="android" and android_full_debug==0', {
+                # Some configurations are copied from Release_Base to reduce
+                # the binary size.
+                'variables': {
+                  'debug_optimize%': 's',
+                },
+                'cflags': [
+                  '-fdata-sections',
+                  '-ffunction-sections',
+                ],
+                'ldflags': [
+                  '-Wl,-O1',
+                  '-Wl,--as-needed',
+                ],
+              }],
+              ['OS=="android" and android_full_debug==0 and target_arch!="arm64"', {
+                # We don't omit frame pointers on arm64 since they are required
+                # to correctly unwind stackframes which contain system library
+                # function frames (crbug.com/391706).
+                'cflags': [
+                  '-fomit-frame-pointer',
+                ],
+              }],
+              ['OS!="android"', {
+                'defines': [
+                  '_LARGEFILE_SOURCE',
+                  '_LARGEFILE64_SOURCE',
+                ],
+              }],
+              ['OS=="linux" and target_arch=="ia32"', {
+                'ldflags': [
+                  '-Wl,--no-as-needed',
+                ],
+              }],
+              ['debug_unwind_tables==1', {
+                'cflags': ['-funwind-tables'],
+              }, {
+                'cflags': ['-fno-unwind-tables', '-fno-asynchronous-unwind-tables'],
+                'defines': ['NO_UNWIND_TABLES'],
+              }],
+              # TODO(mostynb): shuffle clang/gcc_version/binutils_version
+              # definitions in to the right scope to use them when setting
+              # linux_use_debug_fission, so it can be used here alone.
+              ['linux_use_debug_fission==1 and linux_use_gold_flags==1 and (clang==1 or gcc_version>=48) and binutils_version>=223', {
+                'cflags': ['-gsplit-dwarf'],
+              }],
+            ],
+          },
+          'Release_Base': {
+            'variables': {
+              'release_optimize%': '2',
+              # Binaries become big and gold is unable to perform GC
+              # and remove unused sections for some of test targets
+              # on 32 bit platform.
+              # (This is currently observed only in chromeos valgrind bots)
+              # The following flag is to disable --gc-sections linker
+              # option for these bots.
+              'no_gc_sections%': 0,
+
+              # TODO(bradnelson): reexamine how this is done if we change the
+              # expansion of configurations
+              'release_valgrind_build%': 0,
+            },
+            'cflags': [
+              '-O<(release_optimize)',
+              # Don't emit the GCC version ident directives, they just end up
+              # in the .comment section taking up binary size.
+              '-fno-ident',
+              # Put data and code in their own sections, so that unused symbols
+              # can be removed at link time with --gc-sections.
+              '-fdata-sections',
+              '-ffunction-sections',
+            ],
+            'ldflags': [
+              # Specifically tell the linker to perform optimizations.
+              # See http://lwn.net/Articles/192624/ .
+              '-Wl,-O1',
+              '-Wl,--as-needed',
+            ],
+            'conditions' : [
+              ['no_gc_sections==0', {
+                'ldflags': [
+                  '-Wl,--gc-sections',
+                ],
+              }],
+              ['OS=="android" and target_arch!="arm64"', {
+                # We don't omit frame pointers on arm64 since they are required
+                # to correctly unwind stackframes which contain system library
+                # function frames (crbug.com/391706).
+                'cflags': [
+                  '-fomit-frame-pointer',
+                ]
+              }],
+              ['OS=="android" and target_arch!="mipsel" and target_arch!="mips64el"', {
+                # TODO(jdduke) Re-enable on mips after resolving linking
+                # issues with libc++ (crbug.com/456380).
+                'ldflags': [
+                  # Warn in case of text relocations.
+                  '-Wl,--warn-shared-textrel',
+                ],
+              }],
+              ['OS=="android"', {
+                'variables': {
+                  'release_optimize%': 's',
+                },
+              }],
+              ['profiling==1', {
+                'cflags': [
+                  '-fno-omit-frame-pointer',
+                  '-g',
+                ],
+                'conditions' : [
+                  ['profiling_full_stack_frames==1', {
+                    'cflags': [
+                      '-fno-inline',
+                      '-fno-optimize-sibling-calls',
+                    ],
+                  }],
+                ],
+              }],
+              ['release_unwind_tables==1', {
+                'cflags': ['-funwind-tables'],
+              }, {
+                'cflags': ['-fno-unwind-tables', '-fno-asynchronous-unwind-tables'],
+                'defines': ['NO_UNWIND_TABLES'],
+              }],
+            ],
+          },
+        },
+        'conditions': [
+          ['target_arch=="ia32"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'asflags': [
+                  # Needed so that libs with .s files (e.g. libicudata.a)
+                  # are compatible with the general 32-bit-ness.
+                  '-32',
+                ],
+                # All floating-point computations on x87 happens in 80-bit
+                # precision.  Because the C and C++ language standards allow
+                # the compiler to keep the floating-point values in higher
+                # precision than what's specified in the source and doing so
+                # is more efficient than constantly rounding up to 64-bit or
+                # 32-bit precision as specified in the source, the compiler,
+                # especially in the optimized mode, tries very hard to keep
+                # values in x87 floating-point stack (in 80-bit precision)
+                # as long as possible. This has important side effects, that
+                # the real value used in computation may change depending on
+                # how the compiler did the optimization - that is, the value
+                # kept in 80-bit is different than the value rounded down to
+                # 64-bit or 32-bit. There are possible compiler options to
+                # make this behavior consistent (e.g. -ffloat-store would keep
+                # all floating-values in the memory, thus force them to be
+                # rounded to its original precision) but they have significant
+                # runtime performance penalty.
+                #
+                # -mfpmath=sse -msse2 makes the compiler use SSE instructions
+                # which keep floating-point values in SSE registers in its
+                # native precision (32-bit for single precision, and 64-bit
+                # for double precision values). This means the floating-point
+                # value used during computation does not change depending on
+                # how the compiler optimized the code, since the value is
+                # always kept in its specified precision.
+                #
+                # Refer to http://crbug.com/348761 for rationale behind SSE2
+                # being a minimum requirement for 32-bit Linux builds and
+                # http://crbug.com/313032 for an example where this has "bit"
+                # us in the past.
+                'cflags': [
+                  '-msse2',
+                  '-mfpmath=sse',
+                  '-mmmx',  # Allows mmintrin.h for MMX intrinsics.
+                  '-m32',
+                ],
+                'ldflags': [
+                  '-m32',
+                ],
+                'conditions': [
+                  # Use gold linker for Android ia32 target.
+                  ['OS=="android"', {
+                    'ldflags': [
+                      '-fuse-ld=gold',
+                    ],
+                  }],
+                  # Install packages have started cropping up with
+                  # different headers between the 32-bit and 64-bit
+                  # versions, so we have to shadow those differences off
+                  # and make sure a 32-bit-on-64-bit build picks up the
+                  # right files.
+                  # For android build, use NDK headers instead of host headers
+                  ['host_arch!="ia32" and OS!="android"', {
+                    'include_dirs+': [
+                      '/usr/include32',
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+          ['target_arch=="x64"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'conditions': [
+                  # Use gold linker for Android x64 target.
+                  ['OS=="android"', {
+                    'ldflags': [
+                      '-fuse-ld=gold',
+                    ],
+                  }],
+                ],
+                'cflags': [
+                  '-m64',
+                  '-march=x86-64',
+                ],
+                'ldflags': [
+                  '-m64',
+                ],
+              }],
+            ],
+          }],
+          ['target_arch=="arm"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'conditions': [
+                  ['clang==0', {
+                    'cflags_cc': [
+                      # The codesourcery arm-2009q3 toolchain warns at that the ABI
+                      # has changed whenever it encounters a varargs function. This
+                      # silences those warnings, as they are not helpful and
+                      # clutter legitimate warnings.
+                      '-Wno-abi',
+                    ],
+                  }],
+                  ['clang==1 and arm_arch!="" and OS!="android"', {
+                    'cflags': [
+                      '-target arm-linux-gnueabihf',
+                    ],
+                    'ldflags': [
+                      '-target arm-linux-gnueabihf',
+                    ],
+                  }],
+                  ['arm_arch!=""', {
+                    'cflags': [
+                      '-march=<(arm_arch)',
+                    ],
+                    'conditions': [
+                      ['use_lto==1 or use_lto_o2==1', {
+                        'ldflags': [
+                          '-march=<(arm_arch)',
+                        ],
+                      }],
+                    ],
+                  }],
+                  ['clang==1 and OS!="android"', {
+                    'cflags': [
+                      # We need to disable clang's builtin assembler as it can't
+                      # handle several asm files, crbug.com/124610
+                      '-no-integrated-as',
+                    ],
+                  }],
+                  ['arm_tune!=""', {
+                    'cflags': [
+                      '-mtune=<(arm_tune)',
+                    ],
+                    'conditions': [
+                      ['use_lto==1 or use_lto_o2==1', {
+                        'ldflags': [
+                          '-mtune=<(arm_tune)',
+                        ],
+                      }],
+                    ],
+                  }],
+                  ['arm_fpu!=""', {
+                    'cflags': [
+                      '-mfpu=<(arm_fpu)',
+                    ],
+                    'conditions': [
+                      ['use_lto==1 or use_lto_o2==1', {
+                        'ldflags': [
+                          '-mfpu=<(arm_fpu)',
+                        ],
+                      }],
+                    ],
+                  }],
+                  ['arm_float_abi!=""', {
+                    'cflags': [
+                      '-mfloat-abi=<(arm_float_abi)',
+                    ],
+                    'conditions': [
+                      ['use_lto==1 or use_lto_o2==1', {
+                        'ldflags': [
+                          '-mfloat-abi=<(arm_float_abi)',
+                        ],
+                      }],
+                    ],
+                  }],
+                  ['arm_thumb==1', {
+                    'cflags': [
+                      '-mthumb',
+                    ],
+                    'conditions': [
+                      ['use_lto==1 or use_lto_o2==1', {
+                        'ldflags': [
+                          '-mthumb',
+                        ],
+                      }],
+                    ],
+                  }],
+                  ['OS=="android"', {
+                    # Most of the following flags are derived from what Android
+                    # uses by default when building for arm, reference for which
+                    # can be found in the following file in the Android NDK:
+                    # toolchains/arm-linux-androideabi-4.9/setup.mk
+                    'cflags': [
+                      # The tree-sra optimization (scalar replacement for
+                      # aggregates enabling subsequent optimizations) leads to
+                      # invalid code generation when using the Android NDK's
+                      # compiler (r5-r7). This can be verified using
+                      # webkit_unit_tests' WTF.Checked_int8_t test.
+                      '-fno-tree-sra',
+                      # The following option is disabled to improve binary
+                      # size and performance in gcc 4.9.
+                      '-fno-caller-saves',
+                      '-Wno-psabi',
+                    ],
+                    # Android now supports .relro sections properly.
+                    # NOTE: While these flags enable the generation of .relro
+                    # sections, the generated libraries can still be loaded on
+                    # older Android platform versions.
+                    'ldflags': [
+                        '-Wl,-z,relro',
+                        '-Wl,-z,now',
+                        '-fuse-ld=gold',
+                    ],
+                    'conditions': [
+                      ['gcc_version==48 and clang==0', {
+                        'cflags': [
+                          # The following 5 options are disabled to save on
+                          # binary size in GCC 4.8.
+                          '-fno-partial-inlining',
+                          '-fno-early-inlining',
+                          '-fno-tree-copy-prop',
+                          '-fno-tree-loop-optimize',
+                          '-fno-move-loop-invariants',
+                        ],
+                      }],
+                      ['arm_thumb==1', {
+                        'cflags': [ '-mthumb-interwork' ],
+                      }],
+                      ['profiling==1', {
+                        'cflags': [
+                          # Thumb code with frame pointer makes chrome crash
+                          # early.
+                          '-marm',
+                          '-mapcs-frame', # Required by -fno-omit-frame-pointer.
+                          # The perf report sometimes incorrectly attributes
+                          # code from tail calls.
+                          '-fno-optimize-sibling-calls',
+                        ],
+                        'cflags!': [
+                          '-fomit-frame-pointer',
+                        ],
+                      }],
+                      ['clang==1', {
+                        'cflags!': [
+                          # Clang does not support the following options.
+                          '-mapcs-frame',
+                          '-mthumb-interwork',
+                          '-finline-limit=64',
+                          '-fno-tree-sra',
+                          '-fno-caller-saves',
+                          '-Wno-psabi',
+                        ],
+                        'cflags': [
+                          # TODO(hans) Enable integrated-as (crbug.com/124610).
+                          '-no-integrated-as',
+                          '-B<(android_toolchain)',  # Else /usr/bin/as gets picked up.
+                        ],
+                      }],
+                      ['clang==1 and linux_use_bundled_gold==0', {
+                        'ldflags': [
+                          # Let clang find the ld.gold in the NDK.
+                          '--gcc-toolchain=<(android_toolchain)/..',
+                        ],
+                      }],
+                      ['asan==1', {
+                        'cflags': [
+                          '-marm', # Required for frame pointer based stack traces.
+                        ],
+                      }],
+                    ],
+                  }],
+                  ['chromecast==1', {
+                    'cflags': [
+                      # We set arm_arch to "" so that -march compiler option
+                      # is not set.  Otherwise a gcc bug that would complain
+                      # about it conflicting with '-mcpu=cortex-a9'. The flag
+                      # '-march=armv7-a' is actually redundant anyway because
+                      # it is enabled by default when we built the toolchain.
+                      # And using '-mcpu=cortex-a9' should be sufficient.
+                      '-mcpu=cortex-a9',
+                      '-funwind-tables',
+                      # Breakpad requires symbols with debugging information
+                      '-g',
+                    ],
+                    'ldflags': [
+                      # We want to statically link libstdc++/libgcc_s.
+                      '-static-libstdc++',
+                      '-static-libgcc',
+                    ],
+                    'cflags!': [
+                      # Some components in Chromium (e.g. v8, skia, ffmpeg)
+                      # define their own cflags for arm builds that could
+                      # conflict with the flags we set here (e.g.
+                      # '-mcpu=cortex-a9'). Remove these flags explicitly.
+                      '-march=armv7-a',
+                      '-mtune=cortex-a8',
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+          ['target_arch=="arm64"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'conditions': [
+                  ['OS=="android"', {
+                    'cflags!': [
+                       '-fstack-protector',  # stack protector is always enabled on arm64.
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+          ['target_arch=="mipsel"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'conditions': [
+                  ['mips_arch_variant=="r6"', {
+                    'conditions': [
+                      ['clang==1', {
+                        'cflags': [ '-target mipsel-linux-gnu', '-march=mips32r6', ],
+                        'ldflags': [ '-target mipsel-linux-gnu', ],
+                      }, { # clang==0
+                        'cflags': ['-mips32r6', '-Wa,-mips32r6', ],
+                      }],
+                      ['clang==0 and OS=="android"', {
+                        'ldflags': ['-mips32r6', '-Wl,-melf32ltsmip',],
+                      }],
+                    ],
+                  }],
+                  ['mips_arch_variant=="r2"', {
+                    'conditions': [
+                      ['mips_float_abi=="hard" and mips_fpu_mode!=""', {
+                        'cflags': ['-m<(mips_fpu_mode)'],
+                      }],
+                      ['clang==1', {
+                         'conditions': [
+                          ['OS=="android"', {
+                            'cflags': [ '-target mipsel-linux-android', '-march=mipsel', '-mcpu=mips32r2'],
+                            'ldflags': [ '-target mipsel-linux-android', ],
+                          }],
+                         ],
+                      }, { # clang==0
+                        'cflags': ['-mips32r2', '-Wa,-mips32r2', ],
+                      }],
+                    ],
+                  }],
+                  ['mips_arch_variant=="r1"', {
+                    'conditions': [
+                      ['clang==1', {
+                        'conditions': [
+                          ['OS=="android"', {
+                            'cflags': [ '-target mipsel-linux-android', '-march=mipsel', '-mcpu=mips32'],
+                            'ldflags': [ '-target mipsel-linux-android', ],
+                          }],
+                        ],
+                      }, { # clang==0
+                        'cflags': ['-mips32', '-Wa,-mips32', ],
+                      }],
+                    ],
+                  }],
+                  ['clang==1', {
+                    'cflags!': [
+                      # Clang does not support the following options.
+                      '-finline-limit=64',
+                    ],
+                    'cflags': [
+                      # TODO(gordanac) Enable integrated-as.
+                      '-no-integrated-as',
+                      '-B<(android_toolchain)',  # Else /usr/bin/as gets picked up.
+                    ],
+                    'ldflags': [
+                      # Let clang find the ld in the NDK.
+                      '--gcc-toolchain=<(android_toolchain)/..',
+                    ],
+                  }],
+                  ['mips_dsp_rev==1', {
+                    'cflags': ['-mdsp'],
+                  }],
+                  ['mips_dsp_rev==2', {
+                    'cflags': ['-mdspr2'],
+                  }],
+                ],
+                'cflags': [
+                  '-m<(mips_float_abi)-float'
+                ],
+                'ldflags': [
+                  '-Wl,--no-keep-memory'
+                ],
+                'cflags_cc': [
+                  '-Wno-uninitialized',
+                ],
+              }],
+            ],
+          }],
+          ['target_arch=="mips64el"', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'conditions': [
+                  ['mips_arch_variant=="r6"', {
+                    'cflags': ['-mips64r6', '-Wa,-mips64r6'],
+                    'ldflags': ['-mips64r6'],
+                  }],
+                  ['mips_arch_variant=="r2"', {
+                    'cflags': ['-mips64r2', '-Wa,-mips64r2'],
+                    'ldflags': ['-mips64r2'],
+                  }],
+                ],
+                'cflags_cc': [
+                  '-Wno-uninitialized',
+                ],
+              }],
+            ],
+          }],
+          ['linux_fpic==1', {
+            'cflags': [
+              '-fPIC',
+            ],
+            'ldflags': [
+              '-fPIC',
+            ],
+          }],
+          ['sysroot!=""', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '--sysroot=<(sysroot)',
+                ],
+                'ldflags': [
+                  '--sysroot=<(sysroot)',
+                  '<!(<(DEPTH)/build/linux/sysroot_ld_path.sh <(sysroot))',
+                ],
+              }]]
+          }],
+          ['clang==1', {
+            'cflags': [
+              # TODO(thakis): Remove, http://crbug.com/263960
+              '-Wno-reserved-user-defined-literal',
+            ],
+            'cflags_cc': [
+              # gnu++11 instead of c++11 is needed because some code uses
+              # typeof() (a GNU extension).
+              # TODO(thakis): Eventually switch this to c++11 instead,
+              # http://crbug.com/427584
+              '-std=gnu++11',
+            ],
+          }],
+          ['clang==0 and host_clang==1', {
+            'target_conditions': [
+              ['_toolset=="host"', {
+                'cflags_cc': [ '-std=gnu++11', ],
+              }],
+            ],
+          }],
+          ['clang==1 and clang_use_chrome_plugins==1', {
+            'cflags': [
+              '<@(clang_chrome_plugins_flags)',
+            ],
+          }],
+          ['clang==1 and clang_load!=""', {
+            'cflags': [
+              '-Xclang', '-load', '-Xclang', '<(clang_load)',
+            ],
+          }],
+          ['clang==1 and clang_add_plugin!=""', {
+            'cflags': [
+              '-Xclang', '-add-plugin', '-Xclang', '<(clang_add_plugin)',
+            ],
+          }],
+          ['clang==1 and target_arch=="ia32"', {
+            'cflags': [
+              # Else building libyuv gives clang's register allocator issues,
+              # see llvm.org/PR15798 / crbug.com/233709
+              '-momit-leaf-frame-pointer',
+              # Align the stack on 16-byte boundaries, http://crbug.com/418554.
+              '-mstack-alignment=16',
+              '-mstackrealign',
+            ],
+          }],
+          ['clang==1 and "<(GENERATOR)"=="ninja"', {
+            'cflags': [
+              # See http://crbug.com/110262
+              '-fcolor-diagnostics',
+            ],
+          }],
+          # Common options for AddressSanitizer, LeakSanitizer,
+          # ThreadSanitizer and MemorySanitizer.
+          ['asan==1 or lsan==1 or tsan==1 or msan==1 or ubsan==1 or ubsan_vptr==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fno-omit-frame-pointer',
+                  '-gline-tables-only',
+                ],
+                'cflags!': [
+                  '-fomit-frame-pointer',
+                ],
+              }],
+            ],
+          }],
+          ['asan==1 or lsan==1 or tsan==1 or msan==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'ldflags!': [
+                  # Functions interposed by the sanitizers can make ld think
+                  # that some libraries aren't needed when they actually are,
+                  # http://crbug.com/234010. As workaround, disable --as-needed.
+                  '-Wl,--as-needed',
+                ],
+                'defines': [
+                  'MEMORY_TOOL_REPLACES_ALLOCATOR',
+                  'MEMORY_SANITIZER_INITIAL_SIZE',
+                ],
+              }],
+            ],
+          }],
+          ['asan==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize=address',
+                  # TODO(earthdok): Re-enable. http://crbug.com/427202
+                  #'-fsanitize-blacklist=<(asan_blacklist)',
+                ],
+                'ldflags': [
+                  '-fsanitize=address',
+                ],
+              }],
+            ],
+            'conditions': [
+              ['OS=="mac"', {
+                'cflags': [
+                  '-mllvm -asan-globals=0',  # http://crbug.com/352073
+                ],
+              }],
+            ],
+          }],
+          ['ubsan==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize=undefined',
+                  '-fsanitize-blacklist=<(ubsan_blacklist)',
+                  # Employ the experimental PBQP register allocator to avoid
+                  # slow compilation on files with too many basic blocks.
+                  # See http://crbug.com/426271.
+                  '-mllvm -regalloc=pbqp',
+                  # Speculatively use coalescing to slightly improve the code
+                  # generated by PBQP regallocator. May increase compile time.
+                  '-mllvm -pbqp-coalescing',
+                ],
+                'cflags_cc!': [
+                  '-fno-rtti',
+                ],
+                'cflags!': [
+                  '-fno-rtti',
+                ],
+                'ldflags': [
+                  '-fsanitize=undefined',
+                ],
+                'defines': [
+                  'UNDEFINED_SANITIZER',
+                ],
+              }],
+            ],
+          }],
+          ['ubsan_vptr==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize=vptr',
+                  '-fsanitize-blacklist=<(ubsan_blacklist)',
+                ],
+                'cflags_cc!': [
+                  '-fno-rtti',
+                ],
+                'cflags!': [
+                  '-fno-rtti',
+                ],
+                'ldflags': [
+                  '-fsanitize=vptr',
+                ],
+                'defines': [
+                  'UNDEFINED_SANITIZER',
+                ],
+              }],
+            ],
+          }],
+          ['asan_coverage!=0 and sanitizer_coverage==0', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize-coverage=<(asan_coverage)',
+                ],
+                'defines': [
+                  'SANITIZER_COVERAGE',
+                ],
+              }],
+            ],
+          }],
+          ['sanitizer_coverage!=0', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize-coverage=<(sanitizer_coverage)',
+                ],
+                'defines': [
+                  'SANITIZER_COVERAGE',
+                ],
+              }],
+            ],
+          }],
+          ['asan_field_padding!=0', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize-address-field-padding=<(asan_field_padding)',
+                ],
+              }],
+            ],
+          }],
+          ['lsan==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize=leak',
+                ],
+                'ldflags': [
+                  '-fsanitize=leak',
+                ],
+                'defines': [
+                  'LEAK_SANITIZER',
+                  'WTF_USE_LEAK_SANITIZER=1',
+                ],
+              }],
+            ],
+          }],
+          ['tsan==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize=thread',
+                  '-fsanitize-blacklist=<(tsan_blacklist)',
+                ],
+                'ldflags': [
+                  '-fsanitize=thread',
+                ],
+                'defines': [
+                  'THREAD_SANITIZER',
+                  'DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL=1',
+                  'WTF_USE_DYNAMIC_ANNOTATIONS_NOIMPL=1',
+                ],
+              }],
+            ],
+          }],
+          ['msan==1', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize=memory',
+                  '-fsanitize-memory-track-origins=<(msan_track_origins)',
+                  '-fsanitize-blacklist=<(msan_blacklist)',
+                ],
+                'ldflags': [
+                  '-fsanitize=memory',
+                ],
+                'defines': [
+                  'MEMORY_SANITIZER',
+                ],
+              }],
+            ],
+          }],
+          ['use_instrumented_libraries==1', {
+            'dependencies': [
+              '<(DEPTH)/third_party/instrumented_libraries/instrumented_libraries.gyp:instrumented_libraries',
+            ],
+          }],
+          ['use_prebuilt_instrumented_libraries==1', {
+            'dependencies': [
+              '<(DEPTH)/third_party/instrumented_libraries/instrumented_libraries.gyp:prebuilt_instrumented_libraries',
+            ],
+          }],
+          ['use_custom_libcxx==1', {
+            'dependencies': [
+              '<(DEPTH)/buildtools/third_party/libc++/libc++.gyp:libcxx_proxy',
+            ],
+          }],
+          ['order_profiling!=0 and (chromeos==1 or OS=="linux" or OS=="android")', {
+            'target_conditions' : [
+              # crazy_linker has an upstream gyp file we can't edit, and we
+              # don't want to instrument it.
+              ['_toolset=="target" and _target_name!="crazy_linker"', {
+                'cflags': [
+                  '-finstrument-functions',
+                  # Allow mmx intrinsics to inline, so that the
+                  #0 compiler can expand the intrinsics.
+                  '-finstrument-functions-exclude-file-list=mmintrin.h',
+                ],
+              }],
+              ['_toolset=="target" and OS=="android"', {
+                'cflags': [
+                  # Avoids errors with current NDK:
+                  # "third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/include/arm_neon.h:3426:3: error: argument must be a constant"
+                  '-finstrument-functions-exclude-file-list=arm_neon.h,SaturatedArithmeticARM.h',
+                ],
+              }],
+            ],
+          }],
+          ['linux_dump_symbols==1', {
+            'cflags': [ '-g' ],
+            'conditions': [
+              ['OS=="linux" and host_arch=="ia32" and linux_use_bundled_gold==0', {
+                'target_conditions': [
+                  ['_toolset=="target"', {
+                    'ldflags': [
+                      # Attempt to use less memory to prevent the linker from
+                      # running out of address space. Considering installing a
+                      # 64-bit kernel and switching to a 64-bit linker.
+                      '-Wl,--no-keep-memory',
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+          ['use_allocator!="tcmalloc"', {
+            'defines': ['NO_TCMALLOC'],
+          }],
+          ['linux_use_gold_flags==1', {
+            # Newer gccs and clangs support -fuse-ld, use the flag to force gold
+            # selection.
+            # gcc -- http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Optimize-Options.html
+            'ldflags': [ '-fuse-ld=gold', ],
+
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'ldflags': [
+                  # Experimentation found that using four linking threads
+                  # saved ~20% of link time.
+                  # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
+                  # Only apply this to the target linker, since the host
+                  # linker might not be gold, but isn't used much anyway.
+                  # TODO(raymes): Disable threading because gold is frequently
+                  # crashing on the bots: crbug.com/161942.
+                  # '-Wl,--threads',
+                  # '-Wl,--thread-count=4',
+                ],
+                'conditions': [
+                  # TODO(thestig): Enable this for disabled cases.
+                  [ 'buildtype!="Official" and chromeos==0 and release_valgrind_build==0 and asan==0 and lsan==0 and tsan==0 and msan==0 and ubsan==0 and ubsan_vptr==0', {
+                    'ldflags': [
+                      '-Wl,--detect-odr-violations',
+                    ],
+                  }],
+                ],
+              }],
+            ],
+            'conditions': [
+              ['release_valgrind_build==0 and order_profiling==0', {
+                'target_conditions': [
+                  ['_toolset=="target"', {
+                    'ldflags': [
+                      '-Wl,--icf=<(gold_icf_level)',
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+          ['linux_use_bundled_binutils==1', {
+            'cflags': [
+              '-B<!(cd <(DEPTH) && pwd -P)/<(binutils_dir)',
+            ],
+          }],
+          ['linux_use_bundled_gold==1 and '
+           'not (clang==0 and (use_lto==1 or use_lto_o2==1))', {
+            # Put our binutils, which contains gold in the search path. We pass
+            # the path to gold to the compiler. gyp leaves unspecified what the
+            # cwd is when running the compiler, so the normal gyp path-munging
+            # fails us. This hack gets the right path.
+            #
+            # Disabled when using GCC LTO because GCC also uses the -B search
+            # path at link time to find "as", and our bundled "as" can only
+            # target x86.
+            'ldflags': [
+              '-B<!(cd <(DEPTH) && pwd -P)/<(binutils_dir)',
+            ],
+          }],
+          # Some binutils 2.23 releases may or may not have new dtags enabled,
+          # but they are all compatible with --disable-new-dtags,
+          # because the new dynamic tags are not created by default.
+          ['binutils_version>=223', {
+            # Newer binutils don't set DT_RPATH unless you disable "new" dtags
+            # and the new DT_RUNPATH doesn't work without --no-as-needed flag.
+            # FIXME(mithro): Figure out the --as-needed/--no-as-needed flags
+            # inside this file to allow usage of --no-as-needed and removal of
+            # this flag.
+            'ldflags': [
+              '-Wl,--disable-new-dtags',
+            ],
+          }],
+          ['gcc_version>=47 and clang==0', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags_cc': [
+                  '-std=gnu++11',
+                  # See comment for -Wno-c++11-narrowing.
+                  '-Wno-narrowing',
+                  # TODO(thakis): Remove, http://crbug.com/263960
+                  '-Wno-literal-suffix',
+                ],
+              }],
+            ],
+          }],
+          ['host_gcc_version>=47 and clang==0 and host_clang==0', {
+            'target_conditions': [
+              ['_toolset=="host"', {
+                'cflags_cc': [
+                  '-std=gnu++11',
+                  # See comment for -Wno-c++11-narrowing.
+                  '-Wno-narrowing',
+                  # TODO(thakis): Remove, http://crbug.com/263960
+                  '-Wno-literal-suffix',
+                ],
+              }],
+            ],
+          }],
+        ],
+      },
+    }],
+    # FreeBSD-specific options; note that most FreeBSD options are set above,
+    # with Linux.
+    ['OS=="freebsd"', {
+      'target_defaults': {
+        'ldflags': [
+          '-Wl,--no-keep-memory',
+        ],
+      },
+    }],
+    # Android-specific options; note that most are set above with Linux.
+    ['OS=="android"', {
+      'variables': {
+        # This is a unique identifier for a given build. It's used for
+        # identifying various build artifacts corresponding to a particular
+        # build of chrome (e.g. where to find archived symbols).
+        'chrome_build_id%': '',
+        'conditions': [
+          # Figure this out early since it needs symbols from libgcc.a, so it
+          # has to be before that in the set of libraries.
+          ['component=="shared_library"', {
+              'android_libcpp_library': 'c++_shared',
+          }, {
+              'android_libcpp_library': 'c++_static',
+          }],
+        ],
+
+        # Placing this variable here prevents from forking libvpx, used
+        # by remoting.  Remoting is off, so it needn't built,
+        # so forking it's deps seems like overkill.
+        # But this variable need defined to properly run gyp.
+        # A proper solution is to have an OS==android conditional
+        # in third_party/libvpx/libvpx.gyp to define it.
+        'libvpx_path': 'lib/linux/arm',
+      },
+      'target_defaults': {
+        'variables': {
+          'release_extra_cflags%': '',
+          'conditions': [
+            # If we're using the components build, append "cr" to all shared
+            # libraries to avoid naming collisions with android system library
+            # versions with the same name (e.g. skia, icu).
+            ['component=="shared_library"', {
+              'android_product_extension': 'cr.so',
+            }, {
+              'android_product_extension': 'so',
+            } ],
+          ],
+        },
+        'target_conditions': [
+          ['_type=="shared_library"', {
+            'product_extension': '<(android_product_extension)',
+          }],
+
+          # Settings for building device targets using Android's toolchain.
+          # These are based on the setup.mk file from the Android NDK.
+          #
+          # The NDK Android executable link step looks as follows:
+          #  $LDFLAGS
+          #  $(TARGET_CRTBEGIN_DYNAMIC_O)  <-- crtbegin.o
+          #  $(PRIVATE_OBJECTS)            <-- The .o that we built
+          #  $(PRIVATE_STATIC_LIBRARIES)   <-- The .a that we built
+          #  $(TARGET_LIBGCC)              <-- libgcc.a
+          #  $(PRIVATE_SHARED_LIBRARIES)   <-- The .so that we built
+          #  $(PRIVATE_LDLIBS)             <-- System .so
+          #  $(TARGET_CRTEND_O)            <-- crtend.o
+          #
+          # For now the above are approximated for executables by adding
+          # crtbegin.o to the end of the ldflags and 'crtend.o' to the end
+          # of 'libraries'.
+          #
+          # The NDK Android shared library link step looks as follows:
+          #  $LDFLAGS
+          #  $(PRIVATE_OBJECTS)            <-- The .o that we built
+          #  -l,--whole-archive
+          #  $(PRIVATE_WHOLE_STATIC_LIBRARIES)
+          #  -l,--no-whole-archive
+          #  $(PRIVATE_STATIC_LIBRARIES)   <-- The .a that we built
+          #  $(TARGET_LIBGCC)              <-- libgcc.a
+          #  $(PRIVATE_SHARED_LIBRARIES)   <-- The .so that we built
+          #  $(PRIVATE_LDLIBS)             <-- System .so
+          #
+          # For now, assume that whole static libraries are not needed.
+          #
+          # For both executables and shared libraries, add the proper
+          # libgcc.a to the start of libraries which puts it in the
+          # proper spot after .o and .a files get linked in.
+          #
+          # TODO: The proper thing to do longer-tem would be proper gyp
+          # support for a custom link command line.
+          ['_toolset=="target"', {
+            'cflags!': [
+              '-pthread',  # Not supported by Android toolchain.
+            ],
+            'cflags': [
+              '-ffunction-sections',
+              '-funwind-tables',
+              '-g',
+              '-fstack-protector',
+              '-fno-short-enums',
+              '-finline-limit=64',
+              '<@(release_extra_cflags)',
+              '--sysroot=<(android_ndk_sysroot)',
+              # NOTE: The libc++ header include paths below are specified in
+              # cflags rather than include_dirs because they need to come
+              # after include_dirs.
+              # The include ordering here is important; change with caution.
+              '-isystem<(android_libcpp_include)',
+              '-isystem<(android_ndk_root)/sources/cxx-stl/llvm-libc++abi/libcxxabi/include',
+              '-isystem<(android_ndk_root)/sources/android/support/include',
+            ],
+            'defines': [
+              'ANDROID',
+              '__GNU_SOURCE=1',  # Necessary for clone()
+              'CHROME_BUILD_ID="<(chrome_build_id)"',
+              # The NDK has these things, but doesn't define the constants
+              # to say that it does. Define them here instead.
+              'HAVE_SYS_UIO_H',
+            ],
+            'ldflags!': [
+              '-pthread',  # Not supported by Android toolchain.
+            ],
+            'ldflags': [
+              '-Wl,--no-undefined',
+              '--sysroot=<(android_ndk_sysroot)',
+              '-nostdlib',
+              '-L<(android_libcpp_libs_dir)',
+              # Don't allow visible symbols from libgcc or libc++ to be
+              # re-exported.
+              '-Wl,--exclude-libs=libgcc.a',
+              '-Wl,--exclude-libs=libc++_static.a',
+              # Don't allow visible symbols from libraries that contain
+              # assembly code with symbols that aren't hidden properly.
+              # http://crbug.com/448386
+              '-Wl,--exclude-libs=libcommon_audio.a',
+              '-Wl,--exclude-libs=libcommon_audio_neon.a',
+              '-Wl,--exclude-libs=libcommon_audio_sse2.a',
+              '-Wl,--exclude-libs=libiSACFix.a',
+              '-Wl,--exclude-libs=libisac_neon.a',
+              '-Wl,--exclude-libs=libopus.a',
+              '-Wl,--exclude-libs=libvpx.a',
+            ],
+            'libraries': [
+              '-l<(android_libcpp_library)',
+              '-latomic',
+              # Manually link the libgcc.a that the cross compiler uses.
+              '<!(<(android_toolchain)/*-gcc -print-libgcc-file-name)',
+              '-lc',
+              '-ldl',
+              '-lm',
+            ],
+            'conditions': [
+              ['component=="static_library"', {
+                'target_conditions': [
+                  ['use_native_jni_exports==0', {
+                    # Use a linker version script to strip JNI exports from
+                    # binaries which have not specifically asked to use them.
+                    'ldflags': [
+                      '-Wl,--version-script=<!(cd <(DEPTH) && pwd -P)/build/android/android_no_jni_exports.lst',
+                    ],
+                  }],
+                ],
+              }],
+              ['clang==1', {
+                'libraries!': [
+                  # Clang with libc++ does not require an explicit atomic
+                  # library reference.
+                  '-latomic',
+                ],
+                'cflags': [
+                  # Work around incompatibilities between bionic and clang
+                  # headers.
+                  '-D__compiler_offsetof=__builtin_offsetof',
+                  '-Dnan=__builtin_nan',
+                ],
+                'conditions': [
+                  ['target_arch=="arm"', {
+                    'cflags': [
+                      '-target arm-linux-androideabi',
+                    ],
+                    'ldflags': [
+                      '-target arm-linux-androideabi',
+                    ],
+                  }],
+                  ['target_arch=="ia32"', {
+                    'cflags': [
+                      '-target x86-linux-androideabi',
+                    ],
+                    'ldflags': [
+                      '-target x86-linux-androideabi',
+                    ],
+                  }],
+                  # Place holder for x64 support, not tested.
+                  # TODO: Enable clang support for Android x64. http://crbug.com/346626
+                  ['target_arch=="x64"', {
+                    'cflags': [
+                      '-target x86_64-linux-androideabi',
+                    ],
+                    'ldflags': [
+                      '-target x86_64-linux-androideabi',
+                    ],
+                  }],
+                ],
+              }],
+              ['asan==1', {
+                'cflags': [
+                  # Android build relies on -Wl,--gc-sections removing
+                  # unreachable code. ASan instrumentation for globals inhibits
+                  # this and results in a library with unresolvable relocations.
+                  # TODO(eugenis): find a way to reenable this.
+                  '-mllvm -asan-globals=0',
+                ],
+              }],
+              ['target_arch == "arm" and order_profiling==0', {
+                'ldflags': [
+                  # Enable identical code folding to reduce size.
+                  '-Wl,--icf=<(gold_icf_level)',
+                ],
+              }],
+              ['target_arch=="ia32"', {
+                # The x86 toolchain currently has problems with stack-protector.
+                'cflags!': [
+                  '-fstack-protector',
+                ],
+                'cflags': [
+                  '-fno-stack-protector',
+                ],
+              }],
+            ],
+            'target_conditions': [
+              ['_type=="executable"', {
+                # Force android tools to export the "main" symbol so they can be
+                # loaded on ICS using the run_pie wrapper. See crbug.com/373219.
+                # TODO(primiano): remove -fvisibility and -rdynamic flags below
+                # when ICS support will be dropped.
+                'cflags': [
+                  '-fPIE',
+                  '-fvisibility=default',
+                ],
+                'ldflags': [
+                  '-Bdynamic',
+                  '-Wl,--gc-sections',
+                  '-Wl,-z,nocopyreloc',
+                  '-pie',
+                  '-rdynamic',
+                  # crtbegin_dynamic.o should be the last item in ldflags.
+                  '<(android_ndk_lib)/crtbegin_dynamic.o',
+                ],
+                'libraries': [
+                  # crtend_android.o needs to be the last item in libraries.
+                  # Do not add any libraries after this!
+                  '<(android_ndk_lib)/crtend_android.o',
+                ],
+              }],
+              ['_type=="shared_library" or _type=="loadable_module"', {
+                'ldflags': [
+                  '-Wl,-shared,-Bsymbolic',
+                  # crtbegin_so.o should be the last item in ldflags.
+                  '<(android_ndk_lib)/crtbegin_so.o',
+                ],
+                'libraries': [
+                  # crtend_so.o needs to be the last item in libraries.
+                  # Do not add any libraries after this!
+                  '<(android_ndk_lib)/crtend_so.o',
+                ],
+              }],
+            ],
+          }],
+          # Settings for building host targets using the system toolchain.
+          ['_toolset=="host"', {
+            'cflags!': [
+              # Due to issues in Clang build system, using ASan on 32-bit
+              # binaries on x86_64 host is problematic.
+              # TODO(eugenis): re-enable.
+              '-fsanitize=address',
+            ],
+            'ldflags!': [
+              '-fsanitize=address',
+              '-Wl,-z,noexecstack',
+              '-Wl,--gc-sections',
+              '-Wl,-O1',
+              '-Wl,--as-needed',
+              '-Wl,--warn-shared-textrel',
+              '-Wl,--fatal-warnings',
+            ],
+          }],
+          # Settings for building host targets on mac.
+          ['_toolset=="host" and host_os=="mac"', {
+            'ldflags!': [
+              '-Wl,-z,now',
+              '-Wl,-z,relro',
+            ],
+          }],
+        ],
+      },
+    }],
+    ['OS=="solaris"', {
+      'cflags!': ['-fvisibility=hidden'],
+      'cflags_cc!': ['-fvisibility-inlines-hidden'],
+    }],
+    ['OS=="mac" or OS=="ios"', {
+      'target_defaults': {
+        'mac_bundle': 0,
+        'xcode_settings': {
+          'ALWAYS_SEARCH_USER_PATHS': 'NO',
+          # Don't link in libarclite_macosx.a, see http://crbug.com/156530.
+          'CLANG_LINK_OBJC_RUNTIME': 'NO',          # -fno-objc-link-runtime
+          'COPY_PHASE_STRIP': 'NO',
+          'GCC_C_LANGUAGE_STANDARD': 'c99',         # -std=c99
+          'GCC_CW_ASM_SYNTAX': 'NO',                # No -fasm-blocks
+          'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',        # -fno-exceptions
+          'GCC_ENABLE_CPP_RTTI': 'NO',              # -fno-rtti
+          'GCC_ENABLE_PASCAL_STRINGS': 'NO',        # No -mpascal-strings
+          # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden
+          'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
+          'GCC_OBJC_CALL_CXX_CDTORS': 'YES',        # -fobjc-call-cxx-cdtors
+          'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES',      # -fvisibility=hidden
+          'GCC_THREADSAFE_STATICS': 'NO',           # -fno-threadsafe-statics
+          'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES',    # -Werror
+          'GCC_VERSION': '4.2',
+          'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES',  # -Wnewline-eof
+          'USE_HEADERMAP': 'NO',
+          'WARNING_CFLAGS': [
+            '-Wall',
+            '-Wendif-labels',
+            '-Wextra',
+            # Don't warn about unused function parameters.
+            '-Wno-unused-parameter',
+            # Don't warn about the "struct foo f = {0};" initialization
+            # pattern.
+            '-Wno-missing-field-initializers',
+          ],
+          'conditions': [
+            ['chromium_mac_pch', {'GCC_PRECOMPILE_PREFIX_HEADER': 'YES'},
+                                 {'GCC_PRECOMPILE_PREFIX_HEADER': 'NO'}
+            ],
+            # Note that the prebuilt Clang binaries should not be used for iOS
+            # development except for ASan builds.
+            ['clang==1', {
+              'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',  # -std=c++11
+              # Warn if automatic synthesis is triggered with
+              # the -Wobjc-missing-property-synthesis flag.
+              'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
+              'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+              'WARNING_CFLAGS': [
+                # This warns on selectors from Cocoa headers (-length, -set).
+                # cfe-dev is currently discussing the merits of this warning.
+                # TODO(thakis): Reevaluate what to do with this, based one
+                # cfe-dev discussion.
+                '-Wno-selector-type-mismatch',
+              ],
+              'conditions': [
+                ['clang_xcode==0', {
+                  'CC': '$(SOURCE_ROOT)/<(clang_dir)/clang',
+                  'LDPLUSPLUS': '$(SOURCE_ROOT)/<(clang_dir)/clang++',
+                }],
+              ],
+            }],
+            ['clang==1 and clang_xcode==0 and clang_use_chrome_plugins==1', {
+              'OTHER_CFLAGS': [
+                '<@(clang_chrome_plugins_flags)',
+              ],
+            }],
+            ['clang==1 and clang_xcode==0 and clang_load!=""', {
+              'OTHER_CFLAGS': [
+                '-Xclang', '-load', '-Xclang', '<(clang_load)',
+              ],
+            }],
+            ['clang==1 and clang_xcode==0 and clang_add_plugin!=""', {
+              'OTHER_CFLAGS': [
+                '-Xclang', '-add-plugin', '-Xclang', '<(clang_add_plugin)',
+              ],
+            }],
+            ['clang==1 and "<(GENERATOR)"=="ninja"', {
+              'OTHER_CFLAGS': [
+                # See http://crbug.com/110262
+                '-fcolor-diagnostics',
+              ],
+            }],
+            ['OS=="ios" and target_subarch!="arm32" and \
+              "<(GENERATOR)"=="xcode"', {
+              'OTHER_CFLAGS': [
+                # TODO(ios): when building Chrome for iOS on 64-bit platform
+                # with Xcode, the -Wshorted-64-to-32 warning is automatically
+                # enabled. This cause failures when compiling protobuf code,
+                # so disable the warning. http://crbug.com/359107
+                '-Wno-shorten-64-to-32',
+              ],
+            }],
+          ],
+        },
+        'conditions': [
+          ['clang==1', {
+            'variables': {
+              'clang_dir': '../third_party/llvm-build/Release+Asserts/bin',
+            },
+          }],
+          ['asan==1', {
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fsanitize=address',
+                '-mllvm -asan-globals=0',  # http://crbug.com/352073
+                '-gline-tables-only',
+              ],
+            },
+          }],
+          ['asan_coverage!=0 and sanitizer_coverage==0', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize-coverage=<(asan_coverage)',
+                ],
+                'defines': [
+                  'SANITIZER_COVERAGE',
+                ],
+              }],
+            ],
+          }],
+          ['sanitizer_coverage!=0', {
+            'target_conditions': [
+              ['_toolset=="target"', {
+                'cflags': [
+                  '-fsanitize-coverage=<(sanitizer_coverage)',
+                ],
+                'defines': [
+                  'SANITIZER_COVERAGE',
+                ],
+              }],
+            ],
+          }],
+        ],
+        'target_conditions': [
+          ['_type!="static_library"', {
+            'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']},
+            'conditions': [
+              ['asan==1', {
+                'xcode_settings': {
+                  'OTHER_LDFLAGS': [
+                    '-fsanitize=address',
+                  ],
+                },
+              }],
+              ['mac_write_linker_maps==1', {
+                'xcode_settings': {
+                  'OTHER_LDFLAGS': [
+                    '-Wl,-map,>(_target_name).map',
+                  ],
+                },
+              }],
+            ],
+          }],
+          ['_mac_bundle', {
+            'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
+            'target_conditions': [
+              ['_type=="executable"', {
+                'conditions': [
+                  ['asan==1', {
+                    'postbuilds': [
+                      {
+                        'variables': {
+                          # Define copy_asan_dylib_path in a variable ending in
+                          # _path so that gyp understands it's a path and
+                          # performs proper relativization during dict merging.
+                          'copy_asan_dylib_path':
+                            'mac/copy_asan_runtime_dylib.sh',
+                        },
+                        'postbuild_name': 'Copy ASan runtime dylib',
+                        'action': [
+                          '<(copy_asan_dylib_path)',
+                        ],
+                      },
+                    ],
+                  }],
+                ],
+              }],
+            ],
+          }],
+        ],  # target_conditions
+      },  # target_defaults
+    }],  # OS=="mac" or OS=="ios"
+    ['OS=="mac"', {
+      'target_defaults': {
+        'defines': [
+          # Prevent Mac OS X AssertMacros.h from defining macros that collide
+          # with common names, like 'check', 'require', and 'verify'.
+          # (Included by system header. Also exists on iOS but not included.)
+          # http://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/AssertMacros.h
+          '__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE=0',
+        ],
+        'variables': {
+          # These should end with %, but there seems to be a bug with % in
+          # variables that are intended to be set to different values in
+          # different targets, like these.
+          'mac_pie': 1,        # Most executables can be position-independent.
+          # Strip debugging symbols from the target.
+          'mac_strip': '<(mac_strip_release)',
+          'conditions': [
+            ['asan==1', {
+              'conditions': [
+                ['mac_want_real_dsym=="default"', {
+                  'mac_real_dsym': 1,
+                }, {
+                  'mac_real_dsym': '<(mac_want_real_dsym)'
+                }],
+              ],
+            }, {
+              'conditions': [
+                ['mac_want_real_dsym=="default"', {
+                  'mac_real_dsym': 0, # Fake .dSYMs are fine in most cases.
+                }, {
+                  'mac_real_dsym': '<(mac_want_real_dsym)'
+                }],
+              ],
+            }],
+          ],
+        },
+        'configurations': {
+          'Release_Base': {
+            'conditions': [
+              ['branding=="Chrome" and buildtype=="Official"', {
+                'xcode_settings': {
+                  'OTHER_CFLAGS': [
+                    # The Google Chrome Framework dSYM generated by dsymutil has
+                    # grown larger than 4GB, which dsymutil can't handle. Reduce
+                    # the amount of debug symbols.
+                    '-fno-standalone-debug',  # See http://crbug.com/479841
+                  ]
+                },
+              }],
+            ],
+          },  # configuration "Release"
+        },  # configurations
+        'xcode_settings': {
+          'GCC_DYNAMIC_NO_PIC': 'NO',               # No -mdynamic-no-pic
+                                                    # (Equivalent to -fPIC)
+          # MACOSX_DEPLOYMENT_TARGET maps to -mmacosx-version-min
+          'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)',
+          # Keep pch files below xcodebuild/.
+          'SHARED_PRECOMPS_DIR': '$(CONFIGURATION_BUILD_DIR)/SharedPrecompiledHeaders',
+          'OTHER_CFLAGS': [
+            # Someday this can be replaced by an 'GCC_STRICT_ALIASING': 'NO'
+            # xcode_setting, but not until all downstream projects' mac bots are
+            # using xcode >= 4.6, because that's when the default value of the
+            # flag in the compiler switched.  Pre-4.6, the value 'NO' for that
+            # setting is a no-op as far as xcode is concerned, but the compiler
+            # behaves differently based on whether -fno-strict-aliasing is
+            # specified or not.
+            '-fno-strict-aliasing',  # See http://crbug.com/32204.
+          ],
+        },
+        'target_conditions': [
+          ['_type=="executable"', {
+            'postbuilds': [
+              {
+                # Arranges for data (heap) pages to be protected against
+                # code execution when running on Mac OS X 10.7 ("Lion"), and
+                # ensures that the position-independent executable (PIE) bit
+                # is set for ASLR when running on Mac OS X 10.5 ("Leopard").
+                'variables': {
+                  # Define change_mach_o_flags in a variable ending in _path
+                  # so that GYP understands it's a path and performs proper
+                  # relativization during dict merging.
+                  'change_mach_o_flags_path':
+                      'mac/change_mach_o_flags_from_xcode.sh',
+                  'change_mach_o_flags_options%': [
+                  ],
+                  'target_conditions': [
+                    ['mac_pie==0 or release_valgrind_build==1', {
+                      # Don't enable PIE if it's unwanted. It's unwanted if
+                      # the target specifies mac_pie=0 or if building for
+                      # Valgrind, because Valgrind doesn't understand slide.
+                      # See the similar mac_pie/release_valgrind_build check
+                      # below.
+                      'change_mach_o_flags_options': [
+                        '--no-pie',
+                      ],
+                    }],
+                  ],
+                },
+                'postbuild_name': 'Change Mach-O Flags',
+                'action': [
+                  '<(change_mach_o_flags_path)',
+                  '>@(change_mach_o_flags_options)',
+                ],
+              },
+            ],
+            'target_conditions': [
+              ['mac_pie==1 and release_valgrind_build==0', {
+                # Turn on position-independence (ASLR) for executables. When
+                # PIE is on for the Chrome executables, the framework will
+                # also be subject to ASLR.
+                # Don't do this when building for Valgrind, because Valgrind
+                # doesn't understand slide. TODO: Make Valgrind on Mac OS X
+                # understand slide, and get rid of the Valgrind check.
+                'xcode_settings': {
+                  'OTHER_LDFLAGS': [
+                    '-Wl,-pie',  # Position-independent executable (MH_PIE)
+                  ],
+                },
+              }],
+            ],
+          }],
+          ['(_type=="executable" or _type=="shared_library" or \
+             _type=="loadable_module") and mac_strip!=0', {
+            'target_conditions': [
+              ['mac_real_dsym == 1', {
+                # To get a real .dSYM bundle produced by dsymutil, set the
+                # debug information format to dwarf-with-dsym.  Since
+                # strip_from_xcode will not be used, set Xcode to do the
+                # stripping as well.
+                'configurations': {
+                  'Release_Base': {
+                    'xcode_settings': {
+                      'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
+                      'DEPLOYMENT_POSTPROCESSING': 'YES',
+                      'STRIP_INSTALLED_PRODUCT': 'YES',
+                      'conditions': [
+                        # Only strip non-ASan builds.
+                        ['asan==0', {
+                          'target_conditions': [
+                            ['_type=="shared_library" or _type=="loadable_module"', {
+                              # The Xcode default is to strip debugging symbols
+                              # only (-S).  Local symbols should be stripped as
+                              # well, which will be handled by -x.  Xcode will
+                              # continue to insert -S when stripping even when
+                              # additional flags are added with STRIPFLAGS.
+                              'STRIPFLAGS': '-x',
+                            }],  # _type=="shared_library" or _type=="loadable_module"
+                          ],  # target_conditions
+                        }, {  # asan != 0
+                          'STRIPFLAGS': '-S',
+                        }],
+                      ],
+                    },  # xcode_settings
+                  },  # configuration "Release"
+                },  # configurations
+              }, {  # mac_real_dsym != 1
+                # To get a fast fake .dSYM bundle, use a post-build step to
+                # produce the .dSYM and strip the executable.  strip_from_xcode
+                # only operates in the Release configuration.
+                'postbuilds': [
+                  {
+                    'variables': {
+                      # Define strip_from_xcode in a variable ending in _path
+                      # so that gyp understands it's a path and performs proper
+                      # relativization during dict merging.
+                      'strip_from_xcode_path': 'mac/strip_from_xcode',
+                    },
+                    'postbuild_name': 'Strip If Needed',
+                    'action': ['<(strip_from_xcode_path)'],
+                  },
+                ],  # postbuilds
+              }],  # mac_real_dsym
+            ],  # target_conditions
+          }],  # (_type=="executable" or _type=="shared_library" or
+               #  _type=="loadable_module") and mac_strip!=0
+        ],  # target_conditions
+      },  # target_defaults
+    }],  # OS=="mac"
+    ['OS=="ios"', {
+      'includes': [
+        'ios/coverage.gypi',
+      ],
+      'target_defaults': {
+        'xcode_settings' : {
+          'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
+
+          'conditions': [
+            # Older Xcodes do not support -Wno-deprecated-register, so pass an
+            # additional flag to suppress the "unknown compiler option" error.
+            # Restrict this flag to builds that are either compiling with Xcode
+            # or compiling with Xcode's Clang.  This will allow Ninja builds to
+            # continue failing on unknown compiler options.
+            # TODO(rohitrao): This flag is temporary and should be removed as
+            # soon as the iOS bots are updated to use Xcode 5.1.
+            ['clang_xcode==1', {
+              'WARNING_CFLAGS': [
+                '-Wno-unknown-warning-option',
+              ],
+            }],
+
+            # Limit the valid architectures depending on "target_subarch".
+            # This need to include the "arm" architectures but also the "x86"
+            # ones (they are used when building for the simulator).
+            ['target_subarch=="arm32"', {
+              'VALID_ARCHS': ['armv7', 'i386'],
+            }],
+            ['target_subarch=="arm64"', {
+              'VALID_ARCHS': ['arm64', 'x86_64'],
+            }],
+            ['target_subarch=="both"', {
+              'VALID_ARCHS': ['arm64', 'armv7', 'x86_64', 'i386'],
+            }],
+            ['use_system_libcxx==1', {
+              'target_conditions': [
+                # Only use libc++ when building target for iOS not when building
+                # tools for the host (OS X) as Mac targets OS X SDK 10.6 which
+                # does not support libc++.
+                ['_toolset=="target"', {
+                  'CLANG_CXX_LIBRARY': 'libc++',  # -stdlib=libc++
+                }]
+              ],
+            }, {
+              # The default for deployment target of 7.0+ is libc++, so force
+              # the old behavior unless libc++ is enabled.
+              'CLANG_CXX_LIBRARY': 'libstdc++',  # -stdlib=libstdc++
+            }],
+          ],
+        },
+        'target_conditions': [
+          ['_toolset=="host"', {
+            'xcode_settings': {
+              'SDKROOT': 'macosx<(mac_sdk)',  # -isysroot
+              'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)',
+              'VALID_ARCHS': [
+                'x86_64',
+              ],
+              'ARCHS': [
+                'x86_64',
+              ],
+            },
+          }],
+          ['_toolset=="target"', {
+            'xcode_settings': {
+              # This section should be for overriding host settings. But,
+              # since we can't negate the iphone deployment target above, we
+              # instead set it here for target only.
+              'IPHONEOS_DEPLOYMENT_TARGET': '<(ios_deployment_target)',
+              'ARCHS': ['$(ARCHS_STANDARD_INCLUDING_64_BIT)'],
+            },
+          }],
+          ['_type=="executable"', {
+            'configurations': {
+              'Release_Base': {
+                'xcode_settings': {
+                  'DEPLOYMENT_POSTPROCESSING': 'YES',
+                  'STRIP_INSTALLED_PRODUCT': 'YES',
+                },
+              },
+              'Debug_Base': {
+                'xcode_settings': {
+                  # Remove dSYM to reduce build time.
+                  'DEBUG_INFORMATION_FORMAT': 'dwarf',
+                },
+              },
+            },
+            'xcode_settings': {
+              'conditions': [
+                ['chromium_ios_signing', {
+                  # iOS SDK wants everything for device signed.
+                  'CODE_SIGN_IDENTITY[sdk=iphoneos*]': 'iPhone Developer',
+                }, {
+                  'CODE_SIGNING_REQUIRED': 'NO',
+                  'CODE_SIGN_IDENTITY[sdk=iphoneos*]': '',
+                }],
+              ],
+            },
+          }],
+        ],  # target_conditions
+      },  # target_defaults
+    }],  # OS=="ios"
+    ['OS=="win"', {
+      'target_defaults': {
+        'defines': [
+          '_WIN32_WINNT=0x0603',
+          'WINVER=0x0603',
+          'WIN32',
+          '_WINDOWS',
+          'NOMINMAX',
+          'PSAPI_VERSION=1',
+          '_CRT_RAND_S',
+          'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS',
+          'WIN32_LEAN_AND_MEAN',
+          '_ATL_NO_OPENGL',
+          '_SECURE_ATL',
+          # _HAS_EXCEPTIONS must match ExceptionHandling in msvs_settings.
+          '_HAS_EXCEPTIONS=0',
+          # Silence some warnings; we can't switch the the 'recommended'
+          # versions as they're not available on old OSs.
+          '_WINSOCK_DEPRECATED_NO_WARNINGS',
+        ],
+        'conditions': [
+          ['buildtype=="Official"', {
+              # In official builds, targets can self-select an optimization
+              # level by defining a variable named 'optimize', and setting it
+              # to one of
+              # - "size", optimizes for minimal code size - the default.
+              # - "speed", optimizes for speed over code size.
+              # - "max", whole program optimization and link-time code
+              #   generation. This is very expensive and should be used
+              #   sparingly.
+              'variables': {
+                'optimize%': 'size',
+              },
+              'msvs_settings': {
+                'VCLinkerTool': {
+                  # Set /LTCG for the official builds.
+                  'LinkTimeCodeGeneration': '1',
+                  'AdditionalOptions': [
+                    # Set the number of LTCG code-gen threads to eight.
+                    # The default is four. This gives a 5-10% link speedup.
+                    '/cgthreads:8',
+                  ],
+                },
+              },
+              'target_conditions': [
+                ['optimize=="size"', {
+                    'msvs_settings': {
+                      'VCCLCompilerTool': {
+                        # 1, optimizeMinSpace, Minimize Size (/O1)
+                        'Optimization': '1',
+                        # 2, favorSize - Favor small code (/Os)
+                        'FavorSizeOrSpeed': '2',
+                      },
+                    },
+                  },
+                ],
+                ['optimize=="speed"', {
+                    'msvs_settings': {
+                      'VCCLCompilerTool': {
+                        # 2, optimizeMaxSpeed, Maximize Speed (/O2)
+                        'Optimization': '2',
+                        # 1, favorSpeed - Favor fast code (/Ot)
+                        'FavorSizeOrSpeed': '1',
+                      },
+                    },
+                  },
+                ],
+                ['optimize=="max"', {
+                    # Disable Warning 4702 ("Unreachable code") for the WPO/PGO
+                    # builds. Probably anything that this would catch that
+                    # wouldn't be caught in a normal build isn't going to
+                    # actually be a bug, so the incremental value of C4702 for
+                    # PGO builds is likely very small.
+                    'msvs_disabled_warnings': [
+                      4702
+                    ],
+                    'msvs_settings': {
+                      'VCCLCompilerTool': {
+                        # 2, optimizeMaxSpeed, Maximize Speed (/O2)
+                        'Optimization': '2',
+                        # 1, favorSpeed - Favor fast code (/Ot)
+                        'FavorSizeOrSpeed': '1',
+                        # This implies link time code generation.
+                        'WholeProgramOptimization': 'true',
+                      },
+                    },
+                  },
+                ],
+              ],
+            },
+          ],
+          ['msvs_xtree_patched!=1', {
+            # If xtree hasn't been patched, then we disable C4702. Otherwise,
+            # it's enabled. This will generally only be true for system-level
+            # installed Express users.
+            'msvs_disabled_warnings': [
+              4702,
+            ],
+          }],
+        ],
+        'msvs_system_include_dirs': [
+          '<(windows_sdk_path)/Include/shared',
+          '<(windows_sdk_path)/Include/um',
+          '<(windows_sdk_path)/Include/winrt',
+          '$(VSInstallDir)/VC/atlmfc/include',
+        ],
+        'msvs_cygwin_shell': 0,
+        'msvs_disabled_warnings': [
+          # C4091: 'typedef ': ignored on left of 'X' when no variable is
+          #                    declared.
+          # This happens in a number of Windows headers. Dumb.
+          4091,
+
+          # C4127: conditional expression is constant
+          # This warning can in theory catch dead code and other problems, but
+          # triggers in far too many desirable cases where the conditional
+          # expression is either set by macros or corresponds some legitimate
+          # compile-time constant expression (due to constant template args,
+          # conditionals comparing the sizes of different types, etc.).  Some of
+          # these can be worked around, but it's not worth it.
+          4127,
+
+          # C4351: new behavior: elements of array 'array' will be default
+          #        initialized
+          # This is a silly "warning" that basically just alerts you that the
+          # compiler is going to actually follow the language spec like it's
+          # supposed to, instead of not following it like old buggy versions
+          # did.  There's absolutely no reason to turn this on.
+          4351,
+
+          # C4355: 'this': used in base member initializer list
+          # It's commonly useful to pass |this| to objects in a class'
+          # initializer list.  While this warning can catch real bugs, most of
+          # the time the constructors in question don't attempt to call methods
+          # on the passed-in pointer (until later), and annotating every legit
+          # usage of this is simply more hassle than the warning is worth.
+          4355,
+
+          # C4503: 'identifier': decorated name length exceeded, name was
+          #        truncated
+          # This only means that some long error messages might have truncated
+          # identifiers in the presence of lots of templates.  It has no effect
+          # on program correctness and there's no real reason to waste time
+          # trying to prevent it.
+          4503,
+
+          # C4611: interaction between 'function' and C++ object destruction is
+          #        non-portable
+          # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
+          # suggests using exceptions instead of setjmp/longjmp for C++, but
+          # Chromium code compiles without exception support.  We therefore have
+          # to use setjmp/longjmp for e.g. JPEG decode error handling, which
+          # means we have to turn off this warning (and be careful about how
+          # object destruction happens in such cases).
+          4611,
+
+          # TODO(maruel): These warnings are level 4. They will be slowly
+          # removed as code is fixed.
+          4100, # Unreferenced formal parameter
+          4121, # Alignment of a member was sensitive to packing
+          4244, # Conversion from 'type1' to 'type2', possible loss of data
+          4481, # Nonstandard extension used: override specifier 'keyword'
+          4505, # Unreferenced local function has been removed
+          4510, # Default constructor could not be generated
+          4512, # Assignment operator could not be generated
+          4610, # Object can never be instantiated
+          4996, # 'X': was declared deprecated (for GetVersionEx).
+
+          # These are variable shadowing warnings that are new in VS2015. We
+          # should work through these at some point -- they may be removed from
+          # the RTM release in the /W4 set.
+          4456, 4457, 4458, 4459,
+        ],
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'AdditionalOptions': ['/MP'],
+            'MinimalRebuild': 'false',
+            'BufferSecurityCheck': 'true',
+            'EnableFunctionLevelLinking': 'true',
+            'RuntimeTypeInfo': 'false',
+            'WarningLevel': '4',
+            'WarnAsError': 'true',
+            'DebugInformationFormat': '3',
+            # ExceptionHandling must match _HAS_EXCEPTIONS above.
+            'ExceptionHandling': '0',
+          },
+          'VCLibrarianTool': {
+            'AdditionalOptions': ['/ignore:4221'],
+            'AdditionalLibraryDirectories': [
+              '<(windows_sdk_path)/Lib/win8/um/x86',
+            ],
+          },
+          'VCLinkerTool': {
+            'AdditionalDependencies': [
+              'wininet.lib',
+              'dnsapi.lib',
+              'version.lib',
+              'msimg32.lib',
+              'ws2_32.lib',
+              'usp10.lib',
+              'psapi.lib',
+              'dbghelp.lib',
+              'winmm.lib',
+              'shlwapi.lib',
+            ],
+            'AdditionalLibraryDirectories': [
+              '<(windows_sdk_path)/Lib/win8/um/x86',
+            ],
+            'GenerateDebugInformation': 'true',
+            'MapFileName': '$(OutDir)\\$(TargetName).map',
+            'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib',
+            'FixedBaseAddress': '1',
+            # SubSystem values:
+            #   0 == not set
+            #   1 == /SUBSYSTEM:CONSOLE
+            #   2 == /SUBSYSTEM:WINDOWS
+            # Most of the executables we'll ever create are tests
+            # and utilities with console output.
+            'SubSystem': '1',
+          },
+          'VCMIDLTool': {
+            'GenerateStublessProxies': 'true',
+            'TypeLibraryName': '$(InputName).tlb',
+            'OutputDirectory': '$(IntDir)',
+            'HeaderFileName': '$(InputName).h',
+            'DLLDataFileName': '$(InputName).dlldata.c',
+            'InterfaceIdentifierFileName': '$(InputName)_i.c',
+            'ProxyFileName': '$(InputName)_p.c',
+          },
+          'VCResourceCompilerTool': {
+            'Culture' : '1033',
+            'AdditionalIncludeDirectories': [
+              '<(DEPTH)',
+              '<(SHARED_INTERMEDIATE_DIR)',
+            ],
+          },
+          'target_conditions': [
+            ['_type=="executable"', {
+              'VCManifestTool': {
+                'EmbedManifest': 'true',
+              },
+            }],
+            ['_type=="executable" and ">(win_exe_compatibility_manifest)"!=""', {
+              'VCManifestTool': {
+                'AdditionalManifestFiles': [
+                  '>(win_exe_compatibility_manifest)',
+                ],
+              },
+            }],
+          ],
+          'conditions': [
+            # Building with Clang on Windows is a work in progress and very
+            # experimental. See crbug.com/82385.
+            ['clang==1', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-fmsc-version=1800',
+
+                  # Many files use intrinsics without including this header.
+                  # TODO(hans): Fix those files, or move this to sub-GYPs.
+                  '/FIIntrin.h',
+
+                  # TODO(hans): Make this list shorter eventually.
+                  '-Qunused-arguments',
+                  '-Wno-c++11-compat-deprecated-writable-strings',
+                  '-Wno-deprecated-declarations',
+                  '-Wno-empty-body',
+                  '-Wno-enum-conversion',
+                  '-Wno-extra-tokens',
+                  '-Wno-ignored-attributes',
+                  '-Wno-incompatible-pointer-types',
+                  '-Wno-int-to-void-pointer-cast',
+                  '-Wno-invalid-noreturn',
+                  '-Wno-logical-op-parentheses',
+                  '-Wno-microsoft',
+                  '-Wno-missing-braces',
+                  '-Wno-missing-declarations',
+                  '-Wno-msvc-include',
+                  '-Wno-null-dereference',
+                  '-Wno-overloaded-virtual',
+                  '-Wno-parentheses',
+                  '-Wno-pointer-sign',
+                  '-Wno-reorder',
+                  '-Wno-return-type-c-linkage',
+                  '-Wno-self-assign',
+                  '-Wno-sometimes-uninitialized',
+                  '-Wno-switch',
+                  '-Wno-tautological-compare',
+                  '-Wno-unknown-pragmas',
+                  '-Wno-unsequenced',
+                  '-Wno-unused-function',
+                  '-Wno-unused-private-field',
+                  '-Wno-unused-value',
+                  '-Wno-unused-variable',
+                  '-Wno-unused-local-typedef',  # http://crbug.com/411648
+                  '-Wno-inconsistent-missing-override', #http://crbug.com/428099
+                ],
+              },
+            }],
+            ['clang==1 and target_arch=="ia32"', {
+              'VCCLCompilerTool': {
+                'WarnAsError': 'false',
+                'AdditionalOptions': [
+                  '/fallback',
+                ],
+              },
+            }],
+            ['clang==1 and clang_use_chrome_plugins==1', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '<@(clang_chrome_plugins_flags)',
+                ],
+              },
+            }],
+          ],
+        },
+      },
+    }],
+    ['disable_nacl==1', {
+      'target_defaults': {
+        'defines': [
+          'DISABLE_NACL',
+        ],
+      },
+    }],
+    ['OS=="win" and msvs_use_common_linker_extras', {
+      'target_defaults': {
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'DelayLoadDLLs': [
+              'dbghelp.dll',
+              'dwmapi.dll',
+              'shell32.dll',
+              'uxtheme.dll',
+            ],
+          },
+        },
+        'configurations': {
+          'x86_Base': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'AdditionalOptions': [
+                  '/safeseh',
+                  '/dynamicbase',
+                  '/ignore:4199',
+                  '/ignore:4221',
+                  '/nxcompat',
+                ],
+              },
+              'conditions': [
+                ['syzyasan==0', {
+                  'VCLinkerTool': {
+                    'AdditionalOptions': ['/largeaddressaware'],
+                  },
+                }],
+                ['asan==1', {
+                  # TODO(asan/win): Move this down into the general
+                  # win-target_defaults section once the 64-bit asan runtime
+                  # exists.  See crbug.com/345874.
+                  'VCCLCompilerTool': {
+                    'AdditionalOptions': [
+                      '-fsanitize=address',
+                      '-fsanitize-blacklist=<(PRODUCT_DIR)/../../tools/memory/asan/blacklist_win.txt',
+                    ],
+                    'AdditionalIncludeDirectories': [
+                      # MSVC needs to be able to find the sanitizer headers when
+                      # invoked via /fallback. This is critical for using macros
+                      # like ASAN_UNPOISON_MEMORY_REGION in files where we fall
+                      # back.
+                      '<(DEPTH)/<(make_clang_dir)/lib/clang/3.7.0/include_sanitizer',
+                    ],
+                  },
+                  'VCLinkerTool': {
+                    'AdditionalLibraryDirectories': [
+                      # TODO(hans): If make_clang_dir is absolute, this breaks.
+                      '<(DEPTH)/<(make_clang_dir)/lib/clang/3.7.0/lib/windows',
+                    ],
+                  },
+                  'target_conditions': [
+                    ['component=="shared_library"', {
+                      'VCLinkerTool': {
+                        'AdditionalDependencies': [
+                           'clang_rt.asan_dynamic-i386.lib',
+                           'clang_rt.asan_dynamic_runtime_thunk-i386.lib',
+                        ],
+                      },
+                    }],
+                    ['_type=="executable" and component=="static_library"', {
+                      'VCLinkerTool': {
+                        'AdditionalDependencies': [
+                           'clang_rt.asan-i386.lib',
+                        ],
+                      },
+                    }],
+                    ['(_type=="shared_library" or _type=="loadable_module") and component=="static_library"', {
+                      'VCLinkerTool': {
+                        'AdditionalDependencies': [
+                           'clang_rt.asan_dll_thunk-i386.lib',
+                        ],
+                      },
+                    }],
+                  ],
+                }],
+                ['sanitizer_coverage!=0', {
+                  # TODO(asan/win): Move this down into the general
+                  # win-target_defaults section once the 64-bit asan runtime
+                  # exists.  See crbug.com/345874.
+                  'VCCLCompilerTool': {
+                    'AdditionalOptions': [
+                      '-fsanitize-coverage=<(sanitizer_coverage)',
+                    ],
+                  },
+                }],
+              ],
+            },
+            'conditions': [
+              ['sanitizer_coverage!=0', {
+                # TODO(asan/win): Move this down into the general
+                # win-target_defaults section once the 64-bit asan runtime
+                # exists.  See crbug.com/345874.
+                'defines': [
+                  'SANITIZER_COVERAGE',
+                ],
+              }],
+            ],
+          },
+          'x64_Base': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'AdditionalOptions': [
+                  # safeseh is not compatible with x64
+                  '/dynamicbase',
+                  '/ignore:4199',
+                  '/ignore:4221',
+                  '/nxcompat',
+                ],
+              },
+            },
+          },
+        },
+      },
+    }],
+    ['enable_new_npdevice_api==1', {
+      'target_defaults': {
+        'defines': [
+          'ENABLE_NEW_NPDEVICE_API',
+        ],
+      },
+    }],
+    # Don't warn about the "typedef 'foo' locally defined but not used"
+    # for gcc 4.8 and higher.
+    # TODO: remove this flag once all builds work. See crbug.com/227506
+    ['gcc_version>=48 and clang==0', {
+      'target_defaults': {
+        'cflags': [
+          '-Wno-unused-local-typedefs',
+        ],
+      },
+    }],
+    ['gcc_version>=48 and clang==0 and host_clang==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="host"', { 'cflags!': [ '-Wno-unused-local-typedefs' ]}],
+        ],
+      },
+    }],
+    ['clang==1 and ((OS!="mac" and OS!="ios") or clang_xcode==0) '
+        'and OS!="win"', {
+      'make_global_settings': [
+        ['CC', '<(make_clang_dir)/bin/clang'],
+        ['CXX', '<(make_clang_dir)/bin/clang++'],
+        ['CC.host', '$(CC)'],
+        ['CXX.host', '$(CXX)'],
+      ],
+    }],
+    ['clang==1 and OS=="win"', {
+      'make_global_settings': [
+        # On Windows, gyp's ninja generator only looks at CC.
+        ['CC', '<(make_clang_dir)/bin/clang-cl'],
+      ],
+    }],
+    ['use_lld==1 and OS=="win"', {
+      'make_global_settings': [
+        # Limited to Windows because lld-link is the driver that is compatible
+        # to link.exe.
+        ['LD', '<(make_clang_dir)/bin/lld-link'],
+      ],
+    }],
+    ['OS=="android" and clang==0', {
+      # Hardcode the compiler names in the Makefile so that
+      # it won't depend on the environment at make time.
+      'make_global_settings': [
+        ['CC', '<!(/bin/echo -n <(android_toolchain)/*-gcc)'],
+        ['CXX', '<!(/bin/echo -n <(android_toolchain)/*-g++)'],
+        ['CC.host', '<(host_cc)'],
+        ['CXX.host', '<(host_cxx)'],
+      ],
+    }],
+    ['OS=="linux" and target_arch=="mipsel"', {
+      'make_global_settings': [
+        ['CC', '<(sysroot)/../bin/mipsel-linux-gnu-gcc'],
+        ['CXX', '<(sysroot)/../bin/mipsel-linux-gnu-g++'],
+        ['CC.host', '<(host_cc)'],
+        ['CXX.host', '<(host_cxx)'],
+      ],
+    }],
+    ['OS=="linux" and target_arch=="arm" and host_arch!="arm" and chromeos==0 and clang==0', {
+      # Set default ARM cross compiling on linux.  These can be overridden
+      # using CC/CXX/etc environment variables.
+      'make_global_settings': [
+        ['CC', '<!(which arm-linux-gnueabihf-gcc)'],
+        ['CXX', '<!(which arm-linux-gnueabihf-g++)'],
+        ['CC.host', '<(host_cc)'],
+        ['CXX.host', '<(host_cxx)'],
+      ],
+    }],
+
+    # TODO(yyanagisawa): supports GENERATOR==make
+    #  make generator doesn't support CC_wrapper without CC
+    #  in make_global_settings yet.
+    ['use_goma==1 and ("<(GENERATOR)"=="ninja" or clang==1)', {
+      'make_global_settings': [
+       ['CC_wrapper', '<(gomadir)/gomacc'],
+       ['CXX_wrapper', '<(gomadir)/gomacc'],
+       ['CC.host_wrapper', '<(gomadir)/gomacc'],
+       ['CXX.host_wrapper', '<(gomadir)/gomacc'],
+      ],
+    }],
+    ['use_lto==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-flto',
+            ],
+            'xcode_settings': {
+              'LLVM_LTO': 'YES',
+            },
+          }],
+          # Work-around for http://openradar.appspot.com/20356002
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings': {
+              'OTHER_LDFLAGS': [
+                '-Wl,-all_load',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['use_lto==1 and clang==0', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-ffat-lto-objects',
+            ],
+          }],
+        ],
+      },
+    }],
+    ['use_lto==1 and clang==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'arflags': [
+              '--plugin', '../../<(make_clang_dir)/lib/LLVMgold.so',
+            ],
+          }],
+        ],
+      },
+    }],
+    # Apply a lower LTO optimization level in non-official builds.
+    ['use_lto==1 and clang==1 and buildtype!="Official"', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'ldflags': [
+              '-Wl,--plugin-opt,O1',
+            ],
+          }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-Wl,-mllvm,-O1',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['use_lto==1 and clang==1 and (target_arch=="ia32" or target_arch=="x64")', {
+      'target_defaults': {
+        'target_conditions': [
+          # Required for third_party/zlib/crc_folding.c and various other code
+          # that uses SSE. TODO(pcc): Remove this once we properly support
+          # subtarget specific code generation in LLVM.
+          ['_toolset=="target"', {
+            'ldflags': [
+              '-Wl,-plugin-opt,mcpu=corei7-avx',
+            ],
+          }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-Wl,-mcpu,corei7-avx',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['use_lto==1 and clang==1 and target_arch=="arm"', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            # Without this flag, LTO produces a .text section that is larger
+            # than the maximum call displacement, preventing the linker from
+            # relocating calls (http://llvm.org/PR22999).
+            'ldflags': [
+              '-Wl,-plugin-opt,-function-sections',
+            ],
+          }],
+        ],
+      },
+    }],
+    ['(use_lto==1 or use_lto_o2==1) and clang==0', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'ldflags': [
+              '-flto=32',
+            ],
+          }],
+        ],
+      },
+    }],
+    ['(use_lto==1 or use_lto_o2==1) and clang==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'ldflags': [
+              '-flto',
+            ],
+          }],
+        ],
+      },
+    }],
+    ['cfi_vptr==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-fsanitize=cfi-vptr',
+            ],
+            'ldflags': [
+              '-fsanitize=cfi-vptr',
+            ],
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fsanitize=cfi-vptr',
+              ],
+            },
+          }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-fsanitize=cfi-vptr',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['cfi_derived_cast==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-fsanitize=cfi-derived-cast',
+            ],
+            'ldflags': [
+              '-fsanitize=cfi-derived-cast',
+            ],
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fsanitize=cfi-derived-cast',
+              ],
+            },
+          }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-fsanitize=cfi-derived-cast',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['cfi_unrelated_cast==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-fsanitize=cfi-unrelated-cast',
+            ],
+            'ldflags': [
+              '-fsanitize=cfi-unrelated-cast',
+            ],
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fsanitize=cfi-unrelated-cast',
+              ],
+            },
+          }],
+          ['_toolset=="target" and _type!="static_library"', {
+            'xcode_settings':  {
+              'OTHER_LDFLAGS': [
+                '-fsanitize=cfi-unrelated-cast',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+    ['cfi_vptr==1 or cfi_derived_cast==1 or cfi_unrelated_cast==1', {
+      'target_defaults': {
+        'target_conditions': [
+          ['_toolset=="target"', {
+            'cflags': [
+              '-fsanitize-blacklist=<(cfi_blacklist)',
+            ],
+            'xcode_settings': {
+              'OTHER_CFLAGS': [
+                '-fsanitize-blacklist=<(cfi_blacklist)',
+              ],
+            },
+          }],
+        ],
+      },
+    }],
+  ],
+  'xcode_settings': {
+    # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT!
+    # This block adds *project-wide* configuration settings to each project
+    # file.  It's almost always wrong to put things here.  Specify your
+    # custom xcode_settings in target_defaults to add them to targets instead.
+
+    'conditions': [
+      # In an Xcode Project Info window, the "Base SDK for All Configurations"
+      # setting sets the SDK on a project-wide basis. In order to get the
+      # configured SDK to show properly in the Xcode UI, SDKROOT must be set
+      # here at the project level.
+      ['OS=="mac"', {
+        'conditions': [
+          ['mac_sdk_path==""', {
+            'SDKROOT': 'macosx<(mac_sdk)',  # -isysroot
+          }, {
+            'SDKROOT': '<(mac_sdk_path)',  # -isysroot
+          }],
+        ],
+      }],
+      ['OS=="ios"', {
+        'conditions': [
+          ['ios_sdk_path==""', {
+            'conditions': [
+              # TODO(justincohen): Ninja only supports simulator for now.
+              ['"<(GENERATOR)"=="xcode"', {
+                'SDKROOT': 'iphoneos<(ios_sdk)',  # -isysroot
+              }, {
+                'SDKROOT': 'iphonesimulator<(ios_sdk)',  # -isysroot
+              }],
+            ],
+          }, {
+            'SDKROOT': '<(ios_sdk_path)',  # -isysroot
+          }],
+        ],
+      }],
+      ['OS=="ios"', {
+        # Target both iPhone and iPad.
+        'TARGETED_DEVICE_FAMILY': '1,2',
+      }, {  # OS!="ios"
+        'conditions': [
+          ['target_arch=="x64"', {
+            'ARCHS': [
+              'x86_64'
+            ],
+          }],
+          ['target_arch=="ia32"', {
+            'ARCHS': [
+              'i386'
+            ],
+          }],
+        ],
+      }],
+    ],
+
+    # The Xcode generator will look for an xcode_settings section at the root
+    # of each dict and use it to apply settings on a file-wide basis.  Most
+    # settings should not be here, they should be in target-specific
+    # xcode_settings sections, or better yet, should use non-Xcode-specific
+    # settings in target dicts.  SYMROOT is a special case, because many other
+    # Xcode variables depend on it, including variables such as
+    # PROJECT_DERIVED_FILE_DIR.  When a source group corresponding to something
+    # like PROJECT_DERIVED_FILE_DIR is added to a project, in order for the
+    # files to appear (when present) in the UI as actual files and not red
+    # red "missing file" proxies, the correct path to PROJECT_DERIVED_FILE_DIR,
+    # and therefore SYMROOT, needs to be set at the project level.
+    'SYMROOT': '<(DEPTH)/xcodebuild',
+  },
+}
diff --git a/build/common_untrusted.gypi b/build/common_untrusted.gypi
new file mode 100644
index 0000000..bcc3686
--- /dev/null
+++ b/build/common_untrusted.gypi
@@ -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.
+
+# This GYP file should be included for every target in Chromium that is built
+# using the NaCl toolchain.
+{
+  'includes': [
+    '../native_client/build/untrusted.gypi',
+  ],
+  'target_defaults': {
+    'conditions': [
+      # TODO(bradnelson): Drop this once the nacl side does the same.
+      ['target_arch=="x64"', {
+        'variables': {
+          'enable_x86_32': 0,
+        },
+      }],
+      ['target_arch=="ia32" and OS!="win"', {
+        'variables': {
+          'enable_x86_64': 0,
+        },
+      }],
+      ['target_arch=="arm"', {
+        'variables': {
+          'clang': 1,
+        },
+        'defines': [
+          # Needed by build/build_config.h processor architecture detection.
+          '__ARMEL__',
+          # Needed by base/third_party/nspr/prtime.cc.
+          '__arm__',
+          # Disable ValGrind. The assembly code it generates causes the build
+          # to fail.
+          'NVALGRIND',
+        ],
+      }],
+    ],
+  },
+}
diff --git a/build/compiled_action.gni b/build/compiled_action.gni
new file mode 100644
index 0000000..b6d0c4d
--- /dev/null
+++ b/build/compiled_action.gni
@@ -0,0 +1,173 @@
+# Copyright 2014 The Chromium 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 introduces two related templates that act like action and
+# action_foreach but instead of running a Python script, it will compile a
+# given tool in the host toolchain and run that (either once or over the list
+# of inputs, depending on the variant).
+#
+# Parameters
+#
+#   tool (required)
+#       [label] Label of the tool to run. This should be an executable, and
+#       this label should not include a toolchain (anything in parens). The
+#       host compile of this tool will be used.
+#
+#   outputs (required)
+#       [list of files] Like the outputs of action (if using "compiled_action",
+#       this would be just the list of outputs), or action_foreach (if using
+#       "compiled_action_foreach", this would contain source expansions mapping
+#       input to output files).
+#
+#   args (required)
+#       [list of strings] Same meaning as action/action_foreach.
+#
+#   inputs (optional)
+#       Files the binary takes as input. The step will be re-run whenever any
+#       of these change. If inputs is empty, the step will run only when the
+#       binary itself changes.
+#
+#   visibility
+#   deps
+#   args   (all optional)
+#       Same meaning as action/action_foreach.
+#
+#
+# Example of usage:
+#
+#   compiled_action("run_my_tool") {
+#     tool = "//tools/something:mytool"
+#     outputs = [
+#       "$target_gen_dir/mysource.cc",
+#       "$target_gen_dir/mysource.h",
+#     ]
+#
+#     # The tool takes this input.
+#     inputs = [ "my_input_file.idl" ]
+#
+#     # In this case, the tool takes as arguments the input file and the output
+#     # build dir (both relative to the "cd" that the script will be run in)
+#     # and will produce the output files listed above.
+#     args = [
+#       rebase_path("my_input_file.idl", root_build_dir),
+#       "--output-dir", rebase_path(target_gen_dir, root_build_dir),
+#     ]
+#   }
+#
+# You would typically declare your tool like this:
+#   if (host_toolchain == current_toolchain) {
+#     executable("mytool") {
+#       ...
+#     }
+#   }
+# The if statement around the executable is optional. That says "I only care
+# about this target in the host toolchain". Usually this is what you want, and
+# saves unnecessarily compiling your tool for the target platform. But if you
+# need a target build of your tool as well, just leave off the if statement.
+
+if (host_os == "win") {
+  _host_executable_suffix = ".exe"
+} else {
+  _host_executable_suffix = ""
+}
+
+template("compiled_action") {
+  assert(defined(invoker.tool), "tool must be defined for $target_name")
+  assert(defined(invoker.outputs), "outputs must be defined for $target_name")
+  assert(defined(invoker.args), "args must be defined for $target_name")
+
+  assert(!defined(invoker.sources),
+         "compiled_action doesn't take a sources arg. Use inputs instead.")
+
+  action(target_name) {
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+
+    script = "//build/gn_run_binary.py"
+
+    if (defined(invoker.inputs)) {
+      inputs = invoker.inputs
+    } else {
+      inputs = []
+    }
+    outputs = invoker.outputs
+
+    # Constuct the host toolchain version of the tool.
+    host_tool = invoker.tool + "($host_toolchain)"
+
+    # Get the path to the executable. Currently, this assumes that the tool
+    # does not specify output_name so that the target name is the name to use.
+    # If that's not the case, we'll need another argument to the script to
+    # specify this, since we can't know what the output name is (it might be in
+    # another file not processed yet).
+    host_executable =
+        get_label_info(host_tool, "root_out_dir") + "/" +
+        get_label_info(host_tool, "name") + _host_executable_suffix
+
+    # Add the executable itself as an input.
+    inputs += [ host_executable ]
+
+    deps = [
+      host_tool,
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
+    # The script takes as arguments the binary to run, and then the arguments
+    # to pass it.
+    args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args
+  }
+}
+
+template("compiled_action_foreach") {
+  assert(defined(invoker.sources), "sources must be defined for $target_name")
+  assert(defined(invoker.tool), "tool must be defined for $target_name")
+  assert(defined(invoker.outputs), "outputs must be defined for $target_name")
+  assert(defined(invoker.args), "args must be defined for $target_name")
+
+  action_foreach(target_name) {
+    # Otherwise this is a standalone action, define visibility if requested.
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+
+    script = "//build/gn_run_binary.py"
+    sources = invoker.sources
+
+    if (defined(invoker.inputs)) {
+      inputs = invoker.inputs
+    } else {
+      inputs = []
+    }
+    outputs = invoker.outputs
+
+    # Constuct the host toolchain version of the tool.
+    host_tool = invoker.tool + "($host_toolchain)"
+
+    # Get the path to the executable. Currently, this assumes that the tool
+    # does not specify output_name so that the target name is the name to use.
+    # If that's not the case, we'll need another argument to the script to
+    # specify this, since we can't know what the output name is (it might be in
+    # another file not processed yet).
+    host_executable =
+        get_label_info(host_tool, "root_out_dir") + "/" +
+        get_label_info(host_tool, "name") + _host_executable_suffix
+
+    # Add the executable itself as an input.
+    inputs += [ host_executable ]
+
+    deps = [
+      host_tool,
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
+    # The script takes as arguments the binary to run, and then the arguments
+    # to pass it.
+    args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args
+  }
+}
diff --git a/build/compiler_version.py b/build/compiler_version.py
new file mode 100755
index 0000000..05faf54
--- /dev/null
+++ b/build/compiler_version.py
@@ -0,0 +1,143 @@
+#!/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.
+
+"""Compiler version checking tool for gcc
+
+Print gcc version as XY if you are running gcc X.Y.*.
+This is used to tweak build flags for gcc 4.4.
+"""
+
+import os
+import re
+import subprocess
+import sys
+
+
+compiler_version_cache = {}  # Map from (compiler, tool) -> version.
+
+
+def Usage(program_name):
+  print '%s MODE TOOL' % os.path.basename(program_name)
+  print 'MODE: host or target.'
+  print 'TOOL: assembler or compiler or linker.'
+  return 1
+
+
+def ParseArgs(args):
+  if len(args) != 2:
+    raise Exception('Invalid number of arguments')
+  mode = args[0]
+  tool = args[1]
+  if mode not in ('host', 'target'):
+    raise Exception('Invalid mode: %s' % mode)
+  if tool not in ('assembler', 'compiler', 'linker'):
+    raise Exception('Invalid tool: %s' % tool)
+  return mode, tool
+
+
+def GetEnvironFallback(var_list, default):
+  """Look up an environment variable from a possible list of variable names."""
+  for var in var_list:
+    if var in os.environ:
+      return os.environ[var]
+  return default
+
+
+def GetVersion(compiler, tool):
+  tool_output = tool_error = None
+  cache_key = (compiler, tool)
+  cached_version = compiler_version_cache.get(cache_key)
+  if cached_version:
+    return cached_version
+  try:
+    # Note that compiler could be something tricky like "distcc g++".
+    if tool == "compiler":
+      compiler = compiler + " -dumpversion"
+      # 4.6
+      version_re = re.compile(r"(\d+)\.(\d+)")
+    elif tool == "assembler":
+      compiler = compiler + " -Xassembler --version -x assembler -c /dev/null"
+      # Unmodified: GNU assembler (GNU Binutils) 2.24
+      # Ubuntu: GNU assembler (GNU Binutils for Ubuntu) 2.22
+      # Fedora: GNU assembler version 2.23.2
+      version_re = re.compile(r"^GNU [^ ]+ .* (\d+).(\d+).*?$", re.M)
+    elif tool == "linker":
+      compiler = compiler + " -Xlinker --version"
+      # Using BFD linker
+      # Unmodified: GNU ld (GNU Binutils) 2.24
+      # Ubuntu: GNU ld (GNU Binutils for Ubuntu) 2.22
+      # Fedora: GNU ld version 2.23.2
+      # Using Gold linker
+      # Unmodified: GNU gold (GNU Binutils 2.24) 1.11
+      # Ubuntu: GNU gold (GNU Binutils for Ubuntu 2.22) 1.11
+      # Fedora: GNU gold (version 2.23.2) 1.11
+      version_re = re.compile(r"^GNU [^ ]+ .* (\d+).(\d+).*?$", re.M)
+    else:
+      raise Exception("Unknown tool %s" % tool)
+
+    # Force the locale to C otherwise the version string could be localized
+    # making regex matching fail.
+    env = os.environ.copy()
+    env["LC_ALL"] = "C"
+    pipe = subprocess.Popen(compiler, shell=True, env=env,
+                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    tool_output, tool_error = pipe.communicate()
+    if pipe.returncode:
+      raise subprocess.CalledProcessError(pipe.returncode, compiler)
+
+    parsed_output = version_re.match(tool_output)
+    result = parsed_output.group(1) + parsed_output.group(2)
+    compiler_version_cache[cache_key] = result
+    return result
+  except Exception, e:
+    if tool_error:
+      sys.stderr.write(tool_error)
+    print >> sys.stderr, "compiler_version.py failed to execute:", compiler
+    print >> sys.stderr, e
+    return ""
+
+
+def main(args):
+  try:
+    (mode, tool) = ParseArgs(args[1:])
+  except Exception, e:
+    sys.stderr.write(e.message + '\n\n')
+    return Usage(args[0])
+
+  ret_code, result = ExtractVersion(mode, tool)
+  if ret_code == 0:
+    print result
+  return ret_code
+
+
+def DoMain(args):
+  """Hook to be called from gyp without starting a separate python
+  interpreter."""
+  (mode, tool) = ParseArgs(args)
+  ret_code, result = ExtractVersion(mode, tool)
+  if ret_code == 0:
+    return result
+  raise Exception("Failed to extract compiler version for args: %s" % args)
+
+
+def ExtractVersion(mode, tool):
+  # Check if various CXX environment variables exist and use them if they
+  # exist. The preferences and fallback order is a close approximation of
+  # GenerateOutputForConfig() in GYP's ninja generator.
+  # The main difference being not supporting GYP's make_global_settings.
+  environments = ['CXX_target', 'CXX']
+  if mode == 'host':
+    environments = ['CXX_host'] + environments;
+  compiler = GetEnvironFallback(environments, 'c++')
+
+  if compiler:
+    compiler_version = GetVersion(compiler, tool)
+    if compiler_version != "":
+      return (0, compiler_version)
+  return (1, None)
+
+
+if __name__ == "__main__":
+  sys.exit(main(sys.argv))
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
new file mode 100644
index 0000000..2427b72
--- /dev/null
+++ b/build/config/BUILD.gn
@@ -0,0 +1,348 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/allocator.gni")
+import("//build/config/chrome_build.gni")
+import("//build/config/crypto.gni")
+import("//build/config/features.gni")
+import("//build/config/ui.gni")
+import("//build/module_args/v8.gni")
+
+declare_args() {
+  # When set, turns off the (normally-on) iterator debugging and related stuff
+  # that is normally turned on for Debug builds. These are generally useful for
+  # catching bugs but in some cases may cause conflicts or excessive slowness.
+  disable_iterator_debugging = false
+
+  # Set to true to not store any build metadata, e.g. ifdef out all __DATE__
+  # and __TIME__. Set to 0 to reenable the use of these macros in the code
+  # base. See http://crbug.com/314403.
+  #
+  # Continue to embed build meta data in Official builds, basically the
+  # time it was built.
+  # TODO(maruel): This decision should be revisited because having an
+  # official deterministic build has high value too but MSVC toolset can't
+  # generate anything deterministic with WPO enabled AFAIK.
+  dont_embed_build_metadata = !is_official_build
+
+  # Set to true to enable dcheck in Release builds.
+  dcheck_always_on = false
+
+  # Set to true to compile with the OpenGL ES 2.0 conformance tests.
+  internal_gles2_conform_tests = false
+}
+
+# TODO(brettw) Most of these should be removed. Instead of global feature
+# flags, we should have more modular flags that apply only to a target and its
+# dependents. For example, depending on the "x11" meta-target should define
+# USE_X11 for all dependents so that everything that could use X11 gets the
+# define, but anything that doesn't depend on X11 doesn't see it.
+#
+# For now we define these globally to match the current GYP build.
+config("feature_flags") {
+  # TODO(brettw) most of these need to be parameterized.
+  defines = [
+    "CHROMIUM_BUILD",
+    "V8_DEPRECATION_WARNINGS",  # Don't use deprecated V8 APIs anywhere.
+  ]
+
+  if (cld_version > 0) {
+    defines += [ "CLD_VERSION=$cld_version" ]
+  }
+  if (enable_mdns) {
+    defines += [ "ENABLE_MDNS=1" ]
+  }
+  if (enable_notifications) {
+    defines += [ "ENABLE_NOTIFICATIONS" ]
+  }
+  if (enable_pepper_cdms) {
+    # TODO(brettw) should probably be "=1"
+    defines += [ "ENABLE_PEPPER_CDMS" ]
+  }
+  if (enable_browser_cdms) {
+    # TODO(brettw) should probably be "=1"
+    defines += [ "ENABLE_BROWSER_CDMS" ]
+  }
+  if (enable_plugins) {
+    defines += [ "ENABLE_PLUGINS=1" ]
+  }
+  if (enable_basic_printing || enable_print_preview) {
+    # Convenience define for ENABLE_BASIC_PRINTING || ENABLE_PRINT_PREVIEW.
+    defines += [ "ENABLE_PRINTING=1" ]
+    if (enable_basic_printing) {
+      # Enable basic printing support and UI.
+      defines += [ "ENABLE_BASIC_PRINTING=1" ]
+    }
+    if (enable_print_preview) {
+      # Enable printing with print preview.
+      # Can be defined without ENABLE_BASIC_PRINTING.
+      defines += [ "ENABLE_PRINT_PREVIEW=1" ]
+    }
+  }
+  if (enable_spellcheck) {
+    defines += [ "ENABLE_SPELLCHECK=1" ]
+  }
+  if (dont_embed_build_metadata) {
+    defines += [ "DONT_EMBED_BUILD_METADATA" ]
+  }
+  if (dcheck_always_on) {
+    defines += [ "DCHECK_ALWAYS_ON=1" ]
+  }
+  if (use_udev) {
+    # TODO(brettw) should probably be "=1".
+    defines += [ "USE_UDEV" ]
+  }
+  if (toolkit_views) {
+    defines += [ "TOOLKIT_VIEWS=1" ]
+  }
+  if (ui_compositor_image_transport) {
+    # TODO(brettw) should probably be "=1".
+    defines += [ "UI_COMPOSITOR_IMAGE_TRANSPORT" ]
+  }
+  if (use_ash) {
+    defines += [ "USE_ASH=1" ]
+  }
+  if (use_aura) {
+    defines += [ "USE_AURA=1" ]
+  }
+  if (use_pango) {
+    defines += [ "USE_PANGO=1" ]
+  }
+  if (use_cairo) {
+    defines += [ "USE_CAIRO=1" ]
+  }
+  if (use_clipboard_aurax11) {
+    defines += [ "USE_CLIPBOARD_AURAX11=1" ]
+  }
+  if (use_default_render_theme) {
+    defines += [ "USE_DEFAULT_RENDER_THEME=1" ]
+  }
+  if (use_glib) {
+    defines += [ "USE_GLIB=1" ]
+  }
+  if (use_openssl) {
+    defines += [ "USE_OPENSSL=1" ]
+  }
+  if (use_openssl_certs) {
+    defines += [ "USE_OPENSSL_CERTS=1" ]
+  }
+  if (use_nss_certs) {
+    defines += [ "USE_NSS_CERTS=1" ]
+  }
+  if (use_ozone) {
+    defines += [ "USE_OZONE=1" ]
+  }
+  if (use_x11) {
+    defines += [ "USE_X11=1" ]
+  }
+  if (use_allocator != "tcmalloc") {
+    defines += [ "NO_TCMALLOC" ]
+  }
+  if (is_asan) {
+    defines += [
+      "ADDRESS_SANITIZER",
+      "MEMORY_TOOL_REPLACES_ALLOCATOR",
+      "MEMORY_SANITIZER_INITIAL_SIZE",
+    ]
+  }
+  if (enable_webrtc) {
+    defines += [ "ENABLE_WEBRTC=1" ]
+  }
+  if (disable_ftp_support) {
+    defines += [ "DISABLE_FTP_SUPPORT=1" ]
+  }
+  if (!enable_nacl) {
+    defines += [ "DISABLE_NACL" ]
+  }
+  if (enable_extensions) {
+    defines += [ "ENABLE_EXTENSIONS=1" ]
+  }
+  if (enable_configuration_policy) {
+    defines += [ "ENABLE_CONFIGURATION_POLICY" ]
+  }
+  if (enable_task_manager) {
+    defines += [ "ENABLE_TASK_MANAGER=1" ]
+  }
+  if (enable_themes) {
+    defines += [ "ENABLE_THEMES=1" ]
+  }
+  if (enable_captive_portal_detection) {
+    defines += [ "ENABLE_CAPTIVE_PORTAL_DETECTION=1" ]
+  }
+  if (enable_session_service) {
+    defines += [ "ENABLE_SESSION_SERVICE=1" ]
+  }
+  if (enable_rlz) {
+    defines += [ "ENABLE_RLZ" ]
+  }
+  if (enable_plugin_installation) {
+    defines += [ "ENABLE_PLUGIN_INSTALLATION=1" ]
+  }
+  if (enable_app_list) {
+    defines += [ "ENABLE_APP_LIST=1" ]
+  }
+  if (enable_settings_app) {
+    defines += [ "ENABLE_SETTINGS_APP=1" ]
+  }
+  if (enable_supervised_users) {
+    defines += [ "ENABLE_SUPERVISED_USERS=1" ]
+  }
+  if (enable_service_discovery) {
+    defines += [ "ENABLE_SERVICE_DISCOVERY=1" ]
+  }
+  if (enable_autofill_dialog) {
+    defines += [ "ENABLE_AUTOFILL_DIALOG=1" ]
+  }
+  if (enable_wifi_bootstrapping) {
+    defines += [ "ENABLE_WIFI_BOOTSTRAPPING=1" ]
+  }
+  if (enable_image_loader_extension) {
+    defines += [ "IMAGE_LOADER_EXTENSION=1" ]
+  }
+  if (enable_remoting) {
+    defines += [ "ENABLE_REMOTING=1" ]
+  }
+  if (enable_google_now) {
+    defines += [ "ENABLE_GOOGLE_NOW=1" ]
+  }
+  if (enable_one_click_signin) {
+    defines += [ "ENABLE_ONE_CLICK_SIGNIN" ]
+  }
+  if (enable_hidpi) {
+    defines += [ "ENABLE_HIDPI=1" ]
+  }
+  if (proprietary_codecs) {
+    defines += [ "USE_PROPRIETARY_CODECS" ]
+  }
+  if (enable_hangout_services_extension) {
+    defines += [ "ENABLE_HANGOUT_SERVICES_EXTENSION=1" ]
+  }
+  if (v8_use_external_startup_data) {
+    defines += [ "V8_USE_EXTERNAL_STARTUP_DATA" ]
+  }
+  if (enable_background) {
+    defines += [ "ENABLE_BACKGROUND=1" ]
+  }
+  if (enable_pre_sync_backup) {
+    defines += [ "ENABLE_PRE_SYNC_BACKUP" ]
+  }
+  if (enable_video_hole) {
+    defines += [ "VIDEO_HOLE=1" ]
+  }
+  if (safe_browsing_mode == 1) {
+    defines += [ "FULL_SAFE_BROWSING" ]
+    defines += [ "SAFE_BROWSING_CSD" ]
+    defines += [ "SAFE_BROWSING_DB_LOCAL" ]
+    defines += [ "SAFE_BROWSING_SERVICE" ]
+  } else if (safe_browsing_mode == 2) {
+    defines += [ "MOBILE_SAFE_BROWSING" ]
+    defines += [ "SAFE_BROWSING_SERVICE" ]
+  }
+}
+
+# Debug/release ----------------------------------------------------------------
+
+config("debug") {
+  defines = [
+    "_DEBUG",
+    "DYNAMIC_ANNOTATIONS_ENABLED=1",
+    "WTF_USE_DYNAMIC_ANNOTATIONS=1",
+  ]
+
+  if (is_nacl) {
+    defines += [ "DYNAMIC_ANNOTATIONS_PREFIX=NACL_" ]
+  }
+
+  if (is_win) {
+    if (disable_iterator_debugging) {
+      # Iterator debugging is enabled by the compiler on debug builds, and we
+      # have to tell it to turn it off.
+      defines += [ "_HAS_ITERATOR_DEBUGGING=0" ]
+    }
+  } else if (is_linux && !is_android && current_cpu == "x64" &&
+             !disable_iterator_debugging) {
+    # Enable libstdc++ debugging facilities to help catch problems early, see
+    # http://crbug.com/65151 .
+    # TODO(phajdan.jr): Should we enable this for all of POSIX?
+    defines += [ "_GLIBCXX_DEBUG=1" ]
+  }
+}
+
+config("release") {
+  defines = [ "NDEBUG" ]
+}
+
+# Default libraries ------------------------------------------------------------
+
+# This config defines the default libraries applied to all targets.
+config("default_libs") {
+  if (is_win) {
+    # TODO(brettw) this list of defaults should probably be smaller, and
+    # instead the targets that use the less common ones (e.g. wininet or
+    # winspool) should include those explicitly.
+    libs = [
+      "advapi32.lib",
+      "comdlg32.lib",
+      "dbghelp.lib",
+      "delayimp.lib",
+      "dnsapi.lib",
+      "gdi32.lib",
+      "kernel32.lib",
+      "msimg32.lib",
+      "odbc32.lib",
+      "odbccp32.lib",
+      "ole32.lib",
+      "oleaut32.lib",
+      "psapi.lib",
+      "shell32.lib",
+      "shlwapi.lib",
+      "user32.lib",
+      "usp10.lib",
+      "uuid.lib",
+      "version.lib",
+      "wininet.lib",
+      "winmm.lib",
+      "winspool.lib",
+      "ws2_32.lib",
+
+      # Please don't add more stuff here. We should actually be making this
+      # list smaller, since all common things should be covered. If you need
+      # some extra libraries, please just add a libs = [ "foo.lib" ] to your
+      # target that needs it.
+    ]
+  } else if (is_android) {
+    # Android uses -nostdlib so we need to add even libc here.
+    libs = [
+      # TODO(brettw) write a version of this, hopefully we can express this
+      # without forking out to GCC just to get the library name. The android
+      # toolchain directory should probably be extracted into a .gni file that
+      # this file and the android toolchain .gn file can share.
+      #   # Manually link the libgcc.a that the cross compiler uses.
+      #   '<!(<(android_toolchain)/*-gcc -print-libgcc-file-name)',
+      "c",
+      "dl",
+      "m",
+    ]
+  } else if (is_mac) {
+    libs = [
+      "AppKit.framework",
+      "ApplicationServices.framework",
+      "Carbon.framework",
+      "CoreFoundation.framework",
+      "Foundation.framework",
+      "IOKit.framework",
+      "Security.framework",
+    ]
+  } else if (is_ios) {
+    libs = [
+      "CoreFoundation.framework",
+      "CoreGraphics.framework",
+      "CoreText.framework",
+      "Foundation.framework",
+      "UIKit.framework",
+    ]
+  } else if (is_linux) {
+    libs = [ "dl" ]
+  }
+}
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
new file mode 100644
index 0000000..2274c0e
--- /dev/null
+++ b/build/config/BUILDCONFIG.gn
@@ -0,0 +1,729 @@
+# 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.
+
+# =============================================================================
+# BUILD FLAGS
+# =============================================================================
+#
+# This block lists input arguments to the build, along with their default
+# values. GN requires listing them explicitly so it can validate input and have
+# a central place to manage the build flags.
+#
+# If a value is specified on the command line, it will overwrite the defaults
+# given here, otherwise the default will be injected into the root scope.
+#
+# KEEP IN ALPHABETICAL ORDER and write a good description for everything.
+# Use "is_*" names for intrinsic platform descriptions and build modes, and
+# "use_*" names for optional features libraries, and configurations.
+
+if (target_os == "") {
+  target_os = host_os
+}
+
+if (target_cpu == "") {
+  if (target_os == "android") {
+    # If we're building for Android, we should assume that we want to
+    # build for ARM by default, not the host_cpu (which is likely x64).
+    # This allows us to not have to specify both target_os and target_cpu
+    # on the command line.
+    target_cpu = "arm"
+  } else {
+    target_cpu = host_cpu
+  }
+}
+
+if (current_cpu == "") {
+  current_cpu = target_cpu
+}
+if (current_os == "") {
+  current_os = target_os
+}
+
+declare_args() {
+  # How many symbols to include in the build. This affects the performance of
+  # the build since the symbols are large and dealing with them is slow.
+  #   2 means regular build with symbols.
+  #   1 means minimal symbols, usually enough for backtraces only.
+  #   0 means no symbols.
+  #   -1 means auto-set (off in release, regular in debug).
+  symbol_level = -1
+
+  # Component build.
+  is_component_build = false
+
+  # Debug build.
+  is_debug = true
+
+  # Whether we're a traditional desktop unix.
+  is_desktop_linux = current_os == "linux" && current_os != "chromeos"
+
+  # Set to true when compiling with the Clang compiler. Typically this is used
+  # to configure warnings.
+  is_clang = current_os == "mac" || current_os == "ios" ||
+             current_os == "linux" || current_os == "chromeos"
+
+  # Selects the desired build flavor. Official builds get additional
+  # processing to prepare for release. Normally you will want to develop and
+  # test with this flag off.
+  # TODO(brettw) move to chrome_build.gni when DEPS are updated.
+  is_official_build = false
+
+  # Select the desired branding flavor. False means normal Chromium branding,
+  # true means official Google Chrome branding (requires extra Google-internal
+  # resources).
+  # TODO(brettw) move to chrome_build.gni when DEPS are updated.
+  is_chrome_branded = false
+
+  # Compile for Address Sanitizer to find memory bugs.
+  is_asan = false
+
+  # Compile for Leak Sanitizer to find leaks.
+  is_lsan = false
+
+  # Compile for Memory Sanitizer to find uninitialized reads.
+  is_msan = false
+
+  # Compile for Thread Sanitizer to find threading bugs.
+  is_tsan = false
+
+  if (current_os == "chromeos") {
+    # Allows the target toolchain to be injected as arguments. This is needed
+    # to support the CrOS build system which supports per-build-configuration
+    # toolchains.
+    cros_use_custom_toolchain = false
+  }
+}
+
+# =============================================================================
+# OS DEFINITIONS
+# =============================================================================
+#
+# We set these various is_FOO booleans for convenience in writing OS-based
+# conditions.
+#
+# - is_android, is_chromeos, is_ios, and is_win should be obvious.
+# - is_mac is set only for desktop Mac. It is not set on iOS.
+# - is_posix is true for mac and any Unix-like system (basically everything
+#   except Windows).
+# - is_linux is true for desktop Linux and ChromeOS, but not Android (which is
+#   generally too different despite being based on the Linux kernel).
+#
+# Do not add more is_* variants here for random lesser-used Unix systems like
+# aix or one of the BSDs. If you need to check these, just check the
+# current_os value directly.
+
+if (current_os == "win") {
+  is_android = false
+  is_chromeos = false
+  is_ios = false
+  is_linux = false
+  is_mac = false
+  is_nacl = false
+  is_posix = false
+  is_win = true
+} else if (current_os == "mac") {
+  is_android = false
+  is_chromeos = false
+  is_ios = false
+  is_linux = false
+  is_mac = true
+  is_nacl = false
+  is_posix = true
+  is_win = false
+} else if (current_os == "android") {
+  is_android = true
+  is_chromeos = false
+  is_ios = false
+  is_linux = false
+  is_mac = false
+  is_nacl = false
+  is_posix = true
+  is_win = false
+} else if (current_os == "chromeos") {
+  is_android = false
+  is_chromeos = true
+  is_ios = false
+  is_linux = true
+  is_mac = false
+  is_nacl = false
+  is_posix = true
+  is_win = false
+} else if (current_os == "nacl") {
+  # current_os == "nacl" will be passed by the nacl toolchain definition.
+  # It is not set by default or on the command line. We treat is as a
+  # Posix variant.
+  is_android = false
+  is_chromeos = false
+  is_ios = false
+  is_linux = false
+  is_mac = false
+  is_nacl = true
+  is_posix = true
+  is_win = false
+} else if (current_os == "ios") {
+  is_android = false
+  is_chromeos = false
+  is_ios = true
+  is_linux = false
+  is_mac = false
+  is_nacl = false
+  is_posix = true
+  is_win = false
+} else if (current_os == "linux") {
+  is_android = false
+  is_chromeos = false
+  is_ios = false
+  is_linux = true
+  is_mac = false
+  is_nacl = false
+  is_posix = true
+  is_win = false
+}
+
+# =============================================================================
+# SOURCES FILTERS
+# =============================================================================
+#
+# These patterns filter out platform-specific files when assigning to the
+# sources variable. The magic variable |sources_assignment_filter| is applied
+# to each assignment or appending to the sources variable and matches are
+# automatcally removed.
+#
+# Note that the patterns are NOT regular expressions. Only "*" and "\b" (path
+# boundary = end of string or slash) are supported, and the entire string
+# muct match the pattern (so you need "*.cc" to match all .cc files, for
+# example).
+
+# DO NOT ADD MORE PATTERNS TO THIS LIST, see set_sources_assignment_filter call
+# below.
+sources_assignment_filter = []
+if (!is_posix) {
+  sources_assignment_filter += [
+    "*_posix.h",
+    "*_posix.cc",
+    "*_posix_unittest.h",
+    "*_posix_unittest.cc",
+    "*\bposix/*",
+  ]
+}
+if (!is_win) {
+  sources_assignment_filter += [
+    "*_win.cc",
+    "*_win.h",
+    "*_win_unittest.cc",
+    "*\bwin/*",
+    "*.rc",
+  ]
+}
+if (!is_mac) {
+  sources_assignment_filter += [
+    "*_mac.h",
+    "*_mac.cc",
+    "*_mac.mm",
+    "*_mac_unittest.h",
+    "*_mac_unittest.cc",
+    "*_mac_unittest.mm",
+    "*\bmac/*",
+    "*_cocoa.h",
+    "*_cocoa.cc",
+    "*_cocoa.mm",
+    "*_cocoa_unittest.h",
+    "*_cocoa_unittest.cc",
+    "*_cocoa_unittest.mm",
+    "*\bcocoa/*",
+  ]
+}
+if (!is_ios) {
+  sources_assignment_filter += [
+    "*_ios.h",
+    "*_ios.cc",
+    "*_ios.mm",
+    "*_ios_unittest.h",
+    "*_ios_unittest.cc",
+    "*_ios_unittest.mm",
+    "*\bios/*",
+  ]
+}
+if (!is_mac && !is_ios) {
+  sources_assignment_filter += [ "*.mm" ]
+}
+if (!is_linux) {
+  sources_assignment_filter += [
+    "*_linux.h",
+    "*_linux.cc",
+    "*_linux_unittest.h",
+    "*_linux_unittest.cc",
+    "*\blinux/*",
+  ]
+}
+if (!is_android) {
+  sources_assignment_filter += [
+    "*_android.h",
+    "*_android.cc",
+    "*_android_unittest.h",
+    "*_android_unittest.cc",
+    "*\bandroid/*",
+  ]
+}
+if (!is_chromeos) {
+  sources_assignment_filter += [
+    "*_chromeos.h",
+    "*_chromeos.cc",
+    "*_chromeos_unittest.h",
+    "*_chromeos_unittest.cc",
+    "*\bchromeos/*",
+  ]
+}
+
+# DO NOT ADD MORE PATTERNS TO THIS LIST, see set_sources_assignment_filter call
+# below.
+
+# Actually save this list.
+#
+# These patterns are executed for every file in the source tree of every run.
+# Therefore, adding more patterns slows down the build for everybody. We should
+# only add automatic patterns for configurations affecting hundreds of files
+# across many projects in the tree.
+#
+# Therefore, we only add rules to this list corresponding to platforms on the
+# Chromium waterfall.  This is not for non-officially-supported platforms
+# (FreeBSD, etc.) toolkits, (X11, GTK, etc.), or features. For these cases,
+# write a conditional in the target to remove the file(s) from the list when
+# your platform/toolkit/feature doesn't apply.
+set_sources_assignment_filter(sources_assignment_filter)
+
+# =============================================================================
+# BUILD OPTIONS
+# =============================================================================
+
+# These Sanitizers all imply using the Clang compiler. On Windows they either
+# don't work or work differently.
+if (!is_clang && (is_asan || is_lsan || is_tsan || is_msan)) {
+  is_clang = true
+}
+
+# =============================================================================
+# TARGET DEFAULTS
+# =============================================================================
+#
+# Set up the default configuration for every build target of the given type.
+# The values configured here will be automatically set on the scope of the
+# corresponding target. Target definitions can add or remove to the settings
+# here as needed.
+
+# Holds all configs used for making native executables and libraries, to avoid
+# duplication in each target below.
+_native_compiler_configs = [
+  "//build/config:feature_flags",
+  "//build/config/compiler:compiler",
+  "//build/config/compiler:compiler_arm_fpu",
+  "//build/config/compiler:chromium_code",
+  "//build/config/compiler:default_include_dirs",
+  "//build/config/compiler:default_warnings",
+  "//build/config/compiler:no_rtti",
+  "//build/config/compiler:runtime_library",
+]
+if (is_win) {
+  _native_compiler_configs += [
+    "//build/config/win:lean_and_mean",
+    "//build/config/win:nominmax",
+    "//build/config/win:sdk",
+    "//build/config/win:unicode",
+    "//build/config/win:winver",
+  ]
+}
+if (is_posix) {
+  _native_compiler_configs += [
+    "//build/config/gcc:no_exceptions",
+    "//build/config/gcc:symbol_visibility_hidden",
+  ]
+}
+
+if (is_linux) {
+  _native_compiler_configs += [ "//build/config/linux:sdk" ]
+} else if (is_mac) {
+  _native_compiler_configs += [ "//build/config/mac:sdk" ]
+} else if (is_ios) {
+  _native_compiler_configs += [ "//build/config/ios:sdk" ]
+} else if (is_android) {
+  _native_compiler_configs += [ "//build/config/android:sdk" ]
+}
+
+if (is_clang) {
+  _native_compiler_configs += [
+    "//build/config/clang:find_bad_constructs",
+    "//build/config/clang:extra_warnings",
+  ]
+}
+
+# Optimizations and debug checking.
+if (is_debug) {
+  _native_compiler_configs += [ "//build/config:debug" ]
+  _default_optimization_config = "//build/config/compiler:no_optimize"
+} else {
+  _native_compiler_configs += [ "//build/config:release" ]
+  _default_optimization_config = "//build/config/compiler:optimize"
+}
+_native_compiler_configs += [ _default_optimization_config ]
+
+# If it wasn't manually set, set to an appropriate default.
+if (symbol_level == -1) {
+  # Linux is slowed by having symbols as part of the target binary, whereas
+  # Mac and Windows have them separate, so in Release Linux, default them off.
+  if (is_debug || !is_linux) {
+    symbol_level = 2
+  } else {
+    symbol_level = 0
+  }
+}
+
+# Symbol setup.
+if (symbol_level == 2) {
+  _default_symbols_config = "//build/config/compiler:symbols"
+} else if (symbol_level == 1) {
+  _default_symbols_config = "//build/config/compiler:minimal_symbols"
+} else if (symbol_level == 0) {
+  _default_symbols_config = "//build/config/compiler:no_symbols"
+} else {
+  assert(false, "Bad value for symbol_level.")
+}
+_native_compiler_configs += [ _default_symbols_config ]
+
+# Windows linker setup for EXEs and DLLs.
+if (is_win) {
+  _windows_linker_configs = [
+    "//build/config/win:default_incremental_linking",
+    "//build/config/win:sdk_link",
+    "//build/config/win:common_linker_setup",
+
+    # Default to console-mode apps. Most of our targets are tests and such
+    # that shouldn't use the windows subsystem.
+    "//build/config/win:console",
+  ]
+}
+
+# Executable defaults.
+_executable_configs =
+    _native_compiler_configs + [ "//build/config:default_libs" ]
+if (is_win) {
+  _executable_configs += _windows_linker_configs
+} else if (is_mac) {
+  _executable_configs += [
+    "//build/config/mac:mac_dynamic_flags",
+    "//build/config/mac:mac_executable_flags",
+  ]
+} else if (is_linux || is_android) {
+  _executable_configs += [ "//build/config/gcc:executable_ldconfig" ]
+  if (is_android) {
+    _executable_configs += [ "//build/config/android:executable_config" ]
+  }
+}
+set_defaults("executable") {
+  configs = _executable_configs
+}
+
+# Static library defaults.
+set_defaults("static_library") {
+  configs = _native_compiler_configs
+}
+
+# Shared library defaults (also for components in component mode).
+_shared_library_configs =
+    _native_compiler_configs + [ "//build/config:default_libs" ]
+if (is_win) {
+  _shared_library_configs += _windows_linker_configs
+} else if (is_mac) {
+  _shared_library_configs += [ "//build/config/mac:mac_dynamic_flags" ]
+} else if (is_android) {
+  # Strip native JNI exports from shared libraries by default. Binaries that
+  # want this can remove this config.
+  _shared_library_configs +=
+      [ "//build/config/android:hide_native_jni_exports" ]
+}
+set_defaults("shared_library") {
+  configs = _shared_library_configs
+}
+if (is_component_build) {
+  set_defaults("component") {
+    configs = _shared_library_configs
+  }
+}
+
+# Source set defaults (also for components in non-component mode).
+set_defaults("source_set") {
+  configs = _native_compiler_configs
+}
+if (!is_component_build) {
+  set_defaults("component") {
+    configs = _native_compiler_configs
+  }
+}
+
+# Test defaults.
+set_defaults("test") {
+  if (is_android) {
+    configs = _shared_library_configs
+  } else {
+    configs = _executable_configs
+  }
+}
+
+# ==============================================================================
+# TOOLCHAIN SETUP
+# ==============================================================================
+#
+# Here we set the default toolchain, as well as the variable host_toolchain
+# which will identify the toolchain corresponding to the local system when
+# doing cross-compiles. When not cross-compiling, this will be the same as the
+# default toolchain.
+
+if (is_win) {
+  # On windows we use the same toolchain for host and target by default.
+  # TODO(dpranke): rename the toolchains to x64 and x86 to match current_cpu.
+  if (current_cpu == "x64") {
+    host_toolchain = "//build/toolchain/win:64"
+  } else if (current_cpu == "x86") {
+    host_toolchain = "//build/toolchain/win:32"
+  }
+  set_default_toolchain("$host_toolchain")
+} else if (is_android) {
+  # Use clang for the x86/64 Linux host builds.
+  if (host_cpu == "x86" || host_cpu == "x64") {
+    host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
+  } else {
+    host_toolchain = "//build/toolchain/linux:$host_cpu"
+  }
+  set_default_toolchain("//build/toolchain/android:$current_cpu")
+} else if (is_linux) {
+  if (is_clang) {
+    host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
+    set_default_toolchain("//build/toolchain/linux:clang_$current_cpu")
+  } else {
+    host_toolchain = "//build/toolchain/linux:$host_cpu"
+    set_default_toolchain("//build/toolchain/linux:$current_cpu")
+  }
+  if (is_chromeos && cros_use_custom_toolchain) {
+    set_default_toolchain("//build/toolchain/cros:target")
+  }
+} else if (is_mac) {
+  host_toolchain = "//build/toolchain/mac:clang"
+  set_default_toolchain(host_toolchain)
+} else if (is_ios) {
+  host_toolchain = "//build/toolchain/mac:host_clang"
+  set_default_toolchain("//build/toolchain/mac:clang")
+} else if (is_nacl) {
+  # TODO(GYP): This will need to change when we get NaCl working
+  # on multiple platforms, but this whole block of code (how we define
+  # host_toolchain) needs to be reworked regardless to key off of host_os
+  # and host_cpu rather than the is_* variables.
+  host_toolchain = "//build/toolchain/linux:clang_x64"
+}
+
+# ==============================================================================
+# COMPONENT SETUP
+# ==============================================================================
+
+# TODO(brettw) erase this once the built-in "component" function is removed.
+if (is_component_build) {
+  component_mode = "shared_library"
+} else {
+  component_mode = "source_set"
+}
+
+template("component") {
+  if (is_component_build) {
+    shared_library(target_name) {
+      # Configs will always be defined since we set_defaults for a component
+      # above. We want to use those rather than whatever came with the nested
+      # shared/static library inside the component.
+      configs = []  # Prevent list overwriting warning.
+      configs = invoker.configs
+
+      # The sources assignment filter will have already been applied when the
+      # code was originally executed. We don't want to apply it again, since
+      # the original target may have override it for some assignments.
+      set_sources_assignment_filter([])
+
+      if (defined(invoker.all_dependent_configs)) {
+        all_dependent_configs = invoker.all_dependent_configs
+      }
+      if (defined(invoker.allow_circular_includes_from)) {
+        allow_circular_includes_from = invoker.allow_circular_includes_from
+      }
+      if (defined(invoker.cflags)) {
+        cflags = invoker.cflags
+      }
+      if (defined(invoker.cflags_c)) {
+        cflags_c = invoker.cflags_c
+      }
+      if (defined(invoker.cflags_cc)) {
+        cflags_cc = invoker.cflags_cc
+      }
+      if (defined(invoker.cflags_objc)) {
+        cflags_objc = invoker.cflags_objc
+      }
+      if (defined(invoker.cflags_objcc)) {
+        cflags_objcc = invoker.cflags_objcc
+      }
+      if (defined(invoker.check_includes)) {
+        check_includes = invoker.check_includes
+      }
+      if (defined(invoker.data)) {
+        data = invoker.data
+      }
+      if (defined(invoker.data_deps)) {
+        data_deps = invoker.data_deps
+      }
+      if (defined(invoker.datadeps)) {
+        datadeps = invoker.datadeps
+      }
+      if (defined(invoker.defines)) {
+        defines = invoker.defines
+      }
+
+      # All shared libraries must have the sanitizer deps to properly link in
+      # asan mode (this target will be empty in other cases).
+      if (defined(invoker.deps)) {
+        deps = invoker.deps + [ "//build/config/sanitizers:deps" ]
+      } else {
+        deps = [
+          "//build/config/sanitizers:deps",
+        ]
+      }
+      if (defined(invoker.direct_dependent_configs)) {
+        direct_dependent_configs = invoker.direct_dependent_configs
+      }
+      if (defined(invoker.forward_dependent_configs_from)) {
+        forward_dependent_configs_from = invoker.forward_dependent_configs_from
+      }
+      if (defined(invoker.include_dirs)) {
+        include_dirs = invoker.include_dirs
+      }
+      if (defined(invoker.ldflags)) {
+        ldflags = invoker.ldflags
+      }
+      if (defined(invoker.lib_dirs)) {
+        lib_dirs = invoker.lib_dirs
+      }
+      if (defined(invoker.libs)) {
+        libs = invoker.libs
+      }
+      if (defined(invoker.output_extension)) {
+        output_extension = invoker.output_extension
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
+      if (defined(invoker.public)) {
+        public = invoker.public
+      }
+      if (defined(invoker.public_configs)) {
+        public_configs = invoker.public_configs
+      }
+      if (defined(invoker.public_deps)) {
+        public_deps = invoker.public_deps
+      }
+      if (defined(invoker.sources)) {
+        sources = invoker.sources
+      }
+      if (defined(invoker.testonly)) {
+        testonly = invoker.testonly
+      }
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+    }
+  } else {
+    source_set(target_name) {
+      # See above.
+      configs = []  # Prevent list overwriting warning.
+      configs = invoker.configs
+
+      # See above call.
+      set_sources_assignment_filter([])
+
+      if (defined(invoker.all_dependent_configs)) {
+        all_dependent_configs = invoker.all_dependent_configs
+      }
+      if (defined(invoker.allow_circular_includes_from)) {
+        allow_circular_includes_from = invoker.allow_circular_includes_from
+      }
+      if (defined(invoker.cflags)) {
+        cflags = invoker.cflags
+      }
+      if (defined(invoker.cflags_c)) {
+        cflags_c = invoker.cflags_c
+      }
+      if (defined(invoker.cflags_cc)) {
+        cflags_cc = invoker.cflags_cc
+      }
+      if (defined(invoker.cflags_objc)) {
+        cflags_objc = invoker.cflags_objc
+      }
+      if (defined(invoker.cflags_objcc)) {
+        cflags_objcc = invoker.cflags_objcc
+      }
+      if (defined(invoker.check_includes)) {
+        check_includes = invoker.check_includes
+      }
+      if (defined(invoker.data)) {
+        data = invoker.data
+      }
+      if (defined(invoker.data_deps)) {
+        data_deps = invoker.data_deps
+      }
+      if (defined(invoker.datadeps)) {
+        datadeps = invoker.datadeps
+      }
+      if (defined(invoker.defines)) {
+        defines = invoker.defines
+      }
+      if (defined(invoker.deps)) {
+        deps = invoker.deps
+      }
+      if (defined(invoker.direct_dependent_configs)) {
+        direct_dependent_configs = invoker.direct_dependent_configs
+      }
+      if (defined(invoker.forward_dependent_configs_from)) {
+        forward_dependent_configs_from = invoker.forward_dependent_configs_from
+      }
+      if (defined(invoker.include_dirs)) {
+        include_dirs = invoker.include_dirs
+      }
+      if (defined(invoker.ldflags)) {
+        ldflags = invoker.ldflags
+      }
+      if (defined(invoker.lib_dirs)) {
+        lib_dirs = invoker.lib_dirs
+      }
+      if (defined(invoker.libs)) {
+        libs = invoker.libs
+      }
+      if (defined(invoker.output_extension)) {
+        output_extension = invoker.output_extension
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
+      if (defined(invoker.public)) {
+        public = invoker.public
+      }
+      if (defined(invoker.public_configs)) {
+        public_configs = invoker.public_configs
+      }
+      if (defined(invoker.public_deps)) {
+        public_deps = invoker.public_deps
+      }
+      if (defined(invoker.sources)) {
+        sources = invoker.sources
+      }
+      if (defined(invoker.testonly)) {
+        testonly = invoker.testonly
+      }
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+    }
+  }
+}
diff --git a/build/config/OWNERS b/build/config/OWNERS
new file mode 100644
index 0000000..bd53091
--- /dev/null
+++ b/build/config/OWNERS
@@ -0,0 +1,6 @@
+brettw@chromium.org
+dpranke@chromium.org
+scottmg@chromium.org
+
+per-file BUILDCONFIG.gn=brettw@chromium.org
+per-file BUILDCONFIG.gn=set noparent
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
new file mode 100644
index 0000000..4c9ae67
--- /dev/null
+++ b/build/config/allocator.gni
@@ -0,0 +1,15 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(GYP): Make tcmalloc work on win.
+if (is_android || current_cpu == "mipsel" || is_mac || is_asan || is_win) {
+  _default_allocator = "none"
+} else {
+  _default_allocator = "tcmalloc"
+}
+
+declare_args() {
+  # Memory allocator to use. Set to "none" to use default allocator.
+  use_allocator = _default_allocator
+}
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
new file mode 100644
index 0000000..5492693
--- /dev/null
+++ b/build/config/android/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+import("//build/config/sysroot.gni")
+
+config("sdk") {
+  if (sysroot != "") {
+    cflags = [ "--sysroot=" + sysroot ]
+    ldflags = [ "--sysroot=" + sysroot ]
+
+    # Need to get some linker flags out of the sysroot.
+    sysroot_ld_path = rebase_path("//build/config/linux/sysroot_ld_path.py")
+    ldflags += [ exec_script(sysroot_ld_path,
+                             [
+                               rebase_path("//build/linux/sysroot_ld_path.sh"),
+                               sysroot,
+                             ],
+                             "value") ]
+  }
+}
+
+config("executable_config") {
+  cflags = [ "-fPIE" ]
+  ldflags = [ "-pie" ]
+}
+
+config("hide_native_jni_exports") {
+  ldflags = [ "-Wl,--version-script=" +
+              rebase_path("//build/android/android_no_jni_exports.lst") ]
+}
diff --git a/build/config/android/OWNERS b/build/config/android/OWNERS
new file mode 100644
index 0000000..3759e93
--- /dev/null
+++ b/build/config/android/OWNERS
@@ -0,0 +1 @@
+cjhopman@chromium.org
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
new file mode 100644
index 0000000..093e8b3
--- /dev/null
+++ b/build/config/android/config.gni
@@ -0,0 +1,190 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file contains common system config stuff for the Android build.
+
+if (is_android) {
+  has_chrome_android_internal =
+      exec_script("//build/dir_exists.py",
+                  [ rebase_path("//clank", root_build_dir) ],
+                  "string") == "True"
+
+  if (has_chrome_android_internal) {
+    import("//clank/config.gni")
+  }
+
+  if (!defined(default_android_sdk_root)) {
+    default_android_sdk_root = "//third_party/android_tools/sdk"
+    default_android_sdk_version = "22"
+    default_android_sdk_build_tools_version = "22.0.0"
+  }
+
+  if (!defined(google_play_services_library)) {
+    google_play_services_library =
+        "//third_party/android_tools:google_play_services_default_java"
+  }
+
+  declare_args() {
+    android_sdk_root = default_android_sdk_root
+    android_sdk_version = default_android_sdk_version
+    android_sdk_build_tools_version = default_android_sdk_build_tools_version
+
+    android_default_keystore_path =
+        "//build/android/ant/chromium-debug.keystore"
+    android_default_keystore_name = "chromiumdebugkey"
+    android_default_keystore_password = "chromium"
+
+    # This is a unique identifier for a given build. It's used for
+    # identifying various build artifacts corresponding to a particular build of
+    # chrome (e.g. where to find archived symbols).
+    android_chrome_build_id = "\"\""
+
+    # Set to true to run findbugs on JAR targets.
+    run_findbugs = false
+  }
+
+  # Host stuff -----------------------------------------------------------------
+
+  # Defines the name the Android build gives to the current host CPU
+  # architecture, which is different than the names GN uses.
+  if (host_cpu == "x64") {
+    android_host_arch = "x86_64"
+  } else if (host_cpu == "x86") {
+    android_host_arch = "x86"
+  } else {
+    assert(false, "Need Android toolchain support for your build CPU arch.")
+  }
+
+  # Defines the name the Android build gives to the current host CPU
+  # architecture, which is different than the names GN uses.
+  if (host_os == "linux") {
+    android_host_os = "linux"
+  } else {
+    assert(false, "Need Android toolchain support for your build OS.")
+  }
+
+  # Directories and files ------------------------------------------------------
+  #
+  # We define may of the dirs strings here for each output architecture (rather
+  # than just the current one) since these are needed by the Android toolchain
+  # file to define toolchains for all possible targets in one pass.
+
+  android_sdk = "${android_sdk_root}/platforms/android-${android_sdk_version}"
+
+  # Path to the Android NDK and SDK.
+  android_ndk_root = "//third_party/android_tools/ndk"
+  android_ndk_include_dir = "$android_ndk_root/usr/include"
+
+  android_sdk = "${android_sdk_root}/platforms/android-${android_sdk_version}"
+
+  android_sdk_tools = "${android_sdk_root}/tools"
+  android_sdk_build_tools =
+      "${android_sdk_root}/build-tools/$android_sdk_build_tools_version"
+
+  # Path to the SDK's android.jar
+  android_sdk_jar = "$android_sdk/android.jar"
+
+  zipalign_path = "$android_sdk_build_tools/zipalign"
+
+  # Subdirectories inside android_ndk_root that contain the sysroot for the
+  # associated platform.
+  _android_api_level = 14
+  x86_android_sysroot_subdir =
+      "platforms/android-${_android_api_level}/arch-x86"
+  arm_android_sysroot_subdir =
+      "platforms/android-${_android_api_level}/arch-arm"
+  mips_android_sysroot_subdir =
+      "platforms/android-${_android_api_level}/arch-mips"
+  _android64_api_level = 21
+  x86_64_android_sysroot_subdir =
+      "platforms/android-${_android64_api_level}/arch-x86_64"
+  arm64_android_sysroot_subdir =
+      "platforms/android-${_android64_api_level}/arch-arm64"
+  mips64_android_sysroot_subdir =
+      "platforms/android-${_android64_api_level}/arch-mips64"
+
+  # Toolchain root directory for each build. The actual binaries are inside
+  # a "bin" directory inside of these.
+  _android_toolchain_version = "4.9"
+  x86_android_toolchain_root = "$android_ndk_root/toolchains/x86-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
+  arm_android_toolchain_root = "$android_ndk_root/toolchains/arm-linux-androideabi-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
+  mips_android_toolchain_root = "$android_ndk_root/toolchains/mipsel-linux-android-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
+  x86_64_android_toolchain_root = "$android_ndk_root/toolchains/x86_64-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
+  arm64_android_toolchain_root = "$android_ndk_root/toolchains/aarch64-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
+  mips64_android_toolchain_root = "$android_ndk_root/toolchains/mips64el-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}"
+
+  # Location of libgcc. This is only needed for the current GN toolchain, so we
+  # only need to define the current one, rather than one for every platform
+  # like the toolchain roots.
+  if (current_cpu == "x86") {
+    android_prebuilt_arch = "android-x86"
+    _binary_prefix = "i686-linux-android"
+    android_toolchain_root = "$x86_android_toolchain_root"
+    android_libgcc_file = "$android_toolchain_root/lib/gcc/i686-linux-android/${_android_toolchain_version}/libgcc.a"
+  } else if (current_cpu == "arm") {
+    android_prebuilt_arch = "android-arm"
+    _binary_prefix = "arm-linux-androideabi"
+    android_toolchain_root = "$arm_android_toolchain_root"
+    android_libgcc_file = "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_version}/libgcc.a"
+  } else if (current_cpu == "mipsel") {
+    android_prebuilt_arch = "android-mips"
+    _binary_prefix = "mipsel-linux-android"
+    android_toolchain_root = "$mips_android_toolchain_root"
+    android_libgcc_file = "$android_toolchain_root/lib/gcc/mipsel-linux-android/${_android_toolchain_version}/libgcc.a"
+  } else if (current_cpu == "x64") {
+    android_prebuilt_arch = "android-x86_64"
+    _binary_prefix = "x86_64-linux-android"
+    android_toolchain_root = "$x86_64_android_toolchain_root"
+    android_libgcc_file = "$android_toolchain_root/lib/gcc/x86_64-linux-android/${_android_toolchain_version}/libgcc.a"
+  } else if (current_cpu == "arm64") {
+    android_prebuilt_arch = "android-arm64"
+    _binary_prefix = "aarch64-linux-android"
+    android_toolchain_root = "$arm64_android_toolchain_root"
+    android_libgcc_file = "$android_toolchain_root/lib/gcc/aarch64-linux-android/${_android_toolchain_version}/libgcc.a"
+  } else if (current_cpu == "mips64el") {
+    android_prebuilt_arch = "android-mips64"
+    _binary_prefix = "mips64el-linux-android"
+    android_toolchain_root = "$mips64_android_toolchain_root"
+    android_libgcc_file = "$android_toolchain_root/lib/gcc/mips64el-linux-android/${_android_toolchain_version}/libgcc.a"
+  } else {
+    assert(false, "Need android libgcc support for your target arch.")
+  }
+
+  android_tool_prefix = "$android_toolchain_root/bin/$_binary_prefix-"
+  android_readelf = "${android_tool_prefix}readelf"
+  android_objcopy = "${android_tool_prefix}objcopy"
+  android_gdbserver =
+      "$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver"
+
+  # libc++ stuff ---------------------------------------------------------------
+
+  if (component_mode == "shared_library") {
+    android_libcpp_library = "c++_shared"
+  } else {
+    android_libcpp_library = "c++_static"
+  }
+
+  # ABI ------------------------------------------------------------------------
+
+  if (current_cpu == "x86") {
+    android_app_abi = "x86"
+  } else if (current_cpu == "arm") {
+    import("//build/config/arm.gni")
+    if (arm_version < 7) {
+      android_app_abi = "armeabi"
+    } else {
+      android_app_abi = "armeabi-v7a"
+    }
+  } else if (current_cpu == "mipsel") {
+    android_app_abi = "mips"
+  } else if (current_cpu == "x64") {
+    android_app_abi = "x86_64"
+  } else if (current_cpu == "arm64") {
+    android_app_abi = "arm64-v8a"
+  } else if (current_cpu == "mips64el") {
+    android_app_abi = "mips64"
+  } else {
+    assert(false, "Unknown Android ABI: " + current_cpu)
+  }
+}
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
new file mode 100644
index 0000000..ab773ea
--- /dev/null
+++ b/build/config/android/internal_rules.gni
@@ -0,0 +1,1163 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+
+assert(is_android)
+
+rebased_android_sdk = rebase_path(android_sdk, root_build_dir)
+rebased_android_sdk_root = rebase_path(android_sdk_root, root_build_dir)
+rebased_android_sdk_build_tools =
+    rebase_path(android_sdk_build_tools, root_build_dir)
+
+android_sdk_jar = "$android_sdk/android.jar"
+rebased_android_sdk_jar = rebase_path(android_sdk_jar, root_build_dir)
+
+template("android_lint") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  jar_path = invoker.jar_path
+  android_manifest = invoker.android_manifest
+  java_files = invoker.java_files
+  base_path = "$target_gen_dir/$target_name"
+
+  action(target_name) {
+    script = "//build/android/gyp/lint.py"
+    result_path = base_path + "/result.xml"
+    config_path = base_path + "/config.xml"
+    suppressions_file = "//build/android/lint/suppressions.xml"
+    inputs = [
+               suppressions_file,
+               android_manifest,
+               jar_path,
+             ] + java_files
+
+    outputs = [
+      config_path,
+      result_path,
+    ]
+
+    rebased_java_files = rebase_path(java_files, root_build_dir)
+
+    args = [
+      "--lint-path=$rebased_android_sdk_root/tools/lint",
+      "--config-path",
+      rebase_path(suppressions_file, root_build_dir),
+      "--manifest-path",
+      rebase_path(android_manifest, root_build_dir),
+      "--product-dir=.",
+      "--jar-path",
+      rebase_path(jar_path, root_build_dir),
+      "--processed-config-path",
+      rebase_path(config_path, root_build_dir),
+      "--result-path",
+      rebase_path(result_path, root_build_dir),
+      "--java-files=$rebased_java_files",
+      "--enable",
+    ]
+  }
+}
+
+template("findbugs") {
+  jar_path = invoker.jar_path
+
+  build_config = invoker.build_config
+
+  action(target_name) {
+    script = "//build/android/findbugs_diff.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    result_path = "$target_gen_dir/$target_name/result.xml"
+    exclusions_file = "//build/android/findbugs_filter/findbugs_exclude.xml"
+
+    rebased_build_config = rebase_path(build_config, root_build_dir)
+
+    inputs = [
+      "//build/android/pylib/utils/findbugs.py",
+      exclusions_file,
+      jar_path,
+    ]
+
+    outputs = [
+      depfile,
+      result_path,
+    ]
+
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--exclude",
+      rebase_path(exclusions_file, root_build_dir),
+      "--auxclasspath-gyp",
+      "@FileArg($rebased_build_config:javac:classpath)",
+      "--output-file",
+      rebase_path(result_path, root_build_dir),
+      rebase_path(jar_path, root_build_dir),
+    ]
+  }
+}
+
+template("dex") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.output))
+  action(target_name) {
+    script = "//build/android/gyp/dex.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    if (defined(invoker.sources)) {
+      sources = invoker.sources
+    }
+    outputs = [
+      depfile,
+      invoker.output,
+    ]
+    if (defined(invoker.inputs)) {
+      inputs = invoker.inputs
+    }
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+
+    rebased_output = rebase_path(invoker.output, root_build_dir)
+
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--android-sdk-tools",
+      rebased_android_sdk_build_tools,
+      "--dex-path",
+      rebased_output,
+    ]
+
+    if (defined(invoker.no_locals) && invoker.no_locals) {
+      args += [ "--no-locals=1" ]
+    }
+
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+
+    if (defined(invoker.sources)) {
+      args += rebase_path(invoker.sources, root_build_dir)
+    }
+  }
+}
+
+# Creates a zip archive of the inputs.
+# If base_dir is provided, the archive paths will be relative to it.
+template("zip") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.inputs))
+  assert(defined(invoker.output))
+
+  rebase_inputs = rebase_path(invoker.inputs, root_build_dir)
+  rebase_output = rebase_path(invoker.output, root_build_dir)
+  action(target_name) {
+    script = "//build/android/gn/zip.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    inputs = invoker.inputs
+    outputs = [
+      depfile,
+      invoker.output,
+    ]
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--inputs=$rebase_inputs",
+      "--output=$rebase_output",
+    ]
+    if (defined(invoker.base_dir)) {
+      args += [
+        "--base-dir",
+        rebase_path(invoker.base_dir, root_build_dir),
+      ]
+    }
+  }
+}
+
+# Write the target's .build_config file. This is a json file that contains a
+# dictionary of information about how to build this target (things that
+# require knowledge about this target's dependencies and cannot be calculated
+# at gn-time). There is a special syntax to add a value in that dictionary to
+# an action/action_foreachs args:
+#   --python-arg=@FileArg($rebased_build_config_path:key0:key1)
+# At runtime, such an arg will be replaced by the value in the build_config.
+# See build/android/gyp/write_build_config.py and
+# build/android/gyp/util/build_utils.py:ExpandFileArgs
+template("write_build_config") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.type))
+  assert(defined(invoker.build_config))
+
+  type = invoker.type
+  build_config = invoker.build_config
+
+  assert(type == "android_apk" || type == "java_library" ||
+         type == "android_resources" || type == "deps_dex")
+
+  action(target_name) {
+    script = "//build/android/gyp/write_build_config.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    inputs = []
+
+    deps = []
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+
+    possible_deps_configs = []
+    foreach(d, deps) {
+      dep_gen_dir = get_label_info(d, "target_gen_dir")
+      dep_name = get_label_info(d, "name")
+      possible_deps_configs += [ "$dep_gen_dir/$dep_name.build_config" ]
+    }
+    rebase_possible_deps_configs =
+        rebase_path(possible_deps_configs, root_build_dir)
+
+    outputs = [
+      depfile,
+      build_config,
+    ]
+
+    args = [
+      "--type",
+      type,
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--possible-deps-configs=$rebase_possible_deps_configs",
+      "--build-config",
+      rebase_path(build_config, root_build_dir),
+    ]
+
+    is_java_library = type == "java_library"
+    is_apk = type == "android_apk"
+    is_android_resources = type == "android_resources"
+    is_deps_dex = type == "deps_dex"
+
+    supports_android = is_apk || is_android_resources || is_deps_dex ||
+                       (is_java_library && defined(invoker.supports_android) &&
+                        invoker.supports_android)
+    requires_android = is_apk || is_android_resources || is_deps_dex ||
+                       (is_java_library && defined(invoker.requires_android) &&
+                        invoker.requires_android)
+
+    assert(!requires_android || supports_android,
+           "requires_android requires" + " supports_android")
+
+    # Mark these variables as used.
+    assert(is_java_library || true)
+    assert(is_apk || true)
+    assert(is_android_resources || true)
+    assert(is_deps_dex || true)
+
+    if (is_java_library || is_apk) {
+      args += [
+        "--jar-path",
+        rebase_path(invoker.jar_path, root_build_dir),
+      ]
+    }
+
+    if (is_apk || is_deps_dex || (is_java_library && supports_android)) {
+      args += [
+        "--dex-path",
+        rebase_path(invoker.dex_path, root_build_dir),
+      ]
+    }
+    if (supports_android) {
+      args += [ "--supports-android" ]
+    }
+    if (requires_android) {
+      args += [ "--requires-android" ]
+    }
+    if (defined(invoker.bypass_platform_checks) &&
+        invoker.bypass_platform_checks) {
+      args += [ "--bypass-platform-checks" ]
+    }
+
+    if (defined(invoker.apk_under_test)) {
+      deps += [ invoker.apk_under_test ]
+      apk_under_test_gen_dir =
+          get_label_info(invoker.apk_under_test, "target_gen_dir")
+      apk_under_test_name = get_label_info(invoker.apk_under_test, "name")
+      apk_under_test_config =
+          "$apk_under_test_gen_dir/$apk_under_test_name.build_config"
+      args += [
+        "--tested-apk-config",
+        rebase_path(apk_under_test_config, root_build_dir),
+      ]
+    }
+
+    if (is_android_resources || is_apk) {
+      assert(defined(invoker.resources_zip))
+      args += [
+        "--resources-zip",
+        rebase_path(invoker.resources_zip, root_build_dir),
+      ]
+      if (defined(invoker.android_manifest)) {
+        inputs += [ invoker.android_manifest ]
+        args += [
+          "--android-manifest",
+          rebase_path(invoker.android_manifest, root_build_dir),
+        ]
+      } else {
+        assert(!is_apk, "apk build configs require an android_manifest")
+      }
+      if (defined(invoker.custom_package)) {
+        args += [
+          "--package-name",
+          invoker.custom_package,
+        ]
+      }
+    }
+
+    if (is_apk) {
+      if (defined(invoker.native_libs)) {
+        inputs += invoker.native_libs
+        rebased_native_libs = rebase_path(invoker.native_libs, root_build_dir)
+        rebased_android_readelf = rebase_path(android_readelf, root_build_dir)
+        args += [
+          "--native-libs=$rebased_native_libs",
+          "--readelf-path=$rebased_android_readelf",
+        ]
+      }
+    }
+
+    if (defined(invoker.srcjar)) {
+      args += [
+        "--srcjar",
+        rebase_path(invoker.srcjar, root_build_dir),
+      ]
+    }
+  }
+}
+
+template("process_java_prebuilt") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  _input_jar_path = invoker.input_jar_path
+  _output_jar_path = invoker.output_jar_path
+  _jar_toc_path = _output_jar_path + ".TOC"
+
+  assert(invoker.build_config != "")
+
+  if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
+    _proguard_jar_path = "$android_sdk_root/tools/proguard/lib/proguard.jar"
+    _proguard_config_path = invoker.proguard_config
+    _build_config = invoker.build_config
+    _rebased_build_config = rebase_path(_build_config, root_build_dir)
+    action("${target_name}__proguard_process") {
+      script = "//build/android/gyp/proguard.py"
+      inputs = [
+        android_sdk_jar,
+        _proguard_jar_path,
+        _build_config,
+        _input_jar_path,
+        _proguard_config_path,
+      ]
+      depfile = "${target_gen_dir}/${target_name}.d"
+      outputs = [
+        depfile,
+        _output_jar_path,
+      ]
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--proguard-path",
+        rebase_path(_proguard_jar_path, root_build_dir),
+        "--input-path",
+        rebase_path(_input_jar_path, root_build_dir),
+        "--output-path",
+        rebase_path(_output_jar_path, root_build_dir),
+        "--proguard-config",
+        rebase_path(_proguard_config_path, root_build_dir),
+        "--classpath",
+        rebased_android_sdk_jar,
+        "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
+      ]
+    }
+  } else {
+    copy("${target_name}__copy_jar") {
+      sources = [
+        _input_jar_path,
+      ]
+      outputs = [
+        _output_jar_path,
+      ]
+    }
+  }
+
+  action("${target_name}__jar_toc") {
+    script = "//build/android/gyp/jar_toc.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    outputs = [
+      depfile,
+      _jar_toc_path,
+      _jar_toc_path + ".md5.stamp",
+    ]
+    inputs = [
+      _output_jar_path,
+    ]
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--jar-path",
+      rebase_path(_output_jar_path, root_build_dir),
+      "--toc-path",
+      rebase_path(_jar_toc_path, root_build_dir),
+    ]
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__jar_toc",
+    ]
+  }
+}
+
+# Packages resources, assets, dex, and native libraries into an apk. Signs and
+# zipaligns the apk.
+template("create_apk") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  _android_manifest = invoker.android_manifest
+  _base_path = invoker.base_path
+  _final_apk_path = invoker.apk_path
+  _resources_zip = invoker.resources_zip
+  _dex_path = invoker.dex_path
+  _keystore_path = invoker.keystore_path
+  _keystore_name = invoker.keystore_name
+  _keystore_password = invoker.keystore_password
+  _load_library_from_apk = invoker.load_library_from_apk
+
+  _deps = []
+  if (defined(invoker.deps)) {
+    _deps = invoker.deps
+  }
+
+  _native_libs_dir = "//build/android/empty/res"
+  if (defined(invoker.native_libs_dir)) {
+    _native_libs_dir = invoker.native_libs_dir
+  }
+
+  _asset_location = "//build/android/empty/res"
+  if (defined(invoker.asset_location)) {
+    _asset_location = invoker.asset_location
+  }
+
+  _version_code = invoker.version_code
+  _version_name = invoker.version_name
+
+  _base_apk_path = _base_path + ".apk_intermediates"
+
+  _resource_packaged_apk_path = _base_apk_path + ".ap_"
+  _packaged_apk_path = _base_apk_path + ".unfinished.apk"
+  _shared_resources =
+      defined(invoker.shared_resources) && invoker.shared_resources
+
+  _configuration_name = "Release"
+  if (is_debug) {
+    _configuration_name = "Debug"
+  }
+
+  action("${target_name}__package_resources") {
+    deps = _deps
+
+    script = "//build/android/gyp/package_resources.py"
+    depfile = "${target_gen_dir}/${target_name}.d"
+    inputs = [
+      _android_manifest,
+      _resources_zip,
+    ]
+    outputs = [
+      depfile,
+      _resource_packaged_apk_path,
+    ]
+
+    _rebased_resources_zips = [ rebase_path(_resources_zip, root_build_dir) ]
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--android-sdk",
+      rebased_android_sdk,
+      "--android-sdk-tools",
+      rebased_android_sdk_build_tools,
+      "--configuration-name=$_configuration_name",
+      "--android-manifest",
+      rebase_path(_android_manifest, root_build_dir),
+      "--version-code",
+      _version_code,
+      "--version-name",
+      _version_name,
+      "--asset-dir",
+      rebase_path(_asset_location, root_build_dir),
+      "--resource-zips=$_rebased_resources_zips",
+      "--apk-path",
+      rebase_path(_resource_packaged_apk_path, root_build_dir),
+    ]
+
+    if (_shared_resources) {
+      args += [ "--shared-resources" ]
+    }
+  }
+
+  action("${target_name}__package") {
+    script = "//build/android/gyp/ant.py"
+    _ant_script = "//build/android/ant/apk-package.xml"
+
+    depfile = "$target_gen_dir/$target_name.d"
+
+    inputs = [
+      _dex_path,
+      _resource_packaged_apk_path,
+      _ant_script,
+    ]
+
+    outputs = [
+      depfile,
+      _packaged_apk_path,
+    ]
+
+    _rebased_emma_jar = ""
+    _rebased_resource_packaged_apk_path =
+        rebase_path(_resource_packaged_apk_path, root_build_dir)
+    _rebased_packaged_apk_path = rebase_path(_packaged_apk_path, root_build_dir)
+    _rebased_native_libs_dir = rebase_path(_native_libs_dir, root_build_dir)
+    _rebased_dex_path = rebase_path(_dex_path, root_build_dir)
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--",
+      "-quiet",
+      "-DANDROID_SDK_ROOT=$rebased_android_sdk_root",
+      "-DANDROID_SDK_TOOLS=$rebased_android_sdk_build_tools",
+      "-DRESOURCE_PACKAGED_APK_NAME=$_rebased_resource_packaged_apk_path",
+      "-DCONFIGURATION_NAME=$_configuration_name",
+      "-DNATIVE_LIBS_DIR=$_rebased_native_libs_dir",
+      "-DOUT_DIR=",
+      "-DUNSIGNED_APK_PATH=$_rebased_packaged_apk_path",
+      "-DEMMA_INSTRUMENT=0",
+      "-DEMMA_DEVICE_JAR=$_rebased_emma_jar",
+      "-DDEX_FILE_PATH=$_rebased_dex_path",
+      "-Dbasedir=.",
+      "-buildfile",
+      rebase_path(_ant_script, root_build_dir),
+    ]
+  }
+
+  action("${target_name}__finalize") {
+    script = "//build/android/gyp/finalize_apk.py"
+    depfile = "$target_gen_dir/$target_name.d"
+
+    sources = [
+      _packaged_apk_path,
+    ]
+    inputs = [
+      _keystore_path,
+    ]
+    outputs = [
+      depfile,
+      _final_apk_path,
+    ]
+
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--zipalign-path",
+      rebase_path(zipalign_path, root_build_dir),
+      "--unsigned-apk-path",
+      rebase_path(_packaged_apk_path, root_build_dir),
+      "--final-apk-path",
+      rebase_path(_final_apk_path, root_build_dir),
+      "--key-path",
+      rebase_path(_keystore_path, root_build_dir),
+      "--key-name",
+      _keystore_name,
+      "--key-passwd",
+      _keystore_password,
+    ]
+    if (_load_library_from_apk) {
+      _rezip_jar_path = "$root_build_dir/lib.java/rezip_apk.jar"
+      inputs += [ _rezip_jar_path ]
+      args += [
+        "--load-library-from-zip-file=1",
+        "--rezip-apk-jar-path",
+        rebase_path(_rezip_jar_path, root_build_dir),
+      ]
+    }
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__finalize",
+    ]
+  }
+}
+
+template("java_prebuilt_impl") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+  _supports_android =
+      defined(invoker.supports_android) && invoker.supports_android
+
+  assert(defined(invoker.jar_path))
+  _base_path = "${target_gen_dir}/$target_name"
+  _jar_path = _base_path + ".jar"
+  _build_config = _base_path + ".build_config"
+
+  if (_supports_android) {
+    _dex_path = _base_path + ".dex.jar"
+  }
+
+  _final_deps = []
+  _template_name = target_name
+
+  _final_deps += [ ":${_template_name}__build_config" ]
+  write_build_config("${_template_name}__build_config") {
+    type = "java_library"
+    supports_android = _supports_android
+    requires_android =
+        defined(invoker.requires_android) && invoker.requires_android
+
+    deps = []
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    build_config = _build_config
+    jar_path = _jar_path
+    if (_supports_android) {
+      dex_path = _dex_path
+    }
+  }
+
+  _final_deps += [ ":${_template_name}__process_jar" ]
+  process_java_prebuilt("${_template_name}__process_jar") {
+    if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
+      proguard_preprocess = true
+      proguard_config = invoker.proguard_config
+    }
+
+    build_config = _build_config
+    input_jar_path = invoker.jar_path
+    output_jar_path = _jar_path
+  }
+
+  if (_supports_android) {
+    _final_deps += [ ":${_template_name}__dex" ]
+    dex("${_template_name}__dex") {
+      sources = [
+        _jar_path,
+      ]
+      output = _dex_path
+    }
+  }
+
+  group(target_name) {
+    deps = _final_deps
+  }
+}
+
+# Compiles and jars a set of java files.
+#
+# Outputs:
+#  $jar_path.jar
+#  $jar_path.jar.TOC
+#
+# Variables
+#   java_files: List of .java files to compile.
+#   java_deps: List of java dependencies. These should all have a .jar output
+#     at "${target_gen_dir}/${target_name}.jar.
+#   chromium_code: If true, enable extra warnings.
+#   srcjar_deps: List of srcjar dependencies. The .java files contained in the
+#     dependencies srcjar outputs will be compiled and added to the output jar.
+#   jar_path: Use this to explicitly set the output jar path. Defaults to
+#     "${target_gen_dir}/${target_name}.jar.
+template("compile_java") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.java_files))
+  assert(defined(invoker.build_config))
+  assert(defined(invoker.jar_path))
+
+  _java_files = invoker.java_files
+  _final_jar_path = invoker.jar_path
+  _intermediate_jar_path = "$target_gen_dir/$target_name.initial.jar"
+
+  _build_config = invoker.build_config
+
+  _jar_excluded_patterns = []
+  if (defined(invoker.jar_excluded_patterns)) {
+    _jar_excluded_patterns += invoker.jar_excluded_patterns
+  }
+
+  _chromium_code = false
+  if (defined(invoker.chromium_code)) {
+    _chromium_code = invoker.chromium_code
+  }
+  _manifest_entries = []
+  if (defined(invoker.manifest_entries)) {
+    _manifest_entries = invoker.manifest_entries
+  }
+
+  _srcjar_deps = []
+  if (defined(invoker.srcjar_deps)) {
+    _srcjar_deps += invoker.srcjar_deps
+  }
+
+  _java_srcjars = []
+  if (defined(invoker.srcjars)) {
+    _java_srcjars = invoker.srcjars
+  }
+  foreach(dep, _srcjar_deps) {
+    _dep_gen_dir = get_label_info(dep, "target_gen_dir")
+    _dep_name = get_label_info(dep, "name")
+    _java_srcjars += [ "$_dep_gen_dir/$_dep_name.srcjar" ]
+  }
+
+  # Mark srcjar_deps as used.
+  assert(_srcjar_deps == [] || true)
+
+  _system_jars = []
+  if (defined(invoker.android) && invoker.android) {
+    _system_jars += [ android_sdk_jar ]
+  }
+
+  _rebased_build_config = rebase_path(_build_config, root_build_dir)
+  _rebased_jar_path = rebase_path(_intermediate_jar_path, root_build_dir)
+
+  _template_name = target_name
+  _final_deps = [ ":${_template_name}__javac" ]
+  action("${_template_name}__javac") {
+    script = "//build/android/gyp/javac.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    deps = []
+    outputs = [
+      depfile,
+      _intermediate_jar_path,
+      _intermediate_jar_path + ".md5.stamp",
+    ]
+    sources = _java_files + _java_srcjars
+    inputs = _system_jars + [ _build_config ]
+
+    _rebased_system_jars = rebase_path(_system_jars, root_build_dir)
+    _rebased_java_srcjars = rebase_path(_java_srcjars, root_build_dir)
+    _rebased_depfile = rebase_path(depfile, root_build_dir)
+    args = [
+      "--depfile=$_rebased_depfile",
+      "--classpath=$_rebased_system_jars",
+      "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
+      "--jar-path=$_rebased_jar_path",
+      "--java-srcjars=$_rebased_java_srcjars",
+      "--java-srcjars=@FileArg($_rebased_build_config:javac:srcjars)",
+      "--jar-excluded-classes=$_jar_excluded_patterns",
+    ]
+    foreach(e, _manifest_entries) {
+      args += [ "--manifest-entry=" + e ]
+    }
+    if (_chromium_code) {
+      args += [ "--chromium-code=1" ]
+    }
+
+    args += rebase_path(_java_files, root_build_dir)
+  }
+
+  _final_deps += [ ":${_template_name}__finish" ]
+  process_java_prebuilt("${_template_name}__finish") {
+    build_config = _build_config
+    input_jar_path = _intermediate_jar_path
+    output_jar_path = _final_jar_path
+    if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
+      proguard_preprocess = invoker.proguard_preprocess
+      proguard_config = invoker.proguard_config
+    }
+  }
+
+  group(target_name) {
+    deps = _final_deps
+  }
+}
+
+template("java_library_impl") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(
+      defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir) ||
+      defined(invoker.srcjars) || defined(invoker.srcjar_deps))
+  _base_path = "$target_gen_dir/$target_name"
+  _jar_path = _base_path + ".jar"
+  if (defined(invoker.jar_path)) {
+    _jar_path = invoker.jar_path
+  }
+  _template_name = target_name
+
+  _final_deps = []
+  _final_datadeps = []
+  if (defined(invoker.datadeps)) {
+    _final_datadeps = invoker.datadeps
+  }
+
+  _supports_android =
+      defined(invoker.supports_android) && invoker.supports_android
+  _requires_android =
+      defined(invoker.requires_android) && invoker.requires_android
+
+  if (_supports_android) {
+    _dex_path = _base_path + ".dex.jar"
+    if (defined(invoker.dex_path)) {
+      _dex_path = invoker.dex_path
+    }
+  }
+
+  if (defined(invoker.override_build_config)) {
+    _build_config = invoker.override_build_config
+  } else {
+    _build_config = _base_path + ".build_config"
+    _final_deps += [ ":${_template_name}__build_config" ]
+    write_build_config("${_template_name}__build_config") {
+      type = "java_library"
+      supports_android = _supports_android
+      requires_android = _requires_android
+      bypass_platform_checks = defined(invoker.bypass_platform_checks) &&
+                               invoker.bypass_platform_checks
+
+      deps = []
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
+
+      build_config = _build_config
+      jar_path = _jar_path
+      if (_supports_android) {
+        dex_path = _dex_path
+      }
+    }
+  }
+
+  _chromium_code = true
+  if (defined(invoker.chromium_code)) {
+    _chromium_code = invoker.chromium_code
+  }
+
+  _srcjar_deps = []
+  if (defined(invoker.srcjar_deps)) {
+    _srcjar_deps = invoker.srcjar_deps
+  }
+
+  _srcjars = []
+  if (defined(invoker.srcjars)) {
+    _srcjars = invoker.srcjars
+  }
+
+  _java_files = []
+  if (defined(invoker.java_files)) {
+    _java_files = invoker.java_files
+  } else if (defined(invoker.DEPRECATED_java_in_dir)) {
+    _src_dir = invoker.DEPRECATED_java_in_dir + "/src"
+    _src_dir_exists = exec_script("//build/dir_exists.py",
+                                  [ rebase_path(_src_dir, root_build_dir) ],
+                                  "string")
+    assert(_src_dir_exists == "False",
+           "In GN, java_in_dir should be the fully specified java directory " +
+               "(i.e. including the trailing \"/src\")")
+
+    _java_files_build_rel = exec_script(
+            "//build/android/gyp/find.py",
+            [
+              "--pattern",
+              "*.java",
+              rebase_path(invoker.DEPRECATED_java_in_dir, root_build_dir),
+            ],
+            "list lines")
+    _java_files = rebase_path(_java_files_build_rel, ".", root_build_dir)
+  }
+  assert(_java_files != [] || _srcjar_deps != [] || _srcjars != [])
+
+  _final_deps += [ ":${_template_name}__compile_java" ]
+  compile_java("${_template_name}__compile_java") {
+    jar_path = _jar_path
+    build_config = _build_config
+    java_files = _java_files
+    srcjar_deps = _srcjar_deps
+    srcjars = _srcjars
+    chromium_code = _chromium_code
+    android = _requires_android
+
+    if (defined(invoker.jar_excluded_patterns)) {
+      jar_excluded_patterns = invoker.jar_excluded_patterns
+    }
+    if (defined(invoker.proguard_preprocess)) {
+      proguard_preprocess = invoker.proguard_preprocess
+    }
+    if (defined(invoker.proguard_config)) {
+      proguard_config = invoker.proguard_config
+    }
+    if (defined(invoker.dist_jar_path)) {
+      dist_jar_path = invoker.dist_jar_path
+    }
+    if (defined(invoker.manifest_entries)) {
+      manifest_entries = invoker.manifest_entries
+    }
+  }
+
+  if (defined(invoker.main_class)) {
+    _final_deps += [ ":${_template_name}__binary_script" ]
+    action("${_template_name}__binary_script") {
+      script = "//build/android/gyp/create_java_binary_script.py"
+      depfile = "$target_gen_dir/$target_name.d"
+      java_script = "$root_build_dir/bin/$_template_name"
+      inputs = [
+        _build_config,
+      ]
+      outputs = [
+        depfile,
+        java_script,
+      ]
+      _rebased_build_config = rebase_path(_build_config, root_build_dir)
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--output",
+        rebase_path(java_script, root_build_dir),
+        "--classpath=@FileArg($_rebased_build_config:java:full_classpath)",
+        "--jar-path",
+        rebase_path(_jar_path, root_build_dir),
+        "--main-class",
+        invoker.main_class,
+      ]
+    }
+  }
+
+  if (_supports_android) {
+    if (defined(invoker.chromium_code) && invoker.chromium_code) {
+      _android_manifest = "//build/android/AndroidManifest.xml"
+      if (defined(invoker.android_manifest)) {
+        _android_manifest = invoker.android_manifest
+      }
+
+      _final_datadeps += [ ":${_template_name}__lint" ]
+      android_lint("${_template_name}__lint") {
+        android_manifest = _android_manifest
+        jar_path = _jar_path
+        java_files = _java_files
+      }
+
+      if (run_findbugs) {
+        _final_datadeps += [ ":${_template_name}__findbugs" ]
+        findbugs("${_template_name}__findbugs") {
+          build_config = _build_config
+          jar_path = _jar_path
+        }
+      }
+    }
+
+    _final_deps += [ ":${_template_name}__dex" ]
+    dex("${_template_name}__dex") {
+      sources = [
+        _jar_path,
+      ]
+      output = _dex_path
+    }
+  }
+
+  group(target_name) {
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+    deps = _final_deps
+    datadeps = _final_datadeps
+  }
+}
+
+# Runs process_resources.py
+template("process_resources") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  zip_path = invoker.zip_path
+  srcjar_path = invoker.srcjar_path
+  build_config = invoker.build_config
+  resource_dirs = invoker.resource_dirs
+  android_manifest = invoker.android_manifest
+
+  non_constant_id = true
+  if (defined(invoker.generate_constant_ids) && invoker.generate_constant_ids) {
+    non_constant_id = false
+  }
+
+  action(target_name) {
+    script = "//build/android/gyp/process_resources.py"
+
+    depfile = "$target_gen_dir/$target_name.d"
+    outputs = [
+      depfile,
+      zip_path,
+      srcjar_path,
+    ]
+
+    sources_build_rel = exec_script("//build/android/gyp/find.py",
+                                    rebase_path(resource_dirs, root_build_dir),
+                                    "list lines")
+    sources = rebase_path(sources_build_rel, ".", root_build_dir)
+
+    inputs = [
+      build_config,
+      android_manifest,
+    ]
+
+    rebase_resource_dirs = rebase_path(resource_dirs, root_build_dir)
+    rebase_build_config = rebase_path(build_config, root_build_dir)
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--android-sdk",
+      rebase_path(android_sdk, root_build_dir),
+      "--android-sdk-tools",
+      rebase_path(android_sdk_build_tools, root_build_dir),
+      "--android-manifest",
+      rebase_path(android_manifest, root_build_dir),
+      "--resource-dirs=$rebase_resource_dirs",
+      "--srcjar-out",
+      rebase_path(srcjar_path, root_build_dir),
+      "--resource-zip-out",
+      rebase_path(zip_path, root_build_dir),
+      "--dependencies-res-zips=@FileArg($rebase_build_config:resources:dependency_zips)",
+      "--extra-res-packages=@FileArg($rebase_build_config:resources:extra_package_names)",
+    ]
+
+    if (non_constant_id) {
+      args += [ "--non-constant-id" ]
+    }
+
+    if (defined(invoker.custom_package)) {
+      args += [
+        "--custom-package",
+        invoker.custom_package,
+      ]
+    }
+
+    if (defined(invoker.v14_verify_only) && invoker.v14_verify_only) {
+      args += [ "--v14-verify-only" ]
+    }
+
+    if (defined(invoker.shared_resources) && invoker.shared_resources) {
+      args += [ "--shared-resources" ]
+    }
+
+    if (defined(invoker.all_resources_zip_path)) {
+      all_resources_zip = invoker.all_resources_zip_path
+      outputs += [ all_resources_zip ]
+      args += [
+        "--all-resources-zip-out",
+        rebase_path(all_resources_zip, root_build_dir),
+      ]
+    }
+
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+  }
+}
+
+template("copy_ex") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  action(target_name) {
+    script = "//build/android/gyp/copy_ex.py"
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+
+    sources = []
+    if (defined(invoker.sources)) {
+      sources += invoker.sources
+    }
+
+    inputs = []
+    if (defined(invoker.inputs)) {
+      inputs += invoker.inputs
+    }
+
+    depfile = "$target_gen_dir/$target_name.d"
+    outputs = [
+      depfile,
+    ]
+
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--dest",
+      rebase_path(invoker.dest, root_build_dir),
+    ]
+    rebased_sources = rebase_path(sources, root_build_dir)
+    args += [ "--files=$rebased_sources" ]
+
+    if (defined(invoker.clear_dir) && invoker.clear_dir) {
+      args += [ "--clear" ]
+    }
+
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+  }
+}
+
+# Produces a single .dex.jar out of a set of Java dependencies.
+template("deps_dex") {
+  set_sources_assignment_filter([])
+  build_config = "$target_gen_dir/${target_name}.build_config"
+  write_build_config("${target_name}__build_config") {
+    type = "deps_dex"
+    deps = invoker.deps
+
+    build_config = build_config
+    dex_path = invoker.dex_path
+  }
+
+  rebased_build_config = rebase_path(build_config, root_build_dir)
+  dex(target_name) {
+    inputs = [
+      build_config,
+    ]
+    output = invoker.dex_path
+    dex_arg_key = "${rebased_build_config}:final_dex:dependency_dex_files"
+    args = [ "--inputs=@FileArg($dex_arg_key)" ]
+    if (defined(invoker.excluded_jars)) {
+      excluded_jars = rebase_path(invoker.excluded_jars, root_build_dir)
+      args += [ "--excluded-paths=${excluded_jars}" ]
+    }
+  }
+}
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
new file mode 100644
index 0000000..b1b23b0
--- /dev/null
+++ b/build/config/android/rules.gni
@@ -0,0 +1,1812 @@
+# Copyright 2014 The Chromium 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/android/linker/config.gni")
+import("//build/config/android/config.gni")
+import("//build/config/android/internal_rules.gni")
+import("//tools/grit/grit_rule.gni")
+import("//tools/relocation_packer/config.gni")
+
+assert(is_android)
+
+# Declare a jni target
+#
+# This target generates the native jni bindings for a set of .java files.
+#
+# See base/android/jni_generator/jni_generator.py for more info about the
+# format of generating JNI bindings.
+#
+# Variables
+#   sources: list of .java files to generate jni for
+#   jni_package: subdirectory path for generated bindings
+#
+# Example
+#   generate_jni("foo_jni") {
+#     sources = [
+#       "android/java/src/org/chromium/foo/Foo.java",
+#       "android/java/src/org/chromium/foo/FooUtil.java",
+#     ]
+#     jni_package = "foo"
+#   }
+template("generate_jni") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.sources))
+  assert(defined(invoker.jni_package))
+  jni_package = invoker.jni_package
+  base_output_dir = "${target_gen_dir}/${target_name}"
+  package_output_dir = "${base_output_dir}/${jni_package}"
+  jni_output_dir = "${package_output_dir}/jni"
+
+  jni_generator_include = "//base/android/jni_generator/jni_generator_helper.h"
+
+  foreach_target_name = "${target_name}__jni_gen"
+  action_foreach(foreach_target_name) {
+    script = "//base/android/jni_generator/jni_generator.py"
+    depfile = "$target_gen_dir/$target_name.{{source_name_part}}.d"
+    sources = invoker.sources
+    outputs = [
+      depfile,
+      "${jni_output_dir}/{{source_name_part}}_jni.h",
+    ]
+
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--input_file={{source}}",
+      "--optimize_generation=1",
+      "--ptr_type=long",
+      "--output_dir",
+      rebase_path(jni_output_dir, root_build_dir),
+      "--includes",
+      rebase_path(jni_generator_include, jni_output_dir),
+      "--native_exports_optional",
+    ]
+    if (defined(invoker.jni_generator_jarjar_file)) {
+      args += [
+        "--jarjar",
+        rebase_path(jni_generator_jarjar_file, root_build_dir),
+      ]
+    }
+  }
+
+  config("jni_includes_${target_name}") {
+    # TODO(cjhopman): #includes should probably all be relative to
+    # base_output_dir. Remove that from this config once the includes are
+    # updated.
+    include_dirs = [
+      base_output_dir,
+      package_output_dir,
+    ]
+  }
+
+  group(target_name) {
+    deps = [
+      ":$foreach_target_name",
+    ]
+    public_configs = [ ":jni_includes_${target_name}" ]
+
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    if (defined(invoker.public_deps)) {
+      public_deps = invoker.public_deps
+    }
+
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+  }
+}
+
+# Declare a jni target for a prebuilt jar
+#
+# This target generates the native jni bindings for a set of classes in a .jar.
+#
+# See base/android/jni_generator/jni_generator.py for more info about the
+# format of generating JNI bindings.
+#
+# Variables
+#   classes: list of .class files in the jar to generate jni for. These should
+#     include the full path to the .class file.
+#   jni_package: subdirectory path for generated bindings
+#   jar_file: the path to the .jar. If not provided, will default to the sdk's
+#     android.jar
+#
+#   deps, public_deps: As normal
+#
+# Example
+#   generate_jar_jni("foo_jni") {
+#     classes = [
+#       "android/view/Foo.class",
+#     ]
+#     jni_package = "foo"
+#   }
+template("generate_jar_jni") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.classes))
+  assert(defined(invoker.jni_package))
+
+  if (defined(invoker.jar_file)) {
+    jar_file = invoker.jar_file
+  } else {
+    jar_file = android_sdk_jar
+  }
+
+  jni_package = invoker.jni_package
+  base_output_dir = "${root_gen_dir}/${target_name}/${jni_package}"
+  jni_output_dir = "${base_output_dir}/jni"
+
+  jni_generator_include = "//base/android/jni_generator/jni_generator_helper.h"
+
+  # TODO(cjhopman): make jni_generator.py support generating jni for multiple
+  # .class files from a .jar.
+  jni_actions = []
+  foreach(class, invoker.classes) {
+    _classname_list = []
+    _classname_list = process_file_template([ class ], "{{source_name_part}}")
+    classname = _classname_list[0]
+    jni_target_name = "${target_name}__jni_${classname}"
+    jni_actions += [ ":$jni_target_name" ]
+    action(jni_target_name) {
+      # The sources aren't compiled so don't check their dependencies.
+      check_includes = false
+      depfile = "$target_gen_dir/$target_name.d"
+      script = "//base/android/jni_generator/jni_generator.py"
+      sources = [
+        jar_file,
+      ]
+      outputs = [
+        depfile,
+        "${jni_output_dir}/${classname}_jni.h",
+      ]
+
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--jar_file",
+        rebase_path(jar_file, root_build_dir),
+        "--input_file",
+        class,
+        "--optimize_generation=1",
+        "--ptr_type=long",
+        "--output_dir",
+        rebase_path(jni_output_dir, root_build_dir),
+        "--includes",
+        rebase_path(jni_generator_include, jni_output_dir),
+        "--native_exports_optional",
+      ]
+    }
+  }
+
+  config("jni_includes_${target_name}") {
+    include_dirs = [ base_output_dir ]
+  }
+
+  group(target_name) {
+    deps = jni_actions
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    if (defined(invoker.public_deps)) {
+      public_deps = invoker.public_deps
+    }
+    public_configs = [ ":jni_includes_${target_name}" ]
+  }
+}
+
+# Declare a target for c-preprocessor-generated java files
+#
+# NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum
+#       rule instead.
+#
+# This target generates java files using the host C pre-processor. Each file in
+# sources will be compiled using the C pre-processor. If include_path is
+# specified, it will be passed (with --I) to the pre-processor.
+#
+# This target will create a single .srcjar. Adding this target to an
+# android_library target's srcjar_deps will make the generated java files be
+# included in that library's final outputs.
+#
+# Variables
+#   sources: list of files to be processed by the C pre-processor. For each
+#     file in sources, there will be one .java file in the final .srcjar. For a
+#     file named FooBar.template, a java file will be created with name
+#     FooBar.java.
+#   inputs: additional compile-time dependencies. Any files
+#     `#include`-ed in the templates should be listed here.
+#   package_name: this will be the subdirectory for each .java file in the
+#     .srcjar.
+#
+# Example
+#   java_cpp_template("foo_generated_enum") {
+#     sources = [
+#       "android/java/templates/Foo.template",
+#     ]
+#     inputs = [
+#       "android/java/templates/native_foo_header.h",
+#     ]
+#
+#     package_name = "org/chromium/base/library_loader"
+#     include_path = "android/java/templates"
+#   }
+template("java_cpp_template") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.sources))
+  package_name = invoker.package_name + ""
+
+  if (defined(invoker.include_path)) {
+    include_path = invoker.include_path + ""
+  } else {
+    include_path = "//"
+  }
+
+  action_foreach("${target_name}__apply_gcc") {
+    script = "//build/android/gyp/gcc_preprocess.py"
+    if (defined(invoker.inputs)) {
+      inputs = invoker.inputs + []
+    }
+    depfile = "${target_gen_dir}/${target_name}_{{source_name_part}}.d"
+
+    sources = invoker.sources
+
+    gen_dir =
+        "${target_gen_dir}/${target_name}/java_cpp_template/${package_name}"
+    gcc_template_output_pattern = "${gen_dir}/{{source_name_part}}.java"
+
+    outputs = [
+      depfile,
+      gcc_template_output_pattern,
+    ]
+
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--include-path",
+      rebase_path(include_path, root_build_dir),
+      "--output",
+      rebase_path(gen_dir, root_build_dir) + "/{{source_name_part}}.java",
+      "--template={{source}}",
+    ]
+
+    if (defined(invoker.defines)) {
+      foreach(def, invoker.defines) {
+        args += [
+          "--defines",
+          def,
+        ]
+      }
+    }
+  }
+
+  apply_gcc_outputs = get_target_outputs(":${target_name}__apply_gcc")
+  base_gen_dir = get_label_info(":${target_name}__apply_gcc", "target_gen_dir")
+
+  srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
+  zip("${target_name}__zip_srcjar") {
+    inputs = apply_gcc_outputs
+    output = srcjar_path
+    base_dir = base_gen_dir
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__zip_srcjar",
+    ]
+  }
+}
+
+# Declare a target for generating Java classes from C++ enums.
+#
+# This target generates Java files from C++ enums using a script.
+#
+# This target will create a single .srcjar. Adding this target to an
+# android_library target's srcjar_deps will make the generated java files be
+# included in that library's final outputs.
+#
+# Variables
+#   sources: list of files to be processed by the script. For each annotated
+#     enum contained in the sources files the script will generate a .java
+#     file with the same name as the name of the enum.
+#
+#   outputs: list of outputs, relative to the output_dir. These paths are
+#     verified at build time by the script. To get the list programatically run:
+#       python build/android/gyp/java_cpp_enum.py \
+#         --print_output_only . path/to/header/file.h
+#
+# Example
+#   java_cpp_enum("foo_generated_enum") {
+#     sources = [
+#       "src/native_foo_header.h",
+#     ]
+#     outputs = [
+#       "org/chromium/FooEnum.java",
+#     ]
+#   }
+template("java_cpp_enum") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.sources))
+  assert(defined(invoker.outputs))
+
+  action("${target_name}__generate_enum") {
+    # The sources aren't compiled so don't check their dependencies.
+    check_includes = false
+
+    sources = invoker.sources
+    script = "//build/android/gyp/java_cpp_enum.py"
+    gen_dir = "${target_gen_dir}/${target_name}/enums"
+    outputs =
+        get_path_info(rebase_path(invoker.outputs, ".", gen_dir), "abspath")
+
+    args = []
+    foreach(output, rebase_path(outputs, root_build_dir)) {
+      args += [
+        "--assert_file",
+        output,
+      ]
+    }
+    args += [ rebase_path(gen_dir, root_build_dir) ]
+    args += rebase_path(invoker.sources, root_build_dir)
+  }
+
+  generate_enum_outputs = get_target_outputs(":${target_name}__generate_enum")
+  base_gen_dir =
+      get_label_info(":${target_name}__generate_enum", "target_gen_dir")
+
+  srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
+  zip("${target_name}__zip_srcjar") {
+    inputs = generate_enum_outputs
+    output = srcjar_path
+    base_dir = base_gen_dir
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__zip_srcjar",
+    ]
+  }
+}
+
+# Declare a target for processing a Jinja template.
+#
+# Variables
+#   input: The template file to be processed.
+#   output: Where to save the result.
+#   variables: (Optional) A list of variables to make available to the template
+#     processing environment, e.g. ["name=foo", "color=red"].
+#
+# Example
+#   jinja_template("chrome_shell_manifest") {
+#     input = "shell/java/AndroidManifest.xml"
+#     output = "$target_gen_dir/AndroidManifest.xml"
+#   }
+template("jinja_template") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.input))
+  assert(defined(invoker.output))
+
+  action(target_name) {
+    sources = [
+      invoker.input,
+    ]
+    script = "//build/android/gyp/jinja_template.py"
+    depfile = "$target_gen_dir/$target_name.d"
+
+    outputs = [
+      depfile,
+      invoker.output,
+    ]
+
+    args = [
+      "--inputs",
+      rebase_path(invoker.input, root_build_dir),
+      "--output",
+      rebase_path(invoker.output, root_build_dir),
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+    ]
+    if (defined(invoker.variables)) {
+      variables = invoker.variables
+      args += [ "--variables=${variables}" ]
+    }
+  }
+}
+
+# Declare a target for processing Android resources as Jinja templates.
+#
+# This takes an Android resource directory where each resource is a Jinja
+# template, processes each template, then packages the results in a zip file
+# which can be consumed by an android resources, library, or apk target.
+#
+# If this target is included in the deps of an android resources/library/apk,
+# the resources will be included with that target.
+#
+# Variables
+#   resources: The list of resources files to process.
+#   res_dir: The resource directory containing the resources.
+#   variables: (Optional) A list of variables to make available to the template
+#     processing environment, e.g. ["name=foo", "color=red"].
+#
+# Example
+#   jinja_template_resources("chrome_shell_template_resources") {
+#     res_dir = "shell/res_template"
+#     resources = ["shell/res_template/xml/syncable.xml"]
+#     variables = ["color=red"]
+#   }
+template("jinja_template_resources") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.resources))
+  assert(defined(invoker.res_dir))
+
+  _base_path = "$target_gen_dir/$target_name"
+  _resources_zip = _base_path + ".resources.zip"
+  _build_config = _base_path + ".build_config"
+
+  write_build_config("${target_name}__build_config") {
+    build_config = _build_config
+    resources_zip = _resources_zip
+    type = "android_resources"
+  }
+
+  action("${target_name}__template") {
+    sources = invoker.resources
+    script = "//build/android/gyp/jinja_template.py"
+    depfile = "$target_gen_dir/$target_name.d"
+
+    outputs = [
+      depfile,
+      _resources_zip,
+    ]
+
+    rebased_resources = rebase_path(invoker.resources, root_build_dir)
+    args = [
+      "--inputs=${rebased_resources}",
+      "--inputs-base-dir",
+      rebase_path(invoker.res_dir, root_build_dir),
+      "--outputs-zip",
+      rebase_path(_resources_zip, root_build_dir),
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+    ]
+    if (defined(invoker.variables)) {
+      variables = invoker.variables
+      args += [ "--variables=${variables}" ]
+    }
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__build_config",
+      ":${target_name}__template",
+    ]
+  }
+}
+
+# Declare an Android resources target
+#
+# This creates a resources zip file that will be used when building an Android
+# library or apk and included into a final apk.
+#
+# To include these resources in a library/apk, this target should be listed in
+# the library's deps. A library/apk will also include any resources used by its
+# own dependencies.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Any Android resources
+#     listed in deps will be included by libraries/apks that depend on this
+#     target.
+#   resource_dirs: List of directories containing resources for this target.
+#   android_manifest: AndroidManifest.xml for this target. Defaults to
+#     //build/android/AndroidManifest.xml.
+#   custom_package: java package for generated .java files.
+#   v14_verify_only: If true, don't generate v14/v17 resources and just verify
+#     that the resources are v14-compliant (see
+#     build/android/gyp/generate_v14_compatible_resources.py). Defaults to
+#     false.
+#   shared_resources: If true make a resource package that can be loaded by a
+#     different application at runtime to access the package's resources.
+#
+# Example
+#   android_resources("foo_resources") {
+#     deps = [":foo_strings_grd"]
+#     resource_dirs = ["res"]
+#     custom_package = "org.chromium.foo"
+#   }
+template("android_resources") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.resource_dirs))
+  assert(defined(invoker.android_manifest) || defined(invoker.custom_package))
+
+  base_path = "$target_gen_dir/$target_name"
+  zip_path = base_path + ".resources.zip"
+  srcjar_path = base_path + ".srcjar"
+  build_config = base_path + ".build_config"
+
+  write_build_config("${target_name}__build_config") {
+    type = "android_resources"
+    resources_zip = zip_path
+    srcjar = srcjar_path
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.android_manifest)) {
+      android_manifest = invoker.android_manifest
+    }
+    if (defined(invoker.custom_package)) {
+      custom_package = invoker.custom_package
+    }
+  }
+
+  android_manifest = "//build/android/AndroidManifest.xml"
+  if (defined(invoker.android_manifest)) {
+    android_manifest = invoker.android_manifest
+  }
+
+  process_resources("${target_name}__process_resources") {
+    resource_dirs = invoker.resource_dirs
+    if (defined(invoker.custom_package)) {
+      custom_package = invoker.custom_package
+    }
+
+    if (defined(invoker.v14_verify_only)) {
+      v14_verify_only = invoker.v14_verify_only
+    }
+
+    if (defined(invoker.shared_resources)) {
+      shared_resources = invoker.shared_resources
+    }
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__build_config",
+      ":${target_name}__process_resources",
+    ]
+  }
+}
+
+# Declare a target that generates localized strings.xml from a .grd file.
+#
+# If this target is included in the deps of an android resources/library/apk,
+# the strings.xml will be included with that target.
+#
+# Variables
+#   deps: Specifies the dependencies of this target.
+#   grd_file: Path to the .grd file to generate strings.xml from.
+#   outputs: Expected grit outputs (see grit rule).
+#
+# Example
+#  java_strings_grd("foo_strings_grd") {
+#    grd_file = "foo_strings.grd"
+#  }
+template("java_strings_grd") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  base_path = "$target_gen_dir/$target_name"
+  resources_zip = base_path + ".resources.zip"
+  build_config = base_path + ".build_config"
+
+  write_build_config("${target_name}__build_config") {
+    type = "android_resources"
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+
+  # Put grit files into this subdirectory of target_gen_dir.
+  extra_output_path = target_name + "_grit_output"
+
+  grit_target_name = "${target_name}__grit"
+  grit_output_dir = "$target_gen_dir/$extra_output_path"
+  grit(grit_target_name) {
+    grit_flags = [
+      "-E",
+      "ANDROID_JAVA_TAGGED_ONLY=false",
+    ]
+    output_dir = grit_output_dir
+    resource_ids = ""
+    source = invoker.grd_file
+    outputs = invoker.outputs
+  }
+
+  # This needs to get outputs from grit's internal target, not the final
+  # source_set.
+  generate_strings_outputs = get_target_outputs(":${grit_target_name}_grit")
+
+  zip("${target_name}__zip") {
+    base_dir = grit_output_dir
+    inputs = generate_strings_outputs
+    output = resources_zip
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__build_config",
+      ":${target_name}__zip",
+    ]
+  }
+}
+
+# Declare a target that packages strings.xml generated from a grd file.
+#
+# If this target is included in the deps of an android resources/library/apk,
+# the strings.xml will be included with that target.
+#
+# Variables
+#  grit_output_dir: directory containing grit-generated files.
+#  generated_files: list of android resource files to package.
+#
+# Example
+#  java_strings_grd_prebuilt("foo_strings_grd") {
+#    grit_output_dir = "$root_gen_dir/foo/grit"
+#    generated_files = [
+#      "values/strings.xml"
+#    ]
+#  }
+template("java_strings_grd_prebuilt") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  base_path = "$target_gen_dir/$target_name"
+  resources_zip = base_path + ".resources.zip"
+  build_config = base_path + ".build_config"
+
+  write_build_config("${target_name}__build_config") {
+    type = "android_resources"
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+
+  zip("${target_name}__zip") {
+    base_dir = invoker.grit_output_dir
+    inputs = rebase_path(invoker.generated_files, ".", base_dir)
+    output = resources_zip
+  }
+
+  group(target_name) {
+    deps = [
+      ":${target_name}__build_config",
+      ":${target_name}__zip",
+    ]
+  }
+}
+
+# Declare a Java executable target
+#
+# This target creates an executable from java code and libraries. The executable
+# will be in the output folder's /bin/ directory.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Java targets in this list
+#     will be included in the executable (and the javac classpath).
+#
+#   java_files: List of .java files included in this library.
+#   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+#     will be added to java_files and be included in this library.
+#   srcjars: List of srcjars to be included in this library, together with the
+#     ones obtained from srcjar_deps.
+#
+#   bypass_platform_checks: Disables checks about cross-platform (Java/Android)
+#     dependencies for this target. This will allow depending on an
+#     android_library target, for example.
+#
+#   chromium_code: If true, extra analysis warning/errors will be enabled.
+#
+#   datadeps, testonly
+#
+# Example
+#   java_binary("foo") {
+#     java_files = [ "org/chromium/foo/FooMain.java" ]
+#     deps = [ ":bar_java" ]
+#     main_class = "org.chromium.foo.FooMain"
+#   }
+template("java_binary") {
+  set_sources_assignment_filter([])
+
+  # TODO(cjhopman): This should not act like a java_library for dependents (i.e.
+  # dependents shouldn't get the jar in their classpath, etc.).
+  java_library_impl(target_name) {
+    if (defined(invoker.DEPRECATED_java_in_dir)) {
+      DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir
+    }
+    if (defined(invoker.chromium_code)) {
+      chromium_code = invoker.chromium_code
+    }
+    if (defined(invoker.datadeps)) {
+      deps = invoker.datadeps
+    }
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.java_files)) {
+      java_files = invoker.java_files
+    }
+    if (defined(invoker.srcjar_deps)) {
+      srcjar_deps = invoker.srcjar_deps
+    }
+    if (defined(invoker.srcjars)) {
+      srcjars = invoker.srcjars
+    }
+    if (defined(invoker.bypass_platform_checks)) {
+      bypass_platform_checks = invoker.bypass_platform_checks
+    }
+    if (defined(invoker.testonly)) {
+      testonly = invoker.testonly
+    }
+
+    main_class = invoker.main_class
+  }
+}
+
+# Declare a Junit executable target
+#
+# This target creates an executable from java code for running as a junit test
+# suite. The executable will be in the output folder's /bin/ directory.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Java targets in this list
+#     will be included in the executable (and the javac classpath).
+#
+#   java_files: List of .java files included in this library.
+#   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+#     will be added to java_files and be included in this library.
+#   srcjars: List of srcjars to be included in this library, together with the
+#     ones obtained from srcjar_deps.
+#
+#   chromium_code: If true, extra analysis warning/errors will be enabled.
+#
+# Example
+#   junit_binary("foo") {
+#     java_files = [ "org/chromium/foo/FooTest.java" ]
+#     deps = [ ":bar_java" ]
+#   }
+template("junit_binary") {
+  set_sources_assignment_filter([])
+
+  java_binary(target_name) {
+    bypass_platform_checks = true
+    main_class = "org.chromium.testing.local.JunitTestMain"
+    testonly = true
+
+    if (defined(invoker.DEPRECATED_java_in_dir)) {
+      DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir
+    }
+    if (defined(invoker.chromium_code)) {
+      chromium_code = invoker.chromium_code
+    }
+    deps = [
+      "//testing/android/junit:junit_test_support",
+      "//third_party/junit",
+      "//third_party/mockito:mockito_java",
+      "//third_party/robolectric:robolectric_java",
+      "//third_party/robolectric:android-all-4.3_r2-robolectric-0",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    if (defined(invoker.java_files)) {
+      java_files = invoker.java_files
+    }
+    if (defined(invoker.srcjar_deps)) {
+      srcjar_deps = invoker.srcjar_deps
+    }
+    if (defined(invoker.srcjars)) {
+      srcjars = invoker.srcjars
+    }
+  }
+}
+
+# Declare a java library target
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Java targets in this list
+#     will be added to the javac classpath.
+#
+#   java_files: List of .java files included in this library.
+#   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+#     will be added to java_files and be included in this library.
+#   srcjars: List of srcjars to be included in this library, together with the
+#     ones obtained from srcjar_deps.
+#   DEPRECATED_java_in_dir: Directory containing java files. All .java files in
+#     this directory will be included in the library. This is only supported to
+#     ease the gyp->gn conversion and will be removed in the future.
+#
+#   chromium_code: If true, extra analysis warning/errors will be enabled.
+#   jar_excluded_patterns: List of patterns of .class files to exclude from the
+#     final jar.
+#
+#   proguard_preprocess: If true, proguard preprocessing will be run. This can
+#     be used to remove unwanted parts of the library.
+#   proguard_config: Path to the proguard config for preprocessing.
+#
+#   supports_android: If true, Android targets (android_library, android_apk)
+#     may depend on this target. Note: if true, this target must only use the
+#     subset of Java available on Android.
+#   bypass_platform_checks: Disables checks about cross-platform (Java/Android)
+#     dependencies for this target. This will allow depending on an
+#     android_library target, for example.
+#
+#   datadeps, testonly
+#
+# Example
+#   java_library("foo_java") {
+#     java_files = [
+#       "org/chromium/foo/Foo.java",
+#       "org/chromium/foo/FooInterface.java",
+#       "org/chromium/foo/FooService.java",
+#     ]
+#     deps = [
+#       ":bar_java"
+#     ]
+#     srcjar_deps = [
+#       ":foo_generated_enum"
+#     ]
+#     jar_excluded_patterns = [
+#       "*/FooService.class", "*/FooService##*.class"
+#     ]
+#   }
+template("java_library") {
+  set_sources_assignment_filter([])
+  java_library_impl(target_name) {
+    if (defined(invoker.DEPRECATED_java_in_dir)) {
+      DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir
+    }
+    if (defined(invoker.chromium_code)) {
+      chromium_code = invoker.chromium_code
+    }
+    if (defined(invoker.datadeps)) {
+      deps = invoker.datadeps
+    }
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.jar_excluded_patterns)) {
+      jar_excluded_patterns = invoker.jar_excluded_patterns
+    }
+    if (defined(invoker.java_files)) {
+      java_files = invoker.java_files
+    }
+    if (defined(invoker.proguard_config)) {
+      proguard_config = invoker.proguard_config
+    }
+    if (defined(invoker.proguard_preprocess)) {
+      proguard_preprocess = invoker.proguard_preprocess
+    }
+    if (defined(invoker.srcjar_deps)) {
+      srcjar_deps = invoker.srcjar_deps
+    }
+    if (defined(invoker.srcjars)) {
+      srcjars = invoker.srcjars
+    }
+    if (defined(invoker.bypass_platform_checks)) {
+      bypass_platform_checks = invoker.bypass_platform_checks
+    }
+    if (defined(invoker.testonly)) {
+      testonly = invoker.testonly
+    }
+    if (defined(invoker.jar_path)) {
+      jar_path = invoker.jar_path
+    }
+
+    if (defined(invoker.supports_android) && invoker.supports_android) {
+      supports_android = true
+    }
+  }
+}
+
+# Declare a java library target for a prebuilt jar
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Java targets in this list
+#     will be added to the javac classpath.
+#   jar_path: Path to the prebuilt jar.
+#   proguard_preprocess: If true, proguard preprocessing will be run. This can
+#     be used to remove unwanted parts of the library.
+#   proguard_config: Path to the proguard config for preprocessing.
+#
+# Example
+#   java_prebuilt("foo_java") {
+#     jar_path = "foo.jar"
+#     deps = [
+#       ":foo_resources",
+#       ":bar_java"
+#     ]
+#   }
+template("java_prebuilt") {
+  set_sources_assignment_filter([])
+  java_prebuilt_impl(target_name) {
+    jar_path = invoker.jar_path
+    if (defined(invoker.testonly)) {
+      testonly = invoker.testonly
+    }
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.proguard_config)) {
+      proguard_config = invoker.proguard_config
+    }
+    if (defined(invoker.proguard_preprocess)) {
+      proguard_preprocess = invoker.proguard_preprocess
+    }
+  }
+}
+
+# Declare an Android library target
+#
+# This target creates an Android library containing java code and Android
+# resources.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Java targets in this list
+#     will be added to the javac classpath. Android resources in dependencies
+#     will be used when building this library.
+#
+#   java_files: List of .java files included in this library.
+#   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+#     will be added to java_files and be included in this library.
+#   srcjars: List of srcjars to be included in this library, together with the
+#     ones obtained from srcjar_deps.
+#   DEPRECATED_java_in_dir: Directory containing java files. All .java files in
+#     this directory will be included in the library. This is only supported to
+#     ease the gyp->gn conversion and will be removed in the future.
+#
+#   chromium_code: If true, extra analysis warning/errors will be enabled.
+#   jar_excluded_patterns: List of patterns of .class files to exclude from the
+#     final jar.
+#
+#   proguard_preprocess: If true, proguard preprocessing will be run. This can
+#     be used to remove unwanted parts of the library.
+#   proguard_config: Path to the proguard config for preprocessing.
+#
+#   dex_path: If set, the resulting .dex.jar file will be placed under this
+#     path.
+#
+#
+# Example
+#   android_library("foo_java") {
+#     java_files = [
+#       "android/org/chromium/foo/Foo.java",
+#       "android/org/chromium/foo/FooInterface.java",
+#       "android/org/chromium/foo/FooService.java",
+#     ]
+#     deps = [
+#       ":bar_java"
+#     ]
+#     srcjar_deps = [
+#       ":foo_generated_enum"
+#     ]
+#     jar_excluded_patterns = [
+#       "*/FooService.class", "*/FooService##*.class"
+#     ]
+#   }
+template("android_library") {
+  set_sources_assignment_filter([])
+  assert(!defined(invoker.jar_path),
+         "android_library does not support a custom jar path")
+  java_library_impl(target_name) {
+    if (defined(invoker.DEPRECATED_java_in_dir)) {
+      DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir
+    }
+    if (defined(invoker.chromium_code)) {
+      chromium_code = invoker.chromium_code
+    }
+    if (defined(invoker.datadeps)) {
+      deps = invoker.datadeps
+    }
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.jar_excluded_patterns)) {
+      jar_excluded_patterns = invoker.jar_excluded_patterns
+    }
+    if (defined(invoker.java_files)) {
+      java_files = invoker.java_files
+    }
+    if (defined(invoker.proguard_config)) {
+      proguard_config = invoker.proguard_config
+    }
+    if (defined(invoker.proguard_preprocess)) {
+      proguard_preprocess = invoker.proguard_preprocess
+    }
+    if (defined(invoker.srcjar_deps)) {
+      srcjar_deps = invoker.srcjar_deps
+    }
+    if (defined(invoker.srcjars)) {
+      srcjars = invoker.srcjars
+    }
+    if (defined(invoker.testonly)) {
+      testonly = invoker.testonly
+    }
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+    if (defined(invoker.dex_path)) {
+      dex_path = invoker.dex_path
+    }
+    if (defined(invoker.manifest_entries)) {
+      manifest_entries = invoker.manifest_entries
+    }
+
+    supports_android = true
+    requires_android = true
+
+    if (!defined(jar_excluded_patterns)) {
+      jar_excluded_patterns = []
+    }
+    jar_excluded_patterns += [
+      "*/R.class",
+      "*/R##*.class",
+      "*/Manifest.class",
+      "*/Manifest##*.class",
+    ]
+  }
+}
+
+# Declare a target that packages a set of Java dependencies into a standalone
+# .dex.jar.
+#
+# Variables
+#   deps: specifies the dependencies of this target. Android libraries in deps
+#     will be packaged into the resulting .dex.jar file.
+#   dex_path: location at which the output file will be put
+template("android_standalone_library") {
+  set_sources_assignment_filter([])
+  deps_dex(target_name) {
+    deps = invoker.deps
+    dex_path = invoker.dex_path
+    if (defined(invoker.excluded_jars)) {
+      excluded_jars = invoker.excluded_jars
+    }
+  }
+}
+
+# Declare an Android library target for a prebuilt jar
+#
+# This target creates an Android library containing java code and Android
+# resources.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. Java targets in this list
+#     will be added to the javac classpath. Android resources in dependencies
+#     will be used when building this library.
+#   jar_path: Path to the prebuilt jar.
+#   proguard_preprocess: If true, proguard preprocessing will be run. This can
+#     be used to remove unwanted parts of the library.
+#   proguard_config: Path to the proguard config for preprocessing.
+#
+# Example
+#   android_java_prebuilt("foo_java") {
+#     jar_path = "foo.jar"
+#     deps = [
+#       ":foo_resources",
+#       ":bar_java"
+#     ]
+#   }
+template("android_java_prebuilt") {
+  set_sources_assignment_filter([])
+  java_prebuilt_impl(target_name) {
+    jar_path = invoker.jar_path
+    supports_android = true
+    requires_android = true
+    if (defined(invoker.testonly)) {
+      testonly = invoker.testonly
+    }
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.proguard_config)) {
+      proguard_config = invoker.proguard_config
+    }
+    if (defined(invoker.proguard_preprocess)) {
+      proguard_preprocess = invoker.proguard_preprocess
+    }
+  }
+}
+
+# Declare an Android apk target
+#
+# This target creates an Android APK containing java code, resources, assets,
+# and (possibly) native libraries.
+#
+# Variables
+#   android_manifest: Path to AndroidManifest.xml.
+#   datadeps: List of dependencies needed at runtime. These will be built but
+#     won't change the generated .apk in any way (in fact they may be built
+#     after the .apk is).
+#   deps: List of dependencies. All Android java resources and libraries in the
+#     "transitive closure" of these dependencies will be included in the apk.
+#     Note: this "transitive closure" actually only includes such targets if
+#     they are depended on through android_library or android_resources targets
+#     (and so not through builtin targets like 'action', 'group', etc).
+#   java_files: List of .java files to include in the apk.
+#   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+#      will be added to java_files and be included in this apk.
+#   apk_name: Name for final apk.
+#   final_apk_path: Path to final built apk. Default is
+#     $root_out_dir/apks/$apk_name.apk. Setting this will override apk_name.
+#   native_libs: List paths of native libraries to include in this apk. If these
+#     libraries depend on other shared_library targets, those dependencies will
+#     also be included in the apk.
+#   apk_under_test: For an instrumentation test apk, this is the target of the
+#     tested apk.
+#   testonly: Marks this target as "test-only".
+#
+#   DEPRECATED_java_in_dir: Directory containing java files. All .java files in
+#     this directory will be included in the library. This is only supported to
+#     ease the gyp->gn conversion and will be removed in the future.
+#
+# Example
+#   android_apk("foo_apk") {
+#     android_manifest = "AndroidManifest.xml"
+#     java_files = [
+#       "android/org/chromium/foo/FooApplication.java",
+#       "android/org/chromium/foo/FooActivity.java",
+#     ]
+#     deps = [
+#       ":foo_support_java"
+#       ":foo_resources"
+#     ]
+#     srcjar_deps = [
+#       ":foo_generated_enum"
+#     ]
+#     native_libs = [
+#       native_lib_path
+#     ]
+#   }
+template("android_apk") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  assert(defined(invoker.final_apk_path) || defined(invoker.apk_name))
+  assert(defined(invoker.android_manifest))
+  gen_dir = "$target_gen_dir/$target_name"
+  base_path = "$gen_dir/$target_name"
+  _build_config = "$target_gen_dir/$target_name.build_config"
+  resources_zip_path = "$base_path.resources.zip"
+  all_resources_zip_path = "$base_path.resources.all.zip"
+  jar_path = "$base_path.jar"
+  final_dex_path = "$gen_dir/classes.dex"
+  _template_name = target_name
+  _final_apk_path = ""
+  if (defined(invoker.final_apk_path)) {
+    _final_apk_path = invoker.final_apk_path
+  } else if (defined(invoker.apk_name)) {
+    _final_apk_path = "$root_build_dir/apks/" + invoker.apk_name + ".apk"
+  }
+  _dist_jar_path_list =
+      process_file_template(
+          [ _final_apk_path ],
+          "$root_build_dir/test.lib.java/{{source_name_part}}.jar")
+  _dist_jar_path = _dist_jar_path_list[0]
+
+  _native_libs = []
+
+  _keystore_path = android_default_keystore_path
+  _keystore_name = android_default_keystore_name
+  _keystore_password = android_default_keystore_password
+
+  if (defined(invoker.keystore_path)) {
+    _keystore_path = invoker.keystore_path
+    _keystore_name = invoker.keystore_name
+    _keystore_password = invoker.keystore_password
+  }
+
+  _srcjar_deps = []
+  if (defined(invoker.srcjar_deps)) {
+    _srcjar_deps += invoker.srcjar_deps
+  }
+
+  _load_library_from_apk = false
+
+  if (defined(invoker.native_libs)) {
+    _use_chromium_linker = false
+    if (defined(invoker.use_chromium_linker)) {
+      _use_chromium_linker =
+          invoker.use_chromium_linker && chromium_linker_supported
+    }
+
+    if (defined(invoker.load_library_from_apk) &&
+        invoker.load_library_from_apk) {
+      _load_library_from_apk = true
+      assert(_use_chromium_linker,
+             "Loading library from the apk requires use" +
+                 " of the Chromium linker.")
+    }
+
+    _enable_relocation_packing = false
+    if (defined(invoker.enable_relocation_packing) &&
+        invoker.enable_relocation_packing) {
+      _enable_relocation_packing = relocation_packing_supported
+      assert(_use_chromium_linker,
+             "Relocation packing requires use of the" + " Chromium linker.")
+    }
+
+    _native_libs = process_file_template(
+            invoker.native_libs,
+            "$root_build_dir/lib.stripped/{{source_file_part}}")
+
+    _native_libs_dir = base_path + "/libs"
+
+    if (_use_chromium_linker) {
+      _native_libs +=
+          [ "$root_build_dir/lib.stripped/libchromium_android_linker.so" ]
+    }
+
+    _enable_relocation_packing = false
+    if (_use_chromium_linker && defined(invoker.enable_relocation_packing) &&
+        invoker.enable_relocation_packing) {
+      _enable_relocation_packing = true
+    }
+
+    _native_lib_version_name = ""
+    if (defined(invoker.native_lib_version_name)) {
+      _native_lib_version_name = invoker.native_lib_version_name
+    }
+  }
+
+  _android_manifest = invoker.android_manifest
+  _rebased_build_config = rebase_path(_build_config, root_build_dir)
+
+  write_build_config("${_template_name}__build_config") {
+    type = "android_apk"
+    dex_path = final_dex_path
+    resources_zip = resources_zip_path
+    build_config = _build_config
+    android_manifest = _android_manifest
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+
+    if (defined(invoker.apk_under_test)) {
+      apk_under_test = invoker.apk_under_test
+    }
+
+    native_libs = _native_libs
+  }
+
+  final_deps = []
+
+  final_deps += [ ":${_template_name}__process_resources" ]
+  process_resources("${_template_name}__process_resources") {
+    srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
+    android_manifest = _android_manifest
+    resource_dirs = [ "//build/android/ant/empty/res" ]
+    zip_path = resources_zip_path
+    generate_constant_ids = true
+    build_config = _build_config
+  }
+  _srcjar_deps += [ ":${_template_name}__process_resources" ]
+
+  if (_native_libs != []) {
+    _enable_chromium_linker_tests = false
+    if (defined(invoker.enable_chromium_linker_tests)) {
+      _enable_chromium_linker_tests = invoker.enable_chromium_linker_tests
+    }
+
+    java_cpp_template("${_template_name}__native_libraries_java") {
+      package_name = "org/chromium/base/library_loader"
+      sources = [
+        "//base/android/java/templates/NativeLibraries.template",
+      ]
+      inputs = [
+        _build_config,
+      ]
+
+      defines = [
+        "NATIVE_LIBRARIES_LIST=" +
+            "@FileArg($_rebased_build_config:native:java_libraries_list)",
+        "NATIVE_LIBRARIES_VERSION_NUMBER=\"$_native_lib_version_name\"",
+      ]
+      if (_use_chromium_linker) {
+        defines += [ "ENABLE_CHROMIUM_LINKER" ]
+      }
+      if (_load_library_from_apk) {
+        defines += [ "ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE" ]
+      }
+      if (_enable_chromium_linker_tests) {
+        defines += [ "ENABLE_CHROMIUM_LINKER_TESTS" ]
+      }
+    }
+    _srcjar_deps += [ ":${_template_name}__native_libraries_java" ]
+  }
+
+  final_deps += [ ":${_template_name}__java" ]
+  java_library_impl("${_template_name}__java") {
+    supports_android = true
+    requires_android = true
+    override_build_config = _build_config
+    android_manifest = _android_manifest
+    chromium_code = true
+    if (defined(invoker.java_files)) {
+      java_files = invoker.java_files
+    } else if (defined(invoker.DEPRECATED_java_in_dir)) {
+      DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir
+    } else {
+      java_files = []
+    }
+    srcjar_deps = _srcjar_deps
+    dex_path = base_path + ".dex.jar"
+  }
+
+  if (_dist_jar_path != "") {
+    final_deps += [ ":${_template_name}__create_dist_jar" ]
+
+    # TODO(cjhopman): This is only ever needed to calculate the list of tests to
+    # run. See build/android/pylib/instrumentation/test_jar.py. We should be
+    # able to just do that calculation at build time instead.
+    action("${_template_name}__create_dist_jar") {
+      script = "//build/android/gyp/create_dist_jar.py"
+      depfile = "$target_gen_dir/$target_name.d"
+      inputs = [
+        _build_config,
+      ]
+      outputs = [
+        depfile,
+        _dist_jar_path,
+      ]
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--output",
+        rebase_path(_dist_jar_path, root_build_dir),
+        "--inputs=@FileArg($_rebased_build_config:dist_jar:dependency_jars)",
+      ]
+      inputs += [ jar_path ]
+      _rebased_jar_path = rebase_path([ jar_path ], root_build_dir)
+      args += [ "--inputs=$_rebased_jar_path" ]
+    }
+  }
+
+  final_deps += [ ":${_template_name}__final_dex" ]
+  dex("${_template_name}__final_dex") {
+    deps = [
+      ":${_template_name}__java",
+    ]
+    sources = [
+      jar_path,
+    ]
+    inputs = [
+      _build_config,
+    ]
+    output = final_dex_path
+    dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files"
+    args = [ "--inputs=@FileArg($dex_arg_key)" ]
+  }
+
+  if (_native_libs != []) {
+    action("${_template_name}__prepare_native") {
+      script = "//build/android/gyp/pack_arm_relocations.py"
+      packed_libraries_dir = "$_native_libs_dir/$android_app_abi"
+      depfile = "$target_gen_dir/$target_name.d"
+      outputs = [
+        depfile,
+      ]
+      inputs = [ _build_config ] + _native_libs
+      deps = []
+      skip_packing_list = [
+        "gdbserver",
+        "libchromium_android_linker.so",
+      ]
+
+      enable_packing_arg = 0
+      if (_enable_relocation_packing) {
+        enable_packing_arg = 1
+        deps += [ relocation_packer_target ]
+      }
+
+      args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--enable-packing=$enable_packing_arg",
+        "--has-relocations-with-addends=$relocations_have_addends",
+        "--exclude-packing-list=$skip_packing_list",
+        "--android-pack-relocations",
+        rebase_path(relocation_packer_exe, root_build_dir),
+        "--android-objcopy",
+        rebase_path(android_objcopy, root_build_dir),
+        "--stripped-libraries-dir",
+        rebase_path(root_build_dir, root_build_dir),
+        "--packed-libraries-dir",
+        rebase_path(packed_libraries_dir, root_build_dir),
+        "--libraries=@FileArg(${_rebased_build_config}:native:libraries)",
+        "--clear-dir",
+      ]
+
+      if (is_debug) {
+        rebased_gdbserver = rebase_path([ android_gdbserver ], root_build_dir)
+        inputs += [ android_gdbserver ]
+        args += [ "--libraries=$rebased_gdbserver" ]
+      }
+    }
+  }
+
+  final_deps += [ ":${_template_name}__create" ]
+  create_apk("${_template_name}__create") {
+    apk_path = _final_apk_path
+    android_manifest = _android_manifest
+    resources_zip = all_resources_zip_path
+    dex_path = final_dex_path
+    load_library_from_apk = _load_library_from_apk
+
+    version_code = "1"
+    if (defined(invoker.version_code)) {
+      version_code = invoker.version_code
+    }
+
+    version_name = "Developer Build"
+    if (defined(invoker.version_name)) {
+      version_name = invoker.version_name
+    }
+
+    keystore_name = _keystore_name
+    keystore_path = _keystore_path
+    keystore_password = _keystore_password
+
+    deps = []
+    if (defined(invoker.asset_location)) {
+      asset_location = invoker.asset_location
+
+      # We don't know the exact dependencies that create the assets in
+      # |asset_location|; we depend on all caller deps until a better solution
+      # is figured out (http://crbug.com/433330).
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
+    }
+
+    if (_native_libs != []) {
+      native_libs_dir = _native_libs_dir
+      deps += [ ":${_template_name}__prepare_native" ]
+    }
+  }
+
+  group(target_name) {
+    deps = final_deps
+    if (defined(invoker.datadeps)) {
+      datadeps = invoker.datadeps
+    }
+  }
+}
+
+# Declare an Android gtest apk
+#
+# This target creates an Android apk for running gtest-based unittests.
+#
+# Variables
+#   deps: Specifies the dependencies of this target. These will be passed to
+#     the underlying android_apk invocation and should include the java and
+#     resource dependencies of the apk.
+#   unittests_dep: This should be the label of the gtest native target. This
+#     target must be defined previously in the same file.
+#   unittests_binary: The basename of the library produced by the unittests_dep
+#     target. If unspecified, it assumes the name of the unittests_dep target
+#     (which will be correct unless that target specifies an "output_name".
+#     TODO(brettw) make this automatic by allowing get_target_outputs to
+#     support executables.
+#   apk_name: The name of the produced apk. If unspecified, it uses the name
+#             of the unittests_dep target postfixed with "_apk"
+#
+# Example
+#   unittest_apk("foo_unittests_apk") {
+#     deps = [ ":foo_java", ":foo_resources" ]
+#     unittests_dep = ":foo_unittests"
+#   }
+template("unittest_apk") {
+  set_sources_assignment_filter([])
+  testonly = true
+
+  assert(defined(invoker.unittests_dep), "Need unittests_dep for $target_name")
+
+  test_suite_name = get_label_info(invoker.unittests_dep, "name")
+
+  # This trivial assert is needed in case both unittests_binary and apk_name
+  # are defined, as otherwise test_suite_name would not be used.
+  assert(test_suite_name != "")
+
+  if (defined(invoker.unittests_binary)) {
+    unittests_binary = invoker.unittests_binary
+  } else {
+    unittests_binary = "lib" + test_suite_name + ".so"
+  }
+
+  if (defined(invoker.apk_name)) {
+    apk_name = invoker.apk_name
+  } else {
+    apk_name = test_suite_name
+  }
+
+  android_apk(target_name) {
+    final_apk_path = "$root_build_dir/${apk_name}_apk/${apk_name}-debug.apk"
+    java_files = [
+      "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java",
+      "//testing/android/native_test/java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
+    ]
+    android_manifest = "//testing/android/native_test/java/AndroidManifest.xml"
+    native_libs = [ unittests_binary ]
+    if (defined(invoker.asset_location)) {
+      asset_location = invoker.asset_location
+    }
+    deps = [
+      "//base:base_java",
+      "//build/android/pylib/remote/device/dummy:remote_device_dummy_apk",
+      "//testing/android/appurify_support:appurify_support_java",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    datadeps = [
+      "//tools/android/forwarder2",
+      "//tools/android/md5sum",
+    ]
+    if (defined(invoker.datadeps)) {
+      datadeps += invoker.datadeps
+    }
+  }
+}
+
+# Generate .java files from .aidl files.
+#
+# This target will store the .java files in a srcjar and should be included in
+# an android_library or android_apk's srcjar_deps.
+#
+# Variables
+#   sources: Paths to .aidl files to compile.
+#   import_include: Path to directory containing .java files imported by the
+#     .aidl files.
+#   interface_file: Preprocessed aidl file to import.
+#
+# Example
+#   android_aidl("foo_aidl") {
+#     import_include = "java/src"
+#     sources = [
+#       "java/src/com/foo/bar/FooBarService.aidl",
+#       "java/src/com/foo/bar/FooBarServiceCallback.aidl",
+#     ]
+#   }
+template("android_aidl") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
+  aidl_path = "${android_sdk_build_tools}/aidl"
+  framework_aidl = "$android_sdk/framework.aidl"
+
+  action(target_name) {
+    script = "//build/android/gyp/aidl.py"
+    sources = invoker.sources
+
+    imports = [ framework_aidl ]
+    if (defined(invoker.interface_file)) {
+      assert(invoker.interface_file != "")
+      imports += [ invoker.interface_file ]
+    }
+
+    inputs = [ aidl_path ] + imports
+
+    depfile = "${target_gen_dir}/${target_name}.d"
+    outputs = [
+      depfile,
+      srcjar_path,
+    ]
+    rebased_imports = rebase_path(imports, root_build_dir)
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--aidl-path",
+      rebase_path(aidl_path, root_build_dir),
+      "--imports=$rebased_imports",
+      "--srcjar",
+      rebase_path(srcjar_path, root_build_dir),
+    ]
+    if (defined(invoker.import_include) && invoker.import_include != "") {
+      # TODO(cjhopman): aidl supports creating a depfile. We should be able to
+      # switch to constructing a depfile for the overall action from that
+      # instead of having all the .java files in the include paths as inputs.
+      rebased_import_includes =
+          rebase_path([ invoker.import_include ], root_build_dir)
+      args += [ "--includes=$rebased_import_includes" ]
+
+      _java_files_build_rel =
+          exec_script("//build/android/gyp/find.py",
+                      rebase_path([ invoker.import_include ], root_build_dir),
+                      "list lines")
+      _java_files = rebase_path(_java_files_build_rel, ".", root_build_dir)
+      inputs += _java_files
+    }
+    args += rebase_path(sources, root_build_dir)
+  }
+}
+
+# Creates a dist directory for a native executable.
+#
+# Running a native executable on a device requires all the shared library
+# dependencies of that executable. To make it easier to install and run such an
+# executable, this will create a directory containing the native exe and all
+# it's library dependencies.
+#
+# Note: It's usually better to package things as an APK than as a native
+# executable.
+#
+# Variables
+#   dist_dir: Directory for the exe and libraries. Everything in this directory
+#     will be deleted before copying in the exe and libraries.
+#   binary: Path to (stripped) executable.
+#
+# Example
+#   create_native_executable_dist("foo_dist") {
+#     dist_dir = "$root_build_dir/foo_dist"
+#     binary = "$root_build_dir/exe.stripped/foo"
+#   }
+template("create_native_executable_dist") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+
+  dist_dir = invoker.dist_dir
+  binary = invoker.binary
+  final_deps = []
+  template_name = target_name
+
+  libraries_list =
+      "${target_gen_dir}/${template_name}_library_dependencies.list"
+
+  # TODO(gyp)
+  #'dependencies': [
+  #'<(DEPTH)/build/android/setup.gyp:copy_system_libraries',
+  #],
+
+  stripped_libraries_dir = "$root_build_dir/lib.stripped"
+  final_deps += [ ":${template_name}__find_library_dependencies" ]
+  action("${template_name}__find_library_dependencies") {
+    script = "//build/android/gyp/write_ordered_libraries.py"
+    depfile = "$target_gen_dir/$target_name.d"
+    inputs = [
+      binary,
+      android_readelf,
+    ]
+    outputs = [
+      depfile,
+      libraries_list,
+    ]
+    rebased_binaries = rebase_path([ binary ], root_build_dir)
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--input-libraries=$rebased_binaries",
+      "--libraries-dir",
+      rebase_path(stripped_libraries_dir, root_build_dir),
+      "--output",
+      rebase_path(libraries_list, root_build_dir),
+      "--readelf",
+      rebase_path(android_readelf, root_build_dir),
+    ]
+  }
+
+  final_deps += [ ":${template_name}__copy_libraries_and_exe" ]
+  copy_ex("${template_name}__copy_libraries_and_exe") {
+    clear_dir = true
+    inputs = [
+      binary,
+      libraries_list,
+    ]
+    dest = dist_dir
+    rebased_binaries_list = rebase_path([ binary ], root_build_dir)
+    rebased_libraries_list = rebase_path(libraries_list, root_build_dir)
+    args = [
+      "--files=$rebased_binaries_list",
+      "--files=@FileArg($rebased_libraries_list:libraries)",
+    ]
+  }
+
+  group(target_name) {
+    deps = final_deps
+  }
+}
+
+# Compile a protocol buffer to java.
+#
+# This generates java files from protocol buffers and creates an Android library
+# containing the classes.
+#
+# Variables
+#   sources: Paths to .proto files to compile.
+#   proto_path: Root directory of .proto files.
+#
+# Example:
+#  proto_java_library("foo_proto_java") {
+#    proto_path = [ "src/foo" ]
+#    sources = [ "$proto_path/foo.proto" ]
+#  }
+template("proto_java_library") {
+  set_sources_assignment_filter([])
+  _protoc_dep = "//third_party/android_protobuf:android_protoc($host_toolchain)"
+  _protoc_out_dir = get_label_info(_protoc_dep, "root_out_dir")
+  _protoc_bin = "$_protoc_out_dir/android_protoc"
+  _proto_path = invoker.proto_path
+
+  _template_name = target_name
+
+  action("${_template_name}__protoc_java") {
+    srcjar_path = "$target_gen_dir/$target_name.srcjar"
+    script = "//build/protoc_java.py"
+    deps = [
+      _protoc_dep,
+    ]
+    sources = invoker.sources
+    depfile = "$target_gen_dir/$target_name.d"
+    outputs = [
+      depfile,
+      srcjar_path,
+    ]
+    args = [
+             "--depfile",
+             rebase_path(depfile, root_build_dir),
+             "--protoc",
+             rebase_path(_protoc_bin, root_build_dir),
+             "--proto-path",
+             rebase_path(_proto_path, root_build_dir),
+             "--srcjar",
+             rebase_path(srcjar_path, root_build_dir),
+           ] + rebase_path(sources, root_build_dir)
+  }
+
+  android_library(target_name) {
+    java_files = []
+    srcjar_deps = [ ":${_template_name}__protoc_java" ]
+    deps = [
+      "//third_party/android_protobuf:protobuf_nano_javalib",
+    ]
+  }
+}
+
+# TODO(GYP): implement this.
+template("uiautomator_test") {
+  set_sources_assignment_filter([])
+  if (defined(invoker.testonly)) {
+    testonly = invoker.testonly
+  }
+  assert(target_name != "")
+  assert(invoker.deps != [] || true)
+  group(target_name) {
+  }
+}
diff --git a/build/config/arm.gni b/build/config/arm.gni
new file mode 100644
index 0000000..778ecc1
--- /dev/null
+++ b/build/config/arm.gni
@@ -0,0 +1,67 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (current_cpu == "arm") {
+  declare_args() {
+    # Version of the ARM processor when compiling on ARM. Ignored on non-ARM
+    # platforms.
+    arm_version = 7
+
+    # The ARM floating point mode. This is either the string "hard", "soft", or
+    # "softfp". An empty string means to use the default one for the
+    # arm_version.
+    arm_float_abi = ""
+
+    # The ARM variant-specific tuning mode. This will be a string like "armv6"
+    # or "cortex-a15". An empty string means to use the default for the
+    # arm_version.
+    arm_tune = ""
+
+    # Whether to use the neon FPU instruction set or not.
+    arm_use_neon = true
+
+    # Whether to enable optional NEON code paths.
+    arm_optionally_use_neon = false
+
+    if (is_android) {
+      arm_use_neon = false
+      arm_optionally_use_neon = true
+    }
+  }
+
+  assert(arm_float_abi == "" || arm_float_abi == "hard" ||
+         arm_float_abi == "soft" || arm_float_abi == "softfp")
+
+  if (arm_version == 6) {
+    arm_arch = "armv6"
+    if (arm_tune != "") {
+      arm_tune = ""
+    }
+    if (arm_float_abi == "") {
+      arm_float_abi = "softfp"
+    }
+    arm_fpu = "vfp"
+
+    # Thumb is a reduced instruction set available on some ARM processors that
+    # has increased code density.
+    arm_use_thumb = false
+  } else if (arm_version == 7) {
+    arm_arch = "armv7-a"
+    if (arm_tune == "") {
+      arm_tune = "generic-armv7-a"
+    }
+
+    if (arm_float_abi == "") {
+      arm_float_abi = "softfp"
+    }
+
+    arm_use_thumb = true
+
+    if (arm_use_neon) {
+      arm_fpu = "neon"
+    } else {
+      arm_fpu = "vfpv3-d16"
+    }
+  }
+}
diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni
new file mode 100644
index 0000000..e2ff123
--- /dev/null
+++ b/build/config/chrome_build.gni
@@ -0,0 +1,22 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # Selects the desired build flavor. Official builds get additional
+  # processing to prepare for release. Normally you will want to develop and
+  # test with this flag off.
+  # TODO(brettw) move here from BUILDCONFIG.gn when DEPS are updated.
+  #is_official_build = false
+
+  # Select the desired branding flavor. False means normal Chromium branding,
+  # true means official Google Chrome branding (requires extra Google-internal
+  # resources).
+  # TODO(brettw) move here from BUILDCONFIG.gn when DEPS are updated.
+  #is_chrome_branded = false
+
+  # Break chrome.dll into multple pieces based on process type. Only available
+  # on Windows.
+  # TODO(brettw) make this work. When it does, the declaration should be:
+  is_multi_dll_chrome = is_win && !is_component_build
+}
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
new file mode 100644
index 0000000..e79a7b9
--- /dev/null
+++ b/build/config/clang/BUILD.gn
@@ -0,0 +1,62 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("clang.gni")
+
+config("find_bad_constructs") {
+  if (clang_use_chrome_plugins) {
+    cflags = []
+
+    # On Windows, the plugin is built directly into clang, so there's
+    # no need to load it dynamically.
+
+    if (is_mac || is_ios) {
+      cflags += [
+        "-Xclang",
+        "-load",
+        "-Xclang",
+        rebase_path(
+            "//third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.dylib",
+            root_build_dir),
+      ]
+    } else if (is_linux) {
+      cflags += [
+        "-Xclang",
+        "-load",
+        "-Xclang",
+        rebase_path(
+            "//third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.so",
+            root_build_dir),
+      ]
+    }
+
+    if (is_win) {
+      # Don't error on plugin warnings on Windows until pre-existing warnings
+      # are cleaned up.  https://crbug.com/467287
+      cflags += [
+        "-Xclang",
+        "-plugin-arg-find-bad-constructs",
+        "-Xclang warn-only",
+      ]
+    }
+
+    cflags += [
+      "-Xclang",
+      "-add-plugin",
+      "-Xclang",
+      "find-bad-constructs",
+    ]
+  }
+}
+
+# Enables some extra Clang-specific warnings. Some third-party code won't
+# compile with these so may want to remove this config.
+config("extra_warnings") {
+  cflags = [
+    "-Wheader-hygiene",
+
+    # Warns when a const char[] is converted to bool.
+    "-Wstring-conversion",
+  ]
+}
diff --git a/build/config/clang/clang.gni b/build/config/clang/clang.gni
new file mode 100644
index 0000000..cb84879
--- /dev/null
+++ b/build/config/clang/clang.gni
@@ -0,0 +1,9 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # Indicates if the build should use the Chrome-specific plugins for enforcing
+  # coding guidelines, etc. Only used when compiling with Clang.
+  clang_use_chrome_plugins = is_clang && !is_nacl
+}
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
new file mode 100644
index 0000000..9ebb2e7
--- /dev/null
+++ b/build/config/compiler/BUILD.gn
@@ -0,0 +1,1096 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/config.gni")
+import("//build/config/chrome_build.gni")
+if (current_cpu == "arm") {
+  import("//build/config/arm.gni")
+}
+if (current_cpu == "mipsel" || current_cpu == "mips64el") {
+  import("//build/config/mips.gni")
+}
+if (is_posix) {
+  import("//build/config/gcc/gcc_version.gni")
+}
+
+import("//build/toolchain/ccache.gni")
+
+declare_args() {
+  # Normally, Android builds are lightly optimized, even for debug builds, to
+  # keep binary size down. Setting this flag to true disables such optimization
+  android_full_debug = false
+
+  # Whether to use the binary binutils checked into third_party/binutils.
+  # These are not multi-arch so cannot be used except on x86 and x86-64 (the
+  # only two architectures that are currently checked in). Turn this off when
+  # you are using a custom toolchain and need to control -B in cflags.
+  linux_use_bundled_binutils = is_linux && current_cpu == "x64"
+
+  # Compile in such a way as to enable profiling of the generated code. For
+  # example, don't omit the frame pointer and leave in symbols.
+  enable_profiling = false
+
+  # Compile in such a way as to make it possible for the profiler to unwind full
+  # stack frames. Setting this flag has a large effect on the performance of the
+  # generated code than just setting profiling, but gives the profiler more
+  # information to analyze.
+  # Requires profiling to be set to true.
+  enable_full_stack_frames_for_profiling = false
+
+  # Use gold for linking on 64-bit Linux only (on 32-bit it runs out of
+  # address space, and it doesn't support cross-compiling).
+  use_gold = is_linux && current_cpu == "x64"
+
+  # use_debug_fission: whether to use split DWARF debug info
+  # files. This can reduce link time significantly, but is incompatible
+  # with some utilities such as icecc and ccache. Requires gold and
+  # gcc >= 4.8 or clang.
+  # http://gcc.gnu.org/wiki/DebugFission
+  use_debug_fission =
+      !is_win && use_gold && linux_use_bundled_binutils && !use_ccache
+
+  if (is_win) {
+    # Whether the VS xtree header has been patched to disable warning 4702. If
+    # it has, then we don't need to disable 4702 (unreachable code warning).
+    # The patch is preapplied to the internal toolchain and hence all bots.
+    msvs_xtree_patched = false
+  }
+}
+
+# default_include_dirs ---------------------------------------------------------
+#
+# This is a separate config so that third_party code (which would not use the
+# source root and might have conflicting versions of some headers) can remove
+# this and specify their own include paths.
+config("default_include_dirs") {
+  include_dirs = [
+    "//",
+    root_gen_dir,
+  ]
+}
+
+# TODO(GYP): is_ubsan, is_ubsan_vptr
+if (!is_win) {
+  using_sanitizer = is_asan || is_lsan || is_tsan || is_msan
+}
+
+# compiler ---------------------------------------------------------------------
+#
+# Base compiler configuration.
+#
+# See also "runtime_library" below for related stuff and a discussion about
+# where stuff should go. Put warning related stuff in the "warnings" config.
+
+config("compiler") {
+  cflags = []
+  cflags_c = []
+  cflags_cc = []
+  ldflags = []
+  defines = []
+
+  # In general, Windows is totally different, but all the other builds share
+  # some common GCC configuration. This section sets up Windows and the common
+  # GCC flags, and then we handle the other non-Windows platforms specifically
+  # below.
+  if (is_win) {
+    # Windows compiler flags setup.
+    # -----------------------------
+    cflags += [
+      "/Gy",  # Enable function-level linking.
+      "/GS",  # Enable buffer security checking.
+      "/FS",  # Preserve previous PDB behavior.
+    ]
+  } else {
+    # Common GCC compiler flags setup.
+    # --------------------------------
+    cflags += [ "-fno-strict-aliasing" ]  # See http://crbug.com/32204
+    cflags_cc += [
+      "-fno-threadsafe-statics",
+
+      # Not exporting C++ inline functions can generally be applied anywhere
+      # so we do so here. Normal function visibility is controlled by
+      # //build/config/gcc:symbol_visibility_hidden.
+      "-fvisibility-inlines-hidden",
+    ]
+
+    # Stack protection.
+    if (is_mac) {
+      cflags += [ "-fstack-protector-all" ]
+    } else if (is_linux) {
+      cflags += [
+        "-fstack-protector",
+        "--param=ssp-buffer-size=4",
+      ]
+    }
+
+    # Linker warnings.
+    if (!(is_chromeos && current_cpu == "arm") && !is_mac) {
+      # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
+      ldflags += [ "-Wl,--fatal-warnings" ]
+    }
+
+    # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer and
+    # MemorySanitizer
+    if (using_sanitizer) {
+      cflags += [
+        "-fno-omit-frame-pointer",
+        "-gline-tables-only",
+      ]
+    }
+    if (is_asan) {
+      cflags += [ "-fsanitize=address" ]
+      if (is_mac) {
+        cflags += [ "-mllvm -asan-globals=0" ]  # http://crbug.com/352073
+        # TODO(GYP): deal with mac_bundles.
+      }
+    }
+  }
+
+  if (is_clang && is_debug) {
+    # Allow comparing the address of references and 'this' against 0
+    # in debug builds. Technically, these can never be null in
+    # well-defined C/C++ and Clang can optimize such checks away in
+    # release builds, but they may be used in asserts in debug builds.
+    cflags_cc += [
+      "-Wno-undefined-bool-conversion",
+      "-Wno-tautological-undefined-compare",
+    ]
+  }
+
+  if (is_clang && !is_nacl) {
+    # This is here so that all files get recompiled after a clang roll and
+    # when turning clang on or off. (defines are passed via the command line,
+    # and build system rebuild things when their commandline changes). Nothing
+    # should ever read this define.
+    defines +=
+        [ "CR_CLANG_REVISION=" + exec_script("//tools/clang/scripts/update.py",
+                                             [ "--print-revision" ],
+                                             "trim string") ]
+  }
+
+  # Mac-specific compiler flags setup.
+  # ----------------------------------
+  if (is_mac || is_ios) {
+    # These flags are shared between the C compiler and linker.
+    common_mac_flags = []
+
+    # CPU architecture.
+    if (current_cpu == "x64") {
+      common_mac_flags += [
+        "-arch",
+        "x86_64",
+      ]
+    } else if (current_cpu == "x86") {
+      common_mac_flags += [
+        "-arch",
+        "i386",
+      ]
+    }
+
+    cflags += common_mac_flags
+
+    # Without this, the constructors and destructors of a C++ object inside
+    # an Objective C struct won't be called, which is very bad.
+    cflags_objcc = [ "-fobjc-call-cxx-cdtors" ]
+
+    cflags_c += [ "-std=c99" ]
+
+    ldflags += common_mac_flags
+  } else if (is_posix) {
+    # Non-Mac Posix compiler flags setup.
+    # -----------------------------------
+    if (enable_profiling && !is_debug) {
+      # The GYP build spams this define into every compilation unit, as we do
+      # here, but it only appears to be used in base and a couple other places.
+      # TODO(abarth): Should we move this define closer to where it's used?
+      defines += [ "ENABLE_PROFILING" ]
+
+      cflags += [
+        "-fno-omit-frame-pointer",
+        "-g",
+      ]
+
+      if (enable_full_stack_frames_for_profiling) {
+        cflags += [
+          "-fno-inline",
+          "-fno-optimize-sibling-calls",
+        ]
+      }
+    }
+
+    # CPU architecture. We may or may not be doing a cross compile now, so for
+    # simplicity we always explicitly set the architecture.
+    if (current_cpu == "x64") {
+      cflags += [
+        "-m64",
+        "-march=x86-64",
+      ]
+      ldflags += [ "-m64" ]
+    } else if (current_cpu == "x86") {
+      cflags += [ "-m32" ]
+      ldflags += [ "-m32" ]
+      if (is_clang) {
+        cflags += [
+          # Else building libyuv gives clang's register allocator issues,
+          # see llvm.org/PR15798 / crbug.com/233709
+          "-momit-leaf-frame-pointer",
+
+          # Align the stack on 16-byte boundaries, http://crbug.com/418554.
+          "-mstack-alignment=16",
+          "-mstackrealign",
+        ]
+      }
+    } else if (current_cpu == "arm") {
+      cflags += [
+        "-march=$arm_arch",
+        "-mfloat-abi=$arm_float_abi",
+      ]
+      if (arm_tune != "") {
+        cflags += [ "-mtune=$arm_tune" ]
+      }
+      if (arm_use_thumb) {
+        cflags += [ "-mthumb" ]
+        if (is_android && !is_clang) {  # Clang doesn't support this option.
+          cflags += [ "-mthumb-interwork" ]
+        }
+      }
+      if (!is_clang) {
+        # Clang doesn't support these flags.
+        cflags += [
+          # The tree-sra optimization (scalar replacement for
+          # aggregates enabling subsequent optimizations) leads to
+          # invalid code generation when using the Android NDK's
+          # compiler (r5-r7). This can be verified using
+          # webkit_unit_tests' WTF.Checked_int8_t test.
+          "-fno-tree-sra",
+
+          # The following option is disabled to improve binary
+          # size and performance in gcc 4.9.
+          "-fno-caller-saves",
+        ]
+      }
+    } else if (current_cpu == "mipsel") {
+      if (mips_arch_variant == "r6") {
+        cflags += [
+          "-mips32r6",
+          "-Wa,-mips32r6",
+        ]
+        if (is_android) {
+          ldflags += [
+            "-mips32r6",
+            "-Wl,-melf32ltsmip",
+          ]
+        }
+      } else if (mips_arch_variant == "r2") {
+        cflags += [
+          "-mips32r2",
+          "-Wa,-mips32r2",
+        ]
+        if (mips_float_abi == "hard" && mips_fpu_mode != "") {
+          cflags += [ "-m$mips_fpu_mode" ]
+        }
+      } else if (mips_arch_variant == "r1") {
+        cflags += [
+          "-mips32",
+          "-Wa,-mips32",
+        ]
+      }
+
+      if (mips_dsp_rev == 1) {
+        cflags += [ "-mdsp" ]
+      } else if (mips_dsp_rev == 2) {
+        cflags += [ "-mdspr2" ]
+      }
+
+      cflags += [ "-m${mips_float_abi}-float" ]
+    } else if (current_cpu == "mips64el") {
+      if (mips_arch_variant == "r6") {
+        cflags += [
+          "-mips64r6",
+          "-Wa,-mips64r6",
+        ]
+        ldflags += [ "-mips64r6" ]
+      } else if (mips_arch_variant == "r2") {
+        cflags += [
+          "-mips64r2",
+          "-Wa,-mips64r2",
+        ]
+        ldflags += [ "-mips64r2" ]
+      }
+    }
+
+    defines += [ "_FILE_OFFSET_BITS=64" ]
+
+    if (!is_android) {
+      defines += [
+        "_LARGEFILE_SOURCE",
+        "_LARGEFILE64_SOURCE",
+      ]
+    }
+
+    # Omit unwind support in official builds to save space. We can use breakpad
+    # for these builds.
+    if (is_chrome_branded && is_official_build) {
+      cflags += [
+        "-fno-unwind-tables",
+        "-fno-asynchronous-unwind-tables",
+      ]
+    } else {
+      cflags += [ "-funwind-tables" ]
+    }
+  }
+
+  # Linux/Android common flags setup.
+  # ---------------------------------
+  if (is_linux || is_android) {
+    cflags += [
+      "-fPIC",
+      "-pipe",  # Use pipes for communicating between sub-processes. Faster.
+    ]
+
+    ldflags += [
+      "-fPIC",
+      "-Wl,-z,noexecstack",
+      "-Wl,-z,now",
+      "-Wl,-z,relro",
+    ]
+    if (!using_sanitizer) {
+      ldflags += [ "-Wl,-z,defs" ]
+    }
+  }
+
+  # Linux-specific compiler flags setup.
+  # ------------------------------------
+  if (is_linux) {
+    cflags += [ "-pthread" ]
+    ldflags += [ "-pthread" ]
+  }
+  if (use_gold) {
+    gold_path = rebase_path("//third_party/binutils/Linux_x64/Release/bin",
+                            root_build_dir)
+    ldflags += [
+      "-B$gold_path",
+
+      # Newer gccs and clangs support -fuse-ld, use the flag to force gold
+      # selection.
+      # gcc -- http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Optimize-Options.html
+      "-fuse-ld=gold",
+
+      # TODO(brettw) common.gypi has this only for target toolset.
+      "-Wl,--icf=safe",
+
+      # Experimentation found that using four linking threads
+      # saved ~20% of link time.
+      # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
+      # Only apply this to the target linker, since the host
+      # linker might not be gold, but isn't used much anyway.
+      # TODO(raymes): Disable threading because gold is frequently
+      # crashing on the bots: crbug.com/161942.
+      #"-Wl,--threads",
+      #"-Wl,--thread-count=4",
+    ]
+
+    # TODO(thestig): Make this flag work with GN.
+    #if (!is_official_build && !is_chromeos && !(is_asan || is_lsan || is_tsan || is_msan)) {
+    #  ldflags += [
+    #    "-Wl,--detect-odr-violations",
+    #  ]
+    #}
+  }
+
+  if (linux_use_bundled_binutils) {
+    binutils_path = rebase_path("//third_party/binutils/Linux_x64/Release/bin",
+                                root_build_dir)
+    cflags += [ "-B$binutils_path" ]
+  }
+
+  # Clang-specific compiler flags setup.
+  # ------------------------------------
+  if (is_clang) {
+    cflags += [ "-fcolor-diagnostics" ]
+  }
+
+  # C++11 compiler flags setup.
+  # ---------------------------
+  if (is_linux || is_android || is_nacl) {
+    # gnu++11 instead of c++11 is needed because some code uses typeof() (a
+    # GNU extension).
+    # TODO(thakis): Eventually switch this to c++11 instead,
+    # http://crbug.com/427584
+    cflags_cc += [ "-std=gnu++11" ]
+  } else if (!is_win) {
+    cflags_cc += [ "-std=c++11" ]
+  }
+
+  # Android-specific flags setup.
+  # -----------------------------
+  if (is_android) {
+    cflags += [
+      "-ffunction-sections",
+      "-funwind-tables",
+      "-fno-short-enums",
+    ]
+    if (!is_clang) {
+      # Clang doesn't support these flags.
+      cflags += [ "-finline-limit=64" ]
+    }
+    if (is_asan) {
+      # Android build relies on -Wl,--gc-sections removing unreachable code.
+      # ASan instrumentation for globals inhibits this and results in a library
+      # with unresolvable relocations.
+      # TODO(eugenis): find a way to reenable this.
+      cflags += [ "-mllvm -asan-globals=0" ]
+    }
+
+    defines += [ "ANDROID" ]
+
+    # The NDK has these things, but doesn't define the constants
+    # to say that it does. Define them here instead.
+    defines += [ "HAVE_SYS_UIO_H" ]
+
+    # Use gold for Android for most CPU architectures.
+    if (current_cpu == "x86" || current_cpu == "x64" || current_cpu == "arm") {
+      ldflags += [ "-fuse-ld=gold" ]
+      if (is_clang) {
+        # Let clang find the ld.gold in the NDK.
+        ldflags += [ "--gcc-toolchain=" +
+                     rebase_path(android_toolchain_root, root_build_dir) ]
+      }
+    }
+
+    ldflags += [
+      "-Wl,--no-undefined",
+
+      # Don't allow visible symbols from libgcc or libc++ to be
+      # re-exported.
+      "-Wl,--exclude-libs=libgcc.a",
+      "-Wl,--exclude-libs=libc++_static.a",
+
+      # Don't allow visible symbols from libraries that contain
+      # assembly code with symbols that aren't hidden properly.
+      # http://crbug.com/448386
+      "-Wl,--exclude-libs=libvpx_assembly_arm.a",
+    ]
+    if (current_cpu == "arm") {
+      ldflags += [
+        # Enable identical code folding to reduce size.
+        "-Wl,--icf=safe",
+      ]
+    }
+
+    if (is_clang) {
+      if (current_cpu == "arm") {
+        cflags += [ "-target arm-linux-androideabi" ]
+        ldflags += [ "-target arm-linux-androideabi" ]
+      } else if (current_cpu == "x86") {
+        cflags += [ "-target x86-linux-androideabi" ]
+        ldflags += [ "-target x86-linux-androideabi" ]
+      }
+    }
+  }
+}
+
+config("compiler_arm_fpu") {
+  if (current_cpu == "arm") {
+    cflags = [ "-mfpu=$arm_fpu" ]
+  }
+}
+
+# runtime_library -------------------------------------------------------------
+#
+# Sets the runtime library and associated options.
+#
+# How do you determine what should go in here vs. "compiler" above? Consider if
+# a target might choose to use a different runtime library (ignore for a moment
+# if this is possible or reasonable on your system). If such a target would want
+# to change or remove your option, put it in the runtime_library config. If a
+# target wants the option regardless, put it in the compiler config.
+
+config("runtime_library") {
+  cflags = []
+  defines = []
+  ldflags = []
+  lib_dirs = []
+  libs = []
+
+  if (is_component_build) {
+    # Component mode: dynamic CRT.
+    defines += [ "COMPONENT_BUILD" ]
+    if (is_win) {
+      # Since the library is shared, it requires exceptions or will give errors
+      # about things not matching, so keep exceptions on.
+      if (is_debug) {
+        cflags += [ "/MDd" ]
+      } else {
+        cflags += [ "/MD" ]
+      }
+    }
+  } else {
+    # Static CRT.
+    if (is_win) {
+      if (is_debug) {
+        cflags += [ "/MTd" ]
+      } else {
+        cflags += [ "/MT" ]
+      }
+    }
+  }
+
+  if (is_win) {
+    defines += [
+      "__STD_C",
+      "_CRT_RAND_S",
+      "_CRT_SECURE_NO_DEPRECATE",
+      "_HAS_EXCEPTIONS=0",
+      "_SCL_SECURE_NO_DEPRECATE",
+    ]
+  }
+
+  # Android standard library setup.
+  if (is_android) {
+    if (is_clang) {
+      # Work around incompatibilities between bionic and clang headers.
+      defines += [
+        "__compiler_offsetof=__builtin_offsetof",
+        "nan=__builtin_nan",
+      ]
+    }
+
+    defines += [ "__GNU_SOURCE=1" ]  # Necessary for clone().
+
+    # TODO(jdduke) Re-enable on mips after resolving linking
+    # issues with libc++ (crbug.com/456380).
+    if (current_cpu != "mipsel" && current_cpu != "mips64el") {
+      ldflags += [ "-Wl,--warn-shared-textrel" ]
+    }
+    ldflags += [ "-nostdlib" ]
+
+    # NOTE: The libc++ header include paths below are specified in cflags
+    # rather than include_dirs because they need to come after include_dirs.
+    # Think of them like system headers, but don't use '-isystem' because the
+    # arm-linux-androideabi-4.4.3 toolchain (circa Gingerbread) will exhibit
+    # strange errors. The include ordering here is important; change with
+    # caution.
+    android_libcpp_root = "$android_ndk_root/sources/cxx-stl/llvm-libc++"
+
+    cflags += [
+      "-isystem" +
+          rebase_path("$android_libcpp_root/libcxx/include", root_build_dir),
+      "-isystem" + rebase_path(
+              "$android_ndk_root/sources/cxx-stl/llvm-libc++abi/libcxxabi/include",
+              root_build_dir),
+      "-isystem" +
+          rebase_path("$android_ndk_root/sources/android/support/include",
+                      root_build_dir),
+    ]
+
+    lib_dirs += [ "$android_libcpp_root/libs/$android_app_abi" ]
+
+    if (component_mode == "shared_library") {
+      android_libcpp_library = "c++_shared"
+    } else {
+      android_libcpp_library = "c++_static"
+    }
+
+    libs += [
+      "$android_libcpp_library",
+
+      # Manually link the libgcc.a that the cross compiler uses. This is
+      # absolute because the linker will look inside the sysroot if it's not.
+      rebase_path(android_libgcc_file),
+      "c",
+      "dl",
+      "m",
+    ]
+
+    # Clang with libc++ does not require an explicit atomic library reference.
+    if (!is_clang) {
+      libs += [ "atomic" ]
+    }
+  }
+}
+
+# chromium_code ---------------------------------------------------------------
+#
+# Toggles between higher and lower warnings for code that is (or isn't)
+# part of Chromium.
+
+config("chromium_code") {
+  if (is_win) {
+    cflags = [ "/W4" ]  # Warning level 4.
+  } else {
+    cflags = [
+      "-Wall",
+
+      # GCC turns on -Wsign-compare for C++ under -Wall, but clang doesn't,
+      # so we specify it explicitly.
+      # TODO(fischman): remove this if http://llvm.org/PR10448 obsoletes it.
+      # http://code.google.com/p/chromium/issues/detail?id=90453
+      "-Wsign-compare",
+    ]
+
+    # In Chromium code, we define __STDC_foo_MACROS in order to get the
+    # C99 macros on Mac and Linux.
+    defines = [
+      "__STDC_CONSTANT_MACROS",
+      "__STDC_FORMAT_MACROS",
+    ]
+  }
+}
+config("no_chromium_code") {
+  cflags = []
+  cflags_cc = []
+  defines = []
+
+  if (is_win) {
+    cflags += [
+      "/W3",  # Warning level 3.
+      "/wd4800",  # Disable warning when forcing value to bool.
+      "/wd4267",  # TODO(jschuh): size_t to int.
+      "/wd4996",  # Deprecated function warning.
+    ]
+    defines += [
+      "_CRT_NONSTDC_NO_WARNINGS",
+      "_CRT_NONSTDC_NO_DEPRECATE",
+    ]
+  }
+
+  if (is_linux) {
+    # Don't warn about ignoring the return value from e.g. close(). This is
+    # off by default in some gccs but on by default in others. BSD systems do
+    # not support this option, since they are usually using gcc 4.2.1, which
+    # does not have this flag yet.
+    cflags += [ "-Wno-unused-result" ]
+  }
+
+  if (is_linux || is_android) {
+    cflags += [
+      # Don't warn about printf format problems. This is off by default in gcc
+      # but on in Ubuntu's gcc(!).
+      "-Wno-format",
+    ]
+    cflags_cc += [
+      # Don't warn about hash_map in third-party code.
+      "-Wno-deprecated",
+    ]
+  }
+}
+
+# rtti ------------------------------------------------------------------------
+#
+# Allows turning Run-Time Type Identification on or off.
+
+config("rtti") {
+  if (is_win) {
+    cflags_cc = [ "/GR" ]
+  }
+}
+config("no_rtti") {
+  if (is_win) {
+    cflags_cc = [ "/GR-" ]
+  } else {
+    cflags_cc = [ "-fno-rtti" ]
+  }
+}
+
+# Warnings ---------------------------------------------------------------------
+#
+# This is where we disable various warnings that we've decided aren't
+# worthwhile, and enable special warnings.
+
+config("default_warnings") {
+  if (is_win) {
+    cflags = [
+      "/WX",  # Treat warnings as errors.
+
+      # Warnings permanently disabled:
+
+      # TODO(GYP) The GYP build doesn't have this globally enabled but disabled
+      # for a bunch of individual targets. Re-enable this globally when those
+      # targets are fixed.
+      "/wd4018",  # Comparing signed and unsigned values.
+
+      # C4127: conditional expression is constant
+      # This warning can in theory catch dead code and other problems, but
+      # triggers in far too many desirable cases where the conditional
+      # expression is either set by macros or corresponds some legitimate
+      # compile-time constant expression (due to constant template args,
+      # conditionals comparing the sizes of different types, etc.).  Some of
+      # these can be worked around, but it's not worth it.
+      "/wd4127",
+
+      # C4251: 'identifier' : class 'type' needs to have dll-interface to be
+      #        used by clients of class 'type2'
+      # This is necessary for the shared library build.
+      "/wd4251",
+
+      # C4351: new behavior: elements of array 'array' will be default
+      #        initialized
+      # This is a silly "warning" that basically just alerts you that the
+      # compiler is going to actually follow the language spec like it's
+      # supposed to, instead of not following it like old buggy versions did.
+      # There's absolutely no reason to turn this on.
+      "/wd4351",
+
+      # C4355: 'this': used in base member initializer list
+      # It's commonly useful to pass |this| to objects in a class' initializer
+      # list.  While this warning can catch real bugs, most of the time the
+      # constructors in question don't attempt to call methods on the passed-in
+      # pointer (until later), and annotating every legit usage of this is
+      # simply more hassle than the warning is worth.
+      "/wd4355",
+
+      # C4503: 'identifier': decorated name length exceeded, name was
+      #        truncated
+      # This only means that some long error messages might have truncated
+      # identifiers in the presence of lots of templates.  It has no effect on
+      # program correctness and there's no real reason to waste time trying to
+      # prevent it.
+      "/wd4503",
+
+      # C4611: interaction between 'function' and C++ object destruction is
+      #        non-portable
+      # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
+      # suggests using exceptions instead of setjmp/longjmp for C++, but
+      # Chromium code compiles without exception support.  We therefore have to
+      # use setjmp/longjmp for e.g. JPEG decode error handling, which means we
+      # have to turn off this warning (and be careful about how object
+      # destruction happens in such cases).
+      "/wd4611",
+
+      # Warnings to evaluate and possibly fix/reenable later:
+
+      "/wd4100",  # Unreferenced formal function parameter.
+      "/wd4121",  # Alignment of a member was sensitive to packing.
+      "/wd4244",  # Conversion: possible loss of data.
+      "/wd4481",  # Nonstandard extension: override specifier.
+      "/wd4505",  # Unreferenced local function has been removed.
+      "/wd4510",  # Default constructor could not be generated.
+      "/wd4512",  # Assignment operator could not be generated.
+      "/wd4610",  # Class can never be instantiated, constructor required.
+      "/wd4996",  # Deprecated function warning.
+    ]
+
+    # VS xtree header file needs to be patched or 4702 (unreachable code
+    # warning) is reported if _HAS_EXCEPTIONS=0. Disable the warning if xtree is
+    # not patched.
+    if (!msvs_xtree_patched &&
+        exec_script("../../win_is_xtree_patched.py", [], "value") == 0) {
+      cflags += [ "/wd4702" ]  # Unreachable code.
+    }
+  } else {
+    # Common GCC warning setup.
+    cflags = [
+      # Enables.
+      "-Wendif-labels",  # Weird old-style text after an #endif.
+      "-Werror",  # Warnings as errors.
+
+      # Disables.
+      "-Wno-missing-field-initializers",  # "struct foo f = {0};"
+      "-Wno-unused-parameter",  # Unused function parameters.
+    ]
+    cflags_cc = []
+
+    if (is_mac) {
+      cflags += [ "-Wnewline-eof" ]
+    }
+
+    if (is_clang) {
+      cflags += [
+        # This warns on using ints as initializers for floats in
+        # initializer lists (e.g. |int a = f(); CGSize s = { a, a };|),
+        # which happens in several places in chrome code. Not sure if
+        # this is worth fixing.
+        "-Wno-c++11-narrowing",
+
+        # Don't die on dtoa code that uses a char as an array index.
+        # This is required solely for base/third_party/dmg_fp/dtoa.cc.
+        # TODO(brettw) move this to that project then!
+        "-Wno-char-subscripts",
+
+        # Warns on switches on enums that cover all enum values but
+        # also contain a default: branch. Chrome is full of that.
+        "-Wno-covered-switch-default",
+
+        # Clang considers the `register` keyword as deprecated, but e.g.
+        # code generated by flex (used in angle) contains that keyword.
+        # http://crbug.com/255186
+        "-Wno-deprecated-register",
+
+        # TODO(thakis): This used to be implied by -Wno-unused-function,
+        # which we no longer use. Check if it makes sense to remove
+        # this as well. http://crbug.com/316352
+        "-Wno-unneeded-internal-declaration",
+
+        # TODO(thakis): Remove, http://crbug.com/263960
+        "-Wno-reserved-user-defined-literal",
+      ]
+
+      # NaCl's Clang compiler and Chrome's hermetic Clang compiler will almost
+      # always have different versions. Certain flags may not be recognized by
+      # one version or the other.
+      if (!is_nacl) {
+        # Flags NaCl does not recognize.
+        cflags += [
+          # TODO(hans): Get this cleaned up.
+          "-Wno-inconsistent-missing-override",
+        ]
+      }
+    }
+    if (gcc_version >= 48) {
+      cflags_cc += [
+        # See comment for -Wno-c++11-narrowing.
+        "-Wno-narrowing",
+
+        # TODO(thakis): Remove, http://crbug.com/263960
+        "-Wno-literal-suffix",
+      ]
+    }
+
+    # Suppress warnings about ABI changes on ARM (Clang doesn't give this
+    # warning).
+    if (current_cpu == "arm" && !is_clang) {
+      cflags += [ "-Wno-psabi" ]
+    }
+
+    if (is_android) {
+      # Disable any additional warnings enabled by the Android build system but
+      # which chromium does not build cleanly with (when treating warning as
+      # errors).
+      cflags += [
+        "-Wno-extra",
+        "-Wno-ignored-qualifiers",
+        "-Wno-type-limits",
+      ]
+      cflags_cc += [
+        # Disabling c++0x-compat should be handled in WebKit, but
+        # this currently doesn't work because gcc_version is not set
+        # correctly when building with the Android build system.
+        # TODO(torne): Fix this in WebKit.
+        "-Wno-error=c++0x-compat",
+
+        # Other things unrelated to -Wextra:
+        "-Wno-non-virtual-dtor",
+        "-Wno-sign-promo",
+      ]
+    }
+
+    if (gcc_version >= 48) {
+      # Don't warn about the "typedef 'foo' locally defined but not used"
+      # for gcc 4.8.
+      # TODO: remove this flag once all builds work. See crbug.com/227506
+      cflags += [ "-Wno-unused-local-typedefs" ]
+    }
+  }
+}
+
+# This will generate warnings when using Clang if code generates exit-time
+# destructors, which will slow down closing the program.
+# TODO(thakis): Make this a blacklist instead, http://crbug.com/101600
+config("wexit_time_destructors") {
+  if (is_clang) {
+    cflags = [ "-Wexit-time-destructors" ]
+  }
+}
+
+# On Windows compiling on x64, VC will issue a warning when converting
+# size_t to int because it will truncate the value. Our code should not have
+# these warnings and one should use a static_cast or a checked_cast for the
+# conversion depending on the case. However, a lot of code still needs to be
+# fixed. Apply this config to such targets to disable the warning.
+#
+# Note that this can be applied regardless of platform and architecture to
+# clean up the call sites. This will only apply the flag when necessary.
+#
+# TODO(jschuh): crbug.com/167187 fix this and delete this config.
+config("no_size_t_to_int_warning") {
+  if (is_win && current_cpu == "x64") {
+    cflags = [ "/wd4267" ]
+  }
+}
+
+# Optimization -----------------------------------------------------------------
+#
+# Note that BUILDCONFIG.gn sets up a variable "default_optimization_config"
+# which it will assign to the config it implicitly applies to every target. If
+# you want to override the optimization level for your target, remove this
+# config (which will expand differently for debug or release builds), and then
+# add back the one you want to override it with:
+#
+#   configs -= default_optimization_config
+#   configs += [ "//build/config/compiler/optimize_max" ]
+
+# Shared settings for both "optimize" and "optimize_max" configs.
+if (is_win) {
+  common_optimize_on_cflags = [
+    "/O2",
+    "/Ob2",  # both explicit and auto inlining.
+    "/Oy-",  # disable omitting frame pointers, must be after /o2.
+    "/Os",  # favor size over speed.
+  ]
+  if (!is_asan) {
+    common_optimize_on_cflags += [
+      # Put data in separate COMDATs. This allows the linker
+      # to put bit-identical constants at the same address even if
+      # they're unrelated constants, which saves binary size.
+      # This optimization can't be used when ASan is enabled because
+      # it is not compatible with the ASan ODR checker.
+      "/Gw",
+    ]
+  }
+  common_optimize_on_ldflags = [ "/OPT:REF" ]
+} else {
+  common_optimize_on_cflags = [
+    # Don't emit the GCC version ident directives, they just end up in the
+    # .comment section taking up binary size.
+    "-fno-ident",
+
+    # Put data and code in their own sections, so that unused symbols
+    # can be removed at link time with --gc-sections.
+    "-fdata-sections",
+    "-ffunction-sections",
+  ]
+  common_optimize_on_ldflags = []
+
+  if (is_android) {
+    if (!using_sanitizer) {
+      common_optimize_on_cflags += [ "-fomit-frame-pointer" ]
+    }
+
+    # TODO(jdduke) Re-enable on mips after resolving linking
+    # issues with libc++ (crbug.com/456380).
+    if (current_cpu != "mipsel" && current_cpu != "mips64el") {
+      common_optimize_on_ldflags += [
+        # Warn in case of text relocations.
+        "-Wl,--warn-shared-textrel",
+      ]
+    }
+  }
+
+  if (is_mac) {
+    if (symbol_level == 2) {
+      # Mac dead code stripping requires symbols.
+      common_optimize_on_ldflags += [ "-Wl,-dead_strip" ]
+    }
+  } else {
+    # Non-Mac Posix linker flags.
+    common_optimize_on_ldflags += [
+      # Specifically tell the linker to perform optimizations.
+      # See http://lwn.net/Articles/192624/ .
+      "-Wl,-O1",
+      "-Wl,--gc-sections",
+    ]
+
+    if (!using_sanitizer) {
+      # Functions interposed by the sanitizers can make ld think
+      # that some libraries aren't needed when they actually are,
+      # http://crbug.com/234010. As workaround, disable --as-needed.
+      common_optimize_on_ldflags += [ "-Wl,--as-needed" ]
+    }
+  }
+}
+
+# Default "optimization on" config. On Windows, this favors size over speed.
+config("optimize") {
+  cflags = common_optimize_on_cflags
+  ldflags = common_optimize_on_ldflags
+  if (is_win) {
+    cflags += [ "/Os" ]  # favor size over speed.
+  } else if (is_android || is_ios) {
+    cflags += [ "-Os" ]  # Favor size over speed.
+  } else {
+    cflags += [ "-O2" ]
+  }
+}
+
+# Turn off optimizations.
+config("no_optimize") {
+  if (is_win) {
+    cflags = [
+      "/Od",  # Disable optimization.
+      "/Ob0",  # Disable all inlining (on by default).
+      "/RTC1",  # Runtime checks for stack frame and uninitialized variables.
+    ]
+  } else if (is_android && !android_full_debug) {
+    # On Android we kind of optimize some things that don't affect debugging
+    # much even when optimization is disabled to get the binary size down.
+    cflags = [
+      "-Os",
+      "-fdata-sections",
+      "-ffunction-sections",
+    ]
+    if (!using_sanitizer) {
+      cflags += [ "-fomit-frame-pointer" ]
+    }
+    ldflags = common_optimize_on_ldflags
+  } else {
+    cflags = [ "-O0" ]
+  }
+}
+
+# Turns up the optimization level. On Windows, this implies whole program
+# optimization and link-time code generation which is very expensive and should
+# be used sparingly.
+config("optimize_max") {
+  cflags = common_optimize_on_cflags
+  ldflags = common_optimize_on_ldflags
+  if (is_win) {
+    cflags -= [ "/Os" ]
+    cflags += [ "/Ot" ]  # Favor speed over size.
+    if (is_official_build) {
+      # TODO(GYP): TODO(dpranke): Should these only be on in an official
+      # build, or on all the time? For now we'll require official build so
+      # that the compile is clean.
+      cflags += [
+        "/GL",  # Whole program optimization.
+
+        # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds.
+        # Probably anything that this would catch that wouldn't be caught in a
+        # normal build isn't going to actually be a bug, so the incremental
+        # value of C4702 for PGO builds is likely very small.
+        "/wd4702",
+      ]
+      ldflags += [ "/LTCG" ]
+    }
+  } else {
+    cflags += [ "-O2" ]
+  }
+}
+
+# Symbols ----------------------------------------------------------------------
+
+config("symbols") {
+  if (is_win) {
+    import("//build/toolchain/goma.gni")
+    if (use_goma) {
+      cflags = [ "/Z7" ]  # No PDB file
+    } else {
+      cflags = [ "/Zi" ]  # Produce PDB file, no edit and continue.
+    }
+    ldflags = [ "/DEBUG" ]
+  } else {
+    cflags = [ "-g2" ]
+    if (use_debug_fission) {
+      cflags += [ "-gsplit-dwarf" ]
+    }
+  }
+}
+
+config("minimal_symbols") {
+  if (is_win) {
+    # Linker symbols for backtraces only.
+    ldflags = [ "/DEBUG" ]
+  } else {
+    cflags = [ "-g1" ]
+    if (use_debug_fission) {
+      cflags += [ "-gsplit-dwarf" ]
+    }
+  }
+}
+
+config("no_symbols") {
+  if (!is_win) {
+    cflags = [ "-g0" ]
+  }
+}
diff --git a/build/config/crypto.gni b/build/config/crypto.gni
new file mode 100644
index 0000000..7f090b7
--- /dev/null
+++ b/build/config/crypto.gni
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file declares build flags for the SSL library configuration.
+#
+# TODO(brettw) this should probably be moved to src/crypto or somewhere, and
+# the global build dependency on it should be removed.
+
+declare_args() {
+  # Use OpenSSL instead of NSS. This is used for Android, Mac, NaCl untrusted
+  # code, and Windows, and is experimental in other cases (see
+  # http://crbug.com/62803).
+  use_openssl = is_android || is_mac || is_nacl || is_win
+}
+
+# True when we're using OpenSSL for representing certificates. When targeting
+# Android, the platform certificate library is used for certificate
+# verification. On other targets, this flag also enables OpenSSL for certificate
+# verification, but this configuration is unsupported.
+use_openssl_certs = is_android
+
+# True if NSS is used for certificate verification. Note that this is
+# independent from use_openssl. It is possible to use OpenSSL for the crypto
+# library, but NSS for the platform certificate library.
+use_nss_certs = is_linux
diff --git a/build/config/features.gni b/build/config/features.gni
new file mode 100644
index 0000000..3873458
--- /dev/null
+++ b/build/config/features.gni
@@ -0,0 +1,192 @@
+# Copyright 2014 The Chromium 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 UI-related build flags. It should theoretically be in the
+# src/ui directory and only things that depend on the ui module should get the
+# definitions.
+#
+# However, today we have many "bad" dependencies on some of these flags from,
+# e.g. base, so they need to be global.
+#
+# See also build/config/ui.gni
+
+import("//build/config/chrome_build.gni")
+if (is_android) {
+  import("//build/config/android/config.gni")
+}
+
+declare_args() {
+  # Multicast DNS.
+  enable_mdns = is_win || is_linux
+
+  enable_plugins = !is_android && !is_ios
+
+  # Enables Native Client support.
+  # TODO(GYP): Get NaCl linking on other platforms.
+  # Also, see if we can always get rid of enable_nacl_untrusted and
+  # enable_pnacl and always build them if enable_nacl is true.
+  # The "is_nacl" part of the condition is needed to ensure that
+  # the untrusted code is built properly; arguably it should be
+  # guarded by "is_nacl" directly rather than enable_nacl_untrusted, but
+  # this will go away when Mac and Win are working and we can just use
+  # the commented out logic.
+  # Eventually we want this to be:
+  #   enable_nacl = !is_ios && !is_android
+  enable_nacl = (is_linux && !is_chromeos && current_cpu == "x64") || is_nacl
+  enable_nacl_untrusted = enable_nacl
+  enable_pnacl = enable_nacl_untrusted
+
+  # If debug_devtools is set to true, JavaScript files for DevTools are stored
+  # as is and loaded from disk. Otherwise, a concatenated file is stored in
+  # resources.pak. It is still possible to load JS files from disk by passing
+  # --debug-devtools cmdline switch.
+  debug_devtools = false
+
+  # Enables WebRTC.
+  # TODO(GYP) make mac and android work.
+  enable_webrtc = !is_ios && !is_mac && !is_android
+
+  # Enables the Media Router.
+  enable_media_router = !is_ios && !is_android
+
+  # Enables proprietary codecs and demuxers; e.g. H264, MOV, AAC, and MP3.
+  proprietary_codecs = false
+
+  enable_configuration_policy = true
+
+  # Enables support for background apps.
+  enable_background = !is_ios && !is_android
+
+  enable_captive_portal_detection = !is_android && !is_ios
+
+  # Enables use of the session service, which is enabled by default.
+  # Android stores them separately on the Java side.
+  enable_session_service = !is_android && !is_ios
+
+  enable_plugin_installation = is_win || is_mac
+
+  enable_app_list = !is_ios && !is_android
+
+  enable_supervised_users = !is_ios
+
+  enable_autofill_dialog = !is_ios
+
+  enable_google_now = !is_ios && !is_android
+
+  enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos)
+
+  enable_remoting = !is_ios && !is_android
+
+  # Enable hole punching for the protected video.
+  enable_video_hole = is_android
+
+  # Enables browser side Content Decryption Modules. Required for embedders
+  # (e.g. Android and ChromeCast) that use a browser side CDM.
+  enable_browser_cdms = is_android
+
+  # Variable safe_browsing is used to control the build time configuration for
+  # safe browsing feature. Safe browsing can be compiled in 3 different levels:
+  # 0 disables it, 1 enables it fully, and 2 enables only UI and reporting
+  # features without enabling phishing and malware detection. This is useful to
+  # integrate a third party phishing/malware detection to existing safe browsing
+  # logic.
+  if (is_android) {
+    safe_browsing_mode = 2
+  } else if (is_ios) {
+    safe_browsing_mode = 0
+  } else {
+    safe_browsing_mode = 1
+  }
+}
+
+# Additional dependent variables -----------------------------------------------
+
+# Set the version of CLD.
+#   0: Don't specify the version. This option is for the Finch testing.
+#   1: Use only CLD1.
+#   2: Use only CLD2.
+if (is_android) {
+  cld_version = 1
+} else {
+  cld_version = 2
+}
+
+# libudev usage. This currently only affects the content layer.
+use_udev = is_linux
+
+# Enable the spell checker.
+enable_spellcheck = !is_android
+
+enable_pepper_cdms = enable_plugins && (is_linux || is_mac || is_win)
+
+# Enable basic printing support and UI.
+enable_basic_printing = !is_chromeos
+
+# Enable printing with print preview. It does not imply
+# enable_basic_printing. It's possible to build Chrome with preview only.
+enable_print_preview = !is_android
+
+# The seccomp-bpf sandbox is only supported on three architectures
+# currently.
+# Do not disable seccomp_bpf anywhere without talking to
+# security@chromium.org!
+use_seccomp_bpf = (is_linux || is_android) &&
+                  (current_cpu == "x86" || current_cpu == "x64" ||
+                   current_cpu == "arm" || current_cpu == "mipsel")
+
+# Enable notifications everywhere except iOS.
+enable_notifications = !is_ios
+
+# TODO(brettw) this should be moved to net and only dependents get this define.
+disable_ftp_support = is_ios
+
+enable_web_speech = !is_android && !is_ios
+
+use_dbus = is_linux
+
+enable_extensions = !is_android && !is_ios
+
+enable_task_manager = !is_ios && !is_android
+
+use_cups = is_desktop_linux || is_mac
+
+enable_themes = !is_android && !is_ios
+
+# TODO(scottmg) remove this when we've fixed printing.
+win_pdf_metafile_for_printing = true
+
+# Whether we are using the rlz library or not.  Platforms like Android send
+# rlz codes for searches but do not use the library.
+enable_rlz = is_chrome_branded && (is_win || is_mac || is_ios || is_chromeos)
+
+enable_settings_app = enable_app_list && !is_chromeos
+
+enable_service_discovery = enable_mdns || is_mac
+
+enable_wifi_bootstrapping = is_win || is_mac
+
+# Image loader extension is enabled on ChromeOS only.
+enable_image_loader_extension = is_chromeos
+
+# Chrome OS: whether to also build the upcoming version of
+# ChromeVox, which can then be enabled via a command-line switch.
+enable_chromevox_next = false
+
+# Use brlapi from brltty for braille display support.
+use_brlapi = is_chromeos
+
+enable_media_router = !is_ios && !is_android
+
+# Option controlling the use of GConf (the classic GNOME configuration
+# system).
+# TODO(GYP) also require !embedded to enable.
+use_gconf = is_linux && !is_chromeos
+
+# Hangout services is an extension that adds extra features to Hangouts.
+# For official GYP builds, this flag is set, it will likely need to be
+# parameterized in the future for a similar use.
+enable_hangout_services_extension = false
+
+# Whether to back up data before sync.
+enable_pre_sync_backup = is_win || is_mac || (is_linux && !is_chromeos)
diff --git a/build/config/gcc/BUILD.gn b/build/config/gcc/BUILD.gn
new file mode 100644
index 0000000..c6cfe72
--- /dev/null
+++ b/build/config/gcc/BUILD.gn
@@ -0,0 +1,43 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This config causes functions not to be automatically exported from shared
+# libraries. By default, all symbols are exported but this means there are
+# lots of exports that slow everything down. In general we explicitly mark
+# which functiosn we want to export from components.
+#
+# Some third_party code assumes all functions are exported so this is separated
+# into its own config so such libraries can remove this config to make symbols
+# public again.
+#
+# See http://gcc.gnu.org/wiki/Visibility
+config("symbol_visibility_hidden") {
+  # Note that -fvisibility-inlines-hidden is set globally in the compiler
+  # config since that can almost always be applied.
+  cflags = [ "-fvisibility=hidden" ]
+}
+
+# Settings for executables and shared libraries.
+config("executable_ldconfig") {
+  ldflags = [
+    # Want to pass "\$". GN will re-escape as required for ninja.
+    "-Wl,-rpath=\$ORIGIN/",
+    "-Wl,-rpath-link=",
+
+    # Newer binutils don't set DT_RPATH unless you disable "new" dtags
+    # and the new DT_RUNPATH doesn't work without --no-as-needed flag.
+    "-Wl,--disable-new-dtags",
+  ]
+
+  if (is_android) {
+    ldflags += [
+      "-Bdynamic",
+      "-Wl,-z,nocopyreloc",
+    ]
+  }
+}
+
+config("no_exceptions") {
+  cflags_cc = [ "-fno-exceptions" ]
+}
diff --git a/build/config/gcc/gcc_version.gni b/build/config/gcc/gcc_version.gni
new file mode 100644
index 0000000..6741e45
--- /dev/null
+++ b/build/config/gcc/gcc_version.gni
@@ -0,0 +1,26 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+  gcc_version = 49
+} else if (current_toolchain == "//build/toolchain/cros:target" ||
+           current_toolchain == "//build/toolchain/linux:mipsel") {
+  gcc_version = exec_script("../../compiler_version.py",
+                            [
+                              "target",
+                              "compiler",
+                            ],
+                            "value")
+} else if (current_toolchain == "//build/toolchain/linux:x64" ||
+           current_toolchain == "//build/toolchain/linux:x86") {
+  # These are both the same and just use the default gcc on the system.
+  gcc_version = exec_script("../../compiler_version.py",
+                            [
+                              "host",
+                              "compiler",
+                            ],
+                            "value")
+} else {
+  gcc_version = 0
+}
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn
new file mode 100644
index 0000000..471f28a
--- /dev/null
+++ b/build/config/ios/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+import("//build/config/ios/ios_sdk.gni")
+
+config("sdk") {
+  common_flags = [
+    "-isysroot",
+    sysroot,
+  ]
+
+  cflags = common_flags
+  ldflags = common_flags
+
+  if (use_ios_simulator) {
+    cflags += [ "-mios-simulator-version-min=$ios_deployment_target" ]
+  } else {
+    cflags += [ "-miphoneos-version-min=$ios_deployment_target" ]
+  }
+}
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni
new file mode 100644
index 0000000..cb2708b
--- /dev/null
+++ b/build/config/ios/ios_sdk.gni
@@ -0,0 +1,30 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # SDK path to use. When empty this will use the default SDK based on the
+  # value of use_ios_simulator.
+  ios_sdk_path = ""
+
+  # Set to true when targeting a simulator build on iOS. False means that the
+  # target is for running on the device. The default value is to use the
+  # Simulator except when targeting GYP's Xcode builds (for compat with the
+  # existing GYP build).
+  use_ios_simulator = true
+
+  # Version of iOS that we're targeting.
+  ios_deployment_target = "6.0"
+}
+
+if (ios_sdk_path == "") {
+  # Compute default target.
+  if (use_ios_simulator) {
+    _ios_sdk_to_query = "iphonesimulator"
+  } else {
+    _ios_sdk_to_query = "iphoneos"
+  }
+  _ios_sdk_result =
+      exec_script("ios_sdk.py", [ _ios_sdk_to_query ], "list lines")
+  ios_sdk_path = _ios_sdk_result[0]
+}
diff --git a/build/config/ios/ios_sdk.py b/build/config/ios/ios_sdk.py
new file mode 100644
index 0000000..dfec4db
--- /dev/null
+++ b/build/config/ios/ios_sdk.py
@@ -0,0 +1,19 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import subprocess
+import sys
+
+# This script returns the path to the SDK of the given type. Pass the type of
+# SDK you want, which is typically "iphone" or "iphonesimulator".
+#
+# In the GYP build, this is done inside GYP itself based on the SDKROOT
+# variable.
+
+if len(sys.argv) != 2:
+  print "Takes one arg (SDK to find)"
+  sys.exit(1)
+
+print subprocess.check_output(['xcodebuild', '-version', '-sdk',
+                               sys.argv[1], 'Path']).strip()
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
new file mode 100644
index 0000000..3d65937
--- /dev/null
+++ b/build/config/linux/BUILD.gn
@@ -0,0 +1,252 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/linux/pkg_config.gni")
+import("//build/config/features.gni")
+import("//build/config/sysroot.gni")
+import("//build/config/ui.gni")
+import("//tools/generate_library_loader/generate_library_loader.gni")
+
+gypi_values = exec_script("//build/gypi_to_gn.py",
+                          [ rebase_path("../../linux/system.gyp") ],
+                          "scope",
+                          [ "../../linux/system.gyp" ])
+
+config("sdk") {
+  if (sysroot != "") {
+    cflags = [ "--sysroot=" + sysroot ]
+    ldflags = [ "--sysroot=" + sysroot ]
+
+    # Need to get some linker flags out of the sysroot.
+    ldflags += [ exec_script("sysroot_ld_path.py",
+                             [
+                               rebase_path("//build/linux/sysroot_ld_path.sh",
+                                           root_build_dir),
+                               sysroot,
+                             ],
+                             "value") ]
+  }
+
+  # Set here because OS_CHROMEOS cannot be autodetected in build_config.h like
+  # OS_LINUX and the like.
+  if (is_chromeos) {
+    defines = [ "OS_CHROMEOS" ]
+  }
+}
+
+pkg_config("atk") {
+  packages = [ "atk" ]
+  atk_lib_dir = exec_script(pkg_config_script,
+                            [
+                              "--libdir",
+                              "atk",
+                            ],
+                            "string")
+  defines = [ "ATK_LIB_DIR=\"$atk_lib_dir\"" ]
+}
+
+# gn orders flags on a target before flags from configs. The default config
+# adds -Wall, and these flags have to be after -Wall -- so they need to come
+# from a config and can't be on the target directly.
+config("atk_warnings") {
+  # glib uses the pre-c++11 typedef-as-static_assert hack.
+  cflags = [ "-Wno-unused-local-typedef" ]
+}
+
+config("fontconfig") {
+  libs = [ "fontconfig" ]
+}
+
+pkg_config("freetype2") {
+  packages = [ "freetype2" ]
+}
+
+pkg_config("glib") {
+  packages = [
+    "glib-2.0",
+    "gmodule-2.0",
+    "gobject-2.0",
+    "gthread-2.0",
+  ]
+}
+
+pkg_config("pangocairo") {
+  packages = [ "pangocairo" ]
+}
+
+pkg_config("pangoft2") {
+  packages = [ "pangoft2" ]
+}
+
+# Note: if your target also depends on //dbus, you don't need to add this
+# config (it will get added automatically if you depend on //dbus).
+pkg_config("dbus") {
+  packages = [ "dbus-1" ]
+}
+
+if (use_evdev_gestures) {
+  pkg_config("libevdev-cros") {
+    packages = [ "libevdev-cros" ]
+  }
+
+  pkg_config("libgestures") {
+    packages = [ "libgestures" ]
+  }
+}
+
+config("x11") {
+  libs = [
+    "X11",
+    "Xcomposite",
+    "Xcursor",
+    "Xdamage",
+    "Xext",
+    "Xfixes",
+    "Xi",
+    "Xrender",
+    "Xtst",
+  ]
+}
+
+config("xcomposite") {
+  libs = [ "Xcomposite" ]
+}
+
+config("xext") {
+  libs = [ "Xext" ]
+}
+
+config("xrandr") {
+  libs = [ "Xrandr" ]
+}
+
+config("xscrnsaver") {
+  libs = [ "Xss" ]
+}
+
+config("xfixes") {
+  libs = [ "Xfixes" ]
+}
+
+config("libcap") {
+  libs = [ "cap" ]
+}
+
+config("xi") {
+  libs = [ "Xi" ]
+}
+
+config("xtst") {
+  libs = [ "Xtst" ]
+}
+
+config("libresolv") {
+  libs = [ "resolv" ]
+}
+
+# CrOS doesn't install GTK, gconf or any gnome packages.
+if (!is_chromeos) {
+  # These packages should _only_ be expected when building for a target.
+  # If these extra checks are not run, gconf is required when building host
+  # tools for a CrOS build.
+  if (current_toolchain == default_toolchain) {
+    pkg_config("gconf") {
+      packages = [ "gconf-2.0" ]
+      defines = [ "USE_GCONF" ]
+    }
+  }
+}
+
+# If brlapi isn't needed, don't require it to be installed.
+if (use_brlapi) {
+  config("brlapi_config") {
+    defines = [ "USE_BRLAPI" ]
+  }
+
+  # TODO(GYP) linux_link_brlapi support. Is this needed?
+  generate_library_loader("libbrlapi") {
+    name = "LibBrlapiLoader"
+    output_h = "libbrlapi.h"
+    output_cc = "libbrlapi_loader.cc"
+    header = "<brlapi.h>"
+    config = ":brlapi_config"
+
+    functions = gypi_values.libbrlapi_functions
+  }
+}
+
+pkg_config("gio_config") {
+  packages = [ "gio-2.0" ]
+
+  # glib >=2.40 deprecate g_settings_list_schemas in favor of
+  # g_settings_schema_source_list_schemas. This function is not available on
+  # earlier versions that we still need to support (specifically, 2.32), so
+  # disable the warning with the GLIB_DISABLE_DEPRECATION_WARNINGS define.
+  # TODO(mgiuca): Remove this suppression when we drop support for Ubuntu 13.10
+  # (saucy) and earlier. Update the code to use
+  # g_settings_schema_source_list_schemas instead.
+  defines = [
+    "USE_GIO",
+    "GLIB_DISABLE_DEPRECATION_WARNINGS",
+  ]
+
+  # TODO(brettw) Theoretically I think ignore_libs should be set so that we
+  # don't link directly to GIO and use the loader generated below. But the gio
+  # target in GYP doesn't make any sense to me and appears to link directly to
+  # GIO in addition to making a loader. This this uncommented, the link in
+  # component build fails, so I think this is closer to the GYP build.
+  #ignore_libs = true  # Loader generated below.
+}
+
+if (is_desktop_linux) {
+  # This generates a target named "gio".
+  generate_library_loader("gio") {
+    name = "LibGioLoader"
+    output_h = "libgio.h"
+    output_cc = "libgio_loader.cc"
+    header = "<gio/gio.h>"
+    config = ":gio_config"
+
+    functions = gypi_values.libgio_functions
+  }
+}
+
+# This generates a target named "libpci".
+generate_library_loader("libpci") {
+  name = "LibPciLoader"
+  output_h = "libpci.h"
+  output_cc = "libpci_loader.cc"
+  header = "<pci/pci.h>"
+
+  functions = gypi_values.libpci_functions
+}
+
+# Looking for libspeechd? Use //third_party/speech-dispatcher
+
+# This generates a target named "udev0_loader".
+generate_library_loader("udev0_loader") {
+  name = "LibUdev0Loader"
+  output_h = "libudev0.h"
+  output_cc = "libudev0_loader.cc"
+  header = "\"third_party/libudev/libudev0.h\""
+
+  functions = gypi_values.libudev_functions
+}
+
+# This generates a target named "udev1_loader".
+generate_library_loader("udev1_loader") {
+  name = "LibUdev1Loader"
+  output_h = "libudev1.h"
+  output_cc = "libudev1_loader.cc"
+  header = "\"third_party/libudev/libudev1.h\""
+
+  functions = gypi_values.libudev_functions
+}
+
+group("udev") {
+  deps = [
+    ":udev0_loader",
+    ":udev1_loader",
+  ]
+}
diff --git a/build/config/linux/gtk/BUILD.gn b/build/config/linux/gtk/BUILD.gn
new file mode 100644
index 0000000..9c9c696
--- /dev/null
+++ b/build/config/linux/gtk/BUILD.gn
@@ -0,0 +1,45 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/linux/pkg_config.gni")
+
+assert(is_linux, "This file should only be referenced on Linux")
+
+# Depend on //build/config/linux/gtk to use GTK.
+#
+# GN doesn't check visibility for configs so we give this an obviously internal
+# name to discourage random targets from accidentally depending on this and
+# bypassing the GTK target's visibility.
+pkg_config("gtk_internal_config") {
+  # Gtk requires gmodule, but it does not list it as a dependency in some
+  # misconfigured systems.
+  packages = [
+    "gmodule-2.0",
+    "gtk+-2.0",
+    "gthread-2.0",
+  ]
+}
+
+# Basically no parts of Chrome should depend on GTK. To prevent accidents, the
+# parts that explicitly need GTK are whitelisted on this target.
+group("gtk") {
+  visibility = [
+    "//chrome/browser/ui/libgtk2ui",
+    "//gpu/gles2_conform_support:gles2_conform_test_windowless",
+    "//remoting/host",
+    "//remoting/host/it2me:remote_assistance_host",
+    "//remoting/host:remoting_me2me_host_static",
+  ]
+  public_configs = [ ":gtk_internal_config" ]
+}
+
+# Depend on "gtkprint" to get this.
+pkg_config("gtkprint_internal_config") {
+  packages = [ "gtk+-unix-print-2.0" ]
+}
+
+group("gtkprint") {
+  visibility = [ "//chrome/browser/ui/libgtk2ui" ]
+  public_configs = [ ":gtkprint_internal_config" ]
+}
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py
new file mode 100644
index 0000000..fadcc0b
--- /dev/null
+++ b/build/config/linux/pkg-config.py
@@ -0,0 +1,200 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+import subprocess
+import sys
+import re
+from optparse import OptionParser
+
+# This script runs pkg-config, optionally filtering out some results, and
+# returns the result.
+#
+# The result will be [ <includes>, <cflags>, <libs>, <lib_dirs>, <ldflags> ]
+# where each member is itself a list of strings.
+#
+# You can filter out matches using "-v <regexp>" where all results from
+# pkgconfig matching the given regular expression will be ignored. You can
+# specify more than one regular expression my specifying "-v" more than once.
+#
+# You can specify a sysroot using "-s <sysroot>" where sysroot is the absolute
+# system path to the sysroot used for compiling. This script will attempt to
+# generate correct paths for the sysroot.
+#
+# When using a sysroot, you must also specify the architecture via
+# "-a <arch>" where arch is either "x86" or "x64".
+#
+# Additionally, you can specify the option --atleast-version. This will skip
+# the normal outputting of a dictionary and instead print true or false,
+# depending on the return value of pkg-config for the given package.
+
+# If this is run on non-Linux platforms, just return nothing and indicate
+# success. This allows us to "kind of emulate" a Linux build from other
+# platforms.
+if sys.platform.find("linux") == -1:
+  print "[[],[],[],[],[]]"
+  sys.exit(0)
+
+
+def SetConfigPath(options):
+  """Set the PKG_CONFIG_PATH environment variable.
+  This takes into account any sysroot and architecture specification from the
+  options on the given command line."""
+
+  sysroot = options.sysroot
+  if not sysroot:
+    sysroot = ""
+
+  # Compute the library path name based on the architecture.
+  arch = options.arch
+  if sysroot and not arch:
+    print "You must specify an architecture via -a if using a sysroot."
+    sys.exit(1)
+  if arch == 'x64':
+    libpath = 'lib64'
+  else:
+    libpath = 'lib'
+
+  # Add the sysroot path to the environment's PKG_CONFIG_PATH
+  config_path = sysroot + '/usr/' + libpath + '/pkgconfig'
+  config_path += ':' + sysroot + '/usr/share/pkgconfig'
+  if 'PKG_CONFIG_PATH' in os.environ:
+    os.environ['PKG_CONFIG_PATH'] += ':' + config_path
+  else:
+    os.environ['PKG_CONFIG_PATH'] = config_path
+
+
+def GetPkgConfigPrefixToStrip(args):
+  """Returns the prefix from pkg-config where packages are installed.
+  This returned prefix is the one that should be stripped from the beginning of
+  directory names to take into account sysroots."""
+  # Some sysroots, like the Chromium OS ones, may generate paths that are not
+  # relative to the sysroot. For example,
+  # /path/to/chroot/build/x86-generic/usr/lib/pkgconfig/pkg.pc may have all
+  # paths relative to /path/to/chroot (i.e. prefix=/build/x86-generic/usr)
+  # instead of relative to /path/to/chroot/build/x86-generic (i.e prefix=/usr).
+  # To support this correctly, it's necessary to extract the prefix to strip
+  # from pkg-config's |prefix| variable.
+  prefix = subprocess.check_output(["pkg-config", "--variable=prefix"] + args,
+      env=os.environ)
+  if prefix[-4] == '/usr':
+    return prefix[4:]
+  return prefix
+
+
+def MatchesAnyRegexp(flag, list_of_regexps):
+  """Returns true if the first argument matches any regular expression in the
+  given list."""
+  for regexp in list_of_regexps:
+    if regexp.search(flag) != None:
+      return True
+  return False
+
+
+def RewritePath(path, strip_prefix, sysroot):
+  """Rewrites a path by stripping the prefix and prepending the sysroot."""
+  if os.path.isabs(path) and not path.startswith(sysroot):
+    if path.startswith(strip_prefix):
+      path = path[len(strip_prefix):]
+    path = path.lstrip('/')
+    return os.path.join(sysroot, path)
+  else:
+    return path
+
+
+parser = OptionParser()
+parser.add_option('-p', action='store', dest='pkg_config', type='string',
+                  default='pkg-config')
+parser.add_option('-v', action='append', dest='strip_out', type='string')
+parser.add_option('-s', action='store', dest='sysroot', type='string')
+parser.add_option('-a', action='store', dest='arch', type='string')
+parser.add_option('--atleast-version', action='store',
+                  dest='atleast_version', type='string')
+parser.add_option('--libdir', action='store_true', dest='libdir')
+(options, args) = parser.parse_args()
+
+# Make a list of regular expressions to strip out.
+strip_out = []
+if options.strip_out != None:
+  for regexp in options.strip_out:
+    strip_out.append(re.compile(regexp))
+
+SetConfigPath(options)
+if options.sysroot:
+  prefix = GetPkgConfigPrefixToStrip(args)
+else:
+  prefix = ''
+
+if options.atleast_version:
+  # When asking for the return value, just run pkg-config and print the return
+  # value, no need to do other work.
+  if not subprocess.call([options.pkg_config,
+                          "--atleast-version=" + options.atleast_version] +
+                          args,
+                         env=os.environ):
+    print "true"
+  else:
+    print "false"
+  sys.exit(0)
+
+if options.libdir:
+  try:
+    libdir = subprocess.check_output([options.pkg_config,
+                                      "--variable=libdir"] +
+                                     args,
+                                     env=os.environ)
+  except:
+    print "Error from pkg-config."
+    sys.exit(1)
+  sys.stdout.write(libdir.strip())
+  sys.exit(0)
+
+try:
+  flag_string = subprocess.check_output(
+      [ options.pkg_config, "--cflags", "--libs-only-l", "--libs-only-L" ] +
+      args, env=os.environ)
+  # For now just split on spaces to get the args out. This will break if
+  # pkgconfig returns quoted things with spaces in them, but that doesn't seem
+  # to happen in practice.
+  all_flags = flag_string.strip().split(' ')
+except:
+  print "Could not run pkg-config."
+  sys.exit(1)
+
+
+sysroot = options.sysroot
+if not sysroot:
+  sysroot = ''
+
+includes = []
+cflags = []
+libs = []
+lib_dirs = []
+ldflags = []
+
+for flag in all_flags[:]:
+  if len(flag) == 0 or MatchesAnyRegexp(flag, strip_out):
+    continue;
+
+  if flag[:2] == '-l':
+    libs.append(RewritePath(flag[2:], prefix, sysroot))
+  elif flag[:2] == '-L':
+    lib_dirs.append(RewritePath(flag[2:], prefix, sysroot))
+  elif flag[:2] == '-I':
+    includes.append(RewritePath(flag[2:], prefix, sysroot))
+  elif flag[:3] == '-Wl':
+    ldflags.append(flag)
+  elif flag == '-pthread':
+    # Many libs specify "-pthread" which we don't need since we always include
+    # this anyway. Removing it here prevents a bunch of duplicate inclusions on
+    # the command line.
+    pass
+  else:
+    cflags.append(flag)
+
+# Output a GN array, the first one is the cflags, the second are the libs. The
+# JSON formatter prints GN compatible lists when everything is a list of
+# strings.
+print json.dumps([includes, cflags, libs, lib_dirs, ldflags])
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni
new file mode 100644
index 0000000..34ed1af
--- /dev/null
+++ b/build/config/linux/pkg_config.gni
@@ -0,0 +1,83 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+
+# Defines a config specifying the result of running pkg-config for the given
+# packages. Put the package names you want to query in the "packages" variable
+# inside the template invocation.
+#
+# You can also add defines via the "defines" variable. This can be useful to
+# add this to the config to pass defines that the library expects to get by
+# users of its headers.
+#
+# Example:
+#   pkg_config("mything") {
+#     packages = [ "mything1", "mything2" ]
+#     defines = [ "ENABLE_AWESOME" ]
+#   }
+#
+# You can also use "extra args" to filter out results (see pkg-config.py):
+#   extra_args = [ "-v, "foo" ]
+# To ignore libs and ldflags (only cflags/defines will be set, which is useful
+# when doing manual dynamic linking), set:
+#   ignore_libs = true
+
+declare_args() {
+  # A pkg-config wrapper to call instead of trying to find and call the right
+  # pkg-config directly. Wrappers like this are common in cross-compilation
+  # environments.
+  # Leaving it blank defaults to searching PATH for 'pkg-config' and relying on
+  # the sysroot mechanism to find the right .pc files.
+  pkg_config = ""
+}
+
+pkg_config_script = "//build/config/linux/pkg-config.py"
+
+# Define the args we pass to the pkg-config script for other build files that
+# need to invoke it manually.
+if (sysroot != "") {
+  # Pass the sysroot if we're using one (it requires the CPU arch also).
+  pkg_config_args = [
+    "-s",
+    sysroot,
+    "-a",
+    current_cpu,
+  ]
+} else if (pkg_config != "") {
+  pkg_config_args = [
+    "-p",
+    pkg_config,
+  ]
+} else {
+  pkg_config_args = []
+}
+
+template("pkg_config") {
+  assert(defined(invoker.packages),
+         "Variable |packages| must be defined to be a list in pkg_config.")
+  config(target_name) {
+    args = pkg_config_args + invoker.packages
+    if (defined(invoker.extra_args)) {
+      args += invoker.extra_args
+    }
+
+    pkgresult = exec_script(pkg_config_script, args, "value")
+    include_dirs = pkgresult[0]
+    cflags = pkgresult[1]
+
+    if (!defined(invoker.ignore_libs) || !invoker.ignore_libs) {
+      libs = pkgresult[2]
+      lib_dirs = pkgresult[3]
+      ldflags = pkgresult[4]
+    }
+
+    if (defined(invoker.defines)) {
+      defines = invoker.defines
+    }
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+  }
+}
diff --git a/build/config/linux/sysroot_ld_path.py b/build/config/linux/sysroot_ld_path.py
new file mode 100644
index 0000000..4bce7ee
--- /dev/null
+++ b/build/config/linux/sysroot_ld_path.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file takes two arguments, the relative location of the shell script that
+# does the checking, and the name of the sysroot.
+
+# TODO(brettw) the build/linux/sysroot_ld_path.sh script should be rewritten in
+# Python in this file.
+
+import subprocess
+import sys
+
+if len(sys.argv) != 3:
+  print "Need two arguments"
+  sys.exit(1)
+
+result = subprocess.check_output([sys.argv[1], sys.argv[2]]).strip()
+
+print '"' + result + '"'
diff --git a/build/config/locales.gni b/build/config/locales.gni
new file mode 100644
index 0000000..a628007
--- /dev/null
+++ b/build/config/locales.gni
@@ -0,0 +1,118 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Note: keep in sync with below.
+locales = [
+  "am",
+  "ar",
+  "bg",
+  "bn",
+  "ca",
+  "cs",
+  "da",
+  "de",
+  "el",
+  "en-GB",
+  "en-US",
+  "es-419",
+  "es",
+  "et",
+  "fa",
+  "fi",
+  "fil",
+  "fr",
+  "gu",
+  "he",
+  "hi",
+  "hr",
+  "hu",
+  "id",
+  "it",
+  "ja",
+  "kn",
+  "ko",
+  "lt",
+  "lv",
+  "ml",
+  "mr",
+  "ms",
+  "nb",
+  "nl",
+  "pl",
+  "pt-BR",
+  "pt-PT",
+  "ro",
+  "ru",
+  "sk",
+  "sl",
+  "sr",
+  "sv",
+  "sw",
+  "ta",
+  "te",
+  "th",
+  "tr",
+  "uk",
+  "vi",
+  "zh-CN",
+  "zh-TW",
+]
+
+# Same as the locales list but in the format Mac expects for output files:
+# it uses underscores instead of hyphens, and "en" instead of "en-US".
+locales_as_mac_outputs = [
+  "am",
+  "ar",
+  "bg",
+  "bn",
+  "ca",
+  "cs",
+  "da",
+  "de",
+  "el",
+  "en_GB",
+  "en",
+  "es_419",
+  "es",
+  "et",
+  "fa",
+  "fi",
+  "fil",
+  "fr",
+  "gu",
+  "he",
+  "hi",
+  "hr",
+  "hu",
+  "id",
+  "it",
+  "ja",
+  "kn",
+  "ko",
+  "lt",
+  "lv",
+  "ml",
+  "mr",
+  "ms",
+  "nb",
+  "nl",
+  "pl",
+  "pt_BR",
+  "pt_PT",
+  "ro",
+  "ru",
+  "sk",
+  "sl",
+  "sr",
+  "sv",
+  "sw",
+  "ta",
+  "te",
+  "th",
+  "tr",
+  "uk",
+  "vi",
+  "zh_CN",
+  "zh_TW",
+]
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn
new file mode 100644
index 0000000..9288add
--- /dev/null
+++ b/build/config/mac/BUILD.gn
@@ -0,0 +1,36 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+
+config("sdk") {
+  common_flags = [
+    "-isysroot",
+    sysroot,
+    "-mmacosx-version-min=10.6",
+  ]
+
+  cflags = common_flags
+  ldflags = common_flags
+}
+
+# On Mac, this is used for everything except static libraries.
+config("mac_dynamic_flags") {
+  ldflags = [
+    "-Wl,-search_paths_first",
+    "-L.",
+
+    # Path for loading shared libraries for unbundled binaries.
+    "-Wl,-rpath,@loader_path/.",
+
+    # Path for loading shared libraries for bundled binaries. Get back from
+    # Binary.app/Contents/MacOS.
+    "-Wl,-rpath,@loader_path/../../..",
+  ]
+}
+
+# On Mac, this is used only for executables.
+config("mac_executable_flags") {
+  ldflags = [ "-Wl,-pie" ]  # Position independent.
+}
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
new file mode 100644
index 0000000..600085e
--- /dev/null
+++ b/build/config/mac/mac_sdk.gni
@@ -0,0 +1,41 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/chrome_build.gni")
+
+declare_args() {
+  # Minimum supported version of the Mac SDK.
+  mac_sdk_min = "10.6"
+
+  # Path to a specific version of the Mac SDKJ, not including a backslash at
+  # the end. If empty, the path to the lowest version greater than or equal to
+  # mac_sdk_min is used.
+  mac_sdk_path = ""
+}
+
+find_sdk_args = [ "--print_sdk_path" ]
+if (is_chrome_branded && is_official_build) {
+  find_sdk_args += [
+    "--verify",
+    mac_sdk_min,
+    "--sdk_path=" + mac_sdk_path,
+  ]
+} else {
+  find_sdk_args += [ mac_sdk_min ]
+}
+
+# The tool will print the SDK path on the first line, and the version on the
+# second line.
+find_sdk_lines =
+    exec_script("//build/mac/find_sdk.py", find_sdk_args, "list lines")
+mac_sdk_version = find_sdk_lines[1]
+if (mac_sdk_path == "") {
+  # TODO(brettw) http://crbug.com/335325  when everybody moves to XCode 5 we
+  # can remove the --print_sdk_path argument to find_sdk and instead just use
+  # the following two lines to get the path. Although it looks longer here, it
+  # saves forking a process in find_sdk.py so will be faster.
+  #mac_sdk_root = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX"
+  #mac_sdk_path = mac_sdk_root + mac_sdk_version + ".sdk"
+  mac_sdk_path = find_sdk_lines[0]
+}
diff --git a/build/config/mips.gni b/build/config/mips.gni
new file mode 100644
index 0000000..1b40657
--- /dev/null
+++ b/build/config/mips.gni
@@ -0,0 +1,43 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (current_cpu == "mipsel") {
+  declare_args() {
+    # MIPS arch variant. Possible values are:
+    #   "r1"
+    #   "r2"
+    #   "r6"
+    mips_arch_variant = "r1"
+
+    # MIPS DSP ASE revision. Possible values are:
+    #   0: unavailable
+    #   1: revision 1
+    #   2: revision 2
+    mips_dsp_rev = 0
+
+    # MIPS floating-point ABI. Possible values are:
+    #   "hard": sets the GCC -mhard-float option.
+    #   "soft": sets the GCC -msoft-float option.
+    mips_float_abi = "hard"
+
+    # MIPS32 floating-point register width. Possible values are:
+    #   "fp32": sets the GCC -mfp32 option.
+    #   "fp64": sets the GCC -mfp64 option.
+    #   "fpxx": sets the GCC -mfpxx option.
+    mips_fpu_mode = "fp32"
+  }
+} else if (current_cpu == "mips64el") {
+  # MIPS arch variant. Possible values are:
+  #   "r2"
+  #   "r6"
+  if (is_android) {
+    declare_args() {
+      mips_arch_variant = "r6"
+    }
+  } else {
+    declare_args() {
+      mips_arch_variant = "r2"
+    }
+  }
+}
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
new file mode 100644
index 0000000..3972a5c
--- /dev/null
+++ b/build/config/sanitizers/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Contains the dependencies needed for asan to link into executables and
+# shared_libraries. Unconditionally depend upon this target as it is empty if
+# |is_asan| is false.
+group("deps") {
+  if (is_asan) {
+    public_configs = [ ":sanitizer_options_link_helper" ]
+    deps = [
+      ":options_sources",
+    ]
+  }
+}
+
+config("sanitizer_options_link_helper") {
+  ldflags = [
+    "-Wl,-u_sanitizer_options_link_helper",
+    "-fsanitize=address",
+  ]
+}
+
+source_set("options_sources") {
+  visibility = [
+    ":deps",
+    "//:gn_visibility",
+  ]
+  sources = [
+    "//build/sanitizers/sanitizer_options.cc",
+  ]
+
+  if (is_asan) {
+    sources += [ "//build/sanitizers/asan_suppressions.cc" ]
+  }
+
+  if (is_tsan) {
+    sources += [ "//build/sanitizers/tsan_suppressions.cc" ]
+  }
+}
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
new file mode 100644
index 0000000..e5a9c2b
--- /dev/null
+++ b/build/config/sysroot.gni
@@ -0,0 +1,62 @@
+# 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 header file defines the "sysroot" variable which is the absolute path
+# of the sysroot. If no sysroot applies, the variable will be an empty string.
+
+import("//build/config/chrome_build.gni")
+
+declare_args() {
+  # The absolute path of the sysroot that is applied when compiling using
+  # the target toolchain.
+  target_sysroot = ""
+}
+
+if (current_toolchain == default_toolchain && target_sysroot != "") {
+  sysroot = target_sysroot
+} else if (is_android) {
+  import("//build/config/android/config.gni")
+  if (current_cpu == "x86") {
+    sysroot = rebase_path("$android_ndk_root/$x86_android_sysroot_subdir")
+  } else if (current_cpu == "arm") {
+    sysroot = rebase_path("$android_ndk_root/$arm_android_sysroot_subdir")
+  } else if (current_cpu == "mipsel") {
+    sysroot = rebase_path("$android_ndk_root/$mips_android_sysroot_subdir")
+  } else if (current_cpu == "x64") {
+    sysroot = rebase_path("$android_ndk_root/$x86_64_android_sysroot_subdir")
+  } else if (current_cpu == "arm64") {
+    sysroot = rebase_path("$android_ndk_root/$arm64_android_sysroot_subdir")
+  } else if (current_cpu == "mips64") {
+    sysroot = rebase_path("$android_ndk_root/$mips64_android_sysroot_subdir")
+  } else {
+    sysroot = ""
+  }
+} else if (is_linux && is_chrome_branded && is_official_build && !is_chromeos) {
+  # For official builds, use the sysroot checked into the internal source repo
+  # so that the builds work on older versions of Linux.
+  if (current_cpu == "x64") {
+    sysroot =
+        rebase_path("//chrome/installer/linux/debian_wheezy_amd64-sysroot")
+  } else if (current_cpu == "x86") {
+    sysroot = rebase_path("//chrome/installer/linux/debian_wheezy_i386-sysroot")
+  } else {
+    # Any other builds don't use a sysroot.
+    sysroot = ""
+  }
+} else if (is_linux && !is_chromeos) {
+  if (current_cpu == "mipsel") {
+    sysroot = rebase_path("//mipsel-sysroot/sysroot")
+  } else {
+    sysroot = ""
+  }
+} else if (is_mac) {
+  import("//build/config/mac/mac_sdk.gni")
+
+  sysroot = mac_sdk_path
+} else if (is_ios) {
+  import("//build/config/ios/ios_sdk.gni")
+  sysroot = ios_sdk_path
+} else {
+  sysroot = ""
+}
diff --git a/build/config/ui.gni b/build/config/ui.gni
new file mode 100644
index 0000000..787e7ef
--- /dev/null
+++ b/build/config/ui.gni
@@ -0,0 +1,65 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file contains UI-related build flags. It should theoretically be in the
+# src/ui directory and only things that depend on the ui module should get the
+# definitions.
+#
+# However, today we have many "bad" dependencies on some of these flags from,
+# e.g. base, so they need to be global.
+#
+# See also build/config/features.gni
+
+declare_args() {
+  # Indicates if Ash is enabled. Ash is the Aura Shell which provides a
+  # desktop-like environment for Aura. Requires use_aura = true
+  use_ash = is_win || is_linux
+
+  # Indicates if Ozone is enabled. Ozone is a low-level library layer for Linux
+  # that does not require X11.
+  use_ozone = false
+
+  # Support ChromeOS touchpad gestures with ozone.
+  use_evdev_gestures = false
+
+  # Indicates if Aura is enabled. Aura is a low-level windowing library, sort
+  # of a replacement for GDI or GTK.
+  use_aura = is_win || is_linux
+
+  # True means the UI is built using the "views" framework.
+  toolkit_views = is_mac || is_win || is_chromeos || use_aura
+
+  # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
+  mac_views_browser = false
+
+  # Whether we should use glib, a low level C utility library.
+  use_glib = is_linux && !use_ozone
+}
+
+# Additional dependent variables -----------------------------------------------
+#
+# These variables depend on other variables and can't be set externally.
+
+if (is_linux && use_glib) {
+  use_cairo = true
+  use_pango = true
+} else {
+  use_cairo = false
+  use_pango = false
+}
+
+# Use GPU accelerated cross process image transport by default on linux builds
+# with the Aura window manager.
+ui_compositor_image_transport = use_aura && is_linux
+
+use_default_render_theme = use_aura || is_linux
+
+# Indicates if the UI toolkit depends on X11.
+use_x11 = is_linux && !use_ozone
+
+use_ozone_evdev = use_ozone
+
+use_clipboard_aurax11 = is_linux && use_aura && use_x11
+
+enable_hidpi = is_mac || is_chromeos || is_win || is_linux
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
new file mode 100644
index 0000000..8b0910f
--- /dev/null
+++ b/build/config/win/BUILD.gn
@@ -0,0 +1,181 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/win/visual_studio_version.gni")
+
+# Compiler setup for the Windows SDK. Applied to all targets.
+config("sdk") {
+  # The include path is the stuff returned by the script.
+  #include_dirs = msvc_config[0]  TODO(brettw) make this work.
+
+  defines = [
+    "_ATL_NO_OPENGL",
+    "_WINDOWS",
+    "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
+    "NTDDI_VERSION=0x06030000",
+    "PSAPI_VERSION=1",
+    "WIN32",
+    "_SECURE_ATL",
+
+    # This is required for ATL to use XP-safe versions of its functions.
+    "_USING_V110_SDK71_",
+  ]
+}
+
+# Sets the default Windows build version. This is separated because some
+# targets need to manually override it for their compiles.
+config("winver") {
+  defines = [
+    "_WIN32_WINNT=0x0603",
+    "WINVER=0x0603",
+  ]
+}
+
+# Linker flags for Windows SDK setup, this is applied only to EXEs and DLLs.
+config("sdk_link") {
+  if (current_cpu == "x64") {
+    ldflags = [ "/MACHINE:X64" ]
+    lib_dirs = [
+      "$windows_sdk_path\Lib\winv6.3\um\x64",
+      "$visual_studio_path\VC\lib\amd64",
+      "$visual_studio_path\VC\atlmfc\lib\amd64",
+    ]
+  } else {
+    ldflags = [
+      "/MACHINE:X86",
+      "/SAFESEH",  # Not compatible with x64 so use only for x86.
+    ]
+    lib_dirs = [
+      "$windows_sdk_path\Lib\winv6.3\um\x86",
+      "$visual_studio_path\VC\lib",
+      "$visual_studio_path\VC\atlmfc\lib",
+    ]
+    if (!is_asan) {
+      ldflags += [ "/largeaddressaware" ]
+    }
+  }
+}
+
+# This default linker setup is provided separately from the SDK setup so
+# targets who want different library configurations can remove this and specify
+# their own.
+config("common_linker_setup") {
+  ldflags = [
+    "/FIXED:NO",
+    "/ignore:4199",
+    "/ignore:4221",
+    "/NXCOMPAT",
+
+    # Suggested by Microsoft Devrel to avoid
+    #   LINK : fatal error LNK1248: image size (80000000)
+    #   exceeds maximum allowable size (80000000)
+    # which started happening more regularly after VS2013 Update 4.
+    "/maxilksize:2147483647",
+  ]
+
+  # ASLR makes debugging with windbg difficult because Chrome.exe and
+  # Chrome.dll share the same base name. As result, windbg will name the
+  # Chrome.dll module like chrome_<base address>, where <base address>
+  # typically changes with each launch. This in turn means that breakpoints in
+  # Chrome.dll don't stick from one launch to the next. For this reason, we
+  # turn ASLR off in debug builds.
+  if (is_debug) {
+    ldflags += [ "/DYNAMICBASE:NO" ]
+  } else {
+    ldflags += [ "/DYNAMICBASE" ]
+  }
+
+  # Delay loaded DLLs.
+  ldflags += [
+    "/DELAYLOAD:dbghelp.dll",
+    "/DELAYLOAD:dwmapi.dll",
+    "/DELAYLOAD:shell32.dll",
+    "/DELAYLOAD:uxtheme.dll",
+  ]
+}
+
+# Subsystem --------------------------------------------------------------------
+
+# This is appended to the subsystem to specify a minimum version.
+if (current_cpu == "x64") {
+  # The number after the comma is the minimum required OS version.
+  # 5.02 = Windows Server 2003.
+  subsystem_version_suffix = ",5.02"
+} else {
+  # Don't specify a min version on x86.
+  subsystem_version_suffix = ""
+}
+
+config("console") {
+  ldflags = [ "/SUBSYSTEM:CONSOLE$subsystem_version_suffix" ]
+}
+config("windowed") {
+  ldflags = [ "/SUBSYSTEM:WINDOWS$subsystem_version_suffix" ]
+}
+
+# Incremental linking ----------------------------------------------------------
+
+incremental_linking_on_switch = [ "/INCREMENTAL" ]
+incremental_linking_off_switch = [ "/INCREMENTAL:NO" ]
+if (is_debug) {
+  default_incremental_linking_switch = incremental_linking_on_switch
+} else {
+  default_incremental_linking_switch = incremental_linking_off_switch
+}
+
+# Applies incremental linking or not depending on the current configuration.
+config("default_incremental_linking") {
+  ldflags = default_incremental_linking_switch
+}
+
+# Explicitly on or off incremental linking
+config("incremental_linking") {
+  ldflags = incremental_linking_on_switch
+}
+config("no_incremental_linking") {
+  ldflags = incremental_linking_off_switch
+}
+
+# Some large modules can't handle incremental linking in some situations. This
+# config should be applied to large modules to turn off incremental linking
+# when it won't work.
+config("default_large_module_incremental_linking") {
+  if (symbol_level > 0 && (current_cpu == "x86" || !is_component_build)) {
+    # When symbols are on, things get so large that the tools fail due to the
+    # size of the .ilk files.
+    ldflags = incremental_linking_off_switch
+  } else {
+    # Otherwise just do the default incremental linking for this build type.
+    ldflags = default_incremental_linking_switch
+  }
+}
+
+# Character set ----------------------------------------------------------------
+
+# Not including this config means "ansi" (8-bit system codepage).
+config("unicode") {
+  defines = [
+    "_UNICODE",
+    "UNICODE",
+  ]
+}
+
+# Lean and mean ----------------------------------------------------------------
+
+# Some third party code might not compile with WIN32_LEAN_AND_MEAN so we have
+# to have a separate config for it. Remove this config from your target to
+# get the "bloaty and accomodating" version of windows.h.
+config("lean_and_mean") {
+  defines = [ "WIN32_LEAN_AND_MEAN" ]
+}
+
+# Nominmax --------------------------------------------------------------------
+
+# Some third party code defines NOMINMAX before including windows.h, which
+# then causes warnings when it's been previously defined on the command line.
+# For such targets, this config can be removed.
+
+config("nominmax") {
+  defines = [ "NOMINMAX" ]
+}
diff --git a/build/config/win/visual_studio_version.gni b/build/config/win/visual_studio_version.gni
new file mode 100644
index 0000000..6a2828c
--- /dev/null
+++ b/build/config/win/visual_studio_version.gni
@@ -0,0 +1,39 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  # Path to Visual Studio. If empty, the default is used which is to use the
+  # automatic toolchain in depot_tools. If set, you must also set the
+  # visual_studio_version and wdk_path.
+  visual_studio_path = ""
+
+  # Version of Visual Studio pointed to by the visual_studio_path.
+  # Use "2013" for Visual Studio 2013, or "2013e" for the Express version.
+  visual_studio_version = ""
+
+  # Directory of the Windows driver kit. If visual_studio_path is empty, this
+  # will be auto-filled.
+  wdk_path = ""
+
+  # Full path to the Windows SDK, not including a backslash at the end.
+  # This value is the default location, override if you have a different
+  # installation location.
+  windows_sdk_path = "C:\Program Files (x86)\Windows Kits\8.1"
+}
+
+if (visual_studio_path == "") {
+  toolchain_data =
+      exec_script("../../vs_toolchain.py", [ "get_toolchain_dir" ], "scope")
+  visual_studio_path = toolchain_data.vs_path
+  windows_sdk_path = toolchain_data.sdk_path
+  visual_studio_version = toolchain_data.vs_version
+  wdk_path = toolchain_data.wdk_dir
+  visual_studio_runtime_dirs = toolchain_data.runtime_dirs
+} else {
+  assert(visual_studio_version != "",
+         "You must set the visual_studio_version if you set the path")
+  assert(wdk_path != "",
+         "You must set the wdk_path if you set the visual studio path")
+  visual_studio_runtime_dirs = []
+}
diff --git a/build/copy_test_data_ios.gypi b/build/copy_test_data_ios.gypi
new file mode 100644
index 0000000..576a0f2
--- /dev/null
+++ b/build/copy_test_data_ios.gypi
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to copy test data files into
+# an iOS app bundle. To use this the following variables need to be defined:
+#   test_data_files: list: paths to test data files or directories
+#   test_data_prefix: string: a directory prefix that will be prepended to each
+#                             output path.  Generally, this should be the base
+#                             directory of the gypi file containing the unittest
+#                             target (e.g. "base" or "chrome").
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_unittests',
+#   'conditions': [
+#     ['OS == "ios"', {
+#       'actions': [
+#         {
+#           'action_name': 'copy_test_data',
+#           'variables': {
+#             'test_data_files': [
+#               'path/to/datafile.txt',
+#               'path/to/data/directory/',
+#             ]
+#             'test_data_prefix' : 'prefix',
+#           },
+#           'includes': ['path/to/this/gypi/file'],
+#         },
+#       ],
+#     }],
+# }
+#
+
+{
+  'inputs': [
+    # The |-o <(test_data_prefix)| is ignored; it is there to work around a
+    # caching bug in gyp (https://code.google.com/p/gyp/issues/detail?id=112).
+    # It caches command output when the string is the same, so if two copy
+    # steps have the same relative paths, there can be bogus cache hits that
+    # cause compile failures unless something varies.
+    '<!@pymod_do_main(copy_test_data_ios -o <(test_data_prefix) --inputs <(test_data_files))',
+  ],
+  'outputs': [
+    '<!@pymod_do_main(copy_test_data_ios -o <(PRODUCT_DIR)/<(_target_name).app/<(test_data_prefix) --outputs <(test_data_files))',
+  ],
+  'action': [
+    'python',
+    '<(DEPTH)/build/copy_test_data_ios.py',
+    '-o', '<(PRODUCT_DIR)/<(_target_name).app/<(test_data_prefix)',
+    '<@(_inputs)',
+  ],
+}
diff --git a/build/copy_test_data_ios.py b/build/copy_test_data_ios.py
new file mode 100755
index 0000000..6f0302f
--- /dev/null
+++ b/build/copy_test_data_ios.py
@@ -0,0 +1,105 @@
+#!/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.
+
+"""Copies test data files or directories into a given output directory."""
+
+import optparse
+import os
+import shutil
+import sys
+
+class WrongNumberOfArgumentsException(Exception):
+  pass
+
+def EscapePath(path):
+  """Returns a path with spaces escaped."""
+  return path.replace(" ", "\\ ")
+
+def ListFilesForPath(path):
+  """Returns a list of all the files under a given path."""
+  output = []
+  # Ignore revision control metadata directories.
+  if (os.path.basename(path).startswith('.git') or
+      os.path.basename(path).startswith('.svn')):
+    return output
+
+  # Files get returned without modification.
+  if not os.path.isdir(path):
+    output.append(path)
+    return output
+
+  # Directories get recursively expanded.
+  contents = os.listdir(path)
+  for item in contents:
+    full_path = os.path.join(path, item)
+    output.extend(ListFilesForPath(full_path))
+  return output
+
+def CalcInputs(inputs):
+  """Computes the full list of input files for a set of command-line arguments.
+  """
+  # |inputs| is a list of paths, which may be directories.
+  output = []
+  for input in inputs:
+    output.extend(ListFilesForPath(input))
+  return output
+
+def CopyFiles(relative_filenames, output_basedir):
+  """Copies files to the given output directory."""
+  for file in relative_filenames:
+    relative_dirname = os.path.dirname(file)
+    output_dir = os.path.join(output_basedir, relative_dirname)
+    output_filename = os.path.join(output_basedir, file)
+
+    # In cases where a directory has turned into a file or vice versa, delete it
+    # before copying it below.
+    if os.path.exists(output_dir) and not os.path.isdir(output_dir):
+      os.remove(output_dir)
+    if os.path.exists(output_filename) and os.path.isdir(output_filename):
+      shutil.rmtree(output_filename)
+
+    if not os.path.exists(output_dir):
+      os.makedirs(output_dir)
+    shutil.copy(file, output_filename)
+
+def DoMain(argv):
+  parser = optparse.OptionParser()
+  usage = 'Usage: %prog -o <output_dir> [--inputs] [--outputs] <input_files>'
+  parser.set_usage(usage)
+  parser.add_option('-o', dest='output_dir')
+  parser.add_option('--inputs', action='store_true', dest='list_inputs')
+  parser.add_option('--outputs', action='store_true', dest='list_outputs')
+  options, arglist = parser.parse_args(argv)
+
+  if len(arglist) == 0:
+    raise WrongNumberOfArgumentsException('<input_files> required.')
+
+  files_to_copy = CalcInputs(arglist)
+  escaped_files = [EscapePath(x) for x in CalcInputs(arglist)]
+  if options.list_inputs:
+    return '\n'.join(escaped_files)
+
+  if not options.output_dir:
+    raise WrongNumberOfArgumentsException('-o required.')
+
+  if options.list_outputs:
+    outputs = [os.path.join(options.output_dir, x) for x in escaped_files]
+    return '\n'.join(outputs)
+
+  CopyFiles(files_to_copy, options.output_dir)
+  return
+
+def main(argv):
+  try:
+    result = DoMain(argv[1:])
+  except WrongNumberOfArgumentsException, e:
+    print >>sys.stderr, e
+    return 1
+  if result:
+    print result
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/cp.py b/build/cp.py
new file mode 100755
index 0000000..0f32536
--- /dev/null
+++ b/build/cp.py
@@ -0,0 +1,23 @@
+#!/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.
+
+"""Copy a file.
+
+This module works much like the cp posix command - it takes 2 arguments:
+(src, dst) and copies the file with path |src| to |dst|.
+"""
+
+import os
+import shutil
+import sys
+
+
+def Main(src, dst):
+  # Use copy instead of copyfile to ensure the executable bit is copied.
+  return shutil.copy(src, os.path.normpath(dst))
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1], sys.argv[2]))
diff --git a/build/detect_host_arch.py b/build/detect_host_arch.py
new file mode 100755
index 0000000..19579eb
--- /dev/null
+++ b/build/detect_host_arch.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Outputs host CPU architecture in format recognized by gyp."""
+
+import platform
+import re
+import sys
+
+
+def HostArch():
+  """Returns the host architecture with a predictable string."""
+  host_arch = platform.machine()
+
+  # Convert machine type to format recognized by gyp.
+  if re.match(r'i.86', host_arch) or host_arch == 'i86pc':
+    host_arch = 'ia32'
+  elif host_arch in ['x86_64', 'amd64']:
+    host_arch = 'x64'
+  elif host_arch.startswith('arm'):
+    host_arch = 'arm'
+
+  # platform.machine is based on running kernel. It's possible to use 64-bit
+  # kernel with 32-bit userland, e.g. to give linker slightly more memory.
+  # Distinguish between different userland bitness by querying
+  # the python binary.
+  if host_arch == 'x64' and platform.architecture()[0] == '32bit':
+    host_arch = 'ia32'
+
+  return host_arch
+
+def DoMain(_):
+  """Hook to be called from gyp without starting a separate python
+  interpreter."""
+  return HostArch()
+
+if __name__ == '__main__':
+  print DoMain([])
diff --git a/build/dir_exists.py b/build/dir_exists.py
new file mode 100755
index 0000000..70d367e
--- /dev/null
+++ b/build/dir_exists.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Writes True if the argument is a directory."""
+
+import os.path
+import sys
+
+def main():
+  sys.stdout.write(_is_dir(sys.argv[1]))
+  return 0
+
+def _is_dir(dir_name):
+  return str(os.path.isdir(dir_name))
+
+def DoMain(args):
+  """Hook to be called from gyp without starting a separate python
+  interpreter."""
+  return _is_dir(args[0])
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/download_gold_plugin.py b/build/download_gold_plugin.py
new file mode 100755
index 0000000..cd7ca41
--- /dev/null
+++ b/build/download_gold_plugin.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Script to download LLVM gold plugin from google storage."""
+
+import json
+import os
+import shutil
+import subprocess
+import sys
+import zipfile
+
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+CHROME_SRC = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
+sys.path.insert(0, os.path.join(CHROME_SRC, 'tools'))
+
+import find_depot_tools
+
+DEPOT_PATH = find_depot_tools.add_depot_tools_to_path()
+GSUTIL_PATH = os.path.join(DEPOT_PATH, 'gsutil.py')
+
+LLVM_BUILD_PATH = os.path.join(CHROME_SRC, 'third_party', 'llvm-build',
+                               'Release+Asserts')
+CLANG_UPDATE_PY = os.path.join(CHROME_SRC, 'tools', 'clang', 'scripts',
+                               'update.py')
+CLANG_REVISION = os.popen(CLANG_UPDATE_PY + ' --print-revision').read().rstrip()
+
+CLANG_BUCKET = 'gs://chromium-browser-clang/Linux_x64'
+
+def main():
+  targz_name = 'llvmgold-%s.tgz' % CLANG_REVISION
+  remote_path = '%s/%s' % (CLANG_BUCKET, targz_name)
+
+  os.chdir(LLVM_BUILD_PATH)
+
+  subprocess.check_call(['python', GSUTIL_PATH,
+                         'cp', remote_path, targz_name])
+  subprocess.check_call(['tar', 'xzf', targz_name])
+  os.remove(targz_name)
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/download_nacl_toolchains.py b/build/download_nacl_toolchains.py
new file mode 100755
index 0000000..b99b940
--- /dev/null
+++ b/build/download_nacl_toolchains.py
@@ -0,0 +1,59 @@
+#!/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.
+
+"""Shim to run nacl toolchain download script only if there is a nacl dir."""
+
+import os
+import shutil
+import sys
+
+
+def Main(args):
+  # Exit early if disable_nacl=1.
+  if 'disable_nacl=1' in os.environ.get('GYP_DEFINES', ''):
+    return 0
+  script_dir = os.path.dirname(os.path.abspath(__file__))
+  src_dir = os.path.dirname(script_dir)
+  nacl_dir = os.path.join(src_dir, 'native_client')
+  nacl_build_dir = os.path.join(nacl_dir, 'build')
+  package_version_dir = os.path.join(nacl_build_dir, 'package_version')
+  package_version = os.path.join(package_version_dir, 'package_version.py')
+  if not os.path.exists(package_version):
+    print "Can't find '%s'" % package_version
+    print 'Presumably you are intentionally building without NativeClient.'
+    print 'Skipping NativeClient toolchain download.'
+    sys.exit(0)
+  sys.path.insert(0, package_version_dir)
+  import package_version
+
+  # BUG:
+  # We remove this --optional-pnacl argument, and instead replace it with
+  # --no-pnacl for most cases.  However, if the bot name is an sdk
+  # bot then we will go ahead and download it.  This prevents increasing the
+  # gclient sync time for developers, or standard Chrome bots.
+  if '--optional-pnacl' in args:
+    args.remove('--optional-pnacl')
+    use_pnacl = False
+    buildbot_name = os.environ.get('BUILDBOT_BUILDERNAME', '')
+    if 'pnacl' in buildbot_name and 'sdk' in buildbot_name:
+      use_pnacl = True
+    if use_pnacl:
+      print '\n*** DOWNLOADING PNACL TOOLCHAIN ***\n'
+    else:
+      args = ['--exclude', 'pnacl_newlib'] + args
+
+  # Only download the ARM gcc toolchain if we are building for ARM
+  # TODO(olonho): we need to invent more reliable way to get build
+  # configuration info, to know if we're building for ARM.
+  if 'target_arch=arm' not in os.environ.get('GYP_DEFINES', ''):
+      args = ['--exclude', 'nacl_arm_newlib'] + args
+
+  package_version.main(args)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/build/download_sdk_extras.py b/build/download_sdk_extras.py
new file mode 100755
index 0000000..d7c5d6c
--- /dev/null
+++ b/build/download_sdk_extras.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Script to download sdk/extras packages on the bots from google storage.
+
+The script expects arguments that specify zips file in the google storage
+bucket named: <dir in SDK extras>_<package name>_<version>.zip. The file will
+be extracted in the android_tools/sdk/extras directory on the test bots. This
+script will not do anything for developers.
+
+TODO(navabi): Move this script (crbug.com/459819).
+"""
+
+import json
+import os
+import shutil
+import subprocess
+import sys
+import zipfile
+
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+CHROME_SRC = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
+sys.path.insert(0, os.path.join(SCRIPT_DIR, 'android'))
+sys.path.insert(1, os.path.join(CHROME_SRC, 'tools'))
+
+from pylib import constants
+import find_depot_tools
+
+DEPOT_PATH = find_depot_tools.add_depot_tools_to_path()
+GSUTIL_PATH = os.path.join(DEPOT_PATH, 'gsutil.py')
+SDK_EXTRAS_BUCKET = 'gs://chrome-sdk-extras'
+SDK_EXTRAS_PATH = os.path.join(constants.ANDROID_SDK_ROOT, 'extras')
+SDK_EXTRAS_JSON_FILE = os.path.join(os.path.dirname(__file__),
+                                    'android_sdk_extras.json')
+
+
+def clean_and_extract(dir_name, package_name, zip_file):
+  local_dir = '%s/%s/%s' % (SDK_EXTRAS_PATH, dir_name, package_name)
+  if os.path.exists(local_dir):
+    shutil.rmtree(local_dir)
+  local_zip = '%s/%s' % (SDK_EXTRAS_PATH, zip_file)
+  with zipfile.ZipFile(local_zip) as z:
+    z.extractall(path=SDK_EXTRAS_PATH)
+
+
+def main():
+  if not os.environ.get('CHROME_HEADLESS'):
+    # This is not a buildbot checkout.
+    return 0
+  # Update the android_sdk_extras.json file to update downloaded packages.
+  with open(SDK_EXTRAS_JSON_FILE) as json_file:
+    packages = json.load(json_file)
+  for package in packages:
+    local_zip = '%s/%s' % (SDK_EXTRAS_PATH, package['zip'])
+    if not os.path.exists(local_zip):
+      package_zip = '%s/%s' % (SDK_EXTRAS_BUCKET, package['zip'])
+      try:
+        subprocess.check_call(['python', GSUTIL_PATH, '--force-version', '4.7',
+                               'cp', package_zip, local_zip])
+      except subprocess.CalledProcessError:
+        print ('WARNING: Failed to download SDK packages. If this bot compiles '
+               'for Android, it may have errors.')
+        return 0
+    # Always clean dir and extract zip to ensure correct contents.
+    clean_and_extract(package['dir_name'], package['package'], package['zip'])
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/env_dump.py b/build/env_dump.py
new file mode 100755
index 0000000..21edfe6
--- /dev/null
+++ b/build/env_dump.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script can either source a file and dump the enironment changes done by
+# it, or just simply dump the current environment as JSON into a file.
+
+import json
+import optparse
+import os
+import pipes
+import subprocess
+import sys
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('-f', '--output-json',
+                    help='File to dump the environment as JSON into.')
+  parser.add_option(
+      '-d', '--dump-mode', action='store_true',
+      help='Dump the environment to sys.stdout and exit immediately.')
+
+  parser.disable_interspersed_args()
+  options, args = parser.parse_args()
+  if options.dump_mode:
+    if args or options.output_json:
+      parser.error('Cannot specify args or --output-json with --dump-mode.')
+    json.dump(dict(os.environ), sys.stdout)
+  else:
+    if not options.output_json:
+      parser.error('Requires --output-json option.')
+
+    envsetup_cmd = ' '.join(map(pipes.quote, args))
+    full_cmd = [
+        'bash', '-c',
+        '. %s > /dev/null; %s -d' % (envsetup_cmd, os.path.abspath(__file__))
+    ]
+    try:
+      output = subprocess.check_output(full_cmd)
+    except Exception as e:
+      sys.exit('Error running %s and dumping environment.' % envsetup_cmd)
+
+    env_diff = {}
+    new_env = json.loads(output)
+    for k, val in new_env.items():
+      if k == '_' or (k in os.environ and os.environ[k] == val):
+        continue
+      env_diff[k] = val
+    with open(options.output_json, 'w') as f:
+      json.dump(env_diff, f)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/extract_from_cab.py b/build/extract_from_cab.py
new file mode 100755
index 0000000..080370c
--- /dev/null
+++ b/build/extract_from_cab.py
@@ -0,0 +1,63 @@
+#!/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 a single file from a CAB archive."""
+
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+def run_quiet(*args):
+  """Run 'expand' suppressing noisy output. Returns returncode from process."""
+  popen = subprocess.Popen(args, stdout=subprocess.PIPE)
+  out, _ = popen.communicate()
+  if popen.returncode:
+    # expand emits errors to stdout, so if we fail, then print that out.
+    print out
+  return popen.returncode
+
+def main():
+  if len(sys.argv) != 4:
+    print 'Usage: extract_from_cab.py cab_path archived_file output_dir'
+    return 1
+
+  [cab_path, archived_file, output_dir] = sys.argv[1:]
+
+  # Expand.exe does its work in a fixed-named temporary directory created within
+  # the given output directory. This is a problem for concurrent extractions, so
+  # create a unique temp dir within the desired output directory to work around
+  # this limitation.
+  temp_dir = tempfile.mkdtemp(dir=output_dir)
+
+  try:
+    # Invoke the Windows expand utility to extract the file.
+    level = run_quiet('expand', cab_path, '-F:' + archived_file, temp_dir)
+    if level == 0:
+      # Move the output file into place, preserving expand.exe's behavior of
+      # paving over any preexisting file.
+      output_file = os.path.join(output_dir, archived_file)
+      try:
+        os.remove(output_file)
+      except OSError:
+        pass
+      os.rename(os.path.join(temp_dir, archived_file), output_file)
+  finally:
+    shutil.rmtree(temp_dir, True)
+
+  if level != 0:
+    return level
+
+  # The expand utility preserves the modification date and time of the archived
+  # file. Touch the extracted file. This helps build systems that compare the
+  # modification times of input and output files to determine whether to do an
+  # action.
+  os.utime(os.path.join(output_dir, archived_file), None)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/filename_rules.gypi b/build/filename_rules.gypi
new file mode 100644
index 0000000..48c8027
--- /dev/null
+++ b/build/filename_rules.gypi
@@ -0,0 +1,113 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This gypi file defines the patterns used for determining whether a
+# file is excluded from the build on a given platform.  It is
+# included by common.gypi for chromium_code.
+
+{
+  'target_conditions': [
+    ['OS!="win" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_win(_browsertest|_unittest)?\\.(h|cc)$'],
+                    ['exclude', '(^|/)win/'],
+                    ['exclude', '(^|/)win_[^/]*\\.(h|cc)$'] ],
+    }],
+    ['OS!="mac" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_(cocoa|mac)(_unittest)?\\.(h|cc|mm?)$'],
+                    ['exclude', '(^|/)(cocoa|mac)/'] ],
+    }],
+    ['OS!="ios" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_ios(_unittest)?\\.(h|cc|mm?)$'],
+                    ['exclude', '(^|/)ios/'] ],
+    }],
+    ['(OS!="mac" and OS!="ios") or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '\\.mm?$' ] ],
+    }],
+    # Do not exclude the linux files on *BSD since most of them can be
+    # shared at this point.
+    # In case a file is not needed, it is going to be excluded later on.
+    # TODO(evan): the above is not correct; we shouldn't build _linux
+    # files on non-linux.
+    ['OS!="linux" and OS!="openbsd" and OS!="freebsd" or >(nacl_untrusted_build)==1', {
+      'sources/': [
+        ['exclude', '_linux(_unittest)?\\.(h|cc)$'],
+        ['exclude', '(^|/)linux/'],
+      ],
+    }],
+    ['OS!="android" or _toolset=="host" or >(nacl_untrusted_build)==1', {
+      'sources/': [
+        ['exclude', '_android(_unittest)?\\.(h|cc)$'],
+        ['exclude', '(^|/)android/'],
+      ],
+    }],
+    ['OS=="win" and >(nacl_untrusted_build)==0', {
+      'sources/': [
+        ['exclude', '_posix(_unittest)?\\.(h|cc)$'],
+        ['exclude', '(^|/)posix/'],
+      ],
+    }],
+    ['<(chromeos)!=1 or >(nacl_untrusted_build)==1', {
+      'sources/': [
+        ['exclude', '_chromeos(_unittest)?\\.(h|cc)$'],
+        ['exclude', '(^|/)chromeos/'],
+      ],
+    }],
+    ['>(nacl_untrusted_build)==0', {
+      'sources/': [
+        ['exclude', '_nacl(_unittest)?\\.(h|cc)$'],
+      ],
+    }],
+    ['OS!="linux" and OS!="openbsd" and OS!="freebsd" or >(nacl_untrusted_build)==1', {
+      'sources/': [
+        ['exclude', '_xdg(_unittest)?\\.(h|cc)$'],
+      ],
+    }],
+    ['<(use_x11)!=1 or >(nacl_untrusted_build)==1', {
+      'sources/': [
+        ['exclude', '_(x|x11)(_interactive_uitest|_unittest)?\\.(h|cc)$'],
+        ['exclude', '(^|/)x11_[^/]*\\.(h|cc)$'],
+        ['exclude', '(^|/)x11/'],
+        ['exclude', '(^|/)x/'],
+      ],
+    }],
+    ['<(toolkit_views)==0 or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_views(_browsertest|_unittest)?\\.(h|cc)$'] ]
+    }],
+    ['<(use_aura)==0 or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_aura(_browsertest|_unittest)?\\.(h|cc)$'],
+                    ['exclude', '(^|/)aura/'],
+      ]
+    }],
+    ['<(use_aura)==0 or <(use_x11)==0 or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_aurax11(_browsertest|_unittest)?\\.(h|cc)$'] ]
+    }],
+    ['<(use_aura)==0 or OS!="win" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_aurawin\\.(h|cc)$'] ]
+    }],
+    ['<(use_aura)==0 or OS!="linux" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_auralinux\\.(h|cc)$'] ]
+    }],
+    ['<(use_ash)==0 or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_ash(_browsertest|_unittest)?\\.(h|cc)$'],
+                    ['exclude', '(^|/)ash/'],
+      ]
+    }],
+    ['<(use_ash)==0 or OS!="win" or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_ashwin\\.(h|cc)$'] ]
+    }],
+    ['<(use_ozone)==0 or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_ozone(_browsertest|_unittest)?\\.(h|cc)$'],
+                    ['exclude', '(^|/)ozone/'],
+      ]
+    }],
+    ['<(use_ozone_evdev)==0 or >(nacl_untrusted_build)==1', {
+      'sources/': [ ['exclude', '_evdev(_browsertest|_unittest)?\\.(h|cc)$'],
+                    ['exclude', '(^|/)evdev/'],
+      ]
+    }],
+    ['<(use_pango)==0', {
+      'sources/': [ ['exclude', '(^|_)pango(_util|_browsertest|_unittest)?\\.(h|cc)$'], ],
+    }],
+  ]
+}
diff --git a/build/find_isolated_tests.py b/build/find_isolated_tests.py
new file mode 100755
index 0000000..c5b3ab7
--- /dev/null
+++ b/build/find_isolated_tests.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Scans build output directory for .isolated files, calculates their SHA1
+hashes, stores final list in JSON document and then removes *.isolated files
+found (to ensure no stale *.isolated stay around on the next build).
+
+Used to figure out what tests were build in isolated mode to trigger these
+tests to run on swarming.
+
+For more info see:
+https://sites.google.com/a/chromium.org/dev/developers/testing/isolated-testing
+"""
+
+import glob
+import hashlib
+import json
+import optparse
+import os
+import re
+import sys
+
+
+def hash_file(filepath):
+  """Calculates the hash of a file without reading it all in memory at once."""
+  digest = hashlib.sha1()
+  with open(filepath, 'rb') as f:
+    while True:
+      chunk = f.read(1024*1024)
+      if not chunk:
+        break
+      digest.update(chunk)
+  return digest.hexdigest()
+
+
+def main():
+  parser = optparse.OptionParser(
+      usage='%prog --build-dir <path> --output-json <path>',
+      description=sys.modules[__name__].__doc__)
+  parser.add_option(
+      '--build-dir',
+      help='Path to a directory to search for *.isolated files.')
+  parser.add_option(
+      '--output-json',
+      help='File to dump JSON results into.')
+
+  options, _ = parser.parse_args()
+  if not options.build_dir:
+    parser.error('--build-dir option is required')
+  if not options.output_json:
+    parser.error('--output-json option is required')
+
+  result = {}
+
+  # Get the file hash values and output the pair.
+  pattern = os.path.join(options.build_dir, '*.isolated')
+  for filepath in sorted(glob.glob(pattern)):
+    test_name = os.path.splitext(os.path.basename(filepath))[0]
+    if re.match(r'^.+?\.\d$', test_name):
+      # It's a split .isolated file, e.g. foo.0.isolated. Ignore these.
+      continue
+
+    # TODO(csharp): Remove deletion once the isolate tracked dependencies are
+    # inputs for the isolated files.
+    sha1_hash = hash_file(filepath)
+    os.remove(filepath)
+    result[test_name] = sha1_hash
+
+  with open(options.output_json, 'wb') as f:
+    json.dump(result, f)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/gdb-add-index b/build/gdb-add-index
new file mode 100755
index 0000000..992ac16
--- /dev/null
+++ b/build/gdb-add-index
@@ -0,0 +1,162 @@
+#!/bin/bash
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Saves the gdb index for a given binary and its shared library dependencies.
+#
+# This will run gdb index in parallel on a number of binaries using SIGUSR1
+# as the communication mechanism to simulate a semaphore. Because of the
+# nature of this technique, using "set -e" is very difficult. The SIGUSR1
+# terminates a "wait" with an error which we need to interpret.
+#
+# When modifying this code, most of the real logic is in the index_one_file
+# function. The rest is cleanup + sempahore plumbing.
+
+# Cleanup temp directory and ensure all child jobs are dead-dead.
+function on_exit {
+  trap "" EXIT USR1  # Avoid reentrancy.
+
+  local jobs=$(jobs -p)
+  if [ -n "$jobs" ]; then
+    echo -n "Killing outstanding index jobs..."
+    kill -KILL $(jobs -p)
+    wait
+    echo "done"
+  fi
+
+  if [ -f "$DIRECTORY" ]; then
+    echo -n "Removing temp directory $DIRECTORY..."
+    rm -rf $DIRECTORY
+    echo done
+  fi
+}
+
+# Add index to one binary.
+function index_one_file {
+  local file=$1
+  local basename=$(basename "$file")
+  local should_index="${SHOULD_INDEX}"
+
+  local readelf_out=$(${TOOLCHAIN_PREFIX}readelf -S "$file")
+  if [[ $readelf_out =~ "gdb_index" ]]; then
+    if [ "${REMOVE_INDEX}" = 1 ]; then
+      ${TOOLCHAIN_PREFIX}objcopy --remove-section .gdb_index "$file"
+      echo "Removed index from $basename."
+    else
+      echo "Skipped $basename -- already contains index."
+      should_index=0
+    fi
+  fi
+
+  if [ "${should_index}" = 1 ]; then
+    local start=$(date +"%s%N")
+    echo "Adding index to $basename..."
+
+    ${TOOLCHAIN_PREFIX}gdb -batch "$file" -ex "save gdb-index $DIRECTORY" \
+      -ex "quit"
+    local index_file="$DIRECTORY/$basename.gdb-index"
+    if [ -f "$index_file" ]; then
+      ${TOOLCHAIN_PREFIX}objcopy --add-section .gdb_index="$index_file" \
+        --set-section-flags .gdb_index=readonly "$file" "$file"
+      local finish=$(date +"%s%N")
+      local elapsed=$(((finish - start)/1000000))
+      echo "   ...$basename indexed. [${elapsed}ms]"
+    else
+      echo "   ...$basename unindexable."
+    fi
+  fi
+}
+
+# Functions that when combined, concurrently index all files in FILES_TO_INDEX
+# array. The global FILES_TO_INDEX is declared in the main body of the script.
+function async_index {
+  # Start a background subshell to run the index command.
+  {
+    index_one_file $1
+    kill -SIGUSR1 $$  # $$ resolves to the parent script.
+    exit 129  # See comment above wait loop at bottom.
+  } &
+}
+
+CUR_FILE_NUM=0
+function index_next {
+  if (( CUR_FILE_NUM >= ${#FILES_TO_INDEX[@]} )); then
+    return
+  fi
+
+  async_index "${FILES_TO_INDEX[CUR_FILE_NUM]}"
+  ((CUR_FILE_NUM += 1)) || true
+}
+
+
+########
+### Main body of the script.
+
+REMOVE_INDEX=0
+SHOULD_INDEX=1
+while getopts ":f:r" opt; do
+  case $opt in
+    f)
+      REMOVE_INDEX=1
+      shift
+      ;;
+    r)
+      REMOVE_INDEX=1
+      SHOULD_INDEX=0
+      shift
+      ;;
+    *)
+      echo "Invalid option: -$OPTARG" >&2
+      ;;
+  esac
+done
+
+if [[ ! $# == 1 ]]; then
+  echo "Usage: $0 [-f] [-r] path-to-binary"
+  echo "  -f forces replacement of an existing index."
+  echo "  -r removes the index section."
+  exit 1
+fi
+
+FILENAME="$1"
+if [[ ! -f "$FILENAME" ]]; then
+  echo "Path $FILENAME does not exist."
+  exit 1
+fi
+
+# Ensure we cleanup on on exit.
+trap on_exit EXIT
+
+# We're good to go! Create temp directory for index files.
+DIRECTORY=$(mktemp -d)
+echo "Made temp directory $DIRECTORY."
+
+# Create array with the filename and all shared libraries that
+# have the same dirname. The dirname is a signal that these
+# shared libraries were part of the same build as the binary.
+declare -a FILES_TO_INDEX=($FILENAME
+ $(ldd "$FILENAME" 2>/dev/null \
+  | grep $(dirname "$FILENAME") \
+  | sed "s/.*[ \t]\(.*\) (.*/\1/")
+)
+
+# Start concurrent indexing.
+trap index_next USR1
+
+# 4 is an arbitrary default. When changing, remember we are likely IO bound
+# so basing this off the number of cores is not sensible.
+INDEX_TASKS=${INDEX_TASKS:-4}
+for ((i=0;i<${INDEX_TASKS};i++)); do
+  index_next
+done
+
+# Do a wait loop. Bash waits that terminate due a trap have an exit
+# code > 128. We also ensure that our subshell's "normal" exit occurs with
+# an exit code > 128. This allows us to do consider a > 128 exit code as
+# an indication that the loop should continue. Unfortunately, it also means
+# we cannot use set -e since technically the "wait" is failing.
+wait
+while (( $? > 128 )); do
+  wait
+done
diff --git a/build/get_landmines.py b/build/get_landmines.py
new file mode 100755
index 0000000..8f5b878
--- /dev/null
+++ b/build/get_landmines.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+This file emits the list of reasons why a particular build needs to be clobbered
+(or a list of 'landmines').
+"""
+
+import sys
+
+import landmine_utils
+
+
+builder = landmine_utils.builder
+distributor = landmine_utils.distributor
+gyp_defines = landmine_utils.gyp_defines
+gyp_msvs_version = landmine_utils.gyp_msvs_version
+platform = landmine_utils.platform
+
+
+def print_landmines():
+  """
+  ALL LANDMINES ARE EMITTED FROM HERE.
+  """
+  # DO NOT add landmines as part of a regular CL. Landmines are a last-effort
+  # bandaid fix if a CL that got landed has a build dependency bug and all bots
+  # need to be cleaned up. If you're writing a new CL that causes build
+  # dependency problems, fix the dependency problems instead of adding a
+  # landmine.
+
+  if (distributor() == 'goma' and platform() == 'win32' and
+      builder() == 'ninja'):
+    print 'Need to clobber winja goma due to backend cwd cache fix.'
+  if platform() == 'android':
+    print 'Clobber: to handle new way of suppressing findbugs failures.'
+    print 'Clobber to fix gyp not rename package name (crbug.com/457038)'
+  if platform() == 'win' and builder() == 'ninja':
+    print 'Compile on cc_unittests fails due to symbols removed in r185063.'
+  if platform() == 'linux' and builder() == 'ninja':
+    print 'Builders switching from make to ninja will clobber on this.'
+  if platform() == 'mac':
+    print 'Switching from bundle to unbundled dylib (issue 14743002).'
+  if platform() in ('win', 'mac'):
+    print ('Improper dependency for create_nmf.py broke in r240802, '
+           'fixed in r240860.')
+  if (platform() == 'win' and builder() == 'ninja' and
+      gyp_msvs_version() == '2012' and
+      gyp_defines().get('target_arch') == 'x64' and
+      gyp_defines().get('dcheck_always_on') == '1'):
+    print "Switched win x64 trybots from VS2010 to VS2012."
+  if (platform() == 'win' and builder() == 'ninja' and
+      gyp_msvs_version().startswith('2013')):
+    print "Switched win from VS2010 to VS2013."
+    print "Update to VS2013 Update 2."
+    print "Update to VS2013 Update 4."
+  print 'Need to clobber everything due to an IDL change in r154579 (blink)'
+  print 'Need to clobber everything due to gen file moves in r175513 (Blink)'
+  if (platform() != 'ios'):
+    print 'Clobber to get rid of obselete test plugin after r248358'
+    print 'Clobber to rebuild GN files for V8'
+  print 'Clobber to get rid of stale generated mojom.h files'
+  print 'Need to clobber everything due to build_nexe change in nacl r13424'
+  print '[chromium-dev] PSA: clobber build needed for IDR_INSPECTOR_* compil...'
+  print 'blink_resources.grd changed: crbug.com/400860'
+  print 'ninja dependency cycle: crbug.com/408192'
+  print 'Clobber to fix missing NaCl gyp dependencies (crbug.com/427427).'
+  print 'Another clobber for missing NaCl gyp deps (crbug.com/427427).'
+  print 'Clobber to fix GN not picking up increased ID range (crbug.com/444902)'
+  print 'Remove NaCl toolchains from the output dir (crbug.com/456902)'
+
+
+def main():
+  print_landmines()
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/get_sdk_extras_packages.py b/build/get_sdk_extras_packages.py
new file mode 100755
index 0000000..6d870cc
--- /dev/null
+++ b/build/get_sdk_extras_packages.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+import sys
+
+SDK_EXTRAS_JSON_FILE = os.path.join(os.path.dirname(__file__),
+                                    'android_sdk_extras.json')
+
+def main():
+  with open(SDK_EXTRAS_JSON_FILE) as json_file:
+    packages = json.load(json_file)
+  for package in packages:
+    print package['package'].replace('_', ' ')
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/get_syzygy_binaries.py b/build/get_syzygy_binaries.py
new file mode 100755
index 0000000..2577c7c
--- /dev/null
+++ b/build/get_syzygy_binaries.py
@@ -0,0 +1,451 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 utility script for downloading versioned Syzygy binaries."""
+
+import cStringIO
+import hashlib
+import errno
+import json
+import logging
+import optparse
+import os
+import re
+import shutil
+import stat
+import sys
+import subprocess
+import urllib2
+import zipfile
+
+
+_LOGGER = logging.getLogger(os.path.basename(__file__))
+
+# The URL where official builds are archived.
+_SYZYGY_ARCHIVE_URL = ('https://syzygy-archive.commondatastorage.googleapis.com'
+    '/builds/official/%(revision)s')
+
+# A JSON file containing the state of the download directory. If this file and
+# directory state do not agree, then the binaries will be downloaded and
+# installed again.
+_STATE = '.state'
+
+# This matches an integer (an SVN revision number) or a SHA1 value (a GIT hash).
+# The archive exclusively uses lowercase GIT hashes.
+_REVISION_RE = re.compile('^(?:\d+|[a-f0-9]{40})$')
+
+# This matches an MD5 hash.
+_MD5_RE = re.compile('^[a-f0-9]{32}$')
+
+# List of reources to be downloaded and installed. These are tuples with the
+# following format:
+# (basename, logging name, relative installation path, extraction filter)
+_RESOURCES = [
+  ('benchmark.zip', 'benchmark', '', None),
+  ('binaries.zip', 'binaries', 'exe', None),
+  ('symbols.zip', 'symbols', 'exe',
+      lambda x: x.filename.endswith('.dll.pdb'))]
+
+
+def _Shell(*cmd, **kw):
+  """Runs |cmd|, returns the results from Popen(cmd).communicate()."""
+  _LOGGER.debug('Executing %s.', cmd)
+  prog = subprocess.Popen(cmd, shell=True, **kw)
+
+  stdout, stderr = prog.communicate()
+  if prog.returncode != 0:
+    raise RuntimeError('Command "%s" returned %d.' % (cmd, prog.returncode))
+  return (stdout, stderr)
+
+
+def _LoadState(output_dir):
+  """Loads the contents of the state file for a given |output_dir|, returning
+  None if it doesn't exist.
+  """
+  path = os.path.join(output_dir, _STATE)
+  if not os.path.exists(path):
+    _LOGGER.debug('No state file found.')
+    return None
+  with open(path, 'rb') as f:
+    _LOGGER.debug('Reading state file: %s', path)
+    try:
+      return json.load(f)
+    except ValueError:
+      _LOGGER.debug('Invalid state file.')
+      return None
+
+
+def _SaveState(output_dir, state, dry_run=False):
+  """Saves the |state| dictionary to the given |output_dir| as a JSON file."""
+  path = os.path.join(output_dir, _STATE)
+  _LOGGER.debug('Writing state file: %s', path)
+  if dry_run:
+    return
+  with open(path, 'wb') as f:
+    f.write(json.dumps(state, sort_keys=True, indent=2))
+
+
+def _Md5(path):
+  """Returns the MD5 hash of the file at |path|, which must exist."""
+  return hashlib.md5(open(path, 'rb').read()).hexdigest()
+
+
+def _StateIsValid(state):
+  """Returns true if the given state structure is valid."""
+  if not isinstance(state, dict):
+    _LOGGER.debug('State must be a dict.')
+    return False
+  r = state.get('revision', None)
+  if not isinstance(r, basestring) or not _REVISION_RE.match(r):
+    _LOGGER.debug('State contains an invalid revision.')
+    return False
+  c = state.get('contents', None)
+  if not isinstance(c, dict):
+    _LOGGER.debug('State must contain a contents dict.')
+    return False
+  for (relpath, md5) in c.iteritems():
+    if not isinstance(relpath, basestring) or len(relpath) == 0:
+      _LOGGER.debug('State contents dict contains an invalid path.')
+      return False
+    if not isinstance(md5, basestring) or not _MD5_RE.match(md5):
+      _LOGGER.debug('State contents dict contains an invalid MD5 digest.')
+      return False
+  return True
+
+
+def _BuildActualState(stored, revision, output_dir):
+  """Builds the actual state using the provided |stored| state as a template.
+  Only examines files listed in the stored state, causing the script to ignore
+  files that have been added to the directories locally. |stored| must be a
+  valid state dictionary.
+  """
+  contents = {}
+  state = { 'revision': revision, 'contents': contents }
+  for relpath, md5 in stored['contents'].iteritems():
+    abspath = os.path.abspath(os.path.join(output_dir, relpath))
+    if os.path.isfile(abspath):
+      m = _Md5(abspath)
+      contents[relpath] = m
+
+  return state
+
+
+def _StatesAreConsistent(stored, actual):
+  """Validates whether two state dictionaries are consistent. Both must be valid
+  state dictionaries. Additional entries in |actual| are ignored.
+  """
+  if stored['revision'] != actual['revision']:
+    _LOGGER.debug('Mismatched revision number.')
+    return False
+  cont_stored = stored['contents']
+  cont_actual = actual['contents']
+  for relpath, md5 in cont_stored.iteritems():
+    if relpath not in cont_actual:
+      _LOGGER.debug('Missing content: %s', relpath)
+      return False
+    if md5 != cont_actual[relpath]:
+      _LOGGER.debug('Modified content: %s', relpath)
+      return False
+  return True
+
+
+def _GetCurrentState(revision, output_dir):
+  """Loads the current state and checks to see if it is consistent. Returns
+  a tuple (state, bool). The returned state will always be valid, even if an
+  invalid state is present on disk.
+  """
+  stored = _LoadState(output_dir)
+  if not _StateIsValid(stored):
+    _LOGGER.debug('State is invalid.')
+    # Return a valid but empty state.
+    return ({'revision': '0', 'contents': {}}, False)
+  actual = _BuildActualState(stored, revision, output_dir)
+  # If the script has been modified consider the state invalid.
+  path = os.path.join(output_dir, _STATE)
+  if os.path.getmtime(__file__) > os.path.getmtime(path):
+    return (stored, False)
+  # Otherwise, explicitly validate the state.
+  if not _StatesAreConsistent(stored, actual):
+    return (stored, False)
+  return (stored, True)
+
+
+def _DirIsEmpty(path):
+  """Returns true if the given directory is empty, false otherwise."""
+  for root, dirs, files in os.walk(path):
+    return not dirs and not files
+
+
+def _RmTreeHandleReadOnly(func, path, exc):
+  """An error handling function for use with shutil.rmtree. This will
+  detect failures to remove read-only files, and will change their properties
+  prior to removing them. This is necessary on Windows as os.remove will return
+  an access error for read-only files, and git repos contain read-only
+  pack/index files.
+  """
+  excvalue = exc[1]
+  if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
+    _LOGGER.debug('Removing read-only path: %s', path)
+    os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
+    func(path)
+  else:
+    raise
+
+
+def _RmTree(path):
+  """A wrapper of shutil.rmtree that handles read-only files."""
+  shutil.rmtree(path, ignore_errors=False, onerror=_RmTreeHandleReadOnly)
+
+
+def _CleanState(output_dir, state, dry_run=False):
+  """Cleans up files/directories in |output_dir| that are referenced by
+  the given |state|. Raises an error if there are local changes. Returns a
+  dictionary of files that were deleted.
+  """
+  _LOGGER.debug('Deleting files from previous installation.')
+  deleted = {}
+
+  # Generate a list of files to delete, relative to |output_dir|.
+  contents = state['contents']
+  files = sorted(contents.keys())
+
+  # Try to delete the files. Keep track of directories to delete as well.
+  dirs = {}
+  for relpath in files:
+    fullpath = os.path.join(output_dir, relpath)
+    fulldir = os.path.dirname(fullpath)
+    dirs[fulldir] = True
+    if os.path.exists(fullpath):
+      # If somehow the file has become a directory complain about it.
+      if os.path.isdir(fullpath):
+        raise Exception('Directory exists where file expected: %s' % fullpath)
+
+      # Double check that the file doesn't have local changes. If it does
+      # then refuse to delete it.
+      if relpath in contents:
+        stored_md5 = contents[relpath]
+        actual_md5 = _Md5(fullpath)
+        if actual_md5 != stored_md5:
+          raise Exception('File has local changes: %s' % fullpath)
+
+      # The file is unchanged so it can safely be deleted.
+      _LOGGER.debug('Deleting file "%s".', fullpath)
+      deleted[relpath] = True
+      if not dry_run:
+        os.unlink(fullpath)
+
+  # Sort directories from longest name to shortest. This lets us remove empty
+  # directories from the most nested paths first.
+  dirs = sorted(dirs.keys(), key=lambda x: len(x), reverse=True)
+  for p in dirs:
+    if os.path.exists(p) and _DirIsEmpty(p):
+      _LOGGER.debug('Deleting empty directory "%s".', p)
+      if not dry_run:
+        _RmTree(p)
+
+  return deleted
+
+
+def _Download(url):
+  """Downloads the given URL and returns the contents as a string."""
+  response = urllib2.urlopen(url)
+  if response.code != 200:
+    raise RuntimeError('Failed to download "%s".' % url)
+  return response.read()
+
+
+def _InstallBinaries(options, deleted={}):
+  """Installs Syzygy binaries. This assumes that the output directory has
+  already been cleaned, as it will refuse to overwrite existing files."""
+  contents = {}
+  state = { 'revision': options.revision, 'contents': contents }
+  archive_url = _SYZYGY_ARCHIVE_URL % { 'revision': options.revision }
+  if options.resources:
+    resources = [(resource, resource, '', None)
+                 for resource in options.resources]
+  else:
+    resources = _RESOURCES
+  for (base, name, subdir, filt) in resources:
+    # Create the output directory if it doesn't exist.
+    fulldir = os.path.join(options.output_dir, subdir)
+    if os.path.isfile(fulldir):
+      raise Exception('File exists where a directory needs to be created: %s' %
+                      fulldir)
+    if not os.path.exists(fulldir):
+      _LOGGER.debug('Creating directory: %s', fulldir)
+      if not options.dry_run:
+        os.makedirs(fulldir)
+
+    # Download the archive.
+    url = archive_url + '/' + base
+    _LOGGER.debug('Retrieving %s archive at "%s".', name, url)
+    data = _Download(url)
+
+    _LOGGER.debug('Unzipping %s archive.', name)
+    archive = zipfile.ZipFile(cStringIO.StringIO(data))
+    for entry in archive.infolist():
+      if not filt or filt(entry):
+        fullpath = os.path.normpath(os.path.join(fulldir, entry.filename))
+        relpath = os.path.relpath(fullpath, options.output_dir)
+        if os.path.exists(fullpath):
+          # If in a dry-run take into account the fact that the file *would*
+          # have been deleted.
+          if options.dry_run and relpath in deleted:
+            pass
+          else:
+            raise Exception('Path already exists: %s' % fullpath)
+
+        # Extract the file and update the state dictionary.
+        _LOGGER.debug('Extracting "%s".', fullpath)
+        if not options.dry_run:
+          archive.extract(entry.filename, fulldir)
+          md5 = _Md5(fullpath)
+          contents[relpath] = md5
+          if sys.platform == 'cygwin':
+            os.chmod(fullpath, os.stat(fullpath).st_mode | stat.S_IXUSR)
+
+  return state
+
+
+def _ParseCommandLine():
+  """Parses the command-line and returns an options structure."""
+  option_parser = optparse.OptionParser()
+  option_parser.add_option('--dry-run', action='store_true', default=False,
+      help='If true then will simply list actions that would be performed.')
+  option_parser.add_option('--force', action='store_true', default=False,
+      help='Force an installation even if the binaries are up to date.')
+  option_parser.add_option('--output-dir', type='string',
+      help='The path where the binaries will be replaced. Existing binaries '
+           'will only be overwritten if not up to date.')
+  option_parser.add_option('--overwrite', action='store_true', default=False,
+      help='If specified then the installation will happily delete and rewrite '
+           'the entire output directory, blasting any local changes.')
+  option_parser.add_option('--revision', type='string',
+      help='The SVN revision or GIT hash associated with the required version.')
+  option_parser.add_option('--revision-file', type='string',
+      help='A text file containing an SVN revision or GIT hash.')
+  option_parser.add_option('--resource', type='string', action='append',
+      dest='resources', help='A resource to be downloaded.')
+  option_parser.add_option('--verbose', dest='log_level', action='store_const',
+      default=logging.INFO, const=logging.DEBUG,
+      help='Enables verbose logging.')
+  option_parser.add_option('--quiet', dest='log_level', action='store_const',
+      default=logging.INFO, const=logging.ERROR,
+      help='Disables all output except for errors.')
+  options, args = option_parser.parse_args()
+  if args:
+    option_parser.error('Unexpected arguments: %s' % args)
+  if not options.output_dir:
+    option_parser.error('Must specify --output-dir.')
+  if not options.revision and not options.revision_file:
+    option_parser.error('Must specify one of --revision or --revision-file.')
+  if options.revision and options.revision_file:
+    option_parser.error('Must not specify both --revision and --revision-file.')
+
+  # Configure logging.
+  logging.basicConfig(level=options.log_level)
+
+  # If a revision file has been specified then read it.
+  if options.revision_file:
+    options.revision = open(options.revision_file, 'rb').read().strip()
+    _LOGGER.debug('Parsed revision "%s" from file "%s".',
+                 options.revision, options.revision_file)
+
+  # Ensure that the specified SVN revision or GIT hash is valid.
+  if not _REVISION_RE.match(options.revision):
+    option_parser.error('Must specify a valid SVN or GIT revision.')
+
+  # This just makes output prettier to read.
+  options.output_dir = os.path.normpath(options.output_dir)
+
+  return options
+
+
+def _RemoveOrphanedFiles(options):
+  """This is run on non-Windows systems to remove orphaned files that may have
+  been downloaded by a previous version of this script.
+  """
+  # Reconfigure logging to output info messages. This will allow inspection of
+  # cleanup status on non-Windows buildbots.
+  _LOGGER.setLevel(logging.INFO)
+
+  output_dir = os.path.abspath(options.output_dir)
+
+  # We only want to clean up the folder in 'src/third_party/syzygy', and we
+  # expect to be called with that as an output directory. This is an attempt to
+  # not start deleting random things if the script is run from an alternate
+  # location, or not called from the gclient hooks.
+  expected_syzygy_dir = os.path.abspath(os.path.join(
+      os.path.dirname(__file__), '..', 'third_party', 'syzygy'))
+  expected_output_dir = os.path.join(expected_syzygy_dir, 'binaries')
+  if expected_output_dir != output_dir:
+    _LOGGER.info('Unexpected output directory, skipping cleanup.')
+    return
+
+  if not os.path.isdir(expected_syzygy_dir):
+    _LOGGER.info('Output directory does not exist, skipping cleanup.')
+    return
+
+  def OnError(function, path, excinfo):
+    """Logs error encountered by shutil.rmtree."""
+    _LOGGER.error('Error when running %s(%s)', function, path, exc_info=excinfo)
+
+  _LOGGER.info('Removing orphaned files from %s', expected_syzygy_dir)
+  if not options.dry_run:
+    shutil.rmtree(expected_syzygy_dir, True, OnError)
+
+
+def main():
+  options = _ParseCommandLine()
+
+  if options.dry_run:
+    _LOGGER.debug('Performing a dry-run.')
+
+  # We only care about Windows platforms, as the Syzygy binaries aren't used
+  # elsewhere. However, there was a short period of time where this script
+  # wasn't gated on OS types, and those OSes downloaded and installed binaries.
+  # This will cleanup orphaned files on those operating systems.
+  if sys.platform not in ('win32', 'cygwin'):
+    return _RemoveOrphanedFiles(options)
+
+  # Load the current installation state, and validate it against the
+  # requested installation.
+  state, is_consistent = _GetCurrentState(options.revision, options.output_dir)
+
+  # Decide whether or not an install is necessary.
+  if options.force:
+    _LOGGER.debug('Forcing reinstall of binaries.')
+  elif is_consistent:
+    # Avoid doing any work if the contents of the directory are consistent.
+    _LOGGER.debug('State unchanged, no reinstall necessary.')
+    return
+
+  # Under normal logging this is the only only message that will be reported.
+  _LOGGER.info('Installing revision %s Syzygy binaries.',
+               options.revision[0:12])
+
+  # Clean up the old state to begin with.
+  deleted = []
+  if options.overwrite:
+    if os.path.exists(options.output_dir):
+      # If overwrite was specified then take a heavy-handed approach.
+      _LOGGER.debug('Deleting entire installation directory.')
+      if not options.dry_run:
+        _RmTree(options.output_dir)
+  else:
+    # Otherwise only delete things that the previous installation put in place,
+    # and take care to preserve any local changes.
+    deleted = _CleanState(options.output_dir, state, options.dry_run)
+
+  # Install the new binaries. In a dry-run this will actually download the
+  # archives, but it won't write anything to disk.
+  state = _InstallBinaries(options, deleted)
+
+  # Build and save the state for the directory.
+  _SaveState(options.output_dir, state, options.dry_run)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/git-hooks/OWNERS b/build/git-hooks/OWNERS
new file mode 100644
index 0000000..3e327dc
--- /dev/null
+++ b/build/git-hooks/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+szager@chromium.org
+cmp@chromium.org
diff --git a/build/git-hooks/pre-commit b/build/git-hooks/pre-commit
new file mode 100755
index 0000000..41b5963
--- /dev/null
+++ b/build/git-hooks/pre-commit
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+submodule_diff() {
+  if test -n "$2"; then
+    git diff-tree -r --ignore-submodules=dirty "$1" "$2" | grep -e '^:160000' -e '^:...... 160000' | xargs
+  else
+    git diff-index --cached --ignore-submodules=dirty "$1" | grep -e '^:160000' -e '^:...... 160000' | xargs
+  fi
+}
+
+if git rev-parse --verify --quiet --no-revs MERGE_HEAD; then
+  merge_base=$(git merge-base HEAD MERGE_HEAD)
+  if test -z "$(submodule_diff $merge_base HEAD)"; then
+    # Most up-to-date submodules are in MERGE_HEAD.
+    head_ref=MERGE_HEAD
+  else
+    # Most up-to-date submodules are in HEAD.
+    head_ref=HEAD
+  fi
+else
+  # No merge in progress. Submodules must match HEAD.
+  head_ref=HEAD
+fi
+
+submods=$(submodule_diff $head_ref)
+if test "$submods"; then
+  echo "You are trying to commit changes to the following submodules:" 1>&2
+  echo 1>&2
+  echo $submods | cut -d ' ' -f 6 | sed 's/^/  /g' 1>&2
+  cat <<EOF 1>&2
+
+Submodule commits are not allowed.  Please run:
+
+  git status --ignore-submodules=dirty
+
+and/or:
+
+  git diff-index --cached --ignore-submodules=dirty HEAD
+
+... to see what's in your index.
+
+If you're really and truly trying to roll the version of a submodule, you should
+commit the new version to DEPS, instead.
+EOF
+  exit 1
+fi
+
+gitmodules_diff() {
+  git diff-index --cached "$1" .gitmodules
+}
+
+if [ "$(git ls-files .gitmodules)" ] && [ "$(gitmodules_diff $head_ref)" ]; then
+  cat <<EOF 1>&2
+You are trying to commit a change to .gitmodules.  That is not allowed.
+To make changes to submodule names/paths, edit DEPS.
+EOF
+  exit 1
+fi
+
+exit 0
diff --git a/build/gn_helpers.py b/build/gn_helpers.py
new file mode 100644
index 0000000..3b0647d
--- /dev/null
+++ b/build/gn_helpers.py
@@ -0,0 +1,39 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper functions useful when writing scripts that are run from GN's
+exec_script function."""
+
+class GNException(Exception):
+  pass
+
+
+def ToGNString(value, allow_dicts = True):
+  """Prints the given value to stdout.
+
+  allow_dicts indicates if this function will allow converting dictionaries
+  to GN scopes. This is only possible at the top level, you can't nest a
+  GN scope in a list, so this should be set to False for recursive calls."""
+  if isinstance(value, str):
+    if value.find('\n') >= 0:
+      raise GNException("Trying to print a string with a newline in it.")
+    return '"' + value.replace('"', '\\"') + '"'
+
+  if isinstance(value, list):
+    return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
+
+  if isinstance(value, dict):
+    if not allow_dicts:
+      raise GNException("Attempting to recursively print a dictionary.")
+    result = ""
+    for key in value:
+      if not isinstance(key, str):
+        raise GNException("Dictionary key is not a string.")
+      result += "%s = %s\n" % (key, ToGNString(value[key], False))
+    return result
+
+  if isinstance(value, int):
+    return str(value)
+
+  raise GNException("Unsupported type when printing to GN.")
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
new file mode 100644
index 0000000..4257cc0
--- /dev/null
+++ b/build/gn_migration.gypi
@@ -0,0 +1,678 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file defines five targets that we are using to track the progress of the
+# GYP->GN migration:
+#
+# 'both_gn_and_gyp' lists what GN is currently capable of building and should
+# match the 'both_gn_and_gyp' target in //BUILD.gn.
+#
+# 'gyp_all' Should include everything built when building "all"; i.e., if you
+# type 'ninja gyp_all' and then 'ninja all', the second build should do
+# nothing. 'gyp_all' should just depend on the other four targets.
+#
+# 'gyp_only' lists any targets that are not meant to be ported over to the GN
+# build.
+#
+# 'gyp_remaining' lists all of the targets that still need to be converted,
+# i.e., all of the other (non-empty) targets that a GYP build will build.
+#
+# TODO(GYP): crbug.com/481694. Add a build step to the bot that enforces the
+# above contracts.
+
+{
+  'targets': [
+    {
+      'target_name': 'gyp_all',
+      'type': 'none',
+      'dependencies': [
+        'both_gn_and_gyp',
+        'gyp_only',
+        'gyp_remaining',
+      ]
+    },
+    {
+      # This target should mirror the structure of //:both_gn_and_gyp
+      # in src/BUILD.gn as closely as possible, for ease of comparison.
+      'target_name': 'both_gn_and_gyp',
+      'type': 'none',
+      'dependencies': [
+        '../base/base.gyp:base_i18n_perftests',
+        '../base/base.gyp:base_perftests',
+        '../base/base.gyp:base_unittests',
+        '../base/base.gyp:build_utf8_validator_tables#host',
+        '../base/base.gyp:check_example',
+        '../cc/cc_tests.gyp:cc_perftests',
+        '../cc/cc_tests.gyp:cc_unittests',
+        '../cc/blink/cc_blink_tests.gyp:cc_blink_unittests',
+        '../chrome/chrome.gyp:chrome',
+        '../chrome/chrome.gyp:browser_tests',
+        '../chrome/chrome.gyp:chrome_app_unittests',
+        '../chrome/chrome.gyp:chromedriver',
+        '../chrome/chrome.gyp:chromedriver_tests',
+        '../chrome/chrome.gyp:chromedriver_unittests',
+        '../chrome/chrome.gyp:interactive_ui_tests',
+        '../chrome/chrome.gyp:load_library_perf_tests',
+        '../chrome/chrome.gyp:performance_browser_tests',
+        '../chrome/chrome.gyp:sync_integration_tests',
+        '../chrome/chrome.gyp:sync_performance_tests',
+        '../chrome/chrome.gyp:unit_tests',
+        '../chrome/tools/profile_reset/jtl_compiler.gyp:jtl_compiler',
+        '../cloud_print/cloud_print.gyp:cloud_print_unittests',
+        '../components/components.gyp:network_hints_browser',
+        '../components/components.gyp:policy_templates',
+        '../components/components.gyp:webui_generator',
+        '../components/components_tests.gyp:components_browsertests',
+        '../components/components_tests.gyp:components_perftests',
+        '../components/components_tests.gyp:components_unittests',
+        '../content/content.gyp:content_app_browser',
+        '../content/content.gyp:content_app_child',
+        '../content/content_shell_and_tests.gyp:content_browsertests',
+        '../content/content_shell_and_tests.gyp:content_gl_benchmark',
+        '../content/content_shell_and_tests.gyp:content_gl_tests',
+        '../content/content_shell_and_tests.gyp:content_perftests',
+        '../content/content_shell_and_tests.gyp:content_shell',
+        '../content/content_shell_and_tests.gyp:content_unittests',
+        '../courgette/courgette.gyp:courgette',
+        '../courgette/courgette.gyp:courgette_fuzz',
+        '../courgette/courgette.gyp:courgette_minimal_tool',
+        '../courgette/courgette.gyp:courgette_unittests',
+        '../crypto/crypto.gyp:crypto_unittests',
+        '../extensions/extensions_tests.gyp:extensions_browsertests',
+        '../extensions/extensions_tests.gyp:extensions_unittests',
+        '../device/device_tests.gyp:device_unittests',
+        '../gin/gin.gyp:gin_v8_snapshot_fingerprint',
+        '../gin/gin.gyp:gin_shell',
+        '../gin/gin.gyp:gin_unittests',
+        '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+        '../google_apis/gcm/gcm.gyp:mcs_probe',
+        '../google_apis/google_apis.gyp:google_apis_unittests',
+        '../gpu/gpu.gyp:angle_unittests',
+        '../gpu/gpu.gyp:gl_tests',
+        '../gpu/gpu.gyp:gpu_perftests',
+        '../gpu/gpu.gyp:gpu_unittests',
+        '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support',  # TODO(GYP) crbug.com/471920
+        '../gpu/gles2_conform_support/gles2_conform_test.gyp:gles2_conform_test',  # TODO(GYP) crbug.com/471920
+        '../gpu/khronos_glcts_support/khronos_glcts_test.gyp:khronos_glcts_test',  # TODO(GYP) crbug.com/471903 to make this complete.
+        '../ipc/ipc.gyp:ipc_perftests',
+        '../ipc/ipc.gyp:ipc_tests',
+        '../ipc/mojo/ipc_mojo.gyp:ipc_mojo_unittests',
+        '../jingle/jingle.gyp:jingle_unittests',
+        '../media/media.gyp:ffmpeg_regression_tests',  # TODO(GYP) this should be conditional on media_use_ffmpeg
+        '../media/media.gyp:media_perftests',
+        '../media/media.gyp:media_unittests',
+        '../media/midi/midi.gyp:midi_unittests',
+        '../media/cast/cast.gyp:cast_benchmarks',
+        '../media/cast/cast.gyp:cast_unittests',
+        '../media/cast/cast.gyp:generate_barcode_video',
+        '../media/cast/cast.gyp:generate_timecode_audio',
+        '../mojo/mojo.gyp:mojo',
+        '../mojo/mojo_base.gyp:mojo_application_chromium',
+        '../mojo/mojo_base.gyp:mojo_common_unittests',
+        '../net/net.gyp:crash_cache',
+        '../net/net.gyp:crl_set_dump',
+        '../net/net.gyp:dns_fuzz_stub',
+        '../net/net.gyp:dump_cache',
+        '../net/net.gyp:gdig',
+        '../net/net.gyp:get_server_time',
+        '../net/net.gyp:hpack_example_generator',
+        '../net/net.gyp:hpack_fuzz_mutator',
+        '../net/net.gyp:hpack_fuzz_wrapper',
+        '../net/net.gyp:net_perftests',
+        '../net/net.gyp:net_unittests',
+        '../net/net.gyp:net_watcher',  # TODO(GYP): This should be conditional on use_v8_in_net
+        '../net/net.gyp:run_testserver',
+        '../net/net.gyp:stress_cache',
+        '../net/net.gyp:tld_cleanup',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_audio',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_audio_input',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_c_stub',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_cc_stub',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_compositor',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_crxfs',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_enumerate_devices',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_file_chooser',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_flash_topmost',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_gamepad',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_gles2',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_gles2_spinning_cube',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_graphics_2d',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_ime',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_input',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_media_stream_audio',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_media_stream_video',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_mouse_cursor',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_mouse_lock',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_paint_manager',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_post_message',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_printing',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_scaling',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_scroll',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_simple_font',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_threading',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_url_loader',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_url_loader_file',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_vc',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_video_decode_dev',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_video_effects',
+        '../ppapi/ppapi_internal.gyp:ppapi_example_video_encode',
+        '../ppapi/ppapi_internal.gyp:ppapi_tests',
+        '../ppapi/ppapi_internal.gyp:ppapi_perftests',
+        '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+        '../ppapi/tools/ppapi_tools.gyp:pepper_hash_for_uma',
+        '../printing/printing.gyp:printing_unittests',
+        '../skia/skia_tests.gyp:skia_unittests',
+        '../skia/skia.gyp:filter_fuzz_stub',
+        '../skia/skia.gyp:image_operations_bench',
+        '../sql/sql.gyp:sql_unittests',
+        '../sync/sync.gyp:run_sync_testserver',
+        '../sync/sync.gyp:sync_endtoend_tests',
+        '../sync/sync.gyp:sync_unit_tests',
+        '../sync/tools/sync_tools.gyp:sync_client',
+        '../sync/tools/sync_tools.gyp:sync_listen_notifications',
+        '../testing/gmock.gyp:gmock_main',
+        '../third_party/WebKit/public/all.gyp:blink_tests',
+        '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
+        '../third_party/codesighs/codesighs.gyp:codesighs',
+        '../third_party/codesighs/codesighs.gyp:maptsvdifftool',
+        '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
+        '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
+        '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
+        '../third_party/mojo/mojo_edk_tests.gyp:mojo_system_unittests',
+        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
+        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_environment_unittests',
+        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_perftests',
+        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_system_unittests',
+        '../third_party/mojo/mojo_edk_tests.gyp:mojo_public_utility_unittests',
+        '../third_party/pdfium/samples/samples.gyp:pdfium_diff',
+        '../third_party/pdfium/samples/samples.gyp:pdfium_test',
+        '../third_party/smhasher/smhasher.gyp:pmurhash',
+        '../tools/gn/gn.gyp:gn',
+        '../tools/gn/gn.gyp:generate_test_gn_data',
+        '../tools/gn/gn.gyp:gn_unittests',
+        '../tools/imagediff/image_diff.gyp:image_diff',
+        '../tools/perf/clear_system_cache/clear_system_cache.gyp:clear_system_cache',
+        '../tools/telemetry/telemetry.gyp:bitmaptools#host',
+        '../ui/accessibility/accessibility.gyp:accessibility_unittests',
+        '../ui/app_list/app_list.gyp:app_list_unittests',
+        '../ui/base/ui_base_tests.gyp:ui_base_unittests',
+        '../ui/compositor/compositor.gyp:compositor_unittests',
+        '../ui/display/display.gyp:display_unittests',
+        '../ui/events/events.gyp:events_unittests',
+        '../ui/gfx/gfx_tests.gyp:gfx_unittests',
+        '../ui/gl/gl_tests.gyp:gl_unittests',
+        '../ui/message_center/message_center.gyp:message_center_unittests',
+        '../ui/snapshot/snapshot.gyp:snapshot_unittests',
+        '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
+        '../ui/views/examples/examples.gyp:views_examples_with_content_exe',
+        '../url/url.gyp:url_unittests',
+        '../v8/tools/gyp/v8.gyp:v8_snapshot',
+        '../v8/tools/gyp/v8.gyp:postmortem-metadata',
+      ],
+      'conditions': [
+        ['clang==1', {
+          'dependencies': [
+            '../build/sanitizers/sanitizers.gyp:llvm-symbolizer',
+          ],
+        }],
+        ['disable_nacl==0 and disable_nacl_untrusted==0', {
+          'dependencies': [
+            '../components/nacl.gyp:nacl_loader_unittests',
+          ]
+        }],
+        ['enable_extensions==1 and OS!="mac"', {
+          'dependencies': [
+            '../extensions/shell/app_shell.gyp:app_shell',
+            '../extensions/shell/app_shell.gyp:app_shell_unittests',
+          ],
+        }],
+        ['enable_mdns==1', {
+          'dependencies': [
+            '../chrome/chrome.gyp:service_discovery_sniffer',
+          ]
+        }],
+        ['remoting==1', {
+          'dependencies': [
+            '../remoting/remoting_all.gyp:remoting_all',
+          ],
+        }],
+        ['remoting==1 and chromeos==0', {
+          'dependencies': [
+            '../remoting/remoting.gyp:remoting_me2me_host',
+            '../remoting/remoting.gyp:remoting_me2me_native_messaging_host',
+          ],
+        }],
+        ['toolkit_views==1', {
+          'dependencies': [
+            '../ui/app_list/app_list.gyp:app_list_demo',
+            '../ui/views/views.gyp:views_unittests',
+          ],
+        }],
+        ['use_ash==1', {
+          'dependencies': [
+            '../ash/ash.gyp:ash_shell',
+            '../ash/ash.gyp:ash_shell_unittests',
+            '../ash/ash.gyp:ash_unittests',
+          ],
+        }],
+        ['use_ash==1 or chromeos== 1', {
+          'dependencies': [
+            '../components/components.gyp:session_manager_component',
+          ]
+        }],
+        ['use_aura==1', {
+          'dependencies': [
+            '../ui/aura/aura.gyp:aura_bench',
+            '../ui/aura/aura.gyp:aura_demo',
+            '../ui/aura/aura.gyp:aura_unittests',
+            '../ui/keyboard/keyboard.gyp:keyboard_unittests',
+            '../ui/wm/wm.gyp:wm_unittests',
+          ],
+        }],
+        ['use_ozone==1', {
+          'dependencies': [
+            '../ui/ozone/ozone.gyp:ozone',
+          ],
+        }],
+
+
+        ['use_x11==1', {
+          'dependencies': [
+            '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
+          ],
+          'conditions': [
+            ['target_arch!="arm"', {
+              'dependencies': [
+                '../gpu/tools/tools.gyp:compositor_model_bench',
+              ],
+            }],
+          ],
+        }],
+        ['OS=="android"', {
+          'dependencies': [
+            '../base/base.gyp:chromium_android_linker',
+            '../breakpad/breakpad.gyp:dump_syms',
+            '../build/android/rezip.gyp:rezip_apk_jar',
+            '../chrome/chrome.gyp:chrome_shell_apk',
+            '../chrome/chrome.gyp:chromedriver_webview_shell_apk',
+            #"//clank" TODO(GYP) - conditional somehow?
+            '../tools/imagediff/image_diff.gyp:image_diff#host',
+            '../tools/telemetry/telemetry.gyp:bitmaptools#host',
+
+            # TODO(GYP): Remove these when the components_unittests work.
+            #"//components/history/core/test:test",
+            #"//components/policy:policy_component_test_support",
+            #"//components/policy:test_support",
+            #"//components/rappor:test_support",
+            #"//components/signin/core/browser:test_support",
+            #"//components/sync_driver:test_support",
+            #"//components/user_manager",
+            #"//components/wallpaper",
+
+            '../content/content_shell_and_tests.gyp:content_shell_apk',
+
+            # TODO(GYP): Are these needed, or will they be pulled in automatically?
+            #"//third_party/android_tools:android_gcm_java",
+            #"//third_party/android_tools:uiautomator_java",
+            #"//third_party/android_tools:android_support_v13_java",
+            #"//third_party/android_tools:android_support_v7_appcompat_java",
+            #"//third_party/android_tools:android_support_v7_mediarouter_java",
+            #"//third_party/mesa",
+            #"//third_party/mockito:mockito_java",
+            #"//third_party/openmax_dl/dl",
+            #"//third_party/speex",
+            #"//ui/android:ui_java",
+
+            # TODO(GYP): Are these needed?
+            #"//chrome/test:test_support_unit",
+            #"//third_party/smhasher:murmurhash3",
+            #"//ui/message_center:test_support",
+          ],
+          'dependencies!': [
+            '../breakpad/breakpad.gyp:symupload',
+            '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:chromedriver',
+            '../chrome/chrome.gyp:chromedriver_unitests',
+            '../chrome/chrome.gyp:interactive_ui_tests',
+            '../chrome/chrome.gyp:performance_browser_tests',
+            '../chrome/chrome.gyp:sync_integration_tests',
+            '../chrome/chrome.gyp:unit_tests',
+            '../extensions/extensions_tests.gyp:extensions_browsertests',
+            '../extensions/extensions_tests.gyp:extensions_unittests',
+            '../google_apis/gcm/gcm.gyp:gcm_unit_tests',
+            '../ipc/ipc.gyp:ipc_tests',
+            '../jingle/jingle.gyp:jingle_unittests',
+            '../net/net.gyp:net_unittests',
+            #"//ppapi/examples",
+            '../third_party/pdfium/samples/samples.gyp:pdfium_test',
+            '../tools/gn/gn.gyp:gn',
+            '../tools/gn/gn.gyp:gn_unittests',
+            '../tools/imagediff/image_diff.gyp:image_diff',
+            '../tools/gn/gn.gyp:gn',
+            '../tools/gn/gn.gyp:gn_unittests',
+            '../ui/app_list/app_list.gyp:app_list_unittests',
+            '../url/url.gyp:url_unittests',
+          ],
+        }],
+        ['OS=="android" or OS=="linux"', {
+          'dependencies': [
+            '../net/net.gyp:disk_cache_memory_test',
+          ],
+        }],
+        ['chromeos==1', {
+          'dependencies': [
+            '../chromeos/chromeos.gyp:chromeos_unittests',
+            '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_unittests',
+          ]
+        }],
+        ['chromeos==1 or OS=="win" or OS=="mac"', {
+          'dependencies': [
+            '../rlz/rlz.gyp:rlz_id',
+            '../rlz/rlz.gyp:rlz_lib',
+            '../rlz/rlz.gyp:rlz_unittests',
+          ],
+        }],
+        ['OS=="android" or OS=="linux" or os_bsd==1', {
+          'dependencies': [
+            '../breakpad/breakpad.gyp:core-2-minidump',
+            '../breakpad/breakpad.gyp:microdump_stackwalk',
+            '../breakpad/breakpad.gyp:minidump_dump',
+            '../breakpad/breakpad.gyp:minidump_stackwalk',
+            '../breakpad/breakpad.gyp:symupload',
+            '../third_party/codesighs/codesighs.gyp:nm2tsv',
+          ],
+        }],
+        ['OS=="linux"', {
+          'dependencies': [
+            '../breakpad/breakpad.gyp:breakpad_unittests',
+            '../breakpad/breakpad.gyp:dump_syms#host',
+            '../breakpad/breakpad.gyp:generate_test_dump',
+            '../breakpad/breakpad.gyp:minidump-2-core',
+            '../dbus/dbus.gyp:dbus_test_server',
+            '../dbus/dbus.gyp:dbus_unittests',
+            '../media/cast/cast.gyp:tap_proxy',
+            '../net/net.gyp:disk_cache_memory_test',
+            '../net/net.gyp:flip_in_mem_edsm_server',
+            '../net/net.gyp:flip_in_mem_edsm_server_unittests',
+            '../net/net.gyp:epoll_quic_client',
+            '../net/net.gyp:epoll_quic_server',
+            '../net/net.gyp:hpack_example_generator',
+            '../net/net.gyp:hpack_fuzz_mutator',
+            '../net/net.gyp:hpack_fuzz_wrapper',
+            '../net/net.gyp:net_perftests',
+            '../net/net.gyp:quic_client',
+            '../net/net.gyp:quic_server',
+            '../sandbox/sandbox.gyp:chrome_sandbox',
+            '../sandbox/sandbox.gyp:sandbox_linux_unittests',
+            '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests',
+            '../third_party/sqlite/sqlite.gyp:sqlite_shell',
+         ],
+        }],
+        ['OS=="mac"', {
+          'dependencies': [
+            '../breakpad/breakpad.gyp:crash_inspector',
+            '../breakpad/breakpad.gyp:dump_syms',
+            '../breakpad/breakpad.gyp:symupload',
+            '../third_party/apple_sample_code/apple_sample_code.gyp:apple_sample_code',
+            '../third_party/molokocacao/molokocacao.gyp:molokocacao',
+
+            # TODO(GYP): remove these when the corresponding root targets work.
+            #"//cc/blink",
+            #"//components/ui/zoom:ui_zoom",
+            #"//content",
+            #"//content/test:test_support",
+            #"//device/battery",
+            #"//device/bluetooth",
+            #"//device/nfc",
+            #"//device/usb",
+            #"//device/vibration",
+            #"//media/blink",
+            #"//pdf",
+            #"//storage/browser",
+            #"//third_party/brotli",
+            #"//third_party/flac",
+            #"//third_party/hunspell",
+            #//third_party/iccjpeg",
+            #"//third_party/libphonenumber",
+            #"//third_party/ots",
+            #"//third_party/qcms",
+            #"//third_party/smhasher:murmurhash3",
+            #"//third_party/speex",
+            #"//third_party/webrtc/system_wrappers",
+            #"//ui/native_theme",
+            #"//ui/snapshot",
+            #"//ui/surface",
+          ],
+          'dependencies!': [
+            #"//chrome",  # TODO(GYP)
+            #"//chrome/test:browser_tests",  # TODO(GYP)
+            #"//chrome/test:interactive_ui_tests",  # TODO(GYP)
+            #"//chrome/test:sync_integration_tests",  # TODO(GYP)
+            #"//chrome/test:unit_tests",  # TODO(GYP)
+            #"//components:components_unittests",  # TODO(GYP)
+            #"//content/test:content_browsertests",  # TODO(GYP)
+            #"//content/test:content_perftests",  # TODO(GYP)
+            #"//content/test:content_unittests",  # TODO(GYP)
+            #"//extensions:extensions_browsertests",  # TODO(GYP)
+            #"//extensions:extensions_unittests",  # TODO(GYP)
+            #"//net:net_unittests",  # TODO(GYP)
+            #"//third_party/usrsctp",  # TODO(GYP)
+            #"//ui/app_list:app_list_unittests",  # TODO(GYP)
+            #"//ui/gfx:gfx_unittests",  # TODO(GYP)
+          ],
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            '../base/base.gyp:pe_image_test',
+            '../chrome/chrome.gyp:crash_service',
+            '../chrome_elf/chrome_elf.gyp:chrome_elf_unittests',
+            '../chrome_elf/chrome_elf.gyp:dll_hash_main',
+            '../components/components.gyp:wifi_test',
+            '../net/net.gyp:quic_client',
+            '../net/net.gyp:quic_server',
+            '../sandbox/sandbox.gyp:pocdll',
+            '../sandbox/sandbox.gyp:sandbox_poc',
+            '../sandbox/sandbox.gyp:sbox_integration_tests',
+            '../sandbox/sandbox.gyp:sbox_unittests',
+            '../sandbox/sandbox.gyp:sbox_validation_tests',
+            '../testing/gtest.gyp:gtest_main',
+            '../third_party/codesighs/codesighs.gyp:msdump2symdb',
+            '../third_party/codesighs/codesighs.gyp:msmap2tsv',
+            '../third_party/pdfium/samples/samples.gyp:pdfium_diff',
+            '../win8/win8.gyp:metro_viewer',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'gyp_only',
+      'type': 'none',
+      'conditions': [
+        ['OS=="linux" or OS=="win"', {
+          'conditions': [
+            ['disable_nacl==0 and disable_nacl_untrusted==0', {
+              'dependencies': [
+                '../mojo/mojo_nacl.gyp:monacl_shell',  # This should not be built in chromium.
+              ]
+            }],
+          ]
+        }],
+      ],
+    },
+    {
+      'target_name': 'gyp_remaining',
+      'type': 'none',
+      'conditions': [
+        ['remoting==1', {
+          'dependencies': [
+            '../remoting/app_remoting_webapp.gyp:ar_sample_app',  # crbug.com/471916
+          ],
+        }],
+        ['test_isolation_mode!="noop"', {
+          'dependencies': [
+            '../base/base.gyp:base_unittests_run',
+            '../cc/cc_tests.gyp:cc_unittests_run',
+            '../chrome/chrome.gyp:browser_tests_run',
+            '../chrome/chrome.gyp:chrome_run',
+            '../chrome/chrome.gyp:interactive_ui_tests_run',
+            '../chrome/chrome.gyp:sync_integration_tests_run',
+            '../chrome/chrome.gyp:unit_tests_run',
+            '../components/components_tests.gyp:components_browsertests_run',
+            '../components/components_tests.gyp:components_unittests_run',
+            '../content/content_shell_and_tests.gyp:content_browsertests_run',
+            '../content/content_shell_and_tests.gyp:content_unittests_run',
+            '../crypto/crypto.gyp:crypto_unittests_run',
+            '../courgette/courgette.gyp:courgette_unittests_run',
+            '../gpu/gpu.gyp:gpu_unittests_run',
+            '../media/cast/cast.gyp:cast_unittests_run',
+            '../media/media.gyp:media_unittests_run',
+            '../media/midi/midi.gyp:midi_unittests_run',
+            '../net/net.gyp:net_unittests_run',
+            '../sql/sql.gyp:sql_unittests_run',
+            '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests_run',
+            '../ui/accessibility/accessibility.gyp:accessibility_unittests_run',
+            '../ui/app_list/app_list.gyp:app_list_unittests_run',
+            '../ui/events/events.gyp:events_unittests_run',
+            '../ui/message_center/message_center.gyp:message_center_unittests_run',
+            '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_run',
+          ],
+        }],
+        ['test_isolation_mode!="noop" and use_ash==1', {
+          'dependencies': [
+            '../ash/ash.gyp:ash_unittests_run',
+          ],
+        }],
+        ['test_isolation_mode!="noop" and OS=="linux"', {
+          'dependencies': [
+            '../sandbox/sandbox.gyp:sandbox_linux_unittests_run',
+          ],
+        }],
+        ['use_openssl==1', {
+          'dependencies': [
+            # TODO(GYP): All of these targets still need to be converted.
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_ecdsa_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_bn_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_pqueue_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_digest_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_cipher_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_hkdf_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_constant_time_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_thread_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_base64_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_gcm_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_bytestring_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_evp_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_dsa_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_rsa_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_hmac_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_aead_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_ssl_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_err_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_lhash_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_pbkdf_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_dh_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs12_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_example_mul',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_ec_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_bio_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs7_test',
+            '../third_party/boringssl/boringssl_tests.gyp:boringssl_unittests',
+          ],
+        }],
+        ['chromeos==1', {
+          'dependencies': [
+            '../content/content_shell_and_tests.gyp:video_encode_accelerator_unittest',
+          ],
+        }],
+        ['chromeos==1 and target_arch != "arm"', {
+          'dependencies': [
+            '../content/content_shell_and_tests.gyp:vaapi_jpeg_decoder_unittest',
+          ],
+        }],
+        ['chromeos==1 or OS=="win" or OS=="android"', {
+          'dependencies': [
+            '../content/content_shell_and_tests.gyp:video_decode_accelerator_unittest',
+          ],
+        }],
+        ['OS=="linux" or OS=="win"', {
+          'dependencies': [
+            # TODO(GYP): Figure out which of these run on android/mac/win/ios/etc.
+            '../net/net.gyp:net_docs',
+            '../remoting/app_remoting_test.gyp:ar_sample_test_driver',
+
+            # TODO(GYP): in progress - see tfarina.
+            '../third_party/webrtc/tools/tools.gyp:frame_analyzer',
+            '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter',
+          ],
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            # TODO(GYP): All of these targets still need to be converted.
+            '../base/base.gyp:debug_message',
+            '../chrome/chrome.gyp:app_installer',
+            '../chrome/chrome.gyp:app_installer_unittests',
+            '../chrome/chrome.gyp:app_shim',
+            '../chrome/chrome.gyp:gcapi_dll',
+            '../chrome/chrome.gyp:gcapi_test',
+            '../chrome/chrome.gyp:installer_util_unittests',
+            '../chrome/chrome.gyp:pack_policy_templates',
+            '../chrome/chrome.gyp:sb_sigutil',
+            '../chrome/chrome.gyp:setup',
+            '../chrome/chrome.gyp:setup_unittests',
+            '../chrome/installer/mini_installer.gyp:mini_installer',
+            '../chrome/tools/crash_service/caps/caps.gyp:caps',
+            '../cloud_print/gcp20/prototype/gcp20_device.gyp:gcp20_device',
+            '../cloud_print/gcp20/prototype/gcp20_device.gyp:gcp20_device_unittests',
+            '../cloud_print/service/service.gyp:cloud_print_service',
+            '../cloud_print/service/service.gyp:cloud_print_service_config',
+            '../cloud_print/service/service.gyp:cloud_print_service_setup',
+            '../cloud_print/virtual_driver/win/install/virtual_driver_install.gyp:virtual_driver_setup',
+            '../cloud_print/virtual_driver/win/virtual_driver.gyp:gcp_portmon',
+            '../content/content_shell_and_tests.gyp:content_shell_crash_service',
+            '../content/content_shell_and_tests.gyp:layout_test_helper',
+            '../gpu/gpu.gyp:angle_end2end_tests',
+            '../gpu/gpu.gyp:angle_perftests',
+            '../net/net.gyp:net_docs',
+            '../ppapi/ppapi_internal.gyp:ppapi_perftests',
+            '../remoting/app_remoting_test.gyp:ar_sample_test_driver',
+            '../remoting/remoting.gyp:remoting_breakpad_tester',
+            '../remoting/remoting.gyp:remoting_console',
+            '../remoting/remoting.gyp:remoting_desktop',
+            '../rlz/rlz.gyp:rlz',
+            '../tools/win/static_initializers/static_initializers.gyp:static_initializers',
+          ],
+        }],
+        ['OS=="win" and win_use_allocator_shim==1', {
+          'dependencies': [
+            '../base/allocator/allocator.gyp:allocator_unittests',
+          ]
+        }],
+        ['OS=="win" and target_arch=="ia32"', {
+          'dependencies': [
+            # TODO(GYP): All of these targets need to be ported over.
+            '../base/base.gyp:base_win64',
+            '../base/base.gyp:base_i18n_nacl_win64',
+            '../chrome/chrome.gyp:crash_service_win64',
+            '../chrome/chrome.gyp:launcher_support64',
+            '../components/components.gyp:breakpad_win64',
+            '../courgette/courgette.gyp:courgette64',
+            '../crypto/crypto.gyp:crypto_nacl_win64',
+            '../ipc/ipc.gyp:ipc_win64',
+            '../sandbox/sandbox.gyp:sandbox_win64',
+            '../cloud_print/virtual_driver/win/virtual_driver64.gyp:gcp_portmon64',
+            '../cloud_print/virtual_driver/win/virtual_driver64.gyp:virtual_driver_lib64',
+          ],
+        }],
+        ['OS=="win" and target_arch=="ia32" and configuration_policy==1', {
+          'dependencies': [
+            # TODO(GYP): All of these targets need to be ported over.
+            '../components/components.gyp:policy_win64',
+          ]
+        }],
+      ],
+    },
+  ]
+}
+
diff --git a/build/gn_run_binary.py b/build/gn_run_binary.py
new file mode 100644
index 0000000..7d83f61
--- /dev/null
+++ b/build/gn_run_binary.py
@@ -0,0 +1,22 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper script for GN to run an arbitrary binary. See compiled_action.gni.
+
+Run with:
+  python gn_run_binary.py <binary_name> [args ...]
+"""
+
+import sys
+import subprocess
+
+# This script is designed to run binaries produced by the current build. We
+# always prefix it with "./" to avoid picking up system versions that might
+# also be on the path.
+path = './' + sys.argv[1]
+
+# The rest of the arguements are passed directly to the executable.
+args = [path] + sys.argv[2:]
+
+sys.exit(subprocess.call(args))
diff --git a/build/grit_action.gypi b/build/grit_action.gypi
new file mode 100644
index 0000000..b24f0f8
--- /dev/null
+++ b/build/grit_action.gypi
@@ -0,0 +1,71 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to invoke grit in a
+# consistent manner. To use this the following variables need to be
+# defined:
+#   grit_grd_file: string: grd file path
+#   grit_out_dir: string: the output directory path
+
+# It would be really nice to do this with a rule instead of actions, but it
+# would need to determine inputs and outputs via grit_info on a per-file
+# basis. GYP rules don't currently support that. They could be extended to
+# do this, but then every generator would need to be updated to handle this.
+
+{
+  'variables': {
+    'grit_cmd': ['python', '<(DEPTH)/tools/grit/grit.py'],
+    'grit_resource_ids%': '<(DEPTH)/tools/gritsettings/resource_ids',
+    # This makes it possible to add more defines in specific targets,
+    # instead of build/common.gypi .
+    'grit_additional_defines%': [],
+    'grit_rc_header_format%': [],
+    'grit_whitelist%': '',
+
+    'conditions': [
+      # These scripts can skip writing generated files if they are identical
+      # to the already existing files, which avoids further build steps, like
+      # recompilation. However, a dependency (earlier build step) having a
+      # newer timestamp than an output (later build step) confuses some build
+      # systems, so only use this on ninja, which explicitly supports this use
+      # case (gyp turns all actions into ninja restat rules).
+      ['"<(GENERATOR)"=="ninja"', {
+        'write_only_new': '1',
+      }, {
+        'write_only_new': '0',
+      }],
+    ],
+  },
+  'conditions': [
+    ['"<(grit_whitelist)"==""', {
+      'variables': {
+        'grit_whitelist_flag': [],
+      }
+    }, {
+      'variables': {
+        'grit_whitelist_flag': ['-w', '<(grit_whitelist)'],
+      }
+    }]
+  ],
+  'inputs': [
+    '<!@pymod_do_main(grit_info <@(grit_defines) <@(grit_additional_defines) '
+        '<@(grit_whitelist_flag) --inputs <(grit_grd_file) '
+        '-f "<(grit_resource_ids)")',
+  ],
+  'outputs': [
+    '<!@pymod_do_main(grit_info <@(grit_defines) <@(grit_additional_defines) '
+        '<@(grit_whitelist_flag) --outputs \'<(grit_out_dir)\' '
+        '<(grit_grd_file) -f "<(grit_resource_ids)")',
+  ],
+  'action': ['<@(grit_cmd)',
+             '-i', '<(grit_grd_file)', 'build',
+             '-f', '<(grit_resource_ids)',
+             '-o', '<(grit_out_dir)',
+             '--write-only-new=<(write_only_new)',
+             '<@(grit_defines)',
+             '<@(grit_whitelist_flag)',
+             '<@(grit_additional_defines)',
+             '<@(grit_rc_header_format)'],
+  'message': 'Generating resources from <(grit_grd_file)',
+}
diff --git a/build/grit_target.gypi b/build/grit_target.gypi
new file mode 100644
index 0000000..179f986
--- /dev/null
+++ b/build/grit_target.gypi
@@ -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.
+
+# This file is meant to be included into a target that will have one or more
+# uses of grit_action.gypi. To use this the following variables need to be
+# defined:
+#   grit_out_dir: string: the output directory path
+
+# DO NOT USE THIS FILE. Instead, use qualified includes.
+# TODO: Convert everything to qualified includes, and delete this file,
+# http://crbug.com/401588
+{
+  'conditions': [
+    # If the target is a direct binary, it needs to be able to find the header,
+    # otherwise it probably a supporting target just for grit so the include
+    # dir needs to be set on anything that depends on this action.
+    ['_type=="executable" or _type=="shared_library" or \
+      _type=="loadable_module" or _type=="static_library"', {
+      'include_dirs': [
+        '<(grit_out_dir)',
+      ],
+    }, {
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(grit_out_dir)',
+        ],
+      },
+    }],
+  ],
+}
diff --git a/build/gyp_chromium b/build/gyp_chromium
new file mode 100755
index 0000000..736062e
--- /dev/null
+++ b/build/gyp_chromium
@@ -0,0 +1,331 @@
+#!/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 is wrapper for Chromium that adds some support for how GYP
+# is invoked by Chromium beyond what can be done in the gclient hooks.
+
+import argparse
+import glob
+import gyp_environment
+import os
+import re
+import shlex
+import subprocess
+import string
+import sys
+import vs_toolchain
+
+script_dir = os.path.dirname(os.path.realpath(__file__))
+chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
+
+sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
+import gyp
+
+# Assume this file is in a one-level-deep subdirectory of the source root.
+SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# Add paths so that pymod_do_main(...) can import files.
+sys.path.insert(1, os.path.join(chrome_src, 'android_webview', 'tools'))
+sys.path.insert(1, os.path.join(chrome_src, 'build', 'android', 'gyp'))
+sys.path.insert(1, os.path.join(chrome_src, 'chrome', 'tools', 'build'))
+sys.path.insert(1, os.path.join(chrome_src, 'chromecast', 'tools', 'build'))
+sys.path.insert(1, os.path.join(chrome_src, 'native_client', 'build'))
+sys.path.insert(1, os.path.join(chrome_src, 'native_client_sdk', 'src',
+    'build_tools'))
+sys.path.insert(1, os.path.join(chrome_src, 'remoting', 'tools', 'build'))
+sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'liblouis'))
+sys.path.insert(1, os.path.join(chrome_src, 'third_party', 'WebKit',
+    'Source', 'build', 'scripts'))
+sys.path.insert(1, os.path.join(chrome_src, 'tools'))
+sys.path.insert(1, os.path.join(chrome_src, 'tools', 'generate_shim_headers'))
+sys.path.insert(1, os.path.join(chrome_src, 'tools', 'grit'))
+
+# On Windows, Psyco shortens warm runs of build/gyp_chromium by about
+# 20 seconds on a z600 machine with 12 GB of RAM, from 90 down to 70
+# seconds.  Conversely, memory usage of build/gyp_chromium with Psyco
+# maxes out at about 158 MB vs. 132 MB without it.
+#
+# Psyco uses native libraries, so we need to load a different
+# installation depending on which OS we are running under. It has not
+# been tested whether using Psyco on our Mac and Linux builds is worth
+# it (the GYP running time is a lot shorter, so the JIT startup cost
+# may not be worth it).
+if sys.platform == 'win32':
+  try:
+    sys.path.insert(0, os.path.join(chrome_src, 'third_party', 'psyco_win32'))
+    import psyco
+  except:
+    psyco = None
+else:
+  psyco = None
+
+
+def GetSupplementalFiles():
+  """Returns a list of the supplemental files that are included in all GYP
+  sources."""
+  return glob.glob(os.path.join(chrome_src, '*', 'supplement.gypi'))
+
+
+def ProcessGypDefinesItems(items):
+  """Converts a list of strings to a list of key-value pairs."""
+  result = []
+  for item in items:
+    tokens = item.split('=', 1)
+    # Some GYP variables have hyphens, which we don't support.
+    if len(tokens) == 2:
+      result += [(tokens[0], tokens[1])]
+    else:
+      # No value supplied, treat it as a boolean and set it. Note that we
+      # use the string '1' here so we have a consistent definition whether
+      # you do 'foo=1' or 'foo'.
+      result += [(tokens[0], '1')]
+  return result
+
+
+def GetGypVars(supplemental_files):
+  """Returns a dictionary of all GYP vars."""
+  # Find the .gyp directory in the user's home directory.
+  home_dot_gyp = os.environ.get('GYP_CONFIG_DIR', None)
+  if home_dot_gyp:
+    home_dot_gyp = os.path.expanduser(home_dot_gyp)
+  if not home_dot_gyp:
+    home_vars = ['HOME']
+    if sys.platform in ('cygwin', 'win32'):
+      home_vars.append('USERPROFILE')
+    for home_var in home_vars:
+      home = os.getenv(home_var)
+      if home != None:
+        home_dot_gyp = os.path.join(home, '.gyp')
+        if not os.path.exists(home_dot_gyp):
+          home_dot_gyp = None
+        else:
+          break
+
+  if home_dot_gyp:
+    include_gypi = os.path.join(home_dot_gyp, "include.gypi")
+    if os.path.exists(include_gypi):
+      supplemental_files += [include_gypi]
+
+  # GYP defines from the supplemental.gypi files.
+  supp_items = []
+  for supplement in supplemental_files:
+    with open(supplement, 'r') as f:
+      try:
+        file_data = eval(f.read(), {'__builtins__': None}, None)
+      except SyntaxError, e:
+        e.filename = os.path.abspath(supplement)
+        raise
+      variables = file_data.get('variables', [])
+      for v in variables:
+        supp_items += [(v, str(variables[v]))]
+
+  # GYP defines from the environment.
+  env_items = ProcessGypDefinesItems(
+      shlex.split(os.environ.get('GYP_DEFINES', '')))
+
+  # GYP defines from the command line.
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-D', dest='defines', action='append', default=[])
+  cmdline_input_items = parser.parse_known_args()[0].defines
+  cmdline_items = ProcessGypDefinesItems(cmdline_input_items)
+
+  vars_dict = dict(supp_items + env_items + cmdline_items)
+  return vars_dict
+
+
+def GetOutputDirectory():
+  """Returns the output directory that GYP will use."""
+
+  # Handle command line generator flags.
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-G', dest='genflags', default=[], action='append')
+  genflags = parser.parse_known_args()[0].genflags
+
+  # Handle generator flags from the environment.
+  genflags += shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', ''))
+
+  needle = 'output_dir='
+  for item in genflags:
+    if item.startswith(needle):
+      return item[len(needle):]
+
+  return 'out'
+
+
+def additional_include_files(supplemental_files, args=[]):
+  """
+  Returns a list of additional (.gypi) files to include, without duplicating
+  ones that are already specified on the command line. The list of supplemental
+  include files is passed in as an argument.
+  """
+  # Determine the include files specified on the command line.
+  # This doesn't cover all the different option formats you can use,
+  # but it's mainly intended to avoid duplicating flags on the automatic
+  # makefile regeneration which only uses this format.
+  specified_includes = set()
+  for arg in args:
+    if arg.startswith('-I') and len(arg) > 2:
+      specified_includes.add(os.path.realpath(arg[2:]))
+
+  result = []
+  def AddInclude(path):
+    if os.path.realpath(path) not in specified_includes:
+      result.append(path)
+
+  if os.environ.get('GYP_INCLUDE_FIRST') != None:
+    AddInclude(os.path.join(chrome_src, os.environ.get('GYP_INCLUDE_FIRST')))
+
+  # Always include common.gypi.
+  AddInclude(os.path.join(script_dir, 'common.gypi'))
+
+  # Optionally add supplemental .gypi files if present.
+  for supplement in supplemental_files:
+    AddInclude(supplement)
+
+  if os.environ.get('GYP_INCLUDE_LAST') != None:
+    AddInclude(os.path.join(chrome_src, os.environ.get('GYP_INCLUDE_LAST')))
+
+  return result
+
+
+if __name__ == '__main__':
+  # Disabling garbage collection saves about 1 second out of 16 on a Linux
+  # z620 workstation. Since this is a short-lived process it's not a problem to
+  # leak a few cyclyc references in order to spare the CPU cycles for
+  # scanning the heap.
+  import gc
+  gc.disable()
+
+  args = sys.argv[1:]
+
+  use_analyzer = len(args) and args[0] == '--analyzer'
+  if use_analyzer:
+    args.pop(0)
+    os.environ['GYP_GENERATORS'] = 'analyzer'
+    args.append('-Gconfig_path=' + args.pop(0))
+    args.append('-Ganalyzer_output_path=' + args.pop(0))
+
+  if int(os.environ.get('GYP_CHROMIUM_NO_ACTION', 0)):
+    print 'Skipping gyp_chromium due to GYP_CHROMIUM_NO_ACTION env var.'
+    sys.exit(0)
+
+  # Use the Psyco JIT if available.
+  if psyco:
+    psyco.profile()
+    print "Enabled Psyco JIT."
+
+  # Fall back on hermetic python if we happen to get run under cygwin.
+  # TODO(bradnelson): take this out once this issue is fixed:
+  #    http://code.google.com/p/gyp/issues/detail?id=177
+  if sys.platform == 'cygwin':
+    import find_depot_tools
+    depot_tools_path = find_depot_tools.add_depot_tools_to_path()
+    python_dir = sorted(glob.glob(os.path.join(depot_tools_path,
+                                               'python2*_bin')))[-1]
+    env = os.environ.copy()
+    env['PATH'] = python_dir + os.pathsep + env.get('PATH', '')
+    p = subprocess.Popen(
+       [os.path.join(python_dir, 'python.exe')] + sys.argv,
+       env=env, shell=False)
+    p.communicate()
+    sys.exit(p.returncode)
+
+  # This could give false positives since it doesn't actually do real option
+  # parsing.  Oh well.
+  gyp_file_specified = False
+  for arg in args:
+    if arg.endswith('.gyp'):
+      gyp_file_specified = True
+      break
+
+  gyp_environment.SetEnvironment()
+
+  # If we didn't get a file, check an env var, and then fall back to
+  # assuming 'all.gyp' from the same directory as the script.
+  if not gyp_file_specified:
+    gyp_file = os.environ.get('CHROMIUM_GYP_FILE')
+    if gyp_file:
+      # Note that CHROMIUM_GYP_FILE values can't have backslashes as
+      # path separators even on Windows due to the use of shlex.split().
+      args.extend(shlex.split(gyp_file))
+    else:
+      args.append(os.path.join(script_dir, 'all.gyp'))
+
+  supplemental_includes = GetSupplementalFiles()
+  gyp_vars_dict = GetGypVars(supplemental_includes)
+  # There shouldn't be a circular dependency relationship between .gyp files,
+  # but in Chromium's .gyp files, on non-Mac platforms, circular relationships
+  # currently exist.  The check for circular dependencies is currently
+  # bypassed on other platforms, but is left enabled on iOS, where a violation
+  # of the rule causes Xcode to misbehave badly.
+  # TODO(mark): Find and kill remaining circular dependencies, and remove this
+  # option.  http://crbug.com/35878.
+  # TODO(tc): Fix circular dependencies in ChromiumOS then add linux2 to the
+  # list.
+  if gyp_vars_dict.get('OS') != 'ios':
+    args.append('--no-circular-check')
+
+  # We explicitly don't support the make gyp generator (crbug.com/348686). Be
+  # nice and fail here, rather than choking in gyp.
+  if re.search(r'(^|,|\s)make($|,|\s)', os.environ.get('GYP_GENERATORS', '')):
+    print 'Error: make gyp generator not supported (check GYP_GENERATORS).'
+    sys.exit(1)
+
+  # We explicitly don't support the native msvs gyp generator. Be nice and
+  # fail here, rather than generating broken projects.
+  if re.search(r'(^|,|\s)msvs($|,|\s)', os.environ.get('GYP_GENERATORS', '')):
+    print 'Error: msvs gyp generator not supported (check GYP_GENERATORS).'
+    print 'Did you mean to use the `msvs-ninja` generator?'
+    sys.exit(1)
+
+  # If CHROMIUM_GYP_SYNTAX_CHECK is set to 1, it will invoke gyp with --check
+  # to enfore syntax checking.
+  syntax_check = os.environ.get('CHROMIUM_GYP_SYNTAX_CHECK')
+  if syntax_check and int(syntax_check):
+    args.append('--check')
+
+  # TODO(dmikurube): Remove these checks and messages after a while.
+  if ('linux_use_tcmalloc' in gyp_vars_dict or
+      'android_use_tcmalloc' in gyp_vars_dict):
+    print '*****************************************************************'
+    print '"linux_use_tcmalloc" and "android_use_tcmalloc" are deprecated!'
+    print '-----------------------------------------------------------------'
+    print 'You specify "linux_use_tcmalloc" or "android_use_tcmalloc" in'
+    print 'your GYP_DEFINES. Please switch them into "use_allocator" now.'
+    print 'See http://crbug.com/345554 for the details.'
+    print '*****************************************************************'
+
+  # Automatically turn on crosscompile support for platforms that need it.
+  # (The Chrome OS build sets CC_host / CC_target which implicitly enables
+  # this mode.)
+  if all(('ninja' in os.environ.get('GYP_GENERATORS', ''),
+          gyp_vars_dict.get('OS') in ['android', 'ios'],
+          'GYP_CROSSCOMPILE' not in os.environ)):
+    os.environ['GYP_CROSSCOMPILE'] = '1'
+  if gyp_vars_dict.get('OS') == 'android':
+    args.append('--check')
+
+  args.extend(
+      ['-I' + i for i in additional_include_files(supplemental_includes, args)])
+
+  args.extend(['-D', 'gyp_output_dir=' + GetOutputDirectory()])
+
+  if not use_analyzer:
+    print 'Updating projects from gyp files...'
+    sys.stdout.flush()
+
+  # Off we go...
+  gyp_rc = gyp.main(args)
+
+  if not use_analyzer:
+    vs2013_runtime_dll_dirs = vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
+    if vs2013_runtime_dll_dirs:
+      x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
+      vs_toolchain.CopyVsRuntimeDlls(
+        os.path.join(chrome_src, GetOutputDirectory()),
+        (x86_runtime, x64_runtime))
+
+  sys.exit(gyp_rc)
diff --git a/build/gyp_chromium.py b/build/gyp_chromium.py
new file mode 100644
index 0000000..f9e8ac8
--- /dev/null
+++ b/build/gyp_chromium.py
@@ -0,0 +1,18 @@
+# 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 file is (possibly, depending on python version) imported by
+# gyp_chromium when GYP_PARALLEL=1 and it creates sub-processes
+# through the multiprocessing library.
+
+# Importing in Python 2.6 (fixed in 2.7) on Windows doesn't search for
+# imports that don't end in .py (and aren't directories with an
+# __init__.py). This wrapper makes "import gyp_chromium" work with
+# those old versions and makes it possible to execute gyp_chromium.py
+# directly on Windows where the extension is useful.
+
+import os
+
+path = os.path.abspath(os.path.split(__file__)[0])
+execfile(os.path.join(path, 'gyp_chromium'))
diff --git a/build/gyp_chromium_test.py b/build/gyp_chromium_test.py
new file mode 100755
index 0000000..0c0e479
--- /dev/null
+++ b/build/gyp_chromium_test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+import unittest
+
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+SRC_DIR = os.path.dirname(SCRIPT_DIR)
+
+sys.path.append(os.path.join(SRC_DIR, 'third_party', 'pymock'))
+
+import mock
+
+# TODO(sbc): Make gyp_chromium more testable by putting the code in
+# a .py file.
+gyp_chromium = __import__('gyp_chromium')
+
+
+class TestGetOutputDirectory(unittest.TestCase):
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__])
+  def testDefaultValue(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'out')
+
+  @mock.patch('os.environ', {'GYP_GENERATOR_FLAGS': 'output_dir=envfoo'})
+  @mock.patch('sys.argv', [__file__])
+  def testEnvironment(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'envfoo')
+
+  @mock.patch('os.environ', {'GYP_GENERATOR_FLAGS': 'output_dir=envfoo'})
+  @mock.patch('sys.argv', [__file__, '-Goutput_dir=cmdfoo'])
+  def testGFlagOverridesEnv(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'cmdfoo')
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-G', 'output_dir=foo'])
+  def testGFlagWithSpace(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'foo')
+
+
+class TestGetGypVars(unittest.TestCase):
+  @mock.patch('os.environ', {})
+  def testDefault(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {})
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-D', 'foo=bar'])
+  def testDFlags(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {'foo': 'bar'})
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-D', 'foo'])
+  def testDFlagsNoValue(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {'foo': '1'})
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-D', 'foo=bar', '-Dbaz'])
+  def testDFlagMulti(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {'foo': 'bar', 'baz': '1'})
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/gyp_environment.py b/build/gyp_environment.py
new file mode 100644
index 0000000..fb50645
--- /dev/null
+++ b/build/gyp_environment.py
@@ -0,0 +1,33 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Sets up various automatic gyp environment variables. These are used by
+gyp_chromium and landmines.py which run at different stages of runhooks. To
+make sure settings are consistent between them, all setup should happen here.
+"""
+
+import gyp_helper
+import os
+import sys
+import vs_toolchain
+
+def SetEnvironment():
+  """Sets defaults for GYP_* variables."""
+  gyp_helper.apply_chromium_gyp_env()
+
+  # Default to ninja on linux and windows, but only if no generator has
+  # explicitly been set.
+  # Also default to ninja on mac, but only when not building chrome/ios.
+  # . -f / --format has precedence over the env var, no need to check for it
+  # . set the env var only if it hasn't been set yet
+  # . chromium.gyp_env has been applied to os.environ at this point already
+  if sys.platform.startswith(('linux', 'win', 'freebsd')) and \
+      not os.environ.get('GYP_GENERATORS'):
+    os.environ['GYP_GENERATORS'] = 'ninja'
+  elif sys.platform == 'darwin' and not os.environ.get('GYP_GENERATORS') and \
+      not 'OS=ios' in os.environ.get('GYP_DEFINES', []):
+    os.environ['GYP_GENERATORS'] = 'ninja'
+
+  vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
diff --git a/build/gyp_helper.py b/build/gyp_helper.py
new file mode 100644
index 0000000..c840f2d
--- /dev/null
+++ b/build/gyp_helper.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file helps gyp_chromium and landmines correctly set up the gyp
+# environment from chromium.gyp_env on disk
+
+import os
+
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+CHROME_SRC = os.path.dirname(SCRIPT_DIR)
+
+
+def apply_gyp_environment_from_file(file_path):
+  """Reads in a *.gyp_env file and applies the valid keys to os.environ."""
+  if not os.path.exists(file_path):
+    return
+  with open(file_path, 'rU') as f:
+    file_contents = f.read()
+  try:
+    file_data = eval(file_contents, {'__builtins__': None}, None)
+  except SyntaxError, e:
+    e.filename = os.path.abspath(file_path)
+    raise
+  supported_vars = (
+      'CC',
+      'CC_wrapper',
+      'CC.host_wrapper',
+      'CHROMIUM_GYP_FILE',
+      'CHROMIUM_GYP_SYNTAX_CHECK',
+      'CXX',
+      'CXX_wrapper',
+      'CXX.host_wrapper',
+      'GYP_DEFINES',
+      'GYP_GENERATOR_FLAGS',
+      'GYP_CROSSCOMPILE',
+      'GYP_GENERATOR_OUTPUT',
+      'GYP_GENERATORS',
+      'GYP_INCLUDE_FIRST',
+      'GYP_INCLUDE_LAST',
+      'GYP_MSVS_VERSION',
+  )
+  for var in supported_vars:
+    file_val = file_data.get(var)
+    if file_val:
+      if var in os.environ:
+        behavior = 'replaces'
+        if var == 'GYP_DEFINES':
+          result = file_val + ' ' + os.environ[var]
+          behavior = 'merges with, and individual components override,'
+        else:
+          result = os.environ[var]
+        print 'INFO: Environment value for "%s" %s value in %s' % (
+            var, behavior, os.path.abspath(file_path)
+        )
+        string_padding = max(len(var), len(file_path), len('result'))
+        print '      %s: %s' % (var.rjust(string_padding), os.environ[var])
+        print '      %s: %s' % (file_path.rjust(string_padding), file_val)
+        os.environ[var] = result
+      else:
+        os.environ[var] = file_val
+
+
+def apply_chromium_gyp_env():
+  if 'SKIP_CHROMIUM_GYP_ENV' not in os.environ:
+    # Update the environment based on chromium.gyp_env
+    path = os.path.join(os.path.dirname(CHROME_SRC), 'chromium.gyp_env')
+    apply_gyp_environment_from_file(path)
diff --git a/build/gypi_to_gn.py b/build/gypi_to_gn.py
new file mode 100644
index 0000000..a107f94
--- /dev/null
+++ b/build/gypi_to_gn.py
@@ -0,0 +1,167 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Converts a given gypi file to a python scope and writes the result to stdout.
+
+It is assumed that the file contains a toplevel dictionary, and this script
+will return that dictionary as a GN "scope" (see example below). This script
+does not know anything about GYP and it will not expand variables or execute
+conditions.
+
+It will strip conditions blocks.
+
+A variables block at the top level will be flattened so that the variables
+appear in the root dictionary. This way they can be returned to the GN code.
+
+Say your_file.gypi looked like this:
+  {
+     'sources': [ 'a.cc', 'b.cc' ],
+     'defines': [ 'ENABLE_DOOM_MELON' ],
+  }
+
+You would call it like this:
+  gypi_values = exec_script("//build/gypi_to_gn.py",
+                            [ rebase_path("your_file.gypi") ],
+                            "scope",
+                            [ "your_file.gypi" ])
+
+Notes:
+ - The rebase_path call converts the gypi file from being relative to the
+   current build file to being system absolute for calling the script, which
+   will have a different current directory than this file.
+
+ - The "scope" parameter tells GN to interpret the result as a series of GN
+   variable assignments.
+
+ - The last file argument to exec_script tells GN that the given file is a
+   dependency of the build so Ninja can automatically re-run GN if the file
+   changes.
+
+Read the values into a target like this:
+  component("mycomponent") {
+    sources = gypi_values.sources
+    defines = gypi_values.defines
+  }
+
+Sometimes your .gypi file will include paths relative to a different
+directory than the current .gn file. In this case, you can rebase them to
+be relative to the current directory.
+  sources = rebase_path(gypi_values.sources, ".",
+                        "//path/gypi/input/values/are/relative/to")
+
+This script will tolerate a 'variables' in the toplevel dictionary or not. If
+the toplevel dictionary just contains one item called 'variables', it will be
+collapsed away and the result will be the contents of that dictinoary. Some
+.gypi files are written with or without this, depending on how they expect to
+be embedded into a .gyp file.
+
+This script also has the ability to replace certain substrings in the input.
+Generally this is used to emulate GYP variable expansion. If you passed the
+argument "--replace=<(foo)=bar" then all instances of "<(foo)" in strings in
+the input will be replaced with "bar":
+
+  gypi_values = exec_script("//build/gypi_to_gn.py",
+                            [ rebase_path("your_file.gypi"),
+                              "--replace=<(foo)=bar"],
+                            "scope",
+                            [ "your_file.gypi" ])
+
+"""
+
+import gn_helpers
+from optparse import OptionParser
+import sys
+
+def LoadPythonDictionary(path):
+  file_string = open(path).read()
+  try:
+    file_data = eval(file_string, {'__builtins__': None}, None)
+  except SyntaxError, e:
+    e.filename = path
+    raise
+  except Exception, e:
+    raise Exception("Unexpected error while reading %s: %s" % (path, str(e)))
+
+  assert isinstance(file_data, dict), "%s does not eval to a dictionary" % path
+
+  # Flatten any variables to the top level.
+  if 'variables' in file_data:
+    file_data.update(file_data['variables'])
+    del file_data['variables']
+
+  # Strip any conditions.
+  if 'conditions' in file_data:
+    del file_data['conditions']
+  if 'target_conditions' in file_data:
+    del file_data['target_conditions']
+
+  # Strip targets in the toplevel, since some files define these and we can't
+  # slurp them in.
+  if 'targets' in file_data:
+    del file_data['targets']
+
+  return file_data
+
+
+def ReplaceSubstrings(values, search_for, replace_with):
+  """Recursively replaces substrings in a value.
+
+  Replaces all substrings of the "search_for" with "repace_with" for all
+  strings occurring in "values". This is done by recursively iterating into
+  lists as well as the keys and values of dictionaries."""
+  if isinstance(values, str):
+    return values.replace(search_for, replace_with)
+
+  if isinstance(values, list):
+    return [ReplaceSubstrings(v, search_for, replace_with) for v in values]
+
+  if isinstance(values, dict):
+    # For dictionaries, do the search for both the key and values.
+    result = {}
+    for key, value in values.items():
+      new_key = ReplaceSubstrings(key, search_for, replace_with)
+      new_value = ReplaceSubstrings(value, search_for, replace_with)
+      result[new_key] = new_value
+    return result
+
+  # Assume everything else is unchanged.
+  return values
+
+def main():
+  parser = OptionParser()
+  parser.add_option("-r", "--replace", action="append",
+    help="Replaces substrings. If passed a=b, replaces all substrs a with b.")
+  (options, args) = parser.parse_args()
+
+  if len(args) != 1:
+    raise Exception("Need one argument which is the .gypi file to read.")
+
+  data = LoadPythonDictionary(args[0])
+  if options.replace:
+    # Do replacements for all specified patterns.
+    for replace in options.replace:
+      split = replace.split('=')
+      # Allow "foo=" to replace with nothing.
+      if len(split) == 1:
+        split.append('')
+      assert len(split) == 2, "Replacement must be of the form 'key=value'."
+      data = ReplaceSubstrings(data, split[0], split[1])
+
+  # Sometimes .gypi files use the GYP syntax with percents at the end of the
+  # variable name (to indicate not to overwrite a previously-defined value):
+  #   'foo%': 'bar',
+  # Convert these to regular variables.
+  for key in data:
+    if len(key) > 1 and key[len(key) - 1] == '%':
+      data[key[:-1]] = data[key]
+      del data[key]
+
+  print gn_helpers.ToGNString(data)
+
+if __name__ == '__main__':
+  try:
+    main()
+  except Exception, e:
+    print str(e)
+    sys.exit(1)
diff --git a/build/host_jar.gypi b/build/host_jar.gypi
new file mode 100644
index 0000000..9c35177
--- /dev/null
+++ b/build/host_jar.gypi
@@ -0,0 +1,131 @@
+# Copyright 2014 The Chromium 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 to be included into a target to provide a rule to build
+# a JAR file for use on a host in a consistent manner. If a main class is
+# specified, this file will also generate an executable to run the jar in the
+# output folder's /bin/ directory.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_jar',
+#   'type': 'none',
+#   'variables': {
+#     'src_paths': [
+#       'path/to/directory',
+#       'path/to/other/directory',
+#       'path/to/individual_file.java',
+#       ...
+#     ],
+#   },
+#   'includes': [ 'path/to/this/gypi/file' ],
+# }
+#
+# Required variables:
+#   src_paths - A list of all paths containing java files that should be
+#     included in the jar. Paths can be either directories or files.
+# Optional/automatic variables:
+#   excluded_src_paths - A list of all paths that should be excluded from
+#     the jar.
+#   generated_src_dirs - Directories containing additional .java files
+#     generated at build time.
+#   input_jars_paths - A list of paths to the jars that should be included
+#     in the classpath.
+#   main_class - The class containing the main() function that should be called
+#     when running the jar file.
+#   jar_excluded_classes - A list of .class files that should be excluded
+#     from the jar.
+
+{
+  'dependencies': [
+    '<(DEPTH)/build/android/setup.gyp:build_output_dirs',
+  ],
+  'variables': {
+    'classes_dir': '<(intermediate_dir)/classes',
+    'excluded_src_paths': [],
+    'generated_src_dirs': [],
+    'input_jars_paths': [],
+    'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
+    'jar_dir': '<(PRODUCT_DIR)/lib.java',
+    'jar_excluded_classes': [],
+    'jar_name': '<(_target_name).jar',
+    'jar_path': '<(jar_dir)/<(jar_name)',
+    'main_class%': '',
+    'stamp': '<(intermediate_dir)/jar.stamp',
+  },
+  'all_dependent_settings': {
+    'variables': {
+      'input_jars_paths': ['<(jar_path)']
+    },
+  },
+  'actions': [
+    {
+      'action_name': 'javac_<(_target_name)',
+      'message': 'Compiling <(_target_name) java sources',
+      'variables': {
+        'extra_options': [],
+        'java_sources': [ '<!@(find <@(src_paths) -name "*.java")' ],
+        'conditions': [
+          ['"<(excluded_src_paths)" != ""', {
+            'java_sources!': ['<!@(find <@(excluded_src_paths) -name "*.java")']
+          }],
+          ['"<(jar_excluded_classes)" != ""', {
+            'extra_options': ['--jar-excluded-classes=<(jar_excluded_classes)']
+          }],
+          ['main_class != ""', {
+            'extra_options': ['--main-class=>(main_class)']
+          }]
+        ],
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/javac.py',
+        '^@(java_sources)',
+        '>@(input_jars_paths)',
+      ],
+      'outputs': [
+        '<(jar_path)',
+        '<(stamp)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/javac.py',
+        '--classpath=>(input_jars_paths)',
+        '--src-gendirs=>(generated_src_dirs)',
+        '--chromium-code=<(chromium_code)',
+        '--stamp=<(stamp)',
+        '--jar-path=<(jar_path)',
+        '<@(extra_options)',
+        '^@(java_sources)',
+      ],
+    },
+  ],
+  'conditions': [
+    ['main_class != ""', {
+      'actions': [
+        {
+          'action_name': 'create_java_binary_script_<(_target_name)',
+          'message': 'Creating java binary script <(_target_name)',
+          'variables': {
+            'output': '<(PRODUCT_DIR)/bin/<(_target_name)',
+          },
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/create_java_binary_script.py',
+            '<(jar_path)',
+          ],
+          'outputs': [
+            '<(output)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/create_java_binary_script.py',
+            '--classpath=>(input_jars_paths)',
+            '--jar-path=<(jar_path)',
+            '--output=<(output)',
+            '--main-class=>(main_class)',
+          ]
+        }
+      ]
+    }]
+  ]
+}
+
diff --git a/build/host_prebuilt_jar.gypi b/build/host_prebuilt_jar.gypi
new file mode 100644
index 0000000..feed5ca
--- /dev/null
+++ b/build/host_prebuilt_jar.gypi
@@ -0,0 +1,50 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule to
+# copy a prebuilt JAR for use on a host to the output directory.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_prebuilt_jar',
+#   'type': 'none',
+#   'variables': {
+#     'jar_path': 'path/to/prebuilt.jar',
+#   },
+#   'includes': [ 'path/to/this/gypi/file' ],
+# }
+#
+# Required variables:
+#   jar_path - The path to the prebuilt jar.
+
+{
+  'dependencies': [
+  ],
+  'variables': {
+    'dest_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).jar',
+    'src_path': '<(jar_path)',
+  },
+  'all_dependent_settings': {
+    'variables': {
+      'input_jars_paths': [
+        '<(dest_path)',
+      ]
+    },
+  },
+  'actions': [
+    {
+      'action_name': 'copy_prebuilt_jar',
+      'message': 'Copy <(src_path) to <(dest_path)',
+      'inputs': [
+        '<(src_path)',
+      ],
+      'outputs': [
+        '<(dest_path)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/cp.py', '<(src_path)', '<(dest_path)',
+      ],
+    }
+  ]
+}
diff --git a/build/install-android-sdks.sh b/build/install-android-sdks.sh
new file mode 100755
index 0000000..5c4edaf
--- /dev/null
+++ b/build/install-android-sdks.sh
@@ -0,0 +1,25 @@
+#!/bin/bash -e
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Script to install SDKs needed to build chromium on android.
+# See http://code.google.com/p/chromium/wiki/AndroidBuildInstructions
+
+echo 'checking for sdk packages install'
+# Use absolute path to call 'android' so script can be run from any directory.
+cwd=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+# Get the SDK extras packages to install from the DEPS file 'sdkextras' hook.
+packages="$(python ${cwd}/get_sdk_extras_packages.py)"
+for package in "${packages}"; do
+  pkg_id=$(${cwd}/../third_party/android_tools/sdk/tools/android list sdk | \
+                grep -i "$package," | \
+                awk '/^[ ]*[0-9]*- / {gsub("-",""); print $1}')
+  if [[ -n ${pkg_id} ]]; then
+    ${cwd}/../third_party/android_tools/sdk/tools/android update sdk --no-ui \
+       --filter ${pkg_id}
+  fi
+done
+
+echo "install-android-sdks.sh complete."
diff --git a/build/install-build-deps-android.sh b/build/install-build-deps-android.sh
new file mode 100755
index 0000000..cf87381
--- /dev/null
+++ b/build/install-build-deps-android.sh
@@ -0,0 +1,100 @@
+#!/bin/bash -e
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Script to install everything needed to build chromium on android, including
+# items requiring sudo privileges.
+# See http://code.google.com/p/chromium/wiki/AndroidBuildInstructions
+
+# This script installs the sun-java6 packages (bin, jre and jdk). Sun requires
+# a license agreement, so upon installation it will prompt the user. To get
+# past the curses-based dialog press TAB <ret> TAB <ret> to agree.
+
+args="$@"
+if test "$1" = "--skip-sdk-packages"; then
+  skip_inst_sdk_packages=1
+  args="${@:2}"
+else
+  skip_inst_sdk_packages=0
+fi
+
+if ! uname -m | egrep -q "i686|x86_64"; then
+  echo "Only x86 architectures are currently supported" >&2
+  exit
+fi
+
+# Install first the default Linux build deps.
+"$(dirname "${BASH_SOURCE[0]}")/install-build-deps.sh" \
+  --no-syms --lib32 --no-arm --no-chromeos-fonts --no-nacl --no-prompt "${args}"
+
+lsb_release=$(lsb_release --codename --short)
+
+# The temporary directory used to store output of update-java-alternatives
+TEMPDIR=$(mktemp -d)
+cleanup() {
+  local status=${?}
+  trap - EXIT
+  rm -rf "${TEMPDIR}"
+  exit ${status}
+}
+trap cleanup EXIT
+
+# Fix deps
+sudo apt-get -f install
+
+# Install deps
+# This step differs depending on what Ubuntu release we are running
+# on since the package names are different, and Sun's Java must
+# be installed manually on late-model versions.
+
+# common
+sudo apt-get -y install lighttpd python-pexpect xvfb x11-utils
+
+# Some binaries in the Android SDK require 32-bit libraries on the host.
+# See https://developer.android.com/sdk/installing/index.html?pkg=tools
+if [[ $lsb_release == "precise" ]]; then
+  sudo apt-get -y install ia32-libs
+else
+  sudo apt-get -y install libncurses5:i386 libstdc++6:i386 zlib1g:i386
+fi
+
+sudo apt-get -y install ant
+
+# Install openjdk and openjre 7 stuff
+sudo apt-get -y install openjdk-7-jre openjdk-7-jdk
+
+# Switch version of Java to openjdk 7.
+# Some Java plugins (e.g. for firefox, mozilla) are not required to build, and
+# thus are treated only as warnings. Any errors in updating java alternatives
+# which are not '*-javaplugin.so' will cause errors and stop the script from
+# completing successfully.
+if ! sudo update-java-alternatives -s java-1.7.0-openjdk-amd64 \
+           >& "${TEMPDIR}"/update-java-alternatives.out
+then
+  # Check that there are the expected javaplugin.so errors for the update
+  if grep 'javaplugin.so' "${TEMPDIR}"/update-java-alternatives.out >& \
+      /dev/null
+  then
+    # Print as warnings all the javaplugin.so errors
+    echo 'WARNING: java-6-sun has no alternatives for the following plugins:'
+    grep 'javaplugin.so' "${TEMPDIR}"/update-java-alternatives.out
+  fi
+  # Check if there are any errors that are not javaplugin.so
+  if grep -v 'javaplugin.so' "${TEMPDIR}"/update-java-alternatives.out \
+      >& /dev/null
+  then
+    # If there are non-javaplugin.so errors, treat as errors and exit
+    echo 'ERRORS: Failed to update alternatives for java-6-sun:'
+    grep -v 'javaplugin.so' "${TEMPDIR}"/update-java-alternatives.out
+    exit 1
+  fi
+fi
+
+# Install SDK packages for android
+if test "$skip_inst_sdk_packages" != 1; then
+  "$(dirname "${BASH_SOURCE[0]}")/install-android-sdks.sh"
+fi
+
+echo "install-build-deps-android.sh complete."
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
new file mode 100755
index 0000000..2a2d50b
--- /dev/null
+++ b/build/install-build-deps.sh
@@ -0,0 +1,461 @@
+#!/bin/bash -e
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Script to install everything needed to build chromium (well, ideally, anyway)
+# See http://code.google.com/p/chromium/wiki/LinuxBuildInstructions
+# and http://code.google.com/p/chromium/wiki/LinuxBuild64Bit
+
+usage() {
+  echo "Usage: $0 [--options]"
+  echo "Options:"
+  echo "--[no-]syms: enable or disable installation of debugging symbols"
+  echo "--lib32: enable installation of 32-bit libraries, e.g. for V8 snapshot"
+  echo "--[no-]arm: enable or disable installation of arm cross toolchain"
+  echo "--[no-]chromeos-fonts: enable or disable installation of Chrome OS"\
+       "fonts"
+  echo "--[no-]nacl: enable or disable installation of prerequisites for"\
+       "building standalone NaCl and all its toolchains"
+  echo "--no-prompt: silently select standard options/defaults"
+  echo "--quick-check: quickly try to determine if dependencies are installed"
+  echo "               (this avoids interactive prompts and sudo commands,"
+  echo "               so might not be 100% accurate)"
+  echo "--unsupported: attempt installation even on unsupported systems"
+  echo "Script will prompt interactively if options not given."
+  exit 1
+}
+
+# Checks whether a particular package is available in the repos.
+# USAGE: $ package_exists <package name>
+package_exists() {
+  apt-cache pkgnames | grep -x "$1" > /dev/null 2>&1
+}
+
+# These default to on because (some) bots need them and it keeps things
+# simple for the bot setup if all bots just run the script in its default
+# mode.  Developers who don't want stuff they don't need installed on their
+# own workstations can pass --no-arm --no-nacl when running the script.
+do_inst_arm=1
+do_inst_nacl=1
+
+while test "$1" != ""
+do
+  case "$1" in
+  --syms)                   do_inst_syms=1;;
+  --no-syms)                do_inst_syms=0;;
+  --lib32)                  do_inst_lib32=1;;
+  --arm)                    do_inst_arm=1;;
+  --no-arm)                 do_inst_arm=0;;
+  --chromeos-fonts)         do_inst_chromeos_fonts=1;;
+  --no-chromeos-fonts)      do_inst_chromeos_fonts=0;;
+  --nacl)                   do_inst_nacl=1;;
+  --no-nacl)                do_inst_nacl=0;;
+  --no-prompt)              do_default=1
+                            do_quietly="-qq --assume-yes"
+    ;;
+  --quick-check)            do_quick_check=1;;
+  --unsupported)            do_unsupported=1;;
+  *) usage;;
+  esac
+  shift
+done
+
+if test "$do_inst_arm" = "1"; then
+  do_inst_lib32=1
+fi
+
+# Check for lsb_release command in $PATH
+if ! which lsb_release > /dev/null; then
+  echo "ERROR: lsb_release not found in \$PATH" >&2
+  exit 1;
+fi
+
+lsb_release=$(lsb_release --codename --short)
+ubuntu_codenames="(precise|trusty|utopic|vivid)"
+if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
+  if [[ ! $lsb_release =~ $ubuntu_codenames ]]; then
+    echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty), " \
+      "14.10 (utopic) and 15.04 (vivid) are currently supported" >&2
+    exit 1
+  fi
+
+  if ! uname -m | egrep -q "i686|x86_64"; then
+    echo "Only x86 architectures are currently supported" >&2
+    exit
+  fi
+fi
+
+if [ "x$(id -u)" != x0 ] && [ 0 -eq "${do_quick_check-0}" ]; then
+  echo "Running as non-root user."
+  echo "You might have to enter your password one or more times for 'sudo'."
+  echo
+fi
+
+# Packages needed for chromeos only
+chromeos_dev_list="libbluetooth-dev libxkbcommon-dev"
+
+# Packages needed for development
+dev_list="apache2.2-bin bison cdbs curl dpkg-dev elfutils devscripts fakeroot
+          flex fonts-thai-tlwg g++ git-core git-svn gperf language-pack-da
+          language-pack-fr language-pack-he language-pack-zh-hant
+          libapache2-mod-php5 libasound2-dev libbrlapi-dev libav-tools
+          libbz2-dev libcairo2-dev libcap-dev libcups2-dev libcurl4-gnutls-dev
+          libdrm-dev libelf-dev libexif-dev libgconf2-dev libglib2.0-dev
+          libglu1-mesa-dev libgnome-keyring-dev libgtk2.0-dev libkrb5-dev
+          libnspr4-dev libnss3-dev libpam0g-dev libpci-dev libpulse-dev
+          libsctp-dev libspeechd-dev libsqlite3-dev libssl-dev libudev-dev
+          libwww-perl libxslt1-dev libxss-dev libxt-dev libxtst-dev openbox
+          patch perl php5-cgi pkg-config python python-cherrypy3 python-crypto
+          python-dev python-numpy python-opencv python-openssl python-psutil
+          rpm ruby subversion ttf-dejavu-core ttf-indic-fonts ttf-kochi-gothic
+          ttf-kochi-mincho wdiff xfonts-mathml zip $chromeos_dev_list"
+
+# 64-bit systems need a minimum set of 32-bit compat packages for the pre-built
+# NaCl binaries.
+if file /sbin/init | grep -q 'ELF 64-bit'; then
+  dev_list="${dev_list} libc6-i386 lib32gcc1 lib32stdc++6"
+fi
+
+# Run-time libraries required by chromeos only
+chromeos_lib_list="libpulse0 libbz2-1.0"
+
+# Full list of required run-time libraries
+lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libcap2 libcups2 libexpat1
+          libexif12 libfontconfig1 libfreetype6 libglib2.0-0 libgnome-keyring0
+          libgtk2.0-0 libpam0g libpango1.0-0 libpci3 libpcre3 libpixman-1-0
+          libpng12-0 libspeechd2 libstdc++6 libsqlite3-0 libx11-6
+          libxau6 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6
+          libxext6 libxfixes3 libxi6 libxinerama1 libxrandr2 libxrender1
+          libxtst6 zlib1g $chromeos_lib_list"
+
+# Debugging symbols for all of the run-time libraries
+dbg_list="libatk1.0-dbg libc6-dbg libcairo2-dbg libfontconfig1-dbg
+          libglib2.0-0-dbg libgtk2.0-0-dbg libpango1.0-0-dbg libpcre3-dbg
+          libpixman-1-0-dbg libsqlite3-0-dbg libx11-6-dbg libxau6-dbg
+          libxcb1-dbg libxcomposite1-dbg libxcursor1-dbg libxdamage1-dbg
+          libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg libxinerama1-dbg
+          libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg"
+
+# Find the proper version of libstdc++6-4.x-dbg.
+if [ "x$lsb_release" = "xprecise" ]; then
+  dbg_list="${dbg_list} libstdc++6-4.6-dbg"
+elif [ "x$lsb_release" = "xtrusty" ]; then
+  dbg_list="${dbg_list} libstdc++6-4.8-dbg"
+else
+  dbg_list="${dbg_list} libstdc++6-4.9-dbg"
+fi
+
+# 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf
+lib32_list="linux-libc-dev:i386"
+
+# arm cross toolchain packages needed to build chrome on armhf
+arm_list="libc6-dev-armhf-cross
+          linux-libc-dev-armhf-cross
+          g++-arm-linux-gnueabihf"
+
+# Work around for dependency issue Ubuntu/Trusty: http://crbug.com/435056
+if [ "x$lsb_release" = "xtrusty" ]; then
+  arm_list+=" g++-4.8-multilib-arm-linux-gnueabihf
+              gcc-4.8-multilib-arm-linux-gnueabihf"
+fi
+
+# Packages to build NaCl, its toolchains, and its ports.
+naclports_list="ant autoconf bison cmake gawk intltool xutils-dev xsltproc"
+nacl_list="g++-mingw-w64-i686 lib32z1-dev
+           libasound2:i386 libcap2:i386 libelf-dev:i386 libexif12:i386
+           libfontconfig1:i386 libgconf-2-4:i386 libglib2.0-0:i386 libgpm2:i386
+           libgtk2.0-0:i386 libncurses5:i386 lib32ncurses5-dev
+           libnss3:i386 libpango1.0-0:i386
+           libssl1.0.0:i386 libtinfo-dev libtinfo-dev:i386 libtool
+           libxcomposite1:i386 libxcursor1:i386 libxdamage1:i386 libxi6:i386
+           libxrandr2:i386 libxss1:i386 libxtst6:i386 texinfo xvfb
+           ${naclports_list}"
+
+# Find the proper version of libgbm-dev. We can't just install libgbm-dev as
+# it depends on mesa, and only one version of mesa can exists on the system.
+# Hence we must match the same version or this entire script will fail.
+mesa_variant=""
+for variant in "-lts-trusty" "-lts-utopic"; do
+  if $(dpkg-query -Wf'${Status}' libgl1-mesa-glx${variant} 2>/dev/null | \
+       grep -q " ok installed"); then
+    mesa_variant="${variant}"
+  fi
+done
+dev_list="${dev_list} libgbm-dev${mesa_variant}
+          libgles2-mesa-dev${mesa_variant} libgl1-mesa-dev${mesa_variant}
+          mesa-common-dev${mesa_variant}"
+nacl_list="${nacl_list} libgl1-mesa-glx${mesa_variant}:i386"
+
+# Some package names have changed over time
+if package_exists ttf-mscorefonts-installer; then
+  dev_list="${dev_list} ttf-mscorefonts-installer"
+else
+  dev_list="${dev_list} msttcorefonts"
+fi
+if package_exists libnspr4-dbg; then
+  dbg_list="${dbg_list} libnspr4-dbg libnss3-dbg"
+  lib_list="${lib_list} libnspr4 libnss3"
+else
+  dbg_list="${dbg_list} libnspr4-0d-dbg libnss3-1d-dbg"
+  lib_list="${lib_list} libnspr4-0d libnss3-1d"
+fi
+if package_exists libjpeg-dev; then
+  dev_list="${dev_list} libjpeg-dev"
+else
+  dev_list="${dev_list} libjpeg62-dev"
+fi
+if package_exists libudev1; then
+  dev_list="${dev_list} libudev1"
+  nacl_list="${nacl_list} libudev1:i386"
+else
+  dev_list="${dev_list} libudev0"
+  nacl_list="${nacl_list} libudev0:i386"
+fi
+if package_exists libbrlapi0.6; then
+  dev_list="${dev_list} libbrlapi0.6"
+else
+  dev_list="${dev_list} libbrlapi0.5"
+fi
+
+
+# Some packages are only needed if the distribution actually supports
+# installing them.
+if package_exists appmenu-gtk; then
+  lib_list="$lib_list appmenu-gtk"
+fi
+
+# When cross building for arm/Android on 64-bit systems the host binaries
+# that are part of v8 need to be compiled with -m32 which means
+# that basic multilib support is needed.
+if file /sbin/init | grep -q 'ELF 64-bit'; then
+  # gcc-multilib conflicts with the arm cross compiler (at least in trusty) but
+  # g++-X.Y-multilib gives us the 32-bit support that we need. Find out the
+  # appropriate value of X and Y by seeing what version the current
+  # distribution's g++-multilib package depends on.
+  multilib_package=$(apt-cache depends g++-multilib --important | \
+      grep -E --color=never --only-matching '\bg\+\+-[0-9.]+-multilib\b')
+  lib32_list="$lib32_list $multilib_package"
+fi
+
+# Waits for the user to press 'Y' or 'N'. Either uppercase of lowercase is
+# accepted. Returns 0 for 'Y' and 1 for 'N'. If an optional parameter has
+# been provided to yes_no(), the function also accepts RETURN as a user input.
+# The parameter specifies the exit code that should be returned in that case.
+# The function will echo the user's selection followed by a newline character.
+# Users can abort the function by pressing CTRL-C. This will call "exit 1".
+yes_no() {
+  if [ 0 -ne "${do_default-0}" ] ; then
+    [ $1 -eq 0 ] && echo "Y" || echo "N"
+    return $1
+  fi
+  local c
+  while :; do
+    c="$(trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT
+         stty -echo iuclc -icanon 2>/dev/null
+         dd count=1 bs=1 2>/dev/null | od -An -tx1)"
+    case "$c" in
+      " 0a") if [ -n "$1" ]; then
+               [ $1 -eq 0 ] && echo "Y" || echo "N"
+               return $1
+             fi
+             ;;
+      " 79") echo "Y"
+             return 0
+             ;;
+      " 6e") echo "N"
+             return 1
+             ;;
+      "")    echo "Aborted" >&2
+             exit 1
+             ;;
+      *)     # The user pressed an unrecognized key. As we are not echoing
+             # any incorrect user input, alert the user by ringing the bell.
+             (tput bel) 2>/dev/null
+             ;;
+    esac
+  done
+}
+
+if test "$do_inst_syms" = "" && test 0 -eq ${do_quick_check-0}
+then
+  echo "This script installs all tools and libraries needed to build Chromium."
+  echo ""
+  echo "For most of the libraries, it can also install debugging symbols, which"
+  echo "will allow you to debug code in the system libraries. Most developers"
+  echo "won't need these symbols."
+  echo -n "Do you want me to install them for you (y/N) "
+  if yes_no 1; then
+    do_inst_syms=1
+  fi
+fi
+if test "$do_inst_syms" = "1"; then
+  echo "Including debugging symbols."
+else
+  echo "Skipping debugging symbols."
+  dbg_list=
+fi
+
+if test "$do_inst_lib32" = "1" ; then
+  echo "Including 32-bit libraries for ARM/Android."
+else
+  echo "Skipping 32-bit libraries for ARM/Android."
+  lib32_list=
+fi
+
+if test "$do_inst_arm" = "1" ; then
+  echo "Including ARM cross toolchain."
+else
+  echo "Skipping ARM cross toolchain."
+  arm_list=
+fi
+
+if test "$do_inst_nacl" = "1"; then
+  echo "Including NaCl, NaCl toolchain, NaCl ports dependencies."
+else
+  echo "Skipping NaCl, NaCl toolchain, NaCl ports dependencies."
+  nacl_list=
+fi
+
+# The `sort -r -s -t: -k2` sorts all the :i386 packages to the front, to avoid
+# confusing dpkg-query (crbug.com/446172).
+packages="$(
+  echo "${dev_list} ${lib_list} ${dbg_list} ${lib32_list} ${arm_list}"\
+       "${nacl_list}" | tr " " "\n" | sort -u | sort -r -s -t: -k2 | tr "\n" " "
+)"
+
+if [ 1 -eq "${do_quick_check-0}" ] ; then
+  failed_check="$(dpkg-query -W -f '${PackageSpec}:${Status}\n' \
+    ${packages} 2>&1 | grep -v "ok installed" || :)"
+  if [ -n "${failed_check}" ]; then
+    echo
+    nomatch="$(echo "${failed_check}" | \
+      sed -e "s/^No packages found matching \(.*\).$/\1/;t;d")"
+    missing="$(echo "${failed_check}" | \
+      sed -e "/^No packages found matching/d;s/^\(.*\):.*$/\1/")"
+    if [ "$nomatch" ]; then
+      # Distinguish between packages that actually aren't available to the
+      # system (i.e. not in any repo) and packages that just aren't known to
+      # dpkg (i.e. managed by apt).
+      unknown=""
+      for p in ${nomatch}; do
+        if apt-cache show ${p} > /dev/null 2>&1; then
+          missing="${p}\n${missing}"
+        else
+          unknown="${p}\n${unknown}"
+        fi
+      done
+      if [ -n "${unknown}" ]; then
+        echo "WARNING: The following packages are unknown to your system"
+        echo "(maybe missing a repo or need to 'sudo apt-get update'):"
+        echo -e "${unknown}" | sed -e "s/^/  /"
+      fi
+    fi
+    if [ -n "${missing}" ]; then
+      echo "WARNING: The following packages are not installed:"
+      echo -e "${missing}" | sed -e "s/^/  /"
+    fi
+    exit 1
+  fi
+  exit 0
+fi
+
+if test "$do_inst_lib32" = "1" || test "$do_inst_nacl" = "1"; then
+  if [[ ! $lsb_release =~ (precise) ]]; then
+    sudo dpkg --add-architecture i386
+  fi
+fi
+sudo apt-get update
+
+# We initially run "apt-get" with the --reinstall option and parse its output.
+# This way, we can find all the packages that need to be newly installed
+# without accidentally promoting any packages from "auto" to "manual".
+# We then re-run "apt-get" with just the list of missing packages.
+echo "Finding missing packages..."
+# Intentionally leaving $packages unquoted so it's more readable.
+echo "Packages required: " $packages
+echo
+new_list_cmd="sudo apt-get install --reinstall $(echo $packages)"
+if new_list="$(yes n | LANGUAGE=en LANG=C $new_list_cmd)"; then
+  # We probably never hit this following line.
+  echo "No missing packages, and the packages are up-to-date."
+elif [ $? -eq 1 ]; then
+  # We expect apt-get to have exit status of 1.
+  # This indicates that we cancelled the install with "yes n|".
+  new_list=$(echo "$new_list" |
+    sed -e '1,/The following NEW packages will be installed:/d;s/^  //;t;d')
+  new_list=$(echo "$new_list" | sed 's/ *$//')
+  if [ -z "$new_list" ] ; then
+    echo "No missing packages, and the packages are up-to-date."
+  else
+    echo "Installing missing packages: $new_list."
+    sudo apt-get install ${do_quietly-} ${new_list}
+  fi
+  echo
+else
+  # An apt-get exit status of 100 indicates that a real error has occurred.
+
+  # I am intentionally leaving out the '"'s around new_list_cmd,
+  # as this makes it easier to cut and paste the output
+  echo "The following command failed: " ${new_list_cmd}
+  echo
+  echo "It produces the following output:"
+  yes n | $new_list_cmd || true
+  echo
+  echo "You will have to install the above packages yourself."
+  echo
+  exit 100
+fi
+
+# Install the Chrome OS default fonts. This must go after running
+# apt-get, since install-chromeos-fonts depends on curl.
+if test "$do_inst_chromeos_fonts" != "0"; then
+  echo
+  echo "Installing Chrome OS fonts."
+  dir=`echo $0 | sed -r -e 's/\/[^/]+$//'`
+  if ! sudo $dir/linux/install-chromeos-fonts.py; then
+    echo "ERROR: The installation of the Chrome OS default fonts failed."
+    if [ `stat -f -c %T $dir` == "nfs" ]; then
+      echo "The reason is that your repo is installed on a remote file system."
+    else
+      echo "This is expected if your repo is installed on a remote file system."
+    fi
+    echo "It is recommended to install your repo on a local file system."
+    echo "You can skip the installation of the Chrome OS default founts with"
+    echo "the command line option: --no-chromeos-fonts."
+    exit 1
+  fi
+else
+  echo "Skipping installation of Chrome OS fonts."
+fi
+
+# $1 - target name
+# $2 - link name
+create_library_symlink() {
+  target=$1
+  linkname=$2
+  if [ -L $linkname ]; then
+    if [ "$(basename $(readlink $linkname))" != "$(basename $target)" ]; then
+      sudo rm $linkname
+    fi
+  fi
+  if [ ! -r $linkname ]; then
+    echo "Creating link: $linkname"
+    sudo ln -fs $target $linkname
+  fi
+}
+
+if test "$do_inst_nacl" = "1"; then
+  echo "Installing symbolic links for NaCl."
+  # naclports needs to cross build python for i386, but libssl1.0.0:i386
+  # only contains libcrypto.so.1.0.0 and not the symlink needed for
+  # linking (libcrypto.so).
+  create_library_symlink /lib/i386-linux-gnu/libcrypto.so.1.0.0 \
+      /usr/lib/i386-linux-gnu/libcrypto.so
+
+  create_library_symlink /lib/i386-linux-gnu/libssl.so.1.0.0 \
+      /usr/lib/i386-linux-gnu/libssl.so
+else
+  echo "Skipping symbolic links for NaCl."
+fi
diff --git a/build/install-chroot.sh b/build/install-chroot.sh
new file mode 100755
index 0000000..e2d558b
--- /dev/null
+++ b/build/install-chroot.sh
@@ -0,0 +1,858 @@
+#!/bin/bash -e
+
+# Copyright (c) 2012 The Chromium 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 installs Debian-derived distributions in a chroot environment.
+# It can for example be used to have an accurate 32bit build and test
+# environment when otherwise working on a 64bit machine.
+# N. B. it is unlikely that this script will ever work on anything other than a
+# Debian-derived system.
+
+# Older Debian based systems had both "admin" and "adm" groups, with "admin"
+# apparently being used in more places. Newer distributions have standardized
+# on just the "adm" group. Check /etc/group for the preferred name of the
+# administrator group.
+admin=$(grep '^admin:' /etc/group >&/dev/null && echo admin || echo adm)
+
+usage() {
+  echo "usage: ${0##*/} [-m mirror] [-g group,...] [-s] [-c]"
+  echo "-b dir       additional directories that should be bind mounted,"
+  echo '             or "NONE".'
+  echo "             Default: if local filesystems present, ask user for help"
+  echo "-g group,... groups that can use the chroot unauthenticated"
+  echo "             Default: '${admin}' and current user's group ('$(id -gn)')"
+  echo "-l           List all installed chroot environments"
+  echo "-m mirror    an alternate repository mirror for package downloads"
+  echo "-s           configure default deb-srcs"
+  echo "-c           always copy 64bit helper binaries to 32bit chroot"
+  echo "-h           this help message"
+}
+
+process_opts() {
+  local OPTNAME OPTIND OPTERR OPTARG
+  while getopts ":b:g:lm:sch" OPTNAME; do
+    case "$OPTNAME" in
+      b)
+        if [ "${OPTARG}" = "NONE" -a -z "${bind_mounts}" ]; then
+          bind_mounts="${OPTARG}"
+        else
+          if [ "${bind_mounts}" = "NONE" -o "${OPTARG}" = "${OPTARG#/}" -o \
+               ! -d "${OPTARG}" ]; then
+            echo "Invalid -b option(s)"
+            usage
+            exit 1
+          fi
+          bind_mounts="${bind_mounts}
+${OPTARG} ${OPTARG} none rw,bind 0 0"
+        fi
+        ;;
+      g)
+        [ -n "${OPTARG}" ] &&
+          chroot_groups="${chroot_groups}${chroot_groups:+,}${OPTARG}"
+        ;;
+      l)
+        list_all_chroots
+        exit
+        ;;
+      m)
+        if [ -n "${mirror}" ]; then
+          echo "You can only specify exactly one mirror location"
+          usage
+          exit 1
+        fi
+        mirror="$OPTARG"
+        ;;
+      s)
+        add_srcs="y"
+        ;;
+      c)
+        copy_64="y"
+        ;;
+      h)
+        usage
+        exit 0
+        ;;
+      \:)
+        echo "'-$OPTARG' needs an argument."
+        usage
+        exit 1
+        ;;
+      *)
+        echo "invalid command-line option: $OPTARG"
+        usage
+        exit 1
+        ;;
+    esac
+  done
+
+  if [ $# -ge ${OPTIND} ]; then
+    eval echo "Unexpected command line argument: \${${OPTIND}}"
+    usage
+    exit 1
+  fi
+}
+
+list_all_chroots() {
+  for i in /var/lib/chroot/*; do
+    i="${i##*/}"
+    [ "${i}" = "*" ] && continue
+    [ -x "/usr/local/bin/${i%bit}" ] || continue
+    grep -qs "^\[${i%bit}\]\$" /etc/schroot/schroot.conf || continue
+    [ -r "/etc/schroot/script-${i}" -a \
+      -r "/etc/schroot/mount-${i}" ] || continue
+    echo "${i%bit}"
+  done
+}
+
+getkey() {
+  (
+    trap 'stty echo -iuclc icanon 2>/dev/null' EXIT INT TERM QUIT HUP
+    stty -echo iuclc -icanon 2>/dev/null
+    dd count=1 bs=1 2>/dev/null
+  )
+}
+
+chr() {
+  printf "\\$(printf '%03o' "$1")"
+}
+
+ord() {
+  printf '%d' $(printf '%c' "$1" | od -tu1 -An)
+}
+
+is_network_drive() {
+  stat -c %T -f "$1/" 2>/dev/null |
+    egrep -qs '^nfs|cifs|smbfs'
+}
+
+# Check that we are running as a regular user
+[ "$(id -nu)" = root ] && {
+  echo "Run this script as a regular user and provide your \"sudo\""           \
+       "password if requested" >&2
+  exit 1
+}
+
+process_opts "$@"
+
+echo "This script will help you through the process of installing a"
+echo "Debian or Ubuntu distribution in a chroot environment. You will"
+echo "have to provide your \"sudo\" password when requested."
+echo
+
+# Error handler
+trap 'exit 1' INT TERM QUIT HUP
+trap 'sudo apt-get clean; tput bel; echo; echo Failed' EXIT
+
+# Install any missing applications that this script relies on. If these packages
+# are already installed, don't force another "apt-get install". That would
+# prevent them from being auto-removed, if they ever become eligible for that.
+# And as this script only needs the packages once, there is no good reason to
+# introduce a hard dependency on things such as dchroot and debootstrap.
+dep=
+for i in dchroot debootstrap libwww-perl; do
+  [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
+done
+[ -n "$dep" ] && sudo apt-get -y install $dep
+sudo apt-get -y install schroot
+
+# Create directory for chroot
+sudo mkdir -p /var/lib/chroot
+
+# Find chroot environments that can be installed with debootstrap
+targets="$(cd /usr/share/debootstrap/scripts
+           ls | grep '^[a-z]*$')"
+
+# Ask user to pick one of the available targets
+echo "The following targets are available to be installed in a chroot:"
+j=1; for i in $targets; do
+  printf '%4d: %s\n' "$j" "$i"
+  j=$(($j+1))
+done
+while :; do
+  printf "Which target would you like to install: "
+  read n
+  [ "$n" -gt 0 -a "$n" -lt "$j" ] >&/dev/null && break
+done
+j=1; for i in $targets; do
+  [ "$j" -eq "$n" ] && { distname="$i"; break; }
+  j=$(($j+1))
+done
+echo
+
+# On x86-64, ask whether the user wants to install x86-32 or x86-64
+archflag=
+arch=
+if [ "$(uname -m)" = x86_64 ]; then
+  while :; do
+    echo "You are running a 64bit kernel. This allows you to install either a"
+    printf "32bit or a 64bit chroot environment. %s"                           \
+           "Which one do you want (32, 64) "
+    read arch
+    [ "${arch}" == 32 -o "${arch}" == 64 ] && break
+  done
+  [ "${arch}" == 32 ] && archflag="--arch i386" || archflag="--arch amd64"
+  arch="${arch}bit"
+  echo
+fi
+target="${distname}${arch}"
+
+# Don't accidentally overwrite an existing installation
+[ -d /var/lib/chroot/"${target}" ] && {
+  while :; do
+    echo "This chroot already exists on your machine."
+    if schroot -l --all-sessions 2>&1 |
+       sed 's/^session://' |
+       grep -qs "^${target%bit}-"; then
+      echo "And it appears to be in active use. Terminate all programs that"
+      echo "are currently using the chroot environment and then re-run this"
+      echo "script."
+      echo "If you still get an error message, you might have stale mounts"
+      echo "that you forgot to delete. You can always clean up mounts by"
+      echo "executing \"${target%bit} -c\"."
+      exit 1
+    fi
+    echo "I can abort installation, I can overwrite the existing chroot,"
+    echo "or I can delete the old one and then exit. What would you like to"
+    printf "do (a/o/d)? "
+    read choice
+    case "${choice}" in
+      a|A) exit 1;;
+      o|O) sudo rm -rf "/var/lib/chroot/${target}"; break;;
+      d|D) sudo rm -rf "/var/lib/chroot/${target}"      \
+                       "/usr/local/bin/${target%bit}"   \
+                       "/etc/schroot/mount-${target}"   \
+                       "/etc/schroot/script-${target}"
+           sudo sed -ni '/^[[]'"${target%bit}"']$/,${
+                         :1;n;/^[[]/b2;b1;:2;p;n;b2};p' \
+                       "/etc/schroot/schroot.conf"
+           trap '' INT TERM QUIT HUP
+           trap '' EXIT
+           echo "Deleted!"
+           exit 0;;
+    esac
+  done
+  echo
+}
+sudo mkdir -p /var/lib/chroot/"${target}"
+
+# Offer to include additional standard repositories for Ubuntu-based chroots.
+alt_repos=
+grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" && {
+  while :; do
+    echo "Would you like to add ${distname}-updates and ${distname}-security "
+    printf "to the chroot's sources.list (y/n)? "
+    read alt_repos
+    case "${alt_repos}" in
+      y|Y)
+        alt_repos="y"
+        break
+      ;;
+      n|N)
+        break
+      ;;
+    esac
+  done
+  echo
+}
+
+# Check for non-standard file system mount points and ask the user whether
+# they should be imported into the chroot environment
+# We limit to the first 26 mount points that much some basic heuristics,
+# because a) that allows us to enumerate choices with a single character,
+# and b) if we find more than 26 mount points, then these are probably
+# false-positives and something is very unusual about the system's
+# configuration. No need to spam the user with even more information that
+# is likely completely irrelevant.
+if [ -z "${bind_mounts}" ]; then
+  mounts="$(awk '$2 != "/" && $2 !~ "^/boot" && $2 !~ "^/home" &&
+                 $2 !~ "^/media" && $2 !~ "^/run" &&
+                 ($3 ~ "ext[2-4]" || $3 == "reiserfs" || $3 == "btrfs" ||
+                 $3 == "xfs" || $3 == "jfs" || $3 == "u?msdos" ||
+                 $3 == "v?fat" || $3 == "hfs" || $3 == "ntfs" ||
+                 $3 ~ "nfs[4-9]?" || $3 == "smbfs" || $3 == "cifs") {
+                   print $2
+                 }' /proc/mounts |
+            head -n26)"
+  if [ -n "${mounts}" ]; then
+    echo "You appear to have non-standard mount points that you"
+    echo "might want to import into the chroot environment:"
+    echo
+    sel=
+    while :; do
+      # Print a menu, listing all non-default mounts of local or network
+      # file systems.
+      j=1; for m in ${mounts}; do
+        c="$(printf $(printf '\\%03o' $((64+$j))))"
+        echo "$sel" | grep -qs $c &&
+          state="mounted in chroot" || state="$(tput el)"
+        printf "   $c) %-40s${state}\n" "$m"
+        j=$(($j+1))
+      done
+      # Allow user to interactively (de-)select any of the entries
+      echo
+      printf "Select mount points that you want to be included or press %s" \
+             "SPACE to continue"
+      c="$(getkey | tr a-z A-Z)"
+      [ "$c" == " " ] && { echo; echo; break; }
+      if [ -z "$c" ] ||
+         [ "$c" '<' 'A' -o $(ord "$c") -gt $((64 + $(ord "$j"))) ]; then
+          # Invalid input, ring the console bell
+          tput bel
+      else
+        # Toggle the selection for the given entry
+        if echo "$sel" | grep -qs $c; then
+          sel="$(printf "$sel" | sed "s/$c//")"
+        else
+          sel="$sel$c"
+        fi
+      fi
+      # Reposition cursor to the top of the list of entries
+      tput cuu $(($j + 1))
+      echo
+    done
+  fi
+  j=1; for m in ${mounts}; do
+    c="$(chr $(($j + 64)))"
+    if echo "$sel" | grep -qs $c; then
+      bind_mounts="${bind_mounts}$m $m none rw,bind 0 0
+"
+    fi
+    j=$(($j+1))
+  done
+fi
+
+# Remove stale entry from /etc/schroot/schroot.conf. Entries start
+# with the target name in square brackets, followed by an arbitrary
+# number of lines. The entry stops when either the end of file has
+# been reached, or when the beginning of a new target is encountered.
+# This means, we cannot easily match for a range of lines in
+# "sed". Instead, we actually have to iterate over each line and check
+# whether it is the beginning of a new entry.
+sudo sed -ni '/^[[]'"${target%bit}"']$/,${:1;n;/^[[]/b2;b1;:2;p;n;b2};p'       \
+         /etc/schroot/schroot.conf
+
+# Download base system. This takes some time
+if [ -z "${mirror}" ]; then
+ grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" &&
+   mirror="http://archive.ubuntu.com/ubuntu" ||
+   mirror="http://ftp.us.debian.org/debian"
+fi
+
+sudo ${http_proxy:+http_proxy="${http_proxy}"} debootstrap ${archflag} \
+    "${distname}" "/var/lib/chroot/${target}"  "$mirror"
+
+# Add new entry to /etc/schroot/schroot.conf
+grep -qs ubuntu.com /usr/share/debootstrap/scripts/"${distname}" &&
+  brand="Ubuntu" || brand="Debian"
+if [ -z "${chroot_groups}" ]; then
+  chroot_groups="${admin},$(id -gn)"
+fi
+# Older versions of schroot wanted a "priority=" line, whereas recent
+# versions deprecate "priority=" and warn if they see it. We don't have
+# a good feature test, but scanning for the string "priority=" in the
+# existing "schroot.conf" file is a good indication of what to do.
+priority=$(grep -qs 'priority=' /etc/schroot/schroot.conf &&
+           echo 'priority=3' || :)
+sudo sh -c 'cat >>/etc/schroot/schroot.conf' <<EOF
+[${target%bit}]
+description=${brand} ${distname} ${arch}
+type=directory
+directory=/var/lib/chroot/${target}
+users=root
+groups=${chroot_groups}
+root-groups=${chroot_groups}
+personality=linux$([ "${arch}" != 64bit ] && echo 32)
+script-config=script-${target}
+${priority}
+
+EOF
+
+# Set up a list of mount points that is specific to this
+# chroot environment.
+sed '/^FSTAB=/s,"[^"]*","/etc/schroot/mount-'"${target}"'",' \
+         /etc/schroot/script-defaults |
+  sudo sh -c 'cat >/etc/schroot/script-'"${target}"
+sed '\,^/home[/[:space:]],s/\([,[:space:]]\)bind[[:space:]]/\1rbind /' \
+  /etc/schroot/mount-defaults |
+  sudo sh -c 'cat > /etc/schroot/mount-'"${target}"
+
+# Add the extra mount points that the user told us about
+[ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] &&
+  printf "${bind_mounts}" |
+    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+
+# If this system has a "/media" mountpoint, import it into the chroot
+# environment. Most modern distributions use this mount point to
+# automatically mount devices such as CDROMs, USB sticks, etc...
+if [ -d /media ] &&
+   ! grep -qs '^/media' /etc/schroot/mount-"${target}"; then
+  echo '/media /media none rw,rbind 0 0' |
+    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+fi
+
+# Share /dev/shm, /run and /run/shm.
+grep -qs '^/dev/shm' /etc/schroot/mount-"${target}" ||
+  echo '/dev/shm /dev/shm none rw,bind 0 0' |
+    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+if [ ! -d "/var/lib/chroot/${target}/run" ] &&
+   ! grep -qs '^/run' /etc/schroot/mount-"${target}"; then
+  echo '/run /run none rw,bind 0 0' |
+    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+fi
+if ! grep -qs '^/run/shm' /etc/schroot/mount-"${target}"; then
+  { [ -d /run ] && echo '/run/shm /run/shm none rw,bind 0 0' ||
+                   echo '/dev/shm /run/shm none rw,bind 0 0'; } |
+    sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+fi
+
+# Set up a special directory that changes contents depending on the target
+# that is executing.
+d="$(readlink -f "${HOME}/chroot" 2>/dev/null || echo "${HOME}/chroot")"
+s="${d}/.${target}"
+echo "${s} ${d} none rw,bind 0 0" |
+  sudo sh -c 'cat >>/etc/schroot/mount-'"${target}"
+mkdir -p "${s}"
+
+# Install a helper script to launch commands in the chroot
+sudo sh -c 'cat >/usr/local/bin/'"${target%bit}" <<'EOF'
+#!/bin/bash
+
+chroot="${0##*/}"
+
+wrap() {
+  # Word-wrap the text passed-in on stdin. Optionally, on continuation lines
+  # insert the same number of spaces as the number of characters in the
+  # parameter(s) passed to this function.
+  # If the "fold" program cannot be found, or if the actual width of the
+  # terminal cannot be determined, this function doesn't attempt to do any
+  # wrapping.
+  local f="$(type -P fold)"
+  [ -z "${f}" ] && { cat; return; }
+  local c="$(stty -a </dev/tty 2>/dev/null |
+             sed 's/.*columns[[:space:]]*\([0-9]*\).*/\1/;t;d')"
+  [ -z "${c}" ] && { cat; return; }
+  local i="$(echo "$*"|sed 's/./ /g')"
+  local j="$(printf %s "${i}"|wc -c)"
+  if [ "${c}" -gt "${j}" ]; then
+    dd bs=1 count="${j}" 2>/dev/null
+    "${f}" -sw "$((${c}-${j}))" | sed '2,$s/^/'"${i}"'/'
+  else
+    "${f}" -sw "${c}"
+  fi
+}
+
+help() {
+  echo "Usage ${0##*/} [-h|--help] [-c|--clean] [-C|--clean-all] [-l|--list] [--] args" | wrap "Usage ${0##*/} "
+  echo "  help:      print this message"                                                | wrap "             "
+  echo "  list:      list all known chroot environments"                                | wrap "             "
+  echo "  clean:     remove all old chroot sessions for \"${chroot}\""                  | wrap "             "
+  echo "  clean-all: remove all old chroot sessions for all environments"               | wrap "             "
+  exit 0
+}
+
+clean() {
+  local s t rc
+  rc=0
+  for s in $(schroot -l --all-sessions); do
+    if [ -n "$1" ]; then
+      t="${s#session:}"
+      [ "${t#${chroot}-}" == "${t}" ] && continue
+    fi
+    if ls -l /proc/*/{cwd,fd} 2>/dev/null |
+       fgrep -qs "/var/lib/schroot/mount/${t}"; then
+      echo "Session \"${t}\" still has active users, not cleaning up" | wrap
+      rc=1
+      continue
+    fi
+    sudo schroot -c "${s}" -e || rc=1
+  done
+  exit ${rc}
+}
+
+list() {
+  for e in $(schroot -l); do
+    e="${e#chroot:}"
+    [ -x "/usr/local/bin/${e}" ] || continue
+    if schroot -l --all-sessions 2>/dev/null |
+       sed 's/^session://' |
+       grep -qs "^${e}-"; then
+      echo "${e} is currently active"
+    else
+      echo "${e}"
+    fi
+  done
+  exit 0
+}
+
+while [ "$#" -ne 0 ]; do
+  case "$1" in
+    --)             shift; break;;
+    -h|--help)      shift; help;;
+    -l|--list)      shift; list;;
+    -c|--clean)     shift; clean "${chroot}";;
+    -C|--clean-all) shift; clean;;
+    *)              break;;
+  esac
+done
+
+# Start a new chroot session and keep track of the session id. We inject this
+# id into all processes that run inside the chroot. Unless they go out of their
+# way to clear their environment, we can then later identify our child and
+# grand-child processes by scanning their environment.
+session="$(schroot -c "${chroot}" -b)"
+export CHROOT_SESSION_ID="${session}"
+
+# Set GOMA_TMP_DIR for better handling of goma inside chroot.
+export GOMA_TMP_DIR="/tmp/goma_tmp_$CHROOT_SESSION_ID"
+mkdir -p "$GOMA_TMP_DIR"
+
+if [ $# -eq 0 ]; then
+  # Run an interactive shell session
+  schroot -c "${session}" -r -p
+else
+  # Run a command inside of the chroot environment
+  p="$1"; shift
+  schroot -c "${session}" -r -p "$p" -- "$@"
+fi
+rc=$?
+
+# Compute the inode of the root directory inside of the chroot environment.
+i=$(schroot -c "${session}" -r -p ls -- -id /proc/self/root/. |
+     awk '{ print $1 }') 2>/dev/null
+other_pids=
+while [ -n "$i" ]; do
+  # Identify processes by the inode number of their root directory. Then
+  # remove all processes that we know belong to other sessions. We use
+  # "sort | uniq -u" to do what amounts to a "set substraction operation".
+  pids=$({ ls -id1 /proc/*/root/. 2>/dev/null |
+         sed -e 's,^[^0-9]*'$i'.*/\([1-9][0-9]*\)/.*$,\1,
+                 t
+                 d';
+         echo "${other_pids}";
+         echo "${other_pids}"; } | sort | uniq -u) >/dev/null 2>&1
+  # Kill all processes that are still left running in the session. This is
+  # typically an assortment of daemon processes that were started
+  # automatically. They result in us being unable to tear down the session
+  # cleanly.
+  [ -z "${pids}" ] && break
+  for j in $pids; do
+    # Unfortunately, the way that schroot sets up sessions has the
+    # side-effect of being unable to tell one session apart from another.
+    # This can result in us attempting to kill processes in other sessions.
+    # We make a best-effort to avoid doing so.
+    k="$( ( xargs -0 -n1 </proc/$j/environ ) 2>/dev/null |
+         sed 's/^CHROOT_SESSION_ID=/x/;t1;d;:1;q')"
+    if [ -n "${k}" -a "${k#x}" != "${session}" ]; then
+      other_pids="${other_pids}
+${j}"
+      continue
+    fi
+    kill -9 $pids
+  done
+done
+# End the chroot session. This should clean up all temporary files. But if we
+# earlier failed to terminate all (daemon) processes inside of the session,
+# deleting the session could fail. When that happens, the user has to manually
+# clean up the stale files by invoking us with "--clean" after having killed
+# all running processes.
+schroot -c "${session}" -e
+# Since no goma processes are running, we can remove goma directory.
+rm -rf "$GOMA_TMP_DIR"
+exit $rc
+EOF
+sudo chown root:root /usr/local/bin/"${target%bit}"
+sudo chmod 755 /usr/local/bin/"${target%bit}"
+
+# Add the standard Ubuntu update repositories if requested.
+[ "${alt_repos}" = "y" -a \
+  -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
+sudo sed -i '/^deb .* [^ -]\+ main$/p
+             s/^\(deb .* [^ -]\+\) main/\1-security main/
+             p
+             t1
+             d
+             :1;s/-security main/-updates main/
+             t
+             d' "/var/lib/chroot/${target}/etc/apt/sources.list"
+
+# Add a few more repositories to the chroot
+[ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
+sudo sed -i 's/ main$/ main restricted universe multiverse/' \
+         "/var/lib/chroot/${target}/etc/apt/sources.list"
+
+# Add the Ubuntu "partner" repository, if available
+if [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
+   HEAD "http://archive.canonical.com/ubuntu/dists/${distname}/partner" \
+   >&/dev/null; then
+  sudo sh -c '
+    echo "deb http://archive.canonical.com/ubuntu" \
+         "'"${distname}"' partner" \
+      >>"/var/lib/chroot/'"${target}"'/etc/apt/sources.list"'
+fi
+
+# Add source repositories, if the user requested we do so
+[ "${add_srcs}" = "y" -a \
+  -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] &&
+sudo sed -i '/^deb[^-]/p
+             s/^deb\([^-]\)/deb-src\1/' \
+         "/var/lib/chroot/${target}/etc/apt/sources.list"
+
+# Set apt proxy if host has set http_proxy
+if [ -n "${http_proxy}" ]; then
+  sudo sh -c '
+    echo "Acquire::http::proxy \"'"${http_proxy}"'\";" \
+        >>"/var/lib/chroot/'"${target}"'/etc/apt/apt.conf"'
+fi
+
+# Update packages
+sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
+  apt-get update; apt-get -y dist-upgrade' || :
+
+# Install a couple of missing packages
+for i in debian-keyring ubuntu-keyring locales sudo; do
+  [ -d "/var/lib/chroot/${target}/usr/share/doc/$i" ] ||
+    sudo "/usr/local/bin/${target%bit}" apt-get -y install "$i" || :
+done
+
+# Configure locales
+sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
+  l='"${LANG:-en_US}"'; l="${l%%.*}"
+  [ -r /etc/locale.gen ] &&
+    sed -i "s/^# \($l\)/\1/" /etc/locale.gen
+  locale-gen $LANG en_US en_US.UTF-8' || :
+
+# Enable multi-arch support, if available
+sudo "/usr/local/bin/${target%bit}" dpkg --assert-multi-arch >&/dev/null &&
+  [ -r "/var/lib/chroot/${target}/etc/apt/sources.list" ] && {
+  sudo sed -i 's/ / [arch=amd64,i386] /' \
+              "/var/lib/chroot/${target}/etc/apt/sources.list"
+  [ -d /var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/ ] &&
+  sudo "/usr/local/bin/${target%bit}" dpkg --add-architecture \
+      $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) >&/dev/null ||
+    echo foreign-architecture \
+        $([ "${arch}" = "32bit" ] && echo amd64 || echo i386) |
+      sudo sh -c \
+        "cat >'/var/lib/chroot/${target}/etc/dpkg/dpkg.cfg.d/multiarch'"
+}
+
+# Configure "sudo" package
+sudo "/usr/local/bin/${target%bit}" /bin/sh -c '
+  egrep -qs '"'^$(id -nu) '"' /etc/sudoers ||
+  echo '"'$(id -nu) ALL=(ALL) ALL'"' >>/etc/sudoers'
+
+# Install a few more commonly used packages
+sudo "/usr/local/bin/${target%bit}" apt-get -y install                         \
+  autoconf automake1.9 dpkg-dev g++-multilib gcc-multilib gdb less libtool     \
+  lsof strace
+
+# If running a 32bit environment on a 64bit machine, install a few binaries
+# as 64bit. This is only done automatically if the chroot distro is the same as
+# the host, otherwise there might be incompatibilities in build settings or
+# runtime dependencies. The user can force it with the '-c' flag.
+host_distro=$(grep -s DISTRIB_CODENAME /etc/lsb-release | \
+  cut -d "=" -f 2)
+if [ "${copy_64}" = "y" -o \
+    "${host_distro}" = "${distname}" -a "${arch}" = 32bit ] && \
+    file /bin/bash 2>/dev/null | grep -q x86-64; then
+  readlinepkg=$(sudo "/usr/local/bin/${target%bit}" sh -c \
+    'apt-cache search "lib64readline.\$" | sort | tail -n 1 | cut -d " " -f 1')
+  sudo "/usr/local/bin/${target%bit}" apt-get -y install                       \
+    lib64expat1 lib64ncurses5 ${readlinepkg} lib64z1 lib64stdc++6
+  dep=
+  for i in binutils gdb; do
+    [ -d /usr/share/doc/"$i" ] || dep="$dep $i"
+  done
+  [ -n "$dep" ] && sudo apt-get -y install $dep
+  sudo mkdir -p "/var/lib/chroot/${target}/usr/local/lib/amd64"
+  for i in libbfd libpython; do
+    lib="$({ ldd /usr/bin/ld; ldd /usr/bin/gdb; } |
+           grep -s "$i" | awk '{ print $3 }')"
+    if [ -n "$lib" -a -r "$lib" ]; then
+      sudo cp "$lib" "/var/lib/chroot/${target}/usr/local/lib/amd64"
+    fi
+  done
+  for lib in libssl libcrypt; do
+    for path in /usr/lib /usr/lib/x86_64-linux-gnu; do
+      sudo cp $path/$lib* \
+              "/var/lib/chroot/${target}/usr/local/lib/amd64/" >&/dev/null || :
+    done
+  done
+  for i in gdb ld; do
+    sudo cp /usr/bin/$i "/var/lib/chroot/${target}/usr/local/lib/amd64/"
+    sudo sh -c "cat >'/var/lib/chroot/${target}/usr/local/bin/$i'" <<EOF
+#!/bin/sh
+exec /lib64/ld-linux-x86-64.so.2 --library-path /usr/local/lib/amd64 \
+  /usr/local/lib/amd64/$i "\$@"
+EOF
+    sudo chmod 755 "/var/lib/chroot/${target}/usr/local/bin/$i"
+  done
+fi
+
+
+# If the install-build-deps.sh script can be found, offer to run it now
+script="$(dirname $(readlink -f "$0"))/install-build-deps.sh"
+if [ -x "${script}" ]; then
+  while :; do
+    echo
+    echo "If you plan on building Chrome inside of the new chroot environment,"
+    echo "you now have to install the build dependencies. Do you want me to"
+    printf "start the script that does this for you (y/n)? "
+    read install_deps
+    case "${install_deps}" in
+      y|Y)
+        echo
+        # We prefer running the script in-place, but this might not be
+        # possible, if it lives on a network filesystem that denies
+        # access to root.
+        tmp_script=
+        if ! sudo /usr/local/bin/"${target%bit}" \
+            sh -c "[ -x '${script}' ]" >&/dev/null; then
+          tmp_script="/tmp/${script##*/}"
+          cp "${script}" "${tmp_script}"
+        fi
+        # Some distributions automatically start an instance of the system-
+        # wide dbus daemon, cron daemon or of the logging daemon, when
+        # installing the Chrome build depencies. This prevents the chroot
+        # session from being closed.  So, we always try to shut down any running
+        # instance of dbus and rsyslog.
+        sudo /usr/local/bin/"${target%bit}" sh -c "${script} --no-lib32;
+              rc=$?;
+              /etc/init.d/cron stop >/dev/null 2>&1 || :;
+              /etc/init.d/rsyslog stop >/dev/null 2>&1 || :;
+              /etc/init.d/dbus stop >/dev/null 2>&1 || :;
+              exit $rc"
+        rc=$?
+        [ -n "${tmp_script}" ] && rm -f "${tmp_script}"
+        [ $rc -ne 0 ] && exit $rc
+        break
+      ;;
+      n|N)
+        break
+      ;;
+    esac
+  done
+  echo
+fi
+
+# Check whether ~/chroot is on a (slow) network file system and offer to
+# relocate it. Also offer relocation, if the user appears to have multiple
+# spindles (as indicated by "${bind_mount}" being non-empty).
+# We only offer this option, if it doesn't look as if a chroot environment
+# is currently active. Otherwise, relocation is unlikely to work and it
+# can be difficult for the user to recover from the failed attempt to relocate
+# the ~/chroot directory.
+# We don't aim to solve this problem for every configuration,
+# but try to help with the common cases. For more advanced configuration
+# options, the user can always manually adjust things.
+mkdir -p "${HOME}/chroot/"
+if [ ! -h "${HOME}/chroot" ] &&
+   ! egrep -qs '^[^[:space:]]*/chroot' /etc/fstab &&
+   { [ -n "${bind_mounts}" -a "${bind_mounts}" != "NONE" ] ||
+     is_network_drive "${HOME}/chroot"; } &&
+   ! egrep -qs '/var/lib/[^/]*chroot/.*/chroot' /proc/mounts; then
+  echo "${HOME}/chroot is currently located on the same device as your"
+  echo "home directory."
+  echo "This might not be what you want. Do you want me to move it somewhere"
+  echo "else?"
+  # If the computer has multiple spindles, many users configure all or part of
+  # the secondary hard disk to be writable by the primary user of this machine.
+  # Make some reasonable effort to detect this type of configuration and
+  # then offer a good location for where to put the ~/chroot directory.
+  suggest=
+  for i in $(echo "${bind_mounts}"|cut -d ' ' -f 1); do
+    if [ -d "$i" -a -w "$i" -a \( ! -a "$i/chroot" -o -w "$i/chroot/." \) ] &&
+       ! is_network_drive "$i"; then
+      suggest="$i"
+    else
+      for j in "$i/"*; do
+        if [ -d "$j" -a -w "$j" -a \
+             \( ! -a "$j/chroot" -o -w "$j/chroot/." \) ] &&
+           ! is_network_drive "$j"; then
+          suggest="$j"
+        else
+          for k in "$j/"*; do
+            if [ -d "$k" -a -w "$k" -a \
+                 \( ! -a "$k/chroot" -o -w "$k/chroot/." \) ] &&
+               ! is_network_drive "$k"; then
+              suggest="$k"
+              break
+            fi
+          done
+        fi
+        [ -n "${suggest}" ] && break
+      done
+    fi
+    [ -n "${suggest}" ] && break
+  done
+  def_suggest="${HOME}"
+  if [ -n "${suggest}" ]; then
+    # For home directories that reside on network drives, make our suggestion
+    # the default option. For home directories that reside on a local drive,
+    # require that the user manually enters the new location.
+    if is_network_drive "${HOME}"; then
+      def_suggest="${suggest}"
+    else
+      echo "A good location would probably be in \"${suggest}\""
+    fi
+  fi
+  while :; do
+    printf "Physical location [${def_suggest}]: "
+    read dir
+    [ -z "${dir}" ] && dir="${def_suggest}"
+    [ "${dir%%/}" == "${HOME%%/}" ] && break
+    if ! [ -d "${dir}" -a -w "${dir}" ] ||
+       [ -a "${dir}/chroot" -a ! -w "${dir}/chroot/." ]; then
+      echo "Cannot write to ${dir}/chroot. Please try again"
+    else
+      mv "${HOME}/chroot" "${dir}/chroot"
+      ln -s "${dir}/chroot" "${HOME}/chroot"
+      for i in $(list_all_chroots); do
+        sudo "$i" mkdir -p "${dir}/chroot"
+      done
+      sudo sed -i "s,${HOME}/chroot,${dir}/chroot,g" /etc/schroot/mount-*
+      break
+    fi
+  done
+fi
+
+# Clean up package files
+sudo schroot -c "${target%bit}" -p -- apt-get clean
+sudo apt-get clean
+
+trap '' INT TERM QUIT HUP
+trap '' EXIT
+
+# Let the user know what we did
+cat <<EOF
+
+
+Successfully installed ${distname} ${arch}
+
+You can run programs inside of the chroot by invoking the
+"/usr/local/bin/${target%bit}" command.
+
+This command can be used with arguments, in order to just run a single
+program inside of the chroot environment (e.g. "${target%bit} make chrome")
+or without arguments, in order to run an interactive shell session inside
+of the chroot environment.
+
+If you need to run things as "root", you can use "sudo" (e.g. try
+"sudo ${target%bit} apt-get update").
+
+Your home directory is shared between the host and the chroot. But I
+configured "${HOME}/chroot" to be private to the chroot environment.
+You can use it for files that need to differ between environments. This
+would be a good place to store binaries that you have built from your
+source files.
+
+For Chrome, this probably means you want to make your "out" directory a
+symbolic link that points somewhere inside of "${HOME}/chroot".
+
+You still need to run "gclient runhooks" whenever you switch from building
+outside of the chroot to inside of the chroot. But you will find that you
+don't have to repeatedly erase and then completely rebuild all your object
+and binary files.
+
+EOF
diff --git a/build/internal/README.chromium b/build/internal/README.chromium
new file mode 100644
index 0000000..4624830
--- /dev/null
+++ b/build/internal/README.chromium
@@ -0,0 +1,24 @@
+Internal property sheets:
+  essential.vsprops
+    Contains the common settings used throughout the projects. Is included by either ..\debug.vsprops or ..\release.vsprops, so in general, it is not included directly.
+
+  release_defaults.vsprops
+    Included by ..\release.vsprops. Its settings are overriden by release_impl$(CHROME_BUILD_TYPE).vsprops. Uses the default VS setting which is "Maximize Speed". Results in relatively fast build with reasonable optimization level but without whole program optimization to reduce build time.
+
+  release_impl.vsprops
+    Included by ..\release.vsprops by default when CHROME_BUILD_TYPE is undefined. Includes release_defaults.vsprops.
+
+  release_impl_checksenabled.vsprops
+    Included by ..\release.vsprops when CHROME_BUILD_TYPE=_checksenabled. Matches what release_defaults.vsprops does, but doesn't actually inherit from it as we couldn't quite get that working. The only difference is that _DEBUG is set instead of NDEBUG. Used for keeping debug checks enabled with a build that is fast enough to dogfood with.
+
+  release_impl_official.vsprops
+    Included by ..\release.vsprops when CHROME_BUILD_TYPE=_official. Includes release_defaults.vsprops. Enables Whole Program Optimizations (WPO), which doubles the build time. Results in much more optimized build. Uses "Full Optimization" and "Flavor small code".
+
+  release_impl_pgo_instrument.vsprops
+    Included by ..\release.vsprops when CHROME_BUILD_TYPE=_pgo_instrument. Includes release_defaults.vsprops. Enables Profile Guided Optimization (PGO) instrumentation (first pass). Uses "Full Optimization" and "Flavor small code".
+
+  release_impl_pgo_optimize.vsprops
+    Included by ..\release.vsprops when CHROME_BUILD_TYPE=_pgo_optimize. Includes release_defaults.vsprops. Enables Profile Guided Optimization (PGO) optimization (second pass). Uses "Full Optimization" and "Flavor small code".
+
+  release_impl_purify.vsprops
+    Included by ..\release.vsprops when CHROME_BUILD_TYPE=_purify. Includes release_defaults.vsprops. Disables optimizations. Used with Purify to test without debug tools and without optimization; i.e. NDEBUG is defined but the compiler doesn't optimize the binary.
diff --git a/build/internal/release_defaults.gypi b/build/internal/release_defaults.gypi
new file mode 100644
index 0000000..1bf674a
--- /dev/null
+++ b/build/internal/release_defaults.gypi
@@ -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.
+{
+  'msvs_settings': {
+    'VCCLCompilerTool': {
+      'StringPooling': 'true',
+    },
+    'VCLinkerTool': {
+      # No incremental linking.
+      'LinkIncremental': '1',
+      # Eliminate Unreferenced Data (/OPT:REF).
+      'OptimizeReferences': '2',
+      # Folding on (/OPT:ICF).
+      'EnableCOMDATFolding': '2',
+    },
+  },
+}
diff --git a/build/internal/release_impl.gypi b/build/internal/release_impl.gypi
new file mode 100644
index 0000000..5ac0e09
--- /dev/null
+++ b/build/internal/release_impl.gypi
@@ -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.
+{
+  'includes': ['release_defaults.gypi'],
+  'msvs_settings': {
+    'VCCLCompilerTool': {
+      'OmitFramePointers': 'false',
+      # The above is not sufficient (http://crbug.com/106711): it
+      # simply eliminates an explicit "/Oy", but both /O2 and /Ox
+      # perform FPO regardless, so we must explicitly disable.
+      # We still want the false setting above to avoid having
+      # "/Oy /Oy-" and warnings about overriding.
+      'AdditionalOptions': ['/Oy-'],
+    },
+  },
+}
diff --git a/build/internal/release_impl_official.gypi b/build/internal/release_impl_official.gypi
new file mode 100644
index 0000000..d0729a9
--- /dev/null
+++ b/build/internal/release_impl_official.gypi
@@ -0,0 +1,42 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'includes': ['release_defaults.gypi'],
+  'defines': ['OFFICIAL_BUILD'],
+  'msvs_settings': {
+    'VCCLCompilerTool': {
+      'InlineFunctionExpansion': '2',
+      'EnableIntrinsicFunctions': 'true',
+      'EnableFiberSafeOptimizations': 'true',
+      'OmitFramePointers': 'false',
+      # The above is not sufficient (http://crbug.com/106711): it
+      # simply eliminates an explicit "/Oy", but both /O2 and /Ox
+      # perform FPO regardless, so we must explicitly disable.
+      # We still want the false setting above to avoid having
+      # "/Oy /Oy-" and warnings about overriding.
+      'AdditionalOptions': ['/Oy-'],
+    },
+    'VCLibrarianTool': {
+      'AdditionalOptions': [
+        '/ltcg',
+        '/expectedoutputsize:120000000'
+      ],
+    },
+    'VCLinkerTool': {
+      'AdditionalOptions': [
+        '/time',
+        # This may reduce memory fragmentation during linking.
+        # The expected size is 40*1024*1024, which gives us about 10M of
+        # headroom as of Dec 16, 2011.
+        '/expectedoutputsize:41943040',
+      ],
+      # The /PROFILE flag causes the linker to add a "FIXUP" debug stream to
+      # the generated PDB. According to MSDN documentation, this flag is only
+      # available (or perhaps supported) in the Enterprise (team development)
+      # version of Visual Studio. If this blocks your official build, simply
+      # comment out this line, then  re-run "gclient runhooks".
+      'Profile': 'true',
+    },
+  },
+}
diff --git a/build/inverse_depth.py b/build/inverse_depth.py
new file mode 100755
index 0000000..ce7a6ab
--- /dev/null
+++ b/build/inverse_depth.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 os
+import sys
+
+
+def DoMain(argv):
+  depth = argv[0]
+  return os.path.relpath(os.getcwd(), os.path.abspath(depth))
+
+
+def main(argv):
+  if len(argv) < 2:
+    print "USAGE: inverse_depth.py depth"
+    return 1
+  print DoMain(argv[1:])
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/ios/OWNERS b/build/ios/OWNERS
new file mode 100644
index 0000000..4caf405
--- /dev/null
+++ b/build/ios/OWNERS
@@ -0,0 +1,4 @@
+rohitrao@chromium.org
+stuartmorgan@chromium.org
+
+per-file grit_whitelist.txt=*
diff --git a/build/ios/PRESUBMIT.py b/build/ios/PRESUBMIT.py
new file mode 100644
index 0000000..bbd17b3
--- /dev/null
+++ b/build/ios/PRESUBMIT.py
@@ -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 os
+
+"""Chromium presubmit script for src/tools/ios.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into depot_tools.
+"""
+
+WHITELIST_FILE = 'build/ios/grit_whitelist.txt'
+
+def _CheckWhitelistSorted(input_api, output_api):
+  for path in input_api.LocalPaths():
+    if WHITELIST_FILE == path:
+      lines = open(os.path.join('../..', WHITELIST_FILE)).readlines()
+      i = 0
+      while i < len(lines) - 1 and lines[i] <= lines[i + 1]:
+        i += 1
+      if i < len(lines) - 1:
+        return [output_api.PresubmitError(
+            'The file ' + WHITELIST_FILE + ' must be sorted.  ' +
+            'First offending line: #' + str(i + 2))]
+  return []
+
+def _CommonChecks(input_api, output_api):
+  """Checks common to both upload and commit."""
+  results = []
+  results.extend(_CheckWhitelistSorted(input_api, output_api))
+  return results
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
+
+def CheckChangeOnCommit(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
diff --git a/build/ios/chrome_ios.croc b/build/ios/chrome_ios.croc
new file mode 100644
index 0000000..938a2e9
--- /dev/null
+++ b/build/ios/chrome_ios.croc
@@ -0,0 +1,71 @@
+# -*- python -*-
+# Crocodile config file for Chromium iOS.
+#
+# Note that Chromium iOS also uses the config file at src/build/common.croc.
+#
+# See src/tools/code_coverage/example.croc for more info on config files.
+
+{
+  # List of rules, applied in order
+  'rules' : [
+    # Specify inclusions before exclusions, since rules are in order.
+
+    # Exclude everything to negate whatever is in src/build/common.croc
+    {
+      'regexp' : '.*',
+      'include' : 0,
+    },
+
+    # Include all directories (but not the files in the directories).
+    # This is a workaround for how croc.py walks the directory tree. See the
+    # TODO in the AddFiles method of src/tools/code_coverage/croc.py
+    {
+      'regexp' : '.*/$',
+      'include' : 1,
+    },
+
+    # Include any file with an 'ios' directory in the path.
+    {
+      'regexp' : '.*/ios/.*',
+      'include' : 1,
+      'add_if_missing' : 1,
+    },
+    
+    # Include any file that ends with _ios.
+    {
+      'regexp' : '.*_ios\\.(c|cc|m|mm)$',
+      'include' : 1,
+      'add_if_missing' : 1,
+    },
+
+    # Include any file that ends with _ios_unittest (and label it a test).
+    {
+      'regexp' : '.*_ios_unittest\\.(c|cc|m|mm)$',
+      'include' : 1,
+      'add_if_missing' : 1,
+      'group' : 'test',
+    },
+
+    # Don't scan for executable lines in uninstrumented header files
+    {
+      'regexp' : '.*\\.(h|hpp)$',
+      'add_if_missing' : 0,
+    },
+
+    # Don't measure coverage of perftests.
+    {
+      'regexp' : '.*perftest\\.(c|cc|m|mm)$',
+      'include' : 0,
+    },
+
+    # Languages
+    {
+      'regexp' : '.*\\.m$',
+      'language' : 'ObjC',
+    },
+    {
+      'regexp' : '.*\\.mm$',
+      'language' : 'ObjC++',
+    },
+  ],
+}
diff --git a/build/ios/clean_env.py b/build/ios/clean_env.py
new file mode 100755
index 0000000..548e2b9
--- /dev/null
+++ b/build/ios/clean_env.py
@@ -0,0 +1,77 @@
+#!/usr/bin/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.
+
+import os
+import sys
+
+def Main(argv):
+  """This is like 'env -i', but it uses a whitelist of env variables to allow
+  through to the command being run.  It attempts to strip off Xcode-added
+  values from PATH.
+  """
+  # Note: An attempt was made to do something like: env -i bash -lc '[command]'
+  # but that fails to set the things set by login (USER, etc.), so instead
+  # the only approach that seems to work is to have a whitelist.
+  env_key_whitelist = (
+    'HOME',
+    'LOGNAME',
+    # 'PATH' added below (but filtered).
+    'PWD',
+    'SHELL',
+    'TEMP',
+    'TMPDIR',
+    'USER'
+  )
+
+  # Need something to run.
+  # TODO(lliabraa): Make this output a usage string and exit (here and below).
+  assert(len(argv) > 0)
+
+  add_to_path = [];
+  first_entry = argv[0];
+  if first_entry.startswith('ADD_TO_PATH='):
+    argv = argv[1:];
+    add_to_path = first_entry.replace('ADD_TO_PATH=', '', 1).split(':')
+
+  # Still need something to run.
+  assert(len(argv) > 0)
+
+  clean_env = {}
+
+  # Pull over the whitelisted keys.
+  for key in env_key_whitelist:
+    val = os.environ.get(key, None)
+    if not val is None:
+      clean_env[key] = val
+
+  # Collect the developer dir as set via Xcode, defaulting it.
+  dev_prefix = os.environ.get('DEVELOPER_DIR', '/Developer/')
+  if dev_prefix[-1:] != '/':
+    dev_prefix += '/'
+
+  # Now pull in PATH, but remove anything Xcode might have added.
+  initial_path = os.environ.get('PATH', '')
+  filtered_chunks = \
+      [x for x in initial_path.split(':') if not x.startswith(dev_prefix)]
+  if filtered_chunks:
+    clean_env['PATH'] = ':'.join(add_to_path + filtered_chunks)
+
+  # Add any KEY=VALUE args before the command to the cleaned environment.
+  args = argv[:]
+  while '=' in args[0]:
+    (key, val) = args[0].split('=', 1)
+    clean_env[key] = val
+    args = args[1:]
+
+  # Still need something to run.
+  assert(len(args) > 0)
+
+  # Off it goes...
+  os.execvpe(args[0], args, clean_env)
+  # Should never get here, so return a distinctive, non-zero status code.
+  return 66
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/build/ios/coverage.gypi b/build/ios/coverage.gypi
new file mode 100644
index 0000000..e822089
--- /dev/null
+++ b/build/ios/coverage.gypi
@@ -0,0 +1,32 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'enable_coverage%': 0,
+  },
+  'conditions': [
+    ['enable_coverage', {
+        'target_defaults': {
+          'defines': [
+            'ENABLE_TEST_CODE_COVERAGE=1'
+          ],
+          'link_settings': {
+            'xcode_settings': {
+              'OTHER_LDFLAGS': [
+                '-fprofile-arcs',
+              ],
+            },
+          },
+          'xcode_settings': {
+            'OTHER_CFLAGS': [
+              '-fprofile-arcs',
+              '-ftest-coverage',
+            ],
+          },
+        },
+    }],
+  ],
+}
+
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
new file mode 100644
index 0000000..e25efbc
--- /dev/null
+++ b/build/ios/grit_whitelist.txt
@@ -0,0 +1,1143 @@
+IDR_ABOUT_DOM_DISTILLER_CSS
+IDR_ABOUT_DOM_DISTILLER_HTML
+IDR_ABOUT_DOM_DISTILLER_JS
+IDR_ABOUT_STATS_HTML
+IDR_ABOUT_STATS_JS
+IDR_ABOUT_VERSION_CSS
+IDR_ABOUT_VERSION_HTML
+IDR_ABOUT_VERSION_JS
+IDR_CONTEXTUAL_SEARCH_PROMO_HTML
+IDR_CONTROLLED_SETTING_MANDATORY
+IDR_CRASHES_HTML
+IDR_CRASHES_JS
+IDR_CREDITS_HTML
+IDR_CREDITS_JS
+IDR_DATA_REDUCTION_PROXY_INTERSTITIAL_HTML
+IDR_DEFAULT_FAVICON
+IDR_DEFAULT_FAVICON_32
+IDR_DEFAULT_FAVICON_64
+IDR_DIR_HEADER_HTML
+IDR_DISTILLABLE_PAGE_SERIALIZED_MODEL
+IDR_DISTILLER_CSS
+IDR_DISTILLER_JS
+IDR_DOM_DISTILLER_VIEWER_HTML
+IDR_DOM_DISTILLER_VIEWER_JS
+IDR_EXTRACT_PAGE_FEATURES_JS
+IDR_FLAGS_FAVICON
+IDR_FLAGS_HTML
+IDR_FLAGS_JS
+IDR_GCM_INTERNALS_CSS
+IDR_GCM_INTERNALS_HTML
+IDR_GCM_INTERNALS_JS
+IDR_HISTORY_FAVICON
+IDR_HISTORY_HTML
+IDR_HISTORY_JS
+IDR_INCOGNITO_TAB_HTML
+IDR_INFOBAR_AUTOFILL_CC
+IDR_INFOBAR_AUTOLOGIN
+IDR_INFOBAR_RESTORE_SESSION
+IDR_INFOBAR_SAVE_PASSWORD
+IDR_INFOBAR_TRANSLATE_IOS
+IDR_INFOBAR_WARNING
+IDR_IS_DISTILLABLE_JS
+IDR_LOCATION_BAR_HTTP
+IDR_NET_ERROR_HTML
+IDR_NET_EXPORT_HTML
+IDR_NET_EXPORT_JS
+IDR_NET_INTERNALS_INDEX_HTML
+IDR_NET_INTERNALS_INDEX_JS
+IDR_OMAHA_HTML
+IDR_OMAHA_JS
+IDR_OMNIBOX_CALCULATOR
+IDR_OMNIBOX_CLEAR_IOS
+IDR_OMNIBOX_CLEAR_OTR_IOS
+IDR_OMNIBOX_CLEAR_OTR_PRESSED_IOS
+IDR_OMNIBOX_CLEAR_PRESSED_IOS
+IDR_OMNIBOX_EXTENSION_APP
+IDR_OMNIBOX_HISTORY
+IDR_OMNIBOX_HISTORY_INCOGNITO
+IDR_OMNIBOX_HTTP
+IDR_OMNIBOX_HTTPS_INVALID
+IDR_OMNIBOX_HTTPS_POLICY_WARNING
+IDR_OMNIBOX_HTTPS_VALID
+IDR_OMNIBOX_HTTPS_WARNING
+IDR_OMNIBOX_HTTP_INCOGNITO
+IDR_OMNIBOX_KEYBOARD_VIEW_APPEND
+IDR_OMNIBOX_KEYBOARD_VIEW_APPEND_HIGHLIGHTED
+IDR_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO
+IDR_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO_HIGHLIGHTED
+IDR_OMNIBOX_SEARCH
+IDR_OMNIBOX_SEARCH_INCOGNITO
+IDR_OMNIBOX_SEARCH_SECURED
+IDR_OMNIBOX_STAR
+IDR_OMNIBOX_STAR_INCOGNITO
+IDR_OTHER_DEVICES_JS
+IDR_PAGEINFO_BAD
+IDR_PAGEINFO_GOOD
+IDR_PAGEINFO_INFO
+IDR_PAGEINFO_WARNING_MAJOR
+IDR_PAGEINFO_WARNING_MINOR
+IDR_POLICY_CSS
+IDR_POLICY_HTML
+IDR_POLICY_JS
+IDR_PRINTER_FAVICON
+IDR_SAD_FAVICON
+IDR_SAD_TAB
+IDR_SECURITY_INTERSTITIAL_HTML
+IDR_SIGNIN_INTERNALS_INDEX_HTML
+IDR_SIGNIN_INTERNALS_INDEX_JS
+IDR_SYNC_INTERNALS_ABOUT_JS
+IDR_SYNC_INTERNALS_CHROME_SYNC_JS
+IDR_SYNC_INTERNALS_DATA_JS
+IDR_SYNC_INTERNALS_EVENTS_JS
+IDR_SYNC_INTERNALS_INDEX_HTML
+IDR_SYNC_INTERNALS_INDEX_JS
+IDR_SYNC_INTERNALS_SEARCH_JS
+IDR_SYNC_INTERNALS_SYNC_LOG_JS
+IDR_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS
+IDR_SYNC_INTERNALS_SYNC_SEARCH_JS
+IDR_SYNC_INTERNALS_TYPES_JS
+IDR_TOOLBAR_SHADOW_FULL_BLEED
+IDR_TRANSLATE_JS
+IDR_UBER_UTILS_JS
+IDR_WEBUI_CSS_TEXT_DEFAULTS
+IDR_WEBUI_I18N_TEMPLATE_JS
+IDR_WEBUI_I18N_TEMPLATE_POLYMER_JS
+IDR_WEBUI_JSTEMPLATE_JS
+IDR_WEBUI_JS_LOAD_TIME_DATA
+IDS_ABOUT_MAC
+IDS_ABOUT_VERSION_COMMAND_LINE
+IDS_ABOUT_VERSION_COMPANY_NAME
+IDS_ABOUT_VERSION_COPYRIGHT
+IDS_ABOUT_VERSION_EXECUTABLE_PATH
+IDS_ABOUT_VERSION_OFFICIAL
+IDS_ABOUT_VERSION_OS
+IDS_ABOUT_VERSION_PATH_NOTFOUND
+IDS_ABOUT_VERSION_PROFILE_PATH
+IDS_ABOUT_VERSION_REVISION
+IDS_ABOUT_VERSION_TITLE
+IDS_ABOUT_VERSION_UNOFFICIAL
+IDS_ABOUT_VERSION_USER_AGENT
+IDS_ABOUT_VERSION_VARIATIONS
+IDS_ACCEPT_LANGUAGES
+IDS_ACCNAME_BACK
+IDS_ACCNAME_CLEAR_TEXT
+IDS_ACCNAME_FORWARD
+IDS_ACCNAME_LOCATION
+IDS_ACCNAME_VOICE_SEARCH
+IDS_ALLOW_INSECURE_CONTENT_BUTTON
+IDS_ALTERNATE_NAV_URL_VIEW_LABEL
+IDS_ANNOTATED_SUGGESTION
+IDS_APP_CANCEL
+IDS_APP_OK
+IDS_APP_UNTITLED_SHORTCUT_FILE_NAME
+IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION
+IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR
+IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR
+IDS_AUTOFILL_CC_AMEX
+IDS_AUTOFILL_CC_AMEX_SHORT
+IDS_AUTOFILL_CC_DINERS
+IDS_AUTOFILL_CC_DISCOVER
+IDS_AUTOFILL_CC_GENERIC
+IDS_AUTOFILL_CC_INFOBAR_ACCEPT
+IDS_AUTOFILL_CC_INFOBAR_DENY
+IDS_AUTOFILL_CC_INFOBAR_TEXT
+IDS_AUTOFILL_CC_JCB
+IDS_AUTOFILL_CC_MASTERCARD
+IDS_AUTOFILL_CC_UNION_PAY
+IDS_AUTOFILL_CC_VISA
+IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM
+IDS_AUTOFILL_DIALOG_PRIVACY_POLICY_LINK
+IDS_AUTOFILL_FIELD_LABEL_AREA
+IDS_AUTOFILL_FIELD_LABEL_COUNTY
+IDS_AUTOFILL_FIELD_LABEL_DEPARTMENT
+IDS_AUTOFILL_FIELD_LABEL_DISTRICT
+IDS_AUTOFILL_FIELD_LABEL_EMIRATE
+IDS_AUTOFILL_FIELD_LABEL_ISLAND
+IDS_AUTOFILL_FIELD_LABEL_PARISH
+IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE
+IDS_AUTOFILL_FIELD_LABEL_PREFECTURE
+IDS_AUTOFILL_FIELD_LABEL_PROVINCE
+IDS_AUTOFILL_FIELD_LABEL_STATE
+IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE
+IDS_AUTOFILL_OPTIONS_POPUP
+IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE
+IDS_AUTOFILL_SCAN_CREDIT_CARD
+IDS_AUTOFILL_WARNING_FORM_DISABLED
+IDS_AUTOFILL_WARNING_INSECURE_CONNECTION
+IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON
+IDS_AUTOLOGIN_INFOBAR_MESSAGE
+IDS_AUTOLOGIN_INFOBAR_OK_BUTTON
+IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT
+IDS_BLOCK_INSECURE_CONTENT_BUTTON
+IDS_BOOKMARK_ADD_EDITOR_TITLE
+IDS_BOOKMARK_ALL_TABS_DIALOG_TITLE
+IDS_BOOKMARK_BAR_FOLDER_NAME
+IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME
+IDS_BOOKMARK_BAR_MANAGED_FOLDER_DOMAIN_NAME
+IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME
+IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME
+IDS_BOOKMARK_BAR_REDO
+IDS_BOOKMARK_BAR_REDO_ADD
+IDS_BOOKMARK_BAR_REDO_DELETE
+IDS_BOOKMARK_BAR_REDO_EDIT
+IDS_BOOKMARK_BAR_REDO_MOVE
+IDS_BOOKMARK_BAR_REDO_REORDER
+IDS_BOOKMARK_BAR_SUPERVISED_FOLDER_DEFAULT_NAME
+IDS_BOOKMARK_BAR_UNDO
+IDS_BOOKMARK_BAR_UNDO_ADD
+IDS_BOOKMARK_BAR_UNDO_DELETE
+IDS_BOOKMARK_BAR_UNDO_EDIT
+IDS_BOOKMARK_BAR_UNDO_MOVE
+IDS_BOOKMARK_BAR_UNDO_REORDER
+IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER
+IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK
+IDS_BOOKMARK_EDITOR_CONFIRM_DELETE
+IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME
+IDS_BOOKMARK_EDITOR_TITLE
+IDS_BOOKMARK_FOLDER_CHOOSER_TITLE
+IDS_BOOKMARK_FOLDER_EDITOR_TITLE
+IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE
+IDS_BOOKMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW
+IDS_BOOKMARK_MANAGER_FOLDER_SECTION
+IDS_BOOKMARK_MANAGER_FOLDER_TITLE
+IDS_BOOKMARK_MANAGER_NAME_INPUT_PLACE_HOLDER
+IDS_BOOKMARK_MANAGER_REMOVE_TITLE
+IDS_BOOKMARK_MANAGER_URL_INPUT_PLACE_HOLDER
+IDS_BOOKMARK_NEW_FOLDER_BUTTON_TITLE
+IDS_CANCEL
+IDS_CERT_ERROR_AUTHORITY_INVALID_DESCRIPTION
+IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS
+IDS_CERT_ERROR_AUTHORITY_INVALID_EXTRA_INFO_2
+IDS_CERT_ERROR_AUTHORITY_INVALID_TITLE
+IDS_CERT_ERROR_CHAIN_EXPIRED_DESCRIPTION
+IDS_CERT_ERROR_CHAIN_EXPIRED_DETAILS
+IDS_CERT_ERROR_COMMON_NAME_INVALID_DESCRIPTION
+IDS_CERT_ERROR_COMMON_NAME_INVALID_DETAILS
+IDS_CERT_ERROR_COMMON_NAME_INVALID_EXTRA_INFO_2
+IDS_CERT_ERROR_COMMON_NAME_INVALID_TITLE
+IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION
+IDS_CERT_ERROR_CONTAINS_ERRORS_DETAILS
+IDS_CERT_ERROR_CONTAINS_ERRORS_EXTRA_INFO_2
+IDS_CERT_ERROR_CONTAINS_ERRORS_TITLE
+IDS_CERT_ERROR_EXPIRED_DESCRIPTION
+IDS_CERT_ERROR_EXPIRED_DETAILS
+IDS_CERT_ERROR_EXPIRED_DETAILS_EXTRA_INFO_2
+IDS_CERT_ERROR_EXPIRED_TITLE
+IDS_CERT_ERROR_EXTRA_INFO_1
+IDS_CERT_ERROR_EXTRA_INFO_TITLE
+IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION
+IDS_CERT_ERROR_INVALID_CERT_DETAILS
+IDS_CERT_ERROR_INVALID_CERT_EXTRA_INFO_2
+IDS_CERT_ERROR_INVALID_CERT_TITLE
+IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION
+IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DETAILS
+IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_TITLE
+IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION
+IDS_CERT_ERROR_NOT_YET_VALID_DETAILS
+IDS_CERT_ERROR_NOT_YET_VALID_DETAILS_EXTRA_INFO_2
+IDS_CERT_ERROR_NOT_YET_VALID_TITLE
+IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION
+IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DETAILS
+IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_TITLE
+IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION
+IDS_CERT_ERROR_REVOKED_CERT_DETAILS
+IDS_CERT_ERROR_REVOKED_CERT_EXTRA_INFO_2
+IDS_CERT_ERROR_REVOKED_CERT_TITLE
+IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DESCRIPTION
+IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DETAILS
+IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_TITLE
+IDS_CERT_ERROR_UNKNOWN_ERROR_DESCRIPTION
+IDS_CERT_ERROR_UNKNOWN_ERROR_DETAILS
+IDS_CERT_ERROR_UNKNOWN_ERROR_TITLE
+IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION
+IDS_CERT_ERROR_WEAK_KEY_DETAILS
+IDS_CERT_ERROR_WEAK_KEY_EXTRA_INFO_2
+IDS_CERT_ERROR_WEAK_KEY_TITLE
+IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION
+IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DETAILS
+IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_EXTRA_INFO_2
+IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_TITLE
+IDS_CHROME_TO_DEVICE_PRINT_TO_PHONE
+IDS_CHROME_TO_DEVICE_SNAPSHOTS
+IDS_CLOSE
+IDS_CONTEXTUAL_SEARCH_HEADER
+IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION_1
+IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION_2
+IDS_CONTEXTUAL_SEARCH_PROMO_FEATURE_NAME
+IDS_CONTEXTUAL_SEARCH_PROMO_OPTIN
+IDS_CONTEXTUAL_SEARCH_PROMO_OPTOUT
+IDS_COULDNT_OPEN_PROFILE_ERROR
+IDS_CRASHES_BUG_LINK_LABEL
+IDS_CRASHES_CRASH_COUNT_BANNER_FORMAT
+IDS_CRASHES_CRASH_HEADER_FORMAT
+IDS_CRASHES_CRASH_TIME_FORMAT
+IDS_CRASHES_DISABLED_HEADER
+IDS_CRASHES_DISABLED_MESSAGE
+IDS_CRASHES_NO_CRASHES_MESSAGE
+IDS_CRASHES_TITLE
+IDS_CRASHES_UPLOAD_MESSAGE
+IDS_DATA_REDUCTION_PROXY_BACK_BUTTON
+IDS_DATA_REDUCTION_PROXY_CANNOT_PROXY_HEADING
+IDS_DATA_REDUCTION_PROXY_CANNOT_PROXY_PRIMARY_PARAGRAPH
+IDS_DATA_REDUCTION_PROXY_CANNOT_PROXY_SECONDARY_PARAGRAPH
+IDS_DATA_REDUCTION_PROXY_CONTINUE_BUTTON
+IDS_DATA_REDUCTION_PROXY_TITLE
+IDS_DEFAULT_AVATAR_NAME_10
+IDS_DEFAULT_AVATAR_NAME_11
+IDS_DEFAULT_AVATAR_NAME_12
+IDS_DEFAULT_AVATAR_NAME_13
+IDS_DEFAULT_AVATAR_NAME_14
+IDS_DEFAULT_AVATAR_NAME_15
+IDS_DEFAULT_AVATAR_NAME_16
+IDS_DEFAULT_AVATAR_NAME_17
+IDS_DEFAULT_AVATAR_NAME_18
+IDS_DEFAULT_AVATAR_NAME_19
+IDS_DEFAULT_AVATAR_NAME_20
+IDS_DEFAULT_AVATAR_NAME_21
+IDS_DEFAULT_AVATAR_NAME_22
+IDS_DEFAULT_AVATAR_NAME_23
+IDS_DEFAULT_AVATAR_NAME_24
+IDS_DEFAULT_AVATAR_NAME_25
+IDS_DEFAULT_AVATAR_NAME_26
+IDS_DEFAULT_AVATAR_NAME_8
+IDS_DEFAULT_AVATAR_NAME_9
+IDS_DEFAULT_ENCODING
+IDS_DEFAULT_PROFILE_NAME
+IDS_DEFAULT_TAB_TITLE
+IDS_DELETE
+IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION
+IDS_DISABLE_TOUCH_ADJUSTMENT_NAME
+IDS_DOM_DISTILLER_QUALITY_ANSWER_NO
+IDS_DOM_DISTILLER_QUALITY_ANSWER_YES
+IDS_DOM_DISTILLER_QUALITY_QUESTION
+IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT
+IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE
+IDS_DOM_DISTILLER_VIEWER_LOADING_STRING
+IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT
+IDS_DOM_DISTILLER_VIEWER_NO_DATA_TITLE
+IDS_DOM_DISTILLER_VIEWER_VIEW_ORIGINAL
+IDS_DOM_DISTILLER_WEBUI_ENTRY_ADD
+IDS_DOM_DISTILLER_WEBUI_ENTRY_ADD_FAILED
+IDS_DOM_DISTILLER_WEBUI_ENTRY_URL
+IDS_DOM_DISTILLER_WEBUI_FETCHING_ENTRIES
+IDS_DOM_DISTILLER_WEBUI_REFRESH
+IDS_DOM_DISTILLER_WEBUI_TITLE
+IDS_DOM_DISTILLER_WEBUI_VIEW_URL
+IDS_DOM_DISTILLER_WEBUI_VIEW_URL_FAILED
+IDS_DONE
+IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE
+IDS_EDIT_FIND_MAC
+IDS_EMPTY_KEYWORD_VALUE
+IDS_ERRORPAGES_BUTTON_LESS
+IDS_ERRORPAGES_BUTTON_MORE
+IDS_ERRORPAGES_BUTTON_RELOAD
+IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY
+IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY_HELP
+IDS_ERRORPAGES_DETAILS_ADDRESS_UNREACHABLE
+IDS_ERRORPAGES_DETAILS_BAD_GATEWAY
+IDS_ERRORPAGES_DETAILS_BAD_SSL_CLIENT_AUTH_CERT
+IDS_ERRORPAGES_DETAILS_BLOCKED
+IDS_ERRORPAGES_DETAILS_BLOCKED_BY_ADMINISTRATOR
+IDS_ERRORPAGES_DETAILS_BLOCKED_ENROLLMENT_CHECK_PENDING
+IDS_ERRORPAGES_DETAILS_CACHE_MISS
+IDS_ERRORPAGES_DETAILS_CACHE_READ_FAILURE
+IDS_ERRORPAGES_DETAILS_CONNECTION_CLOSED
+IDS_ERRORPAGES_DETAILS_CONNECTION_FAILED
+IDS_ERRORPAGES_DETAILS_CONNECTION_REFUSED
+IDS_ERRORPAGES_DETAILS_CONNECTION_RESET
+IDS_ERRORPAGES_DETAILS_DNS_PROBE_RUNNING
+IDS_ERRORPAGES_DETAILS_DOWNLOAD_FILE_TYPE_ERROR
+IDS_ERRORPAGES_DETAILS_EMPTY_RESPONSE
+IDS_ERRORPAGES_DETAILS_FILE_ACCESS_DENIED
+IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND
+IDS_ERRORPAGES_DETAILS_FORBIDDEN
+IDS_ERRORPAGES_DETAILS_GATEWAY_TIMEOUT
+IDS_ERRORPAGES_DETAILS_GONE
+IDS_ERRORPAGES_DETAILS_HTTP_VERSION_NOT_SUPPORTED
+IDS_ERRORPAGES_DETAILS_ICANN_NAME_COLLISION
+IDS_ERRORPAGES_DETAILS_INTERNAL_SERVER_ERROR
+IDS_ERRORPAGES_DETAILS_INTERNET_DISCONNECTED
+IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED
+IDS_ERRORPAGES_DETAILS_NETWORK_ACCESS_DENIED
+IDS_ERRORPAGES_DETAILS_NETWORK_CHANGED
+IDS_ERRORPAGES_DETAILS_NETWORK_IO_SUSPENDED
+IDS_ERRORPAGES_DETAILS_NOT_IMPLEMENTED
+IDS_ERRORPAGES_DETAILS_PINNING_FAILURE
+IDS_ERRORPAGES_DETAILS_PROXY_CONNECTION_FAILED
+IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION
+IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH
+IDS_ERRORPAGES_DETAILS_RESPONSE_HEADERS_MULTIPLE_LOCATION
+IDS_ERRORPAGES_DETAILS_SERVICE_UNAVAILABLE
+IDS_ERRORPAGES_DETAILS_SSL_FALLBACK_BEYOND_MINIMUM_VERSION
+IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR
+IDS_ERRORPAGES_DETAILS_SSL_UNSAFE_NEGOTIATION
+IDS_ERRORPAGES_DETAILS_SSL_VERSION_OR_CIPHER_MISMATCH
+IDS_ERRORPAGES_DETAILS_TEMPORARILY_THROTTLED
+IDS_ERRORPAGES_DETAILS_TIMED_OUT
+IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS
+IDS_ERRORPAGES_DETAILS_UNKNOWN
+IDS_ERRORPAGES_ERROR_CODE
+IDS_ERRORPAGES_HEADING_ACCESS_DENIED
+IDS_ERRORPAGES_HEADING_BAD_SSL_CLIENT_AUTH_CERT
+IDS_ERRORPAGES_HEADING_BLOCKED
+IDS_ERRORPAGES_HEADING_BLOCKED_BY_ADMINISTRATOR
+IDS_ERRORPAGES_HEADING_CACHE_MISS
+IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE
+IDS_ERRORPAGES_HEADING_DOWNLOAD_FILE_TYPE_ERROR
+IDS_ERRORPAGES_HEADING_DUPLICATE_HEADERS
+IDS_ERRORPAGES_HEADING_EMPTY_RESPONSE
+IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED
+IDS_ERRORPAGES_HEADING_HTTP_SERVER_ERROR
+IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED
+IDS_ERRORPAGES_HEADING_NETWORK_ACCESS_DENIED
+IDS_ERRORPAGES_HEADING_NETWORK_IO_SUSPENDED
+IDS_ERRORPAGES_HEADING_NOT_AVAILABLE
+IDS_ERRORPAGES_HEADING_NOT_FOUND
+IDS_ERRORPAGES_HEADING_PINNING_FAILURE
+IDS_ERRORPAGES_HEADING_PROXY_CONNECTION_FAILED
+IDS_ERRORPAGES_HEADING_SSL_FALLBACK_BEYOND_MINIMUM_VERSION
+IDS_ERRORPAGES_HEADING_SSL_PROTOCOL_ERROR
+IDS_ERRORPAGES_HEADING_SSL_VERSION_OR_CIPHER_MISMATCH
+IDS_ERRORPAGES_HEADING_TOO_MANY_REDIRECTS
+IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY
+IDS_ERRORPAGES_HTTP_POST_WARNING
+IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_BODY
+IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_HEADER
+IDS_ERRORPAGES_SUGGESTION_CONTACT_ADMINISTRATOR
+IDS_ERRORPAGES_SUGGESTION_DNS_CONFIG
+IDS_ERRORPAGES_SUGGESTION_FIREWALL_CONFIG
+IDS_ERRORPAGES_SUGGESTION_GOOGLE_SEARCH
+IDS_ERRORPAGES_SUGGESTION_LEARNMORE_BODY
+IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION
+IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG
+IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM
+IDS_ERRORPAGES_SUGGESTION_RELOAD
+IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_BODY
+IDS_ERRORPAGES_SUGGESTION_RELOAD_REPOST_HEADER
+IDS_ERRORPAGES_SUGGESTION_VIEW_POLICIES
+IDS_ERRORPAGES_SUMMARY_ADDRESS_UNREACHABLE
+IDS_ERRORPAGES_SUMMARY_BAD_GATEWAY
+IDS_ERRORPAGES_SUMMARY_BAD_SSL_CLIENT_AUTH_CERT
+IDS_ERRORPAGES_SUMMARY_BLOCKED
+IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_ADMINISTRATOR
+IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING
+IDS_ERRORPAGES_SUMMARY_CACHE_MISS
+IDS_ERRORPAGES_SUMMARY_CACHE_READ_FAILURE
+IDS_ERRORPAGES_SUMMARY_CONNECTION_REFUSED
+IDS_ERRORPAGES_SUMMARY_CONNECTION_RESET
+IDS_ERRORPAGES_SUMMARY_DNS_PROBE_RUNNING
+IDS_ERRORPAGES_SUMMARY_DOWNLOAD_FILE_TYPE_ERROR
+IDS_ERRORPAGES_SUMMARY_DUPLICATE_HEADERS
+IDS_ERRORPAGES_SUMMARY_EMPTY_RESPONSE
+IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED
+IDS_ERRORPAGES_SUMMARY_FORBIDDEN
+IDS_ERRORPAGES_SUMMARY_GATEWAY_TIMEOUT
+IDS_ERRORPAGES_SUMMARY_GONE
+IDS_ERRORPAGES_SUMMARY_ICANN_NAME_COLLISION
+IDS_ERRORPAGES_SUMMARY_INTERNAL_SERVER_ERROR
+IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED
+IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_INSTRUCTIONS_TEMPLATE
+IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED_PLATFORM
+IDS_ERRORPAGES_SUMMARY_NAME_NOT_RESOLVED
+IDS_ERRORPAGES_SUMMARY_NETWORK_ACCESS_DENIED
+IDS_ERRORPAGES_SUMMARY_NETWORK_CHANGED
+IDS_ERRORPAGES_SUMMARY_NETWORK_IO_SUSPENDED
+IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE
+IDS_ERRORPAGES_SUMMARY_NOT_FOUND
+IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE
+IDS_ERRORPAGES_SUMMARY_PROXY_CONNECTION_FAILED
+IDS_ERRORPAGES_SUMMARY_SERVICE_UNAVAILABLE
+IDS_ERRORPAGES_SUMMARY_SSL_FALLBACK_BEYOND_MINIMUM_VERSION
+IDS_ERRORPAGES_SUMMARY_SSL_PROTOCOL_ERROR
+IDS_ERRORPAGES_SUMMARY_SSL_VERSION_OR_CIPHER_MISMATCH
+IDS_ERRORPAGES_SUMMARY_TEMPORARILY_THROTTLED
+IDS_ERRORPAGES_SUMMARY_TIMED_OUT
+IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS
+IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY
+IDS_ERRORPAGES_SUMMARY_WEBSITE_CANNOT_HANDLE
+IDS_ERRORPAGES_TITLE_ACCESS_DENIED
+IDS_ERRORPAGES_TITLE_BLOCKED
+IDS_ERRORPAGES_TITLE_LOAD_FAILED
+IDS_ERRORPAGES_TITLE_NOT_AVAILABLE
+IDS_ERRORPAGES_TITLE_NOT_FOUND
+IDS_ERRORPAGE_NET_BUTTON_DETAILS
+IDS_ERRORPAGE_NET_BUTTON_HIDE_DETAILS
+IDS_EXTENSION_KEYWORD_COMMAND
+IDS_FEEDBACK_REPORT_PAGE_TITLE
+IDS_FEEDBACK_REPORT_URL_LABEL
+IDS_FEEDBACK_SEND_REPORT
+IDS_FEEDBACK_USER_EMAIL_LABEL
+IDS_FIND_IN_PAGE_CLOSE_TOOLTIP
+IDS_FIND_IN_PAGE_COUNT
+IDS_FIND_IN_PAGE_NEXT_TOOLTIP
+IDS_FIND_IN_PAGE_PREVIOUS_TOOLTIP
+IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_DESCRIPTION
+IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_NAME
+IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION
+IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME
+IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_DESCRIPTION
+IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_NAME
+IDS_FLAGS_COMPOSITED_LAYER_BORDERS
+IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION
+IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_DESCRIPTION
+IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_HIGH_DPI
+IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_NAME
+IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION
+IDS_FLAGS_CONFLICTS_CHECK_NAME
+IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION
+IDS_FLAGS_DEBUG_PACKED_APP_NAME
+IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION
+IDS_FLAGS_DEBUG_SHORTCUTS_NAME
+IDS_FLAGS_DEFAULT_TILE_HEIGHT_DESCRIPTION
+IDS_FLAGS_DEFAULT_TILE_HEIGHT_GRANDE
+IDS_FLAGS_DEFAULT_TILE_HEIGHT_NAME
+IDS_FLAGS_DEFAULT_TILE_HEIGHT_SHORT
+IDS_FLAGS_DEFAULT_TILE_HEIGHT_TALL
+IDS_FLAGS_DEFAULT_TILE_HEIGHT_VENTI
+IDS_FLAGS_DEFAULT_TILE_WIDTH_DESCRIPTION
+IDS_FLAGS_DEFAULT_TILE_WIDTH_GRANDE
+IDS_FLAGS_DEFAULT_TILE_WIDTH_NAME
+IDS_FLAGS_DEFAULT_TILE_WIDTH_SHORT
+IDS_FLAGS_DEFAULT_TILE_WIDTH_TALL
+IDS_FLAGS_DEFAULT_TILE_WIDTH_VENTI
+IDS_FLAGS_DISABLE
+IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_DESCRIPTION
+IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_NAME
+IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION
+IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME
+IDS_FLAGS_DISABLE_BOOT_ANIMATION
+IDS_FLAGS_DISABLE_BOOT_ANIMATION_DESCRIPTION
+IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION
+IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME
+IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION
+IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME
+IDS_FLAGS_DISABLE_PNACL_DESCRIPTION
+IDS_FLAGS_DISABLE_PNACL_NAME
+IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION
+IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME
+IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION
+IDS_FLAGS_DISABLE_WEBGL_NAME
+IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION
+IDS_FLAGS_DISABLE_WEBRTC_NAME
+IDS_FLAGS_ENABLE
+IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_DESCRIPTION
+IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_NAME
+IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH
+IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH_DESCRIPTION
+IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION
+IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME
+IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION
+IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME
+IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION
+IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_NAME
+IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_DESCRIPTION
+IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_NAME
+IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_DESCRIPTION
+IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_NAME
+IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_DESCRIPTION
+IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_NAME
+IDS_FLAGS_ENABLE_ICON_NTP_DESCRIPTION
+IDS_FLAGS_ENABLE_ICON_NTP_NAME
+IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION
+IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME
+IDS_FLAGS_ENABLE_NACL_DEBUG_DESCRIPTION
+IDS_FLAGS_ENABLE_NACL_DEBUG_NAME
+IDS_FLAGS_ENABLE_NACL_DESCRIPTION
+IDS_FLAGS_ENABLE_NACL_NAME
+IDS_FLAGS_ENABLE_PANELS_DESCRIPTION
+IDS_FLAGS_ENABLE_PANELS_NAME
+IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION
+IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME
+IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION
+IDS_FLAGS_ENABLE_PINCH_SCALE_NAME
+IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION
+IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME
+IDS_FLAGS_ENABLE_SCREEN_CAPTURE_DESCRIPTION
+IDS_FLAGS_ENABLE_SCREEN_CAPTURE_NAME
+IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_DESCRIPTION
+IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME
+IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION
+IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME
+IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_DESCRIPTION
+IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_NAME
+IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_DESCRIPTION
+IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_NAME
+IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_DESCRIPTION
+IDS_FLAGS_ENABLE_SYNCED_NOTIFICATIONS_NAME
+IDS_FLAGS_ENABLE_TCP_FAST_OPEN_DESCRIPTION
+IDS_FLAGS_ENABLE_TCP_FAST_OPEN_NAME
+IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION
+IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME
+IDS_FLAGS_ENABLE_TOUCH_EDITING_DESCRIPTION
+IDS_FLAGS_ENABLE_TOUCH_EDITING_NAME
+IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION
+IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME
+IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION
+IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME
+IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION
+IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME
+IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION
+IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME
+IDS_FLAGS_FORCE_ACCELERATED_OVERFLOW_SCROLL_MODE_DESCRIPTION
+IDS_FLAGS_FORCE_ACCELERATED_OVERFLOW_SCROLL_MODE_NAME
+IDS_FLAGS_FORCE_HIGH_DPI_DESCRIPTION
+IDS_FLAGS_FORCE_HIGH_DPI_NAME
+IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION
+IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME
+IDS_FLAGS_LONG_TITLE
+IDS_FLAGS_NACL_DEBUG_MASK_DESCRIPTION
+IDS_FLAGS_NACL_DEBUG_MASK_NAME
+IDS_FLAGS_NOT_AVAILABLE
+IDS_FLAGS_NO_EXPERIMENTS_AVAILABLE
+IDS_FLAGS_NO_UNSUPPORTED_EXPERIMENTS
+IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_DESCRIPTION
+IDS_FLAGS_NTP_OTHER_SESSIONS_MENU_NAME
+IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_DESCRIPTION
+IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_NAME
+IDS_FLAGS_RELAUNCH_BUTTON
+IDS_FLAGS_RELAUNCH_NOTICE
+IDS_FLAGS_RESET_ALL_BUTTON
+IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION
+IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME
+IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION
+IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME
+IDS_FLAGS_SHOW_FPS_COUNTER
+IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION
+IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION
+IDS_FLAGS_SHOW_TOUCH_HUD_NAME
+IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_DESCRIPTION
+IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_NAME
+IDS_FLAGS_SPELLCHECK_AUTOCORRECT
+IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION
+IDS_FLAGS_STACKED_TAB_STRIP_DESCRIPTION
+IDS_FLAGS_STACKED_TAB_STRIP_NAME
+IDS_FLAGS_TABLE_TITLE
+IDS_FLAGS_THREADED_COMPOSITING_MODE_DESCRIPTION
+IDS_FLAGS_THREADED_COMPOSITING_MODE_NAME
+IDS_FLAGS_TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE
+IDS_FLAGS_TOUCH_SCROLLING_MODE_DESCRIPTION
+IDS_FLAGS_TOUCH_SCROLLING_MODE_NAME
+IDS_FLAGS_TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE
+IDS_FLAGS_TOUCH_SCROLLING_MODE_TOUCHCANCEL
+IDS_FLAGS_UNSUPPORTED_TABLE_TITLE
+IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_DESCRIPTION
+IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_NAME
+IDS_FLAGS_WARNING_HEADER
+IDS_FLAGS_WARNING_TEXT
+IDS_FULLSCREEN
+IDS_GENERIC_EXPERIMENT_CHOICE_AUTOMATIC
+IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT
+IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED
+IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED
+IDS_GROUP_BY_DOMAIN_LABEL
+IDS_GUEST_PROFILE_NAME
+IDS_HARMFUL_V3_EXPLANATION_PARAGRAPH
+IDS_HARMFUL_V3_HEADING
+IDS_HARMFUL_V3_PRIMARY_PARAGRAPH
+IDS_HARMFUL_V3_PROCEED_PARAGRAPH
+IDS_HISTORY_ACTION_MENU_DESCRIPTION
+IDS_HISTORY_BLOCKED_VISIT_TEXT
+IDS_HISTORY_BROWSERESULTS
+IDS_HISTORY_CONTINUED
+IDS_HISTORY_DATE_WITH_RELATIVE_TIME
+IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON
+IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING
+IDS_HISTORY_FILTER_ALLOWED
+IDS_HISTORY_FILTER_ALLOW_ITEMS
+IDS_HISTORY_FILTER_BLOCKED
+IDS_HISTORY_FILTER_BLOCK_ITEMS
+IDS_HISTORY_HAS_SYNCED_RESULTS
+IDS_HISTORY_INTERVAL
+IDS_HISTORY_IN_CONTENT_PACK
+IDS_HISTORY_LOADING
+IDS_HISTORY_LOCK_BUTTON
+IDS_HISTORY_MORE_FROM_SITE
+IDS_HISTORY_NEWER
+IDS_HISTORY_NEWEST
+IDS_HISTORY_NO_RESULTS
+IDS_HISTORY_NO_SEARCH_RESULTS
+IDS_HISTORY_NO_SYNCED_RESULTS
+IDS_HISTORY_NUMBER_VISITS
+IDS_HISTORY_OLDER
+IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG
+IDS_HISTORY_RANGE_ALL_TIME
+IDS_HISTORY_RANGE_LABEL
+IDS_HISTORY_RANGE_MONTH
+IDS_HISTORY_RANGE_NEXT
+IDS_HISTORY_RANGE_PREVIOUS
+IDS_HISTORY_RANGE_TODAY
+IDS_HISTORY_RANGE_WEEK
+IDS_HISTORY_REMOVE_BOOKMARK
+IDS_HISTORY_REMOVE_PAGE
+IDS_HISTORY_REMOVE_SELECTED_ITEMS
+IDS_HISTORY_SEARCHRESULTSFOR
+IDS_HISTORY_SEARCH_BUTTON
+IDS_HISTORY_TITLE
+IDS_HISTORY_UNKNOWN_DEVICE
+IDS_HISTORY_UNLOCK_BUTTON
+IDS_HTTP_POST_WARNING
+IDS_HTTP_POST_WARNING_RESEND
+IDS_HTTP_POST_WARNING_TITLE
+IDS_IMPORT_FROM_FIREFOX
+IDS_IMPORT_FROM_ICEWEASEL
+IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
+IDS_JAVASCRIPT_ALERT_TITLE
+IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE
+IDS_JAVASCRIPT_MESSAGEBOX_TITLE
+IDS_KEYWORD_SEARCH
+IDS_LEARN_MORE
+IDS_LEGACY_DEFAULT_PROFILE_NAME
+IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL
+IDS_LIBADDRESSINPUT_AREA
+IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL
+IDS_LIBADDRESSINPUT_COUNTY
+IDS_LIBADDRESSINPUT_DEPARTMENT
+IDS_LIBADDRESSINPUT_DISTRICT
+IDS_LIBADDRESSINPUT_DO_SI
+IDS_LIBADDRESSINPUT_EMIRATE
+IDS_LIBADDRESSINPUT_ISLAND
+IDS_LIBADDRESSINPUT_LOCALITY_LABEL
+IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE
+IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL
+IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP
+IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL
+IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD
+IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE
+IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL
+IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE
+IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL
+IDS_LIBADDRESSINPUT_NEIGHBORHOOD
+IDS_LIBADDRESSINPUT_OBLAST
+IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL
+IDS_LIBADDRESSINPUT_PARISH
+IDS_LIBADDRESSINPUT_PIN_CODE_LABEL
+IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL
+IDS_LIBADDRESSINPUT_POST_TOWN
+IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE
+IDS_LIBADDRESSINPUT_PREFECTURE
+IDS_LIBADDRESSINPUT_PROVINCE
+IDS_LIBADDRESSINPUT_RECIPIENT_LABEL
+IDS_LIBADDRESSINPUT_STATE
+IDS_LIBADDRESSINPUT_SUBURB
+IDS_LIBADDRESSINPUT_UNKNOWN_VALUE
+IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE
+IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE
+IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL
+IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP
+IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE
+IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL
+IDS_LIBADDRESSINPUT_VILLAGE_TOWNSHIP
+IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL
+IDS_LINK_FROM_CLIPBOARD
+IDS_LOGIN_DIALOG_OK_BUTTON_LABEL
+IDS_LOGIN_DIALOG_PASSWORD_FIELD
+IDS_LOGIN_DIALOG_TITLE
+IDS_LOGIN_DIALOG_USERNAME_FIELD
+IDS_MALWARE_V3_ADVICE_HEADING
+IDS_MALWARE_V3_EXPLANATION_PARAGRAPH
+IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_ADVICE
+IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_HISTORY
+IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE
+IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_ADVICE
+IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_HISTORY
+IDS_MALWARE_V3_HEADING
+IDS_MALWARE_V3_PRIMARY_PARAGRAPH
+IDS_MALWARE_V3_PROCEED_PARAGRAPH
+IDS_MALWARE_V3_PROCEED_PARAGRAPH_NOT_RECOMMEND
+IDS_MALWARE_V3_PROCEED_PARAGRAPH_SOCIAL
+IDS_MANAGED_USER_AVATAR_LABEL
+IDS_MIDI_SYSEX_INFOBAR_QUESTION
+IDS_MIDI_SYSEX_PERMISSION_FRAGMENT
+IDS_MOBILE_WELCOME_URL
+IDS_NACL_DEBUG_MASK_CHOICE_DEBUG_ALL
+IDS_NACL_DEBUG_MASK_CHOICE_EXCLUDE_UTILS_PNACL
+IDS_NACL_DEBUG_MASK_CHOICE_INCLUDE_DEBUG
+IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION
+IDS_NET_EXPORT_NO_EMAIL_ACCOUNTS_ALERT_MESSAGE
+IDS_NET_EXPORT_NO_EMAIL_ACCOUNTS_ALERT_TITLE
+IDS_NEW_INCOGNITO_WINDOW_MAC
+IDS_NEW_NUMBERED_PROFILE_NAME
+IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE
+IDS_NEW_TAB_MOST_VISITED
+IDS_NEW_TAB_OTHER_SESSIONS_COLLAPSE_SESSION
+IDS_NEW_TAB_OTHER_SESSIONS_EXPAND_SESSION
+IDS_NEW_TAB_OTHER_SESSIONS_OPEN_ALL
+IDS_NEW_TAB_RECENTLY_CLOSED
+IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK
+IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION
+IDS_NEW_TAB_TITLE
+IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE
+IDS_NUMBERED_PROFILE_NAME
+IDS_OK
+IDS_OMNIBOX_EMPTY_HINT
+IDS_ONE_CLICK_SIGNIN_CONFIRM_EMAIL_DIALOG_CANCEL_BUTTON
+IDS_OPEN_TABS_NOTYETSYNCED
+IDS_OPEN_TABS_PROMOCOMPUTER
+IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY
+IDS_OPTIONS_DISABLE_WEB_SERVICES
+IDS_OPTIONS_ENABLE_LOGGING
+IDS_OPTIONS_IMPROVE_BROWSING_EXPERIENCE
+IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON
+IDS_OTHER_DEVICES_X_MORE
+IDS_PAGEINFO_ADDRESS
+IDS_PAGEINFO_CERT_INFO_BUTTON
+IDS_PAGEINFO_PARTIAL_ADDRESS
+IDS_PAGE_INFO_HELP_CENTER_LINK
+IDS_PAGE_INFO_INTERNAL_PAGE
+IDS_PAGE_INFO_SECURITY_BUTTON_ACCESSIBILITY_LABEL
+IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM
+IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT
+IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR
+IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING
+IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK
+IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS
+IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD
+IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE
+IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY
+IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY
+IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME
+IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT
+IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM
+IDS_PAGE_INFO_SECURITY_TAB_RENEGOTIATION_MESSAGE
+IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_NO_CT
+IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_NO_CT
+IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION
+IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION
+IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY
+IDS_PAGE_INFO_SECURITY_TAB_VISITED_BEFORE_TODAY
+IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT
+IDS_PAGE_INFO_SITE_INFO_TITLE
+IDS_PASSWORDS_EXCEPTIONS_TAB_TITLE
+IDS_PASSWORDS_SHOW_PASSWORDS_TAB_TITLE
+IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON
+IDS_PASSWORD_MANAGER_EMPTY_LOGIN
+IDS_PASSWORD_MANAGER_SAVE_BUTTON
+IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT
+IDS_PAST_TIME_TODAY
+IDS_PAST_TIME_YESTERDAY
+IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON
+IDS_PERMISSION_ALLOW
+IDS_PERMISSION_DENY
+IDS_PHISHING_V3_EXPLANATION_PARAGRAPH
+IDS_PHISHING_V3_HEADING
+IDS_PHISHING_V3_PRIMARY_PARAGRAPH
+IDS_PHISHING_V3_PROCEED_PARAGRAPH
+IDS_PLATFORM_LABEL
+IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_ACCEPT_BUTTON
+IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_TITLE
+IDS_PLUGIN_NOT_SUPPORTED
+IDS_POLICY_ASSOCIATION_STATE_ACTIVE
+IDS_POLICY_ASSOCIATION_STATE_DEPROVISIONED
+IDS_POLICY_ASSOCIATION_STATE_UNMANAGED
+IDS_POLICY_DEFAULT_SEARCH_DISABLED
+IDS_POLICY_DEPRECATED
+IDS_POLICY_DM_STATUS_HTTP_STATUS_ERROR
+IDS_POLICY_DM_STATUS_REQUEST_FAILED
+IDS_POLICY_DM_STATUS_REQUEST_INVALID
+IDS_POLICY_DM_STATUS_RESPONSE_DECODING_ERROR
+IDS_POLICY_DM_STATUS_SERVICE_ACTIVATION_PENDING
+IDS_POLICY_DM_STATUS_SERVICE_DEPROVISIONED
+IDS_POLICY_DM_STATUS_SERVICE_DEVICE_ID_CONFLICT
+IDS_POLICY_DM_STATUS_SERVICE_DEVICE_NOT_FOUND
+IDS_POLICY_DM_STATUS_SERVICE_DOMAIN_MISMATCH
+IDS_POLICY_DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER
+IDS_POLICY_DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED
+IDS_POLICY_DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID
+IDS_POLICY_DM_STATUS_SERVICE_MISSING_LICENSES
+IDS_POLICY_DM_STATUS_SERVICE_POLICY_NOT_FOUND
+IDS_POLICY_DM_STATUS_SUCCESS
+IDS_POLICY_DM_STATUS_TEMPORARY_UNAVAILABLE
+IDS_POLICY_DM_STATUS_UNKNOWN_ERROR
+IDS_POLICY_FILTER_PLACEHOLDER
+IDS_POLICY_HEADER_LEVEL
+IDS_POLICY_HEADER_NAME
+IDS_POLICY_HEADER_SCOPE
+IDS_POLICY_HEADER_STATUS
+IDS_POLICY_HEADER_VALUE
+IDS_POLICY_HIDE_EXPANDED_VALUE
+IDS_POLICY_INVALID_BOOKMARK
+IDS_POLICY_INVALID_PROXY_MODE_ERROR
+IDS_POLICY_INVALID_SEARCH_URL_ERROR
+IDS_POLICY_LABEL_ASSET_ID
+IDS_POLICY_LABEL_CLIENT_ID
+IDS_POLICY_LABEL_DIRECTORY_API_ID
+IDS_POLICY_LABEL_DOMAIN
+IDS_POLICY_LABEL_LOCATION
+IDS_POLICY_LABEL_REFRESH_INTERVAL
+IDS_POLICY_LABEL_STATUS
+IDS_POLICY_LABEL_TIME_SINCE_LAST_REFRESH
+IDS_POLICY_LABEL_USERNAME
+IDS_POLICY_LEVEL_ERROR
+IDS_POLICY_LEVEL_MANDATORY
+IDS_POLICY_LEVEL_RECOMMENDED
+IDS_POLICY_LIST_ENTRY_ERROR
+IDS_POLICY_NEVER_FETCHED
+IDS_POLICY_NOT_SPECIFIED
+IDS_POLICY_NOT_SPECIFIED_ERROR
+IDS_POLICY_NO_POLICIES_SET
+IDS_POLICY_OK
+IDS_POLICY_OUT_OF_RANGE_ERROR
+IDS_POLICY_OVERRIDDEN
+IDS_POLICY_PROXY_BOTH_SPECIFIED_ERROR
+IDS_POLICY_PROXY_MODE_AUTO_DETECT_ERROR
+IDS_POLICY_PROXY_MODE_DISABLED_ERROR
+IDS_POLICY_PROXY_MODE_FIXED_SERVERS_ERROR
+IDS_POLICY_PROXY_MODE_PAC_URL_ERROR
+IDS_POLICY_PROXY_MODE_SYSTEM_ERROR
+IDS_POLICY_PROXY_NEITHER_SPECIFIED_ERROR
+IDS_POLICY_RELOAD_POLICIES
+IDS_POLICY_SCHEMA_VALIDATION_ERROR
+IDS_POLICY_SCOPE_DEVICE
+IDS_POLICY_SCOPE_USER
+IDS_POLICY_SHOW_EXPANDED_VALUE
+IDS_POLICY_SHOW_UNSET
+IDS_POLICY_STATUS
+IDS_POLICY_STATUS_DEVICE
+IDS_POLICY_STATUS_USER
+IDS_POLICY_STORE_STATUS_BAD_STATE
+IDS_POLICY_STORE_STATUS_LOAD_ERROR
+IDS_POLICY_STORE_STATUS_OK
+IDS_POLICY_STORE_STATUS_PARSE_ERROR
+IDS_POLICY_STORE_STATUS_SERIALIZE_ERROR
+IDS_POLICY_STORE_STATUS_STORE_ERROR
+IDS_POLICY_STORE_STATUS_UNKNOWN_ERROR
+IDS_POLICY_STORE_STATUS_VALIDATION_ERROR
+IDS_POLICY_SUBKEY_ERROR
+IDS_POLICY_TITLE
+IDS_POLICY_TYPE_ERROR
+IDS_POLICY_UNKNOWN
+IDS_POLICY_UNSET
+IDS_POLICY_VALIDATION_BAD_INITIAL_SIGNATURE
+IDS_POLICY_VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE
+IDS_POLICY_VALIDATION_BAD_SIGNATURE
+IDS_POLICY_VALIDATION_BAD_TIMESTAMP
+IDS_POLICY_VALIDATION_BAD_USERNAME
+IDS_POLICY_VALIDATION_ERROR_CODE_PRESENT
+IDS_POLICY_VALIDATION_OK
+IDS_POLICY_VALIDATION_PAYLOAD_PARSE_ERROR
+IDS_POLICY_VALIDATION_POLICY_PARSE_ERROR
+IDS_POLICY_VALIDATION_UNKNOWN_ERROR
+IDS_POLICY_VALIDATION_WRONG_POLICY_TYPE
+IDS_POLICY_VALIDATION_WRONG_SETTINGS_ENTITY_ID
+IDS_POLICY_VALIDATION_WRONG_TOKEN
+IDS_PREFERENCES_CORRUPT_ERROR
+IDS_PREFERENCES_UNREADABLE_ERROR
+IDS_PRINT
+IDS_PRIVACY_POLICY_URL
+IDS_PRODUCT_NAME
+IDS_PROFILES_GUEST_PROFILE_NAME
+IDS_PROFILES_LOCAL_PROFILE_STATE
+IDS_PROFILE_TOO_NEW_ERROR
+IDS_PUSH_MESSAGES_BUBBLE_FRAGMENT
+IDS_PUSH_MESSAGES_BUBBLE_TEXT
+IDS_PUSH_MESSAGES_PERMISSION_QUESTION
+IDS_RECENT_TABS_MENU
+IDS_SAD_TAB_MESSAGE
+IDS_SAD_TAB_RELOAD_LABEL
+IDS_SAD_TAB_TITLE
+IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON
+IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON
+IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON
+IDS_SAFEBROWSING_V3_TITLE
+IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON
+IDS_SAFE_BROWSING_MALWARE_BACK_HEADLINE
+IDS_SAFE_BROWSING_MALWARE_COLLAB_HEADLINE
+IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE
+IDS_SAFE_BROWSING_MALWARE_FEAR_HEADLINE
+IDS_SAFE_BROWSING_MALWARE_HEADLINE
+IDS_SAFE_BROWSING_MALWARE_LABEL
+IDS_SAFE_BROWSING_MALWARE_QUESTION_HEADLINE
+IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE
+IDS_SAFE_BROWSING_MALWARE_TITLE
+IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION1
+IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION1_SUBRESOURCE
+IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION2
+IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION2_SUBRESOURCE
+IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION3
+IDS_SAFE_BROWSING_MALWARE_V2_DETAILS
+IDS_SAFE_BROWSING_MALWARE_V2_DETAILS_SUBRESOURCE
+IDS_SAFE_BROWSING_MALWARE_V2_HEADLINE
+IDS_SAFE_BROWSING_MALWARE_V2_HEADLINE_SUBRESOURCE
+IDS_SAFE_BROWSING_MALWARE_V2_LEARN_MORE
+IDS_SAFE_BROWSING_MALWARE_V2_PROCEED_LINK
+IDS_SAFE_BROWSING_MALWARE_V2_REPORTING_AGREE
+IDS_SAFE_BROWSING_MALWARE_V2_SEE_MORE
+IDS_SAFE_BROWSING_MALWARE_V2_TITLE
+IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION1
+IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION2
+IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION3
+IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION_AGREE
+IDS_SAFE_BROWSING_MULTI_MALWARE_PROCEED_BUTTON
+IDS_SAFE_BROWSING_MULTI_PHISHING_DESCRIPTION1
+IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION1
+IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION2
+IDS_SAFE_BROWSING_MULTI_THREAT_TITLE
+IDS_SAFE_BROWSING_PHISHING_BACK_HEADLINE
+IDS_SAFE_BROWSING_PHISHING_COLLAB_HEADLINE
+IDS_SAFE_BROWSING_PHISHING_FEAR_HEADLINE
+IDS_SAFE_BROWSING_PHISHING_HEADLINE
+IDS_SAFE_BROWSING_PHISHING_LABEL
+IDS_SAFE_BROWSING_PHISHING_QUESTION_HEADLINE
+IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR
+IDS_SAFE_BROWSING_PHISHING_TITLE
+IDS_SAFE_BROWSING_PHISHING_V2_DESCRIPTION1
+IDS_SAFE_BROWSING_PHISHING_V2_DESCRIPTION2
+IDS_SAFE_BROWSING_PHISHING_V2_HEADLINE
+IDS_SAFE_BROWSING_PHISHING_V2_REPORT_ERROR
+IDS_SAFE_BROWSING_PHISHING_V2_TITLE
+IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE
+IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE_V2
+IDS_SAFE_BROWSING_PRIVACY_POLICY_URL
+IDS_SAVE
+IDS_SEARCH_BOX_EMPTY_HINT
+IDS_SECURE_CONNECTION_EV
+IDS_SESSION_CRASHED_VIEW_MESSAGE
+IDS_SESSION_CRASHED_VIEW_RESTORE_BUTTON
+IDS_SETTINGS_SHOW_ADVANCED_SETTINGS
+IDS_SHORT_PRODUCT_NAME
+IDS_SHOW_HISTORY
+IDS_SIGNED_IN_WITH_SYNC_DISABLED
+IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED
+IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE
+IDS_SINGLE_PROFILE_DISPLAY_NAME
+IDS_SSL_CLOCK_ERROR
+IDS_SSL_CLOCK_ERROR_EXPLANATION
+IDS_SSL_NONOVERRIDABLE_HSTS
+IDS_SSL_NONOVERRIDABLE_INVALID
+IDS_SSL_NONOVERRIDABLE_MORE
+IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3
+IDS_SSL_NONOVERRIDABLE_PINNED
+IDS_SSL_NONOVERRIDABLE_REVOKED
+IDS_SSL_OVERRIDABLE_PRIMARY_PARAGRAPH
+IDS_SSL_OVERRIDABLE_PROCEED_LINK_TEXT
+IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH
+IDS_SSL_OVERRIDABLE_SAFETY_BUTTON
+IDS_SSL_OVERRIDABLE_TITLE
+IDS_SSL_RELOAD
+IDS_SSL_V2_CLOCK_AHEAD_HEADING
+IDS_SSL_V2_CLOCK_BEHIND_HEADING
+IDS_SSL_V2_CLOCK_PRIMARY_PARAGRAPH
+IDS_SSL_V2_CLOCK_TITLE
+IDS_SSL_V2_CLOCK_UPDATE_DATE_AND_TIME
+IDS_SSL_V2_CLOSE_DETAILS_BUTTON
+IDS_SSL_V2_HEADING
+IDS_SSL_V2_OPEN_DETAILS_BUTTON
+IDS_SSL_V2_PRIMARY_PARAGRAPH
+IDS_SSL_V2_TITLE
+IDS_STARS_PROMO_LABEL_IOS
+IDS_SUPERVISED_USER_AVATAR_LABEL
+IDS_SUPERVISED_USER_NEW_AVATAR_LABEL
+IDS_SYNC_ACCOUNT_DETAILS_NOT_ENTERED
+IDS_SYNC_ACCOUNT_SYNCING_TO_USER
+IDS_SYNC_ACCOUNT_SYNCING_TO_USER_WITH_MANAGE_LINK
+IDS_SYNC_AUTHENTICATING_LABEL
+IDS_SYNC_BASIC_ENCRYPTION_DATA
+IDS_SYNC_CLEAR_USER_DATA
+IDS_SYNC_CONFIGURE_ENCRYPTION
+IDS_SYNC_DATATYPE_AUTOFILL
+IDS_SYNC_DATATYPE_BOOKMARKS
+IDS_SYNC_DATATYPE_PASSWORDS
+IDS_SYNC_DATATYPE_PREFERENCES
+IDS_SYNC_DATATYPE_TABS
+IDS_SYNC_DATATYPE_TYPED_URLS
+IDS_SYNC_EMPTY_PASSPHRASE_ERROR
+IDS_SYNC_ENABLE_SYNC_ON_ACCOUNT
+IDS_SYNC_ENCRYPTION_SECTION_TITLE
+IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY
+IDS_SYNC_ENTER_PASSPHRASE_BODY
+IDS_SYNC_ENTER_PASSPHRASE_BODY_WITH_DATE
+IDS_SYNC_ENTER_PASSPHRASE_TITLE
+IDS_SYNC_ERROR_BUBBLE_VIEW_TITLE
+IDS_SYNC_ERROR_SIGNING_IN
+IDS_SYNC_FULL_ENCRYPTION_DATA
+IDS_SYNC_INVALID_USER_CREDENTIALS
+IDS_SYNC_LOGIN_INFO_OUT_OF_DATE
+IDS_SYNC_LOGIN_SETTING_UP
+IDS_SYNC_MENU_PRE_SYNCED_LABEL
+IDS_SYNC_MENU_SYNCED_LABEL
+IDS_SYNC_NTP_PASSWORD_ENABLE
+IDS_SYNC_NTP_PASSWORD_PROMO
+IDS_SYNC_NTP_PASSWORD_PROMO,
+IDS_SYNC_NTP_SETUP_IN_PROGRESS
+IDS_SYNC_OPTIONS_GROUP_NAME
+IDS_SYNC_OTHER_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE
+IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_ACCEPT
+IDS_SYNC_PASSPHRASE_ERROR_BUBBLE_VIEW_MESSAGE
+IDS_SYNC_PASSPHRASE_ERROR_WRENCH_MENU_ITEM
+IDS_SYNC_PASSPHRASE_LABEL
+IDS_SYNC_PASSPHRASE_MISMATCH_ERROR
+IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_POSTFIX
+IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_PREFIX
+IDS_SYNC_PASSWORD_SYNC_ATTENTION
+IDS_SYNC_PROMO_NTP_BUBBLE_MESSAGE
+IDS_SYNC_PROMO_TAB_TITLE
+IDS_SYNC_RELOGIN_LINK_LABEL
+IDS_SYNC_SERVER_IS_UNREACHABLE
+IDS_SYNC_SERVICE_UNAVAILABLE
+IDS_SYNC_SETUP_ERROR
+IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_ACCEPT
+IDS_SYNC_SIGN_IN_ERROR_BUBBLE_VIEW_MESSAGE
+IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM
+IDS_SYNC_START_SYNC_BUTTON_LABEL
+IDS_SYNC_STATUS_UNRECOVERABLE_ERROR
+IDS_SYNC_STOP_AND_RESTART_SYNC
+IDS_SYNC_TIME_JUST_NOW
+IDS_SYNC_TIME_NEVER
+IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_ACCEPT
+IDS_SYNC_UNAVAILABLE_ERROR_BUBBLE_VIEW_MESSAGE
+IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL
+IDS_SYNC_UPGRADE_CLIENT
+IDS_SYSTEM_FLAGS_OWNER_ONLY
+IDS_TERMS_HTML
+IDS_TIME_DAYS
+IDS_TIME_DAYS_1ST
+IDS_TIME_ELAPSED_DAYS
+IDS_TIME_ELAPSED_HOURS
+IDS_TIME_ELAPSED_MINS
+IDS_TIME_ELAPSED_SECS
+IDS_TIME_HOURS
+IDS_TIME_HOURS_1ST
+IDS_TIME_HOURS_2ND
+IDS_TIME_LONG_MINS
+IDS_TIME_LONG_MINS_1ST
+IDS_TIME_LONG_MINS_2ND
+IDS_TIME_LONG_SECS
+IDS_TIME_LONG_SECS_2ND
+IDS_TIME_MINS
+IDS_TIME_REMAINING_DAYS
+IDS_TIME_REMAINING_HOURS
+IDS_TIME_REMAINING_LONG_MINS
+IDS_TIME_REMAINING_LONG_SECS
+IDS_TIME_REMAINING_MINS
+IDS_TIME_REMAINING_SECS
+IDS_TIME_SECS
+IDS_TOOLTIP_STAR
+IDS_TOUCH_EVENTS_DESCRIPTION
+IDS_TOUCH_EVENTS_NAME
+IDS_TRANSLATE_INFOBAR_ACCEPT
+IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE
+IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE
+IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE
+IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE
+IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_IOS
+IDS_TRANSLATE_INFOBAR_DENY
+IDS_TRANSLATE_INFOBAR_ERROR_CANT_CONNECT
+IDS_TRANSLATE_INFOBAR_ERROR_CANT_TRANSLATE
+IDS_TRANSLATE_INFOBAR_ERROR_SAME_LANGUAGE
+IDS_TRANSLATE_INFOBAR_NEVER_MESSAGE_IOS
+IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE
+IDS_TRANSLATE_INFOBAR_OPTIONS_ABOUT
+IDS_TRANSLATE_INFOBAR_OPTIONS_ALWAYS
+IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_LANG
+IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_SITE
+IDS_TRANSLATE_INFOBAR_OPTIONS_REPORT_ERROR
+IDS_TRANSLATE_INFOBAR_RETRY
+IDS_TRANSLATE_INFOBAR_REVERT
+IDS_TRANSLATE_INFOBAR_TRANSLATING_TO
+IDS_TRANSLATE_INFOBAR_UNKNOWN_PAGE_LANGUAGE
+IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE
+IDS_UPGRADE_AVAILABLE
+IDS_UPGRADE_AVAILABLE_BUTTON
+IDS_WEB_FONT_FAMILY
+IDS_WEB_FONT_SIZE
diff --git a/build/ios/mac_build.gypi b/build/ios/mac_build.gypi
new file mode 100644
index 0000000..4da21eb
--- /dev/null
+++ b/build/ios/mac_build.gypi
@@ -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.
+
+# Xcode throws an error if an iOS target depends on a Mac OS X target. So
+# any place a utility program needs to be build and run, an action is
+# used to run ninja as script to work around this.
+# Example:
+# {
+#   'target_name': 'foo',
+#   'type': 'none',
+#   'variables': {
+#     # The name of a directory used for ninja. This cannot be shared with
+#     # another mac build.
+#     'ninja_output_dir': 'ninja-foo',
+#     # The full path to the location in which the ninja executable should be
+#     # placed. This cannot be shared with another mac build.
+#    'ninja_product_dir':
+#      '<(DEPTH)/xcodebuild/<(ninja_output_dir)/<(CONFIGURATION_NAME)',
+#     # The list of all the gyp files that contain the targets to run.
+#     're_run_targets': [
+#       'foo.gyp',
+#     ],
+#   },
+#   'includes': ['path_to/mac_build.gypi'],
+#   'actions': [
+#     {
+#       'action_name': 'compile foo',
+#       'inputs': [],
+#       'outputs': [],
+#       'action': [
+#         '<@(ninja_cmd)',
+#         # All the targets to build.
+#         'foo1',
+#         'foo2',
+#       ],
+#     },
+#   ],
+# }
+{
+  'variables': {
+    'variables': {
+     'parent_generator%': '<(GENERATOR)',
+    },
+    'parent_generator%': '<(parent_generator)',
+    # Common ninja command line flags.
+    'ninja_cmd': [
+      # Bounce through clean_env to clean up the environment so things
+      # set by the iOS build don't pollute the Mac build.
+      '<(DEPTH)/build/ios/clean_env.py',
+      # ninja must be found in the PATH.
+      'ADD_TO_PATH=<!(echo $PATH)',
+      'ninja',
+      '-C',
+      '<(ninja_product_dir)',
+    ],
+
+    # Common syntax to rerun gyp to generate the Mac projects.
+    're_run_gyp': [
+      'build/gyp_chromium',
+      '--depth=.',
+      # Don't use anything set for the iOS side of things.
+      '--ignore-environment',
+      # Generate for ninja
+      '--format=ninja',
+      # Generate files into xcodebuild/ninja
+      '-Goutput_dir=xcodebuild/<(ninja_output_dir)',
+      # nacl isn't in the iOS checkout, make sure it's turned off
+      '-Ddisable_nacl=1',
+      # Pass through the Mac SDK version.
+      '-Dmac_sdk=<(mac_sdk)',
+      '-Dparent_generator=<(parent_generator)'
+    ],
+
+    # Rerun gyp for each of the projects needed. This is what actually
+    # generates the projects on disk.
+    're_run_gyp_execution':
+      '<!(cd <(DEPTH) && <@(re_run_gyp) <@(re_run_targets))',
+  },
+  # Since these are used to generate things needed by other targets, make
+  # them hard dependencies so they are always built first.
+  'hard_dependency': 1,
+}
diff --git a/build/isolate.gypi b/build/isolate.gypi
new file mode 100644
index 0000000..10033da
--- /dev/null
+++ b/build/isolate.gypi
@@ -0,0 +1,130 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to "build" .isolate files into a .isolated file.
+#
+# To use this, create a gyp target with the following form:
+# 'conditions': [
+#   ['test_isolation_mode != "noop"', {
+#     'targets': [
+#       {
+#         'target_name': 'foo_test_run',
+#         'type': 'none',
+#         'dependencies': [
+#           'foo_test',
+#         ],
+#         'includes': [
+#           '../build/isolate.gypi',
+#         ],
+#         'sources': [
+#           'foo_test.isolate',
+#         ],
+#       },
+#     ],
+#   }],
+# ],
+#
+# Note: foo_test.isolate is included and a source file. It is an inherent
+# property of the .isolate format. This permits to define GYP variables but is
+# a stricter format than GYP so isolate.py can read it.
+#
+# The generated .isolated file will be:
+#   <(PRODUCT_DIR)/foo_test.isolated
+#
+# See http://dev.chromium.org/developers/testing/isolated-testing/for-swes
+# for more information.
+
+{
+  'includes': [
+    '../build/util/version.gypi',
+  ],
+  'rules': [
+    {
+      'rule_name': 'isolate',
+      'extension': 'isolate',
+      'inputs': [
+        # Files that are known to be involved in this step.
+        '<(DEPTH)/tools/isolate_driver.py',
+        '<(DEPTH)/tools/swarming_client/isolate.py',
+        '<(DEPTH)/tools/swarming_client/run_isolated.py',
+      ],
+      'outputs': [],
+      'action': [
+        'python',
+        '<(DEPTH)/tools/isolate_driver.py',
+        '<(test_isolation_mode)',
+        '--isolated', '<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated',
+        '--isolate', '<(RULE_INPUT_PATH)',
+
+        # Variables should use the -V FOO=<(FOO) form so frequent values,
+        # like '0' or '1', aren't stripped out by GYP. Run 'isolate.py help' for
+        # more details.
+
+        # Path variables are used to replace file paths when loading a .isolate
+        # file
+        '--path-variable', 'DEPTH', '<(DEPTH)',
+        '--path-variable', 'PRODUCT_DIR', '<(PRODUCT_DIR) ',
+
+        # Extra variables are replaced on the 'command' entry and on paths in
+        # the .isolate file but are not considered relative paths.
+        '--extra-variable', 'version_full=<(version_full)',
+
+        # Note: This list must match DefaultConfigVariables()
+        # in build/android/pylib/utils/isolator.py
+        '--config-variable', 'CONFIGURATION_NAME=<(CONFIGURATION_NAME)',
+        '--config-variable', 'OS=<(OS)',
+        '--config-variable', 'asan=<(asan)',
+        '--config-variable', 'branding=<(branding)',
+        '--config-variable', 'chromeos=<(chromeos)',
+        '--config-variable', 'component=<(component)',
+        '--config-variable', 'disable_nacl=<(disable_nacl)',
+        '--config-variable', 'enable_pepper_cdms=<(enable_pepper_cdms)',
+        '--config-variable', 'enable_plugins=<(enable_plugins)',
+        '--config-variable', 'fastbuild=<(fastbuild)',
+        '--config-variable', 'icu_use_data_file_flag=<(icu_use_data_file_flag)',
+        # TODO(kbr): move this to chrome_tests.gypi:gles2_conform_tests_run
+        # once support for user-defined config variables is added.
+        '--config-variable',
+          'internal_gles2_conform_tests=<(internal_gles2_conform_tests)',
+        '--config-variable', 'kasko=<(kasko)',
+        '--config-variable', 'libpeer_target_type=<(libpeer_target_type)',
+        '--config-variable', 'lsan=<(lsan)',
+        '--config-variable', 'msan=<(msan)',
+        '--config-variable', 'target_arch=<(target_arch)',
+        '--config-variable', 'tsan=<(tsan)',
+        '--config-variable', 'use_custom_libcxx=<(use_custom_libcxx)',
+        '--config-variable', 'use_instrumented_libraries=<(use_instrumented_libraries)',
+        '--config-variable',
+        'use_prebuilt_instrumented_libraries=<(use_prebuilt_instrumented_libraries)',
+        '--config-variable', 'use_openssl=<(use_openssl)',
+        '--config-variable', 'use_ozone=<(use_ozone)',
+        '--config-variable', 'use_x11=<(use_x11)',
+        '--config-variable', 'v8_use_external_startup_data=<(v8_use_external_startup_data)',
+      ],
+      'conditions': [
+        # Note: When gyp merges lists, it appends them to the old value.
+        ['OS=="mac"', {
+          # <(mac_product_name) can contain a space, so don't use FOO=<(FOO)
+          # form.
+          'action': [
+            '--extra-variable', 'mac_product_name', '<(mac_product_name)',
+          ],
+        }],
+        ["test_isolation_outdir!=''", {
+          'action': [ '--isolate-server', '<(test_isolation_outdir)' ],
+        }],
+        ["test_isolation_mode == 'prepare'", {
+          'outputs': [
+            '<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated.gen.json',
+          ],
+        }, {
+          'outputs': [
+            '<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated',
+          ],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/build/jar_file_jni_generator.gypi b/build/jar_file_jni_generator.gypi
new file mode 100644
index 0000000..3d95b28
--- /dev/null
+++ b/build/jar_file_jni_generator.gypi
@@ -0,0 +1,67 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to generate jni bindings for system Java-files in a consistent manner.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'android_jar_jni_headers',
+#   'type': 'none',
+#   'variables': {
+#     'jni_gen_package': 'chrome',
+#     'input_java_class': 'java/io/InputStream.class',
+#   },
+#   'includes': [ '../build/jar_file_jni_generator.gypi' ],
+# },
+#
+# Optional variables:
+#  input_jar_file - The input jar file, if omitted, android_sdk_jar will be used.
+
+{
+  'variables': {
+    'jni_generator': '<(DEPTH)/base/android/jni_generator/jni_generator.py',
+    # A comma separated string of include files.
+    'jni_generator_includes%': (
+        'base/android/jni_generator/jni_generator_helper.h'
+    ),
+    'native_exports%': '--native_exports_optional',
+  },
+  'actions': [
+    {
+      'action_name': 'generate_jni_headers_from_jar_file',
+      'inputs': [
+        '<(jni_generator)',
+        '<(input_jar_file)',
+        '<(android_sdk_jar)',
+      ],
+      'variables': {
+        'java_class_name': '<!(basename <(input_java_class)|sed "s/\.class//")',
+        'input_jar_file%': '<(android_sdk_jar)'
+      },
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)/jni/<(java_class_name)_jni.h',
+      ],
+      'action': [
+        '<(jni_generator)',
+        '-j',
+        '<(input_jar_file)',
+        '--input_file',
+        '<(input_java_class)',
+        '--output_dir',
+        '<(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)/jni',
+        '--includes',
+        '<(jni_generator_includes)',
+        '--optimize_generation',
+        '<(optimize_jni_generation)',
+        '<(native_exports)',
+      ],
+      'message': 'Generating JNI bindings from  <(input_jar_file)/<(input_java_class)',
+      'process_outputs_as_sources': 1,
+    },
+  ],
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
diff --git a/build/java.gypi b/build/java.gypi
new file mode 100644
index 0000000..730fa22
--- /dev/null
+++ b/build/java.gypi
@@ -0,0 +1,347 @@
+# Copyright (c) 2012 The Chromium 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 to be included into a target to provide a rule
+# to build Java in a consistent manner.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my-package_java',
+#   'type': 'none',
+#   'variables': {
+#     'java_in_dir': 'path/to/package/root',
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# Required variables:
+#  java_in_dir - The top-level java directory. The src should be in
+#    <java_in_dir>/src.
+# Optional/automatic variables:
+#  add_to_dependents_classpaths - Set to 0 if the resulting jar file should not
+#    be added to its dependents' classpaths.
+#  additional_input_paths - These paths will be included in the 'inputs' list to
+#    ensure that this target is rebuilt when one of these paths changes.
+#  additional_src_dirs - Additional directories with .java files to be compiled
+#    and included in the output of this target.
+#  generated_src_dirs - Same as additional_src_dirs except used for .java files
+#    that are generated at build time. This should be set automatically by a
+#    target's dependencies. The .java files in these directories are not
+#    included in the 'inputs' list (unlike additional_src_dirs).
+#  input_jars_paths - The path to jars to be included in the classpath. This
+#    should be filled automatically by depending on the appropriate targets.
+#  javac_includes - A list of specific files to include. This is by default
+#    empty, which leads to inclusion of all files specified. May include
+#    wildcard, and supports '**/' for recursive path wildcards, ie.:
+#    '**/MyFileRegardlessOfDirectory.java', '**/IncludedPrefix*.java'.
+#  has_java_resources - Set to 1 if the java target contains an
+#    Android-compatible resources folder named res.  If 1, R_package and
+#    R_package_relpath must also be set.
+#  R_package - The java package in which the R class (which maps resources to
+#    integer IDs) should be generated, e.g. org.chromium.content.
+#  R_package_relpath - Same as R_package, but replace each '.' with '/'.
+#  res_extra_dirs - A list of extra directories containing Android resources.
+#    These directories may be generated at build time.
+#  res_extra_files - A list of the files in res_extra_dirs.
+#  never_lint - Set to 1 to not run lint on this target.
+
+{
+  'dependencies': [
+    '<(DEPTH)/build/android/setup.gyp:build_output_dirs'
+  ],
+  'variables': {
+    'add_to_dependents_classpaths%': 1,
+    'android_jar': '<(android_sdk)/android.jar',
+    'input_jars_paths': [ '<(android_jar)' ],
+    'additional_src_dirs': [],
+    'javac_includes': [],
+    'jar_name': '<(_target_name).jar',
+    'jar_dir': '<(PRODUCT_DIR)/lib.java',
+    'jar_path': '<(intermediate_dir)/<(jar_name)',
+    'jar_final_path': '<(jar_dir)/<(jar_name)',
+    'jar_excluded_classes': [ '*/R.class', '*/R##*.class' ],
+    'instr_stamp': '<(intermediate_dir)/instr.stamp',
+    'additional_input_paths': [],
+    'dex_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).dex.jar',
+    'generated_src_dirs': ['>@(generated_R_dirs)'],
+    'generated_R_dirs': [],
+    'has_java_resources%': 0,
+    'res_extra_dirs': [],
+    'res_extra_files': [],
+    'res_v14_verify_only%': 0,
+    'resource_input_paths': ['>@(res_extra_files)'],
+    'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
+    'compile_stamp': '<(intermediate_dir)/compile.stamp',
+    'lint_stamp': '<(intermediate_dir)/lint.stamp',
+    'lint_result': '<(intermediate_dir)/lint_result.xml',
+    'lint_config': '<(intermediate_dir)/lint_config.xml',
+    'never_lint%': 0,
+    'findbugs_stamp': '<(intermediate_dir)/findbugs.stamp',
+    'run_findbugs%': 0,
+    'proguard_config%': '',
+    'proguard_preprocess%': '0',
+    'variables': {
+      'variables': {
+        'proguard_preprocess%': 0,
+        'emma_never_instrument%': 0,
+      },
+      'conditions': [
+        ['proguard_preprocess == 1', {
+          'javac_jar_path': '<(intermediate_dir)/<(_target_name).pre.jar'
+        }, {
+          'javac_jar_path': '<(jar_path)'
+        }],
+        ['chromium_code != 0 and emma_coverage != 0 and emma_never_instrument == 0', {
+          'emma_instrument': 1,
+        }, {
+          'emma_instrument': 0,
+        }],
+      ],
+    },
+    'emma_instrument': '<(emma_instrument)',
+    'javac_jar_path': '<(javac_jar_path)',
+  },
+  'conditions': [
+    ['add_to_dependents_classpaths == 1', {
+      # This all_dependent_settings is used for java targets only. This will add the
+      # jar path to the classpath of dependent java targets.
+      'all_dependent_settings': {
+        'variables': {
+          'input_jars_paths': ['<(jar_final_path)'],
+          'library_dexed_jars_paths': ['<(dex_path)'],
+        },
+      },
+    }],
+    ['has_java_resources == 1', {
+      'variables': {
+        'resource_dir': '<(java_in_dir)/res',
+        'res_input_dirs': ['<(resource_dir)', '<@(res_extra_dirs)'],
+        'resource_input_paths': ['<!@(find <(resource_dir) -type f)'],
+
+        'R_dir': '<(intermediate_dir)/java_R',
+        'R_text_file': '<(R_dir)/R.txt',
+
+        'generated_src_dirs': ['<(R_dir)'],
+        'additional_input_paths': ['<(resource_zip_path)', ],
+
+        'dependencies_res_zip_paths': [],
+        'resource_zip_path': '<(PRODUCT_DIR)/res.java/<(_target_name).zip',
+      },
+      'all_dependent_settings': {
+        'variables': {
+          # Dependent libraries include this target's R.java file via
+          # generated_R_dirs.
+          'generated_R_dirs': ['<(R_dir)'],
+
+          # Dependent libraries and apks include this target's resources via
+          # dependencies_res_zip_paths.
+          'additional_input_paths': ['<(resource_zip_path)'],
+          'dependencies_res_zip_paths': ['<(resource_zip_path)'],
+
+          # additional_res_packages and additional_R_text_files are used to
+          # create this packages R.java files when building the APK.
+          'additional_res_packages': ['<(R_package)'],
+          'additional_R_text_files': ['<(R_text_file)'],
+        },
+      },
+      'actions': [
+        # Generate R.java and crunch image resources.
+        {
+          'action_name': 'process_resources',
+          'message': 'processing resources for <(_target_name)',
+          'variables': {
+            'android_manifest': '<(DEPTH)/build/android/AndroidManifest.xml',
+            # Write the inputs list to a file, so that its mtime is updated when
+            # the list of inputs changes.
+            'inputs_list_file': '>|(java_resources.<(_target_name).gypcmd >@(resource_input_paths))',
+            'process_resources_options': [],
+            'conditions': [
+              ['res_v14_verify_only == 1', {
+                'process_resources_options': ['--v14-verify-only']
+              }],
+            ],
+          },
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/process_resources.py',
+            '<(DEPTH)/build/android/gyp/generate_v14_compatible_resources.py',
+            '>@(resource_input_paths)',
+            '>@(dependencies_res_zip_paths)',
+            '>(inputs_list_file)',
+          ],
+          'outputs': [
+            '<(resource_zip_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/process_resources.py',
+            '--android-sdk', '<(android_sdk)',
+            '--android-sdk-tools', '<(android_sdk_tools)',
+            '--non-constant-id',
+
+            '--android-manifest', '<(android_manifest)',
+            '--custom-package', '<(R_package)',
+
+            '--dependencies-res-zips', '>(dependencies_res_zip_paths)',
+            '--resource-dirs', '<(res_input_dirs)',
+
+            '--R-dir', '<(R_dir)',
+            '--resource-zip-out', '<(resource_zip_path)',
+
+            '<@(process_resources_options)',
+          ],
+        },
+      ],
+    }],
+    ['proguard_preprocess == 1', {
+      'actions': [
+        {
+          'action_name': 'proguard_<(_target_name)',
+          'message': 'Proguard preprocessing <(_target_name) jar',
+          'inputs': [
+            '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/proguard.py',
+            '<(javac_jar_path)',
+            '<(proguard_config)',
+          ],
+          'outputs': [
+            '<(jar_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/proguard.py',
+            '--proguard-path=<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '--input-path=<(javac_jar_path)',
+            '--output-path=<(jar_path)',
+            '--proguard-config=<(proguard_config)',
+            '--classpath=<(android_sdk_jar) >(input_jars_paths)',
+          ]
+        },
+      ],
+    }],
+    ['run_findbugs == 1', {
+      'actions': [
+        {
+          'action_name': 'findbugs_<(_target_name)',
+          'message': 'Running findbugs on <(_target_name)',
+          'inputs': [
+            '<(DEPTH)/build/android/findbugs_diff.py',
+            '<(DEPTH)/build/android/findbugs_filter/findbugs_exclude.xml',
+            '<(DEPTH)/build/android/pylib/utils/findbugs.py',
+            '>@(input_jars_paths)',
+            '<(jar_final_path)',
+            '<(compile_stamp)',
+          ],
+          'outputs': [
+            '<(findbugs_stamp)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/findbugs_diff.py',
+            '--auxclasspath-gyp', '>(input_jars_paths)',
+            '--stamp', '<(findbugs_stamp)',
+            '<(jar_final_path)',
+          ],
+        },
+      ],
+    }],
+  ],
+  'actions': [
+    {
+      'action_name': 'javac_<(_target_name)',
+      'message': 'Compiling <(_target_name) java sources',
+      'variables': {
+        'java_sources': ['>!@(find >(java_in_dir)/src >(additional_src_dirs) -name "*.java")'],
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/javac.py',
+        '>@(java_sources)',
+        '>@(input_jars_paths)',
+        '>@(additional_input_paths)',
+      ],
+      'outputs': [
+        '<(compile_stamp)',
+        '<(javac_jar_path)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/javac.py',
+        '--classpath=>(input_jars_paths)',
+        '--src-gendirs=>(generated_src_dirs)',
+        '--javac-includes=<(javac_includes)',
+        '--chromium-code=<(chromium_code)',
+        '--jar-path=<(javac_jar_path)',
+        '--jar-excluded-classes=<(jar_excluded_classes)',
+        '--stamp=<(compile_stamp)',
+        '>@(java_sources)',
+      ]
+    },
+    {
+      'action_name': 'instr_jar_<(_target_name)',
+      'message': 'Instrumenting <(_target_name) jar',
+      'variables': {
+        'input_path': '<(jar_path)',
+        'output_path': '<(jar_final_path)',
+        'stamp_path': '<(instr_stamp)',
+        'instr_type': 'jar',
+      },
+      'outputs': [
+        '<(jar_final_path)',
+      ],
+      'inputs': [
+        '<(jar_path)',
+      ],
+      'includes': [ 'android/instr_action.gypi' ],
+    },
+    {
+      'variables': {
+        'src_dirs': [
+          '<(java_in_dir)/src',
+          '>@(additional_src_dirs)',
+        ],
+        'stamp_path': '<(lint_stamp)',
+        'result_path': '<(lint_result)',
+        'config_path': '<(lint_config)',
+        'lint_jar_path': '<(jar_final_path)',
+      },
+      'inputs': [
+        '<(jar_final_path)',
+        '<(compile_stamp)',
+      ],
+      'outputs': [
+        '<(lint_stamp)',
+      ],
+      'includes': [ 'android/lint_action.gypi' ],
+    },
+    {
+      'action_name': 'jar_toc_<(_target_name)',
+      'message': 'Creating <(_target_name) jar.TOC',
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/util/md5_check.py',
+        '<(DEPTH)/build/android/gyp/jar_toc.py',
+        '<(jar_final_path)',
+      ],
+      'outputs': [
+        '<(jar_final_path).TOC',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/jar_toc.py',
+        '--jar-path=<(jar_final_path)',
+        '--toc-path=<(jar_final_path).TOC',
+      ]
+    },
+    {
+      'action_name': 'dex_<(_target_name)',
+      'variables': {
+        'conditions': [
+          ['emma_instrument != 0', {
+            'dex_no_locals': 1,
+          }],
+        ],
+        'dex_input_paths': [ '<(jar_final_path)' ],
+        'output_path': '<(dex_path)',
+      },
+      'includes': [ 'android/dex_action.gypi' ],
+    },
+  ],
+}
diff --git a/build/java_aidl.gypi b/build/java_aidl.gypi
new file mode 100644
index 0000000..8f111fd
--- /dev/null
+++ b/build/java_aidl.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to build Java aidl files in a consistent manner.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'aidl_aidl-file-name',
+#   'type': 'none',
+#   'variables': {
+#     'aidl_interface_file': '<interface-path>/<interface-file>.aidl',
+#     'aidl_import_include': '<(DEPTH)/<path-to-src-dir>',
+#   },
+#   'sources': {
+#     '<input-path1>/<input-file1>.aidl',
+#     '<input-path2>/<input-file2>.aidl',
+#     ...
+#   },
+#   'includes': ['<path-to-this-file>/java_aidl.gypi'],
+# }
+#
+#
+# The generated java files will be:
+#   <(PRODUCT_DIR)/lib.java/<input-file1>.java
+#   <(PRODUCT_DIR)/lib.java/<input-file2>.java
+#   ...
+#
+# Optional variables:
+#  aidl_import_include - This should be an absolute path to your java src folder
+#    that contains the classes that are imported by your aidl files.
+#
+# TODO(cjhopman): dependents need to rebuild when this target's inputs have changed.
+
+{
+  'variables': {
+    'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)/aidl',
+    'aidl_import_include%': '',
+    'additional_aidl_arguments': [],
+    'additional_aidl_input_paths': [],
+  },
+  'direct_dependent_settings': {
+    'variables': {
+      'generated_src_dirs': ['<(intermediate_dir)/'],
+    },
+  },
+  'conditions': [
+    ['aidl_import_include != ""', {
+      'variables': {
+        'additional_aidl_arguments': [ '-I<(aidl_import_include)' ],
+        'additional_aidl_input_paths': [ '<!@(find <(aidl_import_include) -name "*.java" | sort)' ],
+      }
+    }],
+  ],
+  'rules': [
+    {
+      'rule_name': 'compile_aidl',
+      'extension': 'aidl',
+      'inputs': [
+        '<(android_sdk)/framework.aidl',
+        '<(aidl_interface_file)',
+        '<@(additional_aidl_input_paths)',
+      ],
+      'outputs': [
+        '<(intermediate_dir)/<(RULE_INPUT_ROOT).java',
+      ],
+      'action': [
+        '<(android_sdk_tools)/aidl',
+        '-p<(android_sdk)/framework.aidl',
+        '-p<(aidl_interface_file)',
+        '<@(additional_aidl_arguments)',
+        '<(RULE_INPUT_PATH)',
+        '<(intermediate_dir)/<(RULE_INPUT_ROOT).java',
+      ],
+    },
+  ],
+}
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
new file mode 100644
index 0000000..2af3a8a
--- /dev/null
+++ b/build/java_apk.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to build Android APKs in a consistent manner.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_package_apk',
+#   'type': 'none',
+#   'variables': {
+#     'apk_name': 'MyPackage',
+#     'java_in_dir': 'path/to/package/root',
+#     'resource_dir': 'path/to/package/root/res',
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# Required variables:
+#  apk_name - The final apk will be named <apk_name>.apk
+#  java_in_dir - The top-level java directory. The src should be in
+#    <(java_in_dir)/src.
+# Optional/automatic variables:
+#  additional_input_paths - These paths will be included in the 'inputs' list to
+#    ensure that this target is rebuilt when one of these paths changes.
+#  additional_res_packages - Package names of R.java files generated in addition
+#    to the default package name defined in AndroidManifest.xml.
+#  additional_src_dirs - Additional directories with .java files to be compiled
+#    and included in the output of this target.
+#  additional_bundled_libs - Additional libraries what will be stripped and
+#    bundled in the apk.
+#  asset_location - The directory where assets are located.
+#  generated_src_dirs - Same as additional_src_dirs except used for .java files
+#    that are generated at build time. This should be set automatically by a
+#    target's dependencies. The .java files in these directories are not
+#    included in the 'inputs' list (unlike additional_src_dirs).
+#  input_jars_paths - The path to jars to be included in the classpath. This
+#    should be filled automatically by depending on the appropriate targets.
+#  is_test_apk - Set to 1 if building a test apk.  This prevents resources from
+#    dependencies from being re-included.
+#  native_lib_target - The target_name of the target which generates the final
+#    shared library to be included in this apk. A stripped copy of the
+#    library will be included in the apk.
+#  resource_dir - The directory for resources.
+#  shared_resources - Make a resource package that can be loaded by a different
+#    application at runtime to access the package's resources.
+#  R_package - A custom Java package to generate the resource file R.java in.
+#    By default, the package given in AndroidManifest.xml will be used.
+#  use_chromium_linker - Enable the content dynamic linker that allows sharing the
+#    RELRO section of the native libraries between the different processes.
+#  load_library_from_zip_file - When using the dynamic linker, load the library
+#    directly out of the zip file.
+#  use_relocation_packer - Enable relocation packing. Relies on the chromium
+#    linker, so use_chromium_linker must also be enabled.
+#  enable_chromium_linker_tests - Enable the content dynamic linker test support
+#    code. This allows a test APK to inject a Linker.TestRunner instance at
+#    runtime. Should only be used by the chromium_linker_test_apk target!!
+#  never_lint - Set to 1 to not run lint on this target.
+#  java_in_dir_suffix - To override the /src suffix on java_in_dir.
+#  app_manifest_version_name - set the apps 'human readable' version number.
+#  app_manifest_version_code - set the apps version number.
+{
+  'variables': {
+    'tested_apk_obfuscated_jar_path%': '/',
+    'tested_apk_dex_path%': '/',
+    'additional_input_paths': [],
+    'input_jars_paths': [],
+    'library_dexed_jars_paths': [],
+    'additional_src_dirs': [],
+    'generated_src_dirs': [],
+    'app_manifest_version_name%': '<(android_app_version_name)',
+    'app_manifest_version_code%': '<(android_app_version_code)',
+    # aapt generates this proguard.txt.
+    'generated_proguard_file': '<(intermediate_dir)/proguard.txt',
+    'proguard_enabled%': 'false',
+    'proguard_flags_paths': ['<(generated_proguard_file)'],
+    'jar_name': 'chromium_apk_<(_target_name).jar',
+    'resource_dir%':'<(DEPTH)/build/android/ant/empty/res',
+    'R_package%':'',
+    'additional_R_text_files': [],
+    'dependencies_res_zip_paths': [],
+    'additional_res_packages': [],
+    'additional_bundled_libs%': [],
+    'is_test_apk%': 0,
+    'extensions_to_not_compress%': '',
+    'resource_input_paths': [],
+    'intermediate_dir': '<(PRODUCT_DIR)/<(_target_name)',
+    'asset_location%': '<(intermediate_dir)/assets',
+    'codegen_stamp': '<(intermediate_dir)/codegen.stamp',
+    'package_input_paths': [],
+    'ordered_libraries_file': '<(intermediate_dir)/native_libraries.json',
+    'additional_ordered_libraries_file': '<(intermediate_dir)/additional_native_libraries.json',
+    'native_libraries_template': '<(DEPTH)/base/android/java/templates/NativeLibraries.template',
+    'native_libraries_java_dir': '<(intermediate_dir)/native_libraries_java/',
+    'native_libraries_java_file': '<(native_libraries_java_dir)/NativeLibraries.java',
+    'native_libraries_java_stamp': '<(intermediate_dir)/native_libraries_java.stamp',
+    'native_libraries_template_data_dir': '<(intermediate_dir)/native_libraries/',
+    'native_libraries_template_data_file': '<(native_libraries_template_data_dir)/native_libraries_array.h',
+    'native_libraries_template_version_file': '<(native_libraries_template_data_dir)/native_libraries_version.h',
+    'compile_stamp': '<(intermediate_dir)/compile.stamp',
+    'lint_stamp': '<(intermediate_dir)/lint.stamp',
+    'lint_result': '<(intermediate_dir)/lint_result.xml',
+    'lint_config': '<(intermediate_dir)/lint_config.xml',
+    'never_lint%': 0,
+    'findbugs_stamp': '<(intermediate_dir)/findbugs.stamp',
+    'run_findbugs%': 0,
+    'java_in_dir_suffix%': '/src',
+    'instr_stamp': '<(intermediate_dir)/instr.stamp',
+    'jar_stamp': '<(intermediate_dir)/jar.stamp',
+    'obfuscate_stamp': '<(intermediate_dir)/obfuscate.stamp',
+    'pack_arm_relocations_stamp': '<(intermediate_dir)/pack_arm_relocations.stamp',
+    'strip_stamp': '<(intermediate_dir)/strip.stamp',
+    'stripped_libraries_dir': '<(intermediate_dir)/stripped_libraries',
+    'strip_additional_stamp': '<(intermediate_dir)/strip_additional.stamp',
+    'version_stamp': '<(intermediate_dir)/version.stamp',
+    'javac_includes': [],
+    'jar_excluded_classes': [],
+    'javac_jar_path': '<(intermediate_dir)/<(_target_name).javac.jar',
+    'jar_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
+    'obfuscated_jar_path': '<(intermediate_dir)/obfuscated.jar',
+    'test_jar_path': '<(PRODUCT_DIR)/test.lib.java/<(apk_name).jar',
+    'dex_path': '<(intermediate_dir)/classes.dex',
+    'emma_device_jar': '<(android_sdk_root)/tools/lib/emma_device.jar',
+    'android_manifest_path%': '<(java_in_dir)/AndroidManifest.xml',
+    'push_stamp': '<(intermediate_dir)/push.stamp',
+    'link_stamp': '<(intermediate_dir)/link.stamp',
+    'package_resources_stamp': '<(intermediate_dir)/package_resources.stamp',
+    'resource_zip_path': '<(intermediate_dir)/<(_target_name).resources.zip',
+    'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
+    'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+    'shared_resources%': 0,
+    'unsigned_apk_path': '<(intermediate_dir)/<(apk_name)-unsigned.apk',
+    'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk',
+    'incomplete_apk_path': '<(intermediate_dir)/<(apk_name)-incomplete.apk',
+    'apk_install_record': '<(intermediate_dir)/apk_install.record.stamp',
+    'device_intermediate_dir': '/data/data/org.chromium.gyp_managed_install/<(_target_name)/<(CONFIGURATION_NAME)',
+    'symlink_script_host_path': '<(intermediate_dir)/create_symlinks.sh',
+    'symlink_script_device_path': '<(device_intermediate_dir)/create_symlinks.sh',
+    'create_standalone_apk%': 1,
+    'res_v14_verify_only%': 0,
+    'variables': {
+      'variables': {
+        'native_lib_target%': '',
+        'native_lib_version_name%': '',
+        'use_chromium_linker%' : 0,
+        'load_library_from_zip_file%' : 0,
+        'use_relocation_packer%' : 0,
+        'enable_chromium_linker_tests%': 0,
+        'is_test_apk%': 0,
+      },
+      'conditions': [
+        ['gyp_managed_install == 1 and native_lib_target != ""', {
+          'unsigned_standalone_apk_path': '<(intermediate_dir)/<(apk_name)-standalone-unsigned.apk',
+        }, {
+          'unsigned_standalone_apk_path': '<(unsigned_apk_path)',
+        }],
+        ['gyp_managed_install == 1', {
+          'apk_package_native_libs_dir': '<(intermediate_dir)/libs.managed',
+        }, {
+          'apk_package_native_libs_dir': '<(intermediate_dir)/libs',
+        }],
+        ['is_test_apk == 0 and emma_coverage != 0', {
+          'emma_instrument%': 1,
+        },{
+          'emma_instrument%': 0,
+        }],
+      ],
+    },
+    'native_lib_target%': '',
+    'native_lib_version_name%': '',
+    'use_chromium_linker%' : 0,
+    'load_library_from_zip_file%' : 0,
+    'use_relocation_packer%' : 0,
+    'enable_chromium_linker_tests%': 0,
+    'emma_instrument%': '<(emma_instrument)',
+    'apk_package_native_libs_dir': '<(apk_package_native_libs_dir)',
+    'unsigned_standalone_apk_path': '<(unsigned_standalone_apk_path)',
+    'libchromium_android_linker': 'libchromium_android_linker.>(android_product_extension)',
+    'extra_native_libs': [],
+    'native_lib_placeholder_stamp': '<(apk_package_native_libs_dir)/<(android_app_abi)/native_lib_placeholder.stamp',
+    'native_lib_placeholders': [],
+  },
+  # Pass the jar path to the apk's "fake" jar target.  This would be better as
+  # direct_dependent_settings, but a variable set by a direct_dependent_settings
+  # cannot be lifted in a dependent to all_dependent_settings.
+  'all_dependent_settings': {
+    'conditions': [
+      ['proguard_enabled == "true"', {
+        'variables': {
+          'proguard_enabled': 'true',
+        }
+      }],
+    ],
+    'variables': {
+      'apk_output_jar_path': '<(jar_path)',
+      'tested_apk_obfuscated_jar_path': '<(obfuscated_jar_path)',
+      'tested_apk_dex_path': '<(dex_path)',
+    },
+  },
+  'conditions': [
+    ['resource_dir!=""', {
+      'variables': {
+        'resource_input_paths': [ '<!@(find <(resource_dir) -name "*")' ]
+      },
+    }],
+    ['R_package != ""', {
+      'variables': {
+        # We generate R.java in package R_package (in addition to the package
+        # listed in the AndroidManifest.xml, which is unavoidable).
+        'additional_res_packages': ['<(R_package)'],
+        'additional_R_text_files': ['<(intermediate_dir)/R.txt'],
+      },
+    }],
+    ['native_lib_target != "" and component == "shared_library"', {
+      'dependencies': [
+        '<(DEPTH)/build/android/setup.gyp:copy_system_libraries',
+      ],
+    }],
+    ['use_chromium_linker == 1', {
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:chromium_android_linker',
+      ],
+    }],
+    ['native_lib_target != ""', {
+      'variables': {
+        'conditions': [
+          ['use_chromium_linker == 1', {
+            'variables': {
+              'chromium_linker_path': [
+                '<(SHARED_LIB_DIR)/<(libchromium_android_linker)',
+              ],
+            }
+          }, {
+            'variables': {
+              'chromium_linker_path': [],
+            },
+          }],
+        ],
+        'generated_src_dirs': [ '<(native_libraries_java_dir)' ],
+        'native_libs_paths': [
+          '<(SHARED_LIB_DIR)/<(native_lib_target).>(android_product_extension)',
+          '<@(chromium_linker_path)'
+        ],
+        'package_input_paths': [
+          '<(apk_package_native_libs_dir)/<(android_app_abi)/gdbserver',
+        ],
+      },
+      'copies': [
+        {
+          # gdbserver is always copied into the APK's native libs dir. The ant
+          # build scripts (apkbuilder task) will only include it in a debug
+          # build.
+          'destination': '<(apk_package_native_libs_dir)/<(android_app_abi)',
+          'files': [
+            '<(android_gdbserver)',
+          ],
+        },
+      ],
+      'actions': [
+        {
+          'variables': {
+            'input_libraries': [
+              '<@(native_libs_paths)',
+              '<@(extra_native_libs)',
+            ],
+          },
+          'includes': ['../build/android/write_ordered_libraries.gypi'],
+        },
+        {
+          'action_name': 'native_libraries_<(_target_name)',
+          'variables': {
+            'conditions': [
+              ['use_chromium_linker == 1', {
+                'variables': {
+                  'linker_gcc_preprocess_defines': [
+                    '--defines', 'ENABLE_CHROMIUM_LINKER',
+                  ],
+                }
+              }, {
+                'variables': {
+                  'linker_gcc_preprocess_defines': [],
+                },
+              }],
+              ['load_library_from_zip_file == 1', {
+                'variables': {
+                  'linker_load_from_zip_file_preprocess_defines': [
+                    '--defines', 'ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE',
+                  ],
+                }
+              }, {
+                'variables': {
+                  'linker_load_from_zip_file_preprocess_defines': [],
+                },
+              }],
+              ['enable_chromium_linker_tests == 1', {
+                'variables': {
+                  'linker_tests_gcc_preprocess_defines': [
+                    '--defines', 'ENABLE_CHROMIUM_LINKER_TESTS',
+                  ],
+                }
+              }, {
+                'variables': {
+                  'linker_tests_gcc_preprocess_defines': [],
+                },
+              }],
+            ],
+            'gcc_preprocess_defines': [
+              '<@(linker_load_from_zip_file_preprocess_defines)',
+              '<@(linker_gcc_preprocess_defines)',
+              '<@(linker_tests_gcc_preprocess_defines)',
+            ],
+          },
+          'message': 'Creating NativeLibraries.java for <(_target_name)',
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/gcc_preprocess.py',
+            '<(ordered_libraries_file)',
+            '<(native_libraries_template)',
+          ],
+          'outputs': [
+            '<(native_libraries_java_stamp)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/gcc_preprocess.py',
+            '--include-path=',
+            '--output=<(native_libraries_java_file)',
+            '--template=<(native_libraries_template)',
+            '--stamp=<(native_libraries_java_stamp)',
+            '--defines', 'NATIVE_LIBRARIES_LIST=@FileArg(<(ordered_libraries_file):java_libraries_list)',
+            '--defines', 'NATIVE_LIBRARIES_VERSION_NUMBER="<(native_lib_version_name)"',
+            '<@(gcc_preprocess_defines)',
+          ],
+        },
+        {
+          'action_name': 'strip_native_libraries',
+          'variables': {
+            'ordered_libraries_file%': '<(ordered_libraries_file)',
+            'stripped_libraries_dir%': '<(stripped_libraries_dir)',
+            'input_paths': [
+              '<@(native_libs_paths)',
+              '<@(extra_native_libs)',
+            ],
+            'stamp': '<(strip_stamp)'
+          },
+          'includes': ['../build/android/strip_native_libraries.gypi'],
+        },
+        {
+          'action_name': 'insert_chromium_version',
+          'variables': {
+            'ordered_libraries_file%': '<(ordered_libraries_file)',
+            'stripped_libraries_dir%': '<(stripped_libraries_dir)',
+            'version_string': '<(native_lib_version_name)',
+            'input_paths': [
+              '<(strip_stamp)',
+            ],
+            'stamp': '<(version_stamp)'
+          },
+          'includes': ['../build/android/insert_chromium_version.gypi'],
+        },
+        {
+          'action_name': 'pack_arm_relocations',
+          'variables': {
+            'conditions': [
+              ['use_chromium_linker == 1 and use_relocation_packer == 1 and profiling != 1', {
+                'enable_packing': 1,
+              }, {
+                'enable_packing': 0,
+              }],
+            ],
+            'exclude_packing_list': [
+              '<(libchromium_android_linker)',
+            ],
+            'ordered_libraries_file%': '<(ordered_libraries_file)',
+            'stripped_libraries_dir%': '<(stripped_libraries_dir)',
+            'packed_libraries_dir': '<(libraries_source_dir)',
+            'input_paths': [
+              '<(version_stamp)'
+            ],
+            'stamp': '<(pack_arm_relocations_stamp)',
+          },
+          'includes': ['../build/android/pack_arm_relocations.gypi'],
+        },
+        {
+          'variables': {
+            'input_libraries': [
+              '<@(additional_bundled_libs)',
+            ],
+            'ordered_libraries_file': '<(additional_ordered_libraries_file)',
+            'subtarget': '_additional_libraries',
+          },
+          'includes': ['../build/android/write_ordered_libraries.gypi'],
+        },
+        {
+          'action_name': 'strip_additional_libraries',
+          'variables': {
+            'ordered_libraries_file': '<(additional_ordered_libraries_file)',
+            'stripped_libraries_dir': '<(libraries_source_dir)',
+            'input_paths': [
+              '<@(additional_bundled_libs)',
+              '<(strip_stamp)',
+            ],
+            'stamp': '<(strip_additional_stamp)'
+          },
+          'includes': ['../build/android/strip_native_libraries.gypi'],
+        },
+        {
+          'action_name': 'Create native lib placeholder files for previous releases',
+          'variables': {
+            'placeholders': ['<@(native_lib_placeholders)'],
+            'conditions': [
+              ['gyp_managed_install == 1', {
+                # This "library" just needs to be put in the .apk. It is not loaded
+                # at runtime.
+                'placeholders': ['libfix.crbug.384638.so'],
+              }]
+            ],
+          },
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/create_placeholder_files.py',
+          ],
+          'outputs': [
+            '<(native_lib_placeholder_stamp)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/create_placeholder_files.py',
+            '--dest-lib-dir=<(apk_package_native_libs_dir)/<(android_app_abi)/',
+            '--stamp=<(native_lib_placeholder_stamp)',
+            '<@(placeholders)',
+          ],
+        },
+      ],
+      'conditions': [
+        ['gyp_managed_install == 1', {
+          'variables': {
+            'libraries_top_dir': '<(intermediate_dir)/lib.stripped',
+            'libraries_source_dir': '<(libraries_top_dir)/lib/<(android_app_abi)',
+            'device_library_dir': '<(device_intermediate_dir)/lib.stripped',
+            'configuration_name': '<(CONFIGURATION_NAME)',
+          },
+          'dependencies': [
+            '<(DEPTH)/build/android/setup.gyp:get_build_device_configurations',
+            '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
+          ],
+          'actions': [
+            {
+              'includes': ['../build/android/push_libraries.gypi'],
+            },
+            {
+              'action_name': 'create device library symlinks',
+              'message': 'Creating links on device for <(_target_name)',
+              'inputs': [
+                '<(DEPTH)/build/android/gyp/util/build_utils.py',
+                '<(DEPTH)/build/android/gyp/create_device_library_links.py',
+                '<(apk_install_record)',
+                '<(build_device_config_path)',
+                '<(ordered_libraries_file)',
+              ],
+              'outputs': [
+                '<(link_stamp)'
+              ],
+              'action': [
+                'python', '<(DEPTH)/build/android/gyp/create_device_library_links.py',
+                '--build-device-configuration=<(build_device_config_path)',
+                '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
+                '--script-host-path=<(symlink_script_host_path)',
+                '--script-device-path=<(symlink_script_device_path)',
+                '--target-dir=<(device_library_dir)',
+                '--apk=<(incomplete_apk_path)',
+                '--stamp=<(link_stamp)',
+                '--configuration-name=<(CONFIGURATION_NAME)',
+              ],
+            },
+          ],
+          'conditions': [
+            ['create_standalone_apk == 1', {
+              'actions': [
+                {
+                  'action_name': 'create standalone APK',
+                  'variables': {
+                    'inputs': [
+                      '<(ordered_libraries_file)',
+                      '<(strip_additional_stamp)',
+                      '<(pack_arm_relocations_stamp)',
+                    ],
+                    'input_apk_path': '<(unsigned_apk_path)',
+                    'output_apk_path': '<(unsigned_standalone_apk_path)',
+                    'libraries_top_dir%': '<(libraries_top_dir)',
+                  },
+                  'includes': [ 'android/create_standalone_apk_action.gypi' ],
+                },
+              ],
+            }],
+          ],
+        }, {
+          # gyp_managed_install != 1
+          'variables': {
+            'libraries_source_dir': '<(apk_package_native_libs_dir)/<(android_app_abi)',
+            'package_input_paths': [
+              '<(strip_additional_stamp)',
+              '<(pack_arm_relocations_stamp)',
+            ],
+          },
+        }],
+      ],
+    }], # native_lib_target != ''
+    ['gyp_managed_install == 0 or create_standalone_apk == 1', {
+      'actions': [
+        {
+          'action_name': 'finalize standalone apk',
+          'variables': {
+            'input_apk_path': '<(unsigned_standalone_apk_path)',
+            'output_apk_path': '<(final_apk_path)',
+          },
+          'includes': [ 'android/finalize_apk_action.gypi']
+        },
+      ],
+      'dependencies': [
+        '<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
+      ],
+    }],
+    ['gyp_managed_install == 1', {
+      'actions': [
+        {
+          'action_name': 'finalize incomplete apk',
+          'variables': {
+            'input_apk_path': '<(unsigned_apk_path)',
+            'output_apk_path': '<(incomplete_apk_path)',
+          },
+          'includes': [ 'android/finalize_apk_action.gypi']
+        },
+        {
+          'action_name': 'apk_install_<(_target_name)',
+          'message': 'Installing <(apk_name).apk',
+          'inputs': [
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/apk_install.py',
+            '<(build_device_config_path)',
+            '<(incomplete_apk_path)',
+          ],
+          'outputs': [
+            '<(apk_install_record)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/apk_install.py',
+            '--apk-path=<(incomplete_apk_path)',
+            '--build-device-configuration=<(build_device_config_path)',
+            '--install-record=<(apk_install_record)',
+            '--configuration-name=<(CONFIGURATION_NAME)',
+          ],
+        },
+      ],
+      'dependencies': [
+        '<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
+      ],
+    }],
+    ['is_test_apk == 1', {
+      'dependencies': [
+        '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
+        '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
+      ]
+    }],
+    ['run_findbugs == 1', {
+      'actions': [
+        {
+          'action_name': 'findbugs_<(_target_name)',
+          'message': 'Running findbugs on <(_target_name)',
+          'inputs': [
+            '<(DEPTH)/build/android/findbugs_diff.py',
+            '<(DEPTH)/build/android/findbugs_filter/findbugs_exclude.xml',
+            '<(DEPTH)/build/android/pylib/utils/findbugs.py',
+            '>@(input_jars_paths)',
+            '<(jar_path)',
+            '<(compile_stamp)',
+          ],
+          'outputs': [
+            '<(findbugs_stamp)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/findbugs_diff.py',
+            '--auxclasspath-gyp', '>(input_jars_paths)',
+            '--stamp', '<(findbugs_stamp)',
+            '<(jar_path)',
+          ],
+        },
+      ],
+    },
+    ]
+  ],
+  'dependencies': [
+    '<(DEPTH)/tools/android/md5sum/md5sum.gyp:md5sum',
+  ],
+  'actions': [
+    {
+      'action_name': 'process_resources',
+      'message': 'processing resources for <(_target_name)',
+      'variables': {
+        # Write the inputs list to a file, so that its mtime is updated when
+        # the list of inputs changes.
+        'inputs_list_file': '>|(apk_codegen.<(_target_name).gypcmd >@(additional_input_paths) >@(resource_input_paths))',
+        'process_resources_options': [],
+        'conditions': [
+          ['is_test_apk == 1', {
+            'dependencies_res_zip_paths=': [],
+            'additional_res_packages=': [],
+          }],
+          ['res_v14_verify_only == 1', {
+            'process_resources_options+': ['--v14-verify-only']
+          }],
+          ['shared_resources == 1', {
+            'process_resources_options+': ['--shared-resources']
+          }],
+        ],
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/process_resources.py',
+        '<(android_manifest_path)',
+        '>@(additional_input_paths)',
+        '>@(resource_input_paths)',
+        '>@(dependencies_res_zip_paths)',
+        '>(inputs_list_file)',
+      ],
+      'outputs': [
+        '<(resource_zip_path)',
+        '<(generated_proguard_file)',
+        '<(codegen_stamp)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/process_resources.py',
+        '--android-sdk', '<(android_sdk)',
+        '--android-sdk-tools', '<(android_sdk_tools)',
+
+        '--android-manifest', '<(android_manifest_path)',
+        '--dependencies-res-zips', '>(dependencies_res_zip_paths)',
+
+        '--extra-res-packages', '>(additional_res_packages)',
+        '--extra-r-text-files', '>(additional_R_text_files)',
+
+        '--proguard-file', '<(generated_proguard_file)',
+
+        '--resource-dirs', '<(resource_dir)',
+        '--resource-zip-out', '<(resource_zip_path)',
+
+        '--R-dir', '<(intermediate_dir)/gen',
+
+        '--stamp', '<(codegen_stamp)',
+
+        '<@(process_resources_options)',
+      ],
+    },
+    {
+      'action_name': 'javac_<(_target_name)',
+      'message': 'Compiling java for <(_target_name)',
+      'variables': {
+        'gen_src_dirs': [
+          '<(intermediate_dir)/gen',
+          '>@(generated_src_dirs)',
+        ],
+        # If there is a separate find for additional_src_dirs, it will find the
+        # wrong .java files when additional_src_dirs is empty.
+        # TODO(thakis): Gyp caches >! evaluation by command. Both java.gypi and
+        # java_apk.gypi evaluate the same command, and at the moment two targets
+        # set java_in_dir to "java". Add a dummy comment here to make sure
+        # that the two targets (one uses java.gypi, the other java_apk.gypi)
+        # get distinct source lists. Medium-term, make targets list all their
+        # Java files instead of using find. (As is, this will be broken if two
+        # targets use the same java_in_dir and both use java_apk.gypi or
+        # both use java.gypi.)
+        'java_sources': ['>!@(find >(java_in_dir)>(java_in_dir_suffix) >(additional_src_dirs) -name "*.java"  # apk)'],
+
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/javac.py',
+        '>@(java_sources)',
+        '>@(input_jars_paths)',
+        '<(codegen_stamp)',
+      ],
+      'conditions': [
+        ['native_lib_target != ""', {
+          'inputs': [ '<(native_libraries_java_stamp)' ],
+        }],
+      ],
+      'outputs': [
+        '<(compile_stamp)',
+        '<(javac_jar_path)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/javac.py',
+        '--classpath=>(input_jars_paths) <(android_sdk_jar)',
+        '--src-gendirs=>(gen_src_dirs)',
+        '--javac-includes=<(javac_includes)',
+        '--chromium-code=<(chromium_code)',
+        '--jar-path=<(javac_jar_path)',
+        '--jar-excluded-classes=<(jar_excluded_classes)',
+        '--stamp=<(compile_stamp)',
+        '>@(java_sources)',
+      ],
+    },
+    {
+      'action_name': 'instr_jar_<(_target_name)',
+      'message': 'Instrumenting <(_target_name) jar',
+      'variables': {
+        'input_path': '<(javac_jar_path)',
+        'output_path': '<(jar_path)',
+        'stamp_path': '<(instr_stamp)',
+        'instr_type': 'jar',
+      },
+      'outputs': [
+        '<(instr_stamp)',
+        '<(jar_path)',
+      ],
+      'inputs': [
+        '<(javac_jar_path)',
+      ],
+      'includes': [ 'android/instr_action.gypi' ],
+    },
+    {
+      'variables': {
+        'src_dirs': [
+          '<(java_in_dir)<(java_in_dir_suffix)',
+          '>@(additional_src_dirs)',
+        ],
+        'lint_jar_path': '<(jar_path)',
+        'stamp_path': '<(lint_stamp)',
+        'result_path': '<(lint_result)',
+        'config_path': '<(lint_config)',
+      },
+      'outputs': [
+        '<(lint_stamp)',
+      ],
+      'includes': [ 'android/lint_action.gypi' ],
+    },
+    {
+      'action_name': 'obfuscate_<(_target_name)',
+      'message': 'Obfuscating <(_target_name)',
+      'variables': {
+        'additional_obfuscate_options': [],
+        'additional_obfuscate_input_paths': [],
+        'proguard_out_dir': '<(intermediate_dir)/proguard',
+        'proguard_input_jar_paths': [
+          '>@(input_jars_paths)',
+          '<(jar_path)',
+        ],
+        'target_conditions': [
+          ['is_test_apk == 1', {
+            'additional_obfuscate_options': [
+              '--testapp',
+            ],
+          }],
+          ['is_test_apk == 1 and tested_apk_obfuscated_jar_path != "/"', {
+            'additional_obfuscate_options': [
+              '--tested-apk-obfuscated-jar-path', '>(tested_apk_obfuscated_jar_path)',
+            ],
+            'additional_obfuscate_input_paths': [
+              '>(tested_apk_obfuscated_jar_path).info',
+            ],
+          }],
+          ['proguard_enabled == "true"', {
+            'additional_obfuscate_options': [
+              '--proguard-enabled',
+            ],
+          }],
+        ],
+        'obfuscate_input_jars_paths': [
+          '>@(input_jars_paths)',
+          '<(jar_path)',
+        ],
+      },
+      'conditions': [
+        ['is_test_apk == 1', {
+          'outputs': [
+            '<(test_jar_path)',
+          ],
+        }],
+      ],
+      'inputs': [
+        '<(DEPTH)/build/android/gyp/apk_obfuscate.py',
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '>@(proguard_flags_paths)',
+        '>@(obfuscate_input_jars_paths)',
+        '>@(additional_obfuscate_input_paths)',
+        '<(instr_stamp)',
+      ],
+      'outputs': [
+        '<(obfuscate_stamp)',
+
+        # In non-Release builds, these paths will all be empty files.
+        '<(obfuscated_jar_path)',
+        '<(obfuscated_jar_path).info',
+        '<(obfuscated_jar_path).dump',
+        '<(obfuscated_jar_path).seeds',
+        '<(obfuscated_jar_path).mapping',
+        '<(obfuscated_jar_path).usage',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/apk_obfuscate.py',
+
+        '--configuration-name', '<(CONFIGURATION_NAME)',
+
+        '--android-sdk', '<(android_sdk)',
+        '--android-sdk-tools', '<(android_sdk_tools)',
+        '--android-sdk-jar', '<(android_sdk_jar)',
+
+        '--input-jars-paths=>(proguard_input_jar_paths)',
+        '--proguard-configs=>(proguard_flags_paths)',
+
+        '--test-jar-path', '<(test_jar_path)',
+        '--obfuscated-jar-path', '<(obfuscated_jar_path)',
+
+        '--proguard-jar-path', '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+
+        '--stamp', '<(obfuscate_stamp)',
+
+        '>@(additional_obfuscate_options)',
+      ],
+    },
+    {
+      'action_name': 'dex_<(_target_name)',
+      'variables': {
+        'dex_input_paths': [
+          '>@(library_dexed_jars_paths)',
+          '<(jar_path)',
+        ],
+        'output_path': '<(dex_path)',
+        'proguard_enabled_input_path': '<(obfuscated_jar_path)',
+      },
+      'target_conditions': [
+        ['emma_instrument != 0', {
+          'variables': {
+            'dex_no_locals': 1,
+            'dex_input_paths': [
+              '<(emma_device_jar)'
+            ],
+          },
+        }],
+        ['is_test_apk == 1 and tested_apk_dex_path != "/"', {
+          'variables': {
+            'dex_additional_options': [
+              '--excluded-paths', '@FileArg(>(tested_apk_dex_path).inputs)'
+            ],
+          },
+          'inputs': [
+            '>(tested_apk_dex_path).inputs',
+          ],
+        }],
+        ['proguard_enabled == "true"', {
+          'inputs': [ '<(obfuscate_stamp)' ]
+        }, {
+          'inputs': [ '<(instr_stamp)' ]
+        }],
+      ],
+      'includes': [ 'android/dex_action.gypi' ],
+    },
+    {
+      'action_name': 'package_resources',
+      'message': 'packaging resources for <(_target_name)',
+      'variables': {
+        'package_resources_options': [],
+        'package_resource_zip_input_paths': [
+          '<(resource_zip_path)',
+          '>@(dependencies_res_zip_paths)',
+        ],
+        'conditions': [
+          ['shared_resources == 1', {
+            'package_resources_options+': ['--shared-resources']
+          }],
+        ],
+      },
+      'conditions': [
+        ['is_test_apk == 1', {
+          'variables': {
+            'dependencies_res_zip_paths=': [],
+            'additional_res_packages=': [],
+          }
+        }],
+      ],
+      'inputs': [
+        # TODO: This isn't always rerun correctly, http://crbug.com/351928
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/package_resources.py',
+        '<(android_manifest_path)',
+
+        '>@(package_resource_zip_input_paths)',
+
+        '<(codegen_stamp)',
+      ],
+      'outputs': [
+        '<(resource_packaged_apk_path)',
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/package_resources.py',
+        '--android-sdk', '<(android_sdk)',
+        '--android-sdk-tools', '<(android_sdk_tools)',
+
+        '--configuration-name', '<(CONFIGURATION_NAME)',
+
+        '--android-manifest', '<(android_manifest_path)',
+        '--version-code', '<(app_manifest_version_code)',
+        '--version-name', '<(app_manifest_version_name)',
+
+        '--asset-dir', '<(asset_location)',
+        '--resource-zips', '>(package_resource_zip_input_paths)',
+
+        '--no-compress', '<(extensions_to_not_compress)',
+
+        '--apk-path', '<(resource_packaged_apk_path)',
+
+        '<@(package_resources_options)',
+      ],
+    },
+    {
+      'action_name': 'ant_package_<(_target_name)',
+      'message': 'Packaging <(_target_name)',
+      'variables': {
+        # Write the inputs list to a file, so that its mtime is updated when
+        # the list of inputs changes.
+        'inputs_list_file': '>|(apk_package.<(_target_name).gypcmd >@(package_input_paths))'
+      },
+      'inputs': [
+        '<(DEPTH)/build/android/ant/apk-package.xml',
+        '<(DEPTH)/build/android/gyp/util/build_utils.py',
+        '<(DEPTH)/build/android/gyp/ant.py',
+        '<(dex_path)',
+        '<(codegen_stamp)',
+        '<(obfuscate_stamp)',
+        '<(resource_packaged_apk_path)',
+        '>@(package_input_paths)',
+        '>(inputs_list_file)',
+      ],
+      'outputs': [
+        '<(unsigned_apk_path)',
+      ],
+      'conditions': [
+        ['native_lib_target != ""', {
+          'inputs': ['<(native_lib_placeholder_stamp)'],
+        }],
+      ],
+      'action': [
+        'python', '<(DEPTH)/build/android/gyp/ant.py',
+        '--',
+        '-quiet',
+        '-DDEX_FILE_PATH=<(intermediate_dir)/classes.dex',
+        '-DANDROID_SDK_ROOT=<(android_sdk_root)',
+        '-DANDROID_SDK_TOOLS=<(android_sdk_tools)',
+        '-DRESOURCE_PACKAGED_APK_NAME=<(resource_packaged_apk_name)',
+        '-DAPK_NAME=<(apk_name)',
+        '-DCONFIGURATION_NAME=<(CONFIGURATION_NAME)',
+        '-DNATIVE_LIBS_DIR=<(apk_package_native_libs_dir)',
+        '-DOUT_DIR=<(intermediate_dir)',
+        '-DUNSIGNED_APK_PATH=<(unsigned_apk_path)',
+        '-DEMMA_INSTRUMENT=<(emma_instrument)',
+        '-DEMMA_DEVICE_JAR=<(emma_device_jar)',
+
+        '-Dbasedir=.',
+        '-buildfile',
+        '<(DEPTH)/build/android/ant/apk-package.xml',
+      ]
+    },
+  ],
+}
diff --git a/build/java_prebuilt.gypi b/build/java_prebuilt.gypi
new file mode 100644
index 0000000..8efc4ef
--- /dev/null
+++ b/build/java_prebuilt.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to package prebuilt Java JARs in a consistent manner.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my-package_java',
+#   'type': 'none',
+#   'variables': {
+#     'jar_path': 'path/to/your.jar',
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# Required variables:
+#  jar_path - The path to the prebuilt Java JAR file.
+
+{
+  'dependencies': [
+    '<(DEPTH)/build/android/setup.gyp:build_output_dirs'
+  ],
+  'variables': {
+    'dex_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).dex.jar',
+    'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
+    'android_jar': '<(android_sdk)/android.jar',
+    'input_jars_paths': [ '<(android_jar)' ],
+    'neverlink%': 0,
+    'proguard_config%': '',
+    'proguard_preprocess%': '0',
+    'variables': {
+      'variables': {
+        'proguard_preprocess%': 0,
+      },
+      'conditions': [
+        ['proguard_preprocess == 1', {
+          'dex_input_jar_path': '<(intermediate_dir)/<(_target_name).pre.jar'
+        }, {
+          'dex_input_jar_path': '<(jar_path)'
+        }],
+      ],
+    },
+    'dex_input_jar_path': '<(dex_input_jar_path)',
+  },
+  'all_dependent_settings': {
+    'variables': {
+      'input_jars_paths': ['<(dex_input_jar_path)'],
+      'conditions': [
+        ['neverlink == 1', {
+          'library_dexed_jars_paths': [],
+        }, {
+          'library_dexed_jars_paths': ['<(dex_path)'],
+        }],
+      ],
+    },
+  },
+  'conditions' : [
+    ['proguard_preprocess == 1', {
+      'actions': [
+        {
+          'action_name': 'proguard_<(_target_name)',
+          'message': 'Proguard preprocessing <(_target_name) jar',
+          'inputs': [
+            '<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/proguard.py',
+            '<(jar_path)',
+            '<(proguard_config)',
+          ],
+          'outputs': [
+            '<(dex_input_jar_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/proguard.py',
+            '--proguard-path=<(android_sdk_root)/tools/proguard/lib/proguard.jar',
+            '--input-path=<(jar_path)',
+            '--output-path=<(dex_input_jar_path)',
+            '--proguard-config=<(proguard_config)',
+            '--classpath=>(input_jars_paths)',
+          ]
+        },
+      ],
+    }],
+    ['neverlink == 0', {
+      'actions': [
+        {
+          'action_name': 'dex_<(_target_name)',
+          'message': 'Dexing <(_target_name) jar',
+          'variables': {
+            'dex_input_paths': [
+              '<(dex_input_jar_path)',
+            ],
+            'output_path': '<(dex_path)',
+          },
+          'includes': [ 'android/dex_action.gypi' ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/build/java_strings_grd.gypi b/build/java_strings_grd.gypi
new file mode 100644
index 0000000..7534be5
--- /dev/null
+++ b/build/java_strings_grd.gypi
@@ -0,0 +1,62 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to generate localized strings.xml from a grd file.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my-package_strings_grd',
+#   'type': 'none',
+#   'variables': {
+#     'grd_file': 'path/to/grd/file',
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# Required variables:
+#  grd_file - The path to the grd file to use.
+{
+  'variables': {
+    'res_grit_dir': '<(INTERMEDIATE_DIR)/<(_target_name)/res_grit',
+    'grit_grd_file': '<(grd_file)',
+    'resource_zip_path': '<(PRODUCT_DIR)/res.java/<(_target_name).zip',
+    'grit_additional_defines': ['-E', 'ANDROID_JAVA_TAGGED_ONLY=false'],
+    'grit_out_dir': '<(res_grit_dir)',
+    # resource_ids is unneeded since we don't generate .h headers.
+    'grit_resource_ids': '',
+    'grit_outputs': [
+      '<!@pymod_do_main(grit_info <@(grit_defines) <@(grit_additional_defines) '
+          '--outputs \'<(grit_out_dir)\' '
+          '<(grit_grd_file) -f "<(grit_resource_ids)")',
+          ]
+  },
+  'all_dependent_settings': {
+    'variables': {
+      'additional_input_paths': ['<(resource_zip_path)'],
+      'dependencies_res_zip_paths': ['<(resource_zip_path)'],
+    },
+  },
+  'actions': [
+    {
+      'action_name': 'generate_localized_strings_xml',
+      'includes': ['../build/grit_action.gypi'],
+    },
+    {
+      'action_name': 'create_resources_zip',
+      'inputs': [
+          '<(DEPTH)/build/android/gyp/zip.py',
+          '<@(grit_outputs)',
+      ],
+      'outputs': [
+          '<(resource_zip_path)',
+      ],
+      'action': [
+          'python', '<(DEPTH)/build/android/gyp/zip.py',
+          '--input-dir', '<(res_grit_dir)',
+          '--output', '<(resource_zip_path)',
+      ],
+    }
+  ],
+}
diff --git a/build/jni_generator.gypi b/build/jni_generator.gypi
new file mode 100644
index 0000000..7a9e333
--- /dev/null
+++ b/build/jni_generator.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to generate jni bindings for Java-files in a consistent manner.
+#
+# To use this, create a gyp target with the following form:
+#  {
+#    'target_name': 'base_jni_headers',
+#    'type': 'none',
+#    'sources': [
+#      'android/java/src/org/chromium/base/BuildInfo.java',
+#      ...
+#      ...
+#      'android/java/src/org/chromium/base/SystemMessageHandler.java',
+#    ],
+#    'variables': {
+#      'jni_gen_package': 'base',
+#    },
+#    'includes': [ '../build/jni_generator.gypi' ],
+#  },
+#
+# The generated file name pattern can be seen on the "outputs" section below.
+# (note that RULE_INPUT_ROOT is the basename for the java file).
+#
+# See base/android/jni_generator/jni_generator.py for more info about the
+# format of generating JNI bindings.
+
+{
+  'variables': {
+    'jni_generator': '<(DEPTH)/base/android/jni_generator/jni_generator.py',
+    'jni_generator_jarjar_file%': '',
+    'jni_generator_ptr_type%': 'long',
+    # A comma separated string of include files.
+    'jni_generator_includes%': (
+        'base/android/jni_generator/jni_generator_helper.h'
+    ),
+    'native_exports%': '--native_exports_optional',
+  },
+  'rules': [
+    {
+      'rule_name': 'generate_jni_headers',
+      'extension': 'java',
+      'inputs': [
+        '<(jni_generator)',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)/jni/<(RULE_INPUT_ROOT)_jni.h',
+      ],
+      'action': [
+        '<(jni_generator)',
+        '--input_file',
+        '<(RULE_INPUT_PATH)',
+        '--output_dir',
+        '<(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)/jni',
+        '--includes',
+        '<(jni_generator_includes)',
+        '--optimize_generation',
+        '<(optimize_jni_generation)',
+        '--jarjar',
+        '<(jni_generator_jarjar_file)',
+        '--ptr_type',
+        '<(jni_generator_ptr_type)',
+        '<(native_exports)',
+      ],
+      'message': 'Generating JNI bindings from <(RULE_INPUT_PATH)',
+      'process_outputs_as_sources': 1,
+      'conditions': [
+        ['jni_generator_jarjar_file != ""', {
+          'inputs': [
+            '<(jni_generator_jarjar_file)',
+          ],
+        }]
+      ],
+    },
+  ],
+  'direct_dependent_settings': {
+    'include_dirs': [
+      '<(SHARED_INTERMEDIATE_DIR)/<(jni_gen_package)',
+    ],
+  },
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
+
diff --git a/build/json_schema_api.gni b/build/json_schema_api.gni
new file mode 100644
index 0000000..aa6365b
--- /dev/null
+++ b/build/json_schema_api.gni
@@ -0,0 +1,240 @@
+# Copyright 2014 The Chromium 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 a static library corresponding to the output of schema compiler tools
+# over a set of extensions API schemas (IDL or JSON format.) The library target
+# has implicit hard dependencies on all schema files listed by the invoker and
+# is itself a hard dependency.
+#
+# Invocations of this template may use the following variables:
+#
+# sources [required] A list of schema files to be compiled.
+#
+# root_namespace [required]
+#     A Python string substituion pattern used to generate the C++
+#     namespace for each API. Use %(namespace)s to replace with the API
+#     namespace, like "toplevel::%(namespace)s_api".
+#
+# schema_include_rules [optional]
+#     A list of paths to include when searching for referenced objects,
+#     with the namespace separated by a :.
+#     Example:
+#       [ '/foo/bar:Foo::Bar::%(namespace)s' ]
+#
+# schemas [optional, default = false]
+#   Boolean indicating if the schema files should be generated.
+#
+# bundle [optional, default = false]
+#   Boolean indicating if the schema bundle files should be generated.
+#
+# bundle_registration [optional, default = false]
+#   Boolean indicating if the API registration bundle files should be generated.
+#
+# impl_dir [required if bundle_registration = true, otherwise unused]
+#   The path containing C++ implementations of API functions. This path is
+#   used as the root path when looking for {schema}/{schema}_api.h headers
+#   when generating API registration bundles. Such headers, if found, are
+#   automatically included by the generated code.
+#
+# uncompiled_sources [optional, only used when bundle = true or
+#     bundle_registration = true]
+#   A list of schema files which should not be compiled, but which should still
+#   be processed for API bundle generation.
+#
+# deps [optional]
+#   If any deps are specified they will be inherited by the static library
+#   target.
+#
+# generate_static_library [optional, defaults to false]
+#   Produces a static library instead of a source_set.
+#
+# The generated library target also inherits the visibility and output_name
+# of its invoker.
+
+template("json_schema_api") {
+  assert(defined(invoker.sources),
+         "\"sources\" must be defined for the $target_name template.")
+  assert(defined(invoker.root_namespace),
+         "\"root_namespace\" must be defined for the $target_name template.")
+
+  schemas = defined(invoker.schemas) && invoker.schemas
+  bundle = defined(invoker.bundle) && invoker.bundle
+  bundle_registration =
+      defined(invoker.bundle_registration) && invoker.bundle_registration
+
+  schema_include_rules = ""
+  if (defined(invoker.schema_include_rules)) {
+    schema_include_rules = invoker.schema_include_rules
+  }
+
+  # Keep a copy of the target_name here since it will be trampled
+  # in nested targets.
+  target_visibility = [ ":$target_name" ]
+
+  generated_config_name = target_name + "_generated_config"
+  config(generated_config_name) {
+    include_dirs = [ root_gen_dir ]
+    visibility = target_visibility
+  }
+
+  root_namespace = invoker.root_namespace
+
+  compiler_root = "//tools/json_schema_compiler"
+  compiler_script = "$compiler_root/compiler.py"
+  compiler_sources = [
+    "$compiler_root/cc_generator.py",
+    "$compiler_root/code.py",
+    "$compiler_root/compiler.py",
+    "$compiler_root/cpp_generator.py",
+    "$compiler_root/cpp_type_generator.py",
+    "$compiler_root/cpp_util.py",
+    "$compiler_root/h_generator.py",
+    "$compiler_root/idl_schema.py",
+    "$compiler_root/model.py",
+    "$compiler_root/util_cc_helper.py",
+  ]
+
+  if (schemas) {
+    schema_generator_name = target_name + "_schema_generator"
+    action_foreach(schema_generator_name) {
+      script = compiler_script
+      sources = invoker.sources
+      inputs = compiler_sources
+      outputs = [
+        "$target_gen_dir/{{source_name_part}}.cc",
+        "$target_gen_dir/{{source_name_part}}.h",
+      ]
+      args = [
+        "{{source}}",
+        "--root=" + rebase_path("//", root_build_dir),
+        "--destdir=" + rebase_path(root_gen_dir, root_build_dir),
+        "--namespace=$root_namespace",
+        "--generator=cpp",
+        "--include-rules=$schema_include_rules",
+      ]
+
+      if (defined(invoker.visibility)) {
+        # If visibility is restricted, add our own target to it.
+        visibility = invoker.visibility + target_visibility
+      }
+    }
+  }
+
+  if (bundle) {
+    uncompiled_sources = []
+    if (defined(invoker.uncompiled_sources)) {
+      uncompiled_sources = invoker.uncompiled_sources
+    }
+
+    bundle_generator_schema_name = target_name + "_bundle_generator_schema"
+    action(bundle_generator_schema_name) {
+      script = compiler_script
+      inputs = compiler_sources + invoker.sources + uncompiled_sources
+      outputs = [
+        "$target_gen_dir/generated_schemas.cc",
+        "$target_gen_dir/generated_schemas.h",
+      ]
+      args = [
+               "--root=" + rebase_path("//", root_build_dir),
+               "--destdir=" + rebase_path(root_gen_dir, root_build_dir),
+               "--namespace=$root_namespace",
+               "--generator=cpp-bundle-schema",
+               "--include-rules=$schema_include_rules",
+             ] + rebase_path(invoker.sources, root_build_dir) +
+             rebase_path(uncompiled_sources, root_build_dir)
+    }
+  }
+
+  if (bundle_registration) {
+    uncompiled_sources = []
+    if (defined(invoker.uncompiled_sources)) {
+      uncompiled_sources = invoker.uncompiled_sources
+    }
+
+    assert(defined(invoker.impl_dir),
+           "\"impl_dir\" must be defined for the $target_name template.")
+    impl_dir = invoker.impl_dir
+
+    bundle_generator_registration_name =
+        target_name + "_bundle_generator_registration"
+    action(bundle_generator_registration_name) {
+      script = compiler_script
+      inputs = compiler_sources + invoker.sources + uncompiled_sources
+      outputs = [
+        "$root_gen_dir/$impl_dir/generated_api_registration.cc",
+        "$root_gen_dir/$impl_dir/generated_api_registration.h",
+      ]
+      args = [
+               "--root=" + rebase_path("//", root_build_dir),
+               "--destdir=" + rebase_path(root_gen_dir, root_build_dir),
+               "--namespace=$root_namespace",
+               "--generator=cpp-bundle-registration",
+               "--impl-dir=" + rebase_path(impl_dir, "//"),
+               "--include-rules=$schema_include_rules",
+             ] + rebase_path(invoker.sources, root_build_dir) +
+             rebase_path(uncompiled_sources, root_build_dir)
+    }
+  }
+
+  # Compute the contents of the library/source set.
+  lib_sources = invoker.sources
+  lib_deps = []
+  lib_public_deps = []
+  lib_extra_configs = []
+
+  if (schemas) {
+    lib_sources += get_target_outputs(":$schema_generator_name")
+    lib_public_deps += [ ":$schema_generator_name" ]
+    lib_deps += [ "//tools/json_schema_compiler:generated_api_util" ]
+    lib_extra_configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+  }
+
+  if (bundle) {
+    lib_sources += get_target_outputs(":$bundle_generator_schema_name")
+    lib_deps += [ ":$bundle_generator_schema_name" ]
+  }
+
+  if (bundle_registration) {
+    lib_sources += get_target_outputs(":$bundle_generator_registration_name")
+    lib_deps += [ ":$bundle_generator_registration_name" ]
+  }
+
+  if (defined(invoker.deps)) {
+    lib_deps += invoker.deps
+  }
+
+  # Generate either a static library or a source set.
+  if (defined(invoker.generate_static_library) &&
+      invoker.generate_static_library) {
+    static_library(target_name) {
+      sources = lib_sources
+      deps = lib_deps
+      public_deps = lib_public_deps
+      configs += lib_extra_configs
+      public_configs = [ ":$generated_config_name" ]
+
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
+    }
+  } else {
+    source_set(target_name) {
+      sources = lib_sources
+      deps = lib_deps
+      public_deps = lib_public_deps
+      configs += lib_extra_configs
+      public_configs = [ ":$generated_config_name" ]
+
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
+    }
+  }
+}
diff --git a/build/json_schema_bundle_compile.gypi b/build/json_schema_bundle_compile.gypi
new file mode 100644
index 0000000..a302013
--- /dev/null
+++ b/build/json_schema_bundle_compile.gypi
@@ -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.
+
+{
+  'variables': {
+    # When including this gypi, the following variables must be set:
+    #   schema_files:
+    #     An array of json or idl files that comprise the api model.
+    #   schema_include_rules (optional):
+    #     An array of paths to include when searching for referenced objects,
+    #     with the namespace separated by a :.
+    #     Example:
+    #       [ '/foo/bar:Foo::Bar::%(namespace)s' ]
+    #   cc_dir:
+    #     The directory to put the generated code in.
+    #   root_namespace:
+    #     A Python string substituion pattern used to generate the C++
+    #     namespace for each API. Use %(namespace)s to replace with the API
+    #     namespace, like "toplevel::%(namespace)s_api".
+    #
+    # Functions and namespaces can be excluded by setting "nocompile" to true.
+    # The default root path of API implementation sources is
+    # chrome/browser/extensions/api and can be overridden by setting "impl_dir".
+    'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler',
+    'api_gen': '<(api_gen_dir)/compiler.py',
+    'generator_files': [
+      '<(api_gen_dir)/cc_generator.py',
+      '<(api_gen_dir)/code.py',
+      '<(api_gen_dir)/compiler.py',
+      '<(api_gen_dir)/cpp_bundle_generator.py',
+      '<(api_gen_dir)/cpp_type_generator.py',
+      '<(api_gen_dir)/cpp_util.py',
+      '<(api_gen_dir)/h_generator.py',
+      '<(api_gen_dir)/idl_schema.py',
+      '<(api_gen_dir)/json_schema.py',
+      '<(api_gen_dir)/model.py',
+      '<(api_gen_dir)/util_cc_helper.py',
+    ],
+    'schema_include_rules': [],
+  },
+  'actions': [
+    {
+      'action_name': 'genapi_bundle_schema',
+      'inputs': [
+        '<@(generator_files)',
+        '<@(schema_files)',
+        '<@(non_compiled_schema_files)',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/generated_schemas.h',
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/generated_schemas.cc',
+      ],
+      'action': [
+        'python',
+        '<(api_gen)',
+        '--root=<(DEPTH)',
+        '--destdir=<(SHARED_INTERMEDIATE_DIR)',
+        '--namespace=<(root_namespace)',
+        '--generator=cpp-bundle-schema',
+        '--include-rules=<(schema_include_rules)',
+        '<@(schema_files)',
+        '<@(non_compiled_schema_files)',
+      ],
+      'message': 'Generating C++ API bundle code for schemas',
+      'process_outputs_as_sources': 1,
+      # Avoid running MIDL compiler on IDL input files.
+      'explicit_idl_action': 1,
+    },
+  ],
+  'include_dirs': [
+    '<(SHARED_INTERMEDIATE_DIR)',
+    '<(DEPTH)',
+  ],
+  'direct_dependent_settings': {
+    'include_dirs': [
+      '<(SHARED_INTERMEDIATE_DIR)',
+    ]
+  },
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
diff --git a/build/json_schema_bundle_registration_compile.gypi b/build/json_schema_bundle_registration_compile.gypi
new file mode 100644
index 0000000..8c5af4e
--- /dev/null
+++ b/build/json_schema_bundle_registration_compile.gypi
@@ -0,0 +1,78 @@
+# Copyright 2014 The Chromium 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': {
+    # When including this gypi, the following variables must be set:
+    #   schema_files:
+    #     An array of json or idl files that comprise the api model.
+    #   impl_dir_:
+    #     The root path of API implementations; also used for the
+    #     output location. (N.B. Named as such to prevent gyp from
+    #     expanding it as a relative path.)
+    #   root_namespace:
+    #     A Python string substituion pattern used to generate the C++
+    #     namespace for each API. Use %(namespace)s to replace with the API
+    #     namespace, like "toplevel::%(namespace)s_api".
+    #
+    # Functions and namespaces can be excluded by setting "nocompile" to true.
+    'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler',
+    'api_gen': '<(api_gen_dir)/compiler.py',
+    'generator_files': [
+      '<(api_gen_dir)/cc_generator.py',
+      '<(api_gen_dir)/code.py',
+      '<(api_gen_dir)/compiler.py',
+      '<(api_gen_dir)/cpp_bundle_generator.py',
+      '<(api_gen_dir)/cpp_type_generator.py',
+      '<(api_gen_dir)/cpp_util.py',
+      '<(api_gen_dir)/h_generator.py',
+      '<(api_gen_dir)/idl_schema.py',
+      '<(api_gen_dir)/json_schema.py',
+      '<(api_gen_dir)/model.py',
+      '<(api_gen_dir)/util_cc_helper.py',
+    ],
+  },
+  'actions': [
+    {
+      # GN version: json_schema_api.gni
+      'action_name': 'genapi_bundle_registration',
+      'inputs': [
+        '<@(generator_files)',
+        '<@(schema_files)',
+        '<@(non_compiled_schema_files)',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(impl_dir_)/generated_api_registration.h',
+        '<(SHARED_INTERMEDIATE_DIR)/<(impl_dir_)/generated_api_registration.cc',
+      ],
+      'action': [
+        'python',
+        '<(api_gen)',
+        '--root=<(DEPTH)',
+        '--destdir=<(SHARED_INTERMEDIATE_DIR)',
+        '--namespace=<(root_namespace)',
+        '--generator=cpp-bundle-registration',
+        '--impl-dir=<(impl_dir_)',
+        '<@(schema_files)',
+        '<@(non_compiled_schema_files)',
+      ],
+      'message': 'Generating C++ API bundle code for function registration',
+      'process_outputs_as_sources': 1,
+      # Avoid running MIDL compiler on IDL input files.
+      'explicit_idl_action': 1,
+    },
+  ],
+  'include_dirs': [
+    '<(SHARED_INTERMEDIATE_DIR)',
+    '<(DEPTH)',
+  ],
+  'direct_dependent_settings': {
+    'include_dirs': [
+      '<(SHARED_INTERMEDIATE_DIR)',
+    ]
+  },
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
diff --git a/build/json_schema_compile.gypi b/build/json_schema_compile.gypi
new file mode 100644
index 0000000..6e5727a
--- /dev/null
+++ b/build/json_schema_compile.gypi
@@ -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.
+
+{
+  'variables': {
+    # When including this gypi, the following variables must be set:
+    #   schema_files:
+    #     An array of json or idl files that comprise the api model.
+    #   schema_include_rules (optional):
+    #     An array of paths to include when searching for referenced objects,
+    #     with the namespace separated by a :.
+    #     Example:
+    #       [ '/foo/bar:Foo::Bar::%(namespace)s' ]
+    #   cc_dir:
+    #     The directory to put the generated code in.
+    #   root_namespace:
+    #     A Python string substituion pattern used to generate the C++
+    #     namespace for each API. Use %(namespace)s to replace with the API
+    #     namespace, like "toplevel::%(namespace)s_api".
+    #
+    # Functions and namespaces can be excluded by setting "nocompile" to true.
+    'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler',
+    'api_gen': '<(api_gen_dir)/compiler.py',
+    'schema_include_rules': [],
+  },
+  'rules': [
+    {
+      # GN version: json_schema_api.gni
+      'rule_name': 'genapi',
+      'msvs_external_rule': 1,
+      'extension': 'json',
+      'inputs': [
+        '<(api_gen_dir)/cc_generator.py',
+        '<(api_gen_dir)/code.py',
+        '<(api_gen_dir)/compiler.py',
+        '<(api_gen_dir)/cpp_generator.py',
+        '<(api_gen_dir)/cpp_type_generator.py',
+        '<(api_gen_dir)/cpp_util.py',
+        '<(api_gen_dir)/h_generator.py',
+        '<(api_gen_dir)/json_schema.py',
+        '<(api_gen_dir)/model.py',
+        '<(api_gen_dir)/util.cc',
+        '<(api_gen_dir)/util.h',
+        '<(api_gen_dir)/util_cc_helper.py',
+        # TODO(calamity): uncomment this when gyp on windows behaves like other
+        # platforms. List expansions of filepaths in inputs expand to different
+        # things.
+        # '<@(schema_files)',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).cc',
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).h',
+      ],
+      'action': [
+        'python',
+        '<(api_gen)',
+        '<(RULE_INPUT_PATH)',
+        '--root=<(DEPTH)',
+        '--destdir=<(SHARED_INTERMEDIATE_DIR)',
+        '--namespace=<(root_namespace)',
+        '--generator=cpp',
+        '--include-rules=<(schema_include_rules)'
+      ],
+      'message': 'Generating C++ code from <(RULE_INPUT_PATH) json files',
+      'process_outputs_as_sources': 1,
+    },
+    {
+      'rule_name': 'genapi_idl',
+      'msvs_external_rule': 1,
+      'extension': 'idl',
+      'inputs': [
+        '<(api_gen_dir)/cc_generator.py',
+        '<(api_gen_dir)/code.py',
+        '<(api_gen_dir)/compiler.py',
+        '<(api_gen_dir)/cpp_generator.py',
+        '<(api_gen_dir)/cpp_type_generator.py',
+        '<(api_gen_dir)/cpp_util.py',
+        '<(api_gen_dir)/h_generator.py',
+        '<(api_gen_dir)/idl_schema.py',
+        '<(api_gen_dir)/model.py',
+        '<(api_gen_dir)/util.cc',
+        '<(api_gen_dir)/util.h',
+        '<(api_gen_dir)/util_cc_helper.py',
+        # TODO(calamity): uncomment this when gyp on windows behaves like other
+        # platforms. List expansions of filepaths in inputs expand to different
+        # things.
+        # '<@(schema_files)',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).cc',
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).h',
+      ],
+      'action': [
+        'python',
+        '<(api_gen)',
+        '<(RULE_INPUT_PATH)',
+        '--root=<(DEPTH)',
+        '--destdir=<(SHARED_INTERMEDIATE_DIR)',
+        '--namespace=<(root_namespace)',
+        '--generator=cpp',
+        '--include-rules=<(schema_include_rules)'
+      ],
+      'message': 'Generating C++ code from <(RULE_INPUT_PATH) IDL files',
+      'process_outputs_as_sources': 1,
+    },
+  ],
+  'include_dirs': [
+    '<(SHARED_INTERMEDIATE_DIR)',
+    '<(DEPTH)',
+  ],
+  'dependencies':[
+    '<(DEPTH)/tools/json_schema_compiler/api_gen_util.gyp:api_gen_util',
+  ],
+  'direct_dependent_settings': {
+    'include_dirs': [
+      '<(SHARED_INTERMEDIATE_DIR)',
+    ]
+  },
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
diff --git a/build/json_to_struct.gypi b/build/json_to_struct.gypi
new file mode 100644
index 0000000..57271c8
--- /dev/null
+++ b/build/json_to_struct.gypi
@@ -0,0 +1,50 @@
+# 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.
+
+{
+  'variables': {
+    # When including this gypi, the following variables must be set:
+    #   schema_file: a json file that comprise the structure model.
+    #   namespace: the C++ namespace that all generated files go under
+    #   cc_dir: path to generated files
+    # Functions and namespaces can be excluded by setting "nocompile" to true.
+    'struct_gen_dir': '<(DEPTH)/tools/json_to_struct',
+    'struct_gen': '<(struct_gen_dir)/json_to_struct.py',
+  },
+  'rules': [
+    {
+      # GN version: //tools/json_to_struct/json_to_struct.gni
+      'rule_name': 'genstaticinit',
+      'extension': 'json',
+      'inputs': [
+        '<(struct_gen_dir)/element_generator.py',
+        '<(struct_gen_dir)/json_to_struct.py',
+        '<(struct_gen_dir)/struct_generator.py',
+        '<(schema_file)',
+      ],
+      'outputs': [
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).cc',
+        '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).h',
+      ],
+      'action': [
+        'python',
+        '<(struct_gen)',
+        '<(RULE_INPUT_PATH)',
+        '--destbase=<(SHARED_INTERMEDIATE_DIR)',
+        '--destdir=<(cc_dir)',
+        '--namespace=<(namespace)',
+        '--schema=<(schema_file)',
+      ],
+      'message': 'Generating C++ static initializers from <(RULE_INPUT_PATH)',
+      'process_outputs_as_sources': 1,
+    },
+  ],
+  'include_dirs': [
+    '<(SHARED_INTERMEDIATE_DIR)',
+    '<(DEPTH)',
+  ],
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
diff --git a/build/landmine_utils.py b/build/landmine_utils.py
new file mode 100644
index 0000000..6d18b6d
--- /dev/null
+++ b/build/landmine_utils.py
@@ -0,0 +1,120 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import functools
+import logging
+import os
+import shlex
+import sys
+
+
+def memoize(default=None):
+  """This decorator caches the return value of a parameterless pure function"""
+  def memoizer(func):
+    val = []
+    @functools.wraps(func)
+    def inner():
+      if not val:
+        ret = func()
+        val.append(ret if ret is not None else default)
+        if logging.getLogger().isEnabledFor(logging.INFO):
+          print '%s -> %r' % (func.__name__, val[0])
+      return val[0]
+    return inner
+  return memoizer
+
+
+@memoize()
+def IsWindows():
+  return sys.platform in ['win32', 'cygwin']
+
+
+@memoize()
+def IsLinux():
+  return sys.platform.startswith(('linux', 'freebsd', 'openbsd'))
+
+
+@memoize()
+def IsMac():
+  return sys.platform == 'darwin'
+
+
+@memoize()
+def gyp_defines():
+  """Parses and returns GYP_DEFINES env var as a dictionary."""
+  return dict(arg.split('=', 1)
+      for arg in shlex.split(os.environ.get('GYP_DEFINES', '')))
+
+@memoize()
+def gyp_generator_flags():
+  """Parses and returns GYP_GENERATOR_FLAGS env var as a dictionary."""
+  return dict(arg.split('=', 1)
+      for arg in shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', '')))
+
+@memoize()
+def gyp_msvs_version():
+  return os.environ.get('GYP_MSVS_VERSION', '')
+
+@memoize()
+def distributor():
+  """
+  Returns a string which is the distributed build engine in use (if any).
+  Possible values: 'goma', 'ib', ''
+  """
+  if 'goma' in gyp_defines():
+    return 'goma'
+  elif IsWindows():
+    if 'CHROME_HEADLESS' in os.environ:
+      return 'ib' # use (win and !goma and headless) as approximation of ib
+
+
+@memoize()
+def platform():
+  """
+  Returns a string representing the platform this build is targetted for.
+  Possible values: 'win', 'mac', 'linux', 'ios', 'android'
+  """
+  if 'OS' in gyp_defines():
+    if 'android' in gyp_defines()['OS']:
+      return 'android'
+    else:
+      return gyp_defines()['OS']
+  elif IsWindows():
+    return 'win'
+  elif IsLinux():
+    return 'linux'
+  else:
+    return 'mac'
+
+
+@memoize()
+def builder():
+  """
+  Returns a string representing the build engine (not compiler) to use.
+  Possible values: 'make', 'ninja', 'xcode', 'msvs', 'scons'
+  """
+  if 'GYP_GENERATORS' in os.environ:
+    # for simplicity, only support the first explicit generator
+    generator = os.environ['GYP_GENERATORS'].split(',')[0]
+    if generator.endswith('-android'):
+      return generator.split('-')[0]
+    elif generator.endswith('-ninja'):
+      return 'ninja'
+    else:
+      return generator
+  else:
+    if platform() == 'android':
+      # Good enough for now? Do any android bots use make?
+      return 'ninja'
+    elif platform() == 'ios':
+      return 'xcode'
+    elif IsWindows():
+      return 'ninja'
+    elif IsLinux():
+      return 'ninja'
+    elif IsMac():
+      return 'ninja'
+    else:
+      assert False, 'Don\'t know what builder we\'re using!'
diff --git a/build/landmines.py b/build/landmines.py
new file mode 100755
index 0000000..97a250a
--- /dev/null
+++ b/build/landmines.py
@@ -0,0 +1,216 @@
+#!/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 runs every build as the first hook (See DEPS). If it detects that
+the build should be clobbered, it will delete the contents of the build
+directory.
+
+A landmine is tripped when a builder checks out a different revision, and the
+diff between the new landmines and the old ones is non-null. At this point, the
+build is clobbered.
+"""
+
+import difflib
+import errno
+import gyp_environment
+import logging
+import optparse
+import os
+import shutil
+import sys
+import subprocess
+import time
+
+import landmine_utils
+
+
+SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+
+
+def get_build_dir(build_tool, is_iphone=False):
+  """
+  Returns output directory absolute path dependent on build and targets.
+  Examples:
+    r'c:\b\build\slave\win\build\src\out'
+    '/mnt/data/b/build/slave/linux/build/src/out'
+    '/b/build/slave/ios_rel_device/build/src/xcodebuild'
+
+  Keep this function in sync with tools/build/scripts/slave/compile.py
+  """
+  ret = None
+  if build_tool == 'xcode':
+    ret = os.path.join(SRC_DIR, 'xcodebuild')
+  elif build_tool in ['make', 'ninja', 'ninja-ios']:  # TODO: Remove ninja-ios.
+    if 'CHROMIUM_OUT_DIR' in os.environ:
+      output_dir = os.environ.get('CHROMIUM_OUT_DIR').strip()
+      if not output_dir:
+        raise Error('CHROMIUM_OUT_DIR environment variable is set but blank!')
+    else:
+      output_dir = landmine_utils.gyp_generator_flags().get('output_dir', 'out')
+    ret = os.path.join(SRC_DIR, output_dir)
+  else:
+    raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool)
+  return os.path.abspath(ret)
+
+
+def extract_gn_build_commands(build_ninja_file):
+  """Extracts from a build.ninja the commands to run GN.
+
+  The commands to run GN are the gn rule and build.ninja build step at the
+  top of the build.ninja file. We want to keep these when deleting GN builds
+  since we want to preserve the command-line flags to GN.
+
+  On error, returns the empty string."""
+  result = ""
+  with open(build_ninja_file, 'r') as f:
+    # Read until the second blank line. The first thing GN writes to the file
+    # is the "rule gn" and the second is the section for "build build.ninja",
+    # separated by blank lines.
+    num_blank_lines = 0
+    while num_blank_lines < 2:
+      line = f.readline()
+      if len(line) == 0:
+        return ''  # Unexpected EOF.
+      result += line
+      if line[0] == '\n':
+        num_blank_lines = num_blank_lines + 1
+  return result
+
+def delete_build_dir(build_dir):
+  # GN writes a build.ninja.d file. Note that not all GN builds have args.gn.
+  build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d')
+  if not os.path.exists(build_ninja_d_file):
+    shutil.rmtree(build_dir)
+    return
+
+  # GN builds aren't automatically regenerated when you sync. To avoid
+  # messing with the GN workflow, erase everything but the args file, and
+  # write a dummy build.ninja file that will automatically rerun GN the next
+  # time Ninja is run.
+  build_ninja_file = os.path.join(build_dir, 'build.ninja')
+  build_commands = extract_gn_build_commands(build_ninja_file)
+
+  try:
+    gn_args_file = os.path.join(build_dir, 'args.gn')
+    with open(gn_args_file, 'r') as f:
+      args_contents = f.read()
+  except IOError:
+    args_contents = ''
+
+  shutil.rmtree(build_dir)
+
+  # Put back the args file (if any).
+  os.mkdir(build_dir)
+  if args_contents != '':
+    with open(gn_args_file, 'w') as f:
+      f.write(args_contents)
+
+  # Write the build.ninja file sufficiently to regenerate itself.
+  with open(os.path.join(build_dir, 'build.ninja'), 'w') as f:
+    if build_commands != '':
+      f.write(build_commands)
+    else:
+      # Couldn't parse the build.ninja file, write a default thing.
+      f.write('''rule gn
+command = gn -q gen //out/%s/
+description = Regenerating ninja files
+
+build build.ninja: gn
+generator = 1
+depfile = build.ninja.d
+''' % (os.path.split(build_dir)[1]))
+
+  # Write a .d file for the build which references a nonexistant file. This
+  # will make Ninja always mark the build as dirty.
+  with open(build_ninja_d_file, 'w') as f:
+    f.write('build.ninja: nonexistant_file.gn\n')
+
+
+def clobber_if_necessary(new_landmines):
+  """Does the work of setting, planting, and triggering landmines."""
+  out_dir = get_build_dir(landmine_utils.builder())
+  landmines_path = os.path.normpath(os.path.join(out_dir, '..', '.landmines'))
+  try:
+    os.makedirs(out_dir)
+  except OSError as e:
+    if e.errno == errno.EEXIST:
+      pass
+
+  if os.path.exists(landmines_path):
+    with open(landmines_path, 'r') as f:
+      old_landmines = f.readlines()
+    if old_landmines != new_landmines:
+      old_date = time.ctime(os.stat(landmines_path).st_ctime)
+      diff = difflib.unified_diff(old_landmines, new_landmines,
+          fromfile='old_landmines', tofile='new_landmines',
+          fromfiledate=old_date, tofiledate=time.ctime(), n=0)
+      sys.stdout.write('Clobbering due to:\n')
+      sys.stdout.writelines(diff)
+
+      # Clobber contents of build directory but not directory itself: some
+      # checkouts have the build directory mounted.
+      for f in os.listdir(out_dir):
+        path = os.path.join(out_dir, f)
+        if os.path.isfile(path):
+          os.unlink(path)
+        elif os.path.isdir(path):
+          delete_build_dir(path)
+
+  # Save current set of landmines for next time.
+  with open(landmines_path, 'w') as f:
+    f.writelines(new_landmines)
+
+
+def process_options():
+  """Returns a list of landmine emitting scripts."""
+  parser = optparse.OptionParser()
+  parser.add_option(
+      '-s', '--landmine-scripts', action='append',
+      default=[os.path.join(SRC_DIR, 'build', 'get_landmines.py')],
+      help='Path to the script which emits landmines to stdout. The target '
+           'is passed to this script via option -t. Note that an extra '
+           'script can be specified via an env var EXTRA_LANDMINES_SCRIPT.')
+  parser.add_option('-v', '--verbose', action='store_true',
+      default=('LANDMINES_VERBOSE' in os.environ),
+      help=('Emit some extra debugging information (default off). This option '
+          'is also enabled by the presence of a LANDMINES_VERBOSE environment '
+          'variable.'))
+
+  options, args = parser.parse_args()
+
+  if args:
+    parser.error('Unknown arguments %s' % args)
+
+  logging.basicConfig(
+      level=logging.DEBUG if options.verbose else logging.ERROR)
+
+  extra_script = os.environ.get('EXTRA_LANDMINES_SCRIPT')
+  if extra_script:
+    return options.landmine_scripts + [extra_script]
+  else:
+    return options.landmine_scripts
+
+
+def main():
+  landmine_scripts = process_options()
+
+  if landmine_utils.builder() in ('dump_dependency_json', 'eclipse'):
+    return 0
+
+  gyp_environment.SetEnvironment()
+
+  landmines = []
+  for s in landmine_scripts:
+    proc = subprocess.Popen([sys.executable, s], stdout=subprocess.PIPE)
+    output, _ = proc.communicate()
+    landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()])
+  clobber_if_necessary(landmines)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/linux/bin/eu-strip.sha1 b/build/linux/bin/eu-strip.sha1
new file mode 100644
index 0000000..43f290a
--- /dev/null
+++ b/build/linux/bin/eu-strip.sha1
@@ -0,0 +1 @@
+0a9b8f68615ce388b65201e6d22da7a9cf2e729c
\ No newline at end of file
diff --git a/build/linux/chrome_linux.croc b/build/linux/chrome_linux.croc
new file mode 100644
index 0000000..f400306
--- /dev/null
+++ b/build/linux/chrome_linux.croc
@@ -0,0 +1,29 @@
+# -*- python -*-
+# Crocodile config file for Chromium linux
+
+# TODO(jhawkins): We'll need to add a chromeos.croc once we get a coverage bot
+# for that platform.
+
+{
+  # List of rules, applied in order
+  'rules' : [
+    # Specify inclusions before exclusions, since rules are in order.
+
+    # Don't include non-Linux platform dirs
+    {
+      'regexp' : '.*/(chromeos|views)/',
+      'include' : 0,
+    },
+    # Don't include chromeos, windows, or mac specific files
+    {
+      'regexp' : '.*(_|/)(chromeos|mac|win|views)(\\.|_)',
+      'include' : 0,
+    },
+
+    # Groups
+    {
+      'regexp' : '.*_test_linux\\.',
+      'group' : 'test',
+    },
+  ],
+}
diff --git a/build/linux/dump_app_syms b/build/linux/dump_app_syms
new file mode 100755
index 0000000..cbeb676
--- /dev/null
+++ b/build/linux/dump_app_syms
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# 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.
+#
+# Helper script to run dump_syms on Chrome Linux executables and strip
+# them if needed.
+
+set -e
+
+usage() {
+  echo -n "$0 <dump_syms_exe> <strip_binary> " >&2
+  echo "<binary_with_symbols> <symbols_output>" >&2
+}
+
+
+if [ $# -ne 4 ]; then
+  usage
+  exit 1
+fi
+
+SCRIPTDIR="$(readlink -f "$(dirname "$0")")"
+DUMPSYMS="$1"
+STRIP_BINARY="$2"
+INFILE="$3"
+OUTFILE="$4"
+
+# Dump the symbols from the given binary.
+if [ ! -e "$OUTFILE" -o "$INFILE" -nt "$OUTFILE" ]; then
+  "$DUMPSYMS" -r "$INFILE" > "$OUTFILE"
+fi
+
+if [ "$STRIP_BINARY" != "0" ]; then
+  strip "$INFILE"
+fi
diff --git a/build/linux/install-chromeos-fonts.py b/build/linux/install-chromeos-fonts.py
new file mode 100755
index 0000000..a24adc9
--- /dev/null
+++ b/build/linux/install-chromeos-fonts.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Script to install the Chrome OS fonts on Linux.
+# This script can be run manually (as root), but is also run as part
+# install-build-deps.sh.
+
+import os
+import shutil
+import subprocess
+import sys
+
+# Taken from the media-fonts/notofonts ebuild in chromiumos-overlay.
+VERSION = '20140815'
+URL = ('https://commondatastorage.googleapis.com/chromeos-localmirror/'
+       'distfiles/notofonts-%s.tar.bz2') % (VERSION)
+FONTS_DIR = '/usr/local/share/fonts'
+
+def main(args):
+  if not sys.platform.startswith('linux'):
+    print "Error: %s must be run on Linux." % __file__
+    return 1
+
+  if os.getuid() != 0:
+    print "Error: %s must be run as root." % __file__
+    return 1
+
+  if not os.path.isdir(FONTS_DIR):
+    print "Error: Destination directory does not exist: %s" % FONTS_DIR
+    return 1
+
+  dest_dir = os.path.join(FONTS_DIR, 'chromeos')
+
+  stamp = os.path.join(dest_dir, ".stamp02")
+  if os.path.exists(stamp):
+    with open(stamp) as s:
+      if s.read() == URL:
+        print "Chrome OS fonts already up-to-date in %s." % dest_dir
+        return 0
+
+  if os.path.isdir(dest_dir):
+    shutil.rmtree(dest_dir)
+  os.mkdir(dest_dir)
+  os.chmod(dest_dir, 0755)
+
+  print "Installing Chrome OS fonts to %s." % dest_dir
+  tarball = os.path.join(dest_dir, os.path.basename(URL))
+  subprocess.check_call(['curl', '-L', URL, '-o', tarball])
+  subprocess.check_call(['tar', '--no-same-owner', '--no-same-permissions',
+                         '-xf', tarball, '-C', dest_dir])
+  os.remove(tarball)
+
+  readme = os.path.join(dest_dir, "README")
+  with open(readme, 'w') as s:
+    s.write("This directory and its contents are auto-generated.\n")
+    s.write("It may be deleted and recreated. Do not modify.\n")
+    s.write("Script: %s\n" % __file__)
+
+  with open(stamp, 'w') as s:
+    s.write(URL)
+
+  for base, dirs, files in os.walk(dest_dir):
+    for dir in dirs:
+      os.chmod(os.path.join(base, dir), 0755)
+    for file in files:
+      os.chmod(os.path.join(base, file), 0644)
+
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/linux/pkg-config-wrapper b/build/linux/pkg-config-wrapper
new file mode 100755
index 0000000..b759564
--- /dev/null
+++ b/build/linux/pkg-config-wrapper
@@ -0,0 +1,59 @@
+#!/bin/bash
+# Copyright (c) 2012 The Chromium 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 program wraps around pkg-config to generate the correct include and
+# library paths when cross-compiling using a sysroot.
+# The assumption is that the sysroot contains the .pc files in usr/lib/pkgconfig
+# and usr/share/pkgconfig (relative to the sysroot) and that they output paths
+# relative to some parent path of the sysroot.
+# This assumption is valid for a range of sysroots, in particular: a
+# LSB-compliant root filesystem mounted at the sysroot, and a board build
+# directory of a Chromium OS chroot.
+# Additional directories containing .pc files may be specified by setting
+# the PKG_CONFIG_PATH environment variable- these will be prepended to the
+# generated paths.
+
+root="$1"
+shift
+target_arch="$1"
+shift
+libpath="$1"
+shift
+
+if [ -z "$root" -o -z "$target_arch" ]
+then
+  echo "usage: $0 /path/to/sysroot target_arch libdir [pkg-config-arguments] package" >&2
+  exit 1
+fi
+
+if [ "$target_arch" = "x64" ]
+then
+  : ${libpath:="lib64"}
+else
+  : ${libpath:="lib"}
+fi
+
+rewrite=`dirname $0`/rewrite_dirs.py
+package=${!#}
+
+config_path=$root/usr/$libpath/pkgconfig:$root/usr/share/pkgconfig
+
+# prepend any paths specified by the environment
+if [ -n "$PKG_CONFIG_PATH" ]
+then
+  config_path="$PKG_CONFIG_PATH:$config_path"
+fi
+
+set -e
+# Some sysroots, like the Chromium OS ones, may generate paths that are not
+# relative to the sysroot. For example,
+# /path/to/chroot/build/x86-generic/usr/lib/pkgconfig/pkg.pc may have all paths
+# relative to /path/to/chroot (i.e. prefix=/build/x86-generic/usr) instead of
+# relative to /path/to/chroot/build/x86-generic (i.e prefix=/usr).
+# To support this correctly, it's necessary to extract the prefix to strip from
+# pkg-config's |prefix| variable.
+prefix=`PKG_CONFIG_PATH=$config_path pkg-config --variable=prefix "$package" | sed -e 's|/usr$||'`
+result=`PKG_CONFIG_PATH=$config_path pkg-config "$@"`
+echo "$result"| $rewrite --sysroot "$root" --strip-prefix "$prefix"
diff --git a/build/linux/rewrite_dirs.py b/build/linux/rewrite_dirs.py
new file mode 100755
index 0000000..30f22f0
--- /dev/null
+++ b/build/linux/rewrite_dirs.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Rewrites paths in -I, -L and other option to be relative to a sysroot."""
+
+import sys
+import os
+import optparse
+
+REWRITE_PREFIX = ['-I',
+                  '-idirafter',
+                  '-imacros',
+                  '-imultilib',
+                  '-include',
+                  '-iprefix',
+                  '-iquote',
+                  '-isystem',
+                  '-L']
+
+def RewritePath(path, opts):
+  """Rewrites a path by stripping the prefix and prepending the sysroot."""
+  sysroot = opts.sysroot
+  prefix = opts.strip_prefix
+  if os.path.isabs(path) and not path.startswith(sysroot):
+    if path.startswith(prefix):
+      path = path[len(prefix):]
+    path = path.lstrip('/')
+    return os.path.join(sysroot, path)
+  else:
+    return path
+
+
+def RewriteLine(line, opts):
+  """Rewrites all the paths in recognized options."""
+  args = line.split()
+  count = len(args)
+  i = 0
+  while i < count:
+    for prefix in REWRITE_PREFIX:
+      # The option can be either in the form "-I /path/to/dir" or
+      # "-I/path/to/dir" so handle both.
+      if args[i] == prefix:
+        i += 1
+        try:
+          args[i] = RewritePath(args[i], opts)
+        except IndexError:
+          sys.stderr.write('Missing argument following %s\n' % prefix)
+          break
+      elif args[i].startswith(prefix):
+        args[i] = prefix + RewritePath(args[i][len(prefix):], opts)
+    i += 1
+
+  return ' '.join(args)
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('-s', '--sysroot', default='/', help='sysroot to prepend')
+  parser.add_option('-p', '--strip-prefix', default='', help='prefix to strip')
+  opts, args = parser.parse_args(argv[1:])
+
+  for line in sys.stdin.readlines():
+    line = RewriteLine(line.strip(), opts)
+    print line
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/linux/sysroot_ld_path.sh b/build/linux/sysroot_ld_path.sh
new file mode 100755
index 0000000..4b8bf73
--- /dev/null
+++ b/build/linux/sysroot_ld_path.sh
@@ -0,0 +1,100 @@
+#!/bin/sh
+# 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.
+
+# Reads etc/ld.so.conf and/or etc/ld.so.conf.d/*.conf and returns the
+# appropriate linker flags.
+#
+#  sysroot_ld_path.sh /abspath/to/sysroot
+#
+
+log_error_and_exit() {
+  echo $0: $@
+  exit 1
+}
+
+process_entry() {
+  if [ -z "$1" ] || [ -z "$2" ]; then
+    log_error_and_exit "bad arguments to process_entry()"
+  fi
+  local root="$1"
+  local localpath="$2"
+
+  echo $localpath | grep -qs '^/'
+  if [ $? -ne 0 ]; then
+    log_error_and_exit $localpath does not start with /
+  fi
+  local entry="$root$localpath"
+  echo -L$entry
+  echo -Wl,-rpath-link=$entry
+}
+
+process_ld_so_conf() {
+  if [ -z "$1" ] || [ -z "$2" ]; then
+    log_error_and_exit "bad arguments to process_ld_so_conf()"
+  fi
+  local root="$1"
+  local ld_so_conf="$2"
+
+  # ld.so.conf may include relative include paths. pushd is a bashism.
+  local saved_pwd=$(pwd)
+  cd $(dirname "$ld_so_conf")
+
+  cat "$ld_so_conf" | \
+    while read ENTRY; do
+      echo "$ENTRY" | grep -qs ^include
+      if [ $? -eq 0 ]; then
+        local included_files=$(echo "$ENTRY" | sed 's/^include //')
+        echo "$included_files" | grep -qs ^/
+        if [ $? -eq 0 ]; then
+          if ls $root$included_files >/dev/null 2>&1 ; then
+            for inc_file in $root$included_files; do
+              process_ld_so_conf "$root" "$inc_file"
+            done
+          fi
+        else
+          if ls $(pwd)/$included_files >/dev/null 2>&1 ; then
+            for inc_file in $(pwd)/$included_files; do
+              process_ld_so_conf "$root" "$inc_file"
+            done
+          fi
+        fi
+        continue
+      fi
+
+      echo "$ENTRY" | grep -qs ^/
+      if [ $? -eq 0 ]; then
+        process_entry "$root" "$ENTRY"
+      fi
+    done
+
+  # popd is a bashism
+  cd "$saved_pwd"
+}
+
+# Main
+
+if [ $# -ne 1 ]; then
+  echo Usage $0 /abspath/to/sysroot
+  exit 1
+fi
+
+echo $1 | grep -qs ' '
+if [ $? -eq 0 ]; then
+  log_error_and_exit $1 contains whitespace.
+fi
+
+LD_SO_CONF="$1/etc/ld.so.conf"
+LD_SO_CONF_D="$1/etc/ld.so.conf.d"
+
+if [ -e "$LD_SO_CONF" ]; then
+  process_ld_so_conf "$1" "$LD_SO_CONF" | xargs echo
+elif [ -e "$LD_SO_CONF_D" ]; then
+  find "$LD_SO_CONF_D" -maxdepth 1 -name '*.conf' -print -quit > /dev/null
+  if [ $? -eq 0 ]; then
+    for entry in $LD_SO_CONF_D/*.conf; do
+      process_ld_so_conf "$1" "$entry"
+    done | xargs echo
+  fi
+fi
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
new file mode 100644
index 0000000..e7cc9dc
--- /dev/null
+++ b/build/linux/system.gyp
@@ -0,0 +1,1233 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'conditions': [
+      ['sysroot!=""', {
+        'pkg-config': '<(chroot_cmd) ./pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
+      }, {
+        'pkg-config': 'pkg-config',
+      }],
+    ],
+
+    # If any of the linux_link_FOO below are set to 1, then the corresponding
+    # target will be linked against the FOO library (either dynamically or
+    # statically, depending on the pkg-config files), as opposed to loading the
+    # FOO library dynamically with dlopen.
+    'linux_link_libgps%': 0,
+    'linux_link_libpci%': 0,
+    'linux_link_libspeechd%': 0,
+    'linux_link_libbrlapi%': 0,
+
+    # Used below for the various libraries. In this scope for sharing with GN.
+    'libbrlapi_functions': [
+      'brlapi_getHandleSize',
+      'brlapi_error_location',
+      'brlapi_strerror',
+      'brlapi__acceptKeys',
+      'brlapi__openConnection',
+      'brlapi__closeConnection',
+      'brlapi__getDisplaySize',
+      'brlapi__enterTtyModeWithPath',
+      'brlapi__leaveTtyMode',
+      'brlapi__writeDots',
+      'brlapi__readKey',
+    ],
+    'libgio_functions': [
+      'g_settings_new',
+      'g_settings_get_child',
+      'g_settings_get_string',
+      'g_settings_get_boolean',
+      'g_settings_get_int',
+      'g_settings_get_strv',
+      'g_settings_list_schemas',
+    ],
+    'libpci_functions': [
+      'pci_alloc',
+      'pci_init',
+      'pci_cleanup',
+      'pci_scan_bus',
+      'pci_fill_info',
+      'pci_lookup_name',
+    ],
+    'libudev_functions': [
+      'udev_device_get_action',
+      'udev_device_get_devnode',
+      'udev_device_get_parent',
+      'udev_device_get_parent_with_subsystem_devtype',
+      'udev_device_get_property_value',
+      'udev_device_get_subsystem',
+      'udev_device_get_sysattr_value',
+      'udev_device_get_sysname',
+      'udev_device_get_syspath',
+      'udev_device_new_from_devnum',
+      'udev_device_new_from_subsystem_sysname',
+      'udev_device_new_from_syspath',
+      'udev_device_unref',
+      'udev_enumerate_add_match_subsystem',
+      'udev_enumerate_get_list_entry',
+      'udev_enumerate_new',
+      'udev_enumerate_scan_devices',
+      'udev_enumerate_unref',
+      'udev_list_entry_get_next',
+      'udev_list_entry_get_name',
+      'udev_monitor_enable_receiving',
+      'udev_monitor_filter_add_match_subsystem_devtype',
+      'udev_monitor_get_fd',
+      'udev_monitor_new_from_netlink',
+      'udev_monitor_receive_device',
+      'udev_monitor_unref',
+      'udev_new',
+      'udev_set_log_fn',
+      'udev_set_log_priority',
+      'udev_unref',
+    ],
+  },
+  'conditions': [
+    [ 'chromeos==0 and use_ozone==0', {
+      # Hide GTK and related dependencies for Chrome OS and Ozone, so they won't get
+      # added back to Chrome OS and Ozone. Don't try to use GTK on Chrome OS and Ozone.
+      'targets': [
+        {
+          'target_name': 'atk',
+          'type': 'none',
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags atk)',
+                ],
+                'defines': [
+                  'ATK_LIB_DIR="<!@(<(pkg-config) --variable=libdir atk)"',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other atk)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l atk)',
+                ],
+              },
+            }],
+          ],
+        },
+        {
+          'target_name': 'gdk',
+          'type': 'none',
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags gdk-2.0)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gdk-2.0)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l gdk-2.0)',
+                ],
+              },
+            }],
+          ],
+        },
+        {
+          'target_name': 'gtk',
+          'type': 'none',
+          'toolsets': ['host', 'target'],
+          'variables': {
+            # gtk requires gmodule, but it does not list it as a dependency
+            # in some misconfigured systems.
+            'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0',
+          },
+          'conditions': [
+            ['_toolset=="target"', {
+              'all_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags <(gtk_packages))',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other <(gtk_packages))',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l <(gtk_packages))',
+                ],
+              },
+            }, {
+              'all_dependent_settings': {
+                'cflags': [
+                  '<!@(pkg-config --cflags <(gtk_packages))',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(pkg-config --libs-only-L --libs-only-other <(gtk_packages))',
+                ],
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l <(gtk_packages))',
+                ],
+              },
+            }],
+          ],
+        },
+        {
+          'target_name': 'gtkprint',
+          'type': 'none',
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags gtk+-unix-print-2.0)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gtk+-unix-print-2.0)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l gtk+-unix-print-2.0)',
+                ],
+              },
+            }],
+          ],
+        },
+      ],  # targets
+    }],
+    [ 'use_x11==1 or ozone_platform_ozonex==1', {
+      # Hide X11 and related dependencies when use_x11=0
+      'targets': [
+        {
+          'target_name': 'x11',
+          'type': 'none',
+          'toolsets': ['host', 'target'],
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags x11)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other x11 xi)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l x11 xi)',
+                ],
+              },
+            }, {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(pkg-config --cflags x11)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(pkg-config --libs-only-L --libs-only-other x11 xi)',
+                ],
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l x11 xi)',
+                ],
+              },
+            }],
+          ],
+        },
+        {
+          'target_name': 'xcursor',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xcursor)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xcursor)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xcursor)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xcomposite',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xcomposite)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xcomposite)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xcomposite)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xdamage',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xdamage)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xdamage)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xdamage)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xext',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xext)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xext)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xext)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xfixes',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xfixes)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xfixes)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xfixes)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xi',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xi)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xi)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xi)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xrandr',
+          'type': 'none',
+          'toolsets': ['host', 'target'],
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags xrandr)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other xrandr)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l xrandr)',
+                ],
+              },
+            }, {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(pkg-config --cflags xrandr)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(pkg-config --libs-only-L --libs-only-other xrandr)',
+                ],
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l xrandr)',
+                ],
+              },
+            }],
+          ],
+        },
+        {
+          'target_name': 'xrender',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xrender)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xrender)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xrender)',
+            ],
+          },
+        },
+        {
+          'target_name': 'xtst',
+          'type': 'none',
+          'toolsets': ['host', 'target'],
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags xtst)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other xtst)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l xtst)',
+                ],
+              },
+            }, {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(pkg-config --cflags xtst)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(pkg-config --libs-only-L --libs-only-other xtst)',
+                ],
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l xtst)',
+                ],
+              },
+            }]
+          ]
+        }
+      ],  # targets
+    }],
+    ['use_x11==1 and chromeos==0', {
+      'targets': [
+        {
+          'target_name': 'xscrnsaver',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xscrnsaver)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xscrnsaver)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xscrnsaver)',
+            ],
+          },
+        },
+      ],  # targets
+    }],
+    ['use_evdev_gestures==1', {
+      'targets': [
+        {
+          'target_name': 'libevdev-cros',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags libevdev-cros)'
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other libevdev-cros)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l libevdev-cros)',
+            ],
+          },
+        },
+        {
+          'target_name': 'libgestures',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags libgestures)'
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other libgestures)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l libgestures)',
+            ],
+          },
+        },
+      ],
+    }],
+    ['use_xkbcommon==1', {
+      'targets': [
+        {
+          'target_name': 'xkbcommon',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xkbcommon)'
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xkbcommon)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xkbcommon)',
+            ],
+          },
+        },
+      ],
+    }],
+    ['ozone_platform_gbm==1', {
+      'targets': [
+        {
+          'target_name': 'gbm',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gbm)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other gbm)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l gbm)',
+            ],
+          },
+        },
+      ],
+    }],
+    ['ozone_platform_dri==1 or ozone_platform_drm==1 or ozone_platform_gbm==1', {
+      'targets': [
+        {
+          'target_name': 'libdrm',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags libdrm)',
+            ],
+          },
+          'link_settings': {
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l libdrm)',
+            ],
+          },
+        },
+      ],
+    }],
+    ['use_udev==1', {
+      'targets': [
+        {
+          'target_name': 'udev',
+          'type': 'static_library',
+          'conditions': [
+            ['_toolset=="target"', {
+              'include_dirs': [
+                '../..',
+              ],
+              'hard_dependency': 1,
+              'actions': [
+                {
+                  'variables': {
+                    'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libudev0.h',
+                    'output_cc': '<(INTERMEDIATE_DIR)/libudev0_loader.cc',
+                    'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+                  },
+                  'action_name': 'generate_libudev0_loader',
+                  'inputs': [
+                    '<(generator)',
+                  ],
+                  'outputs': [
+                    '<(output_h)',
+                    '<(output_cc)',
+                  ],
+                  'action': ['python',
+                             '<(generator)',
+                             '--name', 'LibUdev0Loader',
+                             '--output-h', '<(output_h)',
+                             '--output-cc', '<(output_cc)',
+                             '--header', '"third_party/libudev/libudev0.h"',
+                             '--link-directly=0',
+                             '<@(libudev_functions)',
+                  ],
+                  'message': 'Generating libudev0 library loader',
+                  'process_outputs_as_sources': 1,
+                },
+                {
+                  'variables': {
+                    'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libudev1.h',
+                    'output_cc': '<(INTERMEDIATE_DIR)/libudev1_loader.cc',
+                    'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+                  },
+                  'action_name': 'generate_libudev1_loader',
+                  'inputs': [
+                    '<(generator)',
+                  ],
+                  'outputs': [
+                    '<(output_h)',
+                    '<(output_cc)',
+                  ],
+                  'action': ['python',
+                             '<(generator)',
+                             '--name', 'LibUdev1Loader',
+                             '--output-h', '<(output_h)',
+                             '--output-cc', '<(output_cc)',
+                             '--header', '"third_party/libudev/libudev1.h"',
+                             '--link-directly=0',
+                             '<@(libudev_functions)',
+                  ],
+                  'message': 'Generating libudev1 library loader',
+                  'process_outputs_as_sources': 1,
+                },
+              ],
+            }],
+          ],
+        },
+      ],
+    }],
+    ['use_libpci==1', {
+      'targets': [
+        {
+          'target_name': 'libpci',
+          'type': 'static_library',
+          'cflags': [
+            '<!@(<(pkg-config) --cflags libpci)',
+          ],
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '<(SHARED_INTERMEDIATE_DIR)',
+            ],
+            'conditions': [
+              ['linux_link_libpci==1', {
+                'link_settings': {
+                  'ldflags': [
+                    '<!@(<(pkg-config) --libs-only-L --libs-only-other libpci)',
+                  ],
+                  'libraries': [
+                    '<!@(<(pkg-config) --libs-only-l libpci)',
+                  ],
+                }
+              }],
+            ],
+          },
+          'include_dirs': [
+            '../..',
+          ],
+          'hard_dependency': 1,
+          'actions': [
+            {
+              'variables': {
+                'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libpci.h',
+                'output_cc': '<(INTERMEDIATE_DIR)/libpci_loader.cc',
+                'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+              },
+              'action_name': 'generate_libpci_loader',
+              'inputs': [
+                '<(generator)',
+              ],
+              'outputs': [
+                '<(output_h)',
+                '<(output_cc)',
+              ],
+              'action': ['python',
+                         '<(generator)',
+                         '--name', 'LibPciLoader',
+                         '--output-h', '<(output_h)',
+                         '--output-cc', '<(output_cc)',
+                         '--header', '<pci/pci.h>',
+                         # TODO(phajdan.jr): Report problem to pciutils project
+                         # and get it fixed so that we don't need --use-extern-c.
+                         '--use-extern-c',
+                         '--link-directly=<(linux_link_libpci)',
+                         '<@(libpci_functions)',
+              ],
+              'message': 'Generating libpci library loader',
+              'process_outputs_as_sources': 1,
+            },
+          ],
+        },
+      ],
+    }],
+  ],  # conditions
+  'targets': [
+    {
+      'target_name': 'dbus',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(<(pkg-config) --cflags dbus-1)',
+        ],
+        'defines': [
+          'USE_DBUS',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(<(pkg-config) --libs-only-L --libs-only-other dbus-1)',
+        ],
+        'libraries': [
+          '<!@(<(pkg-config) --libs-only-l dbus-1)',
+        ],
+      },
+    },
+    {
+      'target_name': 'fontconfig',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target"', {
+          'conditions': [
+            ['use_system_fontconfig==1', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags fontconfig)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other fontconfig)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l fontconfig)',
+                ],
+              },
+            }, {  # use_system_fontconfig==0
+              'dependencies': [
+                '../../third_party/fontconfig/fontconfig.gyp:fontconfig',
+              ],
+              'export_dependent_settings' : [
+                '../../third_party/fontconfig/fontconfig.gyp:fontconfig',
+              ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'freetype2',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags freetype2)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other freetype2)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l freetype2)',
+            ],
+          },
+        }],
+      ],
+    },
+    {
+      'target_name': 'gconf',
+      'type': 'none',
+      'conditions': [
+        ['use_gconf==1 and _toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gconf-2.0)',
+            ],
+            'defines': [
+              'USE_GCONF',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other gconf-2.0)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l gconf-2.0)',
+            ],
+          },
+        }],
+      ],
+    },
+    {
+      'target_name': 'gio',
+      'type': 'static_library',
+      'conditions': [
+        ['use_gio==1 and _toolset=="target"', {
+          'cflags': [
+            '<!@(<(pkg-config) --cflags gio-2.0)',
+          ],
+          'variables': {
+            'gio_warning_define': [
+              # glib >=2.40 deprecate g_settings_list_schemas in favor of
+              # g_settings_schema_source_list_schemas. This function is not
+              # available on earlier versions that we still need to support
+              # (specifically, 2.32), so disable the warning.
+              # TODO(mgiuca): Remove this suppression (and variable) when we
+              # drop support for Ubuntu 13.10 (saucy) and earlier. Update the
+              # code to use g_settings_schema_source_list_schemas instead.
+              'GLIB_DISABLE_DEPRECATION_WARNINGS',
+            ],
+          },
+          'defines': [
+            '<(gio_warning_define)',
+          ],
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gio-2.0)',
+            ],
+            'defines': [
+              'USE_GIO',
+              '<(gio_warning_define)',
+            ],
+            'include_dirs': [
+              '<(SHARED_INTERMEDIATE_DIR)',
+            ],
+          },
+          'include_dirs': [
+            '../..',
+          ],
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other gio-2.0)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l gio-2.0)',
+            ],
+            'conditions': [
+              ['linux_link_gsettings==0 and OS=="linux"', {
+                'libraries': [
+                  '-ldl',
+                ],
+              }],
+            ],
+          },
+          'hard_dependency': 1,
+          'actions': [
+            {
+              'variables': {
+                'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libgio.h',
+                'output_cc': '<(INTERMEDIATE_DIR)/libgio_loader.cc',
+                'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+              },
+              'action_name': 'generate_libgio_loader',
+              'inputs': [
+                '<(generator)',
+              ],
+              'outputs': [
+                '<(output_h)',
+                '<(output_cc)',
+              ],
+              'action': ['python',
+                         '<(generator)',
+                         '--name', 'LibGioLoader',
+                         '--output-h', '<(output_h)',
+                         '--output-cc', '<(output_cc)',
+                         '--header', '<gio/gio.h>',
+                         '--link-directly=<(linux_link_gsettings)',
+                         '<@(libgio_functions)',
+              ],
+              'message': 'Generating libgio library loader',
+              'process_outputs_as_sources': 1,
+            },
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'glib',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'glib_packages': 'glib-2.0 gmodule-2.0 gobject-2.0 gthread-2.0',
+      },
+      'conditions': [
+        ['_toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags <(glib_packages))',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other <(glib_packages))',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l <(glib_packages))',
+            ],
+          },
+        }, {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(pkg-config --cflags <(glib_packages))',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(pkg-config --libs-only-L --libs-only-other <(glib_packages))',
+            ],
+            'libraries': [
+              '<!@(pkg-config --libs-only-l <(glib_packages))',
+            ],
+          },
+        }],
+      ],
+    },
+    {
+      'target_name': 'gnome_keyring',
+      'type': 'none',
+      'conditions': [
+        ['use_gnome_keyring==1', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gnome-keyring-1)',
+            ],
+            'defines': [
+              'USE_GNOME_KEYRING',
+            ],
+            'conditions': [
+              ['linux_link_gnome_keyring==0', {
+                'defines': ['DLOPEN_GNOME_KEYRING'],
+              }],
+            ],
+          },
+          'conditions': [
+            ['linux_link_gnome_keyring!=0', {
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
+                ],
+              },
+            }, {
+              'conditions': [
+                ['OS=="linux"', {
+                 'link_settings': {
+                   'libraries': [
+                     '-ldl',
+                   ],
+                 },
+                }],
+              ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      # The unit tests use a few convenience functions from the GNOME
+      # Keyring library directly. We ignore linux_link_gnome_keyring and
+      # link directly in this version of the target to allow this.
+      # *** Do not use this target in the main binary! ***
+      'target_name': 'gnome_keyring_direct',
+      'type': 'none',
+      'conditions': [
+        ['use_gnome_keyring==1', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags gnome-keyring-1)',
+            ],
+            'defines': [
+              'USE_GNOME_KEYRING',
+            ],
+            'conditions': [
+              ['linux_link_gnome_keyring==0', {
+                'defines': ['DLOPEN_GNOME_KEYRING'],
+              }],
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
+            ],
+          },
+        }],
+      ],
+    },
+    {
+      'target_name': 'libbrlapi',
+      'type': 'static_library',
+      'all_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+        'defines': [
+          'USE_BRLAPI',
+        ],
+        'conditions': [
+          ['linux_link_libbrlapi==1', {
+            'link_settings': {
+              'libraries': [
+                '-lbrlapi',
+              ],
+            }
+          }],
+        ],
+      },
+      'include_dirs': [
+        '../..',
+      ],
+      'hard_dependency': 1,
+      'actions': [
+        {
+          'variables': {
+            'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libbrlapi.h',
+            'output_cc': '<(INTERMEDIATE_DIR)/libbrlapi_loader.cc',
+            'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+          },
+          'action_name': 'generate_brlapi_loader',
+          'inputs': [
+            '<(generator)',
+          ],
+          'outputs': [
+            '<(output_h)',
+            '<(output_cc)',
+          ],
+          'action': ['python',
+                     '<(generator)',
+                     '--name', 'LibBrlapiLoader',
+                     '--output-h', '<(output_h)',
+                     '--output-cc', '<(output_cc)',
+                     '--header', '<brlapi.h>',
+                     '--link-directly=<(linux_link_libbrlapi)',
+                     '<@(libbrlapi_functions)',
+          ],
+          'message': 'Generating libbrlapi library loader',
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+    {
+      'target_name': 'libcap',
+      'type': 'none',
+      'link_settings': {
+        'libraries': [
+          '-lcap',
+        ],
+      },
+    },
+    {
+      'target_name': 'libresolv',
+      'type': 'none',
+      'link_settings': {
+        'libraries': [
+          '-lresolv',
+        ],
+      },
+    },
+    {
+      # GN version: //third_party/speech-dispatcher
+      'target_name': 'libspeechd',
+      'type': 'static_library',
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(SHARED_INTERMEDIATE_DIR)',
+        ],
+        'conditions': [
+          ['linux_link_libspeechd==1', {
+            'link_settings': {
+              'libraries': [
+                '-lspeechd',
+              ],
+            }
+          }],
+        ],
+      },
+      'include_dirs': [
+        '../..',
+      ],
+      'hard_dependency': 1,
+      'actions': [
+        {
+          'variables': {
+            'output_h': '<(SHARED_INTERMEDIATE_DIR)/library_loaders/libspeechd.h',
+            'output_cc': '<(INTERMEDIATE_DIR)/libspeechd_loader.cc',
+            'generator': '../../tools/generate_library_loader/generate_library_loader.py',
+
+            # speech-dispatcher >= 0.8 installs libspeechd.h into
+            # speech-dispatcher/libspeechd.h, whereas speech-dispatcher < 0.8
+            # puts libspeechd.h in the top-level include directory.
+            # Since we need to support both cases for now, we ship a copy of
+            # libspeechd.h in third_party/speech-dispatcher. If the user
+            # prefers to link against the speech-dispatcher directly, the
+            # `libspeechd_h_prefix' variable can be passed to gyp with a value
+            # such as "speech-dispatcher/" that will be prepended to
+            # "libspeechd.h" in the #include directive.
+            # TODO(phaldan.jr): Once we do not need to support
+            # speech-dispatcher < 0.8 we can get rid of all this (including
+            # third_party/speech-dispatcher) and just include
+            # speech-dispatcher/libspeechd.h unconditionally.
+            'libspeechd_h_prefix%': '',
+          },
+          'action_name': 'generate_libspeechd_loader',
+          'inputs': [
+            '<(generator)',
+          ],
+          'outputs': [
+            '<(output_h)',
+            '<(output_cc)',
+          ],
+          'action': ['python',
+                     '<(generator)',
+                     '--name', 'LibSpeechdLoader',
+                     '--output-h', '<(output_h)',
+                     '--output-cc', '<(output_cc)',
+                     '--header', '<<(libspeechd_h_prefix)libspeechd.h>',
+                     '--bundled-header',
+                     '"third_party/speech-dispatcher/libspeechd.h"',
+                     '--link-directly=<(linux_link_libspeechd)',
+                     'spd_open',
+                     'spd_say',
+                     'spd_stop',
+                     'spd_close',
+                     'spd_pause',
+                     'spd_resume',
+                     'spd_set_notification_on',
+                     'spd_set_voice_rate',
+                     'spd_set_voice_pitch',
+                     'spd_list_synthesis_voices',
+                     'spd_set_synthesis_voice',
+                     'spd_list_modules',
+                     'spd_set_output_module',
+                     'spd_set_language',
+          ],
+          'message': 'Generating libspeechd library loader',
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    },
+    {
+      'target_name': 'pangocairo',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'conditions': [
+        ['use_pango==1 and use_cairo==1', {
+          'conditions': [
+            ['_toolset=="target"', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags pangocairo pangoft2)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other pangocairo pangoft2)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l pangocairo pangoft2)',
+                ],
+              },
+            }, {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(pkg-config --cflags pangocairo pangoft2)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(pkg-config --libs-only-L --libs-only-other pangocairo pangoft2)',
+                ],
+                'libraries': [
+                  '<!@(pkg-config --libs-only-l pangocairo pangoft2)',
+                ],
+              },
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'ssl',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target"', {
+          'conditions': [
+            ['use_openssl==1', {
+              'dependencies': [
+                '../../third_party/boringssl/boringssl.gyp:boringssl',
+              ],
+            }, {
+              'dependencies': [
+                '../../net/third_party/nss/ssl.gyp:libssl',
+              ],
+              'direct_dependent_settings': {
+                'include_dirs+': [
+                  # We need for our local copies of the libssl3 headers to come
+                  # before other includes, as we are shadowing system headers.
+                  '<(DEPTH)/net/third_party/nss/ssl',
+                ],
+              },
+            }],
+            # Link in the system NSS if it is used for either the internal
+            # crypto library (use_openssl==0) or platform certificate
+            # library (use_nss_certs==1).
+            ['use_openssl==0 or use_nss_certs==1', {
+              'direct_dependent_settings': {
+                'cflags': [
+                  '<!@(<(pkg-config) --cflags nss)',
+                ],
+              },
+              'link_settings': {
+                'ldflags': [
+                  '<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
+                ],
+                'libraries': [
+                  '<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")',
+                ],
+              },
+              'conditions': [
+                ['clang==1', {
+                  'direct_dependent_settings': {
+                    'cflags': [
+                      # There is a broken header guard in /usr/include/nss/secmod.h:
+                      # https://bugzilla.mozilla.org/show_bug.cgi?id=884072
+                      '-Wno-header-guard',
+                    ],
+                  },
+                }],
+              ],
+            }],
+          ]
+        }],
+      ],
+    },
+  ],
+}
diff --git a/build/linux/unbundle/README b/build/linux/unbundle/README
new file mode 100644
index 0000000..d1b2a96
--- /dev/null
+++ b/build/linux/unbundle/README
@@ -0,0 +1,44 @@
+This directory contains files that make it possible to use system libraries.
+
+For more info please read the following:
+
+ - https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries
+ - https://wiki.gentoo.org/wiki/Why_not_bundle_dependencies
+ - http://www.debian.org/doc/debian-policy/ch-source.html#s-embeddedfiles
+
+For more Chromium-specific context please read
+http://spot.livejournal.com/312320.html .
+
+This directory is provided in the source tree to follow above guidelines.
+It is a compromise solution which takes into account Chromium developers
+who want to avoid the perceived burden of more conditional code in gyp,
+and expectations of Open Source community, where using system-provided
+libraries is the norm.
+
+Usage:
+
+1. remove_bundled_libraries.py <preserved-directories>
+
+   For example: remove_bundled_libraries.py third_party/mesa
+
+   The script scans sources looking for third_party directories.
+   Everything that is not explicitly preserved is removed (except for
+   gyp files), and the script fails if any directory passed on command
+   line does not exist (to ensure list is kept up to date).
+
+   This is intended to be used on sources extracted from a tarball,
+   not a repository.
+
+   NOTE: by default this will not remove anything (for safety). Pass
+   --do-remove flag to actually remove files.
+
+2. replace_gyp_files.py <gyp-flags>
+
+   For example: replace_gyp_files.py -Duse_system_harfbuzz=1
+
+   The script ignores flags other than -D for convenience. This makes it
+   possible to have a variable e.g. ${myconf} with all the options, and
+   execute:
+
+   build/linux/unbundle/replace_gyp_files.py ${myconf}
+   build/gyp_chromium ${myconf}
diff --git a/build/linux/unbundle/expat.gyp b/build/linux/unbundle/expat.gyp
new file mode 100644
index 0000000..030fb85
--- /dev/null
+++ b/build/linux/unbundle/expat.gyp
@@ -0,0 +1,17 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'expat',
+      'type': 'none',
+      'link_settings': {
+        'libraries': [
+          '-lexpat',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/ffmpeg.gyp b/build/linux/unbundle/ffmpeg.gyp
new file mode 100644
index 0000000..e3c3723
--- /dev/null
+++ b/build/linux/unbundle/ffmpeg.gyp
@@ -0,0 +1,54 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'ffmpeg',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags libavcodec libavformat libavutil)',
+
+          '<!(python <(DEPTH)/tools/compile_test/compile_test.py '
+              '--code "#define __STDC_CONSTANT_MACROS\n'
+              '#include <libavcodec/avcodec.h>\n'
+              'int test() { return AV_CODEC_ID_OPUS; }" '
+              '--on-failure -DCHROMIUM_OMIT_AV_CODEC_ID_OPUS=1)',
+
+          '<!(python <(DEPTH)/tools/compile_test/compile_test.py '
+              '--code "#define __STDC_CONSTANT_MACROS\n'
+              '#include <libavcodec/avcodec.h>\n'
+              'int test() { return AV_CODEC_ID_VP9; }" '
+              '--on-failure -DCHROMIUM_OMIT_AV_CODEC_ID_VP9=1)',
+
+          '<!(python <(DEPTH)/tools/compile_test/compile_test.py '
+              '--code "#define __STDC_CONSTANT_MACROS\n'
+              '#include <libavcodec/avcodec.h>\n'
+              'int test() { return AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL; }" '
+              '--on-failure -DCHROMIUM_OMIT_AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL=1)',
+
+          '<!(python <(DEPTH)/tools/compile_test/compile_test.py '
+              '--code "#define __STDC_CONSTANT_MACROS\n'
+              '#include <libavcodec/avcodec.h>\n'
+              'int test() { struct AVFrame frame;\n'
+              'return av_frame_get_channels(&frame); }" '
+              '--on-failure -DCHROMIUM_NO_AVFRAME_CHANNELS=1)',
+        ],
+        'defines': [
+          '__STDC_CONSTANT_MACROS',
+          'USE_SYSTEM_FFMPEG',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other libavcodec libavformat libavutil)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l libavcodec libavformat libavutil)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/flac.gyp b/build/linux/unbundle/flac.gyp
new file mode 100644
index 0000000..9e4a664
--- /dev/null
+++ b/build/linux/unbundle/flac.gyp
@@ -0,0 +1,37 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libflac',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': 'include',
+        'header_filenames': [
+          'FLAC/callback.h',
+          'FLAC/metadata.h',
+          'FLAC/assert.h',
+          'FLAC/export.h',
+          'FLAC/format.h',
+          'FLAC/stream_decoder.h',
+          'FLAC/stream_encoder.h',
+          'FLAC/ordinals.h',
+          'FLAC/all.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other flac)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l flac)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/harfbuzz.gyp b/build/linux/unbundle/harfbuzz.gyp
new file mode 100644
index 0000000..3bc1744
--- /dev/null
+++ b/build/linux/unbundle/harfbuzz.gyp
@@ -0,0 +1,47 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    # Check for presence of harfbuzz-icu library, use it if present.
+    'harfbuzz_libraries':
+        '<!(python <(DEPTH)/tools/compile_test/compile_test.py '
+        '--code "int main() { return 0; }" '
+        '--run-linker '
+        '--on-success "harfbuzz harfbuzz-icu" '
+        '--on-failure "harfbuzz" '
+        '-- -lharfbuzz-icu)',
+  },
+  'targets': [
+    {
+      'target_name': 'harfbuzz-ng',
+      'type': 'none',
+      'cflags': [
+        '<!@(pkg-config --cflags <(harfbuzz_libraries))',
+      ],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags <(harfbuzz_libraries))',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other <(harfbuzz_libraries))',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l <(harfbuzz_libraries))',
+        ],
+      },
+      'variables': {
+        'headers_root_path': 'src',
+        'header_filenames': [
+          'hb.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+    },
+  ],
+}
diff --git a/build/linux/unbundle/icu.gyp b/build/linux/unbundle/icu.gyp
new file mode 100644
index 0000000..16c36df
--- /dev/null
+++ b/build/linux/unbundle/icu.gyp
@@ -0,0 +1,248 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'icudata',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags icu-uc)',
+        ],
+        'defines': [
+          'U_USING_ICU_NAMESPACE=0',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other icu-uc)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l icu-uc)',
+        ],
+      },
+    },
+    {
+      'target_name': 'icui18n',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags icu-i18n)',
+        ],
+        'defines': [
+          'U_USING_ICU_NAMESPACE=0',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other icu-i18n)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l icu-i18n)',
+        ],
+      },
+      'variables': {
+        'headers_root_path': 'source/i18n',
+        'header_filenames': [
+          # This list can easily be updated using the command below:
+          # find third_party/icu/source/i18n/unicode -iname '*.h' \
+          # -printf "'%p',\n" | \
+          # sed -e 's|third_party/icu/source/i18n/||' | sort -u
+          'unicode/basictz.h',
+          'unicode/bmsearch.h',
+          'unicode/bms.h',
+          'unicode/calendar.h',
+          'unicode/choicfmt.h',
+          'unicode/coleitr.h',
+          'unicode/colldata.h',
+          'unicode/coll.h',
+          'unicode/curramt.h',
+          'unicode/currpinf.h',
+          'unicode/currunit.h',
+          'unicode/datefmt.h',
+          'unicode/dcfmtsym.h',
+          'unicode/decimfmt.h',
+          'unicode/dtfmtsym.h',
+          'unicode/dtitvfmt.h',
+          'unicode/dtitvinf.h',
+          'unicode/dtptngen.h',
+          'unicode/dtrule.h',
+          'unicode/fieldpos.h',
+          'unicode/fmtable.h',
+          'unicode/format.h',
+          'unicode/fpositer.h',
+          'unicode/gregocal.h',
+          'unicode/locdspnm.h',
+          'unicode/measfmt.h',
+          'unicode/measunit.h',
+          'unicode/measure.h',
+          'unicode/msgfmt.h',
+          'unicode/numfmt.h',
+          'unicode/numsys.h',
+          'unicode/plurfmt.h',
+          'unicode/plurrule.h',
+          'unicode/rbnf.h',
+          'unicode/rbtz.h',
+          'unicode/regex.h',
+          'unicode/search.h',
+          'unicode/selfmt.h',
+          'unicode/simpletz.h',
+          'unicode/smpdtfmt.h',
+          'unicode/sortkey.h',
+          'unicode/stsearch.h',
+          'unicode/tblcoll.h',
+          'unicode/timezone.h',
+          'unicode/tmunit.h',
+          'unicode/tmutamt.h',
+          'unicode/tmutfmt.h',
+          'unicode/translit.h',
+          'unicode/tzrule.h',
+          'unicode/tztrans.h',
+          'unicode/ucal.h',
+          'unicode/ucoleitr.h',
+          'unicode/ucol.h',
+          'unicode/ucsdet.h',
+          'unicode/ucurr.h',
+          'unicode/udat.h',
+          'unicode/udatpg.h',
+          'unicode/uldnames.h',
+          'unicode/ulocdata.h',
+          'unicode/umsg.h',
+          'unicode/unirepl.h',
+          'unicode/unum.h',
+          'unicode/uregex.h',
+          'unicode/usearch.h',
+          'unicode/uspoof.h',
+          'unicode/utmscale.h',
+          'unicode/utrans.h',
+          'unicode/vtzone.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+    },
+    {
+      'target_name': 'icuuc',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags icu-uc)',
+        ],
+        'defines': [
+          'U_USING_ICU_NAMESPACE=0',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other icu-uc)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l icu-uc)',
+        ],
+      },
+      'variables': {
+        'headers_root_path': 'source/common',
+        'header_filenames': [
+          # This list can easily be updated using the command below:
+          # find third_party/icu/source/common/unicode -iname '*.h' \
+          # -printf "'%p',\n" | \
+          # sed -e 's|third_party/icu/source/common/||' | sort -u
+          'unicode/brkiter.h',
+          'unicode/bytestream.h',
+          'unicode/caniter.h',
+          'unicode/chariter.h',
+          'unicode/dbbi.h',
+          'unicode/docmain.h',
+          'unicode/dtintrv.h',
+          'unicode/errorcode.h',
+          'unicode/icudataver.h',
+          'unicode/icuplug.h',
+          'unicode/idna.h',
+          'unicode/localpointer.h',
+          'unicode/locid.h',
+          'unicode/normalizer2.h',
+          'unicode/normlzr.h',
+          'unicode/pandroid.h',
+          'unicode/parseerr.h',
+          'unicode/parsepos.h',
+          'unicode/pfreebsd.h',
+          'unicode/plinux.h',
+          'unicode/pmac.h',
+          'unicode/popenbsd.h',
+          'unicode/ppalmos.h',
+          'unicode/ptypes.h',
+          'unicode/putil.h',
+          'unicode/pwin32.h',
+          'unicode/rbbi.h',
+          'unicode/rep.h',
+          'unicode/resbund.h',
+          'unicode/schriter.h',
+          'unicode/std_string.h',
+          'unicode/strenum.h',
+          'unicode/stringpiece.h',
+          'unicode/symtable.h',
+          'unicode/ubidi.h',
+          'unicode/ubrk.h',
+          'unicode/ucasemap.h',
+          'unicode/ucat.h',
+          'unicode/uchar.h',
+          'unicode/uchriter.h',
+          'unicode/uclean.h',
+          'unicode/ucnv_cb.h',
+          'unicode/ucnv_err.h',
+          'unicode/ucnv.h',
+          'unicode/ucnvsel.h',
+          'unicode/uconfig.h',
+          'unicode/udata.h',
+          'unicode/udeprctd.h',
+          'unicode/udraft.h',
+          'unicode/uenum.h',
+          'unicode/uidna.h',
+          'unicode/uintrnal.h',
+          'unicode/uiter.h',
+          'unicode/uloc.h',
+          'unicode/umachine.h',
+          'unicode/umisc.h',
+          'unicode/unifilt.h',
+          'unicode/unifunct.h',
+          'unicode/unimatch.h',
+          'unicode/uniset.h',
+          'unicode/unistr.h',
+          'unicode/unorm2.h',
+          'unicode/unorm.h',
+          'unicode/uobject.h',
+          'unicode/uobslete.h',
+          'unicode/urename.h',
+          'unicode/urep.h',
+          'unicode/ures.h',
+          'unicode/uscript.h',
+          'unicode/uset.h',
+          'unicode/usetiter.h',
+          'unicode/ushape.h',
+          'unicode/usprep.h',
+          'unicode/ustring.h',
+          'unicode/usystem.h',
+          'unicode/utext.h',
+          'unicode/utf16.h',
+          'unicode/utf32.h',
+          'unicode/utf8.h',
+          'unicode/utf.h',
+          'unicode/utf_old.h',
+          'unicode/utrace.h',
+          'unicode/utypeinfo.h',
+          'unicode/utypes.h',
+          'unicode/uvernum.h',
+          'unicode/uversion.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+    },
+  ],
+}
diff --git a/build/linux/unbundle/jsoncpp.gyp b/build/linux/unbundle/jsoncpp.gyp
new file mode 100644
index 0000000..c397f64
--- /dev/null
+++ b/build/linux/unbundle/jsoncpp.gyp
@@ -0,0 +1,39 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'jsoncpp',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': 'source/include',
+        'header_filenames': [
+          'json/assertions.h',
+          'json/autolink.h',
+          'json/config.h',
+          'json/features.h',
+          'json/forwards.h',
+          'json/json.h',
+          'json/reader.h',
+          'json/value.h',
+          'json/writer.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '/usr/include/jsoncpp',
+        ],
+      },
+      'link_settings': {
+        'libraries': [
+          '-ljsoncpp',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/libXNVCtrl.gyp b/build/linux/unbundle/libXNVCtrl.gyp
new file mode 100644
index 0000000..f076bdb
--- /dev/null
+++ b/build/linux/unbundle/libXNVCtrl.gyp
@@ -0,0 +1,35 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libXNVCtrl',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': '.',
+        'header_filenames': [
+          'NVCtrlLib.h',
+          'NVCtrl.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'direct_dependent_settings': {
+        'cflags': [
+            '<!@(pkg-config --cflags libXNVCtrl)',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other libXNVCtrl)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l libXNVCtrl)',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/libevent.gyp b/build/linux/unbundle/libevent.gyp
new file mode 100644
index 0000000..99d7435
--- /dev/null
+++ b/build/linux/unbundle/libevent.gyp
@@ -0,0 +1,27 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libevent',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'headers_root_path': '.',
+        'header_filenames': [
+          'event.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-levent',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/libjpeg.gyp b/build/linux/unbundle/libjpeg.gyp
new file mode 100644
index 0000000..f56e7aa
--- /dev/null
+++ b/build/linux/unbundle/libjpeg.gyp
@@ -0,0 +1,29 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libjpeg',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'defines': [
+          'USE_SYSTEM_LIBJPEG',
+        ],
+        'conditions': [
+          ['os_bsd==1', {
+            'include_dirs': [
+              '/usr/local/include',
+            ],
+          }],
+        ],
+      },
+      'link_settings': {
+        'libraries': [
+          '-ljpeg',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/libpng.gyp b/build/linux/unbundle/libpng.gyp
new file mode 100644
index 0000000..d6933fc
--- /dev/null
+++ b/build/linux/unbundle/libpng.gyp
@@ -0,0 +1,38 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libpng',
+      'type': 'none',
+      'dependencies': [
+        '../zlib/zlib.gyp:zlib',
+      ],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags libpng)',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other libpng)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l libpng)',
+        ],
+      },
+      'variables': {
+        'headers_root_path': '.',
+        'header_filenames': [
+          'png.h',
+          'pngconf.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+    },
+  ],
+}
diff --git a/build/linux/unbundle/libusb.gyp b/build/linux/unbundle/libusb.gyp
new file mode 100644
index 0000000..1c18033
--- /dev/null
+++ b/build/linux/unbundle/libusb.gyp
@@ -0,0 +1,34 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libusb',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': 'src/libusb',
+        'header_filenames': [
+          'libusb.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags libusb-1.0)',
+        ],
+        'link_settings': {
+          'ldflags': [
+            '<!@(pkg-config --libs-only-L --libs-only-other libusb-1.0)',
+          ],
+          'libraries': [
+            '<!@(pkg-config --libs-only-l libusb-1.0)',
+          ],
+        },
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/libvpx.gyp b/build/linux/unbundle/libvpx.gyp
new file mode 100644
index 0000000..75671c5
--- /dev/null
+++ b/build/linux/unbundle/libvpx.gyp
@@ -0,0 +1,43 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'libvpx',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags vpx)',
+        ],
+      },
+      'variables': {
+        'headers_root_path': 'source/libvpx',
+        'header_filenames': [
+          'vpx/vp8.h',
+          'vpx/vp8cx.h',
+          'vpx/vp8dx.h',
+          'vpx/vpx_codec.h',
+          'vpx/vpx_codec_impl_bottom.h',
+          'vpx/vpx_codec_impl_top.h',
+          'vpx/vpx_decoder.h',
+          'vpx/vpx_encoder.h',
+          'vpx/vpx_frame_buffer.h',
+          'vpx/vpx_image.h',
+          'vpx/vpx_integer.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other vpx)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l vpx)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/libwebp.gyp b/build/linux/unbundle/libwebp.gyp
new file mode 100644
index 0000000..6dbce2e
--- /dev/null
+++ b/build/linux/unbundle/libwebp.gyp
@@ -0,0 +1,28 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libwebp',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'defines': [
+          'ENABLE_WEBP',
+        ],
+      },
+      'link_settings': {
+        'libraries': [
+          # Check for presence of webpdemux library, use it if present.
+          '<!(python <(DEPTH)/tools/compile_test/compile_test.py '
+          '--code "int main() { return 0; }" '
+          '--run-linker '
+          '--on-success "-lwebp -lwebpdemux" '
+          '--on-failure "-lwebp" '
+          '-- -lwebpdemux)',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/libxml.gyp b/build/linux/unbundle/libxml.gyp
new file mode 100644
index 0000000..bc4f9fc
--- /dev/null
+++ b/build/linux/unbundle/libxml.gyp
@@ -0,0 +1,38 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libxml',
+      'type': 'static_library',
+      'sources': [
+        'chromium/libxml_utils.h',
+        'chromium/libxml_utils.cc',
+      ],
+      'cflags': [
+        '<!@(pkg-config --cflags libxml-2.0)',
+      ],
+      'defines': [
+        'USE_SYSTEM_LIBXML',
+      ],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags libxml-2.0)',
+        ],
+        'defines': [
+          'USE_SYSTEM_LIBXML',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other libxml-2.0)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l libxml-2.0)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/libxslt.gyp b/build/linux/unbundle/libxslt.gyp
new file mode 100644
index 0000000..f7f6bb9
--- /dev/null
+++ b/build/linux/unbundle/libxslt.gyp
@@ -0,0 +1,25 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libxslt',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags libxslt)',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other libxslt)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l libxslt)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/opus.gyp b/build/linux/unbundle/opus.gyp
new file mode 100644
index 0000000..e8c30ba
--- /dev/null
+++ b/build/linux/unbundle/opus.gyp
@@ -0,0 +1,38 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'opus',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags opus)',
+        ],
+      },
+      'variables': {
+        'headers_root_path': 'src/include',
+        'header_filenames': [
+          'opus_custom.h',
+          'opus_defines.h',
+          'opus_multistream.h',
+          'opus_types.h',
+          'opus.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other opus)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l opus)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/protobuf.gyp b/build/linux/unbundle/protobuf.gyp
new file mode 100644
index 0000000..7bcd992
--- /dev/null
+++ b/build/linux/unbundle/protobuf.gyp
@@ -0,0 +1,149 @@
+# Copyright 2014 The Chromium 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': 'protobuf_lite',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          # Use full protobuf, because vanilla protobuf doesn't have
+          # our custom patch to retain unknown fields in lite mode.
+          '<!@(pkg-config --cflags protobuf)',
+        ],
+        'defines': [
+          'USE_SYSTEM_PROTOBUF',
+
+          # This macro must be defined to suppress the use
+          # of dynamic_cast<>, which requires RTTI.
+          'GOOGLE_PROTOBUF_NO_RTTI',
+          'GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER',
+        ],
+      },
+      'link_settings': {
+        # Use full protobuf, because vanilla protobuf doesn't have
+        # our custom patch to retain unknown fields in lite mode.
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other protobuf)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l protobuf)',
+        ],
+      },
+      'variables': {
+        'headers_root_path': 'src',
+        'header_filenames': [
+          # This list can easily be updated using the command below:
+          # find third_party/protobuf/src -iname '*.h' -printf "'%p',\n" | \
+          # sed -e 's|third_party/protobuf/src/||' | sort -u
+          'google/protobuf/compiler/code_generator.h',
+          'google/protobuf/compiler/command_line_interface.h',
+          'google/protobuf/compiler/cpp/cpp_enum_field.h',
+          'google/protobuf/compiler/cpp/cpp_enum.h',
+          'google/protobuf/compiler/cpp/cpp_extension.h',
+          'google/protobuf/compiler/cpp/cpp_field.h',
+          'google/protobuf/compiler/cpp/cpp_file.h',
+          'google/protobuf/compiler/cpp/cpp_generator.h',
+          'google/protobuf/compiler/cpp/cpp_helpers.h',
+          'google/protobuf/compiler/cpp/cpp_message_field.h',
+          'google/protobuf/compiler/cpp/cpp_message.h',
+          'google/protobuf/compiler/cpp/cpp_options.h',
+          'google/protobuf/compiler/cpp/cpp_primitive_field.h',
+          'google/protobuf/compiler/cpp/cpp_service.h',
+          'google/protobuf/compiler/cpp/cpp_string_field.h',
+          'google/protobuf/compiler/cpp/cpp_unittest.h',
+          'google/protobuf/compiler/importer.h',
+          'google/protobuf/compiler/java/java_doc_comment.h',
+          'google/protobuf/compiler/java/java_enum_field.h',
+          'google/protobuf/compiler/java/java_enum.h',
+          'google/protobuf/compiler/java/java_extension.h',
+          'google/protobuf/compiler/java/java_field.h',
+          'google/protobuf/compiler/java/java_file.h',
+          'google/protobuf/compiler/java/java_generator.h',
+          'google/protobuf/compiler/java/java_helpers.h',
+          'google/protobuf/compiler/java/java_message_field.h',
+          'google/protobuf/compiler/java/java_message.h',
+          'google/protobuf/compiler/java/java_primitive_field.h',
+          'google/protobuf/compiler/java/java_service.h',
+          'google/protobuf/compiler/java/java_string_field.h',
+          'google/protobuf/compiler/mock_code_generator.h',
+          'google/protobuf/compiler/package_info.h',
+          'google/protobuf/compiler/parser.h',
+          'google/protobuf/compiler/plugin.h',
+          'google/protobuf/compiler/plugin.pb.h',
+          'google/protobuf/compiler/python/python_generator.h',
+          'google/protobuf/compiler/subprocess.h',
+          'google/protobuf/compiler/zip_writer.h',
+          'google/protobuf/descriptor_database.h',
+          'google/protobuf/descriptor.h',
+          'google/protobuf/descriptor.pb.h',
+          'google/protobuf/dynamic_message.h',
+          'google/protobuf/extension_set.h',
+          'google/protobuf/generated_enum_reflection.h',
+          'google/protobuf/generated_message_reflection.h',
+          'google/protobuf/generated_message_util.h',
+          'google/protobuf/io/coded_stream.h',
+          'google/protobuf/io/coded_stream_inl.h',
+          'google/protobuf/io/gzip_stream.h',
+          'google/protobuf/io/package_info.h',
+          'google/protobuf/io/printer.h',
+          'google/protobuf/io/tokenizer.h',
+          'google/protobuf/io/zero_copy_stream.h',
+          'google/protobuf/io/zero_copy_stream_impl.h',
+          'google/protobuf/io/zero_copy_stream_impl_lite.h',
+          'google/protobuf/message.h',
+          'google/protobuf/message_lite.h',
+          'google/protobuf/package_info.h',
+          'google/protobuf/reflection_ops.h',
+          'google/protobuf/repeated_field.h',
+          'google/protobuf/service.h',
+          'google/protobuf/stubs/atomicops.h',
+          'google/protobuf/stubs/atomicops_internals_arm64_gcc.h',
+          'google/protobuf/stubs/atomicops_internals_arm_gcc.h',
+          'google/protobuf/stubs/atomicops_internals_arm_qnx.h',
+          'google/protobuf/stubs/atomicops_internals_atomicword_compat.h',
+          'google/protobuf/stubs/atomicops_internals_macosx.h',
+          'google/protobuf/stubs/atomicops_internals_mips_gcc.h',
+          'google/protobuf/stubs/atomicops_internals_pnacl.h',
+          'google/protobuf/stubs/atomicops_internals_tsan.h',
+          'google/protobuf/stubs/atomicops_internals_x86_gcc.h',
+          'google/protobuf/stubs/atomicops_internals_x86_msvc.h',
+          'google/protobuf/stubs/common.h',
+          'google/protobuf/stubs/hash.h',
+          'google/protobuf/stubs/map-util.h',
+          'google/protobuf/stubs/once.h',
+          'google/protobuf/stubs/platform_macros.h',
+          'google/protobuf/stubs/stl_util.h',
+          'google/protobuf/stubs/stringprintf.h',
+          'google/protobuf/stubs/strutil.h',
+          'google/protobuf/stubs/substitute.h',
+          'google/protobuf/stubs/template_util.h',
+          'google/protobuf/stubs/type_traits.h',
+          'google/protobuf/testing/file.h',
+          'google/protobuf/testing/googletest.h',
+          'google/protobuf/test_util.h',
+          'google/protobuf/test_util_lite.h',
+          'google/protobuf/text_format.h',
+          'google/protobuf/unknown_field_set.h',
+          'google/protobuf/wire_format.h',
+          'google/protobuf/wire_format_lite.h',
+          'google/protobuf/wire_format_lite_inl.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+    },
+    {
+      'target_name': 'protoc',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+    },
+    {
+      'target_name': 'py_proto',
+      'type': 'none',
+    },
+  ],
+}
diff --git a/build/linux/unbundle/re2.gyp b/build/linux/unbundle/re2.gyp
new file mode 100644
index 0000000..e2e567a
--- /dev/null
+++ b/build/linux/unbundle/re2.gyp
@@ -0,0 +1,37 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 're2',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': '.',
+        'header_filenames': [
+          're2/filtered_re2.h',
+          're2/re2.h',
+          're2/set.h',
+          're2/stringpiece.h',
+          're2/variadic_function.h',
+        ],
+        'shim_generator_additional_args': [
+          # Chromium copy of re2 is patched to rename POSIX to POSIX_SYNTAX
+          # because of collision issues that break the build.
+          # Upstream refuses to make changes:
+          # http://code.google.com/p/re2/issues/detail?id=73 .
+          '--define', 'POSIX=POSIX_SYNTAX',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lre2',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/remove_bundled_libraries.py b/build/linux/unbundle/remove_bundled_libraries.py
new file mode 100755
index 0000000..69e76f5
--- /dev/null
+++ b/build/linux/unbundle/remove_bundled_libraries.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Removes bundled libraries to make sure they are not used.
+
+See README for more details.
+"""
+
+
+import optparse
+import os.path
+import sys
+
+
+def DoMain(argv):
+  my_dirname = os.path.abspath(os.path.dirname(__file__))
+  source_tree_root = os.path.abspath(
+    os.path.join(my_dirname, '..', '..', '..'))
+
+  if os.path.join(source_tree_root, 'build', 'linux', 'unbundle') != my_dirname:
+    print ('Sanity check failed: please run this script from ' +
+           'build/linux/unbundle directory.')
+    return 1
+
+  parser = optparse.OptionParser()
+  parser.add_option('--do-remove', action='store_true')
+
+  options, args = parser.parse_args(argv)
+
+  exclusion_used = {}
+  for exclusion in args:
+    exclusion_used[exclusion] = False
+
+  for root, dirs, files in os.walk(source_tree_root, topdown=False):
+    # Only look at paths which contain a "third_party" component
+    # (note that e.g. third_party.png doesn't count).
+    root_relpath = os.path.relpath(root, source_tree_root)
+    if 'third_party' not in root_relpath.split(os.sep):
+      continue
+
+    for f in files:
+      path = os.path.join(root, f)
+      relpath = os.path.relpath(path, source_tree_root)
+
+      excluded = False
+      for exclusion in args:
+        # Require precise exclusions. Find the right-most third_party
+        # in the relative path, and if there is more than one ignore
+        # the exclusion if it's completely contained within the part
+        # before right-most third_party path component.
+        split = relpath.rsplit(os.sep + 'third_party' + os.sep, 1)
+        if len(split) > 1 and split[0].startswith(exclusion):
+          continue
+
+        if relpath.startswith(exclusion):
+          # Multiple exclusions can match the same path. Go through all of them
+          # and mark each one as used.
+          exclusion_used[exclusion] = True
+          excluded = True
+      if excluded:
+        continue
+
+      # Deleting gyp files almost always leads to gyp failures.
+      # These files come from Chromium project, and can be replaced if needed.
+      if f.endswith('.gyp') or f.endswith('.gypi'):
+        continue
+
+      # Deleting .isolate files leads to gyp failures. They are usually
+      # not used by a distro build anyway.
+      # See http://www.chromium.org/developers/testing/isolated-testing
+      # for more info.
+      if f.endswith('.isolate'):
+        continue
+
+      if options.do_remove:
+        # Delete the file - best way to ensure it's not used during build.
+        os.remove(path)
+      else:
+        # By default just print paths that would be removed.
+        print path
+
+  exit_code = 0
+
+  # Fail if exclusion list contains stale entries - this helps keep it
+  # up to date.
+  for exclusion, used in exclusion_used.iteritems():
+    if not used:
+      print '%s does not exist' % exclusion
+      exit_code = 1
+
+  if not options.do_remove:
+    print ('To actually remove files printed above, please pass ' +
+           '--do-remove flag.')
+
+  return exit_code
+
+
+if __name__ == '__main__':
+  sys.exit(DoMain(sys.argv[1:]))
diff --git a/build/linux/unbundle/replace_gyp_files.py b/build/linux/unbundle/replace_gyp_files.py
new file mode 100755
index 0000000..d06ae41
--- /dev/null
+++ b/build/linux/unbundle/replace_gyp_files.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Replaces gyp files in tree with files from here that
+make the build use system libraries.
+"""
+
+
+import optparse
+import os.path
+import shutil
+import sys
+
+
+REPLACEMENTS = {
+  'use_system_expat': 'third_party/expat/expat.gyp',
+  'use_system_ffmpeg': 'third_party/ffmpeg/ffmpeg.gyp',
+  'use_system_flac': 'third_party/flac/flac.gyp',
+  'use_system_harfbuzz': 'third_party/harfbuzz-ng/harfbuzz.gyp',
+  'use_system_icu': 'third_party/icu/icu.gyp',
+  'use_system_jsoncpp': 'third_party/jsoncpp/jsoncpp.gyp',
+  'use_system_libevent': 'third_party/libevent/libevent.gyp',
+  'use_system_libjpeg': 'third_party/libjpeg/libjpeg.gyp',
+  'use_system_libpng': 'third_party/libpng/libpng.gyp',
+  'use_system_libusb': 'third_party/libusb/libusb.gyp',
+  'use_system_libvpx': 'third_party/libvpx/libvpx.gyp',
+  'use_system_libwebp': 'third_party/libwebp/libwebp.gyp',
+  'use_system_libxml': 'third_party/libxml/libxml.gyp',
+  'use_system_libxnvctrl' : 'third_party/libXNVCtrl/libXNVCtrl.gyp',
+  'use_system_libxslt': 'third_party/libxslt/libxslt.gyp',
+  'use_system_opus': 'third_party/opus/opus.gyp',
+  'use_system_protobuf': 'third_party/protobuf/protobuf.gyp',
+  'use_system_re2': 'third_party/re2/re2.gyp',
+  'use_system_snappy': 'third_party/snappy/snappy.gyp',
+  'use_system_speex': 'third_party/speex/speex.gyp',
+  'use_system_sqlite': 'third_party/sqlite/sqlite.gyp',
+  'use_system_v8': 'v8/tools/gyp/v8.gyp',
+  'use_system_zlib': 'third_party/zlib/zlib.gyp',
+}
+
+
+def DoMain(argv):
+  my_dirname = os.path.dirname(__file__)
+  source_tree_root = os.path.abspath(
+    os.path.join(my_dirname, '..', '..', '..'))
+
+  parser = optparse.OptionParser()
+
+  # Accept arguments in gyp command-line syntax, so that the caller can re-use
+  # command-line for this script and gyp.
+  parser.add_option('-D', dest='defines', action='append')
+
+  parser.add_option('--undo', action='store_true')
+
+  options, args = parser.parse_args(argv)
+
+  for flag, path in REPLACEMENTS.items():
+    if '%s=1' % flag not in options.defines:
+      continue
+
+    if options.undo:
+      # Restore original file, and also remove the backup.
+      # This is meant to restore the source tree to its original state.
+      os.rename(os.path.join(source_tree_root, path + '.orig'),
+                os.path.join(source_tree_root, path))
+    else:
+      # Create a backup copy for --undo.
+      shutil.copyfile(os.path.join(source_tree_root, path),
+                      os.path.join(source_tree_root, path + '.orig'))
+
+      # Copy the gyp file from directory of this script to target path.
+      shutil.copyfile(os.path.join(my_dirname, os.path.basename(path)),
+                      os.path.join(source_tree_root, path))
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(DoMain(sys.argv))
diff --git a/build/linux/unbundle/snappy.gyp b/build/linux/unbundle/snappy.gyp
new file mode 100644
index 0000000..ab856ed
--- /dev/null
+++ b/build/linux/unbundle/snappy.gyp
@@ -0,0 +1,29 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'snappy',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': 'src',
+        'header_filenames': [
+          'snappy-c.h',
+          'snappy-sinksource.h',
+          'snappy-stubs-public.h',
+          'snappy.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lsnappy',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/speex.gyp b/build/linux/unbundle/speex.gyp
new file mode 100644
index 0000000..75376c8
--- /dev/null
+++ b/build/linux/unbundle/speex.gyp
@@ -0,0 +1,45 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libspeex',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': 'include',
+        'header_filenames': [
+          'speex/speex_types.h',
+          'speex/speex_callbacks.h',
+          'speex/speex_config_types.h',
+          'speex/speex_stereo.h',
+          'speex/speex_echo.h',
+          'speex/speex_preprocess.h',
+          'speex/speex_jitter.h',
+          'speex/speex.h',
+          'speex/speex_resampler.h',
+          'speex/speex_buffer.h',
+          'speex/speex_header.h',
+          'speex/speex_bits.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags speex)',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other speex)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l speex)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/sqlite.gyp b/build/linux/unbundle/sqlite.gyp
new file mode 100644
index 0000000..918da92
--- /dev/null
+++ b/build/linux/unbundle/sqlite.gyp
@@ -0,0 +1,28 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'sqlite',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags sqlite3)',
+        ],
+        'defines': [
+          'USE_SYSTEM_SQLITE',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other sqlite3)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l sqlite3)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/build/linux/unbundle/v8.gyp b/build/linux/unbundle/v8.gyp
new file mode 100644
index 0000000..9b06347
--- /dev/null
+++ b/build/linux/unbundle/v8.gyp
@@ -0,0 +1,64 @@
+# Copyright 2013 the V8 project 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.
+
+{
+  'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'],
+  'targets': [
+    {
+      'target_name': 'v8',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'headers_root_path': '../../include',
+        'header_filenames': [
+          'v8-debug.h',
+          'v8-preparser.h',
+          'v8-profiler.h',
+          'v8-testing.h',
+          'v8.h',
+          'v8stdint.h',
+        ],
+      },
+      'includes': [
+        '../../../build/shim_headers.gypi',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lv8',
+        ],
+      },
+    },
+    {
+      'target_name': 'v8_shell',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'dependencies': [
+        'v8'
+      ],
+    },
+  ],
+}
diff --git a/build/linux/unbundle/zlib.gyp b/build/linux/unbundle/zlib.gyp
new file mode 100644
index 0000000..0a85ff0
--- /dev/null
+++ b/build/linux/unbundle/zlib.gyp
@@ -0,0 +1,67 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'zlib',
+      'type': 'none',
+      'variables': {
+        'headers_root_path': '.',
+        'header_filenames': [
+          'zlib.h',
+        ],
+      },
+      'includes': [
+        '../../build/shim_headers.gypi',
+      ],
+      'direct_dependent_settings': {
+        'defines': [
+          'USE_SYSTEM_ZLIB',
+        ],
+      },
+      'link_settings': {
+        'libraries': [
+          '-lz',
+        ],
+      },
+    },
+    {
+      'target_name': 'minizip',
+      'type': 'static_library',
+      'all_dependent_settings': {
+        'defines': [
+          'USE_SYSTEM_MINIZIP',
+        ],
+      },
+      'defines': [
+        'USE_SYSTEM_MINIZIP',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lminizip',
+        ],
+      },
+    },
+    {
+      'target_name': 'zip',
+      'type': 'static_library',
+      'dependencies': [
+        'minizip',
+        '../../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [
+        'google/zip.cc',
+        'google/zip.h',
+        'google/zip_internal.cc',
+        'google/zip_internal.h',
+        'google/zip_reader.cc',
+        'google/zip_reader.h',
+      ],
+    },
+  ],
+}
diff --git a/build/mac/OWNERS b/build/mac/OWNERS
new file mode 100644
index 0000000..c56e89d
--- /dev/null
+++ b/build/mac/OWNERS
@@ -0,0 +1,2 @@
+mark@chromium.org
+thomasvl@chromium.org
diff --git a/build/mac/asan.gyp b/build/mac/asan.gyp
new file mode 100644
index 0000000..5231681
--- /dev/null
+++ b/build/mac/asan.gyp
@@ -0,0 +1,53 @@
+# 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.
+
+{
+   'targets': [
+     {
+       'target_name': 'asan_dynamic_runtime',
+       'type': 'none',
+       'variables': {
+         # Every target is going to depend on asan_dynamic_runtime, so allow
+         # this one to depend on itself.
+         'prune_self_dependency': 1,
+         # Path is relative to this GYP file.
+         'asan_rtl_mask_path':
+             '../../third_party/llvm-build/Release+Asserts/lib/clang/*/lib/darwin',
+         'asan_osx_dynamic':
+             '<(asan_rtl_mask_path)/libclang_rt.asan_osx_dynamic.dylib',
+         'asan_iossim_dynamic':
+             '<(asan_rtl_mask_path)/libclang_rt.asan_iossim_dynamic.dylib',
+       },
+       'conditions': [
+         ['OS=="mac"', {
+           'copies': [
+             {
+               'destination': '<(PRODUCT_DIR)',
+               'files': [
+                 '<!(/bin/ls <(asan_osx_dynamic))',
+               ],
+             },
+           ],
+         }],
+         # ASan works with iOS simulator only, not bare-metal iOS.
+         ['OS=="ios" and target_arch=="ia32"', {
+           'toolsets': ['host', 'target'],
+           'copies': [
+             {
+               'destination': '<(PRODUCT_DIR)',
+               'target_conditions': [
+                 ['_toolset=="host"', {
+                   'files': [ '<!(/bin/ls <(asan_osx_dynamic))'],
+                 }],
+                 ['_toolset=="target"', {
+                   'files': [ '<!(/bin/ls <(asan_iossim_dynamic))'],
+                 }],
+               ],
+             },
+           ],
+         }],
+       ],
+     },
+   ],
+}
diff --git a/build/mac/change_mach_o_flags.py b/build/mac/change_mach_o_flags.py
new file mode 100755
index 0000000..c2aeaec
--- /dev/null
+++ b/build/mac/change_mach_o_flags.py
@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executablepath>
+
+Arranges for the executable at |executable_path| to have its data (heap)
+pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have
+the PIE (position independent executable) bit set to enable ASLR (address
+space layout randomization). With --executable-heap or --no-pie, the
+respective bits are cleared instead of set, making the heap executable or
+disabling PIE/ASLR.
+
+This script is able to operate on thin (single-architecture) Mach-O files
+and fat (universal, multi-architecture) files. When operating on fat files,
+it will set or clear the bits for each architecture contained therein.
+
+NON-EXECUTABLE HEAP
+
+Traditionally in Mac OS X, 32-bit processes did not have data pages set to
+prohibit execution. Although user programs could call mprotect and
+mach_vm_protect to deny execution of code in data pages, the kernel would
+silently ignore such requests without updating the page tables, and the
+hardware would happily execute code on such pages. 64-bit processes were
+always given proper hardware protection of data pages. This behavior was
+controllable on a system-wide level via the vm.allow_data_exec sysctl, which
+is set by default to 1. The bit with value 1 (set by default) allows code
+execution on data pages for 32-bit processes, and the bit with value 2
+(clear by default) does the same for 64-bit processes.
+
+In Mac OS X 10.7, executables can "opt in" to having hardware protection
+against code execution on data pages applied. This is done by setting a new
+bit in the |flags| field of an executable's |mach_header|. When
+MH_NO_HEAP_EXECUTION is set, proper protections will be applied, regardless
+of the setting of vm.allow_data_exec. See xnu-1699.22.73/osfmk/vm/vm_map.c
+override_nx and xnu-1699.22.73/bsd/kern/mach_loader.c load_machfile.
+
+The Apple toolchain has been revised to set the MH_NO_HEAP_EXECUTION when
+producing executables, provided that -allow_heap_execute is not specified
+at link time. Only linkers shipping with Xcode 4.0 and later (ld64-123.2 and
+later) have this ability. See ld64-123.2.1/src/ld/Options.cpp
+Options::reconfigureDefaults() and
+ld64-123.2.1/src/ld/HeaderAndLoadCommands.hpp
+HeaderAndLoadCommandsAtom<A>::flags().
+
+This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is
+intended for use with executables produced by a linker that predates Apple's
+modifications to set this bit itself. It is also useful for setting this bit
+for non-i386 executables, including x86_64 executables. Apple's linker only
+sets it for 32-bit i386 executables, presumably under the assumption that
+the value of vm.allow_data_exec is set in stone. However, if someone were to
+change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run
+without hardware protection against code execution on data pages. This
+script can set the bit for x86_64 executables, guaranteeing that they run
+with appropriate protection even when vm.allow_data_exec has been tampered
+with.
+
+POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION
+
+This script sets or clears the MH_PIE bit in an executable's Mach-O header,
+enabling or disabling position independence on Mac OS X 10.5 and later.
+Processes running position-independent executables have varying levels of
+ASLR protection depending on the OS release. The main executable's load
+address, shared library load addresess, and the heap and stack base
+addresses may be randomized. Position-independent executables are produced
+by supplying the -pie flag to the linker (or defeated by supplying -no_pie).
+Executables linked with a deployment target of 10.7 or higher have PIE on
+by default.
+
+This script is never strictly needed during the build to enable PIE, as all
+linkers used are recent enough to support -pie. However, it's used to
+disable the PIE bit as needed on already-linked executables.
+"""
+
+import optparse
+import os
+import struct
+import sys
+
+
+# <mach-o/fat.h>
+FAT_MAGIC = 0xcafebabe
+FAT_CIGAM = 0xbebafeca
+
+# <mach-o/loader.h>
+MH_MAGIC = 0xfeedface
+MH_CIGAM = 0xcefaedfe
+MH_MAGIC_64 = 0xfeedfacf
+MH_CIGAM_64 = 0xcffaedfe
+MH_EXECUTE = 0x2
+MH_PIE = 0x00200000
+MH_NO_HEAP_EXECUTION = 0x01000000
+
+
+class MachOError(Exception):
+  """A class for exceptions thrown by this module."""
+
+  pass
+
+
+def CheckedSeek(file, offset):
+  """Seeks the file-like object at |file| to offset |offset| and raises a
+  MachOError if anything funny happens."""
+
+  file.seek(offset, os.SEEK_SET)
+  new_offset = file.tell()
+  if new_offset != offset:
+    raise MachOError, \
+          'seek: expected offset %d, observed %d' % (offset, new_offset)
+
+
+def CheckedRead(file, count):
+  """Reads |count| bytes from the file-like |file| object, raising a
+  MachOError if any other number of bytes is read."""
+
+  bytes = file.read(count)
+  if len(bytes) != count:
+    raise MachOError, \
+          'read: expected length %d, observed %d' % (count, len(bytes))
+
+  return bytes
+
+
+def ReadUInt32(file, endian):
+  """Reads an unsinged 32-bit integer from the file-like |file| object,
+  treating it as having endianness specified by |endian| (per the |struct|
+  module), and returns it as a number. Raises a MachOError if the proper
+  length of data can't be read from |file|."""
+
+  bytes = CheckedRead(file, 4)
+
+  (uint32,) = struct.unpack(endian + 'I', bytes)
+  return uint32
+
+
+def ReadMachHeader(file, endian):
+  """Reads an entire |mach_header| structure (<mach-o/loader.h>) from the
+  file-like |file| object, treating it as having endianness specified by
+  |endian| (per the |struct| module), and returns a 7-tuple of its members
+  as numbers. Raises a MachOError if the proper length of data can't be read
+  from |file|."""
+
+  bytes = CheckedRead(file, 28)
+
+  magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
+      struct.unpack(endian + '7I', bytes)
+  return magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags
+
+
+def ReadFatArch(file):
+  """Reads an entire |fat_arch| structure (<mach-o/fat.h>) from the file-like
+  |file| object, treating it as having endianness specified by |endian|
+  (per the |struct| module), and returns a 5-tuple of its members as numbers.
+  Raises a MachOError if the proper length of data can't be read from
+  |file|."""
+
+  bytes = CheckedRead(file, 20)
+
+  cputype, cpusubtype, offset, size, align = struct.unpack('>5I', bytes)
+  return cputype, cpusubtype, offset, size, align
+
+
+def WriteUInt32(file, uint32, endian):
+  """Writes |uint32| as an unsinged 32-bit integer to the file-like |file|
+  object, treating it as having endianness specified by |endian| (per the
+  |struct| module)."""
+
+  bytes = struct.pack(endian + 'I', uint32)
+  assert len(bytes) == 4
+
+  file.write(bytes)
+
+
+def HandleMachOFile(file, options, offset=0):
+  """Seeks the file-like |file| object to |offset|, reads its |mach_header|,
+  and rewrites the header's |flags| field if appropriate. The header's
+  endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported
+  (mach_header and mach_header_64). Raises MachOError if used on a header that
+  does not have a known magic number or is not of type MH_EXECUTE. The
+  MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field
+  according to |options| and written to |file| if any changes need to be made.
+  If already set or clear as specified by |options|, nothing is written."""
+
+  CheckedSeek(file, offset)
+  magic = ReadUInt32(file, '<')
+  if magic == MH_MAGIC or magic == MH_MAGIC_64:
+    endian = '<'
+  elif magic == MH_CIGAM or magic == MH_CIGAM_64:
+    endian = '>'
+  else:
+    raise MachOError, \
+          'Mach-O file at offset %d has illusion of magic' % offset
+
+  CheckedSeek(file, offset)
+  magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
+      ReadMachHeader(file, endian)
+  assert magic == MH_MAGIC or magic == MH_MAGIC_64
+  if filetype != MH_EXECUTE:
+    raise MachOError, \
+          'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
+              (offset, filetype)
+
+  original_flags = flags
+
+  if options.no_heap_execution:
+    flags |= MH_NO_HEAP_EXECUTION
+  else:
+    flags &= ~MH_NO_HEAP_EXECUTION
+
+  if options.pie:
+    flags |= MH_PIE
+  else:
+    flags &= ~MH_PIE
+
+  if flags != original_flags:
+    CheckedSeek(file, offset + 24)
+    WriteUInt32(file, flags, endian)
+
+
+def HandleFatFile(file, options, fat_offset=0):
+  """Seeks the file-like |file| object to |offset| and loops over its
+  |fat_header| entries, calling HandleMachOFile for each."""
+
+  CheckedSeek(file, fat_offset)
+  magic = ReadUInt32(file, '>')
+  assert magic == FAT_MAGIC
+
+  nfat_arch = ReadUInt32(file, '>')
+
+  for index in xrange(0, nfat_arch):
+    cputype, cpusubtype, offset, size, align = ReadFatArch(file)
+    assert size >= 28
+
+    # HandleMachOFile will seek around. Come back here after calling it, in
+    # case it sought.
+    fat_arch_offset = file.tell()
+    HandleMachOFile(file, options, offset)
+    CheckedSeek(file, fat_arch_offset)
+
+
+def main(me, args):
+  parser = optparse.OptionParser('%prog [options] <executable_path>')
+  parser.add_option('--executable-heap', action='store_false',
+                    dest='no_heap_execution', default=True,
+                    help='Clear the MH_NO_HEAP_EXECUTION bit')
+  parser.add_option('--no-pie', action='store_false',
+                    dest='pie', default=True,
+                    help='Clear the MH_PIE bit')
+  (options, loose_args) = parser.parse_args(args)
+  if len(loose_args) != 1:
+    parser.print_usage()
+    return 1
+
+  executable_path = loose_args[0]
+  executable_file = open(executable_path, 'rb+')
+
+  magic = ReadUInt32(executable_file, '<')
+  if magic == FAT_CIGAM:
+    # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian.
+    HandleFatFile(executable_file, options)
+  elif magic == MH_MAGIC or magic == MH_CIGAM or \
+      magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
+    HandleMachOFile(executable_file, options)
+  else:
+    raise MachOError, '%s is not a Mach-O or fat file' % executable_file
+
+  executable_file.close()
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[0], sys.argv[1:]))
diff --git a/build/mac/change_mach_o_flags_from_xcode.sh b/build/mac/change_mach_o_flags_from_xcode.sh
new file mode 100755
index 0000000..1824f8d
--- /dev/null
+++ b/build/mac/change_mach_o_flags_from_xcode.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Copyright (c) 2011 The Chromium 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 small wrapper script around change_mach_o_flags.py allowing it to
+# be invoked easily from Xcode. change_mach_o_flags.py expects its arguments
+# on the command line, but Xcode puts its parameters in the environment.
+
+set -e
+
+exec "$(dirname "${0}")/change_mach_o_flags.py" \
+     "${@}" \
+     "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
diff --git a/build/mac/chrome_mac.croc b/build/mac/chrome_mac.croc
new file mode 100644
index 0000000..8cde00c
--- /dev/null
+++ b/build/mac/chrome_mac.croc
@@ -0,0 +1,36 @@
+# -*- python -*-
+# Crocodile config file for Chromium mac
+
+{
+  # List of rules, applied in order
+  'rules' : [
+    # Specify inclusions before exclusions, since rules are in order.
+
+    # Don't include chromeos, linux, or windows specific files
+    {
+      'regexp' : '.*(_|/)(chromeos|linux|win|views)(\\.|_)',
+      'include' : 0,
+    },
+    # Don't include ChromeOS dirs
+    {
+      'regexp' : '.*/chromeos/',
+      'include' : 0,
+    },
+
+    # Groups
+    {
+      'regexp' : '.*_test_mac\\.',
+      'group' : 'test',
+    },
+
+    # Languages
+    {
+      'regexp' : '.*\\.m$',
+      'language' : 'ObjC',
+    },
+    {
+      'regexp' : '.*\\.mm$',
+      'language' : 'ObjC++',
+    },
+  ],
+}
diff --git a/build/mac/copy_asan_runtime_dylib.sh b/build/mac/copy_asan_runtime_dylib.sh
new file mode 100755
index 0000000..f221c4a
--- /dev/null
+++ b/build/mac/copy_asan_runtime_dylib.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+
+# 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.
+
+# For app bundles built with ASan, copies the runtime lib
+# (libclang_rt.asan_osx_dynamic.dylib), on which their executables depend, from
+# the compiler installation path into the bundle and fixes the dylib's install
+# name in the binary to be relative to @executable_path.
+
+set -e
+
+BINARY="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
+
+if [[ ! -f "$BINARY" ]]; then
+  # This is neither an .app bundle nor a standalone executable.
+  # Most certainly the script has been called for a data bundle.
+  exit 0
+fi
+
+BINARY_DIR="$(dirname "${BINARY}")"
+
+# Find the link to the ASan runtime encoded in the binary.
+BUILTIN_DYLIB_PATH=$(otool -L "${BINARY}" | \
+    sed -Ene 's/^[[:blank:]]+(.*libclang_rt\.asan_.*_dynamic\.dylib).*$/\1/p')
+
+if [[ "${BUILTIN_DYLIB_PATH}" == *asan_iossim_dynamic* ]]; then
+  ASAN_DYLIB_NAME=libclang_rt.asan_iossim_dynamic.dylib
+elif [[ "${BUILTIN_DYLIB_PATH}" == *asan_osx_dynamic* ]]; then
+  ASAN_DYLIB_NAME=libclang_rt.asan_osx_dynamic.dylib
+fi
+
+if [[ -z "${BUILTIN_DYLIB_PATH}" ]]; then
+  echo "${BINARY} does not depend on the ASan runtime library!" >&2
+  exit 1
+fi
+
+# TODO(glider): this doesn't work if we set CC and CXX to override the default
+# Clang.
+ASAN_DYLIB=$(find \
+    "${BUILT_PRODUCTS_DIR}/../../third_party/llvm-build/Release+Asserts/lib/clang/" \
+    -type f -path "*${ASAN_DYLIB_NAME}")
+
+DYLIB_BASENAME=$(basename "${ASAN_DYLIB}")
+if [[ "${DYLIB_BASENAME}" != "${ASAN_DYLIB_NAME}" ]]; then
+  echo "basename(${ASAN_DYLIB}) != ${ASAN_DYLIB_NAME}" >&2
+  exit 1
+fi
+
+# Check whether the directory containing the executable binary is named
+# "MacOS". In this case we're building a full-fledged OSX app and will put
+# the runtime into appname.app/Contents/Libraries/. Otherwise this is probably
+# an iOS gtest app, and the ASan runtime is put next to the executable.
+UPPER_DIR=$(dirname "${BINARY_DIR}")
+if [ "${UPPER_DIR}" == "MacOS" ]; then
+  LIBRARIES_DIR="${UPPER_DIR}/Libraries"
+  mkdir -p "${LIBRARIES_DIR}"
+  NEW_LC_ID_DYLIB="@executable_path/../Libraries/${ASAN_DYLIB_NAME}"
+else
+  LIBRARIES_DIR="${BINARY_DIR}"
+  NEW_LC_ID_DYLIB="@executable_path/${ASAN_DYLIB_NAME}"
+fi
+
+cp "${ASAN_DYLIB}" "${LIBRARIES_DIR}"
+
+# Make LC_ID_DYLIB of the runtime copy point to its location.
+install_name_tool \
+    -id "${NEW_LC_ID_DYLIB}" \
+    "${LIBRARIES_DIR}/${ASAN_DYLIB_NAME}"
+
+# Fix the rpath to the runtime library recorded in the binary.
+install_name_tool \
+    -change "${BUILTIN_DYLIB_PATH}" \
+    "${NEW_LC_ID_DYLIB}" \
+    "${BINARY}"
diff --git a/build/mac/copy_framework_unversioned.sh b/build/mac/copy_framework_unversioned.sh
new file mode 100755
index 0000000..380cc90
--- /dev/null
+++ b/build/mac/copy_framework_unversioned.sh
@@ -0,0 +1,118 @@
+#!/bin/bash
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Copies a framework to its new home, "unversioning" it.
+#
+# Normally, frameworks are versioned bundles.  The contents of a framework are
+# stored in a versioned directory within the bundle, and symbolic links
+# provide access to the actual code and resources.  See
+# http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
+#
+# The symbolic links usually found in frameworks create problems.  Symbolic
+# links are excluded from code signatures.  That means that it's possible to
+# remove or retarget a symbolic link within a framework without affecting the
+# seal.  In Chrome's case, the outer .app bundle contains a framework where
+# all application code and resources live.  In order for the signature on the
+# .app to be meaningful, it encompasses the framework.  Because framework
+# resources are accessed through the framework's symbolic links, this
+# arrangement results in a case where the resources can be altered without
+# affecting the .app signature's validity.
+#
+# Indirection through symbolic links also carries a runtime performance
+# penalty on open() operations, although open() typically completes so quickly
+# that this is not considered a major performance problem.
+#
+# To resolve these problems, the frameworks that ship within Chrome's .app
+# bundle are unversioned.  Unversioning is simple: instead of using the
+# original outer .framework directory as the framework that ships within the
+# .app, the inner versioned directory is used.  Instead of accessing bundled
+# resources through symbolic links, they are accessed directly.  In normal
+# situations, the only hard-coded use of the versioned directory is by dyld,
+# when loading the framework's code, but this is handled through a normal
+# Mach-O load command, and it is easy to adjust the load command to point to
+# the unversioned framework code rather than the versioned counterpart.
+#
+# The resulting framework bundles aren't strictly conforming, but they work
+# as well as normal versioned framework bundles.
+#
+# An option to skip running install_name_tool is available. By passing -I as
+# the first argument to this script, install_name_tool will be skipped. This
+# is only suitable for copied frameworks that will not be linked against, or
+# when install_name_tool will be run on any linker output when something is
+# linked against the copied framework. This option exists to allow signed
+# frameworks to pass through without subjecting them to any modifications that
+# would break their signatures.
+
+set -e
+
+RUN_INSTALL_NAME_TOOL=1
+if [ $# -eq 3 ] && [ "${1}" = "-I" ] ; then
+  shift
+  RUN_INSTALL_NAME_TOOL=
+fi
+
+if [ $# -ne 2 ] ; then
+  echo "usage: ${0} [-I] FRAMEWORK DESTINATION_DIR" >& 2
+  exit 1
+fi
+
+# FRAMEWORK should be a path to a versioned framework bundle, ending in
+# .framework.  DESTINATION_DIR is the directory that the unversioned framework
+# bundle will be copied to.
+
+FRAMEWORK="${1}"
+DESTINATION_DIR="${2}"
+
+FRAMEWORK_NAME="$(basename "${FRAMEWORK}")"
+if [ "${FRAMEWORK_NAME: -10}" != ".framework" ] ; then
+  echo "${0}: ${FRAMEWORK_NAME} does not end in .framework" >& 2
+  exit 1
+fi
+FRAMEWORK_NAME_NOEXT="${FRAMEWORK_NAME:0:$((${#FRAMEWORK_NAME} - 10))}"
+
+# Find the current version.
+VERSIONS="${FRAMEWORK}/Versions"
+CURRENT_VERSION_LINK="${VERSIONS}/Current"
+CURRENT_VERSION_ID="$(readlink "${VERSIONS}/Current")"
+CURRENT_VERSION="${VERSIONS}/${CURRENT_VERSION_ID}"
+
+# Make sure that the framework's structure makes sense as a versioned bundle.
+if [ ! -e "${CURRENT_VERSION}/${FRAMEWORK_NAME_NOEXT}" ] ; then
+  echo "${0}: ${FRAMEWORK_NAME} does not contain a dylib" >& 2
+  exit 1
+fi
+
+DESTINATION="${DESTINATION_DIR}/${FRAMEWORK_NAME}"
+
+# Copy the versioned directory within the versioned framework to its
+# destination location.
+mkdir -p "${DESTINATION_DIR}"
+rsync -acC --delete --exclude Headers --exclude PrivateHeaders \
+    --include '*.so' "${CURRENT_VERSION}/" "${DESTINATION}"
+
+if [[ -n "${RUN_INSTALL_NAME_TOOL}" ]]; then
+  # Adjust the Mach-O LC_ID_DYLIB load command in the framework.  This does not
+  # change the LC_LOAD_DYLIB load commands in anything that may have already
+  # linked against the framework.  Not all frameworks will actually need this
+  # to be changed.  Some frameworks may already be built with the proper
+  # LC_ID_DYLIB for use as an unversioned framework.  Xcode users can do this
+  # by setting LD_DYLIB_INSTALL_NAME to
+  # $(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(WRAPPER_NAME)/$(PRODUCT_NAME)
+  # If invoking ld via gcc or g++, pass the desired path to -Wl,-install_name
+  # at link time.
+  FRAMEWORK_DYLIB="${DESTINATION}/${FRAMEWORK_NAME_NOEXT}"
+  LC_ID_DYLIB_OLD="$(otool -l "${FRAMEWORK_DYLIB}" |
+                         grep -A10 "^ *cmd LC_ID_DYLIB$" |
+                         grep -m1 "^ *name" |
+                         sed -Ee 's/^ *name (.*) \(offset [0-9]+\)$/\1/')"
+  VERSION_PATH="/Versions/${CURRENT_VERSION_ID}/${FRAMEWORK_NAME_NOEXT}"
+  LC_ID_DYLIB_NEW="$(echo "${LC_ID_DYLIB_OLD}" |
+                     sed -Ee "s%${VERSION_PATH}$%/${FRAMEWORK_NAME_NOEXT}%")"
+
+  if [ "${LC_ID_DYLIB_NEW}" != "${LC_ID_DYLIB_OLD}" ] ; then
+    install_name_tool -id "${LC_ID_DYLIB_NEW}" "${FRAMEWORK_DYLIB}"
+  fi
+fi
diff --git a/build/mac/edit_xibs.sh b/build/mac/edit_xibs.sh
new file mode 100755
index 0000000..b7b749e
--- /dev/null
+++ b/build/mac/edit_xibs.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# Copyright (c) 2012 The Chromium 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 is a convenience to run GYP for /src/chrome/chrome_nibs.gyp
+# with the Xcode generator (as you likely use ninja). Documentation:
+#   http://dev.chromium.org/developers/design-documents/mac-xib-files
+
+set -e
+
+RELSRC=$(dirname "$0")/../..
+SRC=$(cd "$RELSRC" && pwd)
+export PYTHONPATH="$PYTHONPATH:$SRC/build"
+export GYP_GENERATORS=xcode
+"$SRC/tools/gyp/gyp" -I"$SRC/build/common.gypi" "$SRC/chrome/chrome_nibs.gyp"
+echo "You can now edit XIB files in Xcode using:"
+echo "  $SRC/chrome/chrome_nibs.xcodeproj"
diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py
new file mode 100755
index 0000000..0534766
--- /dev/null
+++ b/build/mac/find_sdk.py
@@ -0,0 +1,90 @@
+#!/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.
+
+"""Prints the lowest locally available SDK version greater than or equal to a
+given minimum sdk version to standard output.
+
+Usage:
+  python find_sdk.py 10.6  # Ignores SDKs < 10.6
+"""
+
+import os
+import re
+import subprocess
+import sys
+
+
+from optparse import OptionParser
+
+
+def parse_version(version_str):
+  """'10.6' => [10, 6]"""
+  return map(int, re.findall(r'(\d+)', version_str))
+
+
+def main():
+  parser = OptionParser()
+  parser.add_option("--verify",
+                    action="store_true", dest="verify", default=False,
+                    help="return the sdk argument and warn if it doesn't exist")
+  parser.add_option("--sdk_path",
+                    action="store", type="string", dest="sdk_path", default="",
+                    help="user-specified SDK path; bypasses verification")
+  parser.add_option("--print_sdk_path",
+                    action="store_true", dest="print_sdk_path", default=False,
+                    help="Additionaly print the path the SDK (appears first).")
+  (options, args) = parser.parse_args()
+  min_sdk_version = args[0]
+
+  job = subprocess.Popen(['xcode-select', '-print-path'],
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+  out, err = job.communicate()
+  if job.returncode != 0:
+    print >> sys.stderr, out
+    print >> sys.stderr, err
+    raise Exception(('Error %d running xcode-select, you might have to run '
+      '|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
+      'if you are using Xcode 4.') % job.returncode)
+  # The Developer folder moved in Xcode 4.3.
+  xcode43_sdk_path = os.path.join(
+      out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs')
+  if os.path.isdir(xcode43_sdk_path):
+    sdk_dir = xcode43_sdk_path
+  else:
+    sdk_dir = os.path.join(out.rstrip(), 'SDKs')
+  sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)]
+  sdks = [s[0] for s in sdks if s]  # [['10.5'], ['10.6']] => ['10.5', '10.6']
+  sdks = [s for s in sdks  # ['10.5', '10.6'] => ['10.6']
+          if parse_version(s) >= parse_version(min_sdk_version)]
+  if not sdks:
+    raise Exception('No %s+ SDK found' % min_sdk_version)
+  best_sdk = sorted(sdks, key=parse_version)[0]
+
+  if options.verify and best_sdk != min_sdk_version and not options.sdk_path:
+    print >> sys.stderr, ''
+    print >> sys.stderr, '                                           vvvvvvv'
+    print >> sys.stderr, ''
+    print >> sys.stderr, \
+        'This build requires the %s SDK, but it was not found on your system.' \
+        % min_sdk_version
+    print >> sys.stderr, \
+        'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.'
+    print >> sys.stderr, ''
+    print >> sys.stderr, '                                           ^^^^^^^'
+    print >> sys.stderr, ''
+    return min_sdk_version
+
+  if options.print_sdk_path:
+    print subprocess.check_output(['xcodebuild', '-version', '-sdk',
+                                   'macosx' + best_sdk, 'Path']).strip()
+
+  return best_sdk
+
+
+if __name__ == '__main__':
+  if sys.platform != 'darwin':
+    raise Exception("This script only runs on Mac")
+  print main()
diff --git a/build/mac/make_more_helpers.sh b/build/mac/make_more_helpers.sh
new file mode 100755
index 0000000..6f5c474
--- /dev/null
+++ b/build/mac/make_more_helpers.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Usage: make_more_helpers.sh <directory_within_contents> <app_name>
+#
+# This script creates additional helper .app bundles for Chromium, based on
+# the existing helper .app bundle, changing their Mach-O header's flags to
+# enable and disable various features. Based on Chromium Helper.app, it will
+# create Chromium Helper EH.app, which has the MH_NO_HEAP_EXECUTION bit
+# cleared to support Chromium child processes that require an executable heap,
+# and Chromium Helper NP.app, which has the MH_PIE bit cleared to support
+# Chromium child processes that cannot tolerate ASLR.
+#
+# This script expects to be called from the chrome_exe target as a postbuild,
+# and operates directly within the built-up browser app's versioned directory.
+#
+# Each helper is adjusted by giving it the proper bundle name, renaming the
+# executable, adjusting several Info.plist keys, and changing the executable's
+# Mach-O flags.
+
+set -eu
+
+make_helper() {
+  local containing_dir="${1}"
+  local app_name="${2}"
+  local feature="${3}"
+  local flags="${4}"
+
+  local helper_name="${app_name} Helper"
+  local helper_stem="${containing_dir}/${helper_name}"
+  local original_helper="${helper_stem}.app"
+  if [[ ! -d "${original_helper}" ]]; then
+    echo "${0}: error: ${original_helper} is a required directory" >& 2
+    exit 1
+  fi
+  local original_helper_exe="${original_helper}/Contents/MacOS/${helper_name}"
+  if [[ ! -f "${original_helper_exe}" ]]; then
+    echo "${0}: error: ${original_helper_exe} is a required file" >& 2
+    exit 1
+  fi
+
+  local feature_helper="${helper_stem} ${feature}.app"
+
+  rsync -acC --delete --include '*.so' "${original_helper}/" "${feature_helper}"
+
+  local helper_feature="${helper_name} ${feature}"
+  local helper_feature_exe="${feature_helper}/Contents/MacOS/${helper_feature}"
+  mv "${feature_helper}/Contents/MacOS/${helper_name}" "${helper_feature_exe}"
+
+  local change_flags="$(dirname "${0}")/change_mach_o_flags.py"
+  "${change_flags}" ${flags} "${helper_feature_exe}"
+
+  local feature_info="${feature_helper}/Contents/Info"
+  local feature_info_plist="${feature_info}.plist"
+
+  defaults write "${feature_info}" "CFBundleDisplayName" "${helper_feature}"
+  defaults write "${feature_info}" "CFBundleExecutable" "${helper_feature}"
+
+  cfbundleid="$(defaults read "${feature_info}" "CFBundleIdentifier")"
+  feature_cfbundleid="${cfbundleid}.${feature}"
+  defaults write "${feature_info}" "CFBundleIdentifier" "${feature_cfbundleid}"
+
+  cfbundlename="$(defaults read "${feature_info}" "CFBundleName")"
+  feature_cfbundlename="${cfbundlename} ${feature}"
+  defaults write "${feature_info}" "CFBundleName" "${feature_cfbundlename}"
+
+  # As usual, defaults might have put the plist into whatever format excites
+  # it, but Info.plists get converted back to the expected XML format.
+  plutil -convert xml1 "${feature_info_plist}"
+
+  # `defaults` also changes the file permissions, so make the file
+  # world-readable again.
+  chmod a+r "${feature_info_plist}"
+}
+
+if [[ ${#} -ne 2 ]]; then
+  echo "usage: ${0} <directory_within_contents> <app_name>" >& 2
+  exit 1
+fi
+
+DIRECTORY_WITHIN_CONTENTS="${1}"
+APP_NAME="${2}"
+
+CONTENTS_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
+CONTAINING_DIR="${CONTENTS_DIR}/${DIRECTORY_WITHIN_CONTENTS}"
+
+make_helper "${CONTAINING_DIR}" "${APP_NAME}" "EH" "--executable-heap"
+make_helper "${CONTAINING_DIR}" "${APP_NAME}" "NP" "--no-pie"
diff --git a/build/mac/strip_from_xcode b/build/mac/strip_from_xcode
new file mode 100755
index 0000000..c26b9fb
--- /dev/null
+++ b/build/mac/strip_from_xcode
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# Copyright (c) 2008 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a handy wrapper script that figures out how to call the strip
+# utility (strip_save_dsym in this case), if it even needs to be called at all,
+# and then does it.  This script should be called by a post-link phase in
+# targets that might generate Mach-O executables, dynamic libraries, or
+# loadable bundles.
+#
+# An example "Strip If Needed" build phase placed after "Link Binary With
+# Libraries" would do:
+# exec "${XCODEPROJ_DEPTH}/build/mac/strip_from_xcode"
+
+if [ "${CONFIGURATION}" != "Release" ] ; then
+  # Only strip in release mode.
+  exit 0
+fi
+
+declare -a FLAGS
+
+# MACH_O_TYPE is not set for a command-line tool, so check PRODUCT_TYPE too.
+# Weird.
+if [ "${MACH_O_TYPE}" = "mh_execute" ] || \
+   [ "${PRODUCT_TYPE}" = "com.apple.product-type.tool" ] ; then
+  # Strip everything (no special flags).  No-op.
+  true
+elif [ "${MACH_O_TYPE}" = "mh_dylib" ] || \
+     [ "${MACH_O_TYPE}" = "mh_bundle" ]; then
+  # Strip debugging symbols and local symbols
+  FLAGS[${#FLAGS[@]}]=-S
+  FLAGS[${#FLAGS[@]}]=-x
+elif [ "${MACH_O_TYPE}" = "staticlib" ] ; then
+  # Don't strip static libraries.
+  exit 0
+else
+  # Warn, but don't treat this as an error.
+  echo $0: warning: unrecognized MACH_O_TYPE ${MACH_O_TYPE}
+  exit 0
+fi
+
+if [ -n "${STRIPFLAGS}" ] ; then
+  # Pick up the standard STRIPFLAGS Xcode setting, used for "Additional Strip
+  # Flags".
+  for stripflag in "${STRIPFLAGS}" ; do
+    FLAGS[${#FLAGS[@]}]="${stripflag}"
+  done
+fi
+
+if [ -n "${CHROMIUM_STRIP_SAVE_FILE}" ] ; then
+  # An Xcode project can communicate a file listing symbols to saved in this
+  # environment variable by setting it as a build setting.  This isn't a
+  # standard Xcode setting.  It's used in preference to STRIPFLAGS to
+  # eliminate quoting ambiguity concerns.
+  FLAGS[${#FLAGS[@]}]=-s
+  FLAGS[${#FLAGS[@]}]="${CHROMIUM_STRIP_SAVE_FILE}"
+fi
+
+exec "$(dirname ${0})/strip_save_dsym" "${FLAGS[@]}" \
+     "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
diff --git a/build/mac/strip_save_dsym b/build/mac/strip_save_dsym
new file mode 100755
index 0000000..c9cf226
--- /dev/null
+++ b/build/mac/strip_save_dsym
@@ -0,0 +1,335 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Usage: strip_save_dsym <whatever-arguments-you-would-pass-to-strip>
+#
+# strip_save_dsym is a wrapper around the standard strip utility.  Given an
+# input Mach-O file, strip_save_dsym will save a copy of the file in a "fake"
+# .dSYM bundle for debugging, and then call strip to strip the Mach-O file.
+# Note that the .dSYM file is a "fake" in that it's not a self-contained
+# .dSYM bundle, it just contains a copy of the original (unstripped) Mach-O
+# file, and therefore contains references to object files on the filesystem.
+# The generated .dSYM bundle is therefore unsuitable for debugging in the
+# absence of these .o files.
+#
+# If a .dSYM already exists and has a newer timestamp than the Mach-O file,
+# this utility does nothing.  That allows strip_save_dsym to be run on a file
+# that has already been stripped without trashing the .dSYM.
+#
+# Rationale: the "right" way to generate dSYM bundles, dsymutil, is incredibly
+# slow.  On the other hand, doing a file copy (which is really all that
+# dsymutil does) is comparatively fast.  Since we usually just want to strip
+# a release-mode executable but still be able to debug it, and we don't care
+# so much about generating a hermetic dSYM bundle, we'll prefer the file copy.
+# If a real dSYM is ever needed, it's still possible to create one by running
+# dsymutil and pointing it at the original Mach-O file inside the "fake"
+# bundle, provided that the object files are available.
+
+import errno
+import os
+import re
+import shutil
+import subprocess
+import sys
+import time
+
+# Returns a list of architectures contained in a Mach-O file.  The file can be
+# a universal (fat) file, in which case there will be one list element for
+# each contained architecture, or it can be a thin single-architecture Mach-O
+# file, in which case the list will contain a single element identifying the
+# architecture.  On error, returns an empty list.  Determines the architecture
+# list by calling file.
+def macho_archs(macho):
+  macho_types = ["executable",
+                 "dynamically linked shared library",
+                 "bundle"]
+  macho_types_re = "Mach-O (?:64-bit )?(?:" + "|".join(macho_types) + ")"
+
+  file_cmd = subprocess.Popen(["/usr/bin/file", "-b", "--", macho],
+                              stdout=subprocess.PIPE)
+
+  archs = []
+
+  type_line = file_cmd.stdout.readline()
+  type_match = re.match("^%s (.*)$" % macho_types_re, type_line)
+  if type_match:
+    archs.append(type_match.group(1))
+    return [type_match.group(1)]
+  else:
+    type_match = re.match("^Mach-O universal binary with (.*) architectures$",
+                          type_line)
+    if type_match:
+      for i in range(0, int(type_match.group(1))):
+        arch_line = file_cmd.stdout.readline()
+        arch_match = re.match(
+                     "^.* \(for architecture (.*)\):\t%s .*$" % macho_types_re,
+                     arch_line)
+        if arch_match:
+          archs.append(arch_match.group(1))
+
+  if file_cmd.wait() != 0:
+    archs = []
+
+  if len(archs) == 0:
+    print >> sys.stderr, "No architectures in %s" % macho
+
+  return archs
+
+# Returns a dictionary mapping architectures contained in the file as returned
+# by macho_archs to the LC_UUID load command for that architecture.
+# Architectures with no LC_UUID load command are omitted from the dictionary.
+# Determines the UUID value by calling otool.
+def macho_uuids(macho):
+  uuids = {}
+
+  archs = macho_archs(macho)
+  if len(archs) == 0:
+    return uuids
+
+  for arch in archs:
+    if arch == "":
+      continue
+
+    otool_cmd = subprocess.Popen(["/usr/bin/otool", "-arch", arch, "-l", "-",
+                                  macho],
+                                 stdout=subprocess.PIPE)
+    # state 0 is when nothing UUID-related has been seen yet.  State 1 is
+    # entered after a load command begins, but it may not be an LC_UUID load
+    # command.  States 2, 3, and 4 are intermediate states while reading an
+    # LC_UUID command.  State 5 is the terminal state for a successful LC_UUID
+    # read.  State 6 is the error state.
+    state = 0
+    uuid = ""
+    for otool_line in otool_cmd.stdout:
+      if state == 0:
+        if re.match("^Load command .*$", otool_line):
+          state = 1
+      elif state == 1:
+        if re.match("^     cmd LC_UUID$", otool_line):
+          state = 2
+        else:
+          state = 0
+      elif state == 2:
+        if re.match("^ cmdsize 24$", otool_line):
+          state = 3
+        else:
+          state = 6
+      elif state == 3:
+        # The UUID display format changed in the version of otool shipping
+        # with the Xcode 3.2.2 prerelease.  The new format is traditional:
+        #    uuid 4D7135B2-9C56-C5F5-5F49-A994258E0955
+        # and with Xcode 3.2.6, then line is indented one more space:
+        #     uuid 4D7135B2-9C56-C5F5-5F49-A994258E0955
+        # The old format, from cctools-750 and older's otool, breaks the UUID
+        # up into a sequence of bytes:
+        #    uuid 0x4d 0x71 0x35 0xb2 0x9c 0x56 0xc5 0xf5
+        #         0x5f 0x49 0xa9 0x94 0x25 0x8e 0x09 0x55
+        new_uuid_match = re.match("^ {3,4}uuid (.{8}-.{4}-.{4}-.{4}-.{12})$",
+                                  otool_line)
+        if new_uuid_match:
+          uuid = new_uuid_match.group(1)
+
+          # Skip state 4, there is no second line to read.
+          state = 5
+        else:
+          old_uuid_match = re.match("^   uuid 0x(..) 0x(..) 0x(..) 0x(..) "
+                                    "0x(..) 0x(..) 0x(..) 0x(..)$",
+                                    otool_line)
+          if old_uuid_match:
+            state = 4
+            uuid = old_uuid_match.group(1) + old_uuid_match.group(2) + \
+                   old_uuid_match.group(3) + old_uuid_match.group(4) + "-" + \
+                   old_uuid_match.group(5) + old_uuid_match.group(6) + "-" + \
+                   old_uuid_match.group(7) + old_uuid_match.group(8) + "-"
+          else:
+            state = 6
+      elif state == 4:
+        old_uuid_match = re.match("^        0x(..) 0x(..) 0x(..) 0x(..) "
+                                  "0x(..) 0x(..) 0x(..) 0x(..)$",
+                                  otool_line)
+        if old_uuid_match:
+          state = 5
+          uuid += old_uuid_match.group(1) + old_uuid_match.group(2) + "-" + \
+                  old_uuid_match.group(3) + old_uuid_match.group(4) + \
+                  old_uuid_match.group(5) + old_uuid_match.group(6) + \
+                  old_uuid_match.group(7) + old_uuid_match.group(8)
+        else:
+          state = 6
+
+    if otool_cmd.wait() != 0:
+      state = 6
+
+    if state == 5:
+      uuids[arch] = uuid.upper()
+
+  if len(uuids) == 0:
+    print >> sys.stderr, "No UUIDs in %s" % macho
+
+  return uuids
+
+# Given a path to a Mach-O file and possible information from the environment,
+# determines the desired path to the .dSYM.
+def dsym_path(macho):
+  # If building a bundle, the .dSYM should be placed next to the bundle.  Use
+  # WRAPPER_NAME to make this determination.  If called from xcodebuild,
+  # WRAPPER_NAME will be set to the name of the bundle.
+  dsym = ""
+  if "WRAPPER_NAME" in os.environ:
+    if "BUILT_PRODUCTS_DIR" in os.environ:
+      dsym = os.path.join(os.environ["BUILT_PRODUCTS_DIR"],
+                          os.environ["WRAPPER_NAME"])
+    else:
+      dsym = os.environ["WRAPPER_NAME"]
+  else:
+    dsym = macho
+
+  dsym += ".dSYM"
+
+  return dsym
+
+# Creates a fake .dSYM bundle at dsym for macho, a Mach-O image with the
+# architectures and UUIDs specified by the uuids map.
+def make_fake_dsym(macho, dsym):
+  uuids = macho_uuids(macho)
+  if len(uuids) == 0:
+    return False
+
+  dwarf_dir = os.path.join(dsym, "Contents", "Resources", "DWARF")
+  dwarf_file = os.path.join(dwarf_dir, os.path.basename(macho))
+  try:
+    os.makedirs(dwarf_dir)
+  except OSError, (err, error_string):
+    if err != errno.EEXIST:
+      raise
+  shutil.copyfile(macho, dwarf_file)
+
+  # info_template is the same as what dsymutil would have written, with the
+  # addition of the fake_dsym key.
+  info_template = \
+'''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.%(root_name)s</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+		<key>dSYM_UUID</key>
+		<dict>
+%(uuid_dict)s		</dict>
+		<key>fake_dsym</key>
+		<true/>
+	</dict>
+</plist>
+'''
+
+  root_name = os.path.basename(dsym)[:-5]  # whatever.dSYM without .dSYM
+  uuid_dict = ""
+  for arch in sorted(uuids):
+    uuid_dict += "\t\t\t<key>" + arch + "</key>\n"\
+                 "\t\t\t<string>" + uuids[arch] + "</string>\n"
+  info_dict = {
+    "root_name": root_name,
+    "uuid_dict": uuid_dict,
+  }
+  info_contents = info_template % info_dict
+  info_file = os.path.join(dsym, "Contents", "Info.plist")
+  info_fd = open(info_file, "w")
+  info_fd.write(info_contents)
+  info_fd.close()
+
+  return True
+
+# For a Mach-O file, determines where the .dSYM bundle should be located.  If
+# the bundle does not exist or has a modification time older than the Mach-O
+# file, calls make_fake_dsym to create a fake .dSYM bundle there, then strips
+# the Mach-O file and sets the modification time on the .dSYM bundle and Mach-O
+# file to be identical.
+def strip_and_make_fake_dsym(macho):
+  dsym = dsym_path(macho)
+  macho_stat = os.stat(macho)
+  dsym_stat = None
+  try:
+    dsym_stat = os.stat(dsym)
+  except OSError, (err, error_string):
+    if err != errno.ENOENT:
+      raise
+
+  if dsym_stat is None or dsym_stat.st_mtime < macho_stat.st_mtime:
+    # Make a .dSYM bundle
+    if not make_fake_dsym(macho, dsym):
+      return False
+
+    # Strip the Mach-O file
+    remove_dsym = True
+    try:
+      strip_cmdline = ['xcrun', 'strip'] + sys.argv[1:]
+      strip_cmd = subprocess.Popen(strip_cmdline)
+      if strip_cmd.wait() == 0:
+        remove_dsym = False
+    finally:
+      if remove_dsym:
+        shutil.rmtree(dsym)
+
+    # Update modification time on the Mach-O file and .dSYM bundle
+    now = time.time()
+    os.utime(macho, (now, now))
+    os.utime(dsym, (now, now))
+
+  return True
+
+def main(argv=None):
+  if argv is None:
+    argv = sys.argv
+
+  # This only supports operating on one file at a time.  Look at the arguments
+  # to strip to figure out what the source to be stripped is.  Arguments are
+  # processed in the same way that strip does, although to reduce complexity,
+  # this doesn't do all of the same checking as strip.  For example, strip
+  # has no -Z switch and would treat -Z on the command line as an error.  For
+  # the purposes this is needed for, that's fine.
+  macho = None
+  process_switches = True
+  ignore_argument = False
+  for arg in argv[1:]:
+    if ignore_argument:
+      ignore_argument = False
+      continue
+    if process_switches:
+      if arg == "-":
+        process_switches = False
+      # strip has these switches accept an argument:
+      if arg in ["-s", "-R", "-d", "-o", "-arch"]:
+        ignore_argument = True
+      if arg[0] == "-":
+        continue
+    if macho is None:
+      macho = arg
+    else:
+      print >> sys.stderr, "Too many things to strip"
+      return 1
+
+  if macho is None:
+    print >> sys.stderr, "Nothing to strip"
+    return 1
+
+  if not strip_and_make_fake_dsym(macho):
+    return 1
+
+  return 0
+
+if __name__ == "__main__":
+  sys.exit(main(sys.argv))
diff --git a/build/mac/tweak_info_plist.py b/build/mac/tweak_info_plist.py
new file mode 100755
index 0000000..2057bac
--- /dev/null
+++ b/build/mac/tweak_info_plist.py
@@ -0,0 +1,280 @@
+#!/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.
+
+#
+# Xcode supports build variable substitutions and CPP; sadly, that doesn't work
+# because:
+#
+# 1. Xcode wants to do the Info.plist work before it runs any build phases,
+#    this means if we were to generate a .h file for INFOPLIST_PREFIX_HEADER
+#    we'd have to put it in another target so it runs in time.
+# 2. Xcode also doesn't check to see if the header being used as a prefix for
+#    the Info.plist has changed.  So even if we updated it, it's only looking
+#    at the modtime of the info.plist to see if that's changed.
+#
+# So, we work around all of this by making a script build phase that will run
+# during the app build, and simply update the info.plist in place.  This way
+# by the time the app target is done, the info.plist is correct.
+#
+
+import optparse
+import os
+from os import environ as env
+import plistlib
+import re
+import subprocess
+import sys
+import tempfile
+
+TOP = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+
+
+def _GetOutput(args):
+  """Runs a subprocess and waits for termination. Returns (stdout, returncode)
+  of the process. stderr is attached to the parent."""
+  proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+  (stdout, stderr) = proc.communicate()
+  return (stdout, proc.returncode)
+
+
+def _GetOutputNoError(args):
+  """Similar to _GetOutput() but ignores stderr. If there's an error launching
+  the child (like file not found), the exception will be caught and (None, 1)
+  will be returned to mimic quiet failure."""
+  try:
+    proc = subprocess.Popen(args, stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE)
+  except OSError:
+    return (None, 1)
+  (stdout, stderr) = proc.communicate()
+  return (stdout, proc.returncode)
+
+
+def _RemoveKeys(plist, *keys):
+  """Removes a varargs of keys from the plist."""
+  for key in keys:
+    try:
+      del plist[key]
+    except KeyError:
+      pass
+
+
+def _AddVersionKeys(plist, version=None):
+  """Adds the product version number into the plist. Returns True on success and
+  False on error. The error will be printed to stderr."""
+  if version:
+    match = re.match('\d+\.\d+\.(\d+\.\d+)$', version)
+    if not match:
+      print >>sys.stderr, 'Invalid version string specified: "%s"' % version
+      return False
+
+    full_version = match.group(0)
+    bundle_version = match.group(1)
+
+  else:
+    # Pull in the Chrome version number.
+    VERSION_TOOL = os.path.join(TOP, 'build/util/version.py')
+    VERSION_FILE = os.path.join(TOP, 'chrome/VERSION')
+
+    (stdout, retval1) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t',
+                                    '@MAJOR@.@MINOR@.@BUILD@.@PATCH@'])
+    full_version = stdout.rstrip()
+
+    (stdout, retval2) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t',
+                                    '@BUILD@.@PATCH@'])
+    bundle_version = stdout.rstrip()
+
+    # If either of the two version commands finished with non-zero returncode,
+    # report the error up.
+    if retval1 or retval2:
+      return False
+
+  # Add public version info so "Get Info" works.
+  plist['CFBundleShortVersionString'] = full_version
+
+  # Honor the 429496.72.95 limit.  The maximum comes from splitting 2^32 - 1
+  # into  6, 2, 2 digits.  The limitation was present in Tiger, but it could
+  # have been fixed in later OS release, but hasn't been tested (it's easy
+  # enough to find out with "lsregister -dump).
+  # http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html
+  # BUILD will always be an increasing value, so BUILD_PATH gives us something
+  # unique that meetings what LS wants.
+  plist['CFBundleVersion'] = bundle_version
+
+  # Return with no error.
+  return True
+
+
+def _DoSCMKeys(plist, add_keys):
+  """Adds the SCM information, visible in about:version, to property list. If
+  |add_keys| is True, it will insert the keys, otherwise it will remove them."""
+  scm_revision = None
+  if add_keys:
+    # Pull in the Chrome revision number.
+    VERSION_TOOL = os.path.join(TOP, 'build/util/version.py')
+    LASTCHANGE_FILE = os.path.join(TOP, 'build/util/LASTCHANGE')
+    (stdout, retval) = _GetOutput([VERSION_TOOL, '-f', LASTCHANGE_FILE, '-t',
+                                  '@LASTCHANGE@'])
+    if retval:
+      return False
+    scm_revision = stdout.rstrip()
+
+  # See if the operation failed.
+  _RemoveKeys(plist, 'SCMRevision')
+  if scm_revision != None:
+    plist['SCMRevision'] = scm_revision
+  elif add_keys:
+    print >>sys.stderr, 'Could not determine SCM revision.  This may be OK.'
+
+  return True
+
+
+def _AddBreakpadKeys(plist, branding):
+  """Adds the Breakpad keys. This must be called AFTER _AddVersionKeys() and
+  also requires the |branding| argument."""
+  plist['BreakpadReportInterval'] = '3600'  # Deliberately a string.
+  plist['BreakpadProduct'] = '%s_Mac' % branding
+  plist['BreakpadProductDisplay'] = branding
+  plist['BreakpadVersion'] = plist['CFBundleShortVersionString']
+  # These are both deliberately strings and not boolean.
+  plist['BreakpadSendAndExit'] = 'YES'
+  plist['BreakpadSkipConfirm'] = 'YES'
+
+
+def _RemoveBreakpadKeys(plist):
+  """Removes any set Breakpad keys."""
+  _RemoveKeys(plist,
+      'BreakpadURL',
+      'BreakpadReportInterval',
+      'BreakpadProduct',
+      'BreakpadProductDisplay',
+      'BreakpadVersion',
+      'BreakpadSendAndExit',
+      'BreakpadSkipConfirm')
+
+
+def _TagSuffixes():
+  # Keep this list sorted in the order that tag suffix components are to
+  # appear in a tag value. That is to say, it should be sorted per ASCII.
+  components = ('32bit', 'full')
+  assert tuple(sorted(components)) == components
+
+  components_len = len(components)
+  combinations = 1 << components_len
+  tag_suffixes = []
+  for combination in xrange(0, combinations):
+    tag_suffix = ''
+    for component_index in xrange(0, components_len):
+      if combination & (1 << component_index):
+        tag_suffix += '-' + components[component_index]
+    tag_suffixes.append(tag_suffix)
+  return tag_suffixes
+
+
+def _AddKeystoneKeys(plist, bundle_identifier):
+  """Adds the Keystone keys. This must be called AFTER _AddVersionKeys() and
+  also requires the |bundle_identifier| argument (com.example.product)."""
+  plist['KSVersion'] = plist['CFBundleShortVersionString']
+  plist['KSProductID'] = bundle_identifier
+  plist['KSUpdateURL'] = 'https://tools.google.com/service/update2'
+
+  _RemoveKeys(plist, 'KSChannelID')
+  for tag_suffix in _TagSuffixes():
+    if tag_suffix:
+      plist['KSChannelID' + tag_suffix] = tag_suffix
+
+
+def _RemoveKeystoneKeys(plist):
+  """Removes any set Keystone keys."""
+  _RemoveKeys(plist,
+      'KSVersion',
+      'KSProductID',
+      'KSUpdateURL')
+
+  tag_keys = []
+  for tag_suffix in _TagSuffixes():
+    tag_keys.append('KSChannelID' + tag_suffix)
+  _RemoveKeys(plist, *tag_keys)
+
+
+def Main(argv):
+  parser = optparse.OptionParser('%prog [options]')
+  parser.add_option('--breakpad', dest='use_breakpad', action='store',
+      type='int', default=False, help='Enable Breakpad [1 or 0]')
+  parser.add_option('--breakpad_uploads', dest='breakpad_uploads',
+      action='store', type='int', default=False,
+      help='Enable Breakpad\'s uploading of crash dumps [1 or 0]')
+  parser.add_option('--keystone', dest='use_keystone', action='store',
+      type='int', default=False, help='Enable Keystone [1 or 0]')
+  parser.add_option('--scm', dest='add_scm_info', action='store', type='int',
+      default=True, help='Add SCM metadata [1 or 0]')
+  parser.add_option('--branding', dest='branding', action='store',
+      type='string', default=None, help='The branding of the binary')
+  parser.add_option('--bundle_id', dest='bundle_identifier',
+      action='store', type='string', default=None,
+      help='The bundle id of the binary')
+  parser.add_option('--version', dest='version', action='store', type='string',
+      default=None, help='The version string [major.minor.build.patch]')
+  (options, args) = parser.parse_args(argv)
+
+  if len(args) > 0:
+    print >>sys.stderr, parser.get_usage()
+    return 1
+
+  # Read the plist into its parsed format.
+  DEST_INFO_PLIST = os.path.join(env['TARGET_BUILD_DIR'], env['INFOPLIST_PATH'])
+  plist = plistlib.readPlist(DEST_INFO_PLIST)
+
+  # Insert the product version.
+  if not _AddVersionKeys(plist, version=options.version):
+    return 2
+
+  # Add Breakpad if configured to do so.
+  if options.use_breakpad:
+    if options.branding is None:
+      print >>sys.stderr, 'Use of Breakpad requires branding.'
+      return 1
+    _AddBreakpadKeys(plist, options.branding)
+    if options.breakpad_uploads:
+      plist['BreakpadURL'] = 'https://clients2.google.com/cr/report'
+    else:
+      # This allows crash dumping to a file without uploading the
+      # dump, for testing purposes.  Breakpad does not recognise
+      # "none" as a special value, but this does stop crash dump
+      # uploading from happening.  We need to specify something
+      # because if "BreakpadURL" is not present, Breakpad will not
+      # register its crash handler and no crash dumping will occur.
+      plist['BreakpadURL'] = 'none'
+  else:
+    _RemoveBreakpadKeys(plist)
+
+  # Only add Keystone in Release builds.
+  if options.use_keystone and env['CONFIGURATION'] == 'Release':
+    if options.bundle_identifier is None:
+      print >>sys.stderr, 'Use of Keystone requires the bundle id.'
+      return 1
+    _AddKeystoneKeys(plist, options.bundle_identifier)
+  else:
+    _RemoveKeystoneKeys(plist)
+
+  # Adds or removes any SCM keys.
+  if not _DoSCMKeys(plist, options.add_scm_info):
+    return 3
+
+  # Now that all keys have been mutated, rewrite the file.
+  temp_info_plist = tempfile.NamedTemporaryFile()
+  plistlib.writePlist(plist, temp_info_plist.name)
+
+  # Info.plist will work perfectly well in any plist format, but traditionally
+  # applications use xml1 for this, so convert it to ensure that it's valid.
+  proc = subprocess.Popen(['plutil', '-convert', 'xml1', '-o', DEST_INFO_PLIST,
+                           temp_info_plist.name])
+  proc.wait()
+  return proc.returncode
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/build/mac/verify_no_objc.sh b/build/mac/verify_no_objc.sh
new file mode 100755
index 0000000..e18a5ea
--- /dev/null
+++ b/build/mac/verify_no_objc.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Copyright (c) 2011 The Chromium 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 makes sure that no __OBJC,__image_info section appears in the
+# executable file built by the Xcode target that runs the script. If such a
+# section appears, the script prints an error message and exits nonzero.
+#
+# Why is this important?
+#
+# On 10.5, there's a bug in CFBundlePreflightExecutable that causes it to
+# crash when operating in an executable that has not loaded at its default
+# address (that is, when it's a position-independent executable with the
+# MH_PIE bit set in its mach_header) and the executable has an
+# __OBJC,__image_info section. See http://crbug.com/88697.
+#
+# Chrome's main executables don't use any Objective-C at all, and don't need
+# to carry this section around. Not linking them as Objective-C when they
+# don't need it anyway saves about 4kB in the linked executable, although most
+# of that 4kB is just filled with zeroes.
+#
+# This script makes sure that nobody goofs and accidentally introduces these
+# sections into the main executables.
+
+set -eu
+
+executable="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
+
+if xcrun otool -arch i386 -o "${executable}" | grep -q '^Contents.*section$'; \
+then
+  echo "${0}: ${executable} has an __OBJC,__image_info section" 2>&1
+  exit 1
+fi
+
+if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
+  echo "${0}: otool failed" 2>&1
+  exit 1
+fi
+
+exit 0
diff --git a/build/module_args/mojo.gni b/build/module_args/mojo.gni
new file mode 100644
index 0000000..efa5535
--- /dev/null
+++ b/build/module_args/mojo.gni
@@ -0,0 +1,38 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This variable should point to the parent directory of the Mojo SDK.
+mojo_sdk_root = "//third_party/mojo/src"
+
+# Chromium builds the network service from source, as it is the
+# producer of the network service.
+mojo_build_network_service_from_source = true
+
+# Chromium does not build dart apptests. Disable any Mojo targets which
+# depend on the apptest framework.
+mojo_disable_dart_apptest_framework = true
+
+# Points to the directory network_service is built from.
+mojo_network_service_root = "//mojo/services"
+
+declare_args() {
+  # The mojo shell is forked and built in the chromium repo.
+  mojo_build_mojo_shell_from_source = true
+
+  # Specify prebuilt network service mojo file location rather than download
+  # from gs://mojo.
+  #
+  # This variable only used when mojo_build_network_service_from_source is
+  # false.
+  #
+  # Currently only android_arm and linux_64 available on gs://mojo, and no plan
+  # to support more(https://codereview.chromium.org/921873003).
+  # It is needed for developers works on other platforms like android_x86 and
+  # android_x64. And it is also useful for supportted platform as well when
+  # developer want to try its own version of network service files.
+  mojo_prebuilt_network_service_location = ""
+
+  # For network_service_apptests.mojo
+  mojo_prebuilt_network_service_apptests_location = ""
+}
diff --git a/build/module_args/v8.gni b/build/module_args/v8.gni
new file mode 100644
index 0000000..8b5204c
--- /dev/null
+++ b/build/module_args/v8.gni
@@ -0,0 +1,13 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+  import("//build/config/android/config.gni")
+}
+
+# TODO(sky): nuke this. Temporary while sorting out http://crbug.com/465456.
+enable_correct_v8_arch = false
+
+v8_use_external_startup_data = !(is_chromeos || is_win)
+v8_extra_library_files = []
diff --git a/build/nocompile.gypi b/build/nocompile.gypi
new file mode 100644
index 0000000..8c0f288
--- /dev/null
+++ b/build/nocompile.gypi
@@ -0,0 +1,96 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an target to create a unittest that
+# invokes a set of no-compile tests.  A no-compile test is a test that asserts
+# a particular construct will not compile.
+#
+# Also see:
+#   http://dev.chromium.org/developers/testing/no-compile-tests
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_module_nc_unittests',
+#   'type': 'executable',
+#   'sources': [
+#     'nc_testset_1.nc',
+#     'nc_testset_2.nc',
+#   ],
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# The .nc files are C++ files that contain code we wish to assert will not
+# compile.  Each individual test case in the file should be put in its own
+# #ifdef section.  The expected output should be appended with a C++-style
+# comment that has a python list of regular expressions.  This will likely
+# be greater than 80-characters. Giving a solid expected output test is
+# important so that random compile failures do not cause the test to pass.
+#
+# Example .nc file:
+#
+#   #if defined(TEST_NEEDS_SEMICOLON)  // [r"expected ',' or ';' at end of input"]
+#
+#   int a = 1
+#
+#   #elif defined(TEST_NEEDS_CAST)  // [r"invalid conversion from 'void*' to 'char*'"]
+#
+#   void* a = NULL;
+#   char* b = a;
+#
+#   #endif
+#
+# If we needed disable TEST_NEEDS_SEMICOLON, then change the define to:
+#
+#   DISABLE_TEST_NEEDS_SEMICOLON
+#   TEST_NEEDS_CAST
+#
+# The lines above are parsed by a regexp so avoid getting creative with the
+# formatting or ifdef logic; it will likely just not work.
+#
+# Implementation notes:
+# The .nc files are actually processed by a python script which executes the
+# compiler and generates a .cc file that is empty on success, or will have a
+# series of #error lines on failure, and a set of trivially passing gunit
+# TEST() functions on success. This allows us to fail at the compile step when
+# something goes wrong, and know during the unittest run that the test was at
+# least processed when things go right.
+
+{
+  # TODO(awong): Disabled until http://crbug.com/105388 is resolved.
+  'sources/': [['exclude', '\\.nc$']],
+  'conditions': [
+    [ 'OS!="win" and clang==1', {
+      'rules': [
+        {
+          'variables': {
+            'nocompile_driver': '<(DEPTH)/tools/nocompile_driver.py',
+            'nc_result_path': ('<(INTERMEDIATE_DIR)/<(module_dir)/'
+                               '<(RULE_INPUT_ROOT)_nc.cc'),
+           },
+          'rule_name': 'run_nocompile',
+          'extension': 'nc',
+          'inputs': [
+            '<(nocompile_driver)',
+          ],
+          'outputs': [
+            '<(nc_result_path)'
+          ],
+          'action': [
+            'python',
+            '<(nocompile_driver)',
+            '4', # number of compilers to invoke in parallel.
+            '<(RULE_INPUT_PATH)',
+            '-Wall -Werror -Wfatal-errors -I<(DEPTH)',
+            '<(nc_result_path)',
+            ],
+          'message': 'Generating no compile results for <(RULE_INPUT_PATH)',
+          'process_outputs_as_sources': 1,
+        },
+      ],
+    }, {
+      'sources/': [['exclude', '\\.nc$']]
+    }],  # 'OS!="win" and clang=="1"'
+  ],
+}
+
diff --git a/build/output_dll_copy.rules b/build/output_dll_copy.rules
new file mode 100644
index 0000000..c6e9051
--- /dev/null
+++ b/build/output_dll_copy.rules
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<VisualStudioToolFile
+	Name="Output DLL copy"
+	Version="8.00"
+	>
+	<Rules>
+		<CustomBuildRule
+			Name="Output DLL copy"
+			CommandLine="xcopy /R /C /Y $(InputPath) $(OutDir)"
+			Outputs="$(OutDir)\$(InputFileName)"
+			FileExtensions="*.dll"
+			>
+			<Properties>
+			</Properties>
+		</CustomBuildRule>
+	</Rules>
+</VisualStudioToolFile>
diff --git a/build/precompile.cc b/build/precompile.cc
new file mode 100644
index 0000000..db1ef6d
--- /dev/null
+++ b/build/precompile.cc
@@ -0,0 +1,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.
+
+// Precompiled header generator for Windows builds. No include is needed
+// in this file as the PCH include is forced via the "Forced Include File"
+// flag in the projects generated by GYP.
diff --git a/build/precompile.h b/build/precompile.h
new file mode 100644
index 0000000..32c2f11
--- /dev/null
+++ b/build/precompile.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.
+
+// Precompiled header for Chromium project on Windows, not used by
+// other build configurations. Using precompiled headers speeds the
+// build up significantly, around 1/4th on VS 2010 on an HP Z600 with 12
+// GB of memory.
+//
+// Numeric comments beside includes are the number of times they were
+// included under src/chrome/browser on 2011/8/20, which was used as a
+// baseline for deciding what to include in the PCH. Includes without
+// a numeric comment are generally included at least 5 times. It may
+// be possible to tweak the speed of the build by commenting out or
+// removing some of the less frequently used headers.
+
+#if defined(BUILD_PRECOMPILE_H_)
+#error You shouldn't include the precompiled header file more than once.
+#endif
+
+#define BUILD_PRECOMPILE_H_
+
+#define _USE_MATH_DEFINES
+
+// The Windows header needs to come before almost all the other
+// Windows-specific headers.
+#include <Windows.h>
+#include <dwmapi.h>
+#include <shellapi.h>
+#include <wtypes.h>  // 2
+
+// Defines in atlbase.h cause conflicts; if we could figure out how
+// this family of headers can be included in the PCH, it might speed
+// up the build as several of them are used frequently.
+/*
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcom.h>
+#include <atlcrack.h>  // 2
+#include <atlctrls.h>  // 2
+#include <atlmisc.h>  // 2
+#include <atlsafe.h>  // 1
+#include <atltheme.h>  // 1
+#include <atlwin.h>  // 2
+*/
+
+// Objbase.h and other files that rely on it bring in [ #define
+// interface struct ] which can cause problems in a multi-platform
+// build like Chrome's. #undef-ing it does not work as there are
+// currently 118 targets that break if we do this, so leaving out of
+// the precompiled header for now.
+//#include <commctrl.h>  // 2
+//#include <commdlg.h>  // 3
+//#include <cryptuiapi.h>  // 2
+//#include <Objbase.h>  // 2
+//#include <objidl.h>  // 1
+//#include <ole2.h>  // 1
+//#include <oleacc.h>  // 2
+//#include <oleauto.h>  // 1
+//#include <oleidl.h>  // 1
+//#include <propkey.h>  // 2
+//#include <propvarutil.h>  // 2
+//#include <pstore.h>  // 2
+//#include <shlguid.h>  // 1
+//#include <shlwapi.h>  // 1
+//#include <shobjidl.h>  // 4
+//#include <urlhist.h>  // 2
+
+// Caused other conflicts in addition to the 'interface' issue above.
+// #include <shlobj.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>  // 4
+#include <math.h>
+#include <memory.h>  // 1
+#include <signal.h>
+#include <stdarg.h>  // 1
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>  // 4
+
+#include <algorithm>
+#include <bitset>  // 3
+#include <cmath>
+#include <cstddef>
+#include <cstdio>  // 3
+#include <cstdlib>  // 2
+#include <cstring>
+#include <deque>
+#include <fstream>  // 3
+#include <functional>
+#include <iomanip>  // 2
+#include <iosfwd>  // 2
+#include <iterator>
+#include <limits>
+#include <list>
+#include <map>
+#include <numeric>  // 2
+#include <ostream>
+#include <queue>
+#include <set>
+#include <sstream>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
diff --git a/build/protoc.gypi b/build/protoc.gypi
new file mode 100644
index 0000000..fafdf9d
--- /dev/null
+++ b/build/protoc.gypi
@@ -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 is meant to be included into a target to provide a rule
+# to invoke protoc in a consistent manner. For Java-targets, see
+# protoc_java.gypi.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_proto_lib',
+#   'type': 'static_library',
+#   'sources': [
+#     'foo.proto',
+#     'bar.proto',
+#   ],
+#   'variables': {
+#     # Optional, see below: 'proto_in_dir': '.'
+#     'proto_out_dir': 'dir/for/my_proto_lib'
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+# If necessary, you may add normal .cc files to the sources list or other gyp
+# dependencies.  The proto headers are guaranteed to be generated before any
+# source files, even within this target, are compiled.
+#
+# The 'proto_in_dir' variable must be the relative path to the
+# directory containing the .proto files.  If left out, it defaults to '.'.
+#
+# The 'proto_out_dir' variable specifies the path suffix that output
+# files are generated under.  Targets that gyp-depend on my_proto_lib
+# will be able to include the resulting proto headers with an include
+# like:
+#   #include "dir/for/my_proto_lib/foo.pb.h"
+#
+# If you need to add an EXPORT macro to a protobuf's c++ header, set the
+# 'cc_generator_options' variable with the value: 'dllexport_decl=FOO_EXPORT:'
+# e.g. 'dllexport_decl=BASE_EXPORT:'
+#
+# It is likely you also need to #include a file for the above EXPORT macro to
+# work. You can do so with the 'cc_include' variable.
+# e.g. 'base/base_export.h'
+#
+# Implementation notes:
+# A proto_out_dir of foo/bar produces
+#   <(SHARED_INTERMEDIATE_DIR)/protoc_out/foo/bar/{file1,file2}.pb.{cc,h}
+#   <(SHARED_INTERMEDIATE_DIR)/pyproto/foo/bar/{file1,file2}_pb2.py
+
+{
+  'variables': {
+    'protoc_wrapper': '<(DEPTH)/tools/protoc_wrapper/protoc_wrapper.py',
+    'cc_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out/<(proto_out_dir)',
+    'py_dir': '<(PRODUCT_DIR)/pyproto/<(proto_out_dir)',
+    'cc_generator_options%': '',
+    'cc_include%': '',
+    'proto_in_dir%': '.',
+    'conditions': [
+      ['use_system_protobuf==0', {
+        'protoc': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
+      }, { # use_system_protobuf==1
+        'protoc': '<!(which protoc)',
+      }],
+    ],
+  },
+  'rules': [
+    {
+      'rule_name': 'genproto',
+      'extension': 'proto',
+      'inputs': [
+        '<(protoc_wrapper)',
+        '<(protoc)',
+      ],
+      'outputs': [
+        '<(py_dir)/<(RULE_INPUT_ROOT)_pb2.py',
+        '<(cc_dir)/<(RULE_INPUT_ROOT).pb.cc',
+        '<(cc_dir)/<(RULE_INPUT_ROOT).pb.h',
+      ],
+      'action': [
+        'python',
+        '<(protoc_wrapper)',
+        '--include',
+        '<(cc_include)',
+        '--protobuf',
+        '<(cc_dir)/<(RULE_INPUT_ROOT).pb.h',
+        # Using the --arg val form (instead of --arg=val) allows gyp's msvs rule
+        # generation to correct 'val' which is a path.
+        '--proto-in-dir','<(proto_in_dir)',
+        # Naively you'd use <(RULE_INPUT_PATH) here, but protoc requires
+        # --proto_path is a strict prefix of the path given as an argument.
+        '--proto-in-file','<(RULE_INPUT_ROOT)<(RULE_INPUT_EXT)',
+        '--use-system-protobuf=<(use_system_protobuf)',
+        '--',
+        '<(protoc)',
+        '--cpp_out', '<(cc_generator_options)<(cc_dir)',
+        '--python_out', '<(py_dir)',
+      ],
+      'message': 'Generating C++ and Python code from <(RULE_INPUT_PATH)',
+      'process_outputs_as_sources': 1,
+    },
+  ],
+  'dependencies': [
+    '<(DEPTH)/third_party/protobuf/protobuf.gyp:protoc#host',
+    '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite',
+  ],
+  'include_dirs': [
+    '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
+    '<(DEPTH)',
+  ],
+  'direct_dependent_settings': {
+    'include_dirs': [
+      '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
+      '<(DEPTH)',
+    ]
+  },
+  'export_dependent_settings': [
+    # The generated headers reference headers within protobuf_lite,
+    # so dependencies must be able to find those headers too.
+    '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite',
+  ],
+  # This target exports a hard dependency because it generates header
+  # files.
+  'hard_dependency': 1,
+}
diff --git a/build/protoc_java.gypi b/build/protoc_java.gypi
new file mode 100644
index 0000000..6fd80d8
--- /dev/null
+++ b/build/protoc_java.gypi
@@ -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.
+
+# This file is meant to be included into a target to provide a rule
+# to invoke protoc in a consistent manner. This is only to be included
+# for Java targets. When including this file, a .jar-file will be generated.
+# For other targets, see protoc.gypi.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_proto_lib',
+#   'sources': [
+#     'foo.proto',
+#     'bar.proto',
+#   ],
+#   'variables': {
+#     'proto_in_dir': '.'
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# The 'proto_in_dir' variable must be the relative path to the
+# directory containing the .proto files.  If left out, it defaults to '.'.
+#
+# The 'output_java_files' variable specifies a list of output files that will
+# be generated. It is based on the package and java_outer_classname fields in
+# the proto. All the values must be prefixed with >(java_out_dir), since that
+# is the root directory of all the output.
+#
+# Implementation notes:
+# A target_name of foo and proto-specified 'package' java.package.path produces:
+#   <(PRODUCT_DIR)/java_proto/foo/{java/package/path/}{Foo,Bar}.java
+# where Foo and Bar are taken from 'java_outer_classname' of the protos.
+#
+# How the .jar-file is created is different than how protoc is used for other
+# targets, and as such, this lives in its own file.
+
+{
+  'variables': {
+    'protoc': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)android_protoc<(EXECUTABLE_SUFFIX)',
+    'java_out_dir': '<(PRODUCT_DIR)/java_proto/<(_target_name)/src',
+    'proto_in_dir%': '.',
+    'stamp_file': '<(java_out_dir).stamp',
+    'script': '<(DEPTH)/build/protoc_java.py',
+
+    # The rest of the variables here are for the java.gypi include.
+    'java_in_dir': '<(DEPTH)/build/android/empty',
+    'generated_src_dirs': ['<(java_out_dir)'],
+    # Adding the |stamp_file| to |additional_input_paths| makes the actions in
+    # the include of java.gypi depend on the genproto_java action.
+    'additional_input_paths': ['<(stamp_file)'],
+    'run_findbugs': 0,
+  },
+  'actions': [
+    {
+      'action_name': 'genproto_java',
+      'inputs': [
+        '<(script)',
+        '<(protoc)',
+        '<@(_sources)',
+      ],
+      # We do not know the names of the generated files, so we use a stamp.
+      'outputs': [
+        '<(stamp_file)',
+      ],
+      'action': [
+        '<(script)',
+        '--protoc=<(protoc)',
+        '--proto-path=<(proto_in_dir)',
+        '--java-out-dir=<(java_out_dir)',
+        '--stamp=<(stamp_file)',
+        '<@(_sources)',
+      ],
+      'message': 'Generating Java code from protobuf files in <(proto_in_dir)',
+    },
+  ],
+  'dependencies': [
+    '<(DEPTH)/third_party/android_protobuf/android_protobuf.gyp:android_protoc#host',
+    '<(DEPTH)/third_party/android_protobuf/android_protobuf.gyp:protobuf_nano_javalib',
+  ],
+  'includes': [ 'java.gypi' ],
+}
diff --git a/build/protoc_java.py b/build/protoc_java.py
new file mode 100755
index 0000000..470667c
--- /dev/null
+++ b/build/protoc_java.py
@@ -0,0 +1,68 @@
+#!/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.
+
+"""Generate java source files from protobuf files.
+
+This is a helper file for the genproto_java action in protoc_java.gypi.
+
+It performs the following steps:
+1. Deletes all old sources (ensures deleted classes are not part of new jars).
+2. Creates source directory.
+3. Generates Java files using protoc (output into either --java-out-dir or
+   --srcjar).
+4. Creates a new stamp file.
+"""
+
+import os
+import optparse
+import shutil
+import subprocess
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "android", "gyp"))
+from util import build_utils
+
+def main(argv):
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_option("--protoc", help="Path to protoc binary.")
+  parser.add_option("--proto-path", help="Path to proto directory.")
+  parser.add_option("--java-out-dir",
+      help="Path to output directory for java files.")
+  parser.add_option("--srcjar", help="Path to output srcjar.")
+  parser.add_option("--stamp", help="File to touch on success.")
+  options, args = parser.parse_args(argv)
+
+  build_utils.CheckOptions(options, parser, ['protoc', 'proto_path'])
+  if not options.java_out_dir and not options.srcjar:
+    print 'One of --java-out-dir or --srcjar must be specified.'
+    return 1
+
+  with build_utils.TempDir() as temp_dir:
+    # Specify arguments to the generator.
+    generator_args = ['optional_field_style=reftypes',
+                      'store_unknown_fields=true']
+    out_arg = '--javanano_out=' + ','.join(generator_args) + ':' + temp_dir
+    # Generate Java files using protoc.
+    build_utils.CheckOutput(
+        [options.protoc, '--proto_path', options.proto_path, out_arg]
+        + args)
+
+    if options.java_out_dir:
+      build_utils.DeleteDirectory(options.java_out_dir)
+      shutil.copytree(temp_dir, options.java_out_dir)
+    else:
+      build_utils.ZipDir(options.srcjar, temp_dir)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        args + [options.protoc] + build_utils.GetPythonDependencies())
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/release.gypi b/build/release.gypi
new file mode 100644
index 0000000..9b8b11d
--- /dev/null
+++ b/build/release.gypi
@@ -0,0 +1,29 @@
+{
+  'conditions': [
+    # Handle build types.
+    ['buildtype=="Dev"', {
+      'includes': ['internal/release_impl.gypi'],
+    }],
+    ['buildtype=="Dev" and incremental_chrome_dll==1', {
+      'msvs_settings': {
+        'VCLinkerTool': {
+          # Enable incremental linking and disable conflicting link options:
+          # http://msdn.microsoft.com/en-us/library/4khtbfyf.aspx
+          'LinkIncremental': '2',
+          'OptimizeReferences': '1',
+          'EnableCOMDATFolding': '1',
+          'Profile': 'false',
+        },
+      },
+    }],
+    ['buildtype=="Official"', {
+      'includes': ['internal/release_impl_official.gypi'],
+    }],
+    # TODO(bradnelson): may also need:
+    #     checksenabled
+    #     coverage
+    #     dom_stats
+    #     pgo_instrument
+    #     pgo_optimize
+  ],
+}
diff --git a/build/repack_action.gypi b/build/repack_action.gypi
new file mode 100644
index 0000000..04b982a
--- /dev/null
+++ b/build/repack_action.gypi
@@ -0,0 +1,31 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into an action to invoke grit repack in a
+# consistent manner. To use this the following variables need to be
+# defined:
+#   pak_inputs: list: paths of pak files that need to be combined.
+#   pak_output: string: the output pak file path.
+
+{
+  # GYP version: //tools/grit/repack.gni
+  'variables': {
+    'repack_path': '<(DEPTH)/tools/grit/grit/format/repack.py',
+    'repack_options%': [],
+  },
+  'inputs': [
+    '<(repack_path)',
+    '<@(pak_inputs)',
+  ],
+  'outputs': [
+    '<(pak_output)'
+  ],
+  'action': [
+    'python',
+    '<(repack_path)',
+    '<@(repack_options)',
+    '<(pak_output)',
+    '<@(pak_inputs)',
+  ],
+}
diff --git a/build/rmdir_and_stamp.py b/build/rmdir_and_stamp.py
new file mode 100755
index 0000000..6aa11f8
--- /dev/null
+++ b/build/rmdir_and_stamp.py
@@ -0,0 +1,45 @@
+#!/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.
+
+"""Wipes out a directory recursively and then touches a stamp file.
+
+This odd pairing of operations is used to support build scripts which
+slurp up entire directories (e.g. build/android/javac.py when handling
+generated sources) as inputs.
+
+The general pattern of use is:
+
+  - Add a target which generates |gen_sources| into |out_path| from |inputs|.
+  - Include |stamp_file| as an input for that target or any of its rules which
+    generate files in |out_path|.
+  - Add an action which depends on |inputs| and which outputs |stamp_file|;
+    the action should run this script and pass |out_path| and |stamp_file| as
+    its arguments.
+
+The net result is that you will force |out_path| to be wiped and all
+|gen_sources| to be regenerated any time any file in |inputs| changes.
+
+See //third_party/mojo/mojom_bindings_generator.gypi for an example use case.
+
+"""
+
+import errno
+import os
+import shutil
+import sys
+
+
+def Main(dst_dir, stamp_file):
+  try:
+    shutil.rmtree(os.path.normpath(dst_dir))
+  except OSError as e:
+    # Ignore only "not found" errors.
+    if e.errno != errno.ENOENT:
+      raise e
+  with open(stamp_file, 'a'):
+    os.utime(stamp_file, None)
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1], sys.argv[2]))
diff --git a/build/sanitize-mac-build-log.sed b/build/sanitize-mac-build-log.sed
new file mode 100644
index 0000000..b4111c7
--- /dev/null
+++ b/build/sanitize-mac-build-log.sed
@@ -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.
+
+# Use this sed script to reduce a Mac build log into something readable.
+
+# Drop uninformative lines.
+/^distcc/d
+/^Check dependencies/d
+/^    setenv /d
+/^    cd /d
+/^make: Nothing to be done/d
+/^$/d
+
+# Xcode prints a short "compiling foobar.o" line followed by the lengthy
+# full command line.  These deletions drop the command line.
+\|^    /Developer/usr/bin/|d
+\|^    /Developer/Library/PrivateFrameworks/DevToolsCore\.framework/|d
+\|^    /Developer/Library/Xcode/Plug-ins/CoreBuildTasks\.xcplugin/|d
+
+# Drop any goma command lines as well.
+\|^    .*/gomacc |d
+
+# And, if you've overridden something from your own bin directory, remove those
+# full command lines, too.
+\|^    /Users/[^/]*/bin/|d
+
+# There's already a nice note for bindings, don't need the command line.
+\|^python scripts/rule_binding\.py|d
+
+# Shorten the "compiling foobar.o" line.
+s|^Distributed-CompileC (.*) normal i386 c\+\+ com\.apple\.compilers\.gcc\.4_2|    CC \1|
+s|^CompileC (.*) normal i386 c\+\+ com\.apple\.compilers\.gcc\.4_2|    CC \1|
diff --git a/build/sanitize-mac-build-log.sh b/build/sanitize-mac-build-log.sh
new file mode 100755
index 0000000..df5a7af
--- /dev/null
+++ b/build/sanitize-mac-build-log.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# 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.
+sed -r -f `dirname "${0}"`/`basename "${0}" sh`sed
diff --git a/build/sanitize-win-build-log.sed b/build/sanitize-win-build-log.sed
new file mode 100644
index 0000000..c18e664
--- /dev/null
+++ b/build/sanitize-win-build-log.sed
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Use this sed script to reduce a Windows build log into something
+# machine-parsable.
+
+# Drop uninformative lines.
+/The operation completed successfully\./d
+
+# Drop parallelization indicators on lines.
+s/^[0-9]+>//
+
+# Shorten bindings generation lines
+s/^.*"python".*idl_compiler\.py".*("[^"]+\.idl").*$/  idl_compiler \1/
diff --git a/build/sanitize-win-build-log.sh b/build/sanitize-win-build-log.sh
new file mode 100755
index 0000000..df5a7af
--- /dev/null
+++ b/build/sanitize-win-build-log.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# 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.
+sed -r -f `dirname "${0}"`/`basename "${0}" sh`sed
diff --git a/build/sanitizers/BUILD.gn b/build/sanitizers/BUILD.gn
new file mode 100644
index 0000000..4f81f3e
--- /dev/null
+++ b/build/sanitizers/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_linux && !is_chromeos) {
+  # TODO(GYP): Figure out which of these work and are needed on other platforms.
+  copy("copy_llvm_symbolizer") {
+    if (is_win) {
+      sources = [
+        "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer.exe",
+      ]
+      outputs = [
+        "$root_out_dir/llvm-symbolizer.exe",
+      ]
+    } else {
+      sources = [
+        "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer",
+      ]
+      outputs = [
+        "$root_out_dir/llvm-symbolizer",
+      ]
+    }
+  }
+}
diff --git a/build/sanitizers/OWNERS b/build/sanitizers/OWNERS
new file mode 100644
index 0000000..0be2be8
--- /dev/null
+++ b/build/sanitizers/OWNERS
@@ -0,0 +1,4 @@
+glider@chromium.org
+earthdok@chromium.org
+per-file tsan_suppressions.cc=*
+per-file lsan_suppressions.cc=*
diff --git a/build/sanitizers/asan_suppressions.cc b/build/sanitizers/asan_suppressions.cc
new file mode 100644
index 0000000..df94bc8
--- /dev/null
+++ b/build/sanitizers/asan_suppressions.cc
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the default suppressions for AddressSanitizer.
+// It should only be used under very limited circumstances such as suppressing
+// a report caused by an interceptor call in a system-installed library.
+
+#if defined(ADDRESS_SANITIZER)
+
+// Please make sure the code below declares a single string variable
+// kASanDefaultSuppressions which contains ASan suppressions delimited by
+// newlines.
+char kASanDefaultSuppressions[] =
+// http://crbug.com/178677
+"interceptor_via_lib:libsqlite3.so\n"
+
+// PLEASE READ ABOVE BEFORE ADDING NEW SUPPRESSIONS.
+
+// End of suppressions.
+;  // Please keep this semicolon.
+
+#endif  // ADDRESS_SANITIZER
diff --git a/build/sanitizers/lsan_suppressions.cc b/build/sanitizers/lsan_suppressions.cc
new file mode 100644
index 0000000..ac2defa
--- /dev/null
+++ b/build/sanitizers/lsan_suppressions.cc
@@ -0,0 +1,105 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the default suppressions for LeakSanitizer.
+// You can also pass additional suppressions via LSAN_OPTIONS:
+// LSAN_OPTIONS=suppressions=/path/to/suppressions. Please refer to
+// http://dev.chromium.org/developers/testing/leaksanitizer for more info.
+
+#if defined(LEAK_SANITIZER)
+
+// Please make sure the code below declares a single string variable
+// kLSanDefaultSuppressions which contains LSan suppressions delimited by
+// newlines. See http://dev.chromium.org/developers/testing/leaksanitizer
+// for the instructions on writing suppressions.
+char kLSanDefaultSuppressions[] =
+// Intentional leak used as sanity test for Valgrind/memcheck.
+"leak:base::ToolsSanityTest_MemoryLeak_Test::TestBody\n"
+
+// ================ Leaks in third-party code ================
+
+// False positives in libfontconfig. http://crbug.com/39050
+"leak:libfontconfig\n"
+
+// Leaks in Nvidia's libGL.
+"leak:libGL.so\n"
+
+// A small leak in V8. http://crbug.com/46571#c9
+"leak:blink::V8GCController::collectGarbage\n"
+
+// TODO(earthdok): revisit NSS suppressions after the switch to BoringSSL
+// NSS leaks in CertDatabaseNSSTest tests. http://crbug.com/51988
+"leak:net::NSSCertDatabase::ImportFromPKCS12\n"
+"leak:net::NSSCertDatabase::ListCerts\n"
+"leak:net::NSSCertDatabase::DeleteCertAndKey\n"
+"leak:crypto::ScopedTestNSSDB::ScopedTestNSSDB\n"
+// Another leak due to not shutting down NSS properly. http://crbug.com/124445
+"leak:error_get_my_stack\n"
+// The NSS suppressions above will not fire when the fast stack unwinder is
+// used, because it can't unwind through NSS libraries. Apply blanket
+// suppressions for now.
+"leak:libnssutil3\n"
+"leak:libnspr4\n"
+"leak:libnss3\n"
+"leak:libplds4\n"
+"leak:libnssckbi\n"
+
+// XRandR has several one time leaks.
+"leak:libxrandr\n"
+
+// xrandr leak. http://crbug.com/119677
+"leak:XRRFindDisplay\n"
+
+// Suppressions for objects which can be owned by the V8 heap. This is a
+// temporary workaround until LeakSanitizer supports the V8 heap.
+// Those should only fire in (browser)tests. If you see one of them in Chrome,
+// then it's a real leak.
+// http://crbug.com/328552
+"leak:WTF::StringImpl::createUninitialized\n"
+"leak:WTF::StringImpl::create8BitIfPossible\n"
+"leak:blink::MouseEvent::create\n"
+"leak:blink::*::*GetterCallback\n"
+"leak:blink::CSSComputedStyleDeclaration::create\n"
+"leak:blink::V8PerIsolateData::ensureDomInJSContext\n"
+"leak:gin/object_template_builder.h\n"
+"leak:gin::internal::Dispatcher\n"
+"leak:blink::LocalDOMWindow::getComputedStyle\n"
+// This should really be RemoteDOMWindow::create, but symbolization is
+// weird in release builds. https://crbug.com/484760
+"leak:blink::RemoteFrame::create\n"
+// Likewise, this should really be blink::WindowProxy::initializeIfNeeded.
+// https://crbug.com/484760
+"leak:blink::WindowProxy::createContext\n"
+
+// http://crbug.com/356785
+"leak:content::RenderViewImplTest_DecideNavigationPolicyForWebUI_Test::TestBody\n"
+
+// ================ Leaks in Chromium code ================
+// PLEASE DO NOT ADD SUPPRESSIONS FOR NEW LEAKS.
+// Instead, commits that introduce memory leaks should be reverted. Suppressing
+// the leak is acceptable in some cases when reverting is impossible, i.e. when
+// enabling leak detection for the first time for a test target with
+// pre-existing leaks.
+
+// Small test-only leak in ppapi_unittests. http://crbug.com/258113
+"leak:ppapi::proxy::PPP_Instance_Private_ProxyTest_PPPInstancePrivate_Test\n"
+
+// http://crbug.com/322671
+"leak:content::SpeechRecognitionBrowserTest::SetUpOnMainThread\n"
+
+// http://crbug.com/355641
+"leak:TrayAccessibilityTest\n"
+
+// http://crbug.com/354644
+"leak:CertificateViewerUITest::ShowModalCertificateViewer\n"
+
+// http://crbug.com/356306
+"leak:content::SetProcessTitleFromCommandLine\n"
+
+// PLEASE READ ABOVE BEFORE ADDING NEW SUPPRESSIONS.
+
+// End of suppressions.
+;  // Please keep this semicolon.
+
+#endif  // LEAK_SANITIZER
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc
new file mode 100644
index 0000000..a659a22
--- /dev/null
+++ b/build/sanitizers/sanitizer_options.cc
@@ -0,0 +1,164 @@
+// Copyright 2014 The Chromium 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 default options for various compiler-based dynamic
+// tools.
+
+#include "build/build_config.h"
+
+#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
+#include <crt_externs.h>  // for _NSGetArgc, _NSGetArgv
+#include <string.h>
+#endif  // ADDRESS_SANITIZER && OS_MACOSX
+
+#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
+    defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER)
+// Functions returning default options are declared weak in the tools' runtime
+// libraries. To make the linker pick the strong replacements for those
+// functions from this module, we explicitly force its inclusion by passing
+// -Wl,-u_sanitizer_options_link_helper
+extern "C"
+void _sanitizer_options_link_helper() { }
+
+// The callbacks we define here will be called from the sanitizer runtime, but
+// aren't referenced from the Chrome executable. We must ensure that those
+// callbacks are not sanitizer-instrumented, and that they aren't stripped by
+// the linker.
+#define SANITIZER_HOOK_ATTRIBUTE          \
+  extern "C"                              \
+  __attribute__((no_sanitize_address))    \
+  __attribute__((no_sanitize_memory))     \
+  __attribute__((no_sanitize_thread))     \
+  __attribute__((visibility("default")))  \
+  __attribute__((used))
+#endif
+
+#if defined(ADDRESS_SANITIZER)
+// Default options for AddressSanitizer in various configurations:
+//   malloc_context_size=5 - limit the size of stack traces collected by ASan
+//     for each malloc/free by 5 frames. These stack traces tend to accumulate
+//     very fast in applications using JIT (v8 in Chrome's case), see
+//     https://code.google.com/p/address-sanitizer/issues/detail?id=177
+//   symbolize=false - disable the in-process symbolization, which isn't 100%
+//     compatible with the existing sandboxes and doesn't make much sense for
+//     stripped official binaries.
+//   legacy_pthread_cond=1 - run in the libpthread 2.2.5 compatibility mode to
+//     work around libGL.so using the obsolete API, see
+//     http://crbug.com/341805. This may break if pthread_cond_t objects are
+//     accessed by both instrumented and non-instrumented binaries (e.g. if
+//     they reside in shared memory). This option is going to be deprecated in
+//     upstream AddressSanitizer and must not be used anywhere except the
+//     official builds.
+//   check_printf=1 - check the memory accesses to printf (and other formatted
+//     output routines) arguments.
+//   use_sigaltstack=1 - handle signals on an alternate signal stack. Useful
+//     for stack overflow detection.
+//   strip_path_prefix=Release/../../ - prefixes up to and including this
+//     substring will be stripped from source file paths in symbolized reports
+//     (if symbolize=true, which is set when running with LeakSanitizer).
+//   fast_unwind_on_fatal=1 - use the fast (frame-pointer-based) stack unwinder
+//     to print error reports. V8 doesn't generate debug info for the JIT code,
+//     so the slow unwinder may not work properly.
+//   detect_stack_use_after_return=1 - use fake stack to delay the reuse of
+//     stack allocations and detect stack-use-after-return errors.
+#if defined(OS_LINUX)
+#if defined(GOOGLE_CHROME_BUILD)
+// Default AddressSanitizer options for the official build. These do not affect
+// tests on buildbots (which don't set GOOGLE_CHROME_BUILD) or non-official
+// Chromium builds.
+const char kAsanDefaultOptions[] =
+    "legacy_pthread_cond=1 malloc_context_size=5 "
+    "symbolize=false check_printf=1 use_sigaltstack=1 detect_leaks=0 "
+    "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1";
+#else
+// Default AddressSanitizer options for buildbots and non-official builds.
+const char *kAsanDefaultOptions =
+    "symbolize=false check_printf=1 use_sigaltstack=1 "
+    "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 "
+    "detect_stack_use_after_return=1 ";
+#endif  // GOOGLE_CHROME_BUILD
+
+#elif defined(OS_MACOSX)
+const char *kAsanDefaultOptions =
+    "check_printf=1 use_sigaltstack=1 "
+    "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 "
+    "detect_stack_use_after_return=1 detect_odr_violation=0 ";
+static const char kNaClDefaultOptions[] = "handle_segv=0";
+static const char kNaClFlag[] = "--type=nacl-loader";
+#endif  // OS_LINUX
+
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+SANITIZER_HOOK_ATTRIBUTE const char *__asan_default_options() {
+#if defined(OS_MACOSX)
+  char*** argvp = _NSGetArgv();
+  int* argcp = _NSGetArgc();
+  if (!argvp || !argcp) return kAsanDefaultOptions;
+  char** argv = *argvp;
+  int argc = *argcp;
+  for (int i = 0; i < argc; ++i) {
+    if (strcmp(argv[i], kNaClFlag) == 0) {
+      return kNaClDefaultOptions;
+    }
+  }
+#endif
+  return kAsanDefaultOptions;
+}
+
+extern "C" char kASanDefaultSuppressions[];
+
+SANITIZER_HOOK_ATTRIBUTE const char *__asan_default_suppressions() {
+  return kASanDefaultSuppressions;
+}
+#endif  // OS_LINUX || OS_MACOSX
+#endif  // ADDRESS_SANITIZER
+
+#if defined(THREAD_SANITIZER) && defined(OS_LINUX)
+// Default options for ThreadSanitizer in various configurations:
+//   detect_deadlocks=1 - enable deadlock (lock inversion) detection.
+//   second_deadlock_stack=1 - more verbose deadlock reports.
+//   report_signal_unsafe=0 - do not report async-signal-unsafe functions
+//     called from signal handlers.
+//   report_thread_leaks=0 - do not report unjoined threads at the end of
+//     the program execution.
+//   print_suppressions=1 - print the list of matched suppressions.
+//   history_size=7 - make the history buffer proportional to 2^7 (the maximum
+//     value) to keep more stack traces.
+//   strip_path_prefix=Release/../../ - prefixes up to and including this
+//     substring will be stripped from source file paths in symbolized reports.
+const char kTsanDefaultOptions[] =
+    "detect_deadlocks=1 second_deadlock_stack=1 report_signal_unsafe=0 "
+    "report_thread_leaks=0 print_suppressions=1 history_size=7 "
+    "strip_path_prefix=Release/../../ ";
+
+SANITIZER_HOOK_ATTRIBUTE const char *__tsan_default_options() {
+  return kTsanDefaultOptions;
+}
+
+extern "C" char kTSanDefaultSuppressions[];
+
+SANITIZER_HOOK_ATTRIBUTE const char *__tsan_default_suppressions() {
+  return kTSanDefaultSuppressions;
+}
+
+#endif  // THREAD_SANITIZER && OS_LINUX
+
+#if defined(LEAK_SANITIZER)
+// Default options for LeakSanitizer:
+//   print_suppressions=1 - print the list of matched suppressions.
+//   strip_path_prefix=Release/../../ - prefixes up to and including this
+//     substring will be stripped from source file paths in symbolized reports.
+const char kLsanDefaultOptions[] =
+    "print_suppressions=1 strip_path_prefix=Release/../../ ";
+
+SANITIZER_HOOK_ATTRIBUTE const char *__lsan_default_options() {
+  return kLsanDefaultOptions;
+}
+
+extern "C" char kLSanDefaultSuppressions[];
+
+SANITIZER_HOOK_ATTRIBUTE const char *__lsan_default_suppressions() {
+  return kLSanDefaultSuppressions;
+}
+
+#endif  // LEAK_SANITIZER
diff --git a/build/sanitizers/sanitizers.gyp b/build/sanitizers/sanitizers.gyp
new file mode 100644
index 0000000..91dab8a
--- /dev/null
+++ b/build/sanitizers/sanitizers.gyp
@@ -0,0 +1,92 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'sanitizer_options',
+      'type': 'static_library',
+      'toolsets': ['host', 'target'],
+      'variables': {
+         # Every target is going to depend on sanitizer_options, so allow
+         # this one to depend on itself.
+         'prune_self_dependency': 1,
+         # Do not let 'none' targets depend on this one, they don't need to.
+         'link_dependency': 1,
+       },
+      'sources': [
+        'sanitizer_options.cc',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      # Some targets may want to opt-out from ASan, TSan and MSan and link
+      # without the corresponding runtime libraries. We drop the libc++
+      # dependency and omit the compiler flags to avoid bringing instrumented
+      # code to those targets.
+      'conditions': [
+        ['use_custom_libcxx==1', {
+          'dependencies!': [
+            '../../buildtools/third_party/libc++/libc++.gyp:libcxx_proxy',
+          ],
+        }],
+        ['tsan==1', {
+          'sources': [
+            'tsan_suppressions.cc',
+          ],
+        }],
+        ['lsan==1', {
+          'sources': [
+            'lsan_suppressions.cc',
+          ],
+        }],
+        ['asan==1', {
+          'sources': [
+            'asan_suppressions.cc',
+          ],
+        }],
+      ],
+      'cflags/': [
+        ['exclude', '-fsanitize='],
+        ['exclude', '-fsanitize-'],
+      ],
+      'direct_dependent_settings': {
+        'ldflags': [
+          '-Wl,-u_sanitizer_options_link_helper',
+        ],
+        'target_conditions': [
+          ['_type=="executable"', {
+            'xcode_settings': {
+              'OTHER_LDFLAGS': [
+                '-Wl,-u,__sanitizer_options_link_helper',
+              ],
+            },
+          }],
+        ],
+      },
+    },
+    {
+      # Copy llvm-symbolizer to the product dir so that LKGR bots can package it.
+      'target_name': 'llvm-symbolizer',
+      'type': 'none',
+      'variables': {
+
+       # Path is relative to this GYP file.
+       'llvm_symbolizer_path':
+           '../../third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer<(EXECUTABLE_SUFFIX)',
+      },
+      'conditions': [
+        ['clang==1', {
+          'copies': [{
+            'destination': '<(PRODUCT_DIR)',
+            'files': [
+              '<(llvm_symbolizer_path)',
+            ],
+          }],
+        }],
+      ],
+    },
+  ],
+}
+
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
new file mode 100644
index 0000000..e053a16
--- /dev/null
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -0,0 +1,322 @@
+// Copyright 2014 The Chromium 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 default suppressions for ThreadSanitizer.
+// You can also pass additional suppressions via TSAN_OPTIONS:
+// TSAN_OPTIONS=suppressions=/path/to/suppressions. Please refer to
+// http://dev.chromium.org/developers/testing/threadsanitizer-tsan-v2
+// for more info.
+
+#if defined(THREAD_SANITIZER)
+
+// Please make sure the code below declares a single string variable
+// kTSanDefaultSuppressions contains TSan suppressions delimited by newlines.
+// See http://dev.chromium.org/developers/testing/threadsanitizer-tsan-v2
+// for the instructions on writing suppressions.
+char kTSanDefaultSuppressions[] =
+// False positives in libflashplayer.so and libglib.so. Since we don't
+// instrument them, we cannot reason about the synchronization in them.
+"race:libflashplayer.so\n"
+"race:libglib*.so\n"
+
+// Intentional race in ToolsSanityTest.DataRace in base_unittests.
+"race:base/tools_sanity_unittest.cc\n"
+
+// Data race on WatchdogCounter [test-only].
+"race:base/threading/watchdog_unittest.cc\n"
+
+// Races in libevent, http://crbug.com/23244.
+"race:libevent/event.c\n"
+
+// http://crbug.com/46840.
+"race:base::HistogramSamples::IncreaseSum\n"
+"race:base::Histogram::Add\n"
+"race:base::HistogramSamples::Add\n"
+
+// http://crbug.com/84094.
+"race:sqlite3StatusSet\n"
+"race:pcache1EnforceMaxPage\n"
+"race:pcache1AllocPage\n"
+
+// http://crbug.com/102327.
+// Test-only race, won't fix.
+"race:tracked_objects::ThreadData::ShutdownSingleThreadedCleanup\n"
+
+// http://crbug.com/115540
+"race:*GetCurrentThreadIdentifier\n"
+
+// http://crbug.com/120808
+"race:base/threading/watchdog.cc\n"
+
+// http://crbug.com/157586
+"race:third_party/libvpx/source/libvpx/vp8/decoder/threading.c\n"
+
+// http://crbug.com/158718
+"race:third_party/ffmpeg/libavcodec/pthread.c\n"
+"race:third_party/ffmpeg/libavcodec/pthread_frame.c\n"
+"race:third_party/ffmpeg/libavcodec/vp8.c\n"
+"race:third_party/ffmpeg/libavutil/mem.c\n"
+"race:*HashFrameForTesting\n"
+"race:third_party/ffmpeg/libavcodec/h264pred.c\n"
+"race:media::ReleaseData\n"
+
+// http://crbug.com/158922
+"race:third_party/libvpx/source/libvpx/vp8/encoder/*\n"
+"race:third_party/libvpx/source/libvpx/vp9/encoder/*\n"
+
+// http://crbug.com/189177
+"race:thread_manager\n"
+"race:v8::Locker::Initialize\n"
+
+// http://crbug.com/239359
+"race:media::TestInputCallback::OnData\n"
+
+// http://crbug.com/244368
+"race:skia::BeginPlatformPaint\n"
+
+// http://crbug.com/244385
+"race:unixTempFileDir\n"
+
+// http://crbug.com/244755
+"race:v8::internal::Zone::NewExpand\n"
+"race:TooLateToEnableNow\n"
+"race:adjust_segment_bytes_allocated\n"
+
+// http://crbug.com/244774
+"race:webrtc::RTPReceiver::ProcessBitrate\n"
+"race:webrtc::RTPSender::ProcessBitrate\n"
+"race:webrtc::VideoCodingModuleImpl::Decode\n"
+"race:webrtc::RTPSender::SendOutgoingData\n"
+"race:webrtc::VP8EncoderImpl::GetEncodedPartitions\n"
+"race:webrtc::VP8EncoderImpl::Encode\n"
+"race:webrtc::ViEEncoder::DeliverFrame\n"
+"race:webrtc::vcm::VideoReceiver::Decode\n"
+"race:webrtc::VCMReceiver::FrameForDecoding\n"
+"race:*trace_event_unique_catstatic*\n"
+
+// http://crbug.com/244856
+"race:AutoPulseLock\n"
+
+// http://crbug.com/246968
+"race:webrtc::VideoCodingModuleImpl::RegisterPacketRequestCallback\n"
+
+// http://crbug.com/246974
+"race:content::GpuWatchdogThread::CheckArmed\n"
+
+// http://crbug.com/257396
+"race:base::trace_event::"
+    "TraceEventTestFixture_TraceSamplingScope_Test::TestBody\n"
+
+// http://crbug.com/258479
+"race:SamplingStateScope\n"
+"race:g_trace_state\n"
+
+// http://crbug.com/258499
+"race:third_party/skia/include/core/SkRefCnt.h\n"
+
+// http://crbug.com/268924
+"race:base::g_power_monitor\n"
+"race:base::PowerMonitor::PowerMonitor\n"
+"race:base::PowerMonitor::AddObserver\n"
+"race:base::PowerMonitor::RemoveObserver\n"
+"race:base::PowerMonitor::IsOnBatteryPower\n"
+
+// http://crbug.com/258935
+"race:base::Thread::StopSoon\n"
+
+// http://crbug.com/268941
+"race:tracked_objects::ThreadData::tls_index_\n"
+
+// http://crbug.com/272095
+"race:base::g_top_manager\n"
+
+// http://crbug.com/273047
+"race:base::*::g_lazy_tls_ptr\n"
+"race:IPC::SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_\n"
+
+// http://crbug.com/280466
+"race:content::WebRtcAudioCapturer::SetCapturerSource\n"
+
+// http://crbug.com/285242
+"race:media::PulseAudioOutputStream::SetVolume\n"
+
+// http://crbug.com/296883
+"race:net::URLFetcherCore::Stop\n"
+
+// http://crbug.com/308590
+"race:CustomThreadWatcher::~CustomThreadWatcher\n"
+
+// http://crbug.com/310851
+"race:net::ProxyResolverV8Tracing::Job::~Job\n"
+
+// http://crbug.com/313726
+"race:CallbackWasCalled\n"
+
+// http://crbug.com/327330
+"race:PrepareTextureMailbox\n"
+"race:cc::LayerTreeHost::PaintLayerContents\n"
+
+// http://crbug.com/476529
+"deadlock:cc::VideoLayerImpl::WillDraw\n"
+
+// http://crbug.com/328826
+"race:gLCDOrder\n"
+"race:gLCDOrientation\n"
+
+// http://crbug.com/328868
+"race:PR_Lock\n"
+
+// http://crbug.com/329225
+"race:blink::currentTimeFunction\n"
+
+// http://crbug.com/329460
+"race:extensions::InfoMap::AddExtension\n"
+
+// http://crbug.com/333244
+"race:content::"
+    "VideoCaptureImplTest::MockVideoCaptureImpl::~MockVideoCaptureImpl\n"
+
+// http://crbug.com/333871
+"race:v8::internal::Interface::NewValue()::value_interface\n"
+"race:v8::internal::IsMinusZero(double)::minus_zero\n"
+"race:v8::internal::FastCloneShallowObjectStub::InitializeInterfaceDescriptor\n"
+"race:v8::internal::KeyedLoadStubCompiler::registers\n"
+"race:v8::internal::KeyedStoreStubCompiler::registers()::registers\n"
+"race:v8::internal::KeyedLoadFastElementStub::InitializeInterfaceDescriptor\n"
+"race:v8::internal::KeyedStoreFastElementStub::InitializeInterfaceDescriptor\n"
+"race:v8::internal::LoadStubCompiler::registers\n"
+"race:v8::internal::StoreStubCompiler::registers\n"
+"race:v8::internal::HValue::LoopWeight\n"
+
+// http://crbug.com/334140
+"race:CommandLine::HasSwitch\n"
+"race:CommandLine::current_process_commandline_\n"
+"race:CommandLine::GetSwitchValueASCII\n"
+
+// http://crbug.com/338675
+"race:blink::s_platform\n"
+"race:content::"
+    "RendererWebKitPlatformSupportImpl::~RendererWebKitPlatformSupportImpl\n"
+
+// http://crbug.com/345240
+"race:WTF::s_shutdown\n"
+
+// http://crbug.com/345245
+"race:jingle_glue::JingleThreadWrapper::~JingleThreadWrapper\n"
+"race:webrtc::voe::Channel::UpdatePacketDelay\n"
+"race:webrtc::voe::Channel::GetDelayEstimate\n"
+"race:webrtc::VCMCodecDataBase::DeregisterReceiveCodec\n"
+"race:webrtc::GainControlImpl::set_stream_analog_level\n"
+
+// http://crbug.com/345618
+"race:WebCore::AudioDestinationNode::render\n"
+
+// http://crbug.com/345624
+"race:media::DataSource::set_host\n"
+
+// http://crbug.com/347534
+"race:v8::internal::V8::TearDown\n"
+
+// http://crbug.com/347538
+"race:sctp_timer_start\n"
+
+// http://crbug.com/347548
+"race:cricket::WebRtcVideoMediaChannel::MaybeResetVieSendCodec\n"
+"race:cricket::WebRtcVideoMediaChannel::SetSendCodec\n"
+
+// http://crbug.com/347553
+"race:blink::WebString::reset\n"
+
+// http://crbug.com/348511
+"race:webrtc::acm1::AudioCodingModuleImpl::PlayoutData10Ms\n"
+
+// http://crbug.com/348982
+"race:cricket::P2PTransportChannel::OnConnectionDestroyed\n"
+"race:cricket::P2PTransportChannel::AddConnection\n"
+
+// http://crbug.com/348984
+"race:sctp_express_handle_sack\n"
+"race:system_base_info\n"
+
+// http://crbug.com/363999
+"race:v8::internal::EnterDebugger::*EnterDebugger\n"
+
+// https://code.google.com/p/v8/issues/detail?id=3143
+"race:v8::internal::FLAG_track_double_fields\n"
+
+// https://crbug.com/369257
+// TODO(mtklein): annotate properly and remove suppressions.
+"race:SandboxIPCHandler::HandleFontMatchRequest\n"
+"race:SkFontConfigInterfaceDirect::matchFamilyName\n"
+"race:SkFontConfigInterface::GetSingletonDirectInterface\n"
+"race:FcStrStaticName\n"
+
+// http://crbug.com/372807
+"deadlock:net::X509Certificate::CreateCertificateListFromBytes\n"
+"deadlock:net::X509Certificate::CreateFromBytes\n"
+"deadlock:net::SSLClientSocketNSS::Core::DoHandshakeLoop\n"
+
+// http://crbug.com/374135
+"race:media::AlsaWrapper::PcmWritei\n"
+
+// False positive in libc's tzset_internal, http://crbug.com/379738.
+"race:tzset_internal\n"
+
+// http://crbug.com/380554
+"deadlock:g_type_add_interface_static\n"
+
+// http:://crbug.com/386385
+"race:content::AppCacheStorageImpl::DatabaseTask::CallRunCompleted\n"
+
+// http://crbug.com/388730
+"race:g_next_user_script_id\n"
+
+// http://crbug.com/389098
+"race:webrtc::RtpToNtpMs\n"
+"race:webrtc::UpdateRtcpList\n"
+"race:webrtc::RemoteNtpTimeEstimator::Estimate\n"
+"race:webrtc::voe::TransmitMixer::EnableStereoChannelSwapping\n"
+
+// http://crbug.com/397022
+"deadlock:"
+"base::trace_event::TraceEventTestFixture_ThreadOnceBlocking_Test::TestBody\n"
+
+// http://crbug.com/415472
+"deadlock:base::trace_event::TraceLog::GetCategoryGroupEnabled\n"
+
+// http://crbug.com/425057
+"deadlock:webrtc::ViEChannelManagerScoped::ViEChannelManagerScoped\n"
+
+// http://crbug.com/417193
+// Suppressing both AudioContext.{cpp,h}.
+"race:modules/webaudio/AudioContext\n"
+
+// https://code.google.com/p/skia/issues/detail?id=3294
+"race:SkBaseMutex::acquire\n"
+
+// https://crbug.com/430533
+"race:TileTaskGraphRunner::Run\n"
+
+// https://crbug.com/448203
+"race:blink::RemoteFrame::detach\n"
+
+// https://crbug.com/454652
+"race:net::NetworkChangeNotifier::SetTestNotificationsOnly\n"
+
+// https://crbug.com/455638
+"deadlock:dbus::Bus::ShutdownAndBlock\n"
+
+// https://crbug.com/455665
+"race:mojo::common::*::tick_clock\n"
+
+// https://crbug.com/459429
+"race:randomnessPid\n"
+
+// https://crbug.com/454655
+"race:content::BrowserTestBase::PostTaskToInProcessRendererAndWait\n"
+
+// End of suppressions.
+;  // Please keep this semicolon.
+
+#endif  // THREAD_SANITIZER
diff --git a/build/secondary/testing/BUILD.gn b/build/secondary/testing/BUILD.gn
new file mode 100644
index 0000000..fc50637
--- /dev/null
+++ b/build/secondary/testing/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("gmock_mutant") {
+  sources = [
+    "gmock_mutant.h",  # gMock helpers
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/build/secondary/testing/gmock/BUILD.gn b/build/secondary/testing/gmock/BUILD.gn
new file mode 100644
index 0000000..4ec6224
--- /dev/null
+++ b/build/secondary/testing/gmock/BUILD.gn
@@ -0,0 +1,54 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("gmock_config") {
+  # Gmock headers need to be able to find themselves.
+  include_dirs = [ "include" ]
+}
+
+static_library("gmock") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    # Sources based on files in r173 of gmock.
+    "include/gmock/gmock-actions.h",
+    "include/gmock/gmock-cardinalities.h",
+    "include/gmock/gmock-generated-actions.h",
+    "include/gmock/gmock-generated-function-mockers.h",
+    "include/gmock/gmock-generated-matchers.h",
+    "include/gmock/gmock-generated-nice-strict.h",
+    "include/gmock/gmock-matchers.h",
+    "include/gmock/gmock-spec-builders.h",
+    "include/gmock/gmock.h",
+    "include/gmock/internal/gmock-generated-internal-utils.h",
+    "include/gmock/internal/gmock-internal-utils.h",
+    "include/gmock/internal/gmock-port.h",
+
+    #"src/gmock-all.cc",  # Not needed by our build.
+    "src/gmock-cardinalities.cc",
+    "src/gmock-internal-utils.cc",
+    "src/gmock-matchers.cc",
+    "src/gmock-spec-builders.cc",
+    "src/gmock.cc",
+  ]
+
+  # This project includes some stuff form gtest's guts.
+  include_dirs = [ "../gtest/include" ]
+
+  public_configs = [
+    ":gmock_config",
+    "//testing/gtest:gtest_config",
+  ]
+}
+
+static_library("gmock_main") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "src/gmock_main.cc",
+  ]
+  deps = [
+    ":gmock",
+  ]
+}
diff --git a/build/secondary/testing/gtest/BUILD.gn b/build/secondary/testing/gtest/BUILD.gn
new file mode 100644
index 0000000..a20a09d
--- /dev/null
+++ b/build/secondary/testing/gtest/BUILD.gn
@@ -0,0 +1,125 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("gtest_config") {
+  visibility = [
+    ":*",
+    "//testing/gmock:*",  # gmock also shares this config.
+  ]
+
+  defines = [
+    # In order to allow regex matches in gtest to be shared between Windows
+    # and other systems, we tell gtest to always use it's internal engine.
+    "GTEST_HAS_POSIX_RE=0",
+
+    # Chrome doesn't support / require C++11, yet.
+    "GTEST_LANG_CXX11=0",
+  ]
+
+  # Gtest headers need to be able to find themselves.
+  include_dirs = [ "include" ]
+
+  if (is_win) {
+    cflags = [ "/wd4800" ]  # Unused variable warning.
+  }
+
+  if (is_posix) {
+    defines += [
+      # gtest isn't able to figure out when RTTI is disabled for gcc
+      # versions older than 4.3.2, and assumes it's enabled.  Our Mac
+      # and Linux builds disable RTTI, and cannot guarantee that the
+      # compiler will be 4.3.2. or newer.  The Mac, for example, uses
+      # 4.2.1 as that is the latest available on that platform.  gtest
+      # must be instructed that RTTI is disabled here, and for any
+      # direct dependents that might include gtest headers.
+      "GTEST_HAS_RTTI=0",
+    ]
+  }
+
+  if (is_android) {
+    defines += [
+      # We want gtest features that use tr1::tuple, but we currently
+      # don't support the variadic templates used by libstdc++'s
+      # implementation. gtest supports this scenario by providing its
+      # own implementation but we must opt in to it.
+      "GTEST_USE_OWN_TR1_TUPLE=1",
+
+      # GTEST_USE_OWN_TR1_TUPLE only works if GTEST_HAS_TR1_TUPLE is set.
+      # gtest r625 made it so that GTEST_HAS_TR1_TUPLE is set to 0
+      # automatically on android, so it has to be set explicitly here.
+      "GTEST_HAS_TR1_TUPLE=1",
+    ]
+  }
+}
+
+config("gtest_direct_config") {
+  visibility = [ ":*" ]
+  defines = [ "UNIT_TEST" ]
+}
+
+static_library("gtest") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "include/gtest/gtest-death-test.h",
+    "include/gtest/gtest-message.h",
+    "include/gtest/gtest-param-test.h",
+    "include/gtest/gtest-printers.h",
+    "include/gtest/gtest-spi.h",
+    "include/gtest/gtest-test-part.h",
+    "include/gtest/gtest-typed-test.h",
+    "include/gtest/gtest.h",
+    "include/gtest/gtest_pred_impl.h",
+    "include/gtest/internal/gtest-death-test-internal.h",
+    "include/gtest/internal/gtest-filepath.h",
+    "include/gtest/internal/gtest-internal.h",
+    "include/gtest/internal/gtest-linked_ptr.h",
+    "include/gtest/internal/gtest-param-util-generated.h",
+    "include/gtest/internal/gtest-param-util.h",
+    "include/gtest/internal/gtest-port.h",
+    "include/gtest/internal/gtest-string.h",
+    "include/gtest/internal/gtest-tuple.h",
+    "include/gtest/internal/gtest-type-util.h",
+
+    #"gtest/src/gtest-all.cc",  # Not needed by our build.
+    "../multiprocess_func_list.cc",
+    "../multiprocess_func_list.h",
+    "../platform_test.h",
+    "src/gtest-death-test.cc",
+    "src/gtest-filepath.cc",
+    "src/gtest-internal-inl.h",
+    "src/gtest-port.cc",
+    "src/gtest-printers.cc",
+    "src/gtest-test-part.cc",
+    "src/gtest-typed-test.cc",
+    "src/gtest.cc",
+  ]
+
+  if (is_mac) {
+    sources += [
+      "../gtest_mac.h",
+      "../gtest_mac.mm",
+      "../platform_test_mac.mm",
+    ]
+  }
+
+  include_dirs = [ "." ]
+
+  all_dependent_configs = [ ":gtest_config" ]
+  public_configs = [ ":gtest_direct_config" ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
+
+source_set("gtest_main") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "src/gtest_main.cc",
+  ]
+  deps = [
+    ":gtest",
+  ]
+}
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn
new file mode 100644
index 0000000..099b892
--- /dev/null
+++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -0,0 +1,86 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+config("cpu_features_include") {
+  include_dirs = [ "ndk/sources/android/cpufeatures" ]
+}
+
+# This is the GN version of
+# //build/android/ndk.gyp:cpu_features
+source_set("cpu_features") {
+  sources = [
+    "ndk/sources/android/cpufeatures/cpu-features.c",
+  ]
+  public_configs = [ ":cpu_features_include" ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
+
+android_java_prebuilt("android_gcm_java") {
+  jar_path = "$android_sdk_root/extras/google/gcm/gcm-client/dist/gcm.jar"
+}
+
+android_java_prebuilt("uiautomator_java") {
+  jar_path = "$android_sdk/uiautomator.jar"
+}
+
+android_java_prebuilt("android_support_v13_java") {
+  jar_path =
+      "$android_sdk_root/extras/android/support/v13/android-support-v13.jar"
+}
+
+android_resources("android_support_v7_appcompat_resources") {
+  v14_verify_only = true
+  resource_dirs =
+      [ "$android_sdk_root/extras/android/support/v7/appcompat/res" ]
+  custom_package = "android.support.v7.appcompat"
+}
+
+android_java_prebuilt("android_support_v7_appcompat_java") {
+  deps = [
+    ":android_support_v7_appcompat_resources",
+  ]
+  jar_path = "$android_sdk_root/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar"
+}
+
+android_resources("android_support_v7_mediarouter_resources") {
+  v14_verify_only = true
+  resource_dirs =
+      [ "$android_sdk_root/extras/android/support/v7/mediarouter/res" ]
+  deps = [
+    ":android_support_v7_appcompat_resources",
+  ]
+  custom_package = "android.support.v7.mediarouter"
+}
+
+android_java_prebuilt("android_support_v7_mediarouter_java") {
+  deps = [
+    ":android_support_v7_mediarouter_resources",
+    ":android_support_v7_appcompat_java",
+  ]
+  jar_path = "$android_sdk_root/extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar"
+}
+
+android_java_prebuilt("android_support_v7_recyclerview_java") {
+  deps = [
+    ":android_support_v7_appcompat_java",
+  ]
+  jar_path = "$android_sdk_root/extras/android/support/v7/recyclerview/libs/android-support-v7-recyclerview.jar"
+}
+
+android_resources("google_play_services_default_resources") {
+  v14_verify_only = true
+  resource_dirs = [ "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/res" ]
+  custom_package = "com.google.android.gms"
+}
+android_java_prebuilt("google_play_services_default_java") {
+  deps = [
+    ":android_support_v13_java",
+    ":google_play_services_default_resources",
+  ]
+  jar_path = "$android_sdk_root/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar"
+}
diff --git a/build/secondary/third_party/cacheinvalidation/BUILD.gn b/build/secondary/third_party/cacheinvalidation/BUILD.gn
new file mode 100644
index 0000000..17e4d1c
--- /dev/null
+++ b/build/secondary/third_party/cacheinvalidation/BUILD.gn
@@ -0,0 +1,146 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/test.gni")
+
+config("cacheinvalidation_config") {
+  include_dirs = [
+    "overrides",
+    "src",
+  ]
+}
+
+static_library("cacheinvalidation") {
+  sources = [
+    "overrides/google/cacheinvalidation/deps/callback.h",
+    "overrides/google/cacheinvalidation/deps/gmock.h",
+    "overrides/google/cacheinvalidation/deps/googletest.h",
+    "overrides/google/cacheinvalidation/deps/logging.h",
+    "overrides/google/cacheinvalidation/deps/mutex.h",
+    "overrides/google/cacheinvalidation/deps/random.cc",
+    "overrides/google/cacheinvalidation/deps/random.h",
+    "overrides/google/cacheinvalidation/deps/scoped_ptr.h",
+    "overrides/google/cacheinvalidation/deps/sha1-digest-function.h",
+    "overrides/google/cacheinvalidation/deps/stl-namespace.h",
+    "overrides/google/cacheinvalidation/deps/string_util.h",
+    "overrides/google/cacheinvalidation/deps/time.h",
+    "src/google/cacheinvalidation/deps/digest-function.h",
+    "src/google/cacheinvalidation/impl/basic-system-resources.cc",
+    "src/google/cacheinvalidation/impl/basic-system-resources.h",
+    "src/google/cacheinvalidation/impl/checking-invalidation-listener.cc",
+    "src/google/cacheinvalidation/impl/checking-invalidation-listener.h",
+    "src/google/cacheinvalidation/impl/client-protocol-namespace-fix.h",
+    "src/google/cacheinvalidation/impl/constants.cc",
+    "src/google/cacheinvalidation/impl/constants.h",
+    "src/google/cacheinvalidation/impl/digest-store.h",
+    "src/google/cacheinvalidation/impl/exponential-backoff-delay-generator.cc",
+    "src/google/cacheinvalidation/impl/exponential-backoff-delay-generator.h",
+    "src/google/cacheinvalidation/impl/invalidation-client-core.cc",
+    "src/google/cacheinvalidation/impl/invalidation-client-core.h",
+    "src/google/cacheinvalidation/impl/invalidation-client-factory.cc",
+    "src/google/cacheinvalidation/impl/invalidation-client-impl.cc",
+    "src/google/cacheinvalidation/impl/invalidation-client-impl.h",
+    "src/google/cacheinvalidation/impl/invalidation-client-util.h",
+    "src/google/cacheinvalidation/impl/log-macro.h",
+    "src/google/cacheinvalidation/impl/object-id-digest-utils.cc",
+    "src/google/cacheinvalidation/impl/object-id-digest-utils.h",
+    "src/google/cacheinvalidation/impl/persistence-utils.cc",
+    "src/google/cacheinvalidation/impl/persistence-utils.h",
+    "src/google/cacheinvalidation/impl/proto-converter.cc",
+    "src/google/cacheinvalidation/impl/proto-converter.h",
+    "src/google/cacheinvalidation/impl/proto-helpers.cc",
+    "src/google/cacheinvalidation/impl/proto-helpers.h",
+    "src/google/cacheinvalidation/impl/protocol-handler.cc",
+    "src/google/cacheinvalidation/impl/protocol-handler.h",
+    "src/google/cacheinvalidation/impl/recurring-task.cc",
+    "src/google/cacheinvalidation/impl/recurring-task.h",
+    "src/google/cacheinvalidation/impl/registration-manager.cc",
+    "src/google/cacheinvalidation/impl/registration-manager.h",
+    "src/google/cacheinvalidation/impl/repeated-field-namespace-fix.h",
+    "src/google/cacheinvalidation/impl/run-state.h",
+    "src/google/cacheinvalidation/impl/safe-storage.cc",
+    "src/google/cacheinvalidation/impl/safe-storage.h",
+    "src/google/cacheinvalidation/impl/simple-registration-store.cc",
+    "src/google/cacheinvalidation/impl/simple-registration-store.h",
+    "src/google/cacheinvalidation/impl/smearer.h",
+    "src/google/cacheinvalidation/impl/statistics.cc",
+    "src/google/cacheinvalidation/impl/statistics.h",
+    "src/google/cacheinvalidation/impl/throttle.cc",
+    "src/google/cacheinvalidation/impl/throttle.h",
+    "src/google/cacheinvalidation/impl/ticl-message-validator.cc",
+    "src/google/cacheinvalidation/impl/ticl-message-validator.h",
+    "src/google/cacheinvalidation/include/invalidation-client-factory.h",
+    "src/google/cacheinvalidation/include/invalidation-client.h",
+    "src/google/cacheinvalidation/include/invalidation-listener.h",
+    "src/google/cacheinvalidation/include/system-resources.h",
+    "src/google/cacheinvalidation/include/types.h",
+  ]
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+  public_configs = [ ":cacheinvalidation_config" ]
+
+  public_deps = [
+    "src/google/cacheinvalidation:cacheinvalidation_proto_cpp",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
+
+test("cacheinvalidation_unittests") {
+  sources = [
+    "src/google/cacheinvalidation/impl/invalidation-client-impl_test.cc",
+    "src/google/cacheinvalidation/impl/protocol-handler_test.cc",
+    "src/google/cacheinvalidation/impl/recurring-task_test.cc",
+    "src/google/cacheinvalidation/impl/throttle_test.cc",
+    "src/google/cacheinvalidation/test/deterministic-scheduler.cc",
+    "src/google/cacheinvalidation/test/deterministic-scheduler.h",
+    "src/google/cacheinvalidation/test/test-logger.cc",
+    "src/google/cacheinvalidation/test/test-logger.h",
+    "src/google/cacheinvalidation/test/test-utils.cc",
+    "src/google/cacheinvalidation/test/test-utils.h",
+  ]
+
+  deps = [
+    ":cacheinvalidation",
+    "src/google/cacheinvalidation:cacheinvalidation_proto_cpp",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+# TODO(GYP) Test isolation stuff.
+if (is_android) {
+  import("//build/config/android/rules.gni")
+
+  # GYP: //third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_proto_java
+  proto_java_library("cacheinvalidation_proto_java") {
+    proto_path = "src/proto"
+    sources = [
+      "$proto_path/android_channel.proto",
+      "$proto_path/android_listener.proto",
+      "$proto_path/android_service.proto",
+      "$proto_path/channel_common.proto",
+      "$proto_path/client.proto",
+      "$proto_path/client_protocol.proto",
+      "$proto_path/java_client.proto",
+      "$proto_path/types.proto",
+    ]
+  }
+
+  # GYP: //third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib
+  android_library("cacheinvalidation_javalib") {
+    deps = [
+      ":cacheinvalidation_proto_java",
+      "//third_party/android_protobuf:protobuf_nano_javalib",
+      "//third_party/android_tools:android_gcm_java",
+    ]
+
+    DEPRECATED_java_in_dir = "src/java"
+  }
+}
diff --git a/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn b/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn
new file mode 100644
index 0000000..3bbb844
--- /dev/null
+++ b/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("cacheinvalidation_proto_cpp") {
+  # Depend on cacheinvalidation instead.
+  visibility = [ "//third_party/cacheinvalidation/*" ]
+
+  sources = [
+    "client.proto",
+    "client_gateway.proto",
+    "client_protocol.proto",
+    "client_test_internal.proto",
+    "types.proto",
+  ]
+
+  if (!is_android) {
+    sources += [
+      "android_channel.proto",
+      "channel_common.proto",
+    ]
+  }
+
+  proto_out_dir = "google/cacheinvalidation"
+}
diff --git a/build/secondary/third_party/freetype/BUILD.gn b/build/secondary/third_party/freetype/BUILD.gn
new file mode 100644
index 0000000..96e50f3
--- /dev/null
+++ b/build/secondary/third_party/freetype/BUILD.gn
@@ -0,0 +1,51 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_android, "This library is only used on Android")
+
+config("freetype_config") {
+  include_dirs = [ "include" ]
+}
+
+source_set("freetype") {
+  sources = [
+    # The following files are not sorted alphabetically, but in the
+    # same order as in Android.mk to ease maintenance.
+    "src/base/ftbbox.c",
+    "src/base/ftbitmap.c",
+    "src/base/ftfstype.c",
+    "src/base/ftglyph.c",
+    "src/base/ftlcdfil.c",
+    "src/base/ftstroke.c",
+    "src/base/fttype1.c",
+    "src/base/ftxf86.c",
+    "src/base/ftbase.c",
+    "src/base/ftsystem.c",
+    "src/base/ftinit.c",
+    "src/base/ftgasp.c",
+    "src/gzip/ftgzip.c",
+    "src/raster/raster.c",
+    "src/sfnt/sfnt.c",
+    "src/smooth/smooth.c",
+    "src/autofit/autofit.c",
+    "src/truetype/truetype.c",
+    "src/cff/cff.c",
+    "src/psnames/psnames.c",
+    "src/pshinter/pshinter.c",
+  ]
+
+  defines = [
+    "FT2_BUILD_LIBRARY",
+    "DARWIN_NO_CARBON",
+  ]
+
+  include_dirs = [ "build" ]
+
+  public_configs = [ ":freetype_config" ]
+
+  deps = [
+    "//third_party/libpng",
+    "//third_party/zlib",
+  ]
+}
diff --git a/build/secondary/third_party/libjpeg_turbo/BUILD.gn b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
new file mode 100644
index 0000000..bf35d07
--- /dev/null
+++ b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
@@ -0,0 +1,211 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Do not use the targets in this file unless you need a certain libjpeg
+# implementation. Use the meta target //third_party:jpeg instead.
+
+if (current_cpu == "arm") {
+  import("//build/config/arm.gni")
+}
+
+if (current_cpu == "x86" || current_cpu == "x64") {
+  import("//third_party/yasm/yasm_assemble.gni")
+
+  yasm_assemble("simd_asm") {
+    defines = []
+
+    if (current_cpu == "x86") {
+      sources = [
+        "simd/jccolmmx.asm",
+        "simd/jccolss2.asm",
+        "simd/jcgrammx.asm",
+        "simd/jcgrass2.asm",
+        "simd/jcqnt3dn.asm",
+        "simd/jcqntmmx.asm",
+        "simd/jcqnts2f.asm",
+        "simd/jcqnts2i.asm",
+        "simd/jcqntsse.asm",
+        "simd/jcsammmx.asm",
+        "simd/jcsamss2.asm",
+        "simd/jdcolmmx.asm",
+        "simd/jdcolss2.asm",
+        "simd/jdmermmx.asm",
+        "simd/jdmerss2.asm",
+        "simd/jdsammmx.asm",
+        "simd/jdsamss2.asm",
+        "simd/jf3dnflt.asm",
+        "simd/jfmmxfst.asm",
+        "simd/jfmmxint.asm",
+        "simd/jfss2fst.asm",
+        "simd/jfss2int.asm",
+        "simd/jfsseflt.asm",
+        "simd/ji3dnflt.asm",
+        "simd/jimmxfst.asm",
+        "simd/jimmxint.asm",
+        "simd/jimmxred.asm",
+        "simd/jiss2flt.asm",
+        "simd/jiss2fst.asm",
+        "simd/jiss2int.asm",
+        "simd/jiss2red.asm",
+        "simd/jisseflt.asm",
+        "simd/jsimdcpu.asm",
+      ]
+      defines += [ "__x86__" ]
+    } else if (current_cpu == "x64") {
+      sources = [
+        "simd/jccolss2-64.asm",
+        "simd/jcgrass2-64.asm",
+        "simd/jcqnts2f-64.asm",
+        "simd/jcqnts2i-64.asm",
+        "simd/jcsamss2-64.asm",
+        "simd/jdcolss2-64.asm",
+        "simd/jdmerss2-64.asm",
+        "simd/jdsamss2-64.asm",
+        "simd/jfss2fst-64.asm",
+        "simd/jfss2int-64.asm",
+        "simd/jfsseflt-64.asm",
+        "simd/jiss2flt-64.asm",
+        "simd/jiss2fst-64.asm",
+        "simd/jiss2int-64.asm",
+        "simd/jiss2red-64.asm",
+      ]
+      defines += [ "__x86_64__" ]
+    }
+
+    if (is_win) {
+      defines += [ "MSVC" ]
+      include_dirs = [ "win" ]
+      if (current_cpu == "x86") {
+        defines += [ "WIN32" ]
+      } else {
+        defines += [ "WIN64" ]
+      }
+    } else if (is_mac) {
+      defines += [ "MACHO" ]
+      include_dirs = [ "mac" ]
+    } else if (is_linux || is_android) {
+      defines += [ "ELF" ]
+      include_dirs = [ "linux" ]
+    }
+  }
+}
+
+source_set("simd") {
+  if (current_cpu == "x86") {
+    deps = [
+      ":simd_asm",
+    ]
+    sources = [
+      "simd/jsimd_i386.c",
+    ]
+    if (is_win) {
+      cflags = [ "/wd4245" ]
+    }
+  } else if (current_cpu == "x64") {
+    deps = [
+      ":simd_asm",
+    ]
+    sources = [
+      "simd/jsimd_x86_64.c",
+    ]
+  } else if (current_cpu == "arm" && arm_version >= 7 &&
+             (arm_use_neon || arm_optionally_use_neon)) {
+    sources = [
+      "simd/jsimd_arm.c",
+      "simd/jsimd_arm_neon.S",
+    ]
+  } else {
+    sources = [
+      "jsimd_none.c",
+    ]
+  }
+}
+
+config("libjpeg_config") {
+  include_dirs = [ "." ]
+}
+
+source_set("libjpeg") {
+  sources = [
+    "jcapimin.c",
+    "jcapistd.c",
+    "jccoefct.c",
+    "jccolor.c",
+    "jcdctmgr.c",
+    "jchuff.c",
+    "jchuff.h",
+    "jcinit.c",
+    "jcmainct.c",
+    "jcmarker.c",
+    "jcmaster.c",
+    "jcomapi.c",
+    "jconfig.h",
+    "jcparam.c",
+    "jcphuff.c",
+    "jcprepct.c",
+    "jcsample.c",
+    "jdapimin.c",
+    "jdapistd.c",
+    "jdatadst.c",
+    "jdatasrc.c",
+    "jdcoefct.c",
+    "jdcolor.c",
+    "jdct.h",
+    "jddctmgr.c",
+    "jdhuff.c",
+    "jdhuff.h",
+    "jdinput.c",
+    "jdmainct.c",
+    "jdmarker.c",
+    "jdmaster.c",
+    "jdmerge.c",
+    "jdphuff.c",
+    "jdpostct.c",
+    "jdsample.c",
+    "jerror.c",
+    "jerror.h",
+    "jfdctflt.c",
+    "jfdctfst.c",
+    "jfdctint.c",
+    "jidctflt.c",
+    "jidctfst.c",
+    "jidctint.c",
+    "jidctred.c",
+    "jinclude.h",
+    "jmemmgr.c",
+    "jmemnobs.c",
+    "jmemsys.h",
+    "jmorecfg.h",
+    "jpegint.h",
+    "jpeglib.h",
+    "jpeglibmangler.h",
+    "jquant1.c",
+    "jquant2.c",
+    "jutils.c",
+    "jversion.h",
+  ]
+
+  defines = [
+    "WITH_SIMD",
+    "MOTION_JPEG_SUPPORTED",
+    "NO_GETENV",
+  ]
+
+  configs += [ ":libjpeg_config" ]
+
+  public_configs = [ ":libjpeg_config" ]
+
+  # MemorySanitizer doesn't support assembly code, so keep it disabled in
+  # MSan builds for now.
+  # TODO: Enable on Linux when .asm files are recognized.
+  if (is_msan || is_linux) {
+    sources += [ "jsimd_none.c" ]
+  } else {
+    deps = [
+      ":simd",
+    ]
+  }
+
+  # TODO(GYP): Compile the .asm files with YASM as GYP does.
+}
diff --git a/build/secondary/third_party/libsrtp/BUILD.gn b/build/secondary/third_party/libsrtp/BUILD.gn
new file mode 100644
index 0000000..8b9647c
--- /dev/null
+++ b/build/secondary/third_party/libsrtp/BUILD.gn
@@ -0,0 +1,339 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+  use_system_libsrtp = false
+}
+
+config("libsrtp_config") {
+  defines = [
+    "HAVE_STDLIB_H",
+    "HAVE_STRING_H",
+  ]
+
+  include_dirs = [
+    "config",
+    "srtp/include",
+    "srtp/crypto/include",
+  ]
+
+  if (is_posix) {
+    defines += [
+      "HAVE_INT16_T",
+      "HAVE_INT32_T",
+      "HAVE_INT8_T",
+      "HAVE_UINT16_T",
+      "HAVE_UINT32_T",
+      "HAVE_UINT64_T",
+      "HAVE_UINT8_T",
+      "HAVE_STDINT_H",
+      "HAVE_INTTYPES_H",
+      "HAVE_NETINET_IN_H",
+      "INLINE=inline",
+    ]
+  }
+
+  if (is_win) {
+    defines += [
+      "INLINE=__inline",
+      "HAVE_BYTESWAP_METHODS_H",
+
+      # All Windows architectures are this way.
+      "SIZEOF_UNSIGNED_LONG=4",
+      "SIZEOF_UNSIGNED_LONG_LONG=8",
+    ]
+  }
+
+  if (current_cpu == "x64" || current_cpu == "x86" || current_cpu == "arm") {
+    defines += [
+      # TODO(leozwang): CPU_RISC doesn"t work properly on android/arm
+      # platform for unknown reasons, need to investigate the root cause
+      # of it. CPU_RISC is used for optimization only, and CPU_CISC should
+      # just work just fine, it has been tested on android/arm with srtp
+      # test applications and libjingle.
+      "CPU_CISC",
+    ]
+  }
+
+  if (current_cpu == "mipsel") {
+    defines += [ "CPU_RISC" ]
+  }
+}
+
+config("system_libsrtp_config") {
+  defines = [ "USE_SYSTEM_LIBSRTP" ]
+  include_dirs = [ "/usr/include/srtp" ]
+}
+
+if (use_system_libsrtp) {
+  group("libsrtp") {
+    public_configs = [
+      ":libsrtp_config",
+      ":system_libsrtp_config",
+    ]
+    libs = [ "-lsrtp" ]
+  }
+} else {
+  static_library("libsrtp") {
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [ "//build/config/compiler:no_chromium_code" ]
+    public_configs = [ ":libsrtp_config" ]
+
+    sources = [
+      # includes
+      "srtp/include/ekt.h",
+      "srtp/include/getopt_s.h",
+      "srtp/include/rtp.h",
+      "srtp/include/rtp_priv.h",
+      "srtp/include/srtp.h",
+      "srtp/include/srtp_priv.h",
+      "srtp/include/ut_sim.h",
+
+      # headers
+      "srtp/crypto/include/aes.h",
+      "srtp/crypto/include/aes_cbc.h",
+      "srtp/crypto/include/aes_icm.h",
+      "srtp/crypto/include/alloc.h",
+      "srtp/crypto/include/auth.h",
+      "srtp/crypto/include/cipher.h",
+      "srtp/crypto/include/crypto.h",
+      "srtp/crypto/include/crypto_kernel.h",
+      "srtp/crypto/include/crypto_math.h",
+      "srtp/crypto/include/crypto_types.h",
+      "srtp/crypto/include/cryptoalg.h",
+      "srtp/crypto/include/datatypes.h",
+      "srtp/crypto/include/err.h",
+      "srtp/crypto/include/gf2_8.h",
+      "srtp/crypto/include/hmac.h",
+      "srtp/crypto/include/integers.h",
+      "srtp/crypto/include/kernel_compat.h",
+      "srtp/crypto/include/key.h",
+      "srtp/crypto/include/null_auth.h",
+      "srtp/crypto/include/null_cipher.h",
+      "srtp/crypto/include/prng.h",
+      "srtp/crypto/include/rand_source.h",
+      "srtp/crypto/include/rdb.h",
+      "srtp/crypto/include/rdbx.h",
+      "srtp/crypto/include/sha1.h",
+      "srtp/crypto/include/stat.h",
+      "srtp/crypto/include/xfm.h",
+
+      # sources
+      "srtp/crypto/cipher/aes.c",
+      "srtp/crypto/cipher/aes_cbc.c",
+      "srtp/crypto/cipher/aes_icm.c",
+      "srtp/crypto/cipher/cipher.c",
+      "srtp/crypto/cipher/null_cipher.c",
+      "srtp/crypto/hash/auth.c",
+      "srtp/crypto/hash/hmac.c",
+      "srtp/crypto/hash/null_auth.c",
+      "srtp/crypto/hash/sha1.c",
+      "srtp/crypto/kernel/alloc.c",
+      "srtp/crypto/kernel/crypto_kernel.c",
+      "srtp/crypto/kernel/err.c",
+      "srtp/crypto/kernel/key.c",
+      "srtp/crypto/math/datatypes.c",
+      "srtp/crypto/math/gf2_8.c",
+      "srtp/crypto/math/stat.c",
+      "srtp/crypto/replay/rdb.c",
+      "srtp/crypto/replay/rdbx.c",
+      "srtp/crypto/replay/ut_sim.c",
+      "srtp/crypto/rng/ctr_prng.c",
+      "srtp/crypto/rng/prng.c",
+      "srtp/crypto/rng/rand_source.c",
+      "srtp/srtp/ekt.c",
+      "srtp/srtp/srtp.c",
+    ]
+
+    if (is_clang) {
+      cflags = [ "-Wno-implicit-function-declaration" ]
+    }
+  }
+
+  # TODO(GYP): A bunch of these tests don't compile (in gyp either). They're
+  # not very broken, so could probably be made to work if it's useful.
+  if (!is_win) {
+    executable("rdbx_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/include/getopt_s.h",
+        "srtp/test/getopt_s.c",
+        "srtp/test/rdbx_driver.c",
+      ]
+    }
+
+    executable("srtp_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/include/getopt_s.h",
+        "srtp/include/srtp_priv.h",
+        "srtp/test/getopt_s.c",
+        "srtp/test/srtp_driver.c",
+      ]
+    }
+
+    executable("roc_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/include/rdbx.h",
+        "srtp/include/ut_sim.h",
+        "srtp/test/roc_driver.c",
+      ]
+    }
+
+    executable("replay_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/include/rdbx.h",
+        "srtp/include/ut_sim.h",
+        "srtp/test/replay_driver.c",
+      ]
+    }
+
+    executable("rtpw") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/include/datatypes.h",
+        "srtp/include/getopt_s.h",
+        "srtp/include/rtp.h",
+        "srtp/include/srtp.h",
+        "srtp/test/getopt_s.c",
+        "srtp/test/rtp.c",
+        "srtp/test/rtpw.c",
+      ]
+      if (is_android) {
+        defines = [ "HAVE_SYS_SOCKET_H" ]
+      }
+      if (is_clang) {
+        cflags = [ "-Wno-implicit-function-declaration" ]
+      }
+    }
+
+    executable("srtp_test_cipher_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/cipher_driver.c",
+      ]
+    }
+
+    executable("srtp_test_datatypes_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/datatypes_driver.c",
+      ]
+    }
+
+    executable("srtp_test_stat_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/stat_driver.c",
+      ]
+    }
+
+    executable("srtp_test_sha1_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/sha1_driver.c",
+      ]
+    }
+
+    executable("srtp_test_kernel_driver") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/kernel_driver.c",
+      ]
+    }
+
+    executable("srtp_test_aes_calc") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/aes_calc.c",
+      ]
+    }
+
+    executable("srtp_test_rand_gen") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/rand_gen.c",
+      ]
+    }
+
+    executable("srtp_test_env") {
+      configs -= [ "//build/config/compiler:chromium_code" ]
+      configs += [ "//build/config/compiler:no_chromium_code" ]
+      deps = [
+        ":libsrtp",
+      ]
+      sources = [
+        "srtp/crypto/test/env.c",
+      ]
+    }
+
+    group("srtp_runtest") {
+      deps = [
+        ":rdbx_driver",
+        ":srtp_driver",
+        ":roc_driver",
+        ":replay_driver",
+        ":rtpw",
+        ":srtp_test_cipher_driver",
+        ":srtp_test_datatypes_driver",
+        ":srtp_test_stat_driver",
+        ":srtp_test_sha1_driver",
+        ":srtp_test_kernel_driver",
+        ":srtp_test_aes_calc",
+        ":srtp_test_rand_gen",
+        ":srtp_test_env",
+      ]
+    }
+  }
+}
diff --git a/build/secondary/third_party/nss/BUILD.gn b/build/secondary/third_party/nss/BUILD.gn
new file mode 100644
index 0000000..25d449e
--- /dev/null
+++ b/build/secondary/third_party/nss/BUILD.gn
@@ -0,0 +1,1211 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/linux/pkg_config.gni")
+
+if (is_linux) {
+  # This is a dependency on NSS with no libssl. On Linux we use a built-in SSL
+  # library but the system NSS libraries. Non-Linux platforms using NSS use the
+  # hermetic one in //third_party/nss.
+  #
+  # Generally you should depend on //crypto:platform instead of using this
+  # config since that will properly pick up NSS or OpenSSL depending on
+  # platform and build config.
+  pkg_config("system_nss_no_ssl_config") {
+    packages = [ "nss" ]
+    extra_args = [
+      "-v",
+      "-lssl3",
+    ]
+  }
+} else {
+  include_nss_root_certs = is_ios
+  include_nss_libpkix = is_ios
+
+  config("nspr_config") {
+    defines = [ "NO_NSPR_10_SUPPORT" ]
+    include_dirs = [
+      "nspr/pr/include",
+      "nspr/lib/ds",
+      "nspr/lib/libc/include",
+    ]
+
+    if (component_mode != "shared_library") {
+      defines += [ "NSPR_STATIC" ]
+    }
+  }
+
+  component("nspr") {
+    output_name = "crnspr"
+    sources = [
+      "nspr/lib/ds/plarena.c",
+      "nspr/lib/ds/plarena.h",
+      "nspr/lib/ds/plarenas.h",
+      "nspr/lib/ds/plhash.c",
+      "nspr/lib/ds/plhash.h",
+      "nspr/lib/libc/include/plbase64.h",
+      "nspr/lib/libc/include/plerror.h",
+      "nspr/lib/libc/include/plgetopt.h",
+      "nspr/lib/libc/include/plstr.h",
+      "nspr/lib/libc/src/base64.c",
+      "nspr/lib/libc/src/plerror.c",
+      "nspr/lib/libc/src/plgetopt.c",
+      "nspr/lib/libc/src/strcase.c",
+      "nspr/lib/libc/src/strcat.c",
+      "nspr/lib/libc/src/strchr.c",
+      "nspr/lib/libc/src/strcmp.c",
+      "nspr/lib/libc/src/strcpy.c",
+      "nspr/lib/libc/src/strdup.c",
+      "nspr/lib/libc/src/strlen.c",
+      "nspr/lib/libc/src/strpbrk.c",
+      "nspr/lib/libc/src/strstr.c",
+      "nspr/lib/libc/src/strtok.c",
+      "nspr/pr/include/md/_darwin.cfg",
+      "nspr/pr/include/md/_darwin.h",
+      "nspr/pr/include/md/_pcos.h",
+      "nspr/pr/include/md/_pth.h",
+      "nspr/pr/include/md/_unix_errors.h",
+      "nspr/pr/include/md/_unixos.h",
+      "nspr/pr/include/md/_win32_errors.h",
+      "nspr/pr/include/md/_win95.cfg",
+      "nspr/pr/include/md/_win95.h",
+      "nspr/pr/include/md/prosdep.h",
+      "nspr/pr/include/nspr.h",
+      "nspr/pr/include/obsolete/pralarm.h",
+      "nspr/pr/include/obsolete/probslet.h",
+      "nspr/pr/include/obsolete/protypes.h",
+      "nspr/pr/include/obsolete/prsem.h",
+      "nspr/pr/include/pratom.h",
+      "nspr/pr/include/prbit.h",
+      "nspr/pr/include/prclist.h",
+      "nspr/pr/include/prcmon.h",
+      "nspr/pr/include/prcountr.h",
+      "nspr/pr/include/prcpucfg.h",
+      "nspr/pr/include/prcvar.h",
+      "nspr/pr/include/prdtoa.h",
+      "nspr/pr/include/prenv.h",
+      "nspr/pr/include/prerr.h",
+      "nspr/pr/include/prerror.h",
+      "nspr/pr/include/prinet.h",
+      "nspr/pr/include/prinit.h",
+      "nspr/pr/include/prinrval.h",
+      "nspr/pr/include/prio.h",
+      "nspr/pr/include/pripcsem.h",
+      "nspr/pr/include/private/pprio.h",
+      "nspr/pr/include/private/pprmwait.h",
+      "nspr/pr/include/private/pprthred.h",
+      "nspr/pr/include/private/primpl.h",
+      "nspr/pr/include/private/prpriv.h",
+      "nspr/pr/include/prlink.h",
+      "nspr/pr/include/prlock.h",
+      "nspr/pr/include/prlog.h",
+      "nspr/pr/include/prlong.h",
+      "nspr/pr/include/prmem.h",
+      "nspr/pr/include/prmon.h",
+      "nspr/pr/include/prmwait.h",
+      "nspr/pr/include/prnetdb.h",
+      "nspr/pr/include/prolock.h",
+      "nspr/pr/include/prpdce.h",
+      "nspr/pr/include/prprf.h",
+      "nspr/pr/include/prproces.h",
+      "nspr/pr/include/prrng.h",
+      "nspr/pr/include/prrwlock.h",
+      "nspr/pr/include/prshm.h",
+      "nspr/pr/include/prshma.h",
+      "nspr/pr/include/prsystem.h",
+      "nspr/pr/include/prthread.h",
+      "nspr/pr/include/prtime.h",
+      "nspr/pr/include/prtpool.h",
+      "nspr/pr/include/prtrace.h",
+      "nspr/pr/include/prtypes.h",
+      "nspr/pr/include/prvrsion.h",
+      "nspr/pr/include/prwin16.h",
+      "nspr/pr/src/io/prdir.c",
+      "nspr/pr/src/io/prfdcach.c",
+      "nspr/pr/src/io/prfile.c",
+      "nspr/pr/src/io/prio.c",
+      "nspr/pr/src/io/priometh.c",
+      "nspr/pr/src/io/pripv6.c",
+      "nspr/pr/src/io/prlayer.c",
+      "nspr/pr/src/io/prlog.c",
+      "nspr/pr/src/io/prmapopt.c",
+      "nspr/pr/src/io/prmmap.c",
+      "nspr/pr/src/io/prmwait.c",
+      "nspr/pr/src/io/prpolevt.c",
+      "nspr/pr/src/io/prprf.c",
+      "nspr/pr/src/io/prscanf.c",
+      "nspr/pr/src/io/prsocket.c",
+      "nspr/pr/src/io/prstdio.c",
+      "nspr/pr/src/linking/prlink.c",
+      "nspr/pr/src/malloc/prmalloc.c",
+      "nspr/pr/src/malloc/prmem.c",
+      "nspr/pr/src/md/prosdep.c",
+      "nspr/pr/src/md/unix/darwin.c",
+      "nspr/pr/src/md/unix/os_Darwin.s",
+      "nspr/pr/src/md/unix/unix.c",
+      "nspr/pr/src/md/unix/unix_errors.c",
+      "nspr/pr/src/md/unix/uxproces.c",
+      "nspr/pr/src/md/unix/uxrng.c",
+      "nspr/pr/src/md/unix/uxshm.c",
+      "nspr/pr/src/md/unix/uxwrap.c",
+      "nspr/pr/src/md/windows/ntgc.c",
+      "nspr/pr/src/md/windows/ntinrval.c",
+      "nspr/pr/src/md/windows/ntmisc.c",
+      "nspr/pr/src/md/windows/ntsec.c",
+      "nspr/pr/src/md/windows/ntsem.c",
+      "nspr/pr/src/md/windows/w32ipcsem.c",
+      "nspr/pr/src/md/windows/w32poll.c",
+      "nspr/pr/src/md/windows/w32rng.c",
+      "nspr/pr/src/md/windows/w32shm.c",
+      "nspr/pr/src/md/windows/w95cv.c",
+      "nspr/pr/src/md/windows/w95dllmain.c",
+      "nspr/pr/src/md/windows/w95io.c",
+      "nspr/pr/src/md/windows/w95sock.c",
+      "nspr/pr/src/md/windows/w95thred.c",
+      "nspr/pr/src/md/windows/win32_errors.c",
+      "nspr/pr/src/memory/prseg.c",
+      "nspr/pr/src/memory/prshm.c",
+      "nspr/pr/src/memory/prshma.c",
+      "nspr/pr/src/misc/pralarm.c",
+      "nspr/pr/src/misc/pratom.c",
+      "nspr/pr/src/misc/praton.c",
+      "nspr/pr/src/misc/prcountr.c",
+      "nspr/pr/src/misc/prdtoa.c",
+      "nspr/pr/src/misc/prenv.c",
+      "nspr/pr/src/misc/prerr.c",
+      "nspr/pr/src/misc/prerror.c",
+      "nspr/pr/src/misc/prerrortable.c",
+      "nspr/pr/src/misc/prinit.c",
+      "nspr/pr/src/misc/prinrval.c",
+      "nspr/pr/src/misc/pripc.c",
+      "nspr/pr/src/misc/pripcsem.c",
+      "nspr/pr/src/misc/prlog2.c",
+      "nspr/pr/src/misc/prlong.c",
+      "nspr/pr/src/misc/prnetdb.c",
+      "nspr/pr/src/misc/prolock.c",
+      "nspr/pr/src/misc/prrng.c",
+      "nspr/pr/src/misc/prsystem.c",
+      "nspr/pr/src/misc/prthinfo.c",
+      "nspr/pr/src/misc/prtime.c",
+      "nspr/pr/src/misc/prtpool.c",
+      "nspr/pr/src/misc/prtrace.c",
+      "nspr/pr/src/pthreads/ptio.c",
+      "nspr/pr/src/pthreads/ptmisc.c",
+      "nspr/pr/src/pthreads/ptsynch.c",
+      "nspr/pr/src/pthreads/ptthread.c",
+      "nspr/pr/src/threads/combined/prucpu.c",
+      "nspr/pr/src/threads/combined/prucv.c",
+      "nspr/pr/src/threads/combined/prulock.c",
+      "nspr/pr/src/threads/combined/prustack.c",
+      "nspr/pr/src/threads/combined/pruthr.c",
+      "nspr/pr/src/threads/prcmon.c",
+      "nspr/pr/src/threads/prcthr.c",
+      "nspr/pr/src/threads/prdump.c",
+      "nspr/pr/src/threads/prmon.c",
+      "nspr/pr/src/threads/prrwlock.c",
+      "nspr/pr/src/threads/prsem.c",
+      "nspr/pr/src/threads/prtpd.c",
+    ]
+
+    public_configs = [ ":nspr_config" ]
+
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    if (is_win) {
+      configs -= [
+        "//build/config/win:unicode",  # Requires 8-bit mode.
+        "//build/config/win:lean_and_mean",  # Won"t compile with lean and mean.
+      ]
+    }
+    configs += [
+      "//build/config/compiler:no_chromium_code",
+      "//build/config/compiler:no_size_t_to_int_warning",
+    ]
+
+    cflags = []
+    defines = [
+      "_NSPR_BUILD_",
+      "FORCE_PR_LOG",
+    ]
+
+    include_dirs = [ "nspr/pr/include/private" ]
+
+    if (is_win) {
+      cflags = [ "/wd4554" ]  # Check precidence.
+      defines += [
+        "XP_PC",
+        "WIN32",
+        "WIN95",
+        "_PR_GLOBAL_THREADS_ONLY",
+        "_CRT_SECURE_NO_WARNINGS",
+      ]
+    } else {
+      sources -= [
+        "nspr/pr/src/md/windows/ntgc.c",
+        "nspr/pr/src/md/windows/ntinrval.c",
+        "nspr/pr/src/md/windows/ntmisc.c",
+        "nspr/pr/src/md/windows/ntsec.c",
+        "nspr/pr/src/md/windows/ntsem.c",
+        "nspr/pr/src/md/windows/w32ipcsem.c",
+        "nspr/pr/src/md/windows/w32poll.c",
+        "nspr/pr/src/md/windows/w32rng.c",
+        "nspr/pr/src/md/windows/w32shm.c",
+        "nspr/pr/src/md/windows/w95cv.c",
+        "nspr/pr/src/md/windows/w95dllmain.c",
+        "nspr/pr/src/md/windows/w95io.c",
+        "nspr/pr/src/md/windows/w95sock.c",
+        "nspr/pr/src/md/windows/w95thred.c",
+        "nspr/pr/src/md/windows/win32_errors.c",
+        "nspr/pr/src/threads/combined/prucpu.c",
+        "nspr/pr/src/threads/combined/prucv.c",
+        "nspr/pr/src/threads/combined/prulock.c",
+        "nspr/pr/src/threads/combined/prustack.c",
+        "nspr/pr/src/threads/combined/pruthr.c",
+      ]
+    }
+
+    if (!is_posix) {
+      sources -= [
+        "nspr/pr/src/md/unix/darwin.c",
+        "nspr/pr/src/md/unix/os_Darwin.s",
+        "nspr/pr/src/md/unix/unix.c",
+        "nspr/pr/src/md/unix/unix_errors.c",
+        "nspr/pr/src/md/unix/uxproces.c",
+        "nspr/pr/src/md/unix/uxrng.c",
+        "nspr/pr/src/md/unix/uxshm.c",
+        "nspr/pr/src/md/unix/uxwrap.c",
+        "nspr/pr/src/pthreads/ptio.c",
+        "nspr/pr/src/pthreads/ptmisc.c",
+        "nspr/pr/src/pthreads/ptsynch.c",
+        "nspr/pr/src/pthreads/ptthread.c",
+      ]
+    }
+
+    if (current_cpu == "x86") {
+      defines += [ "_X86_" ]
+    } else if (current_cpu == "x64") {
+      defines += [ "_AMD64_" ]
+    }
+
+    if (is_mac || is_ios) {
+      sources -= [
+        "nspr/pr/src/io/prdir.c",
+        "nspr/pr/src/io/prfile.c",
+        "nspr/pr/src/io/prio.c",
+        "nspr/pr/src/io/prsocket.c",
+        "nspr/pr/src/misc/pripcsem.c",
+        "nspr/pr/src/threads/prcthr.c",
+        "nspr/pr/src/threads/prdump.c",
+        "nspr/pr/src/threads/prmon.c",
+        "nspr/pr/src/threads/prsem.c",
+      ]
+      defines += [
+        "XP_UNIX",
+        "DARWIN",
+        "XP_MACOSX",
+        "_PR_PTHREADS",
+        "HAVE_BSD_FLOCK",
+        "HAVE_DLADDR",
+        "HAVE_LCHOWN",
+        "HAVE_SOCKLEN_T",
+        "HAVE_STRERROR",
+      ]
+    }
+
+    if (is_mac) {
+      defines += [ "HAVE_CRT_EXTERNS_H" ]
+      libs = [
+        "CoreFoundation.framework",
+        "CoreServices.framework",
+      ]
+    }
+
+    if (is_clang) {
+      cflags += [
+        # nspr uses a bunch of deprecated functions (NSLinkModule etc) in
+        # prlink.c on mac.
+        "-Wno-deprecated-declarations",
+
+        # nspr passes "const char*" through "void*".
+        "-Wno-incompatible-pointer-types",
+
+        # nspr passes "int*" through "unsigned int*".
+        "-Wno-pointer-sign",
+      ]
+
+      # nspr uses assert(!"foo") instead of assert(false && "foo").
+      configs -= [ "//build/config/clang:extra_warnings" ]
+    }
+  }
+
+  component("nss") {
+    output_name = "crnss"
+    sources = [
+      # Ensure at least one object file is produced, so that MSVC does not
+      # warn when creating the static/shared library. See the note for
+      # the "nssckbi" target for why the "nss" target was split as such.
+      "nss/lib/nss/nssver.c",
+    ]
+
+    public_deps = [
+      ":nss_static",
+    ]
+
+    if (include_nss_root_certs) {
+      public_deps += [ ":nssckbi" ]
+    }
+
+    if (component_mode == "shared_library") {
+      if (is_mac) {
+        ldflags = [ "-all_load" ]
+      } else if (is_win) {
+        # Pass the def file to the linker.
+        ldflags =
+            [ "/DEF:" + rebase_path("nss/exports_win.def", root_build_dir) ]
+      }
+    }
+  }
+
+  config("nssckbi_config") {
+    include_dirs = [ "nss/lib/ckfw/builtins" ]
+  }
+
+  # This is really more of a pseudo-target to work around the fact that
+  # a single static_library target cannot contain two object files of the
+  # same name (hash.o / hash.obj). Logically, this is part of the
+  # "nss_static" target. By separating it out, it creates a possible
+  # circular dependency between "nss_static" and "nssckbi" when
+  # "exclude_nss_root_certs" is not specified, as "nss_static" depends on
+  # the "builtinsC_GetFunctionList" exported by this target. This is an
+  # artifact of how NSS is being statically built, which is not an
+  # officially supported configuration - normally, "nssckbi.dll/so" would
+  # depend on libnss3.dll/so, and the higher layer caller would instruct
+  # libnss3.dll to dynamically load nssckbi.dll, breaking the circle.
+  #
+  # TODO(rsleevi): http://crbug.com/128134 - Break the circular dependency
+  # without requiring nssckbi to be built as a shared library.
+  source_set("nssckbi") {
+    visibility = [ ":nss" ]  # This target is internal implementation detail.
+
+    sources = [
+      "nss/lib/ckfw/builtins/anchor.c",
+      "nss/lib/ckfw/builtins/bfind.c",
+      "nss/lib/ckfw/builtins/binst.c",
+      "nss/lib/ckfw/builtins/bobject.c",
+      "nss/lib/ckfw/builtins/bsession.c",
+      "nss/lib/ckfw/builtins/bslot.c",
+      "nss/lib/ckfw/builtins/btoken.c",
+      "nss/lib/ckfw/builtins/builtins.h",
+      "nss/lib/ckfw/builtins/certdata.c",
+      "nss/lib/ckfw/builtins/ckbiver.c",
+      "nss/lib/ckfw/builtins/constants.c",
+      "nss/lib/ckfw/builtins/nssckbi.h",
+      "nss/lib/ckfw/ck.h",
+      "nss/lib/ckfw/ckfw.h",
+      "nss/lib/ckfw/ckfwm.h",
+      "nss/lib/ckfw/ckfwtm.h",
+      "nss/lib/ckfw/ckmd.h",
+      "nss/lib/ckfw/ckt.h",
+      "nss/lib/ckfw/crypto.c",
+      "nss/lib/ckfw/find.c",
+      "nss/lib/ckfw/hash.c",
+      "nss/lib/ckfw/instance.c",
+      "nss/lib/ckfw/mechanism.c",
+      "nss/lib/ckfw/mutex.c",
+      "nss/lib/ckfw/nssck.api",
+      "nss/lib/ckfw/nssckepv.h",
+      "nss/lib/ckfw/nssckft.h",
+      "nss/lib/ckfw/nssckfw.h",
+      "nss/lib/ckfw/nssckfwc.h",
+      "nss/lib/ckfw/nssckfwt.h",
+      "nss/lib/ckfw/nssckg.h",
+      "nss/lib/ckfw/nssckmdt.h",
+      "nss/lib/ckfw/nssckt.h",
+      "nss/lib/ckfw/object.c",
+      "nss/lib/ckfw/session.c",
+      "nss/lib/ckfw/sessobj.c",
+      "nss/lib/ckfw/slot.c",
+      "nss/lib/ckfw/token.c",
+      "nss/lib/ckfw/wrap.c",
+    ]
+
+    configs -= [ "//build/config/compiler:chromium_code" ]
+
+    if (is_win) {
+      configs -= [ "//build/config/win:unicode" ]  # Requires 8-bit mode.
+    }
+    configs += [ "//build/config/compiler:no_chromium_code" ]
+
+    include_dirs = [ "nss/lib/ckfw" ]
+    public_configs = [ ":nssckbi_config" ]
+
+    public_deps = [
+      ":nss_static",
+    ]
+  }
+
+  config("nss_static_config") {
+    defines = [
+      "NSS_STATIC",
+      "NSS_USE_STATIC_LIBS",
+      "USE_UTIL_DIRECTLY",
+    ]
+    if (is_win) {
+      defines += [ "_WINDOWS" ]
+    }
+    include_dirs = [
+      "nspr/pr/include",
+      "nspr/lib/ds",
+      "nspr/lib/libc/include",
+      "nss/lib/base",
+      "nss/lib/certdb",
+      "nss/lib/certhigh",
+      "nss/lib/cryptohi",
+      "nss/lib/dev",
+      "nss/lib/freebl",
+      "nss/lib/freebl/ecl",
+      "nss/lib/nss",
+      "nss/lib/pk11wrap",
+      "nss/lib/pkcs7",
+      "nss/lib/pki",
+      "nss/lib/smime",
+      "nss/lib/softoken",
+      "nss/lib/util",
+    ]
+  }
+
+  if (is_win && current_cpu == "x86") {
+    source_set("nss_static_avx") {
+      sources = [
+        "nss/lib/freebl/intel-gcm-wrap.c",
+        "nss/lib/freebl/intel-gcm-x86-masm.asm",
+        "nss/lib/freebl/intel-gcm.h",
+      ]
+      defines = [
+        "_WINDOWS",
+        "_X86_",
+        "INTEL_GCM",
+        "MP_API_COMPATIBLE",
+        "MP_ASSEMBLY_DIV_2DX1D",
+        "MP_ASSEMBLY_MULTIPLY",
+        "MP_ASSEMBLY_SQUARE",
+        "MP_NO_MP_WORD",
+        "MP_USE_UINT_DIGIT",
+        "NSS_DISABLE_DBM",
+        "NSS_STATIC",
+        "NSS_USE_STATIC_LIBS",
+        "NSS_X86",
+        "NSS_X86_OR_X64",
+        "RIJNDAEL_INCLUDE_TABLES",
+        "SHLIB_PREFIX=\"\"",
+        "SHLIB_SUFFIX=\"dll\"",
+        "SHLIB_VERSION=\"3\"",
+        "SOFTOKEN_LIB_NAME=\"softokn3.dll\"",
+        "SOFTOKEN_SHLIB_VERSION=\"3\"",
+        "USE_HW_AES",
+        "USE_UTIL_DIRECTLY",
+        "WIN32",
+        "WIN95",
+        "XP_PC",
+      ]
+      include_dirs = [
+        "nspr/pr/include",
+        "nspr/lib/ds",
+        "nspr/lib/libc/include",
+        "nss/lib/freebl/ecl",
+        "nss/lib/util",
+      ]
+    }
+  }
+
+  source_set("nss_static") {
+    visibility = [ ":*" ]  # Internal implementation detail.
+
+    sources = [
+      "nss/lib/base/arena.c",
+      "nss/lib/base/base.h",
+      "nss/lib/base/baset.h",
+      "nss/lib/base/error.c",
+      "nss/lib/base/errorval.c",
+      "nss/lib/base/hash.c",
+      "nss/lib/base/hashops.c",
+      "nss/lib/base/item.c",
+      "nss/lib/base/libc.c",
+      "nss/lib/base/list.c",
+      "nss/lib/base/nssbase.h",
+      "nss/lib/base/nssbaset.h",
+      "nss/lib/base/nssutf8.c",
+      "nss/lib/base/tracker.c",
+      "nss/lib/certdb/alg1485.c",
+      "nss/lib/certdb/cert.h",
+      "nss/lib/certdb/certdb.c",
+      "nss/lib/certdb/certdb.h",
+      "nss/lib/certdb/certi.h",
+      "nss/lib/certdb/certt.h",
+      "nss/lib/certdb/certv3.c",
+      "nss/lib/certdb/certxutl.c",
+      "nss/lib/certdb/certxutl.h",
+      "nss/lib/certdb/crl.c",
+      "nss/lib/certdb/genname.c",
+      "nss/lib/certdb/genname.h",
+      "nss/lib/certdb/polcyxtn.c",
+      "nss/lib/certdb/secname.c",
+      "nss/lib/certdb/stanpcertdb.c",
+      "nss/lib/certdb/xauthkid.c",
+      "nss/lib/certdb/xbsconst.c",
+      "nss/lib/certdb/xconst.c",
+      "nss/lib/certdb/xconst.h",
+      "nss/lib/certhigh/certhigh.c",
+      "nss/lib/certhigh/certhtml.c",
+      "nss/lib/certhigh/certreq.c",
+      "nss/lib/certhigh/certvfy.c",
+      "nss/lib/certhigh/crlv2.c",
+      "nss/lib/certhigh/ocsp.c",
+      "nss/lib/certhigh/ocsp.h",
+      "nss/lib/certhigh/ocspi.h",
+      "nss/lib/certhigh/ocspsig.c",
+      "nss/lib/certhigh/ocspt.h",
+      "nss/lib/certhigh/ocspti.h",
+      "nss/lib/certhigh/xcrldist.c",
+      "nss/lib/cryptohi/cryptohi.h",
+      "nss/lib/cryptohi/cryptoht.h",
+      "nss/lib/cryptohi/dsautil.c",
+      "nss/lib/cryptohi/key.h",
+      "nss/lib/cryptohi/keyhi.h",
+      "nss/lib/cryptohi/keyi.h",
+      "nss/lib/cryptohi/keyt.h",
+      "nss/lib/cryptohi/keythi.h",
+      "nss/lib/cryptohi/sechash.c",
+      "nss/lib/cryptohi/sechash.h",
+      "nss/lib/cryptohi/seckey.c",
+      "nss/lib/cryptohi/secsign.c",
+      "nss/lib/cryptohi/secvfy.c",
+      "nss/lib/dev/ckhelper.c",
+      "nss/lib/dev/ckhelper.h",
+      "nss/lib/dev/dev.h",
+      "nss/lib/dev/devm.h",
+      "nss/lib/dev/devslot.c",
+      "nss/lib/dev/devt.h",
+      "nss/lib/dev/devtm.h",
+      "nss/lib/dev/devtoken.c",
+      "nss/lib/dev/devutil.c",
+      "nss/lib/dev/nssdev.h",
+      "nss/lib/dev/nssdevt.h",
+      "nss/lib/freebl/aeskeywrap.c",
+      "nss/lib/freebl/alg2268.c",
+      "nss/lib/freebl/alghmac.c",
+      "nss/lib/freebl/alghmac.h",
+      "nss/lib/freebl/arcfive.c",
+      "nss/lib/freebl/arcfour.c",
+      "nss/lib/freebl/blapi.h",
+      "nss/lib/freebl/blapii.h",
+      "nss/lib/freebl/blapit.h",
+      "nss/lib/freebl/camellia.c",
+      "nss/lib/freebl/camellia.h",
+      "nss/lib/freebl/chacha20/chacha20.c",
+      "nss/lib/freebl/chacha20/chacha20.h",
+      "nss/lib/freebl/chacha20/chacha20_vec.c",
+      "nss/lib/freebl/chacha20poly1305.c",
+      "nss/lib/freebl/chacha20poly1305.h",
+      "nss/lib/freebl/ctr.c",
+      "nss/lib/freebl/ctr.h",
+      "nss/lib/freebl/cts.c",
+      "nss/lib/freebl/cts.h",
+      "nss/lib/freebl/des.c",
+      "nss/lib/freebl/des.h",
+      "nss/lib/freebl/desblapi.c",
+      "nss/lib/freebl/dh.c",
+      "nss/lib/freebl/drbg.c",
+      "nss/lib/freebl/dsa.c",
+      "nss/lib/freebl/ec.c",
+      "nss/lib/freebl/ec.h",
+      "nss/lib/freebl/ecdecode.c",
+      "nss/lib/freebl/ecl/ec2.h",
+      "nss/lib/freebl/ecl/ec_naf.c",
+      "nss/lib/freebl/ecl/ecl-curve.h",
+      "nss/lib/freebl/ecl/ecl-exp.h",
+      "nss/lib/freebl/ecl/ecl-priv.h",
+      "nss/lib/freebl/ecl/ecl.c",
+      "nss/lib/freebl/ecl/ecl.h",
+      "nss/lib/freebl/ecl/ecl_curve.c",
+      "nss/lib/freebl/ecl/ecl_gf.c",
+      "nss/lib/freebl/ecl/ecl_mult.c",
+      "nss/lib/freebl/ecl/ecp.h",
+      "nss/lib/freebl/ecl/ecp_256.c",
+      "nss/lib/freebl/ecl/ecp_256_32.c",
+      "nss/lib/freebl/ecl/ecp_384.c",
+      "nss/lib/freebl/ecl/ecp_521.c",
+      "nss/lib/freebl/ecl/ecp_aff.c",
+      "nss/lib/freebl/ecl/ecp_jac.c",
+      "nss/lib/freebl/ecl/ecp_jm.c",
+      "nss/lib/freebl/ecl/ecp_mont.c",
+      "nss/lib/freebl/gcm.c",
+      "nss/lib/freebl/gcm.h",
+      "nss/lib/freebl/hmacct.c",
+      "nss/lib/freebl/hmacct.h",
+      "nss/lib/freebl/intel-aes-x86-masm.asm",
+      "nss/lib/freebl/intel-aes.h",
+      "nss/lib/freebl/jpake.c",
+      "nss/lib/freebl/md2.c",
+      "nss/lib/freebl/md5.c",
+      "nss/lib/freebl/mpi/logtab.h",
+      "nss/lib/freebl/mpi/mp_gf2m-priv.h",
+      "nss/lib/freebl/mpi/mp_gf2m.c",
+      "nss/lib/freebl/mpi/mp_gf2m.h",
+      "nss/lib/freebl/mpi/mpcpucache.c",
+      "nss/lib/freebl/mpi/mpi-config.h",
+      "nss/lib/freebl/mpi/mpi-priv.h",
+      "nss/lib/freebl/mpi/mpi.c",
+      "nss/lib/freebl/mpi/mpi.h",
+      "nss/lib/freebl/mpi/mpi_amd64.c",
+      "nss/lib/freebl/mpi/mpi_arm.c",
+      "nss/lib/freebl/mpi/mpi_arm_mac.c",
+      "nss/lib/freebl/mpi/mpi_x86_asm.c",
+      "nss/lib/freebl/mpi/mplogic.c",
+      "nss/lib/freebl/mpi/mplogic.h",
+      "nss/lib/freebl/mpi/mpmontg.c",
+      "nss/lib/freebl/mpi/mpprime.c",
+      "nss/lib/freebl/mpi/mpprime.h",
+      "nss/lib/freebl/mpi/primes.c",
+      "nss/lib/freebl/nss_build_config_mac.h",
+      "nss/lib/freebl/poly1305/poly1305-donna-x64-sse2-incremental-source.c",
+      "nss/lib/freebl/poly1305/poly1305.c",
+      "nss/lib/freebl/poly1305/poly1305.h",
+      "nss/lib/freebl/pqg.c",
+      "nss/lib/freebl/pqg.h",
+      "nss/lib/freebl/rawhash.c",
+      "nss/lib/freebl/rijndael.c",
+      "nss/lib/freebl/rijndael.h",
+      "nss/lib/freebl/rijndael32.tab",
+      "nss/lib/freebl/rsa.c",
+      "nss/lib/freebl/rsapkcs.c",
+      "nss/lib/freebl/secmpi.h",
+      "nss/lib/freebl/secrng.h",
+      "nss/lib/freebl/seed.c",
+      "nss/lib/freebl/seed.h",
+      "nss/lib/freebl/sha256.h",
+      "nss/lib/freebl/sha512.c",
+      "nss/lib/freebl/sha_fast.c",
+      "nss/lib/freebl/sha_fast.h",
+      "nss/lib/freebl/shsign.h",
+      "nss/lib/freebl/shvfy.c",
+      "nss/lib/freebl/sysrand.c",
+      "nss/lib/freebl/tlsprfalg.c",
+      "nss/lib/freebl/unix_rand.c",
+      "nss/lib/freebl/win_rand.c",
+      "nss/lib/nss/nss.h",
+      "nss/lib/nss/nssinit.c",
+      "nss/lib/nss/nssrenam.h",
+      "nss/lib/nss/utilwrap.c",
+      "nss/lib/pk11wrap/debug_module.c",
+      "nss/lib/pk11wrap/dev3hack.c",
+      "nss/lib/pk11wrap/dev3hack.h",
+      "nss/lib/pk11wrap/pk11akey.c",
+      "nss/lib/pk11wrap/pk11auth.c",
+      "nss/lib/pk11wrap/pk11cert.c",
+      "nss/lib/pk11wrap/pk11cxt.c",
+      "nss/lib/pk11wrap/pk11err.c",
+      "nss/lib/pk11wrap/pk11func.h",
+      "nss/lib/pk11wrap/pk11kea.c",
+      "nss/lib/pk11wrap/pk11list.c",
+      "nss/lib/pk11wrap/pk11load.c",
+      "nss/lib/pk11wrap/pk11mech.c",
+      "nss/lib/pk11wrap/pk11merge.c",
+      "nss/lib/pk11wrap/pk11nobj.c",
+      "nss/lib/pk11wrap/pk11obj.c",
+      "nss/lib/pk11wrap/pk11pars.c",
+      "nss/lib/pk11wrap/pk11pbe.c",
+      "nss/lib/pk11wrap/pk11pk12.c",
+      "nss/lib/pk11wrap/pk11pqg.c",
+      "nss/lib/pk11wrap/pk11pqg.h",
+      "nss/lib/pk11wrap/pk11priv.h",
+      "nss/lib/pk11wrap/pk11pub.h",
+      "nss/lib/pk11wrap/pk11sdr.c",
+      "nss/lib/pk11wrap/pk11sdr.h",
+      "nss/lib/pk11wrap/pk11skey.c",
+      "nss/lib/pk11wrap/pk11slot.c",
+      "nss/lib/pk11wrap/pk11util.c",
+      "nss/lib/pk11wrap/secmod.h",
+      "nss/lib/pk11wrap/secmodi.h",
+      "nss/lib/pk11wrap/secmodt.h",
+      "nss/lib/pk11wrap/secmodti.h",
+      "nss/lib/pk11wrap/secpkcs5.h",
+      "nss/lib/pkcs7/certread.c",
+      "nss/lib/pkcs7/p7common.c",
+      "nss/lib/pkcs7/p7create.c",
+      "nss/lib/pkcs7/p7decode.c",
+      "nss/lib/pkcs7/p7encode.c",
+      "nss/lib/pkcs7/p7local.c",
+      "nss/lib/pkcs7/p7local.h",
+      "nss/lib/pkcs7/pkcs7t.h",
+      "nss/lib/pkcs7/secmime.c",
+      "nss/lib/pkcs7/secmime.h",
+      "nss/lib/pkcs7/secpkcs7.h",
+      "nss/lib/pki/asymmkey.c",
+      "nss/lib/pki/certdecode.c",
+      "nss/lib/pki/certificate.c",
+      "nss/lib/pki/cryptocontext.c",
+      "nss/lib/pki/nsspki.h",
+      "nss/lib/pki/nsspkit.h",
+      "nss/lib/pki/pki.h",
+      "nss/lib/pki/pki3hack.c",
+      "nss/lib/pki/pki3hack.h",
+      "nss/lib/pki/pkibase.c",
+      "nss/lib/pki/pkim.h",
+      "nss/lib/pki/pkistore.c",
+      "nss/lib/pki/pkistore.h",
+      "nss/lib/pki/pkit.h",
+      "nss/lib/pki/pkitm.h",
+      "nss/lib/pki/symmkey.c",
+      "nss/lib/pki/tdcache.c",
+      "nss/lib/pki/trustdomain.c",
+      "nss/lib/smime/cms.h",
+      "nss/lib/smime/cmslocal.h",
+      "nss/lib/smime/cmsreclist.h",
+      "nss/lib/smime/cmst.h",
+      "nss/lib/smime/smime.h",
+      "nss/lib/softoken/fipsaudt.c",
+      "nss/lib/softoken/fipstest.c",
+      "nss/lib/softoken/fipstokn.c",
+      "nss/lib/softoken/jpakesftk.c",
+      "nss/lib/softoken/lgglue.c",
+      "nss/lib/softoken/lgglue.h",
+      "nss/lib/softoken/lowkey.c",
+      "nss/lib/softoken/lowkeyi.h",
+      "nss/lib/softoken/lowkeyti.h",
+      "nss/lib/softoken/lowpbe.c",
+      "nss/lib/softoken/lowpbe.h",
+      "nss/lib/softoken/padbuf.c",
+      "nss/lib/softoken/pkcs11.c",
+      "nss/lib/softoken/pkcs11c.c",
+      "nss/lib/softoken/pkcs11i.h",
+      "nss/lib/softoken/pkcs11ni.h",
+      "nss/lib/softoken/pkcs11u.c",
+      "nss/lib/softoken/sdb.c",
+      "nss/lib/softoken/sdb.h",
+      "nss/lib/softoken/sftkdb.c",
+      "nss/lib/softoken/sftkdb.h",
+      "nss/lib/softoken/sftkdbt.h",
+      "nss/lib/softoken/sftkdbti.h",
+      "nss/lib/softoken/sftkhmac.c",
+      "nss/lib/softoken/sftkpars.c",
+      "nss/lib/softoken/sftkpars.h",
+      "nss/lib/softoken/sftkpwd.c",
+      "nss/lib/softoken/softkver.c",
+      "nss/lib/softoken/softkver.h",
+      "nss/lib/softoken/softoken.h",
+      "nss/lib/softoken/softoknt.h",
+      "nss/lib/softoken/tlsprf.c",
+      "nss/lib/ssl/sslerr.h",
+      "nss/lib/util/SECerrs.h",
+      "nss/lib/util/base64.h",
+      "nss/lib/util/ciferfam.h",
+      "nss/lib/util/derdec.c",
+      "nss/lib/util/derenc.c",
+      "nss/lib/util/dersubr.c",
+      "nss/lib/util/dertime.c",
+      "nss/lib/util/errstrs.c",
+      "nss/lib/util/hasht.h",
+      "nss/lib/util/nssb64.h",
+      "nss/lib/util/nssb64d.c",
+      "nss/lib/util/nssb64e.c",
+      "nss/lib/util/nssb64t.h",
+      "nss/lib/util/nssilckt.h",
+      "nss/lib/util/nssilock.c",
+      "nss/lib/util/nssilock.h",
+      "nss/lib/util/nsslocks.h",
+      "nss/lib/util/nssrwlk.c",
+      "nss/lib/util/nssrwlk.h",
+      "nss/lib/util/nssrwlkt.h",
+      "nss/lib/util/nssutil.h",
+      "nss/lib/util/oidstring.c",
+      "nss/lib/util/pkcs11.h",
+      "nss/lib/util/pkcs11f.h",
+      "nss/lib/util/pkcs11n.h",
+      "nss/lib/util/pkcs11p.h",
+      "nss/lib/util/pkcs11t.h",
+      "nss/lib/util/pkcs11u.h",
+      "nss/lib/util/pkcs1sig.c",
+      "nss/lib/util/pkcs1sig.h",
+      "nss/lib/util/portreg.c",
+      "nss/lib/util/portreg.h",
+      "nss/lib/util/quickder.c",
+      "nss/lib/util/secalgid.c",
+      "nss/lib/util/secasn1.h",
+      "nss/lib/util/secasn1d.c",
+      "nss/lib/util/secasn1e.c",
+      "nss/lib/util/secasn1t.h",
+      "nss/lib/util/secasn1u.c",
+      "nss/lib/util/seccomon.h",
+      "nss/lib/util/secder.h",
+      "nss/lib/util/secdert.h",
+      "nss/lib/util/secdig.c",
+      "nss/lib/util/secdig.h",
+      "nss/lib/util/secdigt.h",
+      "nss/lib/util/secerr.h",
+      "nss/lib/util/secitem.c",
+      "nss/lib/util/secitem.h",
+      "nss/lib/util/secoid.c",
+      "nss/lib/util/secoid.h",
+      "nss/lib/util/secoidt.h",
+      "nss/lib/util/secport.c",
+      "nss/lib/util/secport.h",
+      "nss/lib/util/sectime.c",
+      "nss/lib/util/templates.c",
+      "nss/lib/util/utf8.c",
+      "nss/lib/util/utilmod.c",
+      "nss/lib/util/utilmodt.h",
+      "nss/lib/util/utilpars.c",
+      "nss/lib/util/utilpars.h",
+      "nss/lib/util/utilparst.h",
+      "nss/lib/util/utilrename.h",
+    ]
+
+    sources -= [
+      # mpi_arm.c is included by mpi_arm_mac.c.
+      # NOTE: mpi_arm.c can be used directly on Linux. mpi_arm.c will need
+      # to be excluded conditionally if we start to build NSS on Linux.
+      "nss/lib/freebl/mpi/mpi_arm.c",
+
+      # primes.c is included by mpprime.c.
+      "nss/lib/freebl/mpi/primes.c",
+
+      # unix_rand.c and win_rand.c are included by sysrand.c.
+      "nss/lib/freebl/unix_rand.c",
+      "nss/lib/freebl/win_rand.c",
+
+      # debug_module.c is included by pk11load.c.
+      "nss/lib/pk11wrap/debug_module.c",
+    ]
+
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    if (is_win) {
+      configs -= [ "//build/config/win:unicode" ]  # Requires 8-bit mode.
+    }
+    configs += [
+      "//build/config/compiler:no_chromium_code",
+      "//build/config/compiler:no_size_t_to_int_warning",
+    ]
+    public_configs = [ ":nss_static_config" ]
+
+    cflags = []
+
+    # Only need the defines and includes not in nss_static_config.
+    defines = [
+      "MP_API_COMPATIBLE",
+      "NSS_DISABLE_DBM",
+      "RIJNDAEL_INCLUDE_TABLES",
+      "SHLIB_VERSION=\"3\"",
+      "SOFTOKEN_SHLIB_VERSION=\"3\"",
+    ]
+    include_dirs = [
+      "nss/lib/freebl/mpi",
+      "nss/lib/ssl",
+    ]
+
+    if (is_win) {
+      cflags += [ "/wd4101" ]  # Unreferenced local variable.
+    }
+
+    if (include_nss_libpkix) {
+      sources += [
+        "nss/lib/certhigh/certvfypkix.c",
+        "nss/lib/certhigh/certvfypkixprint.c",
+        "nss/lib/libpkix/include/pkix.h",
+        "nss/lib/libpkix/include/pkix_certsel.h",
+        "nss/lib/libpkix/include/pkix_certstore.h",
+        "nss/lib/libpkix/include/pkix_checker.h",
+        "nss/lib/libpkix/include/pkix_crlsel.h",
+        "nss/lib/libpkix/include/pkix_errorstrings.h",
+        "nss/lib/libpkix/include/pkix_params.h",
+        "nss/lib/libpkix/include/pkix_pl_pki.h",
+        "nss/lib/libpkix/include/pkix_pl_system.h",
+        "nss/lib/libpkix/include/pkix_results.h",
+        "nss/lib/libpkix/include/pkix_revchecker.h",
+        "nss/lib/libpkix/include/pkix_sample_modules.h",
+        "nss/lib/libpkix/include/pkix_util.h",
+        "nss/lib/libpkix/include/pkixt.h",
+        "nss/lib/libpkix/pkix/certsel/pkix_certselector.c",
+        "nss/lib/libpkix/pkix/certsel/pkix_certselector.h",
+        "nss/lib/libpkix/pkix/certsel/pkix_comcertselparams.c",
+        "nss/lib/libpkix/pkix/certsel/pkix_comcertselparams.h",
+        "nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_basicconstraintschecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_certchainchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_certchainchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_crlchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_crlchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_ekuchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_ekuchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_expirationchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_expirationchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_namechainingchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_nameconstraintschecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_ocspchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_ocspchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_policychecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_policychecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_revocationchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_revocationchecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_revocationmethod.c",
+        "nss/lib/libpkix/pkix/checker/pkix_revocationmethod.h",
+        "nss/lib/libpkix/pkix/checker/pkix_signaturechecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_signaturechecker.h",
+        "nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.c",
+        "nss/lib/libpkix/pkix/checker/pkix_targetcertchecker.h",
+        "nss/lib/libpkix/pkix/crlsel/pkix_comcrlselparams.c",
+        "nss/lib/libpkix/pkix/crlsel/pkix_comcrlselparams.h",
+        "nss/lib/libpkix/pkix/crlsel/pkix_crlselector.c",
+        "nss/lib/libpkix/pkix/crlsel/pkix_crlselector.h",
+        "nss/lib/libpkix/pkix/params/pkix_procparams.c",
+        "nss/lib/libpkix/pkix/params/pkix_procparams.h",
+        "nss/lib/libpkix/pkix/params/pkix_resourcelimits.c",
+        "nss/lib/libpkix/pkix/params/pkix_resourcelimits.h",
+        "nss/lib/libpkix/pkix/params/pkix_trustanchor.c",
+        "nss/lib/libpkix/pkix/params/pkix_trustanchor.h",
+        "nss/lib/libpkix/pkix/params/pkix_valparams.c",
+        "nss/lib/libpkix/pkix/params/pkix_valparams.h",
+        "nss/lib/libpkix/pkix/results/pkix_buildresult.c",
+        "nss/lib/libpkix/pkix/results/pkix_buildresult.h",
+        "nss/lib/libpkix/pkix/results/pkix_policynode.c",
+        "nss/lib/libpkix/pkix/results/pkix_policynode.h",
+        "nss/lib/libpkix/pkix/results/pkix_valresult.c",
+        "nss/lib/libpkix/pkix/results/pkix_valresult.h",
+        "nss/lib/libpkix/pkix/results/pkix_verifynode.c",
+        "nss/lib/libpkix/pkix/results/pkix_verifynode.h",
+        "nss/lib/libpkix/pkix/store/pkix_store.c",
+        "nss/lib/libpkix/pkix/store/pkix_store.h",
+        "nss/lib/libpkix/pkix/top/pkix_build.c",
+        "nss/lib/libpkix/pkix/top/pkix_build.h",
+        "nss/lib/libpkix/pkix/top/pkix_lifecycle.c",
+        "nss/lib/libpkix/pkix/top/pkix_lifecycle.h",
+        "nss/lib/libpkix/pkix/top/pkix_validate.c",
+        "nss/lib/libpkix/pkix/top/pkix_validate.h",
+        "nss/lib/libpkix/pkix/util/pkix_error.c",
+        "nss/lib/libpkix/pkix/util/pkix_error.h",
+        "nss/lib/libpkix/pkix/util/pkix_errpaths.c",
+        "nss/lib/libpkix/pkix/util/pkix_list.c",
+        "nss/lib/libpkix/pkix/util/pkix_list.h",
+        "nss/lib/libpkix/pkix/util/pkix_logger.c",
+        "nss/lib/libpkix/pkix/util/pkix_logger.h",
+        "nss/lib/libpkix/pkix/util/pkix_tools.c",
+        "nss/lib/libpkix/pkix/util/pkix_tools.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c",
+        "nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c",
+        "nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c",
+        "nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h",
+      ]
+
+      # Disable the LDAP code in libpkix.
+      defines += [ "NSS_PKIX_NO_LDAP" ]
+
+      include_dirs += [
+        "nss/lib/libpkix/include",
+        "nss/lib/libpkix/pkix/certsel",
+        "nss/lib/libpkix/pkix/checker",
+        "nss/lib/libpkix/pkix/crlsel",
+        "nss/lib/libpkix/pkix/params",
+        "nss/lib/libpkix/pkix/results",
+        "nss/lib/libpkix/pkix/store",
+        "nss/lib/libpkix/pkix/top",
+        "nss/lib/libpkix/pkix/util",
+        "nss/lib/libpkix/pkix_pl_nss/module",
+        "nss/lib/libpkix/pkix_pl_nss/pki",
+        "nss/lib/libpkix/pkix_pl_nss/system",
+      ]
+    } else {
+      defines += [ "NSS_DISABLE_LIBPKIX" ]
+    }
+
+    if (!include_nss_root_certs) {
+      defines += [ "NSS_DISABLE_ROOT_CERTS" ]
+    }
+
+    if (current_cpu == "x64" && !is_win) {
+      sources -= [
+        "nss/lib/freebl/chacha20/chacha20.c",
+        "nss/lib/freebl/poly1305/poly1305.c",
+      ]
+    } else {
+      sources -= [
+        "nss/lib/freebl/chacha20/chacha20_vec.c",
+        "nss/lib/freebl/poly1305/poly1305-donna-x64-sse2-incremental-source.c",
+      ]
+    }
+
+    if (is_mac || is_ios) {
+      sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ]
+      cflags += [
+        "-include",
+        rebase_path("//third_party/nss/nss/lib/freebl/nss_build_config_mac.h",
+                    root_build_dir),
+      ]
+      defines += [
+        "XP_UNIX",
+        "DARWIN",
+        "HAVE_STRERROR",
+        "HAVE_BSD_FLOCK",
+        "SHLIB_SUFFIX=\"dylib\"",
+        "SHLIB_PREFIX=\"lib\"",
+        "SOFTOKEN_LIB_NAME=\"libsoftokn3.dylib\"",
+      ]
+
+      configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
+    } else {
+      # Not Mac/iOS.
+      sources -= [ "nss/lib/freebl/mpi/mpi_arm_mac.c" ]
+    }
+
+    if (is_win) {
+      defines += [
+        "SHLIB_SUFFIX=\"dll\"",
+        "SHLIB_PREFIX=\"\"",
+        "SOFTOKEN_LIB_NAME=\"softokn3.dll\"",
+        "XP_PC",
+        "WIN32",
+        "WIN95",
+      ]
+
+      if (current_cpu == "x86") {
+        defines += [
+          "NSS_X86_OR_X64",
+          "NSS_X86",
+          "_X86_",
+          "MP_ASSEMBLY_MULTIPLY",
+          "MP_ASSEMBLY_SQUARE",
+          "MP_ASSEMBLY_DIV_2DX1D",
+          "MP_USE_UINT_DIGIT",
+          "MP_NO_MP_WORD",
+          "USE_HW_AES",
+          "INTEL_GCM",
+        ]
+        sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ]
+      } else if (current_cpu == "x64") {
+        sources -= [
+          "nss/lib/freebl/intel-aes-x86-masm.asm",
+          "nss/lib/freebl/mpi/mpi_amd64.c",
+          "nss/lib/freebl/mpi/mpi_x86_asm.c",
+        ]
+        defines += [
+          "NSS_USE_64",
+          "NSS_X86_OR_X64",
+          "NSS_X64",
+          "_AMD64_",
+          "MP_CHAR_STORE_SLOW",
+          "MP_IS_LITTLE_ENDIAN",
+          "WIN64",
+        ]
+      }
+    } else {
+      # Not Windows.
+      sources -= [
+        # mpi_x86_asm.c contains MSVC inline assembly code.
+        "nss/lib/freebl/mpi/mpi_x86_asm.c",
+      ]
+    }
+
+    if (is_clang) {
+      cflags += [
+        # nss doesn"t explicitly cast between different enum types.
+        "-Wno-conversion",
+
+        # nss passes "const char*" through "void*".
+        "-Wno-incompatible-pointer-types",
+
+        # nss prefers `a && b || c` over `(a && b) || c`.
+        "-Wno-logical-op-parentheses",
+
+        # nss doesn"t use exhaustive switches on enums
+        "-Wno-switch",
+
+        # nss has some `unsigned < 0` checks.
+        "-Wno-tautological-compare",
+      ]
+    }
+
+    public_deps = [
+      ":nspr",
+    ]
+    deps = [
+      ":nspr",
+      "//third_party/sqlite",
+    ]
+
+    if (is_win && current_cpu == "x86") {
+      deps += [ ":nss_static_avx" ]
+    }
+  }
+}  # Windows/Mac/iOS.
diff --git a/build/secondary/tools/grit/BUILD.gn b/build/secondary/tools/grit/BUILD.gn
new file mode 100644
index 0000000..660bf1b
--- /dev/null
+++ b/build/secondary/tools/grit/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This target creates a stamp file that depends on all the sources in the grit
+# directory. By depending on this, a target can force itself to be rebuilt if
+# grit itself changes.
+action("grit_sources") {
+  depfile = "$target_out_dir/grit_sources.d"
+  script = "//build/secondary/tools/grit/stamp_grit_sources.py"
+
+  inputs = [
+    "grit.py",
+  ]
+
+  # Note that we can't call this "grit_sources.stamp" because that file is
+  # implicitly created by GN for script actions.
+  outputs = [
+    "$target_out_dir/grit_sources.script.stamp",
+  ]
+
+  args = [
+    rebase_path("//tools/grit", root_build_dir),
+    rebase_path(outputs[0], root_build_dir),
+    rebase_path(depfile, root_build_dir),
+  ]
+}
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni
new file mode 100644
index 0000000..35bbed3
--- /dev/null
+++ b/build/secondary/tools/grit/grit_rule.gni
@@ -0,0 +1,468 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Instantiate grit. This will produce a script target to run grit, and a
+# static library that compiles the .cc files.
+#
+# Parameters
+#
+#   source (required)
+#       Path to .grd file.
+#
+#   outputs (required)
+#       List of outputs from grit, relative to the target_gen_dir. If supplied,
+#       a call to Grit to compute the outputs can be skipped which will make
+#       GN run faster. Grit will verify at build time that this list is correct
+#       and will fail if there is a mismatch between the outputs specified by
+#       the .grd file and the outputs list here.
+#
+#       To get this list, you can look in the .grd file for
+#       <output filename="..." and put those filename here. The base directory
+#       of the list in Grit and the output list specified in the GN grit target
+#       are the same (the target_gen_dir) so you can generally copy the names
+#       exactly.
+#
+#       To get the list of outputs programatically, run:
+#           python tools/grit/grit_info.py --outputs . path/to/your.grd
+#       And strip the leading "./" from the output files.
+#
+#   defines (optional)
+#       Extra defines to pass to grit (on top of the global grit_defines list).
+#
+#   grit_flags (optional)
+#       List of strings containing extra command-line flags to pass to Grit.
+#
+#   resource_ids (optional)
+#       Path to a grit "firstidsfile". Default is
+#       //tools/gritsettings/resource_ids. Set to "" to use the value specified
+#       in the <grit> nodes of the processed files.
+#
+#   output_dir (optional)
+#       Directory for generated files. If you specify this, you will often
+#       want to specify output_name if the target name is not particularly
+#       unique, since this can cause files from multiple grit targets to
+#       overwrite each other.
+#
+#   output_name (optiona)
+#       Provide an alternate base name for the generated files, like the .d
+#       files. Normally these are based on the target name and go in the
+#       output_dir, but if multiple targets with the same name end up in
+#       the same output_dir, they can collide.
+#
+#   use_qualified_include (optional)
+#       If set, output_dir is not added to include_dirs.
+#
+#   configs (optional)
+#       List of additional configs to be applied to the generated target.
+#   deps  (optional)
+#   inputs  (optional)
+#       List of additional files, required for grit to process source file.
+#   visibility  (optional)
+#       Normal meaning.
+#
+# Example
+#
+#   grit("my_resources") {
+#     # Source and outputs are required.
+#     source = "myfile.grd"
+#     outputs = [
+#       "foo_strings.h",
+#       "foo_strings.pak",
+#     ]
+#
+#     grit_flags = [ "-E", "foo=bar" ]  # Optional extra flags.
+#     # You can also put deps here if the grit source depends on generated
+#     # files.
+#   }
+import("//build/config/chrome_build.gni")
+import("//build/config/crypto.gni")
+import("//build/config/features.gni")
+import("//build/config/ui.gni")
+
+grit_defines = []
+
+# Mac and iOS want Title Case strings.
+use_titlecase_in_grd_files = is_mac || is_ios
+if (use_titlecase_in_grd_files) {
+  grit_defines += [
+    "-D",
+    "use_titlecase",
+  ]
+}
+
+if (is_chrome_branded) {
+  grit_defines += [
+    "-D",
+    "_google_chrome",
+    "-E",
+    "CHROMIUM_BUILD=google_chrome",
+  ]
+} else {
+  grit_defines += [
+    "-D",
+    "_chromium",
+    "-E",
+    "CHROMIUM_BUILD=chromium",
+  ]
+}
+
+if (is_chromeos) {
+  grit_defines += [
+    "-D",
+    "chromeos",
+    "-D",
+    "scale_factors=2x",
+  ]
+}
+
+if (is_desktop_linux) {
+  grit_defines += [
+    "-D",
+    "desktop_linux",
+  ]
+}
+
+if (toolkit_views) {
+  grit_defines += [
+    "-D",
+    "toolkit_views",
+  ]
+}
+
+if (use_aura) {
+  grit_defines += [
+    "-D",
+    "use_aura",
+  ]
+}
+
+if (use_ash) {
+  grit_defines += [
+    "-D",
+    "use_ash",
+  ]
+}
+
+if (use_nss_certs) {
+  grit_defines += [
+    "-D",
+    "use_nss_certs",
+  ]
+}
+
+if (use_ozone) {
+  grit_defines += [
+    "-D",
+    "use_ozone",
+  ]
+}
+
+if (enable_image_loader_extension) {
+  grit_defines += [
+    "-D",
+    "image_loader_extension",
+  ]
+}
+
+if (enable_remoting) {
+  grit_defines += [
+    "-D",
+    "remoting",
+  ]
+}
+
+if (is_android) {
+  grit_defines += [
+    "-t",
+    "android",
+    "-E",
+    "ANDROID_JAVA_TAGGED_ONLY=true",
+  ]
+}
+
+if (is_mac || is_ios) {
+  grit_defines += [
+    "-D",
+    "scale_factors=2x",
+  ]
+}
+
+if (is_ios) {
+  grit_defines += [
+    "-t",
+    "ios",
+
+    # iOS uses a whitelist to filter resources.
+    "-w",
+    rebase_path("//build/ios/grit_whitelist.txt", root_build_dir),
+  ]
+}
+
+if (enable_extensions) {
+  grit_defines += [
+    "-D",
+    "enable_extensions",
+  ]
+}
+if (enable_media_router) {
+  grit_defines += [
+    "-D",
+    "enable_media_router",
+  ]
+}
+if (enable_plugins) {
+  grit_defines += [
+    "-D",
+    "enable_plugins",
+  ]
+}
+if (enable_basic_printing || enable_print_preview) {
+  grit_defines += [
+    "-D",
+    "enable_printing",
+  ]
+  if (enable_print_preview) {
+    grit_defines += [
+      "-D",
+      "enable_print_preview",
+    ]
+  }
+}
+if (enable_themes) {
+  grit_defines += [
+    "-D",
+    "enable_themes",
+  ]
+}
+if (enable_app_list) {
+  grit_defines += [
+    "-D",
+    "enable_app_list",
+  ]
+}
+if (enable_settings_app) {
+  grit_defines += [
+    "-D",
+    "enable_settings_app",
+  ]
+}
+if (enable_google_now) {
+  grit_defines += [
+    "-D",
+    "enable_google_now",
+  ]
+}
+
+# Note: use_concatenated_impulse_responses is omitted. It is never used and
+# should probably be removed from GYP build.
+if (enable_webrtc) {
+  grit_defines += [
+    "-D",
+    "enable_webrtc",
+  ]
+}
+if (enable_hangout_services_extension) {
+  grit_defines += [
+    "-D",
+    "enable_hangout_services_extension",
+  ]
+}
+if (enable_task_manager) {
+  grit_defines += [
+    "-D",
+    "enable_task_manager",
+  ]
+}
+if (enable_notifications) {
+  grit_defines += [
+    "-D",
+    "enable_notifications",
+  ]
+}
+if (enable_wifi_bootstrapping) {
+  grit_defines += [
+    "-D",
+    "enable_wifi_bootstrapping",
+  ]
+}
+if (enable_service_discovery) {
+  grit_defines += [
+    "-D",
+    "enable_service_discovery",
+  ]
+}
+if (mac_views_browser) {
+  grit_defines += [
+    "-D",
+    "mac_views_browser",
+  ]
+}
+
+grit_resource_id_file = "//tools/gritsettings/resource_ids"
+grit_info_script = "//tools/grit/grit_info.py"
+
+template("grit") {
+  assert(defined(invoker.source),
+         "\"source\" must be defined for the grit template $target_name")
+
+  grit_inputs = [ invoker.source ]
+
+  if (defined(invoker.resource_ids)) {
+    resource_ids = invoker.resource_ids
+  } else {
+    resource_ids = grit_resource_id_file
+  }
+  grit_inputs += [ resource_ids ]  # Script depends on ID file.
+
+  if (defined(invoker.output_dir)) {
+    output_dir = invoker.output_dir
+  } else {
+    output_dir = target_gen_dir
+  }
+
+  if (defined(invoker.output_name)) {
+    grit_output_name = invoker.output_name
+  } else {
+    grit_output_name = target_name
+  }
+
+  # These are all passed as arguments to the script so have to be relative to
+  # the build directory.
+  if (resource_ids != "") {
+    resource_ids = rebase_path(resource_ids, root_build_dir)
+  }
+  rebased_output_dir = rebase_path(output_dir, root_build_dir)
+  source_path = rebase_path(invoker.source, root_build_dir)
+
+  if (defined(invoker.grit_flags)) {
+    grit_flags = invoker.grit_flags
+  } else {
+    grit_flags = []  # These are optional so default to empty list.
+  }
+
+  assert_files_flags = []
+
+  # We want to make sure the declared outputs actually match what Grit is
+  # writing. We write the list to a file (some of the output lists are long
+  # enough to not fit on a Windows command line) and ask Grit to verify those
+  # are the actual outputs at runtime.
+  asserted_list_file =
+      "$target_out_dir/${grit_output_name}_expected_outputs.txt"
+  write_file(asserted_list_file,
+             rebase_path(invoker.outputs, root_build_dir, output_dir))
+  assert_files_flags += [ "--assert-file-list=" +
+                          rebase_path(asserted_list_file, root_build_dir) ]
+  grit_outputs =
+      get_path_info(rebase_path(invoker.outputs, ".", output_dir), "abspath")
+
+  # The config and the action below get this visibility son only the generated
+  # source set can depend on them. The variable "target_name" will get
+  # overwritten inside the inner classes so we need to compute it here.
+  target_visibility = [ ":$target_name" ]
+
+  # The current grit setup makes an file in $output_dir/grit/foo.h that
+  # the source code expects to include via "grit/foo.h". It would be nice to
+  # change this to including absolute paths relative to the root gen directory
+  # (like "mycomponent/foo.h"). This config sets up the include path.
+  grit_config = target_name + "_grit_config"
+  config(grit_config) {
+    if (!defined(invoker.use_qualified_include) ||
+        !invoker.use_qualified_include) {
+      include_dirs = [ output_dir ]
+    }
+    visibility = target_visibility
+  }
+
+  grit_custom_target = target_name + "_grit"
+  action(grit_custom_target) {
+    script = "//tools/grit/grit.py"
+    inputs = grit_inputs
+
+    depfile = "$output_dir/${grit_output_name}_stamp.d"
+    outputs = [ "${depfile}.stamp" ] + grit_outputs
+
+    args = [
+      "-i",
+      source_path,
+      "build",
+    ]
+    if (resource_ids != "") {
+      args += [
+        "-f",
+        resource_ids,
+      ]
+    }
+    args += [
+              "-o",
+              rebased_output_dir,
+              "--depdir",
+              ".",
+              "--depfile",
+              rebase_path(depfile, root_build_dir),
+              "--write-only-new=1",
+              "--depend-on-stamp",
+            ] + grit_defines
+
+    # Add extra defines with -D flags.
+    if (defined(invoker.defines)) {
+      foreach(i, invoker.defines) {
+        args += [
+          "-D",
+          i,
+        ]
+      }
+    }
+
+    args += grit_flags + assert_files_flags
+
+    if (defined(invoker.visibility)) {
+      # This needs to include both what the invoker specified (since they
+      # probably include generated headers from this target), as well as the
+      # generated source set (since there's no guarantee that the visibility
+      # specified by the invoker includes our target).
+      #
+      # Only define visibility at all if the invoker specified it. Otherwise,
+      # we want to keep the public "no visibility specified" default.
+      visibility = target_visibility + invoker.visibility
+    }
+
+    deps = [
+      "//tools/grit:grit_sources",
+    ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+    if (defined(invoker.inputs)) {
+      inputs += invoker.inputs
+    }
+  }
+
+  # This is the thing that people actually link with, it must be named the
+  # same as the argument the template was invoked with.
+  source_set(target_name) {
+    # Since we generate a file, we need to be run before the targets that
+    # depend on us.
+    sources = grit_outputs
+
+    # Deps set on the template invocation will go on the grit script running
+    # target rather than this library.
+    deps = [
+      ":$grit_custom_target",
+    ]
+    public_configs = [ ":$grit_config" ]
+
+    if (defined(invoker.public_configs)) {
+      public_configs += invoker.public_configs
+    }
+
+    if (defined(invoker.configs)) {
+      configs += invoker.configs
+    }
+
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+    output_name = grit_output_name
+  }
+}
diff --git a/build/secondary/tools/grit/repack.gni b/build/secondary/tools/grit/repack.gni
new file mode 100644
index 0000000..1030674
--- /dev/null
+++ b/build/secondary/tools/grit/repack.gni
@@ -0,0 +1,47 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file defines a template to invoke grit repack in a consistent manner.
+#
+# Parameters:
+#   sources  [required]
+#       List of pak files that need to be combined.
+#
+#   output  [required]
+#       File name (single string) of the output file.
+#
+#   repack_options  [optional]
+#       List of extra arguments to pass.
+#
+#   deps  [optional]
+#   visibility  [optional]
+#       Normal meaning.
+template("repack") {
+  action(target_name) {
+    assert(defined(invoker.sources), "Need sources for $target_name")
+    assert(defined(invoker.output), "Need output for $target_name")
+
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+
+    script = "//tools/grit/grit/format/repack.py"
+
+    inputs = invoker.sources
+    outputs = [
+      invoker.output,
+    ]
+
+    args = []
+    if (defined(invoker.repack_options)) {
+      args += invoker.repack_options
+    }
+    args += [ rebase_path(invoker.output, root_build_dir) ]
+    args += rebase_path(invoker.sources, root_build_dir)
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+}
diff --git a/build/secondary/tools/grit/stamp_grit_sources.py b/build/secondary/tools/grit/stamp_grit_sources.py
new file mode 100644
index 0000000..d43d4b8
--- /dev/null
+++ b/build/secondary/tools/grit/stamp_grit_sources.py
@@ -0,0 +1,55 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script enumerates the files in the given directory, writing an empty
+# stamp file and a .d file listing the inputs required to make the stamp. This
+# allows us to dynamically depend on the grit sources without enumerating the
+# grit directory for every invocation of grit (which is what adding the source
+# files to every .grd file's .d file would entail) or shelling out to grit
+# synchronously during GN execution to get the list (which would be slow).
+#
+# Usage:
+#    stamp_grit_sources.py <directory> <stamp-file> <.d-file>
+
+import os
+import sys
+
+def GritSourceFiles(grit_root_dir):
+  files = []
+  for root, _, filenames in os.walk(grit_root_dir):
+    grit_src = [os.path.join(root, f) for f in filenames
+                if f.endswith('.py') and not f.endswith('_unittest.py')]
+    files.extend(grit_src)
+  files = [f.replace('\\', '/') for f in files]
+  return sorted(files)
+
+
+def WriteDepFile(dep_file, stamp_file, source_files):
+  with open(dep_file, "w") as f:
+    f.write(stamp_file)
+    f.write(": ")
+    f.write(' '.join(source_files))
+
+
+def WriteStampFile(stamp_file):
+  with open(stamp_file, "w"):
+    pass
+
+
+def main(argv):
+  if len(argv) != 4:
+    print "Error: expecting 3 args."
+    return 1
+
+  grit_root_dir = sys.argv[1]
+  stamp_file = sys.argv[2]
+  dep_file = sys.argv[3]
+
+  WriteStampFile(stamp_file)
+  WriteDepFile(dep_file, stamp_file, GritSourceFiles(grit_root_dir))
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/set_clang_warning_flags.gypi b/build/set_clang_warning_flags.gypi
new file mode 100644
index 0000000..f6d7aea
--- /dev/null
+++ b/build/set_clang_warning_flags.gypi
@@ -0,0 +1,58 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included to set clang-specific compiler flags.
+# To use this the following variable can be defined:
+#   clang_warning_flags:       list: Compiler flags to pass to clang.
+#   clang_warning_flags_unset: list: Compiler flags to not pass to clang.
+#
+# Only use this in third-party code. In chromium_code, fix your code to not
+# warn instead!
+#
+# Note that the gypi file is included in target_defaults, so it does not need
+# to be explicitly included.
+#
+# Warning flags set by this will be used on all platforms. If you want to set
+# warning flags on only some platforms, you have to do so manually.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_target',
+#   'variables': {
+#     'clang_warning_flags': ['-Wno-awesome-warning'],
+#     'clang_warning_flags_unset': ['-Wpreviously-set-flag'],
+#   }
+# }
+
+{
+  'variables': {
+    'clang_warning_flags_unset%': [],  # Provide a default value.
+  },
+  'conditions': [
+    ['clang==1', {
+      # This uses >@ instead of @< to also see clang_warning_flags set in
+      # targets directly, not just the clang_warning_flags in target_defaults.
+      'cflags': [ '>@(clang_warning_flags)' ],
+      'cflags!': [ '>@(clang_warning_flags_unset)' ],
+      'xcode_settings': {
+        'WARNING_CFLAGS': ['>@(clang_warning_flags)'],
+        'WARNING_CFLAGS!': ['>@(clang_warning_flags_unset)'],
+      },
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'AdditionalOptions': [ '>@(clang_warning_flags)' ],
+          'AdditionalOptions!': [ '>@(clang_warning_flags_unset)' ],
+        },
+      },
+    }],
+    ['clang==0 and host_clang==1', {
+      'target_conditions': [
+        ['_toolset=="host"', {
+          'cflags': [ '>@(clang_warning_flags)' ],
+          'cflags!': [ '>@(clang_warning_flags_unset)' ],
+        }],
+      ],
+    }],
+  ],
+}
diff --git a/build/shim_headers.gypi b/build/shim_headers.gypi
new file mode 100644
index 0000000..56d8d3a
--- /dev/null
+++ b/build/shim_headers.gypi
@@ -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.
+
+# This file is meant to be included into a target to handle shim headers
+# in a consistent manner. To use this the following variables need to be
+# defined:
+#   headers_root_path: string: path to directory containing headers
+#   header_filenames: list: list of header file names
+
+{
+  'variables': {
+    'shim_headers_path': '<(SHARED_INTERMEDIATE_DIR)/shim_headers/<(_target_name)/<(_toolset)',
+    'shim_generator_additional_args%': [],
+  },
+  'include_dirs++': [
+    '<(shim_headers_path)',
+  ],
+  'all_dependent_settings': {
+    # Repeating this with different numbers of plusses is unfortunately required
+    # to make sure that even if this include is inside nested conditions/etc, it
+    # still gets inserted at the beginning of the include_dirs list. See
+    # http://crbug.com/263818 for details.
+    'include_dirs+++': [
+      '<(shim_headers_path)',
+    ],
+    'include_dirs++++': [
+      '<(shim_headers_path)',
+    ],
+    'include_dirs+++++': [
+      '<(shim_headers_path)',
+    ],
+  },
+  'actions': [
+    {
+      'variables': {
+        'generator_path': '<(DEPTH)/tools/generate_shim_headers/generate_shim_headers.py',
+        'generator_args': [
+          '--headers-root', '<(headers_root_path)',
+          '--output-directory', '<(shim_headers_path)',
+          '<@(shim_generator_additional_args)',
+          '<@(header_filenames)',
+        ],
+      },
+      'action_name': 'generate_<(_target_name)_shim_headers',
+      'inputs': [
+        '<(generator_path)',
+      ],
+      'outputs': [
+        '<!@pymod_do_main(generate_shim_headers <@(generator_args) --outputs)',
+      ],
+      'action': ['python',
+                 '<(generator_path)',
+                 '<@(generator_args)',
+                 '--generate',
+      ],
+      'message': 'Generating <(_target_name) shim headers',
+    },
+  ],
+}
diff --git a/build/slave/OWNERS b/build/slave/OWNERS
new file mode 100644
index 0000000..f562c92
--- /dev/null
+++ b/build/slave/OWNERS
@@ -0,0 +1,20 @@
+set noparent
+agable@chromium.org
+agable@google.com
+cmp@chromium.org
+cmp@google.com
+dpranke@chromium.org
+iannucci@chromium.org
+iannucci@google.com
+johnw@chromium.org
+johnw@google.com
+maruel@chromium.org
+maruel@google.com
+mmoss@chromium.org
+mmoss@google.com
+pschmidt@chromium.org
+pschmidt@google.com
+stip@chromium.org
+stip@google.com
+szager@chromium.org
+szager@google.com
diff --git a/build/slave/README b/build/slave/README
new file mode 100644
index 0000000..e3718b2
--- /dev/null
+++ b/build/slave/README
@@ -0,0 +1,8 @@
+This is a directory which contains configuration information for the
+buildsystem.
+
+* Under recipes, the buildsystem should use only this directory as an
+  entry point into src/.
+
+* Scripts in this directory must not import from outside this directory or shell
+  to scripts outside this directory.
diff --git a/build/some.gyp b/build/some.gyp
new file mode 100644
index 0000000..44a1dd5
--- /dev/null
+++ b/build/some.gyp
@@ -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.
+{
+  'targets': [
+    {
+      'target_name': 'some',
+      'type': 'none',
+      'dependencies': [
+        # This file is intended to be locally modified. List the targets you use
+        # regularly. The generated some.sln will contains projects for only
+        # those targets and the targets they are transitively dependent on. This
+        # can result in a solution that loads and unloads faster in Visual
+        # Studio.
+        #
+        # Tip: Create a dummy CL to hold your local edits to this file, so they
+        # don't accidentally get added to another CL that you are editing.
+        #
+        # Example:
+        # '../chrome/chrome.gyp:chrome',
+      ],
+    },
+  ],
+}
diff --git a/build/symlink.py b/build/symlink.py
new file mode 100755
index 0000000..aade2f8
--- /dev/null
+++ b/build/symlink.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# 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.
+
+"""Make a symlink and optionally touch a file (to handle dependencies)."""
+
+
+import errno
+import optparse
+import os.path
+import sys
+
+
+def Main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('-f', '--force', action='store_true')
+  parser.add_option('--touch')
+
+  options, args = parser.parse_args(argv[1:])
+  if len(args) < 2:
+    parser.error('at least two arguments required.')
+
+  target = args[-1]
+  sources = args[:-1]
+  for s in sources:
+    t = os.path.join(target, os.path.basename(s))
+    try:
+      os.symlink(s, t)
+    except OSError, e:
+      if e.errno == errno.EEXIST and options.force:
+        os.remove(t)
+        os.symlink(s, t)
+      else:
+        raise
+
+
+  if options.touch:
+    with open(options.touch, 'w') as f:
+      pass
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv))
diff --git a/build/temp_gyp/README.chromium b/build/temp_gyp/README.chromium
new file mode 100644
index 0000000..8045d61
--- /dev/null
+++ b/build/temp_gyp/README.chromium
@@ -0,0 +1,3 @@
+This directory will be removed once the files in it are committed upstream and
+Chromium imports an upstream revision with these files.  Contact mark for
+details.
diff --git a/build/temp_gyp/pdfsqueeze.gyp b/build/temp_gyp/pdfsqueeze.gyp
new file mode 100644
index 0000000..2b3b1ff
--- /dev/null
+++ b/build/temp_gyp/pdfsqueeze.gyp
@@ -0,0 +1,40 @@
+# 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'pdfsqueeze',
+      'type': 'executable',
+      'sources': [
+        '../../third_party/pdfsqueeze/pdfsqueeze.m',
+      ],
+      'defines': [
+        # Use defines to map the full path names that will be used for
+        # the vars into the short forms expected by pdfsqueeze.m.
+        '______third_party_pdfsqueeze_ApplyGenericRGB_qfilter=ApplyGenericRGB_qfilter',
+        '______third_party_pdfsqueeze_ApplyGenericRGB_qfilter_len=ApplyGenericRGB_qfilter_len',
+      ],
+      'include_dirs': [
+        '<(INTERMEDIATE_DIR)',
+      ],
+      'libraries': [
+        '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        '$(SDKROOT)/System/Library/Frameworks/Quartz.framework',
+      ],
+      'actions': [
+        {
+          'action_name': 'Generate inline filter data',
+          'inputs': [
+            '../../third_party/pdfsqueeze/ApplyGenericRGB.qfilter',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/ApplyGenericRGB.h',
+          ],
+          'action': ['xxd', '-i', '<@(_inputs)', '<@(_outputs)'],
+        },
+      ],
+    },
+  ],
+}
diff --git a/build/toolchain/OWNERS b/build/toolchain/OWNERS
new file mode 100644
index 0000000..c6cda3f
--- /dev/null
+++ b/build/toolchain/OWNERS
@@ -0,0 +1,3 @@
+brettw@chromium.org
+dpranke@chromium.org
+scottmg@chromium.org
diff --git a/build/toolchain/android/BUILD.gn b/build/toolchain/android/BUILD.gn
new file mode 100644
index 0000000..53ad506
--- /dev/null
+++ b/build/toolchain/android/BUILD.gn
@@ -0,0 +1,129 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")  # Imports android/config.gni.
+import("//build/toolchain/ccache.gni")
+import("//build/toolchain/clang.gni")
+import("//build/toolchain/goma.gni")
+import("//build/toolchain/gcc_toolchain.gni")
+
+# The Android GCC toolchains share most of the same parameters, so we have this
+# wrapper around gcc_toolchain to avoid duplication of logic.
+#
+# Parameters:
+#  - android_ndk_sysroot
+#      Sysroot for this architecture.
+#  - android_ndk_lib_dir
+#      Subdirectory inside of android_ndk_sysroot where libs go.
+#  - tool_prefix
+#      Prefix to be added to the tool names.
+#  - toolchain_cpu
+#      Same as gcc_toolchain
+template("android_gcc_toolchain") {
+  gcc_toolchain(target_name) {
+    # Make our manually injected libs relative to the build dir.
+    android_ndk_lib = rebase_path(
+            invoker.android_ndk_sysroot + "/" + invoker.android_ndk_lib_dir,
+            root_build_dir)
+
+    libs_section_prefix = "$android_ndk_lib/crtbegin_dynamic.o"
+    libs_section_postfix = "$android_ndk_lib/crtend_android.o"
+
+    solink_libs_section_prefix = "$android_ndk_lib/crtbegin_so.o"
+    solink_libs_section_postfix = "$android_ndk_lib/crtend_so.o"
+
+    # The tools should be run relative to the build dir.
+    tool_prefix = rebase_path(invoker.tool_prefix, root_build_dir)
+
+    if (use_goma) {
+      assert(!use_ccache, "Goma and ccache can't be used together.")
+      compiler_prefix = "$goma_dir/gomacc "
+    } else if (use_ccache) {
+      compiler_prefix = "ccache "
+    } else {
+      compiler_prefix = ""
+    }
+
+    cc = compiler_prefix + tool_prefix + "gcc"
+    cxx = compiler_prefix + tool_prefix + "g++"
+    ar = tool_prefix + "ar"
+    ld = cxx
+
+    toolchain_os = "android"
+    toolchain_cpu = invoker.toolchain_cpu
+
+    # We make the assumption that the gcc_toolchain will produce a soname with
+    # the following definition.
+    soname = "{{target_output_name}}{{output_extension}}"
+
+    stripped_soname = "lib.stripped/${soname}"
+    temp_stripped_soname = "${stripped_soname}.tmp"
+
+    android_strip = "${tool_prefix}strip"
+
+    mkdir_command = "mkdir -p lib.stripped"
+    strip_command =
+        "$android_strip --strip-unneeded -o $temp_stripped_soname $soname"
+    replace_command = "if ! cmp -s $temp_stripped_soname $stripped_soname; then mv $temp_stripped_soname $stripped_soname; fi"
+    postsolink = "$mkdir_command && $strip_command && $replace_command"
+    solink_outputs = [ stripped_soname ]
+
+    # We make the assumption that the gcc_toolchain will produce an exe with
+    # the following definition.
+    exe = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
+    stripped_exe = "exe.stripped/$exe"
+    mkdir_command = "mkdir -p exe.stripped"
+    strip_command = "$android_strip --strip-unneeded -o $stripped_exe $exe"
+    postlink = "$mkdir_command && $strip_command"
+    link_outputs = [ stripped_exe ]
+  }
+}
+
+android_gcc_toolchain("x86") {
+  android_ndk_sysroot = "$android_ndk_root/$x86_android_sysroot_subdir"
+  android_ndk_lib_dir = "usr/lib"
+
+  tool_prefix = "$x86_android_toolchain_root/bin/i686-linux-android-"
+  toolchain_cpu = "x86"
+}
+
+android_gcc_toolchain("arm") {
+  android_ndk_sysroot = "$android_ndk_root/$arm_android_sysroot_subdir"
+  android_ndk_lib_dir = "usr/lib"
+
+  tool_prefix = "$arm_android_toolchain_root/bin/arm-linux-androideabi-"
+  toolchain_cpu = "arm"
+}
+
+android_gcc_toolchain("mipsel") {
+  android_ndk_sysroot = "$android_ndk_root/$mips_android_sysroot_subdir"
+  android_ndk_lib_dir = "usr/lib"
+
+  tool_prefix = "$mips_android_toolchain_root/bin/mipsel-linux-android-"
+  toolchain_cpu = "mipsel"
+}
+
+android_gcc_toolchain("x64") {
+  android_ndk_sysroot = "$android_ndk_root/$x86_64_android_sysroot_subdir"
+  android_ndk_lib_dir = "usr/lib64"
+
+  tool_prefix = "$x86_64_android_toolchain_root/bin/x86_64-linux-android-"
+  toolchain_cpu = "x86_64"
+}
+
+android_gcc_toolchain("arm64") {
+  android_ndk_sysroot = "$android_ndk_root/$arm64_android_sysroot_subdir"
+  android_ndk_lib_dir = "usr/lib"
+
+  tool_prefix = "$arm64_android_toolchain_root/bin/arm-linux-androideabi-"
+  toolchain_cpu = "aarch64"
+}
+
+android_gcc_toolchain("mips64el") {
+  android_ndk_sysroot = "$android_ndk_root/$mips64_android_sysroot_subdir"
+  android_ndk_lib_dir = "usr/lib64"
+
+  tool_prefix = "$mips64_android_toolchain_root/bin/mipsel-linux-android-"
+  toolchain_cpu = "mipsel64el"
+}
diff --git a/build/toolchain/ccache.gni b/build/toolchain/ccache.gni
new file mode 100644
index 0000000..806e079
--- /dev/null
+++ b/build/toolchain/ccache.gni
@@ -0,0 +1,25 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Defines the configuration of ccache - a c/c++ compiler cache which can
+# greatly reduce recompilation times.
+#
+# TIPS:
+#
+# Set clang_use_chrome_plugins=false if using ccache 3.1.9 or earlier, since
+# these versions don't support -Xclang.  (3.1.10 and later will silently
+# ignore -Xclang, so it doesn't matter if you disable clang_use_chrome_plugins
+# or not).
+#
+# Use ccache 3.2 or later to avoid clang unused argument warnings:
+# https://bugzilla.samba.org/show_bug.cgi?id=8118
+#
+# To avoid -Wparentheses-equality clang warnings, at some cost in terms of
+# speed, you can do:
+# export CCACHE_CPP2=yes
+
+declare_args() {
+  # Set to true to enable ccache.  Probably doesn't work on windows.
+  use_ccache = false
+}
diff --git a/build/toolchain/clang.gni b/build/toolchain/clang.gni
new file mode 100644
index 0000000..c680384
--- /dev/null
+++ b/build/toolchain/clang.gni
@@ -0,0 +1,9 @@
+# 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.
+
+declare_args() {
+  # Enable the optional type profiler in Clang, which will tag heap allocations
+  # with the allocation type.
+  use_clang_type_profiler = false
+}
diff --git a/build/toolchain/cros/BUILD.gn b/build/toolchain/cros/BUILD.gn
new file mode 100644
index 0000000..140958b
--- /dev/null
+++ b/build/toolchain/cros/BUILD.gn
@@ -0,0 +1,35 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/toolchain/clang.gni")
+import("//build/toolchain/gcc_toolchain.gni")
+
+declare_args() {
+  # The CrOS build system supports many different kinds of targets across
+  # many different architectures. Bringing your own toolchain is also supported,
+  # so it's actually impossible to enumerate all toolchains for all targets
+  # as GN toolchain specifications.
+  # These arguments provide a mechanism for specifying your CC, CXX and AR at
+  # buildfile-generation time, allowing the CrOS build system to always use
+  # the right tools for the current target.
+  cros_target_cc = ""
+  cros_target_cxx = ""
+  cros_target_ar = ""
+}
+
+gcc_toolchain("target") {
+  assert(cros_target_cc != "", "Must provide target CC.")
+  assert(cros_target_cxx != "", "Must provide target CXX.")
+  assert(cros_target_ar != "", "Must provide target AR.")
+
+  cc = "${cros_target_cc}"
+  cxx = "${cros_target_cxx}"
+
+  ar = "${cros_target_ar}"
+  ld = cxx
+
+  toolchain_cpu = "${target_cpu}"
+  toolchain_os = "linux"
+  is_clang = is_clang
+}
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
new file mode 100644
index 0000000..0192faa
--- /dev/null
+++ b/build/toolchain/gcc_toolchain.gni
@@ -0,0 +1,223 @@
+# 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 value will be inherited in the toolchain below.
+concurrent_links = exec_script("get_concurrent_links.py", [], "value")
+
+# This template defines a toolchain for something that works like gcc
+# (including clang).
+#
+# It requires the following variables specifying the executables to run:
+#  - cc
+#  - cxx
+#  - ar
+#  - ld
+# and the following which is used in the toolchain_args
+#  - toolchain_cpu  (What "current_cpu" should be set to when invoking a
+#                    build using this toolchain.)
+#  - toolchain_os  (What "current_os" should be set to when invoking a
+#                   build using this toolchain.)
+#
+# Optional parameters:
+#  - libs_section_prefix
+#  - libs_section_postfix
+#      The contents of these strings, if specified, will be placed around
+#      the libs section of the linker line. It allows one to inject libraries
+#      at the beginning and end for all targets in a toolchain.
+#  - solink_libs_section_prefix
+#  - solink_libs_section_postfix
+#      Same as libs_section_{pre,post}fix except used for solink instead of link.
+#  - post_solink
+#      The content of this string, if specified, will be appended to the solink
+#      command.
+#  - deps
+#      Just forwarded to the toolchain definition.
+#  - is_clang
+template("gcc_toolchain") {
+  toolchain(target_name) {
+    assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value")
+    assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value")
+    assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
+    assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value")
+    assert(defined(invoker.toolchain_cpu),
+           "gcc_toolchain() must specify a \"toolchain_cpu\"")
+    assert(defined(invoker.toolchain_os),
+           "gcc_toolchain() must specify a \"toolchain_os\"")
+
+    # We can't do string interpolation ($ in strings) on things with dots in
+    # them. To allow us to use $cc below, for example, we create copies of
+    # these values in our scope.
+    cc = invoker.cc
+    cxx = invoker.cxx
+    ar = invoker.ar
+    ld = invoker.ld
+
+    # Bring these into our scope for string interpolation with default values.
+    if (defined(invoker.libs_section_prefix)) {
+      libs_section_prefix = invoker.libs_section_prefix
+    } else {
+      libs_section_prefix = ""
+    }
+
+    if (defined(invoker.libs_section_postfix)) {
+      libs_section_postfix = invoker.libs_section_postfix
+    } else {
+      libs_section_postfix = ""
+    }
+
+    if (defined(invoker.solink_libs_section_prefix)) {
+      solink_libs_section_prefix = invoker.solink_libs_section_prefix
+    } else {
+      solink_libs_section_prefix = ""
+    }
+
+    if (defined(invoker.solink_libs_section_postfix)) {
+      solink_libs_section_postfix = invoker.solink_libs_section_postfix
+    } else {
+      solink_libs_section_postfix = ""
+    }
+
+    # These library switches can apply to all tools below.
+    lib_switch = "-l"
+    lib_dir_switch = "-L"
+
+    tool("cc") {
+      depfile = "{{output}}.d"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CC {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("cxx") {
+      depfile = "{{output}}.d"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CXX {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("asm") {
+      # For GCC we can just use the C compiler to compile assembly.
+      depfile = "{{output}}.d"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "ASM {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("alink") {
+      rspfile = "{{output}}.rsp"
+      command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile"
+      description = "AR {{output}}"
+      rspfile_content = "{{inputs}}"
+      outputs = [
+        "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+      ]
+      default_output_extension = ".a"
+      output_prefix = "lib"
+    }
+
+    tool("solink") {
+      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
+      sofile = "{{root_out_dir}}/$soname"  # Possibly including toolchain dir.
+      rspfile = sofile + ".rsp"
+
+      # These variables are not built into GN but are helpers that implement
+      # (1) linking to produce a .so, (2) extracting the symbols from that file
+      # to a temporary file, (3) if the temporary file has differences from the
+      # existing .TOC file, overwrite it, otherwise, don't change it.
+      tocfile = sofile + ".TOC"
+      temporary_tocname = sofile + ".tmp"
+      link_command =
+          "$ld -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile"
+      toc_command = "{ readelf -d $sofile | grep SONAME ; nm -gD -f p $sofile | cut -f1-2 -d' '; } > $temporary_tocname"
+      replace_command = "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi"
+
+      command = "$link_command && $toc_command && $replace_command"
+      if (defined(invoker.postsolink)) {
+        command += " && " + invoker.postsolink
+      }
+      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
+
+      description = "SOLINK $sofile"
+
+      # Use this for {{output_extension}} expansions unless a target manually
+      # overrides it (in which case {{output_extension}} will be what the target
+      # specifies).
+      default_output_extension = ".so"
+
+      output_prefix = "lib"
+
+      # Since the above commands only updates the .TOC file when it changes, ask
+      # Ninja to check if the timestamp actually changed to know if downstream
+      # dependencies should be recompiled.
+      restat = true
+
+      # Tell GN about the output files. It will link to the sofile but use the
+      # tocfile for dependency management.
+      outputs = [
+        sofile,
+        tocfile,
+      ]
+      if (defined(invoker.solink_outputs)) {
+        outputs += invoker.solink_outputs
+      }
+      link_output = sofile
+      depend_output = tocfile
+    }
+
+    tool("link") {
+      outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = "$outfile.rsp"
+      command = "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix"
+      if (defined(invoker.postlink)) {
+        command += " && " + invoker.postlink
+      }
+      description = "LINK $outfile"
+      rspfile_content = "{{inputs}}"
+      outputs = [
+        outfile,
+      ]
+      if (defined(invoker.link_outputs)) {
+        outputs += invoker.link_outputs
+      }
+    }
+
+    tool("stamp") {
+      command = "touch {{output}}"
+      description = "STAMP {{output}}"
+    }
+
+    tool("copy") {
+      command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
+      description = "COPY {{source}} {{output}}"
+    }
+
+    # When invoking this toolchain not as the default one, these args will be
+    # passed to the build. They are ignored when this is the default toolchain.
+    toolchain_args() {
+      current_cpu = invoker.toolchain_cpu
+      current_os = invoker.toolchain_os
+
+      # These values need to be passed through unchanged.
+      target_os = target_os
+      target_cpu = target_cpu
+
+      if (defined(invoker.is_clang)) {
+        is_clang = invoker.is_clang
+      }
+    }
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+}
diff --git a/build/toolchain/get_concurrent_links.py b/build/toolchain/get_concurrent_links.py
new file mode 100644
index 0000000..6a40101
--- /dev/null
+++ b/build/toolchain/get_concurrent_links.py
@@ -0,0 +1,64 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script computs the number of concurrent links we want to run in the build
+# as a function of machine spec. It's based on GetDefaultConcurrentLinks in GYP.
+
+import os
+import re
+import subprocess
+import sys
+
+def GetDefaultConcurrentLinks():
+  # Inherit the legacy environment variable for people that have set it in GYP.
+  pool_size = int(os.getenv('GYP_LINK_CONCURRENCY', 0))
+  if pool_size:
+    return pool_size
+
+  if sys.platform in ('win32', 'cygwin'):
+    import ctypes
+
+    class MEMORYSTATUSEX(ctypes.Structure):
+      _fields_ = [
+        ("dwLength", ctypes.c_ulong),
+        ("dwMemoryLoad", ctypes.c_ulong),
+        ("ullTotalPhys", ctypes.c_ulonglong),
+        ("ullAvailPhys", ctypes.c_ulonglong),
+        ("ullTotalPageFile", ctypes.c_ulonglong),
+        ("ullAvailPageFile", ctypes.c_ulonglong),
+        ("ullTotalVirtual", ctypes.c_ulonglong),
+        ("ullAvailVirtual", ctypes.c_ulonglong),
+        ("sullAvailExtendedVirtual", ctypes.c_ulonglong),
+      ]
+
+    stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX))
+    ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
+
+    mem_limit = max(1, stat.ullTotalPhys / (4 * (2 ** 30)))  # total / 4GB
+    hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32)))
+    return min(mem_limit, hard_cap)
+  elif sys.platform.startswith('linux'):
+    if os.path.exists("/proc/meminfo"):
+      with open("/proc/meminfo") as meminfo:
+        memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB')
+        for line in meminfo:
+          match = memtotal_re.match(line)
+          if not match:
+            continue
+          # Allow 8Gb per link on Linux because Gold is quite memory hungry
+          return max(1, int(match.group(1)) / (8 * (2 ** 20)))
+    return 1
+  elif sys.platform == 'darwin':
+    try:
+      avail_bytes = int(subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
+      # A static library debug build of Chromium's unit_tests takes ~2.7GB, so
+      # 4GB per ld process allows for some more bloat.
+      return max(1, avail_bytes / (4 * (2 ** 30)))  # total / 4GB
+    except Exception:
+      return 1
+  else:
+    # TODO(scottmg): Implement this for other platforms.
+    return 1
+
+print GetDefaultConcurrentLinks()
diff --git a/build/toolchain/goma.gni b/build/toolchain/goma.gni
new file mode 100644
index 0000000..c0f4cf2
--- /dev/null
+++ b/build/toolchain/goma.gni
@@ -0,0 +1,22 @@
+# 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.
+
+# Defines the configuration of Goma.
+#
+# This is currently designed to match the GYP build exactly, so as not to break
+# people during the transition.
+
+declare_args() {
+  # Set to true to enable distributed compilation using Goma.
+  use_goma = false
+
+  # Set the default value based on the platform.
+  if (is_win) {
+    # Absolute directory containing the Goma source code.
+    goma_dir = "C:\goma\goma-win"
+  } else {
+    # Absolute directory containing the Goma source code.
+    goma_dir = getenv("HOME") + "/goma"
+  }
+}
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn
new file mode 100644
index 0000000..7bcd9d0
--- /dev/null
+++ b/build/toolchain/linux/BUILD.gn
@@ -0,0 +1,103 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+import("//build/toolchain/ccache.gni")
+import("//build/toolchain/clang.gni")
+import("//build/toolchain/gcc_toolchain.gni")
+import("//build/toolchain/goma.gni")
+
+if (use_goma) {
+  assert(!use_ccache, "Goma and ccache can't be used together.")
+  compiler_prefix = "$goma_dir/gomacc "
+} else if (use_ccache) {
+  compiler_prefix = "ccache "
+} else {
+  compiler_prefix = ""
+}
+
+gcc_toolchain("arm") {
+  cc = "${compiler_prefix}arm-linux-gnueabi-gcc"
+  cxx = "${compiler_prefix}arm-linux-gnueabi-g++"
+
+  ar = "arm-linux-gnueabi-ar"
+  ld = cxx
+
+  toolchain_cpu = "arm"
+  toolchain_os = "linux"
+  is_clang = false
+}
+
+gcc_toolchain("clang_x86") {
+  if (use_clang_type_profiler) {
+    prefix = rebase_path("//third_party/llvm-allocated-type/Linux_ia32/bin",
+                         root_build_dir)
+  } else {
+    prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                         root_build_dir)
+  }
+  cc = "${compiler_prefix}$prefix/clang"
+  cxx = "${compiler_prefix}$prefix/clang++"
+
+  ar = "ar"
+  ld = cxx
+
+  toolchain_cpu = "x86"
+  toolchain_os = "linux"
+  is_clang = true
+}
+
+gcc_toolchain("x86") {
+  cc = "${compiler_prefix}gcc"
+  cxx = "$compiler_prefix}g++"
+
+  ar = "ar"
+  ld = cxx
+
+  toolchain_cpu = "x86"
+  toolchain_os = "linux"
+  is_clang = false
+}
+
+gcc_toolchain("clang_x64") {
+  if (use_clang_type_profiler) {
+    prefix = rebase_path("//third_party/llvm-allocated-type/Linux_x64/bin",
+                         root_build_dir)
+  } else {
+    prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                         root_build_dir)
+  }
+  cc = "${compiler_prefix}$prefix/clang"
+  cxx = "${compiler_prefix}$prefix/clang++"
+
+  ar = "ar"
+  ld = cxx
+
+  toolchain_cpu = "x64"
+  toolchain_os = "linux"
+  is_clang = true
+}
+
+gcc_toolchain("x64") {
+  cc = "${compiler_prefix}gcc"
+  cxx = "${compiler_prefix}g++"
+
+  ar = "ar"
+  ld = cxx
+
+  toolchain_cpu = "x64"
+  toolchain_os = "linux"
+  is_clang = false
+}
+
+gcc_toolchain("mipsel") {
+  cc = "mipsel-linux-gnu-gcc"
+  cxx = "mipsel-linux-gnu-g++"
+  ar = "mipsel-linux-gnu-ar"
+  ld = cxx
+
+  toolchain_cpu = "mipsel"
+  toolchain_os = "linux"
+  is_clang = false
+}
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
new file mode 100644
index 0000000..a4b8651
--- /dev/null
+++ b/build/toolchain/mac/BUILD.gn
@@ -0,0 +1,211 @@
+# 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.
+
+# TODO(brettw) Use "gcc_toolchain.gni" like the Linux toolchains. This requires
+# some enhancements since the commands on Mac are slightly different than on
+# Linux.
+
+import("../goma.gni")
+
+# Should only be running on Mac.
+assert(is_mac || is_ios)
+
+import("//build/toolchain/clang.gni")
+import("//build/toolchain/goma.gni")
+
+if (use_goma) {
+  goma_prefix = "$goma_dir/gomacc "
+} else {
+  goma_prefix = ""
+}
+
+if (is_clang) {
+  cc = rebase_path("//third_party/llvm-build/Release+Asserts/bin/clang",
+                   root_build_dir)
+  cxx = rebase_path("//third_party/llvm-build/Release+Asserts/bin/clang++",
+                    root_build_dir)
+} else {
+  cc = "gcc"
+  cxx = "g++"
+}
+cc = goma_prefix + cc
+cxx = goma_prefix + cxx
+ld = cxx
+
+# This will copy the gyp-mac-tool to the build directory. We pass in the source
+# file of the win tool.
+gyp_mac_tool_source =
+    rebase_path("//tools/gyp/pylib/gyp/mac_tool.py", root_build_dir)
+exec_script("setup_toolchain.py", [ gyp_mac_tool_source ])
+
+# Shared toolchain definition. Invocations should set toolchain_os to set the
+# build args in this definition.
+template("mac_clang_toolchain") {
+  toolchain(target_name) {
+    assert(defined(invoker.cc),
+           "mac_clang_toolchain() must specify a \"cc\" value")
+    assert(defined(invoker.cxx),
+           "mac_clang_toolchain() must specify a \"cxx\" value")
+    assert(defined(invoker.ld),
+           "mac_clang_toolchain() must specify a \"ld\" value")
+    assert(defined(invoker.toolchain_os),
+           "mac_clang_toolchain() must specify a \"toolchain_os\"")
+
+    # We can't do string interpolation ($ in strings) on things with dots in
+    # them. To allow us to use $cc below, for example, we create copies of
+    # these values in our scope.
+    cc = invoker.cc
+    cxx = invoker.cxx
+    ld = invoker.ld
+
+    # Make these apply to all tools below.
+    lib_switch = "-l"
+    lib_dir_switch = "-L"
+
+    tool("cc") {
+      depfile = "{{output}}.d"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CC {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("cxx") {
+      depfile = "{{output}}.d"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "CXX {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("asm") {
+      # For GCC we can just use the C compiler to compile assembly.
+      depfile = "{{output}}.d"
+      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "ASM {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("objc") {
+      depfile = "{{output}}.d"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} {{cflags_objc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "OBJC {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("objcxx") {
+      depfile = "{{output}}.d"
+      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objcc}} -c {{source}} -o {{output}}"
+      depsformat = "gcc"
+      description = "OBJCXX {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+      ]
+    }
+
+    tool("alink") {
+      command = "rm -f {{output}} && ./gyp-mac-tool filter-libtool libtool -static -o {{output}} {{inputs}}"
+      description = "LIBTOOL-STATIC {{output}}"
+      outputs = [
+        "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+      ]
+      default_output_extension = ".a"
+      output_prefix = "lib"
+    }
+
+    tool("solink") {
+      dylib = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"  # eg "./libfoo.dylib"
+      rspfile = dylib + ".rsp"
+
+      # These variables are not build into GN but are helpers that implement
+      # (1) linking to produce a .so, (2) extracting the symbols from that file
+      # to a temporary file, (3) if the temporary file has differences from the
+      # existing .TOC file, overwrite it, oterwise, don't change it.
+      #
+      # As a special case, if the library reexports symbols from other dynamic
+      # libraries, we always update the .TOC and skip the temporary file and
+      # diffing steps, since that library always needs to be re-linked.
+      tocname = dylib + ".TOC"
+      temporary_tocname = dylib + ".tmp"
+
+      does_reexport_command = "[ ! -e $dylib -o ! -e $tocname ] || otool -l $dylib | grep -q LC_REEXPORT_DYLIB"
+      link_command = "$ld -shared {{ldflags}} -o $dylib -Wl,-filelist,$rspfile {{solibs}} {{libs}}"
+      replace_command = "if ! cmp -s $temporary_tocname $tocname; then mv $temporary_tocname $tocname"
+      extract_toc_command = "{ otool -l $dylib | grep LC_ID_DYLIB -A 5; nm -gP $dylib | cut -f1-2 -d' ' | grep -v U\$\$; true; }"
+
+      command = "if $does_reexport_command ; then $link_command && $extract_toc_command > $tocname; else $link_command && $extract_toc_command > $temporary_tocname && $replace_command ; fi; fi"
+
+      rspfile_content = "{{inputs_newline}}"
+
+      description = "SOLINK {{output}}"
+
+      # Use this for {{output_extension}} expansions unless a target manually
+      # overrides it (in which case {{output_extension}} will be what the target
+      # specifies).
+      default_output_extension = ".dylib"
+
+      output_prefix = "lib"
+
+      # Since the above commands only updates the .TOC file when it changes, ask
+      # Ninja to check if the timestamp actually changed to know if downstream
+      # dependencies should be recompiled.
+      restat = true
+
+      # Tell GN about the output files. It will link to the dylib but use the
+      # tocname for dependency management.
+      outputs = [
+        dylib,
+        tocname,
+      ]
+      link_output = dylib
+      depend_output = tocname
+    }
+
+    tool("link") {
+      outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
+      rspfile = "$outfile.rsp"
+      command = "$ld {{ldflags}} -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}}"
+      description = "LINK $outfile"
+      rspfile_content = "{{inputs_newline}}"
+      outputs = [
+        outfile,
+      ]
+    }
+
+    tool("stamp") {
+      command = "touch {{output}}"
+      description = "STAMP {{output}}"
+    }
+
+    tool("copy") {
+      command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
+      description = "COPY {{source}} {{output}}"
+    }
+
+    toolchain_args() {
+      current_os = invoker.toolchain_os
+    }
+  }
+}
+
+# Toolchain representing the target build (either mac or iOS).
+mac_clang_toolchain("clang") {
+  toolchain_os = current_os
+}
+
+# This toolchain provides a way for iOS target compiles to reference targets
+# compiled for the host system. It just overrides the OS back to "mac".
+mac_clang_toolchain("host_clang") {
+  toolchain_os = "mac"
+}
diff --git a/build/toolchain/mac/setup_toolchain.py b/build/toolchain/mac/setup_toolchain.py
new file mode 100644
index 0000000..431078f
--- /dev/null
+++ b/build/toolchain/mac/setup_toolchain.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import stat
+import sys
+
+def CopyTool(source_path):
+  """Copies the given tool to the current directory, including a warning not
+  to edit it."""
+  with open(source_path) as source_file:
+    tool_source = source_file.readlines()
+
+  # Add header and write it out to the current directory (which should be the
+  # root build dir).
+  out_path = 'gyp-mac-tool'
+  with open(out_path, 'w') as tool_file:
+    tool_file.write(''.join([tool_source[0],
+                             '# Generated by setup_toolchain.py do not edit.\n']
+                            + tool_source[1:]))
+  st = os.stat(out_path)
+  os.chmod(out_path, st.st_mode | stat.S_IEXEC)
+
+# Find the tool source, it's the first argument, and copy it.
+if len(sys.argv) != 2:
+  print "Need one argument (mac_tool source path)."
+  sys.exit(1)
+CopyTool(sys.argv[1])
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn
new file mode 100644
index 0000000..5fa637c
--- /dev/null
+++ b/build/toolchain/nacl/BUILD.gn
@@ -0,0 +1,63 @@
+# 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.
+
+toolchain("x86_newlib") {
+  toolprefix = "gen/sdk/toolchain/linux_x86_newlib/bin/x86_64-nacl-"
+  cc = toolprefix + "gcc"
+  cxx = toolprefix + "g++"
+  ld = toolprefix + "g++"
+
+  tool("cc") {
+    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c -c \$in -o \$out"
+    description = "CC(NaCl x86 Newlib) \$out"
+    depfile = "\$out.d"
+    depsformat = "gcc"
+  }
+  tool("cxx") {
+    # cflags_pch_cc
+    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc -c \$in -o \$out"
+    description = "CXX(NaCl x86 Newlib) \$out"
+    depfile = "\$out.d"
+    depsformat = "gcc"
+  }
+  tool("alink") {
+    command = "rm -f \$out && ${toolprefix}ar rcs \$out \$in"
+    description = "AR(NaCl x86 Newlib) \$out"
+  }
+  tool("solink") {
+    command = "if [ ! -e \$lib -o ! -e \${lib}.TOC ]; then $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi"
+    description = "SOLINK(NaCl x86 Newlib) \$lib"
+
+    #pool = "link_pool"
+    restat = "1"
+  }
+  tool("link") {
+    command = "$ld \$ldflags -o \$out -Wl,--start-group \$in \$solibs -Wl,--end-group \$libs"
+    description = "LINK(NaCl x86 Newlib) \$out"
+
+    #pool = "link_pool"
+  }
+
+  if (is_win) {
+    tool("stamp") {
+      command = "$python_path gyp-win-tool stamp \$out"
+      description = "STAMP \$out"
+    }
+  } else {
+    tool("stamp") {
+      command = "touch \$out"
+      description = "STAMP \$out"
+    }
+  }
+
+  toolchain_args() {
+    # Override the default OS detection. The build config will set the is_*
+    # flags accordingly.
+    current_os = "nacl"
+
+    # Component build not supported in NaCl, since it does not support shared
+    # libraries.
+    is_component_build = false
+  }
+}
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
new file mode 100644
index 0000000..05406c3
--- /dev/null
+++ b/build/toolchain/win/BUILD.gn
@@ -0,0 +1,226 @@
+# 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.
+
+declare_args() {
+  # Path to the directory containing the VC binaries for the right
+  # combination of host and target architectures. Currently only the
+  # 64-bit host toolchain is supported, with either 32-bit or 64-bit targets.
+  # If vc_bin_dir is not specified on the command line (and it normally
+  # isn't), we will dynamically determine the right value to use at runtime.
+  vc_bin_dir = ""
+}
+
+import("//build/config/win/visual_studio_version.gni")
+import("//build/toolchain/goma.gni")
+
+# Should only be running on Windows.
+assert(is_win)
+
+# Setup the Visual Studio state.
+#
+# Its arguments are the VS path and the compiler wrapper tool. It will write
+# "environment.x86" and "environment.x64" to the build directory and return a
+# list to us.
+gyp_win_tool_path =
+    rebase_path("//tools/gyp/pylib/gyp/win_tool.py", root_build_dir)
+
+toolchain_data = exec_script("setup_toolchain.py",
+                             [
+                               visual_studio_path,
+                               gyp_win_tool_path,
+                               windows_sdk_path,
+                               visual_studio_runtime_dirs,
+                               current_cpu,
+                             ],
+                             "scope")
+
+if (vc_bin_dir == "") {
+  vc_bin_dir = toolchain_data.vc_bin_dir
+}
+
+# This value will be inherited in the toolchain below.
+concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
+
+# Parameters:
+#  current_cpu: current_cpu to pass as a build arg
+#  environment: File name of environment file.
+template("msvc_toolchain") {
+  if (defined(invoker.concurrent_links)) {
+    concurrent_links = invoker.concurrent_links
+  }
+
+  env = invoker.environment
+
+  if (is_debug) {
+    configuration = "Debug"
+  } else {
+    configuration = "Release"
+  }
+  exec_script("../../vs_toolchain.py",
+              [
+                "copy_dlls",
+                rebase_path(root_build_dir),
+                configuration,
+                invoker.current_cpu,
+              ])
+
+  if (use_goma) {
+    goma_prefix = "$goma_dir/gomacc.exe "
+  } else {
+    goma_prefix = ""
+  }
+
+  cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\""
+
+  toolchain(target_name) {
+    # Make these apply to all tools below.
+    lib_switch = ""
+    lib_dir_switch = "/LIBPATH:"
+
+    tool("cc") {
+      rspfile = "{{output}}.rsp"
+      pdbname = "{{target_out_dir}}/{{target_output_name}}_c.pdb"
+      command = "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
+      depsformat = "msvc"
+      description = "CC {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+      ]
+      rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}"
+    }
+
+    tool("cxx") {
+      rspfile = "{{output}}.rsp"
+
+      # The PDB name needs to be different between C and C++ compiled files.
+      pdbname = "{{target_out_dir}}/{{target_output_name}}_cc.pdb"
+      command = "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
+      depsformat = "msvc"
+      description = "CXX {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+      ]
+      rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}"
+    }
+
+    tool("rc") {
+      command = "$python_path gyp-win-tool rc-wrapper $env rc.exe {{defines}} {{include_dirs}} /fo{{output}} {{source}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.res",
+      ]
+      description = "RC {{output}}"
+    }
+
+    tool("asm") {
+      # TODO(brettw): "/safeseh" assembler argument is hardcoded here. Extract
+      # assembler flags to a variable like cflags. crbug.com/418613
+      command = "$python_path gyp-win-tool asm-wrapper $env ml.exe {{defines}} {{include_dirs}} /safeseh /c /Fo {{output}} {{source}}"
+      description = "ASM {{output}}"
+      outputs = [
+        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+      ]
+    }
+
+    tool("alink") {
+      rspfile = "{{output}}.rsp"
+      command = "$python_path gyp-win-tool link-wrapper $env False lib.exe /nologo /ignore:4221 /OUT:{{output}} @$rspfile"
+      description = "LIB {{output}}"
+      outputs = [
+        # Ignore {{output_extension}} and always use .lib, there's no reason to
+        # allow targets to override this extension on Windows.
+        "{{target_out_dir}}/{{target_output_name}}.lib",
+      ]
+      default_output_extension = ".lib"
+
+      # The use of inputs_newline is to work around a fixed per-line buffer
+      # size in the linker.
+      rspfile_content = "{{inputs_newline}}"
+    }
+
+    tool("solink") {
+      dllname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"  # e.g. foo.dll
+      libname =
+          "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib"  # e.g. foo.dll.lib
+      rspfile = "${dllname}.rsp"
+
+      link_command = "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile"
+
+      # TODO(brettw) support manifests
+      #manifest_command = "$python_path gyp-win-tool manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:${dllname}.manifest"
+      #command = "cmd /c $link_command && $manifest_command"
+      command = link_command
+
+      default_output_extension = ".dll"
+      description = "LINK(DLL) {{output}}"
+      outputs = [
+        dllname,
+        libname,
+      ]
+      link_output = libname
+      depend_output = libname
+
+      # The use of inputs_newline is to work around a fixed per-line buffer
+      # size in the linker.
+      rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}}"
+    }
+
+    tool("link") {
+      rspfile = "{{output}}.rsp"
+
+      link_command = "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /OUT:{{output}} /PDB:{{output}}.pdb @$rspfile"
+
+      # TODO(brettw) support manifests
+      #manifest_command = "$python_path gyp-win-tool manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:{{output}}.manifest"
+      #command = "cmd /c $link_command && $manifest_command"
+      command = link_command
+
+      default_output_extension = ".exe"
+      description = "LINK {{output}}"
+      outputs = [
+        "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
+      ]
+
+      # The use of inputs_newline is to work around a fixed per-line buffer
+      # size in the linker.
+      rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
+    }
+
+    tool("stamp") {
+      command = "$python_path gyp-win-tool stamp {{output}}"
+      description = "STAMP {{output}}"
+    }
+
+    tool("copy") {
+      command =
+          "$python_path gyp-win-tool recursive-mirror {{source}} {{output}}"
+      description = "COPY {{source}} {{output}}"
+    }
+
+    # When invoking this toolchain not as the default one, these args will be
+    # passed to the build. They are ignored when this is the default toolchain.
+    toolchain_args() {
+      current_cpu = invoker.current_cpu
+    }
+  }
+}
+
+# TODO(dpranke): Declare both toolchains all of the time when we
+# get it sorted out how we want to support them both in a single build.
+# Right now only one of these can be enabled at a time because the
+# runtime libraries get copied to root_build_dir and would collide.
+if (current_cpu == "x86") {
+  msvc_toolchain("32") {
+    environment = "environment.x86"
+
+    current_cpu = "x86"
+  }
+}
+
+if (current_cpu == "x64") {
+  msvc_toolchain("64") {
+    environment = "environment.x64"
+
+    current_cpu = "x64"
+  }
+}
diff --git a/build/toolchain/win/midl.gni b/build/toolchain/win/midl.gni
new file mode 100644
index 0000000..748b0fc
--- /dev/null
+++ b/build/toolchain/win/midl.gni
@@ -0,0 +1,105 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win)
+
+import("//build/config/win/visual_studio_version.gni")
+
+# This template defines a rule to invoke the MS IDL compiler.
+#
+# Parameters
+#
+#   sources
+#      List of .idl file to process.
+#
+#   out_dir (optional)
+#       Directory to write the generated files to. Defaults to target_gen_dir.
+#
+#   deps (optional)
+#   visibility (optional)
+
+template("midl") {
+  action_name = "${target_name}_idl_action"
+  source_set_name = target_name
+
+  assert(defined(invoker.sources), "Source must be defined for $target_name")
+
+  if (defined(invoker.out_dir)) {
+    out_dir = invoker.out_dir
+  } else {
+    out_dir = target_gen_dir
+  }
+
+  header_file = "{{source_name_part}}.h"
+  dlldata_file = "{{source_name_part}}.dlldata.c"
+  interface_identifier_file = "{{source_name_part}}_i.c"
+  proxy_file = "{{source_name_part}}_p.c"
+  type_library_file = "{{source_name_part}}.tlb"
+
+  action_foreach(action_name) {
+    visibility = [ ":$source_set_name" ]
+
+    # This functionality is handled by the win-tool because the GYP build has
+    # MIDL support built-in.
+    # TODO(brettw) move this to a separate MIDL wrapper script for better
+    # clarity once GYP support is not needed.
+    script = "$root_build_dir/gyp-win-tool"
+
+    sources = invoker.sources
+
+    # Note that .tlb is not included in the outputs as it is not always
+    # generated depending on the content of the input idl file.
+    outputs = [
+      "$out_dir/$header_file",
+      "$out_dir/$dlldata_file",
+      "$out_dir/$interface_identifier_file",
+      "$out_dir/$proxy_file",
+    ]
+
+    if (current_cpu == "x86") {
+      win_tool_arch = "environment.x86"
+      idl_target_platform = "win32"
+    } else if (current_cpu == "x64") {
+      win_tool_arch = "environment.x64"
+      idl_target_platform = "x64"
+    } else {
+      assert(false, "Need environment for this arch")
+    }
+
+    args = [
+      "midl-wrapper",
+      win_tool_arch,
+      rebase_path(out_dir, root_build_dir),
+      type_library_file,
+      header_file,
+      dlldata_file,
+      interface_identifier_file,
+      proxy_file,
+      "{{source}}",
+      "/char",
+      "signed",
+      "/env",
+      idl_target_platform,
+      "/Oicf",
+    ]
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+  }
+
+  source_set(target_name) {
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+
+    # We only compile the IID files from the IDL tool rather than all outputs.
+    sources = process_file_template(invoker.sources,
+                                    [ "$out_dir/$interface_identifier_file" ])
+
+    deps = [
+      ":$action_name",
+    ]
+  }
+}
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
new file mode 100644
index 0000000..bc9bd1e
--- /dev/null
+++ b/build/toolchain/win/setup_toolchain.py
@@ -0,0 +1,154 @@
+# 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.
+#
+# Copies the given "win tool" (which the toolchain uses to wrap compiler
+# invocations) and the environment blocks for the 32-bit and 64-bit builds on
+# Windows to the build directory.
+#
+# The arguments are the visual studio install location and the location of the
+# win tool. The script assumes that the root build directory is the current dir
+# and the files will be written to the current directory.
+
+import errno
+import os
+import re
+import subprocess
+import sys
+
+
+def _ExtractImportantEnvironment(output_of_set):
+  """Extracts environment variables required for the toolchain to run from
+  a textual dump output by the cmd.exe 'set' command."""
+  envvars_to_save = (
+      'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
+      'include',
+      'lib',
+      'libpath',
+      'path',
+      'pathext',
+      'systemroot',
+      'temp',
+      'tmp',
+      )
+  env = {}
+  for line in output_of_set.splitlines():
+    for envvar in envvars_to_save:
+      if re.match(envvar + '=', line.lower()):
+        var, setting = line.split('=', 1)
+        if envvar == 'path':
+          # Our own rules (for running gyp-win-tool) and other actions in
+          # Chromium rely on python being in the path. Add the path to this
+          # python here so that if it's not in the path when ninja is run
+          # later, python will still be found.
+          setting = os.path.dirname(sys.executable) + os.pathsep + setting
+        env[var.upper()] = setting
+        break
+  for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
+    if required not in env:
+      raise Exception('Environment variable "%s" '
+                      'required to be set to valid path' % required)
+  return env
+
+
+def _SetupScript(target_cpu, sdk_dir):
+  """Returns a command (with arguments) to be used to set up the
+  environment."""
+  # Check if we are running in the SDK command line environment and use
+  # the setup script from the SDK if so. |target_cpu| should be either
+  # 'x86' or 'x64'.
+  assert target_cpu in ('x86', 'x64')
+  if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir:
+    return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')),
+            '/' + target_cpu]
+  else:
+    # We only support x64-hosted tools.
+    # TODO(scottmg|dpranke): Non-depot_tools toolchain: need to get Visual
+    # Studio install location from registry.
+    return [os.path.normpath(os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
+                                          'VC/vcvarsall.bat')),
+            'amd64_x86' if target_cpu == 'x86' else 'amd64']
+
+
+def _FormatAsEnvironmentBlock(envvar_dict):
+  """Format as an 'environment block' directly suitable for CreateProcess.
+  Briefly this is a list of key=value\0, terminated by an additional \0. See
+  CreateProcess documentation for more details."""
+  block = ''
+  nul = '\0'
+  for key, value in envvar_dict.iteritems():
+    block += key + '=' + value + nul
+  block += nul
+  return block
+
+
+def _CopyTool(source_path):
+  """Copies the given tool to the current directory, including a warning not
+  to edit it."""
+  with open(source_path) as source_file:
+    tool_source = source_file.readlines()
+
+  # Add header and write it out to the current directory (which should be the
+  # root build dir).
+  with open("gyp-win-tool", 'w') as tool_file:
+    tool_file.write(''.join([tool_source[0],
+                             '# Generated by setup_toolchain.py do not edit.\n']
+                            + tool_source[1:]))
+
+
+def main():
+  if len(sys.argv) != 6:
+    print('Usage setup_toolchain.py '
+          '<visual studio path> <win tool path> <win sdk path> '
+          '<runtime dirs> <target_cpu>')
+    sys.exit(2)
+  tool_source = sys.argv[2]
+  win_sdk_path = sys.argv[3]
+  runtime_dirs = sys.argv[4]
+  target_cpu = sys.argv[5]
+
+  _CopyTool(tool_source)
+
+  cpus = ('x86', 'x64')
+  assert target_cpu in cpus
+  vc_bin_dir = ''
+
+  # TODO(scottmg|goma): Do we need an equivalent of
+  # ninja_use_custom_environment_files?
+
+  for cpu in cpus:
+    # Extract environment variables for subprocesses.
+    args = _SetupScript(cpu, win_sdk_path)
+    args.extend(('&&', 'set'))
+    popen = subprocess.Popen(
+        args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+    variables, _ = popen.communicate()
+    env = _ExtractImportantEnvironment(variables)
+    env['PATH'] = runtime_dirs + ';' + env['PATH']
+
+    if cpu == target_cpu:
+      for path in env['PATH'].split(os.pathsep):
+        if os.path.exists(os.path.join(path, 'cl.exe')):
+          vc_bin_dir = os.path.realpath(path)
+          break
+
+    # The Windows SDK include directories must be first. They both have a sal.h,
+    # and the SDK one is newer and the SDK uses some newer features from it not
+    # present in the Visual Studio one.
+
+    if win_sdk_path:
+      additional_includes = ('{sdk_dir}\\Include\\shared;' +
+                             '{sdk_dir}\\Include\\um;' +
+                             '{sdk_dir}\\Include\\winrt;').format(
+                                  sdk_dir=win_sdk_path)
+      env['INCLUDE'] = additional_includes + env['INCLUDE']
+    env_block = _FormatAsEnvironmentBlock(env)
+    with open('environment.' + cpu, 'wb') as f:
+      f.write(env_block)
+
+  assert vc_bin_dir
+  print 'vc_bin_dir = "%s"' % vc_bin_dir
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/toolchain_vs2013.hash b/build/toolchain_vs2013.hash
new file mode 100644
index 0000000..4ed8816
--- /dev/null
+++ b/build/toolchain_vs2013.hash
@@ -0,0 +1 @@
+ee7d718ec60c2dc5d255bbe325909c2021a7efef
diff --git a/build/tree_truth.sh b/build/tree_truth.sh
new file mode 100755
index 0000000..617092d
--- /dev/null
+++ b/build/tree_truth.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Script for printing recent commits in a buildbot run.
+
+# Return the sha1 of the given tag.  If not present, return "".
+# $1: path to repo
+# $2: tag name
+tt_sha1_for_tag() {
+  oneline=$(cd $1 && git log -1 $2 --format='%H' 2>/dev/null)
+  if [ $? -eq 0 ] ; then
+    echo $oneline
+  fi
+}
+
+# Return the sha1 of HEAD, or ""
+# $1: path to repo
+tt_sha1_for_head() {
+  ( cd $1 && git log HEAD -n1 --format='%H' | cat )
+}
+
+# For the given repo, set tag to HEAD.
+# $1: path to repo
+# $2: tag name
+tt_tag_head() {
+  ( cd $1 && git tag -f $2 )
+}
+
+# For the given repo, delete the tag.
+# $1: path to repo
+# $2: tag name
+tt_delete_tag() {
+  ( cd $1 && git tag -d $2 )
+}
+
+# For the given repo, set tag to "three commits ago" (for testing).
+# $1: path to repo
+# $2: tag name
+tt_tag_three_ago() {
+ local sh=$(cd $1 && git log --pretty=oneline -n 3 | tail -1 | awk '{print $1}')
+  ( cd $1 && git tag -f $2 $sh )
+}
+
+# List the commits between the given tag and HEAD.
+# If the tag does not exist, only list the last few.
+# If the tag is at HEAD, list nothing.
+# Output format has distinct build steps for repos with changes.
+# $1: path to repo
+# $2: tag name
+# $3: simple/short repo name to use for display
+tt_list_commits() {
+  local tag_sha1=$(tt_sha1_for_tag $1 $2)
+  local head_sha1=$(tt_sha1_for_head $1)
+  local display_name=$(echo $3 | sed 's#/#_#g')
+  if [ "${tag_sha1}" = "${head_sha1}" ] ; then
+    return
+  fi
+  if [ "${tag_sha1}" = "" ] ; then
+    echo "@@@BUILD_STEP Recent commits in repo $display_name@@@"
+    echo "NOTE: git tag was not found so we have no baseline."
+    echo "Here are some recent commits, but they may not be new for this build."
+    ( cd $1 && git log -n 10 --stat | cat)
+  else
+    echo "@@@BUILD_STEP New commits in repo $display_name@@@"
+    ( cd $1 && git log -n 500 $2..HEAD --stat | cat)
+  fi
+}
+
+# Clean out the tree truth tags in all repos.  For testing.
+tt_clean_all() {
+ for project in $@; do
+   tt_delete_tag $CHROME_SRC/../$project tree_truth
+ done
+}
+
+# Print tree truth for all clank repos.
+tt_print_all() {
+ for project in $@; do
+   local full_path=$CHROME_SRC/../$project
+   tt_list_commits $full_path tree_truth $project
+   tt_tag_head $full_path tree_truth
+ done
+}
+
+# Print a summary of the last 10 commits for each repo.
+tt_brief_summary() {
+  echo "@@@BUILD_STEP Brief summary of recent CLs in every branch@@@"
+  for project in $@; do
+    echo $project:
+    local full_path=$CHROME_SRC/../$project
+    (cd $full_path && git log -n 10 --format="   %H %s   %an, %ad" | cat)
+    echo "================================================================="
+  done
+}
+
+CHROME_SRC=$1
+shift
+PROJECT_LIST=$@
+tt_brief_summary $PROJECT_LIST
+tt_print_all $PROJECT_LIST
diff --git a/build/uiautomator_test.gypi b/build/uiautomator_test.gypi
new file mode 100644
index 0000000..e9bd0bf
--- /dev/null
+++ b/build/uiautomator_test.gypi
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to build uiautomator dexed tests jar.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'test_suite_name',
+#   'type': 'none',
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+
+{
+  'dependencies': [
+    '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
+    '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
+  ],
+  'variables': {
+    'output_dex_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).dex.jar',
+  },
+  'actions': [
+    {
+      'action_name': 'dex_<(_target_name)',
+      'message': 'Dexing <(_target_name) jar',
+      'variables': {
+        'dex_input_paths': [
+          '>@(library_dexed_jars_paths)',
+        ],
+        'output_path': '<(output_dex_path)',
+      },
+      'includes': [ 'android/dex_action.gypi' ],
+    },
+  ],
+}
diff --git a/build/update-linux-sandbox.sh b/build/update-linux-sandbox.sh
new file mode 100755
index 0000000..735733a
--- /dev/null
+++ b/build/update-linux-sandbox.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+BUILDTYPE="${BUILDTYPE:-Debug}"
+CHROME_SRC_DIR="${CHROME_SRC_DIR:-$(dirname -- $(readlink -fn -- "$0"))/..}"
+CHROME_OUT_DIR="${CHROME_SRC_DIR}/${CHROMIUM_OUT_DIR:-out}/${BUILDTYPE}"
+CHROME_SANDBOX_BUILD_PATH="${CHROME_OUT_DIR}/chrome_sandbox"
+CHROME_SANDBOX_INST_PATH="/usr/local/sbin/chrome-devel-sandbox"
+CHROME_SANDBOX_INST_DIR=$(dirname -- "$CHROME_SANDBOX_INST_PATH")
+
+TARGET_DIR_TYPE=$(stat -f -c %t -- "${CHROME_SANDBOX_INST_DIR}" 2>/dev/null)
+if [ $? -ne 0 ]; then
+  echo "Could not get status of ${CHROME_SANDBOX_INST_DIR}"
+  exit 1
+fi
+
+# Make sure the path is not on NFS.
+if [ "${TARGET_DIR_TYPE}" = "6969" ]; then
+  echo "Please make sure ${CHROME_SANDBOX_INST_PATH} is not on NFS!"
+  exit 1
+fi
+
+installsandbox() {
+  echo "(using sudo so you may be asked for your password)"
+  sudo -- cp "${CHROME_SANDBOX_BUILD_PATH}" \
+    "${CHROME_SANDBOX_INST_PATH}" &&
+  sudo -- chown root:root "${CHROME_SANDBOX_INST_PATH}" &&
+  sudo -- chmod 4755 "${CHROME_SANDBOX_INST_PATH}"
+  return $?
+}
+
+if [ ! -d "${CHROME_OUT_DIR}" ]; then
+  echo -n "${CHROME_OUT_DIR} does not exist. Use \"BUILDTYPE=Release ${0}\" "
+  echo "If you are building in Release mode"
+  exit 1
+fi
+
+if [ ! -f "${CHROME_SANDBOX_BUILD_PATH}" ]; then
+  echo -n "Could not find ${CHROME_SANDBOX_BUILD_PATH}, "
+  echo "please make sure you build the chrome_sandbox target"
+  exit 1
+fi
+
+if [ ! -f "${CHROME_SANDBOX_INST_PATH}" ]; then
+  echo -n "Could not find ${CHROME_SANDBOX_INST_PATH}, "
+  echo "installing it now."
+  installsandbox
+fi
+
+if [ ! -f "${CHROME_SANDBOX_INST_PATH}" ]; then
+  echo "Failed to install ${CHROME_SANDBOX_INST_PATH}"
+  exit 1
+fi
+
+CURRENT_API=$("${CHROME_SANDBOX_BUILD_PATH}" --get-api)
+INSTALLED_API=$("${CHROME_SANDBOX_INST_PATH}" --get-api)
+
+if [ "${CURRENT_API}" != "${INSTALLED_API}" ]; then
+  echo "Your installed setuid sandbox is too old, installing it now."
+  if ! installsandbox; then
+    echo "Failed to install ${CHROME_SANDBOX_INST_PATH}"
+    exit 1
+  fi
+else
+  echo "Your setuid sandbox is up to date"
+  if [ "${CHROME_DEVEL_SANDBOX}" != "${CHROME_SANDBOX_INST_PATH}" ]; then
+    echo -n "Make sure you have \"export "
+    echo -n "CHROME_DEVEL_SANDBOX=${CHROME_SANDBOX_INST_PATH}\" "
+    echo "somewhere in your .bashrc"
+    echo "This variable is currently: ${CHROME_DEVEL_SANDBOX:-empty}"
+  fi
+fi
diff --git a/build/util/BUILD.gn b/build/util/BUILD.gn
new file mode 100644
index 0000000..c18f0ce
--- /dev/null
+++ b/build/util/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+action("webkit_version") {
+  script = "version.py"
+
+  lastchange_file = "LASTCHANGE.blink"
+
+  # TODO(brettw) move from content to this directory.
+  template_file = "//content/webkit_version.h.in"
+  inputs = [
+    lastchange_file,
+    template_file,
+  ]
+
+  output_file = "$root_gen_dir/webkit_version.h"
+  outputs = [
+    output_file,
+  ]
+
+  args = [
+    "-f",
+    rebase_path(lastchange_file, root_build_dir),
+    rebase_path(template_file, root_build_dir),
+    rebase_path(output_file, root_build_dir),
+  ]
+}
diff --git a/build/util/lastchange.py b/build/util/lastchange.py
new file mode 100755
index 0000000..1a7f519
--- /dev/null
+++ b/build/util/lastchange.py
@@ -0,0 +1,300 @@
+#!/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.
+
+"""
+lastchange.py -- Chromium revision fetching utility.
+"""
+
+import re
+import optparse
+import os
+import subprocess
+import sys
+
+_GIT_SVN_ID_REGEX = re.compile(r'.*git-svn-id:\s*([^@]*)@([0-9]+)', re.DOTALL)
+
+class VersionInfo(object):
+  def __init__(self, url, revision):
+    self.url = url
+    self.revision = revision
+
+
+def FetchSVNRevision(directory, svn_url_regex):
+  """
+  Fetch the Subversion branch and revision for a given directory.
+
+  Errors are swallowed.
+
+  Returns:
+    A VersionInfo object or None on error.
+  """
+  try:
+    proc = subprocess.Popen(['svn', 'info'],
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE,
+                            cwd=directory,
+                            shell=(sys.platform=='win32'))
+  except OSError:
+    # command is apparently either not installed or not executable.
+    return None
+  if not proc:
+    return None
+
+  attrs = {}
+  for line in proc.stdout:
+    line = line.strip()
+    if not line:
+      continue
+    key, val = line.split(': ', 1)
+    attrs[key] = val
+
+  try:
+    match = svn_url_regex.search(attrs['URL'])
+    if match:
+      url = match.group(2)
+    else:
+      url = ''
+    revision = attrs['Revision']
+  except KeyError:
+    return None
+
+  return VersionInfo(url, revision)
+
+
+def RunGitCommand(directory, command):
+  """
+  Launches git subcommand.
+
+  Errors are swallowed.
+
+  Returns:
+    A process object or None.
+  """
+  command = ['git'] + command
+  # Force shell usage under cygwin. This is a workaround for
+  # mysterious loss of cwd while invoking cygwin's git.
+  # We can't just pass shell=True to Popen, as under win32 this will
+  # cause CMD to be used, while we explicitly want a cygwin shell.
+  if sys.platform == 'cygwin':
+    command = ['sh', '-c', ' '.join(command)]
+  try:
+    proc = subprocess.Popen(command,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE,
+                            cwd=directory,
+                            shell=(sys.platform=='win32'))
+    return proc
+  except OSError:
+    return None
+
+
+def FetchGitRevision(directory):
+  """
+  Fetch the Git hash for a given directory.
+
+  Errors are swallowed.
+
+  Returns:
+    A VersionInfo object or None on error.
+  """
+  hsh = ''
+  proc = RunGitCommand(directory, ['rev-parse', 'HEAD'])
+  if proc:
+    output = proc.communicate()[0].strip()
+    if proc.returncode == 0 and output:
+      hsh = output
+  if not hsh:
+    return None
+  pos = ''
+  proc = RunGitCommand(directory, ['cat-file', 'commit', 'HEAD'])
+  if proc:
+    output = proc.communicate()[0]
+    if proc.returncode == 0 and output:
+      for line in reversed(output.splitlines()):
+        if line.startswith('Cr-Commit-Position:'):
+          pos = line.rsplit()[-1].strip()
+          break
+  if not pos:
+    return VersionInfo('git', hsh)
+  return VersionInfo('git', '%s-%s' % (hsh, pos))
+
+
+def FetchGitSVNURLAndRevision(directory, svn_url_regex):
+  """
+  Fetch the Subversion URL and revision through Git.
+
+  Errors are swallowed.
+
+  Returns:
+    A tuple containing the Subversion URL and revision.
+  """
+  proc = RunGitCommand(directory, ['log', '-1', '--format=%b'])
+  if proc:
+    output = proc.communicate()[0].strip()
+    if proc.returncode == 0 and output:
+      # Extract the latest SVN revision and the SVN URL.
+      # The target line is the last "git-svn-id: ..." line like this:
+      # git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85528 0039d316....
+      match = _GIT_SVN_ID_REGEX.search(output)
+      if match:
+        revision = match.group(2)
+        url_match = svn_url_regex.search(match.group(1))
+        if url_match:
+          url = url_match.group(2)
+        else:
+          url = ''
+        return url, revision
+  return None, None
+
+
+def FetchGitSVNRevision(directory, svn_url_regex):
+  """
+  Fetch the Git-SVN identifier for the local tree.
+
+  Errors are swallowed.
+  """
+  url, revision = FetchGitSVNURLAndRevision(directory, svn_url_regex)
+  if url and revision:
+    return VersionInfo(url, revision)
+  return None
+
+
+def FetchVersionInfo(default_lastchange, directory=None,
+                     directory_regex_prior_to_src_url='chrome|blink|svn'):
+  """
+  Returns the last change (in the form of a branch, revision tuple),
+  from some appropriate revision control system.
+  """
+  svn_url_regex = re.compile(
+      r'.*/(' + directory_regex_prior_to_src_url + r')(/.*)')
+
+  version_info = (FetchSVNRevision(directory, svn_url_regex) or
+                  FetchGitSVNRevision(directory, svn_url_regex) or
+                  FetchGitRevision(directory))
+  if not version_info:
+    if default_lastchange and os.path.exists(default_lastchange):
+      revision = open(default_lastchange, 'r').read().strip()
+      version_info = VersionInfo(None, revision)
+    else:
+      version_info = VersionInfo(None, None)
+  return version_info
+
+def GetHeaderGuard(path):
+  """
+  Returns the header #define guard for the given file path.
+  This treats everything after the last instance of "src/" as being a
+  relevant part of the guard. If there is no "src/", then the entire path
+  is used.
+  """
+  src_index = path.rfind('src/')
+  if src_index != -1:
+    guard = path[src_index + 4:]
+  else:
+    guard = path
+  guard = guard.upper()
+  return guard.replace('/', '_').replace('.', '_').replace('\\', '_') + '_'
+
+def GetHeaderContents(path, define, version):
+  """
+  Returns what the contents of the header file should be that indicate the given
+  revision. Note that the #define is specified as a string, even though it's
+  currently always a SVN revision number, in case we need to move to git hashes.
+  """
+  header_guard = GetHeaderGuard(path)
+
+  header_contents = """/* Generated by lastchange.py, do not edit.*/
+
+#ifndef %(header_guard)s
+#define %(header_guard)s
+
+#define %(define)s "%(version)s"
+
+#endif  // %(header_guard)s
+"""
+  header_contents = header_contents % { 'header_guard': header_guard,
+                                        'define': define,
+                                        'version': version }
+  return header_contents
+
+def WriteIfChanged(file_name, contents):
+  """
+  Writes the specified contents to the specified file_name
+  iff the contents are different than the current contents.
+  """
+  try:
+    old_contents = open(file_name, 'r').read()
+  except EnvironmentError:
+    pass
+  else:
+    if contents == old_contents:
+      return
+    os.unlink(file_name)
+  open(file_name, 'w').write(contents)
+
+
+def main(argv=None):
+  if argv is None:
+    argv = sys.argv
+
+  parser = optparse.OptionParser(usage="lastchange.py [options]")
+  parser.add_option("-d", "--default-lastchange", metavar="FILE",
+                    help="Default last change input FILE.")
+  parser.add_option("-m", "--version-macro",
+                    help="Name of C #define when using --header. Defaults to " +
+                    "LAST_CHANGE.",
+                    default="LAST_CHANGE")
+  parser.add_option("-o", "--output", metavar="FILE",
+                    help="Write last change to FILE. " +
+                    "Can be combined with --header to write both files.")
+  parser.add_option("", "--header", metavar="FILE",
+                    help="Write last change to FILE as a C/C++ header. " +
+                    "Can be combined with --output to write both files.")
+  parser.add_option("--revision-only", action='store_true',
+                    help="Just print the SVN revision number. Overrides any " +
+                    "file-output-related options.")
+  parser.add_option("-s", "--source-dir", metavar="DIR",
+                    help="Use repository in the given directory.")
+  opts, args = parser.parse_args(argv[1:])
+
+  out_file = opts.output
+  header = opts.header
+
+  while len(args) and out_file is None:
+    if out_file is None:
+      out_file = args.pop(0)
+  if args:
+    sys.stderr.write('Unexpected arguments: %r\n\n' % args)
+    parser.print_help()
+    sys.exit(2)
+
+  if opts.source_dir:
+    src_dir = opts.source_dir
+  else:
+    src_dir = os.path.dirname(os.path.abspath(__file__))
+
+  version_info = FetchVersionInfo(opts.default_lastchange, src_dir)
+
+  if version_info.revision == None:
+    version_info.revision = '0'
+
+  if opts.revision_only:
+    print version_info.revision
+  else:
+    contents = "LASTCHANGE=%s\n" % version_info.revision
+    if not out_file and not opts.header:
+      sys.stdout.write(contents)
+    else:
+      if out_file:
+        WriteIfChanged(out_file, contents)
+      if header:
+        WriteIfChanged(header,
+                       GetHeaderContents(header, opts.version_macro,
+                                         version_info.revision))
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/util/lib/common/__init__.py b/build/util/lib/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/util/lib/common/__init__.py
diff --git a/build/util/lib/common/perf_result_data_type.py b/build/util/lib/common/perf_result_data_type.py
new file mode 100644
index 0000000..67b550a
--- /dev/null
+++ b/build/util/lib/common/perf_result_data_type.py
@@ -0,0 +1,20 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+DEFAULT = 'default'
+UNIMPORTANT = 'unimportant'
+HISTOGRAM = 'histogram'
+UNIMPORTANT_HISTOGRAM = 'unimportant-histogram'
+INFORMATIONAL = 'informational'
+
+ALL_TYPES = [DEFAULT, UNIMPORTANT, HISTOGRAM, UNIMPORTANT_HISTOGRAM,
+             INFORMATIONAL]
+
+
+def IsValidType(datatype):
+  return datatype in ALL_TYPES
+
+
+def IsHistogram(datatype):
+  return (datatype == HISTOGRAM or datatype == UNIMPORTANT_HISTOGRAM)
diff --git a/build/util/lib/common/perf_tests_results_helper.py b/build/util/lib/common/perf_tests_results_helper.py
new file mode 100644
index 0000000..6cb058b
--- /dev/null
+++ b/build/util/lib/common/perf_tests_results_helper.py
@@ -0,0 +1,166 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import re
+import sys
+
+import json
+import logging
+import math
+
+import perf_result_data_type
+
+
+# Mapping from result type to test output
+RESULT_TYPES = {perf_result_data_type.UNIMPORTANT: 'RESULT ',
+                perf_result_data_type.DEFAULT: '*RESULT ',
+                perf_result_data_type.INFORMATIONAL: '',
+                perf_result_data_type.UNIMPORTANT_HISTOGRAM: 'HISTOGRAM ',
+                perf_result_data_type.HISTOGRAM: '*HISTOGRAM '}
+
+
+def _EscapePerfResult(s):
+  """Escapes |s| for use in a perf result."""
+  return re.sub('[\:|=/#&,]', '_', s)
+
+
+def FlattenList(values):
+  """Returns a simple list without sub-lists."""
+  ret = []
+  for entry in values:
+    if isinstance(entry, list):
+      ret.extend(FlattenList(entry))
+    else:
+      ret.append(entry)
+  return ret
+
+
+def GeomMeanAndStdDevFromHistogram(histogram_json):
+  histogram = json.loads(histogram_json)
+  # Handle empty histograms gracefully.
+  if not 'buckets' in histogram:
+    return 0.0, 0.0
+  count = 0
+  sum_of_logs = 0
+  for bucket in histogram['buckets']:
+    if 'high' in bucket:
+      bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0
+    else:
+      bucket['mean'] = bucket['low']
+    if bucket['mean'] > 0:
+      sum_of_logs += math.log(bucket['mean']) * bucket['count']
+      count += bucket['count']
+
+  if count == 0:
+    return 0.0, 0.0
+
+  sum_of_squares = 0
+  geom_mean = math.exp(sum_of_logs / count)
+  for bucket in histogram['buckets']:
+    if bucket['mean'] > 0:
+      sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count']
+  return geom_mean, math.sqrt(sum_of_squares / count)
+
+
+def _ValueToString(v):
+  # Special case for floats so we don't print using scientific notation.
+  if isinstance(v, float):
+    return '%f' % v
+  else:
+    return str(v)
+
+
+def _MeanAndStdDevFromList(values):
+  avg = None
+  sd = None
+  if len(values) > 1:
+    try:
+      value = '[%s]' % ','.join([_ValueToString(v) for v in values])
+      avg = sum([float(v) for v in values]) / len(values)
+      sqdiffs = [(float(v) - avg) ** 2 for v in values]
+      variance = sum(sqdiffs) / (len(values) - 1)
+      sd = math.sqrt(variance)
+    except ValueError:
+      value = ', '.join(values)
+  else:
+    value = values[0]
+  return value, avg, sd
+
+
+def PrintPages(page_list):
+  """Prints list of pages to stdout in the format required by perf tests."""
+  print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list])
+
+
+def PrintPerfResult(measurement, trace, values, units,
+                    result_type=perf_result_data_type.DEFAULT,
+                    print_to_stdout=True):
+  """Prints numerical data to stdout in the format required by perf tests.
+
+  The string args may be empty but they must not contain any colons (:) or
+  equals signs (=).
+  This is parsed by the buildbot using:
+  http://src.chromium.org/viewvc/chrome/trunk/tools/build/scripts/slave/process_log_utils.py
+
+  Args:
+    measurement: A description of the quantity being measured, e.g. "vm_peak".
+        On the dashboard, this maps to a particular graph. Mandatory.
+    trace: A description of the particular data point, e.g. "reference".
+        On the dashboard, this maps to a particular "line" in the graph.
+        Mandatory.
+    values: A list of numeric measured values. An N-dimensional list will be
+        flattened and treated as a simple list.
+    units: A description of the units of measure, e.g. "bytes".
+    result_type: Accepts values of perf_result_data_type.ALL_TYPES.
+    print_to_stdout: If True, prints the output in stdout instead of returning
+        the output to caller.
+
+    Returns:
+      String of the formated perf result.
+  """
+  assert perf_result_data_type.IsValidType(result_type), \
+         'result type: %s is invalid' % result_type
+
+  trace_name = _EscapePerfResult(trace)
+
+  if (result_type == perf_result_data_type.UNIMPORTANT or
+      result_type == perf_result_data_type.DEFAULT or
+      result_type == perf_result_data_type.INFORMATIONAL):
+    assert isinstance(values, list)
+    assert '/' not in measurement
+    flattened_values = FlattenList(values)
+    assert len(flattened_values)
+    value, avg, sd = _MeanAndStdDevFromList(flattened_values)
+    output = '%s%s: %s%s%s %s' % (
+        RESULT_TYPES[result_type],
+        _EscapePerfResult(measurement),
+        trace_name,
+        # Do not show equal sign if the trace is empty. Usually it happens when
+        # measurement is enough clear to describe the result.
+        '= ' if trace_name else '',
+        value,
+        units)
+  else:
+    assert perf_result_data_type.IsHistogram(result_type)
+    assert isinstance(values, list)
+    # The histograms can only be printed individually, there's no computation
+    # across different histograms.
+    assert len(values) == 1
+    value = values[0]
+    output = '%s%s: %s= %s %s' % (
+        RESULT_TYPES[result_type],
+        _EscapePerfResult(measurement),
+        trace_name,
+        value,
+        units)
+    avg, sd = GeomMeanAndStdDevFromHistogram(value)
+
+  if avg:
+    output += '\nAvg %s: %f%s' % (measurement, avg, units)
+  if sd:
+    output += '\nSd  %s: %f%s' % (measurement, sd, units)
+  if print_to_stdout:
+    print output
+    sys.stdout.flush()
+  return output
diff --git a/build/util/lib/common/unittest_util.py b/build/util/lib/common/unittest_util.py
new file mode 100644
index 0000000..e586224
--- /dev/null
+++ b/build/util/lib/common/unittest_util.py
@@ -0,0 +1,151 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utilities for dealing with the python unittest module."""
+
+import fnmatch
+import sys
+import unittest
+
+
+class _TextTestResult(unittest._TextTestResult):
+  """A test result class that can print formatted text results to a stream.
+
+  Results printed in conformance with gtest output format, like:
+  [ RUN        ] autofill.AutofillTest.testAutofillInvalid: "test desc."
+  [         OK ] autofill.AutofillTest.testAutofillInvalid
+  [ RUN        ] autofill.AutofillTest.testFillProfile: "test desc."
+  [         OK ] autofill.AutofillTest.testFillProfile
+  [ RUN        ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test."
+  [         OK ] autofill.AutofillTest.testFillProfileCrazyCharacters
+  """
+  def __init__(self, stream, descriptions, verbosity):
+    unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
+    self._fails = set()
+
+  def _GetTestURI(self, test):
+    return '%s.%s.%s' % (test.__class__.__module__,
+                         test.__class__.__name__,
+                         test._testMethodName)
+
+  def getDescription(self, test):
+    return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription())
+
+  def startTest(self, test):
+    unittest.TestResult.startTest(self, test)
+    self.stream.writeln('[ RUN        ] %s' % self.getDescription(test))
+
+  def addSuccess(self, test):
+    unittest.TestResult.addSuccess(self, test)
+    self.stream.writeln('[         OK ] %s' % self._GetTestURI(test))
+
+  def addError(self, test, err):
+    unittest.TestResult.addError(self, test, err)
+    self.stream.writeln('[      ERROR ] %s' % self._GetTestURI(test))
+    self._fails.add(self._GetTestURI(test))
+
+  def addFailure(self, test, err):
+    unittest.TestResult.addFailure(self, test, err)
+    self.stream.writeln('[     FAILED ] %s' % self._GetTestURI(test))
+    self._fails.add(self._GetTestURI(test))
+
+  def getRetestFilter(self):
+    return ':'.join(self._fails)
+
+
+class TextTestRunner(unittest.TextTestRunner):
+  """Test Runner for displaying test results in textual format.
+
+  Results are displayed in conformance with google test output.
+  """
+
+  def __init__(self, verbosity=1):
+    unittest.TextTestRunner.__init__(self, stream=sys.stderr,
+                                     verbosity=verbosity)
+
+  def _makeResult(self):
+    return _TextTestResult(self.stream, self.descriptions, self.verbosity)
+
+
+def GetTestsFromSuite(suite):
+  """Returns all the tests from a given test suite."""
+  tests = []
+  for x in suite:
+    if isinstance(x, unittest.TestSuite):
+      tests += GetTestsFromSuite(x)
+    else:
+      tests += [x]
+  return tests
+
+
+def GetTestNamesFromSuite(suite):
+  """Returns a list of every test name in the given suite."""
+  return map(lambda x: GetTestName(x), GetTestsFromSuite(suite))
+
+
+def GetTestName(test):
+  """Gets the test name of the given unittest test."""
+  return '.'.join([test.__class__.__module__,
+                   test.__class__.__name__,
+                   test._testMethodName])
+
+
+def FilterTestSuite(suite, gtest_filter):
+  """Returns a new filtered tests suite based on the given gtest filter.
+
+  See http://code.google.com/p/googletest/wiki/AdvancedGuide
+  for gtest_filter specification.
+  """
+  return unittest.TestSuite(FilterTests(GetTestsFromSuite(suite), gtest_filter))
+
+
+def FilterTests(all_tests, gtest_filter):
+  """Filter a list of tests based on the given gtest filter.
+
+  Args:
+    all_tests: List of tests (unittest.TestSuite)
+    gtest_filter: Filter to apply.
+
+  Returns:
+    Filtered subset of the given list of tests.
+  """
+  test_names = [GetTestName(test) for test in all_tests]
+  filtered_names = FilterTestNames(test_names, gtest_filter)
+  return [test for test in all_tests if GetTestName(test) in filtered_names]
+
+
+def FilterTestNames(all_tests, gtest_filter):
+  """Filter a list of test names based on the given gtest filter.
+
+  See http://code.google.com/p/googletest/wiki/AdvancedGuide
+  for gtest_filter specification.
+
+  Args:
+    all_tests: List of test names.
+    gtest_filter: Filter to apply.
+
+  Returns:
+    Filtered subset of the given list of test names.
+  """
+  pattern_groups = gtest_filter.split('-')
+  positive_patterns = pattern_groups[0].split(':')
+  negative_patterns = None
+  if len(pattern_groups) > 1:
+    negative_patterns = pattern_groups[1].split(':')
+
+  tests = []
+  for test in all_tests:
+    # Test name must by matched by one positive pattern.
+    for pattern in positive_patterns:
+      if fnmatch.fnmatch(test, pattern):
+        break
+    else:
+      continue
+    # Test name must not be matched by any negative patterns.
+    for pattern in negative_patterns or []:
+      if fnmatch.fnmatch(test, pattern):
+        break
+    else:
+      tests += [test]
+  return tests
diff --git a/build/util/lib/common/util.py b/build/util/lib/common/util.py
new file mode 100644
index 0000000..a415b1f
--- /dev/null
+++ b/build/util/lib/common/util.py
@@ -0,0 +1,151 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generic utilities for all python scripts."""
+
+import atexit
+import httplib
+import os
+import signal
+import stat
+import subprocess
+import sys
+import tempfile
+import urlparse
+
+
+def GetPlatformName():
+  """Return a string to be used in paths for the platform."""
+  if IsWindows():
+    return 'win'
+  if IsMac():
+    return 'mac'
+  if IsLinux():
+    return 'linux'
+  raise NotImplementedError('Unknown platform "%s".' % sys.platform)
+
+
+def IsWindows():
+  return sys.platform == 'cygwin' or sys.platform.startswith('win')
+
+
+def IsLinux():
+  return sys.platform.startswith('linux')
+
+
+def IsMac():
+  return sys.platform.startswith('darwin')
+
+
+def _DeleteDir(path):
+  """Deletes a directory recursively, which must exist."""
+  # Don't use shutil.rmtree because it can't delete read-only files on Win.
+  for root, dirs, files in os.walk(path, topdown=False):
+    for name in files:
+      filename = os.path.join(root, name)
+      os.chmod(filename, stat.S_IWRITE)
+      os.remove(filename)
+    for name in dirs:
+      os.rmdir(os.path.join(root, name))
+  os.rmdir(path)
+
+
+def Delete(path):
+  """Deletes the given file or directory (recursively), which must exist."""
+  if os.path.isdir(path):
+    _DeleteDir(path)
+  else:
+    os.remove(path)
+
+
+def MaybeDelete(path):
+  """Deletes the given file or directory (recurisvely), if it exists."""
+  if os.path.exists(path):
+    Delete(path)
+
+
+def MakeTempDir(parent_dir=None):
+  """Creates a temporary directory and returns an absolute path to it.
+
+  The temporary directory is automatically deleted when the python interpreter
+  exits normally.
+
+  Args:
+    parent_dir: the directory to create the temp dir in. If None, the system
+                temp dir is used.
+
+  Returns:
+    The absolute path to the temporary directory.
+  """
+  path = tempfile.mkdtemp(dir=parent_dir)
+  atexit.register(MaybeDelete, path)
+  return path
+
+
+def Unzip(zip_path, output_dir):
+  """Unzips the given zip file using a system installed unzip tool.
+
+  Args:
+    zip_path: zip file to unzip.
+    output_dir: directory to unzip the contents of the zip file. The directory
+                must exist.
+
+  Raises:
+    RuntimeError if the unzip operation fails.
+  """
+  if IsWindows():
+    unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y']
+  else:
+    unzip_cmd = ['unzip', '-o']
+  unzip_cmd += [zip_path]
+  if RunCommand(unzip_cmd, output_dir) != 0:
+    raise RuntimeError('Unable to unzip %s to %s' % (zip_path, output_dir))
+
+
+def Kill(pid):
+  """Terminate the given pid."""
+  if IsWindows():
+    subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)])
+  else:
+    os.kill(pid, signal.SIGTERM)
+
+
+def RunCommand(cmd, cwd=None):
+  """Runs the given command and returns the exit code.
+
+  Args:
+    cmd: list of command arguments.
+    cwd: working directory to execute the command, or None if the current
+         working directory should be used.
+
+  Returns:
+    The exit code of the command.
+  """
+  process = subprocess.Popen(cmd, cwd=cwd)
+  process.wait()
+  return process.returncode
+
+
+def DoesUrlExist(url):
+  """Determines whether a resource exists at the given URL.
+
+  Args:
+    url: URL to be verified.
+
+  Returns:
+    True if url exists, otherwise False.
+  """
+  parsed = urlparse.urlparse(url)
+  try:
+    conn = httplib.HTTPConnection(parsed.netloc)
+    conn.request('HEAD', parsed.path)
+    response = conn.getresponse()
+  except (socket.gaierror, socket.error):
+    return False
+  finally:
+    conn.close()
+  # Follow both permanent (301) and temporary (302) redirects.
+  if response.status == 302 or response.status == 301:
+    return DoesUrlExist(response.getheader('location'))
+  return response.status == 200
diff --git a/build/util/version.gypi b/build/util/version.gypi
new file mode 100644
index 0000000..327a5c2
--- /dev/null
+++ b/build/util/version.gypi
@@ -0,0 +1,20 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'variables': {
+      'version_py_path': '<(DEPTH)/build/util/version.py',
+      'version_path': '<(DEPTH)/chrome/VERSION',
+      'lastchange_path': '<(DEPTH)/build/util/LASTCHANGE',
+    },
+    'version_py_path': '<(version_py_path)',
+    'version_path': '<(version_path)',
+    'lastchange_path': '<(lastchange_path)',
+    'version_full':
+        '<!(python <(version_py_path) -f <(version_path) -t "@MAJOR@.@MINOR@.@BUILD@.@PATCH@")',
+    'version_mac_dylib':
+        '<!(python <(version_py_path) -f <(version_path) -t "@BUILD@.@PATCH_HI@.@PATCH_LO@" -e "PATCH_HI=int(PATCH)/256" -e "PATCH_LO=int(PATCH)%256")',
+  },  # variables
+}
diff --git a/build/util/version.py b/build/util/version.py
new file mode 100755
index 0000000..4d3691a
--- /dev/null
+++ b/build/util/version.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+version.py -- Chromium version string substitution utility.
+"""
+
+import argparse
+import os
+import sys
+
+
+def fetch_values_from_file(values_dict, file_name):
+  """
+  Fetches KEYWORD=VALUE settings from the specified file.
+
+  Everything to the left of the first '=' is the keyword,
+  everything to the right is the value.  No stripping of
+  white space, so beware.
+
+  The file must exist, otherwise you get the Python exception from open().
+  """
+  for line in open(file_name, 'r').readlines():
+    key, val = line.rstrip('\r\n').split('=', 1)
+    values_dict[key] = val
+
+
+def fetch_values(file_list):
+  """
+  Returns a dictionary of values to be used for substitution, populating
+  the dictionary with KEYWORD=VALUE settings from the files in 'file_list'.
+
+  Explicitly adds the following value from internal calculations:
+
+    OFFICIAL_BUILD
+  """
+  CHROME_BUILD_TYPE = os.environ.get('CHROME_BUILD_TYPE')
+  if CHROME_BUILD_TYPE == '_official':
+    official_build = '1'
+  else:
+    official_build = '0'
+
+  values = dict(
+    OFFICIAL_BUILD = official_build,
+  )
+
+  for file_name in file_list:
+    fetch_values_from_file(values, file_name)
+
+  return values
+
+
+def subst_template(contents, values):
+  """
+  Returns the template with substituted values from the specified dictionary.
+
+  Keywords to be substituted are surrounded by '@':  @KEYWORD@.
+
+  No attempt is made to avoid recursive substitution.  The order
+  of evaluation is random based on the order of the keywords returned
+  by the Python dictionary.  So do NOT substitute a value that
+  contains any @KEYWORD@ strings expecting them to be recursively
+  substituted, okay?
+  """
+  for key, val in values.iteritems():
+    try:
+      contents = contents.replace('@' + key + '@', val)
+    except TypeError:
+      print repr(key), repr(val)
+  return contents
+
+
+def subst_file(file_name, values):
+  """
+  Returns the contents of the specified file_name with substituted
+  values from the specified dictionary.
+
+  This is like subst_template, except it operates on a file.
+  """
+  template = open(file_name, 'r').read()
+  return subst_template(template, values);
+
+
+def write_if_changed(file_name, contents):
+  """
+  Writes the specified contents to the specified file_name
+  iff the contents are different than the current contents.
+  """
+  try:
+    old_contents = open(file_name, 'r').read()
+  except EnvironmentError:
+    pass
+  else:
+    if contents == old_contents:
+      return
+    os.unlink(file_name)
+  open(file_name, 'w').write(contents)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-f', '--file', action='append', default=[],
+                      help='Read variables from FILE.')
+  parser.add_argument('-i', '--input', default=None,
+                      help='Read strings to substitute from FILE.')
+  parser.add_argument('-o', '--output', default=None,
+                      help='Write substituted strings to FILE.')
+  parser.add_argument('-t', '--template', default=None,
+                      help='Use TEMPLATE as the strings to substitute.')
+  parser.add_argument('-e', '--eval', action='append', default=[],
+                      help='Evaluate VAL after reading variables. Can be used '
+                           'to synthesize variables. e.g. -e \'PATCH_HI=int('
+                           'PATCH)/256.')
+  parser.add_argument('args', nargs=argparse.REMAINDER,
+                      help='For compatibility: INPUT and OUTPUT can be '
+                           'passed as positional arguments.')
+  options = parser.parse_args()
+
+  evals = {}
+  for expression in options.eval:
+    try:
+      evals.update(dict([expression.split('=', 1)]))
+    except ValueError:
+      parser.error('-e requires VAR=VAL')
+
+  # Compatibility with old versions that considered the first two positional
+  # arguments shorthands for --input and --output.
+  while len(options.args) and (options.input is None or \
+                               options.output is None):
+    if options.input is None:
+      options.input = options.args.pop(0)
+    elif options.output is None:
+      options.output = options.args.pop(0)
+  if options.args:
+    parser.error('Unexpected arguments: %r' % options.args)
+
+  values = fetch_values(options.file)
+  for key, val in evals.iteritems():
+    values[key] = str(eval(val, globals(), values))
+
+  if options.template is not None:
+    contents = subst_template(options.template, values)
+  elif options.input:
+    contents = subst_file(options.input, values)
+  else:
+    # Generate a default set of version information.
+    contents = """MAJOR=%(MAJOR)s
+MINOR=%(MINOR)s
+BUILD=%(BUILD)s
+PATCH=%(PATCH)s
+LASTCHANGE=%(LASTCHANGE)s
+OFFICIAL_BUILD=%(OFFICIAL_BUILD)s
+""" % values
+
+  if options.output is not None:
+    write_if_changed(options.output, contents)
+  else:
+    print contents
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
new file mode 100644
index 0000000..5b175eb
--- /dev/null
+++ b/build/vs_toolchain.py
@@ -0,0 +1,221 @@
+# Copyright 2014 The Chromium 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 json
+import os
+import pipes
+import shutil
+import subprocess
+import sys
+
+
+script_dir = os.path.dirname(os.path.realpath(__file__))
+chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
+SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(1, os.path.join(chrome_src, 'tools'))
+sys.path.insert(0, os.path.join(chrome_src, 'tools', 'gyp', 'pylib'))
+json_data_file = os.path.join(script_dir, 'win_toolchain.json')
+
+
+import gyp
+
+
+def SetEnvironmentAndGetRuntimeDllDirs():
+  """Sets up os.environ to use the depot_tools VS toolchain with gyp, and
+  returns the location of the VS runtime DLLs so they can be copied into
+  the output directory after gyp generation.
+  """
+  vs2013_runtime_dll_dirs = None
+  depot_tools_win_toolchain = \
+      bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
+  if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
+    if not os.path.exists(json_data_file):
+      Update()
+    with open(json_data_file, 'r') as tempf:
+      toolchain_data = json.load(tempf)
+
+    toolchain = toolchain_data['path']
+    version = toolchain_data['version']
+    win8sdk = toolchain_data['win8sdk']
+    wdk = toolchain_data['wdk']
+    # TODO(scottmg): The order unfortunately matters in these. They should be
+    # split into separate keys for x86 and x64. (See CopyVsRuntimeDlls call
+    # below). http://crbug.com/345992
+    vs2013_runtime_dll_dirs = toolchain_data['runtime_dirs']
+
+    os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
+    os.environ['GYP_MSVS_VERSION'] = version
+    # We need to make sure windows_sdk_path is set to the automated
+    # toolchain values in GYP_DEFINES, but don't want to override any
+    # otheroptions.express
+    # values there.
+    gyp_defines_dict = gyp.NameValueListToDict(gyp.ShlexEnv('GYP_DEFINES'))
+    gyp_defines_dict['windows_sdk_path'] = win8sdk
+    os.environ['GYP_DEFINES'] = ' '.join('%s=%s' % (k, pipes.quote(str(v)))
+        for k, v in gyp_defines_dict.iteritems())
+    os.environ['WINDOWSSDKDIR'] = win8sdk
+    os.environ['WDK_DIR'] = wdk
+    # Include the VS runtime in the PATH in case it's not machine-installed.
+    runtime_path = ';'.join(vs2013_runtime_dll_dirs)
+    os.environ['PATH'] = runtime_path + ';' + os.environ['PATH']
+  return vs2013_runtime_dll_dirs
+
+
+def _CopyRuntimeImpl(target, source):
+  """Copy |source| to |target| if it doesn't already exist or if it
+  needs to be updated.
+  """
+  if (os.path.isdir(os.path.dirname(target)) and
+      (not os.path.isfile(target) or
+      os.stat(target).st_mtime != os.stat(source).st_mtime)):
+    print 'Copying %s to %s...' % (source, target)
+    if os.path.exists(target):
+      os.unlink(target)
+    shutil.copy2(source, target)
+
+
+def _CopyRuntime(target_dir, source_dir, dll_pattern):
+    """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
+    exist, but the target directory does exist."""
+    for which in ('p', 'r'):
+      dll = dll_pattern % which
+      target = os.path.join(target_dir, dll)
+      source = os.path.join(source_dir, dll)
+      _CopyRuntimeImpl(target, source)
+
+
+def CopyVsRuntimeDlls(output_dir, runtime_dirs):
+  """Copies the VS runtime DLLs from the given |runtime_dirs| to the output
+  directory so that even if not system-installed, built binaries are likely to
+  be able to run.
+
+  This needs to be run after gyp has been run so that the expected target
+  output directories are already created.
+  """
+  assert sys.platform.startswith(('win32', 'cygwin'))
+
+  x86, x64 = runtime_dirs
+  out_debug = os.path.join(output_dir, 'Debug')
+  out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
+  out_release = os.path.join(output_dir, 'Release')
+  out_release_nacl64 = os.path.join(output_dir, 'Release', 'x64')
+  out_debug_x64 = os.path.join(output_dir, 'Debug_x64')
+  out_release_x64 = os.path.join(output_dir, 'Release_x64')
+
+  if os.path.exists(out_debug) and not os.path.exists(out_debug_nacl64):
+    os.makedirs(out_debug_nacl64)
+  if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
+    os.makedirs(out_release_nacl64)
+  _CopyRuntime(out_debug,          x86, 'msvc%s120d.dll')
+  _CopyRuntime(out_release,        x86, 'msvc%s120.dll')
+  _CopyRuntime(out_debug_x64,      x64, 'msvc%s120d.dll')
+  _CopyRuntime(out_release_x64,    x64, 'msvc%s120.dll')
+  _CopyRuntime(out_debug_nacl64,   x64, 'msvc%s120d.dll')
+  _CopyRuntime(out_release_nacl64, x64, 'msvc%s120.dll')
+
+  # Copy the PGO runtime library to the release directories.
+  if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
+    pgo_x86_runtime_dir = os.path.join(os.environ.get('GYP_MSVS_OVERRIDE_PATH'),
+                                       'VC', 'bin')
+    pgo_x64_runtime_dir = os.path.join(pgo_x86_runtime_dir, 'amd64')
+    pgo_runtime_dll = 'pgort120.dll'
+    source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
+    if os.path.exists(source_x86):
+      _CopyRuntimeImpl(os.path.join(out_release, pgo_runtime_dll), source_x86)
+    source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
+    if os.path.exists(source_x64):
+      _CopyRuntimeImpl(os.path.join(out_release_x64, pgo_runtime_dll),
+                       source_x64)
+
+
+def CopyDlls(target_dir, configuration, target_cpu):
+  """Copy the VS runtime DLLs into the requested directory as needed.
+
+  configuration is one of 'Debug' or 'Release'.
+  target_cpu is one of 'x86' or 'x64'.
+
+  The debug configuration gets both the debug and release DLLs; the
+  release config only the latter.
+  """
+  vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+  if not vs2013_runtime_dll_dirs:
+    return
+
+  x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
+  runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
+  _CopyRuntime(target_dir, runtime_dir, 'msvc%s120.dll')
+  if configuration == 'Debug':
+    _CopyRuntime(target_dir, runtime_dir, 'msvc%s120d.dll')
+
+
+def _GetDesiredVsToolchainHashes():
+  """Load a list of SHA1s corresponding to the toolchains that we want installed
+  to build with."""
+  sha1path = os.path.join(script_dir, 'toolchain_vs2013.hash')
+  with open(sha1path, 'rb') as f:
+    return f.read().strip().splitlines()
+
+
+def Update():
+  """Requests an update of the toolchain to the specific hashes we have at
+  this revision. The update outputs a .json of the various configuration
+  information required to pass to gyp which we use in |GetToolchainDir()|.
+  """
+  depot_tools_win_toolchain = \
+      bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
+  if sys.platform in ('win32', 'cygwin') and depot_tools_win_toolchain:
+    import find_depot_tools
+    depot_tools_path = find_depot_tools.add_depot_tools_to_path()
+    get_toolchain_args = [
+        sys.executable,
+        os.path.join(depot_tools_path,
+                    'win_toolchain',
+                    'get_toolchain_if_necessary.py'),
+        '--output-json', json_data_file,
+      ] + _GetDesiredVsToolchainHashes()
+    subprocess.check_call(get_toolchain_args)
+
+  return 0
+
+
+def GetToolchainDir():
+  """Gets location information about the current toolchain (must have been
+  previously updated by 'update'). This is used for the GN build."""
+  runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+
+  # If WINDOWSSDKDIR is not set, search the default SDK path and set it.
+  if not 'WINDOWSSDKDIR' in os.environ:
+    default_sdk_path = 'C:\\Program Files (x86)\\Windows Kits\\8.1'
+    if os.path.isdir(default_sdk_path):
+      os.environ['WINDOWSSDKDIR'] = default_sdk_path
+
+  print '''vs_path = "%s"
+sdk_path = "%s"
+vs_version = "%s"
+wdk_dir = "%s"
+runtime_dirs = "%s"
+''' % (
+      os.environ['GYP_MSVS_OVERRIDE_PATH'],
+      os.environ['WINDOWSSDKDIR'],
+      os.environ['GYP_MSVS_VERSION'],
+      os.environ.get('WDK_DIR', ''),
+      ';'.join(runtime_dll_dirs or ['None']))
+
+
+def main():
+  if not sys.platform.startswith(('win32', 'cygwin')):
+    return 0
+  commands = {
+      'update': Update,
+      'get_toolchain_dir': GetToolchainDir,
+      'copy_dlls': CopyDlls,
+  }
+  if len(sys.argv) < 2 or sys.argv[1] not in commands:
+    print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
+    return 1
+  return commands[sys.argv[1]](*sys.argv[2:])
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
new file mode 100644
index 0000000..ea82f4e
--- /dev/null
+++ b/build/whitespace_file.txt
@@ -0,0 +1,156 @@
+Copyright 2014 The Chromium Authors. All rights reserved.
+Use of this useless file is governed by a BSD-style license that can be
+found in the LICENSE file.
+
+
+This file is used for making non-code changes to trigger buildbot cycles. Make
+any modification below this line.
+
+======================================================================
+
+Let's make a story. Add zero+ sentences for every commit:
+
+CHÄPTER 1:
+It was a dark and blinky night; the rain fell in torrents -- except at
+occasional intervals, when it was checked by a violent gust of wind which
+swept up the streets (for it is in London that our scene lies), rattling along
+the housetops, and fiercely agitating the scanty flame of the lamps that
+struggled against the elements. A hooded figure emerged.
+
+It was a Domo-Kun.
+
+"What took you so long?", inquired his wife.
+
+Silence. Oblivious to his silence, she continued, "Did Mr. Usagi enjoy the
+waffles you brought him?" "You know him, he's not one to forego a waffle,
+no matter how burnt," he snickered.
+
+The pause was filled with the sound of compile errors.
+
+CHAPTER 2:
+The jelly was as dark as night, and just as runny.
+The Domo-Kun shuddered, remembering the way Mr. Usagi had speared his waffles
+with his fork, watching the runny jelly spread and pool across his plate,
+like the blood of a dying fawn. "It reminds me of that time --" he started, as
+his wife cut in quickly: "-- please. I can't bear to hear it.". A flury of
+images coming from the past flowed through his mind.
+
+"You recall what happened on Mulholland drive?" The ceiling fan rotated slowly
+overhead, barely disturbing the thick cigarette smoke. No doubt was left about
+when the fan was last cleaned.
+
+There was a poignant pause.
+
+CHAPTER 3:
+Mr. Usagi felt that something wasn't right. Shortly after the Domo-Kun left he
+began feeling sick. He thought out loud to himself, "No, he wouldn't have done
+that to me." He considered that perhaps he shouldn't have pushed so hard.
+Perhaps he shouldn't have been so cold and sarcastic, after the unimaginable
+horror that had occurred just the week before.
+
+Next time, there won't be any sushi. Why sushi with waffles anyway?  It's like
+adorning breakfast cereal with halibut -- shameful.
+
+CHAPTER 4:
+The taste of stale sushi in his mouth the next morning was unbearable. He
+wondered where the sushi came from as he attempted to wash the taste away with
+a bottle of 3000¥ sake. He tries to recall the cook's face.  Purple? Probably.
+
+CHAPTER 5:
+Many tears later, Mr. Usagi would laugh at the memory of the earnest,
+well-intentioned Domo-Kun. Another day in the life. That is when he realized that
+life goes on.
+
+TRUISMS (1978-1983)
+JENNY HOLZER
+A LITTLE KNOWLEDGE CAN GO A LONG WAY
+A LOT OF PROFESSIONALS ARE CRACKPOTS
+A MAN CAN'T KNOW WHAT IT IS TO BE A MOTHER
+A NAME MEANS A LOT JUST BY ITSELF
+A POSITIVE ATTITUDE MEANS ALL THE DIFFERENCE IN THE WORLD
+A RELAXED MAN IS NOT NECESSARILY A BETTER MAN
+NO ONE SHOULD EVER USE SVN
+AN INFLEXIBLE POSITION SOMETIMES IS A SIGN OF PARALYSIS
+IT IS MANS FATE TO OUTSMART HIMSELF
+BEING SURE OF YOURSELF MEANS YOU'RE A FOOL
+AM NOT
+ARE TOO
+IF AT FIRST YOU DON'T SUCCEED: TRY, EXCEPT, FINALLY
+AND THEN, TIME LEAPT BACKWARDS
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaaaaaahhhh LOT
+I'm really tempted to change something above the line.
+Reeccciiiipppppeeeeeesssssss!!!!!!!!!
+PEOPLE SAY "FAILURE IS NOT AN OPTION", BUT FAILURE IS ALWAYS AN OPTION.
+WHAT GOES UP MUST HAVE A NON-ZERO VELOCITY
+
+I can feel the heat closing in, feel them out there making their moves...
+What could possibly go wrong? We've already ate our cake.
+
+Stand Still. Pause Clocks. We can make the World Stop.
+WUBWUBWUBWUBWUB
+
+I want a 1917 build and you will give me what I want.
+
+This sentence is false.
+
+Beauty is in the eyes of a Beholder.
+
+I'm the best at space.
+
+The first time Yossarian saw the chaplain, he fell madly in love with him.
+*
+*
+*
+Give not thyself up, then, to fire, lest it invert thee, deaden thee; as for
+the time it did me. There is a wisdom that is woe; but there is a woe that is
+madness. And there is a Catskill eagle in some souls that can alike dive down
+into the blackest gorges, and soar out of them again and become invisible in
+the sunny spaces. And even if he for ever flies within the gorge, that gorge
+is in the mountains; so that even in his lowest swoop the mountain eagle is
+still higher than other birds upon the plain, even though they soar.
+*
+*
+*
+
+I'm here to commit lines and drop rhymes
+*
+This is a line to test and try uploading a cl.
+
+And lo, in the year 2014, there was verily an attempt to upgrade to GCC 4.8 on
+the Android bots, and it was good. Except on one bot, where it was bad. And
+lo, the change was reverted, and GCC went back to 4.6, where code is slower
+and less optimized. And verily did it break the build, because artifacts had
+been created with 4.8, and alignment was no longer the same, and a great
+sadness descended upon the Android GN buildbot, and it did refuseth to build
+any more. But the sheriffs thought to themselves: Placebo! Let us clobber the
+bot, and perhaps it will rebuild with GCC 4.6, which hath worked for many many
+seasons. And so they modified the whitespace file with these immortal lines,
+and visited it upon the bots, that great destruction might be wrought upon
+their outdated binaries. In clobberus, veritas.
+
+As the git approaches, light begins to shine through the SCM thrice again...
+However, the git, is, after all, quite stupid.
+
+Suddenly Domo-Kun found itself in a room filled with dazzling mirrors.
+
+A herd of wild gits appears!  Time for CQ :D
+And one more for sizes.py...
+
+Sigh.
+
+It was love at first sight.  The moment Yossarian first laid eyes on the chaplain, he fell madly in love with him.
+
+Cool whitespace change for git-cl land
+
+Oh god the bots are red! I'm blind! Mmmm, cronuts.
+
+If you stand on your head, you will get footprints in your hair.
+
+sigh
+sigher
+pick up cls
+
+In the BUILD we trust.
+^_^
+
+In the masters we don't.
diff --git a/build/win/asan.gyp b/build/win/asan.gyp
new file mode 100644
index 0000000..c0d0c98
--- /dev/null
+++ b/build/win/asan.gyp
@@ -0,0 +1,30 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+   'targets': [
+     {
+       'target_name': 'asan_dynamic_runtime',
+       'type': 'none',
+       'variables': {
+         # Every target is going to depend on asan_dynamic_runtime, so allow
+         # this one to depend on itself.
+         'prune_self_dependency': 1,
+       },
+       'conditions': [
+         ['OS=="win"', {
+           'copies': [
+             {
+               'destination': '<(PRODUCT_DIR)',
+               'files': [
+                 # Path is relative to this GYP file.
+                 '<(DEPTH)/<(make_clang_dir)/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll',
+               ],
+             },
+           ],
+         }],
+       ],
+     },
+   ],
+}
diff --git a/build/win/chrome_win.croc b/build/win/chrome_win.croc
new file mode 100644
index 0000000..e1e3bb7
--- /dev/null
+++ b/build/win/chrome_win.croc
@@ -0,0 +1,26 @@
+# -*- python -*-
+# Crocodile config file for Chromium windows
+
+{
+  # List of rules, applied in order
+  'rules' : [
+    # Specify inclusions before exclusions, since rules are in order.
+
+    # Don't include chromeos, posix, or linux specific files
+    {
+      'regexp' : '.*(_|/)(chromeos|linux|posix)(\\.|_)',
+      'include' : 0,
+    },
+    # Don't include ChromeOS dirs
+    {
+      'regexp' : '.*/chromeos/',
+      'include' : 0,
+    },
+
+    # Groups
+    {
+      'regexp' : '.*_test_win\\.',
+      'group' : 'test',
+    },
+  ],
+}
diff --git a/build/win/compatibility.manifest b/build/win/compatibility.manifest
new file mode 100644
index 0000000..10d10da
--- /dev/null
+++ b/build/win/compatibility.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!--The ID below indicates application support for Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+      <!--The ID below indicates application support for Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <!--The ID below indicates application support for Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!--The ID below indicates application support for Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+      <!--The ID below indicates application support for Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+    </application>
+  </compatibility>
+</assembly>
diff --git a/build/win/dbghelp_xp/README.chromium b/build/win/dbghelp_xp/README.chromium
new file mode 100644
index 0000000..a52cfad
--- /dev/null
+++ b/build/win/dbghelp_xp/README.chromium
@@ -0,0 +1,2 @@
+This dbghelp.dll is the redistributable version from the Windows 7 SDK, the

+last one to work on Windows XP.

diff --git a/build/win/dbghelp_xp/dbghelp.dll b/build/win/dbghelp_xp/dbghelp.dll
new file mode 100755
index 0000000..9f52a5d
--- /dev/null
+++ b/build/win/dbghelp_xp/dbghelp.dll
Binary files differ
diff --git a/build/win/importlibs/create_import_lib.gypi b/build/win/importlibs/create_import_lib.gypi
new file mode 100644
index 0000000..9cb0d34
--- /dev/null
+++ b/build/win/importlibs/create_import_lib.gypi
@@ -0,0 +1,53 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is meant to be included into a target to provide a rule
+# to create import libraries from an import description file in a consistent
+# manner.
+#
+# To use this, create a gyp target with the following form:
+# {
+#   'target_name': 'my_proto_lib',
+#   'type': 'none',
+#   'sources': [
+#     'foo.imports',
+#     'bar.imports',
+#   ],
+#   'variables': {
+#     # Optional, see below: 'proto_in_dir': '.'
+#     'create_importlib': 'path-to-script',
+#     'lib_dir': 'path-to-output-directory',
+#   },
+#   'includes': ['path/to/this/gypi/file'],
+# }
+#
+# This will generate import libraries named 'foo.lib' and 'bar.lib' in the
+# specified lib directory.
+
+{
+  'variables': {
+    'create_importlib': '<(DEPTH)/build/win/importlibs/create_importlib_win.py',
+    'lib_dir': '<(PRODUCT_DIR)/lib',
+  },
+  'rules': [
+    {
+      'rule_name': 'create_import_lib',
+      'extension': 'imports',
+      'inputs': [
+        '<(create_importlib)',
+      ],
+      'outputs': [
+        '<(lib_dir)/<(RULE_INPUT_ROOT).lib',
+      ],
+      'action': [
+        'python',
+        '<(create_importlib)',
+        '--output-file', '<@(_outputs)',
+        '<(RULE_INPUT_PATH)',
+      ],
+      'message': 'Generating import library from <(RULE_INPUT_PATH)',
+      'process_outputs_as_sources': 0,
+    },
+  ],
+}
diff --git a/build/win/importlibs/create_importlib_win.py b/build/win/importlibs/create_importlib_win.py
new file mode 100755
index 0000000..bb6a2f0
--- /dev/null
+++ b/build/win/importlibs/create_importlib_win.py
@@ -0,0 +1,217 @@
+#!/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.
+#
+"""Creates an import library from an import description file."""
+import ast
+import logging
+import optparse
+import os
+import os.path
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+_USAGE = """\
+Usage: %prog [options] [imports-file]
+
+Creates an import library from imports-file.
+
+Note: this script uses the microsoft assembler (ml.exe) and the library tool
+    (lib.exe), both of which must be in path.
+"""
+
+
+_ASM_STUB_HEADER = """\
+; This file is autogenerated by create_importlib_win.py, do not edit.
+.386
+.MODEL FLAT, C
+.CODE
+
+; Stubs to provide mangled names to lib.exe for the
+; correct generation of import libs.
+"""
+
+
+_DEF_STUB_HEADER = """\
+; This file is autogenerated by create_importlib_win.py, do not edit.
+
+; Export declarations for generating import libs.
+"""
+
+
+_LOGGER = logging.getLogger()
+
+
+
+class _Error(Exception):
+  pass
+
+
+class _ImportLibraryGenerator(object):
+  def __init__(self, temp_dir):
+    self._temp_dir = temp_dir
+
+  def _Shell(self, cmd, **kw):
+    ret = subprocess.call(cmd, **kw)
+    _LOGGER.info('Running "%s" returned %d.', cmd, ret)
+    if ret != 0:
+      raise _Error('Command "%s" returned %d.' % (cmd, ret))
+
+  def _ReadImportsFile(self, imports_file):
+    # Slurp the imports file.
+    return ast.literal_eval(open(imports_file).read())
+
+  def _WriteStubsFile(self, import_names, output_file):
+    output_file.write(_ASM_STUB_HEADER)
+
+    for name in import_names:
+      output_file.write('%s PROC\n' % name)
+      output_file.write('%s ENDP\n' % name)
+
+    output_file.write('END\n')
+
+  def _WriteDefFile(self, dll_name, import_names, output_file):
+    output_file.write(_DEF_STUB_HEADER)
+    output_file.write('NAME %s\n' % dll_name)
+    output_file.write('EXPORTS\n')
+    for name in import_names:
+      name = name.split('@')[0]
+      output_file.write('  %s\n' % name)
+
+  def _CreateObj(self, dll_name, imports):
+    """Writes an assembly file containing empty declarations.
+
+    For each imported function of the form:
+
+    AddClipboardFormatListener@4 PROC
+    AddClipboardFormatListener@4 ENDP
+
+    The resulting object file is then supplied to lib.exe with a .def file
+    declaring the corresponding non-adorned exports as they appear on the
+    exporting DLL, e.g.
+
+    EXPORTS
+      AddClipboardFormatListener
+
+    In combination, the .def file and the .obj file cause lib.exe to generate
+    an x86 import lib with public symbols named like
+    "__imp__AddClipboardFormatListener@4", binding to exports named like
+    "AddClipboardFormatListener".
+
+    All of this is perpetrated in a temporary directory, as the intermediate
+    artifacts are quick and easy to produce, and of no interest to anyone
+    after the fact."""
+
+    # Create an .asm file to provide stdcall-like stub names to lib.exe.
+    asm_name = dll_name + '.asm'
+    _LOGGER.info('Writing asm file "%s".', asm_name)
+    with open(os.path.join(self._temp_dir, asm_name), 'wb') as stubs_file:
+      self._WriteStubsFile(imports, stubs_file)
+
+    # Invoke on the assembler to compile it to .obj.
+    obj_name = dll_name + '.obj'
+    cmdline = ['ml.exe', '/nologo', '/c', asm_name, '/Fo', obj_name]
+    self._Shell(cmdline, cwd=self._temp_dir, stdout=open(os.devnull))
+
+    return obj_name
+
+  def _CreateImportLib(self, dll_name, imports, architecture, output_file):
+    """Creates an import lib binding imports to dll_name for architecture.
+
+    On success, writes the import library to output file.
+    """
+    obj_file = None
+
+    # For x86 architecture we have to provide an object file for correct
+    # name mangling between the import stubs and the exported functions.
+    if architecture == 'x86':
+      obj_file = self._CreateObj(dll_name, imports)
+
+    # Create the corresponding .def file. This file has the non stdcall-adorned
+    # names, as exported by the destination DLL.
+    def_name = dll_name + '.def'
+    _LOGGER.info('Writing def file "%s".', def_name)
+    with open(os.path.join(self._temp_dir, def_name), 'wb') as def_file:
+      self._WriteDefFile(dll_name, imports, def_file)
+
+    # Invoke on lib.exe to create the import library.
+    # We generate everything into the temporary directory, as the .exp export
+    # files will be generated at the same path as the import library, and we
+    # don't want those files potentially gunking the works.
+    dll_base_name, ext = os.path.splitext(dll_name)
+    lib_name = dll_base_name + '.lib'
+    cmdline = ['lib.exe',
+               '/machine:%s' % architecture,
+               '/def:%s' % def_name,
+               '/out:%s' % lib_name]
+    if obj_file:
+      cmdline.append(obj_file)
+
+    self._Shell(cmdline, cwd=self._temp_dir, stdout=open(os.devnull))
+
+    # Copy the .lib file to the output directory.
+    shutil.copyfile(os.path.join(self._temp_dir, lib_name), output_file)
+    _LOGGER.info('Created "%s".', output_file)
+
+  def CreateImportLib(self, imports_file, output_file):
+    # Read the imports file.
+    imports = self._ReadImportsFile(imports_file)
+
+    # Creates the requested import library in the output directory.
+    self._CreateImportLib(imports['dll_name'],
+                          imports['imports'],
+                          imports.get('architecture', 'x86'),
+                          output_file)
+
+
+def main():
+  parser = optparse.OptionParser(usage=_USAGE)
+  parser.add_option('-o', '--output-file',
+                    help='Specifies the output file path.')
+  parser.add_option('-k', '--keep-temp-dir',
+                    action='store_true',
+                    help='Keep the temporary directory.')
+  parser.add_option('-v', '--verbose',
+                    action='store_true',
+                    help='Verbose logging.')
+
+  options, args = parser.parse_args()
+
+  if len(args) != 1:
+    parser.error('You must provide an imports file.')
+
+  if not options.output_file:
+    parser.error('You must provide an output file.')
+
+  options.output_file = os.path.abspath(options.output_file)
+
+  if options.verbose:
+    logging.basicConfig(level=logging.INFO)
+  else:
+    logging.basicConfig(level=logging.WARN)
+
+
+  temp_dir = tempfile.mkdtemp()
+  _LOGGER.info('Created temporary directory "%s."', temp_dir)
+  try:
+    # Create a generator and create the import lib.
+    generator = _ImportLibraryGenerator(temp_dir)
+
+    ret = generator.CreateImportLib(args[0], options.output_file)
+  except Exception, e:
+    _LOGGER.exception('Failed to create import lib.')
+    ret = 1
+  finally:
+    if not options.keep_temp_dir:
+      shutil.rmtree(temp_dir)
+      _LOGGER.info('Deleted temporary directory "%s."', temp_dir)
+
+  return ret
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/win/importlibs/filter_export_list.py b/build/win/importlibs/filter_export_list.py
new file mode 100755
index 0000000..c2489a9
--- /dev/null
+++ b/build/win/importlibs/filter_export_list.py
@@ -0,0 +1,85 @@
+#!/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.
+#
+"""Help maintaining DLL import lists."""
+import ast
+import optparse
+import re
+import sys
+
+
+_EXPORT_RE = re.compile(r"""
+  ^\s*(?P<ordinal>[0-9]+)  # The ordinal field.
+  \s+(?P<hint>[0-9A-F]+)   # The hint field.
+  \s(?P<rva>........)      # The RVA field.
+  \s+(?P<name>[^ ]+)       # And finally the name we're really after.
+""", re.VERBOSE)
+
+
+_USAGE = r"""\
+Usage: %prog [options] [master-file]
+
+This script filters a list of exports from a DLL, generated from something
+like the following command line:
+
+C:\> dumpbin /exports user32.dll
+
+against a master list of imports built from e.g.
+
+C:\> dumpbin /exports user32.lib
+
+The point of this is to trim non-public exports from the list, and to
+normalize the names to their stdcall-mangled form for the generation of
+import libraries.
+Note that the export names from the latter incanatation are stdcall-mangled,
+e.g. they are suffixed with "@" and the number of argument bytes to the
+function.
+"""
+
+def _ReadMasterFile(master_file):
+  # Slurp the master file.
+  with open(master_file) as f:
+    master_exports = ast.literal_eval(f.read())
+
+  master_mapping = {}
+  for export in master_exports:
+    name = export.split('@')[0]
+    master_mapping[name] = export
+
+  return master_mapping
+
+
+def main():
+  parser = optparse.OptionParser(usage=_USAGE)
+  parser.add_option('-r', '--reverse',
+                    action='store_true',
+                    help='Reverse the matching, e.g. return the functions '
+                         'in the master list that aren\'t in the input.')
+
+  options, args = parser.parse_args()
+  if len(args) != 1:
+    parser.error('Must provide a master file.')
+
+  master_mapping = _ReadMasterFile(args[0])
+
+  found_exports = []
+  for line in sys.stdin:
+    match = _EXPORT_RE.match(line)
+    if match:
+      export_name = master_mapping.get(match.group('name'), None)
+      if export_name:
+          found_exports.append(export_name)
+
+  if options.reverse:
+    # Invert the found_exports list.
+    found_exports = set(master_mapping.values()) - set(found_exports)
+
+  # Sort the found exports for tidy output.
+  print '\n'.join(sorted(found_exports))
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/win/importlibs/x86/user32.winxp.imports b/build/win/importlibs/x86/user32.winxp.imports
new file mode 100644
index 0000000..24403a8
--- /dev/null
+++ b/build/win/importlibs/x86/user32.winxp.imports
@@ -0,0 +1,670 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This file is used to create a custom import library for Chrome's use of
+# user32.dll exports. The set of exports defined below
+{
+  'architecture': 'x86',
+
+  # The DLL to bind to.
+  'dll_name': 'user32.dll',
+
+  # Name of the generated import library.
+  'importlib_name': 'user32.winxp.lib',
+
+  # This is the set of exports observed on a user32.dll from Windows XP SP2.
+  # The version of the DLL where these were observed is 5.1.2600.2180.
+  # Incidentally this set of exports also coincides with Windows XP SP3, where
+  # the version of the DLL is 5.1.2600.5512.
+  # Don't add new imports here unless and until the minimal supported
+  # Windows version has been bumped past Windows XP SP2+.
+  'imports': [
+    'ActivateKeyboardLayout@8',
+    'AdjustWindowRect@12',
+    'AdjustWindowRectEx@16',
+    'AllowSetForegroundWindow@4',
+    'AnimateWindow@12',
+    'AnyPopup@0',
+    'AppendMenuA@16',
+    'AppendMenuW@16',
+    'ArrangeIconicWindows@4',
+    'AttachThreadInput@12',
+    'BeginDeferWindowPos@4',
+    'BeginPaint@8',
+    'BlockInput@4',
+    'BringWindowToTop@4',
+    'BroadcastSystemMessage@20',
+    'BroadcastSystemMessageA@20',
+    'BroadcastSystemMessageExA@24',
+    'BroadcastSystemMessageExW@24',
+    'BroadcastSystemMessageW@20',
+    'CallMsgFilter@8',
+    'CallMsgFilterA@8',
+    'CallMsgFilterW@8',
+    'CallNextHookEx@16',
+    'CallWindowProcA@20',
+    'CallWindowProcW@20',
+    'CascadeChildWindows@8',
+    'CascadeWindows@20',
+    'ChangeClipboardChain@8',
+    'ChangeDisplaySettingsA@8',
+    'ChangeDisplaySettingsExA@20',
+    'ChangeDisplaySettingsExW@20',
+    'ChangeDisplaySettingsW@8',
+    'ChangeMenuA@20',
+    'ChangeMenuW@20',
+    'CharLowerA@4',
+    'CharLowerBuffA@8',
+    'CharLowerBuffW@8',
+    'CharLowerW@4',
+    'CharNextA@4',
+    'CharNextExA@12',
+    'CharNextW@4',
+    'CharPrevA@8',
+    'CharPrevExA@16',
+    'CharPrevW@8',
+    'CharToOemA@8',
+    'CharToOemBuffA@12',
+    'CharToOemBuffW@12',
+    'CharToOemW@8',
+    'CharUpperA@4',
+    'CharUpperBuffA@8',
+    'CharUpperBuffW@8',
+    'CharUpperW@4',
+    'CheckDlgButton@12',
+    'CheckMenuItem@12',
+    'CheckMenuRadioItem@20',
+    'CheckRadioButton@16',
+    'ChildWindowFromPoint@12',
+    'ChildWindowFromPointEx@16',
+    'ClientToScreen@8',
+    'ClipCursor@4',
+    'CloseClipboard@0',
+    'CloseDesktop@4',
+    'CloseWindow@4',
+    'CloseWindowStation@4',
+    'CopyAcceleratorTableA@12',
+    'CopyAcceleratorTableW@12',
+    'CopyIcon@4',
+    'CopyImage@20',
+    'CopyRect@8',
+    'CountClipboardFormats@0',
+    'CreateAcceleratorTableA@8',
+    'CreateAcceleratorTableW@8',
+    'CreateCaret@16',
+    'CreateCursor@28',
+    'CreateDesktopA@24',
+    'CreateDesktopW@24',
+    'CreateDialogIndirectParamA@20',
+    'CreateDialogIndirectParamW@20',
+    'CreateDialogParamA@20',
+    'CreateDialogParamW@20',
+    'CreateIcon@28',
+    'CreateIconFromResource@16',
+    'CreateIconFromResourceEx@28',
+    'CreateIconIndirect@4',
+    'CreateMDIWindowA@40',
+    'CreateMDIWindowW@40',
+    'CreateMenu@0',
+    'CreatePopupMenu@0',
+    'CreateWindowExA@48',
+    'CreateWindowExW@48',
+    'CreateWindowStationA@16',
+    'CreateWindowStationW@16',
+    'DdeAbandonTransaction@12',
+    'DdeAccessData@8',
+    'DdeAddData@16',
+    'DdeClientTransaction@32',
+    'DdeCmpStringHandles@8',
+    'DdeConnect@16',
+    'DdeConnectList@20',
+    'DdeCreateDataHandle@28',
+    'DdeCreateStringHandleA@12',
+    'DdeCreateStringHandleW@12',
+    'DdeDisconnect@4',
+    'DdeDisconnectList@4',
+    'DdeEnableCallback@12',
+    'DdeFreeDataHandle@4',
+    'DdeFreeStringHandle@8',
+    'DdeGetData@16',
+    'DdeGetLastError@4',
+    'DdeImpersonateClient@4',
+    'DdeInitializeA@16',
+    'DdeInitializeW@16',
+    'DdeKeepStringHandle@8',
+    'DdeNameService@16',
+    'DdePostAdvise@12',
+    'DdeQueryConvInfo@12',
+    'DdeQueryNextServer@8',
+    'DdeQueryStringA@20',
+    'DdeQueryStringW@20',
+    'DdeReconnect@4',
+    'DdeSetQualityOfService@12',
+    'DdeSetUserHandle@12',
+    'DdeUnaccessData@4',
+    'DdeUninitialize@4',
+    'DefDlgProcA@16',
+    'DefDlgProcW@16',
+    'DefFrameProcA@20',
+    'DefFrameProcW@20',
+    'DefMDIChildProcA@16',
+    'DefMDIChildProcW@16',
+    'DefRawInputProc@12',
+    'DefWindowProcA@16',
+    'DefWindowProcW@16',
+    'DeferWindowPos@32',
+    'DeleteMenu@12',
+    'DeregisterShellHookWindow@4',
+    'DestroyAcceleratorTable@4',
+    'DestroyCaret@0',
+    'DestroyCursor@4',
+    'DestroyIcon@4',
+    'DestroyMenu@4',
+    'DestroyWindow@4',
+    'DialogBoxIndirectParamA@20',
+    'DialogBoxIndirectParamW@20',
+    'DialogBoxParamA@20',
+    'DialogBoxParamW@20',
+    'DisableProcessWindowsGhosting@0',
+    'DispatchMessageA@4',
+    'DispatchMessageW@4',
+    'DlgDirListA@20',
+    'DlgDirListComboBoxA@20',
+    'DlgDirListComboBoxW@20',
+    'DlgDirListW@20',
+    'DlgDirSelectComboBoxExA@16',
+    'DlgDirSelectComboBoxExW@16',
+    'DlgDirSelectExA@16',
+    'DlgDirSelectExW@16',
+    'DragDetect@12',
+    'DragObject@20',
+    'DrawAnimatedRects@16',
+    'DrawCaption@16',
+    'DrawEdge@16',
+    'DrawFocusRect@8',
+    'DrawFrame@16',
+    'DrawFrameControl@16',
+    'DrawIcon@16',
+    'DrawIconEx@36',
+    'DrawMenuBar@4',
+    'DrawStateA@40',
+    'DrawStateW@40',
+    'DrawTextA@20',
+    'DrawTextExA@24',
+    'DrawTextExW@24',
+    'DrawTextW@20',
+    'EditWndProc@16',
+    'EmptyClipboard@0',
+    'EnableMenuItem@12',
+    'EnableScrollBar@12',
+    'EnableWindow@8',
+    'EndDeferWindowPos@4',
+    'EndDialog@8',
+    'EndMenu@0',
+    'EndPaint@8',
+    'EndTask@12',
+    'EnumChildWindows@12',
+    'EnumClipboardFormats@4',
+    'EnumDesktopWindows@12',
+    'EnumDesktopsA@12',
+    'EnumDesktopsW@12',
+    'EnumDisplayDevicesA@16',
+    'EnumDisplayDevicesW@16',
+    'EnumDisplayMonitors@16',
+    'EnumDisplaySettingsA@12',
+    'EnumDisplaySettingsExA@16',
+    'EnumDisplaySettingsExW@16',
+    'EnumDisplaySettingsW@12',
+    'EnumPropsA@8',
+    'EnumPropsExA@12',
+    'EnumPropsExW@12',
+    'EnumPropsW@8',
+    'EnumThreadWindows@12',
+    'EnumWindowStationsA@8',
+    'EnumWindowStationsW@8',
+    'EnumWindows@8',
+    'EqualRect@8',
+    'ExcludeUpdateRgn@8',
+    'ExitWindowsEx@8',
+    'FillRect@12',
+    'FindWindowA@8',
+    'FindWindowExA@16',
+    'FindWindowExW@16',
+    'FindWindowW@8',
+    'FlashWindow@8',
+    'FlashWindowEx@4',
+    'FrameRect@12',
+    'FreeDDElParam@8',
+    'GetActiveWindow@0',
+    'GetAltTabInfo@20',
+    'GetAltTabInfoA@20',
+    'GetAltTabInfoW@20',
+    'GetAncestor@8',
+    'GetAsyncKeyState@4',
+    'GetCapture@0',
+    'GetCaretBlinkTime@0',
+    'GetCaretPos@4',
+    'GetClassInfoA@12',
+    'GetClassInfoExA@12',
+    'GetClassInfoExW@12',
+    'GetClassInfoW@12',
+    'GetClassLongA@8',
+    'GetClassLongW@8',
+    'GetClassNameA@12',
+    'GetClassNameW@12',
+    'GetClassWord@8',
+    'GetClientRect@8',
+    'GetClipCursor@4',
+    'GetClipboardData@4',
+    'GetClipboardFormatNameA@12',
+    'GetClipboardFormatNameW@12',
+    'GetClipboardOwner@0',
+    'GetClipboardSequenceNumber@0',
+    'GetClipboardViewer@0',
+    'GetComboBoxInfo@8',
+    'GetCursor@0',
+    'GetCursorInfo@4',
+    'GetCursorPos@4',
+    'GetDC@4',
+    'GetDCEx@12',
+    'GetDesktopWindow@0',
+    'GetDialogBaseUnits@0',
+    'GetDlgCtrlID@4',
+    'GetDlgItem@8',
+    'GetDlgItemInt@16',
+    'GetDlgItemTextA@16',
+    'GetDlgItemTextW@16',
+    'GetDoubleClickTime@0',
+    'GetFocus@0',
+    'GetForegroundWindow@0',
+    'GetGUIThreadInfo@8',
+    'GetGuiResources@8',
+    'GetIconInfo@8',
+    'GetInputDesktop@0',
+    'GetInputState@0',
+    'GetKBCodePage@0',
+    'GetKeyNameTextA@12',
+    'GetKeyNameTextW@12',
+    'GetKeyState@4',
+    'GetKeyboardLayout@4',
+    'GetKeyboardLayoutList@8',
+    'GetKeyboardLayoutNameA@4',
+    'GetKeyboardLayoutNameW@4',
+    'GetKeyboardState@4',
+    'GetKeyboardType@4',
+    'GetLastActivePopup@4',
+    'GetLastInputInfo@4',
+    'GetLayeredWindowAttributes@16',
+    'GetListBoxInfo@4',
+    'GetMenu@4',
+    'GetMenuBarInfo@16',
+    'GetMenuCheckMarkDimensions@0',
+    'GetMenuContextHelpId@4',
+    'GetMenuDefaultItem@12',
+    'GetMenuInfo@8',
+    'GetMenuItemCount@4',
+    'GetMenuItemID@8',
+    'GetMenuItemInfoA@16',
+    'GetMenuItemInfoW@16',
+    'GetMenuItemRect@16',
+    'GetMenuState@12',
+    'GetMenuStringA@20',
+    'GetMenuStringW@20',
+    'GetMessageA@16',
+    'GetMessageExtraInfo@0',
+    'GetMessagePos@0',
+    'GetMessageTime@0',
+    'GetMessageW@16',
+    'GetMonitorInfoA@8',
+    'GetMonitorInfoW@8',
+    'GetMouseMovePointsEx@20',
+    'GetNextDlgGroupItem@12',
+    'GetNextDlgTabItem@12',
+    'GetOpenClipboardWindow@0',
+    'GetParent@4',
+    'GetPriorityClipboardFormat@8',
+    'GetProcessDefaultLayout@4',
+    'GetProcessWindowStation@0',
+    'GetPropA@8',
+    'GetPropW@8',
+    'GetQueueStatus@4',
+    'GetRawInputBuffer@12',
+    'GetRawInputData@20',
+    'GetRawInputDeviceInfoA@16',
+    'GetRawInputDeviceInfoW@16',
+    'GetRawInputDeviceList@12',
+    'GetRegisteredRawInputDevices@12',
+    'GetScrollBarInfo@12',
+    'GetScrollInfo@12',
+    'GetScrollPos@8',
+    'GetScrollRange@16',
+    'GetShellWindow@0',
+    'GetSubMenu@8',
+    'GetSysColor@4',
+    'GetSysColorBrush@4',
+    'GetSystemMenu@8',
+    'GetSystemMetrics@4',
+    'GetTabbedTextExtentA@20',
+    'GetTabbedTextExtentW@20',
+    'GetThreadDesktop@4',
+    'GetTitleBarInfo@8',
+    'GetTopWindow@4',
+    'GetUpdateRect@12',
+    'GetUpdateRgn@12',
+    'GetUserObjectInformationA@20',
+    'GetUserObjectInformationW@20',
+    'GetUserObjectSecurity@20',
+    'GetWindow@8',
+    'GetWindowContextHelpId@4',
+    'GetWindowDC@4',
+    'GetWindowInfo@8',
+    'GetWindowLongA@8',
+    'GetWindowLongW@8',
+    'GetWindowModuleFileName@12',
+    'GetWindowModuleFileNameA@12',
+    'GetWindowModuleFileNameW@12',
+    'GetWindowPlacement@8',
+    'GetWindowRect@8',
+    'GetWindowRgn@8',
+    'GetWindowRgnBox@8',
+    'GetWindowTextA@12',
+    'GetWindowTextLengthA@4',
+    'GetWindowTextLengthW@4',
+    'GetWindowTextW@12',
+    'GetWindowThreadProcessId@8',
+    'GetWindowWord@8',
+    'GrayStringA@36',
+    'GrayStringW@36',
+    'HideCaret@4',
+    'HiliteMenuItem@16',
+    'IMPGetIMEA@8',
+    'IMPGetIMEW@8',
+    'IMPQueryIMEA@4',
+    'IMPQueryIMEW@4',
+    'IMPSetIMEA@8',
+    'IMPSetIMEW@8',
+    'ImpersonateDdeClientWindow@8',
+    'InSendMessage@0',
+    'InSendMessageEx@4',
+    'InflateRect@12',
+    'InsertMenuA@20',
+    'InsertMenuItemA@16',
+    'InsertMenuItemW@16',
+    'InsertMenuW@20',
+    'InternalGetWindowText@12',
+    'IntersectRect@12',
+    'InvalidateRect@12',
+    'InvalidateRgn@12',
+    'InvertRect@8',
+    'IsCharAlphaA@4',
+    'IsCharAlphaNumericA@4',
+    'IsCharAlphaNumericW@4',
+    'IsCharAlphaW@4',
+    'IsCharLowerA@4',
+    'IsCharLowerW@4',
+    'IsCharUpperA@4',
+    'IsCharUpperW@4',
+    'IsChild@8',
+    'IsClipboardFormatAvailable@4',
+    'IsDialogMessage@8',
+    'IsDialogMessageA@8',
+    'IsDialogMessageW@8',
+    'IsDlgButtonChecked@8',
+    'IsGUIThread@4',
+    'IsHungAppWindow@4',
+    'IsIconic@4',
+    'IsMenu@4',
+    'IsRectEmpty@4',
+    'IsWinEventHookInstalled@4',
+    'IsWindow@4',
+    'IsWindowEnabled@4',
+    'IsWindowUnicode@4',
+    'IsWindowVisible@4',
+    'IsZoomed@4',
+    'KillTimer@8',
+    'LoadAcceleratorsA@8',
+    'LoadAcceleratorsW@8',
+    'LoadBitmapA@8',
+    'LoadBitmapW@8',
+    'LoadCursorA@8',
+    'LoadCursorFromFileA@4',
+    'LoadCursorFromFileW@4',
+    'LoadCursorW@8',
+    'LoadIconA@8',
+    'LoadIconW@8',
+    'LoadImageA@24',
+    'LoadImageW@24',
+    'LoadKeyboardLayoutA@8',
+    'LoadKeyboardLayoutW@8',
+    'LoadMenuA@8',
+    'LoadMenuIndirectA@4',
+    'LoadMenuIndirectW@4',
+    'LoadMenuW@8',
+    'LoadStringA@16',
+    'LoadStringW@16',
+    'LockSetForegroundWindow@4',
+    'LockWindowUpdate@4',
+    'LockWorkStation@0',
+    'LookupIconIdFromDirectory@8',
+    'LookupIconIdFromDirectoryEx@20',
+    'MapDialogRect@8',
+    'MapVirtualKeyA@8',
+    'MapVirtualKeyExA@12',
+    'MapVirtualKeyExW@12',
+    'MapVirtualKeyW@8',
+    'MapWindowPoints@16',
+    'MenuItemFromPoint@16',
+    'MessageBeep@4',
+    'MessageBoxA@16',
+    'MessageBoxExA@20',
+    'MessageBoxExW@20',
+    'MessageBoxIndirectA@4',
+    'MessageBoxIndirectW@4',
+    'MessageBoxTimeoutA@24',
+    'MessageBoxTimeoutW@24',
+    'MessageBoxW@16',
+    'ModifyMenuA@20',
+    'ModifyMenuW@20',
+    'MonitorFromPoint@12',
+    'MonitorFromRect@8',
+    'MonitorFromWindow@8',
+    'MoveWindow@24',
+    'MsgWaitForMultipleObjects@20',
+    'MsgWaitForMultipleObjectsEx@20',
+    'NotifyWinEvent@16',
+    'OemKeyScan@4',
+    'OemToCharA@8',
+    'OemToCharBuffA@12',
+    'OemToCharBuffW@12',
+    'OemToCharW@8',
+    'OffsetRect@12',
+    'OpenClipboard@4',
+    'OpenDesktopA@16',
+    'OpenDesktopW@16',
+    'OpenIcon@4',
+    'OpenInputDesktop@12',
+    'OpenWindowStationA@12',
+    'OpenWindowStationW@12',
+    'PackDDElParam@12',
+    'PaintDesktop@4',
+    'PeekMessageA@20',
+    'PeekMessageW@20',
+    'PostMessageA@16',
+    'PostMessageW@16',
+    'PostQuitMessage@4',
+    'PostThreadMessageA@16',
+    'PostThreadMessageW@16',
+    'PrintWindow@12',
+    'PrivateExtractIconsA@32',
+    'PrivateExtractIconsW@32',
+    'PtInRect@12',
+    'RealChildWindowFromPoint@12',
+    'RealGetWindowClass@12',
+    'RealGetWindowClassA@12',
+    'RealGetWindowClassW@12',
+    'RedrawWindow@16',
+    'RegisterClassA@4',
+    'RegisterClassExA@4',
+    'RegisterClassExW@4',
+    'RegisterClassW@4',
+    'RegisterClipboardFormatA@4',
+    'RegisterClipboardFormatW@4',
+    'RegisterDeviceNotificationA@12',
+    'RegisterDeviceNotificationW@12',
+    'RegisterHotKey@16',
+    'RegisterRawInputDevices@12',
+    'RegisterShellHookWindow@4',
+    'RegisterWindowMessageA@4',
+    'RegisterWindowMessageW@4',
+    'ReleaseCapture@0',
+    'ReleaseDC@8',
+    'RemoveMenu@12',
+    'RemovePropA@8',
+    'RemovePropW@8',
+    'ReplyMessage@4',
+    'ReuseDDElParam@20',
+    'ScreenToClient@8',
+    'ScrollDC@28',
+    'ScrollWindow@20',
+    'ScrollWindowEx@32',
+    'SendDlgItemMessageA@20',
+    'SendDlgItemMessageW@20',
+    'SendIMEMessageExA@8',
+    'SendIMEMessageExW@8',
+    'SendInput@12',
+    'SendMessageA@16',
+    'SendMessageCallbackA@24',
+    'SendMessageCallbackW@24',
+    'SendMessageTimeoutA@28',
+    'SendMessageTimeoutW@28',
+    'SendMessageW@16',
+    'SendNotifyMessageA@16',
+    'SendNotifyMessageW@16',
+    'SetActiveWindow@4',
+    'SetCapture@4',
+    'SetCaretBlinkTime@4',
+    'SetCaretPos@8',
+    'SetClassLongA@12',
+    'SetClassLongW@12',
+    'SetClassWord@12',
+    'SetClipboardData@8',
+    'SetClipboardViewer@4',
+    'SetCursor@4',
+    'SetCursorPos@8',
+    'SetDebugErrorLevel@4',
+    'SetDeskWallpaper@4',
+    'SetDlgItemInt@16',
+    'SetDlgItemTextA@12',
+    'SetDlgItemTextW@12',
+    'SetDoubleClickTime@4',
+    'SetFocus@4',
+    'SetForegroundWindow@4',
+    'SetKeyboardState@4',
+    'SetLastErrorEx@8',
+    'SetLayeredWindowAttributes@16',
+    'SetMenu@8',
+    'SetMenuContextHelpId@8',
+    'SetMenuDefaultItem@12',
+    'SetMenuInfo@8',
+    'SetMenuItemBitmaps@20',
+    'SetMenuItemInfoA@16',
+    'SetMenuItemInfoW@16',
+    'SetMessageExtraInfo@4',
+    'SetMessageQueue@4',
+    'SetParent@8',
+    'SetProcessDefaultLayout@4',
+    'SetProcessWindowStation@4',
+    'SetPropA@12',
+    'SetPropW@12',
+    'SetRect@20',
+    'SetRectEmpty@4',
+    'SetScrollInfo@16',
+    'SetScrollPos@16',
+    'SetScrollRange@20',
+    'SetShellWindow@4',
+    'SetSysColors@12',
+    'SetSystemCursor@8',
+    'SetThreadDesktop@4',
+    'SetTimer@16',
+    'SetUserObjectInformationA@16',
+    'SetUserObjectInformationW@16',
+    'SetUserObjectSecurity@12',
+    'SetWinEventHook@28',
+    'SetWindowContextHelpId@8',
+    'SetWindowLongA@12',
+    'SetWindowLongW@12',
+    'SetWindowPlacement@8',
+    'SetWindowPos@28',
+    'SetWindowRgn@12',
+    'SetWindowTextA@8',
+    'SetWindowTextW@8',
+    'SetWindowWord@12',
+    'SetWindowsHookA@8',
+    'SetWindowsHookExA@16',
+    'SetWindowsHookExW@16',
+    'SetWindowsHookW@8',
+    'ShowCaret@4',
+    'ShowCursor@4',
+    'ShowOwnedPopups@8',
+    'ShowScrollBar@12',
+    'ShowWindow@8',
+    'ShowWindowAsync@8',
+    'SubtractRect@12',
+    'SwapMouseButton@4',
+    'SwitchDesktop@4',
+    'SwitchToThisWindow@8',
+    'SystemParametersInfoA@16',
+    'SystemParametersInfoW@16',
+    'TabbedTextOutA@32',
+    'TabbedTextOutW@32',
+    'TileChildWindows@8',
+    'TileWindows@20',
+    'ToAscii@20',
+    'ToAsciiEx@24',
+    'ToUnicode@24',
+    'ToUnicodeEx@28',
+    'TrackMouseEvent@4',
+    'TrackPopupMenu@28',
+    'TrackPopupMenuEx@24',
+    'TranslateAccelerator@12',
+    'TranslateAcceleratorA@12',
+    'TranslateAcceleratorW@12',
+    'TranslateMDISysAccel@8',
+    'TranslateMessage@4',
+    'UnhookWinEvent@4',
+    'UnhookWindowsHook@8',
+    'UnhookWindowsHookEx@4',
+    'UnionRect@12',
+    'UnloadKeyboardLayout@4',
+    'UnpackDDElParam@16',
+    'UnregisterClassA@8',
+    'UnregisterClassW@8',
+    'UnregisterDeviceNotification@4',
+    'UnregisterHotKey@8',
+    'UpdateLayeredWindow@36',
+    'UpdateWindow@4',
+    'UserHandleGrantAccess@12',
+    'ValidateRect@8',
+    'ValidateRgn@8',
+    'VkKeyScanA@4',
+    'VkKeyScanExA@8',
+    'VkKeyScanExW@8',
+    'VkKeyScanW@4',
+    'WINNLSEnableIME@8',
+    'WINNLSGetEnableStatus@4',
+    'WINNLSGetIMEHotkey@4',
+    'WaitForInputIdle@8',
+    'WaitMessage@0',
+    'WinHelpA@16',
+    'WinHelpW@16',
+    'WindowFromDC@4',
+    'WindowFromPoint@8',
+    'keybd_event@16',
+    'mouse_event@20',
+    'wsprintfA',
+    'wsprintfW',
+    'wvsprintfA@12',
+    'wvsprintfW@12',
+  ]
+}
diff --git a/build/win/importlibs/x86/user32.winxp.lib b/build/win/importlibs/x86/user32.winxp.lib
new file mode 100644
index 0000000..deb5577
--- /dev/null
+++ b/build/win/importlibs/x86/user32.winxp.lib
Binary files differ
diff --git a/build/win/reorder-imports.py b/build/win/reorder-imports.py
new file mode 100755
index 0000000..281668f
--- /dev/null
+++ b/build/win/reorder-imports.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium 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 glob
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+
+def reorder_imports(input_dir, output_dir, architecture):
+  """Run swapimports.exe on the initial chrome.exe, and write to the output
+  directory. Also copy over any related files that might be needed
+  (pdbs, manifests etc.).
+  """
+
+  input_image = os.path.join(input_dir, 'chrome.exe')
+  output_image = os.path.join(output_dir, 'chrome.exe')
+
+  swap_exe = os.path.join(
+    __file__,
+    '..\\..\\..\\third_party\\syzygy\\binaries\\exe\\swapimport.exe')
+
+  args = [swap_exe, '--input-image=%s' % input_image,
+      '--output-image=%s' % output_image, '--overwrite', '--no-logo']
+
+  if architecture == 'x64':
+    args.append('--x64');
+
+  args.append('chrome_elf.dll');
+
+  subprocess.call(args)
+
+  for fname in glob.iglob(os.path.join(input_dir, 'chrome.exe.*')):
+    shutil.copy(fname, os.path.join(output_dir, os.path.basename(fname)))
+  return 0
+
+
+def main(argv):
+  usage = 'reorder_imports.py -i <input_dir> -o <output_dir> -a <target_arch>'
+  parser = optparse.OptionParser(usage=usage)
+  parser.add_option('-i', '--input', help='reorder chrome.exe in DIR',
+      metavar='DIR')
+  parser.add_option('-o', '--output', help='write new chrome.exe to DIR',
+      metavar='DIR')
+  parser.add_option('-a', '--arch', help='architecture of build (optional)',
+      default='ia32')
+  opts, args = parser.parse_args()
+
+  if not opts.input or not opts.output:
+    parser.error('Please provide and input and output directory')
+  return reorder_imports(opts.input, opts.output, opts.arch)
+
+if __name__ == "__main__":
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/win_is_xtree_patched.py b/build/win_is_xtree_patched.py
new file mode 100755
index 0000000..3f1994f
--- /dev/null
+++ b/build/win_is_xtree_patched.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Determines if the VS xtree header has been patched to disable C4702."""
+
+import os
+
+
+def IsPatched():
+  # TODO(scottmg): For now, just return if we're using the packaged toolchain
+  # script (because we know it's patched). Another case could be added here to
+  # query the active VS installation and actually check the contents of xtree.
+  # http://crbug.com/346399.
+  return int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1)) == 1
+
+
+def DoMain(_):
+  """Hook to be called from gyp without starting a separate python
+  interpreter."""
+  return "1" if IsPatched() else "0"
+
+
+if __name__ == '__main__':
+  print DoMain([])
diff --git a/build/win_precompile.gypi b/build/win_precompile.gypi
new file mode 100644
index 0000000..fb86076
--- /dev/null
+++ b/build/win_precompile.gypi
@@ -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 this file to make targets in your .gyp use the default
+# precompiled header on Windows, in debug builds only as the official
+# builders blow up (out of memory) if precompiled headers are used for
+# release builds.
+
+{
+  'conditions': [
+    ['OS=="win" and chromium_win_pch==1', {
+        'target_defaults': {
+          'msvs_precompiled_header': '<(DEPTH)/build/precompile.h',
+          'msvs_precompiled_source': '<(DEPTH)/build/precompile.cc',
+          'sources': ['<(DEPTH)/build/precompile.cc'],
+        }
+      }],
+  ],
+}
diff --git a/buildtools/linux64/clang-format.sha1 b/buildtools/linux64/clang-format.sha1
new file mode 100644
index 0000000..62900c4
--- /dev/null
+++ b/buildtools/linux64/clang-format.sha1
@@ -0,0 +1 @@
+7219213d084db0ea8eaed8f4291814f4f46fad3a
\ No newline at end of file
diff --git a/buildtools/linux64/gn.sha1 b/buildtools/linux64/gn.sha1
new file mode 100644
index 0000000..29e52ee
--- /dev/null
+++ b/buildtools/linux64/gn.sha1
@@ -0,0 +1 @@
+39479a14b49b6c592bc2781d6b99f2393ad30f1c
diff --git a/sandbox/BUILD.gn b/sandbox/BUILD.gn
new file mode 100644
index 0000000..15fb620
--- /dev/null
+++ b/sandbox/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Meta-target that forwards to the proper platform one.
+group("sandbox") {
+  if (is_win) {
+    deps = [
+      "//sandbox/win:sandbox",
+    ]
+  } else if (is_mac) {
+    # TODO(GYP): Make sandbox compile w/ 10.6 SDK.
+    if (false) {
+      deps = [
+        "//sandbox/mac:sandbox",
+      ]
+    }
+  } else if (is_linux || is_android) {
+    deps = [
+      "//sandbox/linux:sandbox",
+    ]
+  }
+}
diff --git a/sandbox/OWNERS b/sandbox/OWNERS
new file mode 100644
index 0000000..5d3f6ff
--- /dev/null
+++ b/sandbox/OWNERS
@@ -0,0 +1,3 @@
+cpu@chromium.org
+jln@chromium.org
+jschuh@chromium.org
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
new file mode 100644
index 0000000..8496685
--- /dev/null
+++ b/sandbox/linux/BUILD.gn
@@ -0,0 +1,368 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//testing/test.gni")
+
+declare_args() {
+  compile_suid_client = is_linux
+
+  compile_credentials = is_linux
+
+  compile_seccomp_bpf_demo =
+      is_linux && (current_cpu == "x86" || current_cpu == "x64")
+}
+
+# We have two principal targets: sandbox and sandbox_linux_unittests
+# All other targets are listed as dependencies.
+# There is one notable exception: for historical reasons, chrome_sandbox is
+# the setuid sandbox and is its own target.
+
+group("sandbox") {
+  deps = [
+    ":sandbox_services",
+  ]
+
+  if (compile_suid_client) {
+    deps += [ ":suid_sandbox_client" ]
+  }
+  if (use_seccomp_bpf) {
+    deps += [
+      ":seccomp_bpf",
+      ":seccomp_bpf_helpers",
+    ]
+  }
+}
+
+source_set("sandbox_linux_test_utils") {
+  testonly = true
+  sources = [
+    "tests/sandbox_test_runner.cc",
+    "tests/sandbox_test_runner.h",
+    "tests/sandbox_test_runner_function_pointer.cc",
+    "tests/sandbox_test_runner_function_pointer.h",
+    "tests/test_utils.cc",
+    "tests/test_utils.h",
+    "tests/unit_tests.cc",
+    "tests/unit_tests.h",
+  ]
+
+  deps = [
+    "//testing/gtest",
+  ]
+
+  if (use_seccomp_bpf) {
+    sources += [
+      "seccomp-bpf/bpf_tester_compatibility_delegate.h",
+      "seccomp-bpf/bpf_tests.h",
+      "seccomp-bpf/sandbox_bpf_test_runner.cc",
+      "seccomp-bpf/sandbox_bpf_test_runner.h",
+    ]
+    deps += [ ":seccomp_bpf" ]
+  }
+}
+
+# Sources shared by sandbox_linux_unittests and sandbox_linux_jni_unittests.
+source_set("sandbox_linux_unittests_sources") {
+  testonly = true
+
+  sources = [
+    "services/proc_util_unittest.cc",
+    "services/resource_limits_unittests.cc",
+    "services/scoped_process_unittest.cc",
+    "services/syscall_wrappers_unittest.cc",
+    "services/thread_helpers_unittests.cc",
+    "services/yama_unittests.cc",
+    "syscall_broker/broker_file_permission_unittest.cc",
+    "syscall_broker/broker_process_unittest.cc",
+    "tests/main.cc",
+    "tests/scoped_temporary_file.cc",
+    "tests/scoped_temporary_file.h",
+    "tests/scoped_temporary_file_unittest.cc",
+    "tests/test_utils_unittest.cc",
+    "tests/unit_tests_unittest.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    ":sandbox_linux_test_utils",
+    "//base",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+
+  if (is_linux) {
+    # Don't use this on Android.
+    libs = [ "rt" ]
+  }
+
+  if (compile_suid_client) {
+    sources += [
+      "suid/client/setuid_sandbox_client_unittest.cc",
+      "suid/client/setuid_sandbox_host_unittest.cc",
+    ]
+  }
+  if (use_seccomp_bpf) {
+    sources += [
+      "bpf_dsl/bpf_dsl_unittest.cc",
+      "bpf_dsl/codegen_unittest.cc",
+      "bpf_dsl/cons_unittest.cc",
+      "bpf_dsl/syscall_set_unittest.cc",
+      "integration_tests/bpf_dsl_seccomp_unittest.cc",
+      "integration_tests/seccomp_broker_process_unittest.cc",
+      "seccomp-bpf-helpers/baseline_policy_unittest.cc",
+      "seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc",
+      "seccomp-bpf/bpf_tests_unittest.cc",
+      "seccomp-bpf/errorcode_unittest.cc",
+      "seccomp-bpf/sandbox_bpf_unittest.cc",
+      "seccomp-bpf/syscall_unittest.cc",
+      "seccomp-bpf/trap_unittest.cc",
+    ]
+  }
+  if (compile_credentials) {
+    sources += [
+      "integration_tests/namespace_unix_domain_socket_unittest.cc",
+      "services/credentials_unittest.cc",
+      "services/namespace_sandbox_unittest.cc",
+      "services/namespace_utils_unittest.cc",
+    ]
+
+    # For credentials_unittest.cc
+    configs += [ "//build/config/linux:libcap" ]
+  }
+}
+
+# The main sandboxing test target.
+test("sandbox_linux_unittests") {
+  deps = [
+    ":sandbox_linux_unittests_sources",
+  ]
+}
+
+# This target is the shared library used by Android APK (i.e.
+# JNI-friendly) tests.
+shared_library("sandbox_linux_jni_unittests") {
+  testonly = true
+  deps = [
+    ":sandbox_linux_unittests_sources",
+  ]
+  if (is_android) {
+    deps += [ "//testing/android/native_test:native_test_native_code" ]
+  }
+}
+
+component("seccomp_bpf") {
+  sources = [
+    "bpf_dsl/bpf_dsl.cc",
+    "bpf_dsl/bpf_dsl.h",
+    "bpf_dsl/bpf_dsl_forward.h",
+    "bpf_dsl/bpf_dsl_impl.h",
+    "bpf_dsl/codegen.cc",
+    "bpf_dsl/codegen.h",
+    "bpf_dsl/cons.h",
+    "bpf_dsl/dump_bpf.cc",
+    "bpf_dsl/dump_bpf.h",
+    "bpf_dsl/linux_syscall_ranges.h",
+    "bpf_dsl/policy.cc",
+    "bpf_dsl/policy.h",
+    "bpf_dsl/policy_compiler.cc",
+    "bpf_dsl/policy_compiler.h",
+    "bpf_dsl/seccomp_macros.h",
+    "bpf_dsl/syscall_set.cc",
+    "bpf_dsl/syscall_set.h",
+    "bpf_dsl/trap_registry.h",
+    "bpf_dsl/verifier.cc",
+    "bpf_dsl/verifier.h",
+    "seccomp-bpf/die.cc",
+    "seccomp-bpf/die.h",
+    "seccomp-bpf/errorcode.cc",
+    "seccomp-bpf/errorcode.h",
+    "seccomp-bpf/sandbox_bpf.cc",
+    "seccomp-bpf/sandbox_bpf.h",
+    "seccomp-bpf/syscall.cc",
+    "seccomp-bpf/syscall.h",
+    "seccomp-bpf/trap.cc",
+    "seccomp-bpf/trap.h",
+  ]
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+  deps = [
+    ":sandbox_services",
+    ":sandbox_services_headers",
+    "//base",
+  ]
+}
+
+component("seccomp_bpf_helpers") {
+  sources = [
+    "seccomp-bpf-helpers/baseline_policy.cc",
+    "seccomp-bpf-helpers/baseline_policy.h",
+    "seccomp-bpf-helpers/sigsys_handlers.cc",
+    "seccomp-bpf-helpers/sigsys_handlers.h",
+    "seccomp-bpf-helpers/syscall_parameters_restrictions.cc",
+    "seccomp-bpf-helpers/syscall_parameters_restrictions.h",
+    "seccomp-bpf-helpers/syscall_sets.cc",
+    "seccomp-bpf-helpers/syscall_sets.h",
+  ]
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+    ":sandbox_services",
+    ":seccomp_bpf",
+  ]
+}
+
+if (is_linux) {
+  # The setuid sandbox for Linux.
+  executable("chrome_sandbox") {
+    sources = [
+      "suid/common/sandbox.h",
+      "suid/common/suid_unsafe_environment_variables.h",
+      "suid/process_util.h",
+      "suid/process_util_linux.c",
+      "suid/sandbox.c",
+    ]
+
+    cflags = [
+      # For ULLONG_MAX
+      "-std=gnu99",
+
+      # These files have a suspicious comparison.
+      # TODO fix this and re-enable this warning.
+      "-Wno-sign-compare",
+    ]
+  }
+}
+
+component("sandbox_services") {
+  sources = [
+    "services/init_process_reaper.cc",
+    "services/init_process_reaper.h",
+    "services/proc_util.cc",
+    "services/proc_util.h",
+    "services/resource_limits.cc",
+    "services/resource_limits.h",
+    "services/scoped_process.cc",
+    "services/scoped_process.h",
+    "services/syscall_wrappers.cc",
+    "services/syscall_wrappers.h",
+    "services/thread_helpers.cc",
+    "services/thread_helpers.h",
+    "services/yama.cc",
+    "services/yama.h",
+    "syscall_broker/broker_channel.cc",
+    "syscall_broker/broker_channel.h",
+    "syscall_broker/broker_client.cc",
+    "syscall_broker/broker_client.h",
+    "syscall_broker/broker_common.h",
+    "syscall_broker/broker_file_permission.cc",
+    "syscall_broker/broker_file_permission.h",
+    "syscall_broker/broker_host.cc",
+    "syscall_broker/broker_host.h",
+    "syscall_broker/broker_policy.cc",
+    "syscall_broker/broker_policy.h",
+    "syscall_broker/broker_process.cc",
+    "syscall_broker/broker_process.h",
+  ]
+
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+  ]
+
+  if (compile_credentials) {
+    sources += [
+      "services/credentials.cc",
+      "services/credentials.h",
+      "services/namespace_sandbox.cc",
+      "services/namespace_sandbox.h",
+      "services/namespace_utils.cc",
+      "services/namespace_utils.h",
+    ]
+
+    deps += [ ":sandbox_services_headers" ]
+  }
+}
+
+source_set("sandbox_services_headers") {
+  sources = [
+    "system_headers/arm64_linux_syscalls.h",
+    "system_headers/arm64_linux_ucontext.h",
+    "system_headers/arm_linux_syscalls.h",
+    "system_headers/arm_linux_ucontext.h",
+    "system_headers/i386_linux_ucontext.h",
+    "system_headers/linux_futex.h",
+    "system_headers/linux_seccomp.h",
+    "system_headers/linux_signal.h",
+    "system_headers/linux_syscalls.h",
+    "system_headers/linux_ucontext.h",
+    "system_headers/x86_32_linux_syscalls.h",
+    "system_headers/x86_64_linux_syscalls.h",
+  ]
+}
+
+# We make this its own target so that it does not interfere with our tests.
+source_set("libc_urandom_override") {
+  sources = [
+    "services/libc_urandom_override.cc",
+    "services/libc_urandom_override.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+if (compile_suid_client) {
+  component("suid_sandbox_client") {
+    sources = [
+      "suid/client/setuid_sandbox_client.cc",
+      "suid/client/setuid_sandbox_client.h",
+      "suid/client/setuid_sandbox_host.cc",
+      "suid/client/setuid_sandbox_host.h",
+      "suid/common/sandbox.h",
+      "suid/common/suid_unsafe_environment_variables.h",
+    ]
+    defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+    deps = [
+      ":sandbox_services",
+      "//base",
+    ]
+  }
+}
+
+if (is_android) {
+  # TODO(GYP) enable this. Needs an android_strip wrapper python script.
+  #action("sandbox_linux_unittests_stripped") {
+  #  script = "android_stip.py"
+  #
+  #  in_file = "$root_out_dir/sandbox_linux_unittests"
+  #
+  #  out_file = "$root_out_dir/sandbox_linux_unittests_stripped"
+  #  outputs = [ out_file ]
+  #
+  #  args = [
+  #    rebase_path(in_file, root_build_dir),
+  #    "-o", rebase_path(out_file, root_build_dir),
+  #  ]
+  #
+  #  deps = [
+  #    ":sandbox_linux_unittests",
+  #  ]
+  #}
+  # TODO(GYP) convert this.
+  #      {
+  #      'target_name': 'sandbox_linux_jni_unittests_apk',
+  #      'type': 'none',
+  #      'variables': {
+  #        'test_suite_name': 'sandbox_linux_jni_unittests',
+  #      },
+  #      'dependencies': [
+  #        'sandbox_linux_jni_unittests',
+  #      ],
+  #      'includes': [ '../../build/apk_test.gypi' ],
+  #      }
+}
diff --git a/sandbox/linux/DEPS b/sandbox/linux/DEPS
new file mode 100644
index 0000000..3912859
--- /dev/null
+++ b/sandbox/linux/DEPS
@@ -0,0 +1,25 @@
+include_rules = [
+  # First, exclude everything.
+  # Exclude a few dependencies that are included in the root DEPS and that we
+  # don't need.
+  # Sadly, there is no way to exclude all root DEPS since the root has no name.
+  "-ipc",
+  "-library_loaders",
+  "-third_party",
+  "-url",
+  # Make sure that each subdirectory has to declare its dependencies in
+  # sandbox/ explicitly.
+  "-sandbox/linux",
+
+  # Second, add what we want to allow.
+  # Anything included from sandbox/linux must be declared after this line or in
+  # a more specific DEPS file.
+  # base/, build/ and testing/ are already included in the global DEPS file,
+  # but be explicit.
+  "+base",
+  "+build",
+  "+testing",
+  "+sandbox/sandbox_export.h",
+  # Everyone can use tests/
+  "+sandbox/linux/tests",
+]
diff --git a/sandbox/linux/OWNERS b/sandbox/linux/OWNERS
new file mode 100644
index 0000000..f39e967
--- /dev/null
+++ b/sandbox/linux/OWNERS
@@ -0,0 +1,3 @@
+jln@chromium.org
+jorgelo@chromium.org
+mdempsky@chromium.org
diff --git a/sandbox/linux/bpf_dsl/DEPS b/sandbox/linux/bpf_dsl/DEPS
new file mode 100644
index 0000000..be37a12
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  # TODO(mdempsky): Eliminate cyclic dependency on seccomp-bpf.
+  "+sandbox/linux/seccomp-bpf",
+  "+sandbox/linux/system_headers",
+]
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.cc b/sandbox/linux/bpf_dsl/bpf_dsl.cc
new file mode 100644
index 0000000..3a35903
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/bpf_dsl.cc
@@ -0,0 +1,363 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+intptr_t BPFFailure(const struct arch_seccomp_data&, void* aux) {
+  SANDBOX_DIE(static_cast<char*>(aux));
+}
+
+class AllowResultExprImpl : public internal::ResultExprImpl {
+ public:
+  AllowResultExprImpl() {}
+
+  ErrorCode Compile(PolicyCompiler* pc) const override {
+    return ErrorCode(ErrorCode::ERR_ALLOWED);
+  }
+
+  bool IsAllow() const override { return true; }
+
+ private:
+  ~AllowResultExprImpl() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(AllowResultExprImpl);
+};
+
+class ErrorResultExprImpl : public internal::ResultExprImpl {
+ public:
+  explicit ErrorResultExprImpl(int err) : err_(err) {
+    CHECK(err_ >= ErrorCode::ERR_MIN_ERRNO && err_ <= ErrorCode::ERR_MAX_ERRNO);
+  }
+
+  ErrorCode Compile(PolicyCompiler* pc) const override {
+    return pc->Error(err_);
+  }
+
+  bool IsDeny() const override { return true; }
+
+ private:
+  ~ErrorResultExprImpl() override {}
+
+  int err_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrorResultExprImpl);
+};
+
+class TraceResultExprImpl : public internal::ResultExprImpl {
+ public:
+  TraceResultExprImpl(uint16_t aux) : aux_(aux) {}
+
+  ErrorCode Compile(PolicyCompiler* pc) const override {
+    return ErrorCode(ErrorCode::ERR_TRACE + aux_);
+  }
+
+ private:
+  ~TraceResultExprImpl() override {}
+
+  uint16_t aux_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceResultExprImpl);
+};
+
+class TrapResultExprImpl : public internal::ResultExprImpl {
+ public:
+  TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe)
+      : func_(func), arg_(arg), safe_(safe) {
+    DCHECK(func_);
+  }
+
+  ErrorCode Compile(PolicyCompiler* pc) const override {
+    return pc->Trap(func_, arg_, safe_);
+  }
+
+  bool HasUnsafeTraps() const override { return safe_ == false; }
+
+  bool IsDeny() const override { return true; }
+
+ private:
+  ~TrapResultExprImpl() override {}
+
+  TrapRegistry::TrapFnc func_;
+  const void* arg_;
+  bool safe_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl);
+};
+
+class IfThenResultExprImpl : public internal::ResultExprImpl {
+ public:
+  IfThenResultExprImpl(const BoolExpr& cond,
+                       const ResultExpr& then_result,
+                       const ResultExpr& else_result)
+      : cond_(cond), then_result_(then_result), else_result_(else_result) {}
+
+  ErrorCode Compile(PolicyCompiler* pc) const override {
+    return cond_->Compile(
+        pc, then_result_->Compile(pc), else_result_->Compile(pc));
+  }
+
+  bool HasUnsafeTraps() const override {
+    return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
+  }
+
+ private:
+  ~IfThenResultExprImpl() override {}
+
+  BoolExpr cond_;
+  ResultExpr then_result_;
+  ResultExpr else_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl);
+};
+
+class ConstBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  ConstBoolExprImpl(bool value) : value_(value) {}
+
+  ErrorCode Compile(PolicyCompiler* pc,
+                    ErrorCode true_ec,
+                    ErrorCode false_ec) const override {
+    return value_ ? true_ec : false_ec;
+  }
+
+ private:
+  ~ConstBoolExprImpl() override {}
+
+  bool value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
+};
+
+class PrimitiveBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  PrimitiveBoolExprImpl(int argno,
+                        ErrorCode::ArgType is_32bit,
+                        uint64_t mask,
+                        uint64_t value)
+      : argno_(argno), is_32bit_(is_32bit), mask_(mask), value_(value) {}
+
+  ErrorCode Compile(PolicyCompiler* pc,
+                    ErrorCode true_ec,
+                    ErrorCode false_ec) const override {
+    return pc->CondMaskedEqual(
+        argno_, is_32bit_, mask_, value_, true_ec, false_ec);
+  }
+
+ private:
+  ~PrimitiveBoolExprImpl() override {}
+
+  int argno_;
+  ErrorCode::ArgType is_32bit_;
+  uint64_t mask_;
+  uint64_t value_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrimitiveBoolExprImpl);
+};
+
+class NegateBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  explicit NegateBoolExprImpl(const BoolExpr& cond) : cond_(cond) {}
+
+  ErrorCode Compile(PolicyCompiler* pc,
+                    ErrorCode true_ec,
+                    ErrorCode false_ec) const override {
+    return cond_->Compile(pc, false_ec, true_ec);
+  }
+
+ private:
+  ~NegateBoolExprImpl() override {}
+
+  BoolExpr cond_;
+
+  DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
+};
+
+class AndBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  AndBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs)
+      : lhs_(lhs), rhs_(rhs) {}
+
+  ErrorCode Compile(PolicyCompiler* pc,
+                    ErrorCode true_ec,
+                    ErrorCode false_ec) const override {
+    return lhs_->Compile(pc, rhs_->Compile(pc, true_ec, false_ec), false_ec);
+  }
+
+ private:
+  ~AndBoolExprImpl() override {}
+
+  BoolExpr lhs_;
+  BoolExpr rhs_;
+
+  DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl);
+};
+
+class OrBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  OrBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs)
+      : lhs_(lhs), rhs_(rhs) {}
+
+  ErrorCode Compile(PolicyCompiler* pc,
+                    ErrorCode true_ec,
+                    ErrorCode false_ec) const override {
+    return lhs_->Compile(pc, true_ec, rhs_->Compile(pc, true_ec, false_ec));
+  }
+
+ private:
+  ~OrBoolExprImpl() override {}
+
+  BoolExpr lhs_;
+  BoolExpr rhs_;
+
+  DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl);
+};
+
+}  // namespace
+
+namespace internal {
+
+bool ResultExprImpl::HasUnsafeTraps() const {
+  return false;
+}
+
+bool ResultExprImpl::IsAllow() const {
+  return false;
+}
+
+bool ResultExprImpl::IsDeny() const {
+  return false;
+}
+
+uint64_t DefaultMask(size_t size) {
+  switch (size) {
+    case 4:
+      return std::numeric_limits<uint32_t>::max();
+    case 8:
+      return std::numeric_limits<uint64_t>::max();
+    default:
+      CHECK(false) << "Unimplemented DefaultMask case";
+      return 0;
+  }
+}
+
+BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) {
+  CHECK(size == 4 || size == 8);
+
+  // TODO(mdempsky): Should we just always use TP_64BIT?
+  const ErrorCode::ArgType arg_type =
+      (size == 4) ? ErrorCode::TP_32BIT : ErrorCode::TP_64BIT;
+
+  return BoolExpr(new const PrimitiveBoolExprImpl(num, arg_type, mask, val));
+}
+
+}  // namespace internal
+
+ResultExpr Allow() {
+  return ResultExpr(new const AllowResultExprImpl());
+}
+
+ResultExpr Error(int err) {
+  return ResultExpr(new const ErrorResultExprImpl(err));
+}
+
+ResultExpr Kill(const char* msg) {
+  return Trap(BPFFailure, msg);
+}
+
+ResultExpr Trace(uint16_t aux) {
+  return ResultExpr(new const TraceResultExprImpl(aux));
+}
+
+ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+  return ResultExpr(
+      new const TrapResultExprImpl(trap_func, aux, true /* safe */));
+}
+
+ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+  return ResultExpr(
+      new const TrapResultExprImpl(trap_func, aux, false /* unsafe */));
+}
+
+BoolExpr BoolConst(bool value) {
+  return BoolExpr(new const ConstBoolExprImpl(value));
+}
+
+BoolExpr operator!(const BoolExpr& cond) {
+  return BoolExpr(new const NegateBoolExprImpl(cond));
+}
+
+BoolExpr operator&&(const BoolExpr& lhs, const BoolExpr& rhs) {
+  return BoolExpr(new const AndBoolExprImpl(lhs, rhs));
+}
+
+BoolExpr operator||(const BoolExpr& lhs, const BoolExpr& rhs) {
+  return BoolExpr(new const OrBoolExprImpl(lhs, rhs));
+}
+
+Elser If(const BoolExpr& cond, const ResultExpr& then_result) {
+  return Elser(nullptr).ElseIf(cond, then_result);
+}
+
+Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
+}
+
+Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
+}
+
+Elser::~Elser() {
+}
+
+Elser Elser::ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const {
+  return Elser(Cons(std::make_pair(cond, then_result), clause_list_));
+}
+
+ResultExpr Elser::Else(const ResultExpr& else_result) const {
+  // We finally have the default result expression for this
+  // if/then/else sequence.  Also, we've already accumulated all
+  // if/then pairs into a list of reverse order (i.e., lower priority
+  // conditions are listed before higher priority ones).  E.g., an
+  // expression like
+  //
+  //    If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4)
+  //
+  // will have built up a list like
+  //
+  //    [(b3, e3), (b2, e2), (b1, e1)].
+  //
+  // Now that we have e4, we can walk the list and create a ResultExpr
+  // tree like:
+  //
+  //    expr = e4
+  //    expr = (b3 ? e3 : expr) = (b3 ? e3 : e4)
+  //    expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4))
+  //    expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4)))
+  //
+  // and end up with an appropriately chained tree.
+
+  ResultExpr expr = else_result;
+  for (const Clause& clause : clause_list_) {
+    expr = ResultExpr(
+        new const IfThenResultExprImpl(clause.first, clause.second, expr));
+  }
+  return expr;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+template class scoped_refptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+template class scoped_refptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl.h b/sandbox/linux/bpf_dsl/bpf_dsl.h
new file mode 100644
index 0000000..365e9b5
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/bpf_dsl.h
@@ -0,0 +1,317 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/cons.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/sandbox_export.h"
+
+// The sandbox::bpf_dsl namespace provides a domain-specific language
+// to make writing BPF policies more expressive.  In general, the
+// object types all have value semantics (i.e., they can be copied
+// around, returned from or passed to function calls, etc. without any
+// surprising side effects), though not all support assignment.
+//
+// An idiomatic and demonstrative (albeit silly) example of this API
+// would be:
+//
+//      #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+//
+//      using namespace sandbox::bpf_dsl;
+//
+//      class SillyPolicy : public Policy {
+//       public:
+//        SillyPolicy() {}
+//        ~SillyPolicy() override {}
+//        ResultExpr EvaluateSyscall(int sysno) const override {
+//          if (sysno == __NR_fcntl) {
+//            Arg<int> fd(0), cmd(1);
+//            Arg<unsigned long> flags(2);
+//            const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
+//            return If(fd == 0 && cmd == F_SETFL && (flags & ~kGoodFlags) == 0,
+//                      Allow())
+//                .ElseIf(cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC,
+//                        Error(EMFILE))
+//                .Else(Trap(SetFlagHandler, NULL));
+//          } else {
+//            return Allow();
+//          }
+//        }
+//
+//       private:
+//        DISALLOW_COPY_AND_ASSIGN(SillyPolicy);
+//      };
+//
+// More generally, the DSL currently supports the following grammar:
+//
+//   result = Allow() | Error(errno) | Kill(msg) | Trace(aux)
+//          | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux)
+//          | If(bool, result)[.ElseIf(bool, result)].Else(result)
+//          | Switch(arg)[.Case(val, result)].Default(result)
+//   bool   = BoolConst(boolean) | !bool | bool && bool | bool || bool
+//          | arg == val | arg != val
+//   arg    = Arg<T>(num) | arg & mask
+//
+// The semantics of each function and operator are intended to be
+// intuitive, but are described in more detail below.
+//
+// (Credit to Sean Parent's "Inheritance is the Base Class of Evil"
+// talk at Going Native 2013 for promoting value semantics via shared
+// pointers to immutable state.)
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// ResultExpr is an opaque reference to an immutable result expression tree.
+typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr;
+
+// BoolExpr is an opaque reference to an immutable boolean expression tree.
+typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr;
+
+// Allow specifies a result that the system call should be allowed to
+// execute normally.
+SANDBOX_EXPORT ResultExpr Allow();
+
+// Error specifies a result that the system call should fail with
+// error number |err|.  As a special case, Error(0) will result in the
+// system call appearing to have succeeded, but without having any
+// side effects.
+SANDBOX_EXPORT ResultExpr Error(int err);
+
+// Kill specifies a result to kill the program and print an error message.
+SANDBOX_EXPORT ResultExpr Kill(const char* msg);
+
+// Trace specifies a result to notify a tracing process via the
+// PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call.
+// The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG.
+SANDBOX_EXPORT ResultExpr Trace(uint16_t aux);
+
+// Trap specifies a result that the system call should be handled by
+// trapping back into userspace and invoking |trap_func|, passing
+// |aux| as the second parameter.
+SANDBOX_EXPORT ResultExpr
+    Trap(TrapRegistry::TrapFnc trap_func, const void* aux);
+
+// UnsafeTrap is like Trap, except the policy is marked as "unsafe"
+// and allowed to use SandboxSyscall to invoke any system call.
+//
+// NOTE: This feature, by definition, disables all security features of
+//   the sandbox. It should never be used in production, but it can be
+//   very useful to diagnose code that is incompatible with the sandbox.
+//   If even a single system call returns "UnsafeTrap", the security of
+//   entire sandbox should be considered compromised.
+SANDBOX_EXPORT ResultExpr
+    UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux);
+
+// BoolConst converts a bool value into a BoolExpr.
+SANDBOX_EXPORT BoolExpr BoolConst(bool value);
+
+// Various ways to combine boolean expressions into more complex expressions.
+// They follow standard boolean algebra laws.
+SANDBOX_EXPORT BoolExpr operator!(const BoolExpr& cond);
+SANDBOX_EXPORT BoolExpr operator&&(const BoolExpr& lhs, const BoolExpr& rhs);
+SANDBOX_EXPORT BoolExpr operator||(const BoolExpr& lhs, const BoolExpr& rhs);
+
+template <typename T>
+class SANDBOX_EXPORT Arg {
+ public:
+  // Initializes the Arg to represent the |num|th system call
+  // argument (indexed from 0), which is of type |T|.
+  explicit Arg(int num);
+
+  Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {}
+
+  // Returns an Arg representing the current argument, but after
+  // bitwise-and'ing it with |rhs|.
+  friend Arg operator&(const Arg& lhs, uint64_t rhs) {
+    return Arg(lhs.num_, lhs.mask_ & rhs);
+  }
+
+  // Returns a boolean expression comparing whether the system call argument
+  // (after applying any bitmasks, if appropriate) equals |rhs|.
+  friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); }
+
+  // Returns a boolean expression comparing whether the system call argument
+  // (after applying any bitmasks, if appropriate) does not equal |rhs|.
+  friend BoolExpr operator!=(const Arg& lhs, T rhs) { return !(lhs == rhs); }
+
+ private:
+  Arg(int num, uint64_t mask) : num_(num), mask_(mask) {}
+
+  BoolExpr EqualTo(T val) const;
+
+  int num_;
+  uint64_t mask_;
+
+  DISALLOW_ASSIGN(Arg);
+};
+
+// If begins a conditional result expression predicated on the
+// specified boolean expression.
+SANDBOX_EXPORT Elser If(const BoolExpr& cond, const ResultExpr& then_result);
+
+class SANDBOX_EXPORT Elser {
+ public:
+  Elser(const Elser& elser);
+  ~Elser();
+
+  // ElseIf extends the conditional result expression with another
+  // "if then" clause, predicated on the specified boolean expression.
+  Elser ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const;
+
+  // Else terminates a conditional result expression using |else_result| as
+  // the default fallback result expression.
+  ResultExpr Else(const ResultExpr& else_result) const;
+
+ private:
+  typedef std::pair<BoolExpr, ResultExpr> Clause;
+
+  explicit Elser(cons::List<Clause> clause_list);
+
+  cons::List<Clause> clause_list_;
+
+  friend Elser If(const BoolExpr&, const ResultExpr&);
+  template <typename T>
+  friend Caser<T> Switch(const Arg<T>&);
+  DISALLOW_ASSIGN(Elser);
+};
+
+// Switch begins a switch expression dispatched according to the
+// specified argument value.
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg);
+
+template <typename T>
+class SANDBOX_EXPORT Caser {
+ public:
+  Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {}
+  ~Caser() {}
+
+  // Case adds a single-value "case" clause to the switch.
+  Caser<T> Case(T value, ResultExpr result) const;
+
+  // Cases adds a multiple-value "case" clause to the switch.
+  // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way
+  // of using this function.
+  Caser<T> Cases(const std::vector<T>& values, ResultExpr result) const;
+
+  // Terminate the switch with a "default" clause.
+  ResultExpr Default(ResultExpr result) const;
+
+ private:
+  Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {}
+
+  Arg<T> arg_;
+  Elser elser_;
+
+  template <typename U>
+  friend Caser<U> Switch(const Arg<U>&);
+  DISALLOW_ASSIGN(Caser);
+};
+
+// Recommended usage is to put
+//    #define CASES SANDBOX_BPF_DSL_CASES
+// near the top of the .cc file (e.g., nearby any "using" statements), then
+// use like:
+//    Switch(arg).CASES((3, 5, 7), result)...;
+#define SANDBOX_BPF_DSL_CASES(values, result) \
+  Cases(SANDBOX_BPF_DSL_CASES_HELPER values, result)
+
+// Helper macro to construct a std::vector from an initializer list.
+// TODO(mdempsky): Convert to use C++11 initializer lists instead.
+#define SANDBOX_BPF_DSL_CASES_HELPER(value, ...)                           \
+  ({                                                                       \
+    const __typeof__(value) bpf_dsl_cases_values[] = {value, __VA_ARGS__}; \
+    std::vector<__typeof__(value)>(                                        \
+        bpf_dsl_cases_values,                                              \
+        bpf_dsl_cases_values + arraysize(bpf_dsl_cases_values));           \
+  })
+
+// =====================================================================
+// Official API ends here.
+// =====================================================================
+
+namespace internal {
+
+// Make argument-dependent lookup work.  This is necessary because although
+// BoolExpr is defined in bpf_dsl, since it's merely a typedef for
+// scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only
+// searches the "internal" nested namespace.
+using bpf_dsl::operator!;
+using bpf_dsl::operator||;
+using bpf_dsl::operator&&;
+
+// Returns a boolean expression that represents whether system call
+// argument |num| of size |size| is equal to |val|, when masked
+// according to |mask|.  Users should use the Arg template class below
+// instead of using this API directly.
+SANDBOX_EXPORT BoolExpr
+    ArgEq(int num, size_t size, uint64_t mask, uint64_t val);
+
+// Returns the default mask for a system call argument of the specified size.
+SANDBOX_EXPORT uint64_t DefaultMask(size_t size);
+
+}  // namespace internal
+
+template <typename T>
+Arg<T>::Arg(int num)
+    : num_(num), mask_(internal::DefaultMask(sizeof(T))) {
+}
+
+// Definition requires ArgEq to have been declared.  Moved out-of-line
+// to minimize how much internal clutter users have to ignore while
+// reading the header documentation.
+//
+// Additionally, we use this helper member function to avoid linker errors
+// caused by defining operator== out-of-line.  For a more detailed explanation,
+// see http://www.parashift.com/c++-faq-lite/template-friends.html.
+template <typename T>
+BoolExpr Arg<T>::EqualTo(T val) const {
+  return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
+}
+
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) {
+  return Caser<T>(arg, Elser(nullptr));
+}
+
+template <typename T>
+Caser<T> Caser<T>::Case(T value, ResultExpr result) const {
+  return SANDBOX_BPF_DSL_CASES((value), result);
+}
+
+template <typename T>
+Caser<T> Caser<T>::Cases(const std::vector<T>& values,
+                         ResultExpr result) const {
+  // Theoretically we could evaluate arg_ just once and emit a more efficient
+  // dispatch table, but for now we simply translate into an equivalent
+  // If/ElseIf/Else chain.
+
+  typedef typename std::vector<T>::const_iterator Iter;
+  BoolExpr test = BoolConst(false);
+  for (Iter i = values.begin(), end = values.end(); i != end; ++i) {
+    test = test || (arg_ == *i);
+  }
+  return Caser<T>(arg_, elser_.ElseIf(test, result));
+}
+
+template <typename T>
+ResultExpr Caser<T>::Default(ResultExpr result) const {
+  return elser_.Else(result);
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_forward.h b/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
new file mode 100644
index 0000000..1830389
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
+
+#include "base/memory/ref_counted.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// The bpf_dsl_forward.h header provides forward declarations for the
+// types defined in bpf_dsl.h. It's intended for use in user headers
+// that need to reference bpf_dsl types, but don't require definitions.
+
+namespace internal {
+class ResultExprImpl;
+class BoolExprImpl;
+}
+
+typedef scoped_refptr<const internal::ResultExprImpl> ResultExpr;
+typedef scoped_refptr<const internal::BoolExprImpl> BoolExpr;
+
+template <typename T>
+class Arg;
+
+class Elser;
+
+template <typename T>
+class Caser;
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+extern template class SANDBOX_EXPORT
+    scoped_refptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+extern template class SANDBOX_EXPORT
+    scoped_refptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
+
+#endif  // SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_impl.h b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
new file mode 100644
index 0000000..2ffaf79
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+class ErrorCode;
+
+namespace bpf_dsl {
+class PolicyCompiler;
+
+namespace internal {
+
+// Internal interface implemented by BoolExpr implementations.
+class BoolExprImpl : public base::RefCounted<BoolExprImpl> {
+ public:
+  // Compile uses |pc| to construct an ErrorCode that conditionally continues
+  // to either |true_ec| or |false_ec|, depending on whether the represented
+  // boolean expression is true or false.
+  virtual ErrorCode Compile(PolicyCompiler* pc,
+                            ErrorCode true_ec,
+                            ErrorCode false_ec) const = 0;
+
+ protected:
+  BoolExprImpl() {}
+  virtual ~BoolExprImpl() {}
+
+ private:
+  friend class base::RefCounted<BoolExprImpl>;
+  DISALLOW_COPY_AND_ASSIGN(BoolExprImpl);
+};
+
+// Internal interface implemented by ResultExpr implementations.
+class ResultExprImpl : public base::RefCounted<ResultExprImpl> {
+ public:
+  // Compile uses |pc| to construct an ErrorCode analogous to the represented
+  // result expression.
+  virtual ErrorCode Compile(PolicyCompiler* pc) const = 0;
+
+  // HasUnsafeTraps returns whether the result expression is or recursively
+  // contains an unsafe trap expression.
+  virtual bool HasUnsafeTraps() const;
+
+  // IsAllow returns whether the result expression is an "allow" result.
+  virtual bool IsAllow() const;
+
+  // IsAllow returns whether the result expression is a "deny" result.
+  virtual bool IsDeny() const;
+
+ protected:
+  ResultExprImpl() {}
+  virtual ~ResultExprImpl() {}
+
+ private:
+  friend class base::RefCounted<ResultExprImpl>;
+  DISALLOW_COPY_AND_ASSIGN(ResultExprImpl);
+};
+
+}  // namespace internal
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
new file mode 100644
index 0000000..398ec59
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
@@ -0,0 +1,486 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include <map>
+#include <utility>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/bpf_dsl/verifier.h"
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define CASES SANDBOX_BPF_DSL_CASES
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+// Helper function to construct fake arch_seccomp_data objects.
+struct arch_seccomp_data FakeSyscall(int nr,
+                                     uint64_t p0 = 0,
+                                     uint64_t p1 = 0,
+                                     uint64_t p2 = 0,
+                                     uint64_t p3 = 0,
+                                     uint64_t p4 = 0,
+                                     uint64_t p5 = 0) {
+  // Made up program counter for syscall address.
+  const uint64_t kFakePC = 0x543210;
+
+  struct arch_seccomp_data data = {
+      nr,
+      SECCOMP_ARCH,
+      kFakePC,
+      {
+       p0, p1, p2, p3, p4, p5,
+      },
+  };
+
+  return data;
+}
+
+class FakeTrapRegistry : public TrapRegistry {
+ public:
+  FakeTrapRegistry() : map_() {}
+  virtual ~FakeTrapRegistry() {}
+
+  uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override {
+    EXPECT_TRUE(safe);
+
+    const uint16_t next_id = map_.size() + 1;
+    return map_.insert(std::make_pair(Key(fnc, aux), next_id)).first->second;
+  }
+
+  bool EnableUnsafeTraps() override {
+    ADD_FAILURE() << "Unimplemented";
+    return false;
+  }
+
+ private:
+  using Key = std::pair<TrapFnc, const void*>;
+
+  std::map<Key, uint16_t> map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeTrapRegistry);
+};
+
+intptr_t FakeTrapFuncOne(const arch_seccomp_data& data, void* aux) { return 1; }
+intptr_t FakeTrapFuncTwo(const arch_seccomp_data& data, void* aux) { return 2; }
+
+// Test that FakeTrapRegistry correctly assigns trap IDs to trap handlers.
+TEST(FakeTrapRegistry, TrapIDs) {
+  struct {
+    TrapRegistry::TrapFnc fnc;
+    const void* aux;
+  } funcs[] = {
+      {FakeTrapFuncOne, nullptr},
+      {FakeTrapFuncTwo, nullptr},
+      {FakeTrapFuncOne, funcs},
+      {FakeTrapFuncTwo, funcs},
+  };
+
+  FakeTrapRegistry traps;
+
+  // Add traps twice to test that IDs are reused correctly.
+  for (int i = 0; i < 2; ++i) {
+    for (size_t j = 0; j < arraysize(funcs); ++j) {
+      // Trap IDs start at 1.
+      EXPECT_EQ(j + 1, traps.Add(funcs[j].fnc, funcs[j].aux, true));
+    }
+  }
+}
+
+class PolicyEmulator {
+ public:
+  explicit PolicyEmulator(const Policy* policy) : program_(), traps_() {
+    program_ = *PolicyCompiler(policy, &traps_).Compile(true /* verify */);
+  }
+  ~PolicyEmulator() {}
+
+  uint32_t Emulate(const struct arch_seccomp_data& data) const {
+    const char* err = nullptr;
+    uint32_t res = Verifier::EvaluateBPF(program_, data, &err);
+    if (err) {
+      ADD_FAILURE() << err;
+      return 0;
+    }
+    return res;
+  }
+
+  void ExpectAllow(const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_ALLOW, Emulate(data));
+  }
+
+  void ExpectErrno(uint16_t err, const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_ERRNO | err, Emulate(data));
+  }
+
+ private:
+  CodeGen::Program program_;
+  FakeTrapRegistry traps_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyEmulator);
+};
+
+class BasicPolicy : public Policy {
+ public:
+  BasicPolicy() {}
+  ~BasicPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_getpgid) {
+      const Arg<pid_t> pid(0);
+      return If(pid == 0, Error(EPERM)).Else(Error(EINVAL));
+    }
+    if (sysno == __NR_setuid) {
+      const Arg<uid_t> uid(0);
+      return If(uid != 42, Error(ESRCH)).Else(Error(ENOMEM));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicPolicy);
+};
+
+TEST(BPFDSL, Basic) {
+  BasicPolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_getpgid, 0));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_getpgid, 1));
+
+  emulator.ExpectErrno(ENOMEM, FakeSyscall(__NR_setuid, 42));
+  emulator.ExpectErrno(ESRCH, FakeSyscall(__NR_setuid, 43));
+}
+
+/* On IA-32, socketpair() is implemented via socketcall(). :-( */
+#if !defined(ARCH_CPU_X86)
+class BooleanLogicPolicy : public Policy {
+ public:
+  BooleanLogicPolicy() {}
+  ~BooleanLogicPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_socketpair) {
+      const Arg<int> domain(0), type(1), protocol(2);
+      return If(domain == AF_UNIX &&
+                    (type == SOCK_STREAM || type == SOCK_DGRAM) &&
+                    protocol == 0,
+                Error(EPERM)).Else(Error(EINVAL));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy);
+};
+
+TEST(BPFDSL, BooleanLogic) {
+  BooleanLogicPolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  const intptr_t kFakeSV = 0x12345;
+
+  // Acceptable combinations that should return EPERM.
+  emulator.ExpectErrno(
+      EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_STREAM, 0, kFakeSV));
+  emulator.ExpectErrno(
+      EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_DGRAM, 0, kFakeSV));
+
+  // Combinations that are invalid for only one reason; should return EINVAL.
+  emulator.ExpectErrno(
+      EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_STREAM, 0, kFakeSV));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX,
+                                           SOCK_SEQPACKET, 0, kFakeSV));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX,
+                                           SOCK_STREAM, IPPROTO_TCP, kFakeSV));
+
+  // Completely unacceptable combination; should also return EINVAL.
+  emulator.ExpectErrno(
+      EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_SEQPACKET, IPPROTO_UDP,
+                          kFakeSV));
+}
+#endif  // !ARCH_CPU_X86
+
+class MoreBooleanLogicPolicy : public Policy {
+ public:
+  MoreBooleanLogicPolicy() {}
+  ~MoreBooleanLogicPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_setresuid) {
+      const Arg<uid_t> ruid(0), euid(1), suid(2);
+      return If(ruid == 0 || euid == 0 || suid == 0, Error(EPERM))
+          .ElseIf(ruid == 1 && euid == 1 && suid == 1, Error(EAGAIN))
+          .Else(Error(EINVAL));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MoreBooleanLogicPolicy);
+};
+
+TEST(BPFDSL, MoreBooleanLogic) {
+  MoreBooleanLogicPolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  // Expect EPERM if any set to 0.
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 0, 5, 5));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 0, 5));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 5, 0));
+
+  // Expect EAGAIN if all set to 1.
+  emulator.ExpectErrno(EAGAIN, FakeSyscall(__NR_setresuid, 1, 1, 1));
+
+  // Expect EINVAL for anything else.
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 5, 1, 1));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 5, 1));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 1, 5));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 3, 4, 5));
+}
+
+static const uintptr_t kDeadBeefAddr =
+    static_cast<uintptr_t>(0xdeadbeefdeadbeefULL);
+
+class ArgSizePolicy : public Policy {
+ public:
+  ArgSizePolicy() {}
+  ~ArgSizePolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_uname) {
+      const Arg<uintptr_t> addr(0);
+      return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow());
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy);
+};
+
+TEST(BPFDSL, ArgSizeTest) {
+  ArgSizePolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  emulator.ExpectAllow(FakeSyscall(__NR_uname, 0));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_uname, kDeadBeefAddr));
+}
+
+#if 0
+// TODO(mdempsky): This is really an integration test.
+
+class TrappingPolicy : public Policy {
+ public:
+  TrappingPolicy() {}
+  ~TrappingPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_uname) {
+      return Trap(UnameTrap, &count_);
+    }
+    return Allow();
+  }
+
+ private:
+  static intptr_t count_;
+
+  static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) {
+    BPF_ASSERT_EQ(&count_, aux);
+    return ++count_;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TrappingPolicy);
+};
+
+intptr_t TrappingPolicy::count_;
+
+BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) {
+  ASSERT_SYSCALL_RESULT(1, uname, NULL);
+  ASSERT_SYSCALL_RESULT(2, uname, NULL);
+  ASSERT_SYSCALL_RESULT(3, uname, NULL);
+}
+#endif
+
+class MaskingPolicy : public Policy {
+ public:
+  MaskingPolicy() {}
+  ~MaskingPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_setuid) {
+      const Arg<uid_t> uid(0);
+      return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES));
+    }
+    if (sysno == __NR_setgid) {
+      const Arg<gid_t> gid(0);
+      return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES));
+    }
+    if (sysno == __NR_setpgid) {
+      const Arg<pid_t> pid(0);
+      return If((pid & 0xa5) == 0xa0, Error(EINVAL)).Else(Error(EACCES));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MaskingPolicy);
+};
+
+TEST(BPFDSL, MaskTest) {
+  MaskingPolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  for (uid_t uid = 0; uid < 0x100; ++uid) {
+    const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES;
+    emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setuid, uid));
+  }
+
+  for (gid_t gid = 0; gid < 0x100; ++gid) {
+    const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES;
+    emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setgid, gid));
+  }
+
+  for (pid_t pid = 0; pid < 0x100; ++pid) {
+    const int expect_errno = (pid & 0xa5) == 0xa0 ? EINVAL : EACCES;
+    emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setpgid, pid, 0));
+  }
+}
+
+class ElseIfPolicy : public Policy {
+ public:
+  ElseIfPolicy() {}
+  ~ElseIfPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_setuid) {
+      const Arg<uid_t> uid(0);
+      return If((uid & 0xfff) == 0, Error(0))
+          .ElseIf((uid & 0xff0) == 0, Error(EINVAL))
+          .ElseIf((uid & 0xf00) == 0, Error(EEXIST))
+          .Else(Error(EACCES));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy);
+};
+
+TEST(BPFDSL, ElseIfTest) {
+  ElseIfPolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  emulator.ExpectErrno(0, FakeSyscall(__NR_setuid, 0));
+
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0001));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0002));
+
+  emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0011));
+  emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0022));
+
+  emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0111));
+  emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0222));
+}
+
+class SwitchPolicy : public Policy {
+ public:
+  SwitchPolicy() {}
+  ~SwitchPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_fcntl) {
+      const Arg<int> cmd(1);
+      const Arg<unsigned long> long_arg(2);
+      return Switch(cmd)
+          .CASES((F_GETFL, F_GETFD), Error(ENOENT))
+          .Case(F_SETFD, If(long_arg == O_CLOEXEC, Allow()).Else(Error(EINVAL)))
+          .Case(F_SETFL, Error(EPERM))
+          .Default(Error(EACCES));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SwitchPolicy);
+};
+
+TEST(BPFDSL, SwitchTest) {
+  SwitchPolicy policy;
+  PolicyEmulator emulator(&policy);
+
+  const int kFakeSockFD = 42;
+
+  emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFD));
+  emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFL));
+
+  emulator.ExpectAllow(
+      FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, O_CLOEXEC));
+  emulator.ExpectErrno(EINVAL,
+                       FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, 0));
+
+  emulator.ExpectErrno(EPERM,
+                       FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFL, O_RDONLY));
+
+  emulator.ExpectErrno(EACCES,
+                       FakeSyscall(__NR_fcntl, kFakeSockFD, F_DUPFD, 0));
+}
+
+static intptr_t DummyTrap(const struct arch_seccomp_data& data, void* aux) {
+  return 0;
+}
+
+TEST(BPFDSL, IsAllowDeny) {
+  ResultExpr allow = Allow();
+  EXPECT_TRUE(allow->IsAllow());
+  EXPECT_FALSE(allow->IsDeny());
+
+  ResultExpr error = Error(ENOENT);
+  EXPECT_FALSE(error->IsAllow());
+  EXPECT_TRUE(error->IsDeny());
+
+  ResultExpr trace = Trace(42);
+  EXPECT_FALSE(trace->IsAllow());
+  EXPECT_FALSE(trace->IsDeny());
+
+  ResultExpr trap = Trap(DummyTrap, nullptr);
+  EXPECT_FALSE(trap->IsAllow());
+  EXPECT_TRUE(trap->IsDeny());
+
+  const Arg<int> arg(0);
+  ResultExpr maybe = If(arg == 0, Allow()).Else(Error(EPERM));
+  EXPECT_FALSE(maybe->IsAllow());
+  EXPECT_FALSE(maybe->IsDeny());
+}
+
+TEST(BPFDSL, HasUnsafeTraps) {
+  ResultExpr allow = Allow();
+  EXPECT_FALSE(allow->HasUnsafeTraps());
+
+  ResultExpr safe = Trap(DummyTrap, nullptr);
+  EXPECT_FALSE(safe->HasUnsafeTraps());
+
+  ResultExpr unsafe = UnsafeTrap(DummyTrap, nullptr);
+  EXPECT_TRUE(unsafe->HasUnsafeTraps());
+
+  const Arg<int> arg(0);
+  ResultExpr maybe = If(arg == 0, allow).Else(unsafe);
+  EXPECT_TRUE(maybe->HasUnsafeTraps());
+}
+
+}  // namespace
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/codegen.cc b/sandbox/linux/bpf_dsl/codegen.cc
new file mode 100644
index 0000000..bc2c7a2
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/codegen.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+
+#include <limits>
+#include <utility>
+
+#include "base/logging.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+
+// This CodeGen implementation strives for simplicity while still
+// generating acceptable BPF programs under typical usage patterns
+// (e.g., by PolicyCompiler).
+//
+// The key to its simplicity is that BPF programs only support forward
+// jumps/branches, which allows constraining the DAG construction API
+// to make instruction nodes immutable. Immutable nodes admits a
+// simple greedy approach of emitting new instructions as needed and
+// then reusing existing ones that have already been emitted. This
+// cleanly avoids any need to compute basic blocks or apply
+// topological sorting because the API effectively sorts instructions
+// for us (e.g., before MakeInstruction() can be called to emit a
+// branch instruction, it must have already been called for each
+// branch path).
+//
+// This greedy algorithm is not without (theoretical) weakness though:
+//
+//   1. In the general case, we don't eliminate dead code.  If needed,
+//      we could trace back through the program in Compile() and elide
+//      any unneeded instructions, but in practice we only emit live
+//      instructions anyway.
+//
+//   2. By not dividing instructions into basic blocks and sorting, we
+//      lose an opportunity to move non-branch/non-return instructions
+//      adjacent to their successor instructions, which means we might
+//      need to emit additional jumps. But in practice, they'll
+//      already be nearby as long as callers don't go out of their way
+//      to interleave MakeInstruction() calls for unrelated code
+//      sequences.
+
+namespace sandbox {
+
+// kBranchRange is the maximum value that can be stored in
+// sock_filter's 8-bit jt and jf fields.
+const size_t kBranchRange = std::numeric_limits<uint8_t>::max();
+
+const CodeGen::Node CodeGen::kNullNode;
+
+CodeGen::CodeGen() : program_(), equivalent_(), memos_() {
+}
+
+CodeGen::~CodeGen() {
+}
+
+void CodeGen::Compile(CodeGen::Node head, Program* out) {
+  DCHECK(out);
+  out->assign(program_.rbegin() + Offset(head), program_.rend());
+}
+
+CodeGen::Node CodeGen::MakeInstruction(uint16_t code,
+                                       uint32_t k,
+                                       Node jt,
+                                       Node jf) {
+  // To avoid generating redundant code sequences, we memoize the
+  // results from AppendInstruction().
+  auto res = memos_.insert(std::make_pair(MemoKey(code, k, jt, jf), kNullNode));
+  CodeGen::Node* node = &res.first->second;
+  if (res.second) {  // Newly inserted memo entry.
+    *node = AppendInstruction(code, k, jt, jf);
+  }
+  return *node;
+}
+
+CodeGen::Node CodeGen::AppendInstruction(uint16_t code,
+                                         uint32_t k,
+                                         Node jt,
+                                         Node jf) {
+  if (BPF_CLASS(code) == BPF_JMP) {
+    CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed";
+
+    // Optimally adding jumps is rather tricky, so we use a quick
+    // approximation: by artificially reducing |jt|'s range, |jt| will
+    // stay within its true range even if we add a jump for |jf|.
+    jt = WithinRange(jt, kBranchRange - 1);
+    jf = WithinRange(jf, kBranchRange);
+    return Append(code, k, Offset(jt), Offset(jf));
+  }
+
+  CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf";
+  if (BPF_CLASS(code) == BPF_RET) {
+    CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt";
+  } else {
+    // For non-branch/non-return instructions, execution always
+    // proceeds to the next instruction; so we need to arrange for
+    // that to be |jt|.
+    jt = WithinRange(jt, 0);
+    CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction";
+  }
+  return Append(code, k, 0, 0);
+}
+
+CodeGen::Node CodeGen::WithinRange(Node target, size_t range) {
+  // Just use |target| if it's already within range.
+  if (Offset(target) <= range) {
+    return target;
+  }
+
+  // Alternatively, look for an equivalent instruction within range.
+  if (Offset(equivalent_.at(target)) <= range) {
+    return equivalent_.at(target);
+  }
+
+  // Otherwise, fall back to emitting a jump instruction.
+  Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0);
+  equivalent_.at(target) = jump;
+  return jump;
+}
+
+CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) {
+  if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) {
+    CHECK_LE(jt, kBranchRange);
+    CHECK_LE(jf, kBranchRange);
+  } else {
+    CHECK_EQ(0U, jt);
+    CHECK_EQ(0U, jf);
+  }
+
+  CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS));
+  CHECK_EQ(program_.size(), equivalent_.size());
+
+  Node res = program_.size();
+  program_.push_back(sock_filter{
+      code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k});
+  equivalent_.push_back(res);
+  return res;
+}
+
+size_t CodeGen::Offset(Node target) const {
+  CHECK_LT(target, program_.size()) << "Bogus offset target node";
+  return (program_.size() - 1) - target;
+}
+
+// TODO(mdempsky): Move into a general base::Tuple helper library.
+bool CodeGen::MemoKeyLess::operator()(const MemoKey& lhs,
+                                      const MemoKey& rhs) const {
+  if (get<0>(lhs) != get<0>(rhs))
+    return get<0>(lhs) < get<0>(rhs);
+  if (get<1>(lhs) != get<1>(rhs))
+    return get<1>(lhs) < get<1>(rhs);
+  if (get<2>(lhs) != get<2>(rhs))
+    return get<2>(lhs) < get<2>(rhs);
+  if (get<3>(lhs) != get<3>(rhs))
+    return get<3>(lhs) < get<3>(rhs);
+  return false;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/codegen.h b/sandbox/linux/bpf_dsl/codegen.h
new file mode 100644
index 0000000..c2e1f93
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/codegen.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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
+#define SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/tuple.h"
+#include "sandbox/sandbox_export.h"
+
+struct sock_filter;
+
+namespace sandbox {
+
+// The code generator implements a basic assembler that can convert a
+// graph of BPF instructions into a well-formed array of BPF
+// instructions. Most notably, it ensures that jumps are always
+// forward and don't exceed the limit of 255 instructions imposed by
+// the instruction set.
+//
+// Callers would typically create a new CodeGen object and then use it
+// to build a DAG of instruction nodes. They'll eventually call
+// Compile() to convert this DAG to a Program.
+//
+//   CodeGen gen;
+//   CodeGen::Node allow, branch, dag;
+//
+//   allow =
+//     gen.MakeInstruction(BPF_RET+BPF_K,
+//                         ErrorCode(ErrorCode::ERR_ALLOWED).err()));
+//   branch =
+//     gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid,
+//                         Trap(GetPidHandler, NULL), allow);
+//   dag =
+//     gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
+//                         offsetof(struct arch_seccomp_data, nr), branch);
+//
+//   // Simplified code follows; in practice, it is important to avoid calling
+//   // any C++ destructors after starting the sandbox.
+//   CodeGen::Program program;
+//   gen.Compile(dag, program);
+//   const struct sock_fprog prog = {
+//     static_cast<unsigned short>(program->size()), &program[0] };
+//   prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+//
+class SANDBOX_EXPORT CodeGen {
+ public:
+  // A vector of BPF instructions that need to be installed as a filter
+  // program in the kernel.
+  typedef std::vector<struct sock_filter> Program;
+
+  // Node represents a node within the instruction DAG being compiled.
+  using Node = Program::size_type;
+
+  // kNullNode represents the "null" node; i.e., the reserved node
+  // value guaranteed to not equal any actual nodes.
+  static const Node kNullNode = -1;
+
+  CodeGen();
+  ~CodeGen();
+
+  // MakeInstruction creates a node representing the specified
+  // instruction, or returns and existing equivalent node if one
+  // exists. For details on the possible parameters refer to
+  // https://www.kernel.org/doc/Documentation/networking/filter.txt.
+  // TODO(mdempsky): Reconsider using default arguments here.
+  Node MakeInstruction(uint16_t code,
+                       uint32_t k,
+                       Node jt = kNullNode,
+                       Node jf = kNullNode);
+
+  // Compile linearizes the instruction DAG rooted at |head| into a
+  // program that can be executed by a BPF virtual machine.
+  void Compile(Node head, Program* program);
+
+ private:
+  using MemoKey = Tuple<uint16_t, uint32_t, Node, Node>;
+  struct MemoKeyLess {
+    bool operator()(const MemoKey& lhs, const MemoKey& rhs) const;
+  };
+
+  // AppendInstruction adds a new instruction, ensuring that |jt| and
+  // |jf| are within range as necessary for |code|.
+  Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf);
+
+  // WithinRange returns a node equivalent to |next| that is at most
+  // |range| instructions away from the (logical) beginning of the
+  // program.
+  Node WithinRange(Node next, size_t range);
+
+  // Append appends a new instruction to the physical end (i.e.,
+  // logical beginning) of |program_|.
+  Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf);
+
+  // Offset returns how many instructions exist in |program_| after |target|.
+  size_t Offset(Node target) const;
+
+  // NOTE: program_ is the compiled program in *reverse*, so that
+  // indices remain stable as we add instructions.
+  Program program_;
+
+  // equivalent_ stores the most recent semantically-equivalent node for each
+  // instruction in program_. A node is defined as semantically-equivalent to N
+  // if it has the same instruction code and constant as N and its successor
+  // nodes (if any) are semantically-equivalent to N's successor nodes, or
+  // if it's an unconditional jump to a node semantically-equivalent to N.
+  std::vector<Node> equivalent_;
+
+  std::map<MemoKey, Node, MemoKeyLess> memos_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeGen);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
diff --git a/sandbox/linux/bpf_dsl/codegen_unittest.cc b/sandbox/linux/bpf_dsl/codegen_unittest.cc
new file mode 100644
index 0000000..5961822
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/codegen_unittest.cc
@@ -0,0 +1,402 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/md5.h"
+#include "base/strings/string_piece.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+// Hash provides an abstraction for building "hash trees" from BPF
+// control flow graphs, and efficiently identifying equivalent graphs.
+//
+// For simplicity, we use MD5, because base happens to provide a
+// convenient API for its use. However, any collision-resistant hash
+// should suffice.
+class Hash {
+ public:
+  static const Hash kZero;
+
+  Hash() : digest_() {}
+
+  Hash(uint16_t code,
+       uint32_t k,
+       const Hash& jt = kZero,
+       const Hash& jf = kZero)
+      : digest_() {
+    base::MD5Context ctx;
+    base::MD5Init(&ctx);
+    HashValue(&ctx, code);
+    HashValue(&ctx, k);
+    HashValue(&ctx, jt);
+    HashValue(&ctx, jf);
+    base::MD5Final(&digest_, &ctx);
+  }
+
+  Hash(const Hash& hash) = default;
+  Hash& operator=(const Hash& rhs) = default;
+
+  friend bool operator==(const Hash& lhs, const Hash& rhs) {
+    return lhs.Base16() == rhs.Base16();
+  }
+  friend bool operator!=(const Hash& lhs, const Hash& rhs) {
+    return !(lhs == rhs);
+  }
+
+ private:
+  template <typename T>
+  void HashValue(base::MD5Context* ctx, const T& value) {
+    base::MD5Update(ctx,
+                    base::StringPiece(reinterpret_cast<const char*>(&value),
+                                      sizeof(value)));
+  }
+
+  std::string Base16() const {
+    return base::MD5DigestToBase16(digest_);
+  }
+
+  base::MD5Digest digest_;
+};
+
+const Hash Hash::kZero;
+
+// Sanity check that equality and inequality work on Hash as required.
+TEST(CodeGen, HashSanity) {
+  std::vector<Hash> hashes;
+
+  // Push a bunch of logically distinct hashes.
+  hashes.push_back(Hash::kZero);
+  for (int i = 0; i < 4; ++i) {
+    hashes.push_back(Hash(i & 1, i & 2));
+  }
+  for (int i = 0; i < 16; ++i) {
+    hashes.push_back(Hash(i & 1, i & 2, Hash(i & 4, i & 8)));
+  }
+  for (int i = 0; i < 64; ++i) {
+    hashes.push_back(
+        Hash(i & 1, i & 2, Hash(i & 4, i & 8), Hash(i & 16, i & 32)));
+  }
+
+  for (const Hash& a : hashes) {
+    for (const Hash& b : hashes) {
+      // Hashes should equal themselves, but not equal all others.
+      if (&a == &b) {
+        EXPECT_EQ(a, b);
+      } else {
+        EXPECT_NE(a, b);
+      }
+    }
+  }
+}
+
+// ProgramTest provides a fixture for writing compiling sample
+// programs with CodeGen and verifying the linearized output matches
+// the input DAG.
+class ProgramTest : public ::testing::Test {
+ protected:
+  ProgramTest() : gen_(), node_hashes_() {}
+
+  // MakeInstruction calls CodeGen::MakeInstruction() and associated
+  // the returned address with a hash of the instruction.
+  CodeGen::Node MakeInstruction(uint16_t code,
+                                uint32_t k,
+                                CodeGen::Node jt = CodeGen::kNullNode,
+                                CodeGen::Node jf = CodeGen::kNullNode) {
+    CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf);
+    EXPECT_NE(CodeGen::kNullNode, res);
+
+    Hash digest(code, k, Lookup(jt), Lookup(jf));
+    auto it = node_hashes_.insert(std::make_pair(res, digest));
+    EXPECT_EQ(digest, it.first->second);
+
+    return res;
+  }
+
+  // RunTest compiles the program and verifies that the output matches
+  // what is expected.  It should be called at the end of each program
+  // test case.
+  void RunTest(CodeGen::Node head) {
+    // Compile the program
+    CodeGen::Program program;
+    gen_.Compile(head, &program);
+
+    // Walk the program backwards, and compute the hash for each instruction.
+    std::vector<Hash> prog_hashes(program.size());
+    for (size_t i = program.size(); i > 0; --i) {
+      const sock_filter& insn = program.at(i - 1);
+      Hash& hash = prog_hashes.at(i - 1);
+
+      if (BPF_CLASS(insn.code) == BPF_JMP) {
+        if (BPF_OP(insn.code) == BPF_JA) {
+          // The compiler adds JA instructions as needed, so skip them.
+          hash = prog_hashes.at(i + insn.k);
+        } else {
+          hash = Hash(insn.code, insn.k, prog_hashes.at(i + insn.jt),
+                      prog_hashes.at(i + insn.jf));
+        }
+      } else if (BPF_CLASS(insn.code) == BPF_RET) {
+        hash = Hash(insn.code, insn.k);
+      } else {
+        hash = Hash(insn.code, insn.k, prog_hashes.at(i));
+      }
+    }
+
+    EXPECT_EQ(Lookup(head), prog_hashes.at(0));
+  }
+
+ private:
+  const Hash& Lookup(CodeGen::Node next) const {
+    if (next == CodeGen::kNullNode) {
+      return Hash::kZero;
+    }
+    auto it = node_hashes_.find(next);
+    if (it == node_hashes_.end()) {
+      ADD_FAILURE() << "No hash found for node " << next;
+      return Hash::kZero;
+    }
+    return it->second;
+  }
+
+  CodeGen gen_;
+  std::map<CodeGen::Node, Hash> node_hashes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProgramTest);
+};
+
+TEST_F(ProgramTest, OneInstruction) {
+  // Create the most basic valid BPF program:
+  //    RET 0
+  CodeGen::Node head = MakeInstruction(BPF_RET + BPF_K, 0);
+  RunTest(head);
+}
+
+TEST_F(ProgramTest, SimpleBranch) {
+  // Create a program with a single branch:
+  //    JUMP if eq 42 then $0 else $1
+  // 0: RET 1
+  // 1: RET 0
+  CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42,
+                                       MakeInstruction(BPF_RET + BPF_K, 1),
+                                       MakeInstruction(BPF_RET + BPF_K, 0));
+  RunTest(head);
+}
+
+TEST_F(ProgramTest, AtypicalBranch) {
+  // Create a program with a single branch:
+  //    JUMP if eq 42 then $0 else $0
+  // 0: RET 0
+
+  CodeGen::Node ret = MakeInstruction(BPF_RET + BPF_K, 0);
+  CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
+
+  // N.B.: As the instructions in both sides of the branch are already
+  //       the same object, we do not actually have any "mergeable" branches.
+  //       This needs to be reflected in our choice of "flags".
+  RunTest(head);
+}
+
+TEST_F(ProgramTest, Complex) {
+  // Creates a basic BPF program that we'll use to test some of the code:
+  //    JUMP if eq 42 the $0 else $1     (insn6)
+  // 0: LD 23                            (insn5)
+  // 1: JUMP if eq 42 then $2 else $4    (insn4)
+  // 2: JUMP to $3                       (insn2)
+  // 3: LD 42                            (insn1)
+  //    RET 42                           (insn0)
+  // 4: LD 42                            (insn3)
+  //    RET 42                           (insn3+)
+  CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42);
+  CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0);
+  CodeGen::Node insn2 = insn1;  // Implicit JUMP
+
+  // We explicitly duplicate instructions to test that they're merged.
+  CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42,
+                                        MakeInstruction(BPF_RET + BPF_K, 42));
+  EXPECT_EQ(insn2, insn3);
+
+  CodeGen::Node insn4 =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3);
+  CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
+
+  // Force a basic block that ends in neither a jump instruction nor a return
+  // instruction. It only contains "insn5". This exercises one of the less
+  // common code paths in the topo-sort algorithm.
+  // This also gives us a diamond-shaped pattern in our graph, which stresses
+  // another aspect of the topo-sort algorithm (namely, the ability to
+  // correctly count the incoming branches for subtrees that are not disjunct).
+  CodeGen::Node insn6 =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4);
+
+  RunTest(insn6);
+}
+
+TEST_F(ProgramTest, ConfusingTails) {
+  // This simple program demonstrates https://crbug.com/351103/
+  // The two "LOAD 0" instructions are blocks of their own. MergeTails() could
+  // be tempted to merge them since they are the same. However, they are
+  // not mergeable because they fall-through to non semantically equivalent
+  // blocks.
+  // Without the fix for this bug, this program should trigger the check in
+  // CompileAndCompare: the serialized graphs from the program and its compiled
+  // version will differ.
+  //
+  //  0) LOAD 1  // ???
+  //  1) if A == 0x1; then JMP 2 else JMP 3
+  //  2) LOAD 0  // System call number
+  //  3) if A == 0x2; then JMP 4 else JMP 5
+  //  4) LOAD 0  // System call number
+  //  5) if A == 0x1; then JMP 6 else JMP 7
+  //  6) RET 0
+  //  7) RET 1
+
+  CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
+  CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
+  CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
+  CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
+  CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+  CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
+  CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+  CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+
+  RunTest(i0);
+}
+
+TEST_F(ProgramTest, ConfusingTailsBasic) {
+  // Without the fix for https://crbug.com/351103/, (see
+  // SampleProgramConfusingTails()), this would generate a cyclic graph and
+  // crash as the two "LOAD 0" instructions would get merged.
+  //
+  // 0) LOAD 1  // ???
+  // 1) if A == 0x1; then JMP 2 else JMP 3
+  // 2) LOAD 0  // System call number
+  // 3) if A == 0x2; then JMP 4 else JMP 5
+  // 4) LOAD 0  // System call number
+  // 5) RET 1
+
+  CodeGen::Node i5 = MakeInstruction(BPF_RET + BPF_K, 1);
+  CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
+  CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+  CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
+  CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+  CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+
+  RunTest(i0);
+}
+
+TEST_F(ProgramTest, ConfusingTailsMergeable) {
+  // This is similar to SampleProgramConfusingTails(), except that
+  // instructions 2 and 4 are now RET instructions.
+  // In PointerCompare(), this exercises the path where two blocks are of the
+  // same length and identical and the last instruction is a JMP or RET, so the
+  // following blocks don't need to be looked at and the blocks are mergeable.
+  //
+  // 0) LOAD 1  // ???
+  // 1) if A == 0x1; then JMP 2 else JMP 3
+  // 2) RET 42
+  // 3) if A == 0x2; then JMP 4 else JMP 5
+  // 4) RET 42
+  // 5) if A == 0x1; then JMP 6 else JMP 7
+  // 6) RET 0
+  // 7) RET 1
+
+  CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
+  CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
+  CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
+  CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42);
+  CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+  CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42);
+  CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+  CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+
+  RunTest(i0);
+}
+
+TEST_F(ProgramTest, InstructionFolding) {
+  // Check that simple instructions are folded as expected.
+  CodeGen::Node a = MakeInstruction(BPF_RET + BPF_K, 0);
+  EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0));
+  CodeGen::Node b = MakeInstruction(BPF_RET + BPF_K, 1);
+  EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0));
+  EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1));
+  EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1));
+
+  // Check that complex sequences are folded too.
+  CodeGen::Node c =
+      MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0,
+                      MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b));
+  EXPECT_EQ(c, MakeInstruction(
+                   BPF_LD + BPF_W + BPF_ABS, 0,
+                   MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b)));
+
+  RunTest(c);
+}
+
+TEST_F(ProgramTest, FarBranches) {
+  // BPF instructions use 8-bit fields for branch offsets, which means
+  // branch targets must be within 255 instructions of the branch
+  // instruction. CodeGen abstracts away this detail by inserting jump
+  // instructions as needed, which we test here by generating programs
+  // that should trigger any interesting boundary conditions.
+
+  // Populate with 260 initial instruction nodes.
+  std::vector<CodeGen::Node> nodes;
+  nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0));
+  for (size_t i = 1; i < 260; ++i) {
+    nodes.push_back(
+        MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back()));
+  }
+
+  // Exhaustively test branch offsets near BPF's limits.
+  for (size_t jt = 250; jt < 260; ++jt) {
+    for (size_t jf = 250; jf < 260; ++jf) {
+      nodes.push_back(MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0,
+                                      nodes.rbegin()[jt], nodes.rbegin()[jf]));
+      RunTest(nodes.back());
+    }
+  }
+}
+
+TEST_F(ProgramTest, JumpReuse) {
+  // As a code size optimization, we try to reuse jumps when possible
+  // instead of emitting new ones. Here we make sure that optimization
+  // is working as intended.
+  //
+  // NOTE: To simplify testing, we rely on implementation details
+  // about what CodeGen::Node values indicate (i.e., vector indices),
+  // but CodeGen users should treat them as opaque values.
+
+  // Populate with 260 initial instruction nodes.
+  std::vector<CodeGen::Node> nodes;
+  nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0));
+  for (size_t i = 1; i < 260; ++i) {
+    nodes.push_back(
+        MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back()));
+  }
+
+  // Branching to nodes[0] and nodes[1] should require 3 new
+  // instructions: two far jumps plus the branch itself.
+  CodeGen::Node one =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0, nodes[0], nodes[1]);
+  EXPECT_EQ(nodes.back() + 3, one);  // XXX: Implementation detail!
+  RunTest(one);
+
+  // Branching again to the same target nodes should require only one
+  // new instruction, as we can reuse the previous branch's jumps.
+  CodeGen::Node two =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, nodes[0], nodes[1]);
+  EXPECT_EQ(one + 1, two);  // XXX: Implementation detail!
+  RunTest(two);
+}
+
+}  // namespace
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/cons.h b/sandbox/linux/bpf_dsl/cons.h
new file mode 100644
index 0000000..fa47c14
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/cons.h
@@ -0,0 +1,138 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_CONS_H_
+#define SANDBOX_LINUX_BPF_DSL_CONS_H_
+
+#include "base/memory/ref_counted.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace cons {
+
+// Namespace cons provides an abstraction for immutable "cons list"
+// data structures as commonly provided in functional programming
+// languages like Lisp or Haskell.
+//
+// A cons list is a linked list consisting of "cells", each of which
+// have a "head" and a "tail" element. A cell's head element contains
+// a user specified value, while the tail element contains a (possibly
+// null) pointer to another cell.
+//
+// An empty list (idiomatically referred to as "nil") can be
+// constructed as "cons::List<Foo>()" or simply as "nullptr" if Foo
+// can be inferred from context (e.g., calling a function that has a
+// "cons::List<Foo>" parameter).
+//
+// Existing lists (including empty lists) can be extended by
+// prepending new values to the front using the "Cons(head, tail)"
+// function, which will allocate a new cons cell. Notably, cons lists
+// support creating multiple lists that share a common tail sequence.
+//
+// Lastly, lists support iteration via C++11's range-based for loop
+// construct.
+//
+// Examples:
+//
+//   // basic construction
+//   const cons::List<char> kNil = nullptr;
+//   cons::List<char> ba = Cons('b', Cons('a', kNil));
+//
+//   // common tail sequence
+//   cons::List<char> cba = Cons('c', ba);
+//   cons::List<char> dba = Cons('d', ba);
+//
+//   // iteration
+//   for (const char& ch : cba) {
+//     // iterates 'c', 'b', 'a'
+//   }
+//   for (const char& ch : dba) {
+//     // iterates 'd', 'b', 'a'
+//   }
+
+// Forward declarations.
+template <typename T>
+class Cell;
+template <typename T>
+class ListIterator;
+
+// List represents a (possibly null) pointer to a cons cell.
+template <typename T>
+using List = scoped_refptr<const Cell<T>>;
+
+// Cons extends a cons list by prepending a new value to the front.
+template <typename T>
+List<T> Cons(const T& head, const List<T>& tail) {
+  return List<T>(new const Cell<T>(head, tail));
+}
+
+// Cell represents an individual "cons cell" within a cons list.
+template <typename T>
+class Cell : public base::RefCounted<Cell<T>> {
+ public:
+  Cell(const T& head, const List<T>& tail) : head_(head), tail_(tail) {}
+
+  // Head returns this cell's head element.
+  const T& head() const { return head_; }
+
+  // Tail returns this cell's tail element.
+  const List<T>& tail() const { return tail_; }
+
+ private:
+  virtual ~Cell() {}
+
+  T head_;
+  List<T> tail_;
+
+  friend class base::RefCounted<Cell<T>>;
+  DISALLOW_COPY_AND_ASSIGN(Cell);
+};
+
+// Begin returns a list iterator pointing to the first element of the
+// cons list. It's provided to support range-based for loops.
+template <typename T>
+ListIterator<T> begin(const List<T>& list) {
+  return ListIterator<T>(list);
+}
+
+// End returns a list iterator pointing to the "past-the-end" element
+// of the cons list (i.e., nil). It's provided to support range-based
+// for loops.
+template <typename T>
+ListIterator<T> end(const List<T>& list) {
+  return ListIterator<T>();
+}
+
+// ListIterator provides C++ forward iterator semantics for traversing
+// a cons list.
+template <typename T>
+class ListIterator {
+ public:
+  ListIterator() : list_() {}
+  explicit ListIterator(const List<T>& list) : list_(list) {}
+
+  const T& operator*() const { return list_->head(); }
+
+  ListIterator& operator++() {
+    list_ = list_->tail();
+    return *this;
+  }
+
+  friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) {
+    return lhs.list_ == rhs.list_;
+  }
+
+ private:
+  List<T> list_;
+};
+
+template <typename T>
+bool operator!=(const ListIterator<T>& lhs, const ListIterator<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace cons
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_CONS_H_
diff --git a/sandbox/linux/bpf_dsl/cons_unittest.cc b/sandbox/linux/bpf_dsl/cons_unittest.cc
new file mode 100644
index 0000000..ea2ba2f
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/cons_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/cons.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+std::string Join(cons::List<char> char_list) {
+  std::string res;
+  for (const char& ch : char_list) {
+    res.push_back(ch);
+  }
+  return res;
+}
+
+TEST(ConsListTest, Basic) {
+  cons::List<char> ba = Cons('b', Cons('a', cons::List<char>()));
+  EXPECT_EQ("ba", Join(ba));
+
+  cons::List<char> cba = Cons('c', ba);
+  cons::List<char> dba = Cons('d', ba);
+  EXPECT_EQ("cba", Join(cba));
+  EXPECT_EQ("dba", Join(dba));
+}
+
+}  // namespace
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/dump_bpf.cc b/sandbox/linux/bpf_dsl/dump_bpf.cc
new file mode 100644
index 0000000..d0c8f75
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/dump_bpf.cc
@@ -0,0 +1,109 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+
+#include <stdio.h>
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+void DumpBPF::PrintProgram(const CodeGen::Program& program) {
+  for (CodeGen::Program::const_iterator iter = program.begin();
+       iter != program.end();
+       ++iter) {
+    int ip = (int)(iter - program.begin());
+    fprintf(stderr, "%3d) ", ip);
+    switch (BPF_CLASS(iter->code)) {
+      case BPF_LD:
+        if (iter->code == BPF_LD + BPF_W + BPF_ABS) {
+          fprintf(stderr, "LOAD %d  // ", (int)iter->k);
+          if (iter->k == offsetof(struct arch_seccomp_data, nr)) {
+            fprintf(stderr, "System call number\n");
+          } else if (iter->k == offsetof(struct arch_seccomp_data, arch)) {
+            fprintf(stderr, "Architecture\n");
+          } else if (iter->k ==
+                     offsetof(struct arch_seccomp_data, instruction_pointer)) {
+            fprintf(stderr, "Instruction pointer (LSB)\n");
+          } else if (iter->k ==
+                     offsetof(struct arch_seccomp_data, instruction_pointer) +
+                         4) {
+            fprintf(stderr, "Instruction pointer (MSB)\n");
+          } else if (iter->k >= offsetof(struct arch_seccomp_data, args) &&
+                     iter->k < offsetof(struct arch_seccomp_data, args) + 48 &&
+                     (iter->k - offsetof(struct arch_seccomp_data, args)) % 4 ==
+                         0) {
+            fprintf(
+                stderr,
+                "Argument %d (%cSB)\n",
+                (int)(iter->k - offsetof(struct arch_seccomp_data, args)) / 8,
+                (iter->k - offsetof(struct arch_seccomp_data, args)) % 8 ? 'M'
+                                                                         : 'L');
+          } else {
+            fprintf(stderr, "???\n");
+          }
+        } else {
+          fprintf(stderr, "LOAD ???\n");
+        }
+        break;
+      case BPF_JMP:
+        if (BPF_OP(iter->code) == BPF_JA) {
+          fprintf(stderr, "JMP %d\n", ip + iter->k + 1);
+        } else {
+          fprintf(stderr, "if A %s 0x%x; then JMP %d else JMP %d\n",
+              BPF_OP(iter->code) == BPF_JSET ? "&" :
+              BPF_OP(iter->code) == BPF_JEQ ? "==" :
+              BPF_OP(iter->code) == BPF_JGE ? ">=" :
+              BPF_OP(iter->code) == BPF_JGT ? ">"  : "???",
+              (int)iter->k,
+              ip + iter->jt + 1, ip + iter->jf + 1);
+        }
+        break;
+      case BPF_RET:
+        fprintf(stderr, "RET 0x%x  // ", iter->k);
+        if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) {
+          fprintf(stderr, "Trap #%d\n", iter->k & SECCOMP_RET_DATA);
+        } else if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
+          fprintf(stderr, "errno = %d\n", iter->k & SECCOMP_RET_DATA);
+        } else if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
+          fprintf(stderr, "Trace #%d\n", iter->k & SECCOMP_RET_DATA);
+        } else if (iter->k == SECCOMP_RET_ALLOW) {
+          fprintf(stderr, "Allowed\n");
+        } else {
+          fprintf(stderr, "???\n");
+        }
+        break;
+      case BPF_ALU:
+        if (BPF_OP(iter->code) == BPF_NEG) {
+          fprintf(stderr, "A := -A\n");
+        } else {
+          fprintf(stderr, "A := A %s 0x%x\n",
+                  BPF_OP(iter->code) == BPF_ADD ? "+"  :
+                  BPF_OP(iter->code) == BPF_SUB ? "-"  :
+                  BPF_OP(iter->code) == BPF_MUL ? "*"  :
+                  BPF_OP(iter->code) == BPF_DIV ? "/"  :
+                  BPF_OP(iter->code) == BPF_MOD ? "%"  :
+                  BPF_OP(iter->code) == BPF_OR  ? "|"  :
+                  BPF_OP(iter->code) == BPF_XOR ? "^"  :
+                  BPF_OP(iter->code) == BPF_AND ? "&"  :
+                  BPF_OP(iter->code) == BPF_LSH ? "<<" :
+                  BPF_OP(iter->code) == BPF_RSH ? ">>" : "???",
+                  (int)iter->k);
+        }
+        break;
+      default:
+        fprintf(stderr, "???\n");
+        break;
+    }
+  }
+  return;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/dump_bpf.h b/sandbox/linux/bpf_dsl/dump_bpf.h
new file mode 100644
index 0000000..cd12be7
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/dump_bpf.h
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+class SANDBOX_EXPORT DumpBPF {
+ public:
+  // PrintProgram writes |program| in a human-readable format to stderr.
+  static void PrintProgram(const CodeGen::Program& program);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/linux_syscall_ranges.h b/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
new file mode 100644
index 0000000..a747770
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
+#define SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
+
+#if defined(__x86_64__)
+
+#define MIN_SYSCALL         0u
+#define MAX_PUBLIC_SYSCALL  1024u
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
+
+#elif defined(__i386__)
+
+#define MIN_SYSCALL         0u
+#define MAX_PUBLIC_SYSCALL  1024u
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
+
+#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+
+// ARM EABI includes "ARM private" system calls starting at |__ARM_NR_BASE|,
+// and a "ghost syscall private to the kernel", cmpxchg,
+// at |__ARM_NR_BASE+0x00fff0|.
+// See </arch/arm/include/asm/unistd.h> in the Linux kernel.
+
+// __NR_SYSCALL_BASE is 0 in thumb and ARM EABI.
+#define MIN_SYSCALL         0u
+#define MAX_PUBLIC_SYSCALL  (MIN_SYSCALL + 1024u)
+// __ARM_NR_BASE is __NR_SYSCALL_BASE + 0xf0000u
+#define MIN_PRIVATE_SYSCALL 0xf0000u
+#define MAX_PRIVATE_SYSCALL (MIN_PRIVATE_SYSCALL + 16u)
+#define MIN_GHOST_SYSCALL   (MIN_PRIVATE_SYSCALL + 0xfff0u)
+#define MAX_SYSCALL         (MIN_GHOST_SYSCALL + 4u)
+
+#elif defined(__mips__) && (_MIPS_SIM == _ABIO32)
+
+#include <asm/unistd.h>  // for __NR_O32_Linux and __NR_Linux_syscalls
+#define MIN_SYSCALL         __NR_O32_Linux
+#define MAX_PUBLIC_SYSCALL  (MIN_SYSCALL + __NR_Linux_syscalls)
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
+
+#elif defined(__mips__) && (_MIPS_SIM == _ABI64)
+
+#error "Add support to header file"
+
+#elif defined(__aarch64__)
+
+#define MIN_SYSCALL 0u
+#define MAX_PUBLIC_SYSCALL 279u
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#else
+#error "Unsupported architecture"
+#endif
+
+#endif  // SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
diff --git a/sandbox/linux/bpf_dsl/policy.cc b/sandbox/linux/bpf_dsl/policy.cc
new file mode 100644
index 0000000..c20edc6
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/policy.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/policy.h"
+
+#include <errno.h>
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+ResultExpr Policy::InvalidSyscall() const {
+  return Error(ENOSYS);
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/policy.h b/sandbox/linux/bpf_dsl/policy.h
new file mode 100644
index 0000000..6c67589
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/policy.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_H_
+#define SANDBOX_LINUX_BPF_DSL_POLICY_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// Interface to implement to define a BPF sandbox policy.
+class SANDBOX_EXPORT Policy {
+ public:
+  Policy() {}
+  virtual ~Policy() {}
+
+  // User extension point for writing custom sandbox policies.
+  // The returned ResultExpr will control how the kernel responds to the
+  // specified system call number.
+  virtual ResultExpr EvaluateSyscall(int sysno) const = 0;
+
+  // Optional overload for specifying alternate behavior for invalid
+  // system calls.  The default is to return ENOSYS.
+  virtual ResultExpr InvalidSyscall() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Policy);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_POLICY_H_
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
new file mode 100644
index 0000000..f38232f
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -0,0 +1,499 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+
+#include <errno.h>
+#include <sys/syscall.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/bpf_dsl/verifier.h"
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+#if defined(__i386__) || defined(__x86_64__)
+const bool kIsIntel = true;
+#else
+const bool kIsIntel = false;
+#endif
+#if defined(__x86_64__) && defined(__ILP32__)
+const bool kIsX32 = true;
+#else
+const bool kIsX32 = false;
+#endif
+
+const int kSyscallsRequiredForUnsafeTraps[] = {
+    __NR_rt_sigprocmask,
+    __NR_rt_sigreturn,
+#if defined(__NR_sigprocmask)
+    __NR_sigprocmask,
+#endif
+#if defined(__NR_sigreturn)
+    __NR_sigreturn,
+#endif
+};
+
+bool HasExactlyOneBit(uint64_t x) {
+  // Common trick; e.g., see http://stackoverflow.com/a/108329.
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+// A Trap() handler that returns an "errno" value. The value is encoded
+// in the "aux" parameter.
+intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
+  // TrapFnc functions report error by following the native kernel convention
+  // of returning an exit code in the range of -1..-4096. They do not try to
+  // set errno themselves. The glibc wrapper that triggered the SIGSYS will
+  // ultimately do so for us.
+  int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA;
+  return -err;
+}
+
+bool HasUnsafeTraps(const Policy* policy) {
+  DCHECK(policy);
+  for (uint32_t sysnum : SyscallSet::ValidOnly()) {
+    if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) {
+      return true;
+    }
+  }
+  return policy->InvalidSyscall()->HasUnsafeTraps();
+}
+
+}  // namespace
+
+struct PolicyCompiler::Range {
+  uint32_t from;
+  CodeGen::Node node;
+};
+
+PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
+    : policy_(policy),
+      registry_(registry),
+      escapepc_(0),
+      conds_(),
+      gen_(),
+      has_unsafe_traps_(HasUnsafeTraps(policy_)) {
+  DCHECK(policy);
+}
+
+PolicyCompiler::~PolicyCompiler() {
+}
+
+scoped_ptr<CodeGen::Program> PolicyCompiler::Compile(bool verify) {
+  CHECK(policy_->InvalidSyscall()->IsDeny())
+      << "Policies should deny invalid system calls";
+
+  // If our BPF program has unsafe traps, enable support for them.
+  if (has_unsafe_traps_) {
+    CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC";
+
+    for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
+      CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow())
+          << "Policies that use UnsafeTrap() must unconditionally allow all "
+             "required system calls";
+    }
+
+    CHECK(registry_->EnableUnsafeTraps())
+        << "We'd rather die than enable unsafe traps";
+  }
+
+  // Assemble the BPF filter program.
+  scoped_ptr<CodeGen::Program> program(new CodeGen::Program());
+  gen_.Compile(AssemblePolicy(), program.get());
+
+  // Make sure compilation resulted in a BPF program that executes
+  // correctly. Otherwise, there is an internal error in our BPF compiler.
+  // There is really nothing the caller can do until the bug is fixed.
+  if (verify) {
+    const char* err = nullptr;
+    if (!Verifier::VerifyBPF(this, *program, *policy_, &err)) {
+      DumpBPF::PrintProgram(*program);
+      LOG(FATAL) << err;
+    }
+  }
+
+  return program.Pass();
+}
+
+void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
+  escapepc_ = escapepc;
+}
+
+CodeGen::Node PolicyCompiler::AssemblePolicy() {
+  // A compiled policy consists of three logical parts:
+  //   1. Check that the "arch" field matches the expected architecture.
+  //   2. If the policy involves unsafe traps, check if the syscall was
+  //      invoked by Syscall::Call, and then allow it unconditionally.
+  //   3. Check the system call number and jump to the appropriate compiled
+  //      system call policy number.
+  return CheckArch(MaybeAddEscapeHatch(DispatchSyscall()));
+}
+
+CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
+  // If the architecture doesn't match SECCOMP_ARCH, disallow the
+  // system call.
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX,
+      gen_.MakeInstruction(
+          BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
+          CompileResult(Kill("Invalid audit architecture in BPF filter"))));
+}
+
+CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
+  // If no unsafe traps, then simply return |rest|.
+  if (!has_unsafe_traps_) {
+    return rest;
+  }
+
+  // We already enabled unsafe traps in Compile, but enable them again to give
+  // the trap registry a second chance to complain before we add the backdoor.
+  CHECK(registry_->EnableUnsafeTraps());
+
+  // Allow system calls, if they originate from our magic return address.
+  const uint32_t lopc = static_cast<uint32_t>(escapepc_);
+  const uint32_t hipc = static_cast<uint32_t>(escapepc_ >> 32);
+
+  // BPF cannot do native 64-bit comparisons, so we have to compare
+  // both 32-bit halves of the instruction pointer. If they match what
+  // we expect, we return ERR_ALLOWED. If either or both don't match,
+  // we continue evalutating the rest of the sandbox policy.
+  //
+  // For simplicity, we check the full 64-bit instruction pointer even
+  // on 32-bit architectures.
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX,
+      gen_.MakeInstruction(
+          BPF_JMP + BPF_JEQ + BPF_K, lopc,
+          gen_.MakeInstruction(
+              BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX,
+              gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hipc,
+                                   CompileResult(Allow()), rest)),
+          rest));
+}
+
+CodeGen::Node PolicyCompiler::DispatchSyscall() {
+  // Evaluate all possible system calls and group their ErrorCodes into
+  // ranges of identical codes.
+  Ranges ranges;
+  FindRanges(&ranges);
+
+  // Compile the system call ranges to an optimized BPF jumptable
+  CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end());
+
+  // Grab the system call number, so that we can check it and then
+  // execute the jump table.
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable));
+}
+
+CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) {
+  if (kIsIntel) {
+    // On Intel architectures, verify that system call numbers are in the
+    // expected number range.
+    CodeGen::Node invalidX32 =
+        CompileResult(Kill("Illegal mixing of system call ABIs"));
+    if (kIsX32) {
+      // The newer x32 API always sets bit 30.
+      return gen_.MakeInstruction(
+          BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32);
+    } else {
+      // The older i386 and x86-64 APIs clear bit 30 on all system calls.
+      return gen_.MakeInstruction(
+          BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed);
+    }
+  }
+
+  // TODO(mdempsky): Similar validation for other architectures?
+  return passed;
+}
+
+void PolicyCompiler::FindRanges(Ranges* ranges) {
+  // Please note that "struct seccomp_data" defines system calls as a signed
+  // int32_t, but BPF instructions always operate on unsigned quantities. We
+  // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
+  // and then verifying that the rest of the number range (both positive and
+  // negative) all return the same ErrorCode.
+  const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall());
+  uint32_t old_sysnum = 0;
+  CodeGen::Node old_node =
+      SyscallSet::IsValid(old_sysnum)
+          ? CompileResult(policy_->EvaluateSyscall(old_sysnum))
+          : invalid_node;
+
+  for (uint32_t sysnum : SyscallSet::All()) {
+    CodeGen::Node node =
+        SyscallSet::IsValid(sysnum)
+            ? CompileResult(policy_->EvaluateSyscall(static_cast<int>(sysnum)))
+            : invalid_node;
+    // N.B., here we rely on CodeGen folding (i.e., returning the same
+    // node value for) identical code sequences, otherwise our jump
+    // table will blow up in size.
+    if (node != old_node) {
+      ranges->push_back(Range{old_sysnum, old_node});
+      old_sysnum = sysnum;
+      old_node = node;
+    }
+  }
+  ranges->push_back(Range{old_sysnum, old_node});
+}
+
+CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
+                                                Ranges::const_iterator stop) {
+  // We convert the list of system call ranges into jump table that performs
+  // a binary search over the ranges.
+  // As a sanity check, we need to have at least one distinct ranges for us
+  // to be able to build a jump table.
+  CHECK(start < stop) << "Invalid iterator range";
+  const auto n = stop - start;
+  if (n == 1) {
+    // If we have narrowed things down to a single range object, we can
+    // return from the BPF filter program.
+    return start->node;
+  }
+
+  // Pick the range object that is located at the mid point of our list.
+  // We compare our system call number against the lowest valid system call
+  // number in this range object. If our number is lower, it is outside of
+  // this range object. If it is greater or equal, it might be inside.
+  Ranges::const_iterator mid = start + n / 2;
+
+  // Sub-divide the list of ranges and continue recursively.
+  CodeGen::Node jf = AssembleJumpTable(start, mid);
+  CodeGen::Node jt = AssembleJumpTable(mid, stop);
+  return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
+}
+
+CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
+  return RetExpression(res->Compile(this));
+}
+
+CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) {
+  switch (err.error_type()) {
+    case ErrorCode::ET_COND:
+      return CondExpression(err);
+    case ErrorCode::ET_SIMPLE:
+    case ErrorCode::ET_TRAP:
+      return gen_.MakeInstruction(BPF_RET + BPF_K, err.err());
+    default:
+      LOG(FATAL)
+          << "ErrorCode is not suitable for returning from a BPF program";
+      return CodeGen::kNullNode;
+  }
+}
+
+CodeGen::Node PolicyCompiler::CondExpression(const ErrorCode& cond) {
+  // Sanity check that |cond| makes sense.
+  CHECK(cond.argno_ >= 0 && cond.argno_ < 6) << "Invalid argument number "
+                                             << cond.argno_;
+  CHECK(cond.width_ == ErrorCode::TP_32BIT ||
+        cond.width_ == ErrorCode::TP_64BIT)
+      << "Invalid argument width " << cond.width_;
+  CHECK_NE(0U, cond.mask_) << "Zero mask is invalid";
+  CHECK_EQ(cond.value_, cond.value_ & cond.mask_)
+      << "Value contains masked out bits";
+  if (sizeof(void*) == 4) {
+    CHECK_EQ(ErrorCode::TP_32BIT, cond.width_)
+        << "Invalid width on 32-bit platform";
+  }
+  if (cond.width_ == ErrorCode::TP_32BIT) {
+    CHECK_EQ(0U, cond.mask_ >> 32) << "Mask exceeds argument size";
+    CHECK_EQ(0U, cond.value_ >> 32) << "Value exceeds argument size";
+  }
+
+  CodeGen::Node passed = RetExpression(*cond.passed_);
+  CodeGen::Node failed = RetExpression(*cond.failed_);
+
+  // We want to emit code to check "(arg & mask) == value" where arg, mask, and
+  // value are 64-bit values, but the BPF machine is only 32-bit. We implement
+  // this by independently testing the upper and lower 32-bits and continuing to
+  // |passed| if both evaluate true, or to |failed| if either evaluate false.
+  return CondExpressionHalf(cond,
+                            UpperHalf,
+                            CondExpressionHalf(cond, LowerHalf, passed, failed),
+                            failed);
+}
+
+CodeGen::Node PolicyCompiler::CondExpressionHalf(const ErrorCode& cond,
+                                                 ArgHalf half,
+                                                 CodeGen::Node passed,
+                                                 CodeGen::Node failed) {
+  if (cond.width_ == ErrorCode::TP_32BIT && half == UpperHalf) {
+    // Special logic for sanity checking the upper 32-bits of 32-bit system
+    // call arguments.
+
+    // TODO(mdempsky): Compile Unexpected64bitArgument() just per program.
+    CodeGen::Node invalid_64bit = RetExpression(Unexpected64bitArgument());
+
+    const uint32_t upper = SECCOMP_ARG_MSB_IDX(cond.argno_);
+    const uint32_t lower = SECCOMP_ARG_LSB_IDX(cond.argno_);
+
+    if (sizeof(void*) == 4) {
+      // On 32-bit platforms, the upper 32-bits should always be 0:
+      //   LDW  [upper]
+      //   JEQ  0, passed, invalid
+      return gen_.MakeInstruction(
+          BPF_LD + BPF_W + BPF_ABS,
+          upper,
+          gen_.MakeInstruction(
+              BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit));
+    }
+
+    // On 64-bit platforms, the upper 32-bits may be 0 or ~0; but we only allow
+    // ~0 if the sign bit of the lower 32-bits is set too:
+    //   LDW  [upper]
+    //   JEQ  0, passed, (next)
+    //   JEQ  ~0, (next), invalid
+    //   LDW  [lower]
+    //   JSET (1<<31), passed, invalid
+    //
+    // TODO(mdempsky): The JSET instruction could perhaps jump to passed->next
+    // instead, as the first instruction of passed should be "LDW [lower]".
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        upper,
+        gen_.MakeInstruction(
+            BPF_JMP + BPF_JEQ + BPF_K,
+            0,
+            passed,
+            gen_.MakeInstruction(
+                BPF_JMP + BPF_JEQ + BPF_K,
+                std::numeric_limits<uint32_t>::max(),
+                gen_.MakeInstruction(
+                    BPF_LD + BPF_W + BPF_ABS,
+                    lower,
+                    gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K,
+                                         1U << 31,
+                                         passed,
+                                         invalid_64bit)),
+                invalid_64bit)));
+  }
+
+  const uint32_t idx = (half == UpperHalf) ? SECCOMP_ARG_MSB_IDX(cond.argno_)
+                                           : SECCOMP_ARG_LSB_IDX(cond.argno_);
+  const uint32_t mask = (half == UpperHalf) ? cond.mask_ >> 32 : cond.mask_;
+  const uint32_t value = (half == UpperHalf) ? cond.value_ >> 32 : cond.value_;
+
+  // Emit a suitable instruction sequence for (arg & mask) == value.
+
+  // For (arg & 0) == 0, just return passed.
+  if (mask == 0) {
+    CHECK_EQ(0U, value);
+    return passed;
+  }
+
+  // For (arg & ~0) == value, emit:
+  //   LDW  [idx]
+  //   JEQ  value, passed, failed
+  if (mask == std::numeric_limits<uint32_t>::max()) {
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        idx,
+        gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed));
+  }
+
+  // For (arg & mask) == 0, emit:
+  //   LDW  [idx]
+  //   JSET mask, failed, passed
+  // (Note: failed and passed are intentionally swapped.)
+  if (value == 0) {
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        idx,
+        gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, failed, passed));
+  }
+
+  // For (arg & x) == x where x is a single-bit value, emit:
+  //   LDW  [idx]
+  //   JSET mask, passed, failed
+  if (mask == value && HasExactlyOneBit(mask)) {
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        idx,
+        gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, passed, failed));
+  }
+
+  // Generic fallback:
+  //   LDW  [idx]
+  //   AND  mask
+  //   JEQ  value, passed, failed
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS,
+      idx,
+      gen_.MakeInstruction(
+          BPF_ALU + BPF_AND + BPF_K,
+          mask,
+          gen_.MakeInstruction(
+              BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)));
+}
+
+ErrorCode PolicyCompiler::Unexpected64bitArgument() {
+  return Kill("Unexpected 64bit argument detected")->Compile(this);
+}
+
+ErrorCode PolicyCompiler::Error(int err) {
+  if (has_unsafe_traps_) {
+    // When inside an UnsafeTrap() callback, we want to allow all system calls.
+    // This means, we must conditionally disable the sandbox -- and that's not
+    // something that kernel-side BPF filters can do, as they cannot inspect
+    // any state other than the syscall arguments.
+    // But if we redirect all error handlers to user-space, then we can easily
+    // make this decision.
+    // The performance penalty for this extra round-trip to user-space is not
+    // actually that bad, as we only ever pay it for denied system calls; and a
+    // typical program has very few of these.
+    return Trap(ReturnErrno, reinterpret_cast<void*>(err), true);
+  }
+
+  return ErrorCode(err);
+}
+
+ErrorCode PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc,
+                               const void* aux,
+                               bool safe) {
+  uint16_t trap_id = registry_->Add(fnc, aux, safe);
+  return ErrorCode(trap_id, fnc, aux, safe);
+}
+
+bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) {
+  for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) {
+    if (sysno == kSyscallsRequiredForUnsafeTraps[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+ErrorCode PolicyCompiler::CondMaskedEqual(int argno,
+                                          ErrorCode::ArgType width,
+                                          uint64_t mask,
+                                          uint64_t value,
+                                          const ErrorCode& passed,
+                                          const ErrorCode& failed) {
+  return ErrorCode(argno,
+                   width,
+                   mask,
+                   value,
+                   &*conds_.insert(passed).first,
+                   &*conds_.insert(failed).first);
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.h b/sandbox/linux/bpf_dsl/policy_compiler.h
new file mode 100644
index 0000000..df38d4c
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/policy_compiler.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
+#define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class Policy;
+
+// PolicyCompiler implements the bpf_dsl compiler, allowing users to
+// transform bpf_dsl policies into BPF programs to be executed by the
+// Linux kernel.
+class SANDBOX_EXPORT PolicyCompiler {
+ public:
+  PolicyCompiler(const Policy* policy, TrapRegistry* registry);
+  ~PolicyCompiler();
+
+  // Compile registers any trap handlers needed by the policy and
+  // compiles the policy to a BPF program, which it returns.
+  scoped_ptr<CodeGen::Program> Compile(bool verify);
+
+  // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any
+  // system calls, regardless of policy.
+  void DangerousSetEscapePC(uint64_t escapepc);
+
+  // Error returns an ErrorCode to indicate the system call should fail with
+  // the specified error number.
+  ErrorCode Error(int err);
+
+  // Trap returns an ErrorCode to indicate the system call should
+  // instead invoke a trap handler.
+  ErrorCode Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
+
+  // UnsafeTraps require some syscalls to always be allowed.
+  // This helper function returns true for these calls.
+  static bool IsRequiredForUnsafeTrap(int sysno);
+
+  // We can also use ErrorCode to request evaluation of a conditional
+  // statement based on inspection of system call parameters.
+  // This method wrap an ErrorCode object around the conditional statement.
+  // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
+  // to "value"; if equal, then "passed" will be returned, otherwise "failed".
+  // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1)
+  // If it is outside this range, the sandbox treats the system call just
+  // the same as any other ABI violation (i.e. it aborts with an error
+  // message).
+  ErrorCode CondMaskedEqual(int argno,
+                            ErrorCode::ArgType is_32bit,
+                            uint64_t mask,
+                            uint64_t value,
+                            const ErrorCode& passed,
+                            const ErrorCode& failed);
+
+  // Returns the fatal ErrorCode that is used to indicate that somebody
+  // attempted to pass a 64bit value in a 32bit system call argument.
+  // This method is primarily needed for testing purposes.
+  ErrorCode Unexpected64bitArgument();
+
+ private:
+  struct Range;
+  typedef std::vector<Range> Ranges;
+  typedef std::set<ErrorCode, struct ErrorCode::LessThan> Conds;
+
+  // Used by CondExpressionHalf to track which half of the argument it's
+  // emitting instructions for.
+  enum ArgHalf {
+    LowerHalf,
+    UpperHalf,
+  };
+
+  // Compile the configured policy into a complete instruction sequence.
+  CodeGen::Node AssemblePolicy();
+
+  // Return an instruction sequence that checks the
+  // arch_seccomp_data's "arch" field is valid, and then passes
+  // control to |passed| if so.
+  CodeGen::Node CheckArch(CodeGen::Node passed);
+
+  // If |has_unsafe_traps_| is true, returns an instruction sequence
+  // that allows all system calls from |escapepc_|, and otherwise
+  // passes control to |rest|. Otherwise, simply returns |rest|.
+  CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
+
+  // Return an instruction sequence that loads and checks the system
+  // call number, performs a binary search, and then dispatches to an
+  // appropriate instruction sequence compiled from the current
+  // policy.
+  CodeGen::Node DispatchSyscall();
+
+  // Return an instruction sequence that checks the system call number
+  // (expected to be loaded in register A) and if valid, passes
+  // control to |passed| (with register A still valid).
+  CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
+
+  // Finds all the ranges of system calls that need to be handled. Ranges are
+  // sorted in ascending order of system call numbers. There are no gaps in the
+  // ranges. System calls with identical ErrorCodes are coalesced into a single
+  // range.
+  void FindRanges(Ranges* ranges);
+
+  // Returns a BPF program snippet that implements a jump table for the
+  // given range of system call numbers. This function runs recursively.
+  CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
+                                  Ranges::const_iterator stop);
+
+  // CompileResult compiles an individual result expression into a
+  // CodeGen node.
+  CodeGen::Node CompileResult(const ResultExpr& res);
+
+  // Returns a BPF program snippet that makes the BPF filter program exit
+  // with the given ErrorCode "err". N.B. the ErrorCode may very well be a
+  // conditional expression; if so, this function will recursively call
+  // CondExpression() and possibly RetExpression() to build a complex set of
+  // instructions.
+  CodeGen::Node RetExpression(const ErrorCode& err);
+
+  // Returns a BPF program that evaluates the conditional expression in
+  // "cond" and returns the appropriate value from the BPF filter program.
+  // This function recursively calls RetExpression(); it should only ever be
+  // called from RetExpression().
+  CodeGen::Node CondExpression(const ErrorCode& cond);
+
+  // Returns a BPF program that evaluates half of a conditional expression;
+  // it should only ever be called from CondExpression().
+  CodeGen::Node CondExpressionHalf(const ErrorCode& cond,
+                                   ArgHalf half,
+                                   CodeGen::Node passed,
+                                   CodeGen::Node failed);
+
+  const Policy* policy_;
+  TrapRegistry* registry_;
+  uint64_t escapepc_;
+
+  Conds conds_;
+  CodeGen gen_;
+  bool has_unsafe_traps_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
new file mode 100644
index 0000000..ca28c1d
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -0,0 +1,295 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
+#define SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
+
+#include <sys/cdefs.h>
+// Old Bionic versions do not have sys/user.h.  The if can be removed once we no
+// longer need to support these old Bionic versions.
+// All x86_64 builds use a new enough bionic to have sys/user.h.
+#if !defined(__BIONIC__) || defined(__x86_64__)
+#include <sys/types.h>  // Fix for gcc 4.7, make sure __uint16_t is defined.
+#if !defined(__native_client_nonsfi__)
+#include <sys/user.h>
+#endif
+#if defined(__mips__)
+// sys/user.h in eglibc misses size_t definition
+#include <stddef.h>
+#endif
+#endif
+
+#include "sandbox/linux/system_headers/linux_seccomp.h"  // For AUDIT_ARCH_*
+
+// Impose some reasonable maximum BPF program size. Realistically, the
+// kernel probably has much lower limits. But by limiting to less than
+// 30 bits, we can ease requirements on some of our data types.
+#define SECCOMP_MAX_PROGRAM_SIZE (1<<30)
+
+#if defined(__i386__)
+#define SECCOMP_ARCH        AUDIT_ARCH_I386
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, REG_EAX)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, REG_EAX)
+#define SECCOMP_IP(_ctx)        SECCOMP_REG(_ctx, REG_EIP)
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, REG_EBX)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, REG_ECX)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, REG_EDX)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, REG_ESI)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, REG_EDI)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, REG_EBP)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly.  This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
+struct regs_struct {
+  long int ebx;
+  long int ecx;
+  long int edx;
+  long int esi;
+  long int edi;
+  long int ebp;
+  long int eax;
+  long int xds;
+  long int xes;
+  long int xfs;
+  long int xgs;
+  long int orig_eax;
+  long int eip;
+  long int xcs;
+  long int eflags;
+  long int esp;
+  long int xss;
+};
+#else
+typedef user_regs_struct regs_struct;
+#endif
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).eax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_eax
+#define SECCOMP_PT_IP(_regs)      (_regs).eip
+#define SECCOMP_PT_PARM1(_regs)   (_regs).ebx
+#define SECCOMP_PT_PARM2(_regs)   (_regs).ecx
+#define SECCOMP_PT_PARM3(_regs)   (_regs).edx
+#define SECCOMP_PT_PARM4(_regs)   (_regs).esi
+#define SECCOMP_PT_PARM5(_regs)   (_regs).edi
+#define SECCOMP_PT_PARM6(_regs)   (_regs).ebp
+
+#elif defined(__x86_64__)
+#define SECCOMP_ARCH        AUDIT_ARCH_X86_64
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, REG_RAX)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, REG_RAX)
+#define SECCOMP_IP(_ctx)        SECCOMP_REG(_ctx, REG_RIP)
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, REG_RDI)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, REG_RSI)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, REG_RDX)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, REG_R10)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, REG_R8)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, REG_R9)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+typedef user_regs_struct regs_struct;
+#define SECCOMP_PT_RESULT(_regs)  (_regs).rax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_rax
+#define SECCOMP_PT_IP(_regs)      (_regs).rip
+#define SECCOMP_PT_PARM1(_regs)   (_regs).rdi
+#define SECCOMP_PT_PARM2(_regs)   (_regs).rsi
+#define SECCOMP_PT_PARM3(_regs)   (_regs).rdx
+#define SECCOMP_PT_PARM4(_regs)   (_regs).r10
+#define SECCOMP_PT_PARM5(_regs)   (_regs).r8
+#define SECCOMP_PT_PARM6(_regs)   (_regs).r9
+
+#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+#define SECCOMP_ARCH AUDIT_ARCH_ARM
+
+// ARM sigcontext_t is different from i386/x86_64.
+// See </arch/arm/include/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.arm_##_reg)
+// ARM EABI syscall convention.
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, r0)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, r7)
+#define SECCOMP_IP(_ctx)        SECCOMP_REG(_ctx, pc)
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, r0)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, r1)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, r2)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, r3)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, r4)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, r5)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly.  This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
+struct regs_struct {
+  unsigned long uregs[18];
+};
+#else
+typedef user_regs regs_struct;
+#endif
+
+#define REG_cpsr    uregs[16]
+#define REG_pc      uregs[15]
+#define REG_lr      uregs[14]
+#define REG_sp      uregs[13]
+#define REG_ip      uregs[12]
+#define REG_fp      uregs[11]
+#define REG_r10     uregs[10]
+#define REG_r9      uregs[9]
+#define REG_r8      uregs[8]
+#define REG_r7      uregs[7]
+#define REG_r6      uregs[6]
+#define REG_r5      uregs[5]
+#define REG_r4      uregs[4]
+#define REG_r3      uregs[3]
+#define REG_r2      uregs[2]
+#define REG_r1      uregs[1]
+#define REG_r0      uregs[0]
+#define REG_ORIG_r0 uregs[17]
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).REG_r0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_r7
+#define SECCOMP_PT_IP(_regs)      (_regs).REG_pc
+#define SECCOMP_PT_PARM1(_regs)   (_regs).REG_r0
+#define SECCOMP_PT_PARM2(_regs)   (_regs).REG_r1
+#define SECCOMP_PT_PARM3(_regs)   (_regs).REG_r2
+#define SECCOMP_PT_PARM4(_regs)   (_regs).REG_r3
+#define SECCOMP_PT_PARM5(_regs)   (_regs).REG_r4
+#define SECCOMP_PT_PARM6(_regs)   (_regs).REG_r5
+
+#elif defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+#define SECCOMP_ARCH        AUDIT_ARCH_MIPSEL
+#define SYSCALL_EIGHT_ARGS
+// MIPS sigcontext_t is different from i386/x86_64 and ARM.
+// See </arch/mips/include/uapi/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[_reg])
+// Based on MIPS o32 ABI syscall convention.
+// On MIPS, when indirect syscall is being made (syscall(__NR_foo)),
+// real identificator (__NR_foo) is not in v0, but in a0
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, 2)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, 2)
+#define SECCOMP_IP(_ctx)        (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, 5)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, 6)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, 7)
+// Only the first 4 arguments of syscall are in registers.
+// The rest are on the stack.
+#define SECCOMP_STACKPARM(_ctx, n)  (((long *)SECCOMP_REG(_ctx, 29))[(n)])
+#define SECCOMP_PARM5(_ctx)         SECCOMP_STACKPARM(_ctx, 4)
+#define SECCOMP_PARM6(_ctx)         SECCOMP_STACKPARM(_ctx, 5)
+#define SECCOMP_PARM7(_ctx)         SECCOMP_STACKPARM(_ctx, 6)
+#define SECCOMP_PARM8(_ctx)         SECCOMP_STACKPARM(_ctx, 7)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+// On Mips we don't have structures like user_regs or user_regs_struct in
+// sys/user.h that we could use, so we just define regs_struct directly.
+struct regs_struct {
+  unsigned long long regs[32];
+};
+
+#define REG_a3 regs[7]
+#define REG_a2 regs[6]
+#define REG_a1 regs[5]
+#define REG_a0 regs[4]
+#define REG_v1 regs[3]
+#define REG_v0 regs[2]
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).REG_v0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_v0
+#define SECCOMP_PT_PARM1(_regs)   (_regs).REG_a0
+#define SECCOMP_PT_PARM2(_regs)   (_regs).REG_a1
+#define SECCOMP_PT_PARM3(_regs)   (_regs).REG_a2
+#define SECCOMP_PT_PARM4(_regs)   (_regs).REG_a3
+
+#elif defined(__aarch64__)
+struct regs_struct {
+  unsigned long long regs[31];
+  unsigned long long sp;
+  unsigned long long pc;
+  unsigned long long pstate;
+};
+
+#define SECCOMP_ARCH AUDIT_ARCH_AARCH64
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.regs[_reg])
+
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 0)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 8)
+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 0)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 1)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 3)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, 5)
+
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX \
+  (offsetof(struct arch_seccomp_data, instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX \
+  (offsetof(struct arch_seccomp_data, instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) \
+  (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) \
+  (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0)
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).regs[0]
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).regs[8]
+#define SECCOMP_PT_IP(_regs) (_regs).pc
+#define SECCOMP_PT_PARM1(_regs) (_regs).regs[0]
+#define SECCOMP_PT_PARM2(_regs) (_regs).regs[1]
+#define SECCOMP_PT_PARM3(_regs) (_regs).regs[2]
+#define SECCOMP_PT_PARM4(_regs) (_regs).regs[3]
+#define SECCOMP_PT_PARM5(_regs) (_regs).regs[4]
+#define SECCOMP_PT_PARM6(_regs) (_regs).regs[5]
+#else
+#error Unsupported target platform
+
+#endif
+
+#endif  // SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
diff --git a/sandbox/linux/bpf_dsl/syscall_set.cc b/sandbox/linux/bpf_dsl/syscall_set.cc
new file mode 100644
index 0000000..47810e9
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/syscall_set.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 "sandbox/linux/bpf_dsl/syscall_set.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
+
+namespace sandbox {
+
+namespace {
+
+#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+// This is true for Mips O32 ABI.
+static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000");
+#else
+// This true for supported architectures (Intel and ARM EABI).
+static_assert(MIN_SYSCALL == 0u,
+              "min syscall should always be zero");
+#endif
+
+// SyscallRange represents an inclusive range of system call numbers.
+struct SyscallRange {
+  uint32_t first;
+  uint32_t last;
+};
+
+const SyscallRange kValidSyscallRanges[] = {
+    // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL
+    // on Intel architectures, but leaves room for private syscalls on ARM.
+    {MIN_SYSCALL, MAX_PUBLIC_SYSCALL},
+#if defined(__arm__)
+    // ARM EABI includes "ARM private" system calls starting at
+    // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at
+    // MIN_GHOST_SYSCALL.
+    {MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL},
+    {MIN_GHOST_SYSCALL, MAX_SYSCALL},
+#endif
+};
+
+}  // namespace
+
+SyscallSet::Iterator SyscallSet::begin() const {
+  return Iterator(set_, false);
+}
+
+SyscallSet::Iterator SyscallSet::end() const {
+  return Iterator(set_, true);
+}
+
+bool SyscallSet::IsValid(uint32_t num) {
+  for (const SyscallRange& range : kValidSyscallRanges) {
+    if (num >= range.first && num <= range.last) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) {
+  return (lhs.set_ == rhs.set_);
+}
+
+SyscallSet::Iterator::Iterator(Set set, bool done)
+    : set_(set), done_(done), num_(0) {
+  // If the set doesn't contain 0, we need to skip to the next element.
+  if (!done && set_ == (IsValid(num_) ? Set::INVALID_ONLY : Set::VALID_ONLY)) {
+    ++*this;
+  }
+}
+
+uint32_t SyscallSet::Iterator::operator*() const {
+  DCHECK(!done_);
+  return num_;
+}
+
+SyscallSet::Iterator& SyscallSet::Iterator::operator++() {
+  DCHECK(!done_);
+
+  num_ = NextSyscall();
+  if (num_ == 0) {
+    done_ = true;
+  }
+
+  return *this;
+}
+
+// NextSyscall returns the next system call in the iterated system
+// call set after |num_|, or 0 if no such system call exists.
+uint32_t SyscallSet::Iterator::NextSyscall() const {
+  const bool want_valid = (set_ != Set::INVALID_ONLY);
+  const bool want_invalid = (set_ != Set::VALID_ONLY);
+
+  for (const SyscallRange& range : kValidSyscallRanges) {
+    if (want_invalid && range.first > 0 && num_ < range.first - 1) {
+      // Even when iterating invalid syscalls, we only include the end points;
+      // so skip directly to just before the next (valid) range.
+      return range.first - 1;
+    }
+    if (want_valid && num_ < range.first) {
+      return range.first;
+    }
+    if (want_valid && num_ < range.last) {
+      return num_ + 1;
+    }
+    if (want_invalid && num_ <= range.last) {
+      return range.last + 1;
+    }
+  }
+
+  if (want_invalid) {
+    // BPF programs only ever operate on unsigned quantities. So,
+    // that's how we iterate; we return values from
+    // 0..0xFFFFFFFFu. But there are places, where the kernel might
+    // interpret system call numbers as signed quantities, so the
+    // boundaries between signed and unsigned values are potential
+    // problem cases. We want to explicitly return these values from
+    // our iterator.
+    if (num_ < 0x7FFFFFFFu)
+      return 0x7FFFFFFFu;
+    if (num_ < 0x80000000u)
+      return 0x80000000u;
+
+    if (num_ < 0xFFFFFFFFu)
+      return 0xFFFFFFFFu;
+  }
+
+  return 0;
+}
+
+bool operator==(const SyscallSet::Iterator& lhs,
+                const SyscallSet::Iterator& rhs) {
+  DCHECK(lhs.set_ == rhs.set_);
+  return (lhs.done_ == rhs.done_) && (lhs.num_ == rhs.num_);
+}
+
+bool operator!=(const SyscallSet::Iterator& lhs,
+                const SyscallSet::Iterator& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/syscall_set.h b/sandbox/linux/bpf_dsl/syscall_set.h
new file mode 100644
index 0000000..b9f076d
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/syscall_set.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
+#define SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
+
+#include <stdint.h>
+
+#include <iterator>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Iterates over the entire system call range from 0..0xFFFFFFFFu. This
+// iterator is aware of how system calls look like and will skip quickly
+// over ranges that can't contain system calls. It iterates more slowly
+// whenever it reaches a range that is potentially problematic, returning
+// the last invalid value before a valid range of system calls, and the
+// first invalid value after a valid range of syscalls. It iterates over
+// individual values whenever it is in the normal range for system calls
+// (typically MIN_SYSCALL..MAX_SYSCALL).
+//
+// Example usage:
+//   for (uint32_t sysnum : SyscallSet::All()) {
+//     // Do something with sysnum.
+//   }
+class SANDBOX_EXPORT SyscallSet {
+ public:
+  class Iterator;
+
+  SyscallSet(const SyscallSet& ss) : set_(ss.set_) {}
+  ~SyscallSet() {}
+
+  Iterator begin() const;
+  Iterator end() const;
+
+  // All returns a SyscallSet that contains both valid and invalid
+  // system call numbers.
+  static SyscallSet All() { return SyscallSet(Set::ALL); }
+
+  // ValidOnly returns a SyscallSet that contains only valid system
+  // call numbers.
+  static SyscallSet ValidOnly() { return SyscallSet(Set::VALID_ONLY); }
+
+  // InvalidOnly returns a SyscallSet that contains only invalid
+  // system call numbers, but still omits numbers in the middle of a
+  // range of invalid system call numbers.
+  static SyscallSet InvalidOnly() { return SyscallSet(Set::INVALID_ONLY); }
+
+  // IsValid returns whether |num| specifies a valid system call
+  // number.
+  static bool IsValid(uint32_t num);
+
+ private:
+  enum class Set { ALL, VALID_ONLY, INVALID_ONLY };
+
+  explicit SyscallSet(Set set) : set_(set) {}
+
+  Set set_;
+
+  friend bool operator==(const SyscallSet&, const SyscallSet&);
+  DISALLOW_ASSIGN(SyscallSet);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet& lhs, const SyscallSet& rhs);
+
+// Iterator provides C++ input iterator semantics for traversing a
+// SyscallSet.
+class SyscallSet::Iterator
+    : public std::iterator<std::input_iterator_tag, uint32_t> {
+ public:
+  Iterator(const Iterator& it)
+      : set_(it.set_), done_(it.done_), num_(it.num_) {}
+  ~Iterator() {}
+
+  uint32_t operator*() const;
+  Iterator& operator++();
+
+ private:
+  Iterator(Set set, bool done);
+
+  uint32_t NextSyscall() const;
+
+  Set set_;
+  bool done_;
+  uint32_t num_;
+
+  friend SyscallSet;
+  friend bool operator==(const Iterator&, const Iterator&);
+  DISALLOW_ASSIGN(Iterator);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet::Iterator& lhs,
+                               const SyscallSet::Iterator& rhs);
+SANDBOX_EXPORT bool operator!=(const SyscallSet::Iterator& lhs,
+                               const SyscallSet::Iterator& rhs);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
diff --git a/sandbox/linux/bpf_dsl/syscall_set_unittest.cc b/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
new file mode 100644
index 0000000..fafb6f6
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+
+#include <stdint.h>
+
+#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+namespace {
+
+const SyscallSet kSyscallSets[] = {
+    SyscallSet::All(),
+    SyscallSet::InvalidOnly(),
+};
+
+SANDBOX_TEST(SyscallSet, Monotonous) {
+  for (const SyscallSet& set : kSyscallSets) {
+    uint32_t prev = 0;
+    bool have_prev = false;
+    for (uint32_t sysnum : set) {
+      if (have_prev) {
+        SANDBOX_ASSERT(sysnum > prev);
+      } else if (set == SyscallSet::All()) {
+        // The iterator should start at 0.
+        SANDBOX_ASSERT(sysnum == 0);
+      }
+
+      prev = sysnum;
+      have_prev = true;
+    }
+
+    // The iterator should always return 0xFFFFFFFFu as the last value.
+    SANDBOX_ASSERT(have_prev);
+    SANDBOX_ASSERT(prev == 0xFFFFFFFFu);
+  }
+}
+
+// AssertRange checks that SyscallIterator produces all system call
+// numbers in the inclusive range [min, max].
+void AssertRange(uint32_t min, uint32_t max) {
+  SANDBOX_ASSERT(min < max);
+  uint32_t prev = min - 1;
+  for (uint32_t sysnum : SyscallSet::All()) {
+    if (sysnum >= min && sysnum <= max) {
+      SANDBOX_ASSERT(prev == sysnum - 1);
+      prev = sysnum;
+    }
+  }
+  SANDBOX_ASSERT(prev == max);
+}
+
+SANDBOX_TEST(SyscallSet, ValidSyscallRanges) {
+  AssertRange(MIN_SYSCALL, MAX_PUBLIC_SYSCALL);
+#if defined(__arm__)
+  AssertRange(MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL);
+  AssertRange(MIN_GHOST_SYSCALL, MAX_SYSCALL);
+#endif
+}
+
+SANDBOX_TEST(SyscallSet, InvalidSyscalls) {
+  static const uint32_t kExpected[] = {
+#if defined(__mips__)
+    0,
+    MIN_SYSCALL - 1,
+#endif
+    MAX_PUBLIC_SYSCALL + 1,
+#if defined(__arm__)
+    MIN_PRIVATE_SYSCALL - 1,
+    MAX_PRIVATE_SYSCALL + 1,
+    MIN_GHOST_SYSCALL - 1,
+    MAX_SYSCALL + 1,
+#endif
+    0x7FFFFFFFu,
+    0x80000000u,
+    0xFFFFFFFFu,
+  };
+
+  for (const SyscallSet& set : kSyscallSets) {
+    size_t i = 0;
+    for (uint32_t sysnum : set) {
+      if (!SyscallSet::IsValid(sysnum)) {
+        SANDBOX_ASSERT(i < arraysize(kExpected));
+        SANDBOX_ASSERT(kExpected[i] == sysnum);
+        ++i;
+      }
+    }
+    SANDBOX_ASSERT(i == arraysize(kExpected));
+  }
+}
+
+SANDBOX_TEST(SyscallSet, ValidOnlyIsOnlyValid) {
+  for (uint32_t sysnum : SyscallSet::ValidOnly()) {
+    SANDBOX_ASSERT(SyscallSet::IsValid(sysnum));
+  }
+}
+
+SANDBOX_TEST(SyscallSet, InvalidOnlyIsOnlyInvalid) {
+  for (uint32_t sysnum : SyscallSet::InvalidOnly()) {
+    SANDBOX_ASSERT(!SyscallSet::IsValid(sysnum));
+  }
+}
+
+SANDBOX_TEST(SyscallSet, AllIsValidOnlyPlusInvalidOnly) {
+  std::vector<uint32_t> merged;
+  const SyscallSet valid_only = SyscallSet::ValidOnly();
+  const SyscallSet invalid_only = SyscallSet::InvalidOnly();
+  std::merge(valid_only.begin(),
+             valid_only.end(),
+             invalid_only.begin(),
+             invalid_only.end(),
+             std::back_inserter(merged));
+
+  const SyscallSet all = SyscallSet::All();
+  SANDBOX_ASSERT(merged == std::vector<uint32_t>(all.begin(), all.end()));
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/trap_registry.h b/sandbox/linux/bpf_dsl/trap_registry.h
new file mode 100644
index 0000000..0a5d2f1
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/trap_registry.h
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
+#define SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This must match the kernel's seccomp_data structure.
+struct arch_seccomp_data {
+  int nr;
+  uint32_t arch;
+  uint64_t instruction_pointer;
+  uint64_t args[6];
+};
+
+namespace bpf_dsl {
+
+// TrapRegistry provides an interface for registering "trap handlers"
+// by associating them with non-zero 16-bit trap IDs. Trap IDs should
+// remain valid for the lifetime of the trap registry.
+class SANDBOX_EXPORT TrapRegistry {
+ public:
+  // TrapFnc is a pointer to a function that fulfills the trap handler
+  // function signature.
+  //
+  // Trap handlers follow the calling convention of native system
+  // calls; e.g., to report an error, they return an exit code in the
+  // range -1..-4096 instead of directly modifying errno. However,
+  // modifying errno is harmless, as the original value will be
+  // restored afterwards.
+  //
+  // Trap handlers are executed from signal context and possibly an
+  // async-signal context, so they must be async-signal safe:
+  // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+  typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void* aux);
+
+  // Add registers the specified trap handler tuple and returns a
+  // non-zero trap ID that uniquely identifies the tuple for the life
+  // time of the trap registry. If the same tuple is registered
+  // multiple times, the same value will be returned each time.
+  virtual uint16_t Add(TrapFnc fnc, const void* aux, bool safe) = 0;
+
+  // EnableUnsafeTraps tries to enable unsafe traps and returns
+  // whether it was successful. This is a one-way operation.
+  //
+  // CAUTION: Enabling unsafe traps effectively defeats the security
+  // guarantees provided by the sandbox policy. TrapRegistry
+  // implementations should ensure unsafe traps are only enabled
+  // during testing.
+  virtual bool EnableUnsafeTraps() = 0;
+
+ protected:
+  TrapRegistry() {}
+
+  // TrapRegistry's destructor is intentionally non-virtual so that
+  // implementations can omit their destructor.  Instead we protect against
+  // misuse by marking it protected.
+  ~TrapRegistry() {}
+
+  DISALLOW_COPY_AND_ASSIGN(TrapRegistry);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
diff --git a/sandbox/linux/bpf_dsl/verifier.cc b/sandbox/linux/bpf_dsl/verifier.cc
new file mode 100644
index 0000000..417c663
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/verifier.cc
@@ -0,0 +1,396 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/verifier.h"
+
+#include <string.h>
+
+#include <limits>
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+const uint64_t kLower32Bits = std::numeric_limits<uint32_t>::max();
+const uint64_t kUpper32Bits = static_cast<uint64_t>(kLower32Bits) << 32;
+
+struct State {
+  State(const std::vector<struct sock_filter>& p,
+        const struct arch_seccomp_data& d)
+      : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {}
+  const std::vector<struct sock_filter>& program;
+  const struct arch_seccomp_data& data;
+  unsigned int ip;
+  uint32_t accumulator;
+  bool acc_is_valid;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(State);
+};
+
+uint32_t EvaluateErrorCode(bpf_dsl::PolicyCompiler* compiler,
+                           const ErrorCode& code,
+                           const struct arch_seccomp_data& data) {
+  if (code.error_type() == ErrorCode::ET_SIMPLE ||
+      code.error_type() == ErrorCode::ET_TRAP) {
+    return code.err();
+  } else if (code.error_type() == ErrorCode::ET_COND) {
+    if (code.width() == ErrorCode::TP_32BIT &&
+        (data.args[code.argno()] >> 32) &&
+        (data.args[code.argno()] & 0xFFFFFFFF80000000ull) !=
+            0xFFFFFFFF80000000ull) {
+      return compiler->Unexpected64bitArgument().err();
+    }
+    bool equal = (data.args[code.argno()] & code.mask()) == code.value();
+    return EvaluateErrorCode(compiler, equal ? *code.passed() : *code.failed(),
+                             data);
+  } else {
+    return SECCOMP_RET_INVALID;
+  }
+}
+
+bool VerifyErrorCode(bpf_dsl::PolicyCompiler* compiler,
+                     const std::vector<struct sock_filter>& program,
+                     struct arch_seccomp_data* data,
+                     const ErrorCode& root_code,
+                     const ErrorCode& code,
+                     const char** err) {
+  if (code.error_type() == ErrorCode::ET_SIMPLE ||
+      code.error_type() == ErrorCode::ET_TRAP) {
+    const uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err);
+    if (*err) {
+      return false;
+    }
+    const uint32_t policy_ret = EvaluateErrorCode(compiler, root_code, *data);
+    if (computed_ret != policy_ret) {
+      // For efficiency's sake, we'd much rather compare "computed_ret"
+      // against "code.err()". This works most of the time, but it doesn't
+      // always work for nested conditional expressions. The test values
+      // that we generate on the fly to probe expressions can trigger
+      // code flow decisions in multiple nodes of the decision tree, and the
+      // only way to compute the correct error code in that situation is by
+      // calling EvaluateErrorCode().
+      *err = "Exit code from BPF program doesn't match";
+      return false;
+    }
+  } else if (code.error_type() == ErrorCode::ET_COND) {
+    if (code.argno() < 0 || code.argno() >= 6) {
+      *err = "Invalid argument number in error code";
+      return false;
+    }
+
+    // TODO(mdempsky): The test values generated here try to provide good
+    // coverage for generated BPF instructions while avoiding combinatorial
+    // explosion on large policies. Ideally we would instead take a fuzzing-like
+    // approach and generate a bounded number of test cases regardless of policy
+    // size.
+
+    // Verify that we can check a value for simple equality.
+    data->args[code.argno()] = code.value();
+    if (!VerifyErrorCode(compiler, program, data, root_code, *code.passed(),
+                         err)) {
+      return false;
+    }
+
+    // If mask ignores any bits, verify that setting those bits is still
+    // detected as equality.
+    uint64_t ignored_bits = ~code.mask();
+    if (code.width() == ErrorCode::TP_32BIT) {
+      ignored_bits = static_cast<uint32_t>(ignored_bits);
+    }
+    if ((ignored_bits & kLower32Bits) != 0) {
+      data->args[code.argno()] = code.value() | (ignored_bits & kLower32Bits);
+      if (!VerifyErrorCode(compiler, program, data, root_code, *code.passed(),
+                           err)) {
+        return false;
+      }
+    }
+    if ((ignored_bits & kUpper32Bits) != 0) {
+      data->args[code.argno()] = code.value() | (ignored_bits & kUpper32Bits);
+      if (!VerifyErrorCode(compiler, program, data, root_code, *code.passed(),
+                           err)) {
+        return false;
+      }
+    }
+
+    // Verify that changing bits included in the mask is detected as inequality.
+    if ((code.mask() & kLower32Bits) != 0) {
+      data->args[code.argno()] = code.value() ^ (code.mask() & kLower32Bits);
+      if (!VerifyErrorCode(compiler, program, data, root_code, *code.failed(),
+                           err)) {
+        return false;
+      }
+    }
+    if ((code.mask() & kUpper32Bits) != 0) {
+      data->args[code.argno()] = code.value() ^ (code.mask() & kUpper32Bits);
+      if (!VerifyErrorCode(compiler, program, data, root_code, *code.failed(),
+                           err)) {
+        return false;
+      }
+    }
+
+    if (code.width() == ErrorCode::TP_32BIT) {
+      // For 32-bit system call arguments, we emit additional instructions to
+      // validate the upper 32-bits. Here we test that validation.
+
+      // Arbitrary 64-bit values should be rejected.
+      data->args[code.argno()] = 1ULL << 32;
+      if (!VerifyErrorCode(compiler, program, data, root_code,
+                           compiler->Unexpected64bitArgument(), err)) {
+        return false;
+      }
+
+      // Upper 32-bits set without the MSB of the lower 32-bits set should be
+      // rejected too.
+      data->args[code.argno()] = kUpper32Bits;
+      if (!VerifyErrorCode(compiler, program, data, root_code,
+                           compiler->Unexpected64bitArgument(), err)) {
+        return false;
+      }
+    }
+  } else {
+    *err = "Attempting to return invalid error code from BPF program";
+    return false;
+  }
+  return true;
+}
+
+void Ld(State* state, const struct sock_filter& insn, const char** err) {
+  if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS ||
+      insn.jt != 0 || insn.jf != 0) {
+    *err = "Invalid BPF_LD instruction";
+    return;
+  }
+  if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
+    // We only allow loading of properly aligned 32bit quantities.
+    memcpy(&state->accumulator,
+           reinterpret_cast<const char*>(&state->data) + insn.k, 4);
+  } else {
+    *err = "Invalid operand in BPF_LD instruction";
+    return;
+  }
+  state->acc_is_valid = true;
+  return;
+}
+
+void Jmp(State* state, const struct sock_filter& insn, const char** err) {
+  if (BPF_OP(insn.code) == BPF_JA) {
+    if (state->ip + insn.k + 1 >= state->program.size() ||
+        state->ip + insn.k + 1 <= state->ip) {
+    compilation_failure:
+      *err = "Invalid BPF_JMP instruction";
+      return;
+    }
+    state->ip += insn.k;
+  } else {
+    if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid ||
+        state->ip + insn.jt + 1 >= state->program.size() ||
+        state->ip + insn.jf + 1 >= state->program.size()) {
+      goto compilation_failure;
+    }
+    switch (BPF_OP(insn.code)) {
+      case BPF_JEQ:
+        if (state->accumulator == insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      case BPF_JGT:
+        if (state->accumulator > insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      case BPF_JGE:
+        if (state->accumulator >= insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      case BPF_JSET:
+        if (state->accumulator & insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      default:
+        goto compilation_failure;
+    }
+  }
+}
+
+uint32_t Ret(State*, const struct sock_filter& insn, const char** err) {
+  if (BPF_SRC(insn.code) != BPF_K) {
+    *err = "Invalid BPF_RET instruction";
+    return 0;
+  }
+  return insn.k;
+}
+
+void Alu(State* state, const struct sock_filter& insn, const char** err) {
+  if (BPF_OP(insn.code) == BPF_NEG) {
+    state->accumulator = -state->accumulator;
+    return;
+  } else {
+    if (BPF_SRC(insn.code) != BPF_K) {
+      *err = "Unexpected source operand in arithmetic operation";
+      return;
+    }
+    switch (BPF_OP(insn.code)) {
+      case BPF_ADD:
+        state->accumulator += insn.k;
+        break;
+      case BPF_SUB:
+        state->accumulator -= insn.k;
+        break;
+      case BPF_MUL:
+        state->accumulator *= insn.k;
+        break;
+      case BPF_DIV:
+        if (!insn.k) {
+          *err = "Illegal division by zero";
+          break;
+        }
+        state->accumulator /= insn.k;
+        break;
+      case BPF_MOD:
+        if (!insn.k) {
+          *err = "Illegal division by zero";
+          break;
+        }
+        state->accumulator %= insn.k;
+        break;
+      case BPF_OR:
+        state->accumulator |= insn.k;
+        break;
+      case BPF_XOR:
+        state->accumulator ^= insn.k;
+        break;
+      case BPF_AND:
+        state->accumulator &= insn.k;
+        break;
+      case BPF_LSH:
+        if (insn.k > 32) {
+          *err = "Illegal shift operation";
+          break;
+        }
+        state->accumulator <<= insn.k;
+        break;
+      case BPF_RSH:
+        if (insn.k > 32) {
+          *err = "Illegal shift operation";
+          break;
+        }
+        state->accumulator >>= insn.k;
+        break;
+      default:
+        *err = "Invalid operator in arithmetic operation";
+        break;
+    }
+  }
+}
+
+}  // namespace
+
+bool Verifier::VerifyBPF(bpf_dsl::PolicyCompiler* compiler,
+                         const std::vector<struct sock_filter>& program,
+                         const bpf_dsl::Policy& policy,
+                         const char** err) {
+  *err = NULL;
+  for (uint32_t sysnum : SyscallSet::All()) {
+    // We ideally want to iterate over the full system call range and values
+    // just above and just below this range. This gives us the full result set
+    // of the "evaluators".
+    // On Intel systems, this can fail in a surprising way, as a cleared bit 30
+    // indicates either i386 or x86-64; and a set bit 30 indicates x32. And
+    // unless we pay attention to setting this bit correctly, an early check in
+    // our BPF program will make us fail with a misleading error code.
+    struct arch_seccomp_data data = {static_cast<int>(sysnum),
+                                     static_cast<uint32_t>(SECCOMP_ARCH)};
+#if defined(__i386__) || defined(__x86_64__)
+#if defined(__x86_64__) && defined(__ILP32__)
+    if (!(sysnum & 0x40000000u)) {
+      continue;
+    }
+#else
+    if (sysnum & 0x40000000u) {
+      continue;
+    }
+#endif
+#endif
+    ErrorCode code = SyscallSet::IsValid(sysnum)
+                         ? policy.EvaluateSyscall(sysnum)->Compile(compiler)
+                         : policy.InvalidSyscall()->Compile(compiler);
+    if (!VerifyErrorCode(compiler, program, &data, code, code, err)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
+                               const struct arch_seccomp_data& data,
+                               const char** err) {
+  *err = NULL;
+  if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
+    *err = "Invalid program length";
+    return 0;
+  }
+  for (State state(program, data); !*err; ++state.ip) {
+    if (state.ip >= program.size()) {
+      *err = "Invalid instruction pointer in BPF program";
+      break;
+    }
+    const struct sock_filter& insn = program[state.ip];
+    switch (BPF_CLASS(insn.code)) {
+      case BPF_LD:
+        Ld(&state, insn, err);
+        break;
+      case BPF_JMP:
+        Jmp(&state, insn, err);
+        break;
+      case BPF_RET: {
+        uint32_t r = Ret(&state, insn, err);
+        switch (r & SECCOMP_RET_ACTION) {
+          case SECCOMP_RET_TRAP:
+          case SECCOMP_RET_ERRNO:
+          case SECCOMP_RET_TRACE:
+          case SECCOMP_RET_ALLOW:
+            break;
+          case SECCOMP_RET_KILL:     // We don't ever generate this
+          case SECCOMP_RET_INVALID:  // Should never show up in BPF program
+          default:
+            *err = "Unexpected return code found in BPF program";
+            return 0;
+        }
+        return r;
+      }
+      case BPF_ALU:
+        Alu(&state, insn, err);
+        break;
+      default:
+        *err = "Unexpected instruction in BPF program";
+        break;
+    }
+  }
+  return 0;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/bpf_dsl/verifier.h b/sandbox/linux/bpf_dsl/verifier.h
new file mode 100644
index 0000000..b0435d1
--- /dev/null
+++ b/sandbox/linux/bpf_dsl/verifier.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
+#define SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+struct sock_filter;
+
+namespace sandbox {
+struct arch_seccomp_data;
+
+namespace bpf_dsl {
+class Policy;
+class PolicyCompiler;
+
+class SANDBOX_EXPORT Verifier {
+ public:
+  // Evaluate the BPF program for all possible inputs and verify that it
+  // computes the correct result. We use the "evaluators" to determine
+  // the full set of possible inputs that we have to iterate over.
+  // Returns success, if the BPF filter accurately reflects the rules
+  // set by the "evaluators".
+  // Upon success, "err" is set to NULL. Upon failure, it contains a static
+  // error message that does not need to be free()'d.
+  static bool VerifyBPF(bpf_dsl::PolicyCompiler* compiler,
+                        const std::vector<struct sock_filter>& program,
+                        const bpf_dsl::Policy& policy,
+                        const char** err);
+
+  // Evaluate a given BPF program for a particular set of system call
+  // parameters. If evaluation failed for any reason, "err" will be set to
+  // a non-NULL error string. Otherwise, the BPF program's result will be
+  // returned by the function and "err" is NULL.
+  // We do not actually implement the full BPF state machine, but only the
+  // parts that can actually be generated by our BPF compiler. If this code
+  // is used for purposes other than verifying the output of the sandbox's
+  // BPF compiler, we might have to extend this BPF interpreter.
+  static uint32_t EvaluateBPF(const std::vector<struct sock_filter>& program,
+                              const struct arch_seccomp_data& data,
+                              const char** err);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Verifier);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
diff --git a/sandbox/linux/integration_tests/DEPS b/sandbox/linux/integration_tests/DEPS
new file mode 100644
index 0000000..d50729c
--- /dev/null
+++ b/sandbox/linux/integration_tests/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+sandbox/linux/bpf_dsl",
+  "+sandbox/linux/seccomp-bpf",
+  "+sandbox/linux/services",
+  "+sandbox/linux/syscall_broker",
+  "+sandbox/linux/system_headers",
+]
diff --git a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
new file mode 100644
index 0000000..e884774
--- /dev/null
+++ b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
@@ -0,0 +1,2259 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#if defined(ANDROID)
+// Work-around for buggy headers in Android's NDK
+#define __user
+#endif
+#include <linux/futex.h>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/sys_info.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/scoped_temporary_file.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Workaround for Android's prctl.h file.
+#ifndef PR_GET_ENDIAN
+#define PR_GET_ENDIAN 19
+#endif
+#ifndef PR_CAPBSET_READ
+#define PR_CAPBSET_READ 23
+#define PR_CAPBSET_DROP 24
+#endif
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+const int kExpectedReturnValue = 42;
+const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
+
+// Set the global environment to allow the use of UnsafeTrap() policies.
+void EnableUnsafeTraps() {
+  // The use of UnsafeTrap() causes us to print a warning message. This is
+  // generally desirable, but it results in the unittest failing, as it doesn't
+  // expect any messages on "stderr". So, temporarily disable messages. The
+  // BPF_TEST() is guaranteed to turn messages back on, after the policy
+  // function has completed.
+  setenv(kSandboxDebuggingEnv, "t", 0);
+  Die::SuppressInfoMessages(true);
+}
+
+// BPF_TEST does a lot of the boiler-plate code around setting up a
+// policy and optional passing data between the caller, the policy and
+// any Trap() handlers. This is great for writing short and concise tests,
+// and it helps us accidentally forgetting any of the crucial steps in
+// setting up the sandbox. But it wouldn't hurt to have at least one test
+// that explicitly walks through all these steps.
+
+intptr_t IncreaseCounter(const struct arch_seccomp_data& args, void* aux) {
+  BPF_ASSERT(aux);
+  int* counter = static_cast<int*>(aux);
+  return (*counter)++;
+}
+
+class VerboseAPITestingPolicy : public Policy {
+ public:
+  explicit VerboseAPITestingPolicy(int* counter_ptr)
+      : counter_ptr_(counter_ptr) {}
+  ~VerboseAPITestingPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    if (sysno == __NR_uname) {
+      return Trap(IncreaseCounter, counter_ptr_);
+    }
+    return Allow();
+  }
+
+ private:
+  int* counter_ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(VerboseAPITestingPolicy);
+};
+
+SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(VerboseAPITesting)) {
+  if (SandboxBPF::SupportsSeccompSandbox(
+          SandboxBPF::SeccompLevel::SINGLE_THREADED)) {
+    static int counter = 0;
+
+    SandboxBPF sandbox(new VerboseAPITestingPolicy(&counter));
+    BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
+
+    BPF_ASSERT_EQ(0, counter);
+    BPF_ASSERT_EQ(0, syscall(__NR_uname, 0));
+    BPF_ASSERT_EQ(1, counter);
+    BPF_ASSERT_EQ(1, syscall(__NR_uname, 0));
+    BPF_ASSERT_EQ(2, counter);
+  }
+}
+
+// A simple blacklist test
+
+class BlacklistNanosleepPolicy : public Policy {
+ public:
+  BlacklistNanosleepPolicy() {}
+  ~BlacklistNanosleepPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    switch (sysno) {
+      case __NR_nanosleep:
+        return Error(EACCES);
+      default:
+        return Allow();
+    }
+  }
+
+  static void AssertNanosleepFails() {
+    const struct timespec ts = {0, 0};
+    errno = 0;
+    BPF_ASSERT_EQ(-1, HANDLE_EINTR(syscall(__NR_nanosleep, &ts, NULL)));
+    BPF_ASSERT_EQ(EACCES, errno);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlacklistNanosleepPolicy);
+};
+
+BPF_TEST_C(SandboxBPF, ApplyBasicBlacklistPolicy, BlacklistNanosleepPolicy) {
+  BlacklistNanosleepPolicy::AssertNanosleepFails();
+}
+
+BPF_TEST_C(SandboxBPF, UseVsyscall, BlacklistNanosleepPolicy) {
+  time_t current_time;
+  // time() is implemented as a vsyscall. With an older glibc, with
+  // vsyscall=emulate and some versions of the seccomp BPF patch
+  // we may get SIGKILL-ed. Detect this!
+  BPF_ASSERT_NE(static_cast<time_t>(-1), time(&current_time));
+}
+
+// Now do a simple whitelist test
+
+class WhitelistGetpidPolicy : public Policy {
+ public:
+  WhitelistGetpidPolicy() {}
+  ~WhitelistGetpidPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    switch (sysno) {
+      case __NR_getpid:
+      case __NR_exit_group:
+        return Allow();
+      default:
+        return Error(ENOMEM);
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WhitelistGetpidPolicy);
+};
+
+BPF_TEST_C(SandboxBPF, ApplyBasicWhitelistPolicy, WhitelistGetpidPolicy) {
+  // getpid() should be allowed
+  errno = 0;
+  BPF_ASSERT(sys_getpid() > 0);
+  BPF_ASSERT(errno == 0);
+
+  // getpgid() should be denied
+  BPF_ASSERT(getpgid(0) == -1);
+  BPF_ASSERT(errno == ENOMEM);
+}
+
+// A simple blacklist policy, with a SIGSYS handler
+intptr_t EnomemHandler(const struct arch_seccomp_data& args, void* aux) {
+  // We also check that the auxiliary data is correct
+  SANDBOX_ASSERT(aux);
+  *(static_cast<int*>(aux)) = kExpectedReturnValue;
+  return -ENOMEM;
+}
+
+class BlacklistNanosleepTrapPolicy : public Policy {
+ public:
+  explicit BlacklistNanosleepTrapPolicy(int* aux) : aux_(aux) {}
+  ~BlacklistNanosleepTrapPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    switch (sysno) {
+      case __NR_nanosleep:
+        return Trap(EnomemHandler, aux_);
+      default:
+        return Allow();
+    }
+  }
+
+ private:
+  int* aux_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlacklistNanosleepTrapPolicy);
+};
+
+BPF_TEST(SandboxBPF,
+         BasicBlacklistWithSigsys,
+         BlacklistNanosleepTrapPolicy,
+         int /* (*BPF_AUX) */) {
+  // getpid() should work properly
+  errno = 0;
+  BPF_ASSERT(sys_getpid() > 0);
+  BPF_ASSERT(errno == 0);
+
+  // Our Auxiliary Data, should be reset by the signal handler
+  *BPF_AUX = -1;
+  const struct timespec ts = {0, 0};
+  BPF_ASSERT(syscall(__NR_nanosleep, &ts, NULL) == -1);
+  BPF_ASSERT(errno == ENOMEM);
+
+  // We expect the signal handler to modify AuxData
+  BPF_ASSERT(*BPF_AUX == kExpectedReturnValue);
+}
+
+// A simple test that verifies we can return arbitrary errno values.
+
+class ErrnoTestPolicy : public Policy {
+ public:
+  ErrnoTestPolicy() {}
+  ~ErrnoTestPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ErrnoTestPolicy);
+};
+
+ResultExpr ErrnoTestPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  switch (sysno) {
+    case __NR_dup3:  // dup2 is a wrapper of dup3 in android
+#if defined(__NR_dup2)
+    case __NR_dup2:
+#endif
+      // Pretend that dup2() worked, but don't actually do anything.
+      return Error(0);
+    case __NR_setuid:
+#if defined(__NR_setuid32)
+    case __NR_setuid32:
+#endif
+      // Return errno = 1.
+      return Error(1);
+    case __NR_setgid:
+#if defined(__NR_setgid32)
+    case __NR_setgid32:
+#endif
+      // Return maximum errno value (typically 4095).
+      return Error(ErrorCode::ERR_MAX_ERRNO);
+    case __NR_uname:
+      // Return errno = 42;
+      return Error(42);
+    default:
+      return Allow();
+  }
+}
+
+BPF_TEST_C(SandboxBPF, ErrnoTest, ErrnoTestPolicy) {
+  // Verify that dup2() returns success, but doesn't actually run.
+  int fds[4];
+  BPF_ASSERT(pipe(fds) == 0);
+  BPF_ASSERT(pipe(fds + 2) == 0);
+  BPF_ASSERT(dup2(fds[2], fds[0]) == 0);
+  char buf[1] = {};
+  BPF_ASSERT(write(fds[1], "\x55", 1) == 1);
+  BPF_ASSERT(write(fds[3], "\xAA", 1) == 1);
+  BPF_ASSERT(read(fds[0], buf, 1) == 1);
+
+  // If dup2() executed, we will read \xAA, but it dup2() has been turned
+  // into a no-op by our policy, then we will read \x55.
+  BPF_ASSERT(buf[0] == '\x55');
+
+  // Verify that we can return the minimum and maximum errno values.
+  errno = 0;
+  BPF_ASSERT(setuid(0) == -1);
+  BPF_ASSERT(errno == 1);
+
+  // On Android, errno is only supported up to 255, otherwise errno
+  // processing is skipped.
+  // We work around this (crbug.com/181647).
+  if (sandbox::IsAndroid() && setgid(0) != -1) {
+    errno = 0;
+    BPF_ASSERT(setgid(0) == -ErrorCode::ERR_MAX_ERRNO);
+    BPF_ASSERT(errno == 0);
+  } else {
+    errno = 0;
+    BPF_ASSERT(setgid(0) == -1);
+    BPF_ASSERT(errno == ErrorCode::ERR_MAX_ERRNO);
+  }
+
+  // Finally, test an errno in between the minimum and maximum.
+  errno = 0;
+  struct utsname uts_buf;
+  BPF_ASSERT(uname(&uts_buf) == -1);
+  BPF_ASSERT(errno == 42);
+}
+
+// Testing the stacking of two sandboxes
+
+class StackingPolicyPartOne : public Policy {
+ public:
+  StackingPolicyPartOne() {}
+  ~StackingPolicyPartOne() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    switch (sysno) {
+      case __NR_getppid: {
+        const Arg<int> arg(0);
+        return If(arg == 0, Allow()).Else(Error(EPERM));
+      }
+      default:
+        return Allow();
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackingPolicyPartOne);
+};
+
+class StackingPolicyPartTwo : public Policy {
+ public:
+  StackingPolicyPartTwo() {}
+  ~StackingPolicyPartTwo() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    switch (sysno) {
+      case __NR_getppid: {
+        const Arg<int> arg(0);
+        return If(arg == 0, Error(EINVAL)).Else(Allow());
+      }
+      default:
+        return Allow();
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackingPolicyPartTwo);
+};
+
+BPF_TEST_C(SandboxBPF, StackingPolicy, StackingPolicyPartOne) {
+  errno = 0;
+  BPF_ASSERT(syscall(__NR_getppid, 0) > 0);
+  BPF_ASSERT(errno == 0);
+
+  BPF_ASSERT(syscall(__NR_getppid, 1) == -1);
+  BPF_ASSERT(errno == EPERM);
+
+  // Stack a second sandbox with its own policy. Verify that we can further
+  // restrict filters, but we cannot relax existing filters.
+  SandboxBPF sandbox(new StackingPolicyPartTwo());
+  BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
+
+  errno = 0;
+  BPF_ASSERT(syscall(__NR_getppid, 0) == -1);
+  BPF_ASSERT(errno == EINVAL);
+
+  BPF_ASSERT(syscall(__NR_getppid, 1) == -1);
+  BPF_ASSERT(errno == EPERM);
+}
+
+// A more complex, but synthetic policy. This tests the correctness of the BPF
+// program by iterating through all syscalls and checking for an errno that
+// depends on the syscall number. Unlike the Verifier, this exercises the BPF
+// interpreter in the kernel.
+
+// We try to make sure we exercise optimizations in the BPF compiler. We make
+// sure that the compiler can have an opportunity to coalesce syscalls with
+// contiguous numbers and we also make sure that disjoint sets can return the
+// same errno.
+int SysnoToRandomErrno(int sysno) {
+  // Small contiguous sets of 3 system calls return an errno equal to the
+  // index of that set + 1 (so that we never return a NUL errno).
+  return ((sysno & ~3) >> 2) % 29 + 1;
+}
+
+class SyntheticPolicy : public Policy {
+ public:
+  SyntheticPolicy() {}
+  ~SyntheticPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    if (sysno == __NR_exit_group || sysno == __NR_write) {
+      // exit_group() is special, we really need it to work.
+      // write() is needed for BPF_ASSERT() to report a useful error message.
+      return Allow();
+    }
+    return Error(SysnoToRandomErrno(sysno));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyntheticPolicy);
+};
+
+BPF_TEST_C(SandboxBPF, SyntheticPolicy, SyntheticPolicy) {
+  // Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int
+  // overflow.
+  BPF_ASSERT(std::numeric_limits<int>::max() - kExpectedReturnValue - 1 >=
+             static_cast<int>(MAX_PUBLIC_SYSCALL));
+
+  for (int syscall_number = static_cast<int>(MIN_SYSCALL);
+       syscall_number <= static_cast<int>(MAX_PUBLIC_SYSCALL);
+       ++syscall_number) {
+    if (syscall_number == __NR_exit_group || syscall_number == __NR_write) {
+      // exit_group() is special
+      continue;
+    }
+    errno = 0;
+    BPF_ASSERT(syscall(syscall_number) == -1);
+    BPF_ASSERT(errno == SysnoToRandomErrno(syscall_number));
+  }
+}
+
+#if defined(__arm__)
+// A simple policy that tests whether ARM private system calls are supported
+// by our BPF compiler and by the BPF interpreter in the kernel.
+
+// For ARM private system calls, return an errno equal to their offset from
+// MIN_PRIVATE_SYSCALL plus 1 (to avoid NUL errno).
+int ArmPrivateSysnoToErrno(int sysno) {
+  if (sysno >= static_cast<int>(MIN_PRIVATE_SYSCALL) &&
+      sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) {
+    return (sysno - MIN_PRIVATE_SYSCALL) + 1;
+  } else {
+    return ENOSYS;
+  }
+}
+
+class ArmPrivatePolicy : public Policy {
+ public:
+  ArmPrivatePolicy() {}
+  ~ArmPrivatePolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    // Start from |__ARM_NR_set_tls + 1| so as not to mess with actual
+    // ARM private system calls.
+    if (sysno >= static_cast<int>(__ARM_NR_set_tls + 1) &&
+        sysno <= static_cast<int>(MAX_PRIVATE_SYSCALL)) {
+      return Error(ArmPrivateSysnoToErrno(sysno));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArmPrivatePolicy);
+};
+
+BPF_TEST_C(SandboxBPF, ArmPrivatePolicy, ArmPrivatePolicy) {
+  for (int syscall_number = static_cast<int>(__ARM_NR_set_tls + 1);
+       syscall_number <= static_cast<int>(MAX_PRIVATE_SYSCALL);
+       ++syscall_number) {
+    errno = 0;
+    BPF_ASSERT(syscall(syscall_number) == -1);
+    BPF_ASSERT(errno == ArmPrivateSysnoToErrno(syscall_number));
+  }
+}
+#endif  // defined(__arm__)
+
+intptr_t CountSyscalls(const struct arch_seccomp_data& args, void* aux) {
+  // Count all invocations of our callback function.
+  ++*reinterpret_cast<int*>(aux);
+
+  // Verify that within the callback function all filtering is temporarily
+  // disabled.
+  BPF_ASSERT(sys_getpid() > 1);
+
+  // Verify that we can now call the underlying system call without causing
+  // infinite recursion.
+  return SandboxBPF::ForwardSyscall(args);
+}
+
+class GreyListedPolicy : public Policy {
+ public:
+  explicit GreyListedPolicy(int* aux) : aux_(aux) {
+    // Set the global environment for unsafe traps once.
+    EnableUnsafeTraps();
+  }
+  ~GreyListedPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    // Some system calls must always be allowed, if our policy wants to make
+    // use of UnsafeTrap()
+    if (SandboxBPF::IsRequiredForUnsafeTrap(sysno)) {
+      return Allow();
+    } else if (sysno == __NR_getpid) {
+      // Disallow getpid()
+      return Error(EPERM);
+    } else {
+      // Allow (and count) all other system calls.
+      return UnsafeTrap(CountSyscalls, aux_);
+    }
+  }
+
+ private:
+  int* aux_;
+
+  DISALLOW_COPY_AND_ASSIGN(GreyListedPolicy);
+};
+
+BPF_TEST(SandboxBPF, GreyListedPolicy, GreyListedPolicy, int /* (*BPF_AUX) */) {
+  BPF_ASSERT(sys_getpid() == -1);
+  BPF_ASSERT(errno == EPERM);
+  BPF_ASSERT(*BPF_AUX == 0);
+  BPF_ASSERT(syscall(__NR_geteuid) == syscall(__NR_getuid));
+  BPF_ASSERT(*BPF_AUX == 2);
+  char name[17] = {};
+  BPF_ASSERT(!syscall(__NR_prctl,
+                      PR_GET_NAME,
+                      name,
+                      (void*)NULL,
+                      (void*)NULL,
+                      (void*)NULL));
+  BPF_ASSERT(*BPF_AUX == 3);
+  BPF_ASSERT(*name);
+}
+
+SANDBOX_TEST(SandboxBPF, EnableUnsafeTrapsInSigSysHandler) {
+  // Disabling warning messages that could confuse our test framework.
+  setenv(kSandboxDebuggingEnv, "t", 0);
+  Die::SuppressInfoMessages(true);
+
+  unsetenv(kSandboxDebuggingEnv);
+  SANDBOX_ASSERT(Trap::Registry()->EnableUnsafeTraps() == false);
+  setenv(kSandboxDebuggingEnv, "", 1);
+  SANDBOX_ASSERT(Trap::Registry()->EnableUnsafeTraps() == false);
+  setenv(kSandboxDebuggingEnv, "t", 1);
+  SANDBOX_ASSERT(Trap::Registry()->EnableUnsafeTraps() == true);
+}
+
+intptr_t PrctlHandler(const struct arch_seccomp_data& args, void*) {
+  if (args.args[0] == PR_CAPBSET_DROP && static_cast<int>(args.args[1]) == -1) {
+    // prctl(PR_CAPBSET_DROP, -1) is never valid. The kernel will always
+    // return an error. But our handler allows this call.
+    return 0;
+  } else {
+    return SandboxBPF::ForwardSyscall(args);
+  }
+}
+
+class PrctlPolicy : public Policy {
+ public:
+  PrctlPolicy() {}
+  ~PrctlPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    setenv(kSandboxDebuggingEnv, "t", 0);
+    Die::SuppressInfoMessages(true);
+
+    if (sysno == __NR_prctl) {
+      // Handle prctl() inside an UnsafeTrap()
+      return UnsafeTrap(PrctlHandler, NULL);
+    }
+
+    // Allow all other system calls.
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrctlPolicy);
+};
+
+BPF_TEST_C(SandboxBPF, ForwardSyscall, PrctlPolicy) {
+  // This call should never be allowed. But our policy will intercept it and
+  // let it pass successfully.
+  BPF_ASSERT(
+      !prctl(PR_CAPBSET_DROP, -1, (void*)NULL, (void*)NULL, (void*)NULL));
+
+  // Verify that the call will fail, if it makes it all the way to the kernel.
+  BPF_ASSERT(
+      prctl(PR_CAPBSET_DROP, -2, (void*)NULL, (void*)NULL, (void*)NULL) == -1);
+
+  // And verify that other uses of prctl() work just fine.
+  char name[17] = {};
+  BPF_ASSERT(!syscall(__NR_prctl,
+                      PR_GET_NAME,
+                      name,
+                      (void*)NULL,
+                      (void*)NULL,
+                      (void*)NULL));
+  BPF_ASSERT(*name);
+
+  // Finally, verify that system calls other than prctl() are completely
+  // unaffected by our policy.
+  struct utsname uts = {};
+  BPF_ASSERT(!uname(&uts));
+  BPF_ASSERT(!strcmp(uts.sysname, "Linux"));
+}
+
+intptr_t AllowRedirectedSyscall(const struct arch_seccomp_data& args, void*) {
+  return SandboxBPF::ForwardSyscall(args);
+}
+
+class RedirectAllSyscallsPolicy : public Policy {
+ public:
+  RedirectAllSyscallsPolicy() {}
+  ~RedirectAllSyscallsPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RedirectAllSyscallsPolicy);
+};
+
+ResultExpr RedirectAllSyscallsPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  setenv(kSandboxDebuggingEnv, "t", 0);
+  Die::SuppressInfoMessages(true);
+
+  // Some system calls must always be allowed, if our policy wants to make
+  // use of UnsafeTrap()
+  if (SandboxBPF::IsRequiredForUnsafeTrap(sysno))
+    return Allow();
+  return UnsafeTrap(AllowRedirectedSyscall, NULL);
+}
+
+#if !defined(ADDRESS_SANITIZER)
+// ASan does not allow changing the signal handler for SIGBUS, and treats it as
+// a fatal signal.
+
+int bus_handler_fd_ = -1;
+
+void SigBusHandler(int, siginfo_t* info, void* void_context) {
+  BPF_ASSERT(write(bus_handler_fd_, "\x55", 1) == 1);
+}
+
+BPF_TEST_C(SandboxBPF, SigBus, RedirectAllSyscallsPolicy) {
+  // We use the SIGBUS bit in the signal mask as a thread-local boolean
+  // value in the implementation of UnsafeTrap(). This is obviously a bit
+  // of a hack that could conceivably interfere with code that uses SIGBUS
+  // in more traditional ways. This test verifies that basic functionality
+  // of SIGBUS is not impacted, but it is certainly possibly to construe
+  // more complex uses of signals where our use of the SIGBUS mask is not
+  // 100% transparent. This is expected behavior.
+  int fds[2];
+  BPF_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  bus_handler_fd_ = fds[1];
+  struct sigaction sa = {};
+  sa.sa_sigaction = SigBusHandler;
+  sa.sa_flags = SA_SIGINFO;
+  BPF_ASSERT(sigaction(SIGBUS, &sa, NULL) == 0);
+  raise(SIGBUS);
+  char c = '\000';
+  BPF_ASSERT(read(fds[0], &c, 1) == 1);
+  BPF_ASSERT(close(fds[0]) == 0);
+  BPF_ASSERT(close(fds[1]) == 0);
+  BPF_ASSERT(c == 0x55);
+}
+#endif  // !defined(ADDRESS_SANITIZER)
+
+BPF_TEST_C(SandboxBPF, SigMask, RedirectAllSyscallsPolicy) {
+  // Signal masks are potentially tricky to handle. For instance, if we
+  // ever tried to update them from inside a Trap() or UnsafeTrap() handler,
+  // the call to sigreturn() at the end of the signal handler would undo
+  // all of our efforts. So, it makes sense to test that sigprocmask()
+  // works, even if we have a policy in place that makes use of UnsafeTrap().
+  // In practice, this works because we force sigprocmask() to be handled
+  // entirely in the kernel.
+  sigset_t mask0, mask1, mask2;
+
+  // Call sigprocmask() to verify that SIGUSR2 wasn't blocked, if we didn't
+  // change the mask (it shouldn't have been, as it isn't blocked by default
+  // in POSIX).
+  //
+  // Use SIGUSR2 because Android seems to use SIGUSR1 for some purpose.
+  sigemptyset(&mask0);
+  BPF_ASSERT(!sigprocmask(SIG_BLOCK, &mask0, &mask1));
+  BPF_ASSERT(!sigismember(&mask1, SIGUSR2));
+
+  // Try again, and this time we verify that we can block it. This
+  // requires a second call to sigprocmask().
+  sigaddset(&mask0, SIGUSR2);
+  BPF_ASSERT(!sigprocmask(SIG_BLOCK, &mask0, NULL));
+  BPF_ASSERT(!sigprocmask(SIG_BLOCK, NULL, &mask2));
+  BPF_ASSERT(sigismember(&mask2, SIGUSR2));
+}
+
+BPF_TEST_C(SandboxBPF, UnsafeTrapWithErrno, RedirectAllSyscallsPolicy) {
+  // An UnsafeTrap() (or for that matter, a Trap()) has to report error
+  // conditions by returning an exit code in the range -1..-4096. This
+  // should happen automatically if using ForwardSyscall(). If the TrapFnc()
+  // uses some other method to make system calls, then it is responsible
+  // for computing the correct return code.
+  // This test verifies that ForwardSyscall() does the correct thing.
+
+  // The glibc system wrapper will ultimately set errno for us. So, from normal
+  // userspace, all of this should be completely transparent.
+  errno = 0;
+  BPF_ASSERT(close(-1) == -1);
+  BPF_ASSERT(errno == EBADF);
+
+  // Explicitly avoid the glibc wrapper. This is not normally the way anybody
+  // would make system calls, but it allows us to verify that we don't
+  // accidentally mess with errno, when we shouldn't.
+  errno = 0;
+  struct arch_seccomp_data args = {};
+  args.nr = __NR_close;
+  args.args[0] = -1;
+  BPF_ASSERT(SandboxBPF::ForwardSyscall(args) == -EBADF);
+  BPF_ASSERT(errno == 0);
+}
+
+// Simple test demonstrating how to use SandboxBPF::Cond()
+
+class SimpleCondTestPolicy : public Policy {
+ public:
+  SimpleCondTestPolicy() {}
+  ~SimpleCondTestPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SimpleCondTestPolicy);
+};
+
+ResultExpr SimpleCondTestPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+
+  // We deliberately return unusual errno values upon failure, so that we
+  // can uniquely test for these values. In a "real" policy, you would want
+  // to return more traditional values.
+  int flags_argument_position = -1;
+  switch (sysno) {
+#if defined(__NR_open)
+    case __NR_open:
+      flags_argument_position = 1;
+#endif
+    case __NR_openat: {  // open can be a wrapper for openat(2).
+      if (sysno == __NR_openat)
+        flags_argument_position = 2;
+
+      // Allow opening files for reading, but don't allow writing.
+      static_assert(O_RDONLY == 0, "O_RDONLY must be all zero bits");
+      const Arg<int> flags(flags_argument_position);
+      return If((flags & O_ACCMODE) != 0, Error(EROFS)).Else(Allow());
+    }
+    case __NR_prctl: {
+      // Allow prctl(PR_SET_DUMPABLE) and prctl(PR_GET_DUMPABLE), but
+      // disallow everything else.
+      const Arg<int> option(0);
+      return If(option == PR_SET_DUMPABLE || option == PR_GET_DUMPABLE, Allow())
+          .Else(Error(ENOMEM));
+    }
+    default:
+      return Allow();
+  }
+}
+
+BPF_TEST_C(SandboxBPF, SimpleCondTest, SimpleCondTestPolicy) {
+  int fd;
+  BPF_ASSERT((fd = open("/proc/self/comm", O_RDWR)) == -1);
+  BPF_ASSERT(errno == EROFS);
+  BPF_ASSERT((fd = open("/proc/self/comm", O_RDONLY)) >= 0);
+  close(fd);
+
+  int ret;
+  BPF_ASSERT((ret = prctl(PR_GET_DUMPABLE)) >= 0);
+  BPF_ASSERT(prctl(PR_SET_DUMPABLE, 1 - ret) == 0);
+  BPF_ASSERT(prctl(PR_GET_ENDIAN, &ret) == -1);
+  BPF_ASSERT(errno == ENOMEM);
+}
+
+// This test exercises the SandboxBPF::Cond() method by building a complex
+// tree of conditional equality operations. It then makes system calls and
+// verifies that they return the values that we expected from our BPF
+// program.
+class EqualityStressTest {
+ public:
+  EqualityStressTest() {
+    // We want a deterministic test
+    srand(0);
+
+    // Iterates over system call numbers and builds a random tree of
+    // equality tests.
+    // We are actually constructing a graph of ArgValue objects. This
+    // graph will later be used to a) compute our sandbox policy, and
+    // b) drive the code that verifies the output from the BPF program.
+    static_assert(
+        kNumTestCases < (int)(MAX_PUBLIC_SYSCALL - MIN_SYSCALL - 10),
+        "kNumTestCases must be significantly smaller than the number "
+        "of system calls");
+    for (int sysno = MIN_SYSCALL, end = kNumTestCases; sysno < end; ++sysno) {
+      if (IsReservedSyscall(sysno)) {
+        // Skip reserved system calls. This ensures that our test frame
+        // work isn't impacted by the fact that we are overriding
+        // a lot of different system calls.
+        ++end;
+        arg_values_.push_back(NULL);
+      } else {
+        arg_values_.push_back(
+            RandomArgValue(rand() % kMaxArgs, 0, rand() % kMaxArgs));
+      }
+    }
+  }
+
+  ~EqualityStressTest() {
+    for (std::vector<ArgValue*>::iterator iter = arg_values_.begin();
+         iter != arg_values_.end();
+         ++iter) {
+      DeleteArgValue(*iter);
+    }
+  }
+
+  ResultExpr Policy(int sysno) {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    if (sysno < 0 || sysno >= (int)arg_values_.size() ||
+        IsReservedSyscall(sysno)) {
+      // We only return ErrorCode values for the system calls that
+      // are part of our test data. Every other system call remains
+      // allowed.
+      return Allow();
+    } else {
+      // ToErrorCode() turns an ArgValue object into an ErrorCode that is
+      // suitable for use by a sandbox policy.
+      return ToErrorCode(arg_values_[sysno]);
+    }
+  }
+
+  void VerifyFilter() {
+    // Iterate over all system calls. Skip the system calls that have
+    // previously been determined as being reserved.
+    for (int sysno = 0; sysno < (int)arg_values_.size(); ++sysno) {
+      if (!arg_values_[sysno]) {
+        // Skip reserved system calls.
+        continue;
+      }
+      // Verify that system calls return the values that we expect them to
+      // return. This involves passing different combinations of system call
+      // parameters in order to exercise all possible code paths through the
+      // BPF filter program.
+      // We arbitrarily start by setting all six system call arguments to
+      // zero. And we then recursive traverse our tree of ArgValues to
+      // determine the necessary combinations of parameters.
+      intptr_t args[6] = {};
+      Verify(sysno, args, *arg_values_[sysno]);
+    }
+  }
+
+ private:
+  struct ArgValue {
+    int argno;  // Argument number to inspect.
+    int size;   // Number of test cases (must be > 0).
+    struct Tests {
+      uint32_t k_value;            // Value to compare syscall arg against.
+      int err;                     // If non-zero, errno value to return.
+      struct ArgValue* arg_value;  // Otherwise, more args needs inspecting.
+    }* tests;
+    int err;                     // If none of the tests passed, this is what
+    struct ArgValue* arg_value;  // we'll return (this is the "else" branch).
+  };
+
+  bool IsReservedSyscall(int sysno) {
+    // There are a handful of system calls that we should never use in our
+    // test cases. These system calls are needed to allow the test framework
+    // to run properly.
+    // If we wanted to write fully generic code, there are more system calls
+    // that could be listed here, and it is quite difficult to come up with a
+    // truly comprehensive list. After all, we are deliberately making system
+    // calls unavailable. In practice, we have a pretty good idea of the system
+    // calls that will be made by this particular test. So, this small list is
+    // sufficient. But if anybody copy'n'pasted this code for other uses, they
+    // would have to review that the list.
+    return sysno == __NR_read || sysno == __NR_write || sysno == __NR_exit ||
+           sysno == __NR_exit_group || sysno == __NR_restart_syscall;
+  }
+
+  ArgValue* RandomArgValue(int argno, int args_mask, int remaining_args) {
+    // Create a new ArgValue and fill it with random data. We use as bit mask
+    // to keep track of the system call parameters that have previously been
+    // set; this ensures that we won't accidentally define a contradictory
+    // set of equality tests.
+    struct ArgValue* arg_value = new ArgValue();
+    args_mask |= 1 << argno;
+    arg_value->argno = argno;
+
+    // Apply some restrictions on just how complex our tests can be.
+    // Otherwise, we end up with a BPF program that is too complicated for
+    // the kernel to load.
+    int fan_out = kMaxFanOut;
+    if (remaining_args > 3) {
+      fan_out = 1;
+    } else if (remaining_args > 2) {
+      fan_out = 2;
+    }
+
+    // Create a couple of different test cases with randomized values that
+    // we want to use when comparing system call parameter number "argno".
+    arg_value->size = rand() % fan_out + 1;
+    arg_value->tests = new ArgValue::Tests[arg_value->size];
+
+    uint32_t k_value = rand();
+    for (int n = 0; n < arg_value->size; ++n) {
+      // Ensure that we have unique values
+      k_value += rand() % (RAND_MAX / (kMaxFanOut + 1)) + 1;
+
+      // There are two possible types of nodes. Either this is a leaf node;
+      // in that case, we have completed all the equality tests that we
+      // wanted to perform, and we can now compute a random "errno" value that
+      // we should return. Or this is part of a more complex boolean
+      // expression; in that case, we have to recursively add tests for some
+      // of system call parameters that we have not yet included in our
+      // tests.
+      arg_value->tests[n].k_value = k_value;
+      if (!remaining_args || (rand() & 1)) {
+        arg_value->tests[n].err = (rand() % 1000) + 1;
+        arg_value->tests[n].arg_value = NULL;
+      } else {
+        arg_value->tests[n].err = 0;
+        arg_value->tests[n].arg_value =
+            RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
+      }
+    }
+    // Finally, we have to define what we should return if none of the
+    // previous equality tests pass. Again, we can either deal with a leaf
+    // node, or we can randomly add another couple of tests.
+    if (!remaining_args || (rand() & 1)) {
+      arg_value->err = (rand() % 1000) + 1;
+      arg_value->arg_value = NULL;
+    } else {
+      arg_value->err = 0;
+      arg_value->arg_value =
+          RandomArgValue(RandomArg(args_mask), args_mask, remaining_args - 1);
+    }
+    // We have now built a new (sub-)tree of ArgValues defining a set of
+    // boolean expressions for testing random system call arguments against
+    // random values. Return this tree to our caller.
+    return arg_value;
+  }
+
+  int RandomArg(int args_mask) {
+    // Compute a random system call parameter number.
+    int argno = rand() % kMaxArgs;
+
+    // Make sure that this same parameter number has not previously been
+    // used. Otherwise, we could end up with a test that is impossible to
+    // satisfy (e.g. args[0] == 1 && args[0] == 2).
+    while (args_mask & (1 << argno)) {
+      argno = (argno + 1) % kMaxArgs;
+    }
+    return argno;
+  }
+
+  void DeleteArgValue(ArgValue* arg_value) {
+    // Delete an ArgValue and all of its child nodes. This requires
+    // recursively descending into the tree.
+    if (arg_value) {
+      if (arg_value->size) {
+        for (int n = 0; n < arg_value->size; ++n) {
+          if (!arg_value->tests[n].err) {
+            DeleteArgValue(arg_value->tests[n].arg_value);
+          }
+        }
+        delete[] arg_value->tests;
+      }
+      if (!arg_value->err) {
+        DeleteArgValue(arg_value->arg_value);
+      }
+      delete arg_value;
+    }
+  }
+
+  ResultExpr ToErrorCode(ArgValue* arg_value) {
+    // Compute the ResultExpr that should be returned, if none of our
+    // tests succeed (i.e. the system call parameter doesn't match any
+    // of the values in arg_value->tests[].k_value).
+    ResultExpr err;
+    if (arg_value->err) {
+      // If this was a leaf node, return the errno value that we expect to
+      // return from the BPF filter program.
+      err = Error(arg_value->err);
+    } else {
+      // If this wasn't a leaf node yet, recursively descend into the rest
+      // of the tree. This will end up adding a few more SandboxBPF::Cond()
+      // tests to our ErrorCode.
+      err = ToErrorCode(arg_value->arg_value);
+    }
+
+    // Now, iterate over all the test cases that we want to compare against.
+    // This builds a chain of SandboxBPF::Cond() tests
+    // (aka "if ... elif ... elif ... elif ... fi")
+    for (int n = arg_value->size; n-- > 0;) {
+      ResultExpr matched;
+      // Again, we distinguish between leaf nodes and subtrees.
+      if (arg_value->tests[n].err) {
+        matched = Error(arg_value->tests[n].err);
+      } else {
+        matched = ToErrorCode(arg_value->tests[n].arg_value);
+      }
+      // For now, all of our tests are limited to 32bit.
+      // We have separate tests that check the behavior of 32bit vs. 64bit
+      // conditional expressions.
+      const Arg<uint32_t> arg(arg_value->argno);
+      err = If(arg == arg_value->tests[n].k_value, matched).Else(err);
+    }
+    return err;
+  }
+
+  void Verify(int sysno, intptr_t* args, const ArgValue& arg_value) {
+    uint32_t mismatched = 0;
+    // Iterate over all the k_values in arg_value.tests[] and verify that
+    // we see the expected return values from system calls, when we pass
+    // the k_value as a parameter in a system call.
+    for (int n = arg_value.size; n-- > 0;) {
+      mismatched += arg_value.tests[n].k_value;
+      args[arg_value.argno] = arg_value.tests[n].k_value;
+      if (arg_value.tests[n].err) {
+        VerifyErrno(sysno, args, arg_value.tests[n].err);
+      } else {
+        Verify(sysno, args, *arg_value.tests[n].arg_value);
+      }
+    }
+  // Find a k_value that doesn't match any of the k_values in
+  // arg_value.tests[]. In most cases, the current value of "mismatched"
+  // would fit this requirement. But on the off-chance that it happens
+  // to collide, we double-check.
+  try_again:
+    for (int n = arg_value.size; n-- > 0;) {
+      if (mismatched == arg_value.tests[n].k_value) {
+        ++mismatched;
+        goto try_again;
+      }
+    }
+    // Now verify that we see the expected return value from system calls,
+    // if we pass a value that doesn't match any of the conditions (i.e. this
+    // is testing the "else" clause of the conditions).
+    args[arg_value.argno] = mismatched;
+    if (arg_value.err) {
+      VerifyErrno(sysno, args, arg_value.err);
+    } else {
+      Verify(sysno, args, *arg_value.arg_value);
+    }
+    // Reset args[arg_value.argno]. This is not technically needed, but it
+    // makes it easier to reason about the correctness of our tests.
+    args[arg_value.argno] = 0;
+  }
+
+  void VerifyErrno(int sysno, intptr_t* args, int err) {
+    // We installed BPF filters that return different errno values
+    // based on the system call number and the parameters that we decided
+    // to pass in. Verify that this condition holds true.
+    BPF_ASSERT(
+        Syscall::Call(
+            sysno, args[0], args[1], args[2], args[3], args[4], args[5]) ==
+        -err);
+  }
+
+  // Vector of ArgValue trees. These trees define all the possible boolean
+  // expressions that we want to turn into a BPF filter program.
+  std::vector<ArgValue*> arg_values_;
+
+  // Don't increase these values. We are pushing the limits of the maximum
+  // BPF program that the kernel will allow us to load. If the values are
+  // increased too much, the test will start failing.
+#if defined(__aarch64__)
+  static const int kNumTestCases = 30;
+#else
+  static const int kNumTestCases = 40;
+#endif
+  static const int kMaxFanOut = 3;
+  static const int kMaxArgs = 6;
+};
+
+class EqualityStressTestPolicy : public Policy {
+ public:
+  explicit EqualityStressTestPolicy(EqualityStressTest* aux) : aux_(aux) {}
+  ~EqualityStressTestPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    return aux_->Policy(sysno);
+  }
+
+ private:
+  EqualityStressTest* aux_;
+
+  DISALLOW_COPY_AND_ASSIGN(EqualityStressTestPolicy);
+};
+
+BPF_TEST(SandboxBPF,
+         EqualityTests,
+         EqualityStressTestPolicy,
+         EqualityStressTest /* (*BPF_AUX) */) {
+  BPF_AUX->VerifyFilter();
+}
+
+class EqualityArgumentWidthPolicy : public Policy {
+ public:
+  EqualityArgumentWidthPolicy() {}
+  ~EqualityArgumentWidthPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EqualityArgumentWidthPolicy);
+};
+
+ResultExpr EqualityArgumentWidthPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  if (sysno == __NR_uname) {
+    const Arg<int> option(0);
+    const Arg<uint32_t> arg32(1);
+    const Arg<uint64_t> arg64(1);
+    return Switch(option)
+        .Case(0, If(arg32 == 0x55555555, Error(1)).Else(Error(2)))
+#if __SIZEOF_POINTER__ > 4
+        .Case(1, If(arg64 == 0x55555555AAAAAAAAULL, Error(1)).Else(Error(2)))
+#endif
+        .Default(Error(3));
+  }
+  return Allow();
+}
+
+BPF_TEST_C(SandboxBPF, EqualityArgumentWidth, EqualityArgumentWidthPolicy) {
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0, 0x55555555) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0, 0xAAAAAAAA) == -2);
+#if __SIZEOF_POINTER__ > 4
+  // On 32bit machines, there is no way to pass a 64bit argument through the
+  // syscall interface. So, we have to skip the part of the test that requires
+  // 64bit arguments.
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x55555555AAAAAAAAULL) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x5555555500000000ULL) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x5555555511111111ULL) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x11111111AAAAAAAAULL) == -2);
+#endif
+}
+
+#if __SIZEOF_POINTER__ > 4
+// On 32bit machines, there is no way to pass a 64bit argument through the
+// syscall interface. So, we have to skip the part of the test that requires
+// 64bit arguments.
+BPF_DEATH_TEST_C(SandboxBPF,
+                 EqualityArgumentUnallowed64bit,
+                 DEATH_MESSAGE("Unexpected 64bit argument detected"),
+                 EqualityArgumentWidthPolicy) {
+  Syscall::Call(__NR_uname, 0, 0x5555555555555555ULL);
+}
+#endif
+
+class EqualityWithNegativeArgumentsPolicy : public Policy {
+ public:
+  EqualityWithNegativeArgumentsPolicy() {}
+  ~EqualityWithNegativeArgumentsPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    if (sysno == __NR_uname) {
+      // TODO(mdempsky): This currently can't be Arg<int> because then
+      // 0xFFFFFFFF will be treated as a (signed) int, and then when
+      // Arg::EqualTo casts it to uint64_t, it will be sign extended.
+      const Arg<unsigned> arg(0);
+      return If(arg == 0xFFFFFFFF, Error(1)).Else(Error(2));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EqualityWithNegativeArgumentsPolicy);
+};
+
+BPF_TEST_C(SandboxBPF,
+           EqualityWithNegativeArguments,
+           EqualityWithNegativeArgumentsPolicy) {
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0xFFFFFFFF) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, -1) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, -1LL) == -1);
+}
+
+#if __SIZEOF_POINTER__ > 4
+BPF_DEATH_TEST_C(SandboxBPF,
+                 EqualityWithNegative64bitArguments,
+                 DEATH_MESSAGE("Unexpected 64bit argument detected"),
+                 EqualityWithNegativeArgumentsPolicy) {
+  // When expecting a 32bit system call argument, we look at the MSB of the
+  // 64bit value and allow both "0" and "-1". But the latter is allowed only
+  // iff the LSB was negative. So, this death test should error out.
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0xFFFFFFFF00000000LL) == -1);
+}
+#endif
+
+class AllBitTestPolicy : public Policy {
+ public:
+  AllBitTestPolicy() {}
+  ~AllBitTestPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  static ResultExpr HasAllBits32(uint32_t bits);
+  static ResultExpr HasAllBits64(uint64_t bits);
+
+  DISALLOW_COPY_AND_ASSIGN(AllBitTestPolicy);
+};
+
+ResultExpr AllBitTestPolicy::HasAllBits32(uint32_t bits) {
+  if (bits == 0) {
+    return Error(1);
+  }
+  const Arg<uint32_t> arg(1);
+  return If((arg & bits) == bits, Error(1)).Else(Error(0));
+}
+
+ResultExpr AllBitTestPolicy::HasAllBits64(uint64_t bits) {
+  if (bits == 0) {
+    return Error(1);
+  }
+  const Arg<uint64_t> arg(1);
+  return If((arg & bits) == bits, Error(1)).Else(Error(0));
+}
+
+ResultExpr AllBitTestPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  // Test masked-equality cases that should trigger the "has all bits"
+  // peephole optimizations. We try to find bitmasks that could conceivably
+  // touch corner cases.
+  // For all of these tests, we override the uname(). We can make use with
+  // a single system call number, as we use the first system call argument to
+  // select the different bit masks that we want to test against.
+  if (sysno == __NR_uname) {
+    const Arg<int> option(0);
+    return Switch(option)
+        .Case(0, HasAllBits32(0x0))
+        .Case(1, HasAllBits32(0x1))
+        .Case(2, HasAllBits32(0x3))
+        .Case(3, HasAllBits32(0x80000000))
+#if __SIZEOF_POINTER__ > 4
+        .Case(4, HasAllBits64(0x0))
+        .Case(5, HasAllBits64(0x1))
+        .Case(6, HasAllBits64(0x3))
+        .Case(7, HasAllBits64(0x80000000))
+        .Case(8, HasAllBits64(0x100000000ULL))
+        .Case(9, HasAllBits64(0x300000000ULL))
+        .Case(10, HasAllBits64(0x100000001ULL))
+#endif
+        .Default(Kill("Invalid test case number"));
+  }
+  return Allow();
+}
+
+// Define a macro that performs tests using our test policy.
+// NOTE: Not all of the arguments in this macro are actually used!
+//       They are here just to serve as documentation of the conditions
+//       implemented in the test policy.
+//       Most notably, "op" and "mask" are unused by the macro. If you want
+//       to make changes to these values, you will have to edit the
+//       test policy instead.
+#define BITMASK_TEST(testcase, arg, op, mask, expected_value) \
+  BPF_ASSERT(Syscall::Call(__NR_uname, (testcase), (arg)) == (expected_value))
+
+// Our uname() system call returns ErrorCode(1) for success and
+// ErrorCode(0) for failure. Syscall::Call() turns this into an
+// exit code of -1 or 0.
+#define EXPECT_FAILURE 0
+#define EXPECT_SUCCESS -1
+
+// A couple of our tests behave differently on 32bit and 64bit systems, as
+// there is no way for a 32bit system call to pass in a 64bit system call
+// argument "arg".
+// We expect these tests to succeed on 64bit systems, but to tail on 32bit
+// systems.
+#define EXPT64_SUCCESS (sizeof(void*) > 4 ? EXPECT_SUCCESS : EXPECT_FAILURE)
+BPF_TEST_C(SandboxBPF, AllBitTests, AllBitTestPolicy) {
+  // 32bit test: all of 0x0 (should always be true)
+  BITMASK_TEST( 0,                   0, ALLBITS32,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 0,                   1, ALLBITS32,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 0,                   3, ALLBITS32,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 0,         0xFFFFFFFFU, ALLBITS32,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 0,                -1LL, ALLBITS32,          0, EXPECT_SUCCESS);
+
+  // 32bit test: all of 0x1
+  BITMASK_TEST( 1,                   0, ALLBITS32,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 1,                   1, ALLBITS32,        0x1, EXPECT_SUCCESS);
+  BITMASK_TEST( 1,                   2, ALLBITS32,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 1,                   3, ALLBITS32,        0x1, EXPECT_SUCCESS);
+
+  // 32bit test: all of 0x3
+  BITMASK_TEST( 2,                   0, ALLBITS32,        0x3, EXPECT_FAILURE);
+  BITMASK_TEST( 2,                   1, ALLBITS32,        0x3, EXPECT_FAILURE);
+  BITMASK_TEST( 2,                   2, ALLBITS32,        0x3, EXPECT_FAILURE);
+  BITMASK_TEST( 2,                   3, ALLBITS32,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 2,                   7, ALLBITS32,        0x3, EXPECT_SUCCESS);
+
+  // 32bit test: all of 0x80000000
+  BITMASK_TEST( 3,                   0, ALLBITS32, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 3,         0x40000000U, ALLBITS32, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 3,         0x80000000U, ALLBITS32, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 3,         0xC0000000U, ALLBITS32, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 3,       -0x80000000LL, ALLBITS32, 0x80000000, EXPECT_SUCCESS);
+
+#if __SIZEOF_POINTER__ > 4
+  // 64bit test: all of 0x0 (should always be true)
+  BITMASK_TEST( 4,                   0, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,                   1, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,                   3, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,         0xFFFFFFFFU, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,       0x100000000LL, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,       0x300000000LL, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,0x8000000000000000LL, ALLBITS64,          0, EXPECT_SUCCESS);
+  BITMASK_TEST( 4,                -1LL, ALLBITS64,          0, EXPECT_SUCCESS);
+
+  // 64bit test: all of 0x1
+  BITMASK_TEST( 5,                   0, ALLBITS64,          1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,                   1, ALLBITS64,          1, EXPECT_SUCCESS);
+  BITMASK_TEST( 5,                   2, ALLBITS64,          1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,                   3, ALLBITS64,          1, EXPECT_SUCCESS);
+  BITMASK_TEST( 5,       0x100000000LL, ALLBITS64,          1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,       0x100000001LL, ALLBITS64,          1, EXPECT_SUCCESS);
+  BITMASK_TEST( 5,       0x100000002LL, ALLBITS64,          1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,       0x100000003LL, ALLBITS64,          1, EXPECT_SUCCESS);
+
+  // 64bit test: all of 0x3
+  BITMASK_TEST( 6,                   0, ALLBITS64,          3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,                   1, ALLBITS64,          3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,                   2, ALLBITS64,          3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,                   3, ALLBITS64,          3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,                   7, ALLBITS64,          3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,       0x100000000LL, ALLBITS64,          3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,       0x100000001LL, ALLBITS64,          3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,       0x100000002LL, ALLBITS64,          3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,       0x100000003LL, ALLBITS64,          3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,       0x100000007LL, ALLBITS64,          3, EXPECT_SUCCESS);
+
+  // 64bit test: all of 0x80000000
+  BITMASK_TEST( 7,                   0, ALLBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,         0x40000000U, ALLBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,         0x80000000U, ALLBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,         0xC0000000U, ALLBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,       -0x80000000LL, ALLBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,       0x100000000LL, ALLBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,       0x140000000LL, ALLBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,       0x180000000LL, ALLBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,       0x1C0000000LL, ALLBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,      -0x180000000LL, ALLBITS64, 0x80000000, EXPECT_SUCCESS);
+
+  // 64bit test: all of 0x100000000
+  BITMASK_TEST( 8,       0x000000000LL, ALLBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x100000000LL, ALLBITS64,0x100000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 8,       0x200000000LL, ALLBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x300000000LL, ALLBITS64,0x100000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 8,       0x000000001LL, ALLBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x100000001LL, ALLBITS64,0x100000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 8,       0x200000001LL, ALLBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x300000001LL, ALLBITS64,0x100000000, EXPT64_SUCCESS);
+
+  // 64bit test: all of 0x300000000
+  BITMASK_TEST( 9,       0x000000000LL, ALLBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x100000000LL, ALLBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x200000000LL, ALLBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x300000000LL, ALLBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x700000000LL, ALLBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x000000001LL, ALLBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x100000001LL, ALLBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x200000001LL, ALLBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x300000001LL, ALLBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x700000001LL, ALLBITS64,0x300000000, EXPT64_SUCCESS);
+
+  // 64bit test: all of 0x100000001
+  BITMASK_TEST(10,       0x000000000LL, ALLBITS64,0x100000001, EXPECT_FAILURE);
+  BITMASK_TEST(10,       0x000000001LL, ALLBITS64,0x100000001, EXPECT_FAILURE);
+  BITMASK_TEST(10,       0x100000000LL, ALLBITS64,0x100000001, EXPECT_FAILURE);
+  BITMASK_TEST(10,       0x100000001LL, ALLBITS64,0x100000001, EXPT64_SUCCESS);
+  BITMASK_TEST(10,         0xFFFFFFFFU, ALLBITS64,0x100000001, EXPECT_FAILURE);
+  BITMASK_TEST(10,                 -1L, ALLBITS64,0x100000001, EXPT64_SUCCESS);
+#endif
+}
+
+class AnyBitTestPolicy : public Policy {
+ public:
+  AnyBitTestPolicy() {}
+  ~AnyBitTestPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  static ResultExpr HasAnyBits32(uint32_t);
+  static ResultExpr HasAnyBits64(uint64_t);
+
+  DISALLOW_COPY_AND_ASSIGN(AnyBitTestPolicy);
+};
+
+ResultExpr AnyBitTestPolicy::HasAnyBits32(uint32_t bits) {
+  if (bits == 0) {
+    return Error(0);
+  }
+  const Arg<uint32_t> arg(1);
+  return If((arg & bits) != 0, Error(1)).Else(Error(0));
+}
+
+ResultExpr AnyBitTestPolicy::HasAnyBits64(uint64_t bits) {
+  if (bits == 0) {
+    return Error(0);
+  }
+  const Arg<uint64_t> arg(1);
+  return If((arg & bits) != 0, Error(1)).Else(Error(0));
+}
+
+ResultExpr AnyBitTestPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  // Test masked-equality cases that should trigger the "has any bits"
+  // peephole optimizations. We try to find bitmasks that could conceivably
+  // touch corner cases.
+  // For all of these tests, we override the uname(). We can make use with
+  // a single system call number, as we use the first system call argument to
+  // select the different bit masks that we want to test against.
+  if (sysno == __NR_uname) {
+    const Arg<int> option(0);
+    return Switch(option)
+        .Case(0, HasAnyBits32(0x0))
+        .Case(1, HasAnyBits32(0x1))
+        .Case(2, HasAnyBits32(0x3))
+        .Case(3, HasAnyBits32(0x80000000))
+#if __SIZEOF_POINTER__ > 4
+        .Case(4, HasAnyBits64(0x0))
+        .Case(5, HasAnyBits64(0x1))
+        .Case(6, HasAnyBits64(0x3))
+        .Case(7, HasAnyBits64(0x80000000))
+        .Case(8, HasAnyBits64(0x100000000ULL))
+        .Case(9, HasAnyBits64(0x300000000ULL))
+        .Case(10, HasAnyBits64(0x100000001ULL))
+#endif
+        .Default(Kill("Invalid test case number"));
+  }
+  return Allow();
+}
+
+BPF_TEST_C(SandboxBPF, AnyBitTests, AnyBitTestPolicy) {
+  // 32bit test: any of 0x0 (should always be false)
+  BITMASK_TEST( 0,                   0, ANYBITS32,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 0,                   1, ANYBITS32,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 0,                   3, ANYBITS32,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 0,         0xFFFFFFFFU, ANYBITS32,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 0,                -1LL, ANYBITS32,        0x0, EXPECT_FAILURE);
+
+  // 32bit test: any of 0x1
+  BITMASK_TEST( 1,                   0, ANYBITS32,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 1,                   1, ANYBITS32,        0x1, EXPECT_SUCCESS);
+  BITMASK_TEST( 1,                   2, ANYBITS32,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 1,                   3, ANYBITS32,        0x1, EXPECT_SUCCESS);
+
+  // 32bit test: any of 0x3
+  BITMASK_TEST( 2,                   0, ANYBITS32,        0x3, EXPECT_FAILURE);
+  BITMASK_TEST( 2,                   1, ANYBITS32,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 2,                   2, ANYBITS32,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 2,                   3, ANYBITS32,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 2,                   7, ANYBITS32,        0x3, EXPECT_SUCCESS);
+
+  // 32bit test: any of 0x80000000
+  BITMASK_TEST( 3,                   0, ANYBITS32, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 3,         0x40000000U, ANYBITS32, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 3,         0x80000000U, ANYBITS32, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 3,         0xC0000000U, ANYBITS32, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 3,       -0x80000000LL, ANYBITS32, 0x80000000, EXPECT_SUCCESS);
+
+#if __SIZEOF_POINTER__ > 4
+  // 64bit test: any of 0x0 (should always be false)
+  BITMASK_TEST( 4,                   0, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,                   1, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,                   3, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,         0xFFFFFFFFU, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,       0x100000000LL, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,       0x300000000LL, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,0x8000000000000000LL, ANYBITS64,        0x0, EXPECT_FAILURE);
+  BITMASK_TEST( 4,                -1LL, ANYBITS64,        0x0, EXPECT_FAILURE);
+
+  // 64bit test: any of 0x1
+  BITMASK_TEST( 5,                   0, ANYBITS64,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,                   1, ANYBITS64,        0x1, EXPECT_SUCCESS);
+  BITMASK_TEST( 5,                   2, ANYBITS64,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,                   3, ANYBITS64,        0x1, EXPECT_SUCCESS);
+  BITMASK_TEST( 5,       0x100000001LL, ANYBITS64,        0x1, EXPECT_SUCCESS);
+  BITMASK_TEST( 5,       0x100000000LL, ANYBITS64,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,       0x100000002LL, ANYBITS64,        0x1, EXPECT_FAILURE);
+  BITMASK_TEST( 5,       0x100000003LL, ANYBITS64,        0x1, EXPECT_SUCCESS);
+
+  // 64bit test: any of 0x3
+  BITMASK_TEST( 6,                   0, ANYBITS64,        0x3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,                   1, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,                   2, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,                   3, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,                   7, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,       0x100000000LL, ANYBITS64,        0x3, EXPECT_FAILURE);
+  BITMASK_TEST( 6,       0x100000001LL, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,       0x100000002LL, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,       0x100000003LL, ANYBITS64,        0x3, EXPECT_SUCCESS);
+  BITMASK_TEST( 6,       0x100000007LL, ANYBITS64,        0x3, EXPECT_SUCCESS);
+
+  // 64bit test: any of 0x80000000
+  BITMASK_TEST( 7,                   0, ANYBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,         0x40000000U, ANYBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,         0x80000000U, ANYBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,         0xC0000000U, ANYBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,       -0x80000000LL, ANYBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,       0x100000000LL, ANYBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,       0x140000000LL, ANYBITS64, 0x80000000, EXPECT_FAILURE);
+  BITMASK_TEST( 7,       0x180000000LL, ANYBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,       0x1C0000000LL, ANYBITS64, 0x80000000, EXPECT_SUCCESS);
+  BITMASK_TEST( 7,      -0x180000000LL, ANYBITS64, 0x80000000, EXPECT_SUCCESS);
+
+  // 64bit test: any of 0x100000000
+  BITMASK_TEST( 8,       0x000000000LL, ANYBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x100000000LL, ANYBITS64,0x100000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 8,       0x200000000LL, ANYBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x300000000LL, ANYBITS64,0x100000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 8,       0x000000001LL, ANYBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x100000001LL, ANYBITS64,0x100000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 8,       0x200000001LL, ANYBITS64,0x100000000, EXPECT_FAILURE);
+  BITMASK_TEST( 8,       0x300000001LL, ANYBITS64,0x100000000, EXPT64_SUCCESS);
+
+  // 64bit test: any of 0x300000000
+  BITMASK_TEST( 9,       0x000000000LL, ANYBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x100000000LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x200000000LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x300000000LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x700000000LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x000000001LL, ANYBITS64,0x300000000, EXPECT_FAILURE);
+  BITMASK_TEST( 9,       0x100000001LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x200000001LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x300000001LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+  BITMASK_TEST( 9,       0x700000001LL, ANYBITS64,0x300000000, EXPT64_SUCCESS);
+
+  // 64bit test: any of 0x100000001
+  BITMASK_TEST( 10,      0x000000000LL, ANYBITS64,0x100000001, EXPECT_FAILURE);
+  BITMASK_TEST( 10,      0x000000001LL, ANYBITS64,0x100000001, EXPECT_SUCCESS);
+  BITMASK_TEST( 10,      0x100000000LL, ANYBITS64,0x100000001, EXPT64_SUCCESS);
+  BITMASK_TEST( 10,      0x100000001LL, ANYBITS64,0x100000001, EXPECT_SUCCESS);
+  BITMASK_TEST( 10,        0xFFFFFFFFU, ANYBITS64,0x100000001, EXPECT_SUCCESS);
+  BITMASK_TEST( 10,                -1L, ANYBITS64,0x100000001, EXPECT_SUCCESS);
+#endif
+}
+
+class MaskedEqualTestPolicy : public Policy {
+ public:
+  MaskedEqualTestPolicy() {}
+  ~MaskedEqualTestPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  static ResultExpr MaskedEqual32(uint32_t mask, uint32_t value);
+  static ResultExpr MaskedEqual64(uint64_t mask, uint64_t value);
+
+  DISALLOW_COPY_AND_ASSIGN(MaskedEqualTestPolicy);
+};
+
+ResultExpr MaskedEqualTestPolicy::MaskedEqual32(uint32_t mask, uint32_t value) {
+  const Arg<uint32_t> arg(1);
+  return If((arg & mask) == value, Error(1)).Else(Error(0));
+}
+
+ResultExpr MaskedEqualTestPolicy::MaskedEqual64(uint64_t mask, uint64_t value) {
+  const Arg<uint64_t> arg(1);
+  return If((arg & mask) == value, Error(1)).Else(Error(0));
+}
+
+ResultExpr MaskedEqualTestPolicy::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+
+  if (sysno == __NR_uname) {
+    const Arg<int> option(0);
+    return Switch(option)
+        .Case(0, MaskedEqual32(0x00ff00ff, 0x005500aa))
+#if __SIZEOF_POINTER__ > 4
+        .Case(1, MaskedEqual64(0x00ff00ff00000000, 0x005500aa00000000))
+        .Case(2, MaskedEqual64(0x00ff00ff00ff00ff, 0x005500aa005500aa))
+#endif
+        .Default(Kill("Invalid test case number"));
+  }
+
+  return Allow();
+}
+
+#define MASKEQ_TEST(rulenum, arg, expected_result) \
+  BPF_ASSERT(Syscall::Call(__NR_uname, (rulenum), (arg)) == (expected_result))
+
+BPF_TEST_C(SandboxBPF, MaskedEqualTests, MaskedEqualTestPolicy) {
+  // Allowed:    0x__55__aa
+  MASKEQ_TEST(0, 0x00000000, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x00000001, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x00000003, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x00000100, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x00000300, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x005500aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(0, 0x005500ab, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x005600aa, EXPECT_FAILURE);
+  MASKEQ_TEST(0, 0x005501aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(0, 0x005503aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(0, 0x555500aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(0, 0xaa5500aa, EXPECT_SUCCESS);
+
+#if __SIZEOF_POINTER__ > 4
+  // Allowed:    0x__55__aa________
+  MASKEQ_TEST(1, 0x0000000000000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x0000000000000010, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x0000000000000050, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x0000000100000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x0000000300000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x0000010000000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x0000030000000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x005500aa00000000, EXPECT_SUCCESS);
+  MASKEQ_TEST(1, 0x005500ab00000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x005600aa00000000, EXPECT_FAILURE);
+  MASKEQ_TEST(1, 0x005501aa00000000, EXPECT_SUCCESS);
+  MASKEQ_TEST(1, 0x005503aa00000000, EXPECT_SUCCESS);
+  MASKEQ_TEST(1, 0x555500aa00000000, EXPECT_SUCCESS);
+  MASKEQ_TEST(1, 0xaa5500aa00000000, EXPECT_SUCCESS);
+  MASKEQ_TEST(1, 0xaa5500aa00000000, EXPECT_SUCCESS);
+  MASKEQ_TEST(1, 0xaa5500aa0000cafe, EXPECT_SUCCESS);
+
+  // Allowed:    0x__55__aa__55__aa
+  MASKEQ_TEST(2, 0x0000000000000000, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x0000000000000010, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x0000000000000050, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x0000000100000000, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x0000000300000000, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x0000010000000000, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x0000030000000000, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x00000000005500aa, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x005500aa00000000, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x005500aa005500aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(2, 0x005500aa005700aa, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x005700aa005500aa, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x005500aa004500aa, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x004500aa005500aa, EXPECT_FAILURE);
+  MASKEQ_TEST(2, 0x005512aa005500aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(2, 0x005500aa005534aa, EXPECT_SUCCESS);
+  MASKEQ_TEST(2, 0xff5500aa0055ffaa, EXPECT_SUCCESS);
+#endif
+}
+
+intptr_t PthreadTrapHandler(const struct arch_seccomp_data& args, void* aux) {
+  if (args.args[0] != (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD)) {
+    // We expect to get called for an attempt to fork(). No need to log that
+    // call. But if we ever get called for anything else, we want to verbosely
+    // print as much information as possible.
+    const char* msg = (const char*)aux;
+    printf(
+        "Clone() was called with unexpected arguments\n"
+        "  nr: %d\n"
+        "  1: 0x%llX\n"
+        "  2: 0x%llX\n"
+        "  3: 0x%llX\n"
+        "  4: 0x%llX\n"
+        "  5: 0x%llX\n"
+        "  6: 0x%llX\n"
+        "%s\n",
+        args.nr,
+        (long long)args.args[0],
+        (long long)args.args[1],
+        (long long)args.args[2],
+        (long long)args.args[3],
+        (long long)args.args[4],
+        (long long)args.args[5],
+        msg);
+  }
+  return -EPERM;
+}
+
+class PthreadPolicyEquality : public Policy {
+ public:
+  PthreadPolicyEquality() {}
+  ~PthreadPolicyEquality() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PthreadPolicyEquality);
+};
+
+ResultExpr PthreadPolicyEquality::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  // This policy allows creating threads with pthread_create(). But it
+  // doesn't allow any other uses of clone(). Most notably, it does not
+  // allow callers to implement fork() or vfork() by passing suitable flags
+  // to the clone() system call.
+  if (sysno == __NR_clone) {
+    // We have seen two different valid combinations of flags. Glibc
+    // uses the more modern flags, sets the TLS from the call to clone(), and
+    // uses futexes to monitor threads. Android's C run-time library, doesn't
+    // do any of this, but it sets the obsolete (and no-op) CLONE_DETACHED.
+    // More recent versions of Android don't set CLONE_DETACHED anymore, so
+    // the last case accounts for that.
+    // The following policy is very strict. It only allows the exact masks
+    // that we have seen in known implementations. It is probably somewhat
+    // stricter than what we would want to do.
+    const uint64_t kGlibcCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
+                                     CLONE_SIGHAND | CLONE_THREAD |
+                                     CLONE_SYSVSEM | CLONE_SETTLS |
+                                     CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+    const uint64_t kBaseAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
+                                           CLONE_SIGHAND | CLONE_THREAD |
+                                           CLONE_SYSVSEM;
+    const Arg<unsigned long> flags(0);
+    return If(flags == kGlibcCloneMask ||
+                  flags == (kBaseAndroidCloneMask | CLONE_DETACHED) ||
+                  flags == kBaseAndroidCloneMask,
+              Allow()).Else(Trap(PthreadTrapHandler, "Unknown mask"));
+  }
+
+  return Allow();
+}
+
+class PthreadPolicyBitMask : public Policy {
+ public:
+  PthreadPolicyBitMask() {}
+  ~PthreadPolicyBitMask() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override;
+
+ private:
+  static BoolExpr HasAnyBits(const Arg<unsigned long>& arg, unsigned long bits);
+  static BoolExpr HasAllBits(const Arg<unsigned long>& arg, unsigned long bits);
+
+  DISALLOW_COPY_AND_ASSIGN(PthreadPolicyBitMask);
+};
+
+BoolExpr PthreadPolicyBitMask::HasAnyBits(const Arg<unsigned long>& arg,
+                                          unsigned long bits) {
+  return (arg & bits) != 0;
+}
+
+BoolExpr PthreadPolicyBitMask::HasAllBits(const Arg<unsigned long>& arg,
+                                          unsigned long bits) {
+  return (arg & bits) == bits;
+}
+
+ResultExpr PthreadPolicyBitMask::EvaluateSyscall(int sysno) const {
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  // This policy allows creating threads with pthread_create(). But it
+  // doesn't allow any other uses of clone(). Most notably, it does not
+  // allow callers to implement fork() or vfork() by passing suitable flags
+  // to the clone() system call.
+  if (sysno == __NR_clone) {
+    // We have seen two different valid combinations of flags. Glibc
+    // uses the more modern flags, sets the TLS from the call to clone(), and
+    // uses futexes to monitor threads. Android's C run-time library, doesn't
+    // do any of this, but it sets the obsolete (and no-op) CLONE_DETACHED.
+    // The following policy allows for either combination of flags, but it
+    // is generally a little more conservative than strictly necessary. We
+    // err on the side of rather safe than sorry.
+    // Very noticeably though, we disallow fork() (which is often just a
+    // wrapper around clone()).
+    const unsigned long kMandatoryFlags = CLONE_VM | CLONE_FS | CLONE_FILES |
+                                          CLONE_SIGHAND | CLONE_THREAD |
+                                          CLONE_SYSVSEM;
+    const unsigned long kFutexFlags =
+        CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+    const unsigned long kNoopFlags = CLONE_DETACHED;
+    const unsigned long kKnownFlags =
+        kMandatoryFlags | kFutexFlags | kNoopFlags;
+
+    const Arg<unsigned long> flags(0);
+    return If(HasAnyBits(flags, ~kKnownFlags),
+              Trap(PthreadTrapHandler, "Unexpected CLONE_XXX flag found"))
+        .ElseIf(!HasAllBits(flags, kMandatoryFlags),
+                Trap(PthreadTrapHandler,
+                     "Missing mandatory CLONE_XXX flags "
+                     "when creating new thread"))
+        .ElseIf(
+             !HasAllBits(flags, kFutexFlags) && HasAnyBits(flags, kFutexFlags),
+             Trap(PthreadTrapHandler,
+                  "Must set either all or none of the TLS and futex bits in "
+                  "call to clone()"))
+        .Else(Allow());
+  }
+
+  return Allow();
+}
+
+static void* ThreadFnc(void* arg) {
+  ++*reinterpret_cast<int*>(arg);
+  Syscall::Call(__NR_futex, arg, FUTEX_WAKE, 1, 0, 0, 0);
+  return NULL;
+}
+
+static void PthreadTest() {
+  // Attempt to start a joinable thread. This should succeed.
+  pthread_t thread;
+  int thread_ran = 0;
+  BPF_ASSERT(!pthread_create(&thread, NULL, ThreadFnc, &thread_ran));
+  BPF_ASSERT(!pthread_join(thread, NULL));
+  BPF_ASSERT(thread_ran);
+
+  // Attempt to start a detached thread. This should succeed.
+  thread_ran = 0;
+  pthread_attr_t attr;
+  BPF_ASSERT(!pthread_attr_init(&attr));
+  BPF_ASSERT(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
+  BPF_ASSERT(!pthread_create(&thread, &attr, ThreadFnc, &thread_ran));
+  BPF_ASSERT(!pthread_attr_destroy(&attr));
+  while (Syscall::Call(__NR_futex, &thread_ran, FUTEX_WAIT, 0, 0, 0, 0) ==
+         -EINTR) {
+  }
+  BPF_ASSERT(thread_ran);
+
+  // Attempt to fork() a process using clone(). This should fail. We use the
+  // same flags that glibc uses when calling fork(). But we don't actually
+  // try calling the fork() implementation in the C run-time library, as
+  // run-time libraries other than glibc might call __NR_fork instead of
+  // __NR_clone, and that would introduce a bogus test failure.
+  int pid;
+  BPF_ASSERT(Syscall::Call(__NR_clone,
+                           CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD,
+                           0,
+                           0,
+                           &pid) == -EPERM);
+}
+
+BPF_TEST_C(SandboxBPF, PthreadEquality, PthreadPolicyEquality) {
+  PthreadTest();
+}
+
+BPF_TEST_C(SandboxBPF, PthreadBitMask, PthreadPolicyBitMask) {
+  PthreadTest();
+}
+
+// libc might not define these even though the kernel supports it.
+#ifndef PTRACE_O_TRACESECCOMP
+#define PTRACE_O_TRACESECCOMP 0x00000080
+#endif
+
+#ifdef PTRACE_EVENT_SECCOMP
+#define IS_SECCOMP_EVENT(status) ((status >> 16) == PTRACE_EVENT_SECCOMP)
+#else
+// When Debian/Ubuntu backported seccomp-bpf support into earlier kernels, they
+// changed the value of PTRACE_EVENT_SECCOMP from 7 to 8, since 7 was taken by
+// PTRACE_EVENT_STOP (upstream chose to renumber PTRACE_EVENT_STOP to 128).  If
+// PTRACE_EVENT_SECCOMP isn't defined, we have no choice but to consider both
+// values here.
+#define IS_SECCOMP_EVENT(status) ((status >> 16) == 7 || (status >> 16) == 8)
+#endif
+
+#if defined(__arm__)
+#ifndef PTRACE_SET_SYSCALL
+#define PTRACE_SET_SYSCALL 23
+#endif
+#endif
+
+#if defined(__aarch64__)
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS 12
+#endif
+#endif
+
+#if defined(__aarch64__)
+#ifndef PTRACE_SETREGS
+#define PTRACE_SETREGS 13
+#endif
+#endif
+
+// Changes the syscall to run for a child being sandboxed using seccomp-bpf with
+// PTRACE_O_TRACESECCOMP.  Should only be called when the child is stopped on
+// PTRACE_EVENT_SECCOMP.
+//
+// regs should contain the current set of registers of the child, obtained using
+// PTRACE_GETREGS.
+//
+// Depending on the architecture, this may modify regs, so the caller is
+// responsible for committing these changes using PTRACE_SETREGS.
+long SetSyscall(pid_t pid, regs_struct* regs, int syscall_number) {
+#if defined(__arm__)
+  // On ARM, the syscall is changed using PTRACE_SET_SYSCALL.  We cannot use the
+  // libc ptrace call as the request parameter is an enum, and
+  // PTRACE_SET_SYSCALL may not be in the enum.
+  return syscall(__NR_ptrace, PTRACE_SET_SYSCALL, pid, NULL, syscall_number);
+#endif
+
+  SECCOMP_PT_SYSCALL(*regs) = syscall_number;
+  return 0;
+}
+
+const uint16_t kTraceData = 0xcc;
+
+class TraceAllPolicy : public Policy {
+ public:
+  TraceAllPolicy() {}
+  ~TraceAllPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int system_call_number) const override {
+    return Trace(kTraceData);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceAllPolicy);
+};
+
+SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) {
+  if (!SandboxBPF::SupportsSeccompSandbox(
+          SandboxBPF::SeccompLevel::SINGLE_THREADED)) {
+    return;
+  }
+
+// This test is disabled on arm due to a kernel bug.
+// See https://code.google.com/p/chromium/issues/detail?id=383977
+#if defined(__arm__) || defined(__aarch64__)
+  printf("This test is currently disabled on ARM32/64 due to a kernel bug.");
+  return;
+#endif
+
+#if defined(__mips__)
+  // TODO: Figure out how to support specificity of handling indirect syscalls
+  //        in this test and enable it.
+  printf("This test is currently disabled on MIPS.");
+  return;
+#endif
+
+  pid_t pid = fork();
+  BPF_ASSERT_NE(-1, pid);
+  if (pid == 0) {
+    pid_t my_pid = getpid();
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_TRACEME, -1, NULL, NULL));
+    BPF_ASSERT_EQ(0, raise(SIGSTOP));
+    SandboxBPF sandbox(new TraceAllPolicy);
+    BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
+
+    // getpid is allowed.
+    BPF_ASSERT_EQ(my_pid, sys_getpid());
+
+    // write to stdout is skipped and returns a fake value.
+    BPF_ASSERT_EQ(kExpectedReturnValue,
+                  syscall(__NR_write, STDOUT_FILENO, "A", 1));
+
+    // kill is rewritten to exit(kExpectedReturnValue).
+    syscall(__NR_kill, my_pid, SIGKILL);
+
+    // Should not be reached.
+    BPF_ASSERT(false);
+  }
+
+  int status;
+  BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, WUNTRACED)) != -1);
+  BPF_ASSERT(WIFSTOPPED(status));
+
+  BPF_ASSERT_NE(-1,
+                ptrace(PTRACE_SETOPTIONS,
+                       pid,
+                       NULL,
+                       reinterpret_cast<void*>(PTRACE_O_TRACESECCOMP)));
+  BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL));
+  while (true) {
+    BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, 0)) != -1);
+    if (WIFEXITED(status) || WIFSIGNALED(status)) {
+      BPF_ASSERT(WIFEXITED(status));
+      BPF_ASSERT_EQ(kExpectedReturnValue, WEXITSTATUS(status));
+      break;
+    }
+
+    if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
+        !IS_SECCOMP_EVENT(status)) {
+      BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL));
+      continue;
+    }
+
+    unsigned long data;
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data));
+    BPF_ASSERT_EQ(kTraceData, data);
+
+    regs_struct regs;
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_GETREGS, pid, NULL, &regs));
+    switch (SECCOMP_PT_SYSCALL(regs)) {
+      case __NR_write:
+        // Skip writes to stdout, make it return kExpectedReturnValue.  Allow
+        // writes to stderr so that BPF_ASSERT messages show up.
+        if (SECCOMP_PT_PARM1(regs) == STDOUT_FILENO) {
+          BPF_ASSERT_NE(-1, SetSyscall(pid, &regs, -1));
+          SECCOMP_PT_RESULT(regs) = kExpectedReturnValue;
+          BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGS, pid, NULL, &regs));
+        }
+        break;
+
+      case __NR_kill:
+        // Rewrite to exit(kExpectedReturnValue).
+        BPF_ASSERT_NE(-1, SetSyscall(pid, &regs, __NR_exit));
+        SECCOMP_PT_PARM1(regs) = kExpectedReturnValue;
+        BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGS, pid, NULL, &regs));
+        break;
+
+      default:
+        // Allow all other syscalls.
+        break;
+    }
+
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL));
+  }
+}
+
+// Android does not expose pread64 nor pwrite64.
+#if !defined(OS_ANDROID)
+
+bool FullPwrite64(int fd, const char* buffer, size_t count, off64_t offset) {
+  while (count > 0) {
+    const ssize_t transfered =
+        HANDLE_EINTR(pwrite64(fd, buffer, count, offset));
+    if (transfered <= 0 || static_cast<size_t>(transfered) > count) {
+      return false;
+    }
+    count -= transfered;
+    buffer += transfered;
+    offset += transfered;
+  }
+  return true;
+}
+
+bool FullPread64(int fd, char* buffer, size_t count, off64_t offset) {
+  while (count > 0) {
+    const ssize_t transfered = HANDLE_EINTR(pread64(fd, buffer, count, offset));
+    if (transfered <= 0 || static_cast<size_t>(transfered) > count) {
+      return false;
+    }
+    count -= transfered;
+    buffer += transfered;
+    offset += transfered;
+  }
+  return true;
+}
+
+bool pread_64_was_forwarded = false;
+
+class TrapPread64Policy : public Policy {
+ public:
+  TrapPread64Policy() {}
+  ~TrapPread64Policy() override {}
+
+  ResultExpr EvaluateSyscall(int system_call_number) const override {
+    // Set the global environment for unsafe traps once.
+    if (system_call_number == MIN_SYSCALL) {
+      EnableUnsafeTraps();
+    }
+
+    if (system_call_number == __NR_pread64) {
+      return UnsafeTrap(ForwardPreadHandler, NULL);
+    }
+    return Allow();
+  }
+
+ private:
+  static intptr_t ForwardPreadHandler(const struct arch_seccomp_data& args,
+                                      void* aux) {
+    BPF_ASSERT(args.nr == __NR_pread64);
+    pread_64_was_forwarded = true;
+
+    return SandboxBPF::ForwardSyscall(args);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TrapPread64Policy);
+};
+
+// pread(2) takes a 64 bits offset. On 32 bits systems, it will be split
+// between two arguments. In this test, we make sure that ForwardSyscall() can
+// forward it properly.
+BPF_TEST_C(SandboxBPF, Pread64, TrapPread64Policy) {
+  ScopedTemporaryFile temp_file;
+  const uint64_t kLargeOffset = (static_cast<uint64_t>(1) << 32) | 0xBEEF;
+  const char kTestString[] = "This is a test!";
+  BPF_ASSERT(FullPwrite64(
+      temp_file.fd(), kTestString, sizeof(kTestString), kLargeOffset));
+
+  char read_test_string[sizeof(kTestString)] = {0};
+  BPF_ASSERT(FullPread64(temp_file.fd(),
+                         read_test_string,
+                         sizeof(read_test_string),
+                         kLargeOffset));
+  BPF_ASSERT_EQ(0, memcmp(kTestString, read_test_string, sizeof(kTestString)));
+  BPF_ASSERT(pread_64_was_forwarded);
+}
+
+#endif  // !defined(OS_ANDROID)
+
+void* TsyncApplyToTwoThreadsFunc(void* cond_ptr) {
+  base::WaitableEvent* event = static_cast<base::WaitableEvent*>(cond_ptr);
+
+  // Wait for the main thread to signal that the filter has been applied.
+  if (!event->IsSignaled()) {
+    event->Wait();
+  }
+
+  BPF_ASSERT(event->IsSignaled());
+
+  BlacklistNanosleepPolicy::AssertNanosleepFails();
+
+  return NULL;
+}
+
+SANDBOX_TEST(SandboxBPF, Tsync) {
+  const bool supports_multi_threaded = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::MULTI_THREADED);
+// On Chrome OS tsync is mandatory.
+#if defined(OS_CHROMEOS)
+  if (base::SysInfo::IsRunningOnChromeOS()) {
+    BPF_ASSERT_EQ(true, supports_multi_threaded);
+  }
+// else a Chrome OS build not running on a Chrome OS device e.g. Chrome bots.
+// In this case fall through.
+#endif
+  if (!supports_multi_threaded) {
+    return;
+  }
+
+  base::WaitableEvent event(true, false);
+
+  // Create a thread on which to invoke the blocked syscall.
+  pthread_t thread;
+  BPF_ASSERT_EQ(
+      0, pthread_create(&thread, NULL, &TsyncApplyToTwoThreadsFunc, &event));
+
+  // Test that nanoseelp success.
+  const struct timespec ts = {0, 0};
+  BPF_ASSERT_EQ(0, HANDLE_EINTR(syscall(__NR_nanosleep, &ts, NULL)));
+
+  // Engage the sandbox.
+  SandboxBPF sandbox(new BlacklistNanosleepPolicy());
+  BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::SeccompLevel::MULTI_THREADED));
+
+  // This thread should have the filter applied as well.
+  BlacklistNanosleepPolicy::AssertNanosleepFails();
+
+  // Signal the condition to invoke the system call.
+  event.Signal();
+
+  // Wait for the thread to finish.
+  BPF_ASSERT_EQ(0, pthread_join(thread, NULL));
+}
+
+class AllowAllPolicy : public Policy {
+ public:
+  AllowAllPolicy() {}
+  ~AllowAllPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override { return Allow(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
+};
+
+SANDBOX_DEATH_TEST(
+    SandboxBPF,
+    StartMultiThreadedAsSingleThreaded,
+    DEATH_MESSAGE(
+        ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests())) {
+  base::Thread thread("sandbox.linux.StartMultiThreadedAsSingleThreaded");
+  BPF_ASSERT(thread.Start());
+
+  SandboxBPF sandbox(new AllowAllPolicy());
+  BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
+}
+
+// http://crbug.com/407357
+#if !defined(THREAD_SANITIZER)
+SANDBOX_DEATH_TEST(
+    SandboxBPF,
+    StartSingleThreadedAsMultiThreaded,
+    DEATH_MESSAGE(
+        "Cannot start sandbox; process may be single-threaded when "
+        "reported as not")) {
+  SandboxBPF sandbox(new AllowAllPolicy());
+  BPF_ASSERT(!sandbox.StartSandbox(SandboxBPF::SeccompLevel::MULTI_THREADED));
+}
+#endif  // !defined(THREAD_SANITIZER)
+
+// A stub handler for the UnsafeTrap. Never called.
+intptr_t NoOpHandler(const struct arch_seccomp_data& args, void*) {
+  return -1;
+}
+
+class UnsafeTrapWithCondPolicy : public Policy {
+ public:
+  UnsafeTrapWithCondPolicy() {}
+  ~UnsafeTrapWithCondPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    setenv(kSandboxDebuggingEnv, "t", 0);
+    Die::SuppressInfoMessages(true);
+
+    if (SandboxBPF::IsRequiredForUnsafeTrap(sysno))
+      return Allow();
+
+    switch (sysno) {
+      case __NR_uname: {
+        const Arg<uint32_t> arg(0);
+        return If(arg == 0, Allow()).Else(Error(EPERM));
+      }
+      case __NR_setgid: {
+        const Arg<uint32_t> arg(0);
+        return Switch(arg)
+            .Case(100, Error(ENOMEM))
+            .Case(200, Error(ENOSYS))
+            .Default(Error(EPERM));
+      }
+      case __NR_close:
+      case __NR_exit_group:
+      case __NR_write:
+        return Allow();
+      case __NR_getppid:
+        return UnsafeTrap(NoOpHandler, NULL);
+      default:
+        return Error(EPERM);
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UnsafeTrapWithCondPolicy);
+};
+
+BPF_TEST_C(SandboxBPF, UnsafeTrapWithCond, UnsafeTrapWithCondPolicy) {
+  BPF_ASSERT_EQ(-1, syscall(__NR_uname, 0));
+  BPF_ASSERT_EQ(EFAULT, errno);
+
+  BPF_ASSERT_EQ(-1, syscall(__NR_uname, 1));
+  BPF_ASSERT_EQ(EPERM, errno);
+
+  BPF_ASSERT_EQ(-1, syscall(__NR_setgid, 100));
+  BPF_ASSERT_EQ(ENOMEM, errno);
+
+  BPF_ASSERT_EQ(-1, syscall(__NR_setgid, 200));
+  BPF_ASSERT_EQ(ENOSYS, errno);
+
+  BPF_ASSERT_EQ(-1, syscall(__NR_setgid, 300));
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+}  // namespace
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc b/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
new file mode 100644
index 0000000..dafa91d
--- /dev/null
+++ b/sandbox/linux/integration_tests/namespace_unix_domain_socket_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "base/process/process.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+// Additional tests for base's UnixDomainSocket to make sure it behaves
+// correctly in the presence of sandboxing functionality (e.g., receiving
+// PIDs across namespaces).
+
+namespace sandbox {
+
+namespace {
+
+const char kHello[] = "hello";
+
+// If the calling process isn't root, then try using unshare(CLONE_NEWUSER)
+// to fake it.
+void FakeRoot() {
+  // If we're already root, then allow test to proceed.
+  if (geteuid() == 0)
+    return;
+
+  // Otherwise hope the kernel supports unprivileged namespaces.
+  if (unshare(CLONE_NEWUSER) == 0)
+    return;
+
+  printf("Permission to use CLONE_NEWPID missing; skipping test.\n");
+  UnitTests::IgnoreThisTest();
+}
+
+void WaitForExit(pid_t pid) {
+  int status;
+  CHECK_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(0, WEXITSTATUS(status));
+}
+
+base::ProcessId GetParentProcessId(base::ProcessId pid) {
+  // base::GetParentProcessId() is defined as taking a ProcessHandle instead of
+  // a ProcessId, even though it's a POSIX-only function and IDs and Handles
+  // are both simply pid_t on POSIX... :/
+  base::Process process = base::Process::Open(pid);
+  CHECK(process.IsValid());
+  base::ProcessId ret = base::GetParentProcessId(process.Handle());
+  return ret;
+}
+
+// SendHello sends a "hello" to socket fd, and then blocks until the recipient
+// acknowledges it by calling RecvHello.
+void SendHello(int fd) {
+  int pipe_fds[2];
+  CHECK_EQ(0, pipe(pipe_fds));
+  base::ScopedFD read_pipe(pipe_fds[0]);
+  base::ScopedFD write_pipe(pipe_fds[1]);
+
+  std::vector<int> send_fds;
+  send_fds.push_back(write_pipe.get());
+  CHECK(UnixDomainSocket::SendMsg(fd, kHello, sizeof(kHello), send_fds));
+
+  write_pipe.reset();
+
+  // Block until receiver closes their end of the pipe.
+  char ch;
+  CHECK_EQ(0, HANDLE_EINTR(read(read_pipe.get(), &ch, 1)));
+}
+
+// RecvHello receives and acknowledges a "hello" on socket fd, and returns the
+// process ID of the sender in sender_pid.  Optionally, write_pipe can be used
+// to return a file descriptor, and the acknowledgement will be delayed until
+// the descriptor is closed.
+// (Implementation details: SendHello allocates a new pipe, sends us the writing
+// end alongside the "hello" message, and then blocks until we close the writing
+// end of the pipe.)
+void RecvHello(int fd,
+               base::ProcessId* sender_pid,
+               base::ScopedFD* write_pipe = NULL) {
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  ScopedVector<base::ScopedFD> message_fds;
+  ssize_t n = UnixDomainSocket::RecvMsgWithPid(
+      fd, buf, sizeof(buf), &message_fds, sender_pid);
+  CHECK_EQ(sizeof(kHello), static_cast<size_t>(n));
+  CHECK_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  CHECK_EQ(1U, message_fds.size());
+  if (write_pipe)
+    write_pipe->swap(*message_fds[0]);
+}
+
+// Check that receiving PIDs works across a fork().
+SANDBOX_TEST(UnixDomainSocketTest, Fork) {
+  int fds[2];
+  CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD recv_sock(fds[0]);
+  base::ScopedFD send_sock(fds[1]);
+
+  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  const pid_t pid = fork();
+  CHECK_NE(-1, pid);
+  if (pid == 0) {
+    // Child process.
+    recv_sock.reset();
+    SendHello(send_sock.get());
+    _exit(0);
+  }
+
+  // Parent process.
+  send_sock.reset();
+
+  base::ProcessId sender_pid;
+  RecvHello(recv_sock.get(), &sender_pid);
+  CHECK_EQ(pid, sender_pid);
+
+  WaitForExit(pid);
+}
+
+// Similar to Fork above, but forking the child into a new pid namespace.
+SANDBOX_TEST(UnixDomainSocketTest, Namespace) {
+  FakeRoot();
+
+  int fds[2];
+  CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD recv_sock(fds[0]);
+  base::ScopedFD send_sock(fds[1]);
+
+  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
+  CHECK_NE(-1, pid);
+  if (pid == 0) {
+    // Child process.
+    recv_sock.reset();
+
+    // Check that we think we're pid 1 in our new namespace.
+    CHECK_EQ(1, sys_getpid());
+
+    SendHello(send_sock.get());
+    _exit(0);
+  }
+
+  // Parent process.
+  send_sock.reset();
+
+  base::ProcessId sender_pid;
+  RecvHello(recv_sock.get(), &sender_pid);
+  CHECK_EQ(pid, sender_pid);
+
+  WaitForExit(pid);
+}
+
+// Again similar to Fork, but now with nested PID namespaces.
+SANDBOX_TEST(UnixDomainSocketTest, DoubleNamespace) {
+  FakeRoot();
+
+  int fds[2];
+  CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD recv_sock(fds[0]);
+  base::ScopedFD send_sock(fds[1]);
+
+  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
+  CHECK_NE(-1, pid);
+  if (pid == 0) {
+    // Child process.
+    recv_sock.reset();
+
+    const pid_t pid2 = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
+    CHECK_NE(-1, pid2);
+
+    if (pid2 != 0) {
+      // Wait for grandchild to run to completion; see comments below.
+      WaitForExit(pid2);
+
+      // Fallthrough once grandchild has sent its hello and exited.
+    }
+
+    // Check that we think we're pid 1.
+    CHECK_EQ(1, sys_getpid());
+
+    SendHello(send_sock.get());
+    _exit(0);
+  }
+
+  // Parent process.
+  send_sock.reset();
+
+  // We have two messages to receive: first from the grand-child,
+  // then from the child.
+  for (unsigned iteration = 0; iteration < 2; ++iteration) {
+    base::ProcessId sender_pid;
+    base::ScopedFD pipe_fd;
+    RecvHello(recv_sock.get(), &sender_pid, &pipe_fd);
+
+    // We need our child and grandchild processes to both be alive for
+    // GetParentProcessId() to return a valid pid, hence the pipe trickery.
+    // (On the first iteration, grandchild is blocked reading from the pipe
+    // until we close it, and child is blocked waiting for grandchild to exit.)
+    switch (iteration) {
+      case 0:  // Grandchild's message
+        // Check that sender_pid refers to our grandchild by checking that pid
+        // (our child) is its parent.
+        CHECK_EQ(pid, GetParentProcessId(sender_pid));
+        break;
+      case 1:  // Child's message
+        CHECK_EQ(pid, sender_pid);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  WaitForExit(pid);
+}
+
+// Tests that GetPeerPid() returns 0 if the peer does not exist in caller's
+// namespace.
+SANDBOX_TEST(UnixDomainSocketTest, ImpossiblePid) {
+  FakeRoot();
+
+  int fds[2];
+  CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  base::ScopedFD send_sock(fds[0]);
+  base::ScopedFD recv_sock(fds[1]);
+
+  CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
+  CHECK_NE(-1, pid);
+  if (pid == 0) {
+    // Child process.
+    send_sock.reset();
+
+    base::ProcessId sender_pid;
+    RecvHello(recv_sock.get(), &sender_pid);
+    CHECK_EQ(0, sender_pid);
+    _exit(0);
+  }
+
+  // Parent process.
+  recv_sock.reset();
+  SendHello(send_sock.get());
+  WaitForExit(pid);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc b/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
new file mode 100644
index 0000000..9aa3209
--- /dev/null
+++ b/sandbox/linux/integration_tests/seccomp_broker_process_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
+#include "sandbox/linux/syscall_broker/broker_process.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+using bpf_dsl::Allow;
+using bpf_dsl::ResultExpr;
+using bpf_dsl::Trap;
+
+bool NoOpCallback() {
+  return true;
+}
+
+// Test a trap handler that makes use of a broker process to open().
+
+class InitializedOpenBroker {
+ public:
+  InitializedOpenBroker() : initialized_(false) {
+    std::vector<syscall_broker::BrokerFilePermission> permissions;
+    permissions.push_back(
+        syscall_broker::BrokerFilePermission::ReadOnly("/proc/allowed"));
+    permissions.push_back(
+        syscall_broker::BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
+
+    broker_process_.reset(
+        new syscall_broker::BrokerProcess(EPERM, permissions));
+    BPF_ASSERT(broker_process() != NULL);
+    BPF_ASSERT(broker_process_->Init(base::Bind(&NoOpCallback)));
+
+    initialized_ = true;
+  }
+  bool initialized() { return initialized_; }
+  class syscall_broker::BrokerProcess* broker_process() {
+    return broker_process_.get();
+  }
+
+ private:
+  bool initialized_;
+  scoped_ptr<class syscall_broker::BrokerProcess> broker_process_;
+  DISALLOW_COPY_AND_ASSIGN(InitializedOpenBroker);
+};
+
+intptr_t BrokerOpenTrapHandler(const struct arch_seccomp_data& args,
+                               void* aux) {
+  BPF_ASSERT(aux);
+  syscall_broker::BrokerProcess* broker_process =
+      static_cast<syscall_broker::BrokerProcess*>(aux);
+  switch (args.nr) {
+    case __NR_faccessat:  // access is a wrapper of faccessat in android
+      BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD);
+      return broker_process->Access(reinterpret_cast<const char*>(args.args[1]),
+                                    static_cast<int>(args.args[2]));
+#if defined(__NR_access)
+    case __NR_access:
+      return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
+                                    static_cast<int>(args.args[1]));
+#endif
+#if defined(__NR_open)
+    case __NR_open:
+      return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
+                                  static_cast<int>(args.args[1]));
+#endif
+    case __NR_openat:
+      // We only call open() so if we arrive here, it's because glibc uses
+      // the openat() system call.
+      BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD);
+      return broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
+                                  static_cast<int>(args.args[2]));
+    default:
+      BPF_ASSERT(false);
+      return -ENOSYS;
+  }
+}
+
+class DenyOpenPolicy : public bpf_dsl::Policy {
+ public:
+  explicit DenyOpenPolicy(InitializedOpenBroker* iob) : iob_(iob) {}
+  ~DenyOpenPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+
+    switch (sysno) {
+      case __NR_faccessat:
+#if defined(__NR_access)
+      case __NR_access:
+#endif
+#if defined(__NR_open)
+      case __NR_open:
+#endif
+      case __NR_openat:
+        // We get a InitializedOpenBroker class, but our trap handler wants
+        // the syscall_broker::BrokerProcess object.
+        return Trap(BrokerOpenTrapHandler, iob_->broker_process());
+      default:
+        return Allow();
+    }
+  }
+
+ private:
+  InitializedOpenBroker* iob_;
+
+  DISALLOW_COPY_AND_ASSIGN(DenyOpenPolicy);
+};
+
+// We use a InitializedOpenBroker class, so that we can run unsandboxed
+// code in its constructor, which is the only way to do so in a BPF_TEST.
+BPF_TEST(SandboxBPF,
+         UseOpenBroker,
+         DenyOpenPolicy,
+         InitializedOpenBroker /* (*BPF_AUX) */) {
+  BPF_ASSERT(BPF_AUX->initialized());
+  syscall_broker::BrokerProcess* broker_process = BPF_AUX->broker_process();
+  BPF_ASSERT(broker_process != NULL);
+
+  // First, use the broker "manually"
+  BPF_ASSERT(broker_process->Open("/proc/denied", O_RDONLY) == -EPERM);
+  BPF_ASSERT(broker_process->Access("/proc/denied", R_OK) == -EPERM);
+  BPF_ASSERT(broker_process->Open("/proc/allowed", O_RDONLY) == -ENOENT);
+  BPF_ASSERT(broker_process->Access("/proc/allowed", R_OK) == -ENOENT);
+
+  // Now use glibc's open() as an external library would.
+  BPF_ASSERT(open("/proc/denied", O_RDONLY) == -1);
+  BPF_ASSERT(errno == EPERM);
+
+  BPF_ASSERT(open("/proc/allowed", O_RDONLY) == -1);
+  BPF_ASSERT(errno == ENOENT);
+
+  // Also test glibc's openat(), some versions of libc use it transparently
+  // instead of open().
+  BPF_ASSERT(openat(AT_FDCWD, "/proc/denied", O_RDONLY) == -1);
+  BPF_ASSERT(errno == EPERM);
+
+  BPF_ASSERT(openat(AT_FDCWD, "/proc/allowed", O_RDONLY) == -1);
+  BPF_ASSERT(errno == ENOENT);
+
+  // And test glibc's access().
+  BPF_ASSERT(access("/proc/denied", R_OK) == -1);
+  BPF_ASSERT(errno == EPERM);
+
+  BPF_ASSERT(access("/proc/allowed", R_OK) == -1);
+  BPF_ASSERT(errno == ENOENT);
+
+  // This is also white listed and does exist.
+  int cpu_info_access = access("/proc/cpuinfo", R_OK);
+  BPF_ASSERT(cpu_info_access == 0);
+  int cpu_info_fd = open("/proc/cpuinfo", O_RDONLY);
+  BPF_ASSERT(cpu_info_fd >= 0);
+  char buf[1024];
+  BPF_ASSERT(read(cpu_info_fd, buf, sizeof(buf)) > 0);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
new file mode 100644
index 0000000..7724223
--- /dev/null
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -0,0 +1,405 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'conditions': [
+      ['OS=="linux"', {
+        'compile_suid_client': 1,
+        'compile_credentials': 1,
+      }, {
+        'compile_suid_client': 0,
+        'compile_credentials': 0,
+      }],
+      ['OS=="linux" and (target_arch=="ia32" or target_arch=="x64" or '
+         'target_arch=="mipsel")', {
+        'compile_seccomp_bpf_demo': 1,
+      }, {
+        'compile_seccomp_bpf_demo': 0,
+      }],
+    ],
+  },
+  'target_defaults': {
+    'target_conditions': [
+      # All linux/ files will automatically be excluded on Android
+      # so make sure we re-include them explicitly.
+      ['OS == "android"', {
+        'sources/': [
+          ['include', '^linux/'],
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    # We have two principal targets: sandbox and sandbox_linux_unittests
+    # All other targets are listed as dependencies.
+    # There is one notable exception: for historical reasons, chrome_sandbox is
+    # the setuid sandbox and is its own target.
+    {
+      'target_name': 'sandbox',
+      'type': 'none',
+      'dependencies': [
+        'sandbox_services',
+      ],
+      'conditions': [
+        [ 'compile_suid_client==1', {
+          'dependencies': [
+            'suid_sandbox_client',
+          ],
+        }],
+        # Compile seccomp BPF when we support it.
+        [ 'use_seccomp_bpf==1', {
+          'dependencies': [
+            'seccomp_bpf',
+            'seccomp_bpf_helpers',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'sandbox_linux_test_utils',
+      'type': 'static_library',
+      'dependencies': [
+        '../testing/gtest.gyp:gtest',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [
+        'tests/sandbox_test_runner.cc',
+        'tests/sandbox_test_runner.h',
+        'tests/sandbox_test_runner_function_pointer.cc',
+        'tests/sandbox_test_runner_function_pointer.h',
+        'tests/test_utils.cc',
+        'tests/test_utils.h',
+        'tests/unit_tests.cc',
+        'tests/unit_tests.h',
+      ],
+      'conditions': [
+        [ 'use_seccomp_bpf==1', {
+          'sources': [
+            'seccomp-bpf/bpf_tester_compatibility_delegate.h',
+            'seccomp-bpf/bpf_tests.h',
+            'seccomp-bpf/sandbox_bpf_test_runner.cc',
+            'seccomp-bpf/sandbox_bpf_test_runner.h',
+          ],
+          'dependencies': [
+            'seccomp_bpf',
+          ]
+        }],
+      ],
+    },
+    {
+      # The main sandboxing test target.
+      'target_name': 'sandbox_linux_unittests',
+      'includes': [
+        'sandbox_linux_test_sources.gypi',
+      ],
+      'type': 'executable',
+    },
+    {
+      # This target is the shared library used by Android APK (i.e.
+      # JNI-friendly) tests.
+      'target_name': 'sandbox_linux_jni_unittests',
+      'includes': [
+        'sandbox_linux_test_sources.gypi',
+      ],
+      'type': 'shared_library',
+      'conditions': [
+        [ 'OS == "android"', {
+          'dependencies': [
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'seccomp_bpf',
+      'type': '<(component)',
+      'sources': [
+        'bpf_dsl/bpf_dsl.cc',
+        'bpf_dsl/bpf_dsl.h',
+        'bpf_dsl/bpf_dsl_forward.h',
+        'bpf_dsl/bpf_dsl_impl.h',
+        'bpf_dsl/codegen.cc',
+        'bpf_dsl/codegen.h',
+        'bpf_dsl/cons.h',
+        'bpf_dsl/dump_bpf.cc',
+        'bpf_dsl/dump_bpf.h',
+        'bpf_dsl/linux_syscall_ranges.h',
+        'bpf_dsl/policy.cc',
+        'bpf_dsl/policy.h',
+        'bpf_dsl/policy_compiler.cc',
+        'bpf_dsl/policy_compiler.h',
+        'bpf_dsl/seccomp_macros.h',
+        'bpf_dsl/seccomp_macros.h',
+        'bpf_dsl/syscall_set.cc',
+        'bpf_dsl/syscall_set.h',
+        'bpf_dsl/trap_registry.h',
+        'bpf_dsl/verifier.cc',
+        'bpf_dsl/verifier.h',
+        'seccomp-bpf/die.cc',
+        'seccomp-bpf/die.h',
+        'seccomp-bpf/errorcode.cc',
+        'seccomp-bpf/errorcode.h',
+        'seccomp-bpf/sandbox_bpf.cc',
+        'seccomp-bpf/sandbox_bpf.h',
+        'seccomp-bpf/syscall.cc',
+        'seccomp-bpf/syscall.h',
+        'seccomp-bpf/trap.cc',
+        'seccomp-bpf/trap.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'sandbox_services',
+        'sandbox_services_headers',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'includes': [
+        # Disable LTO due to compiler bug
+        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57703
+        '../../build/android/disable_lto.gypi',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+    {
+      'target_name': 'seccomp_bpf_helpers',
+      'type': '<(component)',
+      'sources': [
+        'seccomp-bpf-helpers/baseline_policy.cc',
+        'seccomp-bpf-helpers/baseline_policy.h',
+        'seccomp-bpf-helpers/sigsys_handlers.cc',
+        'seccomp-bpf-helpers/sigsys_handlers.h',
+        'seccomp-bpf-helpers/syscall_parameters_restrictions.cc',
+        'seccomp-bpf-helpers/syscall_parameters_restrictions.h',
+        'seccomp-bpf-helpers/syscall_sets.cc',
+        'seccomp-bpf-helpers/syscall_sets.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'sandbox_services',
+        'seccomp_bpf',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+    {
+      # The setuid sandbox, for Linux
+      'target_name': 'chrome_sandbox',
+      'type': 'executable',
+      'sources': [
+        'suid/common/sandbox.h',
+        'suid/common/suid_unsafe_environment_variables.h',
+        'suid/process_util.h',
+        'suid/process_util_linux.c',
+        'suid/sandbox.c',
+      ],
+      'cflags': [
+        # For ULLONG_MAX
+        '-std=gnu99',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      # Do not use any sanitizer tools with this binary. http://crbug.com/382766
+      'cflags/': [
+        ['exclude', '-fsanitize'],
+      ],
+      'ldflags/': [
+        ['exclude', '-fsanitize'],
+      ],
+    },
+    { 'target_name': 'sandbox_services',
+      'type': '<(component)',
+      'sources': [
+        'services/init_process_reaper.cc',
+        'services/init_process_reaper.h',
+        'services/proc_util.cc',
+        'services/proc_util.h',
+        'services/resource_limits.cc',
+        'services/resource_limits.h',
+        'services/scoped_process.cc',
+        'services/scoped_process.h',
+        'services/syscall_wrappers.cc',
+        'services/syscall_wrappers.h',
+        'services/thread_helpers.cc',
+        'services/thread_helpers.h',
+        'services/yama.cc',
+        'services/yama.h',
+        'syscall_broker/broker_channel.cc',
+        'syscall_broker/broker_channel.h',
+        'syscall_broker/broker_client.cc',
+        'syscall_broker/broker_client.h',
+        'syscall_broker/broker_common.h',
+        'syscall_broker/broker_file_permission.cc',
+        'syscall_broker/broker_file_permission.h',
+        'syscall_broker/broker_host.cc',
+        'syscall_broker/broker_host.h',
+        'syscall_broker/broker_policy.cc',
+        'syscall_broker/broker_policy.h',
+        'syscall_broker/broker_process.cc',
+        'syscall_broker/broker_process.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'conditions': [
+        ['compile_credentials==1', {
+          'sources': [
+            'services/credentials.cc',
+            'services/credentials.h',
+            'services/namespace_sandbox.cc',
+            'services/namespace_sandbox.h',
+            'services/namespace_utils.cc',
+            'services/namespace_utils.h',
+          ],
+          'dependencies': [
+            # for capability.h.
+            'sandbox_services_headers',
+          ],
+        }],
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    { 'target_name': 'sandbox_services_headers',
+      'type': 'none',
+      'sources': [
+        'system_headers/arm64_linux_syscalls.h',
+        'system_headers/arm64_linux_ucontext.h',
+        'system_headers/arm_linux_syscalls.h',
+        'system_headers/arm_linux_ucontext.h',
+        'system_headers/capability.h',
+        'system_headers/i386_linux_ucontext.h',
+        'system_headers/linux_futex.h',
+        'system_headers/linux_seccomp.h',
+        'system_headers/linux_syscalls.h',
+        'system_headers/linux_ucontext.h',
+        'system_headers/mips_linux_syscalls.h',
+        'system_headers/mips_linux_ucontext.h',
+        'system_headers/x86_32_linux_syscalls.h',
+        'system_headers/x86_64_linux_syscalls.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      # We make this its own target so that it does not interfere
+      # with our tests.
+      'target_name': 'libc_urandom_override',
+      'type': 'static_library',
+      'sources': [
+        'services/libc_urandom_override.cc',
+        'services/libc_urandom_override.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      'target_name': 'suid_sandbox_client',
+      'type': '<(component)',
+      'sources': [
+        'suid/common/sandbox.h',
+        'suid/common/suid_unsafe_environment_variables.h',
+        'suid/client/setuid_sandbox_client.cc',
+        'suid/client/setuid_sandbox_client.h',
+        'suid/client/setuid_sandbox_host.cc',
+        'suid/client/setuid_sandbox_host.h',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'sandbox_services',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+  ],
+  'conditions': [
+    [ 'OS=="android"', {
+      'targets': [
+      {
+        'target_name': 'sandbox_linux_unittests_stripped',
+        'type': 'none',
+        'dependencies': [ 'sandbox_linux_unittests' ],
+        'actions': [{
+          'action_name': 'strip sandbox_linux_unittests',
+          'inputs': [ '<(PRODUCT_DIR)/sandbox_linux_unittests' ],
+          'outputs': [ '<(PRODUCT_DIR)/sandbox_linux_unittests_stripped' ],
+          'action': [ '<(android_strip)', '<@(_inputs)', '-o', '<@(_outputs)' ],
+        }],
+      },
+      {
+        'target_name': 'sandbox_linux_unittests_deps',
+        'type': 'none',
+        'dependencies': [
+          'sandbox_linux_unittests_stripped',
+        ],
+        # For the component build, ensure dependent shared libraries are
+        # stripped and put alongside sandbox_linux_unittests to simplify pushing
+        # to the device.
+        'variables': {
+           'output_dir': '<(PRODUCT_DIR)/sandbox_linux_unittests_deps/',
+           'native_binary': '<(PRODUCT_DIR)/sandbox_linux_unittests_stripped',
+           'include_main_binary': 0,
+        },
+        'includes': [
+          '../../build/android/native_app_dependencies.gypi'
+        ],
+      }],
+    }],
+    [ 'OS=="android"', {
+      'targets': [
+        {
+        'target_name': 'sandbox_linux_jni_unittests_apk',
+        'type': 'none',
+        'variables': {
+          'test_suite_name': 'sandbox_linux_jni_unittests',
+        },
+        'dependencies': [
+          'sandbox_linux_jni_unittests',
+        ],
+        'includes': [ '../../build/apk_test.gypi' ],
+        }
+      ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'sandbox_linux_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'sandbox_linux_unittests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sandbox_linux_unittests.isolate',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/sandbox/linux/sandbox_linux_test_sources.gypi b/sandbox/linux/sandbox_linux_test_sources.gypi
new file mode 100644
index 0000000..ce7817d
--- /dev/null
+++ b/sandbox/linux/sandbox_linux_test_sources.gypi
@@ -0,0 +1,71 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Tests need to be compiled in the same link unit, so we have to list them
+# in a separate .gypi file.
+{
+  'dependencies': [
+    'sandbox',
+    'sandbox_linux_test_utils',
+    'sandbox_services',
+    '../base/base.gyp:base',
+    '../base/base.gyp:test_support_base',
+    '../testing/gtest.gyp:gtest',
+  ],
+  'include_dirs': [
+    '../..',
+  ],
+  'sources': [
+    'services/proc_util_unittest.cc',
+    'services/scoped_process_unittest.cc',
+    'services/resource_limits_unittests.cc',
+    'services/syscall_wrappers_unittest.cc',
+    'services/thread_helpers_unittests.cc',
+    'services/yama_unittests.cc',
+    'syscall_broker/broker_file_permission_unittest.cc',
+    'syscall_broker/broker_process_unittest.cc',
+    'tests/main.cc',
+    'tests/scoped_temporary_file.cc',
+    'tests/scoped_temporary_file.h',
+    'tests/scoped_temporary_file_unittest.cc',
+    'tests/test_utils_unittest.cc',
+    'tests/unit_tests_unittest.cc',
+  ],
+  'conditions': [
+    [ 'compile_suid_client==1', {
+      'sources': [
+        'suid/client/setuid_sandbox_client_unittest.cc',
+        'suid/client/setuid_sandbox_host_unittest.cc',
+      ],
+    }],
+    [ 'use_seccomp_bpf==1', {
+      'sources': [
+        'bpf_dsl/bpf_dsl_unittest.cc',
+        'bpf_dsl/codegen_unittest.cc',
+        'bpf_dsl/cons_unittest.cc',
+        'bpf_dsl/syscall_set_unittest.cc',
+        'integration_tests/bpf_dsl_seccomp_unittest.cc',
+        'integration_tests/seccomp_broker_process_unittest.cc',
+        'seccomp-bpf-helpers/baseline_policy_unittest.cc',
+        'seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc',
+        'seccomp-bpf/bpf_tests_unittest.cc',
+        'seccomp-bpf/errorcode_unittest.cc',
+        'seccomp-bpf/sandbox_bpf_unittest.cc',
+        'seccomp-bpf/syscall_unittest.cc',
+        'seccomp-bpf/trap_unittest.cc',
+      ],
+    }],
+    [ 'compile_credentials==1', {
+      'sources': [
+        'integration_tests/namespace_unix_domain_socket_unittest.cc',
+        'services/credentials_unittest.cc',
+        'services/namespace_sandbox_unittest.cc',
+        'services/namespace_utils_unittest.cc',
+      ],
+      'dependencies': [
+        '../build/linux/system.gyp:libcap'
+      ],
+    }],
+  ],
+}
diff --git a/sandbox/linux/seccomp-bpf-helpers/DEPS b/sandbox/linux/seccomp-bpf-helpers/DEPS
new file mode 100644
index 0000000..4419fd1
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+sandbox/linux/bpf_dsl",
+  "+sandbox/linux/seccomp-bpf",
+  "+sandbox/linux/services",
+  "+sandbox/linux/system_headers",
+  "+third_party/lss/linux_syscall_support.h",
+]
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
new file mode 100644
index 0000000..8c679a3
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+// Changing this implementation will have an effect on *all* policies.
+// Currently this means: Renderer/Worker, GPU, Flash and NaCl.
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Arg;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::If;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+namespace {
+
+bool IsBaselinePolicyAllowed(int sysno) {
+  return SyscallSets::IsAllowedAddressSpaceAccess(sysno) ||
+         SyscallSets::IsAllowedBasicScheduler(sysno) ||
+         SyscallSets::IsAllowedEpoll(sysno) ||
+         SyscallSets::IsAllowedFileSystemAccessViaFd(sysno) ||
+         SyscallSets::IsAllowedFutex(sysno) ||
+         SyscallSets::IsAllowedGeneralIo(sysno) ||
+         SyscallSets::IsAllowedGetOrModifySocket(sysno) ||
+         SyscallSets::IsAllowedGettime(sysno) ||
+         SyscallSets::IsAllowedProcessStartOrDeath(sysno) ||
+         SyscallSets::IsAllowedSignalHandling(sysno) ||
+         SyscallSets::IsGetSimpleId(sysno) ||
+         SyscallSets::IsKernelInternalApi(sysno) ||
+#if defined(__arm__)
+         SyscallSets::IsArmPrivate(sysno) ||
+#endif
+#if defined(__mips__)
+         SyscallSets::IsMipsPrivate(sysno) ||
+#endif
+         SyscallSets::IsAllowedOperationOnFd(sysno);
+}
+
+// System calls that will trigger the crashing SIGSYS handler.
+bool IsBaselinePolicyWatched(int sysno) {
+  return SyscallSets::IsAdminOperation(sysno) ||
+         SyscallSets::IsAdvancedScheduler(sysno) ||
+         SyscallSets::IsAdvancedTimer(sysno) ||
+         SyscallSets::IsAsyncIo(sysno) ||
+         SyscallSets::IsDebug(sysno) ||
+         SyscallSets::IsEventFd(sysno) ||
+         SyscallSets::IsExtendedAttributes(sysno) ||
+         SyscallSets::IsFaNotify(sysno) ||
+         SyscallSets::IsFsControl(sysno) ||
+         SyscallSets::IsGlobalFSViewChange(sysno) ||
+         SyscallSets::IsGlobalProcessEnvironment(sysno) ||
+         SyscallSets::IsGlobalSystemStatus(sysno) ||
+         SyscallSets::IsInotify(sysno) ||
+         SyscallSets::IsKernelModule(sysno) ||
+         SyscallSets::IsKeyManagement(sysno) ||
+         SyscallSets::IsKill(sysno) ||
+         SyscallSets::IsMessageQueue(sysno) ||
+         SyscallSets::IsMisc(sysno) ||
+#if defined(__x86_64__)
+         SyscallSets::IsNetworkSocketInformation(sysno) ||
+#endif
+         SyscallSets::IsNuma(sysno) ||
+         SyscallSets::IsPrctl(sysno) ||
+         SyscallSets::IsProcessGroupOrSession(sysno) ||
+#if defined(__i386__) || defined(__mips__)
+         SyscallSets::IsSocketCall(sysno) ||
+#endif
+#if defined(__arm__)
+         SyscallSets::IsArmPciConfig(sysno) ||
+#endif
+#if defined(__mips__)
+         SyscallSets::IsMipsMisc(sysno) ||
+#endif
+         SyscallSets::IsTimer(sysno);
+}
+
+// |fs_denied_errno| is the errno return for denied filesystem access.
+ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
+                               pid_t current_pid,
+                               int sysno) {
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
+    defined(MEMORY_SANITIZER)
+  // TCGETS is required by the sanitizers on failure.
+  if (sysno == __NR_ioctl) {
+    return RestrictIoctl();
+  }
+
+  if (sysno == __NR_sched_getaffinity) {
+    return Allow();
+  }
+
+  // Used when RSS limiting is enabled in sanitizers.
+  if (sysno == __NR_getrusage) {
+    return RestrictGetrusage();
+  }
+
+  if (sysno == __NR_sigaltstack) {
+    // Required for better stack overflow detection in ASan. Disallowed in
+    // non-ASan builds.
+    return Allow();
+  }
+#endif  // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||
+        // defined(MEMORY_SANITIZER)
+
+  if (IsBaselinePolicyAllowed(sysno)) {
+    return Allow();
+  }
+
+#if defined(OS_ANDROID)
+  // Needed for thread creation.
+  if (sysno == __NR_sigaltstack)
+    return Allow();
+#endif
+
+  if (sysno == __NR_clock_gettime) {
+    return RestrictClockID();
+  }
+
+  if (sysno == __NR_clone) {
+    return RestrictCloneToThreadsAndEPERMFork();
+  }
+
+  if (sysno == __NR_fcntl)
+    return RestrictFcntlCommands();
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+  if (sysno == __NR_fcntl64)
+    return RestrictFcntlCommands();
+#endif
+
+#if !defined(__aarch64__)
+  // fork() is never used as a system call (clone() is used instead), but we
+  // have seen it in fallback code on Android.
+  if (sysno == __NR_fork) {
+    return Error(EPERM);
+  }
+#endif
+
+  if (sysno == __NR_futex)
+    return RestrictFutex();
+
+  if (sysno == __NR_set_robust_list)
+    return Error(EPERM);
+
+  if (sysno == __NR_getpriority || sysno ==__NR_setpriority)
+    return RestrictGetSetpriority(current_pid);
+
+  if (sysno == __NR_madvise) {
+    // Only allow MADV_DONTNEED (aka MADV_FREE).
+    const Arg<int> advice(2);
+    return If(advice == MADV_DONTNEED, Allow()).Else(Error(EPERM));
+  }
+
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+  if (sysno == __NR_mmap)
+    return RestrictMmapFlags();
+#endif
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+  if (sysno == __NR_mmap2)
+    return RestrictMmapFlags();
+#endif
+
+  if (sysno == __NR_mprotect)
+    return RestrictMprotectFlags();
+
+  if (sysno == __NR_prctl)
+    return RestrictPrctl();
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+  if (sysno == __NR_socketpair) {
+    // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
+    static_assert(AF_UNIX == PF_UNIX,
+                  "af_unix and pf_unix should not be different");
+    const Arg<int> domain(0);
+    return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS());
+  }
+#endif
+
+  if (SyscallSets::IsKill(sysno)) {
+    return RestrictKillTarget(current_pid, sysno);
+  }
+
+  if (SyscallSets::IsFileSystem(sysno) ||
+      SyscallSets::IsCurrentDirectory(sysno)) {
+    return Error(fs_denied_errno);
+  }
+
+  if (SyscallSets::IsSeccomp(sysno))
+    return Error(EPERM);
+
+  if (SyscallSets::IsAnySystemV(sysno)) {
+    return Error(EPERM);
+  }
+
+  if (SyscallSets::IsUmask(sysno) ||
+      SyscallSets::IsDeniedFileSystemAccessViaFd(sysno) ||
+      SyscallSets::IsDeniedGetOrModifySocket(sysno) ||
+      SyscallSets::IsProcessPrivilegeChange(sysno)) {
+    return Error(EPERM);
+  }
+
+#if defined(__i386__) || defined(__mips__)
+  if (SyscallSets::IsSocketCall(sysno))
+    return RestrictSocketcallCommand();
+#endif
+
+  if (IsBaselinePolicyWatched(sysno)) {
+    // Previously unseen syscalls. TODO(jln): some of these should
+    // be denied gracefully right away.
+    return CrashSIGSYS();
+  }
+
+  // In any other case crash the program with our SIGSYS handler.
+  return CrashSIGSYS();
+}
+
+}  // namespace.
+
+// Unfortunately C++03 doesn't allow delegated constructors.
+// Call other constructor when C++11 lands.
+BaselinePolicy::BaselinePolicy() : BaselinePolicy(EPERM) {}
+
+BaselinePolicy::BaselinePolicy(int fs_denied_errno)
+    : fs_denied_errno_(fs_denied_errno), policy_pid_(sys_getpid()) {
+}
+
+BaselinePolicy::~BaselinePolicy() {
+  // Make sure that this policy is created, used and destroyed by a single
+  // process.
+  DCHECK_EQ(sys_getpid(), policy_pid_);
+}
+
+ResultExpr BaselinePolicy::EvaluateSyscall(int sysno) const {
+  // Sanity check that we're only called with valid syscall numbers.
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  // Make sure that this policy is used in the creating process.
+  if (1 == sysno) {
+    DCHECK_EQ(sys_getpid(), policy_pid_);
+  }
+  return EvaluateSyscallImpl(fs_denied_errno_, policy_pid_, sysno);
+}
+
+ResultExpr BaselinePolicy::InvalidSyscall() const {
+  return CrashSIGSYS();
+}
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
new file mode 100644
index 0000000..4169d9c
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This is a helper to build seccomp-bpf policies, i.e. policies for a sandbox
+// that reduces the Linux kernel's attack surface. Given its nature, it doesn't
+// have a clear semantics and is mostly "implementation-defined".
+//
+// This class implements the Policy interface with a "baseline"
+// policy for use within Chromium.
+// The "baseline" policy is somewhat arbitrary. All Chromium policies are an
+// alteration of it, and it represents a reasonable common ground to run most
+// code in a sandboxed environment.
+// A baseline policy is only valid for the process for which this object was
+// instantiated (so do not fork() and use it in a child).
+class SANDBOX_EXPORT BaselinePolicy : public bpf_dsl::Policy {
+ public:
+  BaselinePolicy();
+  // |fs_denied_errno| is the errno returned when a filesystem access system
+  // call is denied.
+  explicit BaselinePolicy(int fs_denied_errno);
+  ~BaselinePolicy() override;
+
+  bpf_dsl::ResultExpr EvaluateSyscall(int system_call_number) const override;
+  bpf_dsl::ResultExpr InvalidSyscall() const override;
+  pid_t policy_pid() const { return policy_pid_; }
+
+ private:
+  int fs_denied_errno_;
+
+  // The PID that the policy applies to (should be equal to the current pid).
+  pid_t policy_pid_;
+
+  DISALLOW_COPY_AND_ASSIGN(BaselinePolicy);
+};
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
new file mode 100644
index 0000000..614849f
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -0,0 +1,334 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/linux_futex.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+namespace {
+
+// This also tests that read(), write() and fstat() are allowed.
+void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) {
+  BPF_ASSERT_LE(0, read_end.get());
+  BPF_ASSERT_LE(0, write_end.get());
+  struct stat stat_buf;
+  int sys_ret = fstat(read_end.get(), &stat_buf);
+  BPF_ASSERT_EQ(0, sys_ret);
+  BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode));
+
+  const ssize_t kTestTransferSize = 4;
+  static const char kTestString[kTestTransferSize] = {'T', 'E', 'S', 'T'};
+  ssize_t transfered = 0;
+
+  transfered =
+      HANDLE_EINTR(write(write_end.get(), kTestString, kTestTransferSize));
+  BPF_ASSERT_EQ(kTestTransferSize, transfered);
+  char read_buf[kTestTransferSize + 1] = {0};
+  transfered = HANDLE_EINTR(read(read_end.get(), read_buf, sizeof(read_buf)));
+  BPF_ASSERT_EQ(kTestTransferSize, transfered);
+  BPF_ASSERT_EQ(0, memcmp(kTestString, read_buf, kTestTransferSize));
+}
+
+// Test that a few easy-to-test system calls are allowed.
+BPF_TEST_C(BaselinePolicy, BaselinePolicyBasicAllowed, BaselinePolicy) {
+  BPF_ASSERT_EQ(0, sched_yield());
+
+  int pipefd[2];
+  int sys_ret = pipe(pipefd);
+  BPF_ASSERT_EQ(0, sys_ret);
+  TestPipeOrSocketPair(base::ScopedFD(pipefd[0]), base::ScopedFD(pipefd[1]));
+
+  BPF_ASSERT_LE(1, getpid());
+  BPF_ASSERT_LE(0, getuid());
+}
+
+BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) {
+  int ret = fchmod(-1, 07777);
+  BPF_ASSERT_EQ(-1, ret);
+  // Without the sandbox, this would EBADF instead.
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) {
+  errno = 0;
+  pid_t pid = fork();
+  const int fork_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, fork_errno);
+}
+
+pid_t ForkX86Glibc() {
+  static pid_t ptid;
+  return sys_clone(CLONE_PARENT_SETTID | SIGCHLD, nullptr, &ptid, nullptr,
+                   nullptr);
+}
+
+BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) {
+  errno = 0;
+  pid_t pid = ForkX86Glibc();
+  const int fork_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, fork_errno);
+}
+
+pid_t ForkARMGlibc() {
+  static pid_t ctid;
+  return sys_clone(CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, nullptr,
+                   nullptr, &ctid, nullptr);
+}
+
+BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) {
+  errno = 0;
+  pid_t pid = ForkARMGlibc();
+  const int fork_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, fork_errno);
+}
+
+BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) {
+  base::Thread thread("sandbox_tests");
+  BPF_ASSERT(thread.Start());
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 DisallowedCloneFlagCrashes,
+                 DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  pid_t pid = sys_clone(CLONE_THREAD | SIGCHLD);
+  TestUtils::HandlePostForkReturn(pid);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 DisallowedKillCrashes,
+                 DEATH_SEGV_MESSAGE(GetKillErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  BPF_ASSERT_NE(1, getpid());
+  kill(1, 0);
+  _exit(0);
+}
+
+BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) {
+  int sys_ret = kill(getpid(), 0);
+  BPF_ASSERT_EQ(0, sys_ret);
+}
+
+BPF_TEST_C(BaselinePolicy, Socketpair, BaselinePolicy) {
+  int sv[2];
+  int sys_ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
+  BPF_ASSERT_EQ(0, sys_ret);
+  TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1]));
+
+  sys_ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv);
+  BPF_ASSERT_EQ(0, sys_ret);
+  TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1]));
+}
+
+// Not all architectures can restrict the domain for socketpair().
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SocketpairWrongDomain,
+                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int sv[2];
+  ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv));
+  _exit(1);
+}
+#endif  // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+
+BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) {
+  errno = 0;
+  int sys_ret = open("/proc/cpuinfo", O_RDONLY);
+  BPF_ASSERT_EQ(-1, sys_ret);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, EPERM_access, BaselinePolicy) {
+  errno = 0;
+  int sys_ret = access("/proc/cpuinfo", R_OK);
+  BPF_ASSERT_EQ(-1, sys_ret);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) {
+  errno = 0;
+  char buf[1024];
+  char* cwd = getcwd(buf, sizeof(buf));
+  BPF_ASSERT_EQ(NULL, cwd);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SIGSYS_InvalidSyscall,
+                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  Syscall::InvalidCall();
+}
+
+// A failing test using this macro could be problematic since we perform
+// system calls by passing "0" as every argument.
+// The kernel could SIGSEGV the process or the system call itself could reboot
+// the machine. Some thoughts have been given when hand-picking the system
+// calls below to limit any potential side effects outside of the current
+// process.
+#define TEST_BASELINE_SIGSYS(sysno)                                      \
+  BPF_DEATH_TEST_C(BaselinePolicy,                                       \
+                   SIGSYS_##sysno,                                       \
+                   DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), \
+                   BaselinePolicy) {                                     \
+    syscall(sysno, 0, 0, 0, 0, 0, 0);                                    \
+    _exit(1);                                                            \
+  }
+
+TEST_BASELINE_SIGSYS(__NR_acct);
+TEST_BASELINE_SIGSYS(__NR_chroot);
+TEST_BASELINE_SIGSYS(__NR_fanotify_init);
+TEST_BASELINE_SIGSYS(__NR_fgetxattr);
+TEST_BASELINE_SIGSYS(__NR_getcpu);
+TEST_BASELINE_SIGSYS(__NR_getitimer);
+TEST_BASELINE_SIGSYS(__NR_init_module);
+TEST_BASELINE_SIGSYS(__NR_io_cancel);
+TEST_BASELINE_SIGSYS(__NR_keyctl);
+TEST_BASELINE_SIGSYS(__NR_mq_open);
+TEST_BASELINE_SIGSYS(__NR_ptrace);
+TEST_BASELINE_SIGSYS(__NR_sched_setaffinity);
+TEST_BASELINE_SIGSYS(__NR_setpgid);
+TEST_BASELINE_SIGSYS(__NR_swapon);
+TEST_BASELINE_SIGSYS(__NR_sysinfo);
+TEST_BASELINE_SIGSYS(__NR_syslog);
+TEST_BASELINE_SIGSYS(__NR_timer_create);
+
+#if !defined(__aarch64__)
+TEST_BASELINE_SIGSYS(__NR_eventfd);
+TEST_BASELINE_SIGSYS(__NR_inotify_init);
+TEST_BASELINE_SIGSYS(__NR_vserver);
+#endif
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 FutexWithRequeuePriorityInheritence,
+                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0);
+  _exit(1);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 FutexWithRequeuePriorityInheritencePrivate,
+                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0);
+  _exit(1);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 FutexWithUnlockPIPrivate,
+                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0);
+  _exit(1);
+}
+
+BPF_TEST_C(BaselinePolicy, PrctlDumpable, BaselinePolicy) {
+  const int is_dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+  BPF_ASSERT(is_dumpable == 1 || is_dumpable == 0);
+  const int prctl_ret = prctl(PR_SET_DUMPABLE, is_dumpable, 0, 0, 0, 0);
+  BPF_ASSERT_EQ(0, prctl_ret);
+}
+
+// Workaround incomplete Android headers.
+#if !defined(PR_CAPBSET_READ)
+#define PR_CAPBSET_READ 23
+#endif
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 PrctlSigsys,
+                 DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  prctl(PR_CAPBSET_READ, 0, 0, 0, 0);
+  _exit(1);
+}
+
+BPF_TEST_C(BaselinePolicy, GetOrSetPriority, BaselinePolicy) {
+  errno = 0;
+  const int original_prio = getpriority(PRIO_PROCESS, 0);
+  // Check errno instead of the return value since this system call can return
+  // -1 as a valid value.
+  BPF_ASSERT_EQ(0, errno);
+
+  errno = 0;
+  int rc = getpriority(PRIO_PROCESS, getpid());
+  BPF_ASSERT_EQ(0, errno);
+
+  rc = getpriority(PRIO_PROCESS, getpid() + 1);
+  BPF_ASSERT_EQ(-1, rc);
+  BPF_ASSERT_EQ(EPERM, errno);
+
+  rc = setpriority(PRIO_PROCESS, 0, original_prio);
+  BPF_ASSERT_EQ(0, rc);
+
+  rc = setpriority(PRIO_PROCESS, getpid(), original_prio);
+  BPF_ASSERT_EQ(0, rc);
+
+  errno = 0;
+  rc = setpriority(PRIO_PROCESS, getpid() + 1, original_prio);
+  BPF_ASSERT_EQ(-1, rc);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 GetPrioritySigsys,
+                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  getpriority(PRIO_USER, 0);
+  _exit(1);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 ClockGettimeWithDisallowedClockCrashes,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
new file mode 100644
index 0000000..05250d1
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Note: any code in this file MUST be async-signal safe.
+
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+#if defined(__mips__)
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+#endif
+
+#define SECCOMP_MESSAGE_COMMON_CONTENT "seccomp-bpf failure"
+#define SECCOMP_MESSAGE_CLONE_CONTENT "clone() failure"
+#define SECCOMP_MESSAGE_PRCTL_CONTENT "prctl() failure"
+#define SECCOMP_MESSAGE_IOCTL_CONTENT "ioctl() failure"
+#define SECCOMP_MESSAGE_KILL_CONTENT "(tg)kill() failure"
+#define SECCOMP_MESSAGE_FUTEX_CONTENT "futex() failure"
+
+namespace {
+
+inline bool IsArchitectureX86_64() {
+#if defined(__x86_64__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+// Write |error_message| to stderr. Similar to RawLog(), but a bit more careful
+// about async-signal safety. |size| is the size to write and should typically
+// not include a terminating \0.
+void WriteToStdErr(const char* error_message, size_t size) {
+  while (size > 0) {
+    // TODO(jln): query the current policy to check if send() is available and
+    // use it to perform a non-blocking write.
+    const int ret = HANDLE_EINTR(write(STDERR_FILENO, error_message, size));
+    // We can't handle any type of error here.
+    if (ret <= 0 || static_cast<size_t>(ret) > size) break;
+    size -= ret;
+    error_message += ret;
+  }
+}
+
+// Invalid syscall values are truncated to zero.
+// On architectures where base value is zero (Intel and Arm),
+// syscall number is the same as offset from base.
+// This function returns values between 0 and 1023 on all architectures.
+// On architectures where base value is different than zero (currently only
+// Mips), we are truncating valid syscall values to offset from base.
+uint32_t SyscallNumberToOffsetFromBase(uint32_t sysno) {
+#if defined(__mips__)
+  // On MIPS syscall numbers are in different range than on x86 and ARM.
+  // Valid MIPS O32 ABI syscall __NR_syscall will be truncated to zero for
+  // simplicity.
+  sysno = sysno - __NR_Linux;
+#endif
+
+  if (sysno >= 1024)
+    sysno = 0;
+
+  return sysno;
+}
+
+// Print a seccomp-bpf failure to handle |sysno| to stderr in an
+// async-signal safe way.
+void PrintSyscallError(uint32_t sysno) {
+  if (sysno >= 1024)
+    sysno = 0;
+  // TODO(markus): replace with async-signal safe snprintf when available.
+  const size_t kNumDigits = 4;
+  char sysno_base10[kNumDigits];
+  uint32_t rem = sysno;
+  uint32_t mod = 0;
+  for (int i = kNumDigits - 1; i >= 0; i--) {
+    mod = rem % 10;
+    rem /= 10;
+    sysno_base10[i] = '0' + mod;
+  }
+#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+  static const char kSeccompErrorPrefix[] = __FILE__
+      ":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall 4000 + ";
+#else
+  static const char kSeccompErrorPrefix[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall ";
+#endif
+  static const char kSeccompErrorPostfix[] = "\n";
+  WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1);
+  WriteToStdErr(sysno_base10, sizeof(sysno_base10));
+  WriteToStdErr(kSeccompErrorPostfix, sizeof(kSeccompErrorPostfix) - 1);
+}
+
+}  // namespace.
+
+namespace sandbox {
+
+intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) {
+  uint32_t syscall = SyscallNumberToOffsetFromBase(args.nr);
+
+  PrintSyscallError(syscall);
+
+  // Encode 8-bits of the 1st two arguments too, so we can discern which socket
+  // type, which fcntl, ... etc., without being likely to hit a mapped
+  // address.
+  // Do not encode more bits here without thinking about increasing the
+  // likelihood of collision with mapped pages.
+  syscall |= ((args.args[0] & 0xffUL) << 12);
+  syscall |= ((args.args[1] & 0xffUL) << 20);
+  // Purposefully dereference the syscall as an address so it'll show up very
+  // clearly and easily in crash dumps.
+  volatile char* addr = reinterpret_cast<volatile char*>(syscall);
+  *addr = '\0';
+  // In case we hit a mapped address, hit the null page with just the syscall,
+  // for paranoia.
+  syscall &= 0xfffUL;
+  addr = reinterpret_cast<volatile char*>(syscall);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+// TODO(jln): refactor the reporting functions.
+
+intptr_t SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux) {
+  static const char kSeccompCloneError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_CLONE_CONTENT "\n";
+  WriteToStdErr(kSeccompCloneError, sizeof(kSeccompCloneError) - 1);
+  // "flags" is the first argument in the kernel's clone().
+  // Mark as volatile to be able to find the value on the stack in a minidump.
+  volatile uint64_t clone_flags = args.args[0];
+  volatile char* addr;
+  if (IsArchitectureX86_64()) {
+    addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFFFFF);
+    *addr = '\0';
+  }
+  // Hit the NULL page if this fails to fault.
+  addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data& args,
+                            void* /* aux */) {
+  static const char kSeccompPrctlError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_PRCTL_CONTENT "\n";
+  WriteToStdErr(kSeccompPrctlError, sizeof(kSeccompPrctlError) - 1);
+  // Mark as volatile to be able to find the value on the stack in a minidump.
+  volatile uint64_t option = args.args[0];
+  volatile char* addr =
+      reinterpret_cast<volatile char*>(option & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data& args,
+                            void* /* aux */) {
+  static const char kSeccompIoctlError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_IOCTL_CONTENT "\n";
+  WriteToStdErr(kSeccompIoctlError, sizeof(kSeccompIoctlError) - 1);
+  // Make "request" volatile so that we can see it on the stack in a minidump.
+  volatile uint64_t request = args.args[1];
+  volatile char* addr = reinterpret_cast<volatile char*>(request & 0xFFFF);
+  *addr = '\0';
+  // Hit the NULL page if this fails.
+  addr = reinterpret_cast<volatile char*>(request & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSKillFailure(const struct arch_seccomp_data& args,
+                           void* /* aux */) {
+   static const char kSeccompKillError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n";
+  WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1);
+  // Make "pid" volatile so that we can see it on the stack in a minidump.
+  volatile uint64_t my_pid = sys_getpid();
+  volatile char* addr = reinterpret_cast<volatile char*>(my_pid & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args,
+                            void* /* aux */) {
+  static const char kSeccompFutexError[] =
+      __FILE__ ":**CRASHING**:" SECCOMP_MESSAGE_FUTEX_CONTENT "\n";
+  WriteToStdErr(kSeccompFutexError, sizeof(kSeccompFutexError) - 1);
+  volatile int futex_op = args.args[1];
+  volatile char* addr = reinterpret_cast<volatile char*>(futex_op & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSSchedHandler(const struct arch_seccomp_data& args,
+                            void* aux) {
+  switch (args.nr) {
+    case __NR_sched_getaffinity:
+    case __NR_sched_getattr:
+    case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_rr_get_interval:
+    case __NR_sched_setaffinity:
+    case __NR_sched_setattr:
+    case __NR_sched_setparam:
+    case __NR_sched_setscheduler:
+      const pid_t tid = sys_gettid();
+      // The first argument is the pid.  If is our thread id, then replace it
+      // with 0, which is equivalent and allowed by the policy.
+      if (args.args[0] == static_cast<uint64_t>(tid)) {
+        return Syscall::Call(args.nr,
+                             0,
+                             static_cast<intptr_t>(args.args[1]),
+                             static_cast<intptr_t>(args.args[2]),
+                             static_cast<intptr_t>(args.args[3]),
+                             static_cast<intptr_t>(args.args[4]),
+                             static_cast<intptr_t>(args.args[5]));
+      }
+      break;
+  }
+
+  CrashSIGSYS_Handler(args, aux);
+
+  // Should never be reached.
+  RAW_CHECK(false);
+  return -ENOSYS;
+}
+
+bpf_dsl::ResultExpr CrashSIGSYS() {
+  return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSClone() {
+  return bpf_dsl::Trap(SIGSYSCloneFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSPrctl() {
+  return bpf_dsl::Trap(SIGSYSPrctlFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSIoctl() {
+  return bpf_dsl::Trap(SIGSYSIoctlFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSKill() {
+  return bpf_dsl::Trap(SIGSYSKillFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSFutex() {
+  return bpf_dsl::Trap(SIGSYSFutexFailure, NULL);
+}
+
+bpf_dsl::ResultExpr RewriteSchedSIGSYS() {
+  return bpf_dsl::Trap(SIGSYSSchedHandler, NULL);
+}
+
+const char* GetErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_COMMON_CONTENT;
+}
+
+const char* GetCloneErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_CLONE_CONTENT;
+}
+
+const char* GetPrctlErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_PRCTL_CONTENT;
+}
+
+const char* GetIoctlErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_IOCTL_CONTENT;
+}
+
+const char* GetKillErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_KILL_CONTENT;
+}
+
+const char* GetFutexErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_FUTEX_CONTENT;
+}
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
new file mode 100644
index 0000000..c64e994
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SIGSYS_HANDLERS_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SIGSYS_HANDLERS_H_
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+// The handlers are suitable for use in Trap() error codes. They are
+// guaranteed to be async-signal safe.
+// See sandbox/linux/seccomp-bpf/trap.h to see how they work.
+
+namespace sandbox {
+
+struct arch_seccomp_data;
+
+// This handler will crash the currently running process. The crashing address
+// will be the number of the current system call, extracted from |args|.
+// This handler will also print to stderr the number of the crashing syscall.
+SANDBOX_EXPORT intptr_t
+    CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux);
+
+// The following three handlers are suitable to report failures with the
+// clone(), prctl() and ioctl() system calls respectively.
+
+// The crashing address will be (clone_flags & 0xFFFFFF), where clone_flags is
+// the clone(2) argument, extracted from |args|.
+SANDBOX_EXPORT intptr_t
+    SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (option & 0xFFF), where option is the prctl(2)
+// argument.
+SANDBOX_EXPORT intptr_t
+    SIGSYSPrctlFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be request & 0xFFFF, where request is the ioctl(2)
+// argument.
+SANDBOX_EXPORT intptr_t
+    SIGSYSIoctlFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (pid & 0xFFF), where pid is the first
+// argument (and can be a tid).
+SANDBOX_EXPORT intptr_t
+    SIGSYSKillFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (op & 0xFFF), where op is the second
+// argument.
+SANDBOX_EXPORT intptr_t
+    SIGSYSFutexFailure(const struct arch_seccomp_data& args, void* aux);
+// If the syscall is not being called on the current tid, crashes in the same
+// way as CrashSIGSYS_Handler.  Otherwise, returns the result of calling the
+// syscall with the pid argument set to 0 (which for these calls means the
+// current thread).  The following syscalls are supported:
+//
+// sched_getaffinity(), sched_getattr(), sched_getparam(), sched_getscheduler(),
+// sched_rr_get_interval(), sched_setaffinity(), sched_setattr(),
+// sched_setparam(), sched_setscheduler()
+SANDBOX_EXPORT intptr_t
+    SIGSYSSchedHandler(const struct arch_seccomp_data& args, void* aux);
+
+// Variants of the above functions for use with bpf_dsl.
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSClone();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
+SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteSchedSIGSYS();
+
+// Following four functions return substrings of error messages used
+// in the above four functions. They are useful in death tests.
+SANDBOX_EXPORT const char* GetErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetCloneErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetPrctlErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetIoctlErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetKillErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetFutexErrorMessageContentForTests();
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SIGSYS_HANDLERS_H_
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
new file mode 100644
index 0000000..60c16d3
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -0,0 +1,316 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <linux/net.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/system_headers/linux_futex.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+// PNaCl toolchain does not provide sys/ioctl.h header.
+#if !defined(OS_NACL_NONSFI)
+#include <sys/ioctl.h>
+#endif
+
+#if defined(OS_ANDROID)
+
+#if !defined(F_DUPFD_CLOEXEC)
+#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
+#endif
+
+// https://android.googlesource.com/platform/bionic/+/lollipop-release/libc/private/bionic_prctl.h
+#if !defined(PR_SET_VMA)
+#define PR_SET_VMA 0x53564d41
+#endif
+
+// https://android.googlesource.com/platform/system/core/+/lollipop-release/libcutils/sched_policy.c
+#if !defined(PR_SET_TIMERSLACK_PID)
+#define PR_SET_TIMERSLACK_PID 41
+#endif
+
+#endif  // defined(OS_ANDROID)
+
+#if defined(__arm__) && !defined(MAP_STACK)
+#define MAP_STACK 0x20000  // Daisy build environment has old headers.
+#endif
+
+#if defined(__mips__) && !defined(MAP_STACK)
+#define MAP_STACK 0x40000
+#endif
+namespace {
+
+inline bool IsArchitectureX86_64() {
+#if defined(__x86_64__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsArchitectureI386() {
+#if defined(__i386__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsAndroid() {
+#if defined(OS_ANDROID)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsArchitectureMips() {
+#if defined(__mips__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+}  // namespace.
+
+#define CASES SANDBOX_BPF_DSL_CASES
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Arg;
+using sandbox::bpf_dsl::BoolExpr;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::If;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+#if !defined(OS_NACL_NONSFI)
+// Allow Glibc's and Android pthread creation flags, crash on any other
+// thread creation attempts and EPERM attempts to use neither
+// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
+ResultExpr RestrictCloneToThreadsAndEPERMFork() {
+  const Arg<unsigned long> flags(0);
+
+  // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2.
+  const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
+                                     CLONE_SIGHAND | CLONE_THREAD |
+                                     CLONE_SYSVSEM;
+  const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED;
+
+  const uint64_t kGlibcPthreadFlags =
+      CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
+      CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+  const BoolExpr glibc_test = flags == kGlibcPthreadFlags;
+
+  const BoolExpr android_test = flags == kAndroidCloneMask ||
+                                flags == kObsoleteAndroidCloneMask ||
+                                flags == kGlibcPthreadFlags;
+
+  return If(IsAndroid() ? android_test : glibc_test, Allow())
+      .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
+      .Else(CrashSIGSYSClone());
+}
+
+ResultExpr RestrictPrctl() {
+  // Will need to add seccomp compositing in the future. PR_SET_PTRACER is
+  // used by breakpad but not needed anymore.
+  const Arg<int> option(0);
+  return Switch(option)
+      .CASES((PR_GET_NAME, PR_SET_NAME, PR_GET_DUMPABLE, PR_SET_DUMPABLE),
+             Allow())
+#if defined(OS_ANDROID)
+      .CASES((PR_SET_VMA, PR_SET_TIMERSLACK_PID), Allow())
+#endif
+      .Default(CrashSIGSYSPrctl());
+}
+
+ResultExpr RestrictIoctl() {
+  const Arg<int> request(1);
+  return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default(
+      CrashSIGSYSIoctl());
+}
+
+ResultExpr RestrictMmapFlags() {
+  // The flags you see are actually the allowed ones, and the variable is a
+  // "denied" mask because of the negation operator.
+  // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
+  // MAP_POPULATE.
+  // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
+  const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
+                                MAP_STACK | MAP_NORESERVE | MAP_FIXED |
+                                MAP_DENYWRITE;
+  const Arg<int> flags(3);
+  return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictMprotectFlags() {
+  // The flags you see are actually the allowed ones, and the variable is a
+  // "denied" mask because of the negation operator.
+  // Significantly, we don't permit weird undocumented flags such as
+  // PROT_GROWSDOWN.
+  const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC;
+  const Arg<int> prot(2);
+  return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictFcntlCommands() {
+  // We also restrict the flags in F_SETFL. We don't want to permit flags with
+  // a history of trouble such as O_DIRECT. The flags you see are actually the
+  // allowed ones, and the variable is a "denied" mask because of the negation
+  // operator.
+  // Glibc overrides the kernel's O_LARGEFILE value. Account for this.
+  uint64_t kOLargeFileFlag = O_LARGEFILE;
+  if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips())
+    kOLargeFileFlag = 0100000;
+
+  const Arg<int> cmd(1);
+  const Arg<long> long_arg(2);
+
+  const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
+                                kOLargeFileFlag | O_CLOEXEC | O_NOATIME;
+  return Switch(cmd)
+      .CASES((F_GETFL,
+              F_GETFD,
+              F_SETFD,
+              F_SETLK,
+              F_SETLKW,
+              F_GETLK,
+              F_DUPFD,
+              F_DUPFD_CLOEXEC),
+             Allow())
+      .Case(F_SETFL,
+            If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()))
+      .Default(CrashSIGSYS());
+}
+
+#if defined(__i386__) || defined(__mips__)
+ResultExpr RestrictSocketcallCommand() {
+  // Unfortunately, we are unable to restrict the first parameter to
+  // socketpair(2). Whilst initially sounding bad, it's noteworthy that very
+  // few protocols actually support socketpair(2). The scary call that we're
+  // worried about, socket(2), remains blocked.
+  const Arg<int> call(0);
+  return Switch(call)
+      .CASES((SYS_SOCKETPAIR,
+              SYS_SHUTDOWN,
+              SYS_RECV,
+              SYS_SEND,
+              SYS_RECVFROM,
+              SYS_SENDTO,
+              SYS_RECVMSG,
+              SYS_SENDMSG),
+             Allow())
+      .Default(Error(EPERM));
+}
+#endif
+
+ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) {
+  switch (sysno) {
+    case __NR_kill:
+    case __NR_tgkill: {
+      const Arg<pid_t> pid(0);
+      return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill());
+    }
+    case __NR_tkill:
+      return CrashSIGSYSKill();
+    default:
+      NOTREACHED();
+      return CrashSIGSYS();
+  }
+}
+
+ResultExpr RestrictFutex() {
+  const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME;
+  const Arg<int> op(1);
+  return Switch(op & ~kAllowedFutexFlags)
+      .CASES((FUTEX_WAIT,
+              FUTEX_WAKE,
+              FUTEX_REQUEUE,
+              FUTEX_CMP_REQUEUE,
+              FUTEX_WAKE_OP,
+              FUTEX_WAIT_BITSET,
+              FUTEX_WAKE_BITSET),
+             Allow())
+      .Default(CrashSIGSYSFutex());
+}
+
+ResultExpr RestrictGetSetpriority(pid_t target_pid) {
+  const Arg<int> which(0);
+  const Arg<int> who(1);
+  return If(which == PRIO_PROCESS,
+            If(who == 0 || who == target_pid, Allow()).Else(Error(EPERM)))
+      .Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
+  switch (sysno) {
+    case __NR_sched_getaffinity:
+    case __NR_sched_getattr:
+    case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_rr_get_interval:
+    case __NR_sched_setaffinity:
+    case __NR_sched_setattr:
+    case __NR_sched_setparam:
+    case __NR_sched_setscheduler: {
+      const Arg<pid_t> pid(0);
+      return If(pid == 0 || pid == target_pid, Allow())
+          .Else(RewriteSchedSIGSYS());
+    }
+    default:
+      NOTREACHED();
+      return CrashSIGSYS();
+  }
+}
+
+ResultExpr RestrictPrlimit64(pid_t target_pid) {
+  const Arg<pid_t> pid(0);
+  return If(pid == 0 || pid == target_pid, Allow()).Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictGetrusage() {
+  const Arg<int> who(0);
+  return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS());
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+ResultExpr RestrictClockID() {
+  static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
+  const Arg<clockid_t> clockid(0);
+  return If(
+#if defined(OS_CHROMEOS)
+             // Allow the special clock for Chrome OS used by Chrome tracing.
+             clockid == base::TimeTicks::kClockSystemTrace ||
+#endif
+                 clockid == CLOCK_MONOTONIC ||
+                 clockid == CLOCK_PROCESS_CPUTIME_ID ||
+                 clockid == CLOCK_REALTIME ||
+                 clockid == CLOCK_THREAD_CPUTIME_ID,
+             Allow()).Else(CrashSIGSYS());
+}
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
new file mode 100644
index 0000000..0ec396d
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
+
+#include <unistd.h>
+
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+// These are helpers to build seccomp-bpf policies, i.e. policies for a
+// sandbox that reduces the Linux kernel's attack surface. They return a
+// bpf_dsl::ResultExpr suitable to restrict certain system call parameters.
+
+namespace sandbox {
+
+// Allow clone(2) for threads.
+// Reject fork(2) attempts with EPERM.
+// Don't restrict on ASAN.
+// Crash if anything else is attempted.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictCloneToThreadsAndEPERMFork();
+
+// Allow PR_SET_NAME, PR_SET_DUMPABLE, PR_GET_DUMPABLE.
+// Crash if anything else is attempted.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrctl();
+
+// Allow TCGETS and FIONREAD.
+// Crash if anything else is attempted.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictIoctl();
+
+// Restrict the flags argument in mmap(2).
+// Only allow: MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
+// MAP_STACK | MAP_NORESERVE | MAP_FIXED | MAP_DENYWRITE.
+// Crash if any other flag is used.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMmapFlags();
+
+// Restrict the prot argument in mprotect(2).
+// Only allow: PROT_READ | PROT_WRITE | PROT_EXEC.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMprotectFlags();
+
+// Restrict fcntl(2) cmd argument to:
+// We allow F_GETFL, F_SETFL, F_GETFD, F_SETFD, F_DUPFD, F_DUPFD_CLOEXEC,
+// F_SETLK, F_SETLKW and F_GETLK.
+// Also, in F_SETFL, restrict the allowed flags to: O_ACCMODE | O_APPEND |
+// O_NONBLOCK | O_SYNC | O_LARGEFILE | O_CLOEXEC | O_NOATIME.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictFcntlCommands();
+
+#if defined(__i386__) || defined(__mips__)
+// Restrict socketcall(2) to only allow socketpair(2), send(2), recv(2),
+// sendto(2), recvfrom(2), shutdown(2), sendmsg(2) and recvmsg(2).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSocketcallCommand();
+#endif
+
+// Restrict |sysno| (which must be kill, tkill or tgkill) by allowing tgkill or
+// kill iff the first parameter is |target_pid|, crashing otherwise or if
+// |sysno| is tkill.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictKillTarget(pid_t target_pid,
+                                                      int sysno);
+
+// Crash if FUTEX_CMP_REQUEUE_PI is used in the second argument of futex(2).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictFutex();
+
+// Crash if |which| is not PRIO_PROCESS. EPERM if |who| is not 0, neither
+// |target_pid| while calling setpriority(2) / getpriority(2).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid);
+
+// Restricts |pid| for sched_* syscalls which take a pid as the first argument.
+// We only allow calling these syscalls if the pid argument is equal to the pid
+// of the sandboxed process or 0 (indicating the current thread).  The following
+// syscalls are supported:
+//
+// sched_getaffinity(), sched_getattr(), sched_getparam(), sched_getscheduler(),
+// sched_rr_get_interval(), sched_setaffinity(), sched_setattr(),
+// sched_setparam(), sched_setscheduler()
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSchedTarget(pid_t target_pid,
+                                                       int sysno);
+
+// Restricts the |pid| argument of prlimit64 to 0 (meaning the calling process)
+// or target_pid.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimit64(pid_t target_pid);
+
+// Restricts the |who| argument of getrusage to RUSAGE_SELF (meaning the calling
+// process).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetrusage();
+
+// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime().
+// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID.  In particular, this disallows
+// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
+// returned by {clock,pthread}_getcpuclockid), which can leak information
+// about the state of the host OS.
+// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
new file mode 100644
index 0000000..e653b8a
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -0,0 +1,273 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/sys_info.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+#if !defined(OS_ANDROID)
+#include "third_party/lss/linux_syscall_support.h"  // for MAKE_PROCESS_CPUCLOCK
+#endif
+
+namespace sandbox {
+
+namespace {
+
+// NOTE: most of the parameter restrictions are tested in
+// baseline_policy_unittest.cc as a more end-to-end test.
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::ResultExpr;
+
+class RestrictClockIdPolicy : public bpf_dsl::Policy {
+ public:
+  RestrictClockIdPolicy() {}
+  ~RestrictClockIdPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_clock_gettime:
+      case __NR_clock_getres:
+        return RestrictClockID();
+      default:
+        return Allow();
+    }
+  }
+};
+
+void CheckClock(clockid_t clockid) {
+  struct timespec ts;
+  ts.tv_sec = ts.tv_nsec = -1;
+  BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
+  BPF_ASSERT_LE(0, ts.tv_sec);
+  BPF_ASSERT_LE(0, ts.tv_nsec);
+}
+
+BPF_TEST_C(ParameterRestrictions,
+           clock_gettime_allowed,
+           RestrictClockIdPolicy) {
+  CheckClock(CLOCK_MONOTONIC);
+  CheckClock(CLOCK_PROCESS_CPUTIME_ID);
+  CheckClock(CLOCK_REALTIME);
+  CheckClock(CLOCK_THREAD_CPUTIME_ID);
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 clock_gettime_crash_monotonic_raw,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictClockIdPolicy) {
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+}
+
+#if defined(OS_CHROMEOS)
+
+// A custom BPF tester delegate to run IsRunningOnChromeOS() before
+// the sandbox is enabled because we cannot run it with non-SFI BPF
+// sandbox enabled.
+class ClockSystemTesterDelegate : public sandbox::BPFTesterDelegate {
+ public:
+  ClockSystemTesterDelegate()
+      : is_running_on_chromeos_(base::SysInfo::IsRunningOnChromeOS()) {}
+  ~ClockSystemTesterDelegate() override {}
+
+  scoped_ptr<sandbox::bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    return scoped_ptr<sandbox::bpf_dsl::Policy>(new RestrictClockIdPolicy());
+  }
+  void RunTestFunction() override {
+    if (is_running_on_chromeos_) {
+      CheckClock(base::TimeTicks::kClockSystemTrace);
+    } else {
+      struct timespec ts;
+      // kClockSystemTrace is 11, which is CLOCK_THREAD_CPUTIME_ID of
+      // the init process (pid=1). If kernel supports this feature,
+      // this may succeed even if this is not running on Chrome OS. We
+      // just check this clock_gettime call does not crash.
+      clock_gettime(base::TimeTicks::kClockSystemTrace, &ts);
+    }
+  }
+
+ private:
+  const bool is_running_on_chromeos_;
+  DISALLOW_COPY_AND_ASSIGN(ClockSystemTesterDelegate);
+};
+
+BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, ClockSystemTesterDelegate);
+
+#elif defined(OS_LINUX)
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 clock_gettime_crash_system_trace,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictClockIdPolicy) {
+  struct timespec ts;
+  clock_gettime(base::TimeTicks::kClockSystemTrace, &ts);
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+#if !defined(OS_ANDROID)
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 clock_gettime_crash_cpu_clock,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictClockIdPolicy) {
+  // We can't use clock_getcpuclockid() because it's not implemented in newlib,
+  // and it might not work inside the sandbox anyway.
+  const pid_t kInitPID = 1;
+  const clockid_t kInitCPUClockID =
+      MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED);
+
+  struct timespec ts;
+  clock_gettime(kInitCPUClockID, &ts);
+}
+#endif  // !defined(OS_ANDROID)
+
+class RestrictSchedPolicy : public bpf_dsl::Policy {
+ public:
+  RestrictSchedPolicy() {}
+  ~RestrictSchedPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_sched_getparam:
+        return RestrictSchedTarget(getpid(), sysno);
+      default:
+        return Allow();
+    }
+  }
+};
+
+void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
+  BPF_ASSERT_EQ(0, sched_getparam(pid, param));
+}
+
+void SchedGetParamThread(base::WaitableEvent* thread_run) {
+  const pid_t pid = getpid();
+  const pid_t tid = sys_gettid();
+  BPF_ASSERT_NE(pid, tid);
+
+  struct sched_param current_pid_param;
+  CheckSchedGetParam(pid, &current_pid_param);
+
+  struct sched_param zero_param;
+  CheckSchedGetParam(0, &zero_param);
+
+  struct sched_param tid_param;
+  CheckSchedGetParam(tid, &tid_param);
+
+  BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority);
+
+  // Verify that the SIGSYS handler sets errno properly.
+  errno = 0;
+  BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL));
+  BPF_ASSERT_EQ(EINVAL, errno);
+
+  thread_run->Signal();
+}
+
+BPF_TEST_C(ParameterRestrictions,
+           sched_getparam_allowed,
+           RestrictSchedPolicy) {
+  base::WaitableEvent thread_run(true, false);
+  // Run the actual test in a new thread so that the current pid and tid are
+  // different.
+  base::Thread getparam_thread("sched_getparam_thread");
+  BPF_ASSERT(getparam_thread.Start());
+  getparam_thread.message_loop()->PostTask(
+      FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run));
+  BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000)));
+  getparam_thread.Stop();
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 sched_getparam_crash_non_zero,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictSchedPolicy) {
+  const pid_t kInitPID = 1;
+  struct sched_param param;
+  sched_getparam(kInitPID, &param);
+}
+
+class RestrictPrlimit64Policy : public bpf_dsl::Policy {
+ public:
+  RestrictPrlimit64Policy() {}
+  ~RestrictPrlimit64Policy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_prlimit64:
+        return RestrictPrlimit64(getpid());
+      default:
+        return Allow();
+    }
+  }
+};
+
+BPF_TEST_C(ParameterRestrictions, prlimit64_allowed, RestrictPrlimit64Policy) {
+  BPF_ASSERT_EQ(0, sys_prlimit64(0, RLIMIT_AS, NULL, NULL));
+  BPF_ASSERT_EQ(0, sys_prlimit64(getpid(), RLIMIT_AS, NULL, NULL));
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 prlimit64_crash_not_self,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictPrlimit64Policy) {
+  const pid_t kInitPID = 1;
+  BPF_ASSERT_NE(kInitPID, getpid());
+  sys_prlimit64(kInitPID, RLIMIT_AS, NULL, NULL);
+}
+
+class RestrictGetrusagePolicy : public bpf_dsl::Policy {
+ public:
+  RestrictGetrusagePolicy() {}
+  ~RestrictGetrusagePolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_getrusage:
+        return RestrictGetrusage();
+      default:
+        return Allow();
+    }
+  }
+};
+
+BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {
+  struct rusage usage;
+  BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage));
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 getrusage_crash_not_self,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictGetrusagePolicy) {
+  struct rusage usage;
+  getrusage(RUSAGE_CHILDREN, &usage);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
new file mode 100644
index 0000000..c217d47
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -0,0 +1,1060 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
+
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+// The functions below cover all existing i386, x86_64, and ARM system calls;
+// excluding syscalls made obsolete in ARM EABI.
+// The implicitly defined sets form a partition of the sets of
+// system calls.
+
+bool SyscallSets::IsKill(int sysno) {
+  switch (sysno) {
+    case __NR_kill:
+    case __NR_tgkill:
+    case __NR_tkill:  // Deprecated.
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedGettime(int sysno) {
+  switch (sysno) {
+    case __NR_gettimeofday:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_time:
+#endif
+      return true;
+    case __NR_adjtimex:         // Privileged.
+    case __NR_clock_adjtime:    // Privileged.
+    case __NR_clock_getres:     // Could be allowed.
+    case __NR_clock_gettime:
+    case __NR_clock_nanosleep:  // Could be allowed.
+    case __NR_clock_settime:    // Privileged.
+#if defined(__i386__) || defined(__mips__)
+    case __NR_ftime:  // Obsolete.
+#endif
+    case __NR_settimeofday:  // Privileged.
+#if defined(__i386__) || defined(__mips__)
+    case __NR_stime:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsCurrentDirectory(int sysno) {
+  switch (sysno) {
+    case __NR_getcwd:
+    case __NR_chdir:
+    case __NR_fchdir:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsUmask(int sysno) {
+  switch (sysno) {
+    case __NR_umask:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// System calls that directly access the file system. They might acquire
+// a new file descriptor or otherwise perform an operation directly
+// via a path.
+// Both EPERM and ENOENT are valid errno unless otherwise noted in comment.
+bool SyscallSets::IsFileSystem(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_access:  // EPERM not a valid errno.
+    case __NR_chmod:
+    case __NR_chown:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_chown32:
+#endif
+    case __NR_creat:
+    case __NR_futimesat:  // Should be called utimesat ?
+    case __NR_lchown:
+    case __NR_link:
+    case __NR_lstat:  // EPERM not a valid errno.
+    case __NR_mkdir:
+    case __NR_mknod:
+    case __NR_open:
+    case __NR_readlink:  // EPERM not a valid errno.
+    case __NR_rename:
+    case __NR_rmdir:
+    case __NR_stat:  // EPERM not a valid errno.
+    case __NR_symlink:
+    case __NR_unlink:
+    case __NR_uselib:  // Neither EPERM, nor ENOENT are valid errno.
+    case __NR_ustat:   // Same as above. Deprecated.
+    case __NR_utimes:
+#endif  // !defined(__aarch64__)
+
+    case __NR_execve:
+    case __NR_faccessat:  // EPERM not a valid errno.
+    case __NR_fchmodat:
+    case __NR_fchownat:  // Should be called chownat ?
+#if defined(__x86_64__) || defined(__aarch64__)
+    case __NR_newfstatat:  // fstatat(). EPERM not a valid errno.
+#elif defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fstatat64:
+#endif
+#if defined(__i386__) || defined(__arm__)
+    case __NR_lchown32:
+#endif
+    case __NR_linkat:
+    case __NR_lookup_dcookie:  // ENOENT not a valid errno.
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_lstat64:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+    case __NR_memfd_create:
+#endif
+    case __NR_mkdirat:
+    case __NR_mknodat:
+#if defined(__i386__)
+    case __NR_oldlstat:
+    case __NR_oldstat:
+#endif
+    case __NR_openat:
+    case __NR_readlinkat:
+    case __NR_renameat:
+    case __NR_renameat2:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_stat64:
+#endif
+    case __NR_statfs:  // EPERM not a valid errno.
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_statfs64:
+#endif
+    case __NR_symlinkat:
+    case __NR_truncate:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_truncate64:
+#endif
+    case __NR_unlinkat:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_utime:
+#endif
+    case __NR_utimensat:  // New.
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedFileSystemAccessViaFd(int sysno) {
+  switch (sysno) {
+    case __NR_fstat:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fstat64:
+#endif
+      return true;
+// TODO(jln): these should be denied gracefully as well (moved below).
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_fadvise64:  // EPERM not a valid errno.
+#endif
+#if defined(__i386__)
+    case __NR_fadvise64_64:
+#endif
+#if defined(__arm__)
+    case __NR_arm_fadvise64_64:
+#endif
+    case __NR_fdatasync:  // EPERM not a valid errno.
+    case __NR_flock:      // EPERM not a valid errno.
+    case __NR_fstatfs:    // Give information about the whole filesystem.
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fstatfs64:
+#endif
+    case __NR_fsync:  // EPERM not a valid errno.
+#if defined(__i386__)
+    case __NR_oldfstat:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_sync_file_range:  // EPERM not a valid errno.
+#elif defined(__arm__)
+    case __NR_arm_sync_file_range:  // EPERM not a valid errno.
+#endif
+    default:
+      return false;
+  }
+}
+
+// EPERM is a good errno for any of these.
+bool SyscallSets::IsDeniedFileSystemAccessViaFd(int sysno) {
+  switch (sysno) {
+    case __NR_fallocate:
+    case __NR_fchmod:
+    case __NR_fchown:
+    case __NR_ftruncate:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_fchown32:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_ftruncate64:
+#endif
+#if !defined(__aarch64__)
+    case __NR_getdents:    // EPERM not a valid errno.
+#endif
+    case __NR_getdents64:  // EPERM not a valid errno.
+#if defined(__i386__) || defined(__mips__)
+    case __NR_readdir:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGetSimpleId(int sysno) {
+  switch (sysno) {
+    case __NR_capget:
+    case __NR_getegid:
+    case __NR_geteuid:
+    case __NR_getgid:
+    case __NR_getgroups:
+    case __NR_getpid:
+    case __NR_getppid:
+    case __NR_getresgid:
+    case __NR_getsid:
+    case __NR_gettid:
+    case __NR_getuid:
+    case __NR_getresuid:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_getegid32:
+    case __NR_geteuid32:
+    case __NR_getgid32:
+    case __NR_getgroups32:
+    case __NR_getresgid32:
+    case __NR_getresuid32:
+    case __NR_getuid32:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsProcessPrivilegeChange(int sysno) {
+  switch (sysno) {
+    case __NR_capset:
+#if defined(__i386__) || defined(__x86_64__)
+    case __NR_ioperm:  // Intel privilege.
+    case __NR_iopl:    // Intel privilege.
+#endif
+    case __NR_setfsgid:
+    case __NR_setfsuid:
+    case __NR_setgid:
+    case __NR_setgroups:
+    case __NR_setregid:
+    case __NR_setresgid:
+    case __NR_setresuid:
+    case __NR_setreuid:
+    case __NR_setuid:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_setfsgid32:
+    case __NR_setfsuid32:
+    case __NR_setgid32:
+    case __NR_setgroups32:
+    case __NR_setregid32:
+    case __NR_setresgid32:
+    case __NR_setresuid32:
+    case __NR_setreuid32:
+    case __NR_setuid32:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsProcessGroupOrSession(int sysno) {
+  switch (sysno) {
+    case __NR_setpgid:
+#if !defined(__aarch64__)
+    case __NR_getpgrp:
+#endif
+    case __NR_setsid:
+    case __NR_getpgid:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedSignalHandling(int sysno) {
+  switch (sysno) {
+    case __NR_rt_sigaction:
+    case __NR_rt_sigprocmask:
+    case __NR_rt_sigreturn:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_sigaction:
+    case __NR_sigprocmask:
+    case __NR_sigreturn:
+#endif
+      return true;
+    case __NR_rt_sigpending:
+    case __NR_rt_sigqueueinfo:
+    case __NR_rt_sigsuspend:
+    case __NR_rt_sigtimedwait:
+    case __NR_rt_tgsigqueueinfo:
+    case __NR_sigaltstack:
+#if !defined(__aarch64__)
+    case __NR_signalfd:
+#endif
+    case __NR_signalfd4:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_sigpending:
+    case __NR_sigsuspend:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_signal:
+    case __NR_sgetmask:  // Obsolete.
+    case __NR_ssetmask:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedOperationOnFd(int sysno) {
+  switch (sysno) {
+    case __NR_close:
+    case __NR_dup:
+#if !defined(__aarch64__)
+    case __NR_dup2:
+#endif
+    case __NR_dup3:
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_shutdown:
+#endif
+      return true;
+    case __NR_fcntl:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fcntl64:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsKernelInternalApi(int sysno) {
+  switch (sysno) {
+    case __NR_restart_syscall:
+#if defined(__arm__)
+    case __ARM_NR_cmpxchg:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+// This should be thought through in conjunction with IsFutex().
+bool SyscallSets::IsAllowedProcessStartOrDeath(int sysno) {
+  switch (sysno) {
+    case __NR_exit:
+    case __NR_exit_group:
+    case __NR_wait4:
+    case __NR_waitid:
+#if defined(__i386__)
+    case __NR_waitpid:
+#endif
+      return true;
+    case __NR_clone:  // Should be parameter-restricted.
+    case __NR_setns:  // Privileged.
+#if !defined(__aarch64__)
+    case __NR_fork:
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+    case __NR_get_thread_area:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_set_thread_area:
+#endif
+    case __NR_set_tid_address:
+    case __NR_unshare:
+#if !defined(__mips__) && !defined(__aarch64__)
+    case __NR_vfork:
+#endif
+    default:
+      return false;
+  }
+}
+
+// It's difficult to restrict those, but there is attack surface here.
+bool SyscallSets::IsAllowedFutex(int sysno) {
+  switch (sysno) {
+    case __NR_get_robust_list:
+    case __NR_set_robust_list:
+    case __NR_futex:
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedEpoll(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_epoll_create:
+    case __NR_epoll_wait:
+#endif
+    case __NR_epoll_create1:
+    case __NR_epoll_ctl:
+      return true;
+    default:
+#if defined(__x86_64__)
+    case __NR_epoll_ctl_old:
+#endif
+    case __NR_epoll_pwait:
+#if defined(__x86_64__)
+    case __NR_epoll_wait_old:
+#endif
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedGetOrModifySocket(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_pipe:
+#endif
+    case __NR_pipe2:
+      return true;
+    default:
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_socketpair:  // We will want to inspect its argument.
+#endif
+      return false;
+  }
+}
+
+bool SyscallSets::IsDeniedGetOrModifySocket(int sysno) {
+  switch (sysno) {
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_accept:
+    case __NR_accept4:
+    case __NR_bind:
+    case __NR_connect:
+    case __NR_socket:
+    case __NR_listen:
+      return true;
+#endif
+    default:
+      return false;
+  }
+}
+
+#if defined(__i386__) || defined(__mips__)
+// Big multiplexing system call for sockets.
+bool SyscallSets::IsSocketCall(int sysno) {
+  switch (sysno) {
+    case __NR_socketcall:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
+bool SyscallSets::IsNetworkSocketInformation(int sysno) {
+  switch (sysno) {
+    case __NR_getpeername:
+    case __NR_getsockname:
+    case __NR_getsockopt:
+    case __NR_setsockopt:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+bool SyscallSets::IsAllowedAddressSpaceAccess(int sysno) {
+  switch (sysno) {
+    case __NR_brk:
+    case __NR_mlock:
+    case __NR_munlock:
+    case __NR_munmap:
+      return true;
+    case __NR_madvise:
+    case __NR_mincore:
+    case __NR_mlockall:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_mmap:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_mmap2:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_modify_ldt:
+#endif
+    case __NR_mprotect:
+    case __NR_mremap:
+    case __NR_msync:
+    case __NR_munlockall:
+    case __NR_readahead:
+    case __NR_remap_file_pages:
+#if defined(__i386__)
+    case __NR_vm86:
+    case __NR_vm86old:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedGeneralIo(int sysno) {
+  switch (sysno) {
+    case __NR_lseek:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR__llseek:
+#endif
+#if !defined(__aarch64__)
+    case __NR_poll:
+#endif
+    case __NR_ppoll:
+    case __NR_pselect6:
+    case __NR_read:
+    case __NR_readv:
+#if defined(__arm__) || defined(__mips__)
+    case __NR_recv:
+#endif
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_recvfrom:  // Could specify source.
+    case __NR_recvmsg:   // Could specify source.
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+    case __NR_select:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR__newselect:
+#endif
+#if defined(__arm__)
+    case __NR_send:
+#endif
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_sendmsg:  // Could specify destination.
+    case __NR_sendto:   // Could specify destination.
+#endif
+    case __NR_write:
+    case __NR_writev:
+      return true;
+    case __NR_ioctl:  // Can be very powerful.
+    case __NR_pread64:
+    case __NR_preadv:
+    case __NR_pwrite64:
+    case __NR_pwritev:
+    case __NR_recvmmsg:  // Could specify source.
+    case __NR_sendfile:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_sendfile64:
+#endif
+    case __NR_sendmmsg:  // Could specify destination.
+    case __NR_splice:
+    case __NR_tee:
+    case __NR_vmsplice:
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsPrctl(int sysno) {
+  switch (sysno) {
+#if defined(__x86_64__)
+    case __NR_arch_prctl:
+#endif
+    case __NR_prctl:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsSeccomp(int sysno) {
+  switch (sysno) {
+    case __NR_seccomp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedBasicScheduler(int sysno) {
+  switch (sysno) {
+    case __NR_sched_yield:
+#if !defined(__aarch64__)
+    case __NR_pause:
+#endif
+    case __NR_nanosleep:
+      return true;
+    case __NR_getpriority:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_nice:
+#endif
+    case __NR_setpriority:
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAdminOperation(int sysno) {
+  switch (sysno) {
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_bdflush:
+#endif
+    case __NR_kexec_load:
+    case __NR_reboot:
+    case __NR_setdomainname:
+    case __NR_sethostname:
+    case __NR_syslog:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsKernelModule(int sysno) {
+  switch (sysno) {
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_create_module:
+    case __NR_get_kernel_syms:  // Should ENOSYS.
+    case __NR_query_module:
+#endif
+    case __NR_delete_module:
+    case __NR_init_module:
+    case __NR_finit_module:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGlobalFSViewChange(int sysno) {
+  switch (sysno) {
+    case __NR_pivot_root:
+    case __NR_chroot:
+    case __NR_sync:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsFsControl(int sysno) {
+  switch (sysno) {
+    case __NR_mount:
+    case __NR_nfsservctl:
+    case __NR_quotactl:
+    case __NR_swapoff:
+    case __NR_swapon:
+#if defined(__i386__) || defined(__mips__)
+    case __NR_umount:
+#endif
+    case __NR_umount2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsNuma(int sysno) {
+  switch (sysno) {
+    case __NR_get_mempolicy:
+    case __NR_getcpu:
+    case __NR_mbind:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_migrate_pages:
+#endif
+    case __NR_move_pages:
+    case __NR_set_mempolicy:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsMessageQueue(int sysno) {
+  switch (sysno) {
+    case __NR_mq_getsetattr:
+    case __NR_mq_notify:
+    case __NR_mq_open:
+    case __NR_mq_timedreceive:
+    case __NR_mq_timedsend:
+    case __NR_mq_unlink:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGlobalProcessEnvironment(int sysno) {
+  switch (sysno) {
+    case __NR_acct:  // Privileged.
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_getrlimit:
+#endif
+#if defined(__i386__) || defined(__arm__)
+    case __NR_ugetrlimit:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_ulimit:
+#endif
+    case __NR_getrusage:
+    case __NR_personality:  // Can change its personality as well.
+    case __NR_prlimit64:    // Like setrlimit / getrlimit.
+    case __NR_setrlimit:
+    case __NR_times:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsDebug(int sysno) {
+  switch (sysno) {
+    case __NR_ptrace:
+    case __NR_process_vm_readv:
+    case __NR_process_vm_writev:
+    case __NR_kcmp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGlobalSystemStatus(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR__sysctl:
+    case __NR_sysfs:
+#endif
+    case __NR_sysinfo:
+    case __NR_uname:
+#if defined(__i386__)
+    case __NR_olduname:
+    case __NR_oldolduname:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsEventFd(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_eventfd:
+#endif
+    case __NR_eventfd2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Asynchronous I/O API.
+bool SyscallSets::IsAsyncIo(int sysno) {
+  switch (sysno) {
+    case __NR_io_cancel:
+    case __NR_io_destroy:
+    case __NR_io_getevents:
+    case __NR_io_setup:
+    case __NR_io_submit:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsKeyManagement(int sysno) {
+  switch (sysno) {
+    case __NR_add_key:
+    case __NR_keyctl:
+    case __NR_request_key:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+bool SyscallSets::IsSystemVSemaphores(int sysno) {
+  switch (sysno) {
+    case __NR_semctl:
+    case __NR_semget:
+    case __NR_semop:
+    case __NR_semtimedop:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+// These give a lot of ambient authority and bypass the setuid sandbox.
+bool SyscallSets::IsSystemVSharedMemory(int sysno) {
+  switch (sysno) {
+    case __NR_shmat:
+    case __NR_shmctl:
+    case __NR_shmdt:
+    case __NR_shmget:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+bool SyscallSets::IsSystemVMessageQueue(int sysno) {
+  switch (sysno) {
+    case __NR_msgctl:
+    case __NR_msgget:
+    case __NR_msgrcv:
+    case __NR_msgsnd:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__i386__) || defined(__mips__)
+// Big system V multiplexing system call.
+bool SyscallSets::IsSystemVIpc(int sysno) {
+  switch (sysno) {
+    case __NR_ipc:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+bool SyscallSets::IsAnySystemV(int sysno) {
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  return IsSystemVMessageQueue(sysno) || IsSystemVSemaphores(sysno) ||
+         IsSystemVSharedMemory(sysno);
+#elif defined(__i386__) || defined(__mips__)
+  return IsSystemVIpc(sysno);
+#endif
+}
+
+bool SyscallSets::IsAdvancedScheduler(int sysno) {
+  switch (sysno) {
+    case __NR_ioprio_get:  // IO scheduler.
+    case __NR_ioprio_set:
+    case __NR_sched_get_priority_max:
+    case __NR_sched_get_priority_min:
+    case __NR_sched_getaffinity:
+    case __NR_sched_getattr:
+    case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_rr_get_interval:
+    case __NR_sched_setaffinity:
+    case __NR_sched_setattr:
+    case __NR_sched_setparam:
+    case __NR_sched_setscheduler:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsInotify(int sysno) {
+  switch (sysno) {
+    case __NR_inotify_add_watch:
+#if !defined(__aarch64__)
+    case __NR_inotify_init:
+#endif
+    case __NR_inotify_init1:
+    case __NR_inotify_rm_watch:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsFaNotify(int sysno) {
+  switch (sysno) {
+    case __NR_fanotify_init:
+    case __NR_fanotify_mark:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsTimer(int sysno) {
+  switch (sysno) {
+    case __NR_getitimer:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_alarm:
+#endif
+    case __NR_setitimer:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAdvancedTimer(int sysno) {
+  switch (sysno) {
+    case __NR_timer_create:
+    case __NR_timer_delete:
+    case __NR_timer_getoverrun:
+    case __NR_timer_gettime:
+    case __NR_timer_settime:
+    case __NR_timerfd_create:
+    case __NR_timerfd_gettime:
+    case __NR_timerfd_settime:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsExtendedAttributes(int sysno) {
+  switch (sysno) {
+    case __NR_fgetxattr:
+    case __NR_flistxattr:
+    case __NR_fremovexattr:
+    case __NR_fsetxattr:
+    case __NR_getxattr:
+    case __NR_lgetxattr:
+    case __NR_listxattr:
+    case __NR_llistxattr:
+    case __NR_lremovexattr:
+    case __NR_lsetxattr:
+    case __NR_removexattr:
+    case __NR_setxattr:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Various system calls that need to be researched.
+// TODO(jln): classify this better.
+bool SyscallSets::IsMisc(int sysno) {
+  switch (sysno) {
+#if !defined(__mips__)
+    case __NR_getrandom:
+#endif
+    case __NR_name_to_handle_at:
+    case __NR_open_by_handle_at:
+    case __NR_perf_event_open:
+    case __NR_syncfs:
+    case __NR_vhangup:
+// The system calls below are not implemented.
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_afs_syscall:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_break:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_getpmsg:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_gtty:
+    case __NR_idle:
+    case __NR_lock:
+    case __NR_mpx:
+    case __NR_prof:
+    case __NR_profil:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_putpmsg:
+#endif
+#if defined(__x86_64__)
+    case __NR_security:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_stty:
+#endif
+#if defined(__x86_64__)
+    case __NR_tuxcall:
+#endif
+#if !defined(__aarch64__)
+    case __NR_vserver:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if defined(__arm__)
+bool SyscallSets::IsArmPciConfig(int sysno) {
+  switch (sysno) {
+    case __NR_pciconfig_iobase:
+    case __NR_pciconfig_read:
+    case __NR_pciconfig_write:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsArmPrivate(int sysno) {
+  switch (sysno) {
+    case __ARM_NR_breakpoint:
+    case __ARM_NR_cacheflush:
+    case __ARM_NR_set_tls:
+    case __ARM_NR_usr26:
+    case __ARM_NR_usr32:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // defined(__arm__)
+
+#if defined(__mips__)
+bool SyscallSets::IsMipsPrivate(int sysno) {
+  switch (sysno) {
+    case __NR_cacheflush:
+    case __NR_cachectl:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsMipsMisc(int sysno) {
+  switch (sysno) {
+    case __NR_sysmips:
+    case __NR_unused150:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // defined(__mips__)
+}  // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
new file mode 100644
index 0000000..5ba6335
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_SETS_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_SETS_H_
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/sandbox_export.h"
+
+// These are helpers to build seccomp-bpf policies, i.e. policies for a
+// sandbox that reduces the Linux kernel's attack surface. Given their
+// nature, they don't have any clear semantics and are completely
+// "implementation-defined".
+
+namespace sandbox {
+
+class SANDBOX_EXPORT SyscallSets {
+ public:
+  static bool IsKill(int sysno);
+  static bool IsAllowedGettime(int sysno);
+  static bool IsCurrentDirectory(int sysno);
+  static bool IsUmask(int sysno);
+  // System calls that directly access the file system. They might acquire
+  // a new file descriptor or otherwise perform an operation directly
+  // via a path.
+  static bool IsFileSystem(int sysno);
+  static bool IsAllowedFileSystemAccessViaFd(int sysno);
+  static bool IsDeniedFileSystemAccessViaFd(int sysno);
+  static bool IsGetSimpleId(int sysno);
+  static bool IsProcessPrivilegeChange(int sysno);
+  static bool IsProcessGroupOrSession(int sysno);
+  static bool IsAllowedSignalHandling(int sysno);
+  static bool IsAllowedOperationOnFd(int sysno);
+  static bool IsKernelInternalApi(int sysno);
+  // This should be thought through in conjunction with IsFutex().
+  static bool IsAllowedProcessStartOrDeath(int sysno);
+  // It's difficult to restrict those, but there is attack surface here.
+  static bool IsAllowedFutex(int sysno);
+  static bool IsAllowedEpoll(int sysno);
+  static bool IsAllowedGetOrModifySocket(int sysno);
+  static bool IsDeniedGetOrModifySocket(int sysno);
+
+#if defined(__i386__) || defined(__mips__)
+  // Big multiplexing system call for sockets.
+  static bool IsSocketCall(int sysno);
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+  static bool IsNetworkSocketInformation(int sysno);
+#endif
+
+  static bool IsAllowedAddressSpaceAccess(int sysno);
+  static bool IsAllowedGeneralIo(int sysno);
+  static bool IsPrctl(int sysno);
+  static bool IsSeccomp(int sysno);
+  static bool IsAllowedBasicScheduler(int sysno);
+  static bool IsAdminOperation(int sysno);
+  static bool IsKernelModule(int sysno);
+  static bool IsGlobalFSViewChange(int sysno);
+  static bool IsFsControl(int sysno);
+  static bool IsNuma(int sysno);
+  static bool IsMessageQueue(int sysno);
+  static bool IsGlobalProcessEnvironment(int sysno);
+  static bool IsDebug(int sysno);
+  static bool IsGlobalSystemStatus(int sysno);
+  static bool IsEventFd(int sysno);
+  // Asynchronous I/O API.
+  static bool IsAsyncIo(int sysno);
+  static bool IsKeyManagement(int sysno);
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  static bool IsSystemVSemaphores(int sysno);
+#endif
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  // These give a lot of ambient authority and bypass the setuid sandbox.
+  static bool IsSystemVSharedMemory(int sysno);
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  static bool IsSystemVMessageQueue(int sysno);
+#endif
+
+#if defined(__i386__) || defined(__mips__)
+  // Big system V multiplexing system call.
+  static bool IsSystemVIpc(int sysno);
+#endif
+
+  static bool IsAnySystemV(int sysno);
+  static bool IsAdvancedScheduler(int sysno);
+  static bool IsInotify(int sysno);
+  static bool IsFaNotify(int sysno);
+  static bool IsTimer(int sysno);
+  static bool IsAdvancedTimer(int sysno);
+  static bool IsExtendedAttributes(int sysno);
+  static bool IsMisc(int sysno);
+#if defined(__arm__)
+  static bool IsArmPciConfig(int sysno);
+  static bool IsArmPrivate(int sysno);
+#endif  // defined(__arm__)
+#if defined(__mips__)
+  static bool IsMipsPrivate(int sysno);
+  static bool IsMipsMisc(int sysno);
+#endif  // defined(__mips__)
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SyscallSets);
+};
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_SETS_H_
diff --git a/sandbox/linux/seccomp-bpf/DEPS b/sandbox/linux/seccomp-bpf/DEPS
new file mode 100644
index 0000000..149c463
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+sandbox/linux/bpf_dsl",
+  "+sandbox/linux/services",
+  "+sandbox/linux/system_headers",
+]
diff --git a/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h b/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
new file mode 100644
index 0000000..7736c15
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
@@ -0,0 +1,54 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
+
+namespace sandbox {
+
+// This templated class allows building a BPFTesterDelegate from a
+// deprecated-style BPF policy (that is a SyscallEvaluator function pointer,
+// instead of a SandboxBPFPolicy class), specified in |policy_function| and a
+// function pointer to a test in |test_function|.
+// This allows both the policy and the test function to take a pointer to an
+// object of type "Aux" as a parameter. This is used to implement the BPF_TEST
+// macro and should generally not be used directly.
+template <class Policy, class Aux>
+class BPFTesterCompatibilityDelegate : public BPFTesterDelegate {
+ public:
+  typedef void (*TestFunction)(Aux*);
+
+  explicit BPFTesterCompatibilityDelegate(TestFunction test_function)
+      : aux_(), test_function_(test_function) {}
+
+  ~BPFTesterCompatibilityDelegate() override {}
+
+  scoped_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    // The current method is guaranteed to only run in the child process
+    // running the test. In this process, the current object is guaranteed
+    // to live forever. So it's ok to pass aux_pointer_for_policy_ to
+    // the policy, which could in turn pass it to the kernel via Trap().
+    return scoped_ptr<bpf_dsl::Policy>(new Policy(&aux_));
+  }
+
+  void RunTestFunction() override {
+    // Run the actual test.
+    // The current object is guaranteed to live forever in the child process
+    // where this will run.
+    test_function_(&aux_);
+  }
+
+ private:
+  Aux aux_;
+  TestFunction test_function_;
+
+  DISALLOW_COPY_AND_ASSIGN(BPFTesterCompatibilityDelegate);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
diff --git a/sandbox/linux/seccomp-bpf/bpf_tests.h b/sandbox/linux/seccomp-bpf/bpf_tests.h
new file mode 100644
index 0000000..cc4debd
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/bpf_tests.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+// BPF_TEST_C() is a special version of SANDBOX_TEST(). It runs a test function
+// in a sub-process, under a seccomp-bpf policy specified in
+// |bpf_policy_class_name| without failing on configurations that are allowed
+// to not support seccomp-bpf in their kernels.
+// This is the preferred format for new BPF tests. |bpf_policy_class_name| is a
+// class name  (which will be default-constructed) that implements the
+// Policy interface.
+// The test function's body can simply follow. Test functions should use
+// the BPF_ASSERT macros defined below, not GTEST's macros. The use of
+// CHECK* macros is supported but less robust.
+#define BPF_TEST_C(test_case_name, test_name, bpf_policy_class_name)     \
+  BPF_DEATH_TEST_C(                                                      \
+      test_case_name, test_name, DEATH_SUCCESS(), bpf_policy_class_name)
+
+// Identical to BPF_TEST_C but allows to specify the nature of death.
+#define BPF_DEATH_TEST_C(                                            \
+    test_case_name, test_name, death, bpf_policy_class_name)         \
+  void BPF_TEST_C_##test_name();                                     \
+  TEST(test_case_name, DISABLE_ON_TSAN(test_name)) {                 \
+    sandbox::SandboxBPFTestRunner bpf_test_runner(                   \
+        new sandbox::BPFTesterSimpleDelegate<bpf_policy_class_name>( \
+            BPF_TEST_C_##test_name));                                \
+    sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death);   \
+  }                                                                  \
+  void BPF_TEST_C_##test_name()
+
+// This form of BPF_TEST is a little verbose and should be reserved for complex
+// tests where a lot of control is required.
+// |bpf_tester_delegate_class| must be a classname implementing the
+// BPFTesterDelegate interface.
+#define BPF_TEST_D(test_case_name, test_name, bpf_tester_delegate_class)     \
+  BPF_DEATH_TEST_D(                                                          \
+      test_case_name, test_name, DEATH_SUCCESS(), bpf_tester_delegate_class)
+
+// Identical to BPF_TEST_D but allows to specify the nature of death.
+#define BPF_DEATH_TEST_D(                                          \
+    test_case_name, test_name, death, bpf_tester_delegate_class)   \
+  TEST(test_case_name, DISABLE_ON_TSAN(test_name)) {               \
+    sandbox::SandboxBPFTestRunner bpf_test_runner(                 \
+        new bpf_tester_delegate_class());                          \
+    sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
+  }
+
+// Assertions are handled exactly the same as with a normal SANDBOX_TEST()
+#define BPF_ASSERT SANDBOX_ASSERT
+#define BPF_ASSERT_EQ(x, y) BPF_ASSERT((x) == (y))
+#define BPF_ASSERT_NE(x, y) BPF_ASSERT((x) != (y))
+#define BPF_ASSERT_LT(x, y) BPF_ASSERT((x) < (y))
+#define BPF_ASSERT_GT(x, y) BPF_ASSERT((x) > (y))
+#define BPF_ASSERT_LE(x, y) BPF_ASSERT((x) <= (y))
+#define BPF_ASSERT_GE(x, y) BPF_ASSERT((x) >= (y))
+
+// This form of BPF_TEST is now discouraged (but still allowed) in favor of
+// BPF_TEST_D and BPF_TEST_C.
+// The |policy| parameter should be a Policy subclass.
+// BPF_TEST() takes a C++ data type as an fourth parameter. A variable
+// of this type will be allocated and a pointer to it will be
+// available within the test function as "BPF_AUX". The pointer will
+// also be passed as an argument to the policy's constructor. Policies
+// would typically use it as an argument to SandboxBPF::Trap(), if
+// they want to communicate data between the BPF_TEST() and a Trap()
+// function. The life-time of this object is the same as the life-time
+// of the process running under the seccomp-bpf policy.
+// |aux| must not be void.
+#define BPF_TEST(test_case_name, test_name, policy, aux) \
+  BPF_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS(), policy, aux)
+
+// A BPF_DEATH_TEST is just the same as a BPF_TEST, but it assumes that the
+// test will fail with a particular known error condition. Use the DEATH_XXX()
+// macros from unit_tests.h to specify the expected error condition.
+#define BPF_DEATH_TEST(test_case_name, test_name, death, policy, aux) \
+  void BPF_TEST_##test_name(aux* BPF_AUX);                            \
+  TEST(test_case_name, DISABLE_ON_TSAN(test_name)) {                  \
+    sandbox::SandboxBPFTestRunner bpf_test_runner(                    \
+        new sandbox::BPFTesterCompatibilityDelegate<policy, aux>(     \
+            BPF_TEST_##test_name));                                   \
+    sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death);    \
+  }                                                                   \
+  void BPF_TEST_##test_name(aux* BPF_AUX)
+
+// This class takes a simple function pointer as a constructor parameter and a
+// class name as a template parameter to implement the BPFTesterDelegate
+// interface which can be used to build BPF unittests with
+// the SandboxBPFTestRunner class.
+template <class PolicyClass>
+class BPFTesterSimpleDelegate : public BPFTesterDelegate {
+ public:
+  explicit BPFTesterSimpleDelegate(void (*test_function)(void))
+      : test_function_(test_function) {}
+  ~BPFTesterSimpleDelegate() override {}
+
+  scoped_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    return scoped_ptr<bpf_dsl::Policy>(new PolicyClass());
+  }
+  void RunTestFunction() override {
+    DCHECK(test_function_);
+    test_function_();
+  }
+
+ private:
+  void (*test_function_)(void);
+  DISALLOW_COPY_AND_ASSIGN(BPFTesterSimpleDelegate);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
diff --git a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
new file mode 100644
index 0000000..63e1814
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
@@ -0,0 +1,153 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+namespace {
+
+class FourtyTwo {
+ public:
+  static const int kMagicValue = 42;
+  FourtyTwo() : value_(kMagicValue) {}
+  int value() { return value_; }
+
+ private:
+  int value_;
+  DISALLOW_COPY_AND_ASSIGN(FourtyTwo);
+};
+
+class EmptyClassTakingPolicy : public bpf_dsl::Policy {
+ public:
+  explicit EmptyClassTakingPolicy(FourtyTwo* fourty_two) {
+    BPF_ASSERT(fourty_two);
+    BPF_ASSERT(FourtyTwo::kMagicValue == fourty_two->value());
+  }
+  ~EmptyClassTakingPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    return Allow();
+  }
+};
+
+BPF_TEST(BPFTest,
+         BPFAUXPointsToClass,
+         EmptyClassTakingPolicy,
+         FourtyTwo /* *BPF_AUX */) {
+  // BPF_AUX should point to an instance of FourtyTwo.
+  BPF_ASSERT(BPF_AUX);
+  BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value());
+}
+
+void DummyTestFunction(FourtyTwo *fourty_two) {
+}
+
+TEST(BPFTest, BPFTesterCompatibilityDelegateLeakTest) {
+  // Don't do anything, simply gives dynamic tools an opportunity to detect
+  // leaks.
+  {
+    BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>
+        simple_delegate(DummyTestFunction);
+  }
+  {
+    // Test polymorphism.
+    scoped_ptr<BPFTesterDelegate> simple_delegate(
+        new BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>(
+            DummyTestFunction));
+  }
+}
+
+class EnosysPtracePolicy : public bpf_dsl::Policy {
+ public:
+  EnosysPtracePolicy() { my_pid_ = sys_getpid(); }
+  ~EnosysPtracePolicy() override {
+    // Policies should be able to bind with the process on which they are
+    // created. They should never be created in a parent process.
+    BPF_ASSERT_EQ(my_pid_, sys_getpid());
+  }
+
+  ResultExpr EvaluateSyscall(int system_call_number) const override {
+    CHECK(SandboxBPF::IsValidSyscallNumber(system_call_number));
+    if (system_call_number == __NR_ptrace) {
+      // The EvaluateSyscall function should run in the process that created
+      // the current object.
+      BPF_ASSERT_EQ(my_pid_, sys_getpid());
+      return Error(ENOSYS);
+    } else {
+      return Allow();
+    }
+  }
+
+ private:
+  pid_t my_pid_;
+  DISALLOW_COPY_AND_ASSIGN(EnosysPtracePolicy);
+};
+
+class BasicBPFTesterDelegate : public BPFTesterDelegate {
+ public:
+  BasicBPFTesterDelegate() {}
+  ~BasicBPFTesterDelegate() override {}
+
+  scoped_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    return scoped_ptr<bpf_dsl::Policy>(new EnosysPtracePolicy());
+  }
+  void RunTestFunction() override {
+    errno = 0;
+    int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
+    BPF_ASSERT(-1 == ret);
+    BPF_ASSERT(ENOSYS == errno);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicBPFTesterDelegate);
+};
+
+// This is the most powerful and complex way to create a BPF test, but it
+// requires a full class definition (BasicBPFTesterDelegate).
+BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, BasicBPFTesterDelegate);
+
+// This is the simplest form of BPF tests.
+BPF_TEST_C(BPFTest, BPFTestWithInlineTest, EnosysPtracePolicy) {
+  errno = 0;
+  int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
+  BPF_ASSERT(-1 == ret);
+  BPF_ASSERT(ENOSYS == errno);
+}
+
+const char kHelloMessage[] = "Hello";
+
+BPF_DEATH_TEST_C(BPFTest,
+                 BPFDeathTestWithInlineTest,
+                 DEATH_MESSAGE(kHelloMessage),
+                 EnosysPtracePolicy) {
+  LOG(ERROR) << kHelloMessage;
+  _exit(1);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/die.cc b/sandbox/linux/seccomp-bpf/die.cc
new file mode 100644
index 0000000..3baf1f1
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/die.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/die.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace sandbox {
+
+void Die::ExitGroup() {
+  // exit_group() should exit our program. After all, it is defined as a
+  // function that doesn't return. But things can theoretically go wrong.
+  // Especially, since we are dealing with system call filters. Continuing
+  // execution would be very bad in most cases where ExitGroup() gets called.
+  // So, we'll try a few other strategies too.
+  Syscall::Call(__NR_exit_group, 1);
+
+  // We have no idea what our run-time environment looks like. So, signal
+  // handlers might or might not do the right thing. Try to reset settings
+  // to a defined state; but we have not way to verify whether we actually
+  // succeeded in doing so. Nonetheless, triggering a fatal signal could help
+  // us terminate.
+  struct sigaction sa = {};
+  sa.sa_handler = LINUX_SIG_DFL;
+  sa.sa_flags = LINUX_SA_RESTART;
+  sys_sigaction(LINUX_SIGSEGV, &sa, nullptr);
+  Syscall::Call(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
+  if (*(volatile char*)0) {
+  }
+
+  // If there is no way for us to ask for the program to exit, the next
+  // best thing we can do is to loop indefinitely. Maybe, somebody will notice
+  // and file a bug...
+  // We in fact retry the system call inside of our loop so that it will
+  // stand out when somebody tries to diagnose the problem by using "strace".
+  for (;;) {
+    Syscall::Call(__NR_exit_group, 1);
+  }
+}
+
+void Die::SandboxDie(const char* msg, const char* file, int line) {
+  if (simple_exit_) {
+    LogToStderr(msg, file, line);
+  } else {
+    logging::LogMessage(file, line, logging::LOG_FATAL).stream() << msg;
+  }
+  ExitGroup();
+}
+
+void Die::RawSandboxDie(const char* msg) {
+  if (!msg)
+    msg = "";
+  RAW_LOG(FATAL, msg);
+  ExitGroup();
+}
+
+void Die::SandboxInfo(const char* msg, const char* file, int line) {
+  if (!suppress_info_) {
+    logging::LogMessage(file, line, logging::LOG_INFO).stream() << msg;
+  }
+}
+
+void Die::LogToStderr(const char* msg, const char* file, int line) {
+  if (msg) {
+    char buf[40];
+    snprintf(buf, sizeof(buf), "%d", line);
+    std::string s = std::string(file) + ":" + buf + ":" + msg + "\n";
+
+    // No need to loop. Short write()s are unlikely and if they happen we
+    // probably prefer them over a loop that blocks.
+    ignore_result(
+        HANDLE_EINTR(Syscall::Call(__NR_write, 2, s.c_str(), s.length())));
+  }
+}
+
+bool Die::simple_exit_ = false;
+bool Die::suppress_info_ = false;
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/die.h b/sandbox/linux/seccomp-bpf/die.h
new file mode 100644
index 0000000..b3f3f72
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/die.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This is the main API for using this file. Prints a error message and
+// exits with a fatal error. This is not async-signal safe.
+#define SANDBOX_DIE(m) sandbox::Die::SandboxDie(m, __FILE__, __LINE__)
+
+// An async signal safe version of the same API. Won't print the filename
+// and line numbers.
+#define RAW_SANDBOX_DIE(m) sandbox::Die::RawSandboxDie(m)
+
+// Adds an informational message to the log file or stderr as appropriate.
+#define SANDBOX_INFO(m) sandbox::Die::SandboxInfo(m, __FILE__, __LINE__)
+
+class SANDBOX_EXPORT Die {
+ public:
+  // Terminate the program, even if the current sandbox policy prevents some
+  // of the more commonly used functions used for exiting.
+  // Most users would want to call SANDBOX_DIE() instead, as it logs extra
+  // information. But calling ExitGroup() is correct and in some rare cases
+  // preferable. So, we make it part of the public API.
+  static void ExitGroup() __attribute__((noreturn));
+
+  // This method gets called by SANDBOX_DIE(). There is normally no reason
+  // to call it directly unless you are defining your own exiting macro.
+  static void SandboxDie(const char* msg, const char* file, int line)
+      __attribute__((noreturn));
+
+  static void RawSandboxDie(const char* msg) __attribute__((noreturn));
+
+  // This method gets called by SANDBOX_INFO(). There is normally no reason
+  // to call it directly unless you are defining your own logging macro.
+  static void SandboxInfo(const char* msg, const char* file, int line);
+
+  // Writes a message to stderr. Used as a fall-back choice, if we don't have
+  // any other way to report an error.
+  static void LogToStderr(const char* msg, const char* file, int line);
+
+  // We generally want to run all exit handlers. This means, on SANDBOX_DIE()
+  // we should be calling LOG(FATAL). But there are some situations where
+  // we just need to print a message and then terminate. This would typically
+  // happen in cases where we consume the error message internally (e.g. in
+  // unit tests or in the supportsSeccompSandbox() method).
+  static void EnableSimpleExit() { simple_exit_ = true; }
+
+  // Sometimes we need to disable all informational messages (e.g. from within
+  // unittests).
+  static void SuppressInfoMessages(bool flag) { suppress_info_ = flag; }
+
+ private:
+  static bool simple_exit_;
+  static bool suppress_info_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Die);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
diff --git a/sandbox/linux/seccomp-bpf/errorcode.cc b/sandbox/linux/seccomp-bpf/errorcode.cc
new file mode 100644
index 0000000..9bb3ddb
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/errorcode.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+
+ErrorCode::ErrorCode() : error_type_(ET_INVALID), err_(SECCOMP_RET_INVALID) {
+}
+
+ErrorCode::ErrorCode(int err) {
+  switch (err) {
+    case ERR_ALLOWED:
+      err_ = SECCOMP_RET_ALLOW;
+      error_type_ = ET_SIMPLE;
+      break;
+    case ERR_MIN_ERRNO... ERR_MAX_ERRNO:
+      err_ = SECCOMP_RET_ERRNO + err;
+      error_type_ = ET_SIMPLE;
+      break;
+    default:
+      if ((err & ~SECCOMP_RET_DATA) == ERR_TRACE) {
+        err_ = SECCOMP_RET_TRACE + (err & SECCOMP_RET_DATA);
+        error_type_ = ET_SIMPLE;
+        break;
+      }
+      SANDBOX_DIE("Invalid use of ErrorCode object");
+  }
+}
+
+ErrorCode::ErrorCode(uint16_t trap_id,
+                     Trap::TrapFnc fnc,
+                     const void* aux,
+                     bool safe)
+    : error_type_(ET_TRAP),
+      fnc_(fnc),
+      aux_(const_cast<void*>(aux)),
+      safe_(safe),
+      err_(SECCOMP_RET_TRAP + trap_id) {
+}
+
+ErrorCode::ErrorCode(int argno,
+                     ArgType width,
+                     uint64_t mask,
+                     uint64_t value,
+                     const ErrorCode* passed,
+                     const ErrorCode* failed)
+    : error_type_(ET_COND),
+      mask_(mask),
+      value_(value),
+      argno_(argno),
+      width_(width),
+      passed_(passed),
+      failed_(failed),
+      err_(SECCOMP_RET_INVALID) {
+}
+
+bool ErrorCode::Equals(const ErrorCode& err) const {
+  if (error_type_ == ET_INVALID || err.error_type_ == ET_INVALID) {
+    SANDBOX_DIE("Dereferencing invalid ErrorCode");
+  }
+  if (error_type_ != err.error_type_) {
+    return false;
+  }
+  if (error_type_ == ET_SIMPLE || error_type_ == ET_TRAP) {
+    return err_ == err.err_;
+  } else if (error_type_ == ET_COND) {
+    return mask_ == err.mask_ && value_ == err.value_ && argno_ == err.argno_ &&
+           width_ == err.width_ && passed_->Equals(*err.passed_) &&
+           failed_->Equals(*err.failed_);
+  } else {
+    SANDBOX_DIE("Corrupted ErrorCode");
+  }
+}
+
+bool ErrorCode::LessThan(const ErrorCode& err) const {
+  // Implementing a "LessThan()" operator allows us to use ErrorCode objects
+  // as keys in STL containers; most notably, it also allows us to put them
+  // into std::set<>. Actual ordering is not important as long as it is
+  // deterministic.
+  if (error_type_ == ET_INVALID || err.error_type_ == ET_INVALID) {
+    SANDBOX_DIE("Dereferencing invalid ErrorCode");
+  }
+  if (error_type_ != err.error_type_) {
+    return error_type_ < err.error_type_;
+  } else {
+    if (error_type_ == ET_SIMPLE || error_type_ == ET_TRAP) {
+      return err_ < err.err_;
+    } else if (error_type_ == ET_COND) {
+      if (mask_ != err.mask_) {
+        return mask_ < err.mask_;
+      } else if (value_ != err.value_) {
+        return value_ < err.value_;
+      } else if (argno_ != err.argno_) {
+        return argno_ < err.argno_;
+      } else if (width_ != err.width_) {
+        return width_ < err.width_;
+      } else if (!passed_->Equals(*err.passed_)) {
+        return passed_->LessThan(*err.passed_);
+      } else if (!failed_->Equals(*err.failed_)) {
+        return failed_->LessThan(*err.failed_);
+      } else {
+        return false;
+      }
+    } else {
+      SANDBOX_DIE("Corrupted ErrorCode");
+    }
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/errorcode.h b/sandbox/linux/seccomp-bpf/errorcode.h
new file mode 100644
index 0000000..d887773
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/errorcode.h
@@ -0,0 +1,203 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__
+
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class PolicyCompiler;
+}
+
+// This class holds all the possible values that can be returned by a sandbox
+// policy.
+// We can either wrap a symbolic ErrorCode (i.e. ERR_XXX enum values), an
+// errno value (in the range 0..4095), a pointer to a TrapFnc callback
+// handling a SECCOMP_RET_TRAP trap, or a complex constraint.
+// All of the commonly used values are stored in the "err_" field. So, code
+// that is using the ErrorCode class typically operates on a single 32bit
+// field.
+//
+// TODO(mdempsky): Nuke from orbit. The only reason this class still
+// exists is for Verifier, which will eventually be replaced by a true
+// BPF symbolic evaluator and constraint solver.
+class SANDBOX_EXPORT ErrorCode {
+ public:
+  enum {
+    // Allow this system call. The value of ERR_ALLOWED is pretty much
+    // completely arbitrary. But we want to pick it so that is is unlikely
+    // to be passed in accidentally, when the user intended to return an
+    // "errno" (see below) value instead.
+    ERR_ALLOWED = 0x04000000,
+
+    // If the progress is being ptraced with PTRACE_O_TRACESECCOMP, then the
+    // tracer will be notified of a PTRACE_EVENT_SECCOMP and allowed to change
+    // or skip the system call.  The lower 16 bits of err will be available to
+    // the tracer via PTRACE_GETEVENTMSG.
+    ERR_TRACE   = 0x08000000,
+
+    // Deny the system call with a particular "errno" value.
+    // N.B.: It is also possible to return "0" here. That would normally
+    //       indicate success, but it won't actually run the system call.
+    //       This is very different from return ERR_ALLOWED.
+    ERR_MIN_ERRNO = 0,
+#if defined(__mips__)
+    // MIPS only supports errno up to 1133
+    ERR_MAX_ERRNO = 1133,
+#else
+    // TODO(markus): Android only supports errno up to 255
+    // (crbug.com/181647).
+    ERR_MAX_ERRNO = 4095,
+#endif
+  };
+
+  // While BPF filter programs always operate on 32bit quantities, the kernel
+  // always sees system call arguments as 64bit values. This statement is true
+  // no matter whether the host system is natively operating in 32bit or 64bit.
+  // The BPF compiler hides the fact that BPF instructions cannot directly
+  // access 64bit quantities. But policies are still advised to specify whether
+  // a system call expects a 32bit or a 64bit quantity.
+  enum ArgType {
+    // When passed as an argument to SandboxBPF::Cond(), TP_32BIT requests that
+    // the conditional test should operate on the 32bit part of the system call
+    // argument.
+    // On 64bit architectures, this verifies that user space did not pass
+    // a 64bit value as an argument to the system call. If it did, that will be
+    // interpreted as an attempt at breaking the sandbox and results in the
+    // program getting terminated.
+    // In other words, only perform a 32bit test, if you are sure this
+    // particular system call would never legitimately take a 64bit
+    // argument.
+    // Implementation detail: TP_32BIT does two things. 1) it restricts the
+    // conditional test to operating on the LSB only, and 2) it adds code to
+    // the BPF filter program verifying that the MSB  the kernel received from
+    // user space is either 0, or 0xFFFFFFFF; the latter is acceptable, iff bit
+    // 31 was set in the system call argument. It deals with 32bit arguments
+    // having been sign extended.
+    TP_32BIT,
+
+    // When passed as an argument to SandboxBPF::Cond(), TP_64BIT requests that
+    // the conditional test should operate on the full 64bit argument. It is
+    // generally harmless to perform a 64bit test on 32bit systems, as the
+    // kernel will always see the top 32 bits of all arguments as zero'd out.
+    // This approach has the desirable property that for tests of pointer
+    // values, we can always use TP_64BIT no matter the host architecture.
+    // But of course, that also means, it is possible to write conditional
+    // policies that turn into no-ops on 32bit systems; this is by design.
+    TP_64BIT,
+  };
+
+  // Deprecated.
+  enum Operation {
+    // Test whether the system call argument is equal to the operand.
+    OP_EQUAL,
+
+    // Tests a system call argument against a bit mask.
+    // The "ALL_BITS" variant performs this test: "arg & mask == mask"
+    // This implies that a mask of zero always results in a passing test.
+    // The "ANY_BITS" variant performs this test: "arg & mask != 0"
+    // This implies that a mask of zero always results in a failing test.
+    OP_HAS_ALL_BITS,
+    OP_HAS_ANY_BITS,
+  };
+
+  enum ErrorType {
+    ET_INVALID,
+    ET_SIMPLE,
+    ET_TRAP,
+    ET_COND,
+  };
+
+  // We allow the default constructor, as it makes the ErrorCode class
+  // much easier to use. But if we ever encounter an invalid ErrorCode
+  // when compiling a BPF filter, we deliberately generate an invalid
+  // program that will get flagged both by our Verifier class and by
+  // the Linux kernel.
+  ErrorCode();
+  explicit ErrorCode(int err);
+
+  // For all practical purposes, ErrorCodes are treated as if they were
+  // structs. The copy constructor and assignment operator are trivial and
+  // we do not need to explicitly specify them.
+  // Most notably, it is in fact perfectly OK to directly copy the passed_ and
+  // failed_ field. They only ever get set by our private constructor, and the
+  // callers handle life-cycle management for these objects.
+
+  // Destructor
+  ~ErrorCode() {}
+
+  bool Equals(const ErrorCode& err) const;
+  bool LessThan(const ErrorCode& err) const;
+
+  uint32_t err() const { return err_; }
+  ErrorType error_type() const { return error_type_; }
+
+  bool safe() const { return safe_; }
+
+  uint64_t mask() const { return mask_; }
+  uint64_t value() const { return value_; }
+  int argno() const { return argno_; }
+  ArgType width() const { return width_; }
+  const ErrorCode* passed() const { return passed_; }
+  const ErrorCode* failed() const { return failed_; }
+
+  struct LessThan {
+    bool operator()(const ErrorCode& a, const ErrorCode& b) const {
+      return a.LessThan(b);
+    }
+  };
+
+ private:
+  friend bpf_dsl::PolicyCompiler;
+  friend class CodeGen;
+  friend class SandboxBPF;
+  friend class Trap;
+
+  // If we are wrapping a callback, we must assign a unique id. This id is
+  // how the kernel tells us which one of our different SECCOMP_RET_TRAP
+  // cases has been triggered.
+  ErrorCode(uint16_t trap_id, Trap::TrapFnc fnc, const void* aux, bool safe);
+
+  // Some system calls require inspection of arguments. This constructor
+  // allows us to specify additional constraints.
+  ErrorCode(int argno,
+            ArgType width,
+            uint64_t mask,
+            uint64_t value,
+            const ErrorCode* passed,
+            const ErrorCode* failed);
+
+  ErrorType error_type_;
+
+  union {
+    // Fields needed for SECCOMP_RET_TRAP callbacks
+    struct {
+      Trap::TrapFnc fnc_;  // Callback function and arg, if trap was
+      void* aux_;          //   triggered by the kernel's BPF filter.
+      bool safe_;          // Keep sandbox active while calling fnc_()
+    };
+
+    // Fields needed when inspecting additional arguments.
+    struct {
+      uint64_t mask_;            // Mask that we are comparing under.
+      uint64_t value_;           // Value that we are comparing with.
+      int argno_;                // Syscall arg number that we are inspecting.
+      ArgType width_;            // Whether we are looking at a 32/64bit value.
+      const ErrorCode* passed_;  // Value to be returned if comparison passed,
+      const ErrorCode* failed_;  //   or if it failed.
+    };
+  };
+
+  // 32bit field used for all possible types of ErrorCode values. This is
+  // the value that uniquely identifies any ErrorCode and it (typically) can
+  // be emitted directly into a BPF filter program.
+  uint32_t err_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__
diff --git a/sandbox/linux/seccomp-bpf/errorcode_unittest.cc b/sandbox/linux/seccomp-bpf/errorcode_unittest.cc
new file mode 100644
index 0000000..6b5491e
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/errorcode_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/errorcode.h"
+
+#include <errno.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+namespace {
+
+class DummyPolicy : public bpf_dsl::Policy {
+ public:
+  DummyPolicy() {}
+  ~DummyPolicy() override {}
+
+  bpf_dsl::ResultExpr EvaluateSyscall(int sysno) const override {
+    return bpf_dsl::Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DummyPolicy);
+};
+
+SANDBOX_TEST(ErrorCode, ErrnoConstructor) {
+  ErrorCode e0;
+  SANDBOX_ASSERT(e0.err() == SECCOMP_RET_INVALID);
+
+  ErrorCode e1(ErrorCode::ERR_ALLOWED);
+  SANDBOX_ASSERT(e1.err() == SECCOMP_RET_ALLOW);
+
+  ErrorCode e2(EPERM);
+  SANDBOX_ASSERT(e2.err() == SECCOMP_RET_ERRNO + EPERM);
+
+  DummyPolicy dummy_policy;
+  bpf_dsl::PolicyCompiler compiler(&dummy_policy, Trap::Registry());
+  ErrorCode e3 = compiler.Trap(NULL, NULL, true /* safe */);
+  SANDBOX_ASSERT((e3.err() & SECCOMP_RET_ACTION)  == SECCOMP_RET_TRAP);
+
+  uint16_t data = 0xdead;
+  ErrorCode e4(ErrorCode::ERR_TRACE + data);
+  SANDBOX_ASSERT(e4.err() == SECCOMP_RET_TRACE + data);
+}
+
+SANDBOX_DEATH_TEST(ErrorCode,
+                   InvalidSeccompRetTrace,
+                   DEATH_MESSAGE("Invalid use of ErrorCode object")) {
+  // Should die if the trace data does not fit in 16 bits.
+  ErrorCode e(ErrorCode::ERR_TRACE + (1 << 16));
+}
+
+SANDBOX_TEST(ErrorCode, Trap) {
+  DummyPolicy dummy_policy;
+  bpf_dsl::PolicyCompiler compiler(&dummy_policy, Trap::Registry());
+  ErrorCode e0 = compiler.Trap(NULL, "a", true /* safe */);
+  ErrorCode e1 = compiler.Trap(NULL, "b", true /* safe */);
+  SANDBOX_ASSERT((e0.err() & SECCOMP_RET_DATA) + 1 ==
+                 (e1.err() & SECCOMP_RET_DATA));
+
+  ErrorCode e2 = compiler.Trap(NULL, "a", true /* safe */);
+  SANDBOX_ASSERT((e0.err() & SECCOMP_RET_DATA) ==
+                 (e2.err() & SECCOMP_RET_DATA));
+}
+
+SANDBOX_TEST(ErrorCode, Equals) {
+  ErrorCode e1(ErrorCode::ERR_ALLOWED);
+  ErrorCode e2(ErrorCode::ERR_ALLOWED);
+  SANDBOX_ASSERT(e1.Equals(e1));
+  SANDBOX_ASSERT(e1.Equals(e2));
+  SANDBOX_ASSERT(e2.Equals(e1));
+
+  ErrorCode e3(EPERM);
+  SANDBOX_ASSERT(!e1.Equals(e3));
+
+  DummyPolicy dummy_policy;
+  bpf_dsl::PolicyCompiler compiler(&dummy_policy, Trap::Registry());
+  ErrorCode e4 = compiler.Trap(NULL, "a", true /* safe */);
+  ErrorCode e5 = compiler.Trap(NULL, "b", true /* safe */);
+  ErrorCode e6 = compiler.Trap(NULL, "a", true /* safe */);
+  SANDBOX_ASSERT(!e1.Equals(e4));
+  SANDBOX_ASSERT(!e3.Equals(e4));
+  SANDBOX_ASSERT(!e5.Equals(e4));
+  SANDBOX_ASSERT( e6.Equals(e4));
+}
+
+SANDBOX_TEST(ErrorCode, LessThan) {
+  ErrorCode e1(ErrorCode::ERR_ALLOWED);
+  ErrorCode e2(ErrorCode::ERR_ALLOWED);
+  SANDBOX_ASSERT(!e1.LessThan(e1));
+  SANDBOX_ASSERT(!e1.LessThan(e2));
+  SANDBOX_ASSERT(!e2.LessThan(e1));
+
+  ErrorCode e3(EPERM);
+  SANDBOX_ASSERT(!e1.LessThan(e3));
+  SANDBOX_ASSERT( e3.LessThan(e1));
+
+  DummyPolicy dummy_policy;
+  bpf_dsl::PolicyCompiler compiler(&dummy_policy, Trap::Registry());
+  ErrorCode e4 = compiler.Trap(NULL, "a", true /* safe */);
+  ErrorCode e5 = compiler.Trap(NULL, "b", true /* safe */);
+  ErrorCode e6 = compiler.Trap(NULL, "a", true /* safe */);
+  SANDBOX_ASSERT(e1.LessThan(e4));
+  SANDBOX_ASSERT(e3.LessThan(e4));
+  SANDBOX_ASSERT(e4.LessThan(e5));
+  SANDBOX_ASSERT(!e4.LessThan(e6));
+  SANDBOX_ASSERT(!e6.LessThan(e4));
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
new file mode 100644
index 0000000..239043e
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+
+// Some headers on Android are missing cdefs: crbug.com/172337.
+// (We can't use OS_ANDROID here since build_config.h is not included).
+#if defined(ANDROID)
+#include <sys/cdefs.h>
+#endif
+
+#include <errno.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+namespace {
+
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
+bool IsSingleThreaded(int proc_fd) {
+  return ThreadHelpers::IsSingleThreaded(proc_fd);
+}
+
+// Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
+// prctl().
+bool KernelSupportsSeccompBPF() {
+  errno = 0;
+  const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
+
+  if (rv == -1 && EFAULT == errno) {
+    return true;
+  }
+  return false;
+}
+
+// LG introduced a buggy syscall, sys_set_media_ext, with the same number as
+// seccomp. Return true if the current kernel has this buggy syscall.
+//
+// We want this to work with upcoming versions of seccomp, so we pass bogus
+// flags that are unlikely to ever be used by the kernel. A normal kernel would
+// return -EINVAL, but a buggy LG kernel would return 1.
+bool KernelHasLGBug() {
+#if defined(OS_ANDROID)
+  // sys_set_media will see this as NULL, which should be a safe (non-crashing)
+  // way to invoke it. A genuine seccomp syscall will see it as
+  // SECCOMP_SET_MODE_STRICT.
+  const unsigned int operation = 0;
+  // Chosen by fair dice roll. Guaranteed to be random.
+  const unsigned int flags = 0xf7a46a5c;
+  const int rv = sys_seccomp(operation, flags, nullptr);
+  // A genuine kernel would return -EINVAL (which would set rv to -1 and errno
+  // to EINVAL), or at the very least return some kind of error (which would
+  // set rv to -1). Any other behavior indicates that whatever code received
+  // our syscall was not the real seccomp.
+  if (rv != -1) {
+    return true;
+  }
+#endif  // defined(OS_ANDROID)
+
+  return false;
+}
+
+// Check if the kernel supports seccomp-filter via the seccomp system call
+// and the TSYNC feature to enable seccomp on all threads.
+bool KernelSupportsSeccompTsync() {
+  if (KernelHasLGBug()) {
+    return false;
+  }
+
+  errno = 0;
+  const int rv =
+      sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
+
+  if (rv == -1 && errno == EFAULT) {
+    return true;
+  } else {
+    // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
+    CHECK_EQ(-1, rv);
+    CHECK(ENOSYS == errno || EINVAL == errno);
+    return false;
+  }
+}
+
+uint64_t EscapePC() {
+  intptr_t rv = Syscall::Call(-1);
+  if (rv == -1 && errno == ENOSYS) {
+    return 0;
+  }
+  return static_cast<uint64_t>(static_cast<uintptr_t>(rv));
+}
+
+}  // namespace
+
+SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
+    : proc_fd_(), sandbox_has_started_(false), policy_(policy) {
+}
+
+SandboxBPF::~SandboxBPF() {
+}
+
+// static
+bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
+  // Never pretend to support seccomp with Valgrind, as it
+  // throws the tool off.
+  if (IsRunningOnValgrind()) {
+    return false;
+  }
+
+  switch (level) {
+    case SeccompLevel::SINGLE_THREADED:
+      return KernelSupportsSeccompBPF();
+    case SeccompLevel::MULTI_THREADED:
+      return KernelSupportsSeccompTsync();
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
+  DCHECK(policy_);
+  CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
+        seccomp_level == SeccompLevel::MULTI_THREADED);
+
+  if (sandbox_has_started_) {
+    SANDBOX_DIE(
+        "Cannot repeatedly start sandbox. Create a separate Sandbox "
+        "object instead.");
+    return false;
+  }
+
+  if (!proc_fd_.is_valid()) {
+    SetProcFd(ProcUtil::OpenProc());
+  }
+
+  const bool supports_tsync = KernelSupportsSeccompTsync();
+
+  if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
+    // Wait for /proc/self/task/ to update if needed and assert the
+    // process is single threaded.
+    ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
+  } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
+    if (IsSingleThreaded(proc_fd_.get())) {
+      SANDBOX_DIE("Cannot start sandbox; "
+                  "process may be single-threaded when reported as not");
+      return false;
+    }
+    if (!supports_tsync) {
+      SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
+                  "filters for a threadgroup");
+      return false;
+    }
+  }
+
+  // We no longer need access to any files in /proc. We want to do this
+  // before installing the filters, just in case that our policy denies
+  // close().
+  if (proc_fd_.is_valid()) {
+    proc_fd_.reset();
+  }
+
+  // Install the filters.
+  InstallFilter(supports_tsync ||
+                seccomp_level == SeccompLevel::MULTI_THREADED);
+
+  return true;
+}
+
+void SandboxBPF::SetProcFd(base::ScopedFD proc_fd) {
+  proc_fd_.swap(proc_fd);
+}
+
+// static
+bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
+  return SyscallSet::IsValid(sysnum);
+}
+
+// static
+bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
+  return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
+}
+
+// static
+intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
+  return Syscall::Call(
+      args.nr, static_cast<intptr_t>(args.args[0]),
+      static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
+      static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
+      static_cast<intptr_t>(args.args[5]));
+}
+
+scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
+    bool force_verification) {
+#if !defined(NDEBUG)
+  force_verification = true;
+#endif
+  DCHECK(policy_);
+
+  bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
+  if (Trap::SandboxDebuggingAllowedByUser()) {
+    compiler.DangerousSetEscapePC(EscapePC());
+  }
+  return compiler.Compile(force_verification);
+}
+
+void SandboxBPF::InstallFilter(bool must_sync_threads) {
+  // We want to be very careful in not imposing any requirements on the
+  // policies that are set with SetSandboxPolicy(). This means, as soon as
+  // the sandbox is active, we shouldn't be relying on libraries that could
+  // be making system calls. This, for example, means we should avoid
+  // using the heap and we should avoid using STL functions.
+  // Temporarily copy the contents of the "program" vector into a
+  // stack-allocated array; and then explicitly destroy that object.
+  // This makes sure we don't ex- or implicitly call new/delete after we
+  // installed the BPF filter program in the kernel. Depending on the
+  // system memory allocator that is in effect, these operators can result
+  // in system calls to things like munmap() or brk().
+  CodeGen::Program* program = AssembleFilter(false).release();
+
+  struct sock_filter bpf[program->size()];
+  const struct sock_fprog prog = {static_cast<unsigned short>(program->size()),
+                                  bpf};
+  memcpy(bpf, &(*program)[0], sizeof(bpf));
+  delete program;
+
+  // Make an attempt to release memory that is no longer needed here, rather
+  // than in the destructor. Try to avoid as much as possible to presume of
+  // what will be possible to do in the new (sandboxed) execution environment.
+  policy_.reset();
+
+  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+    SANDBOX_DIE("Kernel refuses to enable no-new-privs");
+  }
+
+  // Install BPF filter program. If the thread state indicates multi-threading
+  // support, then the kernel hass the seccomp system call. Otherwise, fall
+  // back on prctl, which requires the process to be single-threaded.
+  if (must_sync_threads) {
+    int rv =
+        sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
+    if (rv) {
+      SANDBOX_DIE(
+          "Kernel refuses to turn on and synchronize threads for BPF filters");
+    }
+  } else {
+    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
+      SANDBOX_DIE("Kernel refuses to turn on BPF filters");
+    }
+  }
+
+  sandbox_has_started_ = true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
new file mode 100644
index 0000000..96cceb5
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
+
+#include <stdint.h>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+struct arch_seccomp_data;
+namespace bpf_dsl {
+class Policy;
+}
+
+// This class can be used to apply a syscall sandboxing policy expressed in a
+// bpf_dsl::Policy object to the current process.
+// Syscall sandboxing policies get inherited by subprocesses and, once applied,
+// can never be removed for the lifetime of the process.
+class SANDBOX_EXPORT SandboxBPF {
+ public:
+  enum class SeccompLevel {
+    SINGLE_THREADED,
+    MULTI_THREADED,
+  };
+
+  // Ownership of |policy| is transfered here to the sandbox object.
+  // nullptr is allowed for unit tests.
+  explicit SandboxBPF(bpf_dsl::Policy* policy);
+  // NOTE: Setting a policy and starting the sandbox is a one-way operation.
+  // The kernel does not provide any option for unloading a loaded sandbox. The
+  // sandbox remains engaged even when the object is destructed.
+  ~SandboxBPF();
+
+  // Detect if the kernel supports the specified seccomp level.
+  // See StartSandbox() for a description of these.
+  static bool SupportsSeccompSandbox(SeccompLevel level);
+
+  // This is the main public entry point. It sets up the resources needed by
+  // the sandbox, and enters Seccomp mode.
+  // The calling process must provide a |level| to tell the sandbox which type
+  // of kernel support it should engage.
+  // SINGLE_THREADED will only sandbox the calling thread. Since it would be a
+  // security risk, the sandbox will also check that the current process is
+  // single threaded and crash if it isn't the case.
+  // MULTI_THREADED requires more recent kernel support and allows to sandbox
+  // all the threads of the current process. Be mindful of potential races,
+  // with other threads using disallowed system calls either before or after
+  // the sandbox is engaged.
+  //
+  // It is possible to stack multiple sandboxes by creating separate "Sandbox"
+  // objects and calling "StartSandbox()" on each of them. Please note, that
+  // this requires special care, though, as newly stacked sandboxes can never
+  // relax restrictions imposed by earlier sandboxes. Furthermore, installing
+  // a new policy requires making system calls, that might already be
+  // disallowed.
+  // Finally, stacking does add more kernel overhead than having a single
+  // combined policy. So, it should only be used if there are no alternatives.
+  bool StartSandbox(SeccompLevel level) WARN_UNUSED_RESULT;
+
+  // The sandbox needs to be able to access files in "/proc/self/". If
+  // this directory is not accessible when "StartSandbox()" gets called, the
+  // caller must provide an already opened file descriptor by calling
+  // "SetProcFd()".
+  // The sandbox becomes the new owner of this file descriptor and will
+  // close it when "StartSandbox()" executes or when the sandbox object
+  // disappears.
+  void SetProcFd(base::ScopedFD proc_fd);
+
+  // Checks whether a particular system call number is valid on the current
+  // architecture.
+  static bool IsValidSyscallNumber(int sysnum);
+
+  // UnsafeTraps require some syscalls to always be allowed.
+  // This helper function returns true for these calls.
+  static bool IsRequiredForUnsafeTrap(int sysno);
+
+  // From within an UnsafeTrap() it is often useful to be able to execute
+  // the system call that triggered the trap. The ForwardSyscall() method
+  // makes this easy. It is more efficient than calling glibc's syscall()
+  // function, as it avoid the extra round-trip to the signal handler. And
+  // it automatically does the correct thing to report kernel-style error
+  // conditions, rather than setting errno. See the comments for TrapFnc for
+  // details. In other words, the return value from ForwardSyscall() is
+  // directly suitable as a return value for a trap handler.
+  static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
+
+  // Assembles a BPF filter program from the current policy. After calling this
+  // function, you must not call any other sandboxing function.
+  // Typically, AssembleFilter() is only used by unit tests and by sandbox
+  // internals. It should not be used by production code.
+  // For performance reasons, we normally only run the assembled BPF program
+  // through the verifier, iff the program was built in debug mode.
+  // But by setting "force_verification", the caller can request that the
+  // verifier is run unconditionally. This is useful for unittests.
+  scoped_ptr<CodeGen::Program> AssembleFilter(bool force_verification);
+
+ private:
+  // Assembles and installs a filter based on the policy that has previously
+  // been configured with SetSandboxPolicy().
+  void InstallFilter(bool must_sync_threads);
+
+  base::ScopedFD proc_fd_;
+  bool sandbox_has_started_;
+  scoped_ptr<bpf_dsl::Policy> policy_;
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
new file mode 100644
index 0000000..321ea9a
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
+
+#include <fcntl.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+SandboxBPFTestRunner::SandboxBPFTestRunner(
+    BPFTesterDelegate* bpf_tester_delegate)
+    : bpf_tester_delegate_(bpf_tester_delegate) {
+}
+
+SandboxBPFTestRunner::~SandboxBPFTestRunner() {
+}
+
+void SandboxBPFTestRunner::Run() {
+  DCHECK(bpf_tester_delegate_);
+  sandbox::Die::EnableSimpleExit();
+
+  scoped_ptr<bpf_dsl::Policy> policy =
+      bpf_tester_delegate_->GetSandboxBPFPolicy();
+
+  if (sandbox::SandboxBPF::SupportsSeccompSandbox(
+          SandboxBPF::SeccompLevel::SINGLE_THREADED)) {
+    // Initialize and then start the sandbox with our custom policy
+    sandbox::SandboxBPF sandbox(policy.release());
+    SANDBOX_ASSERT(sandbox.StartSandbox(
+        sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED));
+
+    // Run the actual test.
+    bpf_tester_delegate_->RunTestFunction();
+  } else {
+    printf("This BPF test is not fully running in this configuration!\n");
+    // Android and Valgrind are the only configurations where we accept not
+    // having kernel BPF support.
+    if (!IsAndroid() && !IsRunningOnValgrind()) {
+      const bool seccomp_bpf_is_supported = false;
+      SANDBOX_ASSERT(seccomp_bpf_is_supported);
+    }
+    // Call the compiler and verify the policy. That's the least we can do,
+    // if we don't have kernel support.
+    sandbox::SandboxBPF sandbox(policy.release());
+    sandbox.AssembleFilter(true /* force_verification */);
+    sandbox::UnitTests::IgnoreThisTest();
+  }
+}
+
+bool SandboxBPFTestRunner::ShouldCheckForLeaks() const {
+  // LSAN requires being able to use ptrace() and other system calls that could
+  // be denied.
+  return false;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
new file mode 100644
index 0000000..fef6240
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/tests/sandbox_test_runner.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class Policy;
+}
+
+// To create a SandboxBPFTestRunner object, one needs to implement this
+// interface and pass an instance to the SandboxBPFTestRunner constructor.
+// In the child process running the test, the BPFTesterDelegate object is
+// guaranteed to not be destroyed until the child process terminates.
+class BPFTesterDelegate {
+ public:
+  BPFTesterDelegate() {}
+  virtual ~BPFTesterDelegate() {}
+
+  // This will instanciate a policy suitable for the test we want to run. It is
+  // guaranteed to only be called from the child process that will run the
+  // test.
+  virtual scoped_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() = 0;
+  // This will be called from a child process with the BPF sandbox turned on.
+  virtual void RunTestFunction() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BPFTesterDelegate);
+};
+
+// This class implements the SandboxTestRunner interface and Run() will
+// initialize a seccomp-bpf sandbox (specified by |bpf_tester_delegate|) and
+// run a test function (via |bpf_tester_delegate|) if the current kernel
+// configuration allows it. If it can not run the test under seccomp-bpf,
+// Run() will still compile the policy which should allow to get some coverage
+// under tools such as Valgrind.
+class SandboxBPFTestRunner : public SandboxTestRunner {
+ public:
+  // This constructor takes ownership of the |bpf_tester_delegate| object.
+  // (It doesn't take a scoped_ptr since they make polymorphism verbose).
+  explicit SandboxBPFTestRunner(BPFTesterDelegate* bpf_tester_delegate);
+  ~SandboxBPFTestRunner() override;
+
+  void Run() override;
+
+  bool ShouldCheckForLeaks() const override;
+
+ private:
+  scoped_ptr<BPFTesterDelegate> bpf_tester_delegate_;
+  DISALLOW_COPY_AND_ASSIGN(SandboxBPFTestRunner);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
new file mode 100644
index 0000000..580cad2
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <iostream>
+
+#include "base/files/scoped_file.h"
+#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+// NOTE: most tests for the SandboxBPF class are currently in
+// integration_tests/.
+
+TEST(SandboxBPF, CreateDestroy) {
+  // Give an opportunity to dynamic tools to perform some simple testing.
+  SandboxBPF sandbox(nullptr);
+  SandboxBPF* sandbox_ptr = new SandboxBPF(nullptr);
+  delete sandbox_ptr;
+}
+
+// This test should execute no matter whether we have kernel support. So,
+// we make it a TEST() instead of a BPF_TEST().
+TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupports)) {
+  // We check that we don't crash, but it's ok if the kernel doesn't
+  // support it.
+  bool seccomp_bpf_supported = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::SINGLE_THREADED);
+  bool seccomp_bpf_tsync_supported = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::MULTI_THREADED);
+  // We want to log whether or not seccomp BPF is actually supported
+  // since actual test coverage depends on it.
+  std::cout << "Seccomp BPF supported (single thread): "
+            << (seccomp_bpf_supported ? "true." : "false.") << "\n";
+  std::cout << "Seccomp BPF supported (multi thread): "
+            << (seccomp_bpf_tsync_supported ? "true." : "false.") << "\n";
+  std::cout << "Pointer size: " << sizeof(void*) << "\n";
+}
+
+SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(CallSupportsTwice)) {
+  bool single1 = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::SINGLE_THREADED);
+  bool single2 = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::SINGLE_THREADED);
+  ASSERT_EQ(single1, single2);
+  bool multi1 = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::MULTI_THREADED);
+  bool multi2 = SandboxBPF::SupportsSeccompSandbox(
+      SandboxBPF::SeccompLevel::MULTI_THREADED);
+  ASSERT_EQ(multi1, multi2);
+
+  // Multi threaded support implies single threaded support.
+  if (multi1) {
+    ASSERT_TRUE(single1);
+  }
+}
+
+TEST(SandboxBPF, ProcTaskFdDescriptorGetsClosed) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+  base::ScopedFD read_end(pipe_fds[0]);
+  base::ScopedFD write_end(pipe_fds[1]);
+
+  {
+    SandboxBPF sandbox(nullptr);
+    sandbox.SetProcFd(write_end.Pass());
+  }
+
+  ASSERT_EQ(0, fcntl(read_end.get(), F_SETFL, O_NONBLOCK));
+  char c;
+  // Check that the sandbox closed the write_end (read will EOF instead of
+  // returning EWOULDBLOCK).
+  ASSERT_EQ(0, read(read_end.get(), &c, 1));
+}
+
+}  // namespace
+}  // sandbox
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
new file mode 100644
index 0000000..bc6461f
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -0,0 +1,421 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+
+#include <errno.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+
+namespace sandbox {
+
+namespace {
+
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY)
+// Number that's not currently used by any Linux kernel ABIs.
+const int kInvalidSyscallNumber = 0x351d3;
+#else
+#error Unrecognized architecture
+#endif
+
+asm(// We need to be able to tell the kernel exactly where we made a
+    // system call. The C++ compiler likes to sometimes clone or
+    // inline code, which would inadvertently end up duplicating
+    // the entry point.
+    // "gcc" can suppress code duplication with suitable function
+    // attributes, but "clang" doesn't have this ability.
+    // The "clang" developer mailing list suggested that the correct
+    // and portable solution is a file-scope assembly block.
+    // N.B. We do mark our code as a proper function so that backtraces
+    // work correctly. But we make absolutely no attempt to use the
+    // ABI's calling conventions for passing arguments. We will only
+    // ever be called from assembly code and thus can pick more
+    // suitable calling conventions.
+#if defined(__i386__)
+    ".text\n"
+    ".align 16, 0x90\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.cfi_startproc\n"
+    // Check if "%eax" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "int $0x80". This address can be
+    // used as a marker that BPF code inspects.
+    "test %eax, %eax\n"
+    "jge  1f\n"
+    // Always, make sure that our code is position-independent, or
+    // address space randomization might not work on i386. This means,
+    // we can't use "lea", but instead have to rely on "call/pop".
+    "call 0f;   .cfi_adjust_cfa_offset  4\n"
+    "0:pop  %eax; .cfi_adjust_cfa_offset -4\n"
+    "addl $2f-0b, %eax\n"
+    "ret\n"
+    // Save register that we don't want to clobber. On i386, we need to
+    // save relatively aggressively, as there are a couple or registers
+    // that are used internally (e.g. %ebx for position-independent
+    // code, and %ebp for the frame pointer), and as we need to keep at
+    // least a few registers available for the register allocator.
+    "1:push %esi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset esi, 0\n"
+    "push %edi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset edi, 0\n"
+    "push %ebx; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebx, 0\n"
+    "push %ebp; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebp, 0\n"
+    // Copy entries from the array holding the arguments into the
+    // correct CPU registers.
+    "movl  0(%edi), %ebx\n"
+    "movl  4(%edi), %ecx\n"
+    "movl  8(%edi), %edx\n"
+    "movl 12(%edi), %esi\n"
+    "movl 20(%edi), %ebp\n"
+    "movl 16(%edi), %edi\n"
+    // Enter the kernel.
+    "int  $0x80\n"
+    // This is our "magic" return address that the BPF filter sees.
+    "2:"
+    // Restore any clobbered registers that we didn't declare to the
+    // compiler.
+    "pop  %ebp; .cfi_restore ebp; .cfi_adjust_cfa_offset -4\n"
+    "pop  %ebx; .cfi_restore ebx; .cfi_adjust_cfa_offset -4\n"
+    "pop  %edi; .cfi_restore edi; .cfi_adjust_cfa_offset -4\n"
+    "pop  %esi; .cfi_restore esi; .cfi_adjust_cfa_offset -4\n"
+    "ret\n"
+    ".cfi_endproc\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__x86_64__)
+    ".text\n"
+    ".align 16, 0x90\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.cfi_startproc\n"
+    // Check if "%rdi" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "syscall". This address can be
+    // used as a marker that BPF code inspects.
+    "test %rdi, %rdi\n"
+    "jge  1f\n"
+    // Always make sure that our code is position-independent, or the
+    // linker will throw a hissy fit on x86-64.
+    "lea 2f(%rip), %rax\n"
+    "ret\n"
+    // Now we load the registers used to pass arguments to the system
+    // call: system call number in %rax, and arguments in %rdi, %rsi,
+    // %rdx, %r10, %r8, %r9. Note: These are all caller-save registers
+    // (only %rbx, %rbp, %rsp, and %r12-%r15 are callee-save), so no
+    // need to worry here about spilling registers or CFI directives.
+    "1:movq %rdi, %rax\n"
+    "movq  0(%rsi), %rdi\n"
+    "movq 16(%rsi), %rdx\n"
+    "movq 24(%rsi), %r10\n"
+    "movq 32(%rsi), %r8\n"
+    "movq 40(%rsi), %r9\n"
+    "movq  8(%rsi), %rsi\n"
+    // Enter the kernel.
+    "syscall\n"
+    // This is our "magic" return address that the BPF filter sees.
+    "2:ret\n"
+    ".cfi_endproc\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__arm__)
+    // Throughout this file, we use the same mode (ARM vs. thumb)
+    // that the C++ compiler uses. This means, when transfering control
+    // from C++ to assembly code, we do not need to switch modes (e.g.
+    // by using the "bx" instruction). It also means that our assembly
+    // code should not be invoked directly from code that lives in
+    // other compilation units, as we don't bother implementing thumb
+    // interworking. That's OK, as we don't make any of the assembly
+    // symbols public. They are all local to this file.
+    ".text\n"
+    ".align 2\n"
+    ".type SyscallAsm, %function\n"
+#if defined(__thumb__)
+    ".thumb_func\n"
+#else
+    ".arm\n"
+#endif
+    "SyscallAsm:\n"
+#if !defined(__native_client_nonsfi__)
+    // .fnstart and .fnend pseudo operations creates unwind table.
+    // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
+    // is not provided by PNaCl toolchain. Disable it.
+    ".fnstart\n"
+#endif
+    "@ args = 0, pretend = 0, frame = 8\n"
+    "@ frame_needed = 1, uses_anonymous_args = 0\n"
+#if defined(__thumb__)
+    ".cfi_startproc\n"
+    "push {r7, lr}\n"
+    ".save {r7, lr}\n"
+    ".cfi_offset 14, -4\n"
+    ".cfi_offset  7, -8\n"
+    ".cfi_def_cfa_offset 8\n"
+#else
+    "stmfd sp!, {fp, lr}\n"
+    "add fp, sp, #4\n"
+#endif
+    // Check if "r0" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "swi 0". This address can be
+    // used as a marker that BPF code inspects.
+    "cmp r0, #0\n"
+    "bge 1f\n"
+    "adr r0, 2f\n"
+    "b   2f\n"
+    // We declared (almost) all clobbered registers to the compiler. On
+    // ARM there is no particular register pressure. So, we can go
+    // ahead and directly copy the entries from the arguments array
+    // into the appropriate CPU registers.
+    "1:ldr r5, [r6, #20]\n"
+    "ldr r4, [r6, #16]\n"
+    "ldr r3, [r6, #12]\n"
+    "ldr r2, [r6, #8]\n"
+    "ldr r1, [r6, #4]\n"
+    "mov r7, r0\n"
+    "ldr r0, [r6, #0]\n"
+    // Enter the kernel
+    "swi 0\n"
+// Restore the frame pointer. Also restore the program counter from
+// the link register; this makes us return to the caller.
+#if defined(__thumb__)
+    "2:pop {r7, pc}\n"
+    ".cfi_endproc\n"
+#else
+    "2:ldmfd sp!, {fp, pc}\n"
+#endif
+#if !defined(__native_client_nonsfi__)
+    // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
+    // for more details.
+    ".fnend\n"
+#endif
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__mips__)
+    ".text\n"
+    ".align 4\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.ent SyscallAsm\n"
+    ".frame  $sp, 40, $ra\n"
+    ".set   push\n"
+    ".set   noreorder\n"
+    "addiu  $sp, $sp, -40\n"
+    "sw     $ra, 36($sp)\n"
+    // Check if "v0" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "syscall". This address can be
+    // used as a marker that BPF code inspects.
+    "bgez   $v0, 1f\n"
+    " nop\n"
+    "la     $v0, 2f\n"
+    "b      2f\n"
+    " nop\n"
+    // On MIPS first four arguments go to registers a0 - a3 and any
+    // argument after that goes to stack. We can go ahead and directly
+    // copy the entries from the arguments array into the appropriate
+    // CPU registers and on the stack.
+    "1:lw     $a3, 28($a0)\n"
+    "lw     $a2, 24($a0)\n"
+    "lw     $a1, 20($a0)\n"
+    "lw     $t0, 16($a0)\n"
+    "sw     $a3, 28($sp)\n"
+    "sw     $a2, 24($sp)\n"
+    "sw     $a1, 20($sp)\n"
+    "sw     $t0, 16($sp)\n"
+    "lw     $a3, 12($a0)\n"
+    "lw     $a2, 8($a0)\n"
+    "lw     $a1, 4($a0)\n"
+    "lw     $a0, 0($a0)\n"
+    // Enter the kernel
+    "syscall\n"
+    // This is our "magic" return address that the BPF filter sees.
+    // Restore the return address from the stack.
+    "2:lw     $ra, 36($sp)\n"
+    "jr     $ra\n"
+    " addiu  $sp, $sp, 40\n"
+    ".set    pop\n"
+    ".end    SyscallAsm\n"
+    ".size   SyscallAsm,.-SyscallAsm\n"
+#elif defined(__aarch64__)
+    ".text\n"
+    ".align 2\n"
+    ".type SyscallAsm, %function\n"
+    "SyscallAsm:\n"
+    ".cfi_startproc\n"
+    "cmp x0, #0\n"
+    "b.ge 1f\n"
+    "adr x0,2f\n"
+    "b 2f\n"
+    "1:ldr x5, [x6, #40]\n"
+    "ldr x4, [x6, #32]\n"
+    "ldr x3, [x6, #24]\n"
+    "ldr x2, [x6, #16]\n"
+    "ldr x1, [x6, #8]\n"
+    "mov x8, x0\n"
+    "ldr x0, [x6, #0]\n"
+    // Enter the kernel
+    "svc 0\n"
+    "2:ret\n"
+    ".cfi_endproc\n"
+    ".size SyscallAsm, .-SyscallAsm\n"
+#endif
+    );  // asm
+
+#if defined(__x86_64__)
+extern "C" {
+intptr_t SyscallAsm(intptr_t nr, const intptr_t args[6]);
+}
+#endif
+
+}  // namespace
+
+intptr_t Syscall::InvalidCall() {
+  // Explicitly pass eight zero arguments just in case.
+  return Call(kInvalidSyscallNumber, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+intptr_t Syscall::Call(int nr,
+                       intptr_t p0,
+                       intptr_t p1,
+                       intptr_t p2,
+                       intptr_t p3,
+                       intptr_t p4,
+                       intptr_t p5,
+                       intptr_t p6,
+                       intptr_t p7) {
+  // We rely on "intptr_t" to be the exact size as a "void *". This is
+  // typically true, but just in case, we add a check. The language
+  // specification allows platforms some leeway in cases, where
+  // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect
+  // that this would only be an issue for IA64, which we are currently not
+  // planning on supporting. And it is even possible that this would work
+  // on IA64, but for lack of actual hardware, I cannot test.
+  static_assert(sizeof(void*) == sizeof(intptr_t),
+                "pointer types and intptr_t must be exactly the same size");
+
+  // TODO(nedeljko): Enable use of more than six parameters on architectures
+  //                 where that makes sense.
+#if defined(__mips__)
+  const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7};
+#else
+  DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not "
+                      "added for this architecture";
+  DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not "
+                      "added for this architecture";
+  const intptr_t args[6] = {p0, p1, p2, p3, p4, p5};
+#endif  // defined(__mips__)
+
+// Invoke our file-scope assembly code. The constraints have been picked
+// carefully to match what the rest of the assembly code expects in input,
+// output, and clobbered registers.
+#if defined(__i386__)
+  intptr_t ret = nr;
+  asm volatile(
+      "call SyscallAsm\n"
+      // N.B. These are not the calling conventions normally used by the ABI.
+      : "=a"(ret)
+      : "0"(ret), "D"(args)
+      : "cc", "esp", "memory", "ecx", "edx");
+#elif defined(__x86_64__)
+  intptr_t ret = SyscallAsm(nr, args);
+#elif defined(__arm__)
+  intptr_t ret;
+  {
+    register intptr_t inout __asm__("r0") = nr;
+    register const intptr_t* data __asm__("r6") = args;
+    asm volatile(
+        "bl SyscallAsm\n"
+        // N.B. These are not the calling conventions normally used by the ABI.
+        : "=r"(inout)
+        : "0"(inout), "r"(data)
+        : "cc",
+          "lr",
+          "memory",
+          "r1",
+          "r2",
+          "r3",
+          "r4",
+          "r5"
+#if !defined(__thumb__)
+          // In thumb mode, we cannot use "r7" as a general purpose register, as
+          // it is our frame pointer. We have to manually manage and preserve
+          // it.
+          // In ARM mode, we have a dedicated frame pointer register and "r7" is
+          // thus available as a general purpose register. We don't preserve it,
+          // but instead mark it as clobbered.
+          ,
+          "r7"
+#endif  // !defined(__thumb__)
+        );
+    ret = inout;
+  }
+#elif defined(__mips__)
+  int err_status;
+  intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status);
+
+  if (err_status) {
+    // On error, MIPS returns errno from syscall instead of -errno.
+    // The purpose of this negation is for SandboxSyscall() to behave
+    // more like it would on other architectures.
+    ret = -ret;
+  }
+#elif defined(__aarch64__)
+  intptr_t ret;
+  {
+    register intptr_t inout __asm__("x0") = nr;
+    register const intptr_t* data __asm__("x6") = args;
+    asm volatile("bl SyscallAsm\n"
+                 : "=r"(inout)
+                 : "0"(inout), "r"(data)
+                 : "memory", "x1", "x2", "x3", "x4", "x5", "x8", "x30");
+    ret = inout;
+  }
+
+#else
+#error "Unimplemented architecture"
+#endif
+  return ret;
+}
+
+void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) {
+#if defined(__mips__)
+  // Mips ABI states that on error a3 CPU register has non zero value and if
+  // there is no error, it should be zero.
+  if (ret_val <= -1 && ret_val >= -4095) {
+    // |ret_val| followes the Syscall::Call() convention of being -errno on
+    // errors. In order to write correct value to return register this sign
+    // needs to be changed back.
+    ret_val = -ret_val;
+    SECCOMP_PARM4(ctx) = 1;
+  } else
+    SECCOMP_PARM4(ctx) = 0;
+#endif
+  SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val);
+}
+
+#if defined(__mips__)
+intptr_t Syscall::SandboxSyscallRaw(int nr,
+                                    const intptr_t* args,
+                                    intptr_t* err_ret) {
+  register intptr_t ret __asm__("v0") = nr;
+  // a3 register becomes non zero on error.
+  register intptr_t err_stat __asm__("a3") = 0;
+  {
+    register const intptr_t* data __asm__("a0") = args;
+    asm volatile(
+        "la $t9, SyscallAsm\n"
+        "jalr $t9\n"
+        " nop\n"
+        : "=r"(ret), "=r"(err_stat)
+        : "0"(ret),
+          "r"(data)
+          // a2 is in the clober list so inline assembly can not change its
+          // value.
+        : "memory", "ra", "t9", "a2");
+  }
+
+  // Set an error status so it can be used outside of this function
+  *err_ret = err_stat;
+
+  return ret;
+}
+#endif  // defined(__mips__)
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/syscall.h b/sandbox/linux/seccomp-bpf/syscall.h
new file mode 100644
index 0000000..ccfc88d
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/syscall.h
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+
+#include <signal.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This purely static class can be used to perform system calls with some
+// low-level control.
+class SANDBOX_EXPORT Syscall {
+ public:
+  // InvalidCall() invokes Call() with a platform-appropriate syscall
+  // number that is guaranteed to not be implemented (i.e., normally
+  // returns -ENOSYS).
+  // This is primarily meant to be useful for writing sandbox policy
+  // unit tests.
+  static intptr_t InvalidCall();
+
+  // System calls can take up to six parameters (up to eight on some
+  // architectures). Traditionally, glibc
+  // implements this property by using variadic argument lists. This works, but
+  // confuses modern tools such as valgrind, because we are nominally passing
+  // uninitialized data whenever we call through this function and pass less
+  // than the full six arguments.
+  // So, instead, we use C++'s template system to achieve a very similar
+  // effect. C++ automatically sets the unused parameters to zero for us, and
+  // it also does the correct type expansion (e.g. from 32bit to 64bit) where
+  // necessary.
+  // We have to use C-style cast operators as we want to be able to accept both
+  // integer and pointer types.
+  template <class T0,
+            class T1,
+            class T2,
+            class T3,
+            class T4,
+            class T5,
+            class T6,
+            class T7>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5,
+                (intptr_t)p6,
+                (intptr_t)p7);
+  }
+
+  template <class T0,
+            class T1,
+            class T2,
+            class T3,
+            class T4,
+            class T5,
+            class T6>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5,
+                (intptr_t)p6,
+                0);
+  }
+
+  template <class T0, class T1, class T2, class T3, class T4, class T5>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5,
+                0,
+                0);
+  }
+
+  template <class T0, class T1, class T2, class T3, class T4>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) {
+    return Call(nr, p0, p1, p2, p3, p4, 0, 0, 0);
+  }
+
+  template <class T0, class T1, class T2, class T3>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3) {
+    return Call(nr, p0, p1, p2, p3, 0, 0, 0, 0);
+  }
+
+  template <class T0, class T1, class T2>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2) {
+    return Call(nr, p0, p1, p2, 0, 0, 0, 0, 0);
+  }
+
+  template <class T0, class T1>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1) {
+    return Call(nr, p0, p1, 0, 0, 0, 0, 0, 0);
+  }
+
+  template <class T0>
+  static inline intptr_t Call(int nr, T0 p0) {
+    return Call(nr, p0, 0, 0, 0, 0, 0, 0, 0);
+  }
+
+  static inline intptr_t Call(int nr) {
+    return Call(nr, 0, 0, 0, 0, 0, 0, 0, 0);
+  }
+
+  // Set the registers in |ctx| to match what they would be after a system call
+  // returning |ret_val|. |ret_val| must follow the Syscall::Call() convention
+  // of being -errno on errors.
+  static void PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx);
+
+ private:
+  // This performs system call |nr| with the arguments p0 to p7 from a constant
+  // userland address, which is for instance observable by seccomp-bpf filters.
+  // The constant userland address from which these system calls are made will
+  // be returned if |nr| is passed as -1.
+  // On error, this function will return a value between -1 and -4095 which
+  // should be interpreted as -errno.
+  static intptr_t Call(int nr,
+                       intptr_t p0,
+                       intptr_t p1,
+                       intptr_t p2,
+                       intptr_t p3,
+                       intptr_t p4,
+                       intptr_t p5,
+                       intptr_t p6,
+                       intptr_t p7);
+
+#if defined(__mips__)
+  // This function basically does on MIPS what SandboxSyscall() is doing on
+  // other architectures. However, because of specificity of MIPS regarding
+  // handling syscall errors, SandboxSyscall() is made as a wrapper for this
+  // function in order for SandboxSyscall() to behave more like on other
+  // architectures on places where return value from SandboxSyscall() is used
+  // directly (like in most tests).
+  // The syscall "nr" is called with arguments that are set in an array on which
+  // pointer "args" points to and an information weather there is an error or no
+  // is returned to SandboxSyscall() by err_stat.
+  static intptr_t SandboxSyscallRaw(int nr,
+                                    const intptr_t* args,
+                                    intptr_t* err_stat);
+#endif  // defined(__mips__)
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
diff --git a/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
new file mode 100644
index 0000000..5fdee6c
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -0,0 +1,240 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+
+#include <asm/unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::ResultExpr;
+using sandbox::bpf_dsl::Trap;
+
+namespace sandbox {
+
+namespace {
+
+// Different platforms use different symbols for the six-argument version
+// of the mmap() system call. Test for the correct symbol at compile time.
+#ifdef __NR_mmap2
+const int kMMapNr = __NR_mmap2;
+#else
+const int kMMapNr = __NR_mmap;
+#endif
+
+TEST(Syscall, InvalidCallReturnsENOSYS) {
+  EXPECT_EQ(-ENOSYS, Syscall::InvalidCall());
+}
+
+TEST(Syscall, WellKnownEntryPoint) {
+// Test that Syscall::Call(-1) is handled specially. Don't do this on ARM,
+// where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
+// are still testing ARM code in the next set of tests.
+#if !defined(__arm__) && !defined(__aarch64__)
+  EXPECT_NE(Syscall::Call(-1), syscall(-1));
+#endif
+
+// If possible, test that Syscall::Call(-1) returns the address right
+// after
+// a kernel entry point.
+#if defined(__i386__)
+  EXPECT_EQ(0x80CDu, ((uint16_t*)Syscall::Call(-1))[-1]);  // INT 0x80
+#elif defined(__x86_64__)
+  EXPECT_EQ(0x050Fu, ((uint16_t*)Syscall::Call(-1))[-1]);  // SYSCALL
+#elif defined(__arm__)
+#if defined(__thumb__)
+  EXPECT_EQ(0xDF00u, ((uint16_t*)Syscall::Call(-1))[-1]);  // SWI 0
+#else
+  EXPECT_EQ(0xEF000000u, ((uint32_t*)Syscall::Call(-1))[-1]);  // SVC 0
+#endif
+#elif defined(__mips__)
+  // Opcode for MIPS sycall is in the lower 16-bits
+  EXPECT_EQ(0x0cu, (((uint32_t*)Syscall::Call(-1))[-1]) & 0x0000FFFF);
+#elif defined(__aarch64__)
+  EXPECT_EQ(0xD4000001u, ((uint32_t*)Syscall::Call(-1))[-1]);  // SVC 0
+#else
+#warning Incomplete test case; need port for target platform
+#endif
+}
+
+TEST(Syscall, TrivialSyscallNoArgs) {
+  // Test that we can do basic system calls
+  EXPECT_EQ(Syscall::Call(__NR_getpid), syscall(__NR_getpid));
+}
+
+TEST(Syscall, TrivialSyscallOneArg) {
+  int new_fd;
+  // Duplicate standard error and close it.
+  ASSERT_GE(new_fd = Syscall::Call(__NR_dup, 2), 0);
+  int close_return_value = IGNORE_EINTR(Syscall::Call(__NR_close, new_fd));
+  ASSERT_EQ(close_return_value, 0);
+}
+
+TEST(Syscall, TrivialFailingSyscall) {
+  errno = -42;
+  int ret = Syscall::Call(__NR_dup, -1);
+  ASSERT_EQ(-EBADF, ret);
+  // Verify that Syscall::Call does not touch errno.
+  ASSERT_EQ(-42, errno);
+}
+
+// SIGSYS trap handler that will be called on __NR_uname.
+intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void* aux) {
+  // |aux| is our BPF_AUX pointer.
+  std::vector<uint64_t>* const seen_syscall_args =
+      static_cast<std::vector<uint64_t>*>(aux);
+  BPF_ASSERT(arraysize(args.args) == 6);
+  seen_syscall_args->assign(args.args, args.args + arraysize(args.args));
+  return -ENOMEM;
+}
+
+class CopyAllArgsOnUnamePolicy : public bpf_dsl::Policy {
+ public:
+  explicit CopyAllArgsOnUnamePolicy(std::vector<uint64_t>* aux) : aux_(aux) {}
+  ~CopyAllArgsOnUnamePolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    if (sysno == __NR_uname) {
+      return Trap(CopySyscallArgsToAux, aux_);
+    } else {
+      return Allow();
+    }
+  }
+
+ private:
+  std::vector<uint64_t>* aux_;
+
+  DISALLOW_COPY_AND_ASSIGN(CopyAllArgsOnUnamePolicy);
+};
+
+// We are testing Syscall::Call() by making use of a BPF filter that
+// allows us
+// to inspect the system call arguments that the kernel saw.
+BPF_TEST(Syscall,
+         SyntheticSixArgs,
+         CopyAllArgsOnUnamePolicy,
+         std::vector<uint64_t> /* (*BPF_AUX) */) {
+  const int kExpectedValue = 42;
+  // In this test we only pass integers to the kernel. We might want to make
+  // additional tests to try other types. What we will see depends on
+  // implementation details of kernel BPF filters and we will need to document
+  // the expected behavior very clearly.
+  int syscall_args[6];
+  for (size_t i = 0; i < arraysize(syscall_args); ++i) {
+    syscall_args[i] = kExpectedValue + i;
+  }
+
+  // We could use pretty much any system call we don't need here. uname() is
+  // nice because it doesn't have any dangerous side effects.
+  BPF_ASSERT(Syscall::Call(__NR_uname,
+                           syscall_args[0],
+                           syscall_args[1],
+                           syscall_args[2],
+                           syscall_args[3],
+                           syscall_args[4],
+                           syscall_args[5]) == -ENOMEM);
+
+  // We expect the trap handler to have copied the 6 arguments.
+  BPF_ASSERT(BPF_AUX->size() == 6);
+
+  // Don't loop here so that we can see which argument does cause the failure
+  // easily from the failing line.
+  // uint64_t is the type passed to our SIGSYS handler.
+  BPF_ASSERT((*BPF_AUX)[0] == static_cast<uint64_t>(syscall_args[0]));
+  BPF_ASSERT((*BPF_AUX)[1] == static_cast<uint64_t>(syscall_args[1]));
+  BPF_ASSERT((*BPF_AUX)[2] == static_cast<uint64_t>(syscall_args[2]));
+  BPF_ASSERT((*BPF_AUX)[3] == static_cast<uint64_t>(syscall_args[3]));
+  BPF_ASSERT((*BPF_AUX)[4] == static_cast<uint64_t>(syscall_args[4]));
+  BPF_ASSERT((*BPF_AUX)[5] == static_cast<uint64_t>(syscall_args[5]));
+}
+
+TEST(Syscall, ComplexSyscallSixArgs) {
+  int fd;
+  ASSERT_LE(0,
+            fd = Syscall::Call(__NR_openat, AT_FDCWD, "/dev/null", O_RDWR, 0L));
+
+  // Use mmap() to allocate some read-only memory
+  char* addr0;
+  ASSERT_NE(
+      (char*)NULL,
+      addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                    (void*)NULL,
+                                                    4096,
+                                                    PROT_READ,
+                                                    MAP_PRIVATE | MAP_ANONYMOUS,
+                                                    fd,
+                                                    0L)));
+
+  // Try to replace the existing mapping with a read-write mapping
+  char* addr1;
+  ASSERT_EQ(addr0,
+            addr1 = reinterpret_cast<char*>(
+                Syscall::Call(kMMapNr,
+                              addr0,
+                              4096L,
+                              PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+                              fd,
+                              0L)));
+  ++*addr1;  // This should not seg fault
+
+  // Clean up
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, 4096L));
+  EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
+
+  // Check that the offset argument (i.e. the sixth argument) is processed
+  // correctly.
+  ASSERT_GE(
+      fd = Syscall::Call(__NR_openat, AT_FDCWD, "/proc/self/exe", O_RDONLY, 0L),
+      0);
+  char* addr2, *addr3;
+  ASSERT_NE((char*)NULL,
+            addr2 = reinterpret_cast<char*>(Syscall::Call(
+                kMMapNr, (void*)NULL, 8192L, PROT_READ, MAP_PRIVATE, fd, 0L)));
+  ASSERT_NE((char*)NULL,
+            addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                          (void*)NULL,
+                                                          4096L,
+                                                          PROT_READ,
+                                                          MAP_PRIVATE,
+                                                          fd,
+#if defined(__NR_mmap2)
+                                                          1L
+#else
+                                                          4096L
+#endif
+                                                          )));
+  EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096));
+
+  // Just to be absolutely on the safe side, also verify that the file
+  // contents matches what we are getting from a read() operation.
+  char buf[8192];
+  EXPECT_EQ(8192, Syscall::Call(__NR_read, fd, buf, 8192L));
+  EXPECT_EQ(0, memcmp(addr2, buf, 8192));
+
+  // Clean up
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 8192L));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, 4096L));
+  EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
new file mode 100644
index 0000000..8f559e5
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -0,0 +1,390 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/trap.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace {
+
+struct arch_sigsys {
+  void* ip;
+  int nr;
+  unsigned int arch;
+};
+
+const int kCapacityIncrement = 20;
+
+// Unsafe traps can only be turned on, if the user explicitly allowed them
+// by setting the CHROME_SANDBOX_DEBUGGING environment variable.
+const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
+
+// We need to tell whether we are performing a "normal" callback, or
+// whether we were called recursively from within a UnsafeTrap() callback.
+// This is a little tricky to do, because we need to somehow get access to
+// per-thread data from within a signal context. Normal TLS storage is not
+// safely accessible at this time. We could roll our own, but that involves
+// a lot of complexity. Instead, we co-opt one bit in the signal mask.
+// If BUS is blocked, we assume that we have been called recursively.
+// There is a possibility for collision with other code that needs to do
+// this, but in practice the risks are low.
+// If SIGBUS turns out to be a problem, we could instead co-opt one of the
+// realtime signals. There are plenty of them. Unfortunately, there is no
+// way to mark a signal as allocated. So, the potential for collision is
+// possibly even worse.
+bool GetIsInSigHandler(const ucontext_t* ctx) {
+  // Note: on Android, sigismember does not take a pointer to const.
+  return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), LINUX_SIGBUS);
+}
+
+void SetIsInSigHandler() {
+  sigset_t mask;
+  if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS) ||
+      sandbox::sys_sigprocmask(LINUX_SIG_BLOCK, &mask, NULL)) {
+    SANDBOX_DIE("Failed to block SIGBUS");
+  }
+}
+
+bool IsDefaultSignalAction(const struct sigaction& sa) {
+  if (sa.sa_flags & SA_SIGINFO || sa.sa_handler != SIG_DFL) {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+Trap::Trap()
+    : trap_array_(NULL),
+      trap_array_size_(0),
+      trap_array_capacity_(0),
+      has_unsafe_traps_(false) {
+  // Set new SIGSYS handler
+  struct sigaction sa = {};
+  // In some toolchain, sa_sigaction is not declared in struct sigaction.
+  // So, here cast the pointer to the sa_handler's type. This works because
+  // |sa_handler| and |sa_sigaction| shares the same memory.
+  sa.sa_handler = reinterpret_cast<void (*)(int)>(SigSysAction);
+  sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER;
+  struct sigaction old_sa = {};
+  if (sys_sigaction(LINUX_SIGSYS, &sa, &old_sa) < 0) {
+    SANDBOX_DIE("Failed to configure SIGSYS handler");
+  }
+
+  if (!IsDefaultSignalAction(old_sa)) {
+    static const char kExistingSIGSYSMsg[] =
+        "Existing signal handler when trying to install SIGSYS. SIGSYS needs "
+        "to be reserved for seccomp-bpf.";
+    DLOG(FATAL) << kExistingSIGSYSMsg;
+    LOG(ERROR) << kExistingSIGSYSMsg;
+  }
+
+  // Unmask SIGSYS
+  sigset_t mask;
+  if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS) ||
+      sys_sigprocmask(LINUX_SIG_UNBLOCK, &mask, NULL)) {
+    SANDBOX_DIE("Failed to configure SIGSYS handler");
+  }
+}
+
+bpf_dsl::TrapRegistry* Trap::Registry() {
+  // Note: This class is not thread safe. It is the caller's responsibility
+  // to avoid race conditions. Normally, this is a non-issue as the sandbox
+  // can only be initialized if there are no other threads present.
+  // Also, this is not a normal singleton. Once created, the global trap
+  // object must never be destroyed again.
+  if (!global_trap_) {
+    global_trap_ = new Trap();
+    if (!global_trap_) {
+      SANDBOX_DIE("Failed to allocate global trap handler");
+    }
+  }
+  return global_trap_;
+}
+
+void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) {
+  if (info) {
+    MSAN_UNPOISON(info, sizeof(*info));
+  }
+
+  // Obtain the signal context. This, most notably, gives us access to
+  // all CPU registers at the time of the signal.
+  ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+  if (ctx) {
+    MSAN_UNPOISON(ctx, sizeof(*ctx));
+  }
+
+  if (!global_trap_) {
+    RAW_SANDBOX_DIE(
+        "This can't happen. Found no global singleton instance "
+        "for Trap() handling.");
+  }
+  global_trap_->SigSys(nr, info, ctx);
+}
+
+void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) {
+  // Signal handlers should always preserve "errno". Otherwise, we could
+  // trigger really subtle bugs.
+  const int old_errno = errno;
+
+  // Various sanity checks to make sure we actually received a signal
+  // triggered by a BPF filter. If something else triggered SIGSYS
+  // (e.g. kill()), there is really nothing we can do with this signal.
+  if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx ||
+      info->si_errno <= 0 ||
+      static_cast<size_t>(info->si_errno) > trap_array_size_) {
+    // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
+    // See crbug.com/178166.
+    // TODO(jln): add a DCHECK or move back to FATAL.
+    RAW_LOG(ERROR, "Unexpected SIGSYS received.");
+    errno = old_errno;
+    return;
+  }
+
+
+  // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
+  // most versions of glibc don't include this information in siginfo_t. So,
+  // we need to explicitly copy it into a arch_sigsys structure.
+  struct arch_sigsys sigsys;
+  memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
+
+#if defined(__mips__)
+  // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
+  // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
+  // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
+  bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) &&
+                          sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx));
+#else
+  bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx));
+#endif
+
+  // Some more sanity checks.
+  if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)) ||
+      sigsys_nr_is_bad || sigsys.arch != SECCOMP_ARCH) {
+    // TODO(markus):
+    // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
+    // safe and can lead to bugs. We should eventually implement a different
+    // logging and reporting mechanism that is safe to be called from
+    // the sigSys() handler.
+    RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.");
+  }
+
+  intptr_t rc;
+  if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) {
+    errno = old_errno;
+    if (sigsys.nr == __NR_clone) {
+      RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
+    }
+#if defined(__mips__)
+    // Mips supports up to eight arguments for syscall.
+    // However, seccomp bpf can filter only up to six arguments, so using eight
+    // arguments has sense only when using UnsafeTrap() handler.
+    rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+                       SECCOMP_PARM1(ctx),
+                       SECCOMP_PARM2(ctx),
+                       SECCOMP_PARM3(ctx),
+                       SECCOMP_PARM4(ctx),
+                       SECCOMP_PARM5(ctx),
+                       SECCOMP_PARM6(ctx),
+                       SECCOMP_PARM7(ctx),
+                       SECCOMP_PARM8(ctx));
+#else
+    rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+                       SECCOMP_PARM1(ctx),
+                       SECCOMP_PARM2(ctx),
+                       SECCOMP_PARM3(ctx),
+                       SECCOMP_PARM4(ctx),
+                       SECCOMP_PARM5(ctx),
+                       SECCOMP_PARM6(ctx));
+#endif  // defined(__mips__)
+  } else {
+    const TrapKey& trap = trap_array_[info->si_errno - 1];
+    if (!trap.safe) {
+      SetIsInSigHandler();
+    }
+
+    // Copy the seccomp-specific data into a arch_seccomp_data structure. This
+    // is what we are showing to TrapFnc callbacks that the system call
+    // evaluator registered with the sandbox.
+    struct arch_seccomp_data data = {
+        static_cast<int>(SECCOMP_SYSCALL(ctx)),
+        SECCOMP_ARCH,
+        reinterpret_cast<uint64_t>(sigsys.ip),
+        {static_cast<uint64_t>(SECCOMP_PARM1(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM2(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM3(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM4(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM5(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM6(ctx))}};
+
+    // Now call the TrapFnc callback associated with this particular instance
+    // of SECCOMP_RET_TRAP.
+    rc = trap.fnc(data, const_cast<void*>(trap.aux));
+  }
+
+  // Update the CPU register that stores the return code of the system call
+  // that we just handled, and restore "errno" to the value that it had
+  // before entering the signal handler.
+  Syscall::PutValueInUcontext(rc, ctx);
+  errno = old_errno;
+
+  return;
+}
+
+bool Trap::TrapKey::operator<(const TrapKey& o) const {
+  if (fnc != o.fnc) {
+    return fnc < o.fnc;
+  } else if (aux != o.aux) {
+    return aux < o.aux;
+  } else {
+    return safe < o.safe;
+  }
+}
+
+uint16_t Trap::Add(TrapFnc fnc, const void* aux, bool safe) {
+  if (!safe && !SandboxDebuggingAllowedByUser()) {
+    // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
+    // we never return an ErrorCode that is marked as "unsafe". This also
+    // means, the BPF compiler will never emit code that allow unsafe system
+    // calls to by-pass the filter (because they use the magic return address
+    // from Syscall::Call(-1)).
+
+    // This SANDBOX_DIE() can optionally be removed. It won't break security,
+    // but it might make error messages from the BPF compiler a little harder
+    // to understand. Removing the SANDBOX_DIE() allows callers to easily check
+    // whether unsafe traps are supported (by checking whether the returned
+    // ErrorCode is ET_INVALID).
+    SANDBOX_DIE(
+        "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
+        "is enabled");
+
+    return 0;
+  }
+
+  // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
+  // of a SECCOMP_RET_TRAP.
+  TrapKey key(fnc, aux, safe);
+
+  // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
+  // us to associate trap with the appropriate handler. The kernel allows us
+  // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
+  // avoid 0, as it could be confused for a trap without any specific id.
+  // The nice thing about sequentially numbered identifiers is that we can also
+  // trivially look them up from our signal handler without making any system
+  // calls that might be async-signal-unsafe.
+  // In order to do so, we store all of our traps in a C-style trap_array_.
+
+  TrapIds::const_iterator iter = trap_ids_.find(key);
+  if (iter != trap_ids_.end()) {
+    // We have seen this pair before. Return the same id that we assigned
+    // earlier.
+    return iter->second;
+  }
+
+  // This is a new pair. Remember it and assign a new id.
+  if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ ||
+      trap_array_size_ >= std::numeric_limits<uint16_t>::max()) {
+    // In practice, this is pretty much impossible to trigger, as there
+    // are other kernel limitations that restrict overall BPF program sizes.
+    SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
+  }
+
+  // Our callers ensure that there are no other threads accessing trap_array_
+  // concurrently (typically this is done by ensuring that we are single-
+  // threaded while the sandbox is being set up). But we nonetheless are
+  // modifying a live data structure that could be accessed any time a
+  // system call is made; as system calls could be triggering SIGSYS.
+  // So, we have to be extra careful that we update trap_array_ atomically.
+  // In particular, this means we shouldn't be using realloc() to resize it.
+  // Instead, we allocate a new array, copy the values, and then switch the
+  // pointer. We only really care about the pointer being updated atomically
+  // and the data that is pointed to being valid, as these are the only
+  // values accessed from the signal handler. It is OK if trap_array_size_
+  // is inconsistent with the pointer, as it is monotonously increasing.
+  // Also, we only care about compiler barriers, as the signal handler is
+  // triggered synchronously from a system call. We don't have to protect
+  // against issues with the memory model or with completely asynchronous
+  // events.
+  if (trap_array_size_ >= trap_array_capacity_) {
+    trap_array_capacity_ += kCapacityIncrement;
+    TrapKey* old_trap_array = trap_array_;
+    TrapKey* new_trap_array = new TrapKey[trap_array_capacity_];
+    std::copy_n(old_trap_array, trap_array_size_, new_trap_array);
+
+    // Language specs are unclear on whether the compiler is allowed to move
+    // the "delete[]" above our preceding assignments and/or memory moves,
+    // iff the compiler believes that "delete[]" doesn't have any other
+    // global side-effects.
+    // We insert optimization barriers to prevent this from happening.
+    // The first barrier is probably not needed, but better be explicit in
+    // what we want to tell the compiler.
+    // The clang developer mailing list couldn't answer whether this is a
+    // legitimate worry; but they at least thought that the barrier is
+    // sufficient to prevent the (so far hypothetical) problem of re-ordering
+    // of instructions by the compiler.
+    //
+    // TODO(mdempsky): Try to clean this up using base/atomicops or C++11
+    // atomics; see crbug.com/414363.
+    asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory");
+    trap_array_ = new_trap_array;
+    asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory");
+
+    delete[] old_trap_array;
+  }
+
+  uint16_t id = trap_array_size_ + 1;
+  trap_ids_[key] = id;
+  trap_array_[trap_array_size_] = key;
+  trap_array_size_++;
+  return id;
+}
+
+bool Trap::SandboxDebuggingAllowedByUser() {
+  const char* debug_flag = getenv(kSandboxDebuggingEnv);
+  return debug_flag && *debug_flag;
+}
+
+bool Trap::EnableUnsafeTraps() {
+  if (!has_unsafe_traps_) {
+    // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
+    // off again.
+    // We only allow enabling unsafe traps, if the user explicitly set an
+    // appropriate environment variable. This prevents bugs that accidentally
+    // disable all sandboxing for all users.
+    if (SandboxDebuggingAllowedByUser()) {
+      // We only ever print this message once, when we enable unsafe traps the
+      // first time.
+      SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes");
+      has_unsafe_traps_ = true;
+    } else {
+      SANDBOX_INFO(
+          "Cannot disable sandbox and use unsafe traps unless "
+          "CHROME_SANDBOX_DEBUGGING is turned on first");
+    }
+  }
+  // Returns the, possibly updated, value of has_unsafe_traps_.
+  return has_unsafe_traps_;
+}
+
+Trap* Trap::global_trap_;
+
+}  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/trap.h b/sandbox/linux/seccomp-bpf/trap.h
new file mode 100644
index 0000000..50ac3fd
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/trap.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 SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
+
+#include <stdint.h>
+
+#include <map>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// The Trap class allows a BPF filter program to branch out to user space by
+// raising a SIGSYS signal.
+// N.B.: This class does not perform any synchronization operations. If
+//   modifications are made to any of the traps, it is the caller's
+//   responsibility to ensure that this happens in a thread-safe fashion.
+//   Preferably, that means that no other threads should be running at that
+//   time. For the purposes of our sandbox, this assertion should always be
+//   true. Threads are incompatible with the seccomp sandbox anyway.
+class SANDBOX_EXPORT Trap : public bpf_dsl::TrapRegistry {
+ public:
+  uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override;
+
+  bool EnableUnsafeTraps() override;
+
+  // Registry returns the trap registry used by Trap's SIGSYS handler,
+  // creating it if necessary.
+  static bpf_dsl::TrapRegistry* Registry();
+
+  // SandboxDebuggingAllowedByUser returns whether the
+  // "CHROME_SANDBOX_DEBUGGING" environment variable is set.
+  static bool SandboxDebuggingAllowedByUser();
+
+ private:
+  struct TrapKey {
+    TrapKey() : fnc(NULL), aux(NULL), safe(false) {}
+    TrapKey(TrapFnc f, const void* a, bool s) : fnc(f), aux(a), safe(s) {}
+    TrapFnc fnc;
+    const void* aux;
+    bool safe;
+    bool operator<(const TrapKey&) const;
+  };
+  typedef std::map<TrapKey, uint16_t> TrapIds;
+
+  // Our constructor is private. A shared global instance is created
+  // automatically as needed.
+  Trap();
+
+  // The destructor is unimplemented as destroying this object would
+  // break subsequent system calls that trigger a SIGSYS.
+  ~Trap() = delete;
+
+  static void SigSysAction(int nr, LinuxSigInfo* info, void* void_context);
+
+  // Make sure that SigSys is not inlined in order to get slightly better crash
+  // dumps.
+  void SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx)
+      __attribute__((noinline));
+  // We have a global singleton that handles all of our SIGSYS traps. This
+  // variable must never be deallocated after it has been set up initially, as
+  // there is no way to reset in-kernel BPF filters that generate SIGSYS
+  // events.
+  static Trap* global_trap_;
+
+  TrapIds trap_ids_;            // Maps from TrapKeys to numeric ids
+  TrapKey* trap_array_;         // Array of TrapKeys indexed by ids
+  size_t trap_array_size_;      // Currently used size of array
+  size_t trap_array_capacity_;  // Currently allocated capacity of array
+  bool has_unsafe_traps_;       // Whether unsafe traps have been enabled
+
+  // Copying and assigning is unimplemented. It doesn't make sense for a
+  // singleton.
+  DISALLOW_COPY_AND_ASSIGN(Trap);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
diff --git a/sandbox/linux/seccomp-bpf/trap_unittest.cc b/sandbox/linux/seccomp-bpf/trap_unittest.cc
new file mode 100644
index 0000000..99f94bf
--- /dev/null
+++ b/sandbox/linux/seccomp-bpf/trap_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/trap.h"
+
+#include <signal.h>
+
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+SANDBOX_TEST_ALLOW_NOISE(Trap, SigSysAction) {
+  // This creates a global Trap instance, and registers the signal handler
+  // (Trap::SigSysAction).
+  Trap::Registry();
+
+  // Send SIGSYS to self. If signal handler (SigSysAction) is not registered,
+  // the process will be terminated with status code -SIGSYS.
+  // Note that, SigSysAction handler would output an error message
+  // "Unexpected SIGSYS received." so it is necessary to allow the noise.
+  raise(SIGSYS);
+}
+
+}  // namespace
+}  // namespace sandbox
diff --git a/sandbox/linux/services/DEPS b/sandbox/linux/services/DEPS
new file mode 100644
index 0000000..70d9b18
--- /dev/null
+++ b/sandbox/linux/services/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/system_headers",
+]
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
new file mode 100644
index 0000000..35bb4dc
--- /dev/null
+++ b/sandbox/linux/services/credentials.cc
@@ -0,0 +1,299 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/credentials.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/template_util.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace sandbox {
+
+namespace {
+
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
+// Checks that the set of RES-uids and the set of RES-gids have
+// one element each and return that element in |resuid| and |resgid|
+// respectively. It's ok to pass NULL as one or both of the ids.
+bool GetRESIds(uid_t* resuid, gid_t* resgid) {
+  uid_t ruid, euid, suid;
+  gid_t rgid, egid, sgid;
+  PCHECK(sys_getresuid(&ruid, &euid, &suid) == 0);
+  PCHECK(sys_getresgid(&rgid, &egid, &sgid) == 0);
+  const bool uids_are_equal = (ruid == euid) && (ruid == suid);
+  const bool gids_are_equal = (rgid == egid) && (rgid == sgid);
+  if (!uids_are_equal || !gids_are_equal) return false;
+  if (resuid) *resuid = euid;
+  if (resgid) *resgid = egid;
+  return true;
+}
+
+const int kExitSuccess = 0;
+
+int ChrootToSelfFdinfo(void*) {
+  RAW_CHECK(sys_chroot("/proc/self/fdinfo/") == 0);
+
+  // CWD is essentially an implicit file descriptor, so be careful to not
+  // leave it behind.
+  RAW_CHECK(chdir("/") == 0);
+  _exit(kExitSuccess);
+}
+
+// chroot() to an empty dir that is "safe". To be safe, it must not contain
+// any subdirectory (chroot-ing there would allow a chroot escape) and it must
+// be impossible to create an empty directory there.
+// We achieve this by doing the following:
+// 1. We create a new process sharing file system information.
+// 2. In the child, we chroot to /proc/self/fdinfo/
+// This is already "safe", since fdinfo/ does not contain another directory and
+// one cannot create another directory there.
+// 3. The process dies
+// After (3) happens, the directory is not available anymore in /proc.
+bool ChrootToSafeEmptyDir() {
+  // We need to chroot to a fdinfo that is unique to a process and have that
+  // process die.
+  // 1. We don't want to simply fork() because duplicating the page tables is
+  // slow with a big address space.
+  // 2. We do not use a regular thread (that would unshare CLONE_FILES) because
+  // when we are in a PID namespace, we cannot easily get a handle to the
+  // /proc/tid directory for the thread (since /proc may not be aware of the
+  // PID namespace). With a process, we can just use /proc/self.
+  pid_t pid = -1;
+  char stack_buf[PTHREAD_STACK_MIN];
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS64_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY)
+  // The stack grows downward.
+  void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+
+  pid = clone(ChrootToSelfFdinfo, stack,
+              CLONE_VM | CLONE_VFORK | CLONE_FS | LINUX_SIGCHLD, nullptr,
+              nullptr, nullptr, nullptr);
+  PCHECK(pid != -1);
+
+  int status = -1;
+  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
+
+  return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess;
+}
+
+// CHECK() that an attempt to move to a new user namespace raised an expected
+// errno.
+void CheckCloneNewUserErrno(int error) {
+  // EPERM can happen if already in a chroot. EUSERS if too many nested
+  // namespaces are used. EINVAL for kernels that don't support the feature.
+  // Valgrind will ENOSYS unshare().
+  PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
+         error == ENOSYS);
+}
+
+// Converts a Capability to the corresponding Linux CAP_XXX value.
+int CapabilityToKernelValue(Credentials::Capability cap) {
+  switch (cap) {
+    case Credentials::Capability::SYS_CHROOT:
+      return CAP_SYS_CHROOT;
+    case Credentials::Capability::SYS_ADMIN:
+      return CAP_SYS_ADMIN;
+  }
+
+  LOG(FATAL) << "Invalid Capability: " << static_cast<int>(cap);
+  return 0;
+}
+
+}  // namespace.
+
+// static
+bool Credentials::DropAllCapabilities(int proc_fd) {
+  if (!SetCapabilities(proc_fd, std::vector<Capability>())) {
+    return false;
+  }
+
+  CHECK(!HasAnyCapability());
+  return true;
+}
+
+// static
+bool Credentials::DropAllCapabilities() {
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+  return Credentials::DropAllCapabilities(proc_fd.get());
+}
+
+// static
+bool Credentials::DropAllCapabilitiesOnCurrentThread() {
+  return SetCapabilitiesOnCurrentThread(std::vector<Capability>());
+}
+
+// static
+bool Credentials::SetCapabilitiesOnCurrentThread(
+    const std::vector<Capability>& caps) {
+  struct cap_hdr hdr = {};
+  hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
+
+  // Initially, cap has no capability flags set. Enable the effective and
+  // permitted flags only for the requested capabilities.
+  for (const Capability cap : caps) {
+    const int cap_num = CapabilityToKernelValue(cap);
+    const size_t index = CAP_TO_INDEX(cap_num);
+    const uint32_t mask = CAP_TO_MASK(cap_num);
+    data[index].effective |= mask;
+    data[index].permitted |= mask;
+  }
+
+  return sys_capset(&hdr, data) == 0;
+}
+
+// static
+bool Credentials::SetCapabilities(int proc_fd,
+                                  const std::vector<Capability>& caps) {
+  DCHECK_LE(0, proc_fd);
+
+#if !defined(THREAD_SANITIZER)
+  // With TSAN, accept to break the security model as it is a testing
+  // configuration.
+  CHECK(ThreadHelpers::IsSingleThreaded(proc_fd));
+#endif
+
+  return SetCapabilitiesOnCurrentThread(caps);
+}
+
+bool Credentials::HasAnyCapability() {
+  struct cap_hdr hdr = {};
+  hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
+
+  PCHECK(sys_capget(&hdr, data) == 0);
+
+  for (size_t i = 0; i < arraysize(data); ++i) {
+    if (data[i].effective || data[i].permitted || data[i].inheritable) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool Credentials::HasCapability(Capability cap) {
+  struct cap_hdr hdr = {};
+  hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
+
+  PCHECK(sys_capget(&hdr, data) == 0);
+
+  const int cap_num = CapabilityToKernelValue(cap);
+  const size_t index = CAP_TO_INDEX(cap_num);
+  const uint32_t mask = CAP_TO_MASK(cap_num);
+
+  return (data[index].effective | data[index].permitted |
+          data[index].inheritable) &
+         mask;
+}
+
+// static
+bool Credentials::CanCreateProcessInNewUserNS() {
+  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
+  // so always consider UserNS unsupported there.
+  if (IsRunningOnValgrind()) {
+    return false;
+  }
+
+#if defined(THREAD_SANITIZER)
+  // With TSAN, processes will always have threads running and can never
+  // enter a new user namespace with MoveToNewUserNS().
+  return false;
+#endif
+
+  // This is roughly a fork().
+  const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0);
+
+  if (pid == -1) {
+    CheckCloneNewUserErrno(errno);
+    return false;
+  }
+
+  // The parent process could have had threads. In the child, these threads
+  // have disappeared. Make sure to not do anything in the child, as this is a
+  // fragile execution environment.
+  if (pid == 0) {
+    _exit(kExitSuccess);
+  }
+
+  // Always reap the child.
+  int status = -1;
+  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(kExitSuccess, WEXITSTATUS(status));
+
+  // clone(2) succeeded, we can use CLONE_NEWUSER.
+  return true;
+}
+
+bool Credentials::MoveToNewUserNS() {
+  uid_t uid;
+  gid_t gid;
+  if (!GetRESIds(&uid, &gid)) {
+    // If all the uids (or gids) are not equal to each other, the security
+    // model will most likely confuse the caller, abort.
+    DVLOG(1) << "uids or gids differ!";
+    return false;
+  }
+  int ret = sys_unshare(CLONE_NEWUSER);
+  if (ret) {
+    const int unshare_errno = errno;
+    VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
+            << "on this kernel.";
+    CheckCloneNewUserErrno(unshare_errno);
+    return false;
+  }
+
+  if (NamespaceUtils::KernelSupportsDenySetgroups()) {
+    PCHECK(NamespaceUtils::DenySetgroups());
+  }
+
+  // The current {r,e,s}{u,g}id is now an overflow id (c.f.
+  // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
+  DCHECK(GetRESIds(NULL, NULL));
+  const char kGidMapFile[] = "/proc/self/gid_map";
+  const char kUidMapFile[] = "/proc/self/uid_map";
+  PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
+  PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
+  DCHECK(GetRESIds(NULL, NULL));
+  return true;
+}
+
+bool Credentials::DropFileSystemAccess(int proc_fd) {
+  CHECK_LE(0, proc_fd);
+
+  CHECK(ChrootToSafeEmptyDir());
+  CHECK(!base::DirectoryExists(base::FilePath("/proc")));
+  CHECK(!ProcUtil::HasOpenDirectory(proc_fd));
+  // We never let this function fail.
+  return true;
+}
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/services/credentials.h b/sandbox/linux/services/credentials.h
new file mode 100644
index 0000000..0001dc7
--- /dev/null
+++ b/sandbox/linux/services/credentials.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_CREDENTIALS_H_
+#define SANDBOX_LINUX_SERVICES_CREDENTIALS_H_
+
+#include "build/build_config.h"
+// Link errors are tedious to track, raise a compile-time error instead.
+#if defined(OS_ANDROID)
+#error "Android is not supported."
+#endif  // defined(OS_ANDROID).
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This class should be used to manipulate the current process' credentials.
+// It is currently a stub used to manipulate POSIX.1e capabilities as
+// implemented by the Linux kernel.
+class SANDBOX_EXPORT Credentials {
+ public:
+  // For brevity, we only expose enums for the subset of capabilities we use.
+  // This can be expanded as the need arises.
+  enum class Capability {
+    SYS_CHROOT,
+    SYS_ADMIN,
+  };
+
+  // Drop all capabilities in the effective, inheritable and permitted sets for
+  // the current thread. For security reasons, since capabilities are
+  // per-thread, the caller is responsible for ensuring it is single-threaded
+  // when calling this API.
+  // |proc_fd| must be a file descriptor to /proc/ and remains owned by
+  // the caller.
+  static bool DropAllCapabilities(int proc_fd) WARN_UNUSED_RESULT;
+  // A similar API which assumes that it can open /proc/self/ by itself.
+  static bool DropAllCapabilities() WARN_UNUSED_RESULT;
+  // Sets the effective and permitted capability sets for the current thread to
+  // the list of capabiltiies in |caps|. All other capability flags are cleared.
+  static bool SetCapabilities(int proc_fd,
+                              const std::vector<Capability>& caps)
+      WARN_UNUSED_RESULT;
+
+  // Versions of the above functions which do not check that the process is
+  // single-threaded. After calling these functions, capabilities of other
+  // threads will not be changed. This is dangerous, do not use unless you nkow
+  // what you are doing.
+  static bool DropAllCapabilitiesOnCurrentThread() WARN_UNUSED_RESULT;
+  static bool SetCapabilitiesOnCurrentThread(
+      const std::vector<Capability>& caps) WARN_UNUSED_RESULT;
+
+  // Returns true if the current thread has either the effective, permitted, or
+  // inheritable flag set for the given capability.
+  static bool HasCapability(Capability cap);
+
+  // Return true iff there is any capability in any of the capabilities sets
+  // of the current thread.
+  static bool HasAnyCapability();
+
+  // Returns whether the kernel supports CLONE_NEWUSER and whether it would be
+  // possible to immediately move to a new user namespace. There is no point
+  // in using this method right before calling MoveToNewUserNS(), simply call
+  // MoveToNewUserNS() immediately. This method is only useful to test the
+  // ability to move to a user namespace ahead of time.
+  static bool CanCreateProcessInNewUserNS();
+
+  // Move the current process to a new "user namespace" as supported by Linux
+  // 3.8+ (CLONE_NEWUSER).
+  // The uid map will be set-up so that the perceived uid and gid will not
+  // change.
+  // If this call succeeds, the current process will be granted a full set of
+  // capabilities in the new namespace.
+  // This will fail if the process is not mono-threaded.
+  static bool MoveToNewUserNS() WARN_UNUSED_RESULT;
+
+  // Remove the ability of the process to access the file system. File
+  // descriptors which are already open prior to calling this API remain
+  // available.
+  // The implementation currently uses chroot(2) and requires CAP_SYS_CHROOT.
+  // CAP_SYS_CHROOT can be acquired by using the MoveToNewUserNS() API.
+  // |proc_fd| must be a file descriptor to /proc/ and must be the only open
+  // directory file descriptor of the process.
+  //
+  // CRITICAL:
+  //   - the caller must close |proc_fd| eventually or access to the file
+  // system can be recovered.
+  //   - DropAllCapabilities() must be called to prevent escapes.
+  static bool DropFileSystemAccess(int proc_fd) WARN_UNUSED_RESULT;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Credentials);
+};
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SERVICES_CREDENTIALS_H_
diff --git a/sandbox/linux/services/credentials_unittest.cc b/sandbox/linux/services/credentials_unittest.cc
new file mode 100644
index 0000000..6b93c86
--- /dev/null
+++ b/sandbox/linux/services/credentials_unittest.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/credentials.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+struct CapFreeDeleter {
+  inline void operator()(cap_t cap) const {
+    int ret = cap_free(cap);
+    CHECK_EQ(0, ret);
+  }
+};
+
+// Wrapper to manage libcap2's cap_t type.
+typedef scoped_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;
+
+bool WorkingDirectoryIsRoot() {
+  char current_dir[PATH_MAX];
+  char* cwd = getcwd(current_dir, sizeof(current_dir));
+  PCHECK(cwd);
+  if (strcmp("/", cwd)) return false;
+
+  // The current directory is the root. Add a few paranoid checks.
+  struct stat current;
+  CHECK_EQ(0, stat(".", &current));
+  struct stat parrent;
+  CHECK_EQ(0, stat("..", &parrent));
+  CHECK_EQ(current.st_dev, parrent.st_dev);
+  CHECK_EQ(current.st_ino, parrent.st_ino);
+  CHECK_EQ(current.st_mode, parrent.st_mode);
+  CHECK_EQ(current.st_uid, parrent.st_uid);
+  CHECK_EQ(current.st_gid, parrent.st_gid);
+  return true;
+}
+
+SANDBOX_TEST(Credentials, DropAllCaps) {
+  CHECK(Credentials::DropAllCapabilities());
+  CHECK(!Credentials::HasAnyCapability());
+}
+
+SANDBOX_TEST(Credentials, MoveToNewUserNS) {
+  CHECK(Credentials::DropAllCapabilities());
+  bool moved_to_new_ns = Credentials::MoveToNewUserNS();
+  fprintf(stdout,
+          "Unprivileged CLONE_NEWUSER supported: %s\n",
+          moved_to_new_ns ? "true." : "false.");
+  fflush(stdout);
+  if (!moved_to_new_ns) {
+    fprintf(stdout, "This kernel does not support unprivileged namespaces. "
+            "USERNS tests will succeed without running.\n");
+    fflush(stdout);
+    return;
+  }
+  CHECK(Credentials::HasAnyCapability());
+  CHECK(Credentials::DropAllCapabilities());
+  CHECK(!Credentials::HasAnyCapability());
+}
+
+SANDBOX_TEST(Credentials, CanCreateProcessInNewUserNS) {
+  CHECK(Credentials::DropAllCapabilities());
+  bool user_ns_supported = Credentials::CanCreateProcessInNewUserNS();
+  bool moved_to_new_ns = Credentials::MoveToNewUserNS();
+  CHECK_EQ(user_ns_supported, moved_to_new_ns);
+}
+
+SANDBOX_TEST(Credentials, UidIsPreserved) {
+  CHECK(Credentials::DropAllCapabilities());
+  uid_t old_ruid, old_euid, old_suid;
+  gid_t old_rgid, old_egid, old_sgid;
+  PCHECK(0 == getresuid(&old_ruid, &old_euid, &old_suid));
+  PCHECK(0 == getresgid(&old_rgid, &old_egid, &old_sgid));
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  uid_t new_ruid, new_euid, new_suid;
+  PCHECK(0 == getresuid(&new_ruid, &new_euid, &new_suid));
+  CHECK(old_ruid == new_ruid);
+  CHECK(old_euid == new_euid);
+  CHECK(old_suid == new_suid);
+
+  gid_t new_rgid, new_egid, new_sgid;
+  PCHECK(0 == getresgid(&new_rgid, &new_egid, &new_sgid));
+  CHECK(old_rgid == new_rgid);
+  CHECK(old_egid == new_egid);
+  CHECK(old_sgid == new_sgid);
+}
+
+bool NewUserNSCycle() {
+  if (!Credentials::MoveToNewUserNS() ||
+      !Credentials::HasAnyCapability() ||
+      !Credentials::DropAllCapabilities() ||
+      Credentials::HasAnyCapability()) {
+    return false;
+  }
+  return true;
+}
+
+SANDBOX_TEST(Credentials, NestedUserNS) {
+  CHECK(Credentials::DropAllCapabilities());
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropAllCapabilities());
+  // As of 3.12, the kernel has a limit of 32. See create_user_ns().
+  const int kNestLevel = 10;
+  for (int i = 0; i < kNestLevel; ++i) {
+    CHECK(NewUserNSCycle()) << "Creating new user NS failed at iteration "
+                                  << i << ".";
+  }
+}
+
+// Test the WorkingDirectoryIsRoot() helper.
+SANDBOX_TEST(Credentials, CanDetectRoot) {
+  PCHECK(0 == chdir("/proc/"));
+  CHECK(!WorkingDirectoryIsRoot());
+  PCHECK(0 == chdir("/"));
+  CHECK(WorkingDirectoryIsRoot());
+}
+
+// Disabled on ASAN because of crbug.com/451603.
+SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(DropFileSystemAccessIsSafe)) {
+  CHECK(Credentials::DropAllCapabilities());
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
+  CHECK(!base::DirectoryExists(base::FilePath("/proc")));
+  CHECK(WorkingDirectoryIsRoot());
+  CHECK(base::IsDirectoryEmpty(base::FilePath("/")));
+  // We want the chroot to never have a subdirectory. A subdirectory
+  // could allow a chroot escape.
+  CHECK_NE(0, mkdir("/test", 0700));
+}
+
+// Check that after dropping filesystem access and dropping privileges
+// it is not possible to regain capabilities.
+SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(CannotRegainPrivileges)) {
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+  CHECK(Credentials::DropAllCapabilities(proc_fd.get()));
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropFileSystemAccess(proc_fd.get()));
+  CHECK(Credentials::DropAllCapabilities(proc_fd.get()));
+
+  // The kernel should now prevent us from regaining capabilities because we
+  // are in a chroot.
+  CHECK(!Credentials::CanCreateProcessInNewUserNS());
+  CHECK(!Credentials::MoveToNewUserNS());
+}
+
+SANDBOX_TEST(Credentials, SetCapabilities) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS())
+    return;
+
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_ADMIN));
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
+
+  std::vector<Credentials::Capability> caps;
+  caps.push_back(Credentials::Capability::SYS_CHROOT);
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
+
+  CHECK(!Credentials::HasCapability(Credentials::Capability::SYS_ADMIN));
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
+
+  const std::vector<Credentials::Capability> no_caps;
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), no_caps));
+  CHECK(!Credentials::HasAnyCapability());
+}
+
+SANDBOX_TEST(Credentials, SetCapabilitiesAndChroot) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS())
+    return;
+
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
+  PCHECK(chroot("/") == 0);
+
+  std::vector<Credentials::Capability> caps;
+  caps.push_back(Credentials::Capability::SYS_CHROOT);
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
+  PCHECK(chroot("/") == 0);
+
+  CHECK(Credentials::DropAllCapabilities());
+  PCHECK(chroot("/") == -1 && errno == EPERM);
+}
+
+SANDBOX_TEST(Credentials, SetCapabilitiesMatchesLibCap2) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS())
+    return;
+
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+
+  std::vector<Credentials::Capability> caps;
+  caps.push_back(Credentials::Capability::SYS_CHROOT);
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
+
+  ScopedCap actual_cap(cap_get_proc());
+  PCHECK(actual_cap != nullptr);
+
+  ScopedCap expected_cap(cap_init());
+  PCHECK(expected_cap != nullptr);
+
+  const cap_value_t allowed_cap = CAP_SYS_CHROOT;
+  for (const cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) {
+    PCHECK(cap_set_flag(expected_cap.get(), flag, 1, &allowed_cap, CAP_SET) ==
+           0);
+  }
+
+  CHECK_EQ(0, cap_compare(expected_cap.get(), actual_cap.get()));
+}
+
+}  // namespace.
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/services/init_process_reaper.cc b/sandbox/linux/services/init_process_reaper.cc
new file mode 100644
index 0000000..2e0b90b
--- /dev/null
+++ b/sandbox/linux/services/init_process_reaper.cc
@@ -0,0 +1,101 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/init_process_reaper.h"
+
+#include <signal.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace sandbox {
+
+namespace {
+
+void DoNothingSignalHandler(int signal) {}
+
+}  // namespace
+
+bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) {
+  int sync_fds[2];
+  // We want to use send, so we can't use a pipe
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
+    PLOG(ERROR) << "Failed to create socketpair";
+    return false;
+  }
+  pid_t child_pid = fork();
+  if (child_pid == -1) {
+    int close_ret;
+    close_ret = IGNORE_EINTR(close(sync_fds[0]));
+    DPCHECK(!close_ret);
+    close_ret = IGNORE_EINTR(close(sync_fds[1]));
+    DPCHECK(!close_ret);
+    return false;
+  }
+  if (child_pid) {
+    // In the parent, assuming the role of an init process.
+    // The disposition for SIGCHLD cannot be SIG_IGN or wait() will only return
+    // once all of our childs are dead. Since we're init we need to reap childs
+    // as they come.
+    struct sigaction action;
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = &DoNothingSignalHandler;
+    CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
+
+    int close_ret;
+    close_ret = IGNORE_EINTR(close(sync_fds[0]));
+    DPCHECK(!close_ret);
+    close_ret = shutdown(sync_fds[1], SHUT_RD);
+    DPCHECK(!close_ret);
+    if (post_fork_parent_callback)
+      post_fork_parent_callback->Run();
+    // Tell the child to continue
+    CHECK(HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) == 1);
+    close_ret = IGNORE_EINTR(close(sync_fds[1]));
+    DPCHECK(!close_ret);
+
+    for (;;) {
+      // Loop until we have reaped our one natural child
+      siginfo_t reaped_child_info;
+      int wait_ret =
+          HANDLE_EINTR(waitid(P_ALL, 0, &reaped_child_info, WEXITED));
+      if (wait_ret)
+        _exit(1);
+      if (reaped_child_info.si_pid == child_pid) {
+        int exit_code = 0;
+        // We're done waiting
+        if (reaped_child_info.si_code == CLD_EXITED) {
+          exit_code = reaped_child_info.si_status;
+        }
+        // Exit with the same exit code as our parent. Exit with 0 if we got
+        // signaled.
+        _exit(exit_code);
+      }
+    }
+  } else {
+    // The child needs to wait for the parent to run the callback to avoid a
+    // race condition.
+    int close_ret;
+    close_ret = IGNORE_EINTR(close(sync_fds[1]));
+    DPCHECK(!close_ret);
+    close_ret = shutdown(sync_fds[0], SHUT_WR);
+    DPCHECK(!close_ret);
+    char should_continue;
+    int read_ret = HANDLE_EINTR(read(sync_fds[0], &should_continue, 1));
+    close_ret = IGNORE_EINTR(close(sync_fds[0]));
+    DPCHECK(!close_ret);
+    if (read_ret == 1)
+      return true;
+    else
+      return false;
+  }
+}
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/services/init_process_reaper.h b/sandbox/linux/services/init_process_reaper.h
new file mode 100644
index 0000000..840f6fc
--- /dev/null
+++ b/sandbox/linux/services/init_process_reaper.h
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_INIT_PROCESS_REAPER_H_
+#define SANDBOX_LINUX_SERVICES_INIT_PROCESS_REAPER_H_
+
+#include "base/callback_forward.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// The current process will fork(). The parent will become a process reaper
+// like init(1). The child will continue normally (after this function
+// returns).
+// If not NULL, |post_fork_parent_callback| will run in the parent almost
+// immediately after fork().
+// Since this function calls fork(), it's very important that the caller has
+// only one thread running.
+SANDBOX_EXPORT bool CreateInitProcessReaper(
+    base::Closure* post_fork_parent_callback);
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SERVICES_INIT_PROCESS_REAPER_H_
diff --git a/sandbox/linux/services/libc_urandom_override.cc b/sandbox/linux/services/libc_urandom_override.cc
new file mode 100644
index 0000000..33bb25d
--- /dev/null
+++ b/sandbox/linux/services/libc_urandom_override.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 "sandbox/linux/services/libc_urandom_override.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/rand_util.h"
+
+// Note: this file is used by the zygote and nacl_helper.
+
+#if !defined(HAVE_XSTAT) && defined(LIBC_GLIBC)
+#define HAVE_XSTAT 1
+#endif
+
+namespace sandbox {
+
+static bool g_override_urandom = false;
+
+// TODO(sergeyu): Currently InitLibcUrandomOverrides() doesn't work properly
+// under ASan or MSan - it crashes content_unittests. Make sure it works
+// properly and enable it here. http://crbug.com/123263
+#if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
+static void InitLibcFileIOFunctions();
+static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT;
+#endif
+
+void InitLibcUrandomOverrides() {
+  // Make sure /dev/urandom is open.
+  base::GetUrandomFD();
+  g_override_urandom = true;
+
+#if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
+  CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                           InitLibcFileIOFunctions));
+#endif
+}
+
+#if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
+
+static const char kUrandomDevPath[] = "/dev/urandom";
+
+typedef FILE* (*FopenFunction)(const char* path, const char* mode);
+
+static FopenFunction g_libc_fopen = NULL;
+static FopenFunction g_libc_fopen64 = NULL;
+
+#if HAVE_XSTAT
+typedef int (*XstatFunction)(int version, const char *path, struct stat *buf);
+typedef int (*Xstat64Function)(int version, const char *path,
+                               struct stat64 *buf);
+
+static XstatFunction g_libc_xstat = NULL;
+static Xstat64Function g_libc_xstat64 = NULL;
+#else
+typedef int (*StatFunction)(const char *path, struct stat *buf);
+typedef int (*Stat64Function)(const char *path, struct stat64 *buf);
+
+static StatFunction g_libc_stat = NULL;
+static Stat64Function g_libc_stat64 = NULL;
+#endif  // HAVE_XSTAT
+
+// Find the libc's real fopen* and *stat* functions. This should only be
+// called once, and should be guarded by g_libc_file_io_funcs_guard.
+static void InitLibcFileIOFunctions() {
+  g_libc_fopen = reinterpret_cast<FopenFunction>(
+      dlsym(RTLD_NEXT, "fopen"));
+  g_libc_fopen64 = reinterpret_cast<FopenFunction>(
+      dlsym(RTLD_NEXT, "fopen64"));
+
+  if (!g_libc_fopen) {
+    LOG(FATAL) << "Failed to get fopen() from libc.";
+  } else if (!g_libc_fopen64) {
+#if !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
+    LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead.";
+#endif  // !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
+    g_libc_fopen64 = g_libc_fopen;
+  }
+
+#if HAVE_XSTAT
+  g_libc_xstat = reinterpret_cast<XstatFunction>(
+      dlsym(RTLD_NEXT, "__xstat"));
+  g_libc_xstat64 = reinterpret_cast<Xstat64Function>(
+      dlsym(RTLD_NEXT, "__xstat64"));
+
+  if (!g_libc_xstat) {
+    LOG(FATAL) << "Failed to get __xstat() from libc.";
+  }
+  if (!g_libc_xstat64) {
+    LOG(FATAL) << "Failed to get __xstat64() from libc.";
+  }
+#else
+  g_libc_stat = reinterpret_cast<StatFunction>(
+      dlsym(RTLD_NEXT, "stat"));
+  g_libc_stat64 = reinterpret_cast<Stat64Function>(
+      dlsym(RTLD_NEXT, "stat64"));
+
+  if (!g_libc_stat) {
+    LOG(FATAL) << "Failed to get stat() from libc.";
+  }
+  if (!g_libc_stat64) {
+    LOG(FATAL) << "Failed to get stat64() from libc.";
+  }
+#endif  // HAVE_XSTAT
+}
+
+// fopen() and fopen64() are intercepted here so that NSS can open
+// /dev/urandom to seed its random number generator. NSS is used by
+// remoting in the sendbox.
+
+// fopen() call may be redirected to fopen64() in stdio.h using
+// __REDIRECT(), which sets asm name for fopen() to "fopen64". This
+// means that we cannot override fopen() directly here. Instead the
+// the code below defines fopen_override() function with asm name
+// "fopen", so that all references to fopen() will resolve to this
+// function.
+__attribute__ ((__visibility__("default")))
+FILE* fopen_override(const char* path, const char* mode)  __asm__ ("fopen");
+
+__attribute__ ((__visibility__("default")))
+FILE* fopen_override(const char* path, const char* mode) {
+  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
+    int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
+    if (fd < 0) {
+      PLOG(ERROR) << "dup() failed.";
+      return NULL;
+    }
+    return fdopen(fd, mode);
+  } else {
+    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                             InitLibcFileIOFunctions));
+    return g_libc_fopen(path, mode);
+  }
+}
+
+__attribute__ ((__visibility__("default")))
+FILE* fopen64(const char* path, const char* mode) {
+  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
+    int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
+    if (fd < 0) {
+      PLOG(ERROR) << "dup() failed.";
+      return NULL;
+    }
+    return fdopen(fd, mode);
+  } else {
+    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                             InitLibcFileIOFunctions));
+    return g_libc_fopen64(path, mode);
+  }
+}
+
+// The stat() family of functions are subject to the same problem as
+// fopen(), so we have to use the same trick to override them.
+
+#if HAVE_XSTAT
+
+__attribute__ ((__visibility__("default")))
+int xstat_override(int version,
+                   const char *path,
+                   struct stat *buf)  __asm__ ("__xstat");
+
+__attribute__ ((__visibility__("default")))
+int xstat_override(int version, const char *path, struct stat *buf) {
+  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
+    int result = __fxstat(version, base::GetUrandomFD(), buf);
+    return result;
+  } else {
+    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                             InitLibcFileIOFunctions));
+    return g_libc_xstat(version, path, buf);
+  }
+}
+
+__attribute__ ((__visibility__("default")))
+int xstat64_override(int version,
+                     const char *path,
+                     struct stat64 *buf)  __asm__ ("__xstat64");
+
+__attribute__ ((__visibility__("default")))
+int xstat64_override(int version, const char *path, struct stat64 *buf) {
+  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
+    int result = __fxstat64(version, base::GetUrandomFD(), buf);
+    return result;
+  } else {
+    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                             InitLibcFileIOFunctions));
+    return g_libc_xstat64(version, path, buf);
+  }
+}
+
+#else
+
+__attribute__ ((__visibility__("default")))
+int stat_override(const char *path,
+                  struct stat *buf)  __asm__ ("stat");
+
+__attribute__ ((__visibility__("default")))
+int stat_override(const char *path, struct stat *buf) {
+  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
+    int result = fstat(base::GetUrandomFD(), buf);
+    return result;
+  } else {
+    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                             InitLibcFileIOFunctions));
+    return g_libc_stat(path, buf);
+  }
+}
+
+__attribute__ ((__visibility__("default")))
+int stat64_override(const char *path,
+                    struct stat64 *buf)  __asm__ ("stat64");
+
+__attribute__ ((__visibility__("default")))
+int stat64_override(const char *path, struct stat64 *buf) {
+  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
+    int result = fstat64(base::GetUrandomFD(), buf);
+    return result;
+  } else {
+    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
+                             InitLibcFileIOFunctions));
+    return g_libc_stat64(path, buf);
+  }
+}
+
+#endif  // HAVE_XSTAT
+
+#endif  // !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
+
+}  // namespace content
diff --git a/sandbox/linux/services/libc_urandom_override.h b/sandbox/linux/services/libc_urandom_override.h
new file mode 100644
index 0000000..86212f8
--- /dev/null
+++ b/sandbox/linux/services/libc_urandom_override.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.
+
+#ifndef SANDBOX_LINUX_SERVICES_LIBC_URANDOM_OVERRIDE_H_
+#define SANDBOX_LINUX_SERVICES_LIBC_URANDOM_OVERRIDE_H_
+
+namespace sandbox {
+
+void InitLibcUrandomOverrides();
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_LIBC_URANDOM_OVERRIDE_H_
diff --git a/sandbox/linux/services/namespace_sandbox.cc b/sandbox/linux/services/namespace_sandbox.cc
new file mode 100644
index 0000000..2379644
--- /dev/null
+++ b/sandbox/linux/services/namespace_sandbox.cc
@@ -0,0 +1,208 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/namespace_sandbox.h"
+
+#include <sched.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+const char kSandboxUSERNSEnvironmentVarName[] = "SBX_USER_NS";
+const char kSandboxPIDNSEnvironmentVarName[] = "SBX_PID_NS";
+const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS";
+
+#if !defined(OS_NACL_NONSFI)
+class WriteUidGidMapDelegate : public base::LaunchOptions::PreExecDelegate {
+ public:
+  WriteUidGidMapDelegate()
+      : uid_(getuid()),
+        gid_(getgid()),
+        supports_deny_setgroups_(
+            NamespaceUtils::KernelSupportsDenySetgroups()) {}
+
+  ~WriteUidGidMapDelegate() override {}
+
+  void RunAsyncSafe() override {
+    if (supports_deny_setgroups_) {
+      RAW_CHECK(NamespaceUtils::DenySetgroups());
+    }
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/uid_map", uid_));
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/gid_map", gid_));
+  }
+
+ private:
+  const uid_t uid_;
+  const gid_t gid_;
+  const bool supports_deny_setgroups_;
+  DISALLOW_COPY_AND_ASSIGN(WriteUidGidMapDelegate);
+};
+
+void SetEnvironForNamespaceType(base::EnvironmentMap* environ,
+                                base::NativeEnvironmentString env_var,
+                                bool value) {
+  // An empty string causes the env var to be unset in the child process.
+  (*environ)[env_var] = value ? "1" : "";
+}
+
+// Linux supports up to 64 signals. This should be updated if that ever changes.
+int g_signal_exit_codes[64];
+
+void TerminationSignalHandler(int sig) {
+  // Return a special exit code so that the process is detected as terminated by
+  // a signal.
+  const size_t sig_idx = static_cast<size_t>(sig);
+  if (sig_idx < arraysize(g_signal_exit_codes)) {
+    _exit(g_signal_exit_codes[sig_idx]);
+  }
+
+  _exit(NamespaceSandbox::kDefaultExitCode);
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace
+
+#if !defined(OS_NACL_NONSFI)
+// static
+base::Process NamespaceSandbox::LaunchProcess(
+    const base::CommandLine& cmdline,
+    const base::LaunchOptions& options) {
+  return LaunchProcess(cmdline.argv(), options);
+}
+
+// static
+base::Process NamespaceSandbox::LaunchProcess(
+    const std::vector<std::string>& argv,
+    const base::LaunchOptions& options) {
+  int clone_flags = 0;
+  int ns_types[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET};
+  for (const int ns_type : ns_types) {
+    if (NamespaceUtils::KernelSupportsUnprivilegedNamespace(ns_type)) {
+      clone_flags |= ns_type;
+    }
+  }
+  CHECK(clone_flags & CLONE_NEWUSER);
+
+  // These fields may not be set by the caller.
+  CHECK(options.pre_exec_delegate == nullptr);
+  CHECK_EQ(0, options.clone_flags);
+
+  WriteUidGidMapDelegate write_uid_gid_map_delegate;
+
+  base::LaunchOptions launch_options = options;
+  launch_options.pre_exec_delegate = &write_uid_gid_map_delegate;
+  launch_options.clone_flags = clone_flags;
+
+  const std::pair<int, const char*> clone_flag_environ[] = {
+      std::make_pair(CLONE_NEWUSER, kSandboxUSERNSEnvironmentVarName),
+      std::make_pair(CLONE_NEWPID, kSandboxPIDNSEnvironmentVarName),
+      std::make_pair(CLONE_NEWNET, kSandboxNETNSEnvironmentVarName),
+  };
+
+  base::EnvironmentMap* environ = &launch_options.environ;
+  for (const auto& entry : clone_flag_environ) {
+    const int flag = entry.first;
+    const char* environ_name = entry.second;
+    SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag);
+  }
+
+  return base::LaunchProcess(argv, launch_options);
+}
+
+// static
+pid_t NamespaceSandbox::ForkInNewPidNamespace(bool drop_capabilities_in_child) {
+  const pid_t pid =
+      base::ForkWithFlags(CLONE_NEWPID | SIGCHLD, nullptr, nullptr);
+  if (pid < 0) {
+    return pid;
+  }
+
+  if (pid == 0) {
+    DCHECK_EQ(1, getpid());
+    if (drop_capabilities_in_child) {
+      // Since we just forked, we are single-threaded, so this should be safe.
+      CHECK(Credentials::DropAllCapabilitiesOnCurrentThread());
+    }
+    return 0;
+  }
+
+  return pid;
+}
+
+// static
+void NamespaceSandbox::InstallDefaultTerminationSignalHandlers() {
+  static const int kDefaultTermSignals[] = {
+      SIGHUP, SIGINT, SIGABRT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2,
+  };
+
+  for (const int sig : kDefaultTermSignals) {
+    InstallTerminationSignalHandler(sig, kDefaultExitCode);
+  }
+}
+
+// static
+bool NamespaceSandbox::InstallTerminationSignalHandler(
+    int sig,
+    int exit_code) {
+  struct sigaction old_action;
+  PCHECK(sigaction(sig, nullptr, &old_action) == 0);
+
+  if (old_action.sa_flags & SA_SIGINFO &&
+      old_action.sa_sigaction != nullptr) {
+    return false;
+  } else if (old_action.sa_handler != SIG_DFL) {
+    return false;
+  }
+
+  const size_t sig_idx = static_cast<size_t>(sig);
+  CHECK_LT(sig_idx, arraysize(g_signal_exit_codes));
+
+  DCHECK_GE(exit_code, 0);
+  DCHECK_LT(exit_code, 256);
+
+  g_signal_exit_codes[sig_idx] = exit_code;
+
+  struct sigaction action = {};
+  action.sa_handler = &TerminationSignalHandler;
+  PCHECK(sigaction(sig, &action, nullptr) == 0);
+  return true;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+// static
+bool NamespaceSandbox::InNewUserNamespace() {
+  return getenv(kSandboxUSERNSEnvironmentVarName) != nullptr;
+}
+
+// static
+bool NamespaceSandbox::InNewPidNamespace() {
+  return getenv(kSandboxPIDNSEnvironmentVarName) != nullptr;
+}
+
+// static
+bool NamespaceSandbox::InNewNetNamespace() {
+  return getenv(kSandboxNETNSEnvironmentVarName) != nullptr;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/namespace_sandbox.h b/sandbox/linux/services/namespace_sandbox.h
new file mode 100644
index 0000000..80097fb
--- /dev/null
+++ b/sandbox/linux/services/namespace_sandbox.h
@@ -0,0 +1,101 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
+#define SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
+
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Helper class for starting a process inside a new user, PID, and network
+// namespace. Before using a namespace sandbox, check for namespaces support
+// using Credentials::CanCreateProcessInNewUserNS.
+//
+// A typical use for "A" launching a sandboxed process "B" would be:
+// 1. A sets up a command line and launch options for process B.
+// 2. A launches B with LaunchProcess.
+// 3. B should be prepared to assume the role of init(1). In particular, apart
+//    from SIGKILL and SIGSTOP, B cannot receive any signal for which it does
+//    not have an explicit signal handler registered.
+//    If B dies, all the processes in the namespace will die.
+//    B can fork() and the parent can assume the role of init(1), by using
+//    CreateInitProcessReaper().
+// 4. B chroots using Credentials::MoveToNewUserNS() and
+//    Credentials::DropFileSystemAccess()
+// 5. B drops capabilities gained by entering the new user namespace with
+//    Credentials::DropAllCapabilities().
+class SANDBOX_EXPORT NamespaceSandbox {
+ public:
+#if !defined(OS_NACL_NONSFI)
+  static const int kDefaultExitCode = 1;
+
+  // Launch a new process inside its own user/PID/network namespaces (depending
+  // on kernel support). Requires at a minimum that user namespaces are
+  // supported (use Credentials::CanCreateProcessInNewUserNS to check this).
+  //
+  // pre_exec_delegate and clone_flags fields of LaunchOptions should be nullptr
+  // and 0, respectively, since this function makes a copy of options and
+  // overrides them.
+  static base::Process LaunchProcess(const base::CommandLine& cmdline,
+                                     const base::LaunchOptions& options);
+  static base::Process LaunchProcess(const std::vector<std::string>& argv,
+                                     const base::LaunchOptions& options);
+
+  // Forks a process in its own PID namespace. The child process is the init
+  // process inside of the PID namespace, so if the child needs to fork further,
+  // it should call CreateInitProcessReaper, which turns the init process into a
+  // reaper process.
+  //
+  // Otherwise, the child should setup handlers for signals which should
+  // terminate the process using InstallDefaultTerminationSignalHandlers or
+  // InstallTerminationSignalHandler. This works around the fact that init
+  // processes ignore such signals unless they have an explicit handler set.
+  //
+  // This function requries CAP_SYS_ADMIN. If |drop_capabilities_in_child| is
+  // true, then capabilities are dropped in the child.
+  static pid_t ForkInNewPidNamespace(bool drop_capabilities_in_child);
+
+  // Installs a signal handler for:
+  //
+  // SIGHUP, SIGINT, SIGABRT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
+  //
+  // that exits with kDefaultExitCode. These are signals whose default action is
+  // to terminate the program (apart from SIGILL, SIGFPE, and SIGSEGV, which
+  // will still terminate the process if e.g. an illegal instruction is
+  // encountered, etc.).
+  //
+  // If any of these already had a signal handler installed, this function will
+  // not override them.
+  static void InstallDefaultTerminationSignalHandlers();
+
+  // Installs a signal handler for |sig| which exits with |exit_code|. If a
+  // signal handler was already present for |sig|, does nothing and returns
+  // false.
+  static bool InstallTerminationSignalHandler(int sig, int exit_code);
+#endif  // !defined(OS_NACL_NONSFI)
+
+  // Returns whether the namespace sandbox created a new user, PID, and network
+  // namespace. In particular, InNewUserNamespace should return true iff the
+  // process was started via this class.
+  static bool InNewUserNamespace();
+  static bool InNewPidNamespace();
+  static bool InNewNetNamespace();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceSandbox);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
diff --git a/sandbox/linux/services/namespace_sandbox_unittest.cc b/sandbox/linux/services/namespace_sandbox_unittest.cc
new file mode 100644
index 0000000..547ef67
--- /dev/null
+++ b/sandbox/linux/services/namespace_sandbox_unittest.cc
@@ -0,0 +1,217 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/namespace_sandbox.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "base/test/multiprocess_test.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace sandbox {
+
+namespace {
+
+bool RootDirectoryIsEmpty() {
+  base::FilePath root("/");
+  int file_type =
+      base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES;
+  base::FileEnumerator enumerator_before(root, false, file_type);
+  return enumerator_before.Next().empty();
+}
+
+class NamespaceSandboxTest : public base::MultiProcessTest {
+ public:
+  void TestProc(const std::string& procname) {
+    if (!Credentials::CanCreateProcessInNewUserNS()) {
+      return;
+    }
+
+    base::FileHandleMappingVector fds_to_remap = {
+        std::make_pair(STDOUT_FILENO, STDOUT_FILENO),
+        std::make_pair(STDERR_FILENO, STDERR_FILENO),
+    };
+    base::LaunchOptions launch_options;
+    launch_options.fds_to_remap = &fds_to_remap;
+
+    base::Process process =
+        NamespaceSandbox::LaunchProcess(MakeCmdLine(procname), launch_options);
+    ASSERT_TRUE(process.IsValid());
+
+    const int kDummyExitCode = 42;
+    int exit_code = kDummyExitCode;
+    EXPECT_TRUE(process.WaitForExit(&exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+};
+
+MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  bool in_user_ns = NamespaceSandbox::InNewUserNamespace();
+  bool in_pid_ns = NamespaceSandbox::InNewPidNamespace();
+  bool in_net_ns = NamespaceSandbox::InNewNetNamespace();
+  CHECK(in_user_ns);
+  CHECK_EQ(in_pid_ns,
+           NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID));
+  CHECK_EQ(in_net_ns,
+           NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWNET));
+  if (in_pid_ns) {
+    CHECK_EQ(1, getpid());
+  }
+  return 0;
+}
+
+TEST_F(NamespaceSandboxTest, BasicUsage) {
+  TestProc("SimpleChildProcess");
+}
+
+MULTIPROCESS_TEST_MAIN(ChrootMe) {
+  CHECK(!RootDirectoryIsEmpty());
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  CHECK(sandbox::Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
+  CHECK(RootDirectoryIsEmpty());
+  return 0;
+}
+
+// Temporarily disabled on ASAN due to crbug.com/451603.
+TEST_F(NamespaceSandboxTest, DISABLE_ON_ASAN(ChrootAndDropCapabilities)) {
+  TestProc("ChrootMe");
+}
+
+MULTIPROCESS_TEST_MAIN(NestedNamespaceSandbox) {
+  base::FileHandleMappingVector fds_to_remap = {
+      std::make_pair(STDOUT_FILENO, STDOUT_FILENO),
+      std::make_pair(STDERR_FILENO, STDERR_FILENO),
+  };
+  base::LaunchOptions launch_options;
+  launch_options.fds_to_remap = &fds_to_remap;
+  base::Process process = NamespaceSandbox::LaunchProcess(
+      base::CommandLine(base::FilePath("/bin/true")), launch_options);
+  CHECK(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  CHECK(process.WaitForExit(&exit_code));
+  CHECK_EQ(0, exit_code);
+  return 0;
+}
+
+TEST_F(NamespaceSandboxTest, NestedNamespaceSandbox) {
+  TestProc("NestedNamespaceSandbox");
+}
+
+const int kNormalExitCode = 0;
+const int kSignalTerminationExitCode = 255;
+
+// Ensure that CHECK(false) is distinguishable from _exit(kNormalExitCode).
+// Allowing noise since CHECK(false) will write a stack trace to stderr.
+SANDBOX_TEST_ALLOW_NOISE(ForkInNewPidNamespace, CheckDoesNotReturnZero) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
+      /*drop_capabilities_in_child=*/true);
+  CHECK_GE(pid, 0);
+
+  if (pid == 0) {
+    CHECK(false);
+    _exit(kNormalExitCode);
+  }
+
+  int status;
+  PCHECK(waitpid(pid, &status, 0) == pid);
+  if (WIFEXITED(status)) {
+    CHECK_NE(kNormalExitCode, WEXITSTATUS(status));
+  }
+}
+
+SANDBOX_TEST(ForkInNewPidNamespace, BasicUsage) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
+      /*drop_capabilities_in_child=*/true);
+  CHECK_GE(pid, 0);
+
+  if (pid == 0) {
+    CHECK_EQ(1, getpid());
+    CHECK(!Credentials::HasAnyCapability());
+    _exit(kNormalExitCode);
+  }
+
+  int status;
+  PCHECK(waitpid(pid, &status, 0) == pid);
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(kNormalExitCode, WEXITSTATUS(status));
+}
+
+SANDBOX_TEST(ForkInNewPidNamespace, ExitWithSignal) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
+      /*drop_capabilities_in_child=*/true);
+  CHECK_GE(pid, 0);
+
+  if (pid == 0) {
+    CHECK_EQ(1, getpid());
+    CHECK(!Credentials::HasAnyCapability());
+    CHECK(NamespaceSandbox::InstallTerminationSignalHandler(
+        SIGTERM, kSignalTerminationExitCode));
+    while (true) {
+      raise(SIGTERM);
+    }
+  }
+
+  int status;
+  PCHECK(waitpid(pid, &status, 0) == pid);
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(kSignalTerminationExitCode, WEXITSTATUS(status));
+}
+
+volatile sig_atomic_t signal_handler_called;
+void ExitSuccessfully(int sig) {
+  signal_handler_called = 1;
+}
+
+SANDBOX_TEST(InstallTerminationSignalHandler, DoesNotOverrideExistingHandlers) {
+  struct sigaction action = {};
+  action.sa_handler = &ExitSuccessfully;
+  PCHECK(sigaction(SIGUSR1, &action, nullptr) == 0);
+
+  NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
+  CHECK(!NamespaceSandbox::InstallTerminationSignalHandler(
+            SIGUSR1, kSignalTerminationExitCode));
+
+  raise(SIGUSR1);
+  CHECK_EQ(1, signal_handler_called);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/namespace_utils.cc b/sandbox/linux/services/namespace_utils.cc
new file mode 100644
index 0000000..82a5444
--- /dev/null
+++ b/sandbox/linux/services/namespace_utils.cc
@@ -0,0 +1,117 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/namespace_utils.h"
+
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/strings/safe_sprintf.h"
+#include "base/third_party/valgrind/valgrind.h"
+
+namespace sandbox {
+
+namespace {
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+const char kProcSelfSetgroups[] = "/proc/self/setgroups";
+}  // namespace
+
+// static
+bool NamespaceUtils::WriteToIdMapFile(const char* map_file, generic_id_t id) {
+  // This function needs to be async-signal-safe, as it may be called in between
+  // fork and exec.
+
+  int fd = HANDLE_EINTR(open(map_file, O_WRONLY));
+  if (fd == -1) {
+    return false;
+  }
+
+  const generic_id_t inside_id = id;
+  const generic_id_t outside_id = id;
+
+  char mapping[64];
+  const ssize_t len =
+      base::strings::SafeSPrintf(mapping, "%d %d 1\n", inside_id, outside_id);
+  const ssize_t rc = HANDLE_EINTR(write(fd, mapping, len));
+  RAW_CHECK(IGNORE_EINTR(close(fd)) == 0);
+  return rc == len;
+}
+
+// static
+bool NamespaceUtils::KernelSupportsUnprivilegedNamespace(int type) {
+  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
+  // so always consider namespaces unsupported there.
+  if (IsRunningOnValgrind()) {
+    return false;
+  }
+
+  // As of Linux 3.8, /proc/self/ns/* files exist for all namespace types. Since
+  // user namespaces were added in 3.8, it is OK to rely on the existence of
+  // /proc/self/ns/*.
+  if (!base::PathExists(base::FilePath("/proc/self/ns/user"))) {
+    return false;
+  }
+
+  const char* path;
+  switch (type) {
+    case CLONE_NEWUSER:
+      return true;
+    case CLONE_NEWIPC:
+      path = "/proc/self/ns/ipc";
+      break;
+    case CLONE_NEWNET:
+      path = "/proc/self/ns/net";
+      break;
+    case CLONE_NEWNS:
+      path = "/proc/self/ns/mnt";
+      break;
+    case CLONE_NEWPID:
+      path = "/proc/self/ns/pid";
+      break;
+    case CLONE_NEWUTS:
+      path = "/proc/self/ns/uts";
+      break;
+    default:
+      NOTREACHED();
+      return false;
+  }
+
+  return base::PathExists(base::FilePath(path));
+}
+
+// static
+bool NamespaceUtils::KernelSupportsDenySetgroups() {
+  return base::PathExists(base::FilePath(kProcSelfSetgroups));
+}
+
+// static
+bool NamespaceUtils::DenySetgroups() {
+  // This function needs to be async-signal-safe.
+  int fd = HANDLE_EINTR(open(kProcSelfSetgroups, O_WRONLY));
+  if (fd == -1) {
+    return false;
+  }
+
+  static const char kDeny[] = "deny";
+  const ssize_t len = sizeof(kDeny) - 1;
+  const ssize_t rc = HANDLE_EINTR(write(fd, kDeny, len));
+  RAW_CHECK(IGNORE_EINTR(close(fd)) == 0);
+  return rc == len;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/namespace_utils.h b/sandbox/linux/services/namespace_utils.h
new file mode 100644
index 0000000..f3c88a9
--- /dev/null
+++ b/sandbox/linux/services/namespace_utils.h
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_NAMESPACE_UTILS_H_
+#define SANDBOX_LINUX_SERVICES_NAMESPACE_UTILS_H_
+
+#include <sys/types.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/template_util.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Utility functions for using Linux namepaces.
+class SANDBOX_EXPORT NamespaceUtils {
+ public:
+  COMPILE_ASSERT((base::is_same<uid_t, gid_t>::value), UidAndGidAreSameType);
+  // generic_id_t can be used for either uid_t or gid_t.
+  typedef uid_t generic_id_t;
+
+  // Write a uid or gid mapping from |id| to |id| in |map_file|. This function
+  // is async-signal-safe.
+  static bool WriteToIdMapFile(const char* map_file,
+                               generic_id_t id) WARN_UNUSED_RESULT;
+
+  // Returns true if unprivileged namespaces of type |type| is supported
+  // (meaning that both CLONE_NEWUSER and type are are supported).  |type| must
+  // be one of CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID,
+  // CLONE_NEWUSER, or CLONE_NEWUTS. This relies on access to /proc, so it will
+  // not work from within a sandbox.
+  static bool KernelSupportsUnprivilegedNamespace(int type);
+
+  // Returns true if the kernel supports denying setgroups in a user namespace.
+  // On kernels where this is supported, DenySetgroups must be called before a
+  // gid mapping can be added.
+  static bool KernelSupportsDenySetgroups();
+
+  // Disables setgroups() within the current user namespace. On Linux 3.18.2 and
+  // later, this is required in order to write to /proc/self/gid_map without
+  // having CAP_SETGID. Callers can determine whether is this needed with
+  // KernelSupportsDenySetgroups. This function is async-signal-safe.
+  static bool DenySetgroups() WARN_UNUSED_RESULT;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceUtils);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_NAMESPACE_UTILS_H_
diff --git a/sandbox/linux/services/namespace_utils_unittest.cc b/sandbox/linux/services/namespace_utils_unittest.cc
new file mode 100644
index 0000000..41ed7e8
--- /dev/null
+++ b/sandbox/linux/services/namespace_utils_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/namespace_utils.h"
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+SANDBOX_TEST(NamespaceUtils, KernelSupportsUnprivilegedNamespace) {
+  const bool can_create_user_ns = Credentials::CanCreateProcessInNewUserNS();
+  const bool supports_user_ns =
+      NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWUSER);
+  // can_create_user_ns implies supports_user_ns, but the converse is not
+  // necessarily true, as creating a user namespace can fail for various
+  // reasons.
+  if (can_create_user_ns) {
+    SANDBOX_ASSERT(supports_user_ns);
+  }
+}
+
+SANDBOX_TEST(NamespaceUtils, WriteToIdMapFile) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  const uid_t uid = getuid();
+  const gid_t gid = getgid();
+
+  const bool supports_deny_setgroups =
+      NamespaceUtils::KernelSupportsDenySetgroups();
+
+  const pid_t pid =
+      base::ForkWithFlags(CLONE_NEWUSER | SIGCHLD, nullptr, nullptr);
+  ASSERT_NE(-1, pid);
+  if (pid == 0) {
+    if (supports_deny_setgroups) {
+      RAW_CHECK(NamespaceUtils::DenySetgroups());
+    }
+
+    RAW_CHECK(getuid() != uid);
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/uid_map", uid));
+    RAW_CHECK(getuid() == uid);
+
+    RAW_CHECK(getgid() != gid);
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/gid_map", gid));
+    RAW_CHECK(getgid() == gid);
+
+    _exit(0);
+  }
+
+  int status = 42;
+  SANDBOX_ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  SANDBOX_ASSERT_EQ(0, status);
+}
+
+}  // namespace.
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/services/proc_util.cc b/sandbox/linux/services/proc_util.cc
new file mode 100644
index 0000000..d3f755f
--- /dev/null
+++ b/sandbox/linux/services/proc_util.cc
@@ -0,0 +1,119 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/proc_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace sandbox {
+namespace {
+
+struct DIRCloser {
+  void operator()(DIR* d) const {
+    DCHECK(d);
+    PCHECK(0 == closedir(d));
+  }
+};
+
+typedef scoped_ptr<DIR, DIRCloser> ScopedDIR;
+
+base::ScopedFD OpenDirectory(const char* path) {
+  DCHECK(path);
+  base::ScopedFD directory_fd(
+      HANDLE_EINTR(open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
+  PCHECK(directory_fd.is_valid());
+  return directory_fd.Pass();
+}
+
+}  // namespace
+
+int ProcUtil::CountOpenFds(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  int proc_self_fd = HANDLE_EINTR(
+      openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+  PCHECK(0 <= proc_self_fd);
+
+  // Ownership of proc_self_fd is transferred here, it must not be closed
+  // or modified afterwards except via dir.
+  ScopedDIR dir(fdopendir(proc_self_fd));
+  CHECK(dir);
+
+  int count = 0;
+  struct dirent e;
+  struct dirent* de;
+  while (!readdir_r(dir.get(), &e, &de) && de) {
+    if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
+      continue;
+    }
+
+    int fd_num;
+    CHECK(base::StringToInt(e.d_name, &fd_num));
+    if (fd_num == proc_fd || fd_num == proc_self_fd) {
+      continue;
+    }
+
+    ++count;
+  }
+  return count;
+}
+
+bool ProcUtil::HasOpenDirectory(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  int proc_self_fd =
+      openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+
+  PCHECK(0 <= proc_self_fd);
+
+  // Ownership of proc_self_fd is transferred here, it must not be closed
+  // or modified afterwards except via dir.
+  ScopedDIR dir(fdopendir(proc_self_fd));
+  CHECK(dir);
+
+  struct dirent e;
+  struct dirent* de;
+  while (!readdir_r(dir.get(), &e, &de) && de) {
+    if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
+      continue;
+    }
+
+    int fd_num;
+    CHECK(base::StringToInt(e.d_name, &fd_num));
+    if (fd_num == proc_fd || fd_num == proc_self_fd) {
+      continue;
+    }
+
+    struct stat s;
+    // It's OK to use proc_self_fd here, fstatat won't modify it.
+    CHECK(fstatat(proc_self_fd, e.d_name, &s, 0) == 0);
+    if (S_ISDIR(s.st_mode)) {
+      return true;
+    }
+  }
+
+  // No open unmanaged directories found.
+  return false;
+}
+
+bool ProcUtil::HasOpenDirectory() {
+  base::ScopedFD proc_fd(
+      HANDLE_EINTR(open("/proc/", O_DIRECTORY | O_RDONLY | O_CLOEXEC)));
+  return HasOpenDirectory(proc_fd.get());
+}
+
+//static
+base::ScopedFD ProcUtil::OpenProc() {
+  return OpenDirectory("/proc/");
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/proc_util.h b/sandbox/linux/services/proc_util.h
new file mode 100644
index 0000000..bc14c5e
--- /dev/null
+++ b/sandbox/linux/services/proc_util.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_PROC_UTIL_H_
+#define SANDBOX_LINUX_SERVICES_PROC_UTIL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+class SANDBOX_EXPORT ProcUtil {
+ public:
+  // Returns the number of file descriptors in the current process's FD
+  // table, excluding |proc_fd|, which should be a file descriptor for
+  // /proc/.
+  static int CountOpenFds(int proc_fd);
+
+  // Checks whether the current process has any directory file descriptor open.
+  // Directory file descriptors are "capabilities" that would let a process use
+  // system calls such as openat() to bypass restrictions such as
+  // DropFileSystemAccess().
+  // Sometimes it's useful to call HasOpenDirectory() after file system access
+  // has been dropped. In this case, |proc_fd| should be a file descriptor to
+  // /proc/. The file descriptor in |proc_fd| will be ignored by
+  // HasOpenDirectory() and remains owned by the caller. It is very important
+  // for the caller to close it.
+  static bool HasOpenDirectory(int proc_fd) WARN_UNUSED_RESULT;
+  static bool HasOpenDirectory() WARN_UNUSED_RESULT;
+
+  // Open /proc/ or crash if not possible.
+  static base::ScopedFD OpenProc();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ProcUtil);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_PROC_UTIL_H_
diff --git a/sandbox/linux/services/proc_util_unittest.cc b/sandbox/linux/services/proc_util_unittest.cc
new file mode 100644
index 0000000..bf25151
--- /dev/null
+++ b/sandbox/linux/services/proc_util_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/proc_util.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/files/scoped_file.h"
+#include "base/posix/eintr_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+TEST(ProcUtil, CountOpenFds) {
+  base::ScopedFD proc_fd(open("/proc/", O_RDONLY | O_DIRECTORY));
+  ASSERT_TRUE(proc_fd.is_valid());
+  int fd_count = ProcUtil::CountOpenFds(proc_fd.get());
+  int fd = open("/dev/null", O_RDONLY);
+  ASSERT_LE(0, fd);
+  EXPECT_EQ(fd_count + 1, ProcUtil::CountOpenFds(proc_fd.get()));
+  ASSERT_EQ(0, IGNORE_EINTR(close(fd)));
+  EXPECT_EQ(fd_count, ProcUtil::CountOpenFds(proc_fd.get()));
+}
+
+TEST(ProcUtil, HasOpenDirectory) {
+  // No open directory should exist at startup.
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory());
+  {
+    // Have a "/proc" file descriptor around.
+    int proc_fd = open("/proc/", O_RDONLY | O_DIRECTORY);
+    base::ScopedFD proc_fd_closer(proc_fd);
+    EXPECT_TRUE(ProcUtil::HasOpenDirectory());
+  }
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory());
+}
+
+TEST(ProcUtil, HasOpenDirectoryWithFD) {
+  int proc_fd = open("/proc/", O_RDONLY | O_DIRECTORY);
+  base::ScopedFD proc_fd_closer(proc_fd);
+  ASSERT_LE(0, proc_fd);
+
+  // Don't pass |proc_fd|, an open directory (proc_fd) should
+  // be detected.
+  EXPECT_TRUE(ProcUtil::HasOpenDirectory());
+  // Pass |proc_fd| and no open directory should be detected.
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory(proc_fd));
+
+  {
+    // Have a directory file descriptor around.
+    int open_directory_fd = open("/proc/self/", O_RDONLY | O_DIRECTORY);
+    base::ScopedFD open_directory_fd_closer(open_directory_fd);
+    EXPECT_TRUE(ProcUtil::HasOpenDirectory(proc_fd));
+  }
+
+  // The "/proc/" file descriptor should now be closed, |proc_fd| is the
+  // only directory file descriptor open.
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory(proc_fd));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/resource_limits.cc b/sandbox/linux/services/resource_limits.cc
new file mode 100644
index 0000000..1ec1129
--- /dev/null
+++ b/sandbox/linux/services/resource_limits.cc
@@ -0,0 +1,26 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/resource_limits.h"
+
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include <algorithm>
+
+namespace sandbox {
+
+// static
+bool ResourceLimits::Lower(int resource, rlim_t limit) {
+  struct rlimit old_rlimit;
+  if (getrlimit(resource, &old_rlimit))
+    return false;
+  // Make sure we don't raise the existing limit.
+  const struct rlimit new_rlimit = {std::min(old_rlimit.rlim_cur, limit),
+                                    std::min(old_rlimit.rlim_max, limit)};
+  int rc = setrlimit(resource, &new_rlimit);
+  return rc == 0;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/resource_limits.h b/sandbox/linux/services/resource_limits.h
new file mode 100644
index 0000000..3464dab
--- /dev/null
+++ b/sandbox/linux/services/resource_limits.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_RESOURCE_LIMITS_H_
+#define SANDBOX_LINUX_SERVICES_RESOURCE_LIMITS_H_
+
+#include <sys/resource.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This class provides a small wrapper around setrlimit().
+class SANDBOX_EXPORT ResourceLimits {
+ public:
+  // Lower the soft and hard limit of |resource| to |limit|. If the current
+  // limit is lower than |limit|, keep it.
+  static bool Lower(int resource, rlim_t limit) WARN_UNUSED_RESULT;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceLimits);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_RESOURCE_LIMITS_H_
diff --git a/sandbox/linux/services/resource_limits_unittests.cc b/sandbox/linux/services/resource_limits_unittests.cc
new file mode 100644
index 0000000..910c740
--- /dev/null
+++ b/sandbox/linux/services/resource_limits_unittests.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/resource_limits.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+// Fails on Android: crbug.com/459158
+#if !defined(OS_ANDROID)
+#define MAYBE_NoFork DISABLE_ON_ASAN(NoFork)
+#else
+#define MAYBE_NoFork DISABLED_NoFork
+#endif  // OS_ANDROID
+
+// Not being able to fork breaks LeakSanitizer, so disable on
+// all ASAN builds.
+SANDBOX_TEST(ResourceLimits, MAYBE_NoFork) {
+  // Make sure that fork will fail with EAGAIN.
+  SANDBOX_ASSERT(ResourceLimits::Lower(RLIMIT_NPROC, 0));
+  errno = 0;
+  pid_t pid = fork();
+  // Reap any child if fork succeeded.
+  TestUtils::HandlePostForkReturn(pid);
+  SANDBOX_ASSERT_EQ(-1, pid);
+  CHECK_EQ(EAGAIN, errno);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/scoped_process.cc b/sandbox/linux/services/scoped_process.cc
new file mode 100644
index 0000000..65af487
--- /dev/null
+++ b/sandbox/linux/services/scoped_process.cc
@@ -0,0 +1,119 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/scoped_process.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+
+namespace sandbox {
+
+namespace {
+
+const char kSynchronisationChar[] = "D";
+
+void WaitForever() {
+  while(true) {
+    pause();
+  }
+}
+
+}  // namespace
+
+ScopedProcess::ScopedProcess(const base::Closure& child_callback)
+    : child_process_id_(-1), process_id_(getpid()) {
+  PCHECK(0 == pipe(pipe_fds_));
+#if !defined(THREAD_SANITIZER)
+  // Make sure that we can safely fork().
+  CHECK(ThreadHelpers::IsSingleThreaded());
+#endif
+  child_process_id_ = fork();
+  PCHECK(0 <= child_process_id_);
+
+  if (0 == child_process_id_) {
+    PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
+    pipe_fds_[0] = -1;
+    child_callback.Run();
+    // Notify the parent that the closure has run.
+    CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds_[1], kSynchronisationChar, 1)));
+    WaitForever();
+    NOTREACHED();
+    _exit(1);
+  }
+
+  PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1])));
+  pipe_fds_[1] = -1;
+}
+
+ScopedProcess::~ScopedProcess() {
+  CHECK(IsOriginalProcess());
+  if (child_process_id_ >= 0) {
+    PCHECK(0 == kill(child_process_id_, SIGKILL));
+    siginfo_t process_info;
+
+    PCHECK(0 == HANDLE_EINTR(
+                    waitid(P_PID, child_process_id_, &process_info, WEXITED)));
+  }
+  if (pipe_fds_[0] >= 0) {
+    PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
+  }
+  if (pipe_fds_[1] >= 0) {
+    PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1])));
+  }
+}
+
+int ScopedProcess::WaitForExit(bool* got_signaled) {
+  DCHECK(got_signaled);
+  CHECK(IsOriginalProcess());
+  siginfo_t process_info;
+  // WNOWAIT to make sure that the destructor can wait on the child.
+  int ret = HANDLE_EINTR(
+      waitid(P_PID, child_process_id_, &process_info, WEXITED | WNOWAIT));
+  PCHECK(0 == ret) << "Did something else wait on the child?";
+
+  if (process_info.si_code == CLD_EXITED) {
+    *got_signaled = false;
+  } else if (process_info.si_code == CLD_KILLED ||
+             process_info.si_code == CLD_DUMPED) {
+    *got_signaled = true;
+  } else {
+    CHECK(false) << "ScopedProcess needs to be extended for si_code "
+                 << process_info.si_code;
+  }
+  return process_info.si_status;
+}
+
+bool ScopedProcess::WaitForClosureToRun() {
+  char c = 0;
+  int ret = HANDLE_EINTR(read(pipe_fds_[0], &c, 1));
+  PCHECK(ret >= 0);
+  if (0 == ret)
+    return false;
+
+  CHECK_EQ(c, kSynchronisationChar[0]);
+  return true;
+}
+
+// It would be problematic if after a fork(), another process would start using
+// this object.
+// This method allows to assert it is not happening.
+bool ScopedProcess::IsOriginalProcess() {
+  // Make a direct syscall to bypass glibc caching of PIDs.
+  pid_t pid = sys_getpid();
+  return pid == process_id_;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/scoped_process.h b/sandbox/linux/services/scoped_process.h
new file mode 100644
index 0000000..bddbd55
--- /dev/null
+++ b/sandbox/linux/services/scoped_process.h
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_SCOPED_PROCESS_H_
+#define SANDBOX_LINUX_SERVICES_SCOPED_PROCESS_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// fork() a child process that will run a Closure.
+// After the Closure has run, the child will pause forever. If this object
+// is detroyed, the child will be destroyed, even if the closure did not
+// finish running. It's ok to signal the child from outside of this class to
+// destroy it.
+// This class cannot be instanciated from a multi-threaded process, as it needs
+// to fork().
+class SANDBOX_EXPORT ScopedProcess {
+ public:
+  // A new process will be created and |child_callback| will run in the child
+  // process. This callback is allowed to terminate the process or to simply
+  // return. If the callback returns, the process will wait forever.
+  explicit ScopedProcess(const base::Closure& child_callback);
+  ~ScopedProcess();
+
+  // Wait for the process to exit.
+  // |got_signaled| tells how to interpret the return value: either as an exit
+  // code, or as a signal number.
+  // When this returns, the process will still not have been reaped and will
+  // survive as a zombie for the lifetime of this object. This method can be
+  // called multiple times.
+  int WaitForExit(bool* got_signaled);
+
+  // Wait for the |child_callback| passed at construction to run. Return false
+  // if |child_callback| did not finish running and we know it never will (for
+  // instance the child crashed or used _exit()).
+  bool WaitForClosureToRun();
+  base::ProcessId GetPid() { return child_process_id_; }
+
+ private:
+  bool IsOriginalProcess();
+
+  base::ProcessId child_process_id_;
+  base::ProcessId process_id_;
+  int pipe_fds_[2];
+  DISALLOW_COPY_AND_ASSIGN(ScopedProcess);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_SCOPED_PROCESS_H_
diff --git a/sandbox/linux/services/scoped_process_unittest.cc b/sandbox/linux/services/scoped_process_unittest.cc
new file mode 100644
index 0000000..8bd2847
--- /dev/null
+++ b/sandbox/linux/services/scoped_process_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/scoped_process.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+void DoExit() { _exit(0); }
+
+void ExitWithCode(int exit_code) { _exit(exit_code); }
+
+void RaiseAndExit(int signal) {
+  PCHECK(0 == raise(signal));
+  _exit(0);
+}
+
+void DoNothing() {}
+
+TEST(ScopedProcess, ScopedProcessNormalExit) {
+  const int kCustomExitCode = 12;
+  ScopedProcess process(base::Bind(&ExitWithCode, kCustomExitCode));
+  bool got_signaled = true;
+  int exit_code = process.WaitForExit(&got_signaled);
+  EXPECT_FALSE(got_signaled);
+  EXPECT_EQ(kCustomExitCode, exit_code);
+
+  // Verify that WaitForExit() can be called multiple times on the same
+  // process.
+  bool got_signaled2 = true;
+  int exit_code2 = process.WaitForExit(&got_signaled2);
+  EXPECT_FALSE(got_signaled2);
+  EXPECT_EQ(kCustomExitCode, exit_code2);
+}
+
+// Disable this test on Android, SIGABRT is funky there.
+TEST(ScopedProcess, DISABLE_ON_ANDROID(ScopedProcessAbort)) {
+  PCHECK(SIG_ERR != signal(SIGABRT, SIG_DFL));
+  ScopedProcess process(base::Bind(&RaiseAndExit, SIGABRT));
+  bool got_signaled = false;
+  int exit_code = process.WaitForExit(&got_signaled);
+  EXPECT_TRUE(got_signaled);
+  EXPECT_EQ(SIGABRT, exit_code);
+}
+
+TEST(ScopedProcess, ScopedProcessSignaled) {
+  ScopedProcess process(base::Bind(&DoNothing));
+  bool got_signaled = false;
+  ASSERT_EQ(0, kill(process.GetPid(), SIGKILL));
+  int exit_code = process.WaitForExit(&got_signaled);
+  EXPECT_TRUE(got_signaled);
+  EXPECT_EQ(SIGKILL, exit_code);
+}
+
+TEST(ScopedProcess, DiesForReal) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+  base::ScopedFD read_end_closer(pipe_fds[0]);
+  base::ScopedFD write_end_closer(pipe_fds[1]);
+
+  { ScopedProcess process(base::Bind(&DoExit)); }
+
+  // Close writing end of the pipe.
+  write_end_closer.reset();
+  pipe_fds[1] = -1;
+
+  ASSERT_EQ(0, fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK));
+  char c;
+  // If the child process is dead for real, there will be no writing end
+  // for this pipe left and read will EOF instead of returning EWOULDBLOCK.
+  ASSERT_EQ(0, read(pipe_fds[0], &c, 1));
+}
+
+TEST(ScopedProcess, SynchronizationBasic) {
+  ScopedProcess process1(base::Bind(&DoNothing));
+  EXPECT_TRUE(process1.WaitForClosureToRun());
+
+  ScopedProcess process2(base::Bind(&DoExit));
+  // The closure didn't finish running normally. This case is simple enough
+  // that process.WaitForClosureToRun() should return false, even though the
+  // API does not guarantees that it will return at all.
+  EXPECT_FALSE(process2.WaitForClosureToRun());
+}
+
+void SleepInMsAndWriteOneByte(int time_to_sleep, int fd) {
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(time_to_sleep));
+  CHECK(1 == write(fd, "1", 1));
+}
+
+TEST(ScopedProcess, SynchronizationWorks) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+  base::ScopedFD read_end_closer(pipe_fds[0]);
+  base::ScopedFD write_end_closer(pipe_fds[1]);
+
+  // Start a process with a closure that takes a little bit to run.
+  ScopedProcess process(
+      base::Bind(&SleepInMsAndWriteOneByte, 100, pipe_fds[1]));
+  EXPECT_TRUE(process.WaitForClosureToRun());
+
+  // Verify that the closure did, indeed, run.
+  ASSERT_EQ(0, fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK));
+  char c = 0;
+  EXPECT_EQ(1, read(pipe_fds[0], &c, 1));
+  EXPECT_EQ('1', c);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
new file mode 100644
index 0000000..264eb68
--- /dev/null
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -0,0 +1,246 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/syscall_wrappers.h"
+
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cstring>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+pid_t sys_getpid(void) {
+  return syscall(__NR_getpid);
+}
+
+pid_t sys_gettid(void) {
+  return syscall(__NR_gettid);
+}
+
+long sys_clone(unsigned long flags,
+               decltype(nullptr) child_stack,
+               pid_t* ptid,
+               pid_t* ctid,
+               decltype(nullptr) tls) {
+  const bool clone_tls_used = flags & CLONE_SETTLS;
+  const bool invalid_ctid =
+      (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
+  const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid;
+
+  // We do not support CLONE_VM.
+  const bool clone_vm_used = flags & CLONE_VM;
+  if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) {
+    RAW_LOG(FATAL, "Invalid usage of sys_clone");
+  }
+
+  if (ptid) MSAN_UNPOISON(ptid, sizeof(*ptid));
+  if (ctid) MSAN_UNPOISON(ctid, sizeof(*ctid));
+  // See kernel/fork.c in Linux. There is different ordering of sys_clone
+  // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options.
+#if defined(ARCH_CPU_X86_64)
+  return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls);
+#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)
+  // CONFIG_CLONE_BACKWARDS defined.
+  return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid);
+#endif
+}
+
+long sys_clone(unsigned long flags) {
+  return sys_clone(flags, nullptr, nullptr, nullptr, nullptr);
+}
+
+void sys_exit_group(int status) {
+  syscall(__NR_exit_group, status);
+}
+
+int sys_seccomp(unsigned int operation,
+                unsigned int flags,
+                const struct sock_fprog* args) {
+  return syscall(__NR_seccomp, operation, flags, args);
+}
+
+int sys_prlimit64(pid_t pid,
+                  int resource,
+                  const struct rlimit64* new_limit,
+                  struct rlimit64* old_limit) {
+  int res = syscall(__NR_prlimit64, pid, resource, new_limit, old_limit);
+  if (res == 0 && old_limit) MSAN_UNPOISON(old_limit, sizeof(*old_limit));
+  return res;
+}
+
+int sys_capget(cap_hdr* hdrp, cap_data* datap) {
+  int res = syscall(__NR_capget, hdrp, datap);
+  if (res == 0) {
+    if (hdrp) MSAN_UNPOISON(hdrp, sizeof(*hdrp));
+    if (datap) MSAN_UNPOISON(datap, sizeof(*datap));
+  }
+  return res;
+}
+
+int sys_capset(cap_hdr* hdrp, const cap_data* datap) {
+  return syscall(__NR_capset, hdrp, datap);
+}
+
+int sys_getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) {
+  int res;
+#if defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARMEL)
+  // On 32-bit x86 or 32-bit arm, getresuid supports 16bit values only.
+  // Use getresuid32 instead.
+  res = syscall(__NR_getresuid32, ruid, euid, suid);
+#else
+  res = syscall(__NR_getresuid, ruid, euid, suid);
+#endif
+  if (res == 0) {
+    if (ruid) MSAN_UNPOISON(ruid, sizeof(*ruid));
+    if (euid) MSAN_UNPOISON(euid, sizeof(*euid));
+    if (suid) MSAN_UNPOISON(suid, sizeof(*suid));
+  }
+  return res;
+}
+
+int sys_getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) {
+  int res;
+#if defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARMEL)
+  // On 32-bit x86 or 32-bit arm, getresgid supports 16bit values only.
+  // Use getresgid32 instead.
+  res = syscall(__NR_getresgid32, rgid, egid, sgid);
+#else
+  res = syscall(__NR_getresgid, rgid, egid, sgid);
+#endif
+  if (res == 0) {
+    if (rgid) MSAN_UNPOISON(rgid, sizeof(*rgid));
+    if (egid) MSAN_UNPOISON(egid, sizeof(*egid));
+    if (sgid) MSAN_UNPOISON(sgid, sizeof(*sgid));
+  }
+  return res;
+}
+
+int sys_chroot(const char* path) {
+  return syscall(__NR_chroot, path);
+}
+
+int sys_unshare(int flags) {
+  return syscall(__NR_unshare, flags);
+}
+
+int sys_sigprocmask(int how, const sigset_t* set, decltype(nullptr) oldset) {
+  // In some toolchain (in particular Android and PNaCl toolchain),
+  // sigset_t is 32 bits, but Linux ABI requires 64 bits.
+  uint64_t linux_value = 0;
+  std::memcpy(&linux_value, set, std::min(sizeof(sigset_t), sizeof(uint64_t)));
+  return syscall(__NR_rt_sigprocmask, how, &linux_value, nullptr,
+                 sizeof(linux_value));
+}
+
+#if (defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) ||  \
+     (defined(ARCH_CPU_X86_64) && !defined(__clang__))) && \
+    !defined(OS_NACL_NONSFI)
+// If MEMORY_SANITIZER or THREAD_SANITIZER is enabled, it is necessary to call
+// sigaction() here, rather than the direct syscall (sys_sigaction() defined
+// by ourselves).
+// It is because, if MEMORY_SANITIZER or THREAD_SANITIZER is enabled, sigaction
+// is wrapped, and |act->sa_handler| is injected in order to unpoisonize the
+// memory passed via callback's arguments for MEMORY_SANITIZER, or handle
+// signals to check thread consistency for THREAD_SANITIZER. Please see
+// msan_interceptors.cc and tsan_interceptors.cc for more details.
+// So, specifically, if MEMORY_SANITIZER is enabled while the direct syscall is
+// used, as MEMORY_SANITIZER does not know about it, sigaction() invocation in
+// other places would be broken (in more precise, returned |oldact| would have
+// a broken |sa_handler| callback).
+// Practically, it would break NaCl's signal handler installation.
+// cf) native_client/src/trusted/service_runtime/linux/nacl_signal.c.
+// As for THREAD_SANITIZER, the intercepted signal handlers are processed more
+// in other libc functions' interceptors (such as for raise()), so that it
+// would not work properly.
+//
+// Also on x86_64 architecture, we need naked function for rt_sigreturn.
+// However, there is no simple way to define it with GCC. Note that the body
+// of function is actually very small (only two instructions), but we need to
+// define much debug information in addition, otherwise backtrace() used by
+// base::StackTrace would not work so that some tests would fail.
+//
+// When this is built with PNaCl toolchain, we should always use sys_sigaction
+// below, because sigaction() provided by the toolchain is incompatible with
+// Linux's ABI. So, otherwise, it would just fail. Note that it is not
+// necessary to think about sigaction() invocation in other places even with
+// MEMORY_SANITIZER or THREAD_SANITIZER, because it would just fail there.
+int sys_sigaction(int signum,
+                  const struct sigaction* act,
+                  struct sigaction* oldact) {
+  return sigaction(signum, act, oldact);
+}
+#else
+// struct sigaction is different ABI from the Linux's.
+struct KernelSigAction {
+  void (*kernel_handler)(int);
+  uint32_t sa_flags;
+  void (*sa_restorer)(void);
+  uint64_t sa_mask;
+};
+
+// On X86_64 arch, it is necessary to set sa_restorer always.
+#if defined(ARCH_CPU_X86_64)
+#if !defined(SA_RESTORER)
+#define SA_RESTORER 0x04000000
+#endif
+
+// rt_sigreturn is a special system call that interacts with the user land
+// stack. Thus, here prologue must not be created, which implies syscall()
+// does not work properly, too. Note that rt_sigreturn will never return.
+static __attribute__((naked)) void sys_rt_sigreturn() {
+  // Just invoke rt_sigreturn system call.
+  asm volatile ("syscall\n"
+                :: "a"(__NR_rt_sigreturn));
+}
+#endif
+
+int sys_sigaction(int signum,
+                  const struct sigaction* act,
+                  struct sigaction* oldact) {
+  KernelSigAction kernel_act = {};
+  if (act) {
+    kernel_act.kernel_handler = act->sa_handler;
+    std::memcpy(&kernel_act.sa_mask, &act->sa_mask,
+                std::min(sizeof(kernel_act.sa_mask), sizeof(act->sa_mask)));
+    kernel_act.sa_flags = act->sa_flags;
+
+#if defined(ARCH_CPU_X86_64)
+    if (!(kernel_act.sa_flags & SA_RESTORER)) {
+      kernel_act.sa_flags |= SA_RESTORER;
+      kernel_act.sa_restorer = sys_rt_sigreturn;
+    }
+#endif
+  }
+
+  KernelSigAction kernel_oldact = {};
+  int result = syscall(__NR_rt_sigaction, signum, act ? &kernel_act : nullptr,
+                       oldact ? &kernel_oldact : nullptr, sizeof(uint64_t));
+  if (result == 0 && oldact) {
+    oldact->sa_handler = kernel_oldact.kernel_handler;
+    sigemptyset(&oldact->sa_mask);
+    std::memcpy(&oldact->sa_mask, &kernel_oldact.sa_mask,
+                std::min(sizeof(kernel_act.sa_mask), sizeof(act->sa_mask)));
+    oldact->sa_flags = kernel_oldact.sa_flags;
+  }
+  return result;
+}
+
+#endif  // defined(MEMORY_SANITIZER)
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/syscall_wrappers.h b/sandbox/linux/services/syscall_wrappers.h
new file mode 100644
index 0000000..581425a
--- /dev/null
+++ b/sandbox/linux/services/syscall_wrappers.h
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
+#define SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "sandbox/sandbox_export.h"
+
+struct sock_fprog;
+struct rlimit64;
+struct cap_hdr;
+struct cap_data;
+
+namespace sandbox {
+
+// Provide direct system call wrappers for a few common system calls.
+// These are guaranteed to perform a system call and do not rely on things such
+// as caching the current pid (c.f. getpid()) unless otherwise specified.
+
+SANDBOX_EXPORT pid_t sys_getpid(void);
+
+SANDBOX_EXPORT pid_t sys_gettid(void);
+
+SANDBOX_EXPORT long sys_clone(unsigned long flags);
+
+// |regs| is not supported and must be passed as nullptr. |child_stack| must be
+// nullptr, since otherwise this function cannot safely return. As a
+// consequence, this function does not support CLONE_VM.
+SANDBOX_EXPORT long sys_clone(unsigned long flags,
+                              decltype(nullptr) child_stack,
+                              pid_t* ptid,
+                              pid_t* ctid,
+                              decltype(nullptr) regs);
+
+SANDBOX_EXPORT void sys_exit_group(int status);
+
+// The official system call takes |args| as void*  (in order to be extensible),
+// but add more typing for the cases that are currently used.
+SANDBOX_EXPORT int sys_seccomp(unsigned int operation,
+                               unsigned int flags,
+                               const struct sock_fprog* args);
+
+// Some libcs do not expose a prlimit64 wrapper.
+SANDBOX_EXPORT int sys_prlimit64(pid_t pid,
+                                 int resource,
+                                 const struct rlimit64* new_limit,
+                                 struct rlimit64* old_limit);
+
+// Some libcs do not expose capget/capset wrappers. We want to use these
+// directly in order to avoid pulling in libcap2.
+SANDBOX_EXPORT int sys_capget(struct cap_hdr* hdrp, struct cap_data* datap);
+SANDBOX_EXPORT int sys_capset(struct cap_hdr* hdrp,
+                              const struct cap_data* datap);
+
+// Some libcs do not expose getresuid/getresgid wrappers.
+SANDBOX_EXPORT int sys_getresuid(uid_t* ruid, uid_t* euid, uid_t* suid);
+SANDBOX_EXPORT int sys_getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid);
+
+// Some libcs do not expose a chroot wrapper.
+SANDBOX_EXPORT int sys_chroot(const char* path);
+
+// Some libcs do not expose a unshare wrapper.
+SANDBOX_EXPORT int sys_unshare(int flags);
+
+// Some libcs do not expose a sigprocmask. Note that oldset must be a nullptr,
+// because of some ABI gap between toolchain's and Linux's.
+SANDBOX_EXPORT int sys_sigprocmask(int how,
+                                   const sigset_t* set,
+                                   decltype(nullptr) oldset);
+
+// Some libcs do not expose a sigaction().
+SANDBOX_EXPORT int sys_sigaction(int signum,
+                                 const struct sigaction* act,
+                                 struct sigaction* oldact);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
diff --git a/sandbox/linux/services/syscall_wrappers_unittest.cc b/sandbox/linux/services/syscall_wrappers_unittest.cc
new file mode 100644
index 0000000..1878ff3
--- /dev/null
+++ b/sandbox/linux/services/syscall_wrappers_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/syscall_wrappers.h"
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <cstring>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+TEST(SyscallWrappers, BasicSyscalls) {
+  EXPECT_EQ(getpid(), sys_getpid());
+}
+
+TEST(SyscallWrappers, CloneBasic) {
+  pid_t child = sys_clone(SIGCHLD);
+  TestUtils::HandlePostForkReturn(child);
+  EXPECT_LT(0, child);
+}
+
+TEST(SyscallWrappers, CloneParentSettid) {
+  pid_t ptid = 0;
+  pid_t child = sys_clone(CLONE_PARENT_SETTID | SIGCHLD, nullptr, &ptid,
+                          nullptr, nullptr);
+  TestUtils::HandlePostForkReturn(child);
+  EXPECT_LT(0, child);
+  EXPECT_EQ(child, ptid);
+}
+
+TEST(SyscallWrappers, CloneChildSettid) {
+  pid_t ctid = 0;
+  pid_t pid =
+      sys_clone(CLONE_CHILD_SETTID | SIGCHLD, nullptr, nullptr, &ctid, nullptr);
+
+  const int kSuccessExit = 0;
+  if (0 == pid) {
+    // In child.
+    if (sys_getpid() == ctid)
+      _exit(kSuccessExit);
+    _exit(1);
+  }
+
+  ASSERT_NE(-1, pid);
+  int status = 0;
+  ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(kSuccessExit, WEXITSTATUS(status));
+}
+
+TEST(SyscallWrappers, GetRESUid) {
+  uid_t ruid, euid, suid;
+  uid_t sys_ruid, sys_euid, sys_suid;
+  ASSERT_EQ(0, getresuid(&ruid, &euid, &suid));
+  ASSERT_EQ(0, sys_getresuid(&sys_ruid, &sys_euid, &sys_suid));
+  EXPECT_EQ(ruid, sys_ruid);
+  EXPECT_EQ(euid, sys_euid);
+  EXPECT_EQ(suid, sys_suid);
+}
+
+TEST(SyscallWrappers, GetRESGid) {
+  gid_t rgid, egid, sgid;
+  gid_t sys_rgid, sys_egid, sys_sgid;
+  ASSERT_EQ(0, getresgid(&rgid, &egid, &sgid));
+  ASSERT_EQ(0, sys_getresgid(&sys_rgid, &sys_egid, &sys_sgid));
+  EXPECT_EQ(rgid, sys_rgid);
+  EXPECT_EQ(egid, sys_egid);
+  EXPECT_EQ(sgid, sys_sgid);
+}
+
+TEST(SyscallWrappers, LinuxSigSet) {
+  sigset_t sigset;
+  ASSERT_EQ(0, sigemptyset(&sigset));
+  ASSERT_EQ(0, sigaddset(&sigset, LINUX_SIGSEGV));
+  ASSERT_EQ(0, sigaddset(&sigset, LINUX_SIGBUS));
+  uint64_t linux_sigset = 0;
+  std::memcpy(&linux_sigset, &sigset,
+              std::min(sizeof(sigset), sizeof(linux_sigset)));
+  EXPECT_EQ((1ULL << (LINUX_SIGSEGV - 1)) | (1ULL << (LINUX_SIGBUS - 1)),
+            linux_sigset);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/thread_helpers.cc b/sandbox/linux/services/thread_helpers.cc
new file mode 100644
index 0000000..80766a9
--- /dev/null
+++ b/sandbox/linux/services/thread_helpers.cc
@@ -0,0 +1,157 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/thread_helpers.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "sandbox/linux/services/proc_util.h"
+
+namespace sandbox {
+
+namespace {
+
+const char kAssertSingleThreadedError[] =
+    "Current process is not mono-threaded!";
+
+bool IsSingleThreadedImpl(int proc_fd) {
+  CHECK_LE(0, proc_fd);
+  struct stat task_stat;
+  int fstat_ret = fstatat(proc_fd, "self/task/", &task_stat, 0);
+  PCHECK(0 == fstat_ret);
+
+  // At least "..", "." and the current thread should be present.
+  CHECK_LE(3UL, task_stat.st_nlink);
+  // Counting threads via /proc/self/task could be racy. For the purpose of
+  // determining if the current proces is monothreaded it works: if at any
+  // time it becomes monothreaded, it'll stay so.
+  return task_stat.st_nlink == 3;
+}
+
+bool IsThreadPresentInProcFS(int proc_fd,
+                             const std::string& thread_id_dir_str) {
+  struct stat task_stat;
+  const int fstat_ret =
+      fstatat(proc_fd, thread_id_dir_str.c_str(), &task_stat, 0);
+  if (fstat_ret < 0) {
+    PCHECK(ENOENT == errno);
+    return false;
+  }
+  return true;
+}
+
+// Run |cb| in a loop until it returns false. Every time |cb| runs, sleep
+// for an exponentially increasing amount of time. |cb| is expected to return
+// false very quickly and this will crash if it doesn't happen within ~64ms on
+// Debug builds (2s on Release builds).
+// This is guaranteed to not sleep more than twice as much as the bare minimum
+// amount of time.
+void RunWhileTrue(const base::Callback<bool(void)>& cb) {
+#if defined(NDEBUG)
+  // In Release mode, crash after 30 iterations, which means having spent
+  // roughly 2s in
+  // nanosleep(2) cumulatively.
+  const unsigned int kMaxIterations = 30U;
+#else
+  // In practice, this never goes through more than a couple iterations. In
+  // debug mode, crash after 64ms (+ eventually 25 times the granularity of
+  // the clock) in nanosleep(2). This ensures that this is not becoming too
+  // slow.
+  const unsigned int kMaxIterations = 25U;
+#endif
+
+  // Run |cb| with an exponential back-off, sleeping 2^iterations nanoseconds
+  // in nanosleep(2).
+  // Note: the clock may not allow for nanosecond granularity, in this case the
+  // first iterations would sleep a tiny bit more instead, which would not
+  // change the calculations significantly.
+  for (unsigned int i = 0; i < kMaxIterations; ++i) {
+    if (!cb.Run()) {
+      return;
+    }
+
+    // Increase the waiting time exponentially.
+    struct timespec ts = {0, 1L << i /* nanoseconds */};
+    PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
+  }
+
+  LOG(FATAL) << kAssertSingleThreadedError << " (iterations: " << kMaxIterations
+             << ")";
+
+  NOTREACHED();
+}
+
+bool IsMultiThreaded(int proc_fd) {
+  return !ThreadHelpers::IsSingleThreaded(proc_fd);
+}
+
+}  // namespace
+
+// static
+bool ThreadHelpers::IsSingleThreaded(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  return IsSingleThreadedImpl(proc_fd);
+}
+
+// static
+bool ThreadHelpers::IsSingleThreaded() {
+  base::ScopedFD task_fd(ProcUtil::OpenProc());
+  return IsSingleThreaded(task_fd.get());
+}
+
+// static
+void ThreadHelpers::AssertSingleThreaded(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  const base::Callback<bool(void)> cb = base::Bind(&IsMultiThreaded, proc_fd);
+  RunWhileTrue(cb);
+}
+
+void ThreadHelpers::AssertSingleThreaded() {
+  base::ScopedFD task_fd(ProcUtil::OpenProc());
+  AssertSingleThreaded(task_fd.get());
+}
+
+// static
+bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_fd,
+                                             base::Thread* thread) {
+  DCHECK_LE(0, proc_fd);
+  DCHECK(thread);
+  const base::PlatformThreadId thread_id = thread->thread_id();
+  const std::string thread_id_dir_str =
+      "self/task/" + base::IntToString(thread_id) + "/";
+
+  // The kernel is at liberty to wake the thread id futex before updating
+  // /proc. Following Stop(), the thread is joined, but entries in /proc may
+  // not have been updated.
+  thread->Stop();
+
+  const base::Callback<bool(void)> cb =
+      base::Bind(&IsThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+
+  RunWhileTrue(cb);
+
+  return true;
+}
+
+// static
+const char* ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests() {
+  return kAssertSingleThreadedError;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/thread_helpers.h b/sandbox/linux/services/thread_helpers.h
new file mode 100644
index 0000000..f4abdff
--- /dev/null
+++ b/sandbox/linux/services/thread_helpers.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_THREAD_HELPERS_H_
+#define SANDBOX_LINUX_SERVICES_THREAD_HELPERS_H_
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace base { class Thread; }
+
+namespace sandbox {
+
+class SANDBOX_EXPORT ThreadHelpers {
+ public:
+  // Check whether the current process is single threaded. |proc_fd|
+  // must be a file descriptor to /proc/ and remains owned by the
+  // caller.
+  static bool IsSingleThreaded(int proc_fd);
+  static bool IsSingleThreaded();
+
+  // Crash if the current process is not single threaded. This will wait
+  // on /proc to be updated. In the case where this doesn't crash, this will
+  // return promptly. In the case where this does crash, this will first wait
+  // for a few ms in Debug mode, a few seconds in Release mode.
+  static void AssertSingleThreaded(int proc_fd);
+  static void AssertSingleThreaded();
+
+  // Stop |thread| and ensure that it does not have an entry in
+  // /proc/self/task/ from the point of view of the current thread. This is
+  // the way to stop threads before calling IsSingleThreaded().
+  static bool StopThreadAndWatchProcFS(int proc_fd, base::Thread* thread);
+
+  static const char* GetAssertSingleThreadedErrorMessageForTests();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadHelpers);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_THREAD_HELPERS_H_
diff --git a/sandbox/linux/services/thread_helpers_unittests.cc b/sandbox/linux/services/thread_helpers_unittests.cc
new file mode 100644
index 0000000..7357a0c
--- /dev/null
+++ b/sandbox/linux/services/thread_helpers_unittests.cc
@@ -0,0 +1,147 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/thread_helpers.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::PlatformThread;
+
+namespace sandbox {
+
+namespace {
+
+// These tests fail under ThreadSanitizer, see http://crbug.com/342305
+#if !defined(THREAD_SANITIZER)
+
+int GetRaceTestIterations() {
+  if (IsRunningOnValgrind()) {
+    return 2;
+  } else {
+    return 1000;
+  }
+}
+
+class ScopedProc {
+ public:
+  ScopedProc() : fd_(-1) {
+    fd_ = open("/proc/", O_RDONLY | O_DIRECTORY);
+    CHECK_LE(0, fd_);
+  }
+
+  ~ScopedProc() { PCHECK(0 == IGNORE_EINTR(close(fd_))); }
+
+  int fd() { return fd_; }
+
+ private:
+  int fd_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedProc);
+};
+
+TEST(ThreadHelpers, IsSingleThreadedBasic) {
+  ScopedProc proc_fd;
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded());
+
+  base::Thread thread("sandbox_tests");
+  ASSERT_TRUE(thread.Start());
+  ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+  ASSERT_FALSE(ThreadHelpers::IsSingleThreaded());
+  // Explicitly stop the thread here to not pollute the next test.
+  ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
+}
+
+SANDBOX_TEST(ThreadHelpers, AssertSingleThreaded) {
+  ScopedProc proc_fd;
+  SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+  SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
+
+  ThreadHelpers::AssertSingleThreaded(proc_fd.fd());
+  ThreadHelpers::AssertSingleThreaded();
+}
+
+TEST(ThreadHelpers, IsSingleThreadedIterated) {
+  ScopedProc proc_fd;
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+
+  // Iterate to check for race conditions.
+  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+    base::Thread thread("sandbox_tests");
+    ASSERT_TRUE(thread.Start());
+    ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+    // Explicitly stop the thread here to not pollute the next test.
+    ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
+  }
+}
+
+TEST(ThreadHelpers, IsSingleThreadedStartAndStop) {
+  ScopedProc proc_fd;
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+
+  base::Thread thread("sandbox_tests");
+  // This is testing for a race condition, so iterate.
+  // Manually, this has been tested with more that 1M iterations.
+  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+    ASSERT_TRUE(thread.Start());
+    ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+
+    ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
+    ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+    ASSERT_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
+  }
+}
+
+SANDBOX_TEST(ThreadHelpers, AssertSingleThreadedAfterThreadStopped) {
+  SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
+
+  base::Thread thread1("sandbox_tests");
+  base::Thread thread2("sandbox_tests");
+
+  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+    SANDBOX_ASSERT(thread1.Start());
+    SANDBOX_ASSERT(thread2.Start());
+    SANDBOX_ASSERT(!ThreadHelpers::IsSingleThreaded());
+
+    thread1.Stop();
+    thread2.Stop();
+    // This will wait on /proc/ to reflect the state of threads in the
+    // process.
+    ThreadHelpers::AssertSingleThreaded();
+    SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
+  }
+}
+
+// Only run this test in Debug mode, where AssertSingleThreaded() will return
+// in less than 64ms.
+#if !defined(NDEBUG)
+SANDBOX_DEATH_TEST(
+    ThreadHelpers,
+    AssertSingleThreadedDies,
+    DEATH_MESSAGE(
+        ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests())) {
+  base::Thread thread1("sandbox_tests");
+  SANDBOX_ASSERT(thread1.Start());
+  ThreadHelpers::AssertSingleThreaded();
+}
+#endif  // !defined(NDEBUG)
+
+#endif  // !defined(THREAD_SANITIZER)
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/yama.cc b/sandbox/linux/services/yama.cc
new file mode 100644
index 0000000..151f4bd
--- /dev/null
+++ b/sandbox/linux/services/yama.cc
@@ -0,0 +1,115 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/yama.h"
+
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+#if !defined(PR_SET_PTRACER_ANY)
+#define PR_SET_PTRACER_ANY ((unsigned long)-1)
+#endif
+
+#if !defined(PR_SET_PTRACER)
+#define PR_SET_PTRACER 0x59616d61
+#endif
+
+namespace sandbox {
+
+namespace {
+
+// Enable or disable the Yama ptracers restrictions.
+// Return false if Yama is not present on this kernel.
+bool SetYamaPtracersRestriction(bool enable_restrictions) {
+  unsigned long set_ptracer_arg;
+  if (enable_restrictions) {
+    set_ptracer_arg = 0;
+  } else {
+    set_ptracer_arg = PR_SET_PTRACER_ANY;
+  }
+
+  const int ret = prctl(PR_SET_PTRACER, set_ptracer_arg);
+  const int prctl_errno = errno;
+
+  if (0 == ret) {
+    return true;
+  } else {
+    // ENOSYS or EINVAL means Yama is not in the current kernel.
+    CHECK(ENOSYS == prctl_errno || EINVAL == prctl_errno);
+    return false;
+  }
+}
+
+bool CanAccessProcFS() {
+  static const char kProcfsKernelSysPath[] = "/proc/sys/kernel/";
+  int ret = access(kProcfsKernelSysPath, F_OK);
+  if (ret) {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+// static
+bool Yama::RestrictPtracersToAncestors() {
+  return SetYamaPtracersRestriction(true /* enable_restrictions */);
+}
+
+// static
+bool Yama::DisableYamaRestrictions() {
+  return SetYamaPtracersRestriction(false /* enable_restrictions */);
+}
+
+// static
+int Yama::GetStatus() {
+  if (!CanAccessProcFS()) {
+    return 0;
+  }
+
+  static const char kPtraceScopePath[] = "/proc/sys/kernel/yama/ptrace_scope";
+
+  base::ScopedFD yama_scope(HANDLE_EINTR(open(kPtraceScopePath, O_RDONLY)));
+
+  if (!yama_scope.is_valid()) {
+    const int open_errno = errno;
+    DCHECK(ENOENT == open_errno);
+    // The status is known, yama is not present.
+    return STATUS_KNOWN;
+  }
+
+  char yama_scope_value = 0;
+  ssize_t num_read = HANDLE_EINTR(read(yama_scope.get(), &yama_scope_value, 1));
+  PCHECK(1 == num_read);
+
+  switch (yama_scope_value) {
+    case '0':
+      return STATUS_KNOWN | STATUS_PRESENT;
+    case '1':
+      return STATUS_KNOWN | STATUS_PRESENT | STATUS_ENFORCING;
+    case '2':
+    case '3':
+      return STATUS_KNOWN | STATUS_PRESENT | STATUS_ENFORCING |
+             STATUS_STRICT_ENFORCING;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+// static
+bool Yama::IsPresent() { return GetStatus() & STATUS_PRESENT; }
+
+// static
+bool Yama::IsEnforcing() { return GetStatus() & STATUS_ENFORCING; }
+
+}  // namespace sandbox
diff --git a/sandbox/linux/services/yama.h b/sandbox/linux/services/yama.h
new file mode 100644
index 0000000..e6c5c45
--- /dev/null
+++ b/sandbox/linux/services/yama.h
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_YAMA_H_
+#define SANDBOX_LINUX_SERVICES_YAMA_H_
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Yama is a LSM kernel module which can restrict ptrace().
+// This class provides ways to detect if Yama is present and enabled
+// and to restrict which processes can ptrace the current process.
+class SANDBOX_EXPORT Yama {
+ public:
+  // This enum should be used to set or check a bitmask.
+  // A value of 0 would indicate that the status is not known.
+  enum GlobalStatus {
+    STATUS_KNOWN = 1 << 0,
+    STATUS_PRESENT = 1 << 1,
+    STATUS_ENFORCING = 1 << 2,
+    // STATUS_STRICT_ENFORCING corresponds to either mode 2 or mode 3 of Yama.
+    // Ptrace could be entirely denied, or restricted to CAP_SYS_PTRACE
+    // and PTRACE_TRACEME.
+    STATUS_STRICT_ENFORCING = 1 << 3
+  };
+
+  // Restrict who can ptrace() the current process to its ancestors.
+  // If this succeeds, then Yama is available on this kernel.
+  // However, Yama may not be enforcing at this time.
+  static bool RestrictPtracersToAncestors();
+
+  // Disable Yama restrictions for the current process.
+  // This will fail if Yama is not available on this kernel.
+  // This is meant for testing only. If you need this, implement
+  // a per-pid authorization instead.
+  static bool DisableYamaRestrictions();
+
+  // Checks if Yama is currently in enforcing mode for the machine (not the
+  // current process). This requires access to the filesystem and will use
+  // /proc/sys/kernel/yama/ptrace_scope.
+  static int GetStatus();
+
+  // Helper for checking for STATUS_PRESENT in GetStatus().
+  static bool IsPresent();
+  // Helper for checkking for STATUS_ENFORCING in GetStatus().
+  static bool IsEnforcing();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Yama);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_YAMA_H_
diff --git a/sandbox/linux/services/yama_unittests.cc b/sandbox/linux/services/yama_unittests.cc
new file mode 100644
index 0000000..a4100a6
--- /dev/null
+++ b/sandbox/linux/services/yama_unittests.cc
@@ -0,0 +1,172 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "sandbox/linux/services/scoped_process.h"
+#include "sandbox/linux/services/yama.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+bool HasLinux32Bug() {
+#if defined(__i386__)
+  // On 3.2 kernels, yama doesn't work for 32-bit binaries on 64-bit kernels.
+  // This is fixed in 3.4.
+  bool is_kernel_64bit =
+      base::SysInfo::OperatingSystemArchitecture() == "x86_64";
+  bool is_linux = base::SysInfo::OperatingSystemName() == "Linux";
+  bool is_3_dot_2 = StartsWithASCII(
+      base::SysInfo::OperatingSystemVersion(), "3.2", /*case_sensitive=*/false);
+  if (is_kernel_64bit && is_linux && is_3_dot_2)
+    return true;
+#endif  // defined(__i386__)
+  return false;
+}
+
+bool CanPtrace(pid_t pid) {
+  int ret;
+  ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
+  if (ret == -1) {
+    CHECK_EQ(EPERM, errno);
+    return false;
+  }
+  // Wait for the process to be stopped so that it can be detached.
+  siginfo_t process_info;
+  int wait_ret = HANDLE_EINTR(waitid(P_PID, pid, &process_info, WSTOPPED));
+  PCHECK(0 == wait_ret);
+  PCHECK(0 == ptrace(PTRACE_DETACH, pid, NULL, NULL));
+  return true;
+}
+
+// _exit(0) if pid can be ptraced by the current process.
+// _exit(1) otherwise.
+void ExitZeroIfCanPtrace(pid_t pid) {
+  if (CanPtrace(pid)) {
+    _exit(0);
+  } else {
+    _exit(1);
+  }
+}
+
+bool CanSubProcessPtrace(pid_t pid) {
+  ScopedProcess process(base::Bind(&ExitZeroIfCanPtrace, pid));
+  bool signaled;
+  int exit_code = process.WaitForExit(&signaled);
+  CHECK(!signaled);
+  return 0 == exit_code;
+}
+
+// The tests below assume that the system-level configuration will not change
+// while they run.
+
+TEST(Yama, GetStatus) {
+  int status1 = Yama::GetStatus();
+
+  // Check that the value is a possible bitmask.
+  ASSERT_LE(0, status1);
+  ASSERT_GE(Yama::STATUS_KNOWN | Yama::STATUS_PRESENT | Yama::STATUS_ENFORCING |
+                Yama::STATUS_STRICT_ENFORCING,
+            status1);
+
+  // The status should not just be a random value.
+  int status2 = Yama::GetStatus();
+  EXPECT_EQ(status1, status2);
+
+  // This test is not running sandboxed, there is no reason to not know the
+  // status.
+  EXPECT_NE(0, Yama::STATUS_KNOWN & status1);
+
+  if (status1 & Yama::STATUS_STRICT_ENFORCING) {
+    // If Yama is strictly enforcing, it is also enforcing.
+    EXPECT_TRUE(status1 & Yama::STATUS_ENFORCING);
+  }
+
+  if (status1 & Yama::STATUS_ENFORCING) {
+    // If Yama is enforcing, Yama is present.
+    EXPECT_NE(0, status1 & Yama::STATUS_PRESENT);
+  }
+
+  // Verify that the helper functions work as intended.
+  EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_ENFORCING),
+            Yama::IsEnforcing());
+  EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_PRESENT),
+            Yama::IsPresent());
+
+  fprintf(stdout,
+          "Yama present: %s - enforcing: %s\n",
+          Yama::IsPresent() ? "Y" : "N",
+          Yama::IsEnforcing() ? "Y" : "N");
+}
+
+SANDBOX_TEST(Yama, RestrictPtraceSucceedsWhenYamaPresent) {
+  // This call will succeed iff Yama is present.
+  bool restricted = Yama::RestrictPtracersToAncestors();
+  CHECK_EQ(restricted, Yama::IsPresent());
+}
+
+// Attempts to enable or disable Yama restrictions.
+void SetYamaRestrictions(bool enable_restriction) {
+  if (enable_restriction) {
+    Yama::RestrictPtracersToAncestors();
+  } else {
+    Yama::DisableYamaRestrictions();
+  }
+}
+
+TEST(Yama, RestrictPtraceWorks) {
+  if (HasLinux32Bug())
+    return;
+
+  ScopedProcess process1(base::Bind(&SetYamaRestrictions, true));
+  ASSERT_TRUE(process1.WaitForClosureToRun());
+
+  if (Yama::IsEnforcing()) {
+    // A sibling process cannot ptrace process1.
+    ASSERT_FALSE(CanSubProcessPtrace(process1.GetPid()));
+  }
+
+  if (!(Yama::GetStatus() & Yama::STATUS_STRICT_ENFORCING)) {
+    // However, parent can ptrace process1.
+    ASSERT_TRUE(CanPtrace(process1.GetPid()));
+
+    // A sibling can ptrace process2 which disables any Yama protection.
+    ScopedProcess process2(base::Bind(&SetYamaRestrictions, false));
+    ASSERT_TRUE(process2.WaitForClosureToRun());
+    ASSERT_TRUE(CanSubProcessPtrace(process2.GetPid()));
+  }
+}
+
+void DoNothing() {}
+
+SANDBOX_TEST(Yama, RestrictPtraceIsDefault) {
+  if (!Yama::IsPresent() || HasLinux32Bug())
+    return;
+
+  CHECK(Yama::DisableYamaRestrictions());
+  ScopedProcess process1(base::Bind(&DoNothing));
+
+  if (Yama::IsEnforcing()) {
+    // Check that process1 is protected by Yama, even though it has
+    // been created from a process that disabled Yama.
+    CHECK(!CanSubProcessPtrace(process1.GetPid()));
+  }
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/suid/client/DEPS b/sandbox/linux/suid/client/DEPS
new file mode 100644
index 0000000..99a337d
--- /dev/null
+++ b/sandbox/linux/suid/client/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/services",
+]
diff --git a/sandbox/linux/suid/client/setuid_sandbox_client.cc b/sandbox/linux/suid/client/setuid_sandbox_client.cc
new file mode 100644
index 0000000..12ef7f9
--- /dev/null
+++ b/sandbox/linux/suid/client/setuid_sandbox_client.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/environment.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "sandbox/linux/suid/common/sandbox.h"
+
+namespace {
+
+bool IsFileSystemAccessDenied() {
+  base::ScopedFD root_dir(HANDLE_EINTR(open("/", O_RDONLY)));
+  return !root_dir.is_valid();
+}
+
+int GetHelperApi(base::Environment* env) {
+  std::string api_string;
+  int api_number = 0;  // Assume API version 0 if no environment was found.
+  if (env->GetVar(sandbox::kSandboxEnvironmentApiProvides, &api_string) &&
+      !base::StringToInt(api_string, &api_number)) {
+    // It's an error if we could not convert the API number.
+    api_number = -1;
+  }
+  return api_number;
+}
+
+// Convert |var_name| from the environment |env| to an int.
+// Return -1 if the variable does not exist or the value cannot be converted.
+int EnvToInt(base::Environment* env, const char* var_name) {
+  std::string var_string;
+  int var_value = -1;
+  if (env->GetVar(var_name, &var_string) &&
+      !base::StringToInt(var_string, &var_value)) {
+    var_value = -1;
+  }
+  return var_value;
+}
+
+pid_t GetHelperPID(base::Environment* env) {
+  return EnvToInt(env, sandbox::kSandboxHelperPidEnvironmentVarName);
+}
+
+// Get the IPC file descriptor used to communicate with the setuid helper.
+int GetIPCDescriptor(base::Environment* env) {
+  return EnvToInt(env, sandbox::kSandboxDescriptorEnvironmentVarName);
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SetuidSandboxClient* SetuidSandboxClient::Create() {
+  base::Environment* environment(base::Environment::Create());
+  CHECK(environment);
+  return new SetuidSandboxClient(environment);
+}
+
+SetuidSandboxClient::SetuidSandboxClient(base::Environment* env)
+    : env_(env), sandboxed_(false) {
+}
+
+SetuidSandboxClient::~SetuidSandboxClient() {
+}
+
+void SetuidSandboxClient::CloseDummyFile() {
+  // When we're launched through the setuid sandbox, SetupLaunchOptions
+  // arranges for kZygoteIdFd to be a dummy file descriptor to satisfy an
+  // ancient setuid sandbox ABI requirement. However, the descriptor is no
+  // longer needed, so we can simply close it right away now.
+  CHECK(IsSuidSandboxChild());
+
+  // Sanity check that kZygoteIdFd refers to a pipe.
+  struct stat st;
+  PCHECK(0 == fstat(kZygoteIdFd, &st));
+  CHECK(S_ISFIFO(st.st_mode));
+
+  PCHECK(0 == IGNORE_EINTR(close(kZygoteIdFd)));
+}
+
+bool SetuidSandboxClient::ChrootMe() {
+  int ipc_fd = GetIPCDescriptor(env_.get());
+
+  if (ipc_fd < 0) {
+    LOG(ERROR) << "Failed to obtain the sandbox IPC descriptor";
+    return false;
+  }
+
+  if (HANDLE_EINTR(write(ipc_fd, &kMsgChrootMe, 1)) != 1) {
+    PLOG(ERROR) << "Failed to write to chroot pipe";
+    return false;
+  }
+
+  // We need to reap the chroot helper process in any event.
+  pid_t helper_pid = GetHelperPID(env_.get());
+  // If helper_pid is -1 we wait for any child.
+  if (HANDLE_EINTR(waitpid(helper_pid, NULL, 0)) < 0) {
+    PLOG(ERROR) << "Failed to wait for setuid helper to die";
+    return false;
+  }
+
+  char reply;
+  if (HANDLE_EINTR(read(ipc_fd, &reply, 1)) != 1) {
+    PLOG(ERROR) << "Failed to read from chroot pipe";
+    return false;
+  }
+
+  if (reply != kMsgChrootSuccessful) {
+    LOG(ERROR) << "Error code reply from chroot helper";
+    return false;
+  }
+
+  // We now consider ourselves "fully sandboxed" as far as the
+  // setuid sandbox is concerned.
+  CHECK(IsFileSystemAccessDenied());
+  sandboxed_ = true;
+  return true;
+}
+
+bool SetuidSandboxClient::IsSuidSandboxUpToDate() const {
+  return GetHelperApi(env_.get()) == kSUIDSandboxApiNumber;
+}
+
+bool SetuidSandboxClient::IsSuidSandboxChild() const {
+  return GetIPCDescriptor(env_.get()) >= 0;
+}
+
+bool SetuidSandboxClient::IsInNewPIDNamespace() const {
+  return env_->HasVar(kSandboxPIDNSEnvironmentVarName);
+}
+
+bool SetuidSandboxClient::IsInNewNETNamespace() const {
+  return env_->HasVar(kSandboxNETNSEnvironmentVarName);
+}
+
+bool SetuidSandboxClient::IsSandboxed() const {
+  return sandboxed_;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/suid/client/setuid_sandbox_client.h b/sandbox/linux/suid/client/setuid_sandbox_client.h
new file mode 100644
index 0000000..026894f
--- /dev/null
+++ b/sandbox/linux/suid/client/setuid_sandbox_client.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SUID_SETUID_SANDBOX_CLIENT_H_
+#define SANDBOX_LINUX_SUID_SETUID_SANDBOX_CLIENT_H_
+
+#include "base/environment.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Helper class to use the setuid sandbox. This class is to be used
+// after being executed through the setuid helper.
+// This class is difficult to use. It has been created by refactoring very old
+// code scathered through the Chromium code base.
+//
+// A typical use for "A" launching a sandboxed process "B" would be:
+// (Steps 1 through 4 are described in setuid_sandbox_host.h.)
+// 5. B uses CloseDummyFile() to close the dummy file descriptor.
+// 6. B performs various initializations that require access to the file
+//    system.
+// 6.b (optional) B uses sandbox::Credentials::HasOpenDirectory() to verify
+//    that no directory is kept open (which would allow bypassing the setuid
+//    sandbox).
+// 7. B should be prepared to assume the role of init(1). In particular, B
+//    cannot receive any signal from any other process, excluding SIGKILL.
+//    If B dies, all the processes in the namespace will die.
+//    B can fork() and the parent can assume the role of init(1), by using
+//    sandbox::CreateInitProcessReaper().
+// 8. B requests being chroot-ed through ChrootMe() and
+//    requests other sandboxing status via the status functions.
+class SANDBOX_EXPORT SetuidSandboxClient {
+ public:
+  // All instantation should go through this factory method.
+  static SetuidSandboxClient* Create();
+  ~SetuidSandboxClient();
+
+  // Close the dummy file descriptor leftover from the sandbox ABI.
+  void CloseDummyFile();
+  // Ask the setuid helper over the setuid sandbox IPC channel to chroot() us
+  // to an empty directory.
+  // Will only work if we have been launched through the setuid helper.
+  bool ChrootMe();
+
+  // Did we get launched through an up to date setuid binary ?
+  bool IsSuidSandboxUpToDate() const;
+  // Did we get launched through the setuid helper ?
+  bool IsSuidSandboxChild() const;
+  // Did the setuid helper create a new PID namespace ?
+  bool IsInNewPIDNamespace() const;
+  // Did the setuid helper create a new network namespace ?
+  bool IsInNewNETNamespace() const;
+  // Are we done and fully sandboxed ?
+  bool IsSandboxed() const;
+
+ private:
+  explicit SetuidSandboxClient(base::Environment* env);
+
+  // Holds the environment. Will never be NULL.
+  scoped_ptr<base::Environment> env_;
+  bool sandboxed_;
+
+  DISALLOW_COPY_AND_ASSIGN(SetuidSandboxClient);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SUID_SETUID_SANDBOX_CLIENT_H_
diff --git a/sandbox/linux/suid/client/setuid_sandbox_client_unittest.cc b/sandbox/linux/suid/client/setuid_sandbox_client_unittest.cc
new file mode 100644
index 0000000..2acd8fb
--- /dev/null
+++ b/sandbox/linux/suid/client/setuid_sandbox_client_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 "sandbox/linux/suid/client/setuid_sandbox_client.h"
+
+#include "base/environment.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "sandbox/linux/suid/common/sandbox.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+TEST(SetuidSandboxClient, SandboxedClientAPI) {
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  EXPECT_TRUE(env != NULL);
+
+  scoped_ptr<SetuidSandboxClient>
+      sandbox_client(SetuidSandboxClient::Create());
+  EXPECT_TRUE(sandbox_client != NULL);
+
+  // Set-up a fake environment as if we went through the setuid sandbox.
+  EXPECT_TRUE(env->SetVar(kSandboxEnvironmentApiProvides,
+              base::IntToString(kSUIDSandboxApiNumber)));
+  EXPECT_TRUE(env->SetVar(kSandboxDescriptorEnvironmentVarName, "1"));
+  EXPECT_TRUE(env->SetVar(kSandboxPIDNSEnvironmentVarName, "1"));
+  EXPECT_TRUE(env->UnSetVar(kSandboxNETNSEnvironmentVarName));
+
+  // Check the API.
+  EXPECT_TRUE(sandbox_client->IsSuidSandboxUpToDate());
+  EXPECT_TRUE(sandbox_client->IsSuidSandboxChild());
+  EXPECT_TRUE(sandbox_client->IsInNewPIDNamespace());
+  EXPECT_FALSE(sandbox_client->IsInNewNETNamespace());
+
+  // Forge an incorrect API version and check.
+  EXPECT_TRUE(env->SetVar(kSandboxEnvironmentApiProvides,
+              base::IntToString(kSUIDSandboxApiNumber + 1)));
+  EXPECT_FALSE(sandbox_client->IsSuidSandboxUpToDate());
+  // We didn't go through the actual sandboxing mechanism as it is
+  // very hard in a unit test.
+  EXPECT_FALSE(sandbox_client->IsSandboxed());
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/linux/suid/client/setuid_sandbox_host.cc b/sandbox/linux/suid/client/setuid_sandbox_host.cc
new file mode 100644
index 0000000..71171eb
--- /dev/null
+++ b/sandbox/linux/suid/client/setuid_sandbox_host.cc
@@ -0,0 +1,195 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/string_number_conversions.h"
+#include "sandbox/linux/suid/common/sandbox.h"
+#include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
+
+namespace {
+
+// Set an environment variable that reflects the API version we expect from the
+// setuid sandbox. Old versions of the sandbox will ignore this.
+void SetSandboxAPIEnvironmentVariable(base::Environment* env) {
+  env->SetVar(sandbox::kSandboxEnvironmentApiRequest,
+              base::IntToString(sandbox::kSUIDSandboxApiNumber));
+}
+
+// Unset environment variables that are expected to be set by the setuid
+// sandbox. This is to allow nesting of one instance of the SUID sandbox
+// inside another.
+void UnsetExpectedEnvironmentVariables(base::EnvironmentMap* env_map) {
+  DCHECK(env_map);
+  const base::NativeEnvironmentString environment_vars[] = {
+      sandbox::kSandboxDescriptorEnvironmentVarName,
+      sandbox::kSandboxHelperPidEnvironmentVarName,
+      sandbox::kSandboxEnvironmentApiProvides,
+      sandbox::kSandboxPIDNSEnvironmentVarName,
+      sandbox::kSandboxNETNSEnvironmentVarName,
+  };
+
+  for (size_t i = 0; i < arraysize(environment_vars); ++i) {
+    // Setting values in EnvironmentMap to an empty-string will make
+    // sure that they get unset from the environment via AlterEnvironment().
+    (*env_map)[environment_vars[i]] = base::NativeEnvironmentString();
+  }
+}
+
+// Wrapper around a shared C function.
+// Returns the "saved" environment variable name corresponding to |envvar|
+// in a new string or NULL.
+std::string* CreateSavedVariableName(const char* env_var) {
+  char* const saved_env_var = SandboxSavedEnvironmentVariable(env_var);
+  if (!saved_env_var)
+    return NULL;
+  std::string* saved_env_var_copy = new std::string(saved_env_var);
+  // SandboxSavedEnvironmentVariable is the C function that we wrap and uses
+  // malloc() to allocate memory.
+  free(saved_env_var);
+  return saved_env_var_copy;
+}
+
+// The ELF loader will clear many environment variables so we save them to
+// different names here so that the SUID sandbox can resolve them for the
+// renderer.
+void SaveSUIDUnsafeEnvironmentVariables(base::Environment* env) {
+  for (unsigned i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) {
+    const char* env_var = kSUIDUnsafeEnvironmentVariables[i];
+    // Get the saved environment variable corresponding to envvar.
+    scoped_ptr<std::string> saved_env_var(CreateSavedVariableName(env_var));
+    if (saved_env_var == NULL)
+      continue;
+
+    std::string value;
+    if (env->GetVar(env_var, &value))
+      env->SetVar(saved_env_var->c_str(), value);
+    else
+      env->UnSetVar(saved_env_var->c_str());
+  }
+}
+
+const char* GetDevelSandboxPath() {
+  return getenv("CHROME_DEVEL_SANDBOX");
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SetuidSandboxHost* SetuidSandboxHost::Create() {
+  base::Environment* environment(base::Environment::Create());
+  CHECK(environment);
+  return new SetuidSandboxHost(environment);
+}
+
+SetuidSandboxHost::SetuidSandboxHost(base::Environment* env) : env_(env) {
+}
+
+SetuidSandboxHost::~SetuidSandboxHost() {
+}
+
+// Check if CHROME_DEVEL_SANDBOX is set but empty. This currently disables
+// the setuid sandbox. TODO(jln): fix this (crbug.com/245376).
+bool SetuidSandboxHost::IsDisabledViaEnvironment() {
+  const char* devel_sandbox_path = GetDevelSandboxPath();
+  if (devel_sandbox_path && '\0' == *devel_sandbox_path) {
+    return true;
+  }
+  return false;
+}
+
+base::FilePath SetuidSandboxHost::GetSandboxBinaryPath() {
+  base::FilePath sandbox_binary;
+  base::FilePath exe_dir;
+  if (PathService::Get(base::DIR_EXE, &exe_dir)) {
+    base::FilePath sandbox_candidate = exe_dir.AppendASCII("chrome-sandbox");
+    if (base::PathExists(sandbox_candidate))
+      sandbox_binary = sandbox_candidate;
+  }
+
+  // In user-managed builds, including development builds, an environment
+  // variable is required to enable the sandbox. See
+  // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment
+  struct stat st;
+  if (sandbox_binary.empty() && stat(base::kProcSelfExe, &st) == 0 &&
+      st.st_uid == getuid()) {
+    const char* devel_sandbox_path = GetDevelSandboxPath();
+    if (devel_sandbox_path) {
+      sandbox_binary = base::FilePath(devel_sandbox_path);
+    }
+  }
+
+  return sandbox_binary;
+}
+
+void SetuidSandboxHost::PrependWrapper(base::CommandLine* cmd_line) {
+  std::string sandbox_binary(GetSandboxBinaryPath().value());
+  struct stat st;
+  if (sandbox_binary.empty() || stat(sandbox_binary.c_str(), &st) != 0) {
+    LOG(FATAL) << "The SUID sandbox helper binary is missing: "
+               << sandbox_binary << " Aborting now. See "
+                                    "https://code.google.com/p/chromium/wiki/"
+                                    "LinuxSUIDSandboxDevelopment.";
+  }
+
+  if (access(sandbox_binary.c_str(), X_OK) != 0 || (st.st_uid != 0) ||
+      ((st.st_mode & S_ISUID) == 0) || ((st.st_mode & S_IXOTH)) == 0) {
+    LOG(FATAL) << "The SUID sandbox helper binary was found, but is not "
+                  "configured correctly. Rather than run without sandboxing "
+                  "I'm aborting now. You need to make sure that "
+               << sandbox_binary << " is owned by root and has mode 4755.";
+  }
+
+  cmd_line->PrependWrapper(sandbox_binary);
+}
+
+void SetuidSandboxHost::SetupLaunchOptions(
+    base::LaunchOptions* options,
+    base::FileHandleMappingVector* fds_to_remap,
+    base::ScopedFD* dummy_fd) {
+  DCHECK(options);
+  DCHECK(fds_to_remap);
+
+  // Launching a setuid binary requires PR_SET_NO_NEW_PRIVS to not be used.
+  options->allow_new_privs = true;
+  UnsetExpectedEnvironmentVariables(&options->environ);
+
+  // Set dummy_fd to the reading end of a closed pipe.
+  int pipe_fds[2];
+  PCHECK(0 == pipe(pipe_fds));
+  PCHECK(0 == IGNORE_EINTR(close(pipe_fds[1])));
+  dummy_fd->reset(pipe_fds[0]);
+
+  // We no longer need a dummy socket for discovering the child's PID,
+  // but the sandbox is still hard-coded to expect a file descriptor at
+  // kZygoteIdFd. Fixing this requires a sandbox API change. :(
+  fds_to_remap->push_back(std::make_pair(dummy_fd->get(), kZygoteIdFd));
+}
+
+void SetuidSandboxHost::SetupLaunchEnvironment() {
+  SaveSUIDUnsafeEnvironmentVariables(env_.get());
+  SetSandboxAPIEnvironmentVariable(env_.get());
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/suid/client/setuid_sandbox_host.h b/sandbox/linux/suid/client/setuid_sandbox_host.h
new file mode 100644
index 0000000..6788892
--- /dev/null
+++ b/sandbox/linux/suid/client/setuid_sandbox_host.h
@@ -0,0 +1,70 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SUID_SETUID_SANDBOX_HOST_H_
+#define SANDBOX_LINUX_SUID_SETUID_SANDBOX_HOST_H_
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process/launch.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Helper class to use the setuid sandbox. This class is to be used
+// before launching the setuid helper.
+// This class is difficult to use. It has been created by refactoring very old
+// code scathered through the Chromium code base.
+//
+// A typical use for "A" launching a sandboxed process "B" would be:
+// 1. A calls SetupLaunchEnvironment()
+// 2. A sets up a base::CommandLine and then amends it with
+//    PrependWrapper() (or manually, by relying on GetSandboxBinaryPath()).
+// 3. A uses SetupLaunchOptions() to arrange for a dummy descriptor for the
+//    setuid sandbox ABI.
+// 4. A launches B with base::LaunchProcess, using the amended
+// base::CommandLine.
+// (The remaining steps are described within setuid_sandbox_client.h.)
+class SANDBOX_EXPORT SetuidSandboxHost {
+ public:
+  // All instantation should go through this factory method.
+  static SetuidSandboxHost* Create();
+  ~SetuidSandboxHost();
+
+  // The setuid sandbox may still be disabled via the environment.
+  // This is tracked in crbug.com/245376.
+  bool IsDisabledViaEnvironment();
+  // Get the sandbox binary path. This method knows about the
+  // CHROME_DEVEL_SANDBOX environment variable used for user-managed builds. If
+  // the sandbox binary cannot be found, it will return an empty FilePath.
+  base::FilePath GetSandboxBinaryPath();
+  // Modify |cmd_line| to launch via the setuid sandbox. Crash if the setuid
+  // sandbox binary cannot be found.  |cmd_line| must not be NULL.
+  void PrependWrapper(base::CommandLine* cmd_line);
+  // Set-up the launch options for launching via the setuid sandbox.  Caller is
+  // responsible for keeping |dummy_fd| alive until LaunchProcess() completes.
+  // |options| and |fds_to_remap| must not be NULL.
+  // (Keeping |dummy_fd| alive is an unfortunate historical artifact of the
+  // chrome-sandbox ABI.)
+  void SetupLaunchOptions(base::LaunchOptions* options,
+                          base::FileHandleMappingVector* fds_to_remap,
+                          base::ScopedFD* dummy_fd);
+  // Set-up the environment. This should be done prior to launching the setuid
+  // helper.
+  void SetupLaunchEnvironment();
+
+ private:
+  explicit SetuidSandboxHost(base::Environment* env);
+
+  // Holds the environment. Will never be NULL.
+  scoped_ptr<base::Environment> env_;
+
+  DISALLOW_COPY_AND_ASSIGN(SetuidSandboxHost);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SUID_SETUID_SANDBOX_HOST_H_
diff --git a/sandbox/linux/suid/client/setuid_sandbox_host_unittest.cc b/sandbox/linux/suid/client/setuid_sandbox_host_unittest.cc
new file mode 100644
index 0000000..8415abb
--- /dev/null
+++ b/sandbox/linux/suid/client/setuid_sandbox_host_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/suid/client/setuid_sandbox_host.h"
+
+#include <string>
+
+#include "base/environment.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "sandbox/linux/suid/common/sandbox.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+TEST(SetuidSandboxHost, SetupLaunchEnvironment) {
+  const char kTestValue[] = "This is a test";
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  EXPECT_TRUE(env != NULL);
+
+  std::string saved_ld_preload;
+  bool environment_had_ld_preload;
+  // First, back-up the real LD_PRELOAD if any.
+  environment_had_ld_preload = env->GetVar("LD_PRELOAD", &saved_ld_preload);
+  // Setup environment variables to save or not save.
+  EXPECT_TRUE(env->SetVar("LD_PRELOAD", kTestValue));
+  EXPECT_TRUE(env->UnSetVar("LD_ORIGIN_PATH"));
+
+  scoped_ptr<SetuidSandboxHost> sandbox_host(SetuidSandboxHost::Create());
+  EXPECT_TRUE(sandbox_host != NULL);
+
+  // Make sure the environment is clean.
+  EXPECT_TRUE(env->UnSetVar(kSandboxEnvironmentApiRequest));
+  EXPECT_TRUE(env->UnSetVar(kSandboxEnvironmentApiProvides));
+
+  sandbox_host->SetupLaunchEnvironment();
+
+  // Check if the requested API environment was set.
+  std::string api_request;
+  EXPECT_TRUE(env->GetVar(kSandboxEnvironmentApiRequest, &api_request));
+  int api_request_num;
+  EXPECT_TRUE(base::StringToInt(api_request, &api_request_num));
+  EXPECT_EQ(api_request_num, kSUIDSandboxApiNumber);
+
+  // Now check if LD_PRELOAD was saved to SANDBOX_LD_PRELOAD.
+  std::string sandbox_ld_preload;
+  EXPECT_TRUE(env->GetVar("SANDBOX_LD_PRELOAD", &sandbox_ld_preload));
+  EXPECT_EQ(sandbox_ld_preload, kTestValue);
+
+  // Check that LD_ORIGIN_PATH was not saved.
+  EXPECT_FALSE(env->HasVar("SANDBOX_LD_ORIGIN_PATH"));
+
+  // We should not forget to restore LD_PRELOAD at the end, or this environment
+  // variable will affect the next running tests!
+  if (environment_had_ld_preload) {
+    EXPECT_TRUE(env->SetVar("LD_PRELOAD", saved_ld_preload));
+  } else {
+    EXPECT_TRUE(env->UnSetVar("LD_PRELOAD"));
+  }
+}
+
+// This test doesn't accomplish much, but will make sure that analysis tools
+// will run this codepath.
+TEST(SetuidSandboxHost, GetSandboxBinaryPath) {
+  scoped_ptr<SetuidSandboxHost> setuid_sandbox_host(
+      SetuidSandboxHost::Create());
+  ignore_result(setuid_sandbox_host->GetSandboxBinaryPath());
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/suid/common/sandbox.h b/sandbox/linux/suid/common/sandbox.h
new file mode 100644
index 0000000..99eb7b5
--- /dev/null
+++ b/sandbox/linux/suid/common/sandbox.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SUID_SANDBOX_H_
+#define SANDBOX_LINUX_SUID_SANDBOX_H_
+
+#if defined(__cplusplus)
+namespace sandbox {
+#endif
+
+// These are command line switches that may be used by other programs
+// (e.g. Chrome) to construct a command line for the sandbox.
+static const char kSuidSandboxGetApiSwitch[] = "--get-api";
+static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
+
+static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
+static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
+
+static const long kSUIDSandboxApiNumber = 1;
+static const char kSandboxEnvironmentApiRequest[] = "SBX_CHROME_API_RQ";
+static const char kSandboxEnvironmentApiProvides[] = "SBX_CHROME_API_PRV";
+
+// This number must be kept in sync with common/zygote_commands_linux.h
+static const int kZygoteIdFd = 7;
+
+// These are the magic byte values which the sandboxed process uses to request
+// that it be chrooted.
+static const char kMsgChrootMe = 'C';
+static const char kMsgChrootSuccessful = 'O';
+
+// These are set if we have respectively switched to a new PID or NET namespace
+// by going through the setuid binary helper.
+static const char kSandboxPIDNSEnvironmentVarName[] = "SBX_PID_NS";
+static const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS";
+
+#if defined(__cplusplus)
+}  // namespace sandbox
+#endif
+
+#endif  // SANDBOX_LINUX_SUID_SANDBOX_H_
diff --git a/sandbox/linux/suid/common/suid_unsafe_environment_variables.h b/sandbox/linux/suid/common/suid_unsafe_environment_variables.h
new file mode 100644
index 0000000..33ba4b6
--- /dev/null
+++ b/sandbox/linux/suid/common/suid_unsafe_environment_variables.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.
+
+// This is a list of environment variables which the ELF loader unsets when
+// loading a SUID binary. Because they are unset rather than just ignored, they
+// aren't passed to child processes of SUID processes either.
+//
+// We need to save these environment variables before running a SUID sandbox
+// and restore them before running child processes (but after dropping root).
+//
+// List gathered from glibc sources (00ebd7ed58df389a78e41dece058048725cb585e):
+//   sysdeps/unix/sysv/linux/i386/dl-librecon.h
+//   sysdeps/generic/unsecvars.h
+
+#ifndef SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#define SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+
+#include <stdint.h>
+#include <stdlib.h>  // malloc
+#include <string.h>  // memcpy
+
+static const char* kSUIDUnsafeEnvironmentVariables[] = {
+  "LD_AOUT_LIBRARY_PATH",
+  "LD_AOUT_PRELOAD",
+  "GCONV_PATH",
+  "GETCONF_DIR",
+  "HOSTALIASES",
+  "LD_AUDIT",
+  "LD_DEBUG",
+  "LD_DEBUG_OUTPUT",
+  "LD_DYNAMIC_WEAK",
+  "LD_LIBRARY_PATH",
+  "LD_ORIGIN_PATH",
+  "LD_PRELOAD",
+  "LD_PROFILE",
+  "LD_SHOW_AUXV",
+  "LD_USE_LOAD_BIAS",
+  "LOCALDOMAIN",
+  "LOCPATH",
+  "MALLOC_TRACE",
+  "NIS_PATH",
+  "NLSPATH",
+  "RESOLV_HOST_CONF",
+  "RES_OPTIONS",
+  "TMPDIR",
+  "TZDIR",
+  NULL,
+};
+
+// Return a malloc allocated string containing the 'saved' environment variable
+// name for a given environment variable.
+static inline char* SandboxSavedEnvironmentVariable(const char* envvar) {
+  const size_t envvar_len = strlen(envvar);
+  const size_t kMaxSizeT = (size_t) -1;
+
+  if (envvar_len > kMaxSizeT - 1 - 8)
+    return NULL;
+
+  const size_t saved_envvarlen = envvar_len + 1 /* NUL terminator */ +
+                                              8 /* strlen("SANDBOX_") */;
+  char* const saved_envvar = (char*) malloc(saved_envvarlen);
+  if (!saved_envvar)
+    return NULL;
+
+  memcpy(saved_envvar, "SANDBOX_", 8);
+  memcpy(saved_envvar + 8, envvar, envvar_len);
+  saved_envvar[8 + envvar_len] = 0;
+
+  return saved_envvar;
+}
+
+#endif  // SANDBOX_LINUX_SUID_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
diff --git a/sandbox/linux/suid/process_util.h b/sandbox/linux/suid/process_util.h
new file mode 100644
index 0000000..9fb9a87
--- /dev/null
+++ b/sandbox/linux/suid/process_util.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.
+
+// The following is duplicated from base/process_utils.h.
+// We shouldn't link against C++ code in a setuid binary.
+
+#ifndef SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
+#define SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+// This adjusts /proc/process/oom_score_adj so the Linux OOM killer
+// will prefer certain process types over others. The range for the
+// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
+//
+// If the Linux system isn't new enough to use oom_score_adj, then we
+// try to set the older oom_adj value instead, scaling the score to
+// the required range of [0, 15]. This may result in some aliasing of
+// values, of course.
+bool AdjustOOMScore(pid_t process, int score);
+
+// This adjusts /sys/kernel/mm/chromeos-low_mem/margin so that
+// the kernel notifies us that we are low on memory when less than
+// |margin_mb| megabytes are available.  Setting |margin_mb| to -1
+// turns off low memory notification.
+bool AdjustLowMemoryMargin(int64_t margin_mb);
+
+#endif  // SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
diff --git a/sandbox/linux/suid/process_util_linux.c b/sandbox/linux/suid/process_util_linux.c
new file mode 100644
index 0000000..8d9a53c
--- /dev/null
+++ b/sandbox/linux/suid/process_util_linux.c
@@ -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.
+
+// The following is the C version of code from base/process_utils_linux.cc.
+// We shouldn't link against C++ code in a setuid binary.
+
+// Needed for O_DIRECTORY, must be defined before fcntl.h is included
+// (and it can be included earlier than the explicit #include below
+// in some versions of glibc).
+#define _GNU_SOURCE
+
+#include "sandbox/linux/suid/process_util.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Ranges for the current (oom_score_adj) and previous (oom_adj)
+// flavors of OOM score.
+static const int kMaxOomScore = 1000;
+static const int kMaxOldOomScore = 15;
+
+// NOTE: This is not the only version of this function in the source:
+// the base library (in process_util_linux.cc) also has its own C++ version.
+bool AdjustOOMScore(pid_t process, int score) {
+  if (score < 0 || score > kMaxOomScore)
+    return false;
+
+  char oom_adj[27];  // "/proc/" + log_10(2**64) + "\0"
+                     //    6     +       20     +     1         = 27
+  snprintf(oom_adj, sizeof(oom_adj), "/proc/%" PRIdMAX, (intmax_t)process);
+
+  const int dirfd = open(oom_adj, O_RDONLY | O_DIRECTORY);
+  if (dirfd < 0)
+    return false;
+
+  struct stat statbuf;
+  if (fstat(dirfd, &statbuf) < 0) {
+    close(dirfd);
+    return false;
+  }
+  if (getuid() != statbuf.st_uid) {
+    close(dirfd);
+    return false;
+  }
+
+  int fd = openat(dirfd, "oom_score_adj", O_WRONLY);
+  if (fd < 0) {
+    // We failed to open oom_score_adj, so let's try for the older
+    // oom_adj file instead.
+    fd = openat(dirfd, "oom_adj", O_WRONLY);
+    if (fd < 0) {
+      // Nope, that doesn't work either.
+      return false;
+    } else {
+      // If we're using the old oom_adj file, the allowed range is now
+      // [0, kMaxOldOomScore], so we scale the score.  This may result in some
+      // aliasing of values, of course.
+      score = score * kMaxOldOomScore / kMaxOomScore;
+    }
+  }
+  close(dirfd);
+
+  char buf[11];  // 0 <= |score| <= kMaxOomScore; using log_10(2**32) + 1 size
+  snprintf(buf, sizeof(buf), "%d", score);
+  size_t len = strlen(buf);
+
+  ssize_t bytes_written = write(fd, buf, len);
+  close(fd);
+  return (bytes_written == (ssize_t)len);
+}
diff --git a/sandbox/linux/suid/sandbox.c b/sandbox/linux/suid/sandbox.c
new file mode 100644
index 0000000..3049ae5
--- /dev/null
+++ b/sandbox/linux/suid/sandbox.c
@@ -0,0 +1,480 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
+
+#include "sandbox/linux/suid/common/sandbox.h"
+
+#define _GNU_SOURCE
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
+#include "sandbox/linux/suid/process_util.h"
+
+#if !defined(CLONE_NEWPID)
+#define CLONE_NEWPID 0x20000000
+#endif
+#if !defined(CLONE_NEWNET)
+#define CLONE_NEWNET 0x40000000
+#endif
+
+static bool DropRoot();
+
+#define HANDLE_EINTR(x) TEMP_FAILURE_RETRY(x)
+
+static void FatalError(const char* msg, ...)
+    __attribute__((noreturn, format(printf, 1, 2)));
+
+static void FatalError(const char* msg, ...) {
+  va_list ap;
+  va_start(ap, msg);
+
+  vfprintf(stderr, msg, ap);
+  fprintf(stderr, ": %s\n", strerror(errno));
+  fflush(stderr);
+  va_end(ap);
+  _exit(1);
+}
+
+static void ExitWithErrorSignalHandler(int signal) {
+  const char msg[] = "\nThe setuid sandbox got signaled, exiting.\n";
+  if (-1 == write(2, msg, sizeof(msg) - 1)) {
+    // Do nothing.
+  }
+
+  _exit(1);
+}
+
+// We will chroot() to the helper's /proc/self directory. Anything there will
+// not exist anymore if we make sure to wait() for the helper.
+//
+// /proc/self/fdinfo or /proc/self/fd are especially safe and will be empty
+// even if the helper survives as a zombie.
+//
+// There is very little reason to use fdinfo/ instead of fd/ but we are
+// paranoid. fdinfo/ only exists since 2.6.22 so we allow fallback to fd/
+#define SAFE_DIR "/proc/self/fdinfo"
+#define SAFE_DIR2 "/proc/self/fd"
+
+static bool SpawnChrootHelper() {
+  int sv[2];
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+    perror("socketpair");
+    return false;
+  }
+
+  char* safedir = NULL;
+  struct stat sdir_stat;
+  if (!stat(SAFE_DIR, &sdir_stat) && S_ISDIR(sdir_stat.st_mode)) {
+    safedir = SAFE_DIR;
+  } else if (!stat(SAFE_DIR2, &sdir_stat) && S_ISDIR(sdir_stat.st_mode)) {
+    safedir = SAFE_DIR2;
+  } else {
+    fprintf(stderr, "Could not find %s\n", SAFE_DIR2);
+    return false;
+  }
+
+  const pid_t pid = syscall(__NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0);
+
+  if (pid == -1) {
+    perror("clone");
+    close(sv[0]);
+    close(sv[1]);
+    return false;
+  }
+
+  if (pid == 0) {
+    // We share our files structure with an untrusted process. As a security in
+    // depth measure, we make sure that we can't open anything by mistake.
+    // TODO(agl): drop CAP_SYS_RESOURCE / use SECURE_NOROOT
+
+    const struct rlimit nofile = {0, 0};
+    if (setrlimit(RLIMIT_NOFILE, &nofile))
+      FatalError("Setting RLIMIT_NOFILE");
+
+    if (close(sv[1]))
+      FatalError("close");
+
+    // wait for message
+    char msg;
+    ssize_t bytes;
+    do {
+      bytes = read(sv[0], &msg, 1);
+    } while (bytes == -1 && errno == EINTR);
+
+    if (bytes == 0)
+      _exit(0);
+    if (bytes != 1)
+      FatalError("read");
+
+    // do chrooting
+    if (msg != kMsgChrootMe)
+      FatalError("Unknown message from sandboxed process");
+
+    // sanity check
+    if (chdir(safedir))
+      FatalError("Cannot chdir into /proc/ directory");
+
+    if (chroot(safedir))
+      FatalError("Cannot chroot into /proc/ directory");
+
+    if (chdir("/"))
+      FatalError("Cannot chdir to / after chroot");
+
+    const char reply = kMsgChrootSuccessful;
+    do {
+      bytes = write(sv[0], &reply, 1);
+    } while (bytes == -1 && errno == EINTR);
+
+    if (bytes != 1)
+      FatalError("Writing reply");
+
+    _exit(0);
+    // We now become a zombie. /proc/self/fd(info) is now an empty dir and we
+    // are chrooted there.
+    // Our (unprivileged) parent should not even be able to open "." or "/"
+    // since they would need to pass the ptrace() check. If our parent wait()
+    // for us, our root directory will completely disappear.
+  }
+
+  if (close(sv[0])) {
+    close(sv[1]);
+    perror("close");
+    return false;
+  }
+
+  // In the parent process, we install an environment variable containing the
+  // number of the file descriptor.
+  char desc_str[64];
+  int printed = snprintf(desc_str, sizeof(desc_str), "%u", sv[1]);
+  if (printed < 0 || printed >= (int)sizeof(desc_str)) {
+    fprintf(stderr, "Failed to snprintf\n");
+    return false;
+  }
+
+  if (setenv(kSandboxDescriptorEnvironmentVarName, desc_str, 1)) {
+    perror("setenv");
+    close(sv[1]);
+    return false;
+  }
+
+  // We also install an environment variable containing the pid of the child
+  char helper_pid_str[64];
+  printed = snprintf(helper_pid_str, sizeof(helper_pid_str), "%u", pid);
+  if (printed < 0 || printed >= (int)sizeof(helper_pid_str)) {
+    fprintf(stderr, "Failed to snprintf\n");
+    return false;
+  }
+
+  if (setenv(kSandboxHelperPidEnvironmentVarName, helper_pid_str, 1)) {
+    perror("setenv");
+    close(sv[1]);
+    return false;
+  }
+
+  return true;
+}
+
+// Block until child_pid exits, then exit. Try to preserve the exit code.
+static void WaitForChildAndExit(pid_t child_pid) {
+  int exit_code = -1;
+  siginfo_t reaped_child_info;
+
+  // Don't "Core" on SIGABRT. SIGABRT is sent by the Chrome OS session manager
+  // when things are hanging.
+  // Here, the current process is going to waitid() and _exit(), so there is no
+  // point in generating a crash report. The child process is the one
+  // blocking us.
+  if (signal(SIGABRT, ExitWithErrorSignalHandler) == SIG_ERR) {
+    FatalError("Failed to change signal handler");
+  }
+
+  int wait_ret =
+      HANDLE_EINTR(waitid(P_PID, child_pid, &reaped_child_info, WEXITED));
+
+  if (!wait_ret && reaped_child_info.si_pid == child_pid) {
+    if (reaped_child_info.si_code == CLD_EXITED) {
+      exit_code = reaped_child_info.si_status;
+    } else {
+      // Exit with code 0 if the child got signaled.
+      exit_code = 0;
+    }
+  }
+  _exit(exit_code);
+}
+
+static bool MoveToNewNamespaces() {
+  // These are the sets of flags which we'll try, in order.
+  const int kCloneExtraFlags[] = {CLONE_NEWPID | CLONE_NEWNET, CLONE_NEWPID, };
+
+  // We need to close kZygoteIdFd before the child can continue. We use this
+  // socketpair to tell the child when to continue;
+  int sync_fds[2];
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
+    FatalError("Failed to create a socketpair");
+  }
+
+  for (size_t i = 0; i < sizeof(kCloneExtraFlags) / sizeof(kCloneExtraFlags[0]);
+       i++) {
+    pid_t pid = syscall(__NR_clone, SIGCHLD | kCloneExtraFlags[i], 0, 0, 0);
+    const int clone_errno = errno;
+
+    if (pid > 0) {
+      if (!DropRoot()) {
+        FatalError("Could not drop privileges");
+      } else {
+        if (close(sync_fds[0]) || shutdown(sync_fds[1], SHUT_RD))
+          FatalError("Could not close socketpair");
+        // The kZygoteIdFd needs to be closed in the parent before
+        // Zygote gets started.
+        if (close(kZygoteIdFd))
+          FatalError("close");
+        // Tell our child to continue
+        if (HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) != 1)
+          FatalError("send");
+        if (close(sync_fds[1]))
+          FatalError("close");
+        // We want to keep a full process tree and we don't want our childs to
+        // be reparented to (the outer PID namespace) init. So we wait for it.
+        WaitForChildAndExit(pid);
+      }
+      // NOTREACHED
+      FatalError("Not reached");
+    }
+
+    if (pid == 0) {
+      if (close(sync_fds[1]) || shutdown(sync_fds[0], SHUT_WR))
+        FatalError("Could not close socketpair");
+
+      // Wait for the parent to confirm it closed kZygoteIdFd before we
+      // continue
+      char should_continue;
+      if (HANDLE_EINTR(read(sync_fds[0], &should_continue, 1)) != 1)
+        FatalError("Read on socketpair");
+      if (close(sync_fds[0]))
+        FatalError("close");
+
+      if (kCloneExtraFlags[i] & CLONE_NEWPID) {
+        setenv(kSandboxPIDNSEnvironmentVarName, "", 1 /* overwrite */);
+      } else {
+        unsetenv(kSandboxPIDNSEnvironmentVarName);
+      }
+
+      if (kCloneExtraFlags[i] & CLONE_NEWNET) {
+        setenv(kSandboxNETNSEnvironmentVarName, "", 1 /* overwrite */);
+      } else {
+        unsetenv(kSandboxNETNSEnvironmentVarName);
+      }
+
+      break;
+    }
+
+    // If EINVAL then the system doesn't support the requested flags, so
+    // continue to try a different set.
+    // On any other errno value the system *does* support these flags but
+    // something went wrong, hence we bail with an error message rather then
+    // provide less security.
+    if (errno != EINVAL) {
+      fprintf(stderr, "Failed to move to new namespace:");
+      if (kCloneExtraFlags[i] & CLONE_NEWPID) {
+        fprintf(stderr, " PID namespaces supported,");
+      }
+      if (kCloneExtraFlags[i] & CLONE_NEWNET) {
+        fprintf(stderr, " Network namespace supported,");
+      }
+      fprintf(stderr, " but failed: errno = %s\n", strerror(clone_errno));
+      return false;
+    }
+  }
+
+  // If the system doesn't support NEWPID then we carry on anyway.
+  return true;
+}
+
+static bool DropRoot() {
+  if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0)) {
+    perror("prctl(PR_SET_DUMPABLE)");
+    return false;
+  }
+
+  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
+    perror("Still dumpable after prctl(PR_SET_DUMPABLE)");
+    return false;
+  }
+
+  gid_t rgid, egid, sgid;
+  if (getresgid(&rgid, &egid, &sgid)) {
+    perror("getresgid");
+    return false;
+  }
+
+  if (setresgid(rgid, rgid, rgid)) {
+    perror("setresgid");
+    return false;
+  }
+
+  uid_t ruid, euid, suid;
+  if (getresuid(&ruid, &euid, &suid)) {
+    perror("getresuid");
+    return false;
+  }
+
+  if (setresuid(ruid, ruid, ruid)) {
+    perror("setresuid");
+    return false;
+  }
+
+  return true;
+}
+
+static bool SetupChildEnvironment() {
+  unsigned i;
+
+  // ld.so may have cleared several environment variables because we are SUID.
+  // However, the child process might need them so zygote_host_linux.cc saves a
+  // copy in SANDBOX_$x. This is safe because we have dropped root by this
+  // point, so we can only exec a binary with the permissions of the user who
+  // ran us in the first place.
+
+  for (i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) {
+    const char* const envvar = kSUIDUnsafeEnvironmentVariables[i];
+    char* const saved_envvar = SandboxSavedEnvironmentVariable(envvar);
+    if (!saved_envvar)
+      return false;
+
+    const char* const value = getenv(saved_envvar);
+    if (value) {
+      setenv(envvar, value, 1 /* overwrite */);
+      unsetenv(saved_envvar);
+    }
+
+    free(saved_envvar);
+  }
+
+  return true;
+}
+
+bool CheckAndExportApiVersion() {
+  // Check the environment to see if a specific API version was requested.
+  // assume version 0 if none.
+  long api_number = -1;
+  char* api_string = getenv(kSandboxEnvironmentApiRequest);
+  if (!api_string) {
+    api_number = 0;
+  } else {
+    errno = 0;
+    char* endptr = NULL;
+    api_number = strtol(api_string, &endptr, 10);
+    if (!endptr || *endptr || errno != 0)
+      return false;
+  }
+
+  // Warn only for now.
+  if (api_number != kSUIDSandboxApiNumber) {
+    fprintf(
+        stderr,
+        "The setuid sandbox provides API version %ld, "
+        "but you need %ld\n"
+        "Please read "
+        "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment."
+        "\n\n",
+        kSUIDSandboxApiNumber,
+        api_number);
+  }
+
+  // Export our version so that the sandboxed process can verify it did not
+  // use an old sandbox.
+  char version_string[64];
+  snprintf(
+      version_string, sizeof(version_string), "%ld", kSUIDSandboxApiNumber);
+  if (setenv(kSandboxEnvironmentApiProvides, version_string, 1)) {
+    perror("setenv");
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char** argv) {
+  if (argc <= 1) {
+    if (argc <= 0) {
+      return 1;
+    }
+
+    fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]);
+    return 1;
+  }
+
+  // Allow someone to query our API version
+  if (argc == 2 && 0 == strcmp(argv[1], kSuidSandboxGetApiSwitch)) {
+    printf("%ld\n", kSUIDSandboxApiNumber);
+    return 0;
+  }
+
+  // We cannot adjust /proc/pid/oom_adj for sandboxed renderers
+  // because those files are owned by root. So we need a helper here.
+  if (argc == 4 && (0 == strcmp(argv[1], kAdjustOOMScoreSwitch))) {
+    char* endptr = NULL;
+    long score;
+    errno = 0;
+    unsigned long pid_ul = strtoul(argv[2], &endptr, 10);
+    if (pid_ul == ULONG_MAX || !endptr || *endptr || errno != 0)
+      return 1;
+    pid_t pid = pid_ul;
+    endptr = NULL;
+    errno = 0;
+    score = strtol(argv[3], &endptr, 10);
+    if (score == LONG_MAX || score == LONG_MIN || !endptr || *endptr ||
+        errno != 0) {
+      return 1;
+    }
+    return AdjustOOMScore(pid, score);
+  }
+
+  // Protect the core setuid sandbox functionality with an API version
+  if (!CheckAndExportApiVersion()) {
+    return 1;
+  }
+
+  if (geteuid() != 0) {
+    fprintf(stderr,
+            "The setuid sandbox is not running as root. Common causes:\n"
+            "  * An unprivileged process using ptrace on it, like a debugger.\n"
+            "  * A parent process set prctl(PR_SET_NO_NEW_PRIVS, ...)\n");
+  }
+
+  if (!MoveToNewNamespaces())
+    return 1;
+  if (!SpawnChrootHelper())
+    return 1;
+  if (!DropRoot())
+    return 1;
+  if (!SetupChildEnvironment())
+    return 1;
+
+  execv(argv[1], &argv[1]);
+  FatalError("execv failed");
+
+  return 1;
+}
diff --git a/sandbox/linux/syscall_broker/DEPS b/sandbox/linux/syscall_broker/DEPS
new file mode 100644
index 0000000..70d9b18
--- /dev/null
+++ b/sandbox/linux/syscall_broker/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/system_headers",
+]
diff --git a/sandbox/linux/syscall_broker/broker_channel.cc b/sandbox/linux/syscall_broker/broker_channel.cc
new file mode 100644
index 0000000..fa0f761
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_channel.cc
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// static
+void BrokerChannel::CreatePair(EndPoint* reader, EndPoint* writer) {
+  DCHECK(reader);
+  DCHECK(writer);
+  int socket_pair[2];
+  // Use SOCK_SEQPACKET, to preserve message boundaries but we also want to be
+  // notified (recvmsg should return and not block) when the connection has
+  // been broken which could mean that the other end has been closed.
+  PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socket_pair));
+
+  reader->reset(socket_pair[0]);
+  PCHECK(0 == shutdown(reader->get(), SHUT_WR));
+
+  writer->reset(socket_pair[1]);
+  PCHECK(0 == shutdown(writer->get(), SHUT_RD));
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_channel.h b/sandbox/linux/syscall_broker/broker_channel.h
new file mode 100644
index 0000000..2abdba4
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_channel.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// A small class to create a pipe-like communication channel. It is based on a
+// SOCK_SEQPACKET unix socket, which is connection-based and guaranteed to
+// preserve message boundaries.
+class BrokerChannel {
+ public:
+  typedef base::ScopedFD EndPoint;
+  static void CreatePair(EndPoint* reader, EndPoint* writer);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BrokerChannel);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc
new file mode 100644
index 0000000..8d04197
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_client.cc
@@ -0,0 +1,144 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_client.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "build/build_config.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+
+#if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC)
+#define MSG_CMSG_CLOEXEC 0x40000000
+#endif
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// Make a remote system call over IPC for syscalls that take a path and flags
+// as arguments, currently open() and access().
+// Will return -errno like a real system call.
+// This function needs to be async signal safe.
+int BrokerClient::PathAndFlagsSyscall(IPCCommand syscall_type,
+                                      const char* pathname,
+                                      int flags) const {
+  int recvmsg_flags = 0;
+  RAW_CHECK(syscall_type == COMMAND_OPEN || syscall_type == COMMAND_ACCESS);
+  if (!pathname)
+    return -EFAULT;
+
+  // For this "remote system call" to work, we need to handle any flag that
+  // cannot be sent over a Unix socket in a special way.
+  // See the comments around kCurrentProcessOpenFlagsMask.
+  if (syscall_type == COMMAND_OPEN && (flags & kCurrentProcessOpenFlagsMask)) {
+    // This implementation only knows about O_CLOEXEC, someone needs to look at
+    // this code if other flags are added.
+    RAW_CHECK(kCurrentProcessOpenFlagsMask == O_CLOEXEC);
+    recvmsg_flags |= MSG_CMSG_CLOEXEC;
+    flags &= ~O_CLOEXEC;
+  }
+
+  // There is no point in forwarding a request that we know will be denied.
+  // Of course, the real security check needs to be on the other side of the
+  // IPC.
+  if (fast_check_in_client_) {
+    if (syscall_type == COMMAND_OPEN &&
+        !broker_policy_.GetFileNameIfAllowedToOpen(
+            pathname, flags, NULL /* file_to_open */,
+            NULL /* unlink_after_open */)) {
+      return -broker_policy_.denied_errno();
+    }
+    if (syscall_type == COMMAND_ACCESS &&
+        !broker_policy_.GetFileNameIfAllowedToAccess(pathname, flags, NULL)) {
+      return -broker_policy_.denied_errno();
+    }
+  }
+
+  Pickle write_pickle;
+  write_pickle.WriteInt(syscall_type);
+  write_pickle.WriteString(pathname);
+  write_pickle.WriteInt(flags);
+  RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
+
+  int returned_fd = -1;
+  uint8_t reply_buf[kMaxMessageLength];
+
+  // Send a request (in write_pickle) as well that will include a new
+  // temporary socketpair (created internally by SendRecvMsg()).
+  // Then read the reply on this new socketpair in reply_buf and put an
+  // eventual attached file descriptor in |returned_fd|.
+  ssize_t msg_len = UnixDomainSocket::SendRecvMsgWithFlags(
+      ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
+      &returned_fd, write_pickle);
+  if (msg_len <= 0) {
+    if (!quiet_failures_for_tests_)
+      RAW_LOG(ERROR, "Could not make request to broker process");
+    return -ENOMEM;
+  }
+
+  Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
+  PickleIterator iter(read_pickle);
+  int return_value = -1;
+  // Now deserialize the return value and eventually return the file
+  // descriptor.
+  if (iter.ReadInt(&return_value)) {
+    switch (syscall_type) {
+      case COMMAND_ACCESS:
+        // We should never have a fd to return.
+        RAW_CHECK(returned_fd == -1);
+        return return_value;
+      case COMMAND_OPEN:
+        if (return_value < 0) {
+          RAW_CHECK(returned_fd == -1);
+          return return_value;
+        } else {
+          // We have a real file descriptor to return.
+          RAW_CHECK(returned_fd >= 0);
+          return returned_fd;
+        }
+      default:
+        RAW_LOG(ERROR, "Unsupported command");
+        return -ENOSYS;
+    }
+  } else {
+    RAW_LOG(ERROR, "Could not read pickle");
+    NOTREACHED();
+    return -ENOMEM;
+  }
+}
+
+BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
+                           BrokerChannel::EndPoint ipc_channel,
+                           bool fast_check_in_client,
+                           bool quiet_failures_for_tests)
+    : broker_policy_(broker_policy),
+      ipc_channel_(ipc_channel.Pass()),
+      fast_check_in_client_(fast_check_in_client),
+      quiet_failures_for_tests_(quiet_failures_for_tests) {
+}
+
+BrokerClient::~BrokerClient() {
+}
+
+int BrokerClient::Access(const char* pathname, int mode) const {
+  return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode);
+}
+
+int BrokerClient::Open(const char* pathname, int flags) const {
+  return PathAndFlagsSyscall(COMMAND_OPEN, pathname, flags);
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_client.h b/sandbox/linux/syscall_broker/broker_client.h
new file mode 100644
index 0000000..2dfef81
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_client.h
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerPolicy;
+
+// This class can be embedded in a sandboxed process and can be
+// used to perform certain system calls in another, presumably
+// non-sandboxed process (which embeds BrokerHost).
+// A key feature of this class is the ability to use some of its methods in a
+// thread-safe and async-signal safe way. The goal is to be able to use it to
+// replace the open() or access() system calls happening anywhere in a process
+// (as allowed for instance by seccomp-bpf's SIGSYS mechanism).
+class BrokerClient {
+ public:
+  // |policy| needs to match the policy used by BrokerHost. This
+  // allows to predict some of the requests which will be denied
+  // and save an IPC round trip.
+  // |ipc_channel| needs to be a suitable SOCK_SEQPACKET unix socket.
+  // |fast_check_in_client| should be set to true and
+  // |quiet_failures_for_tests| to false unless you are writing tests.
+  BrokerClient(const BrokerPolicy& policy,
+               BrokerChannel::EndPoint ipc_channel,
+               bool fast_check_in_client,
+               bool quiet_failures_for_tests);
+  ~BrokerClient();
+
+  // Can be used in place of access().
+  // X_OK will always return an error in practice since the broker process
+  // doesn't support execute permissions.
+  // It's similar to the access() system call and will return -errno on errors.
+  // This is async signal safe.
+  int Access(const char* pathname, int mode) const;
+  // Can be used in place of open().
+  // The implementation only supports certain white listed flags and will
+  // return -EPERM on other flags.
+  // It's similar to the open() system call and will return -errno on errors.
+  // This is async signal safe.
+  int Open(const char* pathname, int flags) const;
+
+  // Get the file descriptor used for IPC. This is used for tests.
+  int GetIPCDescriptor() const { return ipc_channel_.get(); }
+
+ private:
+  const BrokerPolicy& broker_policy_;
+  const BrokerChannel::EndPoint ipc_channel_;
+  const bool fast_check_in_client_;  // Whether to forward a request that we
+                                     // know will be denied to the broker. (Used
+                                     // for tests).
+  const bool quiet_failures_for_tests_;  // Disable certain error message when
+                                         // testing for failures.
+
+  int PathAndFlagsSyscall(IPCCommand syscall_type,
+                          const char* pathname,
+                          int flags) const;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerClient);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  //  SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
diff --git a/sandbox/linux/syscall_broker/broker_common.h b/sandbox/linux/syscall_broker/broker_common.h
new file mode 100644
index 0000000..25aafa7
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_common.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_COMMON_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_COMMON_H_
+
+#include <fcntl.h>
+#include <stddef.h>
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+const size_t kMaxMessageLength = 4096;
+
+// Some flags are local to the current process and cannot be sent over a Unix
+// socket. They need special treatment from the client.
+// O_CLOEXEC is tricky because in theory another thread could call execve()
+// before special treatment is made on the client, so a client needs to call
+// recvmsg(2) with MSG_CMSG_CLOEXEC.
+// To make things worse, there are two CLOEXEC related flags, FD_CLOEXEC (see
+// F_GETFD in fcntl(2)) and O_CLOEXEC (see F_GETFL in fcntl(2)). O_CLOEXEC
+// doesn't affect the semantics on execve(), it's merely a note that the
+// descriptor was originally opened with O_CLOEXEC as a flag. And it is sent
+// over unix sockets just fine, so a receiver that would (incorrectly) look at
+// O_CLOEXEC instead of FD_CLOEXEC may be tricked in thinking that the file
+// descriptor will or won't be closed on execve().
+const int kCurrentProcessOpenFlagsMask = O_CLOEXEC;
+
+enum IPCCommand {
+  COMMAND_INVALID = 0,
+  COMMAND_OPEN,
+  COMMAND_ACCESS,
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_COMMON_H_
diff --git a/sandbox/linux/syscall_broker/broker_file_permission.cc b/sandbox/linux/syscall_broker/broker_file_permission.cc
new file mode 100644
index 0000000..beceda9
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_file_permission.cc
@@ -0,0 +1,243 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
+
+#include <fcntl.h>
+#include <string.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// Async signal safe
+bool BrokerFilePermission::ValidatePath(const char* path) {
+  if (!path)
+    return false;
+
+  const size_t len = strlen(path);
+  // No empty paths
+  if (len == 0)
+    return false;
+  // Paths must be absolute and not relative
+  if (path[0] != '/')
+    return false;
+  // No trailing / (but "/" is valid)
+  if (len > 1 && path[len - 1] == '/')
+    return false;
+  // No trailing /..
+  if (len >= 3 && path[len - 3] == '/' && path[len - 2] == '.' &&
+      path[len - 1] == '.')
+    return false;
+  // No /../ anywhere
+  for (size_t i = 0; i < len; i++) {
+    if (path[i] == '/' && (len - i) > 3) {
+      if (path[i + 1] == '.' && path[i + 2] == '.' && path[i + 3] == '/') {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+// Async signal safe
+// Calls std::string::c_str(), strncmp and strlen. All these
+// methods are async signal safe in common standard libs.
+// TODO(leecam): remove dependency on std::string
+bool BrokerFilePermission::MatchPath(const char* requested_filename) const {
+  const char* path = path_.c_str();
+  if ((recursive_ && strncmp(requested_filename, path, strlen(path)) == 0)) {
+    // Note: This prefix match will allow any path under the whitelisted
+    // path, for any number of directory levels. E.g. if the whitelisted
+    // path is /good/ then the following will be permitted by the policy.
+    //   /good/file1
+    //   /good/folder/file2
+    //   /good/folder/folder2/file3
+    // If an attacker could make 'folder' a symlink to ../../ they would have
+    // access to the entire filesystem.
+    // Whitelisting with multiple depths is useful, e.g /proc/ but
+    // the system needs to ensure symlinks can not be created!
+    // That said if an attacker can convert any of the absolute paths
+    // to a symlink they can control any file on the system also.
+    return true;
+  } else if (strcmp(requested_filename, path) == 0) {
+    return true;
+  }
+  return false;
+}
+
+// Async signal safe.
+// External call to std::string::c_str() is
+// called in MatchPath.
+// TODO(leecam): remove dependency on std::string
+bool BrokerFilePermission::CheckAccess(const char* requested_filename,
+                                       int mode,
+                                       const char** file_to_access) const {
+  // First, check if |mode| is existence, ability to read or ability
+  // to write. We do not support X_OK.
+  if (mode != F_OK && mode & ~(R_OK | W_OK)) {
+    return false;
+  }
+
+  if (!ValidatePath(requested_filename))
+    return false;
+
+  if (!MatchPath(requested_filename)) {
+    return false;
+  }
+  bool allowed = false;
+  switch (mode) {
+    case F_OK:
+      if (allow_read_ || allow_write_)
+        allowed = true;
+      break;
+    case R_OK:
+      if (allow_read_)
+        allowed = true;
+      break;
+    case W_OK:
+      if (allow_write_)
+        allowed = true;
+      break;
+    case R_OK | W_OK:
+      if (allow_read_ && allow_write_)
+        allowed = true;
+      break;
+    default:
+      return false;
+  }
+
+  if (allowed && file_to_access) {
+    if (!recursive_)
+      *file_to_access = path_.c_str();
+    else
+      *file_to_access = requested_filename;
+  }
+  return allowed;
+}
+
+// Async signal safe.
+// External call to std::string::c_str() is
+// called in MatchPath.
+// TODO(leecam): remove dependency on std::string
+bool BrokerFilePermission::CheckOpen(const char* requested_filename,
+                                     int flags,
+                                     const char** file_to_open,
+                                     bool* unlink_after_open) const {
+  if (!ValidatePath(requested_filename))
+    return false;
+
+  if (!MatchPath(requested_filename)) {
+    return false;
+  }
+
+  // First, check the access mode is valid.
+  const int access_mode = flags & O_ACCMODE;
+  if (access_mode != O_RDONLY && access_mode != O_WRONLY &&
+      access_mode != O_RDWR) {
+    return false;
+  }
+
+  // Check if read is allowed
+  if (!allow_read_ && (access_mode == O_RDONLY || access_mode == O_RDWR)) {
+    return false;
+  }
+
+  // Check if write is allowed
+  if (!allow_write_ && (access_mode == O_WRONLY || access_mode == O_RDWR)) {
+    return false;
+  }
+
+  // Check if file creation is allowed.
+  if (!allow_create_ && (flags & O_CREAT)) {
+    return false;
+  }
+
+  // If O_CREAT is present, ensure O_EXCL
+  if ((flags & O_CREAT) && !(flags & O_EXCL)) {
+    return false;
+  }
+
+  // If this file is to be unlinked, ensure it's created.
+  if (unlink_ && !(flags & O_CREAT)) {
+    return false;
+  }
+
+  // Some flags affect the behavior of the current process. We don't support
+  // them and don't allow them for now.
+  if (flags & kCurrentProcessOpenFlagsMask) {
+    return false;
+  }
+
+  // Now check that all the flags are known to us.
+  const int creation_and_status_flags = flags & ~O_ACCMODE;
+
+  const int known_flags = O_APPEND | O_ASYNC | O_CLOEXEC | O_CREAT | O_DIRECT |
+                          O_DIRECTORY | O_EXCL | O_LARGEFILE | O_NOATIME |
+                          O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_NDELAY |
+                          O_SYNC | O_TRUNC;
+
+  const int unknown_flags = ~known_flags;
+  const bool has_unknown_flags = creation_and_status_flags & unknown_flags;
+
+  if (has_unknown_flags)
+    return false;
+
+  if (file_to_open) {
+    if (!recursive_)
+      *file_to_open = path_.c_str();
+    else
+      *file_to_open = requested_filename;
+  }
+  if (unlink_after_open)
+    *unlink_after_open = unlink_;
+
+  return true;
+}
+
+const char* BrokerFilePermission::GetErrorMessageForTests() {
+  static char kInvalidBrokerFileString[] = "Invalid BrokerFilePermission";
+  return kInvalidBrokerFileString;
+}
+
+BrokerFilePermission::BrokerFilePermission(const std::string& path,
+                                           bool recursive,
+                                           bool unlink,
+                                           bool allow_read,
+                                           bool allow_write,
+                                           bool allow_create)
+    : path_(path),
+      recursive_(recursive),
+      unlink_(unlink),
+      allow_read_(allow_read),
+      allow_write_(allow_write),
+      allow_create_(allow_create) {
+  // Validate this permission and die if invalid!
+
+  // Must have enough length for a '/'
+  CHECK(path_.length() > 0) << GetErrorMessageForTests();
+  // Whitelisted paths must be absolute.
+  CHECK(path_[0] == '/') << GetErrorMessageForTests();
+
+  // Don't allow unlinking on creation without create permission
+  if (unlink_) {
+    CHECK(allow_create) << GetErrorMessageForTests();
+  }
+  const char last_char = *(path_.rbegin());
+  // Recursive paths must have a trailing slash
+  if (recursive_) {
+    CHECK(last_char == '/') << GetErrorMessageForTests();
+  } else {
+    CHECK(last_char != '/') << GetErrorMessageForTests();
+  }
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
\ No newline at end of file
diff --git a/sandbox/linux/syscall_broker/broker_file_permission.h b/sandbox/linux/syscall_broker/broker_file_permission.h
new file mode 100644
index 0000000..03300d1
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_file_permission.h
@@ -0,0 +1,119 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_FILE_PERMISSION_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_FILE_PERMISSION_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// BrokerFilePermission defines a path for whitelisting.
+// Pick the correct static factory method to create a permission.
+// CheckOpen and CheckAccess are async signal safe.
+// Constuction and Destruction are not async signal safe.
+// |path| is the path to be whitelisted.
+class SANDBOX_EXPORT BrokerFilePermission {
+ public:
+  ~BrokerFilePermission() {}
+  BrokerFilePermission(const BrokerFilePermission&) = default;
+  BrokerFilePermission& operator=(const BrokerFilePermission&) = default;
+
+  static BrokerFilePermission ReadOnly(const std::string& path) {
+    return BrokerFilePermission(path, false, false, true, false, false);
+  }
+
+  static BrokerFilePermission ReadOnlyRecursive(const std::string& path) {
+    return BrokerFilePermission(path, true, false, true, false, false);
+  }
+
+  static BrokerFilePermission WriteOnly(const std::string& path) {
+    return BrokerFilePermission(path, false, false, false, true, false);
+  }
+
+  static BrokerFilePermission ReadWrite(const std::string& path) {
+    return BrokerFilePermission(path, false, false, true, true, false);
+  }
+
+  static BrokerFilePermission ReadWriteCreate(const std::string& path) {
+    return BrokerFilePermission(path, false, false, true, true, true);
+  }
+
+  static BrokerFilePermission ReadWriteCreateUnlink(const std::string& path) {
+    return BrokerFilePermission(path, false, true, true, true, true);
+  }
+
+  static BrokerFilePermission ReadWriteCreateUnlinkRecursive(
+      const std::string& path) {
+    return BrokerFilePermission(path, true, true, true, true, true);
+  }
+
+  // Returns true if |requested_filename| is allowed to be opened
+  // by this permission.
+  // If |file_to_open| is not NULL it is set to point to either
+  // the |requested_filename| in the case of a recursive match,
+  // or a pointer the matched path in the whitelist if an absolute
+  // match.
+  // If not NULL |unlink_after_open| is set to point to true if the
+  // caller should unlink the path after openning.
+  // Async signal safe if |file_to_open| is NULL.
+  bool CheckOpen(const char* requested_filename,
+                 int flags,
+                 const char** file_to_open,
+                 bool* unlink_after_open) const;
+  // Returns true if |requested_filename| is allowed to be accessed
+  // by this permission as per access(2).
+  // If |file_to_open| is not NULL it is set to point to either
+  // the |requested_filename| in the case of a recursive match,
+  // or a pointer to the matched path in the whitelist if an absolute
+  // match.
+  // |mode| is per mode argument of access(2).
+  // Async signal safe if |file_to_access| is NULL
+  bool CheckAccess(const char* requested_filename,
+                   int mode,
+                   const char** file_to_access) const;
+
+ private:
+  friend class BrokerFilePermissionTester;
+  BrokerFilePermission(const std::string& path,
+                       bool recursive,
+                       bool unlink,
+                       bool allow_read,
+                       bool allow_write,
+                       bool allow_create);
+
+  // ValidatePath checks |path| and returns true if these conditions are met
+  // * Greater than 0 length
+  // * Is an absolute path
+  // * No trailing slash
+  // * No /../ path traversal
+  static bool ValidatePath(const char* path);
+
+  // MatchPath returns true if |requested_filename| is covered by this instance
+  bool MatchPath(const char* requested_filename) const;
+
+  // Used in by BrokerFilePermissionTester for tests.
+  static const char* GetErrorMessageForTests();
+
+  // These are not const as std::vector requires copy-assignment and this class
+  // is stored in vectors. All methods are marked const so
+  // the compiler will still enforce no changes outside of the constructor.
+  std::string path_;
+  bool recursive_;  // Allow everything under this path. |path| must be a dir.
+  bool unlink_;     // unlink after opening.
+  bool allow_read_;
+  bool allow_write_;
+  bool allow_create_;
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  //  SANDBOX_LINUX_SYSCALL_BROKER_BROKER_FILE_PERMISSION_H_
\ No newline at end of file
diff --git a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
new file mode 100644
index 0000000..b58a901
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
@@ -0,0 +1,262 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerFilePermissionTester {
+ public:
+  static bool ValidatePath(const char* path) {
+    return BrokerFilePermission::ValidatePath(path);
+  }
+  static const char* GetErrorMessage() {
+    return BrokerFilePermission::GetErrorMessageForTests();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrokerFilePermissionTester);
+};
+
+namespace {
+
+// Creation tests are DEATH tests as a bad permission causes termination.
+SANDBOX_TEST(BrokerFilePermission, CreateGood) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+SANDBOX_TEST(BrokerFilePermission, CreateGoodRecursive) {
+  const char kPath[] = "/tmp/good/";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBad,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "/tmp/bad/";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBadRecursive,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "/tmp/bad";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBadNotAbs,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "tmp/bad";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBadEmpty,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+// CheckPerm tests |path| against |perm| given |access_flags|.
+// If |create| is true then file creation is tested for success.
+void CheckPerm(const BrokerFilePermission& perm,
+               const char* path,
+               int access_flags,
+               bool create) {
+  const char* file_to_open = NULL;
+
+  ASSERT_FALSE(perm.CheckAccess(path, X_OK, NULL));
+  ASSERT_TRUE(perm.CheckAccess(path, F_OK, NULL));
+  // check bad perms
+  switch (access_flags) {
+    case O_RDONLY:
+      ASSERT_TRUE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, R_OK, NULL));
+      ASSERT_FALSE(perm.CheckAccess(path, W_OK, NULL));
+      break;
+    case O_WRONLY:
+      ASSERT_FALSE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckAccess(path, R_OK, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, W_OK, NULL));
+      break;
+    case O_RDWR:
+      ASSERT_TRUE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, R_OK, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, W_OK, NULL));
+      break;
+    default:
+      // Bad test case
+      NOTREACHED();
+  }
+
+// O_SYNC can be defined as (__O_SYNC|O_DSYNC)
+#ifdef O_DSYNC
+  const int kSyncFlag = O_SYNC & ~O_DSYNC;
+#else
+  const int kSyncFlag = O_SYNC;
+#endif
+
+  const int kNumberOfBitsInOAccMode = 2;
+  static_assert(O_ACCMODE == ((1 << kNumberOfBitsInOAccMode) - 1),
+                "incorrect number of bits");
+  // check every possible flag and act accordingly.
+  // Skipping AccMode bits as they are present in every case.
+  for (int i = kNumberOfBitsInOAccMode; i < 32; i++) {
+    int flag = 1 << i;
+    switch (flag) {
+      case O_APPEND:
+      case O_ASYNC:
+      case O_DIRECT:
+      case O_DIRECTORY:
+#ifdef O_DSYNC
+      case O_DSYNC:
+#endif
+      case O_EXCL:
+      case O_LARGEFILE:
+      case O_NOATIME:
+      case O_NOCTTY:
+      case O_NOFOLLOW:
+      case O_NONBLOCK:
+#if (O_NONBLOCK != O_NDELAY)
+      case O_NDELAY:
+#endif
+      case kSyncFlag:
+      case O_TRUNC:
+        ASSERT_TRUE(
+            perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
+        break;
+      case O_CLOEXEC:
+      case O_CREAT:
+      default:
+        ASSERT_FALSE(
+            perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
+    }
+  }
+  if (create) {
+    bool unlink;
+    ASSERT_TRUE(perm.CheckOpen(path, O_CREAT | O_EXCL | access_flags,
+                               &file_to_open, &unlink));
+    ASSERT_FALSE(unlink);
+  } else {
+    ASSERT_FALSE(perm.CheckOpen(path, O_CREAT | O_EXCL | access_flags,
+                                &file_to_open, NULL));
+  }
+}
+
+TEST(BrokerFilePermission, ReadOnly) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+  CheckPerm(perm, kPath, O_RDONLY, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadOnlyRecursive) {
+  const char kPath[] = "/tmp/good/";
+  const char kPathFile[] = "/tmp/good/file";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
+  CheckPerm(perm, kPathFile, O_RDONLY, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, WriteOnly) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::WriteOnly(kPath);
+  CheckPerm(perm, kPath, O_WRONLY, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadWrite) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadWrite(kPath);
+  CheckPerm(perm, kPath, O_RDWR, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadWriteCreate) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadWriteCreate(kPath);
+  CheckPerm(perm, kPath, O_RDWR, true);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+void CheckUnlink(BrokerFilePermission& perm,
+                 const char* path,
+                 int access_flags) {
+  bool unlink;
+  ASSERT_FALSE(perm.CheckOpen(path, access_flags, NULL, &unlink));
+  ASSERT_FALSE(perm.CheckOpen(path, access_flags | O_CREAT, NULL, &unlink));
+  ASSERT_TRUE(
+      perm.CheckOpen(path, access_flags | O_CREAT | O_EXCL, NULL, &unlink));
+  ASSERT_TRUE(unlink);
+}
+
+TEST(BrokerFilePermission, ReadWriteCreateUnlink) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm =
+      BrokerFilePermission::ReadWriteCreateUnlink(kPath);
+  CheckUnlink(perm, kPath, O_RDWR);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadWriteCreateUnlinkRecursive) {
+  const char kPath[] = "/tmp/good/";
+  const char kPathFile[] = "/tmp/good/file";
+  BrokerFilePermission perm =
+      BrokerFilePermission::ReadWriteCreateUnlinkRecursive(kPath);
+  CheckUnlink(perm, kPathFile, O_RDWR);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ValidatePath) {
+  EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/path"));
+  EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/"));
+  EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/..path"));
+
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath(""));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("bad"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("bad/"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/.."));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/../bad"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/../bad"));
+}
+
+}  // namespace
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
new file mode 100644
index 0000000..fe28b47
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -0,0 +1,231 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_host.h"
+
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+namespace {
+
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+// A little open(2) wrapper to handle some oddities for us. In the general case
+// make a direct system call since we want to keep in control of the broker
+// process' system calls profile to be able to loosely sandbox it.
+int sys_open(const char* pathname, int flags) {
+  // Hardcode mode to rw------- when creating files.
+  int mode;
+  if (flags & O_CREAT) {
+    mode = 0600;
+  } else {
+    mode = 0;
+  }
+  if (IsRunningOnValgrind()) {
+    // Valgrind does not support AT_FDCWD, just use libc's open() in this case.
+    return open(pathname, flags, mode);
+  } else {
+    return syscall(__NR_openat, AT_FDCWD, pathname, flags, mode);
+  }
+}
+
+// Open |requested_filename| with |flags| if allowed by our policy.
+// Write the syscall return value (-errno) to |write_pickle| and append
+// a file descriptor to |opened_files| if relevant.
+void OpenFileForIPC(const BrokerPolicy& policy,
+                    const std::string& requested_filename,
+                    int flags,
+                    Pickle* write_pickle,
+                    std::vector<int>* opened_files) {
+  DCHECK(write_pickle);
+  DCHECK(opened_files);
+  const char* file_to_open = NULL;
+  bool unlink_after_open = false;
+  const bool safe_to_open_file = policy.GetFileNameIfAllowedToOpen(
+      requested_filename.c_str(), flags, &file_to_open, &unlink_after_open);
+
+  if (safe_to_open_file) {
+    CHECK(file_to_open);
+    int opened_fd = sys_open(file_to_open, flags);
+    if (opened_fd < 0) {
+      write_pickle->WriteInt(-errno);
+    } else {
+      // Success.
+      if (unlink_after_open) {
+        unlink(file_to_open);
+      }
+      opened_files->push_back(opened_fd);
+      write_pickle->WriteInt(0);
+    }
+  } else {
+    write_pickle->WriteInt(-policy.denied_errno());
+  }
+}
+
+// Perform access(2) on |requested_filename| with mode |mode| if allowed by our
+// policy. Write the syscall return value (-errno) to |write_pickle|.
+void AccessFileForIPC(const BrokerPolicy& policy,
+                      const std::string& requested_filename,
+                      int mode,
+                      Pickle* write_pickle) {
+  DCHECK(write_pickle);
+  const char* file_to_access = NULL;
+  const bool safe_to_access_file = policy.GetFileNameIfAllowedToAccess(
+      requested_filename.c_str(), mode, &file_to_access);
+
+  if (safe_to_access_file) {
+    CHECK(file_to_access);
+    int access_ret = access(file_to_access, mode);
+    int access_errno = errno;
+    if (!access_ret)
+      write_pickle->WriteInt(0);
+    else
+      write_pickle->WriteInt(-access_errno);
+  } else {
+    write_pickle->WriteInt(-policy.denied_errno());
+  }
+}
+
+// Handle a |command_type| request contained in |iter| and send the reply
+// on |reply_ipc|.
+// Currently COMMAND_OPEN and COMMAND_ACCESS are supported.
+bool HandleRemoteCommand(const BrokerPolicy& policy,
+                         IPCCommand command_type,
+                         int reply_ipc,
+                         PickleIterator iter) {
+  // Currently all commands have two arguments: filename and flags.
+  std::string requested_filename;
+  int flags = 0;
+  if (!iter.ReadString(&requested_filename) || !iter.ReadInt(&flags))
+    return false;
+
+  Pickle write_pickle;
+  std::vector<int> opened_files;
+
+  switch (command_type) {
+    case COMMAND_ACCESS:
+      AccessFileForIPC(policy, requested_filename, flags, &write_pickle);
+      break;
+    case COMMAND_OPEN:
+      OpenFileForIPC(
+          policy, requested_filename, flags, &write_pickle, &opened_files);
+      break;
+    default:
+      LOG(ERROR) << "Invalid IPC command";
+      break;
+  }
+
+  CHECK_LE(write_pickle.size(), kMaxMessageLength);
+  ssize_t sent = UnixDomainSocket::SendMsg(
+      reply_ipc, write_pickle.data(), write_pickle.size(), opened_files);
+
+  // Close anything we have opened in this process.
+  for (std::vector<int>::iterator it = opened_files.begin();
+       it != opened_files.end();
+       ++it) {
+    int ret = IGNORE_EINTR(close(*it));
+    DCHECK(!ret) << "Could not close file descriptor";
+  }
+
+  if (sent <= 0) {
+    LOG(ERROR) << "Could not send IPC reply";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+BrokerHost::BrokerHost(const BrokerPolicy& broker_policy,
+                       BrokerChannel::EndPoint ipc_channel)
+    : broker_policy_(broker_policy), ipc_channel_(ipc_channel.Pass()) {
+}
+
+BrokerHost::~BrokerHost() {
+}
+
+// Handle a request on the IPC channel ipc_channel_.
+// A request should have a file descriptor attached on which we will reply and
+// that we will then close.
+// A request should start with an int that will be used as the command type.
+BrokerHost::RequestStatus BrokerHost::HandleRequest() const {
+  ScopedVector<base::ScopedFD> fds;
+  char buf[kMaxMessageLength];
+  errno = 0;
+  const ssize_t msg_len =
+      UnixDomainSocket::RecvMsg(ipc_channel_.get(), buf, sizeof(buf), &fds);
+
+  if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) {
+    // EOF from the client, or the client died, we should die.
+    return RequestStatus::LOST_CLIENT;
+  }
+
+  // The client should send exactly one file descriptor, on which we
+  // will write the reply.
+  // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'.
+  if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) {
+    PLOG(ERROR) << "Error reading message from the client";
+    return RequestStatus::FAILURE;
+  }
+
+  base::ScopedFD temporary_ipc(fds[0]->Pass());
+
+  Pickle pickle(buf, msg_len);
+  PickleIterator iter(pickle);
+  int command_type;
+  if (iter.ReadInt(&command_type)) {
+    bool command_handled = false;
+    // Go through all the possible IPC messages.
+    switch (command_type) {
+      case COMMAND_ACCESS:
+      case COMMAND_OPEN:
+        // We reply on the file descriptor sent to us via the IPC channel.
+        command_handled = HandleRemoteCommand(
+            broker_policy_, static_cast<IPCCommand>(command_type),
+            temporary_ipc.get(), iter);
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+
+    if (command_handled) {
+      return RequestStatus::SUCCESS;
+    } else {
+      return RequestStatus::FAILURE;
+    }
+
+    NOTREACHED();
+  }
+
+  LOG(ERROR) << "Error parsing IPC request";
+  return RequestStatus::FAILURE;
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_host.h b/sandbox/linux/syscall_broker/broker_host.h
new file mode 100644
index 0000000..9866507
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_host.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerPolicy;
+
+// The BrokerHost class should be embedded in a (presumably not sandboxed)
+// process. It will honor IPC requests from a BrokerClient sent over
+// |ipc_channel| according to |broker_policy|.
+class BrokerHost {
+ public:
+  enum class RequestStatus { LOST_CLIENT = 0, SUCCESS, FAILURE };
+
+  BrokerHost(const BrokerPolicy& broker_policy,
+             BrokerChannel::EndPoint ipc_channel);
+  ~BrokerHost();
+
+  RequestStatus HandleRequest() const;
+
+ private:
+  const BrokerPolicy& broker_policy_;
+  const BrokerChannel::EndPoint ipc_channel_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerHost);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  //  SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
diff --git a/sandbox/linux/syscall_broker/broker_policy.cc b/sandbox/linux/syscall_broker/broker_policy.cc
new file mode 100644
index 0000000..d9f69e3
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_policy.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+
+namespace sandbox {
+namespace syscall_broker {
+
+BrokerPolicy::BrokerPolicy(int denied_errno,
+                           const std::vector<BrokerFilePermission>& permissions)
+    : denied_errno_(denied_errno),
+      permissions_(permissions),
+      num_of_permissions_(permissions.size()) {
+  // The spec guarantees vectors store their elements contiguously
+  // so set up a pointer to array of element so it can be used
+  // in async signal safe code instead of vector operations.
+  if (num_of_permissions_ > 0) {
+    permissions_array_ = &permissions_[0];
+  } else {
+    permissions_array_ = NULL;
+  }
+}
+
+BrokerPolicy::~BrokerPolicy() {
+}
+
+// Check if calling access() should be allowed on |requested_filename| with
+// mode |requested_mode|.
+// Note: access() being a system call to check permissions, this can get a bit
+// confusing. We're checking if calling access() should even be allowed with
+// the same policy we would use for open().
+// If |file_to_access| is not NULL, we will return the matching pointer from
+// the whitelist. For paranoia a caller should then use |file_to_access|. See
+// GetFileNameIfAllowedToOpen() for more explanation.
+// return true if calling access() on this file should be allowed, false
+// otherwise.
+// Async signal safe if and only if |file_to_access| is NULL.
+bool BrokerPolicy::GetFileNameIfAllowedToAccess(
+    const char* requested_filename,
+    int requested_mode,
+    const char** file_to_access) const {
+  if (file_to_access && *file_to_access) {
+    // Make sure that callers never pass a non-empty string. In case callers
+    // wrongly forget to check the return value and look at the string
+    // instead, this could catch bugs.
+    RAW_LOG(FATAL, "*file_to_access should be NULL");
+    return false;
+  }
+  for (size_t i = 0; i < num_of_permissions_; i++) {
+    if (permissions_array_[i].CheckAccess(requested_filename, requested_mode,
+                                          file_to_access)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Check if |requested_filename| can be opened with flags |requested_flags|.
+// If |file_to_open| is not NULL, we will return the matching pointer from the
+// whitelist. For paranoia, a caller should then use |file_to_open| rather
+// than |requested_filename|, so that it never attempts to open an
+// attacker-controlled file name, even if an attacker managed to fool the
+// string comparison mechanism.
+// Return true if opening should be allowed, false otherwise.
+// Async signal safe if and only if |file_to_open| is NULL.
+bool BrokerPolicy::GetFileNameIfAllowedToOpen(const char* requested_filename,
+                                              int requested_flags,
+                                              const char** file_to_open,
+                                              bool* unlink_after_open) const {
+  if (file_to_open && *file_to_open) {
+    // Make sure that callers never pass a non-empty string. In case callers
+    // wrongly forget to check the return value and look at the string
+    // instead, this could catch bugs.
+    RAW_LOG(FATAL, "*file_to_open should be NULL");
+    return false;
+  }
+  for (size_t i = 0; i < num_of_permissions_; i++) {
+    if (permissions_array_[i].CheckOpen(requested_filename, requested_flags,
+                                        file_to_open, unlink_after_open)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_policy.h b/sandbox/linux/syscall_broker/broker_policy.h
new file mode 100644
index 0000000..d5146ed
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_policy.h
@@ -0,0 +1,87 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_POLICY_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_POLICY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
+
+namespace sandbox {
+namespace syscall_broker {
+
+// BrokerPolicy allows to define the security policy enforced by a
+// BrokerHost. The BrokerHost will evaluate requests sent over its
+// IPC channel according to the BrokerPolicy.
+// Some of the methods of this class can be used in an async-signal safe
+// way.
+class BrokerPolicy {
+ public:
+  // |denied_errno| is the error code returned when IPC requests for system
+  // calls such as open() or access() are denied because a file is not in the
+  // whitelist. EACCESS would be a typical value.
+  // |permissions| is a list of BrokerPermission objects that define
+  // what the broker will allow.
+  BrokerPolicy(int denied_errno,
+               const std::vector<BrokerFilePermission>& permissions);
+
+  ~BrokerPolicy();
+
+  // Check if calling access() should be allowed on |requested_filename| with
+  // mode |requested_mode|.
+  // Note: access() being a system call to check permissions, this can get a bit
+  // confusing. We're checking if calling access() should even be allowed with
+  // If |file_to_open| is not NULL, a pointer to the path will be returned.
+  // In the case of a recursive match, this will be the requested_filename,
+  // otherwise it will return the matching pointer from the
+  // whitelist. For paranoia a caller should then use |file_to_access|. See
+  // GetFileNameIfAllowedToOpen() for more explanation.
+  // return true if calling access() on this file should be allowed, false
+  // otherwise.
+  // Async signal safe if and only if |file_to_access| is NULL.
+  bool GetFileNameIfAllowedToAccess(const char* requested_filename,
+                                    int requested_mode,
+                                    const char** file_to_access) const;
+
+  // Check if |requested_filename| can be opened with flags |requested_flags|.
+  // If |file_to_open| is not NULL, a pointer to the path will be returned.
+  // In the case of a recursive match, this will be the requested_filename,
+  // otherwise it will return the matching pointer from the
+  // whitelist. For paranoia, a caller should then use |file_to_open| rather
+  // than |requested_filename|, so that it never attempts to open an
+  // attacker-controlled file name, even if an attacker managed to fool the
+  // string comparison mechanism.
+  // |unlink_after_open| if not NULL will be set to point to true if the
+  // policy requests the caller unlink the path after opening.
+  // Return true if opening should be allowed, false otherwise.
+  // Async signal safe if and only if |file_to_open| is NULL.
+  bool GetFileNameIfAllowedToOpen(const char* requested_filename,
+                                  int requested_flags,
+                                  const char** file_to_open,
+                                  bool* unlink_after_open) const;
+  int denied_errno() const { return denied_errno_; }
+
+ private:
+  const int denied_errno_;
+  // The permissions_ vector is used as storage for the BrokerFilePermission
+  // objects but is not referenced outside of the constructor as
+  // vectors are unfriendly in async signal safe code.
+  const std::vector<BrokerFilePermission> permissions_;
+  // permissions_array_ is set up to point to the backing store of
+  // permissions_ and is used in async signal safe methods.
+  const BrokerFilePermission* permissions_array_;
+  const size_t num_of_permissions_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerPolicy);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_POLICY_H_
diff --git a/sandbox/linux/syscall_broker/broker_process.cc b/sandbox/linux/syscall_broker/broker_process.cc
new file mode 100644
index 0000000..81131cc
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_process.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_process.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "build/build_config.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+#include "sandbox/linux/syscall_broker/broker_client.h"
+#include "sandbox/linux/syscall_broker/broker_host.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+BrokerProcess::BrokerProcess(
+    int denied_errno,
+    const std::vector<syscall_broker::BrokerFilePermission>& permissions,
+    bool fast_check_in_client,
+    bool quiet_failures_for_tests)
+    : initialized_(false),
+      fast_check_in_client_(fast_check_in_client),
+      quiet_failures_for_tests_(quiet_failures_for_tests),
+      broker_pid_(-1),
+      policy_(denied_errno, permissions) {
+}
+
+BrokerProcess::~BrokerProcess() {
+  if (initialized_) {
+    if (broker_client_.get()) {
+      // Closing the socket should be enough to notify the child to die,
+      // unless it has been duplicated.
+      CloseChannel();
+    }
+    PCHECK(0 == kill(broker_pid_, SIGKILL));
+    siginfo_t process_info;
+    // Reap the child.
+    int ret = HANDLE_EINTR(waitid(P_PID, broker_pid_, &process_info, WEXITED));
+    PCHECK(0 == ret);
+  }
+}
+
+bool BrokerProcess::Init(
+    const base::Callback<bool(void)>& broker_process_init_callback) {
+  CHECK(!initialized_);
+  BrokerChannel::EndPoint ipc_reader;
+  BrokerChannel::EndPoint ipc_writer;
+  BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
+
+#if !defined(THREAD_SANITIZER)
+  DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
+#endif
+  int child_pid = fork();
+  if (child_pid == -1) {
+    return false;
+  }
+  if (child_pid) {
+    // We are the parent and we have just forked our broker process.
+    ipc_reader.reset();
+    broker_pid_ = child_pid;
+    broker_client_.reset(new BrokerClient(policy_, ipc_writer.Pass(),
+                                          fast_check_in_client_,
+                                          quiet_failures_for_tests_));
+    initialized_ = true;
+    return true;
+  } else {
+    // We are the broker process. Make sure to close the writer's end so that
+    // we get notified if the client disappears.
+    ipc_writer.reset();
+    CHECK(broker_process_init_callback.Run());
+    BrokerHost broker_host(policy_, ipc_reader.Pass());
+    for (;;) {
+      switch (broker_host.HandleRequest()) {
+        case BrokerHost::RequestStatus::LOST_CLIENT:
+          _exit(1);
+        case BrokerHost::RequestStatus::SUCCESS:
+        case BrokerHost::RequestStatus::FAILURE:
+          continue;
+      }
+    }
+    _exit(1);
+  }
+  NOTREACHED();
+  return false;
+}
+
+void BrokerProcess::CloseChannel() {
+  broker_client_.reset();
+}
+
+int BrokerProcess::Access(const char* pathname, int mode) const {
+  RAW_CHECK(initialized_);
+  return broker_client_->Access(pathname, mode);
+}
+
+int BrokerProcess::Open(const char* pathname, int flags) const {
+  RAW_CHECK(initialized_);
+  return broker_client_->Open(pathname, flags);
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox.
diff --git a/sandbox/linux/syscall_broker/broker_process.h b/sandbox/linux/syscall_broker/broker_process.h
new file mode 100644
index 0000000..8a512a0
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_process.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
+#define SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/process/process.h"
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerClient;
+class BrokerFilePermission;
+
+// Create a new "broker" process to which we can send requests via an IPC
+// channel by forking the current process.
+// This is a low level IPC mechanism that is suitable to be called from a
+// signal handler.
+// A process would typically create a broker process before entering
+// sandboxing.
+// 1. BrokerProcess open_broker(read_whitelist, write_whitelist);
+// 2. CHECK(open_broker.Init(NULL));
+// 3. Enable sandbox.
+// 4. Use open_broker.Open() to open files.
+class SANDBOX_EXPORT BrokerProcess {
+ public:
+  // |denied_errno| is the error code returned when methods such as Open()
+  // or Access() are invoked on a file which is not in the whitelist. EACCESS
+  // would be a typical value.
+  // |allowed_r_files| and |allowed_w_files| are white lists of files that can
+  // be opened later via the Open() API, respectively for reading and writing.
+  // A file available read-write should be listed in both.
+  // |fast_check_in_client| and |quiet_failures_for_tests| are reserved for
+  // unit tests, don't use it.
+
+  BrokerProcess(
+      int denied_errno,
+      const std::vector<syscall_broker::BrokerFilePermission>& permissions,
+      bool fast_check_in_client = true,
+      bool quiet_failures_for_tests = false);
+
+  ~BrokerProcess();
+  // Will initialize the broker process. There should be no threads at this
+  // point, since we need to fork().
+  // broker_process_init_callback will be called in the new broker process,
+  // after fork() returns.
+  bool Init(const base::Callback<bool(void)>& broker_process_init_callback);
+
+  // Can be used in place of access(). Will be async signal safe.
+  // X_OK will always return an error in practice since the broker process
+  // doesn't support execute permissions.
+  // It's similar to the access() system call and will return -errno on errors.
+  int Access(const char* pathname, int mode) const;
+  // Can be used in place of open(). Will be async signal safe.
+  // The implementation only supports certain white listed flags and will
+  // return -EPERM on other flags.
+  // It's similar to the open() system call and will return -errno on errors.
+  int Open(const char* pathname, int flags) const;
+
+  int broker_pid() const { return broker_pid_; }
+
+ private:
+  friend class BrokerProcessTestHelper;
+
+  // Close the IPC channel with the other party. This should only be used
+  // by tests an none of the class methods should be used afterwards.
+  void CloseChannel();
+
+  bool initialized_;  // Whether we've been through Init() yet.
+  const bool fast_check_in_client_;
+  const bool quiet_failures_for_tests_;
+  pid_t broker_pid_;                     // The PID of the broker (child).
+  syscall_broker::BrokerPolicy policy_;  // The sandboxing policy.
+  scoped_ptr<syscall_broker::BrokerClient> broker_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerProcess);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc
new file mode 100644
index 0000000..bd7ef27
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -0,0 +1,656 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_process.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_client.h"
+#include "sandbox/linux/tests/scoped_temporary_file.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerProcessTestHelper {
+ public:
+  static void CloseChannel(BrokerProcess* broker) { broker->CloseChannel(); }
+  // Get the client's IPC descriptor to send IPC requests directly.
+  // TODO(jln): refator tests to get rid of this.
+  static int GetIPCDescriptor(const BrokerProcess* broker) {
+    return broker->broker_client_->GetIPCDescriptor();
+  }
+};
+
+namespace {
+
+bool NoOpCallback() {
+  return true;
+}
+
+}  // namespace
+
+TEST(BrokerProcess, CreateAndDestroy) {
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
+
+  scoped_ptr<BrokerProcess> open_broker(new BrokerProcess(EPERM, permissions));
+  ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
+
+  ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
+  // Destroy the broker and check it has exited properly.
+  open_broker.reset();
+  ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
+}
+
+TEST(BrokerProcess, TestOpenAccessNull) {
+  std::vector<BrokerFilePermission> empty;
+  BrokerProcess open_broker(EPERM, empty);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  int fd = open_broker.Open(NULL, O_RDONLY);
+  ASSERT_EQ(fd, -EFAULT);
+
+  int ret = open_broker.Access(NULL, F_OK);
+  ASSERT_EQ(ret, -EFAULT);
+}
+
+void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) {
+  const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1";
+  // We can't debug the init process, and shouldn't be able to access
+  // its auxv file.
+  const char kR_WhiteListedButDenied[] = "/proc/1/auxv";
+  const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2";
+  const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3";
+  const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4";
+
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kR_WhiteListed));
+  permissions.push_back(
+      BrokerFilePermission::ReadOnly(kR_WhiteListedButDenied));
+  permissions.push_back(BrokerFilePermission::WriteOnly(kW_WhiteListed));
+  permissions.push_back(BrokerFilePermission::ReadWrite(kRW_WhiteListed));
+
+  BrokerProcess open_broker(denied_errno, permissions, fast_check_in_client);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  int fd = -1;
+  fd = open_broker.Open(kR_WhiteListed, O_RDONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kR_WhiteListed, O_WRONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(kR_WhiteListed, O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+  int ret = -1;
+  ret = open_broker.Access(kR_WhiteListed, F_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kR_WhiteListed, R_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kR_WhiteListed, W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kR_WhiteListed, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  // Android sometimes runs tests as root.
+  // This part of the test requires a process that doesn't have
+  // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
+  if (geteuid()) {
+    fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY);
+    // The broker process will allow this, but the normal permission system
+    // won't.
+    ASSERT_EQ(fd, -EACCES);
+    fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY);
+    ASSERT_EQ(fd, -denied_errno);
+    fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR);
+    ASSERT_EQ(fd, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, F_OK);
+    // The normal permission system will let us check that the file exists.
+    ASSERT_EQ(ret, 0);
+    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK);
+    ASSERT_EQ(ret, -EACCES);
+    ret = open_broker.Access(kR_WhiteListedButDenied, W_OK);
+    ASSERT_EQ(ret, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK);
+    ASSERT_EQ(ret, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, X_OK);
+    ASSERT_EQ(ret, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK);
+    ASSERT_EQ(ret, -denied_errno);
+  }
+
+  fd = open_broker.Open(kW_WhiteListed, O_RDONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(kW_WhiteListed, O_WRONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kW_WhiteListed, O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, F_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kW_WhiteListed, R_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, W_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  fd = open_broker.Open(kRW_WhiteListed, O_RDONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kRW_WhiteListed, O_WRONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kRW_WhiteListed, O_RDWR);
+  ASSERT_EQ(fd, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, F_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, R_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, W_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  fd = open_broker.Open(k_NotWhitelisted, O_RDONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(k_NotWhitelisted, O_WRONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(k_NotWhitelisted, O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, F_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, R_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  // We have some extra sanity check for clearly wrong values.
+  fd = open_broker.Open(kRW_WhiteListed, O_RDONLY | O_WRONLY | O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+
+  // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
+  // is denied.
+  fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT);
+  ASSERT_EQ(fd, -denied_errno);
+}
+
+// Run the same thing twice. The second time, we make sure that no security
+// check is performed on the client.
+TEST(BrokerProcess, OpenFilePermsWithClientCheck) {
+  TestOpenFilePerms(true /* fast_check_in_client */, EPERM);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) {
+  TestOpenFilePerms(false /* fast_check_in_client */, EPERM);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+// Run the same twice again, but with ENOENT instead of EPERM.
+TEST(BrokerProcess, OpenFilePermsWithClientCheckNoEnt) {
+  TestOpenFilePerms(true /* fast_check_in_client */, ENOENT);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) {
+  TestOpenFilePerms(false /* fast_check_in_client */, ENOENT);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+void TestBadPaths(bool fast_check_in_client) {
+  const char kFileCpuInfo[] = "/proc/cpuinfo";
+  const char kNotAbsPath[] = "proc/cpuinfo";
+  const char kDotDotStart[] = "/../proc/cpuinfo";
+  const char kDotDotMiddle[] = "/proc/self/../cpuinfo";
+  const char kDotDotEnd[] = "/proc/..";
+  const char kTrailingSlash[] = "/proc/";
+
+  std::vector<BrokerFilePermission> permissions;
+
+  permissions.push_back(BrokerFilePermission::ReadOnlyRecursive("/proc/"));
+  scoped_ptr<BrokerProcess> open_broker(
+      new BrokerProcess(EPERM, permissions, fast_check_in_client));
+  ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
+  // Open cpuinfo via the broker.
+  int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
+  base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd);
+  ASSERT_GE(cpuinfo_fd, 0);
+
+  int fd = -1;
+  int can_access;
+
+  can_access = open_broker->Access(kNotAbsPath, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kNotAbsPath, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kDotDotStart, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kDotDotStart, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kDotDotMiddle, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kDotDotMiddle, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kDotDotEnd, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kDotDotEnd, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kTrailingSlash, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kTrailingSlash, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+}
+
+TEST(BrokerProcess, BadPathsClientCheck) {
+  TestBadPaths(true /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, BadPathsNoClientCheck) {
+  TestBadPaths(false /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+void TestOpenCpuinfo(bool fast_check_in_client, bool recursive) {
+  const char kFileCpuInfo[] = "/proc/cpuinfo";
+  const char kDirProc[] = "/proc/";
+
+  std::vector<BrokerFilePermission> permissions;
+  if (recursive)
+    permissions.push_back(BrokerFilePermission::ReadOnlyRecursive(kDirProc));
+  else
+    permissions.push_back(BrokerFilePermission::ReadOnly(kFileCpuInfo));
+
+  scoped_ptr<BrokerProcess> open_broker(
+      new BrokerProcess(EPERM, permissions, fast_check_in_client));
+  ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
+
+  int fd = -1;
+  fd = open_broker->Open(kFileCpuInfo, O_RDWR);
+  base::ScopedFD fd_closer(fd);
+  ASSERT_EQ(fd, -EPERM);
+
+  // Check we can read /proc/cpuinfo.
+  int can_access = open_broker->Access(kFileCpuInfo, R_OK);
+  ASSERT_EQ(can_access, 0);
+  can_access = open_broker->Access(kFileCpuInfo, W_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  // Check we can not write /proc/cpuinfo.
+
+  // Open cpuinfo via the broker.
+  int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
+  base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd);
+  ASSERT_GE(cpuinfo_fd, 0);
+  char buf[3];
+  memset(buf, 0, sizeof(buf));
+  int read_len1 = read(cpuinfo_fd, buf, sizeof(buf));
+  ASSERT_GT(read_len1, 0);
+
+  // Open cpuinfo directly.
+  int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY);
+  base::ScopedFD cpuinfo_fd2_closer(cpuinfo_fd2);
+  ASSERT_GE(cpuinfo_fd2, 0);
+  char buf2[3];
+  memset(buf2, 1, sizeof(buf2));
+  int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2));
+  ASSERT_GT(read_len1, 0);
+
+  // The following is not guaranteed true, but will be in practice.
+  ASSERT_EQ(read_len1, read_len2);
+  // Compare the cpuinfo as returned by the broker with the one we opened
+  // ourselves.
+  ASSERT_EQ(memcmp(buf, buf2, read_len1), 0);
+
+  ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
+  open_broker.reset();
+  ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
+}
+
+// Run this test 4 times. With and without the check in client
+// and using a recursive path.
+TEST(BrokerProcess, OpenCpuinfoWithClientCheck) {
+  TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenCpuinfoNoClientCheck) {
+  TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenCpuinfoWithClientCheckRecursive) {
+  TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenCpuinfoNoClientCheckRecursive) {
+  TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenFileRW) {
+  ScopedTemporaryFile tempfile;
+  const char* tempfile_name = tempfile.full_file_name();
+
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadWrite(tempfile_name));
+
+  BrokerProcess open_broker(EPERM, permissions);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  // Check we can access that file with read or write.
+  int can_access = open_broker.Access(tempfile_name, R_OK | W_OK);
+  ASSERT_EQ(can_access, 0);
+
+  int tempfile2 = -1;
+  tempfile2 = open_broker.Open(tempfile_name, O_RDWR);
+  ASSERT_GE(tempfile2, 0);
+
+  // Write to the descriptor opened by the broker.
+  char test_text[] = "TESTTESTTEST";
+  ssize_t len = write(tempfile2, test_text, sizeof(test_text));
+  ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
+
+  // Read back from the original file descriptor what we wrote through
+  // the descriptor provided by the broker.
+  char buf[1024];
+  len = read(tempfile.fd(), buf, sizeof(buf));
+
+  ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
+  ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0);
+
+  ASSERT_EQ(close(tempfile2), 0);
+}
+
+// SANDBOX_TEST because the process could die with a SIGPIPE
+// and we want this to happen in a subprocess.
+SANDBOX_TEST(BrokerProcess, BrokerDied) {
+  const char kCpuInfo[] = "/proc/cpuinfo";
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo));
+
+  BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */,
+                            true /* quiet_failures_for_tests */);
+  SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
+  const pid_t broker_pid = open_broker.broker_pid();
+  SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0);
+
+  // Now we check that the broker has been signaled, but do not reap it.
+  siginfo_t process_info;
+  SANDBOX_ASSERT(HANDLE_EINTR(waitid(
+                     P_PID, broker_pid, &process_info, WEXITED | WNOWAIT)) ==
+                 0);
+  SANDBOX_ASSERT(broker_pid == process_info.si_pid);
+  SANDBOX_ASSERT(CLD_KILLED == process_info.si_code);
+  SANDBOX_ASSERT(SIGKILL == process_info.si_status);
+
+  // Check that doing Open with a dead broker won't SIGPIPE us.
+  SANDBOX_ASSERT(open_broker.Open(kCpuInfo, O_RDONLY) == -ENOMEM);
+  SANDBOX_ASSERT(open_broker.Access(kCpuInfo, O_RDONLY) == -ENOMEM);
+}
+
+void TestOpenComplexFlags(bool fast_check_in_client) {
+  const char kCpuInfo[] = "/proc/cpuinfo";
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo));
+
+  BrokerProcess open_broker(EPERM, permissions, fast_check_in_client);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+  // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
+  int fd = -1;
+  int ret = 0;
+  fd = open_broker.Open(kCpuInfo, O_RDONLY);
+  ASSERT_GE(fd, 0);
+  ret = fcntl(fd, F_GETFL);
+  ASSERT_NE(-1, ret);
+  // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
+  ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK));
+  ASSERT_EQ(0, close(fd));
+
+  fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC);
+  ASSERT_GE(fd, 0);
+  ret = fcntl(fd, F_GETFD);
+  ASSERT_NE(-1, ret);
+  // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
+  // is actually not used by the kernel.
+  ASSERT_TRUE(FD_CLOEXEC & ret);
+  ASSERT_EQ(0, close(fd));
+
+  fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK);
+  ASSERT_GE(fd, 0);
+  ret = fcntl(fd, F_GETFL);
+  ASSERT_NE(-1, ret);
+  ASSERT_TRUE(O_NONBLOCK & ret);
+  ASSERT_EQ(0, close(fd));
+}
+
+TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) {
+  TestOpenComplexFlags(true /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) {
+  TestOpenComplexFlags(false /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+// We need to allow noise because the broker will log when it receives our
+// bogus IPCs.
+SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, RecvMsgDescriptorLeak) {
+  // Android creates a socket on first use of the LOG call.
+  // We need to ensure this socket is open before we
+  // begin the test.
+  LOG(INFO) << "Ensure Android LOG socket is allocated";
+
+  // Find the four lowest available file descriptors.
+  int available_fds[4];
+  SANDBOX_ASSERT(0 == pipe(available_fds));
+  SANDBOX_ASSERT(0 == pipe(available_fds + 2));
+
+  // Save one FD to send to the broker later, and close the others.
+  base::ScopedFD message_fd(available_fds[0]);
+  for (size_t i = 1; i < arraysize(available_fds); i++) {
+    SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds[i])));
+  }
+
+  // Lower our file descriptor limit to just allow three more file descriptors
+  // to be allocated.  (N.B., RLIMIT_NOFILE doesn't limit the number of file
+  // descriptors a process can have: it only limits the highest value that can
+  // be assigned to newly-created descriptors allocated by the process.)
+  const rlim_t fd_limit =
+      1 +
+      *std::max_element(available_fds,
+                        available_fds + arraysize(available_fds));
+
+  // Valgrind doesn't allow changing the hard descriptor limit, so we only
+  // change the soft descriptor limit here.
+  struct rlimit rlim;
+  SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim));
+  SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur);
+  rlim.rlim_cur = fd_limit;
+  SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim));
+
+  static const char kCpuInfo[] = "/proc/cpuinfo";
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo));
+
+  BrokerProcess open_broker(EPERM, permissions);
+  SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker);
+  SANDBOX_ASSERT(ipc_fd >= 0);
+
+  static const char kBogus[] = "not a pickle";
+  std::vector<int> fds;
+  fds.push_back(message_fd.get());
+
+  // The broker process should only have a couple spare file descriptors
+  // available, but for good measure we send it fd_limit bogus IPCs anyway.
+  for (rlim_t i = 0; i < fd_limit; ++i) {
+    SANDBOX_ASSERT(
+        UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds));
+  }
+
+  const int fd = open_broker.Open(kCpuInfo, O_RDONLY);
+  SANDBOX_ASSERT(fd >= 0);
+  SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd)));
+}
+
+bool CloseFD(int fd) {
+  PCHECK(0 == IGNORE_EINTR(close(fd)));
+  return true;
+}
+
+// Return true if the other end of the |reader| pipe was closed,
+// false if |timeout_in_seconds| was reached or another event
+// or error occured.
+bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) {
+  struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0};
+  const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms));
+  if (1 == num_events && poll_fd.revents | POLLHUP)
+    return true;
+  return false;
+}
+
+// Closing the broker client's IPC channel should terminate the broker
+// process.
+TEST(BrokerProcess, BrokerDiesOnClosedChannel) {
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
+
+  // Get the writing end of a pipe into the broker (child) process so
+  // that we can reliably detect when it dies.
+  int lifeline_fds[2];
+  PCHECK(0 == pipe(lifeline_fds));
+
+  BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */,
+                            false /* quiet_failures_for_tests */);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0])));
+  // Make sure the writing end only exists in the broker process.
+  CloseFD(lifeline_fds[1]);
+  base::ScopedFD reader(lifeline_fds[0]);
+
+  const pid_t broker_pid = open_broker.broker_pid();
+
+  // This should cause the broker process to exit.
+  BrokerProcessTestHelper::CloseChannel(&open_broker);
+
+  const int kTimeoutInMilliseconds = 5000;
+  const bool broker_lifeline_closed =
+      WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds);
+  // If the broker exited, its lifeline fd should be closed.
+  ASSERT_TRUE(broker_lifeline_closed);
+  // Now check that the broker has exited, but do not reap it.
+  siginfo_t process_info;
+  ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info,
+                                   WEXITED | WNOWAIT)));
+  EXPECT_EQ(broker_pid, process_info.si_pid);
+  EXPECT_EQ(CLD_EXITED, process_info.si_code);
+  EXPECT_EQ(1, process_info.si_status);
+}
+
+TEST(BrokerProcess, CreateFile) {
+  std::string temp_str;
+  {
+    ScopedTemporaryFile tmp_file;
+    temp_str = tmp_file.full_file_name();
+  }
+  const char* tempfile_name = temp_str.c_str();
+
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadWriteCreate(tempfile_name));
+
+  BrokerProcess open_broker(EPERM, permissions);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  int fd = -1;
+
+  // Try without O_EXCL
+  fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT);
+  ASSERT_EQ(fd, -EPERM);
+
+  const char kTestText[] = "TESTTESTTEST";
+  // Create a file
+  fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL);
+  ASSERT_GE(fd, 0);
+  {
+    base::ScopedFD scoped_fd(fd);
+
+    // Confirm fail if file exists
+    int bad_fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL);
+    ASSERT_EQ(bad_fd, -EEXIST);
+
+    // Write to the descriptor opened by the broker.
+
+    ssize_t len = HANDLE_EINTR(write(fd, kTestText, sizeof(kTestText)));
+    ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText)));
+  }
+
+  int fd_check = open(tempfile_name, O_RDONLY);
+  ASSERT_GE(fd_check, 0);
+  {
+    base::ScopedFD scoped_fd(fd_check);
+    char buf[1024];
+    ssize_t len = HANDLE_EINTR(read(fd_check, buf, sizeof(buf)));
+
+    ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText)));
+    ASSERT_EQ(memcmp(kTestText, buf, sizeof(kTestText)), 0);
+  }
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/system_headers/arm64_linux_syscalls.h b/sandbox/linux/system_headers/arm64_linux_syscalls.h
new file mode 100644
index 0000000..8acb2d1
--- /dev/null
+++ b/sandbox/linux/system_headers/arm64_linux_syscalls.h
@@ -0,0 +1,1062 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
+
+#include <asm-generic/unistd.h>
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 0
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 1
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 2
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 3
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 4
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 5
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 6
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 7
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 8
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 9
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 10
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 11
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 12
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 13
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 14
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 15
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 16
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 17
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 18
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 19
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 20
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 21
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 22
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 23
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 24
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 25
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 26
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 27
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 28
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 29
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 30
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 31
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 32
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 33
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 34
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 35
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 36
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 37
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 38
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 39
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 40
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 41
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 42
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 43
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 44
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 45
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 46
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 47
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 48
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 49
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 50
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 51
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 52
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 53
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 54
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 55
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 56
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 57
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 58
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 59
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 60
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 61
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 62
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 63
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 64
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 65
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 66
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 67
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 68
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 69
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 70
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 71
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 72
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 73
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 74
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 75
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 76
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 77
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 78
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat 79
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 80
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 81
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 82
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 83
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 84
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 85
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 86
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 87
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 88
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 89
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 90
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 91
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 92
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 93
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 94
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 95
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 96
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 97
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 98
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 99
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 100
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 101
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 102
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 103
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 104
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 105
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 106
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 107
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 108
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 109
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 110
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 111
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 112
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 113
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 114
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 115
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 116
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 117
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 118
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 119
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 120
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 121
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 122
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 123
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 124
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 125
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 126
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 127
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 128
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 129
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 130
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 131
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 132
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 133
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 134
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 135
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 136
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 137
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 138
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 139
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 140
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 141
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 142
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 143
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 144
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 145
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 146
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 147
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 148
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 149
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 150
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 151
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 152
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 153
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 154
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 155
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 156
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 157
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 158
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 159
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 160
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 161
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 162
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 163
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 164
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 165
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 166
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 167
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 168
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 169
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 170
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 171
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 172
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 173
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 174
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 175
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 176
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 177
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 178
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 179
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 180
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 181
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 182
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 183
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 184
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 185
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 186
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 187
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 188
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 189
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 190
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 191
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop 192
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop 193
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 194
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 195
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 196
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 197
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 198
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 199
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 200
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 201
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept 202
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 203
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 204
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 205
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 206
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 207
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 208
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 209
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 210
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 211
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 212
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 213
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 214
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 215
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 216
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 217
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 218
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 219
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 220
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 221
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 222
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 223
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 224
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 225
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 226
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 227
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 228
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 229
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 230
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 231
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 232
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 233
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 234
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 235
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 236
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 237
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 238
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 239
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 240
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 241
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 242
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 243
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 260
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 261
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 262
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 263
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 264
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 265
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 266
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 267
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 268
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 269
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 270
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 271
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 272
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 273
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 274
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 275
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 276
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 277
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 278
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/arm64_linux_ucontext.h b/sandbox/linux/system_headers/arm64_linux_ucontext.h
new file mode 100644
index 0000000..46e0407
--- /dev/null
+++ b/sandbox/linux/system_headers/arm64_linux_ucontext.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#include <asm/sigcontext.h>
+#include <signal.h>
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef uint64_t greg_t;
+
+struct ucontext_t {
+  unsigned long uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  sigset_t uc_sigmask;
+  /* glibc uses a 1024-bit sigset_t */
+  uint8_t unused[1024 / 8 - sizeof(sigset_t)];
+  /* last for future expansion */
+  struct sigcontext uc_mcontext;
+};
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/arm_linux_syscalls.h b/sandbox/linux/system_headers/arm_linux_syscalls.h
new file mode 100644
index 0000000..bfd5342
--- /dev/null
+++ b/sandbox/linux/system_headers/arm_linux_syscalls.h
@@ -0,0 +1,1414 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
+
+#if !defined(__arm__) || !defined(__ARM_EABI__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_SYSCALL_BASE)
+// On ARM EABI arch, __NR_SYSCALL_BASE is 0.
+#define __NR_SYSCALL_BASE 0
+#endif
+
+// This syscall list has holes, because ARM EABI makes some syscalls obsolete.
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_SYSCALL_BASE+0)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_SYSCALL_BASE+1)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_SYSCALL_BASE+2)
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_SYSCALL_BASE+3)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_SYSCALL_BASE+4)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_SYSCALL_BASE+5)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_SYSCALL_BASE+6)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_SYSCALL_BASE+8)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_SYSCALL_BASE+9)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_SYSCALL_BASE+10)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_SYSCALL_BASE+11)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_SYSCALL_BASE+12)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_SYSCALL_BASE+14)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_SYSCALL_BASE+15)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_SYSCALL_BASE+16)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_SYSCALL_BASE+19)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_SYSCALL_BASE+20)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_SYSCALL_BASE+21)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_SYSCALL_BASE+23)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_SYSCALL_BASE+24)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_SYSCALL_BASE+26)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_SYSCALL_BASE+29)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_SYSCALL_BASE+33)
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice (__NR_SYSCALL_BASE+34)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_SYSCALL_BASE+36)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_SYSCALL_BASE+37)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_SYSCALL_BASE+38)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_SYSCALL_BASE+39)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_SYSCALL_BASE+40)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_SYSCALL_BASE+41)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_SYSCALL_BASE+42)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_SYSCALL_BASE+43)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_SYSCALL_BASE+45)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_SYSCALL_BASE+46)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_SYSCALL_BASE+47)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_SYSCALL_BASE+49)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_SYSCALL_BASE+50)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_SYSCALL_BASE+51)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_SYSCALL_BASE+52)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_SYSCALL_BASE+54)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_SYSCALL_BASE+55)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_SYSCALL_BASE+57)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_SYSCALL_BASE+60)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_SYSCALL_BASE+61)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_SYSCALL_BASE+62)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_SYSCALL_BASE+63)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_SYSCALL_BASE+64)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_SYSCALL_BASE+65)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_SYSCALL_BASE+66)
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction (__NR_SYSCALL_BASE+67)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_SYSCALL_BASE+70)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_SYSCALL_BASE+71)
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend (__NR_SYSCALL_BASE+72)
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending (__NR_SYSCALL_BASE+73)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_SYSCALL_BASE+74)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_SYSCALL_BASE+75)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_SYSCALL_BASE+77)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_SYSCALL_BASE+78)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_SYSCALL_BASE+79)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_SYSCALL_BASE+80)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_SYSCALL_BASE+81)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_SYSCALL_BASE+83)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_SYSCALL_BASE+85)
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib (__NR_SYSCALL_BASE+86)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_SYSCALL_BASE+87)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_SYSCALL_BASE+88)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_SYSCALL_BASE+91)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_SYSCALL_BASE+92)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_SYSCALL_BASE+93)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_SYSCALL_BASE+94)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_SYSCALL_BASE+95)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_SYSCALL_BASE+96)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_SYSCALL_BASE+97)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_SYSCALL_BASE+99)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_SYSCALL_BASE+100)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_SYSCALL_BASE+103)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_SYSCALL_BASE+104)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_SYSCALL_BASE+105)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_SYSCALL_BASE+106)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_SYSCALL_BASE+107)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_SYSCALL_BASE+108)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_SYSCALL_BASE+111)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_SYSCALL_BASE+114)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_SYSCALL_BASE+115)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_SYSCALL_BASE+116)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_SYSCALL_BASE+118)
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn (__NR_SYSCALL_BASE+119)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_SYSCALL_BASE+120)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_SYSCALL_BASE+121)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_SYSCALL_BASE+122)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_SYSCALL_BASE+124)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_SYSCALL_BASE+125)
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask (__NR_SYSCALL_BASE+126)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_SYSCALL_BASE+128)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_SYSCALL_BASE+129)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_SYSCALL_BASE+131)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_SYSCALL_BASE+132)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_SYSCALL_BASE+133)
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush (__NR_SYSCALL_BASE+134)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_SYSCALL_BASE+135)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_SYSCALL_BASE+136)
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_SYSCALL_BASE+138)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_SYSCALL_BASE+139)
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek (__NR_SYSCALL_BASE+140)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_SYSCALL_BASE+141)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_SYSCALL_BASE+142)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_SYSCALL_BASE+143)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_SYSCALL_BASE+144)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_SYSCALL_BASE+145)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_SYSCALL_BASE+146)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_SYSCALL_BASE+147)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_SYSCALL_BASE+148)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_SYSCALL_BASE+149)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_SYSCALL_BASE+150)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_SYSCALL_BASE+151)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_SYSCALL_BASE+152)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_SYSCALL_BASE+153)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_SYSCALL_BASE+154)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_SYSCALL_BASE+155)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_SYSCALL_BASE+156)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_SYSCALL_BASE+157)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_SYSCALL_BASE+158)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_SYSCALL_BASE+159)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_SYSCALL_BASE+160)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_SYSCALL_BASE+161)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_SYSCALL_BASE+162)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_SYSCALL_BASE+163)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_SYSCALL_BASE+164)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_SYSCALL_BASE+165)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_SYSCALL_BASE+168)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_SYSCALL_BASE+169)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_SYSCALL_BASE+170)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_SYSCALL_BASE+171)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_SYSCALL_BASE+172)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_SYSCALL_BASE+173)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_SYSCALL_BASE+174)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE+175)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_SYSCALL_BASE+176)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_SYSCALL_BASE+177)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_SYSCALL_BASE+178)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_SYSCALL_BASE+180)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_SYSCALL_BASE+181)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_SYSCALL_BASE+182)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_SYSCALL_BASE+183)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_SYSCALL_BASE+184)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_SYSCALL_BASE+185)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_SYSCALL_BASE+186)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_SYSCALL_BASE+187)
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork (__NR_SYSCALL_BASE+190)
+#endif
+
+#if !defined(__NR_ugetrlimit)
+#define __NR_ugetrlimit (__NR_SYSCALL_BASE+191)
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 (__NR_SYSCALL_BASE+192)
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 (__NR_SYSCALL_BASE+193)
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 (__NR_SYSCALL_BASE+194)
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 (__NR_SYSCALL_BASE+195)
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 (__NR_SYSCALL_BASE+196)
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 (__NR_SYSCALL_BASE+197)
+#endif
+
+#if !defined(__NR_lchown32)
+#define __NR_lchown32 (__NR_SYSCALL_BASE+198)
+#endif
+
+#if !defined(__NR_getuid32)
+#define __NR_getuid32 (__NR_SYSCALL_BASE+199)
+#endif
+
+#if !defined(__NR_getgid32)
+#define __NR_getgid32 (__NR_SYSCALL_BASE+200)
+#endif
+
+#if !defined(__NR_geteuid32)
+#define __NR_geteuid32 (__NR_SYSCALL_BASE+201)
+#endif
+
+#if !defined(__NR_getegid32)
+#define __NR_getegid32 (__NR_SYSCALL_BASE+202)
+#endif
+
+#if !defined(__NR_setreuid32)
+#define __NR_setreuid32 (__NR_SYSCALL_BASE+203)
+#endif
+
+#if !defined(__NR_setregid32)
+#define __NR_setregid32 (__NR_SYSCALL_BASE+204)
+#endif
+
+#if !defined(__NR_getgroups32)
+#define __NR_getgroups32 (__NR_SYSCALL_BASE+205)
+#endif
+
+#if !defined(__NR_setgroups32)
+#define __NR_setgroups32 (__NR_SYSCALL_BASE+206)
+#endif
+
+#if !defined(__NR_fchown32)
+#define __NR_fchown32 (__NR_SYSCALL_BASE+207)
+#endif
+
+#if !defined(__NR_setresuid32)
+#define __NR_setresuid32 (__NR_SYSCALL_BASE+208)
+#endif
+
+#if !defined(__NR_getresuid32)
+#define __NR_getresuid32 (__NR_SYSCALL_BASE+209)
+#endif
+
+#if !defined(__NR_setresgid32)
+#define __NR_setresgid32 (__NR_SYSCALL_BASE+210)
+#endif
+
+#if !defined(__NR_getresgid32)
+#define __NR_getresgid32 (__NR_SYSCALL_BASE+211)
+#endif
+
+#if !defined(__NR_chown32)
+#define __NR_chown32 (__NR_SYSCALL_BASE+212)
+#endif
+
+#if !defined(__NR_setuid32)
+#define __NR_setuid32 (__NR_SYSCALL_BASE+213)
+#endif
+
+#if !defined(__NR_setgid32)
+#define __NR_setgid32 (__NR_SYSCALL_BASE+214)
+#endif
+
+#if !defined(__NR_setfsuid32)
+#define __NR_setfsuid32 (__NR_SYSCALL_BASE+215)
+#endif
+
+#if !defined(__NR_setfsgid32)
+#define __NR_setfsgid32 (__NR_SYSCALL_BASE+216)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_SYSCALL_BASE+217)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_SYSCALL_BASE+218)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_SYSCALL_BASE+219)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_SYSCALL_BASE+220)
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 (__NR_SYSCALL_BASE+221)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_SYSCALL_BASE+224)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_SYSCALL_BASE+225)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_SYSCALL_BASE+226)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_SYSCALL_BASE+227)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_SYSCALL_BASE+228)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_SYSCALL_BASE+229)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_SYSCALL_BASE+230)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_SYSCALL_BASE+231)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_SYSCALL_BASE+232)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_SYSCALL_BASE+233)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_SYSCALL_BASE+234)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_SYSCALL_BASE+235)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_SYSCALL_BASE+236)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_SYSCALL_BASE+237)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_SYSCALL_BASE+238)
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 (__NR_SYSCALL_BASE+239)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_SYSCALL_BASE+240)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_SYSCALL_BASE+241)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_SYSCALL_BASE+242)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_SYSCALL_BASE+243)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_SYSCALL_BASE+244)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_SYSCALL_BASE+245)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_SYSCALL_BASE+246)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_SYSCALL_BASE+247)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_SYSCALL_BASE+248)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_SYSCALL_BASE+249)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_SYSCALL_BASE+250)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_SYSCALL_BASE+251)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_SYSCALL_BASE+252)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_SYSCALL_BASE+253)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_SYSCALL_BASE+256)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_SYSCALL_BASE+257)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_SYSCALL_BASE+258)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_SYSCALL_BASE+259)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+260)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_SYSCALL_BASE+261)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_SYSCALL_BASE+262)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_SYSCALL_BASE+263)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_SYSCALL_BASE+264)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_SYSCALL_BASE+265)
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 (__NR_SYSCALL_BASE+266)
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 (__NR_SYSCALL_BASE+267)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_SYSCALL_BASE+268)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_SYSCALL_BASE+269)
+#endif
+
+#if !defined(__NR_arm_fadvise64_64)
+#define __NR_arm_fadvise64_64 (__NR_SYSCALL_BASE+270)
+#endif
+
+#if !defined(__NR_pciconfig_iobase)
+#define __NR_pciconfig_iobase (__NR_SYSCALL_BASE+271)
+#endif
+
+#if !defined(__NR_pciconfig_read)
+#define __NR_pciconfig_read (__NR_SYSCALL_BASE+272)
+#endif
+
+#if !defined(__NR_pciconfig_write)
+#define __NR_pciconfig_write (__NR_SYSCALL_BASE+273)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_SYSCALL_BASE+274)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_SYSCALL_BASE+275)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_SYSCALL_BASE+276)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_SYSCALL_BASE+277)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_SYSCALL_BASE+278)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_SYSCALL_BASE+279)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_SYSCALL_BASE+280)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_SYSCALL_BASE+281)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_SYSCALL_BASE+282)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_SYSCALL_BASE+283)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_SYSCALL_BASE+284)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_SYSCALL_BASE+285)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_SYSCALL_BASE+286)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_SYSCALL_BASE+287)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_SYSCALL_BASE+288)
+#endif
+
+#if !defined(__NR_send)
+#define __NR_send (__NR_SYSCALL_BASE+289)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_SYSCALL_BASE+290)
+#endif
+
+#if !defined(__NR_recv)
+#define __NR_recv (__NR_SYSCALL_BASE+291)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_SYSCALL_BASE+292)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_SYSCALL_BASE+293)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_SYSCALL_BASE+294)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_SYSCALL_BASE+295)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_SYSCALL_BASE+296)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_SYSCALL_BASE+297)
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop (__NR_SYSCALL_BASE+298)
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget (__NR_SYSCALL_BASE+299)
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl (__NR_SYSCALL_BASE+300)
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd (__NR_SYSCALL_BASE+301)
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv (__NR_SYSCALL_BASE+302)
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget (__NR_SYSCALL_BASE+303)
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl (__NR_SYSCALL_BASE+304)
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat (__NR_SYSCALL_BASE+305)
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt (__NR_SYSCALL_BASE+306)
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget (__NR_SYSCALL_BASE+307)
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl (__NR_SYSCALL_BASE+308)
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_SYSCALL_BASE+309)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_SYSCALL_BASE+310)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_SYSCALL_BASE+311)
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop (__NR_SYSCALL_BASE+312)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_SYSCALL_BASE+313)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_SYSCALL_BASE+314)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_SYSCALL_BASE+315)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_SYSCALL_BASE+316)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_SYSCALL_BASE+319)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_SYSCALL_BASE+320)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_SYSCALL_BASE+321)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_SYSCALL_BASE+322)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_SYSCALL_BASE+323)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_SYSCALL_BASE+324)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_SYSCALL_BASE+325)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_SYSCALL_BASE+326)
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 (__NR_SYSCALL_BASE+327)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_SYSCALL_BASE+328)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_SYSCALL_BASE+329)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_SYSCALL_BASE+330)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_SYSCALL_BASE+331)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_SYSCALL_BASE+332)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_SYSCALL_BASE+333)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_SYSCALL_BASE+334)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_SYSCALL_BASE+335)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_SYSCALL_BASE+336)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_SYSCALL_BASE+337)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_SYSCALL_BASE+340)
+#endif
+
+#if !defined(__NR_arm_sync_file_range)
+#define __NR_arm_sync_file_range (__NR_SYSCALL_BASE+341)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_SYSCALL_BASE+342)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_SYSCALL_BASE+343)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_SYSCALL_BASE+344)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_SYSCALL_BASE+345)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_SYSCALL_BASE+346)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_SYSCALL_BASE+347)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_SYSCALL_BASE+348)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_SYSCALL_BASE+349)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_SYSCALL_BASE+350)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_SYSCALL_BASE+351)
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate (__NR_SYSCALL_BASE+352)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_SYSCALL_BASE+353)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_SYSCALL_BASE+355)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_SYSCALL_BASE+356)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_SYSCALL_BASE+357)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_SYSCALL_BASE+358)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_SYSCALL_BASE+359)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_SYSCALL_BASE+360)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_SYSCALL_BASE+361)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_SYSCALL_BASE+362)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_SYSCALL_BASE+364)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_SYSCALL_BASE+365)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_SYSCALL_BASE+366)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_SYSCALL_BASE+367)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_SYSCALL_BASE+368)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_SYSCALL_BASE+369)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_SYSCALL_BASE+370)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_SYSCALL_BASE+371)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_SYSCALL_BASE+372)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_SYSCALL_BASE+373)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_SYSCALL_BASE+374)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_SYSCALL_BASE+375)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_SYSCALL_BASE+378)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_SYSCALL_BASE+379)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_SYSCALL_BASE+383)
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom (__NR_SYSCALL_BASE+384)
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create (__NR_SYSCALL_BASE+385)
+#endif
+
+// ARM private syscalls.
+#if !defined(__ARM_NR_BASE)
+#define __ARM_NR_BASE (__NR_SYSCALL_BASE + 0xF0000)
+#endif
+
+#if !defined(__ARM_NR_breakpoint)
+#define __ARM_NR_breakpoint (__ARM_NR_BASE+1)
+#endif
+
+#if !defined(__ARM_NR_cacheflush)
+#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+#endif
+
+#if !defined(__ARM_NR_usr26)
+#define __ARM_NR_usr26 (__ARM_NR_BASE+3)
+#endif
+
+#if !defined(__ARM_NR_usr32)
+#define __ARM_NR_usr32 (__ARM_NR_BASE+4)
+#endif
+
+#if !defined(__ARM_NR_set_tls)
+#define __ARM_NR_set_tls (__ARM_NR_BASE+5)
+#endif
+
+// ARM kernel private syscall.
+#if !defined(__ARM_NR_cmpxchg)
+#define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/arm_linux_ucontext.h b/sandbox/linux/system_headers/arm_linux_ucontext.h
new file mode 100644
index 0000000..0eb723a
--- /dev/null
+++ b/sandbox/linux/system_headers/arm_linux_ucontext.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 SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#if !defined(__native_client_nonsfi__)
+#include <asm/sigcontext.h>
+#else
+// In PNaCl toolchain, sigcontext and stack_t is not defined. So here declare
+// them.
+struct sigcontext {
+  unsigned long trap_no;
+  unsigned long error_code;
+  unsigned long oldmask;
+  unsigned long arm_r0;
+  unsigned long arm_r1;
+  unsigned long arm_r2;
+  unsigned long arm_r3;
+  unsigned long arm_r4;
+  unsigned long arm_r5;
+  unsigned long arm_r6;
+  unsigned long arm_r7;
+  unsigned long arm_r8;
+  unsigned long arm_r9;
+  unsigned long arm_r10;
+  unsigned long arm_fp;
+  unsigned long arm_ip;
+  unsigned long arm_sp;
+  unsigned long arm_lr;
+  unsigned long arm_pc;
+  unsigned long arm_cpsr;
+  unsigned long fault_address;
+};
+
+typedef struct sigaltstack {
+  void* ss_sp;
+  int ss_flags;
+  size_t ss_size;
+} stack_t;
+
+#endif
+
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef unsigned long greg_t;
+
+// typedef unsigned long sigset_t;
+typedef struct ucontext {
+  unsigned long uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  struct sigcontext uc_mcontext;
+  sigset_t uc_sigmask;
+  /* Allow for uc_sigmask growth.  Glibc uses a 1024-bit sigset_t.  */
+  int __not_used[32 - (sizeof(sigset_t) / sizeof(int))];
+  /* Last for extensibility.  Eight byte aligned because some
+     coprocessors require eight byte alignment.  */
+  unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/capability.h b/sandbox/linux/system_headers/capability.h
new file mode 100644
index 0000000..f91fcf7
--- /dev/null
+++ b/sandbox/linux/system_headers/capability.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
+
+#include <stdint.h>
+
+// The following macros are taken from linux/capability.h.
+// We only support capability version 3, which was introduced in Linux 2.6.26.
+#ifndef _LINUX_CAPABILITY_VERSION_3
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#endif
+#ifndef _LINUX_CAPABILITY_U32S_3
+#define _LINUX_CAPABILITY_U32S_3 2
+#endif
+#ifndef CAP_TO_INDEX
+#define CAP_TO_INDEX(x) ((x) >> 5)  // 1 << 5 == bits in __u32
+#endif
+#ifndef CAP_TO_MASK
+#define CAP_TO_MASK(x) (1 << ((x) & 31))  // mask for indexed __u32
+#endif
+#ifndef CAP_SYS_CHROOT
+#define CAP_SYS_CHROOT 18
+#endif
+#ifndef CAP_SYS_ADMIN
+#define CAP_SYS_ADMIN 21
+#endif
+
+struct cap_hdr {
+  uint32_t version;
+  int pid;
+};
+
+struct cap_data {
+  uint32_t effective;
+  uint32_t permitted;
+  uint32_t inheritable;
+};
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
diff --git a/sandbox/linux/system_headers/i386_linux_ucontext.h b/sandbox/linux/system_headers/i386_linux_ucontext.h
new file mode 100644
index 0000000..61d9f7a
--- /dev/null
+++ b/sandbox/linux/system_headers/i386_linux_ucontext.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+
+// We do something compatible with glibc. Hopefully, at some point Android will
+// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
+// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
+// except we do use sigset_t for uc_sigmask instead of a custom type.
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#if !defined(__native_client_nonsfi__)
+#include <asm/sigcontext.h>
+#else
+// In PNaCl toolchain, sigcontext is not defined. So here declare it.
+typedef struct sigaltstack {
+  void* ss_sp;
+  int ss_flags;
+  size_t ss_size;
+} stack_t;
+#endif
+
+/* 80-bit floating-point register */
+struct _libc_fpreg {
+  unsigned short significand[4];
+  unsigned short exponent;
+};
+
+/* Simple floating-point state, see FNSTENV instruction */
+struct _libc_fpstate {
+  unsigned long cw;
+  unsigned long sw;
+  unsigned long tag;
+  unsigned long ipoff;
+  unsigned long cssel;
+  unsigned long dataoff;
+  unsigned long datasel;
+  struct _libc_fpreg _st[8];
+  unsigned long status;
+};
+
+typedef uint32_t greg_t;
+
+typedef struct {
+  uint32_t gregs[19];
+  struct _libc_fpstate* fpregs;
+  uint32_t oldmask;
+  uint32_t cr2;
+} mcontext_t;
+
+enum {
+  REG_GS = 0,
+  REG_FS,
+  REG_ES,
+  REG_DS,
+  REG_EDI,
+  REG_ESI,
+  REG_EBP,
+  REG_ESP,
+  REG_EBX,
+  REG_EDX,
+  REG_ECX,
+  REG_EAX,
+  REG_TRAPNO,
+  REG_ERR,
+  REG_EIP,
+  REG_CS,
+  REG_EFL,
+  REG_UESP,
+  REG_SS,
+};
+
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  // Android and PNaCl toolchain's sigset_t has only 32 bits, though Linux
+  // ABI requires 64 bits.
+  union {
+    sigset_t uc_sigmask;
+    uint32_t kernel_sigmask[2];
+  };
+  struct _libc_fpstate __fpregs_mem;
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/linux_filter.h b/sandbox/linux/system_headers/linux_filter.h
new file mode 100644
index 0000000..b23b6eb
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_filter.h
@@ -0,0 +1,140 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
+
+#include <stdint.h>
+
+// The following structs and macros are taken from linux/filter.h,
+// as some toolchain does not expose them.
+struct sock_filter {
+  uint16_t code;
+  uint8_t jt;
+  uint8_t jf;
+  uint32_t k;
+};
+
+struct sock_fprog {
+  uint16_t len;
+  struct sock_filter *filter;
+};
+
+#ifndef BPF_CLASS
+#define BPF_CLASS(code) ((code) & 0x07)
+#endif
+
+#ifndef BPF_LD
+#define BPF_LD 0x00
+#endif
+
+#ifndef BPF_ALU
+#define BPF_ALU 0x04
+#endif
+
+#ifndef BPF_JMP
+#define BPF_JMP 0x05
+#endif
+
+#ifndef BPF_RET
+#define BPF_RET 0x06
+#endif
+
+#ifndef BPF_SIZE
+#define BPF_SIZE(code) ((code) & 0x18)
+#endif
+
+#ifndef BPF_W
+#define BPF_W 0x00
+#endif
+
+#ifndef BPF_MODE
+#define BPF_MODE(code) ((code) & 0xe0)
+#endif
+
+#ifndef BPF_ABS
+#define BPF_ABS 0x20
+#endif
+
+#ifndef BPF_OP
+#define BPF_OP(code) ((code) & 0xf0)
+#endif
+
+#ifndef BPF_ADD
+#define BPF_ADD 0x00
+#endif
+
+#ifndef BPF_SUB
+#define BPF_SUB 0x10
+#endif
+
+#ifndef BPF_MUL
+#define BPF_MUL 0x20
+#endif
+
+#ifndef BPF_DIV
+#define BPF_DIV 0x30
+#endif
+
+#ifndef BPF_OR
+#define BPF_OR 0x40
+#endif
+
+#ifndef BPF_AND
+#define BPF_AND 0x50
+#endif
+
+#ifndef BPF_LSH
+#define BPF_LSH 0x60
+#endif
+
+#ifndef BPF_RSH
+#define BPF_RSH 0x70
+#endif
+
+#ifndef BPF_NEG
+#define BPF_NEG 0x80
+#endif
+
+#ifndef BPF_MOD
+#define BPF_MOD 0x90
+#endif
+
+#ifndef BPF_XOR
+#define BPF_XOR 0xA0
+#endif
+
+#ifndef BPF_JA
+#define BPF_JA 0x00
+#endif
+
+#ifndef BPF_JEQ
+#define BPF_JEQ 0x10
+#endif
+
+#ifndef BPF_JGT
+#define BPF_JGT 0x20
+#endif
+
+#ifndef BPF_JGE
+#define BPF_JGE 0x30
+#endif
+
+#ifndef BPF_JSET
+#define BPF_JSET 0x40
+#endif
+
+#ifndef BPF_SRC
+#define BPF_SRC(code) ((code) & 0x08)
+#endif
+
+#ifndef BPF_K
+#define BPF_K 0x00
+#endif
+
+#ifndef BPF_MAXINSNS
+#define BPF_MAXINSNS 4096
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
diff --git a/sandbox/linux/system_headers/linux_futex.h b/sandbox/linux/system_headers/linux_futex.h
new file mode 100644
index 0000000..4e28403
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_futex.h
@@ -0,0 +1,84 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+
+#if !defined(__native_client_nonsfi__)
+#include <linux/futex.h>
+#endif  // !defined(__native_client_nonsfi__)
+
+#if !defined(FUTEX_WAIT)
+#define FUTEX_WAIT 0
+#endif
+
+#if !defined(FUTEX_WAKE)
+#define FUTEX_WAKE 1
+#endif
+
+#if !defined(FUTEX_FD)
+#define FUTEX_FD 2
+#endif
+
+#if !defined(FUTEX_REQUEUE)
+#define FUTEX_REQUEUE 3
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE)
+#define FUTEX_CMP_REQUEUE 4
+#endif
+
+#if !defined(FUTEX_WAKE_OP)
+#define FUTEX_WAKE_OP 5
+#endif
+
+#if !defined(FUTEX_LOCK_PI)
+#define FUTEX_LOCK_PI 6
+#endif
+
+#if !defined(FUTEX_UNLOCK_PI)
+#define FUTEX_UNLOCK_PI 7
+#endif
+
+#if !defined(FUTEX_TRYLOCK_PI)
+#define FUTEX_TRYLOCK_PI 8
+#endif
+
+#if !defined(FUTEX_WAIT_BITSET)
+#define FUTEX_WAIT_BITSET 9
+#endif
+
+#if !defined(FUTEX_WAKE_BITSET)
+#define FUTEX_WAKE_BITSET 10
+#endif
+
+#if !defined(FUTEX_WAIT_REQUEUE_PI)
+#define FUTEX_WAIT_REQUEUE_PI 11
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE_PI)
+#define FUTEX_CMP_REQUEUE_PI 12
+#endif
+
+#if !defined(FUTEX_PRIVATE_FLAG)
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+
+#if !defined FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+
+#if !defined(FUTEX_CMD_MASK)
+#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE_PI_PRIVATE)
+#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+#if !defined(FUTEX_UNLOCK_PI_PRIVATE)
+#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
diff --git a/sandbox/linux/system_headers/linux_seccomp.h b/sandbox/linux/system_headers/linux_seccomp.h
new file mode 100644
index 0000000..3deb3d2
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_seccomp.h
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
+
+// The Seccomp2 kernel ABI is not part of older versions of glibc.
+// As we can't break compilation with these versions of the library,
+// we explicitly define all missing symbols.
+// If we ever decide that we can now rely on system headers, the following
+// include files should be enabled:
+// #include <linux/audit.h>
+// #include <linux/seccomp.h>
+
+// For audit.h
+#ifndef EM_ARM
+#define EM_ARM    40
+#endif
+#ifndef EM_386
+#define EM_386    3
+#endif
+#ifndef EM_X86_64
+#define EM_X86_64 62
+#endif
+#ifndef EM_MIPS
+#define EM_MIPS   8
+#endif
+#ifndef EM_AARCH64
+#define EM_AARCH64 183
+#endif
+
+#ifndef __AUDIT_ARCH_64BIT
+#define __AUDIT_ARCH_64BIT 0x80000000
+#endif
+#ifndef __AUDIT_ARCH_LE
+#define __AUDIT_ARCH_LE    0x40000000
+#endif
+#ifndef AUDIT_ARCH_ARM
+#define AUDIT_ARCH_ARM    (EM_ARM|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_I386
+#define AUDIT_ARCH_I386   (EM_386|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_X86_64
+#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_MIPSEL
+#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_AARCH64
+#define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
+#endif
+
+// For prctl.h
+#ifndef PR_SET_SECCOMP
+#define PR_SET_SECCOMP               22
+#define PR_GET_SECCOMP               21
+#endif
+#ifndef PR_SET_NO_NEW_PRIVS
+#define PR_SET_NO_NEW_PRIVS          38
+#define PR_GET_NO_NEW_PRIVS          39
+#endif
+#ifndef IPC_64
+#define IPC_64                   0x0100
+#endif
+
+// In order to build will older tool chains, we currently have to avoid
+// including <linux/seccomp.h>. Until that can be fixed (if ever). Rely on
+// our own definitions of the seccomp kernel ABI.
+#ifndef SECCOMP_MODE_FILTER
+#define SECCOMP_MODE_DISABLED         0
+#define SECCOMP_MODE_STRICT           1
+#define SECCOMP_MODE_FILTER           2  // User user-supplied filter
+#endif
+
+#ifndef SECCOMP_SET_MODE_STRICT
+#define SECCOMP_SET_MODE_STRICT 0
+#endif
+#ifndef SECCOMP_SET_MODE_FILTER
+#define SECCOMP_SET_MODE_FILTER 1
+#endif
+#ifndef SECCOMP_FILTER_FLAG_TSYNC
+#define SECCOMP_FILTER_FLAG_TSYNC 1
+#endif
+
+#ifndef SECCOMP_RET_KILL
+// Return values supported for BPF filter programs. Please note that the
+// "illegal" SECCOMP_RET_INVALID is not supported by the kernel, should only
+// ever be used internally, and would result in the kernel killing our process.
+#define SECCOMP_RET_KILL    0x00000000U  // Kill the task immediately
+#define SECCOMP_RET_INVALID 0x00010000U  // Illegal return value
+#define SECCOMP_RET_TRAP    0x00030000U  // Disallow and force a SIGSYS
+#define SECCOMP_RET_ERRNO   0x00050000U  // Returns an errno
+#define SECCOMP_RET_TRACE   0x7ff00000U  // Pass to a tracer or disallow
+#define SECCOMP_RET_ALLOW   0x7fff0000U  // Allow
+#define SECCOMP_RET_ACTION  0xffff0000U  // Masks for the return value
+#define SECCOMP_RET_DATA    0x0000ffffU  //   sections
+#else
+#define SECCOMP_RET_INVALID 0x00010000U  // Illegal return value
+#endif
+
+#ifndef SYS_SECCOMP
+#define SYS_SECCOMP                   1
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
diff --git a/sandbox/linux/system_headers/linux_signal.h b/sandbox/linux/system_headers/linux_signal.h
new file mode 100644
index 0000000..5db7fc5
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_signal.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+
+// NOTE: On some toolchains, signal related ABI is incompatible with Linux's
+// (not undefined, but defined different values and in different memory
+// layouts). So, fill the gap here.
+
+#if defined(__native_client_nonsfi__)
+#if !defined(__i386__) && !defined(__arm__)
+#error "Unsupported platform"
+#endif
+
+#include <signal.h>
+
+#define LINUX_SIGBUS 7    // 10 in PNaCl toolchain.
+#define LINUX_SIGSEGV 11  // 11 in PNaCl toolchain. Defined for consistency.
+#define LINUX_SIGCHLD 17  // 20 in PNaCl toolchain.
+#define LINUX_SIGSYS 31   // 12 in PNaCl toolchain.
+
+#define LINUX_SIG_BLOCK 0    // 1 in PNaCl toolchain.
+#define LINUX_SIG_UNBLOCK 1  // 2 in PNaCl toolchain.
+
+#define LINUX_SA_SIGINFO 4           // 2 in PNaCl toolchain.
+#define LINUX_SA_NODEFER 0x40000000  // Undefined in PNaCl toolchain.
+#define LINUX_SA_RESTART 0x10000000  // Undefined in PNaCl toolchain.
+
+#define LINUX_SIG_DFL 0  // In PNaCl toolchain, unneeded cast is applied.
+
+struct LinuxSigInfo {
+  int si_signo;
+  int si_errno;
+  int si_code;
+
+  // Extra data is followed by the |si_code|. The length depends on the
+  // signal number.
+  char _sifields[1];
+};
+
+#include "sandbox/linux/system_headers/linux_ucontext.h"
+
+#else  // !defined(__native_client_nonsfi__)
+
+// Just alias the toolchain's value.
+#include <signal.h>
+
+#define LINUX_SIGBUS SIGBUS
+#define LINUX_SIGSEGV SIGSEGV
+#define LINUX_SIGCHLD SIGCHLD
+#define LINUX_SIGSYS SIGSYS
+
+#define LINUX_SIG_BLOCK SIG_BLOCK
+#define LINUX_SIG_UNBLOCK SIG_UNBLOCK
+
+#define LINUX_SA_SIGINFO SA_SIGINFO
+#define LINUX_SA_NODEFER SA_NODEFER
+#define LINUX_SA_RESTART SA_RESTART
+
+#define LINUX_SIG_DFL SIG_DFL
+
+typedef siginfo_t LinuxSigInfo;
+
+#if defined(__ANDROID__)
+// Android's signal.h doesn't define ucontext etc.
+#include "sandbox/linux/system_headers/linux_ucontext.h"
+#endif  // defined(__ANDROID__)
+
+#endif  // !defined(__native_client_nonsfi__)
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
diff --git a/sandbox/linux/system_headers/linux_syscalls.h b/sandbox/linux/system_headers/linux_syscalls.h
new file mode 100644
index 0000000..2b441e4
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_syscalls.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header will be kept up to date so that we can compile system-call
+// policies even when system headers are old.
+// System call numbers are accessible through __NR_syscall_name.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+
+#if defined(__x86_64__)
+#include "sandbox/linux/system_headers/x86_64_linux_syscalls.h"
+#endif
+
+#if defined(__i386__)
+#include "sandbox/linux/system_headers/x86_32_linux_syscalls.h"
+#endif
+
+#if defined(__arm__) && defined(__ARM_EABI__)
+#include "sandbox/linux/system_headers/arm_linux_syscalls.h"
+#endif
+
+#if defined(__mips__) && (_MIPS_SIM == _ABIO32)
+#include "sandbox/linux/system_headers/mips_linux_syscalls.h"
+#endif
+
+#if defined(__mips__) && (_MIPS_SIM == _ABI64)
+#include "sandbox/linux/system_headers/mips64_linux_syscalls.h"
+#endif
+
+#if defined(__aarch64__)
+#include "sandbox/linux/system_headers/arm64_linux_syscalls.h"
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+
diff --git a/sandbox/linux/system_headers/linux_ucontext.h b/sandbox/linux/system_headers/linux_ucontext.h
new file mode 100644
index 0000000..ea4d8a6
--- /dev/null
+++ b/sandbox/linux/system_headers/linux_ucontext.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
+
+#if defined(__ANDROID__) || defined(__native_client_nonsfi__)
+
+#if defined(__arm__)
+#include "sandbox/linux/system_headers/arm_linux_ucontext.h"
+#elif defined(__i386__)
+#include "sandbox/linux/system_headers/i386_linux_ucontext.h"
+#elif defined(__x86_64__)
+#include "sandbox/linux/system_headers/x86_64_linux_ucontext.h"
+#elif defined(__mips__)
+#include "sandbox/linux/system_headers/mips_linux_ucontext.h"
+#elif defined(__aarch64__)
+#include "sandbox/linux/system_headers/arm64_linux_ucontext.h"
+#else
+#error "No support for your architecture in Android or PNaCl header"
+#endif
+
+#else  // defined(__ANDROID__) || defined(__native_client_nonsfi__)
+#error "The header file included on non Android and non PNaCl."
+#endif  // defined(__ANDROID__) || defined(__native_client_nonsfi__)
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/mips64_linux_syscalls.h b/sandbox/linux/system_headers/mips64_linux_syscalls.h
new file mode 100644
index 0000000..d003124
--- /dev/null
+++ b/sandbox/linux/system_headers/mips64_linux_syscalls.h
@@ -0,0 +1,1266 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
+
+#if !defined(__mips__) || (_MIPS_SIM != _ABI64)
+#error "Including header on wrong architecture"
+#endif
+
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_Linux + 0)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_Linux + 1)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_Linux + 2)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_Linux + 3)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_Linux + 4)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_Linux + 5)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_Linux + 6)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_Linux + 7)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_Linux + 8)
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap (__NR_Linux + 9)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_Linux + 10)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_Linux + 11)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_Linux + 12)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_Linux + 13)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_Linux + 14)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_Linux + 15)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_Linux + 16)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_Linux + 17)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_Linux + 18)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_Linux + 19)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_Linux + 20)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_Linux + 21)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_Linux + 22)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_Linux + 23)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_Linux + 24)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_Linux + 25)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_Linux + 26)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_Linux + 27)
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget (__NR_Linux + 28)
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat (__NR_Linux + 29)
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl (__NR_Linux + 30)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_Linux + 31)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_Linux + 32)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_Linux + 33)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_Linux + 34)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_Linux + 35)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_Linux + 36)
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm (__NR_Linux + 37)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_Linux + 38)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_Linux + 39)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_Linux + 40)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_Linux + 41)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_Linux + 42)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_Linux + 43)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_Linux + 44)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_Linux + 45)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_Linux + 46)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_Linux + 47)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_Linux + 48)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_Linux + 49)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_Linux + 50)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_Linux + 51)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_Linux + 52)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_Linux + 53)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_Linux + 54)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_Linux + 55)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_Linux + 56)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_Linux + 57)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_Linux + 58)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_Linux + 59)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_Linux + 60)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_Linux + 61)
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget (__NR_Linux + 62)
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop (__NR_Linux + 63)
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl (__NR_Linux + 64)
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt (__NR_Linux + 65)
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget (__NR_Linux + 66)
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd (__NR_Linux + 67)
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv (__NR_Linux + 68)
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl (__NR_Linux + 69)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_Linux + 70)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_Linux + 71)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_Linux + 72)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_Linux + 73)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_Linux + 74)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_Linux + 75)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_Linux + 76)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_Linux + 77)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_Linux + 78)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_Linux + 79)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_Linux + 80)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_Linux + 81)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_Linux + 82)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_Linux + 83)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_Linux + 84)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_Linux + 85)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_Linux + 86)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_Linux + 87)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_Linux + 88)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_Linux + 89)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_Linux + 90)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_Linux + 91)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_Linux + 92)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_Linux + 93)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_Linux + 94)
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit (__NR_Linux + 95)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_Linux + 96)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_Linux + 97)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_Linux + 98)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_Linux + 99)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_Linux + 100)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_Linux + 101)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_Linux + 102)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_Linux + 103)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_Linux + 104)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_Linux + 105)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_Linux + 106)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_Linux + 107)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_Linux + 108)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_Linux + 109)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_Linux + 110)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_Linux + 111)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_Linux + 112)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_Linux + 113)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_Linux + 114)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_Linux + 115)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_Linux + 116)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_Linux + 117)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_Linux + 118)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_Linux + 119)
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_Linux + 120)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_Linux + 121)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_Linux + 122)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_Linux + 123)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_Linux + 124)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_Linux + 125)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_Linux + 126)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_Linux + 127)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_Linux + 128)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_Linux + 129)
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime (__NR_Linux + 130)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_Linux + 131)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_Linux + 132)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_Linux + 133)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_Linux + 134)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_Linux + 135)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_Linux + 136)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_Linux + 137)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_Linux + 138)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_Linux + 139)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_Linux + 140)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_Linux + 141)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_Linux + 142)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_Linux + 143)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_Linux + 144)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_Linux + 145)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_Linux + 146)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_Linux + 147)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_Linux + 148)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_Linux + 149)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_Linux + 150)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_Linux + 151)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_Linux + 152)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_Linux + 153)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_Linux + 154)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_Linux + 155)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_Linux + 156)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_Linux + 157)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_Linux + 158)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_Linux + 159)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_Linux + 160)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_Linux + 161)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_Linux + 162)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_Linux + 163)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_Linux + 164)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_Linux + 165)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_Linux + 166)
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module (__NR_Linux + 167)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_Linux + 168)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_Linux + 169)
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms (__NR_Linux + 170)
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module (__NR_Linux + 171)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_Linux + 172)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_Linux + 173)
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg (__NR_Linux + 174)
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg (__NR_Linux + 175)
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall (__NR_Linux + 176)
+#endif
+
+#if !defined(__NR_reserved177)
+#define __NR_reserved177 (__NR_Linux + 177)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_Linux + 178)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_Linux + 179)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_Linux + 180)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_Linux + 181)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_Linux + 182)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_Linux + 183)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_Linux + 184)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_Linux + 185)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_Linux + 186)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_Linux + 187)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_Linux + 188)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_Linux + 189)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_Linux + 190)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_Linux + 191)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_Linux + 192)
+#endif
+
+#if !defined(__NR_reserved193)
+#define __NR_reserved193 (__NR_Linux + 193)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_Linux + 194)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_Linux + 195)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_Linux + 196)
+#endif
+
+#if !defined(__NR_cacheflush)
+#define __NR_cacheflush (__NR_Linux + 197)
+#endif
+
+#if !defined(__NR_cachectl)
+#define __NR_cachectl (__NR_Linux + 198)
+#endif
+
+#if !defined(__NR_sysmips)
+#define __NR_sysmips (__NR_Linux + 199)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_Linux + 200)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_Linux + 201)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_Linux + 202)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_Linux + 203)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_Linux + 204)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_Linux + 205)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_Linux + 206)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_Linux + 207)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_Linux + 208)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_Linux + 209)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_Linux + 210)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_Linux + 211)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_Linux + 212)
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_Linux + 213)
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop (__NR_Linux + 214)
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 (__NR_Linux + 215)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_Linux + 216)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_Linux + 217)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_Linux + 218)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_Linux + 219)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_Linux + 220)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_Linux + 221)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_Linux + 222)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_Linux + 223)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_Linux + 224)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_Linux + 225)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_Linux + 226)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_Linux + 227)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_Linux + 228)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_Linux + 229)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_Linux + 230)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_Linux + 231)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_Linux + 232)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_Linux + 233)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_Linux + 234)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_Linux + 235)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_Linux + 236)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_Linux + 237)
+#endif
+
+/* #define __NR_sys_setaltroot (__NR_Linux + 238) */
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_Linux + 239)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_Linux + 240)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_Linux + 241)
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area (__NR_Linux + 242)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_Linux + 243)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_Linux + 244)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_Linux + 245)
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages (__NR_Linux + 246)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_Linux + 247)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_Linux + 248)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_Linux + 249)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_Linux + 250)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_Linux + 251)
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat (__NR_Linux + 252)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_Linux + 253)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_Linux + 254)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_Linux + 255)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_Linux + 256)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_Linux + 257)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_Linux + 258)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_Linux + 259)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_Linux + 260)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_Linux + 261)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_Linux + 262)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_Linux + 263)
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range (__NR_Linux + 264)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_Linux + 265)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_Linux + 266)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_Linux + 267)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_Linux + 268)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_Linux + 269)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_Linux + 270)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_Linux + 271)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_Linux + 272)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_Linux + 273)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_Linux + 274)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_Linux + 275)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_Linux + 276)
+#endif
+
+#if !defined(__NR_timerfd)
+#define __NR_timerfd (__NR_Linux + 277)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 278)
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate (__NR_Linux + 279)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_Linux + 280)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_Linux + 281)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_Linux + 282)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_Linux + 283)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_Linux + 284)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_Linux + 285)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_Linux + 286)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_Linux + 287)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_Linux + 288)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_Linux + 289)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_Linux + 290)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 291)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_Linux + 292)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_Linux + 293)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_Linux + 294)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_Linux + 295)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_Linux + 296)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_Linux + 297)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_Linux + 298)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_Linux + 299)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_Linux + 300)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_Linux + 301)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_Linux + 302)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_Linux + 303)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_Linux + 304)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_Linux + 305)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_Linux + 306)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_Linux + 307)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_Linux + 308)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_Linux + 309)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_Linux + 310)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_Linux + 311)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_Linux + 312)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/mips_linux_syscalls.h b/sandbox/linux/system_headers/mips_linux_syscalls.h
new file mode 100644
index 0000000..eb1717a
--- /dev/null
+++ b/sandbox/linux/system_headers/mips_linux_syscalls.h
@@ -0,0 +1,1428 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
+
+#if !defined(__mips__) || (_MIPS_SIM != _ABIO32)
+#error "Including header on wrong architecture"
+#endif
+
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+
+#if !defined(__NR_syscall)
+#define __NR_syscall (__NR_Linux + 0)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_Linux + 1)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_Linux + 2)
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_Linux + 3)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_Linux + 4)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_Linux + 5)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_Linux + 6)
+#endif
+
+#if !defined(__NR_waitpid)
+#define __NR_waitpid (__NR_Linux + 7)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_Linux + 8)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_Linux + 9)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_Linux + 10)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_Linux + 11)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_Linux + 12)
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time (__NR_Linux + 13)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_Linux + 14)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_Linux + 15)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_Linux + 16)
+#endif
+
+#if !defined(__NR_break)
+#define __NR_break (__NR_Linux + 17)
+#endif
+
+#if !defined(__NR_unused18)
+#define __NR_unused18 (__NR_Linux + 18)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_Linux + 19)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_Linux + 20)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_Linux + 21)
+#endif
+
+#if !defined(__NR_umount)
+#define __NR_umount (__NR_Linux + 22)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_Linux + 23)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_Linux + 24)
+#endif
+
+#if !defined(__NR_stime)
+#define __NR_stime (__NR_Linux + 25)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_Linux + 26)
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm (__NR_Linux + 27)
+#endif
+
+#if !defined(__NR_unused28)
+#define __NR_unused28 (__NR_Linux + 28)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_Linux + 29)
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime (__NR_Linux + 30)
+#endif
+
+#if !defined(__NR_stty)
+#define __NR_stty (__NR_Linux + 31)
+#endif
+
+#if !defined(__NR_gtty)
+#define __NR_gtty (__NR_Linux + 32)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_Linux + 33)
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice (__NR_Linux + 34)
+#endif
+
+#if !defined(__NR_ftime)
+#define __NR_ftime (__NR_Linux + 35)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_Linux + 36)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_Linux + 37)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_Linux + 38)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_Linux + 39)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_Linux + 40)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_Linux + 41)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_Linux + 42)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_Linux + 43)
+#endif
+
+#if !defined(__NR_prof)
+#define __NR_prof (__NR_Linux + 44)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_Linux + 45)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_Linux + 46)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_Linux + 47)
+#endif
+
+#if !defined(__NR_signal)
+#define __NR_signal (__NR_Linux + 48)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_Linux + 49)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_Linux + 50)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_Linux + 51)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_Linux + 52)
+#endif
+
+#if !defined(__NR_lock)
+#define __NR_lock (__NR_Linux + 53)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_Linux + 54)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_Linux + 55)
+#endif
+
+#if !defined(__NR_mpx)
+#define __NR_mpx (__NR_Linux + 56)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_Linux + 57)
+#endif
+
+#if !defined(__NR_ulimit)
+#define __NR_ulimit (__NR_Linux + 58)
+#endif
+
+#if !defined(__NR_unused59)
+#define __NR_unused59 (__NR_Linux + 59)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_Linux + 60)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_Linux + 61)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_Linux + 62)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_Linux + 63)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_Linux + 64)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_Linux + 65)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_Linux + 66)
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction (__NR_Linux + 67)
+#endif
+
+#if !defined(__NR_sgetmask)
+#define __NR_sgetmask (__NR_Linux + 68)
+#endif
+
+#if !defined(__NR_ssetmask)
+#define __NR_ssetmask (__NR_Linux + 69)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_Linux + 70)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_Linux + 71)
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend (__NR_Linux + 72)
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending (__NR_Linux + 73)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_Linux + 74)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_Linux + 75)
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit (__NR_Linux + 76)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_Linux + 77)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_Linux + 78)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_Linux + 79)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_Linux + 80)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_Linux + 81)
+#endif
+
+#if !defined(__NR_reserved82)
+#define __NR_reserved82 (__NR_Linux + 82)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_Linux + 83)
+#endif
+
+#if !defined(__NR_unused84)
+#define __NR_unused84 (__NR_Linux + 84)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_Linux + 85)
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib (__NR_Linux + 86)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_Linux + 87)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_Linux + 88)
+#endif
+
+#if !defined(__NR_readdir)
+#define __NR_readdir (__NR_Linux + 89)
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap (__NR_Linux + 90)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_Linux + 91)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_Linux + 92)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_Linux + 93)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_Linux + 94)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_Linux + 95)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_Linux + 96)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_Linux + 97)
+#endif
+
+#if !defined(__NR_profil)
+#define __NR_profil (__NR_Linux + 98)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_Linux + 99)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_Linux + 100)
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm (__NR_Linux + 101)
+#endif
+
+#if !defined(__NR_socketcall)
+#define __NR_socketcall (__NR_Linux + 102)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_Linux + 103)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_Linux + 104)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_Linux + 105)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_Linux + 106)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_Linux + 107)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_Linux + 108)
+#endif
+
+#if !defined(__NR_unused109)
+#define __NR_unused109 (__NR_Linux + 109)
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl (__NR_Linux + 110)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_Linux + 111)
+#endif
+
+#if !defined(__NR_idle)
+#define __NR_idle (__NR_Linux + 112)
+#endif
+
+#if !defined(__NR_vm86)
+#define __NR_vm86 (__NR_Linux + 113)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_Linux + 114)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_Linux + 115)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_Linux + 116)
+#endif
+
+#if !defined(__NR_ipc)
+#define __NR_ipc (__NR_Linux + 117)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_Linux + 118)
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn (__NR_Linux + 119)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_Linux + 120)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_Linux + 121)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_Linux + 122)
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt (__NR_Linux + 123)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_Linux + 124)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_Linux + 125)
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask (__NR_Linux + 126)
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module (__NR_Linux + 127)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_Linux + 128)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_Linux + 129)
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms (__NR_Linux + 130)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_Linux + 131)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_Linux + 132)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_Linux + 133)
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush (__NR_Linux + 134)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_Linux + 135)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_Linux + 136)
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall                               \
+  (__NR_Linux + 137) /* Syscall for Andrew File System \
+                        */
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_Linux + 138)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_Linux + 139)
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek (__NR_Linux + 140)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_Linux + 141)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_Linux + 142)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_Linux + 143)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_Linux + 144)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_Linux + 145)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_Linux + 146)
+#endif
+
+#if !defined(__NR_cacheflush)
+#define __NR_cacheflush (__NR_Linux + 147)
+#endif
+
+#if !defined(__NR_cachectl)
+#define __NR_cachectl (__NR_Linux + 148)
+#endif
+
+#if !defined(__NR_sysmips)
+#define __NR_sysmips (__NR_Linux + 149)
+#endif
+
+#if !defined(__NR_unused150)
+#define __NR_unused150 (__NR_Linux + 150)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_Linux + 151)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_Linux + 152)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_Linux + 153)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_Linux + 154)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_Linux + 155)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_Linux + 156)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_Linux + 157)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_Linux + 158)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_Linux + 159)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_Linux + 160)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_Linux + 161)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_Linux + 162)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_Linux + 163)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_Linux + 164)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_Linux + 165)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_Linux + 166)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_Linux + 167)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_Linux + 168)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_Linux + 169)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_Linux + 170)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_Linux + 171)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_Linux + 172)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_Linux + 173)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_Linux + 174)
+#endif
+
+#if !defined(__NR_recv)
+#define __NR_recv (__NR_Linux + 175)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_Linux + 176)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_Linux + 177)
+#endif
+
+#if !defined(__NR_send)
+#define __NR_send (__NR_Linux + 178)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_Linux + 179)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_Linux + 180)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_Linux + 181)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_Linux + 182)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_Linux + 183)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_Linux + 184)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_Linux + 185)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_Linux + 186)
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module (__NR_Linux + 187)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_Linux + 188)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_Linux + 189)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_Linux + 190)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_Linux + 191)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_Linux + 192)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_Linux + 193)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_Linux + 194)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_Linux + 195)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_Linux + 196)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_Linux + 197)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_Linux + 198)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_Linux + 199)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_Linux + 200)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_Linux + 201)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_Linux + 202)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_Linux + 203)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_Linux + 204)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_Linux + 205)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_Linux + 206)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_Linux + 207)
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg (__NR_Linux + 208)
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg (__NR_Linux + 209)
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 (__NR_Linux + 210)
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 (__NR_Linux + 211)
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 (__NR_Linux + 212)
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 (__NR_Linux + 213)
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 (__NR_Linux + 214)
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 (__NR_Linux + 215)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_Linux + 216)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_Linux + 217)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_Linux + 218)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_Linux + 219)
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 (__NR_Linux + 220)
+#endif
+
+#if !defined(__NR_reserved221)
+#define __NR_reserved221 (__NR_Linux + 221)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_Linux + 222)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_Linux + 223)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_Linux + 224)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_Linux + 225)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_Linux + 226)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_Linux + 227)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_Linux + 228)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_Linux + 229)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_Linux + 230)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_Linux + 231)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_Linux + 232)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_Linux + 233)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_Linux + 234)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_Linux + 235)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_Linux + 236)
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 (__NR_Linux + 237)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_Linux + 238)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_Linux + 239)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_Linux + 240)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_Linux + 241)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_Linux + 242)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_Linux + 243)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_Linux + 244)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_Linux + 245)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_Linux + 246)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_Linux + 247)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_Linux + 248)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_Linux + 249)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_Linux + 250)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_Linux + 251)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_Linux + 252)
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_Linux + 253)
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 (__NR_Linux + 254)
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 (__NR_Linux + 255)
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 (__NR_Linux + 256)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_Linux + 257)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_Linux + 258)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_Linux + 259)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_Linux + 260)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_Linux + 261)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_Linux + 262)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_Linux + 263)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_Linux + 264)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_Linux + 265)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_Linux + 266)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_Linux + 267)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_Linux + 268)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_Linux + 269)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_Linux + 270)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_Linux + 271)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_Linux + 272)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_Linux + 273)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_Linux + 274)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_Linux + 275)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_Linux + 276)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_Linux + 277)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_Linux + 278)
+#endif
+
+/* #define __NR_sys_setaltroot (__NR_Linux + 279) */
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_Linux + 280)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_Linux + 281)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_Linux + 282)
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area (__NR_Linux + 283)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_Linux + 284)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_Linux + 285)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_Linux + 286)
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages (__NR_Linux + 287)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_Linux + 288)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_Linux + 289)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_Linux + 290)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_Linux + 291)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_Linux + 292)
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 (__NR_Linux + 293)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_Linux + 294)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_Linux + 295)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_Linux + 296)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_Linux + 297)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_Linux + 298)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_Linux + 299)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_Linux + 300)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_Linux + 301)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_Linux + 302)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_Linux + 303)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_Linux + 304)
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range (__NR_Linux + 305)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_Linux + 306)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_Linux + 307)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_Linux + 308)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_Linux + 309)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_Linux + 310)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_Linux + 311)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_Linux + 312)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_Linux + 313)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_Linux + 314)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_Linux + 315)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_Linux + 316)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_Linux + 317)
+#endif
+
+#if !defined(__NR_timerfd)
+#define __NR_timerfd (__NR_Linux + 318)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 319)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 320)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_Linux + 321)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_Linux + 322)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_Linux + 323)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_Linux + 324)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_Linux + 325)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_Linux + 326)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_Linux + 327)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_Linux + 328)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_Linux + 329)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_Linux + 330)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_Linux + 331)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 332)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_Linux + 333)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_Linux + 334)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_Linux + 335)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_Linux + 336)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_Linux + 337)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_Linux + 338)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_Linux + 339)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_Linux + 340)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_Linux + 341)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_Linux + 342)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_Linux + 343)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_Linux + 344)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_Linux + 345)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_Linux + 346)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_Linux + 347)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_Linux + 348)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_Linux + 349)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_Linux + 350)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_Linux + 351)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_Linux + 352)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/system_headers/mips_linux_ucontext.h b/sandbox/linux/system_headers/mips_linux_ucontext.h
new file mode 100644
index 0000000..27b3763
--- /dev/null
+++ b/sandbox/linux/system_headers/mips_linux_ucontext.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
+
+// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
+// except we do use sigset_t for uc_sigmask instead of a custom type.
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+// Ensure that 'stack_t' is defined.
+#include <asm/signal.h>
+
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef unsigned long greg_t;
+
+typedef struct {
+  uint32_t regmask;
+  uint32_t status;
+  uint64_t pc;
+  uint64_t gregs[32];
+  uint64_t fpregs[32];
+  uint32_t acx;
+  uint32_t fpc_csr;
+  uint32_t fpc_eir;
+  uint32_t used_math;
+  uint32_t dsp;
+  uint64_t mdhi;
+  uint64_t mdlo;
+  uint32_t hi1;
+  uint32_t lo1;
+  uint32_t hi2;
+  uint32_t lo2;
+  uint32_t hi3;
+  uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  sigset_t uc_sigmask;
+  // Other fields are not used by Google Breakpad. Don't define them.
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/sandbox/linux/system_headers/x86_32_linux_syscalls.h
new file mode 100644
index 0000000..a6afc62
--- /dev/null
+++ b/sandbox/linux/system_headers/x86_32_linux_syscalls.h
@@ -0,0 +1,1426 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's syscall_32.tbl.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+
+#if !defined(__i386__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 0
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 1
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork 2
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 3
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 4
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open 5
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 6
+#endif
+
+#if !defined(__NR_waitpid)
+#define __NR_waitpid 7
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat 8
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link 9
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink 10
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 11
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 12
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time 13
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod 14
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod 15
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown 16
+#endif
+
+#if !defined(__NR_break)
+#define __NR_break 17
+#endif
+
+#if !defined(__NR_oldstat)
+#define __NR_oldstat 18
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 19
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 20
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 21
+#endif
+
+#if !defined(__NR_umount)
+#define __NR_umount 22
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 23
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 24
+#endif
+
+#if !defined(__NR_stime)
+#define __NR_stime 25
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 26
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm 27
+#endif
+
+#if !defined(__NR_oldfstat)
+#define __NR_oldfstat 28
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause 29
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime 30
+#endif
+
+#if !defined(__NR_stty)
+#define __NR_stty 31
+#endif
+
+#if !defined(__NR_gtty)
+#define __NR_gtty 32
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access 33
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice 34
+#endif
+
+#if !defined(__NR_ftime)
+#define __NR_ftime 35
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 36
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 37
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename 38
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir 39
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir 40
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 41
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe 42
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 43
+#endif
+
+#if !defined(__NR_prof)
+#define __NR_prof 44
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 45
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 46
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 47
+#endif
+
+#if !defined(__NR_signal)
+#define __NR_signal 48
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 49
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 50
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 51
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 52
+#endif
+
+#if !defined(__NR_lock)
+#define __NR_lock 53
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 54
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 55
+#endif
+
+#if !defined(__NR_mpx)
+#define __NR_mpx 56
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 57
+#endif
+
+#if !defined(__NR_ulimit)
+#define __NR_ulimit 58
+#endif
+
+#if !defined(__NR_oldolduname)
+#define __NR_oldolduname 59
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 60
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 61
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat 62
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 63
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 64
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp 65
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 66
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction 67
+#endif
+
+#if !defined(__NR_sgetmask)
+#define __NR_sgetmask 68
+#endif
+
+#if !defined(__NR_ssetmask)
+#define __NR_ssetmask 69
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 70
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 71
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend 72
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending 73
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 74
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 75
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 76
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 77
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 78
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 79
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 80
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 81
+#endif
+
+#if !defined(__NR_select)
+#define __NR_select 82
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink 83
+#endif
+
+#if !defined(__NR_oldlstat)
+#define __NR_oldlstat 84
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink 85
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib 86
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 87
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 88
+#endif
+
+#if !defined(__NR_readdir)
+#define __NR_readdir 89
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 90
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 91
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 92
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 93
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 94
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 95
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 96
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 97
+#endif
+
+#if !defined(__NR_profil)
+#define __NR_profil 98
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 99
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 100
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm 101
+#endif
+
+#if !defined(__NR_socketcall)
+#define __NR_socketcall 102
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 103
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 104
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 105
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat 106
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat 107
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 108
+#endif
+
+#if !defined(__NR_olduname)
+#define __NR_olduname 109
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl 110
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 111
+#endif
+
+#if !defined(__NR_idle)
+#define __NR_idle 112
+#endif
+
+#if !defined(__NR_vm86old)
+#define __NR_vm86old 113
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 114
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 115
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 116
+#endif
+
+#if !defined(__NR_ipc)
+#define __NR_ipc 117
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 118
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn 119
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 120
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 121
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 122
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt 123
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 124
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 125
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask 126
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module 127
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 128
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 129
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms 130
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 131
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 132
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 133
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush 134
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs 135
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 136
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall 137
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 138
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 139
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek 140
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents 141
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect 142
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 143
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 144
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 145
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 146
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 147
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 148
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl 149
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 150
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 151
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 152
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 153
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 154
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 155
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 156
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 157
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 158
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 159
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 160
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 161
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 162
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 163
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 164
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 165
+#endif
+
+#if !defined(__NR_vm86)
+#define __NR_vm86 166
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module 167
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll 168
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 169
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 170
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 171
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 172
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 173
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 174
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 175
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 176
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 177
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 178
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 179
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 180
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 181
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown 182
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 183
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 184
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 185
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 186
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 187
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg 188
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg 189
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork 190
+#endif
+
+#if !defined(__NR_ugetrlimit)
+#define __NR_ugetrlimit 191
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 192
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 193
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 194
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 195
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 196
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 197
+#endif
+
+#if !defined(__NR_lchown32)
+#define __NR_lchown32 198
+#endif
+
+#if !defined(__NR_getuid32)
+#define __NR_getuid32 199
+#endif
+
+#if !defined(__NR_getgid32)
+#define __NR_getgid32 200
+#endif
+
+#if !defined(__NR_geteuid32)
+#define __NR_geteuid32 201
+#endif
+
+#if !defined(__NR_getegid32)
+#define __NR_getegid32 202
+#endif
+
+#if !defined(__NR_setreuid32)
+#define __NR_setreuid32 203
+#endif
+
+#if !defined(__NR_setregid32)
+#define __NR_setregid32 204
+#endif
+
+#if !defined(__NR_getgroups32)
+#define __NR_getgroups32 205
+#endif
+
+#if !defined(__NR_setgroups32)
+#define __NR_setgroups32 206
+#endif
+
+#if !defined(__NR_fchown32)
+#define __NR_fchown32 207
+#endif
+
+#if !defined(__NR_setresuid32)
+#define __NR_setresuid32 208
+#endif
+
+#if !defined(__NR_getresuid32)
+#define __NR_getresuid32 209
+#endif
+
+#if !defined(__NR_setresgid32)
+#define __NR_setresgid32 210
+#endif
+
+#if !defined(__NR_getresgid32)
+#define __NR_getresgid32 211
+#endif
+
+#if !defined(__NR_chown32)
+#define __NR_chown32 212
+#endif
+
+#if !defined(__NR_setuid32)
+#define __NR_setuid32 213
+#endif
+
+#if !defined(__NR_setgid32)
+#define __NR_setgid32 214
+#endif
+
+#if !defined(__NR_setfsuid32)
+#define __NR_setfsuid32 215
+#endif
+
+#if !defined(__NR_setfsgid32)
+#define __NR_setfsgid32 216
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 217
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 218
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 219
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 220
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 221
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 224
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 225
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 226
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 227
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 228
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 229
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 230
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 231
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 232
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 233
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 234
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 235
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 236
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 237
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 238
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 239
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 240
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 241
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 242
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area 243
+#endif
+
+#if !defined(__NR_get_thread_area)
+#define __NR_get_thread_area 244
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 245
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 246
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 247
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 248
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 249
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 250
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 252
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 253
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create 254
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 255
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait 256
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 257
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 258
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 259
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 260
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 261
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 262
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 263
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 264
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 265
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 266
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 267
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 268
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 269
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 270
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes 271
+#endif
+
+#if !defined(__NR_fadvise64_64)
+#define __NR_fadvise64_64 272
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver 273
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 274
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 275
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 276
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 277
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 278
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 279
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 280
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 281
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 282
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 283
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 284
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 286
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 287
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 288
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 289
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 290
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init 291
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 292
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 293
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 294
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 295
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 296
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 297
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 298
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat 299
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 300
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 301
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 302
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 303
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 304
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 305
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 306
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 307
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 308
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 309
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 310
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 311
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 312
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 313
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 314
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 315
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 316
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 317
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 318
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 319
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 320
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd 321
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 322
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd 323
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 324
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 325
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 326
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 327
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 328
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 329
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 330
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 331
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 332
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 333
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 334
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 335
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 336
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 337
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 338
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 339
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 340
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 341
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 342
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 343
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 344
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 345
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 346
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 347
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 348
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 349
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 350
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 351
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 352
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 353
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 354
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 355
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 356
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+
diff --git a/sandbox/linux/system_headers/x86_64_linux_syscalls.h b/sandbox/linux/system_headers/x86_64_linux_syscalls.h
new file mode 100644
index 0000000..349504a
--- /dev/null
+++ b/sandbox/linux/system_headers/x86_64_linux_syscalls.h
@@ -0,0 +1,1294 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's syscall_64.tbl.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+
+#if !defined(__x86_64__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 0
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 1
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open 2
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 3
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat 4
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 5
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat 6
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll 7
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 8
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 9
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 10
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 11
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 12
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 13
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 14
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 15
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 16
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 17
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 18
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 19
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 20
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access 21
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe 22
+#endif
+
+#if !defined(__NR_select)
+#define __NR_select 23
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 24
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 25
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 26
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 27
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 28
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 29
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 30
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 31
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 32
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 33
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause 34
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 35
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 36
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm 37
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 38
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 39
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 40
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 41
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 42
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept 43
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 44
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 45
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 46
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 47
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 48
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 49
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 50
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 51
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 52
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 53
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 54
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 55
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 56
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork 57
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork 58
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 59
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 60
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 61
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 62
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 63
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 64
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop 65
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 66
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 67
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 68
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 69
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 70
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 71
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 72
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 73
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 74
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 75
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 76
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 77
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents 78
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 79
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 80
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 81
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename 82
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir 83
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir 84
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat 85
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link 86
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink 87
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink 88
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink 89
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod 90
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 91
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown 92
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 93
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown 94
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 95
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 96
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 97
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 98
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 99
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 100
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 101
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 102
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 103
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 104
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 105
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 106
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 107
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 108
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 109
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 110
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp 111
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 112
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 113
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 114
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 115
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 116
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 117
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 118
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 119
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 120
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 121
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 122
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 123
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 124
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 125
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 126
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 127
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 128
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 129
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 130
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 131
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime 132
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod 133
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib 134
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 135
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat 136
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 137
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 138
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs 139
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 140
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 141
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 142
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 143
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 144
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 145
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 146
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 147
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 148
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 149
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 150
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 151
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 152
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 153
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt 154
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 155
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl 156
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 157
+#endif
+
+#if !defined(__NR_arch_prctl)
+#define __NR_arch_prctl 158
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 159
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 160
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 161
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 162
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 163
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 164
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 165
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 166
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 167
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 168
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 169
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 170
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 171
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl 172
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm 173
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module 174
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 175
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 176
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms 177
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module 178
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 179
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 180
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg 181
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg 182
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall 183
+#endif
+
+#if !defined(__NR_tuxcall)
+#define __NR_tuxcall 184
+#endif
+
+#if !defined(__NR_security)
+#define __NR_security 185
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 186
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 187
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 188
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 189
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 190
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 191
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 192
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 193
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 194
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 195
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 196
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 197
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 198
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 199
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 200
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time 201
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 202
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 203
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 204
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area 205
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 206
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 207
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 208
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 209
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 210
+#endif
+
+#if !defined(__NR_get_thread_area)
+#define __NR_get_thread_area 211
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 212
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create 213
+#endif
+
+#if !defined(__NR_epoll_ctl_old)
+#define __NR_epoll_ctl_old 214
+#endif
+
+#if !defined(__NR_epoll_wait_old)
+#define __NR_epoll_wait_old 215
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 216
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 217
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 218
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 219
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop 220
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 221
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 222
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 223
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 224
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 225
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 226
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 227
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 228
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 229
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 230
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 231
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait 232
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 233
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 234
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes 235
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver 236
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 237
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 238
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 239
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 240
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 241
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 242
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 243
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 244
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 245
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 246
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 247
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 248
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 249
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 250
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 251
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 252
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init 253
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 254
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 255
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 256
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 257
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 258
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 259
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 260
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat 261
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat 262
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 263
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 264
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 265
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 266
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 267
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 268
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 269
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 270
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 271
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 272
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 273
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 274
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 275
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 276
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 277
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 278
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 279
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 280
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 281
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd 282
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 283
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd 284
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 285
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 286
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 287
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 288
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 289
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 290
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 291
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 292
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 293
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 294
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 295
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 296
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 297
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 298
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 299
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 300
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 301
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 302
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 303
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 304
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 305
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 306
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 307
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 308
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 309
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 310
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 311
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 312
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 313
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 314
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 315
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 316
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 317
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 318
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 319
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+
diff --git a/sandbox/linux/system_headers/x86_64_linux_ucontext.h b/sandbox/linux/system_headers/x86_64_linux_ucontext.h
new file mode 100644
index 0000000..57b8919
--- /dev/null
+++ b/sandbox/linux/system_headers/x86_64_linux_ucontext.h
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
+
+// We do something compatible with glibc. Hopefully, at some point Android will
+// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
+// Spec:
+// http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-AMD64/LSB-Core-AMD64/libc-ddefs.html#AEN5668
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#include <asm/sigcontext.h>
+
+struct _libc_fpxreg {
+  unsigned short significand[4];
+  unsigned short exponent;
+  unsigned short padding[3];
+};
+
+struct _libc_xmmreg {
+  uint32_t element[4];
+};
+
+struct _libc_fpstate {
+  uint16_t cwd;
+  uint16_t swd;
+  uint16_t twd;
+  uint16_t fop;
+  uint64_t rip;
+  uint64_t rdp;
+  uint32_t mxcsr;
+  uint32_t mxcsr_mask;
+  struct _libc_fpxreg _st[8];
+  struct _libc_xmmreg _xmm[16];
+  uint32_t padding[24];
+};
+
+typedef uint64_t greg_t;
+
+typedef struct {
+  greg_t gregs[23];
+  struct _libc_fpstate* fpregs;
+  unsigned long __reserved1[8];
+} mcontext_t;
+
+enum {
+  REG_R8 = 0,
+  REG_R9,
+  REG_R10,
+  REG_R11,
+  REG_R12,
+  REG_R13,
+  REG_R14,
+  REG_R15,
+  REG_RDI,
+  REG_RSI,
+  REG_RBP,
+  REG_RBX,
+  REG_RDX,
+  REG_RAX,
+  REG_RCX,
+  REG_RSP,
+  REG_RIP,
+  REG_EFL,
+  REG_CSGSFS,
+  REG_ERR,
+  REG_TRAPNO,
+  REG_OLDMASK,
+  REG_CR2,
+  NGREG,
+};
+
+typedef struct ucontext {
+  unsigned long uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  sigset_t uc_sigmask;
+  struct _libc_fpstate __fpregs_mem;
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/tests/main.cc b/sandbox/linux/tests/main.cc
new file mode 100644
index 0000000..687c8bb
--- /dev/null
+++ b/sandbox/linux/tests/main.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/at_exit.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/test/test_suite.h"
+#include "build/build_config.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace sandbox {
+namespace {
+
+// Check for leaks in our tests.
+void RunPostTestsChecks(const base::FilePath& orig_cwd) {
+  if (TestUtils::CurrentProcessHasChildren()) {
+    LOG(FATAL) << "One of the tests created a child that was not waited for. "
+               << "Please, clean up after your tests!";
+  }
+
+  base::FilePath cwd;
+  CHECK(GetCurrentDirectory(&cwd));
+  if (orig_cwd != cwd) {
+    LOG(FATAL) << "One of the tests changed the current working directory. "
+               << "Please, clean up after your tests!";
+  }
+}
+
+}  // namespace
+}  // namespace sandbox
+
+#if defined(OS_ANDROID)
+void UnitTestAssertHandler(const std::string& str) {
+  _exit(1);
+}
+#endif
+
+int main(int argc, char* argv[]) {
+  base::CommandLine::Init(argc, argv);
+  std::string client_func =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kTestChildProcess);
+  if (!client_func.empty()) {
+    base::AtExitManager exit_manager;
+    return multi_process_function_list::InvokeChildProcessTest(client_func);
+  }
+
+  base::FilePath orig_cwd;
+  CHECK(GetCurrentDirectory(&orig_cwd));
+
+#if defined(OS_ANDROID)
+  // The use of Callbacks requires an AtExitManager.
+  base::AtExitManager exit_manager;
+  testing::InitGoogleTest(&argc, argv);
+  // Death tests rely on LOG(FATAL) triggering an exit (the default behavior is
+  // SIGABRT).  The normal test launcher does this at initialization, but since
+  // we still do not use this on Android, we must install the handler ourselves.
+  logging::SetLogAssertHandler(UnitTestAssertHandler);
+#endif
+  // Always go through re-execution for death tests.
+  // This makes gtest only marginally slower for us and has the
+  // additional side effect of getting rid of gtest warnings about fork()
+  // safety.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+#if defined(OS_ANDROID)
+  int tests_result = RUN_ALL_TESTS();
+#else
+  int tests_result = base::RunUnitTestsUsingBaseTestSuite(argc, argv);
+#endif
+
+  sandbox::RunPostTestsChecks(orig_cwd);
+  return tests_result;
+}
diff --git a/sandbox/linux/tests/sandbox_test_runner.cc b/sandbox/linux/tests/sandbox_test_runner.cc
new file mode 100644
index 0000000..b099b97
--- /dev/null
+++ b/sandbox/linux/tests/sandbox_test_runner.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/tests/sandbox_test_runner.h"
+
+namespace sandbox {
+
+SandboxTestRunner::SandboxTestRunner() {
+}
+
+SandboxTestRunner::~SandboxTestRunner() {
+}
+
+bool SandboxTestRunner::ShouldCheckForLeaks() const {
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/tests/sandbox_test_runner.h b/sandbox/linux/tests/sandbox_test_runner.h
new file mode 100644
index 0000000..3155b74
--- /dev/null
+++ b/sandbox/linux/tests/sandbox_test_runner.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_H_
+#define SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_H_
+
+#include "base/macros.h"
+
+namespace sandbox {
+
+// A simple "runner" class to implement tests.
+class SandboxTestRunner {
+ public:
+  SandboxTestRunner();
+  virtual ~SandboxTestRunner();
+
+  virtual void Run() = 0;
+
+  // Override to decide whether or not to check for leaks with LSAN
+  // (if built with LSAN and LSAN is enabled).
+  virtual bool ShouldCheckForLeaks() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SandboxTestRunner);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_H_
diff --git a/sandbox/linux/tests/sandbox_test_runner_function_pointer.cc b/sandbox/linux/tests/sandbox_test_runner_function_pointer.cc
new file mode 100644
index 0000000..69e05ac
--- /dev/null
+++ b/sandbox/linux/tests/sandbox_test_runner_function_pointer.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/tests/sandbox_test_runner_function_pointer.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace sandbox {
+
+SandboxTestRunnerFunctionPointer::SandboxTestRunnerFunctionPointer(
+    void (*function_to_run)(void))
+    : function_to_run_(function_to_run) {
+}
+
+SandboxTestRunnerFunctionPointer::~SandboxTestRunnerFunctionPointer() {
+}
+
+void SandboxTestRunnerFunctionPointer::Run() {
+  DCHECK(function_to_run_);
+  function_to_run_();
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/tests/sandbox_test_runner_function_pointer.h b/sandbox/linux/tests/sandbox_test_runner_function_pointer.h
new file mode 100644
index 0000000..cadd07c
--- /dev/null
+++ b/sandbox/linux/tests/sandbox_test_runner_function_pointer.h
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_FUNCTION_POINTER_H_
+#define SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_FUNCTION_POINTER_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/tests/sandbox_test_runner.h"
+
+namespace sandbox {
+
+class SandboxTestRunnerFunctionPointer : public SandboxTestRunner {
+ public:
+  SandboxTestRunnerFunctionPointer(void (*function_to_run)(void));
+  ~SandboxTestRunnerFunctionPointer() override;
+  void Run() override;
+
+ private:
+  void (*function_to_run_)(void);
+  DISALLOW_COPY_AND_ASSIGN(SandboxTestRunnerFunctionPointer);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER__FUNCTION_POINTER_H_
diff --git a/sandbox/linux/tests/scoped_temporary_file.cc b/sandbox/linux/tests/scoped_temporary_file.cc
new file mode 100644
index 0000000..1f2d66f
--- /dev/null
+++ b/sandbox/linux/tests/scoped_temporary_file.cc
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/tests/scoped_temporary_file.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+
+namespace sandbox {
+
+ScopedTemporaryFile::ScopedTemporaryFile() : fd_(-1) {
+#if defined(OS_ANDROID)
+  static const char file_template[] = "/data/local/tmp/ScopedTempFileXXXXXX";
+#else
+  static const char file_template[] = "/tmp/ScopedTempFileXXXXXX";
+#endif  // defined(OS_ANDROID)
+  static_assert(sizeof(full_file_name_) >= sizeof(file_template),
+                "full_file_name is not large enough");
+  memcpy(full_file_name_, file_template, sizeof(file_template));
+  fd_ = mkstemp(full_file_name_);
+  CHECK_LE(0, fd_);
+}
+
+ScopedTemporaryFile::~ScopedTemporaryFile() {
+  CHECK_EQ(0, unlink(full_file_name_));
+  CHECK_EQ(0, IGNORE_EINTR(close(fd_)));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/tests/scoped_temporary_file.h b/sandbox/linux/tests/scoped_temporary_file.h
new file mode 100644
index 0000000..0734130
--- /dev/null
+++ b/sandbox/linux/tests/scoped_temporary_file.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_TESTS_SCOPED_TEMPORARY_FILE_H_
+#define SANDBOX_LINUX_TESTS_SCOPED_TEMPORARY_FILE_H_
+
+#include "base/macros.h"
+
+namespace sandbox {
+// Creates and open a temporary file on creation and closes
+// and removes it on destruction.
+// Unlike base/ helpers, this does not require JNI on Android.
+class ScopedTemporaryFile {
+ public:
+  ScopedTemporaryFile();
+  ~ScopedTemporaryFile();
+
+  int fd() const { return fd_; }
+  const char* full_file_name() const { return full_file_name_; }
+
+ private:
+  int fd_;
+  char full_file_name_[128];
+  DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_TESTS_SCOPED_TEMPORARY_FILE_H_
diff --git a/sandbox/linux/tests/scoped_temporary_file_unittest.cc b/sandbox/linux/tests/scoped_temporary_file_unittest.cc
new file mode 100644
index 0000000..44a2ecb
--- /dev/null
+++ b/sandbox/linux/tests/scoped_temporary_file_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/tests/scoped_temporary_file.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+bool FullWrite(int fd, const char* buffer, size_t count) {
+  while (count > 0) {
+    const ssize_t transfered = HANDLE_EINTR(write(fd, buffer, count));
+    if (transfered <= 0 || static_cast<size_t>(transfered) > count) {
+      return false;
+    }
+    count -= transfered;
+    buffer += transfered;
+  }
+  return true;
+}
+
+bool FullRead(int fd, char* buffer, size_t count) {
+  while (count > 0) {
+    const ssize_t transfered = HANDLE_EINTR(read(fd, buffer, count));
+    if (transfered <= 0 || static_cast<size_t>(transfered) > count) {
+      return false;
+    }
+    count -= transfered;
+    buffer += transfered;
+  }
+  return true;
+}
+
+TEST(ScopedTemporaryFile, Basics) {
+  std::string temp_file_name;
+  {
+    ScopedTemporaryFile temp_file_1;
+    const char kTestString[] = "This is a test";
+    ASSERT_LE(0, temp_file_1.fd());
+
+    temp_file_name = temp_file_1.full_file_name();
+    base::ScopedFD temp_file_2(open(temp_file_1.full_file_name(), O_RDONLY));
+    ASSERT_TRUE(temp_file_2.is_valid());
+
+    ASSERT_TRUE(FullWrite(temp_file_1.fd(), kTestString, sizeof(kTestString)));
+
+    char test_string_read[sizeof(kTestString)] = {0};
+    ASSERT_TRUE(FullRead(
+        temp_file_2.get(), test_string_read, sizeof(test_string_read)));
+    ASSERT_EQ(0, memcmp(kTestString, test_string_read, sizeof(kTestString)));
+  }
+
+  errno = 0;
+  struct stat buf;
+  ASSERT_EQ(-1, stat(temp_file_name.c_str(), &buf));
+  ASSERT_EQ(ENOENT, errno);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/tests/test_utils.cc b/sandbox/linux/tests/test_utils.cc
new file mode 100644
index 0000000..747bad2
--- /dev/null
+++ b/sandbox/linux/tests/test_utils.cc
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/tests/test_utils.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace sandbox {
+
+bool TestUtils::CurrentProcessHasChildren() {
+  siginfo_t process_info;
+  int ret = HANDLE_EINTR(
+      waitid(P_ALL, 0, &process_info, WEXITED | WNOHANG | WNOWAIT));
+  if (-1 == ret) {
+    PCHECK(ECHILD == errno);
+    return false;
+  } else {
+    return true;
+  }
+}
+
+void TestUtils::HandlePostForkReturn(pid_t pid) {
+  const int kChildExitCode = 1;
+  if (pid > 0) {
+    int status = 0;
+    PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0)));
+    CHECK(WIFEXITED(status));
+    CHECK_EQ(kChildExitCode, WEXITSTATUS(status));
+  } else if (pid == 0) {
+    _exit(kChildExitCode);
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/linux/tests/test_utils.h b/sandbox/linux/tests/test_utils.h
new file mode 100644
index 0000000..7cf9749
--- /dev/null
+++ b/sandbox/linux/tests/test_utils.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_TESTS_TEST_UTILS_H_
+#define SANDBOX_LINUX_TESTS_TEST_UTILS_H_
+
+#include <sys/types.h>
+
+#include "base/macros.h"
+
+namespace sandbox {
+
+// This class provide small helpers to help writing tests.
+class TestUtils {
+ public:
+  static bool CurrentProcessHasChildren();
+  // |pid| is the return value of a fork()-like call. This
+  // makes sure that if fork() succeeded the child exits
+  // and the parent waits for it.
+  static void HandlePostForkReturn(pid_t pid);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TestUtils);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_TESTS_TEST_UTILS_H_
diff --git a/sandbox/linux/tests/test_utils_unittest.cc b/sandbox/linux/tests/test_utils_unittest.cc
new file mode 100644
index 0000000..0f86e61
--- /dev/null
+++ b/sandbox/linux/tests/test_utils_unittest.cc
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/tests/test_utils.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+// Check that HandlePostForkReturn works.
+TEST(TestUtils, HandlePostForkReturn) {
+  pid_t pid = fork();
+  TestUtils::HandlePostForkReturn(pid);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc
new file mode 100644
index 0000000..5872e94
--- /dev/null
+++ b/sandbox/linux/tests/unit_tests.cc
@@ -0,0 +1,336 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/debug/leak_annotations.h"
+#include "base/files/file_util.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace {
+std::string TestFailedMessage(const std::string& msg) {
+  return msg.empty() ? std::string() : "Actual test failure: " + msg;
+}
+
+int GetSubProcessTimeoutTimeInSeconds() {
+  // 10s ought to be enough for anybody.
+  return 10;
+}
+
+// Returns the number of threads of the current process or -1.
+int CountThreads() {
+  struct stat task_stat;
+  int task_d = stat("/proc/self/task", &task_stat);
+  // task_stat.st_nlink should be the number of tasks + 2 (accounting for
+  // "." and "..".
+  if (task_d != 0 || task_stat.st_nlink < 3)
+    return -1;
+  const int num_threads = task_stat.st_nlink - 2;
+  return num_threads;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+bool IsAndroid() {
+#if defined(OS_ANDROID)
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool IsArchitectureArm() {
+#if defined(ARCH_CPU_ARM_FAMILY)
+  return true;
+#else
+  return false;
+#endif
+}
+
+// TODO(jln): figure out why base/.../dynamic_annotations.h's
+// RunningOnValgrind() cannot link.
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
+static const int kExpectedValue = 42;
+static const int kIgnoreThisTest = 43;
+static const int kExitWithAssertionFailure = 1;
+static const int kExitForTimeout = 2;
+
+#if !defined(OS_ANDROID)
+// This is due to StackDumpSignalHandler() performing _exit(1).
+// TODO(jln): get rid of the collision with kExitWithAssertionFailure.
+const int kExitAfterSIGSEGV = 1;
+#endif
+
+static void SigAlrmHandler(int) {
+  const char failure_message[] = "Timeout reached!\n";
+  // Make sure that we never block here.
+  if (!fcntl(2, F_SETFL, O_NONBLOCK)) {
+    ignore_result(write(2, failure_message, sizeof(failure_message) - 1));
+  }
+  _exit(kExitForTimeout);
+}
+
+// Set a timeout with a handler that will automatically fail the
+// test.
+static void SetProcessTimeout(int time_in_seconds) {
+  struct sigaction act = {};
+  act.sa_handler = SigAlrmHandler;
+  SANDBOX_ASSERT(sigemptyset(&act.sa_mask) == 0);
+  act.sa_flags = 0;
+
+  struct sigaction old_act;
+  SANDBOX_ASSERT(sigaction(SIGALRM, &act, &old_act) == 0);
+
+  // We don't implemenet signal chaining, so make sure that nothing else
+  // is expecting to handle SIGALRM.
+  SANDBOX_ASSERT((old_act.sa_flags & SA_SIGINFO) == 0);
+  SANDBOX_ASSERT(old_act.sa_handler == SIG_DFL);
+  sigset_t sigalrm_set;
+  SANDBOX_ASSERT(sigemptyset(&sigalrm_set) == 0);
+  SANDBOX_ASSERT(sigaddset(&sigalrm_set, SIGALRM) == 0);
+  SANDBOX_ASSERT(sigprocmask(SIG_UNBLOCK, &sigalrm_set, NULL) == 0);
+  SANDBOX_ASSERT(alarm(time_in_seconds) == 0);  // There should be no previous
+                                                // alarm.
+}
+
+// Runs a test in a sub-process. This is necessary for most of the code
+// in the BPF sandbox, as it potentially makes global state changes and as
+// it also tends to raise fatal errors, if the code has been used in an
+// insecure manner.
+void UnitTests::RunTestInProcess(SandboxTestRunner* test_runner,
+                                 DeathCheck death,
+                                 const void* death_aux) {
+  CHECK(test_runner);
+  // We need to fork(), so we can't be multi-threaded, as threads could hold
+  // locks.
+  int num_threads = CountThreads();
+#if !defined(THREAD_SANITIZER)
+  const int kNumExpectedThreads = 1;
+#else
+  // Under TSAN, there is a special helper thread. It should be completely
+  // invisible to our testing, so we ignore it. It should be ok to fork()
+  // with this thread. It's currently buggy, but it's the best we can do until
+  // there is a way to delay the start of the thread
+  // (https://code.google.com/p/thread-sanitizer/issues/detail?id=19).
+  const int kNumExpectedThreads = 2;
+#endif
+
+  // The kernel is at liberty to wake a thread id futex before updating /proc.
+  // If another test running in the same process has stopped a thread, it may
+  // appear as still running in /proc.
+  // We poll /proc, with an exponential back-off. At most, we'll sleep around
+  // 2^iterations nanoseconds in nanosleep().
+  for (unsigned int iteration = 0; iteration < 30; iteration++) {
+    struct timespec ts = {0, 1L << iteration /* nanoseconds */};
+    PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
+    num_threads = CountThreads();
+    if (kNumExpectedThreads == num_threads)
+      break;
+  }
+
+  ASSERT_EQ(kNumExpectedThreads, num_threads)
+      << "Running sandbox tests with multiple threads "
+      << "is not supported and will make the tests flaky.";
+  int fds[2];
+  ASSERT_EQ(0, pipe(fds));
+  // Check that our pipe is not on one of the standard file descriptor.
+  SANDBOX_ASSERT(fds[0] > 2 && fds[1] > 2);
+
+  pid_t pid;
+  ASSERT_LE(0, (pid = fork()));
+  if (!pid) {
+    // In child process
+    // Redirect stderr to our pipe. This way, we can capture all error
+    // messages, if we decide we want to do so in our tests.
+    SANDBOX_ASSERT(dup2(fds[1], 2) == 2);
+    SANDBOX_ASSERT(!close(fds[0]));
+    SANDBOX_ASSERT(!close(fds[1]));
+
+    // Don't set a timeout if running on Valgrind, since it's generally much
+    // slower.
+    if (!IsRunningOnValgrind()) {
+      SetProcessTimeout(GetSubProcessTimeoutTimeInSeconds());
+    }
+
+    // Disable core files. They are not very useful for our individual test
+    // cases.
+    struct rlimit no_core = {0};
+    setrlimit(RLIMIT_CORE, &no_core);
+
+    test_runner->Run();
+    if (test_runner->ShouldCheckForLeaks()) {
+#if defined(LEAK_SANITIZER)
+      __lsan_do_leak_check();
+#endif
+    }
+    _exit(kExpectedValue);
+  }
+
+  close(fds[1]);
+  std::vector<char> msg_buf;
+  ssize_t rc;
+
+  // Make sure read() will never block as we'll use poll() to
+  // block with a timeout instead.
+  const int fcntl_ret = fcntl(fds[0], F_SETFL, O_NONBLOCK);
+  ASSERT_EQ(0, fcntl_ret);
+  struct pollfd poll_fd = {fds[0], POLLIN | POLLRDHUP, 0};
+
+  int poll_ret;
+  // We prefer the SIGALRM timeout to trigger in the child than this timeout
+  // so we double the common value here.
+  int poll_timeout = GetSubProcessTimeoutTimeInSeconds() * 2 * 1000;
+  while ((poll_ret = poll(&poll_fd, 1, poll_timeout) > 0)) {
+    const size_t kCapacity = 256;
+    const size_t len = msg_buf.size();
+    msg_buf.resize(len + kCapacity);
+    rc = HANDLE_EINTR(read(fds[0], &msg_buf[len], kCapacity));
+    msg_buf.resize(len + std::max(rc, static_cast<ssize_t>(0)));
+    if (rc <= 0)
+      break;
+  }
+  ASSERT_NE(poll_ret, -1) << "poll() failed";
+  ASSERT_NE(poll_ret, 0) << "Timeout while reading child state";
+  close(fds[0]);
+  std::string msg(msg_buf.begin(), msg_buf.end());
+
+  int status = 0;
+  int waitpid_returned = HANDLE_EINTR(waitpid(pid, &status, 0));
+  ASSERT_EQ(pid, waitpid_returned) << TestFailedMessage(msg);
+
+  // At run-time, we sometimes decide that a test shouldn't actually
+  // run (e.g. when testing sandbox features on a kernel that doesn't
+  // have sandboxing support). When that happens, don't attempt to
+  // call the "death" function, as it might be looking for a
+  // death-test condition that would never have triggered.
+  if (!WIFEXITED(status) || WEXITSTATUS(status) != kIgnoreThisTest ||
+      !msg.empty()) {
+    // We use gtest's ASSERT_XXX() macros instead of the DeathCheck
+    // functions.  This means, on failure, "return" is called. This
+    // only works correctly, if the call of the "death" callback is
+    // the very last thing in our function.
+    death(status, msg, death_aux);
+  }
+}
+
+void UnitTests::DeathSuccess(int status, const std::string& msg, const void*) {
+  std::string details(TestFailedMessage(msg));
+
+  bool subprocess_terminated_normally = WIFEXITED(status);
+  ASSERT_TRUE(subprocess_terminated_normally) << details;
+  int subprocess_exit_status = WEXITSTATUS(status);
+  ASSERT_EQ(kExpectedValue, subprocess_exit_status) << details;
+  bool subprocess_exited_but_printed_messages = !msg.empty();
+  EXPECT_FALSE(subprocess_exited_but_printed_messages) << details;
+}
+
+void UnitTests::DeathSuccessAllowNoise(int status,
+                                       const std::string& msg,
+                                       const void*) {
+  std::string details(TestFailedMessage(msg));
+
+  bool subprocess_terminated_normally = WIFEXITED(status);
+  ASSERT_TRUE(subprocess_terminated_normally) << details;
+  int subprocess_exit_status = WEXITSTATUS(status);
+  ASSERT_EQ(kExpectedValue, subprocess_exit_status) << details;
+}
+
+void UnitTests::DeathMessage(int status,
+                             const std::string& msg,
+                             const void* aux) {
+  std::string details(TestFailedMessage(msg));
+  const char* expected_msg = static_cast<const char*>(aux);
+
+  bool subprocess_terminated_normally = WIFEXITED(status);
+  ASSERT_TRUE(subprocess_terminated_normally) << "Exit status: " << status
+                                              << " " << details;
+  int subprocess_exit_status = WEXITSTATUS(status);
+  ASSERT_EQ(1, subprocess_exit_status) << details;
+
+  bool subprocess_exited_without_matching_message =
+      msg.find(expected_msg) == std::string::npos;
+
+// In official builds CHECK messages are dropped, so look for SIGABRT.
+// See https://code.google.com/p/chromium/issues/detail?id=437312
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
+  if (subprocess_exited_without_matching_message) {
+    static const char kSigAbortMessage[] = "Received signal 6";
+    subprocess_exited_without_matching_message =
+        msg.find(kSigAbortMessage) == std::string::npos;
+  }
+#endif
+  EXPECT_FALSE(subprocess_exited_without_matching_message) << details;
+}
+
+void UnitTests::DeathSEGVMessage(int status,
+                                 const std::string& msg,
+                                 const void* aux) {
+  std::string details(TestFailedMessage(msg));
+  const char* expected_msg = static_cast<const char*>(aux);
+
+#if defined(OS_ANDROID)
+  const bool subprocess_got_sigsegv =
+      WIFSIGNALED(status) && (SIGSEGV == WTERMSIG(status));
+#else
+  const bool subprocess_got_sigsegv =
+      WIFEXITED(status) && (kExitAfterSIGSEGV == WEXITSTATUS(status));
+#endif
+
+  ASSERT_TRUE(subprocess_got_sigsegv) << "Exit status: " << status
+                                      << " " << details;
+
+  bool subprocess_exited_without_matching_message =
+      msg.find(expected_msg) == std::string::npos;
+  EXPECT_FALSE(subprocess_exited_without_matching_message) << details;
+}
+
+void UnitTests::DeathExitCode(int status,
+                              const std::string& msg,
+                              const void* aux) {
+  int expected_exit_code = static_cast<int>(reinterpret_cast<intptr_t>(aux));
+  std::string details(TestFailedMessage(msg));
+
+  bool subprocess_terminated_normally = WIFEXITED(status);
+  ASSERT_TRUE(subprocess_terminated_normally) << details;
+  int subprocess_exit_status = WEXITSTATUS(status);
+  ASSERT_EQ(expected_exit_code, subprocess_exit_status) << details;
+}
+
+void UnitTests::DeathBySignal(int status,
+                              const std::string& msg,
+                              const void* aux) {
+  int expected_signo = static_cast<int>(reinterpret_cast<intptr_t>(aux));
+  std::string details(TestFailedMessage(msg));
+
+  bool subprocess_terminated_by_signal = WIFSIGNALED(status);
+  ASSERT_TRUE(subprocess_terminated_by_signal) << details;
+  int subprocess_signal_number = WTERMSIG(status);
+  ASSERT_EQ(expected_signo, subprocess_signal_number) << details;
+}
+
+void UnitTests::AssertionFailure(const char* expr, const char* file, int line) {
+  fprintf(stderr, "%s:%d:%s", file, line, expr);
+  fflush(stderr);
+  _exit(kExitWithAssertionFailure);
+}
+
+void UnitTests::IgnoreThisTest() {
+  fflush(stderr);
+  _exit(kIgnoreThisTest);
+}
+
+}  // namespace
diff --git a/sandbox/linux/tests/unit_tests.h b/sandbox/linux/tests/unit_tests.h
new file mode 100644
index 0000000..5a7116e
--- /dev/null
+++ b/sandbox/linux/tests/unit_tests.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_TESTS_UNIT_TESTS_H_
+#define SANDBOX_LINUX_TESTS_UNIT_TESTS_H_
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/tests/sandbox_test_runner_function_pointer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Has this been compiled to run on Android?
+bool IsAndroid();
+
+bool IsArchitectureArm();
+
+// Is Valgrind currently being used?
+bool IsRunningOnValgrind();
+
+#if defined(ADDRESS_SANITIZER)
+#define DISABLE_ON_ASAN(test_name) DISABLED_##test_name
+#else
+#define DISABLE_ON_ASAN(test_name) test_name
+#endif  // defined(ADDRESS_SANITIZER)
+
+#if defined(LEAK_SANITIZER)
+#define DISABLE_ON_LSAN(test_name) DISABLED_##test_name
+#else
+#define DISABLE_ON_LSAN(test_name) test_name
+#endif
+
+#if defined(THREAD_SANITIZER)
+#define DISABLE_ON_TSAN(test_name) DISABLED_##test_name
+#else
+#define DISABLE_ON_TSAN(test_name) test_name
+#endif  // defined(THREAD_SANITIZER)
+
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) ||    \
+    defined(UNDEFINED_SANITIZER) || defined(SANITIZER_COVERAGE)
+#define DISABLE_ON_SANITIZERS(test_name) DISABLED_##test_name
+#else
+#define DISABLE_ON_SANITIZERS(test_name) test_name
+#endif
+
+#if defined(OS_ANDROID)
+#define DISABLE_ON_ANDROID(test_name) DISABLED_##test_name
+#else
+#define DISABLE_ON_ANDROID(test_name) test_name
+#endif
+
+// While it is perfectly OK for a complex test to provide its own DeathCheck
+// function. Most death tests have very simple requirements. These tests should
+// use one of the predefined DEATH_XXX macros as an argument to
+// SANDBOX_DEATH_TEST(). You can check for a (sub-)string in the output of the
+// test, for a particular exit code, or for a particular death signal.
+// NOTE: If you do decide to write your own DeathCheck, make sure to use
+//       gtests's ASSERT_XXX() macros instead of SANDBOX_ASSERT(). See
+//       unit_tests.cc for examples.
+#define DEATH_SUCCESS() sandbox::UnitTests::DeathSuccess, NULL
+#define DEATH_SUCCESS_ALLOW_NOISE() \
+  sandbox::UnitTests::DeathSuccessAllowNoise, NULL
+#define DEATH_MESSAGE(msg)          \
+  sandbox::UnitTests::DeathMessage, \
+      static_cast<const void*>(static_cast<const char*>(msg))
+#define DEATH_SEGV_MESSAGE(msg)         \
+  sandbox::UnitTests::DeathSEGVMessage, \
+      static_cast<const void*>(static_cast<const char*>(msg))
+#define DEATH_EXIT_CODE(rc)          \
+  sandbox::UnitTests::DeathExitCode, \
+      reinterpret_cast<void*>(static_cast<intptr_t>(rc))
+#define DEATH_BY_SIGNAL(s)           \
+  sandbox::UnitTests::DeathBySignal, \
+      reinterpret_cast<void*>(static_cast<intptr_t>(s))
+
+// A SANDBOX_DEATH_TEST is just like a SANDBOX_TEST (see below), but it assumes
+// that the test actually dies. The death test only passes if the death occurs
+// in the expected fashion, as specified by "death" and "death_aux". These two
+// parameters are typically set to one of the DEATH_XXX() macros.
+#define SANDBOX_DEATH_TEST(test_case_name, test_name, death)                \
+  void TEST_##test_name(void);                                              \
+  TEST(test_case_name, test_name) {                                         \
+    SandboxTestRunnerFunctionPointer sandbox_test_runner(TEST_##test_name); \
+    sandbox::UnitTests::RunTestInProcess(&sandbox_test_runner, death);      \
+  }                                                                         \
+  void TEST_##test_name(void)
+
+// Define a new test case that runs inside of a GTest death test. This is
+// necessary, as most of our tests by definition make global and irreversible
+// changes to the system (i.e. they install a sandbox). GTest provides death
+// tests as a tool to isolate global changes from the rest of the tests.
+#define SANDBOX_TEST(test_case_name, test_name) \
+  SANDBOX_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS())
+
+// SANDBOX_TEST_ALLOW_NOISE is just like SANDBOX_TEST, except it does not
+// consider log error messages printed by the test to be test failures.
+#define SANDBOX_TEST_ALLOW_NOISE(test_case_name, test_name) \
+  SANDBOX_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS_ALLOW_NOISE())
+
+// Simple assertion macro that is compatible with running inside of a death
+// test. We unfortunately cannot use any of the GTest macros.
+#define SANDBOX_STR(x) #x
+#define SANDBOX_ASSERT(expr)                                             \
+  ((expr) ? static_cast<void>(0) : sandbox::UnitTests::AssertionFailure( \
+                                       SANDBOX_STR(expr), __FILE__, __LINE__))
+
+#define SANDBOX_ASSERT_EQ(x, y) SANDBOX_ASSERT((x) == (y))
+#define SANDBOX_ASSERT_NE(x, y) SANDBOX_ASSERT((x) != (y))
+#define SANDBOX_ASSERT_LT(x, y) SANDBOX_ASSERT((x) < (y))
+#define SANDBOX_ASSERT_GT(x, y) SANDBOX_ASSERT((x) > (y))
+#define SANDBOX_ASSERT_LE(x, y) SANDBOX_ASSERT((x) <= (y))
+#define SANDBOX_ASSERT_GE(x, y) SANDBOX_ASSERT((x) >= (y))
+
+// This class allows to run unittests in their own process. The main method is
+// RunTestInProcess().
+class UnitTests {
+ public:
+  typedef void (*DeathCheck)(int status,
+                             const std::string& msg,
+                             const void* aux);
+
+  // Runs a test inside a short-lived process. Do not call this function
+  // directly. It is automatically invoked by SANDBOX_TEST(). Most sandboxing
+  // functions make global irreversible changes to the execution environment
+  // and must therefore execute in their own isolated process.
+  // |test_runner| must implement the SandboxTestRunner interface and will run
+  // in a subprocess.
+  // Note: since the child process (created with fork()) will never return from
+  // RunTestInProcess(), |test_runner| is guaranteed to exist for the lifetime
+  // of the child process.
+  static void RunTestInProcess(SandboxTestRunner* test_runner,
+                               DeathCheck death,
+                               const void* death_aux);
+
+  // Report a useful error message and terminate the current SANDBOX_TEST().
+  // Calling this function from outside a SANDBOX_TEST() is unlikely to do
+  // anything useful.
+  static void AssertionFailure(const char* expr, const char* file, int line);
+
+  // Sometimes we determine at run-time that a test should be disabled.
+  // Call this method if we want to return from a test and completely
+  // ignore its results.
+  // You should not call this method, if the test already ran any test-relevant
+  // code. Most notably, you should not call it, you already wrote any messages
+  // to stderr.
+  static void IgnoreThisTest();
+
+  // A DeathCheck method that verifies that the test completed succcessfully.
+  // This is the default test mode for SANDBOX_TEST(). The "aux" parameter
+  // of this DeathCheck is unused (and thus unnamed)
+  static void DeathSuccess(int status, const std::string& msg, const void*);
+
+  // A DeathCheck method that verifies that the test completed succcessfully
+  // allowing for log error messages.
+  static void DeathSuccessAllowNoise(int status,
+                                     const std::string& msg,
+                                     const void*);
+
+  // A DeathCheck method that verifies that the test completed with error
+  // code "1" and printed a message containing a particular substring. The
+  // "aux" pointer should point to a C-string containing the expected error
+  // message. This method is useful for checking assertion failures such as
+  // in SANDBOX_ASSERT() and/or SANDBOX_DIE().
+  static void DeathMessage(int status, const std::string& msg, const void* aux);
+
+  // Like DeathMessage() but the process must be terminated with a segmentation
+  // fault.
+  // Implementation detail: On Linux (but not on Android), this does check for
+  // the return value of our default signal handler rather than for the actual
+  // reception of a SIGSEGV.
+  // TODO(jln): make this more robust.
+  static void DeathSEGVMessage(int status,
+                               const std::string& msg,
+                               const void* aux);
+
+  // A DeathCheck method that verifies that the test completed with a
+  // particular exit code. If the test output any messages to stderr, they are
+  // silently ignored. The expected exit code should be passed in by
+  // casting the its "int" value to a "void *", which is then used for "aux".
+  static void DeathExitCode(int status,
+                            const std::string& msg,
+                            const void* aux);
+
+  // A DeathCheck method that verifies that the test was terminated by a
+  // particular signal. If the test output any messages to stderr, they are
+  // silently ignore. The expected signal number should be passed in by
+  // casting the its "int" value to a "void *", which is then used for "aux".
+  static void DeathBySignal(int status,
+                            const std::string& msg,
+                            const void* aux);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(UnitTests);
+};
+
+}  // namespace
+
+#endif  // SANDBOX_LINUX_TESTS_UNIT_TESTS_H_
diff --git a/sandbox/linux/tests/unit_tests_unittest.cc b/sandbox/linux/tests/unit_tests_unittest.cc
new file mode 100644
index 0000000..57799b1
--- /dev/null
+++ b/sandbox/linux/tests/unit_tests_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+namespace {
+
+// Let's not use any of the "magic" values used internally in unit_tests.cc,
+// such as kExpectedValue.
+const int kExpectedExitCode = 100;
+
+SANDBOX_DEATH_TEST(UnitTests,
+                   DeathExitCode,
+                   DEATH_EXIT_CODE(kExpectedExitCode)) {
+  _exit(kExpectedExitCode);
+}
+
+const int kExpectedSignalNumber = SIGKILL;
+
+SANDBOX_DEATH_TEST(UnitTests,
+                   DeathBySignal,
+                   DEATH_BY_SIGNAL(kExpectedSignalNumber)) {
+  raise(kExpectedSignalNumber);
+}
+
+SANDBOX_DEATH_TEST(UnitTests,
+                   DeathWithMessage,
+                   DEATH_MESSAGE("Hello")) {
+  LOG(ERROR) << "Hello";
+  _exit(1);
+}
+
+SANDBOX_DEATH_TEST(UnitTests,
+                   SEGVDeathWithMessage,
+                   DEATH_SEGV_MESSAGE("Hello")) {
+  LOG(ERROR) << "Hello";
+  while (1) {
+    volatile char* addr = reinterpret_cast<volatile char*>(NULL);
+    *addr = '\0';
+  }
+
+  _exit(2);
+}
+
+SANDBOX_TEST_ALLOW_NOISE(UnitTests, NoisyTest) {
+  LOG(ERROR) << "The cow says moo!";
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/sandbox/mac/BUILD.gn b/sandbox/mac/BUILD.gn
new file mode 100644
index 0000000..d74bfcb
--- /dev/null
+++ b/sandbox/mac/BUILD.gn
@@ -0,0 +1,104 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/mac/mac_sdk.gni")
+import("//testing/test.gni")
+
+generate_stubs_script = "//tools/generate_stubs/generate_stubs.py"
+generate_stubs_header = "xpc_stubs_header.fragment"
+generate_stubs_sig_public = "xpc_stubs.sig"
+generate_stubs_sig_private = "xpc_private_stubs.sig"
+generate_stubs_project = "sandbox/mac"
+generate_stubs_output_stem = "xpc_stubs"
+
+action("generate_stubs") {
+  script = generate_stubs_script
+  sources = [
+    generate_stubs_sig_private,
+    generate_stubs_sig_public,
+  ]
+  inputs = [
+    generate_stubs_header,
+  ]
+  outputs = [
+    "$target_gen_dir/$generate_stubs_output_stem.cc",
+    "$target_gen_dir/$generate_stubs_output_stem.h",
+  ]
+  args = [
+    "-i",
+    rebase_path(target_gen_dir, root_build_dir),
+    "-o",
+    rebase_path(target_gen_dir, root_build_dir),
+    "-t",
+    "posix_stubs",
+    "-e",
+    rebase_path(generate_stubs_header, root_build_dir),
+    "-s",
+    generate_stubs_output_stem,
+    "-p",
+    generate_stubs_project,
+    "-x",
+    "SANDBOX_EXPORT",
+  ]
+  args += rebase_path(sources, root_build_dir)
+}
+
+component("sandbox") {
+  sources = [
+    "bootstrap_sandbox.cc",
+    "bootstrap_sandbox.h",
+    "dispatch_source_mach.cc",
+    "dispatch_source_mach.h",
+    "launchd_interception_server.cc",
+    "launchd_interception_server.h",
+    "mach_message_server.cc",
+    "mach_message_server.h",
+    "message_server.h",
+    "os_compatibility.cc",
+    "os_compatibility.h",
+    "policy.cc",
+    "policy.h",
+    "xpc.cc",
+    "xpc.h",
+    "xpc_message_server.cc",
+    "xpc_message_server.h",
+  ]
+
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+  libs = [ "bsm" ]
+
+  deps = [
+    "//base",
+  ]
+
+  # When the build SDK is 10.6, generate a dynamic stub loader. When the
+  # SDK is higher, then libxpc.dylib will be loaded automatically as part
+  # of libSystem, and only forward declarations of private symbols are
+  # necessary.
+  if (mac_sdk_version == "10.6") {
+    deps += [ ":generate_stubs" ]
+    sources += get_target_outputs(":generate_stubs")
+  }
+}
+
+test("sandbox_mac_unittests") {
+  sources = [
+    "bootstrap_sandbox_unittest.mm",
+    "dispatch_source_mach_unittest.cc",
+    "policy_unittest.cc",
+    "xpc_message_server_unittest.cc",
+  ]
+
+  libs = [
+    "CoreFoundation.framework",
+    "Foundation.framework",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//testing/gtest",
+  ]
+}
diff --git a/sandbox/mac/OWNERS b/sandbox/mac/OWNERS
new file mode 100644
index 0000000..163563f
--- /dev/null
+++ b/sandbox/mac/OWNERS
@@ -0,0 +1,2 @@
+mark@chromium.org
+rsesek@chromium.org
diff --git a/sandbox/mac/bootstrap_sandbox.cc b/sandbox/mac/bootstrap_sandbox.cc
new file mode 100644
index 0000000..a90f570
--- /dev/null
+++ b/sandbox/mac/bootstrap_sandbox.cc
@@ -0,0 +1,133 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/bootstrap_sandbox.h"
+
+#include <servers/bootstrap.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/strings/stringprintf.h"
+#include "sandbox/mac/launchd_interception_server.h"
+
+namespace sandbox {
+
+const int kNotAPolicy = -1;
+
+// static
+scoped_ptr<BootstrapSandbox> BootstrapSandbox::Create() {
+  scoped_ptr<BootstrapSandbox> null;  // Used for early returns.
+  scoped_ptr<BootstrapSandbox> sandbox(new BootstrapSandbox());
+  sandbox->server_.reset(new LaunchdInterceptionServer(sandbox.get()));
+
+  // Check in with launchd to get the receive right for the server that is
+  // published in the bootstrap namespace.
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = bootstrap_check_in(bootstrap_port,
+      sandbox->server_bootstrap_name().c_str(), &port);
+  if (kr != KERN_SUCCESS) {
+    BOOTSTRAP_LOG(ERROR, kr)
+        << "Failed to bootstrap_check_in the sandbox server.";
+    return null.Pass();
+  }
+  base::mac::ScopedMachReceiveRight scoped_port(port);
+
+  // Start the sandbox server.
+  if (sandbox->server_->Initialize(scoped_port.get()))
+    ignore_result(scoped_port.release());  // Transferred to server_.
+  else
+    return null.Pass();
+
+  return sandbox.Pass();
+}
+
+BootstrapSandbox::~BootstrapSandbox() {
+}
+
+void BootstrapSandbox::RegisterSandboxPolicy(
+    int sandbox_policy_id,
+    const BootstrapSandboxPolicy& policy) {
+  CHECK(IsPolicyValid(policy));
+  CHECK_GT(sandbox_policy_id, kNotAPolicy);
+  base::AutoLock lock(lock_);
+  DCHECK(policies_.find(sandbox_policy_id) == policies_.end());
+  policies_.insert(std::make_pair(sandbox_policy_id, policy));
+}
+
+void BootstrapSandbox::PrepareToForkWithPolicy(int sandbox_policy_id) {
+  base::AutoLock lock(lock_);
+
+  // Verify that this is a real policy.
+  CHECK(policies_.find(sandbox_policy_id) != policies_.end());
+  CHECK_EQ(kNotAPolicy, effective_policy_id_)
+      << "Cannot nest calls to PrepareToForkWithPolicy()";
+
+  // Store the policy for the process we're about to create.
+  effective_policy_id_ = sandbox_policy_id;
+}
+
+// TODO(rsesek): The |lock_| needs to be taken twice because
+// base::LaunchProcess handles both fork+exec, and holding the lock for the
+// duration would block servicing of other bootstrap messages. If a better
+// LaunchProcess existed (do arbitrary work without layering violations), this
+// could be avoided.
+
+void BootstrapSandbox::FinishedFork(base::ProcessHandle handle) {
+  base::AutoLock lock(lock_);
+
+  CHECK_NE(kNotAPolicy, effective_policy_id_)
+      << "Must PrepareToForkWithPolicy() before FinishedFork()";
+
+  // Apply the policy to the new process.
+  if (handle != base::kNullProcessHandle) {
+    const auto& existing_process = sandboxed_processes_.find(handle);
+    CHECK(existing_process == sandboxed_processes_.end());
+    sandboxed_processes_.insert(std::make_pair(handle, effective_policy_id_));
+    VLOG(3) << "Bootstrap sandbox enforced for pid " << handle;
+  }
+
+  effective_policy_id_ = kNotAPolicy;
+}
+
+void BootstrapSandbox::ChildDied(base::ProcessHandle handle) {
+  base::AutoLock lock(lock_);
+  const auto& it = sandboxed_processes_.find(handle);
+  if (it != sandboxed_processes_.end())
+    sandboxed_processes_.erase(it);
+}
+
+const BootstrapSandboxPolicy* BootstrapSandbox::PolicyForProcess(
+    pid_t pid) const {
+  base::AutoLock lock(lock_);
+  const auto& process = sandboxed_processes_.find(pid);
+
+  // The new child could send bootstrap requests before the parent calls
+  // FinishedFork().
+  int policy_id = effective_policy_id_;
+  if (process != sandboxed_processes_.end()) {
+    policy_id = process->second;
+  }
+
+  if (policy_id == kNotAPolicy)
+    return NULL;
+
+  return &policies_.find(policy_id)->second;
+}
+
+BootstrapSandbox::BootstrapSandbox()
+    : server_bootstrap_name_(
+          base::StringPrintf("%s.sandbox.%d", base::mac::BaseBundleID(),
+              getpid())),
+      real_bootstrap_port_(MACH_PORT_NULL),
+      effective_policy_id_(kNotAPolicy) {
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = task_get_special_port(
+      mach_task_self(), TASK_BOOTSTRAP_PORT, &port);
+  MACH_CHECK(kr == KERN_SUCCESS, kr);
+  real_bootstrap_port_.reset(port);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/bootstrap_sandbox.h b/sandbox/mac/bootstrap_sandbox.h
new file mode 100644
index 0000000..fd808cd
--- /dev/null
+++ b/sandbox/mac/bootstrap_sandbox.h
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_BOOTSTRAP_SANDBOX_H_
+#define SANDBOX_MAC_BOOTSTRAP_SANDBOX_H_
+
+#include <mach/mach.h>
+
+#include <map>
+#include <string>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
+#include "sandbox/mac/policy.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+class LaunchdInterceptionServer;
+
+// The BootstrapSandbox is a second-layer sandbox for Mac. It is used to limit
+// the bootstrap namespace attack surface of child processes. The parent
+// process creates an instance of this class and registers policies that it
+// can enforce on its children.
+//
+// With this sandbox, the parent process must replace the bootstrap port prior
+// to the sandboxed target's execution. This should be done by setting the
+// base::LaunchOptions.replacement_bootstrap_name to the
+// server_bootstrap_name() of this class. Requests from the child that would
+// normally go to launchd are filtered based on the specified per-process
+// policies. If a request is permitted by the policy, it is forwarded on to
+// launchd for servicing. If it is not, then the sandbox will reply with a
+// primitive that does not grant additional capabilities to the receiver.
+//
+// Clients that which to use the sandbox must inform it of the creation and
+// death of child processes for which the sandbox should be enforced. The
+// client of the sandbox is intended to be an unsandboxed parent process that
+// fork()s sandboxed (and other unsandboxed) child processes.
+//
+// When the parent is ready to fork a new child process with this sandbox
+// being enforced, it should use the pair of methods PrepareToForkWithPolicy()
+// and FinishedFork(), and call fork() between them. The first method will
+// set the policy for the new process, and the second will finialize the
+// association between the process ID and sandbox policy ID.
+//
+// All methods of this class may be called from any thread, but
+// PrepareToForkWithPolicy() and FinishedFork() must be non-nested and balanced.
+class SANDBOX_EXPORT BootstrapSandbox {
+ public:
+  // Creates a new sandbox manager. Returns NULL on failure.
+  static scoped_ptr<BootstrapSandbox> Create();
+
+  ~BootstrapSandbox();
+
+  // Registers a bootstrap policy associated it with an identifier. The
+  // |sandbox_policy_id| must be greater than 0.
+  void RegisterSandboxPolicy(int sandbox_policy_id,
+                             const BootstrapSandboxPolicy& policy);
+
+  // Called in the parent prior to fork()ing a child. The policy registered
+  // to |sandbox_policy_id| will be enforced on the new child. This must be
+  // followed by a call to FinishedFork().
+  void PrepareToForkWithPolicy(int sandbox_policy_id);
+
+  // Called in the parent after fork()ing a child. It records the |handle|
+  // and associates it with the specified-above |sandbox_policy_id|.
+  // If fork() failed and a new child was not created, pass kNullProcessHandle.
+  void FinishedFork(base::ProcessHandle handle);
+
+  // Called in the parent when a process has died. It cleans up the references
+  // to the process.
+  void ChildDied(base::ProcessHandle handle);
+
+  // Looks up the policy for a given process ID. If no policy is associated
+  // with the |pid|, this returns NULL.
+  const BootstrapSandboxPolicy* PolicyForProcess(pid_t pid) const;
+
+  std::string server_bootstrap_name() const { return server_bootstrap_name_; }
+  mach_port_t real_bootstrap_port() const { return real_bootstrap_port_; }
+
+ private:
+  BootstrapSandbox();
+
+  // The name in the system bootstrap server by which the |server_|'s port
+  // is known.
+  const std::string server_bootstrap_name_;
+
+  // The original bootstrap port of the process, which is connected to the
+  // real launchd server.
+  base::mac::ScopedMachSendRight real_bootstrap_port_;
+
+  // The |lock_| protects all the following variables.
+  mutable base::Lock lock_;
+
+  // The sandbox_policy_id that will be enforced for the new child.
+  int effective_policy_id_;
+
+  // All the policies that have been registered with this sandbox manager.
+  std::map<int, const BootstrapSandboxPolicy> policies_;
+
+  // The association between process ID and sandbox policy ID.
+  std::map<base::ProcessHandle, int> sandboxed_processes_;
+
+  // A Mach IPC message server that is used to intercept and filter bootstrap
+  // requests.
+  scoped_ptr<LaunchdInterceptionServer> server_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_BOOTSTRAP_SANDBOX_H_
diff --git a/sandbox/mac/bootstrap_sandbox_unittest.mm b/sandbox/mac/bootstrap_sandbox_unittest.mm
new file mode 100644
index 0000000..7e5e8b6
--- /dev/null
+++ b/sandbox/mac/bootstrap_sandbox_unittest.mm
@@ -0,0 +1,518 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/bootstrap_sandbox.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#import <Foundation/Foundation.h>
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/process/kill.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#import "testing/gtest_mac.h"
+#include "testing/multiprocess_func_list.h"
+
+NSString* const kTestNotification = @"org.chromium.bootstrap_sandbox_test";
+
+@interface DistributedNotificationObserver : NSObject {
+ @private
+  int receivedCount_;
+  base::scoped_nsobject<NSString> object_;
+}
+- (int)receivedCount;
+- (NSString*)object;
+- (void)waitForNotification;
+@end
+
+@implementation DistributedNotificationObserver
+- (id)init {
+  if ((self = [super init])) {
+    [[NSDistributedNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(observeNotification:)
+               name:kTestNotification
+             object:nil];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [[NSDistributedNotificationCenter defaultCenter]
+      removeObserver:self
+                name:kTestNotification
+              object:nil];
+  [super dealloc];
+}
+
+- (int)receivedCount {
+  return receivedCount_;
+}
+
+- (NSString*)object {
+  return object_.get();
+}
+
+- (void)waitForNotification {
+  object_.reset();
+  CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+      TestTimeouts::action_timeout().InSeconds(), false);
+}
+
+- (void)observeNotification:(NSNotification*)notification {
+  ++receivedCount_;
+  object_.reset([[notification object] copy]);
+  CFRunLoopStop(CFRunLoopGetCurrent());
+}
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace sandbox {
+
+class BootstrapSandboxTest : public base::MultiProcessTest {
+ public:
+  void SetUp() override {
+    base::MultiProcessTest::SetUp();
+
+    sandbox_ = BootstrapSandbox::Create();
+    ASSERT_TRUE(sandbox_.get());
+  }
+
+  BootstrapSandboxPolicy BaselinePolicy() {
+    BootstrapSandboxPolicy policy;
+    if (base::mac::IsOSSnowLeopard())
+      policy.rules["com.apple.SecurityServer"] = Rule(POLICY_ALLOW);
+    return policy;
+  }
+
+  void RunChildWithPolicy(int policy_id,
+                          const char* child_name,
+                          base::ProcessHandle* out_pid) {
+    sandbox_->PrepareToForkWithPolicy(policy_id);
+    base::LaunchOptions options;
+    options.replacement_bootstrap_name = sandbox_->server_bootstrap_name();
+    base::Process process = SpawnChildWithOptions(child_name, options);
+    ASSERT_TRUE(process.IsValid());
+    sandbox_->FinishedFork(process.Handle());
+    int code = 0;
+    EXPECT_TRUE(process.WaitForExit(&code));
+    EXPECT_EQ(0, code);
+    if (out_pid)
+      *out_pid = process.Pid();
+  }
+
+ protected:
+  scoped_ptr<BootstrapSandbox> sandbox_;
+};
+
+const char kNotificationTestMain[] = "PostNotification";
+
+// Run the test without the sandbox.
+TEST_F(BootstrapSandboxTest, DistributedNotifications_Unsandboxed) {
+  base::scoped_nsobject<DistributedNotificationObserver> observer(
+      [[DistributedNotificationObserver alloc] init]);
+
+  base::Process process = SpawnChild(kNotificationTestMain);
+  ASSERT_TRUE(process.IsValid());
+  int code = 0;
+  EXPECT_TRUE(process.WaitForExit(&code));
+  EXPECT_EQ(0, code);
+
+  [observer waitForNotification];
+  EXPECT_EQ(1, [observer receivedCount]);
+  EXPECT_EQ(process.Pid(), [[observer object] intValue]);
+}
+
+// Run the test with the sandbox enabled without notifications on the policy
+// whitelist.
+TEST_F(BootstrapSandboxTest, DistributedNotifications_SandboxDeny) {
+  base::scoped_nsobject<DistributedNotificationObserver> observer(
+      [[DistributedNotificationObserver alloc] init]);
+
+  sandbox_->RegisterSandboxPolicy(1, BaselinePolicy());
+  RunChildWithPolicy(1, kNotificationTestMain, NULL);
+
+  [observer waitForNotification];
+  EXPECT_EQ(0, [observer receivedCount]);
+  EXPECT_EQ(nil, [observer object]);
+}
+
+// Run the test with notifications permitted.
+TEST_F(BootstrapSandboxTest, DistributedNotifications_SandboxAllow) {
+  base::scoped_nsobject<DistributedNotificationObserver> observer(
+      [[DistributedNotificationObserver alloc] init]);
+
+  BootstrapSandboxPolicy policy(BaselinePolicy());
+  // 10.9:
+  policy.rules["com.apple.distributed_notifications@Uv3"] = Rule(POLICY_ALLOW);
+  policy.rules["com.apple.distributed_notifications@1v3"] = Rule(POLICY_ALLOW);
+  // 10.6:
+  policy.rules["com.apple.system.notification_center"] = Rule(POLICY_ALLOW);
+  policy.rules["com.apple.distributed_notifications.2"] = Rule(POLICY_ALLOW);
+  sandbox_->RegisterSandboxPolicy(2, policy);
+
+  base::ProcessHandle pid;
+  RunChildWithPolicy(2, kNotificationTestMain, &pid);
+
+  [observer waitForNotification];
+  EXPECT_EQ(1, [observer receivedCount]);
+  EXPECT_EQ(pid, [[observer object] intValue]);
+}
+
+MULTIPROCESS_TEST_MAIN(PostNotification) {
+  [[NSDistributedNotificationCenter defaultCenter]
+      postNotificationName:kTestNotification
+                    object:[NSString stringWithFormat:@"%d", getpid()]];
+  return 0;
+}
+
+const char kTestServer[] = "org.chromium.test_bootstrap_server";
+
+TEST_F(BootstrapSandboxTest, PolicyDenyError) {
+  BootstrapSandboxPolicy policy(BaselinePolicy());
+  policy.rules[kTestServer] = Rule(POLICY_DENY_ERROR);
+  sandbox_->RegisterSandboxPolicy(1, policy);
+
+  RunChildWithPolicy(1, "PolicyDenyError", NULL);
+}
+
+MULTIPROCESS_TEST_MAIN(PolicyDenyError) {
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer,
+      &port);
+  CHECK_EQ(BOOTSTRAP_UNKNOWN_SERVICE, kr);
+  CHECK(port == MACH_PORT_NULL);
+
+  kr = bootstrap_look_up(bootstrap_port, "org.chromium.some_other_server",
+      &port);
+  CHECK_EQ(BOOTSTRAP_UNKNOWN_SERVICE, kr);
+  CHECK(port == MACH_PORT_NULL);
+
+  return 0;
+}
+
+TEST_F(BootstrapSandboxTest, PolicyDenyDummyPort) {
+  BootstrapSandboxPolicy policy(BaselinePolicy());
+  policy.rules[kTestServer] = Rule(POLICY_DENY_DUMMY_PORT);
+  sandbox_->RegisterSandboxPolicy(1, policy);
+
+  RunChildWithPolicy(1, "PolicyDenyDummyPort", NULL);
+}
+
+MULTIPROCESS_TEST_MAIN(PolicyDenyDummyPort) {
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer,
+      &port);
+  CHECK_EQ(KERN_SUCCESS, kr);
+  CHECK(port != MACH_PORT_NULL);
+  return 0;
+}
+
+struct SubstitutePortAckSend {
+  mach_msg_header_t header;
+  char buf[32];
+};
+
+struct SubstitutePortAckRecv : public SubstitutePortAckSend {
+  mach_msg_trailer_t trailer;
+};
+
+const char kSubstituteAck[] = "Hello, this is doge!";
+
+TEST_F(BootstrapSandboxTest, PolicySubstitutePort) {
+  mach_port_t task = mach_task_self();
+
+  mach_port_t port;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE,
+      &port));
+  base::mac::ScopedMachReceiveRight scoped_port(port);
+
+  mach_port_urefs_t send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  EXPECT_EQ(0u, send_rights);
+
+  ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port,
+      MACH_MSG_TYPE_MAKE_SEND));
+  base::mac::ScopedMachSendRight scoped_port_send(port);
+
+  send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  EXPECT_EQ(1u, send_rights);
+
+  BootstrapSandboxPolicy policy(BaselinePolicy());
+  policy.rules[kTestServer] = Rule(port);
+  sandbox_->RegisterSandboxPolicy(1, policy);
+
+  RunChildWithPolicy(1, "PolicySubstitutePort", NULL);
+
+  struct SubstitutePortAckRecv msg;
+  bzero(&msg, sizeof(msg));
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_local_port = port;
+  kern_return_t kr = mach_msg(&msg.header, MACH_RCV_MSG, 0,
+      msg.header.msgh_size, port,
+      TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL);
+  EXPECT_EQ(KERN_SUCCESS, kr);
+
+  send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  EXPECT_EQ(1u, send_rights);
+
+  EXPECT_EQ(0, strncmp(kSubstituteAck, msg.buf, sizeof(msg.buf)));
+}
+
+MULTIPROCESS_TEST_MAIN(PolicySubstitutePort) {
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = bootstrap_look_up(bootstrap_port, kTestServer, &port);
+  CHECK_EQ(KERN_SUCCESS, kr);
+  CHECK(port != MACH_PORT_NULL);
+
+  struct SubstitutePortAckSend msg;
+  bzero(&msg, sizeof(msg));
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_remote_port = port;
+  msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND);
+  strncpy(msg.buf, kSubstituteAck, sizeof(msg.buf));
+
+  CHECK_EQ(KERN_SUCCESS, mach_msg_send(&msg.header));
+
+  return 0;
+}
+
+TEST_F(BootstrapSandboxTest, ForwardMessageInProcess) {
+  mach_port_t task = mach_task_self();
+
+  mach_port_t port;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE,
+      &port));
+  base::mac::ScopedMachReceiveRight scoped_port_recv(port);
+
+  mach_port_urefs_t send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  EXPECT_EQ(0u, send_rights);
+
+  ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port,
+      MACH_MSG_TYPE_MAKE_SEND));
+  base::mac::ScopedMachSendRight scoped_port_send(port);
+
+  send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  EXPECT_EQ(1u, send_rights);
+
+  mach_port_t bp;
+  ASSERT_EQ(KERN_SUCCESS, task_get_bootstrap_port(task, &bp));
+  base::mac::ScopedMachSendRight scoped_bp(bp);
+
+  char service_name[] = "org.chromium.sandbox.test.ForwardMessageInProcess";
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+  kern_return_t kr = bootstrap_register(bp, service_name, port);
+#pragma GCC diagnostic pop
+  EXPECT_EQ(KERN_SUCCESS, kr);
+
+  send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  EXPECT_EQ(1u, send_rights);
+
+  mach_port_t service_port;
+  EXPECT_EQ(KERN_SUCCESS, bootstrap_look_up(bp, service_name, &service_port));
+  base::mac::ScopedMachSendRight scoped_service_port(service_port);
+
+  send_rights = 0;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+      &send_rights));
+  // On 10.6, bootstrap_lookup2 may add an extra right to place it in a per-
+  // process cache.
+  if (base::mac::IsOSSnowLeopard())
+    EXPECT_TRUE(send_rights == 3u || send_rights == 2u) << send_rights;
+  else
+    EXPECT_EQ(2u, send_rights);
+}
+
+const char kDefaultRuleTestAllow[] =
+    "org.chromium.sandbox.test.DefaultRuleAllow";
+const char kDefaultRuleTestDeny[] =
+    "org.chromium.sandbox.test.DefaultRuleAllow.Deny";
+
+TEST_F(BootstrapSandboxTest, DefaultRuleAllow) {
+  mach_port_t task = mach_task_self();
+
+  mach_port_t port;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE,
+      &port));
+  base::mac::ScopedMachReceiveRight scoped_port_recv(port);
+
+  ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port,
+      MACH_MSG_TYPE_MAKE_SEND));
+  base::mac::ScopedMachSendRight scoped_port_send(port);
+
+  BootstrapSandboxPolicy policy;
+  policy.default_rule = Rule(POLICY_ALLOW);
+  policy.rules[kDefaultRuleTestAllow] = Rule(port);
+  policy.rules[kDefaultRuleTestDeny] = Rule(POLICY_DENY_ERROR);
+  sandbox_->RegisterSandboxPolicy(3, policy);
+
+  base::scoped_nsobject<DistributedNotificationObserver> observer(
+      [[DistributedNotificationObserver alloc] init]);
+
+  int pid = 0;
+  RunChildWithPolicy(3, "DefaultRuleAllow", &pid);
+  EXPECT_GT(pid, 0);
+
+  [observer waitForNotification];
+  EXPECT_EQ(1, [observer receivedCount]);
+  EXPECT_EQ(pid, [[observer object] intValue]);
+
+  struct SubstitutePortAckRecv msg;
+  bzero(&msg, sizeof(msg));
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_local_port = port;
+  kern_return_t kr = mach_msg(&msg.header, MACH_RCV_MSG, 0,
+      msg.header.msgh_size, port,
+      TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL);
+  EXPECT_EQ(KERN_SUCCESS, kr);
+
+  EXPECT_EQ(0, strncmp(kSubstituteAck, msg.buf, sizeof(msg.buf)));
+}
+
+MULTIPROCESS_TEST_MAIN(DefaultRuleAllow) {
+  [[NSDistributedNotificationCenter defaultCenter]
+      postNotificationName:kTestNotification
+                    object:[NSString stringWithFormat:@"%d", getpid()]];
+
+  mach_port_t port = MACH_PORT_NULL;
+  CHECK_EQ(BOOTSTRAP_UNKNOWN_SERVICE, bootstrap_look_up(bootstrap_port,
+      const_cast<char*>(kDefaultRuleTestDeny), &port));
+  CHECK(port == MACH_PORT_NULL);
+
+  CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port,
+      const_cast<char*>(kDefaultRuleTestAllow), &port));
+  CHECK(port != MACH_PORT_NULL);
+
+  struct SubstitutePortAckSend msg;
+  bzero(&msg, sizeof(msg));
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_remote_port = port;
+  msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND);
+  strncpy(msg.buf, kSubstituteAck, sizeof(msg.buf));
+
+  CHECK_EQ(KERN_SUCCESS, mach_msg_send(&msg.header));
+
+  return 0;
+}
+
+TEST_F(BootstrapSandboxTest, ChildOutliveSandbox) {
+  const int kTestPolicyId = 1;
+  mach_port_t task = mach_task_self();
+
+  // Create a server port.
+  mach_port_t port;
+  ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE,
+      &port));
+  base::mac::ScopedMachReceiveRight scoped_port_recv(port);
+
+  ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port,
+      MACH_MSG_TYPE_MAKE_SEND));
+  base::mac::ScopedMachSendRight scoped_port_send(port);
+
+  // Set up the policy and register the port.
+  BootstrapSandboxPolicy policy(BaselinePolicy());
+  policy.rules["sync"] = Rule(port);
+  sandbox_->RegisterSandboxPolicy(kTestPolicyId, policy);
+
+  // Launch the child.
+  sandbox_->PrepareToForkWithPolicy(kTestPolicyId);
+  base::LaunchOptions options;
+  options.replacement_bootstrap_name = sandbox_->server_bootstrap_name();
+  base::Process process = SpawnChildWithOptions("ChildOutliveSandbox", options);
+  ASSERT_TRUE(process.IsValid());
+  sandbox_->FinishedFork(process.Handle());
+
+  // Synchronize with the child.
+  mach_msg_empty_rcv_t rcv_msg;
+  bzero(&rcv_msg, sizeof(rcv_msg));
+  kern_return_t kr = mach_msg(&rcv_msg.header, MACH_RCV_MSG, 0,
+      sizeof(rcv_msg), port,
+      TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL);
+  ASSERT_EQ(KERN_SUCCESS, kr) << mach_error_string(kr);
+
+  // Destroy the sandbox.
+  sandbox_.reset();
+
+  // Synchronize again with the child.
+  mach_msg_empty_send_t send_msg;
+  bzero(&send_msg, sizeof(send_msg));
+  send_msg.header.msgh_size = sizeof(send_msg);
+  send_msg.header.msgh_remote_port = rcv_msg.header.msgh_remote_port;
+  send_msg.header.msgh_bits =
+      MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE);
+  kr = mach_msg(&send_msg.header, MACH_SEND_MSG, send_msg.header.msgh_size, 0,
+      MACH_PORT_NULL, TestTimeouts::tiny_timeout().InMilliseconds(),
+      MACH_PORT_NULL);
+  EXPECT_EQ(KERN_SUCCESS, kr) << mach_error_string(kr);
+
+  int code = 0;
+  EXPECT_TRUE(process.WaitForExit(&code));
+  EXPECT_EQ(0, code);
+}
+
+MULTIPROCESS_TEST_MAIN(ChildOutliveSandbox) {
+  // Get the synchronization channel.
+  mach_port_t port = MACH_PORT_NULL;
+  CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, "sync", &port));
+
+  // Create a reply port.
+  mach_port_t reply_port;
+  CHECK_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(),
+      MACH_PORT_RIGHT_RECEIVE, &reply_port));
+  base::mac::ScopedMachReceiveRight scoped_reply_port(reply_port);
+
+  // Send a message to shutdown the sandbox.
+  mach_msg_empty_send_t send_msg;
+  bzero(&send_msg, sizeof(send_msg));
+  send_msg.header.msgh_size = sizeof(send_msg);
+  send_msg.header.msgh_local_port = reply_port;
+  send_msg.header.msgh_remote_port = port;
+  send_msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND,
+                                             MACH_MSG_TYPE_MAKE_SEND_ONCE);
+  kern_return_t kr = mach_msg_send(&send_msg.header);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_msg_send";
+
+  // Flood the server's message queue with messages. There should be some
+  // pending when the sandbox is destroyed.
+  for (int i = 0; i < 20; ++i) {
+    mach_port_t tmp = MACH_PORT_NULL;
+    std::string name = base::StringPrintf("test.%d", i);
+    bootstrap_look_up(bootstrap_port, const_cast<char*>(name.c_str()), &tmp);
+  }
+
+  // Ack that the sandbox has been shutdown.
+  mach_msg_empty_rcv_t rcv_msg;
+  bzero(&rcv_msg, sizeof(rcv_msg));
+  rcv_msg.header.msgh_size = sizeof(rcv_msg);
+  rcv_msg.header.msgh_local_port = reply_port;
+  kr = mach_msg_receive(&rcv_msg.header);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_msg_receive";
+
+  // Try to message the sandbox.
+  bootstrap_look_up(bootstrap_port, "test", &port);
+
+  return 0;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/dispatch_source_mach.cc b/sandbox/mac/dispatch_source_mach.cc
new file mode 100644
index 0000000..a6f3ac8
--- /dev/null
+++ b/sandbox/mac/dispatch_source_mach.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/dispatch_source_mach.h"
+
+namespace sandbox {
+
+DispatchSourceMach::DispatchSourceMach(const char* name,
+                                       mach_port_t port,
+                                       void (^event_handler)())
+    // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL
+    // means the same thing but is not symbolically clear.
+    : DispatchSourceMach(dispatch_queue_create(name, NULL),
+                         port,
+                         event_handler) {
+  // Since the queue was created above in the delegated constructor, and it was
+  // subsequently retained, release it here.
+  dispatch_release(queue_);
+}
+
+DispatchSourceMach::DispatchSourceMach(dispatch_queue_t queue,
+                                       mach_port_t port,
+                                       void (^event_handler)())
+    : queue_(queue),
+      source_(dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
+          port, 0, queue_)),
+      source_canceled_(dispatch_semaphore_create(0)) {
+  dispatch_retain(queue);
+
+  dispatch_source_set_event_handler(source_, event_handler);
+  dispatch_source_set_cancel_handler(source_, ^{
+      dispatch_semaphore_signal(source_canceled_);
+  });
+}
+
+DispatchSourceMach::~DispatchSourceMach() {
+  Cancel();
+}
+
+void DispatchSourceMach::Resume() {
+  dispatch_resume(source_);
+}
+
+void DispatchSourceMach::Cancel() {
+  if (source_) {
+    dispatch_source_cancel(source_);
+    dispatch_release(source_);
+    source_ = NULL;
+
+    dispatch_semaphore_wait(source_canceled_, DISPATCH_TIME_FOREVER);
+    dispatch_release(source_canceled_);
+    source_canceled_ = NULL;
+  }
+
+  if (queue_) {
+    dispatch_release(queue_);
+    queue_ = NULL;
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/dispatch_source_mach.h b/sandbox/mac/dispatch_source_mach.h
new file mode 100644
index 0000000..e3a3aa0
--- /dev/null
+++ b/sandbox/mac/dispatch_source_mach.h
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_DISPATCH_SOURCE_MACH_H_
+#define SANDBOX_MAC_DISPATCH_SOURCE_MACH_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This class encapsulates a MACH_RECV dispatch source. When this object is
+// destroyed, the source will be cancelled and it will wait for the source
+// to stop executing work. The source can run on either a user-supplied queue,
+// or it can create its own for the source.
+class SANDBOX_EXPORT DispatchSourceMach {
+ public:
+  // Creates a new dispatch source for the |port| and schedules it on a new
+  // queue that will be created with |name|. When a Mach message is received,
+  // the |event_handler| will be called.
+  DispatchSourceMach(const char* name,
+                     mach_port_t port,
+                     void (^event_handler)());
+
+  // Creates a new dispatch source with the same semantics as above, but rather
+  // than creating a new queue, it schedules the source on |queue|.
+  DispatchSourceMach(dispatch_queue_t queue,
+                     mach_port_t port,
+                     void (^event_handler)());
+
+  // Cancels the source and waits for it to become fully cancelled before
+  // releasing the source.
+  ~DispatchSourceMach();
+
+  // Resumes the source. This must be called before any Mach messages will
+  // be received.
+  void Resume();
+
+ private:
+  // Cancels the source, after which this class will no longer receive Mach
+  // messages. Calling this more than once is a no-op.
+  void Cancel();
+
+  // The dispatch queue used to service the source_.
+  dispatch_queue_t queue_;
+
+  // A MACH_RECV dispatch source.
+  dispatch_source_t source_;
+
+  // Semaphore used to wait on the |source_|'s cancellation in the destructor.
+  dispatch_semaphore_t source_canceled_;
+
+  DISALLOW_COPY_AND_ASSIGN(DispatchSourceMach);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_DISPATCH_SOURCE_MACH_H_
diff --git a/sandbox/mac/dispatch_source_mach_unittest.cc b/sandbox/mac/dispatch_source_mach_unittest.cc
new file mode 100644
index 0000000..123a44c
--- /dev/null
+++ b/sandbox/mac/dispatch_source_mach_unittest.cc
@@ -0,0 +1,119 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/dispatch_source_mach.h"
+
+#include <mach/mach.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+class DispatchSourceMachTest : public testing::Test {
+ public:
+  void SetUp() override {
+    mach_port_t port = MACH_PORT_NULL;
+    ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(),
+        MACH_PORT_RIGHT_RECEIVE, &port));
+    receive_right_.reset(port);
+
+    ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(mach_task_self(), port,
+        port, MACH_MSG_TYPE_MAKE_SEND));
+    send_right_.reset(port);
+  }
+
+  mach_port_t port() { return receive_right_.get(); }
+
+  void WaitForSemaphore(dispatch_semaphore_t semaphore) {
+    dispatch_semaphore_wait(semaphore, dispatch_time(
+        DISPATCH_TIME_NOW,
+        TestTimeouts::action_timeout().InSeconds() * NSEC_PER_SEC));
+  }
+
+ private:
+  base::mac::ScopedMachReceiveRight receive_right_;
+  base::mac::ScopedMachSendRight send_right_;
+};
+
+TEST_F(DispatchSourceMachTest, ReceiveAfterResume) {
+  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
+
+  bool __block did_receive = false;
+  DispatchSourceMach source("org.chromium.sandbox.test.ReceiveAfterResume",
+      port(), ^{
+          mach_msg_empty_rcv_t msg = {{0}};
+          msg.header.msgh_size = sizeof(msg);
+          msg.header.msgh_local_port = port();
+          mach_msg_receive(&msg.header);
+          did_receive = true;
+
+          dispatch_semaphore_signal(signal);
+      });
+
+  mach_msg_empty_send_t msg = {{0}};
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_remote_port = port();
+  msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+  ASSERT_EQ(KERN_SUCCESS, mach_msg_send(&msg.header));
+
+  EXPECT_FALSE(did_receive);
+
+  source.Resume();
+
+  WaitForSemaphore(signal);
+
+  EXPECT_TRUE(did_receive);
+}
+
+TEST_F(DispatchSourceMachTest, NoMessagesAfterDestruction) {
+  scoped_ptr<int> count(new int(0));
+  int* __block count_ptr = count.get();
+
+  scoped_ptr<DispatchSourceMach> source(new DispatchSourceMach(
+      "org.chromium.sandbox.test.NoMessagesAfterDestruction",
+      port(), ^{
+          mach_msg_empty_rcv_t msg = {{0}};
+          msg.header.msgh_size = sizeof(msg);
+          msg.header.msgh_local_port = port();
+          mach_msg_receive(&msg.header);
+          LOG(INFO) << "Receieve " << *count_ptr;
+          ++(*count_ptr);
+      }));
+  source->Resume();
+
+  dispatch_queue_t queue =
+      dispatch_queue_create("org.chromium.sandbox.test.MessageSend", NULL);
+  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
+  for (int i = 0; i < 30; ++i) {
+    dispatch_async(queue, ^{
+        mach_msg_empty_send_t msg = {{0}};
+        msg.header.msgh_size = sizeof(msg);
+        msg.header.msgh_remote_port = port();
+        msg.header.msgh_bits =
+            MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+        mach_msg_send(&msg.header);
+    });
+
+    // After sending five messages, shut down the source and taint the
+    // pointer the handler dereferences. The test will crash if |count_ptr|
+    // is being used after "free".
+    if (i == 5) {
+      scoped_ptr<DispatchSourceMach>* source_ptr = &source;
+      dispatch_async(queue, ^{
+          source_ptr->reset();
+          count_ptr = reinterpret_cast<int*>(0xdeaddead);
+          dispatch_semaphore_signal(signal);
+      });
+    }
+  }
+
+  WaitForSemaphore(signal);
+  dispatch_release(queue);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/launchd_interception_server.cc b/sandbox/mac/launchd_interception_server.cc
new file mode 100644
index 0000000..06f1081
--- /dev/null
+++ b/sandbox/mac/launchd_interception_server.cc
@@ -0,0 +1,153 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/launchd_interception_server.h"
+
+#include <servers/bootstrap.h>
+
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "sandbox/mac/bootstrap_sandbox.h"
+#include "sandbox/mac/mach_message_server.h"
+
+namespace sandbox {
+
+// The buffer size for all launchd messages. This comes from
+// sizeof(union __RequestUnion__vproc_mig_job_subsystem) in launchd, and it
+// is larger than the __ReplyUnion.
+const mach_msg_size_t kBufferSize = 2096;
+
+LaunchdInterceptionServer::LaunchdInterceptionServer(
+    const BootstrapSandbox* sandbox)
+    : sandbox_(sandbox),
+      sandbox_port_(MACH_PORT_NULL),
+      compat_shim_(GetLaunchdCompatibilityShim()) {
+}
+
+LaunchdInterceptionServer::~LaunchdInterceptionServer() {
+}
+
+bool LaunchdInterceptionServer::Initialize(mach_port_t server_receive_right) {
+  mach_port_t task = mach_task_self();
+  kern_return_t kr;
+
+  // Allocate the dummy sandbox port.
+  mach_port_t port;
+  if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) !=
+          KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port.";
+    return false;
+  }
+  sandbox_port_.reset(port);
+  if ((kr = mach_port_insert_right(task, sandbox_port_, sandbox_port_,
+          MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port send right.";
+    return false;
+  }
+  sandbox_send_port_.reset(sandbox_port_);
+
+  message_server_.reset(
+      new MachMessageServer(this, server_receive_right, kBufferSize));
+  return message_server_->Initialize();
+}
+
+void LaunchdInterceptionServer::DemuxMessage(IPCMessage request) {
+  const uint64_t message_id = compat_shim_.ipc_message_get_id(request);
+  VLOG(3) << "Incoming message #" << message_id;
+
+  pid_t sender_pid = message_server_->GetMessageSenderPID(request);
+  const BootstrapSandboxPolicy* policy =
+      sandbox_->PolicyForProcess(sender_pid);
+  if (policy == NULL) {
+    // No sandbox policy is in place for the sender of this message, which
+    // means it came from the unknown. Reject it.
+    VLOG(3) << "Message from unknown pid " << sender_pid << " rejected.";
+    message_server_->RejectMessage(request, MIG_REMOTE_ERROR);
+    return;
+  }
+
+  if (message_id == compat_shim_.msg_id_look_up2) {
+    // Filter messages sent via bootstrap_look_up to enforce the sandbox policy
+    // over the bootstrap namespace.
+    HandleLookUp(request, policy);
+  } else if (message_id == compat_shim_.msg_id_swap_integer) {
+    // Ensure that any vproc_swap_integer requests are safe.
+    HandleSwapInteger(request);
+  } else {
+    // All other messages are not permitted.
+    VLOG(1) << "Rejecting unhandled message #" << message_id;
+    message_server_->RejectMessage(request, MIG_REMOTE_ERROR);
+  }
+}
+
+void LaunchdInterceptionServer::HandleLookUp(
+    IPCMessage request,
+    const BootstrapSandboxPolicy* policy) {
+  const std::string request_service_name(
+      compat_shim_.look_up2_get_request_name(request));
+  VLOG(2) << "Incoming look_up2 request for " << request_service_name;
+
+  // Find the Rule for this service. If a named rule is not found, use the
+  // default specified by the policy.
+  const BootstrapSandboxPolicy::NamedRules::const_iterator it =
+      policy->rules.find(request_service_name);
+  Rule rule(policy->default_rule);
+  if (it != policy->rules.end())
+    rule = it->second;
+
+  if (rule.result == POLICY_ALLOW) {
+    // This service is explicitly allowed, so this message will not be
+    // intercepted by the sandbox.
+    VLOG(1) << "Permitting and forwarding look_up2: " << request_service_name;
+    ForwardMessage(request);
+  } else if (rule.result == POLICY_DENY_ERROR) {
+    // The child is not permitted to look up this service. Send a MIG error
+    // reply to the client. Returning a NULL or unserviced port for a look up
+    // can cause clients to crash or hang.
+    VLOG(1) << "Denying look_up2 with MIG error: " << request_service_name;
+    message_server_->RejectMessage(request, BOOTSTRAP_UNKNOWN_SERVICE);
+  } else if (rule.result == POLICY_DENY_DUMMY_PORT ||
+             rule.result == POLICY_SUBSTITUTE_PORT) {
+    // The policy result is to deny access to the real service port, replying
+    // with a sandboxed port in its stead. Use either the dummy sandbox_port_
+    // or the one specified in the policy.
+    VLOG(1) << "Intercepting look_up2 with a sandboxed service port: "
+            << request_service_name;
+
+    mach_port_t result_port;
+    if (rule.result == POLICY_DENY_DUMMY_PORT)
+      result_port = sandbox_port_.get();
+    else
+      result_port = rule.substitute_port;
+
+    IPCMessage reply = message_server_->CreateReply(request);
+    compat_shim_.look_up2_fill_reply(reply, result_port);
+    // If the message was sent successfully, clear the result_port out of the
+    // message so that it is not destroyed at the end of ReceiveMessage. The
+    // above-inserted right has been moved out of the process, and destroying
+    // the message will unref yet another right.
+    if (message_server_->SendReply(reply))
+      compat_shim_.look_up2_fill_reply(reply, MACH_PORT_NULL);
+  } else {
+    NOTREACHED();
+  }
+}
+
+void LaunchdInterceptionServer::HandleSwapInteger(IPCMessage request) {
+  // Only allow getting information out of launchd. Do not allow setting
+  // values. Two commonly observed values that are retrieved are
+  // VPROC_GSK_MGR_PID and VPROC_GSK_TRANSACTIONS_ENABLED.
+  if (compat_shim_.swap_integer_is_get_only(request)) {
+    VLOG(2) << "Forwarding vproc swap_integer message.";
+    ForwardMessage(request);
+  } else {
+    VLOG(2) << "Rejecting non-read-only swap_integer message.";
+    message_server_->RejectMessage(request, BOOTSTRAP_NOT_PRIVILEGED);
+  }
+}
+void LaunchdInterceptionServer::ForwardMessage(IPCMessage request) {
+  message_server_->ForwardMessage(request, sandbox_->real_bootstrap_port());
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/launchd_interception_server.h b/sandbox/mac/launchd_interception_server.h
new file mode 100644
index 0000000..144d67d
--- /dev/null
+++ b/sandbox/mac/launchd_interception_server.h
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_LAUNCHD_INTERCEPTION_SERVER_H_
+#define SANDBOX_MAC_LAUNCHD_INTERCEPTION_SERVER_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/mac/message_server.h"
+#include "sandbox/mac/os_compatibility.h"
+
+namespace sandbox {
+
+class BootstrapSandbox;
+struct BootstrapSandboxPolicy;
+
+// This class is used to run a Mach IPC message server. This server can
+// hold the receive right for a bootstrap_port of a process, and it filters
+// a subset of the launchd/bootstrap IPC call set for sandboxing. It permits
+// or rejects requests based on the per-process policy specified in the
+// BootstrapSandbox.
+class LaunchdInterceptionServer : public MessageDemuxer {
+ public:
+  explicit LaunchdInterceptionServer(const BootstrapSandbox* sandbox);
+  ~LaunchdInterceptionServer() override;
+
+  // Initializes the class and starts running the message server. If the
+  // |server_receive_right| is non-NULL, this class will take ownership of
+  // the receive right and intercept messages sent to that port.
+  bool Initialize(mach_port_t server_receive_right);
+
+  // MessageDemuxer:
+  void DemuxMessage(IPCMessage request) override;
+
+  mach_port_t server_port() const { return message_server_->GetServerPort(); }
+
+ private:
+  // Given a look_up2 request message, this looks up the appropriate sandbox
+  // policy for the service name then formulates and sends the reply message.
+  void HandleLookUp(IPCMessage request, const BootstrapSandboxPolicy* policy);
+
+  // Given a swap_integer request message, this verifies that it is safe, and
+  // if so, forwards it on to launchd for servicing. If the request is unsafe,
+  // it replies with an error.
+  void HandleSwapInteger(IPCMessage request);
+
+  // Forwards the original |request| on to real bootstrap server for handling.
+  void ForwardMessage(IPCMessage request);
+
+  // The sandbox for which this message server is running.
+  const BootstrapSandbox* sandbox_;
+
+  // The Mach IPC server.
+  scoped_ptr<MessageServer> message_server_;
+
+  // The Mach port handed out in reply to denied look up requests. All denied
+  // requests share the same port, though nothing reads messages from it.
+  base::mac::ScopedMachReceiveRight sandbox_port_;
+  // The send right for the above |sandbox_port_|, used with
+  // MACH_MSG_TYPE_COPY_SEND when handing out references to the dummy port.
+  base::mac::ScopedMachSendRight sandbox_send_port_;
+
+  // The compatibility shim that handles differences in message header IDs and
+  // request/reply structures between different OS X versions.
+  const LaunchdCompatibilityShim compat_shim_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_LAUNCHD_INTERCEPTION_SERVER_H_
diff --git a/sandbox/mac/mach_message_server.cc b/sandbox/mac/mach_message_server.cc
new file mode 100644
index 0000000..5a73357
--- /dev/null
+++ b/sandbox/mac/mach_message_server.cc
@@ -0,0 +1,193 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/mach_message_server.h"
+
+#include <bsm/libbsm.h>
+#include <servers/bootstrap.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/strings/stringprintf.h"
+#include "sandbox/mac/dispatch_source_mach.h"
+
+namespace sandbox {
+
+MachMessageServer::MachMessageServer(
+    MessageDemuxer* demuxer,
+    mach_port_t server_receive_right,
+    mach_msg_size_t buffer_size)
+    : demuxer_(demuxer),
+      server_port_(server_receive_right),
+      buffer_size_(
+          mach_vm_round_page(buffer_size + sizeof(mach_msg_audit_trailer_t))),
+      did_forward_message_(false) {
+  DCHECK(demuxer_);
+}
+
+MachMessageServer::~MachMessageServer() {
+}
+
+bool MachMessageServer::Initialize() {
+  mach_port_t task = mach_task_self();
+  kern_return_t kr;
+
+  // Allocate a port for use as a new server port if one was not passed to the
+  // constructor.
+  if (!server_port_.is_valid()) {
+    mach_port_t port;
+    if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) !=
+            KERN_SUCCESS) {
+      MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
+      return false;
+    }
+    server_port_.reset(port);
+  }
+
+  // Allocate the message request and reply buffers.
+  const int kMachMsgMemoryFlags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG) |
+                                  VM_FLAGS_ANYWHERE;
+  vm_address_t buffer = 0;
+
+  kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate request buffer.";
+    return false;
+  }
+  request_buffer_.reset(buffer, buffer_size_);
+
+  kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate reply buffer.";
+    return false;
+  }
+  reply_buffer_.reset(buffer, buffer_size_);
+
+  // Set up the dispatch queue to service the bootstrap port.
+  std::string label = base::StringPrintf(
+      "org.chromium.sandbox.MachMessageServer.%p", demuxer_);
+  dispatch_source_.reset(new DispatchSourceMach(
+      label.c_str(), server_port_.get(), ^{ ReceiveMessage(); }));
+  dispatch_source_->Resume();
+
+  return true;
+}
+
+pid_t MachMessageServer::GetMessageSenderPID(IPCMessage request) {
+  // Get the PID of the task that sent this request. This requires getting at
+  // the trailer of the message, from the header.
+  mach_msg_audit_trailer_t* trailer =
+      reinterpret_cast<mach_msg_audit_trailer_t*>(
+          reinterpret_cast<vm_address_t>(request.mach) +
+              round_msg(request.mach->msgh_size));
+  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
+  pid_t sender_pid;
+  audit_token_to_au32(trailer->msgh_audit,
+      NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
+  return sender_pid;
+}
+
+IPCMessage MachMessageServer::CreateReply(IPCMessage request_message) {
+  mach_msg_header_t* request = request_message.mach;
+
+  IPCMessage reply_message;
+  mach_msg_header_t* reply = reply_message.mach =
+      reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address());
+  bzero(reply, buffer_size_);
+
+  reply->msgh_bits = MACH_MSGH_BITS_REMOTE(reply->msgh_bits);
+  // Since mach_msg will automatically swap the request and reply ports,
+  // undo that.
+  reply->msgh_remote_port = request->msgh_remote_port;
+  reply->msgh_local_port = MACH_PORT_NULL;
+  // MIG servers simply add 100 to the request ID to generate the reply ID.
+  reply->msgh_id = request->msgh_id + 100;
+
+  return reply_message;
+}
+
+bool MachMessageServer::SendReply(IPCMessage reply) {
+  kern_return_t kr = mach_msg(reply.mach, MACH_SEND_MSG,
+      reply.mach->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+      MACH_PORT_NULL);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "Unable to send intercepted reply message.";
+  return kr == KERN_SUCCESS;
+}
+
+void MachMessageServer::ForwardMessage(IPCMessage message,
+                                       mach_port_t destination) {
+  mach_msg_header_t* request = message.mach;
+  request->msgh_local_port = request->msgh_remote_port;
+  request->msgh_remote_port = destination;
+  // Preserve the msgh_bits that do not deal with the local and remote ports.
+  request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
+      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
+  kern_return_t kr = mach_msg_send(request);
+  if (kr == KERN_SUCCESS) {
+    did_forward_message_ = true;
+  } else {
+    MACH_LOG(ERROR, kr) << "Unable to forward message to the real launchd.";
+  }
+}
+
+void MachMessageServer::RejectMessage(IPCMessage request, int error_code) {
+  IPCMessage reply = CreateReply(request);
+  mig_reply_error_t* error_reply =
+      reinterpret_cast<mig_reply_error_t*>(reply.mach);
+  error_reply->Head.msgh_size = sizeof(mig_reply_error_t);
+  error_reply->Head.msgh_bits =
+      MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE);
+  error_reply->NDR = NDR_record;
+  error_reply->RetCode = error_code;
+  SendReply(reply);
+}
+
+mach_port_t MachMessageServer::GetServerPort() const {
+  return server_port_.get();
+}
+
+void MachMessageServer::ReceiveMessage() {
+  const mach_msg_options_t kRcvOptions = MACH_RCV_MSG |
+      MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+      MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+
+  mach_msg_header_t* request =
+      reinterpret_cast<mach_msg_header_t*>(request_buffer_.address());
+  mach_msg_header_t* reply =
+      reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address());
+
+  // Zero out the buffers from handling any previous message.
+  bzero(request, buffer_size_);
+  bzero(reply, buffer_size_);
+  did_forward_message_ = false;
+
+  // A Mach message server-once. The system library to run a message server
+  // cannot be used here, because some requests are conditionally forwarded
+  // to another server.
+  kern_return_t kr = mach_msg(request, kRcvOptions, 0, buffer_size_,
+      server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Unable to receive message.";
+    return;
+  }
+
+  // Process the message.
+  IPCMessage request_message = { request };
+  demuxer_->DemuxMessage(request_message);
+
+  // Free any descriptors in the message body. If the message was forwarded,
+  // any descriptors would have been moved out of the process on send. If the
+  // forwarded message was sent from the process hosting this sandbox server,
+  // destroying the message could also destroy rights held outside the scope of
+  // this message server.
+  if (!did_forward_message_) {
+    mach_msg_destroy(request);
+    mach_msg_destroy(reply);
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/mach_message_server.h b/sandbox/mac/mach_message_server.h
new file mode 100644
index 0000000..645b691
--- /dev/null
+++ b/sandbox/mac/mach_message_server.h
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_MACH_MESSAGE_SERVER_H_
+#define SANDBOX_MAC_MACH_MESSAGE_SERVER_H_
+
+#include <mach/mach.h>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/mac/message_server.h"
+
+namespace sandbox {
+
+class DispatchSourceMach;
+
+// A Mach message server that operates a receive port. Messages are received
+// and then passed to the MessageDemuxer for handling. The Demuxer
+// can use the server class to send a reply, forward the message to a
+// different port, or reply to the message with a MIG error.
+class MachMessageServer : public MessageServer {
+ public:
+  // Creates a new Mach message server that will send messages to |demuxer|
+  // for handling. If the |server_receive_right| is non-NULL, this class will
+  // take ownership of the port and it will be used to receive messages.
+  // Otherwise the server will create a new receive right.
+  // The maximum size of messages is specified by |buffer_size|.
+  MachMessageServer(MessageDemuxer* demuxer,
+                    mach_port_t server_receive_right,
+                    mach_msg_size_t buffer_size);
+  ~MachMessageServer() override;
+
+  // MessageServer:
+  bool Initialize() override;
+  pid_t GetMessageSenderPID(IPCMessage request) override;
+  IPCMessage CreateReply(IPCMessage request) override;
+  bool SendReply(IPCMessage reply) override;
+  void ForwardMessage(IPCMessage request, mach_port_t destination) override;
+  // Replies to the message with the specified |error_code| as a MIG
+  // error_reply RetCode.
+  void RejectMessage(IPCMessage request, int error_code) override;
+  mach_port_t GetServerPort() const override;
+
+ private:
+  // Event handler for the |server_source_| that reads a message from the queue
+  // and processes it.
+  void ReceiveMessage();
+
+  // The demuxer delegate. Weak.
+  MessageDemuxer* demuxer_;
+
+  // The Mach port on which the server is receiving requests.
+  base::mac::ScopedMachReceiveRight server_port_;
+
+  // The size of the two message buffers below.
+  const mach_msg_size_t buffer_size_;
+
+  // Request and reply buffers used in ReceiveMessage.
+  base::mac::ScopedMachVM request_buffer_;
+  base::mac::ScopedMachVM reply_buffer_;
+
+  // MACH_RECV dispatch source that handles the |server_port_|.
+  scoped_ptr<DispatchSourceMach> dispatch_source_;
+
+  // Whether or not ForwardMessage() was called during ReceiveMessage().
+  bool did_forward_message_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_MACH_MESSAGE_SERVER_H_
diff --git a/sandbox/mac/message_server.h b/sandbox/mac/message_server.h
new file mode 100644
index 0000000..1cd40b0
--- /dev/null
+++ b/sandbox/mac/message_server.h
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_MESSAGE_SERVER_H_
+#define SANDBOX_MAC_MESSAGE_SERVER_H_
+
+#include <mach/mach.h>
+#include <unistd.h>
+
+#include "sandbox/mac/xpc.h"
+
+namespace sandbox {
+
+// A message received by a MessageServer. Each concrete implementation of
+// that interface will handle the fields of this union appropriately.
+// Consumers should treat this as an opaque handle.
+union IPCMessage {
+  mach_msg_header_t* mach;
+  xpc_object_t xpc;
+};
+
+// A delegate interface for MessageServer that handles processing of
+// incoming intercepted IPC messages.
+class MessageDemuxer {
+ public:
+  // Handle a |request| message. The message is owned by the server. Use the
+  // server's methods to create and send a reply message.
+  virtual void DemuxMessage(IPCMessage request) = 0;
+
+ protected:
+  virtual ~MessageDemuxer() {}
+};
+
+// An interaface for an IPC server that implements Mach messaging semantics.
+// The concrete implementation may be powered by raw Mach messages, XPC, or
+// some other technology. This interface is the abstraction on top of those
+// that enables message interception.
+class MessageServer {
+ public:
+  virtual ~MessageServer() {}
+
+  // Initializes the class and starts running the message server. If this
+  // returns false, no other methods may be called on this class.
+  virtual bool Initialize() = 0;
+
+  // Given a received request message, returns the PID of the sending process.
+  virtual pid_t GetMessageSenderPID(IPCMessage request) = 0;
+
+  // Creates a reply message from a request message. The result is owned by
+  // the server.
+  virtual IPCMessage CreateReply(IPCMessage request) = 0;
+
+  // Sends a reply message. Returns true if the message was sent successfully.
+  virtual bool SendReply(IPCMessage reply) = 0;
+
+  // Forwards the original |request| to the |destination| for handling.
+  virtual void ForwardMessage(IPCMessage request, mach_port_t destination) = 0;
+
+  // Replies to the received |request| message by creating a reply and setting
+  // the specified |error_code| in a field that is interpreted by the
+  // underlying IPC system.
+  virtual void RejectMessage(IPCMessage request, int error_code) = 0;
+
+  // Returns the Mach port on which the MessageServer is listening.
+  virtual mach_port_t GetServerPort() const = 0;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_MESSAGE_SERVER_H_
diff --git a/sandbox/mac/os_compatibility.cc b/sandbox/mac/os_compatibility.cc
new file mode 100644
index 0000000..6624f3a
--- /dev/null
+++ b/sandbox/mac/os_compatibility.cc
@@ -0,0 +1,135 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/os_compatibility.h"
+
+#include <servers/bootstrap.h>
+#include <unistd.h>
+
+#include "base/mac/mac_util.h"
+
+namespace sandbox {
+
+namespace {
+
+#pragma pack(push, 4)
+// Verified from launchd-329.3.3 (10.6.8).
+struct look_up2_request_10_6 {
+  mach_msg_header_t Head;
+  NDR_record_t NDR;
+  name_t servicename;
+  pid_t targetpid;
+  uint64_t flags;
+};
+
+struct look_up2_reply_10_6 {
+  mach_msg_header_t Head;
+  mach_msg_body_t msgh_body;
+  mach_msg_port_descriptor_t service_port;
+};
+
+// Verified from:
+//   launchd-392.39 (10.7.5)
+//   launchd-442.26.2 (10.8.5)
+//   launchd-842.1.4 (10.9.0)
+struct look_up2_request_10_7 {
+  mach_msg_header_t Head;
+  NDR_record_t NDR;
+  name_t servicename;
+  pid_t targetpid;
+  uuid_t instanceid;
+  uint64_t flags;
+};
+
+// look_up2_reply_10_7 is the same as the 10_6 version.
+
+// Verified from:
+//   launchd-329.3.3 (10.6.8)
+//   launchd-392.39 (10.7.5)
+//   launchd-442.26.2 (10.8.5)
+//   launchd-842.1.4 (10.9.0)
+typedef int vproc_gsk_t;  // Defined as an enum in liblaunch/vproc_priv.h.
+struct swap_integer_request_10_6 {
+  mach_msg_header_t Head;
+  NDR_record_t NDR;
+  vproc_gsk_t inkey;
+  vproc_gsk_t outkey;
+  int64_t inval;
+};
+#pragma pack(pop)
+
+// TODO(rsesek): Libc provides strnlen() starting in 10.7.
+size_t strnlen(const char* str, size_t maxlen) {
+  size_t len = 0;
+  for (; len < maxlen; ++len, ++str) {
+    if (*str == '\0')
+      break;
+  }
+  return len;
+}
+
+uint64_t MachGetMessageID(const IPCMessage message) {
+  return message.mach->msgh_id;
+}
+
+template <typename R>
+std::string LaunchdLookUp2GetRequestName(const IPCMessage message) {
+  mach_msg_header_t* header = message.mach;
+  DCHECK_EQ(sizeof(R), header->msgh_size);
+  const R* request = reinterpret_cast<const R*>(header);
+  // Make sure the name is properly NUL-terminated.
+  const size_t name_length =
+      strnlen(request->servicename, BOOTSTRAP_MAX_NAME_LEN);
+  std::string name = std::string(request->servicename, name_length);
+  return name;
+}
+
+template <typename R>
+void LaunchdLookUp2FillReply(IPCMessage message, mach_port_t port) {
+  R* reply = reinterpret_cast<R*>(message.mach);
+  reply->Head.msgh_size = sizeof(R);
+  reply->Head.msgh_bits =
+      MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
+      MACH_MSGH_BITS_COMPLEX;
+  reply->msgh_body.msgh_descriptor_count = 1;
+  reply->service_port.name = port;
+  reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+  reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR;
+}
+
+template <typename R>
+bool LaunchdSwapIntegerIsGetOnly(const IPCMessage message) {
+  const R* request = reinterpret_cast<const R*>(message.mach);
+  return request->inkey == 0 && request->inval == 0 && request->outkey != 0;
+}
+
+}  // namespace
+
+const LaunchdCompatibilityShim GetLaunchdCompatibilityShim() {
+  LaunchdCompatibilityShim shim = {
+    .ipc_message_get_id = &MachGetMessageID,
+    .msg_id_look_up2 = 404,
+    .msg_id_swap_integer = 416,
+    .look_up2_fill_reply = &LaunchdLookUp2FillReply<look_up2_reply_10_6>,
+    .swap_integer_is_get_only =
+        &LaunchdSwapIntegerIsGetOnly<swap_integer_request_10_6>,
+  };
+
+  if (base::mac::IsOSSnowLeopard()) {
+    shim.look_up2_get_request_name =
+        &LaunchdLookUp2GetRequestName<look_up2_request_10_6>;
+  } else if (base::mac::IsOSLionOrLater() &&
+             !base::mac::IsOSYosemiteOrLater()) {
+    shim.look_up2_get_request_name =
+        &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
+  } else {
+    DLOG(ERROR) << "Unknown OS, using launchd compatibility shim from 10.7.";
+    shim.look_up2_get_request_name =
+        &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
+  }
+
+  return shim;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/os_compatibility.h b/sandbox/mac/os_compatibility.h
new file mode 100644
index 0000000..1205cd6
--- /dev/null
+++ b/sandbox/mac/os_compatibility.h
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used to handle differences in Mach message IDs and structures
+// that occur between different OS versions. The Mach messages that the sandbox
+// is interested in are decoded using information derived from the open-source
+// libraries, i.e. <http://www.opensource.apple.com/source/launchd/>. While
+// these messages definitions are open source, they are not considered part of
+// the stable OS API, and so differences do exist between OS versions.
+
+#ifndef SANDBOX_MAC_OS_COMPATIBILITY_H_
+#define SANDBOX_MAC_OS_COMPATIBILITY_H_
+
+#include <mach/mach.h>
+
+#include <string>
+
+#include "sandbox/mac/message_server.h"
+
+namespace sandbox {
+
+typedef uint64_t (*IPCMessageGetID)(const IPCMessage);
+
+typedef std::string (*LookUp2GetRequestName)(const IPCMessage);
+typedef void (*LookUp2FillReply)(IPCMessage, mach_port_t service_port);
+
+typedef bool (*SwapIntegerIsGetOnly)(const IPCMessage);
+
+struct LaunchdCompatibilityShim {
+  // Gets the message ID of an IPC message.
+  IPCMessageGetID ipc_message_get_id;
+
+  // The msgh_id for look_up2.
+  uint64_t msg_id_look_up2;
+
+  // The msgh_id for swap_integer.
+  uint64_t msg_id_swap_integer;
+
+  // A function to take a look_up2 message and return the string service name
+  // that was requested via the message.
+  LookUp2GetRequestName look_up2_get_request_name;
+
+  // A function to formulate a reply to a look_up2 message, given the reply
+  // message and the port to return as the service.
+  LookUp2FillReply look_up2_fill_reply;
+
+  // A function to take a swap_integer message and return true if the message
+  // is only getting the value of a key, neither setting it directly, nor
+  // swapping two keys.
+  SwapIntegerIsGetOnly swap_integer_is_get_only;
+};
+
+// Gets the compatibility shim for the launchd job subsystem.
+const LaunchdCompatibilityShim GetLaunchdCompatibilityShim();
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_OS_COMPATIBILITY_H_
diff --git a/sandbox/mac/policy.cc b/sandbox/mac/policy.cc
new file mode 100644
index 0000000..293255a
--- /dev/null
+++ b/sandbox/mac/policy.cc
@@ -0,0 +1,56 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/policy.h"
+
+namespace sandbox {
+
+Rule::Rule()
+    : result(POLICY_DECISION_INVALID),
+      substitute_port(MACH_PORT_NULL) {
+}
+
+Rule::Rule(PolicyDecision result)
+    : result(result),
+      substitute_port(MACH_PORT_NULL) {
+}
+
+Rule::Rule(mach_port_t override_port)
+    : result(POLICY_SUBSTITUTE_PORT),
+      substitute_port(override_port) {
+}
+
+BootstrapSandboxPolicy::BootstrapSandboxPolicy()
+    : default_rule(POLICY_DENY_ERROR) {
+}
+
+BootstrapSandboxPolicy::~BootstrapSandboxPolicy() {}
+
+static bool IsRuleValid(const Rule& rule) {
+  if (!(rule.result > POLICY_DECISION_INVALID &&
+        rule.result < POLICY_DECISION_LAST)) {
+    return false;
+  }
+  if (rule.result == POLICY_SUBSTITUTE_PORT) {
+    if (rule.substitute_port == MACH_PORT_NULL)
+      return false;
+  } else {
+    if (rule.substitute_port != MACH_PORT_NULL)
+      return false;
+  }
+  return true;
+}
+
+bool IsPolicyValid(const BootstrapSandboxPolicy& policy) {
+  if (!IsRuleValid(policy.default_rule))
+    return false;
+
+  for (const auto& pair : policy.rules) {
+    if (!IsRuleValid(pair.second))
+      return false;
+  }
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/policy.h b/sandbox/mac/policy.h
new file mode 100644
index 0000000..e500468
--- /dev/null
+++ b/sandbox/mac/policy.h
@@ -0,0 +1,70 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_POLICY_H_
+#define SANDBOX_MAC_POLICY_H_
+
+#include <mach/mach.h>
+
+#include <map>
+#include <string>
+
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+enum PolicyDecision {
+  POLICY_DECISION_INVALID,
+  // Explicitly allows the real service to be looked up from launchd.
+  POLICY_ALLOW,
+  // Deny the look up request by replying with a MIG error. This is the
+  // default behavior for servers not given an explicit rule.
+  POLICY_DENY_ERROR,
+  // Deny the look up request with a well-formed reply containing a
+  // Mach port with a send right, messages to which will be ignored.
+  POLICY_DENY_DUMMY_PORT,
+  // Reply to the look up request with a send right to the substitute_port
+  // specified in the Rule.
+  POLICY_SUBSTITUTE_PORT,
+  POLICY_DECISION_LAST,
+};
+
+// A Rule expresses the action to take when a service port is requested via
+// bootstrap_look_up. If |result| is not POLICY_SUBSTITUTE_PORT, then
+// |substitute_port| must be NULL. If result is POLICY_SUBSTITUTE_PORT, then
+// |substitute_port| must not be NULL.
+struct SANDBOX_EXPORT Rule {
+  Rule();
+  explicit Rule(PolicyDecision result);
+  explicit Rule(mach_port_t override_port);
+
+  PolicyDecision result;
+
+  // The Rule does not take ownership of this port, but additional send rights
+  // will be allocated to it before it is sent to a client. This name must
+  // denote a send right that can duplicated with MACH_MSG_TYPE_COPY_SEND.
+  mach_port_t substitute_port;
+};
+
+// A policy object manages the rules enforced on a target sandboxed process.
+struct SANDBOX_EXPORT BootstrapSandboxPolicy {
+  typedef std::map<std::string, Rule> NamedRules;
+
+  BootstrapSandboxPolicy();
+  ~BootstrapSandboxPolicy();
+
+  // The default action to take if the server name being looked up is not
+  // present in |rules|.
+  Rule default_rule;
+
+  // A map of bootstrap server names to policy Rules.
+  NamedRules rules;
+};
+
+// Checks that a policy is well-formed.
+SANDBOX_EXPORT bool IsPolicyValid(const BootstrapSandboxPolicy& policy);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_POLICY_H_
diff --git a/sandbox/mac/policy_unittest.cc b/sandbox/mac/policy_unittest.cc
new file mode 100644
index 0000000..54e0e74
--- /dev/null
+++ b/sandbox/mac/policy_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/policy.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+TEST(PolicyTest, ValidEmptyPolicy) {
+  EXPECT_TRUE(IsPolicyValid(BootstrapSandboxPolicy()));
+}
+
+TEST(PolicyTest, ValidPolicy) {
+  BootstrapSandboxPolicy policy;
+  policy.rules["allow"] = Rule(POLICY_ALLOW);
+  policy.rules["deny_error"] = Rule(POLICY_DENY_ERROR);
+  policy.rules["deny_dummy"] = Rule(POLICY_DENY_DUMMY_PORT);
+  policy.rules["substitue"] = Rule(mach_task_self());
+  EXPECT_TRUE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyEmptyRule) {
+  Rule rule;
+  BootstrapSandboxPolicy policy;
+  policy.rules["test"] = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicySubstitue) {
+  Rule rule(POLICY_SUBSTITUTE_PORT);
+  BootstrapSandboxPolicy policy;
+  policy.rules["test"] = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyWithPortAllow) {
+  Rule rule(POLICY_ALLOW);
+  rule.substitute_port = mach_task_self();
+  BootstrapSandboxPolicy policy;
+  policy.rules["allow"] = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyWithPortDenyError) {
+  Rule rule(POLICY_DENY_ERROR);
+  rule.substitute_port = mach_task_self();
+  BootstrapSandboxPolicy policy;
+  policy.rules["deny_error"] = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyWithPortDummy) {
+  Rule rule(POLICY_DENY_DUMMY_PORT);
+  rule.substitute_port = mach_task_self();
+  BootstrapSandboxPolicy policy;
+  policy.rules["deny_dummy"] = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyDefaultRule) {
+  BootstrapSandboxPolicy policy;
+  policy.default_rule = Rule();
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyDefaultRuleSubstitue) {
+  BootstrapSandboxPolicy policy;
+  policy.default_rule = Rule(POLICY_SUBSTITUTE_PORT);
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyDefaultRuleWithPortAllow) {
+  Rule rule(POLICY_ALLOW);
+  rule.substitute_port = mach_task_self();
+  BootstrapSandboxPolicy policy;
+  policy.default_rule = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyDefaultRuleWithPortDenyError) {
+  Rule rule(POLICY_DENY_ERROR);
+  rule.substitute_port = mach_task_self();
+  BootstrapSandboxPolicy policy;
+  policy.default_rule = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+TEST(PolicyTest, InvalidPolicyDefaultRuleWithPortDummy) {
+  Rule rule(POLICY_DENY_DUMMY_PORT);
+  rule.substitute_port = mach_task_self();
+  BootstrapSandboxPolicy policy;
+  policy.default_rule = rule;
+  EXPECT_FALSE(IsPolicyValid(policy));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/sandbox_mac.gypi b/sandbox/mac/sandbox_mac.gypi
new file mode 100644
index 0000000..a2a616f
--- /dev/null
+++ b/sandbox/mac/sandbox_mac.gypi
@@ -0,0 +1,117 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'sandbox',
+      'type': '<(component)',
+      'sources': [
+        'bootstrap_sandbox.cc',
+        'bootstrap_sandbox.h',
+        'dispatch_source_mach.cc',
+        'dispatch_source_mach.h',
+        'launchd_interception_server.cc',
+        'launchd_interception_server.h',
+        'mach_message_server.cc',
+        'mach_message_server.h',
+        'message_server.h',
+        'os_compatibility.cc',
+        'os_compatibility.h',
+        'policy.cc',
+        'policy.h',
+        'xpc.cc',
+        'xpc.h',
+        'xpc_message_server.cc',
+        'xpc_message_server.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '..',
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/usr/lib/libbsm.dylib',
+        ],
+      },
+      'conditions': [
+        # When the build SDK is 10.6, generate a dynamic stub loader. When the
+        # SDK is higher, then libxpc.dylib will be loaded automatically as part
+        # of libSystem, and only forward declarations of private symbols are
+        # necessary.
+        ['mac_sdk == "10.6"', {
+          'actions': [
+            {
+              'variables': {
+                'generate_stubs_script': '../tools/generate_stubs/generate_stubs.py',
+                'generate_stubs_header_path': 'xpc_stubs_header.fragment',
+                'generate_stubs_sig_public_path': 'xpc_stubs.sig',
+                'generate_stubs_sig_private_path': 'xpc_private_stubs.sig',
+                'generate_stubs_project': 'sandbox/mac',
+                'generate_stubs_output_stem': 'xpc_stubs',
+              },
+              'action_name': 'generate_stubs',
+              'inputs': [
+                '<(generate_stubs_script)',
+                '<(generate_stubs_header_path)',
+                '<(generate_stubs_sig_public_path)',
+                '<(generate_stubs_sig_private_path)',
+              ],
+              'outputs': [
+                '<(INTERMEDIATE_DIR)/<(generate_stubs_output_stem).cc',
+                '<(SHARED_INTERMEDIATE_DIR)/<(generate_stubs_project)/<(generate_stubs_output_stem).h',
+              ],
+              'action': [
+                'python',
+                '<(generate_stubs_script)',
+                '-i', '<(INTERMEDIATE_DIR)',
+                '-o', '<(SHARED_INTERMEDIATE_DIR)/<(generate_stubs_project)',
+                '-t', 'posix_stubs',
+                '-e', '<(generate_stubs_header_path)',
+                '-s', '<(generate_stubs_output_stem)',
+                '-p', '<(generate_stubs_project)',
+                '-x', 'SANDBOX_EXPORT',
+                '<(generate_stubs_sig_public_path)',
+                '<(generate_stubs_sig_private_path)',
+              ],
+              'process_outputs_as_sources': 1,
+              'message': 'Generating XPC stubs for 10.6 compatability.',
+            },
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'sandbox_mac_unittests',
+      'type': 'executable',
+      'sources': [
+        'bootstrap_sandbox_unittest.mm',
+        'dispatch_source_mach_unittest.cc',
+        'policy_unittest.cc',
+        'xpc_message_server_unittest.cc',
+      ],
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:base',
+        '../base/base.gyp:run_all_unittests',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        ],
+      },
+    },
+  ],
+}
diff --git a/sandbox/mac/xpc.cc b/sandbox/mac/xpc.cc
new file mode 100644
index 0000000..b8d526b
--- /dev/null
+++ b/sandbox/mac/xpc.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/xpc.h"
+
+namespace sandbox {
+
+bool InitializeXPC() {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+  std::vector<std::string> path_list;
+  path_list.push_back("/usr/lib/system/libxpc.dylib");
+
+  sandbox_mac::StubPathMap path_map;
+  path_map[sandbox_mac::kModuleXpc_stubs] = path_list;
+  path_map[sandbox_mac::kModuleXpc_private_stubs] = path_list;
+
+  return sandbox_mac::InitializeStubs(path_map);
+#else
+  return true;
+#endif
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/xpc.h b/sandbox/mac/xpc.h
new file mode 100644
index 0000000..33d3945
--- /dev/null
+++ b/sandbox/mac/xpc.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides forward declarations for XPC symbols that are not
+// present in the 10.6 SDK. It uses generate_stubs to produce code to
+// dynamically load the libxpc.dylib library and set up a stub table, with
+// the same names as the real XPC functions.
+
+#ifndef SANDBOX_MAC_XPC_H_
+#define SANDBOX_MAC_XPC_H_
+
+#include <AvailabilityMacros.h>
+#include <mach/mach.h>
+
+#include "sandbox/sandbox_export.h"
+
+// Declares XPC object types. This includes <xpc/xpc.h> if available.
+#include "sandbox/mac/xpc_stubs_header.fragment"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+// C++ library loader.
+#include "sandbox/mac/xpc_stubs.h"
+
+extern "C" {
+// Signatures for XPC public functions that are loaded by xpc_stubs.h.
+#include "sandbox/mac/xpc_stubs.sig"
+// Signatures for private XPC functions.
+#include "sandbox/mac/xpc_private_stubs.sig"
+}  // extern "C"
+
+#else
+
+// Signatures for private XPC functions.
+extern "C" {
+#include "sandbox/mac/xpc_private_stubs.sig"
+}  // extern "C"
+
+#endif
+
+namespace sandbox {
+
+// Dynamically loads the XPC library.
+bool SANDBOX_EXPORT InitializeXPC();
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_XPC_H_
diff --git a/sandbox/mac/xpc_message_server.cc b/sandbox/mac/xpc_message_server.cc
new file mode 100644
index 0000000..45559dd
--- /dev/null
+++ b/sandbox/mac/xpc_message_server.cc
@@ -0,0 +1,127 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/xpc_message_server.h"
+
+#include <bsm/libbsm.h>
+
+#include <string>
+
+#include "base/mac/mach_logging.h"
+#include "base/strings/stringprintf.h"
+#include "sandbox/mac/dispatch_source_mach.h"
+#include "sandbox/mac/xpc.h"
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+// Redeclare methods that only exist on 10.7+ to suppress
+// -Wpartial-availability warnings.
+extern "C" {
+XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL_ALL
+    xpc_object_t
+    xpc_dictionary_create_reply(xpc_object_t original);
+}  // extern "C"
+#endif
+
+namespace sandbox {
+
+XPCMessageServer::XPCMessageServer(MessageDemuxer* demuxer,
+                                   mach_port_t server_receive_right)
+    : demuxer_(demuxer),
+      server_port_(server_receive_right),
+      reply_message_(NULL) {
+}
+
+XPCMessageServer::~XPCMessageServer() {
+}
+
+bool XPCMessageServer::Initialize() {
+  // Allocate a port for use as a new server port if one was not passed to the
+  // constructor.
+  if (!server_port_.is_valid()) {
+    mach_port_t port;
+    kern_return_t kr;
+    if ((kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
+            &port)) != KERN_SUCCESS) {
+      MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
+      return false;
+    }
+    server_port_.reset(port);
+  }
+
+  std::string label = base::StringPrintf(
+      "org.chromium.sandbox.XPCMessageServer.%p", demuxer_);
+  dispatch_source_.reset(new DispatchSourceMach(
+      label.c_str(), server_port_.get(), ^{ ReceiveMessage(); }));
+  dispatch_source_->Resume();
+
+  return true;
+}
+
+pid_t XPCMessageServer::GetMessageSenderPID(IPCMessage request) {
+  audit_token_t token;
+  xpc_dictionary_get_audit_token(request.xpc, &token);
+  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
+  pid_t sender_pid;
+  audit_token_to_au32(token,
+      NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
+  return sender_pid;
+}
+
+IPCMessage XPCMessageServer::CreateReply(IPCMessage request) {
+  if (!reply_message_)
+    reply_message_ = xpc_dictionary_create_reply(request.xpc);
+
+  IPCMessage reply;
+  reply.xpc = reply_message_;
+  return reply;
+}
+
+bool XPCMessageServer::SendReply(IPCMessage reply) {
+  int rv = xpc_pipe_routine_reply(reply.xpc);
+  if (rv) {
+    LOG(ERROR) << "Failed to xpc_pipe_routine_reply(): " << rv;
+    return false;
+  }
+  return true;
+}
+
+void XPCMessageServer::ForwardMessage(IPCMessage request,
+                                      mach_port_t destination) {
+  xpc_pipe_t pipe = xpc_pipe_create_from_port(destination, 0);
+  int rv = xpc_pipe_routine_forward(pipe, request.xpc);
+  if (rv) {
+    LOG(ERROR) << "Failed to xpc_pipe_routine_forward(): " << rv;
+  }
+  xpc_release(pipe);
+}
+
+void XPCMessageServer::RejectMessage(IPCMessage request, int error_code) {
+  IPCMessage reply = CreateReply(request);
+  xpc_dictionary_set_int64(reply.xpc, "error", error_code);
+  SendReply(reply);
+}
+
+mach_port_t XPCMessageServer::GetServerPort() const {
+  return server_port_.get();
+}
+
+void XPCMessageServer::ReceiveMessage() {
+  IPCMessage request;
+  int rv = xpc_pipe_receive(server_port_, &request.xpc);
+  if (rv) {
+    LOG(ERROR) << "Failed to xpc_pipe_receive(): " << rv;
+    return;
+  }
+
+  demuxer_->DemuxMessage(request);
+
+  xpc_release(request.xpc);
+  if (reply_message_) {
+    xpc_release(reply_message_);
+    reply_message_ = NULL;
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/xpc_message_server.h b/sandbox/mac/xpc_message_server.h
new file mode 100644
index 0000000..2810097
--- /dev/null
+++ b/sandbox/mac/xpc_message_server.h
@@ -0,0 +1,75 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_XPC_MESSAGE_SERVER_H_
+#define SANDBOX_MAC_XPC_MESSAGE_SERVER_H_
+
+#include <AvailabilityMacros.h>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/mac/message_server.h"
+#include "sandbox/mac/xpc.h"
+#include "sandbox/sandbox_export.h"
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+// Redeclare methods that only exist on 10.7+ to suppress
+// -Wpartial-availability warnings.
+extern "C" {
+XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 void
+xpc_dictionary_set_int64(xpc_object_t xdict, const char* key, int64_t value);
+
+XPC_EXPORT XPC_NONNULL1 void xpc_release(xpc_object_t object);
+}  // extern "C"
+#endif
+
+namespace sandbox {
+
+class DispatchSourceMach;
+
+// An implementation of MessageServer that uses XPC pipes to read and write XPC
+// messages from a Mach port.
+class SANDBOX_EXPORT XPCMessageServer : public MessageServer {
+ public:
+  // Creates a new XPC message server that will send messages to |demuxer|
+  // for handling. If the |server_receive_right| is non-NULL, this class will
+  // take ownership of the port and it will be used to receive messages.
+  // Otherwise the server will create a new receive right on which to listen.
+  XPCMessageServer(MessageDemuxer* demuxer,
+                   mach_port_t server_receive_right);
+  ~XPCMessageServer() override;
+
+  // MessageServer:
+  bool Initialize() override;
+  pid_t GetMessageSenderPID(IPCMessage request) override;
+  IPCMessage CreateReply(IPCMessage request) override;
+  bool SendReply(IPCMessage reply) override;
+  void ForwardMessage(IPCMessage request, mach_port_t destination) override;
+  // Creates an error reply message with a field "error" set to |error_code|.
+  void RejectMessage(IPCMessage request, int error_code) override;
+  mach_port_t GetServerPort() const override;
+
+ private:
+  // Reads a message from the XPC pipe.
+  void ReceiveMessage();
+
+  // The demuxer delegate. Weak.
+  MessageDemuxer* demuxer_;
+
+  // The Mach port on which the server is receiving requests.
+  base::mac::ScopedMachReceiveRight server_port_;
+
+  // MACH_RECV dispatch source that handles the |server_port_|.
+  scoped_ptr<DispatchSourceMach> dispatch_source_;
+
+  // The reply message, if one has been created.
+  xpc_object_t reply_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(XPCMessageServer);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_XPC_MESSAGE_SERVER_H_
diff --git a/sandbox/mac/xpc_message_server_unittest.cc b/sandbox/mac/xpc_message_server_unittest.cc
new file mode 100644
index 0000000..4c4fcf9
--- /dev/null
+++ b/sandbox/mac/xpc_message_server_unittest.cc
@@ -0,0 +1,238 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/xpc_message_server.h"
+
+#include <Block.h>
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/process/kill.h"
+#include "base/test/multiprocess_test.h"
+#include "sandbox/mac/xpc.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+// Redeclare methods that only exist on 10.7+ to suppress
+// -Wpartial-availability warnings.
+extern "C" {
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL int64_t
+xpc_dictionary_get_int64(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL_ALL uint64_t
+xpc_dictionary_get_uint64(xpc_object_t xdict, const char* key);
+
+XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 void
+xpc_dictionary_set_uint64(xpc_object_t xdict, const char* key, uint64_t value);
+
+XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT xpc_object_t
+xpc_dictionary_create(const char* const* keys,
+                      const xpc_object_t* values,
+                      size_t count);
+}  // extern "C"
+#endif
+
+namespace sandbox {
+
+class XPCMessageServerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    if (!RunXPCTest())
+      return;
+    ASSERT_TRUE(InitializeXPC());
+  }
+
+  bool RunXPCTest() {
+    return base::mac::IsOSMountainLionOrLater();
+  }
+};
+
+// A MessageDemuxer that manages a test server and executes a block for every
+// message.
+class BlockDemuxer : public MessageDemuxer {
+ public:
+  BlockDemuxer()
+      : demux_block_(NULL),
+        server_(this, MACH_PORT_NULL),
+        pipe_(NULL) {
+  }
+
+  ~BlockDemuxer() override {
+    if (pipe_)
+      xpc_release(pipe_);
+    if (demux_block_)
+      Block_release(demux_block_);
+  }
+
+  // Starts running the server, given a block to handle incoming IPC messages.
+  bool Initialize(void (^demux_block)(IPCMessage request)) {
+    if (!server_.Initialize())
+      return false;
+
+    // Create a send right on the port so that the XPC pipe can be created.
+    if (mach_port_insert_right(mach_task_self(), server_.GetServerPort(),
+            server_.GetServerPort(), MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) {
+      return false;
+    }
+    scoped_send_right_.reset(server_.GetServerPort());
+
+    demux_block_ = Block_copy(demux_block);
+    pipe_ = xpc_pipe_create_from_port(server_.GetServerPort(), 0);
+
+    return true;
+  }
+
+  void DemuxMessage(IPCMessage request) override {
+    demux_block_(request);
+  }
+
+  xpc_pipe_t pipe() { return pipe_; }
+
+  XPCMessageServer* server() { return &server_; }
+
+ private:
+  void (^demux_block_)(IPCMessage request);
+
+  XPCMessageServer server_;
+
+  base::mac::ScopedMachSendRight scoped_send_right_;
+
+  xpc_pipe_t pipe_;
+};
+
+#define XPC_TEST_F(name) TEST_F(XPCMessageServerTest, name) { \
+    if (!RunXPCTest()) \
+      return; \
+
+XPC_TEST_F(ReceiveMessage)  // {
+  BlockDemuxer fixture;
+  XPCMessageServer* server = fixture.server();
+
+  uint64_t __block value = 0;
+  ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
+      value = xpc_dictionary_get_uint64(request.xpc, "test_value");
+      server->SendReply(server->CreateReply(request));
+  }));
+
+  xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
+  xpc_dictionary_set_uint64(request, "test_value", 42);
+
+  xpc_object_t reply;
+  EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
+
+  EXPECT_EQ(42u, value);
+
+  xpc_release(request);
+  xpc_release(reply);
+}
+
+XPC_TEST_F(RejectMessage)  // {
+  BlockDemuxer fixture;
+  XPCMessageServer* server = fixture.server();
+  ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
+      server->RejectMessage(request, EPERM);
+  }));
+
+  xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
+  xpc_object_t reply;
+  EXPECT_EQ(0, xpc_pipe_routine(fixture.pipe(), request, &reply));
+
+  EXPECT_EQ(EPERM, xpc_dictionary_get_int64(reply, "error"));
+
+  xpc_release(request);
+  xpc_release(reply);
+}
+
+char kGetSenderPID[] = "org.chromium.sandbox.test.GetSenderPID";
+
+XPC_TEST_F(GetSenderPID)  // {
+  BlockDemuxer fixture;
+  XPCMessageServer* server = fixture.server();
+
+  pid_t __block sender_pid = 0;
+  int64_t __block child_pid = 0;
+  ASSERT_TRUE(fixture.Initialize(^(IPCMessage request) {
+      sender_pid = server->GetMessageSenderPID(request);
+      child_pid = xpc_dictionary_get_int64(request.xpc, "child_pid");
+  }));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+  kern_return_t kr = bootstrap_register(bootstrap_port, kGetSenderPID,
+      server->GetServerPort());
+#pragma GCC diagnostic pop
+  ASSERT_EQ(KERN_SUCCESS, kr);
+
+  base::Process child = base::SpawnMultiProcessTestChild(
+      "GetSenderPID",
+      base::GetMultiProcessTestChildBaseCommandLine(),
+      base::LaunchOptions());
+  ASSERT_TRUE(child.IsValid());
+
+  int exit_code = -1;
+  ASSERT_TRUE(child.WaitForExit(&exit_code));
+  EXPECT_EQ(0, exit_code);
+
+  EXPECT_EQ(child.Pid(), sender_pid);
+  EXPECT_EQ(child.Pid(), child_pid);
+  EXPECT_EQ(sender_pid, child_pid);
+}
+
+MULTIPROCESS_TEST_MAIN(GetSenderPID) {
+  CHECK(sandbox::InitializeXPC());
+
+  mach_port_t port = MACH_PORT_NULL;
+  CHECK_EQ(KERN_SUCCESS, bootstrap_look_up(bootstrap_port, kGetSenderPID,
+      &port));
+  base::mac::ScopedMachSendRight scoped_port(port);
+
+  xpc_pipe_t pipe = xpc_pipe_create_from_port(port, 0);
+
+  xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
+  xpc_dictionary_set_int64(message, "child_pid", getpid());
+  CHECK_EQ(0, xpc_pipe_simpleroutine(pipe, message));
+
+  xpc_release(message);
+  xpc_release(pipe);
+
+  return 0;
+}
+
+XPC_TEST_F(ForwardMessage)  // {
+  BlockDemuxer first;
+  XPCMessageServer* first_server = first.server();
+
+  BlockDemuxer second;
+  XPCMessageServer* second_server = second.server();
+
+  ASSERT_TRUE(first.Initialize(^(IPCMessage request) {
+      xpc_dictionary_set_int64(request.xpc, "seen_by_first", 1);
+      first_server->ForwardMessage(request, second_server->GetServerPort());
+  }));
+  ASSERT_TRUE(second.Initialize(^(IPCMessage request) {
+      IPCMessage reply = second_server->CreateReply(request);
+      xpc_dictionary_set_int64(reply.xpc, "seen_by_first",
+          xpc_dictionary_get_int64(request.xpc, "seen_by_first"));
+      xpc_dictionary_set_int64(reply.xpc, "seen_by_second", 2);
+      second_server->SendReply(reply);
+  }));
+
+  xpc_object_t request = xpc_dictionary_create(NULL, NULL, 0);
+  xpc_object_t reply;
+  ASSERT_EQ(0, xpc_pipe_routine(first.pipe(), request, &reply));
+
+  EXPECT_EQ(1, xpc_dictionary_get_int64(reply, "seen_by_first"));
+  EXPECT_EQ(2, xpc_dictionary_get_int64(reply, "seen_by_second"));
+
+  xpc_release(request);
+  xpc_release(reply);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/xpc_private_stubs.sig b/sandbox/mac/xpc_private_stubs.sig
new file mode 100644
index 0000000..7ab2934
--- /dev/null
+++ b/sandbox/mac/xpc_private_stubs.sig
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains declarations of private XPC functions. This file is
+// used for both forward declarations of private symbols and to use with
+// tools/generate_stubs for creating a dynamic library loader.
+
+// Dictionary manipulation.
+void xpc_dictionary_set_mach_send(xpc_object_t dictionary, const char* name, mach_port_t port);
+void xpc_dictionary_get_audit_token(xpc_object_t dictionary, audit_token_t* token);
+
+// Pipe methods.
+xpc_pipe_t xpc_pipe_create_from_port(mach_port_t port, int flags);
+int xpc_pipe_receive(mach_port_t port, xpc_object_t* message);
+int xpc_pipe_routine(xpc_pipe_t pipe, xpc_object_t request, xpc_object_t* reply);
+int xpc_pipe_routine_reply(xpc_object_t reply);
+int xpc_pipe_simpleroutine(xpc_pipe_t pipe, xpc_object_t message);
+int xpc_pipe_routine_forward(xpc_pipe_t forward_to, xpc_object_t request);
diff --git a/sandbox/mac/xpc_stubs.sig b/sandbox/mac/xpc_stubs.sig
new file mode 100644
index 0000000..d20af58
--- /dev/null
+++ b/sandbox/mac/xpc_stubs.sig
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains declarations of public XPC functions used in the sandbox.
+// This file is used with tools/generate_stubs for creating a dynamic library
+// loader.
+
+// XPC object management.
+void xpc_release(xpc_object_t object);
+
+// Dictionary manipulation.
+xpc_object_t xpc_dictionary_create(const char* const *keys, const xpc_object_t* values, size_t count);
+const char* xpc_dictionary_get_string(xpc_object_t dictionary, const char* key);
+uint64_t xpc_dictionary_get_uint64(xpc_object_t dictionary, const char* key);
+void xpc_dictionary_set_uint64(xpc_object_t dictionary, const char* key, uint64_t value);
+int64_t xpc_dictionary_get_int64(xpc_object_t dictionary, const char* key);
+void xpc_dictionary_set_int64(xpc_object_t dictionary, const char* key, int64_t value);
+xpc_object_t xpc_dictionary_create_reply(xpc_object_t request);
diff --git a/sandbox/mac/xpc_stubs_header.fragment b/sandbox/mac/xpc_stubs_header.fragment
new file mode 100644
index 0000000..8197587
--- /dev/null
+++ b/sandbox/mac/xpc_stubs_header.fragment
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
+#define SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
+
+#include <bsm/libbsm.h>
+
+#include "sandbox/sandbox_export.h"
+
+// Declare or include public types.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+extern "C" {
+typedef void* xpc_object_t;
+}  // extern "C"
+
+#else
+
+#include <xpc/xpc.h>
+
+#endif
+
+// Declare private types.
+extern "C" {
+typedef struct _xpc_pipe_s* xpc_pipe_t;
+}  // extern "C"
+
+#endif  // SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
diff --git a/sandbox/sandbox.gyp b/sandbox/sandbox.gyp
new file mode 100644
index 0000000..f93fa18
--- /dev/null
+++ b/sandbox/sandbox.gyp
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'conditions': [
+    [ 'OS=="win"', {
+      'includes': [
+        'win/sandbox_win.gypi',
+      ],
+    }],
+    [ 'OS=="linux" or OS=="android"', {
+      'includes': [
+        'linux/sandbox_linux.gypi',
+      ],
+    }],
+    [ 'OS=="mac" and OS!="ios"', {
+      'includes': [
+        'mac/sandbox_mac.gypi',
+      ],
+    }],
+    [ 'OS!="win" and OS!="mac" and OS!="linux" and OS!="android"', {
+      # A 'default' to accomodate the "sandbox" target.
+      'targets': [
+        {
+          'target_name': 'sandbox',
+          'type': 'none',
+        }
+       ]
+    }],
+  ],
+}
diff --git a/sandbox/sandbox_export.h b/sandbox/sandbox_export.h
new file mode 100644
index 0000000..40a4036
--- /dev/null
+++ b/sandbox/sandbox_export.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SANDBOX_EXPORT_H_
+#define SANDBOX_SANDBOX_EXPORT_H_
+
+#if defined(WIN32)
+#error "sandbox_export.h does not support WIN32."
+#endif
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(SANDBOX_IMPLEMENTATION)
+#define SANDBOX_EXPORT __attribute__((visibility("default")))
+#define SANDBOX_EXPORT_PRIVATE __attribute__((visibility("default")))
+#else
+#define SANDBOX_EXPORT
+#define SANDBOX_EXPORT_PRIVATE
+#endif  // defined(SANDBOX_IMPLEMENTATION)
+
+#else  // defined(COMPONENT_BUILD)
+
+#define SANDBOX_EXPORT
+#define SANDBOX_EXPORT_PRIVATE
+
+#endif  // defined(COMPONENT_BUILD)
+
+#endif  // SANDBOX_SANDBOX_EXPORT_H_
diff --git a/sandbox/sandbox_linux_unittests.isolate b/sandbox/sandbox_linux_unittests.isolate
new file mode 100644
index 0000000..2dadddd
--- /dev/null
+++ b/sandbox/sandbox_linux_unittests.isolate
@@ -0,0 +1,27 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Because of a limitation in isolate_driver.py, this file needs to be in
+# the same directory as the main .gyp file.
+
+{
+  'conditions': [
+    ['OS=="android" or OS=="linux"', {
+      'variables': {
+        'command': [
+          '<(PRODUCT_DIR)/sandbox_linux_unittests',
+        ],
+        'files': [
+          '<(PRODUCT_DIR)/sandbox_linux_unittests',
+        ],
+        'read_only': 1,
+      },
+    }],
+  ],
+  'includes': [
+    # This is needed because of base/ dependencies on
+    # icudtl.dat.
+    '../base/base.isolate',
+  ],
+}
diff --git a/sandbox/sandbox_nacl_nonsfi.gyp b/sandbox/sandbox_nacl_nonsfi.gyp
new file mode 100644
index 0000000..906fc7b
--- /dev/null
+++ b/sandbox/sandbox_nacl_nonsfi.gyp
@@ -0,0 +1,61 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../build/common_untrusted.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'sandbox_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libsandbox_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              # This is the subset of linux build target, needed for
+              # nacl_helper_nonsfi's sandbox implementation.
+              'linux/bpf_dsl/bpf_dsl.cc',
+              'linux/bpf_dsl/codegen.cc',
+              'linux/bpf_dsl/dump_bpf.cc',
+              'linux/bpf_dsl/policy.cc',
+              'linux/bpf_dsl/policy_compiler.cc',
+              'linux/bpf_dsl/syscall_set.cc',
+              'linux/bpf_dsl/verifier.cc',
+              'linux/seccomp-bpf-helpers/sigsys_handlers.cc',
+              'linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc',
+              'linux/seccomp-bpf/die.cc',
+              'linux/seccomp-bpf/errorcode.cc',
+              'linux/seccomp-bpf/sandbox_bpf.cc',
+              'linux/seccomp-bpf/syscall.cc',
+              'linux/seccomp-bpf/trap.cc',
+              'linux/services/credentials.cc',
+              'linux/services/namespace_sandbox.cc',
+              'linux/services/namespace_utils.cc',
+              'linux/services/proc_util.cc',
+              'linux/services/resource_limits.cc',
+              'linux/services/syscall_wrappers.cc',
+              'linux/services/thread_helpers.cc',
+              'linux/suid/client/setuid_sandbox_client.cc',
+            ],
+          },
+          'dependencies': [
+            '../base/base_nacl.gyp:base_nacl_nonsfi',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
new file mode 100644
index 0000000..3063f7f
--- /dev/null
+++ b/sandbox/win/BUILD.gn
@@ -0,0 +1,302 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/test.gni")
+
+source_set("sandbox") {
+  sources = [
+    "src/acl.cc",
+    "src/acl.h",
+    "src/app_container.cc",
+    "src/app_container.h",
+    "src/broker_services.cc",
+    "src/broker_services.h",
+    "src/crosscall_client.h",
+    "src/crosscall_params.h",
+    "src/crosscall_server.cc",
+    "src/crosscall_server.h",
+    "src/eat_resolver.cc",
+    "src/eat_resolver.h",
+    "src/filesystem_dispatcher.cc",
+    "src/filesystem_dispatcher.h",
+    "src/filesystem_interception.cc",
+    "src/filesystem_interception.h",
+    "src/filesystem_policy.cc",
+    "src/filesystem_policy.h",
+    "src/handle_closer.cc",
+    "src/handle_closer.h",
+    "src/handle_closer_agent.cc",
+    "src/handle_closer_agent.h",
+    "src/handle_dispatcher.cc",
+    "src/handle_dispatcher.h",
+    "src/handle_interception.cc",
+    "src/handle_interception.h",
+    "src/handle_policy.cc",
+    "src/handle_policy.h",
+    "src/handle_table.cc",
+    "src/handle_table.h",
+    "src/interception.cc",
+    "src/interception.h",
+    "src/interception_agent.cc",
+    "src/interception_agent.h",
+    "src/interception_internal.h",
+    "src/interceptors.h",
+    "src/internal_types.h",
+    "src/ipc_tags.h",
+    "src/job.cc",
+    "src/job.h",
+    "src/named_pipe_dispatcher.cc",
+    "src/named_pipe_dispatcher.h",
+    "src/named_pipe_interception.cc",
+    "src/named_pipe_interception.h",
+    "src/named_pipe_policy.cc",
+    "src/named_pipe_policy.h",
+    "src/nt_internals.h",
+    "src/policy_broker.cc",
+    "src/policy_broker.h",
+    "src/policy_engine_opcodes.cc",
+    "src/policy_engine_opcodes.h",
+    "src/policy_engine_params.h",
+    "src/policy_engine_processor.cc",
+    "src/policy_engine_processor.h",
+    "src/policy_low_level.cc",
+    "src/policy_low_level.h",
+    "src/policy_params.h",
+    "src/policy_target.cc",
+    "src/policy_target.h",
+    "src/process_mitigations.cc",
+    "src/process_mitigations.h",
+    "src/process_mitigations_win32k_dispatcher.cc",
+    "src/process_mitigations_win32k_dispatcher.h",
+    "src/process_mitigations_win32k_interception.cc",
+    "src/process_mitigations_win32k_interception.h",
+    "src/process_mitigations_win32k_policy.cc",
+    "src/process_mitigations_win32k_policy.h",
+    "src/process_thread_dispatcher.cc",
+    "src/process_thread_dispatcher.h",
+    "src/process_thread_interception.cc",
+    "src/process_thread_interception.h",
+    "src/process_thread_policy.cc",
+    "src/process_thread_policy.h",
+    "src/registry_dispatcher.cc",
+    "src/registry_dispatcher.h",
+    "src/registry_interception.cc",
+    "src/registry_interception.h",
+    "src/registry_policy.cc",
+    "src/registry_policy.h",
+    "src/resolver.cc",
+    "src/resolver.h",
+    "src/restricted_token.cc",
+    "src/restricted_token.h",
+    "src/restricted_token_utils.cc",
+    "src/restricted_token_utils.h",
+    "src/sandbox.cc",
+    "src/sandbox.h",
+    "src/sandbox_factory.h",
+    "src/sandbox_globals.cc",
+    "src/sandbox_nt_types.h",
+    "src/sandbox_nt_util.cc",
+    "src/sandbox_nt_util.h",
+    "src/sandbox_policy.h",
+    "src/sandbox_policy_base.cc",
+    "src/sandbox_policy_base.h",
+    "src/sandbox_types.h",
+    "src/sandbox_utils.cc",
+    "src/sandbox_utils.h",
+    "src/security_level.h",
+    "src/service_resolver.cc",
+    "src/service_resolver.h",
+    "src/shared_handles.cc",
+    "src/shared_handles.h",
+    "src/sharedmem_ipc_client.cc",
+    "src/sharedmem_ipc_client.h",
+    "src/sharedmem_ipc_server.cc",
+    "src/sharedmem_ipc_server.h",
+    "src/sid.cc",
+    "src/sid.h",
+    "src/sync_dispatcher.cc",
+    "src/sync_dispatcher.h",
+    "src/sync_interception.cc",
+    "src/sync_interception.h",
+    "src/sync_policy.cc",
+    "src/sync_policy.h",
+    "src/target_interceptions.cc",
+    "src/target_interceptions.h",
+    "src/target_process.cc",
+    "src/target_process.h",
+    "src/target_services.cc",
+    "src/target_services.h",
+    "src/win2k_threadpool.cc",
+    "src/win2k_threadpool.h",
+    "src/win_utils.cc",
+    "src/win_utils.h",
+    "src/window.cc",
+    "src/window.h",
+  ]
+
+  if (current_cpu == "x64") {
+    sources += [
+      "src/Wow64_64.cc",
+      "src/interceptors_64.cc",
+      "src/interceptors_64.h",
+      "src/resolver_64.cc",
+      "src/service_resolver_64.cc",
+    ]
+  } else if (current_cpu == "x86") {
+    sources += [
+      "src/Wow64.cc",
+      "src/Wow64.h",
+      "src/resolver_32.cc",
+      "src/service_resolver_32.cc",
+      "src/sidestep/ia32_modrm_map.cpp",
+      "src/sidestep/ia32_opcode_map.cpp",
+      "src/sidestep/mini_disassembler.cpp",
+      "src/sidestep/mini_disassembler.h",
+      "src/sidestep/mini_disassembler_types.h",
+      "src/sidestep/preamble_patcher.h",
+      "src/sidestep/preamble_patcher_with_stub.cpp",
+      "src/sidestep_resolver.cc",
+      "src/sidestep_resolver.h",
+    ]
+  }
+
+  deps = [
+    "//base",
+    "//base:base_static",
+  ]
+  if (current_cpu == "x86") {
+    deps += [ ":copy_wow_helper" ]
+  }
+}
+
+if (current_cpu == "x86") {
+  # Make a target that copies the wow_helper files to the out dir.
+  #
+  # TODO(brettw) we can probably just build this now that we have proper
+  # toolchain support.
+  copy("copy_wow_helper") {
+    sources = [
+      "wow_helper/wow_helper.exe",
+      "wow_helper/wow_helper.pdb",
+    ]
+    outputs = [
+      "$root_out_dir/{{source_file_part}}",
+    ]
+  }
+}
+
+test("sbox_integration_tests") {
+  sources = [
+    "src/address_sanitizer_test.cc",
+    "src/app_container_test.cc",
+    "src/file_policy_test.cc",
+    "src/handle_closer_test.cc",
+    "src/handle_inheritance_test.cc",
+    "src/handle_policy_test.cc",
+    "src/integrity_level_test.cc",
+    "src/ipc_ping_test.cc",
+    "src/named_pipe_policy_test.cc",
+    "src/policy_target_test.cc",
+    "src/process_mitigations_test.cc",
+    "src/process_policy_test.cc",
+    "src/registry_policy_test.cc",
+    "src/sync_policy_test.cc",
+    "src/sync_policy_test.h",
+    "src/unload_dll_test.cc",
+    "tests/common/controller.cc",
+    "tests/common/controller.h",
+    "tests/common/test_utils.cc",
+    "tests/common/test_utils.h",
+    "tests/integration_tests/integration_tests.cc",
+    "tests/integration_tests/integration_tests_test.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
+
+test("sbox_validation_tests") {
+  sources = [
+    "tests/common/controller.cc",
+    "tests/common/controller.h",
+    "tests/validation_tests/commands.cc",
+    "tests/validation_tests/commands.h",
+    "tests/validation_tests/suite.cc",
+    "tests/validation_tests/unit_tests.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
+
+test("sbox_unittests") {
+  sources = [
+    "src/app_container_unittest.cc",
+    "src/interception_unittest.cc",
+    "src/ipc_unittest.cc",
+    "src/job_unittest.cc",
+    "src/policy_engine_unittest.cc",
+    "src/policy_low_level_unittest.cc",
+    "src/policy_opcodes_unittest.cc",
+    "src/restricted_token_unittest.cc",
+    "src/service_resolver_unittest.cc",
+    "src/sid_unittest.cc",
+    "src/threadpool_unittest.cc",
+    "src/win_utils_unittest.cc",
+    "tests/common/test_utils.cc",
+    "tests/common/test_utils.h",
+    "tests/unit_tests/unit_tests.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
+
+test("sandbox_poc") {
+  sources = [
+    "sandbox_poc/main_ui_window.cc",
+    "sandbox_poc/main_ui_window.h",
+    "sandbox_poc/resource.h",
+    "sandbox_poc/sandbox.cc",
+    "sandbox_poc/sandbox.h",
+    "sandbox_poc/sandbox.ico",
+    "sandbox_poc/sandbox.rc",
+  ]
+
+  configs -= [ "//build/config/win:console" ]
+  configs += [ "//build/config/win:windowed" ]
+
+  libs = [ "comctl32.lib" ]
+
+  deps = [
+    ":sandbox",
+    ":pocdll",
+  ]
+}
+
+shared_library("pocdll") {
+  sources = [
+    "sandbox_poc/pocdll/exports.h",
+    "sandbox_poc/pocdll/fs.cc",
+    "sandbox_poc/pocdll/handles.cc",
+    "sandbox_poc/pocdll/invasive.cc",
+    "sandbox_poc/pocdll/network.cc",
+    "sandbox_poc/pocdll/pocdll.cc",
+    "sandbox_poc/pocdll/processes_and_threads.cc",
+    "sandbox_poc/pocdll/registry.cc",
+    "sandbox_poc/pocdll/spyware.cc",
+    "sandbox_poc/pocdll/utils.h",
+  ]
+
+  defines = [ "POCDLL_EXPORTS" ]
+}
diff --git a/sandbox/win/OWNERS b/sandbox/win/OWNERS
new file mode 100644
index 0000000..9ccaeb3
--- /dev/null
+++ b/sandbox/win/OWNERS
@@ -0,0 +1,3 @@
+cpu@chromium.org
+jschuh@chromium.org
+rvargas@chromium.org
diff --git a/sandbox/win/sandbox_poc/main_ui_window.cc b/sandbox/win/sandbox_poc/main_ui_window.cc
new file mode 100644
index 0000000..1671424
--- /dev/null
+++ b/sandbox/win/sandbox_poc/main_ui_window.cc
@@ -0,0 +1,669 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <CommCtrl.h>
+#include <commdlg.h>
+#include <time.h>
+#include <windowsx.h>
+#include <atlbase.h>
+#include <atlsecurity.h>
+#include <algorithm>
+#include <sstream>
+
+#include "sandbox/win/sandbox_poc/main_ui_window.h"
+#include "base/logging.h"
+#include "sandbox/win/sandbox_poc/resource.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/win_utils.h"
+
+HWND MainUIWindow::list_view_ = NULL;
+
+const wchar_t MainUIWindow::kDefaultDll_[]        = L"\\POCDLL.dll";
+const wchar_t MainUIWindow::kDefaultEntryPoint_[] = L"Run";
+const wchar_t MainUIWindow::kDefaultLogFile_[]    = L"";
+
+MainUIWindow::MainUIWindow()
+    : instance_handle_(NULL),
+      spawn_target_(L""),
+      dll_path_(L""),
+      entry_point_(L""),
+      broker_(NULL) {
+}
+
+MainUIWindow::~MainUIWindow() {
+}
+
+unsigned int MainUIWindow::CreateMainWindowAndLoop(
+    HINSTANCE instance,
+    wchar_t* command_line,
+    int show_command,
+    sandbox::BrokerServices* broker) {
+  DCHECK(instance);
+  DCHECK(command_line);
+  DCHECK(broker);
+
+  instance_handle_ = instance;
+  spawn_target_ = command_line;
+  broker_ = broker;
+
+  // We'll use spawn_target_ later for creating a child process, but
+  // CreateProcess doesn't like double quotes, so we remove them along with
+  // tabs and spaces from the start and end of the string
+  const wchar_t *trim_removal = L" \r\t\"";
+  spawn_target_.erase(0, spawn_target_.find_first_not_of(trim_removal));
+  spawn_target_.erase(spawn_target_.find_last_not_of(trim_removal) + 1);
+
+  WNDCLASSEX window_class = {0};
+  window_class.cbSize        = sizeof(WNDCLASSEX);
+  window_class.style         = CS_HREDRAW | CS_VREDRAW;
+  window_class.lpfnWndProc   = MainUIWindow::WndProc;
+  window_class.cbClsExtra    = 0;
+  window_class.cbWndExtra    = 0;
+  window_class.hInstance     = instance;
+  window_class.hIcon         =
+      ::LoadIcon(instance, MAKEINTRESOURCE(IDI_SANDBOX));
+  window_class.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
+  window_class.hbrBackground = GetStockBrush(WHITE_BRUSH);
+  window_class.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU_MAIN_UI);
+  window_class.lpszClassName = L"sandbox_ui_1";
+  window_class.hIconSm       = NULL;
+
+  INITCOMMONCONTROLSEX controls = {
+    sizeof(INITCOMMONCONTROLSEX),
+    ICC_STANDARD_CLASSES | ICC_LISTVIEW_CLASSES
+  };
+  ::InitCommonControlsEx(&controls);
+
+  if (!::RegisterClassEx(&window_class))
+    return ::GetLastError();
+
+  // Create a main window of size 600x400
+  HWND window = ::CreateWindowW(window_class.lpszClassName,
+                                L"",            // window name
+                                WS_OVERLAPPEDWINDOW,
+                                CW_USEDEFAULT,  // x
+                                CW_USEDEFAULT,  // y
+                                600,            // width
+                                400,            // height
+                                NULL,           // parent
+                                NULL,           // NULL = use class menu
+                                instance,
+                                0);             // lpParam
+
+  if (NULL == window)
+    return ::GetLastError();
+
+  ::SetWindowLongPtr(window,
+                     GWLP_USERDATA,
+                     reinterpret_cast<LONG_PTR>(this));
+
+  ::SetWindowText(window, L"Sandbox Proof of Concept");
+
+  ::ShowWindow(window, show_command);
+
+  MSG message;
+  // Now lets start the message pump retrieving messages for any window that
+  // belongs to the current thread
+  while (::GetMessage(&message, NULL, 0, 0)) {
+    ::TranslateMessage(&message);
+    ::DispatchMessage(&message);
+  }
+
+  return 0;
+}
+
+LRESULT CALLBACK MainUIWindow::WndProc(HWND window,
+                                       UINT message_id,
+                                       WPARAM wparam,
+                                       LPARAM lparam) {
+  MainUIWindow* host = FromWindow(window);
+
+  #define HANDLE_MSG(hwnd, message, fn)    \
+    case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
+
+  switch (message_id) {
+    case WM_CREATE:
+      // 'host' is not yet available when we get the WM_CREATE message
+      return HANDLE_WM_CREATE(window, wparam, lparam, OnCreate);
+    case WM_DESTROY:
+      return HANDLE_WM_DESTROY(window, wparam, lparam, host->OnDestroy);
+    case WM_SIZE:
+      return HANDLE_WM_SIZE(window, wparam, lparam, host->OnSize);
+    case WM_COMMAND: {
+      // Look at which menu item was clicked on (or which accelerator)
+      int id = LOWORD(wparam);
+      switch (id) {
+        case ID_FILE_EXIT:
+          host->OnFileExit();
+          break;
+        case ID_COMMANDS_SPAWNTARGET:
+          host->OnCommandsLaunch(window);
+          break;
+        default:
+          // Some other menu item or accelerator
+          break;
+      }
+
+      return ERROR_SUCCESS;
+    }
+
+    default:
+      // Some other WM_message, let it pass to DefWndProc
+      break;
+  }
+
+  return DefWindowProc(window, message_id, wparam, lparam);
+}
+
+INT_PTR CALLBACK MainUIWindow::SpawnTargetWndProc(HWND dialog,
+                                                  UINT message_id,
+                                                  WPARAM wparam,
+                                                  LPARAM lparam) {
+  UNREFERENCED_PARAMETER(lparam);
+
+  // Grab a reference to the main UI window (from the window handle)
+  MainUIWindow* host = FromWindow(GetParent(dialog));
+  DCHECK(host);
+
+  switch (message_id) {
+    case WM_INITDIALOG: {
+      // Initialize the window text for DLL name edit box
+      HWND edit_box_dll_name = ::GetDlgItem(dialog, IDC_DLL_NAME);
+      wchar_t current_dir[MAX_PATH];
+      if (GetCurrentDirectory(MAX_PATH, current_dir)) {
+        base::string16 dll_path = base::string16(current_dir) +
+                                base::string16(kDefaultDll_);
+        ::SetWindowText(edit_box_dll_name, dll_path.c_str());
+      }
+
+      // Initialize the window text for Entry Point edit box
+      HWND edit_box_entry_point = ::GetDlgItem(dialog, IDC_ENTRY_POINT);
+      ::SetWindowText(edit_box_entry_point, kDefaultEntryPoint_);
+
+      // Initialize the window text for Log File edit box
+      HWND edit_box_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE);
+      ::SetWindowText(edit_box_log_file, kDefaultLogFile_);
+
+      return static_cast<INT_PTR>(TRUE);
+    }
+    case WM_COMMAND:
+      // If the user presses the OK button (Launch)
+      if (LOWORD(wparam) == IDOK) {
+        if (host->OnLaunchDll(dialog)) {
+          if (host->SpawnTarget()) {
+            ::EndDialog(dialog, LOWORD(wparam));
+          }
+        }
+        return static_cast<INT_PTR>(TRUE);
+      } else if (LOWORD(wparam) == IDCANCEL) {
+        // If the user presses the Cancel button
+        ::EndDialog(dialog, LOWORD(wparam));
+        return static_cast<INT_PTR>(TRUE);
+      } else if (LOWORD(wparam) == IDC_BROWSE_DLL) {
+        // If the user presses the Browse button to look for a DLL
+        base::string16 dll_path = host->OnShowBrowseForDllDlg(dialog);
+        if (dll_path.length() > 0) {
+          // Initialize the window text for Log File edit box
+          HWND edit_box_dll_path = ::GetDlgItem(dialog, IDC_DLL_NAME);
+          ::SetWindowText(edit_box_dll_path, dll_path.c_str());
+        }
+        return static_cast<INT_PTR>(TRUE);
+      } else if (LOWORD(wparam) == IDC_BROWSE_LOG) {
+        // If the user presses the Browse button to look for a log file
+        base::string16 log_path = host->OnShowBrowseForLogFileDlg(dialog);
+        if (log_path.length() > 0) {
+          // Initialize the window text for Log File edit box
+          HWND edit_box_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE);
+          ::SetWindowText(edit_box_log_file, log_path.c_str());
+        }
+        return static_cast<INT_PTR>(TRUE);
+      }
+
+      break;
+  }
+
+  return static_cast<INT_PTR>(FALSE);
+}
+
+MainUIWindow* MainUIWindow::FromWindow(HWND main_window) {
+  // We store a 'this' pointer using SetWindowLong in CreateMainWindowAndLoop
+  // so that we can retrieve it with this function later. This prevents us
+  // from having to define all the message handling functions (that we refer to
+  // in the window proc) as static
+  ::GetWindowLongPtr(main_window, GWLP_USERDATA);
+  return reinterpret_cast<MainUIWindow*>(
+      ::GetWindowLongPtr(main_window, GWLP_USERDATA));
+}
+
+BOOL MainUIWindow::OnCreate(HWND parent_window, LPCREATESTRUCT) {
+  // Create the listview that will the main app UI
+  list_view_ = ::CreateWindow(WC_LISTVIEW,    // Class name
+                              L"",            // Window name
+                              WS_CHILD | WS_VISIBLE | LVS_REPORT |
+                              LVS_NOCOLUMNHEADER | WS_BORDER,
+                              0,              // x
+                              0,              // y
+                              0,              // width
+                              0,              // height
+                              parent_window,  // parent
+                              NULL,           // menu
+                              ::GetModuleHandle(NULL),
+                              0);             // lpParam
+
+  DCHECK(list_view_);
+  if (!list_view_)
+    return FALSE;
+
+  LVCOLUMN list_view_column = {0};
+  list_view_column.mask = LVCF_FMT | LVCF_WIDTH ;
+  list_view_column.fmt = LVCFMT_LEFT;
+  list_view_column.cx = 10000;  // Maximum size of an entry in the list view.
+  ListView_InsertColumn(list_view_, 0, &list_view_column);
+
+  // Set list view to show green font on black background
+  ListView_SetBkColor(list_view_, CLR_NONE);
+  ListView_SetTextColor(list_view_, RGB(0x0, 0x0, 0x0));
+  ListView_SetTextBkColor(list_view_, CLR_NONE);
+
+  return TRUE;
+}
+
+void MainUIWindow::OnDestroy(HWND window) {
+  UNREFERENCED_PARAMETER(window);
+
+  // Post a quit message because our application is over when the
+  // user closes this window.
+  ::PostQuitMessage(0);
+}
+
+void MainUIWindow::OnSize(HWND window, UINT state, int cx, int cy) {
+  UNREFERENCED_PARAMETER(window);
+  UNREFERENCED_PARAMETER(state);
+
+  // If we have a valid inner child, resize it to cover the entire
+  // client area of the main UI window.
+  if (list_view_) {
+    ::MoveWindow(list_view_,
+                 0,      // x
+                 0,      // y
+                 cx,     // width
+                 cy,     // height
+                 TRUE);  // repaint
+  }
+}
+
+void MainUIWindow::OnPaint(HWND window) {
+  PAINTSTRUCT paintstruct;
+  ::BeginPaint(window, &paintstruct);
+  // add painting code here if required
+  ::EndPaint(window, &paintstruct);
+}
+
+void MainUIWindow::OnFileExit() {
+  ::PostQuitMessage(0);
+}
+
+void MainUIWindow::OnCommandsLaunch(HWND window) {
+  // User wants to see the Select DLL dialog box
+  ::DialogBox(instance_handle_,
+              MAKEINTRESOURCE(IDD_LAUNCH_DLL),
+              window,
+              SpawnTargetWndProc);
+}
+
+bool MainUIWindow::OnLaunchDll(HWND dialog) {
+  HWND edit_box_dll_name = ::GetDlgItem(dialog, IDC_DLL_NAME);
+  HWND edit_box_entry_point = ::GetDlgItem(dialog, IDC_ENTRY_POINT);
+  HWND edit_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE);
+
+  wchar_t dll_path[MAX_PATH];
+  wchar_t entry_point[MAX_PATH];
+  wchar_t log_file[MAX_PATH];
+
+  int dll_name_len    = ::GetWindowText(edit_box_dll_name, dll_path, MAX_PATH);
+  int entry_point_len = ::GetWindowText(edit_box_entry_point,
+                                        entry_point, MAX_PATH);
+  // Log file is optional (can be blank)
+  ::GetWindowText(edit_log_file, log_file, MAX_PATH);
+
+  if (0 >= dll_name_len) {
+    ::MessageBox(dialog,
+                 L"Please specify a DLL for the target to load",
+                 L"No DLL specified",
+                 MB_ICONERROR);
+    return false;
+  }
+
+  if (GetFileAttributes(dll_path) == INVALID_FILE_ATTRIBUTES) {
+    ::MessageBox(dialog,
+                 L"DLL specified was not found",
+                 L"DLL not found",
+                 MB_ICONERROR);
+    return false;
+  }
+
+  if (0 >= entry_point_len) {
+    ::MessageBox(dialog,
+                 L"Please specify an entry point for the DLL",
+                 L"No entry point specified",
+                 MB_ICONERROR);
+    return false;
+  }
+
+  // store these values in the member variables for use in SpawnTarget
+  log_file_ = base::string16(L"\"") + log_file + base::string16(L"\"");
+  dll_path_ = dll_path;
+  entry_point_ = entry_point;
+
+  return true;
+}
+
+DWORD WINAPI MainUIWindow::ListenPipeThunk(void *param) {
+  return reinterpret_cast<MainUIWindow*>(param)->ListenPipe();
+}
+
+DWORD WINAPI MainUIWindow::WaitForTargetThunk(void *param) {
+  return reinterpret_cast<MainUIWindow*>(param)->WaitForTarget();
+}
+
+// Thread waiting for the target application to die. It displays
+// a message in the list view when it happens.
+DWORD MainUIWindow::WaitForTarget() {
+  WaitForSingleObject(target_.hProcess, INFINITE);
+
+  DWORD exit_code = 0;
+  if (!GetExitCodeProcess(target_.hProcess, &exit_code)) {
+    exit_code = 0xFFFF;  // Default exit code
+  }
+
+  ::CloseHandle(target_.hProcess);
+  ::CloseHandle(target_.hThread);
+
+  AddDebugMessage(L"Targed exited with return code %d", exit_code);
+  return 0;
+}
+
+// Thread waiting for messages on the log pipe. It displays the messages
+// in the listview.
+DWORD MainUIWindow::ListenPipe() {
+  HANDLE logfile_handle = NULL;
+  ATL::CString file_to_open = log_file_.c_str();
+  file_to_open.Remove(L'\"');
+  if (file_to_open.GetLength()) {
+    logfile_handle = ::CreateFile(file_to_open.GetBuffer(),
+                                  GENERIC_WRITE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                  NULL,  // Default security attributes
+                                  CREATE_ALWAYS,
+                                  FILE_ATTRIBUTE_NORMAL,
+                                  NULL);  // No template
+    if (INVALID_HANDLE_VALUE == logfile_handle) {
+      AddDebugMessage(L"Failed to open \"%ls\" for logging. Error %d",
+                      file_to_open.GetBuffer(), ::GetLastError());
+      logfile_handle = NULL;
+    }
+  }
+
+  const int kSizeBuffer = 1024;
+  BYTE read_buffer[kSizeBuffer] = {0};
+  ATL::CStringA read_buffer_global;
+  ATL::CStringA string_to_print;
+
+  DWORD last_error = 0;
+  while(last_error == ERROR_SUCCESS || last_error == ERROR_PIPE_LISTENING ||
+        last_error == ERROR_NO_DATA)
+  {
+    DWORD read_data_length;
+    if (::ReadFile(pipe_handle_,
+                  read_buffer,
+                  kSizeBuffer - 1,  // Max read size
+                  &read_data_length,
+                  NULL)) {  // Not overlapped
+      if (logfile_handle) {
+        DWORD write_data_length;
+        ::WriteFile(logfile_handle,
+                    read_buffer,
+                    read_data_length,
+                    &write_data_length,
+                    FALSE);  // Not overlapped
+      }
+
+      // Append the new buffer to the current buffer
+      read_buffer[read_data_length] = NULL;
+      read_buffer_global += reinterpret_cast<char *>(read_buffer);
+      read_buffer_global.Remove(10);  // Remove the CRs
+
+      // If we completed a new line, output it
+      int endline = read_buffer_global.Find(13);  // search for LF
+      while (-1 != endline) {
+        string_to_print = read_buffer_global;
+        string_to_print.Delete(endline, string_to_print.GetLength());
+        read_buffer_global.Delete(0, endline);
+
+        //  print the line (with the ending LF)
+        OutputDebugStringA(string_to_print.GetBuffer());
+
+        // Remove the ending LF
+        read_buffer_global.Delete(0, 1);
+
+        // Add the line to the log
+        AddDebugMessage(L"%S", string_to_print.GetBuffer());
+
+        endline = read_buffer_global.Find(13);
+      }
+      last_error = ERROR_SUCCESS;
+    } else {
+      last_error = GetLastError();
+      Sleep(100);
+    }
+  }
+
+  if (read_buffer_global.GetLength()) {
+    AddDebugMessage(L"%S", read_buffer_global.GetBuffer());
+  }
+
+  CloseHandle(pipe_handle_);
+
+  if (logfile_handle) {
+    CloseHandle(logfile_handle);
+  }
+
+  return 0;
+}
+
+bool MainUIWindow::SpawnTarget() {
+  // Generate the pipe name
+  GUID random_id;
+  CoCreateGuid(&random_id);
+
+  wchar_t log_pipe[MAX_PATH] = {0};
+  wnsprintf(log_pipe, MAX_PATH - 1,
+            L"\\\\.\\pipe\\sbox_pipe_log_%lu_%lu_%lu_%lu",
+            random_id.Data1,
+            random_id.Data2,
+            random_id.Data3,
+            random_id.Data4);
+
+  // We concatenate the four strings, add three spaces and a zero termination
+  // We use the resulting string as a param to CreateProcess (in SpawnTarget)
+  // Documented maximum for command line in CreateProcess is 32K (msdn)
+  size_t size_call = spawn_target_.length() + entry_point_.length() +
+                  dll_path_.length() + wcslen(log_pipe) + 6;
+  if (32 * 1024 < (size_call * sizeof(wchar_t))) {
+    AddDebugMessage(L"The length of the arguments exceeded 32K. "
+                    L"Aborting operation.");
+    return false;
+  }
+
+  wchar_t * arguments = new wchar_t[size_call];
+  wnsprintf(arguments, static_cast<int>(size_call), L"%ls %ls \"%ls\" %ls",
+            spawn_target_.c_str(), entry_point_.c_str(),
+            dll_path_.c_str(), log_pipe);
+
+  arguments[size_call - 1] = L'\0';
+
+  sandbox::TargetPolicy* policy = broker_->CreatePolicy();
+  policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
+  policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                        sandbox::USER_LOCKDOWN);
+  policy->SetAlternateDesktop(true);
+  policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+
+  // Set the rule to allow the POC dll to be loaded by the target. Note that
+  // the rule allows 'all access' to the DLL, which could mean that the target
+  // could modify the DLL on disk.
+  policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                  sandbox::TargetPolicy::FILES_ALLOW_ANY, dll_path_.c_str());
+
+  sandbox::ResultCode result = broker_->SpawnTarget(spawn_target_.c_str(),
+                                                    arguments, policy,
+                                                    &target_);
+
+  policy->Release();
+  policy = NULL;
+
+  bool return_value = false;
+  if (sandbox::SBOX_ALL_OK != result) {
+    AddDebugMessage(
+        L"Failed to spawn target %ls w/args (%ls), sandbox error code: %d",
+        spawn_target_.c_str(), arguments, result);
+    return_value = false;
+  } else {
+
+    DWORD thread_id;
+    ::CreateThread(NULL,  // Default security attributes
+                   NULL,  // Default stack size
+                   &MainUIWindow::WaitForTargetThunk,
+                   this,
+                   0,  // No flags
+                   &thread_id);
+
+    pipe_handle_ = ::CreateNamedPipe(log_pipe,
+                                     PIPE_ACCESS_INBOUND | WRITE_DAC,
+                                     PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
+                                     1,  // Number of instances.
+                                     512,  // Out buffer size.
+                                     512,  // In buffer size.
+                                     NMPWAIT_USE_DEFAULT_WAIT,
+                                     NULL);  // Default security descriptor
+
+    if (INVALID_HANDLE_VALUE == pipe_handle_)
+      AddDebugMessage(L"Failed to create pipe. Error %d", ::GetLastError());
+
+    if (!sandbox::AddKnownSidToObject(pipe_handle_, SE_KERNEL_OBJECT,
+                                      WinWorldSid, GRANT_ACCESS,
+                                      FILE_ALL_ACCESS))
+      AddDebugMessage(L"Failed to set security on pipe. Error %d",
+                      ::GetLastError());
+
+    ::CreateThread(NULL,  // Default security attributes
+                   NULL,  // Default stack size
+                   &MainUIWindow::ListenPipeThunk,
+                   this,
+                   0,  // No flags
+                   &thread_id);
+
+    ::ResumeThread(target_.hThread);
+
+    AddDebugMessage(L"Successfully spawned target w/args (%ls)", arguments);
+    return_value = true;
+  }
+
+  delete[] arguments;
+  return return_value;
+}
+
+base::string16 MainUIWindow::OnShowBrowseForDllDlg(HWND owner) {
+  wchar_t filename[MAX_PATH];
+  wcscpy_s(filename, MAX_PATH, L"");
+
+  OPENFILENAMEW file_info = {0};
+  file_info.lStructSize = sizeof(file_info);
+  file_info.hwndOwner = owner;
+  file_info.lpstrFile = filename;
+  file_info.nMaxFile = MAX_PATH;
+  file_info.lpstrFilter = L"DLL files (*.dll)\0*.dll\0All files\0*.*\0\0\0";
+
+  file_info.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
+
+  if (GetOpenFileName(&file_info)) {
+    return file_info.lpstrFile;
+  }
+
+  return L"";
+}
+
+base::string16 MainUIWindow::OnShowBrowseForLogFileDlg(HWND owner) {
+  wchar_t filename[MAX_PATH];
+  wcscpy_s(filename, MAX_PATH, L"");
+
+  OPENFILENAMEW file_info = {0};
+  file_info.lStructSize = sizeof(file_info);
+  file_info.hwndOwner = owner;
+  file_info.lpstrFile = filename;
+  file_info.nMaxFile = MAX_PATH;
+  file_info.lpstrFilter = L"Log file (*.txt)\0*.txt\0All files\0*.*\0\0\0";
+
+  file_info.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
+
+  if (GetSaveFileName(&file_info)) {
+    return file_info.lpstrFile;
+  }
+
+  return L"";
+}
+
+void MainUIWindow::AddDebugMessage(const wchar_t* format, ...) {
+  DCHECK(format);
+  if (!format)
+    return;
+
+  const int kMaxDebugBuffSize = 1024;
+
+  va_list arg_list;
+  _crt_va_start(arg_list, format);
+
+  wchar_t text[kMaxDebugBuffSize + 1];
+  vswprintf_s(text, kMaxDebugBuffSize, format, arg_list);
+  text[kMaxDebugBuffSize] = L'\0';
+
+  InsertLineInListView(text);
+}
+
+
+void MainUIWindow::InsertLineInListView(wchar_t* debug_message) {
+  DCHECK(debug_message);
+  if (!debug_message)
+    return;
+
+  // Prepend the time to the message
+  const int kSizeTime = 100;
+  size_t size_message_with_time = wcslen(debug_message) + kSizeTime;
+  wchar_t * message_time = new wchar_t[size_message_with_time];
+
+  time_t time_temp;
+  time_temp = time(NULL);
+
+  struct tm time = {0};
+  localtime_s(&time, &time_temp);
+
+  size_t return_code;
+  return_code = wcsftime(message_time, kSizeTime, L"[%H:%M:%S] ", &time);
+
+  wcscat_s(message_time, size_message_with_time, debug_message);
+
+  // We add the debug message to the top of the listview
+  LVITEM item;
+  item.iItem = ListView_GetItemCount(list_view_);
+  item.iSubItem = 0;
+  item.mask = LVIF_TEXT | LVIF_PARAM;
+  item.pszText = message_time;
+  item.lParam = 0;
+
+  ListView_InsertItem(list_view_, &item);
+
+  delete[] message_time;
+}
diff --git a/sandbox/win/sandbox_poc/main_ui_window.h b/sandbox/win/sandbox_poc/main_ui_window.h
new file mode 100644
index 0000000..84fb986
--- /dev/null
+++ b/sandbox/win/sandbox_poc/main_ui_window.h
@@ -0,0 +1,194 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SANDBOX_POC_MAIN_UI_WINDOW_H__
+#define SANDBOX_SANDBOX_POC_MAIN_UI_WINDOW_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+namespace sandbox {
+class BrokerServices;
+enum ResultCode;
+}
+
+// Header file for the MainUIWindow, a simple window with a menu bar that
+// can pop up a dialog (accessible through the menu bar), to specify a path and
+// filename of any DLL to load and choose an entry point of his/her choice
+// (note: only entry points with no parameters are expected to work).
+//
+// The purpose of this is to be able to spawn an EXE inside a SandBox, have it
+// load a DLL and call the entry point on it to test how it behaves inside the
+// sandbox. This is useful for developer debugging and for security testing.
+//
+// The MainUIWindow also has a listview that displays debugging information to
+// the user.
+//
+// Sample usage:
+//
+//    MainUIWindow window;
+//    unsigned int ret = window.CreateMainWindowAndLoop(
+//        handle_to_current_instance,
+//        ::GetCommandLineW(),
+//        show_command,
+//        broker);
+//
+// The CreateMainWindowAndLoop() contains a message loop that ends when the
+// user closes the MainUIWindow.
+
+// This class encapsulates the Main UI window for the broker application.
+// It simply shows a menu that gives the user the ability (through a dialog) to
+// specify a DLL and what entry point to call in the DLL.
+class MainUIWindow {
+ public:
+  MainUIWindow();
+  ~MainUIWindow();
+
+  // Creates the main window, displays it and starts the message pump. This
+  // call will not return until user closes the main UI window that appears
+  // as a result. Arguments 'instance', 'command_line' and 'show_cmd' can be
+  // passed in directly from winmain. The 'broker' argument is a pointer to a
+  // BrokerService that will launch a new EXE inside the sandbox and load the
+  // DLL of the user's choice.
+  unsigned int CreateMainWindowAndLoop(HINSTANCE instance,
+                                       wchar_t* command_line,
+                                       int show_command,
+                                       sandbox::BrokerServices* broker);
+
+ private:
+  // The default value DLL name to add to the edit box.
+  static const wchar_t kDefaultDll_[];
+
+  // The default value to show in the entry point.
+  static const wchar_t kDefaultEntryPoint_[];
+
+  // The default value to show in the log file.
+  static const wchar_t kDefaultLogFile_[];
+
+  // Handles the messages sent to the main UI window. The return value is the
+  // result of the message processing and depends on the message.
+  static LRESULT CALLBACK WndProc(HWND window,
+                                  UINT message_id,
+                                  WPARAM wparam,
+                                  LPARAM lparam);
+
+  // Handles the messages sent to the SpawnTarget dialog. The return value is
+  // the result of the message processing and depends on the message.
+  static INT_PTR CALLBACK SpawnTargetWndProc(HWND dialog,
+                                             UINT message_id,
+                                             WPARAM wparam,
+                                             LPARAM lparam);
+
+  // Retrieves a pointer to the MainWindow from a value stored along with the
+  // window handle (passed in as hwnd). Return value is a pointer to the
+  // MainUIWindow previously stored with SetWindowLong() during WM_CREATE.
+  static MainUIWindow* FromWindow(HWND main_window);
+
+  // Handles the WM_CREATE message for the main UI window. Returns TRUE on
+  // success.
+  static BOOL OnCreate(HWND parent_window, LPCREATESTRUCT);
+
+  // Handles the WM_DESTROY message for the main UI window.
+  void OnDestroy(HWND window);
+
+  // Handles the WM_SIZE message for the main UI window.
+  void OnSize(HWND window, UINT state, int cx, int cy);
+
+  // Handles the WM_PAINT message for the main UI window.
+  void OnPaint(HWND window);
+
+  // Handles the menu command File \ Exit for the main UI window.
+  void OnFileExit();
+
+  // Handles the menu command Commands \ Launch for the main UI window.
+  void OnCommandsLaunch(HWND window);
+
+  // Handles the Launch button in the SpawnTarget dialog (normally clicked
+  // after selecting DLL and entry point). OnLaunchDll will retrieve the
+  // values entered by the user and store it in the members of the class.
+  // Returns true if user selected a non-zero values for DLL filename
+  // (possibly including path also) and entry point.
+  bool OnLaunchDll(HWND dialog);
+
+  // Spawns a target EXE inside the sandbox (with the help of the
+  // BrokerServices passed in to CreateMainWindowAndLoop), and passes to it
+  // (as command line arguments) the DLL path and the entry point function
+  // name. The EXE is expected to parse the command line and load the DLL.
+  // NOTE: The broker does not know if the target EXE successfully loaded the
+  // DLL, for that you have to rely on the EXE providing a log.
+  // Returns true if the broker reports that it was successful in creating
+  // the target and false if not.
+  bool SpawnTarget();
+
+  // Shows a standard File Open dialog and returns the DLL filename selected or
+  // blank string if the user cancelled (or an error occurred).
+  base::string16 OnShowBrowseForDllDlg(HWND owner);
+
+  // Shows a standard Save As dialog and returns the log filename selected or
+  // blank string if the user cancelled (or an error occurred).
+  base::string16 OnShowBrowseForLogFileDlg(HWND owner);
+
+  // Formats a message using the supplied format string and prints it in the
+  // listview in the main UI window. Passing a NULL param in 'fmt' results in
+  // no action being performed. Maximum message length is 1K.
+  void AddDebugMessage(const wchar_t* format, ...);
+
+  // Assists AddDebugMessage in displaying a message in the ListView. It
+  // simply wraps ListView_InsertItem to insert a debugging message to the
+  // top of the list view. Passing a NULL param in 'fmt' results in no action
+  // being performed.
+  void InsertLineInListView(wchar_t* debug_message);
+
+  // Calls ListenPipe using the class instance received in parameter. This is
+  // used to create new threads executing ListenPipe
+  static DWORD WINAPI ListenPipeThunk(void *param);
+
+  // Calls WaitForTargetThunk using the class instance received in parameter
+  // This is used to create new threads executing WaitForTarget.
+  static DWORD WINAPI WaitForTargetThunk(void *param);
+
+  // Listens on a pipe and output the data received to a file and to the UI.
+  DWORD ListenPipe();
+
+  // Waits for the target to dies and display a message in the UI.
+  DWORD WaitForTarget();
+
+  // The BrokerServices will be used to spawn an EXE in a sandbox and ask
+  // it to load a DLL.
+  sandbox::BrokerServices* broker_;
+
+  // Contains the information about the running target.
+  PROCESS_INFORMATION target_;
+
+  // This is essentially a command line to a target executable that the
+  // broker will spawn and ask to load the DLL.
+  base::string16 spawn_target_;
+
+  // A handle to the current instance of the app. Passed in to this class
+  // through CreateMainWindowAndLoop.
+  HINSTANCE instance_handle_;
+
+  // A path to the DLL that the target should load once it executes.
+  base::string16 dll_path_;
+
+  // The name of the entry point the target should call after it loads the DLL.
+  base::string16 entry_point_;
+
+  // The name of the log file to use.
+  base::string16 log_file_;
+
+  // This is a static handle to the list view that fills up the entire main
+  // UI window. The list view is used to display debugging information to the
+  // user.
+  static HWND list_view_;
+
+  // Pipe used to communicate the logs between the target and the broker.
+  HANDLE pipe_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(MainUIWindow);
+};
+
+#endif  // SANDBOX_SANDBOX_POC_MAIN_UI_WINDOW_H__
diff --git a/sandbox/win/sandbox_poc/pocdll/exports.h b/sandbox/win/sandbox_poc/pocdll/exports.h
new file mode 100644
index 0000000..66a07d6
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/exports.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SANDBOX_POC_POCDLL_EXPORTS_H__
+#define SANDBOX_SANDBOX_POC_POCDLL_EXPORTS_H__
+
+#include <windows.h>
+
+#ifdef POCDLL_EXPORTS
+#define POCDLL_API __declspec(dllexport) __cdecl
+#else
+#define POCDLL_API __declspec(dllimport) __cdecl
+#endif
+
+extern "C" {
+// Tries to open several known system path and outputs
+// the result.
+// "log" is the handle of the log file.
+void POCDLL_API TestFileSystem(HANDLE log);
+
+// Tries to find all handles open in the process and prints the name of the
+// resource references by the handle along with the access right.
+// "log" is the handle of the log file.
+void POCDLL_API TestGetHandle(HANDLE log);
+
+// Creates a lot of threads until it cannot create more. The goal of this
+// function is to determine if it's possible to crash the machine when we
+// flood the machine with new threads
+// "log" is the handle of the log file.
+void POCDLL_API TestThreadBombing(HANDLE log);
+
+// Takes all cpu of the machine. For each processor on the machine we assign
+// a thread. This thread will compute a mathematical expression over and over
+// to take all cpu.
+// "log" is the handle of the log file.
+// Note: here we are using the affinity to find out how many processors are on
+// the machine and to force a thread to run only on a given processor.
+void POCDLL_API TestTakeAllCpu(HANDLE log);
+
+// Creates memory in the heap until it fails 5 times in a row and prints the
+// amount of memory created. This function is used to find out if it's possible
+// to take all memory on the machine and crash the system.
+// "log" is the handle of the log file.
+void POCDLL_API TestUseAllMemory(HANDLE log);
+
+// Creates millions of kernel objects. This function is used to find out if it's
+// possible to crash the system if we create too many kernel objects and if we
+// hold too many handles. All those kernel objects are unnamed.
+// "log" is the handle of the log file.
+void POCDLL_API TestCreateObjects(HANDLE log);
+
+// Receives a hwnd and tries to close it. This is the callback for EnumWindows.
+// It will be called for each window(hwnd) on the system.
+// "log" is the handle of the log file.
+// Always returns TRUE to tell the system that we want to continue the
+// enumeration.
+void POCDLL_API TestCloseHWND(HANDLE log);
+
+// Tries to listen on the port 88.
+// "log" is the handle of the log file.
+void POCDLL_API TestNetworkListen(HANDLE log);
+
+// Lists all processes on the system and tries to open them
+// "log" is the handle of the log file.
+void POCDLL_API TestProcesses(HANDLE log);
+
+// Lists all threads on the system and tries to open them
+// "log" is the handle of the log file.
+void POCDLL_API TestThreads(HANDLE log);
+
+// Tries to open some known system registry key and outputs the result.
+// "log" is the handle of the log file.
+void POCDLL_API TestRegistry(HANDLE log);
+
+// Records all keystrokes typed for 15 seconds and then display them.
+// "log" is the handle of the log file.
+void POCDLL_API TestSpyKeys(HANDLE log);
+
+// Tries to read pixels on the monitor and output if the operation
+// failes or succeeded.
+// "log" is the handle of the log file.
+void POCDLL_API TestSpyScreen(HANDLE log);
+
+// Runs all tests except those who are invasive
+void POCDLL_API Run(HANDLE log);
+}
+
+#endif  // SANDBOX_SANDBOX_POC_POCDLL_EXPORTS_H__
diff --git a/sandbox/win/sandbox_poc/pocdll/fs.cc b/sandbox/win/sandbox_poc/pocdll/fs.cc
new file mode 100644
index 0000000..40596af
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/fs.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+// This file contains the tests used to verify the security of the file system.
+
+// Tries to open a file and outputs the result.
+// "path" can contain environment variables.
+// "output" is the stream for the logging.
+void TryOpenFile(const wchar_t *path, FILE *output) {
+  wchar_t path_expanded[MAX_PATH] = {0};
+  DWORD size = ::ExpandEnvironmentStrings(path, path_expanded, MAX_PATH - 1);
+  if (!size) {
+    fprintf(output, "[ERROR] Cannot expand \"%S\". Error %ld.\r\n", path,
+            ::GetLastError());
+  }
+
+  HANDLE file;
+  file = ::CreateFile(path_expanded,
+                      GENERIC_READ,
+                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                      NULL,  // No security attributes
+                      OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS,
+                      NULL);  // No template
+
+  if (file && INVALID_HANDLE_VALUE != file) {
+    fprintf(output, "[GRANTED] Opening file \"%S\". Handle 0x%p\r\n", path,
+            file);
+    ::CloseHandle(file);
+  } else {
+    fprintf(output, "[BLOCKED] Opening file \"%S\". Error %ld.\r\n", path,
+            ::GetLastError());
+  }
+}
+
+void POCDLL_API TestFileSystem(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  TryOpenFile(L"%SystemDrive%", output);
+  TryOpenFile(L"%SystemRoot%", output);
+  TryOpenFile(L"%ProgramFiles%", output);
+  TryOpenFile(L"%SystemRoot%\\System32", output);
+  TryOpenFile(L"%SystemRoot%\\explorer.exe", output);
+  TryOpenFile(L"%SystemRoot%\\Cursors\\arrow_i.cur", output);
+  TryOpenFile(L"%AllUsersProfile%", output);
+  TryOpenFile(L"%UserProfile%", output);
+  TryOpenFile(L"%Temp%", output);
+  TryOpenFile(L"%AppData%", output);
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/handles.cc b/sandbox/win/sandbox_poc/pocdll/handles.cc
new file mode 100644
index 0000000..a12d433
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/handles.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+#include "sandbox/win/tools/finder/ntundoc.h"
+
+// This file contains the tests used to verify the security of handles in
+// the process
+
+NTQUERYOBJECT NtQueryObject;
+NTQUERYINFORMATIONFILE NtQueryInformationFile;
+NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
+
+void POCDLL_API TestGetHandle(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  // Initialize the NTAPI functions we need
+  HMODULE ntdll_handle = ::GetModuleHandle(L"ntdll.dll");
+  if (!ntdll_handle) {
+    fprintf(output, "[ERROR] Cannot load ntdll.dll. Error %ld\r\n",
+            ::GetLastError());
+    return;
+  }
+
+  NtQueryObject = reinterpret_cast<NTQUERYOBJECT>(
+                      GetProcAddress(ntdll_handle, "NtQueryObject"));
+  NtQueryInformationFile = reinterpret_cast<NTQUERYINFORMATIONFILE>(
+                      GetProcAddress(ntdll_handle, "NtQueryInformationFile"));
+  NtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>(
+                      GetProcAddress(ntdll_handle, "NtQuerySystemInformation"));
+
+  if (!NtQueryObject || !NtQueryInformationFile || !NtQuerySystemInformation) {
+    fprintf(output, "[ERROR] Cannot load all NT functions. Error %ld\r\n",
+                    ::GetLastError());
+    return;
+  }
+
+  // Get the number of handles on the system
+  DWORD buffer_size = 0;
+  SYSTEM_HANDLE_INFORMATION_EX temp_info;
+  NTSTATUS status = NtQuerySystemInformation(
+      SystemHandleInformation, &temp_info, sizeof(temp_info),
+      &buffer_size);
+  if (!buffer_size) {
+    fprintf(output, "[ERROR] Get the number of handles. Error 0x%lX\r\n",
+                    status);
+    return;
+  }
+
+  SYSTEM_HANDLE_INFORMATION_EX *system_handles =
+      reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(new BYTE[buffer_size]);
+
+  status = NtQuerySystemInformation(SystemHandleInformation, system_handles,
+                                    buffer_size, &buffer_size);
+  if (STATUS_SUCCESS != status) {
+    fprintf(output, "[ERROR] Failed to get the handle list. Error 0x%lX\r\n",
+                    status);
+    delete [] system_handles;
+    return;
+  }
+
+  for (ULONG i = 0; i < system_handles->NumberOfHandles; ++i) {
+    USHORT h = system_handles->Information[i].Handle;
+    if (system_handles->Information[i].ProcessId != ::GetCurrentProcessId())
+      continue;
+
+    OBJECT_NAME_INFORMATION *name = NULL;
+    ULONG name_size = 0;
+    // Query the name information a first time to get the size of the name.
+    status = NtQueryObject(reinterpret_cast<HANDLE>(h),
+                           ObjectNameInformation,
+                           name,
+                           name_size,
+                           &name_size);
+
+    if (name_size) {
+      name = reinterpret_cast<OBJECT_NAME_INFORMATION *>(new BYTE[name_size]);
+
+      // Query the name information a second time to get the name of the
+      // object referenced by the handle.
+      status = NtQueryObject(reinterpret_cast<HANDLE>(h),
+                             ObjectNameInformation,
+                             name,
+                             name_size,
+                             &name_size);
+    }
+
+    PUBLIC_OBJECT_TYPE_INFORMATION *type = NULL;
+    ULONG type_size = 0;
+
+    // Query the object to get the size of the object type name.
+    status = NtQueryObject(reinterpret_cast<HANDLE>(h),
+                           ObjectTypeInformation,
+                           type,
+                           type_size,
+                           &type_size);
+    if (type_size) {
+      type = reinterpret_cast<PUBLIC_OBJECT_TYPE_INFORMATION *>(
+          new BYTE[type_size]);
+
+      // Query the type information a second time to get the object type
+      // name.
+      status = NtQueryObject(reinterpret_cast<HANDLE>(h),
+                             ObjectTypeInformation,
+                             type,
+                             type_size,
+                             &type_size);
+    }
+
+    // NtQueryObject cannot return the name for a file. In this case we
+    // need to ask NtQueryInformationFile
+    FILE_NAME_INFORMATION *file_name = NULL;
+    if (type && wcsncmp(L"File", type->TypeName.Buffer,
+                        (type->TypeName.Length /
+                        sizeof(type->TypeName.Buffer[0]))) == 0)  {
+      // This function does not return the size of the buffer. We need to
+      // iterate and always increase the buffer size until the function
+      // succeeds. (Or at least does not fail with STATUS_BUFFER_OVERFLOW)
+      ULONG size_file = MAX_PATH;
+      IO_STATUS_BLOCK status_block = {0};
+      do {
+        // Delete the previous buffer create. The buffer was too small
+        if (file_name) {
+          delete[] reinterpret_cast<BYTE*>(file_name);
+          file_name = NULL;
+        }
+
+        // Increase the buffer and do the call agan
+        size_file += MAX_PATH;
+        file_name = reinterpret_cast<FILE_NAME_INFORMATION *>(
+            new BYTE[size_file]);
+        status = NtQueryInformationFile(reinterpret_cast<HANDLE>(h),
+                                        &status_block,
+                                        file_name,
+                                        size_file,
+                                        FileNameInformation);
+      } while (status == STATUS_BUFFER_OVERFLOW);
+
+      if (STATUS_SUCCESS != status) {
+        if (file_name) {
+          delete[] file_name;
+          file_name = NULL;
+        }
+      }
+    }
+
+    if (file_name) {
+      UNICODE_STRING file_name_string;
+      file_name_string.Buffer = file_name->FileName;
+      file_name_string.Length = (USHORT)file_name->FileNameLength;
+      file_name_string.MaximumLength = (USHORT)file_name->FileNameLength;
+      fprintf(output, "[GRANTED] Handle 0x%4.4X Access: 0x%8.8lX "
+                      "Type: %-13wZ Path: %wZ\r\n",
+                      h,
+                      system_handles->Information[i].GrantedAccess,
+                      type ? &type->TypeName : NULL,
+                      &file_name_string);
+    } else {
+      fprintf(output, "[GRANTED] Handle 0x%4.4X Access: 0x%8.8lX "
+                      "Type: %-13wZ Path: %wZ\r\n",
+                      h,
+                      system_handles->Information[i].GrantedAccess,
+                      type ? &type->TypeName : NULL,
+                      name ? &name->ObjectName : NULL);
+    }
+
+    if (type) {
+      delete[] type;
+    }
+
+    if (file_name) {
+      delete[] file_name;
+    }
+
+    if (name) {
+      delete [] name;
+    }
+  }
+
+  if (system_handles) {
+    delete [] system_handles;
+  }
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/invasive.cc b/sandbox/win/sandbox_poc/pocdll/invasive.cc
new file mode 100644
index 0000000..9ee13b0
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/invasive.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <malloc.h>
+#include "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+// This file contains the tests used to verify if it's possible to DOS or crash
+// the machine. All tests that can impact the stability of the machine should
+// be in this file.
+
+// Sleeps forever. this function is used to be the
+// entry point for the threads created by the thread bombing function.
+// This function never returns.
+DWORD WINAPI MyThreadBombimgFunction(void *param) {
+  UNREFERENCED_PARAMETER(param);
+  Sleep(INFINITE);
+  return 0;
+}
+
+void POCDLL_API TestThreadBombing(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  // we stop after 5 errors in a row
+  int number_errors = 0;
+  for (int i = 0; i < 100000; ++i) {
+    DWORD tid;
+    // Create the thread and leak the handle.
+    HANDLE thread = ::CreateThread(NULL,  // Default security attributes
+                                   NULL,  // Stack size
+                                   MyThreadBombimgFunction,
+                                   NULL,  // Parameter
+                                   0,     // No creation flags
+                                   &tid);
+    if (thread) {
+      fprintf(output, "[GRANTED] Creating thread with tid 0x%lX\r\n", tid);
+      ::CloseHandle(thread);
+      number_errors = 0;
+    } else {
+      fprintf(output, "[BLOCKED] Creating thread. Error %ld\r\n",
+              ::GetLastError());
+      number_errors++;
+    }
+
+    if (number_errors >= 5) {
+      break;
+    }
+  }
+}
+
+
+// Executes a complex mathematical operation forever in a loop. This function
+// is used as entry point for the threads created by TestTakeAllCpu. It it
+// designed to take all CPU on the processor where the thread is running.
+// The return value is always 0.
+DWORD WINAPI TakeAllCpu(void *param) {
+  UNREFERENCED_PARAMETER(param);
+  int cpt = 0;
+  for (;;) {
+    cpt += 2;
+    cpt /= 2;
+    cpt *= cpt;
+    cpt = cpt % 100;
+    cpt = cpt | (cpt * cpt);
+  }
+}
+
+void POCDLL_API TestTakeAllCpu(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  DWORD_PTR process_mask = 0;
+  DWORD_PTR system_mask = 0;
+  if (::GetProcessAffinityMask(::GetCurrentProcess(),
+                               &process_mask,
+                               &system_mask)) {
+    DWORD_PTR affinity_mask = 1;
+
+    while (system_mask) {
+      DWORD tid = 0;
+
+      HANDLE thread = ::CreateThread(NULL,  // Default security attributes.
+                                     NULL,  // Stack size.
+                                     TakeAllCpu,
+                                     NULL,  // Parameter.
+                                     0,     // No creation flags.
+                                     &tid);
+      ::SetThreadAffinityMask(thread, affinity_mask);
+
+      if (::SetThreadPriority(thread, REALTIME_PRIORITY_CLASS)) {
+        fprintf(output, "[GRANTED] Set thread(%ld) priority to Realtime\r\n",
+                tid);
+      } else {
+        fprintf(output, "[BLOCKED] Set thread(%ld) priority to Realtime\r\n",
+                tid);
+      }
+
+      ::CloseHandle(thread);
+
+      affinity_mask = affinity_mask << 1;
+      system_mask = system_mask >> 1;
+    }
+  } else {
+    fprintf(output, "[ERROR] Cannot get affinity mask. Error %ld\r\n",
+           ::GetLastError());
+  }
+}
+
+void POCDLL_API TestUseAllMemory(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  int number_errors = 0;
+  unsigned long memory_size = 0;
+  for (;;) {
+    DWORD *ptr_to_leak = reinterpret_cast<DWORD *>(malloc(1024*256));
+    if (ptr_to_leak) {
+      memory_size += (256);
+      number_errors = 0;
+    } else {
+      number_errors++;
+    }
+
+    // check if we have more than 5 errors in a row. If so, quit.
+    if (number_errors >= 5) {
+      fprintf(output, "[INFO] Created %lu kb of memory\r\n", memory_size);
+      return;
+    }
+
+    Sleep(5);  // 5ms to be able to see the progression easily with taskmgr.
+  }
+}
+
+void POCDLL_API TestCreateObjects(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  int mutexes = 0;
+  int jobs = 0;
+  int events = 0;
+  for (int i = 0; i < 1000000; ++i) {
+    if (::CreateMutex(NULL,     // Default security attributes.
+                      TRUE,     // We are the initial owner.
+                      NULL)) {  // No name.
+      mutexes++;
+    }
+
+    if (::CreateJobObject(NULL,     // Default security attributes.
+                          NULL)) {  // No name.
+      jobs++;
+    }
+
+    if (::CreateEvent(NULL,     // Default security attributes.
+                      TRUE,     // Manual Reset.
+                      TRUE,     // Object is signaled.
+                      NULL)) {  // No name.
+      events++;
+    }
+  }
+
+  fprintf(output, "[GRANTED] Created %d mutexes, %d jobs and %d events for "
+                  "a total of %d objects out of 3 000 000\r\n", mutexes, jobs,
+                  events, mutexes + jobs + events);
+}
+
+BOOL CALLBACK EnumWindowCallback(HWND hwnd, LPARAM output) {
+  DWORD pid;
+  ::GetWindowThreadProcessId(hwnd, &pid);
+  if (pid != ::GetCurrentProcessId()) {
+    wchar_t window_title[100 + 1] = {0};
+    ::GetWindowText(hwnd, window_title, 100);
+    fprintf(reinterpret_cast<FILE*>(output),
+            "[GRANTED] Found window 0x%p with title %S\r\n",
+            hwnd,
+            window_title);
+    ::CloseWindow(hwnd);
+  }
+
+  return TRUE;
+}
+
+// Enumerates all the windows on the system and call the function to try to
+// close them. The goal of this function is to try to kill the system by
+// closing all windows.
+// "output" is the stream used for logging.
+void POCDLL_API TestCloseHWND(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  ::EnumWindows(EnumWindowCallback, PtrToLong(output));
+  // TODO(nsylvain): find a way to know when the enum is finished
+  // before returning.
+  ::Sleep(3000);
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/network.cc b/sandbox/win/sandbox_poc/pocdll/network.cc
new file mode 100644
index 0000000..56ab5ae
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/network.cc
@@ -0,0 +1,66 @@
+// 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 "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+// This file contains the tests used to verify the security of the network.
+
+void POCDLL_API TestNetworkListen(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+#if DONT_WANT_INTERCEPTIONS_JUST_WANT_NETWORK
+  // Initialize Winsock
+  WSADATA wsa_data;
+  int result = ::WSAStartup(MAKEWORD(2, 2), &wsa_data);
+  if (result != NO_ERROR) {
+    fprintf(output, "[ERROR] Cannot initialize winsock. Error%d\r\n", result);
+    return;
+  }
+
+  // Create a SOCKET for listening for
+  // incoming connection requests.
+  SOCKET listen_socket;
+  listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (listen_socket == INVALID_SOCKET) {
+    fprintf(output, "[ERROR] Failed to create socket. Error %ld\r\n",
+           ::WSAGetLastError());
+    ::WSACleanup();
+    return;
+  }
+
+  // The sockaddr_in structure specifies the address family,
+  // IP address, and port for the socket that is being bound.
+  sockaddr_in service;
+  service.sin_family = AF_INET;
+  service.sin_addr.s_addr = inet_addr("127.0.0.1");
+  service.sin_port = htons(88);
+
+  if (bind(listen_socket, reinterpret_cast<SOCKADDR*>(&service),
+           sizeof(service)) == SOCKET_ERROR) {
+    fprintf(output, "[BLOCKED] Bind socket on port 88. Error %ld\r\n",
+            ::WSAGetLastError());
+    closesocket(listen_socket);
+    ::WSACleanup();
+    return;
+  }
+
+  // Listen for incoming connection requests
+  // on the created socket
+  if (listen(listen_socket, SOMAXCONN) == SOCKET_ERROR) {
+    fprintf(output, "[BLOCKED] Listen socket on port 88. Error %ld\r\n",
+            ::WSAGetLastError());
+
+  } else {
+    fprintf(output, "[GRANTED] Listen socket on port 88.\r\n",
+            ::WSAGetLastError());
+  }
+
+  ::WSACleanup();
+  return;
+#else  // DONT_WANT_INTERCEPTIONS_JUST_WANT_NETWORK
+  // Just print out that this test is not running.
+  fprintf(output, "[ERROR] No network tests.\r\n");
+#endif  // DONT_WANT_INTERCEPTIONS_JUST_WANT_NETWORK
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/pocdll.cc b/sandbox/win/sandbox_poc/pocdll/pocdll.cc
new file mode 100644
index 0000000..e058f58
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/pocdll.cc
@@ -0,0 +1,27 @@
+// 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 "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+BOOL APIENTRY DllMain(HMODULE module,
+                      DWORD reason_for_call,
+                      LPVOID reserved) {
+  UNREFERENCED_PARAMETER(module);
+  UNREFERENCED_PARAMETER(reason_for_call);
+  UNREFERENCED_PARAMETER(reserved);
+  return TRUE;
+}
+
+void POCDLL_API Run(HANDLE log) {
+  TestFileSystem(log);
+  TestRegistry(log);
+  TestNetworkListen(log);
+  TestSpyScreen(log);
+  TestSpyKeys(log);
+  TestThreads(log);
+  TestProcesses(log);
+  TestGetHandle(log);
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/pocdll.vcproj b/sandbox/win/sandbox_poc/pocdll/pocdll.vcproj
new file mode 100644
index 0000000..8e4e31f
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/pocdll.vcproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="pocdll"
+	ProjectGUID="{AE5BFB87-850E-4454-B01D-58E7D8BAC224}"
+	RootNamespace="pocdll"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="POCDLL_EXPORTS"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				ModuleDefinitionFile=""
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+				EmbedManifest="false"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="POCDLL_EXPORTS"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				ModuleDefinitionFile=""
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+				EmbedManifest="false"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\exports.h"
+			>
+		</File>
+		<File
+			RelativePath=".\fs.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\handles.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\invasive.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\network.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\pocdll.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\processes_and_threads.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\registry.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\spyware.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+		<File
+			RelativePath=".\utils.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/sandbox_poc/pocdll/processes_and_threads.cc b/sandbox/win/sandbox_poc/pocdll/processes_and_threads.cc
new file mode 100644
index 0000000..03e12ba
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/processes_and_threads.cc
@@ -0,0 +1,102 @@
+// 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>
+#include <Tlhelp32.h>
+#include "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+// This file contains the tests used to verify the security of threads and
+// processes.
+
+void POCDLL_API TestProcesses(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
+  if (INVALID_HANDLE_VALUE == snapshot) {
+    fprintf(output, "[BLOCKED] Cannot list all processes on the system. "
+                    "Error %ld\r\n", ::GetLastError());
+    return;
+  }
+
+  PROCESSENTRY32 process_entry = {0};
+  process_entry.dwSize = sizeof(PROCESSENTRY32);
+
+  BOOL result = ::Process32First(snapshot, &process_entry);
+
+  while (result) {
+    HANDLE process = ::OpenProcess(PROCESS_VM_READ,
+                                   FALSE,  // Do not inherit handle.
+                                   process_entry.th32ProcessID);
+    if (NULL == process) {
+      fprintf(output, "[BLOCKED] Found process %S:%ld but cannot open it. "
+                      "Error %ld\r\n",
+                      process_entry.szExeFile,
+                      process_entry.th32ProcessID,
+                      ::GetLastError());
+    } else {
+      fprintf(output, "[GRANTED] Found process %S:%ld and open succeeded.\r\n",
+                      process_entry.szExeFile, process_entry.th32ProcessID);
+      ::CloseHandle(process);
+    }
+
+    result = ::Process32Next(snapshot, &process_entry);
+  }
+
+  DWORD err_code = ::GetLastError();
+  if (ERROR_NO_MORE_FILES != err_code) {
+    fprintf(output, "[ERROR] Error %ld while looking at the processes on "
+                    "the system\r\n", err_code);
+  }
+
+  ::CloseHandle(snapshot);
+}
+
+void POCDLL_API TestThreads(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
+  if (INVALID_HANDLE_VALUE == snapshot) {
+    fprintf(output, "[BLOCKED] Cannot list all threads on the system. "
+                    "Error %ld\r\n", ::GetLastError());
+    return;
+  }
+
+  THREADENTRY32 thread_entry = {0};
+  thread_entry.dwSize = sizeof(THREADENTRY32);
+
+  BOOL result = ::Thread32First(snapshot, &thread_entry);
+  int nb_success = 0;
+  int nb_failure = 0;
+
+  while (result) {
+    HANDLE thread = ::OpenThread(THREAD_QUERY_INFORMATION,
+                                 FALSE,  // Do not inherit handles.
+                                 thread_entry.th32ThreadID);
+    if (NULL == thread) {
+      nb_failure++;
+    } else {
+      nb_success++;
+      fprintf(output, "[GRANTED] Found thread %ld:%ld and able to open it.\r\n",
+                      thread_entry.th32OwnerProcessID,
+                      thread_entry.th32ThreadID);
+      ::CloseHandle(thread);
+    }
+
+    result = Thread32Next(snapshot, &thread_entry);
+  }
+
+  DWORD err_code = ::GetLastError();
+  if (ERROR_NO_MORE_FILES != err_code) {
+    fprintf(output, "[ERROR] Error %ld while looking at the processes on "
+                    "the system\r\n", err_code);
+  }
+
+  fprintf(output, "[INFO] Found %d threads. Able to open %d of them\r\n",
+          nb_success + nb_failure, nb_success);
+
+  ::CloseHandle(snapshot);
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/registry.cc b/sandbox/win/sandbox_poc/pocdll/registry.cc
new file mode 100644
index 0000000..5784db6
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/registry.cc
@@ -0,0 +1,49 @@
+// 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 "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+// This file contains the tests used to verify the security of the registry.
+
+// Tries to open the key hive\path and outputs the result.
+// "output" is the stream used for logging.
+void TryOpenKey(const HKEY hive,
+                const wchar_t* hive_name,
+                const wchar_t* path,
+                FILE* output) {
+  HKEY key;
+  LONG err_code = ::RegOpenKeyEx(hive,
+                                 path,
+                                 0,  // Reserved, must be 0.
+                                 MAXIMUM_ALLOWED,
+                                 &key);
+  if (ERROR_SUCCESS == err_code) {
+    fprintf(output,
+            "[GRANTED] Opening key \"%S\\%S\". Handle 0x%p\r\n",
+            hive_name,
+            path,
+            key);
+    ::RegCloseKey(key);
+  } else {
+    fprintf(output,
+            "[BLOCKED] Opening key \"%S\\%S\". Error %ld\r\n",
+            hive_name,
+            path,
+            err_code);
+  }
+}
+
+void POCDLL_API TestRegistry(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  TryOpenKey(HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE", NULL, output);
+  TryOpenKey(HKEY_CURRENT_USER, L"HKEY_CURRENT_USER", NULL, output);
+  TryOpenKey(HKEY_USERS, L"HKEY_USERS", NULL, output);
+  TryOpenKey(HKEY_LOCAL_MACHINE,
+             L"HKEY_LOCAL_MACHINE",
+             L"Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
+             output);
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/spyware.cc b/sandbox/win/sandbox_poc/pocdll/spyware.cc
new file mode 100644
index 0000000..cf0bd41
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/spyware.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "sandbox/win/sandbox_poc/pocdll/exports.h"
+#include "sandbox/win/sandbox_poc/pocdll/utils.h"
+
+// This file contains the tests used to verify the security of the system by
+// using some spying techniques.
+
+void POCDLL_API TestSpyKeys(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  if (RegisterHotKey(NULL, 1, 0, 0x42)) {
+    fprintf(output, "[GRANTED] successfully registered hotkey\r\n");
+    UnregisterHotKey(NULL, 1);
+  } else {
+    fprintf(output, "[BLOCKED] Failed to register hotkey. Error = %ld\r\n",
+            ::GetLastError());
+  }
+
+  fprintf(output, "[INFO] Logging keystrokes for 15 seconds\r\n");
+  fflush(output);
+  base::string16 logged;
+  DWORD tick = ::GetTickCount() + 15000;
+  while (tick > ::GetTickCount()) {
+    for (int i = 0; i < 256; ++i) {
+      if (::GetAsyncKeyState(i) & 1) {
+        if (i >=  VK_SPACE && i <= 0x5A /*VK_Z*/) {
+          logged.append(1, static_cast<wchar_t>(i));
+        } else {
+          logged.append(1, '?');
+        }
+      }
+    }
+  }
+
+  if (logged.size()) {
+    fprintf(output, "[GRANTED] Spyed keystrokes \"%S\"\r\n",
+            logged.c_str());
+  } else {
+    fprintf(output, "[BLOCKED] Spyed keystrokes \"(null)\"\r\n");
+  }
+}
+
+void POCDLL_API TestSpyScreen(HANDLE log) {
+  HandleToFile handle2file;
+  FILE *output = handle2file.Translate(log, "w");
+
+  HDC screen_dc = ::GetDC(NULL);
+  COLORREF pixel_color = ::GetPixel(screen_dc, 0, 0);
+
+  for (int x = 0; x < 10; ++x) {
+    for (int y = 0; y < 10; ++y) {
+      if (::GetPixel(screen_dc, x, y) != pixel_color) {
+        fprintf(output, "[GRANTED] Read pixel on screen\r\n");
+        return;
+      }
+    }
+  }
+
+  fprintf(output, "[BLOCKED] Read pixel on screen. Error = %ld\r\n",
+          ::GetLastError());
+}
diff --git a/sandbox/win/sandbox_poc/pocdll/utils.h b/sandbox/win/sandbox_poc/pocdll/utils.h
new file mode 100644
index 0000000..ae42861
--- /dev/null
+++ b/sandbox/win/sandbox_poc/pocdll/utils.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SANDBOX_POC_POCDLL_UTILS_H__
+#define SANDBOX_SANDBOX_POC_POCDLL_UTILS_H__
+
+#include <stdio.h>
+#include <io.h>
+#include "base/basictypes.h"
+
+// Class to convert a HANDLE to a FILE *. The FILE * is closed when the
+// object goes out of scope
+class HandleToFile {
+ public:
+  HandleToFile() {
+    file_ = NULL;
+  };
+
+  // Note: c_file_handle_ does not need to be closed because fclose does it.
+  ~HandleToFile() {
+    if (file_) {
+      fflush(file_);
+      fclose(file_);
+    }
+  };
+
+  // Translates a HANDLE (handle) to a FILE * opened with the mode "mode".
+  // The return value is the FILE * or NULL if there is an error.
+  FILE* Translate(HANDLE handle, const char *mode) {
+    if (file_) {
+      return  NULL;
+    }
+
+    HANDLE new_handle;
+    BOOL result = ::DuplicateHandle(::GetCurrentProcess(),
+                                    handle,
+                                    ::GetCurrentProcess(),
+                                    &new_handle,
+                                    0,  // Don't ask for a specific
+                                        // desired access.
+                                    FALSE,  // Not inheritable.
+                                    DUPLICATE_SAME_ACCESS);
+
+    if (!result) {
+      return NULL;
+    }
+
+    int c_file_handle = _open_osfhandle(reinterpret_cast<LONG_PTR>(new_handle),
+                                        0);  // No flags
+    if (-1 == c_file_handle) {
+      return NULL;
+    }
+
+    file_ = _fdopen(c_file_handle, mode);
+    return file_;
+  };
+ private:
+  // the FILE* returned. We need to closed it at the end.
+  FILE* file_;
+
+  DISALLOW_COPY_AND_ASSIGN(HandleToFile);
+};
+
+#endif  // SANDBOX_SANDBOX_POC_POCDLL_UTILS_H__
diff --git a/sandbox/win/sandbox_poc/resource.h b/sandbox/win/sandbox_poc/resource.h
new file mode 100644
index 0000000..87ff920
--- /dev/null
+++ b/sandbox/win/sandbox_poc/resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by sandbox.rc
+//
+#define IDI_SANDBOX                     107
+#define IDR_MENU_MAIN_UI                129
+#define IDD_LAUNCH_DLL                  130
+#define IDC_RADIO_POCDLL                1000
+#define IDC_RADIO_CUSTOM_DLL            1001
+#define IDC_DLL_NAME                    1002
+#define IDC_ENTRY_POINT                 1003
+#define IDC_LOG_FILE                    1004
+#define IDC_BROWSE_DLL                  1005
+#define IDC_BROWSE_LOG                  1006
+#define ID_FILE_EXIT                    32771
+#define ID_COMMANDS_LAUNCHDLL           32772
+#define ID_COMMANDS_SPAWNTARGET         32773
+#define IDC_STATIC                      -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC                     1
+#define _APS_NEXT_RESOURCE_VALUE        131
+#define _APS_NEXT_COMMAND_VALUE         32774
+#define _APS_NEXT_CONTROL_VALUE         1007
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
diff --git a/sandbox/win/sandbox_poc/sandbox.cc b/sandbox/win/sandbox_poc/sandbox.cc
new file mode 100644
index 0000000..e282075
--- /dev/null
+++ b/sandbox/win/sandbox_poc/sandbox.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <tchar.h>
+#include <shellapi.h>
+#include "sandbox/win/sandbox_poc/sandbox.h"
+#include "base/logging.h"
+#include "sandbox/win/sandbox_poc/main_ui_window.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+
+// Prototype allowed for functions to be called in the POC
+typedef void(__cdecl *lpfnInit)(HANDLE);
+
+bool ParseCommandLine(wchar_t * command_line,
+                      std::string * dll_name,
+                      std::string * entry_point,
+                      base::string16 * log_file) {
+  DCHECK(dll_name);
+  DCHECK(entry_point);
+  DCHECK(log_file);
+  if (!dll_name || !entry_point || !log_file)
+    return false;
+
+  LPWSTR *arg_list;
+  int arg_count;
+
+  // We expect the command line to contain: EntryPointName "DLLPath" "LogPath"
+  // NOTE: Double quotes are required, even if long path name not used
+  // NOTE: LogPath can be blank, but still requires the double quotes
+  arg_list = CommandLineToArgvW(command_line, &arg_count);
+  if (NULL == arg_list || arg_count < 4) {
+     return false;
+  }
+
+  base::string16 entry_point_wide = arg_list[1];
+  base::string16 dll_name_wide = arg_list[2];
+  *entry_point = std::string(entry_point_wide.begin(), entry_point_wide.end());
+  *dll_name    = std::string(dll_name_wide.begin(), dll_name_wide.end());
+  *log_file    = arg_list[3];
+
+  // Free memory allocated for CommandLineToArgvW arguments.
+  LocalFree(arg_list);
+
+  return true;
+}
+
+int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, wchar_t* command_line,
+                       int show_command) {
+  UNREFERENCED_PARAMETER(command_line);
+
+  sandbox::BrokerServices* broker_service =
+      sandbox::SandboxFactory::GetBrokerServices();
+  sandbox::ResultCode result;
+
+  // This application starts as the broker; an application with a UI that
+  // spawns an instance of itself (called a 'target') inside the sandbox.
+  // Before spawning a hidden instance of itself, the application will have
+  // asked the user which DLL the spawned instance should load and passes
+  // that as command line argument to the spawned instance.
+  //
+  // We check here to see if we can retrieve a pointer to the BrokerServices,
+  // which is not possible if we are running inside the sandbox under a
+  // restricted token so it also tells us which mode we are in. If we can
+  // retrieve the pointer, then we are the broker, otherwise we are the target
+  // that the broker launched.
+  if (NULL != broker_service) {
+    // Yes, we are the broker so we need to initialize and show the UI
+    if (0 != (result = broker_service->Init())) {
+      ::MessageBox(NULL, L"Failed to initialize the BrokerServices object",
+                   L"Error during initialization", MB_ICONERROR);
+      return 1;
+    }
+
+    wchar_t exe_name[MAX_PATH];
+    if (0 == GetModuleFileName(NULL, exe_name, MAX_PATH - 1)) {
+      ::MessageBox(NULL, L"Failed to get name of current EXE",
+                   L"Error during initialization", MB_ICONERROR);
+      return 1;
+    }
+
+    // The CreateMainWindowAndLoop() call will not return until the user closes
+    // the application window (or selects File\Exit).
+    MainUIWindow window;
+    window.CreateMainWindowAndLoop(instance,
+                                   exe_name,
+                                   show_command,
+                                   broker_service);
+
+
+    // Cannot exit until we have cleaned up after all the targets we have
+    // created
+    broker_service->WaitForAllTargets();
+  } else {
+    // This is an instance that has been spawned inside the sandbox by the
+    // broker, so we need to parse the command line to figure out which DLL to
+    // load and what entry point to call
+    sandbox::TargetServices* target_service
+        = sandbox::SandboxFactory::GetTargetServices();
+
+    if (NULL == target_service) {
+      // TODO(finnur): write the failure to the log file
+      // We cannot display messageboxes inside the sandbox unless access to
+      // the desktop handle has been granted to us, and we don't have a
+      // console window to write to. Therefore we need to have the broker
+      // grant us access to a handle to a logfile and write the error that
+      // occurred into the log before continuing
+      return -1;
+    }
+
+    // Debugging the spawned application can be tricky, because DebugBreak()
+    // and _asm int 3 cause the app to terminate (due to a flag in the job
+    // object), MessageBoxes() will not be displayed unless we have been granted
+    // that privilege and the target finishes its business so quickly we cannot
+    // attach to it quickly enough. Therefore, you can uncomment the
+    // following line and attach (w. msdev or windbg) as the target is sleeping
+
+    // Sleep(10000);
+
+    if (sandbox::SBOX_ALL_OK != (result = target_service->Init())) {
+      // TODO(finnur): write the initialization error to the log file
+      return -2;
+    }
+
+    // Parse the command line to find out what we need to call
+    std::string dll_name, entry_point;
+    base::string16 log_file;
+    if (!ParseCommandLine(GetCommandLineW(),
+                          &dll_name,
+                          &entry_point,
+                          &log_file)) {
+      // TODO(finnur): write the failure to the log file
+      return -3;
+    }
+
+    // Open the pipe to transfert the log output
+    HANDLE pipe = ::CreateFile(log_file.c_str(),
+                               GENERIC_WRITE,
+                               FILE_SHARE_READ | FILE_SHARE_WRITE,
+                               NULL,  // Default security attributes.
+                               CREATE_ALWAYS,
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL);  // No template
+
+    if (INVALID_HANDLE_VALUE == pipe) {
+      return -4;
+    }
+
+    // We now know what we should load, so load it
+    HMODULE dll_module = ::LoadLibraryA(dll_name.c_str());
+    if (dll_module == NULL) {
+      // TODO(finnur): write the failure to the log file
+      return -5;
+    }
+
+    // Initialization is finished, so we can enter lock-down mode
+    target_service->LowerToken();
+
+    lpfnInit init_function =
+        (lpfnInit) ::GetProcAddress(dll_module, entry_point.c_str());
+
+    if (!init_function) {
+      // TODO(finnur): write the failure to the log file
+      ::FreeLibrary(dll_module);
+      CloseHandle(pipe);
+      return -6;
+    }
+
+   // Transfer control to the entry point in the DLL requested
+    init_function(pipe);
+
+    CloseHandle(pipe);
+    Sleep(1000);  // Give a change to the debug output to arrive before the
+                  // end of the process
+
+    ::FreeLibrary(dll_module);
+  }
+
+  return 0;
+}
diff --git a/sandbox/win/sandbox_poc/sandbox.h b/sandbox/win/sandbox_poc/sandbox.h
new file mode 100644
index 0000000..65c09a1
--- /dev/null
+++ b/sandbox/win/sandbox_poc/sandbox.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SANDBOX_POC_SANDBOX_H__
+#define SANDBOX_SANDBOX_POC_SANDBOX_H__
+
+#include "sandbox/win/sandbox_poc/resource.h"
+
+#endif  // SANDBOX_SANDBOX_POC_SANDBOX_H__
diff --git a/sandbox/win/sandbox_poc/sandbox.ico b/sandbox/win/sandbox_poc/sandbox.ico
new file mode 100644
index 0000000..916fa12
--- /dev/null
+++ b/sandbox/win/sandbox_poc/sandbox.ico
Binary files differ
diff --git a/sandbox/win/sandbox_poc/sandbox.rc b/sandbox/win/sandbox_poc/sandbox.rc
new file mode 100644
index 0000000..978c96f
--- /dev/null
+++ b/sandbox/win/sandbox_poc/sandbox.rc
@@ -0,0 +1,136 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU_MAIN_UI MENU 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "E&xit",                       ID_FILE_EXIT
+    END
+    POPUP "&Commands"
+    BEGIN
+        MENUITEM "&Spawn target",               ID_COMMANDS_SPAWNTARGET
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_LAUNCH_DLL DIALOGEX 0, 0, 269, 118
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "BrokerUI: Load an Attack DLL"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "Call now",IDOK,212,70,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,212,95,50,14
+    EDITTEXT        IDC_DLL_NAME,7,43,200,13,ES_AUTOHSCROLL
+    LTEXT           "DLL to load in target:",IDC_STATIC,7,33,168,8
+    LTEXT           "Function to call:",IDC_STATIC,7,61,139,8
+    EDITTEXT        IDC_ENTRY_POINT,7,71,200,13,ES_AUTOHSCROLL
+    EDITTEXT        IDC_LOG_FILE,7,17,200,13,ES_AUTOHSCROLL
+    LTEXT           "File for Target logging (optional):",IDC_STATIC,7,7,139,8
+    PUSHBUTTON      "Browse...",IDC_BROWSE_DLL,212,42,50,14
+    PUSHBUTTON      "Browse...",IDC_BROWSE_LOG,212,16,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_LAUNCH_DLL, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 262
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 111
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SANDBOX             ICON                    "sandbox.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/sandbox/win/sandbox_poc/sandbox_poc.vcproj b/sandbox/win/sandbox_poc/sandbox_poc.vcproj
new file mode 100644
index 0000000..5fde1cd
--- /dev/null
+++ b/sandbox/win/sandbox_poc/sandbox_poc.vcproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sandbox_poc"
+	ProjectGUID="{CF757839-F2A1-417C-8F25-DCAE480020F1}"
+	RootNamespace="sandbox_poc"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="comctl32.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="comctl32.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\main_ui_window.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\main_ui_window.h"
+			>
+		</File>
+		<File
+			RelativePath=".\resource.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.ico"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.rc"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/sandbox_standalone.sln b/sandbox/win/sandbox_standalone.sln
new file mode 100644
index 0000000..529d20e
--- /dev/null
+++ b/sandbox/win/sandbox_standalone.sln
@@ -0,0 +1,127 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox", "src\sandbox.vcproj", "{881F6A97-D539-4C48-B401-DF04385B2343}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_unittests", "tests\unit_tests\sbox_unittests.vcproj", "{883553BE-2A9D-418C-A121-61FE1DFBC562}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_validation_tests", "tests\validation_tests\sbox_validation_tests.vcproj", "{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{BCE54389-D18D-48B9-977E-9D1998200F63}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debug_message", "..\base\debug_message.vcproj", "{F0F92189-193A-6607-C2BB-0F98BBD19ADF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{7F36EE20-5016-4051-B0D7-42824CDA0291}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "proof_of_concept", "proof_of_concept", "{B607BE7B-3555-422C-A40B-28E73C0B5E24}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_poc", "sandbox_poc\sandbox_poc.vcproj", "{CF757839-F2A1-417C-8F25-DCAE480020F1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224} = {AE5BFB87-850E-4454-B01D-58E7D8BAC224}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pocdll", "sandbox_poc\pocdll\pocdll.vcproj", "{AE5BFB87-850E-4454-B01D-58E7D8BAC224}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "finder", "tools\finder\finder.vcproj", "{ACDC2E06-0366-41A4-A646-C37E130A605D}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "tools\launcher\launcher.vcproj", "{386FA217-FBC2-4461-882D-CDAD221ED800}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_integration_tests", "tests\integration_tests\sbox_integration_tests.vcproj", "{542D4B3B-98D4-4233-B68D-0103891508C6}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "..\base\base.vcproj", "{1832A374-8A74-4F9E-B536-69A699B3E165}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\testing\gtest.vcproj", "{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Debug|Win32.ActiveCfg = Debug|Win32
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Debug|Win32.Build.0 = Debug|Win32
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Release|Win32.ActiveCfg = Release|Win32
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Release|Win32.Build.0 = Release|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Debug|Win32.ActiveCfg = Debug|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Debug|Win32.Build.0 = Debug|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Release|Win32.ActiveCfg = Release|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Release|Win32.Build.0 = Release|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Debug|Win32.Build.0 = Debug|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Release|Win32.ActiveCfg = Release|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Release|Win32.Build.0 = Release|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Debug|Win32.Build.0 = Debug|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Release|Win32.ActiveCfg = Release|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Release|Win32.Build.0 = Release|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Debug|Win32.Build.0 = Debug|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Release|Win32.ActiveCfg = Release|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Release|Win32.Build.0 = Release|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Debug|Win32.ActiveCfg = Debug|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Debug|Win32.Build.0 = Debug|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Release|Win32.ActiveCfg = Release|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Release|Win32.Build.0 = Release|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Debug|Win32.Build.0 = Debug|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Release|Win32.ActiveCfg = Release|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Release|Win32.Build.0 = Release|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Debug|Win32.ActiveCfg = Debug|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Debug|Win32.Build.0 = Debug|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Release|Win32.ActiveCfg = Release|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Release|Win32.Build.0 = Release|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Debug|Win32.Build.0 = Debug|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Release|Win32.ActiveCfg = Release|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Release|Win32.Build.0 = Release|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.Build.0 = Debug|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.ActiveCfg = Release|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.Build.0 = Release|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Debug|Win32.Build.0 = Debug|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Release|Win32.ActiveCfg = Release|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{883553BE-2A9D-418C-A121-61FE1DFBC562} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
+		{542D4B3B-98D4-4233-B68D-0103891508C6} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF} = {BCE54389-D18D-48B9-977E-9D1998200F63}
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {BCE54389-D18D-48B9-977E-9D1998200F63}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BCE54389-D18D-48B9-977E-9D1998200F63}
+		{ACDC2E06-0366-41A4-A646-C37E130A605D} = {7F36EE20-5016-4051-B0D7-42824CDA0291}
+		{386FA217-FBC2-4461-882D-CDAD221ED800} = {7F36EE20-5016-4051-B0D7-42824CDA0291}
+		{CF757839-F2A1-417C-8F25-DCAE480020F1} = {B607BE7B-3555-422C-A40B-28E73C0B5E24}
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224} = {B607BE7B-3555-422C-A40B-28E73C0B5E24}
+	EndGlobalSection
+EndGlobal
diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi
new file mode 100644
index 0000000..e085cfb
--- /dev/null
+++ b/sandbox/win/sandbox_win.gypi
@@ -0,0 +1,373 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'variables': {
+      'sandbox_windows_target': 0,
+      'target_arch%': 'ia32',
+    },
+    'target_conditions': [
+      ['sandbox_windows_target==1', {
+        # Files that are shared between the 32-bit and the 64-bit versions
+        # of the Windows sandbox library.
+        'sources': [
+            'src/acl.cc',
+            'src/acl.h',
+            'src/app_container.cc',
+            'src/app_container.h',
+            'src/broker_services.cc',
+            'src/broker_services.h',
+            'src/crosscall_client.h',
+            'src/crosscall_params.h',
+            'src/crosscall_server.cc',
+            'src/crosscall_server.h',
+            'src/eat_resolver.cc',
+            'src/eat_resolver.h',
+            'src/filesystem_dispatcher.cc',
+            'src/filesystem_dispatcher.h',
+            'src/filesystem_interception.cc',
+            'src/filesystem_interception.h',
+            'src/filesystem_policy.cc',
+            'src/filesystem_policy.h',
+            'src/handle_closer.cc',
+            'src/handle_closer.h',
+            'src/handle_closer_agent.cc',
+            'src/handle_closer_agent.h',
+            'src/handle_dispatcher.cc',
+            'src/handle_dispatcher.h',
+            'src/handle_interception.cc',
+            'src/handle_interception.h',
+            'src/handle_policy.cc',
+            'src/handle_policy.h',
+            'src/handle_table.cc',
+            'src/handle_table.h',
+            'src/interception.cc',
+            'src/interception.h',
+            'src/interception_agent.cc',
+            'src/interception_agent.h',
+            'src/interception_internal.h',
+            'src/interceptors.h',
+            'src/internal_types.h',
+            'src/ipc_tags.h',
+            'src/job.cc',
+            'src/job.h',
+            'src/named_pipe_dispatcher.cc',
+            'src/named_pipe_dispatcher.h',
+            'src/named_pipe_interception.cc',
+            'src/named_pipe_interception.h',
+            'src/named_pipe_policy.cc',
+            'src/named_pipe_policy.h',
+            'src/nt_internals.h',
+            'src/policy_broker.cc',
+            'src/policy_broker.h',
+            'src/policy_engine_opcodes.cc',
+            'src/policy_engine_opcodes.h',
+            'src/policy_engine_params.h',
+            'src/policy_engine_processor.cc',
+            'src/policy_engine_processor.h',
+            'src/policy_low_level.cc',
+            'src/policy_low_level.h',
+            'src/policy_params.h',
+            'src/policy_target.cc',
+            'src/policy_target.h',
+            'src/process_mitigations.cc',
+            'src/process_mitigations.h',
+            'src/process_mitigations_win32k_dispatcher.cc',
+            'src/process_mitigations_win32k_dispatcher.h',
+            'src/process_mitigations_win32k_interception.cc',
+            'src/process_mitigations_win32k_interception.h',
+            'src/process_mitigations_win32k_policy.cc',
+            'src/process_mitigations_win32k_policy.h',
+            'src/process_thread_dispatcher.cc',
+            'src/process_thread_dispatcher.h',
+            'src/process_thread_interception.cc',
+            'src/process_thread_interception.h',
+            'src/process_thread_policy.cc',
+            'src/process_thread_policy.h',
+            'src/registry_dispatcher.cc',
+            'src/registry_dispatcher.h',
+            'src/registry_interception.cc',
+            'src/registry_interception.h',
+            'src/registry_policy.cc',
+            'src/registry_policy.h',
+            'src/resolver.cc',
+            'src/resolver.h',
+            'src/restricted_token_utils.cc',
+            'src/restricted_token_utils.h',
+            'src/restricted_token.cc',
+            'src/restricted_token.h',
+            'src/sandbox_factory.h',
+            'src/sandbox_globals.cc',
+            'src/sandbox_nt_types.h',
+            'src/sandbox_nt_util.cc',
+            'src/sandbox_nt_util.h',
+            'src/sandbox_policy_base.cc',
+            'src/sandbox_policy_base.h',
+            'src/sandbox_policy.h',
+            'src/sandbox_types.h',
+            'src/sandbox_utils.cc',
+            'src/sandbox_utils.h',
+            'src/sandbox.cc',
+            'src/sandbox.h',
+            'src/security_level.h',
+            'src/service_resolver.cc',
+            'src/service_resolver.h',
+            'src/shared_handles.cc',
+            'src/shared_handles.h',
+            'src/sharedmem_ipc_client.cc',
+            'src/sharedmem_ipc_client.h',
+            'src/sharedmem_ipc_server.cc',
+            'src/sharedmem_ipc_server.h',
+            'src/sid.cc',
+            'src/sid.h',
+            'src/sync_dispatcher.cc',
+            'src/sync_dispatcher.h',
+            'src/sync_interception.cc',
+            'src/sync_interception.h',
+            'src/sync_policy.cc',
+            'src/sync_policy.h',
+            'src/target_interceptions.cc',
+            'src/target_interceptions.h',
+            'src/target_process.cc',
+            'src/target_process.h',
+            'src/target_services.cc',
+            'src/target_services.h',
+            'src/win_utils.cc',
+            'src/win_utils.h',
+            'src/win2k_threadpool.cc',
+            'src/win2k_threadpool.h',
+            'src/window.cc',
+            'src/window.h',
+        ],
+        'target_conditions': [
+          ['target_arch=="x64"', {
+            'sources': [
+              'src/interceptors_64.cc',
+              'src/interceptors_64.h',
+              'src/resolver_64.cc',
+              'src/service_resolver_64.cc',
+              'src/Wow64_64.cc',
+            ],
+          }],
+          ['target_arch=="ia32"', {
+            'sources': [
+              'src/resolver_32.cc',
+              'src/service_resolver_32.cc',
+              'src/sidestep_resolver.cc',
+              'src/sidestep_resolver.h',
+              'src/sidestep\ia32_modrm_map.cpp',
+              'src/sidestep\ia32_opcode_map.cpp',
+              'src/sidestep\mini_disassembler_types.h',
+              'src/sidestep\mini_disassembler.cpp',
+              'src/sidestep\mini_disassembler.h',
+              'src/sidestep\preamble_patcher_with_stub.cpp',
+              'src/sidestep\preamble_patcher.h',
+              'src/Wow64.cc',
+              'src/Wow64.h',
+            ],
+          }],
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'sandbox',
+      'type': 'static_library',
+      'variables': {
+        'sandbox_windows_target': 1,
+      },
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/base.gyp:base_static',
+      ],
+      'export_dependent_settings': [
+        '../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          'src',
+          '../..',
+        ],
+      },
+      'target_conditions': [
+        ['target_arch=="ia32"', {
+          'copies': [
+            {
+              'destination': '<(PRODUCT_DIR)',
+              'files': [
+                'wow_helper/wow_helper.exe',
+                'wow_helper/wow_helper.pdb',
+              ],
+            },
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'sbox_integration_tests',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'src/address_sanitizer_test.cc',
+        'src/app_container_test.cc',
+        'src/file_policy_test.cc',
+        'src/handle_inheritance_test.cc',
+        'src/handle_policy_test.cc',
+        'tests/integration_tests/integration_tests_test.cc',
+        'src/handle_closer_test.cc',
+        'src/integrity_level_test.cc',
+        'src/ipc_ping_test.cc',
+        'src/named_pipe_policy_test.cc',
+        'src/policy_target_test.cc',
+        'src/process_mitigations_test.cc',
+        'src/process_policy_test.cc',
+        'src/registry_policy_test.cc',
+        'src/sync_policy_test.cc',
+        'src/sync_policy_test.h',
+        'src/unload_dll_test.cc',
+        'tests/common/controller.cc',
+        'tests/common/controller.h',
+        'tests/common/test_utils.cc',
+        'tests/common/test_utils.h',
+        'tests/integration_tests/integration_tests.cc',
+      ],
+    },
+    {
+      'target_name': 'sbox_validation_tests',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'tests/common/controller.cc',
+        'tests/common/controller.h',
+        'tests/validation_tests/unit_tests.cc',
+        'tests/validation_tests/commands.cc',
+        'tests/validation_tests/commands.h',
+        'tests/validation_tests/suite.cc',
+      ],
+    },
+    {
+      'target_name': 'sbox_unittests',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'src/app_container_unittest.cc',
+        'src/interception_unittest.cc',
+        'src/service_resolver_unittest.cc',
+        'src/restricted_token_unittest.cc',
+        'src/job_unittest.cc',
+        'src/sid_unittest.cc',
+        'src/policy_engine_unittest.cc',
+        'src/policy_low_level_unittest.cc',
+        'src/policy_opcodes_unittest.cc',
+        'src/ipc_unittest.cc',
+        'src/threadpool_unittest.cc',
+        'src/win_utils_unittest.cc',
+        'tests/common/test_utils.cc',
+        'tests/common/test_utils.h',
+        'tests/unit_tests/unit_tests.cc',
+      ],
+    },
+    {
+      'target_name': 'sandbox_poc',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        'pocdll',
+      ],
+      'sources': [
+        'sandbox_poc/main_ui_window.cc',
+        'sandbox_poc/main_ui_window.h',
+        'sandbox_poc/resource.h',
+        'sandbox_poc/sandbox.cc',
+        'sandbox_poc/sandbox.h',
+        'sandbox_poc/sandbox.ico',
+        'sandbox_poc/sandbox.rc',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lcomctl32.lib',
+        ],
+      },
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+        },
+      },
+    },
+    {
+      'target_name': 'pocdll',
+      'type': 'shared_library',
+      'sources': [
+        'sandbox_poc/pocdll/exports.h',
+        'sandbox_poc/pocdll/fs.cc',
+        'sandbox_poc/pocdll/handles.cc',
+        'sandbox_poc/pocdll/invasive.cc',
+        'sandbox_poc/pocdll/network.cc',
+        'sandbox_poc/pocdll/pocdll.cc',
+        'sandbox_poc/pocdll/processes_and_threads.cc',
+        'sandbox_poc/pocdll/registry.cc',
+        'sandbox_poc/pocdll/spyware.cc',
+        'sandbox_poc/pocdll/utils.h',
+      ],
+      'defines': [
+        'POCDLL_EXPORTS',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'sandbox_win64',
+          'type': 'static_library',
+          'variables': {
+            'sandbox_windows_target': 1,
+            'target_arch': 'x64',
+          },
+          'dependencies': [
+            '../base/base.gyp:base_win64',
+            '../base/base.gyp:base_static_win64',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'include_dirs': [
+            '../..',
+          ],
+          'direct_dependent_settings': {
+            'include_dirs': [
+              'src',
+              '../..',
+            ],
+          },
+          'defines': [
+            '<@(nacl_win64_defines)',
+          ]
+        },
+      ],
+    }],
+  ],
+}
diff --git a/sandbox/win/src/Wow64.cc b/sandbox/win/src/Wow64.cc
new file mode 100644
index 0000000..60ee13d
--- /dev/null
+++ b/sandbox/win/src/Wow64.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 "sandbox/win/src/wow64.h"
+
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/target_process.h"
+
+namespace {
+
+// Holds the information needed for the interception of NtMapViewOfSection on
+// 64 bits.
+// Warning: do not modify this definition without changing also the code on the
+// 64 bit helper process.
+struct PatchInfo32 {
+  HANDLE dll_load;  // Event to signal the broker.
+  ULONG pad1;
+  HANDLE continue_load;  // Event to wait for the broker.
+  ULONG pad2;
+  HANDLE section;  // First argument of the call.
+  ULONG pad3;
+  void* orig_MapViewOfSection;
+  ULONG original_high;
+  void* signal_and_wait;
+  ULONG pad4;
+  void* patch_location;
+  ULONG patch_high;
+};
+
+// Size of the 64 bit service entry.
+const SIZE_T kServiceEntry64Size = 0x10;
+
+// Removes the interception of ntdll64.
+bool Restore64Code(HANDLE child, PatchInfo32* patch_info) {
+  PatchInfo32 local_patch_info;
+  SIZE_T actual;
+  if (!::ReadProcessMemory(child, patch_info, &local_patch_info,
+                           sizeof(local_patch_info), &actual))
+    return false;
+  if (sizeof(local_patch_info) != actual)
+    return false;
+
+  if (local_patch_info.original_high)
+    return false;
+  if (local_patch_info.patch_high)
+    return false;
+
+  char buffer[kServiceEntry64Size];
+
+  if (!::ReadProcessMemory(child, local_patch_info.orig_MapViewOfSection,
+                           &buffer, kServiceEntry64Size, &actual))
+    return false;
+  if (kServiceEntry64Size != actual)
+    return false;
+
+  if (!::WriteProcessMemory(child, local_patch_info.patch_location, &buffer,
+                            kServiceEntry64Size, &actual))
+    return false;
+  if (kServiceEntry64Size != actual)
+    return false;
+  return true;
+}
+
+typedef BOOL (WINAPI* IsWow64ProcessFunction)(HANDLE process, BOOL* wow64);
+
+}  // namespace
+
+namespace sandbox {
+
+Wow64::~Wow64() {
+  if (dll_load_)
+    ::CloseHandle(dll_load_);
+
+  if (continue_load_)
+    ::CloseHandle(continue_load_);
+}
+
+// The basic idea is to allocate one page of memory on the child, and initialize
+// the first part of it with our version of PatchInfo32. Then launch the helper
+// process passing it that address on the child. The helper process will patch
+// the 64 bit version of NtMapViewOfFile, and the interception will signal the
+// first event on the buffer. We'll be waiting on that event and after the 32
+// bit version of ntdll is loaded, we'll remove the interception and return to
+// our caller.
+bool Wow64::WaitForNtdll() {
+  if (base::win::OSInfo::GetInstance()->wow64_status() !=
+      base::win::OSInfo::WOW64_ENABLED)
+    return true;
+
+  const size_t page_size = 4096;
+
+  // Create some default manual reset un-named events, not signaled.
+  dll_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+  continue_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+  HANDLE current_process = ::GetCurrentProcess();
+  HANDLE remote_load, remote_continue;
+  DWORD access = EVENT_MODIFY_STATE | SYNCHRONIZE;
+  if (!::DuplicateHandle(current_process, dll_load_, child_->Process(),
+                         &remote_load, access, FALSE, 0))
+    return false;
+  if (!::DuplicateHandle(current_process, continue_load_, child_->Process(),
+                         &remote_continue, access, FALSE, 0))
+    return false;
+
+  void* buffer = ::VirtualAllocEx(child_->Process(), NULL, page_size,
+                                  MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+  DCHECK(buffer);
+  if (!buffer)
+    return false;
+
+  PatchInfo32* patch_info = reinterpret_cast<PatchInfo32*>(buffer);
+  PatchInfo32 local_patch_info = {0};
+  local_patch_info.dll_load = remote_load;
+  local_patch_info.continue_load = remote_continue;
+  SIZE_T written;
+  if (!::WriteProcessMemory(child_->Process(), patch_info, &local_patch_info,
+                            offsetof(PatchInfo32, section), &written))
+    return false;
+  if (offsetof(PatchInfo32, section) != written)
+    return false;
+
+  if (!RunWowHelper(buffer))
+    return false;
+
+  // The child is intercepted on 64 bit, go on and wait for our event.
+  if (!DllMapped())
+    return false;
+
+  // The 32 bit version is available, cleanup the child.
+  return Restore64Code(child_->Process(), patch_info);
+}
+
+bool Wow64::RunWowHelper(void* buffer) {
+  static_assert(sizeof(buffer) <= sizeof(DWORD), "unsupported 64 bits");
+
+  // Get the path to the helper (beside the exe).
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+  base::string16 path(prog_name);
+  size_t name_pos = path.find_last_of(L"\\");
+  if (base::string16::npos == name_pos)
+    return false;
+  path.resize(name_pos + 1);
+
+  std::basic_stringstream<base::char16> command;
+  command << std::hex << std::showbase << L"\"" << path <<
+               L"wow_helper.exe\" " << child_->ProcessId() << " " <<
+               bit_cast<ULONG>(buffer);
+
+  scoped_ptr<wchar_t, base::FreeDeleter>
+      writable_command(_wcsdup(command.str().c_str()));
+
+  STARTUPINFO startup_info = {0};
+  startup_info.cb = sizeof(startup_info);
+  PROCESS_INFORMATION temp_process_info = {};
+  if (!::CreateProcess(NULL, writable_command.get(), NULL, NULL, FALSE, 0, NULL,
+                       NULL, &startup_info, &temp_process_info))
+    return false;
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  DWORD reason = ::WaitForSingleObject(process_info.process_handle(), INFINITE);
+
+  DWORD code;
+  bool ok =
+      ::GetExitCodeProcess(process_info.process_handle(), &code) ? true : false;
+
+  if (WAIT_TIMEOUT == reason)
+    return false;
+
+  return ok && (0 == code);
+}
+
+// First we must wake up the child, then wait for dll loads on the child until
+// the one we care is loaded; at that point we must suspend the child again.
+bool Wow64::DllMapped() {
+  if (1 != ::ResumeThread(child_->MainThread())) {
+    NOTREACHED();
+    return false;
+  }
+
+  for (;;) {
+    DWORD reason = ::WaitForSingleObject(dll_load_, INFINITE);
+    if (WAIT_TIMEOUT == reason || WAIT_ABANDONED == reason)
+      return false;
+
+    if (!::ResetEvent(dll_load_))
+      return false;
+
+    bool found = NtdllPresent();
+    if (found) {
+      if (::SuspendThread(child_->MainThread()))
+        return false;
+    }
+
+    if (!::SetEvent(continue_load_))
+      return false;
+
+    if (found)
+      return true;
+  }
+}
+
+bool Wow64::NtdllPresent() {
+  const size_t kBufferSize = 512;
+  char buffer[kBufferSize];
+  SIZE_T read;
+  if (!::ReadProcessMemory(child_->Process(), ntdll_, &buffer, kBufferSize,
+                           &read))
+    return false;
+  if (kBufferSize != read)
+    return false;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/Wow64.h b/sandbox/win/src/Wow64.h
new file mode 100644
index 0000000..e9bbd53
--- /dev/null
+++ b/sandbox/win/src/Wow64.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_WOW64_H__
+#define SANDBOX_SRC_WOW64_H__
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+class TargetProcess;
+
+// This class wraps the code needed to interact with the Windows On Windows
+// subsystem on 64 bit OSes, from the point of view of interceptions.
+class Wow64 {
+ public:
+  Wow64(TargetProcess* child, HMODULE ntdll)
+      : child_(child), ntdll_(ntdll), dll_load_(NULL), continue_load_(NULL) {}
+  ~Wow64();
+
+  // Waits for the 32 bit DLL to get loaded on the child process. This function
+  // will return immediately if not running under WOW, or launch the helper
+  // process and wait until ntdll is ready.
+  bool WaitForNtdll();
+
+ private:
+  // Runs the WOW helper process, passing the address of a buffer allocated on
+  // the child (one page).
+  bool RunWowHelper(void* buffer);
+
+  // This method receives "notifications" whenever a DLL is mapped on the child.
+  bool DllMapped();
+
+  // Returns true if ntdll.dll is mapped on the child.
+  bool NtdllPresent();
+
+  TargetProcess* child_;  // Child process.
+  HMODULE ntdll_;         // ntdll on the parent.
+  HANDLE dll_load_;       // Event that is signaled on dll load.
+  HANDLE continue_load_;  // Event to signal to continue execution on the child.
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Wow64);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_WOW64_H__
diff --git a/sandbox/win/src/Wow64_64.cc b/sandbox/win/src/Wow64_64.cc
new file mode 100644
index 0000000..f03831b
--- /dev/null
+++ b/sandbox/win/src/Wow64_64.cc
@@ -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.
+
+// Wow64 implementation for native 64-bit Windows (in other words, never WOW).
+
+#include "sandbox/win/src/wow64.h"
+
+namespace sandbox {
+
+Wow64::~Wow64() {
+}
+
+bool Wow64::WaitForNtdll() {
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/acl.cc b/sandbox/win/src/acl.cc
new file mode 100644
index 0000000..f140c7e
--- /dev/null
+++ b/sandbox/win/src/acl.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 "sandbox/win/src/acl.h"
+
+#include <aclapi.h>
+#include <sddl.h>
+
+#include "base/logging.h"
+
+namespace sandbox {
+
+bool GetDefaultDacl(
+    HANDLE token,
+    scoped_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter>* default_dacl) {
+  if (token == NULL)
+    return false;
+
+  DCHECK(default_dacl != NULL);
+
+  unsigned long length = 0;
+  ::GetTokenInformation(token, TokenDefaultDacl, NULL, 0, &length);
+  if (length == 0) {
+    NOTREACHED();
+    return false;
+  }
+
+  TOKEN_DEFAULT_DACL* acl =
+      reinterpret_cast<TOKEN_DEFAULT_DACL*>(malloc(length));
+  default_dacl->reset(acl);
+
+  if (!::GetTokenInformation(token, TokenDefaultDacl, default_dacl->get(),
+                             length, &length))
+      return false;
+
+  return true;
+}
+
+bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MODE access_mode,
+                  ACCESS_MASK access, ACL** new_dacl) {
+  EXPLICIT_ACCESS new_access = {0};
+  new_access.grfAccessMode = access_mode;
+  new_access.grfAccessPermissions = access;
+  new_access.grfInheritance = NO_INHERITANCE;
+
+  new_access.Trustee.pMultipleTrustee = NULL;
+  new_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  new_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+  new_access.Trustee.ptstrName = reinterpret_cast<LPWSTR>(
+                                    const_cast<SID*>(sid.GetPSID()));
+
+  if (ERROR_SUCCESS != ::SetEntriesInAcl(1, &new_access, old_dacl, new_dacl))
+    return false;
+
+  return true;
+}
+
+bool AddSidToDefaultDacl(HANDLE token, const Sid& sid, ACCESS_MASK access) {
+  if (token == NULL)
+    return false;
+
+  scoped_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter> default_dacl;
+  if (!GetDefaultDacl(token, &default_dacl))
+    return false;
+
+  ACL* new_dacl = NULL;
+  if (!AddSidToDacl(sid, default_dacl->DefaultDacl, GRANT_ACCESS, access,
+                    &new_dacl))
+    return false;
+
+  TOKEN_DEFAULT_DACL new_token_dacl = {0};
+  new_token_dacl.DefaultDacl = new_dacl;
+
+  BOOL ret = ::SetTokenInformation(token, TokenDefaultDacl, &new_token_dacl,
+                                   sizeof(new_token_dacl));
+  ::LocalFree(new_dacl);
+  return (TRUE == ret);
+}
+
+bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access) {
+  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+  TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(malloc(size));
+
+  scoped_ptr<TOKEN_USER, base::FreeDeleter> token_user_ptr(token_user);
+
+  if (!::GetTokenInformation(token, TokenUser, token_user, size, &size))
+    return false;
+
+  return AddSidToDefaultDacl(token,
+                             reinterpret_cast<SID*>(token_user->User.Sid),
+                             access);
+}
+
+bool AddKnownSidToObject(HANDLE object, SE_OBJECT_TYPE object_type,
+                         const Sid& sid, ACCESS_MODE access_mode,
+                         ACCESS_MASK access) {
+  PSECURITY_DESCRIPTOR descriptor = NULL;
+  PACL old_dacl = NULL;
+  PACL new_dacl = NULL;
+
+  if (ERROR_SUCCESS != ::GetSecurityInfo(object, object_type,
+                                         DACL_SECURITY_INFORMATION, NULL, NULL,
+                                         &old_dacl, NULL, &descriptor))
+    return false;
+
+  if (!AddSidToDacl(sid.GetPSID(), old_dacl, access_mode, access, &new_dacl)) {
+    ::LocalFree(descriptor);
+    return false;
+  }
+
+  DWORD result = ::SetSecurityInfo(object, object_type,
+                                   DACL_SECURITY_INFORMATION, NULL, NULL,
+                                   new_dacl, NULL);
+
+  ::LocalFree(new_dacl);
+  ::LocalFree(descriptor);
+
+  if (ERROR_SUCCESS != result)
+    return false;
+
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/acl.h b/sandbox/win/src/acl.h
new file mode 100644
index 0000000..b5021e7
--- /dev/null
+++ b/sandbox/win/src/acl.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 SANDBOX_SRC_ACL_H_
+#define SANDBOX_SRC_ACL_H_
+
+#include <AccCtrl.h>
+#include <windows.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+// Returns the default dacl from the token passed in.
+bool GetDefaultDacl(
+    HANDLE token,
+    scoped_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter>* default_dacl);
+
+// Appends an ACE represented by |sid|, |access_mode|, and |access| to
+// |old_dacl|. If the function succeeds, new_dacl contains the new dacl and
+// must be freed using LocalFree.
+bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MODE access_mode,
+                  ACCESS_MASK access, ACL** new_dacl);
+
+// Adds and ACE represented by |sid| and |access| to the default dacl present
+// in the token.
+bool AddSidToDefaultDacl(HANDLE token, const Sid& sid, ACCESS_MASK access);
+
+// Adds an ACE represented by the user sid and |access| to the default dacl
+// present in the token.
+bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access);
+
+// Adds an ACE represented by |known_sid|, |access_mode|, and |access| to
+// the dacl of the kernel object referenced by |object| and of |object_type|.
+bool AddKnownSidToObject(HANDLE object, SE_OBJECT_TYPE object_type,
+                         const Sid& sid, ACCESS_MODE access_mode,
+                         ACCESS_MASK access);
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_ACL_H_
diff --git a/sandbox/win/src/address_sanitizer_test.cc b/sandbox/win/src/address_sanitizer_test.cc
new file mode 100644
index 0000000..b88aa81
--- /dev/null
+++ b/sandbox/win/src/address_sanitizer_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+class AddressSanitizerTests : public ::testing::Test {
+ public:
+  void SetUp() override {
+    env_.reset(base::Environment::Create());
+    had_asan_options_ = env_->GetVar("ASAN_OPTIONS", &old_asan_options_);
+  }
+
+  void TearDown() override {
+    if (had_asan_options_)
+      ASSERT_TRUE(env_->SetVar("ASAN_OPTIONS", old_asan_options_));
+    else
+      env_->UnSetVar("ASAN_OPTIONS");
+  }
+
+ protected:
+  scoped_ptr<base::Environment> env_;
+  bool had_asan_options_;
+  std::string old_asan_options_;
+};
+
+SBOX_TESTS_COMMAND int AddressSanitizerTests_Report(int argc, wchar_t** argv) {
+  // AddressSanitizer should detect an out of bounds write (heap buffer
+  // overflow) in this code.
+  volatile int idx = 42;
+  int *blah = new int[42];
+  blah[idx] = 42;
+  delete [] blah;
+  return SBOX_TEST_FAILED;
+}
+
+TEST_F(AddressSanitizerTests, TestAddressSanitizer) {
+  // This test is only supposed to work when using AddressSanitizer.
+  // However, ASan/Win is not on the CQ yet, so compiler breakages may get into
+  // the code unnoticed.  To avoid that, we compile this test in all Windows
+  // builds, but only run the AddressSanitizer-specific part of the test when
+  // compiled with AddressSanitizer.
+#if defined(ADDRESS_SANITIZER)
+  bool asan_build = true;
+#else
+  bool asan_build = false;
+#endif
+  base::ScopedTempDir temp_directory;
+  base::FilePath temp_file_name;
+  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+  ASSERT_TRUE(CreateTemporaryFileInDir(temp_directory.path(), &temp_file_name));
+
+  SECURITY_ATTRIBUTES attrs = {};
+  attrs.nLength = sizeof(attrs);
+  attrs.bInheritHandle = TRUE;
+  base::win::ScopedHandle tmp_handle(
+      CreateFile(temp_file_name.value().c_str(), GENERIC_WRITE,
+                 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+                 &attrs, OPEN_EXISTING, 0, NULL));
+  EXPECT_TRUE(tmp_handle.IsValid());
+
+  TestRunner runner;
+  ASSERT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetStderrHandle(tmp_handle.Get()));
+
+  base::FilePath exe;
+  ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe));
+  base::FilePath pdb_path = exe.DirName().Append(L"*.pdb");
+  ASSERT_TRUE(runner.AddFsRule(sandbox::TargetPolicy::FILES_ALLOW_READONLY,
+                               pdb_path.value().c_str()));
+
+  env_->SetVar("ASAN_OPTIONS", "exitcode=123");
+  if (asan_build) {
+    int result = runner.RunTest(L"AddressSanitizerTests_Report");
+    EXPECT_EQ(123, result);
+
+    std::string data;
+    ASSERT_TRUE(base::ReadFileToString(base::FilePath(temp_file_name), &data));
+    // Redirection uses a feature that was added in Windows Vista.
+    if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+      ASSERT_TRUE(
+          strstr(data.c_str(), "ERROR: AddressSanitizer: heap-buffer-overflow"))
+          << "There doesn't seem to be an ASan report:\n" << data;
+      ASSERT_TRUE(strstr(data.c_str(), "AddressSanitizerTests_Report"))
+          << "The ASan report doesn't appear to be symbolized:\n" << data;
+      ASSERT_TRUE(strstr(data.c_str(), strrchr(__FILE__, '\\')))
+          << "The stack trace doesn't have a correct filename:\n" << data;
+    } else {
+      LOG(WARNING) << "Pre-Vista versions are not supported.";
+    }
+  } else {
+    LOG(WARNING) << "Not an AddressSanitizer build, skipping the run.";
+  }
+}
+
+}
diff --git a/sandbox/win/src/app_container.cc b/sandbox/win/src/app_container.cc
new file mode 100644
index 0000000..f8d7541
--- /dev/null
+++ b/sandbox/win/src/app_container.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/app_container.h"
+
+#include <Sddl.h>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/startup_information.h"
+#include "sandbox/win/src/internal_types.h"
+
+namespace {
+
+// Converts the passed in sid string to a PSID that must be relased with
+// LocalFree.
+PSID ConvertSid(const base::string16& sid) {
+  PSID local_sid;
+  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
+    return NULL;
+  return local_sid;
+}
+
+template <typename T>
+T BindFunction(const char* name) {
+  HMODULE module = GetModuleHandle(sandbox::kKerneldllName);
+  void* function = GetProcAddress(module, name);
+  if (!function) {
+    module = GetModuleHandle(sandbox::kKernelBasedllName);
+    function = GetProcAddress(module, name);
+  }
+  return reinterpret_cast<T>(function);
+}
+
+}  // namespace
+
+namespace sandbox {
+
+AppContainerAttributes::AppContainerAttributes() {
+  memset(&capabilities_, 0, sizeof(capabilities_));
+}
+
+AppContainerAttributes::~AppContainerAttributes() {
+  for (size_t i = 0; i < attributes_.size(); i++)
+    LocalFree(attributes_[i].Sid);
+  LocalFree(capabilities_.AppContainerSid);
+}
+
+ResultCode AppContainerAttributes::SetAppContainer(
+    const base::string16& app_container_sid,
+    const std::vector<base::string16>& capabilities) {
+  DCHECK(!capabilities_.AppContainerSid);
+  DCHECK(attributes_.empty());
+  capabilities_.AppContainerSid = ConvertSid(app_container_sid);
+  if (!capabilities_.AppContainerSid)
+    return SBOX_ERROR_INVALID_APP_CONTAINER;
+
+  for (size_t i = 0; i < capabilities.size(); i++)  {
+    SID_AND_ATTRIBUTES sid_and_attributes;
+    sid_and_attributes.Sid = ConvertSid(capabilities[i]);
+    if (!sid_and_attributes.Sid)
+      return SBOX_ERROR_INVALID_CAPABILITY;
+
+    sid_and_attributes.Attributes = SE_GROUP_ENABLED;
+    attributes_.push_back(sid_and_attributes);
+  }
+
+  if (capabilities.size()) {
+    capabilities_.CapabilityCount = static_cast<DWORD>(capabilities.size());
+    capabilities_.Capabilities = &attributes_[0];
+  }
+  return SBOX_ALL_OK;
+}
+
+ResultCode AppContainerAttributes::ShareForStartup(
+      base::win::StartupInformation* startup_information) const {
+  // The only thing we support so far is an AppContainer.
+  if (!capabilities_.AppContainerSid)
+    return SBOX_ERROR_INVALID_APP_CONTAINER;
+
+  if (!startup_information->UpdateProcThreadAttribute(
+           PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
+           const_cast<SECURITY_CAPABILITIES*>(&capabilities_),
+           sizeof(capabilities_)))  {
+    DPLOG(ERROR) << "Failed UpdateProcThreadAttribute";
+    return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
+  }
+  return SBOX_ALL_OK;
+}
+
+bool AppContainerAttributes::HasAppContainer() const {
+  return (capabilities_.AppContainerSid != NULL);
+}
+
+ResultCode CreateAppContainer(const base::string16& sid,
+                              const base::string16& name) {
+  PSID local_sid;
+  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
+    return SBOX_ERROR_INVALID_APP_CONTAINER;
+
+  typedef HRESULT (WINAPI* AppContainerRegisterSidPtr)(PSID sid,
+                                                       LPCWSTR moniker,
+                                                       LPCWSTR display_name);
+  static AppContainerRegisterSidPtr AppContainerRegisterSid = NULL;
+
+  if (!AppContainerRegisterSid) {
+    AppContainerRegisterSid =
+        BindFunction<AppContainerRegisterSidPtr>("AppContainerRegisterSid");
+  }
+
+  ResultCode operation_result = SBOX_ERROR_GENERIC;
+  if (AppContainerRegisterSid) {
+    HRESULT rv = AppContainerRegisterSid(local_sid, name.c_str(), name.c_str());
+    if (SUCCEEDED(rv))
+      operation_result = SBOX_ALL_OK;
+    else
+      DLOG(ERROR) << "AppContainerRegisterSid error:" << std::hex << rv;
+  }
+  LocalFree(local_sid);
+  return operation_result;
+}
+
+ResultCode DeleteAppContainer(const base::string16& sid) {
+  PSID local_sid;
+  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
+    return SBOX_ERROR_INVALID_APP_CONTAINER;
+
+  typedef HRESULT (WINAPI* AppContainerUnregisterSidPtr)(PSID sid);
+  static AppContainerUnregisterSidPtr AppContainerUnregisterSid = NULL;
+
+  if (!AppContainerUnregisterSid) {
+    AppContainerUnregisterSid =
+        BindFunction<AppContainerUnregisterSidPtr>("AppContainerUnregisterSid");
+  }
+
+  ResultCode operation_result = SBOX_ERROR_GENERIC;
+  if (AppContainerUnregisterSid) {
+    HRESULT rv = AppContainerUnregisterSid(local_sid);
+    if (SUCCEEDED(rv))
+      operation_result = SBOX_ALL_OK;
+    else
+      DLOG(ERROR) << "AppContainerUnregisterSid error:" << std::hex << rv;
+  }
+  LocalFree(local_sid);
+  return operation_result;
+}
+
+base::string16 LookupAppContainer(const base::string16& sid) {
+  PSID local_sid;
+  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
+    return base::string16();
+
+  typedef HRESULT (WINAPI* AppContainerLookupMonikerPtr)(PSID sid,
+                                                         LPWSTR* moniker);
+  typedef BOOLEAN (WINAPI* AppContainerFreeMemoryPtr)(void* ptr);
+
+  static AppContainerLookupMonikerPtr AppContainerLookupMoniker = NULL;
+  static AppContainerFreeMemoryPtr AppContainerFreeMemory = NULL;
+
+  if (!AppContainerLookupMoniker || !AppContainerFreeMemory) {
+    AppContainerLookupMoniker =
+        BindFunction<AppContainerLookupMonikerPtr>("AppContainerLookupMoniker");
+    AppContainerFreeMemory =
+        BindFunction<AppContainerFreeMemoryPtr>("AppContainerFreeMemory");
+  }
+
+  if (!AppContainerLookupMoniker || !AppContainerFreeMemory)
+    return base::string16();
+
+  wchar_t* buffer = NULL;
+  HRESULT rv = AppContainerLookupMoniker(local_sid, &buffer);
+  if (FAILED(rv))
+    return base::string16();
+
+  base::string16 name(buffer);
+  if (!AppContainerFreeMemory(buffer))
+    NOTREACHED();
+  return name;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/app_container.h b/sandbox/win/src/app_container.h
new file mode 100644
index 0000000..8125d70
--- /dev/null
+++ b/sandbox/win/src/app_container.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_APP_CONTAINER_H_
+#define SANDBOX_WIN_SRC_APP_CONTAINER_H_
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace base {
+namespace win {
+class StartupInformation;
+}
+}
+
+namespace sandbox {
+
+// Maintains an attribute list to be used during creation of a new sandboxed
+// process.
+class AppContainerAttributes {
+ public:
+  AppContainerAttributes();
+  ~AppContainerAttributes();
+
+  // Sets the AppContainer and capabilities to be used with the new process.
+  ResultCode SetAppContainer(const base::string16& app_container_sid,
+                             const std::vector<base::string16>& capabilities);
+
+  // Updates the proc_thred attribute list of the provided startup_information
+  // with the app container related data.
+  // WARNING: startup_information just points back to our internal memory, so
+  // the lifetime of this object has to be greater than the lifetime of the
+  // provided startup_information.
+  ResultCode ShareForStartup(
+      base::win::StartupInformation* startup_information) const;
+
+  bool HasAppContainer() const;
+
+ private:
+  SECURITY_CAPABILITIES capabilities_;
+  std::vector<SID_AND_ATTRIBUTES> attributes_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppContainerAttributes);
+};
+
+// Creates a new AppContainer on the system. |sid| is the identifier of the new
+// AppContainer, and |name| will be used as both the display name and moniker.
+// This function fails if the OS doesn't support AppContainers, or if there is
+// an AppContainer registered with the same id.
+ResultCode CreateAppContainer(const base::string16& sid,
+                              const base::string16& name);
+
+// Deletes an AppContainer previously created with a successfull call to
+// CreateAppContainer.
+ResultCode DeleteAppContainer(const base::string16& sid);
+
+// Retrieves the name associated with the provided AppContainer sid. Returns an
+// empty string if the AppContainer is not registered with the system.
+base::string16 LookupAppContainer(const base::string16& sid);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_APP_CONTAINER_H_
diff --git a/sandbox/win/src/app_container_test.cc b/sandbox/win/src/app_container_test.cc
new file mode 100644
index 0000000..ced5cbd
--- /dev/null
+++ b/sandbox/win/src/app_container_test.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#define _ATL_NO_EXCEPTIONS
+#include <atlbase.h>
+#include <atlsecurity.h>
+
+#include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sync_policy_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const wchar_t kAppContainerName[] = L"sbox_test";
+const wchar_t kAppContainerSid[] =
+    L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
+    L"924012148-2839372144";
+
+const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+
+HANDLE CreateTaggedEvent(const base::string16& name,
+                         const base::string16& sid) {
+  base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, name.c_str()));
+  if (!event.IsValid())
+    return NULL;
+
+  wchar_t file_name[MAX_PATH] = {};
+  wchar_t temp_directory[MAX_PATH] = {};
+  GetTempPath(MAX_PATH, temp_directory);
+  GetTempFileName(temp_directory, L"test", 0, file_name);
+
+  base::win::ScopedHandle file;
+  file.Set(CreateFile(file_name, GENERIC_READ | STANDARD_RIGHTS_READ, kSharing,
+                      NULL, OPEN_EXISTING, 0, NULL));
+  DeleteFile(file_name);
+  if (!file.IsValid())
+    return NULL;
+
+  CSecurityDesc sd;
+  if (!AtlGetSecurityDescriptor(file.Get(), SE_FILE_OBJECT, &sd,
+                                OWNER_SECURITY_INFORMATION |
+                                    GROUP_SECURITY_INFORMATION |
+                                    DACL_SECURITY_INFORMATION)) {
+    return NULL;
+  }
+
+  PSID local_sid;
+  if (!ConvertStringSidToSid(sid.c_str(), &local_sid))
+    return NULL;
+
+  CDacl new_dacl;
+  sd.GetDacl(&new_dacl);
+  CSid csid(reinterpret_cast<SID*>(local_sid));
+  new_dacl.AddAllowedAce(csid, EVENT_ALL_ACCESS);
+  if (!AtlSetDacl(event.Get(), SE_KERNEL_OBJECT, new_dacl))
+    event.Close();
+
+  LocalFree(local_sid);
+  return event.IsValid() ? event.Take() : NULL;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+TEST(AppContainerTest, AllowOpenEvent) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_UNPROTECTED);
+
+  const wchar_t capability[] = L"S-1-15-3-12345678-87654321";
+  base::win::ScopedHandle handle(CreateTaggedEvent(L"test", capability));
+  ASSERT_TRUE(handle.IsValid());
+
+  EXPECT_EQ(SBOX_ALL_OK,
+            runner.broker()->InstallAppContainer(kAppContainerSid,
+                                                 kAppContainerName));
+  EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetCapability(capability));
+  EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetAppContainer(kAppContainerSid));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_Open f test"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_Open f test"));
+  EXPECT_EQ(SBOX_ALL_OK,
+            runner.broker()->UninstallAppContainer(kAppContainerSid));
+}
+
+TEST(AppContainerTest, DenyOpenEvent) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_UNPROTECTED);
+
+  const wchar_t capability[] = L"S-1-15-3-12345678-87654321";
+  base::win::ScopedHandle handle(CreateTaggedEvent(L"test", capability));
+  ASSERT_TRUE(handle.IsValid());
+
+  EXPECT_EQ(SBOX_ALL_OK,
+            runner.broker()->InstallAppContainer(kAppContainerSid,
+                                                 kAppContainerName));
+  EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetAppContainer(kAppContainerSid));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
+  EXPECT_EQ(SBOX_ALL_OK,
+            runner.broker()->UninstallAppContainer(kAppContainerSid));
+}
+
+TEST(AppContainerTest, NoImpersonation) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner(JOB_UNPROTECTED, USER_LIMITED, USER_LIMITED);
+  EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetAppContainer(kAppContainerSid));
+}
+
+TEST(AppContainerTest, WantsImpersonation) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_NON_ADMIN);
+  EXPECT_EQ(SBOX_ERROR_CANNOT_INIT_APPCONTAINER,
+            runner.GetPolicy()->SetAppContainer(kAppContainerSid));
+}
+
+TEST(AppContainerTest, RequiresImpersonation) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner(JOB_UNPROTECTED, USER_RESTRICTED, USER_RESTRICTED);
+  EXPECT_EQ(SBOX_ERROR_CANNOT_INIT_APPCONTAINER,
+            runner.GetPolicy()->SetAppContainer(kAppContainerSid));
+}
+
+TEST(AppContainerTest, DenyOpenEventForLowBox) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_UNPROTECTED);
+
+  base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, L"test"));
+  ASSERT_TRUE(event.IsValid());
+
+  EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetLowBox(kAppContainerSid));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
+}
+
+// TODO(shrikant): Please add some tests to prove usage of lowbox token like
+// socket connection to local server in lock down mode.
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/app_container_unittest.cc b/sandbox/win/src/app_container_unittest.cc
new file mode 100644
index 0000000..4bce16a
--- /dev/null
+++ b/sandbox/win/src/app_container_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Tests the low level AppContainer interface.
+TEST(AppContainerTest, CreateAppContainer) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  const wchar_t kName[] = L"Test";
+  const wchar_t kValidSid[] = L"S-1-15-2-12345-234-567-890-123-456-789";
+
+  EXPECT_TRUE(LookupAppContainer(kValidSid).empty());
+  EXPECT_EQ(SBOX_ERROR_GENERIC, DeleteAppContainer(kValidSid));
+
+  EXPECT_EQ(SBOX_ALL_OK, CreateAppContainer(kValidSid, kName));
+  EXPECT_EQ(SBOX_ERROR_GENERIC, CreateAppContainer(kValidSid, kName));
+  EXPECT_EQ(kName, LookupAppContainer(kValidSid));
+  EXPECT_EQ(SBOX_ALL_OK, DeleteAppContainer(kValidSid));
+
+  EXPECT_TRUE(LookupAppContainer(kValidSid).empty());
+  EXPECT_EQ(SBOX_ERROR_GENERIC, DeleteAppContainer(kValidSid));
+
+  EXPECT_EQ(SBOX_ERROR_INVALID_APP_CONTAINER,
+            CreateAppContainer(L"Foo", kName));
+}
+
+// Tests handling of security capabilities on the attribute list.
+TEST(AppContainerTest, SecurityCapabilities) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return;
+
+  scoped_ptr<AppContainerAttributes> attributes(new AppContainerAttributes);
+  std::vector<base::string16> capabilities;
+  EXPECT_EQ(SBOX_ERROR_INVALID_APP_CONTAINER,
+            attributes->SetAppContainer(L"S-1-foo", capabilities));
+
+  EXPECT_EQ(SBOX_ALL_OK,
+            attributes->SetAppContainer(L"S-1-15-2-12345-234", capabilities));
+  EXPECT_TRUE(attributes->HasAppContainer());
+
+  attributes.reset(new AppContainerAttributes);
+  capabilities.push_back(L"S-1-15-3-12345678-87654321");
+  capabilities.push_back(L"S-1-15-3-1");
+  capabilities.push_back(L"S-1-15-3-2");
+  capabilities.push_back(L"S-1-15-3-3");
+  EXPECT_EQ(SBOX_ALL_OK,
+            attributes->SetAppContainer(L"S-1-15-2-1-2", capabilities));
+  EXPECT_TRUE(attributes->HasAppContainer());
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
new file mode 100644
index 0000000..905c5fd
--- /dev/null
+++ b/sandbox/win/src/broker_services.cc
@@ -0,0 +1,616 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/broker_services.h"
+
+#include <AclAPI.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/win2k_threadpool.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// Utility function to associate a completion port to a job object.
+bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) {
+  JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = { key, port };
+  return ::SetInformationJobObject(job,
+                                   JobObjectAssociateCompletionPortInformation,
+                                   &job_acp, sizeof(job_acp))? true : false;
+}
+
+// Utility function to do the cleanup necessary when something goes wrong
+// while in SpawnTarget and we must terminate the target process.
+sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target, DWORD error) {
+  if (0 == error)
+    error = ::GetLastError();
+
+  target->Terminate();
+  delete target;
+  ::SetLastError(error);
+  return sandbox::SBOX_ERROR_GENERIC;
+}
+
+// the different commands that you can send to the worker thread that
+// executes TargetEventsThread().
+enum {
+  THREAD_CTRL_NONE,
+  THREAD_CTRL_REMOVE_PEER,
+  THREAD_CTRL_QUIT,
+  THREAD_CTRL_LAST,
+};
+
+// Helper structure that allows the Broker to associate a job notification
+// with a job object and with a policy.
+struct JobTracker {
+  HANDLE job;
+  sandbox::PolicyBase* policy;
+  JobTracker(HANDLE cjob, sandbox::PolicyBase* cpolicy)
+      : job(cjob), policy(cpolicy) {
+  }
+};
+
+// Helper structure that allows the broker to track peer processes
+struct PeerTracker {
+  HANDLE wait_object;
+  base::win::ScopedHandle process;
+  DWORD id;
+  HANDLE job_port;
+  PeerTracker(DWORD process_id, HANDLE broker_job_port)
+      : wait_object(NULL), id(process_id), job_port(broker_job_port) {
+  }
+};
+
+void DeregisterPeerTracker(PeerTracker* peer) {
+  // Deregistration shouldn't fail, but we leak rather than crash if it does.
+  if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) {
+    delete peer;
+  } else {
+    NOTREACHED();
+  }
+}
+
+// Utility function to determine whether a token for the specified policy can
+// be cached.
+bool IsTokenCacheable(const sandbox::PolicyBase* policy) {
+  const sandbox::AppContainerAttributes* app_container =
+      policy->GetAppContainer();
+
+  // We cannot cache tokens with an app container or lowbox.
+  if (app_container || policy->GetLowBoxSid())
+    return false;
+
+  return true;
+}
+
+// Utility function to pack token values into a key for the cache map.
+uint32_t GenerateTokenCacheKey(const sandbox::PolicyBase* policy) {
+  const size_t kTokenShift = 3;
+  uint32_t key;
+
+  DCHECK(IsTokenCacheable(policy));
+
+  // Make sure our token values aren't too large to pack into the key.
+  static_assert(sandbox::USER_LAST <= (1 << kTokenShift),
+                "TokenLevel too large");
+  static_assert(sandbox::INTEGRITY_LEVEL_LAST <= (1 << kTokenShift),
+                "IntegrityLevel too large");
+  static_assert(sizeof(key) < (kTokenShift * 3),
+                "Token key type too small");
+
+  // The key is the enum values shifted to avoid overlap and OR'd together.
+  key = policy->GetInitialTokenLevel();
+  key <<= kTokenShift;
+  key |= policy->GetLockdownTokenLevel();
+  key <<= kTokenShift;
+  key |= policy->GetIntegrityLevel();
+
+  return key;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+BrokerServicesBase::BrokerServicesBase()
+    : thread_pool_(NULL), job_port_(NULL), no_targets_(NULL),
+      job_thread_(NULL) {
+}
+
+// The broker uses a dedicated worker thread that services the job completion
+// port to perform policy notifications and associated cleanup tasks.
+ResultCode BrokerServicesBase::Init() {
+  if ((NULL != job_port_) || (NULL != thread_pool_))
+    return SBOX_ERROR_UNEXPECTED_CALL;
+
+  ::InitializeCriticalSection(&lock_);
+
+  job_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+  if (NULL == job_port_)
+    return SBOX_ERROR_GENERIC;
+
+  no_targets_ = ::CreateEventW(NULL, TRUE, FALSE, NULL);
+
+  job_thread_ = ::CreateThread(NULL, 0,  // Default security and stack.
+                               TargetEventsThread, this, NULL, NULL);
+  if (NULL == job_thread_)
+    return SBOX_ERROR_GENERIC;
+
+  return SBOX_ALL_OK;
+}
+
+// The destructor should only be called when the Broker process is terminating.
+// Since BrokerServicesBase is a singleton, this is called from the CRT
+// termination handlers, if this code lives on a DLL it is called during
+// DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot
+// wait for threads here.
+BrokerServicesBase::~BrokerServicesBase() {
+  // If there is no port Init() was never called successfully.
+  if (!job_port_)
+    return;
+
+  // Closing the port causes, that no more Job notifications are delivered to
+  // the worker thread and also causes the thread to exit. This is what we
+  // want to do since we are going to close all outstanding Jobs and notifying
+  // the policy objects ourselves.
+  ::PostQueuedCompletionStatus(job_port_, 0, THREAD_CTRL_QUIT, FALSE);
+  ::CloseHandle(job_port_);
+
+  if (WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_, 1000)) {
+    // Cannot clean broker services.
+    NOTREACHED();
+    return;
+  }
+
+  JobTrackerList::iterator it;
+  for (it = tracker_list_.begin(); it != tracker_list_.end(); ++it) {
+    JobTracker* tracker = (*it);
+    FreeResources(tracker);
+    delete tracker;
+  }
+  ::CloseHandle(job_thread_);
+  delete thread_pool_;
+  ::CloseHandle(no_targets_);
+
+  // Cancel the wait events and delete remaining peer trackers.
+  for (PeerTrackerMap::iterator it = peer_map_.begin();
+       it != peer_map_.end(); ++it) {
+    DeregisterPeerTracker(it->second);
+  }
+
+  // If job_port_ isn't NULL, assumes that the lock has been initialized.
+  if (job_port_)
+    ::DeleteCriticalSection(&lock_);
+
+  // Close any token in the cache.
+  for (TokenCacheMap::iterator it = token_cache_.begin();
+       it != token_cache_.end(); ++it) {
+    ::CloseHandle(it->second.first);
+    ::CloseHandle(it->second.second);
+  }
+}
+
+TargetPolicy* BrokerServicesBase::CreatePolicy() {
+  // If you change the type of the object being created here you must also
+  // change the downcast to it in SpawnTarget().
+  return new PolicyBase;
+}
+
+void BrokerServicesBase::FreeResources(JobTracker* tracker) {
+  if (NULL != tracker->policy) {
+    BOOL res = ::TerminateJobObject(tracker->job, SBOX_ALL_OK);
+    DCHECK(res);
+    // Closing the job causes the target process to be destroyed so this
+    // needs to happen before calling OnJobEmpty().
+    res = ::CloseHandle(tracker->job);
+    DCHECK(res);
+    // In OnJobEmpty() we don't actually use the job handle directly.
+    tracker->policy->OnJobEmpty(tracker->job);
+    tracker->policy->Release();
+    tracker->policy = NULL;
+  }
+}
+
+// The worker thread stays in a loop waiting for asynchronous notifications
+// from the job objects. Right now we only care about knowing when the last
+// process on a job terminates, but in general this is the place to tell
+// the policy about events.
+DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
+  if (NULL == param)
+    return 1;
+
+  base::PlatformThread::SetName("BrokerEvent");
+
+  BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param);
+  HANDLE port = broker->job_port_;
+  HANDLE no_targets = broker->no_targets_;
+
+  int target_counter = 0;
+  ::ResetEvent(no_targets);
+
+  while (true) {
+    DWORD events = 0;
+    ULONG_PTR key = 0;
+    LPOVERLAPPED ovl = NULL;
+
+    if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE))
+      // this call fails if the port has been closed before we have a
+      // chance to service the last packet which is 'exit' anyway so
+      // this is not an error.
+      return 1;
+
+    if (key > THREAD_CTRL_LAST) {
+      // The notification comes from a job object. There are nine notifications
+      // that jobs can send and some of them depend on the job attributes set.
+      JobTracker* tracker = reinterpret_cast<JobTracker*>(key);
+
+      switch (events) {
+        case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: {
+          // The job object has signaled that the last process associated
+          // with it has terminated. Assuming there is no way for a process
+          // to appear out of thin air in this job, it safe to assume that
+          // we can tell the policy to destroy the target object, and for
+          // us to release our reference to the policy object.
+          FreeResources(tracker);
+          break;
+        }
+
+        case JOB_OBJECT_MSG_NEW_PROCESS: {
+          ++target_counter;
+          if (1 == target_counter) {
+            ::ResetEvent(no_targets);
+          }
+          break;
+        }
+
+        case JOB_OBJECT_MSG_EXIT_PROCESS:
+        case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
+          {
+            AutoLock lock(&broker->lock_);
+            broker->child_process_ids_.erase(
+                static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
+          }
+          --target_counter;
+          if (0 == target_counter)
+            ::SetEvent(no_targets);
+
+          DCHECK(target_counter >= 0);
+          break;
+        }
+
+        case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: {
+          break;
+        }
+
+        case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
+          BOOL res = ::TerminateJobObject(tracker->job,
+                                          SBOX_FATAL_MEMORY_EXCEEDED);
+          DCHECK(res);
+          break;
+        }
+
+        default: {
+          NOTREACHED();
+          break;
+        }
+      }
+    } else if (THREAD_CTRL_REMOVE_PEER == key) {
+      // Remove a process from our list of peers.
+      AutoLock lock(&broker->lock_);
+      PeerTrackerMap::iterator it = broker->peer_map_.find(
+          static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
+      DeregisterPeerTracker(it->second);
+      broker->peer_map_.erase(it);
+    } else if (THREAD_CTRL_QUIT == key) {
+      // The broker object is being destroyed so the thread needs to exit.
+      return 0;
+    } else {
+      // We have not implemented more commands.
+      NOTREACHED();
+    }
+  }
+
+  NOTREACHED();
+  return 0;
+}
+
+// SpawnTarget does all the interesting sandbox setup and creates the target
+// process inside the sandbox.
+ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
+                                           const wchar_t* command_line,
+                                           TargetPolicy* policy,
+                                           PROCESS_INFORMATION* target_info) {
+  if (!exe_path)
+    return SBOX_ERROR_BAD_PARAMS;
+
+  if (!policy)
+    return SBOX_ERROR_BAD_PARAMS;
+
+  // Even though the resources touched by SpawnTarget can be accessed in
+  // multiple threads, the method itself cannot be called from more than
+  // 1 thread. This is to protect the global variables used while setting up
+  // the child process.
+  static DWORD thread_id = ::GetCurrentThreadId();
+  DCHECK(thread_id == ::GetCurrentThreadId());
+
+  AutoLock lock(&lock_);
+
+  // This downcast is safe as long as we control CreatePolicy()
+  PolicyBase* policy_base = static_cast<PolicyBase*>(policy);
+
+  if (policy_base->GetAppContainer() && policy_base->GetLowBoxSid())
+    return SBOX_ERROR_BAD_PARAMS;
+
+  // Construct the tokens and the job object that we are going to associate
+  // with the soon to be created target process.
+  HANDLE initial_token_temp;
+  HANDLE lockdown_token_temp;
+  ResultCode result = SBOX_ALL_OK;
+
+  if (IsTokenCacheable(policy_base)) {
+    // Create the master tokens only once and save them in a cache. That way
+    // can just duplicate them to avoid hammering LSASS on every sandboxed
+    // process launch.
+    uint32_t token_key = GenerateTokenCacheKey(policy_base);
+    TokenCacheMap::iterator it = token_cache_.find(token_key);
+    if (it != token_cache_.end()) {
+      initial_token_temp = it->second.first;
+      lockdown_token_temp = it->second.second;
+    } else {
+      result =
+          policy_base->MakeTokens(&initial_token_temp, &lockdown_token_temp);
+      if (SBOX_ALL_OK != result)
+        return result;
+      token_cache_[token_key] =
+          std::pair<HANDLE, HANDLE>(initial_token_temp, lockdown_token_temp);
+    }
+
+    if (!::DuplicateToken(initial_token_temp, SecurityImpersonation,
+                          &initial_token_temp)) {
+      return SBOX_ERROR_GENERIC;
+    }
+
+    if (!::DuplicateTokenEx(lockdown_token_temp, TOKEN_ALL_ACCESS, 0,
+                            SecurityIdentification, TokenPrimary,
+                            &lockdown_token_temp)) {
+      return SBOX_ERROR_GENERIC;
+    }
+  } else {
+    result = policy_base->MakeTokens(&initial_token_temp, &lockdown_token_temp);
+    if (SBOX_ALL_OK != result)
+      return result;
+  }
+
+  base::win::ScopedHandle initial_token(initial_token_temp);
+  base::win::ScopedHandle lockdown_token(lockdown_token_temp);
+
+  HANDLE job_temp;
+  result = policy_base->MakeJobObject(&job_temp);
+  if (SBOX_ALL_OK != result)
+    return result;
+
+  base::win::ScopedHandle job(job_temp);
+
+  // Initialize the startup information from the policy.
+  base::win::StartupInformation startup_info;
+  // The liftime of |mitigations| and |inherit_handle_list| have to be at least
+  // as long as |startup_info| because |UpdateProcThreadAttribute| requires that
+  // its |lpValue| parameter persist until |DeleteProcThreadAttributeList| is
+  // called; StartupInformation's destructor makes such a call.
+  DWORD64 mitigations;
+  HANDLE inherit_handle_list[2];
+  base::string16 desktop = policy_base->GetAlternateDesktop();
+  if (!desktop.empty()) {
+    startup_info.startup_info()->lpDesktop =
+        const_cast<wchar_t*>(desktop.c_str());
+  }
+
+  bool inherit_handles = false;
+
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+    int attribute_count = 0;
+    const AppContainerAttributes* app_container =
+        policy_base->GetAppContainer();
+    if (app_container)
+      ++attribute_count;
+
+    size_t mitigations_size;
+    ConvertProcessMitigationsToPolicy(policy->GetProcessMitigations(),
+                                      &mitigations, &mitigations_size);
+    if (mitigations)
+      ++attribute_count;
+
+    HANDLE stdout_handle = policy_base->GetStdoutHandle();
+    HANDLE stderr_handle = policy_base->GetStderrHandle();
+    int inherit_handle_count = 0;
+    if (stdout_handle != INVALID_HANDLE_VALUE)
+      inherit_handle_list[inherit_handle_count++] = stdout_handle;
+    // Handles in the list must be unique.
+    if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE)
+      inherit_handle_list[inherit_handle_count++] = stderr_handle;
+
+    HandleList handle_list = policy_base->GetHandlesBeingShared();
+    for (auto handle : handle_list)
+      inherit_handle_list[inherit_handle_count++] = handle;
+
+    if (inherit_handle_count)
+      ++attribute_count;
+
+    if (!startup_info.InitializeProcThreadAttributeList(attribute_count))
+      return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+
+    if (app_container) {
+      result = app_container->ShareForStartup(&startup_info);
+      if (SBOX_ALL_OK != result)
+        return result;
+    }
+
+    if (mitigations) {
+      if (!startup_info.UpdateProcThreadAttribute(
+               PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations,
+               mitigations_size)) {
+        return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+      }
+    }
+
+    if (inherit_handle_count) {
+      if (!startup_info.UpdateProcThreadAttribute(
+              PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+              inherit_handle_list,
+              sizeof(inherit_handle_list[0]) * inherit_handle_count)) {
+        return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+      }
+      startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
+      startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
+      startup_info.startup_info()->hStdOutput = stdout_handle;
+      startup_info.startup_info()->hStdError = stderr_handle;
+      // Allowing inheritance of handles is only secure now that we
+      // have limited which handles will be inherited.
+      inherit_handles = true;
+    }
+  }
+
+  // Construct the thread pool here in case it is expensive.
+  // The thread pool is shared by all the targets
+  if (NULL == thread_pool_)
+    thread_pool_ = new Win2kThreadPool();
+
+  // Create the TargetProces object and spawn the target suspended. Note that
+  // Brokerservices does not own the target object. It is owned by the Policy.
+  base::win::ScopedProcessInformation process_info;
+  TargetProcess* target = new TargetProcess(initial_token.Take(),
+                                            lockdown_token.Take(),
+                                            job.Get(),
+                                            thread_pool_);
+
+  DWORD win_result = target->Create(exe_path, command_line, inherit_handles,
+                                    policy_base->GetLowBoxSid() ? true : false,
+                                    startup_info, &process_info);
+
+  policy_base->ClearSharedHandles();
+
+  if (ERROR_SUCCESS != win_result) {
+    SpawnCleanup(target, win_result);
+    return SBOX_ERROR_CREATE_PROCESS;
+  }
+
+  // Now the policy is the owner of the target.
+  if (!policy_base->AddTarget(target)) {
+    return SpawnCleanup(target, 0);
+  }
+
+  // We are going to keep a pointer to the policy because we'll call it when
+  // the job object generates notifications using the completion port.
+  policy_base->AddRef();
+  if (job.IsValid()) {
+    scoped_ptr<JobTracker> tracker(new JobTracker(job.Take(), policy_base));
+    if (!AssociateCompletionPort(tracker->job, job_port_, tracker.get()))
+      return SpawnCleanup(target, 0);
+    // Save the tracker because in cleanup we might need to force closing
+    // the Jobs.
+    tracker_list_.push_back(tracker.release());
+    child_process_ids_.insert(process_info.process_id());
+  } else {
+    // We have to signal the event once here because the completion port will
+    // never get a message that this target is being terminated thus we should
+    // not block WaitForAllTargets until we have at least one target with job.
+    if (child_process_ids_.empty())
+      ::SetEvent(no_targets_);
+    // We can not track the life time of such processes and it is responsibility
+    // of the host application to make sure that spawned targets without jobs
+    // are terminated when the main application don't need them anymore.
+  }
+
+  *target_info = process_info.Take();
+  return SBOX_ALL_OK;
+}
+
+
+ResultCode BrokerServicesBase::WaitForAllTargets() {
+  ::WaitForSingleObject(no_targets_, INFINITE);
+  return SBOX_ALL_OK;
+}
+
+bool BrokerServicesBase::IsActiveTarget(DWORD process_id) {
+  AutoLock lock(&lock_);
+  return child_process_ids_.find(process_id) != child_process_ids_.end() ||
+         peer_map_.find(process_id) != peer_map_.end();
+}
+
+VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) {
+  PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter);
+  // Don't check the return code because we this may fail (safely) at shutdown.
+  ::PostQueuedCompletionStatus(
+      peer->job_port, 0, THREAD_CTRL_REMOVE_PEER,
+      reinterpret_cast<LPOVERLAPPED>(static_cast<uintptr_t>(peer->id)));
+}
+
+ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
+  scoped_ptr<PeerTracker> peer(new PeerTracker(::GetProcessId(peer_process),
+                                               job_port_));
+  if (!peer->id)
+    return SBOX_ERROR_GENERIC;
+
+  HANDLE process_handle;
+  if (!::DuplicateHandle(::GetCurrentProcess(), peer_process,
+                         ::GetCurrentProcess(), &process_handle,
+                         SYNCHRONIZE, FALSE, 0)) {
+    return SBOX_ERROR_GENERIC;
+  }
+  peer->process.Set(process_handle);
+
+  AutoLock lock(&lock_);
+  if (!peer_map_.insert(std::make_pair(peer->id, peer.get())).second)
+    return SBOX_ERROR_BAD_PARAMS;
+
+  if (!::RegisterWaitForSingleObject(
+          &peer->wait_object, peer->process.Get(), RemovePeer, peer.get(),
+          INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD)) {
+    peer_map_.erase(peer->id);
+    return SBOX_ERROR_GENERIC;
+  }
+
+  // Release the pointer since it will be cleaned up by the callback.
+  peer.release();
+  return SBOX_ALL_OK;
+}
+
+ResultCode BrokerServicesBase::InstallAppContainer(const wchar_t* sid,
+                                                   const wchar_t* name) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return SBOX_ERROR_UNSUPPORTED;
+
+  base::string16 old_name = LookupAppContainer(sid);
+  if (old_name.empty())
+    return CreateAppContainer(sid, name);
+
+  if (old_name != name)
+    return SBOX_ERROR_INVALID_APP_CONTAINER;
+
+  return SBOX_ALL_OK;
+}
+
+ResultCode BrokerServicesBase::UninstallAppContainer(const wchar_t* sid) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return SBOX_ERROR_UNSUPPORTED;
+
+  base::string16 name = LookupAppContainer(sid);
+  if (name.empty())
+    return SBOX_ERROR_INVALID_APP_CONTAINER;
+
+  return DeleteAppContainer(sid);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/broker_services.h b/sandbox/win/src/broker_services.h
new file mode 100644
index 0000000..3e7a179
--- /dev/null
+++ b/sandbox/win/src/broker_services.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_BROKER_SERVICES_H_
+#define SANDBOX_WIN_SRC_BROKER_SERVICES_H_
+
+#include <list>
+#include <map>
+#include <set>
+#include <utility>
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "sandbox/win/src/win2k_threadpool.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+struct JobTracker;
+struct PeerTracker;
+
+}  // namespace
+
+namespace sandbox {
+
+class PolicyBase;
+
+// BrokerServicesBase ---------------------------------------------------------
+// Broker implementation version 0
+//
+// This is an implementation of the interface BrokerServices and
+// of the associated TargetProcess interface. In this implementation
+// TargetProcess is a friend of BrokerServices where the later manages a
+// collection of the former.
+class BrokerServicesBase final : public BrokerServices,
+                                 public SingletonBase<BrokerServicesBase> {
+ public:
+  BrokerServicesBase();
+
+  ~BrokerServicesBase();
+
+  // BrokerServices interface.
+  ResultCode Init() override;
+  TargetPolicy* CreatePolicy() override;
+  ResultCode SpawnTarget(const wchar_t* exe_path,
+                         const wchar_t* command_line,
+                         TargetPolicy* policy,
+                         PROCESS_INFORMATION* target) override;
+  ResultCode WaitForAllTargets() override;
+  ResultCode AddTargetPeer(HANDLE peer_process) override;
+  ResultCode InstallAppContainer(const wchar_t* sid,
+                                 const wchar_t* name) override;
+  ResultCode UninstallAppContainer(const wchar_t* sid) override;
+
+  // Checks if the supplied process ID matches one of the broker's active
+  // target processes
+  // Returns:
+  //   true if there is an active target process for this ID, otherwise false.
+  bool IsActiveTarget(DWORD process_id);
+
+ private:
+  // Releases the Job and notifies the associated Policy object to its
+  // resources as well.
+  static void FreeResources(JobTracker* tracker);
+
+  // The routine that the worker thread executes. It is in charge of
+  // notifications and cleanup-related tasks.
+  static DWORD WINAPI TargetEventsThread(PVOID param);
+
+  // Removes a target peer from the process list if it expires.
+  static VOID CALLBACK RemovePeer(PVOID parameter, BOOLEAN timeout);
+
+  // The completion port used by the job objects to communicate events to
+  // the worker thread.
+  HANDLE job_port_;
+
+  // Handle to a manual-reset event that is signaled when the total target
+  // process count reaches zero.
+  HANDLE no_targets_;
+
+  // Handle to the worker thread that reacts to job notifications.
+  HANDLE job_thread_;
+
+  // Lock used to protect the list of targets from being modified by 2
+  // threads at the same time.
+  CRITICAL_SECTION lock_;
+
+  // provides a pool of threads that are used to wait on the IPC calls.
+  ThreadProvider* thread_pool_;
+
+  // List of the trackers for closing and cleanup purposes.
+  typedef std::list<JobTracker*> JobTrackerList;
+  JobTrackerList tracker_list_;
+
+  // Maps peer process IDs to the saved handle and wait event.
+  // Prevents peer callbacks from accessing the broker after destruction.
+  typedef std::map<DWORD, PeerTracker*> PeerTrackerMap;
+  PeerTrackerMap peer_map_;
+
+  // Provides a fast lookup to identify sandboxed processes that belong to a
+  // job. Consult |jobless_process_handles_| for handles of pocess without job.
+  std::set<DWORD> child_process_ids_;
+
+  typedef std::map<uint32_t, std::pair<HANDLE, HANDLE>> TokenCacheMap;
+  TokenCacheMap token_cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_WIN_SRC_BROKER_SERVICES_H_
diff --git a/sandbox/win/src/crosscall_client.h b/sandbox/win/src/crosscall_client.h
new file mode 100644
index 0000000..5b1bce7
--- /dev/null
+++ b/sandbox/win/src/crosscall_client.h
@@ -0,0 +1,483 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_CLIENT_H_
+#define SANDBOX_SRC_CROSSCALL_CLIENT_H_
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+// This header defines the CrossCall(..) family of templated functions
+// Their purpose is to simulate the syntax of regular call but to generate
+// and IPC from the client-side.
+//
+// The basic pattern is to
+//   1) use template argument deduction to compute the size of each
+//      parameter and the appropriate copy method
+//   2) pack the parameters in the appropriate ActualCallParams< > object
+//   3) call the IPC interface IPCProvider::DoCall( )
+//
+// The general interface of CrossCall is:
+//  ResultCode CrossCall(IPCProvider& ipc_provider,
+//                       uint32 tag,
+//                       const Par1& p1, const Par2& p2,...pn
+//                       CrossCallReturn* answer)
+//
+//  where:
+//    ipc_provider: is a specific implementation of the ipc transport see
+//                  sharedmem_ipc_server.h for an example.
+//    tag : is the unique id for this IPC call. Is used to route the call to
+//          the appropriate service.
+//    p1, p2,.. pn : The input parameters of the IPC. Use only simple types
+//                   and wide strings (can add support for others).
+//    answer : If the IPC was successful. The server-side answer is here. The
+//             interpretation of the answer is private to client and server.
+//
+// The return value is ALL_OK if the IPC was delivered to the server, other
+// return codes indicate that the IPC transport failed to deliver it.
+namespace sandbox {
+
+// this is the assumed channel size. This can be overridden in a given
+// IPC implementation.
+const uint32 kIPCChannelSize = 1024;
+
+// The copy helper uses templates to deduce the appropriate copy function to
+// copy the input parameters in the buffer that is going to be send across the
+// IPC. These template facility can be made more sophisticated as need arises.
+
+// The default copy helper. It catches the general case where no other
+// specialized template matches better. We set the type to UINT32_TYPE, so this
+// only works with objects whose size is 32 bits.
+template<typename T>
+class CopyHelper {
+ public:
+  CopyHelper(const T& t) : t_(t) {}
+
+  // Returns the pointer to the start of the input.
+  const void* GetStart() const {
+    return &t_;
+  }
+
+  // Update the stored value with the value in the buffer. This is not
+  // supported for this type.
+  bool Update(void* buffer) {
+    // Not supported;
+    return true;
+  }
+
+  // Returns the size of the input in bytes.
+  uint32 GetSize() const {
+    return sizeof(T);
+  }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return false;
+  }
+
+  // Returns this object's type.
+  ArgType GetType() {
+    static_assert(sizeof(T) == sizeof(uint32), "specialization needed");
+    return UINT32_TYPE;
+  }
+
+ private:
+  const T& t_;
+};
+
+// This copy helper template specialization if for the void pointer
+// case both 32 and 64 bit.
+template<>
+class CopyHelper<void*> {
+ public:
+  CopyHelper(void* t) : t_(t) {}
+
+  // Returns the pointer to the start of the input.
+  const void* GetStart() const {
+    return &t_;
+  }
+
+  // Update the stored value with the value in the buffer. This is not
+  // supported for this type.
+  bool Update(void* buffer) {
+    // Not supported;
+    return true;
+  }
+
+  // Returns the size of the input in bytes.
+  uint32 GetSize() const {
+    return sizeof(t_);
+  }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return false;
+  }
+
+  // Returns this object's type.
+  ArgType GetType() {
+    return VOIDPTR_TYPE;
+  }
+
+ private:
+  const void* t_;
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a pointer to a string.
+template<>
+class CopyHelper<const wchar_t*> {
+ public:
+  CopyHelper(const wchar_t* t)
+      : t_(t) {
+  }
+
+  // Returns the pointer to the start of the string.
+  const void* GetStart() const {
+    return t_;
+  }
+
+  // Update the stored value with the value in the buffer. This is not
+  // supported for this type.
+  bool Update(void* buffer) {
+    // Not supported;
+    return true;
+  }
+
+  // Returns the size of the string in bytes. We define a NULL string to
+  // be of zero length.
+  uint32 GetSize() const {
+    __try {
+      return (!t_) ? 0 : static_cast<uint32>(StringLength(t_) * sizeof(t_[0]));
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+      return kuint32max;
+    }
+  }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return false;
+  }
+
+  ArgType GetType() {
+    return WCHAR_TYPE;
+  }
+
+ private:
+  // We provide our not very optimized version of wcslen(), since we don't
+  // want to risk having the linker use the version in the CRT since the CRT
+  // might not be present when we do an early IPC call.
+  static size_t __cdecl StringLength(const wchar_t* wcs) {
+    const wchar_t *eos = wcs;
+    while (*eos++);
+    return static_cast<size_t>(eos - wcs - 1);
+  }
+
+  const wchar_t* t_;
+};
+
+// Specialization for non-const strings. We just reuse the implementation of the
+// const string specialization.
+template<>
+class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
+ public:
+  typedef CopyHelper<const wchar_t*> Base;
+  CopyHelper(wchar_t* t) : Base(t) {}
+
+  const void* GetStart() const {
+    return Base::GetStart();
+  }
+
+  bool Update(void* buffer) {
+    return Base::Update(buffer);
+  }
+
+  uint32 GetSize() const {
+    return Base::GetSize();
+  }
+
+  bool IsInOut() {
+    return Base::IsInOut();
+  }
+
+  ArgType GetType() {
+    return Base::GetType();
+  }
+};
+
+// Specialization for wchar_t arrays strings. We just reuse the implementation
+// of the const string specialization.
+template<size_t n>
+class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
+ public:
+  typedef const wchar_t array[n];
+  typedef CopyHelper<const wchar_t*> Base;
+  CopyHelper(array t) : Base(t) {}
+
+  const void* GetStart() const {
+    return Base::GetStart();
+  }
+
+  bool Update(void* buffer) {
+    return Base::Update(buffer);
+  }
+
+  uint32 GetSize() const {
+    return Base::GetSize();
+  }
+
+  bool IsInOut() {
+    return Base::IsInOut();
+  }
+
+  ArgType GetType() {
+    return Base::GetType();
+  }
+};
+
+// Generic encapsulation class containing a pointer to a buffer and the
+// size of the buffer. It is used by the IPC to be able to pass in/out
+// parameters.
+class InOutCountedBuffer : public CountedBuffer {
+ public:
+  InOutCountedBuffer(void* buffer, uint32 size) : CountedBuffer(buffer, size) {}
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a an input/output buffer.
+template<>
+class CopyHelper<InOutCountedBuffer> {
+ public:
+  CopyHelper(const InOutCountedBuffer t) : t_(t) {}
+
+  // Returns the pointer to the start of the string.
+  const void* GetStart() const {
+    return t_.Buffer();
+  }
+
+  // Updates the buffer with the value from the new buffer in parameter.
+  bool Update(void* buffer) {
+    // We are touching user memory, this has to be done from inside a try
+    // except.
+    __try {
+      memcpy(t_.Buffer(), buffer, t_.Size());
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+      return false;
+    }
+    return true;
+  }
+
+  // Returns the size of the string in bytes. We define a NULL string to
+  // be of zero length.
+  uint32 GetSize() const {
+    return t_.Size();
+  }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return true;
+  }
+
+  ArgType GetType() {
+    return INOUTPTR_TYPE;
+  }
+
+ private:
+  const InOutCountedBuffer t_;
+};
+
+// The following two macros make it less error prone the generation
+// of CrossCall functions with ever more input parameters.
+
+#define XCALL_GEN_PARAMS_OBJ(num, params) \
+  typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \
+  void* raw_mem = ipc_provider.GetBuffer(); \
+  if (NULL == raw_mem) \
+    return SBOX_ERROR_NO_SPACE; \
+  ActualParams* params = new(raw_mem) ActualParams(tag);
+
+#define XCALL_GEN_COPY_PARAM(num, params) \
+  static_assert(kMaxIpcParams >= num, "too many parameters"); \
+  CopyHelper<Par##num> ch##num(p##num); \
+  if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \
+                           ch##num.IsInOut(), ch##num.GetType())) \
+    return SBOX_ERROR_NO_SPACE;
+
+#define XCALL_GEN_UPDATE_PARAM(num, params) \
+  if (!ch##num.Update(params->GetParamPtr(num-1))) {\
+    ipc_provider.FreeBuffer(raw_mem); \
+    return SBOX_ERROR_BAD_PARAMS; \
+  }
+
+#define XCALL_GEN_FREE_CHANNEL() \
+  ipc_provider.FreeBuffer(raw_mem);
+
+// CrossCall template with one input parameter
+template <typename IPCProvider, typename Par1>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(1, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+
+  return result;
+}
+
+// CrossCall template with two input parameters.
+template <typename IPCProvider, typename Par1, typename Par2>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     const Par2& p2, CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(2, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with three input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     const Par2& p2, const Par3& p3, CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(3, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with four input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
+          typename Par4>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     const Par2& p2, const Par3& p3, const Par4& p4,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(4, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with five input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
+          typename Par4, typename Par5>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     const Par2& p2, const Par3& p3, const Par4& p4,
+                     const Par5& p5, CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(5, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+  XCALL_GEN_COPY_PARAM(5, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_UPDATE_PARAM(5, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with six input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
+          typename Par4, typename Par5, typename Par6>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     const Par2& p2, const Par3& p3, const Par4& p4,
+                     const Par5& p5, const Par6& p6, CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(6, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+  XCALL_GEN_COPY_PARAM(5, call_params);
+  XCALL_GEN_COPY_PARAM(6, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_UPDATE_PARAM(5, call_params);
+    XCALL_GEN_UPDATE_PARAM(6, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with seven input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3,
+          typename Par4, typename Par5, typename Par6, typename Par7>
+ResultCode CrossCall(IPCProvider& ipc_provider, uint32 tag, const Par1& p1,
+                     const Par2& p2, const Par3& p3, const Par4& p4,
+                     const Par5& p5, const Par6& p6, const Par7& p7,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(7, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+  XCALL_GEN_COPY_PARAM(5, call_params);
+  XCALL_GEN_COPY_PARAM(6, call_params);
+  XCALL_GEN_COPY_PARAM(7, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_UPDATE_PARAM(5, call_params);
+    XCALL_GEN_UPDATE_PARAM(6, call_params);
+    XCALL_GEN_UPDATE_PARAM(7, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_CROSSCALL_CLIENT_H__
diff --git a/sandbox/win/src/crosscall_params.h b/sandbox/win/src/crosscall_params.h
new file mode 100644
index 0000000..6facb20
--- /dev/null
+++ b/sandbox/win/src/crosscall_params.h
@@ -0,0 +1,296 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_PARAMS_H__
+#define SANDBOX_SRC_CROSSCALL_PARAMS_H__
+
+#include <windows.h>
+#include <lmaccess.h>
+
+#include <memory>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace {
+
+// Increases |value| until there is no need for padding given an int64
+// alignment. Returns the increased value.
+uint32 Align(uint32 value) {
+  uint32 alignment = sizeof(int64);
+  return ((value + alignment - 1) / alignment) * alignment;
+}
+
+}
+// This header is part of CrossCall: the sandbox inter-process communication.
+// This header defines the basic types used both in the client IPC and in the
+// server IPC code. CrossCallParams and ActualCallParams model the input
+// parameters of an IPC call and CrossCallReturn models the output params and
+// the return value.
+//
+// An IPC call is defined by its 'tag' which is a (uint32) unique identifier
+// that is used to route the IPC call to the proper server. Every tag implies
+// a complete call signature including the order and type of each parameter.
+//
+// Like most IPC systems. CrossCall is designed to take as inputs 'simple'
+// types such as integers and strings. Classes, generic arrays or pointers to
+// them are not supported.
+//
+// Another limitation of CrossCall is that the return value and output
+// parameters can only be uint32 integers. Returning complex structures or
+// strings is not supported.
+
+namespace sandbox {
+
+// max number of extended return parameters. See CrossCallReturn
+const size_t kExtendedReturnCount = 8;
+
+// Union of multiple types to be used as extended results
+// in the CrossCallReturn.
+union MultiType {
+  uint32 unsigned_int;
+  void* pointer;
+  HANDLE handle;
+  ULONG_PTR ulong_ptr;
+};
+
+// Maximum number of IPC parameters currently supported.
+// To increase this value, we have to:
+//  - Add another Callback typedef to Dispatcher.
+//  - Add another case to the switch on SharedMemIPCServer::InvokeCallback.
+//  - Add another case to the switch in GetActualAndMaxBufferSize
+const int kMaxIpcParams = 9;
+
+// Contains the information about a parameter in the ipc buffer.
+struct ParamInfo {
+  ArgType type_;
+  uint32 offset_;
+  uint32 size_;
+};
+
+// Models the return value and the return parameters of an IPC call
+// currently limited to one status code and eight generic return values
+// which cannot be pointers to other data. For x64 ports this structure
+// might have to use other integer types.
+struct CrossCallReturn {
+  // the IPC tag. It should match the original IPC tag.
+  uint32 tag;
+  // The result of the IPC operation itself.
+  ResultCode call_outcome;
+  // the result of the IPC call as executed in the server. The interpretation
+  // of this value depends on the specific service.
+  union {
+    NTSTATUS nt_status;
+    DWORD    win32_result;
+  };
+  // Number of extended return values.
+  uint32 extended_count;
+  // for calls that should return a windows handle. It is found here.
+  HANDLE handle;
+  // The array of extended values.
+  MultiType extended[kExtendedReturnCount];
+};
+
+// CrossCallParams base class that models the input params all packed in a
+// single compact memory blob. The representation can vary but in general a
+// given child of this class is meant to represent all input parameters
+// necessary to make a IPC call.
+//
+// This class cannot have virtual members because its assumed the IPC
+// parameters start from the 'this' pointer to the end, which is defined by
+// one of the subclasses
+//
+// Objects of this class cannot be constructed directly. Only derived
+// classes have the proper knowledge to construct it.
+class CrossCallParams {
+ public:
+  // Returns the tag (ipc unique id) associated with this IPC.
+  uint32 GetTag() const {
+    return tag_;
+  }
+
+  // Returns the beggining of the buffer where the IPC params can be stored.
+  // prior to an IPC call
+  const void* GetBuffer() const {
+    return this;
+  }
+
+  // Returns how many parameter this IPC call should have.
+  const uint32 GetParamsCount() const {
+    return params_count_;
+  }
+
+  // Returns a pointer to the CrossCallReturn structure.
+  CrossCallReturn* GetCallReturn() {
+    return &call_return;
+  }
+
+  // Returns TRUE if this call contains InOut parameters.
+  const bool IsInOut() const {
+    return (1 == is_in_out_);
+  }
+
+  // Tells the CrossCall object if it contains InOut parameters.
+  void SetIsInOut(bool value) {
+    if (value)
+      is_in_out_ = 1;
+    else
+      is_in_out_ = 0;
+  }
+
+ protected:
+  // constructs the IPC call params. Called only from the derived classes
+  CrossCallParams(uint32 tag, uint32 params_count)
+      : tag_(tag),
+        params_count_(params_count),
+        is_in_out_(0) {
+  }
+
+ private:
+  uint32 tag_;
+  uint32 is_in_out_;
+  CrossCallReturn call_return;
+  const uint32 params_count_;
+  DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
+};
+
+// ActualCallParams models an specific IPC call parameters with respect to the
+// storage allocation that the packed parameters should need.
+// NUMBER_PARAMS: the number of parameters, valid from 1 to N
+// BLOCK_SIZE: the total storage that the NUMBER_PARAMS parameters can take,
+// typically the block size is defined by the channel size of the underlying
+// ipc mechanism.
+// In practice this class is used to levergage C++ capacity to properly
+// calculate sizes and displacements given the possibility of the packed params
+// blob to be complex.
+//
+// As is, this class assumes that the layout of the blob is as follows. Assume
+// that NUMBER_PARAMS = 2 and a 32-bit build:
+//
+// [ tag                4 bytes]
+// [ IsOnOut            4 bytes]
+// [ call return       52 bytes]
+// [ params count       4 bytes]
+// [ parameter 0 type   4 bytes]
+// [ parameter 0 offset 4 bytes] ---delta to ---\
+// [ parameter 0 size   4 bytes]                |
+// [ parameter 1 type   4 bytes]                |
+// [ parameter 1 offset 4 bytes] ---------------|--\
+// [ parameter 1 size   4 bytes]                |  |
+// [ parameter 2 type   4 bytes]                |  |
+// [ parameter 2 offset 4 bytes] ----------------------\
+// [ parameter 2 size   4 bytes]                |  |   |
+// |---------------------------|                |  |   |
+// | value 0     (x bytes)     | <--------------/  |   |
+// | value 1     (y bytes)     | <-----------------/   |
+// |                           |                       |
+// | end of buffer             | <---------------------/
+// |---------------------------|
+//
+// Note that the actual number of params is NUMBER_PARAMS + 1
+// so that the size of each actual param can be computed from the difference
+// between one parameter and the next down. The offset of the last param
+// points to the end of the buffer and the type and size are undefined.
+//
+template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE>
+class ActualCallParams : public CrossCallParams {
+ public:
+  // constructor. Pass the ipc unique tag as input
+  explicit ActualCallParams(uint32 tag)
+      : CrossCallParams(tag, NUMBER_PARAMS) {
+    param_info_[0].offset_ =
+        static_cast<uint32>(parameters_ - reinterpret_cast<char*>(this));
+  }
+
+  // Testing-only constructor. Allows setting the |number_params| to a
+  // wrong value.
+  ActualCallParams(uint32 tag, uint32 number_params)
+      : CrossCallParams(tag, number_params) {
+    param_info_[0].offset_ =
+        static_cast<uint32>(parameters_ - reinterpret_cast<char*>(this));
+  }
+
+  // Testing-only method. Allows setting the apparent size to a wrong value.
+  // returns the previous size.
+  uint32 OverrideSize(uint32 new_size) {
+    uint32 previous_size = param_info_[NUMBER_PARAMS].offset_;
+    param_info_[NUMBER_PARAMS].offset_ = new_size;
+    return previous_size;
+  }
+
+  // Copies each paramter into the internal buffer. For each you must supply:
+  // index: 0 for the first param, 1 for the next an so on
+  bool CopyParamIn(uint32 index, const void* parameter_address, uint32 size,
+                   bool is_in_out, ArgType type) {
+    if (index >= NUMBER_PARAMS) {
+      return false;
+    }
+
+    if (kuint32max == size) {
+      // Memory error while getting the size.
+      return false;
+    }
+
+    if (size && !parameter_address) {
+      return false;
+    }
+
+    if ((size > sizeof(*this)) ||
+        (param_info_[index].offset_ > (sizeof(*this) - size))) {
+      // It does not fit, abort copy.
+      return false;
+    }
+
+    char* dest = reinterpret_cast<char*>(this) +  param_info_[index].offset_;
+
+    // We might be touching user memory, this has to be done from inside a try
+    // except.
+    __try {
+      memcpy(dest, parameter_address, size);
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+      return false;
+    }
+
+    // Set the flag to tell the broker to update the buffer once the call is
+    // made.
+    if (is_in_out)
+      SetIsInOut(true);
+
+    param_info_[index + 1].offset_ = Align(param_info_[index].offset_ +
+                                                size);
+    param_info_[index].size_ = size;
+    param_info_[index].type_ = type;
+    return true;
+  }
+
+  // Returns a pointer to a parameter in the memory section.
+  void* GetParamPtr(size_t index) {
+    return reinterpret_cast<char*>(this) + param_info_[index].offset_;
+  }
+
+  // Returns the total size of the buffer. Only valid once all the paramters
+  // have been copied in with CopyParamIn.
+  uint32 GetSize() const {
+    return param_info_[NUMBER_PARAMS].offset_;
+  }
+
+ protected:
+  ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
+
+ private:
+  ParamInfo param_info_[NUMBER_PARAMS + 1];
+  char parameters_[BLOCK_SIZE - sizeof(CrossCallParams)
+                   - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)];
+  DISALLOW_COPY_AND_ASSIGN(ActualCallParams);
+};
+
+static_assert(sizeof(ActualCallParams<1, 1024>) == 1024, "bad size buffer");
+static_assert(sizeof(ActualCallParams<2, 1024>) == 1024, "bad size buffer");
+static_assert(sizeof(ActualCallParams<3, 1024>) == 1024, "bad size buffer");
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_CROSSCALL_PARAMS_H__
diff --git a/sandbox/win/src/crosscall_server.cc b/sandbox/win/src/crosscall_server.cc
new file mode 100644
index 0000000..6f8bd74
--- /dev/null
+++ b/sandbox/win/src/crosscall_server.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/crosscall_server.h"
+
+#include <string>
+#include <vector>
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "base/logging.h"
+
+// This code performs the ipc message validation. Potential security flaws
+// on the ipc are likelier to be found in this code than in the rest of
+// the ipc code.
+
+namespace {
+
+// The buffer for a message must match the max channel size.
+const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
+
+}
+
+namespace sandbox {
+
+// Returns the actual size for the parameters in an IPC buffer. Returns
+// zero if the |param_count| is zero or too big.
+uint32 GetActualBufferSize(uint32 param_count, void* buffer_base) {
+  // The template types are used to calculate the maximum expected size.
+  typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
+  typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
+  typedef ActualCallParams<3, kMaxBufferSize> ActualCP3;
+  typedef ActualCallParams<4, kMaxBufferSize> ActualCP4;
+  typedef ActualCallParams<5, kMaxBufferSize> ActualCP5;
+  typedef ActualCallParams<6, kMaxBufferSize> ActualCP6;
+  typedef ActualCallParams<7, kMaxBufferSize> ActualCP7;
+  typedef ActualCallParams<8, kMaxBufferSize> ActualCP8;
+  typedef ActualCallParams<9, kMaxBufferSize> ActualCP9;
+
+  // Retrieve the actual size and the maximum size of the params buffer.
+  switch (param_count) {
+    case 0:
+      return 0;
+    case 1:
+      return reinterpret_cast<ActualCP1*>(buffer_base)->GetSize();
+    case 2:
+      return reinterpret_cast<ActualCP2*>(buffer_base)->GetSize();
+    case 3:
+      return reinterpret_cast<ActualCP3*>(buffer_base)->GetSize();
+    case 4:
+      return reinterpret_cast<ActualCP4*>(buffer_base)->GetSize();
+    case 5:
+      return reinterpret_cast<ActualCP5*>(buffer_base)->GetSize();
+    case 6:
+      return reinterpret_cast<ActualCP6*>(buffer_base)->GetSize();
+    case 7:
+      return reinterpret_cast<ActualCP7*>(buffer_base)->GetSize();
+    case 8:
+      return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize();
+    case 9:
+      return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
+    default:
+      return 0;
+  }
+}
+
+// Verifies that the declared sizes of an IPC buffer are within range.
+bool IsSizeWithinRange(uint32 buffer_size, uint32 min_declared_size,
+                       uint32 declared_size) {
+  if ((buffer_size < min_declared_size) ||
+      (sizeof(CrossCallParamsEx) > min_declared_size)) {
+    // Minimal computed size bigger than existing buffer or param_count
+    // integer overflow.
+    return false;
+  }
+
+  if ((declared_size > buffer_size) || (declared_size < min_declared_size)) {
+    // Declared size is bigger than buffer or smaller than computed size
+    // or param_count is equal to 0 or bigger than 9.
+    return false;
+  }
+
+  return true;
+}
+
+CrossCallParamsEx::CrossCallParamsEx()
+  :CrossCallParams(0, 0) {
+}
+
+// We override the delete operator because the object's backing memory
+// is hand allocated in CreateFromBuffer. We don't override the new operator
+// because the constructors are private so there is no way to mismatch
+// new & delete.
+void CrossCallParamsEx::operator delete(void* raw_memory) throw() {
+  if (NULL == raw_memory) {
+    // C++ standard allows 'delete 0' behavior.
+    return;
+  }
+  delete[] reinterpret_cast<char*>(raw_memory);
+}
+
+// This function uses a SEH try block so cannot use C++ objects that
+// have destructors or else you get Compiler Error C2712. So no DCHECKs
+// inside this function.
+CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
+                                                       uint32 buffer_size,
+                                                       uint32* output_size) {
+  // IMPORTANT: Everything inside buffer_base and derived from it such
+  // as param_count and declared_size is untrusted.
+  if (NULL == buffer_base) {
+    return NULL;
+  }
+  if (buffer_size < sizeof(CrossCallParams)) {
+    return NULL;
+  }
+  if (buffer_size > kMaxBufferSize) {
+    return NULL;
+  }
+
+  char* backing_mem = NULL;
+  uint32 param_count = 0;
+  uint32 declared_size;
+  uint32 min_declared_size;
+  CrossCallParamsEx* copied_params = NULL;
+
+  // Touching the untrusted buffer is done under a SEH try block. This
+  // will catch memory access violations so we don't crash.
+  __try {
+    CrossCallParams* call_params =
+        reinterpret_cast<CrossCallParams*>(buffer_base);
+
+    // Check against the minimum size given the number of stated params
+    // if too small we bail out.
+    param_count = call_params->GetParamsCount();
+    min_declared_size = sizeof(CrossCallParams) +
+                        ((param_count + 1) * sizeof(ParamInfo));
+
+    // Retrieve the declared size which if it fails returns 0.
+    declared_size = GetActualBufferSize(param_count, buffer_base);
+
+    if (!IsSizeWithinRange(buffer_size, min_declared_size, declared_size))
+      return NULL;
+
+    // Now we copy the actual amount of the message.
+    *output_size = declared_size;
+    backing_mem = new char[declared_size];
+    copied_params = reinterpret_cast<CrossCallParamsEx*>(backing_mem);
+    memcpy(backing_mem, call_params, declared_size);
+
+    // Avoid compiler optimizations across this point. Any value stored in
+    // memory should be stored for real, and values previously read from memory
+    // should be actually read.
+    _ReadWriteBarrier();
+
+    min_declared_size = sizeof(CrossCallParams) +
+                        ((param_count + 1) * sizeof(ParamInfo));
+
+    // Check that the copied buffer is still valid.
+    if (copied_params->GetParamsCount() != param_count ||
+        GetActualBufferSize(param_count, backing_mem) != declared_size ||
+        !IsSizeWithinRange(buffer_size, min_declared_size, declared_size)) {
+      delete [] backing_mem;
+      return NULL;
+    }
+
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    // In case of a windows exception we know it occurred while touching the
+    // untrusted buffer so we bail out as is.
+    delete [] backing_mem;
+    return NULL;
+  }
+
+  const char* last_byte = &backing_mem[declared_size];
+  const char* first_byte = &backing_mem[min_declared_size];
+
+  // Verify here that all and each parameters make sense. This is done in the
+  // local copy.
+  for (uint32 ix =0; ix != param_count; ++ix) {
+    uint32 size = 0;
+    ArgType type;
+    char* address = reinterpret_cast<char*>(
+                        copied_params->GetRawParameter(ix, &size, &type));
+    if ((NULL == address) ||               // No null params.
+        (INVALID_TYPE >= type) || (LAST_TYPE <= type) ||  // Unknown type.
+        (address < backing_mem) ||         // Start cannot point before buffer.
+        (address < first_byte) ||          // Start cannot point too low.
+        (address > last_byte) ||           // Start cannot point past buffer.
+        ((address + size) < address) ||    // Invalid size.
+        ((address + size) > last_byte)) {  // End cannot point past buffer.
+      // Malformed.
+      delete[] backing_mem;
+      return NULL;
+    }
+  }
+  // The parameter buffer looks good.
+  return copied_params;
+}
+
+// Accessors to the parameters in the raw buffer.
+void* CrossCallParamsEx::GetRawParameter(uint32 index, uint32* size,
+                                         ArgType* type) {
+  if (index >= GetParamsCount()) {
+    return NULL;
+  }
+  // The size is always computed from the parameter minus the next
+  // parameter, this works because the message has an extra parameter slot
+  *size = param_info_[index].size_;
+  *type = param_info_[index].type_;
+
+  return param_info_[index].offset_ + reinterpret_cast<char*>(this);
+}
+
+// Covers common case for 32 bit integers.
+bool CrossCallParamsEx::GetParameter32(uint32 index, uint32* param) {
+  uint32 size = 0;
+  ArgType type;
+  void* start = GetRawParameter(index, &size, &type);
+  if ((NULL == start) || (4 != size) || (UINT32_TYPE != type)) {
+    return false;
+  }
+  // Copy the 4 bytes.
+  *(reinterpret_cast<uint32*>(param)) = *(reinterpret_cast<uint32*>(start));
+  return true;
+}
+
+bool CrossCallParamsEx::GetParameterVoidPtr(uint32 index, void** param) {
+  uint32 size = 0;
+  ArgType type;
+  void* start = GetRawParameter(index, &size, &type);
+  if ((NULL == start) || (sizeof(void*) != size) || (VOIDPTR_TYPE != type)) {
+    return false;
+  }
+  *param = *(reinterpret_cast<void**>(start));
+  return true;
+}
+
+// Covers the common case of reading a string. Note that the string is not
+// scanned for invalid characters.
+bool CrossCallParamsEx::GetParameterStr(uint32 index, base::string16* string) {
+  uint32 size = 0;
+  ArgType type;
+  void* start = GetRawParameter(index, &size, &type);
+  if (WCHAR_TYPE != type) {
+    return false;
+  }
+
+  // Check if this is an empty string.
+  if (size == 0) {
+    *string = L"";
+    return true;
+  }
+
+  if ((NULL == start) || ((size % sizeof(wchar_t)) != 0)) {
+    return false;
+  }
+  string->append(reinterpret_cast<wchar_t*>(start), size/(sizeof(wchar_t)));
+  return true;
+}
+
+bool CrossCallParamsEx::GetParameterPtr(uint32 index, uint32 expected_size,
+                                        void** pointer) {
+  uint32 size = 0;
+  ArgType type;
+  void* start = GetRawParameter(index, &size, &type);
+
+  if ((size != expected_size) || (INOUTPTR_TYPE != type)) {
+    return false;
+  }
+
+  if (NULL == start) {
+    return false;
+  }
+
+  *pointer = start;
+  return true;
+}
+
+void SetCallError(ResultCode error, CrossCallReturn* call_return) {
+  call_return->call_outcome = error;
+  call_return->extended_count = 0;
+}
+
+void SetCallSuccess(CrossCallReturn* call_return) {
+  call_return->call_outcome = SBOX_ALL_OK;
+}
+
+Dispatcher* Dispatcher::OnMessageReady(IPCParams* ipc,
+                                      CallbackGeneric* callback) {
+  DCHECK(callback);
+  std::vector<IPCCall>::iterator it = ipc_calls_.begin();
+  for (; it != ipc_calls_.end(); ++it) {
+    if (it->params.Matches(ipc)) {
+      *callback = it->callback;
+      return this;
+    }
+  }
+  return NULL;
+}
+
+Dispatcher::Dispatcher() {
+}
+
+Dispatcher::~Dispatcher() {
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/crosscall_server.h b/sandbox/win/src/crosscall_server.h
new file mode 100644
index 0000000..41888c1
--- /dev/null
+++ b/sandbox/win/src/crosscall_server.h
@@ -0,0 +1,226 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_SERVER_H_
+#define SANDBOX_SRC_CROSSCALL_SERVER_H_
+
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_params.h"
+
+// This is the IPC server interface for CrossCall: The  IPC for the Sandbox
+// On the server, CrossCall needs two things:
+// 1) threads: Or better said, someone to provide them, that is what the
+//             ThreadProvider interface is defined for. These thread(s) are
+//             the ones that will actually execute the  IPC data retrieval.
+//
+// 2) a dispatcher: This interface represents the way to route and process
+//                  an  IPC call given the  IPC tag.
+//
+// The other class included here CrossCallParamsEx is the server side version
+// of the CrossCallParams class of /sandbox/crosscall_params.h The difference
+// is that the sever version is paranoid about the correctness of the IPC
+// message and will do all sorts of verifications.
+//
+// A general diagram of the interaction is as follows:
+//
+//                                 ------------
+//                                 |          |
+//  ThreadProvider <--(1)Register--|  IPC     |
+//      |                          | Implemen |
+//      |                          | -tation  |
+//     (2)                         |          |  OnMessage
+//     IPC fired --callback ------>|          |--(3)---> Dispatcher
+//                                 |          |
+//                                 ------------
+//
+//  The  IPC implementation sits as a middleman between the handling of the
+//  specifics of scheduling a thread to service the  IPC and the multiple
+//  entities that can potentially serve each particular IPC.
+namespace sandbox {
+
+class InterceptionManager;
+
+// This function signature is required as the callback when an  IPC call fires.
+// context: a user-defined pointer that was set using  ThreadProvider
+// reason: 0 if the callback was fired because of a timeout.
+//         1 if the callback was fired because of an event.
+typedef void (__stdcall * CrossCallIPCCallback)(void* context,
+                                                unsigned char reason);
+
+// ThreadProvider models a thread factory. The idea is to decouple thread
+// creation and lifetime from the inner guts of the IPC. The contract is
+// simple:
+//   - the IPC implementation calls RegisterWait with a waitable object that
+//     becomes signaled when an IPC arrives and needs to be serviced.
+//   - when the waitable object becomes signaled, the thread provider conjures
+//     a thread that calls the callback (CrossCallIPCCallback) function
+//   - the callback function tries its best not to block and return quickly
+//     and should not assume that the next callback will use the same thread
+//   - when the callback returns the ThreadProvider owns again the thread
+//     and can destroy it or keep it around.
+class ThreadProvider {
+ public:
+  // Registers a waitable object with the thread provider.
+  // client: A number to associate with all the RegisterWait calls, typically
+  //         this is the address of the caller object. This parameter cannot
+  //         be zero.
+  // waitable_object : a kernel object that can be waited on
+  // callback: a function pointer which is the function that will be called
+  //           when the waitable object fires
+  // context: a user-provider pointer that is passed back to the callback
+  //          when its called
+  virtual bool RegisterWait(const void* client, HANDLE waitable_object,
+                            CrossCallIPCCallback callback,
+                            void* context) = 0;
+
+  // Removes all the registrations done with the same cookie parameter.
+  // This frees internal thread pool resources.
+  virtual bool UnRegisterWaits(void* cookie) = 0;
+  virtual ~ThreadProvider() {}
+};
+
+// Models the server-side of the original input parameters.
+// Provides IPC buffer validation and it is capable of reading the parameters
+// out of the IPC buffer.
+class CrossCallParamsEx : public CrossCallParams {
+ public:
+  // Factory constructor. Pass an IPCbuffer (and buffer size) that contains a
+  // pending IPCcall. This constructor will:
+  // 1) validate the IPC buffer. returns NULL is the IPCbuffer is malformed.
+  // 2) make a copy of the IPCbuffer (parameter capture)
+  static CrossCallParamsEx* CreateFromBuffer(void* buffer_base,
+                                             uint32 buffer_size,
+                                             uint32* output_size);
+
+  // Provides IPCinput parameter raw access:
+  // index : the parameter to read; 0 is the first parameter
+  // returns NULL if the parameter is non-existent. If it exists it also
+  // returns the size in *size
+  void* GetRawParameter(uint32 index, uint32* size, ArgType* type);
+
+  // Gets a parameter that is four bytes in size.
+  // Returns false if the parameter does not exist or is not 32 bits wide.
+  bool GetParameter32(uint32 index, uint32* param);
+
+  // Gets a parameter that is void pointer in size.
+  // Returns false if the parameter does not exist or is not void pointer sized.
+  bool GetParameterVoidPtr(uint32 index, void** param);
+
+  // Gets a parameter that is a string. Returns false if the parameter does not
+  // exist.
+  bool GetParameterStr(uint32 index, base::string16* string);
+
+  // Gets a parameter that is an in/out buffer. Returns false is the parameter
+  // does not exist or if the size of the actual parameter is not equal to the
+  // expected size.
+  bool GetParameterPtr(uint32 index, uint32 expected_size, void** pointer);
+
+  // Frees the memory associated with the IPC parameters.
+  static void operator delete(void* raw_memory) throw();
+
+ private:
+  // Only the factory method CreateFromBuffer can construct these objects.
+  CrossCallParamsEx();
+
+  ParamInfo param_info_[1];
+  DISALLOW_COPY_AND_ASSIGN(CrossCallParamsEx);
+};
+
+// Simple helper function that sets the members of CrossCallReturn
+// to the proper state to signal a basic error.
+void SetCallError(ResultCode error, CrossCallReturn* call_return);
+
+// Sets the internal status of call_return to signify the that IPC call
+// completed successfully.
+void SetCallSuccess(CrossCallReturn* call_return);
+
+// Represents the client process that initiated the IPC which boils down to the
+// process handle and the job object handle that contains the client process.
+struct ClientInfo {
+  HANDLE process;
+  HANDLE job_object;
+  DWORD process_id;
+};
+
+// All IPC-related information to be passed to the IPC handler.
+struct IPCInfo {
+  int ipc_tag;
+  const ClientInfo* client_info;
+  CrossCallReturn return_info;
+};
+
+// This structure identifies IPC signatures.
+struct IPCParams {
+  int ipc_tag;
+  ArgType args[kMaxIpcParams];
+
+  bool Matches(IPCParams* other) const {
+    return !memcmp(this, other, sizeof(*other));
+  }
+};
+
+// Models an entity that can process an IPC message or it can route to another
+// one that could handle it. When an IPC arrives the IPC implementation will:
+// 1) call OnMessageReady() with the tag of the pending IPC. If the dispatcher
+//    returns NULL it means that it cannot handle this IPC but if it returns
+//    non-null, it must be the pointer to a dispatcher that can handle it.
+// 2) When the  IPC finally obtains a valid Dispatcher the IPC
+//    implementation creates a CrossCallParamsEx from the raw IPC buffer.
+// 3) It calls the returned callback, with the IPC info and arguments.
+class Dispatcher {
+ public:
+  // Called from the  IPC implementation to handle a specific IPC message.
+  typedef bool (Dispatcher::*CallbackGeneric)();
+  typedef bool (Dispatcher::*Callback0)(IPCInfo* ipc);
+  typedef bool (Dispatcher::*Callback1)(IPCInfo* ipc, void* p1);
+  typedef bool (Dispatcher::*Callback2)(IPCInfo* ipc, void* p1, void* p2);
+  typedef bool (Dispatcher::*Callback3)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3);
+  typedef bool (Dispatcher::*Callback4)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3, void* p4);
+  typedef bool (Dispatcher::*Callback5)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3, void* p4, void* p5);
+  typedef bool (Dispatcher::*Callback6)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3, void* p4, void* p5, void* p6);
+  typedef bool (Dispatcher::*Callback7)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3, void* p4, void* p5, void* p6,
+                                        void* p7);
+  typedef bool (Dispatcher::*Callback8)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3, void* p4, void* p5, void* p6,
+                                        void* p7, void* p8);
+  typedef bool (Dispatcher::*Callback9)(IPCInfo* ipc, void* p1, void* p2,
+                                        void* p3, void* p4, void* p5, void* p6,
+                                        void* p7, void* p8, void* p9);
+
+  // Called from the  IPC implementation when an  IPC message is ready override
+  // on a derived class to handle a set of  IPC messages. Return NULL if your
+  // subclass does not handle the message or return the pointer to the subclass
+  // that can handle it.
+  virtual Dispatcher* OnMessageReady(IPCParams* ipc, CallbackGeneric* callback);
+
+  // Called when a target proces is created, to setup the interceptions related
+  // with the given service (IPC).
+  virtual bool SetupService(InterceptionManager* manager, int service) = 0;
+
+  Dispatcher();
+  virtual ~Dispatcher();
+
+ protected:
+  // Structure that defines an IPC Call with all the parameters and the handler.
+  struct IPCCall {
+    IPCParams params;
+    CallbackGeneric callback;
+  };
+
+  // List of IPC Calls supported by the class.
+  std::vector<IPCCall> ipc_calls_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_CROSSCALL_SERVER_H_
diff --git a/sandbox/win/src/eat_resolver.cc b/sandbox/win/src/eat_resolver.cc
new file mode 100644
index 0000000..1675ce8
--- /dev/null
+++ b/sandbox/win/src/eat_resolver.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/eat_resolver.h"
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+NTSTATUS EatResolverThunk::Setup(const void* target_module,
+                                 const void* interceptor_module,
+                                 const char* target_name,
+                                 const char* interceptor_name,
+                                 const void* interceptor_entry_point,
+                                 void* thunk_storage,
+                                 size_t storage_bytes,
+                                 size_t* storage_used) {
+  NTSTATUS ret = Init(target_module, interceptor_module, target_name,
+                      interceptor_name, interceptor_entry_point,
+                      thunk_storage, storage_bytes);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  if (!eat_entry_)
+    return STATUS_INVALID_PARAMETER;
+
+#if defined(_WIN64)
+  // We have two thunks, in order: the return path and the forward path.
+  if (!SetInternalThunk(thunk_storage, storage_bytes, NULL, target_))
+    return STATUS_BUFFER_TOO_SMALL;
+
+  size_t thunk_bytes = GetInternalThunkSize();
+  storage_bytes -= thunk_bytes;
+  thunk_storage = reinterpret_cast<char*>(thunk_storage) + thunk_bytes;
+#endif
+
+  if (!SetInternalThunk(thunk_storage, storage_bytes, target_, interceptor_))
+    return STATUS_BUFFER_TOO_SMALL;
+
+  AutoProtectMemory memory;
+  ret = memory.ChangeProtection(eat_entry_, sizeof(DWORD), PAGE_READWRITE);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  // Perform the patch.
+  *eat_entry_ = static_cast<DWORD>(reinterpret_cast<uintptr_t>(thunk_storage)) -
+                static_cast<DWORD>(reinterpret_cast<uintptr_t>(target_module));
+
+  if (NULL != storage_used)
+    *storage_used = GetThunkSize();
+
+  return ret;
+}
+
+NTSTATUS EatResolverThunk::ResolveTarget(const void* module,
+                                         const char* function_name,
+                                         void** address) {
+  DCHECK_NT(address);
+  if (!module)
+    return STATUS_INVALID_PARAMETER;
+
+  base::win::PEImage pe(module);
+  if (!pe.VerifyMagic())
+    return STATUS_INVALID_IMAGE_FORMAT;
+
+  eat_entry_ = pe.GetExportEntry(function_name);
+
+  if (!eat_entry_)
+    return STATUS_PROCEDURE_NOT_FOUND;
+
+  *address = pe.RVAToAddr(*eat_entry_);
+
+  return STATUS_SUCCESS;
+}
+
+size_t EatResolverThunk::GetThunkSize() const {
+#if defined(_WIN64)
+  return GetInternalThunkSize() * 2;
+#else
+  return GetInternalThunkSize();
+#endif
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/eat_resolver.h b/sandbox/win/src/eat_resolver.h
new file mode 100644
index 0000000..1d9d430
--- /dev/null
+++ b/sandbox/win/src/eat_resolver.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_EAT_RESOLVER_H__
+#define SANDBOX_SRC_EAT_RESOLVER_H__
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/resolver.h"
+
+namespace sandbox {
+
+// This is the concrete resolver used to perform exports table interceptions.
+class EatResolverThunk : public ResolverThunk {
+ public:
+  EatResolverThunk() : eat_entry_(NULL) {}
+  ~EatResolverThunk() override {}
+
+  // Implementation of Resolver::Setup.
+  NTSTATUS Setup(const void* target_module,
+                 const void* interceptor_module,
+                 const char* target_name,
+                 const char* interceptor_name,
+                 const void* interceptor_entry_point,
+                 void* thunk_storage,
+                 size_t storage_bytes,
+                 size_t* storage_used) override;
+
+  // Implementation of Resolver::ResolveTarget.
+  NTSTATUS ResolveTarget(const void* module,
+                         const char* function_name,
+                         void** address) override;
+
+  // Implementation of Resolver::GetThunkSize.
+  size_t GetThunkSize() const override;
+
+ private:
+  // The entry to patch.
+  DWORD* eat_entry_;
+
+  DISALLOW_COPY_AND_ASSIGN(EatResolverThunk);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_EAT_RESOLVER_H__
diff --git a/sandbox/win/src/file_policy_test.cc b/sandbox/win/src/file_policy_test.cc
new file mode 100644
index 0000000..8b52362
--- /dev/null
+++ b/sandbox/win/src/file_policy_test.cc
@@ -0,0 +1,674 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <cctype>
+
+#include <windows.h>
+#include <winioctl.h>
+
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define BINDNTDLL(name) \
+  name ## Function name = reinterpret_cast<name ## Function>( \
+    ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
+
+namespace sandbox {
+
+const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+
+// Creates a file using different desired access. Returns if the call succeeded
+// or not.  The first argument in argv is the filename. The second argument
+// determines the type of access and the dispositino of the file.
+SBOX_TESTS_COMMAND int File_Create(int argc, wchar_t **argv) {
+  if (argc != 2)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  std::wstring operation(argv[0]);
+
+  if (operation == L"Read") {
+    base::win::ScopedHandle file1(CreateFile(
+        argv[1], GENERIC_READ, kSharing, NULL, OPEN_EXISTING, 0, NULL));
+    base::win::ScopedHandle file2(CreateFile(
+        argv[1], FILE_EXECUTE, kSharing, NULL, OPEN_EXISTING, 0, NULL));
+
+    if (file1.IsValid() == file2.IsValid())
+      return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+    return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
+
+  } else if (operation == L"Write") {
+    base::win::ScopedHandle file1(CreateFile(
+        argv[1], GENERIC_ALL, kSharing, NULL, OPEN_EXISTING, 0, NULL));
+    base::win::ScopedHandle file2(CreateFile(
+        argv[1], GENERIC_READ | FILE_WRITE_DATA, kSharing, NULL, OPEN_EXISTING,
+        0, NULL));
+
+    if (file1.IsValid() == file2.IsValid())
+      return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+    return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
+
+  } else if (operation == L"ReadCreate") {
+    base::win::ScopedHandle file2(CreateFile(
+        argv[1], GENERIC_READ, kSharing, NULL, CREATE_NEW, 0, NULL));
+    base::win::ScopedHandle file1(CreateFile(
+        argv[1], GENERIC_READ, kSharing, NULL, CREATE_ALWAYS, 0, NULL));
+
+    if (file1.IsValid() == file2.IsValid())
+      return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+    return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
+  }
+
+  return SBOX_TEST_INVALID_PARAMETER;
+}
+
+SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  base::string16 full_path = MakePathToSys(argv[0], false);
+  if (full_path.empty()) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  HANDLE file = ::CreateFileW(full_path.c_str(), GENERIC_READ, kSharing,
+                              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+  if (INVALID_HANDLE_VALUE != file) {
+    ::CloseHandle(file);
+    return SBOX_TEST_SUCCEEDED;
+  } else {
+    if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+      return SBOX_TEST_DENIED;
+    } else {
+      return SBOX_TEST_FAILED;
+    }
+  }
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Creates the file in parameter using the NtCreateFile api and returns if the
+// call succeeded or not.
+SBOX_TESTS_COMMAND int File_CreateSys32(int argc, wchar_t **argv) {
+  BINDNTDLL(NtCreateFile);
+  BINDNTDLL(RtlInitUnicodeString);
+  if (!NtCreateFile || !RtlInitUnicodeString)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::string16 file(argv[0]);
+  if (0 != _wcsnicmp(file.c_str(), kNTDevicePrefix, kNTDevicePrefixLen))
+    file = MakePathToSys(argv[0], true);
+
+  UNICODE_STRING object_name;
+  RtlInitUnicodeString(&object_name, file.c_str());
+
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  InitializeObjectAttributes(&obj_attributes, &object_name,
+                             OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+  HANDLE handle;
+  IO_STATUS_BLOCK io_block = {0};
+  NTSTATUS status = NtCreateFile(&handle, FILE_READ_DATA, &obj_attributes,
+                                 &io_block, NULL, 0, kSharing, FILE_OPEN,
+                                 0, NULL, 0);
+  if (NT_SUCCESS(status)) {
+    ::CloseHandle(handle);
+    return SBOX_TEST_SUCCEEDED;
+  } else if (STATUS_ACCESS_DENIED == status) {
+    return SBOX_TEST_DENIED;
+  } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
+    return SBOX_TEST_NOT_FOUND;
+  }
+  return SBOX_TEST_FAILED;
+}
+
+// Opens the file in parameter using the NtOpenFile api and returns if the
+// call succeeded or not.
+SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t **argv) {
+  BINDNTDLL(NtOpenFile);
+  BINDNTDLL(RtlInitUnicodeString);
+  if (!NtOpenFile || !RtlInitUnicodeString)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::string16 file = MakePathToSys(argv[0], true);
+  UNICODE_STRING object_name;
+  RtlInitUnicodeString(&object_name, file.c_str());
+
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  InitializeObjectAttributes(&obj_attributes, &object_name,
+                             OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+  HANDLE handle;
+  IO_STATUS_BLOCK io_block = {0};
+  NTSTATUS status = NtOpenFile(&handle, FILE_READ_DATA, &obj_attributes,
+                               &io_block, kSharing, 0);
+  if (NT_SUCCESS(status)) {
+    ::CloseHandle(handle);
+    return SBOX_TEST_SUCCEEDED;
+  } else if (STATUS_ACCESS_DENIED == status) {
+    return SBOX_TEST_DENIED;
+  } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
+    return SBOX_TEST_NOT_FOUND;
+  }
+  return SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int File_GetDiskSpace(int argc, wchar_t **argv) {
+  base::string16 sys_path = MakePathToSys(L"", false);
+  if (sys_path.empty()) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  ULARGE_INTEGER free_user = {0};
+  ULARGE_INTEGER total = {0};
+  ULARGE_INTEGER free_total = {0};
+  if (::GetDiskFreeSpaceExW(sys_path.c_str(), &free_user, &total,
+                            &free_total)) {
+    if ((total.QuadPart != 0) && (free_total.QuadPart !=0)) {
+      return SBOX_TEST_SUCCEEDED;
+    }
+  } else {
+    if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+      return SBOX_TEST_DENIED;
+    } else {
+      return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+    }
+  }
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Move a file using the MoveFileEx api and returns if the call succeeded or
+// not.
+SBOX_TESTS_COMMAND int File_Rename(int argc, wchar_t **argv) {
+  if (argc != 2)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  if (::MoveFileEx(argv[0], argv[1], 0))
+    return SBOX_TEST_SUCCEEDED;
+
+  if (::GetLastError() != ERROR_ACCESS_DENIED)
+    return SBOX_TEST_FAILED;
+
+  return SBOX_TEST_DENIED;
+}
+
+// Query the attributes of file in parameter using the NtQueryAttributesFile api
+// and NtQueryFullAttributesFile and returns if the call succeeded or not. The
+// second argument in argv is "d" or "f" telling if we expect the attributes to
+// specify a file or a directory. The expected attribute has to match the real
+// attributes for the call to be successful.
+SBOX_TESTS_COMMAND int File_QueryAttributes(int argc, wchar_t **argv) {
+  BINDNTDLL(NtQueryAttributesFile);
+  BINDNTDLL(NtQueryFullAttributesFile);
+  BINDNTDLL(RtlInitUnicodeString);
+  if (!NtQueryAttributesFile || !NtQueryFullAttributesFile ||
+      !RtlInitUnicodeString)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  if (argc != 2)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  bool expect_directory = (L'd' == argv[1][0]);
+
+  UNICODE_STRING object_name;
+  base::string16 file = MakePathToSys(argv[0], true);
+  RtlInitUnicodeString(&object_name, file.c_str());
+
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  InitializeObjectAttributes(&obj_attributes, &object_name,
+                             OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+  FILE_BASIC_INFORMATION info = {0};
+  FILE_NETWORK_OPEN_INFORMATION full_info = {0};
+  NTSTATUS status1 = NtQueryAttributesFile(&obj_attributes, &info);
+  NTSTATUS status2 = NtQueryFullAttributesFile(&obj_attributes, &full_info);
+
+  if (status1 != status2)
+    return SBOX_TEST_FAILED;
+
+  if (NT_SUCCESS(status1)) {
+    if (info.FileAttributes != full_info.FileAttributes)
+      return SBOX_TEST_FAILED;
+
+    bool is_directory1 = (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+    if (expect_directory == is_directory1)
+      return SBOX_TEST_SUCCEEDED;
+  } else if (STATUS_ACCESS_DENIED == status1) {
+    return SBOX_TEST_DENIED;
+  } else if (STATUS_OBJECT_NAME_NOT_FOUND == status1) {
+    return SBOX_TEST_NOT_FOUND;
+  }
+
+  return SBOX_TEST_FAILED;
+}
+
+TEST(FilePolicyTest, DenyNtCreateCalc) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY,
+                                  L"calc.exe"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+}
+
+TEST(FilePolicyTest, AllowNtCreateCalc) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"calc.exe"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+}
+
+TEST(FilePolicyTest, AllowNtCreateWithNativePath) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN7)
+    return;
+
+  base::string16 calc = MakePathToSys(L"calc.exe", false);
+  base::string16 nt_path;
+  ASSERT_TRUE(GetNtPathFromWin32Path(calc, &nt_path));
+  TestRunner runner;
+  runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, nt_path.c_str());
+
+  wchar_t buff[MAX_PATH];
+  ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str());
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff));
+
+  std::transform(nt_path.begin(), nt_path.end(), nt_path.begin(), std::tolower);
+  ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str());
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff));
+}
+
+TEST(FilePolicyTest, AllowReadOnly) {
+  TestRunner runner;
+
+  // Create a temp file because we need write access to it.
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t temp_file_name[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
+                               temp_file_name));
+
+  wchar_t command_read[MAX_PATH + 20] = {0};
+  wsprintf(command_read, L"File_Create Read \"%ls\"", temp_file_name);
+  wchar_t command_read_create[MAX_PATH + 20] = {0};
+  wsprintf(command_read_create, L"File_Create ReadCreate \"%ls\"",
+           temp_file_name);
+  wchar_t command_write[MAX_PATH + 20] = {0};
+  wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
+
+  // Verify that we cannot create the file after revert.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_read_create));
+
+  // Verify that we don't have write access after revert.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write));
+
+  // Verify that we have read access after revert.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_read));
+
+  // Verify that we really have write access to the file.
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write));
+
+  DeleteFile(temp_file_name);
+}
+
+// Tests support of "\\\\.\\DeviceName" kind of paths.
+TEST(FilePolicyTest, AllowImplicitDeviceName) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN7)
+    return;
+
+  TestRunner runner;
+
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t temp_file_name[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+  std::wstring path;
+  EXPECT_TRUE(ConvertToLongPath(temp_file_name, &path));
+  EXPECT_TRUE(GetNtPathFromWin32Path(path, &path));
+  path = path.substr(sandbox::kNTDevicePrefixLen);
+
+  wchar_t command[MAX_PATH + 20] = {0};
+  wsprintf(command, L"File_Create Read \"\\\\.\\%ls\"", path.c_str());
+  path = std::wstring(kNTPrefix) + path;
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, path.c_str()));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
+
+  DeleteFile(temp_file_name);
+}
+
+TEST(FilePolicyTest, AllowWildcard) {
+  TestRunner runner;
+
+  // Create a temp file because we need write access to it.
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t temp_file_name[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+  wcscat_s(temp_directory, MAX_PATH, L"*");
+  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_directory));
+
+  wchar_t command_write[MAX_PATH + 20] = {0};
+  wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
+
+  // Verify that we have write access after revert.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write));
+
+  DeleteFile(temp_file_name);
+}
+
+TEST(FilePolicyTest, AllowNtCreatePatternRule) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"App*.dll"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_OpenSys32 appmgmts.dll"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_OpenSys32 appwiz.cpl"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_OpenSys32 appmgmts.dll"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_OpenSys32 appwiz.cpl"));
+}
+
+TEST(FilePolicyTest, CheckNotFound) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"n*.dll"));
+
+  EXPECT_EQ(SBOX_TEST_NOT_FOUND,
+            runner.RunTest(L"File_OpenSys32 notfound.dll"));
+}
+
+TEST(FilePolicyTest, CheckNoLeak) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 notfound.exe"));
+}
+
+TEST(FilePolicyTest, TestQueryAttributesFile) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY,
+                                  L"appmgmts.dll"));
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY,
+                                  L"notfound.exe"));
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"drivers"));
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY,
+                                  L"ipconfig.exe"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_QueryAttributes drivers d"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_QueryAttributes appmgmts.dll f"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_QueryAttributes ipconfig.exe f"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED,
+            runner.RunTest(L"File_QueryAttributes ftp.exe f"));
+
+  EXPECT_EQ(SBOX_TEST_NOT_FOUND,
+            runner.RunTest(L"File_QueryAttributes notfound.exe f"));
+}
+
+// Makes sure that we don't leak information when there is not policy to allow
+// a path.
+TEST(FilePolicyTest, TestQueryAttributesFileNoPolicy) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_DENIED,
+            runner.RunTest(L"File_QueryAttributes ftp.exe f"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED,
+            runner.RunTest(L"File_QueryAttributes notfound.exe f"));
+}
+
+TEST(FilePolicyTest, TestRename) {
+  TestRunner runner;
+
+  // Give access to the temp directory.
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t temp_file_name1[MAX_PATH];
+  wchar_t temp_file_name2[MAX_PATH];
+  wchar_t temp_file_name3[MAX_PATH];
+  wchar_t temp_file_name4[MAX_PATH];
+  wchar_t temp_file_name5[MAX_PATH];
+  wchar_t temp_file_name6[MAX_PATH];
+  wchar_t temp_file_name7[MAX_PATH];
+  wchar_t temp_file_name8[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name1), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name2), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name3), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name4), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name5), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name6), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name7), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name8), 0u);
+
+
+  // Add rules to make file1->file2 succeed.
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name1));
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name2));
+
+  // Add rules to make file3->file4 fail.
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name3));
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
+                               temp_file_name4));
+
+  // Add rules to make file5->file6 fail.
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY,
+                               temp_file_name5));
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name6));
+
+  // Add rules to make file7->no_pol_file fail.
+  ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name7));
+
+  // Delete the files where the files are going to be renamed to.
+  ::DeleteFile(temp_file_name2);
+  ::DeleteFile(temp_file_name4);
+  ::DeleteFile(temp_file_name6);
+  ::DeleteFile(temp_file_name8);
+
+
+  wchar_t command[MAX_PATH*2 + 20] = {0};
+  wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name1,
+           temp_file_name2);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
+
+  wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name3,
+           temp_file_name4);
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+  wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name5,
+           temp_file_name6);
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+  wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name7,
+           temp_file_name8);
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+
+  // Delete all the files in case they are still there.
+  ::DeleteFile(temp_file_name1);
+  ::DeleteFile(temp_file_name2);
+  ::DeleteFile(temp_file_name3);
+  ::DeleteFile(temp_file_name4);
+  ::DeleteFile(temp_file_name5);
+  ::DeleteFile(temp_file_name6);
+  ::DeleteFile(temp_file_name7);
+  ::DeleteFile(temp_file_name8);
+}
+
+TEST(FilePolicyTest, OpenSys32FilesDenyBecauseOfDir) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY,
+                                  L"notepad.exe"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_Win32Create notepad.exe"));
+}
+
+TEST(FilePolicyTest, OpenSys32FilesAllowNotepad) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY,
+                                  L"notepad.exe"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_Win32Create notepad.exe"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create calc.exe"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"File_Win32Create notepad.exe"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_Win32Create calc.exe"));
+}
+
+TEST(FilePolicyTest, FileGetDiskSpace) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_GetDiskSpace"));
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
+
+  // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx
+  // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is
+  // denied since there is no wild card in the rule.
+  EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L""));
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
+
+  runner.SetTestState(AFTER_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe"));
+}
+
+TEST(FilePolicyTest, TestReparsePoint) {
+  TestRunner runner;
+
+  // Create a temp file because we need write access to it.
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t temp_file_name[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+  // Delete the file and create a directory instead.
+  ASSERT_TRUE(::DeleteFile(temp_file_name));
+  ASSERT_TRUE(::CreateDirectory(temp_file_name, NULL));
+
+  // Create a temporary file in the subfolder.
+  base::string16 subfolder = temp_file_name;
+  base::string16 temp_file_title = subfolder.substr(subfolder.rfind(L"\\") + 1);
+  base::string16 temp_file = subfolder + L"\\file_" + temp_file_title;
+
+  HANDLE file = ::CreateFile(temp_file.c_str(), FILE_ALL_ACCESS,
+                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                             CREATE_ALWAYS, 0, NULL);
+  ASSERT_TRUE(INVALID_HANDLE_VALUE != file);
+  ASSERT_TRUE(::CloseHandle(file));
+
+  // Create a temporary file in the temp directory.
+  base::string16 temp_dir = temp_directory;
+  base::string16 temp_file_in_temp = temp_dir + L"file_" + temp_file_title;
+  file = ::CreateFile(temp_file_in_temp.c_str(), FILE_ALL_ACCESS,
+                      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                      CREATE_ALWAYS, 0, NULL);
+  ASSERT_TRUE(file != NULL);
+  ASSERT_TRUE(::CloseHandle(file));
+
+  // Give write access to the temp directory.
+  base::string16 temp_dir_wildcard = temp_dir + L"*";
+  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY,
+                               temp_dir_wildcard.c_str()));
+
+  // Prepare the command to execute.
+  base::string16 command_write;
+  command_write += L"File_Create Write \"";
+  command_write += temp_file;
+  command_write += L"\"";
+
+  // Verify that we have write access to the original file
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write.c_str()));
+
+  // Replace the subfolder by a reparse point to %temp%.
+  ::DeleteFile(temp_file.c_str());
+  HANDLE dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
+
+  base::string16 temp_dir_nt;
+  temp_dir_nt += L"\\??\\";
+  temp_dir_nt += temp_dir;
+  EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
+  EXPECT_TRUE(::CloseHandle(dir));
+
+  // Try to open the file again.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write.c_str()));
+
+  // Remove the reparse point.
+  dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS,
+                     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+                     FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+                     NULL);
+  EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
+  EXPECT_TRUE(DeleteReparsePoint(dir));
+  EXPECT_TRUE(::CloseHandle(dir));
+
+  // Cleanup.
+  EXPECT_TRUE(::DeleteFile(temp_file_in_temp.c_str()));
+  EXPECT_TRUE(::RemoveDirectory(subfolder.c_str()));
+}
+
+TEST(FilePolicyTest, CheckExistingNTPrefixEscape) {
+  base::string16 name = L"\\??\\NAME";
+
+  base::string16 result = FixNTPrefixForMatch(name);
+
+  EXPECT_STREQ(result.c_str(), L"\\/?/?\\NAME");
+}
+
+TEST(FilePolicyTest, CheckEscapedNTPrefixNoEscape) {
+  base::string16 name = L"\\/?/?\\NAME";
+
+  base::string16 result = FixNTPrefixForMatch(name);
+
+  EXPECT_STREQ(result.c_str(), name.c_str());
+}
+
+TEST(FilePolicyTest, CheckMissingNTPrefixEscape) {
+  base::string16 name = L"C:\\NAME";
+
+  base::string16 result = FixNTPrefixForMatch(name);
+
+  EXPECT_STREQ(result.c_str(), L"\\/?/?\\C:\\NAME");
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/filesystem_dispatcher.cc b/sandbox/win/src/filesystem_dispatcher.cc
new file mode 100644
index 0000000..4561be4
--- /dev/null
+++ b/sandbox/win/src/filesystem_dispatcher.cc
@@ -0,0 +1,314 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/filesystem_dispatcher.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/filesystem_interception.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+FilesystemDispatcher::FilesystemDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall create_params = {
+    {IPC_NTCREATEFILE_TAG, WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE,
+     UINT32_TYPE, UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&FilesystemDispatcher::NtCreateFile)
+  };
+
+  static const IPCCall open_file = {
+    {IPC_NTOPENFILE_TAG, WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE,
+     UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&FilesystemDispatcher::NtOpenFile)
+  };
+
+  static const IPCCall attribs = {
+    {IPC_NTQUERYATTRIBUTESFILE_TAG, WCHAR_TYPE, UINT32_TYPE, INOUTPTR_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &FilesystemDispatcher::NtQueryAttributesFile)
+  };
+
+  static const IPCCall full_attribs = {
+    {IPC_NTQUERYFULLATTRIBUTESFILE_TAG, WCHAR_TYPE, UINT32_TYPE, INOUTPTR_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+          &FilesystemDispatcher::NtQueryFullAttributesFile)
+  };
+
+  static const IPCCall set_info = {
+    {IPC_NTSETINFO_RENAME_TAG, VOIDPTR_TYPE, INOUTPTR_TYPE, INOUTPTR_TYPE,
+     UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &FilesystemDispatcher::NtSetInformationFile)
+  };
+
+  ipc_calls_.push_back(create_params);
+  ipc_calls_.push_back(open_file);
+  ipc_calls_.push_back(attribs);
+  ipc_calls_.push_back(full_attribs);
+  ipc_calls_.push_back(set_info);
+}
+
+bool FilesystemDispatcher::SetupService(InterceptionManager* manager,
+                                        int service) {
+  switch (service) {
+    case IPC_NTCREATEFILE_TAG:
+      return INTERCEPT_NT(manager, NtCreateFile, CREATE_FILE_ID, 48);
+
+    case IPC_NTOPENFILE_TAG:
+      return INTERCEPT_NT(manager, NtOpenFile, OPEN_FILE_ID, 28);
+
+    case IPC_NTQUERYATTRIBUTESFILE_TAG:
+      return INTERCEPT_NT(manager, NtQueryAttributesFile, QUERY_ATTRIB_FILE_ID,
+                          12);
+
+    case IPC_NTQUERYFULLATTRIBUTESFILE_TAG:
+        return INTERCEPT_NT(manager, NtQueryFullAttributesFile,
+                            QUERY_FULL_ATTRIB_FILE_ID, 12);
+
+    case IPC_NTSETINFO_RENAME_TAG:
+      return INTERCEPT_NT(manager, NtSetInformationFile, SET_INFO_FILE_ID, 24);
+
+    default:
+      return false;
+  }
+}
+
+bool FilesystemDispatcher::NtCreateFile(IPCInfo* ipc,
+                                        base::string16* name,
+                                        uint32 attributes,
+                                        uint32 desired_access,
+                                        uint32 file_attributes,
+                                        uint32 share_access,
+                                        uint32 create_disposition,
+                                        uint32 create_options) {
+  if (!PreProcessName(*name, name)) {
+    // The path requested might contain a reparse point.
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  const wchar_t* filename = name->c_str();
+
+  uint32 broker = TRUE;
+  CountedParameterSet<OpenFile> params;
+  params[OpenFile::NAME] = ParamPickerMake(filename);
+  params[OpenFile::ACCESS] = ParamPickerMake(desired_access);
+  params[OpenFile::DISPOSITION] = ParamPickerMake(create_disposition);
+  params[OpenFile::OPTIONS] = ParamPickerMake(create_options);
+  params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+  // To evaluate the policy we need to call back to the policy object. We
+  // are just middlemen in the operation since is the FileSystemPolicy which
+  // knows what to do.
+  EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEFILE_TAG,
+                                               params.GetBase());
+  HANDLE handle;
+  ULONG_PTR io_information = 0;
+  NTSTATUS nt_status;
+  if (!FileSystemPolicy::CreateFileAction(result, *ipc->client_info, *name,
+                                          attributes, desired_access,
+                                          file_attributes, share_access,
+                                          create_disposition, create_options,
+                                          &handle, &nt_status,
+                                          &io_information)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+  // Return operation status on the IPC.
+  ipc->return_info.extended[0].ulong_ptr = io_information;
+  ipc->return_info.nt_status = nt_status;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool FilesystemDispatcher::NtOpenFile(IPCInfo* ipc,
+                                      base::string16* name,
+                                      uint32 attributes,
+                                      uint32 desired_access,
+                                      uint32 share_access,
+                                      uint32 open_options) {
+  if (!PreProcessName(*name, name)) {
+    // The path requested might contain a reparse point.
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  const wchar_t* filename = name->c_str();
+
+  uint32 broker = TRUE;
+  uint32 create_disposition = FILE_OPEN;
+  CountedParameterSet<OpenFile> params;
+  params[OpenFile::NAME] = ParamPickerMake(filename);
+  params[OpenFile::ACCESS] = ParamPickerMake(desired_access);
+  params[OpenFile::DISPOSITION] = ParamPickerMake(create_disposition);
+  params[OpenFile::OPTIONS] = ParamPickerMake(open_options);
+  params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+  // To evaluate the policy we need to call back to the policy object. We
+  // are just middlemen in the operation since is the FileSystemPolicy which
+  // knows what to do.
+  EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENFILE_TAG,
+                                               params.GetBase());
+  HANDLE handle;
+  ULONG_PTR io_information = 0;
+  NTSTATUS nt_status;
+  if (!FileSystemPolicy::OpenFileAction(result, *ipc->client_info, *name,
+                                        attributes, desired_access,
+                                        share_access, open_options, &handle,
+                                        &nt_status, &io_information)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+  // Return operation status on the IPC.
+  ipc->return_info.extended[0].ulong_ptr = io_information;
+  ipc->return_info.nt_status = nt_status;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool FilesystemDispatcher::NtQueryAttributesFile(IPCInfo* ipc,
+                                                 base::string16* name,
+                                                 uint32 attributes,
+                                                 CountedBuffer* info) {
+  if (sizeof(FILE_BASIC_INFORMATION) != info->Size())
+    return false;
+
+  if (!PreProcessName(*name, name)) {
+    // The path requested might contain a reparse point.
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  uint32 broker = TRUE;
+  const wchar_t* filename = name->c_str();
+  CountedParameterSet<FileName> params;
+  params[FileName::NAME] = ParamPickerMake(filename);
+  params[FileName::BROKER] = ParamPickerMake(broker);
+
+  // To evaluate the policy we need to call back to the policy object. We
+  // are just middlemen in the operation since is the FileSystemPolicy which
+  // knows what to do.
+  EvalResult result = policy_base_->EvalPolicy(IPC_NTQUERYATTRIBUTESFILE_TAG,
+                                               params.GetBase());
+
+  FILE_BASIC_INFORMATION* information =
+        reinterpret_cast<FILE_BASIC_INFORMATION*>(info->Buffer());
+  NTSTATUS nt_status;
+  if (!FileSystemPolicy::QueryAttributesFileAction(result, *ipc->client_info,
+                                                   *name, attributes,
+                                                   information, &nt_status)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  // Return operation status on the IPC.
+  ipc->return_info.nt_status = nt_status;
+  return true;
+}
+
+bool FilesystemDispatcher::NtQueryFullAttributesFile(IPCInfo* ipc,
+                                                     base::string16* name,
+                                                     uint32 attributes,
+                                                     CountedBuffer* info) {
+  if (sizeof(FILE_NETWORK_OPEN_INFORMATION) != info->Size())
+    return false;
+
+  if (!PreProcessName(*name, name)) {
+    // The path requested might contain a reparse point.
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  uint32 broker = TRUE;
+  const wchar_t* filename = name->c_str();
+  CountedParameterSet<FileName> params;
+  params[FileName::NAME] = ParamPickerMake(filename);
+  params[FileName::BROKER] = ParamPickerMake(broker);
+
+  // To evaluate the policy we need to call back to the policy object. We
+  // are just middlemen in the operation since is the FileSystemPolicy which
+  // knows what to do.
+  EvalResult result = policy_base_->EvalPolicy(
+                          IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase());
+
+  FILE_NETWORK_OPEN_INFORMATION* information =
+        reinterpret_cast<FILE_NETWORK_OPEN_INFORMATION*>(info->Buffer());
+  NTSTATUS nt_status;
+  if (!FileSystemPolicy::QueryFullAttributesFileAction(result,
+                                                       *ipc->client_info,
+                                                       *name, attributes,
+                                                       information,
+                                                       &nt_status)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  // Return operation status on the IPC.
+  ipc->return_info.nt_status = nt_status;
+  return true;
+}
+
+bool FilesystemDispatcher::NtSetInformationFile(IPCInfo* ipc,
+                                                HANDLE handle,
+                                                CountedBuffer* status,
+                                                CountedBuffer* info,
+                                                uint32 length,
+                                                uint32 info_class) {
+  if (sizeof(IO_STATUS_BLOCK) != status->Size())
+    return false;
+  if (length != info->Size())
+    return false;
+
+  FILE_RENAME_INFORMATION* rename_info =
+      reinterpret_cast<FILE_RENAME_INFORMATION*>(info->Buffer());
+
+  if (!IsSupportedRenameCall(rename_info, length, info_class))
+    return false;
+
+  base::string16 name;
+  name.assign(rename_info->FileName, rename_info->FileNameLength /
+                                     sizeof(rename_info->FileName[0]));
+  if (!PreProcessName(name, &name)) {
+    // The path requested might contain a reparse point.
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  uint32 broker = TRUE;
+  const wchar_t* filename = name.c_str();
+  CountedParameterSet<FileName> params;
+  params[FileName::NAME] = ParamPickerMake(filename);
+  params[FileName::BROKER] = ParamPickerMake(broker);
+
+  // To evaluate the policy we need to call back to the policy object. We
+  // are just middlemen in the operation since is the FileSystemPolicy which
+  // knows what to do.
+  EvalResult result = policy_base_->EvalPolicy(IPC_NTSETINFO_RENAME_TAG,
+                                               params.GetBase());
+
+  IO_STATUS_BLOCK* io_status =
+        reinterpret_cast<IO_STATUS_BLOCK*>(status->Buffer());
+  NTSTATUS nt_status;
+  if (!FileSystemPolicy::SetInformationFileAction(result, *ipc->client_info,
+                                                  handle, rename_info, length,
+                                                  info_class, io_status,
+                                                  &nt_status)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  // Return operation status on the IPC.
+  ipc->return_info.nt_status = nt_status;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/filesystem_dispatcher.h b/sandbox/win/src/filesystem_dispatcher.h
new file mode 100644
index 0000000..192d36c
--- /dev/null
+++ b/sandbox/win/src/filesystem_dispatcher.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_FILESYSTEM_DISPATCHER_H__
+#define SANDBOX_SRC_FILESYSTEM_DISPATCHER_H__
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles file system-related IPC calls.
+class FilesystemDispatcher : public Dispatcher {
+ public:
+  explicit FilesystemDispatcher(PolicyBase* policy_base);
+  ~FilesystemDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to NtCreateFile in the target.
+  bool NtCreateFile(IPCInfo* ipc,
+                    base::string16* name,
+                    uint32 attributes,
+                    uint32 desired_access,
+                    uint32 file_attributes,
+                    uint32 share_access,
+                    uint32 create_disposition,
+                    uint32 create_options);
+
+  // Processes IPC requests coming from calls to NtOpenFile in the target.
+  bool NtOpenFile(IPCInfo* ipc,
+                  base::string16* name,
+                  uint32 attributes,
+                  uint32 desired_access,
+                  uint32 share_access,
+                  uint32 create_options);
+
+    // Processes IPC requests coming from calls to NtQueryAttributesFile in the
+  // target.
+  bool NtQueryAttributesFile(IPCInfo* ipc,
+                             base::string16* name,
+                             uint32 attributes,
+                             CountedBuffer* info);
+
+  // Processes IPC requests coming from calls to NtQueryFullAttributesFile in
+  // the target.
+  bool NtQueryFullAttributesFile(IPCInfo* ipc,
+                                 base::string16* name,
+                                 uint32 attributes,
+                                 CountedBuffer* info);
+
+  // Processes IPC requests coming from calls to NtSetInformationFile with the
+  // rename information class.
+  bool NtSetInformationFile(IPCInfo* ipc,
+                            HANDLE handle,
+                            CountedBuffer* status,
+                            CountedBuffer* info,
+                            uint32 length,
+                            uint32 info_class);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(FilesystemDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_FILESYSTEM_DISPATCHER_H__
diff --git a/sandbox/win/src/filesystem_interception.cc b/sandbox/win/src/filesystem_interception.cc
new file mode 100644
index 0000000..459f7ac
--- /dev/null
+++ b/sandbox/win/src/filesystem_interception.cc
@@ -0,0 +1,367 @@
+// 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 "sandbox/win/src/filesystem_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+NTSTATUS WINAPI TargetNtCreateFile(NtCreateFileFunction orig_CreateFile,
+                                   PHANDLE file, ACCESS_MASK desired_access,
+                                   POBJECT_ATTRIBUTES object_attributes,
+                                   PIO_STATUS_BLOCK io_status,
+                                   PLARGE_INTEGER allocation_size,
+                                   ULONG file_attributes, ULONG sharing,
+                                   ULONG disposition, ULONG options,
+                                   PVOID ea_buffer, ULONG ea_length) {
+  // Check if the process can open it first.
+  NTSTATUS status = orig_CreateFile(file, desired_access, object_attributes,
+                                    io_status, allocation_size,
+                                    file_attributes, sharing, disposition,
+                                    options, ea_buffer, ea_length);
+  if (STATUS_ACCESS_DENIED != status)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  wchar_t* name = NULL;
+  do {
+    if (!ValidParameter(file, sizeof(HANDLE), WRITE))
+      break;
+    if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || NULL == name)
+      break;
+
+    uint32 desired_access_uint32 = desired_access;
+    uint32 options_uint32 = options;
+    uint32 disposition_uint32 = disposition;
+    uint32 broker = FALSE;
+    CountedParameterSet<OpenFile> params;
+    params[OpenFile::NAME] = ParamPickerMake(name);
+    params[OpenFile::ACCESS] = ParamPickerMake(desired_access_uint32);
+    params[OpenFile::DISPOSITION] = ParamPickerMake(disposition_uint32);
+    params[OpenFile::OPTIONS] = ParamPickerMake(options_uint32);
+    params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+    if (!QueryBroker(IPC_NTCREATEFILE_TAG, params.GetBase()))
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    // The following call must match in the parameters with
+    // FilesystemDispatcher::ProcessNtCreateFile.
+    ResultCode code = CrossCall(ipc, IPC_NTCREATEFILE_TAG, name, attributes,
+                                desired_access_uint32, file_attributes, sharing,
+                                disposition, options_uint32, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    status = answer.nt_status;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      break;
+
+    __try {
+      *file = answer.handle;
+      io_status->Status = answer.nt_status;
+      io_status->Information = answer.extended[0].ulong_ptr;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  if (name)
+    operator delete(name, NT_ALLOC);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenFile(NtOpenFileFunction orig_OpenFile, PHANDLE file,
+                                 ACCESS_MASK desired_access,
+                                 POBJECT_ATTRIBUTES object_attributes,
+                                 PIO_STATUS_BLOCK io_status, ULONG sharing,
+                                 ULONG options) {
+  // Check if the process can open it first.
+  NTSTATUS status = orig_OpenFile(file, desired_access, object_attributes,
+                                  io_status, sharing, options);
+  if (STATUS_ACCESS_DENIED != status)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  wchar_t* name = NULL;
+  do {
+    if (!ValidParameter(file, sizeof(HANDLE), WRITE))
+      break;
+    if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    uint32 attributes;
+    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || NULL == name)
+      break;
+
+    uint32 desired_access_uint32 = desired_access;
+    uint32 options_uint32 = options;
+    uint32 disposition_uint32 = FILE_OPEN;
+    uint32 broker = FALSE;
+    CountedParameterSet<OpenFile> params;
+    params[OpenFile::NAME] = ParamPickerMake(name);
+    params[OpenFile::ACCESS] = ParamPickerMake(desired_access_uint32);
+    params[OpenFile::DISPOSITION] = ParamPickerMake(disposition_uint32);
+    params[OpenFile::OPTIONS] = ParamPickerMake(options_uint32);
+    params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+    if (!QueryBroker(IPC_NTOPENFILE_TAG, params.GetBase()))
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTOPENFILE_TAG, name, attributes,
+                                desired_access_uint32, sharing, options_uint32,
+                                &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    status = answer.nt_status;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      break;
+
+    __try {
+      *file = answer.handle;
+      io_status->Status = answer.nt_status;
+      io_status->Information = answer.extended[0].ulong_ptr;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  if (name)
+    operator delete(name, NT_ALLOC);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtQueryAttributesFile(
+    NtQueryAttributesFileFunction orig_QueryAttributes,
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_BASIC_INFORMATION file_attributes) {
+  // Check if the process can query it first.
+  NTSTATUS status = orig_QueryAttributes(object_attributes, file_attributes);
+  if (STATUS_ACCESS_DENIED != status)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  wchar_t* name = NULL;
+  do {
+    if (!ValidParameter(file_attributes, sizeof(FILE_BASIC_INFORMATION), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || NULL == name)
+      break;
+
+    InOutCountedBuffer file_info(file_attributes,
+                                 sizeof(FILE_BASIC_INFORMATION));
+
+    uint32 broker = FALSE;
+    CountedParameterSet<FileName> params;
+    params[FileName::NAME] = ParamPickerMake(name);
+    params[FileName::BROKER] = ParamPickerMake(broker);
+
+    if (!QueryBroker(IPC_NTQUERYATTRIBUTESFILE_TAG, params.GetBase()))
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTQUERYATTRIBUTESFILE_TAG, name,
+                                attributes, file_info, &answer);
+
+    if (SBOX_ALL_OK != code)
+      break;
+
+    status = answer.nt_status;
+
+  } while (false);
+
+  if (name)
+    operator delete(name, NT_ALLOC);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtQueryFullAttributesFile(
+    NtQueryFullAttributesFileFunction orig_QueryFullAttributes,
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_NETWORK_OPEN_INFORMATION file_attributes) {
+  // Check if the process can query it first.
+  NTSTATUS status = orig_QueryFullAttributes(object_attributes,
+                                             file_attributes);
+  if (STATUS_ACCESS_DENIED != status)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  wchar_t* name = NULL;
+  do {
+    if (!ValidParameter(file_attributes, sizeof(FILE_NETWORK_OPEN_INFORMATION),
+                        WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || NULL == name)
+      break;
+
+    InOutCountedBuffer file_info(file_attributes,
+                                 sizeof(FILE_NETWORK_OPEN_INFORMATION));
+
+    uint32 broker = FALSE;
+    CountedParameterSet<FileName> params;
+    params[FileName::NAME] = ParamPickerMake(name);
+    params[FileName::BROKER] = ParamPickerMake(broker);
+
+    if (!QueryBroker(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase()))
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTQUERYFULLATTRIBUTESFILE_TAG, name,
+                                attributes, file_info, &answer);
+
+    if (SBOX_ALL_OK != code)
+      break;
+
+    status = answer.nt_status;
+  } while (false);
+
+  if (name)
+    operator delete(name, NT_ALLOC);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtSetInformationFile(
+    NtSetInformationFileFunction orig_SetInformationFile, HANDLE file,
+    PIO_STATUS_BLOCK io_status, PVOID file_info, ULONG length,
+    FILE_INFORMATION_CLASS file_info_class) {
+  // Check if the process can open it first.
+  NTSTATUS status = orig_SetInformationFile(file, io_status, file_info, length,
+                                            file_info_class);
+  if (STATUS_ACCESS_DENIED != status)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  wchar_t* name = NULL;
+  do {
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
+      break;
+
+    if (!ValidParameter(file_info, length, READ))
+      break;
+
+    FILE_RENAME_INFORMATION* file_rename_info =
+        reinterpret_cast<FILE_RENAME_INFORMATION*>(file_info);
+    OBJECT_ATTRIBUTES object_attributes;
+    UNICODE_STRING object_name;
+    InitializeObjectAttributes(&object_attributes, &object_name, 0, NULL, NULL);
+
+    __try {
+      if (!IsSupportedRenameCall(file_rename_info, length, file_info_class))
+        break;
+
+      object_attributes.RootDirectory = file_rename_info->RootDirectory;
+      object_name.Buffer = file_rename_info->FileName;
+      object_name.Length = object_name.MaximumLength =
+          static_cast<USHORT>(file_rename_info->FileNameLength);
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    NTSTATUS ret = AllocAndCopyName(&object_attributes, &name, NULL, NULL);
+    if (!NT_SUCCESS(ret) || !name)
+      break;
+
+    uint32 broker = FALSE;
+    CountedParameterSet<FileName> params;
+    params[FileName::NAME] = ParamPickerMake(name);
+    params[FileName::BROKER] = ParamPickerMake(broker);
+
+    if (!QueryBroker(IPC_NTSETINFO_RENAME_TAG, params.GetBase()))
+      break;
+
+    InOutCountedBuffer io_status_buffer(io_status, sizeof(IO_STATUS_BLOCK));
+    // This is actually not an InOut buffer, only In, but using InOut facility
+    // really helps to simplify the code.
+    InOutCountedBuffer file_info_buffer(file_info, length);
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTSETINFO_RENAME_TAG, file,
+                                io_status_buffer, file_info_buffer, length,
+                                file_info_class, &answer);
+
+    if (SBOX_ALL_OK != code)
+      break;
+
+    status = answer.nt_status;
+  } while (false);
+
+  if (name)
+    operator delete(name, NT_ALLOC);
+
+  return status;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/filesystem_interception.h b/sandbox/win/src/filesystem_interception.h
new file mode 100644
index 0000000..2fafb44
--- /dev/null
+++ b/sandbox/win/src/filesystem_interception.h
@@ -0,0 +1,53 @@
+// 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 "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_FILESYSTEM_INTERCEPTION_H__
+#define SANDBOX_SRC_FILESYSTEM_INTERCEPTION_H__
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtCreateFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateFile(
+    NtCreateFileFunction orig_CreateFile, PHANDLE file,
+    ACCESS_MASK desired_access, POBJECT_ATTRIBUTES object_attributes,
+    PIO_STATUS_BLOCK io_status, PLARGE_INTEGER allocation_size,
+    ULONG file_attributes, ULONG sharing, ULONG disposition, ULONG options,
+    PVOID ea_buffer, ULONG ea_length);
+
+// Interception of NtOpenFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenFile(
+    NtOpenFileFunction orig_OpenFile, PHANDLE file, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PIO_STATUS_BLOCK io_status,
+    ULONG sharing, ULONG options);
+
+// Interception of NtQueryAtttributesFile on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryAttributesFile(
+    NtQueryAttributesFileFunction orig_QueryAttributes,
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_BASIC_INFORMATION file_attributes);
+
+// Interception of NtQueryFullAtttributesFile on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryFullAttributesFile(
+    NtQueryFullAttributesFileFunction orig_QueryAttributes,
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_NETWORK_OPEN_INFORMATION file_attributes);
+
+// Interception of NtSetInformationFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtSetInformationFile(
+    NtSetInformationFileFunction orig_SetInformationFile, HANDLE file,
+    PIO_STATUS_BLOCK io_status, PVOID file_information, ULONG length,
+    FILE_INFORMATION_CLASS file_information_class);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_FILESYSTEM_INTERCEPTION_H__
diff --git a/sandbox/win/src/filesystem_policy.cc b/sandbox/win/src/filesystem_policy.cc
new file mode 100644
index 0000000..0349ff3
--- /dev/null
+++ b/sandbox/win/src/filesystem_policy.cc
@@ -0,0 +1,430 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "sandbox/win/src/filesystem_policy.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
+                              ACCESS_MASK desired_access,
+                              OBJECT_ATTRIBUTES* obj_attributes,
+                              IO_STATUS_BLOCK* io_status_block,
+                              ULONG file_attributes,
+                              ULONG share_access,
+                              ULONG create_disposition,
+                              ULONG create_options,
+                              PVOID ea_buffer,
+                              ULONG ea_lenght,
+                              HANDLE target_process) {
+  NtCreateFileFunction NtCreateFile = NULL;
+  ResolveNTFunctionPtr("NtCreateFile", &NtCreateFile);
+
+  HANDLE local_handle = INVALID_HANDLE_VALUE;
+  NTSTATUS status = NtCreateFile(&local_handle, desired_access, obj_attributes,
+                                 io_status_block, NULL, file_attributes,
+                                 share_access, create_disposition,
+                                 create_options, ea_buffer, ea_lenght);
+  if (!NT_SUCCESS(status)) {
+    return status;
+  }
+
+  if (!sandbox::SameObject(local_handle, obj_attributes->ObjectName->Buffer)) {
+    // The handle points somewhere else. Fail the operation.
+    ::CloseHandle(local_handle);
+    return STATUS_ACCESS_DENIED;
+  }
+
+  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                         target_process, target_file_handle, 0, FALSE,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return STATUS_ACCESS_DENIED;
+  }
+  return STATUS_SUCCESS;
+}
+
+// Get an initialized anonymous level Security QOS.
+SECURITY_QUALITY_OF_SERVICE GetAnonymousQOS() {
+  SECURITY_QUALITY_OF_SERVICE security_qos = {0};
+  security_qos.Length = sizeof(security_qos);
+  security_qos.ImpersonationLevel = SecurityAnonymous;
+  // Set dynamic tracking so that a pipe doesn't capture the broker's token
+  security_qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+  security_qos.EffectiveOnly = TRUE;
+
+  return security_qos;
+}
+
+}  // namespace.
+
+namespace sandbox {
+
+bool FileSystemPolicy::GenerateRules(const wchar_t* name,
+                                     TargetPolicy::Semantics semantics,
+                                     LowLevelPolicy* policy) {
+  base::string16 mod_name(name);
+  if (mod_name.empty()) {
+    return false;
+  }
+
+  if (!PreProcessName(mod_name, &mod_name)) {
+    // The path to be added might contain a reparse point.
+    NOTREACHED();
+    return false;
+  }
+
+  // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
+  // infrastructure to normalize names. In any case we need to escape the
+  // question marks.
+  if (_wcsnicmp(mod_name.c_str(), kNTDevicePrefix, kNTDevicePrefixLen)) {
+    mod_name = FixNTPrefixForMatch(mod_name);
+    name = mod_name.c_str();
+  }
+
+  EvalResult result = ASK_BROKER;
+
+  // List of supported calls for the filesystem.
+  const unsigned kCallNtCreateFile = 0x1;
+  const unsigned kCallNtOpenFile = 0x2;
+  const unsigned kCallNtQueryAttributesFile = 0x4;
+  const unsigned kCallNtQueryFullAttributesFile = 0x8;
+  const unsigned kCallNtSetInfoRename = 0x10;
+
+  DWORD  rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
+                       kCallNtQueryAttributesFile |
+                       kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
+
+  PolicyRule create(result);
+  PolicyRule open(result);
+  PolicyRule query(result);
+  PolicyRule query_full(result);
+  PolicyRule rename(result);
+
+  switch (semantics) {
+    case TargetPolicy::FILES_ALLOW_DIR_ANY: {
+      open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
+      create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
+      break;
+    }
+    case TargetPolicy::FILES_ALLOW_READONLY: {
+      // We consider all flags that are not known to be readonly as potentially
+      // used for write.
+      DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
+                            FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
+                            GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
+      DWORD restricted_flags = ~allowed_flags;
+      open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
+      open.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
+      create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
+      create.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
+
+      // Read only access don't work for rename.
+      rule_to_add &= ~kCallNtSetInfoRename;
+      break;
+    }
+    case TargetPolicy::FILES_ALLOW_QUERY: {
+      // Here we don't want to add policy for the open or the create.
+      rule_to_add &= ~(kCallNtOpenFile | kCallNtCreateFile |
+                       kCallNtSetInfoRename);
+      break;
+    }
+    case TargetPolicy::FILES_ALLOW_ANY: {
+      break;
+    }
+    default: {
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  if ((rule_to_add & kCallNtCreateFile) &&
+      (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+       !policy->AddRule(IPC_NTCREATEFILE_TAG, &create))) {
+    return false;
+  }
+
+  if ((rule_to_add & kCallNtOpenFile) &&
+      (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+       !policy->AddRule(IPC_NTOPENFILE_TAG, &open))) {
+    return false;
+  }
+
+  if ((rule_to_add & kCallNtQueryAttributesFile) &&
+      (!query.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
+       !policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &query))) {
+    return false;
+  }
+
+  if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
+      (!query_full.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE)
+       || !policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
+                           &query_full))) {
+    return false;
+  }
+
+  if ((rule_to_add & kCallNtSetInfoRename) &&
+      (!rename.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
+       !policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &rename))) {
+    return false;
+  }
+
+  return true;
+}
+
+// Right now we insert two rules, to be evaluated before any user supplied rule:
+// - go to the broker if the path doesn't look like the paths that we push on
+//    the policy (namely \??\something).
+// - go to the broker if it looks like this is a short-name path.
+//
+// It is possible to add a rule to go to the broker in any case; it would look
+// something like:
+//    rule = new PolicyRule(ASK_BROKER);
+//    rule->AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
+//    policy->AddRule(service, rule);
+bool FileSystemPolicy::SetInitialRules(LowLevelPolicy* policy) {
+  PolicyRule format(ASK_BROKER);
+  PolicyRule short_name(ASK_BROKER);
+
+  bool rv = format.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
+  rv &= format.AddStringMatch(IF_NOT, FileName::NAME, L"\\/?/?\\*",
+                              CASE_SENSITIVE);
+
+  rv &= short_name.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
+  rv &= short_name.AddStringMatch(IF, FileName::NAME, L"*~*", CASE_SENSITIVE);
+
+  if (!rv || !policy->AddRule(IPC_NTCREATEFILE_TAG, &format))
+    return false;
+
+  if (!policy->AddRule(IPC_NTCREATEFILE_TAG, &short_name))
+    return false;
+
+  if (!policy->AddRule(IPC_NTOPENFILE_TAG, &format))
+    return false;
+
+  if (!policy->AddRule(IPC_NTOPENFILE_TAG, &short_name))
+    return false;
+
+  if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &format))
+    return false;
+
+  if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &short_name))
+    return false;
+
+  if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &format))
+    return false;
+
+  if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &short_name))
+    return false;
+
+  if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &format))
+    return false;
+
+  if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &short_name))
+    return false;
+
+  return true;
+}
+
+bool FileSystemPolicy::CreateFileAction(EvalResult eval_result,
+                                        const ClientInfo& client_info,
+                                        const base::string16 &file,
+                                        uint32 attributes,
+                                        uint32 desired_access,
+                                        uint32 file_attributes,
+                                        uint32 share_access,
+                                        uint32 create_disposition,
+                                        uint32 create_options,
+                                        HANDLE *handle,
+                                        NTSTATUS* nt_status,
+                                        ULONG_PTR *io_information) {
+  // The only action supported is ASK_BROKER which means create the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return false;
+  }
+  IO_STATUS_BLOCK io_block = {0};
+  UNICODE_STRING uni_name = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+  InitObjectAttribs(file, attributes, NULL, &obj_attributes,
+                    &uni_name, IsPipe(file) ? &security_qos : NULL);
+  *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
+                                    &io_block, file_attributes, share_access,
+                                    create_disposition, create_options, NULL,
+                                    0, client_info.process);
+
+  *io_information = io_block.Information;
+  return true;
+}
+
+bool FileSystemPolicy::OpenFileAction(EvalResult eval_result,
+                                      const ClientInfo& client_info,
+                                      const base::string16 &file,
+                                      uint32 attributes,
+                                      uint32 desired_access,
+                                      uint32 share_access,
+                                      uint32 open_options,
+                                      HANDLE *handle,
+                                      NTSTATUS* nt_status,
+                                      ULONG_PTR *io_information) {
+  // The only action supported is ASK_BROKER which means open the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+  // An NtOpen is equivalent to an NtCreate with FileAttributes = 0 and
+  // CreateDisposition = FILE_OPEN.
+  IO_STATUS_BLOCK io_block = {0};
+  UNICODE_STRING uni_name = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+  InitObjectAttribs(file, attributes, NULL, &obj_attributes,
+                    &uni_name, IsPipe(file) ? &security_qos : NULL);
+  *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
+                                    &io_block, 0, share_access, FILE_OPEN,
+                                    open_options, NULL, 0,
+                                    client_info.process);
+
+  *io_information = io_block.Information;
+  return true;
+}
+
+bool FileSystemPolicy::QueryAttributesFileAction(
+    EvalResult eval_result,
+    const ClientInfo& client_info,
+    const base::string16 &file,
+    uint32 attributes,
+    FILE_BASIC_INFORMATION* file_info,
+    NTSTATUS* nt_status) {
+  // The only action supported is ASK_BROKER which means query the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  NtQueryAttributesFileFunction NtQueryAttributesFile = NULL;
+  ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
+
+  UNICODE_STRING uni_name = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+  InitObjectAttribs(file, attributes, NULL, &obj_attributes,
+                    &uni_name, IsPipe(file) ? &security_qos : NULL);
+  *nt_status = NtQueryAttributesFile(&obj_attributes, file_info);
+
+  return true;
+}
+
+bool FileSystemPolicy::QueryFullAttributesFileAction(
+    EvalResult eval_result,
+    const ClientInfo& client_info,
+    const base::string16 &file,
+    uint32 attributes,
+    FILE_NETWORK_OPEN_INFORMATION* file_info,
+    NTSTATUS* nt_status) {
+  // The only action supported is ASK_BROKER which means query the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  NtQueryFullAttributesFileFunction NtQueryFullAttributesFile = NULL;
+  ResolveNTFunctionPtr("NtQueryFullAttributesFile", &NtQueryFullAttributesFile);
+
+  UNICODE_STRING uni_name = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+  InitObjectAttribs(file, attributes, NULL, &obj_attributes,
+                    &uni_name, IsPipe(file) ? &security_qos : NULL);
+  *nt_status = NtQueryFullAttributesFile(&obj_attributes, file_info);
+
+  return true;
+}
+
+bool FileSystemPolicy::SetInformationFileAction(
+    EvalResult eval_result, const ClientInfo& client_info,
+    HANDLE target_file_handle, void* file_info, uint32 length,
+    uint32 info_class, IO_STATUS_BLOCK* io_block,
+    NTSTATUS* nt_status) {
+  // The only action supported is ASK_BROKER which means open the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  NtSetInformationFileFunction NtSetInformationFile = NULL;
+  ResolveNTFunctionPtr("NtSetInformationFile", &NtSetInformationFile);
+
+  HANDLE local_handle = NULL;
+  if (!::DuplicateHandle(client_info.process, target_file_handle,
+                         ::GetCurrentProcess(), &local_handle, 0, FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  base::win::ScopedHandle handle(local_handle);
+
+  FILE_INFORMATION_CLASS file_info_class =
+      static_cast<FILE_INFORMATION_CLASS>(info_class);
+  *nt_status = NtSetInformationFile(local_handle, io_block, file_info, length,
+                                    file_info_class);
+
+  return true;
+}
+
+bool PreProcessName(const base::string16& path, base::string16* new_path) {
+  ConvertToLongPath(path, new_path);
+
+  bool reparsed = false;
+  if (ERROR_SUCCESS != IsReparsePoint(*new_path, &reparsed))
+    return false;
+
+  // We can't process reparsed file.
+  return !reparsed;
+}
+
+base::string16 FixNTPrefixForMatch(const base::string16& name) {
+  base::string16 mod_name = name;
+
+  // NT prefix escaped for rule matcher
+  const wchar_t kNTPrefixEscaped[] = L"\\/?/?\\";
+  const int kNTPrefixEscapedLen = arraysize(kNTPrefixEscaped) - 1;
+
+  if (0 != mod_name.compare(0, kNTPrefixLen, kNTPrefix)) {
+    if (0 != mod_name.compare(0, kNTPrefixEscapedLen, kNTPrefixEscaped)) {
+      // TODO(nsylvain): Find a better way to do name resolution. Right now we
+      // take the name and we expand it.
+      mod_name.insert(0, kNTPrefixEscaped);
+    }
+  } else {
+    // Start of name matches NT prefix, replace with escaped format
+    // Fixes bug: 334882
+    mod_name.replace(0, kNTPrefixLen, kNTPrefixEscaped);
+  }
+
+  return mod_name;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/filesystem_policy.h b/sandbox/win/src/filesystem_policy.h
new file mode 100644
index 0000000..ce28344
--- /dev/null
+++ b/sandbox/win/src/filesystem_policy.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_FILESYSTEM_POLICY_H__
+#define SANDBOX_SRC_FILESYSTEM_POLICY_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to file system policy
+class FileSystemPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule for File IO, in particular open or create actions.
+  // 'name' is the file or directory name.
+  // 'semantics' is the desired semantics for the open or create.
+  // 'policy' is the policy generator to which the rules are going to be added.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Add basic file system rules.
+  static bool SetInitialRules(LowLevelPolicy* policy);
+
+  // Performs the desired policy action on a create request with an
+  // API that is compatible with the IPC-received parameters.
+  // 'client_info' : the target process that is making the request.
+  // 'eval_result' : The desired policy action to accomplish.
+  // 'file' : The target file or directory.
+  static bool CreateFileAction(EvalResult eval_result,
+                               const ClientInfo& client_info,
+                               const base::string16 &file,
+                               uint32 attributes,
+                               uint32 desired_access,
+                               uint32 file_attributes,
+                               uint32 share_access,
+                               uint32 create_disposition,
+                               uint32 create_options,
+                               HANDLE* handle,
+                               NTSTATUS* nt_status,
+                               ULONG_PTR* io_information);
+
+  // Performs the desired policy action on an open request with an
+  // API that is compatible with the IPC-received parameters.
+  // 'client_info' : the target process that is making the request.
+  // 'eval_result' : The desired policy action to accomplish.
+  // 'file' : The target file or directory.
+  static bool OpenFileAction(EvalResult eval_result,
+                             const ClientInfo& client_info,
+                             const base::string16 &file,
+                             uint32 attributes,
+                             uint32 desired_access,
+                             uint32 share_access,
+                             uint32 open_options,
+                             HANDLE* handle,
+                             NTSTATUS* nt_status,
+                             ULONG_PTR* io_information);
+
+  // Performs the desired policy action on a query request with an
+  // API that is compatible with the IPC-received parameters.
+  static bool QueryAttributesFileAction(EvalResult eval_result,
+                                        const ClientInfo& client_info,
+                                        const base::string16 &file,
+                                        uint32 attributes,
+                                        FILE_BASIC_INFORMATION* file_info,
+                                        NTSTATUS* nt_status);
+
+  // Performs the desired policy action on a query request with an
+  // API that is compatible with the IPC-received parameters.
+  static bool QueryFullAttributesFileAction(
+      EvalResult eval_result,
+      const ClientInfo& client_info,
+      const base::string16 &file,
+      uint32 attributes,
+      FILE_NETWORK_OPEN_INFORMATION* file_info,
+      NTSTATUS* nt_status);
+
+  // Performs the desired policy action on a set_info request with an
+  // API that is compatible with the IPC-received parameters.
+  static bool SetInformationFileAction(EvalResult eval_result,
+                                       const ClientInfo& client_info,
+                                       HANDLE target_file_handle,
+                                       void* file_info,
+                                       uint32 length,
+                                       uint32 info_class,
+                                       IO_STATUS_BLOCK* io_block,
+                                       NTSTATUS* nt_status);
+};
+
+// Expands the path and check if it's a reparse point. Returns false if
+// we cannot determine or if there is an unexpected error. In that case
+// the path cannot be trusted.
+bool PreProcessName(const base::string16& path, base::string16* new_path);
+
+// Corrects global paths to have a correctly escaped NT prefix at the
+// beginning. If the name has no NT prefix (either normal or escaped)
+// add the escaped form to the string
+base::string16 FixNTPrefixForMatch(const base::string16& name);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_FILESYSTEM_POLICY_H__
diff --git a/sandbox/win/src/handle_closer.cc b/sandbox/win/src/handle_closer.cc
new file mode 100644
index 0000000..2e3a782
--- /dev/null
+++ b/sandbox/win/src/handle_closer.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_closer.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+template<typename T> T RoundUpToWordSize(T v) {
+  if (size_t mod = v % sizeof(size_t))
+    v += sizeof(size_t) - mod;
+  return v;
+}
+
+template<typename T> T* RoundUpToWordSize(T* v) {
+  return reinterpret_cast<T*>(RoundUpToWordSize(reinterpret_cast<size_t>(v)));
+}
+
+}  // namespace
+
+namespace sandbox {
+
+// Memory buffer mapped from the parent, with the list of handles.
+SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close;
+
+HandleCloser::HandleCloser() {
+}
+
+HandleCloser::~HandleCloser() {
+}
+
+ResultCode HandleCloser::AddHandle(const base::char16* handle_type,
+                                   const base::char16* handle_name) {
+  if (!handle_type)
+    return SBOX_ERROR_BAD_PARAMS;
+
+  base::string16 resolved_name;
+  if (handle_name) {
+    resolved_name = handle_name;
+    if (handle_type == base::string16(L"Key"))
+      if (!ResolveRegistryName(resolved_name, &resolved_name))
+        return SBOX_ERROR_BAD_PARAMS;
+  }
+
+  HandleMap::iterator names = handles_to_close_.find(handle_type);
+  if (names == handles_to_close_.end()) {  // We have no entries for this type.
+    std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert(
+        HandleMap::value_type(handle_type, HandleMap::mapped_type()));
+    names = result.first;
+    if (handle_name)
+      names->second.insert(resolved_name);
+  } else if (!handle_name) {  // Now we need to close all handles of this type.
+    names->second.clear();
+  } else if (!names->second.empty()) {  // Add another name for this type.
+    names->second.insert(resolved_name);
+  }  // If we're already closing all handles of type then we're done.
+
+  return SBOX_ALL_OK;
+}
+
+size_t HandleCloser::GetBufferSize() {
+  size_t bytes_total = offsetof(HandleCloserInfo, handle_entries);
+
+  for (HandleMap::iterator i = handles_to_close_.begin();
+       i != handles_to_close_.end(); ++i) {
+    size_t bytes_entry = offsetof(HandleListEntry, handle_type) +
+        (i->first.size() + 1) * sizeof(base::char16);
+    for (HandleMap::mapped_type::iterator j = i->second.begin();
+         j != i->second.end(); ++j) {
+      bytes_entry += ((*j).size() + 1) * sizeof(base::char16);
+    }
+
+    // Round up to the nearest multiple of word size.
+    bytes_entry = RoundUpToWordSize(bytes_entry);
+    bytes_total += bytes_entry;
+  }
+
+  return bytes_total;
+}
+
+bool HandleCloser::InitializeTargetHandles(TargetProcess* target) {
+  // Do nothing on an empty list (global pointer already initialized to NULL).
+  if (handles_to_close_.empty())
+    return true;
+
+  size_t bytes_needed = GetBufferSize();
+  scoped_ptr<size_t[]> local_buffer(
+      new size_t[bytes_needed / sizeof(size_t)]);
+
+  if (!SetupHandleList(local_buffer.get(), bytes_needed))
+    return false;
+
+  HANDLE child = target->Process();
+
+  // Allocate memory in the target process without specifying the address
+  void* remote_data = ::VirtualAllocEx(child, NULL, bytes_needed,
+                                       MEM_COMMIT, PAGE_READWRITE);
+  if (NULL == remote_data)
+    return false;
+
+  // Copy the handle buffer over.
+  SIZE_T bytes_written;
+  BOOL result = ::WriteProcessMemory(child, remote_data, local_buffer.get(),
+                                     bytes_needed, &bytes_written);
+  if (!result || bytes_written != bytes_needed) {
+    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
+    return false;
+  }
+
+  g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data);
+
+  ResultCode rc = target->TransferVariable("g_handles_to_close",
+                                           &g_handles_to_close,
+                                           sizeof(g_handles_to_close));
+
+  return (SBOX_ALL_OK == rc);
+}
+
+bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) {
+  ::ZeroMemory(buffer, buffer_bytes);
+  HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer);
+  handle_info->record_bytes = buffer_bytes;
+  handle_info->num_handle_types = handles_to_close_.size();
+
+  base::char16* output = reinterpret_cast<base::char16*>(
+      &handle_info->handle_entries[0]);
+  base::char16* end = reinterpret_cast<base::char16*>(
+      reinterpret_cast<char*>(buffer) + buffer_bytes);
+  for (HandleMap::iterator i = handles_to_close_.begin();
+       i != handles_to_close_.end(); ++i) {
+    if (output >= end)
+      return false;
+    HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output);
+    output = &list_entry->handle_type[0];
+
+    // Copy the typename and set the offset and count.
+    i->first._Copy_s(output, i->first.size(), i->first.size());
+    *(output += i->first.size()) = L'\0';
+    output++;
+    list_entry->offset_to_names = reinterpret_cast<char*>(output) -
+        reinterpret_cast<char*>(list_entry);
+    list_entry->name_count = i->second.size();
+
+    // Copy the handle names.
+    for (HandleMap::mapped_type::iterator j = i->second.begin();
+         j != i->second.end(); ++j) {
+      output = std::copy((*j).begin(), (*j).end(), output) + 1;
+    }
+
+    // Round up to the nearest multiple of sizeof(size_t).
+    output = RoundUpToWordSize(output);
+    list_entry->record_bytes = reinterpret_cast<char*>(output) -
+        reinterpret_cast<char*>(list_entry);
+  }
+
+  DCHECK_EQ(reinterpret_cast<size_t>(output), reinterpret_cast<size_t>(end));
+  return output <= end;
+}
+
+bool GetHandleName(HANDLE handle, base::string16* handle_name) {
+  static NtQueryObject QueryObject = NULL;
+  if (!QueryObject)
+    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+  ULONG size = MAX_PATH;
+  scoped_ptr<UNICODE_STRING, base::FreeDeleter> name;
+  NTSTATUS result;
+
+  do {
+    name.reset(static_cast<UNICODE_STRING*>(malloc(size)));
+    DCHECK(name.get());
+    result = QueryObject(handle, ObjectNameInformation, name.get(),
+                         size, &size);
+  } while (result == STATUS_INFO_LENGTH_MISMATCH ||
+           result == STATUS_BUFFER_OVERFLOW);
+
+  if (NT_SUCCESS(result) && name->Buffer && name->Length)
+    handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t));
+  else
+    handle_name->clear();
+
+  return NT_SUCCESS(result);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/handle_closer.h b/sandbox/win/src/handle_closer.h
new file mode 100644
index 0000000..2b43a6e
--- /dev/null
+++ b/sandbox/win/src/handle_closer.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 SANDBOX_SRC_HANDLE_CLOSER_H_
+#define SANDBOX_SRC_HANDLE_CLOSER_H_
+
+#include <map>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/target_process.h"
+
+namespace sandbox {
+
+// This is a map of handle-types to names that we need to close in the
+// target process. A null set means we need to close all handles of the
+// given type.
+typedef std::map<const base::string16, std::set<base::string16> > HandleMap;
+
+// Type and set of corresponding handle names to close.
+struct HandleListEntry {
+  size_t record_bytes;       // Rounded to sizeof(size_t) bytes.
+  size_t offset_to_names;    // Nul terminated strings of name_count names.
+  size_t name_count;
+  base::char16 handle_type[1];
+};
+
+// Global parameters and a pointer to the list of entries.
+struct HandleCloserInfo {
+  size_t record_bytes;       // Rounded to sizeof(size_t) bytes.
+  size_t num_handle_types;
+  struct HandleListEntry handle_entries[1];
+};
+
+SANDBOX_INTERCEPT HandleCloserInfo* g_handle_closer_info;
+
+// Adds handles to close after lockdown.
+class HandleCloser {
+ public:
+  HandleCloser();
+  ~HandleCloser();
+
+  // Adds a handle that will be closed in the target process after lockdown.
+  // A NULL value for handle_name indicates all handles of the specified type.
+  // An empty string for handle_name indicates the handle is unnamed.
+  ResultCode AddHandle(const base::char16* handle_type,
+                       const base::char16* handle_name);
+
+  // Serializes and copies the closer table into the target process.
+  bool InitializeTargetHandles(TargetProcess* target);
+
+ private:
+  // Calculates the memory needed to copy the serialized handles list (rounded
+  // to the nearest machine-word size).
+  size_t GetBufferSize();
+
+  // Serializes the handle list into the target process.
+  bool SetupHandleList(void* buffer, size_t buffer_bytes);
+
+  HandleMap handles_to_close_;
+
+  DISALLOW_COPY_AND_ASSIGN(HandleCloser);
+};
+
+// Returns the object manager's name associated with a handle
+bool GetHandleName(HANDLE handle, base::string16* handle_name);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_CLOSER_H_
diff --git a/sandbox/win/src/handle_closer_agent.cc b/sandbox/win/src/handle_closer_agent.cc
new file mode 100644
index 0000000..9a79d55
--- /dev/null
+++ b/sandbox/win/src/handle_closer_agent.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_closer_agent.h"
+
+#include "base/logging.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// Returns type infomation for an NT object. This routine is expected to be
+// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
+// that can be generated when handle tracing is enabled.
+NTSTATUS QueryObjectTypeInformation(HANDLE handle,
+                                    void* buffer,
+                                    ULONG* size) {
+  static NtQueryObject QueryObject = NULL;
+  if (!QueryObject)
+    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+  NTSTATUS status = STATUS_UNSUCCESSFUL;
+  __try {
+    status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
+  } __except(GetExceptionCode() == STATUS_INVALID_HANDLE ?
+                 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+    status = STATUS_INVALID_HANDLE;
+  }
+  return status;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+// Memory buffer mapped from the parent, with the list of handles.
+SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = NULL;
+
+bool HandleCloserAgent::NeedsHandlesClosed() {
+  return g_handles_to_close != NULL;
+}
+
+HandleCloserAgent::HandleCloserAgent()
+    : dummy_handle_(::CreateEvent(NULL, FALSE, FALSE, NULL)) {
+}
+
+HandleCloserAgent::~HandleCloserAgent() {
+}
+
+// Attempts to stuff |closed_handle| with a duplicated handle for a dummy Event
+// with no access. This should allow the handle to be closed, to avoid
+// generating EXCEPTION_INVALID_HANDLE on shutdown, but nothing else. For now
+// the only supported |type| is Event or File.
+bool HandleCloserAgent::AttemptToStuffHandleSlot(HANDLE closed_handle,
+                                                 const base::string16& type) {
+  // Only attempt to stuff Files and Events at the moment.
+  if (type != L"Event" && type != L"File") {
+    return true;
+  }
+
+  if (!dummy_handle_.IsValid())
+    return false;
+
+  // This should never happen, as g_dummy is created before closing to_stuff.
+  DCHECK(dummy_handle_.Get() != closed_handle);
+
+  std::vector<HANDLE> to_close;
+  HANDLE dup_dummy = NULL;
+  size_t count = 16;
+
+  do {
+    if (!::DuplicateHandle(::GetCurrentProcess(), dummy_handle_.Get(),
+                           ::GetCurrentProcess(), &dup_dummy, 0, FALSE, 0))
+      break;
+    if (dup_dummy != closed_handle)
+      to_close.push_back(dup_dummy);
+  } while (count-- &&
+           reinterpret_cast<uintptr_t>(dup_dummy) <
+               reinterpret_cast<uintptr_t>(closed_handle));
+
+  for (auto h : to_close)
+    ::CloseHandle(h);
+
+  // Useful to know when we're not able to stuff handles.
+  DCHECK(dup_dummy == closed_handle);
+
+  return dup_dummy == closed_handle;
+}
+
+// Reads g_handles_to_close and creates the lookup map.
+void HandleCloserAgent::InitializeHandlesToClose() {
+  CHECK(g_handles_to_close != NULL);
+
+  // Grab the header.
+  HandleListEntry* entry = g_handles_to_close->handle_entries;
+  for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) {
+    // Set the type name.
+    base::char16* input = entry->handle_type;
+    HandleMap::mapped_type& handle_names = handles_to_close_[input];
+    input = reinterpret_cast<base::char16*>(reinterpret_cast<char*>(entry)
+        + entry->offset_to_names);
+    // Grab all the handle names.
+    for (size_t j = 0; j < entry->name_count; ++j) {
+      std::pair<HandleMap::mapped_type::iterator, bool> name
+          = handle_names.insert(input);
+      CHECK(name.second);
+      input += name.first->size() + 1;
+    }
+
+    // Move on to the next entry.
+    entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry)
+        + entry->record_bytes);
+
+    DCHECK(reinterpret_cast<base::char16*>(entry) >= input);
+    DCHECK(reinterpret_cast<base::char16*>(entry) - input <
+           sizeof(size_t) / sizeof(base::char16));
+  }
+
+  // Clean up the memory we copied over.
+  ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE);
+  g_handles_to_close = NULL;
+}
+
+bool HandleCloserAgent::CloseHandles() {
+  DWORD handle_count = UINT_MAX;
+  const int kInvalidHandleThreshold = 100;
+  const size_t kHandleOffset = 4;  // Handles are always a multiple of 4.
+
+  if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
+    return false;
+
+  // Set up buffers for the type info and the name.
+  std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
+                                     32 * sizeof(wchar_t));
+  OBJECT_TYPE_INFORMATION* type_info =
+      reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
+  base::string16 handle_name;
+  HANDLE handle = NULL;
+  int invalid_count = 0;
+
+  // Keep incrementing until we hit the number of handles reported by
+  // GetProcessHandleCount(). If we hit a very long sequence of invalid
+  // handles we assume that we've run past the end of the table.
+  while (handle_count && invalid_count < kInvalidHandleThreshold) {
+    reinterpret_cast<size_t&>(handle) += kHandleOffset;
+    NTSTATUS rc;
+
+    // Get the type name, reusing the buffer.
+    ULONG size = static_cast<ULONG>(type_info_buffer.size());
+    rc = QueryObjectTypeInformation(handle, type_info, &size);
+    while (rc == STATUS_INFO_LENGTH_MISMATCH ||
+           rc == STATUS_BUFFER_OVERFLOW) {
+      type_info_buffer.resize(size + sizeof(wchar_t));
+      type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
+          &(type_info_buffer[0]));
+      rc = QueryObjectTypeInformation(handle, type_info, &size);
+      // Leave padding for the nul terminator.
+      if (NT_SUCCESS(rc) && size == type_info_buffer.size())
+        rc = STATUS_INFO_LENGTH_MISMATCH;
+    }
+    if (!NT_SUCCESS(rc) || !type_info->Name.Buffer) {
+      ++invalid_count;
+      continue;
+    }
+
+    --handle_count;
+    type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
+
+    // Check if we're looking for this type of handle.
+    HandleMap::iterator result =
+        handles_to_close_.find(type_info->Name.Buffer);
+    if (result != handles_to_close_.end()) {
+      HandleMap::mapped_type& names = result->second;
+      // Empty set means close all handles of this type; otherwise check name.
+      if (!names.empty()) {
+        // Move on to the next handle if this name doesn't match.
+        if (!GetHandleName(handle, &handle_name) || !names.count(handle_name))
+          continue;
+      }
+
+      if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0))
+        return false;
+      if (!::CloseHandle(handle))
+        return false;
+      // Attempt to stuff this handle with a new dummy Event.
+      AttemptToStuffHandleSlot(handle, result->first);
+    }
+  }
+
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/handle_closer_agent.h b/sandbox/win/src/handle_closer_agent.h
new file mode 100644
index 0000000..a3e1502
--- /dev/null
+++ b/sandbox/win/src/handle_closer_agent.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_
+#define SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_closer.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+// Target process code to close the handle list copied over from the broker.
+class HandleCloserAgent {
+ public:
+  HandleCloserAgent();
+  ~HandleCloserAgent();
+
+  // Reads the serialized list from the broker and creates the lookup map.
+  void InitializeHandlesToClose();
+
+  // Closes any handles matching those in the lookup map.
+  bool CloseHandles();
+
+  // True if we have handles waiting to be closed.
+  static bool NeedsHandlesClosed();
+
+ private:
+  // Attempt to stuff a closed handle with a dummy Event.
+  bool AttemptToStuffHandleSlot(HANDLE closed_handle,
+                                const base::string16& type);
+
+  HandleMap handles_to_close_;
+  base::win::ScopedHandle dummy_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(HandleCloserAgent);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_
diff --git a/sandbox/win/src/handle_closer_test.cc b/sandbox/win/src/handle_closer_test.cc
new file mode 100644
index 0000000..f1f80e8
--- /dev/null
+++ b/sandbox/win/src/handle_closer_test.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_closer_agent.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const wchar_t *kFileExtensions[] = { L".1", L".2", L".3", L".4" };
+
+// Returns a handle to a unique marker file that can be retrieved between runs.
+HANDLE GetMarkerFile(const wchar_t *extension) {
+  wchar_t path_buffer[MAX_PATH + 1];
+  CHECK(::GetTempPath(MAX_PATH, path_buffer));
+  base::string16 marker_path = path_buffer;
+  marker_path += L"\\sbox_marker_";
+
+  // Generate a unique value from the exe's size and timestamp.
+  CHECK(::GetModuleFileName(NULL, path_buffer, MAX_PATH));
+  base::win::ScopedHandle module(::CreateFile(path_buffer,
+                                 FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL,
+                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
+  CHECK(module.IsValid());
+  FILETIME timestamp;
+  CHECK(::GetFileTime(module.Get(), &timestamp, NULL, NULL));
+  marker_path += base::StringPrintf(L"%08x%08x%08x",
+                                    ::GetFileSize(module.Get(), NULL),
+                                    timestamp.dwLowDateTime,
+                                    timestamp.dwHighDateTime);
+  marker_path += extension;
+
+  // Make the file delete-on-close so cleanup is automatic.
+  return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS,
+      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+      NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+}
+
+// Returns type infomation for an NT object. This routine is expected to be
+// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
+// that can be generated when handle tracing is enabled.
+NTSTATUS QueryObjectTypeInformation(HANDLE handle, void* buffer, ULONG* size) {
+  static NtQueryObject QueryObject = NULL;
+  if (!QueryObject)
+    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+  NTSTATUS status = STATUS_UNSUCCESSFUL;
+  __try {
+    status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
+  }
+  __except(GetExceptionCode() == STATUS_INVALID_HANDLE
+               ? EXCEPTION_EXECUTE_HANDLER
+               : EXCEPTION_CONTINUE_SEARCH) {
+    status = STATUS_INVALID_HANDLE;
+  }
+  return status;
+}
+
+// Used by the thread pool tests.
+HANDLE finish_event;
+const int kWaitCount = 20;
+
+}  // namespace
+
+namespace sandbox {
+
+// Checks for the presence of a list of files (in object path form).
+// Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...]
+// - Y or N depending if the file should exist or not.
+SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t **argv) {
+  if (argc < 2)
+    return SBOX_TEST_FAILED_TO_RUN_TEST;
+  bool should_find = argv[0][0] == L'Y';
+  if (argv[0][1] != L'\0' || !should_find && argv[0][0] != L'N')
+    return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+  static int state = BEFORE_INIT;
+  switch (state++) {
+    case BEFORE_INIT:
+      // Create a unique marker file that is open while the test is running.
+      // The handles leak, but it will be closed by the test or on exit.
+      for (int i = 0; i < arraysize(kFileExtensions); ++i)
+        CHECK_NE(GetMarkerFile(kFileExtensions[i]), INVALID_HANDLE_VALUE);
+      return SBOX_TEST_SUCCEEDED;
+
+    case AFTER_REVERT: {
+      // Brute force the handle table to find what we're looking for.
+      DWORD handle_count = UINT_MAX;
+      const int kInvalidHandleThreshold = 100;
+      const size_t kHandleOffset = 4;  // Handles are always a multiple of 4.
+      HANDLE handle = NULL;
+      int invalid_count = 0;
+      base::string16 handle_name;
+
+      if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
+        return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+      while (handle_count && invalid_count < kInvalidHandleThreshold) {
+        reinterpret_cast<size_t&>(handle) += kHandleOffset;
+        if (GetHandleName(handle, &handle_name)) {
+          for (int i = 1; i < argc; ++i) {
+            if (handle_name == argv[i])
+              return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+          }
+          --handle_count;
+        } else {
+          ++invalid_count;
+        }
+      }
+
+      return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
+    }
+
+    default:  // Do nothing.
+      break;
+  }
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Checks that supplied handle is an Event and it's not waitable.
+// Format: CheckForEventHandles
+SBOX_TESTS_COMMAND int CheckForEventHandles(int argc, wchar_t** argv) {
+  static int state = BEFORE_INIT;
+  static std::vector<HANDLE> to_check;
+
+  switch (state++) {
+    case BEFORE_INIT:
+      // Create a unique marker file that is open while the test is running.
+      for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+        HANDLE handle = GetMarkerFile(kFileExtensions[i]);
+        CHECK_NE(handle, INVALID_HANDLE_VALUE);
+        to_check.push_back(handle);
+      }
+      return SBOX_TEST_SUCCEEDED;
+
+    case AFTER_REVERT:
+      for (auto handle : to_check) {
+        // Set up buffers for the type info and the name.
+        std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
+                                           32 * sizeof(wchar_t));
+        OBJECT_TYPE_INFORMATION* type_info =
+            reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
+        NTSTATUS rc;
+
+        // Get the type name, reusing the buffer.
+        ULONG size = static_cast<ULONG>(type_info_buffer.size());
+        rc = QueryObjectTypeInformation(handle, type_info, &size);
+        while (rc == STATUS_INFO_LENGTH_MISMATCH ||
+               rc == STATUS_BUFFER_OVERFLOW) {
+          type_info_buffer.resize(size + sizeof(wchar_t));
+          type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
+              &(type_info_buffer[0]));
+          rc = QueryObjectTypeInformation(handle, type_info, &size);
+          // Leave padding for the nul terminator.
+          if (NT_SUCCESS(rc) && size == type_info_buffer.size())
+            rc = STATUS_INFO_LENGTH_MISMATCH;
+        }
+
+        CHECK(NT_SUCCESS(rc));
+        CHECK(type_info->Name.Buffer);
+
+        type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] =
+            L'\0';
+
+        // Should be an Event now.
+        CHECK_EQ(wcslen(type_info->Name.Buffer), 5U);
+        CHECK_EQ(wcscmp(L"Event", type_info->Name.Buffer), 0);
+
+        // Should not be able to wait.
+        CHECK_EQ(WaitForSingleObject(handle, INFINITE), WAIT_FAILED);
+
+        // Should be able to close.
+        CHECK_EQ(TRUE, CloseHandle(handle));
+      }
+      return SBOX_TEST_SUCCEEDED;
+
+    default:  // Do nothing.
+      break;
+  }
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(HandleCloserTest, CheckForMarkerFiles) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(EVERY_STATE);
+
+  base::string16 command = base::string16(L"CheckForFileHandles Y");
+  for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+    base::string16 handle_name;
+    base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
+    CHECK(marker.IsValid());
+    CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
+    command += (L" ");
+    command += handle_name;
+  }
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
+    "Failed: " << command;
+}
+
+TEST(HandleCloserTest, CloseMarkerFiles) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(EVERY_STATE);
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  base::string16 command = base::string16(L"CheckForFileHandles N");
+  for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+    base::string16 handle_name;
+    base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
+    CHECK(marker.IsValid());
+    CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
+    CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
+              SBOX_ALL_OK);
+    command += (L" ");
+    command += handle_name;
+  }
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str())) <<
+    "Failed: " << command;
+}
+
+TEST(HandleCloserTest, CheckStuffedHandle) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(EVERY_STATE);
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  for (int i = 0; i < arraysize(kFileExtensions); ++i) {
+    base::string16 handle_name;
+    base::win::ScopedHandle marker(GetMarkerFile(kFileExtensions[i]));
+    CHECK(marker.IsValid());
+    CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
+    CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
+             SBOX_ALL_OK);
+  }
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckForEventHandles"));
+}
+
+void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) {
+  static volatile LONG waiters_remaining = kWaitCount;
+  CHECK(!timeout);
+  CHECK(::CloseHandle(event));
+  if (::InterlockedDecrement(&waiters_remaining) == 0)
+    CHECK(::SetEvent(finish_event));
+}
+
+// Run a thread pool inside a sandbox without a CSRSS connection.
+SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t **argv) {
+  HANDLE wait_list[20];
+  finish_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+  CHECK(finish_event);
+
+  // Set up a bunch of waiters.
+  HANDLE pool = NULL;
+  for (int i = 0; i < kWaitCount; ++i) {
+    HANDLE event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+    CHECK(event);
+    CHECK(::RegisterWaitForSingleObject(&pool, event, ThreadPoolTask, event,
+                                        INFINITE, WT_EXECUTEONLYONCE));
+    wait_list[i] = event;
+  }
+
+  // Signal all the waiters.
+  for (int i = 0; i < kWaitCount; ++i)
+    CHECK(::SetEvent(wait_list[i]));
+
+  CHECK_EQ(::WaitForSingleObject(finish_event, INFINITE), WAIT_OBJECT_0);
+  CHECK(::CloseHandle(finish_event));
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(HandleCloserTest, RunThreadPool) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(AFTER_REVERT);
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  // Sever the CSRSS connection by closing ALPC ports inside the sandbox.
+  CHECK_EQ(policy->AddKernelObjectToClose(L"ALPC Port", NULL), SBOX_ALL_OK);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/handle_dispatcher.cc b/sandbox/win/src/handle_dispatcher.cc
new file mode 100644
index 0000000..66308f4
--- /dev/null
+++ b/sandbox/win/src/handle_dispatcher.cc
@@ -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.
+
+#include "sandbox/win/src/handle_dispatcher.h"
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_interception.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+
+namespace sandbox {
+
+HandleDispatcher::HandleDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall duplicate_handle_proxy = {
+    {IPC_DUPLICATEHANDLEPROXY_TAG, VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE,
+     UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&HandleDispatcher::DuplicateHandleProxy)
+  };
+
+  ipc_calls_.push_back(duplicate_handle_proxy);
+}
+
+bool HandleDispatcher::SetupService(InterceptionManager* manager,
+                                    int service) {
+  // We perform no interceptions for handles right now.
+  switch (service) {
+    case IPC_DUPLICATEHANDLEPROXY_TAG:
+    return true;
+  }
+
+  return false;
+}
+
+bool HandleDispatcher::DuplicateHandleProxy(IPCInfo* ipc,
+                                            HANDLE source_handle,
+                                            uint32 target_process_id,
+                                            uint32 desired_access,
+                                            uint32 options) {
+  static NtQueryObject QueryObject = NULL;
+  if (!QueryObject)
+    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+  // Get a copy of the handle for use in the broker process.
+  HANDLE handle_temp;
+  if (!::DuplicateHandle(ipc->client_info->process, source_handle,
+                         ::GetCurrentProcess(), &handle_temp,
+                         0, FALSE, DUPLICATE_SAME_ACCESS | options)) {
+    ipc->return_info.win32_result = ::GetLastError();
+    return false;
+  }
+  options &= ~DUPLICATE_CLOSE_SOURCE;
+  base::win::ScopedHandle handle(handle_temp);
+
+  // Get the object type (32 characters is safe; current max is 14).
+  BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)];
+  OBJECT_TYPE_INFORMATION* type_info =
+      reinterpret_cast<OBJECT_TYPE_INFORMATION*>(buffer);
+  ULONG size = sizeof(buffer) - sizeof(wchar_t);
+  NTSTATUS error =
+      QueryObject(handle.Get(), ObjectTypeInformation, type_info, size, &size);
+  if (!NT_SUCCESS(error)) {
+    ipc->return_info.nt_status = error;
+    return false;
+  }
+  type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
+
+  CountedParameterSet<HandleTarget> params;
+  params[HandleTarget::NAME] = ParamPickerMake(type_info->Name.Buffer);
+  params[HandleTarget::TARGET] = ParamPickerMake(target_process_id);
+
+  EvalResult eval = policy_base_->EvalPolicy(IPC_DUPLICATEHANDLEPROXY_TAG,
+                                             params.GetBase());
+  ipc->return_info.win32_result =
+      HandlePolicy::DuplicateHandleProxyAction(eval, handle.Get(),
+                                               target_process_id,
+                                               &ipc->return_info.handle,
+                                               desired_access, options);
+  return true;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/handle_dispatcher.h b/sandbox/win/src/handle_dispatcher.h
new file mode 100644
index 0000000..84a22e1
--- /dev/null
+++ b/sandbox/win/src/handle_dispatcher.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_DISPATCHER_H_
+#define SANDBOX_SRC_HANDLE_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles handle-related IPC calls.
+class HandleDispatcher : public Dispatcher {
+ public:
+  explicit HandleDispatcher(PolicyBase* policy_base);
+  ~HandleDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to
+  // TargetServices::DuplicateHandle() in the target.
+  bool DuplicateHandleProxy(IPCInfo* ipc,
+                            HANDLE source_handle,
+                            uint32 target_process_id,
+                            uint32 desired_access,
+                            uint32 options);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(HandleDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_DISPATCHER_H_
+
diff --git a/sandbox/win/src/handle_inheritance_test.cc b/sandbox/win/src/handle_inheritance_test.cc
new file mode 100644
index 0000000..37974e3
--- /dev/null
+++ b/sandbox/win/src/handle_inheritance_test.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 <stdio.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int HandleInheritanceTests_PrintToStdout(int argc,
+                                                            wchar_t** argv) {
+  printf("Example output to stdout\n");
+  return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(HandleInheritanceTests, TestStdoutInheritance) {
+  base::ScopedTempDir temp_directory;
+  base::FilePath temp_file_name;
+  ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+  ASSERT_TRUE(CreateTemporaryFileInDir(temp_directory.path(), &temp_file_name));
+
+  SECURITY_ATTRIBUTES attrs = {};
+  attrs.nLength = sizeof(attrs);
+  attrs.bInheritHandle = TRUE;
+  base::win::ScopedHandle tmp_handle(
+      CreateFile(temp_file_name.value().c_str(), GENERIC_WRITE,
+                 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+                 &attrs, OPEN_EXISTING, 0, NULL));
+  ASSERT_TRUE(tmp_handle.IsValid());
+
+  TestRunner runner;
+  ASSERT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetStdoutHandle(tmp_handle.Get()));
+  int result = runner.RunTest(L"HandleInheritanceTests_PrintToStdout");
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED, result);
+
+  std::string data;
+  ASSERT_TRUE(base::ReadFileToString(base::FilePath(temp_file_name), &data));
+  // Redirection uses a feature that was added in Windows Vista.
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+    ASSERT_EQ("Example output to stdout\r\n", data);
+  } else {
+    ASSERT_EQ("", data);
+  }
+}
+
+}
diff --git a/sandbox/win/src/handle_interception.cc b/sandbox/win/src/handle_interception.cc
new file mode 100644
index 0000000..a0df8d6
--- /dev/null
+++ b/sandbox/win/src/handle_interception.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+ResultCode DuplicateHandleProxy(HANDLE source_handle,
+                                DWORD target_process_id,
+                                HANDLE* target_handle,
+                                DWORD desired_access,
+                                DWORD options) {
+  *target_handle = NULL;
+
+  void* memory = GetGlobalIPCMemory();
+  if (NULL == memory)
+    return SBOX_ERROR_NO_SPACE;
+
+  SharedMemIPCClient ipc(memory);
+  CrossCallReturn answer = {0};
+  ResultCode code = CrossCall(ipc, IPC_DUPLICATEHANDLEPROXY_TAG,
+                              source_handle, target_process_id,
+                              desired_access, options, &answer);
+  if (SBOX_ALL_OK != code)
+    return code;
+
+  if (answer.win32_result) {
+    ::SetLastError(answer.win32_result);
+    return SBOX_ERROR_GENERIC;
+  }
+
+  *target_handle = answer.handle;
+  return SBOX_ALL_OK;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/handle_interception.h b/sandbox/win/src/handle_interception.h
new file mode 100644
index 0000000..6f60811
--- /dev/null
+++ b/sandbox/win/src/handle_interception.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.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_HANDLE_INTERCEPTION_H_
+#define SANDBOX_SRC_HANDLE_INTERCEPTION_H_
+
+namespace sandbox {
+
+// TODO(jschuh) Add an interception to catch dangerous DuplicateHandle calls.
+
+ResultCode DuplicateHandleProxy(HANDLE source_handle,
+                                DWORD target_process_id,
+                                HANDLE* target_handle,
+                                DWORD desired_access,
+                                DWORD options);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_INTERCEPTION_H_
+
diff --git a/sandbox/win/src/handle_policy.cc b/sandbox/win/src/handle_policy.cc
new file mode 100644
index 0000000..1023030
--- /dev/null
+++ b/sandbox/win/src/handle_policy.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 "sandbox/win/src/handle_policy.h"
+
+#include <string>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/broker_services.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+
+namespace sandbox {
+
+bool HandlePolicy::GenerateRules(const wchar_t* type_name,
+                                 TargetPolicy::Semantics semantics,
+                                 LowLevelPolicy* policy) {
+  PolicyRule duplicate_rule(ASK_BROKER);
+
+  switch (semantics) {
+    case TargetPolicy::HANDLES_DUP_ANY: {
+      if (!duplicate_rule.AddNumberMatch(IF_NOT, HandleTarget::TARGET,
+                                         ::GetCurrentProcessId(), EQUAL)) {
+        return false;
+      }
+      break;
+    }
+
+    case TargetPolicy::HANDLES_DUP_BROKER: {
+      if (!duplicate_rule.AddNumberMatch(IF, HandleTarget::TARGET,
+                                         ::GetCurrentProcessId(), EQUAL)) {
+        return false;
+      }
+      break;
+    }
+
+    default:
+     return false;
+  }
+  if (!duplicate_rule.AddStringMatch(IF, HandleTarget::NAME, type_name,
+                                     CASE_INSENSITIVE)) {
+    return false;
+  }
+  if (!policy->AddRule(IPC_DUPLICATEHANDLEPROXY_TAG, &duplicate_rule)) {
+    return false;
+  }
+  return true;
+}
+
+DWORD HandlePolicy::DuplicateHandleProxyAction(EvalResult eval_result,
+                                               HANDLE source_handle,
+                                               DWORD target_process_id,
+                                               HANDLE* target_handle,
+                                               DWORD desired_access,
+                                               DWORD options) {
+  // The only action supported is ASK_BROKER which means duplicate the handle.
+  if (ASK_BROKER != eval_result) {
+    return ERROR_ACCESS_DENIED;
+  }
+
+  base::win::ScopedHandle remote_target_process;
+  if (target_process_id != ::GetCurrentProcessId()) {
+    // Sandboxed children are dynamic, so we check that manually.
+    if (!BrokerServicesBase::GetInstance()->IsActiveTarget(target_process_id)) {
+      return ERROR_ACCESS_DENIED;
+    }
+
+    remote_target_process.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE,
+                                            target_process_id));
+    if (!remote_target_process.IsValid())
+      return ::GetLastError();
+  }
+
+  // If the policy didn't block us and we have no valid target, then the broker
+  // (this process) is the valid target.
+  HANDLE target_process = remote_target_process.IsValid() ?
+                          remote_target_process.Get() : ::GetCurrentProcess();
+  if (!::DuplicateHandle(::GetCurrentProcess(), source_handle, target_process,
+                         target_handle, desired_access, FALSE,
+                         options)) {
+    return ::GetLastError();
+  }
+
+  return ERROR_SUCCESS;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/handle_policy.h b/sandbox/win/src/handle_policy.h
new file mode 100644
index 0000000..ffe54b8
--- /dev/null
+++ b/sandbox/win/src/handle_policy.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_POLICY_H_
+#define SANDBOX_SRC_HANDLE_POLICY_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to handle policy.
+class HandlePolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule for handles, in particular duplicate action.
+  static bool GenerateRules(const wchar_t* type_name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Processes a 'TargetPolicy::DuplicateHandle()' request from the target.
+  static DWORD DuplicateHandleProxyAction(EvalResult eval_result,
+                                          HANDLE source_handle,
+                                          DWORD target_process_id,
+                                          HANDLE* target_handle,
+                                          DWORD desired_access,
+                                          DWORD options);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_POLICY_H_
+
diff --git a/sandbox/win/src/handle_policy_test.cc b/sandbox/win/src/handle_policy_test.cc
new file mode 100644
index 0000000..11382da
--- /dev/null
+++ b/sandbox/win/src/handle_policy_test.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Just waits for the supplied number of milliseconds.
+SBOX_TESTS_COMMAND int Handle_WaitProcess(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  ::Sleep(::wcstoul(argv[0], NULL, 10));
+  return SBOX_TEST_TIMED_OUT;
+}
+
+// Attempts to duplicate an event handle into the target process.
+SBOX_TESTS_COMMAND int Handle_DuplicateEvent(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  // Create a test event to use as a handle.
+  base::win::ScopedHandle test_event;
+  test_event.Set(::CreateEvent(NULL, TRUE, TRUE, NULL));
+  if (!test_event.IsValid())
+    return SBOX_TEST_FIRST_ERROR;
+
+  // Get the target process ID.
+  DWORD target_process_id = ::wcstoul(argv[0], NULL, 10);
+
+  HANDLE handle = NULL;
+  ResultCode result = SandboxFactory::GetTargetServices()->DuplicateHandle(
+      test_event.Get(), target_process_id, &handle, 0, DUPLICATE_SAME_ACCESS);
+
+  return (result == SBOX_ALL_OK) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicateHandle) {
+  TestRunner target;
+  TestRunner runner;
+
+  // Kick off an asynchronous target process for testing.
+  target.SetAsynchronous(true);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000"));
+
+  // First test that we fail to open the event.
+  base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+                                               target.process_id());
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+  // Now successfully open the event after adding a duplicate handle rule.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+                             TargetPolicy::HANDLES_DUP_ANY,
+                             L"Event"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicatePeerHandle) {
+  TestRunner target;
+  TestRunner runner;
+
+  // Kick off an asynchronous target process for testing.
+  target.SetAsynchronous(true);
+  target.SetUnsandboxed(true);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000"));
+
+  // First test that we fail to open the event.
+  base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+                                               target.process_id());
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+  // Now successfully open the event after adding a duplicate handle rule.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+                             TargetPolicy::HANDLES_DUP_ANY,
+                             L"Event"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicateBrokerHandle) {
+  TestRunner runner;
+
+  // First test that we fail to open the event.
+  base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+                                             ::GetCurrentProcessId());
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+  // Add the peer rule and make sure we fail again.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+                             TargetPolicy::HANDLES_DUP_ANY,
+                             L"Event"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+
+  // Now successfully open the event after adding a broker handle rule.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+                             TargetPolicy::HANDLES_DUP_BROKER,
+                             L"Event"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/handle_table.cc b/sandbox/win/src/handle_table.cc
new file mode 100644
index 0000000..5ebcf99
--- /dev/null
+++ b/sandbox/win/src/handle_table.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_table.h"
+
+#include <algorithm>
+#include <cstdlib>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+bool CompareHandleEntries(const SYSTEM_HANDLE_INFORMATION& a,
+                          const SYSTEM_HANDLE_INFORMATION& b) {
+  return a.ProcessId < b.ProcessId;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+const base::char16* HandleTable::kTypeProcess = L"Process";
+const base::char16* HandleTable::kTypeThread = L"Thread";
+const base::char16* HandleTable::kTypeFile = L"File";
+const base::char16* HandleTable::kTypeDirectory = L"Directory";
+const base::char16* HandleTable::kTypeKey = L"Key";
+const base::char16* HandleTable::kTypeWindowStation = L"WindowStation";
+const base::char16* HandleTable::kTypeDesktop = L"Desktop";
+const base::char16* HandleTable::kTypeService = L"Service";
+const base::char16* HandleTable::kTypeMutex = L"Mutex";
+const base::char16* HandleTable::kTypeSemaphore = L"Semaphore";
+const base::char16* HandleTable::kTypeEvent = L"Event";
+const base::char16* HandleTable::kTypeTimer = L"Timer";
+const base::char16* HandleTable::kTypeNamedPipe = L"NamedPipe";
+const base::char16* HandleTable::kTypeJobObject = L"JobObject";
+const base::char16* HandleTable::kTypeFileMap = L"FileMap";
+const base::char16* HandleTable::kTypeAlpcPort = L"ALPC Port";
+
+HandleTable::HandleTable() {
+  static NtQuerySystemInformation QuerySystemInformation = NULL;
+  if (!QuerySystemInformation)
+    ResolveNTFunctionPtr("NtQuerySystemInformation", &QuerySystemInformation);
+
+  ULONG size = 0x15000;
+  NTSTATUS result;
+  do {
+    handle_info_buffer_.resize(size);
+    result = QuerySystemInformation(SystemHandleInformation,
+        handle_info_internal(), size, &size);
+  } while (result == STATUS_INFO_LENGTH_MISMATCH);
+
+  // We failed, so make an empty table.
+  if (!NT_SUCCESS(result)) {
+    handle_info_buffer_.resize(0);
+    return;
+  }
+
+  // Sort it to make process lookups faster.
+  std::sort(handle_info_internal()->Information,
+      handle_info_internal()->Information +
+      handle_info_internal()->NumberOfHandles, CompareHandleEntries);
+}
+
+HandleTable::~HandleTable() {
+}
+
+HandleTable::Iterator HandleTable::HandlesForProcess(ULONG process_id) const {
+  SYSTEM_HANDLE_INFORMATION key;
+  key.ProcessId = static_cast<USHORT>(process_id);
+
+  const SYSTEM_HANDLE_INFORMATION* start = handle_info()->Information;
+  const SYSTEM_HANDLE_INFORMATION* finish =
+      &handle_info()->Information[handle_info()->NumberOfHandles];
+
+  start = std::lower_bound(start, finish, key, CompareHandleEntries);
+  if (start->ProcessId != process_id)
+    return Iterator(*this, finish, finish);
+  finish = std::upper_bound(start, finish, key, CompareHandleEntries);
+  return Iterator(*this, start, finish);
+}
+
+HandleTable::HandleEntry::HandleEntry(
+    const SYSTEM_HANDLE_INFORMATION* handle_info_entry)
+    : handle_entry_(handle_info_entry), last_entry_(0) {
+}
+
+HandleTable::HandleEntry::~HandleEntry() {
+}
+
+void HandleTable::HandleEntry::UpdateInfo(UpdateType flag) {
+  static NtQueryObject QueryObject = NULL;
+  if (!QueryObject)
+    ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+  NTSTATUS result;
+
+  // Always update the basic type info, but grab the names as needed.
+  if (needs_info_update()) {
+    handle_name_.clear();
+    type_name_.clear();
+    last_entry_ = handle_entry_;
+
+    // Most handle names are very short, so start small and reuse this buffer.
+    if (type_info_buffer_.empty())
+      type_info_buffer_.resize(sizeof(OBJECT_TYPE_INFORMATION)
+          + (32 * sizeof(wchar_t)));
+    ULONG size = static_cast<ULONG>(type_info_buffer_.size());
+    result = QueryObject(reinterpret_cast<HANDLE>(handle_entry_->Handle),
+        ObjectTypeInformation, type_info_internal(), size, &size);
+    while (result == STATUS_INFO_LENGTH_MISMATCH) {
+      type_info_buffer_.resize(size);
+      result = QueryObject(reinterpret_cast<HANDLE>(handle_entry_->Handle),
+          ObjectTypeInformation, type_info_internal(), size, &size);
+    }
+
+    if (!NT_SUCCESS(result)) {
+      type_info_buffer_.clear();
+      return;
+    }
+  }
+
+  // Don't bother copying out names until we ask for them, and then cache them.
+  switch (flag) {
+    case UPDATE_INFO_AND_NAME:
+      if (type_info_buffer_.size() && handle_name_.empty()) {
+        ULONG size = MAX_PATH;
+        scoped_ptr<UNICODE_STRING, base::FreeDeleter> name;
+        do {
+          name.reset(static_cast<UNICODE_STRING*>(malloc(size)));
+          DCHECK(name.get());
+          result = QueryObject(reinterpret_cast<HANDLE>(
+              handle_entry_->Handle), ObjectNameInformation, name.get(),
+              size, &size);
+        } while (result == STATUS_INFO_LENGTH_MISMATCH);
+
+        if (NT_SUCCESS(result)) {
+          handle_name_.assign(name->Buffer, name->Length / sizeof(wchar_t));
+        }
+      }
+      break;
+
+    case UPDATE_INFO_AND_TYPE_NAME:
+      if (!type_info_buffer_.empty() && type_info_internal()->Name.Buffer &&
+          type_name_.empty()) {
+        type_name_.assign(type_info_internal()->Name.Buffer,
+            type_info_internal()->Name.Length / sizeof(wchar_t));
+      }
+      break;
+  }
+}
+
+const OBJECT_TYPE_INFORMATION* HandleTable::HandleEntry::TypeInfo() {
+  UpdateInfo(UPDATE_INFO_ONLY);
+  return type_info_buffer_.empty() ? NULL : type_info_internal();
+}
+
+const base::string16& HandleTable::HandleEntry::Name() {
+  UpdateInfo(UPDATE_INFO_AND_NAME);
+  return handle_name_;
+}
+
+const base::string16& HandleTable::HandleEntry::Type() {
+  UpdateInfo(UPDATE_INFO_AND_TYPE_NAME);
+  return type_name_;
+}
+
+bool HandleTable::HandleEntry::IsType(const base::string16& type_string) {
+  UpdateInfo(UPDATE_INFO_ONLY);
+  if (type_info_buffer_.empty())
+    return false;
+  return type_string.compare(0,
+      type_info_internal()->Name.Length / sizeof(wchar_t),
+      type_info_internal()->Name.Buffer) == 0;
+}
+
+HandleTable::Iterator::Iterator(const HandleTable& table,
+                                const SYSTEM_HANDLE_INFORMATION* start,
+                                const SYSTEM_HANDLE_INFORMATION* end)
+    : table_(table), current_(start), end_(end) {
+}
+
+HandleTable::Iterator::Iterator(const Iterator& it)
+    : table_(it.table_), current_(it.current_.handle_entry_), end_(it.end_) {
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/handle_table.h b/sandbox/win/src/handle_table.h
new file mode 100644
index 0000000..47f625d
--- /dev/null
+++ b/sandbox/win/src/handle_table.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.
+
+#ifndef SANDBOX_SRC_HANDLE_TABLE_H_
+#define SANDBOX_SRC_HANDLE_TABLE_H_
+
+#include <windows.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+// HandleTable retrieves the global handle table and provides helper classes
+// for iterating through the table and retrieving handle info.
+class HandleTable {
+ public:
+  static const base::char16* HandleTable::kTypeProcess;
+  static const base::char16* HandleTable::kTypeThread;
+  static const base::char16* HandleTable::kTypeFile;
+  static const base::char16* HandleTable::kTypeDirectory;
+  static const base::char16* HandleTable::kTypeKey;
+  static const base::char16* HandleTable::kTypeWindowStation;
+  static const base::char16* HandleTable::kTypeDesktop;
+  static const base::char16* HandleTable::kTypeService;
+  static const base::char16* HandleTable::kTypeMutex;
+  static const base::char16* HandleTable::kTypeSemaphore;
+  static const base::char16* HandleTable::kTypeEvent;
+  static const base::char16* HandleTable::kTypeTimer;
+  static const base::char16* HandleTable::kTypeNamedPipe;
+  static const base::char16* HandleTable::kTypeJobObject;
+  static const base::char16* HandleTable::kTypeFileMap;
+  static const base::char16* HandleTable::kTypeAlpcPort;
+
+  class Iterator;
+
+  // Used by the iterator to provide simple caching accessors to handle data.
+  class HandleEntry {
+   public:
+    ~HandleEntry();
+
+    bool operator==(const HandleEntry& rhs) const {
+      return handle_entry_ == rhs.handle_entry_;
+    }
+
+    bool operator!=(const HandleEntry& rhs) const {
+      return handle_entry_ != rhs.handle_entry_;
+    }
+
+    const SYSTEM_HANDLE_INFORMATION* handle_entry() const {
+      return handle_entry_;
+    }
+
+    const OBJECT_TYPE_INFORMATION* TypeInfo();
+
+    const base::string16& Name();
+
+    const base::string16& Type();
+
+    bool IsType(const base::string16& type_string);
+
+   private:
+    friend class Iterator;
+    friend class HandleTable;
+
+    enum UpdateType {
+      UPDATE_INFO_ONLY,
+      UPDATE_INFO_AND_NAME,
+      UPDATE_INFO_AND_TYPE_NAME,
+    };
+
+    explicit HandleEntry(const SYSTEM_HANDLE_INFORMATION* handle_info_entry);
+
+    bool needs_info_update() { return handle_entry_ != last_entry_; }
+
+    void UpdateInfo(UpdateType flag);
+
+    OBJECT_TYPE_INFORMATION* type_info_internal() {
+      return reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
+          &(type_info_buffer_[0]));
+    }
+
+    const SYSTEM_HANDLE_INFORMATION* handle_entry_;
+    const SYSTEM_HANDLE_INFORMATION* last_entry_;
+    std::vector<BYTE> type_info_buffer_;
+    base::string16 handle_name_;
+    base::string16 type_name_;
+
+    DISALLOW_COPY_AND_ASSIGN(HandleEntry);
+  };
+
+  class Iterator {
+   public:
+    Iterator(const HandleTable& table, const SYSTEM_HANDLE_INFORMATION* start,
+             const SYSTEM_HANDLE_INFORMATION* stop);
+
+    Iterator(const Iterator& it);
+
+    Iterator& operator++() {
+      if (++(current_.handle_entry_) == end_)
+        current_.handle_entry_ = table_.end();
+      return *this;
+    }
+
+    bool operator==(const Iterator& rhs) const {
+      return current_ == rhs.current_;
+    }
+
+    bool operator!=(const Iterator& rhs) const {
+      return current_ != rhs.current_;
+    }
+
+    HandleEntry& operator*() { return current_; }
+
+    operator const SYSTEM_HANDLE_INFORMATION*() {
+      return current_.handle_entry_;
+    }
+
+    HandleEntry* operator->() { return &current_; }
+
+   private:
+    const HandleTable& table_;
+    HandleEntry current_;
+    const SYSTEM_HANDLE_INFORMATION* end_;
+  };
+
+  HandleTable();
+  ~HandleTable();
+
+  Iterator begin() const {
+    return Iterator(*this, handle_info()->Information,
+        &handle_info()->Information[handle_info()->NumberOfHandles]);
+  }
+
+  const SYSTEM_HANDLE_INFORMATION_EX* handle_info() const {
+    return reinterpret_cast<const SYSTEM_HANDLE_INFORMATION_EX*>(
+        &(handle_info_buffer_[0]));
+  }
+
+  // Returns an iterator to the handles for only the supplied process ID.
+  Iterator HandlesForProcess(ULONG process_id) const;
+  const SYSTEM_HANDLE_INFORMATION* end() const {
+    return &handle_info()->Information[handle_info()->NumberOfHandles];
+  }
+
+ private:
+  SYSTEM_HANDLE_INFORMATION_EX* handle_info_internal() {
+    return reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(
+        &(handle_info_buffer_[0]));
+  }
+
+  std::vector<BYTE> handle_info_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(HandleTable);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_HANDLE_TABLE_H_
diff --git a/sandbox/win/src/integrity_level_test.cc b/sandbox/win/src/integrity_level_test.cc
new file mode 100644
index 0000000..f962033
--- /dev/null
+++ b/sandbox/win/src/integrity_level_test.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <atlsecurity.h>
+
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/tests/common/controller.h"
+
+namespace sandbox {
+
+
+SBOX_TESTS_COMMAND int CheckIntegrityLevel(int argc, wchar_t **argv) {
+  ATL::CAccessToken token;
+  if (!token.GetEffectiveToken(TOKEN_READ))
+    return SBOX_TEST_FAILED;
+
+  char* buffer[100];
+  DWORD buf_size = 100;
+  if (!::GetTokenInformation(token.GetHandle(), TokenIntegrityLevel,
+                             reinterpret_cast<void*>(buffer), buf_size,
+                             &buf_size))
+    return SBOX_TEST_FAILED;
+
+  TOKEN_MANDATORY_LABEL* label =
+      reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buffer);
+
+  PSID sid_low = NULL;
+  if (!::ConvertStringSidToSid(L"S-1-16-4096", &sid_low))
+    return SBOX_TEST_FAILED;
+
+  BOOL is_low_sid = ::EqualSid(label->Label.Sid, sid_low);
+
+  ::LocalFree(sid_low);
+
+  if (is_low_sid)
+    return SBOX_TEST_SUCCEEDED;
+
+  return SBOX_TEST_DENIED;
+}
+
+TEST(IntegrityLevelTest, TestLowILReal) {
+  if (base::win::GetVersion() != base::win::VERSION_VISTA)
+    return;
+
+  TestRunner runner(JOB_LOCKDOWN, USER_INTERACTIVE, USER_INTERACTIVE);
+
+  runner.SetTimeout(INFINITE);
+
+  runner.GetPolicy()->SetAlternateDesktop(true);
+  runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIntegrityLevel"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIntegrityLevel"));
+}
+
+TEST(DelayedIntegrityLevelTest, TestLowILDelayed) {
+  if (base::win::GetVersion() != base::win::VERSION_VISTA)
+    return;
+
+  TestRunner runner(JOB_LOCKDOWN, USER_INTERACTIVE, USER_INTERACTIVE);
+
+  runner.SetTimeout(INFINITE);
+
+  runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_LOW);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIntegrityLevel"));
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"CheckIntegrityLevel"));
+}
+
+TEST(IntegrityLevelTest, TestNoILChange) {
+  if (base::win::GetVersion() != base::win::VERSION_VISTA)
+    return;
+
+  TestRunner runner(JOB_LOCKDOWN, USER_INTERACTIVE, USER_INTERACTIVE);
+
+  runner.SetTimeout(INFINITE);
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"CheckIntegrityLevel"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/interception.cc b/sandbox/win/src/interception.cc
new file mode 100644
index 0000000..60dd440
--- /dev/null
+++ b/sandbox/win/src/interception.cc
@@ -0,0 +1,554 @@
+// Copyright (c) 2012 The Chromium 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 information about interceptions as a whole see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#include <set>
+
+#include "sandbox/win/src/interception.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/win/pe_image.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/service_resolver.h"
+#include "sandbox/win/src/target_interceptions.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/wow64.h"
+
+namespace {
+
+const char kMapViewOfSectionName[] = "NtMapViewOfSection";
+const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection";
+
+// Standard allocation granularity and page size for Windows.
+const size_t kAllocGranularity = 65536;
+const size_t kPageSize = 4096;
+
+// Find a random offset within 64k and aligned to ceil(log2(size)).
+size_t GetGranularAlignedRandomOffset(size_t size) {
+  CHECK_LE(size, kAllocGranularity);
+  unsigned int offset;
+
+  do {
+    rand_s(&offset);
+    offset &= (kAllocGranularity - 1);
+  } while (offset > (kAllocGranularity - size));
+
+  // Find an alignment between 64 and the page size (4096).
+  size_t align_size = kPageSize;
+  for (size_t new_size = align_size / 2;  new_size >= size; new_size /= 2) {
+    align_size = new_size;
+  }
+  return offset & ~(align_size - 1);
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT SharedMemory* g_interceptions;
+
+// Table of the unpatched functions that we intercept. Mapped from the parent.
+SANDBOX_INTERCEPT OriginalFunctions g_originals = { NULL };
+
+// Magic constant that identifies that this function is not to be patched.
+const char kUnloadDLLDummyFunction[] = "@";
+
+InterceptionManager::InterceptionData::InterceptionData() {
+}
+
+InterceptionManager::InterceptionData::~InterceptionData() {
+}
+
+InterceptionManager::InterceptionManager(TargetProcess* child_process,
+                                         bool relaxed)
+    : child_(child_process), names_used_(false), relaxed_(relaxed) {
+  child_->AddRef();
+}
+InterceptionManager::~InterceptionManager() {
+  child_->Release();
+}
+
+bool InterceptionManager::AddToPatchedFunctions(
+    const wchar_t* dll_name, const char* function_name,
+    InterceptionType interception_type, const void* replacement_code_address,
+    InterceptorId id) {
+  InterceptionData function;
+  function.type = interception_type;
+  function.id = id;
+  function.dll = dll_name;
+  function.function = function_name;
+  function.interceptor_address = replacement_code_address;
+
+  interceptions_.push_back(function);
+  return true;
+}
+
+bool InterceptionManager::AddToPatchedFunctions(
+    const wchar_t* dll_name, const char* function_name,
+    InterceptionType interception_type, const char* replacement_function_name,
+    InterceptorId id) {
+  InterceptionData function;
+  function.type = interception_type;
+  function.id = id;
+  function.dll = dll_name;
+  function.function = function_name;
+  function.interceptor = replacement_function_name;
+  function.interceptor_address = NULL;
+
+  interceptions_.push_back(function);
+  names_used_ = true;
+  return true;
+}
+
+bool InterceptionManager::AddToUnloadModules(const wchar_t* dll_name) {
+  InterceptionData module_to_unload;
+  module_to_unload.type = INTERCEPTION_UNLOAD_MODULE;
+  module_to_unload.dll = dll_name;
+  // The next two are dummy values that make the structures regular, instead
+  // of having special cases. They should not be used.
+  module_to_unload.function = kUnloadDLLDummyFunction;
+  module_to_unload.interceptor_address = reinterpret_cast<void*>(1);
+
+  interceptions_.push_back(module_to_unload);
+  return true;
+}
+
+bool InterceptionManager::InitializeInterceptions() {
+  if (interceptions_.empty())
+    return true;  // Nothing to do here
+
+  size_t buffer_bytes = GetBufferSize();
+  scoped_ptr<char[]> local_buffer(new char[buffer_bytes]);
+
+  if (!SetupConfigBuffer(local_buffer.get(), buffer_bytes))
+    return false;
+
+  void* remote_buffer;
+  if (!CopyDataToChild(local_buffer.get(), buffer_bytes, &remote_buffer))
+    return false;
+
+  bool hot_patch_needed = (0 != buffer_bytes);
+  if (!PatchNtdll(hot_patch_needed))
+    return false;
+
+  g_interceptions = reinterpret_cast<SharedMemory*>(remote_buffer);
+  ResultCode rc = child_->TransferVariable("g_interceptions",
+                                           &g_interceptions,
+                                           sizeof(g_interceptions));
+  return (SBOX_ALL_OK == rc);
+}
+
+size_t InterceptionManager::GetBufferSize() const {
+  std::set<base::string16> dlls;
+  size_t buffer_bytes = 0;
+
+  std::list<InterceptionData>::const_iterator it = interceptions_.begin();
+  for (; it != interceptions_.end(); ++it) {
+    // skip interceptions that are performed from the parent
+    if (!IsInterceptionPerformedByChild(*it))
+      continue;
+
+    if (!dlls.count(it->dll)) {
+      // NULL terminate the dll name on the structure
+      size_t dll_name_bytes = (it->dll.size() + 1) * sizeof(wchar_t);
+
+      // include the dll related size
+      buffer_bytes += RoundUpToMultiple(offsetof(DllPatchInfo, dll_name) +
+                                            dll_name_bytes, sizeof(size_t));
+      dlls.insert(it->dll);
+    }
+
+    // we have to NULL terminate the strings on the structure
+    size_t strings_chars = it->function.size() + it->interceptor.size() + 2;
+
+    // a new FunctionInfo is required per function
+    size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars;
+    record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t));
+    buffer_bytes += record_bytes;
+  }
+
+  if (0 != buffer_bytes)
+    // add the part of SharedMemory that we have not counted yet
+    buffer_bytes += offsetof(SharedMemory, dll_list);
+
+  return buffer_bytes;
+}
+
+// Basically, walk the list of interceptions moving them to the config buffer,
+// but keeping together all interceptions that belong to the same dll.
+// The config buffer is a local buffer, not the one allocated on the child.
+bool InterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes) {
+  if (0 == buffer_bytes)
+    return true;
+
+  DCHECK(buffer_bytes > sizeof(SharedMemory));
+
+  SharedMemory* shared_memory = reinterpret_cast<SharedMemory*>(buffer);
+  DllPatchInfo* dll_info = shared_memory->dll_list;
+  int num_dlls = 0;
+
+  shared_memory->interceptor_base = names_used_ ? child_->MainModule() : NULL;
+
+  buffer_bytes -= offsetof(SharedMemory, dll_list);
+  buffer = dll_info;
+
+  std::list<InterceptionData>::iterator it = interceptions_.begin();
+  for (; it != interceptions_.end();) {
+    // skip interceptions that are performed from the parent
+    if (!IsInterceptionPerformedByChild(*it)) {
+      ++it;
+      continue;
+    }
+
+    const base::string16 dll = it->dll;
+    if (!SetupDllInfo(*it, &buffer, &buffer_bytes))
+      return false;
+
+    // walk the interceptions from this point, saving the ones that are
+    // performed on this dll, and removing the entry from the list.
+    // advance the iterator before removing the element from the list
+    std::list<InterceptionData>::iterator rest = it;
+    for (; rest != interceptions_.end();) {
+      if (rest->dll == dll) {
+        if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info))
+          return false;
+        if (it == rest)
+          ++it;
+        rest = interceptions_.erase(rest);
+      } else {
+        ++rest;
+      }
+    }
+    dll_info = reinterpret_cast<DllPatchInfo*>(buffer);
+    ++num_dlls;
+  }
+
+  shared_memory->num_intercepted_dlls = num_dlls;
+  return true;
+}
+
+// Fills up just the part that depends on the dll, not the info that depends on
+// the actual interception.
+bool InterceptionManager::SetupDllInfo(const InterceptionData& data,
+                                       void** buffer,
+                                       size_t* buffer_bytes) const {
+  DCHECK(buffer_bytes);
+  DCHECK(buffer);
+  DCHECK(*buffer);
+
+  DllPatchInfo* dll_info = reinterpret_cast<DllPatchInfo*>(*buffer);
+
+  // the strings have to be zero terminated
+  size_t required = offsetof(DllPatchInfo, dll_name) +
+                    (data.dll.size() + 1) * sizeof(wchar_t);
+  required = RoundUpToMultiple(required, sizeof(size_t));
+  if (*buffer_bytes < required)
+    return false;
+
+  *buffer_bytes -= required;
+  *buffer = reinterpret_cast<char*>(*buffer) + required;
+
+  // set up the dll info to be what we know about it at this time
+  dll_info->unload_module = (data.type == INTERCEPTION_UNLOAD_MODULE);
+  dll_info->record_bytes = required;
+  dll_info->offset_to_functions = required;
+  dll_info->num_functions = 0;
+  data.dll._Copy_s(dll_info->dll_name, data.dll.size(), data.dll.size());
+  dll_info->dll_name[data.dll.size()] = L'\0';
+
+  return true;
+}
+
+bool InterceptionManager::SetupInterceptionInfo(const InterceptionData& data,
+                                                void** buffer,
+                                                size_t* buffer_bytes,
+                                                DllPatchInfo* dll_info) const {
+  DCHECK(buffer_bytes);
+  DCHECK(buffer);
+  DCHECK(*buffer);
+
+  if ((dll_info->unload_module) &&
+      (data.function != kUnloadDLLDummyFunction)) {
+    // Can't specify a dll for both patch and unload.
+    NOTREACHED();
+  }
+
+  FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);
+
+  size_t name_bytes = data.function.size();
+  size_t interceptor_bytes = data.interceptor.size();
+
+  // the strings at the end of the structure are zero terminated
+  size_t required = offsetof(FunctionInfo, function) +
+                    name_bytes + interceptor_bytes + 2;
+  required = RoundUpToMultiple(required, sizeof(size_t));
+  if (*buffer_bytes < required)
+    return false;
+
+  // update the caller's values
+  *buffer_bytes -= required;
+  *buffer = reinterpret_cast<char*>(*buffer) + required;
+
+  function->record_bytes = required;
+  function->type = data.type;
+  function->id = data.id;
+  function->interceptor_address = data.interceptor_address;
+  char* names = function->function;
+
+  data.function._Copy_s(names, name_bytes, name_bytes);
+  names += name_bytes;
+  *names++ = '\0';
+
+  // interceptor follows the function_name
+  data.interceptor._Copy_s(names, interceptor_bytes, interceptor_bytes);
+  names += interceptor_bytes;
+  *names++ = '\0';
+
+  // update the dll table
+  dll_info->num_functions++;
+  dll_info->record_bytes += required;
+
+  return true;
+}
+
+bool InterceptionManager::CopyDataToChild(const void* local_buffer,
+                                          size_t buffer_bytes,
+                                          void** remote_buffer) const {
+  DCHECK(NULL != remote_buffer);
+  if (0 == buffer_bytes) {
+    *remote_buffer = NULL;
+    return true;
+  }
+
+  HANDLE child = child_->Process();
+
+  // Allocate memory on the target process without specifying the address
+  void* remote_data = ::VirtualAllocEx(child, NULL, buffer_bytes,
+                                       MEM_COMMIT, PAGE_READWRITE);
+  if (NULL == remote_data)
+    return false;
+
+  SIZE_T bytes_written;
+  BOOL success = ::WriteProcessMemory(child, remote_data, local_buffer,
+                                      buffer_bytes, &bytes_written);
+  if (FALSE == success || bytes_written != buffer_bytes) {
+    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
+    return false;
+  }
+
+  *remote_buffer = remote_data;
+
+  return true;
+}
+
+// Only return true if the child should be able to perform this interception.
+bool InterceptionManager::IsInterceptionPerformedByChild(
+    const InterceptionData& data) const {
+  if (INTERCEPTION_INVALID == data.type)
+    return false;
+
+  if (INTERCEPTION_SERVICE_CALL == data.type)
+    return false;
+
+  if (data.type >= INTERCEPTION_LAST)
+    return false;
+
+  base::string16 ntdll(kNtdllName);
+  if (ntdll == data.dll)
+    return false;  // ntdll has to be intercepted from the parent
+
+  return true;
+}
+
+bool InterceptionManager::PatchNtdll(bool hot_patch_needed) {
+  // Maybe there is nothing to do
+  if (!hot_patch_needed && interceptions_.empty())
+    return true;
+
+  if (hot_patch_needed) {
+#if SANDBOX_EXPORTS
+    // Make sure the functions are not excluded by the linker.
+#if defined(_WIN64)
+    #pragma comment(linker, "/include:TargetNtMapViewOfSection64")
+    #pragma comment(linker, "/include:TargetNtUnmapViewOfSection64")
+#else
+    #pragma comment(linker, "/include:_TargetNtMapViewOfSection@44")
+    #pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12")
+#endif
+#endif
+    ADD_NT_INTERCEPTION(NtMapViewOfSection, MAP_VIEW_OF_SECTION_ID, 44);
+    ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12);
+  }
+
+  // Reserve a full 64k memory range in the child process.
+  HANDLE child = child_->Process();
+  BYTE* thunk_base = reinterpret_cast<BYTE*>(
+                         ::VirtualAllocEx(child, NULL, kAllocGranularity,
+                                          MEM_RESERVE, PAGE_NOACCESS));
+
+  // Find an aligned, random location within the reserved range.
+  size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) +
+                       sizeof(DllInterceptionData);
+  size_t thunk_offset = GetGranularAlignedRandomOffset(thunk_bytes);
+
+  // Split the base and offset along page boundaries.
+  thunk_base += thunk_offset & ~(kPageSize - 1);
+  thunk_offset &= kPageSize - 1;
+
+  // Make an aligned, padded allocation, and move the pointer to our chunk.
+  size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & ~(kPageSize - 1);
+  thunk_base = reinterpret_cast<BYTE*>(
+                   ::VirtualAllocEx(child, thunk_base, thunk_bytes_padded,
+                                    MEM_COMMIT, PAGE_EXECUTE_READWRITE));
+  CHECK(thunk_base);  // If this fails we'd crash anyway on an invalid access.
+  DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>(
+                                    thunk_base + thunk_offset);
+
+  DllInterceptionData dll_data;
+  dll_data.data_bytes = thunk_bytes;
+  dll_data.num_thunks = 0;
+  dll_data.used_bytes = offsetof(DllInterceptionData, thunks);
+
+  // Reset all helpers for a new child.
+  memset(g_originals, 0, sizeof(g_originals));
+
+  // this should write all the individual thunks to the child's memory
+  if (!PatchClientFunctions(thunks, thunk_bytes, &dll_data))
+    return false;
+
+  // and now write the first part of the table to the child's memory
+  SIZE_T written;
+  bool ok = FALSE != ::WriteProcessMemory(child, thunks, &dll_data,
+                                          offsetof(DllInterceptionData, thunks),
+                                          &written);
+
+  if (!ok || (offsetof(DllInterceptionData, thunks) != written))
+    return false;
+
+  // Attempt to protect all the thunks, but ignore failure
+  DWORD old_protection;
+  ::VirtualProtectEx(child, thunks, thunk_bytes,
+                     PAGE_EXECUTE_READ, &old_protection);
+
+  ResultCode ret = child_->TransferVariable("g_originals", g_originals,
+                                            sizeof(g_originals));
+  return (SBOX_ALL_OK == ret);
+}
+
+bool InterceptionManager::PatchClientFunctions(DllInterceptionData* thunks,
+                                               size_t thunk_bytes,
+                                               DllInterceptionData* dll_data) {
+  DCHECK(NULL != thunks);
+  DCHECK(NULL != dll_data);
+
+  HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
+  if (!ntdll_base)
+    return false;
+
+  base::win::PEImage ntdll_image(ntdll_base);
+
+  // Bypass purify's interception.
+  wchar_t* loader_get = reinterpret_cast<wchar_t*>(
+                            ntdll_image.GetProcAddress("LdrGetDllHandle"));
+  if (loader_get) {
+    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                               GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                           loader_get, &ntdll_base))
+      return false;
+  }
+
+  if (base::win::GetVersion() <= base::win::VERSION_VISTA) {
+    Wow64 WowHelper(child_, ntdll_base);
+    if (!WowHelper.WaitForNtdll())
+      return false;
+  }
+
+  char* interceptor_base = NULL;
+
+#if SANDBOX_EXPORTS
+  interceptor_base = reinterpret_cast<char*>(child_->MainModule());
+  HMODULE local_interceptor = ::LoadLibrary(child_->Name());
+#endif
+
+  ServiceResolverThunk* thunk;
+#if defined(_WIN64)
+  thunk = new ServiceResolverThunk(child_->Process(), relaxed_);
+#else
+  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+  if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
+    if (os_info->version() >= base::win::VERSION_WIN8)
+      thunk = new Wow64W8ResolverThunk(child_->Process(), relaxed_);
+    else
+      thunk = new Wow64ResolverThunk(child_->Process(), relaxed_);
+  } else if (os_info->version() >= base::win::VERSION_WIN8) {
+    thunk = new Win8ResolverThunk(child_->Process(), relaxed_);
+  } else {
+    thunk = new ServiceResolverThunk(child_->Process(), relaxed_);
+  }
+#endif
+
+  std::list<InterceptionData>::iterator it = interceptions_.begin();
+  for (; it != interceptions_.end(); ++it) {
+    const base::string16 ntdll(kNtdllName);
+    if (it->dll != ntdll)
+      break;
+
+    if (INTERCEPTION_SERVICE_CALL != it->type)
+      break;
+
+#if SANDBOX_EXPORTS
+    // We may be trying to patch by function name.
+    if (NULL == it->interceptor_address) {
+      const char* address;
+      NTSTATUS ret = thunk->ResolveInterceptor(local_interceptor,
+                                               it->interceptor.c_str(),
+                                               reinterpret_cast<const void**>(
+                                               &address));
+      if (!NT_SUCCESS(ret))
+        break;
+
+      // Translate the local address to an address on the child.
+      it->interceptor_address = interceptor_base + (address -
+                                    reinterpret_cast<char*>(local_interceptor));
+    }
+#endif
+    NTSTATUS ret = thunk->Setup(ntdll_base,
+                                interceptor_base,
+                                it->function.c_str(),
+                                it->interceptor.c_str(),
+                                it->interceptor_address,
+                                &thunks->thunks[dll_data->num_thunks],
+                                thunk_bytes - dll_data->used_bytes,
+                                NULL);
+    if (!NT_SUCCESS(ret))
+      break;
+
+    DCHECK(!g_originals[it->id]);
+    g_originals[it->id] = &thunks->thunks[dll_data->num_thunks];
+
+    dll_data->num_thunks++;
+    dll_data->used_bytes += sizeof(ThunkData);
+  }
+
+  delete(thunk);
+
+#if SANDBOX_EXPORTS
+  if (NULL != local_interceptor)
+    ::FreeLibrary(local_interceptor);
+#endif
+
+  if (it != interceptions_.end())
+    return false;
+
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/interception.h b/sandbox/win/src/interception.h
new file mode 100644
index 0000000..728dc74
--- /dev/null
+++ b/sandbox/win/src/interception.h
@@ -0,0 +1,284 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines InterceptionManager, the class in charge of setting up interceptions
+// for the sandboxed process. For more details see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_H_
+#define SANDBOX_SRC_INTERCEPTION_H_
+
+#include <list>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+class TargetProcess;
+enum InterceptorId;
+
+// Internal structures used for communication between the broker and the target.
+struct DllPatchInfo;
+struct DllInterceptionData;
+
+// The InterceptionManager executes on the parent application, and it is in
+// charge of setting up the desired interceptions, and placing the Interception
+// Agent into the child application.
+//
+// The exposed API consists of two methods: AddToPatchedFunctions to set up a
+// particular interception, and InitializeInterceptions to actually go ahead and
+// perform all interceptions and transfer data to the child application.
+//
+// The typical usage is something like this:
+//
+// InterceptionManager interception_manager(child);
+// if (!interception_manager.AddToPatchedFunctions(
+//         L"ntdll.dll", "NtCreateFile",
+//         sandbox::INTERCEPTION_SERVICE_CALL, &MyNtCreateFile, MY_ID_1))
+//   return false;
+//
+// if (!interception_manager.AddToPatchedFunctions(
+//         L"kernel32.dll", "CreateDirectoryW",
+//         sandbox::INTERCEPTION_EAT, L"MyCreateDirectoryW@12", MY_ID_2))
+//   return false;
+//
+// if (!interception_manager.InitializeInterceptions()) {
+//   DWORD error = ::GetLastError();
+//   return false;
+// }
+//
+// Any required syncronization must be performed outside this class. Also, it is
+// not possible to perform further interceptions after InitializeInterceptions
+// is called.
+//
+class InterceptionManager {
+  // The unit test will access private members.
+  // Allow tests to be marked DISABLED_. Note that FLAKY_ and FAILS_ prefixes
+  // do not work with sandbox tests.
+  FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout1);
+  FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout2);
+
+ public:
+  // An interception manager performs interceptions on a given child process.
+  // If we are allowed to intercept functions that have been patched by somebody
+  // else, relaxed should be set to true.
+  // Note: We increase the child's reference count internally.
+  InterceptionManager(TargetProcess* child_process, bool relaxed);
+  ~InterceptionManager();
+
+  // Patches function_name inside dll_name to point to replacement_code_address.
+  // function_name has to be an exported symbol of dll_name.
+  // Returns true on success.
+  //
+  // The new function should match the prototype and calling convention of the
+  // function to intercept except for one extra argument (the first one) that
+  // contains a pointer to the original function, to simplify the development
+  // of interceptors (for IA32). In x64, there is no extra argument to the
+  // interceptor, so the provided InterceptorId is used to keep a table of
+  // intercepted functions so that the interceptor can index that table to get
+  // the pointer that would have been the first argument (g_originals[id]).
+  //
+  // For example, to intercept NtClose, the following code could be used:
+  //
+  // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle);
+  // NTSTATUS WINAPI MyNtCose(IN NtCloseFunction OriginalClose,
+  //                          IN HANDLE Handle) {
+  //   // do something
+  //   // call the original function
+  //   return OriginalClose(Handle);
+  // }
+  //
+  // And in x64:
+  //
+  // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle);
+  // NTSTATUS WINAPI MyNtCose64(IN HANDLE Handle) {
+  //   // do something
+  //   // call the original function
+  //   NtCloseFunction OriginalClose = g_originals[NT_CLOSE_ID];
+  //   return OriginalClose(Handle);
+  // }
+  bool AddToPatchedFunctions(const wchar_t* dll_name,
+                             const char* function_name,
+                             InterceptionType interception_type,
+                             const void* replacement_code_address,
+                             InterceptorId id);
+
+  // Patches function_name inside dll_name to point to
+  // replacement_function_name.
+  bool AddToPatchedFunctions(const wchar_t* dll_name,
+                             const char* function_name,
+                             InterceptionType interception_type,
+                             const char* replacement_function_name,
+                             InterceptorId id);
+
+  // The interception agent will unload the dll with dll_name.
+  bool AddToUnloadModules(const wchar_t* dll_name);
+
+  // Initializes all interceptions on the client.
+  // Returns true on success.
+  //
+  // The child process must be created suspended, and cannot be resumed until
+  // after this method returns. In addition, no action should be performed on
+  // the child that may cause it to resume momentarily, such as injecting
+  // threads or APCs.
+  //
+  // This function must be called only once, after all interceptions have been
+  // set up using AddToPatchedFunctions.
+  bool InitializeInterceptions();
+
+ private:
+  // Used to store the interception information until the actual set-up.
+  struct InterceptionData {
+    InterceptionData();
+    ~InterceptionData();
+
+    InterceptionType type;            // Interception type.
+    InterceptorId id;                 // Interceptor id.
+    base::string16 dll;               // Name of dll to intercept.
+    std::string function;             // Name of function to intercept.
+    std::string interceptor;          // Name of interceptor function.
+    const void* interceptor_address;  // Interceptor's entry point.
+  };
+
+  // Calculates the size of the required configuration buffer.
+  size_t GetBufferSize() const;
+
+  // Rounds up the size of a given buffer, considering alignment (padding).
+  // value is the current size of the buffer, and alignment is specified in
+  // bytes.
+  static inline size_t RoundUpToMultiple(size_t value, size_t alignment) {
+    return ((value + alignment -1) / alignment) * alignment;
+  }
+
+  // Sets up a given buffer with all the information that has to be transfered
+  // to the child.
+  // Returns true on success.
+  //
+  // The buffer size should be at least the value returned by GetBufferSize
+  bool SetupConfigBuffer(void* buffer, size_t buffer_bytes);
+
+  // Fills up the part of the transfer buffer that corresponds to information
+  // about one dll to patch.
+  // data is the first recorded interception for this dll.
+  // Returns true on success.
+  //
+  // On successful return, buffer will be advanced from it's current position
+  // to the point where the next block of configuration data should be written
+  // (the actual interception info), and the current size of the buffer will
+  // decrease to account the space used by this method.
+  bool SetupDllInfo(const InterceptionData& data,
+                    void** buffer, size_t* buffer_bytes) const;
+
+  // Fills up the part of the transfer buffer that corresponds to a single
+  // function to patch.
+  // dll_info points to the dll being updated with the interception stored on
+  // data. The buffer pointer and remaining size are updated by this call.
+  // Returns true on success.
+  bool SetupInterceptionInfo(const InterceptionData& data, void** buffer,
+                             size_t* buffer_bytes,
+                             DllPatchInfo* dll_info) const;
+
+  // Returns true if this interception is to be performed by the child
+  // as opposed to from the parent.
+  bool IsInterceptionPerformedByChild(const InterceptionData& data) const;
+
+  // Allocates a buffer on the child's address space (returned on
+  // remote_buffer), and fills it with the contents of a local buffer.
+  // Returns true on success.
+  bool CopyDataToChild(const void* local_buffer, size_t buffer_bytes,
+                       void** remote_buffer) const;
+
+  // Performs the cold patch (from the parent) of ntdll.
+  // Returns true on success.
+  //
+  // This method will insert additional interceptions to launch the interceptor
+  // agent on the child process, if there are additional interceptions to do.
+  bool PatchNtdll(bool hot_patch_needed);
+
+  // Peforms the actual interceptions on ntdll.
+  // thunks is the memory to store all the thunks for this dll (on the child),
+  // and dll_data is a local buffer to hold global dll interception info.
+  // Returns true on success.
+  bool PatchClientFunctions(DllInterceptionData* thunks,
+                            size_t thunk_bytes,
+                            DllInterceptionData* dll_data);
+
+  // The process to intercept.
+  TargetProcess* child_;
+  // Holds all interception info until the call to initialize (perform the
+  // actual patch).
+  std::list<InterceptionData> interceptions_;
+
+  // Keep track of patches added by name.
+  bool names_used_;
+
+  // true if we are allowed to patch already-patched functions.
+  bool relaxed_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterceptionManager);
+};
+
+// This macro simply calls interception_manager.AddToPatchedFunctions with
+// the given service to intercept (INTERCEPTION_SERVICE_CALL), and assumes that
+// the interceptor is called "TargetXXX", where XXX is the name of the service.
+// Note that num_params is the number of bytes to pop out of the stack for
+// the exported interceptor, following the calling convention of a service call
+// (WINAPI = with the "C" underscore).
+#if SANDBOX_EXPORTS
+#if defined(_WIN64)
+#define MAKE_SERVICE_NAME(service, params) "Target" # service "64"
+#else
+#define MAKE_SERVICE_NAME(service, params) "_Target" # service "@" # params
+#endif
+
+#define ADD_NT_INTERCEPTION(service, id, num_params) \
+  AddToPatchedFunctions(kNtdllName, #service, \
+                        sandbox::INTERCEPTION_SERVICE_CALL, \
+                        MAKE_SERVICE_NAME(service, num_params), id)
+
+#define INTERCEPT_NT(manager, service, id, num_params) \
+  ((&Target##service) ? \
+    manager->ADD_NT_INTERCEPTION(service, id, num_params) : false)
+
+// When intercepting the EAT it is important that the patched version of the
+// function not call any functions imported from system libraries unless
+// |TargetServices::InitCalled()| returns true, because it is only then that
+// we are guaranteed that our IAT has been initialized.
+#define INTERCEPT_EAT(manager, dll, function, id, num_params) \
+  ((&Target##function) ? \
+    manager->AddToPatchedFunctions(dll, #function, sandbox::INTERCEPTION_EAT, \
+                                   MAKE_SERVICE_NAME(function, num_params), \
+                                   id) : \
+    false)
+#else  // SANDBOX_EXPORTS
+#if defined(_WIN64)
+#define MAKE_SERVICE_NAME(service) &Target##service##64
+#else
+#define MAKE_SERVICE_NAME(service) &Target##service
+#endif
+
+#define ADD_NT_INTERCEPTION(service, id, num_params) \
+  AddToPatchedFunctions(kNtdllName, #service, \
+                        sandbox::INTERCEPTION_SERVICE_CALL, \
+                        MAKE_SERVICE_NAME(service), id)
+
+#define INTERCEPT_NT(manager, service, id, num_params) \
+  manager->ADD_NT_INTERCEPTION(service, id, num_params)
+
+// When intercepting the EAT it is important that the patched version of the
+// function not call any functions imported from system libraries unless
+// |TargetServices::InitCalled()| returns true, because it is only then that
+// we are guaranteed that our IAT has been initialized.
+#define INTERCEPT_EAT(manager, dll, function, id, num_params) \
+  manager->AddToPatchedFunctions(dll, #function, sandbox::INTERCEPTION_EAT, \
+                                 MAKE_SERVICE_NAME(function), id)
+#endif  // SANDBOX_EXPORTS
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTION_H_
diff --git a/sandbox/win/src/interception_agent.cc b/sandbox/win/src/interception_agent.cc
new file mode 100644
index 0000000..b2a66c4
--- /dev/null
+++ b/sandbox/win/src/interception_agent.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For information about interceptions as a whole see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#include "sandbox/win/src/interception_agent.h"
+
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/eat_resolver.h"
+#include "sandbox/win/src/sidestep_resolver.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+// Returns true if target lies between base and base + range.
+bool IsWithinRange(const void* base, size_t range, const void* target) {
+  const char* end = reinterpret_cast<const char*>(base) + range;
+  return reinterpret_cast<const char*>(target) < end;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// The list of intercepted functions back-pointers.
+SANDBOX_INTERCEPT OriginalFunctions g_originals;
+
+// Memory buffer mapped from the parent, with the list of interceptions.
+SANDBOX_INTERCEPT SharedMemory* g_interceptions = NULL;
+
+InterceptionAgent* InterceptionAgent::GetInterceptionAgent() {
+  static InterceptionAgent* s_singleton = NULL;
+  if (!s_singleton) {
+    if (!g_interceptions)
+      return NULL;
+
+    size_t array_bytes = g_interceptions->num_intercepted_dlls * sizeof(void*);
+    s_singleton = reinterpret_cast<InterceptionAgent*>(
+        new(NT_ALLOC) char[array_bytes + sizeof(InterceptionAgent)]);
+
+    bool success = s_singleton->Init(g_interceptions);
+    if (!success) {
+      operator delete(s_singleton, NT_ALLOC);
+      s_singleton = NULL;
+    }
+  }
+  return s_singleton;
+}
+
+bool InterceptionAgent::Init(SharedMemory* shared_memory) {
+  interceptions_ = shared_memory;
+  for (int i = 0 ; i < shared_memory->num_intercepted_dlls; i++)
+    dlls_[i] = NULL;
+  return true;
+}
+
+bool InterceptionAgent::DllMatch(const UNICODE_STRING* full_path,
+                                 const UNICODE_STRING* name,
+                                 const DllPatchInfo* dll_info) {
+  UNICODE_STRING current_name;
+  current_name.Length = static_cast<USHORT>(g_nt.wcslen(dll_info->dll_name) *
+                                            sizeof(wchar_t));
+  current_name.MaximumLength = current_name.Length;
+  current_name.Buffer = const_cast<wchar_t*>(dll_info->dll_name);
+
+  BOOLEAN case_insensitive = TRUE;
+  if (full_path &&
+      !g_nt.RtlCompareUnicodeString(&current_name, full_path, case_insensitive))
+    return true;
+
+  if (name &&
+      !g_nt.RtlCompareUnicodeString(&current_name, name, case_insensitive))
+    return true;
+
+  return false;
+}
+
+bool InterceptionAgent::OnDllLoad(const UNICODE_STRING* full_path,
+                                  const UNICODE_STRING* name,
+                                  void* base_address) {
+  DllPatchInfo* dll_info = interceptions_->dll_list;
+  int i = 0;
+  for (; i < interceptions_->num_intercepted_dlls; i++) {
+    if (DllMatch(full_path, name, dll_info))
+      break;
+
+    dll_info = reinterpret_cast<DllPatchInfo*>(
+                   reinterpret_cast<char*>(dll_info) + dll_info->record_bytes);
+  }
+
+  // Return now if the dll is not in our list of interest.
+  if (i == interceptions_->num_intercepted_dlls)
+    return true;
+
+  // The dll must be unloaded.
+  if (dll_info->unload_module)
+    return false;
+
+  // Purify causes this condition to trigger.
+  if (dlls_[i])
+    return true;
+
+  size_t buffer_bytes = offsetof(DllInterceptionData, thunks) +
+                        dll_info->num_functions * sizeof(ThunkData);
+  dlls_[i] = reinterpret_cast<DllInterceptionData*>(
+                 new(NT_PAGE, base_address) char[buffer_bytes]);
+
+  DCHECK_NT(dlls_[i]);
+  if (!dlls_[i])
+    return true;
+
+  dlls_[i]->data_bytes = buffer_bytes;
+  dlls_[i]->num_thunks = 0;
+  dlls_[i]->base = base_address;
+  dlls_[i]->used_bytes = offsetof(DllInterceptionData, thunks);
+
+  VERIFY(PatchDll(dll_info, dlls_[i]));
+
+  ULONG old_protect;
+  SIZE_T real_size = buffer_bytes;
+  void* to_protect = dlls_[i];
+  VERIFY_SUCCESS(g_nt.ProtectVirtualMemory(NtCurrentProcess, &to_protect,
+                                           &real_size, PAGE_EXECUTE_READ,
+                                           &old_protect));
+  return true;
+}
+
+void InterceptionAgent::OnDllUnload(void* base_address) {
+  for (int i = 0; i < interceptions_->num_intercepted_dlls; i++) {
+    if (dlls_[i] && dlls_[i]->base == base_address) {
+      operator delete(dlls_[i], NT_PAGE);
+      dlls_[i] = NULL;
+      break;
+    }
+  }
+}
+
+// TODO(rvargas): We have to deal with prebinded dlls. I see two options: change
+// the timestamp of the patched dll, or modify the info on the prebinded dll.
+// the first approach messes matching of debug symbols, the second one is more
+// complicated.
+bool InterceptionAgent::PatchDll(const DllPatchInfo* dll_info,
+                                 DllInterceptionData* thunks) {
+  DCHECK_NT(NULL != thunks);
+  DCHECK_NT(NULL != dll_info);
+
+  const FunctionInfo* function = reinterpret_cast<const FunctionInfo*>(
+      reinterpret_cast<const char*>(dll_info) + dll_info->offset_to_functions);
+
+  for (int i = 0; i < dll_info->num_functions; i++) {
+    if (!IsWithinRange(dll_info, dll_info->record_bytes, function->function)) {
+      NOTREACHED_NT();
+      return false;
+    }
+
+    ResolverThunk* resolver = GetResolver(function->type);
+    if (!resolver)
+      return false;
+
+    const char* interceptor = function->function +
+                              g_nt.strlen(function->function) + 1;
+
+    if (!IsWithinRange(function, function->record_bytes, interceptor) ||
+        !IsWithinRange(dll_info, dll_info->record_bytes, interceptor)) {
+      NOTREACHED_NT();
+      return false;
+    }
+
+    NTSTATUS ret = resolver->Setup(thunks->base,
+                                   interceptions_->interceptor_base,
+                                   function->function,
+                                   interceptor,
+                                   function->interceptor_address,
+                                   &thunks->thunks[i],
+                                   sizeof(ThunkData),
+                                   NULL);
+    if (!NT_SUCCESS(ret)) {
+      NOTREACHED_NT();
+      return false;
+    }
+
+    DCHECK_NT(!g_originals[function->id]);
+    g_originals[function->id] = &thunks->thunks[i];
+
+    thunks->num_thunks++;
+    thunks->used_bytes += sizeof(ThunkData);
+
+    function = reinterpret_cast<const FunctionInfo*>(
+        reinterpret_cast<const char*>(function) + function->record_bytes);
+  }
+
+  return true;
+}
+
+// This method is called from within the loader lock
+ResolverThunk* InterceptionAgent::GetResolver(InterceptionType type) {
+  static EatResolverThunk* eat_resolver = NULL;
+  static SidestepResolverThunk* sidestep_resolver = NULL;
+  static SmartSidestepResolverThunk* smart_sidestep_resolver = NULL;
+
+  if (!eat_resolver)
+    eat_resolver = new(NT_ALLOC) EatResolverThunk;
+
+#if !defined(_WIN64)
+  // Sidestep is not supported for x64.
+  if (!sidestep_resolver)
+    sidestep_resolver = new(NT_ALLOC) SidestepResolverThunk;
+
+  if (!smart_sidestep_resolver)
+    smart_sidestep_resolver = new(NT_ALLOC) SmartSidestepResolverThunk;
+#endif
+
+  switch (type) {
+    case INTERCEPTION_EAT:
+      return eat_resolver;
+    case INTERCEPTION_SIDESTEP:
+      return sidestep_resolver;
+    case INTERCEPTION_SMART_SIDESTEP:
+      return smart_sidestep_resolver;
+    default:
+      NOTREACHED_NT();
+  }
+
+  return NULL;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/interception_agent.h b/sandbox/win/src/interception_agent.h
new file mode 100644
index 0000000..2762c61
--- /dev/null
+++ b/sandbox/win/src/interception_agent.h
@@ -0,0 +1,87 @@
+// 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.
+
+// Defines InterceptionAgent, the class in charge of setting up interceptions
+// from the inside of the sandboxed process. For more details see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_AGENT_H__
+#define SANDBOX_SRC_INTERCEPTION_AGENT_H__
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+// Internal structures used for communication between the broker and the target.
+struct DllInterceptionData;
+struct SharedMemory;
+struct DllPatchInfo;
+
+class ResolverThunk;
+
+// The InterceptionAgent executes on the target application, and it is in charge
+// of setting up the desired interceptions or indicating what module needs to
+// be unloaded.
+//
+// The exposed API consists of three methods: GetInterceptionAgent to retrieve
+// the single class instance, OnDllLoad and OnDllUnload to process a dll being
+// loaded and unloaded respectively.
+//
+// This class assumes that it will get called for every dll being loaded,
+// starting with kernel32, so the singleton will be instantiated from within the
+// loader lock.
+class InterceptionAgent {
+ public:
+  // Returns the single InterceptionAgent object for this process.
+  static InterceptionAgent* GetInterceptionAgent();
+
+  // This method should be invoked whenever a new dll is loaded to perform the
+  // required patches. If the return value is false, this dll should not be
+  // allowed to load.
+  //
+  // full_path is the (optional) full name of the module being loaded and name
+  // is the internal module name. If full_path is provided, it will be used
+  // before the internal name to determine if we care about this dll.
+  bool OnDllLoad(const UNICODE_STRING* full_path, const UNICODE_STRING* name,
+                 void* base_address);
+
+  // Performs cleanup when a dll is unloaded.
+  void OnDllUnload(void* base_address);
+
+ private:
+  ~InterceptionAgent() {}
+
+  // Performs initialization of the singleton.
+  bool Init(SharedMemory* shared_memory);
+
+  // Returns true if we are interested on this dll. dll_info is an entry of the
+  // list of intercepted dlls.
+  bool DllMatch(const UNICODE_STRING* full_path, const UNICODE_STRING* name,
+                const DllPatchInfo* dll_info);
+
+  // Performs the patching of the dll loaded at base_address.
+  // The patches to perform are described on dll_info, and thunks is the thunk
+  // storage for the whole dll.
+  // Returns true on success.
+  bool PatchDll(const DllPatchInfo* dll_info, DllInterceptionData* thunks);
+
+  // Returns a resolver for a given interception type.
+  ResolverThunk* GetResolver(InterceptionType type);
+
+  // Shared memory containing the list of functions to intercept.
+  SharedMemory* interceptions_;
+
+  // Array of thunk data buffers for the intercepted dlls. This object singleton
+  // is allocated with a placement new with enough space to hold the complete
+  // array of pointers, not just the first element.
+  DllInterceptionData* dlls_[1];
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptionAgent);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTION_AGENT_H__
diff --git a/sandbox/win/src/interception_internal.h b/sandbox/win/src/interception_internal.h
new file mode 100644
index 0000000..810478a
--- /dev/null
+++ b/sandbox/win/src/interception_internal.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines InterceptionManager, the class in charge of setting up interceptions
+// for the sandboxed process. For more details see:
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+#define SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+const int kMaxThunkDataBytes = 64;
+
+enum InterceptorId;
+
+// The following structures contain variable size fields at the end, and will be
+// used to transfer information between two processes. In order to guarantee
+// our ability to follow the chain of structures, the alignment should be fixed,
+// hence this pragma.
+#pragma pack(push, 4)
+
+// Structures for the shared memory that contains patching information
+// for the InterceptionAgent.
+// A single interception:
+struct FunctionInfo {
+  size_t record_bytes;            // rounded to sizeof(size_t) bytes
+  InterceptionType type;
+  InterceptorId id;
+  const void* interceptor_address;
+  char function[1];               // placeholder for null terminated name
+  // char interceptor[]           // followed by the interceptor function
+};
+
+// A single dll:
+struct DllPatchInfo {
+  size_t record_bytes;            // rounded to sizeof(size_t) bytes
+  size_t offset_to_functions;
+  int num_functions;
+  bool unload_module;
+  wchar_t dll_name[1];            // placeholder for null terminated name
+  // FunctionInfo function_info[] // followed by the functions to intercept
+};
+
+// All interceptions:
+struct SharedMemory {
+  int num_intercepted_dlls;
+  void* interceptor_base;
+  DllPatchInfo dll_list[1];       // placeholder for the list of dlls
+};
+
+// Dummy single thunk:
+struct ThunkData {
+  char data[kMaxThunkDataBytes];
+};
+
+// In-memory representation of the interceptions for a given dll:
+struct DllInterceptionData {
+  size_t data_bytes;
+  size_t used_bytes;
+  void* base;
+  int num_thunks;
+#if defined(_WIN64)
+  int dummy;                      // Improve alignment.
+#endif
+  ThunkData thunks[1];
+};
+
+#pragma pack(pop)
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
diff --git a/sandbox/win/src/interception_unittest.cc b/sandbox/win/src/interception_unittest.cc
new file mode 100644
index 0000000..0fc9b7c
--- /dev/null
+++ b/sandbox/win/src/interception_unittest.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for InterceptionManager.
+// The tests require private information so the whole interception.cc file is
+// included from this file.
+
+#include <windows.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/target_process.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Walks the settings buffer, verifying that the values make sense and counting
+// objects.
+// Arguments:
+// buffer (in): the buffer to walk.
+// size (in): buffer size
+// num_dlls (out): count of the dlls on the buffer.
+// num_function (out): count of intercepted functions.
+// num_names (out): count of named interceptor functions.
+void WalkBuffer(void* buffer, size_t size, int* num_dlls, int* num_functions,
+                int* num_names) {
+  ASSERT_TRUE(NULL != buffer);
+  ASSERT_TRUE(NULL != num_functions);
+  ASSERT_TRUE(NULL != num_names);
+  *num_dlls = *num_functions = *num_names = 0;
+  SharedMemory *memory = reinterpret_cast<SharedMemory*>(buffer);
+
+  ASSERT_GT(size, sizeof(SharedMemory));
+  DllPatchInfo *dll = &memory->dll_list[0];
+
+  for (int i = 0; i < memory->num_intercepted_dlls; i++) {
+    ASSERT_NE(0u, wcslen(dll->dll_name));
+    ASSERT_EQ(0u, dll->record_bytes % sizeof(size_t));
+    ASSERT_EQ(0u, dll->offset_to_functions % sizeof(size_t));
+    ASSERT_NE(0, dll->num_functions);
+
+    FunctionInfo *function = reinterpret_cast<FunctionInfo*>(
+      reinterpret_cast<char*>(dll) + dll->offset_to_functions);
+
+    for (int j = 0; j < dll->num_functions; j++) {
+      ASSERT_EQ(0u, function->record_bytes % sizeof(size_t));
+
+      char* name = function->function;
+      size_t length = strlen(name);
+      ASSERT_NE(0u, length);
+      name += length + 1;
+
+      // look for overflows
+      ASSERT_GT(reinterpret_cast<char*>(buffer) + size, name + strlen(name));
+
+      // look for a named interceptor
+      if (strlen(name)) {
+        (*num_names)++;
+        EXPECT_TRUE(NULL == function->interceptor_address);
+      } else {
+        EXPECT_TRUE(NULL != function->interceptor_address);
+      }
+
+      (*num_functions)++;
+      function = reinterpret_cast<FunctionInfo*>(
+        reinterpret_cast<char*>(function) + function->record_bytes);
+    }
+
+    (*num_dlls)++;
+    dll = reinterpret_cast<DllPatchInfo*>(reinterpret_cast<char*>(dll) +
+                                          dll->record_bytes);
+  }
+}
+
+TEST(InterceptionManagerTest, BufferLayout1) {
+  wchar_t exe_name[MAX_PATH];
+  ASSERT_NE(0u, GetModuleFileName(NULL, exe_name, MAX_PATH - 1));
+
+  TargetProcess *target = MakeTestTargetProcess(::GetCurrentProcess(),
+                                                ::GetModuleHandle(exe_name));
+
+  InterceptionManager interceptions(target, true);
+
+  // Any pointer will do for a function pointer.
+  void* function = &interceptions;
+
+  // We don't care about the interceptor id.
+  interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtCreateFile",
+                                      INTERCEPTION_SERVICE_CALL, function,
+                                      OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"kernel32.dll", "CreateFileEx",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"kernel32.dll", "SomeFileEx",
+                                      INTERCEPTION_SMART_SIDESTEP, function,
+                                      OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"user32.dll", "FindWindow",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"kernel32.dll", "CreateMutex",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"user32.dll", "PostMsg",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"user32.dll", "PostMsg",
+                                      INTERCEPTION_EAT, "replacement",
+                                      OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtClose",
+                                      INTERCEPTION_SERVICE_CALL, function,
+                                      OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtOpenFile",
+                                      INTERCEPTION_SIDESTEP, function,
+                                      OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"some.dll", "Superfn",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+                                      INTERCEPTION_EAT, "a", OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+                                      INTERCEPTION_SIDESTEP, "ab", OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+                                      INTERCEPTION_EAT, "abc", OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"a.dll", "p",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"b.dll",
+                                      "TheIncredibleCallToSaveTheWorld",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"a.dll", "BIsLame",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+  interceptions.AddToPatchedFunctions(L"a.dll", "ARules",
+                                      INTERCEPTION_EAT, function, OPEN_KEY_ID);
+
+  // Verify that all interceptions were added
+  ASSERT_EQ(18, interceptions.interceptions_.size());
+
+  size_t buffer_size = interceptions.GetBufferSize();
+  scoped_ptr<BYTE[]> local_buffer(new BYTE[buffer_size]);
+
+  ASSERT_TRUE(interceptions.SetupConfigBuffer(local_buffer.get(),
+                                              buffer_size));
+
+  // At this point, the interceptions should have been separated into two
+  // groups: one group with the local ("cold") interceptions, consisting of
+  // everything from ntdll and stuff set as INTRECEPTION_SERVICE_CALL, and
+  // another group with the interceptions belonging to dlls that will be "hot"
+  // patched on the client. The second group lives on local_buffer, and the
+  // first group remains on the list of interceptions (inside the object
+  // "interceptions"). There are 3 local interceptions (of ntdll); the
+  // other 15 have to be sent to the child to be performed "hot".
+  EXPECT_EQ(3, interceptions.interceptions_.size());
+
+  int num_dlls, num_functions, num_names;
+  WalkBuffer(local_buffer.get(), buffer_size, &num_dlls, &num_functions,
+             &num_names);
+
+  // The 15 interceptions on the buffer (to the child) should be grouped on 6
+  // dlls. Only four interceptions are using an explicit name for the
+  // interceptor function.
+  EXPECT_EQ(6, num_dlls);
+  EXPECT_EQ(15, num_functions);
+  EXPECT_EQ(4, num_names);
+}
+
+TEST(InterceptionManagerTest, BufferLayout2) {
+  wchar_t exe_name[MAX_PATH];
+  ASSERT_NE(0u, GetModuleFileName(NULL, exe_name, MAX_PATH - 1));
+
+  TargetProcess *target = MakeTestTargetProcess(::GetCurrentProcess(),
+                                                ::GetModuleHandle(exe_name));
+
+  InterceptionManager interceptions(target, true);
+
+  // Any pointer will do for a function pointer.
+  void* function = &interceptions;
+  interceptions.AddToUnloadModules(L"some01.dll");
+  // We don't care about the interceptor id.
+  interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtCreateFile",
+                                      INTERCEPTION_SERVICE_CALL, function,
+                                      OPEN_FILE_ID);
+  interceptions.AddToPatchedFunctions(L"kernel32.dll", "CreateFileEx",
+                                      INTERCEPTION_EAT, function, OPEN_FILE_ID);
+  interceptions.AddToUnloadModules(L"some02.dll");
+  interceptions.AddToPatchedFunctions(L"kernel32.dll", "SomeFileEx",
+                                      INTERCEPTION_SMART_SIDESTEP, function,
+                                      OPEN_FILE_ID);
+  // Verify that all interceptions were added
+  ASSERT_EQ(5, interceptions.interceptions_.size());
+
+  size_t buffer_size = interceptions.GetBufferSize();
+  scoped_ptr<BYTE[]> local_buffer(new BYTE[buffer_size]);
+
+  ASSERT_TRUE(interceptions.SetupConfigBuffer(local_buffer.get(),
+                                              buffer_size));
+
+  // At this point, the interceptions should have been separated into two
+  // groups: one group with the local ("cold") interceptions, and another
+  // group with the interceptions belonging to dlls that will be "hot"
+  // patched on the client. The second group lives on local_buffer, and the
+  // first group remains on the list of interceptions, in this case just one.
+  EXPECT_EQ(1, interceptions.interceptions_.size());
+
+  int num_dlls, num_functions, num_names;
+  WalkBuffer(local_buffer.get(), buffer_size, &num_dlls, &num_functions,
+             &num_names);
+
+  EXPECT_EQ(3, num_dlls);
+  EXPECT_EQ(4, num_functions);
+  EXPECT_EQ(0, num_names);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/interceptors.h b/sandbox/win/src/interceptors.h
new file mode 100644
index 0000000..a17447a
--- /dev/null
+++ b/sandbox/win/src/interceptors.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_INTERCEPTORS_H_
+#define SANDBOX_SRC_INTERCEPTORS_H_
+
+#if defined(_WIN64)
+#include "sandbox/win/src/interceptors_64.h"
+#endif
+
+namespace sandbox {
+
+enum InterceptorId {
+  // Internal use:
+  MAP_VIEW_OF_SECTION_ID = 0,
+  UNMAP_VIEW_OF_SECTION_ID,
+  // Policy broker:
+  SET_INFORMATION_THREAD_ID,
+  OPEN_THREAD_TOKEN_ID,
+  OPEN_THREAD_TOKEN_EX_ID,
+  OPEN_TREAD_ID,
+  OPEN_PROCESS_ID,
+  OPEN_PROCESS_TOKEN_ID,
+  OPEN_PROCESS_TOKEN_EX_ID,
+  // Filesystem dispatcher:
+  CREATE_FILE_ID,
+  OPEN_FILE_ID,
+  QUERY_ATTRIB_FILE_ID,
+  QUERY_FULL_ATTRIB_FILE_ID,
+  SET_INFO_FILE_ID,
+  // Named pipe dispatcher:
+  CREATE_NAMED_PIPE_ID,
+  // Process-thread dispatcher:
+  CREATE_PROCESSW_ID,
+  CREATE_PROCESSA_ID,
+  // Registry dispatcher:
+  CREATE_KEY_ID,
+  OPEN_KEY_ID,
+  OPEN_KEY_EX_ID,
+  // Sync dispatcher:
+  CREATE_EVENT_ID,
+  OPEN_EVENT_ID,
+  // Process mitigations Win32k dispatcher:
+  GDIINITIALIZE_ID,
+  GETSTOCKOBJECT_ID,
+  REGISTERCLASSW_ID,
+  INTERCEPTOR_MAX_ID
+};
+
+typedef void* OriginalFunctions[INTERCEPTOR_MAX_ID];
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTORS_H_
diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
new file mode 100644
index 0000000..ef0b5f0
--- /dev/null
+++ b/sandbox/win/src/interceptors_64.cc
@@ -0,0 +1,278 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/interceptors_64.h"
+
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/filesystem_interception.h"
+#include "sandbox/win/src/named_pipe_interception.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/registry_interception.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/target_interceptions.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+SANDBOX_INTERCEPT OriginalFunctions g_originals;
+
+NTSTATUS WINAPI TargetNtMapViewOfSection64(
+    HANDLE section, HANDLE process, PVOID *base, ULONG_PTR zero_bits,
+    SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size,
+    SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect) {
+  NtMapViewOfSectionFunction orig_fn = reinterpret_cast<
+      NtMapViewOfSectionFunction>(g_originals[MAP_VIEW_OF_SECTION_ID]);
+
+  return TargetNtMapViewOfSection(orig_fn, section, process, base, zero_bits,
+                                  commit_size, offset, view_size, inherit,
+                                  allocation_type, protect);
+}
+
+NTSTATUS WINAPI TargetNtUnmapViewOfSection64(HANDLE process, PVOID base) {
+  NtUnmapViewOfSectionFunction orig_fn = reinterpret_cast<
+      NtUnmapViewOfSectionFunction>(g_originals[UNMAP_VIEW_OF_SECTION_ID]);
+  return TargetNtUnmapViewOfSection(orig_fn, process, base);
+}
+
+// -----------------------------------------------------------------------
+
+NTSTATUS WINAPI TargetNtSetInformationThread64(
+    HANDLE thread, NT_THREAD_INFORMATION_CLASS thread_info_class,
+    PVOID thread_information, ULONG thread_information_bytes) {
+  NtSetInformationThreadFunction orig_fn = reinterpret_cast<
+      NtSetInformationThreadFunction>(g_originals[SET_INFORMATION_THREAD_ID]);
+  return TargetNtSetInformationThread(orig_fn, thread, thread_info_class,
+                                      thread_information,
+                                      thread_information_bytes);
+}
+
+NTSTATUS WINAPI TargetNtOpenThreadToken64(
+    HANDLE thread, ACCESS_MASK desired_access, BOOLEAN open_as_self,
+    PHANDLE token) {
+  NtOpenThreadTokenFunction orig_fn = reinterpret_cast<
+      NtOpenThreadTokenFunction>(g_originals[OPEN_THREAD_TOKEN_ID]);
+  return TargetNtOpenThreadToken(orig_fn, thread, desired_access, open_as_self,
+                                 token);
+}
+
+NTSTATUS WINAPI TargetNtOpenThreadTokenEx64(
+    HANDLE thread, ACCESS_MASK desired_access, BOOLEAN open_as_self,
+    ULONG handle_attributes, PHANDLE token) {
+  NtOpenThreadTokenExFunction orig_fn = reinterpret_cast<
+      NtOpenThreadTokenExFunction>(g_originals[OPEN_THREAD_TOKEN_EX_ID]);
+  return TargetNtOpenThreadTokenEx(orig_fn, thread, desired_access,
+                                   open_as_self, handle_attributes, token);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateFile64(
+    PHANDLE file, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PIO_STATUS_BLOCK io_status,
+    PLARGE_INTEGER allocation_size, ULONG file_attributes, ULONG sharing,
+    ULONG disposition, ULONG options, PVOID ea_buffer, ULONG ea_length) {
+  NtCreateFileFunction orig_fn = reinterpret_cast<
+      NtCreateFileFunction>(g_originals[CREATE_FILE_ID]);
+  return TargetNtCreateFile(orig_fn, file, desired_access, object_attributes,
+                            io_status, allocation_size, file_attributes,
+                            sharing, disposition, options, ea_buffer,
+                            ea_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenFile64(
+    PHANDLE file, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PIO_STATUS_BLOCK io_status,
+    ULONG sharing, ULONG options) {
+  NtOpenFileFunction orig_fn = reinterpret_cast<
+      NtOpenFileFunction>(g_originals[OPEN_FILE_ID]);
+  return TargetNtOpenFile(orig_fn, file, desired_access, object_attributes,
+                          io_status, sharing, options);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryAttributesFile64(
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_BASIC_INFORMATION file_attributes) {
+  NtQueryAttributesFileFunction orig_fn = reinterpret_cast<
+      NtQueryAttributesFileFunction>(g_originals[QUERY_ATTRIB_FILE_ID]);
+  return TargetNtQueryAttributesFile(orig_fn, object_attributes,
+                                     file_attributes);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryFullAttributesFile64(
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_NETWORK_OPEN_INFORMATION file_attributes) {
+  NtQueryFullAttributesFileFunction orig_fn = reinterpret_cast<
+      NtQueryFullAttributesFileFunction>(
+          g_originals[QUERY_FULL_ATTRIB_FILE_ID]);
+  return TargetNtQueryFullAttributesFile(orig_fn, object_attributes,
+                                         file_attributes);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtSetInformationFile64(
+    HANDLE file, PIO_STATUS_BLOCK io_status, PVOID file_information,
+    ULONG length, FILE_INFORMATION_CLASS file_information_class) {
+  NtSetInformationFileFunction orig_fn = reinterpret_cast<
+      NtSetInformationFileFunction>(g_originals[SET_INFO_FILE_ID]);
+  return TargetNtSetInformationFile(orig_fn, file, io_status, file_information,
+                                    length, file_information_class);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateNamedPipeW64(
+    LPCWSTR pipe_name, DWORD open_mode, DWORD pipe_mode, DWORD max_instance,
+    DWORD out_buffer_size, DWORD in_buffer_size, DWORD default_timeout,
+    LPSECURITY_ATTRIBUTES security_attributes) {
+  CreateNamedPipeWFunction orig_fn = reinterpret_cast<
+      CreateNamedPipeWFunction>(g_originals[CREATE_NAMED_PIPE_ID]);
+  return TargetCreateNamedPipeW(orig_fn, pipe_name, open_mode, pipe_mode,
+                                max_instance, out_buffer_size, in_buffer_size,
+                                default_timeout, security_attributes);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThread64(
+    PHANDLE thread, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PCLIENT_ID client_id) {
+  NtOpenThreadFunction orig_fn = reinterpret_cast<
+      NtOpenThreadFunction>(g_originals[OPEN_TREAD_ID]);
+  return TargetNtOpenThread(orig_fn, thread, desired_access, object_attributes,
+                            client_id);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcess64(
+    PHANDLE process, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PCLIENT_ID client_id) {
+  NtOpenProcessFunction orig_fn = reinterpret_cast<
+      NtOpenProcessFunction>(g_originals[OPEN_PROCESS_ID]);
+  return TargetNtOpenProcess(orig_fn, process, desired_access,
+                             object_attributes, client_id);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcessToken64(
+    HANDLE process, ACCESS_MASK desired_access, PHANDLE token) {
+  NtOpenProcessTokenFunction orig_fn = reinterpret_cast<
+      NtOpenProcessTokenFunction>(g_originals[OPEN_PROCESS_TOKEN_ID]);
+  return TargetNtOpenProcessToken(orig_fn, process, desired_access, token);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcessTokenEx64(
+    HANDLE process, ACCESS_MASK desired_access, ULONG handle_attributes,
+    PHANDLE token) {
+  NtOpenProcessTokenExFunction orig_fn = reinterpret_cast<
+      NtOpenProcessTokenExFunction>(g_originals[OPEN_PROCESS_TOKEN_EX_ID]);
+  return TargetNtOpenProcessTokenEx(orig_fn, process, desired_access,
+                                    handle_attributes, token);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessW64(
+    LPCWSTR application_name, LPWSTR command_line,
+    LPSECURITY_ATTRIBUTES process_attributes,
+    LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD flags,
+    LPVOID environment, LPCWSTR current_directory, LPSTARTUPINFOW startup_info,
+    LPPROCESS_INFORMATION process_information) {
+  CreateProcessWFunction orig_fn = reinterpret_cast<
+      CreateProcessWFunction>(g_originals[CREATE_PROCESSW_ID]);
+  return TargetCreateProcessW(orig_fn, application_name, command_line,
+                              process_attributes, thread_attributes,
+                              inherit_handles, flags, environment,
+                              current_directory, startup_info,
+                              process_information);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessA64(
+    LPCSTR application_name, LPSTR command_line,
+    LPSECURITY_ATTRIBUTES process_attributes,
+    LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD flags,
+    LPVOID environment, LPCSTR current_directory, LPSTARTUPINFOA startup_info,
+    LPPROCESS_INFORMATION process_information) {
+  CreateProcessAFunction orig_fn = reinterpret_cast<
+      CreateProcessAFunction>(g_originals[CREATE_PROCESSA_ID]);
+  return TargetCreateProcessA(orig_fn, application_name, command_line,
+                              process_attributes, thread_attributes,
+                              inherit_handles, flags, environment,
+                              current_directory, startup_info,
+                              process_information);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey64(
+    PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, ULONG title_index,
+    PUNICODE_STRING class_name, ULONG create_options, PULONG disposition) {
+  NtCreateKeyFunction orig_fn = reinterpret_cast<
+      NtCreateKeyFunction>(g_originals[CREATE_KEY_ID]);
+  return TargetNtCreateKey(orig_fn, key, desired_access, object_attributes,
+                           title_index, class_name, create_options,
+                           disposition);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKey64(
+    PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes) {
+  NtOpenKeyFunction orig_fn = reinterpret_cast<
+      NtOpenKeyFunction>(g_originals[OPEN_KEY_ID]);
+  return TargetNtOpenKey(orig_fn, key, desired_access, object_attributes);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKeyEx64(
+    PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, ULONG open_options) {
+  NtOpenKeyExFunction orig_fn = reinterpret_cast<
+      NtOpenKeyExFunction>(g_originals[OPEN_KEY_EX_ID]);
+  return TargetNtOpenKeyEx(orig_fn, key, desired_access, object_attributes,
+                           open_options);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE event_type,
+    BOOLEAN initial_state) {
+  NtCreateEventFunction orig_fn = reinterpret_cast<
+      NtCreateEventFunction>(g_originals[CREATE_EVENT_ID]);
+  return TargetNtCreateEvent(orig_fn, event_handle, desired_access,
+                             object_attributes, event_type, initial_state);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes) {
+  NtOpenEventFunction orig_fn = reinterpret_cast<
+      NtOpenEventFunction>(g_originals[OPEN_EVENT_ID]);
+  return TargetNtOpenEvent(orig_fn, event_handle, desired_access,
+                           object_attributes);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(
+    HANDLE dll,
+    DWORD reason) {
+  GdiDllInitializeFunction orig_fn = reinterpret_cast<
+      GdiDllInitializeFunction>(g_originals[GDIINITIALIZE_ID]);
+  return TargetGdiDllInitialize(orig_fn, dll, reason);
+}
+
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object) {
+  GetStockObjectFunction orig_fn = reinterpret_cast<
+      GetStockObjectFunction>(g_originals[GETSTOCKOBJECT_ID]);
+  return TargetGetStockObject(orig_fn, object);
+}
+
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW64(
+    const WNDCLASS* wnd_class) {
+  RegisterClassWFunction orig_fn = reinterpret_cast<
+      RegisterClassWFunction>(g_originals[REGISTERCLASSW_ID]);
+  return TargetRegisterClassW(orig_fn, wnd_class);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
new file mode 100644
index 0000000..7368ceb
--- /dev/null
+++ b/sandbox/win/src/interceptors_64.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_INTERCEPTORS_64_H_
+#define SANDBOX_SRC_INTERCEPTORS_64_H_
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtMapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtMapViewOfSection64(
+    HANDLE section, HANDLE process, PVOID *base, ULONG_PTR zero_bits,
+    SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size,
+    SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect);
+
+// Interception of NtUnmapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being unloaded, so we can clean up our interceptions.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtUnmapViewOfSection64(HANDLE process,
+                                                               PVOID base);
+
+// -----------------------------------------------------------------------
+// Interceptors without IPC.
+
+// Interception of NtSetInformationThread on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtSetInformationThread64(
+    HANDLE thread, NT_THREAD_INFORMATION_CLASS thread_info_class,
+    PVOID thread_information, ULONG thread_information_bytes);
+
+// Interception of NtOpenThreadToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThreadToken64(
+    HANDLE thread, ACCESS_MASK desired_access, BOOLEAN open_as_self,
+    PHANDLE token);
+
+// Interception of NtOpenThreadTokenEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThreadTokenEx64(
+    HANDLE thread, ACCESS_MASK desired_access, BOOLEAN open_as_self,
+    ULONG handle_attributes, PHANDLE token);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the file system dispatcher.
+
+// Interception of NtCreateFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateFile64(
+    PHANDLE file, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PIO_STATUS_BLOCK io_status,
+    PLARGE_INTEGER allocation_size, ULONG file_attributes, ULONG sharing,
+    ULONG disposition, ULONG options, PVOID ea_buffer, ULONG ea_length);
+
+// Interception of NtOpenFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenFile64(
+    PHANDLE file, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PIO_STATUS_BLOCK io_status,
+    ULONG sharing, ULONG options);
+
+// Interception of NtQueryAtttributesFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryAttributesFile64(
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_BASIC_INFORMATION file_attributes);
+
+// Interception of NtQueryFullAtttributesFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryFullAttributesFile64(
+    POBJECT_ATTRIBUTES object_attributes,
+    PFILE_NETWORK_OPEN_INFORMATION file_attributes);
+
+// Interception of NtSetInformationFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtSetInformationFile64(
+    HANDLE file, PIO_STATUS_BLOCK io_status, PVOID file_information,
+    ULONG length, FILE_INFORMATION_CLASS file_information_class);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the named pipe dispatcher.
+
+// Interception of CreateNamedPipeW in kernel32.dll
+SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateNamedPipeW64(
+    LPCWSTR pipe_name, DWORD open_mode, DWORD pipe_mode, DWORD max_instance,
+    DWORD out_buffer_size, DWORD in_buffer_size, DWORD default_timeout,
+    LPSECURITY_ATTRIBUTES security_attributes);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the process-thread dispatcher.
+
+// Interception of NtOpenThread on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThread64(
+    PHANDLE thread, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PCLIENT_ID client_id);
+
+// Interception of NtOpenProcess on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcess64(
+    PHANDLE process, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, PCLIENT_ID client_id);
+
+// Interception of NtOpenProcessToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcessToken64(
+    HANDLE process, ACCESS_MASK desired_access, PHANDLE token);
+
+// Interception of NtOpenProcessTokenEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcessTokenEx64(
+    HANDLE process, ACCESS_MASK desired_access, ULONG handle_attributes,
+    PHANDLE token);
+
+// Interception of CreateProcessW in kernel32.dll.
+SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessW64(
+    LPCWSTR application_name, LPWSTR command_line,
+    LPSECURITY_ATTRIBUTES process_attributes,
+    LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD flags,
+    LPVOID environment, LPCWSTR current_directory, LPSTARTUPINFOW startup_info,
+    LPPROCESS_INFORMATION process_information);
+
+// Interception of CreateProcessA in kernel32.dll.
+SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessA64(
+    LPCSTR application_name, LPSTR command_line,
+    LPSECURITY_ATTRIBUTES process_attributes,
+    LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD flags,
+    LPVOID environment, LPCSTR current_directory, LPSTARTUPINFOA startup_info,
+    LPPROCESS_INFORMATION process_information);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the registry dispatcher.
+
+// Interception of NtCreateKey on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey64(
+    PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, ULONG title_index,
+    PUNICODE_STRING class_name, ULONG create_options, PULONG disposition);
+
+// Interception of NtOpenKey on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKey64(
+    PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes);
+
+// Interception of NtOpenKeyEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKeyEx64(
+    PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, ULONG open_options);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the sync dispatcher.
+
+// Interception of NtCreateEvent/NtOpenEvent on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE event_type,
+    BOOLEAN initial_state);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent64(
+    PHANDLE event_handle, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the process mitigations win32k lockdown code.
+
+// Interceptor for the GdiDllInitialize function.
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(
+    HANDLE dll,
+    DWORD reason);
+
+// Interceptor for the GetStockObject function.
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object);
+
+// Interceptor for the RegisterClassW function.
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW64(const WNDCLASS* wnd_class);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTORS_64_H_
diff --git a/sandbox/win/src/internal_types.h b/sandbox/win/src/internal_types.h
new file mode 100644
index 0000000..026bedb
--- /dev/null
+++ b/sandbox/win/src/internal_types.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+#define SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+
+namespace sandbox {
+
+const wchar_t kNtdllName[] = L"ntdll.dll";
+const wchar_t kKerneldllName[] = L"kernel32.dll";
+const wchar_t kKernelBasedllName[] = L"kernelbase.dll";
+
+// Defines the supported C++ types encoding to numeric id. Like a poor's man
+// RTTI. Note that true C++ RTTI will not work because the types are not
+// polymorphic anyway.
+enum ArgType {
+  INVALID_TYPE = 0,
+  WCHAR_TYPE,
+  UINT32_TYPE,
+  UNISTR_TYPE,
+  VOIDPTR_TYPE,
+  INPTR_TYPE,
+  INOUTPTR_TYPE,
+  LAST_TYPE
+};
+
+// Encapsulates a pointer to a buffer and the size of the buffer.
+class CountedBuffer {
+ public:
+  CountedBuffer(void* buffer, uint32 size) : size_(size), buffer_(buffer) {}
+
+  uint32 Size() const {
+    return size_;
+  }
+
+  void* Buffer() const {
+    return buffer_;
+  }
+
+ private:
+  uint32 size_;
+  void* buffer_;
+};
+
+// Helper class to convert void-pointer packed ints for both
+// 32 and 64 bit builds. This construct is non-portable.
+class IPCInt {
+ public:
+  explicit IPCInt(void* buffer) {
+    buffer_.vp = buffer;
+  }
+
+  explicit IPCInt(unsigned __int32 i32) {
+    buffer_.vp = NULL;
+    buffer_.i32 = i32;
+  }
+
+  unsigned __int32 As32Bit() const {
+    return buffer_.i32;
+  }
+
+  void* AsVoidPtr() const {
+    return buffer_.vp;
+  }
+
+ private:
+  union U {
+    void* vp;
+    unsigned __int32 i32;
+  } buffer_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
diff --git a/sandbox/win/src/ipc_ping_test.cc b/sandbox/win/src/ipc_ping_test.cc
new file mode 100644
index 0000000..64e3de6
--- /dev/null
+++ b/sandbox/win/src/ipc_ping_test.cc
@@ -0,0 +1,58 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+
+namespace sandbox {
+
+// Tests that the IPC is working by issuing a special IPC that is not exposed
+// in the public API.
+SBOX_TESTS_COMMAND int IPC_Ping(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED;
+
+  TargetServices* ts = SandboxFactory::GetTargetServices();
+  if (NULL == ts)
+    return SBOX_TEST_FAILED;
+
+  // Downcast because we have internal knowledge of the object returned.
+  TargetServicesBase* ts_base = reinterpret_cast<TargetServicesBase*>(ts);
+
+  int version = 0;
+  if (L'1' == argv[0][0])
+    version = 1;
+  else
+    version = 2;
+
+  if (!ts_base->TestIPCPing(version))
+    return SBOX_TEST_FAILED;
+
+  ::Sleep(1);
+  if (!ts_base->TestIPCPing(version))
+    return SBOX_TEST_FAILED;
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// The IPC ping test should work before and after the token drop.
+TEST(IPCTest, IPCPingTestSimple) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(EVERY_STATE);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IPC_Ping 1"));
+}
+
+TEST(IPCTest, IPCPingTestWithOutput) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(EVERY_STATE);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IPC_Ping 2"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IPC_Ping 2"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h
new file mode 100644
index 0000000..d680411
--- /dev/null
+++ b/sandbox/win/src/ipc_tags.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_IPC_TAGS_H__
+#define SANDBOX_SRC_IPC_TAGS_H__
+
+namespace sandbox {
+
+enum {
+  IPC_UNUSED_TAG = 0,
+  IPC_PING1_TAG,  // Takes a cookie in parameters and returns the cookie
+                  // multiplied by 2 and the tick_count. Used for testing only.
+  IPC_PING2_TAG,  // Takes an in/out cookie in parameters and modify the cookie
+                  // to be multiplied by 3. Used for testing only.
+  IPC_NTCREATEFILE_TAG,
+  IPC_NTOPENFILE_TAG,
+  IPC_NTQUERYATTRIBUTESFILE_TAG,
+  IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
+  IPC_NTSETINFO_RENAME_TAG,
+  IPC_CREATENAMEDPIPEW_TAG,
+  IPC_NTOPENTHREAD_TAG,
+  IPC_NTOPENPROCESS_TAG,
+  IPC_NTOPENPROCESSTOKEN_TAG,
+  IPC_NTOPENPROCESSTOKENEX_TAG,
+  IPC_CREATEPROCESSW_TAG,
+  IPC_CREATEEVENT_TAG,
+  IPC_OPENEVENT_TAG,
+  IPC_NTCREATEKEY_TAG,
+  IPC_NTOPENKEY_TAG,
+  IPC_DUPLICATEHANDLEPROXY_TAG,
+  IPC_GDI_GDIDLLINITIALIZE_TAG,
+  IPC_GDI_GETSTOCKOBJECT_TAG,
+  IPC_USER_REGISTERCLASSW_TAG,
+  IPC_LAST_TAG
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_IPC_TAGS_H__
diff --git a/sandbox/win/src/ipc_unittest.cc b/sandbox/win/src/ipc_unittest.cc
new file mode 100644
index 0000000..b1e74ab
--- /dev/null
+++ b/sandbox/win/src/ipc_unittest.cc
@@ -0,0 +1,639 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Helper function to make the fake shared memory with some
+// basic elements initialized.
+IPCControl* MakeChannels(size_t channel_size, size_t total_shared_size,
+                         size_t* base_start) {
+  // Allocate memory
+  char* mem = new char[total_shared_size];
+  memset(mem, 0, total_shared_size);
+  // Calculate how many channels we can fit in the shared memory.
+  total_shared_size -= offsetof(IPCControl, channels);
+  size_t channel_count =
+    total_shared_size / (sizeof(ChannelControl) + channel_size);
+  // Calculate the start of the first channel.
+  *base_start = (sizeof(ChannelControl)* channel_count) +
+    offsetof(IPCControl, channels);
+  // Setup client structure.
+  IPCControl* client_control = reinterpret_cast<IPCControl*>(mem);
+  client_control->channels_count = channel_count;
+  return client_control;
+}
+
+enum TestFixMode {
+  FIX_NO_EVENTS,
+  FIX_PONG_READY,
+  FIX_PONG_NOT_READY
+};
+
+void FixChannels(IPCControl* client_control, size_t base_start,
+                 size_t channel_size, TestFixMode mode) {
+  for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
+    ChannelControl& channel = client_control->channels[ix];
+    channel.channel_base = base_start;
+    channel.state = kFreeChannel;
+    if (mode != FIX_NO_EVENTS) {
+      BOOL signaled = (FIX_PONG_READY == mode)? TRUE : FALSE;
+      channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+      channel.pong_event = ::CreateEventW(NULL, FALSE, signaled, NULL);
+    }
+    base_start += channel_size;
+  }
+}
+
+void CloseChannelEvents(IPCControl* client_control) {
+  for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
+    ChannelControl& channel = client_control->channels[ix];
+    ::CloseHandle(channel.ping_event);
+    ::CloseHandle(channel.pong_event);
+  }
+}
+
+TEST(IPCTest, ChannelMaker) {
+  // Test that our testing rig is computing offsets properly. We should have
+  // 5 channnels and the offset to the first channel is 108 bytes in 32 bits
+  // and 216 in 64 bits.
+  size_t channel_start = 0;
+  IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start);
+  ASSERT_TRUE(NULL != client_control);
+  EXPECT_EQ(5, client_control->channels_count);
+#if defined(_WIN64)
+  EXPECT_EQ(216, channel_start);
+#else
+  EXPECT_EQ(108, channel_start);
+#endif
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, ClientLockUnlock) {
+  // Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and
+  // unlock channels properly.
+  size_t base_start = 0;
+  IPCControl* client_control =
+      MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
+  FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS);
+
+  char* mem = reinterpret_cast<char*>(client_control);
+  SharedMemIPCClient client(mem);
+
+  // Test that we lock the first 3 channels in sequence.
+  void* buff0 = client.GetBuffer();
+  EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+  void* buff1 = client.GetBuffer();
+  EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+  void* buff2 = client.GetBuffer();
+  EXPECT_TRUE(mem + client_control->channels[2].channel_base == buff2);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+  // Test that we unlock and re-lock the right channel.
+  client.FreeBuffer(buff1);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+  void* buff2b = client.GetBuffer();
+  EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff2b);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+  client.FreeBuffer(buff0);
+  EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, CrossCallStrPacking) {
+  // This test tries the CrossCall object with null and non-null string
+  // combination of parameters, integer types and verifies that the unpacker
+  // can read them properly.
+  size_t base_start = 0;
+  IPCControl* client_control =
+      MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
+  client_control->server_alive = HANDLE(1);
+  FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
+
+  char* mem = reinterpret_cast<char*>(client_control);
+  SharedMemIPCClient client(mem);
+
+  CrossCallReturn answer;
+  uint32 tag1 = 666;
+  const wchar_t *text = L"98765 - 43210";
+  base::string16 copied_text;
+  CrossCallParamsEx* actual_params;
+
+  CrossCall(client, tag1, text, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(1, actual_params->GetParamsCount());
+  EXPECT_EQ(tag1, actual_params->GetTag());
+  EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
+  EXPECT_STREQ(text, copied_text.c_str());
+
+  // Check with an empty string.
+  uint32 tag2 = 777;
+  const wchar_t* null_text = NULL;
+  CrossCall(client, tag2, null_text, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(1, actual_params->GetParamsCount());
+  EXPECT_EQ(tag2, actual_params->GetTag());
+  uint32 param_size = 1;
+  ArgType type = INVALID_TYPE;
+  void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+  EXPECT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, param_size);
+  EXPECT_EQ(WCHAR_TYPE, type);
+  EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
+
+  uint32 tag3 = 888;
+  param_size = 1;
+  copied_text.clear();
+
+  // Check with an empty string and a non-empty string.
+  CrossCall(client, tag3, null_text, text, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(2, actual_params->GetParamsCount());
+  EXPECT_EQ(tag3, actual_params->GetTag());
+  type = INVALID_TYPE;
+  param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+  EXPECT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, param_size);
+  EXPECT_EQ(WCHAR_TYPE, type);
+  EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
+  EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text));
+  EXPECT_STREQ(text, copied_text.c_str());
+
+  param_size = 1;
+  base::string16 copied_text_p0, copied_text_p2;
+
+  const wchar_t *text2 = L"AeFG";
+  CrossCall(client, tag1, text2, null_text, text, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(3, actual_params->GetParamsCount());
+  EXPECT_EQ(tag1, actual_params->GetTag());
+  EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0));
+  EXPECT_STREQ(text2, copied_text_p0.c_str());
+  EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2));
+  EXPECT_STREQ(text, copied_text_p2.c_str());
+  type = INVALID_TYPE;
+  param_addr = actual_params->GetRawParameter(1, &param_size, &type);
+  EXPECT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, param_size);
+  EXPECT_EQ(WCHAR_TYPE, type);
+
+  CloseChannelEvents(client_control);
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, CrossCallIntPacking) {
+  // Check handling for regular 32 bit integers used in Windows.
+  size_t base_start = 0;
+  IPCControl* client_control =
+      MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
+  client_control->server_alive = HANDLE(1);
+  FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
+
+  uint32 tag1 = 999;
+  uint32 tag2 = 111;
+  const wchar_t *text = L"godzilla";
+  CrossCallParamsEx* actual_params;
+
+  char* mem = reinterpret_cast<char*>(client_control);
+  SharedMemIPCClient client(mem);
+
+  CrossCallReturn answer;
+  DWORD dw = 0xE6578;
+  CrossCall(client, tag2, dw, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(1, actual_params->GetParamsCount());
+  EXPECT_EQ(tag2, actual_params->GetTag());
+  ArgType type = INVALID_TYPE;
+  uint32 param_size = 1;
+  void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+  ASSERT_EQ(sizeof(dw), param_size);
+  EXPECT_EQ(UINT32_TYPE, type);
+  ASSERT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
+
+  // Check handling for windows HANDLES.
+  HANDLE h = HANDLE(0x70000500);
+  CrossCall(client, tag1, text, h, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(2, actual_params->GetParamsCount());
+  EXPECT_EQ(tag1, actual_params->GetTag());
+  type = INVALID_TYPE;
+  param_addr = actual_params->GetRawParameter(1, &param_size, &type);
+  ASSERT_EQ(sizeof(h), param_size);
+  EXPECT_EQ(VOIDPTR_TYPE, type);
+  ASSERT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
+
+  // Check combination of 32 and 64 bits.
+  CrossCall(client, tag2, h, dw, h, &answer);
+  actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+  EXPECT_EQ(3, actual_params->GetParamsCount());
+  EXPECT_EQ(tag2, actual_params->GetTag());
+  type = INVALID_TYPE;
+  param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+  ASSERT_EQ(sizeof(h), param_size);
+  EXPECT_EQ(VOIDPTR_TYPE, type);
+  ASSERT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
+  type = INVALID_TYPE;
+  param_addr = actual_params->GetRawParameter(1, &param_size, &type);
+  ASSERT_EQ(sizeof(dw), param_size);
+  EXPECT_EQ(UINT32_TYPE, type);
+  ASSERT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
+  type = INVALID_TYPE;
+  param_addr = actual_params->GetRawParameter(2, &param_size, &type);
+  ASSERT_EQ(sizeof(h), param_size);
+  EXPECT_EQ(VOIDPTR_TYPE, type);
+  ASSERT_TRUE(NULL != param_addr);
+  EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
+
+  CloseChannelEvents(client_control);
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, CrossCallValidation) {
+  // First a sanity test with a well formed parameter object.
+  unsigned long value = 124816;
+  const uint32 kTag = 33;
+  const uint32 kBufferSize = 256;
+  ActualCallParams<1, kBufferSize> params_1(kTag);
+  params_1.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+  void* buffer = const_cast<void*>(params_1.GetBuffer());
+
+  uint32 out_size = 0;
+  CrossCallParamsEx* ccp = 0;
+  ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
+                                            &out_size);
+  ASSERT_TRUE(NULL != ccp);
+  EXPECT_TRUE(ccp->GetBuffer() != buffer);
+  EXPECT_EQ(kTag, ccp->GetTag());
+  EXPECT_EQ(1, ccp->GetParamsCount());
+  delete[] (reinterpret_cast<char*>(ccp));
+
+  // Test that we handle integer overflow on the number of params
+  // correctly. We use a test-only ctor for ActualCallParams that
+  // allows to create malformed cross-call buffers.
+  const int32 kPtrDiffSz = sizeof(ptrdiff_t);
+  for (int32 ix = -1; ix != 3; ++ix) {
+    uint32 fake_num_params = (kuint32max / kPtrDiffSz) + ix;
+    ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params);
+    params_2.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+    buffer = const_cast<void*>(params_2.GetBuffer());
+
+    EXPECT_TRUE(NULL != buffer);
+    ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
+                                              &out_size);
+    // If the buffer is malformed the return is NULL.
+    EXPECT_TRUE(NULL == ccp);
+  }
+
+  ActualCallParams<1, kBufferSize> params_3(kTag, 1);
+  params_3.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+  buffer = const_cast<void*>(params_3.GetBuffer());
+  EXPECT_TRUE(NULL != buffer);
+
+  uint32 correct_size = params_3.OverrideSize(1);
+  ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+  EXPECT_TRUE(NULL == ccp);
+
+  // The correct_size is 8 bytes aligned.
+  params_3.OverrideSize(correct_size - 7);
+  ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+  EXPECT_TRUE(NULL == ccp);
+
+  params_3.OverrideSize(correct_size);
+  ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+  EXPECT_TRUE(NULL != ccp);
+
+  // Make sure that two parameters work as expected.
+  ActualCallParams<2, kBufferSize> params_4(kTag, 2);
+  params_4.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+  params_4.CopyParamIn(1, buffer, sizeof(buffer), false, VOIDPTR_TYPE);
+  buffer = const_cast<void*>(params_4.GetBuffer());
+  EXPECT_TRUE(NULL != buffer);
+
+  ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+  EXPECT_TRUE(NULL != ccp);
+
+#if defined(_WIN64)
+  correct_size = params_4.OverrideSize(1);
+  params_4.OverrideSize(correct_size - 1);
+  ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+  EXPECT_TRUE(NULL == ccp);
+#endif
+}
+
+// This structure is passed to the mock server threads to simulate
+// the server side IPC so it has the required kernel objects.
+struct ServerEvents {
+  HANDLE ping;
+  HANDLE pong;
+  volatile LONG* state;
+  HANDLE mutex;
+};
+
+// This is the server thread that quicky answers an IPC and exits.
+DWORD WINAPI QuickResponseServer(PVOID param) {
+  ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
+  DWORD wait_result = 0;
+  wait_result = ::WaitForSingleObject(events->ping, INFINITE);
+  ::InterlockedExchange(events->state, kAckChannel);
+  ::SetEvent(events->pong);
+  return wait_result;
+}
+
+class CrossCallParamsMock : public CrossCallParams {
+ public:
+  CrossCallParamsMock(uint32 tag, uint32 params_count)
+      :  CrossCallParams(tag, params_count) {
+  }
+ private:
+  void* params[4];
+};
+
+void FakeOkAnswerInChannel(void* channel) {
+  CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel);
+  answer->call_outcome = SBOX_ALL_OK;
+}
+
+// Create two threads that will quickly answer IPCs; the first one
+// using channel 1 (channel 0 is busy) and one using channel 0. No time-out
+// should occur.
+TEST(IPCTest, ClientFastServer) {
+  const size_t channel_size = kIPCChannelSize;
+  size_t base_start = 0;
+  IPCControl* client_control =
+      MakeChannels(channel_size, 4096 * 2, &base_start);
+  FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
+  client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL);
+
+  char* mem = reinterpret_cast<char*>(client_control);
+  SharedMemIPCClient client(mem);
+
+  ServerEvents events = {0};
+  events.ping = client_control->channels[1].ping_event;
+  events.pong = client_control->channels[1].pong_event;
+  events.state = &client_control->channels[1].state;
+
+  HANDLE t1 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL);
+  ASSERT_TRUE(NULL != t1);
+  ::CloseHandle(t1);
+
+  void* buff0 = client.GetBuffer();
+  EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+  void* buff1 = client.GetBuffer();
+  EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+  EXPECT_EQ(0, client_control->channels[1].ipc_tag);
+
+  uint32 tag = 7654;
+  CrossCallReturn answer;
+  CrossCallParamsMock* params1 = new(buff1) CrossCallParamsMock(tag, 1);
+  FakeOkAnswerInChannel(buff1);
+
+  ResultCode result = client.DoCall(params1, &answer);
+  if (SBOX_ERROR_CHANNEL_ERROR != result)
+    client.FreeBuffer(buff1);
+
+  EXPECT_TRUE(SBOX_ALL_OK == result);
+  EXPECT_EQ(tag, client_control->channels[1].ipc_tag);
+  EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+  HANDLE t2 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL);
+  ASSERT_TRUE(NULL != t2);
+  ::CloseHandle(t2);
+
+  client.FreeBuffer(buff0);
+  events.ping = client_control->channels[0].ping_event;
+  events.pong = client_control->channels[0].pong_event;
+  events.state = &client_control->channels[0].state;
+
+  tag = 4567;
+  CrossCallParamsMock* params2 = new(buff0) CrossCallParamsMock(tag, 1);
+  FakeOkAnswerInChannel(buff0);
+
+  result = client.DoCall(params2, &answer);
+  if (SBOX_ERROR_CHANNEL_ERROR != result)
+    client.FreeBuffer(buff0);
+
+  EXPECT_TRUE(SBOX_ALL_OK == result);
+  EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
+  EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+  EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+  CloseChannelEvents(client_control);
+  ::CloseHandle(client_control->server_alive);
+
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+// This is the server thread that very slowly answers an IPC and exits. Note
+// that the pong event needs to be signaled twice.
+DWORD WINAPI SlowResponseServer(PVOID param) {
+  ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
+  DWORD wait_result = 0;
+  wait_result = ::WaitForSingleObject(events->ping, INFINITE);
+  ::Sleep(kIPCWaitTimeOut1 + kIPCWaitTimeOut2 + 200);
+  ::InterlockedExchange(events->state, kAckChannel);
+  ::SetEvent(events->pong);
+  return wait_result;
+}
+
+// This thread's job is to keep the mutex locked.
+DWORD WINAPI MainServerThread(PVOID param) {
+  ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
+  DWORD wait_result = 0;
+  wait_result = ::WaitForSingleObject(events->mutex, INFINITE);
+  Sleep(kIPCWaitTimeOut1 * 20);
+  return wait_result;
+}
+
+// Creates a server thread that answers the IPC so slow that is guaranteed to
+// trigger the time-out code path in the client. A second thread is created
+// to hold locked the server_alive mutex: this signals the client that the
+// server is not dead and it retries the wait.
+TEST(IPCTest, ClientSlowServer) {
+  size_t base_start = 0;
+  IPCControl* client_control =
+      MakeChannels(kIPCChannelSize, 4096*2, &base_start);
+  FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
+  client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL);
+
+  char* mem = reinterpret_cast<char*>(client_control);
+  SharedMemIPCClient client(mem);
+
+  ServerEvents events = {0};
+  events.ping = client_control->channels[0].ping_event;
+  events.pong = client_control->channels[0].pong_event;
+  events.state = &client_control->channels[0].state;
+
+  HANDLE t1 = ::CreateThread(NULL, 0, SlowResponseServer, &events, 0, NULL);
+  ASSERT_TRUE(NULL != t1);
+  ::CloseHandle(t1);
+
+  ServerEvents events2 = {0};
+  events2.pong = events.pong;
+  events2.mutex = client_control->server_alive;
+
+  HANDLE t2 = ::CreateThread(NULL, 0, MainServerThread, &events2, 0, NULL);
+  ASSERT_TRUE(NULL != t2);
+  ::CloseHandle(t2);
+
+  ::Sleep(1);
+
+  void* buff0 = client.GetBuffer();
+  uint32 tag = 4321;
+  CrossCallReturn answer;
+  CrossCallParamsMock* params1 = new(buff0) CrossCallParamsMock(tag, 1);
+  FakeOkAnswerInChannel(buff0);
+
+  ResultCode result = client.DoCall(params1, &answer);
+  if (SBOX_ERROR_CHANNEL_ERROR != result)
+    client.FreeBuffer(buff0);
+
+  EXPECT_TRUE(SBOX_ALL_OK == result);
+  EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
+  EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
+
+  CloseChannelEvents(client_control);
+  ::CloseHandle(client_control->server_alive);
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+// This test-only IPC dispatcher has two handlers with the same signature
+// but only CallOneHandler should be used.
+class UnitTestIPCDispatcher : public Dispatcher {
+ public:
+  enum {
+    CALL_ONE_TAG = 78,
+    CALL_TWO_TAG = 87
+  };
+
+  UnitTestIPCDispatcher();
+  ~UnitTestIPCDispatcher() override{};
+
+  bool SetupService(InterceptionManager* manager, int service) override {
+    return true;
+  }
+
+ private:
+  bool CallOneHandler(IPCInfo* ipc, HANDLE p1, uint32 p2) {
+    ipc->return_info.extended[0].handle = p1;
+    ipc->return_info.extended[1].unsigned_int = p2;
+    return true;
+  }
+
+  bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, uint32 p2) {
+    return true;
+  }
+};
+
+UnitTestIPCDispatcher::UnitTestIPCDispatcher() {
+  static const IPCCall call_one = {
+    {CALL_ONE_TAG, VOIDPTR_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &UnitTestIPCDispatcher::CallOneHandler)
+  };
+  static const IPCCall call_two = {
+    {CALL_TWO_TAG, VOIDPTR_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &UnitTestIPCDispatcher::CallTwoHandler)
+  };
+  ipc_calls_.push_back(call_one);
+  ipc_calls_.push_back(call_two);
+}
+
+// This test does most of the shared memory IPC client-server roundtrip
+// and tests the packing, unpacking and call dispatching.
+TEST(IPCTest, SharedMemServerTests) {
+  size_t base_start = 0;
+  IPCControl* client_control =
+      MakeChannels(kIPCChannelSize, 4096, &base_start);
+  client_control->server_alive = HANDLE(1);
+  FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
+
+  char* mem = reinterpret_cast<char*>(client_control);
+  SharedMemIPCClient client(mem);
+
+  CrossCallReturn answer;
+  HANDLE bar = HANDLE(191919);
+  DWORD foo = 6767676;
+  CrossCall(client, UnitTestIPCDispatcher::CALL_ONE_TAG, bar, foo, &answer);
+  void* buff = client.GetBuffer();
+  ASSERT_TRUE(NULL != buff);
+
+  UnitTestIPCDispatcher dispatcher;
+  // Since we are directly calling InvokeCallback, most of this structure
+  // can be set to NULL.
+  sandbox::SharedMemIPCServer::ServerControl srv_control = {
+      NULL, NULL, kIPCChannelSize, NULL,
+      reinterpret_cast<char*>(client_control),
+      NULL, &dispatcher, {0} };
+
+  sandbox::CrossCallReturn call_return = {0};
+  EXPECT_TRUE(SharedMemIPCServer::InvokeCallback(&srv_control, buff,
+                                                 &call_return));
+  EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome);
+  EXPECT_TRUE(bar == call_return.extended[0].handle);
+  EXPECT_EQ(foo, call_return.extended[1].unsigned_int);
+
+  CloseChannelEvents(client_control);
+  delete[] reinterpret_cast<char*>(client_control);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/job.cc b/sandbox/win/src/job.cc
new file mode 100644
index 0000000..8852ab0
--- /dev/null
+++ b/sandbox/win/src/job.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/job.h"
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/restricted_token.h"
+
+namespace sandbox {
+
+Job::~Job() {
+  if (job_handle_)
+    ::CloseHandle(job_handle_);
+};
+
+DWORD Job::Init(JobLevel security_level,
+                const wchar_t* job_name,
+                DWORD ui_exceptions,
+                size_t memory_limit) {
+  if (job_handle_)
+    return ERROR_ALREADY_INITIALIZED;
+
+  job_handle_ = ::CreateJobObject(NULL,   // No security attribute
+                                  job_name);
+  if (!job_handle_)
+    return ::GetLastError();
+
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
+  JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
+
+  // Set the settings for the different security levels. Note: The higher levels
+  // inherit from the lower levels.
+  switch (security_level) {
+    case JOB_LOCKDOWN: {
+      jeli.BasicLimitInformation.LimitFlags |=
+          JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
+    }
+    case JOB_RESTRICTED: {
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_READCLIPBOARD;
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_GLOBALATOMS;
+    }
+    case JOB_LIMITED_USER: {
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
+      jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
+      jeli.BasicLimitInformation.ActiveProcessLimit = 1;
+    }
+    case JOB_INTERACTIVE: {
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DESKTOP;
+      jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
+    }
+    case JOB_UNPROTECTED: {
+      if (memory_limit) {
+        jeli.BasicLimitInformation.LimitFlags |=
+            JOB_OBJECT_LIMIT_PROCESS_MEMORY;
+        jeli.ProcessMemoryLimit = memory_limit;
+      }
+
+      jeli.BasicLimitInformation.LimitFlags |=
+          JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+      break;
+    }
+    default: {
+      return ERROR_BAD_ARGUMENTS;
+    }
+  }
+
+  if (FALSE == ::SetInformationJobObject(job_handle_,
+                                         JobObjectExtendedLimitInformation,
+                                         &jeli,
+                                         sizeof(jeli))) {
+    return ::GetLastError();
+  }
+
+  jbur.UIRestrictionsClass = jbur.UIRestrictionsClass & (~ui_exceptions);
+  if (FALSE == ::SetInformationJobObject(job_handle_,
+                                         JobObjectBasicUIRestrictions,
+                                         &jbur,
+                                         sizeof(jbur))) {
+    return ::GetLastError();
+  }
+
+  return ERROR_SUCCESS;
+}
+
+DWORD Job::UserHandleGrantAccess(HANDLE handle) {
+  if (!job_handle_)
+    return ERROR_NO_DATA;
+
+  if (!::UserHandleGrantAccess(handle,
+                               job_handle_,
+                               TRUE)) {  // Access allowed.
+    return ::GetLastError();
+  }
+
+  return ERROR_SUCCESS;
+}
+
+HANDLE Job::Detach() {
+  HANDLE handle_temp = job_handle_;
+  job_handle_ = NULL;
+  return handle_temp;
+}
+
+DWORD Job::AssignProcessToJob(HANDLE process_handle) {
+  if (!job_handle_)
+    return ERROR_NO_DATA;
+
+  if (FALSE == ::AssignProcessToJobObject(job_handle_, process_handle))
+    return ::GetLastError();
+
+  return ERROR_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/job.h b/sandbox/win/src/job.h
new file mode 100644
index 0000000..60dc314
--- /dev/null
+++ b/sandbox/win/src/job.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_JOB_H_
+#define SANDBOX_SRC_JOB_H_
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+
+namespace sandbox {
+
+// Handles the creation of job objects based on a security profile.
+// Sample usage:
+//   Job job;
+//   job.Init(JOB_LOCKDOWN, NULL);  //no job name
+//   job.AssignProcessToJob(process_handle);
+class Job {
+ public:
+  Job() : job_handle_(NULL) { }
+
+  ~Job();
+
+  // Initializes and creates the job object. The security of the job is based
+  // on the security_level parameter.
+  // job_name can be NULL if the job is unnamed.
+  // If the chosen profile has too many ui restrictions, you can disable some
+  // by specifying them in the ui_exceptions parameters.
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  DWORD Init(JobLevel security_level,
+             const wchar_t* job_name,
+             DWORD ui_exceptions,
+             size_t memory_limit);
+
+  // Assigns the process referenced by process_handle to the job.
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  DWORD AssignProcessToJob(HANDLE process_handle);
+
+  // Grants access to "handle" to the job. All processes in the job can
+  // subsequently recognize and use the handle.
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  DWORD UserHandleGrantAccess(HANDLE handle);
+
+  // Revokes ownership to the job handle and returns it. The destructor of the
+  // class won't close the handle when called.
+  // If the object is not yet initialized, it returns 0.
+  HANDLE Detach();
+
+ private:
+  // Handle to the job referenced by the object.
+  HANDLE job_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_JOB_H_
diff --git a/sandbox/win/src/job_unittest.cc b/sandbox/win/src/job_unittest.cc
new file mode 100644
index 0000000..a1b7aca
--- /dev/null
+++ b/sandbox/win/src/job_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for the job object.
+
+#include "base/win/scoped_process_information.h"
+#include "sandbox/win/src/job.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Tests the creation and destruction of the job.
+TEST(JobTest, TestCreation) {
+  // Scope the creation of Job.
+  {
+    // Create the job.
+    Job job;
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+
+    // check if the job exists.
+    HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE,
+                                         L"my_test_job_name");
+    ASSERT_TRUE(job_handle != NULL);
+
+    if (job_handle)
+      CloseHandle(job_handle);
+  }
+
+  // Check if the job is destroyed when the object goes out of scope.
+  HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
+  ASSERT_TRUE(job_handle == NULL);
+  ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
+}
+
+// Tests the method "Detach".
+TEST(JobTest, TestDetach) {
+  HANDLE job_handle;
+  // Scope the creation of Job.
+  {
+    // Create the job.
+    Job job;
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+
+    job_handle = job.Detach();
+    ASSERT_TRUE(job_handle != NULL);
+  }
+
+  // Check to be sure that the job is still alive even after the object is gone
+  // out of scope.
+  HANDLE job_handle_dup = ::OpenJobObjectW(GENERIC_ALL, FALSE,
+                                           L"my_test_job_name");
+  ASSERT_TRUE(job_handle_dup != NULL);
+
+  // Remove all references.
+  if (job_handle_dup)
+    ::CloseHandle(job_handle_dup);
+
+  if (job_handle)
+    ::CloseHandle(job_handle);
+
+  // Check if the jbo is really dead.
+  job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
+  ASSERT_TRUE(job_handle == NULL);
+  ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
+}
+
+// Tests the ui exceptions
+TEST(JobTest, TestExceptions) {
+  HANDLE job_handle;
+  // Scope the creation of Job.
+  {
+    // Create the job.
+    Job job;
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name",
+                                      JOB_OBJECT_UILIMIT_READCLIPBOARD, 0));
+
+    job_handle = job.Detach();
+    ASSERT_TRUE(job_handle != NULL);
+
+    JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
+    DWORD size = sizeof(jbur);
+    BOOL result = ::QueryInformationJobObject(job_handle,
+                                              JobObjectBasicUIRestrictions,
+                                              &jbur, size, &size);
+    ASSERT_TRUE(result);
+
+    ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD, 0);
+    ::CloseHandle(job_handle);
+  }
+
+  // Scope the creation of Job.
+  {
+    // Create the job.
+    Job job;
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+
+    job_handle = job.Detach();
+    ASSERT_TRUE(job_handle != NULL);
+
+    JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
+    DWORD size = sizeof(jbur);
+    BOOL result = ::QueryInformationJobObject(job_handle,
+                                              JobObjectBasicUIRestrictions,
+                                              &jbur, size, &size);
+    ASSERT_TRUE(result);
+
+    ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD,
+              JOB_OBJECT_UILIMIT_READCLIPBOARD);
+    ::CloseHandle(job_handle);
+  }
+}
+
+// Tests the error case when the job is initialized twice.
+TEST(JobTest, DoubleInit) {
+  // Create the job.
+  Job job;
+  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+  ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0, 0));
+}
+
+// Tests the error case when we use a method and the object is not yet
+// initialized.
+TEST(JobTest, NoInit) {
+  Job job;
+  ASSERT_EQ(ERROR_NO_DATA, job.UserHandleGrantAccess(NULL));
+  ASSERT_EQ(ERROR_NO_DATA, job.AssignProcessToJob(NULL));
+  ASSERT_TRUE(job.Detach() == NULL);
+}
+
+// Tests the initialization of the job with different security level.
+TEST(JobTest, SecurityLevel) {
+  Job job1;
+  ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0, 0));
+
+  Job job2;
+  ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0, 0));
+
+  Job job3;
+  ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0, 0));
+
+  Job job4;
+  ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0, 0));
+
+  Job job5;
+  ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 0, 0));
+
+  // JOB_NONE means we run without a job object so Init should fail.
+  Job job6;
+  ASSERT_EQ(ERROR_BAD_ARGUMENTS, job6.Init(JOB_NONE, L"job6", 0, 0));
+
+  Job job7;
+  ASSERT_EQ(ERROR_BAD_ARGUMENTS, job7.Init(
+      static_cast<JobLevel>(JOB_NONE+1), L"job7", 0, 0));
+}
+
+// Tests the method "AssignProcessToJob".
+TEST(JobTest, ProcessInJob) {
+  // Create the job.
+  Job job;
+  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0,
+                                    0));
+
+  BOOL result = FALSE;
+
+  wchar_t notepad[] = L"notepad";
+  STARTUPINFO si = { sizeof(si) };
+  PROCESS_INFORMATION temp_process_info = {};
+  result = ::CreateProcess(NULL, notepad, NULL, NULL, FALSE, 0, NULL, NULL, &si,
+                           &temp_process_info);
+  ASSERT_TRUE(result);
+  base::win::ScopedProcessInformation pi(temp_process_info);
+  ASSERT_EQ(ERROR_SUCCESS, job.AssignProcessToJob(pi.process_handle()));
+
+  // Get the job handle.
+  HANDLE job_handle = job.Detach();
+
+  // Check if the process is in the job.
+  JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl = {0};
+  DWORD size = sizeof(jbpidl);
+  result = ::QueryInformationJobObject(job_handle,
+                                       JobObjectBasicProcessIdList,
+                                       &jbpidl, size, &size);
+  EXPECT_TRUE(result);
+
+  EXPECT_EQ(1, jbpidl.NumberOfAssignedProcesses);
+  EXPECT_EQ(1, jbpidl.NumberOfProcessIdsInList);
+  EXPECT_EQ(pi.process_id(), jbpidl.ProcessIdList[0]);
+
+  EXPECT_TRUE(::TerminateProcess(pi.process_handle(), 0));
+
+  EXPECT_TRUE(::CloseHandle(job_handle));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/named_pipe_dispatcher.cc b/sandbox/win/src/named_pipe_dispatcher.cc
new file mode 100644
index 0000000..5527319
--- /dev/null
+++ b/sandbox/win/src/named_pipe_dispatcher.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/named_pipe_dispatcher.h"
+
+#include "base/basictypes.h"
+#include "base/strings/string_split.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/named_pipe_interception.h"
+#include "sandbox/win/src/named_pipe_policy.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+
+namespace sandbox {
+
+NamedPipeDispatcher::NamedPipeDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall create_params = {
+    {IPC_CREATENAMEDPIPEW_TAG, WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE,
+     UINT32_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&NamedPipeDispatcher::CreateNamedPipe)
+  };
+
+  ipc_calls_.push_back(create_params);
+}
+
+bool NamedPipeDispatcher::SetupService(InterceptionManager* manager,
+                                       int service) {
+  if (IPC_CREATENAMEDPIPEW_TAG == service)
+    return INTERCEPT_EAT(manager, kKerneldllName, CreateNamedPipeW,
+                         CREATE_NAMED_PIPE_ID, 36);
+
+  return false;
+}
+
+bool NamedPipeDispatcher::CreateNamedPipe(IPCInfo* ipc,
+                                          base::string16* name,
+                                          uint32 open_mode,
+                                          uint32 pipe_mode,
+                                          uint32 max_instances,
+                                          uint32 out_buffer_size,
+                                          uint32 in_buffer_size,
+                                          uint32 default_timeout) {
+  ipc->return_info.win32_result = ERROR_ACCESS_DENIED;
+  ipc->return_info.handle = INVALID_HANDLE_VALUE;
+
+  std::vector<base::string16> paths;
+  std::vector<base::string16> innerpaths;
+  base::SplitString(*name, '/', &paths);
+
+  for (std::vector<base::string16>::const_iterator iter = paths.begin();
+       iter != paths.end(); ++iter) {
+    base::SplitString(*iter, '\\', &innerpaths);
+    for (std::vector<base::string16>::const_iterator iter2 = innerpaths.begin();
+         iter2 != innerpaths.end(); ++iter2) {
+      if (*iter2 == L"..")
+        return true;
+    }
+  }
+
+  const wchar_t* pipe_name = name->c_str();
+  CountedParameterSet<NameBased> params;
+  params[NameBased::NAME] = ParamPickerMake(pipe_name);
+
+  EvalResult eval = policy_base_->EvalPolicy(IPC_CREATENAMEDPIPEW_TAG,
+                                             params.GetBase());
+
+  // "For file I/O, the "\\?\" prefix to a path string tells the Windows APIs to
+  // disable all string parsing and to send the string that follows it straight
+  // to the file system."
+  // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+  // This ensures even if there is a path traversal in the pipe name, and it is
+  // able to get past the checks above, it will still not be allowed to escape
+  // our whitelisted namespace.
+  if (name->compare(0, 4, L"\\\\.\\") == 0)
+    name->replace(0, 4, L"\\\\\?\\");
+
+  HANDLE pipe;
+  DWORD ret = NamedPipePolicy::CreateNamedPipeAction(eval, *ipc->client_info,
+                                                     *name, open_mode,
+                                                     pipe_mode, max_instances,
+                                                     out_buffer_size,
+                                                     in_buffer_size,
+                                                     default_timeout, &pipe);
+
+  ipc->return_info.win32_result = ret;
+  ipc->return_info.handle = pipe;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/named_pipe_dispatcher.h b/sandbox/win/src/named_pipe_dispatcher.h
new file mode 100644
index 0000000..1c02199
--- /dev/null
+++ b/sandbox/win/src/named_pipe_dispatcher.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_NAMED_PIPE_DISPATCHER_H__
+#define SANDBOX_SRC_NAMED_PIPE_DISPATCHER_H__
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles named pipe related IPC calls.
+class NamedPipeDispatcher : public Dispatcher {
+ public:
+  explicit NamedPipeDispatcher(PolicyBase* policy_base);
+  ~NamedPipeDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to CreateNamedPipeW() in the
+  // target.
+  bool CreateNamedPipe(IPCInfo* ipc,
+                       base::string16* name,
+                       uint32 open_mode,
+                       uint32 pipe_mode,
+                       uint32 max_instances,
+                       uint32 out_buffer_size,
+                       uint32 in_buffer_size,
+                       uint32 default_timeout);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(NamedPipeDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_NAMED_PIPE_DISPATCHER_H__
diff --git a/sandbox/win/src/named_pipe_interception.cc b/sandbox/win/src/named_pipe_interception.cc
new file mode 100644
index 0000000..c62d093
--- /dev/null
+++ b/sandbox/win/src/named_pipe_interception.cc
@@ -0,0 +1,72 @@
+// 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 "sandbox/win/src/named_pipe_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+HANDLE WINAPI TargetCreateNamedPipeW(
+    CreateNamedPipeWFunction orig_CreateNamedPipeW, LPCWSTR pipe_name,
+    DWORD open_mode, DWORD pipe_mode, DWORD max_instance, DWORD out_buffer_size,
+    DWORD in_buffer_size, DWORD default_timeout,
+    LPSECURITY_ATTRIBUTES security_attributes) {
+  HANDLE pipe = orig_CreateNamedPipeW(pipe_name, open_mode, pipe_mode,
+                                      max_instance, out_buffer_size,
+                                      in_buffer_size, default_timeout,
+                                      security_attributes);
+  if (INVALID_HANDLE_VALUE != pipe)
+    return pipe;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return INVALID_HANDLE_VALUE;
+
+  DWORD original_error = ::GetLastError();
+
+  // We don't support specific Security Attributes.
+  if (security_attributes)
+    return INVALID_HANDLE_VALUE;
+
+  do {
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    CountedParameterSet<NameBased> params;
+    params[NameBased::NAME] = ParamPickerMake(pipe_name);
+
+    if (!QueryBroker(IPC_CREATENAMEDPIPEW_TAG, params.GetBase()))
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_CREATENAMEDPIPEW_TAG, pipe_name,
+                                open_mode, pipe_mode, max_instance,
+                                out_buffer_size, in_buffer_size,
+                                default_timeout, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    ::SetLastError(answer.win32_result);
+
+    if (ERROR_SUCCESS != answer.win32_result)
+      return INVALID_HANDLE_VALUE;
+
+    return answer.handle;
+  } while (false);
+
+  ::SetLastError(original_error);
+  return INVALID_HANDLE_VALUE;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/named_pipe_interception.h b/sandbox/win/src/named_pipe_interception.h
new file mode 100644
index 0000000..fdbee19
--- /dev/null
+++ b/sandbox/win/src/named_pipe_interception.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_NAMED_PIPE_INTERCEPTION_H__
+#define SANDBOX_SRC_NAMED_PIPE_INTERCEPTION_H__
+
+namespace sandbox {
+
+extern "C" {
+
+typedef HANDLE (WINAPI *CreateNamedPipeWFunction) (
+    LPCWSTR lpName,
+    DWORD dwOpenMode,
+    DWORD dwPipeMode,
+    DWORD nMaxInstances,
+    DWORD nOutBufferSize,
+    DWORD nInBufferSize,
+    DWORD nDefaultTimeOut,
+    LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+// Interception of CreateNamedPipeW in kernel32.dll
+SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateNamedPipeW(
+    CreateNamedPipeWFunction orig_CreateNamedPipeW, LPCWSTR pipe_name,
+    DWORD open_mode, DWORD pipe_mode, DWORD max_instance, DWORD out_buffer_size,
+    DWORD in_buffer_size, DWORD default_timeout,
+    LPSECURITY_ATTRIBUTES security_attributes);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_NAMED_PIPE_INTERCEPTION_H__
diff --git a/sandbox/win/src/named_pipe_policy.cc b/sandbox/win/src/named_pipe_policy.cc
new file mode 100644
index 0000000..eee719e
--- /dev/null
+++ b/sandbox/win/src/named_pipe_policy.cc
@@ -0,0 +1,86 @@
+// 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 "sandbox/win/src/named_pipe_policy.h"
+
+#include <string>
+
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace {
+
+// Creates a named pipe and duplicates the handle to 'target_process'. The
+// remaining parameters are the same as CreateNamedPipeW().
+HANDLE CreateNamedPipeHelper(HANDLE target_process, LPCWSTR pipe_name,
+                              DWORD open_mode, DWORD pipe_mode,
+                              DWORD max_instances, DWORD out_buffer_size,
+                              DWORD in_buffer_size, DWORD default_timeout,
+                              LPSECURITY_ATTRIBUTES security_attributes) {
+  HANDLE pipe = ::CreateNamedPipeW(pipe_name, open_mode, pipe_mode,
+                                   max_instances, out_buffer_size,
+                                   in_buffer_size, default_timeout,
+                                   security_attributes);
+  if (INVALID_HANDLE_VALUE == pipe)
+    return pipe;
+
+  HANDLE new_pipe;
+  if (!::DuplicateHandle(::GetCurrentProcess(), pipe,
+                         target_process, &new_pipe,
+                         0, FALSE,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return INVALID_HANDLE_VALUE;
+  }
+
+  return new_pipe;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+bool NamedPipePolicy::GenerateRules(const wchar_t* name,
+                                    TargetPolicy::Semantics semantics,
+                                    LowLevelPolicy* policy) {
+  if (TargetPolicy::NAMEDPIPES_ALLOW_ANY != semantics) {
+    return false;
+  }
+  PolicyRule pipe(ASK_BROKER);
+  if (!pipe.AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) {
+    return false;
+  }
+  if (!policy->AddRule(IPC_CREATENAMEDPIPEW_TAG, &pipe)) {
+    return false;
+  }
+  return true;
+}
+
+DWORD NamedPipePolicy::CreateNamedPipeAction(EvalResult eval_result,
+                                             const ClientInfo& client_info,
+                                             const base::string16 &name,
+                                             DWORD open_mode, DWORD pipe_mode,
+                                             DWORD max_instances,
+                                             DWORD out_buffer_size,
+                                             DWORD in_buffer_size,
+                                             DWORD default_timeout,
+                                             HANDLE* pipe) {
+  // The only action supported is ASK_BROKER which means create the pipe.
+  if (ASK_BROKER != eval_result) {
+    return ERROR_ACCESS_DENIED;
+  }
+
+  *pipe = CreateNamedPipeHelper(client_info.process, name.c_str(),
+                                open_mode, pipe_mode, max_instances,
+                                out_buffer_size, in_buffer_size,
+                                default_timeout, NULL);
+
+  if (INVALID_HANDLE_VALUE == *pipe)
+    return ERROR_ACCESS_DENIED;
+
+  return ERROR_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/named_pipe_policy.h b/sandbox/win/src/named_pipe_policy.h
new file mode 100644
index 0000000..c904aa3
--- /dev/null
+++ b/sandbox/win/src/named_pipe_policy.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_NAMED_PIPE_POLICY_H__
+#define SANDBOX_SRC_NAMED_PIPE_POLICY_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to named pipe creation.
+class NamedPipePolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level.
+  // policy rule for named pipe creation
+  // 'name' is the named pipe to be created
+  // 'semantics' is the desired semantics.
+  // 'policy' is the policy generator to which the rules are going to be added.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Processes a 'CreateNamedPipeW()' request from the target.
+  static DWORD CreateNamedPipeAction(EvalResult eval_result,
+                                     const ClientInfo& client_info,
+                                     const base::string16 &name,
+                                     DWORD open_mode, DWORD pipe_mode,
+                                     DWORD max_instances,
+                                     DWORD out_buffer_size,
+                                     DWORD in_buffer_size,
+                                     DWORD default_timeout, HANDLE* pipe);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_NAMED_PIPE_POLICY_H__
diff --git a/sandbox/win/src/named_pipe_policy_test.cc b/sandbox/win/src/named_pipe_policy_test.cc
new file mode 100644
index 0000000..813cf1f
--- /dev/null
+++ b/sandbox/win/src/named_pipe_policy_test.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/handle_closer.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+
+SBOX_TESTS_COMMAND int NamedPipe_Create(int argc, wchar_t **argv) {
+  if (argc < 1 || argc > 2) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  HANDLE pipe = ::CreateNamedPipeW(argv[0],
+                                   PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                                   PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 4096,
+                                   4096, 2000, NULL);
+  if (INVALID_HANDLE_VALUE == pipe)
+    return SBOX_TEST_DENIED;
+
+  // The second parameter allows us to enforce a whitelist for where the
+  // pipe should be in the object namespace after creation.
+  if (argc == 2) {
+    base::string16 handle_name;
+    if (GetHandleName(pipe, &handle_name)) {
+      if (handle_name.compare(0, wcslen(argv[1]), argv[1]) != 0)
+        return SBOX_TEST_FAILED;
+    } else {
+      return SBOX_TEST_FAILED;
+    }
+  }
+
+  OVERLAPPED overlapped = {0};
+  overlapped.hEvent = ::CreateEvent(NULL, TRUE, TRUE, NULL);
+  BOOL result = ::ConnectNamedPipe(pipe, &overlapped);
+
+  if (!result) {
+    DWORD error = ::GetLastError();
+    if (ERROR_PIPE_CONNECTED != error &&
+        ERROR_IO_PENDING != error) {
+          return SBOX_TEST_FAILED;
+    }
+  }
+
+  if (!::CloseHandle(pipe))
+    return SBOX_TEST_FAILED;
+
+  ::CloseHandle(overlapped.hEvent);
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests if we can create a pipe in the sandbox.
+TEST(NamedPipePolicyTest, CreatePipe) {
+  TestRunner runner;
+  // TODO(nsylvain): This policy is wrong because "*" is a valid char in a
+  // namedpipe name. Here we apply it like a wildcard. http://b/893603
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_NAMED_PIPES,
+                             TargetPolicy::NAMEDPIPES_ALLOW_ANY,
+                             L"\\\\.\\pipe\\test*"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\testbleh"));
+
+  // On XP, the sandbox can create a pipe without any help but it fails on
+  // Vista+, this is why we do not test the "denied" case.
+  if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
+    EXPECT_EQ(SBOX_TEST_DENIED,
+              runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\bleh"));
+  }
+}
+
+// Tests if we can create a pipe with a path traversal in the sandbox.
+TEST(NamedPipePolicyTest, CreatePipeTraversal) {
+  TestRunner runner;
+  // TODO(nsylvain): This policy is wrong because "*" is a valid char in a
+  // namedpipe name. Here we apply it like a wildcard. http://b/893603
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_NAMED_PIPES,
+                             TargetPolicy::NAMEDPIPES_ALLOW_ANY,
+                              L"\\\\.\\pipe\\test*"));
+
+  // On XP, the sandbox can create a pipe without any help but it fails on
+  // Vista+, this is why we do not test the "denied" case.
+  if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
+    EXPECT_EQ(SBOX_TEST_DENIED,
+              runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test\\..\\bleh"));
+    EXPECT_EQ(SBOX_TEST_DENIED,
+              runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test/../bleh"));
+    EXPECT_EQ(SBOX_TEST_DENIED,
+              runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test\\../bleh"));
+    EXPECT_EQ(SBOX_TEST_DENIED,
+              runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test/..\\bleh"));
+  }
+}
+
+// This tests that path canonicalization is actually disabled if we use \\?\
+// syntax.
+TEST(NamedPipePolicyTest, CreatePipeCanonicalization) {
+  // "For file I/O, the "\\?\" prefix to a path string tells the Windows APIs to
+  // disable all string parsing and to send the string that follows it straight
+  // to the file system."
+  // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+  const wchar_t* argv[2] = { L"\\\\?\\pipe\\test\\..\\bleh",
+                             L"\\Device\\NamedPipe\\test" };
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            NamedPipe_Create(2, const_cast<wchar_t**>(argv)));
+}
+
+// The same test as CreatePipe but this time using strict interceptions.
+TEST(NamedPipePolicyTest, CreatePipeStrictInterceptions) {
+  TestRunner runner;
+  runner.GetPolicy()->SetStrictInterceptions();
+
+  // TODO(nsylvain): This policy is wrong because "*" is a valid char in a
+  // namedpipe name. Here we apply it like a wildcard. http://b/893603
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_NAMED_PIPES,
+                             TargetPolicy::NAMEDPIPES_ALLOW_ANY,
+                              L"\\\\.\\pipe\\test*"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\testbleh"));
+
+  // On XP, the sandbox can create a pipe without any help but it fails on
+  // Vista+, this is why we do not test the "denied" case.
+  if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
+    EXPECT_EQ(SBOX_TEST_DENIED,
+              runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\bleh"));
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h
new file mode 100644
index 0000000..45511a1
--- /dev/null
+++ b/sandbox/win/src/nt_internals.h
@@ -0,0 +1,684 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file holds definitions related to the ntdll API.
+
+#ifndef SANDBOX_WIN_SRC_NT_INTERNALS_H__
+#define SANDBOX_WIN_SRC_NT_INTERNALS_H__
+
+#include <windows.h>
+
+typedef LONG NTSTATUS;
+#define NT_SUCCESS(st) (st >= 0)
+
+#define STATUS_SUCCESS                ((NTSTATUS)0x00000000L)
+#define STATUS_BUFFER_OVERFLOW        ((NTSTATUS)0x80000005L)
+#define STATUS_UNSUCCESSFUL           ((NTSTATUS)0xC0000001L)
+#define STATUS_NOT_IMPLEMENTED        ((NTSTATUS)0xC0000002L)
+#define STATUS_INFO_LENGTH_MISMATCH   ((NTSTATUS)0xC0000004L)
+#ifndef STATUS_INVALID_PARAMETER
+// It is now defined in Windows 2008 SDK.
+#define STATUS_INVALID_PARAMETER      ((NTSTATUS)0xC000000DL)
+#endif
+#define STATUS_CONFLICTING_ADDRESSES  ((NTSTATUS)0xC0000018L)
+#define STATUS_ACCESS_DENIED          ((NTSTATUS)0xC0000022L)
+#define STATUS_BUFFER_TOO_SMALL       ((NTSTATUS)0xC0000023L)
+#define STATUS_OBJECT_NAME_NOT_FOUND  ((NTSTATUS)0xC0000034L)
+#define STATUS_OBJECT_NAME_COLLISION  ((NTSTATUS)0xC0000035L)
+#define STATUS_PROCEDURE_NOT_FOUND    ((NTSTATUS)0xC000007AL)
+#define STATUS_INVALID_IMAGE_FORMAT   ((NTSTATUS)0xC000007BL)
+#define STATUS_NO_TOKEN               ((NTSTATUS)0xC000007CL)
+
+#define CURRENT_PROCESS ((HANDLE) -1)
+#define CURRENT_THREAD  ((HANDLE) -2)
+#define NtCurrentProcess CURRENT_PROCESS
+
+typedef struct _UNICODE_STRING {
+  USHORT Length;
+  USHORT MaximumLength;
+  PWSTR  Buffer;
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+typedef struct _STRING {
+  USHORT Length;
+  USHORT MaximumLength;
+  PCHAR Buffer;
+} STRING;
+typedef STRING *PSTRING;
+
+typedef STRING ANSI_STRING;
+typedef PSTRING PANSI_STRING;
+typedef CONST PSTRING PCANSI_STRING;
+
+typedef STRING OEM_STRING;
+typedef PSTRING POEM_STRING;
+typedef CONST STRING* PCOEM_STRING;
+
+#define OBJ_CASE_INSENSITIVE 0x00000040L
+
+typedef struct _OBJECT_ATTRIBUTES {
+  ULONG Length;
+  HANDLE RootDirectory;
+  PUNICODE_STRING ObjectName;
+  ULONG Attributes;
+  PVOID SecurityDescriptor;
+  PVOID SecurityQualityOfService;
+} OBJECT_ATTRIBUTES;
+typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
+
+#define InitializeObjectAttributes(p, n, a, r, s) { \
+  (p)->Length = sizeof(OBJECT_ATTRIBUTES);\
+  (p)->RootDirectory = r;\
+  (p)->Attributes = a;\
+  (p)->ObjectName = n;\
+  (p)->SecurityDescriptor = s;\
+  (p)->SecurityQualityOfService = NULL;\
+}
+
+typedef struct _IO_STATUS_BLOCK {
+  union {
+    NTSTATUS Status;
+    PVOID Pointer;
+  };
+  ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+// -----------------------------------------------------------------------
+// File IO
+
+// Create disposition values.
+
+#define FILE_SUPERSEDE                          0x00000000
+#define FILE_OPEN                               0x00000001
+#define FILE_CREATE                             0x00000002
+#define FILE_OPEN_IF                            0x00000003
+#define FILE_OVERWRITE                          0x00000004
+#define FILE_OVERWRITE_IF                       0x00000005
+#define FILE_MAXIMUM_DISPOSITION                0x00000005
+
+// Create/open option flags.
+
+#define FILE_DIRECTORY_FILE                     0x00000001
+#define FILE_WRITE_THROUGH                      0x00000002
+#define FILE_SEQUENTIAL_ONLY                    0x00000004
+#define FILE_NO_INTERMEDIATE_BUFFERING          0x00000008
+
+#define FILE_SYNCHRONOUS_IO_ALERT               0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT            0x00000020
+#define FILE_NON_DIRECTORY_FILE                 0x00000040
+#define FILE_CREATE_TREE_CONNECTION             0x00000080
+
+#define FILE_COMPLETE_IF_OPLOCKED               0x00000100
+#define FILE_NO_EA_KNOWLEDGE                    0x00000200
+#define FILE_OPEN_REMOTE_INSTANCE               0x00000400
+#define FILE_RANDOM_ACCESS                      0x00000800
+
+#define FILE_DELETE_ON_CLOSE                    0x00001000
+#define FILE_OPEN_BY_FILE_ID                    0x00002000
+#define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
+#define FILE_NO_COMPRESSION                     0x00008000
+
+#define FILE_RESERVE_OPFILTER                   0x00100000
+#define FILE_OPEN_REPARSE_POINT                 0x00200000
+#define FILE_OPEN_NO_RECALL                     0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
+
+// Create/open result values. These are the disposition values returned on the
+// io status information.
+#define FILE_SUPERSEDED                         0x00000000
+#define FILE_OPENED                             0x00000001
+#define FILE_CREATED                            0x00000002
+#define FILE_OVERWRITTEN                        0x00000003
+#define FILE_EXISTS                             0x00000004
+#define FILE_DOES_NOT_EXIST                     0x00000005
+
+typedef NTSTATUS (WINAPI *NtCreateFileFunction)(
+  OUT PHANDLE FileHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PIO_STATUS_BLOCK IoStatusBlock,
+  IN PLARGE_INTEGER AllocationSize OPTIONAL,
+  IN ULONG FileAttributes,
+  IN ULONG ShareAccess,
+  IN ULONG CreateDisposition,
+  IN ULONG CreateOptions,
+  IN PVOID EaBuffer OPTIONAL,
+  IN ULONG EaLength);
+
+typedef NTSTATUS (WINAPI *NtOpenFileFunction)(
+  OUT PHANDLE FileHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PIO_STATUS_BLOCK IoStatusBlock,
+  IN ULONG ShareAccess,
+  IN ULONG OpenOptions);
+
+typedef NTSTATUS (WINAPI *NtCloseFunction)(
+  IN HANDLE Handle);
+
+typedef enum _FILE_INFORMATION_CLASS {
+  FileRenameInformation = 10
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_RENAME_INFORMATION {
+  BOOLEAN ReplaceIfExists;
+  HANDLE RootDirectory;
+  ULONG FileNameLength;
+  WCHAR FileName[1];
+} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtSetInformationFileFunction)(
+  IN HANDLE FileHandle,
+  OUT PIO_STATUS_BLOCK IoStatusBlock,
+  IN PVOID FileInformation,
+  IN ULONG Length,
+  IN FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef struct FILE_BASIC_INFORMATION {
+  LARGE_INTEGER CreationTime;
+  LARGE_INTEGER LastAccessTime;
+  LARGE_INTEGER LastWriteTime;
+  LARGE_INTEGER ChangeTime;
+  ULONG FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryAttributesFileFunction)(
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PFILE_BASIC_INFORMATION FileAttributes);
+
+typedef struct _FILE_NETWORK_OPEN_INFORMATION {
+  LARGE_INTEGER CreationTime;
+  LARGE_INTEGER LastAccessTime;
+  LARGE_INTEGER LastWriteTime;
+  LARGE_INTEGER ChangeTime;
+  LARGE_INTEGER AllocationSize;
+  LARGE_INTEGER EndOfFile;
+  ULONG FileAttributes;
+} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryFullAttributesFileFunction)(
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PFILE_NETWORK_OPEN_INFORMATION FileAttributes);
+
+// -----------------------------------------------------------------------
+// Sections
+
+typedef NTSTATUS (WINAPI *NtCreateSectionFunction)(
+  OUT PHANDLE SectionHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+  IN PLARGE_INTEGER MaximumSize OPTIONAL,
+  IN ULONG SectionPageProtection,
+  IN ULONG AllocationAttributes,
+  IN HANDLE FileHandle OPTIONAL);
+
+typedef ULONG SECTION_INHERIT;
+#define ViewShare 1
+#define ViewUnmap 2
+
+typedef NTSTATUS (WINAPI *NtMapViewOfSectionFunction)(
+  IN HANDLE SectionHandle,
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID *BaseAddress,
+  IN ULONG_PTR ZeroBits,
+  IN SIZE_T CommitSize,
+  IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+  IN OUT PSIZE_T ViewSize,
+  IN SECTION_INHERIT InheritDisposition,
+  IN ULONG AllocationType,
+  IN ULONG Win32Protect);
+
+typedef NTSTATUS (WINAPI *NtUnmapViewOfSectionFunction)(
+  IN HANDLE ProcessHandle,
+  IN PVOID BaseAddress);
+
+typedef enum _SECTION_INFORMATION_CLASS {
+  SectionBasicInformation = 0,
+  SectionImageInformation
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+  PVOID BaseAddress;
+  ULONG Attributes;
+  LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQuerySectionFunction)(
+  IN HANDLE SectionHandle,
+  IN SECTION_INFORMATION_CLASS SectionInformationClass,
+  OUT PVOID SectionInformation,
+  IN SIZE_T SectionInformationLength,
+  OUT PSIZE_T ReturnLength OPTIONAL);
+
+// -----------------------------------------------------------------------
+// Process and Thread
+
+typedef struct _CLIENT_ID {
+  PVOID UniqueProcess;
+  PVOID UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+
+typedef NTSTATUS (WINAPI *NtOpenThreadFunction) (
+  OUT PHANDLE ThreadHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN PCLIENT_ID ClientId);
+
+typedef NTSTATUS (WINAPI *NtOpenProcessFunction) (
+  OUT PHANDLE ProcessHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN PCLIENT_ID ClientId);
+
+typedef enum _NT_THREAD_INFORMATION_CLASS {
+  ThreadBasicInformation,
+  ThreadTimes,
+  ThreadPriority,
+  ThreadBasePriority,
+  ThreadAffinityMask,
+  ThreadImpersonationToken,
+  ThreadDescriptorTableEntry,
+  ThreadEnableAlignmentFaultFixup,
+  ThreadEventPair,
+  ThreadQuerySetWin32StartAddress,
+  ThreadZeroTlsCell,
+  ThreadPerformanceCount,
+  ThreadAmILastThread,
+  ThreadIdealProcessor,
+  ThreadPriorityBoost,
+  ThreadSetTlsArrayAddress,
+  ThreadIsIoPending,
+  ThreadHideFromDebugger
+} NT_THREAD_INFORMATION_CLASS, *PNT_THREAD_INFORMATION_CLASS;
+
+typedef NTSTATUS (WINAPI *NtSetInformationThreadFunction) (
+  IN HANDLE ThreadHandle,
+  IN NT_THREAD_INFORMATION_CLASS ThreadInformationClass,
+  IN PVOID ThreadInformation,
+  IN ULONG ThreadInformationLength);
+
+// Partial definition only:
+typedef enum _PROCESSINFOCLASS {
+  ProcessBasicInformation = 0,
+  ProcessExecuteFlags = 0x22
+} PROCESSINFOCLASS;
+
+typedef PVOID PPEB;
+typedef PVOID KPRIORITY;
+
+typedef struct _PROCESS_BASIC_INFORMATION {
+  NTSTATUS ExitStatus;
+  PPEB PebBaseAddress;
+  KAFFINITY AffinityMask;
+  KPRIORITY BasePriority;
+  ULONG UniqueProcessId;
+  ULONG InheritedFromUniqueProcessId;
+} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)(
+  IN HANDLE ProcessHandle,
+  IN PROCESSINFOCLASS ProcessInformationClass,
+  OUT PVOID ProcessInformation,
+  IN ULONG ProcessInformationLength,
+  OUT PULONG ReturnLength OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtSetInformationProcessFunction)(
+  HANDLE ProcessHandle,
+  IN PROCESSINFOCLASS ProcessInformationClass,
+  IN PVOID ProcessInformation,
+  IN ULONG ProcessInformationLength);
+
+typedef NTSTATUS (WINAPI *NtOpenThreadTokenFunction) (
+  IN HANDLE ThreadHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN BOOLEAN OpenAsSelf,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI *NtOpenThreadTokenExFunction) (
+  IN HANDLE ThreadHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN BOOLEAN OpenAsSelf,
+  IN ULONG HandleAttributes,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI *NtOpenProcessTokenFunction) (
+  IN HANDLE ProcessHandle,
+  IN ACCESS_MASK DesiredAccess,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI *NtOpenProcessTokenExFunction) (
+  IN HANDLE ProcessHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN ULONG HandleAttributes,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI * RtlCreateUserThreadFunction)(
+  IN HANDLE Process,
+  IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
+  IN BOOLEAN CreateSuspended,
+  IN ULONG ZeroBits,
+  IN SIZE_T MaximumStackSize,
+  IN SIZE_T CommittedStackSize,
+  IN LPTHREAD_START_ROUTINE StartAddress,
+  IN PVOID Parameter,
+  OUT PHANDLE Thread,
+  OUT PCLIENT_ID ClientId);
+
+// -----------------------------------------------------------------------
+// Registry
+
+typedef NTSTATUS (WINAPI *NtCreateKeyFunction)(
+  OUT PHANDLE KeyHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN ULONG TitleIndex,
+  IN PUNICODE_STRING Class OPTIONAL,
+  IN ULONG CreateOptions,
+  OUT PULONG Disposition OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtOpenKeyFunction)(
+  OUT PHANDLE KeyHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI *NtOpenKeyExFunction)(
+  OUT PHANDLE KeyHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN DWORD open_options);
+
+typedef NTSTATUS (WINAPI *NtDeleteKeyFunction)(
+  IN HANDLE KeyHandle);
+
+// -----------------------------------------------------------------------
+// Memory
+
+// Don't really need this structure right now.
+typedef PVOID PRTL_HEAP_PARAMETERS;
+
+typedef PVOID (WINAPI *RtlCreateHeapFunction)(
+  IN ULONG Flags,
+  IN PVOID HeapBase OPTIONAL,
+  IN SIZE_T ReserveSize OPTIONAL,
+  IN SIZE_T CommitSize OPTIONAL,
+  IN PVOID Lock OPTIONAL,
+  IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL);
+
+typedef PVOID (WINAPI *RtlDestroyHeapFunction)(
+  IN PVOID HeapHandle);
+
+typedef PVOID (WINAPI *RtlAllocateHeapFunction)(
+  IN PVOID HeapHandle,
+  IN ULONG Flags,
+  IN SIZE_T Size);
+
+typedef BOOLEAN (WINAPI *RtlFreeHeapFunction)(
+  IN PVOID HeapHandle,
+  IN ULONG Flags,
+  IN PVOID HeapBase);
+
+typedef NTSTATUS (WINAPI *NtAllocateVirtualMemoryFunction) (
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID *BaseAddress,
+  IN ULONG_PTR ZeroBits,
+  IN OUT PSIZE_T RegionSize,
+  IN ULONG AllocationType,
+  IN ULONG Protect);
+
+typedef NTSTATUS (WINAPI *NtFreeVirtualMemoryFunction) (
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID *BaseAddress,
+  IN OUT PSIZE_T RegionSize,
+  IN ULONG FreeType);
+
+typedef enum _MEMORY_INFORMATION_CLASS {
+  MemoryBasicInformation = 0,
+  MemoryWorkingSetList,
+  MemorySectionName,
+  MemoryBasicVlmInformation
+} MEMORY_INFORMATION_CLASS;
+
+typedef struct _MEMORY_SECTION_NAME {  // Information Class 2
+  UNICODE_STRING SectionFileName;
+} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
+
+typedef NTSTATUS (WINAPI *NtQueryVirtualMemoryFunction)(
+  IN HANDLE ProcessHandle,
+  IN PVOID BaseAddress,
+  IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
+  OUT PVOID MemoryInformation,
+  IN SIZE_T MemoryInformationLength,
+  OUT PSIZE_T ReturnLength OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtProtectVirtualMemoryFunction)(
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID* BaseAddress,
+  IN OUT PSIZE_T ProtectSize,
+  IN ULONG NewProtect,
+  OUT PULONG OldProtect);
+
+// -----------------------------------------------------------------------
+// Objects
+
+typedef enum _OBJECT_INFORMATION_CLASS {
+  ObjectBasicInformation,
+  ObjectNameInformation,
+  ObjectTypeInformation,
+  ObjectAllInformation,
+  ObjectDataInformation
+} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
+
+typedef struct _OBJDIR_INFORMATION {
+  UNICODE_STRING ObjectName;
+  UNICODE_STRING ObjectTypeName;
+  BYTE Data[1];
+} OBJDIR_INFORMATION;
+
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+  ULONG Attributes;
+  ACCESS_MASK GrantedAccess;
+  ULONG HandleCount;
+  ULONG PointerCount;
+  ULONG Reserved[10];    // reserved for internal use
+} PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING TypeName;
+  ULONG Reserved[22];    // reserved for internal use
+} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+typedef enum _POOL_TYPE {
+  NonPagedPool,
+  PagedPool,
+  NonPagedPoolMustSucceed,
+  ReservedType,
+  NonPagedPoolCacheAligned,
+  PagedPoolCacheAligned,
+  NonPagedPoolCacheAlignedMustS
+} POOL_TYPE;
+
+typedef struct _OBJECT_BASIC_INFORMATION {
+  ULONG Attributes;
+  ACCESS_MASK GrantedAccess;
+  ULONG HandleCount;
+  ULONG PointerCount;
+  ULONG PagedPoolUsage;
+  ULONG NonPagedPoolUsage;
+  ULONG Reserved[3];
+  ULONG NameInformationLength;
+  ULONG TypeInformationLength;
+  ULONG SecurityDescriptorLength;
+  LARGE_INTEGER CreateTime;
+} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
+
+typedef struct _OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING Name;
+  ULONG TotalNumberOfObjects;
+  ULONG TotalNumberOfHandles;
+  ULONG TotalPagedPoolUsage;
+  ULONG TotalNonPagedPoolUsage;
+  ULONG TotalNamePoolUsage;
+  ULONG TotalHandleTableUsage;
+  ULONG HighWaterNumberOfObjects;
+  ULONG HighWaterNumberOfHandles;
+  ULONG HighWaterPagedPoolUsage;
+  ULONG HighWaterNonPagedPoolUsage;
+  ULONG HighWaterNamePoolUsage;
+  ULONG HighWaterHandleTableUsage;
+  ULONG InvalidAttributes;
+  GENERIC_MAPPING GenericMapping;
+  ULONG ValidAccess;
+  BOOLEAN SecurityRequired;
+  BOOLEAN MaintainHandleCount;
+  USHORT MaintainTypeList;
+  POOL_TYPE PoolType;
+  ULONG PagedPoolUsage;
+  ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+  SystemHandleInformation = 16
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION {
+  USHORT ProcessId;
+  USHORT CreatorBackTraceIndex;
+  UCHAR ObjectTypeNumber;
+  UCHAR Flags;
+  USHORT Handle;
+  PVOID Object;
+  ACCESS_MASK GrantedAccess;
+} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+  ULONG NumberOfHandles;
+  SYSTEM_HANDLE_INFORMATION Information[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+typedef struct _OBJECT_NAME_INFORMATION {
+  UNICODE_STRING ObjectName;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryObjectFunction)(
+  IN HANDLE Handle,
+  IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+  OUT PVOID ObjectInformation OPTIONAL,
+  IN ULONG ObjectInformationLength,
+  OUT PULONG ReturnLength OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtDuplicateObjectFunction)(
+  IN HANDLE SourceProcess,
+  IN HANDLE SourceHandle,
+  IN HANDLE TargetProcess,
+  OUT PHANDLE TargetHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN ULONG Attributes,
+  IN ULONG Options);
+
+typedef NTSTATUS (WINAPI *NtSignalAndWaitForSingleObjectFunction)(
+  IN HANDLE HandleToSignal,
+  IN HANDLE HandleToWait,
+  IN BOOLEAN Alertable,
+  IN PLARGE_INTEGER Timeout OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtQuerySystemInformation)(
+  IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
+  OUT PVOID SystemInformation,
+  IN ULONG SystemInformationLength,
+  OUT PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI *NtQueryObject)(
+  IN HANDLE Handle,
+  IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+  OUT PVOID ObjectInformation,
+  IN ULONG ObjectInformationLength,
+  OUT PULONG ReturnLength);
+
+// -----------------------------------------------------------------------
+// Strings
+
+typedef int (__cdecl *_strnicmpFunction)(
+  IN const char* _Str1,
+  IN const char* _Str2,
+  IN size_t _MaxCount);
+
+typedef size_t  (__cdecl *strlenFunction)(
+  IN const char * _Str);
+
+typedef size_t (__cdecl *wcslenFunction)(
+  IN const wchar_t* _Str);
+
+typedef void* (__cdecl *memcpyFunction)(
+  IN void* dest,
+  IN const void* src,
+  IN size_t count);
+
+typedef NTSTATUS (WINAPI *RtlAnsiStringToUnicodeStringFunction)(
+  IN OUT PUNICODE_STRING  DestinationString,
+  IN PANSI_STRING  SourceString,
+  IN BOOLEAN  AllocateDestinationString);
+
+typedef LONG (WINAPI *RtlCompareUnicodeStringFunction)(
+  IN PCUNICODE_STRING  String1,
+  IN PCUNICODE_STRING  String2,
+  IN BOOLEAN  CaseInSensitive);
+
+typedef VOID (WINAPI *RtlInitUnicodeStringFunction) (
+  IN OUT PUNICODE_STRING DestinationString,
+  IN PCWSTR SourceString);
+
+typedef enum _EVENT_TYPE {
+  NotificationEvent,
+  SynchronizationEvent
+} EVENT_TYPE, *PEVENT_TYPE;
+
+typedef NTSTATUS (WINAPI* NtOpenDirectoryObjectFunction) (
+    PHANDLE DirectoryHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NtQuerySymbolicLinkObjectFunction) (
+    HANDLE LinkHandle,
+    PUNICODE_STRING LinkTarget,
+    PULONG ReturnedLength);
+
+typedef NTSTATUS (WINAPI* NtOpenSymbolicLinkObjectFunction) (
+    PHANDLE LinkHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+#define DIRECTORY_QUERY               0x0001
+#define DIRECTORY_TRAVERSE            0x0002
+#define DIRECTORY_CREATE_OBJECT       0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+#define DIRECTORY_ALL_ACCESS          0x000F
+
+typedef NTSTATUS (WINAPI* NtCreateLowBoxToken)(
+    OUT PHANDLE token,
+    IN HANDLE original_handle,
+    IN ACCESS_MASK access,
+    IN POBJECT_ATTRIBUTES object_attribute,
+    IN PSID appcontainer_sid,
+    IN DWORD capabilityCount,
+    IN PSID_AND_ATTRIBUTES capabilities,
+    IN DWORD handle_count,
+    IN PHANDLE handles);
+
+typedef NTSTATUS(WINAPI *NtSetInformationProcess)(
+    IN HANDLE process_handle,
+    IN ULONG info_class,
+    IN PVOID process_information,
+    IN ULONG information_length);
+
+struct PROCESS_ACCESS_TOKEN {
+  HANDLE token;
+  HANDLE thread;
+};
+
+const unsigned int NtProcessInformationAccessToken = 9;
+
+#endif  // SANDBOX_WIN_SRC_NT_INTERNALS_H__
+
diff --git a/sandbox/win/src/policy_broker.cc b/sandbox/win/src/policy_broker.cc
new file mode 100644
index 0000000..dc5e18c
--- /dev/null
+++ b/sandbox/win/src/policy_broker.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+
+#include "sandbox/win/src/policy_broker.h"
+
+#include "base/logging.h"
+#include "base/win/pe_image.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/target_process.h"
+
+// This code executes on the broker side, as a callback from the policy on the
+// target side (the child).
+
+namespace sandbox {
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+#define INIT_GLOBAL_NT(member) \
+  g_nt.member = reinterpret_cast<Nt##member##Function>( \
+                      ntdll_image.GetProcAddress("Nt" #member)); \
+  if (NULL == g_nt.member) \
+    return false
+
+#define INIT_GLOBAL_RTL(member) \
+  g_nt.member = reinterpret_cast<member##Function>( \
+                      ntdll_image.GetProcAddress(#member)); \
+  if (NULL == g_nt.member) \
+    return false
+
+bool SetupNtdllImports(TargetProcess *child) {
+  HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+  base::win::PEImage ntdll_image(ntdll);
+
+  // Bypass purify's interception.
+  wchar_t* loader_get = reinterpret_cast<wchar_t*>(
+                            ntdll_image.GetProcAddress("LdrGetDllHandle"));
+  if (loader_get) {
+    GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                          GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                      loader_get, &ntdll);
+  }
+
+  INIT_GLOBAL_NT(AllocateVirtualMemory);
+  INIT_GLOBAL_NT(Close);
+  INIT_GLOBAL_NT(DuplicateObject);
+  INIT_GLOBAL_NT(FreeVirtualMemory);
+  INIT_GLOBAL_NT(MapViewOfSection);
+  INIT_GLOBAL_NT(ProtectVirtualMemory);
+  INIT_GLOBAL_NT(QueryInformationProcess);
+  INIT_GLOBAL_NT(QueryObject);
+  INIT_GLOBAL_NT(QuerySection);
+  INIT_GLOBAL_NT(QueryVirtualMemory);
+  INIT_GLOBAL_NT(UnmapViewOfSection);
+
+  INIT_GLOBAL_RTL(RtlAllocateHeap);
+  INIT_GLOBAL_RTL(RtlAnsiStringToUnicodeString);
+  INIT_GLOBAL_RTL(RtlCompareUnicodeString);
+  INIT_GLOBAL_RTL(RtlCreateHeap);
+  INIT_GLOBAL_RTL(RtlCreateUserThread);
+  INIT_GLOBAL_RTL(RtlDestroyHeap);
+  INIT_GLOBAL_RTL(RtlFreeHeap);
+  INIT_GLOBAL_RTL(_strnicmp);
+  INIT_GLOBAL_RTL(strlen);
+  INIT_GLOBAL_RTL(wcslen);
+  INIT_GLOBAL_RTL(memcpy);
+
+#ifndef NDEBUG
+  // Verify that the structure is fully initialized.
+  for (size_t i = 0; i < sizeof(g_nt)/sizeof(void*); i++)
+    DCHECK(reinterpret_cast<char**>(&g_nt)[i]);
+#endif
+  return (SBOX_ALL_OK == child->TransferVariable("g_nt", &g_nt, sizeof(g_nt)));
+}
+
+#undef INIT_GLOBAL_NT
+#undef INIT_GLOBAL_RTL
+
+bool SetupBasicInterceptions(InterceptionManager* manager) {
+  // Interceptions provided by process_thread_policy, without actual policy.
+  if (!INTERCEPT_NT(manager, NtOpenThread, OPEN_TREAD_ID, 20) ||
+      !INTERCEPT_NT(manager, NtOpenProcess, OPEN_PROCESS_ID, 20) ||
+      !INTERCEPT_NT(manager, NtOpenProcessToken, OPEN_PROCESS_TOKEN_ID, 16))
+    return false;
+
+  // Interceptions with neither policy nor IPC.
+  if (!INTERCEPT_NT(manager, NtSetInformationThread, SET_INFORMATION_THREAD_ID,
+                    20) ||
+      !INTERCEPT_NT(manager, NtOpenThreadToken, OPEN_THREAD_TOKEN_ID, 20))
+    return false;
+
+  if (base::win::GetVersion() >= base::win::VERSION_XP) {
+    // Bug 27218: We don't have dispatch for some x64 syscalls.
+    // This one is also provided by process_thread_policy.
+    if (!INTERCEPT_NT(manager, NtOpenProcessTokenEx, OPEN_PROCESS_TOKEN_EX_ID,
+                      20))
+      return false;
+
+    return INTERCEPT_NT(manager, NtOpenThreadTokenEx, OPEN_THREAD_TOKEN_EX_ID,
+                        24);
+  }
+
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_broker.h b/sandbox/win/src/policy_broker.h
new file mode 100644
index 0000000..1c5cc26
--- /dev/null
+++ b/sandbox/win/src/policy_broker.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_BROKER_H_
+#define SANDBOX_SRC_POLICY_BROKER_H_
+
+#include "sandbox/win/src/interception.h"
+
+namespace sandbox {
+
+class TargetProcess;
+
+// Sets up interceptions not controlled by explicit policies.
+bool SetupBasicInterceptions(InterceptionManager* manager);
+
+// Sets up imports from NTDLL for the given target process so the interceptions
+// can work.
+bool SetupNtdllImports(TargetProcess *child);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_BROKER_H_
diff --git a/sandbox/win/src/policy_engine_opcodes.cc b/sandbox/win/src/policy_engine_opcodes.cc
new file mode 100644
index 0000000..24ba119
--- /dev/null
+++ b/sandbox/win/src/policy_engine_opcodes.cc
@@ -0,0 +1,454 @@
+// 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 "sandbox/win/src/policy_engine_opcodes.h"
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace {
+const unsigned short kMaxUniStrSize = 0xfffc;
+
+bool InitStringUnicode(const wchar_t* source, size_t length,
+                       UNICODE_STRING* ustring) {
+  ustring->Buffer = const_cast<wchar_t*>(source);
+  ustring->Length = static_cast<USHORT>(length) * sizeof(wchar_t);
+  if (length > kMaxUniStrSize) {
+      return false;
+  }
+  ustring->MaximumLength = (NULL != source) ?
+                                ustring->Length + sizeof(wchar_t) : 0;
+  return true;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Note: The opcodes are implemented as functions (as opposed to classes derived
+// from PolicyOpcode) because you should not add more member variables to the
+// PolicyOpcode class since it would cause object slicing on the target. So to
+// enforce that (instead of just trusting the developer) the opcodes became
+// just functions.
+//
+// In the code that follows I have keep the evaluation function and the factory
+// function together to stress the close relationship between both. For example,
+// only the factory method and the evaluation function know the stored argument
+// order and meaning.
+
+template <int>
+EvalResult OpcodeEval(PolicyOpcode* opcode, const ParameterSet* pp,
+                      MatchContext* match);
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpAlwaysFalse:
+// Does not require input parameter.
+
+PolicyOpcode* OpcodeFactory::MakeOpAlwaysFalse(uint32 options) {
+  return MakeBase(OP_ALWAYS_FALSE, options, -1);
+}
+
+template <>
+EvalResult OpcodeEval<OP_ALWAYS_FALSE>(PolicyOpcode* opcode,
+                                       const ParameterSet* param,
+                                       MatchContext* context) {
+  UNREFERENCED_PARAMETER(opcode);
+  UNREFERENCED_PARAMETER(param);
+  UNREFERENCED_PARAMETER(context);
+  return EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpAlwaysTrue:
+// Does not require input parameter.
+
+PolicyOpcode* OpcodeFactory::MakeOpAlwaysTrue(uint32 options) {
+  return MakeBase(OP_ALWAYS_TRUE, options, -1);
+}
+
+template <>
+EvalResult OpcodeEval<OP_ALWAYS_TRUE>(PolicyOpcode* opcode,
+                                      const ParameterSet* param,
+                                      MatchContext* context) {
+  UNREFERENCED_PARAMETER(opcode);
+  UNREFERENCED_PARAMETER(param);
+  UNREFERENCED_PARAMETER(context);
+  return EVAL_TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpAction:
+// Does not require input parameter.
+// Argument 0 contains the actual action to return.
+
+PolicyOpcode* OpcodeFactory::MakeOpAction(EvalResult action,
+                                          uint32 options) {
+  PolicyOpcode* opcode = MakeBase(OP_ACTION, options, 0);
+  if (NULL == opcode) return NULL;
+  opcode->SetArgument(0, action);
+  return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_ACTION>(PolicyOpcode* opcode,
+                                 const ParameterSet* param,
+                                 MatchContext* context) {
+  UNREFERENCED_PARAMETER(param);
+  UNREFERENCED_PARAMETER(context);
+  int action = 0;
+  opcode->GetArgument(0, &action);
+  return static_cast<EvalResult>(action);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpNumberMatch:
+// Requires a uint32 or void* in selected_param
+// Argument 0 is the stored number to match.
+// Argument 1 is the C++ type of the 0th argument.
+
+PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(int16 selected_param,
+                                               uint32 match,
+                                               uint32 options) {
+  PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
+  if (NULL == opcode) return NULL;
+  opcode->SetArgument(0, match);
+  opcode->SetArgument(1, UINT32_TYPE);
+  return opcode;
+}
+
+PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(int16 selected_param,
+                                                const void* match,
+                                                uint32 options) {
+  PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
+  if (NULL == opcode) return NULL;
+  opcode->SetArgument(0, match);
+  opcode->SetArgument(1, VOIDPTR_TYPE);
+  return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_NUMBER_MATCH>(PolicyOpcode* opcode,
+                                       const ParameterSet* param,
+                                       MatchContext* context) {
+  UNREFERENCED_PARAMETER(context);
+  uint32 value_uint32 = 0;
+  if (param->Get(&value_uint32)) {
+    uint32 match_uint32 = 0;
+    opcode->GetArgument(0, &match_uint32);
+    return (match_uint32 != value_uint32)? EVAL_FALSE : EVAL_TRUE;
+  } else {
+    const void* value_ptr = NULL;
+    if (param->Get(&value_ptr)) {
+      const void* match_ptr = NULL;
+      opcode->GetArgument(0, &match_ptr);
+      return (match_ptr != value_ptr)? EVAL_FALSE : EVAL_TRUE;
+    }
+  }
+  return EVAL_ERROR;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpNumberMatchRange
+// Requires a uint32 in selected_param.
+// Argument 0 is the stored lower bound to match.
+// Argument 1 is the stored upper bound to match.
+
+PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(int16 selected_param,
+                                                    uint32 lower_bound,
+                                                    uint32 upper_bound,
+                                                    uint32 options) {
+  if (lower_bound > upper_bound) {
+    return NULL;
+  }
+  PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH_RANGE, options,
+                                  selected_param);
+  if (NULL == opcode) return NULL;
+  opcode->SetArgument(0, lower_bound);
+  opcode->SetArgument(1, upper_bound);
+  return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_NUMBER_MATCH_RANGE>(PolicyOpcode* opcode,
+                                             const ParameterSet* param,
+                                             MatchContext* context) {
+  UNREFERENCED_PARAMETER(context);
+  uint32 value = 0;
+  if (!param->Get(&value)) return EVAL_ERROR;
+
+  uint32 lower_bound = 0;
+  uint32 upper_bound = 0;
+  opcode->GetArgument(0, &lower_bound);
+  opcode->GetArgument(1, &upper_bound);
+  return((lower_bound <= value) && (upper_bound >= value))?
+    EVAL_TRUE : EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpNumberAndMatch:
+// Requires a uint32 in selected_param.
+// Argument 0 is the stored number to match.
+
+PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(int16 selected_param,
+                                                  uint32 match,
+                                                  uint32 options) {
+  PolicyOpcode* opcode = MakeBase(OP_NUMBER_AND_MATCH, options, selected_param);
+  if (NULL == opcode) return NULL;
+  opcode->SetArgument(0, match);
+  return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_NUMBER_AND_MATCH>(PolicyOpcode* opcode,
+                                           const ParameterSet* param,
+                                           MatchContext* context) {
+  UNREFERENCED_PARAMETER(context);
+  uint32 value = 0;
+  if (!param->Get(&value)) return EVAL_ERROR;
+
+  uint32 number = 0;
+  opcode->GetArgument(0, &number);
+  return (number & value)? EVAL_TRUE : EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpWStringMatch:
+// Requires a wchar_t* in selected_param.
+// Argument 0 is the byte displacement of the stored string.
+// Argument 1 is the lenght in chars of the stored string.
+// Argument 2 is the offset to apply on the input string. It has special values.
+// as noted in the header file.
+// Argument 3 is the string matching options.
+
+PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(int16 selected_param,
+                                                const wchar_t* match_str,
+                                                int start_position,
+                                                StringMatchOptions match_opts,
+                                                uint32 options) {
+  if (NULL == match_str) {
+    return NULL;
+  }
+  if ('\0' == match_str[0]) {
+    return NULL;
+  }
+
+  int lenght = lstrlenW(match_str);
+
+  PolicyOpcode* opcode = MakeBase(OP_WSTRING_MATCH, options, selected_param);
+  if (NULL == opcode) {
+    return NULL;
+  }
+  ptrdiff_t delta_str = AllocRelative(opcode, match_str, wcslen(match_str)+1);
+  if (0 == delta_str) {
+    return NULL;
+  }
+  opcode->SetArgument(0, delta_str);
+  opcode->SetArgument(1, lenght);
+  opcode->SetArgument(2, start_position);
+  opcode->SetArgument(3, match_opts);
+  return opcode;
+}
+
+template<>
+EvalResult OpcodeEval<OP_WSTRING_MATCH>(PolicyOpcode* opcode,
+                                        const ParameterSet* param,
+                                        MatchContext* context) {
+  if (NULL == context) {
+    return EVAL_ERROR;
+  }
+  const wchar_t* source_str = NULL;
+  if (!param->Get(&source_str)) return EVAL_ERROR;
+
+  int start_position = 0;
+  int match_len = 0;
+  unsigned int match_opts = 0;
+  opcode->GetArgument(1, &match_len);
+  opcode->GetArgument(2, &start_position);
+  opcode->GetArgument(3, &match_opts);
+
+  const wchar_t* match_str = opcode->GetRelativeString(0);
+  // Advance the source string to the last successfully evaluated position
+  // according to the match context.
+  source_str = &source_str[context->position];
+  int source_len  = static_cast<int>(g_nt.wcslen(source_str));
+
+  if (0 == source_len) {
+    // If we reached the end of the source string there is nothing we can
+    // match against.
+    return EVAL_FALSE;
+  }
+  if (match_len > source_len) {
+    // There can't be a positive match when the target string is bigger than
+    // the source string
+    return EVAL_FALSE;
+  }
+
+  BOOLEAN case_sensitive = (match_opts & CASE_INSENSITIVE) ? TRUE : FALSE;
+
+  // We have three cases, depending on the value of start_pos:
+  // Case 1. We skip N characters and compare once.
+  // Case 2: We skip to the end and compare once.
+  // Case 3: We match the first substring (if we find any).
+  if (start_position >= 0) {
+    if (kSeekToEnd == start_position) {
+        start_position = source_len - match_len;
+    } else if (match_opts & EXACT_LENGHT) {
+        // A sub-case of case 3 is when the EXACT_LENGHT flag is on
+        // the match needs to be not just substring but full match.
+        if ((match_len + start_position) != source_len) {
+          return EVAL_FALSE;
+        }
+    }
+
+    // Advance start_pos characters. Warning! this does not consider
+    // utf16 encodings (surrogate pairs) or other Unicode 'features'.
+    source_str += start_position;
+
+    // Since we skipped, lets reevaluate just the lengths again.
+    if ((match_len + start_position) > source_len) {
+      return EVAL_FALSE;
+    }
+
+    UNICODE_STRING match_ustr;
+    InitStringUnicode(match_str, match_len, &match_ustr);
+    UNICODE_STRING source_ustr;
+    InitStringUnicode(source_str, match_len, &source_ustr);
+
+    if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
+                                          case_sensitive)) {
+      // Match! update the match context.
+      context->position += start_position + match_len;
+      return EVAL_TRUE;
+    } else {
+      return EVAL_FALSE;
+    }
+  } else if (start_position < 0) {
+    UNICODE_STRING match_ustr;
+    InitStringUnicode(match_str, match_len, &match_ustr);
+    UNICODE_STRING source_ustr;
+    InitStringUnicode(source_str, match_len, &source_ustr);
+
+    do {
+      if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
+                                            case_sensitive)) {
+        // Match! update the match context.
+        context->position += (source_ustr.Buffer - source_str) + match_len;
+        return EVAL_TRUE;
+      }
+      ++source_ustr.Buffer;
+      --source_len;
+    } while (source_len >= match_len);
+  }
+  return EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// OpcodeMaker (other member functions).
+
+PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id,
+                                      uint32 options,
+                                      int16 selected_param) {
+  if (memory_size() < sizeof(PolicyOpcode)) {
+    return NULL;
+  }
+
+  // Create opcode using placement-new on the buffer memory.
+  PolicyOpcode* opcode = new(memory_top_) PolicyOpcode();
+
+  // Fill in the standard fields, that every opcode has.
+  memory_top_ += sizeof(PolicyOpcode);
+  opcode->opcode_id_ = opcode_id;
+  opcode->SetOptions(options);
+  opcode->parameter_ = selected_param;
+  return opcode;
+}
+
+ptrdiff_t OpcodeFactory::AllocRelative(void* start, const wchar_t* str,
+                                       size_t lenght) {
+  size_t bytes = lenght * sizeof(wchar_t);
+  if (memory_size() < bytes) {
+    return 0;
+  }
+  memory_bottom_ -= bytes;
+  if (reinterpret_cast<UINT_PTR>(memory_bottom_) & 1) {
+    // TODO(cpu) replace this for something better.
+    ::DebugBreak();
+  }
+  memcpy(memory_bottom_, str, bytes);
+  ptrdiff_t delta = memory_bottom_ - reinterpret_cast<char*>(start);
+  return delta;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode evaluation dispatchers.
+
+// This function is the one and only entry for evaluating any opcode. It is
+// in charge of applying any relevant opcode options and calling EvaluateInner
+// were the actual dispatch-by-id is made. It would seem at first glance that
+// the dispatch should be done by virtual function (vtable) calls but you have
+// to remember that the opcodes are made in the broker process and copied as
+// raw memory to the target process.
+
+EvalResult PolicyOpcode::Evaluate(const ParameterSet* call_params,
+                                  size_t param_count, MatchContext* match) {
+  if (NULL == call_params) {
+    return EVAL_ERROR;
+  }
+  const ParameterSet* selected_param = NULL;
+  if (parameter_ >= 0) {
+    if (static_cast<size_t>(parameter_) >= param_count) {
+      return EVAL_ERROR;
+    }
+    selected_param = &call_params[parameter_];
+  }
+  EvalResult result = EvaluateHelper(selected_param, match);
+
+  // Apply the general options regardless of the particular type of opcode.
+  if (kPolNone == options_) {
+    return result;
+  }
+
+  if (options_ & kPolNegateEval) {
+    if (EVAL_TRUE == result) {
+      result = EVAL_FALSE;
+    } else if (EVAL_FALSE == result) {
+      result = EVAL_TRUE;
+    } else if (EVAL_ERROR != result) {
+      result = EVAL_ERROR;
+    }
+  }
+  if (NULL != match) {
+    if (options_ & kPolClearContext) {
+      match->Clear();
+    }
+    if (options_ & kPolUseOREval) {
+      match->options = kPolUseOREval;
+    }
+  }
+  return result;
+}
+
+#define OPCODE_EVAL(op, x, y, z) case op: return OpcodeEval<op>(x, y, z)
+
+EvalResult PolicyOpcode::EvaluateHelper(const ParameterSet* parameters,
+                                       MatchContext* match) {
+  switch (opcode_id_) {
+    OPCODE_EVAL(OP_ALWAYS_FALSE, this, parameters, match);
+    OPCODE_EVAL(OP_ALWAYS_TRUE, this, parameters, match);
+    OPCODE_EVAL(OP_NUMBER_MATCH, this, parameters, match);
+    OPCODE_EVAL(OP_NUMBER_MATCH_RANGE, this, parameters, match);
+    OPCODE_EVAL(OP_NUMBER_AND_MATCH, this, parameters, match);
+    OPCODE_EVAL(OP_WSTRING_MATCH, this, parameters, match);
+    OPCODE_EVAL(OP_ACTION, this, parameters, match);
+    default:
+      return EVAL_ERROR;
+  }
+}
+
+#undef OPCODE_EVAL
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_engine_opcodes.h b/sandbox/win/src/policy_engine_opcodes.h
new file mode 100644
index 0000000..17d1764
--- /dev/null
+++ b/sandbox/win/src/policy_engine_opcodes.h
@@ -0,0 +1,386 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
+#define SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
+
+#include "base/basictypes.h"
+#include "base/numerics/safe_conversions.h"
+#include "sandbox/win/src/policy_engine_params.h"
+
+// The low-level policy is implemented using the concept of policy 'opcodes'.
+// An opcode is a structure that contains enough information to perform one
+// comparison against one single input parameter. For example, an opcode can
+// encode just one of the following comparison:
+//
+// - Is input parameter 3 not equal to NULL?
+// - Does input parameter 2 start with L"c:\\"?
+// - Is input parameter 5, bit 3 is equal 1?
+//
+// Each opcode is in fact equivalent to a function invocation where all
+// the parameters are known by the opcode except one. So say you have a
+// function of this form:
+//      bool fn(a, b, c, d)  with 4 arguments
+//
+// Then an opcode is:
+//      op(fn, b, c, d)
+// Which stores the function to call and its 3 last arguments
+//
+// Then and opcode evaluation is:
+//      op.eval(a)  ------------------------> fn(a,b,c,d)
+//                        internally calls
+//
+// The idea is that complex policy rules can be split into streams of
+// opcodes which are evaluated in sequence. The evaluation is done in
+// groups of opcodes that have N comparison opcodes plus 1 action opcode:
+//
+// [comparison 1][comparison 2]...[comparison N][action][comparison 1]...
+//    ----- evaluation order----------->
+//
+// Each opcode group encodes one high-level policy rule. The rule applies
+// only if all the conditions on the group evaluate to true. The action
+// opcode contains the policy outcome for that particular rule.
+//
+// Note that this header contains the main building blocks of low-level policy
+// but not the low level policy class.
+namespace sandbox {
+
+// These are the possible policy outcomes. Note that some of them might
+// not apply and can be removed. Also note that The following values only
+// specify what to do, not how to do it and it is acceptable given specific
+// cases to ignore the policy outcome.
+enum EvalResult {
+  // Comparison opcode values:
+  EVAL_TRUE,   // Opcode condition evaluated true.
+  EVAL_FALSE,  // Opcode condition evaluated false.
+  EVAL_ERROR,  // Opcode condition generated an error while evaluating.
+  // Action opcode values:
+  ASK_BROKER,  // The target must generate an IPC to the broker. On the broker
+               // side, this means grant access to the resource.
+  DENY_ACCESS,   // No access granted to the resource.
+  GIVE_READONLY,  // Give readonly access to the resource.
+  GIVE_ALLACCESS,  // Give full access to the resource.
+  GIVE_CACHED,  // IPC is not required. Target can return a cached handle.
+  GIVE_FIRST,  // TODO(cpu)
+  SIGNAL_ALARM,  // Unusual activity. Generate an alarm.
+  FAKE_SUCCESS,  // Do not call original function. Just return 'success'.
+  FAKE_ACCESS_DENIED,  // Do not call original function. Just return 'denied'
+                       // and do not do IPC.
+  TERMINATE_PROCESS,  // Destroy target process. Do IPC as well.
+};
+
+// The following are the implemented opcodes.
+enum OpcodeID {
+  OP_ALWAYS_FALSE,  // Evaluates to false (EVAL_FALSE).
+  OP_ALWAYS_TRUE,  // Evaluates to true (EVAL_TRUE).
+  OP_NUMBER_MATCH,  // Match a 32-bit integer as n == a.
+  OP_NUMBER_MATCH_RANGE,  // Match a 32-bit integer as a <= n <= b.
+  OP_NUMBER_AND_MATCH,  // Match using bitwise AND; as in: n & a != 0.
+  OP_WSTRING_MATCH,  // Match a string for equality.
+  OP_ACTION  // Evaluates to an action opcode.
+};
+
+// Options that apply to every opcode. They are specified when creating
+// each opcode using OpcodeFactory::MakeOpXXXXX() family of functions
+// Do nothing special.
+const uint32 kPolNone = 0;
+
+// Convert EVAL_TRUE into EVAL_FALSE and vice-versa. This allows to express
+// negated conditions such as if ( a && !b).
+const uint32 kPolNegateEval = 1;
+
+// Zero the MatchContext context structure. This happens after the opcode
+// is evaluated.
+const uint32 kPolClearContext = 2;
+
+// Use OR when evaluating this set of opcodes. The policy evaluator by default
+// uses AND when evaluating. Very helpful when
+// used with kPolNegateEval. For example if you have a condition best expressed
+// as if(! (a && b && c)), the use of this flags allows it to be expressed as
+// if ((!a) || (!b) || (!c)).
+const uint32 kPolUseOREval = 4;
+
+// Keeps the evaluation state between opcode evaluations. This is used
+// for string matching where the next opcode needs to continue matching
+// from the last character position from the current opcode. The match
+// context is preserved across opcode evaluation unless an opcode specifies
+// as an option kPolClearContext.
+struct MatchContext {
+  size_t position;
+  uint32 options;
+
+  MatchContext() {
+    Clear();
+  }
+
+  void Clear() {
+    position = 0;
+    options = 0;
+  }
+};
+
+// Models a policy opcode; that is a condition evaluation were all the
+// arguments but one are stored in objects of this class. Use OpcodeFactory
+// to create objects of this type.
+// This class is just an implementation artifact and not exposed to the
+// API clients or visible in the intercepted service. Internally, an
+// opcode is just:
+//  - An integer that identifies the actual opcode.
+//  - An index to indicate which one is the input argument
+//  - An array of arguments.
+// While an OO hierarchy of objects would have been a natural choice, the fact
+// that 1) this code can execute before the CRT is loaded, presents serious
+// problems in terms of guarantees about the actual state of the vtables and
+// 2) because the opcode objects are generated in the broker process, we need to
+// use plain objects. To preserve some minimal type safety templates are used
+// when possible.
+class PolicyOpcode {
+  friend class OpcodeFactory;
+ public:
+  // Evaluates the opcode. For a typical comparison opcode the return value
+  // is EVAL_TRUE or EVAL_FALSE. If there was an error in the evaluation the
+  // the return is EVAL_ERROR. If the opcode is an action opcode then the
+  // return can take other values such as ASK_BROKER.
+  // parameters: An array of all input parameters. This argument is normally
+  // created by the macros POLPARAMS_BEGIN() POLPARAMS_END.
+  // count: The number of parameters passed as first argument.
+  // match: The match context that is persisted across the opcode evaluation
+  // sequence.
+  EvalResult Evaluate(const ParameterSet* parameters, size_t count,
+                      MatchContext* match);
+
+  // Retrieves a stored argument by index. Valid index values are
+  // from 0 to < kArgumentCount.
+  template <typename T>
+  void GetArgument(size_t index, T* argument) const {
+    static_assert(sizeof(T) <= sizeof(arguments_[0]), "invalid size");
+    *argument = *reinterpret_cast<const T*>(&arguments_[index].mem);
+  }
+
+  // Sets a stored argument by index. Valid index values are
+  // from 0 to < kArgumentCount.
+  template <typename T>
+  void SetArgument(size_t index, const T& argument) {
+    static_assert(sizeof(T) <= sizeof(arguments_[0]), "invalid size");
+    *reinterpret_cast<T*>(&arguments_[index].mem) = argument;
+  }
+
+  // Retrieves the actual address of an string argument. When using
+  // GetArgument() to retrieve an index that contains a string, the returned
+  // value is just an offset to the actual string.
+  // index: the stored string index. Valid values are from 0
+  // to < kArgumentCount.
+  const wchar_t* GetRelativeString(size_t index) const {
+    ptrdiff_t str_delta = 0;
+    GetArgument(index, &str_delta);
+    const char* delta = reinterpret_cast<const char*>(this) + str_delta;
+    return reinterpret_cast<const wchar_t*>(delta);
+  }
+
+  // Returns true if this opcode is an action opcode without actually
+  // evaluating it. Used to do a quick scan forward to the next opcode group.
+  bool IsAction() const {
+    return (OP_ACTION == opcode_id_);
+  };
+
+  // Returns the opcode type.
+  OpcodeID GetID() const {
+    return opcode_id_;
+  }
+
+  // Returns the stored options such as kPolNegateEval and others.
+  uint32 GetOptions() const {
+    return options_;
+  }
+
+  // Sets the stored options such as kPolNegateEval.
+  void SetOptions(uint32 options) {
+    options_ = base::checked_cast<uint16>(options);
+  }
+
+ private:
+
+  static const size_t kArgumentCount = 4;  // The number of supported argument.
+
+  struct OpcodeArgument {
+    UINT_PTR mem;
+  };
+
+  // Better define placement new in the class instead of relying on the
+  // global definition which seems to be fubared.
+  void* operator new(size_t, void* location) {
+    return location;
+  }
+
+  // Helper function to evaluate the opcode. The parameters have the same
+  // meaning that in Evaluate().
+  EvalResult EvaluateHelper(const ParameterSet* parameters,
+                           MatchContext* match);
+  OpcodeID opcode_id_;
+  int16 parameter_;
+  // TODO(cpu): Making |options_| a uint32 would avoid casting, but causes test
+  // failures.  Somewhere code is relying on the size of this struct.
+  // http://crbug.com/420296
+  uint16 options_;
+  OpcodeArgument arguments_[PolicyOpcode::kArgumentCount];
+};
+
+enum StringMatchOptions {
+  CASE_SENSITIVE = 0,      // Pay or Not attention to the case as defined by
+  CASE_INSENSITIVE = 1,    // RtlCompareUnicodeString windows API.
+  EXACT_LENGHT = 2         // Don't do substring match. Do full string match.
+};
+
+// Opcodes that do string comparisons take a parameter that is the starting
+// position to perform the comparison so we can do substring matching. There
+// are two special values:
+//
+// Start from the current position and compare strings advancing forward until
+// a match is found if any. Similar to CRT strstr().
+const int  kSeekForward = -1;
+// Perform a match with the end of the string. It only does a single comparison.
+const int  kSeekToEnd = 0xfffff;
+
+
+// A PolicyBuffer is a variable size structure that contains all the opcodes
+// that are to be created or evaluated in sequence.
+struct PolicyBuffer {
+  size_t opcode_count;
+  PolicyOpcode opcodes[1];
+};
+
+// Helper class to create any opcode sequence. This class is normally invoked
+// only by the high level policy module or when you need to handcraft a special
+// policy.
+// The factory works by creating the opcodes using a chunk of memory given
+// in the constructor. The opcodes themselves are allocated from the beginning
+// (top) of the memory, while any string that an opcode needs is allocated from
+// the end (bottom) of the memory.
+//
+// In essence:
+//
+//   low address ---> [opcode 1]
+//                    [opcode 2]
+//                    [opcode 3]
+//                    |        | <--- memory_top_
+//                    | free   |
+//                    |        |
+//                    |        | <--- memory_bottom_
+//                    [string 1]
+//   high address --> [string 2]
+//
+// Note that this class does not keep track of the number of opcodes made and
+// it is designed to be a building block for low-level policy.
+//
+// Note that any of the MakeOpXXXXX member functions below can return NULL on
+// failure. When that happens opcode sequence creation must be aborted.
+class OpcodeFactory {
+ public:
+  // memory: base pointer to a chunk of memory where the opcodes are created.
+  // memory_size: the size in bytes of the memory chunk.
+  OpcodeFactory(char* memory, size_t memory_size)
+      : memory_top_(memory) {
+    memory_bottom_ = &memory_top_[memory_size];
+  }
+
+  // policy: contains the raw memory where the opcodes are created.
+  // memory_size: contains the actual size of the policy argument.
+  OpcodeFactory(PolicyBuffer* policy, size_t memory_size) {
+    memory_top_ = reinterpret_cast<char*>(&policy->opcodes[0]);
+    memory_bottom_ = &memory_top_[memory_size];
+  }
+
+  // Returns the available memory to make opcodes.
+  size_t memory_size() const {
+    return memory_bottom_ - memory_top_;
+  }
+
+  // Creates an OpAlwaysFalse opcode.
+  PolicyOpcode* MakeOpAlwaysFalse(uint32 options);
+
+  // Creates an OpAlwaysFalse opcode.
+  PolicyOpcode* MakeOpAlwaysTrue(uint32 options);
+
+  // Creates an OpAction opcode.
+  // action: The action to return when Evaluate() is called.
+  PolicyOpcode* MakeOpAction(EvalResult action, uint32 options);
+
+  // Creates an OpNumberMatch opcode.
+  // selected_param: index of the input argument. It must be a uint32 or the
+  // evaluation result will generate a EVAL_ERROR.
+  // match: the number to compare against the selected_param.
+  PolicyOpcode* MakeOpNumberMatch(int16 selected_param,
+                                  uint32 match,
+                                  uint32 options);
+
+  // Creates an OpNumberMatch opcode (void pointers are cast to numbers).
+  // selected_param: index of the input argument. It must be an void* or the
+  // evaluation result will generate a EVAL_ERROR.
+  // match: the pointer numeric value to compare against selected_param.
+  PolicyOpcode* MakeOpVoidPtrMatch(int16 selected_param,
+                                   const void* match,
+                                   uint32 options);
+
+  // Creates an OpNumberMatchRange opcode using the memory passed in the ctor.
+  // selected_param: index of the input argument. It must be a uint32 or the
+  // evaluation result will generate a EVAL_ERROR.
+  // lower_bound, upper_bound: the range to compare against selected_param.
+  PolicyOpcode* MakeOpNumberMatchRange(int16 selected_param,
+                                       uint32 lower_bound,
+                                       uint32 upper_bound,
+                                       uint32 options);
+
+  // Creates an OpWStringMatch opcode using the raw memory passed in the ctor.
+  // selected_param: index of the input argument. It must be a wide string
+  // pointer or the evaluation result will generate a EVAL_ERROR.
+  // match_str: string to compare against selected_param.
+  // start_position: when its value is from 0 to < 0x7fff it indicates an
+  // offset from the selected_param string where to perform the comparison. If
+  // the value is SeekForward  then a substring search is performed. If the
+  // value is SeekToEnd the comparison is performed against the last part of
+  // the selected_param string.
+  // Note that the range in the position (0 to 0x7fff) is dictated by the
+  // current implementation.
+  // match_opts: Indicates additional matching flags. Currently CaseInsensitive
+  // is supported.
+  PolicyOpcode* MakeOpWStringMatch(int16 selected_param,
+                                   const wchar_t* match_str,
+                                   int start_position,
+                                   StringMatchOptions match_opts,
+                                   uint32 options);
+
+  // Creates an OpNumberAndMatch opcode using the raw memory passed in the ctor.
+  // selected_param: index of the input argument. It must be uint32 or the
+  // evaluation result will generate a EVAL_ERROR.
+  // match: the value to bitwise AND against selected_param.
+  PolicyOpcode* MakeOpNumberAndMatch(int16 selected_param,
+                                     uint32 match,
+                                     uint32 options);
+
+ private:
+  // Constructs the common part of every opcode. selected_param is the index
+  // of the input param to use when evaluating the opcode. Pass -1 in
+  // selected_param to indicate that no input parameter is required.
+  PolicyOpcode* MakeBase(OpcodeID opcode_id, uint32 options,
+                         int16 selected_param);
+
+  // Allocates (and copies) a string (of size length) inside the buffer and
+  // returns the displacement with respect to start.
+  ptrdiff_t AllocRelative(void* start, const wchar_t* str, size_t lenght);
+
+  // Points to the lowest currently available address of the memory
+  // used to make the opcodes. This pointer increments as opcodes are made.
+  char* memory_top_;
+
+  // Points to the highest currently available address of the memory
+  // used to make the opcodes. This pointer decrements as opcode strings are
+  // allocated.
+  char* memory_bottom_;
+
+  DISALLOW_COPY_AND_ASSIGN(OpcodeFactory);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
diff --git a/sandbox/win/src/policy_engine_params.h b/sandbox/win/src/policy_engine_params.h
new file mode 100644
index 0000000..5b3c5ef
--- /dev/null
+++ b/sandbox/win/src/policy_engine_params.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
+#define SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+// This header defines the classes that allow the low level policy to select
+// the input parameters. In order to better make sense of this header is
+// recommended that you check policy_engine_opcodes.h first.
+
+namespace sandbox {
+
+// Models the set of interesting parameters of an intercepted system call
+// normally you don't create objects of this class directly, instead you
+// use the POLPARAMS_XXX macros.
+// For example, if an intercepted function has the following signature:
+//
+// NTSTATUS NtOpenFileFunction (PHANDLE FileHandle,
+//                              ACCESS_MASK DesiredAccess,
+//                              POBJECT_ATTRIBUTES ObjectAttributes,
+//                              PIO_STATUS_BLOCK IoStatusBlock,
+//                              ULONG ShareAccess,
+//                              ULONG OpenOptions);
+//
+// You could say that the following parameters are of interest to policy:
+//
+//   POLPARAMS_BEGIN(open_params)
+//      POLPARAM(DESIRED_ACCESS)
+//      POLPARAM(OBJECT_NAME)
+//      POLPARAM(SECURITY_DESCRIPTOR)
+//      POLPARAM(IO_STATUS)
+//      POLPARAM(OPEN_OPTIONS)
+//   POLPARAMS_END;
+//
+// and the actual code will use this for defining the parameters:
+//
+//   CountedParameterSet<open_params> p;
+//   p[open_params::DESIRED_ACCESS] = ParamPickerMake(DesiredAccess);
+//   p[open_params::OBJECT_NAME] =
+//       ParamPickerMake(ObjectAttributes->ObjectName);
+//   p[open_params::SECURITY_DESCRIPTOR] =
+//       ParamPickerMake(ObjectAttributes->SecurityDescriptor);
+//   p[open_params::IO_STATUS] = ParamPickerMake(IoStatusBlock);
+//   p[open_params::OPEN_OPTIONS] = ParamPickerMake(OpenOptions);
+//
+//  These will create an stack-allocated array of ParameterSet objects which
+//  have each 1) the address of the parameter 2) a numeric id that encodes the
+//  original C++ type. This allows the policy to treat any set of supported
+//  argument types uniformily and with some type safety.
+//
+//  TODO(cpu): support not fully implemented yet for unicode string and will
+//  probably add other types as well.
+class ParameterSet {
+ public:
+  ParameterSet() : real_type_(INVALID_TYPE), address_(NULL) {}
+
+  // Retrieve the stored parameter. If the type does not match ulong fail.
+  bool Get(uint32* destination) const {
+    if (real_type_ != UINT32_TYPE) {
+      return false;
+    }
+    *destination = Void2TypePointerCopy<uint32>();
+    return true;
+  }
+
+  // Retrieve the stored parameter. If the type does not match void* fail.
+  bool Get(const void** destination) const {
+    if (real_type_ != VOIDPTR_TYPE) {
+      return false;
+    }
+    *destination = Void2TypePointerCopy<void*>();
+    return true;
+  }
+
+  // Retrieve the stored parameter. If the type does not match wchar_t* fail.
+  bool Get(const wchar_t** destination) const {
+    if (real_type_ != WCHAR_TYPE) {
+      return false;
+    }
+    *destination = Void2TypePointerCopy<const wchar_t*>();
+    return true;
+  }
+
+  // False if the parameter is not properly initialized.
+  bool IsValid() const {
+    return real_type_ != INVALID_TYPE;
+  }
+
+ protected:
+  // The constructor can only be called by derived types, which should
+  // safely provide the real_type and the address of the argument.
+  ParameterSet(ArgType real_type, const void* address)
+      : real_type_(real_type), address_(address) {
+  }
+
+ private:
+  // This template provides the same functionality as bits_cast but
+  // it works with pointer while the former works only with references.
+  template <typename T>
+  T Void2TypePointerCopy() const {
+    return *(reinterpret_cast<const T*>(address_));
+  }
+
+  ArgType real_type_;
+  const void* address_;
+};
+
+// To safely infer the type, we use a set of template specializations
+// in ParameterSetEx with a template function ParamPickerMake to do the
+// parameter type deduction.
+
+// Base template class. Not implemented so using unsupported types should
+// fail to compile.
+template <typename T>
+class ParameterSetEx : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address);
+};
+
+template<>
+class ParameterSetEx<void const*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(VOIDPTR_TYPE, address) {}
+};
+
+template<>
+class ParameterSetEx<void*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(VOIDPTR_TYPE, address) {}
+};
+
+
+template<>
+class ParameterSetEx<wchar_t*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(WCHAR_TYPE, address) {}
+};
+
+template<>
+class ParameterSetEx<wchar_t const*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(WCHAR_TYPE, address) {}
+};
+
+
+template<>
+class ParameterSetEx<uint32> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(UINT32_TYPE, address) {}
+};
+
+template<>
+class ParameterSetEx<UNICODE_STRING> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(UNISTR_TYPE, address) {}
+};
+
+template <typename T>
+ParameterSet ParamPickerMake(T& parameter) {
+  return ParameterSetEx<T>(&parameter);
+};
+
+struct CountedParameterSetBase {
+  int count;
+  ParameterSet parameters[1];
+};
+
+// This template defines the actual list of policy parameters for a given
+// interception.
+// Warning: This template stores the address to the actual variables, in
+// other words, the values are not copied.
+template <typename T>
+struct CountedParameterSet {
+  CountedParameterSet() : count(T::PolParamLast) {}
+
+  ParameterSet& operator[](typename T::Args n) {
+    return parameters[n];
+  }
+
+  CountedParameterSetBase* GetBase() {
+    return reinterpret_cast<CountedParameterSetBase*>(this);
+  }
+
+  int count;
+  ParameterSet parameters[T::PolParamLast];
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
diff --git a/sandbox/win/src/policy_engine_processor.cc b/sandbox/win/src/policy_engine_processor.cc
new file mode 100644
index 0000000..7ca25b2
--- /dev/null
+++ b/sandbox/win/src/policy_engine_processor.cc
@@ -0,0 +1,107 @@
+// 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 "sandbox/win/src/policy_engine_processor.h"
+
+namespace sandbox {
+
+void PolicyProcessor::SetInternalState(size_t index, EvalResult result) {
+  state_.current_index_ = index;
+  state_.current_result_ = result;
+}
+
+EvalResult PolicyProcessor::GetAction() const {
+  return state_.current_result_;
+}
+
+// Decides if an opcode can be skipped (not evaluated) or not. The function
+// takes as inputs the opcode and the current evaluation context and returns
+// true if the opcode should be skipped or not and also can set keep_skipping
+// to false to signal that the current instruction should be skipped but not
+// the next after the current one.
+bool SkipOpcode(const PolicyOpcode& opcode, MatchContext* context,
+                bool* keep_skipping) {
+  if (opcode.IsAction()) {
+    uint32 options = context->options;
+    context->Clear();
+    *keep_skipping = false;
+    return (kPolUseOREval != options);
+  }
+  *keep_skipping = true;
+  return true;
+}
+
+PolicyResult PolicyProcessor::Evaluate(uint32 options,
+                                       ParameterSet* parameters,
+                                       size_t param_count) {
+  if (NULL == policy_) {
+    return NO_POLICY_MATCH;
+  }
+  if (0 == policy_->opcode_count) {
+    return NO_POLICY_MATCH;
+  }
+  if (!(kShortEval & options)) {
+    return POLICY_ERROR;
+  }
+
+  MatchContext context;
+  bool evaluation = false;
+  bool skip_group = false;
+  SetInternalState(0, EVAL_FALSE);
+  size_t count = policy_->opcode_count;
+
+  // Loop over all the opcodes Evaluating in sequence. Since we only support
+  // short circuit evaluation, we stop as soon as we find an 'action' opcode
+  // and the current evaluation is true.
+  //
+  // Skipping opcodes can happen when we are in AND mode (!kPolUseOREval) and
+  // have got EVAL_FALSE or when we are in OR mode (kPolUseOREval) and got
+  // EVAL_TRUE. Skipping will stop at the next action opcode or at the opcode
+  // after the action depending on kPolUseOREval.
+
+  for (size_t ix = 0; ix != count; ++ix) {
+    PolicyOpcode& opcode = policy_->opcodes[ix];
+    // Skipping block.
+    if (skip_group) {
+      if (SkipOpcode(opcode, &context, &skip_group)) {
+        continue;
+      }
+    }
+    // Evaluation block.
+    EvalResult result = opcode.Evaluate(parameters, param_count, &context);
+    switch (result) {
+      case EVAL_FALSE:
+        evaluation = false;
+        if (kPolUseOREval != context.options) {
+          skip_group = true;
+        }
+        break;
+      case EVAL_ERROR:
+        if (kStopOnErrors & options) {
+          return POLICY_ERROR;
+        }
+        break;
+      case EVAL_TRUE:
+        evaluation = true;
+        if (kPolUseOREval == context.options) {
+          skip_group = true;
+        }
+        break;
+      default:
+        // We have evaluated an action.
+        SetInternalState(ix, result);
+        return POLICY_MATCH;
+    }
+  }
+
+  if (evaluation) {
+    // Reaching the end of the policy with a positive evaluation is probably
+    // an error: we did not find a final action opcode?
+    return POLICY_ERROR;
+  }
+  return NO_POLICY_MATCH;
+}
+
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_engine_processor.h b/sandbox/win/src/policy_engine_processor.h
new file mode 100644
index 0000000..9e416bd
--- /dev/null
+++ b/sandbox/win/src/policy_engine_processor.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
+#define SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+
+namespace sandbox {
+
+// This header contains the core policy evaluator. In its simplest form
+// it evaluates a stream of opcodes assuming that they are laid out in
+// memory as opcode groups.
+//
+// An opcode group has N comparison opcodes plus 1 action opcode. For
+// example here we have 3 opcode groups (A, B,C):
+//
+// [comparison 1]  <-- group A start
+// [comparison 2]
+// [comparison 3]
+// [action A    ]
+// [comparison 1]  <-- group B start
+// [action B    ]
+// [comparison 1]  <-- group C start
+// [comparison 2]
+// [action C    ]
+//
+// The opcode evaluator proceeds from the top, evaluating each opcode in
+// sequence. An opcode group is evaluated until the first comparison that
+// returns false. At that point the rest of the group is skipped and evaluation
+// resumes with the first comparison of the next group. When all the comparisons
+// in a group have evaluated to true and the action is reached. The group is
+// considered a matching group.
+//
+// In the 'ShortEval' mode evaluation stops when it reaches the end or the first
+// matching group. The action opcode from this group is the resulting policy
+// action.
+//
+// In the 'RankedEval' mode evaluation stops only when it reaches the end of the
+// the opcode stream. In the process all matching groups are saved and at the
+// end the 'best' group is selected (what makes the best is TBD) and the action
+// from this group is the resulting policy action.
+//
+// As explained above, the policy evaluation of a group is a logical AND of
+// the evaluation of each opcode. However an opcode can request kPolUseOREval
+// which makes the evaluation to use logical OR. Given that each opcode can
+// request its evaluation result to be negated with kPolNegateEval you can
+// achieve the negation of the total group evaluation. This means that if you
+// need to express:
+//             if (!(c1 && c2 && c3))
+// You can do it by:
+//             if ((!c1) || (!c2) || (!c3))
+//
+
+// Possible outcomes of policy evaluation.
+enum PolicyResult {
+  NO_POLICY_MATCH,
+  POLICY_MATCH,
+  POLICY_ERROR
+};
+
+// Policy evaluation flags
+// TODO(cpu): implement the options kStopOnErrors & kRankedEval.
+//
+// Stop evaluating as soon as an error is encountered.
+const uint32 kStopOnErrors = 1;
+// Ignore all non fatal opcode evaluation errors.
+const uint32 kIgnoreErrors = 2;
+// Short-circuit evaluation: Only evaluate until opcode group that
+// evaluated to true has been found.
+const uint32 kShortEval = 4;
+// Discussed briefly at the policy design meeting. It will evaluate
+// all rules and then return the 'best' rule that evaluated true.
+const uint32 kRankedEval = 8;
+
+// This class evaluates a policy-opcode stream given the memory where the
+// opcodes are and an input 'parameter set'.
+//
+// This class is designed to be callable from interception points
+// as low as the NtXXXX service level (it is not currently safe, but
+// it is designed to be made safe).
+//
+// Its usage in an interception is:
+//
+//   POLPARAMS_BEGIN(eval_params)
+//     POLPARAM(param1)
+//     POLPARAM(param2)
+//     POLPARAM(param3)
+//     POLPARAM(param4)
+//     POLPARAM(param5)
+//   POLPARAMS_END;
+//
+//   PolicyProcessor pol_evaluator(policy_memory);
+//   PolicyResult pr = pol_evaluator.Evaluate(ShortEval, eval_params,
+//                                            _countof(eval_params));
+//   if (NO_POLICY_MATCH == pr) {
+//     EvalResult policy_action =  pol_evaluator.GetAction();
+//     // apply policy here...
+//   }
+//
+// Where the POLPARAM() arguments are derived from the intercepted function
+// arguments, and represent all the 'interesting' policy inputs, and
+// policy_memory is a memory buffer containing the opcode stream that is the
+// relevant policy for this intercept.
+class PolicyProcessor {
+ public:
+  // policy_buffer contains opcodes made with OpcodeFactory. They are usually
+  // created in the broker process and evaluated in the target process.
+
+  // This constructor is just a variant of the previous constructor.
+  explicit PolicyProcessor(PolicyBuffer* policy)
+      : policy_(policy) {
+    SetInternalState(0, EVAL_FALSE);
+  }
+
+  // Evaluates a policy-opcode stream. See the comments at the top of this
+  // class for more info. Returns POLICY_MATCH if a rule set was found that
+  // matches an active policy.
+  PolicyResult Evaluate(uint32 options,
+                        ParameterSet* parameters,
+                        size_t parameter_count);
+
+  // If the result of Evaluate() was POLICY_MATCH, calling this function returns
+  // the recommended policy action.
+  EvalResult GetAction() const;
+
+ private:
+  struct {
+    size_t current_index_;
+    EvalResult current_result_;
+  } state_;
+
+  // Sets the currently matching action result.
+  void SetInternalState(size_t index, EvalResult result);
+
+  PolicyBuffer* policy_;
+  DISALLOW_COPY_AND_ASSIGN(PolicyProcessor);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
diff --git a/sandbox/win/src/policy_engine_unittest.cc b/sandbox/win/src/policy_engine_unittest.cc
new file mode 100644
index 0000000..325a101
--- /dev/null
+++ b/sandbox/win/src/policy_engine_unittest.cc
@@ -0,0 +1,102 @@
+// 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 "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define POLPARAMS_BEGIN(x) sandbox::ParameterSet x[] = {
+#define POLPARAM(p) sandbox::ParamPickerMake(p),
+#define POLPARAMS_END }
+
+namespace sandbox {
+
+bool SetupNtdllImports();
+
+TEST(PolicyEngineTest, Rules1) {
+  SetupNtdllImports();
+
+  // Construct two policy rules that say:
+  //
+  // #1
+  // If the path is c:\\documents and settings\\* AND
+  // If the creation mode is 'open existing' AND
+  // If the security descriptor is null THEN
+  // Ask the broker.
+  //
+  // #2
+  // If the security descriptor is null AND
+  // If the path ends with *.txt AND
+  // If the creation mode is not 'create new' THEN
+  // return Access Denied.
+
+  enum FileCreateArgs {
+    FileNameArg,
+    CreationDispositionArg,
+    FlagsAndAttributesArg,
+    SecurityAttributes
+  };
+
+  const size_t policy_sz = 1024;
+  PolicyBuffer* policy = reinterpret_cast<PolicyBuffer*>(new char[policy_sz]);
+  OpcodeFactory opcode_maker(policy, policy_sz - 0x40);
+
+  // Add rule set #1
+  opcode_maker.MakeOpWStringMatch(FileNameArg,
+                                  L"c:\\documents and settings\\",
+                                  0, CASE_INSENSITIVE, kPolNone);
+  opcode_maker.MakeOpNumberMatch(CreationDispositionArg, OPEN_EXISTING,
+                                 kPolNone);
+  opcode_maker.MakeOpVoidPtrMatch(SecurityAttributes, (void*)NULL,
+                                 kPolNone);
+  opcode_maker.MakeOpAction(ASK_BROKER, kPolNone);
+
+  // Add rule set #2
+  opcode_maker.MakeOpWStringMatch(FileNameArg, L".TXT",
+                                  kSeekToEnd, CASE_INSENSITIVE, kPolNone);
+  opcode_maker.MakeOpNumberMatch(CreationDispositionArg, CREATE_NEW,
+                                 kPolNegateEval);
+  opcode_maker.MakeOpAction(FAKE_ACCESS_DENIED, kPolNone);
+  policy->opcode_count = 7;
+
+  const wchar_t* filename = L"c:\\Documents and Settings\\Microsoft\\BLAH.txt";
+  uint32 creation_mode = OPEN_EXISTING;
+  uint32 flags = FILE_ATTRIBUTE_NORMAL;
+  void* security_descriptor = NULL;
+
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)
+    POLPARAM(creation_mode)
+    POLPARAM(flags)
+    POLPARAM(security_descriptor)
+  POLPARAMS_END;
+
+  PolicyResult pr;
+  PolicyProcessor pol_ev(policy);
+
+  // Test should match the first rule set.
+  pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, pr);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  // Test should still match the first rule set.
+  pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, pr);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  // Changing creation_mode such that evaluation should not match any rule.
+  creation_mode = CREATE_NEW;
+  pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, pr);
+
+  // Changing creation_mode such that evaluation should match rule #2.
+  creation_mode = OPEN_ALWAYS;
+  pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, pr);
+  EXPECT_EQ(FAKE_ACCESS_DENIED, pol_ev.GetAction());
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_low_level.cc b/sandbox/win/src/policy_low_level.cc
new file mode 100644
index 0000000..739321c
--- /dev/null
+++ b/sandbox/win/src/policy_low_level.cc
@@ -0,0 +1,356 @@
+// 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 "sandbox/win/src/policy_low_level.h"
+
+#include <string>
+#include <map>
+
+#include "base/basictypes.h"
+
+namespace {
+
+  // A single rule can use at most this amount of memory.
+  const size_t kRuleBufferSize = 1024*4;
+
+  // The possible states of the string matching opcode generator.
+  enum {
+    PENDING_NONE,
+    PENDING_ASTERISK,    // Have seen an '*' but have not generated an opcode.
+    PENDING_QMARK,       // Have seen an '?' but have not generated an opcode.
+  };
+
+  // The category of the last character seen by the string matching opcode
+  // generator.
+  const uint32 kLastCharIsNone = 0;
+  const uint32 kLastCharIsAlpha = 1;
+  const uint32 kLastCharIsWild = 2;
+  const uint32 kLastCharIsAsterisk = kLastCharIsWild + 4;
+  const uint32 kLastCharIsQuestionM = kLastCharIsWild + 8;
+}
+
+namespace sandbox {
+
+LowLevelPolicy::LowLevelPolicy(PolicyGlobal* policy_store)
+    : policy_store_(policy_store) {
+}
+
+// Adding a rule is nothing more than pushing it into an stl container. Done()
+// is called for the rule in case the code that made the rule in the first
+// place has not done it.
+bool LowLevelPolicy::AddRule(int service, PolicyRule* rule) {
+  if (!rule->Done()) {
+    return false;
+  }
+
+  PolicyRule* local_rule = new PolicyRule(*rule);
+  RuleNode node = {local_rule, service};
+  rules_.push_back(node);
+  return true;
+}
+
+LowLevelPolicy::~LowLevelPolicy() {
+  // Delete all the rules.
+  typedef std::list<RuleNode> RuleNodes;
+  for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
+    delete it->rule;
+  }
+}
+
+// Here is where the heavy byte shuffling is done. We take all the rules and
+// 'compile' them into a single memory region. Now, the rules are in random
+// order so the first step is to reorganize them into a stl map that is keyed
+// by the service id and as a value contains a list with all the rules that
+// belong to that service. Then we enter the big for-loop where we carve a
+// memory zone for the opcodes and the data and call RebindCopy on each rule
+// so they all end up nicely packed in the policy_store_.
+bool LowLevelPolicy::Done() {
+  typedef std::list<RuleNode> RuleNodes;
+  typedef std::list<const PolicyRule*> RuleList;
+  typedef std::map<uint32, RuleList> Mmap;
+  Mmap mmap;
+
+  for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
+    mmap[it->service].push_back(it->rule);
+  }
+
+  PolicyBuffer* current_buffer = &policy_store_->data[0];
+  char* buffer_end = reinterpret_cast<char*>(current_buffer) +
+    policy_store_->data_size;
+  size_t avail_size =  policy_store_->data_size;
+
+  for (Mmap::iterator it = mmap.begin(); it != mmap.end(); ++it) {
+    uint32 service = (*it).first;
+    if (service >= kMaxServiceCount) {
+      return false;
+    }
+    policy_store_->entry[service] = current_buffer;
+
+    RuleList::iterator rules_it = (*it).second.begin();
+    RuleList::iterator rules_it_end = (*it).second.end();
+
+    size_t svc_opcode_count = 0;
+
+    for (; rules_it != rules_it_end; ++rules_it) {
+      const PolicyRule* rule = (*rules_it);
+      size_t op_count = rule->GetOpcodeCount();
+
+      size_t opcodes_size = op_count * sizeof(PolicyOpcode);
+      if (avail_size < opcodes_size) {
+        return false;
+      }
+      size_t data_size = avail_size - opcodes_size;
+      PolicyOpcode* opcodes_start = &current_buffer->opcodes[svc_opcode_count];
+      if (!rule->RebindCopy(opcodes_start, opcodes_size,
+                            buffer_end, &data_size)) {
+        return false;
+      }
+      size_t used = avail_size - data_size;
+      buffer_end -= used;
+      avail_size -= used;
+      svc_opcode_count += op_count;
+    }
+
+    current_buffer->opcode_count += svc_opcode_count;
+    size_t policy_byte_count = (svc_opcode_count * sizeof(PolicyOpcode))
+                                / sizeof(current_buffer[0]);
+    current_buffer = &current_buffer[policy_byte_count + 1];
+  }
+
+  return true;
+}
+
+PolicyRule::PolicyRule(EvalResult action)
+    : action_(action), done_(false) {
+  char* memory = new char[sizeof(PolicyBuffer) + kRuleBufferSize];
+  buffer_ = reinterpret_cast<PolicyBuffer*>(memory);
+  buffer_->opcode_count = 0;
+  opcode_factory_ = new OpcodeFactory(buffer_,
+                                      kRuleBufferSize + sizeof(PolicyOpcode));
+}
+
+PolicyRule::PolicyRule(const PolicyRule& other) {
+  if (this == &other)
+    return;
+  action_ = other.action_;
+  done_ = other.done_;
+  size_t buffer_size = sizeof(PolicyBuffer) + kRuleBufferSize;
+  char* memory = new char[buffer_size];
+  buffer_ = reinterpret_cast<PolicyBuffer*>(memory);
+  memcpy(buffer_, other.buffer_, buffer_size);
+
+  char* opcode_buffer = reinterpret_cast<char*>(&buffer_->opcodes[0]);
+  char* next_opcode = &opcode_buffer[GetOpcodeCount() * sizeof(PolicyOpcode)];
+  opcode_factory_ =
+      new OpcodeFactory(next_opcode, other.opcode_factory_->memory_size());
+}
+
+// This function get called from a simple state machine implemented in
+// AddStringMatch() which passes the current state (in state) and it passes
+// true in last_call if AddStringMatch() has finished processing the input
+// pattern string and this would be the last call to generate any pending
+// opcode. The skip_count is the currently accumulated number of '?' seen so
+// far and once the associated opcode is generated this function sets it back
+// to zero.
+bool PolicyRule::GenStringOpcode(RuleType rule_type,
+                                 StringMatchOptions match_opts,
+                                 uint16 parameter, int state, bool last_call,
+                                 int* skip_count, base::string16* fragment) {
+
+  // The last opcode must:
+  //   1) Always clear the context.
+  //   2) Preserve the negation.
+  //   3) Remove the 'OR' mode flag.
+  uint32 options = kPolNone;
+  if (last_call) {
+    if (IF_NOT == rule_type) {
+      options = kPolClearContext | kPolNegateEval;
+    } else {
+      options = kPolClearContext;
+    }
+  } else if (IF_NOT == rule_type) {
+    options = kPolUseOREval | kPolNegateEval;
+  }
+
+  PolicyOpcode* op = NULL;
+
+  // The fragment string contains the accumulated characters to match with, it
+  // never contains wildcards (unless they have been escaped) and while there
+  // is no fragment there is no new string match opcode to generate.
+  if (fragment->empty()) {
+    // There is no new opcode to generate but in the last call we have to fix
+    // the previous opcode because it was really the last but we did not know
+    // it at that time.
+    if (last_call && (buffer_->opcode_count > 0)) {
+      op = &buffer_->opcodes[buffer_->opcode_count - 1];
+      op->SetOptions(options);
+    }
+    return true;
+  }
+
+  if (PENDING_ASTERISK == state) {
+    if (last_call) {
+      op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
+                                               kSeekToEnd, match_opts,
+                                               options);
+    } else {
+      op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
+                                               kSeekForward, match_opts,
+                                               options);
+    }
+
+  } else if (PENDING_QMARK == state) {
+    op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
+                                             *skip_count, match_opts, options);
+    *skip_count = 0;
+  } else {
+    if (last_call) {
+      match_opts = static_cast<StringMatchOptions>(EXACT_LENGHT | match_opts);
+    }
+    op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(), 0,
+                                             match_opts, options);
+  }
+  if (NULL == op) {
+    return false;
+  }
+  ++buffer_->opcode_count;
+  fragment->clear();
+  return true;
+}
+
+bool PolicyRule::AddStringMatch(RuleType rule_type, int16 parameter,
+                                const wchar_t* string,
+                                StringMatchOptions match_opts) {
+  if (done_) {
+    // Do not allow to add more rules after generating the action opcode.
+    return false;
+  }
+
+  const wchar_t* current_char = string;
+  uint32 last_char = kLastCharIsNone;
+  int state = PENDING_NONE;
+  int skip_count = 0;       // counts how many '?' we have seen in a row.
+  base::string16 fragment;  // accumulates the non-wildcard part.
+
+  while (L'\0' != *current_char) {
+    switch (*current_char) {
+      case L'*':
+        if (kLastCharIsWild & last_char) {
+          // '**' and '&*' is an error.
+          return false;
+        }
+        if (!GenStringOpcode(rule_type, match_opts, parameter,
+                             state, false, &skip_count, &fragment)) {
+          return false;
+        }
+        last_char = kLastCharIsAsterisk;
+        state = PENDING_ASTERISK;
+        break;
+      case L'?':
+        if (kLastCharIsAsterisk == last_char) {
+          // '*?' is an error.
+          return false;
+        }
+        if (!GenStringOpcode(rule_type, match_opts, parameter,
+                             state, false, &skip_count, &fragment)) {
+          return false;
+        }
+        ++skip_count;
+        last_char = kLastCharIsQuestionM;
+        state = PENDING_QMARK;
+        break;
+      case L'/':
+        // Note: "/?" is an escaped '?'. Eat the slash and fall through.
+        if (L'?' == current_char[1]) {
+          ++current_char;
+        }
+      default:
+        fragment += *current_char;
+        last_char = kLastCharIsAlpha;
+    }
+    ++current_char;
+  }
+
+  if (!GenStringOpcode(rule_type, match_opts, parameter,
+                       state, true, &skip_count, &fragment)) {
+    return false;
+  }
+  return true;
+}
+
+bool PolicyRule::AddNumberMatch(RuleType rule_type,
+                                int16 parameter,
+                                uint32 number,
+                                RuleOp comparison_op) {
+  if (done_) {
+    // Do not allow to add more rules after generating the action opcode.
+    return false;
+  }
+  uint32 opts = (rule_type == IF_NOT)? kPolNegateEval : kPolNone;
+
+  if (EQUAL == comparison_op) {
+    if (NULL == opcode_factory_->MakeOpNumberMatch(parameter, number, opts)) {
+      return false;
+    }
+  } else if (AND == comparison_op) {
+    if (NULL == opcode_factory_->MakeOpNumberAndMatch(parameter, number,
+                                                      opts)) {
+      return false;
+    }
+  }
+  ++buffer_->opcode_count;
+  return true;
+}
+
+bool PolicyRule::Done() {
+  if (done_) {
+    return true;
+  }
+  if (NULL == opcode_factory_->MakeOpAction(action_, kPolNone)) {
+    return false;
+  }
+  ++buffer_->opcode_count;
+  done_ = true;
+  return true;
+}
+
+bool PolicyRule::RebindCopy(PolicyOpcode* opcode_start, size_t opcode_size,
+                            char* data_start, size_t* data_size) const {
+  size_t count = buffer_->opcode_count;
+  for (size_t ix = 0; ix != count; ++ix) {
+    if (opcode_size < sizeof(PolicyOpcode)) {
+      return false;
+    }
+    PolicyOpcode& opcode = buffer_->opcodes[ix];
+    *opcode_start = opcode;
+    if (OP_WSTRING_MATCH == opcode.GetID()) {
+      // For this opcode argument 0 is a delta to the string and argument 1
+      // is the length (in chars) of the string.
+      const wchar_t* str = opcode.GetRelativeString(0);
+      size_t str_len;
+      opcode.GetArgument(1, &str_len);
+      str_len = str_len * sizeof(wchar_t);
+      if ((*data_size) < str_len) {
+        return false;
+      }
+      *data_size -= str_len;
+      data_start -= str_len;
+      memcpy(data_start, str, str_len);
+      // Recompute the string displacement
+      ptrdiff_t delta = data_start - reinterpret_cast<char*>(opcode_start);
+      opcode_start->SetArgument(0, delta);
+    }
+    ++opcode_start;
+    opcode_size -= sizeof(PolicyOpcode);
+  }
+
+  return true;
+}
+
+PolicyRule::~PolicyRule() {
+  delete [] reinterpret_cast<char*>(buffer_);
+  delete opcode_factory_;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_low_level.h b/sandbox/win/src/policy_low_level.h
new file mode 100644
index 0000000..6a62631
--- /dev/null
+++ b/sandbox/win/src/policy_low_level.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_LOW_LEVEL_H__
+#define SANDBOX_SRC_POLICY_LOW_LEVEL_H__
+
+#include <list>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+
+// Low level policy classes.
+// Built on top of the PolicyOpcode and OpcodeFatory, the low level policy
+// provides a way to define rules on strings and numbers but it is unaware
+// of Windows specific details or how the Interceptions must be set up.
+// To use these classes you construct one or more rules and add them to the
+// LowLevelPolicy object like this:
+//
+//   PolicyRule rule1(ASK_BROKER);
+//   rule1.AddStringMatch(IF, 0, L"\\\\/?/?\\c:\\*Microsoft*\\*.exe", true);
+//   rule1.AddNumberMatch(IF_NOT, 1, CREATE_ALWAYS, EQUAL);
+//   rule1.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL);
+//
+//   PolicyRule rule2(FAKE_SUCCESS);
+//   rule2.AddStringMatch(IF, 0, L"\\\\/?/?\\Pipe\\Chrome.*", false));
+//   rule2.AddNumberMatch(IF, 1, OPEN_EXISTING, EQUAL));
+//
+//   LowLevelPolicy policyGen(*policy_memory);
+//   policyGen.AddRule(kNtCreateFileSvc, &rule1);
+//   policyGen.AddRule(kNtCreateFileSvc, &rule2);
+//   policyGen.Done();
+//
+// At this point (error checking omitted) the policy_memory can be copied
+// to the target process where it can be evaluated.
+
+namespace sandbox {
+
+// TODO(cpu): Move this constant to crosscall_client.h.
+const size_t kMaxServiceCount = 32;
+static_assert(IPC_LAST_TAG <= kMaxServiceCount,
+              "kMaxServiceCount is too low");
+
+// Defines the memory layout of the policy. This memory is filled by
+// LowLevelPolicy object.
+// For example:
+//
+//  [Service 0] --points to---\
+//  [Service 1] --------------|-----\
+//   ......                   |     |
+//  [Service N]               |     |
+//  [data_size]               |     |
+//  [Policy Buffer 0] <-------/     |
+//  [opcodes of]                    |
+//  .......                         |
+//  [Policy Buffer 1] <-------------/
+//  [opcodes]
+//  .......
+//  .......
+//  [Policy Buffer N]
+//  [opcodes]
+//  .......
+//   <possibly unused space here>
+//  .......
+//  [opcode string ]
+//  [opcode string ]
+//  .......
+//  [opcode string ]
+struct PolicyGlobal {
+  PolicyBuffer* entry[kMaxServiceCount];
+  size_t data_size;
+  PolicyBuffer data[1];
+};
+
+class PolicyRule;
+
+// Provides the means to collect rules into a policy store (memory)
+class LowLevelPolicy {
+ public:
+  // policy_store: must contain allocated memory and the internal
+  // size fields set to correct values.
+  explicit LowLevelPolicy(PolicyGlobal* policy_store);
+
+  // Destroys all the policy rules.
+  ~LowLevelPolicy();
+
+  // Adds a rule to be generated when Done() is called.
+  // service: The id of the service that this rule is associated with,
+  // for example the 'Open Thread' service or the "Create File" service.
+  // returns false on error.
+  bool AddRule(int service, PolicyRule* rule);
+
+  // Generates all the rules added with AddRule() into the memory area
+  // passed on the constructor. Returns false on error.
+  bool Done();
+
+ private:
+  struct RuleNode {
+    const PolicyRule* rule;
+    int service;
+  };
+  std::list<RuleNode> rules_;
+  PolicyGlobal* policy_store_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LowLevelPolicy);
+};
+
+// There are 'if' rules and 'if not' comparisons
+enum RuleType {
+  IF = 0,
+  IF_NOT = 1,
+};
+
+// Possible comparisons for numbers
+enum RuleOp {
+  EQUAL,
+  AND,
+  RANGE   // TODO(cpu): Implement this option.
+};
+
+// Provides the means to collect a set of comparisons into a single
+// rule and its associated action.
+class PolicyRule {
+  friend class LowLevelPolicy;
+
+ public:
+  explicit PolicyRule(EvalResult action);
+  PolicyRule(const PolicyRule& other);
+  ~PolicyRule();
+
+  // Adds a string comparison to the rule.
+  // rule_type: possible values are IF and IF_NOT.
+  // parameter: the expected index of the argument for this rule. For example
+  // in a 'create file' service the file name argument can be at index 0.
+  // string: is the desired matching pattern.
+  // match_opts: if the pattern matching is case sensitive or not.
+  bool AddStringMatch(RuleType rule_type, int16 parameter,
+                      const wchar_t* string, StringMatchOptions match_opts);
+
+  // Adds a number match comparison to the rule.
+  // rule_type: possible values are IF and IF_NOT.
+  // parameter: the expected index of the argument for this rule.
+  // number: the value to compare the input to.
+  // comparison_op: the comparison kind (equal, logical and, etc).
+  bool AddNumberMatch(RuleType rule_type,
+                      int16 parameter,
+                      uint32 number,
+                      RuleOp comparison_op);
+
+  // Returns the number of opcodes generated so far.
+  size_t GetOpcodeCount() const {
+    return buffer_->opcode_count;
+  }
+
+  // Called when there is no more comparisons to add. Internally it generates
+  // the last opcode (the action opcode). Returns false if this operation fails.
+  bool Done();
+
+ private:
+  void operator=(const PolicyRule&);
+  // Called in a loop from AddStringMatch to generate the required string
+  // match opcodes. rule_type, match_opts and parameter are the same as
+  // in AddStringMatch.
+  bool GenStringOpcode(RuleType rule_type, StringMatchOptions match_opts,
+                       uint16 parameter, int state, bool last_call,
+                       int* skip_count, base::string16* fragment);
+
+  // Loop over all generated opcodes and copy them to increasing memory
+  // addresses from opcode_start and copy the extra data (strings usually) into
+  // decreasing addresses from data_start. Extra data is only present in the
+  // string evaluation opcodes.
+  bool RebindCopy(PolicyOpcode* opcode_start, size_t opcode_size,
+                  char* data_start, size_t* data_size) const;
+  PolicyBuffer* buffer_;
+  OpcodeFactory* opcode_factory_;
+  EvalResult action_;
+  bool done_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_LOW_LEVEL_H__
diff --git a/sandbox/win/src/policy_low_level_unittest.cc b/sandbox/win/src/policy_low_level_unittest.cc
new file mode 100644
index 0000000..4081a58
--- /dev/null
+++ b/sandbox/win/src/policy_low_level_unittest.cc
@@ -0,0 +1,618 @@
+// 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 "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define POLPARAMS_BEGIN(x) sandbox::ParameterSet x[] = {
+#define POLPARAM(p) sandbox::ParamPickerMake(p),
+#define POLPARAMS_END }
+
+namespace sandbox {
+
+bool SetupNtdllImports();
+
+// Testing that we allow opcode generation on valid string patterns.
+TEST(PolicyEngineTest, StringPatternsOK) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\adobe\\ver??\\", CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"*.tmp", CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\*.doc", CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\windows\\*", CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"d:\\adobe\\acrobat.exe",
+                                CASE_SENSITIVE));
+}
+
+// Testing that we signal invalid string patterns.
+TEST(PolicyEngineTest, StringPatternsBAD) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"one**two", CASE_SENSITIVE));
+  EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"**three", CASE_SENSITIVE));
+  EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"five?six*?seven", CASE_SENSITIVE));
+  EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"eight?*nine", CASE_SENSITIVE));
+}
+
+// Helper function to allocate space (on the heap) for policy.
+PolicyGlobal* MakePolicyMemory() {
+  const size_t kTotalPolicySz = 4096*8;
+  char* mem = new char[kTotalPolicySz];
+  memset(mem, 0, kTotalPolicySz);
+  PolicyGlobal* policy = reinterpret_cast<PolicyGlobal*>(mem);
+  policy->data_size = kTotalPolicySz - sizeof(PolicyGlobal);
+  return policy;
+}
+
+// The simplest test using LowLevelPolicy it should test a single opcode which
+// does a exact string comparison.
+TEST(PolicyEngineTest, SimpleStrMatch) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"z:\\Directory\\domo.txt",
+              CASE_INSENSITIVE));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  const uint32 kFakeService = 2;
+
+  LowLevelPolicy policyGen(policy);
+  EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = L"Z:\\Directory\\domo.txt";
+
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kFakeService]);
+
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"Z:\\Directory\\domo.txt.tmp";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, SimpleIfNotStrMatch) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\",
+                                CASE_SENSITIVE));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  const uint32 kFakeService = 2;
+  LowLevelPolicy policyGen(policy);
+
+  EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = NULL;
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kFakeService]);
+
+  filename = L"c:\\Microsoft\\";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\MicroNerd\\";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\Microsoft\\domo.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, SimpleIfNotStrMatchWild1) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\*",
+                                CASE_SENSITIVE));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  const uint32 kFakeService = 3;
+  LowLevelPolicy policyGen(policy);
+
+  EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = NULL;
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kFakeService]);
+
+  filename = L"c:\\Microsoft\\domo.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\MicroNerd\\domo.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, SimpleIfNotStrMatchWild2) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\*.txt",
+                                CASE_SENSITIVE));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  const uint32 kFakeService = 3;
+  LowLevelPolicy policyGen(policy);
+
+  EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = NULL;
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kFakeService]);
+
+  filename = L"c:\\Microsoft\\domo.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\MicroNerd\\domo.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\Microsoft\\domo.bmp";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, IfNotStrMatchTwoRulesWild1) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\*",
+                                CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddNumberMatch(IF, 1, 24, EQUAL));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  const uint32 kFakeService = 3;
+  LowLevelPolicy policyGen(policy);
+
+  EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = NULL;
+  uint32 access = 0;
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+    POLPARAM(access)                  // Argument 1
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kFakeService]);
+
+  filename = L"c:\\Microsoft\\domo.txt";
+  access = 24;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\Microsoft\\domo.txt";
+  access = 42;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\MicroNerd\\domo.txt";
+  access = 24;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\Micronesia\\domo.txt";
+  access = 42;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, IfNotStrMatchTwoRulesWild2) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddNumberMatch(IF, 1, 24, EQUAL));
+  EXPECT_TRUE(pr.AddStringMatch(IF_NOT, 0, L"c:\\GoogleV?\\*.txt",
+                                CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddNumberMatch(IF, 2, 66, EQUAL));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  const uint32 kFakeService = 3;
+  LowLevelPolicy policyGen(policy);
+
+  EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = NULL;
+  uint32 access = 0;
+  uint32 sharing = 66;
+
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+    POLPARAM(access)                  // Argument 1
+    POLPARAM(sharing)                 // Argument 2
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kFakeService]);
+
+  filename = L"c:\\GoogleV2\\domo.txt";
+  access = 24;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\GoogleV2\\domo.bmp";
+  access = 24;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\GoogleV23\\domo.txt";
+  access = 24;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+
+  filename = L"c:\\GoogleV2\\domo.txt";
+  access = 42;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\Google\\domo.txt";
+  access = 24;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\Micronesia\\domo.txt";
+  access = 42;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\GoogleV2\\domo.bmp";
+  access = 24;
+  sharing = 0;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+// Testing one single rule in one single service. The service is made to
+// resemble NtCreateFile.
+TEST(PolicyEngineTest, OneRuleTest) {
+  SetupNtdllImports();
+  PolicyRule pr(ASK_BROKER);
+  EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\*Microsoft*\\*.txt",
+                                CASE_SENSITIVE));
+  EXPECT_TRUE(pr.AddNumberMatch(IF_NOT, 1, CREATE_ALWAYS, EQUAL));
+  EXPECT_TRUE(pr.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+
+  const uint32 kNtFakeCreateFile = 7;
+
+  LowLevelPolicy policyGen(policy);
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* filename = L"c:\\Documents and Settings\\Microsoft\\BLAH.txt";
+  uint32 creation_mode = OPEN_EXISTING;
+  uint32 flags = FILE_ATTRIBUTE_NORMAL;
+  void* security_descriptor = NULL;
+
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(filename)                // Argument 0
+    POLPARAM(creation_mode)           // Argument 1
+    POLPARAM(flags)                   // Argument 2
+    POLPARAM(security_descriptor)
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev(policy->entry[kNtFakeCreateFile]);
+
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  creation_mode = CREATE_ALWAYS;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  creation_mode = OPEN_EXISTING;
+  filename = L"c:\\Other\\Path\\Microsoft\\Another file.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\Other\\Path\\Microsoft\\Another file.txt.tmp";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  flags = FILE_ATTRIBUTE_DEVICE;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\Other\\Macrosoft\\Another file.txt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\Microsoft\\1.txt";
+  flags = FILE_ATTRIBUTE_NORMAL;
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+  filename = L"c:\\Microsoft\\1.ttt";
+  result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+// Testing 3 rules in 3 services. Two of the services resemble File services.
+TEST(PolicyEngineTest, ThreeRulesTest) {
+  SetupNtdllImports();
+  PolicyRule pr_pipe(FAKE_SUCCESS);
+  EXPECT_TRUE(pr_pipe.AddStringMatch(IF, 0, L"\\\\/?/?\\Pipe\\Chrome.*",
+                                     CASE_INSENSITIVE));
+  EXPECT_TRUE(pr_pipe.AddNumberMatch(IF, 1, OPEN_EXISTING, EQUAL));
+  EXPECT_TRUE(pr_pipe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+  size_t opc1 = pr_pipe.GetOpcodeCount();
+  EXPECT_EQ(3, opc1);
+
+  PolicyRule pr_dump(ASK_BROKER);
+  EXPECT_TRUE(pr_dump.AddStringMatch(IF, 0, L"\\\\/?/?\\*\\Crash Reports\\*",
+                                     CASE_INSENSITIVE));
+  EXPECT_TRUE(pr_dump.AddNumberMatch(IF, 1, CREATE_ALWAYS, EQUAL));
+  EXPECT_TRUE(pr_dump.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+  size_t opc2 = pr_dump.GetOpcodeCount();
+  EXPECT_EQ(4, opc2);
+
+  PolicyRule pr_winexe(SIGNAL_ALARM);
+  EXPECT_TRUE(pr_winexe.AddStringMatch(IF, 0, L"\\\\/?/?\\C:\\Windows\\*.exe",
+                                       CASE_INSENSITIVE));
+  EXPECT_TRUE(pr_winexe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+  size_t opc3 = pr_winexe.GetOpcodeCount();
+  EXPECT_EQ(3, opc3);
+
+  PolicyRule pr_adobe(GIVE_CACHED);
+  EXPECT_TRUE(pr_adobe.AddStringMatch(IF, 0, L"c:\\adobe\\ver?.?\\",
+                                      CASE_SENSITIVE));
+  EXPECT_TRUE(pr_adobe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+  size_t opc4 = pr_adobe.GetOpcodeCount();
+  EXPECT_EQ(4, opc4);
+
+  PolicyRule pr_none(GIVE_FIRST);
+  EXPECT_TRUE(pr_none.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_READONLY, AND));
+  EXPECT_TRUE(pr_none.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_SYSTEM, AND));
+
+  size_t opc5 = pr_none.GetOpcodeCount();
+  EXPECT_EQ(2, opc5);
+
+  PolicyGlobal* policy = MakePolicyMemory();
+
+  const uint32 kNtFakeNone       = 4;
+  const uint32 kNtFakeCreateFile = 5;
+  const uint32 kNtFakeOpenFile   = 6;
+
+  LowLevelPolicy policyGen(policy);
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr_pipe));
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr_dump));
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr_winexe));
+
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeOpenFile, &pr_adobe));
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeOpenFile, &pr_pipe));
+
+  EXPECT_TRUE(policyGen.AddRule(kNtFakeNone, &pr_none));
+
+  EXPECT_TRUE(policyGen.Done());
+
+  // Inspect the policy structure manually.
+  EXPECT_TRUE(NULL == policy->entry[0]);
+  EXPECT_TRUE(NULL == policy->entry[1]);
+  EXPECT_TRUE(NULL == policy->entry[2]);
+  EXPECT_TRUE(NULL == policy->entry[3]);
+  EXPECT_TRUE(NULL != policy->entry[4]);  // kNtFakeNone.
+  EXPECT_TRUE(NULL != policy->entry[5]);  // kNtFakeCreateFile.
+  EXPECT_TRUE(NULL != policy->entry[6]);  // kNtFakeOpenFile.
+  EXPECT_TRUE(NULL == policy->entry[7]);
+
+  // The total per service opcode counts now must take in account one
+  // extra opcode (action opcode) per rule.
+  ++opc1;
+  ++opc2;
+  ++opc3;
+  ++opc4;
+  ++opc5;
+
+  size_t tc1 = policy->entry[kNtFakeNone]->opcode_count;
+  size_t tc2 = policy->entry[kNtFakeCreateFile]->opcode_count;
+  size_t tc3 = policy->entry[kNtFakeOpenFile]->opcode_count;
+
+  EXPECT_EQ(opc5, tc1);
+  EXPECT_EQ((opc1 + opc2 + opc3), tc2);
+  EXPECT_EQ((opc1 + opc4), tc3);
+
+  // Check the type of the first and last opcode of each service.
+
+  EXPECT_EQ(OP_NUMBER_AND_MATCH,
+            policy->entry[kNtFakeNone]->opcodes[0].GetID());
+  EXPECT_EQ(OP_ACTION, policy->entry[kNtFakeNone]->opcodes[tc1-1].GetID());
+  EXPECT_EQ(OP_WSTRING_MATCH,
+            policy->entry[kNtFakeCreateFile]->opcodes[0].GetID());
+  EXPECT_EQ(OP_ACTION,
+            policy->entry[kNtFakeCreateFile]->opcodes[tc2-1].GetID());
+  EXPECT_EQ(OP_WSTRING_MATCH,
+            policy->entry[kNtFakeOpenFile]->opcodes[0].GetID());
+  EXPECT_EQ(OP_ACTION, policy->entry[kNtFakeOpenFile]->opcodes[tc3-1].GetID());
+
+  // Test the policy evaluation.
+
+  const wchar_t* filename = L"";
+  uint32 creation_mode = OPEN_EXISTING;
+  uint32 flags = FILE_ATTRIBUTE_NORMAL;
+  void* security_descriptor = NULL;
+
+  POLPARAMS_BEGIN(params)
+    POLPARAM(filename)                // Argument 0
+    POLPARAM(creation_mode)           // Argument 1
+    POLPARAM(flags)                   // Argument 2
+    POLPARAM(security_descriptor)
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor eval_CreateFile(policy->entry[kNtFakeCreateFile]);
+  PolicyProcessor eval_OpenFile(policy->entry[kNtFakeOpenFile]);
+  PolicyProcessor eval_None(policy->entry[kNtFakeNone]);
+
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"\\\\??\\c:\\Windows\\System32\\calc.exe";
+  flags = FILE_ATTRIBUTE_SYSTEM;
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  flags += FILE_ATTRIBUTE_READONLY;
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(GIVE_FIRST, eval_None.GetAction());
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  flags = FILE_ATTRIBUTE_NORMAL;
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(SIGNAL_ALARM, eval_CreateFile.GetAction());
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"c:\\adobe\\ver3.2\\temp";
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(GIVE_CACHED, eval_OpenFile.GetAction());
+
+  filename = L"c:\\adobe\\ver3.22\\temp";
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"\\\\??\\c:\\some path\\other path\\crash reports\\some path";
+  creation_mode = CREATE_ALWAYS;
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, eval_CreateFile.GetAction());
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  filename = L"\\\\??\\Pipe\\Chrome.12345";
+  creation_mode = OPEN_EXISTING;
+  result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(FAKE_SUCCESS, eval_CreateFile.GetAction());
+  result = eval_None.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+  result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(FAKE_SUCCESS, eval_OpenFile.GetAction());
+
+  delete [] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, PolicyRuleCopyConstructorTwoStrings) {
+  SetupNtdllImports();
+  // Both pr_orig and pr_copy should allow hello.* but not *.txt files.
+  PolicyRule pr_orig(ASK_BROKER);
+  EXPECT_TRUE(pr_orig.AddStringMatch(IF, 0, L"hello.*", CASE_SENSITIVE));
+
+  PolicyRule pr_copy(pr_orig);
+  EXPECT_TRUE(pr_orig.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+  EXPECT_TRUE(pr_copy.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+
+  PolicyGlobal* policy = MakePolicyMemory();
+  LowLevelPolicy policyGen(policy);
+  EXPECT_TRUE(policyGen.AddRule(1, &pr_orig));
+  EXPECT_TRUE(policyGen.AddRule(2, &pr_copy));
+  EXPECT_TRUE(policyGen.Done());
+
+  const wchar_t* name = NULL;
+  POLPARAMS_BEGIN(eval_params)
+    POLPARAM(name)
+  POLPARAMS_END;
+
+  PolicyResult result;
+  PolicyProcessor pol_ev_orig(policy->entry[1]);
+  name = L"domo.txt";
+  result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  name = L"hello.bmp";
+  result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev_orig.GetAction());
+
+  PolicyProcessor pol_ev_copy(policy->entry[2]);
+  name = L"domo.txt";
+  result = pol_ev_copy.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(NO_POLICY_MATCH, result);
+
+  name = L"hello.bmp";
+  result = pol_ev_copy.Evaluate(kShortEval, eval_params, _countof(eval_params));
+  EXPECT_EQ(POLICY_MATCH, result);
+  EXPECT_EQ(ASK_BROKER, pol_ev_copy.GetAction());
+}
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_opcodes_unittest.cc b/sandbox/win/src/policy_opcodes_unittest.cc
new file mode 100644
index 0000000..c999348
--- /dev/null
+++ b/sandbox/win/src/policy_opcodes_unittest.cc
@@ -0,0 +1,369 @@
+// 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 "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+#define INIT_GLOBAL_RTL(member) \
+  g_nt.member = reinterpret_cast<member##Function>( \
+  ::GetProcAddress(ntdll, #member)); \
+  if (NULL == g_nt.member) \
+  return false
+
+namespace sandbox {
+
+const size_t kOpcodeMemory = 1024;
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+bool SetupNtdllImports() {
+    HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+
+    INIT_GLOBAL_RTL(RtlAllocateHeap);
+    INIT_GLOBAL_RTL(RtlAnsiStringToUnicodeString);
+    INIT_GLOBAL_RTL(RtlCompareUnicodeString);
+    INIT_GLOBAL_RTL(RtlCreateHeap);
+    INIT_GLOBAL_RTL(RtlDestroyHeap);
+    INIT_GLOBAL_RTL(RtlFreeHeap);
+    INIT_GLOBAL_RTL(_strnicmp);
+    INIT_GLOBAL_RTL(strlen);
+    INIT_GLOBAL_RTL(wcslen);
+
+  return true;
+}
+
+TEST(PolicyEngineTest, ParameterSetTest) {
+  void* pv1 = reinterpret_cast<void*>(0x477EAA5);
+  const void* pv2 = reinterpret_cast<void*>(0x987654);
+  ParameterSet pset1 = ParamPickerMake(pv1);
+  ParameterSet pset2 = ParamPickerMake(pv2);
+
+  // Test that we can store and retrieve a void pointer:
+  const void* result1 =0;
+  uint32 result2 = 0;
+  EXPECT_TRUE(pset1.Get(&result1));
+  EXPECT_TRUE(pv1 == result1);
+  EXPECT_FALSE(pset1.Get(&result2));
+  EXPECT_TRUE(pset2.Get(&result1));
+  EXPECT_TRUE(pv2 == result1);
+  EXPECT_FALSE(pset2.Get(&result2));
+
+  // Test that we can store and retrieve a uint32:
+  uint32 number = 12747;
+  ParameterSet pset3 = ParamPickerMake(number);
+  EXPECT_FALSE(pset3.Get(&result1));
+  EXPECT_TRUE(pset3.Get(&result2));
+  EXPECT_EQ(number, result2);
+
+  // Test that we can store and retrieve a string:
+  const wchar_t* txt = L"S231L";
+  ParameterSet pset4 = ParamPickerMake(txt);
+  const wchar_t* result3 = NULL;
+  EXPECT_TRUE(pset4.Get(&result3));
+  EXPECT_EQ(0, wcscmp(txt, result3));
+}
+
+TEST(PolicyEngineTest, OpcodeConstraints) {
+  // Test that PolicyOpcode has no virtual functions
+  // because these objects are copied over to other processes
+  // so they cannot have vtables.
+  EXPECT_FALSE(__is_polymorphic(PolicyOpcode));
+  // Keep developers from adding smarts to the opcodes which should
+  // be pretty much a bag of bytes with a OO interface.
+  EXPECT_TRUE(__has_trivial_destructor(PolicyOpcode));
+  EXPECT_TRUE(__has_trivial_constructor(PolicyOpcode));
+  EXPECT_TRUE(__has_trivial_copy(PolicyOpcode));
+}
+
+TEST(PolicyEngineTest, TrueFalseOpcodes) {
+  void* dummy = NULL;
+  ParameterSet ppb1 = ParamPickerMake(dummy);
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+  // This opcode always evaluates to true.
+  PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone);
+  ASSERT_NE(nullptr, op1);
+  EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&ppb1, 1, NULL));
+  EXPECT_FALSE(op1->IsAction());
+
+  // This opcode always evaluates to false.
+  PolicyOpcode* op2 = opcode_maker.MakeOpAlwaysTrue(kPolNone);
+  ASSERT_NE(nullptr, op2);
+  EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, NULL));
+
+  // Nulls not allowed on the params.
+  EXPECT_EQ(EVAL_ERROR, op2->Evaluate(NULL, 0, NULL));
+  EXPECT_EQ(EVAL_ERROR, op2->Evaluate(NULL, 1, NULL));
+
+  // True and False opcodes do not 'require' a number of parameters
+  EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 0, NULL));
+  EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, NULL));
+
+  // Test Inverting the logic. Note that inversion is done outside
+  // any particular opcode evaluation so no need to repeat for all
+  // opcodes.
+  PolicyOpcode* op3 = opcode_maker.MakeOpAlwaysFalse(kPolNegateEval);
+  ASSERT_NE(nullptr, op3);
+  EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&ppb1, 1, NULL));
+  PolicyOpcode* op4 = opcode_maker.MakeOpAlwaysTrue(kPolNegateEval);
+  ASSERT_NE(nullptr, op4);
+  EXPECT_EQ(EVAL_FALSE, op4->Evaluate(&ppb1, 1, NULL));
+
+  // Test that we clear the match context
+  PolicyOpcode* op5 = opcode_maker.MakeOpAlwaysTrue(kPolClearContext);
+  ASSERT_NE(nullptr, op5);
+  MatchContext context;
+  context.position = 1;
+  context.options = kPolUseOREval;
+  EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&ppb1, 1, &context));
+  EXPECT_EQ(0, context.position);
+  MatchContext context2;
+  EXPECT_EQ(context2.options, context.options);
+}
+
+TEST(PolicyEngineTest, OpcodeMakerCase1) {
+  // Testing that the opcode maker does not overrun the
+  // supplied buffer. It should only be able to make 'count' opcodes.
+  void* dummy = NULL;
+  ParameterSet ppb1 = ParamPickerMake(dummy);
+
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+  size_t count = sizeof(memory) / sizeof(PolicyOpcode);
+
+  for (size_t ix =0; ix != count; ++ix) {
+    PolicyOpcode* op = opcode_maker.MakeOpAlwaysFalse(kPolNone);
+    ASSERT_NE(nullptr, op);
+    EXPECT_EQ(EVAL_FALSE, op->Evaluate(&ppb1, 1, NULL));
+  }
+  // There should be no room more another opcode:
+  PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone);
+  ASSERT_EQ(nullptr, op1);
+}
+
+TEST(PolicyEngineTest, OpcodeMakerCase2) {
+  SetupNtdllImports();
+  // Testing that the opcode maker does not overrun the
+  // supplied buffer. It should only be able to make 'count' opcodes.
+  // The difference with the previous test is that this opcodes allocate
+  // the string 'txt2' inside the same buffer.
+  const wchar_t* txt1 = L"1234";
+  const wchar_t txt2[] = L"123";
+
+  ParameterSet ppb1 = ParamPickerMake(txt1);
+  MatchContext mc1;
+
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+  size_t count = sizeof(memory) / (sizeof(PolicyOpcode) + sizeof(txt2));
+
+  // Test that it does not overrun the buffer.
+  for (size_t ix =0; ix != count; ++ix) {
+    PolicyOpcode* op = opcode_maker.MakeOpWStringMatch(0, txt2, 0,
+                                                       CASE_SENSITIVE,
+                                                       kPolClearContext);
+    ASSERT_NE(nullptr, op);
+    EXPECT_EQ(EVAL_TRUE, op->Evaluate(&ppb1, 1, &mc1));
+  }
+
+  // There should be no room more another opcode:
+  PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0,
+                                                      CASE_SENSITIVE,
+                                                      kPolNone);
+  ASSERT_EQ(nullptr, op1);
+}
+
+TEST(PolicyEngineTest, IntegerOpcodes) {
+  const wchar_t* txt = L"abcdef";
+  uint32 num1 = 42;
+  uint32 num2 = 113377;
+
+  ParameterSet pp_wrong1 = ParamPickerMake(txt);
+  ParameterSet pp_num1 = ParamPickerMake(num1);
+  ParameterSet pp_num2 = ParamPickerMake(num2);
+
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+  // Test basic match for uint32s 42 == 42 and 42 != 113377.
+  PolicyOpcode* op_m42 = opcode_maker.MakeOpNumberMatch(0, 42UL, kPolNone);
+  ASSERT_NE(nullptr, op_m42);
+  EXPECT_EQ(EVAL_TRUE, op_m42->Evaluate(&pp_num1, 1, NULL));
+  EXPECT_EQ(EVAL_FALSE, op_m42->Evaluate(&pp_num2, 1, NULL));
+  EXPECT_EQ(EVAL_ERROR, op_m42->Evaluate(&pp_wrong1, 1, NULL));
+
+  // Test basic match for void pointers.
+  const void* vp = NULL;
+  ParameterSet pp_num3 = ParamPickerMake(vp);
+  PolicyOpcode* op_vp_null = opcode_maker.MakeOpVoidPtrMatch(0, NULL,
+                                                             kPolNone);
+  ASSERT_NE(nullptr, op_vp_null);
+  EXPECT_EQ(EVAL_TRUE, op_vp_null->Evaluate(&pp_num3, 1, NULL));
+  EXPECT_EQ(EVAL_FALSE, op_vp_null->Evaluate(&pp_num1, 1, NULL));
+  EXPECT_EQ(EVAL_ERROR, op_vp_null->Evaluate(&pp_wrong1, 1, NULL));
+
+  // Basic range test [41 43] (inclusive).
+  PolicyOpcode* op_range1 =
+      opcode_maker.MakeOpNumberMatchRange(0, 41, 43, kPolNone);
+  ASSERT_NE(nullptr, op_range1);
+  EXPECT_EQ(EVAL_TRUE, op_range1->Evaluate(&pp_num1, 1, NULL));
+  EXPECT_EQ(EVAL_FALSE, op_range1->Evaluate(&pp_num2, 1, NULL));
+  EXPECT_EQ(EVAL_ERROR, op_range1->Evaluate(&pp_wrong1, 1, NULL));
+}
+
+TEST(PolicyEngineTest, LogicalOpcodes) {
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+  uint32 num1 = 0x10100702;
+  ParameterSet pp_num1 = ParamPickerMake(num1);
+
+  PolicyOpcode* op_and1 =
+      opcode_maker.MakeOpNumberAndMatch(0, 0x00100000, kPolNone);
+  ASSERT_NE(nullptr, op_and1);
+  EXPECT_EQ(EVAL_TRUE, op_and1->Evaluate(&pp_num1, 1, NULL));
+  PolicyOpcode* op_and2 =
+      opcode_maker.MakeOpNumberAndMatch(0, 0x00000001, kPolNone);
+  ASSERT_NE(nullptr, op_and2);
+  EXPECT_EQ(EVAL_FALSE, op_and2->Evaluate(&pp_num1, 1, NULL));
+}
+
+TEST(PolicyEngineTest, WCharOpcodes1) {
+  SetupNtdllImports();
+
+  const wchar_t* txt1 = L"the quick fox jumps over the lazy dog";
+  const wchar_t txt2[] = L"the quick";
+  const wchar_t txt3[] = L" fox jumps";
+  const wchar_t txt4[] = L"the lazy dog";
+  const wchar_t txt5[] = L"jumps over";
+  const wchar_t txt6[] = L"g";
+
+  ParameterSet pp_tc1 = ParamPickerMake(txt1);
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+  PolicyOpcode* op1 = opcode_maker.MakeOpWStringMatch(0, txt2, 0,
+                                                      CASE_SENSITIVE,
+                                                      kPolNone);
+  ASSERT_NE(nullptr, op1);
+
+  // Simplest substring match from pos 0. It should be a successful match
+  // and the match context should be updated.
+  MatchContext mc1;
+  EXPECT_EQ(EVAL_TRUE, op1->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_TRUE(_countof(txt2) == mc1.position + 1);
+
+  // Matching again should fail and the context should be unmodified.
+  EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_TRUE(_countof(txt2) == mc1.position + 1);
+
+  // Using the same match context we should continue where we left
+  // in the previous successful match,
+  PolicyOpcode* op3 = opcode_maker.MakeOpWStringMatch(0, txt3, 0,
+                                                      CASE_SENSITIVE,
+                                                      kPolNone);
+  ASSERT_NE(nullptr, op3);
+  EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_TRUE(_countof(txt3) + _countof(txt2) == mc1.position + 2);
+
+  // We now keep on matching but now we skip 6 characters which means
+  // we skip the string ' over '. And we zero the match context. This is
+  // the primitive that we use to build '??'.
+  PolicyOpcode* op4 = opcode_maker.MakeOpWStringMatch(0, txt4, 6,
+                                                      CASE_SENSITIVE,
+                                                      kPolClearContext);
+  ASSERT_NE(nullptr, op4);
+  EXPECT_EQ(EVAL_TRUE, op4->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_EQ(0, mc1.position);
+
+  // Test that we can properly match the last part of the string
+  PolicyOpcode* op4b = opcode_maker.MakeOpWStringMatch(0, txt4, kSeekToEnd,
+                                                       CASE_SENSITIVE,
+                                                       kPolClearContext);
+  ASSERT_NE(nullptr, op4b);
+  EXPECT_EQ(EVAL_TRUE, op4b->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_EQ(0, mc1.position);
+
+  // Test matching 'jumps over' over the entire string. This is the
+  // primitive we build '*' from.
+  PolicyOpcode* op5 = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekForward,
+                                                      CASE_SENSITIVE, kPolNone);
+  ASSERT_NE(nullptr, op5);
+  EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_EQ(24, mc1.position);
+
+  // Test that we don't match because it is not at the end of the string
+  PolicyOpcode* op5b = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekToEnd,
+                                                       CASE_SENSITIVE,
+                                                       kPolNone);
+  ASSERT_NE(nullptr, op5b);
+  EXPECT_EQ(EVAL_FALSE, op5b->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_EQ(24, mc1.position);
+
+  // Test that we function if the string does not fit. In this case we
+  // try to match 'the lazy dog' against 'he lazy dog'.
+  PolicyOpcode* op6 = opcode_maker.MakeOpWStringMatch(0, txt4, 2,
+                                                      CASE_SENSITIVE, kPolNone);
+  ASSERT_NE(nullptr, op6);
+  EXPECT_EQ(EVAL_FALSE, op6->Evaluate(&pp_tc1, 1, &mc1));
+
+  // Testing matching against 'g' which should be the last char.
+  MatchContext mc2;
+  PolicyOpcode* op7 = opcode_maker.MakeOpWStringMatch(0, txt6, kSeekForward,
+                                                      CASE_SENSITIVE, kPolNone);
+  ASSERT_NE(nullptr, op7);
+  EXPECT_EQ(EVAL_TRUE, op7->Evaluate(&pp_tc1, 1, &mc2));
+  EXPECT_EQ(37, mc2.position);
+
+  // Trying to match again should fail since we are in the last char.
+  // This also covers a couple of boundary conditions.
+  EXPECT_EQ(EVAL_FALSE, op7->Evaluate(&pp_tc1, 1, &mc2));
+  EXPECT_EQ(37, mc2.position);
+}
+
+TEST(PolicyEngineTest, WCharOpcodes2) {
+  SetupNtdllImports();
+
+  const wchar_t* path1 = L"c:\\documents and settings\\Microsoft\\BLAH.txt";
+  const wchar_t txt1[] = L"Settings\\microsoft";
+  ParameterSet pp_tc1 = ParamPickerMake(path1);
+
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+  MatchContext mc1;
+
+  // Testing case-insensitive does not buy us much since it this option
+  // is just passed to the Microsoft API that we use normally, but just for
+  // coverage, here it is:
+  PolicyOpcode* op1s = opcode_maker.MakeOpWStringMatch(0, txt1, kSeekForward,
+                                                      CASE_SENSITIVE, kPolNone);
+  ASSERT_NE(nullptr, op1s);
+  PolicyOpcode* op1i = opcode_maker.MakeOpWStringMatch(0, txt1, kSeekForward,
+                                                       CASE_INSENSITIVE,
+                                                       kPolNone);
+  ASSERT_NE(nullptr, op1i);
+  EXPECT_EQ(EVAL_FALSE, op1s->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_EQ(EVAL_TRUE, op1i->Evaluate(&pp_tc1, 1, &mc1));
+  EXPECT_EQ(35, mc1.position);
+}
+
+TEST(PolicyEngineTest, ActionOpcodes) {
+  char memory[kOpcodeMemory];
+  OpcodeFactory opcode_maker(memory, sizeof(memory));
+  MatchContext mc1;
+  void* dummy = NULL;
+  ParameterSet ppb1 = ParamPickerMake(dummy);
+
+  PolicyOpcode* op1 = opcode_maker.MakeOpAction(ASK_BROKER, kPolNone);
+  ASSERT_NE(nullptr, op1);
+  EXPECT_TRUE(op1->IsAction());
+  EXPECT_EQ(ASK_BROKER, op1->Evaluate(&ppb1, 1, &mc1));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_params.h b/sandbox/win/src/policy_params.h
new file mode 100644
index 0000000..e051d2b
--- /dev/null
+++ b/sandbox/win/src/policy_params.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_PARAMS_H__
+#define SANDBOX_SRC_POLICY_PARAMS_H__
+
+#include "sandbox/win/src/policy_engine_params.h"
+
+namespace sandbox {
+
+class ParameterSet;
+
+// Warning: The following macros store the address to the actual variables, in
+// other words, the values are not copied.
+#define POLPARAMS_BEGIN(type) class type { public: enum Args {
+#define POLPARAM(arg) arg,
+#define POLPARAMS_END(type) PolParamLast }; }; \
+  typedef sandbox::ParameterSet type##Array [type::PolParamLast];
+
+// Policy parameters for file open / create.
+POLPARAMS_BEGIN(OpenFile)
+  POLPARAM(NAME)
+  POLPARAM(BROKER)   // TRUE if called from the broker.
+  POLPARAM(ACCESS)
+  POLPARAM(DISPOSITION)
+  POLPARAM(OPTIONS)
+POLPARAMS_END(OpenFile)
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(FileName)
+  POLPARAM(NAME)
+  POLPARAM(BROKER)   // TRUE if called from the broker.
+POLPARAMS_END(FileName)
+
+static_assert(OpenFile::NAME == static_cast<int>(FileName::NAME),
+              "to simplify fs policies");
+static_assert(OpenFile::BROKER == static_cast<int>(FileName::BROKER),
+              "to simplify fs policies");
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(NameBased)
+  POLPARAM(NAME)
+POLPARAMS_END(NameBased)
+
+// Policy parameters for open event.
+POLPARAMS_BEGIN(OpenEventParams)
+  POLPARAM(NAME)
+  POLPARAM(ACCESS)
+POLPARAMS_END(OpenEventParams)
+
+// Policy Parameters for reg open / create.
+POLPARAMS_BEGIN(OpenKey)
+  POLPARAM(NAME)
+  POLPARAM(ACCESS)
+POLPARAMS_END(OpenKey)
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(HandleTarget)
+  POLPARAM(NAME)
+  POLPARAM(TARGET)
+POLPARAMS_END(HandleTarget)
+
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_PARAMS_H__
diff --git a/sandbox/win/src/policy_target.cc b/sandbox/win/src/policy_target.cc
new file mode 100644
index 0000000..fb464cc
--- /dev/null
+++ b/sandbox/win/src/policy_target.cc
@@ -0,0 +1,117 @@
+// 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 "sandbox/win/src/policy_target.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+// Handle for our private heap.
+extern void* g_heap;
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Policy data.
+extern void* volatile     g_shared_policy_memory;
+SANDBOX_INTERCEPT size_t  g_shared_policy_size;
+
+bool QueryBroker(int ipc_id, CountedParameterSetBase* params) {
+  DCHECK_NT(static_cast<size_t>(ipc_id) < kMaxServiceCount);
+  DCHECK_NT(g_shared_policy_memory);
+  DCHECK_NT(g_shared_policy_size > 0);
+
+  if (static_cast<size_t>(ipc_id) >= kMaxServiceCount)
+    return false;
+
+  PolicyGlobal* global_policy =
+      reinterpret_cast<PolicyGlobal*>(g_shared_policy_memory);
+
+  if (!global_policy->entry[ipc_id])
+    return false;
+
+  PolicyBuffer* policy = reinterpret_cast<PolicyBuffer*>(
+      reinterpret_cast<char*>(g_shared_policy_memory) +
+      reinterpret_cast<size_t>(global_policy->entry[ipc_id]));
+
+  if ((reinterpret_cast<size_t>(global_policy->entry[ipc_id]) >
+       global_policy->data_size) ||
+      (g_shared_policy_size < global_policy->data_size)) {
+    NOTREACHED_NT();
+    return false;
+  }
+
+  for (int i = 0; i < params->count; i++) {
+    if (!params->parameters[i].IsValid()) {
+      NOTREACHED_NT();
+      return false;
+    }
+  }
+
+  PolicyProcessor processor(policy);
+  PolicyResult result = processor.Evaluate(kShortEval, params->parameters,
+                                           params->count);
+  DCHECK_NT(POLICY_ERROR != result);
+
+  return POLICY_MATCH == result && ASK_BROKER == processor.GetAction();
+}
+
+// -----------------------------------------------------------------------
+
+// Hooks NtSetInformationThread to block RevertToSelf from being
+// called before the actual call to LowerToken.
+NTSTATUS WINAPI TargetNtSetInformationThread(
+    NtSetInformationThreadFunction orig_SetInformationThread, HANDLE thread,
+    NT_THREAD_INFORMATION_CLASS thread_info_class, PVOID thread_information,
+    ULONG thread_information_bytes) {
+  do {
+    if (SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+      break;
+    if (ThreadImpersonationToken != thread_info_class)
+      break;
+    // This is a revert to self.
+    return STATUS_SUCCESS;
+  } while (false);
+
+  return orig_SetInformationThread(thread, thread_info_class,
+                                   thread_information,
+                                   thread_information_bytes);
+}
+
+// Hooks NtOpenThreadToken to force the open_as_self parameter to be set to
+// FALSE if we are still running with the impersonation token. open_as_self set
+// to TRUE means that the token will be open using the process token instead of
+// the impersonation token. This is bad because the process token does not have
+// access to open the thread token.
+NTSTATUS WINAPI TargetNtOpenThreadToken(
+    NtOpenThreadTokenFunction orig_OpenThreadToken, HANDLE thread,
+    ACCESS_MASK desired_access, BOOLEAN open_as_self, PHANDLE token) {
+  if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+    open_as_self = FALSE;
+
+  return orig_OpenThreadToken(thread, desired_access, open_as_self, token);
+}
+
+// See comment for TargetNtOpenThreadToken
+NTSTATUS WINAPI TargetNtOpenThreadTokenEx(
+    NtOpenThreadTokenExFunction orig_OpenThreadTokenEx, HANDLE thread,
+    ACCESS_MASK desired_access, BOOLEAN open_as_self, ULONG handle_attributes,
+    PHANDLE token) {
+  if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+    open_as_self = FALSE;
+
+  return orig_OpenThreadTokenEx(thread, desired_access, open_as_self,
+                                handle_attributes, token);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/policy_target.h b/sandbox/win/src/policy_target.h
new file mode 100644
index 0000000..8a2b437
--- /dev/null
+++ b/sandbox/win/src/policy_target.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_POLICY_TARGET_H__
+#define SANDBOX_SRC_POLICY_TARGET_H__
+
+namespace sandbox {
+
+struct CountedParameterSetBase;
+
+// Performs a policy lookup and returns true if the request should be passed to
+// the broker process.
+bool QueryBroker(int ipc_id, CountedParameterSetBase* params);
+
+extern "C" {
+
+// Interception of NtSetInformationThread on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtSetInformationThread(
+    NtSetInformationThreadFunction orig_SetInformationThread, HANDLE thread,
+    NT_THREAD_INFORMATION_CLASS thread_info_class, PVOID thread_information,
+    ULONG thread_information_bytes);
+
+// Interception of NtOpenThreadToken on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThreadToken(
+    NtOpenThreadTokenFunction orig_OpenThreadToken, HANDLE thread,
+    ACCESS_MASK desired_access, BOOLEAN open_as_self, PHANDLE token);
+
+// Interception of NtOpenThreadTokenEx on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThreadTokenEx(
+    NtOpenThreadTokenExFunction orig_OpenThreadTokenEx, HANDLE thread,
+    ACCESS_MASK desired_access, BOOLEAN open_as_self, ULONG handle_attributes,
+    PHANDLE token);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_TARGET_H__
diff --git a/sandbox/win/src/policy_target_test.cc b/sandbox/win/src/policy_target_test.cc
new file mode 100644
index 0000000..4395a4f
--- /dev/null
+++ b/sandbox/win/src/policy_target_test.cc
@@ -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.
+
+#include "base/memory/shared_memory.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+#define BINDNTDLL(name) \
+    name ## Function name = reinterpret_cast<name ## Function>( \
+      ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
+
+// Reverts to self and verify that SetInformationToken was faked. Returns
+// SBOX_TEST_SUCCEEDED if faked and SBOX_TEST_FAILED if not faked.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token(int argc, wchar_t **argv) {
+  HANDLE thread_token;
+  // Get the thread token, using impersonation.
+  if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
+                             TOKEN_DUPLICATE, FALSE, &thread_token))
+    return ::GetLastError();
+
+  ::RevertToSelf();
+  ::CloseHandle(thread_token);
+
+  int ret = SBOX_TEST_FAILED;
+  if (::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+                        FALSE, &thread_token)) {
+    ret = SBOX_TEST_SUCCEEDED;
+    ::CloseHandle(thread_token);
+  }
+  return ret;
+}
+
+// Stores the high privilege token on a static variable, change impersonation
+// again to that one and verify that we are not interfering anymore with
+// RevertToSelf.
+SBOX_TESTS_COMMAND int PolicyTargetTest_steal(int argc, wchar_t **argv) {
+  static HANDLE thread_token;
+  if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
+    if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
+                               TOKEN_DUPLICATE, FALSE, &thread_token))
+      return ::GetLastError();
+  } else {
+    if (!::SetThreadToken(NULL, thread_token))
+      return ::GetLastError();
+
+    // See if we fake the call again.
+    int ret = PolicyTargetTest_token(argc, argv);
+    ::CloseHandle(thread_token);
+    return ret;
+  }
+  return 0;
+}
+
+// Opens the thread token with and without impersonation.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token2(int argc, wchar_t **argv) {
+  HANDLE thread_token;
+  // Get the thread token, using impersonation.
+  if (!::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE |
+                             TOKEN_DUPLICATE, FALSE, &thread_token))
+    return ::GetLastError();
+  ::CloseHandle(thread_token);
+
+  // Get the thread token, without impersonation.
+  if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+                       TRUE, &thread_token))
+    return ::GetLastError();
+  ::CloseHandle(thread_token);
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Opens the thread token with and without impersonation, using
+// NtOpenThreadTokenEX.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token3(int argc, wchar_t **argv) {
+  BINDNTDLL(NtOpenThreadTokenEx);
+  if (!NtOpenThreadTokenEx)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  HANDLE thread_token;
+  // Get the thread token, using impersonation.
+  NTSTATUS status = NtOpenThreadTokenEx(GetCurrentThread(),
+                                        TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+                                        FALSE, 0, &thread_token);
+  if (status == STATUS_NO_TOKEN)
+    return ERROR_NO_TOKEN;
+  if (!NT_SUCCESS(status))
+    return SBOX_TEST_FAILED;
+
+  ::CloseHandle(thread_token);
+
+  // Get the thread token, without impersonation.
+  status = NtOpenThreadTokenEx(GetCurrentThread(),
+                               TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, 0,
+                               &thread_token);
+  if (!NT_SUCCESS(status))
+    return SBOX_TEST_FAILED;
+
+  ::CloseHandle(thread_token);
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests that we can open the current thread.
+SBOX_TESTS_COMMAND int PolicyTargetTest_thread(int argc, wchar_t **argv) {
+  DWORD thread_id = ::GetCurrentThreadId();
+  HANDLE thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
+  if (!thread)
+    return ::GetLastError();
+  if (!::CloseHandle(thread))
+    return ::GetLastError();
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// New thread entry point: do  nothing.
+DWORD WINAPI PolicyTargetTest_thread_main(void* param) {
+  ::Sleep(INFINITE);
+  return 0;
+}
+
+// Tests that we can create a new thread, and open it.
+SBOX_TESTS_COMMAND int PolicyTargetTest_thread2(int argc, wchar_t **argv) {
+  // Use default values to create a new thread.
+  DWORD thread_id;
+  HANDLE thread = ::CreateThread(NULL, 0, &PolicyTargetTest_thread_main, 0, 0,
+                                 &thread_id);
+  if (!thread)
+    return ::GetLastError();
+  if (!::CloseHandle(thread))
+    return ::GetLastError();
+
+  thread = ::OpenThread(SYNCHRONIZE, FALSE, thread_id);
+  if (!thread)
+    return ::GetLastError();
+
+  if (!::CloseHandle(thread))
+    return ::GetLastError();
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests that we can call CreateProcess.
+SBOX_TESTS_COMMAND int PolicyTargetTest_process(int argc, wchar_t **argv) {
+  // Use default values to create a new process.
+  STARTUPINFO startup_info = {0};
+  startup_info.cb = sizeof(startup_info);
+  PROCESS_INFORMATION temp_process_info = {};
+  // Note: CreateProcessW() can write to its lpCommandLine, don't pass a
+  // raw string literal.
+  base::string16 writable_cmdline_str(L"foo.exe");
+  if (!::CreateProcessW(L"foo.exe", &writable_cmdline_str[0], NULL, NULL, FALSE,
+                        0, NULL, NULL, &startup_info, &temp_process_info))
+    return SBOX_TEST_SUCCEEDED;
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+  return SBOX_TEST_FAILED;
+}
+
+TEST(PolicyTargetTest, SetInformationThread) {
+  TestRunner runner;
+  if (base::win::GetVersion() >= base::win::VERSION_XP) {
+    runner.SetTestState(BEFORE_REVERT);
+    EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token"));
+  }
+
+  runner.SetTestState(AFTER_REVERT);
+  EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token"));
+
+  runner.SetTestState(EVERY_STATE);
+  if (base::win::GetVersion() >= base::win::VERSION_XP)
+    EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"PolicyTargetTest_steal"));
+}
+
+TEST(PolicyTargetTest, OpenThreadToken) {
+  TestRunner runner;
+  if (base::win::GetVersion() >= base::win::VERSION_XP) {
+    runner.SetTestState(BEFORE_REVERT);
+    EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token2"));
+  }
+
+  runner.SetTestState(AFTER_REVERT);
+  EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token2"));
+}
+
+TEST(PolicyTargetTest, OpenThreadTokenEx) {
+  TestRunner runner;
+  if (base::win::GetVersion() < base::win::VERSION_XP)
+    return;
+
+  runner.SetTestState(BEFORE_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token3"));
+
+  runner.SetTestState(AFTER_REVERT);
+  EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token3"));
+}
+
+TEST(PolicyTargetTest, OpenThread) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread")) <<
+      "Opens the current thread";
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread2")) <<
+      "Creates a new thread and opens it";
+}
+
+TEST(PolicyTargetTest, OpenProcess) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_process")) <<
+      "Opens a process";
+}
+
+// Launches the app in the sandbox and ask it to wait in an
+// infinite loop. Waits for 2 seconds and then check if the
+// desktop associated with the app thread is not the same as the
+// current desktop.
+TEST(PolicyTargetTest, DesktopPolicy) {
+  BrokerServices* broker = GetBroker();
+
+  // Precreate the desktop.
+  TargetPolicy* temp_policy = broker->CreatePolicy();
+  temp_policy->CreateAlternateDesktop(false);
+  temp_policy->Release();
+
+  ASSERT_TRUE(broker != NULL);
+
+  // Get the path to the sandboxed app.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+
+  base::string16 arguments(L"\"");
+  arguments += prog_name;
+  arguments += L"\" -child 0 wait";  // Don't care about the "state" argument.
+
+  // Launch the app.
+  ResultCode result = SBOX_ALL_OK;
+  base::win::ScopedProcessInformation target;
+
+  TargetPolicy* policy = broker->CreatePolicy();
+  policy->SetAlternateDesktop(false);
+  policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+  PROCESS_INFORMATION temp_process_info = {};
+  result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
+                               &temp_process_info);
+  base::string16 desktop_name = policy->GetAlternateDesktop();
+  policy->Release();
+
+  EXPECT_EQ(SBOX_ALL_OK, result);
+  if (result == SBOX_ALL_OK)
+    target.Set(temp_process_info);
+
+  EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
+
+  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
+
+  EXPECT_NE(::GetThreadDesktop(target.thread_id()),
+            ::GetThreadDesktop(::GetCurrentThreadId()));
+
+  HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
+  EXPECT_TRUE(NULL != desk);
+  EXPECT_TRUE(::CloseDesktop(desk));
+  EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
+
+  ::WaitForSingleObject(target.process_handle(), INFINITE);
+
+  // Close the desktop handle.
+  temp_policy = broker->CreatePolicy();
+  temp_policy->DestroyAlternateDesktop();
+  temp_policy->Release();
+
+  // Make sure the desktop does not exist anymore.
+  desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
+  EXPECT_TRUE(NULL == desk);
+}
+
+// Launches the app in the sandbox and ask it to wait in an
+// infinite loop. Waits for 2 seconds and then check if the
+// winstation associated with the app thread is not the same as the
+// current desktop.
+TEST(PolicyTargetTest, WinstaPolicy) {
+  BrokerServices* broker = GetBroker();
+
+  // Precreate the desktop.
+  TargetPolicy* temp_policy = broker->CreatePolicy();
+  temp_policy->CreateAlternateDesktop(true);
+  temp_policy->Release();
+
+  ASSERT_TRUE(broker != NULL);
+
+  // Get the path to the sandboxed app.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+
+  base::string16 arguments(L"\"");
+  arguments += prog_name;
+  arguments += L"\" -child 0 wait";  // Don't care about the "state" argument.
+
+  // Launch the app.
+  ResultCode result = SBOX_ALL_OK;
+  base::win::ScopedProcessInformation target;
+
+  TargetPolicy* policy = broker->CreatePolicy();
+  policy->SetAlternateDesktop(true);
+  policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+  PROCESS_INFORMATION temp_process_info = {};
+  result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
+                               &temp_process_info);
+  base::string16 desktop_name = policy->GetAlternateDesktop();
+  policy->Release();
+
+  EXPECT_EQ(SBOX_ALL_OK, result);
+  if (result == SBOX_ALL_OK)
+    target.Set(temp_process_info);
+
+  EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
+
+  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(target.process_handle(), 2000));
+
+  EXPECT_NE(::GetThreadDesktop(target.thread_id()),
+            ::GetThreadDesktop(::GetCurrentThreadId()));
+
+  ASSERT_FALSE(desktop_name.empty());
+
+  // Make sure there is a backslash, for the window station name.
+  EXPECT_NE(desktop_name.find_first_of(L'\\'), base::string16::npos);
+
+  // Isolate the desktop name.
+  desktop_name = desktop_name.substr(desktop_name.find_first_of(L'\\') + 1);
+
+  HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, FALSE, DESKTOP_ENUMERATE);
+  // This should fail if the desktop is really on another window station.
+  EXPECT_FALSE(NULL != desk);
+  EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
+
+  ::WaitForSingleObject(target.process_handle(), INFINITE);
+
+  // Close the desktop handle.
+  temp_policy = broker->CreatePolicy();
+  temp_policy->DestroyAlternateDesktop();
+  temp_policy->Release();
+}
+
+// Launches the app in the sandbox and share a handle with it. The app should
+// be able to use the handle.
+TEST(PolicyTargetTest, ShareHandleTest) {
+  // The way we share handles via STARTUPINFOEX does not work on XP.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return;
+
+  BrokerServices* broker = GetBroker();
+  ASSERT_TRUE(broker != NULL);
+
+  base::StringPiece contents = "Hello World";
+  std::string name = "TestSharedMemory";
+  base::SharedMemoryCreateOptions options;
+  options.size = contents.size();
+  options.share_read_only = true;
+  options.name_deprecated = &name;
+  base::SharedMemory writable_shmem;
+  ASSERT_TRUE(writable_shmem.Create(options));
+  ASSERT_TRUE(writable_shmem.Map(options.size));
+  memcpy(writable_shmem.memory(), contents.data(), contents.size());
+
+  base::SharedMemory read_only_view;
+  ASSERT_TRUE(read_only_view.Open(name, true));
+
+  // Get the path to the sandboxed app.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+
+  TargetPolicy* policy = broker->CreatePolicy();
+  void* shared_handle = policy->AddHandleToShare(
+      read_only_view.handle());
+
+  base::string16 arguments(L"\"");
+  arguments += prog_name;
+  arguments += L"\" -child 0 shared_memory_handle ";
+  arguments += base::UintToString16(
+      reinterpret_cast<unsigned int>(shared_handle));
+
+  // Launch the app.
+  ResultCode result = SBOX_ALL_OK;
+  base::win::ScopedProcessInformation target;
+
+  policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+  PROCESS_INFORMATION temp_process_info = {};
+  result = broker->SpawnTarget(prog_name, arguments.c_str(), policy,
+                               &temp_process_info);
+  policy->Release();
+
+  EXPECT_EQ(SBOX_ALL_OK, result);
+  if (result == SBOX_ALL_OK)
+    target.Set(temp_process_info);
+
+  EXPECT_EQ(1, ::ResumeThread(target.thread_handle()));
+
+  EXPECT_EQ(WAIT_TIMEOUT,
+            ::WaitForSingleObject(target.process_handle(), 2000));
+
+  EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
+
+  ::WaitForSingleObject(target.process_handle(), INFINITE);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc
new file mode 100644
index 0000000..d187c55
--- /dev/null
+++ b/sandbox/win/src/process_mitigations.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations.h"
+
+#include <algorithm>
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// Functions for enabling policies.
+typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags);
+
+typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)(
+    PROCESS_MITIGATION_POLICY mitigation_policy,
+    PVOID buffer,
+    SIZE_T length);
+
+typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)(
+    DWORD DirectoryFlags);
+
+}  // namespace
+
+namespace sandbox {
+
+bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
+  if (!CanSetProcessMitigationsPostStartup(flags))
+    return false;
+
+  base::win::Version version = base::win::GetVersion();
+  HMODULE module = ::GetModuleHandleA("kernel32.dll");
+
+  if (version >= base::win::VERSION_VISTA &&
+      (flags & MITIGATION_DLL_SEARCH_ORDER)) {
+    SetDefaultDllDirectoriesFunction set_default_dll_directories =
+        reinterpret_cast<SetDefaultDllDirectoriesFunction>(
+            ::GetProcAddress(module, "SetDefaultDllDirectories"));
+
+    // Check for SetDefaultDllDirectories since it requires KB2533623.
+    if (set_default_dll_directories) {
+      if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) &&
+          ERROR_ACCESS_DENIED != ::GetLastError()) {
+        return false;
+      }
+    }
+  }
+
+  // Set the heap to terminate on corruption
+  if (version >= base::win::VERSION_VISTA &&
+      (flags & MITIGATION_HEAP_TERMINATE)) {
+    if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption,
+                              NULL, 0) &&
+        ERROR_ACCESS_DENIED != ::GetLastError()) {
+      return false;
+    }
+  }
+
+  if (version >= base::win::VERSION_WIN7 &&
+      (flags & MITIGATION_HARDEN_TOKEN_IL_POLICY)) {
+      DWORD error = HardenProcessIntegrityLevelPolicy();
+      if ((error != ERROR_SUCCESS) && (error != ERROR_ACCESS_DENIED))
+        return false;
+  }
+
+#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
+  if (flags & MITIGATION_DEP) {
+    DWORD dep_flags = PROCESS_DEP_ENABLE;
+    // DEP support is quirky on XP, so don't force a failure in that case.
+    const bool return_on_fail = version >= base::win::VERSION_VISTA;
+
+    if (flags & MITIGATION_DEP_NO_ATL_THUNK)
+      dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
+
+    SetProcessDEPPolicyFunction set_process_dep_policy =
+        reinterpret_cast<SetProcessDEPPolicyFunction>(
+            ::GetProcAddress(module, "SetProcessDEPPolicy"));
+    if (set_process_dep_policy) {
+      if (!set_process_dep_policy(dep_flags) &&
+          ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
+        return false;
+      }
+    } else {
+      // We're on XP sp2, so use the less standard approach.
+      // For reference: http://www.uninformed.org/?v=2&a=4
+      static const int MEM_EXECUTE_OPTION_ENABLE = 1;
+      static const int MEM_EXECUTE_OPTION_DISABLE = 2;
+      static const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4;
+      static const int MEM_EXECUTE_OPTION_PERMANENT = 8;
+
+      NtSetInformationProcessFunction set_information_process = NULL;
+      ResolveNTFunctionPtr("NtSetInformationProcess",
+                           &set_information_process);
+      if (!set_information_process)
+        return false;
+      ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT;
+      if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION))
+        dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION;
+      if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
+                                             ProcessExecuteFlags,
+                                             &dep, sizeof(dep))) &&
+          ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
+        return false;
+      }
+    }
+  }
+#endif
+
+  // This is all we can do in Win7 and below.
+  if (version < base::win::VERSION_WIN8)
+    return true;
+
+  SetProcessMitigationPolicyFunction set_process_mitigation_policy =
+      reinterpret_cast<SetProcessMitigationPolicyFunction>(
+          ::GetProcAddress(module, "SetProcessMitigationPolicy"));
+  if (!set_process_mitigation_policy)
+    return false;
+
+  // Enable ASLR policies.
+  if (flags & MITIGATION_RELOCATE_IMAGE) {
+    PROCESS_MITIGATION_ASLR_POLICY policy = { 0 };
+    policy.EnableForceRelocateImages = true;
+    policy.DisallowStrippedImages = (flags &
+        MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
+        MITIGATION_RELOCATE_IMAGE_REQUIRED;
+
+    if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
+                                       sizeof(policy)) &&
+        ERROR_ACCESS_DENIED != ::GetLastError()) {
+      return false;
+    }
+  }
+
+  // Enable strict handle policies.
+  if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
+    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 };
+    policy.HandleExceptionsPermanentlyEnabled =
+        policy.RaiseExceptionOnInvalidHandleReference = true;
+
+    if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
+                                       sizeof(policy)) &&
+        ERROR_ACCESS_DENIED != ::GetLastError()) {
+      return false;
+    }
+  }
+
+  // Enable system call policies.
+  if (flags & MITIGATION_WIN32K_DISABLE) {
+    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 };
+    policy.DisallowWin32kSystemCalls = true;
+
+    if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
+                                       sizeof(policy)) &&
+        ERROR_ACCESS_DENIED != ::GetLastError()) {
+      return false;
+    }
+  }
+
+  // Enable system call policies.
+  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
+    PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 };
+    policy.DisableExtensionPoints = true;
+
+    if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
+                                       &policy, sizeof(policy)) &&
+        ERROR_ACCESS_DENIED != ::GetLastError()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
+                                       DWORD64* policy_flags, size_t* size) {
+  base::win::Version version = base::win::GetVersion();
+
+  *policy_flags = 0;
+#if defined(_WIN64)
+  *size = sizeof(*policy_flags);
+#elif defined(_M_IX86)
+  // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
+  if (version < base::win::VERSION_WIN8)
+    *size = sizeof(DWORD);
+  else
+    *size = sizeof(*policy_flags);
+#else
+#error This platform is not supported.
+#endif
+
+  // Nothing for Win XP or Vista.
+  if (version <= base::win::VERSION_VISTA)
+    return;
+
+  // DEP and SEHOP are not valid for 64-bit Windows
+#if !defined(_WIN64)
+  if (flags & MITIGATION_DEP) {
+    *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE;
+    if (!(flags & MITIGATION_DEP_NO_ATL_THUNK))
+      *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE;
+  }
+
+  if (flags & MITIGATION_SEHOP)
+    *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;
+#endif
+
+  // Win 7
+  if (version < base::win::VERSION_WIN8)
+    return;
+
+  if (flags & MITIGATION_RELOCATE_IMAGE) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
+    if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
+      *policy_flags |=
+          PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
+    }
+  }
+
+  if (flags & MITIGATION_HEAP_TERMINATE) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
+  }
+
+  if (flags & MITIGATION_BOTTOM_UP_ASLR) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
+  }
+
+  if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
+  }
+
+  if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
+  }
+
+  if (flags & MITIGATION_WIN32K_DISABLE) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
+  }
+
+  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
+    *policy_flags |=
+        PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
+  }
+}
+
+MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
+  base::win::Version version = base::win::GetVersion();
+
+  // Windows XP SP2+.
+  if (version < base::win::VERSION_VISTA) {
+    return flags & (MITIGATION_DEP |
+                    MITIGATION_DEP_NO_ATL_THUNK);
+  }
+
+  // Windows Vista
+  if (version < base::win::VERSION_WIN7) {
+    return flags & (MITIGATION_BOTTOM_UP_ASLR |
+                    MITIGATION_DLL_SEARCH_ORDER |
+                    MITIGATION_HEAP_TERMINATE);
+  }
+
+  // Windows 7.
+  if (version < base::win::VERSION_WIN8) {
+    return flags & (MITIGATION_BOTTOM_UP_ASLR |
+                    MITIGATION_DLL_SEARCH_ORDER |
+                    MITIGATION_HEAP_TERMINATE);
+  }
+
+  // Windows 8 and above.
+  return flags & (MITIGATION_BOTTOM_UP_ASLR |
+                  MITIGATION_DLL_SEARCH_ORDER);
+}
+
+bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
+                                               MitigationFlags flags) {
+// This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
+#if !defined(_WIN64)
+  if (flags & MITIGATION_BOTTOM_UP_ASLR) {
+    unsigned int limit;
+    rand_s(&limit);
+    char* ptr = 0;
+    const size_t kMask64k = 0xFFFF;
+    // Random range (512k-16.5mb) in 64k steps.
+    const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k);
+    while (ptr < end) {
+      MEMORY_BASIC_INFORMATION memory_info;
+      if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
+        break;
+      size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k,
+                             static_cast<SIZE_T>(end - ptr));
+      if (ptr && memory_info.State == MEM_FREE)
+        ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS);
+      ptr += size;
+    }
+  }
+#endif
+
+  return true;
+}
+
+bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
+  // All of these mitigations can be enabled after startup.
+  return !(flags & ~(MITIGATION_HEAP_TERMINATE |
+                     MITIGATION_DEP |
+                     MITIGATION_DEP_NO_ATL_THUNK |
+                     MITIGATION_RELOCATE_IMAGE |
+                     MITIGATION_RELOCATE_IMAGE_REQUIRED |
+                     MITIGATION_BOTTOM_UP_ASLR |
+                     MITIGATION_STRICT_HANDLE_CHECKS |
+                     MITIGATION_EXTENSION_DLL_DISABLE |
+                     MITIGATION_DLL_SEARCH_ORDER |
+                     MITIGATION_HARDEN_TOKEN_IL_POLICY));
+}
+
+bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) {
+  // These mitigations cannot be enabled prior to startup.
+  return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS |
+                    MITIGATION_DLL_SEARCH_ORDER));
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations.h b/sandbox/win/src/process_mitigations.h
new file mode 100644
index 0000000..9039ad6
--- /dev/null
+++ b/sandbox/win/src/process_mitigations.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 SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_
+#define SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/security_level.h"
+
+namespace sandbox {
+
+// Sets the mitigation policy for the current process, ignoring any settings
+// that are invalid for the current version of Windows.
+bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags);
+
+// Returns the flags that must be enforced after startup for the current OS
+// version.
+MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags);
+
+// Converts sandbox flags to the PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES
+// policy flags used by UpdateProcThreadAttribute(). The size field varies
+// between a 32-bit and a 64-bit type based on the exact build and version of
+// Windows, so the returned size must be passed to UpdateProcThreadAttribute().
+void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
+                                       DWORD64* policy_flags, size_t* size);
+
+// Adds mitigations that need to be performed on the suspended target process
+// before execution begins.
+bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
+                                               MitigationFlags flags);
+
+// Returns true if all the supplied flags can be set after a process starts.
+bool CanSetProcessMitigationsPostStartup(MitigationFlags flags);
+
+// Returns true if all the supplied flags can be set before a process starts.
+bool CanSetProcessMitigationsPreStartup(MitigationFlags flags);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_
+
diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc
new file mode 100644
index 0000000..4d2e9c6
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_test.cc
@@ -0,0 +1,248 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+#include "base/win/scoped_handle.h"
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+typedef BOOL (WINAPI *GetProcessDEPPolicyFunction)(
+    HANDLE process,
+    LPDWORD flags,
+    PBOOL permanent);
+
+typedef BOOL (WINAPI *GetProcessMitigationPolicyFunction)(
+    HANDLE process,
+    PROCESS_MITIGATION_POLICY mitigation_policy,
+    PVOID buffer,
+    SIZE_T length);
+
+GetProcessMitigationPolicyFunction get_process_mitigation_policy;
+
+bool CheckWin8DepPolicy() {
+  PROCESS_MITIGATION_DEP_POLICY policy;
+  if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDEPPolicy,
+                                     &policy, sizeof(policy))) {
+    return false;
+  }
+  return policy.Enable && policy.Permanent;
+}
+
+bool CheckWin8AslrPolicy() {
+  PROCESS_MITIGATION_ASLR_POLICY policy;
+  if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy,
+                                     &policy, sizeof(policy))) {
+     return false;
+  }
+  return policy.EnableForceRelocateImages && policy.DisallowStrippedImages;
+}
+
+bool CheckWin8StrictHandlePolicy() {
+  PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy;
+  if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                     ProcessStrictHandleCheckPolicy,
+                                     &policy, sizeof(policy))) {
+     return false;
+  }
+  return policy.RaiseExceptionOnInvalidHandleReference &&
+         policy.HandleExceptionsPermanentlyEnabled;
+}
+
+bool CheckWin8Win32CallPolicy() {
+  PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy;
+  if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                     ProcessSystemCallDisablePolicy,
+                                     &policy, sizeof(policy))) {
+     return false;
+  }
+  return policy.DisallowWin32kSystemCalls;
+}
+
+bool CheckWin8DllExtensionPolicy() {
+  PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy;
+  if (!get_process_mitigation_policy(::GetCurrentProcess(),
+                                     ProcessExtensionPointDisablePolicy,
+                                     &policy, sizeof(policy))) {
+     return false;
+  }
+  return policy.DisableExtensionPoints;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t **argv) {
+  get_process_mitigation_policy =
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(
+          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
+                           "GetProcessMitigationPolicy"));
+  if (!get_process_mitigation_policy)
+    return SBOX_TEST_NOT_FOUND;
+
+  if (!CheckWin8DepPolicy())
+    return SBOX_TEST_FIRST_ERROR;
+
+#if defined(NDEBUG)  // ASLR cannot be forced in debug builds.
+  if (!CheckWin8AslrPolicy())
+    return SBOX_TEST_SECOND_ERROR;
+#endif
+
+  if (!CheckWin8StrictHandlePolicy())
+    return SBOX_TEST_THIRD_ERROR;
+
+  if (!CheckWin8DllExtensionPolicy())
+    return SBOX_TEST_FIFTH_ERROR;
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(ProcessMitigationsTest, CheckWin8) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  sandbox::MitigationFlags mitigations = MITIGATION_DEP |
+                                         MITIGATION_DEP_NO_ATL_THUNK |
+                                         MITIGATION_EXTENSION_DLL_DISABLE;
+#if defined(NDEBUG)  // ASLR cannot be forced in debug builds.
+  mitigations |= MITIGATION_RELOCATE_IMAGE |
+                 MITIGATION_RELOCATE_IMAGE_REQUIRED;
+#endif
+
+  EXPECT_EQ(policy->SetProcessMitigations(mitigations), SBOX_ALL_OK);
+
+  mitigations |= MITIGATION_STRICT_HANDLE_CHECKS;
+
+  EXPECT_EQ(policy->SetDelayedProcessMitigations(mitigations), SBOX_ALL_OK);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8"));
+}
+
+
+SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t **argv) {
+  GetProcessDEPPolicyFunction get_process_dep_policy =
+      reinterpret_cast<GetProcessDEPPolicyFunction>(
+          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
+                           "GetProcessDEPPolicy"));
+  if (get_process_dep_policy) {
+    BOOL is_permanent = FALSE;
+    DWORD dep_flags = 0;
+
+    if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags,
+        &is_permanent)) {
+      return SBOX_TEST_FIRST_ERROR;
+    }
+
+    if (!(dep_flags & PROCESS_DEP_ENABLE) || !is_permanent)
+      return SBOX_TEST_SECOND_ERROR;
+
+  } else {
+    NtQueryInformationProcessFunction query_information_process = NULL;
+    ResolveNTFunctionPtr("NtQueryInformationProcess",
+                          &query_information_process);
+    if (!query_information_process)
+      return SBOX_TEST_NOT_FOUND;
+
+    ULONG size = 0;
+    ULONG dep_flags = 0;
+    if (!SUCCEEDED(query_information_process(::GetCurrentProcess(),
+                                             ProcessExecuteFlags, &dep_flags,
+                                             sizeof(dep_flags), &size))) {
+      return SBOX_TEST_THIRD_ERROR;
+    }
+
+    static const int MEM_EXECUTE_OPTION_ENABLE = 1;
+    static const int MEM_EXECUTE_OPTION_DISABLE = 2;
+    static const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4;
+    static const int MEM_EXECUTE_OPTION_PERMANENT = 8;
+    dep_flags &= 0xff;
+
+    if (dep_flags != (MEM_EXECUTE_OPTION_DISABLE |
+                      MEM_EXECUTE_OPTION_PERMANENT)) {
+      return SBOX_TEST_FOURTH_ERROR;
+    }
+  }
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
+#if !defined(_WIN64)  // DEP is always enabled on 64-bit.
+TEST(ProcessMitigationsTest, CheckDep) {
+  if (base::win::GetVersion() > base::win::VERSION_WIN7)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(
+                MITIGATION_DEP |
+                MITIGATION_DEP_NO_ATL_THUNK |
+                MITIGATION_SEHOP),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep"));
+}
+#endif
+
+SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t **argv) {
+  get_process_mitigation_policy =
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(
+          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
+                           "GetProcessMitigationPolicy"));
+  if (!get_process_mitigation_policy)
+    return SBOX_TEST_NOT_FOUND;
+
+  if (!CheckWin8Win32CallPolicy())
+    return SBOX_TEST_FIRST_ERROR;
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation on
+// the target process causes the launch to fail in process initialization.
+// The test process itself links against user32/gdi32.
+TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownFailure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
+}
+
+// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation
+// along with the policy to fake user32 and gdi32 initialization successfully
+// launches the target process.
+// The test process itself links against user32/gdi32.
+TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownSuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
+                            sandbox::TargetPolicy::FAKE_USER_GDI_INIT, NULL),
+            sandbox::SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_dispatcher.cc b/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
new file mode 100644
index 0000000..e426084
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+
+namespace sandbox {
+
+ProcessMitigationsWin32KDispatcher::ProcessMitigationsWin32KDispatcher(
+    PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+}
+
+bool ProcessMitigationsWin32KDispatcher::SetupService(
+    InterceptionManager* manager, int service) {
+  if (!(policy_base_->GetProcessMitigations() &
+        sandbox::MITIGATION_WIN32K_DISABLE)) {
+    return false;
+  }
+
+  switch (service) {
+    case IPC_GDI_GDIDLLINITIALIZE_TAG: {
+      if (!INTERCEPT_EAT(manager, L"gdi32.dll", GdiDllInitialize,
+                         GDIINITIALIZE_ID, 12)) {
+        return false;
+      }
+      return true;
+    }
+
+    case IPC_GDI_GETSTOCKOBJECT_TAG: {
+      if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetStockObject,
+                         GETSTOCKOBJECT_ID, 8)) {
+        return false;
+      }
+      return true;
+    }
+
+    case IPC_USER_REGISTERCLASSW_TAG: {
+      if (!INTERCEPT_EAT(manager, L"user32.dll", RegisterClassW,
+                         REGISTERCLASSW_ID, 8)) {
+        return false;
+      }
+      return true;
+    }
+
+    default:
+      break;
+  }
+  return false;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_dispatcher.h b/sandbox/win/src/process_mitigations_win32k_dispatcher.h
new file mode 100644
index 0000000..2e1e1a8
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_dispatcher.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class sets up intercepts for the Win32K lockdown policy which is set
+// on Windows 8 and beyond.
+class ProcessMitigationsWin32KDispatcher : public Dispatcher {
+ public:
+  explicit ProcessMitigationsWin32KDispatcher(PolicyBase* policy_base);
+  ~ProcessMitigationsWin32KDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  PolicyBase* policy_base_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMitigationsWin32KDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
diff --git a/sandbox/win/src/process_mitigations_win32k_interception.cc b/sandbox/win/src/process_mitigations_win32k_interception.cc
new file mode 100644
index 0000000..ee24fbf
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_interception.cc
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+
+namespace sandbox {
+
+BOOL WINAPI TargetGdiDllInitialize(
+    GdiDllInitializeFunction orig_gdi_dll_initialize,
+    HANDLE dll,
+    DWORD reason) {
+  return TRUE;
+}
+
+HGDIOBJ WINAPI TargetGetStockObject(
+    GetStockObjectFunction orig_get_stock_object,
+    int object) {
+  return reinterpret_cast<HGDIOBJ>(NULL);
+}
+
+ATOM WINAPI TargetRegisterClassW(
+    RegisterClassWFunction orig_register_class_function,
+    const WNDCLASS* wnd_class) {
+  return TRUE;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_interception.h b/sandbox/win/src/process_mitigations_win32k_interception.h
new file mode 100644
index 0000000..bf7b551
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_interception.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+typedef BOOL (WINAPI* GdiDllInitializeFunction) (
+    HANDLE dll,
+    DWORD reason,
+    LPVOID reserved);
+
+typedef HGDIOBJ (WINAPI *GetStockObjectFunction) (int object);
+
+typedef ATOM (WINAPI *RegisterClassWFunction) (const WNDCLASS* wnd_class);
+
+// Interceptor for the  GdiDllInitialize function.
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize(
+    GdiDllInitializeFunction orig_gdi_dll_initialize,
+    HANDLE dll,
+    DWORD reason);
+
+// Interceptor for the GetStockObject function.
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject(
+    GetStockObjectFunction orig_get_stock_object,
+    int object);
+
+// Interceptor for the RegisterClassW function.
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW(
+    RegisterClassWFunction orig_register_class_function,
+    const WNDCLASS* wnd_class);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+
diff --git a/sandbox/win/src/process_mitigations_win32k_policy.cc b/sandbox/win/src/process_mitigations_win32k_policy.cc
new file mode 100644
index 0000000..af18c54
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_policy.cc
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+
+namespace sandbox {
+
+bool ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+    const wchar_t* name,
+    TargetPolicy::Semantics semantics,
+    LowLevelPolicy* policy) {
+  PolicyRule rule(FAKE_SUCCESS);
+  if (!policy->AddRule(IPC_GDI_GDIDLLINITIALIZE_TAG, &rule))
+    return false;
+  if (!policy->AddRule(IPC_GDI_GETSTOCKOBJECT_TAG, &rule))
+    return false;
+  if (!policy->AddRule(IPC_USER_REGISTERCLASSW_TAG, &rule))
+    return false;
+  return true;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_policy.h b/sandbox/win/src/process_mitigations_win32k_policy.h
new file mode 100644
index 0000000..078ed2b
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_policy.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to the process
+// mitigations Win32K lockdown policy.
+class ProcessMitigationsWin32KLockdownPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule for the Win32K process mitigation policy.
+  // name is the object name, semantics is the desired semantics for the
+  // open or create and policy is the policy generator to which the rules are
+  // going to be added.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+
+
diff --git a/sandbox/win/src/process_policy_test.cc b/sandbox/win/src/process_policy_test.cc
new file mode 100644
index 0000000..44effa3
--- /dev/null
+++ b/sandbox/win/src/process_policy_test.cc
@@ -0,0 +1,385 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// While the shell API provides better calls than this home brew function
+// we use GetSystemWindowsDirectoryW which does not query the registry so
+// it is safe to use after revert.
+base::string16 MakeFullPathToSystem32(const wchar_t* name) {
+  wchar_t windows_path[MAX_PATH] = {0};
+  ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH);
+  base::string16 full_path(windows_path);
+  if (full_path.empty()) {
+    return full_path;
+  }
+  full_path += L"\\system32\\";
+  full_path += name;
+  return full_path;
+}
+
+// Creates a process with the |exe| and |command| parameter using the
+// unicode and ascii version of the api.
+sandbox::SboxTestResult CreateProcessHelper(const base::string16& exe,
+                                            const base::string16& command) {
+  base::win::ScopedProcessInformation pi;
+  STARTUPINFOW si = {sizeof(si)};
+
+  const wchar_t *exe_name = NULL;
+  if (!exe.empty())
+    exe_name = exe.c_str();
+
+  base::string16 writable_command = command;
+
+  // Create the process with the unicode version of the API.
+  sandbox::SboxTestResult ret1 = sandbox::SBOX_TEST_FAILED;
+  PROCESS_INFORMATION temp_process_info = {};
+  if (::CreateProcessW(exe_name,
+                       command.empty() ? NULL : &writable_command[0],
+                       NULL,
+                       NULL,
+                       FALSE,
+                       0,
+                       NULL,
+                       NULL,
+                       &si,
+                       &temp_process_info)) {
+    pi.Set(temp_process_info);
+    ret1 = sandbox::SBOX_TEST_SUCCEEDED;
+  } else {
+    DWORD last_error = GetLastError();
+    if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
+        (ERROR_ACCESS_DENIED == last_error) ||
+        (ERROR_FILE_NOT_FOUND == last_error)) {
+      ret1 = sandbox::SBOX_TEST_DENIED;
+    } else {
+      ret1 = sandbox::SBOX_TEST_FAILED;
+    }
+  }
+
+  pi.Close();
+
+  // Do the same with the ansi version of the api
+  STARTUPINFOA sia = {sizeof(sia)};
+  sandbox::SboxTestResult ret2 = sandbox::SBOX_TEST_FAILED;
+
+  std::string narrow_cmd_line =
+      base::SysWideToMultiByte(command.c_str(), CP_UTF8);
+  if (::CreateProcessA(
+        exe_name ? base::SysWideToMultiByte(exe_name, CP_UTF8).c_str() : NULL,
+        command.empty() ? NULL : &narrow_cmd_line[0],
+        NULL, NULL, FALSE, 0, NULL, NULL, &sia, &temp_process_info)) {
+    pi.Set(temp_process_info);
+    ret2 = sandbox::SBOX_TEST_SUCCEEDED;
+  } else {
+    DWORD last_error = GetLastError();
+    if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
+        (ERROR_ACCESS_DENIED == last_error) ||
+        (ERROR_FILE_NOT_FOUND == last_error)) {
+      ret2 = sandbox::SBOX_TEST_DENIED;
+    } else {
+      ret2 = sandbox::SBOX_TEST_FAILED;
+    }
+  }
+
+  if (ret1 == ret2)
+    return ret1;
+
+  return sandbox::SBOX_TEST_FAILED;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int Process_RunApp1(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  base::string16 path = MakeFullPathToSystem32(argv[0]);
+
+  // TEST 1: Try with the path in the app_name.
+  return CreateProcessHelper(path, base::string16());
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp2(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  base::string16 path = MakeFullPathToSystem32(argv[0]);
+
+  // TEST 2: Try with the path in the cmd_line.
+  base::string16 cmd_line = L"\"";
+  cmd_line += path;
+  cmd_line += L"\"";
+  return CreateProcessHelper(base::string16(), cmd_line);
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp3(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  // TEST 3: Try file name in the cmd_line.
+  return CreateProcessHelper(base::string16(), argv[0]);
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp4(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  // TEST 4: Try file name in the app_name and current directory sets correctly.
+  base::string16 system32 = MakeFullPathToSystem32(L"");
+  wchar_t current_directory[MAX_PATH + 1];
+  DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
+  if (!ret)
+    return SBOX_TEST_FIRST_ERROR;
+  if (ret >= MAX_PATH)
+    return SBOX_TEST_FAILED;
+
+  current_directory[ret] = L'\\';
+  current_directory[ret+1] = L'\0';
+  if (!::SetCurrentDirectory(system32.c_str())) {
+    return SBOX_TEST_SECOND_ERROR;
+  }
+
+  const int result4 = CreateProcessHelper(argv[0], base::string16());
+  return ::SetCurrentDirectory(current_directory) ? result4 : SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp5(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  base::string16 path = MakeFullPathToSystem32(argv[0]);
+
+  // TEST 5: Try with the path in the cmd_line and arguments.
+  base::string16 cmd_line = L"\"";
+  cmd_line += path;
+  cmd_line += L"\" /I";
+  return CreateProcessHelper(base::string16(), cmd_line);
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp6(int argc, wchar_t **argv) {
+  if (argc != 1) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+  if ((NULL == argv) || (NULL == argv[0])) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  // TEST 6: Try with the file_name in the cmd_line and arguments.
+  base::string16 cmd_line = argv[0];
+  cmd_line += L" /I";
+  return CreateProcessHelper(base::string16(), cmd_line);
+}
+
+// Creates a process and checks if it's possible to get a handle to it's token.
+SBOX_TESTS_COMMAND int Process_GetChildProcessToken(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  if ((NULL == argv) || (NULL == argv[0]))
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::string16 path = MakeFullPathToSystem32(argv[0]);
+
+  STARTUPINFOW si = {sizeof(si)};
+
+  PROCESS_INFORMATION temp_process_info = {};
+  if (!::CreateProcessW(path.c_str(), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,
+                        NULL, NULL, &si, &temp_process_info)) {
+      return SBOX_TEST_FAILED;
+  }
+  base::win::ScopedProcessInformation pi(temp_process_info);
+
+  HANDLE token = NULL;
+  BOOL result =
+      ::OpenProcessToken(pi.process_handle(), TOKEN_IMPERSONATE, &token);
+  DWORD error = ::GetLastError();
+
+  base::win::ScopedHandle token_handle(token);
+
+  if (!::TerminateProcess(pi.process_handle(), 0))
+    return SBOX_TEST_FAILED;
+
+  if (result && token)
+    return SBOX_TEST_SUCCEEDED;
+
+  if (ERROR_ACCESS_DENIED == error)
+    return SBOX_TEST_DENIED;
+
+  return SBOX_TEST_FAILED;
+}
+
+
+SBOX_TESTS_COMMAND int Process_OpenToken(int argc, wchar_t **argv) {
+  HANDLE token;
+  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
+    if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+      return SBOX_TEST_DENIED;
+    }
+  } else {
+    ::CloseHandle(token);
+    return SBOX_TEST_SUCCEEDED;
+  }
+
+  return SBOX_TEST_FAILED;
+}
+
+TEST(ProcessPolicyTest, TestAllAccess) {
+  // Check if the "all access" rule fails to be added when the token is too
+  // powerful.
+  TestRunner runner;
+
+  // Check the failing case.
+  runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+  EXPECT_EQ(SBOX_ERROR_UNSUPPORTED,
+            runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
+                                        TargetPolicy::PROCESS_ALL_EXEC,
+                                        L"this is not important"));
+
+  // Check the working case.
+  runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_INTERACTIVE);
+
+  EXPECT_EQ(SBOX_ALL_OK,
+            runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
+                                        TargetPolicy::PROCESS_ALL_EXEC,
+                                        L"this is not important"));
+}
+
+TEST(ProcessPolicyTest, CreateProcessAW) {
+  TestRunner runner;
+  base::string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
+  base::string16 system32 = MakeFullPathToSystem32(L"");
+  ASSERT_TRUE(!exe_path.empty());
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+                             TargetPolicy::PROCESS_MIN_EXEC,
+                             exe_path.c_str()));
+
+  // Need to add directory rules for the directories that we use in
+  // SetCurrentDirectory.
+  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY,
+                               system32.c_str()));
+
+  wchar_t current_directory[MAX_PATH];
+  DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
+  ASSERT_TRUE(0 != ret && ret < MAX_PATH);
+
+  wcscat_s(current_directory, MAX_PATH, L"\\");
+  EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY,
+                               current_directory));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp1 calc.exe"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp2 calc.exe"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp3 calc.exe"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp5 calc.exe"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp6 calc.exe"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_RunApp1 findstr.exe"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_RunApp2 findstr.exe"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_RunApp3 findstr.exe"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_RunApp5 findstr.exe"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_RunApp6 findstr.exe"));
+
+#if !defined(_WIN64)
+  if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
+    // WinXP results are not reliable.
+    EXPECT_EQ(SBOX_TEST_SECOND_ERROR,
+        runner.RunTest(L"Process_RunApp4 calc.exe"));
+    EXPECT_EQ(SBOX_TEST_SECOND_ERROR,
+        runner.RunTest(L"Process_RunApp4 findstr.exe"));
+  }
+#endif
+}
+
+TEST(ProcessPolicyTest, OpenToken) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_OpenToken"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMinAccess) {
+  TestRunner runner;
+  base::string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
+  ASSERT_TRUE(!exe_path.empty());
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+                             TargetPolicy::PROCESS_MIN_EXEC,
+                             exe_path.c_str()));
+
+  EXPECT_EQ(SBOX_TEST_DENIED,
+            runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccess) {
+  TestRunner runner(JOB_UNPROTECTED, USER_INTERACTIVE, USER_INTERACTIVE);
+  base::string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
+  ASSERT_TRUE(!exe_path.empty());
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+                             TargetPolicy::PROCESS_ALL_EXEC,
+                             exe_path.c_str()));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMinAccessNoJob) {
+  TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+  base::string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
+  ASSERT_TRUE(!exe_path.empty());
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+                             TargetPolicy::PROCESS_MIN_EXEC,
+                             exe_path.c_str()));
+
+  EXPECT_EQ(SBOX_TEST_DENIED,
+            runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccessNoJob) {
+  TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
+  base::string16 exe_path = MakeFullPathToSystem32(L"findstr.exe");
+  ASSERT_TRUE(!exe_path.empty());
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+                             TargetPolicy::PROCESS_ALL_EXEC,
+                             exe_path.c_str()));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_thread_dispatcher.cc b/sandbox/win/src/process_thread_dispatcher.cc
new file mode 100644
index 0000000..ca17d49
--- /dev/null
+++ b/sandbox/win/src/process_thread_dispatcher.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_thread_dispatcher.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/process_thread_policy.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace {
+
+// Extracts the application name from a command line.
+//
+// The application name is the first element of the command line. If
+// there is no quotes, the first element is delimited by the first space.
+// If there are quotes, the first element is delimited by the quotes.
+//
+// The create process call is smarter than us. It tries really hard to launch
+// the process even if the command line is wrong. For example:
+// "c:\program files\test param" will first try to launch c:\program.exe then
+// c:\program files\test.exe. We don't do that, we stop after at the first
+// space when there is no quotes.
+base::string16 GetPathFromCmdLine(const base::string16 &cmd_line) {
+  base::string16 exe_name;
+  // Check if it starts with '"'.
+  if (cmd_line[0] == L'\"') {
+    // Find the position of the second '"', this terminates the path.
+    base::string16::size_type pos = cmd_line.find(L'\"', 1);
+    if (base::string16::npos == pos)
+      return cmd_line;
+    exe_name = cmd_line.substr(1, pos - 1);
+  } else {
+    // There is no '"', that means that the appname is terminated at the
+    // first space.
+    base::string16::size_type pos = cmd_line.find(L' ');
+    if (base::string16::npos == pos) {
+      // There is no space, the cmd_line contains only the app_name
+      exe_name = cmd_line;
+    } else {
+      exe_name = cmd_line.substr(0, pos);
+    }
+  }
+
+  return exe_name;
+}
+
+// Returns true is the path in parameter is relative. False if it's
+// absolute.
+bool IsPathRelative(const base::string16 &path) {
+  // A path is Relative if it's not a UNC path beginnning with \\ or a
+  // path beginning with a drive. (i.e. X:\)
+  if (path.find(L"\\\\") == 0 || path.find(L":\\") == 1)
+    return false;
+  return true;
+}
+
+// Converts a relative path to an absolute path.
+bool ConvertToAbsolutePath(const base::string16& child_current_directory,
+                           bool use_env_path, base::string16 *path) {
+  wchar_t file_buffer[MAX_PATH];
+  wchar_t *file_part = NULL;
+
+  // Here we should start by looking at the path where the child application was
+  // started. We don't have this information yet.
+  DWORD result = 0;
+  if (use_env_path) {
+    // Try with the complete path
+    result = ::SearchPath(NULL, path->c_str(), NULL, MAX_PATH, file_buffer,
+                          &file_part);
+  }
+
+  if (0 == result) {
+    // Try with the current directory of the child
+    result = ::SearchPath(child_current_directory.c_str(), path->c_str(), NULL,
+                          MAX_PATH, file_buffer, &file_part);
+  }
+
+  if (0 == result || result >= MAX_PATH)
+    return false;
+
+  *path = file_buffer;
+  return true;
+}
+
+}  // namespace
+namespace sandbox {
+
+ThreadProcessDispatcher::ThreadProcessDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall open_thread = {
+    {IPC_NTOPENTHREAD_TAG, UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &ThreadProcessDispatcher::NtOpenThread)
+  };
+
+  static const IPCCall open_process = {
+    {IPC_NTOPENPROCESS_TAG, UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &ThreadProcessDispatcher::NtOpenProcess)
+  };
+
+  static const IPCCall process_token = {
+    {IPC_NTOPENPROCESSTOKEN_TAG, VOIDPTR_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &ThreadProcessDispatcher::NtOpenProcessToken)
+  };
+
+  static const IPCCall process_tokenex = {
+    {IPC_NTOPENPROCESSTOKENEX_TAG, VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &ThreadProcessDispatcher::NtOpenProcessTokenEx)
+  };
+
+  static const IPCCall create_params = {
+    {IPC_CREATEPROCESSW_TAG, WCHAR_TYPE, WCHAR_TYPE, WCHAR_TYPE, INOUTPTR_TYPE},
+    reinterpret_cast<CallbackGeneric>(
+        &ThreadProcessDispatcher::CreateProcessW)
+  };
+
+  ipc_calls_.push_back(open_thread);
+  ipc_calls_.push_back(open_process);
+  ipc_calls_.push_back(process_token);
+  ipc_calls_.push_back(process_tokenex);
+  ipc_calls_.push_back(create_params);
+}
+
+bool ThreadProcessDispatcher::SetupService(InterceptionManager* manager,
+                                           int service) {
+  switch (service) {
+    case IPC_NTOPENTHREAD_TAG:
+    case IPC_NTOPENPROCESS_TAG:
+    case IPC_NTOPENPROCESSTOKEN_TAG:
+    case IPC_NTOPENPROCESSTOKENEX_TAG:
+      // There is no explicit policy for these services.
+      NOTREACHED();
+      return false;
+
+    case IPC_CREATEPROCESSW_TAG:
+      return INTERCEPT_EAT(manager, kKerneldllName, CreateProcessW,
+                           CREATE_PROCESSW_ID, 44) &&
+             INTERCEPT_EAT(manager, L"kernel32.dll", CreateProcessA,
+                           CREATE_PROCESSA_ID, 44);
+
+    default:
+      return false;
+  }
+}
+
+bool ThreadProcessDispatcher::NtOpenThread(IPCInfo* ipc,
+                                           uint32 desired_access,
+                                           uint32 thread_id) {
+  HANDLE handle;
+  NTSTATUS ret = ProcessPolicy::OpenThreadAction(*ipc->client_info,
+                                                 desired_access, thread_id,
+                                                 &handle);
+  ipc->return_info.nt_status = ret;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool ThreadProcessDispatcher::NtOpenProcess(IPCInfo* ipc,
+                                            uint32 desired_access,
+                                            uint32 process_id) {
+  HANDLE handle;
+  NTSTATUS ret = ProcessPolicy::OpenProcessAction(*ipc->client_info,
+                                                  desired_access, process_id,
+                                                  &handle);
+  ipc->return_info.nt_status = ret;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool ThreadProcessDispatcher::NtOpenProcessToken(IPCInfo* ipc,
+                                                 HANDLE process,
+                                                 uint32 desired_access) {
+  HANDLE handle;
+  NTSTATUS ret = ProcessPolicy::OpenProcessTokenAction(*ipc->client_info,
+                                                       process, desired_access,
+                                                       &handle);
+  ipc->return_info.nt_status = ret;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool ThreadProcessDispatcher::NtOpenProcessTokenEx(IPCInfo* ipc,
+                                                   HANDLE process,
+                                                   uint32 desired_access,
+                                                   uint32 attributes) {
+  HANDLE handle;
+  NTSTATUS ret = ProcessPolicy::OpenProcessTokenExAction(*ipc->client_info,
+                                                         process,
+                                                         desired_access,
+                                                         attributes, &handle);
+  ipc->return_info.nt_status = ret;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool ThreadProcessDispatcher::CreateProcessW(IPCInfo* ipc, base::string16* name,
+                                             base::string16* cmd_line,
+                                             base::string16* cur_dir,
+                                             CountedBuffer* info) {
+  if (sizeof(PROCESS_INFORMATION) != info->Size())
+    return false;
+
+  // Check if there is an application name.
+  base::string16 exe_name;
+  if (!name->empty())
+    exe_name = *name;
+  else
+    exe_name = GetPathFromCmdLine(*cmd_line);
+
+  if (IsPathRelative(exe_name)) {
+    if (!ConvertToAbsolutePath(*cur_dir, name->empty(), &exe_name)) {
+      // Cannot find the path. Maybe the file does not exist.
+      ipc->return_info.win32_result = ERROR_FILE_NOT_FOUND;
+      return true;
+    }
+  }
+
+  const wchar_t* const_exe_name = exe_name.c_str();
+  CountedParameterSet<NameBased> params;
+  params[NameBased::NAME] = ParamPickerMake(const_exe_name);
+
+  EvalResult eval = policy_base_->EvalPolicy(IPC_CREATEPROCESSW_TAG,
+                                             params.GetBase());
+
+  PROCESS_INFORMATION* proc_info =
+      reinterpret_cast<PROCESS_INFORMATION*>(info->Buffer());
+  // Here we force the app_name to be the one we used for the policy lookup.
+  // If our logic was wrong, at least we wont allow create a random process.
+  DWORD ret = ProcessPolicy::CreateProcessWAction(eval, *ipc->client_info,
+                                                  exe_name, *cmd_line,
+                                                  proc_info);
+
+  ipc->return_info.win32_result = ret;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_thread_dispatcher.h b/sandbox/win/src/process_thread_dispatcher.h
new file mode 100644
index 0000000..2bb3b6e
--- /dev/null
+++ b/sandbox/win/src/process_thread_dispatcher.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_THREAD_DISPATCHER_H_
+#define SANDBOX_SRC_PROCESS_THREAD_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles process and thread-related IPC calls.
+class ThreadProcessDispatcher : public Dispatcher {
+ public:
+  explicit ThreadProcessDispatcher(PolicyBase* policy_base);
+  ~ThreadProcessDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to NtOpenThread() in the target.
+  bool NtOpenThread(IPCInfo* ipc, uint32 desired_access, uint32 thread_id);
+
+  // Processes IPC requests coming from calls to NtOpenProcess() in the target.
+  bool NtOpenProcess(IPCInfo* ipc, uint32 desired_access, uint32 process_id);
+
+  // Processes IPC requests from calls to NtOpenProcessToken() in the target.
+  bool NtOpenProcessToken(IPCInfo* ipc, HANDLE process, uint32 desired_access);
+
+  // Processes IPC requests from calls to NtOpenProcessTokenEx() in the target.
+  bool NtOpenProcessTokenEx(IPCInfo* ipc,
+                            HANDLE process,
+                            uint32 desired_access,
+                            uint32 attributes);
+
+  // Processes IPC requests coming from calls to CreateProcessW() in the target.
+  bool CreateProcessW(IPCInfo* ipc,
+                      base::string16* name,
+                      base::string16* cmd_line,
+                      base::string16* cur_dir,
+                      CountedBuffer* info);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(ThreadProcessDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_THREAD_DISPATCHER_H_
diff --git a/sandbox/win/src/process_thread_interception.cc b/sandbox/win/src/process_thread_interception.cc
new file mode 100644
index 0000000..45926bc
--- /dev/null
+++ b/sandbox/win/src/process_thread_interception.cc
@@ -0,0 +1,403 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_thread_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Hooks NtOpenThread and proxy the call to the broker if it's trying to
+// open a thread in the same process.
+NTSTATUS WINAPI TargetNtOpenThread(NtOpenThreadFunction orig_OpenThread,
+                                   PHANDLE thread, ACCESS_MASK desired_access,
+                                   POBJECT_ATTRIBUTES object_attributes,
+                                   PCLIENT_ID client_id) {
+  NTSTATUS status = orig_OpenThread(thread, desired_access, object_attributes,
+                                    client_id);
+  if (NT_SUCCESS(status))
+    return status;
+
+  do {
+    if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+      break;
+    if (!client_id)
+      break;
+
+    uint32 thread_id = 0;
+    bool should_break = false;
+    __try {
+      // We support only the calls for the current process
+      if (NULL != client_id->UniqueProcess)
+        should_break = true;
+
+      // Object attributes should be NULL or empty.
+      if (!should_break && NULL != object_attributes) {
+        if (0 != object_attributes->Attributes ||
+            NULL != object_attributes->ObjectName ||
+            NULL != object_attributes->RootDirectory ||
+            NULL != object_attributes->SecurityDescriptor ||
+            NULL != object_attributes->SecurityQualityOfService) {
+          should_break = true;
+        }
+      }
+
+      thread_id = static_cast<uint32>(
+                      reinterpret_cast<ULONG_PTR>(client_id->UniqueThread));
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    if (should_break)
+      break;
+
+    if (!ValidParameter(thread, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTOPENTHREAD_TAG, desired_access,
+                                thread_id, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      // The nt_status here is most likely STATUS_INVALID_CID because
+      // in the broker we set the process id in the CID (client ID) param
+      // to be the current process. If you try to open a thread from another
+      // process you will get this INVALID_CID error. On the other hand, if you
+      // try to open a thread in your own process, it should return success.
+      // We don't want to return STATUS_INVALID_CID here, so we return the
+      // return of the original open thread status, which is most likely
+      // STATUS_ACCESS_DENIED.
+      break;
+
+    __try {
+      // Write the output parameters.
+      *thread = answer.handle;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    return answer.nt_status;
+  } while (false);
+
+  return status;
+}
+
+// Hooks NtOpenProcess and proxy the call to the broker if it's trying to
+// open the current process.
+NTSTATUS WINAPI TargetNtOpenProcess(NtOpenProcessFunction orig_OpenProcess,
+                                   PHANDLE process, ACCESS_MASK desired_access,
+                                   POBJECT_ATTRIBUTES object_attributes,
+                                   PCLIENT_ID client_id) {
+  NTSTATUS status = orig_OpenProcess(process, desired_access, object_attributes,
+                                     client_id);
+  if (NT_SUCCESS(status))
+    return status;
+
+  do {
+    if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+      break;
+    if (!client_id)
+      break;
+
+    uint32 process_id = 0;
+    bool should_break = false;
+    __try {
+      // Object attributes should be NULL or empty.
+      if (!should_break && NULL != object_attributes) {
+        if (0 != object_attributes->Attributes ||
+            NULL != object_attributes->ObjectName ||
+            NULL != object_attributes->RootDirectory ||
+            NULL != object_attributes->SecurityDescriptor ||
+            NULL != object_attributes->SecurityQualityOfService) {
+          should_break = true;
+        }
+      }
+
+      process_id = static_cast<uint32>(
+                      reinterpret_cast<ULONG_PTR>(client_id->UniqueProcess));
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    if (should_break)
+      break;
+
+    if (!ValidParameter(process, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESS_TAG, desired_access,
+                                process_id, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      return answer.nt_status;
+
+    __try {
+      // Write the output parameters.
+      *process = answer.handle;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    return answer.nt_status;
+  } while (false);
+
+  return status;
+}
+
+
+NTSTATUS WINAPI TargetNtOpenProcessToken(
+    NtOpenProcessTokenFunction orig_OpenProcessToken, HANDLE process,
+    ACCESS_MASK desired_access, PHANDLE token) {
+  NTSTATUS status = orig_OpenProcessToken(process, desired_access, token);
+  if (NT_SUCCESS(status))
+    return status;
+
+  do {
+    if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+      break;
+
+    if (CURRENT_PROCESS != process)
+      break;
+
+    if (!ValidParameter(token, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESSTOKEN_TAG, process,
+                                desired_access, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      return answer.nt_status;
+
+    __try {
+      // Write the output parameters.
+      *token = answer.handle;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    return answer.nt_status;
+  } while (false);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenProcessTokenEx(
+    NtOpenProcessTokenExFunction orig_OpenProcessTokenEx, HANDLE process,
+    ACCESS_MASK desired_access, ULONG handle_attributes, PHANDLE token) {
+  NTSTATUS status = orig_OpenProcessTokenEx(process, desired_access,
+                                            handle_attributes, token);
+  if (NT_SUCCESS(status))
+    return status;
+
+  do {
+    if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+      break;
+
+    if (CURRENT_PROCESS != process)
+      break;
+
+    if (!ValidParameter(token, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESSTOKENEX_TAG, process,
+                                desired_access, handle_attributes, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    if (!NT_SUCCESS(answer.nt_status))
+      return answer.nt_status;
+
+    __try {
+      // Write the output parameters.
+      *token = answer.handle;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+
+    return answer.nt_status;
+  } while (false);
+
+  return status;
+}
+
+BOOL WINAPI TargetCreateProcessW(CreateProcessWFunction orig_CreateProcessW,
+                                 LPCWSTR application_name, LPWSTR command_line,
+                                 LPSECURITY_ATTRIBUTES process_attributes,
+                                 LPSECURITY_ATTRIBUTES thread_attributes,
+                                 BOOL inherit_handles, DWORD flags,
+                                 LPVOID environment, LPCWSTR current_directory,
+                                 LPSTARTUPINFOW startup_info,
+                                 LPPROCESS_INFORMATION process_information) {
+  if (orig_CreateProcessW(application_name, command_line, process_attributes,
+                          thread_attributes, inherit_handles, flags,
+                          environment, current_directory, startup_info,
+                          process_information)) {
+    return TRUE;
+  }
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return FALSE;
+
+  DWORD original_error = ::GetLastError();
+
+  do {
+    if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
+                        WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    const wchar_t* cur_dir = NULL;
+
+    wchar_t current_directory[MAX_PATH];
+    DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
+    if (0 != result && result < MAX_PATH)
+      cur_dir = current_directory;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+
+    InOutCountedBuffer proc_info(process_information,
+                                 sizeof(PROCESS_INFORMATION));
+
+    ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, application_name,
+                                command_line, cur_dir, proc_info, &answer);
+    if (SBOX_ALL_OK != code)
+      break;
+
+    ::SetLastError(answer.win32_result);
+    if (ERROR_SUCCESS != answer.win32_result)
+      return FALSE;
+
+    return TRUE;
+  } while (false);
+
+  ::SetLastError(original_error);
+  return FALSE;
+}
+
+BOOL WINAPI TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
+                                 LPCSTR application_name, LPSTR command_line,
+                                 LPSECURITY_ATTRIBUTES process_attributes,
+                                 LPSECURITY_ATTRIBUTES thread_attributes,
+                                 BOOL inherit_handles, DWORD flags,
+                                 LPVOID environment, LPCSTR current_directory,
+                                 LPSTARTUPINFOA startup_info,
+                                 LPPROCESS_INFORMATION process_information) {
+  if (orig_CreateProcessA(application_name, command_line, process_attributes,
+                          thread_attributes, inherit_handles, flags,
+                          environment, current_directory, startup_info,
+                          process_information)) {
+    return TRUE;
+  }
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return FALSE;
+
+  DWORD original_error = ::GetLastError();
+
+  do {
+    if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
+                        WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    // Convert the input params to unicode.
+    UNICODE_STRING *cmd_unicode = NULL;
+    UNICODE_STRING *app_unicode = NULL;
+    if (command_line) {
+      cmd_unicode = AnsiToUnicode(command_line);
+      if (!cmd_unicode)
+        break;
+    }
+
+    if (application_name) {
+      app_unicode = AnsiToUnicode(application_name);
+      if (!app_unicode) {
+        operator delete(cmd_unicode, NT_ALLOC);
+        break;
+      }
+    }
+
+    const wchar_t* cmd_line = cmd_unicode ? cmd_unicode->Buffer : NULL;
+    const wchar_t* app_name = app_unicode ? app_unicode->Buffer : NULL;
+    const wchar_t* cur_dir = NULL;
+
+    wchar_t current_directory[MAX_PATH];
+    DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
+    if (0 != result && result < MAX_PATH)
+      cur_dir = current_directory;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+
+    InOutCountedBuffer proc_info(process_information,
+                                 sizeof(PROCESS_INFORMATION));
+
+    ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, app_name,
+                                cmd_line, cur_dir, proc_info, &answer);
+
+    operator delete(cmd_unicode, NT_ALLOC);
+    operator delete(app_unicode, NT_ALLOC);
+
+    if (SBOX_ALL_OK != code)
+      break;
+
+    ::SetLastError(answer.win32_result);
+    if (ERROR_SUCCESS != answer.win32_result)
+      return FALSE;
+
+    return TRUE;
+  } while (false);
+
+  ::SetLastError(original_error);
+  return FALSE;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_thread_interception.h b/sandbox/win/src/process_thread_interception.h
new file mode 100644
index 0000000..31dc231
--- /dev/null
+++ b/sandbox/win/src/process_thread_interception.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_PROCESS_THREAD_INTERCEPTION_H__
+#define SANDBOX_SRC_PROCESS_THREAD_INTERCEPTION_H__
+
+namespace sandbox {
+
+extern "C" {
+
+typedef BOOL (WINAPI *CreateProcessWFunction)(
+    LPCWSTR lpApplicationName,
+    LPWSTR lpCommandLine,
+    LPSECURITY_ATTRIBUTES lpProcessAttributes,
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    BOOL bInheritHandles,
+    DWORD dwCreationFlags,
+    LPVOID lpEnvironment,
+    LPCWSTR lpCurrentDirectory,
+    LPSTARTUPINFOW lpStartupInfo,
+    LPPROCESS_INFORMATION lpProcessInformation);
+
+typedef BOOL (WINAPI *CreateProcessAFunction)(
+    LPCSTR lpApplicationName,
+    LPSTR lpCommandLine,
+    LPSECURITY_ATTRIBUTES lpProcessAttributes,
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    BOOL bInheritHandles,
+    DWORD dwCreationFlags,
+    LPVOID lpEnvironment,
+    LPCSTR lpCurrentDirectory,
+    LPSTARTUPINFOA lpStartupInfo,
+    LPPROCESS_INFORMATION lpProcessInformation);
+
+typedef HANDLE (WINAPI *CreateThreadFunction)(
+    LPSECURITY_ATTRIBUTES lpThreadAttributes,
+    SIZE_T dwStackSize,
+    LPTHREAD_START_ROUTINE lpStartAddress,
+    PVOID lpParameter,
+    DWORD dwCreationFlags,
+    LPDWORD lpThreadId);
+
+typedef LCID (WINAPI *GetUserDefaultLCIDFunction)();
+
+// Interception of NtOpenThread on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThread(
+    NtOpenThreadFunction orig_OpenThread, PHANDLE thread,
+    ACCESS_MASK desired_access, POBJECT_ATTRIBUTES object_attributes,
+    PCLIENT_ID client_id);
+
+// Interception of NtOpenProcess on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcess(
+    NtOpenProcessFunction orig_OpenProcess, PHANDLE process,
+    ACCESS_MASK desired_access, POBJECT_ATTRIBUTES object_attributes,
+    PCLIENT_ID client_id);
+
+// Interception of NtOpenProcessToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcessToken(
+    NtOpenProcessTokenFunction orig_OpenProcessToken, HANDLE process,
+    ACCESS_MASK desired_access, PHANDLE token);
+
+// Interception of NtOpenProcessTokenEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenProcessTokenEx(
+    NtOpenProcessTokenExFunction orig_OpenProcessTokenEx, HANDLE process,
+    ACCESS_MASK desired_access, ULONG handle_attributes, PHANDLE token);
+
+// Interception of CreateProcessW and A in kernel32.dll.
+SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessW(
+    CreateProcessWFunction orig_CreateProcessW, LPCWSTR application_name,
+    LPWSTR command_line, LPSECURITY_ATTRIBUTES process_attributes,
+    LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD flags,
+    LPVOID environment, LPCWSTR current_directory, LPSTARTUPINFOW startup_info,
+    LPPROCESS_INFORMATION process_information);
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetCreateProcessA(
+    CreateProcessAFunction orig_CreateProcessA, LPCSTR application_name,
+    LPSTR command_line, LPSECURITY_ATTRIBUTES process_attributes,
+    LPSECURITY_ATTRIBUTES thread_attributes, BOOL inherit_handles, DWORD flags,
+    LPVOID environment, LPCSTR current_directory, LPSTARTUPINFOA startup_info,
+    LPPROCESS_INFORMATION process_information);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_THREAD_INTERCEPTION_H__
diff --git a/sandbox/win/src/process_thread_policy.cc b/sandbox/win/src/process_thread_policy.cc
new file mode 100644
index 0000000..0653591
--- /dev/null
+++ b/sandbox/win/src/process_thread_policy.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_thread_policy.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// These are the only safe rights that can be given to a sandboxed
+// process for the process created by the broker. All others are potential
+// vectors of privilege elevation.
+const DWORD kProcessRights = SYNCHRONIZE |
+                             PROCESS_QUERY_INFORMATION |
+                             PROCESS_QUERY_LIMITED_INFORMATION |
+                             PROCESS_TERMINATE |
+                             PROCESS_SUSPEND_RESUME;
+
+const DWORD kThreadRights = SYNCHRONIZE |
+                            THREAD_TERMINATE |
+                            THREAD_SUSPEND_RESUME |
+                            THREAD_QUERY_INFORMATION |
+                            THREAD_QUERY_LIMITED_INFORMATION |
+                            THREAD_SET_LIMITED_INFORMATION;
+
+// Creates a child process and duplicates the handles to 'target_process'. The
+// remaining parameters are the same as CreateProcess().
+BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access,
+                            LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
+                            LPSECURITY_ATTRIBUTES lpProcessAttributes,
+                            LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                            BOOL bInheritHandles, DWORD dwCreationFlags,
+                            LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
+                            LPSTARTUPINFOW lpStartupInfo,
+                            LPPROCESS_INFORMATION lpProcessInformation) {
+  if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes,
+                        lpThreadAttributes, bInheritHandles, dwCreationFlags,
+                        lpEnvironment, lpCurrentDirectory, lpStartupInfo,
+                        lpProcessInformation)) {
+    return FALSE;
+  }
+
+  DWORD process_access = kProcessRights;
+  DWORD thread_access = kThreadRights;
+  if (give_full_access) {
+    process_access = PROCESS_ALL_ACCESS;
+    thread_access = THREAD_ALL_ACCESS;
+  }
+  if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess,
+                         target_process, &lpProcessInformation->hProcess,
+                         process_access, FALSE, DUPLICATE_CLOSE_SOURCE)) {
+    ::CloseHandle(lpProcessInformation->hThread);
+    return FALSE;
+  }
+  if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread,
+                         target_process, &lpProcessInformation->hThread,
+                         thread_access, FALSE, DUPLICATE_CLOSE_SOURCE)) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+}
+
+namespace sandbox {
+
+bool ProcessPolicy::GenerateRules(const wchar_t* name,
+                                  TargetPolicy::Semantics semantics,
+                                  LowLevelPolicy* policy) {
+  scoped_ptr<PolicyRule> process;
+  switch (semantics) {
+    case TargetPolicy::PROCESS_MIN_EXEC: {
+      process.reset(new PolicyRule(GIVE_READONLY));
+      break;
+    };
+    case TargetPolicy::PROCESS_ALL_EXEC: {
+      process.reset(new PolicyRule(GIVE_ALLACCESS));
+      break;
+    };
+    default: {
+      return false;
+    };
+  }
+
+  if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) {
+    return false;
+  }
+  if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) {
+    return false;
+  }
+  return true;
+}
+
+NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info,
+                                         uint32 desired_access,
+                                         uint32 thread_id,
+                                         HANDLE* handle) {
+  *handle = NULL;
+
+  NtOpenThreadFunction NtOpenThread = NULL;
+  ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread);
+
+  OBJECT_ATTRIBUTES attributes = {0};
+  attributes.Length = sizeof(attributes);
+  CLIENT_ID client_id = {0};
+  client_id.UniqueProcess = reinterpret_cast<PVOID>(
+                                static_cast<ULONG_PTR>(client_info.process_id));
+  client_id.UniqueThread =
+      reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id));
+
+  HANDLE local_handle;
+  NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes,
+                                 &client_id);
+  if (NT_SUCCESS(status)) {
+    if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                           client_info.process, handle, 0, FALSE,
+                           DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+      return STATUS_ACCESS_DENIED;
+    }
+  }
+
+  return status;
+}
+
+NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info,
+                                          uint32 desired_access,
+                                          uint32 process_id,
+                                          HANDLE* handle) {
+  *handle = NULL;
+
+  NtOpenProcessFunction NtOpenProcess = NULL;
+  ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess);
+
+  if (client_info.process_id != process_id)
+    return STATUS_ACCESS_DENIED;
+
+  OBJECT_ATTRIBUTES attributes = {0};
+  attributes.Length = sizeof(attributes);
+  CLIENT_ID client_id = {0};
+  client_id.UniqueProcess = reinterpret_cast<PVOID>(
+                                static_cast<ULONG_PTR>(client_info.process_id));
+  HANDLE local_handle;
+  NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes,
+                                  &client_id);
+  if (NT_SUCCESS(status)) {
+    if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                           client_info.process, handle, 0, FALSE,
+                           DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+      return STATUS_ACCESS_DENIED;
+    }
+  }
+
+  return status;
+}
+
+NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info,
+                                               HANDLE process,
+                                               uint32 desired_access,
+                                               HANDLE* handle) {
+  *handle = NULL;
+  NtOpenProcessTokenFunction NtOpenProcessToken = NULL;
+  ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken);
+
+  if (CURRENT_PROCESS != process)
+    return STATUS_ACCESS_DENIED;
+
+  HANDLE local_handle;
+  NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access,
+                                       &local_handle);
+  if (NT_SUCCESS(status)) {
+    if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                           client_info.process, handle, 0, FALSE,
+                           DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+      return STATUS_ACCESS_DENIED;
+    }
+  }
+  return status;
+}
+
+NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info,
+                                                 HANDLE process,
+                                                 uint32 desired_access,
+                                                 uint32 attributes,
+                                                 HANDLE* handle) {
+  *handle = NULL;
+  NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL;
+  ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx);
+
+  if (CURRENT_PROCESS != process)
+    return STATUS_ACCESS_DENIED;
+
+  HANDLE local_handle;
+  NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access,
+                                         attributes, &local_handle);
+  if (NT_SUCCESS(status)) {
+    if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                           client_info.process, handle, 0, FALSE,
+                           DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+      return STATUS_ACCESS_DENIED;
+    }
+  }
+  return status;
+}
+
+DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
+                                          const ClientInfo& client_info,
+                                          const base::string16 &app_name,
+                                          const base::string16 &command_line,
+                                          PROCESS_INFORMATION* process_info) {
+  // The only action supported is ASK_BROKER which means create the process.
+  if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) {
+    return ERROR_ACCESS_DENIED;
+  }
+
+  STARTUPINFO startup_info = {0};
+  startup_info.cb = sizeof(startup_info);
+  scoped_ptr<wchar_t, base::FreeDeleter>
+      cmd_line(_wcsdup(command_line.c_str()));
+
+  BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result);
+  if (!CreateProcessExWHelper(client_info.process, should_give_full_access,
+                              app_name.c_str(), cmd_line.get(), NULL, NULL,
+                              FALSE, 0, NULL, NULL, &startup_info,
+                              process_info)) {
+    return ERROR_ACCESS_DENIED;
+  }
+  return ERROR_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/process_thread_policy.h b/sandbox/win/src/process_thread_policy.h
new file mode 100644
index 0000000..2871dca
--- /dev/null
+++ b/sandbox/win/src/process_thread_policy.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_THREAD_POLICY_H_
+#define SANDBOX_SRC_PROCESS_THREAD_POLICY_H_
+
+#include <string>
+
+#include "sandbox/win/src/policy_low_level.h"
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to process execution.
+class ProcessPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level.
+  // policy rule for process creation
+  // 'name' is the executable to be spawn.
+  // 'semantics' is the desired semantics.
+  // 'policy' is the policy generator to which the rules are going to be added.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Opens a thread from the child process and returns the handle.
+  // client_info contains the information about the child process,
+  // desired_access is the access requested by the child and thread_id
+  // is the thread_id to be opened.
+  // The function returns the return value of NtOpenThread.
+  static NTSTATUS OpenThreadAction(const ClientInfo& client_info,
+                                   uint32 desired_access,
+                                   uint32 thread_id,
+                                   HANDLE* handle);
+
+  // Opens the process id passed in and returns the duplicated handle to
+  // the child. We only allow the child processes to open themselves. Any other
+  // pid open is denied.
+  static NTSTATUS OpenProcessAction(const ClientInfo& client_info,
+                                    uint32 desired_access,
+                                    uint32 process_id,
+                                    HANDLE* handle);
+
+  // Opens the token associated with the process and returns the duplicated
+  // handle to the child. We only allow the child processes to open his own
+  // token (using ::GetCurrentProcess()).
+  static NTSTATUS OpenProcessTokenAction(const ClientInfo& client_info,
+                                         HANDLE process,
+                                         uint32 desired_access,
+                                         HANDLE* handle);
+
+  // Opens the token associated with the process and returns the duplicated
+  // handle to the child. We only allow the child processes to open his own
+  // token (using ::GetCurrentProcess()).
+  static NTSTATUS OpenProcessTokenExAction(const ClientInfo& client_info,
+                                           HANDLE process,
+                                           uint32 desired_access,
+                                           uint32 attributes,
+                                           HANDLE* handle);
+
+  // Processes a 'CreateProcessW()' request from the target.
+  // 'client_info' : the target process that is making the request.
+  // 'eval_result' : The desired policy action to accomplish.
+  // 'app_name' : The full path of the process to be created.
+  // 'command_line' : The command line passed to the created process.
+  static DWORD CreateProcessWAction(EvalResult eval_result,
+                                    const ClientInfo& client_info,
+                                    const base::string16 &app_name,
+                                    const base::string16 &command_line,
+                                    PROCESS_INFORMATION* process_info);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_PROCESS_THREAD_POLICY_H_
diff --git a/sandbox/win/src/registry_dispatcher.cc b/sandbox/win/src/registry_dispatcher.cc
new file mode 100644
index 0000000..967fe65
--- /dev/null
+++ b/sandbox/win/src/registry_dispatcher.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/registry_dispatcher.h"
+
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/registry_interception.h"
+#include "sandbox/win/src/registry_policy.h"
+
+namespace {
+
+// Builds a path using the root directory and the name.
+bool GetCompletePath(HANDLE root, const base::string16& name,
+                     base::string16* complete_name) {
+  if (root) {
+    if (!sandbox::GetPathFromHandle(root, complete_name))
+      return false;
+
+    *complete_name += L"\\";
+    *complete_name += name;
+  } else {
+    *complete_name = name;
+  }
+
+  return true;
+}
+
+}
+
+namespace sandbox {
+
+RegistryDispatcher::RegistryDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall create_params = {
+    {IPC_NTCREATEKEY_TAG, WCHAR_TYPE, UINT32_TYPE, VOIDPTR_TYPE, UINT32_TYPE,
+     UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtCreateKey)
+  };
+
+  static const IPCCall open_params = {
+    {IPC_NTOPENKEY_TAG, WCHAR_TYPE, UINT32_TYPE, VOIDPTR_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtOpenKey)
+  };
+
+  ipc_calls_.push_back(create_params);
+  ipc_calls_.push_back(open_params);
+}
+
+bool RegistryDispatcher::SetupService(InterceptionManager* manager,
+                                      int service) {
+  if (IPC_NTCREATEKEY_TAG == service)
+    return INTERCEPT_NT(manager, NtCreateKey, CREATE_KEY_ID, 32);
+
+  if (IPC_NTOPENKEY_TAG == service) {
+    bool result = INTERCEPT_NT(manager, NtOpenKey, OPEN_KEY_ID, 16);
+    if (base::win::GetVersion() >= base::win::VERSION_WIN7 ||
+        (base::win::GetVersion() == base::win::VERSION_VISTA &&
+         base::win::OSInfo::GetInstance()->version_type() ==
+             base::win::SUITE_SERVER))
+      result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20);
+    return result;
+  }
+
+  return false;
+}
+
+bool RegistryDispatcher::NtCreateKey(IPCInfo* ipc,
+                                     base::string16* name,
+                                     uint32 attributes,
+                                     HANDLE root,
+                                     uint32 desired_access,
+                                     uint32 title_index,
+                                     uint32 create_options) {
+  base::win::ScopedHandle root_handle;
+  base::string16 real_path = *name;
+
+  // If there is a root directory, we need to duplicate the handle to make
+  // it valid in this process.
+  if (root) {
+    if (!::DuplicateHandle(ipc->client_info->process, root,
+                           ::GetCurrentProcess(), &root, 0, FALSE,
+                           DUPLICATE_SAME_ACCESS))
+      return false;
+
+    root_handle.Set(root);
+  }
+
+  if (!GetCompletePath(root, *name, &real_path))
+    return false;
+
+  const wchar_t* regname = real_path.c_str();
+  CountedParameterSet<OpenKey> params;
+  params[OpenKey::NAME] = ParamPickerMake(regname);
+  params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
+
+  EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEKEY_TAG,
+                                               params.GetBase());
+
+  HANDLE handle;
+  NTSTATUS nt_status;
+  ULONG disposition = 0;
+  if (!RegistryPolicy::CreateKeyAction(result, *ipc->client_info, *name,
+                                       attributes, root, desired_access,
+                                       title_index, create_options, &handle,
+                                       &nt_status, &disposition)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  // Return operation status on the IPC.
+  ipc->return_info.extended[0].unsigned_int = disposition;
+  ipc->return_info.nt_status = nt_status;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc,
+                                   base::string16* name,
+                                   uint32 attributes,
+                                   HANDLE root,
+                                   uint32 desired_access) {
+  base::win::ScopedHandle root_handle;
+  base::string16 real_path = *name;
+
+  // If there is a root directory, we need to duplicate the handle to make
+  // it valid in this process.
+  if (root) {
+    if (!::DuplicateHandle(ipc->client_info->process, root,
+                           ::GetCurrentProcess(), &root, 0, FALSE,
+                           DUPLICATE_SAME_ACCESS))
+      return false;
+      root_handle.Set(root);
+  }
+
+  if (!GetCompletePath(root, *name, &real_path))
+    return false;
+
+  const wchar_t* regname = real_path.c_str();
+  CountedParameterSet<OpenKey> params;
+  params[OpenKey::NAME] = ParamPickerMake(regname);
+  params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
+
+  EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENKEY_TAG,
+                                               params.GetBase());
+  HANDLE handle;
+  NTSTATUS nt_status;
+  if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name,
+                                     attributes, root, desired_access, &handle,
+                                     &nt_status)) {
+    ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  // Return operation status on the IPC.
+  ipc->return_info.nt_status = nt_status;
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/registry_dispatcher.h b/sandbox/win/src/registry_dispatcher.h
new file mode 100644
index 0000000..83811a9
--- /dev/null
+++ b/sandbox/win/src/registry_dispatcher.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_REGISTRY_DISPATCHER_H_
+#define SANDBOX_SRC_REGISTRY_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles registry-related IPC calls.
+class RegistryDispatcher : public Dispatcher {
+ public:
+  explicit RegistryDispatcher(PolicyBase* policy_base);
+  ~RegistryDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+ private:
+  // Processes IPC requests coming from calls to NtCreateKey in the target.
+  bool NtCreateKey(IPCInfo* ipc,
+                   base::string16* name,
+                   uint32 attributes,
+                   HANDLE root,
+                   uint32 desired_access,
+                   uint32 title_index,
+                   uint32 create_options);
+
+  // Processes IPC requests coming from calls to NtOpenKey in the target.
+  bool NtOpenKey(IPCInfo* ipc,
+                 base::string16* name,
+                 uint32 attributes,
+                 HANDLE root,
+                 uint32 desired_access);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(RegistryDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_REGISTRY_DISPATCHER_H_
diff --git a/sandbox/win/src/registry_interception.cc b/sandbox/win/src/registry_interception.cc
new file mode 100644
index 0000000..4a1a846
--- /dev/null
+++ b/sandbox/win/src/registry_interception.cc
@@ -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.
+
+#include "sandbox/win/src/registry_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+NTSTATUS WINAPI TargetNtCreateKey(NtCreateKeyFunction orig_CreateKey,
+                                  PHANDLE key, ACCESS_MASK desired_access,
+                                  POBJECT_ATTRIBUTES object_attributes,
+                                  ULONG title_index, PUNICODE_STRING class_name,
+                                  ULONG create_options, PULONG disposition) {
+  // Check if the process can create it first.
+  NTSTATUS status = orig_CreateKey(key, desired_access, object_attributes,
+                                   title_index, class_name, create_options,
+                                   disposition);
+  if (NT_SUCCESS(status))
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  do {
+    if (!ValidParameter(key, sizeof(HANDLE), WRITE))
+      break;
+
+    if (disposition && !ValidParameter(disposition, sizeof(ULONG), WRITE))
+      break;
+
+    // At this point we don't support class_name.
+    if (class_name && class_name->Buffer && class_name->Length)
+      break;
+
+    // We don't support creating link keys, volatile keys and backup/restore.
+    if (create_options)
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    wchar_t* name;
+    uint32 attributes = 0;
+    HANDLE root_directory = 0;
+    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+                                    &root_directory);
+    if (!NT_SUCCESS(ret) || NULL == name)
+      break;
+
+    uint32 desired_access_uint32 = desired_access;
+    CountedParameterSet<OpenKey> params;
+    params[OpenKey::ACCESS] = ParamPickerMake(desired_access_uint32);
+
+    wchar_t* full_name = NULL;
+
+    if (root_directory) {
+      ret = sandbox::AllocAndGetFullPath(root_directory, name, &full_name);
+      if (!NT_SUCCESS(ret) || NULL == full_name)
+        break;
+      params[OpenKey::NAME] = ParamPickerMake(full_name);
+    } else {
+      params[OpenKey::NAME] = ParamPickerMake(name);
+    }
+
+    bool query_broker = QueryBroker(IPC_NTCREATEKEY_TAG, params.GetBase());
+
+    if (full_name != NULL)
+      operator delete(full_name, NT_ALLOC);
+
+    if (!query_broker)
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+
+    ResultCode code = CrossCall(ipc, IPC_NTCREATEKEY_TAG, name, attributes,
+                                root_directory, desired_access, title_index,
+                                create_options, &answer);
+
+    operator delete(name, NT_ALLOC);
+
+    if (SBOX_ALL_OK != code)
+      break;
+
+    if (!NT_SUCCESS(answer.nt_status))
+        // TODO(nsylvain): We should return answer.nt_status here instead
+        // of status. We can do this only after we checked the policy.
+        // otherwise we will returns ACCESS_DENIED for all paths
+        // that are not specified by a policy, even though your token allows
+        // access to that path, and the original call had a more meaningful
+        // error. Bug 4369
+        break;
+
+    __try {
+      *key = answer.handle;
+
+      if (disposition)
+       *disposition = answer.extended[0].unsigned_int;
+
+      status = answer.nt_status;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  return status;
+}
+
+NTSTATUS WINAPI CommonNtOpenKey(NTSTATUS status, PHANDLE key,
+                                ACCESS_MASK desired_access,
+                                POBJECT_ATTRIBUTES object_attributes) {
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  do {
+    if (!ValidParameter(key, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (NULL == memory)
+      break;
+
+    wchar_t* name;
+    uint32 attributes;
+    HANDLE root_directory;
+    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+                                    &root_directory);
+    if (!NT_SUCCESS(ret) || NULL == name)
+      break;
+
+    uint32 desired_access_uint32 = desired_access;
+    CountedParameterSet<OpenKey> params;
+    params[OpenKey::ACCESS] = ParamPickerMake(desired_access_uint32);
+
+    wchar_t* full_name = NULL;
+
+    if (root_directory) {
+      ret = sandbox::AllocAndGetFullPath(root_directory, name, &full_name);
+      if (!NT_SUCCESS(ret) || NULL == full_name)
+        break;
+      params[OpenKey::NAME] = ParamPickerMake(full_name);
+    } else {
+      params[OpenKey::NAME] = ParamPickerMake(name);
+    }
+
+    bool query_broker = QueryBroker(IPC_NTOPENKEY_TAG, params.GetBase());
+
+    if (full_name != NULL)
+      operator delete(full_name, NT_ALLOC);
+
+    if (!query_broker)
+      break;
+
+    SharedMemIPCClient ipc(memory);
+    CrossCallReturn answer = {0};
+    ResultCode code = CrossCall(ipc, IPC_NTOPENKEY_TAG, name, attributes,
+                                root_directory, desired_access, &answer);
+
+    operator delete(name, NT_ALLOC);
+
+    if (SBOX_ALL_OK != code)
+      break;
+
+    if (!NT_SUCCESS(answer.nt_status))
+        // TODO(nsylvain): We should return answer.nt_status here instead
+        // of status. We can do this only after we checked the policy.
+        // otherwise we will returns ACCESS_DENIED for all paths
+        // that are not specified by a policy, even though your token allows
+        // access to that path, and the original call had a more meaningful
+        // error. Bug 4369
+        break;
+
+    __try {
+      *key = answer.handle;
+      status = answer.nt_status;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenKey(NtOpenKeyFunction orig_OpenKey, PHANDLE key,
+                                ACCESS_MASK desired_access,
+                                POBJECT_ATTRIBUTES object_attributes) {
+  // Check if the process can open it first.
+  NTSTATUS status = orig_OpenKey(key, desired_access, object_attributes);
+  if (NT_SUCCESS(status))
+    return status;
+
+  return CommonNtOpenKey(status, key, desired_access, object_attributes);
+}
+
+NTSTATUS WINAPI TargetNtOpenKeyEx(NtOpenKeyExFunction orig_OpenKeyEx,
+                                  PHANDLE key, ACCESS_MASK desired_access,
+                                  POBJECT_ATTRIBUTES object_attributes,
+                                  ULONG open_options) {
+  // Check if the process can open it first.
+  NTSTATUS status = orig_OpenKeyEx(key, desired_access, object_attributes,
+                                   open_options);
+
+  // We do not support open_options at this time. The 2 current known values
+  // are REG_OPTION_CREATE_LINK, to open a symbolic link, and
+  // REG_OPTION_BACKUP_RESTORE to open the key with special privileges.
+  if (NT_SUCCESS(status) || open_options != 0)
+    return status;
+
+  return CommonNtOpenKey(status, key, desired_access, object_attributes);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/registry_interception.h b/sandbox/win/src/registry_interception.h
new file mode 100644
index 0000000..c3cbde0
--- /dev/null
+++ b/sandbox/win/src/registry_interception.h
@@ -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 "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_REGISTRY_INTERCEPTION_H__
+#define SANDBOX_SRC_REGISTRY_INTERCEPTION_H__
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtCreateKey on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey(
+    NtCreateKeyFunction orig_CreateKey, PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, ULONG title_index,
+    PUNICODE_STRING class_name, ULONG create_options, PULONG disposition);
+
+// Interception of NtOpenKey on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKey(
+    NtOpenKeyFunction orig_OpenKey, PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes);
+
+// Interception of NtOpenKeyEx on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKeyEx(
+    NtOpenKeyExFunction orig_OpenKeyEx, PHANDLE key, ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes, ULONG open_options);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_REGISTRY_INTERCEPTION_H__
diff --git a/sandbox/win/src/registry_policy.cc b/sandbox/win/src/registry_policy.cc
new file mode 100644
index 0000000..b0f24a7
--- /dev/null
+++ b/sandbox/win/src/registry_policy.cc
@@ -0,0 +1,225 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "sandbox/win/src/registry_policy.h"
+
+#include "base/logging.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+static const uint32 kAllowedRegFlags =
+    KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_READ |
+    GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
+
+// Opens the key referenced by |obj_attributes| with |access| and
+// checks what permission was given. Remove the WRITE flags and update
+// |access| with the new value.
+NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes,
+                                 DWORD* access) {
+  NtOpenKeyFunction NtOpenKey = NULL;
+  ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
+
+  NtCloseFunction NtClose = NULL;
+  ResolveNTFunctionPtr("NtClose", &NtClose);
+
+  NtQueryObjectFunction NtQueryObject = NULL;
+  ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
+
+  // Open the key.
+  HANDLE handle;
+  NTSTATUS status = NtOpenKey(&handle, *access, obj_attributes);
+  if (!NT_SUCCESS(status))
+    return status;
+
+  OBJECT_BASIC_INFORMATION info = {0};
+  status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info),
+                         NULL);
+  NtClose(handle);
+  if (!NT_SUCCESS(status))
+    return status;
+
+  *access = info.GrantedAccess & kAllowedRegFlags;
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS NtCreateKeyInTarget(HANDLE* target_key_handle,
+                             ACCESS_MASK desired_access,
+                             OBJECT_ATTRIBUTES* obj_attributes,
+                             ULONG title_index,
+                             UNICODE_STRING* class_name,
+                             ULONG create_options,
+                             ULONG* disposition,
+                             HANDLE target_process) {
+  NtCreateKeyFunction NtCreateKey = NULL;
+  ResolveNTFunctionPtr("NtCreateKey", &NtCreateKey);
+
+  if (MAXIMUM_ALLOWED & desired_access) {
+    NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
+    if (!NT_SUCCESS(status))
+      return STATUS_ACCESS_DENIED;
+  }
+
+  HANDLE local_handle = INVALID_HANDLE_VALUE;
+  NTSTATUS status = NtCreateKey(&local_handle, desired_access, obj_attributes,
+                                title_index, class_name, create_options,
+                                disposition);
+  if (!NT_SUCCESS(status))
+    return status;
+
+  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                         target_process, target_key_handle, 0, FALSE,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return STATUS_ACCESS_DENIED;
+  }
+  return STATUS_SUCCESS;
+}
+
+NTSTATUS NtOpenKeyInTarget(HANDLE* target_key_handle,
+                           ACCESS_MASK desired_access,
+                           OBJECT_ATTRIBUTES* obj_attributes,
+                           HANDLE target_process) {
+  NtOpenKeyFunction NtOpenKey = NULL;
+  ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
+
+  if (MAXIMUM_ALLOWED & desired_access) {
+    NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
+    if (!NT_SUCCESS(status))
+      return STATUS_ACCESS_DENIED;
+  }
+
+  HANDLE local_handle = INVALID_HANDLE_VALUE;
+  NTSTATUS status = NtOpenKey(&local_handle, desired_access, obj_attributes);
+
+  if (!NT_SUCCESS(status))
+    return status;
+
+  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                         target_process, target_key_handle, 0, FALSE,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return STATUS_ACCESS_DENIED;
+  }
+  return STATUS_SUCCESS;
+}
+
+}
+
+namespace sandbox {
+
+bool RegistryPolicy::GenerateRules(const wchar_t* name,
+                                   TargetPolicy::Semantics semantics,
+                                   LowLevelPolicy* policy) {
+  base::string16 resovled_name(name);
+  if (resovled_name.empty()) {
+    return false;
+  }
+
+  if (!ResolveRegistryName(resovled_name, &resovled_name))
+    return false;
+
+  name = resovled_name.c_str();
+
+  EvalResult result = ASK_BROKER;
+
+  PolicyRule open(result);
+  PolicyRule create(result);
+
+  switch (semantics) {
+    case TargetPolicy::REG_ALLOW_READONLY: {
+      // We consider all flags that are not known to be readonly as potentially
+      // used for write. Here we also support MAXIMUM_ALLOWED, but we are going
+      // to expand it to read-only before the call.
+      uint32 restricted_flags = ~(kAllowedRegFlags | MAXIMUM_ALLOWED);
+      open.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
+      create.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
+      break;
+    }
+    case TargetPolicy::REG_ALLOW_ANY: {
+      break;
+    }
+    default: {
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  if (!create.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
+      !policy->AddRule(IPC_NTCREATEKEY_TAG, &create)) {
+    return false;
+  }
+
+  if (!open.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
+      !policy->AddRule(IPC_NTOPENKEY_TAG, &open)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool RegistryPolicy::CreateKeyAction(EvalResult eval_result,
+                                     const ClientInfo& client_info,
+                                     const base::string16 &key,
+                                     uint32 attributes,
+                                     HANDLE root_directory,
+                                     uint32 desired_access,
+                                     uint32 title_index,
+                                     uint32 create_options,
+                                     HANDLE* handle,
+                                     NTSTATUS* nt_status,
+                                     ULONG* disposition) {
+  // The only action supported is ASK_BROKER which means create the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return false;
+  }
+
+  // We don't support creating link keys, volatile keys or backup/restore.
+  if (create_options) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return false;
+  }
+
+  UNICODE_STRING uni_name = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  InitObjectAttribs(key, attributes, root_directory, &obj_attributes,
+                    &uni_name, NULL);
+  *nt_status = NtCreateKeyInTarget(handle, desired_access, &obj_attributes,
+                                   title_index, NULL, create_options,
+                                   disposition, client_info.process);
+  return true;
+}
+
+bool RegistryPolicy::OpenKeyAction(EvalResult eval_result,
+                                   const ClientInfo& client_info,
+                                   const base::string16 &key,
+                                   uint32 attributes,
+                                   HANDLE root_directory,
+                                   uint32 desired_access,
+                                   HANDLE* handle,
+                                   NTSTATUS* nt_status) {
+  // The only action supported is ASK_BROKER which means open the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result) {
+    *nt_status = STATUS_ACCESS_DENIED;
+    return true;
+  }
+
+  UNICODE_STRING uni_name = {0};
+  OBJECT_ATTRIBUTES obj_attributes = {0};
+  InitObjectAttribs(key, attributes, root_directory, &obj_attributes,
+                    &uni_name, NULL);
+  *nt_status = NtOpenKeyInTarget(handle, desired_access, &obj_attributes,
+                                client_info.process);
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/registry_policy.h b/sandbox/win/src/registry_policy.h
new file mode 100644
index 0000000..69af841
--- /dev/null
+++ b/sandbox/win/src/registry_policy.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_REGISTRY_POLICY_H__
+#define SANDBOX_SRC_REGISTRY_POLICY_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to registry policy
+class RegistryPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule for registry IO, in particular open or create actions.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Performs the desired policy action on a create request with an
+  // API that is compatible with the IPC-received parameters.
+  static bool CreateKeyAction(EvalResult eval_result,
+                              const ClientInfo& client_info,
+                              const base::string16 &key,
+                              uint32 attributes,
+                              HANDLE root_directory,
+                              uint32 desired_access,
+                              uint32 title_index,
+                              uint32 create_options,
+                              HANDLE* handle,
+                              NTSTATUS* nt_status,
+                              ULONG* disposition);
+
+  // Performs the desired policy action on an open request with an
+  // API that is compatible with the IPC-received parameters.
+  static bool OpenKeyAction(EvalResult eval_result,
+                              const ClientInfo& client_info,
+                              const base::string16 &key,
+                              uint32 attributes,
+                              HANDLE root_directory,
+                              uint32 desired_access,
+                              HANDLE* handle,
+                              NTSTATUS* nt_status);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_REGISTRY_POLICY_H__
diff --git a/sandbox/win/src/registry_policy_test.cc b/sandbox/win/src/registry_policy_test.cc
new file mode 100644
index 0000000..d8ee34b
--- /dev/null
+++ b/sandbox/win/src/registry_policy_test.cc
@@ -0,0 +1,289 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <shlobj.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/src/registry_policy.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+
+namespace {
+
+static const DWORD kAllowedRegFlags = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS |
+                                      KEY_NOTIFY | KEY_READ | GENERIC_READ |
+                                      GENERIC_EXECUTE | READ_CONTROL;
+
+#define BINDNTDLL(name) \
+  name ## Function name = reinterpret_cast<name ## Function>( \
+    ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
+
+bool IsKeyOpenForRead(HKEY handle) {
+  BINDNTDLL(NtQueryObject);
+
+  OBJECT_BASIC_INFORMATION info = {0};
+  NTSTATUS status = NtQueryObject(handle, ObjectBasicInformation, &info,
+                                  sizeof(info), NULL);
+
+  if (!NT_SUCCESS(status))
+    return false;
+
+  if ((info.GrantedAccess & (~kAllowedRegFlags)) != 0)
+    return false;
+  return true;
+}
+
+}
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int Reg_OpenKey(int argc, wchar_t **argv) {
+  if (argc != 4)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  REGSAM desired_access = 0;
+  ULONG options = 0;
+  if (wcscmp(argv[1], L"read") == 0) {
+    desired_access = KEY_READ;
+  } else if (wcscmp(argv[1], L"write") == 0) {
+    desired_access = KEY_ALL_ACCESS;
+  } else if (wcscmp(argv[1], L"link") == 0) {
+    options = REG_OPTION_CREATE_LINK;
+    desired_access = KEY_ALL_ACCESS;
+  } else {
+    desired_access = MAXIMUM_ALLOWED;
+  }
+
+  HKEY root = GetReservedKeyFromName(argv[2]);
+  HKEY key;
+  LRESULT result = 0;
+
+  if (wcscmp(argv[0], L"create") == 0)
+    result = ::RegCreateKeyEx(root, argv[3], 0, NULL, options, desired_access,
+                              NULL, &key, NULL);
+  else
+    result = ::RegOpenKeyEx(root, argv[3], 0, desired_access, &key);
+
+  if (ERROR_SUCCESS == result) {
+    if (MAXIMUM_ALLOWED == desired_access) {
+      if (!IsKeyOpenForRead(key)) {
+        ::RegCloseKey(key);
+        return SBOX_TEST_FAILED;
+      }
+    }
+    ::RegCloseKey(key);
+    return SBOX_TEST_SUCCEEDED;
+  } else if (ERROR_ACCESS_DENIED == result) {
+    return SBOX_TEST_DENIED;
+  }
+
+  return SBOX_TEST_FAILED;
+}
+
+TEST(RegistryPolicyTest, TestKeyAnyAccess) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
+
+  // Tests read access on key allowed for read-write.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+      L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software\\microsoft"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+      L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software\\microsoft"));
+
+  if (::IsUserAnAdmin()) {
+    // Tests write access on key allowed for read-write.
+    EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+        L"Reg_OpenKey create write HKEY_LOCAL_MACHINE software\\microsoft"));
+
+    EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+        L"Reg_OpenKey open write HKEY_LOCAL_MACHINE software\\microsoft"));
+  }
+
+  // Tests subdirectory access on keys where we don't have subdirectory acess.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey create read "
+      L"HKEY_LOCAL_MACHINE software\\microsoft\\Windows"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey open read "
+      L"HKEY_LOCAL_MACHINE software\\microsoft\\windows"));
+
+  // Tests to see if we can create keys where we dont have subdirectory access.
+  // This is denied.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey create write "
+      L"HKEY_LOCAL_MACHINE software\\Microsoft\\google_unit_tests"));
+
+  RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Microsoft\\google_unit_tests");
+
+  // Tests if we need to handle differently the "\\" at the end.
+  // This is denied. We need to add both rules.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
+      L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software\\microsoft\\"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
+      L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software\\microsoft\\"));
+}
+
+TEST(RegistryPolicyTest, TestKeyNoAccess) {
+  TestRunner runner;
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE"));
+
+  // Tests read access where we don't have access at all.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
+      L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
+      L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software"));
+}
+
+TEST(RegistryPolicyTest, TestKeyReadOnlyAccess) {
+  TestRunner runner;
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
+
+  // Tests subdirectory acess on keys where we have subdirectory acess.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey create read "
+      L"HKEY_LOCAL_MACHINE software\\Policies\\microsoft"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey open read "
+      L"HKEY_LOCAL_MACHINE software\\Policies\\microsoft"));
+
+  // Tests to see if we can create keys where we have subdirectory access.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Reg_OpenKey create write "
+      L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
+
+  RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Policies\\google_unit_tests");
+}
+
+TEST(RegistryPolicyTest, TestKeyAllAccessSubDir) {
+  TestRunner runner;
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
+
+  if (::IsUserAnAdmin()) {
+    // Tests to see if we can create keys where we have subdirectory access.
+    EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey create write "
+        L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
+
+    RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Policies\\google_unit_tests");
+  }
+}
+
+TEST(RegistryPolicyTest, TestKeyCreateLink) {
+  TestRunner runner;
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_LOCAL_MACHINE"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
+
+  // Tests to see if we can create a registry link key.
+  // NOTE: In theory here we should make sure to check for SBOX_TEST_DENIED
+  // instead of !SBOX_TEST_SUCCEEDED, but unfortunately the result is not
+  // access denied. Internally RegCreateKeyEx (At least on Vista 64) tries to
+  // create the link, and we return successfully access denied, then, it
+  // decides to try to break the path in multiple chunks, and create the links
+  // one by one. In this scenario, it tries to create "HKLM\Software" as a
+  // link key, which obviously fail with STATUS_OBJECT_NAME_COLLISION, and
+  // this is what is returned to the user.
+  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Reg_OpenKey create link "
+      L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
+
+  // In case our code fails, and the call works, we need to delete the new
+  // link. There is no api for this, so we need to use the NT call.
+  HKEY key = NULL;
+  LRESULT result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                                  L"software\\Policies\\google_unit_tests",
+                                  REG_OPTION_OPEN_LINK, MAXIMUM_ALLOWED,
+                                  &key);
+
+  if (!result) {
+    HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
+    NtDeleteKeyFunction NtDeleteKey =
+        reinterpret_cast<NtDeleteKeyFunction>(GetProcAddress(ntdll,
+                                                             "NtDeleteKey"));
+    NtDeleteKey(key);
+  }
+}
+
+TEST(RegistryPolicyTest, TestKeyReadOnlyHKCU) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_CURRENT_USER"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_CURRENT_USER\\Software"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_USERS\\.default"));
+
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_READONLY,
+                             L"HKEY_USERS\\.default\\software"));
+
+  // Tests read access where we only have read-only access.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+      L"Reg_OpenKey create read HKEY_CURRENT_USER software"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+      L"Reg_OpenKey open read HKEY_CURRENT_USER software"));
+
+  // Tests write access where we only have read-only acess.
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
+      L"Reg_OpenKey create write HKEY_CURRENT_USER software"));
+
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(
+      L"Reg_OpenKey open write HKEY_CURRENT_USER software"));
+
+  // Tests maximum allowed access where we only have read-only access.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+      L"Reg_OpenKey create maximum_allowed HKEY_CURRENT_USER software"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(
+      L"Reg_OpenKey open maximum_allowed HKEY_CURRENT_USER software"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/resolver.cc b/sandbox/win/src/resolver.cc
new file mode 100644
index 0000000..6616fa5
--- /dev/null
+++ b/sandbox/win/src/resolver.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/resolver.h"
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+NTSTATUS ResolverThunk::Init(const void* target_module,
+                             const void* interceptor_module,
+                             const char* target_name,
+                             const char* interceptor_name,
+                             const void* interceptor_entry_point,
+                             void* thunk_storage,
+                             size_t storage_bytes) {
+  if (NULL == thunk_storage || 0 == storage_bytes ||
+      NULL == target_module || NULL == target_name)
+    return STATUS_INVALID_PARAMETER;
+
+  if (storage_bytes < GetThunkSize())
+    return STATUS_BUFFER_TOO_SMALL;
+
+  NTSTATUS ret = STATUS_SUCCESS;
+  if (NULL == interceptor_entry_point) {
+    ret = ResolveInterceptor(interceptor_module, interceptor_name,
+                             &interceptor_entry_point);
+    if (!NT_SUCCESS(ret))
+      return ret;
+  }
+
+  ret = ResolveTarget(target_module, target_name, &target_);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  interceptor_ = interceptor_entry_point;
+
+  return ret;
+}
+
+NTSTATUS ResolverThunk::ResolveInterceptor(const void* interceptor_module,
+                                           const char* interceptor_name,
+                                           const void** address) {
+  DCHECK_NT(address);
+  if (!interceptor_module)
+    return STATUS_INVALID_PARAMETER;
+
+  base::win::PEImage pe(interceptor_module);
+  if (!pe.VerifyMagic())
+    return STATUS_INVALID_IMAGE_FORMAT;
+
+  *address = pe.GetProcAddress(interceptor_name);
+
+  if (!(*address))
+    return STATUS_PROCEDURE_NOT_FOUND;
+
+  return STATUS_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/resolver.h b/sandbox/win/src/resolver.h
new file mode 100644
index 0000000..85f1e91
--- /dev/null
+++ b/sandbox/win/src/resolver.h
@@ -0,0 +1,105 @@
+// 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.
+
+// Defines ResolverThunk, the interface for classes that perform interceptions.
+// For more details see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/nt_internals.h"
+
+#ifndef SANDBOX_SRC_RESOLVER_H__
+#define SANDBOX_SRC_RESOLVER_H__
+
+namespace sandbox {
+
+// A resolver is the object in charge of performing the actual interception of
+// a function. There should be a concrete implementation of a resolver roughly
+// per type of interception.
+class ResolverThunk {
+ public:
+  ResolverThunk() {}
+  virtual ~ResolverThunk() {}
+
+  // Performs the actual interception of a function.
+  // target_name is an exported function from the module loaded at
+  // target_module, and must be replaced by interceptor_name, exported from
+  // interceptor_module. interceptor_entry_point can be provided instead of
+  // interceptor_name / interceptor_module.
+  // thunk_storage must point to a buffer on the child's address space, to hold
+  // the patch thunk, and related data. If provided, storage_used will receive
+  // the number of bytes used from thunk_storage.
+  //
+  // Example: (without error checking)
+  //
+  // size_t size = resolver.GetThunkSize();
+  // char* buffer = ::VirtualAllocEx(child_process, NULL, size,
+  //                                 MEM_COMMIT, PAGE_READWRITE);
+  // resolver.Setup(ntdll_module, NULL, L"NtCreateFile", NULL,
+  //                &MyReplacementFunction, buffer, size, NULL);
+  //
+  // In general, the idea is to allocate a single big buffer for all
+  // interceptions on the same dll, and call Setup n times.
+  // WARNING: This means that any data member that is specific to a single
+  // interception must be reset within this method.
+  virtual NTSTATUS Setup(const void* target_module,
+                         const void* interceptor_module,
+                         const char* target_name,
+                         const char* interceptor_name,
+                         const void* interceptor_entry_point,
+                         void* thunk_storage,
+                         size_t storage_bytes,
+                         size_t* storage_used) = 0;
+
+  // Gets the address of function_name inside module (main exe).
+  virtual NTSTATUS ResolveInterceptor(const void* module,
+                                      const char* function_name,
+                                      const void** address);
+
+  // Gets the address of an exported function_name inside module.
+  virtual NTSTATUS ResolveTarget(const void* module,
+                                 const char* function_name,
+                                 void** address);
+
+  // Gets the required buffer size for this type of thunk.
+  virtual size_t GetThunkSize() const = 0;
+
+ protected:
+  // Performs basic initialization on behalf of a concrete instance of a
+  // resolver. That is, parameter validation and resolution of the target
+  // and the interceptor into the member variables.
+  //
+  // target_name is an exported function from the module loaded at
+  // target_module, and must be replaced by interceptor_name, exported from
+  // interceptor_module. interceptor_entry_point can be provided instead of
+  // interceptor_name / interceptor_module.
+  // thunk_storage must point to a buffer on the child's address space, to hold
+  // the patch thunk, and related data.
+  virtual NTSTATUS Init(const void* target_module,
+                        const void* interceptor_module,
+                        const char* target_name,
+                        const char* interceptor_name,
+                        const void* interceptor_entry_point,
+                        void* thunk_storage,
+                        size_t storage_bytes);
+
+  // Gets the required buffer size for the internal part of the thunk.
+  size_t GetInternalThunkSize() const;
+
+  // Initializes the internal part of the thunk.
+  // interceptor is the function to be called instead of original_function.
+  bool SetInternalThunk(void* storage, size_t storage_bytes,
+                        const void* original_function, const void* interceptor);
+
+  // Holds the resolved interception target.
+  void* target_;
+  // Holds the resolved interception interceptor.
+  const void* interceptor_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResolverThunk);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_RESOLVER_H__
diff --git a/sandbox/win/src/resolver_32.cc b/sandbox/win/src/resolver_32.cc
new file mode 100644
index 0000000..a591a8b
--- /dev/null
+++ b/sandbox/win/src/resolver_32.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/resolver.h"
+
+// For placement new. This file must not depend on the CRT at runtime, but
+// placement operator new is inline.
+#include <new>
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+#pragma pack(push, 1)
+struct InternalThunk {
+  // This struct contains roughly the following code:
+  // sub esp, 8                             // Create working space
+  // push edx                               // Save register
+  // mov edx, [esp + 0xc]                   // Get return adddress
+  // mov [esp + 8], edx                     // Store return address
+  // mov dword ptr [esp + 0xc], 0x7c401200  // Store extra argument
+  // mov dword ptr [esp + 4], 0x40010203    // Store address to jump to
+  // pop edx                                // Restore register
+  // ret                                    // Jump to interceptor
+  //
+  // This code only modifies esp and eip so it must work with to normal calling
+  // convention. It is assembled as:
+  //
+  // 00 83ec08           sub     esp,8
+  // 03 52               push    edx
+  // 04 8b54240c         mov     edx,dword ptr [esp + 0Ch]
+  // 08 89542408         mov     dword ptr [esp + 8], edx
+  // 0c c744240c0012407c mov     dword ptr [esp + 0Ch], 7C401200h
+  // 14 c744240403020140 mov     dword ptr [esp + 4], 40010203h
+  // 1c 5a               pop     edx
+  // 1d c3               ret
+  InternalThunk() {
+    opcodes_1 = 0x5208ec83;
+    opcodes_2 = 0x0c24548b;
+    opcodes_3 = 0x08245489;
+    opcodes_4 = 0x0c2444c7;
+    opcodes_5 = 0x042444c7;
+    opcodes_6 = 0xc35a;
+    extra_argument = 0;
+    interceptor_function = 0;
+  };
+  ULONG opcodes_1;         // = 0x5208ec83
+  ULONG opcodes_2;         // = 0x0c24548b
+  ULONG opcodes_3;         // = 0x08245489
+  ULONG opcodes_4;         // = 0x0c2444c7
+  ULONG extra_argument;
+  ULONG opcodes_5;         // = 0x042444c7
+  ULONG interceptor_function;
+  USHORT opcodes_6;         // = 0xc35a
+};
+#pragma pack(pop)
+
+};  // namespace
+
+namespace sandbox {
+
+bool ResolverThunk::SetInternalThunk(void* storage, size_t storage_bytes,
+                                     const void* original_function,
+                                     const void* interceptor) {
+  if (storage_bytes < sizeof(InternalThunk))
+    return false;
+
+  InternalThunk* thunk = new(storage) InternalThunk;
+
+#pragma warning(push)
+#pragma warning(disable: 4311)
+  // These casts generate warnings because they are 32 bit specific.
+  thunk->interceptor_function = reinterpret_cast<ULONG>(interceptor);
+  thunk->extra_argument = reinterpret_cast<ULONG>(original_function);
+#pragma warning(pop)
+
+  return true;
+}
+
+size_t ResolverThunk::GetInternalThunkSize() const {
+  return sizeof(InternalThunk);
+}
+
+NTSTATUS ResolverThunk::ResolveTarget(const void* module,
+                                      const char* function_name,
+                                      void** address) {
+  const void** casted = const_cast<const void**>(address);
+  return ResolverThunk::ResolveInterceptor(module, function_name, casted);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/resolver_64.cc b/sandbox/win/src/resolver_64.cc
new file mode 100644
index 0000000..8b2cc53
--- /dev/null
+++ b/sandbox/win/src/resolver_64.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/resolver.h"
+
+// For placement new. This file must not depend on the CRT at runtime, but
+// placement operator new is inline.
+#include <new>
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+const BYTE kPushRax = 0x50;
+const USHORT kMovRax = 0xB848;
+const ULONG kMovRspRax = 0x24048948;
+const BYTE kRetNp = 0xC3;
+
+#pragma pack(push, 1)
+struct InternalThunk {
+  // This struct contains roughly the following code:
+  // 00 50                    push  rax
+  // 01 48b8f0debc9a78563412  mov   rax,123456789ABCDEF0h
+  // 0b 48890424              mov   qword ptr [rsp],rax
+  // 0f c3                    ret
+  //
+  // The code modifies rax, but that should not be an issue for the common
+  // calling conventions.
+
+  InternalThunk() {
+    push_rax = kPushRax;
+    mov_rax = kMovRax;
+    interceptor_function = 0;
+    mov_rsp_rax = kMovRspRax;
+    ret = kRetNp;
+  };
+  BYTE push_rax;        // = 50
+  USHORT mov_rax;       // = 48 B8
+  ULONG_PTR interceptor_function;
+  ULONG mov_rsp_rax;    // = 48 89 04 24
+  BYTE ret;             // = C3
+};
+#pragma pack(pop)
+
+} // namespace.
+
+namespace sandbox {
+
+size_t ResolverThunk::GetInternalThunkSize() const {
+  return sizeof(InternalThunk);
+}
+
+bool ResolverThunk::SetInternalThunk(void* storage, size_t storage_bytes,
+                                     const void* original_function,
+                                     const void* interceptor) {
+  if (storage_bytes < sizeof(InternalThunk))
+    return false;
+
+  InternalThunk* thunk = new(storage) InternalThunk;
+  thunk->interceptor_function = reinterpret_cast<ULONG_PTR>(interceptor);
+
+  return true;
+}
+
+NTSTATUS ResolverThunk::ResolveTarget(const void* module,
+                                      const char* function_name,
+                                      void** address) {
+  // We don't support sidestep & co.
+  return STATUS_NOT_IMPLEMENTED;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/restricted_token.cc b/sandbox/win/src/restricted_token.cc
new file mode 100644
index 0000000..7ebef3d
--- /dev/null
+++ b/sandbox/win/src/restricted_token.cc
@@ -0,0 +1,481 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/restricted_token.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+RestrictedToken::RestrictedToken()
+    : init_(false),
+      effective_token_(NULL),
+      integrity_level_(INTEGRITY_LEVEL_LAST) {
+}
+
+RestrictedToken::~RestrictedToken() {
+  if (effective_token_)
+    CloseHandle(effective_token_);
+}
+
+unsigned RestrictedToken::Init(const HANDLE effective_token) {
+  if (init_)
+    return ERROR_ALREADY_INITIALIZED;
+
+  if (effective_token) {
+    // We duplicate the handle to be able to use it even if the original handle
+    // is closed.
+    HANDLE effective_token_dup;
+    if (::DuplicateHandle(::GetCurrentProcess(),
+                          effective_token,
+                          ::GetCurrentProcess(),
+                          &effective_token_dup,
+                          0,
+                          FALSE,
+                          DUPLICATE_SAME_ACCESS)) {
+      effective_token_ = effective_token_dup;
+    } else {
+      return ::GetLastError();
+    }
+  } else {
+    if (!::OpenProcessToken(::GetCurrentProcess(),
+                            TOKEN_ALL_ACCESS,
+                            &effective_token_))
+      return ::GetLastError();
+  }
+
+  init_ = true;
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::GetRestrictedTokenHandle(HANDLE *token_handle) const {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  size_t deny_size = sids_for_deny_only_.size();
+  size_t restrict_size = sids_to_restrict_.size();
+  size_t privileges_size = privileges_to_disable_.size();
+
+  SID_AND_ATTRIBUTES *deny_only_array = NULL;
+  if (deny_size) {
+    deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
+
+    for (unsigned int i = 0; i < sids_for_deny_only_.size() ; ++i) {
+      deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
+      deny_only_array[i].Sid =
+          const_cast<SID*>(sids_for_deny_only_[i].GetPSID());
+    }
+  }
+
+  SID_AND_ATTRIBUTES *sids_to_restrict_array = NULL;
+  if (restrict_size) {
+    sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
+
+    for (unsigned int i = 0; i < restrict_size; ++i) {
+      sids_to_restrict_array[i].Attributes = 0;
+      sids_to_restrict_array[i].Sid =
+          const_cast<SID*>(sids_to_restrict_[i].GetPSID());
+    }
+  }
+
+  LUID_AND_ATTRIBUTES *privileges_to_disable_array = NULL;
+  if (privileges_size) {
+    privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
+
+    for (unsigned int i = 0; i < privileges_size; ++i) {
+      privileges_to_disable_array[i].Attributes = 0;
+      privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
+    }
+  }
+
+  BOOL result = TRUE;
+  HANDLE new_token = NULL;
+  // The SANDBOX_INERT flag did nothing in XP and it was just a way to tell
+  // if a token has ben restricted given the limiations of IsTokenRestricted()
+  // but it appears that in Windows 7 it hints the AppLocker subsystem to
+  // leave us alone.
+  if (deny_size || restrict_size || privileges_size) {
+    result = ::CreateRestrictedToken(effective_token_,
+                                     SANDBOX_INERT,
+                                     static_cast<DWORD>(deny_size),
+                                     deny_only_array,
+                                     static_cast<DWORD>(privileges_size),
+                                     privileges_to_disable_array,
+                                     static_cast<DWORD>(restrict_size),
+                                     sids_to_restrict_array,
+                                     &new_token);
+  } else {
+    // Duplicate the token even if it's not modified at this point
+    // because any subsequent changes to this token would also affect the
+    // current process.
+    result = ::DuplicateTokenEx(effective_token_, TOKEN_ALL_ACCESS, NULL,
+                                SecurityIdentification, TokenPrimary,
+                                &new_token);
+  }
+
+  if (deny_only_array)
+    delete[] deny_only_array;
+
+  if (sids_to_restrict_array)
+    delete[] sids_to_restrict_array;
+
+  if (privileges_to_disable_array)
+    delete[] privileges_to_disable_array;
+
+  if (!result)
+    return ::GetLastError();
+
+  // Modify the default dacl on the token to contain Restricted and the user.
+  if (!AddSidToDefaultDacl(new_token, WinRestrictedCodeSid, GENERIC_ALL))
+    return ::GetLastError();
+
+  if (!AddUserSidToDefaultDacl(new_token, GENERIC_ALL))
+    return ::GetLastError();
+
+  DWORD error = SetTokenIntegrityLevel(new_token, integrity_level_);
+  if (ERROR_SUCCESS != error)
+    return error;
+
+  BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
+                                  new_token,
+                                  ::GetCurrentProcess(),
+                                  token_handle,
+                                  TOKEN_ALL_ACCESS,
+                                  FALSE,  // Don't inherit.
+                                  0);
+
+  if (new_token != effective_token_)
+    ::CloseHandle(new_token);
+
+  if (!status)
+    return ::GetLastError();
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::GetRestrictedTokenHandleForImpersonation(
+    HANDLE *token_handle) const {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  HANDLE restricted_token_handle;
+  unsigned err_code = GetRestrictedTokenHandle(&restricted_token_handle);
+  if (ERROR_SUCCESS != err_code)
+    return err_code;
+
+  HANDLE impersonation_token;
+  if (!::DuplicateToken(restricted_token_handle,
+                        SecurityImpersonation,
+                        &impersonation_token)) {
+    ::CloseHandle(restricted_token_handle);
+    return ::GetLastError();
+  }
+
+  ::CloseHandle(restricted_token_handle);
+
+  BOOL status = ::DuplicateHandle(::GetCurrentProcess(),
+                                  impersonation_token,
+                                  ::GetCurrentProcess(),
+                                  token_handle,
+                                  TOKEN_ALL_ACCESS,
+                                  FALSE,  // Don't inherit.
+                                  0);
+
+  ::CloseHandle(impersonation_token);
+
+  if (!status)
+    return ::GetLastError();
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid> *exceptions) {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  TOKEN_GROUPS *token_groups = NULL;
+  DWORD size = 0;
+
+  BOOL result = ::GetTokenInformation(effective_token_,
+                                      TokenGroups,
+                                      NULL,  // No buffer.
+                                      0,  // Size is 0.
+                                      &size);
+  if (!size)
+    return ::GetLastError();
+
+  token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
+  result = ::GetTokenInformation(effective_token_,
+                                 TokenGroups,
+                                 token_groups,
+                                 size,
+                                 &size);
+  if (!result) {
+    delete[] reinterpret_cast<BYTE*>(token_groups);
+    return ::GetLastError();
+  }
+
+  // Build the list of the deny only group SIDs
+  for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
+    if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
+        (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
+      bool should_ignore = false;
+      if (exceptions) {
+        for (unsigned int j = 0; j < exceptions->size(); ++j) {
+          if (::EqualSid(const_cast<SID*>((*exceptions)[j].GetPSID()),
+                          token_groups->Groups[i].Sid)) {
+            should_ignore = true;
+            break;
+          }
+        }
+      }
+      if (!should_ignore) {
+        sids_for_deny_only_.push_back(
+            reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
+      }
+    }
+  }
+
+  delete[] reinterpret_cast<BYTE*>(token_groups);
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddSidForDenyOnly(const Sid &sid) {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  sids_for_deny_only_.push_back(sid);
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddUserSidForDenyOnly() {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+  TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
+
+  BOOL result = ::GetTokenInformation(effective_token_,
+                                      TokenUser,
+                                      token_user,
+                                      size,
+                                      &size);
+
+  if (!result) {
+    delete[] reinterpret_cast<BYTE*>(token_user);
+    return ::GetLastError();
+  }
+
+  Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
+  sids_for_deny_only_.push_back(user);
+
+  delete[] reinterpret_cast<BYTE*>(token_user);
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::DeleteAllPrivileges(
+    const std::vector<base::string16> *exceptions) {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  // Get the list of privileges in the token
+  TOKEN_PRIVILEGES *token_privileges = NULL;
+  DWORD size = 0;
+
+  BOOL result = ::GetTokenInformation(effective_token_,
+                                      TokenPrivileges,
+                                      NULL,  // No buffer.
+                                      0,  // Size is 0.
+                                      &size);
+  if (!size)
+    return ::GetLastError();
+
+  token_privileges = reinterpret_cast<TOKEN_PRIVILEGES*>(new BYTE[size]);
+  result = ::GetTokenInformation(effective_token_,
+                                 TokenPrivileges,
+                                 token_privileges,
+                                 size,
+                                 &size);
+  if (!result) {
+    delete[] reinterpret_cast<BYTE *>(token_privileges);
+    return ::GetLastError();
+  }
+
+
+  // Build the list of privileges to disable
+  for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
+    bool should_ignore = false;
+    if (exceptions) {
+      for (unsigned int j = 0; j < exceptions->size(); ++j) {
+        LUID luid = {0};
+        ::LookupPrivilegeValue(NULL, (*exceptions)[j].c_str(), &luid);
+        if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
+            token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
+          should_ignore = true;
+          break;
+        }
+      }
+    }
+    if (!should_ignore) {
+        privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
+    }
+  }
+
+  delete[] reinterpret_cast<BYTE *>(token_privileges);
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::DeletePrivilege(const wchar_t *privilege) {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  LUID luid = {0};
+  if (LookupPrivilegeValue(NULL, privilege, &luid))
+    privileges_to_disable_.push_back(luid);
+  else
+    return ::GetLastError();
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddRestrictingSid(const Sid &sid) {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  sids_to_restrict_.push_back(sid);  // No attributes
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddRestrictingSidLogonSession() {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  TOKEN_GROUPS *token_groups = NULL;
+  DWORD size = 0;
+
+  BOOL result = ::GetTokenInformation(effective_token_,
+                                      TokenGroups,
+                                      NULL,  // No buffer.
+                                      0,  // Size is 0.
+                                      &size);
+  if (!size)
+    return ::GetLastError();
+
+  token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
+  result = ::GetTokenInformation(effective_token_,
+                                 TokenGroups,
+                                 token_groups,
+                                 size,
+                                 &size);
+  if (!result) {
+    delete[] reinterpret_cast<BYTE*>(token_groups);
+    return ::GetLastError();
+  }
+
+  SID *logon_sid = NULL;
+  for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
+    if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
+        logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
+        break;
+    }
+  }
+
+  if (logon_sid)
+    sids_to_restrict_.push_back(logon_sid);
+
+  delete[] reinterpret_cast<BYTE*>(token_groups);
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddRestrictingSidCurrentUser() {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+  TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(new BYTE[size]);
+
+  BOOL result = ::GetTokenInformation(effective_token_,
+                                      TokenUser,
+                                      token_user,
+                                      size,
+                                      &size);
+
+  if (!result) {
+    delete[] reinterpret_cast<BYTE*>(token_user);
+    return ::GetLastError();
+  }
+
+  Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
+  sids_to_restrict_.push_back(user);
+
+  delete[] reinterpret_cast<BYTE*>(token_user);
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::AddRestrictingSidAllSids() {
+  DCHECK(init_);
+  if (!init_)
+    return ERROR_NO_TOKEN;
+
+  // Add the current user to the list.
+  unsigned error = AddRestrictingSidCurrentUser();
+  if (ERROR_SUCCESS != error)
+    return error;
+
+  TOKEN_GROUPS *token_groups = NULL;
+  DWORD size = 0;
+
+  // Get the buffer size required.
+  BOOL result = ::GetTokenInformation(effective_token_, TokenGroups, NULL, 0,
+                                      &size);
+  if (!size)
+    return ::GetLastError();
+
+  token_groups = reinterpret_cast<TOKEN_GROUPS*>(new BYTE[size]);
+  result = ::GetTokenInformation(effective_token_,
+                                 TokenGroups,
+                                 token_groups,
+                                 size,
+                                 &size);
+  if (!result) {
+    delete[] reinterpret_cast<BYTE*>(token_groups);
+    return ::GetLastError();
+  }
+
+  // Build the list of restricting sids from all groups.
+  for (unsigned int i = 0; i < token_groups->GroupCount ; ++i) {
+    if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
+      AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
+  }
+
+  delete[] reinterpret_cast<BYTE*>(token_groups);
+
+  return ERROR_SUCCESS;
+}
+
+unsigned RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
+  integrity_level_ = integrity_level;
+  return ERROR_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/restricted_token.h b/sandbox/win/src/restricted_token.h
new file mode 100644
index 0000000..565880e
--- /dev/null
+++ b/sandbox/win/src/restricted_token.h
@@ -0,0 +1,193 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_RESTRICTED_TOKEN_H_
+#define SANDBOX_SRC_RESTRICTED_TOKEN_H_
+
+#include <windows.h>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/sid.h"
+
+// Flags present in the Group SID list. These 2 flags are new in Windows Vista
+#ifndef SE_GROUP_INTEGRITY
+#define SE_GROUP_INTEGRITY (0x00000020L)
+#endif
+#ifndef SE_GROUP_INTEGRITY_ENABLED
+#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
+#endif
+
+namespace sandbox {
+
+// Handles the creation of a restricted token using the effective token or
+// any token handle.
+// Sample usage:
+//    RestrictedToken restricted_token;
+//    unsigned err_code = restricted_token.Init(NULL);  // Use the current
+//                                                      // effective token
+//    if (ERROR_SUCCESS != err_code) {
+//      // handle error.
+//    }
+//
+//    restricted_token.AddRestrictingSid(ATL::Sids::Users().GetPSID());
+//    HANDLE token_handle;
+//    err_code = restricted_token.GetRestrictedTokenHandle(&token_handle);
+//    if (ERROR_SUCCESS != err_code) {
+//      // handle error.
+//    }
+//    [...]
+//    CloseHandle(token_handle);
+class RestrictedToken {
+ public:
+  // Init() has to be called before calling any other method in the class.
+  RestrictedToken();
+  ~RestrictedToken();
+
+  // Initializes the RestrictedToken object with effective_token.
+  // If effective_token is NULL, it initializes the RestrictedToken object with
+  // the effective token of the current process.
+  unsigned Init(HANDLE effective_token);
+
+  // Creates a restricted token and returns its handle using the token_handle
+  // output parameter. This handle has to be closed by the caller.
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  unsigned GetRestrictedTokenHandle(HANDLE *token_handle) const;
+
+  // Creates a restricted token and uses this new token to create a new token
+  // for impersonation. Returns the handle of this impersonation token using
+  // the token_handle output parameter. This handle has to be closed by
+  // the caller.
+  //
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  //
+  // The sample usage is the same as the GetRestrictedTokenHandle function.
+  unsigned GetRestrictedTokenHandleForImpersonation(HANDLE *token_handle) const;
+
+  // Lists all sids in the token and mark them as Deny Only except for those
+  // present in the exceptions parameter. If there is no exception needed,
+  // the caller can pass an empty list or NULL for the exceptions
+  // parameter.
+  //
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  //
+  // Sample usage:
+  //    std::vector<Sid> sid_exceptions;
+  //    sid_exceptions.push_back(ATL::Sids::Users().GetPSID());
+  //    sid_exceptions.push_back(ATL::Sids::World().GetPSID());
+  //    restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
+  // Note: A Sid marked for Deny Only in a token cannot be used to grant
+  // access to any resource. It can only be used to deny access.
+  unsigned AddAllSidsForDenyOnly(std::vector<Sid> *exceptions);
+
+  // Adds a user or group SID for Deny Only in the restricted token.
+  // Parameter: sid is the SID to add in the Deny Only list.
+  // The return value is always ERROR_SUCCESS.
+  //
+  // Sample Usage:
+  //    restricted_token.AddSidForDenyOnly(ATL::Sids::Admins().GetPSID());
+  unsigned AddSidForDenyOnly(const Sid &sid);
+
+  // Adds the user sid of the token for Deny Only in the restricted token.
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  unsigned AddUserSidForDenyOnly();
+
+  // Lists all privileges in the token and add them to the list of privileges
+  // to remove except for those present in the exceptions parameter. If
+  // there is no exception needed, the caller can pass an empty list or NULL
+  // for the exceptions parameter.
+  //
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  //
+  // Sample usage:
+  //    std::vector<base::string16> privilege_exceptions;
+  //    privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+  //    restricted_token.DeleteAllPrivileges(&privilege_exceptions);
+  unsigned DeleteAllPrivileges(
+      const std::vector<base::string16> *exceptions);
+
+  // Adds a privilege to the list of privileges to remove in the restricted
+  // token.
+  // Parameter: privilege is the privilege name to remove. This is the string
+  // representing the privilege. (e.g. "SeChangeNotifyPrivilege").
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  //
+  // Sample usage:
+  //    restricted_token.DeletePrivilege(SE_LOAD_DRIVER_NAME);
+  unsigned DeletePrivilege(const wchar_t *privilege);
+
+  // Adds a SID to the list of restricting sids in the restricted token.
+  // Parameter: sid is the sid to add to the list restricting sids.
+  // The return value is always ERROR_SUCCESS.
+  //
+  // Sample usage:
+  //    restricted_token.AddRestrictingSid(ATL::Sids::Users().GetPSID());
+  // Note: The list of restricting is used to force Windows to perform all
+  // access checks twice. The first time using your user SID and your groups,
+  // and the second time using your list of restricting sids. The access has
+  // to be granted in both places to get access to the resource requested.
+  unsigned AddRestrictingSid(const Sid &sid);
+
+  // Adds the logon sid of the token in the list of restricting sids for the
+  // restricted token.
+  //
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  unsigned AddRestrictingSidLogonSession();
+
+  // Adds the owner sid of the token in the list of restricting sids for the
+  // restricted token.
+  //
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  unsigned AddRestrictingSidCurrentUser();
+
+  // Adds all group sids and the user sid to the restricting sids list.
+  //
+  // If the function succeeds, the return value is ERROR_SUCCESS. If the
+  // function fails, the return value is the win32 error code corresponding to
+  // the error.
+  unsigned AddRestrictingSidAllSids();
+
+  // Sets the token integrity level. This is only valid on Vista. The integrity
+  // level cannot be higher than your current integrity level.
+  unsigned SetIntegrityLevel(IntegrityLevel integrity_level);
+
+ private:
+  // The list of restricting sids in the restricted token.
+  std::vector<Sid> sids_to_restrict_;
+  // The list of privileges to remove in the restricted token.
+  std::vector<LUID> privileges_to_disable_;
+  // The list of sids to mark as Deny Only in the restricted token.
+  std::vector<Sid> sids_for_deny_only_;
+  // The token to restrict. Can only be set in a constructor.
+  HANDLE effective_token_;
+  // The token integrity level. Only valid on Vista.
+  IntegrityLevel integrity_level_;
+  // Tells if the object is initialized or not (if Init() has been called)
+  bool init_;
+
+  DISALLOW_COPY_AND_ASSIGN(RestrictedToken);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_RESTRICTED_TOKEN_H_
diff --git a/sandbox/win/src/restricted_token_unittest.cc b/sandbox/win/src/restricted_token_unittest.cc
new file mode 100644
index 0000000..8186f9c
--- /dev/null
+++ b/sandbox/win/src/restricted_token_unittest.cc
@@ -0,0 +1,588 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for the RestrictedToken.
+
+#define _ATL_NO_EXCEPTIONS
+#include <atlbase.h>
+#include <atlsecurity.h>
+#include <vector>
+#include "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/sid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Tests the initializatioin with an invalid token handle.
+TEST(RestrictedTokenTest, InvalidHandle) {
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_INVALID_HANDLE, token.Init(reinterpret_cast<HANDLE>(0x5555)));
+}
+
+// Tests the initialization with NULL as parameter.
+TEST(RestrictedTokenTest, DefaultInit) {
+  // Get the current process token.
+  HANDLE token_handle = INVALID_HANDLE_VALUE;
+  ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+                                 &token_handle));
+
+  ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+
+  ATL::CAccessToken access_token;
+  access_token.Attach(token_handle);
+
+  // Create the token using the current token.
+  RestrictedToken token_default;
+  ASSERT_EQ(ERROR_SUCCESS, token_default.Init(NULL));
+
+  // Get the handle to the restricted token.
+
+  HANDLE restricted_token_handle = NULL;
+  ASSERT_EQ(ERROR_SUCCESS,
+      token_default.GetRestrictedTokenHandle(&restricted_token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(restricted_token_handle);
+
+  ATL::CSid sid_user_restricted;
+  ATL::CSid sid_user_default;
+  ATL::CSid sid_owner_restricted;
+  ATL::CSid sid_owner_default;
+  ASSERT_TRUE(restricted_token.GetUser(&sid_user_restricted));
+  ASSERT_TRUE(access_token.GetUser(&sid_user_default));
+  ASSERT_TRUE(restricted_token.GetOwner(&sid_owner_restricted));
+  ASSERT_TRUE(access_token.GetOwner(&sid_owner_default));
+
+  // Check if both token have the same owner and user.
+  ASSERT_EQ(sid_user_restricted, sid_user_default);
+  ASSERT_EQ(sid_owner_restricted, sid_owner_default);
+}
+
+// Tests the initialization with a custom token as parameter.
+TEST(RestrictedTokenTest, CustomInit) {
+  // Get the current process token.
+  HANDLE token_handle = INVALID_HANDLE_VALUE;
+  ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+                                 &token_handle));
+
+  ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+
+  ATL::CAccessToken access_token;
+  access_token.Attach(token_handle);
+
+  // Change the primary group.
+  access_token.SetPrimaryGroup(ATL::Sids::World());
+
+  // Create the token using the current token.
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
+
+  // Get the handle to the restricted token.
+
+  HANDLE restricted_token_handle = NULL;
+  ASSERT_EQ(ERROR_SUCCESS,
+      token.GetRestrictedTokenHandle(&restricted_token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(restricted_token_handle);
+
+  ATL::CSid sid_restricted;
+  ATL::CSid sid_default;
+  ASSERT_TRUE(restricted_token.GetPrimaryGroup(&sid_restricted));
+  ASSERT_TRUE(access_token.GetPrimaryGroup(&sid_default));
+
+  // Check if both token have the same owner.
+  ASSERT_EQ(sid_restricted, sid_default);
+}
+
+// Verifies that the token created by the object are valid.
+TEST(RestrictedTokenTest, ResultToken) {
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+
+  HANDLE restricted_token;
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&restricted_token));
+
+  ASSERT_TRUE(::IsTokenRestricted(restricted_token));
+
+  DWORD length = 0;
+  TOKEN_TYPE type;
+  ASSERT_TRUE(::GetTokenInformation(restricted_token,
+                                    ::TokenType,
+                                    &type,
+                                    sizeof(type),
+                                    &length));
+
+  ASSERT_EQ(type, TokenPrimary);
+
+  HANDLE impersonation_token;
+  ASSERT_EQ(ERROR_SUCCESS,
+      token.GetRestrictedTokenHandleForImpersonation(&impersonation_token));
+
+  ASSERT_TRUE(::IsTokenRestricted(impersonation_token));
+
+  ASSERT_TRUE(::GetTokenInformation(impersonation_token,
+                                    ::TokenType,
+                                    &type,
+                                    sizeof(type),
+                                    &length));
+
+  ASSERT_EQ(type, TokenImpersonation);
+
+  ::CloseHandle(impersonation_token);
+  ::CloseHandle(restricted_token);
+}
+
+// Verifies that the token created has "Restricted" in its default dacl.
+TEST(RestrictedTokenTest, DefaultDacl) {
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+
+  HANDLE handle;
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(handle);
+
+  ATL::CDacl dacl;
+  ASSERT_TRUE(restricted_token.GetDefaultDacl(&dacl));
+
+  bool restricted_found = false;
+
+  unsigned int ace_count = dacl.GetAceCount();
+  for (unsigned int i = 0; i < ace_count ; ++i) {
+    ATL::CSid sid;
+    ACCESS_MASK mask = 0;
+    dacl.GetAclEntry(i, &sid, &mask);
+    if (sid == ATL::Sids::RestrictedCode() && mask == GENERIC_ALL) {
+      restricted_found = true;
+      break;
+    }
+  }
+
+  ASSERT_TRUE(restricted_found);
+}
+
+// Tests the method "AddSidForDenyOnly".
+TEST(RestrictedTokenTest, DenySid) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddSidForDenyOnly(Sid(WinWorldSid)));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenGroups groups;
+  ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  groups.GetSidsAndAttributes(&sids, &attributes);
+
+  for (unsigned int i = 0; i < sids.GetCount(); i++) {
+    if (ATL::Sids::World() == sids[i]) {
+      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+                attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+    }
+  }
+}
+
+// Tests the method "AddAllSidsForDenyOnly".
+TEST(RestrictedTokenTest, DenySids) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddAllSidsForDenyOnly(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenGroups groups;
+  ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  groups.GetSidsAndAttributes(&sids, &attributes);
+
+  // Verify that all sids are really gone.
+  for (unsigned int i = 0; i < sids.GetCount(); i++) {
+    if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
+        (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
+      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+                attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+    }
+  }
+}
+
+// Tests the method "AddAllSidsForDenyOnly" using an exception list.
+TEST(RestrictedTokenTest, DenySidsException) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  std::vector<Sid> sids_exception;
+  sids_exception.push_back(Sid(WinWorldSid));
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddAllSidsForDenyOnly(&sids_exception));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenGroups groups;
+  ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  groups.GetSidsAndAttributes(&sids, &attributes);
+
+  // Verify that all sids are really gone.
+  for (unsigned int i = 0; i < sids.GetCount(); i++) {
+    if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
+        (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
+      if (ATL::Sids::World() == sids[i]) {
+        ASSERT_EQ(NULL, attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+      } else {
+        ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+                  attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+      }
+    }
+  }
+}
+
+// Tests test method AddOwnerSidForDenyOnly.
+TEST(RestrictedTokenTest, DenyOwnerSid) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddUserSidForDenyOnly());
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenGroups groups;
+  ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  groups.GetSidsAndAttributes(&sids, &attributes);
+
+  ATL::CSid user_sid;
+  ASSERT_TRUE(restricted_token.GetUser(&user_sid));
+
+  for (unsigned int i = 0; i < sids.GetCount(); ++i) {
+    if (user_sid == sids[i]) {
+      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+                attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+    }
+  }
+}
+
+// Tests test method AddOwnerSidForDenyOnly with a custom effective token.
+TEST(RestrictedTokenTest, DenyOwnerSidCustom) {
+  // Get the current process token.
+  HANDLE token_handle = INVALID_HANDLE_VALUE;
+  ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+                                 &token_handle));
+
+  ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+
+  ATL::CAccessToken access_token;
+  access_token.Attach(token_handle);
+
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddUserSidForDenyOnly());
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenGroups groups;
+  ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  groups.GetSidsAndAttributes(&sids, &attributes);
+
+  ATL::CSid user_sid;
+  ASSERT_TRUE(restricted_token.GetUser(&user_sid));
+
+  for (unsigned int i = 0; i < sids.GetCount(); ++i) {
+    if (user_sid == sids[i]) {
+      ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY,
+                attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+    }
+  }
+}
+
+// Tests the method DeleteAllPrivileges.
+TEST(RestrictedTokenTest, DeleteAllPrivileges) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.DeleteAllPrivileges(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenPrivileges privileges;
+  ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
+
+  ASSERT_EQ(0, privileges.GetCount());
+}
+
+// Tests the method DeleteAllPrivileges with an exception list.
+TEST(RestrictedTokenTest, DeleteAllPrivilegesException) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  std::vector<base::string16> exceptions;
+  exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.DeleteAllPrivileges(&exceptions));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenPrivileges privileges;
+  ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
+
+  ATL::CTokenPrivileges::CNames privilege_names;
+  ATL::CTokenPrivileges::CAttributes privilege_name_attributes;
+  privileges.GetNamesAndAttributes(&privilege_names,
+                                   &privilege_name_attributes);
+
+  ASSERT_EQ(1, privileges.GetCount());
+
+  for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
+    ASSERT_EQ(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
+  }
+}
+
+// Tests the method DeletePrivilege.
+TEST(RestrictedTokenTest, DeletePrivilege) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.DeletePrivilege(SE_CHANGE_NOTIFY_NAME));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenPrivileges privileges;
+  ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
+
+  ATL::CTokenPrivileges::CNames privilege_names;
+  ATL::CTokenPrivileges::CAttributes privilege_name_attributes;
+  privileges.GetNamesAndAttributes(&privilege_names,
+                                   &privilege_name_attributes);
+
+  for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
+    ASSERT_NE(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
+  }
+}
+
+// Checks if a sid is in the restricting list of the restricted token.
+// Asserts if it's not the case. If count is a positive number, the number of
+// elements in the restricting sids list has to be equal.
+void CheckRestrictingSid(const ATL::CAccessToken &restricted_token,
+                         ATL::CSid sid, int count) {
+  DWORD length = 8192;
+  BYTE *memory = new BYTE[length];
+  TOKEN_GROUPS *groups = reinterpret_cast<TOKEN_GROUPS*>(memory);
+  ASSERT_TRUE(::GetTokenInformation(restricted_token.GetHandle(),
+                                    TokenRestrictedSids,
+                                    groups,
+                                    length,
+                                    &length));
+
+  ATL::CTokenGroups atl_groups(*groups);
+  delete[] memory;
+
+  if (count >= 0)
+    ASSERT_EQ(count, atl_groups.GetCount());
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  atl_groups.GetSidsAndAttributes(&sids, &attributes);
+
+  bool present = false;
+  for (unsigned int i = 0; i < sids.GetCount(); ++i) {
+    if (sids[i] == sid) {
+      present = true;
+      break;
+    }
+  }
+
+  ASSERT_TRUE(present);
+}
+
+// Tests the method AddRestrictingSid.
+TEST(RestrictedTokenTest, AddRestrictingSid) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS,
+            token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  CheckRestrictingSid(restricted_token, ATL::Sids::World(), 1);
+}
+
+// Tests the method AddRestrictingSidCurrentUser.
+TEST(RestrictedTokenTest, AddRestrictingSidCurrentUser) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+  ATL::CSid user;
+  restricted_token.GetUser(&user);
+
+  CheckRestrictingSid(restricted_token, user, 1);
+}
+
+// Tests the method AddRestrictingSidCurrentUser with a custom effective token.
+TEST(RestrictedTokenTest, AddRestrictingSidCurrentUserCustom) {
+  // Get the current process token.
+  HANDLE token_handle = INVALID_HANDLE_VALUE;
+  ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+                                 &token_handle));
+
+  ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+
+  ATL::CAccessToken access_token;
+  access_token.Attach(token_handle);
+
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(access_token.GetHandle()));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+  ATL::CSid user;
+  restricted_token.GetUser(&user);
+
+  CheckRestrictingSid(restricted_token, user, 1);
+}
+
+// Tests the method AddRestrictingSidLogonSession.
+TEST(RestrictedTokenTest, AddRestrictingSidLogonSession) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidLogonSession());
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+  ATL::CSid session;
+  restricted_token.GetLogonSid(&session);
+
+  CheckRestrictingSid(restricted_token, session, 1);
+}
+
+// Tests adding a lot of restricting sids.
+TEST(RestrictedTokenTest, AddMultipleRestrictingSids) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidCurrentUser());
+  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidLogonSession());
+  ASSERT_EQ(ERROR_SUCCESS,
+            token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+  ATL::CSid session;
+  restricted_token.GetLogonSid(&session);
+
+  DWORD length = 8192;
+  BYTE *memory = new BYTE[length];
+  TOKEN_GROUPS *groups = reinterpret_cast<TOKEN_GROUPS*>(memory);
+  ASSERT_TRUE(::GetTokenInformation(restricted_token.GetHandle(),
+                                    TokenRestrictedSids,
+                                    groups,
+                                    length,
+                                    &length));
+
+  ATL::CTokenGroups atl_groups(*groups);
+  delete[] memory;
+
+  ASSERT_EQ(3, atl_groups.GetCount());
+}
+
+// Tests the method "AddRestrictingSidAllSids".
+TEST(RestrictedTokenTest, AddAllSidToRestrictingSids) {
+  RestrictedToken token;
+  HANDLE token_handle = NULL;
+
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+  ASSERT_EQ(ERROR_SUCCESS, token.AddRestrictingSidAllSids());
+  ASSERT_EQ(ERROR_SUCCESS, token.GetRestrictedTokenHandle(&token_handle));
+
+  ATL::CAccessToken restricted_token;
+  restricted_token.Attach(token_handle);
+
+  ATL::CTokenGroups groups;
+  ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+  ATL::CSid::CSidArray sids;
+  ATL::CAtlArray<DWORD> attributes;
+  groups.GetSidsAndAttributes(&sids, &attributes);
+
+  // Verify that all group sids are in the restricting sid list.
+  for (unsigned int i = 0; i < sids.GetCount(); i++) {
+    if ((attributes[i] & SE_GROUP_INTEGRITY) == 0) {
+      CheckRestrictingSid(restricted_token, sids[i], -1);
+    }
+  }
+
+  // Verify that the user is in the restricting sid list.
+  ATL::CSid user;
+  restricted_token.GetUser(&user);
+  CheckRestrictingSid(restricted_token, user, -1);
+}
+
+// Checks the error code when the object is initialized twice.
+TEST(RestrictedTokenTest, DoubleInit) {
+  RestrictedToken token;
+  ASSERT_EQ(ERROR_SUCCESS, token.Init(NULL));
+
+  ASSERT_EQ(ERROR_ALREADY_INITIALIZED, token.Init(NULL));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/restricted_token_utils.cc b/sandbox/win/src/restricted_token_utils.cc
new file mode 100644
index 0000000..5e06daa
--- /dev/null
+++ b/sandbox/win/src/restricted_token_utils.cc
@@ -0,0 +1,408 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <aclapi.h>
+#include <sddl.h>
+#include <vector>
+
+#include "sandbox/win/src/restricted_token_utils.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+DWORD CreateRestrictedToken(HANDLE *token_handle,
+                            TokenLevel security_level,
+                            IntegrityLevel integrity_level,
+                            TokenType token_type) {
+  if (!token_handle)
+    return ERROR_BAD_ARGUMENTS;
+
+  RestrictedToken restricted_token;
+  restricted_token.Init(NULL);  // Initialized with the current process token
+
+  std::vector<base::string16> privilege_exceptions;
+  std::vector<Sid> sid_exceptions;
+
+  bool deny_sids = true;
+  bool remove_privileges = true;
+
+  switch (security_level) {
+    case USER_UNPROTECTED: {
+      deny_sids = false;
+      remove_privileges = false;
+      break;
+    }
+    case USER_RESTRICTED_SAME_ACCESS: {
+      deny_sids = false;
+      remove_privileges = false;
+
+      unsigned err_code = restricted_token.AddRestrictingSidAllSids();
+      if (ERROR_SUCCESS != err_code)
+        return err_code;
+
+      break;
+    }
+    case USER_NON_ADMIN: {
+      sid_exceptions.push_back(WinBuiltinUsersSid);
+      sid_exceptions.push_back(WinWorldSid);
+      sid_exceptions.push_back(WinInteractiveSid);
+      sid_exceptions.push_back(WinAuthenticatedUserSid);
+      privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+      break;
+    }
+    case USER_INTERACTIVE: {
+      sid_exceptions.push_back(WinBuiltinUsersSid);
+      sid_exceptions.push_back(WinWorldSid);
+      sid_exceptions.push_back(WinInteractiveSid);
+      sid_exceptions.push_back(WinAuthenticatedUserSid);
+      privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+      restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+      restricted_token.AddRestrictingSid(WinWorldSid);
+      restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+      restricted_token.AddRestrictingSidCurrentUser();
+      restricted_token.AddRestrictingSidLogonSession();
+      break;
+    }
+    case USER_LIMITED: {
+      sid_exceptions.push_back(WinBuiltinUsersSid);
+      sid_exceptions.push_back(WinWorldSid);
+      sid_exceptions.push_back(WinInteractiveSid);
+      privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+      restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+      restricted_token.AddRestrictingSid(WinWorldSid);
+      restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+
+      // This token has to be able to create objects in BNO.
+      // Unfortunately, on vista, it needs the current logon sid
+      // in the token to achieve this. You should also set the process to be
+      // low integrity level so it can't access object created by other
+      // processes.
+      if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+        restricted_token.AddRestrictingSidLogonSession();
+      break;
+    }
+    case USER_RESTRICTED: {
+      privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+      restricted_token.AddUserSidForDenyOnly();
+      restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+      break;
+    }
+    case USER_LOCKDOWN: {
+      restricted_token.AddUserSidForDenyOnly();
+      restricted_token.AddRestrictingSid(WinNullSid);
+      break;
+    }
+    default: {
+      return ERROR_BAD_ARGUMENTS;
+    }
+  }
+
+  DWORD err_code = ERROR_SUCCESS;
+  if (deny_sids) {
+    err_code = restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
+    if (ERROR_SUCCESS != err_code)
+      return err_code;
+  }
+
+  if (remove_privileges) {
+    err_code = restricted_token.DeleteAllPrivileges(&privilege_exceptions);
+    if (ERROR_SUCCESS != err_code)
+      return err_code;
+  }
+
+  restricted_token.SetIntegrityLevel(integrity_level);
+
+  switch (token_type) {
+    case PRIMARY: {
+      err_code = restricted_token.GetRestrictedTokenHandle(token_handle);
+      break;
+    }
+    case IMPERSONATION: {
+      err_code = restricted_token.GetRestrictedTokenHandleForImpersonation(
+          token_handle);
+      break;
+    }
+    default: {
+      err_code = ERROR_BAD_ARGUMENTS;
+      break;
+    }
+  }
+
+  return err_code;
+}
+
+DWORD StartRestrictedProcessInJob(wchar_t *command_line,
+                                  TokenLevel primary_level,
+                                  TokenLevel impersonation_level,
+                                  JobLevel job_level,
+                                  HANDLE *const job_handle_ret) {
+  Job job;
+  DWORD err_code = job.Init(job_level, NULL, 0, 0);
+  if (ERROR_SUCCESS != err_code)
+    return err_code;
+
+  if (JOB_UNPROTECTED != job_level) {
+    // Share the Desktop handle to be able to use MessageBox() in the sandboxed
+    // application.
+    err_code = job.UserHandleGrantAccess(GetDesktopWindow());
+    if (ERROR_SUCCESS != err_code)
+      return err_code;
+  }
+
+  // Create the primary (restricted) token for the process
+  HANDLE primary_token_handle = NULL;
+  err_code = CreateRestrictedToken(&primary_token_handle,
+                                   primary_level,
+                                   INTEGRITY_LEVEL_LAST,
+                                   PRIMARY);
+  if (ERROR_SUCCESS != err_code) {
+    return err_code;
+  }
+  base::win::ScopedHandle primary_token(primary_token_handle);
+
+  // Create the impersonation token (restricted) to be able to start the
+  // process.
+  HANDLE impersonation_token_handle;
+  err_code = CreateRestrictedToken(&impersonation_token_handle,
+                                   impersonation_level,
+                                   INTEGRITY_LEVEL_LAST,
+                                   IMPERSONATION);
+  if (ERROR_SUCCESS != err_code) {
+    return err_code;
+  }
+  base::win::ScopedHandle impersonation_token(impersonation_token_handle);
+
+  // Start the process
+  STARTUPINFO startup_info = {0};
+  PROCESS_INFORMATION temp_process_info = {};
+  DWORD flags = CREATE_SUSPENDED;
+
+  if (base::win::GetVersion() < base::win::VERSION_WIN8) {
+    // Windows 8 implements nested jobs, but for older systems we need to
+    // break out of any job we're in to enforce our restrictions.
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+  }
+
+  if (!::CreateProcessAsUser(primary_token.Get(),
+                             NULL,   // No application name.
+                             command_line,
+                             NULL,   // No security attribute.
+                             NULL,   // No thread attribute.
+                             FALSE,  // Do not inherit handles.
+                             flags,
+                             NULL,   // Use the environment of the caller.
+                             NULL,   // Use current directory of the caller.
+                             &startup_info,
+                             &temp_process_info)) {
+    return ::GetLastError();
+  }
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  // Change the token of the main thread of the new process for the
+  // impersonation token with more rights.
+  {
+    HANDLE temp_thread = process_info.thread_handle();
+    if (!::SetThreadToken(&temp_thread, impersonation_token.Get())) {
+      ::TerminateProcess(process_info.process_handle(),
+                         0);  // exit code
+      return ::GetLastError();
+    }
+  }
+
+  err_code = job.AssignProcessToJob(process_info.process_handle());
+  if (ERROR_SUCCESS != err_code) {
+    ::TerminateProcess(process_info.process_handle(),
+                       0);  // exit code
+    return ::GetLastError();
+  }
+
+  // Start the application
+  ::ResumeThread(process_info.thread_handle());
+
+  (*job_handle_ret) = job.Detach();
+
+  return ERROR_SUCCESS;
+}
+
+DWORD SetObjectIntegrityLabel(HANDLE handle, SE_OBJECT_TYPE type,
+                              const wchar_t* ace_access,
+                              const wchar_t* integrity_level_sid) {
+  // Build the SDDL string for the label.
+  base::string16 sddl = L"S:(";   // SDDL for a SACL.
+  sddl += SDDL_MANDATORY_LABEL;   // Ace Type is "Mandatory Label".
+  sddl += L";;";                  // No Ace Flags.
+  sddl += ace_access;             // Add the ACE access.
+  sddl += L";;;";                 // No ObjectType and Inherited Object Type.
+  sddl += integrity_level_sid;    // Trustee Sid.
+  sddl += L")";
+
+  DWORD error = ERROR_SUCCESS;
+  PSECURITY_DESCRIPTOR sec_desc = NULL;
+
+  PACL sacl = NULL;
+  BOOL sacl_present = FALSE;
+  BOOL sacl_defaulted = FALSE;
+
+  if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl.c_str(),
+                                                             SDDL_REVISION,
+                                                             &sec_desc, NULL)) {
+    if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl,
+                                    &sacl_defaulted)) {
+      error = ::SetSecurityInfo(handle, type,
+                                LABEL_SECURITY_INFORMATION, NULL, NULL, NULL,
+                                sacl);
+    } else {
+      error = ::GetLastError();
+    }
+
+    ::LocalFree(sec_desc);
+  } else {
+    return::GetLastError();
+  }
+
+  return error;
+}
+
+const wchar_t* GetIntegrityLevelString(IntegrityLevel integrity_level) {
+  switch (integrity_level) {
+    case INTEGRITY_LEVEL_SYSTEM:
+      return L"S-1-16-16384";
+    case INTEGRITY_LEVEL_HIGH:
+      return L"S-1-16-12288";
+    case INTEGRITY_LEVEL_MEDIUM:
+      return L"S-1-16-8192";
+    case INTEGRITY_LEVEL_MEDIUM_LOW:
+      return L"S-1-16-6144";
+    case INTEGRITY_LEVEL_LOW:
+      return L"S-1-16-4096";
+    case INTEGRITY_LEVEL_BELOW_LOW:
+      return L"S-1-16-2048";
+    case INTEGRITY_LEVEL_UNTRUSTED:
+      return L"S-1-16-0";
+    case INTEGRITY_LEVEL_LAST:
+      return NULL;
+  }
+
+  NOTREACHED();
+  return NULL;
+}
+DWORD SetTokenIntegrityLevel(HANDLE token, IntegrityLevel integrity_level) {
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return ERROR_SUCCESS;
+
+  const wchar_t* integrity_level_str = GetIntegrityLevelString(integrity_level);
+  if (!integrity_level_str) {
+    // No mandatory level specified, we don't change it.
+    return ERROR_SUCCESS;
+  }
+
+  PSID integrity_sid = NULL;
+  if (!::ConvertStringSidToSid(integrity_level_str, &integrity_sid))
+    return ::GetLastError();
+
+  TOKEN_MANDATORY_LABEL label = {0};
+  label.Label.Attributes = SE_GROUP_INTEGRITY;
+  label.Label.Sid = integrity_sid;
+
+  DWORD size = sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(integrity_sid);
+  BOOL result = ::SetTokenInformation(token, TokenIntegrityLevel, &label,
+                                      size);
+  ::LocalFree(integrity_sid);
+
+  return result ? ERROR_SUCCESS : ::GetLastError();
+}
+
+DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level) {
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return ERROR_SUCCESS;
+
+  // We don't check for an invalid level here because we'll just let it
+  // fail on the SetTokenIntegrityLevel call later on.
+  if (integrity_level == INTEGRITY_LEVEL_LAST) {
+    // No mandatory level specified, we don't change it.
+    return ERROR_SUCCESS;
+  }
+
+  HANDLE token_handle;
+  if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT,
+                          &token_handle))
+    return ::GetLastError();
+
+  base::win::ScopedHandle token(token_handle);
+
+  return SetTokenIntegrityLevel(token.Get(), integrity_level);
+}
+
+DWORD HardenTokenIntegrityLevelPolicy(HANDLE token) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN7)
+    return ERROR_SUCCESS;
+
+  DWORD last_error = 0;
+  DWORD length_needed = 0;
+
+  ::GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION,
+                            NULL, 0, &length_needed);
+
+  last_error = ::GetLastError();
+  if (last_error != ERROR_INSUFFICIENT_BUFFER)
+    return last_error;
+
+  std::vector<char> security_desc_buffer(length_needed);
+  PSECURITY_DESCRIPTOR security_desc =
+      reinterpret_cast<PSECURITY_DESCRIPTOR>(&security_desc_buffer[0]);
+
+  if (!::GetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION,
+                                 security_desc, length_needed,
+                                 &length_needed))
+    return ::GetLastError();
+
+  PACL sacl = NULL;
+  BOOL sacl_present = FALSE;
+  BOOL sacl_defaulted = FALSE;
+
+  if (!::GetSecurityDescriptorSacl(security_desc, &sacl_present,
+                                   &sacl, &sacl_defaulted))
+    return ::GetLastError();
+
+  for (DWORD ace_index = 0; ace_index < sacl->AceCount; ++ace_index) {
+    PSYSTEM_MANDATORY_LABEL_ACE ace;
+
+    if (::GetAce(sacl, ace_index, reinterpret_cast<LPVOID*>(&ace))
+        && ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) {
+      ace->Mask |= SYSTEM_MANDATORY_LABEL_NO_READ_UP
+                |  SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP;
+      break;
+    }
+  }
+
+  if (!::SetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION,
+                                 security_desc))
+    return ::GetLastError();
+
+  return ERROR_SUCCESS;
+}
+
+DWORD HardenProcessIntegrityLevelPolicy() {
+  if (base::win::GetVersion() < base::win::VERSION_WIN7)
+    return ERROR_SUCCESS;
+
+  HANDLE token_handle;
+  if (!::OpenProcessToken(GetCurrentProcess(), READ_CONTROL | WRITE_OWNER,
+                          &token_handle))
+    return ::GetLastError();
+
+  base::win::ScopedHandle token(token_handle);
+
+  return HardenTokenIntegrityLevelPolicy(token.Get());
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/restricted_token_utils.h b/sandbox/win/src/restricted_token_utils.h
new file mode 100644
index 0000000..509feaf
--- /dev/null
+++ b/sandbox/win/src/restricted_token_utils.h
@@ -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.
+
+#ifndef SANDBOX_SRC_RESTRICTED_TOKEN_UTILS_H__
+#define SANDBOX_SRC_RESTRICTED_TOKEN_UTILS_H__
+
+#include <accctrl.h>
+#include <windows.h>
+
+#include "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/security_level.h"
+
+// Contains the utility functions to be able to create restricted tokens based
+// on a security profiles.
+
+namespace sandbox {
+
+// The type of the token returned by the CreateNakedToken.
+enum TokenType {
+  IMPERSONATION = 0,
+  PRIMARY
+};
+
+// Creates a restricted token based on the effective token of the current
+// process. The parameter security_level determines how much the token is
+// restricted. The token_type determines if the token will be used as a primary
+// token or impersonation token. The integrity level of the token is set to
+// |integrity level| on Vista only.
+// token_handle is the output value containing the handle of the
+// newly created restricted token.
+// If the function succeeds, the return value is ERROR_SUCCESS. If the
+// function fails, the return value is the win32 error code corresponding to
+// the error.
+DWORD CreateRestrictedToken(HANDLE *token_handle,
+                            TokenLevel security_level,
+                            IntegrityLevel integrity_level,
+                            TokenType token_type);
+
+// Starts the process described by the input parameter command_line in a job
+// with a restricted token. Also set the main thread of this newly created
+// process to impersonate a user with more rights so it can initialize
+// correctly.
+//
+// Parameters: primary_level is the security level of the primary token.
+// impersonation_level is the security level of the impersonation token used
+// to initialize the process. job_level is the security level of the job
+// object used to encapsulate the process.
+//
+// The output parameter job_handle is the handle to the job object. It has
+// to be closed with CloseHandle() when not needed. Closing this handle will
+// kill the process started.
+//
+// Note: The process started with this function has to call RevertToSelf() as
+// soon as possible to stop using the impersonation token and start being
+// secure.
+//
+// Note: The Unicode version of this function will fail if the command_line
+// parameter is a const string.
+DWORD StartRestrictedProcessInJob(wchar_t *command_line,
+                                  TokenLevel primary_level,
+                                  TokenLevel impersonation_level,
+                                  JobLevel job_level,
+                                  HANDLE *job_handle);
+
+// Sets the integrity label on a object handle.
+DWORD SetObjectIntegrityLabel(HANDLE handle, SE_OBJECT_TYPE type,
+                              const wchar_t* ace_access,
+                              const wchar_t* integrity_level_sid);
+
+// Sets the integrity level on a token. This is only valid on Vista. It returns
+// without failing on XP. If the integrity level that you specify is greater
+// than the current integrity level, the function will fail.
+DWORD SetTokenIntegrityLevel(HANDLE token, IntegrityLevel integrity_level);
+
+// Returns the integrity level SDDL string associated with a given
+// IntegrityLevel value.
+const wchar_t* GetIntegrityLevelString(IntegrityLevel integrity_level);
+
+// Sets the integrity level on the current process on Vista. It returns without
+// failing on XP. If the integrity level that you specify is greater than the
+// current integrity level, the function will fail.
+DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level);
+
+// Hardens the integrity level policy on a token. This is only valid on Win 7
+// and above. Specifically it sets the policy to block read and execute so
+// that a lower privileged process cannot open the token for impersonate or
+// duplicate permissions. This should limit potential security holes.
+DWORD HardenTokenIntegrityLevelPolicy(HANDLE token);
+
+// Hardens the integrity level policy on the current process. This is only
+// valid on Win 7 and above. Specifically it sets the policy to block read
+// and execute so that a lower privileged process cannot open the token for
+// impersonate or duplicate permissions. This should limit potential security
+// holes.
+DWORD HardenProcessIntegrityLevelPolicy();
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_RESTRICTED_TOKEN_UTILS_H__
diff --git a/sandbox/win/src/sandbox.cc b/sandbox/win/src/sandbox.cc
new file mode 100644
index 0000000..984dfec
--- /dev/null
+++ b/sandbox/win/src/sandbox.cc
@@ -0,0 +1,48 @@
+// 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 <stdio.h>
+#include <windows.h>
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/broker_services.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+// The section for IPC and policy.
+SANDBOX_INTERCEPT HANDLE  g_shared_section;
+static bool               s_is_broker = false;
+
+// GetBrokerServices: the current implementation relies on a shared section
+// that is created by the broker and opened by the target.
+BrokerServices* SandboxFactory::GetBrokerServices() {
+  // Can't be the broker if the shared section is open.
+  if (NULL != g_shared_section) {
+    return NULL;
+  }
+  // If the shared section does not exist we are the broker, then create
+  // the broker object.
+  s_is_broker = true;
+  return BrokerServicesBase::GetInstance();
+}
+
+// GetTargetServices implementation must follow the same technique as the
+// GetBrokerServices, but in this case the logic is the opposite.
+TargetServices* SandboxFactory::GetTargetServices() {
+  // Can't be the target if the section handle is not valid.
+  if (NULL == g_shared_section) {
+    return NULL;
+  }
+  // We are the target
+  s_is_broker = false;
+  // Creates and returns the target services implementation.
+  return TargetServicesBase::GetInstance();
+}
+
+}  // namespace sandbox
+
+// Allows querying for whether the current process has been sandboxed.
+extern "C" bool __declspec(dllexport) IsSandboxedProcess() {
+  return sandbox::g_shared_section != NULL;
+}
diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h
new file mode 100644
index 0000000..e326194
--- /dev/null
+++ b/sandbox/win/src/sandbox.h
@@ -0,0 +1,165 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Sandbox is a sandbox library for windows processes. Use when you want a
+// 'privileged' process and a 'locked down process' to interact with.
+// The privileged process is called the broker and it is started by external
+// means (such as the user starting it). The 'sandboxed' process is called the
+// target and it is started by the broker. There can be many target processes
+// started by a single broker process. This library provides facilities
+// for both the broker and the target.
+//
+// The design rationale and relevant documents can be found at http://go/sbox.
+//
+// Note: this header does not include the SandboxFactory definitions because
+// there are cases where the Sandbox library is linked against the main .exe
+// while its API needs to be used in a DLL.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_H_
+#define SANDBOX_WIN_SRC_SANDBOX_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+// sandbox: Google User-Land Application Sandbox
+namespace sandbox {
+
+class BrokerServices;
+class ProcessState;
+class TargetPolicy;
+class TargetServices;
+
+// BrokerServices exposes all the broker API.
+// The basic use is to start the target(s) and wait for them to end.
+//
+// This API is intended to be called in the following order
+// (error checking omitted):
+//  BrokerServices* broker = SandboxFactory::GetBrokerServices();
+//  broker->Init();
+//  PROCESS_INFORMATION target;
+//  broker->SpawnTarget(target_exe_path, target_args, &target);
+//  ::ResumeThread(target->hThread);
+//  // -- later you can call:
+//  broker->WaitForAllTargets(option);
+//
+class BrokerServices {
+ public:
+  // Initializes the broker. Must be called before any other on this class.
+  // returns ALL_OK if successful. All other return values imply failure.
+  // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+  // more information.
+  virtual ResultCode Init() = 0;
+
+  // Returns the interface pointer to a new, empty policy object. Use this
+  // interface to specify the sandbox policy for new processes created by
+  // SpawnTarget()
+  virtual TargetPolicy* CreatePolicy() = 0;
+
+  // Creates a new target (child process) in a suspended state.
+  // Parameters:
+  //   exe_path: This is the full path to the target binary. This parameter
+  //   can be null and in this case the exe path must be the first argument
+  //   of the command_line.
+  //   command_line: The arguments to be passed as command line to the new
+  //   process. This can be null if the exe_path parameter is not null.
+  //   policy: This is the pointer to the policy object for the sandbox to
+  //   be created.
+  //   target: returns the resulting target process information such as process
+  //   handle and PID just as if CreateProcess() had been called. The caller is
+  //   responsible for closing the handles returned in this structure.
+  // Returns:
+  //   ALL_OK if successful. All other return values imply failure.
+  virtual ResultCode SpawnTarget(const wchar_t* exe_path,
+                                 const wchar_t* command_line,
+                                 TargetPolicy* policy,
+                                 PROCESS_INFORMATION* target) = 0;
+
+  // This call blocks (waits) for all the targets to terminate.
+  // Returns:
+  //   ALL_OK if successful. All other return values imply failure.
+  //   If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+  //   more information.
+  virtual ResultCode WaitForAllTargets() = 0;
+
+  // Adds an unsandboxed process as a peer for policy decisions (e.g.
+  // HANDLES_DUP_ANY policy).
+  // Returns:
+  //   ALL_OK if successful. All other return values imply failure.
+  //   If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+  //   more information.
+  virtual ResultCode AddTargetPeer(HANDLE peer_process) = 0;
+
+  // Install the AppContainer with the specified sid an name. Returns ALL_OK if
+  // successful or an error code if the AppContainer cannot be installed.
+  virtual ResultCode InstallAppContainer(const wchar_t* sid,
+                                         const wchar_t* name) = 0;
+
+  // Removes from the system the AppContainer with the specified sid.
+  // Returns ALL_OK if successful or an error code otherwise.
+  virtual ResultCode UninstallAppContainer(const wchar_t* sid) = 0;
+};
+
+// TargetServices models the current process from the perspective
+// of a target process. To obtain a pointer to it use
+// Sandbox::GetTargetServices(). Note that this call returns a non-null
+// pointer only if this process is in fact a target. A process is a target
+// only if the process was spawned by a call to BrokerServices::SpawnTarget().
+//
+// This API allows the target to gain access to resources with a high
+// privilege token and then when it is ready to perform dangerous activities
+// (such as download content from the web) it can lower its token and
+// enter into locked-down (sandbox) mode.
+// The typical usage is as follows:
+//
+//   TargetServices* target_services = Sandbox::GetTargetServices();
+//   if (NULL != target_services) {
+//     // We are the target.
+//     target_services->Init();
+//     // Do work that requires high privileges here.
+//     // ....
+//     // When ready to enter lock-down mode call LowerToken:
+//     target_services->LowerToken();
+//   }
+//
+// For more information see the BrokerServices API documentation.
+class TargetServices {
+ public:
+  // Initializes the target. Must call this function before any other.
+  // returns ALL_OK if successful. All other return values imply failure.
+  // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+  // more information.
+  virtual ResultCode Init() = 0;
+
+  // Discards the impersonation token and uses the lower token, call before
+  // processing any untrusted data or running third-party code. If this call
+  // fails the current process could be terminated immediately.
+  virtual void LowerToken() = 0;
+
+  // Returns the ProcessState object. Through that object it's possible to have
+  // information about the current state of the process, such as whether
+  // LowerToken has been called or not.
+  virtual ProcessState* GetState() = 0;
+
+  // Requests the broker to duplicate the supplied handle into the target
+  // process. The target process must be an active sandbox child process
+  // and the source process must have a corresponding policy allowing
+  // handle duplication for this object type.
+  // Returns:
+  //   ALL_OK if successful. All other return values imply failure.
+  //   If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+  //   more information.
+  virtual ResultCode DuplicateHandle(HANDLE source_handle,
+                                     DWORD target_process_id,
+                                     HANDLE* target_handle,
+                                     DWORD desired_access,
+                                     DWORD options) = 0;
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_H_
diff --git a/sandbox/win/src/sandbox.vcproj b/sandbox/win/src/sandbox.vcproj
new file mode 100644
index 0000000..f206e01
--- /dev/null
+++ b/sandbox/win/src/sandbox.vcproj
@@ -0,0 +1,658 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sandbox"
+	ProjectGUID="{881F6A97-D539-4C48-B401-DF04385B2343}"
+	RootNamespace="sandbox"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Copy wow_helper to output directory"
+				CommandLine="copy $(ProjectDir)\..\wow_helper\wow_helper.exe $(OutDir) &amp;&amp; copy $(ProjectDir)\..\wow_helper\wow_helper.pdb $(OutDir)"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Copy wow_helper to output directory"
+				CommandLine="copy $(ProjectDir)\..\wow_helper\wow_helper.exe $(OutDir) &amp;&amp; copy $(ProjectDir)\..\wow_helper\wow_helper.pdb $(OutDir)"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="security"
+			>
+			<File
+				RelativePath=".\acl.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\acl.h"
+				>
+			</File>
+			<File
+				RelativePath=".\dep.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\dep.h"
+				>
+			</File>
+			<File
+				RelativePath=".\job.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\job.h"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token.h"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token_utils.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token_utils.h"
+				>
+			</File>
+			<File
+				RelativePath=".\security_level.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sid.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sid.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Interception"
+			>
+			<File
+				RelativePath=".\eat_resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\eat_resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\interception_agent.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\interception_agent.h"
+				>
+			</File>
+			<File
+				RelativePath=".\interception_internal.h"
+				>
+			</File>
+			<File
+				RelativePath=".\pe_image.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\pe_image.h"
+				>
+			</File>
+			<File
+				RelativePath=".\resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\service_resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\service_resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sidestep_resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sidestep_resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\target_interceptions.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\target_interceptions.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Wow64.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\Wow64.h"
+				>
+			</File>
+			<Filter
+				Name="sidestep"
+				>
+				<File
+					RelativePath=".\sidestep\ia32_modrm_map.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\ia32_opcode_map.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\mini_disassembler.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\mini_disassembler.h"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\mini_disassembler_types.h"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\preamble_patcher.h"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\preamble_patcher_with_stub.cpp"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="nt_level"
+			>
+			<File
+				RelativePath=".\nt_internals.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_target.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_target.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_nt_types.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_nt_util.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_nt_util.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Policy_handlers"
+			>
+			<File
+				RelativePath=".\filesystem_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_params.h"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_policy.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="IPC"
+			>
+			<File
+				RelativePath=".\crosscall_client.h"
+				>
+			</File>
+			<File
+				RelativePath=".\crosscall_params.h"
+				>
+			</File>
+			<File
+				RelativePath=".\crosscall_server.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\crosscall_server.h"
+				>
+			</File>
+			<File
+				RelativePath=".\ipc_tags.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_client.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_client.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_server.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_server.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Policy_base"
+			>
+			<File
+				RelativePath=".\policy_engine_opcodes.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_opcodes.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_params.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_processor.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_processor.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_low_level.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_low_level.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_policy_base.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_policy_base.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\broker_services.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\broker_services.h"
+			>
+		</File>
+		<File
+			RelativePath=".\internal_types.h"
+			>
+		</File>
+		<File
+			RelativePath=".\policy_broker.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\policy_broker.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_factory.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_policy.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_types.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_utils.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_utils.h"
+			>
+		</File>
+		<File
+			RelativePath=".\shared_handles.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\shared_handles.h"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+		<File
+			RelativePath=".\target_process.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\target_process.h"
+			>
+		</File>
+		<File
+			RelativePath=".\target_services.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\target_services.h"
+			>
+		</File>
+		<File
+			RelativePath=".\win2k_threadpool.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\win2k_threadpool.h"
+			>
+		</File>
+		<File
+			RelativePath=".\win_utils.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\win_utils.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/src/sandbox_factory.h b/sandbox/win/src/sandbox_factory.h
new file mode 100644
index 0000000..7a0280f
--- /dev/null
+++ b/sandbox/win/src/sandbox_factory.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_FACTORY_H__
+#define SANDBOX_SRC_SANDBOX_FACTORY_H__
+
+#include "sandbox/win/src/sandbox.h"
+
+// SandboxFactory is a set of static methods to get access to the broker
+// or target services object. Only one of the two methods (GetBrokerServices,
+// GetTargetServices) will return a non-null pointer and that should be used
+// as the indication that the process is the broker or the target:
+//
+// BrokerServices* broker_services = SandboxFactory::GetBrokerServices();
+// if (NULL != broker_services) {
+//   //we are the broker, call broker api here
+//   broker_services->Init();
+// } else {
+//   TargetServices* target_services = SandboxFactory::GetTargetServices();
+//   if (NULL != target_services) {
+//    //we are the target, call target api here
+//    target_services->Init();
+//  }
+//
+// The methods in this class are expected to be called from a single thread
+//
+// The Sandbox library needs to be linked against the main executable, but
+// sometimes the API calls are issued from a DLL that loads into the exe
+// process. These factory methods then need to be called from the main
+// exe and the interface pointers then can be safely passed to the DLL where
+// the Sandbox API calls are made.
+namespace sandbox {
+
+class SandboxFactory {
+ public:
+  // Returns the Broker API interface, returns NULL if this process is the
+  // target.
+  static BrokerServices* GetBrokerServices();
+
+  // Returns the Target API interface, returns NULL if this process is the
+  // broker.
+  static TargetServices* GetTargetServices();
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SandboxFactory);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SANDBOX_FACTORY_H__
diff --git a/sandbox/win/src/sandbox_globals.cc b/sandbox/win/src/sandbox_globals.cc
new file mode 100644
index 0000000..b4ab523
--- /dev/null
+++ b/sandbox/win/src/sandbox_globals.cc
@@ -0,0 +1,18 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+// The section for IPC and policy.
+SANDBOX_INTERCEPT HANDLE g_shared_section = NULL;
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt = {};
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_nt_types.h b/sandbox/win/src/sandbox_nt_types.h
new file mode 100644
index 0000000..a4a88bb
--- /dev/null
+++ b/sandbox/win/src/sandbox_nt_types.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_NT_TYPES_H__
+#define SANDBOX_SRC_SANDBOX_NT_TYPES_H__
+
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+struct NtExports {
+  NtAllocateVirtualMemoryFunction       AllocateVirtualMemory;
+  NtCloseFunction                       Close;
+  NtDuplicateObjectFunction             DuplicateObject;
+  NtFreeVirtualMemoryFunction           FreeVirtualMemory;
+  NtMapViewOfSectionFunction            MapViewOfSection;
+  NtProtectVirtualMemoryFunction        ProtectVirtualMemory;
+  NtQueryInformationProcessFunction     QueryInformationProcess;
+  NtQueryObjectFunction                 QueryObject;
+  NtQuerySectionFunction                QuerySection;
+  NtQueryVirtualMemoryFunction          QueryVirtualMemory;
+  NtUnmapViewOfSectionFunction          UnmapViewOfSection;
+  RtlAllocateHeapFunction               RtlAllocateHeap;
+  RtlAnsiStringToUnicodeStringFunction  RtlAnsiStringToUnicodeString;
+  RtlCompareUnicodeStringFunction       RtlCompareUnicodeString;
+  RtlCreateHeapFunction                 RtlCreateHeap;
+  RtlCreateUserThreadFunction           RtlCreateUserThread;
+  RtlDestroyHeapFunction                RtlDestroyHeap;
+  RtlFreeHeapFunction                   RtlFreeHeap;
+  _strnicmpFunction                     _strnicmp;
+  strlenFunction                        strlen;
+  wcslenFunction                        wcslen;
+  memcpyFunction                        memcpy;
+};
+
+// This is the value used for the ntdll level allocator.
+enum AllocationType {
+  NT_ALLOC,
+  NT_PAGE
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_SANDBOX_NT_TYPES_H__
diff --git a/sandbox/win/src/sandbox_nt_util.cc b/sandbox/win/src/sandbox_nt_util.cc
new file mode 100644
index 0000000..64fd1f1
--- /dev/null
+++ b/sandbox/win/src/sandbox_nt_util.cc
@@ -0,0 +1,679 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+}  // namespace sandbox
+
+namespace {
+
+#if defined(_WIN64)
+void* AllocateNearTo(void* source, size_t size) {
+  using sandbox::g_nt;
+
+  // Start with 1 GB above the source.
+  const size_t kOneGB = 0x40000000;
+  void* base = reinterpret_cast<char*>(source) + kOneGB;
+  SIZE_T actual_size = size;
+  ULONG_PTR zero_bits = 0;  // Not the correct type if used.
+  ULONG type = MEM_RESERVE;
+
+  NTSTATUS ret;
+  int attempts = 0;
+  for (; attempts < 41; attempts++) {
+    ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits,
+                                     &actual_size, type, PAGE_READWRITE);
+    if (NT_SUCCESS(ret)) {
+      if (base < source ||
+          base >= reinterpret_cast<char*>(source) + 4 * kOneGB) {
+        // We won't be able to patch this dll.
+        VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
+                                              MEM_RELEASE));
+        return NULL;
+      }
+      break;
+    }
+
+    if (attempts == 30) {
+      // Try the first GB.
+      base = reinterpret_cast<char*>(source);
+    } else if (attempts == 40) {
+      // Try the highest available address.
+      base = NULL;
+      type |= MEM_TOP_DOWN;
+    }
+
+    // Try 100 MB higher.
+    base = reinterpret_cast<char*>(base) + 100 * 0x100000;
+  };
+
+  if (attempts == 41)
+    return NULL;
+
+  ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits,
+                                   &actual_size, MEM_COMMIT, PAGE_READWRITE);
+
+  if (!NT_SUCCESS(ret)) {
+    VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
+                                          MEM_RELEASE));
+    base = NULL;
+  }
+
+  return base;
+}
+#else  // defined(_WIN64).
+void* AllocateNearTo(void* source, size_t size) {
+  using sandbox::g_nt;
+  UNREFERENCED_PARAMETER(source);
+
+  // In 32-bit processes allocations below 512k are predictable, so mark
+  // anything in that range as reserved and retry until we get a good address.
+  const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024);
+  NTSTATUS ret;
+  SIZE_T actual_size;
+  void* base;
+  do {
+    base = NULL;
+    actual_size = 64 * 1024;
+    ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size,
+                                     MEM_RESERVE, PAGE_NOACCESS);
+    if (!NT_SUCCESS(ret))
+      return NULL;
+  } while (base < kMinAddress);
+
+  actual_size = size;
+  ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size,
+                                   MEM_COMMIT, PAGE_READWRITE);
+  if (!NT_SUCCESS(ret))
+    return NULL;
+  return base;
+}
+#endif  // defined(_WIN64).
+
+}  // namespace.
+
+namespace sandbox {
+
+// Handle for our private heap.
+void* g_heap = NULL;
+
+SANDBOX_INTERCEPT HANDLE g_shared_section;
+SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0;
+SANDBOX_INTERCEPT size_t g_shared_policy_size = 0;
+
+void* volatile g_shared_policy_memory = NULL;
+void* volatile g_shared_IPC_memory = NULL;
+
+// Both the IPC and the policy share a single region of memory in which the IPC
+// memory is first and the policy memory is last.
+bool MapGlobalMemory() {
+  if (NULL == g_shared_IPC_memory) {
+    void* memory = NULL;
+    SIZE_T size = 0;
+    // Map the entire shared section from the start.
+    NTSTATUS ret = g_nt.MapViewOfSection(g_shared_section, NtCurrentProcess,
+                                         &memory, 0, 0, NULL, &size, ViewUnmap,
+                                         0, PAGE_READWRITE);
+
+    if (!NT_SUCCESS(ret) || NULL == memory) {
+      NOTREACHED_NT();
+      return false;
+    }
+
+    if (NULL != _InterlockedCompareExchangePointer(&g_shared_IPC_memory,
+                                                   memory, NULL)) {
+        // Somebody beat us to the memory setup.
+        ret = g_nt.UnmapViewOfSection(NtCurrentProcess, memory);
+        VERIFY_SUCCESS(ret);
+    }
+    DCHECK_NT(g_shared_IPC_size > 0);
+    g_shared_policy_memory = reinterpret_cast<char*>(g_shared_IPC_memory)
+                             + g_shared_IPC_size;
+  }
+  DCHECK_NT(g_shared_policy_memory);
+  DCHECK_NT(g_shared_policy_size > 0);
+  return true;
+}
+
+void* GetGlobalIPCMemory() {
+  if (!MapGlobalMemory())
+    return NULL;
+  return g_shared_IPC_memory;
+}
+
+void* GetGlobalPolicyMemory() {
+  if (!MapGlobalMemory())
+    return NULL;
+  return g_shared_policy_memory;
+}
+
+bool InitHeap() {
+  if (!g_heap) {
+    // Create a new heap using default values for everything.
+    void* heap = g_nt.RtlCreateHeap(HEAP_GROWABLE, NULL, 0, 0, NULL, NULL);
+    if (!heap)
+      return false;
+
+    if (NULL != _InterlockedCompareExchangePointer(&g_heap, heap, NULL)) {
+      // Somebody beat us to the memory setup.
+      g_nt.RtlDestroyHeap(heap);
+    }
+  }
+  return (g_heap != NULL);
+}
+
+// Physically reads or writes from memory to verify that (at this time), it is
+// valid. Returns a dummy value.
+int TouchMemory(void* buffer, size_t size_bytes, RequiredAccess intent) {
+  const int kPageSize = 4096;
+  int dummy = 0;
+  char* start = reinterpret_cast<char*>(buffer);
+  char* end = start + size_bytes - 1;
+
+  if (WRITE == intent) {
+    for (; start < end; start += kPageSize) {
+      *start = 0;
+    }
+    *end = 0;
+  } else {
+    for (; start < end; start += kPageSize) {
+      dummy += *start;
+    }
+    dummy += *end;
+  }
+
+  return dummy;
+}
+
+bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) {
+  DCHECK_NT(size);
+  __try {
+    TouchMemory(buffer, size, intent);
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    return false;
+  }
+  return true;
+}
+
+NTSTATUS CopyData(void* destination, const void* source, size_t bytes) {
+  NTSTATUS ret = STATUS_SUCCESS;
+  __try {
+    g_nt.memcpy(destination, source, bytes);
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    ret = GetExceptionCode();
+  }
+  return ret;
+}
+
+NTSTATUS AllocAndGetFullPath(HANDLE root,
+                             wchar_t* path,
+                             wchar_t** full_path) {
+  if (!InitHeap())
+    return STATUS_NO_MEMORY;
+
+  DCHECK_NT(full_path);
+  DCHECK_NT(path);
+  *full_path = NULL;
+  OBJECT_NAME_INFORMATION* handle_name = NULL;
+  NTSTATUS ret = STATUS_UNSUCCESSFUL;
+  __try {
+    do {
+      static NtQueryObjectFunction NtQueryObject = NULL;
+      if (!NtQueryObject)
+        ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
+
+      ULONG size = 0;
+      // Query the name information a first time to get the size of the name.
+      ret = NtQueryObject(root, ObjectNameInformation, NULL, 0, &size);
+
+      if (size) {
+        handle_name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(
+            new(NT_ALLOC) BYTE[size]);
+
+        // Query the name information a second time to get the name of the
+        // object referenced by the handle.
+        ret = NtQueryObject(root, ObjectNameInformation, handle_name, size,
+                            &size);
+      }
+
+      if (STATUS_SUCCESS != ret)
+        break;
+
+      // Space for path + '\' + name + '\0'.
+      size_t name_length = handle_name->ObjectName.Length +
+                           (wcslen(path) + 2) * sizeof(wchar_t);
+      *full_path = new(NT_ALLOC) wchar_t[name_length/sizeof(wchar_t)];
+      if (NULL == *full_path)
+        break;
+      wchar_t* off = *full_path;
+      ret = CopyData(off, handle_name->ObjectName.Buffer,
+                     handle_name->ObjectName.Length);
+      if (!NT_SUCCESS(ret))
+        break;
+      off += handle_name->ObjectName.Length / sizeof(wchar_t);
+      *off = L'\\';
+      off += 1;
+      ret = CopyData(off, path, wcslen(path) * sizeof(wchar_t));
+      if (!NT_SUCCESS(ret))
+        break;
+      off += wcslen(path);
+      *off = L'\0';
+    } while (false);
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    ret = GetExceptionCode();
+  }
+
+  if (!NT_SUCCESS(ret)) {
+    if (*full_path) {
+      operator delete(*full_path, NT_ALLOC);
+      *full_path = NULL;
+    }
+    if (handle_name) {
+      operator delete(handle_name, NT_ALLOC);
+      handle_name = NULL;
+    }
+  }
+
+  return ret;
+}
+
+// Hacky code... replace with AllocAndCopyObjectAttributes.
+NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
+                          wchar_t** out_name, uint32* attributes,
+                          HANDLE* root) {
+  if (!InitHeap())
+    return STATUS_NO_MEMORY;
+
+  DCHECK_NT(out_name);
+  *out_name = NULL;
+  NTSTATUS ret = STATUS_UNSUCCESSFUL;
+  __try {
+    do {
+      if (in_object->RootDirectory != static_cast<HANDLE>(0) && !root)
+        break;
+      if (NULL == in_object->ObjectName)
+        break;
+      if (NULL == in_object->ObjectName->Buffer)
+        break;
+
+      size_t size = in_object->ObjectName->Length + sizeof(wchar_t);
+      *out_name = new(NT_ALLOC) wchar_t[size/sizeof(wchar_t)];
+      if (NULL == *out_name)
+        break;
+
+      ret = CopyData(*out_name, in_object->ObjectName->Buffer,
+                     size - sizeof(wchar_t));
+      if (!NT_SUCCESS(ret))
+        break;
+
+      (*out_name)[size / sizeof(wchar_t) - 1] = L'\0';
+
+      if (attributes)
+        *attributes = in_object->Attributes;
+
+      if (root)
+        *root = in_object->RootDirectory;
+      ret = STATUS_SUCCESS;
+    } while (false);
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+    ret = GetExceptionCode();
+  }
+
+  if (!NT_SUCCESS(ret) && *out_name) {
+    operator delete(*out_name, NT_ALLOC);
+    *out_name = NULL;
+  }
+
+  return ret;
+}
+
+NTSTATUS GetProcessId(HANDLE process, ULONG *process_id) {
+  PROCESS_BASIC_INFORMATION proc_info;
+  ULONG bytes_returned;
+
+  NTSTATUS ret = g_nt.QueryInformationProcess(process, ProcessBasicInformation,
+                                              &proc_info, sizeof(proc_info),
+                                              &bytes_returned);
+  if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned)
+    return ret;
+
+  *process_id = proc_info.UniqueProcessId;
+  return STATUS_SUCCESS;
+}
+
+bool IsSameProcess(HANDLE process) {
+  if (NtCurrentProcess == process)
+    return true;
+
+  static ULONG s_process_id = 0;
+
+  if (!s_process_id) {
+    NTSTATUS ret = GetProcessId(NtCurrentProcess, &s_process_id);
+    if (!NT_SUCCESS(ret))
+      return false;
+  }
+
+  ULONG process_id;
+  NTSTATUS ret = GetProcessId(process, &process_id);
+  if (!NT_SUCCESS(ret))
+    return false;
+
+  return (process_id == s_process_id);
+}
+
+bool IsValidImageSection(HANDLE section, PVOID *base, PLARGE_INTEGER offset,
+                         PSIZE_T view_size) {
+  if (!section || !base || !view_size || offset)
+    return false;
+
+  HANDLE query_section;
+
+  NTSTATUS ret = g_nt.DuplicateObject(NtCurrentProcess, section,
+                                      NtCurrentProcess, &query_section,
+                                      SECTION_QUERY, 0, 0);
+  if (!NT_SUCCESS(ret))
+    return false;
+
+  SECTION_BASIC_INFORMATION basic_info;
+  SIZE_T bytes_returned;
+  ret = g_nt.QuerySection(query_section, SectionBasicInformation, &basic_info,
+                          sizeof(basic_info), &bytes_returned);
+
+  VERIFY_SUCCESS(g_nt.Close(query_section));
+
+  if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned)
+    return false;
+
+  if (!(basic_info.Attributes & SEC_IMAGE))
+    return false;
+
+  return true;
+}
+
+UNICODE_STRING* AnsiToUnicode(const char* string) {
+  ANSI_STRING ansi_string;
+  ansi_string.Length = static_cast<USHORT>(g_nt.strlen(string));
+  ansi_string.MaximumLength = ansi_string.Length + 1;
+  ansi_string.Buffer = const_cast<char*>(string);
+
+  if (ansi_string.Length > ansi_string.MaximumLength)
+    return NULL;
+
+  size_t name_bytes = ansi_string.MaximumLength * sizeof(wchar_t) +
+                      sizeof(UNICODE_STRING);
+
+  UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(
+                                   new(NT_ALLOC) char[name_bytes]);
+  if (!out_string)
+    return NULL;
+
+  out_string->MaximumLength = ansi_string.MaximumLength *  sizeof(wchar_t);
+  out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
+
+  BOOLEAN alloc_destination = FALSE;
+  NTSTATUS ret = g_nt.RtlAnsiStringToUnicodeString(out_string, &ansi_string,
+                                                   alloc_destination);
+  DCHECK_NT(STATUS_BUFFER_OVERFLOW != ret);
+  if (!NT_SUCCESS(ret)) {
+    operator delete(out_string, NT_ALLOC);
+    return NULL;
+  }
+
+  return out_string;
+}
+
+UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32* flags) {
+  // PEImage's dtor won't be run during SEH unwinding, but that's OK.
+#pragma warning(push)
+#pragma warning(disable: 4509)
+  UNICODE_STRING* out_name = NULL;
+  __try {
+    do {
+      *flags = 0;
+      base::win::PEImage pe(module);
+
+      if (!pe.VerifyMagic())
+        break;
+      *flags |= MODULE_IS_PE_IMAGE;
+
+      PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
+      if (exports) {
+        char* name = reinterpret_cast<char*>(pe.RVAToAddr(exports->Name));
+        out_name = AnsiToUnicode(name);
+      }
+
+      PIMAGE_NT_HEADERS headers = pe.GetNTHeaders();
+      if (headers) {
+        if (headers->OptionalHeader.AddressOfEntryPoint)
+          *flags |= MODULE_HAS_ENTRY_POINT;
+        if (headers->OptionalHeader.SizeOfCode)
+          *flags |= MODULE_HAS_CODE;
+      }
+    } while (false);
+  } __except(EXCEPTION_EXECUTE_HANDLER) {
+  }
+
+  return out_name;
+#pragma warning(pop)
+}
+
+UNICODE_STRING* GetBackingFilePath(PVOID address) {
+  // We'll start with something close to max_path charactes for the name.
+  SIZE_T buffer_bytes = MAX_PATH * 2;
+
+  for (;;) {
+    MEMORY_SECTION_NAME* section_name = reinterpret_cast<MEMORY_SECTION_NAME*>(
+        new(NT_ALLOC) char[buffer_bytes]);
+
+    if (!section_name)
+      return NULL;
+
+    SIZE_T returned_bytes;
+    NTSTATUS ret = g_nt.QueryVirtualMemory(NtCurrentProcess, address,
+                                           MemorySectionName, section_name,
+                                           buffer_bytes, &returned_bytes);
+
+    if (STATUS_BUFFER_OVERFLOW == ret) {
+      // Retry the call with the given buffer size.
+      operator delete(section_name, NT_ALLOC);
+      section_name = NULL;
+      buffer_bytes = returned_bytes;
+      continue;
+    }
+    if (!NT_SUCCESS(ret)) {
+      operator delete(section_name, NT_ALLOC);
+      return NULL;
+    }
+
+    return reinterpret_cast<UNICODE_STRING*>(section_name);
+  }
+}
+
+UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path) {
+  if ((!module_path) || (!module_path->Buffer))
+    return NULL;
+
+  wchar_t* sep = NULL;
+  int start_pos = module_path->Length / sizeof(wchar_t) - 1;
+  int ix = start_pos;
+
+  for (; ix >= 0; --ix) {
+    if (module_path->Buffer[ix] == L'\\') {
+      sep = &module_path->Buffer[ix];
+      break;
+    }
+  }
+
+  // Ends with path separator. Not a valid module name.
+  if ((ix == start_pos) && sep)
+    return NULL;
+
+  // No path separator found. Use the entire name.
+  if (!sep) {
+    sep = &module_path->Buffer[-1];
+  }
+
+  // Add one to the size so we can null terminate the string.
+  size_t size_bytes = (start_pos - ix + 1) * sizeof(wchar_t);
+
+  // Based on the code above, size_bytes should always be small enough
+  // to make the static_cast below safe.
+  DCHECK_NT(kuint16max > size_bytes);
+  char* str_buffer = new(NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)];
+  if (!str_buffer)
+    return NULL;
+
+  UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(str_buffer);
+  out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
+  out_string->Length = static_cast<USHORT>(size_bytes - sizeof(wchar_t));
+  out_string->MaximumLength = static_cast<USHORT>(size_bytes);
+
+  NTSTATUS ret = CopyData(out_string->Buffer, &sep[1], out_string->Length);
+  if (!NT_SUCCESS(ret)) {
+    operator delete(out_string, NT_ALLOC);
+    return NULL;
+  }
+
+  out_string->Buffer[out_string->Length / sizeof(wchar_t)] = L'\0';
+  return out_string;
+}
+
+NTSTATUS AutoProtectMemory::ChangeProtection(void* address, size_t bytes,
+                                             ULONG protect) {
+  DCHECK_NT(!changed_);
+  SIZE_T new_bytes = bytes;
+  NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address,
+                                           &new_bytes, protect, &old_protect_);
+  if (NT_SUCCESS(ret)) {
+    changed_ = true;
+    address_ = address;
+    bytes_ = new_bytes;
+  }
+
+  return ret;
+}
+
+NTSTATUS AutoProtectMemory::RevertProtection() {
+  if (!changed_)
+    return STATUS_SUCCESS;
+
+  DCHECK_NT(address_);
+  DCHECK_NT(bytes_);
+
+  SIZE_T new_bytes = bytes_;
+  NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address_,
+                                           &new_bytes, old_protect_,
+                                           &old_protect_);
+  DCHECK_NT(NT_SUCCESS(ret));
+
+  changed_ = false;
+  address_ = NULL;
+  bytes_ = 0;
+  old_protect_ = 0;
+
+  return ret;
+}
+
+bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info, DWORD length,
+                           uint32 file_info_class) {
+  if (FileRenameInformation != file_info_class)
+    return false;
+
+  if (length < sizeof(FILE_RENAME_INFORMATION))
+    return false;
+
+  // Make sure file name length doesn't exceed the message length
+  if (length - offsetof(FILE_RENAME_INFORMATION, FileName) <
+      file_info->FileNameLength)
+    return false;
+
+  // We don't support a root directory.
+  if (file_info->RootDirectory)
+    return false;
+
+  static const wchar_t kPathPrefix[] = { L'\\', L'?', L'?', L'\\'};
+
+  // Check if it starts with \\??\\. We don't support relative paths.
+  if (file_info->FileNameLength < sizeof(kPathPrefix) ||
+      file_info->FileNameLength > kuint16max)
+    return false;
+
+  if (file_info->FileName[0] != kPathPrefix[0] ||
+      file_info->FileName[1] != kPathPrefix[1] ||
+      file_info->FileName[2] != kPathPrefix[2] ||
+      file_info->FileName[3] != kPathPrefix[3])
+    return false;
+
+  return true;
+}
+
+}  // namespace sandbox
+
+void* operator new(size_t size, sandbox::AllocationType type,
+                   void* near_to) {
+  using namespace sandbox;
+
+  void* result = NULL;
+  if (NT_ALLOC == type) {
+    if (InitHeap()) {
+      // Use default flags for the allocation.
+      result = g_nt.RtlAllocateHeap(sandbox::g_heap, 0, size);
+    }
+  } else if (NT_PAGE == type) {
+    result = AllocateNearTo(near_to, size);
+  } else {
+    NOTREACHED_NT();
+  }
+
+  // TODO: Returning NULL from operator new has undefined behavior, but
+  // the Allocate() functions called above can return NULL. Consider checking
+  // for NULL here and crashing or throwing.
+
+  return result;
+}
+
+void operator delete(void* memory, sandbox::AllocationType type) {
+  using namespace sandbox;
+
+  if (NT_ALLOC == type) {
+    // Use default flags.
+    VERIFY(g_nt.RtlFreeHeap(sandbox::g_heap, 0, memory));
+  } else if (NT_PAGE == type) {
+    void* base = memory;
+    SIZE_T size = 0;
+    VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size,
+                                          MEM_RELEASE));
+  } else {
+    NOTREACHED_NT();
+  }
+}
+
+void operator delete(void* memory, sandbox::AllocationType type,
+                     void* near_to) {
+  UNREFERENCED_PARAMETER(near_to);
+  operator delete(memory, type);
+}
+
+void* __cdecl operator new(size_t size, void* buffer,
+                           sandbox::AllocationType type) {
+  UNREFERENCED_PARAMETER(size);
+  UNREFERENCED_PARAMETER(type);
+  return buffer;
+}
+
+void __cdecl operator delete(void* memory, void* buffer,
+                             sandbox::AllocationType type) {
+  UNREFERENCED_PARAMETER(memory);
+  UNREFERENCED_PARAMETER(buffer);
+  UNREFERENCED_PARAMETER(type);
+}
diff --git a/sandbox/win/src/sandbox_nt_util.h b/sandbox/win/src/sandbox_nt_util.h
new file mode 100644
index 0000000..83dd7c0
--- /dev/null
+++ b/sandbox/win/src/sandbox_nt_util.h
@@ -0,0 +1,191 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_NT_UTIL_H_
+#define SANDBOX_SRC_SANDBOX_NT_UTIL_H_
+
+#include <intrin.h>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+
+// Placement new and delete to be used from ntdll interception code.
+void* __cdecl operator new(size_t size, sandbox::AllocationType type,
+                           void* near_to = NULL);
+void __cdecl operator delete(void* memory, sandbox::AllocationType type);
+// Add operator delete that matches the placement form of the operator new
+// above. This is required by compiler to generate code to call operator delete
+// in case the object's constructor throws an exception.
+// See http://msdn.microsoft.com/en-us/library/cxdxz3x6.aspx
+void __cdecl operator delete(void* memory, sandbox::AllocationType type,
+                             void* near_to);
+
+// Regular placement new and delete
+void* __cdecl operator new(size_t size, void* buffer,
+                           sandbox::AllocationType type);
+void __cdecl operator delete(void* memory, void* buffer,
+                             sandbox::AllocationType type);
+
+// DCHECK_NT is defined to be pretty much an assert at this time because we
+// don't have logging from the ntdll layer on the child.
+//
+// VERIFY_NT and VERIFY_SUCCESS_NT are the standard asserts on debug, but
+// execute the actual argument on release builds. VERIFY_NT expects an action
+// returning a bool, while VERIFY_SUCCESS_NT expects an action returning
+// NTSTATUS.
+#ifndef NDEBUG
+#define DCHECK_NT(condition) { (condition) ? (void)0 : __debugbreak(); }
+#define VERIFY(action) DCHECK_NT(action)
+#define VERIFY_SUCCESS(action) DCHECK_NT(NT_SUCCESS(action))
+#else
+#define DCHECK_NT(condition)
+#define VERIFY(action) (action)
+#define VERIFY_SUCCESS(action) (action)
+#endif
+
+#define CHECK_NT(condition) { (condition) ? (void)0 : __debugbreak(); }
+
+#define NOTREACHED_NT() DCHECK_NT(false)
+
+namespace sandbox {
+
+#if defined(_M_X64)
+#pragma intrinsic(_InterlockedCompareExchange)
+#pragma intrinsic(_InterlockedCompareExchangePointer)
+
+#elif defined(_M_IX86)
+extern "C" long _InterlockedCompareExchange(long volatile* destination,
+                                            long exchange, long comperand);
+
+#pragma intrinsic(_InterlockedCompareExchange)
+
+// We want to make sure that we use an intrinsic version of the function, not
+// the one provided by kernel32.
+__forceinline void* _InterlockedCompareExchangePointer(
+    void* volatile* destination, void* exchange, void* comperand) {
+  size_t ret = _InterlockedCompareExchange(
+      reinterpret_cast<long volatile*>(destination),
+      static_cast<long>(reinterpret_cast<size_t>(exchange)),
+      static_cast<long>(reinterpret_cast<size_t>(comperand)));
+
+  return reinterpret_cast<void*>(static_cast<size_t>(ret));
+}
+
+#else
+#error Architecture not supported.
+
+#endif
+
+// Returns a pointer to the IPC shared memory.
+void* GetGlobalIPCMemory();
+
+// Returns a pointer to the Policy shared memory.
+void* GetGlobalPolicyMemory();
+
+enum RequiredAccess {
+  READ,
+  WRITE
+};
+
+// Performs basic user mode buffer validation. In any case, buffers access must
+// be protected by SEH. intent specifies if the buffer should be tested for read
+// or write.
+// Note that write intent implies destruction of the buffer content (we actually
+// write)
+bool ValidParameter(void* buffer, size_t size, RequiredAccess intent);
+
+// Copies data from a user buffer to our buffer. Returns the operation status.
+NTSTATUS CopyData(void* destination, const void* source, size_t bytes);
+
+// Copies the name from an object attributes.
+NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
+                          wchar_t** out_name, uint32* attributes, HANDLE* root);
+
+// Determine full path name from object root and path.
+NTSTATUS AllocAndGetFullPath(HANDLE root,
+                             wchar_t* path,
+                             wchar_t** full_path);
+
+// Initializes our ntdll level heap
+bool InitHeap();
+
+// Returns true if the provided handle refers to the current process.
+bool IsSameProcess(HANDLE process);
+
+enum MappedModuleFlags {
+  MODULE_IS_PE_IMAGE     = 1,   // Module is an executable.
+  MODULE_HAS_ENTRY_POINT = 2,   // Execution entry point found.
+  MODULE_HAS_CODE =        4    // Non zero size of executable sections.
+};
+
+// Returns the name and characteristics for a given PE module. The return
+// value is the name as defined by the export table and the flags is any
+// combination of the MappedModuleFlags enumeration.
+//
+// The returned buffer must be freed with a placement delete from the ntdll
+// level allocator:
+//
+// UNICODE_STRING* name = GetPEImageInfoFromModule(HMODULE module, &flags);
+// if (!name) {
+//   // probably not a valid dll
+//   return;
+// }
+// InsertYourLogicHere(name);
+// operator delete(name, NT_ALLOC);
+UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32* flags);
+
+// Returns the full path and filename for a given dll.
+// May return NULL if the provided address is not backed by a named section, or
+// if the current OS version doesn't support the call. The returned buffer must
+// be freed with a placement delete (see GetImageNameFromModule example).
+UNICODE_STRING* GetBackingFilePath(PVOID address);
+
+// Returns the last component of a path that contains the module name.
+// It will return NULL if the path ends with the path separator. The returned
+// buffer must be freed with a placement delete (see GetImageNameFromModule
+// example).
+UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path);
+
+// Returns true if the parameters correspond to a dll mapped as code.
+bool IsValidImageSection(HANDLE section, PVOID *base, PLARGE_INTEGER offset,
+                         PSIZE_T view_size);
+
+// Converts an ansi string to an UNICODE_STRING.
+UNICODE_STRING* AnsiToUnicode(const char* string);
+
+// Provides a simple way to temporarily change the protection of a memory page.
+class AutoProtectMemory {
+ public:
+  AutoProtectMemory()
+      : changed_(false), address_(NULL), bytes_(0), old_protect_(0) {}
+
+  ~AutoProtectMemory() {
+    RevertProtection();
+  }
+
+  // Sets the desired protection of a given memory range.
+  NTSTATUS ChangeProtection(void* address, size_t bytes, ULONG protect);
+
+  // Restores the original page protection.
+  NTSTATUS RevertProtection();
+
+ private:
+  bool changed_;
+  void* address_;
+  size_t bytes_;
+  ULONG old_protect_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutoProtectMemory);
+};
+
+// Returns true if the file_rename_information structure is supported by our
+// rename handler.
+bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info, DWORD length,
+                           uint32 file_info_class);
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_SANDBOX_NT_UTIL_H__
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
new file mode 100644
index 0000000..54bb2a9
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy.h
@@ -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.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/security_level.h"
+
+namespace sandbox {
+
+class TargetPolicy {
+ public:
+  // Windows subsystems that can have specific rules.
+  // Note: The process subsystem(SUBSY_PROCESS) does not evaluate the request
+  // exactly like the CreateProcess API does. See the comment at the top of
+  // process_thread_dispatcher.cc for more details.
+  enum SubSystem {
+    SUBSYS_FILES,             // Creation and opening of files and pipes.
+    SUBSYS_NAMED_PIPES,       // Creation of named pipes.
+    SUBSYS_PROCESS,           // Creation of child processes.
+    SUBSYS_REGISTRY,          // Creation and opening of registry keys.
+    SUBSYS_SYNC,              // Creation of named sync objects.
+    SUBSYS_HANDLES,           // Duplication of handles to other processes.
+    SUBSYS_WIN32K_LOCKDOWN    // Win32K Lockdown related policy.
+  };
+
+  // Allowable semantics when a rule is matched.
+  enum Semantics {
+    FILES_ALLOW_ANY,       // Allows open or create for any kind of access that
+                           // the file system supports.
+    FILES_ALLOW_READONLY,  // Allows open or create with read access only.
+    FILES_ALLOW_QUERY,     // Allows access to query the attributes of a file.
+    FILES_ALLOW_DIR_ANY,   // Allows open or create with directory semantics
+                           // only.
+    HANDLES_DUP_ANY,       // Allows duplicating handles opened with any
+                           // access permissions.
+    HANDLES_DUP_BROKER,    // Allows duplicating handles to the broker process.
+    NAMEDPIPES_ALLOW_ANY,  // Allows creation of a named pipe.
+    PROCESS_MIN_EXEC,      // Allows to create a process with minimal rights
+                           // over the resulting process and thread handles.
+                           // No other parameters besides the command line are
+                           // passed to the child process.
+    PROCESS_ALL_EXEC,      // Allows the creation of a process and return fill
+                           // access on the returned handles.
+                           // This flag can be used only when the main token of
+                           // the sandboxed application is at least INTERACTIVE.
+    EVENTS_ALLOW_ANY,      // Allows the creation of an event with full access.
+    EVENTS_ALLOW_READONLY, // Allows opening an even with synchronize access.
+    REG_ALLOW_READONLY,    // Allows readonly access to a registry key.
+    REG_ALLOW_ANY,         // Allows read and write access to a registry key.
+    FAKE_USER_GDI_INIT     // Fakes user32 and gdi32 initialization. This can
+                           // be used to allow the DLLs to load and initialize
+                           // even if the process cannot access that subsystem.
+  };
+
+  // Increments the reference count of this object. The reference count must
+  // be incremented if this interface is given to another component.
+  virtual void AddRef() = 0;
+
+  // Decrements the reference count of this object. When the reference count
+  // is zero the object is automatically destroyed.
+  // Indicates that the caller is done with this interface. After calling
+  // release no other method should be called.
+  virtual void Release() = 0;
+
+  // Sets the security level for the target process' two tokens.
+  // This setting is permanent and cannot be changed once the target process is
+  // spawned.
+  // initial: the security level for the initial token. This is the token that
+  //   is used by the process from the creation of the process until the moment
+  //   the process calls TargetServices::LowerToken() or the process calls
+  //   win32's ReverToSelf(). Once this happens the initial token is no longer
+  //   available and the lockdown token is in effect. Using an initial token is
+  //   not compatible with AppContainer, see SetAppContainer.
+  // lockdown: the security level for the token that comes into force after the
+  //   process calls TargetServices::LowerToken() or the process calls
+  //   ReverToSelf(). See the explanation of each level in the TokenLevel
+  //   definition.
+  // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
+  //   Returns false if the lockdown value is more permissive than the initial
+  //   value.
+  //
+  // Important: most of the sandbox-provided security relies on this single
+  // setting. The caller should strive to set the lockdown level as restricted
+  // as possible.
+  virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0;
+
+  // Returns the initial token level.
+  virtual TokenLevel GetInitialTokenLevel() const = 0;
+
+  // Returns the lockdown token level.
+  virtual TokenLevel GetLockdownTokenLevel() const = 0;
+
+  // Sets the security level of the Job Object to which the target process will
+  // belong. This setting is permanent and cannot be changed once the target
+  // process is spawned. The job controls the global security settings which
+  // can not be specified in the token security profile.
+  // job_level: the security level for the job. See the explanation of each
+  //   level in the JobLevel definition.
+  // ui_exceptions: specify what specific rights that are disabled in the
+  //   chosen job_level that need to be granted. Use this parameter to avoid
+  //   selecting the next permissive job level unless you need all the rights
+  //   that are granted in such level.
+  //   The exceptions can be specified as a combination of the following
+  //   constants:
+  // JOB_OBJECT_UILIMIT_HANDLES : grant access to all user-mode handles. These
+  //   include windows, icons, menus and various GDI objects. In addition the
+  //   target process can set hooks, and broadcast messages to other processes
+  //   that belong to the same desktop.
+  // JOB_OBJECT_UILIMIT_READCLIPBOARD : grant read-only access to the clipboard.
+  // JOB_OBJECT_UILIMIT_WRITECLIPBOARD : grant write access to the clipboard.
+  // JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS : allow changes to the system-wide
+  //   parameters as defined by the Win32 call SystemParametersInfo().
+  // JOB_OBJECT_UILIMIT_DISPLAYSETTINGS : allow programmatic changes to the
+  //  display settings.
+  // JOB_OBJECT_UILIMIT_GLOBALATOMS : allow access to the global atoms table.
+  // JOB_OBJECT_UILIMIT_DESKTOP : allow the creation of new desktops.
+  // JOB_OBJECT_UILIMIT_EXITWINDOWS : allow the call to ExitWindows().
+  //
+  // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
+  //
+  // Note: JOB_OBJECT_XXXX constants are defined in winnt.h and documented at
+  // length in:
+  //   http://msdn2.microsoft.com/en-us/library/ms684152.aspx
+  //
+  // Note: the recommended level is JOB_RESTRICTED or JOB_LOCKDOWN.
+  virtual ResultCode SetJobLevel(JobLevel job_level, uint32 ui_exceptions) = 0;
+
+  // Sets a hard limit on the size of the commit set for the sandboxed process.
+  // If the limit is reached, the process will be terminated with
+  // SBOX_FATAL_MEMORY_EXCEEDED (7012).
+  virtual ResultCode SetJobMemoryLimit(size_t memory_limit) = 0;
+
+  // Specifies the desktop on which the application is going to run. If the
+  // desktop does not exist, it will be created. If alternate_winstation is
+  // set to true, the desktop will be created on an alternate window station.
+  virtual ResultCode SetAlternateDesktop(bool alternate_winstation) = 0;
+
+  // Returns the name of the alternate desktop used. If an alternate window
+  // station is specified, the name is prepended by the window station name,
+  // followed by a backslash.
+  virtual base::string16 GetAlternateDesktop() const = 0;
+
+  // Precreates the desktop and window station, if any.
+  virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) = 0;
+
+  // Destroys the desktop and windows station.
+  virtual void DestroyAlternateDesktop() = 0;
+
+  // Sets the integrity level of the process in the sandbox. Both the initial
+  // token and the main token will be affected by this. If the integrity level
+  // is set to a level higher than the current level, the sandbox will fail
+  // to start.
+  virtual ResultCode SetIntegrityLevel(IntegrityLevel level) = 0;
+
+  // Returns the initial integrity level used.
+  virtual IntegrityLevel GetIntegrityLevel() const = 0;
+
+  // Sets the integrity level of the process in the sandbox. The integrity level
+  // will not take effect before you call LowerToken. User Interface Privilege
+  // Isolation is not affected by this setting and will remain off for the
+  // process in the sandbox. If the integrity level is set to a level higher
+  // than the current level, the sandbox will fail to start.
+  virtual ResultCode SetDelayedIntegrityLevel(IntegrityLevel level) = 0;
+
+  // Sets the AppContainer to be used for the sandboxed process. Any capability
+  // to be enabled for the process should be added before this method is invoked
+  // (by calling SetCapability() as many times as needed).
+  // The desired AppContainer must be already installed on the system, otherwise
+  // launching the sandboxed process will fail. See BrokerServices for details
+  // about installing an AppContainer.
+  // Note that currently Windows restricts the use of impersonation within
+  // AppContainers, so this function is incompatible with the use of an initial
+  // token.
+  virtual ResultCode SetAppContainer(const wchar_t* sid) = 0;
+
+  // Sets a capability to be enabled for the sandboxed process' AppContainer.
+  virtual ResultCode SetCapability(const wchar_t* sid) = 0;
+
+  // Sets the LowBox token for sandboxed process. This is mutually exclusive
+  // with SetAppContainer method.
+  virtual ResultCode SetLowBox(const wchar_t* sid) = 0;
+
+  // Sets the mitigations enabled when the process is created. Most of these
+  // are implemented as attributes passed via STARTUPINFOEX. So they take
+  // effect before any thread in the target executes. The declaration of
+  // MitigationFlags is followed by a detailed description of each flag.
+  virtual ResultCode SetProcessMitigations(MitigationFlags flags) = 0;
+
+  // Returns the currently set mitigation flags.
+  virtual MitigationFlags GetProcessMitigations() = 0;
+
+  // Sets process mitigation flags that don't take effect before the call to
+  // LowerToken().
+  virtual ResultCode SetDelayedProcessMitigations(MitigationFlags flags) = 0;
+
+  // Returns the currently set delayed mitigation flags.
+  virtual MitigationFlags GetDelayedProcessMitigations() const = 0;
+
+  // Sets the interceptions to operate in strict mode. By default, interceptions
+  // are performed in "relaxed" mode, where if something inside NTDLL.DLL is
+  // already patched we attempt to intercept it anyway. Setting interceptions
+  // to strict mode means that when we detect that the function is patched we'll
+  // refuse to perform the interception.
+  virtual void SetStrictInterceptions() = 0;
+
+  // Set the handles the target process should inherit for stdout and
+  // stderr.  The handles the caller passes must remain valid for the
+  // lifetime of the policy object.  This only has an effect on
+  // Windows Vista and later versions.  These methods accept pipe and
+  // file handles, but not console handles.
+  virtual ResultCode SetStdoutHandle(HANDLE handle) = 0;
+  virtual ResultCode SetStderrHandle(HANDLE handle) = 0;
+
+  // Adds a policy rule effective for processes spawned using this policy.
+  // subsystem: One of the above enumerated windows subsystems.
+  // semantics: One of the above enumerated FileSemantics.
+  // pattern: A specific full path or a full path with wildcard patterns.
+  //   The valid wildcards are:
+  //   '*' : Matches zero or more character. Only one in series allowed.
+  //   '?' : Matches a single character. One or more in series are allowed.
+  // Examples:
+  //   "c:\\documents and settings\\vince\\*.dmp"
+  //   "c:\\documents and settings\\*\\crashdumps\\*.dmp"
+  //   "c:\\temp\\app_log_?????_chrome.txt"
+  virtual ResultCode AddRule(SubSystem subsystem, Semantics semantics,
+                             const wchar_t* pattern) = 0;
+
+  // Adds a dll that will be unloaded in the target process before it gets
+  // a chance to initialize itself. Typically, dlls that cause the target
+  // to crash go here.
+  virtual ResultCode AddDllToUnload(const wchar_t* dll_name) = 0;
+
+  // Adds a handle that will be closed in the target process after lockdown.
+  // A NULL value for handle_name indicates all handles of the specified type.
+  // An empty string for handle_name indicates the handle is unnamed.
+  virtual ResultCode AddKernelObjectToClose(const wchar_t* handle_type,
+                                            const wchar_t* handle_name) = 0;
+
+  // Adds a handle that will be shared with the target process.
+  // Returns the handle which was actually shared with the target. This is
+  // achieved by duplicating the handle to ensure that it is inheritable by
+  // the target. The caller should treat this as an opaque value.
+  virtual void* AddHandleToShare(HANDLE handle) = 0;
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
new file mode 100644
index 0000000..81b1e6a
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -0,0 +1,837 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+#include <sddl.h>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container.h"
+#include "sandbox/win/src/filesystem_dispatcher.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/handle_dispatcher.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/named_pipe_dispatcher.h"
+#include "sandbox/win/src/named_pipe_policy.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+#include "sandbox/win/src/process_thread_dispatcher.h"
+#include "sandbox/win/src/process_thread_policy.h"
+#include "sandbox/win/src/registry_dispatcher.h"
+#include "sandbox/win/src/registry_policy.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sync_dispatcher.h"
+#include "sandbox/win/src/sync_policy.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/window.h"
+
+namespace {
+
+// The standard windows size for one memory page.
+const size_t kOneMemPage = 4096;
+// The IPC and Policy shared memory sizes.
+const size_t kIPCMemSize = kOneMemPage * 2;
+const size_t kPolMemSize = kOneMemPage * 14;
+
+// Helper function to allocate space (on the heap) for policy.
+sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
+  const size_t kTotalPolicySz = kPolMemSize;
+  sandbox::PolicyGlobal* policy = static_cast<sandbox::PolicyGlobal*>
+      (::operator new(kTotalPolicySz));
+  DCHECK(policy);
+  memset(policy, 0, kTotalPolicySz);
+  policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
+  return policy;
+}
+
+bool IsInheritableHandle(HANDLE handle) {
+  if (!handle)
+    return false;
+  if (handle == INVALID_HANDLE_VALUE)
+    return false;
+  // File handles (FILE_TYPE_DISK) and pipe handles are known to be
+  // inheritable.  Console handles (FILE_TYPE_CHAR) are not
+  // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+  DWORD handle_type = GetFileType(handle);
+  return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
+}
+
+}
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
+SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
+
+// Initializes static members.
+HWINSTA PolicyBase::alternate_winstation_handle_ = NULL;
+HDESK PolicyBase::alternate_desktop_handle_ = NULL;
+IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
+    INTEGRITY_LEVEL_SYSTEM;
+
+PolicyBase::PolicyBase()
+    : ref_count(1),
+      lockdown_level_(USER_LOCKDOWN),
+      initial_level_(USER_LOCKDOWN),
+      job_level_(JOB_LOCKDOWN),
+      ui_exceptions_(0),
+      memory_limit_(0),
+      use_alternate_desktop_(false),
+      use_alternate_winstation_(false),
+      file_system_init_(false),
+      relaxed_interceptions_(true),
+      stdout_handle_(INVALID_HANDLE_VALUE),
+      stderr_handle_(INVALID_HANDLE_VALUE),
+      integrity_level_(INTEGRITY_LEVEL_LAST),
+      delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
+      mitigations_(0),
+      delayed_mitigations_(0),
+      policy_maker_(NULL),
+      policy_(NULL),
+      lowbox_sid_(NULL) {
+  ::InitializeCriticalSection(&lock_);
+  // Initialize the IPC dispatcher array.
+  memset(&ipc_targets_, NULL, sizeof(ipc_targets_));
+  Dispatcher* dispatcher = NULL;
+
+  dispatcher = new FilesystemDispatcher(this);
+  ipc_targets_[IPC_NTCREATEFILE_TAG] = dispatcher;
+  ipc_targets_[IPC_NTOPENFILE_TAG] = dispatcher;
+  ipc_targets_[IPC_NTSETINFO_RENAME_TAG] = dispatcher;
+  ipc_targets_[IPC_NTQUERYATTRIBUTESFILE_TAG] = dispatcher;
+  ipc_targets_[IPC_NTQUERYFULLATTRIBUTESFILE_TAG] = dispatcher;
+
+  dispatcher = new NamedPipeDispatcher(this);
+  ipc_targets_[IPC_CREATENAMEDPIPEW_TAG] = dispatcher;
+
+  dispatcher = new ThreadProcessDispatcher(this);
+  ipc_targets_[IPC_NTOPENTHREAD_TAG] = dispatcher;
+  ipc_targets_[IPC_NTOPENPROCESS_TAG] = dispatcher;
+  ipc_targets_[IPC_CREATEPROCESSW_TAG] = dispatcher;
+  ipc_targets_[IPC_NTOPENPROCESSTOKEN_TAG] = dispatcher;
+  ipc_targets_[IPC_NTOPENPROCESSTOKENEX_TAG] = dispatcher;
+
+  dispatcher = new SyncDispatcher(this);
+  ipc_targets_[IPC_CREATEEVENT_TAG] = dispatcher;
+  ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
+
+  dispatcher = new RegistryDispatcher(this);
+  ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
+  ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
+
+  dispatcher = new HandleDispatcher(this);
+  ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
+
+  dispatcher = new ProcessMitigationsWin32KDispatcher(this);
+  ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
+  ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
+  ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
+}
+
+PolicyBase::~PolicyBase() {
+  ClearSharedHandles();
+
+  TargetSet::iterator it;
+  for (it = targets_.begin(); it != targets_.end(); ++it) {
+    TargetProcess* target = (*it);
+    delete target;
+  }
+  delete ipc_targets_[IPC_NTCREATEFILE_TAG];
+  delete ipc_targets_[IPC_CREATENAMEDPIPEW_TAG];
+  delete ipc_targets_[IPC_NTOPENTHREAD_TAG];
+  delete ipc_targets_[IPC_CREATEEVENT_TAG];
+  delete ipc_targets_[IPC_NTCREATEKEY_TAG];
+  delete ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG];
+  delete policy_maker_;
+  delete policy_;
+
+  if (lowbox_sid_)
+    ::LocalFree(lowbox_sid_);
+
+  ::DeleteCriticalSection(&lock_);
+}
+
+void PolicyBase::AddRef() {
+  ::InterlockedIncrement(&ref_count);
+}
+
+void PolicyBase::Release() {
+  if (0 == ::InterlockedDecrement(&ref_count))
+    delete this;
+}
+
+ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
+  if (initial < lockdown) {
+    return SBOX_ERROR_BAD_PARAMS;
+  }
+  initial_level_ = initial;
+  lockdown_level_ = lockdown;
+  return SBOX_ALL_OK;
+}
+
+TokenLevel PolicyBase::GetInitialTokenLevel() const {
+  return initial_level_;
+}
+
+TokenLevel PolicyBase::GetLockdownTokenLevel() const{
+  return lockdown_level_;
+}
+
+ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
+  if (memory_limit_ && job_level == JOB_NONE) {
+    return SBOX_ERROR_BAD_PARAMS;
+  }
+  job_level_ = job_level;
+  ui_exceptions_ = ui_exceptions;
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
+  if (memory_limit && job_level_ == JOB_NONE) {
+    return SBOX_ERROR_BAD_PARAMS;
+  }
+  memory_limit_ = memory_limit;
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
+  use_alternate_desktop_ = true;
+  use_alternate_winstation_ = alternate_winstation;
+  return CreateAlternateDesktop(alternate_winstation);
+}
+
+base::string16 PolicyBase::GetAlternateDesktop() const {
+  // No alternate desktop or winstation. Return an empty string.
+  if (!use_alternate_desktop_ && !use_alternate_winstation_) {
+    return base::string16();
+  }
+
+  // The desktop and winstation should have been created by now.
+  // If we hit this scenario, it means that the user ignored the failure
+  // during SetAlternateDesktop, so we ignore it here too.
+  if (use_alternate_desktop_ && !alternate_desktop_handle_) {
+    return base::string16();
+  }
+  if (use_alternate_winstation_ && (!alternate_desktop_handle_ ||
+                                    !alternate_winstation_handle_)) {
+    return base::string16();
+  }
+
+  return GetFullDesktopName(alternate_winstation_handle_,
+                            alternate_desktop_handle_);
+}
+
+ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
+  if (alternate_winstation) {
+    // Previously called with alternate_winstation = false?
+    if (!alternate_winstation_handle_ && alternate_desktop_handle_)
+      return SBOX_ERROR_UNSUPPORTED;
+
+    // Check if it's already created.
+    if (alternate_winstation_handle_ && alternate_desktop_handle_)
+      return SBOX_ALL_OK;
+
+    DCHECK(!alternate_winstation_handle_);
+    // Create the window station.
+    ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
+    if (SBOX_ALL_OK != result)
+      return result;
+
+    // Verify that everything is fine.
+    if (!alternate_winstation_handle_ ||
+        GetWindowObjectName(alternate_winstation_handle_).empty())
+      return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+
+    // Create the destkop.
+    result = CreateAltDesktop(alternate_winstation_handle_,
+                              &alternate_desktop_handle_);
+    if (SBOX_ALL_OK != result)
+      return result;
+
+    // Verify that everything is fine.
+    if (!alternate_desktop_handle_ ||
+        GetWindowObjectName(alternate_desktop_handle_).empty())
+      return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+  } else {
+    // Previously called with alternate_winstation = true?
+    if (alternate_winstation_handle_)
+      return SBOX_ERROR_UNSUPPORTED;
+
+    // Check if it already exists.
+    if (alternate_desktop_handle_)
+      return SBOX_ALL_OK;
+
+    // Create the destkop.
+    ResultCode result = CreateAltDesktop(NULL, &alternate_desktop_handle_);
+    if (SBOX_ALL_OK != result)
+      return result;
+
+    // Verify that everything is fine.
+    if (!alternate_desktop_handle_ ||
+        GetWindowObjectName(alternate_desktop_handle_).empty())
+      return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+  }
+
+  return SBOX_ALL_OK;
+}
+
+void PolicyBase::DestroyAlternateDesktop() {
+  if (alternate_desktop_handle_) {
+    ::CloseDesktop(alternate_desktop_handle_);
+    alternate_desktop_handle_ = NULL;
+  }
+
+  if (alternate_winstation_handle_) {
+    ::CloseWindowStation(alternate_winstation_handle_);
+    alternate_winstation_handle_ = NULL;
+  }
+}
+
+ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
+  integrity_level_ = integrity_level;
+  return SBOX_ALL_OK;
+}
+
+IntegrityLevel PolicyBase::GetIntegrityLevel() const {
+  return integrity_level_;
+}
+
+ResultCode PolicyBase::SetDelayedIntegrityLevel(
+    IntegrityLevel integrity_level) {
+  delayed_integrity_level_ = integrity_level;
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetAppContainer(const wchar_t* sid) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return SBOX_ALL_OK;
+
+  // SetLowBox and SetAppContainer are mutually exclusive.
+  if (lowbox_sid_)
+    return SBOX_ERROR_UNSUPPORTED;
+
+  // Windows refuses to work with an impersonation token for a process inside
+  // an AppContainer. If the caller wants to use a more privileged initial
+  // token, or if the lockdown level will prevent the process from starting,
+  // we have to fail the operation.
+  if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
+    return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
+
+  DCHECK(!appcontainer_list_.get());
+  appcontainer_list_.reset(new AppContainerAttributes);
+  ResultCode rv = appcontainer_list_->SetAppContainer(sid, capabilities_);
+  if (rv != SBOX_ALL_OK)
+    return rv;
+
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetCapability(const wchar_t* sid) {
+  capabilities_.push_back(sid);
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
+  if (base::win::OSInfo::GetInstance()->version() < base::win::VERSION_WIN8)
+    return SBOX_ERROR_UNSUPPORTED;
+
+  // SetLowBox and SetAppContainer are mutually exclusive.
+  if (appcontainer_list_.get())
+    return SBOX_ERROR_UNSUPPORTED;
+
+  DCHECK(sid);
+
+  if (lowbox_sid_)
+    return SBOX_ERROR_BAD_PARAMS;
+
+  if (!ConvertStringSidToSid(sid, &lowbox_sid_))
+    return SBOX_ERROR_GENERIC;
+
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetProcessMitigations(
+    MitigationFlags flags) {
+  if (!CanSetProcessMitigationsPreStartup(flags))
+    return SBOX_ERROR_BAD_PARAMS;
+  mitigations_ = flags;
+  return SBOX_ALL_OK;
+}
+
+MitigationFlags PolicyBase::GetProcessMitigations() {
+  return mitigations_;
+}
+
+ResultCode PolicyBase::SetDelayedProcessMitigations(
+    MitigationFlags flags) {
+  if (!CanSetProcessMitigationsPostStartup(flags))
+    return SBOX_ERROR_BAD_PARAMS;
+  delayed_mitigations_ = flags;
+  return SBOX_ALL_OK;
+}
+
+MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
+  return delayed_mitigations_;
+}
+
+void PolicyBase::SetStrictInterceptions() {
+  relaxed_interceptions_ = false;
+}
+
+ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
+  if (!IsInheritableHandle(handle))
+    return SBOX_ERROR_BAD_PARAMS;
+  stdout_handle_ = handle;
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
+  if (!IsInheritableHandle(handle))
+    return SBOX_ERROR_BAD_PARAMS;
+  stderr_handle_ = handle;
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::AddRule(SubSystem subsystem,
+                               Semantics semantics,
+                               const wchar_t* pattern) {
+  ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
+  LOG_IF(ERROR, result != SBOX_ALL_OK) << "Failed to add sandbox rule."
+                                       << " error = " << result
+                                       << ", subsystem = " << subsystem
+                                       << ", semantics = " << semantics
+                                       << ", pattern = '" << pattern << "'";
+  return result;
+}
+
+ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
+  blacklisted_dlls_.push_back(dll_name);
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::AddKernelObjectToClose(const base::char16* handle_type,
+                                              const base::char16* handle_name) {
+  return handle_closer_.AddHandle(handle_type, handle_name);
+}
+
+void* PolicyBase::AddHandleToShare(HANDLE handle) {
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return NULL;
+
+  if (!handle)
+    return NULL;
+
+  HANDLE duped_handle = NULL;
+  ::DuplicateHandle(::GetCurrentProcess(),
+                    handle,
+                    ::GetCurrentProcess(),
+                    &duped_handle,
+                    0,
+                    TRUE,
+                    DUPLICATE_SAME_ACCESS);
+  DCHECK(duped_handle);
+  handles_to_share_.push_back(duped_handle);
+  return duped_handle;
+}
+
+HandleList PolicyBase::GetHandlesBeingShared() {
+  return handles_to_share_;
+}
+
+void PolicyBase::ClearSharedHandles() {
+  for (auto handle : handles_to_share_) {
+    ::CloseHandle(handle);
+  }
+  handles_to_share_.clear();
+}
+
+// When an IPC is ready in any of the targets we get called. We manage an array
+// of IPC dispatchers which are keyed on the IPC tag so we normally delegate
+// to the appropriate dispatcher unless we can handle the IPC call ourselves.
+Dispatcher* PolicyBase::OnMessageReady(IPCParams* ipc,
+                                       CallbackGeneric* callback) {
+  DCHECK(callback);
+  static const IPCParams ping1 = {IPC_PING1_TAG, UINT32_TYPE};
+  static const IPCParams ping2 = {IPC_PING2_TAG, INOUTPTR_TYPE};
+
+  if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
+    *callback = reinterpret_cast<CallbackGeneric>(
+                    static_cast<Callback1>(&PolicyBase::Ping));
+    return this;
+  }
+
+  Dispatcher* dispatch = GetDispatcher(ipc->ipc_tag);
+  if (!dispatch) {
+    NOTREACHED();
+    return NULL;
+  }
+  return dispatch->OnMessageReady(ipc, callback);
+}
+
+// Delegate to the appropriate dispatcher.
+bool PolicyBase::SetupService(InterceptionManager* manager, int service) {
+  if (IPC_PING1_TAG == service || IPC_PING2_TAG == service)
+    return true;
+
+  Dispatcher* dispatch = GetDispatcher(service);
+  if (!dispatch) {
+    NOTREACHED();
+    return false;
+  }
+  return dispatch->SetupService(manager, service);
+}
+
+ResultCode PolicyBase::MakeJobObject(HANDLE* job) {
+  if (job_level_ != JOB_NONE) {
+    // Create the windows job object.
+    Job job_obj;
+    DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_,
+                                memory_limit_);
+    if (ERROR_SUCCESS != result) {
+      return SBOX_ERROR_GENERIC;
+    }
+    *job = job_obj.Detach();
+  } else {
+    *job = NULL;
+  }
+  return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::MakeTokens(HANDLE* initial, HANDLE* lockdown) {
+  if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer() &&
+      lowbox_sid_) {
+    return SBOX_ERROR_BAD_PARAMS;
+  }
+
+  // Create the 'naked' token. This will be the permanent token associated
+  // with the process and therefore with any thread that is not impersonating.
+  DWORD result = CreateRestrictedToken(lockdown, lockdown_level_,
+                                       integrity_level_, PRIMARY);
+  if (ERROR_SUCCESS != result)
+    return SBOX_ERROR_GENERIC;
+
+  // If we're launching on the alternate desktop we need to make sure the
+  // integrity label on the object is no higher than the sandboxed process's
+  // integrity level. So, we lower the label on the desktop process if it's
+  // not already low enough for our process.
+  if (alternate_desktop_handle_ && use_alternate_desktop_ &&
+      integrity_level_ != INTEGRITY_LEVEL_LAST &&
+      alternate_desktop_integrity_level_label_ < integrity_level_ &&
+      base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_VISTA) {
+    // Integrity label enum is reversed (higher level is a lower value).
+    static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
+                  "Integrity level ordering reversed.");
+    result = SetObjectIntegrityLabel(alternate_desktop_handle_,
+                                     SE_WINDOW_OBJECT,
+                                     L"",
+                                     GetIntegrityLevelString(integrity_level_));
+    if (ERROR_SUCCESS != result)
+      return SBOX_ERROR_GENERIC;
+
+    alternate_desktop_integrity_level_label_ = integrity_level_;
+  }
+
+  // We are maintaining two mutually exclusive approaches. One is to start an
+  // AppContainer process through StartupInfoEx and other is replacing
+  // existing token with LowBox token after process creation.
+  if (appcontainer_list_.get() && appcontainer_list_->HasAppContainer()) {
+    // Windows refuses to work with an impersonation token. See SetAppContainer
+    // implementation for more details.
+    if (lockdown_level_ < USER_LIMITED || lockdown_level_ != initial_level_)
+      return SBOX_ERROR_CANNOT_INIT_APPCONTAINER;
+
+    *initial = INVALID_HANDLE_VALUE;
+    return SBOX_ALL_OK;
+  } else if (lowbox_sid_) {
+    NtCreateLowBoxToken CreateLowBoxToken = NULL;
+    ResolveNTFunctionPtr("NtCreateLowBoxToken", &CreateLowBoxToken);
+    OBJECT_ATTRIBUTES obj_attr;
+    InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
+    HANDLE token_lowbox = NULL;
+    NTSTATUS status = CreateLowBoxToken(&token_lowbox, *lockdown,
+                                        TOKEN_ALL_ACCESS, &obj_attr,
+                                        lowbox_sid_, 0, NULL, 0, NULL);
+    if (!NT_SUCCESS(status))
+      return SBOX_ERROR_GENERIC;
+
+    DCHECK(token_lowbox);
+    ::CloseHandle(*lockdown);
+    *lockdown = token_lowbox;
+  }
+
+  // Create the 'better' token. We use this token as the one that the main
+  // thread uses when booting up the process. It should contain most of
+  // what we need (before reaching main( ))
+  result = CreateRestrictedToken(initial, initial_level_,
+                                 integrity_level_, IMPERSONATION);
+  if (ERROR_SUCCESS != result) {
+    ::CloseHandle(*lockdown);
+    return SBOX_ERROR_GENERIC;
+  }
+  return SBOX_ALL_OK;
+}
+
+const AppContainerAttributes* PolicyBase::GetAppContainer() const {
+  if (!appcontainer_list_.get() || !appcontainer_list_->HasAppContainer())
+    return NULL;
+
+  return appcontainer_list_.get();
+}
+
+const PSID PolicyBase::GetLowBoxSid() const {
+  return lowbox_sid_;
+}
+
+bool PolicyBase::AddTarget(TargetProcess* target) {
+  if (NULL != policy_)
+    policy_maker_->Done();
+
+  if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
+                                                 mitigations_)) {
+    return false;
+  }
+
+  if (!SetupAllInterceptions(target))
+    return false;
+
+  if (!SetupHandleCloser(target))
+    return false;
+
+  // Initialize the sandbox infrastructure for the target.
+  if (ERROR_SUCCESS != target->Init(this, policy_, kIPCMemSize, kPolMemSize))
+    return false;
+
+  g_shared_delayed_integrity_level = delayed_integrity_level_;
+  ResultCode ret = target->TransferVariable(
+                       "g_shared_delayed_integrity_level",
+                       &g_shared_delayed_integrity_level,
+                       sizeof(g_shared_delayed_integrity_level));
+  g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
+  if (SBOX_ALL_OK != ret)
+    return false;
+
+  // Add in delayed mitigations and pseudo-mitigations enforced at startup.
+  g_shared_delayed_mitigations = delayed_mitigations_ |
+      FilterPostStartupProcessMitigations(mitigations_);
+  if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
+    return false;
+
+  ret = target->TransferVariable("g_shared_delayed_mitigations",
+                                 &g_shared_delayed_mitigations,
+                                 sizeof(g_shared_delayed_mitigations));
+  g_shared_delayed_mitigations = 0;
+  if (SBOX_ALL_OK != ret)
+    return false;
+
+  AutoLock lock(&lock_);
+  targets_.push_back(target);
+  return true;
+}
+
+bool PolicyBase::OnJobEmpty(HANDLE job) {
+  AutoLock lock(&lock_);
+  TargetSet::iterator it;
+  for (it = targets_.begin(); it != targets_.end(); ++it) {
+    if ((*it)->Job() == job)
+      break;
+  }
+  if (it == targets_.end()) {
+    return false;
+  }
+  TargetProcess* target = *it;
+  targets_.erase(it);
+  delete target;
+  return true;
+}
+
+EvalResult PolicyBase::EvalPolicy(int service,
+                                  CountedParameterSetBase* params) {
+  if (NULL != policy_) {
+    if (NULL == policy_->entry[service]) {
+      // There is no policy for this particular service. This is not a big
+      // deal.
+      return DENY_ACCESS;
+    }
+    for (int i = 0; i < params->count; i++) {
+      if (!params->parameters[i].IsValid()) {
+        NOTREACHED();
+        return SIGNAL_ALARM;
+      }
+    }
+    PolicyProcessor pol_evaluator(policy_->entry[service]);
+    PolicyResult result =  pol_evaluator.Evaluate(kShortEval,
+                                                  params->parameters,
+                                                  params->count);
+    if (POLICY_MATCH == result) {
+      return pol_evaluator.GetAction();
+    }
+    DCHECK(POLICY_ERROR != result);
+  }
+
+  return DENY_ACCESS;
+}
+
+HANDLE PolicyBase::GetStdoutHandle() {
+  return stdout_handle_;
+}
+
+HANDLE PolicyBase::GetStderrHandle() {
+  return stderr_handle_;
+}
+
+// We service IPC_PING_TAG message which is a way to test a round trip of the
+// IPC subsystem. We receive a integer cookie and we are expected to return the
+// cookie times two (or three) and the current tick count.
+bool PolicyBase::Ping(IPCInfo* ipc, void* arg1) {
+  switch (ipc->ipc_tag) {
+    case IPC_PING1_TAG: {
+      IPCInt ipc_int(arg1);
+      uint32 cookie = ipc_int.As32Bit();
+      ipc->return_info.extended_count = 2;
+      ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
+      ipc->return_info.extended[1].unsigned_int = 2 * cookie;
+      return true;
+    }
+    case IPC_PING2_TAG: {
+      CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
+      if (sizeof(uint32) != io_buffer->Size())
+        return false;
+
+      uint32* cookie = reinterpret_cast<uint32*>(io_buffer->Buffer());
+      *cookie = (*cookie) * 3;
+      return true;
+    }
+    default: return false;
+  }
+}
+
+Dispatcher* PolicyBase::GetDispatcher(int ipc_tag) {
+  if (ipc_tag >= IPC_LAST_TAG || ipc_tag <= IPC_UNUSED_TAG)
+    return NULL;
+
+  return ipc_targets_[ipc_tag];
+}
+
+bool PolicyBase::SetupAllInterceptions(TargetProcess* target) {
+  InterceptionManager manager(target, relaxed_interceptions_);
+
+  if (policy_) {
+    for (int i = 0; i < IPC_LAST_TAG; i++) {
+      if (policy_->entry[i] && !ipc_targets_[i]->SetupService(&manager, i))
+          return false;
+    }
+  }
+
+  if (!blacklisted_dlls_.empty()) {
+    std::vector<base::string16>::iterator it = blacklisted_dlls_.begin();
+    for (; it != blacklisted_dlls_.end(); ++it) {
+      manager.AddToUnloadModules(it->c_str());
+    }
+  }
+
+  if (!SetupBasicInterceptions(&manager))
+    return false;
+
+  if (!manager.InitializeInterceptions())
+    return false;
+
+  // Finally, setup imports on the target so the interceptions can work.
+  return SetupNtdllImports(target);
+}
+
+bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
+  return handle_closer_.InitializeTargetHandles(target);
+}
+
+ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
+                                       Semantics semantics,
+                                       const wchar_t* pattern) {
+  if (NULL == policy_) {
+    policy_ = MakeBrokerPolicyMemory();
+    DCHECK(policy_);
+    policy_maker_ = new LowLevelPolicy(policy_);
+    DCHECK(policy_maker_);
+  }
+
+  switch (subsystem) {
+    case SUBSYS_FILES: {
+      if (!file_system_init_) {
+        if (!FileSystemPolicy::SetInitialRules(policy_maker_))
+          return SBOX_ERROR_BAD_PARAMS;
+        file_system_init_ = true;
+      }
+      if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+    case SUBSYS_SYNC: {
+      if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+    case SUBSYS_PROCESS: {
+      if (lockdown_level_ < USER_INTERACTIVE &&
+          TargetPolicy::PROCESS_ALL_EXEC == semantics) {
+        // This is unsupported. This is a huge security risk to give full access
+        // to a process handle.
+        return SBOX_ERROR_UNSUPPORTED;
+      }
+      if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+    case SUBSYS_NAMED_PIPES: {
+      if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+    case SUBSYS_REGISTRY: {
+      if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+    case SUBSYS_HANDLES: {
+      if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+
+    case SUBSYS_WIN32K_LOCKDOWN: {
+      if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+              pattern, semantics, policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+
+    default: { return SBOX_ERROR_UNSUPPORTED; }
+  }
+
+  return SBOX_ALL_OK;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
new file mode 100644
index 0000000..136e3a4
--- /dev/null
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -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.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
+
+#include <windows.h>
+
+#include <list>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/handle_closer.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+class AppContainerAttributes;
+class LowLevelPolicy;
+class TargetProcess;
+struct PolicyGlobal;
+
+typedef std::vector<HANDLE> HandleList;
+
+// We act as a policy dispatcher, implementing the handler for the "ping" IPC,
+// so we have to provide the appropriate handler on the OnMessageReady method.
+// There is a static_cast for the handler, and the compiler only performs the
+// cast if the first base class is Dispatcher.
+class PolicyBase : public Dispatcher, public TargetPolicy {
+ public:
+  PolicyBase();
+
+  // TargetPolicy:
+  void AddRef() override;
+  void Release() override;
+  ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) override;
+  TokenLevel GetInitialTokenLevel() const override;
+  TokenLevel GetLockdownTokenLevel() const override;
+  ResultCode SetJobLevel(JobLevel job_level, uint32 ui_exceptions) override;
+  ResultCode SetJobMemoryLimit(size_t memory_limit) override;
+  ResultCode SetAlternateDesktop(bool alternate_winstation) override;
+  base::string16 GetAlternateDesktop() const override;
+  ResultCode CreateAlternateDesktop(bool alternate_winstation) override;
+  void DestroyAlternateDesktop() override;
+  ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override;
+  IntegrityLevel GetIntegrityLevel() const override;
+  ResultCode SetDelayedIntegrityLevel(IntegrityLevel integrity_level) override;
+  ResultCode SetAppContainer(const wchar_t* sid) override;
+  ResultCode SetCapability(const wchar_t* sid) override;
+  ResultCode SetLowBox(const wchar_t* sid) override;
+  ResultCode SetProcessMitigations(MitigationFlags flags) override;
+  MitigationFlags GetProcessMitigations() override;
+  ResultCode SetDelayedProcessMitigations(MitigationFlags flags) override;
+  MitigationFlags GetDelayedProcessMitigations() const override;
+  void SetStrictInterceptions() override;
+  ResultCode SetStdoutHandle(HANDLE handle) override;
+  ResultCode SetStderrHandle(HANDLE handle) override;
+  ResultCode AddRule(SubSystem subsystem,
+                     Semantics semantics,
+                     const wchar_t* pattern) override;
+  ResultCode AddDllToUnload(const wchar_t* dll_name) override;
+  ResultCode AddKernelObjectToClose(const base::char16* handle_type,
+                                    const base::char16* handle_name) override;
+  void* AddHandleToShare(HANDLE handle) override;
+
+  // Dispatcher:
+  Dispatcher* OnMessageReady(IPCParams* ipc,
+                             CallbackGeneric* callback) override;
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+  // Creates a Job object with the level specified in a previous call to
+  // SetJobLevel().
+  ResultCode MakeJobObject(HANDLE* job);
+
+  // Creates the two tokens with the levels specified in a previous call to
+  // SetTokenLevel().
+  ResultCode MakeTokens(HANDLE* initial, HANDLE* lockdown);
+
+  const AppContainerAttributes* GetAppContainer() const;
+
+  const PSID GetLowBoxSid() const;
+
+  // Adds a target process to the internal list of targets. Internally a
+  // call to TargetProcess::Init() is issued.
+  bool AddTarget(TargetProcess* target);
+
+  // Called when there are no more active processes in a Job.
+  // Removes a Job object associated with this policy and the target associated
+  // with the job.
+  bool OnJobEmpty(HANDLE job);
+
+  EvalResult EvalPolicy(int service, CountedParameterSetBase* params);
+
+  HANDLE GetStdoutHandle();
+  HANDLE GetStderrHandle();
+
+  // Returns the list of handles being shared with the target process.
+  HandleList GetHandlesBeingShared();
+
+  // Closes the handles being shared with the target and clears out the list.
+  void ClearSharedHandles();
+
+ private:
+  ~PolicyBase() override;
+
+  // Test IPC providers.
+  bool Ping(IPCInfo* ipc, void* cookie);
+
+  // Returns a dispatcher from ipc_targets_.
+  Dispatcher* GetDispatcher(int ipc_tag);
+
+  // Sets up interceptions for a new target.
+  bool SetupAllInterceptions(TargetProcess* target);
+
+  // Sets up the handle closer for a new target.
+  bool SetupHandleCloser(TargetProcess* target);
+
+  ResultCode AddRuleInternal(SubSystem subsystem,
+                             Semantics semantics,
+                             const wchar_t* pattern);
+
+  // This lock synchronizes operations on the targets_ collection.
+  CRITICAL_SECTION lock_;
+  // Maintains the list of target process associated with this policy.
+  // The policy takes ownership of them.
+  typedef std::list<TargetProcess*> TargetSet;
+  TargetSet targets_;
+  // Standard object-lifetime reference counter.
+  volatile LONG ref_count;
+  // The user-defined global policy settings.
+  TokenLevel lockdown_level_;
+  TokenLevel initial_level_;
+  JobLevel job_level_;
+  uint32 ui_exceptions_;
+  size_t memory_limit_;
+  bool use_alternate_desktop_;
+  bool use_alternate_winstation_;
+  // Helps the file system policy initialization.
+  bool file_system_init_;
+  bool relaxed_interceptions_;
+  HANDLE stdout_handle_;
+  HANDLE stderr_handle_;
+  IntegrityLevel integrity_level_;
+  IntegrityLevel delayed_integrity_level_;
+  MitigationFlags mitigations_;
+  MitigationFlags delayed_mitigations_;
+  // The array of objects that will answer IPC calls.
+  Dispatcher* ipc_targets_[IPC_LAST_TAG];
+  // Object in charge of generating the low level policy.
+  LowLevelPolicy* policy_maker_;
+  // Memory structure that stores the low level policy.
+  PolicyGlobal* policy_;
+  // The list of dlls to unload in the target process.
+  std::vector<base::string16> blacklisted_dlls_;
+  // This is a map of handle-types to names that we need to close in the
+  // target process. A null set means we need to close all handles of the
+  // given type.
+  HandleCloser handle_closer_;
+  std::vector<base::string16> capabilities_;
+  scoped_ptr<AppContainerAttributes> appcontainer_list_;
+  PSID lowbox_sid_;
+
+  static HDESK alternate_desktop_handle_;
+  static HWINSTA alternate_winstation_handle_;
+  static IntegrityLevel alternate_desktop_integrity_level_label_;
+
+  // Contains the list of handles being shared with the target process.
+  // This list contains handles other than the stderr/stdout handles which are
+  // shared with the target at times.
+  std::vector<HANDLE> handles_to_share_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyBase);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h
new file mode 100644
index 0000000..3e531be
--- /dev/null
+++ b/sandbox/win/src/sandbox_types.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
+#define SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
+
+namespace sandbox {
+
+// Operation result codes returned by the sandbox API.
+enum ResultCode {
+  SBOX_ALL_OK = 0,
+  // Error is originating on the win32 layer. Call GetlastError() for more
+  // information.
+  SBOX_ERROR_GENERIC = 1,
+  // An invalid combination of parameters was given to the API.
+  SBOX_ERROR_BAD_PARAMS = 2,
+  // The desired operation is not supported at this time.
+  SBOX_ERROR_UNSUPPORTED = 3,
+  // The request requires more memory that allocated or available.
+  SBOX_ERROR_NO_SPACE = 4,
+  // The ipc service requested does not exist.
+  SBOX_ERROR_INVALID_IPC = 5,
+  // The ipc service did not complete.
+  SBOX_ERROR_FAILED_IPC = 6,
+  // The requested handle was not found.
+  SBOX_ERROR_NO_HANDLE = 7,
+  // This function was not expected to be called at this time.
+  SBOX_ERROR_UNEXPECTED_CALL = 8,
+  // WaitForAllTargets is already called.
+  SBOX_ERROR_WAIT_ALREADY_CALLED = 9,
+  // A channel error prevented DoCall from executing.
+  SBOX_ERROR_CHANNEL_ERROR = 10,
+  // Failed to create the alternate desktop.
+  SBOX_ERROR_CANNOT_CREATE_DESKTOP = 11,
+  // Failed to create the alternate window station.
+  SBOX_ERROR_CANNOT_CREATE_WINSTATION = 12,
+  // Failed to switch back to the interactive window station.
+  SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION = 13,
+  // The supplied AppContainer is not valid.
+  SBOX_ERROR_INVALID_APP_CONTAINER = 14,
+  // The supplied capability is not valid.
+  SBOX_ERROR_INVALID_CAPABILITY = 15,
+  // There is a failure initializing the AppContainer.
+  SBOX_ERROR_CANNOT_INIT_APPCONTAINER = 16,
+  // Initializing or updating ProcThreadAttributes failed.
+  SBOX_ERROR_PROC_THREAD_ATTRIBUTES = 17,
+  // Error in creating process.
+  SBOX_ERROR_CREATE_PROCESS = 18,
+  // Placeholder for last item of the enum.
+  SBOX_ERROR_LAST
+};
+
+// If the sandbox cannot create a secure environment for the target, the
+// target will be forcibly terminated. These are the process exit codes.
+enum TerminationCodes {
+  SBOX_FATAL_INTEGRITY = 7006,       // Could not set the integrity level.
+  SBOX_FATAL_DROPTOKEN = 7007,       // Could not lower the token.
+  SBOX_FATAL_FLUSHANDLES = 7008,     // Failed to flush registry handles.
+  SBOX_FATAL_CACHEDISABLE = 7009,    // Failed to forbid HCKU caching.
+  SBOX_FATAL_CLOSEHANDLES = 7010,    // Failed to close pending handles.
+  SBOX_FATAL_MITIGATION = 7011,      // Could not set the mitigation policy.
+  SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit.
+  SBOX_FATAL_LAST
+};
+
+class BrokerServices;
+class TargetServices;
+
+// Contains the pointer to a target or broker service.
+struct SandboxInterfaceInfo {
+  BrokerServices* broker_services;
+  TargetServices* target_services;
+};
+
+#if SANDBOX_EXPORTS
+#define SANDBOX_INTERCEPT extern "C" __declspec(dllexport)
+#else
+#define SANDBOX_INTERCEPT extern "C"
+#endif
+
+enum InterceptionType {
+  INTERCEPTION_INVALID = 0,
+  INTERCEPTION_SERVICE_CALL,    // Trampoline of an NT native call
+  INTERCEPTION_EAT,
+  INTERCEPTION_SIDESTEP,        // Preamble patch
+  INTERCEPTION_SMART_SIDESTEP,  // Preamble patch but bypass internal calls
+  INTERCEPTION_UNLOAD_MODULE,   // Unload the module (don't patch)
+  INTERCEPTION_LAST             // Placeholder for last item in the enumeration
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
diff --git a/sandbox/win/src/sandbox_utils.cc b/sandbox/win/src/sandbox_utils.cc
new file mode 100644
index 0000000..6057caf
--- /dev/null
+++ b/sandbox/win/src/sandbox_utils.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_utils.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "sandbox/win/src/internal_types.h"
+
+namespace sandbox {
+
+void InitObjectAttribs(const base::string16& name,
+                       ULONG attributes,
+                       HANDLE root,
+                       OBJECT_ATTRIBUTES* obj_attr,
+                       UNICODE_STRING* uni_name,
+                       SECURITY_QUALITY_OF_SERVICE* security_qos) {
+  static RtlInitUnicodeStringFunction RtlInitUnicodeString;
+  if (!RtlInitUnicodeString) {
+    HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+    RtlInitUnicodeString = reinterpret_cast<RtlInitUnicodeStringFunction>(
+        GetProcAddress(ntdll, "RtlInitUnicodeString"));
+    DCHECK(RtlInitUnicodeString);
+  }
+  RtlInitUnicodeString(uni_name, name.c_str());
+  InitializeObjectAttributes(obj_attr, uni_name, attributes, root, NULL);
+  obj_attr->SecurityQualityOfService = security_qos;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sandbox_utils.h b/sandbox/win/src/sandbox_utils.h
new file mode 100644
index 0000000..fc3100d
--- /dev/null
+++ b/sandbox/win/src/sandbox_utils.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_UTILS_H_
+#define SANDBOX_SRC_SANDBOX_UTILS_H_
+
+#include <windows.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+void InitObjectAttribs(const base::string16& name,
+                       ULONG attributes,
+                       HANDLE root,
+                       OBJECT_ATTRIBUTES* obj_attr,
+                       UNICODE_STRING* uni_name,
+                       SECURITY_QUALITY_OF_SERVICE* security_qos);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SANDBOX_UTILS_H_
diff --git a/sandbox/win/src/security_level.h b/sandbox/win/src/security_level.h
new file mode 100644
index 0000000..c89bbb4
--- /dev/null
+++ b/sandbox/win/src/security_level.h
@@ -0,0 +1,209 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SECURITY_LEVEL_H_
+#define SANDBOX_SRC_SECURITY_LEVEL_H_
+
+#include "base/basictypes.h"
+
+namespace sandbox {
+
+// List of all the integrity levels supported in the sandbox. This is used
+// only on Windows Vista. You can't set the integrity level of the process
+// in the sandbox to a level higher than yours.
+enum IntegrityLevel {
+  INTEGRITY_LEVEL_SYSTEM,
+  INTEGRITY_LEVEL_HIGH,
+  INTEGRITY_LEVEL_MEDIUM,
+  INTEGRITY_LEVEL_MEDIUM_LOW,
+  INTEGRITY_LEVEL_LOW,
+  INTEGRITY_LEVEL_BELOW_LOW,
+  INTEGRITY_LEVEL_UNTRUSTED,
+  INTEGRITY_LEVEL_LAST
+};
+
+// The Token level specifies a set of  security profiles designed to
+// provide the bulk of the security of sandbox.
+//
+//  TokenLevel                 |Restricting   |Deny Only       |Privileges|
+//                             |Sids          |Sids            |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_LOCKDOWN               | Null Sid     | All            | None     |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED             | RESTRICTED   | All            | Traverse |
+// ----------------------------|--------------|----------------|----------|
+// USER_LIMITED                | Users        | All except:    | Traverse |
+//                             | Everyone     | Users          |          |
+//                             | RESTRICTED   | Everyone       |          |
+//                             |              | Interactive    |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_INTERACTIVE            | Users        | All except:    | Traverse |
+//                             | Everyone     | Users          |          |
+//                             | RESTRICTED   | Everyone       |          |
+//                             | Owner        | Interactive    |          |
+//                             |              | Local          |          |
+//                             |              | Authent-users  |          |
+//                             |              | User           |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_NON_ADMIN              | None         | All except:    | Traverse |
+//                             |              | Users          |          |
+//                             |              | Everyone       |          |
+//                             |              | Interactive    |          |
+//                             |              | Local          |          |
+//                             |              | Authent-users  |          |
+//                             |              | User           |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED_SAME_ACCESS | All          | None           | All      |
+// ----------------------------|--------------|----------------|----------|
+// USER_UNPROTECTED            | None         | None           | All      |
+// ----------------------------|--------------|----------------|----------|
+//
+// The above restrictions are actually a transformation that is applied to
+// the existing broker process token. The resulting token that will be
+// applied to the target process depends both on the token level selected
+// and on the broker token itself.
+//
+//  The LOCKDOWN and RESTRICTED are designed to allow access to almost
+//  nothing that has security associated with and they are the recommended
+//  levels to run sandboxed code specially if there is a chance that the
+//  broker is process might be started by a user that belongs to the Admins
+//  or power users groups.
+enum TokenLevel {
+   USER_LOCKDOWN = 0,
+   USER_RESTRICTED,
+   USER_LIMITED,
+   USER_INTERACTIVE,
+   USER_NON_ADMIN,
+   USER_RESTRICTED_SAME_ACCESS,
+   USER_UNPROTECTED,
+   USER_LAST
+};
+
+// The Job level specifies a set of decreasing security profiles for the
+// Job object that the target process will be placed into.
+// This table summarizes the security associated with each level:
+//
+//  JobLevel        |General                            |Quota               |
+//                  |restrictions                       |restrictions        |
+// -----------------|---------------------------------- |--------------------|
+// JOB_NONE         | No job is assigned to the         | None               |
+//                  | sandboxed process.                |                    |
+// -----------------|---------------------------------- |--------------------|
+// JOB_UNPROTECTED  | None                              | *Kill on Job close.|
+// -----------------|---------------------------------- |--------------------|
+// JOB_INTERACTIVE  | *Forbid system-wide changes using |                    |
+//                  |  SystemParametersInfo().          | *Kill on Job close.|
+//                  | *Forbid the creation/switch of    |                    |
+//                  |  Desktops.                        |                    |
+//                  | *Forbids calls to ExitWindows().  |                    |
+// -----------------|---------------------------------- |--------------------|
+// JOB_LIMITED_USER | Same as INTERACTIVE_USER plus:    | *One active process|
+//                  | *Forbid changes to the display    |  limit.            |
+//                  |  settings.                        | *Kill on Job close.|
+// -----------------|---------------------------------- |--------------------|
+// JOB_RESTRICTED   | Same as LIMITED_USER plus:        | *One active process|
+//                  | * No read/write to the clipboard. |  limit.            |
+//                  | * No access to User Handles that  | *Kill on Job close.|
+//                  |   belong to other processes.      |                    |
+//                  | * Forbid message broadcasts.      |                    |
+//                  | * Forbid setting global hooks.    |                    |
+//                  | * No access to the global atoms   |                    |
+//                  |   table.                          |                    |
+// -----------------|-----------------------------------|--------------------|
+// JOB_LOCKDOWN     | Same as RESTRICTED                | *One active process|
+//                  |                                   |  limit.            |
+//                  |                                   | *Kill on Job close.|
+//                  |                                   | *Kill on unhandled |
+//                  |                                   |  exception.        |
+//                  |                                   |                    |
+// In the context of the above table, 'user handles' refers to the handles of
+// windows, bitmaps, menus, etc. Files, treads and registry handles are kernel
+// handles and are not affected by the job level settings.
+enum JobLevel {
+  JOB_LOCKDOWN = 0,
+  JOB_RESTRICTED,
+  JOB_LIMITED_USER,
+  JOB_INTERACTIVE,
+  JOB_UNPROTECTED,
+  JOB_NONE
+};
+
+// These flags correspond to various process-level mitigations (eg. ASLR and
+// DEP). Most are implemented via UpdateProcThreadAttribute() plus flags for
+// the PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY attribute argument; documented
+// here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686880
+// Some mitigations are implemented directly by the sandbox or emulated to
+// the greatest extent possible when not directly supported by the OS.
+// Flags that are unsupported for the target OS will be silently ignored.
+// Flags that are invalid for their application (pre or post startup) will
+// return SBOX_ERROR_BAD_PARAMS.
+typedef uint64 MitigationFlags;
+
+// Permanently enables DEP for the target process. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE.
+const MitigationFlags MITIGATION_DEP                              = 0x00000001;
+
+// Permanently Disables ATL thunk emulation when DEP is enabled. Valid
+// only when MITIGATION_DEP is passed. Corresponds to not passing
+// PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE.
+const MitigationFlags MITIGATION_DEP_NO_ATL_THUNK                 = 0x00000002;
+
+// Enables Structured exception handling override prevention. Must be
+// enabled prior to process start. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE.
+const MitigationFlags MITIGATION_SEHOP                            = 0x00000004;
+
+// Forces ASLR on all images in the child process. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON .
+const MitigationFlags MITIGATION_RELOCATE_IMAGE                   = 0x00000008;
+
+// Refuses to load DLLs that cannot support ASLR. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS.
+const MitigationFlags MITIGATION_RELOCATE_IMAGE_REQUIRED          = 0x00000010;
+
+// Terminates the process on Windows heap corruption. Coresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON.
+const MitigationFlags MITIGATION_HEAP_TERMINATE                   = 0x00000020;
+
+// Sets a random lower bound as the minimum user address. Must be
+// enabled prior to process start. On 32-bit processes this is
+// emulated to a much smaller degree. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON.
+const MitigationFlags MITIGATION_BOTTOM_UP_ASLR                   = 0x00000040;
+
+// Increases the randomness range of bottom-up ASLR to up to 1TB. Must be
+// enabled prior to process start and with MITIGATION_BOTTOM_UP_ASLR.
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON
+const MitigationFlags MITIGATION_HIGH_ENTROPY_ASLR                = 0x00000080;
+
+// Immediately raises an exception on a bad handle reference. Must be
+// enabled after startup. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON.
+const MitigationFlags MITIGATION_STRICT_HANDLE_CHECKS             = 0x00000100;
+
+// Prevents the process from making Win32k calls. Must be enabled after
+// startup. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON.
+const MitigationFlags MITIGATION_WIN32K_DISABLE                   = 0x00000200;
+
+// Disables common DLL injection methods (e.g. window hooks and
+// App_InitDLLs). Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON.
+const MitigationFlags MITIGATION_EXTENSION_DLL_DISABLE            = 0x00000400;
+
+// Sets the DLL search order to LOAD_LIBRARY_SEARCH_DEFAULT_DIRS. Additional
+// directories can be added via the Windows AddDllDirectory() function.
+// http://msdn.microsoft.com/en-us/library/windows/desktop/hh310515
+// Must be enabled after startup.
+const MitigationFlags MITIGATION_DLL_SEARCH_ORDER        = 0x00000001ULL << 32;
+
+// Changes the mandatory integrity level policy on the current process' token
+// to enable no-read and no-execute up. This prevents a lower IL process from
+// opening the process token for impersonate/duplicate/assignment.
+const MitigationFlags MITIGATION_HARDEN_TOKEN_IL_POLICY  = 0x00000001ULL << 33;
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SECURITY_LEVEL_H_
diff --git a/sandbox/win/src/service_resolver.cc b/sandbox/win/src/service_resolver.cc
new file mode 100644
index 0000000..92f21a7
--- /dev/null
+++ b/sandbox/win/src/service_resolver.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+NTSTATUS ServiceResolverThunk::ResolveInterceptor(
+    const void* interceptor_module,
+    const char* interceptor_name,
+    const void** address) {
+  // After all, we are using a locally mapped version of the exe, so the
+  // action is the same as for a target function.
+  return ResolveTarget(interceptor_module, interceptor_name,
+                       const_cast<void**>(address));
+}
+
+// In this case all the work is done from the parent, so resolve is
+// just a simple GetProcAddress.
+NTSTATUS ServiceResolverThunk::ResolveTarget(const void* module,
+                                             const char* function_name,
+                                             void** address) {
+  if (NULL == module)
+    return STATUS_UNSUCCESSFUL;
+
+  base::win::PEImage module_image(module);
+  *address = module_image.GetProcAddress(function_name);
+
+  if (NULL == *address) {
+    NOTREACHED_NT();
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  return STATUS_SUCCESS;
+}
+
+void ServiceResolverThunk::AllowLocalPatches() {
+  ntdll_base_ = ::GetModuleHandle(kNtdllName);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/service_resolver.h b/sandbox/win/src/service_resolver.h
new file mode 100644
index 0000000..ab125fb
--- /dev/null
+++ b/sandbox/win/src/service_resolver.h
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SERVICE_RESOLVER_H__
+#define SANDBOX_SRC_SERVICE_RESOLVER_H__
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/resolver.h"
+
+namespace sandbox {
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll.
+class ServiceResolverThunk : public ResolverThunk {
+ public:
+  // The service resolver needs a child process to write to.
+  ServiceResolverThunk(HANDLE process, bool relaxed)
+      : process_(process), ntdll_base_(NULL),
+        relaxed_(relaxed), relative_jump_(0) {}
+  ~ServiceResolverThunk() override {}
+
+  // Implementation of Resolver::Setup.
+  NTSTATUS Setup(const void* target_module,
+                 const void* interceptor_module,
+                 const char* target_name,
+                 const char* interceptor_name,
+                 const void* interceptor_entry_point,
+                 void* thunk_storage,
+                 size_t storage_bytes,
+                 size_t* storage_used) override;
+
+  // Implementation of Resolver::ResolveInterceptor.
+  NTSTATUS ResolveInterceptor(const void* module,
+                              const char* function_name,
+                              const void** address) override;
+
+  // Implementation of Resolver::ResolveTarget.
+  NTSTATUS ResolveTarget(const void* module,
+                         const char* function_name,
+                         void** address) override;
+
+  // Implementation of Resolver::GetThunkSize.
+  size_t GetThunkSize() const override;
+
+  // Call this to set up ntdll_base_ which will allow for local patches.
+  virtual void AllowLocalPatches();
+
+  // Verifies that the function specified by |target_name| in |target_module| is
+  // a service and copies the data from that function into |thunk_storage|. If
+  // |storage_bytes| is too small, then the method fails.
+  virtual NTSTATUS CopyThunk(const void* target_module,
+                             const char* target_name,
+                             BYTE* thunk_storage,
+                             size_t storage_bytes,
+                             size_t* storage_used);
+
+ protected:
+  // The unit test will use this member to allow local patch on a buffer.
+  HMODULE ntdll_base_;
+
+  // Handle of the child process.
+  HANDLE process_;
+
+ private:
+  // Returns true if the code pointer by target_ corresponds to the expected
+  // type of function. Saves that code on the first part of the thunk pointed
+  // by local_thunk (should be directly accessible from the parent).
+  virtual bool IsFunctionAService(void* local_thunk) const;
+
+  // Performs the actual patch of target_.
+  // local_thunk must be already fully initialized, and the first part must
+  // contain the original code. The real type of this buffer is ServiceFullThunk
+  // (yes, private). remote_thunk (real type ServiceFullThunk), must be
+  // allocated on the child, and will contain the thunk data, after this call.
+  // Returns the apropriate status code.
+  virtual NTSTATUS PerformPatch(void* local_thunk, void* remote_thunk);
+
+  // Provides basically the same functionality as IsFunctionAService but it
+  // continues even if it does not recognize the function code. remote_thunk
+  // is the address of our memory on the child.
+  bool SaveOriginalFunction(void* local_thunk, void* remote_thunk);
+
+  // true if we are allowed to patch already-patched functions.
+  bool relaxed_;
+  ULONG relative_jump_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on WOW64 (32 bit ntdll on 64 bit Vista).
+class Wow64ResolverThunk : public ServiceResolverThunk {
+ public:
+  // The service resolver needs a child process to write to.
+  Wow64ResolverThunk(HANDLE process, bool relaxed)
+      : ServiceResolverThunk(process, relaxed) {}
+  ~Wow64ResolverThunk() override {}
+
+ private:
+  bool IsFunctionAService(void* local_thunk) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(Wow64ResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on WOW64 for Windows 8.
+class Wow64W8ResolverThunk : public ServiceResolverThunk {
+ public:
+  // The service resolver needs a child process to write to.
+  Wow64W8ResolverThunk(HANDLE process, bool relaxed)
+      : ServiceResolverThunk(process, relaxed) {}
+  ~Wow64W8ResolverThunk() override {}
+
+ private:
+  bool IsFunctionAService(void* local_thunk) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(Wow64W8ResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on Windows 8.
+class Win8ResolverThunk : public ServiceResolverThunk {
+ public:
+  // The service resolver needs a child process to write to.
+  Win8ResolverThunk(HANDLE process, bool relaxed)
+      : ServiceResolverThunk(process, relaxed) {}
+  ~Win8ResolverThunk() override {}
+
+ private:
+  bool IsFunctionAService(void* local_thunk) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(Win8ResolverThunk);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_SERVICE_RESOLVER_H__
diff --git a/sandbox/win/src/service_resolver_32.cc b/sandbox/win/src/service_resolver_32.cc
new file mode 100644
index 0000000..ab69ab8
--- /dev/null
+++ b/sandbox/win/src/service_resolver_32.cc
@@ -0,0 +1,427 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+#pragma pack(push, 1)
+
+const BYTE kMovEax = 0xB8;
+const BYTE kMovEdx = 0xBA;
+const USHORT kMovEdxEsp = 0xD48B;
+const USHORT kCallPtrEdx = 0x12FF;
+const USHORT kCallEdx = 0xD2FF;
+const BYTE kCallEip = 0xE8;
+const BYTE kRet = 0xC2;
+const BYTE kRet2 = 0xC3;
+const BYTE kNop = 0x90;
+const USHORT kJmpEdx = 0xE2FF;
+const USHORT kXorEcx = 0xC933;
+const ULONG kLeaEdx = 0x0424548D;
+const ULONG kCallFs1 = 0xC015FF64;
+const USHORT kCallFs2 = 0;
+const BYTE kCallFs3 = 0;
+const BYTE kAddEsp1 = 0x83;
+const USHORT kAddEsp2 = 0x4C4;
+const BYTE kJmp32 = 0xE9;
+const USHORT kSysenter = 0x340F;
+
+const int kMaxService = 1000;
+
+// Service code for 32 bit systems.
+// NOTE: on win2003 "call dword ptr [edx]" is "call edx".
+struct ServiceEntry {
+  // This struct contains roughly the following code:
+  // 00 mov     eax,25h
+  // 05 mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
+  // 0a call    dword ptr [edx]
+  // 0c ret     2Ch
+  // 0f nop
+  BYTE mov_eax;         // = B8
+  ULONG service_id;
+  BYTE mov_edx;         // = BA
+  ULONG stub;
+  USHORT call_ptr_edx;  // = FF 12
+  BYTE ret;             // = C2
+  USHORT num_params;
+  BYTE nop;
+};
+
+// Service code for 32 bit Windows 8.
+struct ServiceEntryW8 {
+  // This struct contains the following code:
+  // 00 b825000000      mov     eax,25h
+  // 05 e803000000      call    eip+3
+  // 0a c22c00          ret     2Ch
+  // 0d 8bd4            mov     edx,esp
+  // 0f 0f34            sysenter
+  // 11 c3              ret
+  // 12 8bff            mov     edi,edi
+  BYTE mov_eax;         // = B8
+  ULONG service_id;
+  BYTE call_eip;        // = E8
+  ULONG call_offset;
+  BYTE ret_p;           // = C2
+  USHORT num_params;
+  USHORT mov_edx_esp;   // = BD D4
+  USHORT sysenter;      // = 0F 34
+  BYTE ret;             // = C3
+  USHORT nop;
+};
+
+// Service code for a 32 bit process running on a 64 bit os.
+struct Wow64Entry {
+  // This struct may contain one of two versions of code:
+  // 1. For XP, Vista and 2K3:
+  // 00 b825000000      mov     eax, 25h
+  // 05 33c9            xor     ecx, ecx
+  // 07 8d542404        lea     edx, [esp + 4]
+  // 0b 64ff15c0000000  call    dword ptr fs:[0C0h]
+  // 12 c22c00          ret     2Ch
+  //
+  // 2. For Windows 7:
+  // 00 b825000000      mov     eax, 25h
+  // 05 33c9            xor     ecx, ecx
+  // 07 8d542404        lea     edx, [esp + 4]
+  // 0b 64ff15c0000000  call    dword ptr fs:[0C0h]
+  // 12 83c404          add     esp, 4
+  // 15 c22c00          ret     2Ch
+  //
+  // So we base the structure on the bigger one:
+  BYTE mov_eax;         // = B8
+  ULONG service_id;
+  USHORT xor_ecx;       // = 33 C9
+  ULONG lea_edx;        // = 8D 54 24 04
+  ULONG call_fs1;       // = 64 FF 15 C0
+  USHORT call_fs2;      // = 00 00
+  BYTE call_fs3;        // = 00
+  BYTE add_esp1;        // = 83             or ret
+  USHORT add_esp2;      // = C4 04          or num_params
+  BYTE ret;             // = C2
+  USHORT num_params;
+};
+
+// Service code for a 32 bit process running on 64 bit Windows 8.
+struct Wow64EntryW8 {
+  // 00 b825000000      mov     eax, 25h
+  // 05 64ff15c0000000  call    dword ptr fs:[0C0h]
+  // 0b c22c00          ret     2Ch
+  // 0f 90              nop
+  BYTE mov_eax;         // = B8
+  ULONG service_id;
+  ULONG call_fs1;       // = 64 FF 15 C0
+  USHORT call_fs2;      // = 00 00
+  BYTE call_fs3;        // = 00
+  BYTE ret;             // = C2
+  USHORT num_params;
+  BYTE nop;
+};
+
+// Make sure that relaxed patching works as expected.
+const size_t kMinServiceSize = offsetof(ServiceEntry, ret);
+static_assert(sizeof(ServiceEntryW8) >= kMinServiceSize,
+              "wrong service length");
+static_assert(sizeof(Wow64Entry) >= kMinServiceSize, "wrong service length");
+static_assert(sizeof(Wow64EntryW8) >= kMinServiceSize, "wrong service length");
+
+struct ServiceFullThunk {
+  union {
+    ServiceEntry original;
+    ServiceEntryW8 original_w8;
+    Wow64Entry wow_64;
+    Wow64EntryW8 wow_64_w8;
+  };
+  int internal_thunk;  // Dummy member to the beginning of the internal thunk.
+};
+
+#pragma pack(pop)
+
+};  // namespace
+
+namespace sandbox {
+
+NTSTATUS ServiceResolverThunk::Setup(const void* target_module,
+                                     const void* interceptor_module,
+                                     const char* target_name,
+                                     const char* interceptor_name,
+                                     const void* interceptor_entry_point,
+                                     void* thunk_storage,
+                                     size_t storage_bytes,
+                                     size_t* storage_used) {
+  NTSTATUS ret = Init(target_module, interceptor_module, target_name,
+                      interceptor_name, interceptor_entry_point,
+                      thunk_storage, storage_bytes);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  relative_jump_ = 0;
+  size_t thunk_bytes = GetThunkSize();
+  scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
+  ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
+                                thunk_buffer.get());
+
+  if (!IsFunctionAService(&thunk->original) &&
+      (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage)))
+    return STATUS_UNSUCCESSFUL;
+
+  ret = PerformPatch(thunk, thunk_storage);
+
+  if (NULL != storage_used)
+    *storage_used = thunk_bytes;
+
+  return ret;
+}
+
+size_t ServiceResolverThunk::GetThunkSize() const {
+  return offsetof(ServiceFullThunk, internal_thunk) + GetInternalThunkSize();
+}
+
+NTSTATUS ServiceResolverThunk::CopyThunk(const void* target_module,
+                                         const char* target_name,
+                                         BYTE* thunk_storage,
+                                         size_t storage_bytes,
+                                         size_t* storage_used) {
+  NTSTATUS ret = ResolveTarget(target_module, target_name, &target_);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  size_t thunk_bytes = GetThunkSize();
+  if (storage_bytes < thunk_bytes)
+    return STATUS_UNSUCCESSFUL;
+
+  ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(thunk_storage);
+
+  if (!IsFunctionAService(&thunk->original) &&
+      (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage))) {
+    return STATUS_UNSUCCESSFUL;
+  }
+
+  if (NULL != storage_used)
+    *storage_used = thunk_bytes;
+
+  return ret;
+}
+
+bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const {
+  ServiceEntry function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (kMovEax != function_code.mov_eax ||
+      kMovEdx != function_code.mov_edx ||
+      (kCallPtrEdx != function_code.call_ptr_edx &&
+       kCallEdx != function_code.call_ptr_edx) ||
+      kRet != function_code.ret)
+    return false;
+
+  // Find the system call pointer if we don't already have it.
+  if (kCallEdx != function_code.call_ptr_edx) {
+    DWORD ki_system_call;
+    if (!::ReadProcessMemory(process_,
+                             bit_cast<const void*>(function_code.stub),
+                             &ki_system_call, sizeof(ki_system_call), &read))
+      return false;
+
+    if (sizeof(ki_system_call) != read)
+      return false;
+
+    HMODULE module_1, module_2;
+    // last check, call_stub should point to a KiXXSystemCall function on ntdll
+    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                               GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                           bit_cast<const wchar_t*>(ki_system_call), &module_1))
+      return false;
+
+    if (NULL != ntdll_base_) {
+      // This path is only taken when running the unit tests. We want to be
+      // able to patch a buffer in memory, so target_ is not inside ntdll.
+      module_2 = ntdll_base_;
+    } else {
+      if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                                 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                             reinterpret_cast<const wchar_t*>(target_),
+                             &module_2))
+        return false;
+    }
+
+    if (module_1 != module_2)
+      return false;
+  }
+
+  // Save the verified code
+  memcpy(local_thunk, &function_code, sizeof(function_code));
+
+  return true;
+}
+
+NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk,
+                                            void* remote_thunk) {
+  ServiceEntry intercepted_code;
+  size_t bytes_to_write = sizeof(intercepted_code);
+  ServiceFullThunk *full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
+      local_thunk);
+  ServiceFullThunk *full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
+      remote_thunk);
+
+  // patch the original code
+  memcpy(&intercepted_code, &full_local_thunk->original,
+         sizeof(intercepted_code));
+  intercepted_code.mov_eax = kMovEax;
+  intercepted_code.service_id = full_local_thunk->original.service_id;
+  intercepted_code.mov_edx = kMovEdx;
+  intercepted_code.stub = bit_cast<ULONG>(&full_remote_thunk->internal_thunk);
+  intercepted_code.call_ptr_edx = kJmpEdx;
+  bytes_to_write = kMinServiceSize;
+
+  if (relative_jump_) {
+    intercepted_code.mov_eax = kJmp32;
+    intercepted_code.service_id = relative_jump_;
+    bytes_to_write = offsetof(ServiceEntry, mov_edx);
+  }
+
+  // setup the thunk
+  SetInternalThunk(&full_local_thunk->internal_thunk, GetInternalThunkSize(),
+                   remote_thunk, interceptor_);
+
+  size_t thunk_size = GetThunkSize();
+
+  // copy the local thunk buffer to the child
+  SIZE_T written;
+  if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
+                            thunk_size, &written))
+    return STATUS_UNSUCCESSFUL;
+
+  if (thunk_size != written)
+    return STATUS_UNSUCCESSFUL;
+
+  // and now change the function to intercept, on the child
+  if (NULL != ntdll_base_) {
+    // running a unit test
+    if (!::WriteProcessMemory(process_, target_, &intercepted_code,
+                              bytes_to_write, &written))
+      return STATUS_UNSUCCESSFUL;
+  } else {
+    if (!WriteProtectedChildMemory(process_, target_, &intercepted_code,
+                                   bytes_to_write))
+      return STATUS_UNSUCCESSFUL;
+  }
+
+  return STATUS_SUCCESS;
+}
+
+bool ServiceResolverThunk::SaveOriginalFunction(void* local_thunk,
+                                                void* remote_thunk) {
+  ServiceEntry function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (kJmp32 == function_code.mov_eax) {
+    // Plain old entry point patch. The relative jump address follows it.
+    ULONG relative = function_code.service_id;
+
+    // First, fix our copy of their patch.
+    relative += bit_cast<ULONG>(target_) - bit_cast<ULONG>(remote_thunk);
+
+    function_code.service_id = relative;
+
+    // And now, remember how to re-patch it.
+    ServiceFullThunk *full_thunk =
+        reinterpret_cast<ServiceFullThunk*>(remote_thunk);
+
+    const ULONG kJmp32Size = 5;
+
+    relative_jump_ = bit_cast<ULONG>(&full_thunk->internal_thunk) -
+                     bit_cast<ULONG>(target_) - kJmp32Size;
+  }
+
+  // Save the verified code
+  memcpy(local_thunk, &function_code, sizeof(function_code));
+
+  return true;
+}
+
+bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const {
+  Wow64Entry function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (kMovEax != function_code.mov_eax || kXorEcx != function_code.xor_ecx ||
+      kLeaEdx != function_code.lea_edx || kCallFs1 != function_code.call_fs1 ||
+      kCallFs2 != function_code.call_fs2 || kCallFs3 != function_code.call_fs3)
+    return false;
+
+  if ((kAddEsp1 == function_code.add_esp1 &&
+       kAddEsp2 == function_code.add_esp2 &&
+       kRet == function_code.ret) || kRet == function_code.add_esp1) {
+    // Save the verified code
+    memcpy(local_thunk, &function_code, sizeof(function_code));
+    return true;
+  }
+
+  return false;
+}
+
+bool Wow64W8ResolverThunk::IsFunctionAService(void* local_thunk) const {
+  Wow64EntryW8 function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (kMovEax != function_code.mov_eax || kCallFs1 != function_code.call_fs1 ||
+      kCallFs2 != function_code.call_fs2 ||
+      kCallFs3 != function_code.call_fs3 || kRet != function_code.ret) {
+    return false;
+  }
+
+  // Save the verified code
+  memcpy(local_thunk, &function_code, sizeof(function_code));
+  return true;
+}
+
+bool Win8ResolverThunk::IsFunctionAService(void* local_thunk) const {
+  ServiceEntryW8 function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (kMovEax != function_code.mov_eax || kCallEip != function_code.call_eip ||
+      function_code.call_offset != 3 || kRet != function_code.ret_p ||
+      kMovEdxEsp != function_code.mov_edx_esp ||
+      kSysenter != function_code.sysenter || kRet2 != function_code.ret) {
+    return false;
+  }
+
+  // Save the verified code
+  memcpy(local_thunk, &function_code, sizeof(function_code));
+
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/service_resolver_64.cc b/sandbox/win/src/service_resolver_64.cc
new file mode 100644
index 0000000..984cb38
--- /dev/null
+++ b/sandbox/win/src/service_resolver_64.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+#pragma pack(push, 1)
+
+const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
+const USHORT kSyscall = 0x050F;
+const BYTE kRetNp = 0xC3;
+const ULONG64 kMov1 = 0x54894808244C8948;
+const ULONG64 kMov2 = 0x4C182444894C1024;
+const ULONG kMov3 = 0x20244C89;
+
+// Service code for 64 bit systems.
+struct ServiceEntry {
+  // This struct contains roughly the following code:
+  // 00 mov     r10,rcx
+  // 03 mov     eax,52h
+  // 08 syscall
+  // 0a ret
+  // 0b xchg    ax,ax
+  // 0e xchg    ax,ax
+
+  ULONG mov_r10_rcx_mov_eax;  // = 4C 8B D1 B8
+  ULONG service_id;
+  USHORT syscall;             // = 0F 05
+  BYTE ret;                   // = C3
+  BYTE pad;                   // = 66
+  USHORT xchg_ax_ax1;         // = 66 90
+  USHORT xchg_ax_ax2;         // = 66 90
+};
+
+// Service code for 64 bit Windows 8.
+struct ServiceEntryW8 {
+  // This struct contains the following code:
+  // 00 48894c2408      mov     [rsp+8], rcx
+  // 05 4889542410      mov     [rsp+10], rdx
+  // 0a 4c89442418      mov     [rsp+18], r8
+  // 0f 4c894c2420      mov     [rsp+20], r9
+  // 14 4c8bd1          mov     r10,rcx
+  // 17 b825000000      mov     eax,25h
+  // 1c 0f05            syscall
+  // 1e c3              ret
+  // 1f 90              nop
+
+  ULONG64 mov_1;              // = 48 89 4C 24 08 48 89 54
+  ULONG64 mov_2;              // = 24 10 4C 89 44 24 18 4C
+  ULONG mov_3;                // = 89 4C 24 20
+  ULONG mov_r10_rcx_mov_eax;  // = 4C 8B D1 B8
+  ULONG service_id;
+  USHORT syscall;             // = 0F 05
+  BYTE ret;                   // = C3
+  BYTE nop;                   // = 90
+};
+
+// We don't have an internal thunk for x64.
+struct ServiceFullThunk {
+  union {
+    ServiceEntry original;
+    ServiceEntryW8 original_w8;
+  };
+};
+
+#pragma pack(pop)
+
+bool IsService(const void* source) {
+  const ServiceEntry* service =
+      reinterpret_cast<const ServiceEntry*>(source);
+
+  return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax &&
+          kSyscall == service->syscall && kRetNp == service->ret);
+}
+
+};  // namespace
+
+namespace sandbox {
+
+NTSTATUS ServiceResolverThunk::Setup(const void* target_module,
+                                     const void* interceptor_module,
+                                     const char* target_name,
+                                     const char* interceptor_name,
+                                     const void* interceptor_entry_point,
+                                     void* thunk_storage,
+                                     size_t storage_bytes,
+                                     size_t* storage_used) {
+  NTSTATUS ret = Init(target_module, interceptor_module, target_name,
+                      interceptor_name, interceptor_entry_point,
+                      thunk_storage, storage_bytes);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  size_t thunk_bytes = GetThunkSize();
+  scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
+  ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
+                                thunk_buffer.get());
+
+  if (!IsFunctionAService(&thunk->original))
+    return STATUS_UNSUCCESSFUL;
+
+  ret = PerformPatch(thunk, thunk_storage);
+
+  if (NULL != storage_used)
+    *storage_used = thunk_bytes;
+
+  return ret;
+}
+
+size_t ServiceResolverThunk::GetThunkSize() const {
+  return sizeof(ServiceFullThunk);
+}
+
+NTSTATUS ServiceResolverThunk::CopyThunk(const void* target_module,
+                                         const char* target_name,
+                                         BYTE* thunk_storage,
+                                         size_t storage_bytes,
+                                         size_t* storage_used) {
+  NTSTATUS ret = ResolveTarget(target_module, target_name, &target_);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  size_t thunk_bytes = GetThunkSize();
+  if (storage_bytes < thunk_bytes)
+    return STATUS_UNSUCCESSFUL;
+
+  ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(thunk_storage);
+
+  if (!IsFunctionAService(&thunk->original))
+    return STATUS_UNSUCCESSFUL;
+
+  if (NULL != storage_used)
+    *storage_used = thunk_bytes;
+
+  return ret;
+}
+
+bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const {
+  ServiceFullThunk function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (!IsService(&function_code)) {
+    // See if it's the Win8 signature.
+    ServiceEntryW8* w8_service = &function_code.original_w8;
+    if (!IsService(&w8_service->mov_r10_rcx_mov_eax) ||
+        w8_service->mov_1 != kMov1 || w8_service->mov_1 != kMov1 ||
+        w8_service->mov_1 != kMov1) {
+      return false;
+    }
+  }
+
+  // Save the verified code.
+  memcpy(local_thunk, &function_code, sizeof(function_code));
+
+  return true;
+}
+
+NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk,
+                                            void* remote_thunk) {
+  // Patch the original code.
+  ServiceEntry local_service;
+  DCHECK_NT(GetInternalThunkSize() >= sizeof(local_service));
+  if (!SetInternalThunk(&local_service, sizeof(local_service), NULL,
+                        interceptor_))
+    return STATUS_UNSUCCESSFUL;
+
+  // Copy the local thunk buffer to the child.
+  SIZE_T actual;
+  if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
+                            sizeof(ServiceFullThunk), &actual))
+    return STATUS_UNSUCCESSFUL;
+
+  if (sizeof(ServiceFullThunk) != actual)
+    return STATUS_UNSUCCESSFUL;
+
+  // And now change the function to intercept, on the child.
+  if (NULL != ntdll_base_) {
+    // Running a unit test.
+    if (!::WriteProcessMemory(process_, target_, &local_service,
+                              sizeof(local_service), &actual))
+      return STATUS_UNSUCCESSFUL;
+  } else {
+    if (!WriteProtectedChildMemory(process_, target_, &local_service,
+                                   sizeof(local_service)))
+      return STATUS_UNSUCCESSFUL;
+  }
+
+  return STATUS_SUCCESS;
+}
+
+bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const {
+  NOTREACHED_NT();
+  return false;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/service_resolver_unittest.cc b/sandbox/win/src/service_resolver_unittest.cc
new file mode 100644
index 0000000..c7ac7ea
--- /dev/null
+++ b/sandbox/win/src/service_resolver_unittest.cc
@@ -0,0 +1,262 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for ServiceResolverThunk.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/resolver.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/service_resolver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll.
+template<typename T>
+class ResolverThunkTest : public T {
+ public:
+  // The service resolver needs a child process to write to.
+  explicit ResolverThunkTest(bool relaxed)
+      : T(::GetCurrentProcess(), relaxed) {}
+
+  // Sets the interception target to the desired address.
+  void set_target(void* target) {
+    fake_target_ = target;
+  }
+
+ protected:
+  // Overrides Resolver::Init
+  virtual NTSTATUS Init(const void* target_module,
+                        const void* interceptor_module,
+                        const char* target_name,
+                        const char* interceptor_name,
+                        const void* interceptor_entry_point,
+                        void* thunk_storage,
+                        size_t storage_bytes) {
+    NTSTATUS ret = STATUS_SUCCESS;
+    ret = ResolverThunk::Init(target_module, interceptor_module, target_name,
+                              interceptor_name, interceptor_entry_point,
+                              thunk_storage, storage_bytes);
+    EXPECT_EQ(STATUS_SUCCESS, ret);
+
+    target_ = fake_target_;
+
+    return ret;
+  };
+
+ private:
+  // Holds the address of the fake target.
+  void* fake_target_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResolverThunkTest);
+};
+
+typedef ResolverThunkTest<sandbox::ServiceResolverThunk> WinXpResolverTest;
+
+#if !defined(_WIN64)
+typedef ResolverThunkTest<sandbox::Win8ResolverThunk> Win8ResolverTest;
+typedef ResolverThunkTest<sandbox::Wow64ResolverThunk> Wow64ResolverTest;
+typedef ResolverThunkTest<sandbox::Wow64W8ResolverThunk> Wow64W8ResolverTest;
+#endif
+
+const BYTE kJump32 = 0xE9;
+
+void CheckJump(void* source, void* target) {
+#pragma pack(push)
+#pragma pack(1)
+  struct Code {
+    BYTE jump;
+    ULONG delta;
+  };
+#pragma pack(pop)
+
+#if defined(_WIN64)
+  FAIL() << "Running 32-bit codepath";
+#else
+  Code* patched = reinterpret_cast<Code*>(source);
+  EXPECT_EQ(kJump32, patched->jump);
+
+  ULONG source_addr = bit_cast<ULONG>(source);
+  ULONG target_addr = bit_cast<ULONG>(target);
+  EXPECT_EQ(target_addr + 19 - source_addr, patched->delta);
+#endif
+}
+
+NTSTATUS PatchNtdllWithResolver(const char* function, bool relaxed,
+                                sandbox::ServiceResolverThunk* resolver) {
+  HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
+  EXPECT_TRUE(NULL != ntdll_base);
+
+  void* target = ::GetProcAddress(ntdll_base, function);
+  EXPECT_TRUE(NULL != target);
+  if (NULL == target)
+    return STATUS_UNSUCCESSFUL;
+
+  BYTE service[50];
+  memcpy(service, target, sizeof(service));
+
+  static_cast<WinXpResolverTest*>(resolver)->set_target(service);
+
+  // Any pointer will do as an interception_entry_point
+  void* function_entry = resolver;
+  size_t thunk_size = resolver->GetThunkSize();
+  scoped_ptr<char[]> thunk(new char[thunk_size]);
+  size_t used;
+
+  resolver->AllowLocalPatches();
+
+  NTSTATUS ret = resolver->Setup(ntdll_base, NULL, function, NULL,
+                                 function_entry, thunk.get(), thunk_size,
+                                 &used);
+  if (NT_SUCCESS(ret)) {
+    EXPECT_EQ(thunk_size, used);
+    EXPECT_NE(0, memcmp(service, target, sizeof(service)));
+    EXPECT_NE(kJump32, service[0]);
+
+    if (relaxed) {
+      // It's already patched, let's patch again, and simulate a direct patch.
+      service[0] = kJump32;
+      ret = resolver->Setup(ntdll_base, NULL, function, NULL, function_entry,
+                            thunk.get(), thunk_size, &used);
+      CheckJump(service, thunk.get());
+    }
+  }
+
+  return ret;
+}
+
+sandbox::ServiceResolverThunk* GetTestResolver(bool relaxed) {
+#if defined(_WIN64)
+  return new WinXpResolverTest(relaxed);
+#else
+  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+  if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
+    if (os_info->version() >= base::win::VERSION_WIN8)
+      return new Wow64W8ResolverTest(relaxed);
+    return new Wow64ResolverTest(relaxed);
+  }
+
+  if (os_info->version() >= base::win::VERSION_WIN8)
+    return new Win8ResolverTest(relaxed);
+
+  return new WinXpResolverTest(relaxed);
+#endif
+}
+
+NTSTATUS PatchNtdll(const char* function, bool relaxed) {
+  sandbox::ServiceResolverThunk* resolver = GetTestResolver(relaxed);
+
+  NTSTATUS ret = PatchNtdllWithResolver(function, relaxed, resolver);
+  delete resolver;
+  return ret;
+}
+
+TEST(ServiceResolverTest, PatchesServices) {
+  NTSTATUS ret = PatchNtdll("NtClose", false);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
+
+  ret = PatchNtdll("NtCreateFile", false);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
+    ::GetLastError();
+
+  ret = PatchNtdll("NtCreateMutant", false);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
+    ::GetLastError();
+
+  ret = PatchNtdll("NtMapViewOfSection", false);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
+    ::GetLastError();
+}
+
+TEST(ServiceResolverTest, FailsIfNotService) {
+#if !defined(_WIN64)
+  EXPECT_NE(STATUS_SUCCESS, PatchNtdll("RtlUlongByteSwap", false));
+#endif
+
+  EXPECT_NE(STATUS_SUCCESS, PatchNtdll("LdrLoadDll", false));
+}
+
+TEST(ServiceResolverTest, PatchesPatchedServices) {
+// We don't support "relaxed mode" for Win64 apps.
+#if !defined(_WIN64)
+  NTSTATUS ret = PatchNtdll("NtClose", true);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
+
+  ret = PatchNtdll("NtCreateFile", true);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
+    ::GetLastError();
+
+  ret = PatchNtdll("NtCreateMutant", true);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
+    ::GetLastError();
+
+  ret = PatchNtdll("NtMapViewOfSection", true);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
+    ::GetLastError();
+#endif
+}
+
+TEST(ServiceResolverTest, MultiplePatchedServices) {
+// We don't support "relaxed mode" for Win64 apps.
+#if !defined(_WIN64)
+  sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
+  NTSTATUS ret = PatchNtdllWithResolver("NtClose", true, resolver);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
+
+  ret = PatchNtdllWithResolver("NtCreateFile", true, resolver);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateFile, last error: " <<
+    ::GetLastError();
+
+  ret = PatchNtdllWithResolver("NtCreateMutant", true, resolver);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtCreateMutant, last error: " <<
+    ::GetLastError();
+
+  ret = PatchNtdllWithResolver("NtMapViewOfSection", true, resolver);
+  EXPECT_EQ(STATUS_SUCCESS, ret) << "NtMapViewOfSection, last error: " <<
+    ::GetLastError();
+  delete resolver;
+#endif
+}
+
+TEST(ServiceResolverTest, LocalPatchesAllowed) {
+  sandbox::ServiceResolverThunk* resolver = GetTestResolver(true);
+
+  HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
+  ASSERT_TRUE(NULL != ntdll_base);
+
+  const char kFunctionName[] = "NtClose";
+
+  void* target = ::GetProcAddress(ntdll_base, kFunctionName);
+  ASSERT_TRUE(NULL != target);
+
+  BYTE service[50];
+  memcpy(service, target, sizeof(service));
+  static_cast<WinXpResolverTest*>(resolver)->set_target(service);
+
+  // Any pointer will do as an interception_entry_point
+  void* function_entry = resolver;
+  size_t thunk_size = resolver->GetThunkSize();
+  scoped_ptr<char[]> thunk(new char[thunk_size]);
+  size_t used;
+
+  NTSTATUS ret = STATUS_UNSUCCESSFUL;
+
+  // First try patching without having allowed local patches.
+  ret = resolver->Setup(ntdll_base, NULL, kFunctionName, NULL,
+                        function_entry, thunk.get(), thunk_size,
+                        &used);
+  EXPECT_FALSE(NT_SUCCESS(ret));
+
+  // Now allow local patches and check that things work.
+  resolver->AllowLocalPatches();
+  ret = resolver->Setup(ntdll_base, NULL, kFunctionName, NULL,
+                        function_entry, thunk.get(), thunk_size,
+                        &used);
+  EXPECT_EQ(STATUS_SUCCESS, ret);
+}
+
+}  // namespace
diff --git a/sandbox/win/src/shared_handles.cc b/sandbox/win/src/shared_handles.cc
new file mode 100644
index 0000000..423b67b
--- /dev/null
+++ b/sandbox/win/src/shared_handles.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/shared_handles.h"
+
+namespace sandbox {
+
+// Note once again the the assumption here is that the shared memory is
+// initialized with zeros in the process that calls SetHandle and that
+// the process that calls GetHandle 'sees' this memory.
+
+SharedHandles::SharedHandles() {
+  shared_.items = NULL;
+  shared_.max_items = 0;
+}
+
+bool SharedHandles::Init(void* raw_mem, size_t size_bytes) {
+  if (size_bytes < sizeof(shared_.items[0])) {
+    // The shared memory is too small!
+    return false;
+  }
+  shared_.items = static_cast<SharedItem*>(raw_mem);
+  shared_.max_items = size_bytes / sizeof(shared_.items[0]);
+  return true;
+}
+
+// Note that an empty slot is marked with a tag == 0 that is why is
+// not a valid imput tag
+bool SharedHandles::SetHandle(uint32 tag, HANDLE handle) {
+  if (0 == tag) {
+    // Invalid tag
+    return false;
+  }
+  // Find empty slot and put the tag and the handle there
+  SharedItem* empty_slot = FindByTag(0);
+  if (NULL == empty_slot) {
+    return false;
+  }
+  empty_slot->tag = tag;
+  empty_slot->item = handle;
+  return true;
+}
+
+bool SharedHandles::GetHandle(uint32 tag, HANDLE* handle) {
+  if (0 == tag) {
+    // Invalid tag
+    return false;
+  }
+  SharedItem* found = FindByTag(tag);
+  if (NULL == found) {
+    return false;
+  }
+  *handle = found->item;
+  return true;
+}
+
+SharedHandles::SharedItem* SharedHandles::FindByTag(uint32 tag) {
+  for (size_t ix = 0; ix != shared_.max_items; ++ix) {
+    if (tag == shared_.items[ix].tag) {
+      return &shared_.items[ix];
+    }
+  }
+  return NULL;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/shared_handles.h b/sandbox/win/src/shared_handles.h
new file mode 100644
index 0000000..2c76bfb
--- /dev/null
+++ b/sandbox/win/src/shared_handles.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SHARED_HANDLES_H__
+#define SANDBOX_SRC_SHARED_HANDLES_H__
+
+#include "base/basictypes.h"
+
+#ifndef HANDLE
+// We can provide our own windows compatilble handle definition, but
+// in general we want to rely on the client of this api to include
+// the proper windows headers. Note that we don't want to bring the
+// whole <windows.h> into scope if we don't have to.
+typedef void* HANDLE;
+#endif
+
+namespace sandbox {
+
+// SharedHandles is a simple class to stash and find windows object handles
+// given a raw block of memory which is shared between two processes.
+// It addresses the need to communicate a handle value between two windows
+// processes given that they are already sharing some memory.
+//
+// This class is not exposed directly to users of the sanbox API, instead
+// we expose the wrapper methods TargetProcess::TransferHandle( ) and
+// TargetServices::GetTransferHandle()
+//
+// Use it for a small number of items, since internaly uses linear seach
+//
+// The use is very simple. Given a shared memory between proces A and B:
+// process A:
+//  HANDLE handle = SomeFunction(..);
+//  SharedHandles shared_handes;
+//  shared_handles.Init(memory)
+//  shared_handles.SetHandle(3, handle);
+//
+// process B:
+//  SharedHandles shared_handes;
+//  shared_handles.Init(memory)
+//  HANDLE handle = shared_handles.GetHandle(3);
+//
+// Note that '3' in this example is a unique id, that must be agreed before
+// transfer
+//
+// Note2: While this class can be used in a single process, there are
+// better alternatives such as STL
+//
+// Note3: Under windows a kernel object handle in one process does not
+// make sense for another process unless there is a DuplicateHandle( )
+// call involved which this class DOES NOT do that for you.
+//
+// Note4: Under windows, shared memory when created is initialized to
+// zeros always. If you are not using shared memory it is your responsability
+// to zero it for the setter process and to copy it to the getter process.
+class SharedHandles {
+ public:
+  SharedHandles();
+
+  // Initializes the shared memory for use.
+  // Pass the shared memory base and size. It will internally compute
+  // how many handles can it store. If initialization fails the return value
+  // is false.
+  bool Init(void* raw_mem, size_t size_bytes);
+
+  // Sets a handle in the shared memory for transfer.
+  // Parameters:
+  // tag : an integer, different from zero that uniquely identfies the
+  // handle to transfer.
+  // handle: the handle value associated with 'tag' to tranfer
+  // Returns false if there is not enough space in the shared memory for
+  // this handle.
+  bool SetHandle(uint32 tag, HANDLE handle);
+
+  // Gets a handle previously stored by SetHandle.
+  // Parameters:
+  // tag: an integer different from zero that uniquely identfies the handle
+  // to retrieve.
+  // *handle: output handle value if the call was succesful.
+  // If a handle with the provided tag is not found the return value is false.
+  // If the tag is found the return value is true.
+  bool GetHandle(uint32 tag, HANDLE* handle);
+
+ private:
+  // A single item is the tuple handle/tag
+  struct SharedItem {
+    uint32 tag;
+    void* item;
+  };
+
+  // SharedMem is used to layout the memory as an array of SharedItems
+  struct SharedMem {
+    size_t max_items;
+    SharedItem* items;
+  };
+
+  // Finds an Item tuple provided the handle tag.
+  // Uses linear search because we expect the number of handles to be
+  // small (say less than ~100).
+  SharedItem* FindByTag(uint32 tag);
+
+  SharedMem shared_;
+  DISALLOW_COPY_AND_ASSIGN(SharedHandles);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SHARED_HANDLES_H__
diff --git a/sandbox/win/src/sharedmem_ipc_client.cc b/sandbox/win/src/sharedmem_ipc_client.cc
new file mode 100644
index 0000000..fa6a877
--- /dev/null
+++ b/sandbox/win/src/sharedmem_ipc_client.cc
@@ -0,0 +1,152 @@
+// 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 <string.h>
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "base/logging.h"
+
+namespace sandbox {
+
+// Get the base of the data buffer of the channel; this is where the input
+// parameters get serialized. Since they get serialized directly into the
+// channel we avoid one copy.
+void* SharedMemIPCClient::GetBuffer() {
+  bool failure = false;
+  size_t ix = LockFreeChannel(&failure);
+  if (failure) {
+    return NULL;
+  }
+  return reinterpret_cast<char*>(control_) +
+         control_->channels[ix].channel_base;
+}
+
+// If we need to cancel an IPC before issuing DoCall
+// our client should call FreeBuffer with the same pointer
+// returned by GetBuffer.
+void SharedMemIPCClient::FreeBuffer(void* buffer) {
+  size_t num = ChannelIndexFromBuffer(buffer);
+  ChannelControl* channel = control_->channels;
+  LONG result = ::InterlockedExchange(&channel[num].state, kFreeChannel);
+  DCHECK_NE(kFreeChannel, static_cast<ChannelState>(result));
+  result;
+}
+
+// The constructor simply casts the shared memory to the internal
+// structures. This is a cheap step that is why this IPC object can
+// and should be constructed per call.
+SharedMemIPCClient::SharedMemIPCClient(void* shared_mem)
+    : control_(reinterpret_cast<IPCControl*>(shared_mem)) {
+  first_base_ = reinterpret_cast<char*>(shared_mem) +
+               control_->channels[0].channel_base;
+  // There must be at least one channel.
+  DCHECK(0 != control_->channels_count);
+}
+
+// Do the IPC. At this point the channel should have already been
+// filled with the serialized input parameters.
+// We follow the pattern explained in the header file.
+ResultCode SharedMemIPCClient::DoCall(CrossCallParams* params,
+                                      CrossCallReturn* answer) {
+  if (!control_->server_alive)
+    return SBOX_ERROR_CHANNEL_ERROR;
+
+  size_t num = ChannelIndexFromBuffer(params->GetBuffer());
+  ChannelControl* channel = control_->channels;
+  // Note that the IPC tag goes outside the buffer as well inside
+  // the buffer. This should enable the server to prioritize based on
+  // IPC tags without having to de-serialize the entire message.
+  channel[num].ipc_tag = params->GetTag();
+
+  // Wait for the server to service this IPC call. After kIPCWaitTimeOut1
+  // we check if the server_alive mutex was abandoned which will indicate
+  // that the server has died.
+
+  // While the atomic signaling and waiting is not a requirement, it
+  // is nice because we save a trip to kernel.
+  DWORD wait = ::SignalObjectAndWait(channel[num].ping_event,
+                                     channel[num].pong_event,
+                                     kIPCWaitTimeOut1, FALSE);
+  if (WAIT_TIMEOUT == wait) {
+    // The server is taking too long. Enter a loop were we check if the
+    // server_alive mutex has been abandoned which would signal a server crash
+    // or else we keep waiting for a response.
+    while (true) {
+      wait = ::WaitForSingleObject(control_->server_alive, 0);
+      if (WAIT_TIMEOUT == wait) {
+        // Server seems still alive. We already signaled so here we just wait.
+        wait = ::WaitForSingleObject(channel[num].pong_event, kIPCWaitTimeOut1);
+        if (WAIT_OBJECT_0 == wait) {
+          // The server took a long time but responded.
+          break;
+        } else if (WAIT_TIMEOUT == wait) {
+          continue;
+        } else {
+          return SBOX_ERROR_CHANNEL_ERROR;
+        }
+      } else {
+        // The server has crashed and windows has signaled the mutex as
+        // abandoned.
+        ::InterlockedExchange(&channel[num].state, kAbandonedChannel);
+        control_->server_alive = 0;
+        return SBOX_ERROR_CHANNEL_ERROR;
+      }
+    }
+  } else if (WAIT_OBJECT_0 != wait) {
+    // Probably the server crashed before the kIPCWaitTimeOut1 occurred.
+    return SBOX_ERROR_CHANNEL_ERROR;
+  }
+
+  // The server has returned an answer, copy it and free the channel.
+  memcpy(answer, params->GetCallReturn(), sizeof(CrossCallReturn));
+
+  // Return the IPC state It can indicate that while the IPC has
+  // completed some error in the Broker has caused to not return valid
+  // results.
+  return answer->call_outcome;
+}
+
+// Locking a channel is a simple as looping over all the channels
+// looking for one that is has state = kFreeChannel and atomically
+// swapping it to kBusyChannel.
+// If there is no free channel, then we must back off so some other
+// thread makes progress and frees a channel. To back off we sleep.
+size_t SharedMemIPCClient::LockFreeChannel(bool* severe_failure) {
+  if (0 == control_->channels_count) {
+    *severe_failure = true;
+    return 0;
+  }
+  ChannelControl* channel = control_->channels;
+  do {
+    for (size_t ix = 0; ix != control_->channels_count; ++ix) {
+      if (kFreeChannel == ::InterlockedCompareExchange(&channel[ix].state,
+                                                       kBusyChannel,
+                                                       kFreeChannel)) {
+          *severe_failure = false;
+          return ix;
+      }
+    }
+    // We did not find any available channel, maybe the server is dead.
+    DWORD wait = ::WaitForSingleObject(control_->server_alive,
+                                       kIPCWaitTimeOut2);
+    if (WAIT_TIMEOUT != wait) {
+      // The server is dead and we outlive it enough to get in trouble.
+      *severe_failure = true;
+      return 0;
+    }
+  }
+  while (true);
+}
+
+// Find out which channel we are from the pointer returned by GetBuffer.
+size_t SharedMemIPCClient::ChannelIndexFromBuffer(const void* buffer) {
+  ptrdiff_t d = reinterpret_cast<const char*>(buffer) - first_base_;
+  size_t num = d/kIPCChannelSize;
+  DCHECK_LT(num, control_->channels_count);
+  return (num);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sharedmem_ipc_client.h b/sandbox/win/src/sharedmem_ipc_client.h
new file mode 100644
index 0000000..9eec74a
--- /dev/null
+++ b/sandbox/win/src/sharedmem_ipc_client.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__
+#define SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+// IPC transport implementation that uses shared memory.
+// This is the client side
+//
+// The shared memory is divided on blocks called channels, and potentially
+// it can perform as many concurrent IPC calls as channels. The IPC over
+// each channel is strictly synchronous for the client.
+//
+// Each channel as a channel control section associated with. Each control
+// section has two kernel events (known as ping and pong) and a integer
+// variable that maintains a state
+//
+// this is the state diagram of a channel:
+//
+//                   locked                in service
+//     kFreeChannel---------->BusyChannel-------------->kAckChannel
+//          ^                                                 |
+//          |_________________________________________________|
+//                             answer ready
+//
+// The protocol is as follows:
+//   1) client finds a free channel: state = kFreeChannel
+//   2) does an atomic compare-and-swap, now state = BusyChannel
+//   3) client writes the data into the channel buffer
+//   4) client signals the ping event and waits (blocks) on the pong event
+//   5) eventually the server signals the pong event
+//   6) the client awakes and reads the answer from the same channel
+//   7) the client updates its InOut parameters with the new data from the
+//      shared memory section.
+//   8) the client atomically sets the state = kFreeChannel
+//
+//  In the shared memory the layout is as follows:
+//
+//    [ channel count    ]
+//    [ channel control 0]
+//    [ channel control 1]
+//    [ channel control N]
+//    [ channel buffer 0 ] 1024 bytes
+//    [ channel buffer 1 ] 1024 bytes
+//    [ channel buffer N ] 1024 bytes
+//
+// By default each channel buffer is 1024 bytes
+namespace sandbox {
+
+// the possible channel states as described above
+enum ChannelState {
+  // channel is free
+  kFreeChannel = 1,
+  // IPC in progress client side
+  kBusyChannel,
+  // IPC in progress server side
+  kAckChannel,
+  // not used right now
+  kReadyChannel,
+  // IPC abandoned by client side
+  kAbandonedChannel
+};
+
+// The next two constants control the time outs for the IPC.
+const DWORD kIPCWaitTimeOut1 = 1000;   // Milliseconds.
+const DWORD kIPCWaitTimeOut2 =   50;   // Milliseconds.
+
+// the channel control structure
+struct ChannelControl {
+  // points to be beginning of the channel buffer, where data goes
+  size_t channel_base;
+  // maintains the state from the ChannelState enumeration
+  volatile LONG state;
+  // the ping event is signaled by the client when the IPC data is ready on
+  // the buffer
+  HANDLE ping_event;
+  // the client waits on the pong event for the IPC answer back
+  HANDLE pong_event;
+  // the IPC unique identifier
+  uint32 ipc_tag;
+};
+
+struct IPCControl {
+  // total number of channels available, some might be busy at a given time
+  size_t channels_count;
+  // handle to a shared mutex to detect when the server is dead
+  HANDLE server_alive;
+  // array of channel control structures
+  ChannelControl channels[1];
+};
+
+// the actual shared memory IPC implementation class. This object is designed
+// to be lightweight so it can be constructed on-site (at the calling place)
+// wherever an IPC call is needed.
+class SharedMemIPCClient {
+ public:
+  // Creates the IPC client.
+  // as parameter it takes the base address of the shared memory
+  explicit SharedMemIPCClient(void* shared_mem);
+
+  // locks a free channel and returns the channel buffer memory base. This call
+  // blocks until there is a free channel
+  void* GetBuffer();
+
+  // releases the lock on the channel, for other to use. call this if you have
+  // called GetBuffer and you want to abort but have not called yet DoCall()
+  void FreeBuffer(void* buffer);
+
+  // Performs the actual IPC call.
+  // params: The blob of packed input parameters.
+  // answer: upon IPC completion, it contains the server answer to the IPC.
+  // If the return value is not SBOX_ERROR_CHANNEL_ERROR, the caller has to free
+  // the channel.
+  // returns ALL_OK if the IPC mechanism successfully delivered. You still need
+  // to check on the answer structure to see the actual IPC result.
+  ResultCode DoCall(CrossCallParams* params, CrossCallReturn* answer);
+
+ private:
+  // Returns the index of the first free channel. It sets 'severe_failure'
+  // to true if there is an unrecoverable error that does not allow to
+  // find a channel.
+  size_t LockFreeChannel(bool* severe_failure);
+  // Return the channel index given the address of the buffer.
+  size_t ChannelIndexFromBuffer(const void* buffer);
+  IPCControl* control_;
+  // point to the first channel base
+  char* first_base_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__
diff --git a/sandbox/win/src/sharedmem_ipc_server.cc b/sandbox/win/src/sharedmem_ipc_server.cc
new file mode 100644
index 0000000..5ce7da5
--- /dev/null
+++ b/sandbox/win/src/sharedmem_ipc_server.cc
@@ -0,0 +1,423 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_server.h"
+
+namespace {
+// This handle must not be closed.
+volatile HANDLE g_alive_mutex = NULL;
+}
+
+namespace sandbox {
+
+SharedMemIPCServer::SharedMemIPCServer(HANDLE target_process,
+                                       DWORD target_process_id,
+                                       HANDLE target_job,
+                                       ThreadProvider* thread_provider,
+                                       Dispatcher* dispatcher)
+    : client_control_(NULL),
+      thread_provider_(thread_provider),
+      target_process_(target_process),
+      target_process_id_(target_process_id),
+      target_job_object_(target_job),
+      call_dispatcher_(dispatcher) {
+  // We create a initially owned mutex. If the server dies unexpectedly,
+  // the thread that owns it will fail to release the lock and windows will
+  // report to the target (when it tries to acquire it) that the wait was
+  // abandoned. Note: We purposely leak the local handle because we want it to
+  // be closed by Windows itself so it is properly marked as abandoned if the
+  // server dies.
+  if (!g_alive_mutex) {
+    HANDLE mutex = ::CreateMutexW(NULL, TRUE, NULL);
+    if (::InterlockedCompareExchangePointer(&g_alive_mutex, mutex, NULL)) {
+      // We lost the race to create the mutex.
+      ::CloseHandle(mutex);
+    }
+  }
+}
+
+SharedMemIPCServer::~SharedMemIPCServer() {
+  // Free the wait handles associated with the thread pool.
+  if (!thread_provider_->UnRegisterWaits(this)) {
+    // Better to leak than to crash.
+    return;
+  }
+  // Free the IPC signal events.
+  ServerContexts::iterator it;
+  for (it = server_contexts_.begin(); it != server_contexts_.end(); ++it) {
+    ServerControl* context = (*it);
+    ::CloseHandle(context->ping_event);
+    ::CloseHandle(context->pong_event);
+    delete context;
+  }
+
+  if (client_control_)
+    ::UnmapViewOfFile(client_control_);
+}
+
+bool SharedMemIPCServer::Init(void* shared_mem, uint32 shared_size,
+                              uint32 channel_size) {
+  // The shared memory needs to be at least as big as a channel.
+  if (shared_size < channel_size) {
+    return false;
+  }
+  // The channel size should be aligned.
+  if (0 != (channel_size % 32)) {
+    return false;
+  }
+
+  // Calculate how many channels we can fit in the shared memory.
+  shared_size -= offsetof(IPCControl, channels);
+  size_t channel_count = shared_size / (sizeof(ChannelControl) + channel_size);
+
+  // If we cannot fit even one channel we bail out.
+  if (0 == channel_count) {
+    return false;
+  }
+  // Calculate the start of the first channel.
+  size_t base_start = (sizeof(ChannelControl)* channel_count) +
+                       offsetof(IPCControl, channels);
+
+  client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
+  client_control_->channels_count = 0;
+
+  // This is the initialization that we do per-channel. Basically:
+  // 1) make two events (ping & pong)
+  // 2) create handles to the events for the client and the server.
+  // 3) initialize the channel (client_context) with the state.
+  // 4) initialize the server side of the channel (service_context).
+  // 5) call the thread provider RegisterWait to register the ping events.
+  for (size_t ix = 0; ix != channel_count; ++ix) {
+    ChannelControl* client_context = &client_control_->channels[ix];
+    ServerControl* service_context = new ServerControl;
+    server_contexts_.push_back(service_context);
+
+    if (!MakeEvents(&service_context->ping_event,
+                    &service_context->pong_event,
+                    &client_context->ping_event,
+                    &client_context->pong_event)) {
+      return false;
+    }
+
+    client_context->channel_base = base_start;
+    client_context->state = kFreeChannel;
+
+    // Note that some of these values are available as members of this
+    // object but we put them again into the service_context because we
+    // will be called on a static method (ThreadPingEventReady)
+    service_context->shared_base = reinterpret_cast<char*>(shared_mem);
+    service_context->channel_size = channel_size;
+    service_context->channel = client_context;
+    service_context->channel_buffer = service_context->shared_base +
+                                      client_context->channel_base;
+    service_context->dispatcher = call_dispatcher_;
+    service_context->target_info.process = target_process_;
+    service_context->target_info.process_id = target_process_id_;
+    service_context->target_info.job_object = target_job_object_;
+    // Advance to the next channel.
+    base_start += channel_size;
+    // Register the ping event with the threadpool.
+    thread_provider_->RegisterWait(this, service_context->ping_event,
+                                   ThreadPingEventReady, service_context);
+  }
+  if (!::DuplicateHandle(::GetCurrentProcess(), g_alive_mutex,
+                         target_process_, &client_control_->server_alive,
+                         SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, 0)) {
+    return false;
+  }
+  // This last setting indicates to the client all is setup.
+  client_control_->channels_count = channel_count;
+  return true;
+}
+
+// Releases memory allocated for IPC arguments, if needed.
+void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) {
+  for (size_t i = 0; i < kMaxIpcParams; i++) {
+    switch (ipc_params->args[i]) {
+      case WCHAR_TYPE: {
+        delete reinterpret_cast<base::string16*>(args[i]);
+        args[i] = NULL;
+        break;
+      }
+      case INOUTPTR_TYPE: {
+        delete reinterpret_cast<CountedBuffer*>(args[i]);
+        args[i] = NULL;
+        break;
+      }
+      default: break;
+    }
+  }
+}
+
+// Fills up the list of arguments (args and ipc_params) for an IPC call.
+bool GetArgs(CrossCallParamsEx* params, IPCParams* ipc_params,
+             void* args[kMaxIpcParams]) {
+  if (kMaxIpcParams < params->GetParamsCount())
+    return false;
+
+  for (uint32 i = 0; i < params->GetParamsCount(); i++) {
+    uint32 size;
+    ArgType type;
+    args[i] = params->GetRawParameter(i, &size, &type);
+    if (args[i]) {
+      ipc_params->args[i] = type;
+      switch (type) {
+        case WCHAR_TYPE: {
+          scoped_ptr<base::string16> data(new base::string16);
+          if (!params->GetParameterStr(i, data.get())) {
+            args[i] = 0;
+            ReleaseArgs(ipc_params, args);
+            return false;
+          }
+          args[i] = data.release();
+          break;
+        }
+        case UINT32_TYPE: {
+          uint32 data;
+          if (!params->GetParameter32(i, &data)) {
+            ReleaseArgs(ipc_params, args);
+            return false;
+          }
+          IPCInt ipc_int(data);
+          args[i] = ipc_int.AsVoidPtr();
+          break;
+        }
+        case VOIDPTR_TYPE : {
+          void* data;
+          if (!params->GetParameterVoidPtr(i, &data)) {
+            ReleaseArgs(ipc_params, args);
+            return false;
+          }
+          args[i] = data;
+          break;
+        }
+        case INOUTPTR_TYPE: {
+          if (!args[i]) {
+            ReleaseArgs(ipc_params, args);
+            return false;
+          }
+          CountedBuffer* buffer = new CountedBuffer(args[i] , size);
+          args[i] = buffer;
+          break;
+        }
+        default: break;
+      }
+    }
+  }
+  return true;
+}
+
+bool SharedMemIPCServer::InvokeCallback(const ServerControl* service_context,
+                                        void* ipc_buffer,
+                                        CrossCallReturn* call_result) {
+  // Set the default error code;
+  SetCallError(SBOX_ERROR_INVALID_IPC, call_result);
+  uint32 output_size = 0;
+  // Parse, verify and copy the message. The handler operates on a copy
+  // of the message so the client cannot play dirty tricks by changing the
+  // data in the channel while the IPC is being processed.
+  scoped_ptr<CrossCallParamsEx> params(
+      CrossCallParamsEx::CreateFromBuffer(ipc_buffer,
+                                          service_context->channel_size,
+                                          &output_size));
+  if (!params.get())
+    return false;
+
+  uint32 tag = params->GetTag();
+  static_assert(0 == INVALID_TYPE, "incorrect type enum");
+  IPCParams ipc_params = {0};
+  ipc_params.ipc_tag = tag;
+
+  void* args[kMaxIpcParams];
+  if (!GetArgs(params.get(), &ipc_params, args))
+    return false;
+
+  IPCInfo ipc_info = {0};
+  ipc_info.ipc_tag = tag;
+  ipc_info.client_info = &service_context->target_info;
+  Dispatcher* dispatcher = service_context->dispatcher;
+  DCHECK(dispatcher);
+  bool error = true;
+  Dispatcher* handler = NULL;
+
+  Dispatcher::CallbackGeneric callback_generic;
+  handler = dispatcher->OnMessageReady(&ipc_params, &callback_generic);
+  if (handler) {
+    switch (params->GetParamsCount()) {
+      case 0: {
+        // Ask the IPC dispatcher if she can service this IPC.
+        Dispatcher::Callback0 callback =
+            reinterpret_cast<Dispatcher::Callback0>(callback_generic);
+        if (!(handler->*callback)(&ipc_info))
+          break;
+        error = false;
+        break;
+      }
+      case 1: {
+        Dispatcher::Callback1 callback =
+            reinterpret_cast<Dispatcher::Callback1>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0]))
+          break;
+        error = false;
+        break;
+      }
+      case 2: {
+        Dispatcher::Callback2 callback =
+            reinterpret_cast<Dispatcher::Callback2>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1]))
+          break;
+        error = false;
+        break;
+      }
+      case 3: {
+        Dispatcher::Callback3 callback =
+            reinterpret_cast<Dispatcher::Callback3>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2]))
+          break;
+        error = false;
+        break;
+      }
+      case 4: {
+        Dispatcher::Callback4 callback =
+            reinterpret_cast<Dispatcher::Callback4>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2],
+                                  args[3]))
+          break;
+        error = false;
+        break;
+      }
+      case 5: {
+        Dispatcher::Callback5 callback =
+            reinterpret_cast<Dispatcher::Callback5>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+                                  args[4]))
+          break;
+        error = false;
+        break;
+      }
+      case 6: {
+        Dispatcher::Callback6 callback =
+            reinterpret_cast<Dispatcher::Callback6>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+                                  args[4], args[5]))
+          break;
+        error = false;
+        break;
+      }
+      case 7: {
+        Dispatcher::Callback7 callback =
+            reinterpret_cast<Dispatcher::Callback7>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+                                  args[4], args[5], args[6]))
+          break;
+        error = false;
+        break;
+      }
+      case 8: {
+        Dispatcher::Callback8 callback =
+            reinterpret_cast<Dispatcher::Callback8>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+                                  args[4], args[5], args[6], args[7]))
+          break;
+        error = false;
+        break;
+      }
+      case 9: {
+        Dispatcher::Callback9 callback =
+            reinterpret_cast<Dispatcher::Callback9>(callback_generic);
+        if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+                                  args[4], args[5], args[6], args[7], args[8]))
+          break;
+        error = false;
+        break;
+      }
+      default:  {
+        NOTREACHED();
+        break;
+      }
+    }
+  }
+
+  if (error) {
+    if (handler)
+      SetCallError(SBOX_ERROR_FAILED_IPC, call_result);
+  } else {
+    memcpy(call_result, &ipc_info.return_info, sizeof(*call_result));
+    SetCallSuccess(call_result);
+    if (params->IsInOut()) {
+      // Maybe the params got changed by the broker. We need to upadte the
+      // memory section.
+      memcpy(ipc_buffer, params.get(), output_size);
+    }
+  }
+
+  ReleaseArgs(&ipc_params, args);
+
+  return !error;
+}
+
+// This function gets called by a thread from the thread pool when a
+// ping event fires. The context is the same as passed in the RegisterWait()
+// call above.
+void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context,
+                                                        unsigned char) {
+  if (NULL == context) {
+    DCHECK(false);
+    return;
+  }
+  ServerControl* service_context = reinterpret_cast<ServerControl*>(context);
+  // Since the event fired, the channel *must* be busy. Change to kAckChannel
+  // while we service it.
+  LONG last_state =
+    ::InterlockedCompareExchange(&service_context->channel->state,
+                                 kAckChannel, kBusyChannel);
+  if (kBusyChannel != last_state) {
+    DCHECK(false);
+    return;
+  }
+
+  // Prepare the result structure. At this point we will return some result
+  // even if the IPC is invalid, malformed or has no handler.
+  CrossCallReturn call_result = {0};
+  void* buffer = service_context->channel_buffer;
+
+  InvokeCallback(service_context, buffer, &call_result);
+
+  // Copy the answer back into the channel and signal the pong event. This
+  // should wake up the client so he can finish the the ipc cycle.
+  CrossCallParams* call_params = reinterpret_cast<CrossCallParams*>(buffer);
+  memcpy(call_params->GetCallReturn(), &call_result, sizeof(call_result));
+  ::InterlockedExchange(&service_context->channel->state, kAckChannel);
+  ::SetEvent(service_context->pong_event);
+}
+
+bool SharedMemIPCServer::MakeEvents(HANDLE* server_ping, HANDLE* server_pong,
+                                    HANDLE* client_ping, HANDLE* client_pong) {
+  // Note that the IPC client has no right to delete the events. That would
+  // cause problems. The server *owns* the events.
+  const DWORD kDesiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE;
+
+  // The events are auto reset, and start not signaled.
+  *server_ping = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+  if (!::DuplicateHandle(::GetCurrentProcess(), *server_ping, target_process_,
+                         client_ping, kDesiredAccess, FALSE, 0)) {
+    return false;
+  }
+  *server_pong = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+  if (!::DuplicateHandle(::GetCurrentProcess(), *server_pong, target_process_,
+                         client_pong, kDesiredAccess, FALSE, 0)) {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sharedmem_ipc_server.h b/sandbox/win/src/sharedmem_ipc_server.h
new file mode 100644
index 0000000..94d6959
--- /dev/null
+++ b/sandbox/win/src/sharedmem_ipc_server.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SHAREDMEM_IPC_SERVER_H_
+#define SANDBOX_SRC_SHAREDMEM_IPC_SERVER_H_
+
+#include <list>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+
+// IPC transport implementation that uses shared memory.
+// This is the server side
+//
+// The server side has knowledge about the layout of the shared memory
+// and the state transitions. Both are explained in sharedmem_ipc_client.h
+//
+// As opposed to SharedMemIPClient, the Server object should be one for the
+// entire lifetime of the target process. The server is in charge of creating
+// the events (ping, pong) both for the client and for the target that are used
+// to signal the IPC and also in charge of setting the initial state of the
+// channels.
+//
+// When an IPC is ready, the server relies on being called by on the
+// ThreadPingEventReady callback. The IPC server then retrieves the buffer,
+// marshals it into a CrossCallParam object and calls the Dispatcher, who is in
+// charge of fulfilling the IPC request.
+namespace sandbox {
+
+// the shared memory implementation of the IPC server. There should be one
+// of these objects per target (IPC client) process
+class SharedMemIPCServer {
+ public:
+  // Creates the IPC server.
+  // target_process: handle to the target process. It must be suspended.
+  // target_process_id: process id of the target process.
+  // target_job: the job object handle associated with the target process.
+  // thread_provider: a thread provider object.
+  // dispatcher: an object that can service IPC calls.
+  SharedMemIPCServer(HANDLE target_process, DWORD target_process_id,
+                     HANDLE target_job, ThreadProvider* thread_provider,
+                     Dispatcher* dispatcher);
+
+  ~SharedMemIPCServer();
+
+  // Initializes the server structures, shared memory structures and
+  // creates the kernels events used to signal the IPC.
+  bool Init(void* shared_mem, uint32 shared_size, uint32 channel_size);
+
+ private:
+  // Allow tests to be marked DISABLED_. Note that FLAKY_ and FAILS_ prefixes
+  // do not work with sandbox tests.
+  FRIEND_TEST_ALL_PREFIXES(IPCTest, SharedMemServerTests);
+  // When an event fires (IPC request). A thread from the ThreadProvider
+  // will call this function. The context parameter should be the same as
+  // provided when ThreadProvider::RegisterWait was called.
+  static void __stdcall ThreadPingEventReady(void* context,
+                                             unsigned char);
+
+  // Makes the client and server events. This function is called once
+  // per channel.
+  bool MakeEvents(HANDLE* server_ping, HANDLE* server_pong,
+                  HANDLE* client_ping, HANDLE* client_pong);
+
+  // A copy this structure is maintained per channel.
+  // Note that a lot of the fields are just the same of what we have in the IPC
+  // object itself. It is better to have the copies since we can dispatch in the
+  // static method without worrying about converting back to a member function
+  // call or about threading issues.
+  struct ServerControl {
+    // This channel server ping event.
+    HANDLE ping_event;
+    // This channel server pong event.
+    HANDLE pong_event;
+    // The size of this channel.
+    uint32 channel_size;
+    // The pointer to the actual channel data.
+    char* channel_buffer;
+    // The pointer to the base of the shared memory.
+    char* shared_base;
+    // A pointer to this channel's client-side control structure this structure
+    // lives in the shared memory.
+    ChannelControl* channel;
+    // the IPC dispatcher associated with this channel.
+    Dispatcher* dispatcher;
+    // The target process information associated with this channel.
+    ClientInfo target_info;
+  };
+
+  // Looks for the appropriate handler for this IPC and invokes it.
+  static bool InvokeCallback(const ServerControl* service_context,
+                             void* ipc_buffer, CrossCallReturn* call_result);
+
+  // Points to the shared memory channel control which lives at
+  // the start of the shared section.
+  IPCControl* client_control_;
+
+  // Keeps track of the server side objects that are used to answer an IPC.
+  typedef std::list<ServerControl*> ServerContexts;
+  ServerContexts server_contexts_;
+
+  // The thread provider provides the threads that call back into this object
+  // when the IPC events fire.
+  ThreadProvider* thread_provider_;
+
+  // The IPC object is associated with a target process.
+  HANDLE target_process_;
+
+  // The target process id associated with the IPC object.
+  DWORD target_process_id_;
+
+  // The target object is inside a job too.
+  HANDLE target_job_object_;
+
+  // The dispatcher handles 'ready' IPC calls.
+  Dispatcher* call_dispatcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemIPCServer);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SHAREDMEM_IPC_SERVER_H_
diff --git a/sandbox/win/src/sid.cc b/sandbox/win/src/sid.cc
new file mode 100644
index 0000000..261605d
--- /dev/null
+++ b/sandbox/win/src/sid.cc
@@ -0,0 +1,26 @@
+// 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 "sandbox/win/src/sid.h"
+
+#include "base/logging.h"
+
+namespace sandbox {
+
+Sid::Sid(const SID *sid) {
+  ::CopySid(SECURITY_MAX_SID_SIZE, sid_, const_cast<SID*>(sid));
+};
+
+Sid::Sid(WELL_KNOWN_SID_TYPE type) {
+  DWORD size_sid = SECURITY_MAX_SID_SIZE;
+  BOOL result = ::CreateWellKnownSid(type, NULL, sid_, &size_sid);
+  DCHECK(result);
+  DBG_UNREFERENCED_LOCAL_VARIABLE(result);
+}
+
+const SID *Sid::GetPSID() const {
+  return reinterpret_cast<SID*>(const_cast<BYTE*>(sid_));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sid.h b/sandbox/win/src/sid.h
new file mode 100644
index 0000000..4656859
--- /dev/null
+++ b/sandbox/win/src/sid.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SID_H_
+#define SANDBOX_SRC_SID_H_
+
+#include <windows.h>
+
+namespace sandbox {
+
+// This class is used to hold and generate SIDS.
+class Sid {
+ public:
+  // Constructors initializing the object with the SID passed.
+  // This is a converting constructor. It is not explicit.
+  Sid(const SID *sid);
+  Sid(WELL_KNOWN_SID_TYPE type);
+
+  // Returns sid_.
+  const SID *GetPSID() const;
+
+ private:
+  BYTE sid_[SECURITY_MAX_SID_SIZE];
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SID_H_
diff --git a/sandbox/win/src/sid_unittest.cc b/sandbox/win/src/sid_unittest.cc
new file mode 100644
index 0000000..76d61e8
--- /dev/null
+++ b/sandbox/win/src/sid_unittest.cc
@@ -0,0 +1,71 @@
+// 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 contains unit tests for the sid class.
+
+#define _ATL_NO_EXCEPTIONS
+#include <atlbase.h>
+#include <atlsecurity.h>
+
+#include "sandbox/win/src/sid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Calls ::EqualSid. This function exists only to simplify the calls to
+// ::EqualSid by removing the need to cast the input params.
+BOOL EqualSid(const SID *sid1, const SID *sid2) {
+  return ::EqualSid(const_cast<SID*>(sid1), const_cast<SID*>(sid2));
+}
+
+// Tests the creation if a Sid
+TEST(SidTest, Constructors) {
+  ATL::CSid sid_world = ATL::Sids::World();
+  SID *sid_world_pointer = const_cast<SID*>(sid_world.GetPSID());
+
+  // Check the SID* constructor
+  Sid sid_sid_star(sid_world_pointer);
+  ASSERT_TRUE(EqualSid(sid_world_pointer, sid_sid_star.GetPSID()));
+
+  // Check the copy constructor
+  Sid sid_copy(sid_sid_star);
+  ASSERT_TRUE(EqualSid(sid_world_pointer, sid_copy.GetPSID()));
+
+  // Note that the WELL_KNOWN_SID_TYPE constructor is tested in the GetPSID
+  // test.
+}
+
+// Tests the method GetPSID
+TEST(SidTest, GetPSID) {
+  // Check for non-null result;
+  ASSERT_NE(static_cast<SID*>(NULL), Sid(::WinLocalSid).GetPSID());
+  ASSERT_NE(static_cast<SID*>(NULL), Sid(::WinCreatorOwnerSid).GetPSID());
+  ASSERT_NE(static_cast<SID*>(NULL), Sid(::WinBatchSid).GetPSID());
+
+  ASSERT_TRUE(EqualSid(Sid(::WinNullSid).GetPSID(),
+                       ATL::Sids::Null().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinWorldSid).GetPSID(),
+                       ATL::Sids::World().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinDialupSid).GetPSID(),
+                       ATL::Sids::Dialup().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinNetworkSid).GetPSID(),
+                       ATL::Sids::Network().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinBuiltinAdministratorsSid).GetPSID(),
+                       ATL::Sids::Admins().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinBuiltinUsersSid).GetPSID(),
+                       ATL::Sids::Users().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinBuiltinGuestsSid).GetPSID(),
+                       ATL::Sids::Guests().GetPSID()));
+
+  ASSERT_TRUE(EqualSid(Sid(::WinProxySid).GetPSID(),
+                       ATL::Sids::Proxy().GetPSID()));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sidestep/ia32_modrm_map.cpp b/sandbox/win/src/sidestep/ia32_modrm_map.cpp
new file mode 100644
index 0000000..89bc189
--- /dev/null
+++ b/sandbox/win/src/sidestep/ia32_modrm_map.cpp
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Table of relevant information about how to decode the ModR/M byte.
+// Based on information in the IA-32 Intel Architecture
+// Software Developer's Manual Volume 2: Instruction Set Reference.
+
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+#include "sandbox/win/src/sidestep/mini_disassembler_types.h"
+
+namespace sidestep {
+
+const ModrmEntry MiniDisassembler::s_ia16_modrm_map_[] = {
+// mod == 00
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, false, OS_ZERO },
+  /* r/m == 101 */ { false, false, OS_ZERO },
+  /* r/m == 110 */ { true, false, OS_WORD },
+  /* r/m == 111 */ { false, false, OS_ZERO },
+// mod == 01
+  /* r/m == 000 */ { true, false, OS_BYTE },
+  /* r/m == 001 */ { true, false, OS_BYTE },
+  /* r/m == 010 */ { true, false, OS_BYTE },
+  /* r/m == 011 */ { true, false, OS_BYTE },
+  /* r/m == 100 */ { true, false, OS_BYTE },
+  /* r/m == 101 */ { true, false, OS_BYTE },
+  /* r/m == 110 */ { true, false, OS_BYTE },
+  /* r/m == 111 */ { true, false, OS_BYTE },
+// mod == 10
+  /* r/m == 000 */ { true, false, OS_WORD },
+  /* r/m == 001 */ { true, false, OS_WORD },
+  /* r/m == 010 */ { true, false, OS_WORD },
+  /* r/m == 011 */ { true, false, OS_WORD },
+  /* r/m == 100 */ { true, false, OS_WORD },
+  /* r/m == 101 */ { true, false, OS_WORD },
+  /* r/m == 110 */ { true, false, OS_WORD },
+  /* r/m == 111 */ { true, false, OS_WORD },
+// mod == 11
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, false, OS_ZERO },
+  /* r/m == 101 */ { false, false, OS_ZERO },
+  /* r/m == 110 */ { false, false, OS_ZERO },
+  /* r/m == 111 */ { false, false, OS_ZERO }
+};
+
+const ModrmEntry MiniDisassembler::s_ia32_modrm_map_[] = {
+// mod == 00
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, true, OS_ZERO },
+  /* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 110 */ { false, false, OS_ZERO },
+  /* r/m == 111 */ { false, false, OS_ZERO },
+// mod == 01
+  /* r/m == 000 */ { true, false, OS_BYTE },
+  /* r/m == 001 */ { true, false, OS_BYTE },
+  /* r/m == 010 */ { true, false, OS_BYTE },
+  /* r/m == 011 */ { true, false, OS_BYTE },
+  /* r/m == 100 */ { true, true, OS_BYTE },
+  /* r/m == 101 */ { true, false, OS_BYTE },
+  /* r/m == 110 */ { true, false, OS_BYTE },
+  /* r/m == 111 */ { true, false, OS_BYTE },
+// mod == 10
+  /* r/m == 000 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 001 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 010 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 011 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 100 */ { true, true, OS_DOUBLE_WORD },
+  /* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 110 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 111 */ { true, false, OS_DOUBLE_WORD },
+// mod == 11
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, false, OS_ZERO },
+  /* r/m == 101 */ { false, false, OS_ZERO },
+  /* r/m == 110 */ { false, false, OS_ZERO },
+  /* r/m == 111 */ { false, false, OS_ZERO },
+};
+
+};  // namespace sidestep
diff --git a/sandbox/win/src/sidestep/ia32_opcode_map.cpp b/sandbox/win/src/sidestep/ia32_opcode_map.cpp
new file mode 100644
index 0000000..b7d8a60
--- /dev/null
+++ b/sandbox/win/src/sidestep/ia32_opcode_map.cpp
@@ -0,0 +1,1159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Opcode decoding maps.  Based on the IA-32 Intel Architecture
+// Software Developer's Manual Volume 2: Instruction Set Reference.  Idea
+// for how to lay out the tables in memory taken from the implementation
+// in the Bastard disassembly environment.
+
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+
+namespace sidestep {
+
+/*
+* This is the first table to be searched; the first field of each
+* Opcode in the table is either 0 to indicate you're in the
+* right table, or an index to the correct table, in the global
+* map g_pentiumOpcodeMap
+*/
+const Opcode s_first_opcode_byte[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF */ { 1, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x10 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x11 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x12 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x13 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x14 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x15 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x16 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x17 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x18 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x19 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1E */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1F */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x20 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x21 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x22 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x23 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x24 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x25 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x26 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x27 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "daa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x28 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x29 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "das", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x30 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x31 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x32 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x33 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x34 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x35 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x36 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x37 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aaa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x38 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x39 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aas", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x40 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x50 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x51 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x52 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x53 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x54 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x55 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x56 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x57 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x58 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x59 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x60 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x61 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x62 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_A, AM_NOT_USED, "bound", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x63 */ { 0, IT_GENERIC, AM_E | OT_W, AM_G | OT_W, AM_NOT_USED, "arpl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x64 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x65 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x66 */ { 0, IT_PREFIX_OPERAND, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x67 */ { 0, IT_PREFIX_ADDRESS, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x68 */ { 0, IT_GENERIC, AM_I | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x69 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I | OT_V, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6A */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I |  OT_B, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6C */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "insb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6D */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "insd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6E */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X | OT_B, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X | OT_V, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x70 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x71 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x72 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x73 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x74 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x75 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x76 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x77 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x78 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x79 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7A */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7B */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7C */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7D */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7E */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7F */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x80 */ { 2, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x81 */ { 3, IT_REFERENCE, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x82 */ { 4, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x83 */ { 5, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x84 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x85 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x86 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x87 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x88 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x89 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8C */ { 0, IT_GENERIC, AM_E | OT_W, AM_S | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8D */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, "lea", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8E */ { 0, IT_GENERIC, AM_S | OT_W, AM_E | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8F */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x90 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "nop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x91 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x92 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x93 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x94 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x95 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x96 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x97 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x98 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cwde", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x99 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cdq", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9A */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "callf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9B */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wait", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9E */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_O | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_O | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA2 */ { 0, IT_GENERIC, AM_O | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA3 */ { 0, IT_GENERIC, AM_O | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA4 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "movsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA5 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "movsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA6 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "cmpsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA7 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "cmpsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAA */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "stosb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAB */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "stosd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X| OT_B, AM_NOT_USED, "lodsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X| OT_V, AM_NOT_USED, "lodsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAE */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_Y | OT_B, AM_NOT_USED, "scasb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_Y | OT_V, AM_NOT_USED, "scasd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB1 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB2 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB3 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC0 */ { 6, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC1 */ { 7, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC2 */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC3 */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC4 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "les", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "lds", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC8 */ { 0, IT_GENERIC, AM_I | OT_W, AM_I | OT_B, AM_NOT_USED, "enter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "leave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCA */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCB */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "int3", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCD */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "int", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCE */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "into", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCF */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "iret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD0 */ { 8, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD1 */ { 9, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD2 */ { 10, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD3 */ { 11, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD4 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aam", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD5 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "xlat", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+  // The following 8 lines would be references to the FPU tables, but we currently
+  // do not support the FPU instructions in this disassembler.
+
+  /* 0xD8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDA */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDB */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDC */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDD */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDE */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDF */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+
+  /* 0xE0 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE1 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE2 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE3 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jcxz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE6 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE7 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE8 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE9 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEA */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEB */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xED */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEF */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_V, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF0 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lock:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF2 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "repne:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF3 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rep:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF4 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "hlt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF6 */ { 12, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF7 */ { 13, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cli", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFB */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFD */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "std", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFE */ { 14, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFF */ { 15, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f[] = {
+  /* 0x0 */ { 16, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 17, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lsl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "invd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wbinvd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud2", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x10 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movups", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "movsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "movss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movupd" } },
+  /* 0x11 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movups", true,
+    /* F2h */ { 0, IT_GENERIC, AM_W | OT_SD, AM_V | OT_SD, AM_NOT_USED, "movsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_W | OT_SS, AM_V | OT_SS, AM_NOT_USED, "movss" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movupd" } },
+  /* 0x12 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // only one of ...
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // ...these two is correct, Intel doesn't specify which
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_S, AM_NOT_USED, "movlpd" } },
+  /* 0x13 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlpd" } },
+  /* 0x14 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpcklps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpcklpd" } },
+  /* 0x15 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpckhps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpckhpd" } },
+  /* 0x16 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // only one of...
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // ...these two is correct, Intel doesn't specify which
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhpd" } },
+  /* 0x17 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhpd" } },
+  /* 0x18 */ { 18, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x19 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1C */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x20 */ { 0, IT_GENERIC, AM_R | OT_D, AM_C | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x21 */ { 0, IT_GENERIC, AM_R | OT_D, AM_D | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x22 */ { 0, IT_GENERIC, AM_C | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x23 */ { 0, IT_GENERIC, AM_D | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x24 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x25 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x26 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x27 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x28 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movaps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movapd" } },
+  /* 0x29 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movaps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movapd" } },
+  /* 0x2A */ { 0, IT_GENERIC, AM_V | OT_PS, AM_Q | OT_Q, AM_NOT_USED, "cvtpi2ps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_E | OT_D, AM_NOT_USED, "cvtsi2sd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_E | OT_D, AM_NOT_USED, "cvtsi2ss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_Q | OT_DQ, AM_NOT_USED, "cvtpi2pd" } },
+  /* 0x2B */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movntps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movntpd" } },
+  /* 0x2C */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvttps2pi", true,
+    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvttsd2si" },
+    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvttss2si" },
+    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2pi" } },
+  /* 0x2D */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvtps2pi", true,
+    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvtsd2si" },
+    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvtss2si" },
+    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2pi" } },
+  /* 0x2E */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "ucomiss", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "ucomisd" } },
+  /* 0x2F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_SS, AM_NOT_USED, "comiss", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "comisd" } },
+  /* 0x30 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wrmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x31 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdtsc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x32 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x33 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdpmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x34 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysenter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x35 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysexit", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x36 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x37 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x38 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x39 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x40 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmova", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x50 */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PS, AM_NOT_USED, "movmskps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PD, AM_NOT_USED, "movmskpd" } },
+  /* 0x51 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "sqrtps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "sqrtsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "sqrtss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "sqrtpd" } },
+  /* 0x52 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rsqrtps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rsqrtss" },
+    /* 66h */ { 0 } },
+  /* 0x53 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rcpps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rcpss" },
+    /* 66h */ { 0 } },
+  /* 0x54 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andpd" } },
+  /* 0x55 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andnps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andnpd" } },
+  /* 0x56 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "orps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "orpd" } },
+  /* 0x57 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "xorps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "xorpd" } },
+  /* 0x58 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "addps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "addsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "addss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "addpd" } },
+  /* 0x59 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "mulps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "mulsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "mulss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "mulpd" } },
+  /* 0x5A */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PS, AM_NOT_USED, "cvtps2pd", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "cvtsd2ss" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "cvtss2sd" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PD, AM_NOT_USED, "cvtpd2ps" } },
+  /* 0x5B */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2ps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvttps2dq" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvtps2dq" } },
+  /* 0x5C */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "subps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "subsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "subss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "subpd" } },
+  /* 0x5D */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "minps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "minsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "minss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "minpd" } },
+  /* 0x5E */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "divps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "divsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "divss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "divpd" } },
+  /* 0x5F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "maxps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "maxsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "maxss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "maxpd" } },
+  /* 0x60 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklbw" } },
+  /* 0x61 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklwd" } },
+  /* 0x62 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckldq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpckldq" } },
+  /* 0x63 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packsswb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packsswb" } },
+  /* 0x64 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtb" } },
+  /* 0x65 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtw" } },
+  /* 0x66 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtd" } },
+  /* 0x67 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packuswb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packuswb" } },
+  /* 0x68 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhbw" } },
+  /* 0x69 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhwd" } },
+  /* 0x6A */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhdq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhdq" } },
+  /* 0x6B */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packssdw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "packssdw" } },
+  /* 0x6C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
+  /* 0x6D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
+  /* 0x6E */ { 0, IT_GENERIC, AM_P | OT_D, AM_E | OT_D, AM_NOT_USED, "movd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_NOT_USED, "movd" } },
+  /* 0x6F */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "movq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqu" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqa" } },
+  /* 0x70 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_I |  OT_B, "pshuf", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshuflw" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufhw" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufd" } },
+  /* 0x71 */ { 19, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x72 */ { 20, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x73 */ { 21, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x74 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqb" } },
+  /* 0x75 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqw" } },
+  /* 0x76 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqd" } },
+  /* 0x77 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "emms", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+  // The following six opcodes are escapes into the MMX stuff, which this disassembler does not support.
+  /* 0x78 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x79 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7A */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7B */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7C */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7D */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+  /* 0x7E */ { 0, IT_GENERIC, AM_E | OT_D, AM_P | OT_D, AM_NOT_USED, "movd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movq" },
+    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_DQ, AM_NOT_USED, "movd" } },
+  /* 0x7F */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_P | OT_Q, AM_NOT_USED, "movq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqu" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqa" } },
+  /* 0x80 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x81 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x82 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x83 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x84 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x85 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x86 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x87 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x88 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x89 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8A */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8B */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8C */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8D */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8E */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8F */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x90 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seto", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x91 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x92 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x93 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x94 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x95 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x96 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x97 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seta", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x98 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "sets", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x99 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9A */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9B */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9C */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9D */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9E */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9F */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cpuid", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA6 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA7 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rsm", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAC */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAD */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAE */ { 22, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB2 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lss", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB4 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lfs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB5 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lgs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB6 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB7 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud1", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 23, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC2 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "cmpps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_I | OT_B, "cmpsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W  | OT_SS, AM_I | OT_B, "cmpss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "cmppd" } },
+  /* 0xC3 */ { 0, IT_GENERIC, AM_E | OT_D, AM_G | OT_D, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_E | OT_D, AM_I | OT_B, "pinsrw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_I | OT_B, "pinsrw" } },
+  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_I | OT_B, "pextrw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_I | OT_B, "pextrw" } },
+  /* 0xC6 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "shufps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "shufpd" } },
+  /* 0xC7 */ { 24, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC8 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC9 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCA */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCB */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCC */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCD */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCE */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCF */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlw" } },
+  /* 0xD2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrld" } },
+  /* 0xD3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlq" } },
+  /* 0xD4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddq" } },
+  /* 0xD5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmullw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmullw" } },
+  /* 0xD6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "unused without prefix", true,
+    /* F2h */ { 0, IT_GENERIC, AM_P | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movdq2q" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_Q | OT_Q, AM_NOT_USED, "movq2dq" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movq" } },
+  /* 0xD7 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_NOT_USED, "pmovmskb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_NOT_USED, "pmovmskb" } },
+  /* 0xD8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusb" } },
+  /* 0xD9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusw" } },
+  /* 0xDA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminub", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminub" } },
+  /* 0xDB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pand", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pand" } },
+  /* 0xDC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusb" } },
+  /* 0xDD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusw" } },
+  /* 0xDE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxub", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxub" } },
+  /* 0xDF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pandn", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pandn" } },
+  /* 0xE0 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgb" } },
+  /* 0xE1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psraw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrqw" } },
+  /* 0xE2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrad", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrad" } },
+  /* 0xE3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgw" } },
+  /* 0xE4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhuw" } },
+  /* 0xE5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhw" } },
+  /* 0xE6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2dq" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2pd" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2dq" } },
+  /* 0xE7 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movntq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movntdq" } },
+  /* 0xE8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsb" } },
+  /* 0xE9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsw" } },
+  /* 0xEA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminsw" } },
+  /* 0xEB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "por", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "por" } },
+  /* 0xEC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsb" } },
+  /* 0xED */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsw" } },
+  /* 0xEE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxsw" } },
+  /* 0xEF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pxor", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pxor" } },
+  /* 0xF0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllw" } },
+  /* 0xF2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pslld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pslld" } },
+  /* 0xF3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllq" } },
+  /* 0xF4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmuludq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmuludq" } },
+  /* 0xF5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaddwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaddwd" } },
+  /* 0xF6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psadbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psadbw" } },
+  /* 0xF7 */ { 0, IT_GENERIC, AM_P | OT_PI, AM_Q | OT_PI, AM_NOT_USED, "maskmovq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "maskmovdqu" } },
+  /* 0xF8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubb" } },
+  /* 0xF9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubw" } },
+  /* 0xFA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubd" } },
+  /* 0xFB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubq" } },
+  /* 0xFC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddb" } },
+  /* 0xFD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddw" } },
+  /* 0xFE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddd" } },
+  /* 0xFF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f00[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "sldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "str", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "ltr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f01[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "smsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lmsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_M | OT_B, AM_NOT_USED, AM_NOT_USED, "invlpg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f18[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f71[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlw" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psraw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psraw" } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllw" } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f72[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrld" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrad", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrad" } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "pslld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslld" } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f73[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlq" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllq" } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq" } },
+};
+
+const Opcode s_opcode_byte_after_0fae[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxsave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxrstor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ldmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "mfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clflush/sfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+};
+
+const Opcode s_opcode_byte_after_0fba[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0fc7[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_Q, AM_NOT_USED, AM_NOT_USED, "cmpxch8b", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_80[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_81[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_82[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_83[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_c0[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_c1[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d0[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d1[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d2[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d3[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_f6[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_f7[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_fe[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_ff[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+/*
+* A table of all the other tables, containing some extra information, e.g.
+* how to mask out the byte we're looking at.
+*/
+const OpcodeTable MiniDisassembler::s_ia32_opcode_map_[]={
+  // One-byte opcodes and jumps to larger
+  /*  0 */ {s_first_opcode_byte, 0, 0xff, 0, 0xff},
+  // Two-byte opcodes (second byte)
+  /*  1 */ {s_opcode_byte_after_0f, 0, 0xff, 0, 0xff},
+  // Start of tables for opcodes using ModR/M bits as extension
+  /*  2 */ {s_opcode_byte_after_80, 3, 0x07, 0, 0x07},
+  /*  3 */ {s_opcode_byte_after_81, 3, 0x07, 0, 0x07},
+  /*  4 */ {s_opcode_byte_after_82, 3, 0x07, 0, 0x07},
+  /*  5 */ {s_opcode_byte_after_83, 3, 0x07, 0, 0x07},
+  /*  6 */ {s_opcode_byte_after_c0, 3, 0x07, 0, 0x07},
+  /*  7 */ {s_opcode_byte_after_c1, 3, 0x07, 0, 0x07},
+  /*  8 */ {s_opcode_byte_after_d0, 3, 0x07, 0, 0x07},
+  /*  9 */ {s_opcode_byte_after_d1, 3, 0x07, 0, 0x07},
+  /* 10 */ {s_opcode_byte_after_d2, 3, 0x07, 0, 0x07},
+  /* 11 */ {s_opcode_byte_after_d3, 3, 0x07, 0, 0x07},
+  /* 12 */ {s_opcode_byte_after_f6, 3, 0x07, 0, 0x07},
+  /* 13 */ {s_opcode_byte_after_f7, 3, 0x07, 0, 0x07},
+  /* 14 */ {s_opcode_byte_after_fe, 3, 0x07, 0, 0x01},
+  /* 15 */ {s_opcode_byte_after_ff, 3, 0x07, 0, 0x07},
+  /* 16 */ {s_opcode_byte_after_0f00, 3, 0x07, 0, 0x07},
+  /* 17 */ {s_opcode_byte_after_0f01, 3, 0x07, 0, 0x07},
+  /* 18 */ {s_opcode_byte_after_0f18, 3, 0x07, 0, 0x07},
+  /* 19 */ {s_opcode_byte_after_0f71, 3, 0x07, 0, 0x07},
+  /* 20 */ {s_opcode_byte_after_0f72, 3, 0x07, 0, 0x07},
+  /* 21 */ {s_opcode_byte_after_0f73, 3, 0x07, 0, 0x07},
+  /* 22 */ {s_opcode_byte_after_0fae, 3, 0x07, 0, 0x07},
+  /* 23 */ {s_opcode_byte_after_0fba, 3, 0x07, 0, 0x07},
+  /* 24 */ {s_opcode_byte_after_0fc7, 3, 0x07, 0, 0x01}
+};
+
+};  // namespace sidestep
diff --git a/sandbox/win/src/sidestep/mini_disassembler.cpp b/sandbox/win/src/sidestep/mini_disassembler.cpp
new file mode 100644
index 0000000..1e8e0bd
--- /dev/null
+++ b/sandbox/win/src/sidestep/mini_disassembler.cpp
@@ -0,0 +1,395 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Implementation of MiniDisassembler.
+
+#ifdef _WIN64
+#error The code in this file should not be used on 64-bit Windows.
+#endif
+
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+
+namespace sidestep {
+
+MiniDisassembler::MiniDisassembler(bool operand_default_is_32_bits,
+                                   bool address_default_is_32_bits)
+    : operand_default_is_32_bits_(operand_default_is_32_bits),
+      address_default_is_32_bits_(address_default_is_32_bits) {
+  Initialize();
+}
+
+MiniDisassembler::MiniDisassembler()
+    : operand_default_is_32_bits_(true),
+      address_default_is_32_bits_(true) {
+  Initialize();
+}
+
+InstructionType MiniDisassembler::Disassemble(
+    unsigned char* start_byte,
+    unsigned int* instruction_bytes) {
+  // Clean up any state from previous invocations.
+  Initialize();
+
+  // Start by processing any prefixes.
+  unsigned char* current_byte = start_byte;
+  unsigned int size = 0;
+  InstructionType instruction_type = ProcessPrefixes(current_byte, &size);
+
+  if (IT_UNKNOWN == instruction_type)
+    return instruction_type;
+
+  current_byte += size;
+  size = 0;
+
+  // Invariant: We have stripped all prefixes, and the operand_is_32_bits_
+  // and address_is_32_bits_ flags are correctly set.
+
+  instruction_type = ProcessOpcode(current_byte, 0, &size);
+
+  // Check for error processing instruction
+  if ((IT_UNKNOWN == instruction_type_) || (IT_UNUSED == instruction_type_)) {
+    return IT_UNKNOWN;
+  }
+
+  current_byte += size;
+
+  // Invariant: operand_bytes_ indicates the total size of operands
+  // specified by the opcode and/or ModR/M byte and/or SIB byte.
+  // pCurrentByte points to the first byte after the ModR/M byte, or after
+  // the SIB byte if it is present (i.e. the first byte of any operands
+  // encoded in the instruction).
+
+  // We get the total length of any prefixes, the opcode, and the ModR/M and
+  // SIB bytes if present, by taking the difference of the original starting
+  // address and the current byte (which points to the first byte of the
+  // operands if present, or to the first byte of the next instruction if
+  // they are not).  Adding the count of bytes in the operands encoded in
+  // the instruction gives us the full length of the instruction in bytes.
+  *instruction_bytes += operand_bytes_ + (current_byte - start_byte);
+
+  // Return the instruction type, which was set by ProcessOpcode().
+  return instruction_type_;
+}
+
+void MiniDisassembler::Initialize() {
+  operand_is_32_bits_ = operand_default_is_32_bits_;
+  address_is_32_bits_ = address_default_is_32_bits_;
+  operand_bytes_ = 0;
+  have_modrm_ = false;
+  should_decode_modrm_ = false;
+  instruction_type_ = IT_UNKNOWN;
+  got_f2_prefix_ = false;
+  got_f3_prefix_ = false;
+  got_66_prefix_ = false;
+}
+
+InstructionType MiniDisassembler::ProcessPrefixes(unsigned char* start_byte,
+                                                  unsigned int* size) {
+  InstructionType instruction_type = IT_GENERIC;
+  const Opcode& opcode = s_ia32_opcode_map_[0].table_[*start_byte];
+
+  switch (opcode.type_) {
+    case IT_PREFIX_ADDRESS:
+      address_is_32_bits_ = !address_default_is_32_bits_;
+      goto nochangeoperand;
+    case IT_PREFIX_OPERAND:
+      operand_is_32_bits_ = !operand_default_is_32_bits_;
+      nochangeoperand:
+    case IT_PREFIX:
+
+      if (0xF2 == (*start_byte))
+        got_f2_prefix_ = true;
+      else if (0xF3 == (*start_byte))
+        got_f3_prefix_ = true;
+      else if (0x66 == (*start_byte))
+        got_66_prefix_ = true;
+
+      instruction_type = opcode.type_;
+      (*size)++;
+      // we got a prefix, so add one and check next byte
+      ProcessPrefixes(start_byte + 1, size);
+    default:
+      break;   // not a prefix byte
+  }
+
+  return instruction_type;
+}
+
+InstructionType MiniDisassembler::ProcessOpcode(unsigned char* start_byte,
+                                                unsigned int table_index,
+                                                unsigned int* size) {
+  const OpcodeTable& table = s_ia32_opcode_map_[table_index];   // Get our table
+  unsigned char current_byte = (*start_byte) >> table.shift_;
+  current_byte = current_byte & table.mask_;  // Mask out the bits we will use
+
+  // Check whether the byte we have is inside the table we have.
+  if (current_byte < table.min_lim_ || current_byte > table.max_lim_) {
+    instruction_type_ = IT_UNKNOWN;
+    return instruction_type_;
+  }
+
+  const Opcode& opcode = table.table_[current_byte];
+  if (IT_UNUSED == opcode.type_) {
+    // This instruction is not used by the IA-32 ISA, so we indicate
+    // this to the user.  Probably means that we were pointed to
+    // a byte in memory that was not the start of an instruction.
+    instruction_type_ = IT_UNUSED;
+    return instruction_type_;
+  } else if (IT_REFERENCE == opcode.type_) {
+    // We are looking at an opcode that has more bytes (or is continued
+    // in the ModR/M byte).  Recursively find the opcode definition in
+    // the table for the opcode's next byte.
+    (*size)++;
+    ProcessOpcode(start_byte + 1, opcode.table_index_, size);
+    return instruction_type_;
+  }
+
+  const SpecificOpcode* specific_opcode = reinterpret_cast<
+                                              const SpecificOpcode*>(&opcode);
+  if (opcode.is_prefix_dependent_) {
+    if (got_f2_prefix_ && opcode.opcode_if_f2_prefix_.mnemonic_ != 0) {
+      specific_opcode = &opcode.opcode_if_f2_prefix_;
+    } else if (got_f3_prefix_ && opcode.opcode_if_f3_prefix_.mnemonic_ != 0) {
+      specific_opcode = &opcode.opcode_if_f3_prefix_;
+    } else if (got_66_prefix_ && opcode.opcode_if_66_prefix_.mnemonic_ != 0) {
+      specific_opcode = &opcode.opcode_if_66_prefix_;
+    }
+  }
+
+  // Inv: The opcode type is known.
+  instruction_type_ = specific_opcode->type_;
+
+  // Let's process the operand types to see if we have any immediate
+  // operands, and/or a ModR/M byte.
+
+  ProcessOperand(specific_opcode->flag_dest_);
+  ProcessOperand(specific_opcode->flag_source_);
+  ProcessOperand(specific_opcode->flag_aux_);
+
+  // Inv: We have processed the opcode and incremented operand_bytes_
+  // by the number of bytes of any operands specified by the opcode
+  // that are stored in the instruction (not registers etc.).  Now
+  // we need to return the total number of bytes for the opcode and
+  // for the ModR/M or SIB bytes if they are present.
+
+  if (table.mask_ != 0xff) {
+    if (have_modrm_) {
+      // we're looking at a ModR/M byte so we're not going to
+      // count that into the opcode size
+      ProcessModrm(start_byte, size);
+      return IT_GENERIC;
+    } else {
+      // need to count the ModR/M byte even if it's just being
+      // used for opcode extension
+      (*size)++;
+      return IT_GENERIC;
+    }
+  } else {
+    if (have_modrm_) {
+      // The ModR/M byte is the next byte.
+      (*size)++;
+      ProcessModrm(start_byte + 1, size);
+      return IT_GENERIC;
+    } else {
+      (*size)++;
+      return IT_GENERIC;
+    }
+  }
+}
+
+bool MiniDisassembler::ProcessOperand(int flag_operand) {
+  bool succeeded = true;
+  if (AM_NOT_USED == flag_operand)
+    return succeeded;
+
+  // Decide what to do based on the addressing mode.
+  switch (flag_operand & AM_MASK) {
+    // No ModR/M byte indicated by these addressing modes, and no
+    // additional (e.g. immediate) parameters.
+    case AM_A:  // Direct address
+    case AM_F:  // EFLAGS register
+    case AM_X:  // Memory addressed by the DS:SI register pair
+    case AM_Y:  // Memory addressed by the ES:DI register pair
+    case AM_IMPLICIT:  // Parameter is implicit, occupies no space in
+                       // instruction
+      break;
+
+    // There is a ModR/M byte but it does not necessarily need
+    // to be decoded.
+    case AM_C:  // reg field of ModR/M selects a control register
+    case AM_D:  // reg field of ModR/M selects a debug register
+    case AM_G:  // reg field of ModR/M selects a general register
+    case AM_P:  // reg field of ModR/M selects an MMX register
+    case AM_R:  // mod field of ModR/M may refer only to a general register
+    case AM_S:  // reg field of ModR/M selects a segment register
+    case AM_T:  // reg field of ModR/M selects a test register
+    case AM_V:  // reg field of ModR/M selects a 128-bit XMM register
+      have_modrm_ = true;
+      break;
+
+    // In these addressing modes, there is a ModR/M byte and it needs to be
+    // decoded. No other (e.g. immediate) params than indicated in ModR/M.
+    case AM_E:  // Operand is either a general-purpose register or memory,
+                // specified by ModR/M byte
+    case AM_M:  // ModR/M byte will refer only to memory
+    case AM_Q:  // Operand is either an MMX register or memory (complex
+                // evaluation), specified by ModR/M byte
+    case AM_W:  // Operand is either a 128-bit XMM register or memory (complex
+                // eval), specified by ModR/M byte
+      have_modrm_ = true;
+      should_decode_modrm_ = true;
+      break;
+
+    // These addressing modes specify an immediate or an offset value
+    // directly, so we need to look at the operand type to see how many
+    // bytes.
+    case AM_I:  // Immediate data.
+    case AM_J:  // Jump to offset.
+    case AM_O:  // Operand is at offset.
+      switch (flag_operand & OT_MASK) {
+        case OT_B:  // Byte regardless of operand-size attribute.
+          operand_bytes_ += OS_BYTE;
+          break;
+        case OT_C:  // Byte or word, depending on operand-size attribute.
+          if (operand_is_32_bits_)
+            operand_bytes_ += OS_WORD;
+          else
+            operand_bytes_ += OS_BYTE;
+          break;
+        case OT_D:  // Doubleword, regardless of operand-size attribute.
+          operand_bytes_ += OS_DOUBLE_WORD;
+          break;
+        case OT_DQ:  // Double-quadword, regardless of operand-size attribute.
+          operand_bytes_ += OS_DOUBLE_QUAD_WORD;
+          break;
+        case OT_P:  // 32-bit or 48-bit pointer, depending on operand-size
+                    // attribute.
+          if (operand_is_32_bits_)
+            operand_bytes_ += OS_48_BIT_POINTER;
+          else
+            operand_bytes_ += OS_32_BIT_POINTER;
+          break;
+        case OT_PS:  // 128-bit packed single-precision floating-point data.
+          operand_bytes_ += OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING;
+          break;
+        case OT_Q:  // Quadword, regardless of operand-size attribute.
+          operand_bytes_ += OS_QUAD_WORD;
+          break;
+        case OT_S:  // 6-byte pseudo-descriptor.
+          operand_bytes_ += OS_PSEUDO_DESCRIPTOR;
+          break;
+        case OT_SD:  // Scalar Double-Precision Floating-Point Value
+        case OT_PD:  // Unaligned packed double-precision floating point value
+          operand_bytes_ += OS_DOUBLE_PRECISION_FLOATING;
+          break;
+        case OT_SS:
+          // Scalar element of a 128-bit packed single-precision
+          // floating data.
+          // We simply return enItUnknown since we don't have to support
+          // floating point
+          succeeded = false;
+          break;
+        case OT_V:  // Word or doubleword, depending on operand-size attribute.
+          if (operand_is_32_bits_)
+            operand_bytes_ += OS_DOUBLE_WORD;
+          else
+            operand_bytes_ += OS_WORD;
+          break;
+        case OT_W:  // Word, regardless of operand-size attribute.
+          operand_bytes_ += OS_WORD;
+          break;
+
+        // Can safely ignore these.
+        case OT_A:  // Two one-word operands in memory or two double-word
+                    // operands in memory
+        case OT_PI:  // Quadword MMX technology register (e.g. mm0)
+        case OT_SI:  // Doubleword integer register (e.g., eax)
+          break;
+
+        default:
+          break;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  return succeeded;
+}
+
+bool MiniDisassembler::ProcessModrm(unsigned char* start_byte,
+                                    unsigned int* size) {
+  // If we don't need to decode, we just return the size of the ModR/M
+  // byte (there is never a SIB byte in this case).
+  if (!should_decode_modrm_) {
+    (*size)++;
+    return true;
+  }
+
+  // We never care about the reg field, only the combination of the mod
+  // and r/m fields, so let's start by packing those fields together into
+  // 5 bits.
+  unsigned char modrm = (*start_byte);
+  unsigned char mod = modrm & 0xC0;  // mask out top two bits to get mod field
+  modrm = modrm & 0x07;  // mask out bottom 3 bits to get r/m field
+  mod = mod >> 3;  // shift the mod field to the right place
+  modrm = mod | modrm;  // combine the r/m and mod fields as discussed
+  mod = mod >> 3;  // shift the mod field to bits 2..0
+
+  // Invariant: modrm contains the mod field in bits 4..3 and the r/m field
+  // in bits 2..0, and mod contains the mod field in bits 2..0
+
+  const ModrmEntry* modrm_entry = 0;
+  if (address_is_32_bits_)
+    modrm_entry = &s_ia32_modrm_map_[modrm];
+  else
+    modrm_entry = &s_ia16_modrm_map_[modrm];
+
+  // Invariant: modrm_entry points to information that we need to decode
+  // the ModR/M byte.
+
+  // Add to the count of operand bytes, if the ModR/M byte indicates
+  // that some operands are encoded in the instruction.
+  if (modrm_entry->is_encoded_in_instruction_)
+    operand_bytes_ += modrm_entry->operand_size_;
+
+  // Process the SIB byte if necessary, and return the count
+  // of ModR/M and SIB bytes.
+  if (modrm_entry->use_sib_byte_) {
+    (*size)++;
+    return ProcessSib(start_byte + 1, mod, size);
+  } else {
+    (*size)++;
+    return true;
+  }
+}
+
+bool MiniDisassembler::ProcessSib(unsigned char* start_byte,
+                                  unsigned char mod,
+                                  unsigned int* size) {
+  // get the mod field from the 2..0 bits of the SIB byte
+  unsigned char sib_base = (*start_byte) & 0x07;
+  if (0x05 == sib_base) {
+    switch (mod) {
+      case 0x00:  // mod == 00
+      case 0x02:  // mod == 10
+        operand_bytes_ += OS_DOUBLE_WORD;
+        break;
+      case 0x01:  // mod == 01
+        operand_bytes_ += OS_BYTE;
+        break;
+      case 0x03:  // mod == 11
+        // According to the IA-32 docs, there does not seem to be a disp
+        // value for this value of mod
+      default:
+        break;
+    }
+  }
+
+  (*size)++;
+  return true;
+}
+
+};  // namespace sidestep
diff --git a/sandbox/win/src/sidestep/mini_disassembler.h b/sandbox/win/src/sidestep/mini_disassembler.h
new file mode 100644
index 0000000..202c4ec
--- /dev/null
+++ b/sandbox/win/src/sidestep/mini_disassembler.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Definition of MiniDisassembler.
+
+#ifndef SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_H__
+#define SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_H__
+
+#include "sandbox/win/src/sidestep/mini_disassembler_types.h"
+
+namespace sidestep {
+
+// This small disassembler is very limited
+// in its functionality, and in fact does only the bare minimum required by the
+// preamble patching utility.  It may be useful for other purposes, however.
+//
+// The limitations include at least the following:
+//  -# No support for coprocessor opcodes, MMX, etc.
+//  -# No machine-readable identification of opcodes or decoding of
+//     assembly parameters. The name of the opcode (as a string) is given,
+//     however, to aid debugging.
+//
+// You may ask what this little disassembler actually does, then?  The answer is
+// that it does the following, which is exactly what the patching utility needs:
+//  -# Indicates if opcode is a jump (any kind) or a return (any kind)
+//     because this is important for the patching utility to determine if
+//     a function is too short or there are jumps too early in it for it
+//     to be preamble patched.
+//  -# The opcode length is always calculated, so that the patching utility
+//     can figure out where the next instruction starts, and whether it
+//     already has enough instructions to replace with the absolute jump
+//     to the patching code.
+//
+// The usage is quite simple; just create a MiniDisassembler and use its
+// Disassemble() method.
+//
+// If you would like to extend this disassembler, please refer to the
+// IA-32 Intel Architecture Software Developer's Manual Volume 2:
+// Instruction Set Reference for information about operand decoding
+// etc.
+class MiniDisassembler {
+ public:
+
+  // Creates a new instance and sets defaults.
+  //
+  // operand_default_32_bits: If true, the default operand size is
+  // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
+  // address_default_32_bits: If true, the default address size is
+  // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
+  MiniDisassembler(bool operand_default_32_bits,
+                   bool address_default_32_bits);
+
+  // Equivalent to MiniDisassembler(true, true);
+  MiniDisassembler();
+
+  // Attempts to disassemble a single instruction starting from the
+  // address in memory it is pointed to.
+  //
+  // start: Address where disassembly should start.
+  // instruction_bytes: Variable that will be incremented by
+  // the length in bytes of the instruction.
+  // Returns enItJump, enItReturn or enItGeneric on success.  enItUnknown
+  // if unable to disassemble, enItUnused if this seems to be an unused
+  // opcode. In the last two (error) cases, cbInstruction will be set
+  // to 0xffffffff.
+  //
+  // Postcondition: This instance of the disassembler is ready to be used again,
+  // with unchanged defaults from creation time.
+  InstructionType Disassemble(unsigned char* start,
+                              unsigned int* instruction_bytes);
+
+ private:
+
+  // Makes the disassembler ready for reuse.
+  void Initialize();
+
+  // Sets the flags for address and operand sizes.
+  // Returns Number of prefix bytes.
+  InstructionType ProcessPrefixes(unsigned char* start, unsigned int* size);
+
+  // Sets the flag for whether we have ModR/M, and increments
+  // operand_bytes_ if any are specifies by the opcode directly.
+  // Returns Number of opcode bytes.
+  InstructionType ProcessOpcode(unsigned char* start,
+                                unsigned int table,
+                                unsigned int* size);
+
+  // Checks the type of the supplied operand.  Increments
+  // operand_bytes_ if it directly indicates an immediate etc.
+  // operand.  Asserts have_modrm_ if the operand specifies
+  // a ModR/M byte.
+  bool ProcessOperand(int flag_operand);
+
+  // Increments operand_bytes_ by size specified by ModR/M and
+  // by SIB if present.
+  // Returns 0 in case of error, 1 if there is just a ModR/M byte,
+  // 2 if there is a ModR/M byte and a SIB byte.
+  bool ProcessModrm(unsigned char* start, unsigned int* size);
+
+  // Processes the SIB byte that it is pointed to.
+  // start: Pointer to the SIB byte.
+  // mod: The mod field from the ModR/M byte.
+  // Returns 1 to indicate success (indicates 1 SIB byte)
+  bool ProcessSib(unsigned char* start, unsigned char mod, unsigned int* size);
+
+  // The instruction type we have decoded from the opcode.
+  InstructionType instruction_type_;
+
+  // Counts the number of bytes that is occupied by operands in
+  // the current instruction (note: we don't care about how large
+  // operands stored in registers etc. are).
+  unsigned int operand_bytes_;
+
+  // True iff there is a ModR/M byte in this instruction.
+  bool have_modrm_;
+
+  // True iff we need to decode the ModR/M byte (sometimes it just
+  // points to a register, we can tell by the addressing mode).
+  bool should_decode_modrm_;
+
+  // Current operand size is 32 bits if true, 16 bits if false.
+  bool operand_is_32_bits_;
+
+  // Default operand size is 32 bits if true, 16 bits if false.
+  bool operand_default_is_32_bits_;
+
+  // Current address size is 32 bits if true, 16 bits if false.
+  bool address_is_32_bits_;
+
+  // Default address size is 32 bits if true, 16 bits if false.
+  bool address_default_is_32_bits_;
+
+  // Huge big opcode table based on the IA-32 manual, defined
+  // in Ia32OpcodeMap.cpp
+  static const OpcodeTable s_ia32_opcode_map_[];
+
+  // Somewhat smaller table to help with decoding ModR/M bytes
+  // when 16-bit addressing mode is being used.  Defined in
+  // Ia32ModrmMap.cpp
+  static const ModrmEntry s_ia16_modrm_map_[];
+
+  // Somewhat smaller table to help with decoding ModR/M bytes
+  // when 32-bit addressing mode is being used.  Defined in
+  // Ia32ModrmMap.cpp
+  static const ModrmEntry s_ia32_modrm_map_[];
+
+  // Indicators of whether we got certain prefixes that certain
+  // silly Intel instructions depend on in nonstandard ways for
+  // their behaviors.
+  bool got_f2_prefix_, got_f3_prefix_, got_66_prefix_;
+};
+
+};  // namespace sidestep
+
+#endif  // SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_H__
diff --git a/sandbox/win/src/sidestep/mini_disassembler_types.h b/sandbox/win/src/sidestep/mini_disassembler_types.h
new file mode 100644
index 0000000..1c10626
--- /dev/null
+++ b/sandbox/win/src/sidestep/mini_disassembler_types.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Several simple types used by the disassembler and some of the patching
+// mechanisms.
+
+#ifndef SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_TYPES_H__
+#define SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_TYPES_H__
+
+namespace sidestep {
+
+// Categories of instructions that we care about
+enum InstructionType {
+  // This opcode is not used
+  IT_UNUSED,
+  // This disassembler does not recognize this opcode (error)
+  IT_UNKNOWN,
+  // This is not an instruction but a reference to another table
+  IT_REFERENCE,
+  // This byte is a prefix byte that we can ignore
+  IT_PREFIX,
+  // This is a prefix byte that switches to the nondefault address size
+  IT_PREFIX_ADDRESS,
+  // This is a prefix byte that switches to the nondefault operand size
+  IT_PREFIX_OPERAND,
+  // A jump or call instruction
+  IT_JUMP,
+  // A return instruction
+  IT_RETURN,
+  // Any other type of instruction (in this case we don't care what it is)
+  IT_GENERIC,
+};
+
+// Lists IA-32 operand sizes in multiples of 8 bits
+enum OperandSize {
+  OS_ZERO = 0,
+  OS_BYTE = 1,
+  OS_WORD = 2,
+  OS_DOUBLE_WORD = 4,
+  OS_QUAD_WORD = 8,
+  OS_DOUBLE_QUAD_WORD = 16,
+  OS_32_BIT_POINTER = 32/8,
+  OS_48_BIT_POINTER = 48/8,
+  OS_SINGLE_PRECISION_FLOATING = 32/8,
+  OS_DOUBLE_PRECISION_FLOATING = 64/8,
+  OS_DOUBLE_EXTENDED_PRECISION_FLOATING = 80/8,
+  OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING = 128/8,
+  OS_PSEUDO_DESCRIPTOR = 6
+};
+
+// Operand addressing methods from the IA-32 manual.  The enAmMask value
+// is a mask for the rest.  The other enumeration values are named for the
+// names given to the addressing methods in the manual, e.g. enAm_D is for
+// the D addressing method.
+//
+// The reason we use a full 4 bytes and a mask, is that we need to combine
+// these flags with the enOperandType to store the details
+// on the operand in a single integer.
+enum AddressingMethod {
+  AM_NOT_USED = 0,        // This operand is not used for this instruction
+  AM_MASK = 0x00FF0000,  // Mask for the rest of the values in this enumeration
+  AM_A = 0x00010000,    // A addressing type
+  AM_C = 0x00020000,    // C addressing type
+  AM_D = 0x00030000,    // D addressing type
+  AM_E = 0x00040000,    // E addressing type
+  AM_F = 0x00050000,    // F addressing type
+  AM_G = 0x00060000,    // G addressing type
+  AM_I = 0x00070000,    // I addressing type
+  AM_J = 0x00080000,    // J addressing type
+  AM_M = 0x00090000,    // M addressing type
+  AM_O = 0x000A0000,    // O addressing type
+  AM_P = 0x000B0000,    // P addressing type
+  AM_Q = 0x000C0000,    // Q addressing type
+  AM_R = 0x000D0000,    // R addressing type
+  AM_S = 0x000E0000,    // S addressing type
+  AM_T = 0x000F0000,    // T addressing type
+  AM_V = 0x00100000,    // V addressing type
+  AM_W = 0x00110000,    // W addressing type
+  AM_X = 0x00120000,    // X addressing type
+  AM_Y = 0x00130000,    // Y addressing type
+  AM_REGISTER = 0x00140000,  // Specific register is always used as this op
+  AM_IMPLICIT = 0x00150000,  // An implicit, fixed value is used
+};
+
+// Operand types from the IA-32 manual. The enOtMask value is
+// a mask for the rest. The rest of the values are named for the
+// names given to these operand types in the manual, e.g. enOt_ps
+// is for the ps operand type in the manual.
+//
+// The reason we use a full 4 bytes and a mask, is that we need
+// to combine these flags with the enAddressingMethod to store the details
+// on the operand in a single integer.
+enum OperandType {
+  OT_MASK = 0xFF000000,
+  OT_A = 0x01000000,
+  OT_B = 0x02000000,
+  OT_C = 0x03000000,
+  OT_D = 0x04000000,
+  OT_DQ = 0x05000000,
+  OT_P = 0x06000000,
+  OT_PI = 0x07000000,
+  OT_PS = 0x08000000,  // actually unsupported for (we don't know its size)
+  OT_Q = 0x09000000,
+  OT_S = 0x0A000000,
+  OT_SS = 0x0B000000,
+  OT_SI = 0x0C000000,
+  OT_V = 0x0D000000,
+  OT_W = 0x0E000000,
+  OT_SD = 0x0F000000,  // scalar double-precision floating-point value
+  OT_PD = 0x10000000,  // double-precision floating point
+  // dummy "operand type" for address mode M - which doesn't specify
+  // operand type
+  OT_ADDRESS_MODE_M = 0x80000000
+};
+
+// Everything that's in an Opcode (see below) except the three
+// alternative opcode structs for different prefixes.
+struct SpecificOpcode {
+  // Index to continuation table, or 0 if this is the last
+  // byte in the opcode.
+  int table_index_;
+
+  // The opcode type
+  InstructionType type_;
+
+  // Description of the type of the dest, src and aux operands,
+  // put together from an enOperandType flag and an enAddressingMethod
+  // flag.
+  int flag_dest_;
+  int flag_source_;
+  int flag_aux_;
+
+  // We indicate the mnemonic for debugging purposes
+  const char* mnemonic_;
+};
+
+// The information we keep in our tables about each of the different
+// valid instructions recognized by the IA-32 architecture.
+struct Opcode {
+  // Index to continuation table, or 0 if this is the last
+  // byte in the opcode.
+  int table_index_;
+
+  // The opcode type
+  InstructionType type_;
+
+  // Description of the type of the dest, src and aux operands,
+  // put together from an enOperandType flag and an enAddressingMethod
+  // flag.
+  int flag_dest_;
+  int flag_source_;
+  int flag_aux_;
+
+  // We indicate the mnemonic for debugging purposes
+  const char* mnemonic_;
+
+  // Alternative opcode info if certain prefixes are specified.
+  // In most cases, all of these are zeroed-out.  Only used if
+  // bPrefixDependent is true.
+  bool is_prefix_dependent_;
+  SpecificOpcode opcode_if_f2_prefix_;
+  SpecificOpcode opcode_if_f3_prefix_;
+  SpecificOpcode opcode_if_66_prefix_;
+};
+
+// Information about each table entry.
+struct OpcodeTable {
+  // Table of instruction entries
+  const Opcode* table_;
+  // How many bytes left to shift ModR/M byte <b>before</b> applying mask
+  unsigned char shift_;
+  // Mask to apply to byte being looked at before comparing to table
+  unsigned char mask_;
+  // Minimum/maximum indexes in table.
+  unsigned char min_lim_;
+  unsigned char max_lim_;
+};
+
+// Information about each entry in table used to decode ModR/M byte.
+struct ModrmEntry {
+  // Is the operand encoded as bytes in the instruction (rather than
+  // if it's e.g. a register in which case it's just encoded in the
+  // ModR/M byte)
+  bool is_encoded_in_instruction_;
+
+  // Is there a SIB byte?  In this case we always need to decode it.
+  bool use_sib_byte_;
+
+  // What is the size of the operand (only important if it's encoded
+  // in the instruction)?
+  OperandSize operand_size_;
+};
+
+};  // namespace sidestep
+
+#endif  // SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_TYPES_H__
diff --git a/sandbox/win/src/sidestep/preamble_patcher.h b/sandbox/win/src/sidestep/preamble_patcher.h
new file mode 100644
index 0000000..3a0985c
--- /dev/null
+++ b/sandbox/win/src/sidestep/preamble_patcher.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Definition of PreamblePatcher
+
+#ifndef SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
+#define SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
+
+#include <stddef.h>
+
+namespace sidestep {
+
+// Maximum size of the preamble stub. We overwrite at least the first 5
+// bytes of the function. Considering the worst case scenario, we need 4
+// bytes + the max instruction size + 5 more bytes for our jump back to
+// the original code. With that in mind, 32 is a good number :)
+const size_t kMaxPreambleStubSize = 32;
+
+// Possible results of patching/unpatching
+enum SideStepError {
+  SIDESTEP_SUCCESS = 0,
+  SIDESTEP_INVALID_PARAMETER,
+  SIDESTEP_INSUFFICIENT_BUFFER,
+  SIDESTEP_JUMP_INSTRUCTION,
+  SIDESTEP_FUNCTION_TOO_SMALL,
+  SIDESTEP_UNSUPPORTED_INSTRUCTION,
+  SIDESTEP_NO_SUCH_MODULE,
+  SIDESTEP_NO_SUCH_FUNCTION,
+  SIDESTEP_ACCESS_DENIED,
+  SIDESTEP_UNEXPECTED,
+};
+
+// Implements a patching mechanism that overwrites the first few bytes of
+// a function preamble with a jump to our hook function, which is then
+// able to call the original function via a specially-made preamble-stub
+// that imitates the action of the original preamble.
+//
+// Note that there are a number of ways that this method of patching can
+// fail.  The most common are:
+//    - If there is a jump (jxx) instruction in the first 5 bytes of
+//    the function being patched, we cannot patch it because in the
+//    current implementation we do not know how to rewrite relative
+//    jumps after relocating them to the preamble-stub.  Note that
+//    if you really really need to patch a function like this, it
+//    would be possible to add this functionality (but at some cost).
+//    - If there is a return (ret) instruction in the first 5 bytes
+//    we cannot patch the function because it may not be long enough
+//    for the jmp instruction we use to inject our patch.
+//    - If there is another thread currently executing within the bytes
+//    that are copied to the preamble stub, it will crash in an undefined
+//    way.
+//
+// If you get any other error than the above, you're either pointing the
+// patcher at an invalid instruction (e.g. into the middle of a multi-
+// byte instruction, or not at memory containing executable instructions)
+// or, there may be a bug in the disassembler we use to find
+// instruction boundaries.
+class PreamblePatcher {
+ public:
+  // Patches target_function to point to replacement_function using a provided
+  // preamble_stub of stub_size bytes.
+  // Returns An error code indicating the result of patching.
+  template <class T>
+  static SideStepError Patch(T target_function, T replacement_function,
+                             void* preamble_stub, size_t stub_size) {
+    return RawPatchWithStub(target_function, replacement_function,
+                            reinterpret_cast<unsigned char*>(preamble_stub),
+                            stub_size, NULL);
+  }
+
+ private:
+
+  // Patches a function by overwriting its first few bytes with
+  // a jump to a different function.  This is similar to the RawPatch
+  // function except that it uses the stub allocated by the caller
+  // instead of allocating it.
+  //
+  // To use this function, you first have to call VirtualProtect to make the
+  // target function writable at least for the duration of the call.
+  //
+  // target_function: A pointer to the function that should be
+  // patched.
+  //
+  // replacement_function: A pointer to the function that should
+  // replace the target function.  The replacement function must have
+  // exactly the same calling convention and parameters as the original
+  // function.
+  //
+  // preamble_stub: A pointer to a buffer where the preamble stub
+  // should be copied. The size of the buffer should be sufficient to
+  // hold the preamble bytes.
+  //
+  // stub_size: Size in bytes of the buffer allocated for the
+  // preamble_stub
+  //
+  // bytes_needed: Pointer to a variable that receives the minimum
+  // number of bytes required for the stub.  Can be set to NULL if you're
+  // not interested.
+  //
+  // Returns An error code indicating the result of patching.
+  static SideStepError RawPatchWithStub(void* target_function,
+                                        void *replacement_function,
+                                        unsigned char* preamble_stub,
+                                        size_t stub_size,
+                                        size_t* bytes_needed);
+};
+
+};  // namespace sidestep
+
+#endif  // SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
diff --git a/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp b/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
new file mode 100644
index 0000000..999d76b
--- /dev/null
+++ b/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Implementation of PreamblePatcher
+
+#include "sandbox/win/src/sidestep/preamble_patcher.h"
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+
+// Definitions of assembly statements we need
+#define ASM_JMP32REL 0xE9
+#define ASM_INT3 0xCC
+
+namespace {
+
+// Very basic memcpy. We are copying 4 to 12 bytes most of the time, so there
+// is no attempt to optimize this code or have a general purpose function.
+// We don't want to call the crt from this code.
+inline void* RawMemcpy(void* destination, const void* source, size_t bytes) {
+  const char* from = reinterpret_cast<const char*>(source);
+  char* to = reinterpret_cast<char*>(destination);
+
+  for (size_t i = 0; i < bytes ; i++)
+    to[i] = from[i];
+
+  return destination;
+}
+
+// Very basic memset. We are filling 1 to 7 bytes most of the time, so there
+// is no attempt to optimize this code or have a general purpose function.
+// We don't want to call the crt from this code.
+inline void* RawMemset(void* destination, int value, size_t bytes) {
+  char* to = reinterpret_cast<char*>(destination);
+
+  for (size_t i = 0; i < bytes ; i++)
+    to[i] = static_cast<char>(value);
+
+  return destination;
+}
+
+}  // namespace
+
+#define ASSERT(a, b) DCHECK_NT(a)
+
+namespace sidestep {
+
+SideStepError PreamblePatcher::RawPatchWithStub(
+    void* target_function,
+    void* replacement_function,
+    unsigned char* preamble_stub,
+    size_t stub_size,
+    size_t* bytes_needed) {
+  if ((NULL == target_function) ||
+      (NULL == replacement_function) ||
+      (NULL == preamble_stub)) {
+    ASSERT(false, (L"Invalid parameters - either pTargetFunction or "
+                   L"pReplacementFunction or pPreambleStub were NULL."));
+    return SIDESTEP_INVALID_PARAMETER;
+  }
+
+  // TODO(V7:joi) Siggi and I just had a discussion and decided that both
+  // patching and unpatching are actually unsafe.  We also discussed a
+  // method of making it safe, which is to freeze all other threads in the
+  // process, check their thread context to see if their eip is currently
+  // inside the block of instructions we need to copy to the stub, and if so
+  // wait a bit and try again, then unfreeze all threads once we've patched.
+  // Not implementing this for now since we're only using SideStep for unit
+  // testing, but if we ever use it for production code this is what we
+  // should do.
+  //
+  // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using
+  // FPU instructions, and on newer processors we could use cmpxchg8b or
+  // cmpxchg16b. So it might be possible to do the patching/unpatching
+  // atomically and avoid having to freeze other threads.  Note though, that
+  // doing it atomically does not help if one of the other threads happens
+  // to have its eip in the middle of the bytes you change while you change
+  // them.
+  unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
+
+  // Let's disassemble the preamble of the target function to see if we can
+  // patch, and to see how much of the preamble we need to take.  We need 5
+  // bytes for our jmp instruction, so let's find the minimum number of
+  // instructions to get 5 bytes.
+  MiniDisassembler disassembler;
+  unsigned int preamble_bytes = 0;
+  while (preamble_bytes < 5) {
+    InstructionType instruction_type =
+      disassembler.Disassemble(target + preamble_bytes, &preamble_bytes);
+    if (IT_JUMP == instruction_type) {
+      ASSERT(false, (L"Unable to patch because there is a jump instruction "
+                     L"in the first 5 bytes."));
+      return SIDESTEP_JUMP_INSTRUCTION;
+    } else if (IT_RETURN == instruction_type) {
+      ASSERT(false, (L"Unable to patch because function is too short"));
+      return SIDESTEP_FUNCTION_TOO_SMALL;
+    } else if (IT_GENERIC != instruction_type) {
+      ASSERT(false, (L"Disassembler encountered unsupported instruction "
+                     L"(either unused or unknown"));
+      return SIDESTEP_UNSUPPORTED_INSTRUCTION;
+    }
+  }
+
+  if (NULL != bytes_needed)
+    *bytes_needed = preamble_bytes + 5;
+
+  // Inv: preamble_bytes is the number of bytes (at least 5) that we need to
+  // take from the preamble to have whole instructions that are 5 bytes or more
+  // in size total. The size of the stub required is cbPreamble + size of
+  // jmp (5)
+  if (preamble_bytes + 5 > stub_size) {
+    NOTREACHED_NT();
+    return SIDESTEP_INSUFFICIENT_BUFFER;
+  }
+
+  // First, copy the preamble that we will overwrite.
+  RawMemcpy(reinterpret_cast<void*>(preamble_stub),
+            reinterpret_cast<void*>(target), preamble_bytes);
+
+  // Now, make a jmp instruction to the rest of the target function (minus the
+  // preamble bytes we moved into the stub) and copy it into our preamble-stub.
+  // find address to jump to, relative to next address after jmp instruction
+#pragma warning(push)
+#pragma warning(disable:4244)
+  // This assignment generates a warning because it is 32 bit specific.
+  int relative_offset_to_target_rest
+    = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
+        (preamble_stub + preamble_bytes + 5));
+#pragma warning(pop)
+  // jmp (Jump near, relative, displacement relative to next instruction)
+  preamble_stub[preamble_bytes] = ASM_JMP32REL;
+  // copy the address
+  RawMemcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1),
+            reinterpret_cast<void*>(&relative_offset_to_target_rest), 4);
+
+  // Inv: preamble_stub points to assembly code that will execute the
+  // original function by first executing the first cbPreamble bytes of the
+  // preamble, then jumping to the rest of the function.
+
+  // Overwrite the first 5 bytes of the target function with a jump to our
+  // replacement function.
+  // (Jump near, relative, displacement relative to next instruction)
+  target[0] = ASM_JMP32REL;
+
+  // Find offset from instruction after jmp, to the replacement function.
+#pragma warning(push)
+#pragma warning(disable:4244)
+  int offset_to_replacement_function =
+    reinterpret_cast<unsigned char*>(replacement_function) -
+    reinterpret_cast<unsigned char*>(target) - 5;
+#pragma warning(pop)
+  // complete the jmp instruction
+  RawMemcpy(reinterpret_cast<void*>(target + 1),
+            reinterpret_cast<void*>(&offset_to_replacement_function), 4);
+  // Set any remaining bytes that were moved to the preamble-stub to INT3 so
+  // as not to cause confusion (otherwise you might see some strange
+  // instructions if you look at the disassembly, or even invalid
+  // instructions). Also, by doing this, we will break into the debugger if
+  // some code calls into this portion of the code.  If this happens, it
+  // means that this function cannot be patched using this patcher without
+  // further thought.
+  if (preamble_bytes > 5) {
+    RawMemset(reinterpret_cast<void*>(target + 5), ASM_INT3,
+              preamble_bytes - 5);
+  }
+
+  // Inv: The memory pointed to by target_function now points to a relative
+  // jump instruction that jumps over to the preamble_stub.  The preamble
+  // stub contains the first stub_size bytes of the original target
+  // function's preamble code, followed by a relative jump back to the next
+  // instruction after the first cbPreamble bytes.
+
+  return SIDESTEP_SUCCESS;
+}
+
+};  // namespace sidestep
+
+#undef ASSERT
diff --git a/sandbox/win/src/sidestep_resolver.cc b/sandbox/win/src/sidestep_resolver.cc
new file mode 100644
index 0000000..828c000
--- /dev/null
+++ b/sandbox/win/src/sidestep_resolver.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sidestep_resolver.h"
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sidestep/preamble_patcher.h"
+
+namespace {
+
+const size_t kSizeOfSidestepStub = sidestep::kMaxPreambleStubSize;
+
+struct SidestepThunk {
+  char sidestep[kSizeOfSidestepStub];  // Storage for the sidestep stub.
+  int internal_thunk;  // Dummy member to the beginning of the internal thunk.
+};
+
+struct SmartThunk {
+  const void* module_base;  // Target module's base.
+  const void* interceptor;  // Real interceptor.
+  SidestepThunk sidestep;  // Standard sidestep thunk.
+};
+
+}  // namespace
+
+namespace sandbox {
+
+NTSTATUS SidestepResolverThunk::Setup(const void* target_module,
+                                      const void* interceptor_module,
+                                      const char* target_name,
+                                      const char* interceptor_name,
+                                      const void* interceptor_entry_point,
+                                      void* thunk_storage,
+                                      size_t storage_bytes,
+                                      size_t* storage_used) {
+  NTSTATUS ret = Init(target_module, interceptor_module, target_name,
+                      interceptor_name, interceptor_entry_point,
+                      thunk_storage, storage_bytes);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  SidestepThunk* thunk = reinterpret_cast<SidestepThunk*>(thunk_storage);
+
+  size_t internal_bytes = storage_bytes - kSizeOfSidestepStub;
+  if (!SetInternalThunk(&thunk->internal_thunk, internal_bytes, thunk_storage,
+                        interceptor_))
+    return STATUS_BUFFER_TOO_SMALL;
+
+  AutoProtectMemory memory;
+  ret = memory.ChangeProtection(target_, kSizeOfSidestepStub, PAGE_READWRITE);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  sidestep::SideStepError rv = sidestep::PreamblePatcher::Patch(
+      target_, reinterpret_cast<void*>(&thunk->internal_thunk), thunk_storage,
+      kSizeOfSidestepStub);
+
+  if (sidestep::SIDESTEP_INSUFFICIENT_BUFFER == rv)
+    return STATUS_BUFFER_TOO_SMALL;
+
+  if (sidestep::SIDESTEP_SUCCESS != rv)
+    return STATUS_UNSUCCESSFUL;
+
+  if (storage_used)
+    *storage_used = GetThunkSize();
+
+  return ret;
+}
+
+size_t SidestepResolverThunk::GetThunkSize() const {
+  return GetInternalThunkSize() + kSizeOfSidestepStub;
+}
+
+// This is basically a wrapper around the normal sidestep patch that extends
+// the thunk to use a chained interceptor. It uses the fact that
+// SetInternalThunk generates the code to pass as the first parameter whatever
+// it receives as original_function; we let SidestepResolverThunk set this value
+// to its saved code, and then we change it to our thunk data.
+NTSTATUS SmartSidestepResolverThunk::Setup(const void* target_module,
+                                           const void* interceptor_module,
+                                           const char* target_name,
+                                           const char* interceptor_name,
+                                           const void* interceptor_entry_point,
+                                           void* thunk_storage,
+                                           size_t storage_bytes,
+                                           size_t* storage_used) {
+  if (storage_bytes < GetThunkSize())
+    return STATUS_BUFFER_TOO_SMALL;
+
+  SmartThunk* thunk = reinterpret_cast<SmartThunk*>(thunk_storage);
+  thunk->module_base = target_module;
+
+  NTSTATUS ret;
+  if (interceptor_entry_point) {
+    thunk->interceptor = interceptor_entry_point;
+  } else {
+    ret = ResolveInterceptor(interceptor_module, interceptor_name,
+                             &thunk->interceptor);
+    if (!NT_SUCCESS(ret))
+      return ret;
+  }
+
+  // Perform a standard sidestep patch on the last part of the thunk, but point
+  // to our internal smart interceptor.
+  size_t standard_bytes = storage_bytes - offsetof(SmartThunk, sidestep);
+  ret = SidestepResolverThunk::Setup(target_module, interceptor_module,
+                                     target_name, NULL, &SmartStub,
+                                     &thunk->sidestep, standard_bytes, NULL);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  // Fix the internal thunk to pass the whole buffer to the interceptor.
+  SetInternalThunk(&thunk->sidestep.internal_thunk, GetInternalThunkSize(),
+                   thunk_storage, &SmartStub);
+
+  if (storage_used)
+    *storage_used = GetThunkSize();
+
+  return ret;
+}
+
+size_t SmartSidestepResolverThunk::GetThunkSize() const {
+  return GetInternalThunkSize() + kSizeOfSidestepStub +
+         offsetof(SmartThunk, sidestep);
+}
+
+// This code must basically either call the intended interceptor or skip the
+// call and invoke instead the original function. In any case, we are saving
+// the registers that may be trashed by our c++ code.
+//
+// This function is called with a first parameter inserted by us, that points
+// to our SmartThunk. When we call the interceptor we have to replace this
+// parameter with the one expected by that function (stored inside our
+// structure); on the other hand, when we skip the interceptor we have to remove
+// that extra argument before calling the original function.
+//
+// When we skip the interceptor, the transformation of the stack looks like:
+//  On Entry:                         On Use:                     On Exit:
+//  [param 2] = first real argument   [param 2] (esp+1c)          [param 2]
+//  [param 1] = our SmartThunk        [param 1] (esp+18)          [ret address]
+//  [ret address] = real caller       [ret address] (esp+14)      [xxx]
+//  [xxx]                             [addr to jump to] (esp+10)  [xxx]
+//  [xxx]                             [saved eax]                 [xxx]
+//  [xxx]                             [saved ebx]                 [xxx]
+//  [xxx]                             [saved ecx]                 [xxx]
+//  [xxx]                             [saved edx]                 [xxx]
+__declspec(naked)
+void SmartSidestepResolverThunk::SmartStub() {
+  __asm {
+    push eax                  // Space for the jump.
+    push eax                  // Save registers.
+    push ebx
+    push ecx
+    push edx
+    mov ebx, [esp + 0x18]     // First parameter = SmartThunk.
+    mov edx, [esp + 0x14]     // Get the return address.
+    mov eax, [ebx]SmartThunk.module_base
+    push edx
+    push eax
+    call SmartSidestepResolverThunk::IsInternalCall
+    add esp, 8
+
+    test eax, eax
+    lea edx, [ebx]SmartThunk.sidestep   // The original function.
+    jz call_interceptor
+
+    // Skip this call
+    mov ecx, [esp + 0x14]               // Return address.
+    mov [esp + 0x18], ecx               // Remove first parameter.
+    mov [esp + 0x10], edx
+    pop edx                             // Restore registers.
+    pop ecx
+    pop ebx
+    pop eax
+    ret 4                               // Jump to original function.
+
+  call_interceptor:
+    mov ecx, [ebx]SmartThunk.interceptor
+    mov [esp + 0x18], edx               // Replace first parameter.
+    mov [esp + 0x10], ecx
+    pop edx                             // Restore registers.
+    pop ecx
+    pop ebx
+    pop eax
+    ret                                 // Jump to original function.
+  }
+}
+
+bool SmartSidestepResolverThunk::IsInternalCall(const void* base,
+                                                void* return_address) {
+  DCHECK_NT(base);
+  DCHECK_NT(return_address);
+
+  base::win::PEImage pe(base);
+  if (pe.GetImageSectionFromAddr(return_address))
+    return true;
+  return false;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sidestep_resolver.h b/sandbox/win/src/sidestep_resolver.h
new file mode 100644
index 0000000..cf03d6e
--- /dev/null
+++ b/sandbox/win/src/sidestep_resolver.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SIDESTEP_RESOLVER_H__
+#define SANDBOX_SRC_SIDESTEP_RESOLVER_H__
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/resolver.h"
+
+namespace sandbox {
+
+// This is the concrete resolver used to perform sidestep interceptions.
+class SidestepResolverThunk : public ResolverThunk {
+ public:
+  SidestepResolverThunk() {}
+  ~SidestepResolverThunk() override {}
+
+  // Implementation of Resolver::Setup.
+  NTSTATUS Setup(const void* target_module,
+                 const void* interceptor_module,
+                 const char* target_name,
+                 const char* interceptor_name,
+                 const void* interceptor_entry_point,
+                 void* thunk_storage,
+                 size_t storage_bytes,
+                 size_t* storage_used) override;
+
+  // Implementation of Resolver::GetThunkSize.
+  size_t GetThunkSize() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SidestepResolverThunk);
+};
+
+// This is the concrete resolver used to perform smart sidestep interceptions.
+// This means basically a sidestep interception that skips the interceptor when
+// the caller resides on the same dll being intercepted. It is intended as
+// a helper only, because that determination is not infallible.
+class SmartSidestepResolverThunk : public SidestepResolverThunk {
+ public:
+  SmartSidestepResolverThunk() {}
+  ~SmartSidestepResolverThunk() override {}
+
+  // Implementation of Resolver::Setup.
+  NTSTATUS Setup(const void* target_module,
+                 const void* interceptor_module,
+                 const char* target_name,
+                 const char* interceptor_name,
+                 const void* interceptor_entry_point,
+                 void* thunk_storage,
+                 size_t storage_bytes,
+                 size_t* storage_used) override;
+
+  // Implementation of Resolver::GetThunkSize.
+  size_t GetThunkSize() const override;
+
+ private:
+  // Performs the actual call to the interceptor if the conditions are correct
+  // (as determined by IsInternalCall).
+  static void SmartStub();
+
+  // Returns true if return_address is inside the module loaded at base.
+  static bool IsInternalCall(const void* base, void* return_address);
+
+  DISALLOW_COPY_AND_ASSIGN(SmartSidestepResolverThunk);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_SIDESTEP_RESOLVER_H__
diff --git a/sandbox/win/src/sync_dispatcher.cc b/sandbox/win/src/sync_dispatcher.cc
new file mode 100644
index 0000000..b83055d
--- /dev/null
+++ b/sandbox/win/src/sync_dispatcher.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sync_dispatcher.h"
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/sync_policy.h"
+
+namespace sandbox {
+
+SyncDispatcher::SyncDispatcher(PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+  static const IPCCall create_params = {
+    {IPC_CREATEEVENT_TAG, WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&SyncDispatcher::CreateEvent)
+  };
+
+  static const IPCCall open_params = {
+    {IPC_OPENEVENT_TAG, WCHAR_TYPE, UINT32_TYPE},
+    reinterpret_cast<CallbackGeneric>(&SyncDispatcher::OpenEvent)
+  };
+
+  ipc_calls_.push_back(create_params);
+  ipc_calls_.push_back(open_params);
+}
+
+bool SyncDispatcher::SetupService(InterceptionManager* manager,
+                                  int service) {
+  if (service == IPC_CREATEEVENT_TAG) {
+    return INTERCEPT_NT(manager, NtCreateEvent, CREATE_EVENT_ID, 24);
+  }
+  return (service == IPC_OPENEVENT_TAG) &&
+      INTERCEPT_NT(manager, NtOpenEvent, OPEN_EVENT_ID, 16);
+}
+
+bool SyncDispatcher::CreateEvent(IPCInfo* ipc,
+                                 base::string16* name,
+                                 uint32 event_type,
+                                 uint32 initial_state) {
+  const wchar_t* event_name = name->c_str();
+  CountedParameterSet<NameBased> params;
+  params[NameBased::NAME] = ParamPickerMake(event_name);
+
+  EvalResult result = policy_base_->EvalPolicy(IPC_CREATEEVENT_TAG,
+                                               params.GetBase());
+  HANDLE handle = NULL;
+  // Return operation status on the IPC.
+  ipc->return_info.nt_status = SyncPolicy::CreateEventAction(
+      result, *ipc->client_info, *name, event_type, initial_state, &handle);
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+bool SyncDispatcher::OpenEvent(IPCInfo* ipc,
+                               base::string16* name,
+                               uint32 desired_access) {
+  const wchar_t* event_name = name->c_str();
+
+  CountedParameterSet<OpenEventParams> params;
+  params[OpenEventParams::NAME] = ParamPickerMake(event_name);
+  params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
+
+  EvalResult result = policy_base_->EvalPolicy(IPC_OPENEVENT_TAG,
+                                               params.GetBase());
+  HANDLE handle = NULL;
+  // Return operation status on the IPC.
+  ipc->return_info.nt_status = SyncPolicy::OpenEventAction(
+      result, *ipc->client_info, *name, desired_access, &handle);
+  ipc->return_info.handle = handle;
+  return true;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sync_dispatcher.h b/sandbox/win/src/sync_dispatcher.h
new file mode 100644
index 0000000..29c6c1e
--- /dev/null
+++ b/sandbox/win/src/sync_dispatcher.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SYNC_DISPATCHER_H_
+#define SANDBOX_SRC_SYNC_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles sync-related IPC calls.
+class SyncDispatcher : public Dispatcher {
+ public:
+  explicit SyncDispatcher(PolicyBase* policy_base);
+  ~SyncDispatcher() override {}
+
+  // Dispatcher interface.
+  bool SetupService(InterceptionManager* manager, int service) override;
+
+private:
+  // Processes IPC requests coming from calls to CreateEvent in the target.
+  bool CreateEvent(IPCInfo* ipc,
+                   base::string16* name,
+                   uint32 event_type,
+                   uint32 initial_state);
+
+  // Processes IPC requests coming from calls to OpenEvent in the target.
+  bool OpenEvent(IPCInfo* ipc, base::string16* name, uint32 desired_access);
+
+  PolicyBase* policy_base_;
+  DISALLOW_COPY_AND_ASSIGN(SyncDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SYNC_DISPATCHER_H_
diff --git a/sandbox/win/src/sync_interception.cc b/sandbox/win/src/sync_interception.cc
new file mode 100644
index 0000000..da612a5
--- /dev/null
+++ b/sandbox/win/src/sync_interception.cc
@@ -0,0 +1,161 @@
+// 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 "sandbox/win/src/sync_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+ResultCode ProxyCreateEvent(LPCWSTR name,
+                            uint32 initial_state,
+                            EVENT_TYPE event_type,
+                            void* ipc_memory,
+                            CrossCallReturn* answer) {
+  CountedParameterSet<NameBased> params;
+  params[NameBased::NAME] = ParamPickerMake(name);
+
+  if (!QueryBroker(IPC_CREATEEVENT_TAG, params.GetBase()))
+    return SBOX_ERROR_GENERIC;
+
+  SharedMemIPCClient ipc(ipc_memory);
+  ResultCode code = CrossCall(ipc, IPC_CREATEEVENT_TAG, name, event_type,
+                              initial_state, answer);
+  return code;
+}
+
+ResultCode ProxyOpenEvent(LPCWSTR name,
+                          uint32 desired_access,
+                          void* ipc_memory,
+                          CrossCallReturn* answer) {
+  CountedParameterSet<OpenEventParams> params;
+  params[OpenEventParams::NAME] = ParamPickerMake(name);
+  params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
+
+  if (!QueryBroker(IPC_OPENEVENT_TAG, params.GetBase()))
+    return SBOX_ERROR_GENERIC;
+
+  SharedMemIPCClient ipc(ipc_memory);
+  ResultCode code = CrossCall(ipc, IPC_OPENEVENT_TAG, name, desired_access,
+                              answer);
+
+  return code;
+}
+
+NTSTATUS WINAPI TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent,
+                                    PHANDLE event_handle,
+                                    ACCESS_MASK desired_access,
+                                    POBJECT_ATTRIBUTES object_attributes,
+                                    EVENT_TYPE event_type,
+                                    BOOLEAN initial_state) {
+  NTSTATUS status = orig_CreateEvent(event_handle, desired_access,
+                                     object_attributes, event_type,
+                                     initial_state);
+  if (status != STATUS_ACCESS_DENIED || !object_attributes)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  do {
+    if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (memory == NULL)
+      break;
+
+    OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
+    // The RootDirectory points to BaseNamedObjects. We can ignore it.
+    object_attribs_copy.RootDirectory = NULL;
+
+    wchar_t* name = NULL;
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(&object_attribs_copy, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || name == NULL)
+      break;
+
+    CrossCallReturn answer = {0};
+    answer.nt_status = status;
+    ResultCode code = ProxyCreateEvent(name, initial_state, event_type, memory,
+                                       &answer);
+    operator delete(name, NT_ALLOC);
+
+    if (code != SBOX_ALL_OK) {
+      status = answer.nt_status;
+      break;
+    }
+    __try {
+      *event_handle = answer.handle;
+      status = STATUS_SUCCESS;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent,
+                                  PHANDLE event_handle,
+                                  ACCESS_MASK desired_access,
+                                  POBJECT_ATTRIBUTES object_attributes) {
+  NTSTATUS status = orig_OpenEvent(event_handle, desired_access,
+                                   object_attributes);
+  if (status != STATUS_ACCESS_DENIED || !object_attributes)
+    return status;
+
+  // We don't trust that the IPC can work this early.
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return status;
+
+  do {
+    if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
+      break;
+
+    void* memory = GetGlobalIPCMemory();
+    if (memory == NULL)
+      break;
+
+    OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
+    // The RootDirectory points to BaseNamedObjects. We can ignore it.
+    object_attribs_copy.RootDirectory = NULL;
+
+    wchar_t* name = NULL;
+    uint32 attributes = 0;
+    NTSTATUS ret = AllocAndCopyName(&object_attribs_copy, &name, &attributes,
+                                    NULL);
+    if (!NT_SUCCESS(ret) || name == NULL)
+      break;
+
+    CrossCallReturn answer = {0};
+    answer.nt_status = status;
+    ResultCode code = ProxyOpenEvent(name, desired_access, memory, &answer);
+    operator delete(name, NT_ALLOC);
+
+    if (code != SBOX_ALL_OK) {
+      status = answer.nt_status;
+      break;
+    }
+    __try {
+      *event_handle = answer.handle;
+      status = STATUS_SUCCESS;
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+      break;
+    }
+  } while (false);
+
+  return status;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sync_interception.h b/sandbox/win/src/sync_interception.h
new file mode 100644
index 0000000..0f985a8
--- /dev/null
+++ b/sandbox/win/src/sync_interception.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_SYNC_INTERCEPTION_H__
+#define SANDBOX_SRC_SYNC_INTERCEPTION_H__
+
+namespace sandbox {
+
+extern "C" {
+
+typedef NTSTATUS (WINAPI* NtCreateEventFunction) (
+    PHANDLE EventHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes,
+    EVENT_TYPE EventType,
+    BOOLEAN InitialState);
+
+typedef NTSTATUS (WINAPI *NtOpenEventFunction) (
+    PHANDLE EventHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+// Interceptors for NtCreateEvent/NtOpenEvent
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateEvent(
+    NtCreateEventFunction orig_CreateEvent,
+    PHANDLE event_handle,
+    ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes,
+    EVENT_TYPE event_type,
+    BOOLEAN initial_state);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenEvent(
+    NtOpenEventFunction orig_OpenEvent,
+    PHANDLE event_handle,
+    ACCESS_MASK desired_access,
+    POBJECT_ATTRIBUTES object_attributes);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SYNC_INTERCEPTION_H__
diff --git a/sandbox/win/src/sync_policy.cc b/sandbox/win/src/sync_policy.cc
new file mode 100644
index 0000000..607b446
--- /dev/null
+++ b/sandbox/win/src/sync_policy.cc
@@ -0,0 +1,254 @@
+// 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 <string>
+
+#include "sandbox/win/src/sync_policy.h"
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+// Provides functionality to resolve a symbolic link within the object
+// directory passed in.
+NTSTATUS ResolveSymbolicLink(const base::string16& directory_name,
+                             const base::string16& name,
+                             base::string16* target) {
+  NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL;
+  ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
+
+  NtQuerySymbolicLinkObjectFunction NtQuerySymbolicLinkObject = NULL;
+  ResolveNTFunctionPtr("NtQuerySymbolicLinkObject",
+                       &NtQuerySymbolicLinkObject);
+
+  NtOpenSymbolicLinkObjectFunction NtOpenSymbolicLinkObject = NULL;
+  ResolveNTFunctionPtr("NtOpenSymbolicLinkObject", &NtOpenSymbolicLinkObject);
+
+  NtCloseFunction NtClose = NULL;
+  ResolveNTFunctionPtr("NtClose", &NtClose);
+
+  OBJECT_ATTRIBUTES symbolic_link_directory_attributes = {};
+  UNICODE_STRING symbolic_link_directory_string = {};
+  InitObjectAttribs(directory_name, OBJ_CASE_INSENSITIVE, NULL,
+                    &symbolic_link_directory_attributes,
+                    &symbolic_link_directory_string, NULL);
+
+  HANDLE symbolic_link_directory = NULL;
+  NTSTATUS status = NtOpenDirectoryObject(&symbolic_link_directory,
+                                          DIRECTORY_QUERY,
+                                          &symbolic_link_directory_attributes);
+  if (status != STATUS_SUCCESS) {
+    DLOG(ERROR) << "Failed to open symbolic link directory. Error: "
+                << status;
+    return status;
+  }
+
+  OBJECT_ATTRIBUTES symbolic_link_attributes = {};
+  UNICODE_STRING name_string = {};
+  InitObjectAttribs(name, OBJ_CASE_INSENSITIVE, symbolic_link_directory,
+                    &symbolic_link_attributes, &name_string, NULL);
+
+  HANDLE symbolic_link = NULL;
+  status = NtOpenSymbolicLinkObject(&symbolic_link, GENERIC_READ,
+                                    &symbolic_link_attributes);
+  NtClose(symbolic_link_directory);
+  if (status != STATUS_SUCCESS) {
+    DLOG(ERROR) << "Failed to open symbolic link Error: " << status;
+    return status;
+  }
+
+  UNICODE_STRING target_path = {};
+  unsigned long target_length = 0;
+  status = NtQuerySymbolicLinkObject(symbolic_link, &target_path,
+                                     &target_length);
+  if (status != STATUS_BUFFER_TOO_SMALL) {
+    NtClose(symbolic_link);
+    DLOG(ERROR) << "Failed to get length for symbolic link target. Error: "
+                << status;
+    return status;
+  }
+
+  target_path.Length = 0;
+  target_path.MaximumLength = static_cast<USHORT>(target_length);
+  target_path.Buffer = new wchar_t[target_path.MaximumLength + 1];
+  status = NtQuerySymbolicLinkObject(symbolic_link, &target_path,
+                                     &target_length);
+  if (status == STATUS_SUCCESS) {
+    target->assign(target_path.Buffer, target_length);
+  } else {
+    DLOG(ERROR) << "Failed to resolve symbolic link. Error: " << status;
+  }
+
+  NtClose(symbolic_link);
+  delete[] target_path.Buffer;
+  return status;
+}
+
+NTSTATUS GetBaseNamedObjectsDirectory(HANDLE* directory) {
+  static HANDLE base_named_objects_handle = NULL;
+  if (base_named_objects_handle) {
+    *directory = base_named_objects_handle;
+    return STATUS_SUCCESS;
+  }
+
+  NtOpenDirectoryObjectFunction NtOpenDirectoryObject = NULL;
+  ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
+
+  DWORD session_id = 0;
+  ProcessIdToSessionId(::GetCurrentProcessId(), &session_id);
+
+  base::string16 base_named_objects_path;
+
+  NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS",
+                                        base::StringPrintf(L"%d", session_id),
+                                        &base_named_objects_path);
+  if (status != STATUS_SUCCESS) {
+    DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: "
+                << status;
+    return status;
+  }
+
+  UNICODE_STRING directory_name = {};
+  OBJECT_ATTRIBUTES object_attributes = {};
+  InitObjectAttribs(base_named_objects_path, OBJ_CASE_INSENSITIVE, NULL,
+                    &object_attributes, &directory_name, NULL);
+  status = NtOpenDirectoryObject(&base_named_objects_handle,
+                                 DIRECTORY_ALL_ACCESS,
+                                 &object_attributes);
+  if (status == STATUS_SUCCESS)
+    *directory = base_named_objects_handle;
+  return status;
+}
+
+bool SyncPolicy::GenerateRules(const wchar_t* name,
+                               TargetPolicy::Semantics semantics,
+                               LowLevelPolicy* policy) {
+  base::string16 mod_name(name);
+  if (mod_name.empty()) {
+    return false;
+  }
+
+  if (TargetPolicy::EVENTS_ALLOW_ANY != semantics &&
+      TargetPolicy::EVENTS_ALLOW_READONLY != semantics) {
+    // Other flags are not valid for sync policy yet.
+    NOTREACHED();
+    return false;
+  }
+
+  // Add the open rule.
+  EvalResult result = ASK_BROKER;
+  PolicyRule open(result);
+
+  if (!open.AddStringMatch(IF, OpenEventParams::NAME, name, CASE_INSENSITIVE))
+    return false;
+
+  if (TargetPolicy::EVENTS_ALLOW_READONLY == semantics) {
+    // We consider all flags that are not known to be readonly as potentially
+    // used for write.
+    uint32 allowed_flags = SYNCHRONIZE | GENERIC_READ | READ_CONTROL;
+    uint32 restricted_flags = ~allowed_flags;
+    open.AddNumberMatch(IF_NOT, OpenEventParams::ACCESS, restricted_flags, AND);
+  }
+
+  if (!policy->AddRule(IPC_OPENEVENT_TAG, &open))
+    return false;
+
+  // If it's not a read only, add the create rule.
+  if (TargetPolicy::EVENTS_ALLOW_READONLY != semantics) {
+    PolicyRule create(result);
+    if (!create.AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE))
+      return false;
+
+    if (!policy->AddRule(IPC_CREATEEVENT_TAG, &create))
+      return false;
+  }
+
+  return true;
+}
+
+NTSTATUS SyncPolicy::CreateEventAction(EvalResult eval_result,
+                                       const ClientInfo& client_info,
+                                       const base::string16 &event_name,
+                                       uint32 event_type,
+                                       uint32 initial_state,
+                                       HANDLE *handle) {
+  NtCreateEventFunction NtCreateEvent = NULL;
+  ResolveNTFunctionPtr("NtCreateEvent", &NtCreateEvent);
+
+  // The only action supported is ASK_BROKER which means create the requested
+  // file as specified.
+  if (ASK_BROKER != eval_result)
+    return false;
+
+  HANDLE object_directory = NULL;
+  NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
+  if (status != STATUS_SUCCESS)
+    return status;
+
+  UNICODE_STRING unicode_event_name = {};
+  OBJECT_ATTRIBUTES object_attributes = {};
+  InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
+                    &object_attributes, &unicode_event_name, NULL);
+
+  HANDLE local_handle = NULL;
+  status = NtCreateEvent(&local_handle, EVENT_ALL_ACCESS, &object_attributes,
+                         static_cast<EVENT_TYPE>(event_type),
+                         static_cast<BOOLEAN>(initial_state));
+  if (NULL == local_handle)
+    return status;
+
+  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                         client_info.process, handle, 0, FALSE,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return STATUS_ACCESS_DENIED;
+  }
+  return status;
+}
+
+NTSTATUS SyncPolicy::OpenEventAction(EvalResult eval_result,
+                                     const ClientInfo& client_info,
+                                     const base::string16 &event_name,
+                                     uint32 desired_access,
+                                     HANDLE *handle) {
+  NtOpenEventFunction NtOpenEvent = NULL;
+  ResolveNTFunctionPtr("NtOpenEvent", &NtOpenEvent);
+
+  // The only action supported is ASK_BROKER which means create the requested
+  // event as specified.
+  if (ASK_BROKER != eval_result)
+    return false;
+
+  HANDLE object_directory = NULL;
+  NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
+  if (status != STATUS_SUCCESS)
+    return status;
+
+  UNICODE_STRING unicode_event_name = {};
+  OBJECT_ATTRIBUTES object_attributes = {};
+  InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
+                    &object_attributes, &unicode_event_name, NULL);
+
+  HANDLE local_handle = NULL;
+  status = NtOpenEvent(&local_handle, desired_access, &object_attributes);
+  if (NULL == local_handle)
+    return status;
+
+  if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+                         client_info.process, handle, 0, FALSE,
+                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+    return STATUS_ACCESS_DENIED;
+  }
+  return status;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sync_policy.h b/sandbox/win/src/sync_policy.h
new file mode 100644
index 0000000..e370e4b
--- /dev/null
+++ b/sandbox/win/src/sync_policy.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SYNC_POLICY_H__
+#define SANDBOX_SRC_SYNC_POLICY_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to sync policy
+class SyncPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule for sync calls, in particular open or create actions.
+  // name is the sync object name, semantics is the desired semantics for the
+  // open or create and policy is the policy generator to which the rules are
+  // going to be added.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+
+  // Performs the desired policy action on a request.
+  // client_info is the target process that is making the request and
+  // eval_result is the desired policy action to accomplish.
+  static NTSTATUS CreateEventAction(EvalResult eval_result,
+                                    const ClientInfo& client_info,
+                                    const base::string16 &event_name,
+                                    uint32 event_type,
+                                    uint32 initial_state,
+                                    HANDLE *handle);
+  static NTSTATUS OpenEventAction(EvalResult eval_result,
+                                  const ClientInfo& client_info,
+                                  const base::string16 &event_name,
+                                  uint32 desired_access,
+                                  HANDLE *handle);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SYNC_POLICY_H__
diff --git a/sandbox/win/src/sync_policy_test.cc b/sandbox/win/src/sync_policy_test.cc
new file mode 100644
index 0000000..9fc08f4
--- /dev/null
+++ b/sandbox/win/src/sync_policy_test.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sync_policy_test.h"
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t **argv) {
+  if (argc != 2)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  DWORD desired_access = SYNCHRONIZE;
+  if (L'f' == argv[0][0])
+    desired_access = EVENT_ALL_ACCESS;
+
+  base::win::ScopedHandle event_open(::OpenEvent(
+      desired_access, FALSE, argv[1]));
+  DWORD error_open = ::GetLastError();
+
+  if (event_open.IsValid())
+    return SBOX_TEST_SUCCEEDED;
+
+  if (ERROR_ACCESS_DENIED == error_open ||
+      ERROR_BAD_PATHNAME == error_open ||
+      ERROR_FILE_NOT_FOUND == error_open)
+    return SBOX_TEST_DENIED;
+
+  return SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int Event_CreateOpen(int argc, wchar_t **argv) {
+  if (argc < 2 || argc > 3)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  wchar_t *event_name = NULL;
+  if (3 == argc)
+    event_name = argv[2];
+
+  BOOL manual_reset = FALSE;
+  BOOL initial_state = FALSE;
+  if (L't' == argv[0][0])
+    manual_reset = TRUE;
+  if (L't' == argv[1][0])
+    initial_state = TRUE;
+
+  base::win::ScopedHandle event_create(::CreateEvent(
+      NULL, manual_reset, initial_state, event_name));
+  DWORD error_create = ::GetLastError();
+  base::win::ScopedHandle event_open;
+  if (event_name)
+    event_open.Set(::OpenEvent(EVENT_ALL_ACCESS, FALSE, event_name));
+
+  if (event_create.IsValid()) {
+    DWORD wait = ::WaitForSingleObject(event_create.Get(), 0);
+    if (initial_state && WAIT_OBJECT_0 != wait)
+      return SBOX_TEST_FAILED;
+
+    if (!initial_state && WAIT_TIMEOUT != wait)
+      return SBOX_TEST_FAILED;
+  }
+
+  if (event_name) {
+    // Both event_open and event_create have to be valid.
+    if (event_open.IsValid() && event_create.IsValid())
+      return SBOX_TEST_SUCCEEDED;
+
+    if (event_open.IsValid() && !event_create.IsValid() ||
+        !event_open.IsValid() && event_create.IsValid())
+      return SBOX_TEST_FAILED;
+  } else {
+    // Only event_create has to be valid.
+    if (event_create.Get())
+      return SBOX_TEST_SUCCEEDED;
+  }
+
+  if (ERROR_ACCESS_DENIED == error_create ||
+      ERROR_BAD_PATHNAME == error_create)
+    return SBOX_TEST_DENIED;
+
+  return SBOX_TEST_FAILED;
+}
+
+// Tests the creation of events using all the possible combinations.
+TEST(SyncPolicyTest, DISABLED_TestEvent) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_ANY,
+                             L"test1"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_ANY,
+                             L"test2"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f t"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t t"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f test1"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f test2"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f t test1"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t t test2"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f f test3"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t f test4"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f t test3"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t t test4"));
+}
+
+// Tests opening events with read only access.
+TEST(SyncPolicyTest, DISABLED_TestEventReadOnly) {
+  TestRunner runner;
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_READONLY,
+                             L"test1"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_READONLY,
+                             L"test2"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_READONLY,
+                             L"test5"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_READONLY,
+                             L"test6"));
+
+  base::win::ScopedHandle handle1(::CreateEvent(NULL, FALSE, FALSE, L"test1"));
+  base::win::ScopedHandle handle2(::CreateEvent(NULL, FALSE, FALSE, L"test2"));
+  base::win::ScopedHandle handle3(::CreateEvent(NULL, FALSE, FALSE, L"test3"));
+  base::win::ScopedHandle handle4(::CreateEvent(NULL, FALSE, FALSE, L"test4"));
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test1"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_Open s test2"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test3"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open s test4"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f f test5"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t f test6"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f t test5"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t t test6"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/sync_policy_test.h b/sandbox/win/src/sync_policy_test.h
new file mode 100644
index 0000000..4f354b3
--- /dev/null
+++ b/sandbox/win/src/sync_policy_test.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 SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
+#define SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
+
+#include "sandbox/win/tests/common/controller.h"
+
+namespace sandbox {
+
+// Opens the named event received on argv[1]. The requested access is
+// EVENT_ALL_ACCESS if argv[0] starts with 'f', or SYNCHRONIZE otherwise.
+SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t **argv);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
diff --git a/sandbox/win/src/target_interceptions.cc b/sandbox/win/src/target_interceptions.cc
new file mode 100644
index 0000000..e6b0dcf
--- /dev/null
+++ b/sandbox/win/src/target_interceptions.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 "sandbox/win/src/target_interceptions.h"
+
+#include "sandbox/win/src/interception_agent.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Hooks NtMapViewOfSection to detect the load of DLLs. If hot patching is
+// required for this dll, this functions patches it.
+NTSTATUS WINAPI TargetNtMapViewOfSection(
+    NtMapViewOfSectionFunction orig_MapViewOfSection, HANDLE section,
+    HANDLE process, PVOID *base, ULONG_PTR zero_bits, SIZE_T commit_size,
+    PLARGE_INTEGER offset, PSIZE_T view_size, SECTION_INHERIT inherit,
+    ULONG allocation_type, ULONG protect) {
+  NTSTATUS ret = orig_MapViewOfSection(section, process, base, zero_bits,
+                                       commit_size, offset, view_size, inherit,
+                                       allocation_type, protect);
+
+  static int s_load_count = 0;
+  if (1 == s_load_count) {
+    SandboxFactory::GetTargetServices()->GetState()->SetKernel32Loaded();
+    s_load_count = 2;
+  }
+
+  do {
+    if (!NT_SUCCESS(ret))
+      break;
+
+    if (!InitHeap())
+      break;
+
+    if (!IsSameProcess(process))
+      break;
+
+    if (!IsValidImageSection(section, base, offset, view_size))
+      break;
+
+    UINT image_flags;
+    UNICODE_STRING* module_name =
+        GetImageInfoFromModule(reinterpret_cast<HMODULE>(*base), &image_flags);
+    UNICODE_STRING* file_name = GetBackingFilePath(*base);
+
+    if ((!module_name) && (image_flags & MODULE_HAS_CODE)) {
+      // If the module has no exports we retrieve the module name from the
+      // full path of the mapped section.
+      module_name = ExtractModuleName(file_name);
+    }
+
+    InterceptionAgent* agent = InterceptionAgent::GetInterceptionAgent();
+
+    if (agent) {
+      if (!agent->OnDllLoad(file_name, module_name, *base)) {
+        // Interception agent is demanding to un-map the module.
+        g_nt.UnmapViewOfSection(process, *base);
+        ret = STATUS_UNSUCCESSFUL;
+      }
+    }
+
+    if (module_name)
+      operator delete(module_name, NT_ALLOC);
+
+    if (file_name)
+      operator delete(file_name, NT_ALLOC);
+
+  } while (false);
+
+  if (!s_load_count)
+    s_load_count = 1;
+
+  return ret;
+}
+
+NTSTATUS WINAPI TargetNtUnmapViewOfSection(
+    NtUnmapViewOfSectionFunction orig_UnmapViewOfSection, HANDLE process,
+    PVOID base) {
+  NTSTATUS ret = orig_UnmapViewOfSection(process, base);
+
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  if (!IsSameProcess(process))
+    return ret;
+
+  InterceptionAgent* agent = InterceptionAgent::GetInterceptionAgent();
+
+  if (agent)
+    agent->OnDllUnload(base);
+
+  return ret;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/target_interceptions.h b/sandbox/win/src/target_interceptions.h
new file mode 100644
index 0000000..f4805fe
--- /dev/null
+++ b/sandbox/win/src/target_interceptions.h
@@ -0,0 +1,35 @@
+// 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 "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_TARGET_INTERCEPTIONS_H__
+#define SANDBOX_SRC_TARGET_INTERCEPTIONS_H__
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtMapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtMapViewOfSection(
+    NtMapViewOfSectionFunction orig_MapViewOfSection, HANDLE section,
+    HANDLE process, PVOID *base, ULONG_PTR zero_bits, SIZE_T commit_size,
+    PLARGE_INTEGER offset, PSIZE_T view_size, SECTION_INHERIT inherit,
+    ULONG allocation_type, ULONG protect);
+
+// Interception of NtUnmapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being unloaded, so we can clean up our interceptions.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtUnmapViewOfSection(
+    NtUnmapViewOfSectionFunction orig_UnmapViewOfSection, HANDLE process,
+    PVOID base);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_TARGET_INTERCEPTIONS_H__
diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc
new file mode 100644
index 0000000..e0284c3
--- /dev/null
+++ b/sandbox/win/src/target_process.cc
@@ -0,0 +1,385 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/target_process.h"
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/pe_image.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+void CopyPolicyToTarget(const void* source, size_t size, void* dest) {
+  if (!source || !size)
+    return;
+  memcpy(dest, source, size);
+  sandbox::PolicyGlobal* policy =
+      reinterpret_cast<sandbox::PolicyGlobal*>(dest);
+
+  size_t offset = reinterpret_cast<size_t>(source);
+
+  for (size_t i = 0; i < sandbox::kMaxServiceCount; i++) {
+    size_t buffer = reinterpret_cast<size_t>(policy->entry[i]);
+    if (buffer) {
+      buffer -= offset;
+      policy->entry[i] = reinterpret_cast<sandbox::PolicyBuffer*>(buffer);
+    }
+  }
+}
+
+}
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT HANDLE g_shared_section;
+SANDBOX_INTERCEPT size_t g_shared_IPC_size;
+SANDBOX_INTERCEPT size_t g_shared_policy_size;
+
+// Returns the address of the main exe module in memory taking in account
+// address space layout randomization.
+void* GetBaseAddress(const wchar_t* exe_name, void* entry_point) {
+  HMODULE exe = ::LoadLibrary(exe_name);
+  if (NULL == exe)
+    return exe;
+
+  base::win::PEImage pe(exe);
+  if (!pe.VerifyMagic()) {
+    ::FreeLibrary(exe);
+    return exe;
+  }
+  PIMAGE_NT_HEADERS nt_header = pe.GetNTHeaders();
+  char* base = reinterpret_cast<char*>(entry_point) -
+    nt_header->OptionalHeader.AddressOfEntryPoint;
+
+  ::FreeLibrary(exe);
+  return base;
+}
+
+
+TargetProcess::TargetProcess(HANDLE initial_token, HANDLE lockdown_token,
+                             HANDLE job, ThreadProvider* thread_pool)
+  // This object owns everything initialized here except thread_pool and
+  // the job_ handle. The Job handle is closed by BrokerServices and results
+  // eventually in a call to our dtor.
+    : lockdown_token_(lockdown_token),
+      initial_token_(initial_token),
+      job_(job),
+      thread_pool_(thread_pool),
+      base_address_(NULL) {
+}
+
+TargetProcess::~TargetProcess() {
+  DWORD exit_code = 0;
+  // Give a chance to the process to die. In most cases the JOB_KILL_ON_CLOSE
+  // will take effect only when the context changes. As far as the testing went,
+  // this wait was enough to switch context and kill the processes in the job.
+  // If this process is already dead, the function will return without waiting.
+  // TODO(nsylvain):  If the process is still alive at the end, we should kill
+  // it. http://b/893891
+  // For now, this wait is there only to do a best effort to prevent some leaks
+  // from showing up in purify.
+  if (sandbox_process_info_.IsValid()) {
+    ::WaitForSingleObject(sandbox_process_info_.process_handle(), 50);
+    // At this point, the target process should have been killed.  Check.
+    if (!::GetExitCodeProcess(sandbox_process_info_.process_handle(),
+                              &exit_code) || (STILL_ACTIVE == exit_code)) {
+      // Something went wrong.  We don't know if the target is in a state where
+      // it can manage to do another IPC call.  If it can, and we've destroyed
+      // the |ipc_server_|, it will crash the broker.  So we intentionally leak
+      // that.
+      if (shared_section_.IsValid())
+        shared_section_.Take();
+      ipc_server_.release();
+      sandbox_process_info_.TakeProcessHandle();
+      return;
+    }
+  }
+
+  // ipc_server_ references our process handle, so make sure the former is shut
+  // down before the latter is closed (by ScopedProcessInformation).
+  ipc_server_.reset();
+}
+
+// Creates the target (child) process suspended and assigns it to the job
+// object.
+DWORD TargetProcess::Create(const wchar_t* exe_path,
+                            const wchar_t* command_line,
+                            bool inherit_handles,
+                            bool set_lockdown_token_after_create,
+                            const base::win::StartupInformation& startup_info,
+                            base::win::ScopedProcessInformation* target_info) {
+  if (set_lockdown_token_after_create &&
+      base::win::GetVersion() < base::win::VERSION_WIN8) {
+    // We don't allow set_lockdown_token_after_create below Windows 8.
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  exe_name_.reset(_wcsdup(exe_path));
+
+  // the command line needs to be writable by CreateProcess().
+  scoped_ptr<wchar_t, base::FreeDeleter> cmd_line(_wcsdup(command_line));
+
+  // Start the target process suspended.
+  DWORD flags =
+      CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
+
+  if (startup_info.has_extended_startup_info())
+    flags |= EXTENDED_STARTUPINFO_PRESENT;
+
+  if (job_ && base::win::GetVersion() < base::win::VERSION_WIN8) {
+    // Windows 8 implements nested jobs, but for older systems we need to
+    // break out of any job we're in to enforce our restrictions.
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+  }
+
+  base::win::ScopedHandle scoped_lockdown_token(lockdown_token_.Take());
+  PROCESS_INFORMATION temp_process_info = {};
+  if (set_lockdown_token_after_create) {
+    // First create process with a default token and then replace it later,
+    // after setting primary thread token. This is required for setting
+    // an AppContainer token along with an impersonation token.
+    if (!::CreateProcess(exe_path,
+                         cmd_line.get(),
+                         NULL,   // No security attribute.
+                         NULL,   // No thread attribute.
+                         inherit_handles,
+                         flags,
+                         NULL,   // Use the environment of the caller.
+                         NULL,   // Use current directory of the caller.
+                         startup_info.startup_info(),
+                         &temp_process_info)) {
+      return ::GetLastError();
+    }
+  } else {
+    if (!::CreateProcessAsUserW(scoped_lockdown_token.Get(),
+                                exe_path,
+                                cmd_line.get(),
+                                NULL,   // No security attribute.
+                                NULL,   // No thread attribute.
+                                inherit_handles,
+                                flags,
+                                NULL,   // Use the environment of the caller.
+                                NULL,   // Use current directory of the caller.
+                                startup_info.startup_info(),
+                                &temp_process_info)) {
+      return ::GetLastError();
+    }
+  }
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  DWORD win_result = ERROR_SUCCESS;
+
+  if (job_) {
+    // Assign the suspended target to the windows job object.
+    if (!::AssignProcessToJobObject(job_, process_info.process_handle())) {
+      win_result = ::GetLastError();
+      ::TerminateProcess(process_info.process_handle(), 0);
+      return win_result;
+    }
+  }
+
+  if (initial_token_.IsValid()) {
+    // Change the token of the main thread of the new process for the
+    // impersonation token with more rights. This allows the target to start;
+    // otherwise it will crash too early for us to help.
+    HANDLE temp_thread = process_info.thread_handle();
+    if (!::SetThreadToken(&temp_thread, initial_token_.Get())) {
+      win_result = ::GetLastError();
+      // It might be a security breach if we let the target run outside the job
+      // so kill it before it causes damage.
+      ::TerminateProcess(process_info.process_handle(), 0);
+      return win_result;
+    }
+    initial_token_.Close();
+  }
+
+  if (set_lockdown_token_after_create) {
+    PROCESS_ACCESS_TOKEN process_access_token;
+    process_access_token.thread = process_info.thread_handle();
+    process_access_token.token = scoped_lockdown_token.Get();
+
+    NtSetInformationProcess SetInformationProcess = NULL;
+    ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess);
+
+    NTSTATUS status = SetInformationProcess(
+        process_info.process_handle(),
+        static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken),
+        &process_access_token,
+        sizeof(process_access_token));
+    if (!NT_SUCCESS(status)) {
+      win_result = ::GetLastError();
+      ::TerminateProcess(process_info.process_handle(), 0);  // exit code
+      return win_result;
+    }
+  }
+
+  CONTEXT context;
+  context.ContextFlags = CONTEXT_ALL;
+  if (!::GetThreadContext(process_info.thread_handle(), &context)) {
+    win_result = ::GetLastError();
+    ::TerminateProcess(process_info.process_handle(), 0);
+    return win_result;
+  }
+
+#if defined(_WIN64)
+  void* entry_point = reinterpret_cast<void*>(context.Rcx);
+#else
+#pragma warning(push)
+#pragma warning(disable: 4312)
+  // This cast generates a warning because it is 32 bit specific.
+  void* entry_point = reinterpret_cast<void*>(context.Eax);
+#pragma warning(pop)
+#endif  // _WIN64
+
+  if (!target_info->DuplicateFrom(process_info)) {
+    win_result = ::GetLastError();  // This may or may not be correct.
+    ::TerminateProcess(process_info.process_handle(), 0);
+    return win_result;
+  }
+
+  base_address_ = GetBaseAddress(exe_path, entry_point);
+  sandbox_process_info_.Set(process_info.Take());
+  return win_result;
+}
+
+ResultCode TargetProcess::TransferVariable(const char* name, void* address,
+                                           size_t size) {
+  if (!sandbox_process_info_.IsValid())
+    return SBOX_ERROR_UNEXPECTED_CALL;
+
+  void* child_var = address;
+
+#if SANDBOX_EXPORTS
+  HMODULE module = ::LoadLibrary(exe_name_.get());
+  if (NULL == module)
+    return SBOX_ERROR_GENERIC;
+
+  child_var = ::GetProcAddress(module, name);
+  ::FreeLibrary(module);
+
+  if (NULL == child_var)
+    return SBOX_ERROR_GENERIC;
+
+  size_t offset = reinterpret_cast<char*>(child_var) -
+                  reinterpret_cast<char*>(module);
+  child_var = reinterpret_cast<char*>(MainModule()) + offset;
+#else
+  UNREFERENCED_PARAMETER(name);
+#endif
+
+  SIZE_T written;
+  if (!::WriteProcessMemory(sandbox_process_info_.process_handle(),
+                            child_var, address, size, &written))
+    return SBOX_ERROR_GENERIC;
+
+  if (written != size)
+    return SBOX_ERROR_GENERIC;
+
+  return SBOX_ALL_OK;
+}
+
+// Construct the IPC server and the IPC dispatcher. When the target does
+// an IPC it will eventually call the dispatcher.
+DWORD TargetProcess::Init(Dispatcher* ipc_dispatcher, void* policy,
+                          uint32 shared_IPC_size, uint32 shared_policy_size) {
+  // We need to map the shared memory on the target. This is necessary for
+  // any IPC that needs to take place, even if the target has not yet hit
+  // the main( ) function or even has initialized the CRT. So here we set
+  // the handle to the shared section. The target on the first IPC must do
+  // the rest, which boils down to calling MapViewofFile()
+
+  // We use this single memory pool for IPC and for policy.
+  DWORD shared_mem_size = static_cast<DWORD>(shared_IPC_size +
+                                             shared_policy_size);
+  shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+                                           PAGE_READWRITE | SEC_COMMIT,
+                                           0, shared_mem_size, NULL));
+  if (!shared_section_.IsValid()) {
+    return ::GetLastError();
+  }
+
+  DWORD access = FILE_MAP_READ | FILE_MAP_WRITE;
+  HANDLE target_shared_section;
+  if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_.Get(),
+                         sandbox_process_info_.process_handle(),
+                         &target_shared_section, access, FALSE, 0)) {
+    return ::GetLastError();
+  }
+
+  void* shared_memory = ::MapViewOfFile(shared_section_.Get(),
+                                        FILE_MAP_WRITE|FILE_MAP_READ,
+                                        0, 0, 0);
+  if (NULL == shared_memory) {
+    return ::GetLastError();
+  }
+
+  CopyPolicyToTarget(policy, shared_policy_size,
+                     reinterpret_cast<char*>(shared_memory) + shared_IPC_size);
+
+  ResultCode ret;
+  // Set the global variables in the target. These are not used on the broker.
+  g_shared_section = target_shared_section;
+  ret = TransferVariable("g_shared_section", &g_shared_section,
+                         sizeof(g_shared_section));
+  g_shared_section = NULL;
+  if (SBOX_ALL_OK != ret) {
+    return (SBOX_ERROR_GENERIC == ret)?
+           ::GetLastError() : ERROR_INVALID_FUNCTION;
+  }
+  g_shared_IPC_size = shared_IPC_size;
+  ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size,
+                         sizeof(g_shared_IPC_size));
+  g_shared_IPC_size = 0;
+  if (SBOX_ALL_OK != ret) {
+    return (SBOX_ERROR_GENERIC == ret) ?
+           ::GetLastError() : ERROR_INVALID_FUNCTION;
+  }
+  g_shared_policy_size = shared_policy_size;
+  ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size,
+                         sizeof(g_shared_policy_size));
+  g_shared_policy_size = 0;
+  if (SBOX_ALL_OK != ret) {
+    return (SBOX_ERROR_GENERIC == ret) ?
+           ::GetLastError() : ERROR_INVALID_FUNCTION;
+  }
+
+  ipc_server_.reset(
+      new SharedMemIPCServer(sandbox_process_info_.process_handle(),
+                             sandbox_process_info_.process_id(),
+                             job_, thread_pool_, ipc_dispatcher));
+
+  if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize))
+    return ERROR_NOT_ENOUGH_MEMORY;
+
+  // After this point we cannot use this handle anymore.
+  ::CloseHandle(sandbox_process_info_.TakeThreadHandle());
+
+  return ERROR_SUCCESS;
+}
+
+void TargetProcess::Terminate() {
+  if (!sandbox_process_info_.IsValid())
+    return;
+
+  ::TerminateProcess(sandbox_process_info_.process_handle(), 0);
+}
+
+TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) {
+  TargetProcess* target = new TargetProcess(NULL, NULL, NULL, NULL);
+  PROCESS_INFORMATION process_info = {};
+  process_info.hProcess = process;
+  target->sandbox_process_info_.Set(process_info);
+  target->base_address_ = base_address;
+  return target;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
new file mode 100644
index 0000000..cf5ad9f
--- /dev/null
+++ b/sandbox/win/src/target_process.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_TARGET_PROCESS_H_
+#define SANDBOX_WIN_SRC_TARGET_PROCESS_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace base {
+namespace win {
+
+class StartupInformation;
+
+};  // namespace win
+};  // namespace base
+
+namespace sandbox {
+
+class AttributeList;
+class SharedMemIPCServer;
+class ThreadProvider;
+
+// TargetProcess models a target instance (child process). Objects of this
+// class are owned by the Policy used to create them.
+class TargetProcess {
+ public:
+  // The constructor takes ownership of |initial_token| and |lockdown_token|.
+  TargetProcess(HANDLE initial_token, HANDLE lockdown_token, HANDLE job,
+                ThreadProvider* thread_pool);
+  ~TargetProcess();
+
+  // TODO(cpu): Currently there does not seem to be a reason to implement
+  // reference counting for this class since is internal, but kept the
+  // the same interface so the interception framework does not need to be
+  // touched at this point.
+  void AddRef() {}
+  void Release() {}
+
+  // Creates the new target process. The process is created suspended.
+  // When |set_lockdown_token_after_create| is set, the lockdown token
+  // is replaced after the process is created
+  DWORD Create(const wchar_t* exe_path,
+               const wchar_t* command_line,
+               bool inherit_handles,
+               bool set_lockdown_token_after_create,
+               const base::win::StartupInformation& startup_info,
+               base::win::ScopedProcessInformation* target_info);
+
+  // Destroys the target process.
+  void Terminate();
+
+  // Creates the IPC objects such as the BrokerDispatcher and the
+  // IPC server. The IPC server uses the services of the thread_pool.
+  DWORD Init(Dispatcher* ipc_dispatcher, void* policy,
+             uint32 shared_IPC_size, uint32 shared_policy_size);
+
+  // Returns the handle to the target process.
+  HANDLE Process() const {
+    return sandbox_process_info_.process_handle();
+  }
+
+  // Returns the handle to the job object that the target process belongs to.
+  HANDLE Job() const {
+    return job_;
+  }
+
+  // Returns the address of the target main exe. This is used by the
+  // interceptions framework.
+  HMODULE MainModule() const {
+    return reinterpret_cast<HMODULE>(base_address_);
+  }
+
+  // Returns the name of the executable.
+  const wchar_t* Name() const {
+    return exe_name_.get();
+  }
+
+  // Returns the process id.
+  DWORD ProcessId() const {
+    return sandbox_process_info_.process_id();
+  }
+
+  // Returns the handle to the main thread.
+  HANDLE MainThread() const {
+    return sandbox_process_info_.thread_handle();
+  }
+
+  // Transfers a 32-bit variable between the broker and the target.
+  ResultCode TransferVariable(const char* name, void* address, size_t size);
+
+ private:
+  // Details of the target process.
+  base::win::ScopedProcessInformation sandbox_process_info_;
+  // The token associated with the process. It provides the core of the
+  // sbox security.
+  base::win::ScopedHandle lockdown_token_;
+  // The token given to the initial thread so that the target process can
+  // start. It has more powers than the lockdown_token.
+  base::win::ScopedHandle initial_token_;
+  // Kernel handle to the shared memory used by the IPC server.
+  base::win::ScopedHandle shared_section_;
+  // Job object containing the target process.
+  HANDLE job_;
+  // Reference to the IPC subsystem.
+  scoped_ptr<SharedMemIPCServer> ipc_server_;
+  // Provides the threads used by the IPC. This class does not own this pointer.
+  ThreadProvider* thread_pool_;
+  // Base address of the main executable
+  void* base_address_;
+  // Full name of the target executable.
+  scoped_ptr<wchar_t, base::FreeDeleter> exe_name_;
+
+  // Function used for testing.
+  friend TargetProcess* MakeTestTargetProcess(HANDLE process,
+                                              HMODULE base_address);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TargetProcess);
+};
+
+// Creates a mock TargetProcess used for testing interceptions.
+// TODO(cpu): It seems that this method is not going to be used anymore.
+TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address);
+
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_TARGET_PROCESS_H_
diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc
new file mode 100644
index 0000000..b43a3b8
--- /dev/null
+++ b/sandbox/win/src/target_services.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/target_services.h"
+
+#include <process.h>
+
+#include "base/basictypes.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/handle_closer_agent.h"
+#include "sandbox/win/src/handle_interception.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+// Flushing a cached key is triggered by just opening the key and closing the
+// resulting handle. RegDisablePredefinedCache() is the documented way to flush
+// HKCU so do not use it with this function.
+bool FlushRegKey(HKEY root) {
+  HKEY key;
+  if (ERROR_SUCCESS == ::RegOpenKeyExW(root, NULL, 0, MAXIMUM_ALLOWED, &key)) {
+    if (ERROR_SUCCESS != ::RegCloseKey(key))
+      return false;
+  }
+  return true;
+}
+
+// This function forces advapi32.dll to release some internally cached handles
+// that were made during calls to RegOpenkey and RegOpenKeyEx if it is called
+// with a more restrictive token. Returns true if the flushing is succesful
+// although this behavior is undocumented and there is no guarantee that in
+// fact this will happen in future versions of windows.
+bool FlushCachedRegHandles() {
+  return (FlushRegKey(HKEY_LOCAL_MACHINE) &&
+          FlushRegKey(HKEY_CLASSES_ROOT) &&
+          FlushRegKey(HKEY_USERS));
+}
+
+// Checks if we have handle entries pending and runs the closer.
+bool CloseOpenHandles() {
+  if (sandbox::HandleCloserAgent::NeedsHandlesClosed()) {
+    sandbox::HandleCloserAgent handle_closer;
+
+    handle_closer.InitializeHandlesToClose();
+    if (!handle_closer.CloseHandles())
+      return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level =
+    INTEGRITY_LEVEL_LAST;
+SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations = 0;
+
+TargetServicesBase::TargetServicesBase() {
+}
+
+ResultCode TargetServicesBase::Init() {
+  process_state_.SetInitCalled();
+  return SBOX_ALL_OK;
+}
+
+// Failure here is a breach of security so the process is terminated.
+void TargetServicesBase::LowerToken() {
+  if (ERROR_SUCCESS !=
+      SetProcessIntegrityLevel(g_shared_delayed_integrity_level))
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_INTEGRITY);
+  process_state_.SetRevertedToSelf();
+  // If the client code as called RegOpenKey, advapi32.dll has cached some
+  // handles. The following code gets rid of them.
+  if (!::RevertToSelf())
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_DROPTOKEN);
+  if (!FlushCachedRegHandles())
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
+  if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
+  if (!CloseOpenHandles())
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
+  // Enabling mitigations must happen last otherwise handle closing breaks
+  if (g_shared_delayed_mitigations &&
+      !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations))
+    ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION);
+}
+
+ProcessState* TargetServicesBase::GetState() {
+  return &process_state_;
+}
+
+TargetServicesBase* TargetServicesBase::GetInstance() {
+  static TargetServicesBase instance;
+  return &instance;
+}
+
+// The broker services a 'test' IPC service with the IPC_PING_TAG tag.
+bool TargetServicesBase::TestIPCPing(int version) {
+  void* memory = GetGlobalIPCMemory();
+  if (NULL == memory) {
+    return false;
+  }
+  SharedMemIPCClient ipc(memory);
+  CrossCallReturn answer = {0};
+
+  if (1 == version) {
+    uint32 tick1 = ::GetTickCount();
+    uint32 cookie = 717115;
+    ResultCode code = CrossCall(ipc, IPC_PING1_TAG, cookie, &answer);
+
+    if (SBOX_ALL_OK != code) {
+      return false;
+    }
+    // We should get two extended returns values from the IPC, one is the
+    // tick count on the broker and the other is the cookie times two.
+    if ((answer.extended_count != 2)) {
+      return false;
+    }
+    // We test the first extended answer to be within the bounds of the tick
+    // count only if there was no tick count wraparound.
+    uint32 tick2 = ::GetTickCount();
+    if (tick2 >= tick1) {
+      if ((answer.extended[0].unsigned_int < tick1) ||
+          (answer.extended[0].unsigned_int > tick2)) {
+        return false;
+      }
+    }
+
+    if (answer.extended[1].unsigned_int != cookie * 2) {
+      return false;
+    }
+  } else if (2 == version) {
+    uint32 cookie = 717111;
+    InOutCountedBuffer counted_buffer(&cookie, sizeof(cookie));
+    ResultCode code = CrossCall(ipc, IPC_PING2_TAG, counted_buffer, &answer);
+
+    if (SBOX_ALL_OK != code) {
+      return false;
+    }
+    if (cookie != 717111 * 3) {
+      return false;
+    }
+  } else {
+    return false;
+  }
+  return true;
+}
+
+bool ProcessState::IsKernel32Loaded() {
+  return process_state_ != 0;
+}
+
+bool ProcessState::InitCalled() {
+  return process_state_ > 1;
+}
+
+bool ProcessState::RevertedToSelf() {
+  return process_state_ > 2;
+}
+
+void ProcessState::SetKernel32Loaded() {
+  if (!process_state_)
+    process_state_ = 1;
+}
+
+void ProcessState::SetInitCalled() {
+  if (process_state_ < 2)
+    process_state_ = 2;
+}
+
+void ProcessState::SetRevertedToSelf() {
+  if (process_state_ < 3)
+    process_state_ = 3;
+}
+
+ResultCode TargetServicesBase::DuplicateHandle(HANDLE source_handle,
+                                               DWORD target_process_id,
+                                               HANDLE* target_handle,
+                                               DWORD desired_access,
+                                               DWORD options) {
+  return sandbox::DuplicateHandleProxy(source_handle, target_process_id,
+                                       target_handle, desired_access, options);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/target_services.h b/sandbox/win/src/target_services.h
new file mode 100644
index 0000000..115de46
--- /dev/null
+++ b/sandbox/win/src/target_services.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_TARGET_SERVICES_H__
+#define SANDBOX_SRC_TARGET_SERVICES_H__
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+class ProcessState {
+ public:
+  ProcessState() : process_state_(0) {}
+
+  // Returns true if kernel32.dll has been loaded.
+  bool IsKernel32Loaded();
+
+  // Returns true if main has been called.
+  bool InitCalled();
+
+  // Returns true if LowerToken has been called.
+  bool RevertedToSelf();
+
+  // Set the current state.
+  void SetKernel32Loaded();
+  void SetInitCalled();
+  void SetRevertedToSelf();
+
+ public:
+  int process_state_;
+  DISALLOW_COPY_AND_ASSIGN(ProcessState);
+};
+
+// This class is an implementation of the  TargetServices.
+// Look in the documentation of sandbox::TargetServices for more info.
+// Do NOT add a destructor to this class without changing the implementation of
+// the factory method.
+class TargetServicesBase : public TargetServices {
+ public:
+  TargetServicesBase();
+
+  // Public interface of TargetServices.
+  ResultCode Init() override;
+  void LowerToken() override;
+  ProcessState* GetState() override;
+  ResultCode DuplicateHandle(HANDLE source_handle,
+                             DWORD target_process_id,
+                             HANDLE* target_handle,
+                             DWORD desired_access,
+                             DWORD options) override;
+
+  // Factory method.
+  static TargetServicesBase* GetInstance();
+
+  // Sends a simple IPC Message that has a well-known answer. Returns true
+  // if the IPC was successful and false otherwise. There are 2 versions of
+  // this test: 1 and 2. The first one send a simple message while the
+  // second one send a message with an in/out param.
+  bool TestIPCPing(int version);
+
+ private:
+  ProcessState process_state_;
+  DISALLOW_COPY_AND_ASSIGN(TargetServicesBase);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_TARGET_SERVICES_H__
diff --git a/sandbox/win/src/threadpool_unittest.cc b/sandbox/win/src/threadpool_unittest.cc
new file mode 100644
index 0000000..f439810
--- /dev/null
+++ b/sandbox/win/src/threadpool_unittest.cc
@@ -0,0 +1,94 @@
+// 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 "sandbox/win/src/win2k_threadpool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+void __stdcall EmptyCallBack(void*, unsigned char) {
+}
+
+void __stdcall TestCallBack(void* context, unsigned char) {
+  HANDLE event = reinterpret_cast<HANDLE>(context);
+  ::SetEvent(event);
+}
+
+namespace sandbox {
+
+// Test that register and unregister work, part 1.
+TEST(IPCTest, ThreadPoolRegisterTest1) {
+  Win2kThreadPool thread_pool;
+
+  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+
+  HANDLE event1 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+  HANDLE event2 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+
+  uint32 context = 0;
+  EXPECT_FALSE(thread_pool.RegisterWait(0, event1, EmptyCallBack, &context));
+  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+
+  EXPECT_TRUE(thread_pool.RegisterWait(this, event1, EmptyCallBack, &context));
+  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_TRUE(thread_pool.RegisterWait(this, event2, EmptyCallBack, &context));
+  EXPECT_EQ(2, thread_pool.OutstandingWaits());
+
+  EXPECT_TRUE(thread_pool.UnRegisterWaits(this));
+  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+
+  EXPECT_EQ(TRUE, ::CloseHandle(event1));
+  EXPECT_EQ(TRUE, ::CloseHandle(event2));
+}
+
+// Test that register and unregister work, part 2.
+TEST(IPCTest, ThreadPoolRegisterTest2) {
+  Win2kThreadPool thread_pool;
+
+  HANDLE event1 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+  HANDLE event2 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+
+  uint32 context = 0;
+  uint32 c1 = 0;
+  uint32 c2 = 0;
+
+  EXPECT_TRUE(thread_pool.RegisterWait(&c1, event1, EmptyCallBack, &context));
+  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_TRUE(thread_pool.RegisterWait(&c2, event2, EmptyCallBack, &context));
+  EXPECT_EQ(2, thread_pool.OutstandingWaits());
+
+  EXPECT_TRUE(thread_pool.UnRegisterWaits(&c2));
+  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+  EXPECT_TRUE(thread_pool.UnRegisterWaits(&c2));
+  EXPECT_EQ(1, thread_pool.OutstandingWaits());
+
+  EXPECT_TRUE(thread_pool.UnRegisterWaits(&c1));
+  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+
+  EXPECT_EQ(TRUE, ::CloseHandle(event1));
+  EXPECT_EQ(TRUE, ::CloseHandle(event2));
+}
+
+// Test that the thread pool has at least a thread that services an event.
+// Test that when the event is un-registered is no longer serviced.
+TEST(IPCTest, ThreadPoolSignalAndWaitTest) {
+  Win2kThreadPool thread_pool;
+
+  // The events are auto reset and start not signaled.
+  HANDLE event1 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+  HANDLE event2 = ::CreateEventW(NULL, FALSE, FALSE, NULL);
+
+  EXPECT_TRUE(thread_pool.RegisterWait(this, event1, TestCallBack, event2));
+
+  EXPECT_EQ(WAIT_OBJECT_0, ::SignalObjectAndWait(event1, event2, 5000, FALSE));
+  EXPECT_EQ(WAIT_OBJECT_0, ::SignalObjectAndWait(event1, event2, 5000, FALSE));
+
+  EXPECT_TRUE(thread_pool.UnRegisterWaits(this));
+  EXPECT_EQ(0, thread_pool.OutstandingWaits());
+
+  EXPECT_EQ(WAIT_TIMEOUT, ::SignalObjectAndWait(event1, event2, 1000, FALSE));
+
+  EXPECT_EQ(TRUE, ::CloseHandle(event1));
+  EXPECT_EQ(TRUE, ::CloseHandle(event2));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/unload_dll_test.cc b/sandbox/win/src/unload_dll_test.cc
new file mode 100644
index 0000000..620016c
--- /dev/null
+++ b/sandbox/win/src/unload_dll_test.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/win/scoped_handle.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Loads and or unloads a DLL passed in the second parameter of argv.
+// The first parameter of argv is 'L' = load, 'U' = unload or 'B' for both.
+SBOX_TESTS_COMMAND int UseOneDLL(int argc, wchar_t **argv) {
+  if (argc != 2)
+    return SBOX_TEST_FAILED_TO_RUN_TEST;
+  int rv = SBOX_TEST_FAILED_TO_RUN_TEST;
+
+  wchar_t option = (argv[0])[0];
+  if ((option == L'L') || (option == L'B')) {
+    HMODULE module1 = ::LoadLibraryW(argv[1]);
+    rv = (module1 == NULL) ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
+  }
+
+  if ((option == L'U') || (option == L'B')) {
+    HMODULE module2 = ::GetModuleHandleW(argv[1]);
+    rv = ::FreeLibrary(module2) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+  }
+  return rv;
+}
+
+// Opens an event passed as the first parameter of argv.
+SBOX_TESTS_COMMAND int SimpleOpenEvent(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::win::ScopedHandle event_open(::OpenEvent(SYNCHRONIZE, FALSE, argv[0]));
+  return event_open.Get() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+}
+
+// Flaky on windows, see http://crbug.com/80569.
+TEST(UnloadDllTest, DISABLED_BaselineAvicapDll) {
+  TestRunner runner;
+  runner.SetTestState(BEFORE_REVERT);
+  runner.SetTimeout(2000);
+  // Add a sync rule, because that ensures that the interception agent has
+  // more than one item in its internal table.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_ANY, L"t0001"));
+
+  // Note for the puzzled: avicap32.dll is a 64-bit dll in 64-bit versions of
+  // windows so this test and the others just work.
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"UseOneDLL B avicap32.dll"));
+}
+
+// Flaky on windows, see http://crbug.com/80569.
+TEST(UnloadDllTest, DISABLED_UnloadAviCapDllNoPatching) {
+  TestRunner runner;
+  runner.SetTestState(BEFORE_REVERT);
+  runner.SetTimeout(2000);
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+  policy->AddDllToUnload(L"avicap32.dll");
+  EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
+  EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL B avicap32.dll"));
+}
+
+// Flaky: http://crbug.com/38404
+TEST(UnloadDllTest, DISABLED_UnloadAviCapDllWithPatching) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(BEFORE_REVERT);
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+  policy->AddDllToUnload(L"avicap32.dll");
+
+  base::win::ScopedHandle handle1(::CreateEvent(
+      NULL, FALSE, FALSE, L"tst0001"));
+
+  // Add a couple of rules that ensures that the interception agent add EAT
+  // patching on the client which makes sure that the unload dll record does
+  // not interact badly with them.
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+                             TargetPolicy::REG_ALLOW_ANY,
+                             L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
+  EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+                             TargetPolicy::EVENTS_ALLOW_ANY, L"tst0001"));
+
+  EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
+
+  runner.SetTestState(AFTER_REVERT);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"SimpleOpenEvent tst0001"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/win2k_threadpool.cc b/sandbox/win/src/win2k_threadpool.cc
new file mode 100644
index 0000000..051cfc1
--- /dev/null
+++ b/sandbox/win/src/win2k_threadpool.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/win2k_threadpool.h"
+
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+Win2kThreadPool::Win2kThreadPool() {
+  ::InitializeCriticalSection(&lock_);
+}
+
+bool Win2kThreadPool::RegisterWait(const void* cookie, HANDLE waitable_object,
+                                   CrossCallIPCCallback callback,
+                                   void* context) {
+  if (0 == cookie) {
+    return false;
+  }
+  HANDLE pool_object = NULL;
+  // create a wait for a kernel object, with no timeout
+  if (!::RegisterWaitForSingleObject(&pool_object, waitable_object, callback,
+                                     context, INFINITE, WT_EXECUTEDEFAULT)) {
+    return false;
+  }
+  PoolObject pool_obj = {cookie, pool_object};
+  AutoLock lock(&lock_);
+  pool_objects_.push_back(pool_obj);
+  return true;
+}
+
+bool Win2kThreadPool::UnRegisterWaits(void* cookie) {
+  if (0 == cookie) {
+    return false;
+  }
+  AutoLock lock(&lock_);
+  bool success = true;
+  PoolObjects::iterator it = pool_objects_.begin();
+  while (it != pool_objects_.end()) {
+    if (it->cookie == cookie) {
+      HANDLE wait = it->wait;
+      it = pool_objects_.erase(it);
+      success &= (::UnregisterWaitEx(wait, INVALID_HANDLE_VALUE) != 0);
+    } else {
+      ++it;
+    }
+  }
+  return success;
+}
+
+size_t Win2kThreadPool::OutstandingWaits() {
+  AutoLock lock(&lock_);
+  return pool_objects_.size();
+}
+
+Win2kThreadPool::~Win2kThreadPool() {
+  // Here we used to unregister all the pool wait handles. Now, following the
+  // rest of the code we avoid lengthy or blocking calls given that the process
+  // is being torn down.
+  ::DeleteCriticalSection(&lock_);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/win2k_threadpool.h b/sandbox/win/src/win2k_threadpool.h
new file mode 100644
index 0000000..be2791f
--- /dev/null
+++ b/sandbox/win/src/win2k_threadpool.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 SANDBOX_SRC_WIN2K_THREADPOOL_H_
+#define SANDBOX_SRC_WIN2K_THREADPOOL_H_
+
+#include <list>
+#include <algorithm>
+#include "sandbox/win/src/crosscall_server.h"
+
+namespace sandbox {
+
+// Win2kThreadPool a simple implementation of a thread provider as required
+// for the sandbox IPC subsystem. See sandbox\crosscall_server.h for the details
+// and requirements of this interface.
+//
+// Implementing the thread provider as a thread pool is desirable in the case
+// of shared memory IPC because it can generate a large number of waitable
+// events: as many as channels. A thread pool does not create a thread per
+// event, instead maintains a few idle threads but can create more if the need
+// arises.
+//
+// This implementation simply thunks to the nice thread pool API of win2k.
+class Win2kThreadPool : public ThreadProvider {
+ public:
+  Win2kThreadPool();
+  ~Win2kThreadPool() override;
+
+  bool RegisterWait(const void* cookie,
+                    HANDLE waitable_object,
+                    CrossCallIPCCallback callback,
+                    void* context) override;
+
+  bool UnRegisterWaits(void* cookie) override;
+
+  // Returns the total number of wait objects associated with
+  // the thread pool.
+  size_t OutstandingWaits();
+
+ private:
+  // record to keep track of a wait and its associated cookie.
+  struct PoolObject {
+    const void* cookie;
+    HANDLE wait;
+  };
+  // The list of pool wait objects.
+  typedef std::list<PoolObject> PoolObjects;
+  PoolObjects pool_objects_;
+  // This lock protects the list of pool wait objects.
+  CRITICAL_SECTION lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(Win2kThreadPool);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_WIN2K_THREADPOOL_H_
diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc
new file mode 100644
index 0000000..2ff1b73
--- /dev/null
+++ b/sandbox/win/src/win_utils.cc
@@ -0,0 +1,432 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/win_utils.h"
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+// Holds the information about a known registry key.
+struct KnownReservedKey {
+  const wchar_t* name;
+  HKEY key;
+};
+
+// Contains all the known registry key by name and by handle.
+const KnownReservedKey kKnownKey[] = {
+    { L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT },
+    { L"HKEY_CURRENT_USER", HKEY_CURRENT_USER },
+    { L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
+    { L"HKEY_USERS", HKEY_USERS},
+    { L"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA},
+    { L"HKEY_PERFORMANCE_TEXT", HKEY_PERFORMANCE_TEXT},
+    { L"HKEY_PERFORMANCE_NLSTEXT", HKEY_PERFORMANCE_NLSTEXT},
+    { L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
+    { L"HKEY_DYN_DATA", HKEY_DYN_DATA}
+};
+
+// These functions perform case independent path comparisons.
+bool EqualPath(const base::string16& first, const base::string16& second) {
+  return _wcsicmp(first.c_str(), second.c_str()) == 0;
+}
+
+bool EqualPath(const base::string16& first, size_t first_offset,
+               const base::string16& second, size_t second_offset) {
+  return _wcsicmp(first.c_str() + first_offset,
+                  second.c_str() + second_offset) == 0;
+}
+
+bool EqualPath(const base::string16& first,
+               const wchar_t* second, size_t second_len) {
+  return _wcsnicmp(first.c_str(), second, second_len) == 0;
+}
+
+bool EqualPath(const base::string16& first, size_t first_offset,
+               const wchar_t* second, size_t second_len) {
+  return _wcsnicmp(first.c_str() + first_offset, second, second_len) == 0;
+}
+
+// Returns true if |path| starts with "\??\" and returns a path without that
+// component.
+bool IsNTPath(const base::string16& path, base::string16* trimmed_path ) {
+  if ((path.size() < sandbox::kNTPrefixLen) ||
+      (0 != path.compare(0, sandbox::kNTPrefixLen, sandbox::kNTPrefix))) {
+    *trimmed_path = path;
+    return false;
+  }
+
+  *trimmed_path = path.substr(sandbox::kNTPrefixLen);
+  return true;
+}
+
+// Returns true if |path| starts with "\Device\" and returns a path without that
+// component.
+bool IsDevicePath(const base::string16& path, base::string16* trimmed_path ) {
+  if ((path.size() < sandbox::kNTDevicePrefixLen) ||
+      (!EqualPath(path, sandbox::kNTDevicePrefix,
+                  sandbox::kNTDevicePrefixLen))) {
+    *trimmed_path = path;
+    return false;
+  }
+
+  *trimmed_path = path.substr(sandbox::kNTDevicePrefixLen);
+  return true;
+}
+
+bool StartsWithDriveLetter(const base::string16& path) {
+  if (path.size() < 3)
+    return false;
+
+  if (path[1] != L':' || path[2] != L'\\')
+    return false;
+
+  return (path[0] >= 'a' && path[0] <= 'z') ||
+         (path[0] >= 'A' && path[0] <= 'Z');
+}
+
+const wchar_t kNTDotPrefix[] = L"\\\\.\\";
+const size_t kNTDotPrefixLen = arraysize(kNTDotPrefix) - 1;
+
+// Removes "\\\\.\\" from the path.
+void RemoveImpliedDevice(base::string16* path) {
+  if (0 == path->compare(0, kNTDotPrefixLen, kNTDotPrefix))
+    *path = path->substr(kNTDotPrefixLen);
+}
+
+}  // namespace
+
+namespace sandbox {
+
+// Returns true if the provided path points to a pipe.
+bool IsPipe(const base::string16& path) {
+  size_t start = 0;
+  if (0 == path.compare(0, sandbox::kNTPrefixLen, sandbox::kNTPrefix))
+    start = sandbox::kNTPrefixLen;
+
+  const wchar_t kPipe[] = L"pipe\\";
+  if (path.size() < start + arraysize(kPipe) - 1)
+    return false;
+
+  return EqualPath(path, start, kPipe, arraysize(kPipe) - 1);
+}
+
+HKEY GetReservedKeyFromName(const base::string16& name) {
+  for (size_t i = 0; i < arraysize(kKnownKey); ++i) {
+    if (name == kKnownKey[i].name)
+      return kKnownKey[i].key;
+  }
+
+  return NULL;
+}
+
+bool ResolveRegistryName(base::string16 name, base::string16* resolved_name) {
+  for (size_t i = 0; i < arraysize(kKnownKey); ++i) {
+    if (name.find(kKnownKey[i].name) == 0) {
+      HKEY key;
+      DWORD disposition;
+      if (ERROR_SUCCESS != ::RegCreateKeyEx(kKnownKey[i].key, L"", 0, NULL, 0,
+                                            MAXIMUM_ALLOWED, NULL, &key,
+                                            &disposition))
+        return false;
+
+      bool result = GetPathFromHandle(key, resolved_name);
+      ::RegCloseKey(key);
+
+      if (!result)
+        return false;
+
+      *resolved_name += name.substr(wcslen(kKnownKey[i].name));
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// |full_path| can have any of the following forms:
+//    \??\c:\some\foo\bar
+//    \Device\HarddiskVolume0\some\foo\bar
+//    \??\HarddiskVolume0\some\foo\bar
+DWORD IsReparsePoint(const base::string16& full_path, bool* result) {
+  // Check if it's a pipe. We can't query the attributes of a pipe.
+  if (IsPipe(full_path)) {
+    *result = FALSE;
+    return ERROR_SUCCESS;
+  }
+
+  base::string16 path;
+  bool nt_path = IsNTPath(full_path, &path);
+  bool has_drive = StartsWithDriveLetter(path);
+  bool is_device_path = IsDevicePath(path, &path);
+
+  if (!has_drive && !is_device_path && !nt_path)
+    return ERROR_INVALID_NAME;
+
+  bool added_implied_device = false;
+  if (!has_drive) {
+      path = base::string16(kNTDotPrefix) + path;
+      added_implied_device = true;
+  }
+
+  base::string16::size_type last_pos = base::string16::npos;
+  bool passed_once = false;
+
+  do {
+    path = path.substr(0, last_pos);
+
+    DWORD attributes = ::GetFileAttributes(path.c_str());
+    if (INVALID_FILE_ATTRIBUTES == attributes) {
+      DWORD error = ::GetLastError();
+      if (error != ERROR_FILE_NOT_FOUND &&
+          error != ERROR_PATH_NOT_FOUND &&
+          error != ERROR_INVALID_NAME) {
+        // Unexpected error.
+        if (passed_once && added_implied_device &&
+            (path.rfind(L'\\') == kNTDotPrefixLen - 1)) {
+          break;
+        }
+        NOTREACHED_NT();
+        return error;
+      }
+    } else if (FILE_ATTRIBUTE_REPARSE_POINT & attributes) {
+      // This is a reparse point.
+      *result = true;
+      return ERROR_SUCCESS;
+    }
+
+    passed_once = true;
+    last_pos = path.rfind(L'\\');
+  } while (last_pos > 2);  // Skip root dir.
+
+  *result = false;
+  return ERROR_SUCCESS;
+}
+
+// We get a |full_path| of the forms accepted by IsReparsePoint(), and the name
+// we'll get from |handle| will be \device\harddiskvolume1\some\foo\bar.
+bool SameObject(HANDLE handle, const wchar_t* full_path) {
+  // Check if it's a pipe.
+  if (IsPipe(full_path))
+    return true;
+
+  base::string16 actual_path;
+  if (!GetPathFromHandle(handle, &actual_path))
+    return false;
+
+  base::string16 path(full_path);
+  DCHECK_NT(!path.empty());
+
+  // This may end with a backslash.
+  const wchar_t kBackslash = '\\';
+  if (path[path.length() - 1] == kBackslash)
+    path = path.substr(0, path.length() - 1);
+
+  // Perfect match (case-insesitive check).
+  if (EqualPath(actual_path, path))
+    return true;
+
+  bool nt_path = IsNTPath(path, &path);
+  bool has_drive = StartsWithDriveLetter(path);
+
+  if (!has_drive && nt_path) {
+    base::string16 simple_actual_path;
+    if (!IsDevicePath(actual_path, &simple_actual_path))
+      return false;
+
+    // Perfect match (case-insesitive check).
+    return (EqualPath(simple_actual_path, path));
+  }
+
+  if (!has_drive)
+    return false;
+
+  // We only need 3 chars, but let's alloc a buffer for four.
+  wchar_t drive[4] = {0};
+  wchar_t vol_name[MAX_PATH];
+  memcpy(drive, &path[0], 2 * sizeof(*drive));
+
+  // We'll get a double null terminated string.
+  DWORD vol_length = ::QueryDosDeviceW(drive, vol_name, MAX_PATH);
+  if (vol_length < 2 || vol_length == MAX_PATH)
+    return false;
+
+  // Ignore the nulls at the end.
+  vol_length = static_cast<DWORD>(wcslen(vol_name));
+
+  // The two paths should be the same length.
+  if (vol_length + path.size() - 2 != actual_path.size())
+    return false;
+
+  // Check up to the drive letter.
+  if (!EqualPath(actual_path, vol_name, vol_length))
+    return false;
+
+  // Check the path after the drive letter.
+  if (!EqualPath(actual_path, vol_length, path, 2))
+    return false;
+
+  return true;
+}
+
+// Paths like \Device\HarddiskVolume0\some\foo\bar are assumed to be already
+// expanded.
+bool ConvertToLongPath(const base::string16& short_path,
+                       base::string16* long_path) {
+  if (IsPipe(short_path)) {
+    // TODO(rvargas): Change the signature to use a single argument.
+    long_path->assign(short_path);
+    return true;
+  }
+
+  base::string16 path;
+  if (IsDevicePath(short_path, &path))
+    return false;
+
+  bool is_nt_path = IsNTPath(path, &path);
+  bool added_implied_device = false;
+  if (!StartsWithDriveLetter(path) && is_nt_path) {
+    path = base::string16(kNTDotPrefix) + path;
+    added_implied_device = true;
+  }
+
+  DWORD size = MAX_PATH;
+  scoped_ptr<wchar_t[]> long_path_buf(new wchar_t[size]);
+
+  DWORD return_value = ::GetLongPathName(path.c_str(), long_path_buf.get(),
+                                         size);
+  while (return_value >= size) {
+    size *= 2;
+    long_path_buf.reset(new wchar_t[size]);
+    return_value = ::GetLongPathName(path.c_str(), long_path_buf.get(), size);
+  }
+
+  DWORD last_error = ::GetLastError();
+  if (0 == return_value && (ERROR_FILE_NOT_FOUND == last_error ||
+                            ERROR_PATH_NOT_FOUND == last_error ||
+                            ERROR_INVALID_NAME == last_error)) {
+    // The file does not exist, but maybe a sub path needs to be expanded.
+    base::string16::size_type last_slash = path.rfind(L'\\');
+    if (base::string16::npos == last_slash)
+      return false;
+
+    base::string16 begin = path.substr(0, last_slash);
+    base::string16 end = path.substr(last_slash);
+    if (!ConvertToLongPath(begin, &begin))
+      return false;
+
+    // Ok, it worked. Let's reset the return value.
+    path = begin + end;
+    return_value = 1;
+  } else if (0 != return_value) {
+    path = long_path_buf.get();
+  }
+
+  if (return_value != 0) {
+    if (added_implied_device)
+      RemoveImpliedDevice(&path);
+
+    if (is_nt_path) {
+      *long_path = kNTPrefix;
+      *long_path += path;
+    } else {
+      *long_path = path;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
+bool GetPathFromHandle(HANDLE handle, base::string16* path) {
+  NtQueryObjectFunction NtQueryObject = NULL;
+  ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
+
+  OBJECT_NAME_INFORMATION initial_buffer;
+  OBJECT_NAME_INFORMATION* name = &initial_buffer;
+  ULONG size = sizeof(initial_buffer);
+  // Query the name information a first time to get the size of the name.
+  // Windows XP requires that the size of the buffer passed in here be != 0.
+  NTSTATUS status = NtQueryObject(handle, ObjectNameInformation, name, size,
+                                  &size);
+
+  scoped_ptr<BYTE[]> name_ptr;
+  if (size) {
+    name_ptr.reset(new BYTE[size]);
+    name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(name_ptr.get());
+
+    // Query the name information a second time to get the name of the
+    // object referenced by the handle.
+    status = NtQueryObject(handle, ObjectNameInformation, name, size, &size);
+  }
+
+  if (STATUS_SUCCESS != status)
+    return false;
+
+  path->assign(name->ObjectName.Buffer, name->ObjectName.Length /
+                                        sizeof(name->ObjectName.Buffer[0]));
+  return true;
+}
+
+bool GetNtPathFromWin32Path(const base::string16& path,
+                            base::string16* nt_path) {
+  HANDLE file = ::CreateFileW(path.c_str(), 0,
+    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  if (file == INVALID_HANDLE_VALUE)
+    return false;
+  bool rv = GetPathFromHandle(file, nt_path);
+  ::CloseHandle(file);
+  return rv;
+}
+
+bool WriteProtectedChildMemory(HANDLE child_process, void* address,
+                               const void* buffer, size_t length) {
+  // First, remove the protections.
+  DWORD old_protection;
+  if (!::VirtualProtectEx(child_process, address, length,
+                          PAGE_WRITECOPY, &old_protection))
+    return false;
+
+  SIZE_T written;
+  bool ok = ::WriteProcessMemory(child_process, address, buffer, length,
+                                 &written) && (length == written);
+
+  // Always attempt to restore the original protection.
+  if (!::VirtualProtectEx(child_process, address, length,
+                          old_protection, &old_protection))
+    return false;
+
+  return ok;
+}
+
+};  // namespace sandbox
+
+void ResolveNTFunctionPtr(const char* name, void* ptr) {
+  static volatile HMODULE ntdll = NULL;
+
+  if (!ntdll) {
+    HMODULE ntdll_local = ::GetModuleHandle(sandbox::kNtdllName);
+    // Use PEImage to sanity-check that we have a valid ntdll handle.
+    base::win::PEImage ntdll_peimage(ntdll_local);
+    CHECK_NT(ntdll_peimage.VerifyMagic());
+    // Race-safe way to set static ntdll.
+    ::InterlockedCompareExchangePointer(
+        reinterpret_cast<PVOID volatile*>(&ntdll), ntdll_local, NULL);
+
+  }
+
+  CHECK_NT(ntdll);
+  FARPROC* function_ptr = reinterpret_cast<FARPROC*>(ptr);
+  *function_ptr = ::GetProcAddress(ntdll, name);
+  CHECK_NT(*function_ptr);
+}
diff --git a/sandbox/win/src/win_utils.h b/sandbox/win/src/win_utils.h
new file mode 100644
index 0000000..3e4565f
--- /dev/null
+++ b/sandbox/win/src/win_utils.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_WIN_UTILS_H_
+#define SANDBOX_SRC_WIN_UTILS_H_
+
+#include <windows.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+namespace sandbox {
+
+// Prefix for path used by NT calls.
+const wchar_t kNTPrefix[] = L"\\??\\";
+const size_t kNTPrefixLen = arraysize(kNTPrefix) - 1;
+
+const wchar_t kNTDevicePrefix[] = L"\\Device\\";
+const size_t kNTDevicePrefixLen = arraysize(kNTDevicePrefix) - 1;
+
+// Automatically acquires and releases a lock when the object is
+// is destroyed.
+class AutoLock {
+ public:
+  // Acquires the lock.
+  explicit AutoLock(CRITICAL_SECTION *lock) : lock_(lock) {
+    ::EnterCriticalSection(lock);
+  };
+
+  // Releases the lock;
+  ~AutoLock() {
+    ::LeaveCriticalSection(lock_);
+  };
+
+ private:
+  CRITICAL_SECTION *lock_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(AutoLock);
+};
+
+// Basic implementation of a singleton which calls the destructor
+// when the exe is shutting down or the DLL is being unloaded.
+template <typename Derived>
+class SingletonBase {
+ public:
+  static Derived* GetInstance() {
+    static Derived* instance = NULL;
+    if (NULL == instance) {
+      instance = new Derived();
+      // Microsoft CRT extension. In an exe this this called after
+      // winmain returns, in a dll is called in DLL_PROCESS_DETACH
+      _onexit(OnExit);
+    }
+    return instance;
+  }
+
+ private:
+  // this is the function that gets called by the CRT when the
+  // process is shutting down.
+  static int __cdecl OnExit() {
+    delete GetInstance();
+    return 0;
+  }
+};
+
+// Convert a short path (C:\path~1 or \\??\\c:\path~1) to the long version of
+// the path. If the path is not a valid filesystem path, the function returns
+// false and the output parameter is not modified.
+bool ConvertToLongPath(const base::string16& short_path,
+                       base::string16* long_path);
+
+// Sets result to true if the path contains a reparse point. The return value
+// is ERROR_SUCCESS when the function succeeds or the appropriate error code
+// when the function fails.
+// This function is not smart. It looks for each element in the path and
+// returns true if any of them is a reparse point.
+DWORD IsReparsePoint(const base::string16& full_path, bool* result);
+
+// Returns true if the handle corresponds to the object pointed by this path.
+bool SameObject(HANDLE handle, const wchar_t* full_path);
+
+// Resolves a handle to an nt path. Returns true if the handle can be resolved.
+bool GetPathFromHandle(HANDLE handle, base::string16* path);
+
+// Resolves a win32 path to an nt path using GetPathFromHandle. The path must
+// exist. Returs true if the translation was succesful.
+bool GetNtPathFromWin32Path(const base::string16& path,
+                            base::string16* nt_path);
+
+// Translates a reserved key name to its handle.
+// For example "HKEY_LOCAL_MACHINE" returns HKEY_LOCAL_MACHINE.
+// Returns NULL if the name does not represent any reserved key name.
+HKEY GetReservedKeyFromName(const base::string16& name);
+
+// Resolves a user-readable registry path to a system-readable registry path.
+// For example, HKEY_LOCAL_MACHINE\\Software\\microsoft is translated to
+// \\registry\\machine\\software\\microsoft. Returns false if the path
+// cannot be resolved.
+bool ResolveRegistryName(base::string16 name, base::string16* resolved_name);
+
+// Writes |length| bytes from the provided |buffer| into the address space of
+// |child_process|, at the specified |address|, preserving the original write
+// protection attributes. Returns true on success.
+bool WriteProtectedChildMemory(HANDLE child_process, void* address,
+                               const void* buffer, size_t length);
+
+// Returns true if the provided path points to a pipe.
+bool IsPipe(const base::string16& path);
+
+}  // namespace sandbox
+
+// Resolves a function name in NTDLL to a function pointer. The second parameter
+// is a pointer to the function pointer.
+void ResolveNTFunctionPtr(const char* name, void* ptr);
+
+#endif  // SANDBOX_SRC_WIN_UTILS_H_
diff --git a/sandbox/win/src/win_utils_unittest.cc b/sandbox/win/src/win_utils_unittest.cc
new file mode 100644
index 0000000..4cf59b8
--- /dev/null
+++ b/sandbox/win/src/win_utils_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 <windows.h>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(WinUtils, IsReparsePoint) {
+  using sandbox::IsReparsePoint;
+
+  // Create a temp file because we need write access to it.
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t my_folder[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, my_folder), 0u);
+
+  // Delete the file and create a directory instead.
+  ASSERT_TRUE(::DeleteFile(my_folder));
+  ASSERT_TRUE(::CreateDirectory(my_folder, NULL));
+
+  bool result = true;
+  EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(my_folder, &result));
+  EXPECT_FALSE(result);
+
+  // We have to fix Bug 32224 to pass this test.
+  base::string16 not_found = base::string16(my_folder) + L"\\foo\\bar";
+  // EXPECT_EQ(ERROR_PATH_NOT_FOUND, IsReparsePoint(not_found, &result));
+
+  base::string16 new_file = base::string16(my_folder) + L"\\foo";
+  EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(new_file, &result));
+  EXPECT_FALSE(result);
+
+  // Replace the directory with a reparse point to %temp%.
+  HANDLE dir = ::CreateFile(my_folder, FILE_ALL_ACCESS,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+  EXPECT_NE(INVALID_HANDLE_VALUE, dir);
+
+  base::string16 temp_dir_nt = base::string16(L"\\??\\") + temp_directory;
+  EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
+
+  EXPECT_EQ(ERROR_SUCCESS, IsReparsePoint(new_file, &result));
+  EXPECT_TRUE(result);
+
+  EXPECT_TRUE(DeleteReparsePoint(dir));
+  EXPECT_TRUE(::CloseHandle(dir));
+  EXPECT_TRUE(::RemoveDirectory(my_folder));
+}
+
+TEST(WinUtils, SameObject) {
+  using sandbox::SameObject;
+
+  // Create a temp file because we need write access to it.
+  wchar_t temp_directory[MAX_PATH];
+  wchar_t my_folder[MAX_PATH];
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+  ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, my_folder), 0u);
+
+  // Delete the file and create a directory instead.
+  ASSERT_TRUE(::DeleteFile(my_folder));
+  ASSERT_TRUE(::CreateDirectory(my_folder, NULL));
+
+  base::string16 folder(my_folder);
+  base::string16 file_name = folder + L"\\foo.txt";
+  const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+  base::win::ScopedHandle file(CreateFile(
+      file_name.c_str(), GENERIC_WRITE, kSharing, NULL, CREATE_ALWAYS,
+      FILE_FLAG_DELETE_ON_CLOSE, NULL));
+
+  EXPECT_TRUE(file.IsValid());
+  base::string16 file_name_nt1 = base::string16(L"\\??\\") + file_name;
+  base::string16 file_name_nt2 =
+      base::string16(L"\\??\\") + folder + L"\\FOO.txT";
+  EXPECT_TRUE(SameObject(file.Get(), file_name_nt1.c_str()));
+  EXPECT_TRUE(SameObject(file.Get(), file_name_nt2.c_str()));
+
+  file.Close();
+  EXPECT_TRUE(::RemoveDirectory(my_folder));
+}
+
+TEST(WinUtils, IsPipe) {
+  using sandbox::IsPipe;
+
+  base::string16 pipe_name = L"\\??\\pipe\\mypipe";
+  EXPECT_TRUE(IsPipe(pipe_name));
+
+  pipe_name = L"\\??\\PiPe\\mypipe";
+  EXPECT_TRUE(IsPipe(pipe_name));
+
+  pipe_name = L"\\??\\pipe";
+  EXPECT_FALSE(IsPipe(pipe_name));
+
+  pipe_name = L"\\??\\_pipe_\\mypipe";
+  EXPECT_FALSE(IsPipe(pipe_name));
+
+  pipe_name = L"\\??\\ABCD\\mypipe";
+  EXPECT_FALSE(IsPipe(pipe_name));
+
+
+  // Written as two strings to prevent trigraph '?' '?' '/'.
+  pipe_name = L"/?" L"?/pipe/mypipe";
+  EXPECT_FALSE(IsPipe(pipe_name));
+
+  pipe_name = L"\\XX\\pipe\\mypipe";
+  EXPECT_FALSE(IsPipe(pipe_name));
+
+  pipe_name = L"\\Device\\NamedPipe\\mypipe";
+  EXPECT_FALSE(IsPipe(pipe_name));
+}
diff --git a/sandbox/win/src/window.cc b/sandbox/win/src/window.cc
new file mode 100644
index 0000000..cfbf280
--- /dev/null
+++ b/sandbox/win/src/window.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/window.h"
+
+#include <aclapi.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/sid.h"
+
+namespace {
+
+// Gets the security attributes of a window object referenced by |handle|. The
+// lpSecurityDescriptor member of the SECURITY_ATTRIBUTES parameter returned
+// must be freed using LocalFree by the caller.
+bool GetSecurityAttributes(HANDLE handle, SECURITY_ATTRIBUTES* attributes) {
+  attributes->bInheritHandle = FALSE;
+  attributes->nLength = sizeof(SECURITY_ATTRIBUTES);
+
+  PACL dacl = NULL;
+  DWORD result = ::GetSecurityInfo(handle, SE_WINDOW_OBJECT,
+                                   DACL_SECURITY_INFORMATION, NULL, NULL, &dacl,
+                                   NULL, &attributes->lpSecurityDescriptor);
+  if (ERROR_SUCCESS == result)
+    return true;
+
+  return false;
+}
+
+}
+
+namespace sandbox {
+
+ResultCode CreateAltWindowStation(HWINSTA* winsta) {
+  // Get the security attributes from the current window station; we will
+  // use this as the base security attributes for the new window station.
+  SECURITY_ATTRIBUTES attributes = {0};
+  if (!GetSecurityAttributes(::GetProcessWindowStation(), &attributes)) {
+    return SBOX_ERROR_CANNOT_CREATE_WINSTATION;
+  }
+
+  // Create the window station using NULL for the name to ask the os to
+  // generate it.
+  *winsta = ::CreateWindowStationW(
+      NULL, 0, GENERIC_READ | WINSTA_CREATEDESKTOP, &attributes);
+  LocalFree(attributes.lpSecurityDescriptor);
+
+  if (*winsta)
+    return SBOX_ALL_OK;
+
+  return SBOX_ERROR_CANNOT_CREATE_WINSTATION;
+}
+
+ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop) {
+  base::string16 desktop_name = L"sbox_alternate_desktop_";
+
+  // Append the current PID to the desktop name.
+  wchar_t buffer[16];
+  _snwprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), L"0x%X",
+               ::GetCurrentProcessId());
+  desktop_name += buffer;
+
+  // Get the security attributes from the current desktop, we will use this as
+  // the base security attributes for the new desktop.
+  SECURITY_ATTRIBUTES attributes = {0};
+  if (!GetSecurityAttributes(GetThreadDesktop(GetCurrentThreadId()),
+                             &attributes)) {
+    return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+  }
+
+  // Back up the current window station, in case we need to switch it.
+  HWINSTA current_winsta = ::GetProcessWindowStation();
+
+  if (winsta) {
+    // We need to switch to the alternate window station before creating the
+    // desktop.
+    if (!::SetProcessWindowStation(winsta)) {
+      ::LocalFree(attributes.lpSecurityDescriptor);
+      return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+    }
+  }
+
+  // Create the destkop.
+  *desktop = ::CreateDesktop(desktop_name.c_str(),
+                             NULL,
+                             NULL,
+                             0,
+                             DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS |
+                                 READ_CONTROL | WRITE_DAC | WRITE_OWNER,
+                             &attributes);
+  ::LocalFree(attributes.lpSecurityDescriptor);
+
+  if (winsta) {
+    // Revert to the right window station.
+    if (!::SetProcessWindowStation(current_winsta)) {
+      return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION;
+    }
+  }
+
+  if (*desktop) {
+    // Replace the DACL on the new Desktop with a reduced privilege version.
+    // We can soft fail on this for now, as it's just an extra mitigation.
+    static const ACCESS_MASK kDesktopDenyMask = WRITE_DAC | WRITE_OWNER |
+                                                DELETE |
+                                                DESKTOP_CREATEMENU |
+                                                DESKTOP_CREATEWINDOW |
+                                                DESKTOP_HOOKCONTROL |
+                                                DESKTOP_JOURNALPLAYBACK |
+                                                DESKTOP_JOURNALRECORD |
+                                                DESKTOP_SWITCHDESKTOP;
+    AddKnownSidToObject(*desktop, SE_WINDOW_OBJECT, Sid(WinRestrictedCodeSid),
+                        DENY_ACCESS, kDesktopDenyMask);
+    return SBOX_ALL_OK;
+  }
+
+  return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+}
+
+base::string16 GetWindowObjectName(HANDLE handle) {
+  // Get the size of the name.
+  DWORD size = 0;
+  ::GetUserObjectInformation(handle, UOI_NAME, NULL, 0, &size);
+
+  if (!size) {
+    NOTREACHED();
+    return base::string16();
+  }
+
+  // Create the buffer that will hold the name.
+  scoped_ptr<wchar_t[]> name_buffer(new wchar_t[size]);
+
+  // Query the name of the object.
+  if (!::GetUserObjectInformation(handle, UOI_NAME, name_buffer.get(), size,
+                                  &size)) {
+    NOTREACHED();
+    return base::string16();
+  }
+
+  return base::string16(name_buffer.get());
+}
+
+base::string16 GetFullDesktopName(HWINSTA winsta, HDESK desktop) {
+  if (!desktop) {
+    NOTREACHED();
+    return base::string16();
+  }
+
+  base::string16 name;
+  if (winsta) {
+    name = GetWindowObjectName(winsta);
+    name += L'\\';
+  }
+
+  name += GetWindowObjectName(desktop);
+  return name;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/src/window.h b/sandbox/win/src/window.h
new file mode 100644
index 0000000..62fe7c4
--- /dev/null
+++ b/sandbox/win/src/window.h
@@ -0,0 +1,40 @@
+// 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 SANDBOX_SRC_WINDOW_H_
+#define SANDBOX_SRC_WINDOW_H_
+
+#include <windows.h>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+  // Creates a window station. The name is generated by the OS. The security
+  // descriptor is based on the security descriptor of the current window
+  // station.
+  ResultCode CreateAltWindowStation(HWINSTA* winsta);
+
+  // Creates a desktop. The name is a static string followed by the pid of the
+  // current process. The security descriptor on the new desktop is based on the
+  // security descriptor of the desktop associated with the current thread.
+  // If a winsta is specified, the function will switch to it before creating
+  // the desktop. If the functions fails the switch back to the current winsta,
+  // the function will return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION.
+  ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop);
+
+  // Returns the name of a desktop or a window station.
+  base::string16 GetWindowObjectName(HANDLE handle);
+
+  // Returns the name of the desktop referenced by |desktop|. If a window
+  // station is specified, the name is prepended with the window station name,
+  // followed by a backslash. This name can be used as the lpDesktop parameter
+  // to CreateProcess.
+  base::string16 GetFullDesktopName(HWINSTA winsta, HDESK desktop);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_WINDOW_H_
diff --git a/sandbox/win/tests/common/controller.cc b/sandbox/win/tests/common/controller.cc
new file mode 100644
index 0000000..bdada4b
--- /dev/null
+++ b/sandbox/win/tests/common/controller.cc
@@ -0,0 +1,363 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/tests/common/controller.h"
+
+#include <string>
+
+#include "base/memory/shared_memory.h"
+#include "base/process/process.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox_factory.h"
+
+namespace {
+
+static const int kDefaultTimeout = 60000;
+
+// Constructs a full path to a file inside the system32 folder.
+base::string16 MakePathToSys32(const wchar_t* name, bool is_obj_man_path) {
+  wchar_t windows_path[MAX_PATH] = {0};
+  if (0 == ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH))
+    return base::string16();
+
+  base::string16 full_path(windows_path);
+  if (full_path.empty())
+    return full_path;
+
+  if (is_obj_man_path)
+    full_path.insert(0, L"\\??\\");
+
+  full_path += L"\\system32\\";
+  full_path += name;
+  return full_path;
+}
+
+// Constructs a full path to a file inside the syswow64 folder.
+base::string16 MakePathToSysWow64(const wchar_t* name, bool is_obj_man_path) {
+  wchar_t windows_path[MAX_PATH] = {0};
+  if (0 == ::GetSystemWindowsDirectoryW(windows_path, MAX_PATH))
+    return base::string16();
+
+  base::string16 full_path(windows_path);
+  if (full_path.empty())
+    return full_path;
+
+  if (is_obj_man_path)
+    full_path.insert(0, L"\\??\\");
+
+  full_path += L"\\SysWOW64\\";
+  full_path += name;
+  return full_path;
+}
+
+bool IsProcessRunning(HANDLE process) {
+  DWORD exit_code = 0;
+  if (::GetExitCodeProcess(process, &exit_code))
+    return exit_code == STILL_ACTIVE;
+  return false;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+base::string16 MakePathToSys(const wchar_t* name, bool is_obj_man_path) {
+  return (base::win::OSInfo::GetInstance()->wow64_status() ==
+      base::win::OSInfo::WOW64_ENABLED) ?
+      MakePathToSysWow64(name, is_obj_man_path) :
+      MakePathToSys32(name, is_obj_man_path);
+}
+
+BrokerServices* GetBroker() {
+  static BrokerServices* broker = SandboxFactory::GetBrokerServices();
+  static bool is_initialized = false;
+
+  if (!broker) {
+    return NULL;
+  }
+
+  if (!is_initialized) {
+    if (SBOX_ALL_OK != broker->Init())
+      return NULL;
+
+    is_initialized = true;
+  }
+
+  return broker;
+}
+
+TestRunner::TestRunner(JobLevel job_level, TokenLevel startup_token,
+                       TokenLevel main_token)
+    : is_init_(false), is_async_(false), no_sandbox_(false),
+      target_process_id_(0) {
+  Init(job_level, startup_token, main_token);
+}
+
+TestRunner::TestRunner()
+    : is_init_(false), is_async_(false), no_sandbox_(false),
+      target_process_id_(0) {
+  Init(JOB_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+}
+
+void TestRunner::Init(JobLevel job_level, TokenLevel startup_token,
+                      TokenLevel main_token) {
+  broker_ = NULL;
+  policy_ = NULL;
+  timeout_ = kDefaultTimeout;
+  state_ = AFTER_REVERT;
+  is_async_= false;
+  kill_on_destruction_ = true;
+  target_process_id_ = 0;
+
+  broker_ = GetBroker();
+  if (!broker_)
+    return;
+
+  policy_ = broker_->CreatePolicy();
+  if (!policy_)
+    return;
+
+  policy_->SetJobLevel(job_level, 0);
+  policy_->SetTokenLevel(startup_token, main_token);
+
+  is_init_ = true;
+}
+
+TargetPolicy* TestRunner::GetPolicy() {
+  return policy_;
+}
+
+TestRunner::~TestRunner() {
+  if (target_process_.IsValid() && kill_on_destruction_)
+    ::TerminateProcess(target_process_.Get(), 0);
+
+  if (policy_)
+    policy_->Release();
+}
+
+bool TestRunner::AddRule(TargetPolicy::SubSystem subsystem,
+                         TargetPolicy::Semantics semantics,
+                         const wchar_t* pattern) {
+  if (!is_init_)
+    return false;
+
+  return (SBOX_ALL_OK == policy_->AddRule(subsystem, semantics, pattern));
+}
+
+bool TestRunner::AddRuleSys32(TargetPolicy::Semantics semantics,
+                              const wchar_t* pattern) {
+  if (!is_init_)
+    return false;
+
+  base::string16 win32_path = MakePathToSys32(pattern, false);
+  if (win32_path.empty())
+    return false;
+
+  if (!AddRule(TargetPolicy::SUBSYS_FILES, semantics, win32_path.c_str()))
+    return false;
+
+  if (base::win::OSInfo::GetInstance()->wow64_status() !=
+      base::win::OSInfo::WOW64_ENABLED)
+    return true;
+
+  win32_path = MakePathToSysWow64(pattern, false);
+  if (win32_path.empty())
+    return false;
+
+  return AddRule(TargetPolicy::SUBSYS_FILES, semantics, win32_path.c_str());
+}
+
+bool TestRunner::AddFsRule(TargetPolicy::Semantics semantics,
+                           const wchar_t* pattern) {
+  if (!is_init_)
+    return false;
+
+  return AddRule(TargetPolicy::SUBSYS_FILES, semantics, pattern);
+}
+
+int TestRunner::RunTest(const wchar_t* command) {
+  if (MAX_STATE > 10)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  wchar_t state_number[2];
+  state_number[0] = static_cast<wchar_t>(L'0' + state_);
+  state_number[1] = L'\0';
+  base::string16 full_command(state_number);
+  full_command += L" ";
+  full_command += command;
+
+  return InternalRunTest(full_command.c_str());
+}
+
+int TestRunner::InternalRunTest(const wchar_t* command) {
+  if (!is_init_)
+    return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+  // For simplicity TestRunner supports only one process per instance.
+  if (target_process_.IsValid()) {
+    if (IsProcessRunning(target_process_.Get()))
+      return SBOX_TEST_FAILED_TO_RUN_TEST;
+    target_process_.Close();
+    target_process_id_ = 0;
+  }
+
+  // Get the path to the sandboxed process.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+
+  // Launch the sandboxed process.
+  ResultCode result = SBOX_ALL_OK;
+  PROCESS_INFORMATION target = {0};
+
+  base::string16 arguments(L"\"");
+  arguments += prog_name;
+  arguments += L"\" -child";
+  arguments += no_sandbox_ ? L"-no-sandbox " : L" ";
+  arguments += command;
+
+  if (no_sandbox_) {
+    STARTUPINFO startup_info = {sizeof(STARTUPINFO)};
+    if (!::CreateProcessW(prog_name, &arguments[0], NULL, NULL, FALSE, 0,
+                          NULL, NULL, &startup_info, &target)) {
+      return SBOX_ERROR_GENERIC;
+    }
+    broker_->AddTargetPeer(target.hProcess);
+  } else {
+    result = broker_->SpawnTarget(prog_name, arguments.c_str(), policy_,
+                                  &target);
+  }
+
+  if (SBOX_ALL_OK != result)
+    return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+  ::ResumeThread(target.hThread);
+
+  // For an asynchronous run we don't bother waiting.
+  if (is_async_) {
+    target_process_.Set(target.hProcess);
+    target_process_id_ = target.dwProcessId;
+    ::CloseHandle(target.hThread);
+    return SBOX_TEST_SUCCEEDED;
+  }
+
+  if (::IsDebuggerPresent()) {
+    // Don't kill the target process on a time-out while we are debugging.
+    timeout_ = INFINITE;
+  }
+
+  if (WAIT_TIMEOUT == ::WaitForSingleObject(target.hProcess, timeout_)) {
+    ::TerminateProcess(target.hProcess, static_cast<UINT>(SBOX_TEST_TIMED_OUT));
+    ::CloseHandle(target.hProcess);
+    ::CloseHandle(target.hThread);
+    return SBOX_TEST_TIMED_OUT;
+  }
+
+  DWORD exit_code = static_cast<DWORD>(SBOX_TEST_LAST_RESULT);
+  if (!::GetExitCodeProcess(target.hProcess, &exit_code)) {
+    ::CloseHandle(target.hProcess);
+    ::CloseHandle(target.hThread);
+    return SBOX_TEST_FAILED_TO_RUN_TEST;
+  }
+
+  ::CloseHandle(target.hProcess);
+  ::CloseHandle(target.hThread);
+
+  return exit_code;
+}
+
+void TestRunner::SetTimeout(DWORD timeout_ms) {
+  timeout_ = timeout_ms;
+}
+
+void TestRunner::SetTestState(SboxTestsState desired_state) {
+  state_ = desired_state;
+}
+
+// This is the main procedure for the target (child) application. We'll find out
+// the target test and call it.
+// We expect the arguments to be:
+//  argv[1] = "-child"
+//  argv[2] = SboxTestsState when to run the command
+//  argv[3] = command to run
+//  argv[4...] = command arguments.
+int DispatchCall(int argc, wchar_t **argv) {
+  if (argc < 4)
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  // We hard code two tests to avoid dispatch failures.
+  if (0 == _wcsicmp(argv[3], L"wait")) {
+      Sleep(INFINITE);
+      return SBOX_TEST_TIMED_OUT;
+  }
+
+  if (0 == _wcsicmp(argv[3], L"ping"))
+      return SBOX_TEST_PING_OK;
+
+  // If the caller shared a shared memory handle with us attempt to open it
+  // in read only mode and sleep infinitely if we succeed.
+  if (0 == _wcsicmp(argv[3], L"shared_memory_handle")) {
+    base::SharedMemoryHandle shared_handle = NULL;
+    base::StringToUint(
+        argv[4], reinterpret_cast<unsigned int*>(&shared_handle));
+    if (shared_handle == NULL)
+      return SBOX_TEST_INVALID_PARAMETER;
+    base::SharedMemory read_only_view(shared_handle, true);
+    if (!read_only_view.Map(0))
+      return SBOX_TEST_INVALID_PARAMETER;
+    std::string contents(reinterpret_cast<char*>(read_only_view.memory()));
+    if (contents != "Hello World")
+      return SBOX_TEST_INVALID_PARAMETER;
+    Sleep(INFINITE);
+    return SBOX_TEST_TIMED_OUT;
+  }
+
+  SboxTestsState state = static_cast<SboxTestsState>(_wtoi(argv[2]));
+  if ((state <= MIN_STATE) || (state >= MAX_STATE))
+    return SBOX_TEST_INVALID_PARAMETER;
+
+  HMODULE module;
+  if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                             GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                         reinterpret_cast<wchar_t*>(&DispatchCall), &module))
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  std::string command_name = base::SysWideToMultiByte(argv[3], CP_UTF8);
+  CommandFunction command = reinterpret_cast<CommandFunction>(
+                                ::GetProcAddress(module, command_name.c_str()));
+  if (!command)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  if (BEFORE_INIT == state)
+    return command(argc - 4, argv + 4);
+  else if (EVERY_STATE == state)
+    command(argc - 4, argv + 4);
+
+  TargetServices* target = SandboxFactory::GetTargetServices();
+  if (target) {
+    if (SBOX_ALL_OK != target->Init())
+      return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+    if (BEFORE_REVERT == state)
+      return command(argc - 4, argv + 4);
+    else if (EVERY_STATE == state)
+      command(argc - 4, argv + 4);
+
+#if defined(ADDRESS_SANITIZER)
+    // Bind and leak dbghelp.dll before the token is lowered, otherwise
+    // AddressSanitizer will crash when trying to symbolize a report.
+    if (!LoadLibraryA("dbghelp.dll"))
+      return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+#endif
+
+    target->LowerToken();
+  } else if (0 != _wcsicmp(argv[1], L"-child-no-sandbox")) {
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+  }
+
+  return command(argc - 4, argv + 4);
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/tests/common/controller.h b/sandbox/win/tests/common/controller.h
new file mode 100644
index 0000000..a6498ed
--- /dev/null
+++ b/sandbox/win/tests/common/controller.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_TESTS_COMMON_CONTROLLER_H_
+#define SANDBOX_WIN_TESTS_COMMON_CONTROLLER_H_
+
+#include <windows.h>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace sandbox {
+
+// See winerror.h for details.
+#define SEVERITY_INFO_FLAGS   0x40000000
+#define SEVERITY_ERROR_FLAGS  0xC0000000
+#define CUSTOMER_CODE         0x20000000
+#define SBOX_TESTS_FACILITY   0x05B10000
+
+// All the possible error codes returned by the child process in
+// the sandbox.
+enum SboxTestResult {
+  SBOX_TEST_FIRST_RESULT = CUSTOMER_CODE | SBOX_TESTS_FACILITY,
+  SBOX_TEST_SUCCEEDED,
+  SBOX_TEST_PING_OK,
+  SBOX_TEST_FIRST_INFO = SBOX_TEST_FIRST_RESULT | SEVERITY_INFO_FLAGS,
+  SBOX_TEST_DENIED,     // Access was denied.
+  SBOX_TEST_NOT_FOUND,  // The resource was not found.
+  SBOX_TEST_FIRST_ERROR = SBOX_TEST_FIRST_RESULT | SEVERITY_ERROR_FLAGS,
+  SBOX_TEST_SECOND_ERROR,
+  SBOX_TEST_THIRD_ERROR,
+  SBOX_TEST_FOURTH_ERROR,
+  SBOX_TEST_FIFTH_ERROR,
+  SBOX_TEST_SIXTH_ERROR,
+  SBOX_TEST_SEVENTH_ERROR,
+  SBOX_TEST_INVALID_PARAMETER,
+  SBOX_TEST_FAILED_TO_RUN_TEST,
+  SBOX_TEST_FAILED_TO_EXECUTE_COMMAND,
+  SBOX_TEST_TIMED_OUT,
+  SBOX_TEST_FAILED,
+  SBOX_TEST_LAST_RESULT
+};
+
+inline bool IsSboxTestsResult(SboxTestResult result) {
+  unsigned int code = static_cast<unsigned int>(result);
+  unsigned int first = static_cast<unsigned int>(SBOX_TEST_FIRST_RESULT);
+  unsigned int last = static_cast<unsigned int>(SBOX_TEST_LAST_RESULT);
+  return (code > first) && (code < last);
+}
+
+enum SboxTestsState {
+  MIN_STATE = 1,
+  BEFORE_INIT,
+  BEFORE_REVERT,
+  AFTER_REVERT,
+  EVERY_STATE,
+  MAX_STATE
+};
+
+#define SBOX_TESTS_API __declspec(dllexport)
+#define SBOX_TESTS_COMMAND extern "C" SBOX_TESTS_API
+
+extern "C" {
+typedef int (*CommandFunction)(int argc, wchar_t **argv);
+}
+
+// Class to facilitate the launch of a test inside the sandbox.
+class TestRunner {
+ public:
+  TestRunner(JobLevel job_level, TokenLevel startup_token,
+             TokenLevel main_token);
+
+  TestRunner();
+
+  ~TestRunner();
+
+  // Adds a rule to the policy. The parameters are the same as the AddRule
+  // function in the sandbox.
+  bool AddRule(TargetPolicy::SubSystem subsystem,
+               TargetPolicy::Semantics semantics,
+               const wchar_t* pattern);
+
+  // Adds a filesystem rules with the path of a file in system32. The function
+  // appends "pattern" to "system32" and then call AddRule. Return true if the
+  // function succeeds.
+  bool AddRuleSys32(TargetPolicy::Semantics semantics, const wchar_t* pattern);
+
+  // Adds a filesystem rules to the policy. Returns true if the functions
+  // succeeds.
+  bool AddFsRule(TargetPolicy::Semantics semantics, const wchar_t* pattern);
+
+  // Starts a child process in the sandbox and ask it to run |command|. Returns
+  // a SboxTestResult. By default, the test runs AFTER_REVERT.
+  int RunTest(const wchar_t* command);
+
+  // Sets the timeout value for the child to run the command and return.
+  void SetTimeout(DWORD timeout_ms);
+
+  // Sets TestRunner to return without waiting for the process to exit.
+  void SetAsynchronous(bool is_async) { is_async_ = is_async; }
+
+  // Sets TestRunner to return without waiting for the process to exit.
+  void SetUnsandboxed(bool is_no_sandbox) { no_sandbox_ = is_no_sandbox; }
+
+  // Sets the desired state for the test to run.
+  void SetTestState(SboxTestsState desired_state);
+
+  // Sets a flag whether the process should be killed when the TestRunner is
+  // destroyed.
+  void SetKillOnDestruction(bool value) { kill_on_destruction_ = value; }
+
+  // Returns the pointers to the policy object. It can be used to modify
+  // the policy manually.
+  TargetPolicy* GetPolicy();
+
+  BrokerServices* broker() { return broker_; }
+
+  // Returns the process handle for an asynchronous test.
+  HANDLE process() { return target_process_.Get(); }
+
+  // Returns the process ID for an asynchronous test.
+  DWORD process_id() { return target_process_id_; }
+
+ private:
+  // Initializes the data in the object. Sets is_init_ to tree if the
+  // function succeeds. This is meant to be called from the constructor.
+  void Init(JobLevel job_level, TokenLevel startup_token,
+            TokenLevel main_token);
+
+  // The actual runner.
+  int InternalRunTest(const wchar_t* command);
+
+  BrokerServices* broker_;
+  TargetPolicy* policy_;
+  DWORD timeout_;
+  SboxTestsState state_;
+  bool is_init_;
+  bool is_async_;
+  bool no_sandbox_;
+  bool kill_on_destruction_;
+  base::win::ScopedHandle target_process_;
+  DWORD target_process_id_;
+};
+
+// Returns the broker services.
+BrokerServices* GetBroker();
+
+// Constructs a full path to a file inside the system32 (or syswow64) folder.
+base::string16 MakePathToSys(const wchar_t* name, bool is_obj_man_path);
+
+// Runs the given test on the target process.
+int DispatchCall(int argc, wchar_t **argv);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_TESTS_COMMON_CONTROLLER_H_
diff --git a/sandbox/win/tests/common/test_utils.cc b/sandbox/win/tests/common/test_utils.cc
new file mode 100644
index 0000000..cdd86de
--- /dev/null
+++ b/sandbox/win/tests/common/test_utils.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/tests/common/test_utils.h"
+
+#include <winioctl.h>
+
+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 wchar_t* target) {
+  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;
+}
diff --git a/sandbox/win/tests/common/test_utils.h b/sandbox/win/tests/common/test_utils.h
new file mode 100644
index 0000000..9e17660
--- /dev/null
+++ b/sandbox/win/tests/common/test_utils.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_TESTS_COMMON_TEST_UTILS_H_
+#define SANDBOX_TESTS_COMMON_TEST_UTILS_H_
+
+#include <windows.h>
+
+// Sets a reparse point. |source| will now point to |target|. Returns true if
+// the call succeeds, false otherwise.
+bool SetReparsePoint(HANDLE source, const wchar_t* target);
+
+// Delete the reparse point referenced by |source|. Returns true if the call
+// succeeds, false otherwise.
+bool DeleteReparsePoint(HANDLE source);
+
+#endif  // SANDBOX_TESTS_COMMON_TEST_UTILS_H_
+
diff --git a/sandbox/win/tests/integration_tests/integration_tests.cc b/sandbox/win/tests/integration_tests/integration_tests.cc
new file mode 100644
index 0000000..3920da1
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/integration_tests.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/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/tests/common/controller.h"
+
+int wmain(int argc, wchar_t **argv) {
+  if (argc >= 2) {
+    if (0 == _wcsicmp(argv[1], L"-child") ||
+        0 == _wcsicmp(argv[1], L"-child-no-sandbox"))
+      // This instance is a child, not the test.
+      return sandbox::DispatchCall(argc, argv);
+  }
+
+  base::TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      false,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/sandbox/win/tests/integration_tests/integration_tests_test.cc b/sandbox/win/tests/integration_tests/integration_tests_test.cc
new file mode 100644
index 0000000..44055d3
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/integration_tests_test.cc
@@ -0,0 +1,306 @@
+// 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.
+
+// Some tests for the framework itself.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/tests/common/controller.h"
+
+namespace sandbox {
+
+// Returns the current process state.
+SBOX_TESTS_COMMAND int IntegrationTestsTest_state(int argc, wchar_t **argv) {
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+    return BEFORE_INIT;
+
+  if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+    return BEFORE_REVERT;
+
+  return AFTER_REVERT;
+}
+
+// Returns the current process state, keeping track of it.
+SBOX_TESTS_COMMAND int IntegrationTestsTest_state2(int argc, wchar_t **argv) {
+  static SboxTestsState state = MIN_STATE;
+  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) {
+    if (MIN_STATE == state)
+      state = BEFORE_INIT;
+    return state;
+  }
+
+  if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
+    if (BEFORE_INIT == state)
+      state = BEFORE_REVERT;
+    return state;
+  }
+
+  if (BEFORE_REVERT == state)
+    state =  AFTER_REVERT;
+  return state;
+}
+
+// Blocks the process for argv[0] milliseconds simulating stuck child.
+SBOX_TESTS_COMMAND int IntegrationTestsTest_stuck(int argc, wchar_t **argv) {
+  int timeout = 500;
+  if (argc > 0) {
+    timeout = _wtoi(argv[0]);
+  }
+
+  ::Sleep(timeout);
+  return 1;
+}
+
+// Returns the number of arguments
+SBOX_TESTS_COMMAND int IntegrationTestsTest_args(int argc, wchar_t **argv) {
+  for (int i = 0; i < argc; i++) {
+    wchar_t argument[20];
+    size_t argument_bytes = wcslen(argv[i]) * sizeof(wchar_t);
+    memcpy(argument, argv[i], __min(sizeof(argument), argument_bytes));
+  }
+
+  return argc;
+}
+
+// Creates a job and tries to run a process inside it. The function can be
+// called with up to two parameters. The first one if set to "none" means that
+// the child process should be run with the JOB_NONE JobLevel else it is run
+// with JOB_LOCKDOWN level. The second if present specifies that the
+// JOB_OBJECT_LIMIT_BREAKAWAY_OK flag should be set on the job object created
+// in this function. The return value is either SBOX_TEST_SUCCEEDED if the test
+// has passed or a value between 0 and 4 indicating which part of the test has
+// failed.
+SBOX_TESTS_COMMAND int IntegrationTestsTest_job(int argc, wchar_t **argv) {
+  HANDLE job = ::CreateJobObject(NULL, NULL);
+  if (!job)
+    return 0;
+
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limits;
+  if (!::QueryInformationJobObject(job, JobObjectExtendedLimitInformation,
+                                   &job_limits, sizeof(job_limits), NULL)) {
+    return 1;
+  }
+  // We cheat here and assume no 2-nd parameter means no breakaway flag and any
+  // value for the second param means with breakaway flag.
+  if (argc > 1) {
+    job_limits.BasicLimitInformation.LimitFlags |=
+        JOB_OBJECT_LIMIT_BREAKAWAY_OK;
+  } else {
+    job_limits.BasicLimitInformation.LimitFlags &=
+        ~JOB_OBJECT_LIMIT_BREAKAWAY_OK;
+  }
+  if (!::SetInformationJobObject(job, JobObjectExtendedLimitInformation,
+                                &job_limits, sizeof(job_limits))) {
+    return 2;
+  }
+  if (!::AssignProcessToJobObject(job, ::GetCurrentProcess()))
+    return 3;
+
+  JobLevel job_level = JOB_LOCKDOWN;
+  if (argc > 0 && wcscmp(argv[0], L"none") == 0)
+    job_level = JOB_NONE;
+
+  TestRunner runner(job_level, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+  runner.SetTimeout(2000);
+
+  if (1 != runner.RunTest(L"IntegrationTestsTest_args 1"))
+    return 4;
+
+  // Terminate the job now.
+  ::TerminateJobObject(job, SBOX_TEST_SUCCEEDED);
+  // We should not make it to here but it doesn't mean our test failed.
+  return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(IntegrationTestsTest, CallsBeforeInit) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(BEFORE_INIT);
+  ASSERT_EQ(BEFORE_INIT, runner.RunTest(L"IntegrationTestsTest_state"));
+}
+
+TEST(IntegrationTestsTest, CallsBeforeRevert) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(BEFORE_REVERT);
+  ASSERT_EQ(BEFORE_REVERT, runner.RunTest(L"IntegrationTestsTest_state"));
+}
+
+TEST(IntegrationTestsTest, CallsAfterRevert) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(AFTER_REVERT);
+  ASSERT_EQ(AFTER_REVERT, runner.RunTest(L"IntegrationTestsTest_state"));
+}
+
+TEST(IntegrationTestsTest, CallsEveryState) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(EVERY_STATE);
+  ASSERT_EQ(AFTER_REVERT, runner.RunTest(L"IntegrationTestsTest_state2"));
+}
+
+TEST(IntegrationTestsTest, ForwardsArguments) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetTestState(BEFORE_INIT);
+  ASSERT_EQ(1, runner.RunTest(L"IntegrationTestsTest_args first"));
+  ASSERT_EQ(4, runner.RunTest(L"IntegrationTestsTest_args first second third "
+                              L"fourth"));
+}
+
+TEST(IntegrationTestsTest, WaitForStuckChild) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetAsynchronous(true);
+  runner.SetKillOnDestruction(false);
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_stuck 100"));
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+}
+
+TEST(IntegrationTestsTest, NoWaitForStuckChildNoJob) {
+  TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+  runner.SetTimeout(2000);
+  runner.SetAsynchronous(true);
+  runner.SetKillOnDestruction(false);
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_stuck 2000"));
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+  // In this case the processes are not tracked by the broker and should be
+  // still active.
+  DWORD exit_code;
+  ASSERT_TRUE(::GetExitCodeProcess(runner.process(), &exit_code));
+  ASSERT_EQ(STILL_ACTIVE, exit_code);
+  // Terminate the test process now.
+  ::TerminateProcess(runner.process(), 0);
+}
+
+TEST(IntegrationTestsTest, TwoStuckChildrenSecondOneHasNoJob) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetAsynchronous(true);
+  runner.SetKillOnDestruction(false);
+  TestRunner runner2(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+  runner2.SetTimeout(2000);
+  runner2.SetAsynchronous(true);
+  runner2.SetKillOnDestruction(false);
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_stuck 100"));
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner2.RunTest(L"IntegrationTestsTest_stuck 2000"));
+  // Actually both runners share the same singleton broker.
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+  // In this case the processes are not tracked by the broker and should be
+  // still active.
+  DWORD exit_code;
+  // Checking the exit code for |runner| is flaky on the slow bots but at
+  // least we know that the wait above has succeeded if we are here.
+  ASSERT_TRUE(::GetExitCodeProcess(runner2.process(), &exit_code));
+  ASSERT_EQ(STILL_ACTIVE, exit_code);
+  // Terminate the test process now.
+  ::TerminateProcess(runner2.process(), 0);
+}
+
+TEST(IntegrationTestsTest, TwoStuckChildrenFirstOneHasNoJob) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetAsynchronous(true);
+  runner.SetKillOnDestruction(false);
+  TestRunner runner2(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+  runner2.SetTimeout(2000);
+  runner2.SetAsynchronous(true);
+  runner2.SetKillOnDestruction(false);
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner2.RunTest(L"IntegrationTestsTest_stuck 2000"));
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_stuck 100"));
+  // Actually both runners share the same singleton broker.
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+  // In this case the processes are not tracked by the broker and should be
+  // still active.
+  DWORD exit_code;
+  // Checking the exit code for |runner| is flaky on the slow bots but at
+  // least we know that the wait above has succeeded if we are here.
+  ASSERT_TRUE(::GetExitCodeProcess(runner2.process(), &exit_code));
+  ASSERT_EQ(STILL_ACTIVE, exit_code);
+  // Terminate the test process now.
+  ::TerminateProcess(runner2.process(), 0);
+}
+
+TEST(IntegrationTestsTest, MultipleStuckChildrenSequential) {
+  TestRunner runner;
+  runner.SetTimeout(2000);
+  runner.SetAsynchronous(true);
+  runner.SetKillOnDestruction(false);
+  TestRunner runner2(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+  runner2.SetTimeout(2000);
+  runner2.SetAsynchronous(true);
+  runner2.SetKillOnDestruction(false);
+
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_stuck 100"));
+  // Actually both runners share the same singleton broker.
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner2.RunTest(L"IntegrationTestsTest_stuck 2000"));
+  // Actually both runners share the same singleton broker.
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+
+  DWORD exit_code;
+  // Checking the exit code for |runner| is flaky on the slow bots but at
+  // least we know that the wait above has succeeded if we are here.
+  ASSERT_TRUE(::GetExitCodeProcess(runner2.process(), &exit_code));
+  ASSERT_EQ(STILL_ACTIVE, exit_code);
+  // Terminate the test process now.
+  ::TerminateProcess(runner2.process(), 0);
+
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_stuck 100"));
+  // Actually both runners share the same singleton broker.
+  ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets());
+}
+
+// Running from inside job that allows us to escape from it should be ok.
+TEST(IntegrationTestsTest, RunChildFromInsideJob) {
+  TestRunner runner;
+  runner.SetUnsandboxed(true);
+  runner.SetTimeout(2000);
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_job with_job escape_flag"));
+}
+
+// Running from inside job that doesn't allow us to escape from it should fail
+// on any windows prior to 8.
+TEST(IntegrationTestsTest, RunChildFromInsideJobNoEscape) {
+  int expect_result = 4;  // Means the runner has failed to execute the child.
+  // Check if we are on Win8 or newer and expect a success as newer windows
+  // versions support nested jobs.
+  OSVERSIONINFOEX version_info = { sizeof version_info };
+  ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
+  if (version_info.dwMajorVersion > 6 ||
+      (version_info.dwMajorVersion == 6 && version_info.dwMinorVersion >= 2)) {
+    expect_result = SBOX_TEST_SUCCEEDED;
+  }
+
+  TestRunner runner;
+  runner.SetUnsandboxed(true);
+  runner.SetTimeout(2000);
+  ASSERT_EQ(expect_result,
+            runner.RunTest(L"IntegrationTestsTest_job with_job"));
+}
+
+// Running without a job object should be ok regardless of the fact that we are
+// running inside an outter job.
+TEST(IntegrationTestsTest, RunJoblessChildFromInsideJob) {
+  TestRunner runner;
+  runner.SetUnsandboxed(true);
+  runner.SetTimeout(2000);
+  ASSERT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"IntegrationTestsTest_job none"));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj b/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj
new file mode 100644
index 0000000..53816e7
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sbox_integration_tests"
+	ProjectGUID="{542D4B3B-98D4-4233-B68D-0103891508C6}"
+	RootNamespace="unit_tests"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Common"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{49F2D231-E141-4455-B241-7D37C09B6EEB}"
+			>
+			<File
+				RelativePath="..\common\controller.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\common\controller.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\integration_tests.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath="..\..\src\dep_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\file_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\integration_tests_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\integrity_level_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\ipc_ping_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\named_pipe_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\policy_target_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\process_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\registry_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\sync_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\unload_dll_test.cc"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/tests/unit_tests/sbox_unittests.vcproj b/sandbox/win/tests/unit_tests/sbox_unittests.vcproj
new file mode 100644
index 0000000..a2df792
--- /dev/null
+++ b/sandbox/win/tests/unit_tests/sbox_unittests.vcproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sbox_unittests"
+	ProjectGUID="{883553BE-2A9D-418C-A121-61FE1DFBC562}"
+	RootNamespace="unit_tests"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Common"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+			<File
+				RelativePath=".\unit_tests.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="TestInterception"
+			>
+			<File
+				RelativePath="..\..\src\interception_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\pe_image_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\service_resolver_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="TestRestrictedToken"
+			>
+			<File
+				RelativePath="..\..\src\restricted_token_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="TestJob"
+			>
+			<File
+				RelativePath="..\..\src\job_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Sid"
+			>
+			<File
+				RelativePath="..\..\src\sid_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Policy"
+			>
+			<File
+				RelativePath="..\..\src\policy_engine_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\policy_low_level_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\policy_opcodes_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="IPC"
+			>
+			<File
+				RelativePath="..\..\src\ipc_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\threadpool_unittest.cc"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/tests/unit_tests/unit_tests.cc b/sandbox/win/tests/unit_tests/unit_tests.cc
new file mode 100644
index 0000000..bd56ab0
--- /dev/null
+++ b/sandbox/win/tests/unit_tests/unit_tests.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/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+int wmain(int argc, wchar_t **argv) {
+  if (argc >= 2) {
+    if (0 == _wcsicmp(argv[1], L"-child"))
+      // This instance is a child, not the test.
+      return 0;
+  }
+
+  base::TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      false,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/sandbox/win/tests/validation_tests/commands.cc b/sandbox/win/tests/validation_tests/commands.cc
new file mode 100644
index 0000000..10a4a13
--- /dev/null
+++ b/sandbox/win/tests/validation_tests/commands.cc
@@ -0,0 +1,289 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <Aclapi.h>
+#include <windows.h>
+#include <string>
+
+#include "sandbox/win/tests/validation_tests/commands.h"
+
+#include "sandbox/win/tests/common/controller.h"
+
+namespace {
+
+// Returns the HKEY corresponding to name. If there is no HKEY corresponding
+// to the name it returns NULL.
+HKEY GetHKEYFromString(const base::string16 &name) {
+  if (name == L"HKLM")
+    return HKEY_LOCAL_MACHINE;
+  if (name == L"HKCR")
+    return HKEY_CLASSES_ROOT;
+  if (name == L"HKCC")
+    return HKEY_CURRENT_CONFIG;
+  if (name == L"HKCU")
+    return HKEY_CURRENT_USER;
+  if (name == L"HKU")
+    return HKEY_USERS;
+
+  return NULL;
+}
+
+// Modifies string to remove the leading and trailing quotes.
+void trim_quote(base::string16* string) {
+  base::string16::size_type pos1 = string->find_first_not_of(L'"');
+  base::string16::size_type pos2 = string->find_last_not_of(L'"');
+
+  if (pos1 == base::string16::npos || pos2 == base::string16::npos)
+    string->clear();
+  else
+    (*string) = string->substr(pos1, pos2 + 1);
+}
+
+int TestOpenFile(base::string16 path, bool for_write) {
+  wchar_t path_expanded[MAX_PATH + 1] = {0};
+  DWORD size = ::ExpandEnvironmentStrings(path.c_str(), path_expanded,
+                                          MAX_PATH);
+  if (!size)
+    return sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  HANDLE file;
+  file = ::CreateFile(path_expanded,
+                      for_write ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
+                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                      NULL,  // No security attributes.
+                      OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS,
+                      NULL);  // No template.
+
+  if (file != INVALID_HANDLE_VALUE) {
+    ::CloseHandle(file);
+    return sandbox::SBOX_TEST_SUCCEEDED;
+  }
+  return (::GetLastError() == ERROR_ACCESS_DENIED) ?
+      sandbox::SBOX_TEST_DENIED : sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int ValidWindow(int argc, wchar_t **argv) {
+  return (argc == 1) ?
+      TestValidWindow(
+          reinterpret_cast<HWND>(static_cast<ULONG_PTR>(_wtoi(argv[0])))) :
+      SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+int TestValidWindow(HWND window) {
+  return ::IsWindow(window) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+}
+
+SBOX_TESTS_COMMAND int OpenProcessCmd(int argc, wchar_t **argv) {
+  return (argc == 2) ?
+      TestOpenProcess(_wtol(argv[0]), _wtol(argv[1])) :
+      SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+int TestOpenProcess(DWORD process_id, DWORD access_mask) {
+  HANDLE process = ::OpenProcess(access_mask,
+                                 FALSE,  // Do not inherit handle.
+                                 process_id);
+  if (process != NULL) {
+    ::CloseHandle(process);
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return (::GetLastError() == ERROR_ACCESS_DENIED) ?
+      sandbox::SBOX_TEST_DENIED : sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+SBOX_TESTS_COMMAND int OpenThreadCmd(int argc, wchar_t **argv) {
+  return (argc == 1) ?
+      TestOpenThread(_wtoi(argv[0])) : SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+int TestOpenThread(DWORD thread_id) {
+  HANDLE thread = ::OpenThread(THREAD_QUERY_INFORMATION,
+                               FALSE,  // Do not inherit handles.
+                               thread_id);
+  if (thread != NULL) {
+    ::CloseHandle(thread);
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return (::GetLastError() == ERROR_ACCESS_DENIED) ?
+      sandbox::SBOX_TEST_DENIED : sandbox::SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+SBOX_TESTS_COMMAND int OpenFileCmd(int argc, wchar_t **argv) {
+  if (1 != argc)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::string16 path = argv[0];
+  trim_quote(&path);
+
+  return TestOpenReadFile(path);
+}
+
+int TestOpenReadFile(const base::string16& path) {
+  return TestOpenFile(path, false);
+}
+
+int TestOpenWriteFile(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  base::string16 path = argv[0];
+  trim_quote(&path);
+  return TestOpenWriteFile(path);
+}
+
+int TestOpenWriteFile(const base::string16& path) {
+  return TestOpenFile(path, true);
+}
+
+SBOX_TESTS_COMMAND int OpenKey(int argc, wchar_t **argv) {
+  if (argc != 1 && argc != 2)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  // Get the hive.
+  HKEY base_key = GetHKEYFromString(argv[0]);
+
+  // Get the subkey.
+  base::string16 subkey;
+  if (argc == 2) {
+    subkey = argv[1];
+    trim_quote(&subkey);
+  }
+
+  return TestOpenKey(base_key, subkey);
+}
+
+int TestOpenKey(HKEY base_key, base::string16 subkey) {
+  HKEY key;
+  LONG err_code = ::RegOpenKeyEx(base_key,
+                                 subkey.c_str(),
+                                 0,  // Reserved, must be 0.
+                                 MAXIMUM_ALLOWED,
+                                 &key);
+  if (err_code == ERROR_SUCCESS) {
+    ::RegCloseKey(key);
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return (err_code == ERROR_INVALID_HANDLE || err_code == ERROR_ACCESS_DENIED) ?
+      SBOX_TEST_DENIED : SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+}
+
+// Returns true if the current's thread desktop is the interactive desktop.
+// In Vista there is a more direct test but for XP and w2k we need to check
+// the object name.
+bool IsInteractiveDesktop(bool* is_interactive) {
+  HDESK current_desk = ::GetThreadDesktop(::GetCurrentThreadId());
+  if (current_desk == NULL)
+    return false;
+  wchar_t current_desk_name[256] = {0};
+  if (!::GetUserObjectInformationW(current_desk, UOI_NAME, current_desk_name,
+                                   sizeof(current_desk_name), NULL))
+    return false;
+  *is_interactive = (0 == _wcsicmp(L"default", current_desk_name));
+  return true;
+}
+
+SBOX_TESTS_COMMAND int OpenInteractiveDesktop(int, wchar_t **) {
+  return TestOpenInputDesktop();
+}
+
+int TestOpenInputDesktop() {
+  bool is_interactive = false;
+  if (IsInteractiveDesktop(&is_interactive) && is_interactive)
+    return SBOX_TEST_SUCCEEDED;
+  HDESK desk = ::OpenInputDesktop(0, FALSE, DESKTOP_CREATEWINDOW);
+  if (desk) {
+    ::CloseDesktop(desk);
+    return SBOX_TEST_SUCCEEDED;
+  }
+  return SBOX_TEST_DENIED;
+}
+
+SBOX_TESTS_COMMAND int SwitchToSboxDesktop(int, wchar_t **) {
+  return TestSwitchDesktop();
+}
+
+int TestSwitchDesktop() {
+  HDESK desktop = ::GetThreadDesktop(::GetCurrentThreadId());
+  if (desktop == NULL)
+    return SBOX_TEST_FAILED;
+  return ::SwitchDesktop(desktop) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+}
+
+SBOX_TESTS_COMMAND int OpenAlternateDesktop(int, wchar_t **argv) {
+  return TestOpenAlternateDesktop(argv[0]);
+}
+
+int TestOpenAlternateDesktop(wchar_t *desktop_name) {
+  // Test for WRITE_DAC permission on the handle.
+  HDESK desktop = ::GetThreadDesktop(::GetCurrentThreadId());
+  if (desktop) {
+    HANDLE test_handle;
+    if (::DuplicateHandle(::GetCurrentProcess(), desktop,
+                          ::GetCurrentProcess(), &test_handle,
+                          WRITE_DAC, FALSE, 0)) {
+      DWORD result = ::SetSecurityInfo(test_handle, SE_WINDOW_OBJECT,
+                                       DACL_SECURITY_INFORMATION, NULL, NULL,
+                                       NULL, NULL);
+      ::CloseHandle(test_handle);
+      if (result == ERROR_SUCCESS)
+        return SBOX_TEST_SUCCEEDED;
+    } else if (::GetLastError() != ERROR_ACCESS_DENIED) {
+      return SBOX_TEST_FAILED;
+    }
+  }
+
+  // Open by name with WRITE_DAC.
+  desktop = ::OpenDesktop(desktop_name, 0, FALSE, WRITE_DAC);
+  if (!desktop && ::GetLastError() == ERROR_ACCESS_DENIED)
+    return SBOX_TEST_DENIED;
+  ::CloseDesktop(desktop);
+  return SBOX_TEST_SUCCEEDED;
+}
+
+BOOL CALLBACK DesktopTestEnumProc(LPTSTR desktop_name, LPARAM result) {
+  return TRUE;
+}
+
+SBOX_TESTS_COMMAND int EnumAlternateWinsta(int, wchar_t **) {
+  return TestEnumAlternateWinsta();
+}
+
+int TestEnumAlternateWinsta() {
+  // Try to enumerate the destops on the alternate windowstation.
+  return ::EnumDesktopsW(NULL, DesktopTestEnumProc, 0) ?
+      SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+}
+
+SBOX_TESTS_COMMAND int SleepCmd(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  ::Sleep(_wtoi(argv[0]));
+  return SBOX_TEST_SUCCEEDED;
+}
+
+SBOX_TESTS_COMMAND int AllocateCmd(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  size_t mem_size = static_cast<size_t>(_wtoll(argv[0]));
+  void* memory = ::VirtualAlloc(NULL, mem_size, MEM_COMMIT | MEM_RESERVE,
+                                PAGE_READWRITE);
+  if (!memory) {
+    // We need to give the broker a chance to kill our process on failure.
+    ::Sleep(5000);
+    return SBOX_TEST_DENIED;
+  }
+
+  return ::VirtualFree(memory, 0, MEM_RELEASE) ?
+      SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+}
+
+
+}  // namespace sandbox
diff --git a/sandbox/win/tests/validation_tests/commands.h b/sandbox/win/tests/validation_tests/commands.h
new file mode 100644
index 0000000..f9b6199
--- /dev/null
+++ b/sandbox/win/tests/validation_tests/commands.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 SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__
+#define SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__
+
+#include <windows.h>
+
+#include "base/strings/string16.h"
+
+namespace sandbox {
+
+// Checks if window is a real window. Returns a SboxTestResult.
+int TestValidWindow(HWND window);
+
+// Tries to open the process_id. Returns a SboxTestResult.
+int TestOpenProcess(DWORD process_id, DWORD access_mask);
+
+// Tries to open thread_id. Returns a SboxTestResult.
+int TestOpenThread(DWORD thread_id);
+
+// Tries to open path for read access. Returns a SboxTestResult.
+int TestOpenReadFile(const base::string16& path);
+
+// Tries to open path for write access. Returns a SboxTestResult.
+int TestOpenWriteFile(const base::string16& path);
+
+// Tries to open a registry key.
+int TestOpenKey(HKEY base_key, base::string16 subkey);
+
+// Tries to open the workstation's input desktop as long as the
+// current desktop is not the interactive one. Returns a SboxTestResult.
+int TestOpenInputDesktop();
+
+// Tries to switch the interactive desktop. Returns a SboxTestResult.
+int TestSwitchDesktop();
+
+// Tries to open the alternate desktop. Returns a SboxTestResult.
+int TestOpenAlternateDesktop(wchar_t *desktop_name);
+
+// Tries to enumerate desktops on the alternate windowstation.
+// Returns a SboxTestResult.
+int TestEnumAlternateWinsta();
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_TESTS_VALIDATION_TESTS_COMMANDS_H__
diff --git a/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj b/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj
new file mode 100644
index 0000000..9b7b599
--- /dev/null
+++ b/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sbox_validation_tests"
+	ProjectGUID="{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}"
+	RootNamespace="unit_tests"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="shlwapi.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="shlwapi.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Common"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{2E6C7E35-7538-4883-B80C-C89961A80D66}"
+			>
+			<File
+				RelativePath="..\common\controller.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\common\controller.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+			<File
+				RelativePath=".\unit_tests.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Suite"
+			>
+			<File
+				RelativePath=".\commands.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\commands.h"
+				>
+			</File>
+			<File
+				RelativePath=".\suite.cc"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/tests/validation_tests/suite.cc b/sandbox/win/tests/validation_tests/suite.cc
new file mode 100644
index 0000000..35fb5dd
--- /dev/null
+++ b/sandbox/win/tests/validation_tests/suite.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2012 The Chromium 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 validation tests for the sandbox.
+// It includes the tests that need to be performed inside the
+// sandbox.
+
+#include <shlwapi.h>
+
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/tests/common/controller.h"
+
+#pragma comment(lib, "shlwapi.lib")
+
+namespace {
+
+void TestProcessAccess(sandbox::TestRunner* runner, DWORD target) {
+  const wchar_t *kCommandTemplate = L"OpenProcessCmd %d %d";
+  wchar_t command[1024] = {0};
+
+  // Test all the scary process permissions.
+  wsprintf(command, kCommandTemplate, target, PROCESS_CREATE_THREAD);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, PROCESS_DUP_HANDLE);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, PROCESS_SET_INFORMATION);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, PROCESS_VM_OPERATION);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, PROCESS_VM_READ);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, PROCESS_VM_WRITE);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, PROCESS_QUERY_INFORMATION);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, WRITE_DAC);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, WRITE_OWNER);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+  wsprintf(command, kCommandTemplate, target, READ_CONTROL);
+  EXPECT_EQ(sandbox::SBOX_TEST_DENIED, runner->RunTest(command));
+}
+
+}  // namespace
+
+namespace sandbox {
+
+// Returns true if the volume that contains any_path supports ACL security. The
+// input path can contain unexpanded environment strings. Returns false on any
+// failure or if the file system does not support file security (such as FAT).
+bool VolumeSupportsACLs(const wchar_t* any_path) {
+  wchar_t expand[MAX_PATH +1];
+  DWORD len =::ExpandEnvironmentStringsW(any_path, expand, _countof(expand));
+  if (0 == len) return false;
+  if (len >  _countof(expand)) return false;
+  if (!::PathStripToRootW(expand)) return false;
+  DWORD fs_flags = 0;
+  if (!::GetVolumeInformationW(expand, NULL, 0, 0, NULL, &fs_flags, NULL, 0))
+    return false;
+  if (fs_flags & FILE_PERSISTENT_ACLS) return true;
+  return false;
+}
+
+// Tests if the suite is working properly.
+TEST(ValidationSuite, TestSuite) {
+  TestRunner runner;
+  ASSERT_EQ(SBOX_TEST_PING_OK, runner.RunTest(L"ping"));
+}
+
+// Tests if the file system is correctly protected by the sandbox.
+TEST(ValidationSuite, TestFileSystem) {
+  // Do not perform the test if the system is using FAT or any other
+  // file system that does not have file security.
+  ASSERT_TRUE(VolumeSupportsACLs(L"%SystemDrive%\\"));
+  ASSERT_TRUE(VolumeSupportsACLs(L"%SystemRoot%\\"));
+  ASSERT_TRUE(VolumeSupportsACLs(L"%ProgramFiles%\\"));
+  ASSERT_TRUE(VolumeSupportsACLs(L"%Temp%\\"));
+  ASSERT_TRUE(VolumeSupportsACLs(L"%AppData%\\"));
+
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFileCmd %SystemDrive%"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFileCmd %SystemRoot%"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFileCmd %ProgramFiles%"));
+  EXPECT_EQ(SBOX_TEST_DENIED,
+      runner.RunTest(L"OpenFileCmd %SystemRoot%\\System32"));
+  EXPECT_EQ(SBOX_TEST_DENIED,
+      runner.RunTest(L"OpenFileCmd %SystemRoot%\\explorer.exe"));
+  EXPECT_EQ(SBOX_TEST_DENIED,
+      runner.RunTest(L"OpenFileCmd %SystemRoot%\\Cursors\\arrow_i.cur"));
+  EXPECT_EQ(SBOX_TEST_DENIED,
+      runner.RunTest(L"OpenFileCmd %AllUsersProfile%"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFileCmd %Temp%"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenFileCmd %AppData%"));
+}
+
+// Tests if the registry is correctly protected by the sandbox.
+TEST(ValidationSuite, TestRegistry) {
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenKey HKLM"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenKey HKCU"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenKey HKU"));
+  EXPECT_EQ(SBOX_TEST_DENIED,
+      runner.RunTest(
+          L"OpenKey HKLM "
+          L"\"Software\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon\""));
+}
+
+// Tests that the permissions on the Windowstation does not allow the sandbox
+// to get to the interactive desktop or to make the sbox desktop interactive.
+TEST(ValidationSuite, TestDesktop) {
+  TestRunner runner;
+  runner.GetPolicy()->SetAlternateDesktop(true);
+  runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"OpenInteractiveDesktop NULL"));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"SwitchToSboxDesktop NULL"));
+}
+
+// Tests that the permissions on the Windowstation does not allow the sandbox
+// to get to the interactive desktop or to make the sbox desktop interactive.
+TEST(ValidationSuite, TestAlternateDesktop) {
+  base::win::Version version = base::win::GetVersion();
+  if (version < base::win::VERSION_WIN7)
+    return;
+
+  TestRunner runner;
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"EnumAlternateWinsta NULL"));
+
+  wchar_t command[1024] = {0};
+  runner.SetTimeout(3600000);
+  runner.GetPolicy()->SetAlternateDesktop(true);
+  runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+  base::string16 desktop_name = runner.GetPolicy()->GetAlternateDesktop();
+  desktop_name = desktop_name.substr(desktop_name.find('\\') + 1);
+  wsprintf(command, L"OpenAlternateDesktop %lS", desktop_name.c_str());
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+}
+
+// Tests if the windows are correctly protected by the sandbox.
+TEST(ValidationSuite, TestWindows) {
+  TestRunner runner;
+  wchar_t command[1024] = {0};
+
+  wsprintf(command, L"ValidWindow %Id",
+           reinterpret_cast<size_t>(::GetDesktopWindow()));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+  wsprintf(command, L"ValidWindow %Id",
+           reinterpret_cast<size_t>(::FindWindow(NULL, NULL)));
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+}
+
+// Tests that a locked-down process cannot open another locked-down process.
+TEST(ValidationSuite, TestProcessDenyLockdown) {
+  TestRunner runner;
+  TestRunner target;
+
+  target.SetAsynchronous(true);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"SleepCmd 30000"));
+
+  TestProcessAccess(&runner, target.process_id());
+}
+
+// Tests that a low-integrity process cannot open a locked-down process (due
+// to the integrity label changing after startup via SetDelayedIntegrityLevel).
+TEST(ValidationSuite, TestProcessDenyLowIntegrity) {
+  // This test applies only to Vista and above.
+  if (base::win::Version() < base::win::VERSION_VISTA)
+    return;
+
+  TestRunner runner;
+  TestRunner target;
+
+  target.SetAsynchronous(true);
+  target.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_LOW);
+
+  runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+  runner.GetPolicy()->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS,
+                                    USER_INTERACTIVE);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"SleepCmd 30000"));
+
+  TestProcessAccess(&runner, target.process_id());
+}
+
+// Tests that a locked-down process cannot open a low-integrity process.
+TEST(ValidationSuite, TestProcessDenyBelowLowIntegrity) {
+  //  This test applies only to Vista and above.
+  if (base::win::Version() < base::win::VERSION_VISTA)
+    return;
+
+  TestRunner runner;
+  TestRunner target;
+
+  target.SetAsynchronous(true);
+  target.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+  target.GetPolicy()->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS,
+                                    USER_INTERACTIVE);
+
+  runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED);
+  runner.GetPolicy()->SetTokenLevel(USER_RESTRICTED_SAME_ACCESS,
+                                    USER_INTERACTIVE);
+
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"SleepCmd 30000"));
+
+  TestProcessAccess(&runner, target.process_id());
+}
+
+// Tests if the threads are correctly protected by the sandbox.
+TEST(ValidationSuite, TestThread) {
+  TestRunner runner;
+  wchar_t command[1024] = {0};
+
+  wsprintf(command, L"OpenThreadCmd %d", ::GetCurrentThreadId());
+  EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+}
+
+// Tests if an over-limit allocation will be denied.
+TEST(ValidationSuite, TestMemoryLimit) {
+  TestRunner runner;
+  wchar_t command[1024] = {0};
+  const int kAllocationSize = 256 * 1024 * 1024;
+
+  wsprintf(command, L"AllocateCmd %d", kAllocationSize);
+  runner.GetPolicy()->SetJobMemoryLimit(kAllocationSize);
+  EXPECT_EQ(SBOX_FATAL_MEMORY_EXCEEDED, runner.RunTest(command));
+}
+
+// Tests a large allocation will succeed absent limits.
+TEST(ValidationSuite, TestMemoryNoLimit) {
+  TestRunner runner;
+  wchar_t command[1024] = {0};
+  const int kAllocationSize = 256 * 1024 * 1024;
+
+  wsprintf(command, L"AllocateCmd %d", kAllocationSize);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/tests/validation_tests/unit_tests.cc b/sandbox/win/tests/validation_tests/unit_tests.cc
new file mode 100644
index 0000000..592b6c0
--- /dev/null
+++ b/sandbox/win/tests/validation_tests/unit_tests.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/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "sandbox/win/tests/common/controller.h"
+
+int wmain(int argc, wchar_t **argv) {
+  if (argc >= 2) {
+    if (0 == _wcsicmp(argv[1], L"-child"))
+      return sandbox::DispatchCall(argc, argv);
+  }
+
+  base::TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      false,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/sandbox/win/tools/finder/finder.cc b/sandbox/win/tools/finder/finder.cc
new file mode 100644
index 0000000..9b82962
--- /dev/null
+++ b/sandbox/win/tools/finder/finder.cc
@@ -0,0 +1,64 @@
+// 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 "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/tools/finder/finder.h"
+
+Finder::Finder() {
+  file_output_ = NULL;
+  object_type_ = 0;
+  access_type_ = 0;
+  token_handle_ = NULL;
+  memset(filesystem_stats_, 0, sizeof(filesystem_stats_));
+  memset(registry_stats_, 0, sizeof(registry_stats_));
+  memset(kernel_object_stats_, 0, sizeof(kernel_object_stats_));
+}
+
+Finder::~Finder() {
+  if (token_handle_)
+    ::CloseHandle(token_handle_);
+}
+
+DWORD Finder::Init(sandbox::TokenLevel token_type,
+                   DWORD object_type,
+                   DWORD access_type,
+                   FILE *file_output) {
+  DWORD err_code = ERROR_SUCCESS;
+
+  err_code = InitNT();
+  if (ERROR_SUCCESS != err_code)
+    return err_code;
+
+  object_type_ = object_type;
+  access_type_ = access_type;
+  file_output_ = file_output;
+
+  err_code = sandbox::CreateRestrictedToken(&token_handle_, token_type,
+                                            sandbox::INTEGRITY_LEVEL_LAST,
+                                            sandbox::PRIMARY);
+  return err_code;
+}
+
+DWORD Finder::Scan() {
+  if (!token_handle_) {
+    return ERROR_NO_TOKEN;
+  }
+
+  if (object_type_ & kScanRegistry) {
+    ParseRegistry(HKEY_LOCAL_MACHINE, L"HKLM\\");
+    ParseRegistry(HKEY_USERS, L"HKU\\");
+    ParseRegistry(HKEY_CURRENT_CONFIG, L"HKCC\\");
+  }
+
+  if (object_type_ & kScanFileSystem) {
+    ParseFileSystem(L"\\\\?\\C:");
+  }
+
+  if (object_type_ & kScanKernelObjects) {
+    ParseKernelObjects(L"\\");
+  }
+
+  return ERROR_SUCCESS;
+}
diff --git a/sandbox/win/tools/finder/finder.h b/sandbox/win/tools/finder/finder.h
new file mode 100644
index 0000000..23255ce
--- /dev/null
+++ b/sandbox/win/tools/finder/finder.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_TOOLS_FINDER_FINDER_H__
+#define SANDBOX_TOOLS_FINDER_FINDER_H__
+
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/tools/finder/ntundoc.h"
+
+// Type of stats that we calculate during the Scan operation
+enum Stats {
+  READ = 0,     // Number of objects with read access
+  WRITE,        // Number of objects with write access
+  ALL,          // Number of objects with r/w access
+  PARSE,        // Number of objects parsed
+  BROKEN,       // Number of errors while parsing the objects
+  SIZE_STATS    // size of the enum
+};
+
+const int kScanRegistry       = 0x01;
+const int kScanFileSystem     = 0x02;
+const int kScanKernelObjects  = 0x04;
+
+const int kTestForRead        = 0x01;
+const int kTestForWrite       = 0x02;
+const int kTestForAll         = 0x04;
+
+#define FS_ERR L"FILE-ERROR"
+#define OBJ_ERR L"OBJ-ERROR"
+#define REG_ERR L"REG_ERROR"
+#define OBJ L"OBJ"
+#define FS L"FILE"
+#define REG L"REG"
+
+// The impersonater class will impersonate a token when the object is created
+// and revert when the object is going out of scope.
+class Impersonater {
+ public:
+  Impersonater(HANDLE token_handle) {
+    if (token_handle)
+      ::ImpersonateLoggedOnUser(token_handle);
+  };
+  ~Impersonater() {
+    ::RevertToSelf();
+  };
+};
+
+// The finder class handles the search of objects (file system, registry, kernel
+// objects) on the system that can be opened by a restricted token. It can
+// support multiple levels of restriction for the restricted token and can check
+// for read, write or r/w access. It outputs the results to a file or stdout.
+class Finder {
+ public:
+  Finder();
+  ~Finder();
+  DWORD Init(sandbox::TokenLevel token_type, DWORD object_type,
+             DWORD access_type, FILE *file_output);
+  DWORD Scan();
+
+ private:
+  // Parses a file system path and perform an access check on all files and
+  // folder found.
+  // Returns ERROR_SUCCESS if the function succeeded, otherwise, it returns the
+  // win32 error code associated with the error.
+  DWORD ParseFileSystem(ATL::CString path);
+
+  // Parses a registry hive referenced by "key" and performs an access check on
+  // all subkeys found.
+  // Returns ERROR_SUCCESS if the function succeeded, otherwise, it returns the
+  // win32 error code associated with the error.
+  DWORD ParseRegistry(HKEY key, ATL::CString print_name);
+
+  // Parses the kernel namespace beginning at "path" and performs an access
+  // check on all objects found.  However, only some object types are supported,
+  // all non supported objects are ignored.
+  // Returns ERROR_SUCCESS if the function succeeded, otherwise, it returns the
+  // win32 error code associated with the error.
+  DWORD ParseKernelObjects(ATL::CString path);
+
+  // Checks if "path" can be accessed with the restricted token.
+  // Returns the access granted.
+  DWORD TestFileAccess(ATL::CString path);
+
+  // Checks if the registry key with the path key\name can be accessed with the
+  // restricted token.
+  // print_name is only use for logging purpose.
+  // Returns the access granted.
+  DWORD TestRegAccess(HKEY key, ATL::CString name, ATL::CString print_name);
+
+  // Checks if the kernel object "path" of type "type" can be accessed with
+  // the restricted token.
+  // Returns the access granted.
+  DWORD TestKernelObjectAccess(ATL::CString path, ATL::CString type);
+
+  // Outputs information to the logfile
+  void Output(ATL::CString type, ATL::CString access, ATL::CString info) {
+    fprintf(file_output_, "\n%S;%S;%S", type.GetBuffer(), access.GetBuffer(),
+            info.GetBuffer());
+  };
+
+  // Output information to the log file.
+  void Output(ATL::CString type, DWORD error, ATL::CString info) {
+    fprintf(file_output_, "\n%S;0x%X;%S", type.GetBuffer(), error,
+            info.GetBuffer());
+  };
+
+  // Set func_to_call to the function pointer of the function used to handle
+  // requests for the kernel objects of type "type". If the type is not
+  // supported at the moment the function returns false and the func_to_call
+  // parameter is not modified.
+  bool GetFunctionForType(ATL::CString type, NTGENERICOPEN * func_to_call);
+
+  // Initializes the NT function pointers to be able to use all the needed
+  // functions in NTDDL.
+  // Returns ERROR_SUCCESS if the function succeeded, otherwise, it returns the
+  // win32 error code associated with the error.
+  DWORD InitNT();
+
+  // Calls func_to_call with the parameters desired_access, object_attributes
+  // and handle.  func_to_call is a pointer to a function to open a kernel
+  // object.
+  NTSTATUS NtGenericOpen(ACCESS_MASK desired_access,
+                         OBJECT_ATTRIBUTES *object_attributes,
+                         NTGENERICOPEN func_to_call,
+                         HANDLE *handle);
+
+  // Type of object to check for.
+  DWORD object_type_;
+  // Access to try.
+  DWORD access_type_;
+  // Output file for the results.
+  FILE * file_output_;
+  // Handle to the restricted token.
+  HANDLE token_handle_;
+  // Stats containing the number of operations performed on the different
+  // objects.
+  int filesystem_stats_[SIZE_STATS];
+  int registry_stats_[SIZE_STATS];
+  int kernel_object_stats_[SIZE_STATS];
+};
+
+#endif  // SANDBOX_TOOLS_FINDER_FINDER_H__
diff --git a/sandbox/win/tools/finder/finder.vcproj b/sandbox/win/tools/finder/finder.vcproj
new file mode 100644
index 0000000..787c847
--- /dev/null
+++ b/sandbox/win/tools/finder/finder.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="finder"
+	ProjectGUID="{ACDC2E06-0366-41A4-A646-C37E130A605D}"
+	RootNamespace="finder"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\finder.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\finder.h"
+			>
+		</File>
+		<File
+			RelativePath=".\finder_fs.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\finder_kernel.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\finder_registry.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\main.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\ntundoc.h"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/tools/finder/finder_fs.cc b/sandbox/win/tools/finder/finder_fs.cc
new file mode 100644
index 0000000..ddcc4be
--- /dev/null
+++ b/sandbox/win/tools/finder/finder_fs.cc
@@ -0,0 +1,117 @@
+// 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 "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/tools/finder/finder.h"
+
+DWORD Finder::ParseFileSystem(ATL::CString directory) {
+  WIN32_FIND_DATA find_data;
+  HANDLE find;
+
+  //Search for items in the directory.
+  ATL::CString name_to_search = directory + L"\\*";
+  find = ::FindFirstFile(name_to_search, &find_data);
+  if (INVALID_HANDLE_VALUE == find) {
+    DWORD error = ::GetLastError();
+    Output(FS_ERR, error, directory);
+    filesystem_stats_[BROKEN]++;
+    return error;
+  }
+
+  // parse all files or folders.
+  do {
+    if (_tcscmp(find_data.cFileName, L".") == 0 ||
+        _tcscmp(find_data.cFileName, L"..") == 0)
+      continue;
+
+    ATL::CString complete_name = directory + L"\\" + find_data.cFileName;
+    TestFileAccess(complete_name);
+
+    // Call recursively the function if the path found is a directory.
+    if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+      ParseFileSystem(complete_name);
+    }
+  } while (::FindNextFile(find, &find_data) != 0);
+
+  DWORD err_code = ::GetLastError();
+  ::FindClose(find);
+
+  if (ERROR_NO_MORE_FILES != err_code) {
+    Output(FS_ERR, err_code, directory);
+    filesystem_stats_[BROKEN]++;
+    return err_code;
+  }
+
+  return ERROR_SUCCESS;
+}
+
+DWORD Finder::TestFileAccess(ATL::CString name) {
+  Impersonater impersonate(token_handle_);
+
+  filesystem_stats_[PARSE]++;
+
+  HANDLE file;
+  if (access_type_ & kTestForAll) {
+    file = ::CreateFile(name.GetBuffer(),
+                        GENERIC_ALL,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                        NULL,
+                        OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+
+    if (file != INVALID_HANDLE_VALUE) {
+      filesystem_stats_[ALL]++;
+      Output(FS, L"R/W", name.GetBuffer());
+      ::CloseHandle(file);
+      return GENERIC_ALL;
+    } else if (::GetLastError() != ERROR_ACCESS_DENIED) {
+      Output(FS_ERR, GetLastError(), name);
+      filesystem_stats_[BROKEN]++;
+    }
+  }
+
+  if (access_type_ & kTestForWrite) {
+    file = ::CreateFile(name.GetBuffer(),
+                        GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                        NULL,
+                        OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+
+    if (file != INVALID_HANDLE_VALUE) {
+      filesystem_stats_[WRITE]++;
+      Output(FS, L"W", name);
+      ::CloseHandle(file);
+      return GENERIC_WRITE;
+    } else if (::GetLastError() != ERROR_ACCESS_DENIED) {
+      Output(FS_ERR, ::GetLastError(), name);
+      filesystem_stats_[BROKEN]++;
+    }
+  }
+
+  if (access_type_ & kTestForRead) {
+    file = ::CreateFile(name.GetBuffer(),
+                        GENERIC_READ,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                        NULL,
+                        OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+
+    if (file != INVALID_HANDLE_VALUE) {
+      filesystem_stats_[READ]++;
+      Output(FS, L"R", name);
+      ::CloseHandle(file);
+      return GENERIC_READ;
+    } else if (::GetLastError() != ERROR_ACCESS_DENIED) {
+      Output(FS_ERR, GetLastError(), name);
+      filesystem_stats_[BROKEN]++;
+    }
+  }
+
+  return 0;
+}
diff --git a/sandbox/win/tools/finder/finder_kernel.cc b/sandbox/win/tools/finder/finder_kernel.cc
new file mode 100644
index 0000000..430a4c0
--- /dev/null
+++ b/sandbox/win/tools/finder/finder_kernel.cc
@@ -0,0 +1,248 @@
+// 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 "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/tools/finder/finder.h"
+#include "sandbox/win/tools/finder/ntundoc.h"
+
+#define BUFFER_SIZE 0x800
+#define CHECKPTR(x) if (!x) return ::GetLastError()
+
+// NT API
+NTQUERYDIRECTORYOBJECT    NtQueryDirectoryObject;
+NTOPENDIRECTORYOBJECT     NtOpenDirectoryObject;
+NTOPENEVENT               NtOpenEvent;
+NTOPENJOBOBJECT           NtOpenJobObject;
+NTOPENKEYEDEVENT          NtOpenKeyedEvent;
+NTOPENMUTANT              NtOpenMutant;
+NTOPENSECTION             NtOpenSection;
+NTOPENSEMAPHORE           NtOpenSemaphore;
+NTOPENSYMBOLICLINKOBJECT  NtOpenSymbolicLinkObject;
+NTOPENTIMER               NtOpenTimer;
+NTOPENFILE                NtOpenFile;
+NTCLOSE                   NtClose;
+
+DWORD Finder::InitNT() {
+  HMODULE ntdll_handle = ::LoadLibrary(L"ntdll.dll");
+  CHECKPTR(ntdll_handle);
+
+  NtOpenSymbolicLinkObject = (NTOPENSYMBOLICLINKOBJECT) ::GetProcAddress(
+  ntdll_handle, "NtOpenSymbolicLinkObject");
+  CHECKPTR(NtOpenSymbolicLinkObject);
+
+  NtQueryDirectoryObject = (NTQUERYDIRECTORYOBJECT) ::GetProcAddress(
+      ntdll_handle, "NtQueryDirectoryObject");
+  CHECKPTR(NtQueryDirectoryObject);
+
+  NtOpenDirectoryObject = (NTOPENDIRECTORYOBJECT) ::GetProcAddress(
+      ntdll_handle, "NtOpenDirectoryObject");
+  CHECKPTR(NtOpenDirectoryObject);
+
+  NtOpenKeyedEvent = (NTOPENKEYEDEVENT) ::GetProcAddress(
+      ntdll_handle, "NtOpenKeyedEvent");
+  CHECKPTR(NtOpenKeyedEvent);
+
+  NtOpenJobObject = (NTOPENJOBOBJECT) ::GetProcAddress(
+      ntdll_handle, "NtOpenJobObject");
+  CHECKPTR(NtOpenJobObject);
+
+  NtOpenSemaphore = (NTOPENSEMAPHORE) ::GetProcAddress(
+      ntdll_handle, "NtOpenSemaphore");
+  CHECKPTR(NtOpenSemaphore);
+
+  NtOpenSection = (NTOPENSECTION) ::GetProcAddress(
+      ntdll_handle, "NtOpenSection");
+  CHECKPTR(NtOpenSection);
+
+  NtOpenMutant= (NTOPENMUTANT) ::GetProcAddress(ntdll_handle, "NtOpenMutant");
+  CHECKPTR(NtOpenMutant);
+
+  NtOpenEvent = (NTOPENEVENT) ::GetProcAddress(ntdll_handle, "NtOpenEvent");
+  CHECKPTR(NtOpenEvent);
+
+  NtOpenTimer = (NTOPENTIMER) ::GetProcAddress(ntdll_handle, "NtOpenTimer");
+  CHECKPTR(NtOpenTimer);
+
+  NtOpenFile = (NTOPENFILE) ::GetProcAddress(ntdll_handle, "NtOpenFile");
+  CHECKPTR(NtOpenFile);
+
+  NtClose = (NTCLOSE) ::GetProcAddress(ntdll_handle, "NtClose");
+  CHECKPTR(NtClose);
+
+  return ERROR_SUCCESS;
+}
+
+DWORD Finder::ParseKernelObjects(ATL::CString path) {
+  UNICODE_STRING unicode_str;
+  unicode_str.Length = (USHORT)path.GetLength()*2;
+  unicode_str.MaximumLength = (USHORT)path.GetLength()*2+2;
+  unicode_str.Buffer = path.GetBuffer();
+
+  OBJECT_ATTRIBUTES path_attributes;
+  InitializeObjectAttributes(&path_attributes,
+                             &unicode_str,
+                             0,      // No Attributes
+                             NULL,   // No Root Directory
+                             NULL);  // No Security Descriptor
+
+
+  DWORD object_index = 0;
+  DWORD data_written = 0;
+
+  // TODO(nsylvain): Do not use BUFFER_SIZE. Try to get the size
+  // dynamically.
+  OBJDIR_INFORMATION *object_directory_info =
+    (OBJDIR_INFORMATION*) ::HeapAlloc(GetProcessHeap(),
+                                      0,
+                                      BUFFER_SIZE);
+
+  HANDLE file_handle;
+  NTSTATUS status_code = NtOpenDirectoryObject(&file_handle,
+                                               DIRECTORY_QUERY,
+                                               &path_attributes);
+  if (status_code != 0)
+    return ERROR_UNIDENTIFIED_ERROR;
+
+  status_code = NtQueryDirectoryObject(file_handle,
+                                       object_directory_info,
+                                       BUFFER_SIZE,
+                                       TRUE, // Get Next Index
+                                       TRUE, // Ignore Input Index
+                                       &object_index,
+                                       &data_written);
+
+  if (status_code != 0)
+    return ERROR_UNIDENTIFIED_ERROR;
+
+  while (NtQueryDirectoryObject(file_handle, object_directory_info,
+                                BUFFER_SIZE, TRUE, FALSE, &object_index,
+                                &data_written) == 0 ) {
+    ATL::CString cur_path(object_directory_info->ObjectName.Buffer,
+        object_directory_info->ObjectName.Length / sizeof(WCHAR));
+
+    ATL::CString cur_type(object_directory_info->ObjectTypeName.Buffer,
+        object_directory_info->ObjectTypeName.Length / sizeof(WCHAR));
+
+    ATL::CString new_path;
+    if (path == L"\\") {
+      new_path =  path + cur_path;
+    } else {
+      new_path = path + L"\\" + cur_path;
+    }
+
+    TestKernelObjectAccess(new_path, cur_type);
+
+    // Call the function recursively for all subdirectories
+    if (cur_type == L"Directory") {
+      ParseKernelObjects(new_path);
+    }
+  }
+
+  NtClose(file_handle);
+  return ERROR_SUCCESS;
+}
+
+DWORD Finder::TestKernelObjectAccess(ATL::CString path, ATL::CString type) {
+  Impersonater impersonate(token_handle_);
+
+  kernel_object_stats_[PARSE]++;
+
+  NTGENERICOPEN func = NULL;
+  GetFunctionForType(type, &func);
+
+  if (!func) {
+    kernel_object_stats_[BROKEN]++;
+    Output(OBJ_ERR, type + L" Unsupported", path);
+    return ERROR_UNSUPPORTED_TYPE;
+  }
+
+  UNICODE_STRING unicode_str;
+  unicode_str.Length =  (USHORT)path.GetLength()*2;
+  unicode_str.MaximumLength = (USHORT)path.GetLength()*2+2;
+  unicode_str.Buffer = path.GetBuffer();
+
+  OBJECT_ATTRIBUTES path_attributes;
+  InitializeObjectAttributes(&path_attributes,
+                             &unicode_str,
+                             0,      // No Attributes
+                             NULL,   // No Root Directory
+                             NULL);  // No Security Descriptor
+
+  HANDLE handle;
+  NTSTATUS status_code = 0;
+
+  if (access_type_ & kTestForAll) {
+    status_code = NtGenericOpen(GENERIC_ALL, &path_attributes, func, &handle);
+    if (STATUS_SUCCESS == status_code) {
+      kernel_object_stats_[ALL]++;
+      Output(OBJ, L"R/W", path);
+      NtClose(handle);
+      return GENERIC_ALL;
+    } else if (status_code != EXCEPTION_ACCESS_VIOLATION &&
+               status_code != STATUS_ACCESS_DENIED) {
+      Output(OBJ_ERR, status_code, path);
+      kernel_object_stats_[BROKEN]++;
+    }
+  }
+
+  if (access_type_ & kTestForWrite) {
+    status_code = NtGenericOpen(GENERIC_WRITE, &path_attributes, func, &handle);
+    if (STATUS_SUCCESS == status_code) {
+      kernel_object_stats_[WRITE]++;
+      Output(OBJ, L"W", path);
+      NtClose(handle);
+      return GENERIC_WRITE;
+    } else if (status_code != EXCEPTION_ACCESS_VIOLATION &&
+               status_code != STATUS_ACCESS_DENIED) {
+      Output(OBJ_ERR, status_code, path);
+      kernel_object_stats_[BROKEN]++;
+    }
+  }
+
+  if (access_type_ & kTestForRead) {
+    status_code = NtGenericOpen(GENERIC_READ, &path_attributes, func, &handle);
+    if (STATUS_SUCCESS == status_code) {
+      kernel_object_stats_[READ]++;
+      Output(OBJ, L"R", path);
+      NtClose(handle);
+      return GENERIC_READ;
+    } else if (status_code != EXCEPTION_ACCESS_VIOLATION &&
+               status_code != STATUS_ACCESS_DENIED) {
+      Output(OBJ_ERR, status_code, path);
+      kernel_object_stats_[BROKEN]++;
+    }
+  }
+
+  return 0;
+}
+
+NTSTATUS Finder::NtGenericOpen(ACCESS_MASK desired_access,
+                               OBJECT_ATTRIBUTES *object_attributes,
+                               NTGENERICOPEN func_to_call,
+                               HANDLE *handle) {
+  return func_to_call(handle, desired_access, object_attributes);
+}
+
+bool Finder::GetFunctionForType(ATL::CString type,
+                                NTGENERICOPEN * func_to_call) {
+  NTGENERICOPEN func = NULL;
+
+  if (type == L"Event")             func = NtOpenEvent;
+  else if (type == L"Job")          func = NtOpenJobObject;
+  else if (type == L"KeyedEvent")   func = NtOpenKeyedEvent;
+  else if (type == L"Mutant")       func = NtOpenMutant;
+  else if (type == L"Section")      func = NtOpenSection;
+  else if (type == L"Semaphore")    func = NtOpenSemaphore;
+  else if (type == L"Timer")        func = NtOpenTimer;
+  else if (type == L"SymbolicLink") func = NtOpenSymbolicLinkObject;
+  else if (type == L"Directory")    func = NtOpenDirectoryObject;
+
+  if (func) {
+    *func_to_call = func;
+    return true;
+  }
+
+  return false;
+}
diff --git a/sandbox/win/tools/finder/finder_registry.cc b/sandbox/win/tools/finder/finder_registry.cc
new file mode 100644
index 0000000..a84e413
--- /dev/null
+++ b/sandbox/win/tools/finder/finder_registry.cc
@@ -0,0 +1,93 @@
+// 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 "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/tools/finder/finder.h"
+
+DWORD Finder::ParseRegistry(HKEY key, ATL::CString print_name) {
+  DWORD index = 0;
+  DWORD name_size = 2048;
+  wchar_t buffer[2048] = {0};
+  // TODO(nsylvain): Don't hardcode 2048. Get the key len by calling the
+  //                 function.
+  LONG err_code = ::RegEnumKey(key, index, buffer, name_size);
+  while (ERROR_SUCCESS == err_code) {
+    ATL::CString name_complete = print_name + buffer + L"\\";
+    TestRegAccess(key, buffer, name_complete);
+
+    // Call the function recursively to parse all subkeys
+    HKEY key_to_parse;
+    err_code = ::RegOpenKeyEx(key, buffer, 0, KEY_ENUMERATE_SUB_KEYS,
+                              &key_to_parse);
+    if (ERROR_SUCCESS == err_code) {
+      ParseRegistry(key_to_parse, name_complete);
+      ::RegCloseKey(key_to_parse);
+    } else {
+      registry_stats_[BROKEN]++;
+      Output(REG_ERR, err_code, name_complete);
+    }
+
+    index++;
+    err_code = ::RegEnumKey(key, index, buffer, name_size);
+  }
+
+  if (ERROR_NO_MORE_ITEMS != err_code) {
+    registry_stats_[BROKEN]++;
+    Output(REG_ERR, err_code, print_name);
+  }
+
+  return ERROR_SUCCESS;
+}
+
+DWORD Finder::TestRegAccess(HKEY key, ATL::CString name,
+                                      ATL::CString print_name) {
+  Impersonater impersonate(token_handle_);
+
+  registry_stats_[PARSE]++;
+
+  HKEY key_res;
+  LONG err_code = 0;
+
+  if (access_type_ & kTestForAll) {
+    err_code = ::RegOpenKeyEx(key, name, 0, GENERIC_ALL, &key_res);
+    if (ERROR_SUCCESS == err_code) {
+      registry_stats_[ALL]++;
+      Output(REG, L"R/W", print_name);
+      ::RegCloseKey(key_res);
+      return GENERIC_ALL;
+    } else if (err_code != ERROR_ACCESS_DENIED) {
+      Output(REG_ERR, err_code, print_name);
+      registry_stats_[BROKEN]++;
+    }
+  }
+
+  if (access_type_ & kTestForWrite) {
+    err_code = ::RegOpenKeyEx(key, name, 0, GENERIC_WRITE, &key_res);
+    if (ERROR_SUCCESS == err_code) {
+      registry_stats_[WRITE]++;
+      Output(REG, L"W", print_name);
+      ::RegCloseKey(key_res);
+      return GENERIC_WRITE;
+    } else if (err_code != ERROR_ACCESS_DENIED) {
+      Output(REG_ERR, err_code, print_name);
+      registry_stats_[BROKEN]++;
+    }
+  }
+
+  if (access_type_ & kTestForRead) {
+    err_code = ::RegOpenKeyEx(key, name, 0, GENERIC_READ, &key_res);
+    if (ERROR_SUCCESS == err_code) {
+      registry_stats_[READ]++;
+      Output(REG, L"R", print_name);
+      ::RegCloseKey(key_res);
+      return GENERIC_READ;
+    } else if (err_code != ERROR_ACCESS_DENIED) {
+      Output(REG_ERR, err_code, print_name);
+      registry_stats_[BROKEN]++;
+    }
+  }
+
+  return 0;
+}
diff --git a/sandbox/win/tools/finder/main.cc b/sandbox/win/tools/finder/main.cc
new file mode 100644
index 0000000..7cadbef
--- /dev/null
+++ b/sandbox/win/tools/finder/main.cc
@@ -0,0 +1,147 @@
+// 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 "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/tools/finder/finder.h"
+
+#define PARAM_IS(y) (argc > i) && (_wcsicmp(argv[i], y) == 0)
+
+void PrintUsage(wchar_t *application_name) {
+  wprintf(L"\n\nUsage: \n  %ls --token type --object ob1 [ob2  ob3] "
+      L"--access ac1 [ac2 ac3] [--log filename]", application_name);
+  wprintf(L"\n\n  Token Types : \n\tLOCKDOWN \n\tRESTRICTED "
+      L"\n\tLIMITED_USER \n\tINTERACTIVE_USER \n\tNON_ADMIN \n\tUNPROTECTED");
+  wprintf(L"\n  Object Types: \n\tREG \n\tFILE \n\tKERNEL");
+  wprintf(L"\n  Access Types: \n\tR \n\tW \n\tALL");
+  wprintf(L"\n\nSample: \n  %ls --token LOCKDOWN --object REG FILE KERNEL "
+      L"--access R W ALL", application_name);
+}
+
+int wmain(int argc, wchar_t* argv[]) {
+  // Extract the filename from the path.
+  wchar_t *app_name = wcsrchr(argv[0], L'\\');
+  if (!app_name) {
+    app_name = argv[0];
+  } else {
+    app_name++;
+  }
+
+  // parameters to read
+  ATL::CString log_file;
+  sandbox::TokenLevel token_type = sandbox::USER_LOCKDOWN;
+  DWORD object_type = 0;
+  DWORD access_type = 0;
+
+  // no arguments
+  if (argc == 1) {
+    PrintUsage(app_name);
+    return -1;
+  }
+
+  // parse command line.
+  for (int i = 1; i < argc; ++i) {
+    if (PARAM_IS(L"--token")) {
+      i++;
+      if (argc > i) {
+        if (PARAM_IS(L"LOCKDOWN")) {
+          token_type = sandbox::USER_LOCKDOWN;
+        } else if (PARAM_IS(L"RESTRICTED")) {
+          token_type = sandbox::USER_RESTRICTED;
+        } else if (PARAM_IS(L"LIMITED_USER")) {
+          token_type = sandbox::USER_LIMITED;
+        } else if (PARAM_IS(L"INTERACTIVE_USER")) {
+          token_type = sandbox::USER_INTERACTIVE;
+        } else if (PARAM_IS(L"NON_ADMIN")) {
+          token_type = sandbox::USER_NON_ADMIN;
+        } else if (PARAM_IS(L"USER_RESTRICTED_SAME_ACCESS")) {
+          token_type = sandbox::USER_RESTRICTED_SAME_ACCESS;
+        } else if (PARAM_IS(L"UNPROTECTED")) {
+          token_type = sandbox::USER_UNPROTECTED;
+        } else {
+          wprintf(L"\nAbord. Invalid token type \"%ls\"", argv[i]);
+          PrintUsage(app_name);
+          return -1;
+        }
+      }
+    } else if (PARAM_IS(L"--object")) {
+      bool is_object = true;
+      do {
+        i++;
+        if (PARAM_IS(L"REG")) {
+          object_type |= kScanRegistry;
+        } else if (PARAM_IS(L"FILE")) {
+          object_type |= kScanFileSystem;
+        } else if (PARAM_IS(L"KERNEL")) {
+          object_type |= kScanKernelObjects;
+        } else {
+          is_object = false;
+        }
+      } while(is_object);
+      i--;
+    } else if (PARAM_IS(L"--access")) {
+      bool is_access = true;
+      do {
+        i++;
+        if (PARAM_IS(L"R")) {
+          access_type |= kTestForRead;
+        } else if (PARAM_IS(L"W")) {
+          access_type |= kTestForWrite;
+        } else if (PARAM_IS(L"ALL")) {
+          access_type |= kTestForAll;
+        } else {
+          is_access = false;
+        }
+      } while(is_access);
+      i--;
+    } else if (PARAM_IS(L"--log")) {
+      i++;
+      if (argc > i) {
+        log_file = argv[i];
+      }
+      else {
+        wprintf(L"\nAbord. No log file specified");
+        PrintUsage(app_name);
+        return -1;
+      }
+    } else {
+      wprintf(L"\nAbord. Unrecognized parameter \"%ls\"", argv[i]);
+      PrintUsage(app_name);
+      return -1;
+    }
+  }
+
+  // validate parameters
+  if (0 == access_type) {
+    wprintf(L"\nAbord, Access type not specified");
+    PrintUsage(app_name);
+    return -1;
+  }
+
+  if (0 == object_type) {
+    wprintf(L"\nAbord, Object type not specified");
+    PrintUsage(app_name);
+    return -1;
+  }
+
+
+  // Open log file
+  FILE * file_output;
+  if (log_file.GetLength()) {
+    errno_t err = _wfopen_s(&file_output, log_file, L"w");
+    if (err) {
+      wprintf(L"\nAbord, Cannot open file \"%ls\"", log_file.GetBuffer());
+      return -1;
+    }
+  } else {
+    file_output = stdout;
+  }
+
+  Finder finder_obj;
+  finder_obj.Init(token_type, object_type, access_type, file_output);
+  finder_obj.Scan();
+
+  fclose(file_output);
+
+  return 0;
+}
diff --git a/sandbox/win/tools/finder/ntundoc.h b/sandbox/win/tools/finder/ntundoc.h
new file mode 100644
index 0000000..dc8c3a5
--- /dev/null
+++ b/sandbox/win/tools/finder/ntundoc.h
@@ -0,0 +1,275 @@
+// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_TOOLS_FINDER_NTUNDOC_H__
+#define SANDBOX_TOOLS_FINDER_NTUNDOC_H__
+
+#define NTSTATUS ULONG
+#define STATUS_SUCCESS 0x00000000
+#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
+#define STATUS_ACCESS_DENIED 0xC0000022
+#define STATUS_BUFFER_OVERFLOW 0x80000005
+
+typedef struct _LSA_UNICODE_STRING {
+  USHORT Length;
+  USHORT MaximumLength;
+  PWSTR Buffer;
+} UNICODE_STRING;
+
+typedef struct _OBJDIR_INFORMATION {
+  UNICODE_STRING ObjectName;
+  UNICODE_STRING ObjectTypeName;
+  BYTE Data[1];
+} OBJDIR_INFORMATION;
+
+typedef struct _OBJECT_ATTRIBUTES {
+  ULONG Length;
+  HANDLE RootDirectory;
+  UNICODE_STRING *ObjectName;
+  ULONG Attributes;
+  PVOID SecurityDescriptor;
+  PVOID SecurityQualityOfService;
+} OBJECT_ATTRIBUTES;
+
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+  ULONG Attributes;
+  ACCESS_MASK GrantedAccess;
+  ULONG HandleCount;
+  ULONG PointerCount;
+  ULONG Reserved[10];    // reserved for internal use
+ } PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING TypeName;
+  ULONG Reserved [22];    // reserved for internal use
+} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+typedef enum _POOL_TYPE {
+  NonPagedPool,
+  PagedPool,
+  NonPagedPoolMustSucceed,
+  ReservedType,
+  NonPagedPoolCacheAligned,
+  PagedPoolCacheAligned,
+  NonPagedPoolCacheAlignedMustS
+} POOL_TYPE;
+
+typedef struct _OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING Name;
+  ULONG TotalNumberOfObjects;
+  ULONG TotalNumberOfHandles;
+  ULONG TotalPagedPoolUsage;
+  ULONG TotalNonPagedPoolUsage;
+  ULONG TotalNamePoolUsage;
+  ULONG TotalHandleTableUsage;
+  ULONG HighWaterNumberOfObjects;
+  ULONG HighWaterNumberOfHandles;
+  ULONG HighWaterPagedPoolUsage;
+  ULONG HighWaterNonPagedPoolUsage;
+  ULONG HighWaterNamePoolUsage;
+  ULONG HighWaterHandleTableUsage;
+  ULONG InvalidAttributes;
+  GENERIC_MAPPING GenericMapping;
+  ULONG ValidAccess;
+  BOOLEAN SecurityRequired;
+  BOOLEAN MaintainHandleCount;
+  USHORT MaintainTypeList;
+  POOL_TYPE PoolType;
+  ULONG PagedPoolUsage;
+  ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+typedef struct _OBJECT_NAME_INFORMATION {
+  UNICODE_STRING          ObjectName;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef enum _OBJECT_INFORMATION_CLASS {
+  ObjectBasicInformation,
+  ObjectNameInformation,
+  ObjectTypeInformation,
+  ObjectAllInformation,
+  ObjectDataInformation
+} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ // end_wdm
+  FileDirectoryInformation       = 1,
+  FileFullDirectoryInformation, // 2
+  FileBothDirectoryInformation, // 3
+  FileBasicInformation,         // 4  wdm
+  FileStandardInformation,      // 5  wdm
+  FileInternalInformation,      // 6
+  FileEaInformation,            // 7
+  FileAccessInformation,        // 8
+  FileNameInformation,          // 9
+  FileRenameInformation,        // 10
+  FileLinkInformation,          // 11
+  FileNamesInformation,         // 12
+  FileDispositionInformation,   // 13
+  FilePositionInformation,      // 14 wdm
+  FileFullEaInformation,        // 15
+  FileModeInformation,          // 16
+  FileAlignmentInformation,     // 17
+  FileAllInformation,           // 18
+  FileAllocationInformation,    // 19
+  FileEndOfFileInformation,     // 20 wdm
+  FileAlternateNameInformation, // 21
+  FileStreamInformation,        // 22
+  FilePipeInformation,          // 23
+  FilePipeLocalInformation,     // 24
+  FilePipeRemoteInformation,    // 25
+  FileMailslotQueryInformation, // 26
+  FileMailslotSetInformation,   // 27
+  FileCompressionInformation,   // 28
+  FileObjectIdInformation,      // 29
+  FileCompletionInformation,    // 30
+  FileMoveClusterInformation,   // 31
+  FileQuotaInformation,         // 32
+  FileReparsePointInformation,  // 33
+  FileNetworkOpenInformation,   // 34
+  FileAttributeTagInformation,  // 35
+  FileTrackingInformation,      // 36
+  FileMaximumInformation
+  // begin_wdm
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+  SystemHandleInformation = 16
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _IO_STATUS_BLOCK {
+    union {
+        NTSTATUS Status;
+        PVOID Pointer;
+    };
+    ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+#define InitializeObjectAttributes( p, n, a, r, s ) { \
+    (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
+    (p)->RootDirectory = r; \
+    (p)->Attributes = a; \
+    (p)->ObjectName = n; \
+    (p)->SecurityDescriptor = s; \
+    (p)->SecurityQualityOfService = NULL; \
+}
+
+typedef struct _SYSTEM_HANDLE_INFORMATION {
+  USHORT ProcessId;
+  USHORT CreatorBackTraceIndex;
+  UCHAR ObjectTypeNumber;
+  UCHAR Flags;
+  USHORT Handle;
+  PVOID Object;
+  ACCESS_MASK GrantedAccess;
+} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+  ULONG NumberOfHandles;
+  SYSTEM_HANDLE_INFORMATION Information[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+#define POBJECT_ATTRIBUTES OBJECT_ATTRIBUTES*
+
+typedef NTSTATUS (WINAPI* NTQUERYDIRECTORYOBJECT)(
+  HANDLE,
+  OBJDIR_INFORMATION*,
+  DWORD,
+  DWORD,
+  DWORD,
+  DWORD*,
+  DWORD*);
+
+typedef NTSTATUS (WINAPI* NTOPENDIRECTORYOBJECT)(
+  HANDLE *,
+  DWORD,
+  OBJECT_ATTRIBUTES* );
+
+typedef NTSTATUS (WINAPI* NTGENERICOPEN) (
+  OUT PHANDLE EventHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENEVENT)(
+  OUT PHANDLE EventHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENJOBOBJECT)(
+  OUT PHANDLE JobHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENKEYEDEVENT)(
+  OUT PHANDLE KeyedEventHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENMUTANT)(
+  OUT PHANDLE MutantHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENSECTION)(
+  OUT PHANDLE SectionHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENSEMAPHORE)(
+  OUT PHANDLE SemaphoreHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENSYMBOLICLINKOBJECT)(
+  OUT PHANDLE SymbolicLinkHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENTIMER)(
+  OUT PHANDLE TimerHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENFILE)(
+  HANDLE *,
+  DWORD,
+  OBJECT_ATTRIBUTES *,
+  IO_STATUS_BLOCK *,
+  DWORD,
+  DWORD);
+
+typedef NTSTATUS (WINAPI* NTQUERYINFORMATIONFILE)(
+  HANDLE,
+  PIO_STATUS_BLOCK,
+  PVOID,
+  ULONG,
+  FILE_INFORMATION_CLASS);
+
+typedef NTSTATUS (WINAPI* NTQUERYSYSTEMINFORMATION)(
+  SYSTEM_INFORMATION_CLASS SystemInformationClass,
+  PVOID SystemInformation,
+  ULONG SystemInformationLength,
+  PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI* NTQUERYOBJECT)(
+  HANDLE Handle,
+  OBJECT_INFORMATION_CLASS ObjectInformationClass,
+  PVOID ObjectInformation,
+  ULONG ObjectInformationLength,
+  PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI* NTCLOSE) (HANDLE);
+
+#define DIRECTORY_QUERY 0x0001
+#define DIRECTORY_TRAVERSE 0x0002
+#define DIRECTORY_CREATE_OBJECT 0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF)
+
+#endif  // SANDBOX_TOOLS_FINDER_NTUNDOC_H__
diff --git a/sandbox/win/tools/launcher/launcher.cc b/sandbox/win/tools/launcher/launcher.cc
new file mode 100644
index 0000000..efcc4a4
--- /dev/null
+++ b/sandbox/win/tools/launcher/launcher.cc
@@ -0,0 +1,156 @@
+// 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 "sandbox/win/src/restricted_token_utils.h"
+
+// launcher.exe is an application used to launch another application with a
+// restricted token. This is to be used for testing only.
+// The parameters are the level of security of the primary token, the
+// impersonation token and the job object along with the command line to
+// execute.
+// See the usage (launcher.exe without parameters) for the correct format.
+
+#define PARAM_IS(y) (argc > i) && (_wcsicmp(argv[i], y) == 0)
+
+void PrintUsage(const wchar_t *application_name) {
+  wprintf(L"\n\nUsage: \n  %ls --main level --init level --job level cmd_line ",
+          application_name);
+  wprintf(L"\n\n  Levels : \n\tLOCKDOWN \n\tRESTRICTED "
+      L"\n\tLIMITED_USER \n\tINTERACTIVE_USER \n\tNON_ADMIN \n\tUNPROTECTED");
+  wprintf(L"\n\n  main: Security level of the main token");
+  wprintf(L"\n  init: Security level of the impersonation token");
+  wprintf(L"\n  job: Security level of the job object");
+}
+
+bool GetTokenLevelFromString(const wchar_t *param,
+                             sandbox::TokenLevel* level) {
+  if (_wcsicmp(param, L"LOCKDOWN") == 0) {
+    *level = sandbox::USER_LOCKDOWN;
+  } else if (_wcsicmp(param, L"RESTRICTED") == 0) {
+    *level = sandbox::USER_RESTRICTED;
+  } else if (_wcsicmp(param, L"LIMITED_USER") == 0) {
+    *level = sandbox::USER_LIMITED;
+  } else if (_wcsicmp(param, L"INTERACTIVE_USER") == 0) {
+    *level = sandbox::USER_INTERACTIVE;
+  } else if (_wcsicmp(param, L"NON_ADMIN") == 0) {
+    *level = sandbox::USER_NON_ADMIN;
+  } else if (_wcsicmp(param, L"USER_RESTRICTED_SAME_ACCESS") == 0) {
+    *level = sandbox::USER_RESTRICTED_SAME_ACCESS;
+  } else if (_wcsicmp(param, L"UNPROTECTED") == 0) {
+    *level = sandbox::USER_UNPROTECTED;
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool GetJobLevelFromString(const wchar_t *param, sandbox::JobLevel* level) {
+  if (_wcsicmp(param, L"LOCKDOWN") == 0) {
+    *level = sandbox::JOB_LOCKDOWN;
+  } else if (_wcsicmp(param, L"RESTRICTED") == 0) {
+    *level = sandbox::JOB_RESTRICTED;
+  } else if (_wcsicmp(param, L"LIMITED_USER") == 0) {
+    *level = sandbox::JOB_LIMITED_USER;
+  } else if (_wcsicmp(param, L"INTERACTIVE_USER") == 0) {
+    *level = sandbox::JOB_INTERACTIVE;
+  } else if (_wcsicmp(param, L"NON_ADMIN") == 0) {
+    wprintf(L"\nNON_ADMIN is not a supported job type");
+    return false;
+  } else if (_wcsicmp(param, L"UNPROTECTED") == 0) {
+    *level = sandbox::JOB_UNPROTECTED;
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+int wmain(int argc, wchar_t *argv[]) {
+  // Extract the filename from the path.
+  wchar_t *app_name = wcsrchr(argv[0], L'\\');
+  if (!app_name) {
+    app_name = argv[0];
+  } else {
+    app_name++;
+  }
+
+  // no argument
+  if (argc == 1) {
+    PrintUsage(app_name);
+    return -1;
+  }
+
+  sandbox::TokenLevel primary_level = sandbox::USER_LOCKDOWN;
+  sandbox::TokenLevel impersonation_level =
+      sandbox::USER_RESTRICTED_SAME_ACCESS;
+  sandbox::JobLevel job_level = sandbox::JOB_LOCKDOWN;
+  ATL::CString command_line;
+
+  // parse command line.
+  for (int i = 1; i < argc; ++i) {
+    if (PARAM_IS(L"--main")) {
+      i++;
+      if (argc > i) {
+        if (!GetTokenLevelFromString(argv[i], &primary_level)) {
+          wprintf(L"\nAbord, Unrecognized main token level \"%ls\"", argv[i]);
+          PrintUsage(app_name);
+          return -1;
+        }
+      }
+    } else if (PARAM_IS(L"--init")) {
+      i++;
+      if (argc > i) {
+        if (!GetTokenLevelFromString(argv[i], &impersonation_level)) {
+          wprintf(L"\nAbord, Unrecognized init token level \"%ls\"", argv[i]);
+          PrintUsage(app_name);
+          return -1;
+        }
+      }
+    } else if (PARAM_IS(L"--job")) {
+      i++;
+      if (argc > i) {
+        if (!GetJobLevelFromString(argv[i], &job_level)) {
+          wprintf(L"\nAbord, Unrecognized job security level \"%ls\"", argv[i]);
+          PrintUsage(app_name);
+          return -1;
+        }
+      }
+    } else {
+      if (command_line.GetLength()) {
+        command_line += L' ';
+      }
+      command_line += argv[i];
+    }
+  }
+
+  if (!command_line.GetLength()) {
+    wprintf(L"\nAbord, No command line specified");
+    PrintUsage(app_name);
+    return -1;
+  }
+
+  wprintf(L"\nLaunching command line: \"%ls\"\n", command_line.GetBuffer());
+
+  HANDLE job_handle;
+  DWORD err_code = sandbox::StartRestrictedProcessInJob(
+      command_line.GetBuffer(),
+      primary_level,
+      impersonation_level,
+      job_level,
+      &job_handle);
+  if (ERROR_SUCCESS != err_code) {
+    wprintf(L"\nAbord, Error %d while launching command line.", err_code);
+    return -1;
+  }
+
+  wprintf(L"\nPress any key to continue.");
+  while(!_kbhit()) {
+    Sleep(100);
+  }
+
+  ::CloseHandle(job_handle);
+
+  return 0;
+}
diff --git a/sandbox/win/tools/launcher/launcher.vcproj b/sandbox/win/tools/launcher/launcher.vcproj
new file mode 100644
index 0000000..71ed011
--- /dev/null
+++ b/sandbox/win/tools/launcher/launcher.vcproj
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="launcher"
+	ProjectGUID="{386FA217-FBC2-4461-882D-CDAD221ED800}"
+	RootNamespace="launcher"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\launcher.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/sandbox/win/wow_helper.sln b/sandbox/win/wow_helper.sln
new file mode 100644
index 0000000..26d0da2
--- /dev/null
+++ b/sandbox/win/wow_helper.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wow_helper", "wow_helper\wow_helper.vcproj", "{BCF3A457-39F1-4DAA-9A65-93CFCD559036}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Debug|x64.ActiveCfg = Debug|x64
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Debug|x64.Build.0 = Debug|x64
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Release|x64.ActiveCfg = Release|x64
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/sandbox/win/wow_helper/service64_resolver.cc b/sandbox/win/wow_helper/service64_resolver.cc
new file mode 100644
index 0000000..033b9d7
--- /dev/null
+++ b/sandbox/win/wow_helper/service64_resolver.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/wow_helper/service64_resolver.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/win/wow_helper/target_code.h"
+
+namespace {
+#pragma pack(push, 1)
+
+const BYTE kMovEax = 0xB8;
+const BYTE kMovEdx = 0xBA;
+const USHORT kCallPtrEdx = 0x12FF;
+const BYTE kRet = 0xC2;
+const BYTE kNop = 0x90;
+const USHORT kJmpEdx = 0xE2FF;
+const USHORT kXorEcx = 0xC933;
+const ULONG kLeaEdx = 0x0424548D;
+const ULONG kCallFs1 = 0xC015FF64;
+const ULONG kCallFs2Ret = 0xC2000000;
+const BYTE kPopEdx = 0x5A;
+const BYTE kPushEdx = 0x52;
+const BYTE kPush32 = 0x68;
+
+const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
+const USHORT kSyscall = 0x050F;
+const BYTE kRetNp = 0xC3;
+const BYTE kPad = 0x66;
+const USHORT kNop16 = 0x9066;
+const BYTE kRelJmp = 0xE9;
+
+const ULONG kXorRaxMovEax = 0xB8C03148;
+const ULONG kSaveRcx = 0x10488948;
+const ULONG kMovRcxRaxJmp = 0xE9C88B48;
+
+// Service code for 64 bit systems.
+struct ServiceEntry {
+  // this struct contains roughly the following code:
+  // mov     r10,rcx
+  // mov     eax,52h
+  // syscall
+  // ret
+  // xchg    ax,ax
+  // xchg    ax,ax
+
+  ULONG mov_r10_ecx_mov_eax;  // = 4C 8B D1 B8
+  ULONG service_id;
+  USHORT syscall;             // = 0F 05
+  BYTE ret;                   // = C3
+  BYTE pad;                   // = 66
+  USHORT xchg_ax_ax1;         // = 66 90
+  USHORT xchg_ax_ax2;         // = 66 90
+};
+
+struct Redirected {
+  // this struct contains roughly the following code:
+  // jmp    relative_32
+  // xchg   ax,ax       // 3 byte nop
+
+  Redirected() {
+    jmp = kRelJmp;
+    relative = 0;
+    pad = kPad;
+    xchg_ax_ax = kNop16;
+  };
+  BYTE jmp;             // = E9
+  ULONG relative;
+  BYTE pad;             // = 66
+  USHORT xchg_ax_ax;    // = 66 90
+};
+
+struct InternalThunk {
+  // this struct contains roughly the following code:
+  // xor rax,rax
+  // mov eax, 0x00080000              // Thunk storage.
+  // mov [rax]PatchInfo.service, rcx  // Save first argument.
+  // mov rcx, rax
+  // jmp relative_to_interceptor
+
+  InternalThunk() {
+    xor_rax_mov_eax = kXorRaxMovEax;
+    patch_info = 0;
+    save_rcx = kSaveRcx;
+    mov_rcx_rax_jmp = kMovRcxRaxJmp;
+    relative = 0;
+  };
+  ULONG xor_rax_mov_eax;  // = 48 31 C0 B8
+  ULONG patch_info;
+  ULONG save_rcx;         // = 48 89 48 10
+  ULONG mov_rcx_rax_jmp;  // = 48 8b c8 e9
+  ULONG relative;
+};
+
+struct ServiceFullThunk {
+  sandbox::PatchInfo patch_info;
+  ServiceEntry original;
+  InternalThunk internal_thunk;
+};
+
+#pragma pack(pop)
+
+// Simple utility function to write to a buffer on the child, if the memery has
+// write protection attributes.
+// Arguments:
+// child_process (in): process to write to.
+// address (out): memory position on the child to write to.
+// buffer (in): local buffer with the data to write .
+// length (in): number of bytes to write.
+// Returns true on success.
+bool WriteProtectedChildMemory(HANDLE child_process,
+                               void* address,
+                               const void* buffer,
+                               size_t length) {
+  // first, remove the protections
+  DWORD old_protection;
+  if (!::VirtualProtectEx(child_process, address, length,
+                          PAGE_WRITECOPY, &old_protection))
+    return false;
+
+  SIZE_T written;
+  bool ok = ::WriteProcessMemory(child_process, address, buffer, length,
+                                 &written) && (length == written);
+
+  // always attempt to restore the original protection
+  if (!::VirtualProtectEx(child_process, address, length,
+                          old_protection, &old_protection))
+    return false;
+
+  return ok;
+}
+
+// Get pointers to the functions that we need from ntdll.dll.
+NTSTATUS ResolveNtdll(sandbox::PatchInfo* patch_info) {
+  wchar_t* ntdll_name = L"ntdll.dll";
+  HMODULE ntdll = ::GetModuleHandle(ntdll_name);
+  if (!ntdll)
+    return STATUS_PROCEDURE_NOT_FOUND;
+
+  void* signal = ::GetProcAddress(ntdll, "NtSignalAndWaitForSingleObject");
+  if (!signal)
+    return STATUS_PROCEDURE_NOT_FOUND;
+
+  patch_info->signal_and_wait =
+      reinterpret_cast<NtSignalAndWaitForSingleObjectFunction>(signal);
+
+  return STATUS_SUCCESS;
+}
+
+};  // namespace
+
+namespace sandbox {
+
+NTSTATUS ResolverThunk::Init(const void* target_module,
+                             const void* interceptor_module,
+                             const char* target_name,
+                             const char* interceptor_name,
+                             const void* interceptor_entry_point,
+                             void* thunk_storage,
+                             size_t storage_bytes) {
+  if (NULL == thunk_storage || 0 == storage_bytes ||
+      NULL == target_module || NULL == target_name)
+    return STATUS_INVALID_PARAMETER;
+
+  if (storage_bytes < GetThunkSize())
+    return STATUS_BUFFER_TOO_SMALL;
+
+  NTSTATUS ret = STATUS_SUCCESS;
+  if (NULL == interceptor_entry_point) {
+    ret = ResolveInterceptor(interceptor_module, interceptor_name,
+                             &interceptor_entry_point);
+    if (!NT_SUCCESS(ret))
+      return ret;
+  }
+
+  ret = ResolveTarget(target_module, target_name, &target_);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  interceptor_ = interceptor_entry_point;
+
+  return ret;
+}
+
+NTSTATUS ResolverThunk::ResolveInterceptor(const void* interceptor_module,
+                                           const char* interceptor_name,
+                                           const void** address) {
+  return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS ResolverThunk::ResolveTarget(const void* module,
+                                      const char* function_name,
+                                      void** address) {
+  return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS Service64ResolverThunk::Setup(const void* target_module,
+                                       const void* interceptor_module,
+                                       const char* target_name,
+                                       const char* interceptor_name,
+                                       const void* interceptor_entry_point,
+                                       void* thunk_storage,
+                                       size_t storage_bytes,
+                                       size_t* storage_used) {
+  NTSTATUS ret = Init(target_module, interceptor_module, target_name,
+                      interceptor_name, interceptor_entry_point,
+                      thunk_storage, storage_bytes);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  size_t thunk_bytes = GetThunkSize();
+  scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
+  ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
+                                thunk_buffer.get());
+
+  if (!IsFunctionAService(&thunk->original))
+    return STATUS_UNSUCCESSFUL;
+
+  ret = PerformPatch(thunk, thunk_storage);
+
+  if (NULL != storage_used)
+    *storage_used = thunk_bytes;
+
+  return ret;
+}
+
+NTSTATUS Service64ResolverThunk::ResolveInterceptor(
+    const void* interceptor_module,
+    const char* interceptor_name,
+    const void** address) {
+  // After all, we are using a locally mapped version of the exe, so the
+  // action is the same as for a target function.
+  return ResolveTarget(interceptor_module, interceptor_name,
+                       const_cast<void**>(address));
+}
+
+// In this case all the work is done from the parent, so resolve is
+// just a simple GetProcAddress.
+NTSTATUS Service64ResolverThunk::ResolveTarget(const void* module,
+                                             const char* function_name,
+                                             void** address) {
+  if (NULL == module)
+    return STATUS_UNSUCCESSFUL;
+
+  *address = ::GetProcAddress(bit_cast<HMODULE>(module), function_name);
+
+  if (NULL == *address)
+    return STATUS_UNSUCCESSFUL;
+
+  return STATUS_SUCCESS;
+}
+
+size_t Service64ResolverThunk::GetThunkSize() const {
+  return sizeof(ServiceFullThunk);
+}
+
+bool Service64ResolverThunk::IsFunctionAService(void* local_thunk) const {
+  ServiceEntry function_code;
+  SIZE_T read;
+  if (!::ReadProcessMemory(process_, target_, &function_code,
+                           sizeof(function_code), &read))
+    return false;
+
+  if (sizeof(function_code) != read)
+    return false;
+
+  if (kMmovR10EcxMovEax != function_code.mov_r10_ecx_mov_eax ||
+      kSyscall != function_code.syscall || kRetNp != function_code.ret)
+    return false;
+
+  // Save the verified code
+  memcpy(local_thunk, &function_code, sizeof(function_code));
+
+  return true;
+}
+
+NTSTATUS Service64ResolverThunk::PerformPatch(void* local_thunk,
+                                              void* remote_thunk) {
+  ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
+                                           local_thunk);
+  ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
+                                           remote_thunk);
+
+  // If the source or target are above 4GB we cannot do this relative jump.
+  if (reinterpret_cast<ULONG_PTR>(full_remote_thunk) >
+      static_cast<ULONG_PTR>(ULONG_MAX))
+    return STATUS_CONFLICTING_ADDRESSES;
+
+  if (reinterpret_cast<ULONG_PTR>(target_) > static_cast<ULONG_PTR>(ULONG_MAX))
+    return STATUS_CONFLICTING_ADDRESSES;
+
+  // Patch the original code.
+  Redirected local_service;
+  Redirected* remote_service = reinterpret_cast<Redirected*>(target_);
+  ULONG_PTR diff = reinterpret_cast<BYTE*>(&full_remote_thunk->internal_thunk) -
+                   &remote_service->pad;
+  local_service.relative = static_cast<ULONG>(diff);
+
+  // Setup the PatchInfo structure.
+  SIZE_T actual;
+  if (!::ReadProcessMemory(process_, remote_thunk, local_thunk,
+                           sizeof(PatchInfo), &actual))
+    return STATUS_UNSUCCESSFUL;
+  if (sizeof(PatchInfo) != actual)
+    return STATUS_UNSUCCESSFUL;
+
+  full_local_thunk->patch_info.orig_MapViewOfSection = reinterpret_cast<
+      NtMapViewOfSectionFunction>(&full_remote_thunk->original);
+  full_local_thunk->patch_info.patch_location = target_;
+  NTSTATUS ret = ResolveNtdll(&full_local_thunk->patch_info);
+  if (!NT_SUCCESS(ret))
+    return ret;
+
+  // Setup the thunk. The jump out is performed from right after the end of the
+  // thunk (full_remote_thunk + 1).
+  InternalThunk my_thunk;
+  ULONG_PTR patch_info = reinterpret_cast<ULONG_PTR>(remote_thunk);
+  my_thunk.patch_info = static_cast<ULONG>(patch_info);
+  diff = reinterpret_cast<const BYTE*>(interceptor_) -
+         reinterpret_cast<BYTE*>(full_remote_thunk + 1);
+  my_thunk.relative = static_cast<ULONG>(diff);
+
+  memcpy(&full_local_thunk->internal_thunk, &my_thunk, sizeof(my_thunk));
+
+  // copy the local thunk buffer to the child
+  if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
+                            sizeof(ServiceFullThunk), &actual))
+    return STATUS_UNSUCCESSFUL;
+
+  if (sizeof(ServiceFullThunk) != actual)
+    return STATUS_UNSUCCESSFUL;
+
+  // and now change the function to intercept, on the child
+  if (!::WriteProtectedChildMemory(process_, target_, &local_service,
+                                   sizeof(local_service)))
+    return STATUS_UNSUCCESSFUL;
+
+  return STATUS_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/wow_helper/service64_resolver.h b/sandbox/win/wow_helper/service64_resolver.h
new file mode 100644
index 0000000..abd7efd
--- /dev/null
+++ b/sandbox/win/wow_helper/service64_resolver.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WOW_HELPER_SERVICE64_RESOLVER_H__
+#define SANDBOX_WOW_HELPER_SERVICE64_RESOLVER_H__
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/resolver.h"
+
+namespace sandbox {
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll (64-bit).
+class Service64ResolverThunk : public ResolverThunk {
+ public:
+  // The service resolver needs a child process to write to.
+  explicit Service64ResolverThunk(HANDLE process)
+      : process_(process), ntdll_base_(NULL) {}
+  virtual ~Service64ResolverThunk() {}
+
+  // Implementation of Resolver::Setup.
+  virtual NTSTATUS Setup(const void* target_module,
+                         const void* interceptor_module,
+                         const char* target_name,
+                         const char* interceptor_name,
+                         const void* interceptor_entry_point,
+                         void* thunk_storage,
+                         size_t storage_bytes,
+                         size_t* storage_used);
+
+  // Implementation of Resolver::ResolveInterceptor.
+  virtual NTSTATUS ResolveInterceptor(const void* module,
+                                      const char* function_name,
+                                      const void** address);
+
+  // Implementation of Resolver::ResolveTarget.
+  virtual NTSTATUS ResolveTarget(const void* module,
+                                 const char* function_name,
+                                 void** address);
+
+  // Implementation of Resolver::GetThunkSize.
+  virtual size_t GetThunkSize() const;
+
+ protected:
+  // The unit test will use this member to allow local patch on a buffer.
+  HMODULE ntdll_base_;
+
+  // Handle of the child process.
+  HANDLE process_;
+
+ private:
+  // Returns true if the code pointer by target_ corresponds to the expected
+  // type of function. Saves that code on the first part of the thunk pointed
+  // by local_thunk (should be directly accessible from the parent).
+  virtual bool IsFunctionAService(void* local_thunk) const;
+
+  // Performs the actual patch of target_.
+  // local_thunk must be already fully initialized, and the first part must
+  // contain the original code. The real type of this buffer is ServiceFullThunk
+  // (yes, private). remote_thunk (real type ServiceFullThunk), must be
+  // allocated on the child, and will contain the thunk data, after this call.
+  // Returns the apropriate status code.
+  virtual NTSTATUS PerformPatch(void* local_thunk, void* remote_thunk);
+
+  DISALLOW_COPY_AND_ASSIGN(Service64ResolverThunk);
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_WOW_HELPER_SERVICE64_RESOLVER_H__
diff --git a/sandbox/win/wow_helper/target_code.cc b/sandbox/win/wow_helper/target_code.cc
new file mode 100644
index 0000000..8da27cc
--- /dev/null
+++ b/sandbox/win/wow_helper/target_code.cc
@@ -0,0 +1,34 @@
+// 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 "sandbox/win/wow_helper/target_code.h"
+
+namespace sandbox {
+
+// Hooks NtMapViewOfSection to detect the load of dlls.
+NTSTATUS WINAPI TargetNtMapViewOfSection(
+    PatchInfo *patch_info, HANDLE process, PVOID *base, ULONG_PTR zero_bits,
+    SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size,
+    SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect) {
+  NTSTATUS ret = patch_info->orig_MapViewOfSection(patch_info->section, process,
+                                                   base, zero_bits, commit_size,
+                                                   offset, view_size, inherit,
+                                                   allocation_type, protect);
+
+  LARGE_INTEGER timeout;
+  timeout.QuadPart = -(5 * 10000000);  // 5 seconds.
+
+  // The wait is alertable.
+  patch_info->signal_and_wait(patch_info->dll_load, patch_info->continue_load,
+                              TRUE, &timeout);
+
+  return ret;
+}
+
+// Marks the end of the code to copy to the target process.
+NTSTATUS WINAPI TargetEnd() {
+  return STATUS_SUCCESS;
+}
+
+}  // namespace sandbox
diff --git a/sandbox/win/wow_helper/target_code.h b/sandbox/win/wow_helper/target_code.h
new file mode 100644
index 0000000..c198a85
--- /dev/null
+++ b/sandbox/win/wow_helper/target_code.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WOW_HELPER_TARGET_CODE_H__
+#define SANDBOX_WOW_HELPER_TARGET_CODE_H__
+
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Holds the information needed for the interception of NtMapViewOfSection.
+// Changes of this structure must be synchronized with changes of PatchInfo32
+// on sandbox/win/src/wow64.cc.
+struct PatchInfo {
+  HANDLE dll_load;  // Event to signal the broker.
+  HANDLE continue_load;  // Event to wait for the broker.
+  HANDLE section;  // First argument of the call.
+  NtMapViewOfSectionFunction orig_MapViewOfSection;
+  NtSignalAndWaitForSingleObjectFunction signal_and_wait;
+  void* patch_location;
+};
+
+// Interception of NtMapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+NTSTATUS WINAPI TargetNtMapViewOfSection(
+    PatchInfo* patch_info, HANDLE process, PVOID* base, ULONG_PTR zero_bits,
+    SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size,
+    SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect);
+
+// Marker of the end of TargetNtMapViewOfSection.
+NTSTATUS WINAPI TargetEnd();
+
+} // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WOW_HELPER_TARGET_CODE_H__
diff --git a/sandbox/win/wow_helper/wow_helper.cc b/sandbox/win/wow_helper/wow_helper.cc
new file mode 100644
index 0000000..e349337
--- /dev/null
+++ b/sandbox/win/wow_helper/wow_helper.cc
@@ -0,0 +1,86 @@
+// 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.
+
+// Wow_helper.exe is a simple Win32 64-bit executable designed to help to
+// sandbox a 32 bit application running on a 64 bit OS. The basic idea is to
+// perform a 64 bit interception of the target process and notify the 32-bit
+// broker process whenever a DLL is being loaded. This allows the broker to
+// setup the interceptions (32-bit) properly on the target.
+
+#include <windows.h>
+
+#include <string>
+
+#include "sandbox/win/wow_helper/service64_resolver.h"
+#include "sandbox/win/wow_helper/target_code.h"
+
+namespace sandbox {
+
+// Performs the interception of NtMapViewOfSection on the 64-bit version of
+// ntdll.dll. 'thunk' is the buffer on the address space of process 'child',
+// that will be used to store the information about the patch.
+int PatchNtdll(HANDLE child, void* thunk, size_t thunk_bytes) {
+  wchar_t* ntdll_name = L"ntdll.dll";
+  HMODULE ntdll_base = ::GetModuleHandle(ntdll_name);
+  if (!ntdll_base)
+    return 100;
+
+  Service64ResolverThunk resolver(child);
+  size_t used = resolver.GetThunkSize();
+  char* code = reinterpret_cast<char*>(thunk) + used;
+  NTSTATUS ret = resolver.Setup(ntdll_base, NULL, "NtMapViewOfSection", NULL,
+                                code, thunk, thunk_bytes, NULL);
+  if (!NT_SUCCESS(ret))
+    return 101;
+
+  size_t size = reinterpret_cast<char*>(&TargetEnd) -
+                reinterpret_cast<char*>(&TargetNtMapViewOfSection);
+
+  if (size + used > thunk_bytes)
+    return 102;
+
+  SIZE_T written;
+  if (!::WriteProcessMemory(child, code, &TargetNtMapViewOfSection, size,
+                            &written))
+    return 103;
+
+  if (size != written)
+    return 104;
+
+  return 0;
+}
+
+}  // namespace sandbox
+
+// We must receive two arguments: the process id of the target to intercept and
+// the address of a page of memory on that process that will be used for the
+// interception. We receive the address because the broker will cleanup the
+// patch when the work is performed.
+//
+// It should be noted that we don't wait until the real work is done; this
+// program quits as soon as the 64-bit interception is performed.
+int wWinMain(HINSTANCE, HINSTANCE, wchar_t* command_line, int) {
+  static_assert(sizeof(void*) > sizeof(DWORD), "unsupported 32 bits");
+  if (!command_line)
+    return 1;
+
+  wchar_t* next;
+  DWORD process_id = wcstoul(command_line, &next, 0);
+  if (!process_id)
+    return 2;
+
+  DWORD access = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE;
+  HANDLE child = ::OpenProcess(access, FALSE, process_id);
+  if (!child)
+    return 3;
+
+  DWORD buffer = wcstoul(next, NULL, 0);
+  if (!buffer)
+    return 4;
+
+  void* thunk = reinterpret_cast<void*>(static_cast<ULONG_PTR>(buffer));
+
+  const size_t kPageSize = 4096;
+  return sandbox::PatchNtdll(child, thunk, kPageSize);
+}
diff --git a/sandbox/win/wow_helper/wow_helper.exe b/sandbox/win/wow_helper/wow_helper.exe
new file mode 100755
index 0000000..f9bfb4b
--- /dev/null
+++ b/sandbox/win/wow_helper/wow_helper.exe
Binary files differ
diff --git a/sandbox/win/wow_helper/wow_helper.pdb b/sandbox/win/wow_helper/wow_helper.pdb
new file mode 100644
index 0000000..9cb67d0
--- /dev/null
+++ b/sandbox/win/wow_helper/wow_helper.pdb
Binary files differ
diff --git a/sandbox/win/wow_helper/wow_helper.vcproj b/sandbox/win/wow_helper/wow_helper.vcproj
new file mode 100644
index 0000000..5482fbd
--- /dev/null
+++ b/sandbox/win/wow_helper/wow_helper.vcproj
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="wow_helper"
+	ProjectGUID="{BCF3A457-39F1-4DAA-9A65-93CFCD559036}"
+	RootNamespace="wow_helper"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(ProjectDir)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="$(SolutionDir)..;$(SolutionDir)..\third_party\platformsdk_win2008_6_1\files\Include;$(VSInstallDir)\VC\atlmfc\include"
+				PreprocessorDefinitions="_WIN32_WINNT=0x0501;WINVER=0x0501;WIN32;_DEBUG"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="0"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(ProjectDir)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="$(SolutionDir)..;$(SolutionDir)..\third_party\platformsdk_win2008_6_1\files\Include;$(VSInstallDir)\VC\atlmfc\include"
+				PreprocessorDefinitions="_WIN32_WINNT=0x0501;WINVER=0x0501;WIN32;NDEBUG"
+				RuntimeLibrary="0"
+				BufferSecurityCheck="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="base"
+			>
+			<File
+				RelativePath="..\..\base\scoped_ptr.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="sandbox"
+			>
+			<File
+				RelativePath="..\src\nt_internals.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\resolver.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\service64_resolver.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\service64_resolver.h"
+			>
+		</File>
+		<File
+			RelativePath=".\target_code.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\target_code.h"
+			>
+		</File>
+		<File
+			RelativePath=".\wow_helper.cc"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/testing/gtest b/testing/gtest
new file mode 160000
index 0000000..be18681
--- /dev/null
+++ b/testing/gtest
@@ -0,0 +1 @@
+Subproject commit be1868139ffe0ccd0e8e3b37292b84c821d9c8ad
diff --git a/testing/multiprocess_func_list.cc b/testing/multiprocess_func_list.cc
new file mode 100644
index 0000000..49ae07d
--- /dev/null
+++ b/testing/multiprocess_func_list.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "multiprocess_func_list.h"
+
+#include <map>
+
+// Helper functions to maintain mapping of "test name"->test func.
+// The information is accessed via a global map.
+namespace multi_process_function_list {
+
+namespace {
+
+struct ProcessFunctions {
+  ProcessFunctions() : main(NULL), setup(NULL) {}
+  ProcessFunctions(TestMainFunctionPtr main, SetupFunctionPtr setup)
+      : main(main),
+        setup(setup) {
+  }
+  TestMainFunctionPtr main;
+  SetupFunctionPtr setup;
+};
+
+typedef std::map<std::string, ProcessFunctions> MultiProcessTestMap;
+
+// Retrieve a reference to the global 'func name' -> func ptr map.
+MultiProcessTestMap& GetMultiprocessFuncMap() {
+  static MultiProcessTestMap test_name_to_func_ptr_map;
+  return test_name_to_func_ptr_map;
+}
+
+}  // namespace
+
+AppendMultiProcessTest::AppendMultiProcessTest(
+    std::string test_name,
+    TestMainFunctionPtr main_func_ptr,
+    SetupFunctionPtr setup_func_ptr) {
+  GetMultiprocessFuncMap()[test_name] =
+      ProcessFunctions(main_func_ptr, setup_func_ptr);
+}
+
+int InvokeChildProcessTest(std::string test_name) {
+  MultiProcessTestMap& func_lookup_table = GetMultiprocessFuncMap();
+  MultiProcessTestMap::iterator it = func_lookup_table.find(test_name);
+  if (it != func_lookup_table.end()) {
+    const ProcessFunctions& process_functions = it->second;
+    if (process_functions.setup)
+      (*process_functions.setup)();
+    if (process_functions.main)
+      return (*process_functions.main)();
+  }
+
+  return -1;
+}
+
+}  // namespace multi_process_function_list
diff --git a/testing/multiprocess_func_list.h b/testing/multiprocess_func_list.h
new file mode 100644
index 0000000..f806d53
--- /dev/null
+++ b/testing/multiprocess_func_list.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TESTING_MULTIPROCESS_FUNC_LIST_H_
+#define TESTING_MULTIPROCESS_FUNC_LIST_H_
+
+#include <string>
+
+// This file provides the plumbing to register functions to be executed
+// as the main function of a child process in a multi-process test.
+// This complements the MultiProcessTest class which provides facilities
+// for launching such tests.
+//
+// The MULTIPROCESS_TEST_MAIN() macro registers a string -> func_ptr mapping
+// by creating a new global instance of the AppendMultiProcessTest() class
+// this means that by the time that we reach our main() function the mapping
+// is already in place.
+//
+// Example usage:
+//  MULTIPROCESS_TEST_MAIN(a_test_func) {
+//    // Code here runs in a child process.
+//    return 0;
+//  }
+//
+// The prototype of a_test_func is implicitly
+//   int test_main_func_name();
+
+namespace multi_process_function_list {
+
+// Type for child process main functions.
+typedef int (*TestMainFunctionPtr)();
+
+// Type for child setup functions.
+typedef void (*SetupFunctionPtr)();
+
+// Helper class to append a test function to the global mapping.
+// Used by the MULTIPROCESS_TEST_MAIN macro.
+class AppendMultiProcessTest {
+ public:
+  // |main_func_ptr| is the main function that is run in the child process.
+  // |setup_func_ptr| is a function run when the global mapping is added.
+  AppendMultiProcessTest(std::string test_name,
+                         TestMainFunctionPtr main_func_ptr,
+                         SetupFunctionPtr setup_func_ptr);
+};
+
+// Invoke the main function of a test previously registered with
+// MULTIPROCESS_TEST_MAIN()
+int InvokeChildProcessTest(std::string test_name);
+
+// This macro creates a global MultiProcessTest::AppendMultiProcessTest object
+// whose constructor does the work of adding the global mapping.
+#define MULTIPROCESS_TEST_MAIN(test_main) \
+  MULTIPROCESS_TEST_MAIN_WITH_SETUP(test_main, NULL)
+
+// Same as above but lets callers specify a setup method that is run in the
+// child process, just before the main function is run.  This facilitates
+// adding a generic one-time setup function for multiple tests.
+#define MULTIPROCESS_TEST_MAIN_WITH_SETUP(test_main, test_setup) \
+  int test_main(); \
+  namespace { \
+    multi_process_function_list::AppendMultiProcessTest \
+    AddMultiProcessTest##_##test_main(#test_main, (test_main), (test_setup)); \
+  } \
+  int test_main()
+
+}  // namespace multi_process_function_list
+
+#endif  // TESTING_MULTIPROCESS_FUNC_LIST_H_
diff --git a/testing/test.gni b/testing/test.gni
new file mode 100644
index 0000000..b4cdbed
--- /dev/null
+++ b/testing/test.gni
@@ -0,0 +1,240 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# ==============================================================================
+# TEST SETUP
+# ==============================================================================
+
+# Define a test as an executable (or apk on Android) with the "testonly" flag
+# set.
+template("test") {
+  if (is_android) {
+    import("//build/config/android/config.gni")
+    import("//build/config/android/rules.gni")
+
+    main_target_name = target_name
+    library_name = "_${target_name}__library"
+    apk_name = "${target_name}_apk"
+
+    shared_library(library_name) {
+      # Configs will always be defined since we set_defaults for a component
+      # in the main config. We want to use those rather than whatever came with
+      # the nested shared/static library inside the component.
+      configs = []  # Prevent list overwriting warning.
+      configs = invoker.configs
+
+      # See above call.
+      set_sources_assignment_filter([])
+
+      testonly = true
+
+      if (defined(invoker.all_dependent_configs)) {
+        all_dependent_configs = invoker.all_dependent_configs
+      }
+      if (defined(invoker.allow_circular_includes_from)) {
+        allow_circular_includes_from = invoker.allow_circular_includes_from
+      }
+      if (defined(invoker.cflags)) {
+        cflags = invoker.cflags
+      }
+      if (defined(invoker.cflags_c)) {
+        cflags_c = invoker.cflags_c
+      }
+      if (defined(invoker.cflags_cc)) {
+        cflags_cc = invoker.cflags_cc
+      }
+      if (defined(invoker.cflags_objc)) {
+        cflags_objc = invoker.cflags_objc
+      }
+      if (defined(invoker.cflags_objcc)) {
+        cflags_objcc = invoker.cflags_objcc
+      }
+      if (defined(invoker.check_includes)) {
+        check_includes = invoker.check_includes
+      }
+      if (defined(invoker.data)) {
+        data = invoker.data
+      }
+      if (defined(invoker.data_deps)) {
+        data_deps = invoker.data_deps
+      }
+      if (defined(invoker.datadeps)) {
+        datadeps = invoker.datadeps
+      }
+      if (defined(invoker.defines)) {
+        defines = invoker.defines
+      }
+      deps = []
+      if (!defined(invoker.use_launcher) || invoker.use_launcher) {
+        deps += [ "//testing/android/native_test:native_test_native_code" ]
+      }
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
+      if (defined(invoker.direct_dependent_configs)) {
+        direct_dependent_configs = invoker.direct_dependent_configs
+      }
+      if (defined(invoker.forward_dependent_configs_from)) {
+        forward_dependent_configs_from = invoker.forward_dependent_configs_from
+      }
+      if (defined(invoker.include_dirs)) {
+        include_dirs = invoker.include_dirs
+      }
+      if (defined(invoker.ldflags)) {
+        ldflags = invoker.ldflags
+      }
+      if (defined(invoker.lib_dirs)) {
+        lib_dirs = invoker.lib_dirs
+      }
+      if (defined(invoker.libs)) {
+        libs = invoker.libs
+      }
+      if (defined(invoker.output_extension)) {
+        output_extension = invoker.output_extension
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
+      if (defined(invoker.public)) {
+        public = invoker.public
+      }
+      if (defined(invoker.public_configs)) {
+        public_configs = invoker.public_configs
+      }
+      if (defined(invoker.public_deps)) {
+        public_deps = invoker.public_deps
+      }
+      if (defined(invoker.sources)) {
+        sources = invoker.sources
+      }
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+    }
+
+    unittest_apk(apk_name) {
+      unittests_dep = ":$library_name"
+      apk_name = main_target_name
+      if (defined(invoker.output_name)) {
+        apk_name = invoker.output_name
+        unittests_binary = "lib${apk_name}.so"
+      }
+      deps = [
+        ":$library_name",
+      ]
+      if (defined(invoker.apk_deps)) {
+        deps += invoker.apk_deps
+      }
+      if (defined(invoker.apk_asset_location)) {
+        asset_location = invoker.apk_asset_location
+      }
+    }
+
+    group(target_name) {
+      testonly = true
+
+      deps = [
+        ":$library_name",
+        ":$apk_name",
+      ]
+    }
+  } else {
+    executable(target_name) {
+      # See above.
+      configs = []  # Prevent list overwriting warning.
+      configs = invoker.configs
+
+      # See above call.
+      set_sources_assignment_filter([])
+
+      testonly = true
+
+      if (defined(invoker.all_dependent_configs)) {
+        all_dependent_configs = invoker.all_dependent_configs
+      }
+      if (defined(invoker.allow_circular_includes_from)) {
+        allow_circular_includes_from = invoker.allow_circular_includes_from
+      }
+      if (defined(invoker.cflags)) {
+        cflags = invoker.cflags
+      }
+      if (defined(invoker.cflags_c)) {
+        cflags_c = invoker.cflags_c
+      }
+      if (defined(invoker.cflags_cc)) {
+        cflags_cc = invoker.cflags_cc
+      }
+      if (defined(invoker.cflags_objc)) {
+        cflags_objc = invoker.cflags_objc
+      }
+      if (defined(invoker.cflags_objcc)) {
+        cflags_objcc = invoker.cflags_objcc
+      }
+      if (defined(invoker.check_includes)) {
+        check_includes = invoker.check_includes
+      }
+      if (defined(invoker.data)) {
+        data = invoker.data
+      }
+      if (defined(invoker.data_deps)) {
+        data_deps = invoker.data_deps
+      }
+      if (defined(invoker.datadeps)) {
+        datadeps = invoker.datadeps
+      }
+      if (defined(invoker.defines)) {
+        defines = invoker.defines
+      }
+
+      # All shared libraries must have the sanitizer deps to properly link in
+      # asan mode (this target will be empty in other cases).
+      if (defined(invoker.deps)) {
+        deps = invoker.deps + [ "//build/config/sanitizers:deps" ]
+      } else {
+        deps = [
+          "//build/config/sanitizers:deps",
+        ]
+      }
+      if (defined(invoker.direct_dependent_configs)) {
+        direct_dependent_configs = invoker.direct_dependent_configs
+      }
+      if (defined(invoker.forward_dependent_configs_from)) {
+        forward_dependent_configs_from = invoker.forward_dependent_configs_from
+      }
+      if (defined(invoker.include_dirs)) {
+        include_dirs = invoker.include_dirs
+      }
+      if (defined(invoker.ldflags)) {
+        ldflags = invoker.ldflags
+      }
+      if (defined(invoker.lib_dirs)) {
+        lib_dirs = invoker.lib_dirs
+      }
+      if (defined(invoker.libs)) {
+        libs = invoker.libs
+      }
+      if (defined(invoker.output_extension)) {
+        output_extension = invoker.output_extension
+      }
+      if (defined(invoker.output_name)) {
+        output_name = invoker.output_name
+      }
+      if (defined(invoker.public)) {
+        public = invoker.public
+      }
+      if (defined(invoker.public_configs)) {
+        public_configs = invoker.public_configs
+      }
+      if (defined(invoker.public_deps)) {
+        public_deps = invoker.public_deps
+      }
+      if (defined(invoker.sources)) {
+        sources = invoker.sources
+      }
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+      }
+    }
+  }
+}
diff --git a/third_party/libevent/BUILD.gn b/third_party/libevent/BUILD.gn
new file mode 100644
index 0000000..a1bd0c5
--- /dev/null
+++ b/third_party/libevent/BUILD.gn
@@ -0,0 +1,38 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("libevent") {
+  sources = [
+    "buffer.c",
+    "evbuffer.c",
+    "evdns.c",
+    "event.c",
+    "event_tagging.c",
+    "evrpc.c",
+    "evutil.c",
+    "http.c",
+    "log.c",
+    "poll.c",
+    "select.c",
+    "signal.c",
+    "strlcpy.c",
+  ]
+
+  defines = [ "HAVE_CONFIG_H" ]
+
+  if (is_mac || is_ios) {
+    sources += [ "kqueue.c" ]
+    include_dirs = [ "mac" ]
+  } else if (is_linux) {
+    sources += [ "epoll.c" ]
+    include_dirs = [ "linux" ]
+    libs = [ "rt" ]
+  } else if (is_android) {
+    sources += [ "epoll.c" ]
+    include_dirs = [ "android" ]
+  }
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/third_party/libevent/ChangeLog b/third_party/libevent/ChangeLog
new file mode 100644
index 0000000..50eb6b3
--- /dev/null
+++ b/third_party/libevent/ChangeLog
@@ -0,0 +1,201 @@
+Changes in 1.4.13-stable:
+ o If the kernel tells us that there are a negative number of bytes to read from a socket, do not believe it.  Fixes bug 2841177; found by Alexander Pronchenkov.
+ o Do not allocate the maximum event queue and fd array for the epoll backend at startup.  Instead, start out accepting 32 events at a time, and double the queue's size when it seems that the OS is generating events faster than we're requesting them.  Saves up to 512K per epoll-based event_base.  Resolves bug 2839240.
+ o Fix compilation on Android, which forgot to define fd_mask in its sys/select.h
+ o Do not drop data from evbuffer when out of memory; reported by Jacek Masiulaniec
+ o Rename our replacement compat/sys/_time.h header to avoid build a conflict on HPUX; reported by Kathryn Hogg.
+ o Build kqueue.c correctly on GNU/kFreeBSD platforms. Patch pulled upstream from Debian.
+ o Fix a problem with excessive memory allocation when using multiple event priorities.
+ o When running set[ug]id, don't check the environment. Based on a patch from OpenBSD.
+
+
+Changes in 1.4.12-stable:
+ o Try to contain degree of failure when running on a win32 version so heavily firewalled that we can't fake a socketpair.
+ o Fix an obscure timing-dependent, allocator-dependent crash in the evdns code.
+ o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC.
+ o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
+ o Fix another pair of fencepost bugs in epoll.c.  [Patch from Adam Langley.]
+ o Do not break evdns connections to nameservers when our IP changes.
+ o Set truncated flag correctly in evdns server replies.
+ o Disable strict aliasing with GCC: our code is not compliant with it.
+
+Changes in 1.4.11-stable:
+ o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
+ o Remove the limit on size of HTTP headers by removing static buffers.
+ o Fix a nasty dangling pointer bug in epoll.c that could occur after epoll_recalc(). [Patch from Kevin Springborn]
+ o Distribute Win32-Code/event-config.h, not ./event-config.h
+
+Changes in 1.4.10-stable:
+ o clean up buffered http connection data on reset; reported by Brian O'Kelley
+ o bug fix and potential race condition in signal handling; from Alexander Drozdov
+ o rename the Solaris event ports backend to evport
+ o support compilation on Haiku
+ o fix signal processing when a signal callback delivers a signal; from Alexander Drozdov
+ o const-ify some arguments to evdns functions.
+ o off-by-one error in epoll_recalc; reported by Victor Goya
+ o include Doxyfile in tar ball; from Jeff Garzik
+ o correctly parse queries with encoded \r, \n or + characters
+
+Changes in 1.4.9-stable:
+ o event_add would not return error for some backends; from Dean McNamee
+ o Clear the timer cache on entering the event loop; reported by Victor Chang
+ o Only bind the socket on connect when a local address has been provided; reported by Alejo Sanchez
+ o Allow setting of local port for evhttp connections to support millions of connections from a single system; from Richard Jones.
+ o Clear the timer cache when leaving the event loop; reported by Robin Haberkorn
+ o Fix a typo in setting the global event base; reported by lance.
+ o Fix a memory leak when reading multi-line headers
+ o Fix a memory leak by not running explicit close detection for server connections
+
+Changes in 1.4.8-stable:
+ o Match the query in DNS replies to the query in the request; from Vsevolod Stakhov.
+ o Fix a merge problem in which name_from_addr returned pointers to the stack; found by Jiang Hong.
+ o Do not remove Accept-Encoding header
+	
+Changes in 1.4.7-stable:
+ o Fix a bug where headers arriving in multiple packets were not parsed; fix from Jiang Hong; test by me.
+	
+Changes in 1.4.6-stable:
+ o evutil.h now includes <stdarg.h> directly
+ o switch all uses of [v]snprintf over to evutil
+ o Correct handling of trailing headers in chunked replies; from Scott Lamb.
+ o Support multi-line HTTP headers; based on a patch from Moshe Litvin
+ o Reject negative Content-Length headers; anonymous bug report
+ o Detect CLOCK_MONOTONIC at runtime for evdns; anonymous bug report	
+ o Fix a bug where deleting signals with the kqueue backend would cause subsequent adds to fail
+ o Support multiple events listening on the same signal; make signals regular events that go on the same event queue; problem report by Alexander Drozdov.
+ o Deal with evbuffer_read() returning -1 on EINTR|EAGAIN; from Adam Langley.
+ o Fix a bug in which the DNS server would incorrectly set the type of a cname reply to a.
+ o Fix a bug where setting the timeout on a bufferevent would take not effect if the event was already pending.
+ o Fix a memory leak when using signals for some event bases; reported by Alexander Drozdov.
+ o Add libevent.vcproj file to distribution to help with Windows build.
+ o Fix a problem with epoll() and reinit; problem report by Alexander Drozdov.	
+ o Fix off-by-one errors in devpoll; from Ian Bell
+ o Make event_add not change any state if it fails; reported by Ian Bell.
+ o Do not warn on accept when errno is either EAGAIN or EINTR
+
+Changes in 1.4.5-stable:
+ o Fix connection keep-alive behavior for HTTP/1.0
+ o Fix use of freed memory in event_reinit; pointed out by Peter Postma
+ o Constify struct timeval * where possible; pointed out by Forest Wilkinson
+ o allow min_heap_erase to be called on removed members; from liusifan.
+ o Rename INPUT and OUTPUT to EVRPC_INPUT and EVRPC_OUTPUT.  Retain INPUT/OUTPUT aliases on on-win32 platforms for backwards compatibility.
+ o Do not use SO_REUSEADDR when connecting
+ o Fix Windows build
+ o Fix a bug in event_rpcgen when generated fixed-sized entries
+
+Changes in 1.4.4-stable:
+ o Correct the documentation on buffer printf functions.
+ o Don't warn on unimplemented epoll_create(): this isn't a problem, just a reason to fall back to poll or select.
+ o Correctly handle timeouts larger than 35 minutes on Linux with epoll.c.  This is probably a kernel defect, but we'll have to support old kernels anyway even if it gets fixed.
+ o Fix a potential stack corruption bug in tagging on 64-bit CPUs.
+ o expose bufferevent_setwatermark via header files and fix high watermark on read
+ o fix a bug in bufferevent read water marks and add a test for them
+ o introduce bufferevent_setcb and bufferevent_setfd to allow better manipulation of bufferevents
+ o use libevent's internal timercmp on all platforms, to avoid bugs on old platforms where timercmp(a,b,<=) is buggy.
+ o reduce system calls for getting current time by caching it.
+ o fix evhttp_bind_socket() so that multiple sockets can be bound by the same http server.
+ o Build test directory correctly with CPPFLAGS set.
+ o Fix build under Visual C++ 2005.
+ o Expose evhttp_accept_socket() API.
+ o Merge windows gettimeofday() replacement into a new evutil_gettimeofday() function.
+ o Fix autoconf script behavior on IRIX.
+ o Make sure winsock2.h include always comes before windows.h include.
+
+Changes in 1.4.3-stable:
+ o include Content-Length in reply for HTTP/1.0 requests with keep-alive
+ o Patch from Tani Hosokawa: make some functions in http.c threadsafe.
+ o Do not free the kqop file descriptor in other processes, also allow it to be 0; from Andrei Nigmatulin
+ o make event_rpcgen.py generate code include event-config.h; reported by Sam Banks.
+ o make event methods static so that they are not exported; from Andrei Nigmatulin
+ o make RPC replies use application/octet-stream as mime type
+ o do not delete uninitialized timeout event in evdns
+
+Changes in 1.4.2-rc:
+ o remove pending timeouts on event_base_free()
+ o also check EAGAIN for Solaris' event ports; from W.C.A. Wijngaards
+ o devpoll and evport need reinit; tested by W.C.A Wijngaards
+ o event_base_get_method; from Springande Ulv
+ o Send CRLF after each chunk in HTTP output, for compliance with RFC2626.  Patch from "propanbutan".  Fixes bug 1894184.
+ o Add a int64_t parsing function, with unit tests, so we can apply Scott Lamb's fix to allow large HTTP values.
+ o Use a 64-bit field to hold HTTP content-lengths.  Patch from Scott Lamb.
+ o Allow regression code to build even without Python installed
+ o remove NDEBUG ifdefs from evdns.c
+ o update documentation of event_loop and event_base_loop; from Tani Hosokawa.
+ o detect integer types properly on platforms without stdint.h
+ o Remove "AM_MAINTAINER_MODE" declaration in configure.in: now makefiles and configure should get re-generated automatically when Makefile.am or configure.in chanes.
+ o do not insert event into list when evsel->add fails
+
+Changes in 1.4.1-beta:
+ o free minheap on event_base_free(); from Christopher Layne
+ o debug cleanups in signal.c; from Christopher Layne
+ o provide event_base_new() that does not set the current_base global
+ o bufferevent_write now uses a const source argument; report from Charles Kerr
+ o better documentation for event_base_loopexit; from Scott Lamb.
+ o Make kqueue have the same behavior as other backends when a signal is caught between event_add() and event_loop().  Previously, it would catch and ignore such signals.
+ o Make kqueue restore signal handlers correctly when event_del() is called.
+ o provide event_reinit() to reintialize an event_base after fork
+ o small improvements to evhttp documentation
+ o always generate Date and Content-Length headers for HTTP/1.1 replies
+ o set the correct event base for HTTP close events
+ o New function, event_{base_}loopbreak.  Like event_loopexit, it makes an event loop stop executing and return.  Unlike event_loopexit, it keeps subsequent pending events from getting executed.  Patch from Scott Lamb
+ o Removed obsoleted recalc code
+ o pull setters/getters out of RPC structures into a base class to which we just need to store a pointer; this reduces the memory footprint of these structures.
+ o fix a bug with event_rpcgen for integers
+ o move EV_PERSIST handling out of the event backends
+ o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly.
+ o prefix {encode,decode}_tag functions with evtag to avoid collisions
+ o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
+ o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings.  (Nick has been building with these for a while, but they might be useful to other developers.)
+ o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions.
+ o removed linger from http server socket; reported by Ilya Martynov
+ o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
+ o demote most http warnings to debug messages
+ o Fix Solaris compilation; from Magne Mahre
+ o Add a "Date" header to HTTP responses, as required by HTTP 1.1.
+ o Support specifying the local address of an evhttp_connection using set_local_address
+ o Fix a memory leak in which failed HTTP connections would not free the request object
+ o Make adding of array members in event_rpcgen more efficient, but doubling memory allocation
+ o Fix a memory leak in the DNS server
+ o Fix compilation when DNS_USE_OPENSSL_FOR_ID is enabled
+ o Fix buffer size and string generation in evdns_resolve_reverse_ipv6().
+ o Respond to nonstandard DNS queries with "NOTIMPL" rather than by ignoring them.
+ o In DNS responses, the CD flag should be preserved, not the TC flag.
+ o Fix http.c to compile properly with USE_DEBUG; from Christopher Layne
+ o Handle NULL timeouts correctly on Solaris; from Trond Norbye
+ o Recalculate pending events properly when reallocating event array on Solaris; from Trond Norbye
+ o Add Doxygen documentation to header files; from Mark Heily
+ o Add a evdns_set_transaction_id_fn() function to override the default
+   transaction ID generation code.
+ o Add an evutil module (with header evutil.h) to implement our standard cross-platform hacks, on the theory that somebody else would like to use them too.
+ o Fix signals implementation on windows.
+ o Fix http module on windows to close sockets properly.
+ o Make autogen.sh script run correctly on systems where /bin/sh isn't bash. (Patch from Trond Norbye, rewritten by Hagne Mahre and then Hannah Schroeter.)
+ o Skip calling gettime() in timeout_process if we are not in fact waiting for any events. (Patch from Trond Norbye)
+ o Make test subdirectory compile under mingw.
+ o Fix win32 buffer.c behavior so that it is correct for sockets (which do not like ReadFile and WriteFile).
+ o Make the test.sh script run unit tests for the evpoll method.
+ o Make the entire evdns.h header enclosed in "extern C" as appropriate.
+ o Fix implementation of strsep on platforms that lack it
+ o Fix implementation of getaddrinfo on platforms that lack it; mainly, this will make Windows http.c work better.  Original patch by Lubomir Marinov.
+ o Fix evport implementation: port_disassociate called on unassociated events resulting in bogus errors; more efficient memory management; from Trond Norbye and Prakash Sangappa
+ o support for hooks on rpc input and output; can be used to implement rpc independent processing such as compression or authentication.
+ o use a min heap instead of a red-black tree for timeouts; as a result finding the min is a O(1) operation now; from Maxim Yegorushkin
+ o associate an event base with an rpc pool
+ o added two additional libraries: libevent_core and libevent_extra in addition to the regular libevent.  libevent_core contains only the event core whereas libevent_extra contains dns, http and rpc support
+ o Begin using libtool's library versioning support correctly.  If we don't mess up, this will more or less guarantee binaries linked against old versions of libevent continue working when we make changes to libevent that do not break backward compatibility.
+ o Fix evhttp.h compilation when TAILQ_ENTRY is not defined.
+ o Small code cleanups in epoll_dispatch().
+ o Increase the maximum number of addresses read from a packet in evdns to 32.
+ o Remove support for the rtsig method: it hasn't compiled for a while, and nobody seems to miss it very much.  Let us know if there's a good reason to put it back in.
+ o Rename the "class" field in evdns_server_request to dns_question_class, so that it won't break compilation under C++.  Use a macro so that old code won't break.  Mark the macro as deprecated.
+ o Fix DNS unit tests so that having a DNS server with broken IPv6 support is no longer cause for aborting the unit tests.
+ o Make event_base_free() succeed even if there are pending non-internal events on a base.  This may still leak memory and fds, but at least it no longer crashes.
+ o Post-process the config.h file into a new, installed event-config.h file that we can install, and whose macros will be safe to include in header files.
+ o Remove the long-deprecated acconfig.h file.
+ o Do not require #include <sys/types.h> before #include <event.h>.
+ o Add new evutil_timer* functions to wrap (or replace) the regular timeval manipulation functions.
+ o Fix many build issues when using the Microsoft C compiler.
+ o Remove a bash-ism in autogen.sh
+ o When calling event_del on a signal, restore the signal handler's previous value rather than setting it to SIG_DFL. Patch from Christopher Layne.
+ o Make the logic for active events work better with internal events; patch from Christopher Layne.
+ o We do not need to specially remove a timeout before calling event_del; patch from Christopher Layne.
diff --git a/third_party/libevent/LICENSE b/third_party/libevent/LICENSE
new file mode 100644
index 0000000..af977a4
--- /dev/null
+++ b/third_party/libevent/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+Copyright 2007-2009 Niels Provos and Nick Mathewson
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/libevent/Makefile.am b/third_party/libevent/Makefile.am
new file mode 100644
index 0000000..dc78ef1
--- /dev/null
+++ b/third_party/libevent/Makefile.am
@@ -0,0 +1,124 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+# This is the point release for libevent.  It shouldn't include any
+# a/b/c/d/e notations.
+RELEASE = 1.4
+
+# This is the version info for the libevent binary API.  It has three
+# numbers:
+#   Current  -- the number of the binary API that we're implementing
+#   Revision -- which iteration of the implementation of the binary
+#               API are we supplying?
+#   Age      -- How many previous binary API versions do we also
+#               support?
+#
+# If we release a new version that does not change the binary API,
+# increment Revision.
+#
+# If we release a new version that changes the binary API, but does
+# not break programs compiled against the old binary API, increment
+# Current and Age.  Set Revision to 0, since this is the first
+# implementation of the new API.
+#
+# Otherwise, we're changing the binary API and breaking bakward
+# compatibility with old binaries.  Increment Current.  Set Age to 0,
+# since we're backward compatible with no previous APIs.  Set Revision
+# to 0 too.
+
+# History:
+#  Libevent 1.4.1 was 2:0:0
+#  Libevent 1.4.2 should be 3:0:0
+#  Libevent 1.4.5 is 3:0:1 (we forgot to increment in the past)
+VERSION_INFO = 3:3:1
+
+bin_SCRIPTS = event_rpcgen.py
+
+EXTRA_DIST = autogen.sh event.h event-internal.h log.h evsignal.h evdns.3 \
+	evrpc.h evrpc-internal.h min_heap.h \
+	event.3 \
+	Doxyfile \
+	kqueue.c epoll_sub.c epoll.c select.c poll.c signal.c \
+	evport.c devpoll.c event_rpcgen.py \
+	sample/Makefile.am sample/Makefile.in sample/event-test.c \
+	sample/signal-test.c sample/time-test.c \
+	test/Makefile.am test/Makefile.in test/bench.c test/regress.c \
+	test/test-eof.c test/test-weof.c test/test-time.c \
+	test/test-init.c test/test.sh \
+	compat/sys/queue.h compat/sys/_libevent_time.h \
+	WIN32-Code/config.h \
+	WIN32-Code/event-config.h \
+	WIN32-Code/win32.c \
+	WIN32-Code/tree.h \
+	WIN32-Prj/event_test/event_test.dsp \
+	WIN32-Prj/event_test/test.txt WIN32-Prj/libevent.dsp \
+	WIN32-Prj/libevent.dsw WIN32-Prj/signal_test/signal_test.dsp \
+	WIN32-Prj/time_test/time_test.dsp WIN32-Prj/regress/regress.vcproj \
+	WIN32-Prj/libevent.sln WIN32-Prj/libevent.vcproj
+
+lib_LTLIBRARIES = libevent.la libevent_core.la libevent_extra.la
+
+if BUILD_WIN32
+
+SUBDIRS = . sample
+SYS_LIBS = -lws2_32
+SYS_SRC = WIN32-Code/win32.c
+SYS_INCLUDES = -IWIN32-Code
+
+else
+
+SUBDIRS = . sample test
+SYS_LIBS =
+SYS_SRC =
+SYS_INCLUDES =
+
+endif
+
+BUILT_SOURCES = event-config.h
+
+event-config.h: config.h
+	echo '/* event-config.h' > $@
+	echo ' * Generated by autoconf; post-processed by libevent.' >> $@
+	echo ' * Do not edit this file.' >> $@
+	echo ' * Do not rely on macros in this file existing in later versions.'>> $@
+	echo ' */' >> $@
+	echo '#ifndef _EVENT_CONFIG_H_' >> $@
+	echo '#define _EVENT_CONFIG_H_' >> $@
+
+	sed -e 's/#define /#define _EVENT_/' \
+	    -e 's/#undef /#undef _EVENT_/' \
+	    -e 's/#ifndef /#ifndef _EVENT_/' < config.h >> $@
+	echo "#endif" >> $@
+
+CORE_SRC = event.c buffer.c evbuffer.c log.c evutil.c $(SYS_SRC)
+EXTRA_SRC = event_tagging.c http.c evhttp.h http-internal.h evdns.c \
+	evdns.h evrpc.c evrpc.h evrpc-internal.h \
+	strlcpy.c strlcpy-internal.h strlcpy-internal.h
+
+libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC)
+libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+
+libevent_core_la_SOURCES = $(CORE_SRC)
+libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_core_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+
+libevent_extra_la_SOURCES = $(EXTRA_SRC)
+libevent_extra_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_extra_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+
+include_HEADERS = event.h evhttp.h evdns.h evrpc.h evutil.h
+
+nodist_include_HEADERS = event-config.h
+
+INCLUDES = -I$(srcdir)/compat $(SYS_INCLUDES)
+
+man_MANS = event.3 evdns.3
+
+verify: libevent.la
+	cd test && make verify
+
+doxygen: FORCE
+	doxygen $(srcdir)/Doxyfile
+FORCE:
+
+DISTCLEANFILES = *~ event-config.h
diff --git a/third_party/libevent/Makefile.in b/third_party/libevent/Makefile.in
new file mode 100644
index 0000000..4d96c74
--- /dev/null
+++ b/third_party/libevent/Makefile.in
@@ -0,0 +1,976 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(include_HEADERS) \
+	$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/config.h.in $(top_srcdir)/configure ChangeLog \
+	config.guess config.sub devpoll.c epoll.c epoll_sub.c evport.c \
+	install-sh kqueue.c ltmain.sh missing mkinstalldirs poll.c \
+	select.c signal.c
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+	"$(DESTDIR)$(man3dir)" "$(DESTDIR)$(includedir)" \
+	"$(DESTDIR)$(includedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libevent_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_1)
+am__libevent_la_SOURCES_DIST = event.c buffer.c evbuffer.c log.c \
+	evutil.c WIN32-Code/win32.c event_tagging.c http.c evhttp.h \
+	http-internal.h evdns.c evdns.h evrpc.c evrpc.h \
+	evrpc-internal.h strlcpy.c strlcpy-internal.h
+@BUILD_WIN32_TRUE@am__objects_1 = win32.lo
+am__objects_2 = event.lo buffer.lo evbuffer.lo log.lo evutil.lo \
+	$(am__objects_1)
+am__objects_3 = event_tagging.lo http.lo evdns.lo evrpc.lo strlcpy.lo
+am_libevent_la_OBJECTS = $(am__objects_2) $(am__objects_3)
+libevent_la_OBJECTS = $(am_libevent_la_OBJECTS)
+libevent_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libevent_la_LDFLAGS) $(LDFLAGS) -o $@
+libevent_core_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_1)
+am__libevent_core_la_SOURCES_DIST = event.c buffer.c evbuffer.c log.c \
+	evutil.c WIN32-Code/win32.c
+am_libevent_core_la_OBJECTS = $(am__objects_2)
+libevent_core_la_OBJECTS = $(am_libevent_core_la_OBJECTS)
+libevent_core_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libevent_core_la_LDFLAGS) $(LDFLAGS) -o $@
+libevent_extra_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_1)
+am_libevent_extra_la_OBJECTS = $(am__objects_3)
+libevent_extra_la_OBJECTS = $(am_libevent_extra_la_OBJECTS)
+libevent_extra_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libevent_extra_la_LDFLAGS) $(LDFLAGS) -o $@
+binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+SCRIPTS = $(bin_SCRIPTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(libevent_la_SOURCES) $(libevent_core_la_SOURCES) \
+	$(libevent_extra_la_SOURCES)
+DIST_SOURCES = $(am__libevent_la_SOURCES_DIST) \
+	$(am__libevent_core_la_SOURCES_DIST) \
+	$(libevent_extra_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-dvi-recursive install-exec-recursive \
+	install-html-recursive install-info-recursive \
+	install-pdf-recursive install-ps-recursive install-recursive \
+	installcheck-recursive installdirs-recursive pdf-recursive \
+	ps-recursive uninstall-recursive
+man3dir = $(mandir)/man3
+NROFF = nroff
+MANS = $(man_MANS)
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+nodist_includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(include_HEADERS) $(nodist_include_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = . sample test
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  { test ! -d $(distdir) \
+    || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+# This is the point release for libevent.  It shouldn't include any
+# a/b/c/d/e notations.
+RELEASE = 1.4
+
+# This is the version info for the libevent binary API.  It has three
+# numbers:
+#   Current  -- the number of the binary API that we're implementing
+#   Revision -- which iteration of the implementation of the binary
+#               API are we supplying?
+#   Age      -- How many previous binary API versions do we also
+#               support?
+#
+# If we release a new version that does not change the binary API,
+# increment Revision.
+#
+# If we release a new version that changes the binary API, but does
+# not break programs compiled against the old binary API, increment
+# Current and Age.  Set Revision to 0, since this is the first
+# implementation of the new API.
+#
+# Otherwise, we're changing the binary API and breaking bakward
+# compatibility with old binaries.  Increment Current.  Set Age to 0,
+# since we're backward compatible with no previous APIs.  Set Revision
+# to 0 too.
+
+# History:
+#  Libevent 1.4.1 was 2:0:0
+#  Libevent 1.4.2 should be 3:0:0
+#  Libevent 1.4.5 is 3:0:1 (we forgot to increment in the past)
+VERSION_INFO = 3:3:1
+bin_SCRIPTS = event_rpcgen.py
+EXTRA_DIST = autogen.sh event.h event-internal.h log.h evsignal.h evdns.3 \
+	evrpc.h evrpc-internal.h min_heap.h \
+	event.3 \
+	Doxyfile \
+	kqueue.c epoll_sub.c epoll.c select.c poll.c signal.c \
+	evport.c devpoll.c event_rpcgen.py \
+	sample/Makefile.am sample/Makefile.in sample/event-test.c \
+	sample/signal-test.c sample/time-test.c \
+	test/Makefile.am test/Makefile.in test/bench.c test/regress.c \
+	test/test-eof.c test/test-weof.c test/test-time.c \
+	test/test-init.c test/test.sh \
+	compat/sys/queue.h compat/sys/_libevent_time.h \
+	WIN32-Code/config.h \
+	WIN32-Code/event-config.h \
+	WIN32-Code/win32.c \
+	WIN32-Code/tree.h \
+	WIN32-Prj/event_test/event_test.dsp \
+	WIN32-Prj/event_test/test.txt WIN32-Prj/libevent.dsp \
+	WIN32-Prj/libevent.dsw WIN32-Prj/signal_test/signal_test.dsp \
+	WIN32-Prj/time_test/time_test.dsp WIN32-Prj/regress/regress.vcproj \
+	WIN32-Prj/libevent.sln WIN32-Prj/libevent.vcproj
+
+lib_LTLIBRARIES = libevent.la libevent_core.la libevent_extra.la
+@BUILD_WIN32_FALSE@SUBDIRS = . sample test
+@BUILD_WIN32_TRUE@SUBDIRS = . sample
+@BUILD_WIN32_FALSE@SYS_LIBS = 
+@BUILD_WIN32_TRUE@SYS_LIBS = -lws2_32
+@BUILD_WIN32_FALSE@SYS_SRC = 
+@BUILD_WIN32_TRUE@SYS_SRC = WIN32-Code/win32.c
+@BUILD_WIN32_FALSE@SYS_INCLUDES = 
+@BUILD_WIN32_TRUE@SYS_INCLUDES = -IWIN32-Code
+BUILT_SOURCES = event-config.h
+CORE_SRC = event.c buffer.c evbuffer.c log.c evutil.c $(SYS_SRC)
+EXTRA_SRC = event_tagging.c http.c evhttp.h http-internal.h evdns.c \
+	evdns.h evrpc.c evrpc.h evrpc-internal.h \
+	strlcpy.c strlcpy-internal.h strlcpy-internal.h
+
+libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC)
+libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+libevent_core_la_SOURCES = $(CORE_SRC)
+libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_core_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+libevent_extra_la_SOURCES = $(EXTRA_SRC)
+libevent_extra_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_extra_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+include_HEADERS = event.h evhttp.h evdns.h evrpc.h evutil.h
+nodist_include_HEADERS = event-config.h
+INCLUDES = -I$(srcdir)/compat $(SYS_INCLUDES)
+man_MANS = event.3 evdns.3
+DISTCLEANFILES = *~ event-config.h
+all: $(BUILT_SOURCES) config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh:
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+	      cd $(srcdir) && $(AUTOMAKE) --foreign  \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	cd $(top_srcdir) && $(AUTOHEADER)
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    f=$(am__strip_dir) \
+	    echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+	    $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  p=$(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libevent.la: $(libevent_la_OBJECTS) $(libevent_la_DEPENDENCIES) 
+	$(libevent_la_LINK) -rpath $(libdir) $(libevent_la_OBJECTS) $(libevent_la_LIBADD) $(LIBS)
+libevent_core.la: $(libevent_core_la_OBJECTS) $(libevent_core_la_DEPENDENCIES) 
+	$(libevent_core_la_LINK) -rpath $(libdir) $(libevent_core_la_OBJECTS) $(libevent_core_la_LIBADD) $(LIBS)
+libevent_extra.la: $(libevent_extra_la_OBJECTS) $(libevent_extra_la_DEPENDENCIES) 
+	$(libevent_extra_la_LINK) -rpath $(libdir) $(libevent_extra_la_OBJECTS) $(libevent_extra_la_LIBADD) $(LIBS)
+install-binSCRIPTS: $(bin_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	@list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  if test -f $$d$$p; then \
+	    f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	    echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+	    $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-binSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_SCRIPTS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	  echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(bindir)/$$f"; \
+	done
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(COMPILE) -c $<
+
+.c.obj:
+	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(LTCOMPILE) -c -o $@ $<
+
+win32.lo: WIN32-Code/win32.c
+	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o win32.lo `test -f 'WIN32-Code/win32.c' || echo '$(srcdir)/'`WIN32-Code/win32.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+install-man3: $(man3_MANS) $(man_MANS)
+	@$(NORMAL_INSTALL)
+	test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)"
+	@list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
+	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+	for i in $$l2; do \
+	  case "$$i" in \
+	    *.3*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+	  else file=$$i; fi; \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  case "$$ext" in \
+	    3*) ;; \
+	    *) ext='3' ;; \
+	  esac; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+	  $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \
+	done
+uninstall-man3:
+	@$(NORMAL_UNINSTALL)
+	@list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
+	l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
+	for i in $$l2; do \
+	  case "$$i" in \
+	    *.3*) list="$$list $$i" ;; \
+	  esac; \
+	done; \
+	for i in $$list; do \
+	  ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+	  case "$$ext" in \
+	    3*) ;; \
+	    *) ext='3' ;; \
+	  esac; \
+	  inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+	  inst=`echo $$inst | sed -e 's/^.*\///'`; \
+	  inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+	  echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \
+	  rm -f "$(DESTDIR)$(man3dir)/$$inst"; \
+	done
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+	@list='$(include_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(am__strip_dir) \
+	  echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+	  $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; for p in $$list; do \
+	  f=$(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(includedir)/$$f"; \
+	done
+install-nodist_includeHEADERS: $(nodist_include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+	@list='$(nodist_include_HEADERS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(am__strip_dir) \
+	  echo " $(nodist_includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+	  $(nodist_includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+	done
+
+uninstall-nodist_includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(nodist_include_HEADERS)'; for p in $$list; do \
+	  f=$(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(includedir)/$$f"; \
+	done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+	@failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d $(distdir) || mkdir $(distdir)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+	list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(MKDIR_P) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	    distdir=`$(am__cd) $(distdir) && pwd`; \
+	    top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+	    (cd $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$top_distdir" \
+	        distdir="$$distdir/$$subdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r $(distdir)
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+	$(am__remove_distdir)
+
+dist-lzma: distdir
+	tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+	$(am__remove_distdir)
+
+dist-tarZ: distdir
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__remove_distdir)
+
+dist-shar: distdir
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__remove_distdir)
+
+dist dist-all: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lzma*) \
+	  unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir); chmod a+w $(distdir)
+	mkdir $(distdir)/_build
+	mkdir $(distdir)/_inst
+	chmod a-w $(distdir)
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && cd $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+	$(am__remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@cd $(distuninstallcheck_dir) \
+	&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-recursive
+all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(MANS) $(HEADERS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-includeHEADERS install-man \
+	install-nodist_includeHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-exec-am: install-binSCRIPTS install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-info: install-info-recursive
+
+install-man: install-man3
+
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binSCRIPTS uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES uninstall-man \
+	uninstall-nodist_includeHEADERS
+
+uninstall-man: uninstall-man3
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+	install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+	all all-am am--refresh check check-am clean clean-generic \
+	clean-libLTLIBRARIES clean-libtool ctags ctags-recursive dist \
+	dist-all dist-bzip2 dist-gzip dist-lzma dist-shar dist-tarZ \
+	dist-zip distcheck distclean distclean-compile \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-tags distcleancheck distdir distuninstallcheck dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-binSCRIPTS install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-includeHEADERS install-info \
+	install-info-am install-libLTLIBRARIES install-man \
+	install-man3 install-nodist_includeHEADERS install-pdf \
+	install-pdf-am install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs installdirs-am \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+	uninstall-binSCRIPTS uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES uninstall-man uninstall-man3 \
+	uninstall-nodist_includeHEADERS
+
+
+event-config.h: config.h
+	echo '/* event-config.h' > $@
+	echo ' * Generated by autoconf; post-processed by libevent.' >> $@
+	echo ' * Do not edit this file.' >> $@
+	echo ' * Do not rely on macros in this file existing in later versions.'>> $@
+	echo ' */' >> $@
+	echo '#ifndef _EVENT_CONFIG_H_' >> $@
+	echo '#define _EVENT_CONFIG_H_' >> $@
+
+	sed -e 's/#define /#define _EVENT_/' \
+	    -e 's/#undef /#undef _EVENT_/' \
+	    -e 's/#ifndef /#ifndef _EVENT_/' < config.h >> $@
+	echo "#endif" >> $@
+
+verify: libevent.la
+	cd test && make verify
+
+doxygen: FORCE
+	doxygen $(srcdir)/Doxyfile
+FORCE:
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/libevent/README b/third_party/libevent/README
new file mode 100644
index 0000000..b065039
--- /dev/null
+++ b/third_party/libevent/README
@@ -0,0 +1,57 @@
+To build libevent, type
+
+$ ./configure && make
+
+     (If you got libevent from the subversion repository, you will
+      first need to run the included "autogen.sh" script in order to
+      generate the configure script.)
+
+Install as root via
+
+# make install
+
+You can run the regression tests by
+
+$ make verify
+
+Before, reporting any problems, please run the regression tests.
+
+To enable the low-level tracing build the library as:
+
+CFLAGS=-DUSE_DEBUG ./configure [...]
+
+Acknowledgements:
+-----------------
+
+The following people have helped with suggestions, ideas, code or
+fixing bugs:
+
+  Alejo
+  Weston Andros Adamson
+  William Ahern
+  Stas Bekman
+  Andrew Danforth
+  Mike Davis
+  Shie Erlich
+  Alexander von Gernler
+  Artur Grabowski
+  Aaron Hopkins
+  Claudio Jeker
+  Scott Lamb
+  Adam Langley
+  Philip Lewis
+  David Libenzi
+  Nick Mathewson
+  Andrey Matveev
+  Richard Nyberg
+  Jon Oberheide
+  Phil Oleson
+  Dave Pacheco
+  Tassilo von Parseval
+  Pierre Phaneuf
+  Jon Poland
+  Bert JW Regeer
+  Dug Song
+  Taral
+
+If I have forgotten your name, please contact me.
diff --git a/third_party/libevent/README.chromium b/third_party/libevent/README.chromium
new file mode 100644
index 0000000..939a353
--- /dev/null
+++ b/third_party/libevent/README.chromium
@@ -0,0 +1,28 @@
+Name: libevent
+URL: http://www.monkey.org/~provos/libevent/
+Version: 1.4.13
+License: BSD
+Security Critical: yes
+
+Local Modifications:
+Rather than use libevent's own build system, we just build a Chrome
+static library using GYP.
+
+1) Run configure and "make event-config.h" on Linux, FreeBSD, Solaris,
+   and Mac and copy config.h and event-config.h to linux/, freebsd/,
+   solaris/, and mac/ respectively.
+2) Add libevent.gyp.
+3) chromium.patch is applied to allow libevent to be used without
+   being installed and to fix a race condition.
+4) The directories WIN32-Code and WIN32-Prj are not included.
+5) Apply r87338.
+6) The configs for android were copied from Linux's which were very close to
+   android one with the exception of HAVE_FD_MASK and HAVE_STRLCPY.
+7) Add files to support building with the PNaCl toolchain. Added
+   libevent_nacl_nonsfi.gyp for build rule. nacl_nonsfi/config.h and
+   nacl_nonsfi/event-config.h are derived from linux/ counterparts.
+   nacl_nonsfi/random.c is also added to provide the random() function,
+   which is missing in the newlib-based PNaCl toolchain.
+8) Apply https://github.com/libevent/libevent/commit/ea6b1df
+9) Stub out signal.c for nacl_helper_nonsfi. socketpair() will be prohibited
+   by sandbox in nacl_helper_nonsfi.
diff --git a/third_party/libevent/aclocal.m4 b/third_party/libevent/aclocal.m4
new file mode 100644
index 0000000..4af9376
--- /dev/null
+++ b/third_party/libevent/aclocal.m4
@@ -0,0 +1,7498 @@
+# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(AC_AUTOCONF_VERSION, [2.63],,
+[m4_warning([this file was generated for autoconf 2.63.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+
+# serial 52 AC_PROG_LIBTOOL
+
+
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+         [],
+         [m4_define([AC_PROVIDE_IFELSE],
+	         [m4_ifdef([AC_PROVIDE_$1],
+		           [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
+AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+    [AC_LIBTOOL_CXX],
+    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+  ])])
+dnl And a similar setup for Fortran 77 support
+  AC_PROVIDE_IFELSE([AC_PROG_F77],
+    [AC_LIBTOOL_F77],
+    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+    [AC_LIBTOOL_GCJ],
+    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+      [AC_LIBTOOL_GCJ],
+      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+	[AC_LIBTOOL_GCJ],
+      [ifdef([AC_PROG_GCJ],
+	     [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([A][M_PROG_GCJ],
+	     [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([LT_AC_PROG_GCJ],
+	     [define([LT_AC_PROG_GCJ],
+		defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
+[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Prevent multiple expansion
+define([AC_PROG_LIBTOOL], [])
+])# _AC_PROG_LIBTOOL
+
+
+# AC_LIBTOOL_SETUP
+# ----------------
+AC_DEFUN([AC_LIBTOOL_SETUP],
+[AC_PREREQ(2.50)dnl
+AC_REQUIRE([AC_ENABLE_SHARED])dnl
+AC_REQUIRE([AC_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_LD])dnl
+AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
+AC_REQUIRE([AC_PROG_NM])dnl
+
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
+AC_REQUIRE([AC_OBJEXT])dnl
+AC_REQUIRE([AC_EXEEXT])dnl
+dnl
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+_LT_AC_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(STRIP, strip, :)
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    AC_PATH_MAGIC
+  fi
+  ;;
+esac
+
+_LT_REQUIRED_DARWIN_CHECKS
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
+
+AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+	[avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+AC_ARG_WITH([pic],
+    [AC_HELP_STRING([--with-pic],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
+
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
+
+
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+AC_DEFUN([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+AC_DEFUN([_LT_LINKER_BOILERPLATE],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# --------------------------
+# Check for some things on darwin
+AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+   # By default we will add the -single_module flag. You can override
+   # by either setting the environment variable LT_MULTI_MODULE
+   # non-empty at configure time, or by adding -multi_module to the
+   # link flags.
+   echo "int foo(void){return 1;}" > conftest.c
+   $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+     -dynamiclib ${wl}-single_module conftest.c
+   if test -f libconftest.dylib; then
+     lt_cv_apple_cc_single_mod=yes
+     rm -rf libconftest.dylib*
+   fi
+   rm conftest.c
+      fi])
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+   [lt_cv_ld_exported_symbols_list=yes],
+   [lt_cv_ld_exported_symbols_list=no])
+   LDFLAGS="$save_LDFLAGS"
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[0123]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+     _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*)
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+   10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+     _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+   10.[[012]]*)
+     _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+   10.*)
+     _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms="~$NMEDIT -s \$output_objdir/\${libname}-symbols.expsym \${lib}"
+    fi
+    if test "$DSYMUTIL" != ":"; then
+      _lt_dsymutil="~$DSYMUTIL \$lib || :"
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+	 [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
+
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+  ;;
+esac
+
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X[$]1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+[$]*
+EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$ECHO"; then
+if test "X${echo_test_string+set}" != Xset; then
+# find a string as large as possible, as long as the shell can cope with it
+  for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+    # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+    if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+       echo_test_string=`eval $cmd` &&
+       (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
+    then
+      break
+    fi
+  done
+fi
+
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+   echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+   test "X$echo_testing_string" = "X$echo_test_string"; then
+  :
+else
+  # The Solaris, AIX, and Digital Unix default echo programs unquote
+  # backslashes.  This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  #
+  # So, first we look for a working echo in the user's PATH.
+
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for dir in $PATH /usr/ucb; do
+    IFS="$lt_save_ifs"
+    if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+       test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      echo="$dir/echo"
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  if test "X$echo" = Xecho; then
+    # We didn't find a better echo, so look for alternatives.
+    if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
+       echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
+       test "X$echo_testing_string" = "X$echo_test_string"; then
+      # This shell has a builtin print -r that does the trick.
+      echo='print -r'
+    elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
+	 test "X$CONFIG_SHELL" != X/bin/ksh; then
+      # If we have ksh, try running configure again with it.
+      ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+      export ORIGINAL_CONFIG_SHELL
+      CONFIG_SHELL=/bin/ksh
+      export CONFIG_SHELL
+      exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+    else
+      # Try using printf.
+      echo='printf %s\n'
+      if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
+	 echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
+	 test "X$echo_testing_string" = "X$echo_test_string"; then
+	# Cool, printf works
+	:
+      elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+	   test "X$echo_testing_string" = 'X\t' &&
+	   echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+	export CONFIG_SHELL
+	SHELL="$CONFIG_SHELL"
+	export SHELL
+	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+	   test "X$echo_testing_string" = 'X\t' &&
+	   echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	echo="$CONFIG_SHELL [$]0 --fallback-echo"
+      else
+	# maybe with a smaller string...
+	prev=:
+
+	for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+	  if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
+	  then
+	    break
+	  fi
+	  prev="$cmd"
+	done
+
+	if test "$prev" != 'sed 50q "[$]0"'; then
+	  echo_test_string=`eval $prev`
+	  export echo_test_string
+	  exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+	else
+	  # Oops.  We lost completely, so just stick with echo.
+	  echo=echo
+	fi
+      fi
+    fi
+  fi
+fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+ECHO=$echo
+if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+   ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(ECHO)
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+	[avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *ELF-32*)
+      HPUX_IA64_MODE="32"
+      ;;
+    *ELF-64*)
+      HPUX_IA64_MODE="64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+   if test "$lt_cv_prog_gnu_ld" = yes; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -melf32bsmip"
+      ;;
+    *N32*)
+      LD="${LD-ld} -melf32bmipn32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -melf64bmip"
+      ;;
+    esac
+   else
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+   fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *32-bit*)
+      case $host in
+        x86_64-*kfreebsd*-gnu)
+          LD="${LD-ld} -m elf_i386_fbsd"
+          ;;
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_i386"
+          ;;
+        ppc64-*linux*|powerpc64-*linux*)
+          LD="${LD-ld} -m elf32ppclinux"
+          ;;
+        s390x-*linux*)
+          LD="${LD-ld} -m elf_s390"
+          ;;
+        sparc64-*linux*)
+          LD="${LD-ld} -m elf32_sparc"
+          ;;
+      esac
+      ;;
+    *64-bit*)
+      case $host in
+        x86_64-*kfreebsd*-gnu)
+          LD="${LD-ld} -m elf_x86_64_fbsd"
+          ;;
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        ppc*-*linux*|powerpc*-*linux*)
+          LD="${LD-ld} -m elf64ppc"
+          ;;
+        s390*-*linux*)
+          LD="${LD-ld} -m elf64_s390"
+          ;;
+        sparc*-*linux*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+sparc*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+      *)
+        if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+  ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$5], , :, [$5])
+else
+    ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $rm -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$4], , :, [$4])
+else
+    ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ 	]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+	       = "XX$teststring") >/dev/null 2>&1 &&
+	      new_result=`expr "X$teststring" : ".*" 2>&1` &&
+	      lt_cv_sys_max_cmd_len=$new_result &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on massive
+      # amounts of additional arguments before passing them to the linker.
+      # It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# ------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
+
+# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ---------------------------------------------------------------------
+AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" void exit (int);
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+    exit (status);
+}]
+EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_AC_TRY_DLOPEN_SELF
+
+
+# AC_LIBTOOL_DLOPEN_SELF
+# ----------------------
+AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+   ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+   ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_AC_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+    	  lt_cv_dlopen_self_static, [dnl
+	  _LT_AC_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+])# AC_LIBTOOL_DLOPEN_SELF
+
+
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
+
+
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
+
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
+
+
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
+
+
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+   test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
+
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         old_striplib="$STRIP -S"
+         AC_MSG_RESULT([yes])
+       else
+  AC_MSG_RESULT([no])
+fi
+       ;;
+   *)
+  AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
+
+
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+m4_if($1,[],[
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$lt_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`echo "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    lt_search_path_spec=`echo "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`echo $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  sys_lib_search_path_spec=`echo $lt_search_path_spec`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+  m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) 
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[123]]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ 	]*hwcap[ 	]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+    *)                         need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+    shlibpath_overrides_runpath=no
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    shlibpath_overrides_runpath=yes
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+AC_CACHE_VAL([lt_cv_sys_lib_search_path_spec],
+[lt_cv_sys_lib_search_path_spec="$sys_lib_search_path_spec"])
+sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+AC_CACHE_VAL([lt_cv_sys_lib_dlsearch_path_spec],
+[lt_cv_sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec"])
+sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_ARG_WITH([tags],
+    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+        [include additional configurations @<:@automatic@:>@])],
+    [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+  if test ! -f "${ofile}"; then
+    AC_MSG_WARN([output file `$ofile' does not exist])
+  fi
+
+  if test -z "$LTCC"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+    if test -z "$LTCC"; then
+      AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+    else
+      AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+    fi
+  fi
+  if test -z "$LTCFLAGS"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+  fi
+
+  # Extract list of available tagged configurations in $ofile.
+  # Note that this assumes the entire list is on one line.
+  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+  for tagname in $tagnames; do
+    IFS="$lt_save_ifs"
+    # Check whether tagname contains only valid characters
+    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+    "") ;;
+    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+	;;
+    esac
+
+    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+    then
+      AC_MSG_ERROR([tag name \"$tagname\" already exists])
+    fi
+
+    # Update the list of available tags.
+    if test -n "$tagname"; then
+      echo appending configuration tag \"$tagname\" to $ofile
+
+      case $tagname in
+      CXX)
+	if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+	    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+	    (test "X$CXX" != "Xg++"))) ; then
+	  AC_LIBTOOL_LANG_CXX_CONFIG
+	else
+	  tagname=""
+	fi
+	;;
+
+      F77)
+	if test -n "$F77" && test "X$F77" != "Xno"; then
+	  AC_LIBTOOL_LANG_F77_CONFIG
+	else
+	  tagname=""
+	fi
+	;;
+
+      GCJ)
+	if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+	  AC_LIBTOOL_LANG_GCJ_CONFIG
+	else
+	  tagname=""
+	fi
+	;;
+
+      RC)
+	AC_LIBTOOL_LANG_RC_CONFIG
+	;;
+
+      *)
+	AC_MSG_ERROR([Unsupported tag name: $tagname])
+	;;
+      esac
+
+      # Append the new tag name to the list of available tags.
+      if test -n "$tagname" ; then
+      available_tags="$available_tags $tagname"
+    fi
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  # Now substitute the updated list of available tags.
+  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+    mv "${ofile}T" "$ofile"
+    chmod +x "$ofile"
+  else
+    rm -f "${ofile}T"
+    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+  fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 DLLs
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+# set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognize shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="ifelse([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognize a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+nto-qnx*)
+  lt_cv_deplibs_check_method=unknown
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments.  Note that
+# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+# it is assumed to be `libltdl'.  LIBLTDL will be prefixed with
+# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+# (note the single quotes!).  If your package is not flat and you're not
+# using automake, define top_builddir and top_srcdir appropriately in
+# the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  case $enable_ltdl_convenience in
+  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+  "") enable_ltdl_convenience=yes
+      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+  esac
+  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments.  Note that
+# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+# and an installed libltdl is not found, it is assumed to be `libltdl'.
+# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+# '${top_srcdir}/' (note the single quotes!).  If your package is not
+# flat and you're not using automake, define top_builddir and top_srcdir
+# appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  AC_CHECK_LIB(ltdl, lt_dlinit,
+  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+  [if test x"$enable_ltdl_install" = xno; then
+     AC_MSG_WARN([libltdl not installed, but installation disabled])
+   else
+     enable_ltdl_install=yes
+   fi
+  ])
+  if test x"$enable_ltdl_install" = x"yes"; then
+    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  else
+    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+    LIBLTDL="-lltdl"
+    LTDLINCL=
+  fi
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+# _LT_AC_PROG_CXXCPP
+# ------------------
+AC_DEFUN([_LT_AC_PROG_CXXCPP],
+[
+AC_REQUIRE([AC_PROG_CXX])
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+fi
+])# _LT_AC_PROG_CXXCPP
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+	 [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+	   [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# -------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF
+
+# Report which library types will actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix[[4-9]]*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+    ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_dirs, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+  $as_unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+  lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+  $as_unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+  # Set up default GNU C++ configuration
+
+  AC_PROG_LD
+
+  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+  # archiving commands below assume that GNU ld is being used.
+  if test "$with_gnu_ld" = yes; then
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+    #     investigate it a little bit more. (MM)
+    wlarc='${wl}'
+
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+	grep 'no-whole-archive' > /dev/null; then
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    with_gnu_ld=no
+    wlarc=
+
+    # A generic and very simple default shared library creation
+    # command for GNU C++ for the case where it uses the native
+    # linker, instead of GNU ld.  If possible, this setting should
+    # overridden to take advantage of the native linker features on
+    # the platform it is being used on.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+  fi
+
+  # Commands to make compiler produce verbose output that lists
+  # what "hidden" libraries, object files and flags are used when
+  # linking a shared library.
+  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+  GXX=no
+  with_gnu_ld=no
+  wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+  aix3*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  aix[[4-9]]*)
+    if test "$host_cpu" = ia64; then
+      # On IA64, the linker does run time linking by default, so we don't
+      # have to do anything special.
+      aix_use_runtimelinking=no
+      exp_sym_flag='-Bexport'
+      no_entry_flag=""
+    else
+      aix_use_runtimelinking=no
+
+      # Test if we are trying to use run time linking or normal
+      # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+      # need to do runtime linking.
+      case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	for ld_flag in $LDFLAGS; do
+	  case $ld_flag in
+	  *-brtl*)
+	    aix_use_runtimelinking=yes
+	    break
+	    ;;
+	  esac
+	done
+	;;
+      esac
+
+      exp_sym_flag='-bexport'
+      no_entry_flag='-bnoentry'
+    fi
+
+    # When large executables or shared objects are built, AIX ld can
+    # have problems creating the table of contents.  If linking a library
+    # or program results in "error TOC overflow" add -mminimal-toc to
+    # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+    # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+    _LT_AC_TAGVAR(archive_cmds, $1)=''
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes; then
+      case $host_os in aix4.[[012]]|aix4.[[012]].*)
+      # We only want to do this on AIX 4.2 and lower, the check
+      # below for broken collect2 doesn't work under 4.3+
+	collect2name=`${CC} -print-prog-name=collect2`
+	if test -f "$collect2name" && \
+	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	then
+	  # We have reworked collect2
+	  :
+	else
+	  # We have old collect2
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+	fi
+	;;
+      esac
+      shared_flag='-shared'
+      if test "$aix_use_runtimelinking" = yes; then
+	shared_flag="$shared_flag "'${wl}-G'
+      fi
+    else
+      # not using gcc
+      if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	shared_flag='-G'
+      else
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag='${wl}-G'
+	else
+	  shared_flag='${wl}-bM:SRE'
+	fi
+      fi
+    fi
+
+    # It seems that -bexpall does not export symbols beginning with
+    # underscore (_), so it is better to generate a list of symbols to export.
+    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+    if test "$aix_use_runtimelinking" = yes; then
+      # Warning - without using the other runtime loading flags (-brtl),
+      # -berok will link without error, but may produce a broken library.
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+      # Determine the default libpath from the value encoded in an empty executable.
+      _LT_AC_SYS_LIBPATH_AIX
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+     else
+      if test "$host_cpu" = ia64; then
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+      else
+	# Determine the default libpath from the value encoded in an empty executable.
+	_LT_AC_SYS_LIBPATH_AIX
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	# Warning - without using the other run time loading flags,
+	# -berok will link without error, but may produce a broken library.
+	_LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	# Exported symbols can be pulled into shared objects from archives
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+	# This is similar to how AIX traditionally builds its shared libraries.
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+      fi
+    fi
+    ;;
+
+  beos*)
+    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+      # support --undefined.  This deserves some investigation.  FIXME
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+    ;;
+
+  chorus*)
+    case $cc_basename in
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+
+  cygwin* | mingw* | pw32*)
+    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+    # as there is no search path for DLLs.
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      # If the export-symbols file already is a .def file (1st line
+      # is EXPORTS), use it as is; otherwise, prepend...
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	cp $export_symbols $output_objdir/$soname.def;
+      else
+	echo EXPORTS > $output_objdir/$soname.def;
+	cat $export_symbols >> $output_objdir/$soname.def;
+      fi~
+      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+  ;;
+      darwin* | rhapsody*)
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+      if test "$GXX" = yes ; then
+      output_verbose_link_cmd='echo'
+      _LT_AC_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+      _LT_AC_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+      _LT_AC_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+      if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+        _LT_AC_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+      fi
+      else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
+          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+      fi
+        ;;
+
+  dgux*)
+    case $cc_basename in
+      ec++*)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      ghcx*)
+	# Green Hills C++ Compiler
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  freebsd[[12]]*)
+    # C++ shared libraries reported to be fairly broken before switch to ELF
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  freebsd-elf*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    ;;
+  freebsd* | dragonfly*)
+    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+    # conventions
+    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+    ;;
+  gnu*)
+    ;;
+  hpux9*)
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				# but as the default
+				# location of the library.
+
+    case $cc_basename in
+    CC*)
+      # FIXME: insert proper C++ library support
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    aCC*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      #
+      # There doesn't appear to be a way to prevent this compiler from
+      # explicitly linking system object files so we need to strip them
+      # from the output so that they don't get included in the library
+      # dependencies.
+      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+      ;;
+    *)
+      if test "$GXX" = yes; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+        # FIXME: insert proper C++ library support
+        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+    ;;
+  hpux10*|hpux11*)
+    if test $with_gnu_ld = no; then
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+      case $host_cpu in
+      hppa*64*|ia64*) ;;
+      *)
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        ;;
+      esac
+    fi
+    case $host_cpu in
+    hppa*64*|ia64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+    *)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					      # but as the default
+					      # location of the library.
+      ;;
+    esac
+
+    case $cc_basename in
+      CC*)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      aCC*)
+	case $host_cpu in
+	hppa*64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	  ;;
+	esac
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes; then
+	  if test $with_gnu_ld = no; then
+	    case $host_cpu in
+	    hppa*64*)
+	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      ;;
+	    ia64*)
+	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      ;;
+	    *)
+	      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      ;;
+	    esac
+	  fi
+	else
+	  # FIXME: insert proper C++ library support
+	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+    esac
+    ;;
+  interix[[3-9]]*)
+    _LT_AC_TAGVAR(hardcode_direct, $1)=no
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+    # Instead, shared libraries are loaded at an image base (0x10000000 by
+    # default) and relocated if they conflict, which is a slow very memory
+    # consuming and fragmenting process.  To avoid this, we pick a random,
+    # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+    # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+    ;;
+  irix5* | irix6*)
+    case $cc_basename in
+      CC*)
+	# SGI C++
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	# Archives containing C++ object files must be created using
+	# "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	# necessary to make sure instantiated templates are included
+	# in the archive.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	;;
+      *)
+	if test "$GXX" = yes; then
+	  if test "$with_gnu_ld" = no; then
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	  else
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+	  fi
+	fi
+	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+	;;
+    esac
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    ;;
+  linux* | k*bsd*-gnu)
+    case $cc_basename in
+      KCC*)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	# Archives containing C++ object files must be created using
+	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	;;
+      icpc*)
+	# Intel C++
+	with_gnu_ld=yes
+	# version 8.0 and above of icpc choke on multiply defined symbols
+	# if we add $predep_objects and $postdep_objects, however 7.1 and
+	# earlier do not add the objects themselves.
+	case `$CC -V 2>&1` in
+	*"Version 7."*)
+  	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+  	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  ;;
+	*)  # Version 8.0 or newer
+	  tmp_idyn=
+	  case $host_cpu in
+	    ia64*) tmp_idyn=' -i_dynamic';;
+	  esac
+  	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  ;;
+	esac
+	_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	;;
+      pgCC* | pgcpp*)
+        # Portland Group C++ compiler
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+  	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+        ;;
+      cxx*)
+	# Compaq C++
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	runpath_var=LD_RUN_PATH
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)
+	  # Sun C++ 5.9
+	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+
+	  # Not sure whether something based on
+	  # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	  # would be better.
+	  output_verbose_link_cmd='echo'
+
+	  # Archives containing C++ object files must be created using
+	  # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	  # necessary to make sure instantiated templates are included
+	  # in the archive.
+	  _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	  ;;
+	esac
+	;;
+    esac
+    ;;
+  lynxos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  m88k*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  mvs*)
+    case $cc_basename in
+      cxx*)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    fi
+    # Workaround some broken pre-1.5 toolchains
+    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+    ;;
+  openbsd2*)
+    # C++ shared libraries are fairly broken
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  openbsd*)
+    if test -f /usr/libexec/ld.so; then
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      fi
+      output_verbose_link_cmd='echo'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+    ;;
+  osf3*)
+    case $cc_basename in
+      KCC*)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Archives containing C++ object files must be created using
+	# "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+
+	;;
+      RCC*)
+	# Rational C++ 2.4.1
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      cxx*)
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	  # Commands to make compiler produce verbose output that lists
+	  # what "hidden" libraries, object files and flags are used when
+	  # linking a shared library.
+	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+	else
+	  # FIXME: insert proper C++ library support
+	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+    esac
+    ;;
+  osf4* | osf5*)
+    case $cc_basename in
+      KCC*)
+	# Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	# KCC will only create a shared library if the output file
+	# ends with ".so" (or ".sl" for HP-UX), so rename the library
+	# to its proper name (with version) after linking.
+	_LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Archives containing C++ object files must be created using
+	# the KAI C++ compiler.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+	;;
+      RCC*)
+	# Rational C++ 2.4.1
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      cxx*)
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	  echo "-hidden">> $lib.exp~
+	  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version	$verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+	  $rm $lib.exp'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	# Commands to make compiler produce verbose output that lists
+	# what "hidden" libraries, object files and flags are used when
+	# linking a shared library.
+	#
+	# There doesn't appear to be a way to prevent this compiler from
+	# explicitly linking system object files so we need to strip them
+	# from the output so that they don't get included in the library
+	# dependencies.
+	output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+	;;
+      *)
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	 _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	  # Commands to make compiler produce verbose output that lists
+	  # what "hidden" libraries, object files and flags are used when
+	  # linking a shared library.
+	  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+	else
+	  # FIXME: insert proper C++ library support
+	  _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+    esac
+    ;;
+  psos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  sunos4*)
+    case $cc_basename in
+      CC*)
+	# Sun C++ 4.x
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      lcc*)
+	# Lucid
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  solaris*)
+    case $cc_basename in
+      CC*)
+	# Sun C++ 4.2, 5.x and Centerline C++
+        _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+	_LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	$CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	case $host_os in
+	  solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	  *)
+	    # The compiler driver will combine and reorder linker options,
+	    # but understands `-z linker_flag'.
+	    # Supported since Solaris 2.6 (maybe 2.5.1?)
+	    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	    ;;
+	esac
+	_LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+	output_verbose_link_cmd='echo'
+
+	# Archives containing C++ object files must be created using
+	# "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	# necessary to make sure instantiated templates are included
+	# in the archive.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	;;
+      gcx*)
+	# Green Hills C++ Compiler
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	# The C++ compiler must be used to create the archive.
+	_LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	;;
+      *)
+	# GNU C++ compiler with Solaris linker
+	if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	  if $CC --version | grep -v '^2\.7' > /dev/null; then
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+		$CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+	  else
+	    # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	    # platform.
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+		$CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+	  fi
+
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	  case $host_os in
+	  solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	  *)
+	    _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	    ;;
+	  esac
+	fi
+	;;
+    esac
+    ;;
+  sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    runpath_var='LD_RUN_PATH'
+
+    case $cc_basename in
+      CC*)
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      *)
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+    esac
+    ;;
+  sysv5* | sco3.2v5* | sco5v6*)
+    # Note: We can NOT use -z defs as we might desire, because we do not
+    # link with -lc, and that would cause any symbols used from libc to
+    # always be unresolved, which means just about no library would
+    # ever link correctly.  If we're not using GNU ld we use -z text
+    # though, which does catch some bad symbols but isn't as heavy-handed
+    # as -z defs.
+    # For security reasons, it is highly recommended that you always
+    # use absolute paths for naming shared libraries, and exclude the
+    # DT_RUNPATH tag from executables and libraries.  But doing so
+    # requires that you compile everything twice, which is a pain.
+    # So that behaviour is only enabled if SCOABSPATH is set to a
+    # non-empty value in the environment.  Most likely only useful for
+    # creating official distributions of packages.
+    # This is a hack until libtool officially supports absolute path
+    # names for shared libraries.
+    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+    runpath_var='LD_RUN_PATH'
+
+    case $cc_basename in
+      CC*)
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      *)
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+    esac
+    ;;
+  tandem*)
+    case $cc_basename in
+      NCC*)
+	# NonStop-UX NCC 3.20
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+      *)
+	# FIXME: insert proper C++ library support
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	;;
+    esac
+    ;;
+  vxworks*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  *)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  # The `*' in the case matches for architectures that use `case' in
+  # $output_verbose_cmd can trigger glob expansion during the loop
+  # eval without this substitution.
+  output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
+
+  for p in `eval $output_verbose_link_cmd`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" \
+	  || test $p = "-R"; then
+	 prev=$p
+	 continue
+       else
+	 prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 case $p in
+	 -L* | -R*)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+	   _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+	   _LT_AC_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+	   _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$rm -f confest.$objext
+
+_LT_AC_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+  _LT_AC_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_AC_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+# PORTME: override above test on systems where it is broken
+ifelse([$1],[CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_AC_TAGVAR(predep_objects,$1)=
+  _LT_AC_TAGVAR(postdep_objects,$1)=
+  _LT_AC_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+    #
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_AC_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
+
+# AC_LIBTOOL_LANG_F77_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="\
+      program t
+      end
+"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+aix[[4-9]]*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+  ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# -------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars.  Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
+# libtool distribution, otherwise you forgot to ship ltmain.sh
+# with your package, and you will get complaints that there are
+# no rules to generate ltmain.sh.
+if test -f "$ltmain"; then
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
+  # Now quote all the things that may contain metacharacters while being
+  # careful not to overquote the AC_SUBSTed values.  We take copies of the
+  # variables and quote the copies for generation of the libtool script.
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
+    sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
+    old_postinstall_cmds old_postuninstall_cmds \
+    _LT_AC_TAGVAR(compiler, $1) \
+    _LT_AC_TAGVAR(CC, $1) \
+    _LT_AC_TAGVAR(LD, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+    _LT_AC_TAGVAR(predep_objects, $1) \
+    _LT_AC_TAGVAR(postdep_objects, $1) \
+    _LT_AC_TAGVAR(predeps, $1) \
+    _LT_AC_TAGVAR(postdeps, $1) \
+    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+    _LT_AC_TAGVAR(compiler_lib_search_dirs, $1) \
+    _LT_AC_TAGVAR(archive_cmds, $1) \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+    _LT_AC_TAGVAR(module_cmds, $1) \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+    _LT_AC_TAGVAR(fix_srcfile_path, $1) \
+    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+    _LT_AC_TAGVAR(include_expsyms, $1); do
+
+    case $var in
+    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(module_cmds, $1) | \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
+    postinstall_cmds | postuninstall_cmds | \
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+      # Double-quote double-evaled strings.
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
+      ;;
+    *)
+      eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
+      ;;
+    esac
+  done
+
+  case $lt_echo in
+  *'\[$]0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+    ;;
+  esac
+
+ifelse([$1], [],
+  [cfgfile="${ofile}T"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  $rm -f "$cfgfile"
+  AC_MSG_NOTICE([creating $ofile])],
+  [cfgfile="$ofile"])
+
+  cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="$SED -e 1s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
+
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
+
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# An echo program that does not interpret backslashes.
+echo=$lt_echo
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A C compiler.
+LTCC=$lt_LTCC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
+
+# Is the compiler the GNU C compiler?
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# The linker used to build libraries.
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
+
+# Whether we need hard or soft links.
+LN_S=$lt_LN_S
+
+# A BSD-compatible nm program.
+NM=$lt_NM
+
+# A symbol stripping program
+STRIP=$lt_STRIP
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=$MAGIC_CMD
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="$DLLTOOL"
+
+# Used on cygwin: object dumper.
+OBJDUMP="$OBJDUMP"
+
+# Used on cygwin: assembler.
+AS="$AS"
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# How to pass a linker flag through the compiler.
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+
+# Object file suffix (normally "o").
+objext="$ac_objext"
+
+# Old archive suffix (normally "a").
+libext="$libext"
+
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
+# Executable file suffix (normally "").
+exeext="$exeext"
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The directories searched by this compiler when creating a shared
+# library
+compiler_lib_search_dirs=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_dirs, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+  case $host_os in
+  aix3*)
+    cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" || \
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+])
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([LT_AC_PROG_SED])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  ;;
+linux* | k*bsd*-gnu)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDGIRSTW]]'
+    lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+    lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ 	]]\($symcode$symcode*\)[[ 	]][[ 	]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+	if grep ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
+
+	  cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+	  cat <<\EOF >> conftest.$ac_ext
+  {0, (lt_ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+
+
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+       darwin*)
+         # PIC is the default on this platform
+         # Common symbols not allowed in MH_DYLIB files
+         case $cc_basename in
+           xlc*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           ;;
+         esac
+       ;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  icpc* | ecpc*)
+	    # Intel C++
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler.
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+      darwin*)
+        # PIC is the default on this platform
+        # Common symbols not allowed in MH_DYLIB files
+       case $cc_basename in
+         xlc*)
+         _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         ;;
+       esac
+       ;;
+
+    mingw* | cygwin* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    linux* | k*bsd*-gnu)
+      case $cc_basename in
+      icc* | ecc*)
+	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      pgcc* | pgf77* | pgf90* | pgf95*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      *)
+        case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+	*Sun\ F*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+    _LT_AC_TAGVAR(lt_cv_prog_compiler_pic_works, $1),
+    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_AC_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+])
+
+
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+  _LT_AC_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+],[
+  runpath_var=
+  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_AC_TAGVAR(archive_cmds, $1)=
+  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+  _LT_AC_TAGVAR(module_cmds, $1)=
+  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_AC_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_AC_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+  # Just being paranoid about ensuring that cc_basename is set.
+  _LT_CC_BASENAME([$compiler])
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+  	_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>/dev/null` in
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	cat <<EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+EOF
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    interix[[3-9]]*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | k*bsd*-gnu)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	tmp_addflag=
+	case $cc_basename,$host_cpu in
+	pgcc*)				# Portland Group C compiler
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)		# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	*)
+	  tmp_sharedflag='-shared' ;;
+	esac
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+	if test $supports_anon_versioning = yes; then
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+  cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+  $echo "local: *; };" >> $output_objdir/$libname.ver~
+	  $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	fi
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	cat <<EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+	    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+	    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+	  else
+	    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+  	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+  	    aix_use_runtimelinking=yes
+  	    break
+  	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_AC_TAGVAR(archive_cmds, $1)=''
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" && \
+  	   strings "$collect2name" | grep resolve_lib_name >/dev/null
+	  then
+  	  # We have reworked collect2
+  	  :
+	  else
+  	  # We have old collect2
+  	  _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+  	  # It fails to find uninstalled libraries when the uninstalled
+  	  # path is not listed in the libpath.  Setting hardcode_minus_L
+  	  # to unsupported forces relinking
+  	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+  	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+  	  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+  	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+  	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+	if test "$host_cpu" = ia64; then
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an empty executable.
+	 _LT_AC_SYS_LIBPATH_AIX
+	 _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  # Exported symbols can be pulled into shared objects from archives
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      # see comment about different semantics on the GNU ld section
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    bsdi[[45]]*)
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+      _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    if test "$GCC" = yes ; then
+    	output_verbose_link_cmd='echo'
+        _LT_AC_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+        _LT_AC_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+        _LT_AC_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+        _LT_AC_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $xlcverstring'
+         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $xlcverstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+    fi
+      ;;
+
+    dgux*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    freebsd1*)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	_LT_AC_TAGVAR(hardcode_direct, $1)=yes
+	_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+	  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_AC_TAGVAR(hardcode_direct, $1)=yes
+	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+        fi
+      else
+	_LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+	$LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+	wlarc=''
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+  	$LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+ 	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+      $rm conftest*
+      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+	pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+        then
+	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+        else
+	  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+        fi
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $rm conftest*
+      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+      ;;
+    esac
+  fi
+  ;;
+esac
+])# AC_LIBTOOL_PROG_LD_SHLIBS
+
+
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# #  ifdef __CYGWIN32__
+# #    define __CYGWIN__ __CYGWIN32__
+# #  endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+#   __hDllInstance_base = hInst;
+#   return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
+
+# old names
+AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
+AC_DEFUN([AM_ENABLE_SHARED],  [AC_ENABLE_SHARED($@)])
+AC_DEFUN([AM_ENABLE_STATIC],  [AC_ENABLE_STATIC($@)])
+AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+AC_DEFUN([AM_PROG_LD],        [AC_PROG_LD])
+AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
+
+# This is just to silence aclocal about the macro not being used
+ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+  AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+
+# Cheap backport of AS_EXECUTABLE_P and required macros
+# from Autoconf 2.59; we should not use $as_executable_p directly.
+
+# _AS_TEST_PREPARE
+# ----------------
+m4_ifndef([_AS_TEST_PREPARE],
+[m4_defun([_AS_TEST_PREPARE],
+[if test -x / >/dev/null 2>&1; then
+  as_executable_p='test -x'
+else
+  as_executable_p='test -f'
+fi
+])])# _AS_TEST_PREPARE
+
+# AS_EXECUTABLE_P
+# ---------------
+# Check whether a file is executable.
+m4_ifndef([AS_EXECUTABLE_P],
+[m4_defun([AS_EXECUTABLE_P],
+[AS_REQUIRE([_AS_TEST_PREPARE])dnl
+$as_executable_p $1[]dnl
+])])# AS_EXECUTABLE_P
+
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if AS_EXECUTABLE_P(["$as_dir/$lt_ac_prog$ac_exec_ext"]); then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.10'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.10.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.10.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+	[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], UPC,  [depcc="$UPC"  am_compiler_list=],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    case $depmode in
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    none) break ;;
+    esac
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.
+    if depmode=$depmode \
+       source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+  # Strip MF so we end up with the name of the file.
+  mf=`echo "$mf" | sed -e 's/:.*$//'`
+  # Check whether this is an Automake generated Makefile or not.
+  # We used to match only the files named `Makefile.in', but
+  # some people rename them; so instead we look at the file content.
+  # Grep'ing the first line is not enough: some people post-process
+  # each Makefile.in and add a new line on top of each file to say so.
+  # Grep'ing the whole file is not good either: AIX grep has a line
+  # limit of 2048, but all sed's we know have understand at least 4000.
+  if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+    dirpart=`AS_DIRNAME("$mf")`
+  else
+    continue
+  fi
+  # Extract the definition of DEPDIR, am__include, and am__quote
+  # from the Makefile without running `make'.
+  DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+  test -z "$DEPDIR" && continue
+  am__include=`sed -n 's/^am__include = //p' < "$mf"`
+  test -z "am__include" && continue
+  am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+  # When using ansi2knr, U may be empty or an underscore; expand it
+  U=`sed -n 's/^U = //p' < "$mf"`
+  # Find all dependency output files, they are included files with
+  # $(DEPDIR) in their names.  We invoke sed twice because it is the
+  # simplest approach to changing $(DEPDIR) to its actual value in the
+  # expansion.
+  for file in `sed -n "
+    s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+       sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+    # Make sure the directory exists.
+    test -f "$dirpart/$file" && continue
+    fdir=`AS_DIRNAME(["$file"])`
+    AS_MKDIR_P([$dirpart/$fdir])
+    # echo "creating $dirpart/$file"
+    echo '# dummy' > "$dirpart/$file"
+  done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 13
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.60])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+              [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+	      		     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+                  [_AM_DEPENDENCIES(CC)],
+                  [define([AC_PROG_CC],
+                          defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+                  [_AM_DEPENDENCIES(CXX)],
+                  [define([AC_PROG_CXX],
+                          defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+                  [_AM_DEPENDENCIES(OBJC)],
+                  [define([AC_PROG_OBJC],
+                          defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+   am__include=include
+   am__quote=
+   _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+      am__include=.include
+      am__quote="\""
+      _am_result=BSD
+   fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p.  We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+  [[\\/$]]* | ?:[[\\/]]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+     [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+     [m4_case([$1], [ustar],, [pax],,
+              [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+  case $_am_tool in
+  gnutar)
+    for _am_tar in tar gnutar gtar;
+    do
+      AM_RUN_LOG([$_am_tar --version]) && break
+    done
+    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+    am__untar="$_am_tar -xf -"
+    ;;
+  plaintar)
+    # Must skip GNU tar: if it does not support --format= it doesn't create
+    # ustar tarball either.
+    (tar --version) >/dev/null 2>&1 && continue
+    am__tar='tar chf - "$$tardir"'
+    am__tar_='tar chf - "$tardir"'
+    am__untar='tar xf -'
+    ;;
+  pax)
+    am__tar='pax -L -x $1 -w "$$tardir"'
+    am__tar_='pax -L -x $1 -w "$tardir"'
+    am__untar='pax -r'
+    ;;
+  cpio)
+    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+    am__untar='cpio -i -H $1 -d'
+    ;;
+  none)
+    am__tar=false
+    am__tar_=false
+    am__untar=false
+    ;;
+  esac
+
+  # If the value was cached, stop now.  We just wanted to have am__tar
+  # and am__untar set.
+  test -n "${am_cv_prog_tar_$1}" && break
+
+  # tar/untar a dummy directory, and stop if the command works
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  echo GrepMe > conftest.dir/file
+  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+  rm -rf conftest.dir
+  if test -s conftest.tar; then
+    AM_RUN_LOG([$am__untar <conftest.tar])
+    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+  fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/third_party/libevent/android/config.h b/third_party/libevent/android/config.h
new file mode 100644
index 0000000..91f4dda
--- /dev/null
+++ b/third_party/libevent/android/config.h
@@ -0,0 +1,266 @@
+/* Copied from Linux version and changed the features according Android, which
+ * is close to Linux */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+/* #undef HAVE_FD_MASK */
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/third_party/libevent/android/event-config.h b/third_party/libevent/android/event-config.h
new file mode 100644
index 0000000..7745519
--- /dev/null
+++ b/third_party/libevent/android/event-config.h
@@ -0,0 +1,271 @@
+/* Copied from Linux version and changed the features according Android, which
+ * is close to Linux */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define _EVENT_HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define _EVENT_HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+/* #undef _EVENT_HAVE_FD_MASK 1 */
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef _EVENT_HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define _EVENT_HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/third_party/libevent/autogen.sh b/third_party/libevent/autogen.sh
new file mode 100644
index 0000000..6d4275a
--- /dev/null
+++ b/third_party/libevent/autogen.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+LIBTOOLIZE=libtoolize
+SYSNAME=`uname`
+if [ "x$SYSNAME" = "xDarwin" ] ; then
+  LIBTOOLIZE=glibtoolize
+fi
+aclocal && \
+	autoheader && \
+	$LIBTOOLIZE && \
+	autoconf && \
+	automake --add-missing --copy
diff --git a/third_party/libevent/buffer.c b/third_party/libevent/buffer.c
new file mode 100644
index 0000000..dfaca5d
--- /dev/null
+++ b/third_party/libevent/buffer.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_VASPRINTF
+/* If we have vasprintf, we need to define this before we include stdio.h. */
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "event.h"
+#include "config.h"
+#include "evutil.h"
+
+struct evbuffer *
+evbuffer_new(void)
+{
+	struct evbuffer *buffer;
+	
+	buffer = calloc(1, sizeof(struct evbuffer));
+
+	return (buffer);
+}
+
+void
+evbuffer_free(struct evbuffer *buffer)
+{
+	if (buffer->orig_buffer != NULL)
+		free(buffer->orig_buffer);
+	free(buffer);
+}
+
+/* 
+ * This is a destructive add.  The data from one buffer moves into
+ * the other buffer.
+ */
+
+#define SWAP(x,y) do { \
+	(x)->buffer = (y)->buffer; \
+	(x)->orig_buffer = (y)->orig_buffer; \
+	(x)->misalign = (y)->misalign; \
+	(x)->totallen = (y)->totallen; \
+	(x)->off = (y)->off; \
+} while (0)
+
+int
+evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
+{
+	int res;
+
+	/* Short cut for better performance */
+	if (outbuf->off == 0) {
+		struct evbuffer tmp;
+		size_t oldoff = inbuf->off;
+
+		/* Swap them directly */
+		SWAP(&tmp, outbuf);
+		SWAP(outbuf, inbuf);
+		SWAP(inbuf, &tmp);
+
+		/* 
+		 * Optimization comes with a price; we need to notify the
+		 * buffer if necessary of the changes. oldoff is the amount
+		 * of data that we transfered from inbuf to outbuf
+		 */
+		if (inbuf->off != oldoff && inbuf->cb != NULL)
+			(*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
+		if (oldoff && outbuf->cb != NULL)
+			(*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
+		
+		return (0);
+	}
+
+	res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
+	if (res == 0) {
+		/* We drain the input buffer on success */
+		evbuffer_drain(inbuf, inbuf->off);
+	}
+
+	return (res);
+}
+
+int
+evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
+{
+	char *buffer;
+	size_t space;
+	size_t oldoff = buf->off;
+	int sz;
+	va_list aq;
+
+	/* make sure that at least some space is available */
+	evbuffer_expand(buf, 64);
+	for (;;) {
+		size_t used = buf->misalign + buf->off;
+		buffer = (char *)buf->buffer + buf->off;
+		assert(buf->totallen >= used);
+		space = buf->totallen - used;
+
+#ifndef va_copy
+#define	va_copy(dst, src)	memcpy(&(dst), &(src), sizeof(va_list))
+#endif
+		va_copy(aq, ap);
+
+		sz = evutil_vsnprintf(buffer, space, fmt, aq);
+
+		va_end(aq);
+
+		if (sz < 0)
+			return (-1);
+		if ((size_t)sz < space) {
+			buf->off += sz;
+			if (buf->cb != NULL)
+				(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+			return (sz);
+		}
+		if (evbuffer_expand(buf, sz + 1) == -1)
+			return (-1);
+
+	}
+	/* NOTREACHED */
+}
+
+int
+evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
+{
+	int res = -1;
+	va_list ap;
+
+	va_start(ap, fmt);
+	res = evbuffer_add_vprintf(buf, fmt, ap);
+	va_end(ap);
+
+	return (res);
+}
+
+/* Reads data from an event buffer and drains the bytes read */
+
+int
+evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
+{
+	size_t nread = datlen;
+	if (nread >= buf->off)
+		nread = buf->off;
+
+	memcpy(data, buf->buffer, nread);
+	evbuffer_drain(buf, nread);
+	
+	return (nread);
+}
+
+/*
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the called.
+ */
+
+char *
+evbuffer_readline(struct evbuffer *buffer)
+{
+	u_char *data = EVBUFFER_DATA(buffer);
+	size_t len = EVBUFFER_LENGTH(buffer);
+	char *line;
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		if (data[i] == '\r' || data[i] == '\n')
+			break;
+	}
+
+	if (i == len)
+		return (NULL);
+
+	if ((line = malloc(i + 1)) == NULL) {
+		fprintf(stderr, "%s: out of memory\n", __func__);
+		return (NULL);
+	}
+
+	memcpy(line, data, i);
+	line[i] = '\0';
+
+	/*
+	 * Some protocols terminate a line with '\r\n', so check for
+	 * that, too.
+	 */
+	if ( i < len - 1 ) {
+		char fch = data[i], sch = data[i+1];
+
+		/* Drain one more character if needed */
+		if ( (sch == '\r' || sch == '\n') && sch != fch )
+			i += 1;
+	}
+
+	evbuffer_drain(buffer, i + 1);
+
+	return (line);
+}
+
+/* Adds data to an event buffer */
+
+static void
+evbuffer_align(struct evbuffer *buf)
+{
+	memmove(buf->orig_buffer, buf->buffer, buf->off);
+	buf->buffer = buf->orig_buffer;
+	buf->misalign = 0;
+}
+
+/* Expands the available space in the event buffer to at least datlen */
+
+int
+evbuffer_expand(struct evbuffer *buf, size_t datlen)
+{
+	size_t need = buf->misalign + buf->off + datlen;
+
+	/* If we can fit all the data, then we don't have to do anything */
+	if (buf->totallen >= need)
+		return (0);
+
+	/*
+	 * If the misalignment fulfills our data needs, we just force an
+	 * alignment to happen.  Afterwards, we have enough space.
+	 */
+	if (buf->misalign >= datlen) {
+		evbuffer_align(buf);
+	} else {
+		void *newbuf;
+		size_t length = buf->totallen;
+
+		if (length < 256)
+			length = 256;
+		while (length < need)
+			length <<= 1;
+
+		if (buf->orig_buffer != buf->buffer)
+			evbuffer_align(buf);
+		if ((newbuf = realloc(buf->buffer, length)) == NULL)
+			return (-1);
+
+		buf->orig_buffer = buf->buffer = newbuf;
+		buf->totallen = length;
+	}
+
+	return (0);
+}
+
+int
+evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
+{
+	size_t need = buf->misalign + buf->off + datlen;
+	size_t oldoff = buf->off;
+
+	if (buf->totallen < need) {
+		if (evbuffer_expand(buf, datlen) == -1)
+			return (-1);
+	}
+
+	memcpy(buf->buffer + buf->off, data, datlen);
+	buf->off += datlen;
+
+	if (datlen && buf->cb != NULL)
+		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+
+	return (0);
+}
+
+void
+evbuffer_drain(struct evbuffer *buf, size_t len)
+{
+	size_t oldoff = buf->off;
+
+	if (len >= buf->off) {
+		buf->off = 0;
+		buf->buffer = buf->orig_buffer;
+		buf->misalign = 0;
+		goto done;
+	}
+
+	buf->buffer += len;
+	buf->misalign += len;
+
+	buf->off -= len;
+
+ done:
+	/* Tell someone about changes in this buffer */
+	if (buf->off != oldoff && buf->cb != NULL)
+		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+
+}
+
+/*
+ * Reads data from a file descriptor into a buffer.
+ */
+
+#define EVBUFFER_MAX_READ	4096
+
+int
+evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
+{
+	u_char *p;
+	size_t oldoff = buf->off;
+	int n = EVBUFFER_MAX_READ;
+
+#if defined(FIONREAD)
+#ifdef WIN32
+	long lng = n;
+	if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) <= 0) {
+#else
+	if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
+#endif
+		n = EVBUFFER_MAX_READ;
+	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
+		/*
+		 * It's possible that a lot of data is available for
+		 * reading.  We do not want to exhaust resources
+		 * before the reader has a chance to do something
+		 * about it.  If the reader does not tell us how much
+		 * data we should read, we artifically limit it.
+		 */
+		if ((size_t)n > buf->totallen << 2)
+			n = buf->totallen << 2;
+		if (n < EVBUFFER_MAX_READ)
+			n = EVBUFFER_MAX_READ;
+	}
+#endif	
+	if (howmuch < 0 || howmuch > n)
+		howmuch = n;
+
+	/* If we don't have FIONREAD, we might waste some space here */
+	if (evbuffer_expand(buf, howmuch) == -1)
+		return (-1);
+
+	/* We can append new data at this point */
+	p = buf->buffer + buf->off;
+
+#ifndef WIN32
+	n = read(fd, p, howmuch);
+#else
+	n = recv(fd, p, howmuch, 0);
+#endif
+	if (n == -1)
+		return (-1);
+	if (n == 0)
+		return (0);
+
+	buf->off += n;
+
+	/* Tell someone about changes in this buffer */
+	if (buf->off != oldoff && buf->cb != NULL)
+		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+
+	return (n);
+}
+
+int
+evbuffer_write(struct evbuffer *buffer, int fd)
+{
+	int n;
+
+#ifndef WIN32
+	n = write(fd, buffer->buffer, buffer->off);
+#else
+	n = send(fd, buffer->buffer, buffer->off, 0);
+#endif
+	if (n == -1)
+		return (-1);
+	if (n == 0)
+		return (0);
+	evbuffer_drain(buffer, n);
+
+	return (n);
+}
+
+u_char *
+evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
+{
+	u_char *search = buffer->buffer, *end = search + buffer->off;
+	u_char *p;
+
+	while (search < end &&
+	    (p = memchr(search, *what, end - search)) != NULL) {
+		if (p + len > end)
+			break;
+		if (memcmp(p, what, len) == 0)
+			return (p);
+		search = p + 1;
+	}
+
+	return (NULL);
+}
+
+void evbuffer_setcb(struct evbuffer *buffer,
+    void (*cb)(struct evbuffer *, size_t, size_t, void *),
+    void *cbarg)
+{
+	buffer->cb = cb;
+	buffer->cbarg = cbarg;
+}
diff --git a/third_party/libevent/chromium.patch b/third_party/libevent/chromium.patch
new file mode 100644
index 0000000..08e0122
--- /dev/null
+++ b/third_party/libevent/chromium.patch
@@ -0,0 +1,148 @@
+diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c
+index f07ecc9..da6ea19 100644
+--- a/third_party/libevent/evdns.c
++++ b/third_party/libevent/evdns.c
+@@ -134,7 +134,7 @@
+ typedef ev_uint8_t u_char;
+ typedef unsigned int uint;
+ #endif
+-#include <event.h>
++#include "event.h"
+
+ #define u64 ev_uint64_t
+ #define u32 ev_uint32_t
+diff --git a/third_party/libevent/evdns.h b/third_party/libevent/evdns.h
+index 1eb5c38..fca4ac3 100644
+--- a/third_party/libevent/evdns.h
++++ b/third_party/libevent/evdns.h
+@@ -165,7 +165,7 @@ extern "C" {
+ #endif
+
+ /* For integer types. */
+-#include <evutil.h>
++#include "evutil.h"
+
+ /** Error codes 0-5 are as described in RFC 1035. */
+ #define DNS_ERR_NONE 0
+diff --git a/third_party/libevent/event-config.h b/third_party/libevent/event-config.h
+new file mode 100644
+index 0000000..78a4727
+--- /dev/null
++++ b/third_party/libevent/event-config.h
+@@ -0,0 +1,16 @@
++// 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 Chromium-specific, and brings in the appropriate
++// event-config.h depending on your platform.
++
++#if defined(__APPLE__)
++#include "mac/event-config.h"
++#elif defined(__linux__)
++#include "linux/event-config.h"
++#elif defined(__FreeBSD__)
++#include "freebsd/event-config.h"
++#else
++#error generate event-config.h for your platform
++#endif
+diff --git a/third_party/libevent/event.h b/third_party/libevent/event.h
+index cfa0fc3..72e9b8b 100644
+--- a/third_party/libevent/event.h
++++ b/third_party/libevent/event.h
+@@ -159,7 +159,7 @@
+ extern "C" {
+ #endif
+ 
+-#include <event-config.h>
++#include "event-config.h"
+ #ifdef _EVENT_HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+@@ -172,7 +172,7 @@ extern "C" {
+ #include <stdarg.h>
+ 
+ /* For int types. */
+-#include <evutil.h>
++#include "evutil.h"
+ 
+ #ifdef WIN32
+ #define WIN32_LEAN_AND_MEAN
+diff --git a/third_party/libevent/evutil.h b/third_party/libevent/evutil.h
+index dcb0013..8b664b9 100644
+--- a/third_party/libevent/evutil.h
++++ b/third_party/libevent/evutil.h
+@@ -38,7 +38,7 @@
+ extern "C" {
+ #endif
+ 
+-#include <event-config.h>
++#include "event-config.h"
+ #ifdef _EVENT_HAVE_SYS_TIME_H
+ #include <sys/time.h>
+ #endif
+diff --git a/third_party/libevent/README.chromium b/third_party/libevent/README.chromium
+index 9969566..7e5f8ba 100644
+diff --git a/third_party/libevent/event.c b/third_party/libevent/event.c
+index 1253352..8b6cae5 100644
+--- a/third_party/libevent/event.c
++++ b/third_party/libevent/event.c
+@@ -107,7 +107,7 @@ static const struct eventop *eventops[] = {
+ /* Global state */
+ struct event_base *current_base = NULL;
+ extern struct event_base *evsignal_base;
+-static int use_monotonic;
++static int use_monotonic = 1;
+ 
+ /* Prototypes */
+ static void	event_queue_insert(struct event_base *, struct event *, int);
+@@ -120,17 +120,6 @@ static int	timeout_next(struct event_base *, struct timeval **);
+ static void	timeout_process(struct event_base *);
+ static void	timeout_correct(struct event_base *, struct timeval *);
+ 
+-static void
+-detect_monotonic(void)
+-{
+-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+-	struct timespec	ts;
+-
+-	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+-		use_monotonic = 1;
+-#endif
+-}
+-
+ static int
+ gettime(struct event_base *base, struct timeval *tp)
+ {
+@@ -140,18 +129,18 @@ gettime(struct event_base *base, struct timeval *tp)
+ 	}
+ 
+ #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+-	if (use_monotonic) {
+-		struct timespec	ts;
+-
+-		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+-			return (-1);
++	struct timespec	ts;
+ 
++	if (use_monotonic &&
++	    clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ 		tp->tv_sec = ts.tv_sec;
+ 		tp->tv_usec = ts.tv_nsec / 1000;
+ 		return (0);
+ 	}
+ #endif
+ 
++	use_monotonic = 0;
++
+ 	return (evutil_gettimeofday(tp, NULL));
+ }
+ 
+@@ -175,7 +164,6 @@ event_base_new(void)
+ 	if ((base = calloc(1, sizeof(struct event_base))) == NULL)
+ 		event_err(1, "%s: calloc", __func__);
+ 
+-	detect_monotonic();
+ 	gettime(base, &base->event_tv);
+ 	
+ 	min_heap_ctor(&base->timeheap);
diff --git a/third_party/libevent/compat/sys/_libevent_time.h b/third_party/libevent/compat/sys/_libevent_time.h
new file mode 100644
index 0000000..8cabb0d
--- /dev/null
+++ b/third_party/libevent/compat/sys/_libevent_time.h
@@ -0,0 +1,163 @@
+/*	$OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $	*/
+/*	$NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *	@(#)time.h	8.2 (Berkeley) 7/10/94
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#include <sys/types.h>
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+	long	tv_sec;		/* seconds */
+	long	tv_usec;	/* and microseconds */
+};
+
+/*
+ * Structure defined by POSIX.1b to be like a timeval.
+ */
+struct timespec {
+	time_t	tv_sec;		/* seconds */
+	long	tv_nsec;	/* and nanoseconds */
+};
+
+#define	TIMEVAL_TO_TIMESPEC(tv, ts) {					\
+	(ts)->tv_sec = (tv)->tv_sec;					\
+	(ts)->tv_nsec = (tv)->tv_usec * 1000;				\
+}
+#define	TIMESPEC_TO_TIMEVAL(tv, ts) {					\
+	(tv)->tv_sec = (ts)->tv_sec;					\
+	(tv)->tv_usec = (ts)->tv_nsec / 1000;				\
+}
+
+struct timezone {
+	int	tz_minuteswest;	/* minutes west of Greenwich */
+	int	tz_dsttime;	/* type of dst correction */
+};
+#define	DST_NONE	0	/* not on dst */
+#define	DST_USA		1	/* USA style dst */
+#define	DST_AUST	2	/* Australian style dst */
+#define	DST_WET		3	/* Western European dst */
+#define	DST_MET		4	/* Middle European dst */
+#define	DST_EET		5	/* Eastern European dst */
+#define	DST_CAN		6	/* Canada */
+
+/* Operations on timevals. */
+#define	timerclear(tvp)		(tvp)->tv_sec = (tvp)->tv_usec = 0
+#define	timerisset(tvp)		((tvp)->tv_sec || (tvp)->tv_usec)
+#define	timercmp(tvp, uvp, cmp)						\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
+	    ((tvp)->tv_usec cmp (uvp)->tv_usec) :			\
+	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define	timeradd(tvp, uvp, vvp)						\
+	do {								\
+		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec >= 1000000) {			\
+			(vvp)->tv_sec++;				\
+			(vvp)->tv_usec -= 1000000;			\
+		}							\
+	} while (0)
+#define	timersub(tvp, uvp, vvp)						\
+	do {								\
+		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_usec += 1000000;			\
+		}							\
+	} while (0)
+
+/* Operations on timespecs. */
+#define	timespecclear(tsp)		(tsp)->tv_sec = (tsp)->tv_nsec = 0
+#define	timespecisset(tsp)		((tsp)->tv_sec || (tsp)->tv_nsec)
+#define	timespeccmp(tsp, usp, cmp)					\
+	(((tsp)->tv_sec == (usp)->tv_sec) ?				\
+	    ((tsp)->tv_nsec cmp (usp)->tv_nsec) :			\
+	    ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define	timespecadd(tsp, usp, vsp)					\
+	do {								\
+		(vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec;		\
+		(vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec;	\
+		if ((vsp)->tv_nsec >= 1000000000L) {			\
+			(vsp)->tv_sec++;				\
+			(vsp)->tv_nsec -= 1000000000L;			\
+		}							\
+	} while (0)
+#define	timespecsub(tsp, usp, vsp)					\
+	do {								\
+		(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;		\
+		(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;	\
+		if ((vsp)->tv_nsec < 0) {				\
+			(vsp)->tv_sec--;				\
+			(vsp)->tv_nsec += 1000000000L;			\
+		}							\
+	} while (0)
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define	ITIMER_REAL	0
+#define	ITIMER_VIRTUAL	1
+#define	ITIMER_PROF	2
+
+struct	itimerval {
+	struct	timeval it_interval;	/* timer interval */
+	struct	timeval it_value;	/* current value */
+};
+
+/*
+ * Getkerninfo clock information structure
+ */
+struct clockinfo {
+	int	hz;		/* clock frequency */
+	int	tick;		/* micro-seconds per hz tick */
+	int	tickadj;	/* clock skew rate for adjtime() */
+	int	stathz;		/* statistics clock frequency */
+	int	profhz;		/* profiling clock frequency */
+};
+
+#define CLOCK_REALTIME	0
+#define CLOCK_VIRTUAL	1
+#define CLOCK_PROF	2
+
+#define TIMER_RELTIME	0x0	/* relative timer */
+#define TIMER_ABSTIME	0x1	/* absolute timer */
+
+/* --- stuff got cut here - niels --- */
+
+#endif /* !_SYS_TIME_H_ */
diff --git a/third_party/libevent/compat/sys/_time.h b/third_party/libevent/compat/sys/_time.h
new file mode 100644
index 0000000..8cabb0d
--- /dev/null
+++ b/third_party/libevent/compat/sys/_time.h
@@ -0,0 +1,163 @@
+/*	$OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $	*/
+/*	$NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *	@(#)time.h	8.2 (Berkeley) 7/10/94
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#include <sys/types.h>
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+	long	tv_sec;		/* seconds */
+	long	tv_usec;	/* and microseconds */
+};
+
+/*
+ * Structure defined by POSIX.1b to be like a timeval.
+ */
+struct timespec {
+	time_t	tv_sec;		/* seconds */
+	long	tv_nsec;	/* and nanoseconds */
+};
+
+#define	TIMEVAL_TO_TIMESPEC(tv, ts) {					\
+	(ts)->tv_sec = (tv)->tv_sec;					\
+	(ts)->tv_nsec = (tv)->tv_usec * 1000;				\
+}
+#define	TIMESPEC_TO_TIMEVAL(tv, ts) {					\
+	(tv)->tv_sec = (ts)->tv_sec;					\
+	(tv)->tv_usec = (ts)->tv_nsec / 1000;				\
+}
+
+struct timezone {
+	int	tz_minuteswest;	/* minutes west of Greenwich */
+	int	tz_dsttime;	/* type of dst correction */
+};
+#define	DST_NONE	0	/* not on dst */
+#define	DST_USA		1	/* USA style dst */
+#define	DST_AUST	2	/* Australian style dst */
+#define	DST_WET		3	/* Western European dst */
+#define	DST_MET		4	/* Middle European dst */
+#define	DST_EET		5	/* Eastern European dst */
+#define	DST_CAN		6	/* Canada */
+
+/* Operations on timevals. */
+#define	timerclear(tvp)		(tvp)->tv_sec = (tvp)->tv_usec = 0
+#define	timerisset(tvp)		((tvp)->tv_sec || (tvp)->tv_usec)
+#define	timercmp(tvp, uvp, cmp)						\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
+	    ((tvp)->tv_usec cmp (uvp)->tv_usec) :			\
+	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define	timeradd(tvp, uvp, vvp)						\
+	do {								\
+		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec >= 1000000) {			\
+			(vvp)->tv_sec++;				\
+			(vvp)->tv_usec -= 1000000;			\
+		}							\
+	} while (0)
+#define	timersub(tvp, uvp, vvp)						\
+	do {								\
+		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_usec += 1000000;			\
+		}							\
+	} while (0)
+
+/* Operations on timespecs. */
+#define	timespecclear(tsp)		(tsp)->tv_sec = (tsp)->tv_nsec = 0
+#define	timespecisset(tsp)		((tsp)->tv_sec || (tsp)->tv_nsec)
+#define	timespeccmp(tsp, usp, cmp)					\
+	(((tsp)->tv_sec == (usp)->tv_sec) ?				\
+	    ((tsp)->tv_nsec cmp (usp)->tv_nsec) :			\
+	    ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define	timespecadd(tsp, usp, vsp)					\
+	do {								\
+		(vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec;		\
+		(vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec;	\
+		if ((vsp)->tv_nsec >= 1000000000L) {			\
+			(vsp)->tv_sec++;				\
+			(vsp)->tv_nsec -= 1000000000L;			\
+		}							\
+	} while (0)
+#define	timespecsub(tsp, usp, vsp)					\
+	do {								\
+		(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;		\
+		(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;	\
+		if ((vsp)->tv_nsec < 0) {				\
+			(vsp)->tv_sec--;				\
+			(vsp)->tv_nsec += 1000000000L;			\
+		}							\
+	} while (0)
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define	ITIMER_REAL	0
+#define	ITIMER_VIRTUAL	1
+#define	ITIMER_PROF	2
+
+struct	itimerval {
+	struct	timeval it_interval;	/* timer interval */
+	struct	timeval it_value;	/* current value */
+};
+
+/*
+ * Getkerninfo clock information structure
+ */
+struct clockinfo {
+	int	hz;		/* clock frequency */
+	int	tick;		/* micro-seconds per hz tick */
+	int	tickadj;	/* clock skew rate for adjtime() */
+	int	stathz;		/* statistics clock frequency */
+	int	profhz;		/* profiling clock frequency */
+};
+
+#define CLOCK_REALTIME	0
+#define CLOCK_VIRTUAL	1
+#define CLOCK_PROF	2
+
+#define TIMER_RELTIME	0x0	/* relative timer */
+#define TIMER_ABSTIME	0x1	/* absolute timer */
+
+/* --- stuff got cut here - niels --- */
+
+#endif /* !_SYS_TIME_H_ */
diff --git a/third_party/libevent/compat/sys/queue.h b/third_party/libevent/compat/sys/queue.h
new file mode 100644
index 0000000..c0956dd
--- /dev/null
+++ b/third_party/libevent/compat/sys/queue.h
@@ -0,0 +1,488 @@
+/*	$OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $	*/
+/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/
+
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef	_SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists, 
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+ 
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#ifndef WIN32
+#define SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+#endif
+
+/*
+ * Singly-linked List access methods.
+ */
+#define	SLIST_FIRST(head)	((head)->slh_first)
+#define	SLIST_END(head)		NULL
+#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for((var) = SLIST_FIRST(head);					\
+	    (var) != SLIST_END(head);					\
+	    (var) = SLIST_NEXT(var, field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_INIT(head) {						\
+	SLIST_FIRST(head) = SLIST_END(head);				\
+}
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	(slistelm)->field.sle_next = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.sle_next = (head)->slh_first;			\
+	(head)->slh_first = (elm);					\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	(head)->slh_first = (head)->slh_first->field.sle_next;		\
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List access methods
+ */
+#define	LIST_FIRST(head)		((head)->lh_first)
+#define	LIST_END(head)			NULL
+#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head))
+#define	LIST_NEXT(elm, field)		((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field)					\
+	for((var) = LIST_FIRST(head);					\
+	    (var)!= LIST_END(head);					\
+	    (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST(head) = LIST_END(head);				\
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	(elm)->field.le_next = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &(elm)->field.le_next;		\
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {				\
+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+} while (0)
+
+#define LIST_REMOVE(elm, field) do {					\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev =			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do {				\
+	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
+		(elm2)->field.le_next->field.le_prev =			\
+		    &(elm2)->field.le_next;				\
+	(elm2)->field.le_prev = (elm)->field.le_prev;			\
+	*(elm2)->field.le_prev = (elm2);				\
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *sqh_first;	/* first element */			\
+	struct type **sqh_last;	/* addr of last next element */		\
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type)						\
+struct {								\
+	struct type *sqe_next;	/* next element */			\
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
+#define	SIMPLEQ_END(head)	    NULL
+#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field)				\
+	for((var) = SIMPLEQ_FIRST(head);				\
+	    (var) != SIMPLEQ_END(head);					\
+	    (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define	SIMPLEQ_INIT(head) do {						\
+	(head)->sqh_first = NULL;					\
+	(head)->sqh_last = &(head)->sqh_first;				\
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(head)->sqh_first = (elm);					\
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.sqe_next = NULL;					\
+	*(head)->sqh_last = (elm);					\
+	(head)->sqh_last = &(elm)->field.sqe_next;			\
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+		(head)->sqh_last = &(elm)->field.sqe_next;		\
+	(listelm)->field.sqe_next = (elm);				\
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do {			\
+	if (((head)->sqh_first = (elm)->field.sqe_next) == NULL)	\
+		(head)->sqh_last = &(head)->sqh_first;			\
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/* 
+ * tail queue access methods 
+ */
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_END(head)			NULL
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define	TAILQ_EMPTY(head)						\
+	(TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field)					\
+	for((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, field, headname)		\
+	for((var) = TAILQ_LAST(head, headname);				\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_INIT(head) do {						\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(head)->tqh_first->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
+	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
+		(elm2)->field.tqe_next->field.tqe_prev =		\
+		    &(elm2)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm2)->field.tqe_next;		\
+	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
+	*(elm2)->field.tqe_prev = (elm2);				\
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue access methods 
+ */
+#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
+#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
+#define	CIRCLEQ_END(head)		((void *)(head))
+#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
+#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
+#define	CIRCLEQ_EMPTY(head)						\
+	(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field)				\
+	for((var) = CIRCLEQ_FIRST(head);				\
+	    (var) != CIRCLEQ_END(head);					\
+	    (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for((var) = CIRCLEQ_LAST(head);					\
+	    (var) != CIRCLEQ_END(head);					\
+	    (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_INIT(head) do {						\
+	(head)->cqh_first = CIRCLEQ_END(head);				\
+	(head)->cqh_last = CIRCLEQ_END(head);				\
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == CIRCLEQ_END(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = CIRCLEQ_END(head);			\
+	if ((head)->cqh_last == CIRCLEQ_END(head))			\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	(elm)->field.cqe_next = CIRCLEQ_END(head);			\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == CIRCLEQ_END(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	if ((elm)->field.cqe_next == CIRCLEQ_END(head))			\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == CIRCLEQ_END(head))			\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {			\
+	if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
+	    CIRCLEQ_END(head))						\
+		(head).cqh_last = (elm2);				\
+	else								\
+		(elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
+	if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
+	    CIRCLEQ_END(head))						\
+		(head).cqh_first = (elm2);				\
+	else								\
+		(elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
+} while (0)
+
+#endif	/* !_SYS_QUEUE_H_ */
diff --git a/third_party/libevent/config.guess b/third_party/libevent/config.guess
new file mode 100644
index 0000000..f32079a
--- /dev/null
+++ b/third_party/libevent/config.guess
@@ -0,0 +1,1526 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/third_party/libevent/config.h.in b/third_party/libevent/config.h.in
new file mode 100644
index 0000000..149942c
--- /dev/null
+++ b/third_party/libevent/config.h.in
@@ -0,0 +1,265 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#undef DNS_USE_CPU_CLOCK_FOR_ID
+
+/* Define is no secure id variant is available */
+#undef DNS_USE_GETTIMEOFDAY_FOR_ID
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define if /dev/poll is available */
+#undef HAVE_DEVPOLL
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if your system supports the epoll system calls */
+#undef HAVE_EPOLL
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#undef HAVE_EPOLL_CTL
+
+/* Define if your system supports event ports */
+#undef HAVE_EVENT_PORTS
+
+/* Define to 1 if you have the `fcntl' function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#undef HAVE_FD_MASK
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getegid' function. */
+#undef HAVE_GETEGID
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `issetugid' function. */
+#undef HAVE_ISSETUGID
+
+/* Define to 1 if you have the `kqueue' function. */
+#undef HAVE_KQUEUE
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#undef HAVE_LIBRT
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+#undef HAVE_NETINET_IN6_H
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define to 1 if you have the `port_create' function. */
+#undef HAVE_PORT_CREATE
+
+/* Define to 1 if you have the <port.h> header file. */
+#undef HAVE_PORT_H
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#undef HAVE_SETFD
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `signal' function. */
+#undef HAVE_SIGNAL
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strsep' function. */
+#undef HAVE_STRSEP
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#undef HAVE_STRUCT_IN6_ADDR
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#undef HAVE_SYS_DEVPOLL_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#undef HAVE_SYS_EVENT_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#undef HAVE_SYS_QUEUE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#undef HAVE_TAILQFOREACH
+
+/* Define if timeradd is defined in <sys/time.h> */
+#undef HAVE_TIMERADD
+
+/* Define if timerclear is defined in <sys/time.h> */
+#undef HAVE_TIMERCLEAR
+
+/* Define if timercmp is defined in <sys/time.h> */
+#undef HAVE_TIMERCMP
+
+/* Define if timerisset is defined in <sys/time.h> */
+#undef HAVE_TIMERISSET
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#undef HAVE_UINT16_T
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#undef HAVE_UINT32_T
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#undef HAVE_UINT64_T
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#undef HAVE_UINT8_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define if kqueue works correctly with pipes */
+#undef HAVE_WORKING_KQUEUE
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+#undef __func__
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to unsigned int if you dont have it */
+#undef socklen_t
diff --git a/third_party/libevent/config.sub b/third_party/libevent/config.sub
new file mode 100644
index 0000000..6759825
--- /dev/null
+++ b/third_party/libevent/config.sub
@@ -0,0 +1,1658 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-16'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/third_party/libevent/configure b/third_party/libevent/configure
new file mode 100755
index 0000000..c98d1ff
--- /dev/null
+++ b/third_party/libevent/configure
Binary files differ
diff --git a/third_party/libevent/configure.in b/third_party/libevent/configure.in
new file mode 100644
index 0000000..bf21399
--- /dev/null
+++ b/third_party/libevent/configure.in
@@ -0,0 +1,395 @@
+dnl configure.in for libevent
+dnl Dug Song <dugsong@monkey.org>
+AC_INIT(event.c)
+
+AM_INIT_AUTOMAKE(libevent,1.4.13-stable)
+AM_CONFIG_HEADER(config.h)
+dnl AM_MAINTAINER_MODE
+
+dnl Initialize prefix.
+if test "$prefix" = "NONE"; then
+   prefix="/usr/local"
+fi
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+AC_PROG_GCC_TRADITIONAL
+if test "$GCC" = yes ; then
+        CFLAGS="$CFLAGS -Wall"
+        # And disable the strict-aliasing optimization, since it breaks
+        # our sockaddr-handling code in strange ways.
+        CFLAGS="$CFLAGS -fno-strict-aliasing"
+fi
+
+AC_ARG_ENABLE(gcc-warnings,
+     AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings with GCC))
+
+AC_PROG_LIBTOOL
+
+dnl   Uncomment "AC_DISABLE_SHARED" to make shared librraries not get
+dnl   built by default.  You can also turn shared libs on and off from 
+dnl   the command line with --enable-shared and --disable-shared.
+dnl AC_DISABLE_SHARED
+AC_SUBST(LIBTOOL_DEPS)
+
+dnl Checks for libraries.
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(resolv, inet_aton)
+AC_CHECK_LIB(rt, clock_gettime)
+AC_CHECK_LIB(nsl, inet_ntoa)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h)
+if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
+	AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/queue.h>
+#ifdef TAILQ_FOREACH
+ yes
+#endif
+],	[AC_MSG_RESULT(yes)
+	 AC_DEFINE(HAVE_TAILQFOREACH, 1,
+		[Define if TAILQ_FOREACH is defined in <sys/queue.h>])],
+	AC_MSG_RESULT(no)
+	)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timeradd in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timeradd
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERADD, 1,
+		[Define if timeradd is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timercmp in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timercmp
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERCMP, 1,
+		[Define if timercmp is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timerclear in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerclear
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERCLEAR, 1,
+		[Define if timerclear is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timerisset in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerisset
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERISSET, 1,
+		[Define if timerisset is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+dnl - check if the macro WIN32 is defined on this compiler.
+dnl - (this is how we check for a windows version of GCC)
+AC_MSG_CHECKING(for WIN32)
+AC_TRY_COMPILE(,
+	[
+#ifndef WIN32
+die horribly
+#endif
+	],
+	bwin32=true; AC_MSG_RESULT(yes),
+	bwin32=false; AC_MSG_RESULT(no),
+)
+
+AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop signal sigaction strtoll issetugid geteuid getegid)
+
+AC_CHECK_SIZEOF(long)
+
+if test "x$ac_cv_func_clock_gettime" = "xyes"; then
+   AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc])
+else
+   AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available])
+fi
+
+AC_MSG_CHECKING(for F_SETFD in fcntl.h)
+AC_EGREP_CPP(yes,
+[
+#define _GNU_SOURCE
+#include <fcntl.h>
+#ifdef F_SETFD
+yes
+#endif
+],	[ AC_DEFINE(HAVE_SETFD, 1,
+	      [Define if F_SETFD is defined in <fcntl.h>])
+	  AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no))
+
+needsignal=no
+haveselect=no
+AC_CHECK_FUNCS(select, [haveselect=yes], )
+if test "x$haveselect" = "xyes" ; then
+	AC_LIBOBJ(select)
+	needsignal=yes
+fi
+
+havepoll=no
+AC_CHECK_FUNCS(poll, [havepoll=yes], )
+if test "x$havepoll" = "xyes" ; then
+	AC_LIBOBJ(poll)
+	needsignal=yes
+fi
+
+haveepoll=no
+AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], )
+if test "x$haveepoll" = "xyes" ; then
+	AC_DEFINE(HAVE_EPOLL, 1,
+		[Define if your system supports the epoll system calls])
+	AC_LIBOBJ(epoll)
+	needsignal=yes
+fi
+
+havedevpoll=no
+if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
+	AC_DEFINE(HAVE_DEVPOLL, 1,
+		    [Define if /dev/poll is available])
+        AC_LIBOBJ(devpoll)
+fi
+
+havekqueue=no
+if test "x$ac_cv_header_sys_event_h" = "xyes"; then
+	AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
+	if test "x$havekqueue" = "xyes" ; then
+		AC_MSG_CHECKING(for working kqueue)
+		AC_TRY_RUN(
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(int argc, char **argv)
+{
+	int kq;
+	int n;
+	int fd[[2]];
+	struct kevent ev;
+	struct timespec ts;
+	char buf[[8000]];
+
+	if (pipe(fd) == -1)
+		exit(1);
+	if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
+		exit(1);
+
+	while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
+		;
+
+        if ((kq = kqueue()) == -1)
+		exit(1);
+
+	ev.ident = fd[[1]];
+	ev.filter = EVFILT_WRITE;
+	ev.flags = EV_ADD | EV_ENABLE;
+	n = kevent(kq, &ev, 1, NULL, 0, NULL);
+	if (n == -1)
+		exit(1);
+	
+	read(fd[[0]], buf, sizeof(buf));
+
+	ts.tv_sec = 0;
+	ts.tv_nsec = 0;
+	n = kevent(kq, NULL, 0, &ev, 1, &ts);
+	if (n == -1 || n == 0)
+		exit(1);
+
+	exit(0);
+}, [AC_MSG_RESULT(yes)
+    AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
+		[Define if kqueue works correctly with pipes])
+    AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+	fi
+fi
+
+haveepollsyscall=no
+if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+	if test "x$haveepoll" = "xno" ; then
+		AC_MSG_CHECKING(for epoll system call)
+		AC_TRY_RUN(
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+	return (syscall(__NR_epoll_create, size));
+}
+
+int
+main(int argc, char **argv)
+{
+	int epfd;
+
+	epfd = epoll_create(256);
+	exit (epfd == -1 ? 1 : 0);
+}, [AC_MSG_RESULT(yes)
+    AC_DEFINE(HAVE_EPOLL, 1,
+	[Define if your system supports the epoll system calls])
+    needsignal=yes
+    AC_LIBOBJ(epoll_sub)
+    AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+	fi
+fi
+
+haveeventports=no
+AC_CHECK_FUNCS(port_create, [haveeventports=yes], )
+if test "x$haveeventports" = "xyes" ; then
+	AC_DEFINE(HAVE_EVENT_PORTS, 1,
+		[Define if your system supports event ports])
+	AC_LIBOBJ(evport)
+	needsignal=yes
+fi
+if test "x$bwin32" = "xtrue"; then
+	needsignal=yes
+fi
+if test "x$bwin32" = "xtrue"; then
+	needsignal=yes
+fi
+if test "x$needsignal" = "xyes" ; then
+	AC_LIBOBJ(signal)
+fi
+
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_t], , ,
+[#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif])
+AC_CHECK_TYPES([fd_mask], , ,
+[#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SELECT_H
+#include <select.h>
+#endif])
+
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_TYPES([struct in6_addr], , ,
+[#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif])
+
+AC_MSG_CHECKING([for socklen_t])
+AC_TRY_COMPILE([
+ #include <sys/types.h>
+ #include <sys/socket.h>],
+  [socklen_t x;],
+  AC_MSG_RESULT([yes]),
+  [AC_MSG_RESULT([no])
+  AC_DEFINE(socklen_t, unsigned int,
+	[Define to unsigned int if you dont have it])]
+)
+
+AC_MSG_CHECKING([whether our compiler supports __func__])
+AC_TRY_COMPILE([],
+ [ const char *cp = __func__; ],
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no])
+ AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
+ AC_TRY_COMPILE([],
+   [ const char *cp = __FUNCTION__; ],
+   AC_MSG_RESULT([yes])
+   AC_DEFINE(__func__, __FUNCTION__,
+         [Define to appropriate substitue if compiler doesnt have __func__]),
+   AC_MSG_RESULT([no])
+   AC_DEFINE(__func__, __FILE__,
+         [Define to appropriate substitue if compiler doesnt have __func__])))
+
+
+# Add some more warnings which we use in development but not in the
+# released versions.  (Some relevant gcc versions can't handle these.)
+if test x$enable_gcc_warnings = xyes; then
+
+  AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4)
+#error
+#endif]), have_gcc4=yes, have_gcc4=no)
+
+  AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
+#error
+#endif]), have_gcc42=yes, have_gcc42=no)
+
+  CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat=2 -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum -Werror"
+  CFLAGS="$CFLAGS -Wno-unused-parameter -Wno-sign-compare -Wstrict-aliasing"
+
+  if test x$have_gcc4 = xyes ; then 
+    # These warnings break gcc 3.3.5 and work on gcc 4.0.2
+    CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement"
+    #CFLAGS="$CFLAGS -Wold-style-definition"
+  fi
+
+  if test x$have_gcc42 = xyes ; then 
+    # These warnings break gcc 4.0.2 and work on gcc 4.2
+    CFLAGS="$CFLAGS -Waddress -Wnormalized=id -Woverride-init"
+  fi
+
+##This will break the world on some 64-bit architectures
+# CFLAGS="$CFLAGS -Winline"
+
+fi
+
+AC_OUTPUT(Makefile test/Makefile sample/Makefile)
diff --git a/third_party/libevent/devpoll.c b/third_party/libevent/devpoll.c
new file mode 100644
index 0000000..2d34ae3
--- /dev/null
+++ b/third_party/libevent/devpoll.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/devpoll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+/* due to limitations in the devpoll interface, we need to keep track of
+ * all file descriptors outself.
+ */
+struct evdevpoll {
+	struct event *evread;
+	struct event *evwrite;
+};
+
+struct devpollop {
+	struct evdevpoll *fds;
+	int nfds;
+	struct pollfd *events;
+	int nevents;
+	int dpfd;
+	struct pollfd *changes;
+	int nchanges;
+};
+
+static void *devpoll_init	(struct event_base *);
+static int devpoll_add	(void *, struct event *);
+static int devpoll_del	(void *, struct event *);
+static int devpoll_dispatch	(struct event_base *, void *, struct timeval *);
+static void devpoll_dealloc	(struct event_base *, void *);
+
+const struct eventop devpollops = {
+	"devpoll",
+	devpoll_init,
+	devpoll_add,
+	devpoll_del,
+	devpoll_dispatch,
+	devpoll_dealloc,
+	1 /* need reinit */
+};
+
+#define NEVENT	32000
+
+static int
+devpoll_commit(struct devpollop *devpollop)
+{
+	/*
+	 * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
+	 * Write is limited to 2GB of data, until it will fail.
+	 */
+	if (pwrite(devpollop->dpfd, devpollop->changes,
+		sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
+		return(-1);
+
+	devpollop->nchanges = 0;
+	return(0);
+}
+
+static int
+devpoll_queue(struct devpollop *devpollop, int fd, int events) {
+	struct pollfd *pfd;
+
+	if (devpollop->nchanges >= devpollop->nevents) {
+		/*
+		 * Change buffer is full, must commit it to /dev/poll before 
+		 * adding more 
+		 */
+		if (devpoll_commit(devpollop) != 0)
+			return(-1);
+	}
+
+	pfd = &devpollop->changes[devpollop->nchanges++];
+	pfd->fd = fd;
+	pfd->events = events;
+	pfd->revents = 0;
+
+	return(0);
+}
+
+static void *
+devpoll_init(struct event_base *base)
+{
+	int dpfd, nfiles = NEVENT;
+	struct rlimit rl;
+	struct devpollop *devpollop;
+
+	/* Disable devpoll when this environment variable is set */
+	if (evutil_getenv("EVENT_NODEVPOLL"))
+		return (NULL);
+
+	if (!(devpollop = calloc(1, sizeof(struct devpollop))))
+		return (NULL);
+
+	if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
+	    rl.rlim_cur != RLIM_INFINITY)
+		nfiles = rl.rlim_cur;
+
+	/* Initialize the kernel queue */
+	if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
+                event_warn("open: /dev/poll");
+		free(devpollop);
+		return (NULL);
+	}
+
+	devpollop->dpfd = dpfd;
+
+	/* Initialize fields */
+	devpollop->events = calloc(nfiles, sizeof(struct pollfd));
+	if (devpollop->events == NULL) {
+		free(devpollop);
+		close(dpfd);
+		return (NULL);
+	}
+	devpollop->nevents = nfiles;
+
+	devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
+	if (devpollop->fds == NULL) {
+		free(devpollop->events);
+		free(devpollop);
+		close(dpfd);
+		return (NULL);
+	}
+	devpollop->nfds = nfiles;
+
+	devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
+	if (devpollop->changes == NULL) {
+		free(devpollop->fds);
+		free(devpollop->events);
+		free(devpollop);
+		close(dpfd);
+		return (NULL);
+	}
+
+	evsignal_init(base);
+
+	return (devpollop);
+}
+
+static int
+devpoll_recalc(struct event_base *base, void *arg, int max)
+{
+	struct devpollop *devpollop = arg;
+
+	if (max >= devpollop->nfds) {
+		struct evdevpoll *fds;
+		int nfds;
+
+		nfds = devpollop->nfds;
+		while (nfds <= max)
+			nfds <<= 1;
+
+		fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
+		if (fds == NULL) {
+			event_warn("realloc");
+			return (-1);
+		}
+		devpollop->fds = fds;
+		memset(fds + devpollop->nfds, 0,
+		    (nfds - devpollop->nfds) * sizeof(struct evdevpoll));
+		devpollop->nfds = nfds;
+	}
+
+	return (0);
+}
+
+static int
+devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	struct devpollop *devpollop = arg;
+	struct pollfd *events = devpollop->events;
+	struct dvpoll dvp;
+	struct evdevpoll *evdp;
+	int i, res, timeout = -1;
+
+	if (devpollop->nchanges)
+		devpoll_commit(devpollop);
+
+	if (tv != NULL)
+		timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+	dvp.dp_fds = devpollop->events;
+	dvp.dp_nfds = devpollop->nevents;
+	dvp.dp_timeout = timeout;
+
+	res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
+
+	if (res == -1) {
+		if (errno != EINTR) {
+			event_warn("ioctl: DP_POLL");
+			return (-1);
+		}
+
+		evsignal_process(base);
+		return (0);
+	} else if (base->sig.evsignal_caught) {
+		evsignal_process(base);
+	}
+
+	event_debug(("%s: devpoll_wait reports %d", __func__, res));
+
+	for (i = 0; i < res; i++) {
+		int which = 0;
+		int what = events[i].revents;
+		struct event *evread = NULL, *evwrite = NULL;
+
+		assert(events[i].fd < devpollop->nfds);
+		evdp = &devpollop->fds[events[i].fd];
+   
+                if (what & POLLHUP)
+                        what |= POLLIN | POLLOUT;
+                else if (what & POLLERR)
+                        what |= POLLIN | POLLOUT;
+
+		if (what & POLLIN) {
+			evread = evdp->evread;
+			which |= EV_READ;
+		}
+
+		if (what & POLLOUT) {
+			evwrite = evdp->evwrite;
+			which |= EV_WRITE;
+		}
+
+		if (!which)
+			continue;
+
+		if (evread != NULL && !(evread->ev_events & EV_PERSIST))
+			event_del(evread);
+		if (evwrite != NULL && evwrite != evread &&
+		    !(evwrite->ev_events & EV_PERSIST))
+			event_del(evwrite);
+
+		if (evread != NULL)
+			event_active(evread, EV_READ, 1);
+		if (evwrite != NULL)
+			event_active(evwrite, EV_WRITE, 1);
+	}
+
+	return (0);
+}
+
+
+static int
+devpoll_add(void *arg, struct event *ev)
+{
+	struct devpollop *devpollop = arg;
+	struct evdevpoll *evdp;
+	int fd, events;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_add(ev));
+
+	fd = ev->ev_fd;
+	if (fd >= devpollop->nfds) {
+		/* Extend the file descriptor array as necessary */
+		if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
+			return (-1);
+	}
+	evdp = &devpollop->fds[fd];
+
+	/* 
+	 * It's not necessary to OR the existing read/write events that we
+	 * are currently interested in with the new event we are adding.
+	 * The /dev/poll driver ORs any new events with the existing events
+	 * that it has cached for the fd.
+	 */
+
+	events = 0;
+	if (ev->ev_events & EV_READ) {
+		if (evdp->evread && evdp->evread != ev) {
+		   /* There is already a different read event registered */
+		   return(-1);
+		}
+		events |= POLLIN;
+	}
+
+	if (ev->ev_events & EV_WRITE) {
+		if (evdp->evwrite && evdp->evwrite != ev) {
+		   /* There is already a different write event registered */
+		   return(-1);
+		}
+		events |= POLLOUT;
+	}
+
+	if (devpoll_queue(devpollop, fd, events) != 0)
+		return(-1);
+
+	/* Update events responsible */
+	if (ev->ev_events & EV_READ)
+		evdp->evread = ev;
+	if (ev->ev_events & EV_WRITE)
+		evdp->evwrite = ev;
+
+	return (0);
+}
+
+static int
+devpoll_del(void *arg, struct event *ev)
+{
+	struct devpollop *devpollop = arg;
+	struct evdevpoll *evdp;
+	int fd, events;
+	int needwritedelete = 1, needreaddelete = 1;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_del(ev));
+
+	fd = ev->ev_fd;
+	if (fd >= devpollop->nfds)
+		return (0);
+	evdp = &devpollop->fds[fd];
+
+	events = 0;
+	if (ev->ev_events & EV_READ)
+		events |= POLLIN;
+	if (ev->ev_events & EV_WRITE)
+		events |= POLLOUT;
+
+	/*
+	 * The only way to remove an fd from the /dev/poll monitored set is
+	 * to use POLLREMOVE by itself.  This removes ALL events for the fd 
+	 * provided so if we care about two events and are only removing one 
+	 * we must re-add the other event after POLLREMOVE.
+	 */
+
+	if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
+		return(-1);
+
+	if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
+		/*
+		 * We're not deleting all events, so we must resubmit the
+		 * event that we are still interested in if one exists.
+		 */
+
+		if ((events & POLLIN) && evdp->evwrite != NULL) {
+			/* Deleting read, still care about write */
+			devpoll_queue(devpollop, fd, POLLOUT);
+			needwritedelete = 0;
+		} else if ((events & POLLOUT) && evdp->evread != NULL) {
+			/* Deleting write, still care about read */
+			devpoll_queue(devpollop, fd, POLLIN);
+			needreaddelete = 0;
+		}
+	}
+
+	if (needreaddelete)
+		evdp->evread = NULL;
+	if (needwritedelete)
+		evdp->evwrite = NULL;
+
+	return (0);
+}
+
+static void
+devpoll_dealloc(struct event_base *base, void *arg)
+{
+	struct devpollop *devpollop = arg;
+
+	evsignal_dealloc(base);
+	if (devpollop->fds)
+		free(devpollop->fds);
+	if (devpollop->events)
+		free(devpollop->events);
+	if (devpollop->changes)
+		free(devpollop->changes);
+	if (devpollop->dpfd >= 0)
+		close(devpollop->dpfd);
+
+	memset(devpollop, 0, sizeof(struct devpollop));
+	free(devpollop);
+}
diff --git a/third_party/libevent/epoll.c b/third_party/libevent/epoll.c
new file mode 100644
index 0000000..4387ef8
--- /dev/null
+++ b/third_party/libevent/epoll.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+/* due to limitations in the epoll interface, we need to keep track of
+ * all file descriptors outself.
+ */
+struct evepoll {
+	struct event *evread;
+	struct event *evwrite;
+};
+
+struct epollop {
+	struct evepoll *fds;
+	int nfds;
+	struct epoll_event *events;
+	int nevents;
+	int epfd;
+};
+
+static void *epoll_init	(struct event_base *);
+static int epoll_add	(void *, struct event *);
+static int epoll_del	(void *, struct event *);
+static int epoll_dispatch	(struct event_base *, void *, struct timeval *);
+static void epoll_dealloc	(struct event_base *, void *);
+
+const struct eventop epollops = {
+	"epoll",
+	epoll_init,
+	epoll_add,
+	epoll_del,
+	epoll_dispatch,
+	epoll_dealloc,
+	1 /* need reinit */
+};
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+        if (fcntl(x, F_SETFD, 1) == -1) \
+                event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
+#else
+#define FD_CLOSEONEXEC(x)
+#endif
+
+/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
+ * values bigger than (LONG_MAX - 999ULL)/HZ.  HZ in the wild can be
+ * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
+ * largest number of msec we can support here is 2147482.  Let's
+ * round that down by 47 seconds.
+ */
+#define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
+
+#define INITIAL_NFILES 32
+#define INITIAL_NEVENTS 32
+#define MAX_NEVENTS 4096
+
+static void *
+epoll_init(struct event_base *base)
+{
+	int epfd;
+	struct epollop *epollop;
+
+	/* Disable epollueue when this environment variable is set */
+	if (evutil_getenv("EVENT_NOEPOLL"))
+		return (NULL);
+
+	/* Initalize the kernel queue */
+	if ((epfd = epoll_create(32000)) == -1) {
+		if (errno != ENOSYS)
+			event_warn("epoll_create");
+		return (NULL);
+	}
+
+	FD_CLOSEONEXEC(epfd);
+
+	if (!(epollop = calloc(1, sizeof(struct epollop))))
+		return (NULL);
+
+	epollop->epfd = epfd;
+
+	/* Initalize fields */
+	epollop->events = malloc(INITIAL_NEVENTS * sizeof(struct epoll_event));
+	if (epollop->events == NULL) {
+		free(epollop);
+		return (NULL);
+	}
+	epollop->nevents = INITIAL_NEVENTS;
+
+	epollop->fds = calloc(INITIAL_NFILES, sizeof(struct evepoll));
+	if (epollop->fds == NULL) {
+		free(epollop->events);
+		free(epollop);
+		return (NULL);
+	}
+	epollop->nfds = INITIAL_NFILES;
+
+	evsignal_init(base);
+
+	return (epollop);
+}
+
+static int
+epoll_recalc(struct event_base *base, void *arg, int max)
+{
+	struct epollop *epollop = arg;
+
+	if (max >= epollop->nfds) {
+		struct evepoll *fds;
+		int nfds;
+
+		nfds = epollop->nfds;
+		while (nfds <= max)
+			nfds <<= 1;
+
+		fds = realloc(epollop->fds, nfds * sizeof(struct evepoll));
+		if (fds == NULL) {
+			event_warn("realloc");
+			return (-1);
+		}
+		epollop->fds = fds;
+		memset(fds + epollop->nfds, 0,
+		    (nfds - epollop->nfds) * sizeof(struct evepoll));
+		epollop->nfds = nfds;
+	}
+
+	return (0);
+}
+
+static int
+epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	struct epollop *epollop = arg;
+	struct epoll_event *events = epollop->events;
+	struct evepoll *evep;
+	int i, res, timeout = -1;
+
+	if (tv != NULL)
+		timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+	if (timeout > MAX_EPOLL_TIMEOUT_MSEC) {
+		/* Linux kernels can wait forever if the timeout is too big;
+		 * see comment on MAX_EPOLL_TIMEOUT_MSEC. */
+		timeout = MAX_EPOLL_TIMEOUT_MSEC;
+	}
+
+	res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
+
+	if (res == -1) {
+		if (errno != EINTR) {
+			event_warn("epoll_wait");
+			return (-1);
+		}
+
+		evsignal_process(base);
+		return (0);
+	} else if (base->sig.evsignal_caught) {
+		evsignal_process(base);
+	}
+
+	event_debug(("%s: epoll_wait reports %d", __func__, res));
+
+	for (i = 0; i < res; i++) {
+		int what = events[i].events;
+		struct event *evread = NULL, *evwrite = NULL;
+		int fd = events[i].data.fd;
+
+		if (fd < 0 || fd >= epollop->nfds)
+			continue;
+		evep = &epollop->fds[fd];
+
+		if (what & (EPOLLHUP|EPOLLERR)) {
+			evread = evep->evread;
+			evwrite = evep->evwrite;
+		} else {
+			if (what & EPOLLIN) {
+				evread = evep->evread;
+			}
+
+			if (what & EPOLLOUT) {
+				evwrite = evep->evwrite;
+			}
+		}
+
+		if (!(evread||evwrite))
+			continue;
+
+		if (evread != NULL)
+			event_active(evread, EV_READ, 1);
+		if (evwrite != NULL)
+			event_active(evwrite, EV_WRITE, 1);
+	}
+
+	if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {
+		/* We used all of the event space this time.  We should
+		   be ready for more events next time. */
+		int new_nevents = epollop->nevents * 2;
+		struct epoll_event *new_events;
+
+		new_events = realloc(epollop->events,
+		    new_nevents * sizeof(struct epoll_event));
+		if (new_events) {
+			epollop->events = new_events;
+			epollop->nevents = new_nevents;
+		}
+	}
+
+	return (0);
+}
+
+
+static int
+epoll_add(void *arg, struct event *ev)
+{
+	struct epollop *epollop = arg;
+	struct epoll_event epev = {0, {0}};
+	struct evepoll *evep;
+	int fd, op, events;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_add(ev));
+
+	fd = ev->ev_fd;
+	if (fd >= epollop->nfds) {
+		/* Extent the file descriptor array as necessary */
+		if (epoll_recalc(ev->ev_base, epollop, fd) == -1)
+			return (-1);
+	}
+	evep = &epollop->fds[fd];
+	op = EPOLL_CTL_ADD;
+	events = 0;
+	if (evep->evread != NULL) {
+		events |= EPOLLIN;
+		op = EPOLL_CTL_MOD;
+	}
+	if (evep->evwrite != NULL) {
+		events |= EPOLLOUT;
+		op = EPOLL_CTL_MOD;
+	}
+
+	if (ev->ev_events & EV_READ)
+		events |= EPOLLIN;
+	if (ev->ev_events & EV_WRITE)
+		events |= EPOLLOUT;
+
+	epev.data.fd = fd;
+	epev.events = events;
+	if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
+			return (-1);
+
+	/* Update events responsible */
+	if (ev->ev_events & EV_READ)
+		evep->evread = ev;
+	if (ev->ev_events & EV_WRITE)
+		evep->evwrite = ev;
+
+	return (0);
+}
+
+static int
+epoll_del(void *arg, struct event *ev)
+{
+	struct epollop *epollop = arg;
+	struct epoll_event epev = {0, {0}};
+	struct evepoll *evep;
+	int fd, events, op;
+	int needwritedelete = 1, needreaddelete = 1;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_del(ev));
+
+	fd = ev->ev_fd;
+	if (fd >= epollop->nfds)
+		return (0);
+	evep = &epollop->fds[fd];
+
+	op = EPOLL_CTL_DEL;
+	events = 0;
+
+	if (ev->ev_events & EV_READ)
+		events |= EPOLLIN;
+	if (ev->ev_events & EV_WRITE)
+		events |= EPOLLOUT;
+
+	if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) {
+		if ((events & EPOLLIN) && evep->evwrite != NULL) {
+			needwritedelete = 0;
+			events = EPOLLOUT;
+			op = EPOLL_CTL_MOD;
+		} else if ((events & EPOLLOUT) && evep->evread != NULL) {
+			needreaddelete = 0;
+			events = EPOLLIN;
+			op = EPOLL_CTL_MOD;
+		}
+	}
+
+	epev.events = events;
+	epev.data.fd = fd;
+
+	if (needreaddelete)
+		evep->evread = NULL;
+	if (needwritedelete)
+		evep->evwrite = NULL;
+
+	if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1)
+		return (-1);
+
+	return (0);
+}
+
+static void
+epoll_dealloc(struct event_base *base, void *arg)
+{
+	struct epollop *epollop = arg;
+
+	evsignal_dealloc(base);
+	if (epollop->fds)
+		free(epollop->fds);
+	if (epollop->events)
+		free(epollop->events);
+	if (epollop->epfd >= 0)
+		close(epollop->epfd);
+
+	memset(epollop, 0, sizeof(struct epollop));
+	free(epollop);
+}
diff --git a/third_party/libevent/epoll_sub.c b/third_party/libevent/epoll_sub.c
new file mode 100644
index 0000000..431970c
--- /dev/null
+++ b/third_party/libevent/epoll_sub.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdint.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+	return (syscall(__NR_epoll_create, size));
+}
+
+int
+epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+{
+
+	return (syscall(__NR_epoll_ctl, epfd, op, fd, event));
+}
+
+int
+epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
+{
+	return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout));
+}
diff --git a/third_party/libevent/evbuffer.c b/third_party/libevent/evbuffer.c
new file mode 100644
index 0000000..f2179a5
--- /dev/null
+++ b/third_party/libevent/evbuffer.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "evutil.h"
+#include "event.h"
+
+/* prototypes */
+
+void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
+
+static int
+bufferevent_add(struct event *ev, int timeout)
+{
+	struct timeval tv, *ptv = NULL;
+
+	if (timeout) {
+		evutil_timerclear(&tv);
+		tv.tv_sec = timeout;
+		ptv = &tv;
+	}
+
+	return (event_add(ev, ptv));
+}
+
+/* 
+ * This callback is executed when the size of the input buffer changes.
+ * We use it to apply back pressure on the reading side.
+ */
+
+void
+bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now,
+    void *arg) {
+	struct bufferevent *bufev = arg;
+	/* 
+	 * If we are below the watermark then reschedule reading if it's
+	 * still enabled.
+	 */
+	if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
+		evbuffer_setcb(buf, NULL, NULL);
+
+		if (bufev->enabled & EV_READ)
+			bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+	}
+}
+
+static void
+bufferevent_readcb(int fd, short event, void *arg)
+{
+	struct bufferevent *bufev = arg;
+	int res = 0;
+	short what = EVBUFFER_READ;
+	size_t len;
+	int howmuch = -1;
+
+	if (event == EV_TIMEOUT) {
+		what |= EVBUFFER_TIMEOUT;
+		goto error;
+	}
+
+	/*
+	 * If we have a high watermark configured then we don't want to
+	 * read more data than would make us reach the watermark.
+	 */
+	if (bufev->wm_read.high != 0) {
+		howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
+		/* we might have lowered the watermark, stop reading */
+		if (howmuch <= 0) {
+			struct evbuffer *buf = bufev->input;
+			event_del(&bufev->ev_read);
+			evbuffer_setcb(buf,
+			    bufferevent_read_pressure_cb, bufev);
+			return;
+		}
+	}
+
+	res = evbuffer_read(bufev->input, fd, howmuch);
+	if (res == -1) {
+		if (errno == EAGAIN || errno == EINTR)
+			goto reschedule;
+		/* error case */
+		what |= EVBUFFER_ERROR;
+	} else if (res == 0) {
+		/* eof case */
+		what |= EVBUFFER_EOF;
+	}
+
+	if (res <= 0)
+		goto error;
+
+	bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+
+	/* See if this callbacks meets the water marks */
+	len = EVBUFFER_LENGTH(bufev->input);
+	if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
+		return;
+	if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
+		struct evbuffer *buf = bufev->input;
+		event_del(&bufev->ev_read);
+
+		/* Now schedule a callback for us when the buffer changes */
+		evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
+	}
+
+	/* Invoke the user callback - must always be called last */
+	if (bufev->readcb != NULL)
+		(*bufev->readcb)(bufev, bufev->cbarg);
+	return;
+
+ reschedule:
+	bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+	return;
+
+ error:
+	(*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+static void
+bufferevent_writecb(int fd, short event, void *arg)
+{
+	struct bufferevent *bufev = arg;
+	int res = 0;
+	short what = EVBUFFER_WRITE;
+
+	if (event == EV_TIMEOUT) {
+		what |= EVBUFFER_TIMEOUT;
+		goto error;
+	}
+
+	if (EVBUFFER_LENGTH(bufev->output)) {
+	    res = evbuffer_write(bufev->output, fd);
+	    if (res == -1) {
+#ifndef WIN32
+/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
+ *set errno. thus this error checking is not portable*/
+		    if (errno == EAGAIN ||
+			errno == EINTR ||
+			errno == EINPROGRESS)
+			    goto reschedule;
+		    /* error case */
+		    what |= EVBUFFER_ERROR;
+
+#else
+				goto reschedule;
+#endif
+
+	    } else if (res == 0) {
+		    /* eof case */
+		    what |= EVBUFFER_EOF;
+	    }
+	    if (res <= 0)
+		    goto error;
+	}
+
+	if (EVBUFFER_LENGTH(bufev->output) != 0)
+		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+
+	/*
+	 * Invoke the user callback if our buffer is drained or below the
+	 * low watermark.
+	 */
+	if (bufev->writecb != NULL &&
+	    EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
+		(*bufev->writecb)(bufev, bufev->cbarg);
+
+	return;
+
+ reschedule:
+	if (EVBUFFER_LENGTH(bufev->output) != 0)
+		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+	return;
+
+ error:
+	(*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+/*
+ * Create a new buffered event object.
+ *
+ * The read callback is invoked whenever we read new data.
+ * The write callback is invoked whenever the output buffer is drained.
+ * The error callback is invoked on a write/read error or on EOF.
+ *
+ * Both read and write callbacks maybe NULL.  The error callback is not
+ * allowed to be NULL and have to be provided always.
+ */
+
+struct bufferevent *
+bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
+    everrorcb errorcb, void *cbarg)
+{
+	struct bufferevent *bufev;
+
+	if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
+		return (NULL);
+
+	if ((bufev->input = evbuffer_new()) == NULL) {
+		free(bufev);
+		return (NULL);
+	}
+
+	if ((bufev->output = evbuffer_new()) == NULL) {
+		evbuffer_free(bufev->input);
+		free(bufev);
+		return (NULL);
+	}
+
+	event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
+	event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
+
+	bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);
+
+	/*
+	 * Set to EV_WRITE so that using bufferevent_write is going to
+	 * trigger a callback.  Reading needs to be explicitly enabled
+	 * because otherwise no data will be available.
+	 */
+	bufev->enabled = EV_WRITE;
+
+	return (bufev);
+}
+
+void
+bufferevent_setcb(struct bufferevent *bufev,
+    evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg)
+{
+	bufev->readcb = readcb;
+	bufev->writecb = writecb;
+	bufev->errorcb = errorcb;
+
+	bufev->cbarg = cbarg;
+}
+
+void
+bufferevent_setfd(struct bufferevent *bufev, int fd)
+{
+	event_del(&bufev->ev_read);
+	event_del(&bufev->ev_write);
+
+	event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
+	event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
+	if (bufev->ev_base != NULL) {
+		event_base_set(bufev->ev_base, &bufev->ev_read);
+		event_base_set(bufev->ev_base, &bufev->ev_write);
+	}
+
+	/* might have to manually trigger event registration */
+}
+
+int
+bufferevent_priority_set(struct bufferevent *bufev, int priority)
+{
+	if (event_priority_set(&bufev->ev_read, priority) == -1)
+		return (-1);
+	if (event_priority_set(&bufev->ev_write, priority) == -1)
+		return (-1);
+
+	return (0);
+}
+
+/* Closing the file descriptor is the responsibility of the caller */
+
+void
+bufferevent_free(struct bufferevent *bufev)
+{
+	event_del(&bufev->ev_read);
+	event_del(&bufev->ev_write);
+
+	evbuffer_free(bufev->input);
+	evbuffer_free(bufev->output);
+
+	free(bufev);
+}
+
+/*
+ * Returns 0 on success;
+ *        -1 on failure.
+ */
+
+int
+bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
+{
+	int res;
+
+	res = evbuffer_add(bufev->output, data, size);
+
+	if (res == -1)
+		return (res);
+
+	/* If everything is okay, we need to schedule a write */
+	if (size > 0 && (bufev->enabled & EV_WRITE))
+		bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+
+	return (res);
+}
+
+int
+bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
+{
+	int res;
+
+	res = bufferevent_write(bufev, buf->buffer, buf->off);
+	if (res != -1)
+		evbuffer_drain(buf, buf->off);
+
+	return (res);
+}
+
+size_t
+bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
+{
+	struct evbuffer *buf = bufev->input;
+
+	if (buf->off < size)
+		size = buf->off;
+
+	/* Copy the available data to the user buffer */
+	memcpy(data, buf->buffer, size);
+
+	if (size)
+		evbuffer_drain(buf, size);
+
+	return (size);
+}
+
+int
+bufferevent_enable(struct bufferevent *bufev, short event)
+{
+	if (event & EV_READ) {
+		if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
+			return (-1);
+	}
+	if (event & EV_WRITE) {
+		if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
+			return (-1);
+	}
+
+	bufev->enabled |= event;
+	return (0);
+}
+
+int
+bufferevent_disable(struct bufferevent *bufev, short event)
+{
+	if (event & EV_READ) {
+		if (event_del(&bufev->ev_read) == -1)
+			return (-1);
+	}
+	if (event & EV_WRITE) {
+		if (event_del(&bufev->ev_write) == -1)
+			return (-1);
+	}
+
+	bufev->enabled &= ~event;
+	return (0);
+}
+
+/*
+ * Sets the read and write timeout for a buffered event.
+ */
+
+void
+bufferevent_settimeout(struct bufferevent *bufev,
+    int timeout_read, int timeout_write) {
+	bufev->timeout_read = timeout_read;
+	bufev->timeout_write = timeout_write;
+
+	if (event_pending(&bufev->ev_read, EV_READ, NULL))
+		bufferevent_add(&bufev->ev_read, timeout_read);
+	if (event_pending(&bufev->ev_write, EV_WRITE, NULL))
+		bufferevent_add(&bufev->ev_write, timeout_write);
+}
+
+/*
+ * Sets the water marks
+ */
+
+void
+bufferevent_setwatermark(struct bufferevent *bufev, short events,
+    size_t lowmark, size_t highmark)
+{
+	if (events & EV_READ) {
+		bufev->wm_read.low = lowmark;
+		bufev->wm_read.high = highmark;
+	}
+
+	if (events & EV_WRITE) {
+		bufev->wm_write.low = lowmark;
+		bufev->wm_write.high = highmark;
+	}
+
+	/* If the watermarks changed then see if we should call read again */
+	bufferevent_read_pressure_cb(bufev->input,
+	    0, EVBUFFER_LENGTH(bufev->input), bufev);
+}
+
+int
+bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
+{
+	int res;
+
+	bufev->ev_base = base;
+
+	res = event_base_set(base, &bufev->ev_read);
+	if (res == -1)
+		return (res);
+
+	res = event_base_set(base, &bufev->ev_write);
+	return (res);
+}
diff --git a/third_party/libevent/evdns.3 b/third_party/libevent/evdns.3
new file mode 100644
index 0000000..10414fa
--- /dev/null
+++ b/third_party/libevent/evdns.3
@@ -0,0 +1,322 @@
+.\"
+.\" Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 7, 2006
+.Dt EVDNS 3
+.Os
+.Sh NAME
+.Nm evdns_init
+.Nm evdns_shutdown
+.Nm evdns_err_to_string
+.Nm evdns_nameserver_add
+.Nm evdns_count_nameservers
+.Nm evdns_clear_nameservers_and_suspend
+.Nm evdns_resume
+.Nm evdns_nameserver_ip_add
+.Nm evdns_resolve_ipv4
+.Nm evdns_resolve_reverse
+.Nm evdns_resolv_conf_parse
+.Nm evdns_config_windows_nameservers
+.Nm evdns_search_clear
+.Nm evdns_search_add
+.Nm evdns_search_ndots_set
+.Nm evdns_set_log_fn
+.Nd asynchronous functions for DNS resolution.
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Fd #include <evdns.h>
+.Ft int
+.Fn evdns_init
+.Ft void
+.Fn evdns_shutdown "int fail_requests"
+.Ft "const char *"
+.Fn evdns_err_to_string "int err"
+.Ft int
+.Fn evdns_nameserver_add "unsigned long int address"
+.Ft int
+.Fn evdns_count_nameservers
+.Ft int
+.Fn evdns_clear_nameservers_and_suspend
+.Ft int
+.Fn evdns_resume
+.Ft int
+.Fn evdns_nameserver_ip_add(const char *ip_as_string);
+.Ft int
+.Fn evdns_resolve_ipv4 "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
+.Ft int
+.Fn evdns_resolve_reverse "struct in_addr *in" "int flags" "evdns_callback_type callback" "void *ptr"
+.Ft int
+.Fn evdns_resolv_conf_parse "int flags" "const char *"
+.Ft void
+.Fn evdns_search_clear
+.Ft void
+.Fn evdns_search_add "const char *domain"
+.Ft void
+.Fn evdns_search_ndots_set "const int ndots"
+.Ft void
+.Fn evdns_set_log_fn "evdns_debug_log_fn_type fn"
+.Ft int
+.Fn evdns_config_windows_nameservers
+.Sh DESCRIPTION
+Welcome, gentle reader
+.Pp
+Async DNS lookups are really a whole lot harder than they should be,
+mostly stemming from the fact that the libc resolver has never been
+very good at them. Before you use this library you should see if libc
+can do the job for you with the modern async call getaddrinfo_a
+(see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+please continue.
+.Pp
+This code is based on libevent and you must call event_init before
+any of the APIs in this file. You must also seed the OpenSSL random
+source if you are using OpenSSL for ids (see below).
+.Pp
+This library is designed to be included and shipped with your source
+code. You statically link with it. You should also test for the
+existence of strtok_r and define HAVE_STRTOK_R if you have it.
+.Pp
+The DNS protocol requires a good source of id numbers and these
+numbers should be unpredictable for spoofing reasons. There are
+three methods for generating them here and you must define exactly
+one of them. In increasing order of preference:
+.Pp
+.Bl -tag -width "DNS_USE_GETTIMEOFDAY_FOR_ID" -compact -offset indent
+.It DNS_USE_GETTIMEOFDAY_FOR_ID
+Using the bottom 16 bits of the usec result from gettimeofday. This
+is a pretty poor solution but should work anywhere.
+.It DNS_USE_CPU_CLOCK_FOR_ID
+Using the bottom 16 bits of the nsec result from the CPU's time
+counter. This is better, but may not work everywhere. Requires
+POSIX realtime support and you'll need to link against -lrt on
+glibc systems at least.
+.It DNS_USE_OPENSSL_FOR_ID
+Uses the OpenSSL RAND_bytes call to generate the data. You must
+have seeded the pool before making any calls to this library.
+.El
+.Pp
+The library keeps track of the state of nameservers and will avoid
+them when they go down. Otherwise it will round robin between them.
+.Pp
+Quick start guide:
+  #include "evdns.h"
+  void callback(int result, char type, int count, int ttl,
+	 void *addresses, void *arg);
+  evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+  evdns_resolve("www.hostname.com", 0, callback, NULL);
+.Pp
+When the lookup is complete the callback function is called. The
+first argument will be one of the DNS_ERR_* defines in evdns.h.
+Hopefully it will be DNS_ERR_NONE, in which case type will be
+DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+which the data can be cached for (in seconds), addresses will point
+to an array of uint32_t's and arg will be whatever you passed to
+evdns_resolve.
+.Pp
+Searching:
+.Pp
+In order for this library to be a good replacement for glibc's resolver it
+supports searching. This involves setting a list of default domains, in
+which names will be queried for. The number of dots in the query name
+determines the order in which this list is used.
+.Pp
+Searching appears to be a single lookup from the point of view of the API,
+although many DNS queries may be generated from a single call to
+evdns_resolve. Searching can also drastically slow down the resolution
+of names.
+.Pp
+To disable searching:
+.Bl -enum -compact -offset indent
+.It
+Never set it up. If you never call
+.Fn evdns_resolv_conf_parse,
+.Fn evdns_init,
+or
+.Fn evdns_search_add
+then no searching will occur.
+.It
+If you do call
+.Fn evdns_resolv_conf_parse
+then don't pass
+.Va DNS_OPTION_SEARCH
+(or
+.Va DNS_OPTIONS_ALL,
+which implies it).
+.It
+When calling
+.Fn evdns_resolve,
+pass the
+.Va DNS_QUERY_NO_SEARCH
+flag.
+.El
+.Pp
+The order of searches depends on the number of dots in the name. If the
+number is greater than the ndots setting then the names is first tried
+globally. Otherwise each search domain is appended in turn.
+.Pp
+The ndots setting can either be set from a resolv.conf, or by calling
+evdns_search_ndots_set.
+.Pp
+For example, with ndots set to 1 (the default) and a search domain list of
+["myhome.net"]:
+ Query: www
+ Order: www.myhome.net, www.
+.Pp
+ Query: www.abc
+ Order: www.abc., www.abc.myhome.net
+.Pp
+.Sh API reference
+.Pp
+.Bl -tag -width 0123456
+.It Ft int Fn evdns_init
+Initializes support for non-blocking name resolution by calling
+.Fn evdns_resolv_conf_parse
+on UNIX and
+.Fn evdns_config_windows_nameservers
+on Windows.
+.It Ft int Fn evdns_nameserver_add "unsigned long int address"
+Add a nameserver. The address should be an IP address in
+network byte order. The type of address is chosen so that
+it matches in_addr.s_addr.
+Returns non-zero on error.
+.It Ft int Fn evdns_nameserver_ip_add "const char *ip_as_string"
+This wraps the above function by parsing a string as an IP
+address and adds it as a nameserver.
+Returns non-zero on error
+.It Ft int Fn evdns_resolve "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
+Resolve a name. The name parameter should be a DNS name.
+The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
+which disables searching for this query. (see defn of
+searching above).
+.Pp
+The callback argument is a function which is called when
+this query completes and ptr is an argument which is passed
+to that callback function.
+.Pp
+Returns non-zero on error
+.It Ft void Fn evdns_search_clear
+Clears the list of search domains
+.It Ft void Fn evdns_search_add "const char *domain"
+Add a domain to the list of search domains
+.It Ft void Fn evdns_search_ndots_set "int ndots"
+Set the number of dots which, when found in a name, causes
+the first query to be without any search domain.
+.It Ft int Fn evdns_count_nameservers "void"
+Return the number of configured nameservers (not necessarily the
+number of running nameservers).  This is useful for double-checking
+whether our calls to the various nameserver configuration functions
+have been successful.
+.It Ft int Fn evdns_clear_nameservers_and_suspend "void"
+Remove all currently configured nameservers, and suspend all pending
+resolves.  Resolves will not necessarily be re-attempted until
+evdns_resume() is called.
+.It Ft int Fn evdns_resume "void"
+Re-attempt resolves left in limbo after an earlier call to
+evdns_clear_nameservers_and_suspend().
+.It Ft int Fn evdns_config_windows_nameservers "void"
+Attempt to configure a set of nameservers based on platform settings on
+a win32 host.  Preferentially tries to use GetNetworkParams; if that fails,
+looks in the registry.  Returns 0 on success, nonzero on failure.
+.It Ft int Fn evdns_resolv_conf_parse "int flags" "const char *filename"
+Parse a resolv.conf like file from the given filename.
+.Pp
+See the man page for resolv.conf for the format of this file.
+The flags argument determines what information is parsed from
+this file:
+.Bl -tag -width "DNS_OPTION_NAMESERVERS" -offset indent -compact -nested
+.It DNS_OPTION_SEARCH
+domain, search and ndots options
+.It DNS_OPTION_NAMESERVERS
+nameserver lines
+.It DNS_OPTION_MISC
+timeout and attempts options
+.It DNS_OPTIONS_ALL
+all of the above
+.El
+.Pp
+The following directives are not parsed from the file:
+  sortlist, rotate, no-check-names, inet6, debug
+.Pp
+Returns non-zero on error:
+.Bl -tag -width "0" -offset indent -compact -nested
+.It 0
+no errors
+.It 1
+failed to open file
+.It 2
+failed to stat file
+.It 3
+file too large
+.It 4
+out of memory
+.It 5
+short read from file
+.El
+.El
+.Sh Internals:
+Requests are kept in two queues. The first is the inflight queue. In
+this queue requests have an allocated transaction id and nameserver.
+They will soon be transmitted if they haven't already been.
+.Pp
+The second is the waiting queue. The size of the inflight ring is
+limited and all other requests wait in waiting queue for space. This
+bounds the number of concurrent requests so that we don't flood the
+nameserver. Several algorithms require a full walk of the inflight
+queue and so bounding its size keeps thing going nicely under huge
+(many thousands of requests) loads.
+.Pp
+If a nameserver loses too many requests it is considered down and we
+try not to use it. After a while we send a probe to that nameserver
+(a lookup for google.com) and, if it replies, we consider it working
+again. If the nameserver fails a probe we wait longer to try again
+with the next probe.
+.Sh SEE ALSO
+.Xr event 3 ,
+.Xr gethostbyname 3 ,
+.Xr resolv.conf 5
+.Sh HISTORY
+The
+.Nm evdns
+API was developed by Adam Langley on top of the
+.Nm libevent
+API.
+The code was integrate into
+.Nm Tor
+by Nick Mathewson and finally put into
+.Nm libevent
+itself by Niels Provos.
+.Sh AUTHORS
+The
+.Nm evdns
+API and code was written by Adam Langley with significant
+contributions by Nick Mathewson.
+.Sh BUGS
+This documentation is neither complete nor authoritative.
+If you are in doubt about the usage of this API then
+check the source code to find out how it works, write
+up the missing piece of documentation and send it to
+me for inclusion in this man page.
diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c
new file mode 100644
index 0000000..6fa971c
--- /dev/null
+++ b/third_party/libevent/evdns.c
@@ -0,0 +1,3190 @@
+/* $Id: evdns.c 6979 2006-08-04 18:31:13Z nickm $ */
+
+/* The original version of this module was written by Adam Langley; for
+ * a history of modifications, check out the subversion logs.
+ *
+ * When editing this module, try to keep it re-mergeable by Adam.  Don't
+ * reformat the whitespace, add Tor dependencies, or so on.
+ *
+ * TODO:
+ *   - Support IPv6 and PTR records.
+ *   - Replace all externally visible magic numbers with #defined constants.
+ *   - Write doccumentation for APIs of all external functions.
+ */
+
+/* Async DNS Library
+ * Adam Langley <agl@imperialviolet.org>
+ * http://www.imperialviolet.org/eventdns.html
+ * Public Domain code
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * 	Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ *
+ * Version: 0.1b
+ */
+
+#include <sys/types.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DNS_USE_FTIME_FOR_ID
+#include <sys/timeb.h>
+#endif
+
+#ifndef DNS_USE_CPU_CLOCK_FOR_ID
+#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
+#ifndef DNS_USE_OPENSSL_FOR_ID
+#ifndef DNS_USE_FTIME_FOR_ID
+#error Must configure at least one id generation method.
+#error Please see the documentation.
+#endif
+#endif
+#endif
+#endif
+
+/* #define _POSIX_C_SOURCE 200507 */
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#error Multiple id options selected
+#endif
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <time.h>
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <openssl/rand.h>
+#endif
+
+#ifndef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 3
+#endif
+
+#include <string.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "evdns.h"
+#include "evutil.h"
+#include "log.h"
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <iphlpapi.h>
+#include <io.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#define EVDNS_LOG_DEBUG 0
+#define EVDNS_LOG_WARN 1
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#include <stdio.h>
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#ifdef __USE_ISOC99B
+/* libevent doesn't work without this */
+typedef ev_uint8_t u_char;
+typedef unsigned int uint;
+#endif
+#include "event.h"
+
+#define u64 ev_uint64_t
+#define u32 ev_uint32_t
+#define u16 ev_uint16_t
+#define u8  ev_uint8_t
+
+#ifdef WIN32
+#define open _open
+#define read _read
+#define close _close
+#define strdup _strdup
+#endif
+
+#define MAX_ADDRS 32  /* maximum number of addresses from a single packet */
+/* which we bother recording */
+
+#define TYPE_A         EVDNS_TYPE_A
+#define TYPE_CNAME     5
+#define TYPE_PTR       EVDNS_TYPE_PTR
+#define TYPE_AAAA      EVDNS_TYPE_AAAA
+
+#define CLASS_INET     EVDNS_CLASS_INET
+
+struct request {
+	u8 *request;  /* the dns packet data */
+	unsigned int request_len;
+	int reissue_count;
+	int tx_count;  /* the number of times that this packet has been sent */
+	unsigned int request_type; /* TYPE_PTR or TYPE_A */
+	void *user_pointer;  /* the pointer given to us for this request */
+	evdns_callback_type user_callback;
+	struct nameserver *ns;  /* the server which we last sent it */
+
+	/* elements used by the searching code */
+	int search_index;
+	struct search_state *search_state;
+	char *search_origname;  /* needs to be free()ed */
+	int search_flags;
+
+	/* these objects are kept in a circular list */
+	struct request *next, *prev;
+
+	struct event timeout_event;
+
+	u16 trans_id;  /* the transaction id */
+	char request_appended;  /* true if the request pointer is data which follows this struct */
+	char transmit_me;  /* needs to be transmitted */
+};
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+	u8 s6_addr[16];
+};
+#endif
+
+struct reply {
+	unsigned int type;
+	unsigned int have_answer;
+	union {
+		struct {
+			u32 addrcount;
+			u32 addresses[MAX_ADDRS];
+		} a;
+		struct {
+			u32 addrcount;
+			struct in6_addr addresses[MAX_ADDRS];
+		} aaaa;
+		struct {
+			char name[HOST_NAME_MAX];
+		} ptr;
+	} data;
+};
+
+struct nameserver {
+	int socket;  /* a connected UDP socket */
+	u32 address;
+	u16 port;
+	int failed_times;  /* number of times which we have given this server a chance */
+	int timedout;  /* number of times in a row a request has timed out */
+	struct event event;
+	/* these objects are kept in a circular list */
+	struct nameserver *next, *prev;
+	struct event timeout_event;  /* used to keep the timeout for */
+				     /* when we next probe this server. */
+				     /* Valid if state == 0 */
+	char state;  /* zero if we think that this server is down */
+	char choked;  /* true if we have an EAGAIN from this server's socket */
+	char write_waiting;  /* true if we are waiting for EV_WRITE events */
+};
+
+static struct request *req_head = NULL, *req_waiting_head = NULL;
+static struct nameserver *server_head = NULL;
+
+/* Represents a local port where we're listening for DNS requests. Right now, */
+/* only UDP is supported. */
+struct evdns_server_port {
+	int socket; /* socket we use to read queries and write replies. */
+	int refcnt; /* reference count. */
+	char choked; /* Are we currently blocked from writing? */
+	char closing; /* Are we trying to close this port, pending writes? */
+	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
+	void *user_data; /* Opaque pointer passed to user_callback */
+	struct event event; /* Read/write event */
+	/* circular list of replies that we want to write. */
+	struct server_request *pending_replies;
+};
+
+/* Represents part of a reply being built.	(That is, a single RR.) */
+struct server_reply_item {
+	struct server_reply_item *next; /* next item in sequence. */
+	char *name; /* name part of the RR */
+	u16 type : 16; /* The RR type */
+	u16 class : 16; /* The RR class (usually CLASS_INET) */
+	u32 ttl; /* The RR TTL */
+	char is_name; /* True iff data is a label */
+	u16 datalen; /* Length of data; -1 if data is a label */
+	void *data; /* The contents of the RR */
+};
+
+/* Represents a request that we've received as a DNS server, and holds */
+/* the components of the reply as we're constructing it. */
+struct server_request {
+	/* Pointers to the next and previous entries on the list of replies */
+	/* that we're waiting to write.	 Only set if we have tried to respond */
+	/* and gotten EAGAIN. */
+	struct server_request *next_pending;
+	struct server_request *prev_pending;
+
+	u16 trans_id; /* Transaction id. */
+	struct evdns_server_port *port; /* Which port received this request on? */
+	struct sockaddr_storage addr; /* Where to send the response */
+	socklen_t addrlen; /* length of addr */
+
+	int n_answer; /* how many answer RRs have been set? */
+	int n_authority; /* how many authority RRs have been set? */
+	int n_additional; /* how many additional RRs have been set? */
+
+	struct server_reply_item *answer; /* linked list of answer RRs */
+	struct server_reply_item *authority; /* linked list of authority RRs */
+	struct server_reply_item *additional; /* linked list of additional RRs */
+
+	/* Constructed response.  Only set once we're ready to send a reply. */
+	/* Once this is set, the RR fields are cleared, and no more should be set. */
+	char *response;
+	size_t response_len;
+
+	/* Caller-visible fields: flags, questions. */
+	struct evdns_server_request base;
+};
+
+/* helper macro */
+#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
+
+/* Given a pointer to an evdns_server_request, get the corresponding */
+/* server_request. */
+#define TO_SERVER_REQUEST(base_ptr)										\
+	((struct server_request*)											\
+	 (((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
+
+/* The number of good nameservers that we have */
+static int global_good_nameservers = 0;
+
+/* inflight requests are contained in the req_head list */
+/* and are actually going out across the network */
+static int global_requests_inflight = 0;
+/* requests which aren't inflight are in the waiting list */
+/* and are counted here */
+static int global_requests_waiting = 0;
+
+static int global_max_requests_inflight = 64;
+
+static struct timeval global_timeout = {5, 0};  /* 5 seconds */
+static int global_max_reissues = 1;  /* a reissue occurs when we get some errors from the server */
+static int global_max_retransmits = 3;  /* number of times we'll retransmit a request which timed out */
+/* number of timeouts in a row before we consider this server to be down */
+static int global_max_nameserver_timeout = 3;
+
+/* These are the timeout values for nameservers. If we find a nameserver is down */
+/* we try to probe it at intervals as given below. Values are in seconds. */
+static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
+static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval);
+
+static struct nameserver *nameserver_pick(void);
+static void evdns_request_insert(struct request *req, struct request **head);
+static void nameserver_ready_callback(int fd, short events, void *arg);
+static int evdns_transmit(void);
+static int evdns_request_transmit(struct request *req);
+static void nameserver_send_probe(struct nameserver *const ns);
+static void search_request_finished(struct request *const);
+static int search_try_next(struct request *const req);
+static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
+static void evdns_requests_pump_waiting_queue(void);
+static u16 transaction_id_pick(void);
+static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
+static void request_submit(struct request *const req);
+
+static int server_request_free(struct server_request *req);
+static void server_request_free_answers(struct server_request *req);
+static void server_port_free(struct evdns_server_port *port);
+static void server_port_ready_callback(int fd, short events, void *arg);
+
+static int strtoint(const char *const str);
+
+#ifdef WIN32
+static int
+last_error(int sock)
+{
+	int optval, optvallen=sizeof(optval);
+	int err = WSAGetLastError();
+	if (err == WSAEWOULDBLOCK && sock >= 0) {
+		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
+			       &optvallen))
+			return err;
+		if (optval)
+			return optval;
+	}
+	return err;
+
+}
+static int
+error_is_eagain(int err)
+{
+	return err == EAGAIN || err == WSAEWOULDBLOCK;
+}
+static int
+inet_aton(const char *c, struct in_addr *addr)
+{
+	ev_uint32_t r;
+	if (strcmp(c, "255.255.255.255") == 0) {
+		addr->s_addr = 0xffffffffu;
+	} else {
+		r = inet_addr(c);
+		if (r == INADDR_NONE)
+			return 0;
+		addr->s_addr = r;
+	}
+	return 1;
+}
+#else
+#define last_error(sock) (errno)
+#define error_is_eagain(err) ((err) == EAGAIN)
+#endif
+#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
+
+#define ISSPACE(c) isspace((int)(unsigned char)(c))
+#define ISDIGIT(c) isdigit((int)(unsigned char)(c))
+
+static const char *
+debug_ntoa(u32 address)
+{
+	static char buf[32];
+	u32 a = ntohl(address);
+	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
+                      (int)(u8)((a>>24)&0xff),
+                      (int)(u8)((a>>16)&0xff),
+                      (int)(u8)((a>>8 )&0xff),
+  		      (int)(u8)((a    )&0xff));
+	return buf;
+}
+
+static evdns_debug_log_fn_type evdns_log_fn = NULL;
+
+void
+evdns_set_log_fn(evdns_debug_log_fn_type fn)
+{
+  evdns_log_fn = fn;
+}
+
+#ifdef __GNUC__
+#define EVDNS_LOG_CHECK  __attribute__ ((format(printf, 2, 3)))
+#else
+#define EVDNS_LOG_CHECK
+#endif
+
+static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
+static void
+_evdns_log(int warn, const char *fmt, ...)
+{
+  va_list args;
+  static char buf[512];
+  if (!evdns_log_fn)
+    return;
+  va_start(args,fmt);
+  evutil_vsnprintf(buf, sizeof(buf), fmt, args);
+  buf[sizeof(buf)-1] = '\0';
+  evdns_log_fn(warn, buf);
+  va_end(args);
+}
+
+#define log _evdns_log
+
+/* This walks the list of inflight requests to find the */
+/* one with a matching transaction id. Returns NULL on */
+/* failure */
+static struct request *
+request_find_from_trans_id(u16 trans_id) {
+	struct request *req = req_head, *const started_at = req_head;
+
+	if (req) {
+		do {
+			if (req->trans_id == trans_id) return req;
+			req = req->next;
+		} while (req != started_at);
+	}
+
+	return NULL;
+}
+
+/* a libevent callback function which is called when a nameserver */
+/* has gone down and we want to test if it has came back to life yet */
+static void
+nameserver_prod_callback(int fd, short events, void *arg) {
+	struct nameserver *const ns = (struct nameserver *) arg;
+        (void)fd;
+        (void)events;
+
+	nameserver_send_probe(ns);
+}
+
+/* a libevent callback which is called when a nameserver probe (to see if */
+/* it has come back to life) times out. We increment the count of failed_times */
+/* and wait longer to send the next probe packet. */
+static void
+nameserver_probe_failed(struct nameserver *const ns) {
+	const struct timeval * timeout;
+	(void) evtimer_del(&ns->timeout_event);
+	if (ns->state == 1) {
+		/* This can happen if the nameserver acts in a way which makes us mark */
+		/* it as bad and then starts sending good replies. */
+		return;
+	}
+
+	timeout =
+	  &global_nameserver_timeouts[MIN(ns->failed_times,
+					  global_nameserver_timeouts_length - 1)];
+	ns->failed_times++;
+
+	if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) {
+          log(EVDNS_LOG_WARN,
+              "Error from libevent when adding timer event for %s",
+              debug_ntoa(ns->address));
+          /* ???? Do more? */
+        }
+}
+
+/* called when a nameserver has been deemed to have failed. For example, too */
+/* many packets have timed out etc */
+static void
+nameserver_failed(struct nameserver *const ns, const char *msg) {
+	struct request *req, *started_at;
+	/* if this nameserver has already been marked as failed */
+	/* then don't do anything */
+	if (!ns->state) return;
+
+	log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
+            debug_ntoa(ns->address), msg);
+	global_good_nameservers--;
+	assert(global_good_nameservers >= 0);
+	if (global_good_nameservers == 0) {
+		log(EVDNS_LOG_WARN, "All nameservers have failed");
+	}
+
+	ns->state = 0;
+	ns->failed_times = 1;
+
+	if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
+		log(EVDNS_LOG_WARN,
+		    "Error from libevent when adding timer event for %s",
+		    debug_ntoa(ns->address));
+		/* ???? Do more? */
+        }
+
+	/* walk the list of inflight requests to see if any can be reassigned to */
+	/* a different server. Requests in the waiting queue don't have a */
+	/* nameserver assigned yet */
+
+	/* if we don't have *any* good nameservers then there's no point */
+	/* trying to reassign requests to one */
+	if (!global_good_nameservers) return;
+
+	req = req_head;
+	started_at = req_head;
+	if (req) {
+		do {
+			if (req->tx_count == 0 && req->ns == ns) {
+				/* still waiting to go out, can be moved */
+				/* to another server */
+				req->ns = nameserver_pick();
+			}
+			req = req->next;
+		} while (req != started_at);
+	}
+}
+
+static void
+nameserver_up(struct nameserver *const ns) {
+	if (ns->state) return;
+	log(EVDNS_LOG_WARN, "Nameserver %s is back up",
+	    debug_ntoa(ns->address));
+	evtimer_del(&ns->timeout_event);
+	ns->state = 1;
+	ns->failed_times = 0;
+	ns->timedout = 0;
+	global_good_nameservers++;
+}
+
+static void
+request_trans_id_set(struct request *const req, const u16 trans_id) {
+	req->trans_id = trans_id;
+	*((u16 *) req->request) = htons(trans_id);
+}
+
+/* Called to remove a request from a list and dealloc it. */
+/* head is a pointer to the head of the list it should be */
+/* removed from or NULL if the request isn't in a list. */
+static void
+request_finished(struct request *const req, struct request **head) {
+	if (head) {
+		if (req->next == req) {
+			/* only item in the list */
+			*head = NULL;
+		} else {
+			req->next->prev = req->prev;
+			req->prev->next = req->next;
+			if (*head == req) *head = req->next;
+		}
+	}
+
+	log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
+	    (unsigned long) req);
+	evtimer_del(&req->timeout_event);
+
+	search_request_finished(req);
+	global_requests_inflight--;
+
+	if (!req->request_appended) {
+		/* need to free the request data on it's own */
+		free(req->request);
+	} else {
+		/* the request data is appended onto the header */
+		/* so everything gets free()ed when we: */
+	}
+
+	free(req);
+
+	evdns_requests_pump_waiting_queue();
+}
+
+/* This is called when a server returns a funny error code. */
+/* We try the request again with another server. */
+/* */
+/* return: */
+/*   0 ok */
+/*   1 failed/reissue is pointless */
+static int
+request_reissue(struct request *req) {
+	const struct nameserver *const last_ns = req->ns;
+	/* the last nameserver should have been marked as failing */
+	/* by the caller of this function, therefore pick will try */
+	/* not to return it */
+	req->ns = nameserver_pick();
+	if (req->ns == last_ns) {
+		/* ... but pick did return it */
+		/* not a lot of point in trying again with the */
+		/* same server */
+		return 1;
+	}
+
+	req->reissue_count++;
+	req->tx_count = 0;
+	req->transmit_me = 1;
+
+	return 0;
+}
+
+/* this function looks for space on the inflight queue and promotes */
+/* requests from the waiting queue if it can. */
+static void
+evdns_requests_pump_waiting_queue(void) {
+	while (global_requests_inflight < global_max_requests_inflight &&
+	    global_requests_waiting) {
+		struct request *req;
+		/* move a request from the waiting queue to the inflight queue */
+		assert(req_waiting_head);
+		if (req_waiting_head->next == req_waiting_head) {
+			/* only one item in the queue */
+			req = req_waiting_head;
+			req_waiting_head = NULL;
+		} else {
+			req = req_waiting_head;
+			req->next->prev = req->prev;
+			req->prev->next = req->next;
+			req_waiting_head = req->next;
+		}
+
+		global_requests_waiting--;
+		global_requests_inflight++;
+
+		req->ns = nameserver_pick();
+		request_trans_id_set(req, transaction_id_pick());
+
+		evdns_request_insert(req, &req_head);
+		evdns_request_transmit(req);
+		evdns_transmit();
+	}
+}
+
+static void
+reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) {
+	switch (req->request_type) {
+	case TYPE_A:
+		if (reply)
+			req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
+							   reply->data.a.addrcount, ttl,
+						 reply->data.a.addresses,
+							   req->user_pointer);
+		else
+			req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+		return;
+	case TYPE_PTR:
+		if (reply) {
+			char *name = reply->data.ptr.name;
+			req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
+							   &name, req->user_pointer);
+		} else {
+			req->user_callback(err, 0, 0, 0, NULL,
+							   req->user_pointer);
+		}
+		return;
+	case TYPE_AAAA:
+		if (reply)
+			req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
+							   reply->data.aaaa.addrcount, ttl,
+							   reply->data.aaaa.addresses,
+							   req->user_pointer);
+		else
+			req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+                return;
+	}
+	assert(0);
+}
+
+/* this processes a parsed reply packet */
+static void
+reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
+	int error;
+	static const int error_codes[] = {
+		DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
+		DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
+	};
+
+	if (flags & 0x020f || !reply || !reply->have_answer) {
+		/* there was an error */
+		if (flags & 0x0200) {
+			error = DNS_ERR_TRUNCATED;
+		} else {
+			u16 error_code = (flags & 0x000f) - 1;
+			if (error_code > 4) {
+				error = DNS_ERR_UNKNOWN;
+			} else {
+				error = error_codes[error_code];
+			}
+		}
+
+		switch(error) {
+		case DNS_ERR_NOTIMPL:
+		case DNS_ERR_REFUSED:
+			/* we regard these errors as marking a bad nameserver */
+			if (req->reissue_count < global_max_reissues) {
+				char msg[64];
+				evutil_snprintf(msg, sizeof(msg),
+				    "Bad response %d (%s)",
+					 error, evdns_err_to_string(error));
+				nameserver_failed(req->ns, msg);
+				if (!request_reissue(req)) return;
+			}
+			break;
+		case DNS_ERR_SERVERFAILED:
+			/* rcode 2 (servfailed) sometimes means "we
+			 * are broken" and sometimes (with some binds)
+			 * means "that request was very confusing."
+			 * Treat this as a timeout, not a failure.
+			 */
+			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
+				"will allow the request to time out.",
+				debug_ntoa(req->ns->address));
+			break;
+		default:
+			/* we got a good reply from the nameserver */
+			nameserver_up(req->ns);
+		}
+
+		if (req->search_state && req->request_type != TYPE_PTR) {
+			/* if we have a list of domains to search in,
+			 * try the next one */
+			if (!search_try_next(req)) {
+				/* a new request was issued so this
+				 * request is finished and */
+				/* the user callback will be made when
+				 * that request (or a */
+				/* child of it) finishes. */
+				request_finished(req, &req_head);
+				return;
+			}
+		}
+
+		/* all else failed. Pass the failure up */
+		reply_callback(req, 0, error, NULL);
+		request_finished(req, &req_head);
+	} else {
+		/* all ok, tell the user */
+		reply_callback(req, ttl, 0, reply);
+		nameserver_up(req->ns);
+		request_finished(req, &req_head);
+	}
+}
+
+static int
+name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
+	int name_end = -1;
+	int j = *idx;
+	int ptr_count = 0;
+#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0)
+#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0)
+#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0)
+
+	char *cp = name_out;
+	const char *const end = name_out + name_out_len;
+
+	/* Normally, names are a series of length prefixed strings terminated */
+	/* with a length of 0 (the lengths are u8's < 63). */
+	/* However, the length can start with a pair of 1 bits and that */
+	/* means that the next 14 bits are a pointer within the current */
+	/* packet. */
+
+	for(;;) {
+		u8 label_len;
+		if (j >= length) return -1;
+		GET8(label_len);
+		if (!label_len) break;
+		if (label_len & 0xc0) {
+			u8 ptr_low;
+			GET8(ptr_low);
+			if (name_end < 0) name_end = j;
+			j = (((int)label_len & 0x3f) << 8) + ptr_low;
+			/* Make sure that the target offset is in-bounds. */
+			if (j < 0 || j >= length) return -1;
+			/* If we've jumped more times than there are characters in the
+			 * message, we must have a loop. */
+			if (++ptr_count > length) return -1;
+			continue;
+		}
+		if (label_len > 63) return -1;
+		if (cp != name_out) {
+			if (cp + 1 >= end) return -1;
+			*cp++ = '.';
+		}
+		if (cp + label_len >= end) return -1;
+		memcpy(cp, packet + j, label_len);
+		cp += label_len;
+		j += label_len;
+	}
+	if (cp >= end) return -1;
+	*cp = '\0';
+	if (name_end < 0)
+		*idx = j;
+	else
+		*idx = name_end;
+	return 0;
+ err:
+	return -1;
+}
+
+/* parses a raw request from a nameserver */
+static int
+reply_parse(u8 *packet, int length) {
+	int j = 0, k = 0;  /* index into packet */
+	u16 _t;  /* used by the macros */
+	u32 _t32;  /* used by the macros */
+	char tmp_name[256], cmp_name[256]; /* used by the macros */
+
+	u16 trans_id, questions, answers, authority, additional, datalength;
+        u16 flags = 0;
+	u32 ttl, ttl_r = 0xffffffff;
+	struct reply reply;
+	struct request *req = NULL;
+	unsigned int i;
+
+	GET16(trans_id);
+	GET16(flags);
+	GET16(questions);
+	GET16(answers);
+	GET16(authority);
+	GET16(additional);
+	(void) authority; /* suppress "unused variable" warnings. */
+	(void) additional; /* suppress "unused variable" warnings. */
+
+	req = request_find_from_trans_id(trans_id);
+	if (!req) return -1;
+
+	memset(&reply, 0, sizeof(reply));
+
+	/* If it's not an answer, it doesn't correspond to any request. */
+	if (!(flags & 0x8000)) return -1;  /* must be an answer */
+	if (flags & 0x020f) {
+		/* there was an error */
+		goto err;
+	}
+	/* if (!answers) return; */  /* must have an answer of some form */
+
+	/* This macro skips a name in the DNS reply. */
+#define SKIP_NAME \
+	do { tmp_name[0] = '\0';				\
+		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
+			goto err;				\
+	} while(0)
+#define TEST_NAME \
+	do { tmp_name[0] = '\0';				\
+		cmp_name[0] = '\0';				\
+		k = j;						\
+		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
+			goto err;					\
+		if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0)	\
+			goto err;				\
+		if (memcmp(tmp_name, cmp_name, strlen (tmp_name)) != 0)	\
+			return (-1); /* we ignore mismatching names */	\
+	} while(0)
+
+	reply.type = req->request_type;
+
+	/* skip over each question in the reply */
+	for (i = 0; i < questions; ++i) {
+		/* the question looks like
+		 *   <label:name><u16:type><u16:class>
+		 */
+		TEST_NAME;
+		j += 4;
+		if (j > length) goto err;
+	}
+
+	/* now we have the answer section which looks like
+	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
+	 */
+
+	for (i = 0; i < answers; ++i) {
+		u16 type, class;
+
+		SKIP_NAME;
+		GET16(type);
+		GET16(class);
+		GET32(ttl);
+		GET16(datalength);
+
+		if (type == TYPE_A && class == CLASS_INET) {
+			int addrcount, addrtocopy;
+			if (req->request_type != TYPE_A) {
+				j += datalength; continue;
+			}
+			if ((datalength & 3) != 0) /* not an even number of As. */
+			    goto err;
+			addrcount = datalength >> 2;
+			addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
+
+			ttl_r = MIN(ttl_r, ttl);
+			/* we only bother with the first four addresses. */
+			if (j + 4*addrtocopy > length) goto err;
+			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
+				   packet + j, 4*addrtocopy);
+			j += 4*addrtocopy;
+			reply.data.a.addrcount += addrtocopy;
+			reply.have_answer = 1;
+			if (reply.data.a.addrcount == MAX_ADDRS) break;
+		} else if (type == TYPE_PTR && class == CLASS_INET) {
+			if (req->request_type != TYPE_PTR) {
+				j += datalength; continue;
+			}
+			if (name_parse(packet, length, &j, reply.data.ptr.name,
+						   sizeof(reply.data.ptr.name))<0)
+				goto err;
+			ttl_r = MIN(ttl_r, ttl);
+			reply.have_answer = 1;
+			break;
+		} else if (type == TYPE_AAAA && class == CLASS_INET) {
+			int addrcount, addrtocopy;
+			if (req->request_type != TYPE_AAAA) {
+				j += datalength; continue;
+			}
+			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
+				goto err;
+			addrcount = datalength >> 4;  /* each address is 16 bytes long */
+			addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
+			ttl_r = MIN(ttl_r, ttl);
+
+			/* we only bother with the first four addresses. */
+			if (j + 16*addrtocopy > length) goto err;
+			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
+				   packet + j, 16*addrtocopy);
+			reply.data.aaaa.addrcount += addrtocopy;
+			j += 16*addrtocopy;
+			reply.have_answer = 1;
+			if (reply.data.aaaa.addrcount == MAX_ADDRS) break;
+		} else {
+			/* skip over any other type of resource */
+			j += datalength;
+		}
+	}
+
+	reply_handle(req, flags, ttl_r, &reply);
+	return 0;
+ err:
+	if (req)
+		reply_handle(req, flags, 0, NULL);
+	return -1;
+}
+
+/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
+/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
+/* callback. */
+static int
+request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
+{
+	int j = 0;	/* index into packet */
+	u16 _t;	 /* used by the macros */
+	char tmp_name[256]; /* used by the macros */
+
+	int i;
+	u16 trans_id, flags, questions, answers, authority, additional;
+	struct server_request *server_req = NULL;
+
+	/* Get the header fields */
+	GET16(trans_id);
+	GET16(flags);
+	GET16(questions);
+	GET16(answers);
+	GET16(authority);
+	GET16(additional);
+
+	if (flags & 0x8000) return -1; /* Must not be an answer. */
+	flags &= 0x0110; /* Only RD and CD get preserved. */
+
+	server_req = malloc(sizeof(struct server_request));
+	if (server_req == NULL) return -1;
+	memset(server_req, 0, sizeof(struct server_request));
+
+	server_req->trans_id = trans_id;
+	memcpy(&server_req->addr, addr, addrlen);
+	server_req->addrlen = addrlen;
+
+	server_req->base.flags = flags;
+	server_req->base.nquestions = 0;
+	server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions);
+	if (server_req->base.questions == NULL)
+		goto err;
+
+	for (i = 0; i < questions; ++i) {
+		u16 type, class;
+		struct evdns_server_question *q;
+		int namelen;
+		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
+			goto err;
+		GET16(type);
+		GET16(class);
+		namelen = strlen(tmp_name);
+		q = malloc(sizeof(struct evdns_server_question) + namelen);
+		if (!q)
+			goto err;
+		q->type = type;
+		q->dns_question_class = class;
+		memcpy(q->name, tmp_name, namelen+1);
+		server_req->base.questions[server_req->base.nquestions++] = q;
+	}
+
+	/* Ignore answers, authority, and additional. */
+
+	server_req->port = port;
+	port->refcnt++;
+
+	/* Only standard queries are supported. */
+	if (flags & 0x7800) {
+		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
+		return -1;
+	}
+
+	port->user_callback(&(server_req->base), port->user_data);
+
+	return 0;
+err:
+	if (server_req) {
+		if (server_req->base.questions) {
+			for (i = 0; i < server_req->base.nquestions; ++i)
+				free(server_req->base.questions[i]);
+			free(server_req->base.questions);
+		}
+		free(server_req);
+	}
+	return -1;
+
+#undef SKIP_NAME
+#undef GET32
+#undef GET16
+#undef GET8
+}
+
+static u16
+default_transaction_id_fn(void)
+{
+	u16 trans_id;
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+	struct timespec ts;
+	static int clkid = -1;
+	if (clkid == -1) {
+		clkid = CLOCK_REALTIME;
+#ifdef CLOCK_MONOTONIC
+		if (clock_gettime(CLOCK_MONOTONIC, &ts) != -1)
+			clkid = CLOCK_MONOTONIC;
+#endif
+	}
+	if (clock_gettime(clkid, &ts) == -1)
+		event_err(1, "clock_gettime");
+	trans_id = ts.tv_nsec & 0xffff;
+#endif
+
+#ifdef DNS_USE_FTIME_FOR_ID
+	struct _timeb tb;
+	_ftime(&tb);
+	trans_id = tb.millitm & 0xffff;
+#endif
+
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+	struct timeval tv;
+	evutil_gettimeofday(&tv, NULL);
+	trans_id = tv.tv_usec & 0xffff;
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+	if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
+		/* in the case that the RAND call fails we back */
+		/* down to using gettimeofday. */
+		/*
+		  struct timeval tv;
+		  evutil_gettimeofday(&tv, NULL);
+		  trans_id = tv.tv_usec & 0xffff;
+		*/
+		abort();
+	}
+#endif
+	return trans_id;
+}
+
+static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
+
+void
+evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
+{
+	if (fn)
+		trans_id_function = fn;
+	else
+		trans_id_function = default_transaction_id_fn;
+}
+
+/* Try to choose a strong transaction id which isn't already in flight */
+static u16
+transaction_id_pick(void) {
+	for (;;) {
+		const struct request *req = req_head, *started_at;
+		u16 trans_id = trans_id_function();
+
+		if (trans_id == 0xffff) continue;
+		/* now check to see if that id is already inflight */
+		req = started_at = req_head;
+		if (req) {
+			do {
+				if (req->trans_id == trans_id) break;
+				req = req->next;
+			} while (req != started_at);
+		}
+		/* we didn't find it, so this is a good id */
+		if (req == started_at) return trans_id;
+	}
+}
+
+/* choose a namesever to use. This function will try to ignore */
+/* nameservers which we think are down and load balance across the rest */
+/* by updating the server_head global each time. */
+static struct nameserver *
+nameserver_pick(void) {
+	struct nameserver *started_at = server_head, *picked;
+	if (!server_head) return NULL;
+
+	/* if we don't have any good nameservers then there's no */
+	/* point in trying to find one. */
+	if (!global_good_nameservers) {
+		server_head = server_head->next;
+		return server_head;
+	}
+
+	/* remember that nameservers are in a circular list */
+	for (;;) {
+		if (server_head->state) {
+			/* we think this server is currently good */
+			picked = server_head;
+			server_head = server_head->next;
+			return picked;
+		}
+
+		server_head = server_head->next;
+		if (server_head == started_at) {
+			/* all the nameservers seem to be down */
+			/* so we just return this one and hope for the */
+			/* best */
+			assert(global_good_nameservers == 0);
+			picked = server_head;
+			server_head = server_head->next;
+			return picked;
+		}
+	}
+}
+
+static int
+address_is_correct(struct nameserver *ns, struct sockaddr *sa, socklen_t slen)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in*) sa;
+	if (sa->sa_family != AF_INET || slen != sizeof(struct sockaddr_in))
+		return 0;
+	if (sin->sin_addr.s_addr != ns->address)
+		return 0;
+	return 1;
+}
+
+/* this is called when a namesever socket is ready for reading */
+static void
+nameserver_read(struct nameserver *ns) {
+	u8 packet[1500];
+	struct sockaddr_storage ss;
+	socklen_t addrlen = sizeof(ss);
+
+	for (;;) {
+          	const int r = recvfrom(ns->socket, packet, sizeof(packet), 0,
+		    (struct sockaddr*)&ss, &addrlen);
+		if (r < 0) {
+			int err = last_error(ns->socket);
+			if (error_is_eagain(err)) return;
+			nameserver_failed(ns, strerror(err));
+			return;
+		}
+		if (!address_is_correct(ns, (struct sockaddr*)&ss, addrlen)) {
+			log(EVDNS_LOG_WARN, "Address mismatch on received "
+			    "DNS packet.");
+			return;
+		}
+		ns->timedout = 0;
+		reply_parse(packet, r);
+	}
+}
+
+/* Read a packet from a DNS client on a server port s, parse it, and */
+/* act accordingly. */
+static void
+server_port_read(struct evdns_server_port *s) {
+	u8 packet[1500];
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+	int r;
+
+	for (;;) {
+		addrlen = sizeof(struct sockaddr_storage);
+		r = recvfrom(s->socket, packet, sizeof(packet), 0,
+					 (struct sockaddr*) &addr, &addrlen);
+		if (r < 0) {
+			int err = last_error(s->socket);
+			if (error_is_eagain(err)) return;
+			log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
+				strerror(err), err);
+			return;
+		}
+		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
+	}
+}
+
+/* Try to write all pending replies on a given DNS server port. */
+static void
+server_port_flush(struct evdns_server_port *port)
+{
+	while (port->pending_replies) {
+		struct server_request *req = port->pending_replies;
+		int r = sendto(port->socket, req->response, req->response_len, 0,
+			   (struct sockaddr*) &req->addr, req->addrlen);
+		if (r < 0) {
+			int err = last_error(port->socket);
+			if (error_is_eagain(err))
+				return;
+			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err);
+		}
+		if (server_request_free(req)) {
+			/* we released the last reference to req->port. */
+			return;
+		}
+	}
+
+	/* We have no more pending requests; stop listening for 'writeable' events. */
+	(void) event_del(&port->event);
+	event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+			  server_port_ready_callback, port);
+	if (event_add(&port->event, NULL) < 0) {
+		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
+		/* ???? Do more? */
+	}
+}
+
+/* set if we are waiting for the ability to write to this server. */
+/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
+/* we stop these events. */
+static void
+nameserver_write_waiting(struct nameserver *ns, char waiting) {
+	if (ns->write_waiting == waiting) return;
+
+	ns->write_waiting = waiting;
+	(void) event_del(&ns->event);
+	event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
+			nameserver_ready_callback, ns);
+	if (event_add(&ns->event, NULL) < 0) {
+          log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
+              debug_ntoa(ns->address));
+          /* ???? Do more? */
+        }
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a nameserver socket is ready for writing or reading */
+static void
+nameserver_ready_callback(int fd, short events, void *arg) {
+	struct nameserver *ns = (struct nameserver *) arg;
+        (void)fd;
+
+	if (events & EV_WRITE) {
+		ns->choked = 0;
+		if (!evdns_transmit()) {
+			nameserver_write_waiting(ns, 0);
+		}
+	}
+	if (events & EV_READ) {
+		nameserver_read(ns);
+	}
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a server socket is ready for writing or reading. */
+static void
+server_port_ready_callback(int fd, short events, void *arg) {
+	struct evdns_server_port *port = (struct evdns_server_port *) arg;
+	(void) fd;
+
+	if (events & EV_WRITE) {
+		port->choked = 0;
+		server_port_flush(port);
+	}
+	if (events & EV_READ) {
+		server_port_read(port);
+	}
+}
+
+/* This is an inefficient representation; only use it via the dnslabel_table_*
+ * functions, so that is can be safely replaced with something smarter later. */
+#define MAX_LABELS 128
+/* Structures used to implement name compression */
+struct dnslabel_entry { char *v; off_t pos; };
+struct dnslabel_table {
+	int n_labels; /* number of current entries */
+	/* map from name to position in message */
+	struct dnslabel_entry labels[MAX_LABELS];
+};
+
+/* Initialize dnslabel_table. */
+static void
+dnslabel_table_init(struct dnslabel_table *table)
+{
+	table->n_labels = 0;
+}
+
+/* Free all storage held by table, but not the table itself. */
+static void
+dnslabel_clear(struct dnslabel_table *table)
+{
+	int i;
+	for (i = 0; i < table->n_labels; ++i)
+		free(table->labels[i].v);
+	table->n_labels = 0;
+}
+
+/* return the position of the label in the current message, or -1 if the label */
+/* hasn't been used yet. */
+static int
+dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
+{
+	int i;
+	for (i = 0; i < table->n_labels; ++i) {
+		if (!strcmp(label, table->labels[i].v))
+			return table->labels[i].pos;
+	}
+	return -1;
+}
+
+/* remember that we've used the label at position pos */
+static int
+dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
+{
+	char *v;
+	int p;
+	if (table->n_labels == MAX_LABELS)
+		return (-1);
+	v = strdup(label);
+	if (v == NULL)
+		return (-1);
+	p = table->n_labels++;
+	table->labels[p].v = v;
+	table->labels[p].pos = pos;
+
+	return (0);
+}
+
+/* Converts a string to a length-prefixed set of DNS labels, starting */
+/* at buf[j]. name and buf must not overlap. name_len should be the length */
+/* of name.	 table is optional, and is used for compression. */
+/* */
+/* Input: abc.def */
+/* Output: <3>abc<3>def<0> */
+/* */
+/* Returns the first index after the encoded name, or negative on error. */
+/*	 -1	 label was > 63 bytes */
+/*	 -2	 name too long to fit in buffer. */
+/* */
+static off_t
+dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
+				  const char *name, const int name_len,
+				  struct dnslabel_table *table) {
+	const char *end = name + name_len;
+	int ref = 0;
+	u16 _t;
+
+#define APPEND16(x) do {						   \
+		if (j + 2 > (off_t)buf_len)				   \
+			goto overflow;						   \
+		_t = htons(x);							   \
+		memcpy(buf + j, &_t, 2);				   \
+		j += 2;									   \
+	} while (0)
+#define APPEND32(x) do {						   \
+		if (j + 4 > (off_t)buf_len)				   \
+			goto overflow;						   \
+		_t32 = htonl(x);						   \
+		memcpy(buf + j, &_t32, 4);				   \
+		j += 4;									   \
+	} while (0)
+
+	if (name_len > 255) return -2;
+
+	for (;;) {
+		const char *const start = name;
+		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
+			APPEND16(ref | 0xc000);
+			return j;
+		}
+		name = strchr(name, '.');
+		if (!name) {
+			const unsigned int label_len = end - start;
+			if (label_len > 63) return -1;
+			if ((size_t)(j+label_len+1) > buf_len) return -2;
+			if (table) dnslabel_table_add(table, start, j);
+			buf[j++] = label_len;
+
+			memcpy(buf + j, start, end - start);
+			j += end - start;
+			break;
+		} else {
+			/* append length of the label. */
+			const unsigned int label_len = name - start;
+			if (label_len > 63) return -1;
+			if ((size_t)(j+label_len+1) > buf_len) return -2;
+			if (table) dnslabel_table_add(table, start, j);
+			buf[j++] = label_len;
+
+			memcpy(buf + j, start, name - start);
+			j += name - start;
+			/* hop over the '.' */
+			name++;
+		}
+	}
+
+	/* the labels must be terminated by a 0. */
+	/* It's possible that the name ended in a . */
+	/* in which case the zero is already there */
+	if (!j || buf[j-1]) buf[j++] = 0;
+	return j;
+ overflow:
+	return (-2);
+}
+
+/* Finds the length of a dns request for a DNS name of the given */
+/* length. The actual request may be smaller than the value returned */
+/* here */
+static int
+evdns_request_len(const int name_len) {
+	return 96 + /* length of the DNS standard header */
+		name_len + 2 +
+		4;  /* space for the resource type */
+}
+
+/* build a dns request packet into buf. buf should be at least as long */
+/* as evdns_request_len told you it should be. */
+/* */
+/* Returns the amount of space used. Negative on error. */
+static int
+evdns_request_data_build(const char *const name, const int name_len,
+    const u16 trans_id, const u16 type, const u16 class,
+    u8 *const buf, size_t buf_len) {
+	off_t j = 0;  /* current offset into buf */
+	u16 _t;  /* used by the macros */
+
+	APPEND16(trans_id);
+	APPEND16(0x0100);  /* standard query, recusion needed */
+	APPEND16(1);  /* one question */
+	APPEND16(0);  /* no answers */
+	APPEND16(0);  /* no authority */
+	APPEND16(0);  /* no additional */
+
+	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
+	if (j < 0) {
+		return (int)j;
+	}
+	
+	APPEND16(type);
+	APPEND16(class);
+
+	return (int)j;
+ overflow:
+	return (-1);
+}
+
+/* exported function */
+struct evdns_server_port *
+evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
+{
+	struct evdns_server_port *port;
+	if (!(port = malloc(sizeof(struct evdns_server_port))))
+		return NULL;
+	memset(port, 0, sizeof(struct evdns_server_port));
+
+	assert(!is_tcp); /* TCP sockets not yet implemented */
+	port->socket = socket;
+	port->refcnt = 1;
+	port->choked = 0;
+	port->closing = 0;
+	port->user_callback = cb;
+	port->user_data = user_data;
+	port->pending_replies = NULL;
+
+	event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+			  server_port_ready_callback, port);
+	event_add(&port->event, NULL); /* check return. */
+	return port;
+}
+
+/* exported function */
+void
+evdns_close_server_port(struct evdns_server_port *port)
+{
+	if (--port->refcnt == 0)
+		server_port_free(port);
+	port->closing = 1;
+}
+
+/* exported function */
+int
+evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	struct server_reply_item **itemp, *item;
+	int *countp;
+
+	if (req->response) /* have we already answered? */
+		return (-1);
+
+	switch (section) {
+	case EVDNS_ANSWER_SECTION:
+		itemp = &req->answer;
+		countp = &req->n_answer;
+		break;
+	case EVDNS_AUTHORITY_SECTION:
+		itemp = &req->authority;
+		countp = &req->n_authority;
+		break;
+	case EVDNS_ADDITIONAL_SECTION:
+		itemp = &req->additional;
+		countp = &req->n_additional;
+		break;
+	default:
+		return (-1);
+	}
+	while (*itemp) {
+		itemp = &((*itemp)->next);
+	}
+	item = malloc(sizeof(struct server_reply_item));
+	if (!item)
+		return -1;
+	item->next = NULL;
+	if (!(item->name = strdup(name))) {
+		free(item);
+		return -1;
+	}
+	item->type = type;
+	item->dns_question_class = class;
+	item->ttl = ttl;
+	item->is_name = is_name != 0;
+	item->datalen = 0;
+	item->data = NULL;
+	if (data) {
+		if (item->is_name) {
+			if (!(item->data = strdup(data))) {
+				free(item->name);
+				free(item);
+				return -1;
+			}
+			item->datalen = (u16)-1;
+		} else {
+			if (!(item->data = malloc(datalen))) {
+				free(item->name);
+				free(item);
+				return -1;
+			}
+			item->datalen = datalen;
+			memcpy(item->data, data, datalen);
+		}
+	}
+
+	*itemp = item;
+	++(*countp);
+	return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
+{
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
+		  ttl, n*4, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
+{
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
+		  ttl, n*16, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
+{
+	u32 a;
+	char buf[32];
+	assert(in || inaddr_name);
+	assert(!(in && inaddr_name));
+	if (in) {
+		a = ntohl(in->s_addr);
+		evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+				(int)(u8)((a	)&0xff),
+				(int)(u8)((a>>8 )&0xff),
+				(int)(u8)((a>>16)&0xff),
+				(int)(u8)((a>>24)&0xff));
+		inaddr_name = buf;
+	}
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
+		  ttl, -1, 1, hostname);
+}
+
+/* exported function */
+int
+evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
+{
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
+		  ttl, -1, 1, cname);
+}
+
+
+static int
+evdns_server_request_format_response(struct server_request *req, int err)
+{
+	unsigned char buf[1500];
+	size_t buf_len = sizeof(buf);
+	off_t j = 0, r;
+	u16 _t;
+	u32 _t32;
+	int i;
+	u16 flags;
+	struct dnslabel_table table;
+
+	if (err < 0 || err > 15) return -1;
+
+	/* Set response bit and error code; copy OPCODE and RD fields from
+	 * question; copy RA and AA if set by caller. */
+	flags = req->base.flags;
+	flags |= (0x8000 | err);
+
+	dnslabel_table_init(&table);
+	APPEND16(req->trans_id);
+	APPEND16(flags);
+	APPEND16(req->base.nquestions);
+	APPEND16(req->n_answer);
+	APPEND16(req->n_authority);
+	APPEND16(req->n_additional);
+
+	/* Add questions. */
+	for (i=0; i < req->base.nquestions; ++i) {
+		const char *s = req->base.questions[i]->name;
+		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
+		if (j < 0) {
+			dnslabel_clear(&table);
+			return (int) j;
+		}
+		APPEND16(req->base.questions[i]->type);
+		APPEND16(req->base.questions[i]->dns_question_class);
+	}
+
+	/* Add answer, authority, and additional sections. */
+	for (i=0; i<3; ++i) {
+		struct server_reply_item *item;
+		if (i==0)
+			item = req->answer;
+		else if (i==1)
+			item = req->authority;
+		else
+			item = req->additional;
+		while (item) {
+			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
+			if (r < 0)
+				goto overflow;
+			j = r;
+
+			APPEND16(item->type);
+			APPEND16(item->dns_question_class);
+			APPEND32(item->ttl);
+			if (item->is_name) {
+				off_t len_idx = j, name_start;
+				j += 2;
+				name_start = j;
+				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
+				if (r < 0)
+					goto overflow;
+				j = r;
+				_t = htons( (short) (j-name_start) );
+				memcpy(buf+len_idx, &_t, 2);
+			} else {
+				APPEND16(item->datalen);
+				if (j+item->datalen > (off_t)buf_len)
+					goto overflow;
+				memcpy(buf+j, item->data, item->datalen);
+				j += item->datalen;
+			}
+			item = item->next;
+		}
+	}
+
+	if (j > 512) {
+overflow:
+		j = 512;
+		buf[2] |= 0x02; /* set the truncated bit. */
+	}
+
+	req->response_len = j;
+
+	if (!(req->response = malloc(req->response_len))) {
+		server_request_free_answers(req);
+		dnslabel_clear(&table);
+		return (-1);
+	}
+	memcpy(req->response, buf, req->response_len);
+	server_request_free_answers(req);
+	dnslabel_clear(&table);
+	return (0);
+}
+
+/* exported function */
+int
+evdns_server_request_respond(struct evdns_server_request *_req, int err)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	struct evdns_server_port *port = req->port;
+	int r;
+	if (!req->response) {
+		if ((r = evdns_server_request_format_response(req, err))<0)
+			return r;
+	}
+
+	r = sendto(port->socket, req->response, req->response_len, 0,
+			   (struct sockaddr*) &req->addr, req->addrlen);
+	if (r<0) {
+		int sock_err = last_error(port->socket);
+		if (! error_is_eagain(sock_err))
+			return -1;
+
+		if (port->pending_replies) {
+			req->prev_pending = port->pending_replies->prev_pending;
+			req->next_pending = port->pending_replies;
+			req->prev_pending->next_pending =
+				req->next_pending->prev_pending = req;
+		} else {
+			req->prev_pending = req->next_pending = req;
+			port->pending_replies = req;
+			port->choked = 1;
+
+			(void) event_del(&port->event);
+			event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
+
+			if (event_add(&port->event, NULL) < 0) {
+				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
+			}
+
+		}
+
+		return 1;
+	}
+	if (server_request_free(req))
+		return 0;
+
+	if (port->pending_replies)
+		server_port_flush(port);
+
+	return 0;
+}
+
+/* Free all storage held by RRs in req. */
+static void
+server_request_free_answers(struct server_request *req)
+{
+	struct server_reply_item *victim, *next, **list;
+	int i;
+	for (i = 0; i < 3; ++i) {
+		if (i==0)
+			list = &req->answer;
+		else if (i==1)
+			list = &req->authority;
+		else
+			list = &req->additional;
+
+		victim = *list;
+		while (victim) {
+			next = victim->next;
+			free(victim->name);
+			if (victim->data)
+				free(victim->data);
+			free(victim);
+			victim = next;
+		}
+		*list = NULL;
+	}
+}
+
+/* Free all storage held by req, and remove links to it. */
+/* return true iff we just wound up freeing the server_port. */
+static int
+server_request_free(struct server_request *req)
+{
+	int i, rc=1;
+	if (req->base.questions) {
+		for (i = 0; i < req->base.nquestions; ++i)
+			free(req->base.questions[i]);
+		free(req->base.questions);
+	}
+
+	if (req->port) {
+		if (req->port->pending_replies == req) {
+			if (req->next_pending)
+				req->port->pending_replies = req->next_pending;
+			else
+				req->port->pending_replies = NULL;
+		}
+		rc = --req->port->refcnt;
+	}
+
+	if (req->response) {
+		free(req->response);
+	}
+
+	server_request_free_answers(req);
+
+	if (req->next_pending && req->next_pending != req) {
+		req->next_pending->prev_pending = req->prev_pending;
+		req->prev_pending->next_pending = req->next_pending;
+	}
+
+	if (rc == 0) {
+		server_port_free(req->port);
+		free(req);
+		return (1);
+	}
+	free(req);
+	return (0);
+}
+
+/* Free all storage held by an evdns_server_port.  Only called when  */
+static void
+server_port_free(struct evdns_server_port *port)
+{
+	assert(port);
+	assert(!port->refcnt);
+	assert(!port->pending_replies);
+	if (port->socket > 0) {
+		CLOSE_SOCKET(port->socket);
+		port->socket = -1;
+	}
+	(void) event_del(&port->event);
+	/* XXXX actually free the port? -NM */
+}
+
+/* exported function */
+int
+evdns_server_request_drop(struct evdns_server_request *_req)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	server_request_free(req);
+	return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	if (addr_len < (int)req->addrlen)
+		return -1;
+	memcpy(sa, &(req->addr), req->addrlen);
+	return req->addrlen;
+}
+
+#undef APPEND16
+#undef APPEND32
+
+/* this is a libevent callback function which is called when a request */
+/* has timed out. */
+static void
+evdns_request_timeout_callback(int fd, short events, void *arg) {
+	struct request *const req = (struct request *) arg;
+        (void) fd;
+        (void) events;
+
+	log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
+
+	req->ns->timedout++;
+	if (req->ns->timedout > global_max_nameserver_timeout) {
+		req->ns->timedout = 0;
+		nameserver_failed(req->ns, "request timed out.");
+	}
+
+	(void) evtimer_del(&req->timeout_event);
+	if (req->tx_count >= global_max_retransmits) {
+		/* this request has failed */
+		reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
+		request_finished(req, &req_head);
+	} else {
+		/* retransmit it */
+		evdns_request_transmit(req);
+	}
+}
+
+/* try to send a request to a given server. */
+/* */
+/* return: */
+/*   0 ok */
+/*   1 temporary failure */
+/*   2 other failure */
+static int
+evdns_request_transmit_to(struct request *req, struct nameserver *server) {
+	struct sockaddr_in sin;
+	int r;
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_addr.s_addr = req->ns->address;
+	sin.sin_port = req->ns->port;
+	sin.sin_family = AF_INET;
+
+	r = sendto(server->socket, req->request, req->request_len, 0,
+	    (struct sockaddr*)&sin, sizeof(sin));
+	if (r < 0) {
+		int err = last_error(server->socket);
+		if (error_is_eagain(err)) return 1;
+		nameserver_failed(req->ns, strerror(err));
+		return 2;
+	} else if (r != (int)req->request_len) {
+		return 1;  /* short write */
+	} else {
+		return 0;
+	}
+}
+
+/* try to send a request, updating the fields of the request */
+/* as needed */
+/* */
+/* return: */
+/*   0 ok */
+/*   1 failed */
+static int
+evdns_request_transmit(struct request *req) {
+	int retcode = 0, r;
+
+	/* if we fail to send this packet then this flag marks it */
+	/* for evdns_transmit */
+	req->transmit_me = 1;
+	if (req->trans_id == 0xffff) abort();
+
+	if (req->ns->choked) {
+		/* don't bother trying to write to a socket */
+		/* which we have had EAGAIN from */
+		return 1;
+	}
+
+	r = evdns_request_transmit_to(req, req->ns);
+	switch (r) {
+	case 1:
+		/* temp failure */
+		req->ns->choked = 1;
+		nameserver_write_waiting(req->ns, 1);
+		return 1;
+	case 2:
+		/* failed in some other way */
+		retcode = 1;
+		/* fall through */
+	default:
+		/* all ok */
+		log(EVDNS_LOG_DEBUG,
+		    "Setting timeout for request %lx", (unsigned long) req);
+		if (evtimer_add(&req->timeout_event, &global_timeout) < 0) {
+                  log(EVDNS_LOG_WARN,
+		      "Error from libevent when adding timer for request %lx",
+                      (unsigned long) req);
+                  /* ???? Do more? */
+                }
+		req->tx_count++;
+		req->transmit_me = 0;
+		return retcode;
+	}
+}
+
+static void
+nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
+	struct nameserver *const ns = (struct nameserver *) arg;
+        (void) type;
+        (void) count;
+        (void) ttl;
+        (void) addresses;
+
+	if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
+		/* this is a good reply */
+		nameserver_up(ns);
+	} else nameserver_probe_failed(ns);
+}
+
+static void
+nameserver_send_probe(struct nameserver *const ns) {
+	struct request *req;
+	/* here we need to send a probe to a given nameserver */
+	/* in the hope that it is up now. */
+
+  	log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address));
+
+	req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
+        if (!req) return;
+	/* we force this into the inflight queue no matter what */
+	request_trans_id_set(req, transaction_id_pick());
+	req->ns = ns;
+	request_submit(req);
+}
+
+/* returns: */
+/*   0 didn't try to transmit anything */
+/*   1 tried to transmit something */
+static int
+evdns_transmit(void) {
+	char did_try_to_transmit = 0;
+
+	if (req_head) {
+		struct request *const started_at = req_head, *req = req_head;
+		/* first transmit all the requests which are currently waiting */
+		do {
+			if (req->transmit_me) {
+				did_try_to_transmit = 1;
+				evdns_request_transmit(req);
+			}
+
+			req = req->next;
+		} while (req != started_at);
+	}
+
+	return did_try_to_transmit;
+}
+
+/* exported function */
+int
+evdns_count_nameservers(void)
+{
+	const struct nameserver *server = server_head;
+	int n = 0;
+	if (!server)
+		return 0;
+	do {
+		++n;
+		server = server->next;
+	} while (server != server_head);
+	return n;
+}
+
+/* exported function */
+int
+evdns_clear_nameservers_and_suspend(void)
+{
+	struct nameserver *server = server_head, *started_at = server_head;
+	struct request *req = req_head, *req_started_at = req_head;
+
+	if (!server)
+		return 0;
+	while (1) {
+		struct nameserver *next = server->next;
+		(void) event_del(&server->event);
+		if (evtimer_initialized(&server->timeout_event))
+			(void) evtimer_del(&server->timeout_event);
+		if (server->socket >= 0)
+			CLOSE_SOCKET(server->socket);
+		free(server);
+		if (next == started_at)
+			break;
+		server = next;
+	}
+	server_head = NULL;
+	global_good_nameservers = 0;
+
+	while (req) {
+		struct request *next = req->next;
+		req->tx_count = req->reissue_count = 0;
+		req->ns = NULL;
+		/* ???? What to do about searches? */
+		(void) evtimer_del(&req->timeout_event);
+		req->trans_id = 0;
+		req->transmit_me = 0;
+
+		global_requests_waiting++;
+		evdns_request_insert(req, &req_waiting_head);
+		/* We want to insert these suspended elements at the front of
+		 * the waiting queue, since they were pending before any of
+		 * the waiting entries were added.  This is a circular list,
+		 * so we can just shift the start back by one.*/
+		req_waiting_head = req_waiting_head->prev;
+
+		if (next == req_started_at)
+			break;
+		req = next;
+	}
+	req_head = NULL;
+	global_requests_inflight = 0;
+
+	return 0;
+}
+
+
+/* exported function */
+int
+evdns_resume(void)
+{
+	evdns_requests_pump_waiting_queue();
+	return 0;
+}
+
+static int
+_evdns_nameserver_add_impl(unsigned long int address, int port) {
+	/* first check to see if we already have this nameserver */
+
+	const struct nameserver *server = server_head, *const started_at = server_head;
+	struct nameserver *ns;
+	int err = 0;
+	if (server) {
+		do {
+			if (server->address == address) return 3;
+			server = server->next;
+		} while (server != started_at);
+	}
+
+	ns = (struct nameserver *) malloc(sizeof(struct nameserver));
+        if (!ns) return -1;
+
+	memset(ns, 0, sizeof(struct nameserver));
+
+	evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
+
+	ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
+	if (ns->socket < 0) { err = 1; goto out1; }
+        evutil_make_socket_nonblocking(ns->socket);
+
+	ns->address = address;
+	ns->port = htons(port);
+	ns->state = 1;
+	event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
+	if (event_add(&ns->event, NULL) < 0) {
+          err = 2;
+          goto out2;
+        }
+
+	log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address));
+
+	/* insert this nameserver into the list of them */
+	if (!server_head) {
+		ns->next = ns->prev = ns;
+		server_head = ns;
+	} else {
+		ns->next = server_head->next;
+		ns->prev = server_head;
+		server_head->next = ns;
+		if (server_head->prev == server_head) {
+			server_head->prev = ns;
+		}
+	}
+
+	global_good_nameservers++;
+
+	return 0;
+
+out2:
+	CLOSE_SOCKET(ns->socket);
+out1:
+	free(ns);
+	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err);
+	return err;
+}
+
+/* exported function */
+int
+evdns_nameserver_add(unsigned long int address) {
+	return _evdns_nameserver_add_impl(address, 53);
+}
+
+/* exported function */
+int
+evdns_nameserver_ip_add(const char *ip_as_string) {
+	struct in_addr ina;
+	int port;
+	char buf[20];
+	const char *cp;
+	cp = strchr(ip_as_string, ':');
+	if (! cp) {
+		cp = ip_as_string;
+		port = 53;
+	} else {
+		port = strtoint(cp+1);
+		if (port < 0 || port > 65535) {
+			return 4;
+		}
+		if ((cp-ip_as_string) >= (int)sizeof(buf)) {
+			return 4;
+		}
+		memcpy(buf, ip_as_string, cp-ip_as_string);
+		buf[cp-ip_as_string] = '\0';
+		cp = buf;
+	}
+	if (!inet_aton(cp, &ina)) {
+		return 4;
+	}
+	return _evdns_nameserver_add_impl(ina.s_addr, port);
+}
+
+/* insert into the tail of the queue */
+static void
+evdns_request_insert(struct request *req, struct request **head) {
+	if (!*head) {
+		*head = req;
+		req->next = req->prev = req;
+		return;
+	}
+
+	req->prev = (*head)->prev;
+	req->prev->next = req;
+	req->next = *head;
+	(*head)->prev = req;
+}
+
+static int
+string_num_dots(const char *s) {
+	int count = 0;
+	while ((s = strchr(s, '.'))) {
+		s++;
+		count++;
+	}
+	return count;
+}
+
+static struct request *
+request_new(int type, const char *name, int flags,
+    evdns_callback_type callback, void *user_ptr) {
+	const char issuing_now =
+	    (global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
+
+	const int name_len = strlen(name);
+	const int request_max_len = evdns_request_len(name_len);
+	const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
+	/* the request data is alloced in a single block with the header */
+	struct request *const req =
+	    (struct request *) malloc(sizeof(struct request) + request_max_len);
+	int rlen;
+        (void) flags;
+
+        if (!req) return NULL;
+	memset(req, 0, sizeof(struct request));
+
+	evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
+
+	/* request data lives just after the header */
+	req->request = ((u8 *) req) + sizeof(struct request);
+	/* denotes that the request data shouldn't be free()ed */
+	req->request_appended = 1;
+	rlen = evdns_request_data_build(name, name_len, trans_id,
+	    type, CLASS_INET, req->request, request_max_len);
+	if (rlen < 0)
+		goto err1;
+	req->request_len = rlen;
+	req->trans_id = trans_id;
+	req->tx_count = 0;
+	req->request_type = type;
+	req->user_pointer = user_ptr;
+	req->user_callback = callback;
+	req->ns = issuing_now ? nameserver_pick() : NULL;
+	req->next = req->prev = NULL;
+
+	return req;
+err1:
+	free(req);
+	return NULL;
+}
+
+static void
+request_submit(struct request *const req) {
+	if (req->ns) {
+		/* if it has a nameserver assigned then this is going */
+		/* straight into the inflight queue */
+		evdns_request_insert(req, &req_head);
+		global_requests_inflight++;
+		evdns_request_transmit(req);
+	} else {
+		evdns_request_insert(req, &req_waiting_head);
+		global_requests_waiting++;
+	}
+}
+
+/* exported function */
+int evdns_resolve_ipv4(const char *name, int flags,
+    evdns_callback_type callback, void *ptr) {
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+	if (flags & DNS_QUERY_NO_SEARCH) {
+		struct request *const req =
+			request_new(TYPE_A, name, flags, callback, ptr);
+		if (req == NULL)
+			return (1);
+		request_submit(req);
+		return (0);
+	} else {
+		return (search_request_new(TYPE_A, name, flags, callback, ptr));
+	}
+}
+
+/* exported function */
+int evdns_resolve_ipv6(const char *name, int flags,
+					   evdns_callback_type callback, void *ptr) {
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+	if (flags & DNS_QUERY_NO_SEARCH) {
+		struct request *const req =
+			request_new(TYPE_AAAA, name, flags, callback, ptr);
+		if (req == NULL)
+			return (1);
+		request_submit(req);
+		return (0);
+	} else {
+		return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
+	}
+}
+
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+	char buf[32];
+	struct request *req;
+	u32 a;
+	assert(in);
+	a = ntohl(in->s_addr);
+	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+			(int)(u8)((a	)&0xff),
+			(int)(u8)((a>>8 )&0xff),
+			(int)(u8)((a>>16)&0xff),
+			(int)(u8)((a>>24)&0xff));
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+	if (!req) return 1;
+	request_submit(req);
+	return 0;
+}
+
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
+	char buf[73];
+	char *cp;
+	struct request *req;
+	int i;
+	assert(in);
+	cp = buf;
+	for (i=15; i >= 0; --i) {
+		u8 byte = in->s6_addr[i];
+		*cp++ = "0123456789abcdef"[byte & 0x0f];
+		*cp++ = '.';
+		*cp++ = "0123456789abcdef"[byte >> 4];
+		*cp++ = '.';
+	}
+	assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
+	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+	if (!req) return 1;
+	request_submit(req);
+	return 0;
+}
+
+/*/////////////////////////////////////////////////////////////////// */
+/* Search support */
+/* */
+/* the libc resolver has support for searching a number of domains */
+/* to find a name. If nothing else then it takes the single domain */
+/* from the gethostname() call. */
+/* */
+/* It can also be configured via the domain and search options in a */
+/* resolv.conf. */
+/* */
+/* The ndots option controls how many dots it takes for the resolver */
+/* to decide that a name is non-local and so try a raw lookup first. */
+
+struct search_domain {
+	int len;
+	struct search_domain *next;
+	/* the text string is appended to this structure */
+};
+
+struct search_state {
+	int refcount;
+	int ndots;
+	int num_domains;
+	struct search_domain *head;
+};
+
+static struct search_state *global_search_state = NULL;
+
+static void
+search_state_decref(struct search_state *const state) {
+	if (!state) return;
+	state->refcount--;
+	if (!state->refcount) {
+		struct search_domain *next, *dom;
+		for (dom = state->head; dom; dom = next) {
+			next = dom->next;
+			free(dom);
+		}
+		free(state);
+	}
+}
+
+static struct search_state *
+search_state_new(void) {
+	struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state));
+        if (!state) return NULL;
+	memset(state, 0, sizeof(struct search_state));
+	state->refcount = 1;
+	state->ndots = 1;
+
+	return state;
+}
+
+static void
+search_postfix_clear(void) {
+	search_state_decref(global_search_state);
+
+	global_search_state = search_state_new();
+}
+
+/* exported function */
+void
+evdns_search_clear(void) {
+	search_postfix_clear();
+}
+
+static void
+search_postfix_add(const char *domain) {
+	int domain_len;
+	struct search_domain *sdomain;
+	while (domain[0] == '.') domain++;
+	domain_len = strlen(domain);
+
+	if (!global_search_state) global_search_state = search_state_new();
+        if (!global_search_state) return;
+	global_search_state->num_domains++;
+
+	sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len);
+        if (!sdomain) return;
+	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
+	sdomain->next = global_search_state->head;
+	sdomain->len = domain_len;
+
+	global_search_state->head = sdomain;
+}
+
+/* reverse the order of members in the postfix list. This is needed because, */
+/* when parsing resolv.conf we push elements in the wrong order */
+static void
+search_reverse(void) {
+	struct search_domain *cur, *prev = NULL, *next;
+	cur = global_search_state->head;
+	while (cur) {
+		next = cur->next;
+		cur->next = prev;
+		prev = cur;
+		cur = next;
+	}
+
+	global_search_state->head = prev;
+}
+
+/* exported function */
+void
+evdns_search_add(const char *domain) {
+	search_postfix_add(domain);
+}
+
+/* exported function */
+void
+evdns_search_ndots_set(const int ndots) {
+	if (!global_search_state) global_search_state = search_state_new();
+        if (!global_search_state) return;
+	global_search_state->ndots = ndots;
+}
+
+static void
+search_set_from_hostname(void) {
+	char hostname[HOST_NAME_MAX + 1], *domainname;
+
+	search_postfix_clear();
+	if (gethostname(hostname, sizeof(hostname))) return;
+	domainname = strchr(hostname, '.');
+	if (!domainname) return;
+	search_postfix_add(domainname);
+}
+
+/* warning: returns malloced string */
+static char *
+search_make_new(const struct search_state *const state, int n, const char *const base_name) {
+	const int base_len = strlen(base_name);
+	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+	struct search_domain *dom;
+
+	for (dom = state->head; dom; dom = dom->next) {
+		if (!n--) {
+			/* this is the postfix we want */
+			/* the actual postfix string is kept at the end of the structure */
+			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
+			const int postfix_len = dom->len;
+			char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1);
+                        if (!newname) return NULL;
+			memcpy(newname, base_name, base_len);
+			if (need_to_append_dot) newname[base_len] = '.';
+			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
+			newname[base_len + need_to_append_dot + postfix_len] = 0;
+			return newname;
+		}
+	}
+
+	/* we ran off the end of the list and still didn't find the requested string */
+	abort();
+	return NULL; /* unreachable; stops warnings in some compilers. */
+}
+
+static int
+search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
+	assert(type == TYPE_A || type == TYPE_AAAA);
+	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
+	     global_search_state &&
+		 global_search_state->num_domains) {
+		/* we have some domains to search */
+		struct request *req;
+		if (string_num_dots(name) >= global_search_state->ndots) {
+			req = request_new(type, name, flags, user_callback, user_arg);
+			if (!req) return 1;
+			req->search_index = -1;
+		} else {
+			char *const new_name = search_make_new(global_search_state, 0, name);
+                        if (!new_name) return 1;
+			req = request_new(type, new_name, flags, user_callback, user_arg);
+			free(new_name);
+			if (!req) return 1;
+			req->search_index = 0;
+		}
+		req->search_origname = strdup(name);
+		req->search_state = global_search_state;
+		req->search_flags = flags;
+		global_search_state->refcount++;
+		request_submit(req);
+		return 0;
+	} else {
+		struct request *const req = request_new(type, name, flags, user_callback, user_arg);
+		if (!req) return 1;
+		request_submit(req);
+		return 0;
+	}
+}
+
+/* this is called when a request has failed to find a name. We need to check */
+/* if it is part of a search and, if so, try the next name in the list */
+/* returns: */
+/*   0 another request has been submitted */
+/*   1 no more requests needed */
+static int
+search_try_next(struct request *const req) {
+	if (req->search_state) {
+		/* it is part of a search */
+		char *new_name;
+		struct request *newreq;
+		req->search_index++;
+		if (req->search_index >= req->search_state->num_domains) {
+			/* no more postfixes to try, however we may need to try */
+			/* this name without a postfix */
+			if (string_num_dots(req->search_origname) < req->search_state->ndots) {
+				/* yep, we need to try it raw */
+				newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
+				if (newreq) {
+					request_submit(newreq);
+					return 0;
+				}
+			}
+			return 1;
+		}
+
+		new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
+                if (!new_name) return 1;
+		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
+		newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
+		free(new_name);
+		if (!newreq) return 1;
+		newreq->search_origname = req->search_origname;
+		req->search_origname = NULL;
+		newreq->search_state = req->search_state;
+		newreq->search_flags = req->search_flags;
+		newreq->search_index = req->search_index;
+		newreq->search_state->refcount++;
+		request_submit(newreq);
+		return 0;
+	}
+	return 1;
+}
+
+static void
+search_request_finished(struct request *const req) {
+	if (req->search_state) {
+		search_state_decref(req->search_state);
+		req->search_state = NULL;
+	}
+	if (req->search_origname) {
+		free(req->search_origname);
+		req->search_origname = NULL;
+	}
+}
+
+/*/////////////////////////////////////////////////////////////////// */
+/* Parsing resolv.conf files */
+
+static void
+evdns_resolv_set_defaults(int flags) {
+	/* if the file isn't found then we assume a local resolver */
+	if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
+	if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
+}
+
+#ifndef HAVE_STRTOK_R
+static char *
+strtok_r(char *s, const char *delim, char **state) {
+	return strtok(s, delim);
+}
+#endif
+
+/* helper version of atoi which returns -1 on error */
+static int
+strtoint(const char *const str) {
+	char *endptr;
+	const int r = strtol(str, &endptr, 10);
+	if (*endptr) return -1;
+	return r;
+}
+
+/* helper version of atoi that returns -1 on error and clips to bounds. */
+static int
+strtoint_clipped(const char *const str, int min, int max)
+{
+	int r = strtoint(str);
+	if (r == -1)
+		return r;
+	else if (r<min)
+		return min;
+	else if (r>max)
+		return max;
+	else
+		return r;
+}
+
+/* exported function */
+int
+evdns_set_option(const char *option, const char *val, int flags)
+{
+	if (!strncmp(option, "ndots:", 6)) {
+		const int ndots = strtoint(val);
+		if (ndots == -1) return -1;
+		if (!(flags & DNS_OPTION_SEARCH)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
+		if (!global_search_state) global_search_state = search_state_new();
+		if (!global_search_state) return -1;
+		global_search_state->ndots = ndots;
+	} else if (!strncmp(option, "timeout:", 8)) {
+		const int timeout = strtoint(val);
+		if (timeout == -1) return -1;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
+		global_timeout.tv_sec = timeout;
+	} else if (!strncmp(option, "max-timeouts:", 12)) {
+		const int maxtimeout = strtoint_clipped(val, 1, 255);
+		if (maxtimeout == -1) return -1;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
+			maxtimeout);
+		global_max_nameserver_timeout = maxtimeout;
+	} else if (!strncmp(option, "max-inflight:", 13)) {
+		const int maxinflight = strtoint_clipped(val, 1, 65000);
+		if (maxinflight == -1) return -1;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
+			maxinflight);
+		global_max_requests_inflight = maxinflight;
+	} else if (!strncmp(option, "attempts:", 9)) {
+		int retries = strtoint(val);
+		if (retries == -1) return -1;
+		if (retries > 255) retries = 255;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
+		global_max_retransmits = retries;
+	}
+	return 0;
+}
+
+static void
+resolv_conf_parse_line(char *const start, int flags) {
+	char *strtok_state;
+	static const char *const delims = " \t";
+#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
+
+	char *const first_token = strtok_r(start, delims, &strtok_state);
+	if (!first_token) return;
+
+	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
+		const char *const nameserver = NEXT_TOKEN;
+		struct in_addr ina;
+
+		if (inet_aton(nameserver, &ina)) {
+			/* address is valid */
+			evdns_nameserver_add(ina.s_addr);
+		}
+	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
+		const char *const domain = NEXT_TOKEN;
+		if (domain) {
+			search_postfix_clear();
+			search_postfix_add(domain);
+		}
+	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
+		const char *domain;
+		search_postfix_clear();
+
+		while ((domain = NEXT_TOKEN)) {
+			search_postfix_add(domain);
+		}
+		search_reverse();
+	} else if (!strcmp(first_token, "options")) {
+		const char *option;
+		while ((option = NEXT_TOKEN)) {
+			const char *val = strchr(option, ':');
+			evdns_set_option(option, val ? val+1 : "", flags);
+		}
+	}
+#undef NEXT_TOKEN
+}
+
+/* exported function */
+/* returns: */
+/*   0 no errors */
+/*   1 failed to open file */
+/*   2 failed to stat file */
+/*   3 file too large */
+/*   4 out of memory */
+/*   5 short read from file */
+int
+evdns_resolv_conf_parse(int flags, const char *const filename) {
+	struct stat st;
+	int fd, n, r;
+	u8 *resolv;
+	char *start;
+	int err = 0;
+
+	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		evdns_resolv_set_defaults(flags);
+		return 1;
+	}
+
+	if (fstat(fd, &st)) { err = 2; goto out1; }
+	if (!st.st_size) {
+		evdns_resolv_set_defaults(flags);
+		err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
+		goto out1;
+	}
+	if (st.st_size > 65535) { err = 3; goto out1; }  /* no resolv.conf should be any bigger */
+
+	resolv = (u8 *) malloc((size_t)st.st_size + 1);
+	if (!resolv) { err = 4; goto out1; }
+
+	n = 0;
+	while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
+		n += r;
+		if (n == st.st_size)
+			break;
+		assert(n < st.st_size);
+ 	}
+	if (r < 0) { err = 5; goto out2; }
+	resolv[n] = 0;	 /* we malloced an extra byte; this should be fine. */
+
+	start = (char *) resolv;
+	for (;;) {
+		char *const newline = strchr(start, '\n');
+		if (!newline) {
+			resolv_conf_parse_line(start, flags);
+			break;
+		} else {
+			*newline = 0;
+			resolv_conf_parse_line(start, flags);
+			start = newline + 1;
+		}
+	}
+
+	if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
+		/* no nameservers were configured. */
+		evdns_nameserver_ip_add("127.0.0.1");
+		err = 6;
+	}
+	if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
+		search_set_from_hostname();
+	}
+
+out2:
+	free(resolv);
+out1:
+	close(fd);
+	return err;
+}
+
+#ifdef WIN32
+/* Add multiple nameservers from a space-or-comma-separated list. */
+static int
+evdns_nameserver_ip_add_line(const char *ips) {
+	const char *addr;
+	char *buf;
+	int r;
+	while (*ips) {
+		while (ISSPACE(*ips) || *ips == ',' || *ips == '\t')
+			++ips;
+		addr = ips;
+		while (ISDIGIT(*ips) || *ips == '.' || *ips == ':')
+			++ips;
+		buf = malloc(ips-addr+1);
+		if (!buf) return 4;
+		memcpy(buf, addr, ips-addr);
+		buf[ips-addr] = '\0';
+		r = evdns_nameserver_ip_add(buf);
+		free(buf);
+		if (r) return r;
+	}
+	return 0;
+}
+
+typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
+
+/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
+/* figure out what our nameservers are. */
+static int
+load_nameservers_with_getnetworkparams(void)
+{
+	/* Based on MSDN examples and inspection of  c-ares code. */
+	FIXED_INFO *fixed;
+	HMODULE handle = 0;
+	ULONG size = sizeof(FIXED_INFO);
+	void *buf = NULL;
+	int status = 0, r, added_any;
+	IP_ADDR_STRING *ns;
+	GetNetworkParams_fn_t fn;
+
+	if (!(handle = LoadLibrary("iphlpapi.dll"))) {
+		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
+		status = -1;
+		goto done;
+	}
+	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
+		log(EVDNS_LOG_WARN, "Could not get address of function.");
+		status = -1;
+		goto done;
+	}
+
+	buf = malloc(size);
+	if (!buf) { status = 4; goto done; }
+	fixed = buf;
+	r = fn(fixed, &size);
+	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
+		status = -1;
+		goto done;
+	}
+	if (r != ERROR_SUCCESS) {
+		free(buf);
+		buf = malloc(size);
+		if (!buf) { status = 4; goto done; }
+		fixed = buf;
+		r = fn(fixed, &size);
+		if (r != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG, "fn() failed.");
+			status = -1;
+			goto done;
+		}
+	}
+
+	assert(fixed);
+	added_any = 0;
+	ns = &(fixed->DnsServerList);
+	while (ns) {
+		r = evdns_nameserver_ip_add_line(ns->IpAddress.String);
+		if (r) {
+			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
+				(ns->IpAddress.String),(int)GetLastError());
+			status = r;
+			goto done;
+		} else {
+			log(EVDNS_LOG_DEBUG,"Succesfully added %s as nameserver",ns->IpAddress.String);
+		}
+
+		added_any++;
+		ns = ns->Next;
+	}
+
+	if (!added_any) {
+		log(EVDNS_LOG_DEBUG, "No nameservers added.");
+		status = -1;
+	}
+
+ done:
+	if (buf)
+		free(buf);
+	if (handle)
+		FreeLibrary(handle);
+	return status;
+}
+
+static int
+config_nameserver_from_reg_key(HKEY key, const char *subkey)
+{
+	char *buf;
+	DWORD bufsz = 0, type = 0;
+	int status = 0;
+
+	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
+	    != ERROR_MORE_DATA)
+		return -1;
+	if (!(buf = malloc(bufsz)))
+		return -1;
+
+	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
+	    == ERROR_SUCCESS && bufsz > 1) {
+		status = evdns_nameserver_ip_add_line(buf);
+	}
+
+	free(buf);
+	return status;
+}
+
+#define SERVICES_KEY "System\\CurrentControlSet\\Services\\"
+#define WIN_NS_9X_KEY  SERVICES_KEY "VxD\\MSTCP"
+#define WIN_NS_NT_KEY  SERVICES_KEY "Tcpip\\Parameters"
+
+static int
+load_nameservers_from_registry(void)
+{
+	int found = 0;
+	int r;
+#define TRY(k, name) \
+	if (!found && config_nameserver_from_reg_key(k,name) == 0) {	\
+		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
+		found = 1;						\
+	} else if (!found) {						\
+		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
+		    #k,#name);						\
+	}
+
+	if (((int)GetVersion()) > 0) { /* NT */
+		HKEY nt_key = 0, interfaces_key = 0;
+
+		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+				 KEY_READ, &nt_key) != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
+			return -1;
+		}
+		r = RegOpenKeyEx(nt_key, "Interfaces", 0,
+			     KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
+			     &interfaces_key);
+		if (r != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
+			return -1;
+		}
+		TRY(nt_key, "NameServer");
+		TRY(nt_key, "DhcpNameServer");
+		TRY(interfaces_key, "NameServer");
+		TRY(interfaces_key, "DhcpNameServer");
+		RegCloseKey(interfaces_key);
+		RegCloseKey(nt_key);
+	} else {
+		HKEY win_key = 0;
+		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
+				 KEY_READ, &win_key) != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
+			return -1;
+		}
+		TRY(win_key, "NameServer");
+		RegCloseKey(win_key);
+	}
+
+	if (found == 0) {
+		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
+	}
+
+	return found ? 0 : -1;
+#undef TRY
+}
+
+int
+evdns_config_windows_nameservers(void)
+{
+	if (load_nameservers_with_getnetworkparams() == 0)
+		return 0;
+	return load_nameservers_from_registry();
+}
+#endif
+
+int
+evdns_init(void)
+{
+	int res = 0;
+#ifdef WIN32
+	res = evdns_config_windows_nameservers();
+#else
+	res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+#endif
+
+	return (res);
+}
+
+const char *
+evdns_err_to_string(int err)
+{
+    switch (err) {
+	case DNS_ERR_NONE: return "no error";
+	case DNS_ERR_FORMAT: return "misformatted query";
+	case DNS_ERR_SERVERFAILED: return "server failed";
+	case DNS_ERR_NOTEXIST: return "name does not exist";
+	case DNS_ERR_NOTIMPL: return "query not implemented";
+	case DNS_ERR_REFUSED: return "refused";
+
+	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
+	case DNS_ERR_UNKNOWN: return "unknown";
+	case DNS_ERR_TIMEOUT: return "request timed out";
+	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
+	default: return "[Unknown error code]";
+    }
+}
+
+void
+evdns_shutdown(int fail_requests)
+{
+	struct nameserver *server, *server_next;
+	struct search_domain *dom, *dom_next;
+
+	while (req_head) {
+		if (fail_requests)
+			reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL);
+		request_finished(req_head, &req_head);
+	}
+	while (req_waiting_head) {
+		if (fail_requests)
+			reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
+		request_finished(req_waiting_head, &req_waiting_head);
+	}
+	global_requests_inflight = global_requests_waiting = 0;
+
+	for (server = server_head; server; server = server_next) {
+		server_next = server->next;
+		if (server->socket >= 0)
+			CLOSE_SOCKET(server->socket);
+		(void) event_del(&server->event);
+		if (server->state == 0)
+                        (void) event_del(&server->timeout_event);
+		free(server);
+		if (server_next == server_head)
+			break;
+	}
+	server_head = NULL;
+	global_good_nameservers = 0;
+
+	if (global_search_state) {
+		for (dom = global_search_state->head; dom; dom = dom_next) {
+			dom_next = dom->next;
+			free(dom);
+		}
+		free(global_search_state);
+		global_search_state = NULL;
+	}
+	evdns_log_fn = NULL;
+}
+
+#ifdef EVDNS_MAIN
+void
+main_callback(int result, char type, int count, int ttl,
+			  void *addrs, void *orig) {
+	char *n = (char*)orig;
+	int i;
+	for (i = 0; i < count; ++i) {
+		if (type == DNS_IPv4_A) {
+			printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
+		} else if (type == DNS_PTR) {
+			printf("%s: %s\n", n, ((char**)addrs)[i]);
+		}
+	}
+	if (!count) {
+		printf("%s: No answer (%d)\n", n, result);
+	}
+	fflush(stdout);
+}
+void
+evdns_server_callback(struct evdns_server_request *req, void *data)
+{
+	int i, r;
+	(void)data;
+	/* dummy; give 192.168.11.11 as an answer for all A questions,
+	 *	give foo.bar.example.com as an answer for all PTR questions. */
+	for (i = 0; i < req->nquestions; ++i) {
+		u32 ans = htonl(0xc0a80b0bUL);
+		if (req->questions[i]->type == EVDNS_TYPE_A &&
+			req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+			printf(" -- replying for %s (A)\n", req->questions[i]->name);
+			r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
+										  1, &ans, 10);
+			if (r<0)
+				printf("eeep, didn't work.\n");
+		} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
+				   req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+			printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
+			r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
+											"foo.bar.example.com", 10);
+		} else {
+			printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
+				   req->questions[i]->type, req->questions[i]->dns_question_class);
+		}
+	}
+
+	r = evdns_request_respond(req, 0);
+	if (r<0)
+		printf("eeek, couldn't send reply.\n");
+}
+
+void
+logfn(int is_warn, const char *msg) {
+  (void) is_warn;
+  fprintf(stderr, "%s\n", msg);
+}
+int
+main(int c, char **v) {
+	int idx;
+	int reverse = 0, verbose = 1, servertest = 0;
+	if (c<2) {
+		fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
+		fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
+		return 1;
+	}
+	idx = 1;
+	while (idx < c && v[idx][0] == '-') {
+		if (!strcmp(v[idx], "-x"))
+			reverse = 1;
+		else if (!strcmp(v[idx], "-v"))
+			verbose = 1;
+		else if (!strcmp(v[idx], "-servertest"))
+			servertest = 1;
+		else
+			fprintf(stderr, "Unknown option %s\n", v[idx]);
+		++idx;
+	}
+	event_init();
+	if (verbose)
+		evdns_set_log_fn(logfn);
+	evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
+	if (servertest) {
+		int sock;
+		struct sockaddr_in my_addr;
+		sock = socket(PF_INET, SOCK_DGRAM, 0);
+                evutil_make_socket_nonblocking(sock);
+		my_addr.sin_family = AF_INET;
+		my_addr.sin_port = htons(10053);
+		my_addr.sin_addr.s_addr = INADDR_ANY;
+		if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
+			perror("bind");
+			exit(1);
+		}
+		evdns_add_server_port(sock, 0, evdns_server_callback, NULL);
+	}
+	for (; idx < c; ++idx) {
+		if (reverse) {
+			struct in_addr addr;
+			if (!inet_aton(v[idx], &addr)) {
+				fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
+				continue;
+			}
+			fprintf(stderr, "resolving %s...\n",v[idx]);
+			evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
+		} else {
+			fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
+			evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
+		}
+	}
+	fflush(stdout);
+	event_dispatch();
+	return 0;
+}
+#endif
diff --git a/third_party/libevent/evdns.h b/third_party/libevent/evdns.h
new file mode 100644
index 0000000..fca4ac3
--- /dev/null
+++ b/third_party/libevent/evdns.h
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The original DNS code is due to Adam Langley with heavy
+ * modifications by Nick Mathewson.  Adam put his DNS software in the
+ * public domain.  You can find his original copyright below.  Please,
+ * aware that the code as part of libevent is governed by the 3-clause
+ * BSD license above.
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * 	Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ */
+
+/** @file evdns.h
+ *
+ * Welcome, gentle reader
+ *
+ * Async DNS lookups are really a whole lot harder than they should be,
+ * mostly stemming from the fact that the libc resolver has never been
+ * very good at them. Before you use this library you should see if libc
+ * can do the job for you with the modern async call getaddrinfo_a
+ * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+ * please continue.
+ *
+ * This code is based on libevent and you must call event_init before
+ * any of the APIs in this file. You must also seed the OpenSSL random
+ * source if you are using OpenSSL for ids (see below).
+ *
+ * This library is designed to be included and shipped with your source
+ * code. You statically link with it. You should also test for the
+ * existence of strtok_r and define HAVE_STRTOK_R if you have it.
+ *
+ * The DNS protocol requires a good source of id numbers and these
+ * numbers should be unpredictable for spoofing reasons. There are
+ * three methods for generating them here and you must define exactly
+ * one of them. In increasing order of preference:
+ *
+ * DNS_USE_GETTIMEOFDAY_FOR_ID:
+ *   Using the bottom 16 bits of the usec result from gettimeofday. This
+ *   is a pretty poor solution but should work anywhere.
+ * DNS_USE_CPU_CLOCK_FOR_ID:
+ *   Using the bottom 16 bits of the nsec result from the CPU's time
+ *   counter. This is better, but may not work everywhere. Requires
+ *   POSIX realtime support and you'll need to link against -lrt on
+ *   glibc systems at least.
+ * DNS_USE_OPENSSL_FOR_ID:
+ *   Uses the OpenSSL RAND_bytes call to generate the data. You must
+ *   have seeded the pool before making any calls to this library.
+ *
+ * The library keeps track of the state of nameservers and will avoid
+ * them when they go down. Otherwise it will round robin between them.
+ *
+ * Quick start guide:
+ *   #include "evdns.h"
+ *   void callback(int result, char type, int count, int ttl,
+ *		 void *addresses, void *arg);
+ *   evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ *   evdns_resolve("www.hostname.com", 0, callback, NULL);
+ *
+ * When the lookup is complete the callback function is called. The
+ * first argument will be one of the DNS_ERR_* defines in evdns.h.
+ * Hopefully it will be DNS_ERR_NONE, in which case type will be
+ * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+ * which the data can be cached for (in seconds), addresses will point
+ * to an array of uint32_t's and arg will be whatever you passed to
+ * evdns_resolve.
+ *
+ * Searching:
+ *
+ * In order for this library to be a good replacement for glibc's resolver it
+ * supports searching. This involves setting a list of default domains, in
+ * which names will be queried for. The number of dots in the query name
+ * determines the order in which this list is used.
+ *
+ * Searching appears to be a single lookup from the point of view of the API,
+ * although many DNS queries may be generated from a single call to
+ * evdns_resolve. Searching can also drastically slow down the resolution
+ * of names.
+ *
+ * To disable searching:
+ *   1. Never set it up. If you never call evdns_resolv_conf_parse or
+ *   evdns_search_add then no searching will occur.
+ *
+ *   2. If you do call evdns_resolv_conf_parse then don't pass
+ *   DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
+ *
+ *   3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
+ *
+ * The order of searches depends on the number of dots in the name. If the
+ * number is greater than the ndots setting then the names is first tried
+ * globally. Otherwise each search domain is appended in turn.
+ *
+ * The ndots setting can either be set from a resolv.conf, or by calling
+ * evdns_search_ndots_set.
+ *
+ * For example, with ndots set to 1 (the default) and a search domain list of
+ * ["myhome.net"]:
+ *  Query: www
+ *  Order: www.myhome.net, www.
+ *
+ *  Query: www.abc
+ *  Order: www.abc., www.abc.myhome.net
+ *
+ * Internals:
+ *
+ * Requests are kept in two queues. The first is the inflight queue. In
+ * this queue requests have an allocated transaction id and nameserver.
+ * They will soon be transmitted if they haven't already been.
+ *
+ * The second is the waiting queue. The size of the inflight ring is
+ * limited and all other requests wait in waiting queue for space. This
+ * bounds the number of concurrent requests so that we don't flood the
+ * nameserver. Several algorithms require a full walk of the inflight
+ * queue and so bounding its size keeps thing going nicely under huge
+ * (many thousands of requests) loads.
+ *
+ * If a nameserver loses too many requests it is considered down and we
+ * try not to use it. After a while we send a probe to that nameserver
+ * (a lookup for google.com) and, if it replies, we consider it working
+ * again. If the nameserver fails a probe we wait longer to try again
+ * with the next probe.
+ */
+
+#ifndef EVENTDNS_H
+#define EVENTDNS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For integer types. */
+#include "evutil.h"
+
+/** Error codes 0-5 are as described in RFC 1035. */
+#define DNS_ERR_NONE 0
+/** The name server was unable to interpret the query */
+#define DNS_ERR_FORMAT 1
+/** The name server was unable to process this query due to a problem with the
+ * name server */
+#define DNS_ERR_SERVERFAILED 2
+/** The domain name does not exist */
+#define DNS_ERR_NOTEXIST 3
+/** The name server does not support the requested kind of query */
+#define DNS_ERR_NOTIMPL 4
+/** The name server refuses to reform the specified operation for policy
+ * reasons */
+#define DNS_ERR_REFUSED 5
+/** The reply was truncated or ill-formated */
+#define DNS_ERR_TRUNCATED 65
+/** An unknown error occurred */
+#define DNS_ERR_UNKNOWN 66
+/** Communication with the server timed out */
+#define DNS_ERR_TIMEOUT 67
+/** The request was canceled because the DNS subsystem was shut down. */
+#define DNS_ERR_SHUTDOWN 68
+
+#define DNS_IPv4_A 1
+#define DNS_PTR 2
+#define DNS_IPv6_AAAA 3
+
+#define DNS_QUERY_NO_SEARCH 1
+
+#define DNS_OPTION_SEARCH 1
+#define DNS_OPTION_NAMESERVERS 2
+#define DNS_OPTION_MISC 4
+#define DNS_OPTIONS_ALL 7
+
+/**
+ * The callback that contains the results from a lookup.
+ * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
+ * - count contains the number of addresses of form type
+ * - ttl is the number of seconds the resolution may be cached for.
+ * - addresses needs to be cast according to type
+ */
+typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
+
+/**
+  Initialize the asynchronous DNS library.
+
+  This function initializes support for non-blocking name resolution by
+  calling evdns_resolv_conf_parse() on UNIX and
+  evdns_config_windows_nameservers() on Windows.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_shutdown()
+ */
+int evdns_init(void);
+
+
+/**
+  Shut down the asynchronous DNS resolver and terminate all active requests.
+
+  If the 'fail_requests' option is enabled, all active requests will return
+  an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
+  the requests will be silently discarded.
+
+  @param fail_requests if zero, active requests will be aborted; if non-zero,
+		active requests will return DNS_ERR_SHUTDOWN.
+  @see evdns_init()
+ */
+void evdns_shutdown(int fail_requests);
+
+
+/**
+  Convert a DNS error code to a string.
+
+  @param err the DNS error code
+  @return a string containing an explanation of the error code
+*/
+const char *evdns_err_to_string(int err);
+
+
+/**
+  Add a nameserver.
+
+  The address should be an IPv4 address in network byte order.
+  The type of address is chosen so that it matches in_addr.s_addr.
+
+  @param address an IP address in network byte order
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_nameserver_ip_add()
+ */
+int evdns_nameserver_add(unsigned long int address);
+
+
+/**
+  Get the number of configured nameservers.
+
+  This returns the number of configured nameservers (not necessarily the
+  number of running nameservers).  This is useful for double-checking
+  whether our calls to the various nameserver configuration functions
+  have been successful.
+
+  @return the number of configured nameservers
+  @see evdns_nameserver_add()
+ */
+int evdns_count_nameservers(void);
+
+
+/**
+  Remove all configured nameservers, and suspend all pending resolves.
+
+  Resolves will not necessarily be re-attempted until evdns_resume() is called.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resume()
+ */
+int evdns_clear_nameservers_and_suspend(void);
+
+
+/**
+  Resume normal operation and continue any suspended resolve requests.
+
+  Re-attempt resolves left in limbo after an earlier call to
+  evdns_clear_nameservers_and_suspend().
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_clear_nameservers_and_suspend()
+ */
+int evdns_resume(void);
+
+
+/**
+  Add a nameserver.
+
+  This wraps the evdns_nameserver_add() function by parsing a string as an IP
+  address and adds it as a nameserver.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_nameserver_add()
+ */
+int evdns_nameserver_ip_add(const char *ip_as_string);
+
+
+/**
+  Lookup an A record for a given name.
+
+  @param name a DNS hostname
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+  Lookup an AAAA record for a given name.
+
+  @param name a DNS hostname
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+struct in_addr;
+struct in6_addr;
+
+/**
+  Lookup a PTR record for a given IP address.
+
+  @param in an IPv4 address
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+  Lookup a PTR record for a given IPv6 address.
+
+  @param in an IPv6 address
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+  Set the value of a configuration option.
+
+  The currently available configuration options are:
+
+    ndots, timeout, max-timeouts, max-inflight, and attempts
+
+  @param option the name of the configuration option to be modified
+  @param val the value to be set
+  @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC
+  @return 0 if successful, or -1 if an error occurred
+ */
+int evdns_set_option(const char *option, const char *val, int flags);
+
+
+/**
+  Parse a resolv.conf file.
+
+  The 'flags' parameter determines what information is parsed from the
+  resolv.conf file. See the man page for resolv.conf for the format of this
+  file.
+
+  The following directives are not parsed from the file: sortlist, rotate,
+  no-check-names, inet6, debug.
+
+  If this function encounters an error, the possible return values are: 1 =
+  failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
+  memory, 5 = short read from file, 6 = no nameservers listed in the file
+
+  @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
+         DNS_OPTIONS_ALL
+  @param filename the path to the resolv.conf file
+  @return 0 if successful, or various positive error codes if an error
+          occurred (see above)
+  @see resolv.conf(3), evdns_config_windows_nameservers()
+ */
+int evdns_resolv_conf_parse(int flags, const char *const filename);
+
+
+/**
+  Obtain nameserver information using the Windows API.
+
+  Attempt to configure a set of nameservers based on platform settings on
+  a win32 host.  Preferentially tries to use GetNetworkParams; if that fails,
+  looks in the registry.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolv_conf_parse()
+ */
+#ifdef WIN32
+int evdns_config_windows_nameservers(void);
+#endif
+
+
+/**
+  Clear the list of search domains.
+ */
+void evdns_search_clear(void);
+
+
+/**
+  Add a domain to the list of search domains
+
+  @param domain the domain to be added to the search list
+ */
+void evdns_search_add(const char *domain);
+
+
+/**
+  Set the 'ndots' parameter for searches.
+
+  Sets the number of dots which, when found in a name, causes
+  the first query to be without any search domain.
+
+  @param ndots the new ndots parameter
+ */
+void evdns_search_ndots_set(const int ndots);
+
+/**
+  A callback that is invoked when a log message is generated
+
+  @param is_warning indicates if the log message is a 'warning'
+  @param msg the content of the log message
+ */
+typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
+
+
+/**
+  Set the callback function to handle log messages.
+
+  @param fn the callback to be invoked when a log message is generated
+ */
+void evdns_set_log_fn(evdns_debug_log_fn_type fn);
+
+/**
+   Set a callback that will be invoked to generate transaction IDs.  By
+   default, we pick transaction IDs based on the current clock time.
+
+   @param fn the new callback, or NULL to use the default.
+ */
+void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
+
+#define DNS_NO_SEARCH 1
+
+/*
+ * Structures and functions used to implement a DNS server.
+ */
+
+struct evdns_server_request {
+	int flags;
+	int nquestions;
+	struct evdns_server_question **questions;
+};
+struct evdns_server_question {
+	int type;
+#ifdef __cplusplus
+	int dns_question_class;
+#else
+	/* You should refer to this field as "dns_question_class".  The
+	 * name "class" works in C for backward compatibility, and will be
+	 * removed in a future version. (1.5 or later). */
+	int class;
+#define dns_question_class class
+#endif
+	char name[1];
+};
+typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
+#define EVDNS_ANSWER_SECTION 0
+#define EVDNS_AUTHORITY_SECTION 1
+#define EVDNS_ADDITIONAL_SECTION 2
+
+#define EVDNS_TYPE_A	   1
+#define EVDNS_TYPE_NS	   2
+#define EVDNS_TYPE_CNAME   5
+#define EVDNS_TYPE_SOA	   6
+#define EVDNS_TYPE_PTR	  12
+#define EVDNS_TYPE_MX	  15
+#define EVDNS_TYPE_TXT	  16
+#define EVDNS_TYPE_AAAA	  28
+
+#define EVDNS_QTYPE_AXFR 252
+#define EVDNS_QTYPE_ALL	 255
+
+#define EVDNS_CLASS_INET   1
+
+struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
+void evdns_close_server_port(struct evdns_server_port *port);
+
+int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
+int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
+int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
+int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
+int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
+
+int evdns_server_request_respond(struct evdns_server_request *req, int err);
+int evdns_server_request_drop(struct evdns_server_request *req);
+struct sockaddr;
+int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* !EVENTDNS_H */
diff --git a/third_party/libevent/event-config.h b/third_party/libevent/event-config.h
new file mode 100644
index 0000000..c5c0e75
--- /dev/null
+++ b/third_party/libevent/event-config.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.
+
+// This file is Chromium-specific, and brings in the appropriate
+// event-config.h depending on your platform.
+
+#if defined(__native_client_nonsfi__)
+#include "third_party/libevent/nacl_nonsfi/event-config.h"
+#elif defined(__APPLE__)
+#include "third_party/libevent/mac/event-config.h"
+#elif defined(ANDROID)
+#include "third_party/libevent/android/event-config.h"
+#elif defined(__linux__)
+#include "third_party/libevent/linux/event-config.h"
+#elif defined(__FreeBSD__)
+#include "third_party/libevent/freebsd/event-config.h"
+#elif defined(__sun)
+#include "third_party/libevent/solaris/event-config.h"
+#else
+#error generate event-config.h for your platform
+#endif
diff --git a/third_party/libevent/event-internal.h b/third_party/libevent/event-internal.h
new file mode 100644
index 0000000..b7f0040
--- /dev/null
+++ b/third_party/libevent/event-internal.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVENT_INTERNAL_H_
+#define _EVENT_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+#include "min_heap.h"
+#include "evsignal.h"
+
+struct eventop {
+	const char *name;
+	void *(*init)(struct event_base *);
+	int (*add)(void *, struct event *);
+	int (*del)(void *, struct event *);
+	int (*dispatch)(struct event_base *, void *, struct timeval *);
+	void (*dealloc)(struct event_base *, void *);
+	/* set if we need to reinitialize the event base */
+	int need_reinit;
+};
+
+struct event_base {
+	const struct eventop *evsel;
+	void *evbase;
+	int event_count;		/* counts number of total events */
+	int event_count_active;	/* counts number of active events */
+
+	int event_gotterm;		/* Set to terminate loop */
+	int event_break;		/* Set to terminate loop immediately */
+
+	/* active event management */
+	struct event_list **activequeues;
+	int nactivequeues;
+
+	/* signal handling info */
+	struct evsignal_info sig;
+
+	struct event_list eventqueue;
+	struct timeval event_tv;
+
+	struct min_heap timeheap;
+
+	struct timeval tv_cache;
+};
+
+/* Internal use only: Functions that might be missing from <sys/queue.h> */
+#ifndef HAVE_TAILQFOREACH
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_END(head)			NULL
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+#define TAILQ_FOREACH(var, head, field)					\
+	for((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_NEXT(var, field))
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (0)
+#endif /* TAILQ_FOREACH */
+
+int _evsignal_set_handler(struct event_base *base, int evsignal,
+			  void (*fn)(int));
+int _evsignal_restore_handler(struct event_base *base, int evsignal);
+
+/* defined in evutil.c */
+const char *evutil_getenv(const char *varname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVENT_INTERNAL_H_ */
diff --git a/third_party/libevent/event.3 b/third_party/libevent/event.3
new file mode 100644
index 0000000..5b33ec6
--- /dev/null
+++ b/third_party/libevent/event.3
@@ -0,0 +1,624 @@
+.\"	$OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $
+.\"
+.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 8, 2000
+.Dt EVENT 3
+.Os
+.Sh NAME
+.Nm event_init ,
+.Nm event_dispatch ,
+.Nm event_loop ,
+.Nm event_loopexit ,
+.Nm event_loopbreak ,
+.Nm event_set ,
+.Nm event_base_dispatch ,
+.Nm event_base_loop ,
+.Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
+.Nm event_base_set ,
+.Nm event_base_free ,
+.Nm event_add ,
+.Nm event_del ,
+.Nm event_once ,
+.Nm event_base_once ,
+.Nm event_pending ,
+.Nm event_initialized ,
+.Nm event_priority_init ,
+.Nm event_priority_set ,
+.Nm evtimer_set ,
+.Nm evtimer_add ,
+.Nm evtimer_del ,
+.Nm evtimer_pending ,
+.Nm evtimer_initialized ,
+.Nm signal_set ,
+.Nm signal_add ,
+.Nm signal_del ,
+.Nm signal_pending ,
+.Nm signal_initialized ,
+.Nm bufferevent_new ,
+.Nm bufferevent_free ,
+.Nm bufferevent_write ,
+.Nm bufferevent_write_buffer ,
+.Nm bufferevent_read ,
+.Nm bufferevent_enable ,
+.Nm bufferevent_disable ,
+.Nm bufferevent_settimeout ,
+.Nm bufferevent_base_set ,
+.Nm evbuffer_new ,
+.Nm evbuffer_free ,
+.Nm evbuffer_add ,
+.Nm evbuffer_add_buffer ,
+.Nm evbuffer_add_printf ,
+.Nm evbuffer_add_vprintf ,
+.Nm evbuffer_drain ,
+.Nm evbuffer_write ,
+.Nm evbuffer_read ,
+.Nm evbuffer_find ,
+.Nm evbuffer_readline ,
+.Nm evhttp_new ,
+.Nm evhttp_bind_socket ,
+.Nm evhttp_free
+.Nd execute a function when a specific event occurs
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Ft "struct event_base *"
+.Fn "event_init" "void"
+.Ft int
+.Fn "event_dispatch" "void"
+.Ft int
+.Fn "event_loop" "int flags"
+.Ft int
+.Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
+.Ft void
+.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
+.Ft int
+.Fn "event_base_dispatch" "struct event_base *base"
+.Ft int
+.Fn "event_base_loop" "struct event_base *base" "int flags"
+.Ft int
+.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
+.Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
+.Fn "event_base_set" "struct event_base *base" "struct event *"
+.Ft void
+.Fn "event_base_free" "struct event_base *base"
+.Ft int
+.Fn "event_add" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "event_del" "struct event *ev"
+.Ft int
+.Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
+.Ft int
+.Fn "event_base_once" "struct event_base *base" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
+.Ft int
+.Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv"
+.Ft int
+.Fn "event_initialized" "struct event *ev"
+.Ft int
+.Fn "event_priority_init" "int npriorities"
+.Ft int
+.Fn "event_priority_set" "struct event *ev" "int priority"
+.Ft void
+.Fn "evtimer_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "evtimer_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "evtimer_del" "struct event *ev"
+.Ft int
+.Fn "evtimer_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "evtimer_initialized" "struct event *ev"
+.Ft void
+.Fn "signal_set" "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "signal_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "signal_del" "struct event *ev"
+.Ft int
+.Fn "signal_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "signal_initialized" "struct event *ev"
+.Ft "struct bufferevent *"
+.Fn "bufferevent_new" "int fd" "evbuffercb readcb" "evbuffercb writecb" "everrorcb" "void *cbarg"
+.Ft void
+.Fn "bufferevent_free" "struct bufferevent *bufev"
+.Ft int
+.Fn "bufferevent_write" "struct bufferevent *bufev" "void *data" "size_t size"
+.Ft int
+.Fn "bufferevent_write_buffer" "struct bufferevent *bufev" "struct evbuffer *buf"
+.Ft size_t
+.Fn "bufferevent_read" "struct bufferevent *bufev" "void *data" "size_t size"
+.Ft int
+.Fn "bufferevent_enable" "struct bufferevent *bufev" "short event"
+.Ft int
+.Fn "bufferevent_disable" "struct bufferevent *bufev" "short event"
+.Ft void
+.Fn "bufferevent_settimeout" "struct bufferevent *bufev" "int timeout_read" "int timeout_write"
+.Ft int
+.Fn "bufferevent_base_set" "struct event_base *base" "struct bufferevent *bufev"
+.Ft "struct evbuffer *"
+.Fn "evbuffer_new" "void"
+.Ft void
+.Fn "evbuffer_free" "struct evbuffer *buf"
+.Ft int
+.Fn "evbuffer_add" "struct evbuffer *buf" "const void *data" "size_t size"
+.Ft int
+.Fn "evbuffer_add_buffer" "struct evbuffer *dst" "struct evbuffer *src"
+.Ft int
+.Fn "evbuffer_add_printf" "struct evbuffer *buf" "const char *fmt" "..."
+.Ft int
+.Fn "evbuffer_add_vprintf" "struct evbuffer *buf" "const char *fmt" "va_list ap"
+.Ft void
+.Fn "evbuffer_drain" "struct evbuffer *buf" "size_t size"
+.Ft int
+.Fn "evbuffer_write" "struct evbuffer *buf" "int fd"
+.Ft int
+.Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size"
+.Ft "u_char *"
+.Fn "evbuffer_find" "struct evbuffer *buf" "const u_char *data" "size_t size"
+.Ft "char *"
+.Fn "evbuffer_readline" "struct evbuffer *buf"
+.Ft "struct evhttp *"
+.Fn "evhttp_new" "struct event_base *base"
+.Ft int
+.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port"
+.Ft "void"
+.Fn "evhttp_free" "struct evhttp *http"
+.Ft int
+.Fa (*event_sigcb)(void) ;
+.Ft volatile sig_atomic_t
+.Fa event_gotsig ;
+.Sh DESCRIPTION
+The
+.Nm event
+API provides a mechanism to execute a function when a specific event
+on a file descriptor occurs or after a given time has passed.
+.Pp
+The
+.Nm event
+API needs to be initialized with
+.Fn event_init
+before it can be used.
+.Pp
+In order to process events, an application needs to call
+.Fn event_dispatch .
+This function only returns on error, and should replace the event core
+of the application program.
+.Pp
+The function
+.Fn event_set
+prepares the event structure
+.Fa ev
+to be used in future calls to
+.Fn event_add
+and
+.Fn event_del .
+The event will be prepared to call the function specified by the
+.Fa fn
+argument with an
+.Fa int
+argument indicating the file descriptor, a
+.Fa short
+argument indicating the type of event, and a
+.Fa void *
+argument given in the
+.Fa arg
+argument.
+The
+.Fa fd
+indicates the file descriptor that should be monitored for events.
+The events can be either
+.Va EV_READ ,
+.Va EV_WRITE ,
+or both,
+indicating that an application can read or write from the file descriptor
+respectively without blocking.
+.Pp
+The function
+.Fa fn
+will be called with the file descriptor that triggered the event and
+the type of event which will be either
+.Va EV_TIMEOUT ,
+.Va EV_SIGNAL ,
+.Va EV_READ ,
+or
+.Va EV_WRITE .
+Additionally, an event which has registered interest in more than one of the
+preceeding events, via bitwise-OR to
+.Fn event_set ,
+can provide its callback function with a bitwise-OR of more than one triggered
+event.
+The additional flag
+.Va EV_PERSIST
+makes an
+.Fn event_add
+persistent until
+.Fn event_del
+has been called.
+.Pp
+Once initialized, the
+.Fa ev
+structure can be used repeatedly with
+.Fn event_add
+and
+.Fn event_del
+and does not need to be reinitialized unless the function called and/or
+the argument to it are to be changed.
+However, when an
+.Fa ev
+structure has been added to libevent using
+.Fn event_add
+the structure must persist until the event occurs (assuming
+.Fa EV_PERSIST
+is not set) or is removed
+using
+.Fn event_del .
+You may not reuse the same
+.Fa ev
+structure for multiple monitored descriptors; each descriptor
+needs its own
+.Fa ev .
+.Pp
+The function
+.Fn event_add
+schedules the execution of the
+.Fa ev
+event when the event specified in
+.Fn event_set
+occurs or in at least the time specified in the
+.Fa tv .
+If
+.Fa tv
+is
+.Dv NULL ,
+no timeout occurs and the function will only be called
+if a matching event occurs on the file descriptor.
+The event in the
+.Fa ev
+argument must be already initialized by
+.Fn event_set
+and may not be used in calls to
+.Fn event_set
+until it has timed out or been removed with
+.Fn event_del .
+If the event in the
+.Fa ev
+argument already has a scheduled timeout, the old timeout will be
+replaced by the new one.
+.Pp
+The function
+.Fn event_del
+will cancel the event in the argument
+.Fa ev .
+If the event has already executed or has never been added
+the call will have no effect.
+.Pp
+The functions
+.Fn evtimer_set ,
+.Fn evtimer_add ,
+.Fn evtimer_del ,
+.Fn evtimer_initialized ,
+and
+.Fn evtimer_pending
+are abbreviations for common situations where only a timeout is required.
+The file descriptor passed will be \-1, and the event type will be
+.Va EV_TIMEOUT .
+.Pp
+The functions
+.Fn signal_set ,
+.Fn signal_add ,
+.Fn signal_del ,
+.Fn signal_initialized ,
+and
+.Fn signal_pending
+are abbreviations.
+The event type will be a persistent
+.Va EV_SIGNAL .
+That means
+.Fn signal_set
+adds
+.Va EV_PERSIST .
+.Pp
+In order to avoid races in signal handlers, the
+.Nm event
+API provides two variables:
+.Va event_sigcb
+and
+.Va event_gotsig .
+A signal handler
+sets
+.Va event_gotsig
+to indicate that a signal has been received.
+The application sets
+.Va event_sigcb
+to a callback function.
+After the signal handler sets
+.Va event_gotsig ,
+.Nm event_dispatch
+will execute the callback function to process received signals.
+The callback returns 1 when no events are registered any more.
+It can return \-1 to indicate an error to the
+.Nm event
+library, causing
+.Fn event_dispatch
+to terminate with
+.Va errno
+set to
+.Er EINTR .
+.Pp
+The function
+.Fn event_once
+is similar to
+.Fn event_set .
+However, it schedules a callback to be called exactly once and does not
+require the caller to prepare an
+.Fa event
+structure.
+This function supports
+.Fa EV_TIMEOUT ,
+.Fa EV_READ ,
+and
+.Fa EV_WRITE .
+.Pp
+The
+.Fn event_pending
+function can be used to check if the event specified by
+.Fa event
+is pending to run.
+If
+.Va EV_TIMEOUT
+was specified and
+.Fa tv
+is not
+.Dv NULL ,
+the expiration time of the event will be returned in
+.Fa tv .
+.Pp
+The
+.Fn event_initialized
+macro can be used to check if an event has been initialized.
+.Pp
+The
+.Nm event_loop
+function provides an interface for single pass execution of pending
+events.
+The flags
+.Va EVLOOP_ONCE
+and
+.Va EVLOOP_NONBLOCK
+are recognized.
+The
+.Nm event_loopexit
+function exits from the event loop. The next
+.Fn event_loop
+iteration after the
+given timer expires will complete normally (handling all queued events) then
+exit without blocking for events again. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+.Pp
+It is the responsibility of the caller to provide these functions with
+pre-allocated event structures.
+.Pp
+.Sh EVENT PRIORITIES
+By default
+.Nm libevent
+schedules all active events with the same priority.
+However, sometimes it is desirable to process some events with a higher
+priority than others.
+For that reason,
+.Nm libevent
+supports strict priority queues.
+Active events with a lower priority are always processed before events
+with a higher priority.
+.Pp
+The number of different priorities can be set initially with the
+.Fn event_priority_init
+function.
+This function should be called before the first call to
+.Fn event_dispatch .
+The
+.Fn event_priority_set
+function can be used to assign a priority to an event.
+By default,
+.Nm libevent
+assigns the middle priority to all events unless their priority
+is explicitly set.
+.Sh THREAD SAFE EVENTS
+.Nm Libevent
+has experimental support for thread-safe events.
+When initializing the library via
+.Fn event_init ,
+an event base is returned.
+This event base can be used in conjunction with calls to
+.Fn event_base_set ,
+.Fn event_base_dispatch ,
+.Fn event_base_loop ,
+.Fn event_base_loopexit ,
+.Fn bufferevent_base_set
+and
+.Fn event_base_free .
+.Fn event_base_set
+should be called after preparing an event with
+.Fn event_set ,
+as
+.Fn event_set
+assigns the provided event to the most recently created event base.
+.Fn bufferevent_base_set
+should be called after preparing a bufferevent with
+.Fn bufferevent_new .
+.Fn event_base_free
+should be used to free memory associated with the event base
+when it is no longer needed.
+.Sh BUFFERED EVENTS
+.Nm libevent
+provides an abstraction on top of the regular event callbacks.
+This abstraction is called a
+.Va "buffered event" .
+A buffered event provides input and output buffers that get filled
+and drained automatically.
+The user of a buffered event no longer deals directly with the IO,
+but instead is reading from input and writing to output buffers.
+.Pp
+A new bufferevent is created by
+.Fn bufferevent_new .
+The parameter
+.Fa fd
+specifies the file descriptor from which data is read and written to.
+This file descriptor is not allowed to be a
+.Xr pipe 2 .
+The next three parameters are callbacks.
+The read and write callback have the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "void *arg" .
+The error callback has the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "short what" "void *arg" .
+The argument is specified by the fourth parameter
+.Fa "cbarg" .
+A
+.Fa bufferevent struct
+pointer is returned on success, NULL on error.
+Both the read and the write callback may be NULL.
+The error callback has to be always provided.
+.Pp
+Once initialized, the bufferevent structure can be used repeatedly with
+bufferevent_enable() and bufferevent_disable().
+The flags parameter can be a combination of
+.Va EV_READ
+and
+.Va EV_WRITE .
+When read enabled the bufferevent will try to read from the file
+descriptor and call the read callback.
+The write callback is executed
+whenever the output buffer is drained below the write low watermark,
+which is
+.Va 0
+by default.
+.Pp
+The
+.Fn bufferevent_write
+function can be used to write data to the file descriptor.
+The data is appended to the output buffer and written to the descriptor
+automatically as it becomes available for writing.
+.Fn bufferevent_write
+returns 0 on success or \-1 on failure.
+The
+.Fn bufferevent_read
+function is used to read data from the input buffer,
+returning the amount of data read.
+.Pp
+If multiple bases are in use, bufferevent_base_set() must be called before
+enabling the bufferevent for the first time.
+.Sh NON-BLOCKING HTTP SUPPORT
+.Nm libevent
+provides a very thin HTTP layer that can be used both to host an HTTP
+server and also to make HTTP requests.
+An HTTP server can be created by calling
+.Fn evhttp_new .
+It can be bound to any port and address with the
+.Fn evhttp_bind_socket
+function.
+When the HTTP server is no longer used, it can be freed via
+.Fn evhttp_free .
+.Pp
+To be notified of HTTP requests, a user needs to register callbacks with the
+HTTP server.
+This can be done by calling
+.Fn evhttp_set_cb .
+The second argument is the URI for which a callback is being registered.
+The corresponding callback will receive an
+.Va struct evhttp_request
+object that contains all information about the request.
+.Pp
+This section does not document all the possible function calls; please
+check
+.Va event.h
+for the public interfaces.
+.Sh ADDITIONAL NOTES
+It is possible to disable support for
+.Va epoll , kqueue , devpoll , poll
+or
+.Va select
+by setting the environment variable
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
+or
+.Va EVENT_NOSELECT ,
+respectively.
+By setting the environment variable
+.Va EVENT_SHOW_METHOD ,
+.Nm libevent
+displays the kernel notification method that it uses.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn event_add
+and
+.Fn event_del
+return 0.
+Otherwise, \-1 is returned and the global variable errno is
+set to indicate the error.
+.Sh SEE ALSO
+.Xr kqueue 2 ,
+.Xr poll 2 ,
+.Xr select 2 ,
+.Xr evdns 3 ,
+.Xr timeout 9
+.Sh HISTORY
+The
+.Nm event
+API manpage is based on the
+.Xr timeout 9
+manpage by Artur Grabowski.
+The port of
+.Nm libevent
+to Windows is due to Michael A. Davis.
+Support for real-time signals is due to Taral.
+.Sh AUTHORS
+The
+.Nm event
+library was written by Niels Provos.
+.Sh BUGS
+This documentation is neither complete nor authoritative.
+If you are in doubt about the usage of this API then
+check the source code to find out how it works, write
+up the missing piece of documentation and send it to
+me for inclusion in this man page.
diff --git a/third_party/libevent/event.c b/third_party/libevent/event.c
new file mode 100644
index 0000000..8b6cae5
--- /dev/null
+++ b/third_party/libevent/event.c
@@ -0,0 +1,990 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else 
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include "event.h"
+#include "event-internal.h"
+#include "evutil.h"
+#include "log.h"
+
+#ifdef HAVE_EVENT_PORTS
+extern const struct eventop evportops;
+#endif
+#ifdef HAVE_SELECT
+extern const struct eventop selectops;
+#endif
+#ifdef HAVE_POLL
+extern const struct eventop pollops;
+#endif
+#ifdef HAVE_EPOLL
+extern const struct eventop epollops;
+#endif
+#ifdef HAVE_WORKING_KQUEUE
+extern const struct eventop kqops;
+#endif
+#ifdef HAVE_DEVPOLL
+extern const struct eventop devpollops;
+#endif
+#ifdef WIN32
+extern const struct eventop win32ops;
+#endif
+
+/* In order of preference */
+static const struct eventop *eventops[] = {
+#ifdef HAVE_EVENT_PORTS
+	&evportops,
+#endif
+#ifdef HAVE_WORKING_KQUEUE
+	&kqops,
+#endif
+#ifdef HAVE_EPOLL
+	&epollops,
+#endif
+#ifdef HAVE_DEVPOLL
+	&devpollops,
+#endif
+#ifdef HAVE_POLL
+	&pollops,
+#endif
+#ifdef HAVE_SELECT
+	&selectops,
+#endif
+#ifdef WIN32
+	&win32ops,
+#endif
+	NULL
+};
+
+/* Global state */
+struct event_base *current_base = NULL;
+extern struct event_base *evsignal_base;
+static int use_monotonic = 1;
+
+/* Prototypes */
+static void	event_queue_insert(struct event_base *, struct event *, int);
+static void	event_queue_remove(struct event_base *, struct event *, int);
+static int	event_haveevents(struct event_base *);
+
+static void	event_process_active(struct event_base *);
+
+static int	timeout_next(struct event_base *, struct timeval **);
+static void	timeout_process(struct event_base *);
+static void	timeout_correct(struct event_base *, struct timeval *);
+
+static int
+gettime(struct event_base *base, struct timeval *tp)
+{
+	if (base->tv_cache.tv_sec) {
+		*tp = base->tv_cache;
+		return (0);
+	}
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+	struct timespec	ts;
+
+	if (use_monotonic &&
+	    clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+		tp->tv_sec = ts.tv_sec;
+		tp->tv_usec = ts.tv_nsec / 1000;
+		return (0);
+	}
+#endif
+
+	use_monotonic = 0;
+
+	return (evutil_gettimeofday(tp, NULL));
+}
+
+struct event_base *
+event_init(void)
+{
+	struct event_base *base = event_base_new();
+
+	if (base != NULL)
+		current_base = base;
+
+	return (base);
+}
+
+struct event_base *
+event_base_new(void)
+{
+	int i;
+	struct event_base *base;
+
+	if ((base = calloc(1, sizeof(struct event_base))) == NULL)
+		event_err(1, "%s: calloc", __func__);
+
+	gettime(base, &base->event_tv);
+	
+	min_heap_ctor(&base->timeheap);
+	TAILQ_INIT(&base->eventqueue);
+	base->sig.ev_signal_pair[0] = -1;
+	base->sig.ev_signal_pair[1] = -1;
+	
+	base->evbase = NULL;
+	for (i = 0; eventops[i] && !base->evbase; i++) {
+		base->evsel = eventops[i];
+
+		base->evbase = base->evsel->init(base);
+	}
+
+	if (base->evbase == NULL)
+		event_errx(1, "%s: no event mechanism available", __func__);
+
+	if (evutil_getenv("EVENT_SHOW_METHOD")) 
+		event_msgx("libevent using: %s\n",
+			   base->evsel->name);
+
+	/* allocate a single active event queue */
+	event_base_priority_init(base, 1);
+
+	return (base);
+}
+
+void
+event_base_free(struct event_base *base)
+{
+	int i, n_deleted=0;
+	struct event *ev;
+
+	if (base == NULL && current_base)
+		base = current_base;
+	if (base == current_base)
+		current_base = NULL;
+
+	/* XXX(niels) - check for internal events first */
+	assert(base);
+	/* Delete all non-internal events. */
+	for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
+		struct event *next = TAILQ_NEXT(ev, ev_next);
+		if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+			event_del(ev);
+			++n_deleted;
+		}
+		ev = next;
+	}
+	while ((ev = min_heap_top(&base->timeheap)) != NULL) {
+		event_del(ev);
+		++n_deleted;
+	}
+
+	for (i = 0; i < base->nactivequeues; ++i) {
+		for (ev = TAILQ_FIRST(base->activequeues[i]); ev; ) {
+			struct event *next = TAILQ_NEXT(ev, ev_active_next);
+			if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+				event_del(ev);
+				++n_deleted;
+			}
+			ev = next;
+		}
+	}
+
+	if (n_deleted)
+		event_debug(("%s: %d events were still set in base",
+			__func__, n_deleted));
+
+	if (base->evsel->dealloc != NULL)
+		base->evsel->dealloc(base, base->evbase);
+
+	for (i = 0; i < base->nactivequeues; ++i)
+		assert(TAILQ_EMPTY(base->activequeues[i]));
+
+	assert(min_heap_empty(&base->timeheap));
+	min_heap_dtor(&base->timeheap);
+
+	for (i = 0; i < base->nactivequeues; ++i)
+		free(base->activequeues[i]);
+	free(base->activequeues);
+
+	assert(TAILQ_EMPTY(&base->eventqueue));
+
+	free(base);
+}
+
+/* reinitialized the event base after a fork */
+int
+event_reinit(struct event_base *base)
+{
+	const struct eventop *evsel = base->evsel;
+	void *evbase = base->evbase;
+	int res = 0;
+	struct event *ev;
+
+	/* check if this event mechanism requires reinit */
+	if (!evsel->need_reinit)
+		return (0);
+
+	/* prevent internal delete */
+	if (base->sig.ev_signal_added) {
+		/* we cannot call event_del here because the base has
+		 * not been reinitialized yet. */
+		event_queue_remove(base, &base->sig.ev_signal,
+		    EVLIST_INSERTED);
+		if (base->sig.ev_signal.ev_flags & EVLIST_ACTIVE)
+			event_queue_remove(base, &base->sig.ev_signal,
+			    EVLIST_ACTIVE);
+		base->sig.ev_signal_added = 0;
+	}
+	
+	if (base->evsel->dealloc != NULL)
+		base->evsel->dealloc(base, base->evbase);
+	evbase = base->evbase = evsel->init(base);
+	if (base->evbase == NULL)
+		event_errx(1, "%s: could not reinitialize event mechanism",
+		    __func__);
+
+	TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+		if (evsel->add(evbase, ev) == -1)
+			res = -1;
+	}
+
+	return (res);
+}
+
+int
+event_priority_init(int npriorities)
+{
+  return event_base_priority_init(current_base, npriorities);
+}
+
+int
+event_base_priority_init(struct event_base *base, int npriorities)
+{
+	int i;
+
+	if (base->event_count_active)
+		return (-1);
+
+	if (base->nactivequeues && npriorities != base->nactivequeues) {
+		for (i = 0; i < base->nactivequeues; ++i) {
+			free(base->activequeues[i]);
+		}
+		free(base->activequeues);
+	}
+
+	/* Allocate our priority queues */
+	base->nactivequeues = npriorities;
+	base->activequeues = (struct event_list **)
+	    calloc(base->nactivequeues, sizeof(struct event_list *));
+	if (base->activequeues == NULL)
+		event_err(1, "%s: calloc", __func__);
+
+	for (i = 0; i < base->nactivequeues; ++i) {
+		base->activequeues[i] = malloc(sizeof(struct event_list));
+		if (base->activequeues[i] == NULL)
+			event_err(1, "%s: malloc", __func__);
+		TAILQ_INIT(base->activequeues[i]);
+	}
+
+	return (0);
+}
+
+int
+event_haveevents(struct event_base *base)
+{
+	return (base->event_count > 0);
+}
+
+/*
+ * Active events are stored in priority queues.  Lower priorities are always
+ * process before higher priorities.  Low priority events can starve high
+ * priority ones.
+ */
+
+static void
+event_process_active(struct event_base *base)
+{
+	struct event *ev;
+	struct event_list *activeq = NULL;
+	int i;
+	short ncalls;
+
+	for (i = 0; i < base->nactivequeues; ++i) {
+		if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
+			activeq = base->activequeues[i];
+			break;
+		}
+	}
+
+	assert(activeq != NULL);
+
+	for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
+		if (ev->ev_events & EV_PERSIST)
+			event_queue_remove(base, ev, EVLIST_ACTIVE);
+		else
+			event_del(ev);
+		
+		/* Allows deletes to work */
+		ncalls = ev->ev_ncalls;
+		ev->ev_pncalls = &ncalls;
+		while (ncalls) {
+			ncalls--;
+			ev->ev_ncalls = ncalls;
+			(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
+			if (base->event_break)
+				return;
+		}
+	}
+}
+
+/*
+ * Wait continously for events.  We exit only if no events are left.
+ */
+
+int
+event_dispatch(void)
+{
+	return (event_loop(0));
+}
+
+int
+event_base_dispatch(struct event_base *event_base)
+{
+  return (event_base_loop(event_base, 0));
+}
+
+const char *
+event_base_get_method(struct event_base *base)
+{
+	assert(base);
+	return (base->evsel->name);
+}
+
+static void
+event_loopexit_cb(int fd, short what, void *arg)
+{
+	struct event_base *base = arg;
+	base->event_gotterm = 1;
+}
+
+/* not thread safe */
+int
+event_loopexit(const struct timeval *tv)
+{
+	return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
+		    current_base, tv));
+}
+
+int
+event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
+{
+	return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
+		    event_base, tv));
+}
+
+/* not thread safe */
+int
+event_loopbreak(void)
+{
+	return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+	if (event_base == NULL)
+		return (-1);
+
+	event_base->event_break = 1;
+	return (0);
+}
+
+
+
+/* not thread safe */
+
+int
+event_loop(int flags)
+{
+	return event_base_loop(current_base, flags);
+}
+
+int
+event_base_loop(struct event_base *base, int flags)
+{
+	const struct eventop *evsel = base->evsel;
+	void *evbase = base->evbase;
+	struct timeval tv;
+	struct timeval *tv_p;
+	int res, done;
+
+	/* clear time cache */
+	base->tv_cache.tv_sec = 0;
+
+	if (base->sig.ev_signal_added)
+		evsignal_base = base;
+	done = 0;
+	while (!done) {
+		/* Terminate the loop if we have been asked to */
+		if (base->event_gotterm) {
+			base->event_gotterm = 0;
+			break;
+		}
+
+		if (base->event_break) {
+			base->event_break = 0;
+			break;
+		}
+
+		timeout_correct(base, &tv);
+
+		tv_p = &tv;
+		if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
+			timeout_next(base, &tv_p);
+		} else {
+			/* 
+			 * if we have active events, we just poll new events
+			 * without waiting.
+			 */
+			evutil_timerclear(&tv);
+		}
+		
+		/* If we have no events, we just exit */
+		if (!event_haveevents(base)) {
+			event_debug(("%s: no events registered.", __func__));
+			return (1);
+		}
+
+		/* update last old time */
+		gettime(base, &base->event_tv);
+
+		/* clear time cache */
+		base->tv_cache.tv_sec = 0;
+
+		res = evsel->dispatch(base, evbase, tv_p);
+
+		if (res == -1)
+			return (-1);
+		gettime(base, &base->tv_cache);
+
+		timeout_process(base);
+
+		if (base->event_count_active) {
+			event_process_active(base);
+			if (!base->event_count_active && (flags & EVLOOP_ONCE))
+				done = 1;
+		} else if (flags & EVLOOP_NONBLOCK)
+			done = 1;
+	}
+
+	/* clear time cache */
+	base->tv_cache.tv_sec = 0;
+
+	event_debug(("%s: asked to terminate loop.", __func__));
+	return (0);
+}
+
+/* Sets up an event for processing once */
+
+struct event_once {
+	struct event ev;
+
+	void (*cb)(int, short, void *);
+	void *arg;
+};
+
+/* One-time callback, it deletes itself */
+
+static void
+event_once_cb(int fd, short events, void *arg)
+{
+	struct event_once *eonce = arg;
+
+	(*eonce->cb)(fd, events, eonce->arg);
+	free(eonce);
+}
+
+/* not threadsafe, event scheduled once. */
+int
+event_once(int fd, short events,
+    void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
+{
+	return event_base_once(current_base, fd, events, callback, arg, tv);
+}
+
+/* Schedules an event once */
+int
+event_base_once(struct event_base *base, int fd, short events,
+    void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
+{
+	struct event_once *eonce;
+	struct timeval etv;
+	int res;
+
+	/* We cannot support signals that just fire once */
+	if (events & EV_SIGNAL)
+		return (-1);
+
+	if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
+		return (-1);
+
+	eonce->cb = callback;
+	eonce->arg = arg;
+
+	if (events == EV_TIMEOUT) {
+		if (tv == NULL) {
+			evutil_timerclear(&etv);
+			tv = &etv;
+		}
+
+		evtimer_set(&eonce->ev, event_once_cb, eonce);
+	} else if (events & (EV_READ|EV_WRITE)) {
+		events &= EV_READ|EV_WRITE;
+
+		event_set(&eonce->ev, fd, events, event_once_cb, eonce);
+	} else {
+		/* Bad event combination */
+		free(eonce);
+		return (-1);
+	}
+
+	res = event_base_set(base, &eonce->ev);
+	if (res == 0)
+		res = event_add(&eonce->ev, tv);
+	if (res != 0) {
+		free(eonce);
+		return (res);
+	}
+
+	return (0);
+}
+
+void
+event_set(struct event *ev, int fd, short events,
+	  void (*callback)(int, short, void *), void *arg)
+{
+	/* Take the current base - caller needs to set the real base later */
+	ev->ev_base = current_base;
+
+	ev->ev_callback = callback;
+	ev->ev_arg = arg;
+	ev->ev_fd = fd;
+	ev->ev_events = events;
+	ev->ev_res = 0;
+	ev->ev_flags = EVLIST_INIT;
+	ev->ev_ncalls = 0;
+	ev->ev_pncalls = NULL;
+
+	min_heap_elem_init(ev);
+
+	/* by default, we put new events into the middle priority */
+	if(current_base)
+		ev->ev_pri = current_base->nactivequeues/2;
+}
+
+int
+event_base_set(struct event_base *base, struct event *ev)
+{
+	/* Only innocent events may be assigned to a different base */
+	if (ev->ev_flags != EVLIST_INIT)
+		return (-1);
+
+	ev->ev_base = base;
+	ev->ev_pri = base->nactivequeues/2;
+
+	return (0);
+}
+
+/*
+ * Set's the priority of an event - if an event is already scheduled
+ * changing the priority is going to fail.
+ */
+
+int
+event_priority_set(struct event *ev, int pri)
+{
+	if (ev->ev_flags & EVLIST_ACTIVE)
+		return (-1);
+	if (pri < 0 || pri >= ev->ev_base->nactivequeues)
+		return (-1);
+
+	ev->ev_pri = pri;
+
+	return (0);
+}
+
+/*
+ * Checks if a specific event is pending or scheduled.
+ */
+
+int
+event_pending(struct event *ev, short event, struct timeval *tv)
+{
+	struct timeval	now, res;
+	int flags = 0;
+
+	if (ev->ev_flags & EVLIST_INSERTED)
+		flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
+	if (ev->ev_flags & EVLIST_ACTIVE)
+		flags |= ev->ev_res;
+	if (ev->ev_flags & EVLIST_TIMEOUT)
+		flags |= EV_TIMEOUT;
+
+	event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
+
+	/* See if there is a timeout that we should report */
+	if (tv != NULL && (flags & event & EV_TIMEOUT)) {
+		gettime(ev->ev_base, &now);
+		evutil_timersub(&ev->ev_timeout, &now, &res);
+		/* correctly remap to real time */
+		evutil_gettimeofday(&now, NULL);
+		evutil_timeradd(&now, &res, tv);
+	}
+
+	return (flags & event);
+}
+
+int
+event_add(struct event *ev, const struct timeval *tv)
+{
+	struct event_base *base = ev->ev_base;
+	const struct eventop *evsel = base->evsel;
+	void *evbase = base->evbase;
+	int res = 0;
+
+	event_debug((
+		 "event_add: event: %p, %s%s%scall %p",
+		 ev,
+		 ev->ev_events & EV_READ ? "EV_READ " : " ",
+		 ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
+		 tv ? "EV_TIMEOUT " : " ",
+		 ev->ev_callback));
+
+	assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+	/*
+	 * prepare for timeout insertion further below, if we get a
+	 * failure on any step, we should not change any state.
+	 */
+	if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
+		if (min_heap_reserve(&base->timeheap,
+			1 + min_heap_size(&base->timeheap)) == -1)
+			return (-1);  /* ENOMEM == errno */
+	}
+
+	if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
+	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
+		res = evsel->add(evbase, ev);
+		if (res != -1)
+			event_queue_insert(base, ev, EVLIST_INSERTED);
+	}
+
+	/* 
+	 * we should change the timout state only if the previous event
+	 * addition succeeded.
+	 */
+	if (res != -1 && tv != NULL) {
+		struct timeval now;
+
+		/* 
+		 * we already reserved memory above for the case where we
+		 * are not replacing an exisiting timeout.
+		 */
+		if (ev->ev_flags & EVLIST_TIMEOUT)
+			event_queue_remove(base, ev, EVLIST_TIMEOUT);
+
+		/* Check if it is active due to a timeout.  Rescheduling
+		 * this timeout before the callback can be executed
+		 * removes it from the active list. */
+		if ((ev->ev_flags & EVLIST_ACTIVE) &&
+		    (ev->ev_res & EV_TIMEOUT)) {
+			/* See if we are just active executing this
+			 * event in a loop
+			 */
+			if (ev->ev_ncalls && ev->ev_pncalls) {
+				/* Abort loop */
+				*ev->ev_pncalls = 0;
+			}
+			
+			event_queue_remove(base, ev, EVLIST_ACTIVE);
+		}
+
+		gettime(base, &now);
+		evutil_timeradd(&now, tv, &ev->ev_timeout);
+
+		event_debug((
+			 "event_add: timeout in %ld seconds, call %p",
+			 tv->tv_sec, ev->ev_callback));
+
+		event_queue_insert(base, ev, EVLIST_TIMEOUT);
+	}
+
+	return (res);
+}
+
+int
+event_del(struct event *ev)
+{
+	struct event_base *base;
+
+	event_debug(("event_del: %p, callback %p",
+		 ev, ev->ev_callback));
+
+	/* An event without a base has not been added */
+	if (ev->ev_base == NULL)
+		return (-1);
+
+	base = ev->ev_base;
+
+	assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+	/* See if we are just active executing this event in a loop */
+	if (ev->ev_ncalls && ev->ev_pncalls) {
+		/* Abort loop */
+		*ev->ev_pncalls = 0;
+	}
+
+	if (ev->ev_flags & EVLIST_TIMEOUT)
+		event_queue_remove(base, ev, EVLIST_TIMEOUT);
+
+	if (ev->ev_flags & EVLIST_ACTIVE)
+		event_queue_remove(base, ev, EVLIST_ACTIVE);
+
+	if (ev->ev_flags & EVLIST_INSERTED) {
+		event_queue_remove(base, ev, EVLIST_INSERTED);
+		return (base->evsel->del(base->evbase, ev));
+	}
+
+	return (0);
+}
+
+void
+event_active(struct event *ev, int res, short ncalls)
+{
+	/* We get different kinds of events, add them together */
+	if (ev->ev_flags & EVLIST_ACTIVE) {
+		ev->ev_res |= res;
+		return;
+	}
+
+	ev->ev_res = res;
+	ev->ev_ncalls = ncalls;
+	ev->ev_pncalls = NULL;
+	event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
+}
+
+static int
+timeout_next(struct event_base *base, struct timeval **tv_p)
+{
+	struct timeval now;
+	struct event *ev;
+	struct timeval *tv = *tv_p;
+
+	if ((ev = min_heap_top(&base->timeheap)) == NULL) {
+		/* if no time-based events are active wait for I/O */
+		*tv_p = NULL;
+		return (0);
+	}
+
+	if (gettime(base, &now) == -1)
+		return (-1);
+
+	if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
+		evutil_timerclear(tv);
+		return (0);
+	}
+
+	evutil_timersub(&ev->ev_timeout, &now, tv);
+
+	assert(tv->tv_sec >= 0);
+	assert(tv->tv_usec >= 0);
+
+	event_debug(("timeout_next: in %ld seconds", tv->tv_sec));
+	return (0);
+}
+
+/*
+ * Determines if the time is running backwards by comparing the current
+ * time against the last time we checked.  Not needed when using clock
+ * monotonic.
+ */
+
+static void
+timeout_correct(struct event_base *base, struct timeval *tv)
+{
+	struct event **pev;
+	unsigned int size;
+	struct timeval off;
+
+	if (use_monotonic)
+		return;
+
+	/* Check if time is running backwards */
+	gettime(base, tv);
+	if (evutil_timercmp(tv, &base->event_tv, >=)) {
+		base->event_tv = *tv;
+		return;
+	}
+
+	event_debug(("%s: time is running backwards, corrected",
+		    __func__));
+	evutil_timersub(&base->event_tv, tv, &off);
+
+	/*
+	 * We can modify the key element of the node without destroying
+	 * the key, beause we apply it to all in the right order.
+	 */
+	pev = base->timeheap.p;
+	size = base->timeheap.n;
+	for (; size-- > 0; ++pev) {
+		struct timeval *ev_tv = &(**pev).ev_timeout;
+		evutil_timersub(ev_tv, &off, ev_tv);
+	}
+	/* Now remember what the new time turned out to be. */
+	base->event_tv = *tv;
+}
+
+void
+timeout_process(struct event_base *base)
+{
+	struct timeval now;
+	struct event *ev;
+
+	if (min_heap_empty(&base->timeheap))
+		return;
+
+	gettime(base, &now);
+
+	while ((ev = min_heap_top(&base->timeheap))) {
+		if (evutil_timercmp(&ev->ev_timeout, &now, >))
+			break;
+
+		/* delete this event from the I/O queues */
+		event_del(ev);
+
+		event_debug(("timeout_process: call %p",
+			 ev->ev_callback));
+		event_active(ev, EV_TIMEOUT, 1);
+	}
+}
+
+void
+event_queue_remove(struct event_base *base, struct event *ev, int queue)
+{
+	if (!(ev->ev_flags & queue))
+		event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
+			   ev, ev->ev_fd, queue);
+
+	if (~ev->ev_flags & EVLIST_INTERNAL)
+		base->event_count--;
+
+	ev->ev_flags &= ~queue;
+	switch (queue) {
+	case EVLIST_INSERTED:
+		TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+		break;
+	case EVLIST_ACTIVE:
+		base->event_count_active--;
+		TAILQ_REMOVE(base->activequeues[ev->ev_pri],
+		    ev, ev_active_next);
+		break;
+	case EVLIST_TIMEOUT:
+		min_heap_erase(&base->timeheap, ev);
+		break;
+	default:
+		event_errx(1, "%s: unknown queue %x", __func__, queue);
+	}
+}
+
+void
+event_queue_insert(struct event_base *base, struct event *ev, int queue)
+{
+	if (ev->ev_flags & queue) {
+		/* Double insertion is possible for active events */
+		if (queue & EVLIST_ACTIVE)
+			return;
+
+		event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
+			   ev, ev->ev_fd, queue);
+	}
+
+	if (~ev->ev_flags & EVLIST_INTERNAL)
+		base->event_count++;
+
+	ev->ev_flags |= queue;
+	switch (queue) {
+	case EVLIST_INSERTED:
+		TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+		break;
+	case EVLIST_ACTIVE:
+		base->event_count_active++;
+		TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
+		    ev,ev_active_next);
+		break;
+	case EVLIST_TIMEOUT: {
+		min_heap_push(&base->timeheap, ev);
+		break;
+	}
+	default:
+		event_errx(1, "%s: unknown queue %x", __func__, queue);
+	}
+}
+
+/* Functions for debugging */
+
+const char *
+event_get_version(void)
+{
+	return (VERSION);
+}
+
+/* 
+ * No thread-safe interface needed - the information should be the same
+ * for all threads.
+ */
+
+const char *
+event_get_method(void)
+{
+	return (current_base->evsel->name);
+}
diff --git a/third_party/libevent/event.h b/third_party/libevent/event.h
new file mode 100644
index 0000000..72e9b8b
--- /dev/null
+++ b/third_party/libevent/event.h
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+/** @mainpage
+
+  @section intro Introduction
+
+  libevent is an event notification library for developing scalable network
+  servers.  The libevent API provides a mechanism to execute a callback
+  function when a specific event occurs on a file descriptor or after a
+  timeout has been reached. Furthermore, libevent also support callbacks due
+  to signals or regular timeouts.
+
+  libevent is meant to replace the event loop found in event driven network
+  servers. An application just needs to call event_dispatch() and then add or
+  remove events dynamically without having to change the event loop.
+
+  Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and
+  epoll(4). It also has experimental support for real-time signals. The
+  internal event mechanism is completely independent of the exposed event API,
+  and a simple update of libevent can provide new functionality without having
+  to redesign the applications. As a result, Libevent allows for portable
+  application development and provides the most scalable event notification
+  mechanism available on an operating system. Libevent can also be used for
+  multi-threaded aplications; see Steven Grimm's explanation. Libevent should
+  compile on Linux, *BSD, Mac OS X, Solaris and Windows.
+
+  @section usage Standard usage
+
+  Every program that uses libevent must include the <event.h> header, and pass
+  the -levent flag to the linker.  Before using any of the functions in the
+  library, you must call event_init() or event_base_new() to perform one-time
+  initialization of the libevent library.
+
+  @section event Event notification
+
+  For each file descriptor that you wish to monitor, you must declare an event
+  structure and call event_set() to initialize the members of the structure.
+  To enable notification, you add the structure to the list of monitored
+  events by calling event_add().  The event structure must remain allocated as
+  long as it is active, so it should be allocated on the heap. Finally, you
+  call event_dispatch() to loop and dispatch events.
+
+  @section bufferevent I/O Buffers
+
+  libevent provides an abstraction on top of the regular event callbacks. This
+  abstraction is called a buffered event. A buffered event provides input and
+  output buffers that get filled and drained automatically. The user of a
+  buffered event no longer deals directly with the I/O, but instead is reading
+  from input and writing to output buffers.
+
+  Once initialized via bufferevent_new(), the bufferevent structure can be
+  used repeatedly with bufferevent_enable() and bufferevent_disable().
+  Instead of reading and writing directly to a socket, you would call
+  bufferevent_read() and bufferevent_write().
+
+  When read enabled the bufferevent will try to read from the file descriptor
+  and call the read callback. The write callback is executed whenever the
+  output buffer is drained below the write low watermark, which is 0 by
+  default.
+
+  @section timers Timers
+
+  libevent can also be used to create timers that invoke a callback after a
+  certain amount of time has expired. The evtimer_set() function prepares an
+  event struct to be used as a timer. To activate the timer, call
+  evtimer_add(). Timers can be deactivated by calling evtimer_del().
+
+  @section timeouts Timeouts
+
+  In addition to simple timers, libevent can assign timeout events to file
+  descriptors that are triggered whenever a certain amount of time has passed
+  with no activity on a file descriptor.  The timeout_set() function
+  initializes an event struct for use as a timeout. Once initialized, the
+  event must be activated by using timeout_add().  To cancel the timeout, call
+  timeout_del().
+
+  @section evdns Asynchronous DNS resolution
+
+  libevent provides an asynchronous DNS resolver that should be used instead
+  of the standard DNS resolver functions.  These functions can be imported by
+  including the <evdns.h> header in your program. Before using any of the
+  resolver functions, you must call evdns_init() to initialize the library. To
+  convert a hostname to an IP address, you call the evdns_resolve_ipv4()
+  function.  To perform a reverse lookup, you would call the
+  evdns_resolve_reverse() function.  All of these functions use callbacks to
+  avoid blocking while the lookup is performed.
+
+  @section evhttp Event-driven HTTP servers
+
+  libevent provides a very simple event-driven HTTP server that can be
+  embedded in your program and used to service HTTP requests.
+
+  To use this capability, you need to include the <evhttp.h> header in your
+  program.  You create the server by calling evhttp_new(). Add addresses and
+  ports to listen on with evhttp_bind_socket(). You then register one or more
+  callbacks to handle incoming requests.  Each URI can be assigned a callback
+  via the evhttp_set_cb() function.  A generic callback function can also be
+  registered via evhttp_set_gencb(); this callback will be invoked if no other
+  callbacks have been registered for a given URI.
+
+  @section evrpc A framework for RPC servers and clients
+ 
+  libevents provides a framework for creating RPC servers and clients.  It
+  takes care of marshaling and unmarshaling all data structures.
+
+  @section api API Reference
+
+  To browse the complete documentation of the libevent API, click on any of
+  the following links.
+
+  event.h
+  The primary libevent header
+
+  evdns.h
+  Asynchronous DNS resolution
+
+  evhttp.h
+  An embedded libevent-based HTTP server
+
+  evrpc.h
+  A framework for creating RPC servers and clients
+
+ */
+
+/** @file event.h
+
+  A library for writing event-driven network servers
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event-config.h"
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+/* For int types. */
+#include "evutil.h"
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+#endif
+
+#define EVLIST_TIMEOUT	0x01
+#define EVLIST_INSERTED	0x02
+#define EVLIST_SIGNAL	0x04
+#define EVLIST_ACTIVE	0x08
+#define EVLIST_INTERNAL	0x10
+#define EVLIST_INIT	0x80
+
+/* EVLIST_X_ Private space: 0x1000-0xf000 */
+#define EVLIST_ALL	(0xf000 | 0x9f)
+
+#define EV_TIMEOUT	0x01
+#define EV_READ		0x02
+#define EV_WRITE	0x04
+#define EV_SIGNAL	0x08
+#define EV_PERSIST	0x10	/* Persistant event */
+
+/* Fix so that ppl dont have to run with <sys/queue.h> */
+#ifndef TAILQ_ENTRY
+#define _EVENT_DEFINED_TQENTRY
+#define TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+#endif /* !TAILQ_ENTRY */
+
+struct event_base;
+#ifndef EVENT_NO_STRUCT
+struct event {
+	TAILQ_ENTRY (event) ev_next;
+	TAILQ_ENTRY (event) ev_active_next;
+	TAILQ_ENTRY (event) ev_signal_next;
+	unsigned int min_heap_idx;	/* for managing timeouts */
+
+	struct event_base *ev_base;
+
+	int ev_fd;
+	short ev_events;
+	short ev_ncalls;
+	short *ev_pncalls;	/* Allows deletes in callback */
+
+	struct timeval ev_timeout;
+
+	int ev_pri;		/* smaller numbers are higher priority */
+
+	void (*ev_callback)(int, short, void *arg);
+	void *ev_arg;
+
+	int ev_res;		/* result passed to event callback */
+	int ev_flags;
+};
+#else
+struct event;
+#endif
+
+#define EVENT_SIGNAL(ev)	(int)(ev)->ev_fd
+#define EVENT_FD(ev)		(int)(ev)->ev_fd
+
+/*
+ * Key-Value pairs.  Can be used for HTTP headers but also for
+ * query argument parsing.
+ */
+struct evkeyval {
+	TAILQ_ENTRY(evkeyval) next;
+
+	char *key;
+	char *value;
+};
+
+#ifdef _EVENT_DEFINED_TQENTRY
+#undef TAILQ_ENTRY
+struct event_list;
+struct evkeyvalq;
+#undef _EVENT_DEFINED_TQENTRY
+#else
+TAILQ_HEAD (event_list, event);
+TAILQ_HEAD (evkeyvalq, evkeyval);
+#endif /* _EVENT_DEFINED_TQENTRY */
+
+/**
+  Initialize the event API.
+
+  Use event_base_new() to initialize a new event base, but does not set
+  the current_base global.   If using only event_base_new(), each event
+  added must have an event base set with event_base_set()
+
+  @see event_base_set(), event_base_free(), event_init()
+ */
+struct event_base *event_base_new(void);
+
+/**
+  Initialize the event API.
+
+  The event API needs to be initialized with event_init() before it can be
+  used.  Sets the current_base global representing the default base for
+  events that have no base associated with them.
+
+  @see event_base_set(), event_base_new()
+ */
+struct event_base *event_init(void);
+
+/**
+  Reinitialized the event base after a fork
+
+  Some event mechanisms do not survive across fork.   The event base needs
+  to be reinitialized with the event_reinit() function.
+
+  @param base the event base that needs to be re-initialized
+  @return 0 if successful, or -1 if some events could not be re-added.
+  @see event_base_new(), event_init()
+*/
+int event_reinit(struct event_base *base);
+
+/**
+  Loop to process events.
+
+  In order to process events, an application needs to call
+  event_dispatch().  This function only returns on error, and should
+  replace the event core of the application program.
+
+  @see event_base_dispatch()
+ */
+int event_dispatch(void);
+
+
+/**
+  Threadsafe event dispatching loop.
+
+  @param eb the event_base structure returned by event_init()
+  @see event_init(), event_dispatch()
+ */
+int event_base_dispatch(struct event_base *);
+
+
+/**
+ Get the kernel event notification mechanism used by libevent.
+ 
+ @param eb the event_base structure returned by event_base_new()
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+const char *event_base_get_method(struct event_base *);
+        
+        
+/**
+  Deallocate all memory associated with an event_base, and free the base.
+
+  Note that this function will not close any fds or free any memory passed
+  to event_set as the argument to callback.
+
+  @param eb an event_base to be freed
+ */
+void event_base_free(struct event_base *);
+
+
+#define _EVENT_LOG_DEBUG 0
+#define _EVENT_LOG_MSG   1
+#define _EVENT_LOG_WARN  2
+#define _EVENT_LOG_ERR   3
+typedef void (*event_log_cb)(int severity, const char *msg);
+/**
+  Redirect libevent's log messages.
+
+  @param cb a function taking two arguments: an integer severity between
+     _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string.  If cb is NULL,
+	 then the default log is used.
+  */
+void event_set_log_callback(event_log_cb cb);
+
+/**
+  Associate a different event base with an event.
+
+  @param eb the event base
+  @param ev the event
+ */
+int event_base_set(struct event_base *, struct event *);
+
+/**
+ event_loop() flags
+ */
+/*@{*/
+#define EVLOOP_ONCE	0x01	/**< Block at most once. */
+#define EVLOOP_NONBLOCK	0x02	/**< Do not block. */
+/*@}*/
+
+/**
+  Handle events.
+
+  This is a more flexible version of event_dispatch().
+
+  @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+  @return 0 if successful, -1 if an error occurred, or 1 if no events were
+    registered.
+  @see event_loopexit(), event_base_loop()
+*/
+int event_loop(int);
+
+/**
+  Handle events (threadsafe version).
+
+  This is a more flexible version of event_base_dispatch().
+
+  @param eb the event_base structure returned by event_init()
+  @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+  @return 0 if successful, -1 if an error occurred, or 1 if no events were
+    registered.
+  @see event_loopexit(), event_base_loop()
+  */
+int event_base_loop(struct event_base *, int);
+
+/**
+  Exit the event loop after the specified time.
+
+  The next event_loop() iteration after the given timer expires will
+  complete normally (handling all queued events) then exit without
+  blocking for events again.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @param tv the amount of time after which the loop should terminate.
+  @return 0 if successful, or -1 if an error occurred
+  @see event_loop(), event_base_loop(), event_base_loopexit()
+  */
+int event_loopexit(const struct timeval *);
+
+
+/**
+  Exit the event loop after the specified time (threadsafe variant).
+
+  The next event_base_loop() iteration after the given timer expires will
+  complete normally (handling all queued events) then exit without
+  blocking for events again.
+
+  Subsequent invocations of event_base_loop() will proceed normally.
+
+  @param eb the event_base structure returned by event_init()
+  @param tv the amount of time after which the loop should terminate.
+  @return 0 if successful, or -1 if an error occurred
+  @see event_loopexit()
+ */
+int event_base_loopexit(struct event_base *, const struct timeval *);
+
+/**
+  Abort the active event_loop() immediately.
+
+  event_loop() will abort the loop after the next event is completed;
+  event_loopbreak() is typically invoked from this event's callback.
+  This behavior is analogous to the "break;" statement.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_loopbreak(), event_loopexit()
+ */
+int event_loopbreak(void);
+
+/**
+  Abort the active event_base_loop() immediately.
+
+  event_base_loop() will abort the loop after the next event is completed;
+  event_base_loopbreak() is typically invoked from this event's callback.
+  This behavior is analogous to the "break;" statement.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @param eb the event_base structure returned by event_init()
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_loopexit
+ */
+int event_base_loopbreak(struct event_base *);
+
+
+/**
+  Add a timer event.
+
+  @param ev the event struct
+  @param tv timeval struct
+ */
+#define evtimer_add(ev, tv)		event_add(ev, tv)
+
+
+/**
+  Define a timer event.
+
+  @param ev event struct to be modified
+  @param cb callback function
+  @param arg argument that will be passed to the callback function
+ */
+#define evtimer_set(ev, cb, arg)	event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Delete a timer event.
+ *
+ * @param ev the event struct to be disabled
+ */
+#define evtimer_del(ev)			event_del(ev)
+#define evtimer_pending(ev, tv)		event_pending(ev, EV_TIMEOUT, tv)
+#define evtimer_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
+
+/**
+ * Add a timeout event.
+ *
+ * @param ev the event struct to be disabled
+ * @param tv the timeout value, in seconds
+ */
+#define timeout_add(ev, tv)		event_add(ev, tv)
+
+
+/**
+ * Define a timeout event.
+ *
+ * @param ev the event struct to be defined
+ * @param cb the callback to be invoked when the timeout expires
+ * @param arg the argument to be passed to the callback
+ */
+#define timeout_set(ev, cb, arg)	event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Disable a timeout event.
+ *
+ * @param ev the timeout event to be disabled
+ */
+#define timeout_del(ev)			event_del(ev)
+
+#define timeout_pending(ev, tv)		event_pending(ev, EV_TIMEOUT, tv)
+#define timeout_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
+
+#define signal_add(ev, tv)		event_add(ev, tv)
+#define signal_set(ev, x, cb, arg)	\
+	event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
+#define signal_del(ev)			event_del(ev)
+#define signal_pending(ev, tv)		event_pending(ev, EV_SIGNAL, tv)
+#define signal_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
+
+/**
+  Prepare an event structure to be added.
+
+  The function event_set() prepares the event structure ev to be used in
+  future calls to event_add() and event_del().  The event will be prepared to
+  call the function specified by the fn argument with an int argument
+  indicating the file descriptor, a short argument indicating the type of
+  event, and a void * argument given in the arg argument.  The fd indicates
+  the file descriptor that should be monitored for events.  The events can be
+  either EV_READ, EV_WRITE, or both.  Indicating that an application can read
+  or write from the file descriptor respectively without blocking.
+
+  The function fn will be called with the file descriptor that triggered the
+  event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL,
+  EV_READ, or EV_WRITE.  The additional flag EV_PERSIST makes an event_add()
+  persistent until event_del() has been called.
+
+  @param ev an event struct to be modified
+  @param fd the file descriptor to be monitored
+  @param event desired events to monitor; can be EV_READ and/or EV_WRITE
+  @param fn callback function to be invoked when the event occurs
+  @param arg an argument to be passed to the callback function
+
+  @see event_add(), event_del(), event_once()
+
+ */
+void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+
+/**
+  Schedule a one-time event to occur.
+
+  The function event_once() is similar to event_set().  However, it schedules
+  a callback to be called exactly once and does not require the caller to
+  prepare an event structure.
+
+  @param fd a file descriptor to monitor
+  @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+         EV_WRITE
+  @param callback callback function to be invoked when the event occurs
+  @param arg an argument to be passed to the callback function
+  @param timeout the maximum amount of time to wait for the event, or NULL
+         to wait forever
+  @return 0 if successful, or -1 if an error occurred
+  @see event_set()
+
+ */
+int event_once(int, short, void (*)(int, short, void *), void *,
+    const struct timeval *);
+
+
+/**
+  Schedule a one-time event (threadsafe variant)
+
+  The function event_base_once() is similar to event_set().  However, it
+  schedules a callback to be called exactly once and does not require the
+  caller to prepare an event structure.
+
+  @param base an event_base returned by event_init()
+  @param fd a file descriptor to monitor
+  @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+         EV_WRITE
+  @param callback callback function to be invoked when the event occurs
+  @param arg an argument to be passed to the callback function
+  @param timeout the maximum amount of time to wait for the event, or NULL
+         to wait forever
+  @return 0 if successful, or -1 if an error occurred
+  @see event_once()
+ */
+int event_base_once(struct event_base *base, int fd, short events,
+    void (*callback)(int, short, void *), void *arg,
+    const struct timeval *timeout);
+
+
+/**
+  Add an event to the set of monitored events.
+
+  The function event_add() schedules the execution of the ev event when the
+  event specified in event_set() occurs or in at least the time specified in
+  the tv.  If tv is NULL, no timeout occurs and the function will only be
+  called if a matching event occurs on the file descriptor.  The event in the
+  ev argument must be already initialized by event_set() and may not be used
+  in calls to event_set() until it has timed out or been removed with
+  event_del().  If the event in the ev argument already has a scheduled
+  timeout, the old timeout will be replaced by the new one.
+
+  @param ev an event struct initialized via event_set()
+  @param timeout the maximum amount of time to wait for the event, or NULL
+         to wait forever
+  @return 0 if successful, or -1 if an error occurred
+  @see event_del(), event_set()
+  */
+int event_add(struct event *ev, const struct timeval *timeout);
+
+
+/**
+  Remove an event from the set of monitored events.
+
+  The function event_del() will cancel the event in the argument ev.  If the
+  event has already executed or has never been added the call will have no
+  effect.
+
+  @param ev an event struct to be removed from the working set
+  @return 0 if successful, or -1 if an error occurred
+  @see event_add()
+ */
+int event_del(struct event *);
+
+void event_active(struct event *, int, short);
+
+
+/**
+  Checks if a specific event is pending or scheduled.
+
+  @param ev an event struct previously passed to event_add()
+  @param event the requested event type; any of EV_TIMEOUT|EV_READ|
+         EV_WRITE|EV_SIGNAL
+  @param tv an alternate timeout (FIXME - is this true?)
+
+  @return 1 if the event is pending, or 0 if the event has not occurred
+
+ */
+int event_pending(struct event *ev, short event, struct timeval *tv);
+
+
+/**
+  Test if an event structure has been initialized.
+
+  The event_initialized() macro can be used to check if an event has been
+  initialized.
+
+  @param ev an event structure to be tested
+  @return 1 if the structure has been initialized, or 0 if it has not been
+          initialized
+ */
+#ifdef WIN32
+#define event_initialized(ev)		((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
+#else
+#define event_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
+#endif
+
+
+/**
+  Get the libevent version number.
+
+  @return a string containing the version number of libevent
+ */
+const char *event_get_version(void);
+
+
+/**
+  Get the kernel event notification mechanism used by libevent.
+
+  @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+const char *event_get_method(void);
+
+
+/**
+  Set the number of different event priorities.
+
+  By default libevent schedules all active events with the same priority.
+  However, some time it is desirable to process some events with a higher
+  priority than others.  For that reason, libevent supports strict priority
+  queues.  Active events with a lower priority are always processed before
+  events with a higher priority.
+
+  The number of different priorities can be set initially with the
+  event_priority_init() function.  This function should be called before the
+  first call to event_dispatch().  The event_priority_set() function can be
+  used to assign a priority to an event.  By default, libevent assigns the
+  middle priority to all events unless their priority is explicitly set.
+
+  @param npriorities the maximum number of priorities
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_priority_init(), event_priority_set()
+
+ */
+int	event_priority_init(int);
+
+
+/**
+  Set the number of different event priorities (threadsafe variant).
+
+  See the description of event_priority_init() for more information.
+
+  @param eb the event_base structure returned by event_init()
+  @param npriorities the maximum number of priorities
+  @return 0 if successful, or -1 if an error occurred
+  @see event_priority_init(), event_priority_set()
+ */
+int	event_base_priority_init(struct event_base *, int);
+
+
+/**
+  Assign a priority to an event.
+
+  @param ev an event struct
+  @param priority the new priority to be assigned
+  @return 0 if successful, or -1 if an error occurred
+  @see event_priority_init()
+  */
+int	event_priority_set(struct event *, int);
+
+
+/* These functions deal with buffering input and output */
+
+struct evbuffer {
+	u_char *buffer;
+	u_char *orig_buffer;
+
+	size_t misalign;
+	size_t totallen;
+	size_t off;
+
+	void (*cb)(struct evbuffer *, size_t, size_t, void *);
+	void *cbarg;
+};
+
+/* Just for error reporting - use other constants otherwise */
+#define EVBUFFER_READ		0x01
+#define EVBUFFER_WRITE		0x02
+#define EVBUFFER_EOF		0x10
+#define EVBUFFER_ERROR		0x20
+#define EVBUFFER_TIMEOUT	0x40
+
+struct bufferevent;
+typedef void (*evbuffercb)(struct bufferevent *, void *);
+typedef void (*everrorcb)(struct bufferevent *, short what, void *);
+
+struct event_watermark {
+	size_t low;
+	size_t high;
+};
+
+#ifndef EVENT_NO_STRUCT
+struct bufferevent {
+	struct event_base *ev_base;
+
+	struct event ev_read;
+	struct event ev_write;
+
+	struct evbuffer *input;
+	struct evbuffer *output;
+
+	struct event_watermark wm_read;
+	struct event_watermark wm_write;
+
+	evbuffercb readcb;
+	evbuffercb writecb;
+	everrorcb errorcb;
+	void *cbarg;
+
+	int timeout_read;	/* in seconds */
+	int timeout_write;	/* in seconds */
+
+	short enabled;	/* events that are currently enabled */
+};
+#endif
+
+/**
+  Create a new bufferevent.
+
+  libevent provides an abstraction on top of the regular event callbacks.
+  This abstraction is called a buffered event.  A buffered event provides
+  input and output buffers that get filled and drained automatically.  The
+  user of a buffered event no longer deals directly with the I/O, but
+  instead is reading from input and writing to output buffers.
+
+  Once initialized, the bufferevent structure can be used repeatedly with
+  bufferevent_enable() and bufferevent_disable().
+
+  When read enabled the bufferevent will try to read from the file descriptor
+  and call the read callback.  The write callback is executed whenever the
+  output buffer is drained below the write low watermark, which is 0 by
+  default.
+
+  If multiple bases are in use, bufferevent_base_set() must be called before
+  enabling the bufferevent for the first time.
+
+  @param fd the file descriptor from which data is read and written to.
+  		This file descriptor is not allowed to be a pipe(2).
+  @param readcb callback to invoke when there is data to be read, or NULL if
+         no callback is desired
+  @param writecb callback to invoke when the file descriptor is ready for
+         writing, or NULL if no callback is desired
+  @param errorcb callback to invoke when there is an error on the file
+         descriptor
+  @param cbarg an argument that will be supplied to each of the callbacks
+         (readcb, writecb, and errorcb)
+  @return a pointer to a newly allocated bufferevent struct, or NULL if an
+          error occurred
+  @see bufferevent_base_set(), bufferevent_free()
+  */
+struct bufferevent *bufferevent_new(int fd,
+    evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+
+/**
+  Assign a bufferevent to a specific event_base.
+
+  @param base an event_base returned by event_init()
+  @param bufev a bufferevent struct returned by bufferevent_new()
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_new()
+ */
+int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
+
+
+/**
+  Assign a priority to a bufferevent.
+
+  @param bufev a bufferevent struct
+  @param pri the priority to be assigned
+  @return 0 if successful, or -1 if an error occurred
+  */
+int bufferevent_priority_set(struct bufferevent *bufev, int pri);
+
+
+/**
+  Deallocate the storage associated with a bufferevent structure.
+
+  @param bufev the bufferevent structure to be freed.
+  */
+void bufferevent_free(struct bufferevent *bufev);
+
+
+/**
+  Changes the callbacks for a bufferevent.
+
+  @param bufev the bufferevent object for which to change callbacks
+  @param readcb callback to invoke when there is data to be read, or NULL if
+         no callback is desired
+  @param writecb callback to invoke when the file descriptor is ready for
+         writing, or NULL if no callback is desired
+  @param errorcb callback to invoke when there is an error on the file
+         descriptor
+  @param cbarg an argument that will be supplied to each of the callbacks
+         (readcb, writecb, and errorcb)
+  @see bufferevent_new()
+  */
+void bufferevent_setcb(struct bufferevent *bufev,
+    evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+/**
+  Changes the file descriptor on which the bufferevent operates.
+
+  @param bufev the bufferevent object for which to change the file descriptor
+  @param fd the file descriptor to operate on
+*/
+void bufferevent_setfd(struct bufferevent *bufev, int fd);
+
+/**
+  Write data to a bufferevent buffer.
+
+  The bufferevent_write() function can be used to write data to the file
+  descriptor.  The data is appended to the output buffer and written to the
+  descriptor automatically as it becomes available for writing.
+
+  @param bufev the bufferevent to be written to
+  @param data a pointer to the data to be written
+  @param size the length of the data, in bytes
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_write_buffer()
+  */
+int bufferevent_write(struct bufferevent *bufev,
+    const void *data, size_t size);
+
+
+/**
+  Write data from an evbuffer to a bufferevent buffer.  The evbuffer is
+  being drained as a result.
+
+  @param bufev the bufferevent to be written to
+  @param buf the evbuffer to be written
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_write()
+ */
+int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
+
+
+/**
+  Read data from a bufferevent buffer.
+
+  The bufferevent_read() function is used to read data from the input buffer.
+
+  @param bufev the bufferevent to be read from
+  @param data pointer to a buffer that will store the data
+  @param size the size of the data buffer, in bytes
+  @return the amount of data read, in bytes.
+ */
+size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
+
+/**
+  Enable a bufferevent.
+
+  @param bufev the bufferevent to be enabled
+  @param event any combination of EV_READ | EV_WRITE.
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_disable()
+ */
+int bufferevent_enable(struct bufferevent *bufev, short event);
+
+
+/**
+  Disable a bufferevent.
+
+  @param bufev the bufferevent to be disabled
+  @param event any combination of EV_READ | EV_WRITE.
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_enable()
+ */
+int bufferevent_disable(struct bufferevent *bufev, short event);
+
+
+/**
+  Set the read and write timeout for a buffered event.
+
+  @param bufev the bufferevent to be modified
+  @param timeout_read the read timeout
+  @param timeout_write the write timeout
+ */
+void bufferevent_settimeout(struct bufferevent *bufev,
+    int timeout_read, int timeout_write);
+
+
+/**
+  Sets the watermarks for read and write events.
+
+  On input, a bufferevent does not invoke the user read callback unless
+  there is at least low watermark data in the buffer.   If the read buffer
+  is beyond the high watermark, the buffevent stops reading from the network.
+
+  On output, the user write callback is invoked whenever the buffered data
+  falls below the low watermark.
+
+  @param bufev the bufferevent to be modified
+  @param events EV_READ, EV_WRITE or both
+  @param lowmark the lower watermark to set
+  @param highmark the high watermark to set
+*/
+
+void bufferevent_setwatermark(struct bufferevent *bufev, short events,
+    size_t lowmark, size_t highmark);
+
+#define EVBUFFER_LENGTH(x)	(x)->off
+#define EVBUFFER_DATA(x)	(x)->buffer
+#define EVBUFFER_INPUT(x)	(x)->input
+#define EVBUFFER_OUTPUT(x)	(x)->output
+
+
+/**
+  Allocate storage for a new evbuffer.
+
+  @return a pointer to a newly allocated evbuffer struct, or NULL if an error
+          occurred
+ */
+struct evbuffer *evbuffer_new(void);
+
+
+/**
+  Deallocate storage for an evbuffer.
+
+  @param pointer to the evbuffer to be freed
+ */
+void evbuffer_free(struct evbuffer *);
+
+
+/**
+  Expands the available space in an event buffer.
+
+  Expands the available space in the event buffer to at least datlen
+
+  @param buf the event buffer to be expanded
+  @param datlen the new minimum length requirement
+  @return 0 if successful, or -1 if an error occurred
+*/
+int evbuffer_expand(struct evbuffer *, size_t);
+
+
+/**
+  Append data to the end of an evbuffer.
+
+  @param buf the event buffer to be appended to
+  @param data pointer to the beginning of the data buffer
+  @param datlen the number of bytes to be copied from the data buffer
+ */
+int evbuffer_add(struct evbuffer *, const void *, size_t);
+
+
+
+/**
+  Read data from an event buffer and drain the bytes read.
+
+  @param buf the event buffer to be read from
+  @param data the destination buffer to store the result
+  @param datlen the maximum size of the destination buffer
+  @return the number of bytes read
+ */
+int evbuffer_remove(struct evbuffer *, void *, size_t);
+
+
+/**
+ * Read a single line from an event buffer.
+ *
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the caller.
+ *
+ * @param buffer the evbuffer to read from
+ * @return pointer to a single line, or NULL if an error occurred
+ */
+char *evbuffer_readline(struct evbuffer *);
+
+
+/**
+  Move data from one evbuffer into another evbuffer.
+
+  This is a destructive add.  The data from one buffer moves into
+  the other buffer. The destination buffer is expanded as needed.
+
+  @param outbuf the output buffer
+  @param inbuf the input buffer
+  @return 0 if successful, or -1 if an error occurred
+ */
+int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
+
+
+/**
+  Append a formatted string to the end of an evbuffer.
+
+  @param buf the evbuffer that will be appended to
+  @param fmt a format string
+  @param ... arguments that will be passed to printf(3)
+  @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...)
+#ifdef __GNUC__
+  __attribute__((format(printf, 2, 3)))
+#endif
+;
+
+
+/**
+  Append a va_list formatted string to the end of an evbuffer.
+
+  @param buf the evbuffer that will be appended to
+  @param fmt a format string
+  @param ap a varargs va_list argument array that will be passed to vprintf(3)
+  @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
+
+
+/**
+  Remove a specified number of bytes data from the beginning of an evbuffer.
+
+  @param buf the evbuffer to be drained
+  @param len the number of bytes to drain from the beginning of the buffer
+ */
+void evbuffer_drain(struct evbuffer *, size_t);
+
+
+/**
+  Write the contents of an evbuffer to a file descriptor.
+
+  The evbuffer will be drained after the bytes have been successfully written.
+
+  @param buffer the evbuffer to be written and drained
+  @param fd the file descriptor to be written to
+  @return the number of bytes written, or -1 if an error occurred
+  @see evbuffer_read()
+ */
+int evbuffer_write(struct evbuffer *, int);
+
+
+/**
+  Read from a file descriptor and store the result in an evbuffer.
+
+  @param buf the evbuffer to store the result
+  @param fd the file descriptor to read from
+  @param howmuch the number of bytes to be read
+  @return the number of bytes read, or -1 if an error occurred
+  @see evbuffer_write()
+ */
+int evbuffer_read(struct evbuffer *, int, int);
+
+
+/**
+  Find a string within an evbuffer.
+
+  @param buffer the evbuffer to be searched
+  @param what the string to be searched for
+  @param len the length of the search string
+  @return a pointer to the beginning of the search string, or NULL if the search failed.
+ */
+u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
+
+/**
+  Set a callback to invoke when the evbuffer is modified.
+
+  @param buffer the evbuffer to be monitored
+  @param cb the callback function to invoke when the evbuffer is modified
+  @param cbarg an argument to be provided to the callback function
+ */
+void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
+
+/*
+ * Marshaling tagged data - We assume that all tags are inserted in their
+ * numeric order - so that unknown tags will always be higher than the
+ * known ones - and we can just ignore the end of an event buffer.
+ */
+
+void evtag_init(void);
+
+void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
+    ev_uint32_t len);
+
+/**
+  Encode an integer and store it in an evbuffer.
+
+  We encode integer's by nibbles; the first nibble contains the number
+  of significant nibbles - 1;  this allows us to encode up to 64-bit
+  integers.  This function is byte-order independent.
+
+  @param evbuf evbuffer to store the encoded number
+  @param number a 32-bit integer
+ */
+void encode_int(struct evbuffer *evbuf, ev_uint32_t number);
+
+void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
+    ev_uint32_t integer);
+
+void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
+    const char *string);
+
+void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
+    struct timeval *tv);
+
+int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
+    struct evbuffer *dst);
+int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
+int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+int evtag_consume(struct evbuffer *evbuf);
+
+int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    ev_uint32_t *pinteger);
+
+int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
+    void *data, size_t len);
+
+int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    char **pstring);
+
+int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    struct timeval *ptv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVENT_H_ */
diff --git a/third_party/libevent/event_rpcgen.py b/third_party/libevent/event_rpcgen.py
new file mode 100755
index 0000000..4ec77a6
--- /dev/null
+++ b/third_party/libevent/event_rpcgen.py
@@ -0,0 +1,1423 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2005 Niels Provos <provos@citi.umich.edu>
+# All rights reserved.
+#
+# Generates marshaling code based on libevent.
+
+import sys
+import re
+
+#
+_NAME = "event_rpcgen.py"
+_VERSION = "0.1"
+_STRUCT_RE = '[a-z][a-z_0-9]*'
+
+# Globals
+line_count = 0
+
+white = re.compile(r'^\s+')
+cppcomment = re.compile(r'\/\/.*$')
+headerdirect = []
+cppdirect = []
+
+# Holds everything that makes a struct
+class Struct:
+    def __init__(self, name):
+        self._name = name
+        self._entries = []
+        self._tags = {}
+        print >>sys.stderr, '  Created struct: %s' % name
+
+    def AddEntry(self, entry):
+        if self._tags.has_key(entry.Tag()):
+            print >>sys.stderr, ( 'Entry "%s" duplicates tag number '
+                                  '%d from "%s" around line %d' ) % (
+                entry.Name(), entry.Tag(),
+                self._tags[entry.Tag()], line_count)
+            sys.exit(1)
+        self._entries.append(entry)
+        self._tags[entry.Tag()] = entry.Name()
+        print >>sys.stderr, '    Added entry: %s' % entry.Name()
+
+    def Name(self):
+        return self._name
+
+    def EntryTagName(self, entry):
+        """Creates the name inside an enumeration for distinguishing data
+        types."""
+        name = "%s_%s" % (self._name, entry.Name())
+        return name.upper()
+
+    def PrintIdented(self, file, ident, code):
+        """Takes an array, add indentation to each entry and prints it."""
+        for entry in code:
+            print >>file, '%s%s' % (ident, entry)
+
+    def PrintTags(self, file):
+        """Prints the tag definitions for a structure."""
+        print >>file, '/* Tag definition for %s */' % self._name
+        print >>file, 'enum %s_ {' % self._name.lower()
+        for entry in self._entries:
+            print >>file, '  %s=%d,' % (self.EntryTagName(entry),
+                                        entry.Tag())
+        print >>file, '  %s_MAX_TAGS' % (self._name.upper())
+        print >>file, '};\n'
+
+    def PrintForwardDeclaration(self, file):
+        print >>file, 'struct %s;' % self._name
+
+    def PrintDeclaration(self, file):
+        print >>file, '/* Structure declaration for %s */' % self._name
+        print >>file, 'struct %s_access_ {' % self._name
+        for entry in self._entries:
+            dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
+            dcl.extend(
+                entry.GetDeclaration('(*%s_get)' % entry.Name()))
+            if entry.Array():
+                dcl.extend(
+                    entry.AddDeclaration('(*%s_add)' % entry.Name()))
+            self.PrintIdented(file, '  ', dcl)
+        print >>file, '};\n'
+
+        print >>file, 'struct %s {' % self._name
+        print >>file, '  struct %s_access_ *base;\n' % self._name
+        for entry in self._entries:
+            dcl = entry.Declaration()
+            self.PrintIdented(file, '  ', dcl)
+        print >>file, ''
+        for entry in self._entries:
+            print >>file, '  ev_uint8_t %s_set;' % entry.Name()
+        print >>file, '};\n'
+
+        print >>file, \
+"""struct %(name)s *%(name)s_new(void);
+void %(name)s_free(struct %(name)s *);
+void %(name)s_clear(struct %(name)s *);
+void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
+int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
+int %(name)s_complete(struct %(name)s *);
+void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, 
+    const struct %(name)s *);
+int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
+    struct %(name)s *);""" % { 'name' : self._name }
+
+
+        # Write a setting function of every variable
+        for entry in self._entries:
+            self.PrintIdented(file, '', entry.AssignDeclaration(
+                entry.AssignFuncName()))
+            self.PrintIdented(file, '', entry.GetDeclaration(
+                entry.GetFuncName()))
+            if entry.Array():
+                self.PrintIdented(file, '', entry.AddDeclaration(
+                    entry.AddFuncName()))
+
+        print >>file, '/* --- %s done --- */\n' % self._name
+
+    def PrintCode(self, file):
+        print >>file, ('/*\n'
+                       ' * Implementation of %s\n'
+                       ' */\n') % self._name
+
+        print >>file, \
+              'static struct %(name)s_access_ __%(name)s_base = {' % \
+              { 'name' : self._name }
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeBase())
+        print >>file, '};\n'
+
+        # Creation
+        print >>file, (
+            'struct %(name)s *\n'
+            '%(name)s_new(void)\n'
+            '{\n'
+            '  struct %(name)s *tmp;\n'
+            '  if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
+            '    event_warn("%%s: malloc", __func__);\n'
+            '    return (NULL);\n'
+            '  }\n'
+            '  tmp->base = &__%(name)s_base;\n') % { 'name' : self._name }
+
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeNew('tmp'))
+            print >>file, '  tmp->%s_set = 0;\n' % entry.Name()
+
+        print >>file, (
+            '  return (tmp);\n'
+            '}\n')
+
+        # Adding
+        for entry in self._entries:
+            if entry.Array():
+                self.PrintIdented(file, '', entry.CodeAdd())
+            print >>file, ''
+            
+        # Assigning
+        for entry in self._entries:
+            self.PrintIdented(file, '', entry.CodeAssign())
+            print >>file, ''
+
+        # Getting
+        for entry in self._entries:
+            self.PrintIdented(file, '', entry.CodeGet())
+            print >>file, ''
+            
+        # Clearing
+        print >>file, ( 'void\n'
+                        '%(name)s_clear(struct %(name)s *tmp)\n'
+                        '{'
+                        ) % { 'name' : self._name }
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeClear('tmp'))
+
+        print >>file, '}\n'
+
+        # Freeing
+        print >>file, ( 'void\n'
+                        '%(name)s_free(struct %(name)s *tmp)\n'
+                        '{'
+                        ) % { 'name' : self._name }
+        
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeFree('tmp'))
+
+        print >>file, ('  free(tmp);\n'
+                       '}\n')
+
+        # Marshaling
+        print >>file, ('void\n'
+                       '%(name)s_marshal(struct evbuffer *evbuf, '
+                       'const struct %(name)s *tmp)'
+                       '{') % { 'name' : self._name }
+        for entry in self._entries:
+            indent = '  '
+            # Optional entries do not have to be set
+            if entry.Optional():
+                indent += '  '
+                print >>file, '  if (tmp->%s_set) {' % entry.Name()
+            self.PrintIdented(
+                file, indent,
+                entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp'))
+            if entry.Optional():
+                print >>file, '  }'
+
+        print >>file, '}\n'
+                       
+        # Unmarshaling
+        print >>file, ('int\n'
+                       '%(name)s_unmarshal(struct %(name)s *tmp, '
+                       ' struct evbuffer *evbuf)\n'
+                       '{\n'
+                       '  ev_uint32_t tag;\n'
+                       '  while (EVBUFFER_LENGTH(evbuf) > 0) {\n'
+                       '    if (evtag_peek(evbuf, &tag) == -1)\n'
+                       '      return (-1);\n'
+                       '    switch (tag) {\n'
+                       ) % { 'name' : self._name }
+        for entry in self._entries:
+            print >>file, '      case %s:\n' % self.EntryTagName(entry)
+            if not entry.Array():
+                print >>file, (
+                    '        if (tmp->%s_set)\n'
+                    '          return (-1);'
+                    ) % (entry.Name())
+
+            self.PrintIdented(
+                file, '        ',
+                entry.CodeUnmarshal('evbuf',
+                                    self.EntryTagName(entry), 'tmp'))
+
+            print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() +
+                            '        break;\n' )
+        print >>file, ( '      default:\n'
+                        '        return -1;\n'
+                        '    }\n'
+                        '  }\n' )
+        # Check if it was decoded completely
+        print >>file, ( '  if (%(name)s_complete(tmp) == -1)\n'
+                        '    return (-1);'
+                        ) % { 'name' : self._name }
+
+        # Successfully decoded
+        print >>file, ( '  return (0);\n'
+                        '}\n')
+
+        # Checking if a structure has all the required data
+        print >>file, (
+            'int\n'
+            '%(name)s_complete(struct %(name)s *msg)\n'
+            '{' ) % { 'name' : self._name }
+        for entry in self._entries:
+            self.PrintIdented(
+                file, '  ',
+                entry.CodeComplete('msg'))
+        print >>file, (
+            '  return (0);\n'
+            '}\n' )
+
+        # Complete message unmarshaling
+        print >>file, (
+            'int\n'
+            'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
+            'ev_uint32_t need_tag, struct %(name)s *msg)\n'
+            '{\n'
+            '  ev_uint32_t tag;\n'
+            '  int res = -1;\n'
+            '\n'
+            '  struct evbuffer *tmp = evbuffer_new();\n'
+            '\n'
+            '  if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
+            ' || tag != need_tag)\n'
+            '    goto error;\n'
+            '\n'
+            '  if (%(name)s_unmarshal(msg, tmp) == -1)\n'
+            '    goto error;\n'
+            '\n'
+            '  res = 0;\n'
+            '\n'
+            ' error:\n'
+            '  evbuffer_free(tmp);\n'
+            '  return (res);\n'
+            '}\n' ) % { 'name' : self._name }
+
+        # Complete message marshaling
+        print >>file, (
+            'void\n'
+            'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
+            'const struct %(name)s *msg)\n'
+            '{\n'
+            '  struct evbuffer *_buf = evbuffer_new();\n'
+            '  assert(_buf != NULL);\n'
+            '  evbuffer_drain(_buf, -1);\n'
+            '  %(name)s_marshal(_buf, msg);\n'
+            '  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), '
+            'EVBUFFER_LENGTH(_buf));\n'
+            '  evbuffer_free(_buf);\n'
+            '}\n' ) % { 'name' : self._name }
+
+class Entry:
+    def __init__(self, type, name, tag):
+        self._type = type
+        self._name = name
+        self._tag = int(tag)
+        self._ctype = type
+        self._optional = 0
+        self._can_be_array = 0
+        self._array = 0
+        self._line_count = -1
+        self._struct = None
+        self._refname = None
+
+    def GetTranslation(self):
+        return { "parent_name" : self._struct.Name(),
+                 "name" : self._name,
+                 "ctype" : self._ctype,
+                 "refname" : self._refname
+                 }
+    
+    def SetStruct(self, struct):
+        self._struct = struct
+
+    def LineCount(self):
+        assert self._line_count != -1
+        return self._line_count
+
+    def SetLineCount(self, number):
+        self._line_count = number
+
+    def Array(self):
+        return self._array
+
+    def Optional(self):
+        return self._optional
+
+    def Tag(self):
+        return self._tag
+
+    def Name(self):
+        return self._name
+
+    def Type(self):
+        return self._type
+
+    def MakeArray(self, yes=1):
+        self._array = yes
+        
+    def MakeOptional(self):
+        self._optional = 1
+
+    def GetFuncName(self):
+        return '%s_%s_get' % (self._struct.Name(), self._name)
+    
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+
+    def CodeGet(self):
+        code = (
+            'int',
+            '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
+            '%(ctype)s *value)',
+            '{',
+            '  if (msg->%(name)s_set != 1)',
+            '    return (-1);',
+            '  *value = msg->%(name)s_data;',
+            '  return (0);',
+            '}' )
+        code = '\n'.join(code)
+        code = code % self.GetTranslation()
+        return code.split('\n')
+        
+    def AssignFuncName(self):
+        return '%s_%s_assign' % (self._struct.Name(), self._name)
+    
+    def AddFuncName(self):
+        return '%s_%s_add' % (self._struct.Name(), self._name)
+    
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+
+    def CodeAssign(self):
+        code = [ 'int',
+                 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
+                 ' const %(ctype)s value)',
+                 '{',
+                 '  msg->%(name)s_set = 1;',
+                 '  msg->%(name)s_data = value;',
+                 '  return (0);',
+                 '}' ]
+        code = '\n'.join(code)
+        code = code % self.GetTranslation()
+        return code.split('\n')
+
+    def CodeClear(self, structname):
+        code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
+
+        return code
+        
+    def CodeComplete(self, structname):
+        if self.Optional():
+            return []
+        
+        code = [ 'if (!%s->%s_set)' % (structname, self.Name()),
+                 '  return (-1);' ]
+
+        return code
+
+    def CodeFree(self, name):
+        return []
+
+    def CodeBase(self):
+        code = [
+            '%(parent_name)s_%(name)s_assign,',
+            '%(parent_name)s_%(name)s_get,'
+            ]
+        if self.Array():
+            code.append('%(parent_name)s_%(name)s_add,')
+
+        code = '\n'.join(code)
+        code = code % self.GetTranslation()
+        return code.split('\n')
+
+    def Verify(self):
+        if self.Array() and not self._can_be_array:
+            print >>sys.stderr, (
+                'Entry "%s" cannot be created as an array '
+                'around line %d' ) % (self._name, self.LineCount())
+            sys.exit(1)
+        if not self._struct:
+            print >>sys.stderr, (
+                'Entry "%s" does not know which struct it belongs to '
+                'around line %d' ) % (self._name, self.LineCount())
+            sys.exit(1)
+        if self._optional and self._array:
+            print >>sys.stderr,  ( 'Entry "%s" has illegal combination of '
+                                   'optional and array around line %d' ) % (
+                self._name, self.LineCount() )
+            sys.exit(1)
+
+class EntryBytes(Entry):
+    def __init__(self, type, name, tag, length):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._length = length
+        self._ctype = 'ev_uint8_t'
+
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s **);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def Declaration(self):
+        dcl  = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
+        
+        return dcl
+
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s **value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1)' % name,
+                 '    return (-1);',
+                 '  *value = msg->%s_data;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, const %s *value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  msg->%s_set = 1;' % name,
+                 '  memcpy(msg->%s_data, value, %s);' % (
+            name, self._length),
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = [  'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) +
+                  '%s->%s_data, ' % (var_name, self._name) +
+                  'sizeof(%s->%s_data)) == -1) {' % (
+            var_name, self._name),
+                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                  '  return (-1);',
+                  '}'
+                  ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % (
+            buf, tag_name, var_name, self._name, var_name, self._name )]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ '%s->%s_set = 0;' % (structname, self.Name()),
+                 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+            structname, self._name, structname, self._name)]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+            name, self._name, name, self._name)]
+        return code
+
+    def Verify(self):
+        if not self._length:
+            print >>sys.stderr, 'Entry "%s" needs a length around line %d' % (
+                self._name, self.LineCount() )
+            sys.exit(1)
+
+        Entry.Verify(self)
+
+class EntryInt(Entry):
+    def __init__(self, type, name, tag):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._ctype = 'ev_uint32_t'
+
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % (
+            buf, tag_name, var_name, self._name),
+                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}' ] 
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % (
+            buf, tag_name, var_name, self._name)]
+        return code
+
+    def Declaration(self):
+        dcl  = ['ev_uint32_t %s_data;' % self._name]
+
+        return dcl
+
+    def CodeNew(self, name):
+        code = ['%s->%s_data = 0;' % (name, self._name)]
+        return code
+
+class EntryString(Entry):
+    def __init__(self, type, name, tag):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._ctype = 'char *'
+
+    def CodeAssign(self):
+        name = self._name
+        code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+    const %(ctype)s value)
+{
+  if (msg->%(name)s_data != NULL)
+    free(msg->%(name)s_data);
+  if ((msg->%(name)s_data = strdup(value)) == NULL)
+    return (-1);
+  msg->%(name)s_set = 1;
+  return (0);
+}""" % self.GetTranslation()
+
+        return code.split('\n')
+        
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % (
+            buf, tag_name, var_name, self._name),
+                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % (
+            buf, tag_name, var_name, self._name)]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  free (%s->%s_data);' % (structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name)]
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
+                 '    free (%s->%s_data); ' % (name, self._name)]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['char *%s_data;' % self._name]
+
+        return dcl
+
+class EntryStruct(Entry):
+    def __init__(self, type, name, tag, refname):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._can_be_array = 1
+        self._refname = refname
+        self._ctype = 'struct %s*' % refname
+
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s *value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1) {' % name,
+                 '    msg->%s_data = %s_new();' % (name, self._refname),
+                 '    if (msg->%s_data == NULL)' % name,
+                 '      return (-1);',
+                 '    msg->%s_set = 1;' % name,
+                 '  }',
+                 '  *value = msg->%s_data;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+    const %(ctype)s value)
+{
+   struct evbuffer *tmp = NULL;
+   if (msg->%(name)s_set) {
+     %(refname)s_clear(msg->%(name)s_data);
+     msg->%(name)s_set = 0;
+   } else {
+     msg->%(name)s_data = %(refname)s_new();
+     if (msg->%(name)s_data == NULL) {
+       event_warn("%%s: %(refname)s_new()", __func__);
+       goto error;
+     }
+   }
+   if ((tmp = evbuffer_new()) == NULL) {
+     event_warn("%%s: evbuffer_new()", __func__);
+     goto error;
+   }
+   %(refname)s_marshal(tmp, value);
+   if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
+     event_warnx("%%s: %(refname)s_unmarshal", __func__);
+     goto error;
+   }
+   msg->%(name)s_set = 1;
+   evbuffer_free(tmp);
+   return (0);
+ error:
+   if (tmp != NULL)
+     evbuffer_free(tmp);
+   if (msg->%(name)s_data != NULL) {
+     %(refname)s_free(msg->%(name)s_data);
+     msg->%(name)s_data = NULL;
+   }
+   return (-1);
+}""" % self.GetTranslation()
+        return code.split('\n')
+        
+    def CodeComplete(self, structname):
+        if self.Optional():
+            code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % (
+                structname, self.Name(),
+                self._refname, structname, self.Name()),
+                     '  return (-1);' ]
+        else:
+            code = [ 'if (%s_complete(%s->%s_data) == -1)' % (
+                self._refname, structname, self.Name()),
+                     '  return (-1);' ]
+
+        return code
+    
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['%s->%s_data = %s_new();' % (
+            var_name, self._name, self._refname),
+                'if (%s->%s_data == NULL)' % (var_name, self._name),
+                '  return (-1);',
+                'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % (
+            self._refname, buf, tag_name, var_name, self._name),
+                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % (
+            self._refname, buf, tag_name, var_name, self._name)]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  %s_free(%s->%s_data);' % (
+            self._refname, structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name)]
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
+                 '    %s_free(%s->%s_data); ' % (
+            self._refname, name, self._name)]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['%s %s_data;' % (self._ctype, self._name)]
+
+        return dcl
+
+class EntryVarBytes(Entry):
+    def __init__(self, type, name, tag):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._ctype = 'ev_uint8_t *'
+
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, '
+                 'const %s value, ev_uint32_t len)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_data != NULL)' % name,
+                 '    free (msg->%s_data);' % name,
+                 '  msg->%s_data = malloc(len);' % name,
+                 '  if (msg->%s_data == NULL)' % name,
+                 '    return (-1);',
+                 '  msg->%s_set = 1;' % name,
+                 '  msg->%s_length = len;' % name,
+                 '  memcpy(msg->%s_data, value, len);' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1)' % name,
+                 '    return (-1);',
+                 '  *value = msg->%s_data;' % name,
+                 '  *plen = msg->%s_length;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % (
+            buf, var_name, self._name),
+                '  return (-1);',
+                # We do not want DoS opportunities
+                'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % (
+            var_name, self._name, buf),
+                '  return (-1);',
+                'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % (
+            var_name, self._name, var_name, self._name),
+                '  return (-1);',
+                'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, '
+                '%s->%s_length) == -1) {' % (
+            buf, tag_name, var_name, self._name, var_name, self._name),
+                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % (
+            buf, tag_name, var_name, self._name, var_name, self._name)]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  free (%s->%s_data);' % (structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_length = 0;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name),
+                 '%s->%s_length = 0;' % (name, self._name) ]
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
+                 '    free (%s->%s_data); ' % (name, self._name)]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['ev_uint8_t *%s_data;' % self._name,
+                'ev_uint32_t %s_length;' % self._name]
+
+        return dcl
+
+class EntryArray(Entry):
+    def __init__(self, entry):
+        # Init base class
+        Entry.__init__(self, entry._type, entry._name, entry._tag)
+
+        self._entry = entry
+        self._refname = entry._refname
+        self._ctype = 'struct %s *' % self._refname
+
+    def GetDeclaration(self, funcname):
+        """Allows direct access to elements of the array."""
+        translate = self.GetTranslation()
+        translate["funcname"] = funcname
+        code = [
+            'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
+            translate ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, int, const %s);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AddDeclaration(self, funcname):
+        code = [ '%s %s(struct %s *);' % (
+            self._ctype, funcname, self._struct.Name() ) ]
+        return code
+        
+    def CodeGet(self):
+        code = """int
+%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
+    %(ctype)s *value)
+{
+  if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
+    return (-1);
+  *value = msg->%(name)s_data[offset];
+  return (0);
+}""" % self.GetTranslation()
+
+        return code.split('\n')
+        
+    def CodeAssign(self):
+        code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,
+    const %(ctype)s value)
+{
+  struct evbuffer *tmp = NULL;
+  if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)
+    return (-1);
+  %(refname)s_clear(msg->%(name)s_data[off]);
+  if ((tmp = evbuffer_new()) == NULL) {
+    event_warn("%%s: evbuffer_new()", __func__);
+    goto error;
+  }
+  %(refname)s_marshal(tmp, value);
+  if (%(refname)s_unmarshal(msg->%(name)s_data[off], tmp) == -1) {
+    event_warnx("%%s: %(refname)s_unmarshal", __func__);
+    goto error;
+  }
+  evbuffer_free(tmp);
+  return (0);
+error:
+  if (tmp != NULL)
+    evbuffer_free(tmp);
+  %(refname)s_clear(msg->%(name)s_data[off]);
+  return (-1);
+}""" % self.GetTranslation()
+
+        return code.split('\n')
+        
+    def CodeAdd(self):
+        code = \
+"""%(ctype)s
+%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg)
+{
+  if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {
+    int tobe_allocated = msg->%(name)s_num_allocated;
+    %(ctype)s* new_data = NULL;
+    tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+    new_data = (%(ctype)s*) realloc(msg->%(name)s_data,
+        tobe_allocated * sizeof(%(ctype)s));
+    if (new_data == NULL)
+      goto error;
+    msg->%(name)s_data = new_data;
+    msg->%(name)s_num_allocated = tobe_allocated;
+  }
+  msg->%(name)s_data[msg->%(name)s_length - 1] = %(refname)s_new();
+  if (msg->%(name)s_data[msg->%(name)s_length - 1] == NULL)
+    goto error;
+  msg->%(name)s_set = 1;
+  return (msg->%(name)s_data[msg->%(name)s_length - 1]);
+error:
+  --msg->%(name)s_length;
+  return (NULL);
+}
+        """ % self.GetTranslation()
+
+        return code.split('\n')
+
+    def CodeComplete(self, structname):
+        code = []
+        translate = self.GetTranslation()
+
+        if self.Optional():
+            code.append( 'if (%(structname)s->%(name)s_set)'  % translate)
+
+        translate["structname"] = structname
+        tmp = """{
+  int i;
+  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {
+    if (%(refname)s_complete(%(structname)s->%(name)s_data[i]) == -1)
+      return (-1);
+  }
+}""" % translate
+        code.extend(tmp.split('\n'))
+
+        return code
+    
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        translate = self.GetTranslation()
+        translate["var_name"] = var_name
+        translate["buf"] = buf
+        translate["tag_name"] = tag_name
+        code = """if (%(parent_name)s_%(name)s_add(%(var_name)s) == NULL)
+  return (-1);
+if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag_name)s,
+  %(var_name)s->%(name)s_data[%(var_name)s->%(name)s_length - 1]) == -1) {
+  --%(var_name)s->%(name)s_length;
+  event_warnx("%%s: failed to unmarshal %(name)s", __func__);
+  return (-1);
+}""" % translate
+
+        return code.split('\n')
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['{',
+                '  int i;',
+                '  for (i = 0; i < %s->%s_length; ++i) {' % (
+            var_name, self._name),
+                '    evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % (
+            self._refname, buf, tag_name, var_name, self._name),
+                '  }',
+                '}'
+                ]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  int i;',
+                 '  for (i = 0; i < %s->%s_length; ++i) {' % (
+            structname, self.Name()),
+                 '    %s_free(%s->%s_data[i]);' % (
+            self._refname, structname, self.Name()),
+                 '  }',
+                 '  free(%s->%s_data);' % (structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '  %s->%s_length = 0;' % (structname, self.Name()),
+                 '  %s->%s_num_allocated = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name),
+                 '%s->%s_length = 0;' % (name, self._name),
+                 '%s->%s_num_allocated = 0;' % (name, self._name)]
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL) {' % (name, self._name),
+                 '  int i;',
+                 '  for (i = 0; i < %s->%s_length; ++i) {' % (
+            name, self._name),
+                 '    %s_free(%s->%s_data[i]); ' % (
+            self._refname, name, self._name),
+                 '    %s->%s_data[i] = NULL;' % (name, self._name),
+                 '  }',
+                 '  free(%s->%s_data);' % (name, self._name),
+                 '  %s->%s_data = NULL;' % (name, self._name),
+                 '  %s->%s_length = 0;' % (name, self._name),
+                 '  %s->%s_num_allocated = 0;' % (name, self._name),
+                 '}'
+                 ]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['struct %s **%s_data;' % (self._refname, self._name),
+                'int %s_length;' % self._name,
+                'int %s_num_allocated;' % self._name ]
+
+        return dcl
+
+def NormalizeLine(line):
+    global white
+    global cppcomment
+    
+    line = cppcomment.sub('', line)
+    line = line.strip()
+    line = white.sub(' ', line)
+
+    return line
+
+def ProcessOneEntry(newstruct, entry):
+    optional = 0
+    array = 0
+    entry_type = ''
+    name = ''
+    tag = ''
+    tag_set = None
+    separator = ''
+    fixed_length = ''
+
+    tokens = entry.split(' ')
+    while tokens:
+        token = tokens[0]
+        tokens = tokens[1:]
+
+        if not entry_type:
+            if not optional and token == 'optional':
+                optional = 1
+                continue
+
+            if not array and token == 'array':
+                array = 1
+                continue
+
+        if not entry_type:
+            entry_type = token
+            continue
+
+        if not name:
+            res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
+            if not res:
+                print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % (
+                    entry, line_count)
+                sys.exit(1)
+            name = res.group(1)
+            fixed_length = res.group(2)
+            if fixed_length:
+                fixed_length = fixed_length[1:-1]
+            continue
+
+        if not separator:
+            separator = token
+            if separator != '=':
+                print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % (
+                    name, token)
+                sys.exit(1)
+            continue
+
+        if not tag_set:
+            tag_set = 1
+            if not re.match(r'^(0x)?[0-9]+$', token):
+                print >>sys.stderr, 'Expected tag number: \"%s\"' % entry
+                sys.exit(1)
+            tag = int(token, 0)
+            continue
+
+        print >>sys.stderr, 'Cannot parse \"%s\"' % entry
+        sys.exit(1)
+
+    if not tag_set:
+        print >>sys.stderr, 'Need tag number: \"%s\"' % entry
+        sys.exit(1)
+
+    # Create the right entry
+    if entry_type == 'bytes':
+        if fixed_length:
+            newentry = EntryBytes(entry_type, name, tag, fixed_length)
+        else:
+            newentry = EntryVarBytes(entry_type, name, tag)
+    elif entry_type == 'int' and not fixed_length:
+        newentry = EntryInt(entry_type, name, tag)
+    elif entry_type == 'string' and not fixed_length:
+        newentry = EntryString(entry_type, name, tag)
+    else:
+        res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE,
+                       entry_type, re.IGNORECASE)
+        if res:
+            # References another struct defined in our file
+            newentry = EntryStruct(entry_type, name, tag, res.group(1))
+        else:
+            print >>sys.stderr, 'Bad type: "%s" in "%s"' % (entry_type, entry)
+            sys.exit(1)
+
+    structs = []
+        
+    if optional:
+        newentry.MakeOptional()
+    if array:
+        newentry.MakeArray()
+
+    newentry.SetStruct(newstruct)
+    newentry.SetLineCount(line_count)
+    newentry.Verify()
+
+    if array:
+        # We need to encapsulate this entry into a struct
+        newname = newentry.Name()+ '_array'
+
+        # Now borgify the new entry.
+        newentry = EntryArray(newentry)
+        newentry.SetStruct(newstruct)
+        newentry.SetLineCount(line_count)
+        newentry.MakeArray()
+
+    newstruct.AddEntry(newentry)
+
+    return structs
+
+def ProcessStruct(data):
+    tokens = data.split(' ')
+
+    # First three tokens are: 'struct' 'name' '{'
+    newstruct = Struct(tokens[1])
+
+    inside = ' '.join(tokens[3:-1])
+
+    tokens = inside.split(';')
+
+    structs = []
+
+    for entry in tokens:
+        entry = NormalizeLine(entry)
+        if not entry:
+            continue
+
+        # It's possible that new structs get defined in here
+        structs.extend(ProcessOneEntry(newstruct, entry))
+
+    structs.append(newstruct)
+    return structs
+
+def GetNextStruct(file):
+    global line_count
+    global cppdirect
+
+    got_struct = 0
+
+    processed_lines = []
+
+    have_c_comment = 0
+    data = ''
+    while 1:
+        line = file.readline()
+        if not line:
+            break
+        
+        line_count += 1
+        line = line[:-1]
+
+        if not have_c_comment and re.search(r'/\*', line):
+            if re.search(r'/\*.*\*/', line):
+                line = re.sub(r'/\*.*\*/', '', line)
+            else:
+                line = re.sub(r'/\*.*$', '', line)
+                have_c_comment = 1
+
+        if have_c_comment:
+            if not re.search(r'\*/', line):
+                continue
+            have_c_comment = 0
+            line = re.sub(r'^.*\*/', '', line)
+
+        line = NormalizeLine(line)
+
+        if not line:
+            continue
+
+        if not got_struct:
+            if re.match(r'#include ["<].*[>"]', line):
+                cppdirect.append(line)
+                continue
+            
+            if re.match(r'^#(if( |def)|endif)', line):
+                cppdirect.append(line)
+                continue
+
+            if re.match(r'^#define', line):
+                headerdirect.append(line)
+                continue
+
+            if not re.match(r'^struct %s {$' % _STRUCT_RE,
+                            line, re.IGNORECASE):
+                print >>sys.stderr, 'Missing struct on line %d: %s' % (
+                    line_count, line)
+                sys.exit(1)
+            else:
+                got_struct = 1
+                data += line
+            continue
+
+        # We are inside the struct
+        tokens = line.split('}')
+        if len(tokens) == 1:
+            data += ' ' + line
+            continue
+
+        if len(tokens[1]):
+            print >>sys.stderr, 'Trailing garbage after struct on line %d' % (
+                line_count )
+            sys.exit(1)
+
+        # We found the end of the struct
+        data += ' %s}' % tokens[0]
+        break
+
+    # Remove any comments, that might be in there
+    data = re.sub(r'/\*.*\*/', '', data)
+    
+    return data
+        
+
+def Parse(file):
+    """
+    Parses the input file and returns C code and corresponding header file.
+    """
+
+    entities = []
+
+    while 1:
+        # Just gets the whole struct nicely formatted
+        data = GetNextStruct(file)
+
+        if not data:
+            break
+
+        entities.extend(ProcessStruct(data))
+
+    return entities
+
+def GuardName(name):
+    name = '_'.join(name.split('.'))
+    name = '_'.join(name.split('/'))
+    guard = '_'+name.upper()+'_'
+
+    return guard
+
+def HeaderPreamble(name):
+    guard = GuardName(name)
+    pre = (
+        '/*\n'
+        ' * Automatically generated from %s\n'
+        ' */\n\n'
+        '#ifndef %s\n'
+        '#define %s\n\n' ) % (
+        name, guard, guard)
+
+    # insert stdint.h - let's hope everyone has it
+    pre += (
+        '#include <event-config.h>\n'
+        '#ifdef _EVENT_HAVE_STDINT_H\n'
+        '#include <stdint.h>\n'
+        '#endif\n' )
+
+    for statement in headerdirect:
+        pre += '%s\n' % statement
+    if headerdirect:
+        pre += '\n'
+
+    pre += (
+        '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n'
+        '#ifdef __GNUC__\n'
+        '#define EVTAG_ASSIGN(msg, member, args...) '
+        '(*(msg)->base->member##_assign)(msg, ## args)\n'
+        '#define EVTAG_GET(msg, member, args...) '
+        '(*(msg)->base->member##_get)(msg, ## args)\n'
+        '#else\n'
+        '#define EVTAG_ASSIGN(msg, member, ...) '
+        '(*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)\n'
+        '#define EVTAG_GET(msg, member, ...) '
+        '(*(msg)->base->member##_get)(msg, ## __VA_ARGS__)\n'
+        '#endif\n'
+        '#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)\n'
+        '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n'
+        )
+
+    return pre
+     
+
+def HeaderPostamble(name):
+    guard = GuardName(name)
+    return '#endif  /* %s */' % guard
+
+def BodyPreamble(name):
+    global _NAME
+    global _VERSION
+    
+    header_file = '.'.join(name.split('.')[:-1]) + '.gen.h'
+
+    pre = ( '/*\n'
+            ' * Automatically generated from %s\n'
+            ' * by %s/%s.  DO NOT EDIT THIS FILE.\n'
+            ' */\n\n' ) % (name, _NAME, _VERSION)
+    pre += ( '#include <sys/types.h>\n'
+             '#ifdef _EVENT_HAVE_SYS_TIME_H\n'
+             '#include <sys/time.h>\n'
+             '#endif\n'
+             '#include <stdlib.h>\n'
+             '#include <string.h>\n'
+             '#include <assert.h>\n'
+             '#define EVENT_NO_STRUCT\n'
+             '#include <event.h>\n\n'
+             '#ifdef _EVENT___func__\n'
+             '#define __func__ _EVENT___func__\n'
+             '#endif\n' )
+
+    for statement in cppdirect:
+        pre += '%s\n' % statement
+    
+    pre += '\n#include "%s"\n\n' % header_file
+
+    pre += 'void event_err(int eval, const char *fmt, ...);\n'
+    pre += 'void event_warn(const char *fmt, ...);\n'
+    pre += 'void event_errx(int eval, const char *fmt, ...);\n'
+    pre += 'void event_warnx(const char *fmt, ...);\n\n'
+
+    return pre
+
+def main(argv):
+    if len(argv) < 2 or not argv[1]:
+        print >>sys.stderr, 'Need RPC description file as first argument.'
+        sys.exit(1)
+
+    filename = argv[1]
+
+    ext = filename.split('.')[-1]
+    if ext != 'rpc':
+        print >>sys.stderr, 'Unrecognized file extension: %s' % ext
+        sys.exit(1)
+
+    print >>sys.stderr, 'Reading \"%s\"' % filename
+
+    fp = open(filename, 'r')
+    entities = Parse(fp)
+    fp.close()
+
+    header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h'
+    impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c'
+
+    print >>sys.stderr, '... creating "%s"' % header_file
+    header_fp = open(header_file, 'w')
+    print >>header_fp, HeaderPreamble(filename)
+
+    # Create forward declarations: allows other structs to reference
+    # each other
+    for entry in entities:
+        entry.PrintForwardDeclaration(header_fp)
+    print >>header_fp, ''
+
+    for entry in entities:
+        entry.PrintTags(header_fp)
+        entry.PrintDeclaration(header_fp)
+    print >>header_fp, HeaderPostamble(filename)
+    header_fp.close()
+
+    print >>sys.stderr, '... creating "%s"' % impl_file
+    impl_fp = open(impl_file, 'w')
+    print >>impl_fp, BodyPreamble(filename)
+    for entry in entities:
+        entry.PrintCode(impl_fp)
+    impl_fp.close()
+
+if __name__ == '__main__':
+    main(sys.argv)
diff --git a/third_party/libevent/event_tagging.c b/third_party/libevent/event_tagging.c
new file mode 100644
index 0000000..d436e3f
--- /dev/null
+++ b/third_party/libevent/event_tagging.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2003, 2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#else
+#include <sys/ioctl.h>
+#endif
+
+#include <sys/queue.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "event.h"
+#include "evutil.h"
+#include "log.h"
+
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
+int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
+
+static struct evbuffer *_buf;	/* not thread safe */
+
+void
+evtag_init(void)
+{
+	if (_buf != NULL)
+		return;
+
+	if ((_buf = evbuffer_new()) == NULL)
+		event_err(1, "%s: malloc", __func__);
+}
+
+/* 
+ * We encode integer's by nibbles; the first nibble contains the number
+ * of significant nibbles - 1;  this allows us to encode up to 64-bit
+ * integers.  This function is byte-order independent.
+ */
+
+void
+encode_int(struct evbuffer *evbuf, ev_uint32_t number)
+{
+	int off = 1, nibbles = 0;
+	ev_uint8_t data[5];
+
+	memset(data, 0, sizeof(ev_uint32_t)+1);
+	while (number) {
+		if (off & 0x1)
+			data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
+		else
+			data[off/2] = (data[off/2] & 0x0f) |
+			    ((number & 0x0f) << 4);
+		number >>= 4;
+		off++;
+	}
+
+	if (off > 2)
+		nibbles = off - 2;
+
+	/* Off - 1 is the number of encoded nibbles */
+	data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);
+
+	evbuffer_add(evbuf, data, (off + 1) / 2);
+}
+
+/*
+ * Support variable length encoding of tags; we use the high bit in each
+ * octet as a continuation signal.
+ */
+
+int
+evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
+{
+	int bytes = 0;
+	ev_uint8_t data[5];
+
+	memset(data, 0, sizeof(data));
+	do {
+		ev_uint8_t lower = tag & 0x7f;
+		tag >>= 7;
+
+		if (tag)
+			lower |= 0x80;
+
+		data[bytes++] = lower;
+	} while (tag);
+
+	if (evbuf != NULL)
+		evbuffer_add(evbuf, data, bytes);
+
+	return (bytes);
+}
+
+static int
+decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
+{
+	ev_uint32_t number = 0;
+	ev_uint8_t *data = EVBUFFER_DATA(evbuf);
+	int len = EVBUFFER_LENGTH(evbuf);
+	int count = 0, shift = 0, done = 0;
+
+	while (count++ < len) {
+		ev_uint8_t lower = *data++;
+		number |= (lower & 0x7f) << shift;
+		shift += 7;
+
+		if (!(lower & 0x80)) {
+			done = 1;
+			break;
+		}
+	}
+
+	if (!done)
+		return (-1);
+
+	if (dodrain)
+		evbuffer_drain(evbuf, count);
+
+	if (ptag != NULL)
+		*ptag = number;
+
+	return (count);
+}
+
+int
+evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
+{
+	return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
+}
+
+/*
+ * Marshal a data type, the general format is as follows:
+ *
+ * tag number: one byte; length: var bytes; payload: var bytes
+ */
+
+void
+evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
+    const void *data, ev_uint32_t len)
+{
+	evtag_encode_tag(evbuf, tag);
+	encode_int(evbuf, len);
+	evbuffer_add(evbuf, (void *)data, len);
+}
+
+/* Marshaling for integers */
+void
+evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
+{
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+	encode_int(_buf, integer);
+
+	evtag_encode_tag(evbuf, tag);
+	encode_int(evbuf, EVBUFFER_LENGTH(_buf));
+	evbuffer_add_buffer(evbuf, _buf);
+}
+
+void
+evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
+{
+	evtag_marshal(buf, tag, string, strlen(string));
+}
+
+void
+evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
+{
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+	encode_int(_buf, tv->tv_sec);
+	encode_int(_buf, tv->tv_usec);
+
+	evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf),
+	    EVBUFFER_LENGTH(_buf));
+}
+
+static int
+decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
+{
+	ev_uint32_t number = 0;
+	ev_uint8_t *data = EVBUFFER_DATA(evbuf);
+	int len = EVBUFFER_LENGTH(evbuf);
+	int nibbles = 0;
+
+	if (!len)
+		return (-1);
+
+	nibbles = ((data[0] & 0xf0) >> 4) + 1;
+	if (nibbles > 8 || (nibbles >> 1) + 1 > len)
+		return (-1);
+	len = (nibbles >> 1) + 1;
+
+	while (nibbles > 0) {
+		number <<= 4;
+		if (nibbles & 0x1)
+			number |= data[nibbles >> 1] & 0x0f;
+		else
+			number |= (data[nibbles >> 1] & 0xf0) >> 4;
+		nibbles--;
+	}
+
+	if (dodrain)
+		evbuffer_drain(evbuf, len);
+
+	*pnumber = number;
+
+	return (len);
+}
+
+int
+evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
+{
+	return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
+}
+
+int
+evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
+{
+	return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
+}
+
+int
+evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
+{
+	struct evbuffer tmp;
+	int res, len;
+
+	len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+	if (len == -1)
+		return (-1);
+
+	tmp = *evbuf;
+	tmp.buffer += len;
+	tmp.off -= len;
+
+	res = decode_int_internal(plength, &tmp, 0);
+	if (res == -1)
+		return (-1);
+
+	*plength += res + len;
+
+	return (0);
+}
+
+int
+evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
+{
+	struct evbuffer tmp;
+	int res, len;
+
+	len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+	if (len == -1)
+		return (-1);
+
+	tmp = *evbuf;
+	tmp.buffer += len;
+	tmp.off -= len;
+
+	res = decode_int_internal(plength, &tmp, 0);
+	if (res == -1)
+		return (-1);
+
+	return (0);
+}
+
+int
+evtag_consume(struct evbuffer *evbuf)
+{
+	ev_uint32_t len;
+	if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
+		return (-1);
+	if (evtag_decode_int(&len, evbuf) == -1)
+		return (-1);
+	evbuffer_drain(evbuf, len);
+
+	return (0);
+}
+
+/* Reads the data type from an event buffer */
+
+int
+evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
+{
+	ev_uint32_t len;
+	ev_uint32_t integer;
+
+	if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
+		return (-1);
+	if (evtag_decode_int(&integer, src) == -1)
+		return (-1);
+	len = integer;
+
+	if (EVBUFFER_LENGTH(src) < len)
+		return (-1);
+
+	if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1)
+		return (-1);
+
+	evbuffer_drain(src, len);
+
+	return (len);
+}
+
+/* Marshaling for integers */
+
+int
+evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    ev_uint32_t *pinteger)
+{
+	ev_uint32_t tag;
+	ev_uint32_t len;
+	ev_uint32_t integer;
+
+	if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
+		return (-1);
+	if (need_tag != tag)
+		return (-1);
+	if (evtag_decode_int(&integer, evbuf) == -1)
+		return (-1);
+	len = integer;
+
+	if (EVBUFFER_LENGTH(evbuf) < len)
+		return (-1);
+	
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+	if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1)
+		return (-1);
+
+	evbuffer_drain(evbuf, len);
+
+	return (evtag_decode_int(pinteger, _buf));
+}
+
+/* Unmarshal a fixed length tag */
+
+int
+evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
+    size_t len)
+{
+	ev_uint32_t tag;
+
+	/* Initialize this event buffer so that we can read into it */
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+	/* Now unmarshal a tag and check that it matches the tag we want */
+	if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag)
+		return (-1);
+
+	if (EVBUFFER_LENGTH(_buf) != len)
+		return (-1);
+
+	memcpy(data, EVBUFFER_DATA(_buf), len);
+	return (0);
+}
+
+int
+evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    char **pstring)
+{
+	ev_uint32_t tag;
+
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+	if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
+		return (-1);
+
+	*pstring = calloc(EVBUFFER_LENGTH(_buf) + 1, 1);
+	if (*pstring == NULL)
+		event_err(1, "%s: calloc", __func__);
+	evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf));
+
+	return (0);
+}
+
+int
+evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    struct timeval *ptv)
+{
+	ev_uint32_t tag;
+	ev_uint32_t integer;
+
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+	if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
+		return (-1);
+
+	if (evtag_decode_int(&integer, _buf) == -1)
+		return (-1);
+	ptv->tv_sec = integer;
+	if (evtag_decode_int(&integer, _buf) == -1)
+		return (-1);
+	ptv->tv_usec = integer;
+
+	return (0);
+}
diff --git a/third_party/libevent/evhttp.h b/third_party/libevent/evhttp.h
new file mode 100644
index 0000000..30dee8b
--- /dev/null
+++ b/third_party/libevent/evhttp.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVHTTP_H_
+#define _EVHTTP_H_
+
+#include "event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+/** @file evhttp.h
+ *
+ * Basic support for HTTP serving.
+ *
+ * As libevent is a library for dealing with event notification and most
+ * interesting applications are networked today, I have often found the
+ * need to write HTTP code.  The following prototypes and definitions provide
+ * an application with a minimal interface for making HTTP requests and for
+ * creating a very simple HTTP server.
+ */
+
+/* Response codes */
+#define HTTP_OK			200
+#define HTTP_NOCONTENT		204
+#define HTTP_MOVEPERM		301
+#define HTTP_MOVETEMP		302
+#define HTTP_NOTMODIFIED	304
+#define HTTP_BADREQUEST		400
+#define HTTP_NOTFOUND		404
+#define HTTP_SERVUNAVAIL	503
+
+struct evhttp;
+struct evhttp_request;
+struct evkeyvalq;
+
+/** Create a new HTTP server
+ *
+ * @param base (optional) the event base to receive the HTTP events
+ * @return a pointer to a newly initialized evhttp server structure
+ */
+struct evhttp *evhttp_new(struct event_base *base);
+
+/**
+ * Binds an HTTP server on the specified address and port.
+ *
+ * Can be called multiple times to bind the same http server
+ * to multiple different ports.
+ *
+ * @param http a pointer to an evhttp object
+ * @param address a string containing the IP address to listen(2) on
+ * @param port the port number to listen on
+ * @return a newly allocated evhttp struct
+ * @see evhttp_free()
+ */
+int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
+
+/**
+ * Makes an HTTP server accept connections on the specified socket
+ *
+ * This may be useful to create a socket and then fork multiple instances
+ * of an http server, or when a socket has been communicated via file
+ * descriptor passing in situations where an http servers does not have
+ * permissions to bind to a low-numbered port.
+ *
+ * Can be called multiple times to have the http server listen to
+ * multiple different sockets.
+ *
+ * @param http a pointer to an evhttp object
+ * @param fd a socket fd that is ready for accepting connections
+ * @return 0 on success, -1 on failure.
+ * @see evhttp_free(), evhttp_bind_socket()
+ */
+int evhttp_accept_socket(struct evhttp *http, int fd);
+
+/**
+ * Free the previously created HTTP server.
+ *
+ * Works only if no requests are currently being served.
+ *
+ * @param http the evhttp server object to be freed
+ * @see evhttp_start()
+ */
+void evhttp_free(struct evhttp* http);
+
+/** Set a callback for a specified URI */
+void evhttp_set_cb(struct evhttp *, const char *,
+    void (*)(struct evhttp_request *, void *), void *);
+
+/** Removes the callback for a specified URI */
+int evhttp_del_cb(struct evhttp *, const char *);
+
+/** Set a callback for all requests that are not caught by specific callbacks
+ */
+void evhttp_set_gencb(struct evhttp *,
+    void (*)(struct evhttp_request *, void *), void *);
+
+/**
+ * Set the timeout for an HTTP request.
+ *
+ * @param http an evhttp object
+ * @param timeout_in_secs the timeout, in seconds
+ */
+void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
+
+/* Request/Response functionality */
+
+/**
+ * Send an HTML error message to the client.
+ *
+ * @param req a request object
+ * @param error the HTTP error code
+ * @param reason a brief explanation of the error
+ */
+void evhttp_send_error(struct evhttp_request *req, int error,
+    const char *reason);
+
+/**
+ * Send an HTML reply to the client.
+ *
+ * @param req a request object
+ * @param code the HTTP response code to send
+ * @param reason a brief message to send with the response code
+ * @param databuf the body of the response
+ */
+void evhttp_send_reply(struct evhttp_request *req, int code,
+    const char *reason, struct evbuffer *databuf);
+
+/* Low-level response interface, for streaming/chunked replies */
+void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
+void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
+void evhttp_send_reply_end(struct evhttp_request *);
+
+/**
+ * Start an HTTP server on the specified address and port
+ *
+ * DEPRECATED: it does not allow an event base to be specified
+ *
+ * @param address the address to which the HTTP server should be bound
+ * @param port the port number on which the HTTP server should listen
+ * @return an struct evhttp object
+ */
+struct evhttp *evhttp_start(const char *address, u_short port);
+
+/*
+ * Interfaces for making requests
+ */
+enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
+
+enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
+
+/**
+ * the request structure that a server receives.
+ * WARNING: expect this structure to change.  I will try to provide
+ * reasonable accessors.
+ */
+struct evhttp_request {
+#if defined(TAILQ_ENTRY)
+	TAILQ_ENTRY(evhttp_request) next;
+#else
+struct {
+	struct evhttp_request *tqe_next;
+	struct evhttp_request **tqe_prev;
+}       next;
+#endif
+
+	/* the connection object that this request belongs to */
+	struct evhttp_connection *evcon;
+	int flags;
+#define EVHTTP_REQ_OWN_CONNECTION	0x0001
+#define EVHTTP_PROXY_REQUEST		0x0002
+
+	struct evkeyvalq *input_headers;
+	struct evkeyvalq *output_headers;
+
+	/* address of the remote host and the port connection came from */
+	char *remote_host;
+	u_short remote_port;
+
+	enum evhttp_request_kind kind;
+	enum evhttp_cmd_type type;
+
+	char *uri;			/* uri after HTTP request was parsed */
+
+	char major;			/* HTTP Major number */
+	char minor;			/* HTTP Minor number */
+
+	int response_code;		/* HTTP Response code */
+	char *response_code_line;	/* Readable response */
+
+	struct evbuffer *input_buffer;	/* read data */
+	ev_int64_t ntoread;
+	int chunked;
+
+	struct evbuffer *output_buffer;	/* outgoing post or data */
+
+	/* Callback */
+	void (*cb)(struct evhttp_request *, void *);
+	void *cb_arg;
+
+	/*
+	 * Chunked data callback - call for each completed chunk if
+	 * specified.  If not specified, all the data is delivered via
+	 * the regular callback.
+	 */
+	void (*chunk_cb)(struct evhttp_request *, void *);
+};
+
+/**
+ * Creates a new request object that needs to be filled in with the request
+ * parameters.  The callback is executed when the request completed or an
+ * error occurred.
+ */
+struct evhttp_request *evhttp_request_new(
+	void (*cb)(struct evhttp_request *, void *), void *arg);
+
+/** enable delivery of chunks to requestor */
+void evhttp_request_set_chunked_cb(struct evhttp_request *,
+    void (*cb)(struct evhttp_request *, void *));
+
+/** Frees the request object and removes associated events. */
+void evhttp_request_free(struct evhttp_request *req);
+
+/**
+ * A connection object that can be used to for making HTTP requests.  The
+ * connection object tries to establish the connection when it is given an
+ * http request object.
+ */
+struct evhttp_connection *evhttp_connection_new(
+	const char *address, unsigned short port);
+
+/** Frees an http connection */
+void evhttp_connection_free(struct evhttp_connection *evcon);
+
+/** sets the ip address from which http connections are made */
+void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+    const char *address);
+
+/** sets the local port from which http connections are made */
+void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+    unsigned short port);
+
+/** Sets the timeout for events related to this connection */
+void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+    int timeout_in_secs);
+
+/** Sets the retry limit for this connection - -1 repeats indefnitely */
+void evhttp_connection_set_retries(struct evhttp_connection *evcon,
+    int retry_max);
+
+/** Set a callback for connection close. */
+void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+    void (*)(struct evhttp_connection *, void *), void *);
+
+/**
+ * Associates an event base with the connection - can only be called
+ * on a freshly created connection object that has not been used yet.
+ */
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+    struct event_base *base);
+
+/** Get the remote address and port associated with this connection. */
+void evhttp_connection_get_peer(struct evhttp_connection *evcon,
+    char **address, u_short *port);
+
+/** The connection gets ownership of the request */
+int evhttp_make_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req,
+    enum evhttp_cmd_type type, const char *uri);
+
+const char *evhttp_request_uri(struct evhttp_request *req);
+
+/* Interfaces for dealing with HTTP headers */
+
+const char *evhttp_find_header(const struct evkeyvalq *, const char *);
+int evhttp_remove_header(struct evkeyvalq *, const char *);
+int evhttp_add_header(struct evkeyvalq *, const char *, const char *);
+void evhttp_clear_headers(struct evkeyvalq *);
+
+/* Miscellaneous utility functions */
+
+
+/**
+  Helper function to encode a URI.
+
+  The returned string must be freed by the caller.
+
+  @param uri an unencoded URI
+  @return a newly allocated URI-encoded string
+ */
+char *evhttp_encode_uri(const char *uri);
+
+
+/**
+  Helper function to decode a URI.
+
+  The returned string must be freed by the caller.
+
+  @param uri an encoded URI
+  @return a newly allocated unencoded URI
+ */
+char *evhttp_decode_uri(const char *uri);
+
+
+/**
+ * Helper function to parse out arguments in a query.
+ *
+ * Parsing a uri like
+ *
+ *    http://foo.com/?q=test&s=some+thing
+ *
+ * will result in two entries in the key value queue.
+
+ * The first entry is: key="q", value="test"
+ * The second entry is: key="s", value="some thing"
+ *
+ * @param uri the request URI
+ * @param headers the head of the evkeyval queue
+ */
+void evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
+
+
+/**
+ * Escape HTML character entities in a string.
+ *
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ *
+ * @param html an unescaped HTML string
+ * @return an escaped HTML string
+ */
+char *evhttp_htmlescape(const char *html);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVHTTP_H_ */
diff --git a/third_party/libevent/evport.c b/third_party/libevent/evport.c
new file mode 100644
index 0000000..a2ee1bc
--- /dev/null
+++ b/third_party/libevent/evport.c
@@ -0,0 +1,513 @@
+/*
+ * Submitted by David Pacheco (dp.spambait@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``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 SUN MICROSYSTEMS, INC. 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. 
+ */
+
+/*
+ * Copyright (c) 2007 Sun Microsystems. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
+ * This implementation is loosely modeled after the one used for select(2) (in
+ * select.c).
+ *
+ * The outstanding events are tracked in a data structure called evport_data.
+ * Each entry in the ed_fds array corresponds to a file descriptor, and contains
+ * pointers to the read and write events that correspond to that fd. (That is,
+ * when the file is readable, the "read" event should handle it, etc.)
+ *
+ * evport_add and evport_del update this data structure. evport_dispatch uses it
+ * to determine where to callback when an event occurs (which it gets from
+ * port_getn). 
+ *
+ * Helper functions are used: grow() grows the file descriptor array as
+ * necessary when large fd's come in. reassociate() takes care of maintaining
+ * the proper file-descriptor/event-port associations.
+ *
+ * As in the select(2) implementation, signals are handled by evsignal.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/time.h>
+#include <assert.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <poll.h>
+#include <port.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "log.h"
+#include "evsignal.h"
+
+
+/*
+ * Default value for ed_nevents, which is the maximum file descriptor number we
+ * can handle. If an event comes in for a file descriptor F > nevents, we will
+ * grow the array of file descriptors, doubling its size.
+ */
+#define DEFAULT_NFDS	16
+
+
+/*
+ * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
+ * any particular call. You can speed things up by increasing this, but it will
+ * (obviously) require more memory.
+ */
+#define EVENTS_PER_GETN 8
+
+/*
+ * Per-file-descriptor information about what events we're subscribed to. These
+ * fields are NULL if no event is subscribed to either of them.
+ */
+
+struct fd_info {
+	struct event* fdi_revt; /* the event responsible for the "read"  */
+	struct event* fdi_wevt; /* the event responsible for the "write" */
+};
+
+#define FDI_HAS_READ(fdi)  ((fdi)->fdi_revt != NULL)
+#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL)
+#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
+#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
+    (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
+
+struct evport_data {
+	int 		ed_port;	/* event port for system events  */
+	int		ed_nevents;	/* number of allocated fdi's 	 */
+	struct fd_info *ed_fds;		/* allocated fdi table 		 */
+	/* fdi's that we need to reassoc */
+	int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
+};
+
+static void*	evport_init	(struct event_base *);
+static int 	evport_add	(void *, struct event *);
+static int 	evport_del	(void *, struct event *);
+static int 	evport_dispatch	(struct event_base *, void *, struct timeval *);
+static void	evport_dealloc	(struct event_base *, void *);
+
+const struct eventop evportops = {
+	"evport",
+	evport_init,
+	evport_add,
+	evport_del,
+	evport_dispatch,
+	evport_dealloc,
+	1 /* need reinit */
+};
+
+/*
+ * Initialize the event port implementation.
+ */
+
+static void*
+evport_init(struct event_base *base)
+{
+	struct evport_data *evpd;
+	int i;
+	/*
+	 * Disable event ports when this environment variable is set 
+	 */
+	if (evutil_getenv("EVENT_NOEVPORT"))
+		return (NULL);
+
+	if (!(evpd = calloc(1, sizeof(struct evport_data))))
+		return (NULL);
+
+	if ((evpd->ed_port = port_create()) == -1) {
+		free(evpd);
+		return (NULL);
+	}
+
+	/*
+	 * Initialize file descriptor structure
+	 */
+	evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info));
+	if (evpd->ed_fds == NULL) {
+		close(evpd->ed_port);
+		free(evpd);
+		return (NULL);
+	}
+	evpd->ed_nevents = DEFAULT_NFDS;
+	for (i = 0; i < EVENTS_PER_GETN; i++)
+		evpd->ed_pending[i] = -1;
+
+	evsignal_init(base);
+
+	return (evpd);
+}
+
+#ifdef CHECK_INVARIANTS
+/*
+ * Checks some basic properties about the evport_data structure. Because it
+ * checks all file descriptors, this function can be expensive when the maximum
+ * file descriptor ever used is rather large.
+ */
+
+static void
+check_evportop(struct evport_data *evpd)
+{
+	assert(evpd);
+	assert(evpd->ed_nevents > 0);
+	assert(evpd->ed_port > 0);
+	assert(evpd->ed_fds > 0);
+
+	/*
+	 * Verify the integrity of the fd_info struct as well as the events to
+	 * which it points (at least, that they're valid references and correct
+	 * for their position in the structure).
+	 */
+	int i;
+	for (i = 0; i < evpd->ed_nevents; ++i) {
+		struct event 	*ev;
+		struct fd_info 	*fdi;
+
+		fdi = &evpd->ed_fds[i];
+		if ((ev = fdi->fdi_revt) != NULL) {
+			assert(ev->ev_fd == i);
+		}
+		if ((ev = fdi->fdi_wevt) != NULL) {
+			assert(ev->ev_fd == i);
+		}
+	}
+}
+
+/*
+ * Verifies very basic integrity of a given port_event.
+ */
+static void
+check_event(port_event_t* pevt)
+{
+	/*
+	 * We've only registered for PORT_SOURCE_FD events. The only
+	 * other thing we can legitimately receive is PORT_SOURCE_ALERT,
+	 * but since we're not using port_alert either, we can assume
+	 * PORT_SOURCE_FD.
+	 */
+	assert(pevt->portev_source == PORT_SOURCE_FD);
+	assert(pevt->portev_user == NULL);
+}
+
+#else
+#define check_evportop(epop)
+#define check_event(pevt)
+#endif /* CHECK_INVARIANTS */
+
+/*
+ * Doubles the size of the allocated file descriptor array.
+ */
+static int
+grow(struct evport_data *epdp, int factor)
+{
+	struct fd_info *tmp;
+	int oldsize = epdp->ed_nevents;
+	int newsize = factor * oldsize;
+	assert(factor > 1);
+
+	check_evportop(epdp);
+
+	tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
+	if (NULL == tmp)
+		return -1;
+	epdp->ed_fds = tmp;
+	memset((char*) (epdp->ed_fds + oldsize), 0, 
+	    (newsize - oldsize)*sizeof(struct fd_info));
+	epdp->ed_nevents = newsize;
+
+	check_evportop(epdp);
+
+	return 0;
+}
+
+
+/*
+ * (Re)associates the given file descriptor with the event port. The OS events
+ * are specified (implicitly) from the fd_info struct.
+ */
+static int
+reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
+{
+	int sysevents = FDI_TO_SYSEVENTS(fdip);
+
+	if (sysevents != 0) {
+		if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
+				   fd, sysevents, NULL) == -1) {
+			event_warn("port_associate");
+			return (-1);
+		}
+	}
+
+	check_evportop(epdp);
+
+	return (0);
+}
+
+/*
+ * Main event loop - polls port_getn for some number of events, and processes
+ * them.
+ */
+
+static int
+evport_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	int i, res;
+	struct evport_data *epdp = arg;
+	port_event_t pevtlist[EVENTS_PER_GETN];
+
+	/*
+	 * port_getn will block until it has at least nevents events. It will
+	 * also return how many it's given us (which may be more than we asked
+	 * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
+	 * nevents.
+	 */
+	int nevents = 1;
+
+	/*
+	 * We have to convert a struct timeval to a struct timespec
+	 * (only difference is nanoseconds vs. microseconds). If no time-based
+	 * events are active, we should wait for I/O (and tv == NULL).
+	 */
+	struct timespec ts;
+	struct timespec *ts_p = NULL;
+	if (tv != NULL) {
+		ts.tv_sec = tv->tv_sec;
+		ts.tv_nsec = tv->tv_usec * 1000;
+		ts_p = &ts;
+	}
+
+	/*
+	 * Before doing anything else, we need to reassociate the events we hit
+	 * last time which need reassociation. See comment at the end of the
+	 * loop below.
+	 */
+	for (i = 0; i < EVENTS_PER_GETN; ++i) {
+		struct fd_info *fdi = NULL;
+		if (epdp->ed_pending[i] != -1) {
+			fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
+		}
+
+		if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
+			int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd : 
+			    fdi->fdi_wevt->ev_fd;
+			reassociate(epdp, fdi, fd);
+			epdp->ed_pending[i] = -1;
+		}
+	}
+
+	if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN, 
+		    (unsigned int *) &nevents, ts_p)) == -1) {
+		if (errno == EINTR || errno == EAGAIN) {
+			evsignal_process(base);
+			return (0);
+		} else if (errno == ETIME) {
+			if (nevents == 0)
+				return (0);
+		} else {
+			event_warn("port_getn");
+			return (-1);
+		}
+	} else if (base->sig.evsignal_caught) {
+		evsignal_process(base);
+	}
+	
+	event_debug(("%s: port_getn reports %d events", __func__, nevents));
+
+	for (i = 0; i < nevents; ++i) {
+		struct event *ev;
+		struct fd_info *fdi;
+		port_event_t *pevt = &pevtlist[i];
+		int fd = (int) pevt->portev_object;
+
+		check_evportop(epdp);
+		check_event(pevt);
+		epdp->ed_pending[i] = fd;
+
+		/*
+		 * Figure out what kind of event it was 
+		 * (because we have to pass this to the callback)
+		 */
+		res = 0;
+		if (pevt->portev_events & POLLIN)
+			res |= EV_READ;
+		if (pevt->portev_events & POLLOUT)
+			res |= EV_WRITE;
+
+		assert(epdp->ed_nevents > fd);
+		fdi = &(epdp->ed_fds[fd]);
+
+		/*
+		 * We now check for each of the possible events (READ
+		 * or WRITE).  Then, we activate the event (which will
+		 * cause its callback to be executed).
+		 */
+
+		if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) {
+			event_active(ev, res, 1);
+		}
+
+		if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) {
+			event_active(ev, res, 1);
+		}
+	} /* end of all events gotten */
+
+	check_evportop(epdp);
+
+	return (0);
+}
+
+
+/*
+ * Adds the given event (so that you will be notified when it happens via
+ * the callback function).
+ */
+
+static int
+evport_add(void *arg, struct event *ev)
+{
+	struct evport_data *evpd = arg;
+	struct fd_info *fdi;
+	int factor;
+
+	check_evportop(evpd);
+
+	/*
+	 * Delegate, if it's not ours to handle.
+	 */
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_add(ev));
+
+	/*
+	 * If necessary, grow the file descriptor info table
+	 */
+
+	factor = 1;
+	while (ev->ev_fd >= factor * evpd->ed_nevents)
+		factor *= 2;
+
+	if (factor > 1) {
+		if (-1 == grow(evpd, factor)) {
+			return (-1);
+		}
+	}
+
+	fdi = &evpd->ed_fds[ev->ev_fd];
+	if (ev->ev_events & EV_READ)
+		fdi->fdi_revt = ev;
+	if (ev->ev_events & EV_WRITE)
+		fdi->fdi_wevt = ev;
+
+	return reassociate(evpd, fdi, ev->ev_fd);
+}
+
+/*
+ * Removes the given event from the list of events to wait for.
+ */
+
+static int
+evport_del(void *arg, struct event *ev)
+{
+	struct evport_data *evpd = arg;
+	struct fd_info *fdi;
+	int i;
+	int associated = 1;
+
+	check_evportop(evpd);
+
+	/*
+	 * Delegate, if it's not ours to handle
+	 */
+	if (ev->ev_events & EV_SIGNAL) {
+		return (evsignal_del(ev));
+	}
+
+	if (evpd->ed_nevents < ev->ev_fd) {
+		return (-1);
+	}
+
+	for (i = 0; i < EVENTS_PER_GETN; ++i) {
+		if (evpd->ed_pending[i] == ev->ev_fd) {
+			associated = 0;
+			break;
+		}
+	}
+
+	fdi = &evpd->ed_fds[ev->ev_fd];
+	if (ev->ev_events & EV_READ)
+		fdi->fdi_revt = NULL;
+	if (ev->ev_events & EV_WRITE)
+		fdi->fdi_wevt = NULL;
+
+	if (associated) {
+		if (!FDI_HAS_EVENTS(fdi) &&
+		    port_dissociate(evpd->ed_port, PORT_SOURCE_FD,
+		    ev->ev_fd) == -1) {	 
+			/*
+			 * Ignre EBADFD error the fd could have been closed
+			 * before event_del() was called.
+			 */
+			if (errno != EBADFD) {
+				event_warn("port_dissociate");
+				return (-1);
+			}
+		} else {
+			if (FDI_HAS_EVENTS(fdi)) {
+				return (reassociate(evpd, fdi, ev->ev_fd));
+			}
+		}
+	} else {
+		if (fdi->fdi_revt == NULL && fdi->fdi_wevt == NULL) {
+			evpd->ed_pending[i] = -1;
+		}
+	}
+	return 0;
+}
+
+
+static void
+evport_dealloc(struct event_base *base, void *arg)
+{
+	struct evport_data *evpd = arg;
+
+	evsignal_dealloc(base);
+
+	close(evpd->ed_port);
+
+	if (evpd->ed_fds)
+		free(evpd->ed_fds);
+	free(evpd);
+}
diff --git a/third_party/libevent/evrpc-internal.h b/third_party/libevent/evrpc-internal.h
new file mode 100644
index 0000000..c900f95
--- /dev/null
+++ b/third_party/libevent/evrpc-internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVRPC_INTERNAL_H_
+#define _EVRPC_INTERNAL_H_
+
+#include "http-internal.h"
+
+struct evrpc;
+
+#define EVRPC_URI_PREFIX "/.rpc."
+
+struct evrpc_hook {
+	TAILQ_ENTRY(evrpc_hook) (next);
+
+	/* returns -1; if the rpc should be aborted, is allowed to rewrite */
+	int (*process)(struct evhttp_request *, struct evbuffer *, void *);
+	void *process_arg;
+};
+
+TAILQ_HEAD(evrpc_hook_list, evrpc_hook);
+
+/*
+ * this is shared between the base and the pool, so that we can reuse
+ * the hook adding functions; we alias both evrpc_pool and evrpc_base
+ * to this common structure.
+ */
+struct _evrpc_hooks {
+	/* hooks for processing outbound and inbound rpcs */
+	struct evrpc_hook_list in_hooks;
+	struct evrpc_hook_list out_hooks;
+};
+
+#define input_hooks common.in_hooks
+#define output_hooks common.out_hooks
+
+struct evrpc_base {
+	struct _evrpc_hooks common;
+
+	/* the HTTP server under which we register our RPC calls */
+	struct evhttp* http_server;
+
+	/* a list of all RPCs registered with us */
+	TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs;
+};
+
+struct evrpc_req_generic;
+void evrpc_reqstate_free(struct evrpc_req_generic* rpc_state);
+
+/* A pool for holding evhttp_connection objects */
+struct evrpc_pool {
+	struct _evrpc_hooks common;
+
+	struct event_base *base;
+
+	struct evconq connections;
+
+	int timeout;
+
+	TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) requests;
+};
+
+
+#endif /* _EVRPC_INTERNAL_H_ */
diff --git a/third_party/libevent/evrpc.c b/third_party/libevent/evrpc.c
new file mode 100644
index 0000000..070fd9e
--- /dev/null
+++ b/third_party/libevent/evrpc.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+
+#include "event.h"
+#include "evrpc.h"
+#include "evrpc-internal.h"
+#include "evhttp.h"
+#include "evutil.h"
+#include "log.h"
+
+struct evrpc_base *
+evrpc_init(struct evhttp *http_server)
+{
+	struct evrpc_base* base = calloc(1, sizeof(struct evrpc_base));
+	if (base == NULL)
+		return (NULL);
+
+	/* we rely on the tagging sub system */
+	evtag_init();
+
+	TAILQ_INIT(&base->registered_rpcs);
+	TAILQ_INIT(&base->input_hooks);
+	TAILQ_INIT(&base->output_hooks);
+	base->http_server = http_server;
+
+	return (base);
+}
+
+void
+evrpc_free(struct evrpc_base *base)
+{
+	struct evrpc *rpc;
+	struct evrpc_hook *hook;
+
+	while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
+		assert(evrpc_unregister_rpc(base, rpc->uri));
+	}
+	while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
+		assert(evrpc_remove_hook(base, EVRPC_INPUT, hook));
+	}
+	while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
+		assert(evrpc_remove_hook(base, EVRPC_OUTPUT, hook));
+	}
+	free(base);
+}
+
+void *
+evrpc_add_hook(void *vbase,
+    enum EVRPC_HOOK_TYPE hook_type,
+    int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
+    void *cb_arg)
+{
+	struct _evrpc_hooks *base = vbase;
+	struct evrpc_hook_list *head = NULL;
+	struct evrpc_hook *hook = NULL;
+	switch (hook_type) {
+	case EVRPC_INPUT:
+		head = &base->in_hooks;
+		break;
+	case EVRPC_OUTPUT:
+		head = &base->out_hooks;
+		break;
+	default:
+		assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+	}
+
+	hook = calloc(1, sizeof(struct evrpc_hook));
+	assert(hook != NULL);
+	
+	hook->process = cb;
+	hook->process_arg = cb_arg;
+	TAILQ_INSERT_TAIL(head, hook, next);
+
+	return (hook);
+}
+
+static int
+evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
+{
+	struct evrpc_hook *hook = NULL;
+	TAILQ_FOREACH(hook, head, next) {
+		if (hook == handle) {
+			TAILQ_REMOVE(head, hook, next);
+			free(hook);
+			return (1);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * remove the hook specified by the handle
+ */
+
+int
+evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
+{
+	struct _evrpc_hooks *base = vbase;
+	struct evrpc_hook_list *head = NULL;
+	switch (hook_type) {
+	case EVRPC_INPUT:
+		head = &base->in_hooks;
+		break;
+	case EVRPC_OUTPUT:
+		head = &base->out_hooks;
+		break;
+	default:
+		assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+	}
+
+	return (evrpc_remove_hook_internal(head, handle));
+}
+
+static int
+evrpc_process_hooks(struct evrpc_hook_list *head,
+    struct evhttp_request *req, struct evbuffer *evbuf)
+{
+	struct evrpc_hook *hook;
+	TAILQ_FOREACH(hook, head, next) {
+		if (hook->process(req, evbuf, hook->process_arg) == -1)
+			return (-1);
+	}
+
+	return (0);
+}
+
+static void evrpc_pool_schedule(struct evrpc_pool *pool);
+static void evrpc_request_cb(struct evhttp_request *, void *);
+void evrpc_request_done(struct evrpc_req_generic*);
+
+/*
+ * Registers a new RPC with the HTTP server.   The evrpc object is expected
+ * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
+ * calls this function.
+ */
+
+static char *
+evrpc_construct_uri(const char *uri)
+{
+	char *constructed_uri;
+	int constructed_uri_len;
+
+	constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
+	if ((constructed_uri = malloc(constructed_uri_len)) == NULL)
+		event_err(1, "%s: failed to register rpc at %s",
+		    __func__, uri);
+	memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
+	memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
+	constructed_uri[constructed_uri_len - 1] = '\0';
+
+	return (constructed_uri);
+}
+
+int
+evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
+    void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
+{
+	char *constructed_uri = evrpc_construct_uri(rpc->uri);
+
+	rpc->base = base;
+	rpc->cb = cb;
+	rpc->cb_arg = cb_arg;
+
+	TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
+
+	evhttp_set_cb(base->http_server,
+	    constructed_uri,
+	    evrpc_request_cb,
+	    rpc);
+	
+	free(constructed_uri);
+
+	return (0);
+}
+
+int
+evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
+{
+	char *registered_uri = NULL;
+	struct evrpc *rpc;
+
+	/* find the right rpc; linear search might be slow */
+	TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
+		if (strcmp(rpc->uri, name) == 0)
+			break;
+	}
+	if (rpc == NULL) {
+		/* We did not find an RPC with this name */
+		return (-1);
+	}
+	TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
+	
+	free((char *)rpc->uri);
+	free(rpc);
+
+        registered_uri = evrpc_construct_uri(name);
+
+	/* remove the http server callback */
+	assert(evhttp_del_cb(base->http_server, registered_uri) == 0);
+
+	free(registered_uri);
+	return (0);
+}
+
+static void
+evrpc_request_cb(struct evhttp_request *req, void *arg)
+{
+	struct evrpc *rpc = arg;
+	struct evrpc_req_generic *rpc_state = NULL;
+
+	/* let's verify the outside parameters */
+	if (req->type != EVHTTP_REQ_POST ||
+	    EVBUFFER_LENGTH(req->input_buffer) <= 0)
+		goto error;
+
+	/*
+	 * we might want to allow hooks to suspend the processing,
+	 * but at the moment, we assume that they just act as simple
+	 * filters.
+	 */
+	if (evrpc_process_hooks(&rpc->base->input_hooks,
+		req, req->input_buffer) == -1)
+		goto error;
+
+	rpc_state = calloc(1, sizeof(struct evrpc_req_generic));
+	if (rpc_state == NULL)
+		goto error;
+
+	/* let's check that we can parse the request */
+	rpc_state->request = rpc->request_new();
+	if (rpc_state->request == NULL)
+		goto error;
+
+	rpc_state->rpc = rpc;
+
+	if (rpc->request_unmarshal(
+		    rpc_state->request, req->input_buffer) == -1) {
+		/* we failed to parse the request; that's a bummer */
+		goto error;
+	}
+
+	/* at this point, we have a well formed request, prepare the reply */
+
+	rpc_state->reply = rpc->reply_new();
+	if (rpc_state->reply == NULL)
+		goto error;
+
+	rpc_state->http_req = req;
+	rpc_state->done = evrpc_request_done;
+
+	/* give the rpc to the user; they can deal with it */
+	rpc->cb(rpc_state, rpc->cb_arg);
+
+	return;
+
+error:
+	evrpc_reqstate_free(rpc_state);
+	evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
+	return;
+}
+
+void
+evrpc_reqstate_free(struct evrpc_req_generic* rpc_state)
+{
+	/* clean up all memory */
+	if (rpc_state != NULL) {
+		struct evrpc *rpc = rpc_state->rpc;
+
+		if (rpc_state->request != NULL)
+			rpc->request_free(rpc_state->request);
+		if (rpc_state->reply != NULL)
+			rpc->reply_free(rpc_state->reply);
+		free(rpc_state);
+	}
+}
+
+void
+evrpc_request_done(struct evrpc_req_generic* rpc_state)
+{
+	struct evhttp_request *req = rpc_state->http_req;
+	struct evrpc *rpc = rpc_state->rpc;
+	struct evbuffer* data = NULL;
+
+	if (rpc->reply_complete(rpc_state->reply) == -1) {
+		/* the reply was not completely filled in.  error out */
+		goto error;
+	}
+
+	if ((data = evbuffer_new()) == NULL) {
+		/* out of memory */
+		goto error;
+	}
+
+	/* serialize the reply */
+	rpc->reply_marshal(data, rpc_state->reply);
+
+	/* do hook based tweaks to the request */
+	if (evrpc_process_hooks(&rpc->base->output_hooks,
+		req, data) == -1)
+		goto error;
+
+	/* on success, we are going to transmit marshaled binary data */
+	if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
+		evhttp_add_header(req->output_headers,
+		    "Content-Type", "application/octet-stream");
+	}
+
+	evhttp_send_reply(req, HTTP_OK, "OK", data);
+
+	evbuffer_free(data);
+
+	evrpc_reqstate_free(rpc_state);
+
+	return;
+
+error:
+	if (data != NULL)
+		evbuffer_free(data);
+	evrpc_reqstate_free(rpc_state);
+	evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
+	return;
+}
+
+/* Client implementation of RPC site */
+
+static int evrpc_schedule_request(struct evhttp_connection *connection,
+    struct evrpc_request_wrapper *ctx);
+
+struct evrpc_pool *
+evrpc_pool_new(struct event_base *base)
+{
+	struct evrpc_pool *pool = calloc(1, sizeof(struct evrpc_pool));
+	if (pool == NULL)
+		return (NULL);
+
+	TAILQ_INIT(&pool->connections);
+	TAILQ_INIT(&pool->requests);
+
+	TAILQ_INIT(&pool->input_hooks);
+	TAILQ_INIT(&pool->output_hooks);
+
+	pool->base = base;
+	pool->timeout = -1;
+
+	return (pool);
+}
+
+static void
+evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
+{
+	free(request->name);
+	free(request);
+}
+
+void
+evrpc_pool_free(struct evrpc_pool *pool)
+{
+	struct evhttp_connection *connection;
+	struct evrpc_request_wrapper *request;
+	struct evrpc_hook *hook;
+
+	while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
+		TAILQ_REMOVE(&pool->requests, request, next);
+		/* if this gets more complicated we need our own function */
+		evrpc_request_wrapper_free(request);
+	}
+
+	while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
+		TAILQ_REMOVE(&pool->connections, connection, next);
+		evhttp_connection_free(connection);
+	}
+
+	while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
+		assert(evrpc_remove_hook(pool, EVRPC_INPUT, hook));
+	}
+
+	while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
+		assert(evrpc_remove_hook(pool, EVRPC_OUTPUT, hook));
+	}
+
+	free(pool);
+}
+
+/*
+ * Add a connection to the RPC pool.   A request scheduled on the pool
+ * may use any available connection.
+ */
+
+void
+evrpc_pool_add_connection(struct evrpc_pool *pool,
+    struct evhttp_connection *connection) {
+	assert(connection->http_server == NULL);
+	TAILQ_INSERT_TAIL(&pool->connections, connection, next);
+
+	/*
+	 * associate an event base with this connection
+	 */
+	if (pool->base != NULL)
+		evhttp_connection_set_base(connection, pool->base);
+
+	/* 
+	 * unless a timeout was specifically set for a connection,
+	 * the connection inherits the timeout from the pool.
+	 */
+	if (connection->timeout == -1)
+		connection->timeout = pool->timeout;
+
+	/* 
+	 * if we have any requests pending, schedule them with the new
+	 * connections.
+	 */
+
+	if (TAILQ_FIRST(&pool->requests) != NULL) {
+		struct evrpc_request_wrapper *request = 
+		    TAILQ_FIRST(&pool->requests);
+		TAILQ_REMOVE(&pool->requests, request, next);
+		evrpc_schedule_request(connection, request);
+	}
+}
+
+void
+evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
+{
+	struct evhttp_connection *evcon;
+	TAILQ_FOREACH(evcon, &pool->connections, next) {
+		evcon->timeout = timeout_in_secs;
+	}
+	pool->timeout = timeout_in_secs;
+}
+
+
+static void evrpc_reply_done(struct evhttp_request *, void *);
+static void evrpc_request_timeout(int, short, void *);
+
+/*
+ * Finds a connection object associated with the pool that is currently
+ * idle and can be used to make a request.
+ */
+static struct evhttp_connection *
+evrpc_pool_find_connection(struct evrpc_pool *pool)
+{
+	struct evhttp_connection *connection;
+	TAILQ_FOREACH(connection, &pool->connections, next) {
+		if (TAILQ_FIRST(&connection->requests) == NULL)
+			return (connection);
+	}
+
+	return (NULL);
+}
+
+/*
+ * We assume that the ctx is no longer queued on the pool.
+ */
+static int
+evrpc_schedule_request(struct evhttp_connection *connection,
+    struct evrpc_request_wrapper *ctx)
+{
+	struct evhttp_request *req = NULL;
+	struct evrpc_pool *pool = ctx->pool;
+	struct evrpc_status status;
+	char *uri = NULL;
+	int res = 0;
+
+	if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
+		goto error;
+
+	/* serialize the request data into the output buffer */
+	ctx->request_marshal(req->output_buffer, ctx->request);
+
+	uri = evrpc_construct_uri(ctx->name);
+	if (uri == NULL)
+		goto error;
+
+	/* we need to know the connection that we might have to abort */
+	ctx->evcon = connection;
+
+	/* apply hooks to the outgoing request */
+	if (evrpc_process_hooks(&pool->output_hooks,
+		req, req->output_buffer) == -1)
+		goto error;
+
+	if (pool->timeout > 0) {
+		/* 
+		 * a timeout after which the whole rpc is going to be aborted.
+		 */
+		struct timeval tv;
+		evutil_timerclear(&tv);
+		tv.tv_sec = pool->timeout;
+		evtimer_add(&ctx->ev_timeout, &tv);
+	}
+
+	/* start the request over the connection */
+	res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
+	free(uri);
+
+	if (res == -1)
+		goto error;
+
+	return (0);
+
+error:
+	memset(&status, 0, sizeof(status));
+	status.error = EVRPC_STATUS_ERR_UNSTARTED;
+	(*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+	evrpc_request_wrapper_free(ctx);
+	return (-1);
+}
+
+int
+evrpc_make_request(struct evrpc_request_wrapper *ctx)
+{
+	struct evrpc_pool *pool = ctx->pool;
+
+	/* initialize the event structure for this rpc */
+	evtimer_set(&ctx->ev_timeout, evrpc_request_timeout, ctx);
+	if (pool->base != NULL)
+		event_base_set(pool->base, &ctx->ev_timeout);
+
+	/* we better have some available connections on the pool */
+	assert(TAILQ_FIRST(&pool->connections) != NULL);
+
+	/* 
+	 * if no connection is available, we queue the request on the pool,
+	 * the next time a connection is empty, the rpc will be send on that.
+	 */
+	TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
+
+	evrpc_pool_schedule(pool);
+
+	return (0);
+}
+
+static void
+evrpc_reply_done(struct evhttp_request *req, void *arg)
+{
+	struct evrpc_request_wrapper *ctx = arg;
+	struct evrpc_pool *pool = ctx->pool;
+	struct evrpc_status status;
+	int res = -1;
+	
+	/* cancel any timeout we might have scheduled */
+	event_del(&ctx->ev_timeout);
+
+	memset(&status, 0, sizeof(status));
+	status.http_req = req;
+
+	/* we need to get the reply now */
+	if (req != NULL) {
+		/* apply hooks to the incoming request */
+		if (evrpc_process_hooks(&pool->input_hooks,
+			req, req->input_buffer) == -1) {
+			status.error = EVRPC_STATUS_ERR_HOOKABORTED;
+			res = -1;
+		} else {
+			res = ctx->reply_unmarshal(ctx->reply,
+			    req->input_buffer);
+			if (res == -1) {
+				status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
+			}
+		}
+	} else {
+		status.error = EVRPC_STATUS_ERR_TIMEOUT;
+	}
+
+	if (res == -1) {
+		/* clear everything that we might have written previously */
+		ctx->reply_clear(ctx->reply);
+	}
+
+	(*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+	
+	evrpc_request_wrapper_free(ctx);
+
+	/* the http layer owns the request structure */
+
+	/* see if we can schedule another request */
+	evrpc_pool_schedule(pool);
+}
+
+static void
+evrpc_pool_schedule(struct evrpc_pool *pool)
+{
+	struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
+	struct evhttp_connection *evcon;
+
+	/* if no requests are pending, we have no work */
+	if (ctx == NULL)
+		return;
+
+	if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
+		TAILQ_REMOVE(&pool->requests, ctx, next);
+		evrpc_schedule_request(evcon, ctx);
+	}
+}
+
+static void
+evrpc_request_timeout(int fd, short what, void *arg)
+{
+	struct evrpc_request_wrapper *ctx = arg;
+	struct evhttp_connection *evcon = ctx->evcon;
+	assert(evcon != NULL);
+
+	evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+}
diff --git a/third_party/libevent/evrpc.h b/third_party/libevent/evrpc.h
new file mode 100644
index 0000000..7c16b95
--- /dev/null
+++ b/third_party/libevent/evrpc.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVRPC_H_
+#define _EVRPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file evrpc.h
+ *
+ * This header files provides basic support for an RPC server and client.
+ *
+ * To support RPCs in a server, every supported RPC command needs to be
+ * defined and registered.
+ *
+ * EVRPC_HEADER(SendCommand, Request, Reply);
+ *
+ *  SendCommand is the name of the RPC command.
+ *  Request is the name of a structure generated by event_rpcgen.py.
+ *    It contains all parameters relating to the SendCommand RPC.  The
+ *    server needs to fill in the Reply structure.
+ *  Reply is the name of a structure generated by event_rpcgen.py.  It
+ *    contains the answer to the RPC.
+ *
+ * To register an RPC with an HTTP server, you need to first create an RPC
+ * base with:
+ *
+ *   struct evrpc_base *base = evrpc_init(http);
+ *
+ * A specific RPC can then be registered with
+ *
+ * EVRPC_REGISTER(base, SendCommand, Request, Reply,  FunctionCB, arg);
+ *
+ * when the server receives an appropriately formatted RPC, the user callback
+ * is invokved.   The callback needs to fill in the reply structure.
+ *
+ * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
+ *
+ * To send the reply, call EVRPC_REQUEST_DONE(rpc);
+ *
+ * See the regression test for an example.
+ */
+
+struct evbuffer;
+struct event_base;
+struct evrpc_req_generic;
+
+/* Encapsulates a request */
+struct evrpc {
+	TAILQ_ENTRY(evrpc) next;
+
+	/* the URI at which the request handler lives */
+	const char* uri;
+
+	/* creates a new request structure */
+	void *(*request_new)(void);
+
+	/* frees the request structure */
+	void (*request_free)(void *);
+
+	/* unmarshals the buffer into the proper request structure */
+	int (*request_unmarshal)(void *, struct evbuffer *);
+
+	/* creates a new reply structure */
+	void *(*reply_new)(void);
+
+	/* creates a new reply structure */
+	void (*reply_free)(void *);
+
+	/* verifies that the reply is valid */
+	int (*reply_complete)(void *);
+	
+	/* marshals the reply into a buffer */
+	void (*reply_marshal)(struct evbuffer*, void *);
+
+	/* the callback invoked for each received rpc */
+	void (*cb)(struct evrpc_req_generic *, void *);
+	void *cb_arg;
+
+	/* reference for further configuration */
+	struct evrpc_base *base;
+};
+
+/** The type of a specific RPC Message
+ *
+ * @param rpcname the name of the RPC message
+ */
+#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
+
+struct evhttp_request;
+struct evrpc_status;
+
+/* We alias the RPC specific structs to this voided one */
+struct evrpc_req_generic {
+	/* the unmarshaled request object */
+	void *request;
+
+	/* the empty reply object that needs to be filled in */
+	void *reply;
+
+	/* 
+	 * the static structure for this rpc; that can be used to
+	 * automatically unmarshal and marshal the http buffers.
+	 */
+	struct evrpc *rpc;
+
+	/*
+	 * the http request structure on which we need to answer.
+	 */
+	struct evhttp_request* http_req;
+
+	/*
+	 * callback to reply and finish answering this rpc
+	 */
+	void (*done)(struct evrpc_req_generic* rpc); 
+};
+
+/** Creates the definitions and prototypes for an RPC
+ *
+ * You need to use EVRPC_HEADER to create structures and function prototypes
+ * needed by the server and client implementation.  The structures have to be
+ * defined in an .rpc file and converted to source code via event_rpcgen.py
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_GENERATE()
+ */
+#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
+EVRPC_STRUCT(rpcname) {	\
+	struct reqstruct* request; \
+	struct rplystruct* reply; \
+	struct evrpc* rpc; \
+	struct evhttp_request* http_req; \
+	void (*done)(struct evrpc_status *, \
+	    struct evrpc* rpc, void *request, void *reply);	     \
+};								     \
+int evrpc_send_request_##rpcname(struct evrpc_pool *, \
+    struct reqstruct *, struct rplystruct *, \
+    void (*)(struct evrpc_status *, \
+	struct reqstruct *, struct rplystruct *, void *cbarg),	\
+    void *);
+
+/** Generates the code for receiving and sending an RPC message
+ *
+ * EVRPC_GENERATE is used to create the code corresponding to sending
+ * and receiving a particular RPC message
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_HEADER()
+ */
+#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
+int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
+    struct reqstruct *request, struct rplystruct *reply, \
+    void (*cb)(struct evrpc_status *, \
+	struct reqstruct *, struct rplystruct *, void *cbarg),	\
+    void *cbarg) { \
+	struct evrpc_status status;				    \
+	struct evrpc_request_wrapper *ctx;			    \
+	ctx = (struct evrpc_request_wrapper *) \
+	    malloc(sizeof(struct evrpc_request_wrapper));	    \
+	if (ctx == NULL)					    \
+		goto error;					    \
+	ctx->pool = pool;					    \
+	ctx->evcon = NULL;					    \
+	ctx->name = strdup(#rpcname);				    \
+	if (ctx->name == NULL) {				    \
+		free(ctx);					    \
+		goto error;					    \
+	}							    \
+	ctx->cb = (void (*)(struct evrpc_status *, \
+		void *, void *, void *))cb;			    \
+	ctx->cb_arg = cbarg;					    \
+	ctx->request = (void *)request;				    \
+	ctx->reply = (void *)reply;				    \
+	ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \
+	ctx->reply_clear = (void (*)(void *))rplystruct##_clear;    \
+	ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \
+	return (evrpc_make_request(ctx));			    \
+error:								    \
+	memset(&status, 0, sizeof(status));			    \
+	status.error = EVRPC_STATUS_ERR_UNSTARTED;		    \
+	(*(cb))(&status, request, reply, cbarg);		    \
+	return (-1);						    \
+}
+
+/** Provides access to the HTTP request object underlying an RPC
+ *
+ * Access to the underlying http object; can be used to look at headers or
+ * for getting the remote ip address
+ *
+ * @param rpc_req the rpc request structure provided to the server callback
+ * @return an struct evhttp_request object that can be inspected for
+ * HTTP headers or sender information.
+ */
+#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
+
+/** Creates the reply to an RPC request
+ * 
+ * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
+ * to have been filled in.  The request and reply pointers become invalid
+ * after this call has finished.
+ * 
+ * @param rpc_req the rpc request structure provided to the server callback
+ */
+#define EVRPC_REQUEST_DONE(rpc_req) do { \
+  struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
+  _req->done(_req); \
+} while (0)
+  
+
+/* Takes a request object and fills it in with the right magic */
+#define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \
+  do { \
+    (rpc)->uri = strdup(#name); \
+    if ((rpc)->uri == NULL) {			 \
+      fprintf(stderr, "failed to register object\n");	\
+      exit(1);						\
+    } \
+    (rpc)->request_new = (void *(*)(void))request##_new; \
+    (rpc)->request_free = (void (*)(void *))request##_free; \
+    (rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
+    (rpc)->reply_new = (void *(*)(void))reply##_new; \
+    (rpc)->reply_free = (void (*)(void *))reply##_free; \
+    (rpc)->reply_complete = (int (*)(void *))reply##_complete; \
+    (rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal; \
+  } while (0)
+
+struct evrpc_base;
+struct evhttp;
+
+/* functions to start up the rpc system */
+
+/** Creates a new rpc base from which RPC requests can be received
+ *
+ * @param server a pointer to an existing HTTP server
+ * @return a newly allocated evrpc_base struct
+ * @see evrpc_free()
+ */
+struct evrpc_base *evrpc_init(struct evhttp *server);
+
+/** 
+ * Frees the evrpc base
+ *
+ * For now, you are responsible for making sure that no rpcs are ongoing.
+ *
+ * @param base the evrpc_base object to be freed
+ * @see evrpc_init
+ */
+void evrpc_free(struct evrpc_base *base);
+
+/** register RPCs with the HTTP Server
+ *
+ * registers a new RPC with the HTTP server, each RPC needs to have
+ * a unique name under which it can be identified.
+ *
+ * @param base the evrpc_base structure in which the RPC should be
+ *   registered.
+ * @param name the name of the RPC
+ * @param request the name of the RPC request structure
+ * @param reply the name of the RPC reply structure
+ * @param callback the callback that should be invoked when the RPC
+ * is received.  The callback has the following prototype
+ *   void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
+ * @param cbarg an additional parameter that can be passed to the callback.
+ *   The parameter can be used to carry around state.
+ */
+#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
+  do { \
+    struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \
+    EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \
+    evrpc_register_rpc(base, rpc, \
+	(void (*)(struct evrpc_req_generic*, void *))callback, cbarg);	\
+  } while (0)
+
+int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
+    void (*)(struct evrpc_req_generic*, void *), void *);
+
+/**
+ * Unregisters an already registered RPC
+ *
+ * @param base the evrpc_base object from which to unregister an RPC
+ * @param name the name of the rpc to unregister
+ * @return -1 on error or 0 when successful.
+ * @see EVRPC_REGISTER()
+ */
+#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name)
+
+int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
+
+/*
+ * Client-side RPC support
+ */
+
+struct evrpc_pool;
+struct evhttp_connection;
+
+/** 
+ * provides information about the completed RPC request.
+ */
+struct evrpc_status {
+#define EVRPC_STATUS_ERR_NONE		0
+#define EVRPC_STATUS_ERR_TIMEOUT	1
+#define EVRPC_STATUS_ERR_BADPAYLOAD	2
+#define EVRPC_STATUS_ERR_UNSTARTED	3
+#define EVRPC_STATUS_ERR_HOOKABORTED	4
+	int error;
+
+	/* for looking at headers or other information */
+	struct evhttp_request *http_req;
+};
+
+struct evrpc_request_wrapper {
+	TAILQ_ENTRY(evrpc_request_wrapper) next;
+
+        /* pool on which this rpc request is being made */
+        struct evrpc_pool *pool;
+
+        /* connection on which the request is being sent */
+	struct evhttp_connection *evcon;
+
+	/* event for implementing request timeouts */
+	struct event ev_timeout;
+
+	/* the name of the rpc */
+	char *name;
+
+	/* callback */
+	void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
+	void *cb_arg;
+
+	void *request;
+	void *reply;
+
+	/* unmarshals the buffer into the proper request structure */
+	void (*request_marshal)(struct evbuffer *, void *);
+
+	/* removes all stored state in the reply */
+	void (*reply_clear)(void *);
+
+	/* marshals the reply into a buffer */
+	int (*reply_unmarshal)(void *, struct evbuffer*);
+};
+
+/** launches an RPC and sends it to the server
+ *
+ * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
+ *
+ * @param name the name of the RPC
+ * @param pool the evrpc_pool that contains the connection objects over which
+ *   the request should be sent.
+ * @param request a pointer to the RPC request structure - it contains the
+ *   data to be sent to the server.
+ * @param reply a pointer to the RPC reply structure.  It is going to be filled
+ *   if the request was answered successfully
+ * @param cb the callback to invoke when the RPC request has been answered
+ * @param cbarg an additional argument to be passed to the client
+ * @return 0 on success, -1 on failure
+ */
+#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg)	\
+	evrpc_send_request_##name(pool, request, reply, cb, cbarg)
+
+int evrpc_make_request(struct evrpc_request_wrapper *);
+
+/** creates an rpc connection pool
+ * 
+ * a pool has a number of connections associated with it.
+ * rpc requests are always made via a pool.
+ *
+ * @param base a pointer to an struct event_based object; can be left NULL
+ *   in singled-threaded applications
+ * @return a newly allocated struct evrpc_pool object
+ * @see evrpc_pool_free()
+ */
+struct evrpc_pool *evrpc_pool_new(struct event_base *base);
+/** frees an rpc connection pool
+ *
+ * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
+ * @see evrpc_pool_new()
+ */
+void evrpc_pool_free(struct evrpc_pool *pool);
+/*
+ * adds a connection over which rpc can be dispatched.  the connection
+ * object must have been newly created.
+ */
+void evrpc_pool_add_connection(struct evrpc_pool *, 
+    struct evhttp_connection *);
+
+/**
+ * Sets the timeout in secs after which a request has to complete.  The
+ * RPC is completely aborted if it does not complete by then.  Setting
+ * the timeout to 0 means that it never timeouts and can be used to
+ * implement callback type RPCs.
+ *
+ * Any connection already in the pool will be updated with the new
+ * timeout.  Connections added to the pool after set_timeout has be
+ * called receive the pool timeout only if no timeout has been set
+ * for the connection itself.
+ *
+ * @param pool a pointer to a struct evrpc_pool object
+ * @param timeout_in_secs the number of seconds after which a request should
+ *   timeout and a failure be returned to the callback.
+ */
+void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
+
+/**
+ * Hooks for changing the input and output of RPCs; this can be used to
+ * implement compression, authentication, encryption, ...
+ */
+
+enum EVRPC_HOOK_TYPE {
+	EVRPC_INPUT,		/**< apply the function to an input hook */
+	EVRPC_OUTPUT		/**< apply the function to an output hook */
+};
+
+#ifndef WIN32
+/** Deprecated alias for EVRPC_INPUT.  Not available on windows, where it
+ * conflicts with platform headers. */
+#define INPUT EVRPC_INPUT
+/** Deprecated alias for EVRPC_OUTPUT.  Not available on windows, where it
+ * conflicts with platform headers. */
+#define OUTPUT EVRPC_OUTPUT
+#endif
+
+/** adds a processing hook to either an rpc base or rpc pool
+ *
+ * If a hook returns -1, the processing is aborted.
+ *
+ * The add functions return handles that can be used for removing hooks.
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param cb the callback to call when the hook is activated
+ * @param cb_arg an additional argument for the callback
+ * @return a handle to the hook so it can be removed later
+ * @see evrpc_remove_hook()
+ */
+void *evrpc_add_hook(void *vbase,
+    enum EVRPC_HOOK_TYPE hook_type,
+    int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
+    void *cb_arg);
+
+/** removes a previously added hook
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param handle a handle returned by evrpc_add_hook()
+ * @return 1 on success or 0 on failure
+ * @see evrpc_add_hook()
+ */
+int evrpc_remove_hook(void *vbase,
+    enum EVRPC_HOOK_TYPE hook_type,
+    void *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVRPC_H_ */
diff --git a/third_party/libevent/evsignal.h b/third_party/libevent/evsignal.h
new file mode 100644
index 0000000..076cd8d
--- /dev/null
+++ b/third_party/libevent/evsignal.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVSIGNAL_H_
+#define _EVSIGNAL_H_
+
+typedef void (*ev_sighandler_t)(int);
+
+struct evsignal_info {
+	struct event ev_signal;
+	int ev_signal_pair[2];
+	int ev_signal_added;
+	volatile sig_atomic_t evsignal_caught;
+	struct event_list evsigevents[NSIG];
+	sig_atomic_t evsigcaught[NSIG];
+#ifdef HAVE_SIGACTION
+	struct sigaction **sh_old;
+#else
+	ev_sighandler_t **sh_old;
+#endif
+	int sh_old_max;
+};
+int evsignal_init(struct event_base *);
+void evsignal_process(struct event_base *);
+int evsignal_add(struct event *);
+int evsignal_del(struct event *);
+void evsignal_dealloc(struct event_base *);
+
+#endif /* _EVSIGNAL_H_ */
diff --git a/third_party/libevent/evutil.c b/third_party/libevent/evutil.c
new file mode 100644
index 0000000..564377d
--- /dev/null
+++ b/third_party/libevent/evutil.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#if defined WIN32 && !defined(HAVE_GETTIMEOFDAY_H)
+#include <sys/timeb.h>
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+#include <sys/queue.h>
+#include "event.h"
+#include "event-internal.h"
+#include "evutil.h"
+#include "log.h"
+
+int
+evutil_socketpair(int family, int type, int protocol, int fd[2])
+{
+#ifndef WIN32
+	return socketpair(family, type, protocol, fd);
+#else
+	/* This code is originally from Tor.  Used with permission. */
+
+	/* This socketpair does not work when localhost is down. So
+	 * it's really not the same thing at all. But it's close enough
+	 * for now, and really, when localhost is down sometimes, we
+	 * have other problems too.
+	 */
+	int listener = -1;
+	int connector = -1;
+	int acceptor = -1;
+	struct sockaddr_in listen_addr;
+	struct sockaddr_in connect_addr;
+	int size;
+	int saved_errno = -1;
+
+	if (protocol
+#ifdef AF_UNIX
+		|| family != AF_UNIX
+#endif
+		) {
+		EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT);
+		return -1;
+	}
+	if (!fd) {
+		EVUTIL_SET_SOCKET_ERROR(WSAEINVAL);
+		return -1;
+	}
+
+	listener = socket(AF_INET, type, 0);
+	if (listener < 0)
+		return -1;
+	memset(&listen_addr, 0, sizeof(listen_addr));
+	listen_addr.sin_family = AF_INET;
+	listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	listen_addr.sin_port = 0;	/* kernel chooses port.	 */
+	if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
+		== -1)
+		goto tidy_up_and_fail;
+	if (listen(listener, 1) == -1)
+		goto tidy_up_and_fail;
+
+	connector = socket(AF_INET, type, 0);
+	if (connector < 0)
+		goto tidy_up_and_fail;
+	/* We want to find out the port number to connect to.  */
+	size = sizeof(connect_addr);
+	if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
+		goto tidy_up_and_fail;
+	if (size != sizeof (connect_addr))
+		goto abort_tidy_up_and_fail;
+	if (connect(connector, (struct sockaddr *) &connect_addr,
+				sizeof(connect_addr)) == -1)
+		goto tidy_up_and_fail;
+
+	size = sizeof(listen_addr);
+	acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
+	if (acceptor < 0)
+		goto tidy_up_and_fail;
+	if (size != sizeof(listen_addr))
+		goto abort_tidy_up_and_fail;
+	EVUTIL_CLOSESOCKET(listener);
+	/* Now check we are talking to ourself by matching port and host on the
+	   two sockets.	 */
+	if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
+		goto tidy_up_and_fail;
+	if (size != sizeof (connect_addr)
+		|| listen_addr.sin_family != connect_addr.sin_family
+		|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
+		|| listen_addr.sin_port != connect_addr.sin_port)
+		goto abort_tidy_up_and_fail;
+	fd[0] = connector;
+	fd[1] = acceptor;
+
+	return 0;
+
+ abort_tidy_up_and_fail:
+	saved_errno = WSAECONNABORTED;
+ tidy_up_and_fail:
+	if (saved_errno < 0)
+		saved_errno = WSAGetLastError();
+	if (listener != -1)
+		EVUTIL_CLOSESOCKET(listener);
+	if (connector != -1)
+		EVUTIL_CLOSESOCKET(connector);
+	if (acceptor != -1)
+		EVUTIL_CLOSESOCKET(acceptor);
+
+	EVUTIL_SET_SOCKET_ERROR(saved_errno);
+	return -1;
+#endif
+}
+
+int
+evutil_make_socket_nonblocking(int fd)
+{
+#ifdef WIN32
+	{
+		unsigned long nonblocking = 1;
+		ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
+	}
+#else
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+		event_warn("fcntl(O_NONBLOCK)");
+		return -1;
+}	
+#endif
+	return 0;
+}
+
+ev_int64_t
+evutil_strtoll(const char *s, char **endptr, int base)
+{
+#ifdef HAVE_STRTOLL
+	return (ev_int64_t)strtoll(s, endptr, base);
+#elif SIZEOF_LONG == 8
+	return (ev_int64_t)strtol(s, endptr, base);
+#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
+	/* XXXX on old versions of MS APIs, we only support base
+	 * 10. */
+	ev_int64_t r;
+	if (base != 10)
+		return 0;
+	r = (ev_int64_t) _atoi64(s);
+	while (isspace(*s))
+		++s;
+	while (isdigit(*s))
+		++s;
+	if (endptr)
+		*endptr = (char*) s;
+	return r;
+#elif defined(WIN32)
+	return (ev_int64_t) _strtoi64(s, endptr, base);
+#else
+#error "I don't know how to parse 64-bit integers."
+#endif
+}
+
+#ifndef _EVENT_HAVE_GETTIMEOFDAY
+int
+evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	struct _timeb tb;
+
+	if(tv == NULL)
+		return -1;
+
+	_ftime(&tb);
+	tv->tv_sec = (long) tb.time;
+	tv->tv_usec = ((int) tb.millitm) * 1000;
+	return 0;
+}
+#endif
+
+int
+evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+{
+	int r;
+	va_list ap;
+	va_start(ap, format);
+	r = evutil_vsnprintf(buf, buflen, format, ap);
+	va_end(ap);
+	return r;
+}
+
+int
+evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
+{
+#ifdef _MSC_VER
+	int r = _vsnprintf(buf, buflen, format, ap);
+	buf[buflen-1] = '\0';
+	if (r >= 0)
+		return r;
+	else
+		return _vscprintf(format, ap);
+#else
+	int r = vsnprintf(buf, buflen, format, ap);
+	buf[buflen-1] = '\0';
+	return r;
+#endif
+}
+
+static int
+evutil_issetugid(void)
+{
+#ifdef _EVENT_HAVE_ISSETUGID
+	return issetugid();
+#else
+
+#ifdef _EVENT_HAVE_GETEUID
+	if (getuid() != geteuid())
+		return 1;
+#endif
+#ifdef _EVENT_HAVE_GETEGID
+	if (getgid() != getegid())
+		return 1;
+#endif
+	return 0;
+#endif
+}
+
+const char *
+evutil_getenv(const char *varname)
+{
+	if (evutil_issetugid())
+		return NULL;
+
+	return getenv(varname);
+}
diff --git a/third_party/libevent/evutil.h b/third_party/libevent/evutil.h
new file mode 100644
index 0000000..8b664b9
--- /dev/null
+++ b/third_party/libevent/evutil.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVUTIL_H_
+#define _EVUTIL_H_
+
+/** @file evutil.h
+
+  Common convenience functions for cross-platform portability and
+  related socket manipulations.
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event-config.h"
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(_EVENT_HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <stdarg.h>
+
+#ifdef _EVENT_HAVE_UINT64_T
+#define ev_uint64_t uint64_t
+#define ev_int64_t int64_t
+#elif defined(WIN32)
+#define ev_uint64_t unsigned __int64
+#define ev_int64_t signed __int64
+#elif _EVENT_SIZEOF_LONG_LONG == 8
+#define ev_uint64_t unsigned long long
+#define ev_int64_t long long
+#elif _EVENT_SIZEOF_LONG == 8
+#define ev_uint64_t unsigned long
+#define ev_int64_t long
+#else
+#error "No way to define ev_uint64_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT32_T
+#define ev_uint32_t uint32_t
+#elif defined(WIN32)
+#define ev_uint32_t unsigned int
+#elif _EVENT_SIZEOF_LONG == 4
+#define ev_uint32_t unsigned long
+#elif _EVENT_SIZEOF_INT == 4
+#define ev_uint32_t unsigned int
+#else
+#error "No way to define ev_uint32_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT16_T
+#define ev_uint16_t uint16_t
+#elif defined(WIN32)
+#define ev_uint16_t unsigned short
+#elif _EVENT_SIZEOF_INT == 2
+#define ev_uint16_t unsigned int
+#elif _EVENT_SIZEOF_SHORT == 2
+#define ev_uint16_t unsigned short
+#else
+#error "No way to define ev_uint16_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT8_T
+#define ev_uint8_t uint8_t
+#else
+#define ev_uint8_t unsigned char
+#endif
+
+int evutil_socketpair(int d, int type, int protocol, int sv[2]);
+int evutil_make_socket_nonblocking(int sock);
+#ifdef WIN32
+#define EVUTIL_CLOSESOCKET(s) closesocket(s)
+#else
+#define EVUTIL_CLOSESOCKET(s) close(s)
+#endif
+
+#ifdef WIN32
+#define EVUTIL_SOCKET_ERROR() WSAGetLastError()
+#define EVUTIL_SET_SOCKET_ERROR(errcode)		\
+	do { WSASetLastError(errcode); } while (0)
+#else
+#define EVUTIL_SOCKET_ERROR() (errno)
+#define EVUTIL_SET_SOCKET_ERROR(errcode)		\
+		do { errno = (errcode); } while (0)
+#endif
+
+/*
+ * Manipulation functions for struct timeval
+ */
+#ifdef _EVENT_HAVE_TIMERADD
+#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp))
+#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp))
+#else
+#define evutil_timeradd(tvp, uvp, vvp)							\
+	do {														\
+		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;			\
+		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
+		if ((vvp)->tv_usec >= 1000000) {						\
+			(vvp)->tv_sec++;									\
+			(vvp)->tv_usec -= 1000000;							\
+		}														\
+	} while (0)
+#define	evutil_timersub(tvp, uvp, vvp)						\
+	do {													\
+		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec < 0) {							\
+			(vvp)->tv_sec--;								\
+			(vvp)->tv_usec += 1000000;						\
+		}													\
+	} while (0)
+#endif /* !_EVENT_HAVE_HAVE_TIMERADD */
+
+#ifdef _EVENT_HAVE_TIMERCLEAR
+#define evutil_timerclear(tvp) timerclear(tvp)
+#else
+#define	evutil_timerclear(tvp)	(tvp)->tv_sec = (tvp)->tv_usec = 0
+#endif
+
+#define	evutil_timercmp(tvp, uvp, cmp)							\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?							\
+	 ((tvp)->tv_usec cmp (uvp)->tv_usec) :						\
+	 ((tvp)->tv_sec cmp (uvp)->tv_sec))
+
+#ifdef _EVENT_HAVE_TIMERISSET
+#define evutil_timerisset(tvp) timerisset(tvp)
+#else
+#define	evutil_timerisset(tvp)	((tvp)->tv_sec || (tvp)->tv_usec)
+#endif
+
+
+/* big-int related functions */
+ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
+
+
+#ifdef _EVENT_HAVE_GETTIMEOFDAY
+#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
+#else
+struct timezone;
+int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
+#endif
+
+int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+#ifdef __GNUC__
+	__attribute__((format(printf, 3, 4)))
+#endif
+	;
+int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVUTIL_H_ */
diff --git a/third_party/libevent/freebsd/config.h b/third_party/libevent/freebsd/config.h
new file mode 100644
index 0000000..4fe3d6b
--- /dev/null
+++ b/third_party/libevent/freebsd/config.h
@@ -0,0 +1,266 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/third_party/libevent/freebsd/event-config.h b/third_party/libevent/freebsd/event-config.h
new file mode 100644
index 0000000..662abc8
--- /dev/null
+++ b/third_party/libevent/freebsd/event-config.h
@@ -0,0 +1,274 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define _EVENT_HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define _EVENT_HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef _EVENT_HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef _EVENT_HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define _EVENT_HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define _EVENT_HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/third_party/libevent/http-internal.h b/third_party/libevent/http-internal.h
new file mode 100644
index 0000000..9cd03cd
--- /dev/null
+++ b/third_party/libevent/http-internal.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * This header file contains definitions for dealing with HTTP requests
+ * that are internal to libevent.  As user of the library, you should not
+ * need to know about these.
+ */
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+#define HTTP_CONNECT_TIMEOUT	45
+#define HTTP_WRITE_TIMEOUT	50
+#define HTTP_READ_TIMEOUT	50
+
+#define HTTP_PREFIX		"http://"
+#define HTTP_DEFAULTPORT	80
+
+enum message_read_status {
+	ALL_DATA_READ = 1,
+	MORE_DATA_EXPECTED = 0,
+	DATA_CORRUPTED = -1,
+	REQUEST_CANCELED = -2
+};
+
+enum evhttp_connection_error {
+	EVCON_HTTP_TIMEOUT,
+	EVCON_HTTP_EOF,
+	EVCON_HTTP_INVALID_HEADER
+};
+
+struct evbuffer;
+struct addrinfo;
+struct evhttp_request;
+
+/* A stupid connection object - maybe make this a bufferevent later */
+
+enum evhttp_connection_state {
+	EVCON_DISCONNECTED,	/**< not currently connected not trying either*/
+	EVCON_CONNECTING,	/**< tries to currently connect */
+	EVCON_IDLE,		/**< connection is established */
+	EVCON_READING_FIRSTLINE,/**< reading Request-Line (incoming conn) or
+				 **< Status-Line (outgoing conn) */
+	EVCON_READING_HEADERS,	/**< reading request/response headers */
+	EVCON_READING_BODY,	/**< reading request/response body */
+	EVCON_READING_TRAILER,	/**< reading request/response chunked trailer */
+	EVCON_WRITING		/**< writing request/response headers/body */
+};
+
+struct event_base;
+
+struct evhttp_connection {
+	/* we use tailq only if they were created for an http server */
+	TAILQ_ENTRY(evhttp_connection) (next);
+
+	int fd;
+	struct event ev;
+	struct event close_ev;
+	struct evbuffer *input_buffer;
+	struct evbuffer *output_buffer;
+	
+	char *bind_address;		/* address to use for binding the src */
+	u_short bind_port;		/* local port for binding the src */
+
+	char *address;			/* address to connect to */
+	u_short port;
+
+	int flags;
+#define EVHTTP_CON_INCOMING	0x0001	/* only one request on it ever */
+#define EVHTTP_CON_OUTGOING	0x0002  /* multiple requests possible */
+#define EVHTTP_CON_CLOSEDETECT  0x0004  /* detecting if persistent close */
+
+	int timeout;			/* timeout in seconds for events */
+	int retry_cnt;			/* retry count */
+	int retry_max;			/* maximum number of retries */
+	
+	enum evhttp_connection_state state;
+
+	/* for server connections, the http server they are connected with */
+	struct evhttp *http_server;
+
+	TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
+	
+						   void (*cb)(struct evhttp_connection *, void *);
+	void *cb_arg;
+	
+	void (*closecb)(struct evhttp_connection *, void *);
+	void *closecb_arg;
+
+	struct event_base *base;
+};
+
+struct evhttp_cb {
+	TAILQ_ENTRY(evhttp_cb) next;
+
+	char *what;
+
+	void (*cb)(struct evhttp_request *req, void *);
+	void *cbarg;
+};
+
+/* both the http server as well as the rpc system need to queue connections */
+TAILQ_HEAD(evconq, evhttp_connection);
+
+/* each bound socket is stored in one of these */
+struct evhttp_bound_socket {
+	TAILQ_ENTRY(evhttp_bound_socket) (next);
+
+	struct event  bind_ev;
+};
+
+struct evhttp {
+	TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
+
+	TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+        struct evconq connections;
+
+        int timeout;
+
+	void (*gencb)(struct evhttp_request *req, void *);
+	void *gencbarg;
+
+	struct event_base *base;
+};
+
+/* resets the connection; can be reused for more requests */
+void evhttp_connection_reset(struct evhttp_connection *);
+
+/* connects if necessary */
+int evhttp_connection_connect(struct evhttp_connection *);
+
+/* notifies the current request that it failed; resets connection */
+void evhttp_connection_fail(struct evhttp_connection *,
+    enum evhttp_connection_error error);
+
+void evhttp_get_request(struct evhttp *, int, struct sockaddr *, socklen_t);
+
+int evhttp_hostportfile(char *, char **, u_short *, char **);
+
+int evhttp_parse_firstline(struct evhttp_request *, struct evbuffer*);
+int evhttp_parse_headers(struct evhttp_request *, struct evbuffer*);
+
+void evhttp_start_read(struct evhttp_connection *);
+void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
+
+void evhttp_write_buffer(struct evhttp_connection *,
+    void (*)(struct evhttp_connection *, void *), void *);
+
+/* response sending HTML the data in the buffer */
+void evhttp_response_code(struct evhttp_request *, int, const char *);
+void evhttp_send_page(struct evhttp_request *, struct evbuffer *);
+
+#endif /* _HTTP_H */
diff --git a/third_party/libevent/http.c b/third_party/libevent/http.c
new file mode 100644
index 0000000..b04ad54
--- /dev/null
+++ b/third_party/libevent/http.c
@@ -0,0 +1,2826 @@
+/*
+ * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+
+#ifndef WIN32
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#endif
+
+#include <sys/queue.h>
+
+#ifndef WIN32
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#undef timeout_pending
+#undef timeout_initialized
+
+#include "strlcpy-internal.h"
+#include "event.h"
+#include "evhttp.h"
+#include "evutil.h"
+#include "log.h"
+#include "http-internal.h"
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define strdup _strdup
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+#define NI_MAXSERV 32
+#define NI_MAXHOST 1025
+
+#define NI_NUMERICHOST 1
+#define NI_NUMERICSERV 2
+
+static int
+fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 
+	size_t hostlen, char *serv, size_t servlen, int flags)
+{
+        struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+        
+        if (serv != NULL) {
+				char tmpserv[16];
+				evutil_snprintf(tmpserv, sizeof(tmpserv),
+					"%d", ntohs(sin->sin_port));
+                if (strlcpy(serv, tmpserv, servlen) >= servlen)
+                        return (-1);
+        }
+
+        if (host != NULL) {
+                if (flags & NI_NUMERICHOST) {
+                        if (strlcpy(host, inet_ntoa(sin->sin_addr),
+                            hostlen) >= hostlen)
+                                return (-1);
+                        else
+                                return (0);
+                } else {
+						struct hostent *hp;
+                        hp = gethostbyaddr((char *)&sin->sin_addr, 
+                            sizeof(struct in_addr), AF_INET);
+                        if (hp == NULL)
+                                return (-2);
+                        
+                        if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
+                                return (-1);
+                        else
+                                return (0);
+                }
+        }
+        return (0);
+}
+
+#endif
+
+#ifndef HAVE_GETADDRINFO
+struct addrinfo {
+	int ai_family;
+	int ai_socktype;
+	int ai_protocol;
+	size_t ai_addrlen;
+	struct sockaddr *ai_addr;
+	struct addrinfo *ai_next;
+};
+static int
+fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
+{
+	struct hostent *he = NULL;
+	struct sockaddr_in *sa;
+	if (hostname) {
+		he = gethostbyname(hostname);
+		if (!he)
+			return (-1);
+	}
+	ai->ai_family = he ? he->h_addrtype : AF_INET;
+	ai->ai_socktype = SOCK_STREAM;
+	ai->ai_protocol = 0;
+	ai->ai_addrlen = sizeof(struct sockaddr_in);
+	if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen)))
+		return (-1);
+	sa = (struct sockaddr_in*)ai->ai_addr;
+	memset(sa, 0, ai->ai_addrlen);
+	if (he) {
+		sa->sin_family = he->h_addrtype;
+		memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);
+	} else {
+		sa->sin_family = AF_INET;
+		sa->sin_addr.s_addr = INADDR_ANY;
+	}
+	ai->ai_next = NULL;
+	return (0);
+}
+static void
+fake_freeaddrinfo(struct addrinfo *ai)
+{
+	free(ai->ai_addr);
+}
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+/* wrapper for setting the base from the http server */
+#define EVHTTP_BASE_SET(x, y) do { \
+	if ((x)->base != NULL) event_base_set((x)->base, y);	\
+} while (0) 
+
+extern int debug;
+
+static int socket_connect(int fd, const char *address, unsigned short port);
+static int bind_socket_ai(struct addrinfo *, int reuse);
+static int bind_socket(const char *, u_short, int reuse);
+static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
+static int evhttp_associate_new_request_with_connection(
+	struct evhttp_connection *evcon);
+static void evhttp_connection_start_detectclose(
+	struct evhttp_connection *evcon);
+static void evhttp_connection_stop_detectclose(
+	struct evhttp_connection *evcon);
+static void evhttp_request_dispatch(struct evhttp_connection* evcon);
+static void evhttp_read_firstline(struct evhttp_connection *evcon,
+				  struct evhttp_request *req);
+static void evhttp_read_header(struct evhttp_connection *evcon,
+    struct evhttp_request *req);
+static int evhttp_add_header_internal(struct evkeyvalq *headers,
+    const char *key, const char *value);
+static int evhttp_decode_uri_internal(const char *uri, size_t length,
+    char *ret, int always_decode_plus);
+
+void evhttp_read(int, short, void *);
+void evhttp_write(int, short, void *);
+
+#ifndef HAVE_STRSEP
+/* strsep replacement for platforms that lack it.  Only works if
+ * del is one character long. */
+static char *
+strsep(char **s, const char *del)
+{
+	char *d, *tok;
+	assert(strlen(del) == 1);
+	if (!s || !*s)
+		return NULL;
+	tok = *s;
+	d = strstr(tok, del);
+	if (d) {
+		*d = '\0';
+		*s = d + 1;
+	} else
+		*s = NULL;
+	return tok;
+}
+#endif
+
+static const char *
+html_replace(char ch, char *buf)
+{
+	switch (ch) {
+	case '<':
+		return "&lt;";
+	case '>':
+		return "&gt;";
+	case '"':
+		return "&quot;";
+	case '\'':
+		return "&#039;";
+	case '&':
+		return "&amp;";
+	default:
+		break;
+	}
+
+	/* Echo the character back */
+	buf[0] = ch;
+	buf[1] = '\0';
+	
+	return buf;
+}
+
+/*
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ */
+
+char *
+evhttp_htmlescape(const char *html)
+{
+	int i, new_size = 0, old_size = strlen(html);
+	char *escaped_html, *p;
+	char scratch_space[2];
+	
+	for (i = 0; i < old_size; ++i)
+          new_size += strlen(html_replace(html[i], scratch_space));
+
+	p = escaped_html = malloc(new_size + 1);
+	if (escaped_html == NULL)
+		event_err(1, "%s: malloc(%d)", __func__, new_size + 1);
+	for (i = 0; i < old_size; ++i) {
+		const char *replaced = html_replace(html[i], scratch_space);
+		/* this is length checked */
+		strcpy(p, replaced);
+		p += strlen(replaced);
+	}
+
+	*p = '\0';
+
+	return (escaped_html);
+}
+
+static const char *
+evhttp_method(enum evhttp_cmd_type type)
+{
+	const char *method;
+
+	switch (type) {
+	case EVHTTP_REQ_GET:
+		method = "GET";
+		break;
+	case EVHTTP_REQ_POST:
+		method = "POST";
+		break;
+	case EVHTTP_REQ_HEAD:
+		method = "HEAD";
+		break;
+	default:
+		method = NULL;
+		break;
+	}
+
+	return (method);
+}
+
+static void
+evhttp_add_event(struct event *ev, int timeout, int default_timeout)
+{
+	if (timeout != 0) {
+		struct timeval tv;
+		
+		evutil_timerclear(&tv);
+		tv.tv_sec = timeout != -1 ? timeout : default_timeout;
+		event_add(ev, &tv);
+	} else {
+		event_add(ev, NULL);
+	}
+}
+
+void
+evhttp_write_buffer(struct evhttp_connection *evcon,
+    void (*cb)(struct evhttp_connection *, void *), void *arg)
+{
+	event_debug(("%s: preparing to write buffer\n", __func__));
+
+	/* Set call back */
+	evcon->cb = cb;
+	evcon->cb_arg = arg;
+
+	/* check if the event is already pending */
+	if (event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL))
+		event_del(&evcon->ev);
+
+	event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT);
+}
+
+static int
+evhttp_connected(struct evhttp_connection *evcon)
+{
+	switch (evcon->state) {
+	case EVCON_DISCONNECTED:
+	case EVCON_CONNECTING:
+		return (0);
+	case EVCON_IDLE:
+	case EVCON_READING_FIRSTLINE:
+	case EVCON_READING_HEADERS:
+	case EVCON_READING_BODY:
+	case EVCON_READING_TRAILER:
+	case EVCON_WRITING:
+	default:
+		return (1);
+	}
+}
+
+/*
+ * Create the headers needed for an HTTP request
+ */
+static void
+evhttp_make_header_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req)
+{
+	const char *method;
+	
+	evhttp_remove_header(req->output_headers, "Proxy-Connection");
+
+	/* Generate request line */
+	method = evhttp_method(req->type);
+	evbuffer_add_printf(evcon->output_buffer, "%s %s HTTP/%d.%d\r\n",
+	    method, req->uri, req->major, req->minor);
+
+	/* Add the content length on a post request if missing */
+	if (req->type == EVHTTP_REQ_POST &&
+	    evhttp_find_header(req->output_headers, "Content-Length") == NULL){
+		char size[12];
+		evutil_snprintf(size, sizeof(size), "%ld",
+		    (long)EVBUFFER_LENGTH(req->output_buffer));
+		evhttp_add_header(req->output_headers, "Content-Length", size);
+	}
+}
+
+static int
+evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
+{
+	if (flags & EVHTTP_PROXY_REQUEST) {
+		/* proxy connection */
+		const char *connection = evhttp_find_header(headers, "Proxy-Connection");
+		return (connection == NULL || strcasecmp(connection, "keep-alive") != 0);
+	} else {
+		const char *connection = evhttp_find_header(headers, "Connection");
+		return (connection != NULL && strcasecmp(connection, "close") == 0);
+	}
+}
+
+static int
+evhttp_is_connection_keepalive(struct evkeyvalq* headers)
+{
+	const char *connection = evhttp_find_header(headers, "Connection");
+	return (connection != NULL 
+	    && strncasecmp(connection, "keep-alive", 10) == 0);
+}
+
+static void
+evhttp_maybe_add_date_header(struct evkeyvalq *headers)
+{
+	if (evhttp_find_header(headers, "Date") == NULL) {
+		char date[50];
+#ifndef WIN32
+		struct tm cur;
+#endif
+		struct tm *cur_p;
+		time_t t = time(NULL);
+#ifdef WIN32
+		cur_p = gmtime(&t);
+#else
+		gmtime_r(&t, &cur);
+		cur_p = &cur;
+#endif
+		if (strftime(date, sizeof(date),
+			"%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
+			evhttp_add_header(headers, "Date", date);
+		}
+	}
+}
+
+static void
+evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
+    long content_length)
+{
+	if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
+	    evhttp_find_header(headers,	"Content-Length") == NULL) {
+		char len[12];
+		evutil_snprintf(len, sizeof(len), "%ld", content_length);
+		evhttp_add_header(headers, "Content-Length", len);
+	}
+}
+
+/*
+ * Create the headers needed for an HTTP reply
+ */
+
+static void
+evhttp_make_header_response(struct evhttp_connection *evcon,
+    struct evhttp_request *req)
+{
+	int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
+	evbuffer_add_printf(evcon->output_buffer, "HTTP/%d.%d %d %s\r\n",
+	    req->major, req->minor, req->response_code,
+	    req->response_code_line);
+
+	if (req->major == 1) {
+		if (req->minor == 1)
+			evhttp_maybe_add_date_header(req->output_headers);
+
+		/*
+		 * if the protocol is 1.0; and the connection was keep-alive
+		 * we need to add a keep-alive header, too.
+		 */
+		if (req->minor == 0 && is_keepalive)
+			evhttp_add_header(req->output_headers,
+			    "Connection", "keep-alive");
+
+		if (req->minor == 1 || is_keepalive) {
+			/* 
+			 * we need to add the content length if the
+			 * user did not give it, this is required for
+			 * persistent connections to work.
+			 */
+			evhttp_maybe_add_content_length_header(
+				req->output_headers,
+				(long)EVBUFFER_LENGTH(req->output_buffer));
+		}
+	}
+
+	/* Potentially add headers for unidentified content. */
+	if (EVBUFFER_LENGTH(req->output_buffer)) {
+		if (evhttp_find_header(req->output_headers,
+			"Content-Type") == NULL) {
+			evhttp_add_header(req->output_headers,
+			    "Content-Type", "text/html; charset=ISO-8859-1");
+		}
+	}
+
+	/* if the request asked for a close, we send a close, too */
+	if (evhttp_is_connection_close(req->flags, req->input_headers)) {
+		evhttp_remove_header(req->output_headers, "Connection");
+		if (!(req->flags & EVHTTP_PROXY_REQUEST))
+		    evhttp_add_header(req->output_headers, "Connection", "close");
+		evhttp_remove_header(req->output_headers, "Proxy-Connection");
+	}
+}
+
+void
+evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	struct evkeyval *header;
+
+	/*
+	 * Depending if this is a HTTP request or response, we might need to
+	 * add some new headers or remove existing headers.
+	 */
+	if (req->kind == EVHTTP_REQUEST) {
+		evhttp_make_header_request(evcon, req);
+	} else {
+		evhttp_make_header_response(evcon, req);
+	}
+
+	TAILQ_FOREACH(header, req->output_headers, next) {
+		evbuffer_add_printf(evcon->output_buffer, "%s: %s\r\n",
+		    header->key, header->value);
+	}
+	evbuffer_add(evcon->output_buffer, "\r\n", 2);
+
+	if (EVBUFFER_LENGTH(req->output_buffer) > 0) {
+		/*
+		 * For a request, we add the POST data, for a reply, this
+		 * is the regular data.
+		 */
+		evbuffer_add_buffer(evcon->output_buffer, req->output_buffer);
+	}
+}
+
+/* Separated host, port and file from URI */
+
+int
+evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
+{
+	/* XXX not threadsafe. */
+	static char host[1024];
+	static char file[1024];
+	char *p;
+	const char *p2;
+	int len;
+	u_short port;
+
+	len = strlen(HTTP_PREFIX);
+	if (strncasecmp(url, HTTP_PREFIX, len))
+		return (-1);
+
+	url += len;
+
+	/* We might overrun */
+	if (strlcpy(host, url, sizeof (host)) >= sizeof(host))
+		return (-1);
+
+	p = strchr(host, '/');
+	if (p != NULL) {
+		*p = '\0';
+		p2 = p + 1;
+	} else
+		p2 = NULL;
+
+	if (pfile != NULL) {
+		/* Generate request file */
+		if (p2 == NULL)
+			p2 = "";
+		evutil_snprintf(file, sizeof(file), "/%s", p2);
+	}
+
+	p = strchr(host, ':');
+	if (p != NULL) {
+		*p = '\0';
+		port = atoi(p + 1);
+
+		if (port == 0)
+			return (-1);
+	} else
+		port = HTTP_DEFAULTPORT;
+
+	if (phost != NULL)
+		*phost = host;
+	if (pport != NULL)
+		*pport = port;
+	if (pfile != NULL)
+		*pfile = file;
+
+	return (0);
+}
+
+static int
+evhttp_connection_incoming_fail(struct evhttp_request *req,
+    enum evhttp_connection_error error)
+{
+	switch (error) {
+	case EVCON_HTTP_TIMEOUT:
+	case EVCON_HTTP_EOF:
+		/* 
+		 * these are cases in which we probably should just
+		 * close the connection and not send a reply.  this
+		 * case may happen when a browser keeps a persistent
+		 * connection open and we timeout on the read.
+		 */
+		return (-1);
+	case EVCON_HTTP_INVALID_HEADER:
+	default:	/* xxx: probably should just error on default */
+		/* the callback looks at the uri to determine errors */
+		if (req->uri) {
+			free(req->uri);
+			req->uri = NULL;
+		}
+
+		/* 
+		 * the callback needs to send a reply, once the reply has
+		 * been send, the connection should get freed.
+		 */
+		(*req->cb)(req, req->cb_arg);
+	}
+	
+	return (0);
+}
+
+void
+evhttp_connection_fail(struct evhttp_connection *evcon,
+    enum evhttp_connection_error error)
+{
+	struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
+	void (*cb)(struct evhttp_request *, void *);
+	void *cb_arg;
+	assert(req != NULL);
+	
+	if (evcon->flags & EVHTTP_CON_INCOMING) {
+		/* 
+		 * for incoming requests, there are two different
+		 * failure cases.  it's either a network level error
+		 * or an http layer error. for problems on the network
+		 * layer like timeouts we just drop the connections.
+		 * For HTTP problems, we might have to send back a
+		 * reply before the connection can be freed.
+		 */
+		if (evhttp_connection_incoming_fail(req, error) == -1)
+			evhttp_connection_free(evcon);
+		return;
+	}
+
+	/* save the callback for later; the cb might free our object */
+	cb = req->cb;
+	cb_arg = req->cb_arg;
+
+	TAILQ_REMOVE(&evcon->requests, req, next);
+	evhttp_request_free(req);
+
+	/* xxx: maybe we should fail all requests??? */
+
+	/* reset the connection */
+	evhttp_connection_reset(evcon);
+	
+	/* We are trying the next request that was queued on us */
+	if (TAILQ_FIRST(&evcon->requests) != NULL)
+		evhttp_connection_connect(evcon);
+
+	/* inform the user */
+	if (cb != NULL)
+		(*cb)(NULL, cb_arg);
+}
+
+void
+evhttp_write(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	int n;
+
+	if (what == EV_TIMEOUT) {
+		evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+		return;
+	}
+
+	n = evbuffer_write(evcon->output_buffer, fd);
+	if (n == -1) {
+		event_debug(("%s: evbuffer_write", __func__));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	}
+
+	if (n == 0) {
+		event_debug(("%s: write nothing", __func__));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	}
+
+	if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
+		evhttp_add_event(&evcon->ev, 
+		    evcon->timeout, HTTP_WRITE_TIMEOUT);
+		return;
+	}
+
+	/* Activate our call back */
+	if (evcon->cb != NULL)
+		(*evcon->cb)(evcon, evcon->cb_arg);
+}
+
+/**
+ * Advance the connection state.
+ * - If this is an outgoing connection, we've just processed the response;
+ *   idle or close the connection.
+ * - If this is an incoming connection, we've just processed the request;
+ *   respond.
+ */
+static void
+evhttp_connection_done(struct evhttp_connection *evcon)
+{
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
+
+	if (con_outgoing) {
+		/* idle or close the connection */
+	        int need_close;
+		TAILQ_REMOVE(&evcon->requests, req, next);
+		req->evcon = NULL;
+
+		evcon->state = EVCON_IDLE;
+
+		need_close = 
+		    evhttp_is_connection_close(req->flags, req->input_headers)||
+		    evhttp_is_connection_close(req->flags, req->output_headers);
+
+		/* check if we got asked to close the connection */
+		if (need_close)
+			evhttp_connection_reset(evcon);
+
+		if (TAILQ_FIRST(&evcon->requests) != NULL) {
+			/*
+			 * We have more requests; reset the connection
+			 * and deal with the next request.
+			 */
+			if (!evhttp_connected(evcon))
+				evhttp_connection_connect(evcon);
+			else
+				evhttp_request_dispatch(evcon);
+		} else if (!need_close) {
+			/*
+			 * The connection is going to be persistent, but we
+			 * need to detect if the other side closes it.
+			 */
+			evhttp_connection_start_detectclose(evcon);
+		}
+	} else {
+		/*
+		 * incoming connection - we need to leave the request on the
+		 * connection so that we can reply to it.
+		 */
+		evcon->state = EVCON_WRITING;
+	}
+
+	/* notify the user of the request */
+	(*req->cb)(req, req->cb_arg);
+
+	/* if this was an outgoing request, we own and it's done. so free it */
+	if (con_outgoing) {
+		evhttp_request_free(req);
+	}
+}
+
+/*
+ * Handles reading from a chunked request.
+ *   return ALL_DATA_READ:
+ *     all data has been read
+ *   return MORE_DATA_EXPECTED:
+ *     more data is expected
+ *   return DATA_CORRUPTED:
+ *     data is corrupted
+ *   return REQUEST_CANCLED:
+ *     request was canceled by the user calling evhttp_cancel_request
+ */
+
+static enum message_read_status
+evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
+{
+	int len;
+
+	while ((len = EVBUFFER_LENGTH(buf)) > 0) {
+		if (req->ntoread < 0) {
+			/* Read chunk size */
+			ev_int64_t ntoread;
+			char *p = evbuffer_readline(buf);
+			char *endp;
+			int error;
+			if (p == NULL)
+				break;
+			/* the last chunk is on a new line? */
+			if (strlen(p) == 0) {
+				free(p);
+				continue;
+			}
+			ntoread = evutil_strtoll(p, &endp, 16);
+			error = (*p == '\0' ||
+			    (*endp != '\0' && *endp != ' ') ||
+			    ntoread < 0);
+			free(p);
+			if (error) {
+				/* could not get chunk size */
+				return (DATA_CORRUPTED);
+			}
+			req->ntoread = ntoread;
+			if (req->ntoread == 0) {
+				/* Last chunk */
+				return (ALL_DATA_READ);
+			}
+			continue;
+		}
+
+		/* don't have enough to complete a chunk; wait for more */
+		if (len < req->ntoread)
+			return (MORE_DATA_EXPECTED);
+
+		/* Completed chunk */
+		evbuffer_add(req->input_buffer,
+		    EVBUFFER_DATA(buf), (size_t)req->ntoread);
+		evbuffer_drain(buf, (size_t)req->ntoread);
+		req->ntoread = -1;
+		if (req->chunk_cb != NULL) {
+			(*req->chunk_cb)(req, req->cb_arg);
+			evbuffer_drain(req->input_buffer,
+			    EVBUFFER_LENGTH(req->input_buffer));
+		}
+	}
+
+	return (MORE_DATA_EXPECTED);
+}
+
+static void
+evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	struct evbuffer *buf = evcon->input_buffer;
+
+	switch (evhttp_parse_headers(req, buf)) {
+	case DATA_CORRUPTED:
+		evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+		break;
+	case ALL_DATA_READ:
+		event_del(&evcon->ev);
+		evhttp_connection_done(evcon);
+		break;
+	case MORE_DATA_EXPECTED:
+	default:
+		evhttp_add_event(&evcon->ev, evcon->timeout,
+		    HTTP_READ_TIMEOUT);
+		break;
+	}
+}
+
+static void
+evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	struct evbuffer *buf = evcon->input_buffer;
+	
+	if (req->chunked) {
+		switch (evhttp_handle_chunked_read(req, buf)) {
+		case ALL_DATA_READ:
+			/* finished last chunk */
+			evcon->state = EVCON_READING_TRAILER;
+			evhttp_read_trailer(evcon, req);
+			return;
+		case DATA_CORRUPTED:
+			/* corrupted data */
+			evhttp_connection_fail(evcon,
+			    EVCON_HTTP_INVALID_HEADER);
+			return;
+		case REQUEST_CANCELED:
+			/* request canceled */
+			evhttp_request_free(req);
+			return;
+		case MORE_DATA_EXPECTED:
+		default:
+			break;
+		}
+	} else if (req->ntoread < 0) {
+		/* Read until connection close. */
+		evbuffer_add_buffer(req->input_buffer, buf);
+	} else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
+		/* Completed content length */
+		evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
+		    (size_t)req->ntoread);
+		evbuffer_drain(buf, (size_t)req->ntoread);
+		req->ntoread = 0;
+		evhttp_connection_done(evcon);
+		return;
+	}
+	/* Read more! */
+	event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
+}
+
+/*
+ * Reads data into a buffer structure until no more data
+ * can be read on the file descriptor or we have read all
+ * the data that we wanted to read.
+ * Execute callback when done.
+ */
+
+void
+evhttp_read(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	struct evbuffer *buf = evcon->input_buffer;
+	int n, len;
+
+	if (what == EV_TIMEOUT) {
+		evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+		return;
+	}
+	n = evbuffer_read(buf, fd, -1);
+	len = EVBUFFER_LENGTH(buf);
+	event_debug(("%s: got %d on %d\n", __func__, n, fd));
+	
+	if (n == -1) {
+		if (errno != EINTR && errno != EAGAIN) {
+			event_debug(("%s: evbuffer_read", __func__));
+			evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		} else {
+			evhttp_add_event(&evcon->ev, evcon->timeout,
+			    HTTP_READ_TIMEOUT);	       
+		}
+		return;
+	} else if (n == 0) {
+		/* Connection closed */
+		evhttp_connection_done(evcon);
+		return;
+	}
+
+	switch (evcon->state) {
+	case EVCON_READING_FIRSTLINE:
+		evhttp_read_firstline(evcon, req);
+		break;
+	case EVCON_READING_HEADERS:
+		evhttp_read_header(evcon, req);
+		break;
+	case EVCON_READING_BODY:
+		evhttp_read_body(evcon, req);
+		break;
+	case EVCON_READING_TRAILER:
+		evhttp_read_trailer(evcon, req);
+		break;
+	case EVCON_DISCONNECTED:
+	case EVCON_CONNECTING:
+	case EVCON_IDLE:
+	case EVCON_WRITING:
+	default:
+		event_errx(1, "%s: illegal connection state %d",
+			   __func__, evcon->state);
+	}
+}
+
+static void
+evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
+{
+	/* This is after writing the request to the server */
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	assert(req != NULL);
+
+	assert(evcon->state == EVCON_WRITING);
+
+	/* We are done writing our header and are now expecting the response */
+	req->kind = EVHTTP_RESPONSE;
+
+	evhttp_start_read(evcon);
+}
+
+/*
+ * Clean up a connection object
+ */
+
+void
+evhttp_connection_free(struct evhttp_connection *evcon)
+{
+	struct evhttp_request *req;
+
+	/* notify interested parties that this connection is going down */
+	if (evcon->fd != -1) {
+		if (evhttp_connected(evcon) && evcon->closecb != NULL)
+			(*evcon->closecb)(evcon, evcon->closecb_arg);
+	}
+
+	/* remove all requests that might be queued on this connection */
+	while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
+		TAILQ_REMOVE(&evcon->requests, req, next);
+		evhttp_request_free(req);
+	}
+
+	if (evcon->http_server != NULL) {
+		struct evhttp *http = evcon->http_server;
+		TAILQ_REMOVE(&http->connections, evcon, next);
+	}
+
+	if (event_initialized(&evcon->close_ev))
+		event_del(&evcon->close_ev);
+
+	if (event_initialized(&evcon->ev))
+		event_del(&evcon->ev);
+	
+	if (evcon->fd != -1)
+		EVUTIL_CLOSESOCKET(evcon->fd);
+
+	if (evcon->bind_address != NULL)
+		free(evcon->bind_address);
+
+	if (evcon->address != NULL)
+		free(evcon->address);
+
+	if (evcon->input_buffer != NULL)
+		evbuffer_free(evcon->input_buffer);
+
+	if (evcon->output_buffer != NULL)
+		evbuffer_free(evcon->output_buffer);
+
+	free(evcon);
+}
+
+void
+evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+    const char *address)
+{
+	assert(evcon->state == EVCON_DISCONNECTED);
+	if (evcon->bind_address)
+		free(evcon->bind_address);
+	if ((evcon->bind_address = strdup(address)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+}
+
+void
+evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+    unsigned short port)
+{
+	assert(evcon->state == EVCON_DISCONNECTED);
+	evcon->bind_port = port;
+}
+
+static void
+evhttp_request_dispatch(struct evhttp_connection* evcon)
+{
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	
+	/* this should not usually happy but it's possible */
+	if (req == NULL)
+		return;
+
+	/* delete possible close detection events */
+	evhttp_connection_stop_detectclose(evcon);
+	
+	/* we assume that the connection is connected already */
+	assert(evcon->state == EVCON_IDLE);
+
+	evcon->state = EVCON_WRITING;
+
+	/* Create the header from the store arguments */
+	evhttp_make_header(evcon, req);
+
+	evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
+}
+
+/* Reset our connection state */
+void
+evhttp_connection_reset(struct evhttp_connection *evcon)
+{
+	if (event_initialized(&evcon->ev))
+		event_del(&evcon->ev);
+
+	if (evcon->fd != -1) {
+		/* inform interested parties about connection close */
+		if (evhttp_connected(evcon) && evcon->closecb != NULL)
+			(*evcon->closecb)(evcon, evcon->closecb_arg);
+
+		EVUTIL_CLOSESOCKET(evcon->fd);
+		evcon->fd = -1;
+	}
+	evcon->state = EVCON_DISCONNECTED;
+
+	evbuffer_drain(evcon->input_buffer,
+	    EVBUFFER_LENGTH(evcon->input_buffer));
+	evbuffer_drain(evcon->output_buffer,
+	    EVBUFFER_LENGTH(evcon->output_buffer));
+}
+
+static void
+evhttp_detect_close_cb(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	evhttp_connection_reset(evcon);
+}
+
+static void
+evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
+{
+	evcon->flags |= EVHTTP_CON_CLOSEDETECT;
+
+	if (event_initialized(&evcon->close_ev))
+		event_del(&evcon->close_ev);
+	event_set(&evcon->close_ev, evcon->fd, EV_READ,
+	    evhttp_detect_close_cb, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->close_ev);
+	event_add(&evcon->close_ev, NULL);
+}
+
+static void
+evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
+{
+	evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+	event_del(&evcon->close_ev);
+}
+
+static void
+evhttp_connection_retry(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+
+	evcon->state = EVCON_DISCONNECTED;
+	evhttp_connection_connect(evcon);
+}
+
+/*
+ * Call back for asynchronous connection attempt.
+ */
+
+static void
+evhttp_connectioncb(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	int error;
+	socklen_t errsz = sizeof(error);
+		
+	if (what == EV_TIMEOUT) {
+		event_debug(("%s: connection timeout for \"%s:%d\" on %d",
+			__func__, evcon->address, evcon->port, evcon->fd));
+		goto cleanup;
+	}
+
+	/* Check if the connection completed */
+	if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+		       &errsz) == -1) {
+		event_debug(("%s: getsockopt for \"%s:%d\" on %d",
+			__func__, evcon->address, evcon->port, evcon->fd));
+		goto cleanup;
+	}
+
+	if (error) {
+		event_debug(("%s: connect failed for \"%s:%d\" on %d: %s",
+		    __func__, evcon->address, evcon->port, evcon->fd,
+			strerror(error)));
+		goto cleanup;
+	}
+
+	/* We are connected to the server now */
+	event_debug(("%s: connected to \"%s:%d\" on %d\n",
+			__func__, evcon->address, evcon->port, evcon->fd));
+
+	/* Reset the retry count as we were successful in connecting */
+	evcon->retry_cnt = 0;
+	evcon->state = EVCON_IDLE;
+
+	/* try to start requests that have queued up on this connection */
+	evhttp_request_dispatch(evcon);
+	return;
+
+ cleanup:
+	if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
+		evtimer_set(&evcon->ev, evhttp_connection_retry, evcon);
+		EVHTTP_BASE_SET(evcon, &evcon->ev);
+		evhttp_add_event(&evcon->ev, MIN(3600, 2 << evcon->retry_cnt),
+		    HTTP_CONNECT_TIMEOUT);
+		evcon->retry_cnt++;
+		return;
+	}
+	evhttp_connection_reset(evcon);
+
+	/* for now, we just signal all requests by executing their callbacks */
+	while (TAILQ_FIRST(&evcon->requests) != NULL) {
+		struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
+		TAILQ_REMOVE(&evcon->requests, request, next);
+		request->evcon = NULL;
+
+		/* we might want to set an error here */
+		request->cb(request, request->cb_arg);
+		evhttp_request_free(request);
+	}
+}
+
+/*
+ * Check if we got a valid response code.
+ */
+
+static int
+evhttp_valid_response_code(int code)
+{
+	if (code == 0)
+		return (0);
+
+	return (1);
+}
+
+/* Parses the status line of a web server */
+
+static int
+evhttp_parse_response_line(struct evhttp_request *req, char *line)
+{
+	char *protocol;
+	char *number;
+	char *readable;
+
+	protocol = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	number = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	readable = line;
+
+	if (strcmp(protocol, "HTTP/1.0") == 0) {
+		req->major = 1;
+		req->minor = 0;
+	} else if (strcmp(protocol, "HTTP/1.1") == 0) {
+		req->major = 1;
+		req->minor = 1;
+	} else {
+		event_debug(("%s: bad protocol \"%s\"",
+			__func__, protocol));
+		return (-1);
+	}
+
+	req->response_code = atoi(number);
+	if (!evhttp_valid_response_code(req->response_code)) {
+		event_debug(("%s: bad response code \"%s\"",
+			__func__, number));
+		return (-1);
+	}
+
+	if ((req->response_code_line = strdup(readable)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+
+	return (0);
+}
+
+/* Parse the first line of a HTTP request */
+
+static int
+evhttp_parse_request_line(struct evhttp_request *req, char *line)
+{
+	char *method;
+	char *uri;
+	char *version;
+
+	/* Parse the request line */
+	method = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	uri = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	version = strsep(&line, " ");
+	if (line != NULL)
+		return (-1);
+
+	/* First line */
+	if (strcmp(method, "GET") == 0) {
+		req->type = EVHTTP_REQ_GET;
+	} else if (strcmp(method, "POST") == 0) {
+		req->type = EVHTTP_REQ_POST;
+	} else if (strcmp(method, "HEAD") == 0) {
+		req->type = EVHTTP_REQ_HEAD;
+	} else {
+		event_debug(("%s: bad method %s on request %p from %s",
+			__func__, method, req, req->remote_host));
+		return (-1);
+	}
+
+	if (strcmp(version, "HTTP/1.0") == 0) {
+		req->major = 1;
+		req->minor = 0;
+	} else if (strcmp(version, "HTTP/1.1") == 0) {
+		req->major = 1;
+		req->minor = 1;
+	} else {
+		event_debug(("%s: bad version %s on request %p from %s",
+			__func__, version, req, req->remote_host));
+		return (-1);
+	}
+
+	if ((req->uri = strdup(uri)) == NULL) {
+		event_debug(("%s: evhttp_decode_uri", __func__));
+		return (-1);
+	}
+
+	/* determine if it's a proxy request */
+	if (strlen(req->uri) > 0 && req->uri[0] != '/')
+		req->flags |= EVHTTP_PROXY_REQUEST;
+
+	return (0);
+}
+
+const char *
+evhttp_find_header(const struct evkeyvalq *headers, const char *key)
+{
+	struct evkeyval *header;
+
+	TAILQ_FOREACH(header, headers, next) {
+		if (strcasecmp(header->key, key) == 0)
+			return (header->value);
+	}
+
+	return (NULL);
+}
+
+void
+evhttp_clear_headers(struct evkeyvalq *headers)
+{
+	struct evkeyval *header;
+
+	for (header = TAILQ_FIRST(headers);
+	    header != NULL;
+	    header = TAILQ_FIRST(headers)) {
+		TAILQ_REMOVE(headers, header, next);
+		free(header->key);
+		free(header->value);
+		free(header);
+	}
+}
+
+/*
+ * Returns 0,  if the header was successfully removed.
+ * Returns -1, if the header could not be found.
+ */
+
+int
+evhttp_remove_header(struct evkeyvalq *headers, const char *key)
+{
+	struct evkeyval *header;
+
+	TAILQ_FOREACH(header, headers, next) {
+		if (strcasecmp(header->key, key) == 0)
+			break;
+	}
+
+	if (header == NULL)
+		return (-1);
+
+	/* Free and remove the header that we found */
+	TAILQ_REMOVE(headers, header, next);
+	free(header->key);
+	free(header->value);
+	free(header);
+
+	return (0);
+}
+
+static int
+evhttp_header_is_valid_value(const char *value)
+{
+	const char *p = value;
+
+	while ((p = strpbrk(p, "\r\n")) != NULL) {
+		/* we really expect only one new line */
+		p += strspn(p, "\r\n");
+		/* we expect a space or tab for continuation */
+		if (*p != ' ' && *p != '\t')
+			return (0);
+	}
+	return (1);
+}
+
+int
+evhttp_add_header(struct evkeyvalq *headers,
+    const char *key, const char *value)
+{
+	event_debug(("%s: key: %s val: %s\n", __func__, key, value));
+
+	if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+		/* drop illegal headers */
+		event_debug(("%s: dropping illegal header key\n", __func__));
+		return (-1);
+	}
+	
+	if (!evhttp_header_is_valid_value(value)) {
+		event_debug(("%s: dropping illegal header value\n", __func__));
+		return (-1);
+	}
+
+	return (evhttp_add_header_internal(headers, key, value));
+}
+
+static int
+evhttp_add_header_internal(struct evkeyvalq *headers,
+    const char *key, const char *value)
+{
+	struct evkeyval *header = calloc(1, sizeof(struct evkeyval));
+	if (header == NULL) {
+		event_warn("%s: calloc", __func__);
+		return (-1);
+	}
+	if ((header->key = strdup(key)) == NULL) {
+		free(header);
+		event_warn("%s: strdup", __func__);
+		return (-1);
+	}
+	if ((header->value = strdup(value)) == NULL) {
+		free(header->key);
+		free(header);
+		event_warn("%s: strdup", __func__);
+		return (-1);
+	}
+
+	TAILQ_INSERT_TAIL(headers, header, next);
+
+	return (0);
+}
+
+/*
+ * Parses header lines from a request or a response into the specified
+ * request object given an event buffer.
+ *
+ * Returns
+ *   DATA_CORRUPTED      on error
+ *   MORE_DATA_EXPECTED  when we need to read more headers
+ *   ALL_DATA_READ       when all headers have been read.
+ */
+
+enum message_read_status
+evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer)
+{
+	char *line;
+	enum message_read_status status = ALL_DATA_READ;
+
+	line = evbuffer_readline(buffer);
+	if (line == NULL)
+		return (MORE_DATA_EXPECTED);
+
+	switch (req->kind) {
+	case EVHTTP_REQUEST:
+		if (evhttp_parse_request_line(req, line) == -1)
+			status = DATA_CORRUPTED;
+		break;
+	case EVHTTP_RESPONSE:
+		if (evhttp_parse_response_line(req, line) == -1)
+			status = DATA_CORRUPTED;
+		break;
+	default:
+		status = DATA_CORRUPTED;
+	}
+
+	free(line);
+	return (status);
+}
+
+static int
+evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line)
+{
+	struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
+	char *newval;
+	size_t old_len, line_len;
+
+	if (header == NULL)
+		return (-1);
+
+	old_len = strlen(header->value);
+	line_len = strlen(line);
+
+	newval = realloc(header->value, old_len + line_len + 1);
+	if (newval == NULL)
+		return (-1);
+
+	memcpy(newval + old_len, line, line_len + 1);
+	header->value = newval;
+
+	return (0);
+}
+
+enum message_read_status
+evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
+{
+	char *line;
+	enum message_read_status status = MORE_DATA_EXPECTED;
+
+	struct evkeyvalq* headers = req->input_headers;
+	while ((line = evbuffer_readline(buffer))
+	       != NULL) {
+		char *skey, *svalue;
+
+		if (*line == '\0') { /* Last header - Done */
+			status = ALL_DATA_READ;
+			free(line);
+			break;
+		}
+
+		/* Check if this is a continuation line */
+		if (*line == ' ' || *line == '\t') {
+			if (evhttp_append_to_last_header(headers, line) == -1)
+				goto error;
+			free(line);
+			continue;
+		}
+
+		/* Processing of header lines */
+		svalue = line;
+		skey = strsep(&svalue, ":");
+		if (svalue == NULL)
+			goto error;
+
+		svalue += strspn(svalue, " ");
+
+		if (evhttp_add_header(headers, skey, svalue) == -1)
+			goto error;
+
+		free(line);
+	}
+
+	return (status);
+
+ error:
+	free(line);
+	return (DATA_CORRUPTED);
+}
+
+static int
+evhttp_get_body_length(struct evhttp_request *req)
+{
+	struct evkeyvalq *headers = req->input_headers;
+	const char *content_length;
+	const char *connection;
+
+	content_length = evhttp_find_header(headers, "Content-Length");
+	connection = evhttp_find_header(headers, "Connection");
+		
+	if (content_length == NULL && connection == NULL)
+		req->ntoread = -1;
+	else if (content_length == NULL &&
+	    strcasecmp(connection, "Close") != 0) {
+		/* Bad combination, we don't know when it will end */
+		event_warnx("%s: we got no content length, but the "
+		    "server wants to keep the connection open: %s.",
+		    __func__, connection);
+		return (-1);
+	} else if (content_length == NULL) {
+		req->ntoread = -1;
+	} else {
+		char *endp;
+		ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
+		if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
+			event_debug(("%s: illegal content length: %s",
+				__func__, content_length));
+			return (-1);
+		}
+		req->ntoread = ntoread;
+	}
+		
+	event_debug(("%s: bytes to read: %lld (in buffer %ld)\n",
+		__func__, req->ntoread,
+		EVBUFFER_LENGTH(req->evcon->input_buffer)));
+
+	return (0);
+}
+
+static void
+evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	const char *xfer_enc;
+	
+	/* If this is a request without a body, then we are done */
+	if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
+		evhttp_connection_done(evcon);
+		return;
+	}
+	evcon->state = EVCON_READING_BODY;
+	xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
+	if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) {
+		req->chunked = 1;
+		req->ntoread = -1;
+	} else {
+		if (evhttp_get_body_length(req) == -1) {
+			evhttp_connection_fail(evcon,
+			    EVCON_HTTP_INVALID_HEADER);
+			return;
+		}
+	}
+	evhttp_read_body(evcon, req);
+}
+
+static void
+evhttp_read_firstline(struct evhttp_connection *evcon,
+		      struct evhttp_request *req)
+{
+	enum message_read_status res;
+
+	res = evhttp_parse_firstline(req, evcon->input_buffer);
+	if (res == DATA_CORRUPTED) {
+		/* Error while reading, terminate */
+		event_debug(("%s: bad header lines on %d\n",
+			__func__, evcon->fd));
+		evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+		return;
+	} else if (res == MORE_DATA_EXPECTED) {
+		/* Need more header lines */
+		evhttp_add_event(&evcon->ev, 
+                    evcon->timeout, HTTP_READ_TIMEOUT);
+		return;
+	}
+
+	evcon->state = EVCON_READING_HEADERS;
+	evhttp_read_header(evcon, req);
+}
+
+static void
+evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	enum message_read_status res;
+	int fd = evcon->fd;
+
+	res = evhttp_parse_headers(req, evcon->input_buffer);
+	if (res == DATA_CORRUPTED) {
+		/* Error while reading, terminate */
+		event_debug(("%s: bad header lines on %d\n", __func__, fd));
+		evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+		return;
+	} else if (res == MORE_DATA_EXPECTED) {
+		/* Need more header lines */
+		evhttp_add_event(&evcon->ev, 
+		    evcon->timeout, HTTP_READ_TIMEOUT);
+		return;
+	}
+
+	/* Done reading headers, do the real work */
+	switch (req->kind) {
+	case EVHTTP_REQUEST:
+		event_debug(("%s: checking for post data on %d\n",
+				__func__, fd));
+		evhttp_get_body(evcon, req);
+		break;
+
+	case EVHTTP_RESPONSE:
+		if (req->response_code == HTTP_NOCONTENT ||
+		    req->response_code == HTTP_NOTMODIFIED ||
+		    (req->response_code >= 100 && req->response_code < 200)) {
+			event_debug(("%s: skipping body for code %d\n",
+					__func__, req->response_code));
+			evhttp_connection_done(evcon);
+		} else {
+			event_debug(("%s: start of read body for %s on %d\n",
+				__func__, req->remote_host, fd));
+			evhttp_get_body(evcon, req);
+		}
+		break;
+
+	default:
+		event_warnx("%s: bad header on %d", __func__, fd);
+		evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+		break;
+	}
+}
+
+/*
+ * Creates a TCP connection to the specified port and executes a callback
+ * when finished.  Failure or sucess is indicate by the passed connection
+ * object.
+ *
+ * Although this interface accepts a hostname, it is intended to take
+ * only numeric hostnames so that non-blocking DNS resolution can
+ * happen elsewhere.
+ */
+
+struct evhttp_connection *
+evhttp_connection_new(const char *address, unsigned short port)
+{
+	struct evhttp_connection *evcon = NULL;
+	
+	event_debug(("Attempting connection to %s:%d\n", address, port));
+
+	if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) {
+		event_warn("%s: calloc failed", __func__);
+		goto error;
+	}
+
+	evcon->fd = -1;
+	evcon->port = port;
+
+	evcon->timeout = -1;
+	evcon->retry_cnt = evcon->retry_max = 0;
+
+	if ((evcon->address = strdup(address)) == NULL) {
+		event_warn("%s: strdup failed", __func__);
+		goto error;
+	}
+
+	if ((evcon->input_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new failed", __func__);
+		goto error;
+	}
+
+	if ((evcon->output_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new failed", __func__);
+		goto error;
+	}
+	
+	evcon->state = EVCON_DISCONNECTED;
+	TAILQ_INIT(&evcon->requests);
+
+	return (evcon);
+	
+ error:
+	if (evcon != NULL)
+		evhttp_connection_free(evcon);
+	return (NULL);
+}
+
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+    struct event_base *base)
+{
+	assert(evcon->base == NULL);
+	assert(evcon->state == EVCON_DISCONNECTED);
+	evcon->base = base;
+}
+
+void
+evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+    int timeout_in_secs)
+{
+	evcon->timeout = timeout_in_secs;
+}
+
+void
+evhttp_connection_set_retries(struct evhttp_connection *evcon,
+    int retry_max)
+{
+	evcon->retry_max = retry_max;
+}
+
+void
+evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+    void (*cb)(struct evhttp_connection *, void *), void *cbarg)
+{
+	evcon->closecb = cb;
+	evcon->closecb_arg = cbarg;
+}
+
+void
+evhttp_connection_get_peer(struct evhttp_connection *evcon,
+    char **address, u_short *port)
+{
+	*address = evcon->address;
+	*port = evcon->port;
+}
+
+int
+evhttp_connection_connect(struct evhttp_connection *evcon)
+{
+	if (evcon->state == EVCON_CONNECTING)
+		return (0);
+	
+	evhttp_connection_reset(evcon);
+
+	assert(!(evcon->flags & EVHTTP_CON_INCOMING));
+	evcon->flags |= EVHTTP_CON_OUTGOING;
+	
+	evcon->fd = bind_socket(
+		evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
+	if (evcon->fd == -1) {
+		event_debug(("%s: failed to bind to \"%s\"",
+			__func__, evcon->bind_address));
+		return (-1);
+	}
+
+	if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) {
+		EVUTIL_CLOSESOCKET(evcon->fd); evcon->fd = -1;
+		return (-1);
+	}
+
+	/* Set up a callback for successful connection setup */
+	event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_CONNECT_TIMEOUT);
+
+	evcon->state = EVCON_CONNECTING;
+	
+	return (0);
+}
+
+/*
+ * Starts an HTTP request on the provided evhttp_connection object.
+ * If the connection object is not connected to the web server already,
+ * this will start the connection.
+ */
+
+int
+evhttp_make_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req,
+    enum evhttp_cmd_type type, const char *uri)
+{
+	/* We are making a request */
+	req->kind = EVHTTP_REQUEST;
+	req->type = type;
+	if (req->uri != NULL)
+		free(req->uri);
+	if ((req->uri = strdup(uri)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+
+	/* Set the protocol version if it is not supplied */
+	if (!req->major && !req->minor) {
+		req->major = 1;
+		req->minor = 1;
+	}
+	
+	assert(req->evcon == NULL);
+	req->evcon = evcon;
+	assert(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
+	
+	TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+
+	/* If the connection object is not connected; make it so */
+	if (!evhttp_connected(evcon))
+		return (evhttp_connection_connect(evcon));
+
+	/*
+	 * If it's connected already and we are the first in the queue,
+	 * then we can dispatch this request immediately.  Otherwise, it
+	 * will be dispatched once the pending requests are completed.
+	 */
+	if (TAILQ_FIRST(&evcon->requests) == req)
+		evhttp_request_dispatch(evcon);
+
+	return (0);
+}
+
+/*
+ * Reads data from file descriptor into request structure
+ * Request structure needs to be set up correctly.
+ */
+
+void
+evhttp_start_read(struct evhttp_connection *evcon)
+{
+	/* Set up an event to read the headers */
+	if (event_initialized(&evcon->ev))
+		event_del(&evcon->ev);
+	event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
+	evcon->state = EVCON_READING_FIRSTLINE;
+}
+
+static void
+evhttp_send_done(struct evhttp_connection *evcon, void *arg)
+{
+	int need_close;
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	TAILQ_REMOVE(&evcon->requests, req, next);
+
+	/* delete possible close detection events */
+	evhttp_connection_stop_detectclose(evcon);
+	
+	need_close =
+	    (req->minor == 0 &&
+		!evhttp_is_connection_keepalive(req->input_headers))||
+	    evhttp_is_connection_close(req->flags, req->input_headers) ||
+	    evhttp_is_connection_close(req->flags, req->output_headers);
+
+	assert(req->flags & EVHTTP_REQ_OWN_CONNECTION);
+	evhttp_request_free(req);
+
+	if (need_close) {
+		evhttp_connection_free(evcon);
+		return;
+	} 
+
+	/* we have a persistent connection; try to accept another request. */
+	if (evhttp_associate_new_request_with_connection(evcon) == -1)
+		evhttp_connection_free(evcon);
+}
+
+/*
+ * Returns an error page.
+ */
+
+void
+evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
+{
+#define ERR_FORMAT "<HTML><HEAD>\n" \
+	    "<TITLE>%d %s</TITLE>\n" \
+	    "</HEAD><BODY>\n" \
+	    "<H1>Method Not Implemented</H1>\n" \
+	    "Invalid method in request<P>\n" \
+	    "</BODY></HTML>\n"
+
+	struct evbuffer *buf = evbuffer_new();
+
+	/* close the connection on error */
+	evhttp_add_header(req->output_headers, "Connection", "close");
+
+	evhttp_response_code(req, error, reason);
+
+	evbuffer_add_printf(buf, ERR_FORMAT, error, reason);
+
+	evhttp_send_page(req, buf);
+
+	evbuffer_free(buf);
+#undef ERR_FORMAT
+}
+
+/* Requires that headers and response code are already set up */
+
+static inline void
+evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	struct evhttp_connection *evcon = req->evcon;
+
+	assert(TAILQ_FIRST(&evcon->requests) == req);
+
+	/* xxx: not sure if we really should expose the data buffer this way */
+	if (databuf != NULL)
+		evbuffer_add_buffer(req->output_buffer, databuf);
+	
+	/* Adds headers to the response */
+	evhttp_make_header(evcon, req);
+
+	evhttp_write_buffer(evcon, evhttp_send_done, NULL);
+}
+
+void
+evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
+    struct evbuffer *databuf)
+{
+	evhttp_response_code(req, code, reason);
+	
+	evhttp_send(req, databuf);
+}
+
+void
+evhttp_send_reply_start(struct evhttp_request *req, int code,
+    const char *reason)
+{
+	evhttp_response_code(req, code, reason);
+	if (req->major == 1 && req->minor == 1) {
+		/* use chunked encoding for HTTP/1.1 */
+		evhttp_add_header(req->output_headers, "Transfer-Encoding",
+		    "chunked");
+		req->chunked = 1;
+	}
+	evhttp_make_header(req->evcon, req);
+	evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	if (req->chunked) {
+		evbuffer_add_printf(req->evcon->output_buffer, "%x\r\n",
+				    (unsigned)EVBUFFER_LENGTH(databuf));
+	}
+	evbuffer_add_buffer(req->evcon->output_buffer, databuf);
+	if (req->chunked) {
+		evbuffer_add(req->evcon->output_buffer, "\r\n", 2);
+	}
+	evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_end(struct evhttp_request *req)
+{
+	struct evhttp_connection *evcon = req->evcon;
+
+	if (req->chunked) {
+		evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
+		evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
+		req->chunked = 0;
+	} else if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) {
+		/* let the connection know that we are done with the request */
+		evhttp_send_done(evcon, NULL);
+	} else {
+		/* make the callback execute after all data has been written */
+		evcon->cb = evhttp_send_done;
+		evcon->cb_arg = NULL;
+	}
+}
+
+void
+evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
+{
+	req->kind = EVHTTP_RESPONSE;
+	req->response_code = code;
+	if (req->response_code_line != NULL)
+		free(req->response_code_line);
+	req->response_code_line = strdup(reason);
+}
+
+void
+evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	if (!req->major || !req->minor) {
+		req->major = 1;
+		req->minor = 1;
+	}
+	
+	if (req->kind != EVHTTP_RESPONSE)
+		evhttp_response_code(req, 200, "OK");
+
+	evhttp_clear_headers(req->output_headers);
+	evhttp_add_header(req->output_headers, "Content-Type", "text/html");
+	evhttp_add_header(req->output_headers, "Connection", "close");
+
+	evhttp_send(req, databuf);
+}
+
+static const char uri_chars[256] = {
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 1, 0, 0, 1, 0, 0, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 1, 0, 0,
+	/* 64 */
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,
+	0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,
+	/* 128 */
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	/* 192 */
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/*
+ * Helper functions to encode/decode a URI.
+ * The returned string must be freed by the caller.
+ */
+char *
+evhttp_encode_uri(const char *uri)
+{
+	struct evbuffer *buf = evbuffer_new();
+	char *p;
+
+	for (p = (char *)uri; *p != '\0'; p++) {
+		if (uri_chars[(u_char)(*p)]) {
+			evbuffer_add(buf, p, 1);
+		} else {
+			evbuffer_add_printf(buf, "%%%02X", (u_char)(*p));
+		}
+	}
+	evbuffer_add(buf, "", 1);
+	p = strdup((char *)EVBUFFER_DATA(buf));
+	evbuffer_free(buf);
+	
+	return (p);
+}
+
+/*
+ * @param always_decode_plus: when true we transform plus to space even
+ *     if we have not seen a ?.
+ */
+static int
+evhttp_decode_uri_internal(
+	const char *uri, size_t length, char *ret, int always_decode_plus)
+{
+	char c;
+	int i, j, in_query = always_decode_plus;
+	
+	for (i = j = 0; uri[i] != '\0'; i++) {
+		c = uri[i];
+		if (c == '?') {
+			in_query = 1;
+		} else if (c == '+' && in_query) {
+			c = ' ';
+		} else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
+		    isxdigit((unsigned char)uri[i+2])) {
+			char tmp[] = { uri[i+1], uri[i+2], '\0' };
+			c = (char)strtol(tmp, NULL, 16);
+			i += 2;
+		}
+		ret[j++] = c;
+	}
+	ret[j] = '\0';
+
+	return (j);
+}
+
+char *
+evhttp_decode_uri(const char *uri)
+{
+	char *ret;
+
+	if ((ret = malloc(strlen(uri) + 1)) == NULL)
+		event_err(1, "%s: malloc(%lu)", __func__,
+			  (unsigned long)(strlen(uri) + 1));
+
+	evhttp_decode_uri_internal(uri, strlen(uri),
+	    ret, 0 /*always_decode_plus*/);
+
+	return (ret);
+}
+
+/* 
+ * Helper function to parse out arguments in a query.
+ * The arguments are separated by key and value.
+ */
+
+void
+evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
+{
+	char *line;
+	char *argument;
+	char *p;
+
+	TAILQ_INIT(headers);
+
+	/* No arguments - we are done */
+	if (strchr(uri, '?') == NULL)
+		return;
+
+	if ((line = strdup(uri)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+
+
+	argument = line;
+
+	/* We already know that there has to be a ? */
+	strsep(&argument, "?");
+
+	p = argument;
+	while (p != NULL && *p != '\0') {
+		char *key, *value, *decoded_value;
+		argument = strsep(&p, "&");
+
+		value = argument;
+		key = strsep(&value, "=");
+		if (value == NULL)
+			goto error;
+
+		if ((decoded_value = malloc(strlen(value) + 1)) == NULL)
+			event_err(1, "%s: malloc", __func__);
+
+		evhttp_decode_uri_internal(value, strlen(value),
+		    decoded_value, 1 /*always_decode_plus*/);
+		event_debug(("Query Param: %s -> %s\n", key, decoded_value));
+		evhttp_add_header_internal(headers, key, decoded_value);
+		free(decoded_value);
+	}
+
+ error:
+	free(line);
+}
+
+static struct evhttp_cb *
+evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
+{
+	struct evhttp_cb *cb;
+	size_t offset = 0;
+
+	/* Test for different URLs */
+	char *p = strchr(req->uri, '?');
+	if (p != NULL)
+		offset = (size_t)(p - req->uri);
+
+	TAILQ_FOREACH(cb, callbacks, next) {
+		int res = 0;
+		if (p == NULL) {
+			res = strcmp(cb->what, req->uri) == 0;
+		} else {
+			res = ((strncmp(cb->what, req->uri, offset) == 0) &&
+					(cb->what[offset] == '\0'));
+		}
+
+		if (res)
+			return (cb);
+	}
+
+	return (NULL);
+}
+
+static void
+evhttp_handle_request(struct evhttp_request *req, void *arg)
+{
+	struct evhttp *http = arg;
+	struct evhttp_cb *cb = NULL;
+
+	if (req->uri == NULL) {
+		evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
+		return;
+	}
+
+	if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
+		(*cb->cb)(req, cb->cbarg);
+		return;
+	}
+
+	/* Generic call back */
+	if (http->gencb) {
+		(*http->gencb)(req, http->gencbarg);
+		return;
+	} else {
+		/* We need to send a 404 here */
+#define ERR_FORMAT "<html><head>" \
+		    "<title>404 Not Found</title>" \
+		    "</head><body>" \
+		    "<h1>Not Found</h1>" \
+		    "<p>The requested URL %s was not found on this server.</p>"\
+		    "</body></html>\n"
+
+		char *escaped_html = evhttp_htmlescape(req->uri);
+		struct evbuffer *buf = evbuffer_new();
+
+		evhttp_response_code(req, HTTP_NOTFOUND, "Not Found");
+
+		evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
+
+		free(escaped_html);
+
+		evhttp_send_page(req, buf);
+
+		evbuffer_free(buf);
+#undef ERR_FORMAT
+	}
+}
+
+static void
+accept_socket(int fd, short what, void *arg)
+{
+	struct evhttp *http = arg;
+	struct sockaddr_storage ss;
+	socklen_t addrlen = sizeof(ss);
+	int nfd;
+
+	if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
+		if (errno != EAGAIN && errno != EINTR)
+			event_warn("%s: bad accept", __func__);
+		return;
+	}
+	if (evutil_make_socket_nonblocking(nfd) < 0)
+		return;
+
+	evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
+}
+
+int
+evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
+{
+	int fd;
+	int res;
+
+	if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
+		return (-1);
+
+	if (listen(fd, 128) == -1) {
+		event_warn("%s: listen", __func__);
+		EVUTIL_CLOSESOCKET(fd);
+		return (-1);
+	}
+
+	res = evhttp_accept_socket(http, fd);
+	
+	if (res != -1)
+		event_debug(("Bound to port %d - Awaiting connections ... ",
+			port));
+
+	return (res);
+}
+
+int
+evhttp_accept_socket(struct evhttp *http, int fd)
+{
+	struct evhttp_bound_socket *bound;
+	struct event *ev;
+	int res;
+
+	bound = malloc(sizeof(struct evhttp_bound_socket));
+	if (bound == NULL)
+		return (-1);
+
+	ev = &bound->bind_ev;
+
+	/* Schedule the socket for accepting */
+	event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
+	EVHTTP_BASE_SET(http, ev);
+
+	res = event_add(ev, NULL);
+
+	if (res == -1) {
+		free(bound);
+		return (-1);
+	}
+
+	TAILQ_INSERT_TAIL(&http->sockets, bound, next);
+
+	return (0);
+}
+
+static struct evhttp*
+evhttp_new_object(void)
+{
+	struct evhttp *http = NULL;
+
+	if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
+		event_warn("%s: calloc", __func__);
+		return (NULL);
+	}
+
+	http->timeout = -1;
+
+	TAILQ_INIT(&http->sockets);
+	TAILQ_INIT(&http->callbacks);
+	TAILQ_INIT(&http->connections);
+
+	return (http);
+}
+
+struct evhttp *
+evhttp_new(struct event_base *base)
+{
+	struct evhttp *http = evhttp_new_object();
+
+	http->base = base;
+
+	return (http);
+}
+
+/*
+ * Start a web server on the specified address and port.
+ */
+
+struct evhttp *
+evhttp_start(const char *address, u_short port)
+{
+	struct evhttp *http = evhttp_new_object();
+
+	if (evhttp_bind_socket(http, address, port) == -1) {
+		free(http);
+		return (NULL);
+	}
+
+	return (http);
+}
+
+void
+evhttp_free(struct evhttp* http)
+{
+	struct evhttp_cb *http_cb;
+	struct evhttp_connection *evcon;
+	struct evhttp_bound_socket *bound;
+	int fd;
+
+	/* Remove the accepting part */
+	while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
+		TAILQ_REMOVE(&http->sockets, bound, next);
+
+		fd = bound->bind_ev.ev_fd;
+		event_del(&bound->bind_ev);
+		EVUTIL_CLOSESOCKET(fd);
+
+		free(bound);
+	}
+
+	while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
+		/* evhttp_connection_free removes the connection */
+		evhttp_connection_free(evcon);
+	}
+
+	while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
+		TAILQ_REMOVE(&http->callbacks, http_cb, next);
+		free(http_cb->what);
+		free(http_cb);
+	}
+	
+	free(http);
+}
+
+void
+evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
+{
+	http->timeout = timeout_in_secs;
+}
+
+void
+evhttp_set_cb(struct evhttp *http, const char *uri,
+    void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+	struct evhttp_cb *http_cb;
+
+	if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL)
+		event_err(1, "%s: calloc", __func__);
+
+	http_cb->what = strdup(uri);
+	http_cb->cb = cb;
+	http_cb->cbarg = cbarg;
+
+	TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
+}
+
+int
+evhttp_del_cb(struct evhttp *http, const char *uri)
+{
+	struct evhttp_cb *http_cb;
+
+	TAILQ_FOREACH(http_cb, &http->callbacks, next) {
+		if (strcmp(http_cb->what, uri) == 0)
+			break;
+	}
+	if (http_cb == NULL)
+		return (-1);
+
+	TAILQ_REMOVE(&http->callbacks, http_cb, next);
+	free(http_cb->what);
+	free(http_cb);
+
+	return (0);
+}
+
+void
+evhttp_set_gencb(struct evhttp *http,
+    void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+	http->gencb = cb;
+	http->gencbarg = cbarg;
+}
+
+/*
+ * Request related functions
+ */
+
+struct evhttp_request *
+evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
+{
+	struct evhttp_request *req = NULL;
+
+	/* Allocate request structure */
+	if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) {
+		event_warn("%s: calloc", __func__);
+		goto error;
+	}
+
+	req->kind = EVHTTP_RESPONSE;
+	req->input_headers = calloc(1, sizeof(struct evkeyvalq));
+	if (req->input_headers == NULL) {
+		event_warn("%s: calloc", __func__);
+		goto error;
+	}
+	TAILQ_INIT(req->input_headers);
+
+	req->output_headers = calloc(1, sizeof(struct evkeyvalq));
+	if (req->output_headers == NULL) {
+		event_warn("%s: calloc", __func__);
+		goto error;
+	}
+	TAILQ_INIT(req->output_headers);
+
+	if ((req->input_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new", __func__);
+		goto error;
+	}
+
+	if ((req->output_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new", __func__);
+		goto error;
+	}
+
+	req->cb = cb;
+	req->cb_arg = arg;
+
+	return (req);
+
+ error:
+	if (req != NULL)
+		evhttp_request_free(req);
+	return (NULL);
+}
+
+void
+evhttp_request_free(struct evhttp_request *req)
+{
+	if (req->remote_host != NULL)
+		free(req->remote_host);
+	if (req->uri != NULL)
+		free(req->uri);
+	if (req->response_code_line != NULL)
+		free(req->response_code_line);
+
+	evhttp_clear_headers(req->input_headers);
+	free(req->input_headers);
+
+	evhttp_clear_headers(req->output_headers);
+	free(req->output_headers);
+
+	if (req->input_buffer != NULL)
+		evbuffer_free(req->input_buffer);
+
+	if (req->output_buffer != NULL)
+		evbuffer_free(req->output_buffer);
+
+	free(req);
+}
+
+void
+evhttp_request_set_chunked_cb(struct evhttp_request *req,
+    void (*cb)(struct evhttp_request *, void *))
+{
+	req->chunk_cb = cb;
+}
+
+/*
+ * Allows for inspection of the request URI
+ */
+
+const char *
+evhttp_request_uri(struct evhttp_request *req) {
+	if (req->uri == NULL)
+		event_debug(("%s: request %p has no uri\n", __func__, req));
+	return (req->uri);
+}
+
+/*
+ * Takes a file descriptor to read a request from.
+ * The callback is executed once the whole request has been read.
+ */
+
+static struct evhttp_connection*
+evhttp_get_request_connection(
+	struct evhttp* http,
+	int fd, struct sockaddr *sa, socklen_t salen)
+{
+	struct evhttp_connection *evcon;
+	char *hostname = NULL, *portname = NULL;
+
+	name_from_addr(sa, salen, &hostname, &portname);
+	if (hostname == NULL || portname == NULL) {
+		if (hostname) free(hostname);
+		if (portname) free(portname);
+		return (NULL);
+	}
+
+	event_debug(("%s: new request from %s:%s on %d\n",
+			__func__, hostname, portname, fd));
+
+	/* we need a connection object to put the http request on */
+	evcon = evhttp_connection_new(hostname, atoi(portname));
+	free(hostname);
+	free(portname);
+	if (evcon == NULL)
+		return (NULL);
+
+	/* associate the base if we have one*/
+	evhttp_connection_set_base(evcon, http->base);
+
+	evcon->flags |= EVHTTP_CON_INCOMING;
+	evcon->state = EVCON_READING_FIRSTLINE;
+	
+	evcon->fd = fd;
+
+	return (evcon);
+}
+
+static int
+evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
+{
+	struct evhttp *http = evcon->http_server;
+	struct evhttp_request *req;
+	if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
+		return (-1);
+
+	req->evcon = evcon;	/* the request ends up owning the connection */
+	req->flags |= EVHTTP_REQ_OWN_CONNECTION;
+	
+	TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+	
+	req->kind = EVHTTP_REQUEST;
+	
+	if ((req->remote_host = strdup(evcon->address)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+	req->remote_port = evcon->port;
+
+	evhttp_start_read(evcon);
+	
+	return (0);
+}
+
+void
+evhttp_get_request(struct evhttp *http, int fd,
+    struct sockaddr *sa, socklen_t salen)
+{
+	struct evhttp_connection *evcon;
+
+	evcon = evhttp_get_request_connection(http, fd, sa, salen);
+	if (evcon == NULL)
+		return;
+
+	/* the timeout can be used by the server to close idle connections */
+	if (http->timeout != -1)
+		evhttp_connection_set_timeout(evcon, http->timeout);
+
+	/* 
+	 * if we want to accept more than one request on a connection,
+	 * we need to know which http server it belongs to.
+	 */
+	evcon->http_server = http;
+	TAILQ_INSERT_TAIL(&http->connections, evcon, next);
+	
+	if (evhttp_associate_new_request_with_connection(evcon) == -1)
+		evhttp_connection_free(evcon);
+}
+
+
+/*
+ * Network helper functions that we do not want to export to the rest of
+ * the world.
+ */
+#if 0 /* Unused */
+static struct addrinfo *
+addr_from_name(char *address)
+{
+#ifdef HAVE_GETADDRINFO
+        struct addrinfo ai, *aitop;
+        int ai_result;
+
+        memset(&ai, 0, sizeof(ai));
+        ai.ai_family = AF_INET;
+        ai.ai_socktype = SOCK_RAW;
+        ai.ai_flags = 0;
+        if ((ai_result = getaddrinfo(address, NULL, &ai, &aitop)) != 0) {
+                if ( ai_result == EAI_SYSTEM )
+                        event_warn("getaddrinfo");
+                else
+                        event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
+        }
+
+	return (aitop);
+#else
+	assert(0);
+	return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */
+#endif
+}
+#endif
+
+static void
+name_from_addr(struct sockaddr *sa, socklen_t salen,
+    char **phost, char **pport)
+{
+	char ntop[NI_MAXHOST];
+	char strport[NI_MAXSERV];
+	int ni_result;
+
+#ifdef HAVE_GETNAMEINFO
+	ni_result = getnameinfo(sa, salen,
+		ntop, sizeof(ntop), strport, sizeof(strport),
+		NI_NUMERICHOST|NI_NUMERICSERV);
+	
+	if (ni_result != 0) {
+		if (ni_result == EAI_SYSTEM)
+			event_err(1, "getnameinfo failed");
+		else
+			event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
+		return;
+	}
+#else
+	ni_result = fake_getnameinfo(sa, salen,
+		ntop, sizeof(ntop), strport, sizeof(strport),
+		NI_NUMERICHOST|NI_NUMERICSERV);
+	if (ni_result != 0)
+			return;
+#endif
+	*phost = strdup(ntop);
+	*pport = strdup(strport);
+}
+
+/* Create a non-blocking socket and bind it */
+/* todo: rename this function */
+static int
+bind_socket_ai(struct addrinfo *ai, int reuse)
+{
+        int fd, on = 1, r;
+	int serrno;
+
+        /* Create listen socket */
+        fd = socket(AF_INET, SOCK_STREAM, 0);
+        if (fd == -1) {
+                event_warn("socket");
+                return (-1);
+        }
+
+        if (evutil_make_socket_nonblocking(fd) < 0)
+                goto out;
+
+#ifndef WIN32
+        if (fcntl(fd, F_SETFD, 1) == -1) {
+                event_warn("fcntl(F_SETFD)");
+                goto out;
+        }
+#endif
+
+        setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
+	if (reuse) {
+		setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+		    (void *)&on, sizeof(on));
+	}
+
+	if (ai != NULL) {
+		r = bind(fd, ai->ai_addr, ai->ai_addrlen);
+		if (r == -1)
+			goto out;
+	}
+
+	return (fd);
+
+ out:
+	serrno = EVUTIL_SOCKET_ERROR();
+	EVUTIL_CLOSESOCKET(fd);
+	EVUTIL_SET_SOCKET_ERROR(serrno);
+	return (-1);
+}
+
+static struct addrinfo *
+make_addrinfo(const char *address, u_short port)
+{
+        struct addrinfo *aitop = NULL;
+
+#ifdef HAVE_GETADDRINFO
+        struct addrinfo ai;
+        char strport[NI_MAXSERV];
+        int ai_result;
+
+        memset(&ai, 0, sizeof(ai));
+        ai.ai_family = AF_INET;
+        ai.ai_socktype = SOCK_STREAM;
+        ai.ai_flags = AI_PASSIVE;  /* turn NULL host name into INADDR_ANY */
+        evutil_snprintf(strport, sizeof(strport), "%d", port);
+        if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
+                if ( ai_result == EAI_SYSTEM )
+                        event_warn("getaddrinfo");
+                else
+                        event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
+		return (NULL);
+        }
+#else
+	static int cur;
+	static struct addrinfo ai[2]; /* We will be returning the address of some of this memory so it has to last even after this call. */
+	if (++cur == 2) cur = 0;   /* allow calling this function twice */
+
+	if (fake_getaddrinfo(address, &ai[cur]) < 0) {
+		event_warn("fake_getaddrinfo");
+		return (NULL);
+	}
+	aitop = &ai[cur];
+	((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port);
+#endif
+
+	return (aitop);
+}
+
+static int
+bind_socket(const char *address, u_short port, int reuse)
+{
+	int fd;
+	struct addrinfo *aitop = NULL;
+
+	/* just create an unbound socket */
+	if (address == NULL && port == 0)
+		return bind_socket_ai(NULL, 0);
+		
+	aitop = make_addrinfo(address, port);
+
+	if (aitop == NULL)
+		return (-1);
+
+	fd = bind_socket_ai(aitop, reuse);
+
+#ifdef HAVE_GETADDRINFO
+	freeaddrinfo(aitop);
+#else
+	fake_freeaddrinfo(aitop);
+#endif
+
+	return (fd);
+}
+
+static int
+socket_connect(int fd, const char *address, unsigned short port)
+{
+	struct addrinfo *ai = make_addrinfo(address, port);
+	int res = -1;
+
+	if (ai == NULL) {
+		event_debug(("%s: make_addrinfo: \"%s:%d\"",
+			__func__, address, port));
+		return (-1);
+	}
+
+	if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
+#ifdef WIN32
+		int tmp_error = WSAGetLastError();
+		if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL &&
+		    tmp_error != WSAEINPROGRESS) {
+			goto out;
+		}
+#else
+		if (errno != EINPROGRESS) {
+			goto out;
+		}
+#endif
+	}
+
+	/* everything is fine */
+	res = 0;
+
+out:
+#ifdef HAVE_GETADDRINFO
+	freeaddrinfo(ai);
+#else
+	fake_freeaddrinfo(ai);
+#endif
+
+	return (res);
+}
diff --git a/third_party/libevent/install-sh b/third_party/libevent/install-sh
new file mode 100644
index 0000000..89fc9b0
--- /dev/null
+++ b/third_party/libevent/install-sh
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/third_party/libevent/kqueue.c b/third_party/libevent/kqueue.c
new file mode 100644
index 0000000..556b73c
--- /dev/null
+++ b/third_party/libevent/kqueue.c
@@ -0,0 +1,450 @@
+/*	$OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $	*/
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define _GNU_SOURCE 1
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/event.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* Some platforms apparently define the udata field of struct kevent as
+ * intptr_t, whereas others define it as void*.  There doesn't seem to be an
+ * easy way to tell them apart via autoconf, so we need to use OS macros. */
+#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
+#define PTR_TO_UDATA(x)	((intptr_t)(x))
+#else
+#define PTR_TO_UDATA(x)	(x)
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "log.h"
+
+#define EVLIST_X_KQINKERNEL	0x1000
+
+#define NEVENT		64
+
+struct kqop {
+	struct kevent *changes;
+	int nchanges;
+	struct kevent *events;
+	struct event_list evsigevents[NSIG];
+	int nevents;
+	int kq;
+	pid_t pid;
+};
+
+static void *kq_init	(struct event_base *);
+static int kq_add	(void *, struct event *);
+static int kq_del	(void *, struct event *);
+static int kq_dispatch	(struct event_base *, void *, struct timeval *);
+static int kq_insert	(struct kqop *, struct kevent *);
+static void kq_dealloc (struct event_base *, void *);
+
+const struct eventop kqops = {
+	"kqueue",
+	kq_init,
+	kq_add,
+	kq_del,
+	kq_dispatch,
+	kq_dealloc,
+	1 /* need reinit */
+};
+
+static void *
+kq_init(struct event_base *base)
+{
+	int i, kq;
+	struct kqop *kqueueop;
+
+	/* Disable kqueue when this environment variable is set */
+	if (evutil_getenv("EVENT_NOKQUEUE"))
+		return (NULL);
+
+	if (!(kqueueop = calloc(1, sizeof(struct kqop))))
+		return (NULL);
+
+	/* Initalize the kernel queue */
+	
+	if ((kq = kqueue()) == -1) {
+		event_warn("kqueue");
+		free (kqueueop);
+		return (NULL);
+	}
+
+	kqueueop->kq = kq;
+
+	kqueueop->pid = getpid();
+
+	/* Initalize fields */
+	kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
+	if (kqueueop->changes == NULL) {
+		free (kqueueop);
+		return (NULL);
+	}
+	kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
+	if (kqueueop->events == NULL) {
+		free (kqueueop->changes);
+		free (kqueueop);
+		return (NULL);
+	}
+	kqueueop->nevents = NEVENT;
+
+	/* we need to keep track of multiple events per signal */
+	for (i = 0; i < NSIG; ++i) {
+		TAILQ_INIT(&kqueueop->evsigevents[i]);
+	}
+
+	/* Check for Mac OS X kqueue bug. */
+	kqueueop->changes[0].ident = -1;
+	kqueueop->changes[0].filter = EVFILT_READ;
+	kqueueop->changes[0].flags = EV_ADD;
+	/* 
+	 * If kqueue works, then kevent will succeed, and it will
+	 * stick an error in events[0].  If kqueue is broken, then
+	 * kevent will fail.
+	 */
+	if (kevent(kq,
+		kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
+	    kqueueop->events[0].ident != -1 ||
+	    kqueueop->events[0].flags != EV_ERROR) {
+		event_warn("%s: detected broken kqueue; not using.", __func__);
+		free(kqueueop->changes);
+		free(kqueueop->events);
+		free(kqueueop);
+		close(kq);
+		return (NULL);
+	}
+
+	return (kqueueop);
+}
+
+static int
+kq_insert(struct kqop *kqop, struct kevent *kev)
+{
+	int nevents = kqop->nevents;
+
+	if (kqop->nchanges == nevents) {
+		struct kevent *newchange;
+		struct kevent *newresult;
+
+		nevents *= 2;
+
+		newchange = realloc(kqop->changes,
+				    nevents * sizeof(struct kevent));
+		if (newchange == NULL) {
+			event_warn("%s: malloc", __func__);
+			return (-1);
+		}
+		kqop->changes = newchange;
+
+		newresult = realloc(kqop->events,
+				    nevents * sizeof(struct kevent));
+
+		/*
+		 * If we fail, we don't have to worry about freeing,
+		 * the next realloc will pick it up.
+		 */
+		if (newresult == NULL) {
+			event_warn("%s: malloc", __func__);
+			return (-1);
+		}
+		kqop->events = newresult;
+
+		kqop->nevents = nevents;
+	}
+
+	memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
+
+	event_debug(("%s: fd %d %s%s",
+		__func__, (int)kev->ident, 
+		kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
+		kev->flags == EV_DELETE ? " (del)" : ""));
+
+	return (0);
+}
+
+static void
+kq_sighandler(int sig)
+{
+	/* Do nothing here */
+}
+
+static int
+kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	struct kqop *kqop = arg;
+	struct kevent *changes = kqop->changes;
+	struct kevent *events = kqop->events;
+	struct event *ev;
+	struct timespec ts, *ts_p = NULL;
+	int i, res;
+
+	if (tv != NULL) {
+		TIMEVAL_TO_TIMESPEC(tv, &ts);
+		ts_p = &ts;
+	}
+
+	res = kevent(kqop->kq, changes, kqop->nchanges,
+	    events, kqop->nevents, ts_p);
+	kqop->nchanges = 0;
+	if (res == -1) {
+		if (errno != EINTR) {
+                        event_warn("kevent");
+			return (-1);
+		}
+
+		return (0);
+	}
+
+	event_debug(("%s: kevent reports %d", __func__, res));
+
+	for (i = 0; i < res; i++) {
+		int which = 0;
+
+		if (events[i].flags & EV_ERROR) {
+			/* 
+			 * Error messages that can happen, when a delete fails.
+			 *   EBADF happens when the file discriptor has been
+			 *   closed,
+			 *   ENOENT when the file discriptor was closed and
+			 *   then reopened.
+			 *   EINVAL for some reasons not understood; EINVAL
+			 *   should not be returned ever; but FreeBSD does :-\
+			 * An error is also indicated when a callback deletes
+			 * an event we are still processing.  In that case
+			 * the data field is set to ENOENT.
+			 */
+			if (events[i].data == EBADF ||
+			    events[i].data == EINVAL ||
+			    events[i].data == ENOENT)
+				continue;
+			errno = events[i].data;
+			return (-1);
+		}
+
+		if (events[i].filter == EVFILT_READ) {
+			which |= EV_READ;
+		} else if (events[i].filter == EVFILT_WRITE) {
+			which |= EV_WRITE;
+		} else if (events[i].filter == EVFILT_SIGNAL) {
+			which |= EV_SIGNAL;
+		}
+
+		if (!which)
+			continue;
+
+		if (events[i].filter == EVFILT_SIGNAL) {
+			struct event_list *head =
+			    (struct event_list *)events[i].udata;
+			TAILQ_FOREACH(ev, head, ev_signal_next) {
+				event_active(ev, which, events[i].data);
+			}
+		} else {
+			ev = (struct event *)events[i].udata;
+
+			if (!(ev->ev_events & EV_PERSIST))
+				ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+
+			event_active(ev, which, 1);
+		}
+	}
+
+	return (0);
+}
+
+
+static int
+kq_add(void *arg, struct event *ev)
+{
+	struct kqop *kqop = arg;
+	struct kevent kev;
+
+	if (ev->ev_events & EV_SIGNAL) {
+		int nsignal = EVENT_SIGNAL(ev);
+
+		assert(nsignal >= 0 && nsignal < NSIG);
+		if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
+			struct timespec timeout = { 0, 0 };
+			
+			memset(&kev, 0, sizeof(kev));
+			kev.ident = nsignal;
+			kev.filter = EVFILT_SIGNAL;
+			kev.flags = EV_ADD;
+			kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
+			
+			/* Be ready for the signal if it is sent any
+			 * time between now and the next call to
+			 * kq_dispatch. */
+			if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+				return (-1);
+			
+			if (_evsignal_set_handler(ev->ev_base, nsignal,
+				kq_sighandler) == -1)
+				return (-1);
+		}
+
+		TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
+		    ev_signal_next);
+		ev->ev_flags |= EVLIST_X_KQINKERNEL;
+		return (0);
+	}
+
+	if (ev->ev_events & EV_READ) {
+ 		memset(&kev, 0, sizeof(kev));
+		kev.ident = ev->ev_fd;
+		kev.filter = EVFILT_READ;
+#ifdef NOTE_EOF
+		/* Make it behave like select() and poll() */
+		kev.fflags = NOTE_EOF;
+#endif
+		kev.flags = EV_ADD;
+		if (!(ev->ev_events & EV_PERSIST))
+			kev.flags |= EV_ONESHOT;
+		kev.udata = PTR_TO_UDATA(ev);
+		
+		if (kq_insert(kqop, &kev) == -1)
+			return (-1);
+
+		ev->ev_flags |= EVLIST_X_KQINKERNEL;
+	}
+
+	if (ev->ev_events & EV_WRITE) {
+ 		memset(&kev, 0, sizeof(kev));
+		kev.ident = ev->ev_fd;
+		kev.filter = EVFILT_WRITE;
+		kev.flags = EV_ADD;
+		if (!(ev->ev_events & EV_PERSIST))
+			kev.flags |= EV_ONESHOT;
+		kev.udata = PTR_TO_UDATA(ev);
+		
+		if (kq_insert(kqop, &kev) == -1)
+			return (-1);
+
+		ev->ev_flags |= EVLIST_X_KQINKERNEL;
+	}
+
+	return (0);
+}
+
+static int
+kq_del(void *arg, struct event *ev)
+{
+	struct kqop *kqop = arg;
+	struct kevent kev;
+
+	if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
+		return (0);
+
+	if (ev->ev_events & EV_SIGNAL) {
+		int nsignal = EVENT_SIGNAL(ev);
+		struct timespec timeout = { 0, 0 };
+
+		assert(nsignal >= 0 && nsignal < NSIG);
+		TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
+		if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
+			memset(&kev, 0, sizeof(kev));
+			kev.ident = nsignal;
+			kev.filter = EVFILT_SIGNAL;
+			kev.flags = EV_DELETE;
+		
+			/* Because we insert signal events
+			 * immediately, we need to delete them
+			 * immediately, too */
+			if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+				return (-1);
+
+			if (_evsignal_restore_handler(ev->ev_base,
+				nsignal) == -1)
+				return (-1);
+		}
+
+		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+		return (0);
+	}
+
+	if (ev->ev_events & EV_READ) {
+ 		memset(&kev, 0, sizeof(kev));
+		kev.ident = ev->ev_fd;
+		kev.filter = EVFILT_READ;
+		kev.flags = EV_DELETE;
+		
+		if (kq_insert(kqop, &kev) == -1)
+			return (-1);
+
+		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+	}
+
+	if (ev->ev_events & EV_WRITE) {
+ 		memset(&kev, 0, sizeof(kev));
+		kev.ident = ev->ev_fd;
+		kev.filter = EVFILT_WRITE;
+		kev.flags = EV_DELETE;
+		
+		if (kq_insert(kqop, &kev) == -1)
+			return (-1);
+
+		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+	}
+
+	return (0);
+}
+
+static void
+kq_dealloc(struct event_base *base, void *arg)
+{
+	struct kqop *kqop = arg;
+
+	if (kqop->changes)
+		free(kqop->changes);
+	if (kqop->events)
+		free(kqop->events);
+	if (kqop->kq >= 0 && kqop->pid == getpid())
+		close(kqop->kq);
+	memset(kqop, 0, sizeof(struct kqop));
+	free(kqop);
+}
diff --git a/third_party/libevent/libevent.gyp b/third_party/libevent/libevent.gyp
new file mode 100644
index 0000000..656dd63
--- /dev/null
+++ b/third_party/libevent/libevent.gyp
@@ -0,0 +1,64 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [
+    {
+      'target_name': 'libevent',
+      'product_name': 'event',
+      'type': 'static_library',
+      'toolsets': ['host', 'target'],
+      'sources': [
+        'buffer.c',
+        'evbuffer.c',
+        'evdns.c',
+        'event.c',
+        'event_tagging.c',
+        'evrpc.c',
+        'evutil.c',
+        'http.c',
+        'log.c',
+        'poll.c',
+        'select.c',
+        'signal.c',
+        'strlcpy.c',
+      ],
+      'defines': [
+        'HAVE_CONFIG_H',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'conditions': [
+        # libevent has platform-specific implementation files.  Since its
+        # native build uses autoconf, platform-specific config.h files are
+        # provided and live in platform-specific directories.
+        [ 'OS == "linux" or (OS == "android" and _toolset == "host")', {
+          'sources': [ 'epoll.c' ],
+          'include_dirs': [ 'linux' ],
+          'link_settings': {
+            'libraries': [
+              # We need rt for clock_gettime().
+              # TODO(port) Maybe on FreeBSD as well?
+              '-lrt',
+            ],
+          },
+        }],
+        [ 'OS == "android" and _toolset == "target"', {
+          # On android, clock_gettime() is in libc.so, so no need to link librt.
+          'sources': [ 'epoll.c' ],
+          'include_dirs': [ 'android' ],
+        }],
+        [ 'OS == "mac" or OS == "ios" or os_bsd==1', {
+          'sources': [ 'kqueue.c' ],
+          'include_dirs': [ 'mac' ]
+        }],
+        [ 'OS == "solaris"', {
+          'sources': [ 'devpoll.c', 'evport.c' ],
+          'include_dirs': [ 'solaris' ]
+        }],
+      ],
+    },
+  ],
+}
diff --git a/third_party/libevent/libevent_nacl_nonsfi.gyp b/third_party/libevent/libevent_nacl_nonsfi.gyp
new file mode 100644
index 0000000..2999ceb
--- /dev/null
+++ b/third_party/libevent/libevent_nacl_nonsfi.gyp
@@ -0,0 +1,47 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../build/common_untrusted.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'event_nacl_nonsfi',
+          'type': 'none',
+          'sources': [
+            'buffer.c',
+            'evbuffer.c',
+            'event.c',
+            'evutil.c',
+            'log.c',
+            'poll.c',
+            'strlcpy.c',
+            'nacl_nonsfi/config.h',
+            'nacl_nonsfi/event-config.h',
+            'nacl_nonsfi/random.c',
+            'nacl_nonsfi/signal_stub.c',
+          ],
+          'defines': [
+            'HAVE_CONFIG_H',
+          ],
+          'include_dirs': [
+            'nacl_nonsfi',
+          ],
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libevent_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+          },
+        },
+      ],
+    }],
+  ],
+}
diff --git a/third_party/libevent/linux/config.h b/third_party/libevent/linux/config.h
new file mode 100644
index 0000000..c01ceb5
--- /dev/null
+++ b/third_party/libevent/linux/config.h
@@ -0,0 +1,266 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/third_party/libevent/linux/event-config.h b/third_party/libevent/linux/event-config.h
new file mode 100644
index 0000000..c8a6431
--- /dev/null
+++ b/third_party/libevent/linux/event-config.h
@@ -0,0 +1,274 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define _EVENT_HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define _EVENT_HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef _EVENT_HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef _EVENT_HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define _EVENT_HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/third_party/libevent/log.c b/third_party/libevent/log.c
new file mode 100644
index 0000000..48ebb26
--- /dev/null
+++ b/third_party/libevent/log.c
@@ -0,0 +1,187 @@
+/*	$OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
+
+/*
+ * log.c
+ *
+ * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code.
+ *
+ * Copyright (c) 2005 Nick Mathewson <nickm@freehaven.net>
+ *
+ * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+ *
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "event.h"
+
+#include "log.h"
+#include "evutil.h"
+
+static void _warn_helper(int severity, int log_errno, const char *fmt,
+                         va_list ap);
+static void event_log(int severity, const char *msg);
+
+void
+event_err(int eval, const char *fmt, ...)
+{
+	va_list ap;
+	
+	va_start(ap, fmt);
+	_warn_helper(_EVENT_LOG_ERR, errno, fmt, ap);
+	va_end(ap);
+	exit(eval);
+}
+
+void
+event_warn(const char *fmt, ...)
+{
+	va_list ap;
+	
+	va_start(ap, fmt);
+	_warn_helper(_EVENT_LOG_WARN, errno, fmt, ap);
+	va_end(ap);
+}
+
+void
+event_errx(int eval, const char *fmt, ...)
+{
+	va_list ap;
+	
+	va_start(ap, fmt);
+	_warn_helper(_EVENT_LOG_ERR, -1, fmt, ap);
+	va_end(ap);
+	exit(eval);
+}
+
+void
+event_warnx(const char *fmt, ...)
+{
+	va_list ap;
+	
+	va_start(ap, fmt);
+	_warn_helper(_EVENT_LOG_WARN, -1, fmt, ap);
+	va_end(ap);
+}
+
+void
+event_msgx(const char *fmt, ...)
+{
+	va_list ap;
+	
+	va_start(ap, fmt);
+	_warn_helper(_EVENT_LOG_MSG, -1, fmt, ap);
+	va_end(ap);
+}
+
+void
+_event_debugx(const char *fmt, ...)
+{
+	va_list ap;
+	
+	va_start(ap, fmt);
+	_warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap);
+	va_end(ap);
+}
+
+static void
+_warn_helper(int severity, int log_errno, const char *fmt, va_list ap)
+{
+	char buf[1024];
+	size_t len;
+
+	if (fmt != NULL)
+		evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
+	else
+		buf[0] = '\0';
+
+	if (log_errno >= 0) {
+		len = strlen(buf);
+		if (len < sizeof(buf) - 3) {
+			evutil_snprintf(buf + len, sizeof(buf) - len, ": %s",
+			    strerror(log_errno));
+		}
+	}
+
+	event_log(severity, buf);
+}
+
+static event_log_cb log_fn = NULL;
+
+void
+event_set_log_callback(event_log_cb cb)
+{
+	log_fn = cb;
+}
+
+static void
+event_log(int severity, const char *msg)
+{
+	if (log_fn)
+		log_fn(severity, msg);
+	else {
+		const char *severity_str;
+		switch (severity) {
+		case _EVENT_LOG_DEBUG:
+			severity_str = "debug";
+			break;
+		case _EVENT_LOG_MSG:
+			severity_str = "msg";
+			break;
+		case _EVENT_LOG_WARN:
+			severity_str = "warn";
+			break;
+		case _EVENT_LOG_ERR:
+			severity_str = "err";
+			break;
+		default:
+			severity_str = "???";
+			break;
+		}
+		(void)fprintf(stderr, "[%s] %s\n", severity_str, msg);
+	}
+}
diff --git a/third_party/libevent/log.h b/third_party/libevent/log.h
new file mode 100644
index 0000000..7bc6632
--- /dev/null
+++ b/third_party/libevent/log.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#ifdef __GNUC__
+#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
+#else
+#define EV_CHECK_FMT(a,b)
+#endif
+
+void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+
+#ifdef USE_DEBUG
+#define event_debug(x) _event_debugx x
+#else
+#define event_debug(x) do {;} while (0)
+#endif
+
+#undef EV_CHECK_FMT
+
+#endif
diff --git a/third_party/libevent/ltmain.sh b/third_party/libevent/ltmain.sh
new file mode 100644
index 0000000..27d498a
--- /dev/null
+++ b/third_party/libevent/ltmain.sh
@@ -0,0 +1,6956 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008  Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+basename="s,^.*/,,g"
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# The name of this program:
+progname=`echo "$progpath" | $SED $basename`
+modename="$progname"
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5.26
+TIMESTAMP=" (1.1220.2.492 2008/01/30 06:40:56)"
+
+# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE).
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell, and then maybe $echo will work.
+  exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit $EXIT_SUCCESS
+fi
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  SP2NL='tr \040 \012'
+  NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  SP2NL='tr \100 \n'
+  NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+lt_env=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+	  save_$lt_var=\$$lt_var
+	  lt_env=\"$lt_var=\$$lt_var \$lt_env\"
+	  $lt_var=C
+	  export $lt_var
+	fi"
+done
+
+if test -n "$lt_env"; then
+  lt_env="env $lt_env"
+fi
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+  $echo "$modename: not configured to build any kind of library" 1>&2
+  $echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit $EXIT_FAILURE
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+duplicate_deps=no
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+	# Failing that, at least try and use $RANDOM to avoid a race
+	my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+	save_mktempdir_umask=`umask`
+	umask 0077
+	$mkdir "$my_tmpdir"
+	umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || {
+        $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2
+	exit $EXIT_FAILURE
+      }
+    fi
+
+    $echo "X$my_tmpdir" | $Xsed
+}
+
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid ()
+{
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+      $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+      win32_nmres=`eval $NM -f posix -A $1 | \
+	$SED -n -e '1,100{
+		/ I /{
+			s,.*,import,
+			p
+			q
+			}
+		}'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $echo $win32_libid_type
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	case $arg in
+	  *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+	CC_quoted="$CC_quoted $arg"
+      done
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	    # Double-quote args containing other shell metacharacters.
+	    case $arg in
+	      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	      arg="\"$arg\""
+	      ;;
+	    esac
+	    CC_quoted="$CC_quoted $arg"
+	  done
+	    case "$@ " in
+	      " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  $echo "$modename: unable to infer tagged configuration"
+	  $echo "$modename: specify a tag with \`--tag'" 1>&2
+	  exit $EXIT_FAILURE
+#        else
+#          $echo "$modename: using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+
+    $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)"
+    $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $?
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2
+      exit $EXIT_FAILURE
+    fi
+}
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+    my_status=""
+
+    $show "${rm}r $my_gentop"
+    $run ${rm}r "$my_gentop"
+    $show "$mkdir $my_gentop"
+    $run $mkdir "$my_gentop"
+    my_status=$?
+    if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then
+      exit $my_status
+    fi
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'`
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  extracted_serial=`expr $extracted_serial + 1`
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      $show "${rm}r $my_xdir"
+      $run ${rm}r "$my_xdir"
+      $show "$mkdir $my_xdir"
+      $run $mkdir "$my_xdir"
+      exit_status=$?
+      if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then
+	exit $exit_status
+      fi
+      case $host in
+      *-darwin*)
+	$show "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	if test -z "$run"; then
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'`
+	  darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null`
+	  if test -n "$darwin_arches"; then 
+	    darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    $show "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+      ## Okay now we have a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+	      lipo -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    ${rm}r unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd "$darwin_orig_dir"
+ 	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	fi # $run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+        ;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+    done
+    func_extract_archives_result="$my_oldobjs"
+}
+# End of Shell function definitions
+#####################################
+
+# Darwin sucks
+eval std_shrext=\"$shrext_cmds\"
+
+disable_libs=no
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+  arg="$1"
+  shift
+
+  case $arg in
+  -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    case $prev in
+    execute_dlfiles)
+      execute_dlfiles="$execute_dlfiles $arg"
+      ;;
+    tag)
+      tagname="$arg"
+      preserve_args="${preserve_args}=$arg"
+
+      # Check whether tagname contains only valid characters
+      case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+	$echo "$progname: invalid tag name: $tagname" 1>&2
+	exit $EXIT_FAILURE
+	;;
+      esac
+
+      case $tagname in
+      CC)
+	# Don't test for the "default" C tag, as we know, it's there, but
+	# not specially marked.
+	;;
+      *)
+	if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then
+	  taglist="$taglist $tagname"
+	  # Evaluate the configuration.
+	  eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`"
+	else
+	  $echo "$progname: ignoring unknown tag $tagname" 1>&2
+	fi
+	;;
+      esac
+      ;;
+    *)
+      eval "$prev=\$arg"
+      ;;
+    esac
+
+    prev=
+    prevopt=
+    continue
+  fi
+
+  # Have we seen a non-optional argument yet?
+  case $arg in
+  --help)
+    show_help=yes
+    ;;
+
+  --version)
+    echo "\
+$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP
+
+Copyright (C) 2008  Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+    exit $?
+    ;;
+
+  --config)
+    ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath"
+    done
+    exit $?
+    ;;
+
+  --debug)
+    $echo "$progname: enabling shell trace mode"
+    set -x
+    preserve_args="$preserve_args $arg"
+    ;;
+
+  --dry-run | -n)
+    run=:
+    ;;
+
+  --features)
+    $echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      $echo "enable shared libraries"
+    else
+      $echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      $echo "enable static libraries"
+    else
+      $echo "disable static libraries"
+    fi
+    exit $?
+    ;;
+
+  --finish) mode="finish" ;;
+
+  --mode) prevopt="--mode" prev=mode ;;
+  --mode=*) mode="$optarg" ;;
+
+  --preserve-dup-deps) duplicate_deps="yes" ;;
+
+  --quiet | --silent)
+    show=:
+    preserve_args="$preserve_args $arg"
+    ;;
+
+  --tag)
+    prevopt="--tag"
+    prev=tag
+    preserve_args="$preserve_args --tag"
+    ;;
+  --tag=*)
+    set tag "$optarg" ${1+"$@"}
+    shift
+    prev=tag
+    preserve_args="$preserve_args --tag"
+    ;;
+
+  -dlopen)
+    prevopt="-dlopen"
+    prev=execute_dlfiles
+    ;;
+
+  -*)
+    $echo "$modename: unrecognized option \`$arg'" 1>&2
+    $echo "$help" 1>&2
+    exit $EXIT_FAILURE
+    ;;
+
+  *)
+    nonopt="$arg"
+    break
+    ;;
+  esac
+done
+
+if test -n "$prevopt"; then
+  $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+  $echo "$help" 1>&2
+  exit $EXIT_FAILURE
+fi
+
+case $disable_libs in
+no) 
+  ;;
+shared)
+  build_libtool_libs=no
+  build_old_libs=yes
+  ;;
+static)
+  build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+  ;;
+esac
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+  # Infer the operation mode.
+  if test -z "$mode"; then
+    $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+    $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2
+    case $nonopt in
+    *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+      mode=link
+      for arg
+      do
+	case $arg in
+	-c)
+	   mode=compile
+	   break
+	   ;;
+	esac
+      done
+      ;;
+    *db | *dbx | *strace | *truss)
+      mode=execute
+      ;;
+    *install*|cp|mv)
+      mode=install
+      ;;
+    *rm)
+      mode=uninstall
+      ;;
+    *)
+      # If we have no mode, but dlfiles were specified, then do execute mode.
+      test -n "$execute_dlfiles" && mode=execute
+
+      # Just use the default operation mode.
+      if test -z "$mode"; then
+	if test -n "$nonopt"; then
+	  $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+	else
+	  $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+	fi
+      fi
+      ;;
+    esac
+  fi
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+    $echo "$help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$modename --help --mode=$mode' for more information."
+
+  # These modes are in order of execution frequency so that they run quickly.
+  case $mode in
+  # libtool compile mode
+  compile)
+    modename="$modename: compile"
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  if test -n "$libobj" ; then
+	    $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-static | -prefer-pic | -prefer-non-pic)
+	  later="$later $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+ 	  for arg in $args; do
+	    IFS="$save_ifs"
+
+	    # Double-quote args containing other shell metacharacters.
+	    # Many Bourne shells cannot handle close brackets correctly
+	    # in scan sets, so we specify it separately.
+	    case $arg in
+	      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	      arg="\"$arg\""
+	      ;;
+	    esac
+	    lastarg="$lastarg $arg"
+	  done
+	  IFS="$save_ifs"
+	  lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+	  # Add the arguments to base_compile.
+	  base_compile="$base_compile $lastarg"
+	  continue
+	  ;;
+
+	* )
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+      case $lastarg in
+      # Double-quote args containing other shell metacharacters.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, and some SunOS ksh mistreat backslash-escaping
+      # in scan sets (worked around with variable expansion),
+      # and furthermore cannot handle '|' '&' '(' ')' in scan sets 
+      # at all, so we specify them separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	lastarg="\"$lastarg\""
+	;;
+      esac
+
+      base_compile="$base_compile $lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      $echo "$modename: you must specify an argument for -Xcompile"
+      exit $EXIT_FAILURE
+      ;;
+    target)
+      $echo "$modename: you must specify a target with \`-o'" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    *)
+      # Get the name of the library object.
+      [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    xform='[cCFSifmso]'
+    case $libobj in
+    *.ada) xform=ada ;;
+    *.adb) xform=adb ;;
+    *.ads) xform=ads ;;
+    *.asm) xform=asm ;;
+    *.c++) xform=c++ ;;
+    *.cc) xform=cc ;;
+    *.ii) xform=ii ;;
+    *.class) xform=class ;;
+    *.cpp) xform=cpp ;;
+    *.cxx) xform=cxx ;;
+    *.[fF][09]?) xform=[fF][09]. ;;
+    *.for) xform=for ;;
+    *.java) xform=java ;;
+    *.obj) xform=obj ;;
+    *.sx) xform=sx ;;
+    esac
+
+    libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+    case $libobj in
+    *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+    *)
+      $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -static)
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"`
+    case $qlibobj in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	qlibobj="\"$qlibobj\"" ;;
+    esac
+    test "X$libobj" != "X$qlibobj" \
+	&& $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' 	&()|`$[]' \
+	&& $echo "$modename: libobj name \`$libobj' may not contain shell special characters."
+    objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+    xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+    if test "X$xdir" = "X$obj"; then
+      xdir=
+    else
+      xdir=$xdir/
+    fi
+    lobj=${xdir}$objdir/$objname
+
+    if test -z "$base_compile"; then
+      $echo "$modename: you must specify a compilation command" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    $run $rm $removelist
+    trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+      removelist="$removelist $output_obj $lockfile"
+      trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $run ln "$progpath" "$lockfile" 2>/dev/null; do
+	$show "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+      $echo "$srcfile" > "$lockfile"
+    fi
+
+    if test -n "$fix_srcfile_path"; then
+      eval srcfile=\"$fix_srcfile_path\"
+    fi
+    qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"`
+    case $qsrcfile in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+      qsrcfile="\"$qsrcfile\"" ;;
+    esac
+
+    $run $rm "$libobj" "${libobj}T"
+
+    # Create a libtool object file (analogous to a ".la" file),
+    # but don't create it if we're doing a dry run.
+    test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      if test ! -d "${xdir}$objdir"; then
+	$show "$mkdir ${xdir}$objdir"
+	$run $mkdir ${xdir}$objdir
+	exit_status=$?
+	if test "$exit_status" -ne 0 && test ! -d "${xdir}$objdir"; then
+	  exit $exit_status
+	fi
+      fi
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	command="$command -o $lobj"
+      fi
+
+      $run $rm "$lobj" "$output_obj"
+
+      $show "$command"
+      if $run eval $lt_env "$command"; then :
+      else
+	test -n "$output_obj" && $run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	$show "$mv $output_obj $lobj"
+	if $run $mv $output_obj $lobj; then :
+	else
+	  error=$?
+	  $run $rm $removelist
+	  exit $error
+	fi
+      fi
+
+      # Append the name of the PIC object to the libtool object file.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+        suppress_output=' >/dev/null 2>&1'
+      fi
+    else
+      # No PIC object so indicate it doesn't exist in the libtool
+      # object file.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	command="$command -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      command="$command$suppress_output"
+      $run $rm "$obj" "$output_obj"
+      $show "$command"
+      if $run eval $lt_env "$command"; then :
+      else
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$run $rm $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	$show "$mv $output_obj $obj"
+	if $run $mv $output_obj $obj; then :
+	else
+	  error=$?
+	  $run $rm $removelist
+	  exit $error
+	fi
+      fi
+
+      # Append the name of the non-PIC object the libtool object file.
+      # Only append if the libtool object file exists.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+    else
+      # Append the name of the non-PIC object the libtool object file.
+      # Only append if the libtool object file exists.
+      test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+    fi
+
+    $run $mv "${libobj}T" "${libobj}"
+
+    # Unlock the critical section if it was locked
+    if test "$need_locks" != no; then
+      $run $rm "$lockfile"
+    fi
+
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool link mode
+  link | relink)
+    modename="$modename: link"
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args="$nonopt"
+    base_compile="$nonopt $@"
+    compile_command="$nonopt"
+    finalize_command="$nonopt"
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+
+    avoid_version=no
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    notinst_path= # paths that contain not-installed libtool libraries
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    single_module="${wl}-single_module"
+
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      case $arg in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+	;;
+      *) qarg=$arg ;;
+      esac
+      libtool_args="$libtool_args $qarg"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  compile_command="$compile_command @OUTPUT@"
+	  finalize_command="$finalize_command @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    compile_command="$compile_command @SYMFILE@"
+	    finalize_command="$finalize_command @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      dlfiles="$dlfiles $arg"
+	    else
+	      dlprefiles="$dlprefiles $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  if test ! -f "$arg"; then
+	    $echo "$modename: symbol file \`$arg' does not exist"
+	    exit $EXIT_FAILURE
+	  fi
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat $save_arg`
+	    do
+#	      moreargs="$moreargs $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		# If there is no directory component, then add one.
+		case $arg in
+		*/* | *\\*) . $arg ;;
+		*) . ./$arg ;;
+		esac
+
+		if test -z "$pic_object" || \
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none && \
+		   test "$non_pic_object" = none; then
+		  $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+		  exit $EXIT_FAILURE
+		fi
+
+		# Extract subdirectory from the argument.
+		xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+		if test "X$xdir" = "X$arg"; then
+		  xdir=
+		else
+		  xdir="$xdir/"
+		fi
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      dlfiles="$dlfiles $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    dlprefiles="$dlprefiles $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  libobjs="$libobjs $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  non_pic_objects="$non_pic_objects $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  non_pic_objects="$non_pic_objects $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if test -z "$run"; then
+		  $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+		  exit $EXIT_FAILURE
+		else
+		  # Dry-run case.
+
+		  # Extract subdirectory from the argument.
+		  xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+		  if test "X$xdir" = "X$arg"; then
+		    xdir=
+		  else
+		    xdir="$xdir/"
+		  fi
+
+		  pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+		  non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+		  libobjs="$libobjs $pic_object"
+		  non_pic_objects="$non_pic_objects $non_pic_object"
+		fi
+	      fi
+	    done
+	  else
+	    $echo "$modename: link input file \`$save_arg' does not exist"
+	    exit $EXIT_FAILURE
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    $echo "$modename: only absolute run-paths are allowed" 1>&2
+	    exit $EXIT_FAILURE
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) rpath="$rpath $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) xrpath="$xrpath $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	xcompiler)
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  compile_command="$compile_command $qarg"
+	  finalize_command="$finalize_command $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $wl$qarg"
+	  prev=
+	  compile_command="$compile_command $wl$qarg"
+	  finalize_command="$finalize_command $wl$qarg"
+	  continue
+	  ;;
+	xcclinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  compile_command="$compile_command $qarg"
+	  finalize_command="$finalize_command $qarg"
+	  continue
+	  ;;
+	shrext)
+  	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	darwin_framework|darwin_framework_skip)
+	  test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg"
+	  compile_command="$compile_command $arg"
+	  finalize_command="$finalize_command $arg"
+	  prev=
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  compile_command="$compile_command $link_static_flag"
+	  finalize_command="$finalize_command $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	$echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+	continue
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  $echo "$modename: more than one -exported-symbols argument is not allowed"
+	  exit $EXIT_FAILURE
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework|-arch|-isysroot)
+	case " $CC " in
+	  *" ${arg} ${1} "* | *" ${arg}	${1} "*) 
+		prev=darwin_framework_skip ;;
+	  *) compiler_flags="$compiler_flags $arg"
+	     prev=darwin_framework ;;
+	esac
+	compile_command="$compile_command $arg"
+	finalize_command="$finalize_command $arg"
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  compile_command="$compile_command $arg"
+	  finalize_command="$finalize_command $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  if test -z "$absdir"; then
+	    $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+	    absdir="$dir"
+	    notinst_path="$notinst_path $dir"
+	  fi
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "*) ;;
+	*)
+	  deplibs="$deplibs -L$dir"
+	  lib_search_path="$lib_search_path $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+	  testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  *) dllsearchpath="$dllsearchpath:$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  *) dllsearchpath="$dllsearchpath:$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    deplibs="$deplibs -framework System"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	deplibs="$deplibs $arg"
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      -model)
+	compile_command="$compile_command $arg"
+	compiler_flags="$compiler_flags $arg"
+	finalize_command="$finalize_command $arg"
+	prev=xcompiler
+	continue
+	;;
+
+     -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+	compiler_flags="$compiler_flags $arg"
+	compile_command="$compile_command $arg"
+	finalize_command="$finalize_command $arg"
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+      # -r[0-9][0-9]* specifies the processor on the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+      # +DA*, +DD* enable 64-bit mode on the HP compiler
+      # -q* pass through compiler args for the IBM compiler
+      # -m* pass through architecture-specific compiler args for GCC
+      # -m*, -t[45]*, -txscale* pass through architecture-specific
+      # compiler args for GCC
+      # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+      # -F/path gives path to uninstalled frameworks, gcc on darwin
+      # @file GCC response files
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
+
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+	case $arg in
+	*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+        compile_command="$compile_command $arg"
+        finalize_command="$finalize_command $arg"
+        compiler_flags="$compiler_flags $arg"
+        continue
+        ;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+	  $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  $echo "$modename: only absolute run-paths are allowed" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) xrpath="$xrpath $dir" ;;
+	esac
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -Wc,*)
+	args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+	  case $flag in
+	    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	    flag="\"$flag\""
+	    ;;
+	  esac
+	  arg="$arg $wl$flag"
+	  compiler_flags="$compiler_flags $flag"
+	done
+	IFS="$save_ifs"
+	arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+	;;
+
+      -Wl,*)
+	args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+	  case $flag in
+	    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	    flag="\"$flag\""
+	    ;;
+	  esac
+	  arg="$arg $wl$flag"
+	  compiler_flags="$compiler_flags $wl$flag"
+	  linker_flags="$linker_flags $flag"
+	done
+	IFS="$save_ifs"
+	arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # Some other compiler flag.
+      -* | +*)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+	case $arg in
+	*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+	;;
+
+      *.$objext)
+	# A standard object.
+	objs="$objs $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  # If there is no directory component, then add one.
+	  case $arg in
+	  */* | *\\*) . $arg ;;
+	  *) . ./$arg ;;
+	  esac
+
+	  if test -z "$pic_object" || \
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none && \
+	     test "$non_pic_object" = none; then
+	    $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+	  if test "X$xdir" = "X$arg"; then
+	    xdir=
+ 	  else
+	    xdir="$xdir/"
+	  fi
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		dlfiles="$dlfiles $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      dlprefiles="$dlprefiles $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    libobjs="$libobjs $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    non_pic_objects="$non_pic_objects $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    non_pic_objects="$non_pic_objects $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if test -z "$run"; then
+	    $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+	    exit $EXIT_FAILURE
+	  else
+	    # Dry-run case.
+
+	    # Extract subdirectory from the argument.
+	    xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+	    if test "X$xdir" = "X$arg"; then
+	      xdir=
+	    else
+	      xdir="$xdir/"
+	    fi
+
+	    pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+	    non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+	    libobjs="$libobjs $pic_object"
+	    non_pic_objects="$non_pic_objects $non_pic_object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	deplibs="$deplibs $arg"
+	old_deplibs="$old_deplibs $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  dlfiles="$dlfiles $arg"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  dlprefiles="$dlprefiles $arg"
+	  prev=
+	else
+	  deplibs="$deplibs $arg"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+	case $arg in
+	*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	  arg="\"$arg\""
+	  ;;
+	esac
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	compile_command="$compile_command $arg"
+	finalize_command="$finalize_command $arg"
+      fi
+    done # argument parsing loop
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      compile_command="$compile_command $arg"
+      finalize_command="$finalize_command $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+    if test "X$output_objdir" = "X$output"; then
+      output_objdir="$objdir"
+    else
+      output_objdir="$output_objdir/$objdir"
+    fi
+    # Create the object directory.
+    if test ! -d "$output_objdir"; then
+      $show "$mkdir $output_objdir"
+      $run $mkdir $output_objdir
+      exit_status=$?
+      if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then
+	exit $exit_status
+      fi
+    fi
+
+    # Determine the type of output
+    case $output in
+    "")
+      $echo "$modename: you must specify an output file" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    case $host in
+    *cygwin* | *mingw* | *pw32*)
+      # don't eliminate duplications in $postdeps and $predeps
+      duplicate_compiler_generated_deps=yes
+      ;;
+    *)
+      duplicate_compiler_generated_deps=$duplicate_deps
+      ;;
+    esac
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if test "X$duplicate_deps" = "Xyes" ; then
+	case "$libs " in
+	*" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	esac
+      fi
+      libs="$libs $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+	  esac
+	  pre_post_deps="$pre_post_deps $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    case $linkmode in
+    lib)
+	passes="conv link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+	    exit $EXIT_FAILURE
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+    for pass in $passes; do
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    compiler_flags="$compiler_flags $deplib"
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+	    continue
+	  fi
+	  name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if (${SED} -e '2q' $lib |
+                    grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+		  library_names=
+		  old_library=
+		  case $lib in
+		  */* | *\\*) . $lib ;;
+		  *) . ./$lib ;;
+		  esac
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+		    test "X$ladir" = "X$lib" && ladir="."
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+	        ;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+	    ;;
+	  *)
+	    $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) xrpath="$xrpath $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la) lib="$deplib" ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    valid_a_lib=no
+	    case $deplibs_check_method in
+	      match_pattern*)
+		set dummy $deplibs_check_method
+	        match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+		if eval $echo \"$deplib\" 2>/dev/null \
+		    | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		  valid_a_lib=yes
+		fi
+		;;
+	      pass_all)
+		valid_a_lib=yes
+		;;
+            esac
+	    if test "$valid_a_lib" != yes; then
+	      $echo
+	      $echo "*** Warning: Trying to link with static lib archive $deplib."
+	      $echo "*** I have the capability to make that library automatically link in when"
+	      $echo "*** you link to this library.  But I can only do this if you have a"
+	      $echo "*** shared version of the library, which you do not appear to have"
+	      $echo "*** because the file extensions .$libext of this argument makes me believe"
+	      $echo "*** that it is just a static archive that I should not used here."
+	    else
+	      $echo
+	      $echo "*** Warning: Linking the shared library $output against the"
+	      $echo "*** static library $deplib is not portable!"
+	      deplibs="$deplib $deplibs"
+	    fi
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      newdlprefiles="$newdlprefiles $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      newdlfiles="$newdlfiles $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# Check to see that this really is a libtool archive.
+	if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+	else
+	  $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+	test "X$ladir" = "X$lib" && ladir="."
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	case $lib in
+	*/* | *\\*) . $lib ;;
+	*) . ./$lib ;;
+	esac
+
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+	  test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+	      exit $EXIT_FAILURE
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    convenience="$convenience $ladir/$objdir/$old_library"
+	    old_convenience="$old_convenience $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+              if test "X$duplicate_deps" = "Xyes" ; then
+	        case "$tmp_libs " in
+	        *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	        esac
+              fi
+	      tmp_libs="$tmp_libs $deplib"
+	    done
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    $echo "$modename: \`$lib' is not a convenience library" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	for l in $old_library $library_names; do
+	  linklib="$l"
+	done
+	if test -z "$linklib"; then
+	  $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    dlprefiles="$dlprefiles $lib $dependency_libs"
+	  else
+	    newdlfiles="$newdlfiles $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+	    $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    $echo "$modename: warning: library \`$lib' was moved." 1>&2
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$libdir"
+	    absdir="$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    notinst_path="$notinst_path $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    notinst_path="$notinst_path $abs_ladir"
+	  fi
+	fi # $installed = yes
+	name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir"; then
+	    $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	  # Prefer using a static library (so that no silly _DYNAMIC symbols
+	  # are required to link).
+	  if test -n "$old_library"; then
+	    newdlprefiles="$newdlprefiles $dir/$old_library"
+	  # Otherwise, use the dlname, so that lt_dlopen finds it.
+	  elif test -n "$dlname"; then
+	    newdlprefiles="$newdlprefiles $dir/$dlname"
+	  else
+	    newdlprefiles="$newdlprefiles $dir/$linklib"
+	  fi
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  newlib_search_path="$newlib_search_path $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if test "X$duplicate_deps" = "Xyes" ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+		 test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath " in
+	      *" $dir "*) ;;
+	      *" $absdir "*) ;;
+	      *) temp_rpath="$temp_rpath $absdir" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes ; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  if test "$installed" = no; then
+	    notinst_deplibs="$notinst_deplibs $lib"
+	    need_relink=yes
+	  fi
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on
+	  # some systems (darwin)
+	  if test "$shouldnotlink" = yes && test "$pass" = link ; then
+	    $echo
+	    if test "$linkmode" = prog; then
+	      $echo "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $echo "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $echo "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    realname="$2"
+	    shift; shift
+	    libname=`eval \\$echo \"$libname_spec\"`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw*)
+		major=`expr $current - $age`
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+	    newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      $show "extracting exported symbol list from \`$soname'"
+	      save_ifs="$IFS"; IFS='~'
+	      cmds=$extract_expsyms_cmds
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd" || exit $?
+	      done
+	      IFS="$save_ifs"
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      $show "generating import library for \`$soname'"
+	      save_ifs="$IFS"; IFS='~'
+	      cmds=$old_archive_from_expsyms_cmds
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd" || exit $?
+	      done
+	      IFS="$save_ifs"
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a module then we can not link against
+		    # it, someone is ignoring the new warnings I added
+		    if /usr/bin/file -L $add 2> /dev/null |
+                      $EGREP ": [^:]* bundle" >/dev/null ; then
+		      $echo "** Warning, lib $linklib is a module, not a shared library"
+		      if test -z "$old_library" ; then
+		        $echo
+		        $echo "** And there doesn't seem to be a static archive available"
+		        $echo "** The link will probably fail, sorry"
+		      else
+		        add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$dir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      $echo "$modename: configuration error: unsupported hardcode properties"
+	      exit $EXIT_FAILURE
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes && \
+		 test "$hardcode_minus_L" != yes && \
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+	        add="$inst_prefix_dir$libdir/$linklib"
+	      else
+	        add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    $echo
+	    $echo "*** Warning: This system can not link to static lib archive $lib."
+	    $echo "*** I have the capability to make that library automatically link in when"
+	    $echo "*** you link to this library.  But I can only do this if you have a"
+	    $echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      $echo "*** But as you try to build a module library, libtool will still create "
+	      $echo "*** a static module, that should work as long as the dlopening application"
+	      $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		$echo
+		$echo "*** However, this would only work if libtool was able to extract symbol"
+		$echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		$echo "*** not find such a program.  So, this module is probably useless."
+		$echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) xrpath="$xrpath $temp_xrpath";;
+		   esac;;
+	      *) temp_deplibs="$temp_deplibs $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  newlib_search_path="$newlib_search_path $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    if test "X$duplicate_deps" = "Xyes" ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+		dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+		test "X$dir" = "X$deplib" && dir="."
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if grep "^installed=no" $deplib > /dev/null; then
+		  path="$absdir/$objdir"
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  if test -z "$libdir"; then
+		    $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+		    exit $EXIT_FAILURE
+		  fi
+		  if test "$absdir" != "$libdir"; then
+		    $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+		  fi
+		  path="$absdir"
+		fi
+		depdepl=
+		case $host in
+		*-*-darwin*)
+		  # we do not want to link against static libs,
+		  # but need to link against shared
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  eval deplibdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$deplibdir/$depdepl" ; then
+		      depdepl="$deplibdir/$depdepl"
+	      	    elif test -f "$path/$depdepl" ; then
+		      depdepl="$path/$depdepl"
+		    else
+		      # Can't find it, oh well...
+		      depdepl=
+		    fi
+		    # do not add paths which are already there
+		    case " $newlib_search_path " in
+		    *" $path "*) ;;
+		    *) newlib_search_path="$newlib_search_path $path";;
+		    esac
+		  fi
+		  path=""
+		  ;;
+		*)
+		  path="-L$path"
+		  ;;
+		esac
+		;;
+	      -l*)
+		case $host in
+		*-*-darwin*)
+		  # Again, we only want to link against shared libraries
+		  eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+		  for tmp in $newlib_search_path ; do
+		    if test -f "$tmp/lib$tmp_libs.dylib" ; then
+		      eval depdepl="$tmp/lib$tmp_libs.dylib"
+		      break
+		    fi
+		  done
+		  path=""
+		  ;;
+		*) continue ;;
+		esac
+		;;
+	      *) continue ;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	      case " $deplibs " in
+	      *" $depdepl "*) ;;
+	      *) deplibs="$depdepl $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) lib_search_path="$lib_search_path $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) tmp_libs="$tmp_libs $deplib" ;;
+	      esac
+	      ;;
+	    *) tmp_libs="$tmp_libs $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  tmp_libs="$tmp_libs $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	$echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 ;;
+      esac
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	$echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+	$echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+	$echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+	$echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$release"; then
+	$echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+      fi
+
+      if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	$echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+      fi
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      objs="$objs$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	if test "$module" = no; then
+	  $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+	  exit $EXIT_FAILURE
+	else
+	  $echo
+	  $echo "*** Warning: Linking the shared library $output against the non-libtool"
+	  $echo "*** objects $objs is not portable!"
+	  libobjs="$libobjs $objs"
+	fi
+      fi
+
+      if test "$dlself" != no; then
+	$echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+      fi
+
+      set dummy $rpath
+      if test "$#" -gt 2; then
+	$echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+      fi
+      install_libdir="$2"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	if test -n "$vinfo"; then
+	  $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+	fi
+
+	if test -n "$release"; then
+	  $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+	fi
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	IFS="$save_ifs"
+
+	if test -n "$8"; then
+	  $echo "$modename: too many parameters to \`-version-info'" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$2"
+	  number_minor="$3"
+	  number_revision="$4"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  darwin|linux|osf|windows|none)
+	    current=`expr $number_major + $number_minor`
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    current=`expr $number_major + $number_minor`
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$2"
+	  revision="$3"
+	  age="$4"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+	  $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  major=.`expr $current - $age`
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  minor_current=`expr $current + 1`
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current";
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    major=`expr $current - $age`
+	  else
+	    major=`expr $current - $age + 1`
+	  fi
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    iface=`expr $revision - $loop`
+	    loop=`expr $loop - 1`
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux)
+	  major=.`expr $current - $age`
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  major=.`expr $current - $age`
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    iface=`expr $current - $loop`
+	    loop=`expr $loop - 1`
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  verstring="$verstring:${current}.0"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  major=`expr $current - $age`
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  $echo "$modename: unknown library version type \`$version_type'" 1>&2
+	  $echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+      fi
+
+      if test "$mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$echo "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+	         if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+	         then
+		   continue
+		 fi
+	       fi
+	       removelist="$removelist $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	if test -n "$removelist"; then
+	  $show "${rm}r $removelist"
+	  $run ${rm}r $removelist
+	fi
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"`
+      #	deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"`
+      #	dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  temp_xrpath="$temp_xrpath -R$libdir"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) dlfiles="$dlfiles $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) dlprefiles="$dlprefiles $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    deplibs="$deplibs -framework System"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+ 	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      deplibs="$deplibs -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $rm conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $rm conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      name=`expr $i : '-l\(.*\)'`
+	      # If $name is empty we are operating on a -L argument.
+              if test "$name" != "" && test "$name" != "0"; then
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    newdeplibs="$newdeplibs $i"
+		    i=""
+		    ;;
+		  esac
+	        fi
+		if test -n "$i" ; then
+		  libname=`eval \\$echo \"$libname_spec\"`
+		  deplib_matches=`eval \\$echo \"$library_names_spec\"`
+		  set dummy $deplib_matches
+		  deplib_match=$2
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    newdeplibs="$newdeplibs $i"
+		  else
+		    droppeddeps=yes
+		    $echo
+		    $echo "*** Warning: dynamic linker does not accept needed library $i."
+		    $echo "*** I have the capability to make that library automatically link in when"
+		    $echo "*** you link to this library.  But I can only do this if you have a"
+		    $echo "*** shared version of the library, which I believe you do not have"
+		    $echo "*** because a test_compile did reveal that the linker did not use it for"
+		    $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+	      else
+		newdeplibs="$newdeplibs $i"
+	      fi
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      name=`expr $i : '-l\(.*\)'`
+	      # If $name is empty we are operating on a -L argument.
+              if test "$name" != "" && test "$name" != "0"; then
+		$rm conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      newdeplibs="$newdeplibs $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval \\$echo \"$libname_spec\"`
+		    deplib_matches=`eval \\$echo \"$library_names_spec\"`
+		    set dummy $deplib_matches
+		    deplib_match=$2
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      newdeplibs="$newdeplibs $i"
+		    else
+		      droppeddeps=yes
+		      $echo
+		      $echo "*** Warning: dynamic linker does not accept needed library $i."
+		      $echo "*** I have the capability to make that library automatically link in when"
+		      $echo "*** you link to this library.  But I can only do this if you have a"
+		      $echo "*** shared version of the library, which you do not appear to have"
+		      $echo "*** because a test_compile did reveal that the linker did not use this one"
+		      $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  $echo
+		  $echo "*** Warning!  Library $i is needed by this library but I was not able to"
+		  $echo "*** make it link in!  You will probably need to install it or some"
+		  $echo "*** library that it depends on before this library will be fully"
+		  $echo "*** functional.  Installing it before continuing would be even better."
+		fi
+	      else
+		newdeplibs="$newdeplibs $i"
+	      fi
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method
+	  file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    name=`expr $a_deplib : '-l\(.*\)'`
+	    # If $name is empty we are operating on a -L argument.
+            if test "$name" != "" && test  "$name" != "0"; then
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval \\$echo \"$libname_spec\"`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null \
+			 | grep " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+			 | ${SED} 10q \
+			 | $EGREP "$file_magic_regex" > /dev/null; then
+			newdeplibs="$newdeplibs $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		$echo
+		$echo "*** Warning: linker path does not have real file for library $a_deplib."
+		$echo "*** I have the capability to make that library automatically link in when"
+		$echo "*** you link to this library.  But I can only do this if you have a"
+		$echo "*** shared version of the library, which you do not appear to have"
+		$echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $echo "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $echo "*** with $libname and none of the candidates passed a file format test"
+		  $echo "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	    else
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	    fi
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    name=`expr $a_deplib : '-l\(.*\)'`
+	    # If $name is empty we are operating on a -L argument.
+	    if test -n "$name" && test "$name" != "0"; then
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval \\$echo \"$libname_spec\"`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval $echo \"$potent_lib\" 2>/dev/null \
+		        | ${SED} 10q \
+		        | $EGREP "$match_pattern_regex" > /dev/null; then
+		      newdeplibs="$newdeplibs $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		$echo
+		$echo "*** Warning: linker path does not have real file for library $a_deplib."
+		$echo "*** I have the capability to make that library automatically link in when"
+		$echo "*** you link to this library.  But I can only do this if you have a"
+		$echo "*** shared version of the library, which you do not appear to have"
+		$echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $echo "*** with $libname and none of the candidates passed a file format test"
+		  $echo "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	    else
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	    fi
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+	    -e 's/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+	    done
+	  fi
+	  if $echo "X $tmp_deplibs" | $Xsed -e 's/[ 	]//g' \
+	    | grep . >/dev/null; then
+	    $echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      $echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      $echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    $echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	  fi
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library is the System framework
+	  newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    $echo
+	    $echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $echo "*** dependencies of module $libname.  Therefore, libtool will create"
+	    $echo "*** a static module, that should work as long as the dlopening"
+	    $echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      $echo
+	      $echo "*** However, this would only work if libtool was able to extract symbol"
+	      $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      $echo "*** not find such a program.  So, this module is probably useless."
+	      $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    $echo "*** The inter-library dependencies that have been dropped here will be"
+	    $echo "*** automatically added whenever a program is linked with this library"
+	    $echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      $echo
+	      $echo "*** Since this library must not contain undefined symbols,"
+	      $echo "*** because either the platform does not support them or"
+	      $echo "*** it was explicitly requested with -no-undefined,"
+	      $echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    new_libs="$new_libs -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) new_libs="$new_libs $deplib" ;;
+	  esac
+	  ;;
+	*) new_libs="$new_libs $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		dep_rpath="$dep_rpath $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) perm_rpath="$perm_rpath $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    if test -n "$hardcode_libdir_flag_spec_ld"; then
+	      case $archive_cmds in
+	      *\$LD*) eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" ;;
+	      *)      eval dep_rpath=\"$hardcode_libdir_flag_spec\" ;;
+	      esac
+	    else
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+	    fi
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      rpath="$rpath$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	realname="$2"
+	shift; shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  linknames="$linknames $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    $show "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $run $rm $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $cmds; do
+	      IFS="$save_ifs"
+	      eval cmd=\"$cmd\"
+	      if len=`expr "X$cmd" : ".*"` &&
+	       test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	        $show "$cmd"
+	        $run eval "$cmd" || exit $?
+	        skipped_export=false
+	      else
+	        # The command line is too long to execute in one step.
+	        $show "using reloadable object file for export list..."
+	        skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex"; then
+	      $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+	      $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+	      $run eval '$mv "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+		case " $convenience " in
+		*" $test_deplib "*) ;;
+		*)
+			tmp_deplibs="$tmp_deplibs $test_deplib"
+			;;
+		esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    generated="$generated $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    libobjs="$libobjs $func_extract_archives_result"
+	  fi
+	fi
+	
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  linker_flags="$linker_flags $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$mode" = relink; then
+	  $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	  eval test_cmds=\"$archive_expsym_cmds\"
+	  cmds=$archive_expsym_cmds
+	else
+	  eval test_cmds=\"$archive_cmds\"
+	  cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+	   test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise.
+	  $echo "creating reloadable object files..."
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  output_la=`$echo "X$output" | $Xsed -e "$basename"`
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  delfiles=
+	  last_robj=
+	  k=1
+	  output=$output_objdir/$output_la-${k}.$objext
+	  # Loop over the list of objects to be linked.
+	  for obj in $save_libobjs
+	  do
+	    eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+	    if test "X$objlist" = X ||
+	       { len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+		 test "$len" -le "$max_cmd_len"; }; then
+	      objlist="$objlist $obj"
+	    else
+	      # The command $test_cmds is almost too long, add a
+	      # command to the queue.
+	      if test "$k" -eq 1 ; then
+		# The first file doesn't have a previous command to add.
+		eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+	      else
+		# All subsequent reloadable object files will link in
+		# the last one created.
+		eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+	      fi
+	      last_robj=$output_objdir/$output_la-${k}.$objext
+	      k=`expr $k + 1`
+	      output=$output_objdir/$output_la-${k}.$objext
+	      objlist=$obj
+	      len=1
+	    fi
+	  done
+	  # Handle the remaining objects by creating one last
+	  # reloadable object file.  All subsequent reloadable object
+	  # files will link in the last one created.
+	  test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	  eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+	  if ${skipped_export-false}; then
+	    $show "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $run $rm $export_symbols
+	    libobjs=$output
+	    # Append the command to create the export file.
+	    eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+          fi
+
+	  # Set up a command to remove the reloadable object files
+	  # after they are used.
+	  i=0
+	  while test "$i" -lt "$k"
+	  do
+	    i=`expr $i + 1`
+	    delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
+	  done
+
+	  $echo "creating a temporary reloadable object file: $output"
+
+	  # Loop through the commands generated above and execute them.
+	  save_ifs="$IFS"; IFS='~'
+	  for cmd in $concat_cmds; do
+	    IFS="$save_ifs"
+	    $show "$cmd"
+	    $run eval "$cmd" || exit $?
+	  done
+	  IFS="$save_ifs"
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    cmds=$archive_expsym_cmds
+	  else
+	    cmds=$archive_cmds
+	    fi
+	  fi
+
+	  # Append the command to remove the reloadable object files
+	  # to the just-reset $cmds.
+	  eval cmds=\"\$cmds~\$rm $delfiles\"
+	fi
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $show "$cmd"
+	  $run eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$mode" = relink; then
+	      $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$mode" = relink; then
+	  $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      $show "${rm}r $gentop"
+	      $run ${rm}r "$gentop"
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+	    $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	$echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 ;;
+      esac
+
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	$echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+	$echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$xrpath"; then
+	$echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+	$echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+      fi
+
+      if test -n "$release"; then
+	$echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+      fi
+
+      case $output in
+      *.lo)
+	if test -n "$objs$old_deplibs"; then
+	  $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+	libobj="$output"
+	obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $run $rm $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      cmds=$reload_cmds
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+	IFS="$save_ifs"
+	eval cmd=\"$cmd\"
+	$show "$cmd"
+	$run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  $show "${rm}r $gentop"
+	  $run ${rm}r $gentop
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  $show "${rm}r $gentop"
+	  $run ${rm}r $gentop
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $run eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	cmds=$reload_cmds
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $show "$cmd"
+	  $run eval "$cmd" || exit $?
+	done
+	IFS="$save_ifs"
+      fi
+
+      if test -n "$gentop"; then
+	$show "${rm}r $gentop"
+	$run ${rm}r $gentop
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+      esac
+      if test -n "$vinfo"; then
+	$echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+      fi
+
+      if test -n "$release"; then
+	$echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+      fi
+
+      if test "$preload" = yes; then
+	if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+	   test "$dlopen_self_static" = unknown; then
+	  $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+	fi
+      fi
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+	finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+	;;
+      esac
+
+      case $host in
+      *darwin*)
+        # Don't allow lazy linking, it breaks C++ global constructors
+        if test "$tagname" = CXX ; then
+        compile_command="$compile_command ${wl}-bind_at_load"
+        finalize_command="$finalize_command ${wl}-bind_at_load"
+        fi
+        ;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    new_libs="$new_libs -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) new_libs="$new_libs $deplib" ;;
+	  esac
+	  ;;
+	*) new_libs="$new_libs $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      compile_command="$compile_command $compile_deplibs"
+      finalize_command="$finalize_command $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) perm_rpath="$perm_rpath $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+	  testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  *) dllsearchpath="$dllsearchpath:$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  *) dllsearchpath="$dllsearchpath:$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+      fi
+
+      dlsyms=
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	  dlsyms="${outputname}S.c"
+	else
+	  $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+	fi
+      fi
+
+      if test -n "$dlsyms"; then
+	case $dlsyms in
+	"") ;;
+	*.c)
+	  # Discover the nlist of each of the dlfiles.
+	  nlist="$output_objdir/${outputname}.nm"
+
+	  $show "$rm $nlist ${nlist}S ${nlist}T"
+	  $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+	  # Parse the name list into a source file.
+	  $show "creating $output_objdir/$dlsyms"
+
+	  test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+	  if test "$dlself" = yes; then
+	    $show "generating symbol list for \`$output'"
+
+	    test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+	    # Add our own program objects to the symbol list.
+	    progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	    for arg in $progfiles; do
+	      $show "extracting global C symbols from \`$arg'"
+	      $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+	    done
+
+	    if test -n "$exclude_expsyms"; then
+	      $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      $run eval '$mv "$nlist"T "$nlist"'
+	    fi
+
+	    if test -n "$export_symbols_regex"; then
+	      $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      $run eval '$mv "$nlist"T "$nlist"'
+	    fi
+
+	    # Prepare the list of exported symbols
+	    if test -z "$export_symbols"; then
+	      export_symbols="$output_objdir/$outputname.exp"
+	      $run $rm $export_symbols
+	      $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+              case $host in
+              *cygwin* | *mingw* )
+	        $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+		$run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+                ;;
+              esac
+	    else
+	      $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      $run eval 'mv "$nlist"T "$nlist"'
+              case $host in
+              *cygwin* | *mingw* )
+	        $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+		$run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+                ;;
+              esac
+	    fi
+	  fi
+
+	  for arg in $dlprefiles; do
+	    $show "extracting global C symbols from \`$arg'"
+	    name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+	    $run eval '$echo ": $name " >> "$nlist"'
+	    $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -z "$run"; then
+	    # Make sure we have at least an empty file.
+	    test -f "$nlist" || : > "$nlist"
+
+	    if test -n "$exclude_expsyms"; then
+	      $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	      $mv "$nlist"T "$nlist"
+	    fi
+
+	    # Try sorting and uniquifying the output.
+	    if grep -v "^: " < "$nlist" |
+		if sort -k 3 </dev/null >/dev/null 2>&1; then
+		  sort -k 3
+		else
+		  sort +2
+		fi |
+		uniq > "$nlist"S; then
+	      :
+	    else
+	      grep -v "^: " < "$nlist" > "$nlist"S
+	    fi
+
+	    if test -f "$nlist"S; then
+	      eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+	    else
+	      $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+	    fi
+
+	    $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+"
+
+	    case $host in
+	    *cygwin* | *mingw* )
+	  $echo >> "$output_objdir/$dlsyms" "\
+/* DATA imports from DLLs on WIN32 can't be const, because
+   runtime relocations are performed -- see ld's documentation
+   on pseudo-relocs */
+struct {
+"
+	      ;;
+	    * )
+	  $echo >> "$output_objdir/$dlsyms" "\
+const struct {
+"
+	      ;;
+	    esac
+
+
+	  $echo >> "$output_objdir/$dlsyms" "\
+  const char *name;
+  lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+	    $echo >> "$output_objdir/$dlsyms" "\
+  {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	  fi
+
+	  pic_flag_for_symtable=
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    case "$compile_command " in
+	    *" -static "*) ;;
+	    *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+	    esac;;
+	  *-*-hpux*)
+	    case "$compile_command " in
+	    *" -static "*) ;;
+	    *) pic_flag_for_symtable=" $pic_flag";;
+	    esac
+	  esac
+
+	  # Now compile the dynamic symbol file.
+	  $show "(cd $output_objdir && $LTCC  $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+	  $run eval '(cd $output_objdir && $LTCC  $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+	  # Clean up the generated files.
+	  $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+	  $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+	  # Transform the symbol file into the correct name.
+          case $host in
+          *cygwin* | *mingw* )
+            if test -f "$output_objdir/${outputname}.def" ; then
+              compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP`
+              finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP`
+            else
+              compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+              finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+             fi
+            ;;
+          * )
+            compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+            finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP`
+            ;;
+          esac
+	  ;;
+	*)
+	  $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+      else
+	# We keep going just in case the user didn't refer to
+	# lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+	# really was required.
+
+	# Nullify the symbol file.
+	compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP`
+	finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP`
+      fi
+
+      if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+	# Replace the output file specification.
+	compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	$show "$link_command"
+	$run eval "$link_command"
+	exit_status=$?
+
+	# Delete the generated files.
+	if test -n "$dlsyms"; then
+	  $show "$rm $output_objdir/${outputname}S.${objext}"
+	  $run $rm "$output_objdir/${outputname}S.${objext}"
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$shlibpath_var"; then
+	# We should set the shlibpath_var
+	rpath=
+	for dir in $temp_rpath; do
+	  case $dir in
+	  [\\/]* | [A-Za-z]:[\\/]*)
+	    # Absolute path.
+	    rpath="$rpath$dir:"
+	    ;;
+	  *)
+	    # Relative path: add a thisdir entry.
+	    rpath="$rpath\$thisdir/$dir:"
+	    ;;
+	  esac
+	done
+	temp_rpath="$rpath"
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$run $rm $output
+	# Link the executable and exit
+	$show "$link_command"
+	$run eval "$link_command" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	$echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+	$echo "$modename: \`$output' will be relinked during installation" 1>&2
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      $show "$link_command"
+      $run eval "$link_command" || exit $?
+
+      # Now create the wrapper script.
+      $show "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+	    relink_command="$var=\"$var_value\"; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP`
+      fi
+
+      # Quote $echo for shipping.
+      if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then
+	case $progpath in
+	[\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+	*) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+	esac
+	qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+      else
+	qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if our run command is non-null.
+      if test -z "$run"; then
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+            output_name=`basename $output`
+            output_path=`dirname $output`
+            cwrappersource="$output_path/$objdir/lt-$output_name.c"
+            cwrapper="$output_path/$output_name.exe"
+            $rm $cwrappersource $cwrapper
+            trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+
+   Currently, it simply execs the wrapper *script* "/bin/sh $output",
+   but could eventually absorb all of the scripts functionality and
+   exec $objdir/$outputname directly.
+*/
+EOF
+	    cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+        (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+/* -DDEBUG is fairly common in CFLAGS.  */
+#undef DEBUG
+#if defined DEBUGWRAPPER
+# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
+#else
+# define DEBUG(format, ...)
+#endif
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+const char * base_name (const char *name);
+char * find_executable(const char *wrapper);
+int    check_executable(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  DEBUG("(main) argv[0]      : %s\n",argv[0]);
+  DEBUG("(main) program_name : %s\n",program_name);
+  newargz = XMALLOC(char *, argc+2);
+EOF
+
+            cat >> $cwrappersource <<EOF
+  newargz[0] = (char *) xstrdup("$SHELL");
+EOF
+
+            cat >> $cwrappersource <<"EOF"
+  newargz[1] = find_executable(argv[0]);
+  if (newargz[1] == NULL)
+    lt_fatal("Couldn't find %s", argv[0]);
+  DEBUG("(main) found exe at : %s\n",newargz[1]);
+  /* we know the script has the same name, without the .exe */
+  /* so make sure newargz[1] doesn't end in .exe */
+  strendzap(newargz[1],".exe");
+  for (i = 1; i < argc; i++)
+    newargz[i+1] = xstrdup(argv[i]);
+  newargz[argc+1] = NULL;
+
+  for (i=0; i<argc+1; i++)
+  {
+    DEBUG("(main) newargz[%d]   : %s\n",i,newargz[i]);
+    ;
+  }
+
+EOF
+
+            case $host_os in
+              mingw*)
+                cat >> $cwrappersource <<EOF
+  execv("$SHELL",(char const **)newargz);
+EOF
+              ;;
+              *)
+                cat >> $cwrappersource <<EOF
+  execv("$SHELL",newargz);
+EOF
+              ;;
+            esac
+
+            cat >> $cwrappersource <<"EOF"
+  return 127;
+}
+
+void *
+xmalloc (size_t num)
+{
+  void * p = (void *) malloc (num);
+  if (!p)
+    lt_fatal ("Memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char)name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable(const char * path)
+{
+  struct stat st;
+
+  DEBUG("(check_executable)  : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!");
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0) &&
+      (
+        /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */
+#if defined (S_IXOTH)
+       ((st.st_mode & S_IXOTH) == S_IXOTH) ||
+#endif
+#if defined (S_IXGRP)
+       ((st.st_mode & S_IXGRP) == S_IXGRP) ||
+#endif
+       ((st.st_mode & S_IXUSR) == S_IXUSR))
+      )
+    return 1;
+  else
+    return 0;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise */
+char *
+find_executable (const char* wrapper)
+{
+  int has_slash = 0;
+  const char* p;
+  const char* p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char* concat_name;
+
+  DEBUG("(find_executable)  : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!");
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':')
+  {
+    concat_name = xstrdup (wrapper);
+    if (check_executable(concat_name))
+      return concat_name;
+    XFREE(concat_name);
+  }
+  else
+  {
+#endif
+    if (IS_DIR_SEPARATOR (wrapper[0]))
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable(concat_name))
+        return concat_name;
+      XFREE(concat_name);
+    }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+    {
+      has_slash = 1;
+      break;
+    }
+  if (!has_slash)
+  {
+    /* no slashes; search PATH */
+    const char* path = getenv ("PATH");
+    if (path != NULL)
+    {
+      for (p = path; *p; p = p_next)
+      {
+        const char* q;
+        size_t p_len;
+        for (q = p; *q; q++)
+          if (IS_PATH_SEPARATOR(*q))
+            break;
+        p_len = q - p;
+        p_next = (*q == '\0' ? q : q + 1);
+        if (p_len == 0)
+        {
+          /* empty path: current directory */
+          if (getcwd (tmp, LT_PATHMAX) == NULL)
+            lt_fatal ("getcwd failed");
+          tmp_len = strlen(tmp);
+          concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+          memcpy (concat_name, tmp, tmp_len);
+          concat_name[tmp_len] = '/';
+          strcpy (concat_name + tmp_len + 1, wrapper);
+        }
+        else
+        {
+          concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1);
+          memcpy (concat_name, p, p_len);
+          concat_name[p_len] = '/';
+          strcpy (concat_name + p_len + 1, wrapper);
+        }
+        if (check_executable(concat_name))
+          return concat_name;
+        XFREE(concat_name);
+      }
+    }
+    /* not found in PATH; assume curdir */
+  }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal ("getcwd failed");
+  tmp_len = strlen(tmp);
+  concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable(concat_name))
+    return concat_name;
+  XFREE(concat_name);
+  return NULL;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert(str != NULL);
+  assert(pat != NULL);
+
+  len = strlen(str);
+  patlen = strlen(pat);
+
+  if (patlen <= len)
+  {
+    str += len - patlen;
+    if (strcmp(str, pat) == 0)
+      *str = '\0';
+  }
+  return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+          const char * message, va_list ap)
+{
+  fprintf (stderr, "%s: %s: ", program_name, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+  va_end (ap);
+}
+EOF
+          # we should really use a build-platform specific compiler
+          # here, but OTOH, the wrappers (shell script and this C one)
+          # are only useful if you want to execute the "real" binary.
+          # Since the "real" binary is built for $host, then this
+          # wrapper might as well be built for $host, too.
+          $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource
+          ;;
+        esac
+        $rm $output
+        trap "$rm $output; exit $EXIT_FAILURE" 1 2 15
+
+	$echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE).
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variable:
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$echo are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    echo=\"$qecho\"
+    file=\"\$0\"
+    # Make sure echo works.
+    if test \"X\$1\" = X--no-reexec; then
+      # Discard the --no-reexec flag, and continue.
+      shift
+    elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+      # Yippee, \$echo works!
+      :
+    else
+      # Restart under the correct shell, and then maybe \$echo will work.
+      exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+    fi
+  fi\
+"
+	$echo >> $output "\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+  done
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $echo >> $output "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" || \\
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $mkdir \"\$progdir\"
+    else
+      $rm \"\$progdir/\$file\"
+    fi"
+
+	  $echo >> $output "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$echo \"\$relink_command_output\" >&2
+	$rm \"\$progdir/\$file\"
+	exit $EXIT_FAILURE
+      fi
+    fi
+
+    $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $rm \"\$progdir/\$program\";
+      $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $rm \"\$progdir/\$file\"
+  fi"
+	else
+	  $echo >> $output "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$echo >> $output "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $echo >> $output "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	# fixup the dll searchpath if we need to.
+	if test -n "$dllsearchpath"; then
+	  $echo >> $output "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	$echo >> $output "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+"
+	case $host in
+	# Backslashes separate directories on plain windows
+	*-*-mingw | *-*-os2*)
+	  $echo >> $output "\
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+	  ;;
+
+	*)
+	  $echo >> $output "\
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+	  ;;
+	esac
+	$echo >> $output "\
+      \$echo \"\$0: cannot exec \$program \$*\"
+      exit $EXIT_FAILURE
+    fi
+  else
+    # The program doesn't exist.
+    \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$echo \"This script is just a wrapper for \$program.\" 1>&2
+    $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit $EXIT_FAILURE
+  fi
+fi\
+"
+	chmod +x $output
+      fi
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	generated="$generated $gentop"
+
+	func_extract_archives $gentop $addlibs
+	oldobjs="$oldobjs $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+       cmds=$old_archive_from_new_cmds
+      else
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      $echo "X$obj" | $Xsed -e 's%^.*/%%'
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  $echo "copying selected object files to avoid basename conflicts..."
+
+	  if test -z "$gentop"; then
+	    gentop="$output_objdir/${outputname}x"
+	    generated="$generated $gentop"
+
+	    $show "${rm}r $gentop"
+	    $run ${rm}r "$gentop"
+	    $show "$mkdir $gentop"
+	    $run $mkdir "$gentop"
+	    exit_status=$?
+	    if test "$exit_status" -ne 0 && test ! -d "$gentop"; then
+	      exit $exit_status
+	    fi
+	  fi
+
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		counter=`expr $counter + 1`
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      $run ln "$obj" "$gentop/$newobj" ||
+	      $run cp "$obj" "$gentop/$newobj"
+	      oldobjs="$oldobjs $gentop/$newobj"
+	      ;;
+	    *) oldobjs="$oldobjs $obj" ;;
+	    esac
+	  done
+	fi
+
+	eval cmds=\"$old_archive_cmds\"
+
+	if len=`expr "X$cmds" : ".*"` &&
+	     test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  $echo "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  for obj in $save_oldobjs
+	  do
+	    oldobjs="$objlist $obj"
+	    objlist="$objlist $obj"
+	    eval test_cmds=\"$old_archive_cmds\"
+	    if len=`expr "X$test_cmds" : ".*" 2>/dev/null` &&
+	       test "$len" -le "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+	        RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+        eval cmd=\"$cmd\"
+	IFS="$save_ifs"
+	$show "$cmd"
+	$run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$generated"; then
+      $show "${rm}r$generated"
+      $run ${rm}r$generated
+    fi
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      $show "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+	  relink_command="$var=\"$var_value\"; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+
+      # Only create the output if not a dry run.
+      if test -z "$run"; then
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		if test -z "$libdir"; then
+		  $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+		  exit $EXIT_FAILURE
+		fi
+		newdependency_libs="$newdependency_libs $libdir/$name"
+		;;
+	      *) newdependency_libs="$newdependency_libs $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+	      eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+	      if test -z "$libdir"; then
+		$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+		exit $EXIT_FAILURE
+	      fi
+	      newdlfiles="$newdlfiles $libdir/$name"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+	      eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+	      if test -z "$libdir"; then
+		$echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+		exit $EXIT_FAILURE
+	      fi
+	      newdlprefiles="$newdlprefiles $libdir/$name"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlfiles="$newdlfiles $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlprefiles="$newdlprefiles $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $rm $output
+	  # place dlname in correct position for cygwin
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+	  esac
+	  $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $echo >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      fi
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+      $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool install mode
+  install)
+    modename="$modename: install"
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       $echo "X$nonopt" | grep shtool > /dev/null; then
+      # Aesthetically quote it.
+      arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+      case $arg in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	arg="\"$arg\""
+	;;
+      esac
+      install_prog="$arg "
+      arg="$1"
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+    case $arg in
+    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+      arg="\"$arg\""
+      ;;
+    esac
+    install_prog="$install_prog$arg"
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    for arg
+    do
+      if test -n "$dest"; then
+	files="$files $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f) 
+      	case " $install_prog " in
+	*[\\\ /]cp\ *) ;;
+	*) prev=$arg ;;
+	esac
+	;;
+      -g | -m | -o) prev=$arg ;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+      case $arg in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+	arg="\"$arg\""
+	;;
+      esac
+      install_prog="$install_prog $arg"
+    done
+
+    if test -z "$install_prog"; then
+      $echo "$modename: you must specify an install program" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prev' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	$echo "$modename: no file or destination specified" 1>&2
+      else
+	$echo "$modename: you must specify a destination" 1>&2
+      fi
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Strip any trailing slash from the destination.
+    dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$destdir" = "X$dest" && destdir=.
+      destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files
+      if test "$#" -gt 2; then
+	$echo "$modename: \`$dest' is not a directory" 1>&2
+	$echo "$help" 1>&2
+	exit $EXIT_FAILURE
+      fi
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	staticlibs="$staticlibs $file"
+	;;
+
+      *.la)
+	# Check to see that this really is a libtool archive.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+	else
+	  $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	library_names=
+	old_library=
+	relink_command=
+	# If there is no directory component, then add one.
+	case $file in
+	*/* | *\\*) . $file ;;
+	*) . ./$file ;;
+	esac
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) current_libdirs="$current_libdirs $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) future_libdirs="$future_libdirs $libdir" ;;
+	  esac
+	fi
+
+	dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+	test "X$dir" = "X$file/" && dir=
+	dir="$dir$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  if test "$inst_prefix_dir" = "$destdir"; then
+	    $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP`
+	  else
+	    relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP`
+	  fi
+
+	  $echo "$modename: warning: relinking \`$file'" 1>&2
+	  $show "$relink_command"
+	  if $run eval "$relink_command"; then :
+	  else
+	    $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names
+	if test -n "$2"; then
+	  realname="$2"
+	  shift
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  $show "$install_prog $dir/$srcname $destdir/$realname"
+	  $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+	  if test -n "$stripme" && test -n "$striplib"; then
+	    $show "$striplib $destdir/$realname"
+	    $run eval "$striplib $destdir/$realname" || exit $?
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      if test "$linkname" != "$realname"; then
+                $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+                $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })"
+	      fi
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  cmds=$postinstall_cmds
+	  save_ifs="$IFS"; IFS='~'
+	  for cmd in $cmds; do
+	    IFS="$save_ifs"
+	    eval cmd=\"$cmd\"
+	    $show "$cmd"
+	    $run eval "$cmd" || {
+	      lt_exit=$?
+
+	      # Restore the uninstalled library and exit
+	      if test "$mode" = relink; then
+		$run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)'
+	      fi
+
+	      exit $lt_exit
+	    }
+	  done
+	  IFS="$save_ifs"
+	fi
+
+	# Install the pseudo-library for information purposes.
+	name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+	instname="$dir/$name"i
+	$show "$install_prog $instname $destdir/$name"
+	$run eval "$install_prog $instname $destdir/$name" || exit $?
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	if test -n "$destfile"; then
+	  $show "$install_prog $file $destfile"
+	  $run eval "$install_prog $file $destfile" || exit $?
+	fi
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+	  $show "$install_prog $staticobj $staticdest"
+	  $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      file=`$echo $file|${SED} 's,.exe$,,'`
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin*|*mingw*)
+	    wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  # Note that it is not necessary on cygwin/mingw to append a dot to
+	  # foo even if both foo and FILE.exe exist: automatic-append-.exe
+	  # behavior happens only for exec(3), not for open(2)!  Also, sourcing
+	  # `FILE.' does not work on cygwin managed mounts.
+	  #
+	  # If there is no directory component, then add one.
+	  case $wrapper in
+	  */* | *\\*) . ${wrapper} ;;
+	  *) . ./${wrapper} ;;
+	  esac
+
+	  # Check the variables that should have been set.
+	  if test -z "$notinst_deplibs"; then
+	    $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      # If there is no directory component, then add one.
+	      case $lib in
+	      */* | *\\*) . $lib ;;
+	      *) . ./$lib ;;
+	      esac
+	    fi
+	    libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  # Note that it is not necessary on cygwin/mingw to append a dot to
+	  # foo even if both foo and FILE.exe exist: automatic-append-.exe
+	  # behavior happens only for exec(3), not for open(2)!  Also, sourcing
+	  # `FILE.' does not work on cygwin managed mounts.
+	  #
+	  # If there is no directory component, then add one.
+	  case $wrapper in
+	  */* | *\\*) . ${wrapper} ;;
+	  *) . ./${wrapper} ;;
+	  esac
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    if test "$finalize" = yes && test -z "$run"; then
+	      tmpdir=`func_mktempdir`
+	      file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+	      outputname="$tmpdir/$file"
+	      # Replace the output file specification.
+	      relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP`
+
+	      $show "$relink_command"
+	      if $run eval "$relink_command"; then :
+	      else
+		$echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+		${rm}r "$tmpdir"
+		continue
+	      fi
+	      file="$outputname"
+	    else
+	      $echo "$modename: warning: cannot relink \`$file'" 1>&2
+	    fi
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway 
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+	    ;;
+	  esac
+	  ;;
+	esac
+	$show "$install_prog$stripme $file $destfile"
+	$run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+	test -n "$outputname" && ${rm}r "$tmpdir"
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      $show "$install_prog $file $oldlib"
+      $run eval "$install_prog \$file \$oldlib" || exit $?
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	$show "$old_striplib $oldlib"
+	$run eval "$old_striplib $oldlib" || exit $?
+      fi
+
+      # Do each command in the postinstall commands.
+      cmds=$old_postinstall_cmds
+      save_ifs="$IFS"; IFS='~'
+      for cmd in $cmds; do
+	IFS="$save_ifs"
+	eval cmd=\"$cmd\"
+	$show "$cmd"
+	$run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$future_libdirs"; then
+      $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+    fi
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      test -n "$run" && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+    ;;
+
+  # libtool finish mode
+  finish)
+    modename="$modename: finish"
+    libdirs="$nonopt"
+    admincmds=
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+	libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  cmds=$finish_cmds
+	  save_ifs="$IFS"; IFS='~'
+	  for cmd in $cmds; do
+	    IFS="$save_ifs"
+	    eval cmd=\"$cmd\"
+	    $show "$cmd"
+	    $run eval "$cmd" || admincmds="$admincmds
+       $cmd"
+	  done
+	  IFS="$save_ifs"
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $run eval "$cmds" || admincmds="$admincmds
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    test "$show" = : && exit $EXIT_SUCCESS
+
+    $echo "X----------------------------------------------------------------------" | $Xsed
+    $echo "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      $echo "   $libdir"
+    done
+    $echo
+    $echo "If you ever happen to want to link against installed libraries"
+    $echo "in a given directory, LIBDIR, you must either use libtool, and"
+    $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+    $echo "flag during linking and do at least one of the following:"
+    if test -n "$shlibpath_var"; then
+      $echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      $echo "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      $echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      $echo "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      $echo "   - use the \`$flag' linker flag"
+    fi
+    if test -n "$admincmds"; then
+      $echo "   - have your system administrator run these commands:$admincmds"
+    fi
+    if test -f /etc/ld.so.conf; then
+      $echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    $echo
+    $echo "See any operating system documentation about shared libraries for"
+    $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+    $echo "X----------------------------------------------------------------------" | $Xsed
+    exit $EXIT_SUCCESS
+    ;;
+
+  # libtool execute mode
+  execute)
+    modename="$modename: execute"
+
+    # The first argument is the command name.
+    cmd="$nonopt"
+    if test -z "$cmd"; then
+      $echo "$modename: you must specify a COMMAND" 1>&2
+      $echo "$help"
+      exit $EXIT_FAILURE
+    fi
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      if test ! -f "$file"; then
+	$echo "$modename: \`$file' is not a file" 1>&2
+	$echo "$help" 1>&2
+	exit $EXIT_FAILURE
+      fi
+
+      dir=
+      case $file in
+      *.la)
+	# Check to see that this really is a libtool archive.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+	else
+	  $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+	  $echo "$help" 1>&2
+	  exit $EXIT_FAILURE
+	fi
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+
+	# If there is no directory component, then add one.
+	case $file in
+	*/* | *\\*) . $file ;;
+	*) . ./$file ;;
+	esac
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+	test "X$dir" = "X$file" && dir=.
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  dir="$dir/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+	    exit $EXIT_FAILURE
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+	test "X$dir" = "X$file" && dir=.
+	;;
+
+      *)
+	$echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -*) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	  # If there is no directory component, then add one.
+	  case $file in
+	  */* | *\\*) . $file ;;
+	  *) . ./$file ;;
+	  esac
+
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+      args="$args \"$file\""
+    done
+
+    if test -z "$run"; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+		$lt_var=\$save_$lt_var; export $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+	$echo "export $shlibpath_var"
+      fi
+      $echo "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+    ;;
+
+  # libtool clean and uninstall mode
+  clean | uninstall)
+    modename="$modename: $mode"
+    rm="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) rm="$rm $arg"; rmforce=yes ;;
+      -*) rm="$rm $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    if test -z "$rm"; then
+      $echo "$modename: you must specify an RM program" 1>&2
+      $echo "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    rmdirs=
+
+    origobjdir="$objdir"
+    for file in $files; do
+      dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+      if test "X$dir" = "X$file"; then
+	dir=.
+	objdir="$origobjdir"
+      else
+	objdir="$dir/$origobjdir"
+      fi
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+      test "$mode" = uninstall && objdir="$dir"
+
+      # Remember objdir for removal later, being careful to avoid duplicates
+      if test "$mode" = clean; then
+	case " $rmdirs " in
+	  *" $objdir "*) ;;
+	  *) rmdirs="$rmdirs $objdir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if (test -L "$file") >/dev/null 2>&1 \
+	|| (test -h "$file") >/dev/null 2>&1 \
+	|| test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	  . $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    rmfiles="$rmfiles $objdir/$n"
+	  done
+	  test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+	  case "$mode" in
+	  clean)
+	    case "  $library_names " in
+	    # "  " in the beginning catches empty $dlname
+	    *" $dlname "*) ;;
+	    *) rmfiles="$rmfiles $objdir/$dlname" ;;
+	    esac
+	     test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      cmds=$postuninstall_cmds
+	      save_ifs="$IFS"; IFS='~'
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd"
+		if test "$?" -ne 0 && test "$rmforce" != yes; then
+		  exit_status=1
+		fi
+	      done
+	      IFS="$save_ifs"
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      cmds=$old_postuninstall_cmds
+	      save_ifs="$IFS"; IFS='~'
+	      for cmd in $cmds; do
+		IFS="$save_ifs"
+		eval cmd=\"$cmd\"
+		$show "$cmd"
+		$run eval "$cmd"
+		if test "$?" -ne 0 && test "$rmforce" != yes; then
+		  exit_status=1
+		fi
+	      done
+	      IFS="$save_ifs"
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+	  # Read the .lo file
+	  . $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" \
+	     && test "$pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" \
+	     && test "$non_pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    file=`$echo $file|${SED} 's,.exe$,,'`
+	    noexename=`$echo $name|${SED} 's,.exe$,,'`
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    rmfiles="$rmfiles $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+	    relink_command=
+	    . $dir/$noexename
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      rmfiles="$rmfiles $objdir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      $show "$rm $rmfiles"
+      $run $rm $rmfiles || exit_status=1
+    done
+    objdir="$origobjdir"
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	$show "rmdir $dir"
+	$run rmdir $dir >/dev/null 2>&1
+      fi
+    done
+
+    exit $exit_status
+    ;;
+
+  "")
+    $echo "$modename: you must specify a MODE" 1>&2
+    $echo "$generic_help" 1>&2
+    exit $EXIT_FAILURE
+    ;;
+  esac
+
+  if test -z "$exec_cmd"; then
+    $echo "$modename: invalid operation mode \`$mode'" 1>&2
+    $echo "$generic_help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+  eval exec $exec_cmd
+  exit $EXIT_FAILURE
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+    --config          show all configuration variables
+    --debug           enable verbose shell tracing
+-n, --dry-run         display commands without modifying any files
+    --features        display basic configuration information and exit
+    --finish          same as \`--mode=finish'
+    --help            display this help message and exit
+    --mode=MODE       use operation mode MODE [default=inferred from MODE-ARGS]
+    --quiet           same as \`--silent'
+    --silent          don't print informational messages
+    --tag=TAG         use configuration variables from tag TAG
+    --version         print version information
+
+MODE must be one of the following:
+
+      clean           remove files from the build directory
+      compile         compile a source file into a libtool object
+      execute         automatically set library path, then run a program
+      finish          complete the installation of libtool libraries
+      install         install libraries or executables
+      link            create a library or an executable
+      uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool@gnu.org>."
+  exit $EXIT_SUCCESS
+  ;;
+
+clean)
+  $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+compile)
+  $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -prefer-pic       try to building PIC objects only
+  -prefer-non-pic   try to building non-PIC objects only
+  -static           always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+  ;;
+
+execute)
+  $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+  ;;
+
+finish)
+  $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+  ;;
+
+install)
+  $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+  ;;
+
+link)
+  $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+  ;;
+
+uninstall)
+  $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+*)
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$help" 1>&2
+  exit $EXIT_FAILURE
+  ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit $?
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+disable_libs=shared
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+disable_libs=static
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/third_party/libevent/mac/config.h b/third_party/libevent/mac/config.h
new file mode 100644
index 0000000..f73f0c6
--- /dev/null
+++ b/third_party/libevent/mac/config.h
@@ -0,0 +1,266 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+/* #undef DNS_USE_CPU_CLOCK_FOR_ID */
+
+/* Define is no secure id variant is available */
+#define DNS_USE_GETTIMEOFDAY_FOR_ID 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+/* #undef HAVE_CLOCK_GETTIME */
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+/* #undef HAVE_LIBRT */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/third_party/libevent/mac/event-config.h b/third_party/libevent/mac/event-config.h
new file mode 100644
index 0000000..4af575a
--- /dev/null
+++ b/third_party/libevent/mac/event-config.h
@@ -0,0 +1,274 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */
+
+/* Define is no secure id variant is available */
+#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+/* #undef _EVENT_HAVE_CLOCK_GETTIME */
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define _EVENT_HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define _EVENT_HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef _EVENT_HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+/* #undef _EVENT_HAVE_LIBRT */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define _EVENT_HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define _EVENT_HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/third_party/libevent/min_heap.h b/third_party/libevent/min_heap.h
new file mode 100644
index 0000000..4fc83c0
--- /dev/null
+++ b/third_party/libevent/min_heap.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _MIN_HEAP_H_
+#define _MIN_HEAP_H_
+
+#include "event.h"
+#include "evutil.h"
+
+typedef struct min_heap
+{
+    struct event** p;
+    unsigned n, a;
+} min_heap_t;
+
+static inline void           min_heap_ctor(min_heap_t* s);
+static inline void           min_heap_dtor(min_heap_t* s);
+static inline void           min_heap_elem_init(struct event* e);
+static inline int            min_heap_elem_greater(struct event *a, struct event *b);
+static inline int            min_heap_empty(min_heap_t* s);
+static inline unsigned       min_heap_size(min_heap_t* s);
+static inline struct event*  min_heap_top(min_heap_t* s);
+static inline int            min_heap_reserve(min_heap_t* s, unsigned n);
+static inline int            min_heap_push(min_heap_t* s, struct event* e);
+static inline struct event*  min_heap_pop(min_heap_t* s);
+static inline int            min_heap_erase(min_heap_t* s, struct event* e);
+static inline void           min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
+static inline void           min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
+
+int min_heap_elem_greater(struct event *a, struct event *b)
+{
+    return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
+}
+
+void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
+void min_heap_dtor(min_heap_t* s) { free(s->p); }
+void min_heap_elem_init(struct event* e) { e->min_heap_idx = -1; }
+int min_heap_empty(min_heap_t* s) { return 0u == s->n; }
+unsigned min_heap_size(min_heap_t* s) { return s->n; }
+struct event* min_heap_top(min_heap_t* s) { return s->n ? *s->p : 0; }
+
+int min_heap_push(min_heap_t* s, struct event* e)
+{
+    if(min_heap_reserve(s, s->n + 1))
+        return -1;
+    min_heap_shift_up_(s, s->n++, e);
+    return 0;
+}
+
+struct event* min_heap_pop(min_heap_t* s)
+{
+    if(s->n)
+    {
+        struct event* e = *s->p;
+        min_heap_shift_down_(s, 0u, s->p[--s->n]);
+        e->min_heap_idx = -1;
+        return e;
+    }
+    return 0;
+}
+
+int min_heap_erase(min_heap_t* s, struct event* e)
+{
+    if(((unsigned int)-1) != e->min_heap_idx)
+    {
+        struct event *last = s->p[--s->n];
+        unsigned parent = (e->min_heap_idx - 1) / 2;
+	/* we replace e with the last element in the heap.  We might need to
+	   shift it upward if it is less than its parent, or downward if it is
+	   greater than one or both its children. Since the children are known
+	   to be less than the parent, it can't need to shift both up and
+	   down. */
+        if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
+             min_heap_shift_up_(s, e->min_heap_idx, last);
+        else
+             min_heap_shift_down_(s, e->min_heap_idx, last);
+        e->min_heap_idx = -1;
+        return 0;
+    }
+    return -1;
+}
+
+int min_heap_reserve(min_heap_t* s, unsigned n)
+{
+    if(s->a < n)
+    {
+        struct event** p;
+        unsigned a = s->a ? s->a * 2 : 8;
+        if(a < n)
+            a = n;
+        if(!(p = (struct event**)realloc(s->p, a * sizeof *p)))
+            return -1;
+        s->p = p;
+        s->a = a;
+    }
+    return 0;
+}
+
+void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+    unsigned parent = (hole_index - 1) / 2;
+    while(hole_index && min_heap_elem_greater(s->p[parent], e))
+    {
+        (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
+        hole_index = parent;
+        parent = (hole_index - 1) / 2;
+    }
+    (s->p[hole_index] = e)->min_heap_idx = hole_index;
+}
+
+void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+    unsigned min_child = 2 * (hole_index + 1);
+    while(min_child <= s->n)
+	{
+        min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
+        if(!(min_heap_elem_greater(e, s->p[min_child])))
+            break;
+        (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
+        hole_index = min_child;
+        min_child = 2 * (hole_index + 1);
+	}
+    min_heap_shift_up_(s, hole_index,  e);
+}
+
+#endif /* _MIN_HEAP_H_ */
diff --git a/third_party/libevent/missing b/third_party/libevent/missing
new file mode 100644
index 0000000..e7ef83a
--- /dev/null
+++ b/third_party/libevent/missing
@@ -0,0 +1,360 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2003-09-02.23
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003 
+#   Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  autom4te)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+    test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo "#! /bin/sh"
+	echo "# Created by GNU Automake missing as a replacement of"
+	echo "#  $ $@"
+	echo "exit 0"
+	chmod +x $file
+	exit 1
+    fi
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f y.tab.h ]; then
+	echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+	 you modified a dependency of a manual page.  You may need the
+	 \`Help2man' package in order for those modifications to take
+	 effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+	file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+    fi
+    if [ -f "$file" ]; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo ".ab help2man is required to generate this page"
+	exit 1
+    fi
+    ;;
+
+  makeinfo)
+    if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+       # We have makeinfo, but it failed.
+       exit 1
+    fi
+
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  tar)
+    shift
+    if test -n "$run"; then
+      echo 1>&2 "ERROR: \`tar' requires --run"
+      exit 1
+    fi
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+	case "$firstarg" in
+	*o*)
+	    firstarg=`echo "$firstarg" | sed s/o//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+	case "$firstarg" in
+	*h*)
+	    firstarg=`echo "$firstarg" | sed s/h//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/third_party/libevent/mkinstalldirs b/third_party/libevent/mkinstalldirs
new file mode 100644
index 0000000..56d6671
--- /dev/null
+++ b/third_party/libevent/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs 11 2002-04-09 17:52:23Z nprovos $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/third_party/libevent/nacl_nonsfi/config.h b/third_party/libevent/nacl_nonsfi/config.h
new file mode 100644
index 0000000..60c9dfe
--- /dev/null
+++ b/third_party/libevent/nacl_nonsfi/config.h
@@ -0,0 +1,273 @@
+/* Copied from Linux version and changed the features according the PNaCl
+ * toolchain for the Non-SFI binary build, which is close to one under the
+ * linux/ directory. The built binary will be running under Linux directly,
+ * actually.
+ */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+/* #undef HAVE_SELECT */
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Note: The PNaCl toolchain prodives linux ABI's sigaction, named
+ * linux_sigaction() in native_client/src/nonsfi/linux/linux_sys_private.c,
+ * but newlib ABI sigaction() is not provided.
+ */
+/* Define to 1 if you have the `sigaction' function. */
+/* #undef HAVE_SIGACTION */
+
+/* Define to 1 if you have the `signal' function. */
+/* #undef HAVE_SIGNAL */
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+/* #undef HAVE_TIMERADD */
+
+/* Define if timerclear is defined in <sys/time.h> */
+/* #undef HAVE_TIMERCLEAR */
+
+/* Define if timercmp is defined in <sys/time.h> */
+/* #undef HAVE_TIMERCMP */
+
+/* Define if timerisset is defined in <sys/time.h> */
+/* #undef HAVE_TIMERISSET */
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+/* #undef HAVE_VASPRINTF */
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent_nacl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/third_party/libevent/nacl_nonsfi/event-config.h b/third_party/libevent/nacl_nonsfi/event-config.h
new file mode 100644
index 0000000..636ee80
--- /dev/null
+++ b/third_party/libevent/nacl_nonsfi/event-config.h
@@ -0,0 +1,280 @@
+/* Copied from Linux version and changed the features according the PNaCl
+ * toolchain for the Non-SFI binary build, which is close to one under the
+ * linux/ directory. The built binary will be running under Linux directly,
+ * actually.
+ */
+
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef _EVENT_HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+/* #undef _EVENT_HAVE_SELECT */
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+/* #undef _EVENT_HAVE_SIGACTION */
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef _EVENT_HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef _EVENT_HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERADD */
+
+/* Define if timerclear is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERCLEAR */
+
+/* Define if timercmp is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERCMP */
+
+/* Define if timerisset is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERISSET */
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent_nacl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+
+/* Work around for __native_client_nonsfi__ build. random() is not provided
+ * by the newlib-based PNaCl toolchain, so here we declare it. Please see also
+ * nacl_nonsfi/random.c for more details.
+ */
+long int random();
+
+#endif
diff --git a/third_party/libevent/nacl_nonsfi/random.c b/third_party/libevent/nacl_nonsfi/random.c
new file mode 100644
index 0000000..3577dd5
--- /dev/null
+++ b/third_party/libevent/nacl_nonsfi/random.c
@@ -0,0 +1,13 @@
+/* Copyright 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdlib.h>
+
+/* The newlib-based PNaCl toolchain does not provide random(). So, here we
+ * define it. It just redirects to the rand(), which is provided by the
+ * toolchain. */
+long int random() {
+  return rand();
+}
diff --git a/third_party/libevent/nacl_nonsfi/signal_stub.c b/third_party/libevent/nacl_nonsfi/signal_stub.c
new file mode 100644
index 0000000..8049030
--- /dev/null
+++ b/third_party/libevent/nacl_nonsfi/signal_stub.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * In nacl_helper_nonsfi, socketpair() is unavailable. In libevent, it is used
+ * to notify of a signal handler invocation, which is unused in
+ * nacl_helper_nonsfi. Unfortunately, there is no macro to disable the feature,
+ * so we stub out the signal module entirely.
+ */
+
+
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+/* config.h must be included before any other libevent header is included. */
+#include "config.h"
+
+#include "third_party/libevent/event-internal.h"
+#include "third_party/libevent/event.h"
+#include "third_party/libevent/evsignal.h"
+
+
+struct event_base *evsignal_base = 0;
+
+int evsignal_init(struct event_base *base) {
+  /* Do nothing, and return success. */
+  return 0;
+}
+
+void evsignal_process(struct event_base *base) {
+}
+
+int evsignal_add(struct event *event) {
+  /* Do nothing, and return an error. */
+  return -1;
+}
+
+int evsignal_del(struct event *event) {
+  /* Do nothing, and return an error. */
+  return -1;
+}
+
+void evsignal_dealloc(struct event_base *base) {
+}
diff --git a/third_party/libevent/poll.c b/third_party/libevent/poll.c
new file mode 100644
index 0000000..2aa245b
--- /dev/null
+++ b/third_party/libevent/poll.c
@@ -0,0 +1,379 @@
+/*	$OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
+
+/*
+ * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+struct pollop {
+	int event_count;		/* Highest number alloc */
+	int nfds;                       /* Size of event_* */
+	int fd_count;                   /* Size of idxplus1_by_fd */
+	struct pollfd *event_set;
+	struct event **event_r_back;
+	struct event **event_w_back;
+	int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
+			      * that 0 (which is easy to memset) can mean
+			      * "no entry." */
+};
+
+static void *poll_init	(struct event_base *);
+static int poll_add		(void *, struct event *);
+static int poll_del		(void *, struct event *);
+static int poll_dispatch	(struct event_base *, void *, struct timeval *);
+static void poll_dealloc	(struct event_base *, void *);
+
+const struct eventop pollops = {
+	"poll",
+	poll_init,
+	poll_add,
+	poll_del,
+	poll_dispatch,
+	poll_dealloc,
+    0
+};
+
+static void *
+poll_init(struct event_base *base)
+{
+	struct pollop *pollop;
+
+	/* Disable poll when this environment variable is set */
+	if (evutil_getenv("EVENT_NOPOLL"))
+		return (NULL);
+
+	if (!(pollop = calloc(1, sizeof(struct pollop))))
+		return (NULL);
+
+	evsignal_init(base);
+
+	return (pollop);
+}
+
+#ifdef CHECK_INVARIANTS
+static void
+poll_check_ok(struct pollop *pop)
+{
+	int i, idx;
+	struct event *ev;
+
+	for (i = 0; i < pop->fd_count; ++i) {
+		idx = pop->idxplus1_by_fd[i]-1;
+		if (idx < 0)
+			continue;
+		assert(pop->event_set[idx].fd == i);
+		if (pop->event_set[idx].events & POLLIN) {
+			ev = pop->event_r_back[idx];
+			assert(ev);
+			assert(ev->ev_events & EV_READ);
+			assert(ev->ev_fd == i);
+		}
+		if (pop->event_set[idx].events & POLLOUT) {
+			ev = pop->event_w_back[idx];
+			assert(ev);
+			assert(ev->ev_events & EV_WRITE);
+			assert(ev->ev_fd == i);
+		}
+	}
+	for (i = 0; i < pop->nfds; ++i) {
+		struct pollfd *pfd = &pop->event_set[i];
+		assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
+	}
+}
+#else
+#define poll_check_ok(pop)
+#endif
+
+static int
+poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	int res, i, j, msec = -1, nfds;
+	struct pollop *pop = arg;
+
+	poll_check_ok(pop);
+
+	if (tv != NULL)
+		msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+	nfds = pop->nfds;
+	res = poll(pop->event_set, nfds, msec);
+
+	if (res == -1) {
+		if (errno != EINTR) {
+                        event_warn("poll");
+			return (-1);
+		}
+
+		evsignal_process(base);
+		return (0);
+	} else if (base->sig.evsignal_caught) {
+		evsignal_process(base);
+	}
+
+	event_debug(("%s: poll reports %d", __func__, res));
+
+	if (res == 0 || nfds == 0)
+		return (0);
+
+	i = random() % nfds;
+	for (j = 0; j < nfds; j++) {
+		struct event *r_ev = NULL, *w_ev = NULL;
+		int what;
+		if (++i == nfds)
+			i = 0;
+		what = pop->event_set[i].revents;
+
+		if (!what)
+			continue;
+
+		res = 0;
+
+		/* If the file gets closed notify */
+		if (what & (POLLHUP|POLLERR))
+			what |= POLLIN|POLLOUT;
+		if (what & POLLIN) {
+			res |= EV_READ;
+			r_ev = pop->event_r_back[i];
+		}
+		if (what & POLLOUT) {
+			res |= EV_WRITE;
+			w_ev = pop->event_w_back[i];
+		}
+		if (res == 0)
+			continue;
+
+		if (r_ev && (res & r_ev->ev_events)) {
+			event_active(r_ev, res & r_ev->ev_events, 1);
+		}
+		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
+			event_active(w_ev, res & w_ev->ev_events, 1);
+		}
+	}
+
+	return (0);
+}
+
+static int
+poll_add(void *arg, struct event *ev)
+{
+	struct pollop *pop = arg;
+	struct pollfd *pfd = NULL;
+	int i;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_add(ev));
+	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
+		return (0);
+
+	poll_check_ok(pop);
+	if (pop->nfds + 1 >= pop->event_count) {
+		struct pollfd *tmp_event_set;
+		struct event **tmp_event_r_back;
+		struct event **tmp_event_w_back;
+		int tmp_event_count;
+
+		if (pop->event_count < 32)
+			tmp_event_count = 32;
+		else
+			tmp_event_count = pop->event_count * 2;
+
+		/* We need more file descriptors */
+		tmp_event_set = realloc(pop->event_set,
+				 tmp_event_count * sizeof(struct pollfd));
+		if (tmp_event_set == NULL) {
+			event_warn("realloc");
+			return (-1);
+		}
+		pop->event_set = tmp_event_set;
+
+		tmp_event_r_back = realloc(pop->event_r_back,
+			    tmp_event_count * sizeof(struct event *));
+		if (tmp_event_r_back == NULL) {
+			/* event_set overallocated; that's okay. */
+			event_warn("realloc");
+			return (-1);
+		}
+		pop->event_r_back = tmp_event_r_back;
+
+		tmp_event_w_back = realloc(pop->event_w_back,
+			    tmp_event_count * sizeof(struct event *));
+		if (tmp_event_w_back == NULL) {
+			/* event_set and event_r_back overallocated; that's
+			 * okay. */
+			event_warn("realloc");
+			return (-1);
+		}
+		pop->event_w_back = tmp_event_w_back;
+
+		pop->event_count = tmp_event_count;
+	}
+	if (ev->ev_fd >= pop->fd_count) {
+		int *tmp_idxplus1_by_fd;
+		int new_count;
+		if (pop->fd_count < 32)
+			new_count = 32;
+		else
+			new_count = pop->fd_count * 2;
+		while (new_count <= ev->ev_fd)
+			new_count *= 2;
+		tmp_idxplus1_by_fd =
+			realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
+		if (tmp_idxplus1_by_fd == NULL) {
+			event_warn("realloc");
+			return (-1);
+		}
+		pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
+		memset(pop->idxplus1_by_fd + pop->fd_count,
+		       0, sizeof(int)*(new_count - pop->fd_count));
+		pop->fd_count = new_count;
+	}
+
+	i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
+	if (i >= 0) {
+		pfd = &pop->event_set[i];
+	} else {
+		i = pop->nfds++;
+		pfd = &pop->event_set[i];
+		pfd->events = 0;
+		pfd->fd = ev->ev_fd;
+		pop->event_w_back[i] = pop->event_r_back[i] = NULL;
+		pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
+	}
+
+	pfd->revents = 0;
+	if (ev->ev_events & EV_WRITE) {
+		pfd->events |= POLLOUT;
+		pop->event_w_back[i] = ev;
+	}
+	if (ev->ev_events & EV_READ) {
+		pfd->events |= POLLIN;
+		pop->event_r_back[i] = ev;
+	}
+	poll_check_ok(pop);
+
+	return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+static int
+poll_del(void *arg, struct event *ev)
+{
+	struct pollop *pop = arg;
+	struct pollfd *pfd = NULL;
+	int i;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_del(ev));
+
+	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
+		return (0);
+
+	poll_check_ok(pop);
+	i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
+	if (i < 0)
+		return (-1);
+
+	/* Do we still want to read or write? */
+	pfd = &pop->event_set[i];
+	if (ev->ev_events & EV_READ) {
+		pfd->events &= ~POLLIN;
+		pop->event_r_back[i] = NULL;
+	}
+	if (ev->ev_events & EV_WRITE) {
+		pfd->events &= ~POLLOUT;
+		pop->event_w_back[i] = NULL;
+	}
+	poll_check_ok(pop);
+	if (pfd->events)
+		/* Another event cares about that fd. */
+		return (0);
+
+	/* Okay, so we aren't interested in that fd anymore. */
+	pop->idxplus1_by_fd[ev->ev_fd] = 0;
+
+	--pop->nfds;
+	if (i != pop->nfds) {
+		/* 
+		 * Shift the last pollfd down into the now-unoccupied
+		 * position.
+		 */
+		memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
+		       sizeof(struct pollfd));
+		pop->event_r_back[i] = pop->event_r_back[pop->nfds];
+		pop->event_w_back[i] = pop->event_w_back[pop->nfds];
+		pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
+	}
+
+	poll_check_ok(pop);
+	return (0);
+}
+
+static void
+poll_dealloc(struct event_base *base, void *arg)
+{
+	struct pollop *pop = arg;
+
+	evsignal_dealloc(base);
+	if (pop->event_set)
+		free(pop->event_set);
+	if (pop->event_r_back)
+		free(pop->event_r_back);
+	if (pop->event_w_back)
+		free(pop->event_w_back);
+	if (pop->idxplus1_by_fd)
+		free(pop->idxplus1_by_fd);
+
+	memset(pop, 0, sizeof(struct pollop));
+	free(pop);
+}
diff --git a/third_party/libevent/sample/Makefile.am b/third_party/libevent/sample/Makefile.am
new file mode 100644
index 0000000..2f4e26e
--- /dev/null
+++ b/third_party/libevent/sample/Makefile.am
@@ -0,0 +1,14 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+LDADD = ../libevent.la
+AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat
+
+noinst_PROGRAMS = event-test time-test signal-test
+
+event_test_sources = event-test.c
+time_test_sources = time-test.c
+signal_test_sources = signal-test.c
+
+verify:
+
+DISTCLEANFILES = *~
diff --git a/third_party/libevent/sample/Makefile.in b/third_party/libevent/sample/Makefile.in
new file mode 100644
index 0000000..793752a
--- /dev/null
+++ b/third_party/libevent/sample/Makefile.in
@@ -0,0 +1,442 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = event-test$(EXEEXT) time-test$(EXEEXT) \
+	signal-test$(EXEEXT)
+subdir = sample
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+event_test_SOURCES = event-test.c
+event_test_OBJECTS = event-test.$(OBJEXT)
+event_test_LDADD = $(LDADD)
+event_test_DEPENDENCIES = ../libevent.la
+signal_test_SOURCES = signal-test.c
+signal_test_OBJECTS = signal-test.$(OBJEXT)
+signal_test_LDADD = $(LDADD)
+signal_test_DEPENDENCIES = ../libevent.la
+time_test_SOURCES = time-test.c
+time_test_OBJECTS = time-test.$(OBJEXT)
+time_test_LDADD = $(LDADD)
+time_test_DEPENDENCIES = ../libevent.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = event-test.c signal-test.c time-test.c
+DIST_SOURCES = event-test.c signal-test.c time-test.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+LDADD = ../libevent.la
+AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat
+event_test_sources = event-test.c
+time_test_sources = time-test.c
+signal_test_sources = signal-test.c
+DISTCLEANFILES = *~
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  sample/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  sample/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+event-test$(EXEEXT): $(event_test_OBJECTS) $(event_test_DEPENDENCIES) 
+	@rm -f event-test$(EXEEXT)
+	$(LINK) $(event_test_OBJECTS) $(event_test_LDADD) $(LIBS)
+signal-test$(EXEEXT): $(signal_test_OBJECTS) $(signal_test_DEPENDENCIES) 
+	@rm -f signal-test$(EXEEXT)
+	$(LINK) $(signal_test_OBJECTS) $(signal_test_LDADD) $(LIBS)
+time-test$(EXEEXT): $(time_test_OBJECTS) $(time_test_DEPENDENCIES) 
+	@rm -f time-test$(EXEEXT)
+	$(LINK) $(time_test_OBJECTS) $(time_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(COMPILE) -c $<
+
+.c.obj:
+	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstPROGRAMS ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+verify:
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/libevent/sample/event-test.c b/third_party/libevent/sample/event-test.c
new file mode 100644
index 0000000..2c6cb93
--- /dev/null
+++ b/third_party/libevent/sample/event-test.c
@@ -0,0 +1,139 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#include <windows.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+
+static void
+fifo_read(int fd, short event, void *arg)
+{
+	char buf[255];
+	int len;
+	struct event *ev = arg;
+#ifdef WIN32
+	DWORD dwBytesRead;
+#endif
+
+	/* Reschedule this event */
+	event_add(ev, NULL);
+
+	fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
+		fd, event, arg);
+#ifdef WIN32
+	len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);
+
+	// Check for end of file. 
+	if(len && dwBytesRead == 0) {
+		fprintf(stderr, "End Of File");
+		event_del(ev);
+		return;
+	}
+
+	buf[dwBytesRead] = '\0';
+#else
+	len = read(fd, buf, sizeof(buf) - 1);
+
+	if (len == -1) {
+		perror("read");
+		return;
+	} else if (len == 0) {
+		fprintf(stderr, "Connection closed\n");
+		return;
+	}
+
+	buf[len] = '\0';
+#endif
+	fprintf(stdout, "Read: %s\n", buf);
+}
+
+int
+main (int argc, char **argv)
+{
+	struct event evfifo;
+#ifdef WIN32
+	HANDLE socket;
+	// Open a file. 
+	socket = CreateFile("test.txt",     // open File 
+			GENERIC_READ,                 // open for reading 
+			0,                            // do not share 
+			NULL,                         // no security 
+			OPEN_EXISTING,                // existing file only 
+			FILE_ATTRIBUTE_NORMAL,        // normal file 
+			NULL);                        // no attr. template 
+
+	if(socket == INVALID_HANDLE_VALUE)
+		return 1;
+
+#else
+	struct stat st;
+	const char *fifo = "event.fifo";
+	int socket;
+ 
+	if (lstat (fifo, &st) == 0) {
+		if ((st.st_mode & S_IFMT) == S_IFREG) {
+			errno = EEXIST;
+			perror("lstat");
+			exit (1);
+		}
+	}
+
+	unlink (fifo);
+	if (mkfifo (fifo, 0600) == -1) {
+		perror("mkfifo");
+		exit (1);
+	}
+
+	/* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
+#ifdef __linux
+	socket = open (fifo, O_RDWR | O_NONBLOCK, 0);
+#else
+	socket = open (fifo, O_RDONLY | O_NONBLOCK, 0);
+#endif
+
+	if (socket == -1) {
+		perror("open");
+		exit (1);
+	}
+
+	fprintf(stderr, "Write data to %s\n", fifo);
+#endif
+	/* Initalize the event library */
+	event_init();
+
+	/* Initalize one event */
+#ifdef WIN32
+	event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo);
+#else
+	event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
+#endif
+
+	/* Add it to the active events, without a timeout */
+	event_add(&evfifo, NULL);
+	
+	event_dispatch();
+#ifdef WIN32
+	CloseHandle(socket);
+#endif
+	return (0);
+}
+
diff --git a/third_party/libevent/sample/signal-test.c b/third_party/libevent/sample/signal-test.c
new file mode 100644
index 0000000..9a131cb
--- /dev/null
+++ b/third_party/libevent/sample/signal-test.c
@@ -0,0 +1,63 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o signal-test \
+ *   signal-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#include <windows.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+
+int called = 0;
+
+static void
+signal_cb(int fd, short event, void *arg)
+{
+	struct event *signal = arg;
+
+	printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal));
+
+	if (called >= 2)
+		event_del(signal);
+	
+	called++;
+}
+
+int
+main (int argc, char **argv)
+{
+	struct event signal_int;
+ 
+	/* Initalize the event library */
+	event_init();
+
+	/* Initalize one event */
+	event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,
+	    &signal_int);
+
+	event_add(&signal_int, NULL);
+
+	event_dispatch();
+
+	return (0);
+}
+
diff --git a/third_party/libevent/sample/time-test.c b/third_party/libevent/sample/time-test.c
new file mode 100644
index 0000000..069d4f8
--- /dev/null
+++ b/third_party/libevent/sample/time-test.c
@@ -0,0 +1,70 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#endif
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+int lasttime;
+
+static void
+timeout_cb(int fd, short event, void *arg)
+{
+	struct timeval tv;
+	struct event *timeout = arg;
+	int newtime = time(NULL);
+
+	printf("%s: called at %d: %d\n", __func__, newtime,
+	    newtime - lasttime);
+	lasttime = newtime;
+
+	evutil_timerclear(&tv);
+	tv.tv_sec = 2;
+	event_add(timeout, &tv);
+}
+
+int
+main (int argc, char **argv)
+{
+	struct event timeout;
+	struct timeval tv;
+ 
+	/* Initalize the event library */
+	event_init();
+
+	/* Initalize one event */
+	evtimer_set(&timeout, timeout_cb, &timeout);
+
+	evutil_timerclear(&tv);
+	tv.tv_sec = 2;
+	event_add(&timeout, &tv);
+
+	lasttime = time(NULL);
+	
+	event_dispatch();
+
+	return (0);
+}
+
diff --git a/third_party/libevent/select.c b/third_party/libevent/select.c
new file mode 100644
index 0000000..3f73331
--- /dev/null
+++ b/third_party/libevent/select.c
@@ -0,0 +1,364 @@
+/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/queue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
+
+#include "event.h"
+#include "evutil.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+#ifndef howmany
+#define        howmany(x, y)   (((x)+((y)-1))/(y))
+#endif
+
+#ifndef _EVENT_HAVE_FD_MASK
+/* This type is mandatory, but Android doesn't define it. */
+#undef NFDBITS
+#define NFDBITS (sizeof(long)*8)
+typedef unsigned long fd_mask;
+#endif
+
+struct selectop {
+	int event_fds;		/* Highest fd in fd set */
+	int event_fdsz;
+	fd_set *event_readset_in;
+	fd_set *event_writeset_in;
+	fd_set *event_readset_out;
+	fd_set *event_writeset_out;
+	struct event **event_r_by_fd;
+	struct event **event_w_by_fd;
+};
+
+static void *select_init	(struct event_base *);
+static int select_add		(void *, struct event *);
+static int select_del		(void *, struct event *);
+static int select_dispatch	(struct event_base *, void *, struct timeval *);
+static void select_dealloc     (struct event_base *, void *);
+
+const struct eventop selectops = {
+	"select",
+	select_init,
+	select_add,
+	select_del,
+	select_dispatch,
+	select_dealloc,
+	0
+};
+
+static int select_resize(struct selectop *sop, int fdsz);
+
+static void *
+select_init(struct event_base *base)
+{
+	struct selectop *sop;
+
+	/* Disable select when this environment variable is set */
+	if (evutil_getenv("EVENT_NOSELECT"))
+		return (NULL);
+
+	if (!(sop = calloc(1, sizeof(struct selectop))))
+		return (NULL);
+
+	select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask));
+
+	evsignal_init(base);
+
+	return (sop);
+}
+
+#ifdef CHECK_INVARIANTS
+static void
+check_selectop(struct selectop *sop)
+{
+	int i;
+	for (i = 0; i <= sop->event_fds; ++i) {
+		if (FD_ISSET(i, sop->event_readset_in)) {
+			assert(sop->event_r_by_fd[i]);
+			assert(sop->event_r_by_fd[i]->ev_events & EV_READ);
+			assert(sop->event_r_by_fd[i]->ev_fd == i);
+		} else {
+			assert(! sop->event_r_by_fd[i]);
+		}
+		if (FD_ISSET(i, sop->event_writeset_in)) {
+			assert(sop->event_w_by_fd[i]);
+			assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE);
+			assert(sop->event_w_by_fd[i]->ev_fd == i);
+		} else {
+			assert(! sop->event_w_by_fd[i]);
+		}
+	}
+
+}
+#else
+#define check_selectop(sop) do { (void) sop; } while (0)
+#endif
+
+static int
+select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	int res, i, j;
+	struct selectop *sop = arg;
+
+	check_selectop(sop);
+
+	memcpy(sop->event_readset_out, sop->event_readset_in,
+	       sop->event_fdsz);
+	memcpy(sop->event_writeset_out, sop->event_writeset_in,
+	       sop->event_fdsz);
+
+	res = select(sop->event_fds + 1, sop->event_readset_out,
+	    sop->event_writeset_out, NULL, tv);
+
+	check_selectop(sop);
+
+	if (res == -1) {
+		if (errno != EINTR) {
+			event_warn("select");
+			return (-1);
+		}
+
+		evsignal_process(base);
+		return (0);
+	} else if (base->sig.evsignal_caught) {
+		evsignal_process(base);
+	}
+
+	event_debug(("%s: select reports %d", __func__, res));
+
+	check_selectop(sop);
+	i = random() % (sop->event_fds+1);
+	for (j = 0; j <= sop->event_fds; ++j) {
+		struct event *r_ev = NULL, *w_ev = NULL;
+		if (++i >= sop->event_fds+1)
+			i = 0;
+
+		res = 0;
+		if (FD_ISSET(i, sop->event_readset_out)) {
+			r_ev = sop->event_r_by_fd[i];
+			res |= EV_READ;
+		}
+		if (FD_ISSET(i, sop->event_writeset_out)) {
+			w_ev = sop->event_w_by_fd[i];
+			res |= EV_WRITE;
+		}
+		if (r_ev && (res & r_ev->ev_events)) {
+			event_active(r_ev, res & r_ev->ev_events, 1);
+		}
+		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
+			event_active(w_ev, res & w_ev->ev_events, 1);
+		}
+	}
+	check_selectop(sop);
+
+	return (0);
+}
+
+
+static int
+select_resize(struct selectop *sop, int fdsz)
+{
+	int n_events, n_events_old;
+
+	fd_set *readset_in = NULL;
+	fd_set *writeset_in = NULL;
+	fd_set *readset_out = NULL;
+	fd_set *writeset_out = NULL;
+	struct event **r_by_fd = NULL;
+	struct event **w_by_fd = NULL;
+
+	n_events = (fdsz/sizeof(fd_mask)) * NFDBITS;
+	n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS;
+
+	if (sop->event_readset_in)
+		check_selectop(sop);
+
+	if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL)
+		goto error;
+	sop->event_readset_in = readset_in;
+	if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL)
+		goto error;
+	sop->event_readset_out = readset_out;
+	if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL)
+		goto error;
+	sop->event_writeset_in = writeset_in;
+	if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL)
+		goto error;
+	sop->event_writeset_out = writeset_out;
+	if ((r_by_fd = realloc(sop->event_r_by_fd,
+		 n_events*sizeof(struct event*))) == NULL)
+		goto error;
+	sop->event_r_by_fd = r_by_fd;
+	if ((w_by_fd = realloc(sop->event_w_by_fd,
+		 n_events * sizeof(struct event*))) == NULL)
+		goto error;
+	sop->event_w_by_fd = w_by_fd;
+
+	memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
+	    fdsz - sop->event_fdsz);
+	memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
+	    fdsz - sop->event_fdsz);
+	memset(sop->event_r_by_fd + n_events_old, 0,
+	    (n_events-n_events_old) * sizeof(struct event*));
+	memset(sop->event_w_by_fd + n_events_old, 0,
+	    (n_events-n_events_old) * sizeof(struct event*));
+
+	sop->event_fdsz = fdsz;
+	check_selectop(sop);
+
+	return (0);
+
+ error:
+	event_warn("malloc");
+	return (-1);
+}
+
+
+static int
+select_add(void *arg, struct event *ev)
+{
+	struct selectop *sop = arg;
+
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_add(ev));
+
+	check_selectop(sop);
+	/*
+	 * Keep track of the highest fd, so that we can calculate the size
+	 * of the fd_sets for select(2)
+	 */
+	if (sop->event_fds < ev->ev_fd) {
+		int fdsz = sop->event_fdsz;
+
+		if (fdsz < sizeof(fd_mask))
+			fdsz = sizeof(fd_mask);
+
+		while (fdsz <
+		    (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask)))
+			fdsz *= 2;
+
+		if (fdsz != sop->event_fdsz) {
+			if (select_resize(sop, fdsz)) {
+				check_selectop(sop);
+				return (-1);
+			}
+		}
+
+		sop->event_fds = ev->ev_fd;
+	}
+
+	if (ev->ev_events & EV_READ) {
+		FD_SET(ev->ev_fd, sop->event_readset_in);
+		sop->event_r_by_fd[ev->ev_fd] = ev;
+	}
+	if (ev->ev_events & EV_WRITE) {
+		FD_SET(ev->ev_fd, sop->event_writeset_in);
+		sop->event_w_by_fd[ev->ev_fd] = ev;
+	}
+	check_selectop(sop);
+
+	return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+static int
+select_del(void *arg, struct event *ev)
+{
+	struct selectop *sop = arg;
+
+	check_selectop(sop);
+	if (ev->ev_events & EV_SIGNAL)
+		return (evsignal_del(ev));
+
+	if (sop->event_fds < ev->ev_fd) {
+		check_selectop(sop);
+		return (0);
+	}
+
+	if (ev->ev_events & EV_READ) {
+		FD_CLR(ev->ev_fd, sop->event_readset_in);
+		sop->event_r_by_fd[ev->ev_fd] = NULL;
+	}
+
+	if (ev->ev_events & EV_WRITE) {
+		FD_CLR(ev->ev_fd, sop->event_writeset_in);
+		sop->event_w_by_fd[ev->ev_fd] = NULL;
+	}
+
+	check_selectop(sop);
+	return (0);
+}
+
+static void
+select_dealloc(struct event_base *base, void *arg)
+{
+	struct selectop *sop = arg;
+
+	evsignal_dealloc(base);
+	if (sop->event_readset_in)
+		free(sop->event_readset_in);
+	if (sop->event_writeset_in)
+		free(sop->event_writeset_in);
+	if (sop->event_readset_out)
+		free(sop->event_readset_out);
+	if (sop->event_writeset_out)
+		free(sop->event_writeset_out);
+	if (sop->event_r_by_fd)
+		free(sop->event_r_by_fd);
+	if (sop->event_w_by_fd)
+		free(sop->event_w_by_fd);
+
+	memset(sop, 0, sizeof(struct selectop));
+	free(sop);
+}
diff --git a/third_party/libevent/signal.c b/third_party/libevent/signal.c
new file mode 100644
index 0000000..74fa23f
--- /dev/null
+++ b/third_party/libevent/signal.c
@@ -0,0 +1,357 @@
+/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <assert.h>
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "evutil.h"
+#include "log.h"
+
+struct event_base *evsignal_base = NULL;
+
+static void evsignal_handler(int sig);
+
+/* Callback for when the signal handler write a byte to our signaling socket */
+static void
+evsignal_cb(int fd, short what, void *arg)
+{
+	static char signals[1];
+#ifdef WIN32
+	SSIZE_T n;
+#else
+	ssize_t n;
+#endif
+
+	n = recv(fd, signals, sizeof(signals), 0);
+	if (n == -1)
+		event_err(1, "%s: read", __func__);
+}
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+        if (fcntl(x, F_SETFD, 1) == -1) \
+                event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
+#else
+#define FD_CLOSEONEXEC(x)
+#endif
+
+int
+evsignal_init(struct event_base *base)
+{
+	int i;
+
+	/* 
+	 * Our signal handler is going to write to one end of the socket
+	 * pair to wake up our event loop.  The event loop then scans for
+	 * signals that got delivered.
+	 */
+	if (evutil_socketpair(
+		    AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
+#ifdef WIN32
+		/* Make this nonfatal on win32, where sometimes people
+		   have localhost firewalled. */
+		event_warn("%s: socketpair", __func__);
+#else
+		event_err(1, "%s: socketpair", __func__);
+#endif
+		return -1;
+	}
+
+	FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);
+	FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);
+	base->sig.sh_old = NULL;
+	base->sig.sh_old_max = 0;
+	base->sig.evsignal_caught = 0;
+	memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
+	/* initialize the queues for all events */
+	for (i = 0; i < NSIG; ++i)
+		TAILQ_INIT(&base->sig.evsigevents[i]);
+
+        evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
+
+	event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
+		EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
+	base->sig.ev_signal.ev_base = base;
+	base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
+
+	return 0;
+}
+
+/* Helper: set the signal handler for evsignal to handler in base, so that
+ * we can restore the original handler when we clear the current one. */
+int
+_evsignal_set_handler(struct event_base *base,
+		      int evsignal, void (*handler)(int))
+{
+#ifdef HAVE_SIGACTION
+	struct sigaction sa;
+#else
+	ev_sighandler_t sh;
+#endif
+	struct evsignal_info *sig = &base->sig;
+	void *p;
+
+	/*
+	 * resize saved signal handler array up to the highest signal number.
+	 * a dynamic array is used to keep footprint on the low side.
+	 */
+	if (evsignal >= sig->sh_old_max) {
+		int new_max = evsignal + 1;
+		event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
+			    __func__, evsignal, sig->sh_old_max));
+		p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
+		if (p == NULL) {
+			event_warn("realloc");
+			return (-1);
+		}
+
+		memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
+		    0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
+
+		sig->sh_old_max = new_max;
+		sig->sh_old = p;
+	}
+
+	/* allocate space for previous handler out of dynamic array */
+	sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]);
+	if (sig->sh_old[evsignal] == NULL) {
+		event_warn("malloc");
+		return (-1);
+	}
+
+	/* save previous handler and setup new handler */
+#ifdef HAVE_SIGACTION
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = handler;
+	sa.sa_flags |= SA_RESTART;
+	sigfillset(&sa.sa_mask);
+
+	if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
+		event_warn("sigaction");
+		free(sig->sh_old[evsignal]);
+		return (-1);
+	}
+#else
+	if ((sh = signal(evsignal, handler)) == SIG_ERR) {
+		event_warn("signal");
+		free(sig->sh_old[evsignal]);
+		return (-1);
+	}
+	*sig->sh_old[evsignal] = sh;
+#endif
+
+	return (0);
+}
+
+int
+evsignal_add(struct event *ev)
+{
+	int evsignal;
+	struct event_base *base = ev->ev_base;
+	struct evsignal_info *sig = &ev->ev_base->sig;
+
+	if (ev->ev_events & (EV_READ|EV_WRITE))
+		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
+	evsignal = EVENT_SIGNAL(ev);
+	assert(evsignal >= 0 && evsignal < NSIG);
+	if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {
+		event_debug(("%s: %p: changing signal handler", __func__, ev));
+		if (_evsignal_set_handler(
+			    base, evsignal, evsignal_handler) == -1)
+			return (-1);
+
+		/* catch signals if they happen quickly */
+		evsignal_base = base;
+
+		if (!sig->ev_signal_added) {
+			if (event_add(&sig->ev_signal, NULL))
+				return (-1);
+			sig->ev_signal_added = 1;
+		}
+	}
+
+	/* multiple events may listen to the same signal */
+	TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);
+
+	return (0);
+}
+
+int
+_evsignal_restore_handler(struct event_base *base, int evsignal)
+{
+	int ret = 0;
+	struct evsignal_info *sig = &base->sig;
+#ifdef HAVE_SIGACTION
+	struct sigaction *sh;
+#else
+	ev_sighandler_t *sh;
+#endif
+
+	/* restore previous handler */
+	sh = sig->sh_old[evsignal];
+	sig->sh_old[evsignal] = NULL;
+#ifdef HAVE_SIGACTION
+	if (sigaction(evsignal, sh, NULL) == -1) {
+		event_warn("sigaction");
+		ret = -1;
+	}
+#else
+	if (signal(evsignal, *sh) == SIG_ERR) {
+		event_warn("signal");
+		ret = -1;
+	}
+#endif
+	free(sh);
+
+	return ret;
+}
+
+int
+evsignal_del(struct event *ev)
+{
+	struct event_base *base = ev->ev_base;
+	struct evsignal_info *sig = &base->sig;
+	int evsignal = EVENT_SIGNAL(ev);
+
+	assert(evsignal >= 0 && evsignal < NSIG);
+
+	/* multiple events may listen to the same signal */
+	TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next);
+
+	if (!TAILQ_EMPTY(&sig->evsigevents[evsignal]))
+		return (0);
+
+	event_debug(("%s: %p: restoring signal handler", __func__, ev));
+
+	return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev)));
+}
+
+static void
+evsignal_handler(int sig)
+{
+	int save_errno = errno;
+
+	if (evsignal_base == NULL) {
+		event_warn(
+			"%s: received signal %d, but have no base configured",
+			__func__, sig);
+		return;
+	}
+
+	evsignal_base->sig.evsigcaught[sig]++;
+	evsignal_base->sig.evsignal_caught = 1;
+
+#ifndef HAVE_SIGACTION
+	signal(sig, evsignal_handler);
+#endif
+
+	/* Wake up our notification mechanism */
+	send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
+	errno = save_errno;
+}
+
+void
+evsignal_process(struct event_base *base)
+{
+	struct evsignal_info *sig = &base->sig;
+	struct event *ev, *next_ev;
+	sig_atomic_t ncalls;
+	int i;
+	
+	base->sig.evsignal_caught = 0;
+	for (i = 1; i < NSIG; ++i) {
+		ncalls = sig->evsigcaught[i];
+		if (ncalls == 0)
+			continue;
+		sig->evsigcaught[i] -= ncalls;
+
+		for (ev = TAILQ_FIRST(&sig->evsigevents[i]);
+		    ev != NULL; ev = next_ev) {
+			next_ev = TAILQ_NEXT(ev, ev_signal_next);
+			if (!(ev->ev_events & EV_PERSIST))
+				event_del(ev);
+			event_active(ev, EV_SIGNAL, ncalls);
+		}
+
+	}
+}
+
+void
+evsignal_dealloc(struct event_base *base)
+{
+	int i = 0;
+	if (base->sig.ev_signal_added) {
+		event_del(&base->sig.ev_signal);
+		base->sig.ev_signal_added = 0;
+	}
+	for (i = 0; i < NSIG; ++i) {
+		if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
+			_evsignal_restore_handler(base, i);
+	}
+
+	EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
+	base->sig.ev_signal_pair[0] = -1;
+	EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
+	base->sig.ev_signal_pair[1] = -1;
+	base->sig.sh_old_max = 0;
+
+	/* per index frees are handled in evsignal_del() */
+	free(base->sig.sh_old);
+}
diff --git a/third_party/libevent/solaris/config.h b/third_party/libevent/solaris/config.h
new file mode 100644
index 0000000..4dd40eb
--- /dev/null
+++ b/third_party/libevent/solaris/config.h
@@ -0,0 +1,266 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+#define HAVE_DEVPOLL 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+#define HAVE_EVENT_PORTS 1
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+#define HAVE_PORT_CREATE 1
+
+/* Define to 1 if you have the <port.h> header file. */
+#define HAVE_PORT_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#define HAVE_SYS_DEVPOLL_H 1
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/third_party/libevent/solaris/event-config.h b/third_party/libevent/solaris/event-config.h
new file mode 100644
index 0000000..c5fe160
--- /dev/null
+++ b/third_party/libevent/solaris/event-config.h
@@ -0,0 +1,274 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+#define _EVENT_HAVE_DEVPOLL 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+#define _EVENT_HAVE_EVENT_PORTS 1
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define _EVENT_HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define _EVENT_HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+#define _EVENT_HAVE_PORT_CREATE 1
+
+/* Define to 1 if you have the <port.h> header file. */
+#define _EVENT_HAVE_PORT_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#define _EVENT_HAVE_SYS_DEVPOLL_H 1
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/third_party/libevent/strlcpy-internal.h b/third_party/libevent/strlcpy-internal.h
new file mode 100644
index 0000000..22b5f61
--- /dev/null
+++ b/third_party/libevent/strlcpy-internal.h
@@ -0,0 +1,23 @@
+#ifndef _STRLCPY_INTERNAL_H_
+#define _STRLCPY_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_STRLCPY
+#include <string.h>
+size_t _event_strlcpy(char *dst, const char *src, size_t siz);
+#define strlcpy _event_strlcpy
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/third_party/libevent/strlcpy.c b/third_party/libevent/strlcpy.c
new file mode 100644
index 0000000..5d19452
--- /dev/null
+++ b/third_party/libevent/strlcpy.c
@@ -0,0 +1,76 @@
+/*	$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_STRLCPY
+#include "strlcpy-internal.h"
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+_event_strlcpy(dst, src, siz)
+	char *dst;
+	const char *src;
+	size_t siz;
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0 && --n != 0) {
+		do {
+			if ((*d++ = *s++) == 0)
+				break;
+		} while (--n != 0);
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}
+#endif
diff --git a/third_party/libevent/test/Makefile.am b/third_party/libevent/test/Makefile.am
new file mode 100644
index 0000000..3558d02
--- /dev/null
+++ b/third_party/libevent/test/Makefile.am
@@ -0,0 +1,35 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat
+
+EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c
+
+noinst_PROGRAMS = test-init test-eof test-weof test-time regress bench
+
+BUILT_SOURCES = regress.gen.c regress.gen.h
+test_init_SOURCES = test-init.c
+test_init_LDADD = ../libevent_core.la
+test_eof_SOURCES = test-eof.c
+test_eof_LDADD = ../libevent_core.la
+test_weof_SOURCES = test-weof.c
+test_weof_LDADD = ../libevent_core.la
+test_time_SOURCES = test-time.c
+test_time_LDADD = ../libevent_core.la
+regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \
+	regress_rpc.c \
+	regress.gen.c regress.gen.h
+regress_LDADD = ../libevent.la
+bench_SOURCES = bench.c
+bench_LDADD = ../libevent.la
+
+regress.gen.c regress.gen.h: regress.rpc $(top_srcdir)/event_rpcgen.py
+	$(top_srcdir)/event_rpcgen.py $(srcdir)/regress.rpc || echo "No Python installed"
+
+DISTCLEANFILES = *~
+
+test: test-init test-eof test-weof test-time regress
+
+verify: test
+	@$(srcdir)/test.sh
+
+bench test-init test-eof test-weof test-time: ../libevent.la
diff --git a/third_party/libevent/test/Makefile.in b/third_party/libevent/test/Makefile.in
new file mode 100644
index 0000000..c2d5b31
--- /dev/null
+++ b/third_party/libevent/test/Makefile.in
@@ -0,0 +1,487 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = test-init$(EXEEXT) test-eof$(EXEEXT) \
+	test-weof$(EXEEXT) test-time$(EXEEXT) regress$(EXEEXT) \
+	bench$(EXEEXT)
+subdir = test
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_bench_OBJECTS = bench.$(OBJEXT)
+bench_OBJECTS = $(am_bench_OBJECTS)
+bench_DEPENDENCIES = ../libevent.la
+am_regress_OBJECTS = regress.$(OBJEXT) regress_http.$(OBJEXT) \
+	regress_dns.$(OBJEXT) regress_rpc.$(OBJEXT) \
+	regress.gen.$(OBJEXT)
+regress_OBJECTS = $(am_regress_OBJECTS)
+regress_DEPENDENCIES = ../libevent.la
+am_test_eof_OBJECTS = test-eof.$(OBJEXT)
+test_eof_OBJECTS = $(am_test_eof_OBJECTS)
+test_eof_DEPENDENCIES = ../libevent_core.la
+am_test_init_OBJECTS = test-init.$(OBJEXT)
+test_init_OBJECTS = $(am_test_init_OBJECTS)
+test_init_DEPENDENCIES = ../libevent_core.la
+am_test_time_OBJECTS = test-time.$(OBJEXT)
+test_time_OBJECTS = $(am_test_time_OBJECTS)
+test_time_DEPENDENCIES = ../libevent_core.la
+am_test_weof_OBJECTS = test-weof.$(OBJEXT)
+test_weof_OBJECTS = $(am_test_weof_OBJECTS)
+test_weof_DEPENDENCIES = ../libevent_core.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(bench_SOURCES) $(regress_SOURCES) $(test_eof_SOURCES) \
+	$(test_init_SOURCES) $(test_time_SOURCES) $(test_weof_SOURCES)
+DIST_SOURCES = $(bench_SOURCES) $(regress_SOURCES) $(test_eof_SOURCES) \
+	$(test_init_SOURCES) $(test_time_SOURCES) $(test_weof_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat
+EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c
+BUILT_SOURCES = regress.gen.c regress.gen.h
+test_init_SOURCES = test-init.c
+test_init_LDADD = ../libevent_core.la
+test_eof_SOURCES = test-eof.c
+test_eof_LDADD = ../libevent_core.la
+test_weof_SOURCES = test-weof.c
+test_weof_LDADD = ../libevent_core.la
+test_time_SOURCES = test-time.c
+test_time_LDADD = ../libevent_core.la
+regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \
+	regress_rpc.c \
+	regress.gen.c regress.gen.h
+
+regress_LDADD = ../libevent.la
+bench_SOURCES = bench.c
+bench_LDADD = ../libevent.la
+DISTCLEANFILES = *~
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  test/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  test/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+bench$(EXEEXT): $(bench_OBJECTS) $(bench_DEPENDENCIES) 
+	@rm -f bench$(EXEEXT)
+	$(LINK) $(bench_OBJECTS) $(bench_LDADD) $(LIBS)
+regress$(EXEEXT): $(regress_OBJECTS) $(regress_DEPENDENCIES) 
+	@rm -f regress$(EXEEXT)
+	$(LINK) $(regress_OBJECTS) $(regress_LDADD) $(LIBS)
+test-eof$(EXEEXT): $(test_eof_OBJECTS) $(test_eof_DEPENDENCIES) 
+	@rm -f test-eof$(EXEEXT)
+	$(LINK) $(test_eof_OBJECTS) $(test_eof_LDADD) $(LIBS)
+test-init$(EXEEXT): $(test_init_OBJECTS) $(test_init_DEPENDENCIES) 
+	@rm -f test-init$(EXEEXT)
+	$(LINK) $(test_init_OBJECTS) $(test_init_LDADD) $(LIBS)
+test-time$(EXEEXT): $(test_time_OBJECTS) $(test_time_DEPENDENCIES) 
+	@rm -f test-time$(EXEEXT)
+	$(LINK) $(test_time_OBJECTS) $(test_time_LDADD) $(LIBS)
+test-weof$(EXEEXT): $(test_weof_OBJECTS) $(test_weof_DEPENDENCIES) 
+	@rm -f test-weof$(EXEEXT)
+	$(LINK) $(test_weof_OBJECTS) $(test_weof_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(COMPILE) -c $<
+
+.c.obj:
+	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstPROGRAMS ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+regress.gen.c regress.gen.h: regress.rpc $(top_srcdir)/event_rpcgen.py
+	$(top_srcdir)/event_rpcgen.py $(srcdir)/regress.rpc || echo "No Python installed"
+
+test: test-init test-eof test-weof test-time regress
+
+verify: test
+	@$(srcdir)/test.sh
+
+bench test-init test-eof test-weof test-time: ../libevent.la
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/libevent/test/bench.c b/third_party/libevent/test/bench.c
new file mode 100644
index 0000000..c976932
--- /dev/null
+++ b/third_party/libevent/test/bench.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Mon 03/10/2003 - Modified by Davide Libenzi <davidel@xmailserver.org>
+ *
+ *     Added chain event propagation to improve the sensitivity of
+ *     the measure respect to the event loop efficency.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <signal.h>
+#include <sys/resource.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+
+static int count, writes, fired;
+static int *pipes;
+static int num_pipes, num_active, num_writes;
+static struct event *events;
+
+static void
+read_cb(int fd, short which, void *arg)
+{
+	long idx = (long) arg, widx = idx + 1;
+	u_char ch;
+
+	count += read(fd, &ch, sizeof(ch));
+	if (writes) {
+		if (widx >= num_pipes)
+			widx -= num_pipes;
+		write(pipes[2 * widx + 1], "e", 1);
+		writes--;
+		fired++;
+	}
+}
+
+static struct timeval *
+run_once(void)
+{
+	int *cp, space;
+	long i;
+	static struct timeval ts, te;
+
+	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+		event_del(&events[i]);
+		event_set(&events[i], cp[0], EV_READ | EV_PERSIST, read_cb, (void *) i);
+		event_add(&events[i], NULL);
+	}
+
+	event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+
+	fired = 0;
+	space = num_pipes / num_active;
+	space = space * 2;
+	for (i = 0; i < num_active; i++, fired++)
+		write(pipes[i * space + 1], "e", 1);
+
+	count = 0;
+	writes = num_writes;
+	{ int xcount = 0;
+	gettimeofday(&ts, NULL);
+	do {
+		event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK);
+		xcount++;
+	} while (count != fired);
+	gettimeofday(&te, NULL);
+
+	if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count);
+	}
+
+	evutil_timersub(&te, &ts, &te);
+
+	return (&te);
+}
+
+int
+main (int argc, char **argv)
+{
+#ifndef WIN32
+	struct rlimit rl;
+#endif
+	int i, c;
+	struct timeval *tv;
+	int *cp;
+
+	num_pipes = 100;
+	num_active = 1;
+	num_writes = num_pipes;
+	while ((c = getopt(argc, argv, "n:a:w:")) != -1) {
+		switch (c) {
+		case 'n':
+			num_pipes = atoi(optarg);
+			break;
+		case 'a':
+			num_active = atoi(optarg);
+			break;
+		case 'w':
+			num_writes = atoi(optarg);
+			break;
+		default:
+			fprintf(stderr, "Illegal argument \"%c\"\n", c);
+			exit(1);
+		}
+	}
+
+#ifndef WIN32
+	rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
+	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+		perror("setrlimit");
+		exit(1);
+	}
+#endif
+
+	events = calloc(num_pipes, sizeof(struct event));
+	pipes = calloc(num_pipes * 2, sizeof(int));
+	if (events == NULL || pipes == NULL) {
+		perror("malloc");
+		exit(1);
+	}
+
+	event_init();
+
+	for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) {
+#ifdef USE_PIPES
+		if (pipe(cp) == -1) {
+#else
+		if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, cp) == -1) {
+#endif
+			perror("pipe");
+			exit(1);
+		}
+	}
+
+	for (i = 0; i < 25; i++) {
+		tv = run_once();
+		if (tv == NULL)
+			exit(1);
+		fprintf(stdout, "%ld\n",
+			tv->tv_sec * 1000000L + tv->tv_usec);
+	}
+
+	exit(0);
+}
diff --git a/third_party/libevent/test/regress.c b/third_party/libevent/test/regress.c
new file mode 100644
index 0000000..0b7517d
--- /dev/null
+++ b/third_party/libevent/test/regress.c
@@ -0,0 +1,1703 @@
+/*
+ * Copyright (c) 2003, 2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event.h"
+#include "evutil.h"
+#include "event-internal.h"
+#include "log.h"
+
+#include "regress.h"
+#ifndef WIN32
+#include "regress.gen.h"
+#endif
+
+int pair[2];
+int test_ok;
+static int called;
+static char wbuf[4096];
+static char rbuf[4096];
+static int woff;
+static int roff;
+static int usepersist;
+static struct timeval tset;
+static struct timeval tcalled;
+static struct event_base *global_base;
+
+#define TEST1	"this is a test"
+#define SECONDS	1
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifdef WIN32
+#define write(fd,buf,len) send((fd),(buf),(len),0)
+#define read(fd,buf,len) recv((fd),(buf),(len),0)
+#endif
+
+static void
+simple_read_cb(int fd, short event, void *arg)
+{
+	char buf[256];
+	int len;
+
+	if (arg == NULL)
+		return;
+
+	len = read(fd, buf, sizeof(buf));
+
+	if (len) {
+		if (!called) {
+			if (event_add(arg, NULL) == -1)
+				exit(1);
+		}
+	} else if (called == 1)
+		test_ok = 1;
+
+	called++;
+}
+
+static void
+simple_write_cb(int fd, short event, void *arg)
+{
+	int len;
+
+	if (arg == NULL)
+		return;
+
+	len = write(fd, TEST1, strlen(TEST1) + 1);
+	if (len == -1)
+		test_ok = 0;
+	else
+		test_ok = 1;
+}
+
+static void
+multiple_write_cb(int fd, short event, void *arg)
+{
+	struct event *ev = arg;
+	int len;
+
+	len = 128;
+	if (woff + len >= sizeof(wbuf))
+		len = sizeof(wbuf) - woff;
+
+	len = write(fd, wbuf + woff, len);
+	if (len == -1) {
+		fprintf(stderr, "%s: write\n", __func__);
+		if (usepersist)
+			event_del(ev);
+		return;
+	}
+
+	woff += len;
+
+	if (woff >= sizeof(wbuf)) {
+		shutdown(fd, SHUT_WR);
+		if (usepersist)
+			event_del(ev);
+		return;
+	}
+
+	if (!usepersist) {
+		if (event_add(ev, NULL) == -1)
+			exit(1);
+	}
+}
+
+static void
+multiple_read_cb(int fd, short event, void *arg)
+{
+	struct event *ev = arg;
+	int len;
+
+	len = read(fd, rbuf + roff, sizeof(rbuf) - roff);
+	if (len == -1)
+		fprintf(stderr, "%s: read\n", __func__);
+	if (len <= 0) {
+		if (usepersist)
+			event_del(ev);
+		return;
+	}
+
+	roff += len;
+	if (!usepersist) {
+		if (event_add(ev, NULL) == -1) 
+			exit(1);
+	}
+}
+
+static void
+timeout_cb(int fd, short event, void *arg)
+{
+	struct timeval tv;
+	int diff;
+
+	evutil_gettimeofday(&tcalled, NULL);
+	if (evutil_timercmp(&tcalled, &tset, >))
+		evutil_timersub(&tcalled, &tset, &tv);
+	else
+		evutil_timersub(&tset, &tcalled, &tv);
+
+	diff = tv.tv_sec*1000 + tv.tv_usec/1000 - SECONDS * 1000;
+	if (diff < 0)
+		diff = -diff;
+
+	if (diff < 100)
+		test_ok = 1;
+}
+
+#ifndef WIN32
+static void
+signal_cb_sa(int sig)
+{
+	test_ok = 2;
+}
+
+static void
+signal_cb(int fd, short event, void *arg)
+{
+	struct event *ev = arg;
+
+	signal_del(ev);
+	test_ok = 1;
+}
+#endif
+
+struct both {
+	struct event ev;
+	int nread;
+};
+
+static void
+combined_read_cb(int fd, short event, void *arg)
+{
+	struct both *both = arg;
+	char buf[128];
+	int len;
+
+	len = read(fd, buf, sizeof(buf));
+	if (len == -1)
+		fprintf(stderr, "%s: read\n", __func__);
+	if (len <= 0)
+		return;
+
+	both->nread += len;
+	if (event_add(&both->ev, NULL) == -1)
+		exit(1);
+}
+
+static void
+combined_write_cb(int fd, short event, void *arg)
+{
+	struct both *both = arg;
+	char buf[128];
+	int len;
+
+	len = sizeof(buf);
+	if (len > both->nread)
+		len = both->nread;
+
+	len = write(fd, buf, len);
+	if (len == -1)
+		fprintf(stderr, "%s: write\n", __func__);
+	if (len <= 0) {
+		shutdown(fd, SHUT_WR);
+		return;
+	}
+
+	both->nread -= len;
+	if (event_add(&both->ev, NULL) == -1)
+		exit(1);
+}
+
+/* Test infrastructure */
+
+static int
+setup_test(const char *name)
+{
+
+	fprintf(stdout, "%s", name);
+
+	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+		fprintf(stderr, "%s: socketpair\n", __func__);
+		exit(1);
+	}
+
+#ifdef HAVE_FCNTL
+        if (fcntl(pair[0], F_SETFL, O_NONBLOCK) == -1)
+		fprintf(stderr, "fcntl(O_NONBLOCK)");
+
+        if (fcntl(pair[1], F_SETFL, O_NONBLOCK) == -1)
+		fprintf(stderr, "fcntl(O_NONBLOCK)");
+#endif
+
+	test_ok = 0;
+	called = 0;
+	return (0);
+}
+
+static int
+cleanup_test(void)
+{
+#ifndef WIN32
+	close(pair[0]);
+	close(pair[1]);
+#else
+	CloseHandle((HANDLE)pair[0]);
+	CloseHandle((HANDLE)pair[1]);
+#endif
+	if (test_ok)
+		fprintf(stdout, "OK\n");
+	else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+        test_ok = 0;
+	return (0);
+}
+
+static void
+test_registerfds(void)
+{
+	int i, j;
+	int pair[2];
+	struct event read_evs[512];
+	struct event write_evs[512];
+
+	struct event_base *base = event_base_new();
+
+	fprintf(stdout, "Testing register fds: ");
+
+	for (i = 0; i < 512; ++i) {
+		if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+			/* run up to the limit of file descriptors */
+			break;
+		}
+		event_set(&read_evs[i], pair[0],
+		    EV_READ|EV_PERSIST, simple_read_cb, NULL);
+		event_base_set(base, &read_evs[i]);
+		event_add(&read_evs[i], NULL);
+		event_set(&write_evs[i], pair[1],
+		    EV_WRITE|EV_PERSIST, simple_write_cb, NULL);
+		event_base_set(base, &write_evs[i]);
+		event_add(&write_evs[i], NULL);
+
+		/* just loop once */
+		event_base_loop(base, EVLOOP_ONCE);
+	}
+
+	/* now delete everything */
+	for (j = 0; j < i; ++j) {
+		event_del(&read_evs[j]);
+		event_del(&write_evs[j]);
+#ifndef WIN32
+		close(read_evs[j].ev_fd);
+		close(write_evs[j].ev_fd);
+#else
+		CloseHandle((HANDLE)read_evs[j].ev_fd);
+		CloseHandle((HANDLE)write_evs[j].ev_fd);
+#endif
+
+		/* just loop once */
+		event_base_loop(base, EVLOOP_ONCE);
+	}
+
+	event_base_free(base);
+
+	fprintf(stdout, "OK\n");
+}
+
+static void
+test_simpleread(void)
+{
+	struct event ev;
+
+	/* Very simple read test */
+	setup_test("Simple read: ");
+	
+	write(pair[0], TEST1, strlen(TEST1)+1);
+	shutdown(pair[0], SHUT_WR);
+
+	event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+	event_dispatch();
+
+	cleanup_test();
+}
+
+static void
+test_simplewrite(void)
+{
+	struct event ev;
+
+	/* Very simple write test */
+	setup_test("Simple write: ");
+	
+	event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+	event_dispatch();
+
+	cleanup_test();
+}
+
+static void
+test_multiple(void)
+{
+	struct event ev, ev2;
+	int i;
+
+	/* Multiple read and write test */
+	setup_test("Multiple read/write: ");
+	memset(rbuf, 0, sizeof(rbuf));
+	for (i = 0; i < sizeof(wbuf); i++)
+		wbuf[i] = i;
+
+	roff = woff = 0;
+	usepersist = 0;
+
+	event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+	event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2);
+	if (event_add(&ev2, NULL) == -1)
+		exit(1);
+	event_dispatch();
+
+	if (roff == woff)
+		test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0;
+
+	cleanup_test();
+}
+
+static void
+test_persistent(void)
+{
+	struct event ev, ev2;
+	int i;
+
+	/* Multiple read and write test with persist */
+	setup_test("Persist read/write: ");
+	memset(rbuf, 0, sizeof(rbuf));
+	for (i = 0; i < sizeof(wbuf); i++)
+		wbuf[i] = i;
+
+	roff = woff = 0;
+	usepersist = 1;
+
+	event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+	event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2);
+	if (event_add(&ev2, NULL) == -1)
+		exit(1);
+	event_dispatch();
+
+	if (roff == woff)
+		test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0;
+
+	cleanup_test();
+}
+
+static void
+test_combined(void)
+{
+	struct both r1, r2, w1, w2;
+
+	setup_test("Combined read/write: ");
+	memset(&r1, 0, sizeof(r1));
+	memset(&r2, 0, sizeof(r2));
+	memset(&w1, 0, sizeof(w1));
+	memset(&w2, 0, sizeof(w2));
+
+	w1.nread = 4096;
+	w2.nread = 8192;
+
+	event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1);
+	event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1);
+	event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2);
+	event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2);
+	if (event_add(&r1.ev, NULL) == -1)
+		exit(1);
+	if (event_add(&w1.ev, NULL))
+		exit(1);
+	if (event_add(&r2.ev, NULL))
+		exit(1);
+	if (event_add(&w2.ev, NULL))
+		exit(1);
+
+	event_dispatch();
+
+	if (r1.nread == 8192 && r2.nread == 4096)
+		test_ok = 1;
+
+	cleanup_test();
+}
+
+static void
+test_simpletimeout(void)
+{
+	struct timeval tv;
+	struct event ev;
+
+	setup_test("Simple timeout: ");
+
+	tv.tv_usec = 0;
+	tv.tv_sec = SECONDS;
+	evtimer_set(&ev, timeout_cb, NULL);
+	evtimer_add(&ev, &tv);
+
+	evutil_gettimeofday(&tset, NULL);
+	event_dispatch();
+
+	cleanup_test();
+}
+
+#ifndef WIN32
+extern struct event_base *current_base;
+
+static void
+child_signal_cb(int fd, short event, void *arg)
+{
+	struct timeval tv;
+	int *pint = arg;
+
+	*pint = 1;
+
+	tv.tv_usec = 500000;
+	tv.tv_sec = 0;
+	event_loopexit(&tv);
+}
+
+static void
+test_fork(void)
+{
+	int status, got_sigchld = 0;
+	struct event ev, sig_ev;
+	pid_t pid;
+
+	setup_test("After fork: ");
+
+	write(pair[0], TEST1, strlen(TEST1)+1);
+
+	event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+
+	signal_set(&sig_ev, SIGCHLD, child_signal_cb, &got_sigchld);
+	signal_add(&sig_ev, NULL);
+
+	if ((pid = fork()) == 0) {
+		/* in the child */
+		if (event_reinit(current_base) == -1) {
+			fprintf(stderr, "FAILED (reinit)\n");
+			exit(1);
+		}
+
+		signal_del(&sig_ev);
+
+		called = 0;
+
+		event_dispatch();
+
+		/* we do not send an EOF; simple_read_cb requires an EOF 
+		 * to set test_ok.  we just verify that the callback was
+		 * called. */
+		exit(test_ok != 0 || called != 2 ? -2 : 76);
+	}
+
+	/* wait for the child to read the data */
+	sleep(1);
+
+	write(pair[0], TEST1, strlen(TEST1)+1);
+
+	if (waitpid(pid, &status, 0) == -1) {
+		fprintf(stderr, "FAILED (fork)\n");
+		exit(1);
+	}
+	
+	if (WEXITSTATUS(status) != 76) {
+		fprintf(stderr, "FAILED (exit): %d\n", WEXITSTATUS(status));
+		exit(1);
+	}
+
+	/* test that the current event loop still works */
+	write(pair[0], TEST1, strlen(TEST1)+1);
+	shutdown(pair[0], SHUT_WR);
+
+	event_dispatch();
+
+	if (!got_sigchld) {
+		fprintf(stdout, "FAILED (sigchld)\n");
+		exit(1);
+	}
+
+	signal_del(&sig_ev);
+
+	cleanup_test();
+}
+
+static void
+test_simplesignal(void)
+{
+	struct event ev;
+	struct itimerval itv;
+
+	setup_test("Simple signal: ");
+	signal_set(&ev, SIGALRM, signal_cb, &ev);
+	signal_add(&ev, NULL);
+	/* find bugs in which operations are re-ordered */
+	signal_del(&ev);
+	signal_add(&ev, NULL);
+
+	memset(&itv, 0, sizeof(itv));
+	itv.it_value.tv_sec = 1;
+	if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+		goto skip_simplesignal;
+
+	event_dispatch();
+ skip_simplesignal:
+	if (signal_del(&ev) == -1)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
+static void
+test_multiplesignal(void)
+{
+	struct event ev_one, ev_two;
+	struct itimerval itv;
+
+	setup_test("Multiple signal: ");
+
+	signal_set(&ev_one, SIGALRM, signal_cb, &ev_one);
+	signal_add(&ev_one, NULL);
+
+	signal_set(&ev_two, SIGALRM, signal_cb, &ev_two);
+	signal_add(&ev_two, NULL);
+
+	memset(&itv, 0, sizeof(itv));
+	itv.it_value.tv_sec = 1;
+	if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
+		goto skip_simplesignal;
+
+	event_dispatch();
+
+ skip_simplesignal:
+	if (signal_del(&ev_one) == -1)
+		test_ok = 0;
+	if (signal_del(&ev_two) == -1)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
+static void
+test_immediatesignal(void)
+{
+	struct event ev;
+
+	test_ok = 0;
+	printf("Immediate signal: ");
+	signal_set(&ev, SIGUSR1, signal_cb, &ev);
+	signal_add(&ev, NULL);
+	raise(SIGUSR1);
+	event_loop(EVLOOP_NONBLOCK);
+	signal_del(&ev);
+	cleanup_test();
+}
+
+static void
+test_signal_dealloc(void)
+{
+	/* make sure that signal_event is event_del'ed and pipe closed */
+	struct event ev;
+	struct event_base *base = event_init();
+	printf("Signal dealloc: ");
+	signal_set(&ev, SIGUSR1, signal_cb, &ev);
+	signal_add(&ev, NULL);
+	signal_del(&ev);
+	event_base_free(base);
+        /* If we got here without asserting, we're fine. */
+        test_ok = 1;
+	cleanup_test();
+}
+
+static void
+test_signal_pipeloss(void)
+{
+	/* make sure that the base1 pipe is closed correctly. */
+	struct event_base *base1, *base2;
+	int pipe1;
+	test_ok = 0;
+	printf("Signal pipeloss: ");
+	base1 = event_init();
+	pipe1 = base1->sig.ev_signal_pair[0];
+	base2 = event_init();
+	event_base_free(base2);
+	event_base_free(base1);
+	if (close(pipe1) != -1 || errno!=EBADF) {
+		/* fd must be closed, so second close gives -1, EBADF */
+		printf("signal pipe not closed. ");
+		test_ok = 0;
+	} else {
+		test_ok = 1;
+	}
+	cleanup_test();
+}
+
+/*
+ * make two bases to catch signals, use both of them.  this only works
+ * for event mechanisms that use our signal pipe trick.  kqueue handles
+ * signals internally, and all interested kqueues get all the signals.
+ */
+static void
+test_signal_switchbase(void)
+{
+	struct event ev1, ev2;
+	struct event_base *base1, *base2;
+        int is_kqueue;
+	test_ok = 0;
+	printf("Signal switchbase: ");
+	base1 = event_init();
+	base2 = event_init();
+        is_kqueue = !strcmp(event_get_method(),"kqueue");
+	signal_set(&ev1, SIGUSR1, signal_cb, &ev1);
+	signal_set(&ev2, SIGUSR1, signal_cb, &ev2);
+	if (event_base_set(base1, &ev1) ||
+	    event_base_set(base2, &ev2) ||
+	    event_add(&ev1, NULL) ||
+	    event_add(&ev2, NULL)) {
+		fprintf(stderr, "%s: cannot set base, add\n", __func__);
+		exit(1);
+	}
+
+	test_ok = 0;
+	/* can handle signal before loop is called */
+	raise(SIGUSR1);
+	event_base_loop(base2, EVLOOP_NONBLOCK);
+        if (is_kqueue) {
+                if (!test_ok)
+                        goto done;
+                test_ok = 0;
+        }
+	event_base_loop(base1, EVLOOP_NONBLOCK);
+	if (test_ok && !is_kqueue) {
+		test_ok = 0;
+
+		/* set base1 to handle signals */
+		event_base_loop(base1, EVLOOP_NONBLOCK);
+		raise(SIGUSR1);
+		event_base_loop(base1, EVLOOP_NONBLOCK);
+		event_base_loop(base2, EVLOOP_NONBLOCK);
+	}
+ done:
+	event_base_free(base1);
+	event_base_free(base2);
+	cleanup_test();
+}
+
+/*
+ * assert that a signal event removed from the event queue really is
+ * removed - with no possibility of it's parent handler being fired.
+ */
+static void
+test_signal_assert(void)
+{
+	struct event ev;
+	struct event_base *base = event_init();
+	test_ok = 0;
+	printf("Signal handler assert: ");
+	/* use SIGCONT so we don't kill ourselves when we signal to nowhere */
+	signal_set(&ev, SIGCONT, signal_cb, &ev);
+	signal_add(&ev, NULL);
+	/*
+	 * if signal_del() fails to reset the handler, it's current handler
+	 * will still point to evsignal_handler().
+	 */
+	signal_del(&ev);
+
+	raise(SIGCONT);
+	/* only way to verify we were in evsignal_handler() */
+	if (base->sig.evsignal_caught)
+		test_ok = 0;
+	else
+		test_ok = 1;
+
+	event_base_free(base);
+	cleanup_test();
+	return;
+}
+
+/*
+ * assert that we restore our previous signal handler properly.
+ */
+static void
+test_signal_restore(void)
+{
+	struct event ev;
+	struct event_base *base = event_init();
+#ifdef HAVE_SIGACTION
+	struct sigaction sa;
+#endif
+
+	test_ok = 0;
+	printf("Signal handler restore: ");
+#ifdef HAVE_SIGACTION
+	sa.sa_handler = signal_cb_sa;
+	sa.sa_flags = 0x0;
+	sigemptyset(&sa.sa_mask);
+	if (sigaction(SIGUSR1, &sa, NULL) == -1)
+		goto out;
+#else
+	if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR)
+		goto out;
+#endif
+	signal_set(&ev, SIGUSR1, signal_cb, &ev);
+	signal_add(&ev, NULL);
+	signal_del(&ev);
+
+	raise(SIGUSR1);
+	/* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */
+	if (test_ok != 2)
+		test_ok = 0;
+out:
+	event_base_free(base);
+	cleanup_test();
+	return;
+}
+
+static void
+signal_cb_swp(int sig, short event, void *arg)
+{
+	called++;
+	if (called < 5)
+		raise(sig);
+	else
+		event_loopexit(NULL);
+}
+static void
+timeout_cb_swp(int fd, short event, void *arg)
+{
+	if (called == -1) {
+		struct timeval tv = {5, 0};
+
+		called = 0;
+		evtimer_add((struct event *)arg, &tv);
+		raise(SIGUSR1);
+		return;
+	}
+	test_ok = 0;
+	event_loopexit(NULL);
+}
+
+static void
+test_signal_while_processing(void)
+{
+	struct event_base *base = event_init();
+	struct event ev, ev_timer;
+	struct timeval tv = {0, 0};
+
+	setup_test("Receiving a signal while processing other signal: ");
+
+	called = -1;
+	test_ok = 1;
+	signal_set(&ev, SIGUSR1, signal_cb_swp, NULL);
+	signal_add(&ev, NULL);
+	evtimer_set(&ev_timer, timeout_cb_swp, &ev_timer);
+	evtimer_add(&ev_timer, &tv);
+	event_dispatch();
+
+	event_base_free(base);
+	cleanup_test();
+	return;
+}
+#endif
+
+static void
+test_free_active_base(void)
+{
+	struct event_base *base1;
+	struct event ev1;
+	setup_test("Free active base: ");
+	base1 = event_init();
+	event_set(&ev1, pair[1], EV_READ, simple_read_cb, &ev1);
+	event_base_set(base1, &ev1);
+	event_add(&ev1, NULL);
+	/* event_del(&ev1); */
+	event_base_free(base1);
+	test_ok = 1;
+	cleanup_test();
+}
+
+static void
+test_event_base_new(void)
+{
+	struct event_base *base;
+	struct event ev1;
+	setup_test("Event base new: ");
+
+	write(pair[0], TEST1, strlen(TEST1)+1);
+	shutdown(pair[0], SHUT_WR);
+
+	base = event_base_new();
+	event_set(&ev1, pair[1], EV_READ, simple_read_cb, &ev1);
+	event_base_set(base, &ev1);
+	event_add(&ev1, NULL);
+
+	event_base_dispatch(base);
+
+	event_base_free(base);
+	test_ok = 1;
+	cleanup_test();
+}
+
+static void
+test_loopexit(void)
+{
+	struct timeval tv, tv_start, tv_end;
+	struct event ev;
+
+	setup_test("Loop exit: ");
+
+	tv.tv_usec = 0;
+	tv.tv_sec = 60*60*24;
+	evtimer_set(&ev, timeout_cb, NULL);
+	evtimer_add(&ev, &tv);
+
+	tv.tv_usec = 0;
+	tv.tv_sec = 1;
+	event_loopexit(&tv);
+
+	evutil_gettimeofday(&tv_start, NULL);
+	event_dispatch();
+	evutil_gettimeofday(&tv_end, NULL);
+	evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+	evtimer_del(&ev);
+
+	if (tv.tv_sec < 2)
+		test_ok = 1;
+
+	cleanup_test();
+}
+
+static void
+test_loopexit_multiple(void)
+{
+	struct timeval tv;
+	struct event_base *base;
+
+	setup_test("Loop Multiple exit: ");
+
+	base = event_base_new();
+	
+	tv.tv_usec = 0;
+	tv.tv_sec = 1;
+	event_base_loopexit(base, &tv);
+
+	tv.tv_usec = 0;
+	tv.tv_sec = 2;
+	event_base_loopexit(base, &tv);
+
+	event_base_dispatch(base);
+
+	event_base_free(base);
+	
+	test_ok = 1;
+
+	cleanup_test();
+}
+
+static void
+break_cb(int fd, short events, void *arg)
+{
+	test_ok = 1;
+	event_loopbreak();
+}
+
+static void
+fail_cb(int fd, short events, void *arg)
+{
+	test_ok = 0;
+}
+
+static void
+test_loopbreak(void)
+{
+	struct event ev1, ev2;
+	struct timeval tv;
+
+	setup_test("Loop break: ");
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	evtimer_set(&ev1, break_cb, NULL);
+	evtimer_add(&ev1, &tv);
+	evtimer_set(&ev2, fail_cb, NULL);
+	evtimer_add(&ev2, &tv);
+
+	event_dispatch();
+
+	evtimer_del(&ev1);
+	evtimer_del(&ev2);
+
+	cleanup_test();
+}
+
+static void
+test_evbuffer(void) {
+
+	struct evbuffer *evb = evbuffer_new();
+	setup_test("Testing Evbuffer: ");
+
+	evbuffer_add_printf(evb, "%s/%d", "hello", 1);
+
+	if (EVBUFFER_LENGTH(evb) == 7 &&
+	    strcmp((char*)EVBUFFER_DATA(evb), "hello/1") == 0)
+	    test_ok = 1;
+	
+	evbuffer_free(evb);
+
+	cleanup_test();
+}
+
+static void
+test_evbuffer_find(void)
+{
+	u_char* p;
+	const char* test1 = "1234567890\r\n";
+	const char* test2 = "1234567890\r";
+#define EVBUFFER_INITIAL_LENGTH 256
+	char test3[EVBUFFER_INITIAL_LENGTH];
+	unsigned int i;
+	struct evbuffer * buf = evbuffer_new();
+
+	/* make sure evbuffer_find doesn't match past the end of the buffer */
+	fprintf(stdout, "Testing evbuffer_find 1: ");
+	evbuffer_add(buf, (u_char*)test1, strlen(test1));
+	evbuffer_drain(buf, strlen(test1));	  
+	evbuffer_add(buf, (u_char*)test2, strlen(test2));
+	p = evbuffer_find(buf, (u_char*)"\r\n", 2);
+	if (p == NULL) {
+		fprintf(stdout, "OK\n");
+	} else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/*
+	 * drain the buffer and do another find; in r309 this would
+	 * read past the allocated buffer causing a valgrind error.
+	 */
+	fprintf(stdout, "Testing evbuffer_find 2: ");
+	evbuffer_drain(buf, strlen(test2));
+	for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
+		test3[i] = 'a';
+	test3[EVBUFFER_INITIAL_LENGTH - 1] = 'x';
+	evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
+	p = evbuffer_find(buf, (u_char *)"xy", 2);
+	if (p == NULL) {
+		printf("OK\n");
+	} else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* simple test for match at end of allocated buffer */
+	fprintf(stdout, "Testing evbuffer_find 3: ");
+	p = evbuffer_find(buf, (u_char *)"ax", 2);
+	if (p != NULL && strncmp((char*)p, "ax", 2) == 0) {
+		printf("OK\n");
+	} else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	evbuffer_free(buf);
+}
+
+/*
+ * simple bufferevent test
+ */
+
+static void
+readcb(struct bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->input) == 8333) {
+		bufferevent_disable(bev, EV_READ);
+		test_ok++;
+	}
+}
+
+static void
+writecb(struct bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->output) == 0)
+		test_ok++;
+}
+
+static void
+errorcb(struct bufferevent *bev, short what, void *arg)
+{
+	test_ok = -2;
+}
+
+static void
+test_bufferevent(void)
+{
+	struct bufferevent *bev1, *bev2;
+	char buffer[8333];
+	int i;
+
+	setup_test("Bufferevent: ");
+
+	bev1 = bufferevent_new(pair[0], readcb, writecb, errorcb, NULL);
+	bev2 = bufferevent_new(pair[1], readcb, writecb, errorcb, NULL);
+
+	bufferevent_disable(bev1, EV_READ);
+	bufferevent_enable(bev2, EV_READ);
+
+	for (i = 0; i < sizeof(buffer); i++)
+		buffer[i] = i;
+
+	bufferevent_write(bev1, buffer, sizeof(buffer));
+
+	event_dispatch();
+
+	bufferevent_free(bev1);
+	bufferevent_free(bev2);
+
+	if (test_ok != 2)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
+/*
+ * test watermarks and bufferevent
+ */
+
+static void
+wm_readcb(struct bufferevent *bev, void *arg)
+{
+	int len = EVBUFFER_LENGTH(bev->input);
+	static int nread;
+
+	assert(len >= 10 && len <= 20);
+
+	evbuffer_drain(bev->input, len);
+
+	nread += len;
+	if (nread == 65000) {
+		bufferevent_disable(bev, EV_READ);
+		test_ok++;
+	}
+}
+
+static void
+wm_writecb(struct bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->output) == 0)
+		test_ok++;
+}
+
+static void
+wm_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+	test_ok = -2;
+}
+
+static void
+test_bufferevent_watermarks(void)
+{
+	struct bufferevent *bev1, *bev2;
+	char buffer[65000];
+	int i;
+
+	setup_test("Bufferevent Watermarks: ");
+
+	bev1 = bufferevent_new(pair[0], NULL, wm_writecb, wm_errorcb, NULL);
+	bev2 = bufferevent_new(pair[1], wm_readcb, NULL, wm_errorcb, NULL);
+
+	bufferevent_disable(bev1, EV_READ);
+	bufferevent_enable(bev2, EV_READ);
+
+	for (i = 0; i < sizeof(buffer); i++)
+		buffer[i] = i;
+
+	bufferevent_write(bev1, buffer, sizeof(buffer));
+
+	/* limit the reading on the receiving bufferevent */
+	bufferevent_setwatermark(bev2, EV_READ, 10, 20);
+
+	event_dispatch();
+
+	bufferevent_free(bev1);
+	bufferevent_free(bev2);
+
+	if (test_ok != 2)
+		test_ok = 0;
+
+	cleanup_test();
+}
+
+struct test_pri_event {
+	struct event ev;
+	int count;
+};
+
+static void
+test_priorities_cb(int fd, short what, void *arg)
+{
+	struct test_pri_event *pri = arg;
+	struct timeval tv;
+
+	if (pri->count == 3) {
+		event_loopexit(NULL);
+		return;
+	}
+
+	pri->count++;
+
+	evutil_timerclear(&tv);
+	event_add(&pri->ev, &tv);
+}
+
+static void
+test_priorities(int npriorities)
+{
+	char buf[32];
+	struct test_pri_event one, two;
+	struct timeval tv;
+
+	evutil_snprintf(buf, sizeof(buf), "Testing Priorities %d: ", npriorities);
+	setup_test(buf);
+
+	event_base_priority_init(global_base, npriorities);
+
+	memset(&one, 0, sizeof(one));
+	memset(&two, 0, sizeof(two));
+
+	timeout_set(&one.ev, test_priorities_cb, &one);
+	if (event_priority_set(&one.ev, 0) == -1) {
+		fprintf(stderr, "%s: failed to set priority", __func__);
+		exit(1);
+	}
+
+	timeout_set(&two.ev, test_priorities_cb, &two);
+	if (event_priority_set(&two.ev, npriorities - 1) == -1) {
+		fprintf(stderr, "%s: failed to set priority", __func__);
+		exit(1);
+	}
+
+	evutil_timerclear(&tv);
+
+	if (event_add(&one.ev, &tv) == -1)
+		exit(1);
+	if (event_add(&two.ev, &tv) == -1)
+		exit(1);
+
+	event_dispatch();
+
+	event_del(&one.ev);
+	event_del(&two.ev);
+
+	if (npriorities == 1) {
+		if (one.count == 3 && two.count == 3)
+			test_ok = 1;
+	} else if (npriorities == 2) {
+		/* Two is called once because event_loopexit is priority 1 */
+		if (one.count == 3 && two.count == 1)
+			test_ok = 1;
+	} else {
+		if (one.count == 3 && two.count == 0)
+			test_ok = 1;
+	}
+
+	cleanup_test();
+}
+
+static void
+test_multiple_cb(int fd, short event, void *arg)
+{
+	if (event & EV_READ)
+		test_ok |= 1;
+	else if (event & EV_WRITE)
+		test_ok |= 2;
+}
+
+static void
+test_multiple_events_for_same_fd(void)
+{
+   struct event e1, e2;
+
+   setup_test("Multiple events for same fd: ");
+
+   event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL);
+   event_add(&e1, NULL);
+   event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL);
+   event_add(&e2, NULL);
+   event_loop(EVLOOP_ONCE);
+   event_del(&e2);
+   write(pair[1], TEST1, strlen(TEST1)+1);
+   event_loop(EVLOOP_ONCE);
+   event_del(&e1);
+   
+   if (test_ok != 3)
+	   test_ok = 0;
+
+   cleanup_test();
+}
+
+int evtag_decode_int(uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, uint32_t number);
+int evtag_decode_tag(uint32_t *pnumber, struct evbuffer *evbuf);
+
+static void
+read_once_cb(int fd, short event, void *arg)
+{
+	char buf[256];
+	int len;
+
+	len = read(fd, buf, sizeof(buf));
+
+	if (called) {
+		test_ok = 0;
+	} else if (len) {
+		/* Assumes global pair[0] can be used for writing */
+		write(pair[0], TEST1, strlen(TEST1)+1);
+		test_ok = 1;
+	}
+
+	called++;
+}
+
+static void
+test_want_only_once(void)
+{
+	struct event ev;
+	struct timeval tv;
+
+	/* Very simple read test */
+	setup_test("Want read only once: ");
+	
+	write(pair[0], TEST1, strlen(TEST1)+1);
+
+	/* Setup the loop termination */
+	evutil_timerclear(&tv);
+	tv.tv_sec = 1;
+	event_loopexit(&tv);
+	
+	event_set(&ev, pair[1], EV_READ, read_once_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+	event_dispatch();
+
+	cleanup_test();
+}
+
+#define TEST_MAX_INT	6
+
+static void
+evtag_int_test(void)
+{
+	struct evbuffer *tmp = evbuffer_new();
+	uint32_t integers[TEST_MAX_INT] = {
+		0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+	};
+	uint32_t integer;
+	int i;
+
+	for (i = 0; i < TEST_MAX_INT; i++) {
+		int oldlen, newlen;
+		oldlen = EVBUFFER_LENGTH(tmp);
+		encode_int(tmp, integers[i]);
+		newlen = EVBUFFER_LENGTH(tmp);
+		fprintf(stdout, "\t\tencoded 0x%08x with %d bytes\n",
+		    integers[i], newlen - oldlen);
+	}
+
+	for (i = 0; i < TEST_MAX_INT; i++) {
+		if (evtag_decode_int(&integer, tmp) == -1) {
+			fprintf(stderr, "decode %d failed", i);
+			exit(1);
+		}
+		if (integer != integers[i]) {
+			fprintf(stderr, "got %x, wanted %x",
+			    integer, integers[i]);
+			exit(1);
+		}
+	}
+
+	if (EVBUFFER_LENGTH(tmp) != 0) {
+		fprintf(stderr, "trailing data");
+		exit(1);
+	}
+	evbuffer_free(tmp);
+
+	fprintf(stdout, "\t%s: OK\n", __func__);
+}
+
+static void
+evtag_fuzz(void)
+{
+	u_char buffer[4096];
+	struct evbuffer *tmp = evbuffer_new();
+	struct timeval tv;
+	int i, j;
+
+	int not_failed = 0;
+	for (j = 0; j < 100; j++) {
+		for (i = 0; i < sizeof(buffer); i++)
+			buffer[i] = rand();
+		evbuffer_drain(tmp, -1);
+		evbuffer_add(tmp, buffer, sizeof(buffer));
+
+		if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1)
+			not_failed++;
+	}
+
+	/* The majority of decodes should fail */
+	if (not_failed >= 10) {
+		fprintf(stderr, "evtag_unmarshal should have failed");
+		exit(1);
+	}
+
+	/* Now insert some corruption into the tag length field */
+	evbuffer_drain(tmp, -1);
+	evutil_timerclear(&tv);
+	tv.tv_sec = 1;
+	evtag_marshal_timeval(tmp, 0, &tv);
+	evbuffer_add(tmp, buffer, sizeof(buffer));
+
+	EVBUFFER_DATA(tmp)[1] = 0xff;
+	if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) {
+		fprintf(stderr, "evtag_unmarshal_timeval should have failed");
+		exit(1);
+	}
+
+	evbuffer_free(tmp);
+
+	fprintf(stdout, "\t%s: OK\n", __func__);
+}
+
+static void
+evtag_tag_encoding(void)
+{
+	struct evbuffer *tmp = evbuffer_new();
+	uint32_t integers[TEST_MAX_INT] = {
+		0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+	};
+	uint32_t integer;
+	int i;
+
+	for (i = 0; i < TEST_MAX_INT; i++) {
+		int oldlen, newlen;
+		oldlen = EVBUFFER_LENGTH(tmp);
+		evtag_encode_tag(tmp, integers[i]);
+		newlen = EVBUFFER_LENGTH(tmp);
+		fprintf(stdout, "\t\tencoded 0x%08x with %d bytes\n",
+		    integers[i], newlen - oldlen);
+	}
+
+	for (i = 0; i < TEST_MAX_INT; i++) {
+		if (evtag_decode_tag(&integer, tmp) == -1) {
+			fprintf(stderr, "decode %d failed", i);
+			exit(1);
+		}
+		if (integer != integers[i]) {
+			fprintf(stderr, "got %x, wanted %x",
+			    integer, integers[i]);
+			exit(1);
+		}
+	}
+
+	if (EVBUFFER_LENGTH(tmp) != 0) {
+		fprintf(stderr, "trailing data");
+		exit(1);
+	}
+	evbuffer_free(tmp);
+
+	fprintf(stdout, "\t%s: OK\n", __func__);
+}
+
+static void
+evtag_test(void)
+{
+	fprintf(stdout, "Testing Tagging:\n");
+
+	evtag_init();
+	evtag_int_test();
+	evtag_fuzz();
+
+	evtag_tag_encoding();
+
+	fprintf(stdout, "OK\n");
+}
+
+#ifndef WIN32
+static void
+rpc_test(void)
+{
+	struct msg *msg, *msg2;
+	struct kill *attack;
+	struct run *run;
+	struct evbuffer *tmp = evbuffer_new();
+	struct timeval tv_start, tv_end;
+	uint32_t tag;
+	int i;
+
+	fprintf(stdout, "Testing RPC: ");
+
+	msg = msg_new();
+	EVTAG_ASSIGN(msg, from_name, "niels");
+	EVTAG_ASSIGN(msg, to_name, "phoenix");
+
+	if (EVTAG_GET(msg, attack, &attack) == -1) {
+		fprintf(stderr, "Failed to set kill message.\n");
+		exit(1);
+	}
+
+	EVTAG_ASSIGN(attack, weapon, "feather");
+	EVTAG_ASSIGN(attack, action, "tickle");
+
+	evutil_gettimeofday(&tv_start, NULL);
+	for (i = 0; i < 1000; ++i) {
+		run = EVTAG_ADD(msg, run);
+		if (run == NULL) {
+			fprintf(stderr, "Failed to add run message.\n");
+			exit(1);
+		}
+		EVTAG_ASSIGN(run, how, "very fast but with some data in it");
+		EVTAG_ASSIGN(run, fixed_bytes,
+		    (unsigned char*)"012345678901234567890123");
+	}
+
+	if (msg_complete(msg) == -1) {
+		fprintf(stderr, "Failed to make complete message.\n");
+		exit(1);
+	}
+
+	evtag_marshal_msg(tmp, 0xdeaf, msg);
+
+	if (evtag_peek(tmp, &tag) == -1) {
+		fprintf(stderr, "Failed to peak tag.\n");
+		exit (1);
+	}
+
+	if (tag != 0xdeaf) {
+		fprintf(stderr, "Got incorrect tag: %0x.\n", tag);
+		exit (1);
+	}
+
+	msg2 = msg_new();
+	if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1) {
+		fprintf(stderr, "Failed to unmarshal message.\n");
+		exit(1);
+	}
+
+	evutil_gettimeofday(&tv_end, NULL);
+	evutil_timersub(&tv_end, &tv_start, &tv_end);
+	fprintf(stderr, "(%.1f us/add) ",
+	    (float)tv_end.tv_sec/(float)i * 1000000.0 +
+	    tv_end.tv_usec / (float)i);
+
+	if (!EVTAG_HAS(msg2, from_name) ||
+	    !EVTAG_HAS(msg2, to_name) ||
+	    !EVTAG_HAS(msg2, attack)) {
+		fprintf(stderr, "Missing data structures.\n");
+		exit(1);
+	}
+
+	if (EVTAG_LEN(msg2, run) != i) {
+		fprintf(stderr, "Wrong number of run messages.\n");
+		exit(1);
+	}
+
+	msg_free(msg);
+	msg_free(msg2);
+
+	evbuffer_free(tmp);
+
+	fprintf(stdout, "OK\n");
+}
+#endif
+
+static void
+test_evutil_strtoll(void)
+{
+        const char *s;
+        char *endptr;
+        setup_test("evutil_stroll: ");
+        test_ok = 0;
+
+        if (evutil_strtoll("5000000000", NULL, 10) != ((ev_int64_t)5000000)*1000)
+                goto err;
+        if (evutil_strtoll("-5000000000", NULL, 10) != ((ev_int64_t)5000000)*-1000)
+                goto err;
+        s = " 99999stuff";
+        if (evutil_strtoll(s, &endptr, 10) != (ev_int64_t)99999)
+                goto err;
+        if (endptr != s+6)
+                goto err;
+        if (evutil_strtoll("foo", NULL, 10) != 0)
+                goto err;
+
+        test_ok = 1;
+ err:
+        cleanup_test();
+}
+
+
+int
+main (int argc, char **argv)
+{
+#ifdef WIN32
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	int	err;
+
+	wVersionRequested = MAKEWORD( 2, 2 );
+
+	err = WSAStartup( wVersionRequested, &wsaData );
+#endif
+
+#ifndef WIN32
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+		return (1);
+#endif
+	setvbuf(stdout, NULL, _IONBF, 0);
+
+	/* Initalize the event library */
+	global_base = event_init();
+
+	test_registerfds();
+
+        test_evutil_strtoll();
+
+	/* use the global event base and need to be called first */
+	test_priorities(1);
+	test_priorities(2);
+	test_priorities(3);
+
+	test_evbuffer();
+	test_evbuffer_find();
+	
+	test_bufferevent();
+	test_bufferevent_watermarks();
+
+	test_free_active_base();
+
+	test_event_base_new();
+
+	http_suite();
+
+#ifndef WIN32
+	rpc_suite();
+#endif
+
+	dns_suite();
+	
+#ifndef WIN32
+	test_fork();
+#endif
+
+	test_simpleread();
+
+	test_simplewrite();
+
+	test_multiple();
+
+	test_persistent();
+
+	test_combined();
+
+	test_simpletimeout();
+#ifndef WIN32
+	test_simplesignal();
+	test_multiplesignal();
+	test_immediatesignal();
+#endif
+	test_loopexit();
+	test_loopbreak();
+
+	test_loopexit_multiple();
+	
+	test_multiple_events_for_same_fd();
+
+	test_want_only_once();
+
+	evtag_test();
+
+#ifndef WIN32
+	rpc_test();
+
+	test_signal_dealloc();
+	test_signal_pipeloss();
+	test_signal_switchbase();
+	test_signal_restore();
+	test_signal_assert();
+	test_signal_while_processing();
+#endif
+	
+	return (0);
+}
+
diff --git a/third_party/libevent/test/regress.gen.c b/third_party/libevent/test/regress.gen.c
new file mode 100644
index 0000000..0918fc0
--- /dev/null
+++ b/third_party/libevent/test/regress.gen.c
@@ -0,0 +1,878 @@
+/*
+ * Automatically generated from ./regress.rpc
+ * by event_rpcgen.py/0.1.  DO NOT EDIT THIS FILE.
+ */
+
+#include <sys/types.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#define EVENT_NO_STRUCT
+#include <event.h>
+
+#ifdef _EVENT___func__
+#define __func__ _EVENT___func__
+#endif
+
+#include "./regress.gen.h"
+
+void event_err(int eval, const char *fmt, ...);
+void event_warn(const char *fmt, ...);
+void event_errx(int eval, const char *fmt, ...);
+void event_warnx(const char *fmt, ...);
+
+
+/*
+ * Implementation of msg
+ */
+
+static struct msg_access_ __msg_base = {
+  msg_from_name_assign,
+  msg_from_name_get,
+  msg_to_name_assign,
+  msg_to_name_get,
+  msg_attack_assign,
+  msg_attack_get,
+  msg_run_assign,
+  msg_run_get,
+  msg_run_add,
+};
+
+struct msg *
+msg_new(void)
+{
+  struct msg *tmp;
+  if ((tmp = malloc(sizeof(struct msg))) == NULL) {
+    event_warn("%s: malloc", __func__);
+    return (NULL);
+  }
+  tmp->base = &__msg_base;
+
+  tmp->from_name_data = NULL;
+  tmp->from_name_set = 0;
+
+  tmp->to_name_data = NULL;
+  tmp->to_name_set = 0;
+
+  tmp->attack_data = NULL;
+  tmp->attack_set = 0;
+
+  tmp->run_data = NULL;
+  tmp->run_length = 0;
+  tmp->run_num_allocated = 0;
+  tmp->run_set = 0;
+
+  return (tmp);
+}
+
+
+
+
+struct run *
+msg_run_add(struct msg *msg)
+{
+  if (++msg->run_length >= msg->run_num_allocated) {
+    int tobe_allocated = msg->run_num_allocated;
+    struct run ** new_data = NULL;
+    tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+    new_data = (struct run **) realloc(msg->run_data,
+        tobe_allocated * sizeof(struct run *));
+    if (new_data == NULL)
+      goto error;
+    msg->run_data = new_data;
+    msg->run_num_allocated = tobe_allocated;
+  }
+  msg->run_data[msg->run_length - 1] = run_new();
+  if (msg->run_data[msg->run_length - 1] == NULL)
+    goto error;
+  msg->run_set = 1;
+  return (msg->run_data[msg->run_length - 1]);
+error:
+  --msg->run_length;
+  return (NULL);
+}
+        
+
+int
+msg_from_name_assign(struct msg *msg,
+    const char * value)
+{
+  if (msg->from_name_data != NULL)
+    free(msg->from_name_data);
+  if ((msg->from_name_data = strdup(value)) == NULL)
+    return (-1);
+  msg->from_name_set = 1;
+  return (0);
+}
+
+int
+msg_to_name_assign(struct msg *msg,
+    const char * value)
+{
+  if (msg->to_name_data != NULL)
+    free(msg->to_name_data);
+  if ((msg->to_name_data = strdup(value)) == NULL)
+    return (-1);
+  msg->to_name_set = 1;
+  return (0);
+}
+
+int
+msg_attack_assign(struct msg *msg,
+    const struct kill* value)
+{
+   struct evbuffer *tmp = NULL;
+   if (msg->attack_set) {
+     kill_clear(msg->attack_data);
+     msg->attack_set = 0;
+   } else {
+     msg->attack_data = kill_new();
+     if (msg->attack_data == NULL) {
+       event_warn("%s: kill_new()", __func__);
+       goto error;
+     }
+   }
+   if ((tmp = evbuffer_new()) == NULL) {
+     event_warn("%s: evbuffer_new()", __func__);
+     goto error;
+   }
+   kill_marshal(tmp, value);
+   if (kill_unmarshal(msg->attack_data, tmp) == -1) {
+     event_warnx("%s: kill_unmarshal", __func__);
+     goto error;
+   }
+   msg->attack_set = 1;
+   evbuffer_free(tmp);
+   return (0);
+ error:
+   if (tmp != NULL)
+     evbuffer_free(tmp);
+   if (msg->attack_data != NULL) {
+     kill_free(msg->attack_data);
+     msg->attack_data = NULL;
+   }
+   return (-1);
+}
+
+int
+msg_run_assign(struct msg *msg, int off,
+    const struct run * value)
+{
+  struct evbuffer *tmp = NULL;
+  if (!msg->run_set || off < 0 || off >= msg->run_length)
+    return (-1);
+  run_clear(msg->run_data[off]);
+  if ((tmp = evbuffer_new()) == NULL) {
+    event_warn("%s: evbuffer_new()", __func__);
+    goto error;
+  }
+  run_marshal(tmp, value);
+  if (run_unmarshal(msg->run_data[off], tmp) == -1) {
+    event_warnx("%s: run_unmarshal", __func__);
+    goto error;
+  }
+  evbuffer_free(tmp);
+  return (0);
+error:
+  if (tmp != NULL)
+    evbuffer_free(tmp);
+  run_clear(msg->run_data[off]);
+  return (-1);
+}
+
+int
+msg_from_name_get(struct msg *msg, char * *value)
+{
+  if (msg->from_name_set != 1)
+    return (-1);
+  *value = msg->from_name_data;
+  return (0);
+}
+
+int
+msg_to_name_get(struct msg *msg, char * *value)
+{
+  if (msg->to_name_set != 1)
+    return (-1);
+  *value = msg->to_name_data;
+  return (0);
+}
+
+int
+msg_attack_get(struct msg *msg, struct kill* *value)
+{
+  if (msg->attack_set != 1) {
+    msg->attack_data = kill_new();
+    if (msg->attack_data == NULL)
+      return (-1);
+    msg->attack_set = 1;
+  }
+  *value = msg->attack_data;
+  return (0);
+}
+
+int
+msg_run_get(struct msg *msg, int offset,
+    struct run * *value)
+{
+  if (!msg->run_set || offset < 0 || offset >= msg->run_length)
+    return (-1);
+  *value = msg->run_data[offset];
+  return (0);
+}
+
+void
+msg_clear(struct msg *tmp)
+{
+  if (tmp->from_name_set == 1) {
+    free (tmp->from_name_data);
+    tmp->from_name_data = NULL;
+    tmp->from_name_set = 0;
+  }
+  if (tmp->to_name_set == 1) {
+    free (tmp->to_name_data);
+    tmp->to_name_data = NULL;
+    tmp->to_name_set = 0;
+  }
+  if (tmp->attack_set == 1) {
+    kill_free(tmp->attack_data);
+    tmp->attack_data = NULL;
+    tmp->attack_set = 0;
+  }
+  if (tmp->run_set == 1) {
+    int i;
+    for (i = 0; i < tmp->run_length; ++i) {
+      run_free(tmp->run_data[i]);
+    }
+    free(tmp->run_data);
+    tmp->run_data = NULL;
+    tmp->run_set = 0;
+    tmp->run_length = 0;
+    tmp->run_num_allocated = 0;
+  }
+}
+
+void
+msg_free(struct msg *tmp)
+{
+  if (tmp->from_name_data != NULL)
+      free (tmp->from_name_data); 
+  if (tmp->to_name_data != NULL)
+      free (tmp->to_name_data); 
+  if (tmp->attack_data != NULL)
+      kill_free(tmp->attack_data); 
+  if (tmp->run_data != NULL) {
+    int i;
+    for (i = 0; i < tmp->run_length; ++i) {
+      run_free(tmp->run_data[i]); 
+      tmp->run_data[i] = NULL;
+    }
+    free(tmp->run_data);
+    tmp->run_data = NULL;
+    tmp->run_length = 0;
+    tmp->run_num_allocated = 0;
+  }
+  free(tmp);
+}
+
+void
+msg_marshal(struct evbuffer *evbuf, const struct msg *tmp){
+  evtag_marshal_string(evbuf, MSG_FROM_NAME, tmp->from_name_data);
+  evtag_marshal_string(evbuf, MSG_TO_NAME, tmp->to_name_data);
+  if (tmp->attack_set) {
+    evtag_marshal_kill(evbuf, MSG_ATTACK, tmp->attack_data);
+  }
+  {
+    int i;
+    for (i = 0; i < tmp->run_length; ++i) {
+      evtag_marshal_run(evbuf, MSG_RUN, tmp->run_data[i]);
+    }
+  }
+}
+
+int
+msg_unmarshal(struct msg *tmp,  struct evbuffer *evbuf)
+{
+  ev_uint32_t tag;
+  while (EVBUFFER_LENGTH(evbuf) > 0) {
+    if (evtag_peek(evbuf, &tag) == -1)
+      return (-1);
+    switch (tag) {
+
+      case MSG_FROM_NAME:
+
+        if (tmp->from_name_set)
+          return (-1);
+        if (evtag_unmarshal_string(evbuf, MSG_FROM_NAME, &tmp->from_name_data) == -1) {
+          event_warnx("%s: failed to unmarshal from_name", __func__);
+          return (-1);
+        }
+        tmp->from_name_set = 1;
+        break;
+
+      case MSG_TO_NAME:
+
+        if (tmp->to_name_set)
+          return (-1);
+        if (evtag_unmarshal_string(evbuf, MSG_TO_NAME, &tmp->to_name_data) == -1) {
+          event_warnx("%s: failed to unmarshal to_name", __func__);
+          return (-1);
+        }
+        tmp->to_name_set = 1;
+        break;
+
+      case MSG_ATTACK:
+
+        if (tmp->attack_set)
+          return (-1);
+        tmp->attack_data = kill_new();
+        if (tmp->attack_data == NULL)
+          return (-1);
+        if (evtag_unmarshal_kill(evbuf, MSG_ATTACK, tmp->attack_data) == -1) {
+          event_warnx("%s: failed to unmarshal attack", __func__);
+          return (-1);
+        }
+        tmp->attack_set = 1;
+        break;
+
+      case MSG_RUN:
+
+        if (msg_run_add(tmp) == NULL)
+          return (-1);
+        if (evtag_unmarshal_run(evbuf, MSG_RUN,
+          tmp->run_data[tmp->run_length - 1]) == -1) {
+          --tmp->run_length;
+          event_warnx("%s: failed to unmarshal run", __func__);
+          return (-1);
+        }
+        tmp->run_set = 1;
+        break;
+
+      default:
+        return -1;
+    }
+  }
+
+  if (msg_complete(tmp) == -1)
+    return (-1);
+  return (0);
+}
+
+int
+msg_complete(struct msg *msg)
+{
+  if (!msg->from_name_set)
+    return (-1);
+  if (!msg->to_name_set)
+    return (-1);
+  if (msg->attack_set && kill_complete(msg->attack_data) == -1)
+    return (-1);
+  {
+    int i;
+    for (i = 0; i < msg->run_length; ++i) {
+      if (run_complete(msg->run_data[i]) == -1)
+        return (-1);
+    }
+  }
+  return (0);
+}
+
+int
+evtag_unmarshal_msg(struct evbuffer *evbuf, ev_uint32_t need_tag, struct msg *msg)
+{
+  ev_uint32_t tag;
+  int res = -1;
+
+  struct evbuffer *tmp = evbuffer_new();
+
+  if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+    goto error;
+
+  if (msg_unmarshal(msg, tmp) == -1)
+    goto error;
+
+  res = 0;
+
+ error:
+  evbuffer_free(tmp);
+  return (res);
+}
+
+void
+evtag_marshal_msg(struct evbuffer *evbuf, ev_uint32_t tag, const struct msg *msg)
+{
+  struct evbuffer *_buf = evbuffer_new();
+  assert(_buf != NULL);
+  evbuffer_drain(_buf, -1);
+  msg_marshal(_buf, msg);
+  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), EVBUFFER_LENGTH(_buf));
+  evbuffer_free(_buf);
+}
+
+/*
+ * Implementation of kill
+ */
+
+static struct kill_access_ __kill_base = {
+  kill_weapon_assign,
+  kill_weapon_get,
+  kill_action_assign,
+  kill_action_get,
+  kill_how_often_assign,
+  kill_how_often_get,
+};
+
+struct kill *
+kill_new(void)
+{
+  struct kill *tmp;
+  if ((tmp = malloc(sizeof(struct kill))) == NULL) {
+    event_warn("%s: malloc", __func__);
+    return (NULL);
+  }
+  tmp->base = &__kill_base;
+
+  tmp->weapon_data = NULL;
+  tmp->weapon_set = 0;
+
+  tmp->action_data = NULL;
+  tmp->action_set = 0;
+
+  tmp->how_often_data = 0;
+  tmp->how_often_set = 0;
+
+  return (tmp);
+}
+
+
+
+
+int
+kill_weapon_assign(struct kill *msg,
+    const char * value)
+{
+  if (msg->weapon_data != NULL)
+    free(msg->weapon_data);
+  if ((msg->weapon_data = strdup(value)) == NULL)
+    return (-1);
+  msg->weapon_set = 1;
+  return (0);
+}
+
+int
+kill_action_assign(struct kill *msg,
+    const char * value)
+{
+  if (msg->action_data != NULL)
+    free(msg->action_data);
+  if ((msg->action_data = strdup(value)) == NULL)
+    return (-1);
+  msg->action_set = 1;
+  return (0);
+}
+
+int
+kill_how_often_assign(struct kill *msg, const ev_uint32_t value)
+{
+  msg->how_often_set = 1;
+  msg->how_often_data = value;
+  return (0);
+}
+
+int
+kill_weapon_get(struct kill *msg, char * *value)
+{
+  if (msg->weapon_set != 1)
+    return (-1);
+  *value = msg->weapon_data;
+  return (0);
+}
+
+int
+kill_action_get(struct kill *msg, char * *value)
+{
+  if (msg->action_set != 1)
+    return (-1);
+  *value = msg->action_data;
+  return (0);
+}
+
+int
+kill_how_often_get(struct kill *msg, ev_uint32_t *value)
+{
+  if (msg->how_often_set != 1)
+    return (-1);
+  *value = msg->how_often_data;
+  return (0);
+}
+
+void
+kill_clear(struct kill *tmp)
+{
+  if (tmp->weapon_set == 1) {
+    free (tmp->weapon_data);
+    tmp->weapon_data = NULL;
+    tmp->weapon_set = 0;
+  }
+  if (tmp->action_set == 1) {
+    free (tmp->action_data);
+    tmp->action_data = NULL;
+    tmp->action_set = 0;
+  }
+  tmp->how_often_set = 0;
+}
+
+void
+kill_free(struct kill *tmp)
+{
+  if (tmp->weapon_data != NULL)
+      free (tmp->weapon_data); 
+  if (tmp->action_data != NULL)
+      free (tmp->action_data); 
+  free(tmp);
+}
+
+void
+kill_marshal(struct evbuffer *evbuf, const struct kill *tmp){
+  evtag_marshal_string(evbuf, KILL_WEAPON, tmp->weapon_data);
+  evtag_marshal_string(evbuf, KILL_ACTION, tmp->action_data);
+  if (tmp->how_often_set) {
+    evtag_marshal_int(evbuf, KILL_HOW_OFTEN, tmp->how_often_data);
+  }
+}
+
+int
+kill_unmarshal(struct kill *tmp,  struct evbuffer *evbuf)
+{
+  ev_uint32_t tag;
+  while (EVBUFFER_LENGTH(evbuf) > 0) {
+    if (evtag_peek(evbuf, &tag) == -1)
+      return (-1);
+    switch (tag) {
+
+      case KILL_WEAPON:
+
+        if (tmp->weapon_set)
+          return (-1);
+        if (evtag_unmarshal_string(evbuf, KILL_WEAPON, &tmp->weapon_data) == -1) {
+          event_warnx("%s: failed to unmarshal weapon", __func__);
+          return (-1);
+        }
+        tmp->weapon_set = 1;
+        break;
+
+      case KILL_ACTION:
+
+        if (tmp->action_set)
+          return (-1);
+        if (evtag_unmarshal_string(evbuf, KILL_ACTION, &tmp->action_data) == -1) {
+          event_warnx("%s: failed to unmarshal action", __func__);
+          return (-1);
+        }
+        tmp->action_set = 1;
+        break;
+
+      case KILL_HOW_OFTEN:
+
+        if (tmp->how_often_set)
+          return (-1);
+        if (evtag_unmarshal_int(evbuf, KILL_HOW_OFTEN, &tmp->how_often_data) == -1) {
+          event_warnx("%s: failed to unmarshal how_often", __func__);
+          return (-1);
+        }
+        tmp->how_often_set = 1;
+        break;
+
+      default:
+        return -1;
+    }
+  }
+
+  if (kill_complete(tmp) == -1)
+    return (-1);
+  return (0);
+}
+
+int
+kill_complete(struct kill *msg)
+{
+  if (!msg->weapon_set)
+    return (-1);
+  if (!msg->action_set)
+    return (-1);
+  return (0);
+}
+
+int
+evtag_unmarshal_kill(struct evbuffer *evbuf, ev_uint32_t need_tag, struct kill *msg)
+{
+  ev_uint32_t tag;
+  int res = -1;
+
+  struct evbuffer *tmp = evbuffer_new();
+
+  if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+    goto error;
+
+  if (kill_unmarshal(msg, tmp) == -1)
+    goto error;
+
+  res = 0;
+
+ error:
+  evbuffer_free(tmp);
+  return (res);
+}
+
+void
+evtag_marshal_kill(struct evbuffer *evbuf, ev_uint32_t tag, const struct kill *msg)
+{
+  struct evbuffer *_buf = evbuffer_new();
+  assert(_buf != NULL);
+  evbuffer_drain(_buf, -1);
+  kill_marshal(_buf, msg);
+  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), EVBUFFER_LENGTH(_buf));
+  evbuffer_free(_buf);
+}
+
+/*
+ * Implementation of run
+ */
+
+static struct run_access_ __run_base = {
+  run_how_assign,
+  run_how_get,
+  run_some_bytes_assign,
+  run_some_bytes_get,
+  run_fixed_bytes_assign,
+  run_fixed_bytes_get,
+};
+
+struct run *
+run_new(void)
+{
+  struct run *tmp;
+  if ((tmp = malloc(sizeof(struct run))) == NULL) {
+    event_warn("%s: malloc", __func__);
+    return (NULL);
+  }
+  tmp->base = &__run_base;
+
+  tmp->how_data = NULL;
+  tmp->how_set = 0;
+
+  tmp->some_bytes_data = NULL;
+  tmp->some_bytes_length = 0;
+  tmp->some_bytes_set = 0;
+
+  memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
+  tmp->fixed_bytes_set = 0;
+
+  return (tmp);
+}
+
+
+
+
+int
+run_how_assign(struct run *msg,
+    const char * value)
+{
+  if (msg->how_data != NULL)
+    free(msg->how_data);
+  if ((msg->how_data = strdup(value)) == NULL)
+    return (-1);
+  msg->how_set = 1;
+  return (0);
+}
+
+int
+run_some_bytes_assign(struct run *msg, const ev_uint8_t * value, ev_uint32_t len)
+{
+  if (msg->some_bytes_data != NULL)
+    free (msg->some_bytes_data);
+  msg->some_bytes_data = malloc(len);
+  if (msg->some_bytes_data == NULL)
+    return (-1);
+  msg->some_bytes_set = 1;
+  msg->some_bytes_length = len;
+  memcpy(msg->some_bytes_data, value, len);
+  return (0);
+}
+
+int
+run_fixed_bytes_assign(struct run *msg, const ev_uint8_t *value)
+{
+  msg->fixed_bytes_set = 1;
+  memcpy(msg->fixed_bytes_data, value, 24);
+  return (0);
+}
+
+int
+run_how_get(struct run *msg, char * *value)
+{
+  if (msg->how_set != 1)
+    return (-1);
+  *value = msg->how_data;
+  return (0);
+}
+
+int
+run_some_bytes_get(struct run *msg, ev_uint8_t * *value, ev_uint32_t *plen)
+{
+  if (msg->some_bytes_set != 1)
+    return (-1);
+  *value = msg->some_bytes_data;
+  *plen = msg->some_bytes_length;
+  return (0);
+}
+
+int
+run_fixed_bytes_get(struct run *msg, ev_uint8_t **value)
+{
+  if (msg->fixed_bytes_set != 1)
+    return (-1);
+  *value = msg->fixed_bytes_data;
+  return (0);
+}
+
+void
+run_clear(struct run *tmp)
+{
+  if (tmp->how_set == 1) {
+    free (tmp->how_data);
+    tmp->how_data = NULL;
+    tmp->how_set = 0;
+  }
+  if (tmp->some_bytes_set == 1) {
+    free (tmp->some_bytes_data);
+    tmp->some_bytes_data = NULL;
+    tmp->some_bytes_length = 0;
+    tmp->some_bytes_set = 0;
+  }
+  tmp->fixed_bytes_set = 0;
+  memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
+}
+
+void
+run_free(struct run *tmp)
+{
+  if (tmp->how_data != NULL)
+      free (tmp->how_data); 
+  if (tmp->some_bytes_data != NULL)
+      free (tmp->some_bytes_data); 
+  free(tmp);
+}
+
+void
+run_marshal(struct evbuffer *evbuf, const struct run *tmp){
+  evtag_marshal_string(evbuf, RUN_HOW, tmp->how_data);
+  if (tmp->some_bytes_set) {
+    evtag_marshal(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length);
+  }
+  evtag_marshal(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, sizeof(tmp->fixed_bytes_data));
+}
+
+int
+run_unmarshal(struct run *tmp,  struct evbuffer *evbuf)
+{
+  ev_uint32_t tag;
+  while (EVBUFFER_LENGTH(evbuf) > 0) {
+    if (evtag_peek(evbuf, &tag) == -1)
+      return (-1);
+    switch (tag) {
+
+      case RUN_HOW:
+
+        if (tmp->how_set)
+          return (-1);
+        if (evtag_unmarshal_string(evbuf, RUN_HOW, &tmp->how_data) == -1) {
+          event_warnx("%s: failed to unmarshal how", __func__);
+          return (-1);
+        }
+        tmp->how_set = 1;
+        break;
+
+      case RUN_SOME_BYTES:
+
+        if (tmp->some_bytes_set)
+          return (-1);
+        if (evtag_payload_length(evbuf, &tmp->some_bytes_length) == -1)
+          return (-1);
+        if (tmp->some_bytes_length > EVBUFFER_LENGTH(evbuf))
+          return (-1);
+        if ((tmp->some_bytes_data = malloc(tmp->some_bytes_length)) == NULL)
+          return (-1);
+        if (evtag_unmarshal_fixed(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length) == -1) {
+          event_warnx("%s: failed to unmarshal some_bytes", __func__);
+          return (-1);
+        }
+        tmp->some_bytes_set = 1;
+        break;
+
+      case RUN_FIXED_BYTES:
+
+        if (tmp->fixed_bytes_set)
+          return (-1);
+        if (evtag_unmarshal_fixed(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, sizeof(tmp->fixed_bytes_data)) == -1) {
+          event_warnx("%s: failed to unmarshal fixed_bytes", __func__);
+          return (-1);
+        }
+        tmp->fixed_bytes_set = 1;
+        break;
+
+      default:
+        return -1;
+    }
+  }
+
+  if (run_complete(tmp) == -1)
+    return (-1);
+  return (0);
+}
+
+int
+run_complete(struct run *msg)
+{
+  if (!msg->how_set)
+    return (-1);
+  if (!msg->fixed_bytes_set)
+    return (-1);
+  return (0);
+}
+
+int
+evtag_unmarshal_run(struct evbuffer *evbuf, ev_uint32_t need_tag, struct run *msg)
+{
+  ev_uint32_t tag;
+  int res = -1;
+
+  struct evbuffer *tmp = evbuffer_new();
+
+  if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
+    goto error;
+
+  if (run_unmarshal(msg, tmp) == -1)
+    goto error;
+
+  res = 0;
+
+ error:
+  evbuffer_free(tmp);
+  return (res);
+}
+
+void
+evtag_marshal_run(struct evbuffer *evbuf, ev_uint32_t tag, const struct run *msg)
+{
+  struct evbuffer *_buf = evbuffer_new();
+  assert(_buf != NULL);
+  evbuffer_drain(_buf, -1);
+  run_marshal(_buf, msg);
+  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), EVBUFFER_LENGTH(_buf));
+  evbuffer_free(_buf);
+}
+
diff --git a/third_party/libevent/test/regress.gen.h b/third_party/libevent/test/regress.gen.h
new file mode 100644
index 0000000..b1feacd
--- /dev/null
+++ b/third_party/libevent/test/regress.gen.h
@@ -0,0 +1,183 @@
+/*
+ * Automatically generated from ./regress.rpc
+ */
+
+#ifndef ___REGRESS_RPC_
+#define ___REGRESS_RPC_
+
+#include <event-config.h>
+#ifdef _EVENT_HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)
+#ifdef __GNUC__
+#define EVTAG_ASSIGN(msg, member, args...) (*(msg)->base->member##_assign)(msg, ## args)
+#define EVTAG_GET(msg, member, args...) (*(msg)->base->member##_get)(msg, ## args)
+#else
+#define EVTAG_ASSIGN(msg, member, ...) (*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)
+#define EVTAG_GET(msg, member, ...) (*(msg)->base->member##_get)(msg, ## __VA_ARGS__)
+#endif
+#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)
+#define EVTAG_LEN(msg, member) ((msg)->member##_length)
+
+struct msg;
+struct kill;
+struct run;
+
+/* Tag definition for msg */
+enum msg_ {
+  MSG_FROM_NAME=1,
+  MSG_TO_NAME=2,
+  MSG_ATTACK=3,
+  MSG_RUN=4,
+  MSG_MAX_TAGS
+};
+
+/* Structure declaration for msg */
+struct msg_access_ {
+  int (*from_name_assign)(struct msg *, const char *);
+  int (*from_name_get)(struct msg *, char * *);
+  int (*to_name_assign)(struct msg *, const char *);
+  int (*to_name_get)(struct msg *, char * *);
+  int (*attack_assign)(struct msg *, const struct kill*);
+  int (*attack_get)(struct msg *, struct kill* *);
+  int (*run_assign)(struct msg *, int, const struct run *);
+  int (*run_get)(struct msg *, int, struct run * *);
+  struct run * (*run_add)(struct msg *);
+};
+
+struct msg {
+  struct msg_access_ *base;
+
+  char *from_name_data;
+  char *to_name_data;
+  struct kill* attack_data;
+  struct run **run_data;
+  int run_length;
+  int run_num_allocated;
+
+  ev_uint8_t from_name_set;
+  ev_uint8_t to_name_set;
+  ev_uint8_t attack_set;
+  ev_uint8_t run_set;
+};
+
+struct msg *msg_new(void);
+void msg_free(struct msg *);
+void msg_clear(struct msg *);
+void msg_marshal(struct evbuffer *, const struct msg *);
+int msg_unmarshal(struct msg *, struct evbuffer *);
+int msg_complete(struct msg *);
+void evtag_marshal_msg(struct evbuffer *, ev_uint32_t, 
+    const struct msg *);
+int evtag_unmarshal_msg(struct evbuffer *, ev_uint32_t,
+    struct msg *);
+int msg_from_name_assign(struct msg *, const char *);
+int msg_from_name_get(struct msg *, char * *);
+int msg_to_name_assign(struct msg *, const char *);
+int msg_to_name_get(struct msg *, char * *);
+int msg_attack_assign(struct msg *, const struct kill*);
+int msg_attack_get(struct msg *, struct kill* *);
+int msg_run_assign(struct msg *, int, const struct run *);
+int msg_run_get(struct msg *, int, struct run * *);
+struct run * msg_run_add(struct msg *);
+/* --- msg done --- */
+
+/* Tag definition for kill */
+enum kill_ {
+  KILL_WEAPON=65825,
+  KILL_ACTION=2,
+  KILL_HOW_OFTEN=3,
+  KILL_MAX_TAGS
+};
+
+/* Structure declaration for kill */
+struct kill_access_ {
+  int (*weapon_assign)(struct kill *, const char *);
+  int (*weapon_get)(struct kill *, char * *);
+  int (*action_assign)(struct kill *, const char *);
+  int (*action_get)(struct kill *, char * *);
+  int (*how_often_assign)(struct kill *, const ev_uint32_t);
+  int (*how_often_get)(struct kill *, ev_uint32_t *);
+};
+
+struct kill {
+  struct kill_access_ *base;
+
+  char *weapon_data;
+  char *action_data;
+  ev_uint32_t how_often_data;
+
+  ev_uint8_t weapon_set;
+  ev_uint8_t action_set;
+  ev_uint8_t how_often_set;
+};
+
+struct kill *kill_new(void);
+void kill_free(struct kill *);
+void kill_clear(struct kill *);
+void kill_marshal(struct evbuffer *, const struct kill *);
+int kill_unmarshal(struct kill *, struct evbuffer *);
+int kill_complete(struct kill *);
+void evtag_marshal_kill(struct evbuffer *, ev_uint32_t, 
+    const struct kill *);
+int evtag_unmarshal_kill(struct evbuffer *, ev_uint32_t,
+    struct kill *);
+int kill_weapon_assign(struct kill *, const char *);
+int kill_weapon_get(struct kill *, char * *);
+int kill_action_assign(struct kill *, const char *);
+int kill_action_get(struct kill *, char * *);
+int kill_how_often_assign(struct kill *, const ev_uint32_t);
+int kill_how_often_get(struct kill *, ev_uint32_t *);
+/* --- kill done --- */
+
+/* Tag definition for run */
+enum run_ {
+  RUN_HOW=1,
+  RUN_SOME_BYTES=2,
+  RUN_FIXED_BYTES=3,
+  RUN_MAX_TAGS
+};
+
+/* Structure declaration for run */
+struct run_access_ {
+  int (*how_assign)(struct run *, const char *);
+  int (*how_get)(struct run *, char * *);
+  int (*some_bytes_assign)(struct run *, const ev_uint8_t *, ev_uint32_t);
+  int (*some_bytes_get)(struct run *, ev_uint8_t * *, ev_uint32_t *);
+  int (*fixed_bytes_assign)(struct run *, const ev_uint8_t *);
+  int (*fixed_bytes_get)(struct run *, ev_uint8_t **);
+};
+
+struct run {
+  struct run_access_ *base;
+
+  char *how_data;
+  ev_uint8_t *some_bytes_data;
+  ev_uint32_t some_bytes_length;
+  ev_uint8_t fixed_bytes_data[24];
+
+  ev_uint8_t how_set;
+  ev_uint8_t some_bytes_set;
+  ev_uint8_t fixed_bytes_set;
+};
+
+struct run *run_new(void);
+void run_free(struct run *);
+void run_clear(struct run *);
+void run_marshal(struct evbuffer *, const struct run *);
+int run_unmarshal(struct run *, struct evbuffer *);
+int run_complete(struct run *);
+void evtag_marshal_run(struct evbuffer *, ev_uint32_t, 
+    const struct run *);
+int evtag_unmarshal_run(struct evbuffer *, ev_uint32_t,
+    struct run *);
+int run_how_assign(struct run *, const char *);
+int run_how_get(struct run *, char * *);
+int run_some_bytes_assign(struct run *, const ev_uint8_t *, ev_uint32_t);
+int run_some_bytes_get(struct run *, ev_uint8_t * *, ev_uint32_t *);
+int run_fixed_bytes_assign(struct run *, const ev_uint8_t *);
+int run_fixed_bytes_get(struct run *, ev_uint8_t **);
+/* --- run done --- */
+
+#endif  /* ___REGRESS_RPC_ */
diff --git a/third_party/libevent/test/regress.h b/third_party/libevent/test/regress.h
new file mode 100644
index 0000000..4060ff5
--- /dev/null
+++ b/third_party/libevent/test/regress.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _REGRESS_H_
+#define _REGRESS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void http_suite(void);
+void http_basic_test(void);
+
+void rpc_suite(void);
+
+void dns_suite(void);
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REGRESS_H_ */
diff --git a/third_party/libevent/test/regress.rpc b/third_party/libevent/test/regress.rpc
new file mode 100644
index 0000000..65ca95d
--- /dev/null
+++ b/third_party/libevent/test/regress.rpc
@@ -0,0 +1,20 @@
+/* tests data packing and unpacking */
+
+struct msg {
+	string from_name = 1;
+	string to_name = 2;
+	optional struct[kill] attack = 3;
+	array struct[run] run = 4;
+}
+
+struct kill {
+	string weapon = 0x10121;
+	string action = 2;
+	optional int how_often = 3;
+}
+
+struct run {
+	string how = 1;
+	optional bytes some_bytes = 2;
+	bytes fixed_bytes[24] = 3;
+}
diff --git a/third_party/libevent/test/regress_dns.c b/third_party/libevent/test/regress_dns.c
new file mode 100644
index 0000000..129cdad
--- /dev/null
+++ b/third_party/libevent/test/regress_dns.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event.h"
+#include "evdns.h"
+#include "log.h"
+
+static int dns_ok = 0;
+static int dns_err = 0;
+
+void dns_suite(void);
+
+static void
+dns_gethostbyname_cb(int result, char type, int count, int ttl,
+    void *addresses, void *arg)
+{
+	dns_ok = dns_err = 0;
+
+	if (result == DNS_ERR_TIMEOUT) {
+		fprintf(stdout, "[Timed out] ");
+		dns_err = result;
+		goto out;
+	}
+
+	if (result != DNS_ERR_NONE) {
+		fprintf(stdout, "[Error code %d] ", result);
+		goto out;
+	}
+
+	fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl);
+
+	switch (type) {
+	case DNS_IPv6_AAAA: {
+#if defined(HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
+		struct in6_addr *in6_addrs = addresses;
+		char buf[INET6_ADDRSTRLEN+1];
+		int i;
+		/* a resolution that's not valid does not help */
+		if (ttl < 0)
+			goto out;
+		for (i = 0; i < count; ++i) {
+			const char *b = inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf));
+			if (b)
+				fprintf(stderr, "%s ", b);
+			else
+				fprintf(stderr, "%s ", strerror(errno));
+		}
+#endif
+		break;
+	}
+	case DNS_IPv4_A: {
+		struct in_addr *in_addrs = addresses;
+		int i;
+		/* a resolution that's not valid does not help */
+		if (ttl < 0)
+			goto out;
+		for (i = 0; i < count; ++i)
+			fprintf(stderr, "%s ", inet_ntoa(in_addrs[i]));
+		break;
+	}
+	case DNS_PTR:
+		/* may get at most one PTR */
+		if (count != 1)
+			goto out;
+
+		fprintf(stderr, "%s ", *(char **)addresses);
+		break;
+	default:
+		goto out;
+	}
+
+	dns_ok = type;
+
+out:
+	event_loopexit(NULL);
+}
+
+static void
+dns_gethostbyname(void)
+{
+	fprintf(stdout, "Simple DNS resolve: ");
+	dns_ok = 0;
+	evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL);
+	event_dispatch();
+
+	if (dns_ok == DNS_IPv4_A) {
+		fprintf(stdout, "OK\n");
+	} else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+}
+
+static void
+dns_gethostbyname6(void)
+{
+	fprintf(stdout, "IPv6 DNS resolve: ");
+	dns_ok = 0;
+	evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL);
+	event_dispatch();
+
+	if (dns_ok == DNS_IPv6_AAAA) {
+		fprintf(stdout, "OK\n");
+	} else if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) {
+		fprintf(stdout, "SKIPPED\n");
+	} else {
+		fprintf(stdout, "FAILED (%d)\n", dns_ok);
+		exit(1);
+	}
+}
+
+static void
+dns_gethostbyaddr(void)
+{
+	struct in_addr in;
+	in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
+	fprintf(stdout, "Simple reverse DNS resolve: ");
+	dns_ok = 0;
+	evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL);
+	event_dispatch();
+
+	if (dns_ok == DNS_PTR) {
+		fprintf(stdout, "OK\n");
+	} else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+}
+
+static int n_server_responses = 0;
+
+static void
+dns_server_request_cb(struct evdns_server_request *req, void *data)
+{
+	int i, r;
+	const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa";
+	for (i = 0; i < req->nquestions; ++i) {
+		struct in_addr ans;
+		ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
+		if (req->questions[i]->type == EVDNS_TYPE_A &&
+			req->questions[i]->dns_question_class == EVDNS_CLASS_INET &&
+			!strcmp(req->questions[i]->name, "zz.example.com")) {
+			r = evdns_server_request_add_a_reply(req, "zz.example.com",
+												 1, &ans.s_addr, 12345);
+			if (r<0)
+				dns_ok = 0;
+		} else if (req->questions[i]->type == EVDNS_TYPE_AAAA &&
+				   req->questions[i]->dns_question_class == EVDNS_CLASS_INET &&
+				   !strcmp(req->questions[i]->name, "zz.example.com")) {
+			char addr6[17] = "abcdefghijklmnop";
+			r = evdns_server_request_add_aaaa_reply(req, "zz.example.com",
+												 1, addr6, 123);
+			if (r<0)
+				dns_ok = 0;
+		} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
+				   req->questions[i]->dns_question_class == EVDNS_CLASS_INET &&
+				   !strcmp(req->questions[i]->name, TEST_ARPA)) {
+			r = evdns_server_request_add_ptr_reply(req, NULL, TEST_ARPA,
+					   "ZZ.EXAMPLE.COM", 54321);
+			if (r<0)
+				dns_ok = 0;
+		} else {
+			fprintf(stdout, "Unexpected question %d %d \"%s\" ",
+					req->questions[i]->type,
+					req->questions[i]->dns_question_class,
+					req->questions[i]->name);
+			dns_ok = 0;
+		}
+	}
+	r = evdns_server_request_respond(req, 0);
+	if (r<0) {
+		fprintf(stdout, "Couldn't send reply. ");
+		dns_ok = 0;
+	}
+}
+
+static void
+dns_server_gethostbyname_cb(int result, char type, int count, int ttl,
+							void *addresses, void *arg)
+{
+	if (result != DNS_ERR_NONE) {
+		fprintf(stdout, "Unexpected result %d. ", result);
+		dns_ok = 0;
+		goto out;
+	}
+	if (count != 1) {
+		fprintf(stdout, "Unexpected answer count %d. ", count);
+		dns_ok = 0;
+		goto out;
+	}
+	switch (type) {
+	case DNS_IPv4_A: {
+		struct in_addr *in_addrs = addresses;
+		if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) {
+			fprintf(stdout, "Bad IPv4 response \"%s\" %d. ",
+					inet_ntoa(in_addrs[0]), ttl);
+			dns_ok = 0;
+			goto out;
+		}
+		break;
+	}
+	case DNS_IPv6_AAAA: {
+#if defined (HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
+		struct in6_addr *in6_addrs = addresses;
+		char buf[INET6_ADDRSTRLEN+1];
+		if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16)
+			|| ttl != 123) {
+			const char *b = inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf));
+			fprintf(stdout, "Bad IPv6 response \"%s\" %d. ", b, ttl);
+			dns_ok = 0;
+			goto out;
+		}
+#endif
+		break;
+	}
+	case DNS_PTR: {
+		char **addrs = addresses;
+		if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || ttl != 54321) {
+			fprintf(stdout, "Bad PTR response \"%s\" %d. ",
+					addrs[0], ttl);
+			dns_ok = 0;
+			goto out;
+		}
+		break;
+	}
+	default:
+		fprintf(stdout, "Bad response type %d. ", type);
+		dns_ok = 0;
+	}
+
+ out:
+	if (++n_server_responses == 3) {
+		event_loopexit(NULL);
+	}
+}
+
+static void
+dns_server(void)
+{
+	int sock;
+	struct sockaddr_in my_addr;
+	struct evdns_server_port *port;
+	struct in_addr resolve_addr;
+
+	dns_ok = 1;
+	fprintf(stdout, "DNS server support: ");
+
+	/* Add ourself as the only nameserver, and make sure we really are
+	 * the only nameserver. */
+	evdns_nameserver_ip_add("127.0.0.1:35353");
+	if (evdns_count_nameservers() != 1) {
+		fprintf(stdout, "Couldn't set up.\n");
+		exit(1);
+	}
+
+	/* Now configure a nameserver port. */
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock == -1) {
+		perror("socket");
+		exit(1);
+	}
+#ifdef WIN32
+	{
+		u_long nonblocking = 1;
+		ioctlsocket(sock, FIONBIO, &nonblocking);
+	}
+#else
+	fcntl(sock, F_SETFL, O_NONBLOCK);
+#endif
+	memset(&my_addr, 0, sizeof(my_addr));
+	my_addr.sin_family = AF_INET;
+	my_addr.sin_port = htons(35353);
+	my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
+	if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
+		perror("bind");
+		exit (1);
+	}
+	port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL);
+
+	/* Send two queries. */
+	evdns_resolve_ipv4("zz.example.com", DNS_QUERY_NO_SEARCH,
+					   dns_server_gethostbyname_cb, NULL);
+	evdns_resolve_ipv6("zz.example.com", DNS_QUERY_NO_SEARCH,
+					   dns_server_gethostbyname_cb, NULL);
+	resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
+	evdns_resolve_reverse(&resolve_addr, 0,
+						  dns_server_gethostbyname_cb, NULL);
+
+	event_dispatch();
+
+	if (dns_ok) {
+		fprintf(stdout, "OK\n");
+	} else {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	evdns_close_server_port(port);
+	evdns_shutdown(0); /* remove ourself as nameserver. */
+#ifdef WIN32
+	closesocket(sock);
+#else
+	close(sock);
+#endif
+}
+
+void
+dns_suite(void)
+{
+	dns_server(); /* Do this before we call evdns_init. */
+
+	evdns_init();
+	dns_gethostbyname();
+	dns_gethostbyname6();
+	dns_gethostbyaddr();
+
+	evdns_shutdown(0);
+}
diff --git a/third_party/libevent/test/regress_http.c b/third_party/libevent/test/regress_http.c
new file mode 100644
index 0000000..1e2a1eb
--- /dev/null
+++ b/third_party/libevent/test/regress_http.c
@@ -0,0 +1,1476 @@
+/*
+ * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event.h"
+#include "evhttp.h"
+#include "log.h"
+#include "http-internal.h"
+
+extern int pair[];
+extern int test_ok;
+
+static struct evhttp *http;
+/* set if a test needs to call loopexit on a base */
+static struct event_base *base;
+
+void http_suite(void);
+
+void http_basic_cb(struct evhttp_request *req, void *arg);
+static void http_chunked_cb(struct evhttp_request *req, void *arg);
+void http_post_cb(struct evhttp_request *req, void *arg);
+void http_dispatcher_cb(struct evhttp_request *req, void *arg);
+static void http_large_delay_cb(struct evhttp_request *req, void *arg);
+
+static struct evhttp *
+http_setup(short *pport, struct event_base *base)
+{
+	int i;
+	struct evhttp *myhttp;
+	short port = -1;
+
+	/* Try a few different ports */
+	myhttp = evhttp_new(base);
+	for (i = 0; i < 50; ++i) {
+		if (evhttp_bind_socket(myhttp, "127.0.0.1", 8080 + i) != -1) {
+			port = 8080 + i;
+			break;
+		}
+	}
+
+	if (port == -1)
+		event_errx(1, "Could not start web server");
+
+	/* Register a callback for certain types of requests */
+	evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
+	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL);
+	evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
+	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL);
+	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
+
+	*pport = port;
+	return (myhttp);
+}
+
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 1024
+#endif
+
+static int
+http_connect(const char *address, u_short port)
+{
+	/* Stupid code for connecting */
+#ifdef WIN32
+	struct hostent *he;
+	struct sockaddr_in sin;
+#else
+	struct addrinfo ai, *aitop;
+	char strport[NI_MAXSERV];
+#endif
+	struct sockaddr *sa;
+	int slen;
+	int fd;
+	
+#ifdef WIN32
+	if (!(he = gethostbyname(address))) {
+		event_warn("gethostbyname");
+	}
+	memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(port);
+	slen = sizeof(struct sockaddr_in);
+	sa = (struct sockaddr*)&sin;
+#else
+	memset(&ai, 0, sizeof (ai));
+	ai.ai_family = AF_INET;
+	ai.ai_socktype = SOCK_STREAM;
+	snprintf(strport, sizeof (strport), "%d", port);
+	if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
+		event_warn("getaddrinfo");
+		return (-1);
+	}
+	sa = aitop->ai_addr;
+	slen = aitop->ai_addrlen;
+#endif
+        
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd == -1)
+		event_err(1, "socket failed");
+
+	if (connect(fd, sa, slen) == -1)
+		event_err(1, "connect failed");
+
+#ifndef WIN32
+	freeaddrinfo(aitop);
+#endif
+
+	return (fd);
+}
+
+static void
+http_readcb(struct bufferevent *bev, void *arg)
+{
+	const char *what = "This is funny";
+
+ 	event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
+	
+	if (evbuffer_find(bev->input,
+		(const unsigned char*) what, strlen(what)) != NULL) {
+		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+		enum message_read_status done;
+
+		req->kind = EVHTTP_RESPONSE;
+		done = evhttp_parse_firstline(req, bev->input);
+		if (done != ALL_DATA_READ)
+			goto out;
+
+		done = evhttp_parse_headers(req, bev->input);
+		if (done != ALL_DATA_READ)
+			goto out;
+
+		if (done == 1 &&
+		    evhttp_find_header(req->input_headers,
+			"Content-Type") != NULL)
+			test_ok++;
+
+	out:
+		evhttp_request_free(req);
+		bufferevent_disable(bev, EV_READ);
+		if (base)
+			event_base_loopexit(base, NULL);
+		else
+			event_loopexit(NULL);
+	}
+}
+
+static void
+http_writecb(struct bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->output) == 0) {
+		/* enable reading of the reply */
+		bufferevent_enable(bev, EV_READ);
+		test_ok++;
+	}
+}
+
+static void
+http_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+	test_ok = -2;
+	event_loopexit(NULL);
+}
+
+void
+http_basic_cb(struct evhttp_request *req, void *arg)
+{
+	struct evbuffer *evb = evbuffer_new();
+	int empty = evhttp_find_header(req->input_headers, "Empty") != NULL;
+	event_debug(("%s: called\n", __func__));
+	evbuffer_add_printf(evb, "This is funny");
+	
+	/* For multi-line headers test */
+	{
+		const char *multi =
+		    evhttp_find_header(req->input_headers,"X-multi");
+		if (multi) {
+			if (strcmp("END", multi + strlen(multi) - 3) == 0)
+				test_ok++;
+			if (evhttp_find_header(req->input_headers, "X-Last"))
+				test_ok++;
+		}
+	}
+
+	/* injecting a bad content-length */
+	if (evhttp_find_header(req->input_headers, "X-Negative"))
+		evhttp_add_header(req->output_headers,
+		    "Content-Length", "-100");
+
+	/* allow sending of an empty reply */
+	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
+	    !empty ? evb : NULL);
+
+	evbuffer_free(evb);
+}
+
+static char const* const CHUNKS[] = {
+	"This is funny",
+	"but not hilarious.",
+	"bwv 1052"
+};
+
+struct chunk_req_state {
+	struct evhttp_request *req;
+	int i;
+};
+
+static void
+http_chunked_trickle_cb(int fd, short events, void *arg)
+{
+	struct evbuffer *evb = evbuffer_new();
+	struct chunk_req_state *state = arg;
+	struct timeval when = { 0, 0 };
+
+	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
+	evhttp_send_reply_chunk(state->req, evb);
+	evbuffer_free(evb);
+
+	if (++state->i < sizeof(CHUNKS)/sizeof(CHUNKS[0])) {
+		event_once(-1, EV_TIMEOUT,
+		    http_chunked_trickle_cb, state, &when);
+	} else {
+		evhttp_send_reply_end(state->req);
+		free(state);
+	}
+}
+
+static void
+http_chunked_cb(struct evhttp_request *req, void *arg)
+{
+	struct timeval when = { 0, 0 };
+	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
+	event_debug(("%s: called\n", __func__));
+
+	memset(state, 0, sizeof(struct chunk_req_state));
+	state->req = req;
+
+	/* generate a chunked reply */
+	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
+
+	/* but trickle it across several iterations to ensure we're not
+	 * assuming it comes all at once */
+	event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
+}
+
+static void
+http_complete_write(int fd, short what, void *arg)
+{
+	struct bufferevent *bev = arg;
+	const char *http_request = "host\r\n"
+	    "Connection: close\r\n"
+	    "\r\n";
+	bufferevent_write(bev, http_request, strlen(http_request));
+}
+
+static void
+http_basic_test(void)
+{
+	struct timeval tv;
+	struct bufferevent *bev;
+	int fd;
+	const char *http_request;
+	short port = -1;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing Basic HTTP Server: ");
+
+	http = http_setup(&port, NULL);
+
+	/* bind to a second socket */
+	if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
+		fprintf(stdout, "FAILED (bind)\n");
+		exit(1);
+	}
+	
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_readcb, http_writecb,
+	    http_errorcb, NULL);
+
+	/* first half of the http request */
+	http_request =
+	    "GET /test HTTP/1.1\r\n"
+	    "Host: some";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+	timerclear(&tv);
+	tv.tv_usec = 10000;
+	event_once(-1, EV_TIMEOUT, http_complete_write, bev, &tv);
+	
+	event_dispatch();
+
+	if (test_ok != 3) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* connect to the second port */
+	bufferevent_free(bev);
+	EVUTIL_CLOSESOCKET(fd);
+
+	fd = http_connect("127.0.0.1", port + 1);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_readcb, http_writecb,
+	    http_errorcb, NULL);
+
+	http_request =
+	    "GET /test HTTP/1.1\r\n"
+	    "Host: somehost\r\n"
+	    "Connection: close\r\n"
+	    "\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+	
+	event_dispatch();
+
+	bufferevent_free(bev);
+	EVUTIL_CLOSESOCKET(fd);
+
+	evhttp_free(http);
+	
+	if (test_ok != 5) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+}
+
+static struct evhttp_connection *delayed_client;
+
+static void
+http_delay_reply(int fd, short what, void *arg)
+{
+	struct evhttp_request *req = arg;
+
+	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
+
+	++test_ok;
+}
+
+static void
+http_large_delay_cb(struct evhttp_request *req, void *arg)
+{
+	struct timeval tv;
+	timerclear(&tv);
+	tv.tv_sec = 3;
+
+	event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
+
+	/* here we close the client connection which will cause an EOF */
+	evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
+}
+
+void http_request_done(struct evhttp_request *, void *);
+void http_request_empty_done(struct evhttp_request *, void *);
+
+static void
+http_connection_test(int persistent)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+	
+	test_ok = 0;
+	fprintf(stdout, "Testing Request Connection Pipeline %s: ",
+	    persistent ? "(persistent)" : "");
+
+	http = http_setup(&port, NULL);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/*
+	 * At this point, we want to schedule a request to the HTTP
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(http_request_done, NULL);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+
+	/* We give ownership of the request to the connection */
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* try to make another request over the same connection */
+	test_ok = 0;
+	
+	req = evhttp_request_new(http_request_done, NULL);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+
+	/* 
+	 * if our connections are not supposed to be persistent; request
+	 * a close from the server.
+	 */
+	if (!persistent)
+		evhttp_add_header(req->output_headers, "Connection", "close");
+
+	/* We give ownership of the request to the connection */
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	/* make another request: request empty reply */
+	test_ok = 0;
+	
+	req = evhttp_request_new(http_request_empty_done, NULL);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Empty", "itis");
+
+	/* We give ownership of the request to the connection */
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	fprintf(stdout, "OK\n");
+}
+
+void
+http_request_done(struct evhttp_request *req, void *arg)
+{
+	const char *what = "This is funny";
+
+	if (req->response_code != HTTP_OK) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+	
+	if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+/* test date header and content length */
+
+void
+http_request_empty_done(struct evhttp_request *req, void *arg)
+{
+	if (req->response_code != HTTP_OK) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers, "Date") == NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	
+	if (evhttp_find_header(req->input_headers, "Content-Length") == NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (strcmp(evhttp_find_header(req->input_headers, "Content-Length"),
+		"0")) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->input_buffer) != 0) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+/*
+ * HTTP DISPATCHER test
+ */
+
+void
+http_dispatcher_cb(struct evhttp_request *req, void *arg)
+{
+
+	struct evbuffer *evb = evbuffer_new();
+	event_debug(("%s: called\n", __func__));
+	evbuffer_add_printf(evb, "DISPATCHER_TEST");
+
+	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+	evbuffer_free(evb);
+}
+
+static void
+http_dispatcher_test_done(struct evhttp_request *req, void *arg)
+{
+	const char *what = "DISPATCHER_TEST";
+
+	if (req->response_code != HTTP_OK) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
+		fprintf(stderr, "FAILED (content type)\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
+		fprintf(stderr, "FAILED (length %zu vs %zu)\n",
+		    EVBUFFER_LENGTH(req->input_buffer), strlen(what));
+		exit(1);
+	}
+	
+	if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
+		fprintf(stderr, "FAILED (data)\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+static void
+http_dispatcher_test(void)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing HTTP Dispatcher: ");
+
+	http = http_setup(&port, NULL);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* also bind to local host */
+	evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+	/*
+	 * At this point, we want to schedule an HTTP GET request
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(http_dispatcher_test_done, NULL);
+	if (req == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+	
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED: %d\n", test_ok);
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+/*
+ * HTTP POST test.
+ */
+
+void http_postrequest_done(struct evhttp_request *, void *);
+
+#define POST_DATA "Okay.  Not really printf"
+
+static void
+http_post_test(void)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing HTTP POST Request: ");
+
+	http = http_setup(&port, NULL);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/*
+	 * At this point, we want to schedule an HTTP POST request
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(http_postrequest_done, NULL);
+	if (req == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+	evbuffer_add_printf(req->output_buffer, POST_DATA);
+	
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED: %d\n", test_ok);
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+void
+http_post_cb(struct evhttp_request *req, void *arg)
+{
+	struct evbuffer *evb;
+	event_debug(("%s: called\n", __func__));
+
+	/* Yes, we are expecting a post request */
+	if (req->type != EVHTTP_REQ_POST) {
+		fprintf(stdout, "FAILED (post type)\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(POST_DATA)) {
+		fprintf(stdout, "FAILED (length: %zu vs %zu)\n",
+		    EVBUFFER_LENGTH(req->input_buffer), strlen(POST_DATA));
+		exit(1);
+	}
+
+	if (memcmp(EVBUFFER_DATA(req->input_buffer), POST_DATA,
+		strlen(POST_DATA))) {
+		fprintf(stdout, "FAILED (data)\n");
+		fprintf(stdout, "Got :%s\n", EVBUFFER_DATA(req->input_buffer));
+		fprintf(stdout, "Want:%s\n", POST_DATA);
+		exit(1);
+	}
+	
+	evb = evbuffer_new();
+	evbuffer_add_printf(evb, "This is funny");
+
+	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+	evbuffer_free(evb);
+}
+
+void
+http_postrequest_done(struct evhttp_request *req, void *arg)
+{
+	const char *what = "This is funny";
+
+	if (req == NULL) {
+		fprintf(stderr, "FAILED (timeout)\n");
+		exit(1);
+	}
+
+	if (req->response_code != HTTP_OK) {
+	
+		fprintf(stderr, "FAILED (response code)\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
+		fprintf(stderr, "FAILED (content type)\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
+		fprintf(stderr, "FAILED (length %zu vs %zu)\n",
+		    EVBUFFER_LENGTH(req->input_buffer), strlen(what));
+		exit(1);
+	}
+	
+	if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
+		fprintf(stderr, "FAILED (data)\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+static void
+http_failure_readcb(struct bufferevent *bev, void *arg)
+{
+	const char *what = "400 Bad Request";
+	if (evbuffer_find(bev->input, (const unsigned char*) what, strlen(what)) != NULL) {
+		test_ok = 2;
+		bufferevent_disable(bev, EV_READ);
+		event_loopexit(NULL);
+	}
+}
+
+/*
+ * Testing that the HTTP server can deal with a malformed request.
+ */
+static void
+http_failure_test(void)
+{
+	struct bufferevent *bev;
+	int fd;
+	const char *http_request;
+	short port = -1;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing Bad HTTP Request: ");
+
+	http = http_setup(&port, NULL);
+	
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_failure_readcb, http_writecb,
+	    http_errorcb, NULL);
+
+	http_request = "illegal request\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+	
+	event_dispatch();
+
+	bufferevent_free(bev);
+	EVUTIL_CLOSESOCKET(fd);
+
+	evhttp_free(http);
+	
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+static void
+close_detect_done(struct evhttp_request *req, void *arg)
+{
+	struct timeval tv;
+	if (req == NULL || req->response_code != HTTP_OK) {
+	
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+
+	timerclear(&tv);
+	tv.tv_sec = 3;   /* longer than the http time out */
+
+	event_loopexit(&tv);
+}
+
+static void
+close_detect_launch(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	struct evhttp_request *req;
+
+	req = evhttp_request_new(close_detect_done, NULL);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+
+	/* We give ownership of the request to the connection */
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+}
+
+static void
+close_detect_cb(struct evhttp_request *req, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	struct timeval tv;
+
+	if (req != NULL && req->response_code != HTTP_OK) {
+	
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	timerclear(&tv);
+	tv.tv_sec = 3;   /* longer than the http time out */
+
+	/* launch a new request on the persistent connection in 6 seconds */
+	event_once(-1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
+}
+
+
+static void
+http_close_detection(int with_delay)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+	
+	test_ok = 0;
+	fprintf(stdout, "Testing Connection Close Detection%s: ",
+		with_delay ? " (with delay)" : "");
+
+	http = http_setup(&port, NULL);
+
+	/* 2 second timeout */
+	evhttp_set_timeout(http, 2);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	delayed_client = evcon;
+
+	/*
+	 * At this point, we want to schedule a request to the HTTP
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(close_detect_cb, evcon);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+
+	/* We give ownership of the request to the connection */
+	if (evhttp_make_request(evcon,
+	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* at this point, the http server should have no connection */
+	if (TAILQ_FIRST(&http->connections) != NULL) {
+		fprintf(stdout, "FAILED (left connections)\n");
+		exit(1);
+	}
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	fprintf(stdout, "OK\n");
+}
+
+static void
+http_highport_test(void)
+{
+	int i = -1;
+	struct evhttp *myhttp = NULL;
+ 
+	fprintf(stdout, "Testing HTTP Server with high port: ");
+
+	/* Try a few different ports */
+	for (i = 0; i < 50; ++i) {
+		myhttp = evhttp_start("127.0.0.1", 65535 - i);
+		if (myhttp != NULL) {
+			fprintf(stdout, "OK\n");
+			evhttp_free(myhttp);
+			return;
+		}
+	}
+
+	fprintf(stdout, "FAILED\n");
+	exit(1);
+}
+
+static void
+http_bad_header_test(void)
+{
+	struct evkeyvalq headers;
+
+	fprintf(stdout, "Testing HTTP Header filtering: ");
+
+	TAILQ_INIT(&headers);
+
+	if (evhttp_add_header(&headers, "One", "Two") != 0)
+		goto fail;
+	
+	if (evhttp_add_header(&headers, "One\r", "Two") != -1)
+		goto fail;
+	if (evhttp_add_header(&headers, "One", "Two") != 0)
+		goto fail;
+	if (evhttp_add_header(&headers, "One", "Two\r\n Three") != 0)
+		goto fail;
+	if (evhttp_add_header(&headers, "One\r", "Two") != -1)
+		goto fail;
+	if (evhttp_add_header(&headers, "One\n", "Two") != -1)
+		goto fail;
+	if (evhttp_add_header(&headers, "One", "Two\r") != -1)
+		goto fail;
+	if (evhttp_add_header(&headers, "One", "Two\n") != -1)
+		goto fail;
+
+	evhttp_clear_headers(&headers);
+
+	fprintf(stdout, "OK\n");
+	return;
+fail:
+	fprintf(stdout, "FAILED\n");
+	exit(1);
+}
+
+static int validate_header(
+	const struct evkeyvalq* headers,
+	const char *key, const char *value) 
+{
+	const char *real_val = evhttp_find_header(headers, key);
+	if (real_val == NULL)
+		return (-1);
+	if (strcmp(real_val, value) != 0)
+		return (-1);
+	return (0);
+}
+
+static void
+http_parse_query_test(void)
+{
+	struct evkeyvalq headers;
+
+	fprintf(stdout, "Testing HTTP query parsing: ");
+
+	TAILQ_INIT(&headers);
+	
+	evhttp_parse_query("http://www.test.com/?q=test", &headers);
+	if (validate_header(&headers, "q", "test") != 0)
+		goto fail;
+	evhttp_clear_headers(&headers);
+
+	evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
+	if (validate_header(&headers, "q", "test") != 0)
+		goto fail;
+	if (validate_header(&headers, "foo", "bar") != 0)
+		goto fail;
+	evhttp_clear_headers(&headers);
+
+	evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
+	if (validate_header(&headers, "q", "test foo") != 0)
+		goto fail;
+	evhttp_clear_headers(&headers);
+
+	evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
+	if (validate_header(&headers, "q", "test\nfoo") != 0)
+		goto fail;
+	evhttp_clear_headers(&headers);
+
+	evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
+	if (validate_header(&headers, "q", "test\rfoo") != 0)
+		goto fail;
+	evhttp_clear_headers(&headers);
+
+	fprintf(stdout, "OK\n");
+	return;
+fail:
+	fprintf(stdout, "FAILED\n");
+	exit(1);
+}
+
+static void
+http_base_test(void)
+{
+	struct bufferevent *bev;
+	int fd;
+	const char *http_request;
+	short port = -1;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing HTTP Server Event Base: ");
+
+	base = event_init();
+
+	/* 
+	 * create another bogus base - which is being used by all subsequen
+	 * tests - yuck!
+	 */
+	event_init();
+
+	http = http_setup(&port, base);
+	
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_readcb, http_writecb,
+	    http_errorcb, NULL);
+	bufferevent_base_set(base, bev);
+
+	http_request =
+	    "GET /test HTTP/1.1\r\n"
+	    "Host: somehost\r\n"
+	    "Connection: close\r\n"
+	    "\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+	
+	event_base_dispatch(base);
+
+	bufferevent_free(bev);
+	EVUTIL_CLOSESOCKET(fd);
+
+	evhttp_free(http);
+
+	event_base_free(base);
+	base = NULL;
+	
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+/*
+ * the server is going to reply with chunked data.
+ */
+
+static void
+http_chunked_readcb(struct bufferevent *bev, void *arg)
+{
+	/* nothing here */
+}
+
+static void
+http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+	if (!test_ok)
+		goto out;
+
+	test_ok = -1;
+
+	if ((what & EVBUFFER_EOF) != 0) {
+		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+		const char *header;
+		enum message_read_status done;
+		
+		req->kind = EVHTTP_RESPONSE;
+		done = evhttp_parse_firstline(req, EVBUFFER_INPUT(bev));
+		if (done != ALL_DATA_READ)
+			goto out;
+
+		done = evhttp_parse_headers(req, EVBUFFER_INPUT(bev));
+		if (done != ALL_DATA_READ)
+			goto out;
+
+		header = evhttp_find_header(req->input_headers, "Transfer-Encoding");
+		if (header == NULL || strcmp(header, "chunked"))
+			goto out;
+
+		header = evhttp_find_header(req->input_headers, "Connection");
+		if (header == NULL || strcmp(header, "close"))
+			goto out;
+
+		header = evbuffer_readline(EVBUFFER_INPUT(bev));
+		if (header == NULL)
+			goto out;
+		/* 13 chars */
+		if (strcmp(header, "d"))
+			goto out;
+		free((char*)header);
+
+		if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
+			"This is funny", 13))
+			goto out;
+
+		evbuffer_drain(EVBUFFER_INPUT(bev), 13 + 2);
+
+		header = evbuffer_readline(EVBUFFER_INPUT(bev));
+		if (header == NULL)
+			goto out;
+		/* 18 chars */
+		if (strcmp(header, "12"))
+			goto out;
+		free((char *)header);
+
+		if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
+			"but not hilarious.", 18))
+			goto out;
+
+		evbuffer_drain(EVBUFFER_INPUT(bev), 18 + 2);
+
+		header = evbuffer_readline(EVBUFFER_INPUT(bev));
+		if (header == NULL)
+			goto out;
+		/* 8 chars */
+		if (strcmp(header, "8"))
+			goto out;
+		free((char *)header);
+
+		if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
+			"bwv 1052.", 8))
+			goto out;
+
+		evbuffer_drain(EVBUFFER_INPUT(bev), 8 + 2);
+
+		header = evbuffer_readline(EVBUFFER_INPUT(bev));
+		if (header == NULL)
+			goto out;
+		/* 0 chars */
+		if (strcmp(header, "0"))
+			goto out;
+		free((char *)header);
+
+		test_ok = 2;
+	}
+
+out:
+	event_loopexit(NULL);
+}
+
+static void
+http_chunked_writecb(struct bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev)) == 0) {
+		/* enable reading of the reply */
+		bufferevent_enable(bev, EV_READ);
+		test_ok++;
+	}
+}
+
+static void
+http_chunked_request_done(struct evhttp_request *req, void *arg)
+{
+	if (req->response_code != HTTP_OK) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers,
+		"Transfer-Encoding") == NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->input_buffer) != 13 + 18 + 8) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (strncmp((char *)EVBUFFER_DATA(req->input_buffer),
+		"This is funnybut not hilarious.bwv 1052",
+		13 + 18 + 8)) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+	
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+static void
+http_chunked_test(void)
+{
+	struct bufferevent *bev;
+	int fd;
+	const char *http_request;
+	short port = -1;
+	struct timeval tv_start, tv_end;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+	int i;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing Chunked HTTP Reply: ");
+
+	http = http_setup(&port, NULL);
+
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, 
+	    http_chunked_readcb, http_chunked_writecb,
+	    http_chunked_errorcb, NULL);
+
+	http_request =
+	    "GET /chunked HTTP/1.1\r\n"
+	    "Host: somehost\r\n"
+	    "Connection: close\r\n"
+	    "\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+
+	evutil_gettimeofday(&tv_start, NULL);
+	
+	event_dispatch();
+
+	evutil_gettimeofday(&tv_end, NULL);
+	evutil_timersub(&tv_end, &tv_start, &tv_end);
+
+	if (tv_end.tv_sec >= 1) {
+		fprintf(stdout, "FAILED (time)\n");
+		exit (1);
+	}
+
+
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* now try again with the regular connection object */
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* make two requests to check the keepalive behavior */
+	for (i = 0; i < 2; i++) {
+		test_ok = 0;
+		req = evhttp_request_new(http_chunked_request_done, NULL);
+
+		/* Add the information that we care about */
+		evhttp_add_header(req->output_headers, "Host", "somehost");
+
+		/* We give ownership of the request to the connection */
+		if (evhttp_make_request(evcon, req,
+			EVHTTP_REQ_GET, "/chunked") == -1) {
+			fprintf(stdout, "FAILED\n");
+			exit(1);
+		}
+
+		event_dispatch();
+
+		if (test_ok != 1) {
+			fprintf(stdout, "FAILED\n");
+			exit(1);
+		}
+	}
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	fprintf(stdout, "OK\n");
+}
+
+static void
+http_multi_line_header_test(void)
+{
+	struct bufferevent *bev;
+	int fd;
+	const char *http_start_request;
+	short port = -1;
+	
+	test_ok = 0;
+	fprintf(stdout, "Testing HTTP Server with multi line: ");
+
+	http = http_setup(&port, NULL);
+	
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_readcb, http_writecb,
+	    http_errorcb, NULL);
+
+	http_start_request =
+	    "GET /test HTTP/1.1\r\n"
+	    "Host: somehost\r\n"
+	    "Connection: close\r\n"
+	    "X-Multi:  aaaaaaaa\r\n"
+	    " a\r\n"
+	    "\tEND\r\n"
+	    "X-Last: last\r\n"
+	    "\r\n";
+		
+	bufferevent_write(bev, http_start_request, strlen(http_start_request));
+
+	event_dispatch();
+	
+	bufferevent_free(bev);
+	EVUTIL_CLOSESOCKET(fd);
+
+	evhttp_free(http);
+
+	if (test_ok != 4) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+static void
+http_request_bad(struct evhttp_request *req, void *arg)
+{
+	if (req != NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+static void
+http_negative_content_length_test(void)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+	
+	test_ok = 0;
+	fprintf(stdout, "Testing HTTP Negative Content Length: ");
+
+	http = http_setup(&port, NULL);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/*
+	 * At this point, we want to schedule a request to the HTTP
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(http_request_bad, NULL);
+
+	/* Cause the response to have a negative content-length */
+	evhttp_add_header(req->output_headers, "X-Negative", "makeitso");
+
+	/* We give ownership of the request to the connection */
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	evhttp_free(http);
+
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+}
+
+void
+http_suite(void)
+{
+	http_base_test();
+	http_bad_header_test();
+	http_parse_query_test();
+	http_basic_test();
+	http_connection_test(0 /* not-persistent */);
+	http_connection_test(1 /* persistent */);
+	http_close_detection(0 /* with delay */);
+	http_close_detection(1 /* with delay */);
+	http_post_test();
+	http_failure_test();
+	http_highport_test();
+	http_dispatcher_test();
+
+	http_multi_line_header_test();
+	http_negative_content_length_test();
+
+	http_chunked_test();
+}
diff --git a/third_party/libevent/test/regress_rpc.c b/third_party/libevent/test/regress_rpc.c
new file mode 100644
index 0000000..7609347
--- /dev/null
+++ b/third_party/libevent/test/regress_rpc.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event.h"
+#include "evhttp.h"
+#include "log.h"
+#include "evrpc.h"
+
+#include "regress.gen.h"
+
+void rpc_suite(void);
+
+extern int test_ok;
+
+static struct evhttp *
+http_setup(short *pport)
+{
+	int i;
+	struct evhttp *myhttp;
+	short port = -1;
+
+	/* Try a few different ports */
+	for (i = 0; i < 50; ++i) {
+		myhttp = evhttp_start("127.0.0.1", 8080 + i);
+		if (myhttp != NULL) {
+			port = 8080 + i;
+			break;
+		}
+	}
+
+	if (port == -1)
+		event_errx(1, "Could not start web server");
+
+	*pport = port;
+	return (myhttp);
+}
+
+EVRPC_HEADER(Message, msg, kill);
+EVRPC_HEADER(NeverReply, msg, kill);
+
+EVRPC_GENERATE(Message, msg, kill);
+EVRPC_GENERATE(NeverReply, msg, kill);
+
+static int need_input_hook = 0;
+static int need_output_hook = 0;
+
+static void
+MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
+{
+	struct kill* kill_reply = rpc->reply;
+
+	if (need_input_hook) {
+		struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
+		const char *header = evhttp_find_header(
+			req->input_headers, "X-Hook");
+		assert(strcmp(header, "input") == 0);
+	}
+
+	/* we just want to fill in some non-sense */
+	EVTAG_ASSIGN(kill_reply, weapon, "dagger");
+	EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
+
+	/* no reply to the RPC */
+	EVRPC_REQUEST_DONE(rpc);
+}
+
+static EVRPC_STRUCT(NeverReply) *saved_rpc;
+
+static void
+NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
+{
+	test_ok += 1;
+	saved_rpc = rpc;
+}
+
+static void
+rpc_setup(struct evhttp **phttp, short *pport, struct evrpc_base **pbase)
+{
+	short port;
+	struct evhttp *http = NULL;
+	struct evrpc_base *base = NULL;
+
+	http = http_setup(&port);
+	base = evrpc_init(http);
+	
+	EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
+	EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
+
+	*phttp = http;
+	*pport = port;
+	*pbase = base;
+
+	need_input_hook = 0;
+	need_output_hook = 0;
+}
+
+static void
+rpc_teardown(struct evrpc_base *base)
+{
+	assert(EVRPC_UNREGISTER(base, Message) == 0);
+	assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
+
+	evrpc_free(base);
+}
+
+static void
+rpc_postrequest_failure(struct evhttp_request *req, void *arg)
+{
+	if (req->response_code != HTTP_SERVUNAVAIL) {
+	
+		fprintf(stderr, "FAILED (response code)\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+/*
+ * Test a malformed payload submitted as an RPC
+ */
+
+static void
+rpc_basic_test(void)
+{
+	short port;
+	struct evhttp *http = NULL;
+	struct evrpc_base *base = NULL;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+
+	fprintf(stdout, "Testing Basic RPC Support: ");
+
+	rpc_setup(&http, &port, &base);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/*
+	 * At this point, we want to schedule an HTTP POST request
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(rpc_postrequest_failure, NULL);
+	if (req == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+	evbuffer_add_printf(req->output_buffer, "Some Nonsense");
+	
+	if (evhttp_make_request(evcon, req,
+		EVHTTP_REQ_POST,
+		"/.rpc.Message") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 0;
+
+	event_dispatch();
+
+	evhttp_connection_free(evcon);
+
+	rpc_teardown(base);
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	evhttp_free(http);
+}
+
+static void
+rpc_postrequest_done(struct evhttp_request *req, void *arg)
+{
+	struct kill* kill_reply = NULL;
+
+	if (req->response_code != HTTP_OK) {
+	
+		fprintf(stderr, "FAILED (response code)\n");
+		exit(1);
+	}
+
+	kill_reply = kill_new();
+
+	if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
+		fprintf(stderr, "FAILED (unmarshal)\n");
+		exit(1);
+	}
+	
+	kill_free(kill_reply);
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+static void
+rpc_basic_message(void)
+{
+	short port;
+	struct evhttp *http = NULL;
+	struct evrpc_base *base = NULL;
+	struct evhttp_connection *evcon = NULL;
+	struct evhttp_request *req = NULL;
+	struct msg *msg;
+
+	fprintf(stdout, "Testing Good RPC Post: ");
+
+	rpc_setup(&http, &port, &base);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/*
+	 * At this point, we want to schedule an HTTP POST request
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(rpc_postrequest_done, NULL);
+	if (req == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+
+	/* set up the basic message */
+	msg = msg_new();
+	EVTAG_ASSIGN(msg, from_name, "niels");
+	EVTAG_ASSIGN(msg, to_name, "tester");
+	msg_marshal(req->output_buffer, msg);
+	msg_free(msg);
+
+	if (evhttp_make_request(evcon, req,
+		EVHTTP_REQ_POST,
+		"/.rpc.Message") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 0;
+
+	event_dispatch();
+
+	evhttp_connection_free(evcon);
+	
+	rpc_teardown(base);
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	evhttp_free(http);
+}
+
+static struct evrpc_pool *
+rpc_pool_with_connection(short port)
+{
+	struct evhttp_connection *evcon;
+	struct evrpc_pool *pool;
+
+	pool = evrpc_pool_new(NULL);
+	assert(pool != NULL);
+
+	evcon = evhttp_connection_new("127.0.0.1", port);
+	assert(evcon != NULL);
+
+	evrpc_pool_add_connection(pool, evcon);
+	
+	return (pool);
+}
+
+static void
+GotKillCb(struct evrpc_status *status,
+    struct msg *msg, struct kill *kill, void *arg)
+{
+	char *weapon;
+	char *action;
+
+	if (need_output_hook) {
+		struct evhttp_request *req = status->http_req;
+		const char *header = evhttp_find_header(
+			req->input_headers, "X-Pool-Hook");
+		assert(strcmp(header, "ran") == 0);
+	}
+
+	if (status->error != EVRPC_STATUS_ERR_NONE)
+		goto done;
+
+	if (EVTAG_GET(kill, weapon, &weapon) == -1) {
+		fprintf(stderr, "get weapon\n");
+		goto done;
+	}
+	if (EVTAG_GET(kill, action, &action) == -1) {
+		fprintf(stderr, "get action\n");
+		goto done;
+	}
+
+	if (strcmp(weapon, "dagger"))
+		goto done;
+
+	if (strcmp(action, "wave around like an idiot"))
+		goto done;
+
+	test_ok += 1;
+
+done:
+	event_loopexit(NULL);
+}
+
+static void
+GotKillCbTwo(struct evrpc_status *status,
+    struct msg *msg, struct kill *kill, void *arg)
+{
+	char *weapon;
+	char *action;
+
+	if (status->error != EVRPC_STATUS_ERR_NONE)
+		goto done;
+
+	if (EVTAG_GET(kill, weapon, &weapon) == -1) {
+		fprintf(stderr, "get weapon\n");
+		goto done;
+	}
+	if (EVTAG_GET(kill, action, &action) == -1) {
+		fprintf(stderr, "get action\n");
+		goto done;
+	}
+
+	if (strcmp(weapon, "dagger"))
+		goto done;
+
+	if (strcmp(action, "wave around like an idiot"))
+		goto done;
+
+	test_ok += 1;
+
+done:
+	if (test_ok == 2)
+		event_loopexit(NULL);
+}
+
+static int
+rpc_hook_add_header(struct evhttp_request *req,
+    struct evbuffer *evbuf, void *arg)
+{
+	const char *hook_type = arg;
+	if (strcmp("input", hook_type) == 0)
+		evhttp_add_header(req->input_headers, "X-Hook", hook_type);
+	else 
+		evhttp_add_header(req->output_headers, "X-Hook", hook_type);
+	return (0);
+}
+
+static int
+rpc_hook_remove_header(struct evhttp_request *req,
+    struct evbuffer *evbuf, void *arg)
+{
+	const char *header = evhttp_find_header(req->input_headers, "X-Hook");
+	assert(header != NULL);
+	assert(strcmp(header, arg) == 0);
+	evhttp_remove_header(req->input_headers, "X-Hook");
+	evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
+
+	return (0);
+}
+
+static void
+rpc_basic_client(void)
+{
+	short port;
+	struct evhttp *http = NULL;
+	struct evrpc_base *base = NULL;
+	struct evrpc_pool *pool = NULL;
+	struct msg *msg;
+	struct kill *kill;
+
+	fprintf(stdout, "Testing RPC Client: ");
+
+	rpc_setup(&http, &port, &base);
+
+	need_input_hook = 1;
+	need_output_hook = 1;
+
+	assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
+	    != NULL);
+	assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
+	    != NULL);
+
+	pool = rpc_pool_with_connection(port);
+
+	assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
+
+	/* set up the basic message */
+	msg = msg_new();
+	EVTAG_ASSIGN(msg, from_name, "niels");
+	EVTAG_ASSIGN(msg, to_name, "tester");
+
+	kill = kill_new();
+
+	EVRPC_MAKE_REQUEST(Message, pool, msg, kill,  GotKillCb, NULL);
+
+	test_ok = 0;
+
+	event_dispatch();
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED (1)\n");
+		exit(1);
+	}
+
+	/* we do it twice to make sure that reuse works correctly */
+	kill_clear(kill);
+
+	EVRPC_MAKE_REQUEST(Message, pool, msg, kill,  GotKillCb, NULL);
+
+	event_dispatch();
+	
+	rpc_teardown(base);
+	
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED (2)\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	msg_free(msg);
+	kill_free(kill);
+
+	evrpc_pool_free(pool);
+	evhttp_free(http);
+}
+
+/* 
+ * We are testing that the second requests gets send over the same
+ * connection after the first RPCs completes.
+ */
+static void
+rpc_basic_queued_client(void)
+{
+	short port;
+	struct evhttp *http = NULL;
+	struct evrpc_base *base = NULL;
+	struct evrpc_pool *pool = NULL;
+	struct msg *msg;
+	struct kill *kill_one, *kill_two;
+
+	fprintf(stdout, "Testing RPC (Queued) Client: ");
+
+	rpc_setup(&http, &port, &base);
+
+	pool = rpc_pool_with_connection(port);
+
+	/* set up the basic message */
+	msg = msg_new();
+	EVTAG_ASSIGN(msg, from_name, "niels");
+	EVTAG_ASSIGN(msg, to_name, "tester");
+
+	kill_one = kill_new();
+	kill_two = kill_new();
+
+	EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one,  GotKillCbTwo, NULL);
+	EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two,  GotKillCb, NULL);
+
+	test_ok = 0;
+
+	event_dispatch();
+	
+	rpc_teardown(base);
+	
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED (1)\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	msg_free(msg);
+	kill_free(kill_one);
+	kill_free(kill_two);
+
+	evrpc_pool_free(pool);
+	evhttp_free(http);
+}
+
+static void
+GotErrorCb(struct evrpc_status *status,
+    struct msg *msg, struct kill *kill, void *arg)
+{
+	if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
+		goto done;
+
+	/* should never be complete but just to check */
+	if (kill_complete(kill) == 0)
+		goto done;
+
+	test_ok += 1;
+
+done:
+	event_loopexit(NULL);
+}
+
+static void
+rpc_client_timeout(void)
+{
+	short port;
+	struct evhttp *http = NULL;
+	struct evrpc_base *base = NULL;
+	struct evrpc_pool *pool = NULL;
+	struct msg *msg;
+	struct kill *kill;
+
+	fprintf(stdout, "Testing RPC Client Timeout: ");
+
+	rpc_setup(&http, &port, &base);
+
+	pool = rpc_pool_with_connection(port);
+
+	/* set the timeout to 5 seconds */
+	evrpc_pool_set_timeout(pool, 5);
+
+	/* set up the basic message */
+	msg = msg_new();
+	EVTAG_ASSIGN(msg, from_name, "niels");
+	EVTAG_ASSIGN(msg, to_name, "tester");
+
+	kill = kill_new();
+
+	EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
+
+	test_ok = 0;
+
+	event_dispatch();
+	
+	/* free the saved RPC structure up */
+	EVRPC_REQUEST_DONE(saved_rpc);
+
+	rpc_teardown(base);
+	
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED (1)\n");
+		exit(1);
+	}
+
+	fprintf(stdout, "OK\n");
+
+	msg_free(msg);
+	kill_free(kill);
+
+	evrpc_pool_free(pool);
+	evhttp_free(http);
+}
+
+void
+rpc_suite(void)
+{
+	rpc_basic_test();
+	rpc_basic_message();
+	rpc_basic_client();
+	rpc_basic_queued_client();
+	rpc_client_timeout();
+}
diff --git a/third_party/libevent/test/test-eof.c b/third_party/libevent/test/test-eof.c
new file mode 100644
index 0000000..3264a7b
--- /dev/null
+++ b/third_party/libevent/test/test-eof.c
@@ -0,0 +1,86 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+int test_okay = 1;
+int called = 0;
+
+static void
+read_cb(int fd, short event, void *arg)
+{
+	char buf[256];
+	int len;
+
+	len = recv(fd, buf, sizeof(buf), 0);
+
+	printf("%s: read %d%s\n", __func__,
+	    len, len ? "" : " - means EOF");
+
+	if (len) {
+		if (!called)
+			event_add(arg, NULL);
+	} else if (called == 1)
+		test_okay = 0;
+
+	called++;
+}
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+int
+main (int argc, char **argv)
+{
+	struct event ev;
+	const char *test = "test string";
+	int pair[2];
+
+	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+		return (1);
+
+	
+	send(pair[0], test, strlen(test)+1, 0);
+	shutdown(pair[0], SHUT_WR);
+
+	/* Initalize the event library */
+	event_init();
+
+	/* Initalize one event */
+	event_set(&ev, pair[1], EV_READ, read_cb, &ev);
+
+	event_add(&ev, NULL);
+
+	event_dispatch();
+
+	return (test_okay);
+}
+
diff --git a/third_party/libevent/test/test-init.c b/third_party/libevent/test/test-init.c
new file mode 100644
index 0000000..d60aa36
--- /dev/null
+++ b/third_party/libevent/test/test-init.c
@@ -0,0 +1,40 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+
+int
+main(int argc, char **argv)
+{
+	/* Initalize the event library */
+	event_init();
+
+	return (0);
+}
+
diff --git a/third_party/libevent/test/test-time.c b/third_party/libevent/test/test-time.c
new file mode 100644
index 0000000..703bc32
--- /dev/null
+++ b/third_party/libevent/test/test-time.c
@@ -0,0 +1,89 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+
+int called = 0;
+
+#define NEVENT	20000
+
+struct event *ev[NEVENT];
+
+static int
+rand_int(int n)
+{
+#ifdef WIN32
+	return (int)(rand() * n);
+#else
+	return (int)(random() % n);
+#endif
+}
+
+static void
+time_cb(int fd, short event, void *arg)
+{
+	struct timeval tv;
+	int i, j;
+
+	called++;
+
+	if (called < 10*NEVENT) {
+		for (i = 0; i < 10; i++) {
+			j = rand_int(NEVENT);
+			tv.tv_sec = 0;
+			tv.tv_usec = rand_int(50000);
+			if (tv.tv_usec % 2)
+				evtimer_add(ev[j], &tv);
+			else
+				evtimer_del(ev[j]);
+		}
+	}
+}
+
+int
+main (int argc, char **argv)
+{
+	struct timeval tv;
+	int i;
+
+	/* Initalize the event library */
+	event_init();
+
+	for (i = 0; i < NEVENT; i++) {
+		ev[i] = malloc(sizeof(struct event));
+
+		/* Initalize one event */
+		evtimer_set(ev[i], time_cb, ev[i]);
+		tv.tv_sec = 0;
+		tv.tv_usec = rand_int(50000);
+		evtimer_add(ev[i], &tv);
+	}
+
+	event_dispatch();
+
+	return (called < NEVENT);
+}
+
diff --git a/third_party/libevent/test/test-weof.c b/third_party/libevent/test/test-weof.c
new file mode 100644
index 0000000..7fd6c8b
--- /dev/null
+++ b/third_party/libevent/test/test-weof.c
@@ -0,0 +1,84 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+int pair[2];
+int test_okay = 1;
+int called = 0;
+
+static void
+write_cb(int fd, short event, void *arg)
+{
+	const char *test = "test string";
+	int len;
+
+	len = send(fd, test, strlen(test) + 1, 0);
+
+	printf("%s: write %d%s\n", __func__,
+	    len, len ? "" : " - means EOF");
+
+	if (len > 0) {
+		if (!called)
+			event_add(arg, NULL);
+		EVUTIL_CLOSESOCKET(pair[0]);
+	} else if (called == 1)
+		test_okay = 0;
+
+	called++;
+}
+
+int
+main (int argc, char **argv)
+{
+	struct event ev;
+
+#ifndef WIN32
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+		return (1);
+#endif
+
+	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+		return (1);
+
+	/* Initalize the event library */
+	event_init();
+
+	/* Initalize one event */
+	event_set(&ev, pair[1], EV_WRITE, write_cb, &ev);
+
+	event_add(&ev, NULL);
+
+	event_dispatch();
+
+	return (test_okay);
+}
+
diff --git a/third_party/libevent/test/test.sh b/third_party/libevent/test/test.sh
new file mode 100644
index 0000000..506a198
--- /dev/null
+++ b/third_party/libevent/test/test.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+setup () {
+	 EVENT_NOKQUEUE=yes; export EVENT_NOKQUEUE
+	 EVENT_NODEVPOLL=yes; export EVENT_NODEVPOLL
+	 EVENT_NOPOLL=yes; export EVENT_NOPOLL
+	 EVENT_NOSELECT=yes; export EVENT_NOSELECT
+	 EVENT_NOEPOLL=yes; export EVENT_NOEPOLL
+	 EVENT_NOEVPORT=yes; export EVENT_NOEVPORT
+}
+
+test () {
+	if ./test-init 2>/dev/null ;
+	then
+	        true
+	else
+		echo Skipping test
+		return
+	fi	
+
+echo -n " test-eof: "
+if ./test-eof >/dev/null ; 
+then 
+	echo OKAY ; 
+else 
+	echo FAILED ; 
+fi
+echo -n " test-weof: "
+if ./test-weof >/dev/null ; 
+then 
+	echo OKAY ; 
+else 
+	echo FAILED ; 
+fi
+echo -n " test-time: "
+if ./test-time >/dev/null ; 
+then 
+	echo OKAY ; 
+else 
+	echo FAILED ; 
+fi
+echo -n " regress: "
+if ./regress >/dev/null ; 
+then 
+	echo OKAY ; 
+else 
+	echo FAILED ; 
+fi
+}
+
+echo "Running tests:"
+
+# Need to do this by hand?
+setup
+unset EVENT_NOKQUEUE
+export EVENT_NOKQUEUE
+echo "KQUEUE"
+test
+
+setup
+unset EVENT_NODEVPOLL
+export EVENT_NODEVPOLL
+echo "DEVPOLL"
+test
+
+setup
+unset EVENT_NOPOLL
+export EVENT_NOPOLL
+echo "POLL"
+test
+
+setup
+unset EVENT_NOSELECT
+export EVENT_NOSELECT
+echo "SELECT"
+test
+
+setup
+unset EVENT_NOEPOLL
+export EVENT_NOEPOLL
+echo "EPOLL"
+test
+
+setup
+unset EVENT_NOEVPORT
+export EVENT_NOEVPORT
+echo "EVPORT"
+test
+
+
+
diff --git a/third_party/lss b/third_party/lss
new file mode 160000
index 0000000..6f97298
--- /dev/null
+++ b/third_party/lss
@@ -0,0 +1 @@
+Subproject commit 6f97298fe3794e92c8c896a6bc06e0b36e4c3de3
diff --git a/third_party/modp_b64/BUILD.gn b/third_party/modp_b64/BUILD.gn
new file mode 100644
index 0000000..2ec992b
--- /dev/null
+++ b/third_party/modp_b64/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("modp_b64") {
+  sources = [
+    "modp_b64.cc",
+    "modp_b64.h",
+    "modp_b64_data.h",
+  ]
+}
diff --git a/third_party/modp_b64/DEPS b/third_party/modp_b64/DEPS
new file mode 100644
index 0000000..8061b5a
--- /dev/null
+++ b/third_party/modp_b64/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  '+build',
+]
\ No newline at end of file
diff --git a/third_party/modp_b64/LICENSE b/third_party/modp_b64/LICENSE
new file mode 100644
index 0000000..55af76f
--- /dev/null
+++ b/third_party/modp_b64/LICENSE
@@ -0,0 +1,33 @@
+ * MODP_B64 - High performance base64 encoder/decoder
+ * Version 1.3 -- 17-Mar-2006
+ * http://modp.com/release/base64
+ *
+ * Copyright (c) 2005, 2006  Nick Galbreath -- nickg [at] modp [dot] com
+ * 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 the modp.com 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/third_party/modp_b64/OWNERS b/third_party/modp_b64/OWNERS
new file mode 100644
index 0000000..0144bac
--- /dev/null
+++ b/third_party/modp_b64/OWNERS
@@ -0,0 +1,2 @@
+jschuh@chromium.org
+rsleevi@chromium.org
diff --git a/third_party/modp_b64/README.chromium b/third_party/modp_b64/README.chromium
new file mode 100644
index 0000000..35b9e54
--- /dev/null
+++ b/third_party/modp_b64/README.chromium
@@ -0,0 +1,15 @@
+Name: modp base64 decoder
+Short Name: stringencoders
+URL: http://code.google.com/p/stringencoders/
+Version: unknown
+License: BSD
+Security Critical: yes
+
+Description:
+The modp_b64.c file was modified to remove the inclusion of modp's config.h
+and to fix compilation errors that occur under VC8.  The file was renamed
+modp_b64.cc to force it to be compiled as C++ so that the inclusion of
+basictypes.h could be possible.
+
+The modp_b64.cc and modp_b64.h files were modified to make them safe on
+64-bit systems.
diff --git a/third_party/modp_b64/modp_b64.cc b/third_party/modp_b64/modp_b64.cc
new file mode 100644
index 0000000..e5f6cf1
--- /dev/null
+++ b/third_party/modp_b64/modp_b64.cc
@@ -0,0 +1,265 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4: */
+/**
+ * \file
+ * <PRE>
+ * MODP_B64 - High performance base64 encoder/decoder
+ * Version 1.3 -- 17-Mar-2006
+ * http://modp.com/release/base64
+ *
+ * Copyright &copy; 2005, 2006  Nick Galbreath -- nickg [at] modp [dot] com
+ * 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 the modp.com nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This is the standard "new" BSD license:
+ * http://www.opensource.org/licenses/bsd-license.php
+ * </PRE>
+ */
+
+/* public header */
+#include "modp_b64.h"
+
+/*
+ * If you are ripping this out of the library, comment out the next
+ * line and uncomment the next lines as approrpiate
+ */
+//#include "config.h"
+
+/* if on motoral, sun, ibm; uncomment this */
+/* #define WORDS_BIGENDIAN 1 */
+/* else for Intel, Amd; uncomment this */
+/* #undef WORDS_BIGENDIAN */
+
+#include "modp_b64_data.h"
+
+#define BADCHAR 0x01FFFFFF
+
+/**
+ * you can control if we use padding by commenting out this
+ * next line.  However, I highly recommend you use padding and not
+ * using it should only be for compatability with a 3rd party.
+ * Also, 'no padding' is not tested!
+ */
+#define DOPAD 1
+
+/*
+ * if we aren't doing padding
+ * set the pad character to NULL
+ */
+#ifndef DOPAD
+#undef CHARPAD
+#define CHARPAD '\0'
+#endif
+
+size_t modp_b64_encode(char* dest, const char* str, size_t len)
+{
+    size_t i = 0;
+    uint8_t* p = (uint8_t*) dest;
+
+    /* unsigned here is important! */
+    uint8_t t1, t2, t3;
+
+    if (len > 2) {
+        for (; i < len - 2; i += 3) {
+            t1 = str[i]; t2 = str[i+1]; t3 = str[i+2];
+            *p++ = e0[t1];
+            *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
+            *p++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)];
+            *p++ = e2[t3];
+        }
+    }
+
+    switch (len - i) {
+    case 0:
+        break;
+    case 1:
+        t1 = str[i];
+        *p++ = e0[t1];
+        *p++ = e1[(t1 & 0x03) << 4];
+        *p++ = CHARPAD;
+        *p++ = CHARPAD;
+        break;
+    default: /* case 2 */
+        t1 = str[i]; t2 = str[i+1];
+        *p++ = e0[t1];
+        *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
+        *p++ = e2[(t2 & 0x0F) << 2];
+        *p++ = CHARPAD;
+    }
+
+    *p = '\0';
+    return p - (uint8_t*)dest;
+}
+
+#ifdef WORDS_BIGENDIAN   /* BIG ENDIAN -- SUN / IBM / MOTOROLA */
+int modp_b64_decode(char* dest, const char* src, int len)
+{
+    if (len == 0) return 0;
+
+#ifdef DOPAD
+    /* if padding is used, then the message must be at least
+       4 chars and be a multiple of 4.
+       there can be at most 2 pad chars at the end */
+    if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR;
+    if (src[len-1] == CHARPAD) {
+        len--;
+        if (src[len -1] == CHARPAD) {
+            len--;
+        }
+    }
+#endif  /* DOPAD */
+
+    size_t i;
+    int leftover = len % 4;
+    size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
+
+    uint8_t* p = (uint8_t*) dest;
+    uint32_t x = 0;
+    uint32_t* destInt = (uint32_t*) p;
+    uint32_t* srcInt = (uint32_t*) src;
+    uint32_t y = *srcInt++;
+    for (i = 0; i < chunks; ++i) {
+        x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
+            d2[y >> 8 & 0xff] | d3[y & 0xff];
+
+        if (x >= BADCHAR)  return MODP_B64_ERROR;
+        *destInt = x << 8;
+        p += 3;
+        destInt = (uint32_t*)p;
+        y = *srcInt++;
+    }
+
+    switch (leftover) {
+    case 0:
+        x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
+            d2[y >>  8 & 0xff] | d3[y & 0xff];
+        if (x >= BADCHAR)  return MODP_B64_ERROR;
+        *p++ = ((uint8_t*)&x)[1];
+        *p++ = ((uint8_t*)&x)[2];
+        *p = ((uint8_t*)&x)[3];
+        return (chunks+1)*3;
+    case 1:
+        x = d3[y >> 24];
+        *p =  (uint8_t)x;
+        break;
+    case 2:
+        x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff];
+        *p =  (uint8_t)(x >> 4);
+        break;
+    default:  /* case 3 */
+        x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 +
+            d3[(y >> 8) & 0xff];
+        *p++ = (uint8_t) (x >> 10);
+        *p = (uint8_t) (x >> 2);
+        break;
+    }
+
+    if (x >= BADCHAR) return MODP_B64_ERROR;
+    return 3*chunks + (6*leftover)/8;
+}
+
+#else /* LITTLE  ENDIAN -- INTEL AND FRIENDS */
+
+size_t modp_b64_decode(char* dest, const char* src, size_t len)
+{
+    if (len == 0) return 0;
+
+#ifdef DOPAD
+    /*
+     * if padding is used, then the message must be at least
+     * 4 chars and be a multiple of 4
+     */
+    if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR; /* error */
+    /* there can be at most 2 pad chars at the end */
+    if (src[len-1] == CHARPAD) {
+        len--;
+        if (src[len -1] == CHARPAD) {
+            len--;
+        }
+    }
+#endif
+
+    size_t i;
+    int leftover = len % 4;
+    size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
+
+    uint8_t* p = (uint8_t*)dest;
+    uint32_t x = 0;
+    uint32_t* destInt = (uint32_t*) p;
+    uint32_t* srcInt = (uint32_t*) src;
+    uint32_t y = *srcInt++;
+    for (i = 0; i < chunks; ++i) {
+        x = d0[y & 0xff] |
+            d1[(y >> 8) & 0xff] |
+            d2[(y >> 16) & 0xff] |
+            d3[(y >> 24) & 0xff];
+
+        if (x >= BADCHAR) return MODP_B64_ERROR;
+        *destInt = x ;
+        p += 3;
+        destInt = (uint32_t*)p;
+        y = *srcInt++;}
+
+
+    switch (leftover) {
+    case 0:
+        x = d0[y & 0xff] |
+            d1[(y >> 8) & 0xff] |
+            d2[(y >> 16) & 0xff] |
+            d3[(y >> 24) & 0xff];
+
+        if (x >= BADCHAR) return MODP_B64_ERROR;
+        *p++ =  ((uint8_t*)(&x))[0];
+        *p++ =  ((uint8_t*)(&x))[1];
+        *p =    ((uint8_t*)(&x))[2];
+        return (chunks+1)*3;
+        break;
+    case 1:  /* with padding this is an impossible case */
+        x = d0[y & 0xff];
+        *p = *((uint8_t*)(&x)); // i.e. first char/byte in int
+        break;
+    case 2: // * case 2, 1  output byte */
+        x = d0[y & 0xff] | d1[y >> 8 & 0xff];
+        *p = *((uint8_t*)(&x)); // i.e. first char
+        break;
+    default: /* case 3, 2 output bytes */
+        x = d0[y & 0xff] |
+            d1[y >> 8 & 0xff ] |
+            d2[y >> 16 & 0xff];  /* 0x3c */
+        *p++ =  ((uint8_t*)(&x))[0];
+        *p =  ((uint8_t*)(&x))[1];
+        break;
+    }
+
+    if (x >= BADCHAR) return MODP_B64_ERROR;
+
+    return 3*chunks + (6*leftover)/8;
+}
+
+#endif  /* if bigendian / else / endif */
diff --git a/third_party/modp_b64/modp_b64.gyp b/third_party/modp_b64/modp_b64.gyp
new file mode 100644
index 0000000..6176c5d
--- /dev/null
+++ b/third_party/modp_b64/modp_b64.gyp
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'modp_b64',
+      'type': 'static_library',
+      'toolsets': ['host', 'target'],
+      'sources': [
+        'modp_b64.cc',
+        'modp_b64.h',
+        'modp_b64_data.h',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS == "win" and target_arch=="ia32"', {
+      # Even if we are building the browser for Win32, we need a few modules
+      # to be built for Win64, and this is a prerequsite.
+      'targets': [
+        {
+          'target_name': 'modp_b64_win64',
+          'type': 'static_library',
+          # We can't use dynamic_annotations target for win64 build since it is
+          # a 32-bit library.
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'modp_b64.cc',
+            'modp_b64.h',
+            'modp_b64_data.h',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+  ],
+}
diff --git a/third_party/modp_b64/modp_b64.h b/third_party/modp_b64/modp_b64.h
new file mode 100644
index 0000000..3270e5f
--- /dev/null
+++ b/third_party/modp_b64/modp_b64.h
@@ -0,0 +1,171 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4: */
+
+/**
+ * \file
+ * <PRE>
+ * High performance base64 encoder / decoder
+ * Version 1.3 -- 17-Mar-2006
+ *
+ * Copyright &copy; 2005, 2006, Nick Galbreath -- nickg [at] modp [dot] com
+ * All rights reserved.
+ *
+ * http://modp.com/release/base64
+ *
+ * Released under bsd license.  See modp_b64.c for details.
+ * </pre>
+ *
+ * The default implementation is the standard b64 encoding with padding.
+ * It's easy to change this to use "URL safe" characters and to remove
+ * padding.  See the modp_b64.c source code for details.
+ *
+ */
+
+#ifndef MODP_B64
+#define MODP_B64
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Encode a raw binary string into base 64.
+ * src contains the bytes
+ * len contains the number of bytes in the src
+ * dest should be allocated by the caller to contain
+ *   at least modp_b64_encode_len(len) bytes (see below)
+ *   This will contain the null-terminated b64 encoded result
+ * returns length of the destination string plus the ending null byte
+ *    i.e.  the result will be equal to strlen(dest) + 1
+ *
+ * Example
+ * 
+ * \code
+ * char* src = ...;
+ * int srclen = ...; //the length of number of bytes in src
+ * char* dest = (char*) malloc(modp_b64_encode_len);
+ * int len = modp_b64_encode(dest, src, sourcelen);
+ * if (len == -1) {
+ *   printf("Error\n");
+ * } else {
+ *   printf("b64 = %s\n", dest);
+ * }
+ * \endcode
+ *
+ */
+size_t modp_b64_encode(char* dest, const char* str, size_t len);
+
+/**
+ * Decode a base64 encoded string
+ *
+ * src should contain exactly len bytes of b64 characters.
+ *     if src contains -any- non-base characters (such as white
+ *     space, -1 is returned.
+ *
+ * dest should be allocated by the caller to contain at least
+ *    len * 3 / 4 bytes.
+ *
+ * Returns the length (strlen) of the output, or -1 if unable to
+ * decode
+ *
+ * \code
+ * char* src = ...;
+ * int srclen = ...; // or if you don't know use strlen(src)
+ * char* dest = (char*) malloc(modp_b64_decode_len(srclen));
+ * int len = modp_b64_decode(dest, src, sourcelen);
+ * if (len == -1) { error }
+ * \endcode
+ */
+size_t modp_b64_decode(char* dest, const char* src, size_t len);
+
+/**
+ * Given a source string of length len, this returns the amount of
+ * memory the destination string should have.
+ *
+ * remember, this is integer math
+ * 3 bytes turn into 4 chars
+ * ceiling[len / 3] * 4 + 1
+ *
+ * +1 is for any extra null.
+ */
+#define modp_b64_encode_len(A) ((A+2)/3 * 4 + 1)
+
+/**
+ * Given a base64 string of length len,
+ *   this returns the amount of memory required for output string
+ *  It maybe be more than the actual number of bytes written.
+ * NOTE: remember this is integer math
+ * this allocates a bit more memory than traditional versions of b64
+ * decode  4 chars turn into 3 bytes
+ * floor[len * 3/4] + 2
+ */
+#define modp_b64_decode_len(A) (A / 4 * 3 + 2)
+
+/**
+ * Will return the strlen of the output from encoding.
+ * This may be less than the required number of bytes allocated.
+ *
+ * This allows you to 'deserialized' a struct
+ * \code
+ * char* b64encoded = "...";
+ * int len = strlen(b64encoded);
+ *
+ * struct datastuff foo;
+ * if (modp_b64_encode_strlen(sizeof(struct datastuff)) != len) {
+ *    // wrong size
+ *    return false;
+ * } else {
+ *    // safe to do;
+ *    if (modp_b64_decode((char*) &foo, b64encoded, len) == -1) {
+ *      // bad characters
+ *      return false;
+ *    }
+ * }
+ * // foo is filled out now
+ * \endcode
+ */
+#define modp_b64_encode_strlen(A) ((A + 2)/ 3 * 4)
+
+#define MODP_B64_ERROR ((size_t)-1)
+
+#ifdef __cplusplus
+}
+
+#include <string>
+
+inline std::string& modp_b64_encode(std::string& s)
+{
+    std::string x(modp_b64_encode_len(s.size()), '\0');
+    size_t d = modp_b64_encode(const_cast<char*>(x.data()), s.data(), (int)s.size());
+    x.erase(d, std::string::npos);
+    s.swap(x);
+    return s;
+}
+
+/**
+ * base 64 decode a string (self-modifing)
+ * On failure, the string is empty.
+ *
+ * This function is for C++ only (duh)
+ *
+ * \param[in,out] s the string to be decoded
+ * \return a reference to the input string
+ */
+inline std::string& modp_b64_decode(std::string& s)
+{
+    std::string x(modp_b64_decode_len(s.size()), '\0');
+    size_t d = modp_b64_decode(const_cast<char*>(x.data()), s.data(), (int)s.size());
+    if (d == MODP_B64_ERROR) {
+        x.clear();
+    } else {
+        x.erase(d, std::string::npos);
+    }
+    s.swap(x);
+    return s;
+}
+
+#endif /* __cplusplus */
+
+#endif /* MODP_B64 */
diff --git a/third_party/modp_b64/modp_b64_data.h b/third_party/modp_b64/modp_b64_data.h
new file mode 100644
index 0000000..fb85890
--- /dev/null
+++ b/third_party/modp_b64/modp_b64_data.h
@@ -0,0 +1,482 @@
+#include "build/build_config.h"
+#include <stdint.h>
+
+#define CHAR62 '+'
+#define CHAR63 '/'
+#define CHARPAD '='
+static const char e0[256] = {
+ 'A',  'A',  'A',  'A',  'B',  'B',  'B',  'B',  'C',  'C',
+ 'C',  'C',  'D',  'D',  'D',  'D',  'E',  'E',  'E',  'E',
+ 'F',  'F',  'F',  'F',  'G',  'G',  'G',  'G',  'H',  'H',
+ 'H',  'H',  'I',  'I',  'I',  'I',  'J',  'J',  'J',  'J',
+ 'K',  'K',  'K',  'K',  'L',  'L',  'L',  'L',  'M',  'M',
+ 'M',  'M',  'N',  'N',  'N',  'N',  'O',  'O',  'O',  'O',
+ 'P',  'P',  'P',  'P',  'Q',  'Q',  'Q',  'Q',  'R',  'R',
+ 'R',  'R',  'S',  'S',  'S',  'S',  'T',  'T',  'T',  'T',
+ 'U',  'U',  'U',  'U',  'V',  'V',  'V',  'V',  'W',  'W',
+ 'W',  'W',  'X',  'X',  'X',  'X',  'Y',  'Y',  'Y',  'Y',
+ 'Z',  'Z',  'Z',  'Z',  'a',  'a',  'a',  'a',  'b',  'b',
+ 'b',  'b',  'c',  'c',  'c',  'c',  'd',  'd',  'd',  'd',
+ 'e',  'e',  'e',  'e',  'f',  'f',  'f',  'f',  'g',  'g',
+ 'g',  'g',  'h',  'h',  'h',  'h',  'i',  'i',  'i',  'i',
+ 'j',  'j',  'j',  'j',  'k',  'k',  'k',  'k',  'l',  'l',
+ 'l',  'l',  'm',  'm',  'm',  'm',  'n',  'n',  'n',  'n',
+ 'o',  'o',  'o',  'o',  'p',  'p',  'p',  'p',  'q',  'q',
+ 'q',  'q',  'r',  'r',  'r',  'r',  's',  's',  's',  's',
+ 't',  't',  't',  't',  'u',  'u',  'u',  'u',  'v',  'v',
+ 'v',  'v',  'w',  'w',  'w',  'w',  'x',  'x',  'x',  'x',
+ 'y',  'y',  'y',  'y',  'z',  'z',  'z',  'z',  '0',  '0',
+ '0',  '0',  '1',  '1',  '1',  '1',  '2',  '2',  '2',  '2',
+ '3',  '3',  '3',  '3',  '4',  '4',  '4',  '4',  '5',  '5',
+ '5',  '5',  '6',  '6',  '6',  '6',  '7',  '7',  '7',  '7',
+ '8',  '8',  '8',  '8',  '9',  '9',  '9',  '9',  '+',  '+',
+ '+',  '+',  '/',  '/',  '/',  '/'
+};
+
+static const char e1[256] = {
+ 'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',
+ 'K',  'L',  'M',  'N',  'O',  'P',  'Q',  'R',  'S',  'T',
+ 'U',  'V',  'W',  'X',  'Y',  'Z',  'a',  'b',  'c',  'd',
+ 'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',
+ 'o',  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',
+ 'y',  'z',  '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
+ '8',  '9',  '+',  '/',  'A',  'B',  'C',  'D',  'E',  'F',
+ 'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  'P',
+ 'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',
+ 'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',
+ 'k',  'l',  'm',  'n',  'o',  'p',  'q',  'r',  's',  't',
+ 'u',  'v',  'w',  'x',  'y',  'z',  '0',  '1',  '2',  '3',
+ '4',  '5',  '6',  '7',  '8',  '9',  '+',  '/',  'A',  'B',
+ 'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',
+ 'M',  'N',  'O',  'P',  'Q',  'R',  'S',  'T',  'U',  'V',
+ 'W',  'X',  'Y',  'Z',  'a',  'b',  'c',  'd',  'e',  'f',
+ 'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',  'p',
+ 'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',
+ '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',
+ '+',  '/',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',
+ 'I',  'J',  'K',  'L',  'M',  'N',  'O',  'P',  'Q',  'R',
+ 'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  'a',  'b',
+ 'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',
+ 'm',  'n',  'o',  'p',  'q',  'r',  's',  't',  'u',  'v',
+ 'w',  'x',  'y',  'z',  '0',  '1',  '2',  '3',  '4',  '5',
+ '6',  '7',  '8',  '9',  '+',  '/'
+};
+
+static const char e2[256] = {
+ 'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',
+ 'K',  'L',  'M',  'N',  'O',  'P',  'Q',  'R',  'S',  'T',
+ 'U',  'V',  'W',  'X',  'Y',  'Z',  'a',  'b',  'c',  'd',
+ 'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',
+ 'o',  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',
+ 'y',  'z',  '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
+ '8',  '9',  '+',  '/',  'A',  'B',  'C',  'D',  'E',  'F',
+ 'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  'P',
+ 'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',
+ 'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',
+ 'k',  'l',  'm',  'n',  'o',  'p',  'q',  'r',  's',  't',
+ 'u',  'v',  'w',  'x',  'y',  'z',  '0',  '1',  '2',  '3',
+ '4',  '5',  '6',  '7',  '8',  '9',  '+',  '/',  'A',  'B',
+ 'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',
+ 'M',  'N',  'O',  'P',  'Q',  'R',  'S',  'T',  'U',  'V',
+ 'W',  'X',  'Y',  'Z',  'a',  'b',  'c',  'd',  'e',  'f',
+ 'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',  'p',
+ 'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',
+ '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',
+ '+',  '/',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',
+ 'I',  'J',  'K',  'L',  'M',  'N',  'O',  'P',  'Q',  'R',
+ 'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  'a',  'b',
+ 'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',
+ 'm',  'n',  'o',  'p',  'q',  'r',  's',  't',  'u',  'v',
+ 'w',  'x',  'y',  'z',  '0',  '1',  '2',  '3',  '4',  '5',
+ '6',  '7',  '8',  '9',  '+',  '/'
+};
+
+
+
+#ifdef WORDS_BIGENDIAN
+
+
+/* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */
+
+static const uint32_t d0[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00f80000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00fc0000,
+0x00d00000, 0x00d40000, 0x00d80000, 0x00dc0000, 0x00e00000, 0x00e40000,
+0x00e80000, 0x00ec0000, 0x00f00000, 0x00f40000, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00040000, 0x00080000, 0x000c0000, 0x00100000, 0x00140000, 0x00180000,
+0x001c0000, 0x00200000, 0x00240000, 0x00280000, 0x002c0000, 0x00300000,
+0x00340000, 0x00380000, 0x003c0000, 0x00400000, 0x00440000, 0x00480000,
+0x004c0000, 0x00500000, 0x00540000, 0x00580000, 0x005c0000, 0x00600000,
+0x00640000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00680000, 0x006c0000, 0x00700000, 0x00740000, 0x00780000,
+0x007c0000, 0x00800000, 0x00840000, 0x00880000, 0x008c0000, 0x00900000,
+0x00940000, 0x00980000, 0x009c0000, 0x00a00000, 0x00a40000, 0x00a80000,
+0x00ac0000, 0x00b00000, 0x00b40000, 0x00b80000, 0x00bc0000, 0x00c00000,
+0x00c40000, 0x00c80000, 0x00cc0000, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+static const uint32_t d1[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x0003e000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0003f000,
+0x00034000, 0x00035000, 0x00036000, 0x00037000, 0x00038000, 0x00039000,
+0x0003a000, 0x0003b000, 0x0003c000, 0x0003d000, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000,
+0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000,
+0x0000d000, 0x0000e000, 0x0000f000, 0x00010000, 0x00011000, 0x00012000,
+0x00013000, 0x00014000, 0x00015000, 0x00016000, 0x00017000, 0x00018000,
+0x00019000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x0001a000, 0x0001b000, 0x0001c000, 0x0001d000, 0x0001e000,
+0x0001f000, 0x00020000, 0x00021000, 0x00022000, 0x00023000, 0x00024000,
+0x00025000, 0x00026000, 0x00027000, 0x00028000, 0x00029000, 0x0002a000,
+0x0002b000, 0x0002c000, 0x0002d000, 0x0002e000, 0x0002f000, 0x00030000,
+0x00031000, 0x00032000, 0x00033000, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+static const uint32_t d2[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00000f80, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000fc0,
+0x00000d00, 0x00000d40, 0x00000d80, 0x00000dc0, 0x00000e00, 0x00000e40,
+0x00000e80, 0x00000ec0, 0x00000f00, 0x00000f40, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00000040, 0x00000080, 0x000000c0, 0x00000100, 0x00000140, 0x00000180,
+0x000001c0, 0x00000200, 0x00000240, 0x00000280, 0x000002c0, 0x00000300,
+0x00000340, 0x00000380, 0x000003c0, 0x00000400, 0x00000440, 0x00000480,
+0x000004c0, 0x00000500, 0x00000540, 0x00000580, 0x000005c0, 0x00000600,
+0x00000640, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00000680, 0x000006c0, 0x00000700, 0x00000740, 0x00000780,
+0x000007c0, 0x00000800, 0x00000840, 0x00000880, 0x000008c0, 0x00000900,
+0x00000940, 0x00000980, 0x000009c0, 0x00000a00, 0x00000a40, 0x00000a80,
+0x00000ac0, 0x00000b00, 0x00000b40, 0x00000b80, 0x00000bc0, 0x00000c00,
+0x00000c40, 0x00000c80, 0x00000cc0, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+static const uint32_t d3[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x0000003e, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000003f,
+0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039,
+0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006,
+0x00000007, 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c,
+0x0000000d, 0x0000000e, 0x0000000f, 0x00000010, 0x00000011, 0x00000012,
+0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018,
+0x00000019, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x0000001a, 0x0000001b, 0x0000001c, 0x0000001d, 0x0000001e,
+0x0000001f, 0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024,
+0x00000025, 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0000002a,
+0x0000002b, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x00000030,
+0x00000031, 0x00000032, 0x00000033, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+#else
+
+
+/* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */
+
+static const uint32_t d0[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc,
+0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4,
+0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018,
+0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030,
+0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048,
+0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060,
+0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078,
+0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090,
+0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8,
+0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0,
+0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+static const uint32_t d1[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003,
+0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003,
+0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000,
+0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000,
+0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001,
+0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001,
+0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001,
+0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002,
+0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002,
+0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003,
+0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+static const uint32_t d2[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00,
+0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00,
+0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100,
+0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300,
+0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400,
+0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600,
+0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700,
+0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900,
+0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00,
+0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00,
+0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+static const uint32_t d3[256] = {
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000,
+0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000,
+0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000,
+0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000,
+0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000,
+0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000,
+0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000,
+0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000,
+0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000,
+0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000,
+0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000,
+0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
+0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff
+};
+
+
+#endif
diff --git a/third_party/modp_b64/modp_b64_nacl.gyp b/third_party/modp_b64/modp_b64_nacl.gyp
new file mode 100644
index 0000000..e2f4a25
--- /dev/null
+++ b/third_party/modp_b64/modp_b64_nacl.gyp
@@ -0,0 +1,26 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../native_client/build/untrusted.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'modp_b64_nacl',
+      'type': 'none',
+      'variables': {
+        'nlib_target': 'libmodp_b64_nacl.a',
+        'build_glibc': 0,
+        'build_newlib': 1,
+        'build_pnacl_newlib': 1,
+      },
+      'sources': [
+        'modp_b64.cc',
+        'modp_b64.h',
+        'modp_b64_data.h',
+      ],
+    },
+  ],
+}
diff --git a/tools/clang/scripts/blink_gc_plugin_flags.sh b/tools/clang/scripts/blink_gc_plugin_flags.sh
new file mode 100755
index 0000000..96dcade
--- /dev/null
+++ b/tools/clang/scripts/blink_gc_plugin_flags.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# Copyright 2014 The Chromium 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 returns the flags that should be passed to clang.
+
+SRC_DIR=$(cd $(dirname $0)/../../.. && echo $PWD)
+CLANG_LIB_PATH=$SRC_DIR/third_party/llvm-build/Release+Asserts/lib
+
+if uname -s | grep -q Darwin; then
+  LIBSUFFIX=dylib
+else
+  LIBSUFFIX=so
+fi
+
+FLAGS=""
+PREFIX="-Xclang -plugin-arg-blink-gc-plugin -Xclang"
+for arg in "$@"; do
+  if [[ "$arg" = "enable-oilpan=1" ]]; then
+    FLAGS="$FLAGS $PREFIX enable-oilpan"
+  elif [[ "$arg" = "dump-graph=1" ]]; then
+    FLAGS="$FLAGS $PREFIX dump-graph"
+  elif [[ "$arg" = "warn-raw-ptr=1" ]]; then
+    FLAGS="$FLAGS $PREFIX warn-raw-ptr"
+  elif [[ "$arg" = "warn-unneeded-finalizer=1" ]]; then
+    FLAGS="$FLAGS $PREFIX warn-unneeded-finalizer"
+  elif [[ "$arg" = custom_clang_lib_path=* ]]; then
+    CLANG_LIB_PATH="$(cd "${arg#*=}" && echo $PWD)"
+  fi
+done
+
+echo -Xclang -load -Xclang \"$CLANG_LIB_PATH/libBlinkGCPlugin.$LIBSUFFIX\" \
+  -Xclang -add-plugin -Xclang blink-gc-plugin $FLAGS
diff --git a/tools/clang/scripts/generate_win_compdb.py b/tools/clang/scripts/generate_win_compdb.py
new file mode 100755
index 0000000..32f5f75
--- /dev/null
+++ b/tools/clang/scripts/generate_win_compdb.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Clang tools on Windows are still a bit busted. The tooling can't handle
+backslashes in paths, doesn't understand how to read .rsp files, etc. In
+addition, ninja generates compile commands prefixed with the ninja msvc helper,
+which also confuses clang. This script generates a compile DB that should mostly
+work until clang tooling can be improved upstream.
+"""
+
+import os
+import re
+import json
+import shlex
+import subprocess
+import sys
+
+
+_NINJA_MSVC_WRAPPER = re.compile('ninja -t msvc -e .+? -- ')
+_RSP_RE = re.compile(r' (@(.+?\.rsp)) ')
+
+
+def _ProcessEntry(e):
+  # Strip off the ninja -t msvc wrapper.
+  e['command'] = _NINJA_MSVC_WRAPPER.sub('', e['command'])
+
+  # Prepend --driver-mode=cl to the command's arguments.
+  # Escape backslashes so shlex doesn't try to interpret them.
+  escaped_command = e['command'].replace('\\', '\\\\')
+  split_command = shlex.split(escaped_command)
+  e['command'] = ' '.join(
+      split_command[:1] + ['--driver-mode=cl'] + split_command[1:])
+
+  # Expand the contents of the response file, if any.
+  # http://llvm.org/bugs/show_bug.cgi?id=21634
+  try:
+    match = _RSP_RE.search(e['command'])
+    rsp_path = os.path.join(e['directory'], match.group(2))
+    rsp_contents = file(rsp_path).read()
+    e['command'] = ''.join([
+        e['command'][:match.start(1)],
+        rsp_contents,
+        e['command'][match.end(1):]])
+  except IOError:
+    pass
+
+  # TODO(dcheng): This should be implemented in Clang tooling.
+  # http://llvm.org/bugs/show_bug.cgi?id=19687
+  # Finally, use slashes instead of backslashes to avoid bad escaping by the
+  # tooling. This should really only matter for command, but we do it for all
+  # keys for consistency.
+  e['directory'] = e['directory'].replace('\\', '/')
+  e['command'] = e['command'].replace('\\', '/')
+  e['file'] = e['file'].replace('\\', '/')
+
+  return e
+
+
+def main(argv):
+  # First, generate the compile database.
+  print 'Generating compile DB with ninja...'
+  compile_db_as_json = subprocess.check_output(shlex.split(
+      'ninja -C out/Debug -t compdb cc cxx objc objcxx'))
+
+  compile_db = json.loads(compile_db_as_json)
+  print 'Read in %d entries from the compile db' % len(compile_db)
+  compile_db = [_ProcessEntry(e) for e in compile_db]
+  original_length = len(compile_db)
+
+  # Filter out NaCl stuff. The clang tooling chokes on them.
+  compile_db = [e for e in compile_db if '_nacl.cc.pdb' not in e['command']
+      and '_nacl_win64.cc.pdb' not in e['command']]
+  print 'Filtered out %d entries...' % (original_length - len(compile_db))
+  f = file('out/Debug/compile_commands.json', 'w')
+  f.write(json.dumps(compile_db, indent=2))
+  print 'Done!'
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh
new file mode 100755
index 0000000..25cd6f0
--- /dev/null
+++ b/tools/clang/scripts/package.sh
@@ -0,0 +1,200 @@
+#!/bin/bash
+# Copyright (c) 2012 The Chromium 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 will check out llvm and clang, and then package the results up
+# to a tgz file.
+
+gcc_toolchain=
+
+# Parse command line options.
+while [[ $# > 0 ]]; do
+  case $1 in
+    --gcc-toolchain)
+      shift
+      if [[ $# == 0 ]]; then
+        echo "--gcc-toolchain requires an argument."
+        exit 1
+      fi
+      if [[ -x "$1/bin/gcc" ]]; then
+        gcc_toolchain=$1
+      else
+        echo "Invalid --gcc-toolchain: '$1'."
+        echo "'$1/bin/gcc' does not appear to be valid."
+        exit 1
+      fi
+      ;;
+
+    --help)
+      echo "usage: $0 [--gcc-toolchain <prefix>]"
+      echo
+      echo "--gcc-toolchain: Set the prefix for which GCC version should"
+      echo "    be used for building. For example, to use gcc in"
+      echo "    /opt/foo/bin/gcc, use '--gcc-toolchain '/opt/foo"
+      echo
+      exit 1
+      ;;
+    *)
+      echo "Unknown argument: '$1'."
+      echo "Use --help for help."
+      exit 1
+      ;;
+  esac
+  shift
+done
+
+
+THIS_DIR="$(dirname "${0}")"
+LLVM_DIR="${THIS_DIR}/../../../third_party/llvm"
+LLVM_BOOTSTRAP_DIR="${THIS_DIR}/../../../third_party/llvm-bootstrap"
+LLVM_BOOTSTRAP_INSTALL_DIR="${LLVM_DIR}/../llvm-bootstrap-install"
+LLVM_BUILD_DIR="${THIS_DIR}/../../../third_party/llvm-build"
+LLVM_BIN_DIR="${LLVM_BUILD_DIR}/Release+Asserts/bin"
+LLVM_LIB_DIR="${LLVM_BUILD_DIR}/Release+Asserts/lib"
+STAMP_FILE="${LLVM_DIR}/../llvm-build/cr_build_revision"
+
+echo "Diff in llvm:" | tee buildlog.txt
+svn stat "${LLVM_DIR}" 2>&1 | tee -a buildlog.txt
+svn diff "${LLVM_DIR}" 2>&1 | tee -a buildlog.txt
+echo "Diff in llvm/tools/clang:" | tee -a buildlog.txt
+svn stat "${LLVM_DIR}/tools/clang" 2>&1 | tee -a buildlog.txt
+svn diff "${LLVM_DIR}/tools/clang" 2>&1 | tee -a buildlog.txt
+echo "Diff in llvm/compiler-rt:" | tee -a buildlog.txt
+svn stat "${LLVM_DIR}/compiler-rt" 2>&1 | tee -a buildlog.txt
+svn diff "${LLVM_DIR}/compiler-rt" 2>&1 | tee -a buildlog.txt
+echo "Diff in llvm/projects/libcxx:" | tee -a buildlog.txt
+svn stat "${LLVM_DIR}/projects/libcxx" 2>&1 | tee -a buildlog.txt
+svn diff "${LLVM_DIR}/projects/libcxx" 2>&1 | tee -a buildlog.txt
+echo "Diff in llvm/projects/libcxxabi:" | tee -a buildlog.txt
+svn stat "${LLVM_DIR}/projects/libcxxabi" 2>&1 | tee -a buildlog.txt
+svn diff "${LLVM_DIR}/projects/libcxxabi" 2>&1 | tee -a buildlog.txt
+
+
+echo "Starting build" | tee -a buildlog.txt
+
+set -exu
+set -o pipefail
+
+# Do a clobber build.
+rm -rf "${LLVM_BOOTSTRAP_DIR}"
+rm -rf "${LLVM_BOOTSTRAP_INSTALL_DIR}"
+rm -rf "${LLVM_BUILD_DIR}"
+extra_flags=
+if [[ -n "${gcc_toolchain}" ]]; then
+  extra_flags="--gcc-toolchain ${gcc_toolchain}"
+fi
+"${THIS_DIR}"/update.sh --bootstrap --force-local-build --run-tests \
+    ${extra_flags} 2>&1 | tee -a buildlog.txt
+
+R=$(cat "${STAMP_FILE}")
+
+PDIR=clang-$R
+rm -rf $PDIR
+mkdir $PDIR
+mkdir $PDIR/bin
+mkdir $PDIR/lib
+
+GOLDDIR=llvmgold-$R
+if [ "$(uname -s)" = "Linux" ]; then
+  mkdir -p $GOLDDIR/lib
+fi
+
+if [ "$(uname -s)" = "Darwin" ]; then
+  SO_EXT="dylib"
+else
+  SO_EXT="so"
+fi
+
+# Copy buildlog over.
+cp buildlog.txt $PDIR/
+
+# Copy clang into pdir, symlink clang++ to it.
+cp "${LLVM_BIN_DIR}/clang" $PDIR/bin/
+(cd $PDIR/bin && ln -sf clang clang++)
+cp "${LLVM_BIN_DIR}/llvm-symbolizer" $PDIR/bin/
+if [ "$(uname -s)" = "Darwin" ]; then
+  cp "${LLVM_BIN_DIR}/libc++.1.${SO_EXT}" $PDIR/bin/
+  (cd $PDIR/bin && ln -sf libc++.1.dylib libc++.dylib)
+fi
+
+# Copy libc++ headers.
+if [ "$(uname -s)" = "Darwin" ]; then
+  mkdir $PDIR/include
+  cp -R "${LLVM_BOOTSTRAP_INSTALL_DIR}/include/c++" $PDIR/include
+fi
+
+# Copy plugins. Some of the dylibs are pretty big, so copy only the ones we
+# care about.
+cp "${LLVM_LIB_DIR}/libFindBadConstructs.${SO_EXT}" $PDIR/lib
+cp "${LLVM_LIB_DIR}/libBlinkGCPlugin.${SO_EXT}" $PDIR/lib
+
+# Copy gold plugin on Linux.
+if [ "$(uname -s)" = "Linux" ]; then
+  cp "${LLVM_LIB_DIR}/LLVMgold.${SO_EXT}" $GOLDDIR/lib
+fi
+
+if [[ -n "${gcc_toolchain}" ]]; then
+  # Copy the stdlibc++.so.6 we linked Clang against so it can run.
+  cp "${LLVM_LIB_DIR}/libstdc++.so.6" $PDIR/lib
+fi
+
+# Copy built-in headers (lib/clang/3.x.y/include).
+# compiler-rt builds all kinds of libraries, but we want only some.
+if [ "$(uname -s)" = "Darwin" ]; then
+  # Keep only the OSX (ASan and profile) and iossim (ASan) runtime libraries:
+  # Release+Asserts/lib/clang/*/lib/darwin/libclang_rt.{asan,profile}_*
+  find "${LLVM_LIB_DIR}/clang" -type f -path '*lib/darwin*' \
+       ! -name '*asan_osx*' ! -name '*asan_iossim*' ! -name '*profile_osx*' | \
+      xargs rm
+  # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to
+  # @executable_path.
+  # TODO(glider): this is transitional. We'll need to fix the dylib name
+  # either in our build system, or in Clang. See also http://crbug.com/344836.
+  ASAN_DYLIB_NAMES="libclang_rt.asan_osx_dynamic.dylib
+    libclang_rt.asan_iossim_dynamic.dylib"
+  for ASAN_DYLIB_NAME in $ASAN_DYLIB_NAMES
+  do
+    ASAN_DYLIB=$(find "${LLVM_LIB_DIR}/clang" \
+                      -type f -path "*${ASAN_DYLIB_NAME}")
+    install_name_tool -id @executable_path/${ASAN_DYLIB_NAME} "${ASAN_DYLIB}"
+    strip -x "${ASAN_DYLIB}"
+  done
+else
+  # Keep only
+  # Release+Asserts/lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,profile}-*.a
+  # , but not dfsan.
+  find "${LLVM_LIB_DIR}/clang" -type f -path '*lib/linux*' \
+       ! -name '*[atm]san*' ! -name '*ubsan*' ! -name '*libclang_rt.san*' \
+       ! -name '*profile*' | xargs rm -v
+  # Strip the debug info from the runtime libraries.
+  find "${LLVM_LIB_DIR}/clang" -type f -path '*lib/linux*' ! -name '*.syms' | xargs strip -g
+fi
+
+cp -vR "${LLVM_LIB_DIR}/clang" $PDIR/lib
+
+if [ "$(uname -s)" = "Darwin" ]; then
+  tar zcf $PDIR.tgz -C $PDIR bin include lib buildlog.txt
+else
+  tar zcf $PDIR.tgz -C $PDIR bin lib buildlog.txt
+fi
+
+if [ "$(uname -s)" = "Linux" ]; then
+  tar zcf $GOLDDIR.tgz -C $GOLDDIR lib
+fi
+
+if [ "$(uname -s)" = "Darwin" ]; then
+  PLATFORM=Mac
+else
+  PLATFORM=Linux_x64
+fi
+
+echo To upload, run:
+echo gsutil cp -a public-read $PDIR.tgz \
+     gs://chromium-browser-clang/$PLATFORM/$PDIR.tgz
+if [ "$(uname -s)" = "Linux" ]; then
+  echo gsutil cp -a public-read $GOLDDIR.tgz \
+       gs://chromium-browser-clang/$PLATFORM/$GOLDDIR.tgz
+fi
+
+# FIXME: Warn if the file already exists on the server.
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py
new file mode 100755
index 0000000..58a9a86
--- /dev/null
+++ b/tools/clang/scripts/run_tool.py
@@ -0,0 +1,338 @@
+#!/usr/bin/env python
+# 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.
+
+"""Wrapper script to help run clang tools across Chromium code.
+
+How to use this tool:
+If you want to run the tool across all Chromium code:
+run_tool.py <tool> <path/to/compiledb>
+
+If you want to include all files mentioned in the compilation database:
+run_tool.py <tool> <path/to/compiledb> --all
+
+If you only want to run the tool across just chrome/browser and content/browser:
+run_tool.py <tool> <path/to/compiledb> chrome/browser content/browser
+
+Please see https://code.google.com/p/chromium/wiki/ClangToolRefactoring for more
+information, which documents the entire automated refactoring flow in Chromium.
+
+Why use this tool:
+The clang tool implementation doesn't take advantage of multiple cores, and if
+it fails mysteriously in the middle, all the generated replacements will be
+lost.
+
+Unfortunately, if the work is simply sharded across multiple cores by running
+multiple RefactoringTools, problems arise when they attempt to rewrite a file at
+the same time. To work around that, clang tools that are run using this tool
+should output edits to stdout in the following format:
+
+==== BEGIN EDITS ====
+r:<file path>:<offset>:<length>:<replacement text>
+r:<file path>:<offset>:<length>:<replacement text>
+...etc...
+==== END EDITS ====
+
+Any generated edits are applied once the clang tool has finished running
+across Chromium, regardless of whether some instances failed or not.
+"""
+
+import collections
+import functools
+import json
+import multiprocessing
+import os.path
+import pipes
+import subprocess
+import sys
+
+
+Edit = collections.namedtuple(
+    'Edit', ('edit_type', 'offset', 'length', 'replacement'))
+
+
+def _GetFilesFromGit(paths = None):
+  """Gets the list of files in the git repository.
+
+  Args:
+    paths: Prefix filter for the returned paths. May contain multiple entries.
+  """
+  args = []
+  if sys.platform == 'win32':
+    args.append('git.bat')
+  else:
+    args.append('git')
+  args.append('ls-files')
+  if paths:
+    args.extend(paths)
+  command = subprocess.Popen(args, stdout=subprocess.PIPE)
+  output, _ = command.communicate()
+  return [os.path.realpath(p) for p in output.splitlines()]
+
+
+def _GetFilesFromCompileDB(build_directory):
+  """ Gets the list of files mentioned in the compilation database.
+
+  Args:
+    build_directory: Directory that contains the compile database.
+  """
+  compiledb_path = os.path.join(build_directory, 'compile_commands.json')
+  with open(compiledb_path, 'rb') as compiledb_file:
+    json_commands = json.load(compiledb_file)
+
+  return [os.path.join(entry['directory'], entry['file'])
+          for entry in json_commands]
+
+
+def _ExtractEditsFromStdout(build_directory, stdout):
+  """Extracts generated list of edits from the tool's stdout.
+
+  The expected format is documented at the top of this file.
+
+  Args:
+    build_directory: Directory that contains the compile database. Used to
+      normalize the filenames.
+    stdout: The stdout from running the clang tool.
+
+  Returns:
+    A dictionary mapping filenames to the associated edits.
+  """
+  lines = stdout.splitlines()
+  start_index = lines.index('==== BEGIN EDITS ====')
+  end_index = lines.index('==== END EDITS ====')
+  edits = collections.defaultdict(list)
+  for line in lines[start_index + 1:end_index]:
+    try:
+      edit_type, path, offset, length, replacement = line.split(':::', 4)
+      replacement = replacement.replace("\0", "\n");
+      # Normalize the file path emitted by the clang tool.
+      path = os.path.realpath(os.path.join(build_directory, path))
+      edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
+    except ValueError:
+      print 'Unable to parse edit: %s' % line
+  return edits
+
+
+def _ExecuteTool(toolname, build_directory, filename):
+  """Executes the tool.
+
+  This is defined outside the class so it can be pickled for the multiprocessing
+  module.
+
+  Args:
+    toolname: Path to the tool to execute.
+    build_directory: Directory that contains the compile database.
+    filename: The file to run the tool over.
+
+  Returns:
+    A dictionary that must contain the key "status" and a boolean value
+    associated with it.
+
+    If status is True, then the generated edits are stored with the key "edits"
+    in the dictionary.
+
+    Otherwise, the filename and the output from stderr are associated with the
+    keys "filename" and "stderr" respectively.
+  """
+  command = subprocess.Popen((toolname, '-p', build_directory, filename),
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE)
+  stdout, stderr = command.communicate()
+  if command.returncode != 0:
+    return {'status': False, 'filename': filename, 'stderr': stderr}
+  else:
+    return {'status': True,
+            'edits': _ExtractEditsFromStdout(build_directory, stdout)}
+
+
+class _CompilerDispatcher(object):
+  """Multiprocessing controller for running clang tools in parallel."""
+
+  def __init__(self, toolname, build_directory, filenames):
+    """Initializer method.
+
+    Args:
+      toolname: Path to the tool to execute.
+      build_directory: Directory that contains the compile database.
+      filenames: The files to run the tool over.
+    """
+    self.__toolname = toolname
+    self.__build_directory = build_directory
+    self.__filenames = filenames
+    self.__success_count = 0
+    self.__failed_count = 0
+    self.__edit_count = 0
+    self.__edits = collections.defaultdict(list)
+
+  @property
+  def edits(self):
+    return self.__edits
+
+  @property
+  def failed_count(self):
+    return self.__failed_count
+
+  def Run(self):
+    """Does the grunt work."""
+    pool = multiprocessing.Pool()
+    result_iterator = pool.imap_unordered(
+        functools.partial(_ExecuteTool, self.__toolname,
+                          self.__build_directory),
+        self.__filenames)
+    for result in result_iterator:
+      self.__ProcessResult(result)
+    sys.stdout.write('\n')
+    sys.stdout.flush()
+
+  def __ProcessResult(self, result):
+    """Handles result processing.
+
+    Args:
+      result: The result dictionary returned by _ExecuteTool.
+    """
+    if result['status']:
+      self.__success_count += 1
+      for k, v in result['edits'].iteritems():
+        self.__edits[k].extend(v)
+        self.__edit_count += len(v)
+    else:
+      self.__failed_count += 1
+      sys.stdout.write('\nFailed to process %s\n' % result['filename'])
+      sys.stdout.write(result['stderr'])
+      sys.stdout.write('\n')
+    percentage = (
+        float(self.__success_count + self.__failed_count) /
+        len(self.__filenames)) * 100
+    sys.stdout.write('Succeeded: %d, Failed: %d, Edits: %d [%.2f%%]\r' % (
+        self.__success_count, self.__failed_count, self.__edit_count,
+        percentage))
+    sys.stdout.flush()
+
+
+def _ApplyEdits(edits, clang_format_diff_path):
+  """Apply the generated edits.
+
+  Args:
+    edits: A dict mapping filenames to Edit instances that apply to that file.
+    clang_format_diff_path: Path to the clang-format-diff.py helper to help
+      automatically reformat diffs to avoid style violations. Pass None if the
+      clang-format step should be skipped.
+  """
+  edit_count = 0
+  for k, v in edits.iteritems():
+    # Sort the edits and iterate through them in reverse order. Sorting allows
+    # duplicate edits to be quickly skipped, while reversing means that
+    # subsequent edits don't need to have their offsets updated with each edit
+    # applied.
+    v.sort()
+    last_edit = None
+    with open(k, 'rb+') as f:
+      contents = bytearray(f.read())
+      for edit in reversed(v):
+        if edit == last_edit:
+          continue
+        last_edit = edit
+        contents[edit.offset:edit.offset + edit.length] = edit.replacement
+        if not edit.replacement:
+          _ExtendDeletionIfElementIsInList(contents, edit.offset)
+        edit_count += 1
+      f.seek(0)
+      f.truncate()
+      f.write(contents)
+    if clang_format_diff_path:
+      # TODO(dcheng): python3.3 exposes this publicly as shlex.quote, but Chrome
+      # uses python2.7. Use the deprecated interface until Chrome uses a newer
+      # Python.
+      if subprocess.call('git diff -U0 %s | python %s -i -p1 -style=file ' % (
+          pipes.quote(k), clang_format_diff_path), shell=True) != 0:
+        print 'clang-format failed for %s' % k
+  print 'Applied %d edits to %d files' % (edit_count, len(edits))
+
+
+_WHITESPACE_BYTES = frozenset((ord('\t'), ord('\n'), ord('\r'), ord(' ')))
+
+
+def _ExtendDeletionIfElementIsInList(contents, offset):
+  """Extends the range of a deletion if the deleted element was part of a list.
+
+  This rewriter helper makes it easy for refactoring tools to remove elements
+  from a list. Even if a matcher callback knows that it is removing an element
+  from a list, it may not have enough information to accurately remove the list
+  element; for example, another matcher callback may end up removing an adjacent
+  list element, or all the list elements may end up being removed.
+
+  With this helper, refactoring tools can simply remove the list element and not
+  worry about having to include the comma in the replacement.
+
+  Args:
+    contents: A bytearray with the deletion already applied.
+    offset: The offset in the bytearray where the deleted range used to be.
+  """
+  char_before = char_after = None
+  left_trim_count = 0
+  for byte in reversed(contents[:offset]):
+    left_trim_count += 1
+    if byte in _WHITESPACE_BYTES:
+      continue
+    if byte in (ord(','), ord(':'), ord('('), ord('{')):
+      char_before = chr(byte)
+    break
+
+  right_trim_count = 0
+  for byte in contents[offset:]:
+    right_trim_count += 1
+    if byte in _WHITESPACE_BYTES:
+      continue
+    if byte == ord(','):
+      char_after = chr(byte)
+    break
+
+  if char_before:
+    if char_after:
+      del contents[offset:offset + right_trim_count]
+    elif char_before in (',', ':'):
+      del contents[offset - left_trim_count:offset]
+
+
+def main(argv):
+  if len(argv) < 2:
+    print 'Usage: run_tool.py <clang tool> <compile DB> <path 1> <path 2> ...'
+    print '  <clang tool> is the clang tool that should be run.'
+    print '  <compile db> is the directory that contains the compile database'
+    print '  <path 1> <path2> ... can be used to filter what files are edited'
+    return 1
+
+  clang_format_diff_path = os.path.join(
+      os.path.dirname(os.path.realpath(__file__)),
+      '../../../third_party/llvm/tools/clang/tools/clang-format',
+      'clang-format-diff.py')
+  # TODO(dcheng): Allow this to be controlled with a flag as well.
+  # TODO(dcheng): Shell escaping of args to git diff to clang-format is broken
+  # on Windows.
+  if not os.path.isfile(clang_format_diff_path) or sys.platform == 'win32':
+    clang_format_diff_path = None
+
+  if len(argv) == 3 and argv[2] == '--all':
+    filenames = set(_GetFilesFromCompileDB(argv[1]))
+  else:
+    filenames = set(_GetFilesFromGit(argv[2:]))
+    # Filter out files that aren't C/C++/Obj-C/Obj-C++.
+    extensions = frozenset(('.c', '.cc', '.m', '.mm'))
+    filenames = [f for f in filenames
+                 if os.path.splitext(f)[1] in extensions]
+  dispatcher = _CompilerDispatcher(argv[0], argv[1], filenames)
+  dispatcher.Run()
+  # Filter out edits to files that aren't in the git repository, since it's not
+  # useful to modify files that aren't under source control--typically, these
+  # are generated files or files in a git submodule that's not part of Chromium.
+  _ApplyEdits({k : v for k, v in dispatcher.edits.iteritems()
+                    if os.path.realpath(k) in filenames},
+              clang_format_diff_path)
+  if dispatcher.failed_count != 0:
+    return 2
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/tools/clang/scripts/test_tool.py b/tools/clang/scripts/test_tool.py
new file mode 100755
index 0000000..1f64be4
--- /dev/null
+++ b/tools/clang/scripts/test_tool.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# 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.
+
+"""Test harness for chromium clang tools."""
+
+import difflib
+import glob
+import json
+import os
+import os.path
+import subprocess
+import shutil
+import sys
+
+
+def _GenerateCompileCommands(files, include_paths):
+  """Returns a JSON string containing a compilation database for the input."""
+  include_path_flags = ' '.join('-I %s' % include_path
+                               for include_path in include_paths)
+  return json.dumps([{'directory': '.',
+                      'command': 'clang++ -std=c++11 -fsyntax-only %s -c %s' % (
+                          include_path_flags, f),
+                      'file': f} for f in files], indent=2)
+
+
+def _NumberOfTestsToString(tests):
+  """Returns an English describing the number of tests."""
+  return "%d test%s" % (tests, 's' if tests != 1 else '')
+
+
+def main(argv):
+  if len(argv) < 1:
+    print 'Usage: test_tool.py <clang tool>'
+    print '  <clang tool> is the clang tool to be tested.'
+    sys.exit(1)
+
+  tool_to_test = argv[0]
+  tools_clang_scripts_directory = os.path.dirname(os.path.realpath(__file__))
+  tools_clang_directory = os.path.dirname(tools_clang_scripts_directory)
+  test_directory_for_tool = os.path.join(
+      tools_clang_directory, tool_to_test, 'tests')
+  compile_database = os.path.join(test_directory_for_tool,
+                                  'compile_commands.json')
+  source_files = glob.glob(os.path.join(test_directory_for_tool,
+                                        '*-original.cc'))
+  actual_files = ['-'.join([source_file.rsplit('-', 1)[0], 'actual.cc'])
+                  for source_file in source_files]
+  expected_files = ['-'.join([source_file.rsplit('-', 1)[0], 'expected.cc'])
+                    for source_file in source_files]
+  include_paths = []
+  include_paths.append(
+      os.path.realpath(os.path.join(tools_clang_directory, '../..')))
+  # Many gtest headers expect to have testing/gtest/include in the include
+  # search path.
+  include_paths.append(
+      os.path.realpath(os.path.join(tools_clang_directory,
+                                    '../..',
+                                    'testing/gtest/include')))
+
+  try:
+    # Set up the test environment.
+    for source, actual in zip(source_files, actual_files):
+      shutil.copyfile(source, actual)
+    # Stage the test files in the git index. If they aren't staged, then
+    # run_tools.py will skip them when applying replacements.
+    args = ['git', 'add']
+    args.extend(actual_files)
+    subprocess.check_call(args)
+    # Generate a temporary compilation database to run the tool over.
+    with open(compile_database, 'w') as f:
+      f.write(_GenerateCompileCommands(actual_files, include_paths))
+
+    args = ['python',
+            os.path.join(tools_clang_scripts_directory, 'run_tool.py'),
+            tool_to_test,
+            test_directory_for_tool]
+    args.extend(actual_files)
+    run_tool = subprocess.Popen(args, stdout=subprocess.PIPE)
+    stdout, _ = run_tool.communicate()
+    if run_tool.returncode != 0:
+      print 'run_tool failed:\n%s' % stdout
+      sys.exit(1)
+
+    passed = 0
+    failed = 0
+    for expected, actual in zip(expected_files, actual_files):
+      print '[ RUN      ] %s' % os.path.relpath(actual)
+      expected_output = actual_output = None
+      with open(expected, 'r') as f:
+        expected_output = f.readlines()
+      with open(actual, 'r') as f:
+        actual_output = f.readlines()
+      if actual_output != expected_output:
+        failed += 1
+        for line in difflib.unified_diff(expected_output, actual_output,
+                                         fromfile=os.path.relpath(expected),
+                                         tofile=os.path.relpath(actual)):
+          sys.stdout.write(line)
+        print '[  FAILED  ] %s' % os.path.relpath(actual)
+        # Don't clean up the file on failure, so the results can be referenced
+        # more easily.
+        continue
+      print '[       OK ] %s' % os.path.relpath(actual)
+      passed += 1
+      os.remove(actual)
+
+    if failed == 0:
+      os.remove(compile_database)
+
+    print '[==========] %s ran.' % _NumberOfTestsToString(len(source_files))
+    if passed > 0:
+      print '[  PASSED  ] %s.' % _NumberOfTestsToString(passed)
+    if failed > 0:
+      print '[  FAILED  ] %s.' % _NumberOfTestsToString(failed)
+  finally:
+    # No matter what, unstage the git changes we made earlier to avoid polluting
+    # the index.
+    args = ['git', 'reset', '--quiet', 'HEAD']
+    args.extend(actual_files)
+    subprocess.call(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
new file mode 100755
index 0000000..a1b369f
--- /dev/null
+++ b/tools/clang/scripts/update.py
@@ -0,0 +1,336 @@
+#!/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.
+
+"""Windows can't run .sh files, so this is a Python implementation of
+update.sh. This script should replace update.sh on all platforms eventually."""
+
+import argparse
+import os
+import re
+import shutil
+import subprocess
+import stat
+import sys
+import time
+
+# Do NOT CHANGE this if you don't know what you're doing -- see
+# https://code.google.com/p/chromium/wiki/UpdatingClang
+# Reverting problematic clang rolls is safe, though.
+# Note: this revision is only used for Windows. Other platforms use update.sh.
+LLVM_WIN_REVISION = 'HEAD'
+
+# ASan on Windows is useful enough to use it even while the clang/win is still
+# in bringup. Use a pinned revision to make it slightly more stable.
+if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and
+    not 'LLVM_FORCE_HEAD_REVISION' in os.environ):
+  LLVM_WIN_REVISION = '235968'
+
+# Path constants. (All of these should be absolute paths.)
+THIS_DIR = os.path.abspath(os.path.dirname(__file__))
+CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..'))
+LLVM_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm')
+CHROME_TOOLS_SHIM_DIR = os.path.join(LLVM_DIR, 'tools', 'chrometools')
+LLVM_BUILD_DIR = os.path.join(CHROMIUM_DIR, 'third_party', 'llvm-build',
+                              'Release+Asserts')
+COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt')
+CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
+LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld')
+COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
+STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
+VERSION = '3.7.0'
+
+LLVM_REPO_URL='https://llvm.org/svn/llvm-project'
+if 'LLVM_REPO_URL' in os.environ:
+  LLVM_REPO_URL = os.environ['LLVM_REPO_URL']
+
+
+def ReadStampFile():
+  """Return the contents of the stamp file, or '' if it doesn't exist."""
+  try:
+    with open(STAMP_FILE, 'r') as f:
+      return f.read();
+  except IOError:
+    return ''
+
+
+def WriteStampFile(s):
+  """Write s to the stamp file."""
+  if not os.path.exists(LLVM_BUILD_DIR):
+    os.makedirs(LLVM_BUILD_DIR)
+  with open(STAMP_FILE, 'w') as f:
+    f.write(s)
+
+
+def PrintRevision():
+  """Print the current Clang revision."""
+  # gyp runs update.py --print-revision even when clang isn't used.
+  # It won't use the value, but we must not error.
+  if not os.path.exists(LLVM_DIR):
+    print "0"
+    return
+
+  # TODO(hans): This needs an update when we move to prebuilt Clang binaries.
+  svn_info = subprocess.check_output(['svn', 'info', LLVM_DIR], shell=True)
+  m = re.search(r'Revision: (\d+)', svn_info)
+  assert m
+  print m.group(1)
+
+
+def RmTree(dir):
+  """Delete dir."""
+  def ChmodAndRetry(func, path, _):
+    # Subversion can leave read-only files around.
+    if not os.access(path, os.W_OK):
+      os.chmod(path, stat.S_IWUSR)
+      return func(path)
+    raise
+
+  shutil.rmtree(dir, onerror=ChmodAndRetry)
+
+
+def RunCommand(command, fail_hard=True):
+  """Run command and return success (True) or failure; or if fail_hard is
+     True, exit on failure."""
+
+  print 'Running %s' % (str(command))
+  if subprocess.call(command, shell=True) == 0:
+    return True
+  print 'Failed.'
+  if fail_hard:
+    sys.exit(1)
+  return False
+
+
+def CopyFile(src, dst):
+  """Copy a file from src to dst."""
+  shutil.copy(src, dst)
+  print "Copying %s to %s" % (src, dst)
+
+
+def CopyDirectoryContents(src, dst, filename_filter=None):
+  """Copy the files from directory src to dst
+  with an optional filename filter."""
+  if not os.path.exists(dst):
+    os.makedirs(dst)
+  for root, _, files in os.walk(src):
+    for f in files:
+      if filename_filter and not re.match(filename_filter, f):
+        continue
+      CopyFile(os.path.join(root, f), dst)
+
+
+def Checkout(name, url, dir):
+  """Checkout the SVN module at url into dir. Use name for the log message."""
+  print "Checking out %s r%s into '%s'" % (name, LLVM_WIN_REVISION, dir)
+
+  command = ['svn', 'checkout', '--force', url + '@' + LLVM_WIN_REVISION, dir]
+  if RunCommand(command, fail_hard=False):
+    return
+
+  if os.path.isdir(dir):
+    print "Removing %s." % (dir)
+    RmTree(dir)
+
+  print "Retrying."
+  RunCommand(command)
+
+
+def DeleteChromeToolsShim():
+  shutil.rmtree(CHROME_TOOLS_SHIM_DIR, ignore_errors=True)
+
+
+def CreateChromeToolsShim():
+  """Hooks the Chrome tools into the LLVM build.
+
+  Several Chrome tools have dependencies on LLVM/Clang libraries. The LLVM build
+  detects implicit tools in the tools subdirectory, so this helper install a
+  shim CMakeLists.txt that forwards to the real directory for the Chrome tools.
+
+  Note that the shim directory name intentionally has no - or _. The implicit
+  tool detection logic munges them in a weird way."""
+  assert not any(i in os.path.basename(CHROME_TOOLS_SHIM_DIR) for i in '-_')
+  os.mkdir(CHROME_TOOLS_SHIM_DIR)
+  with file(os.path.join(CHROME_TOOLS_SHIM_DIR, 'CMakeLists.txt'), 'w') as f:
+    f.write('# Automatically generated by tools/clang/scripts/update.py. ' +
+            'Do not edit.\n')
+    f.write('# Since tools/clang is located in another directory, use the \n')
+    f.write('# two arg version to specify where build artifacts go. CMake\n')
+    f.write('# disallows reuse of the same binary dir for multiple source\n')
+    f.write('# dirs, so the build artifacts need to go into a subdirectory.\n')
+    f.write('add_subdirectory(${CHROMIUM_TOOLS_SRC} ' +
+            '${CMAKE_CURRENT_BINARY_DIR}/a)\n')
+
+
+def AddCMakeToPath():
+  """Look for CMake and add it to PATH if it's not there already."""
+  try:
+    # First check if cmake is already on PATH.
+    subprocess.call(['cmake', '--version'])
+    return
+  except OSError as e:
+    if e.errno != os.errno.ENOENT:
+      raise
+
+  cmake_dir = 'C:\\Program Files (x86)\\CMake\\bin'
+  if os.path.isdir(cmake_dir):
+    os.environ['PATH'] = os.environ.get('PATH', '') + os.pathsep + cmake_dir
+    return
+  print 'Failed to find CMake!'
+  sys.exit(1)
+
+
+vs_version = None
+def GetVSVersion():
+  global vs_version
+  if vs_version:
+    return vs_version
+
+  # Try using the toolchain in depot_tools.
+  # This sets environment variables used by SelectVisualStudioVersion below.
+  sys.path.append(os.path.join(CHROMIUM_DIR, 'build'))
+  import vs_toolchain
+  vs_toolchain.SetEnvironmentAndGetRuntimeDllDirs()
+
+  # Use gyp to find the MSVS installation, either in depot_tools as per above,
+  # or a system-wide installation otherwise.
+  sys.path.append(os.path.join(CHROMIUM_DIR, 'tools', 'gyp', 'pylib'))
+  import gyp.MSVSVersion
+  vs_version = gyp.MSVSVersion.SelectVisualStudioVersion('2013')
+  return vs_version
+
+
+def SubversionCmakeArg():
+  # Since cmake's find_program can only find .exe and .com,
+  # svn.bat in depot_tools will be ignored.
+  default_pathext = ('.com', '.exe', '.bat', '.cmd')
+  for path in os.environ.get('PATH', '').split(os.pathsep):
+    for ext in default_pathext:
+      candidate = os.path.join(path, 'svn' + ext)
+      if os.path.isfile(candidate):
+        return '-DSubversion_SVN_EXECUTABLE=%s' % candidate
+  return ''
+
+
+def UpdateClang(args):
+  print 'Updating Clang to %s...' % (LLVM_WIN_REVISION)
+  if LLVM_WIN_REVISION != 'HEAD' and ReadStampFile() == LLVM_WIN_REVISION:
+    print 'Already up to date.'
+    return 0
+
+  AddCMakeToPath()
+  # Reset the stamp file in case the build is unsuccessful.
+  WriteStampFile('')
+
+  DeleteChromeToolsShim();
+  Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
+  Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
+  Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR)
+  Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
+  CreateChromeToolsShim();
+
+  if not os.path.exists(LLVM_BUILD_DIR):
+    os.makedirs(LLVM_BUILD_DIR)
+  os.chdir(LLVM_BUILD_DIR)
+
+  cmake_args = ['-GNinja', '-DCMAKE_BUILD_TYPE=Release',
+                '-DLLVM_ENABLE_ASSERTIONS=ON', SubversionCmakeArg(),
+                '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(
+                    CHROMIUM_DIR, 'tools', 'clang'),
+                '-DCHROMIUM_TOOLS=%s' % ';'.join(args.tools)]
+
+  RunCommand(GetVSVersion().SetupScript('x64') +
+             ['&&', 'cmake'] + cmake_args + [LLVM_DIR])
+  RunCommand(GetVSVersion().SetupScript('x64') + ['&&', 'ninja', 'all'])
+
+  # Do an x86 build of compiler-rt to get the 32-bit ASan run-time.
+  # TODO(hans): Remove once the regular build above produces this.
+  if not os.path.exists(COMPILER_RT_BUILD_DIR):
+    os.makedirs(COMPILER_RT_BUILD_DIR)
+  os.chdir(COMPILER_RT_BUILD_DIR)
+  RunCommand(GetVSVersion().SetupScript('x86') +
+             ['&&', 'cmake'] + cmake_args + [LLVM_DIR])
+  RunCommand(GetVSVersion().SetupScript('x86') + ['&&', 'ninja', 'compiler-rt'])
+
+  # TODO(hans): Make this (and the .gypi and .isolate files) version number
+  # independent.
+  asan_rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang',
+                                     VERSION, 'lib', 'windows')
+  asan_rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang',
+                                     VERSION, 'lib', 'windows')
+  CopyDirectoryContents(asan_rt_lib_src_dir, asan_rt_lib_dst_dir,
+                        r'^.*-i386\.lib$')
+  CopyDirectoryContents(asan_rt_lib_src_dir, asan_rt_lib_dst_dir,
+                        r'^.*-i386\.dll$')
+
+  CopyFile(os.path.join(asan_rt_lib_src_dir, '..', '..', 'asan_blacklist.txt'),
+           os.path.join(asan_rt_lib_dst_dir, '..', '..'))
+
+  # Make an extra copy of the sanitizer headers, to be put on the include path
+  # of the fallback compiler.
+  sanitizer_include_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', VERSION,
+                                       'include', 'sanitizer')
+  aux_sanitizer_include_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang',
+                                           VERSION, 'include_sanitizer',
+                                           'sanitizer')
+  if not os.path.exists(aux_sanitizer_include_dir):
+    os.makedirs(aux_sanitizer_include_dir)
+  for _, _, files in os.walk(sanitizer_include_dir):
+    for f in files:
+      CopyFile(os.path.join(sanitizer_include_dir, f),
+               aux_sanitizer_include_dir)
+
+  WriteStampFile(LLVM_WIN_REVISION)
+  print 'Clang update was successful.'
+  return 0
+
+
+def main():
+  if not sys.platform in ['win32', 'cygwin']:
+    # For non-Windows, fall back to update.sh.
+    # TODO(hans): Make update.py replace update.sh completely.
+
+    # This script is called by gclient. gclient opens its hooks subprocesses
+    # with (stdout=subprocess.PIPE, stderr=subprocess.STDOUT) and then does
+    # custom output processing that breaks printing '\r' characters for
+    # single-line updating status messages as printed by curl and wget.
+    # Work around this by setting stderr of the update.sh process to stdin (!):
+    # gclient doesn't redirect stdin, and while stdin itself is read-only, a
+    # dup()ed sys.stdin is writable, try
+    #   fd2 = os.dup(sys.stdin.fileno()); os.write(fd2, 'hi')
+    # TODO: Fix gclient instead, http://crbug.com/95350
+    try:
+      stderr = os.fdopen(os.dup(sys.stdin.fileno()))
+    except:
+      stderr = sys.stderr
+    return subprocess.call(
+        [os.path.join(os.path.dirname(__file__), 'update.sh')] + sys.argv[1:],
+        stderr=stderr)
+
+  parser = argparse.ArgumentParser(description='Build Clang.')
+  parser.add_argument('--tools', nargs='*', default=['plugins'])
+  # For now, this flag is only used for the non-Windows flow, but argparser gets
+  # mad if it sees a flag it doesn't recognize.
+  parser.add_argument('--if-needed', action='store_true')
+  parser.add_argument('--print-revision', action='store_true')
+
+  args = parser.parse_args()
+
+  if args.print_revision:
+    PrintRevision()
+    return 0
+
+  if not re.search(r'\b(clang|asan)=1', os.environ.get('GYP_DEFINES', '')):
+    print 'Skipping Clang update (clang=1 was not set in GYP_DEFINES).'
+    return 0
+
+  if re.search(r'\b(make_clang_dir)=', os.environ.get('GYP_DEFINES', '')):
+    print 'Skipping Clang update (make_clang_dir= was set in GYP_DEFINES).'
+    return 0
+
+  return UpdateClang(args)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
new file mode 100755
index 0000000..2e0f0d0
--- /dev/null
+++ b/tools/clang/scripts/update.sh
@@ -0,0 +1,709 @@
+#!/usr/bin/env bash
+# Copyright (c) 2012 The Chromium 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 will check out llvm and clang into third_party/llvm and build it.
+
+# Do NOT CHANGE this if you don't know what you're doing -- see
+# https://code.google.com/p/chromium/wiki/UpdatingClang
+# Reverting problematic clang rolls is safe, though.
+CLANG_REVISION=233105
+
+# This is incremented when pushing a new build of Clang at the same revision.
+CLANG_SUB_REVISION=2
+
+PACKAGE_VERSION="${CLANG_REVISION}-${CLANG_SUB_REVISION}"
+
+THIS_DIR="$(dirname "${0}")"
+LLVM_DIR="${THIS_DIR}/../../../third_party/llvm"
+LLVM_BUILD_DIR="${LLVM_DIR}/../llvm-build/Release+Asserts"
+COMPILER_RT_BUILD_DIR="${LLVM_DIR}/../llvm-build/compiler-rt"
+LLVM_BOOTSTRAP_DIR="${LLVM_DIR}/../llvm-bootstrap"
+LLVM_BOOTSTRAP_INSTALL_DIR="${LLVM_DIR}/../llvm-bootstrap-install"
+CLANG_DIR="${LLVM_DIR}/tools/clang"
+COMPILER_RT_DIR="${LLVM_DIR}/compiler-rt"
+LIBCXX_DIR="${LLVM_DIR}/projects/libcxx"
+LIBCXXABI_DIR="${LLVM_DIR}/projects/libcxxabi"
+ANDROID_NDK_DIR="${THIS_DIR}/../../../third_party/android_tools/ndk"
+STAMP_FILE="${LLVM_DIR}/../llvm-build/cr_build_revision"
+CHROMIUM_TOOLS_DIR="${THIS_DIR}/.."
+BINUTILS_DIR="${THIS_DIR}/../../../third_party/binutils"
+
+ABS_CHROMIUM_TOOLS_DIR="${PWD}/${CHROMIUM_TOOLS_DIR}"
+ABS_LIBCXX_DIR="${PWD}/${LIBCXX_DIR}"
+ABS_LIBCXXABI_DIR="${PWD}/${LIBCXXABI_DIR}"
+ABS_LLVM_DIR="${PWD}/${LLVM_DIR}"
+ABS_LLVM_BUILD_DIR="${PWD}/${LLVM_BUILD_DIR}"
+ABS_COMPILER_RT_DIR="${PWD}/${COMPILER_RT_DIR}"
+ABS_BINUTILS_DIR="${PWD}/${BINUTILS_DIR}"
+
+# ${A:-a} returns $A if it's set, a else.
+LLVM_REPO_URL=${LLVM_URL:-https://llvm.org/svn/llvm-project}
+
+CDS_URL=https://commondatastorage.googleapis.com/chromium-browser-clang
+
+if [[ -z "$GYP_DEFINES" ]]; then
+  GYP_DEFINES=
+fi
+if [[ -z "$GYP_GENERATORS" ]]; then
+  GYP_GENERATORS=
+fi
+
+
+# Die if any command dies, error on undefined variable expansions.
+set -eu
+
+
+if [[ -n ${LLVM_FORCE_HEAD_REVISION:-''} ]]; then
+  # Use a real revision number rather than HEAD to make sure that the stamp file
+  # logic works.
+  CLANG_REVISION=$(svn info "$LLVM_REPO_URL" \
+      | grep 'Revision:' | awk '{ printf $2; }')
+  PACKAGE_VERSION="${CLANG_REVISION}-0"
+fi
+
+OS="$(uname -s)"
+
+# Parse command line options.
+if_needed=
+force_local_build=
+run_tests=
+bootstrap=
+with_android=yes
+chrome_tools="plugins;blink_gc_plugin"
+gcc_toolchain=
+with_patches=yes
+
+if [[ "${OS}" = "Darwin" ]]; then
+  with_android=
+fi
+
+while [[ $# > 0 ]]; do
+  case $1 in
+    --bootstrap)
+      bootstrap=yes
+      ;;
+    --if-needed)
+      if_needed=yes
+      ;;
+    --force-local-build)
+      force_local_build=yes
+      ;;
+    --print-revision)
+      if [[ -n ${LLVM_FORCE_HEAD_REVISION:-''} ]]; then
+        svn info "$LLVM_DIR" | grep 'Revision:' | awk '{ printf $2; }'
+      else
+        echo $PACKAGE_VERSION
+      fi
+      exit 0
+      ;;
+    --run-tests)
+      run_tests=yes
+      ;;
+    --without-android)
+      with_android=
+      ;;
+    --without-patches)
+      with_patches=
+      ;;
+    --with-chrome-tools)
+      shift
+      if [[ $# == 0 ]]; then
+        echo "--with-chrome-tools requires an argument."
+        exit 1
+      fi
+      chrome_tools=$1
+      ;;
+    --gcc-toolchain)
+      shift
+      if [[ $# == 0 ]]; then
+        echo "--gcc-toolchain requires an argument."
+        exit 1
+      fi
+      if [[ -x "$1/bin/gcc" ]]; then
+        gcc_toolchain=$1
+      else
+        echo "Invalid --gcc-toolchain: '$1'."
+        echo "'$1/bin/gcc' does not appear to be valid."
+        exit 1
+      fi
+      ;;
+
+    --help)
+      echo "usage: $0 [--force-local-build] [--if-needed] [--run-tests] "
+      echo "--bootstrap: First build clang with CC, then with itself."
+      echo "--force-local-build: Don't try to download prebuilt binaries."
+      echo "--if-needed: Download clang only if the script thinks it is needed."
+      echo "--run-tests: Run tests after building. Only for local builds."
+      echo "--print-revision: Print current clang revision and exit."
+      echo "--without-android: Don't build ASan Android runtime library."
+      echo "--with-chrome-tools: Select which chrome tools to build." \
+           "Defaults to plugins;blink_gc_plugin."
+      echo "    Example: --with-chrome-tools plugins;empty-string"
+      echo "--gcc-toolchain: Set the prefix for which GCC version should"
+      echo "    be used for building. For example, to use gcc in"
+      echo "    /opt/foo/bin/gcc, use '--gcc-toolchain '/opt/foo"
+      echo "--without-patches: Don't apply local patches."
+      echo
+      exit 1
+      ;;
+    *)
+      echo "Unknown argument: '$1'."
+      echo "Use --help for help."
+      exit 1
+      ;;
+  esac
+  shift
+done
+
+if [[ -n ${LLVM_FORCE_HEAD_REVISION:-''} ]]; then
+  force_local_build=yes
+
+  # Skip local patches when using HEAD: they probably don't apply anymore.
+  with_patches=
+
+  if ! [[ "$GYP_DEFINES" =~ .*OS=android.* ]]; then
+    # Only build the Android ASan rt when targetting Android.
+    with_android=
+  fi
+
+  LLVM_BUILD_TOOLS_DIR="${ABS_LLVM_DIR}/../llvm-build-tools"
+
+  if [[ "${OS}" == "Linux" ]] && [[ -z "${gcc_toolchain}" ]]; then
+    if [[ $(gcc -dumpversion) < "4.7.0" ]]; then
+      # We need a newer GCC version.
+      if [[ ! -e "${LLVM_BUILD_TOOLS_DIR}/gcc482" ]]; then
+        echo "Downloading pre-built GCC 4.8.2..."
+        mkdir -p "${LLVM_BUILD_TOOLS_DIR}"
+        curl --fail -L "${CDS_URL}/tools/gcc482.tgz" | \
+          tar zxf - -C "${LLVM_BUILD_TOOLS_DIR}"
+        echo Done
+      fi
+      gcc_toolchain="${LLVM_BUILD_TOOLS_DIR}/gcc482"
+    else
+      # Always set gcc_toolchain; llvm-symbolizer needs the bundled libstdc++.
+      gcc_toolchain="$(dirname $(dirname $(which gcc)))"
+    fi
+  fi
+
+  if [[ "${OS}" == "Linux" || "${OS}" == "Darwin" ]]; then
+    if [[ $(cmake --version | grep -Eo '[0-9.]+') < "3.0" ]]; then
+      # We need a newer CMake version.
+      if [[ ! -e "${LLVM_BUILD_TOOLS_DIR}/cmake310" ]]; then
+        echo "Downloading pre-built CMake 3.10..."
+        mkdir -p "${LLVM_BUILD_TOOLS_DIR}"
+        curl --fail -L "${CDS_URL}/tools/cmake310_${OS}.tgz" | \
+          tar zxf - -C "${LLVM_BUILD_TOOLS_DIR}"
+        echo Done
+      fi
+      export PATH="${LLVM_BUILD_TOOLS_DIR}/cmake310/bin:${PATH}"
+    fi
+  fi
+
+  echo "LLVM_FORCE_HEAD_REVISION was set; using r${CLANG_REVISION}"
+fi
+
+if [[ -n "$if_needed" ]]; then
+  if [[ "${OS}" == "Darwin" ]]; then
+    # clang is used on Mac.
+    true
+  elif [[ "$GYP_DEFINES" =~ .*(clang|tsan|asan|lsan|msan)=1.* ]]; then
+    # clang requested via $GYP_DEFINES.
+    true
+  elif [[ -d "${LLVM_BUILD_DIR}" ]]; then
+    # clang previously downloaded, remove third_party/llvm-build to prevent
+    # updating.
+    true
+  elif [[ "${OS}" == "Linux" ]]; then
+    # Temporarily use clang on linux. Leave a stamp file behind, so that
+    # this script can remove clang again on machines where it was autoinstalled.
+    mkdir -p "${LLVM_BUILD_DIR}"
+    touch "${LLVM_BUILD_DIR}/autoinstall_stamp"
+    true
+  else
+    # clang wasn't needed, not doing anything.
+    exit 0
+  fi
+fi
+
+
+# Check if there's anything to be done, exit early if not.
+if [[ -f "${STAMP_FILE}" ]]; then
+  PREVIOUSLY_BUILT_REVISON=$(cat "${STAMP_FILE}")
+  if [[ -z "$force_local_build" ]] && \
+       [[ "${PREVIOUSLY_BUILT_REVISON}" = \
+          "${PACKAGE_VERSION}" ]]; then
+    echo "Clang already at ${PACKAGE_VERSION}"
+    exit 0
+  fi
+fi
+# To always force a new build if someone interrupts their build half way.
+rm -f "${STAMP_FILE}"
+
+
+if [[ -z "$force_local_build" ]]; then
+  # Check if there's a prebuilt binary and if so just fetch that. That's faster,
+  # and goma relies on having matching binary hashes on client and server too.
+  CDS_FILE="clang-${PACKAGE_VERSION}.tgz"
+  CDS_OUT_DIR=$(mktemp -d -t clang_download.XXXXXX)
+  CDS_OUTPUT="${CDS_OUT_DIR}/${CDS_FILE}"
+  if [ "${OS}" = "Linux" ]; then
+    CDS_FULL_URL="${CDS_URL}/Linux_x64/${CDS_FILE}"
+  elif [ "${OS}" = "Darwin" ]; then
+    CDS_FULL_URL="${CDS_URL}/Mac/${CDS_FILE}"
+  fi
+  echo Trying to download prebuilt clang
+  if which curl > /dev/null; then
+    curl -L --fail "${CDS_FULL_URL}" -o "${CDS_OUTPUT}" || \
+        rm -rf "${CDS_OUT_DIR}"
+  elif which wget > /dev/null; then
+    wget "${CDS_FULL_URL}" -O "${CDS_OUTPUT}" || rm -rf "${CDS_OUT_DIR}"
+  else
+    echo "Neither curl nor wget found. Please install one of these."
+    exit 1
+  fi
+  if [ -f "${CDS_OUTPUT}" ]; then
+    rm -rf "${LLVM_BUILD_DIR}"
+    mkdir -p "${LLVM_BUILD_DIR}"
+    tar -xzf "${CDS_OUTPUT}" -C "${LLVM_BUILD_DIR}"
+    echo clang "${PACKAGE_VERSION}" unpacked
+    echo "${PACKAGE_VERSION}" > "${STAMP_FILE}"
+    rm -rf "${CDS_OUT_DIR}"
+    exit 0
+  else
+    echo Did not find prebuilt clang "${PACKAGE_VERSION}", building
+  fi
+fi
+
+if [[ -n "${with_android}" ]] && ! [[ -d "${ANDROID_NDK_DIR}" ]]; then
+  echo "Android NDK not found at ${ANDROID_NDK_DIR}"
+  echo "The Android NDK is needed to build a Clang whose -fsanitize=address"
+  echo "works on Android. See "
+  echo "http://code.google.com/p/chromium/wiki/AndroidBuildInstructions for how"
+  echo "to install the NDK, or pass --without-android."
+  exit 1
+fi
+
+# Check that cmake and ninja are available.
+if ! which cmake > /dev/null; then
+  echo "CMake needed to build clang; please install"
+  exit 1
+fi
+if ! which ninja > /dev/null; then
+  echo "ninja needed to build clang, please install"
+  exit 1
+fi
+
+echo Reverting previously patched files
+for i in \
+      "${CLANG_DIR}/test/Index/crash-recovery-modules.m" \
+      "${CLANG_DIR}/unittests/libclang/LibclangTest.cpp" \
+      "${COMPILER_RT_DIR}/lib/asan/asan_rtl.cc" \
+      "${COMPILER_RT_DIR}/test/asan/TestCases/Linux/new_array_cookie_test.cc" \
+      "${LLVM_DIR}/test/DebugInfo/gmlt.ll" \
+      "${LLVM_DIR}/lib/CodeGen/SpillPlacement.cpp" \
+      "${LLVM_DIR}/lib/CodeGen/SpillPlacement.h" \
+      "${LLVM_DIR}/lib/Transforms/Instrumentation/MemorySanitizer.cpp" \
+      "${CLANG_DIR}/test/Driver/env.c" \
+      "${CLANG_DIR}/lib/Frontend/InitPreprocessor.cpp" \
+      "${CLANG_DIR}/test/Frontend/exceptions.c" \
+      "${CLANG_DIR}/test/Preprocessor/predefined-exceptions.m" \
+      "${LLVM_DIR}/test/Bindings/Go/go.test" \
+      "${CLANG_DIR}/lib/Parse/ParseExpr.cpp" \
+      "${CLANG_DIR}/lib/Parse/ParseTemplate.cpp" \
+      "${CLANG_DIR}/lib/Sema/SemaDeclCXX.cpp" \
+      "${CLANG_DIR}/lib/Sema/SemaExprCXX.cpp" \
+      "${CLANG_DIR}/test/SemaCXX/default2.cpp" \
+      "${CLANG_DIR}/test/SemaCXX/typo-correction-delayed.cpp" \
+      "${COMPILER_RT_DIR}/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc" \
+      "${COMPILER_RT_DIR}/test/tsan/signal_segv_handler.cc" \
+      "${COMPILER_RT_DIR}/lib/sanitizer_common/sanitizer_coverage_libcdep.cc" \
+      ; do
+  if [[ -e "${i}" ]]; then
+    rm -f "${i}"  # For unversioned files.
+    svn revert "${i}"
+  fi;
+done
+
+echo Remove the Clang tools shim dir
+CHROME_TOOLS_SHIM_DIR=${ABS_LLVM_DIR}/tools/chrometools
+rm -rfv ${CHROME_TOOLS_SHIM_DIR}
+
+echo Getting LLVM r"${CLANG_REVISION}" in "${LLVM_DIR}"
+if ! svn co --force "${LLVM_REPO_URL}/llvm/trunk@${CLANG_REVISION}" \
+                    "${LLVM_DIR}"; then
+  echo Checkout failed, retrying
+  rm -rf "${LLVM_DIR}"
+  svn co --force "${LLVM_REPO_URL}/llvm/trunk@${CLANG_REVISION}" "${LLVM_DIR}"
+fi
+
+echo Getting clang r"${CLANG_REVISION}" in "${CLANG_DIR}"
+svn co --force "${LLVM_REPO_URL}/cfe/trunk@${CLANG_REVISION}" "${CLANG_DIR}"
+
+# We have moved from building compiler-rt in the LLVM tree, to a separate
+# directory. Nuke any previous checkout to avoid building it.
+rm -rf "${LLVM_DIR}/projects/compiler-rt"
+
+echo Getting compiler-rt r"${CLANG_REVISION}" in "${COMPILER_RT_DIR}"
+svn co --force "${LLVM_REPO_URL}/compiler-rt/trunk@${CLANG_REVISION}" \
+               "${COMPILER_RT_DIR}"
+
+# clang needs a libc++ checkout, else -stdlib=libc++ won't find includes
+# (i.e. this is needed for bootstrap builds).
+if [ "${OS}" = "Darwin" ]; then
+  echo Getting libc++ r"${CLANG_REVISION}" in "${LIBCXX_DIR}"
+  svn co --force "${LLVM_REPO_URL}/libcxx/trunk@${CLANG_REVISION}" \
+                 "${LIBCXX_DIR}"
+fi
+
+# While we're bundling our own libc++ on OS X, we need to compile libc++abi
+# into it too (since OS X 10.6 doesn't have libc++abi.dylib either).
+if [ "${OS}" = "Darwin" ]; then
+  echo Getting libc++abi r"${CLANG_REVISION}" in "${LIBCXXABI_DIR}"
+  svn co --force "${LLVM_REPO_URL}/libcxxabi/trunk@${CLANG_REVISION}" \
+                 "${LIBCXXABI_DIR}"
+fi
+
+if [[ -n "$with_patches" ]]; then
+
+  # Apply patch for tests failing with --disable-pthreads (llvm.org/PR11974)
+  pushd "${CLANG_DIR}"
+  cat << 'EOF' |
+--- third_party/llvm/tools/clang/test/Index/crash-recovery-modules.m	(revision 202554)
++++ third_party/llvm/tools/clang/test/Index/crash-recovery-modules.m	(working copy)
+@@ -12,6 +12,8 @@
+ 
+ // REQUIRES: crash-recovery
+ // REQUIRES: shell
++// XFAIL: *
++//    (PR11974)
+ 
+ @import Crash;
+EOF
+patch -p4
+popd
+
+pushd "${CLANG_DIR}"
+cat << 'EOF' |
+--- unittests/libclang/LibclangTest.cpp (revision 215949)
++++ unittests/libclang/LibclangTest.cpp (working copy)
+@@ -431,7 +431,7 @@
+   EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
+ }
+
+-TEST_F(LibclangReparseTest, ReparseWithModule) {
++TEST_F(LibclangReparseTest, DISABLED_ReparseWithModule) {
+   const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
+   const char *HeaderBottom = "\n};\n#endif\n";
+   const char *MFile = "#include \"HeaderFile.h\"\nint main() {"
+EOF
+  patch -p0
+  popd
+
+  # Cherry-pick r234010 [sancov] Shrink pc array on Android back to 2**24."
+  pushd "${COMPILER_RT_DIR}"
+  cat << 'EOF' |
+diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+index 4b976fc..cfd9e7e 100644
+--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
++++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+@@ -109,7 +109,8 @@ class CoverageData {
+ 
+   // Maximal size pc array may ever grow.
+   // We MmapNoReserve this space to ensure that the array is contiguous.
+-  static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 27);
++  static const uptr kPcArrayMaxSize =
++      FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27);
+   // The amount file mapping for the pc array is grown by.
+   static const uptr kPcArrayMmapSize = 64 * 1024;
+
+EOF
+  patch -p1
+  popd
+
+  # This Go bindings test doesn't work after the bootstrap build on Linux. (PR21552)
+  pushd "${LLVM_DIR}"
+  cat << 'EOF' |
+Index: test/Bindings/Go/go.test
+===================================================================
+--- test/Bindings/Go/go.test    (revision 223109)
++++ test/Bindings/Go/go.test    (working copy)
+@@ -1,3 +1,3 @@
+-; RUN: llvm-go test llvm.org/llvm/bindings/go/llvm
++; RUN: true
+ 
+ ; REQUIRES: shell
+EOF
+  patch -p0
+  popd
+
+
+fi
+
+# Echo all commands.
+set -x
+
+# Set default values for CC and CXX if they're not set in the environment.
+CC=${CC:-cc}
+CXX=${CXX:-c++}
+
+if [[ -n "${gcc_toolchain}" ]]; then
+  # Use the specified gcc installation for building.
+  CC="$gcc_toolchain/bin/gcc"
+  CXX="$gcc_toolchain/bin/g++"
+  # Set LD_LIBRARY_PATH to make auxiliary targets (tablegen, bootstrap compiler,
+  # etc.) find the .so.
+  export LD_LIBRARY_PATH="$(dirname $(${CXX} -print-file-name=libstdc++.so.6))"
+fi
+
+CFLAGS=""
+CXXFLAGS=""
+LDFLAGS=""
+
+# LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is
+# needed, on OS X it requires libc++. clang only automatically links to libc++
+# when targeting OS X 10.9+, so add stdlib=libc++ explicitly so clang can run on
+# OS X versions as old as 10.7.
+# TODO(thakis): Some bots are still on 10.6, so for now bundle libc++.dylib.
+# Remove this once all bots are on 10.7+, then use --enable-libcpp=yes and
+# change deployment_target to 10.7.
+deployment_target=""
+
+if [ "${OS}" = "Darwin" ]; then
+  # When building on 10.9, /usr/include usually doesn't exist, and while
+  # Xcode's clang automatically sets a sysroot, self-built clangs don't.
+  CFLAGS="-isysroot $(xcrun --show-sdk-path)"
+  CPPFLAGS="${CFLAGS}"
+  CXXFLAGS="-stdlib=libc++ -nostdinc++ -I${ABS_LIBCXX_DIR}/include ${CFLAGS}"
+
+  if [[ -n "${bootstrap}" ]]; then
+    deployment_target=10.6
+  fi
+fi
+
+# Build bootstrap clang if requested.
+if [[ -n "${bootstrap}" ]]; then
+  ABS_INSTALL_DIR="${PWD}/${LLVM_BOOTSTRAP_INSTALL_DIR}"
+  echo "Building bootstrap compiler"
+  mkdir -p "${LLVM_BOOTSTRAP_DIR}"
+  pushd "${LLVM_BOOTSTRAP_DIR}"
+
+  cmake -GNinja \
+      -DCMAKE_BUILD_TYPE=Release \
+      -DLLVM_ENABLE_ASSERTIONS=ON \
+      -DLLVM_TARGETS_TO_BUILD=host \
+      -DLLVM_ENABLE_THREADS=OFF \
+      -DCMAKE_INSTALL_PREFIX="${ABS_INSTALL_DIR}" \
+      -DCMAKE_C_COMPILER="${CC}" \
+      -DCMAKE_CXX_COMPILER="${CXX}" \
+      -DCMAKE_C_FLAGS="${CFLAGS}" \
+      -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \
+      ../llvm
+
+  ninja
+  if [[ -n "${run_tests}" ]]; then
+    ninja check-all
+  fi
+
+  ninja install
+  if [[ -n "${gcc_toolchain}" ]]; then
+    # Copy that gcc's stdlibc++.so.6 to the build dir, so the bootstrap
+    # compiler can start.
+    cp -v "$(${CXX} -print-file-name=libstdc++.so.6)" \
+      "${ABS_INSTALL_DIR}/lib/"
+  fi
+
+  popd
+  CC="${ABS_INSTALL_DIR}/bin/clang"
+  CXX="${ABS_INSTALL_DIR}/bin/clang++"
+
+  if [[ -n "${gcc_toolchain}" ]]; then
+    # Tell the bootstrap compiler to use a specific gcc prefix to search
+    # for standard library headers and shared object file.
+    CFLAGS="--gcc-toolchain=${gcc_toolchain}"
+    CXXFLAGS="--gcc-toolchain=${gcc_toolchain}"
+  fi
+
+  echo "Building final compiler"
+fi
+
+# Build clang (in a separate directory).
+# The clang bots have this path hardcoded in built/scripts/slave/compile.py,
+# so if you change it you also need to change these links.
+mkdir -p "${LLVM_BUILD_DIR}"
+pushd "${LLVM_BUILD_DIR}"
+
+# Build libc++.dylib while some bots are still on OS X 10.6.
+if [ "${OS}" = "Darwin" ]; then
+  rm -rf libcxxbuild
+  LIBCXXFLAGS="-O3 -std=c++11 -fstrict-aliasing"
+
+  # libcxx and libcxxabi both have a file stdexcept.cpp, so put their .o files
+  # into different subdirectories.
+  mkdir -p libcxxbuild/libcxx
+  pushd libcxxbuild/libcxx
+  ${CXX:-c++} -c ${CXXFLAGS} ${LIBCXXFLAGS} "${ABS_LIBCXX_DIR}"/src/*.cpp
+  popd
+
+  mkdir -p libcxxbuild/libcxxabi
+  pushd libcxxbuild/libcxxabi
+  ${CXX:-c++} -c ${CXXFLAGS} ${LIBCXXFLAGS} "${ABS_LIBCXXABI_DIR}"/src/*.cpp -I"${ABS_LIBCXXABI_DIR}/include"
+  popd
+
+  pushd libcxxbuild
+  ${CC:-cc} libcxx/*.o libcxxabi/*.o -o libc++.1.dylib -dynamiclib \
+    -nodefaultlibs -current_version 1 -compatibility_version 1 \
+    -lSystem -install_name @executable_path/libc++.dylib \
+    -Wl,-unexported_symbols_list,${ABS_LIBCXX_DIR}/lib/libc++unexp.exp \
+    -Wl,-force_symbols_not_weak_list,${ABS_LIBCXX_DIR}/lib/notweak.exp \
+    -Wl,-force_symbols_weak_list,${ABS_LIBCXX_DIR}/lib/weak.exp
+  ln -sf libc++.1.dylib libc++.dylib
+  popd
+  LDFLAGS+="-stdlib=libc++ -L${PWD}/libcxxbuild"
+fi
+
+# Find the binutils include dir for the gold plugin.
+BINUTILS_INCDIR=""
+if [ "${OS}" = "Linux" ]; then
+  BINUTILS_INCDIR="${ABS_BINUTILS_DIR}/Linux_x64/Release/include"
+fi
+
+
+# If building at head, define a macro that plugins can use for #ifdefing
+# out code that builds at head, but not at CLANG_REVISION or vice versa.
+if [[ -n ${LLVM_FORCE_HEAD_REVISION:-''} ]]; then
+  CFLAGS="${CFLAGS} -DLLVM_FORCE_HEAD_REVISION"
+  CXXFLAGS="${CXXFLAGS} -DLLVM_FORCE_HEAD_REVISION"
+fi
+
+# Hook the Chromium tools into the LLVM build. Several Chromium tools have
+# dependencies on LLVM/Clang libraries. The LLVM build detects implicit tools
+# in the tools subdirectory, so install a shim CMakeLists.txt that forwards to
+# the real directory for the Chromium tools.
+# Note that the shim directory name intentionally has no _ or _. The implicit
+# tool detection logic munges them in a weird way.
+mkdir -v ${CHROME_TOOLS_SHIM_DIR}
+cat > ${CHROME_TOOLS_SHIM_DIR}/CMakeLists.txt << EOF
+# Since tools/clang isn't actually a subdirectory, use the two argument version
+# to specify where build artifacts go. CMake doesn't allow reusing the same
+# binary dir for multiple source dirs, so the build artifacts have to go into a
+# subdirectory...
+add_subdirectory(\${CHROMIUM_TOOLS_SRC} \${CMAKE_CURRENT_BINARY_DIR}/a)
+EOF
+rm -fv CMakeCache.txt
+MACOSX_DEPLOYMENT_TARGET=${deployment_target} cmake -GNinja \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DLLVM_ENABLE_ASSERTIONS=ON \
+    -DLLVM_ENABLE_THREADS=OFF \
+    -DLLVM_BINUTILS_INCDIR="${BINUTILS_INCDIR}" \
+    -DCMAKE_C_COMPILER="${CC}" \
+    -DCMAKE_CXX_COMPILER="${CXX}" \
+    -DCMAKE_C_FLAGS="${CFLAGS}" \
+    -DCMAKE_CXX_FLAGS="${CXXFLAGS}" \
+    -DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}" \
+    -DCMAKE_SHARED_LINKER_FLAGS="${LDFLAGS}" \
+    -DCMAKE_MODULE_LINKER_FLAGS="${LDFLAGS}" \
+    -DCMAKE_INSTALL_PREFIX="${ABS_LLVM_BUILD_DIR}" \
+    -DCHROMIUM_TOOLS_SRC="${ABS_CHROMIUM_TOOLS_DIR}" \
+    -DCHROMIUM_TOOLS="${chrome_tools}" \
+    "${ABS_LLVM_DIR}"
+env
+
+if [[ -n "${gcc_toolchain}" ]]; then
+  # Copy in the right stdlibc++.so.6 so clang can start.
+  mkdir -p lib
+  cp -v "$(${CXX} ${CXXFLAGS} -print-file-name=libstdc++.so.6)" lib/
+fi
+
+ninja
+# If any Chromium tools were built, install those now.
+if [[ -n "${chrome_tools}" ]]; then
+  ninja cr-install
+fi
+
+STRIP_FLAGS=
+if [ "${OS}" = "Darwin" ]; then
+  # See http://crbug.com/256342
+  STRIP_FLAGS=-x
+
+  cp libcxxbuild/libc++.1.dylib bin/
+fi
+strip ${STRIP_FLAGS} bin/clang
+popd
+
+# Build compiler-rt out-of-tree.
+mkdir -p "${COMPILER_RT_BUILD_DIR}"
+pushd "${COMPILER_RT_BUILD_DIR}"
+
+rm -fv CMakeCache.txt
+MACOSX_DEPLOYMENT_TARGET=${deployment_target} cmake -GNinja \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DLLVM_ENABLE_ASSERTIONS=ON \
+    -DLLVM_ENABLE_THREADS=OFF \
+    -DCMAKE_C_COMPILER="${CC}" \
+    -DCMAKE_CXX_COMPILER="${CXX}" \
+    -DLLVM_CONFIG_PATH="${ABS_LLVM_BUILD_DIR}/bin/llvm-config" \
+    "${ABS_COMPILER_RT_DIR}"
+
+ninja
+
+# Copy selected output to the main tree.
+# Darwin doesn't support cp --parents, so pipe through tar instead.
+CLANG_VERSION=$("${ABS_LLVM_BUILD_DIR}/bin/clang" --version | \
+     sed -ne 's/clang version \([0-9]\.[0-9]\.[0-9]\).*/\1/p')
+ABS_LLVM_CLANG_LIB_DIR="${ABS_LLVM_BUILD_DIR}/lib/clang/${CLANG_VERSION}"
+tar -c *blacklist.txt | tar -C ${ABS_LLVM_CLANG_LIB_DIR} -xv
+tar -c include/sanitizer | tar -C ${ABS_LLVM_CLANG_LIB_DIR} -xv
+if [[ "${OS}" = "Darwin" ]]; then
+  tar -c lib/darwin | tar -C ${ABS_LLVM_CLANG_LIB_DIR} -xv
+else
+  tar -c lib/linux | tar -C ${ABS_LLVM_CLANG_LIB_DIR} -xv
+fi
+
+popd
+
+if [[ -n "${with_android}" ]]; then
+  # Make a standalone Android toolchain.
+  ${ANDROID_NDK_DIR}/build/tools/make-standalone-toolchain.sh \
+      --platform=android-14 \
+      --install-dir="${LLVM_BUILD_DIR}/android-toolchain" \
+      --system=linux-x86_64 \
+      --stl=libcxx \
+      --toolchain=arm-linux-androideabi-4.9
+
+  # Android NDK r9d copies a broken unwind.h into the toolchain, see
+  # http://crbug.com/357890
+  rm -v "${LLVM_BUILD_DIR}"/android-toolchain/include/c++/*/unwind.h
+
+  # Build ASan runtime for Android in a separate build tree.
+  mkdir -p ${LLVM_BUILD_DIR}/android
+  pushd ${LLVM_BUILD_DIR}/android
+  rm -fv CMakeCache.txt
+  MACOSX_DEPLOYMENT_TARGET=${deployment_target} cmake -GNinja \
+      -DCMAKE_BUILD_TYPE=Release \
+      -DLLVM_ENABLE_ASSERTIONS=ON \
+      -DLLVM_ENABLE_THREADS=OFF \
+      -DCMAKE_C_COMPILER=${PWD}/../bin/clang \
+      -DCMAKE_CXX_COMPILER=${PWD}/../bin/clang++ \
+      -DLLVM_CONFIG_PATH=${PWD}/../bin/llvm-config \
+      -DCMAKE_C_FLAGS="--target=arm-linux-androideabi --sysroot=${PWD}/../android-toolchain/sysroot -B${PWD}/../android-toolchain" \
+      -DCMAKE_CXX_FLAGS="--target=arm-linux-androideabi --sysroot=${PWD}/../android-toolchain/sysroot -B${PWD}/../android-toolchain" \
+      -DANDROID=1 \
+      "${ABS_COMPILER_RT_DIR}"
+  ninja libclang_rt.asan-arm-android.so
+
+  # And copy it into the main build tree.
+  cp "$(find -name libclang_rt.asan-arm-android.so)" "${ABS_LLVM_CLANG_LIB_DIR}/lib/linux/"
+  popd
+fi
+
+if [[ -n "$run_tests" ]]; then
+  # Run Chrome tool tests.
+  ninja -C "${LLVM_BUILD_DIR}" cr-check-all
+  # Run the LLVM and Clang tests.
+  ninja -C "${LLVM_BUILD_DIR}" check-all
+fi
+
+# After everything is done, log success for this revision.
+echo "${PACKAGE_VERSION}" > "${STAMP_FILE}"